summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile3
-rw-r--r--drivers/accessibility/braille/braille_console.c4
-rw-r--r--drivers/accessibility/speakup/i18n.c7
-rw-r--r--drivers/accessibility/speakup/i18n.h9
-rw-r--r--drivers/accessibility/speakup/main.c4
-rw-r--r--drivers/accessibility/speakup/spk_ttyio.c9
-rw-r--r--drivers/acpi/Kconfig18
-rw-r--r--drivers/acpi/Makefile8
-rw-r--r--drivers/acpi/acpi_amba.c1
-rw-r--r--drivers/acpi/acpi_cmos_rtc.c6
-rw-r--r--drivers/acpi/acpi_configfs.c5
-rw-r--r--drivers/acpi/acpi_fpdt.c4
-rw-r--r--drivers/acpi/acpi_ipmi.c7
-rw-r--r--drivers/acpi/acpi_lpss.c13
-rw-r--r--drivers/acpi/acpi_video.c15
-rw-r--r--drivers/acpi/acpica/acutils.h2
-rw-r--r--drivers/acpi/acpica/exfield.c8
-rw-r--r--drivers/acpi/acpica/exserial.c12
-rw-r--r--drivers/acpi/acpica/nsrepair2.c7
-rw-r--r--drivers/acpi/acpica/utprint.c2
-rw-r--r--drivers/acpi/acpica/utuuid.c41
-rw-r--r--drivers/acpi/apei/einj.c2
-rw-r--r--drivers/acpi/apei/ghes.c81
-rw-r--r--drivers/acpi/arm64/Makefile1
-rw-r--r--drivers/acpi/arm64/dma.c50
-rw-r--r--drivers/acpi/arm64/iort.c134
-rw-r--r--drivers/acpi/bgrt.c57
-rw-r--r--drivers/acpi/blacklist.c9
-rw-r--r--drivers/acpi/bus.c20
-rw-r--r--drivers/acpi/device_pm.c70
-rw-r--r--drivers/acpi/device_sysfs.c7
-rw-r--r--drivers/acpi/dptf/int340x_thermal.c2
-rw-r--r--drivers/acpi/ec.c39
-rw-r--r--drivers/acpi/event.c8
-rw-r--r--drivers/acpi/fan.c7
-rw-r--r--drivers/acpi/fan.h13
-rw-r--r--drivers/acpi/glue.c29
-rw-r--r--drivers/acpi/internal.h15
-rw-r--r--drivers/acpi/nvs.c32
-rw-r--r--drivers/acpi/osl.c11
-rw-r--r--drivers/acpi/pci_root.c4
-rw-r--r--drivers/acpi/pmic/Kconfig2
-rw-r--r--drivers/acpi/pmic/intel_pmic_chtdc_ti.c2
-rw-r--r--drivers/acpi/power.c116
-rw-r--r--drivers/acpi/pptt.c18
-rw-r--r--drivers/acpi/prmt.c303
-rw-r--r--drivers/acpi/processor_idle.c40
-rw-r--r--drivers/acpi/processor_perflib.c38
-rw-r--r--drivers/acpi/processor_thermal.c2
-rw-r--r--drivers/acpi/processor_throttling.c75
-rw-r--r--drivers/acpi/reboot.c4
-rw-r--r--drivers/acpi/resource.c9
-rw-r--r--drivers/acpi/sbs.c12
-rw-r--r--drivers/acpi/sbshc.c9
-rw-r--r--drivers/acpi/scan.c396
-rw-r--r--drivers/acpi/sleep.c22
-rw-r--r--drivers/acpi/sysfs.c85
-rw-r--r--drivers/acpi/tables.c9
-rw-r--r--drivers/acpi/utils.c14
-rw-r--r--drivers/acpi/viot.c366
-rw-r--r--drivers/acpi/x86/s2idle.c157
-rw-r--r--drivers/acpi/x86/utils.c25
-rw-r--r--drivers/ata/Kconfig8
-rw-r--r--drivers/ata/ahci.c4
-rw-r--r--drivers/ata/ahci.h7
-rw-r--r--drivers/ata/ahci_sunxi.c2
-rw-r--r--drivers/ata/libata-scsi.c30
-rw-r--r--drivers/ata/pata_atiixp.c3
-rw-r--r--drivers/ata/pata_cs5520.c3
-rw-r--r--drivers/ata/pata_cs5530.c3
-rw-r--r--drivers/ata/pata_cypress.c10
-rw-r--r--drivers/ata/pata_ep93xx.c2
-rw-r--r--drivers/ata/pata_falcon.c62
-rw-r--r--drivers/ata/pata_ixp4xx_cf.c1
-rw-r--r--drivers/ata/pata_macio.c5
-rw-r--r--drivers/ata/pata_octeon_cf.c5
-rw-r--r--drivers/ata/pata_rb532_cf.c8
-rw-r--r--drivers/ata/pata_sc1200.c3
-rw-r--r--drivers/ata/pata_serverworks.c3
-rw-r--r--drivers/ata/sata_fsl.c2
-rw-r--r--drivers/ata/sata_highbank.c6
-rw-r--r--drivers/ata/sata_mv.c6
-rw-r--r--drivers/ata/sata_nv.c12
-rw-r--r--drivers/ata/sata_sil24.c5
-rw-r--r--drivers/atm/fore200e.c1
-rw-r--r--drivers/atm/iphase.c13
-rw-r--r--drivers/atm/iphase.h1
-rw-r--r--drivers/atm/nicstar.c26
-rw-r--r--drivers/atm/zeprom.h2
-rw-r--r--drivers/base/Makefile3
-rw-r--r--drivers/base/arch_topology.c27
-rw-r--r--drivers/base/attribute_container.c6
-rw-r--r--drivers/base/base.h1
-rw-r--r--drivers/base/bus.c8
-rw-r--r--drivers/base/component.c96
-rw-r--r--drivers/base/core.c37
-rw-r--r--drivers/base/cpu.c4
-rw-r--r--drivers/base/dd.c192
-rw-r--r--drivers/base/devcoredump.c4
-rw-r--r--drivers/base/devres.c105
-rw-r--r--drivers/base/firmware_loader/builtin/Makefile1
-rw-r--r--drivers/base/memory.c4
-rw-r--r--drivers/base/node.c22
-rw-r--r--drivers/base/platform.c22
-rw-r--r--drivers/base/power/domain.c102
-rw-r--r--drivers/base/power/domain_governor.c1
-rw-r--r--drivers/base/power/main.c5
-rw-r--r--drivers/base/power/runtime.c18
-rw-r--r--drivers/base/power/wakeirq.c4
-rw-r--r--drivers/base/property.c47
-rw-r--r--drivers/base/regmap/Kconfig6
-rw-r--r--drivers/base/regmap/Makefile1
-rw-r--r--drivers/base/regmap/regmap-i2c.c45
-rw-r--r--drivers/base/regmap/regmap-irq.c7
-rw-r--r--drivers/base/regmap/regmap-mdio.c116
-rw-r--r--drivers/base/regmap/regmap.c15
-rw-r--r--drivers/base/swnode.c16
-rw-r--r--drivers/base/test/property-entry-test.c56
-rw-r--r--drivers/base/trace.c10
-rw-r--r--drivers/base/trace.h56
-rw-r--r--drivers/block/amiflop.c16
-rw-r--r--drivers/block/aoe/aoeblk.c33
-rw-r--r--drivers/block/aoe/aoechr.c4
-rw-r--r--drivers/block/aoe/aoecmd.c2
-rw-r--r--drivers/block/aoe/aoedev.c3
-rw-r--r--drivers/block/ataflop.c16
-rw-r--r--drivers/block/brd.c94
-rw-r--r--drivers/block/drbd/drbd_main.c23
-rw-r--r--drivers/block/drbd/drbd_receiver.c22
-rw-r--r--drivers/block/floppy.c22
-rw-r--r--drivers/block/loop.c466
-rw-r--r--drivers/block/loop.h15
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c176
-rw-r--r--drivers/block/n64cart.c8
-rw-r--r--drivers/block/nbd.c113
-rw-r--r--drivers/block/null_blk/main.c36
-rw-r--r--drivers/block/paride/pcd.c19
-rw-r--r--drivers/block/paride/pd.c30
-rw-r--r--drivers/block/paride/pf.c18
-rw-r--r--drivers/block/pktcdvd.c13
-rw-r--r--drivers/block/ps3disk.c36
-rw-r--r--drivers/block/ps3vram.c31
-rw-r--r--drivers/block/rbd.c52
-rw-r--r--drivers/block/rnbd/rnbd-clt.c40
-rw-r--r--drivers/block/rnbd/rnbd-clt.h5
-rw-r--r--drivers/block/rsxx/dev.c39
-rw-r--r--drivers/block/rsxx/dma.c6
-rw-r--r--drivers/block/rsxx/rsxx_priv.h1
-rw-r--r--drivers/block/sunvdc.c53
-rw-r--r--drivers/block/swim.c34
-rw-r--r--drivers/block/swim3.c33
-rw-r--r--drivers/block/sx8.c25
-rw-r--r--drivers/block/virtio_blk.c43
-rw-r--r--drivers/block/xen-blkfront.c316
-rw-r--r--drivers/block/z2ram.c25
-rw-r--r--drivers/block/zram/zram_drv.c37
-rw-r--r--drivers/block/zram/zram_drv.h4
-rw-r--r--drivers/bluetooth/btbcm.c1
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c4
-rw-r--r--drivers/bluetooth/btmtkuart.c6
-rw-r--r--drivers/bluetooth/btqca.c113
-rw-r--r--drivers/bluetooth/btqca.h14
-rw-r--r--drivers/bluetooth/btrtl.c35
-rw-r--r--drivers/bluetooth/btrtl.h7
-rw-r--r--drivers/bluetooth/btusb.c45
-rw-r--r--drivers/bluetooth/hci_ag6xx.c1
-rw-r--r--drivers/bluetooth/hci_h5.c5
-rw-r--r--drivers/bluetooth/hci_ldisc.c12
-rw-r--r--drivers/bluetooth/hci_qca.c118
-rw-r--r--drivers/bluetooth/virtio_bt.c3
-rw-r--r--drivers/bus/brcmstb_gisb.c1
-rw-r--r--drivers/bus/fsl-mc/dprc-driver.c8
-rw-r--r--drivers/bus/fsl-mc/dprc.c4
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-allocator.c10
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-bus.c19
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-msi.c2
-rw-r--r--drivers/bus/fsl-mc/mc-io.c6
-rw-r--r--drivers/bus/fsl-mc/mc-sys.c19
-rw-r--r--drivers/bus/mhi/core/pm.c19
-rw-r--r--drivers/bus/mhi/pci_generic.c5
-rw-r--r--drivers/bus/qcom-ebi2.c4
-rw-r--r--drivers/cdrom/cdrom.c2
-rw-r--r--drivers/cdrom/gdrom.c45
-rw-r--r--drivers/char/Kconfig34
-rw-r--r--drivers/char/Makefile3
-rw-r--r--drivers/char/hpet.c4
-rw-r--r--drivers/char/hw_random/Kconfig12
-rw-r--r--drivers/char/hw_random/amd-rng.c2
-rw-r--r--drivers/char/hw_random/core.c38
-rw-r--r--drivers/char/hw_random/exynos-trng.c7
-rw-r--r--drivers/char/hw_random/ixp4xx-rng.c53
-rw-r--r--drivers/char/hw_random/ks-sa-rng.c3
-rw-r--r--drivers/char/hw_random/omap-rng.c6
-rw-r--r--drivers/char/hw_random/pseries-rng.c2
-rw-r--r--drivers/char/ipmi/Kconfig27
-rw-r--r--drivers/char/ipmi/Makefile2
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c1
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c22
-rw-r--r--drivers/char/ipmi/kcs_bmc.c505
-rw-r--r--drivers/char/ipmi/kcs_bmc.h92
-rw-r--r--drivers/char/ipmi/kcs_bmc_aspeed.c633
-rw-r--r--drivers/char/ipmi/kcs_bmc_cdev_ipmi.c568
-rw-r--r--drivers/char/ipmi/kcs_bmc_client.h45
-rw-r--r--drivers/char/ipmi/kcs_bmc_device.h22
-rw-r--r--drivers/char/ipmi/kcs_bmc_npcm7xx.c92
-rw-r--r--drivers/char/ipmi/kcs_bmc_serio.c157
-rw-r--r--drivers/char/mem.c1
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c7
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c3
-rw-r--r--drivers/char/pcmcia/scr24x_cs.c1
-rw-r--r--drivers/char/pcmcia/synclink_cs.c24
-rw-r--r--drivers/char/powernv-op-panel.c1
-rw-r--r--drivers/char/raw.c362
-rw-r--r--drivers/char/tpm/tpm1-cmd.c4
-rw-r--r--drivers/char/tpm/tpm2-cmd.c2
-rw-r--r--drivers/char/tpm/tpm_crb.c2
-rw-r--r--drivers/char/tpm/tpm_tis.c6
-rw-r--r--drivers/char/tpm/tpm_tis_core.c25
-rw-r--r--drivers/char/tpm/tpm_tis_core.h3
-rw-r--r--drivers/char/tpm/tpm_tis_i2c_cr50.c4
-rw-r--r--drivers/char/tpm/tpm_tis_spi_main.c14
-rw-r--r--drivers/char/ttyprintk.c52
-rw-r--r--drivers/char/virtio_console.c4
-rw-r--r--drivers/char/xillybus/Kconfig22
-rw-r--r--drivers/char/xillybus/Makefile2
-rw-r--r--drivers/char/xillybus/xillybus.h10
-rw-r--r--drivers/char/xillybus/xillybus_class.c262
-rw-r--r--drivers/char/xillybus/xillybus_class.h30
-rw-r--r--drivers/char/xillybus/xillybus_core.c180
-rw-r--r--drivers/char/xillybus/xillybus_of.c1
-rw-r--r--drivers/char/xillybus/xillybus_pcie.c1
-rw-r--r--drivers/char/xillybus/xillyusb.c2259
-rw-r--r--drivers/clk/Kconfig30
-rw-r--r--drivers/clk/Makefile4
-rw-r--r--drivers/clk/actions/owl-s500.c92
-rw-r--r--drivers/clk/analogbits/wrpll-cln28hpc.c6
-rw-r--r--drivers/clk/clk-bd718x7.c11
-rw-r--r--drivers/clk/clk-divider.c75
-rw-r--r--drivers/clk/clk-k210.c1
-rw-r--r--drivers/clk/clk-lmk04832.c1599
-rw-r--r--drivers/clk/clk-si5341.c324
-rw-r--r--drivers/clk/clk-stm32mp1.c501
-rw-r--r--drivers/clk/clk-versaclock5.c27
-rw-r--r--drivers/clk/clkdev.c28
-rw-r--r--drivers/clk/hisilicon/Kconfig7
-rw-r--r--drivers/clk/hisilicon/Makefile1
-rw-r--r--drivers/clk/hisilicon/clk-hi3559a.c845
-rw-r--r--drivers/clk/hisilicon/clk.c2
-rw-r--r--drivers/clk/hisilicon/clk.h2
-rw-r--r--drivers/clk/imx/Makefile3
-rw-r--r--drivers/clk/imx/clk-imx8mp.c1
-rw-r--r--drivers/clk/imx/clk-imx8mq.c56
-rw-r--r--drivers/clk/imx/clk-imx8qm-rsrc.c116
-rw-r--r--drivers/clk/imx/clk-imx8qxp-rsrc.c89
-rw-r--r--drivers/clk/imx/clk-imx8qxp.c377
-rw-r--r--drivers/clk/imx/clk-scu.c312
-rw-r--r--drivers/clk/imx/clk-scu.h56
-rw-r--r--drivers/clk/ingenic/Kconfig10
-rw-r--r--drivers/clk/ingenic/Makefile1
-rw-r--r--drivers/clk/ingenic/cgu.c92
-rw-r--r--drivers/clk/ingenic/cgu.h12
-rw-r--r--drivers/clk/ingenic/jz4725b-cgu.c12
-rw-r--r--drivers/clk/ingenic/jz4740-cgu.c12
-rw-r--r--drivers/clk/ingenic/jz4760-cgu.c428
-rw-r--r--drivers/clk/ingenic/jz4770-cgu.c15
-rw-r--r--drivers/clk/ingenic/tcu.c2
-rw-r--r--drivers/clk/keystone/syscon-clk.c17
-rw-r--r--drivers/clk/meson/axg-audio.c5
-rw-r--r--drivers/clk/meson/clk-pll.c26
-rw-r--r--drivers/clk/meson/clk-regmap.c19
-rw-r--r--drivers/clk/meson/g12a.c8
-rw-r--r--drivers/clk/qcom/Kconfig21
-rw-r--r--drivers/clk/qcom/Makefile3
-rw-r--r--drivers/clk/qcom/apcs-sdx55.c18
-rw-r--r--drivers/clk/qcom/camcc-sm8250.c2456
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.c176
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.h6
-rw-r--r--drivers/clk/qcom/clk-rcg2.c81
-rw-r--r--drivers/clk/qcom/clk-smd-rpm.c673
-rw-r--r--drivers/clk/qcom/dispcc-sm8250.c190
-rw-r--r--drivers/clk/qcom/gcc-mdm9607.c1632
-rw-r--r--drivers/clk/qcom/gcc-msm8974.c169
-rw-r--r--drivers/clk/qcom/gcc-sc7280.c1
-rw-r--r--drivers/clk/qcom/gcc-sm6125.c4190
-rw-r--r--drivers/clk/renesas/Kconfig9
-rw-r--r--drivers/clk/renesas/Makefile2
-rw-r--r--drivers/clk/renesas/clk-div6.c80
-rw-r--r--drivers/clk/renesas/r8a77995-cpg-mssr.c1
-rw-r--r--drivers/clk/renesas/r8a779a0-cpg-mssr.c4
-rw-r--r--drivers/clk/renesas/r9a06g032-clocks.c25
-rw-r--r--drivers/clk/renesas/r9a07g044-cpg.c142
-rw-r--r--drivers/clk/renesas/rcar-gen3-cpg.c183
-rw-r--r--drivers/clk/renesas/rcar-usb2-clock-sel.c24
-rw-r--r--drivers/clk/renesas/renesas-cpg-mssr.c10
-rw-r--r--drivers/clk/renesas/renesas-rzg2l-cpg.c758
-rw-r--r--drivers/clk/renesas/renesas-rzg2l-cpg.h155
-rw-r--r--drivers/clk/rockchip/clk-rk3036.c2
-rw-r--r--drivers/clk/rockchip/clk-rk3568.c10
-rw-r--r--drivers/clk/rockchip/clk.h29
-rw-r--r--drivers/clk/sifive/sifive-prci.c2
-rw-r--r--drivers/clk/socfpga/clk-agilex.c93
-rw-r--r--drivers/clk/socfpga/clk-gate-s10.c119
-rw-r--r--drivers/clk/socfpga/clk-periph-s10.c11
-rw-r--r--drivers/clk/socfpga/clk-pll.c3
-rw-r--r--drivers/clk/socfpga/clk-s10.c87
-rw-r--r--drivers/clk/socfpga/stratix10-clk.h2
-rw-r--r--drivers/clk/st/clk-flexgen.c367
-rw-r--r--drivers/clk/st/clkgen-fsyn.c113
-rw-r--r--drivers/clk/st/clkgen-pll.c121
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun8i-v3s.c4
-rw-r--r--drivers/clk/tegra/clk-periph-gate.c80
-rw-r--r--drivers/clk/tegra/clk-periph.c11
-rw-r--r--drivers/clk/tegra/clk-pll.c12
-rw-r--r--drivers/clk/tegra/clk-tegra-periph.c6
-rw-r--r--drivers/clk/tegra/clk-tegra-super-cclk.c16
-rw-r--r--drivers/clk/tegra/clk-tegra124-dfll-fcpu.c4
-rw-r--r--drivers/clk/tegra/clk-tegra124-emc.c4
-rw-r--r--drivers/clk/tegra/clk-tegra20.c6
-rw-r--r--drivers/clk/tegra/clk-tegra30.c6
-rw-r--r--drivers/clk/tegra/clk.h4
-rw-r--r--drivers/clk/ti/adpll.c5
-rw-r--r--drivers/clk/ti/dpll.c39
-rw-r--r--drivers/clk/ti/dpll3xxx.c87
-rw-r--r--drivers/clk/versatile/Kconfig3
-rw-r--r--drivers/clk/zynqmp/clk-gate-zynqmp.c4
-rw-r--r--drivers/clk/zynqmp/clk-mux-zynqmp.c37
-rw-r--r--drivers/clk/zynqmp/clk-zynqmp.h33
-rw-r--r--drivers/clk/zynqmp/clkc.c25
-rw-r--r--drivers/clk/zynqmp/divider.c40
-rw-r--r--drivers/clk/zynqmp/pll.c28
-rw-r--r--drivers/clocksource/Kconfig20
-rw-r--r--drivers/clocksource/arm_arch_timer.c3
-rw-r--r--drivers/clocksource/arm_global_timer.c122
-rw-r--r--drivers/clocksource/ingenic-sysost.c10
-rw-r--r--drivers/clocksource/samsung_pwm_timer.c41
-rw-r--r--drivers/clocksource/timer-mediatek.c24
-rw-r--r--drivers/clocksource/timer-ti-dm.c9
-rw-r--r--drivers/comedi/drivers/comedi_8254.c3
-rw-r--r--drivers/comedi/drivers/comedi_isadma.c2
-rw-r--r--drivers/comedi/drivers/jr3_pci.c15
-rw-r--r--drivers/comedi/drivers/ni_routes.c7
-rw-r--r--drivers/comedi/drivers/ni_routes.h1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes.h1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/all.h1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6070e.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6220.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6221.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6229.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6251.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6254.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6259.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6534.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6602.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6713.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6723.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6733.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6030e.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6224.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6225.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6251.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6733.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6251.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6535.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6738.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_route_values.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_route_values.h1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_route_values/all.h1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_route_values/ni_660x.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_route_values/ni_eseries.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/ni_route_values/ni_mseries.c1
-rw-r--r--drivers/comedi/drivers/ni_routing/tools/convert_c_to_py.c1
-rwxr-xr-xdrivers/comedi/drivers/ni_routing/tools/convert_csv_to_c.py7
-rwxr-xr-xdrivers/comedi/drivers/ni_routing/tools/convert_py_to_csv.py1
-rw-r--r--drivers/comedi/drivers/ni_routing/tools/csv_collection.py1
-rwxr-xr-xdrivers/comedi/drivers/ni_routing/tools/make_blank_csv.py1
-rw-r--r--drivers/comedi/drivers/ni_routing/tools/ni_names.py1
-rw-r--r--drivers/comedi/drivers/ni_tio.c12
-rw-r--r--drivers/comedi/drivers/tests/comedi_example_test.c1
-rw-r--r--drivers/comedi/drivers/tests/ni_routes_test.c1
-rw-r--r--drivers/comedi/drivers/tests/unittest.h1
-rw-r--r--drivers/counter/104-quad-8.c13
-rw-r--r--drivers/counter/Kconfig10
-rw-r--r--drivers/counter/Makefile1
-rw-r--r--drivers/counter/ftm-quaddec.c2
-rw-r--r--drivers/counter/intel-qep.c544
-rw-r--r--drivers/counter/interrupt-cnt.c8
-rw-r--r--drivers/counter/microchip-tcb-capture.c4
-rw-r--r--drivers/counter/stm32-lptimer-cnt.c4
-rw-r--r--drivers/counter/stm32-timer-cnt.c4
-rw-r--r--drivers/cpufreq/Kconfig.arm10
-rw-r--r--drivers/cpufreq/cppc_cpufreq.c324
-rw-r--r--drivers/cpufreq/cpufreq-dt-platdev.c10
-rw-r--r--drivers/cpufreq/cpufreq.c55
-rw-r--r--drivers/cpufreq/cpufreq_stats.c5
-rw-r--r--drivers/cpufreq/intel_pstate.c274
-rw-r--r--drivers/cpufreq/longhaul.c2
-rw-r--r--drivers/cpufreq/loongson2_cpufreq.c1
-rw-r--r--drivers/cpufreq/mediatek-cpufreq.c1
-rw-r--r--drivers/cpufreq/powernv-cpufreq.c23
-rw-r--r--drivers/cpufreq/sc520_freq.c1
-rw-r--r--drivers/cpufreq/scmi-cpufreq.c2
-rw-r--r--drivers/cpufreq/sh-cpufreq.c1
-rw-r--r--drivers/cpuidle/cpuidle-qcom-spm.c14
-rw-r--r--drivers/cpuidle/governors/menu.c6
-rw-r--r--drivers/cpuidle/governors/teo.c476
-rw-r--r--drivers/crypto/Kconfig41
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/cavium/cpt/cptpf_main.c2
-rw-r--r--drivers/crypto/cavium/cpt/cptvf_reqmanager.c10
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_isr.c4
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_main.c21
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_mbx.c4
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_reqmgr.c16
-rw-r--r--drivers/crypto/cavium/nitrox/nitrox_skcipher.c2
-rw-r--r--drivers/crypto/ccp/ccp-dev.c2
-rw-r--r--drivers/crypto/ccp/ccp-dmaengine.c3
-rw-r--r--drivers/crypto/ccp/sev-dev.c4
-rw-r--r--drivers/crypto/ccp/sp-pci.c6
-rw-r--r--drivers/crypto/gemini/Makefile2
-rw-r--r--drivers/crypto/gemini/sl3516-ce-cipher.c387
-rw-r--r--drivers/crypto/gemini/sl3516-ce-core.c535
-rw-r--r--drivers/crypto/gemini/sl3516-ce-rng.c61
-rw-r--r--drivers/crypto/gemini/sl3516-ce.h347
-rw-r--r--drivers/crypto/hisilicon/hpre/hpre_crypto.c185
-rw-r--r--drivers/crypto/hisilicon/hpre/hpre_main.c256
-rw-r--r--drivers/crypto/hisilicon/qm.c1843
-rw-r--r--drivers/crypto/hisilicon/qm.h17
-rw-r--r--drivers/crypto/hisilicon/sec2/sec.h23
-rw-r--r--drivers/crypto/hisilicon/sec2/sec_crypto.c1036
-rw-r--r--drivers/crypto/hisilicon/sec2/sec_crypto.h193
-rw-r--r--drivers/crypto/hisilicon/sec2/sec_main.c103
-rw-r--r--drivers/crypto/hisilicon/zip/zip_main.c99
-rw-r--r--drivers/crypto/ixp4xx_crypto.c417
-rw-r--r--drivers/crypto/marvell/cesa/cesa.h2
-rw-r--r--drivers/crypto/marvell/octeontx2/Makefile13
-rw-r--r--drivers/crypto/marvell/octeontx2/cn10k_cpt.c93
-rw-r--r--drivers/crypto/marvell/octeontx2/cn10k_cpt.h36
-rw-r--r--drivers/crypto/marvell/octeontx2/otx2_cpt_common.h23
-rw-r--r--drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h16
-rw-r--r--drivers/crypto/marvell/octeontx2/otx2_cptlf.c9
-rw-r--r--drivers/crypto/marvell/octeontx2/otx2_cptlf.h10
-rw-r--r--drivers/crypto/marvell/octeontx2/otx2_cptpf.h1
-rw-r--r--drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c160
-rw-r--r--drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c32
-rw-r--r--drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.h8
-rw-r--r--drivers/crypto/marvell/octeontx2/otx2_cptvf.h3
-rw-r--r--drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c49
-rw-r--r--drivers/crypto/marvell/octeontx2/otx2_cptvf_mbox.c43
-rw-r--r--drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c17
-rw-r--r--drivers/crypto/nx/Kconfig1
-rw-r--r--drivers/crypto/nx/Makefile2
-rw-r--r--drivers/crypto/nx/nx-aes-cbc.c2
-rw-r--r--drivers/crypto/nx/nx-aes-ccm.c4
-rw-r--r--drivers/crypto/nx/nx-aes-ctr.c4
-rw-r--r--drivers/crypto/nx/nx-aes-ecb.c2
-rw-r--r--drivers/crypto/nx/nx-aes-gcm.c2
-rw-r--r--drivers/crypto/nx/nx-common-powernv.c10
-rw-r--r--drivers/crypto/nx/nx-common-pseries.c (renamed from drivers/crypto/nx/nx-842-pseries.c)169
-rw-r--r--drivers/crypto/nx/nx-sha256.c19
-rw-r--r--drivers/crypto/nx/nx-sha512.c19
-rw-r--r--drivers/crypto/nx/nx_csbcpb.h4
-rw-r--r--drivers/crypto/omap-crypto.c3
-rw-r--r--drivers/crypto/omap-des.c9
-rw-r--r--drivers/crypto/omap-sham.c4
-rw-r--r--drivers/crypto/qat/qat_common/adf_ctl_drv.c2
-rw-r--r--drivers/crypto/qat/qat_common/icp_qat_fw_loader_handle.h2
-rw-r--r--drivers/crypto/qat/qat_common/qat_hal.c14
-rw-r--r--drivers/crypto/qat/qat_common/qat_uclo.c12
-rw-r--r--drivers/crypto/qce/Makefile1
-rw-r--r--drivers/crypto/qce/aead.c847
-rw-r--r--drivers/crypto/qce/aead.h56
-rw-r--r--drivers/crypto/qce/common.c196
-rw-r--r--drivers/crypto/qce/common.h9
-rw-r--r--drivers/crypto/qce/core.c4
-rw-r--r--drivers/crypto/qce/skcipher.c19
-rw-r--r--drivers/crypto/sa2ul.c50
-rw-r--r--drivers/crypto/ux500/hash/hash_core.c1
-rw-r--r--drivers/cxl/Kconfig43
-rw-r--r--drivers/cxl/Makefile12
-rw-r--r--drivers/cxl/acpi.c434
-rw-r--r--drivers/cxl/bus.c29
-rw-r--r--drivers/cxl/core.c1067
-rw-r--r--drivers/cxl/cxl.h332
-rw-r--r--drivers/cxl/mem.h81
-rw-r--r--drivers/cxl/pci.c (renamed from drivers/cxl/mem.c)439
-rw-r--r--drivers/cxl/pci.h2
-rw-r--r--drivers/cxl/pmem.c230
-rw-r--r--drivers/dax/device.c2
-rw-r--r--drivers/devfreq/Kconfig1
-rw-r--r--drivers/devfreq/devfreq.c1
-rw-r--r--drivers/devfreq/governor_passive.c3
-rw-r--r--drivers/devfreq/governor_userspace.c10
-rw-r--r--drivers/devfreq/imx-bus.c14
-rw-r--r--drivers/devfreq/tegra30-devfreq.c1
-rw-r--r--drivers/dma-buf/sync_file.c13
-rw-r--r--drivers/dma/altera-msgdma.c20
-rw-r--r--drivers/dma/fsl-qdma.c6
-rw-r--r--drivers/dma/hsu/hsu.c3
-rw-r--r--drivers/dma/idxd/cdev.c2
-rw-r--r--drivers/dma/idxd/init.c3
-rw-r--r--drivers/dma/imx-sdma.c58
-rw-r--r--drivers/dma/ipu/ipu_idmac.c2
-rw-r--r--drivers/dma/mpc512x_dma.c1
-rw-r--r--drivers/dma/qcom/gpi.c1
-rw-r--r--drivers/dma/sf-pdma/sf-pdma.c5
-rw-r--r--drivers/dma/sh/Makefile2
-rw-r--r--drivers/dma/sh/shdma-of.c76
-rw-r--r--drivers/dma/sun4i-dma.c5
-rw-r--r--drivers/dma/ti/k3-udma.c1
-rw-r--r--drivers/dma/ti/omap-dma.c3
-rw-r--r--drivers/dma/xilinx/xilinx_dpdma.c44
-rw-r--r--drivers/edac/Kconfig3
-rw-r--r--drivers/edac/altera_edac.c1
-rw-r--r--drivers/edac/aspeed_edac.c4
-rw-r--r--drivers/edac/i10nm_base.c174
-rw-r--r--drivers/edac/igen6_edac.c374
-rw-r--r--drivers/edac/mce_amd.c70
-rw-r--r--drivers/edac/pnd2_edac.c3
-rw-r--r--drivers/edac/sb_edac.c3
-rw-r--r--drivers/edac/skx_base.c3
-rw-r--r--drivers/edac/skx_common.c82
-rw-r--r--drivers/edac/skx_common.h34
-rw-r--r--drivers/edac/thunderx_edac.c4
-rw-r--r--drivers/edac/ti_edac.c1
-rw-r--r--drivers/eisa/eisa-bus.c23
-rw-r--r--drivers/extcon/Kconfig2
-rw-r--r--drivers/extcon/extcon-intel-mrfld.c9
-rw-r--r--drivers/extcon/extcon-max14577.c16
-rw-r--r--drivers/extcon/extcon-max77693.c17
-rw-r--r--drivers/extcon/extcon-max8997.c46
-rw-r--r--drivers/extcon/extcon-sm5502.c212
-rw-r--r--drivers/extcon/extcon-sm5502.h82
-rw-r--r--drivers/firewire/core-topology.c1
-rw-r--r--drivers/firewire/nosy.c43
-rw-r--r--drivers/firmware/Kconfig3
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/arm_ffa/Kconfig21
-rw-r--r--drivers/firmware/arm_ffa/Makefile6
-rw-r--r--drivers/firmware/arm_ffa/bus.c210
-rw-r--r--drivers/firmware/arm_ffa/common.h31
-rw-r--r--drivers/firmware/arm_ffa/driver.c733
-rw-r--r--drivers/firmware/arm_ffa/smccc.c39
-rw-r--r--drivers/firmware/arm_scmi/bus.c8
-rw-r--r--drivers/firmware/arm_scmi/common.h2
-rw-r--r--drivers/firmware/arm_scmi/driver.c38
-rw-r--r--drivers/firmware/arm_scmi/mailbox.c3
-rw-r--r--drivers/firmware/arm_scmi/notify.c4
-rw-r--r--drivers/firmware/arm_scmi/scmi_pm_domain.c26
-rw-r--r--drivers/firmware/arm_scmi/sensors.c6
-rw-r--r--drivers/firmware/arm_scmi/smc.c3
-rw-r--r--drivers/firmware/arm_scpi.c11
-rw-r--r--drivers/firmware/efi/apple-properties.c2
-rw-r--r--drivers/firmware/efi/dev-path-parser.c49
-rw-r--r--drivers/firmware/google/gsmi.c1
-rw-r--r--drivers/firmware/psci/psci.c21
-rw-r--r--drivers/firmware/qcom_scm.c3
-rw-r--r--drivers/firmware/qemu_fw_cfg.c8
-rw-r--r--drivers/firmware/smccc/smccc.c4
-rw-r--r--drivers/firmware/stratix10-svc.c22
-rw-r--r--drivers/firmware/tegra/Makefile1
-rw-r--r--drivers/firmware/tegra/bpmp-private.h3
-rw-r--r--drivers/firmware/tegra/bpmp-tegra210.c2
-rw-r--r--drivers/firmware/tegra/bpmp.c3
-rw-r--r--drivers/firmware/turris-mox-rwtm.c56
-rw-r--r--drivers/fpga/Kconfig4
-rw-r--r--drivers/fpga/altera-pr-ip-core.c10
-rw-r--r--drivers/fpga/fpga-bridge.c40
-rw-r--r--drivers/fpga/fpga-mgr.c42
-rw-r--r--drivers/fpga/fpga-region.c30
-rw-r--r--drivers/fpga/machxo2-spi.c2
-rw-r--r--drivers/fpga/of-fpga-region.c8
-rw-r--r--drivers/fpga/stratix10-soc.c3
-rw-r--r--drivers/fsi/fsi-core.c4
-rw-r--r--drivers/fsi/fsi-master-aspeed.c33
-rw-r--r--drivers/fsi/fsi-master-ast-cf.c2
-rw-r--r--drivers/fsi/fsi-master-gpio.c1
-rw-r--r--drivers/fsi/fsi-occ.c12
-rw-r--r--drivers/fsi/fsi-sbefifo.c10
-rw-r--r--drivers/fsi/fsi-scom.c105
-rw-r--r--drivers/gpio/Kconfig16
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-104-idio-16.c23
-rw-r--r--drivers/gpio/gpio-adp5520.c18
-rw-r--r--drivers/gpio/gpio-altera-a10sr.c11
-rw-r--r--drivers/gpio/gpio-ath79.c9
-rw-r--r--drivers/gpio/gpio-bd9571mwv.c11
-rw-r--r--drivers/gpio/gpio-crystalcove.c10
-rw-r--r--drivers/gpio/gpio-da9052.c11
-rw-r--r--drivers/gpio/gpio-da9055.c11
-rw-r--r--drivers/gpio/gpio-dwapb.c23
-rw-r--r--drivers/gpio/gpio-idt3243x.c206
-rw-r--r--drivers/gpio/gpio-logicvc.c4
-rw-r--r--drivers/gpio/gpio-lp87565.c6
-rw-r--r--drivers/gpio/gpio-mockup.c9
-rw-r--r--drivers/gpio/gpio-mxc.c2
-rw-r--r--drivers/gpio/gpio-mxs.c4
-rw-r--r--drivers/gpio/gpio-pca953x.c1
-rw-r--r--drivers/gpio/gpio-regmap.c32
-rw-r--r--drivers/gpio/gpio-spear-spics.c12
-rw-r--r--drivers/gpio/gpio-sprd.c10
-rw-r--r--drivers/gpio/gpio-sta2x11.c10
-rw-r--r--drivers/gpio/gpio-stmpe.c32
-rw-r--r--drivers/gpio/gpio-tc3589x.c11
-rw-r--r--drivers/gpio/gpio-tegra186.c14
-rw-r--r--drivers/gpio/gpio-tps65218.c13
-rw-r--r--drivers/gpio/gpio-tps6586x.c13
-rw-r--r--drivers/gpio/gpio-tps65910.c12
-rw-r--r--drivers/gpio/gpio-tps65912.c12
-rw-r--r--drivers/gpio/gpio-tps68470.c12
-rw-r--r--drivers/gpio/gpio-visconti.c10
-rw-r--r--drivers/gpio/gpio-wcove.c39
-rw-r--r--drivers/gpio/gpio-wm831x.c12
-rw-r--r--drivers/gpio/gpio-wm8350.c12
-rw-r--r--drivers/gpio/gpio-wm8994.c13
-rw-r--r--drivers/gpio/gpio-xgene.c11
-rw-r--r--drivers/gpio/gpio-xilinx.c391
-rw-r--r--drivers/gpio/gpio-zynq.c32
-rw-r--r--drivers/gpio/gpiolib-acpi.c61
-rw-r--r--drivers/gpio/gpiolib-cdev.c1
-rw-r--r--drivers/gpio/gpiolib-sysfs.c34
-rw-r--r--drivers/gpio/gpiolib.c59
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c22
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c37
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c14
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c18
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c49
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h14
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c21
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/athub_v2_0.c12
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_virtual.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c266
-rw-r--r--drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c85
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c51
-rw-r--r--drivers/gpu/drm/amd/amdgpu/nv.c37
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/smuio_v11_0.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/soc15.c10
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c45
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_migrate.c100
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_priv.h9
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process.c275
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c1
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_svm.c242
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_svm.h19
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c15
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c31
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/Makefile2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/Makefile8
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/irq_service.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq_types.h2
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c60
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h16
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c5
-rw-r--r--drivers/gpu/drm/amd/include/amd_shared.h10
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/mp/mp_13_0_1_offset.h355
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/mp/mp_13_0_1_sh_mask.h531
-rw-r--r--drivers/gpu/drm/amd/include/navi10_enum.h2
-rw-r--r--drivers/gpu/drm/amd/pm/amdgpu_pm.c95
-rw-r--r--drivers/gpu/drm/amd/pm/inc/smu_v13_0.h1
-rw-r--r--drivers/gpu/drm/amd/pm/inc/smu_v13_0_1.h57
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c8
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c1
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c24
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_1.c311
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c52
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c17
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c1
-rw-r--r--drivers/gpu/drm/gma500/framebuffer.c7
-rw-r--r--drivers/gpu/drm/i915/Kconfig2
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_shrinker.c1
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c2
-rw-r--r--drivers/gpu/drm/i915/gt/gen8_ppgtt.c5
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_cs.c2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_ring_submission.c7
-rw-r--r--drivers/gpu/drm/i915/gvt/kvmgt.c11
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c1
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c10
-rw-r--r--drivers/gpu/drm/i915/i915_irq.h1
-rw-r--r--drivers/gpu/drm/kmb/kmb_drv.c1
-rw-r--r--drivers/gpu/drm/lima/lima_trace.h2
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c2
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if000c.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_prime.c17
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_svm.c156
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c1
-rw-r--r--drivers/gpu/drm/panel/panel-novatek-nt35510.c4
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-ld9040.c1
-rw-r--r--drivers/gpu/drm/qxl/qxl_ttm.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c29
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_prime.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c13
-rw-r--r--drivers/gpu/drm/ttm/ttm_range_manager.c3
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c44
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_mob.c1
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_client.c43
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_hid.h12
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_pcie.c89
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_pcie.h43
-rw-r--r--drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c48
-rw-r--r--drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h11
-rw-r--r--drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h112
-rw-r--r--drivers/hid/hid-core.c10
-rw-r--r--drivers/hid/hid-debug.c11
-rw-r--r--drivers/hid/hid-google-hammer.c10
-rw-r--r--drivers/hid/hid-ids.h2
-rw-r--r--drivers/hid/hid-input.c30
-rw-r--r--drivers/hid/hid-ite.c1
-rw-r--r--drivers/hid/hid-lg-g15.c141
-rw-r--r--drivers/hid/hid-logitech-dj.c16
-rw-r--r--drivers/hid/hid-logitech-hidpp.c12
-rw-r--r--drivers/hid/hid-multitouch.c3
-rw-r--r--drivers/hid/hid-sony.c98
-rw-r--r--drivers/hid/hid-thrustmaster.c5
-rw-r--r--drivers/hid/intel-ish-hid/Kconfig1
-rw-r--r--drivers/hid/intel-ish-hid/ipc/ipc.c28
-rw-r--r--drivers/hid/intel-ish-hid/ipc/pci-ish.c3
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-fw-loader.c51
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-hid-client.c15
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-hid.c2
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-hid.h9
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/bus.c24
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/client.c23
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/hbm.c10
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/hbm.h1
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h5
-rw-r--r--drivers/hid/surface-hid/surface_hid.c2
-rw-r--r--drivers/hid/usbhid/hid-core.c8
-rw-r--r--drivers/hid/usbhid/usbkbd.c4
-rw-r--r--drivers/hid/usbhid/usbmouse.c2
-rw-r--r--drivers/hid/wacom_wac.h2
-rw-r--r--drivers/hv/Makefile3
-rw-r--r--drivers/hv/channel.c23
-rw-r--r--drivers/hv/connection.c4
-rw-r--r--drivers/hv/hv_balloon.c1
-rw-r--r--drivers/hv/hv_common.c66
-rw-r--r--drivers/hv/hv_fcopy.c1
-rw-r--r--drivers/hv/hv_kvp.c1
-rw-r--r--drivers/hv/hv_util.c4
-rw-r--r--drivers/hv/hyperv_vmbus.h2
-rw-r--r--drivers/hv/ring_buffer.c95
-rw-r--r--drivers/hv/vmbus_drv.c1
-rw-r--r--drivers/hwmon/Kconfig11
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/bt1-pvt.c4
-rw-r--r--drivers/hwmon/corsair-cpro.c1
-rw-r--r--drivers/hwmon/hwmon.c36
-rw-r--r--drivers/hwmon/ina3221.c22
-rw-r--r--drivers/hwmon/lm70.c28
-rw-r--r--drivers/hwmon/lm75.c13
-rw-r--r--drivers/hwmon/lm90.c92
-rw-r--r--drivers/hwmon/max31722.c9
-rw-r--r--drivers/hwmon/max31790.c72
-rw-r--r--drivers/hwmon/max6621.c2
-rw-r--r--drivers/hwmon/ntc_thermistor.c4
-rw-r--r--drivers/hwmon/occ/common.c7
-rw-r--r--drivers/hwmon/pmbus/Kconfig34
-rw-r--r--drivers/hwmon/pmbus/Makefile3
-rw-r--r--drivers/hwmon/pmbus/adm1275.c14
-rw-r--r--drivers/hwmon/pmbus/bpa-rs600.c29
-rw-r--r--drivers/hwmon/pmbus/dps920ab.c206
-rw-r--r--drivers/hwmon/pmbus/mp2888.c408
-rw-r--r--drivers/hwmon/pmbus/pim4328.c233
-rw-r--r--drivers/hwmon/pmbus/pmbus.c19
-rw-r--r--drivers/hwmon/pmbus/pmbus.h2
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c151
-rw-r--r--drivers/hwmon/pmbus/zl6100.c94
-rw-r--r--drivers/hwmon/sch5627.c18
-rw-r--r--drivers/hwmon/sch5636.c9
-rw-r--r--drivers/hwmon/sch56xx-common.c65
-rw-r--r--drivers/hwmon/sch56xx-common.h4
-rw-r--r--drivers/hwmon/sht4x.c296
-rw-r--r--drivers/hwspinlock/Kconfig9
-rw-r--r--drivers/hwspinlock/Makefile1
-rw-r--r--drivers/hwspinlock/sun6i_hwspinlock.c210
-rw-r--r--drivers/hwtracing/coresight/coresight-core.c11
-rw-r--r--drivers/hwtracing/coresight/coresight-cpu-debug.c1
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x-core.c5
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etf.c2
-rw-r--r--drivers/hwtracing/intel_th/core.c29
-rw-r--r--drivers/hwtracing/intel_th/gth.c16
-rw-r--r--drivers/hwtracing/intel_th/intel_th.h3
-rw-r--r--drivers/hwtracing/intel_th/msu.c48
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c5
-rw-r--r--drivers/i2c/busses/i2c-aspeed.c12
-rw-r--r--drivers/i2c/busses/i2c-cadence.c57
-rw-r--r--drivers/i2c/busses/i2c-cht-wc.c3
-rw-r--r--drivers/i2c/busses/i2c-cp2615.c14
-rw-r--r--drivers/i2c/busses/i2c-davinci.c5
-rw-r--r--drivers/i2c/busses/i2c-i801.c139
-rw-r--r--drivers/i2c/busses/i2c-imx.c19
-rw-r--r--drivers/i2c/busses/i2c-mpc.c2
-rw-r--r--drivers/i2c/busses/i2c-mt65xx.c9
-rw-r--r--drivers/i2c/busses/i2c-qcom-cci.c1
-rw-r--r--drivers/i2c/busses/i2c-rcar.c1
-rw-r--r--drivers/i2c/busses/i2c-riic.c23
-rw-r--r--drivers/i2c/busses/i2c-robotfuzz-osif.c4
-rw-r--r--drivers/i2c/busses/i2c-stm32f7.c73
-rw-r--r--drivers/i2c/busses/i2c-xiic.c9
-rw-r--r--drivers/i2c/i2c-core-acpi.c8
-rw-r--r--drivers/i2c/i2c-core-base.c108
-rw-r--r--drivers/i2c/i2c-core-smbus.c12
-rw-r--r--drivers/i2c/i2c-dev.c2
-rw-r--r--drivers/i3c/master/i3c-master-cdns.c2
-rw-r--r--drivers/i3c/master/svc-i3c-master.c3
-rw-r--r--drivers/ide/Kconfig849
-rw-r--r--drivers/ide/Makefile111
-rw-r--r--drivers/ide/aec62xx.c331
-rw-r--r--drivers/ide/ali14xx.c250
-rw-r--r--drivers/ide/alim15x3.c602
-rw-r--r--drivers/ide/amd74xx.c343
-rw-r--r--drivers/ide/atiixp.c212
-rw-r--r--drivers/ide/buddha.c238
-rw-r--r--drivers/ide/cmd640.c848
-rw-r--r--drivers/ide/cmd64x.c452
-rw-r--r--drivers/ide/cs5520.c168
-rw-r--r--drivers/ide/cs5530.c295
-rw-r--r--drivers/ide/cs5535.c216
-rw-r--r--drivers/ide/cs5536.c294
-rw-r--r--drivers/ide/cy82c693.c234
-rw-r--r--drivers/ide/delkin_cb.c181
-rw-r--r--drivers/ide/dtc2278.c155
-rw-r--r--drivers/ide/falconide.c197
-rw-r--r--drivers/ide/gayle.c188
-rw-r--r--drivers/ide/hpt366.c1545
-rw-r--r--drivers/ide/ht6560b.c383
-rw-r--r--drivers/ide/icside.c692
-rw-r--r--drivers/ide/ide-4drives.c65
-rw-r--r--drivers/ide/ide-acpi.c622
-rw-r--r--drivers/ide/ide-atapi.c756
-rw-r--r--drivers/ide/ide-cd.c1858
-rw-r--r--drivers/ide/ide-cd.h123
-rw-r--r--drivers/ide/ide-cd_ioctl.c468
-rw-r--r--drivers/ide/ide-cd_verbose.c362
-rw-r--r--drivers/ide/ide-cs.c364
-rw-r--r--drivers/ide/ide-devsets.c192
-rw-r--r--drivers/ide/ide-disk.c795
-rw-r--r--drivers/ide/ide-disk.h30
-rw-r--r--drivers/ide/ide-disk_ioctl.c33
-rw-r--r--drivers/ide/ide-disk_proc.c125
-rw-r--r--drivers/ide/ide-dma-sff.c336
-rw-r--r--drivers/ide/ide-dma.c551
-rw-r--r--drivers/ide/ide-eh.c443
-rw-r--r--drivers/ide/ide-floppy.c551
-rw-r--r--drivers/ide/ide-floppy.h42
-rw-r--r--drivers/ide/ide-floppy_ioctl.c339
-rw-r--r--drivers/ide/ide-floppy_proc.c34
-rw-r--r--drivers/ide/ide-gd.c432
-rw-r--r--drivers/ide/ide-gd.h43
-rw-r--r--drivers/ide/ide-generic.c139
-rw-r--r--drivers/ide/ide-io-std.c262
-rw-r--r--drivers/ide/ide-io.c904
-rw-r--r--drivers/ide/ide-ioctls.c306
-rw-r--r--drivers/ide/ide-iops.c536
-rw-r--r--drivers/ide/ide-legacy.c59
-rw-r--r--drivers/ide/ide-lib.c146
-rw-r--r--drivers/ide/ide-park.c155
-rw-r--r--drivers/ide/ide-pci-generic.c203
-rw-r--r--drivers/ide/ide-pio-blacklist.c96
-rw-r--r--drivers/ide/ide-pm.c261
-rw-r--r--drivers/ide/ide-pnp.c92
-rw-r--r--drivers/ide/ide-probe.c1623
-rw-r--r--drivers/ide/ide-proc.c633
-rw-r--r--drivers/ide/ide-scan-pci.c113
-rw-r--r--drivers/ide/ide-sysfs.c143
-rw-r--r--drivers/ide/ide-tape.c2083
-rw-r--r--drivers/ide/ide-taskfile.c668
-rw-r--r--drivers/ide/ide-timings.c198
-rw-r--r--drivers/ide/ide-xfer-mode.c267
-rw-r--r--drivers/ide/ide.c415
-rw-r--r--drivers/ide/ide_platform.c133
-rw-r--r--drivers/ide/it8172.c165
-rw-r--r--drivers/ide/it8213.c217
-rw-r--r--drivers/ide/it821x.c715
-rw-r--r--drivers/ide/jmicron.c176
-rw-r--r--drivers/ide/macide.c161
-rw-r--r--drivers/ide/ns87415.c350
-rw-r--r--drivers/ide/opti621.c179
-rw-r--r--drivers/ide/palm_bk3710.c387
-rw-r--r--drivers/ide/pdc202xx_new.c557
-rw-r--r--drivers/ide/pdc202xx_old.c362
-rw-r--r--drivers/ide/piix.c476
-rw-r--r--drivers/ide/pmac.c1703
-rw-r--r--drivers/ide/q40ide.c168
-rw-r--r--drivers/ide/qd65xx.c446
-rw-r--r--drivers/ide/qd65xx.h145
-rw-r--r--drivers/ide/rapide.c106
-rw-r--r--drivers/ide/rz1000.c100
-rw-r--r--drivers/ide/sc1200.c355
-rw-r--r--drivers/ide/serverworks.c456
-rw-r--r--drivers/ide/setup-pci.c682
-rw-r--r--drivers/ide/siimage.c843
-rw-r--r--drivers/ide/sis5513.c637
-rw-r--r--drivers/ide/sl82c105.c367
-rw-r--r--drivers/ide/slc90e66.c182
-rw-r--r--drivers/ide/tc86c001.c270
-rw-r--r--drivers/ide/triflex.c143
-rw-r--r--drivers/ide/trm290.c374
-rw-r--r--drivers/ide/tx4938ide.c209
-rw-r--r--drivers/ide/tx4939ide.c628
-rw-r--r--drivers/ide/umc8672.c184
-rw-r--r--drivers/ide/via82cxxx.c532
-rw-r--r--drivers/idle/intel_idle.c33
-rw-r--r--drivers/iio/accel/Kconfig51
-rw-r--r--drivers/iio/accel/Makefile4
-rw-r--r--drivers/iio/accel/adis16201.c3
-rw-r--r--drivers/iio/accel/adis16209.c3
-rw-r--r--drivers/iio/accel/adxl372.c4
-rw-r--r--drivers/iio/accel/bma180.c112
-rw-r--r--drivers/iio/accel/bma220_spi.c10
-rw-r--r--drivers/iio/accel/bma400_core.c2
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c234
-rw-r--r--drivers/iio/accel/bmc150-accel-i2c.c245
-rw-r--r--drivers/iio/accel/bmc150-accel-spi.c31
-rw-r--r--drivers/iio/accel/bmc150-accel.h72
-rw-r--r--drivers/iio/accel/bmi088-accel-core.c27
-rw-r--r--drivers/iio/accel/fxls8962af-core.c968
-rw-r--r--drivers/iio/accel/fxls8962af-i2c.c57
-rw-r--r--drivers/iio/accel/fxls8962af-spi.c57
-rw-r--r--drivers/iio/accel/fxls8962af.h22
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c19
-rw-r--r--drivers/iio/accel/kxcjk-1013.c253
-rw-r--r--drivers/iio/accel/kxsd9.c2
-rw-r--r--drivers/iio/accel/mma8452.c7
-rw-r--r--drivers/iio/accel/mma9551.c1
-rw-r--r--drivers/iio/accel/mma9551_core.c4
-rw-r--r--drivers/iio/accel/mma9553.c1
-rw-r--r--drivers/iio/accel/mxc4005.c12
-rw-r--r--drivers/iio/accel/sca3300.c472
-rw-r--r--drivers/iio/accel/st_accel.h12
-rw-r--r--drivers/iio/accel/st_accel_core.c230
-rw-r--r--drivers/iio/accel/st_accel_i2c.c17
-rw-r--r--drivers/iio/accel/st_accel_spi.c17
-rw-r--r--drivers/iio/accel/stk8312.c27
-rw-r--r--drivers/iio/accel/stk8ba50.c19
-rw-r--r--drivers/iio/adc/Kconfig12
-rw-r--r--drivers/iio/adc/Makefile1
-rw-r--r--drivers/iio/adc/ad7124.c48
-rw-r--r--drivers/iio/adc/ad7192.c93
-rw-r--r--drivers/iio/adc/ad7298.c8
-rw-r--r--drivers/iio/adc/ad7476.c120
-rw-r--r--drivers/iio/adc/ad7606.c3
-rw-r--r--drivers/iio/adc/ad7766.c10
-rw-r--r--drivers/iio/adc/ad7768-1.c4
-rw-r--r--drivers/iio/adc/ad7780.c38
-rw-r--r--drivers/iio/adc/ad7791.c44
-rw-r--r--drivers/iio/adc/ad7793.c53
-rw-r--r--drivers/iio/adc/ad7887.c1
-rw-r--r--drivers/iio/adc/ad9467.c2
-rw-r--r--drivers/iio/adc/ad_sigma_delta.c82
-rw-r--r--drivers/iio/adc/adi-axi-adc.c24
-rw-r--r--drivers/iio/adc/at91-sama5d2_adc.c5
-rw-r--r--drivers/iio/adc/at91_adc.c4
-rw-r--r--drivers/iio/adc/dln2-adc.c3
-rw-r--r--drivers/iio/adc/ep93xx_adc.c4
-rw-r--r--drivers/iio/adc/exynos_adc.c2
-rw-r--r--drivers/iio/adc/hi8435.c1
-rw-r--r--drivers/iio/adc/hx711.c4
-rw-r--r--drivers/iio/adc/ina2xx-adc.c3
-rw-r--r--drivers/iio/adc/max1027.c2
-rw-r--r--drivers/iio/adc/max11100.c34
-rw-r--r--drivers/iio/adc/max1118.c68
-rw-r--r--drivers/iio/adc/max1241.c2
-rw-r--r--drivers/iio/adc/mp2629_adc.c1
-rw-r--r--drivers/iio/adc/mt6360-adc.c1
-rw-r--r--drivers/iio/adc/mxs-lradc-adc.c5
-rw-r--r--drivers/iio/adc/rcar-gyroadc.c15
-rw-r--r--drivers/iio/adc/sc27xx_adc.c1
-rw-r--r--drivers/iio/adc/stm32-adc.c28
-rw-r--r--drivers/iio/adc/stm32-dfsdm-core.c6
-rw-r--r--drivers/iio/adc/ti-adc081c.c43
-rw-r--r--drivers/iio/adc/ti-adc0832.c39
-rw-r--r--drivers/iio/adc/ti-adc084s021.c3
-rw-r--r--drivers/iio/adc/ti-adc108s102.c45
-rw-r--r--drivers/iio/adc/ti-adc161s626.c51
-rw-r--r--drivers/iio/adc/ti-ads1015.c17
-rw-r--r--drivers/iio/adc/ti-ads124s08.c2
-rw-r--r--drivers/iio/adc/ti-ads131e08.c3
-rw-r--r--drivers/iio/adc/ti-ads8688.c3
-rw-r--r--drivers/iio/adc/ti-tsc2046.c712
-rw-r--r--drivers/iio/adc/vf610_adc.c10
-rw-r--r--drivers/iio/adc/xilinx-xadc-core.c2
-rw-r--r--drivers/iio/afe/iio-rescale.c41
-rw-r--r--drivers/iio/buffer/industrialio-buffer-dmaengine.c22
-rw-r--r--drivers/iio/buffer/industrialio-hw-consumer.c25
-rw-r--r--drivers/iio/buffer/industrialio-triggered-buffer.c23
-rw-r--r--drivers/iio/chemical/Kconfig27
-rw-r--r--drivers/iio/chemical/Makefile2
-rw-r--r--drivers/iio/chemical/atlas-sensor.c19
-rw-r--r--drivers/iio/chemical/bme680_i2c.c8
-rw-r--r--drivers/iio/chemical/bme680_spi.c8
-rw-r--r--drivers/iio/chemical/ccs811.c2
-rw-r--r--drivers/iio/chemical/scd30_core.c3
-rw-r--r--drivers/iio/chemical/sgp30.c2
-rw-r--r--drivers/iio/chemical/sps30.c275
-rw-r--r--drivers/iio/chemical/sps30.h35
-rw-r--r--drivers/iio/chemical/sps30_i2c.c258
-rw-r--r--drivers/iio/chemical/sps30_serial.c431
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-attributes.c32
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c24
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.h3
-rw-r--r--drivers/iio/common/scmi_sensors/Makefile2
-rw-r--r--drivers/iio/common/scmi_sensors/scmi_iio.c1
-rw-r--r--drivers/iio/dac/ad5766.c2
-rw-r--r--drivers/iio/dac/stm32-dac.c3
-rw-r--r--drivers/iio/dummy/Kconfig1
-rw-r--r--drivers/iio/frequency/adf4350.c6
-rw-r--r--drivers/iio/gyro/adis16136.c20
-rw-r--r--drivers/iio/gyro/adis16260.c9
-rw-r--r--drivers/iio/gyro/adxrs290.c2
-rw-r--r--drivers/iio/gyro/bmg160_core.c17
-rw-r--r--drivers/iio/gyro/fxas21002c_core.c13
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c6
-rw-r--r--drivers/iio/gyro/itg3200_buffer.c2
-rw-r--r--drivers/iio/gyro/itg3200_core.c3
-rw-r--r--drivers/iio/gyro/mpu3050-core.c4
-rw-r--r--drivers/iio/gyro/st_gyro.h12
-rw-r--r--drivers/iio/gyro/st_gyro_core.c53
-rw-r--r--drivers/iio/gyro/st_gyro_i2c.c17
-rw-r--r--drivers/iio/gyro/st_gyro_spi.c17
-rw-r--r--drivers/iio/health/afe4403.c2
-rw-r--r--drivers/iio/health/afe4404.c2
-rw-r--r--drivers/iio/humidity/am2315.c25
-rw-r--r--drivers/iio/humidity/hdc2010.c1
-rw-r--r--drivers/iio/humidity/hid-sensor-humidity.c2
-rw-r--r--drivers/iio/imu/Kconfig1
-rw-r--r--drivers/iio/imu/Makefile1
-rw-r--r--drivers/iio/imu/adis.c4
-rw-r--r--drivers/iio/imu/adis16400.c27
-rw-r--r--drivers/iio/imu/adis16460.c3
-rw-r--r--drivers/iio/imu/adis16475.c11
-rw-r--r--drivers/iio/imu/adis16480.c166
-rw-r--r--drivers/iio/imu/adis_buffer.c27
-rw-r--r--drivers/iio/imu/adis_trigger.c3
-rw-r--r--drivers/iio/imu/bmi160/bmi160_core.c6
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_core.c2
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c27
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c8
-rw-r--r--drivers/iio/imu/kmx61.c7
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c8
-rw-r--r--drivers/iio/imu/st_lsm9ds0/Kconfig28
-rw-r--r--drivers/iio/imu/st_lsm9ds0/Makefile5
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h23
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c163
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c84
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c83
-rw-r--r--drivers/iio/industrialio-buffer.c13
-rw-r--r--drivers/iio/industrialio-core.c126
-rw-r--r--drivers/iio/industrialio-trigger.c37
-rw-r--r--drivers/iio/industrialio-triggered-event.c2
-rw-r--r--drivers/iio/inkern.c107
-rw-r--r--drivers/iio/light/Kconfig11
-rw-r--r--drivers/iio/light/Makefile1
-rw-r--r--drivers/iio/light/acpi-als.c3
-rw-r--r--drivers/iio/light/hid-sensor-als.c6
-rw-r--r--drivers/iio/light/hid-sensor-prox.c6
-rw-r--r--drivers/iio/light/isl29028.c5
-rw-r--r--drivers/iio/light/isl29125.c10
-rw-r--r--drivers/iio/light/ltr501.c25
-rw-r--r--drivers/iio/light/pa12203001.c4
-rw-r--r--drivers/iio/light/rpr0521.c9
-rw-r--r--drivers/iio/light/si1133.c18
-rw-r--r--drivers/iio/light/si1145.c12
-rw-r--r--drivers/iio/light/tcs3414.c10
-rw-r--r--drivers/iio/light/tcs3472.c16
-rw-r--r--drivers/iio/light/tsl2583.c13
-rw-r--r--drivers/iio/light/tsl2591.c1225
-rw-r--r--drivers/iio/light/us5182d.c4
-rw-r--r--drivers/iio/light/vcnl4000.c9
-rw-r--r--drivers/iio/light/vcnl4035.c9
-rw-r--r--drivers/iio/light/veml6030.c2
-rw-r--r--drivers/iio/magnetometer/ak8974.c3
-rw-r--r--drivers/iio/magnetometer/ak8975.c2
-rw-r--r--drivers/iio/magnetometer/bmc150_magn.c26
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c7
-rw-r--r--drivers/iio/magnetometer/hmc5843.h8
-rw-r--r--drivers/iio/magnetometer/hmc5843_core.c7
-rw-r--r--drivers/iio/magnetometer/rm3100-core.c5
-rw-r--r--drivers/iio/magnetometer/st_magn.h4
-rw-r--r--drivers/iio/magnetometer/st_magn_core.c181
-rw-r--r--drivers/iio/magnetometer/st_magn_i2c.c14
-rw-r--r--drivers/iio/magnetometer/st_magn_spi.c14
-rw-r--r--drivers/iio/magnetometer/yamaha-yas530.c2
-rw-r--r--drivers/iio/orientation/hid-sensor-incl-3d.c6
-rw-r--r--drivers/iio/orientation/hid-sensor-rotation.c5
-rw-r--r--drivers/iio/position/hid-sensor-custom-intel-hinge.c4
-rw-r--r--drivers/iio/potentiostat/lmp91000.c7
-rw-r--r--drivers/iio/pressure/hid-sensor-press.c6
-rw-r--r--drivers/iio/pressure/icp10100.c5
-rw-r--r--drivers/iio/pressure/st_pressure.h4
-rw-r--r--drivers/iio/pressure/st_pressure_core.c15
-rw-r--r--drivers/iio/pressure/st_pressure_i2c.c17
-rw-r--r--drivers/iio/pressure/st_pressure_spi.c17
-rw-r--r--drivers/iio/pressure/zpa2326.c3
-rw-r--r--drivers/iio/proximity/as3935.c13
-rw-r--r--drivers/iio/proximity/isl29501.c2
-rw-r--r--drivers/iio/proximity/pulsedlight-lidar-lite-v2.c14
-rw-r--r--drivers/iio/proximity/srf04.c8
-rw-r--r--drivers/iio/proximity/srf08.c14
-rw-r--r--drivers/iio/proximity/sx9310.c2
-rw-r--r--drivers/iio/proximity/sx9500.c2
-rw-r--r--drivers/iio/temperature/Kconfig10
-rw-r--r--drivers/iio/temperature/Makefile1
-rw-r--r--drivers/iio/temperature/hid-sensor-temperature.c2
-rw-r--r--drivers/iio/temperature/mlx90614.c25
-rw-r--r--drivers/iio/temperature/tmp117.c185
-rw-r--r--drivers/iio/test/iio-test-format.c2
-rw-r--r--drivers/iio/trigger/stm32-timer-trigger.c2
-rw-r--r--drivers/infiniband/Kconfig2
-rw-r--r--drivers/infiniband/core/cache.c40
-rw-r--r--drivers/infiniband/core/cm.c863
-rw-r--r--drivers/infiniband/core/cma.c48
-rw-r--r--drivers/infiniband/core/core_priv.h15
-rw-r--r--drivers/infiniband/core/counters.c4
-rw-r--r--drivers/infiniband/core/device.c41
-rw-r--r--drivers/infiniband/core/iwcm.c9
-rw-r--r--drivers/infiniband/core/iwcm.h2
-rw-r--r--drivers/infiniband/core/iwpm_msg.c22
-rw-r--r--drivers/infiniband/core/iwpm_util.c16
-rw-r--r--drivers/infiniband/core/iwpm_util.h4
-rw-r--r--drivers/infiniband/core/mad.c27
-rw-r--r--drivers/infiniband/core/mad_priv.h1
-rw-r--r--drivers/infiniband/core/multicast.c20
-rw-r--r--drivers/infiniband/core/netlink.c2
-rw-r--r--drivers/infiniband/core/nldev.c10
-rw-r--r--drivers/infiniband/core/roce_gid_mgmt.c5
-rw-r--r--drivers/infiniband/core/rw.c8
-rw-r--r--drivers/infiniband/core/sa_query.c10
-rw-r--r--drivers/infiniband/core/security.c9
-rw-r--r--drivers/infiniband/core/sysfs.c1110
-rw-r--r--drivers/infiniband/core/ucma.c11
-rw-r--r--drivers/infiniband/core/ud_header.c8
-rw-r--r--drivers/infiniband/core/umem_odp.c2
-rw-r--r--drivers/infiniband/core/user_mad.c4
-rw-r--r--drivers/infiniband/core/uverbs.h2
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c23
-rw-r--r--drivers/infiniband/core/uverbs_main.c12
-rw-r--r--drivers/infiniband/core/uverbs_uapi.c2
-rw-r--r--drivers/infiniband/core/verbs.c23
-rw-r--r--drivers/infiniband/hw/Makefile2
-rw-r--r--drivers/infiniband/hw/bnxt_re/hw_counters.c7
-rw-r--r--drivers/infiniband/hw/bnxt_re/hw_counters.h4
-rw-r--r--drivers/infiniband/hw/bnxt_re/ib_verbs.c30
-rw-r--r--drivers/infiniband/hw/bnxt_re/main.c19
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_fp.h2
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_res.c17
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_res.h7
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_sp.c13
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_sp.h2
-rw-r--r--drivers/infiniband/hw/cxgb4/cq.c6
-rw-r--r--drivers/infiniband/hw/cxgb4/ev.c8
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h2
-rw-r--r--drivers/infiniband/hw/cxgb4/provider.c11
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c2
-rw-r--r--drivers/infiniband/hw/efa/efa.h3
-rw-r--r--drivers/infiniband/hw/efa/efa_main.c3
-rw-r--r--drivers/infiniband/hw/efa/efa_verbs.c11
-rw-r--r--drivers/infiniband/hw/hfi1/chip.c4
-rw-r--r--drivers/infiniband/hw/hfi1/file_ops.c6
-rw-r--r--drivers/infiniband/hw/hfi1/hfi.h9
-rw-r--r--drivers/infiniband/hw/hfi1/init.c4
-rw-r--r--drivers/infiniband/hw/hfi1/pio.c2
-rw-r--r--drivers/infiniband/hw/hfi1/pio.h2
-rw-r--r--drivers/infiniband/hw/hfi1/sdma.c4
-rw-r--r--drivers/infiniband/hw/hfi1/sysfs.c530
-rw-r--r--drivers/infiniband/hw/hfi1/tid_rdma.c2
-rw-r--r--drivers/infiniband/hw/hfi1/trace.c5
-rw-r--r--drivers/infiniband/hw/hfi1/trace_misc.h4
-rw-r--r--drivers/infiniband/hw/hfi1/trace_rc.h4
-rw-r--r--drivers/infiniband/hw/hfi1/trace_tid.h6
-rw-r--r--drivers/infiniband/hw/hfi1/trace_tx.h8
-rw-r--r--drivers/infiniband/hw/hfi1/verbs.c92
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_alloc.c114
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_common.h12
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_cq.c15
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_db.c3
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_device.h72
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hem.c371
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hem.h13
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v1.c79
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v1.h5
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v2.c1983
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v2.h969
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_main.c40
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_mr.c84
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_pd.c94
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_qp.c47
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_srq.c22
-rw-r--r--drivers/infiniband/hw/i40iw/Kconfig9
-rw-r--r--drivers/infiniband/hw/i40iw/Makefile9
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw.h602
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_cm.c4419
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_cm.h462
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_ctrl.c5243
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_d.h1746
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_hmc.c821
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_hmc.h241
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_hw.c851
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_main.c2065
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_osdep.h195
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_p.h129
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_pble.c611
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_pble.h131
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_puda.c1496
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_puda.h188
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_register.h1030
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_status.h101
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_type.h1358
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_uk.c1200
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_user.h422
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_utils.c1518
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_verbs.c2652
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_verbs.h179
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_vf.c85
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_vf.h62
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_virtchnl.c759
-rw-r--r--drivers/infiniband/hw/i40iw/i40iw_virtchnl.h124
-rw-r--r--drivers/infiniband/hw/irdma/Kconfig12
-rw-r--r--drivers/infiniband/hw/irdma/Makefile27
-rw-r--r--drivers/infiniband/hw/irdma/cm.c4421
-rw-r--r--drivers/infiniband/hw/irdma/cm.h417
-rw-r--r--drivers/infiniband/hw/irdma/ctrl.c5657
-rw-r--r--drivers/infiniband/hw/irdma/defs.h1155
-rw-r--r--drivers/infiniband/hw/irdma/hmc.c710
-rw-r--r--drivers/infiniband/hw/irdma/hmc.h180
-rw-r--r--drivers/infiniband/hw/irdma/hw.c2725
-rw-r--r--drivers/infiniband/hw/irdma/i40iw_hw.c216
-rw-r--r--drivers/infiniband/hw/irdma/i40iw_hw.h160
-rw-r--r--drivers/infiniband/hw/irdma/i40iw_if.c216
-rw-r--r--drivers/infiniband/hw/irdma/icrdma_hw.c149
-rw-r--r--drivers/infiniband/hw/irdma/icrdma_hw.h71
-rw-r--r--drivers/infiniband/hw/irdma/irdma.h153
-rw-r--r--drivers/infiniband/hw/irdma/main.c358
-rw-r--r--drivers/infiniband/hw/irdma/main.h555
-rw-r--r--drivers/infiniband/hw/irdma/osdep.h86
-rw-r--r--drivers/infiniband/hw/irdma/pble.c520
-rw-r--r--drivers/infiniband/hw/irdma/pble.h136
-rw-r--r--drivers/infiniband/hw/irdma/protos.h116
-rw-r--r--drivers/infiniband/hw/irdma/puda.c1744
-rw-r--r--drivers/infiniband/hw/irdma/puda.h194
-rw-r--r--drivers/infiniband/hw/irdma/status.h71
-rw-r--r--drivers/infiniband/hw/irdma/trace.c112
-rw-r--r--drivers/infiniband/hw/irdma/trace.h3
-rw-r--r--drivers/infiniband/hw/irdma/trace_cm.h458
-rw-r--r--drivers/infiniband/hw/irdma/type.h1541
-rw-r--r--drivers/infiniband/hw/irdma/uda.c271
-rw-r--r--drivers/infiniband/hw/irdma/uda.h89
-rw-r--r--drivers/infiniband/hw/irdma/uda_d.h128
-rw-r--r--drivers/infiniband/hw/irdma/uk.c1684
-rw-r--r--drivers/infiniband/hw/irdma/user.h437
-rw-r--r--drivers/infiniband/hw/irdma/utils.c2541
-rw-r--r--drivers/infiniband/hw/irdma/verbs.c4544
-rw-r--r--drivers/infiniband/hw/irdma/verbs.h225
-rw-r--r--drivers/infiniband/hw/irdma/ws.c406
-rw-r--r--drivers/infiniband/hw/irdma/ws.h41
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c8
-rw-r--r--drivers/infiniband/hw/mlx4/main.c27
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c11
-rw-r--r--drivers/infiniband/hw/mlx5/counters.c42
-rw-r--r--drivers/infiniband/hw/mlx5/cq.c10
-rw-r--r--drivers/infiniband/hw/mlx5/doorbell.c3
-rw-r--r--drivers/infiniband/hw/mlx5/fs.c9
-rw-r--r--drivers/infiniband/hw/mlx5/main.c19
-rw-r--r--drivers/infiniband/hw/mlx5/mlx5_ib.h12
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c12
-rw-r--r--drivers/infiniband/hw/mlx5/odp.c13
-rw-r--r--drivers/infiniband/hw/mlx5/qp.c177
-rw-r--r--drivers/infiniband/hw/mlx5/qpc.c6
-rw-r--r--drivers/infiniband/hw/mlx5/srq.c2
-rw-r--r--drivers/infiniband/hw/mlx5/wr.c14
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c2
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_main.c2
-rw-r--r--drivers/infiniband/hw/qedr/main.c2
-rw-r--r--drivers/infiniband/hw/qib/qib.h8
-rw-r--r--drivers/infiniband/hw/qib/qib_sysfs.c616
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.c6
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib_main.c3
-rw-r--r--drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c2
-rw-r--r--drivers/infiniband/sw/rdmavt/mr.c4
-rw-r--r--drivers/infiniband/sw/rdmavt/qp.c3
-rw-r--r--drivers/infiniband/sw/rdmavt/trace_cq.h4
-rw-r--r--drivers/infiniband/sw/rdmavt/trace_mr.h2
-rw-r--r--drivers/infiniband/sw/rdmavt/trace_qp.h4
-rw-r--r--drivers/infiniband/sw/rdmavt/trace_rc.h2
-rw-r--r--drivers/infiniband/sw/rdmavt/trace_tx.h4
-rw-r--r--drivers/infiniband/sw/rdmavt/vt.c6
-rw-r--r--drivers/infiniband/sw/rxe/Makefile1
-rw-r--r--drivers/infiniband/sw/rxe/rxe.c1
-rw-r--r--drivers/infiniband/sw/rxe/rxe_comp.c36
-rw-r--r--drivers/infiniband/sw/rxe/rxe_cq.c32
-rw-r--r--drivers/infiniband/sw/rxe/rxe_hw_counters.c7
-rw-r--r--drivers/infiniband/sw/rxe/rxe_hw_counters.h4
-rw-r--r--drivers/infiniband/sw/rxe/rxe_loc.h38
-rw-r--r--drivers/infiniband/sw/rxe/rxe_mr.c130
-rw-r--r--drivers/infiniband/sw/rxe/rxe_mw.c343
-rw-r--r--drivers/infiniband/sw/rxe/rxe_net.c14
-rw-r--r--drivers/infiniband/sw/rxe/rxe_opcode.c11
-rw-r--r--drivers/infiniband/sw/rxe/rxe_opcode.h3
-rw-r--r--drivers/infiniband/sw/rxe/rxe_param.h19
-rw-r--r--drivers/infiniband/sw/rxe/rxe_pool.c45
-rw-r--r--drivers/infiniband/sw/rxe/rxe_pool.h8
-rw-r--r--drivers/infiniband/sw/rxe/rxe_qp.c23
-rw-r--r--drivers/infiniband/sw/rxe/rxe_queue.c21
-rw-r--r--drivers/infiniband/sw/rxe/rxe_queue.h272
-rw-r--r--drivers/infiniband/sw/rxe/rxe_req.c159
-rw-r--r--drivers/infiniband/sw/rxe/rxe_resp.c208
-rw-r--r--drivers/infiniband/sw/rxe/rxe_srq.c5
-rw-r--r--drivers/infiniband/sw/rxe/rxe_verbs.c101
-rw-r--r--drivers/infiniband/sw/rxe/rxe_verbs.h53
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c8
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c48
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c4
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c2
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c2
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c18
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.h3
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs-clt-sysfs.c5
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs-clt.c254
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs-clt.h6
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs-pri.h27
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs-srv-stats.c12
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c1
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs-srv.c199
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs-srv.h4
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs.c53
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs.h2
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c258
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h2
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c1
-rw-r--r--drivers/input/Kconfig1
-rw-r--r--drivers/input/evbug.c3
-rw-r--r--drivers/input/gameport/Kconfig1
-rw-r--r--drivers/input/joydev.c2
-rw-r--r--drivers/input/joystick/Kconfig10
-rw-r--r--drivers/input/joystick/Makefile1
-rw-r--r--drivers/input/joystick/qwiic-joystick.c146
-rw-r--r--drivers/input/joystick/sidewinder.c1
-rw-r--r--drivers/input/joystick/xpad.c6
-rw-r--r--drivers/input/keyboard/Kconfig3
-rw-r--r--drivers/input/keyboard/atkbd.c2
-rw-r--r--drivers/input/keyboard/cros_ec_keyb.c2
-rw-r--r--drivers/input/keyboard/hil_kbd.c1
-rw-r--r--drivers/input/misc/ims-pcu.c6
-rw-r--r--drivers/input/misc/pm8941-pwrkey.c103
-rw-r--r--drivers/input/mouse/trackpoint.c2
-rw-r--r--drivers/input/serio/i8042.c4
-rw-r--r--drivers/input/serio/serport.c8
-rw-r--r--drivers/input/touchscreen/cy8ctmg110_ts.c167
-rw-r--r--drivers/input/touchscreen/cyttsp_core.c47
-rw-r--r--drivers/input/touchscreen/cyttsp_core.h3
-rw-r--r--drivers/input/touchscreen/cyttsp_i2c.c10
-rw-r--r--drivers/input/touchscreen/cyttsp_spi.c10
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c38
-rw-r--r--drivers/input/touchscreen/elants_i2c.c11
-rw-r--r--drivers/input/touchscreen/goodix.c52
-rw-r--r--drivers/input/touchscreen/hideep.c13
-rw-r--r--drivers/input/touchscreen/resistive-adc-touch.c136
-rw-r--r--drivers/input/touchscreen/tsc200x-core.c2
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c8
-rw-r--r--drivers/interconnect/qcom/Kconfig9
-rw-r--r--drivers/interconnect/qcom/Makefile2
-rw-r--r--drivers/interconnect/qcom/sc7280.c1938
-rw-r--r--drivers/interconnect/qcom/sc7280.h154
-rw-r--r--drivers/iommu/Kconfig4
-rw-r--r--drivers/iommu/amd/amd_iommu.h2
-rw-r--r--drivers/iommu/amd/init.c20
-rw-r--r--drivers/iommu/amd/iommu.c33
-rw-r--r--drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c59
-rw-r--r--drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c224
-rw-r--r--drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h48
-rw-r--r--drivers/iommu/arm/arm-smmu/arm-smmu-impl.c3
-rw-r--r--drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c90
-rw-r--r--drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c43
-rw-r--r--drivers/iommu/arm/arm-smmu/arm-smmu.c39
-rw-r--r--drivers/iommu/arm/arm-smmu/arm-smmu.h1
-rw-r--r--drivers/iommu/arm/arm-smmu/qcom_iommu.c1
-rw-r--r--drivers/iommu/dma-iommu.c19
-rw-r--r--drivers/iommu/exynos-iommu.c1
-rw-r--r--drivers/iommu/intel/Kconfig6
-rw-r--r--drivers/iommu/intel/Makefile1
-rw-r--r--drivers/iommu/intel/debugfs.c111
-rw-r--r--drivers/iommu/intel/dmar.c54
-rw-r--r--drivers/iommu/intel/iommu.c206
-rw-r--r--drivers/iommu/intel/pasid.c2
-rw-r--r--drivers/iommu/intel/perf.c166
-rw-r--r--drivers/iommu/intel/perf.h73
-rw-r--r--drivers/iommu/intel/svm.c643
-rw-r--r--drivers/iommu/iommu.c3
-rw-r--r--drivers/iommu/iova.c18
-rw-r--r--drivers/iommu/ipmmu-vmsa.c1
-rw-r--r--drivers/iommu/msm_iommu.c1
-rw-r--r--drivers/iommu/mtk_iommu.c1
-rw-r--r--drivers/iommu/mtk_iommu_v1.c1
-rw-r--r--drivers/iommu/of_iommu.c68
-rw-r--r--drivers/iommu/omap-iommu.c1
-rw-r--r--drivers/iommu/rockchip-iommu.c177
-rw-r--r--drivers/iommu/tegra-smmu.c16
-rw-r--r--drivers/iommu/virtio-iommu.c12
-rw-r--r--drivers/ipack/carriers/tpci200.c9
-rw-r--r--drivers/ipack/carriers/tpci200.h4
-rw-r--r--drivers/ipack/devices/ipoctal.c8
-rw-r--r--drivers/ipack/devices/ipoctal.h6
-rw-r--r--drivers/irqchip/Kconfig2
-rw-r--r--drivers/irqchip/exynos-combiner.c14
-rw-r--r--drivers/irqchip/irq-al-fic.c7
-rw-r--r--drivers/irqchip/irq-apple-aic.c9
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c19
-rw-r--r--drivers/irqchip/irq-aspeed-i2c-ic.c8
-rw-r--r--drivers/irqchip/irq-aspeed-scu-ic.c6
-rw-r--r--drivers/irqchip/irq-ath79-misc.c2
-rw-r--r--drivers/irqchip/irq-bcm2835.c2
-rw-r--r--drivers/irqchip/irq-bcm2836.c2
-rw-r--r--drivers/irqchip/irq-bcm7038-l1.c6
-rw-r--r--drivers/irqchip/irq-bcm7120-l2.c6
-rw-r--r--drivers/irqchip/irq-brcmstb-l2.c2
-rw-r--r--drivers/irqchip/irq-dw-apb-ictl.c3
-rw-r--r--drivers/irqchip/irq-gic-common.c13
-rw-r--r--drivers/irqchip/irq-gic-common.h2
-rw-r--r--drivers/irqchip/irq-gic-pm.c4
-rw-r--r--drivers/irqchip/irq-gic-v2m.c4
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c8
-rw-r--r--drivers/irqchip/irq-gic-v3.c6
-rw-r--r--drivers/irqchip/irq-gic.c19
-rw-r--r--drivers/irqchip/irq-goldfish-pic.c5
-rw-r--r--drivers/irqchip/irq-i8259.c4
-rw-r--r--drivers/irqchip/irq-idt3243x.c6
-rw-r--r--drivers/irqchip/irq-imgpdc.c19
-rw-r--r--drivers/irqchip/irq-imx-gpcv2.c4
-rw-r--r--drivers/irqchip/irq-imx-intmux.c9
-rw-r--r--drivers/irqchip/irq-imx-irqsteer.c9
-rw-r--r--drivers/irqchip/irq-ingenic-tcu.c2
-rw-r--r--drivers/irqchip/irq-ingenic.c3
-rw-r--r--drivers/irqchip/irq-keystone.c14
-rw-r--r--drivers/irqchip/irq-loongson-htpic.c2
-rw-r--r--drivers/irqchip/irq-loongson-htvec.c4
-rw-r--r--drivers/irqchip/irq-loongson-liointc.c2
-rw-r--r--drivers/irqchip/irq-lpc32xx.c2
-rw-r--r--drivers/irqchip/irq-ls-scfg-msi.c6
-rw-r--r--drivers/irqchip/irq-ls1x.c2
-rw-r--r--drivers/irqchip/irq-mbigen.c12
-rw-r--r--drivers/irqchip/irq-mips-cpu.c10
-rw-r--r--drivers/irqchip/irq-mips-gic.c21
-rw-r--r--drivers/irqchip/irq-mscc-ocelot.c2
-rw-r--r--drivers/irqchip/irq-mvebu-pic.c7
-rw-r--r--drivers/irqchip/irq-mvebu-sei.c13
-rw-r--r--drivers/irqchip/irq-nvic.c4
-rw-r--r--drivers/irqchip/irq-orion.c2
-rw-r--r--drivers/irqchip/irq-partition-percpu.c9
-rw-r--r--drivers/irqchip/irq-pic32-evic.c5
-rw-r--r--drivers/irqchip/irq-pruss-intc.c9
-rw-r--r--drivers/irqchip/irq-realtek-rtl.c2
-rw-r--r--drivers/irqchip/irq-renesas-irqc.c2
-rw-r--r--drivers/irqchip/irq-sifive-plic.c8
-rw-r--r--drivers/irqchip/irq-stm32-exti.c10
-rw-r--r--drivers/irqchip/irq-sun4i.c8
-rw-r--r--drivers/irqchip/irq-sunxi-nmi.c3
-rw-r--r--drivers/irqchip/irq-tb10x.c2
-rw-r--r--drivers/irqchip/irq-ti-sci-inta.c9
-rw-r--r--drivers/irqchip/irq-ts4800.c3
-rw-r--r--drivers/irqchip/irq-versatile-fpga.c2
-rw-r--r--drivers/irqchip/irq-vic.c2
-rw-r--r--drivers/irqchip/irq-xilinx-intc.c23
-rw-r--r--drivers/irqchip/qcom-irq-combiner.c6
-rw-r--r--drivers/irqchip/qcom-pdc.c8
-rw-r--r--drivers/isdn/capi/capi.c40
-rw-r--r--drivers/isdn/hardware/mISDN/hfcpci.c2
-rw-r--r--drivers/isdn/mISDN/dsp_pipeline.c46
-rw-r--r--drivers/leds/Kconfig2
-rw-r--r--drivers/leds/blink/leds-lgm-sso.c53
-rw-r--r--drivers/leds/led-class.c6
-rw-r--r--drivers/leds/leds-as3645a.c3
-rw-r--r--drivers/leds/leds-bcm6328.c2
-rw-r--r--drivers/leds/leds-blinkm.c5
-rw-r--r--drivers/leds/leds-el15203000.c37
-rw-r--r--drivers/leds/leds-gpio-register.c1
-rw-r--r--drivers/leds/leds-is31fl32xx.c3
-rw-r--r--drivers/leds/leds-ktd2692.c27
-rw-r--r--drivers/leds/leds-lm3530.c2
-rw-r--r--drivers/leds/leds-lm3532.c7
-rw-r--r--drivers/leds/leds-lm36274.c4
-rw-r--r--drivers/leds/leds-lm3692x.c26
-rw-r--r--drivers/leds/leds-lm3697.c12
-rw-r--r--drivers/leds/leds-lp3944.c6
-rw-r--r--drivers/leds/leds-lp50xx.c2
-rw-r--r--drivers/leds/leds-lp55xx-common.c2
-rw-r--r--drivers/leds/leds-lp8860.c16
-rw-r--r--drivers/leds/leds-lt3593.c8
-rw-r--r--drivers/leds/leds-mlxcpld.c38
-rw-r--r--drivers/leds/leds-mlxreg.c3
-rw-r--r--drivers/leds/leds-pwm.c16
-rw-r--r--drivers/leds/leds-tlc591xx.c8
-rw-r--r--drivers/leds/leds-turris-omnia.c1
-rw-r--r--drivers/leds/trigger/ledtrig-activity.c1
-rw-r--r--drivers/leds/trigger/ledtrig-cpu.c2
-rw-r--r--drivers/leds/trigger/ledtrig-heartbeat.c1
-rw-r--r--drivers/leds/trigger/ledtrig-panic.c1
-rw-r--r--drivers/lightnvm/core.c24
-rw-r--r--drivers/mailbox/Kconfig12
-rw-r--r--drivers/mailbox/Makefile2
-rw-r--r--drivers/mailbox/arm_mhu.c4
-rw-r--r--drivers/mailbox/bcm-flexrm-mailbox.c1
-rw-r--r--drivers/mailbox/bcm-pdc-mailbox.c1
-rw-r--r--drivers/mailbox/bcm2835-mailbox.c1
-rw-r--r--drivers/mailbox/hi3660-mailbox.c2
-rw-r--r--drivers/mailbox/hi6220-mailbox.c2
-rw-r--r--drivers/mailbox/imx-mailbox.c200
-rw-r--r--drivers/mailbox/mailbox-mpfs.c251
-rw-r--r--drivers/mailbox/mtk-cmdq-mailbox.c28
-rw-r--r--drivers/mailbox/qcom-apcs-ipc-mailbox.c8
-rw-r--r--drivers/mailbox/qcom-ipcc.c6
-rw-r--r--drivers/mcb/mcb-lpc.c13
-rw-r--r--drivers/md/Kconfig6
-rw-r--r--drivers/md/Makefile4
-rw-r--r--drivers/md/bcache/super.c15
-rw-r--r--drivers/md/dm-cache-target.c82
-rw-r--r--drivers/md/dm-core.h65
-rw-r--r--drivers/md/dm-crypt.c31
-rw-r--r--drivers/md/dm-era-target.c24
-rw-r--r--drivers/md/dm-flakey.c7
-rw-r--r--drivers/md/dm-io-tracker.h81
-rw-r--r--drivers/md/dm-kcopyd.c41
-rw-r--r--drivers/md/dm-linear.c7
-rw-r--r--drivers/md/dm-ps-io-affinity.c1
-rw-r--r--drivers/md/dm-raid1.c2
-rw-r--r--drivers/md/dm-rq.c9
-rw-r--r--drivers/md/dm-table.c23
-rw-r--r--drivers/md/dm-thin-metadata.c91
-rw-r--r--drivers/md/dm-writecache.c140
-rw-r--r--drivers/md/dm-zone.c660
-rw-r--r--drivers/md/dm-zoned-metadata.c7
-rw-r--r--drivers/md/dm-zoned-reclaim.c2
-rw-r--r--drivers/md/dm.c230
-rw-r--r--drivers/md/dm.h30
-rw-r--r--drivers/md/md-bitmap.c2
-rw-r--r--drivers/md/md-faulty.c2
-rw-r--r--drivers/md/md-linear.c2
-rw-r--r--drivers/md/md-multipath.c2
-rw-r--r--drivers/md/md.c141
-rw-r--r--drivers/md/md.h19
-rw-r--r--drivers/md/persistent-data/dm-array.c52
-rw-r--r--drivers/md/persistent-data/dm-btree-internal.h13
-rw-r--r--drivers/md/persistent-data/dm-btree-remove.c7
-rw-r--r--drivers/md/persistent-data/dm-btree-spine.c16
-rw-r--r--drivers/md/persistent-data/dm-btree.c542
-rw-r--r--drivers/md/persistent-data/dm-btree.h10
-rw-r--r--drivers/md/persistent-data/dm-space-map-common.c534
-rw-r--r--drivers/md/persistent-data/dm-space-map-common.h34
-rw-r--r--drivers/md/persistent-data/dm-space-map-disk.c83
-rw-r--r--drivers/md/persistent-data/dm-space-map-metadata.c105
-rw-r--r--drivers/md/persistent-data/dm-space-map.h18
-rw-r--r--drivers/md/persistent-data/dm-transaction-manager.c61
-rw-r--r--drivers/md/persistent-data/dm-transaction-manager.h22
-rw-r--r--drivers/md/raid0.c3
-rw-r--r--drivers/md/raid1.c15
-rw-r--r--drivers/md/raid1.h1
-rw-r--r--drivers/md/raid10.c6
-rw-r--r--drivers/md/raid10.h1
-rw-r--r--drivers/md/raid5.c63
-rw-r--r--drivers/media/cec/platform/s5p/s5p_cec.c7
-rw-r--r--drivers/media/common/Kconfig4
-rw-r--r--drivers/media/common/Makefile1
-rw-r--r--drivers/media/common/siano/smscoreapi.c22
-rw-r--r--drivers/media/common/siano/smscoreapi.h4
-rw-r--r--drivers/media/common/siano/smsdvb-main.c11
-rw-r--r--drivers/media/common/ttpci-eeprom.c (renamed from drivers/media/pci/ttpci/ttpci-eeprom.c)0
-rw-r--r--drivers/media/common/ttpci-eeprom.h (renamed from drivers/media/pci/ttpci/ttpci-eeprom.h)0
-rw-r--r--drivers/media/common/videobuf2/frame_vector.c2
-rw-r--r--drivers/media/common/videobuf2/videobuf2-v4l2.c14
-rw-r--r--drivers/media/dvb-core/dmxdev.c2
-rw-r--r--drivers/media/dvb-core/dvb_ca_en50221.c1
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c222
-rw-r--r--drivers/media/dvb-core/dvb_net.c25
-rw-r--r--drivers/media/dvb-core/dvbdev.c3
-rw-r--r--drivers/media/dvb-frontends/Kconfig12
-rw-r--r--drivers/media/dvb-frontends/Makefile1
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drxj.h35
-rw-r--r--drivers/media/dvb-frontends/mxl692.c4
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.c4
-rw-r--r--drivers/media/i2c/Kconfig22
-rw-r--r--drivers/media/i2c/Makefile1
-rw-r--r--drivers/media/i2c/adv7170.c6
-rw-r--r--drivers/media/i2c/adv7175.c6
-rw-r--r--drivers/media/i2c/adv7180.c18
-rw-r--r--drivers/media/i2c/adv7183.c8
-rw-r--r--drivers/media/i2c/adv748x/adv748x-afe.c13
-rw-r--r--drivers/media/i2c/adv748x/adv748x-csi2.c14
-rw-r--r--drivers/media/i2c/adv748x/adv748x-hdmi.c13
-rw-r--r--drivers/media/i2c/adv7511-v4l2.c10
-rw-r--r--drivers/media/i2c/adv7604.c12
-rw-r--r--drivers/media/i2c/adv7842.c53
-rw-r--r--drivers/media/i2c/ak7375.c10
-rw-r--r--drivers/media/i2c/ak881x.c6
-rw-r--r--drivers/media/i2c/ccs/ccs-core.c125
-rw-r--r--drivers/media/i2c/ccs/ccs-limits.c4
-rw-r--r--drivers/media/i2c/ccs/ccs-limits.h4
-rw-r--r--drivers/media/i2c/ccs/ccs-regs.h6
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c2
-rw-r--r--drivers/media/i2c/dw9714.c10
-rw-r--r--drivers/media/i2c/dw9768.c10
-rw-r--r--drivers/media/i2c/dw9807-vcm.c10
-rw-r--r--drivers/media/i2c/et8ek8/et8ek8_driver.c23
-rw-r--r--drivers/media/i2c/hi556.c18
-rw-r--r--drivers/media/i2c/imx208.c1088
-rw-r--r--drivers/media/i2c/imx214.c43
-rw-r--r--drivers/media/i2c/imx219.c36
-rw-r--r--drivers/media/i2c/imx258.c25
-rw-r--r--drivers/media/i2c/imx274.c41
-rw-r--r--drivers/media/i2c/imx290.c26
-rw-r--r--drivers/media/i2c/imx319.c24
-rw-r--r--drivers/media/i2c/imx334.c35
-rw-r--r--drivers/media/i2c/imx355.c24
-rw-r--r--drivers/media/i2c/ir-kbd-i2c.c4
-rw-r--r--drivers/media/i2c/m5mols/m5mols_core.c21
-rw-r--r--drivers/media/i2c/max9271.c42
-rw-r--r--drivers/media/i2c/max9271.h9
-rw-r--r--drivers/media/i2c/max9286.c58
-rw-r--r--drivers/media/i2c/ml86v7667.c4
-rw-r--r--drivers/media/i2c/mt9m001.c27
-rw-r--r--drivers/media/i2c/mt9m032.c38
-rw-r--r--drivers/media/i2c/mt9m111.c18
-rw-r--r--drivers/media/i2c/mt9p031.c45
-rw-r--r--drivers/media/i2c/mt9t001.c44
-rw-r--r--drivers/media/i2c/mt9t112.c14
-rw-r--r--drivers/media/i2c/mt9v011.c6
-rw-r--r--drivers/media/i2c/mt9v032.c44
-rw-r--r--drivers/media/i2c/mt9v111.c25
-rw-r--r--drivers/media/i2c/noon010pc30.c19
-rw-r--r--drivers/media/i2c/ov02a10.c23
-rw-r--r--drivers/media/i2c/ov13858.c24
-rw-r--r--drivers/media/i2c/ov2640.c16
-rw-r--r--drivers/media/i2c/ov2659.c47
-rw-r--r--drivers/media/i2c/ov2680.c23
-rw-r--r--drivers/media/i2c/ov2685.c17
-rw-r--r--drivers/media/i2c/ov2740.c21
-rw-r--r--drivers/media/i2c/ov5640.c14
-rw-r--r--drivers/media/i2c/ov5645.c38
-rw-r--r--drivers/media/i2c/ov5647.c35
-rw-r--r--drivers/media/i2c/ov5648.c20
-rw-r--r--drivers/media/i2c/ov5670.c25
-rw-r--r--drivers/media/i2c/ov5675.c18
-rw-r--r--drivers/media/i2c/ov5695.c21
-rw-r--r--drivers/media/i2c/ov6650.c28
-rw-r--r--drivers/media/i2c/ov7251.c39
-rw-r--r--drivers/media/i2c/ov7670.c17
-rw-r--r--drivers/media/i2c/ov772x.c12
-rw-r--r--drivers/media/i2c/ov7740.c23
-rw-r--r--drivers/media/i2c/ov8856.c2467
-rw-r--r--drivers/media/i2c/ov8865.c22
-rw-r--r--drivers/media/i2c/ov9640.c8
-rw-r--r--drivers/media/i2c/ov9650.c21
-rw-r--r--drivers/media/i2c/ov9734.c18
-rw-r--r--drivers/media/i2c/rdacm20.c88
-rw-r--r--drivers/media/i2c/rdacm21.c71
-rw-r--r--drivers/media/i2c/rj54n1cb0c.c12
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c61
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3.h2
-rw-r--r--drivers/media/i2c/s5k4ecgx.c32
-rw-r--r--drivers/media/i2c/s5k5baf.c55
-rw-r--r--drivers/media/i2c/s5k6a3.c19
-rw-r--r--drivers/media/i2c/s5k6aa.c49
-rw-r--r--drivers/media/i2c/saa6588.c4
-rw-r--r--drivers/media/i2c/saa6752hs.c6
-rw-r--r--drivers/media/i2c/saa7115.c2
-rw-r--r--drivers/media/i2c/saa717x.c2
-rw-r--r--drivers/media/i2c/sr030pc30.c8
-rw-r--r--drivers/media/i2c/st-mipid02.c21
-rw-r--r--drivers/media/i2c/tc358743.c9
-rw-r--r--drivers/media/i2c/tda1997x.c14
-rw-r--r--drivers/media/i2c/tvp514x.c12
-rw-r--r--drivers/media/i2c/tvp5150.c36
-rw-r--r--drivers/media/i2c/tvp7002.c11
-rw-r--r--drivers/media/i2c/tw9910.c10
-rw-r--r--drivers/media/i2c/video-i2c.c12
-rw-r--r--drivers/media/i2c/vs6624.c8
-rw-r--r--drivers/media/mc/Makefile2
-rw-r--r--drivers/media/mc/mc-entity.c2
-rw-r--r--drivers/media/mc/mc-request.c3
-rw-r--r--drivers/media/pci/bt8xx/bt878.c6
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c6
-rw-r--r--drivers/media/pci/cobalt/cobalt-driver.c1
-rw-r--r--drivers/media/pci/cobalt/cobalt-driver.h7
-rw-r--r--drivers/media/pci/cx18/cx18-av-core.c2
-rw-r--r--drivers/media/pci/cx88/cx88-alsa.c6
-rw-r--r--drivers/media/pci/cx88/cx88-blackbird.c3
-rw-r--r--drivers/media/pci/cx88/cx88-core.c6
-rw-r--r--drivers/media/pci/cx88/cx88-dvb.c3
-rw-r--r--drivers/media/pci/cx88/cx88-mpeg.c6
-rw-r--r--drivers/media/pci/cx88/cx88-vbi.c3
-rw-r--r--drivers/media/pci/cx88/cx88-video.c5
-rw-r--r--drivers/media/pci/intel/ipu3/cio2-bridge.c10
-rw-r--r--drivers/media/pci/intel/ipu3/ipu3-cio2-main.c20
-rw-r--r--drivers/media/pci/ivtv/Kconfig12
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.h2
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.c221
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c40
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c5
-rw-r--r--drivers/media/pci/saa7134/saa7134-tvaudio.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c6
-rw-r--r--drivers/media/pci/ttpci/Kconfig74
-rw-r--r--drivers/media/pci/ttpci/Makefile11
-rw-r--r--drivers/media/pci/ttpci/budget-core.c3
-rw-r--r--drivers/media/pci/ttpci/budget.h2
-rw-r--r--drivers/media/pci/tw5864/tw5864-reg.h62
-rw-r--r--drivers/media/platform/Makefile1
-rw-r--r--drivers/media/platform/allegro-dvt/nal-h264.c2
-rw-r--r--drivers/media/platform/allegro-dvt/nal-hevc.c2
-rw-r--r--drivers/media/platform/am437x/am437x-vpfe.c15
-rw-r--r--drivers/media/platform/atmel/Kconfig11
-rw-r--r--drivers/media/platform/atmel/Makefile2
-rw-r--r--drivers/media/platform/atmel/atmel-isc-base.c427
-rw-r--r--drivers/media/platform/atmel/atmel-isc-regs.h133
-rw-r--r--drivers/media/platform/atmel/atmel-isc.h122
-rw-r--r--drivers/media/platform/atmel/atmel-isi.c38
-rw-r--r--drivers/media/platform/atmel/atmel-sama5d2-isc.c300
-rw-r--r--drivers/media/platform/atmel/atmel-sama7g5-isc.c630
-rw-r--r--drivers/media/platform/cadence/cdns-csi2rx.c8
-rw-r--r--drivers/media/platform/cadence/cdns-csi2tx.c22
-rw-r--r--drivers/media/platform/coda/coda-common.c11
-rw-r--r--drivers/media/platform/davinci/vpbe_display.c2
-rw-r--r--drivers/media/platform/davinci/vpbe_venc.c6
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c2
-rw-r--r--drivers/media/platform/davinci/vpif_display.c2
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.c11
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c4
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c28
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.c6
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp-video.c10
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.c44
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c44
-rw-r--r--drivers/media/platform/exynos4-is/fimc-m2m.c5
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c10
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c27
-rw-r--r--drivers/media/platform/imx-jpeg/mxc-jpeg.c18
-rw-r--r--drivers/media/platform/imx-jpeg/mxc-jpeg.h18
-rw-r--r--drivers/media/platform/marvell-ccic/cafe-driver.c12
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c14
-rw-r--r--drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c4
-rw-r--r--drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c6
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c4
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c8
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h2
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h26
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c92
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c17
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h2
-rw-r--r--drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c4
-rw-r--r--drivers/media/platform/mtk-vcodec/venc_ipi_msg.h4
-rw-r--r--drivers/media/platform/mtk-vpu/mtk_vpu.c12
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c85
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c49
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.c41
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c69
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.c70
-rw-r--r--drivers/media/platform/pxa_camera.c5
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid.c49
-rw-r--r--drivers/media/platform/qcom/camss/camss-csiphy.c59
-rw-r--r--drivers/media/platform/qcom/camss/camss-ispif.c48
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe.c92
-rw-r--r--drivers/media/platform/qcom/venus/core.c60
-rw-r--r--drivers/media/platform/qcom/venus/core.h7
-rw-r--r--drivers/media/platform/qcom/venus/helpers.c5
-rw-r--r--drivers/media/platform/qcom/venus/hfi_cmds.c31
-rw-r--r--drivers/media/platform/qcom/venus/hfi_cmds.h2
-rw-r--r--drivers/media/platform/qcom/venus/hfi_helper.h10
-rw-r--r--drivers/media/platform/qcom/venus/hfi_msgs.c16
-rw-r--r--drivers/media/platform/qcom/venus/hfi_msgs.h6
-rw-r--r--drivers/media/platform/qcom/venus/hfi_platform.c16
-rw-r--r--drivers/media/platform/qcom/venus/hfi_platform.h4
-rw-r--r--drivers/media/platform/qcom/venus/hfi_platform_v4.c28
-rw-r--r--drivers/media/platform/qcom/venus/hfi_platform_v6.c28
-rw-r--r--drivers/media/platform/qcom/venus/pm_helpers.c153
-rw-r--r--drivers/media/platform/qcom/venus/vdec.c6
-rw-r--r--drivers/media/platform/qcom/venus/venc.c5
-rw-r--r--drivers/media/platform/rcar-fcp.c10
-rw-r--r--drivers/media/platform/rcar-vin/rcar-core.c4
-rw-r--r--drivers/media/platform/rcar-vin/rcar-csi2.c34
-rw-r--r--drivers/media/platform/rcar-vin/rcar-dma.c6
-rw-r--r--drivers/media/platform/rcar-vin/rcar-v4l2.c16
-rw-r--r--drivers/media/platform/rcar_fdp1.c28
-rw-r--r--drivers/media/platform/rcar_jpu.c6
-rw-r--r--drivers/media/platform/renesas-ceu.c11
-rw-r--r--drivers/media/platform/rockchip/rga/rga-buf.c3
-rw-r--r--drivers/media/platform/rockchip/rga/rga.c4
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c19
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c112
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-params.c5
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c95
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c20
-rw-r--r--drivers/media/platform/s3c-camif/camif-core.c5
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.c3
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c1
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_pm.c6
-rw-r--r--drivers/media/platform/sh_vou.c6
-rw-r--r--drivers/media/platform/sti/bdisp/Makefile2
-rw-r--r--drivers/media/platform/sti/bdisp/bdisp-v4l2.c8
-rw-r--r--drivers/media/platform/sti/delta/Makefile2
-rw-r--r--drivers/media/platform/sti/delta/delta-v4l2.c9
-rw-r--r--drivers/media/platform/sti/hva/Makefile2
-rw-r--r--drivers/media/platform/sti/hva/hva-hw.c20
-rw-r--r--drivers/media/platform/stm32/stm32-dcmi.c19
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c22
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c4
-rw-r--r--drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c2
-rw-r--r--drivers/media/platform/ti-vpe/cal-camerarx.c35
-rw-r--r--drivers/media/platform/ti-vpe/cal-video.c4
-rw-r--r--drivers/media/platform/ti-vpe/cal.c8
-rw-r--r--drivers/media/platform/ti-vpe/vpe.c8
-rw-r--r--drivers/media/platform/via-camera.c5
-rw-r--r--drivers/media/platform/video-mux.c32
-rw-r--r--drivers/media/platform/vsp1/vsp1_brx.c34
-rw-r--r--drivers/media/platform/vsp1/vsp1_clu.c13
-rw-r--r--drivers/media/platform/vsp1/vsp1_drv.c10
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.c59
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.h20
-rw-r--r--drivers/media/platform/vsp1/vsp1_histo.c51
-rw-r--r--drivers/media/platform/vsp1/vsp1_hsit.c14
-rw-r--r--drivers/media/platform/vsp1/vsp1_lif.c13
-rw-r--r--drivers/media/platform/vsp1/vsp1_lut.c13
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.c32
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_sru.c22
-rw-r--r--drivers/media/platform/vsp1/vsp1_uds.c22
-rw-r--r--drivers/media/platform/vsp1/vsp1_uif.c27
-rw-r--r--drivers/media/platform/xilinx/xilinx-csi2rxss.c26
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c5
-rw-r--r--drivers/media/platform/xilinx/xilinx-tpg.c25
-rw-r--r--drivers/media/platform/xilinx/xilinx-vip.c18
-rw-r--r--drivers/media/platform/xilinx/xilinx-vip.h4
-rw-r--r--drivers/media/radio/si4713/radio-platform-si4713.c2
-rw-r--r--drivers/media/rc/Kconfig83
-rw-r--r--drivers/media/rc/Makefile1
-rw-r--r--drivers/media/rc/bpf-lirc.c3
-rw-r--r--drivers/media/rc/imon.c15
-rw-r--r--drivers/media/rc/ite-cir.h2
-rw-r--r--drivers/media/rc/keymaps/Makefile2
-rw-r--r--drivers/media/rc/keymaps/rc-ct-90405.c86
-rw-r--r--drivers/media/rc/keymaps/rc-tango.c89
-rw-r--r--drivers/media/rc/st_rc.c22
-rw-r--r--drivers/media/rc/tango-ir.c267
-rw-r--r--drivers/media/spi/cxd2880-spi.c12
-rw-r--r--drivers/media/test-drivers/vim2m.c5
-rw-r--r--drivers/media/test-drivers/vimc/vimc-debayer.c20
-rw-r--r--drivers/media/test-drivers/vimc/vimc-scaler.c36
-rw-r--r--drivers/media/test-drivers/vimc/vimc-sensor.c16
-rw-r--r--drivers/media/test-drivers/vivid/vivid-core.c44
-rw-r--r--drivers/media/test-drivers/vivid/vivid-core.h1
-rw-r--r--drivers/media/test-drivers/vivid/vivid-kthread-cap.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-sdr-cap.c3
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vbi-cap.c8
-rw-r--r--drivers/media/usb/Kconfig5
-rw-r--r--drivers/media/usb/airspy/airspy.c3
-rw-r--r--drivers/media/usb/au0828/au0828-core.c4
-rw-r--r--drivers/media/usb/cpia2/cpia2.h1
-rw-r--r--drivers/media/usb/cpia2/cpia2_core.c12
-rw-r--r--drivers/media/usb/cpia2/cpia2_usb.c13
-rw-r--r--drivers/media/usb/cpia2/cpia2_v4l.c149
-rw-r--r--drivers/media/usb/dvb-usb-v2/lmedm04.c9
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c5
-rw-r--r--drivers/media/usb/dvb-usb/Makefile2
-rw-r--r--drivers/media/usb/dvb-usb/cinergyT2-core.c13
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.c2
-rw-r--r--drivers/media/usb/dvb-usb/dtv5100.c7
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c6
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c8
-rw-r--r--drivers/media/usb/go7007/s2250-board.c2
-rw-r--r--drivers/media/usb/gspca/cpia1.c5
-rw-r--r--drivers/media/usb/gspca/gl860/gl860.c4
-rw-r--r--drivers/media/usb/gspca/ov519.c2
-rw-r--r--drivers/media/usb/gspca/sq905.c2
-rw-r--r--drivers/media/usb/gspca/sunplus.c8
-rw-r--r--drivers/media/usb/hackrf/hackrf.c3
-rw-r--r--drivers/media/usb/msi2500/msi2500.c3
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c4
-rw-r--r--drivers/media/usb/s2255/s2255drv.c2
-rw-r--r--drivers/media/usb/ttusb-dec/ttusb_dec.c23
-rw-r--r--drivers/media/usb/uvc/uvc_video.c27
-rw-r--r--drivers/media/usb/zr364xx/zr364xx.c1
-rw-r--r--drivers/media/v4l2-core/Kconfig5
-rw-r--r--drivers/media/v4l2-core/Makefile8
-rw-r--r--drivers/media/v4l2-core/v4l2-async.c23
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c3
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-api.c1225
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-core.c1946
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-defs.c1579
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-priv.h96
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-request.c496
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c5035
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c10
-rw-r--r--drivers/media/v4l2-core/v4l2-event.c6
-rw-r--r--drivers/media/v4l2-core/v4l2-fh.c1
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c38
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c166
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-sg.c1
-rw-r--r--drivers/memory/atmel-ebi.c4
-rw-r--r--drivers/memory/emif.c678
-rw-r--r--drivers/memory/fsl_ifc.c8
-rw-r--r--drivers/memory/pl353-smc.c315
-rw-r--r--drivers/memory/stm32-fmc2-ebi.c4
-rw-r--r--drivers/memory/tegra/Kconfig18
-rw-r--r--drivers/memory/tegra/Makefile6
-rw-r--r--drivers/memory/tegra/mc.c321
-rw-r--r--drivers/memory/tegra/mc.h25
-rw-r--r--drivers/memory/tegra/tegra114.c1245
-rw-r--r--drivers/memory/tegra/tegra124-emc.c8
-rw-r--r--drivers/memory/tegra/tegra124.c1306
-rw-r--r--drivers/memory/tegra/tegra186.c1679
-rw-r--r--drivers/memory/tegra/tegra194.c1351
-rw-r--r--drivers/memory/tegra/tegra20-emc.c52
-rw-r--r--drivers/memory/tegra/tegra20.c110
-rw-r--r--drivers/memory/tegra/tegra210-emc-core.c4
-rw-r--r--drivers/memory/tegra/tegra210.c1433
-rw-r--r--drivers/memory/tegra/tegra30-emc.c56
-rw-r--r--drivers/memory/tegra/tegra30.c1292
-rw-r--r--drivers/memstick/core/ms_block.c63
-rw-r--r--drivers/memstick/core/mspro_block.c26
-rw-r--r--drivers/memstick/host/rtsx_usb_ms.c10
-rw-r--r--drivers/message/fusion/mptbase.c2
-rw-r--r--drivers/message/fusion/mptfc.c35
-rw-r--r--drivers/message/fusion/mptsas.c119
-rw-r--r--drivers/mfd/88pm800.c14
-rw-r--r--drivers/mfd/88pm805.c29
-rw-r--r--drivers/mfd/Kconfig47
-rw-r--r--drivers/mfd/Makefile17
-rw-r--r--drivers/mfd/ab8500-core.c33
-rw-r--r--drivers/mfd/arizona-core.c2
-rw-r--r--drivers/mfd/as3722.c14
-rw-r--r--drivers/mfd/asic3.c12
-rw-r--r--drivers/mfd/axp20x.c24
-rw-r--r--drivers/mfd/cros_ec_dev.c21
-rw-r--r--drivers/mfd/da9052-i2c.c10
-rw-r--r--drivers/mfd/da9055-core.c38
-rw-r--r--drivers/mfd/da9062-core.c13
-rw-r--r--drivers/mfd/da9063-i2c.c2
-rw-r--r--drivers/mfd/db8500-prcmu.c6
-rw-r--r--drivers/mfd/hi655x-pmic.c2
-rw-r--r--drivers/mfd/intel-lpss-pci.c13
-rw-r--r--drivers/mfd/intel_soc_pmic_bxtwc.c20
-rw-r--r--drivers/mfd/ioc3.c1
-rw-r--r--drivers/mfd/iqs62x.c2
-rw-r--r--drivers/mfd/janz-cmodio.c6
-rw-r--r--drivers/mfd/kempld-core.c19
-rw-r--r--drivers/mfd/lp87565.c27
-rw-r--r--drivers/mfd/max8907.c8
-rw-r--r--drivers/mfd/max8997.c9
-rw-r--r--drivers/mfd/max8998.c8
-rw-r--r--drivers/mfd/mfd-core.c15
-rw-r--r--drivers/mfd/motorola-cpcap.c4
-rw-r--r--drivers/mfd/mt6358-irq.c89
-rw-r--r--drivers/mfd/mt6360-core.c552
-rw-r--r--drivers/mfd/mt6397-core.c44
-rw-r--r--drivers/mfd/omap-usb-host.c2
-rw-r--r--drivers/mfd/omap-usb-tll.c2
-rw-r--r--drivers/mfd/pcf50633-core.c12
-rw-r--r--drivers/mfd/qcom-pm8008.c260
-rw-r--r--drivers/mfd/rk808.c81
-rw-r--r--drivers/mfd/rn5t618.c2
-rw-r--r--drivers/mfd/rt4831.c115
-rw-r--r--drivers/mfd/sec-core.c70
-rw-r--r--drivers/mfd/sec-irq.c4
-rw-r--r--drivers/mfd/si476x-cmd.c28
-rw-r--r--drivers/mfd/si476x-i2c.c10
-rw-r--r--drivers/mfd/sm501.c8
-rw-r--r--drivers/mfd/stmpe-i2c.c2
-rw-r--r--drivers/mfd/sun6i-prcm.c30
-rw-r--r--drivers/mfd/syscon.c2
-rw-r--r--drivers/mfd/t7l66xb.c12
-rw-r--r--drivers/mfd/timberdale.c6
-rw-r--r--drivers/mfd/tps68470.c97
-rw-r--r--drivers/mfd/tps80031.c6
-rw-r--r--drivers/mfd/twl-core.c2
-rw-r--r--drivers/mfd/ucb1x00-assabet.c2
-rw-r--r--drivers/mfd/wcd934x.c50
-rw-r--r--drivers/mfd/wm831x-core.c250
-rw-r--r--drivers/mfd/wm831x-otp.c6
-rw-r--r--drivers/misc/bcm-vk/bcm_vk_dev.c1
-rw-r--r--drivers/misc/bcm-vk/bcm_vk_msg.c6
-rw-r--r--drivers/misc/bcm-vk/bcm_vk_msg.h2
-rw-r--r--drivers/misc/bcm-vk/bcm_vk_tty.c2
-rw-r--r--drivers/misc/cardreader/alcor_pci.c8
-rw-r--r--drivers/misc/cxl/file.c5
-rw-r--r--drivers/misc/eeprom/Kconfig5
-rw-r--r--drivers/misc/eeprom/at25.c158
-rw-r--r--drivers/misc/eeprom/ee1004.c223
-rw-r--r--drivers/misc/eeprom/eeprom_93xx46.c90
-rw-r--r--drivers/misc/eeprom/idt_89hpesx.c41
-rw-r--r--drivers/misc/habanalabs/common/command_submission.c81
-rw-r--r--drivers/misc/habanalabs/common/context.c9
-rw-r--r--drivers/misc/habanalabs/common/debugfs.c5
-rw-r--r--drivers/misc/habanalabs/common/device.c82
-rw-r--r--drivers/misc/habanalabs/common/firmware_if.c1792
-rw-r--r--drivers/misc/habanalabs/common/habanalabs.h280
-rw-r--r--drivers/misc/habanalabs/common/habanalabs_drv.c24
-rw-r--r--drivers/misc/habanalabs/common/habanalabs_ioctl.c23
-rw-r--r--drivers/misc/habanalabs/common/hw_queue.c42
-rw-r--r--drivers/misc/habanalabs/common/irq.c24
-rw-r--r--drivers/misc/habanalabs/common/memory.c22
-rw-r--r--drivers/misc/habanalabs/common/mmu/mmu.c14
-rw-r--r--drivers/misc/habanalabs/common/pci/pci.c34
-rw-r--r--drivers/misc/habanalabs/common/sysfs.c2
-rw-r--r--drivers/misc/habanalabs/gaudi/gaudi.c1013
-rw-r--r--drivers/misc/habanalabs/gaudi/gaudiP.h1
-rw-r--r--drivers/misc/habanalabs/gaudi/gaudi_coresight.c6
-rw-r--r--drivers/misc/habanalabs/gaudi/gaudi_security.c15
-rw-r--r--drivers/misc/habanalabs/goya/goya.c251
-rw-r--r--drivers/misc/habanalabs/goya/goyaP.h2
-rw-r--r--drivers/misc/habanalabs/goya/goya_coresight.c2
-rw-r--r--drivers/misc/habanalabs/include/common/cpucp_if.h45
-rw-r--r--drivers/misc/habanalabs/include/common/hl_boot_if.h184
-rw-r--r--drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h14
-rw-r--r--drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h31
-rw-r--r--drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h46
-rw-r--r--drivers/misc/habanalabs/include/gaudi/gaudi_masks.h15
-rw-r--r--drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h10
-rw-r--r--drivers/misc/hpilo.c10
-rw-r--r--drivers/misc/hpilo.h3
-rw-r--r--drivers/misc/ibmasm/heartbeat.c1
-rw-r--r--drivers/misc/ibmasm/module.c5
-rw-r--r--drivers/misc/ibmasm/remote.h2
-rw-r--r--drivers/misc/lattice-ecp3-config.c2
-rw-r--r--drivers/misc/lkdtm/bugs.c17
-rw-r--r--drivers/misc/lkdtm/cfi.c3
-rw-r--r--drivers/misc/lkdtm/core.c58
-rw-r--r--drivers/misc/lkdtm/fortify.c3
-rw-r--r--drivers/misc/lkdtm/heap.c97
-rw-r--r--drivers/misc/lkdtm/lkdtm.h46
-rw-r--r--drivers/misc/lkdtm/stackleak.c4
-rw-r--r--drivers/misc/lkdtm/usercopy.c7
-rw-r--r--drivers/misc/mei/bus-fixup.c2
-rw-r--r--drivers/misc/mei/client.c22
-rw-r--r--drivers/misc/mei/hbm.c2
-rw-r--r--drivers/misc/mei/hdcp/Kconfig1
-rw-r--r--drivers/misc/mei/hw-me.c4
-rw-r--r--drivers/misc/mei/hw.h28
-rw-r--r--drivers/misc/mei/interrupt.c23
-rw-r--r--drivers/misc/mei/main.c4
-rw-r--r--drivers/misc/mei/mei-trace.h6
-rw-r--r--drivers/misc/mei/pci-txe.c2
-rw-r--r--drivers/misc/pvpanic/pvpanic-mmio.c17
-rw-r--r--drivers/misc/pvpanic/pvpanic-pci.c22
-rw-r--r--drivers/misc/pvpanic/pvpanic.c34
-rw-r--r--drivers/misc/pvpanic/pvpanic.h3
-rw-r--r--drivers/misc/sgi-gru/grufault.c4
-rw-r--r--drivers/misc/sram.c6
-rw-r--r--drivers/misc/ti-st/st_core.c30
-rw-r--r--drivers/misc/uacce/uacce.c11
-rw-r--r--drivers/misc/vmw_vmci/vmci_context.c2
-rw-r--r--drivers/misc/xilinx_sdfec.c3
-rw-r--r--drivers/mmc/core/block.c40
-rw-r--r--drivers/mmc/core/core.c29
-rw-r--r--drivers/mmc/core/core.h9
-rw-r--r--drivers/mmc/core/debugfs.c1
-rw-r--r--drivers/mmc/core/host.c3
-rw-r--r--drivers/mmc/core/mmc.c68
-rw-r--r--drivers/mmc/core/mmc_ops.c163
-rw-r--r--drivers/mmc/core/mmc_ops.h12
-rw-r--r--drivers/mmc/core/queue.c23
-rw-r--r--drivers/mmc/core/queue.h2
-rw-r--r--drivers/mmc/core/sd.c481
-rw-r--r--drivers/mmc/core/sd_ops.c38
-rw-r--r--drivers/mmc/core/sdio.c6
-rw-r--r--drivers/mmc/core/sdio_uart.c6
-rw-r--r--drivers/mmc/host/Kconfig6
-rw-r--r--drivers/mmc/host/cqhci-core.c21
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c1
-rw-r--r--drivers/mmc/host/jz4740_mmc.c8
-rw-r--r--drivers/mmc/host/meson-gx-mmc.c50
-rw-r--r--drivers/mmc/host/mmc_spi.c12
-rw-r--r--drivers/mmc/host/mtk-sd.c25
-rw-r--r--drivers/mmc/host/of_mmc_spi.c2
-rw-r--r--drivers/mmc/host/renesas_sdhi_core.c2
-rw-r--r--drivers/mmc/host/s3cmci.c7
-rw-r--r--drivers/mmc/host/sdhci-acpi.c11
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c18
-rw-r--r--drivers/mmc/host/sdhci-iproc.c30
-rw-r--r--drivers/mmc/host/sdhci-of-arasan.c14
-rw-r--r--drivers/mmc/host/sdhci-of-aspeed-test.c34
-rw-r--r--drivers/mmc/host/sdhci-of-aspeed.c50
-rw-r--r--drivers/mmc/host/sdhci-omap.c5
-rw-r--r--drivers/mmc/host/sdhci-pci-gli.c4
-rw-r--r--drivers/mmc/host/sdhci-sprd.c1
-rw-r--r--drivers/mmc/host/sdhci.c12
-rw-r--r--drivers/mmc/host/sdhci.h3
-rw-r--r--drivers/mmc/host/sdhci_am654.c6
-rw-r--r--drivers/mmc/host/usdhi6rol0.c1
-rw-r--r--drivers/mmc/host/via-sdmmc.c3
-rw-r--r--drivers/mmc/host/vub300.c2
-rw-r--r--drivers/mtd/chips/cfi_util.c4
-rw-r--r--drivers/mtd/chips/chipreg.c5
-rw-r--r--drivers/mtd/devices/Kconfig6
-rw-r--r--drivers/mtd/devices/Makefile1
-rw-r--r--drivers/mtd/devices/mchp48l640.c373
-rw-r--r--drivers/mtd/devices/ms02-nv.c1
-rw-r--r--drivers/mtd/devices/phram.c1
-rw-r--r--drivers/mtd/inftlmount.c17
-rw-r--r--drivers/mtd/maps/amd76xrom.c6
-rw-r--r--drivers/mtd/maps/ck804xrom.c8
-rw-r--r--drivers/mtd/maps/esb2rom.c7
-rw-r--r--drivers/mtd/maps/ichxrom.c6
-rw-r--r--drivers/mtd/maps/plat-ram.c1
-rw-r--r--drivers/mtd/maps/sun_uflash.c4
-rw-r--r--drivers/mtd/mtd_blkdevs.c49
-rw-r--r--drivers/mtd/mtdcore.c246
-rw-r--r--drivers/mtd/mtdoops.c4
-rw-r--r--drivers/mtd/mtdpart.c9
-rw-r--r--drivers/mtd/mtdpstore.c10
-rw-r--r--drivers/mtd/nand/bbt.c2
-rw-r--r--drivers/mtd/nand/raw/Kconfig8
-rw-r--r--drivers/mtd/nand/raw/Makefile1
-rw-r--r--drivers/mtd/nand/raw/arasan-nand-controller.c341
-rw-r--r--drivers/mtd/nand/raw/atmel/nand-controller.c11
-rw-r--r--drivers/mtd/nand/raw/cadence-nand-controller.c6
-rw-r--r--drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h2
-rw-r--r--drivers/mtd/nand/raw/hisi504_nand.c4
-rw-r--r--drivers/mtd/nand/raw/internals.h5
-rw-r--r--drivers/mtd/nand/raw/marvell_nand.c6
-rw-r--r--drivers/mtd/nand/raw/mtk_ecc.c4
-rw-r--r--drivers/mtd/nand/raw/nand_base.c364
-rw-r--r--drivers/mtd/nand/raw/nand_legacy.c2
-rw-r--r--drivers/mtd/nand/raw/nand_onfi.c5
-rw-r--r--drivers/mtd/nand/raw/nand_timings.c370
-rw-r--r--drivers/mtd/nand/raw/omap2.c229
-rw-r--r--drivers/mtd/nand/raw/omap_elm.c2
-rw-r--r--drivers/mtd/nand/raw/pl35x-nand-controller.c1194
-rw-r--r--drivers/mtd/nand/raw/qcom_nandc.c23
-rw-r--r--drivers/mtd/nand/raw/r852.c7
-rw-r--r--drivers/mtd/nand/raw/sunxi_nand.c4
-rw-r--r--drivers/mtd/nand/spi/core.c174
-rw-r--r--drivers/mtd/nand/spi/macronix.c112
-rw-r--r--drivers/mtd/nftlcore.c1
-rw-r--r--drivers/mtd/nftlmount.c7
-rw-r--r--drivers/mtd/parsers/Kconfig2
-rw-r--r--drivers/mtd/parsers/parser_trx.c9
-rw-r--r--drivers/mtd/parsers/qcomsmempart.c10
-rw-r--r--drivers/mtd/parsers/redboot.c76
-rw-r--r--drivers/mtd/rfd_ftl.c5
-rw-r--r--drivers/mtd/sm_ftl.c51
-rw-r--r--drivers/mtd/spi-nor/Makefile2
-rw-r--r--drivers/mtd/spi-nor/controllers/intel-spi-pci.c1
-rw-r--r--drivers/mtd/spi-nor/controllers/nxp-spifi.c2
-rw-r--r--drivers/mtd/spi-nor/core.c22
-rw-r--r--drivers/mtd/spi-nor/core.h16
-rw-r--r--drivers/mtd/spi-nor/macronix.c5
-rw-r--r--drivers/mtd/spi-nor/otp.c160
-rw-r--r--drivers/mtd/spi-nor/sfdp.c58
-rw-r--r--drivers/mtd/spi-nor/sysfs.c93
-rw-r--r--drivers/mtd/spi-nor/winbond.c1
-rw-r--r--drivers/mtd/tests/oobtest.c7
-rw-r--r--drivers/mtd/tests/torturetest.c2
-rw-r--r--drivers/mtd/ubi/block.c68
-rw-r--r--drivers/mtd/ubi/debug.c2
-rw-r--r--drivers/net/Kconfig23
-rw-r--r--drivers/net/appletalk/cops.c30
-rw-r--r--drivers/net/appletalk/ltpc.c16
-rw-r--r--drivers/net/bareudp.c1
-rw-r--r--drivers/net/bonding/bond_alb.c13
-rw-r--r--drivers/net/bonding/bond_debugfs.c3
-rw-r--r--drivers/net/bonding/bond_main.c220
-rw-r--r--drivers/net/bonding/bond_netlink.c2
-rw-r--r--drivers/net/bonding/bond_options.c5
-rw-r--r--drivers/net/bonding/bond_procfs.c1
-rw-r--r--drivers/net/bonding/bond_sysfs.c7
-rw-r--r--drivers/net/caif/Kconfig9
-rw-r--r--drivers/net/caif/Makefile3
-rw-r--r--drivers/net/caif/caif_hsi.c1454
-rw-r--r--drivers/net/caif/caif_serial.c13
-rw-r--r--drivers/net/caif/caif_virtio.c6
-rw-r--r--drivers/net/can/at91_can.c2
-rw-r--r--drivers/net/can/c_can/Makefile5
-rw-r--r--drivers/net/can/c_can/c_can.h3
-rw-r--r--drivers/net/can/c_can/c_can_ethtool.c43
-rw-r--r--drivers/net/can/c_can/c_can_main.c (renamed from drivers/net/can/c_can/c_can.c)2
-rw-r--r--drivers/net/can/m_can/m_can.c244
-rw-r--r--drivers/net/can/peak_canfd/peak_canfd.c4
-rw-r--r--drivers/net/can/slcan.c10
-rw-r--r--drivers/net/can/softing/softing_main.c2
-rw-r--r--drivers/net/can/spi/hi311x.c2
-rw-r--r--drivers/net/can/spi/mcp251x.c2
-rw-r--r--drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c2
-rw-r--r--drivers/net/can/usb/Kconfig2
-rw-r--r--drivers/net/can/usb/ems_usb.c3
-rw-r--r--drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c14
-rw-r--r--drivers/net/dsa/b53/b53_common.c30
-rw-r--r--drivers/net/dsa/b53/b53_srab.c3
-rw-r--r--drivers/net/dsa/hirschmann/hellcreek.c3
-rw-r--r--drivers/net/dsa/microchip/ksz8795.c214
-rw-r--r--drivers/net/dsa/microchip/ksz8795_reg.h67
-rw-r--r--drivers/net/dsa/microchip/ksz_common.c4
-rw-r--r--drivers/net/dsa/mt7530.c264
-rw-r--r--drivers/net/dsa/mt7530.h20
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c28
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.c6
-rw-r--r--drivers/net/dsa/ocelot/felix.c2
-rw-r--r--drivers/net/dsa/ocelot/seville_vsc9953.c5
-rw-r--r--drivers/net/dsa/qca8k.c803
-rw-r--r--drivers/net/dsa/qca8k.h58
-rw-r--r--drivers/net/dsa/sja1105/Kconfig9
-rw-r--r--drivers/net/dsa/sja1105/Makefile1
-rw-r--r--drivers/net/dsa/sja1105/sja1105.h128
-rw-r--r--drivers/net/dsa/sja1105/sja1105_clocking.c170
-rw-r--r--drivers/net/dsa/sja1105/sja1105_dynamic_config.c360
-rw-r--r--drivers/net/dsa/sja1105/sja1105_dynamic_config.h1
-rw-r--r--drivers/net/dsa/sja1105/sja1105_ethtool.c1089
-rw-r--r--drivers/net/dsa/sja1105/sja1105_flower.c13
-rw-r--r--drivers/net/dsa/sja1105/sja1105_main.c783
-rw-r--r--drivers/net/dsa/sja1105/sja1105_mdio.c543
-rw-r--r--drivers/net/dsa/sja1105/sja1105_ptp.c97
-rw-r--r--drivers/net/dsa/sja1105/sja1105_ptp.h13
-rw-r--r--drivers/net/dsa/sja1105/sja1105_sgmii.h53
-rw-r--r--drivers/net/dsa/sja1105/sja1105_spi.c518
-rw-r--r--drivers/net/dsa/sja1105/sja1105_static_config.c500
-rw-r--r--drivers/net/dsa/sja1105/sja1105_static_config.h109
-rw-r--r--drivers/net/dsa/sja1105/sja1105_tas.c14
-rw-r--r--drivers/net/dsa/sja1105/sja1105_tas.h2
-rw-r--r--drivers/net/dsa/sja1105/sja1105_vl.c2
-rw-r--r--drivers/net/dsa/xrs700x/xrs700x.c78
-rw-r--r--drivers/net/ethernet/3com/3c59x.c2
-rw-r--r--drivers/net/ethernet/8390/axnet_cs.c14
-rw-r--r--drivers/net/ethernet/8390/pcnet_cs.c2
-rw-r--r--drivers/net/ethernet/8390/smc-ultra.c6
-rw-r--r--drivers/net/ethernet/8390/stnic.c2
-rw-r--r--drivers/net/ethernet/aeroflex/greth.c3
-rw-r--r--drivers/net/ethernet/alteon/acenic.c26
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_admin_defs.h2
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_com.c3
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_eth_com.c30
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_ethtool.c18
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_netdev.c220
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_netdev.h23
-rw-r--r--drivers/net/ethernet/amd/amd8111e.c4
-rw-r--r--drivers/net/ethernet/amd/amd8111e.h6
-rw-r--r--drivers/net/ethernet/amd/atarilance.c2
-rw-r--r--drivers/net/ethernet/amd/declance.c2
-rw-r--r--drivers/net/ethernet/amd/lance.c4
-rw-r--r--drivers/net/ethernet/amd/ni65.c12
-rw-r--r--drivers/net/ethernet/amd/nmclan_cs.c12
-rw-r--r--drivers/net/ethernet/amd/sun3lance.c12
-rw-r--r--drivers/net/ethernet/apple/bmac.c30
-rw-r--r--drivers/net/ethernet/apple/mace.c8
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_macsec.h4
-rw-r--r--drivers/net/ethernet/arc/emac_rockchip.c2
-rw-r--r--drivers/net/ethernet/atheros/alx/alx.h2
-rw-r--r--drivers/net/ethernet/atheros/alx/ethtool.c21
-rw-r--r--drivers/net/ethernet/atheros/alx/main.c84
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c.h28
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_hw.c40
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_hw.h42
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_main.c587
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_main.c4
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl1.c2
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig1
-rw-r--r--drivers/net/ethernet/broadcom/b44.c20
-rw-r--r--drivers/net/ethernet/broadcom/bcm4908_enet.c6
-rw-r--r--drivers/net/ethernet/broadcom/bgmac-platform.c21
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c6
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c4
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h1
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/Makefile2
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c135
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h10
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c34
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h667
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c473
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h81
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c4
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c2
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c24
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c6
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmmii.c4
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_cee.c2
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c3
-rw-r--r--drivers/net/ethernet/cadence/macb_pci.c2
-rw-r--r--drivers/net/ethernet/cadence/macb_ptp.c2
-rw-r--r--drivers/net/ethernet/calxeda/xgmac.c8
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_main.c2
-rw-r--r--drivers/net/ethernet/cavium/thunder/thunder_bgx.c3
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/adapter.h2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/common.h2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c19
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/sge.c44
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c6
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c20
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c3
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c7
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/sge.c2
-rw-r--r--drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c2
-rw-r--r--drivers/net/ethernet/cortina/gemini.c34
-rw-r--r--drivers/net/ethernet/dec/tulip/de2104x.c4
-rw-r--r--drivers/net/ethernet/dec/tulip/de4x5.c6
-rw-r--r--drivers/net/ethernet/dec/tulip/dmfe.c18
-rw-r--r--drivers/net/ethernet/dec/tulip/pnic2.c4
-rw-r--r--drivers/net/ethernet/dec/tulip/tulip.h1
-rw-r--r--drivers/net/ethernet/dec/tulip/uli526x.c10
-rw-r--r--drivers/net/ethernet/dec/tulip/winbond-840.c4
-rw-r--r--drivers/net/ethernet/dlink/sundance.c12
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.c6
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c2
-rw-r--r--drivers/net/ethernet/ezchip/nps_enet.c7
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c6
-rw-r--r--drivers/net/ethernet/fealnx.c2
-rw-r--r--drivers/net/ethernet/freescale/dpaa/dpaa_eth.c8
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c6
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c10
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c103
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h1
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c2
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_ierb.c4
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_pf.c9
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_qos.c31
-rw-r--r--drivers/net/ethernet/freescale/fec.h5
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c43
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c76
-rw-r--r--drivers/net/ethernet/freescale/gianfar.h74
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth.c3
-rw-r--r--drivers/net/ethernet/freescale/xgmac_mdio.c30
-rw-r--r--drivers/net/ethernet/fujitsu/fmvj18x_cs.c6
-rw-r--r--drivers/net/ethernet/google/Kconfig2
-rw-r--r--drivers/net/ethernet/google/gve/Makefile2
-rw-r--r--drivers/net/ethernet/google/gve/gve.h332
-rw-r--r--drivers/net/ethernet/google/gve/gve_adminq.c334
-rw-r--r--drivers/net/ethernet/google/gve/gve_adminq.h112
-rw-r--r--drivers/net/ethernet/google/gve/gve_desc_dqo.h256
-rw-r--r--drivers/net/ethernet/google/gve/gve_dqo.h81
-rw-r--r--drivers/net/ethernet/google/gve/gve_ethtool.c21
-rw-r--r--drivers/net/ethernet/google/gve/gve_main.c314
-rw-r--r--drivers/net/ethernet/google/gve/gve_rx.c54
-rw-r--r--drivers/net/ethernet/google/gve/gve_rx_dqo.c756
-rw-r--r--drivers/net/ethernet/google/gve/gve_tx.c25
-rw-r--r--drivers/net/ethernet/google/gve/gve_tx_dqo.c1030
-rw-r--r--drivers/net/ethernet/google/gve/gve_utils.c81
-rw-r--r--drivers/net/ethernet/google/gve/gve_utils.h28
-rw-r--r--drivers/net/ethernet/hisilicon/Kconfig2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c9
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c16
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c76
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c8
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c4
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_enet.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h10
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hnae3.h90
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c1471
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h64
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.c1225
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.h99
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c86
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c13
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h41
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c2604
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h47
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c414
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h89
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c621
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h60
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c115
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c542
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.h134
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c215
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h19
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h1
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c76
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h2
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_ethtool.c1
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c4
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c18
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c6
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_if.c4
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_io.c4
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c4
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c2
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c1
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_main.c5
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_port.c10
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_rx.c1
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_tx.c4
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_main.c27
-rw-r--r--drivers/net/ethernet/ibm/emac/emac.h2
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c54
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.c302
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.h6
-rw-r--r--drivers/net/ethernet/intel/Kconfig3
-rw-r--r--drivers/net/ethernet/intel/e100.c12
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_ethtool.c2
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_hw.c4
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c27
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.c2
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_pci.c11
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_client.c253
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_common.c124
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ethtool.c3
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c18
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ptp.c8
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_type.h1
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_xsk.c3
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_common.c124
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_main.c1
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_type.h1
-rw-r--r--drivers/net/ethernet/intel/ice/Makefile2
-rw-r--r--drivers/net/ethernet/intel/ice/ice.h55
-rw-r--r--drivers/net/ethernet/intel/ice/ice_adminq_cmd.h80
-rw-r--r--drivers/net/ethernet/intel/ice/ice_arfs.h12
-rw-r--r--drivers/net/ethernet/intel/ice/ice_base.c134
-rw-r--r--drivers/net/ethernet/intel/ice/ice_base.h2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.c465
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.h19
-rw-r--r--drivers/net/ethernet/intel/ice/ice_controlq.c62
-rw-r--r--drivers/net/ethernet/intel/ice/ice_controlq.h2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dcb_lib.c21
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dcb_lib.h15
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dcb_nl.h9
-rw-r--r--drivers/net/ethernet/intel/ice/ice_devlink.c9
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool.c33
-rw-r--r--drivers/net/ethernet/intel/ice/ice_fw_update.c10
-rw-r--r--drivers/net/ethernet/intel/ice/ice_hw_autogen.h90
-rw-r--r--drivers/net/ethernet/intel/ice/ice_idc.c334
-rw-r--r--drivers/net/ethernet/intel/ice/ice_idc_int.h14
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lag.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h151
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.c120
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.h10
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c315
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp.c1558
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp.h204
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp_hw.c651
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp_hw.h79
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sbq_cmd.h92
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sched.c93
-rw-r--r--drivers/net/ethernet/intel/ice/ice_switch.c28
-rw-r--r--drivers/net/ethernet/intel/ice/ice_switch.h5
-rw-r--r--drivers/net/ethernet/intel/ice/ice_trace.h232
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.c54
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.h5
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx_lib.c26
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx_lib.h2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_type.h69
-rw-r--r--drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c227
-rw-r--r--drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h31
-rw-r--r--drivers/net/ethernet/intel/ice/ice_xsk.c7
-rw-r--r--drivers/net/ethernet/intel/ice/ice_xsk.h4
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.c2
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c2
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c28
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ptp.c4
-rw-r--r--drivers/net/ethernet/intel/igbvf/netdev.c6
-rw-r--r--drivers/net/ethernet/intel/igbvf/vf.h42
-rw-r--r--drivers/net/ethernet/intel/igc/igc.h36
-rw-r--r--drivers/net/ethernet/intel/igc/igc_base.h2
-rw-r--r--drivers/net/ethernet/intel/igc/igc_defines.h9
-rw-r--r--drivers/net/ethernet/intel/igc/igc_dump.c2
-rw-r--r--drivers/net/ethernet/intel/igc/igc_ethtool.c41
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c734
-rw-r--r--drivers/net/ethernet/intel/igc/igc_regs.h2
-rw-r--r--drivers/net/ethernet/intel/igc/igc_xdp.c109
-rw-r--r--drivers/net/ethernet/intel/igc/igc_xdp.h8
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c9
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.c16
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c8
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ipsec.c20
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c4
-rw-r--r--drivers/net/ethernet/lantiq_xrx200.c9
-rw-r--r--drivers/net/ethernet/marvell/mvmdio.c20
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c52
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2.h3
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c123
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c3
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/cgx.c292
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/cgx.h10
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/common.h5
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/lmac_common.h12
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/mbox.h112
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/npc.h107
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h3915
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu.c57
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu.h83
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c111
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c200
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c256
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c926
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c617
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c33
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h22
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h88
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_trace.h12
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/Makefile2
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c410
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h14
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c3
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h57
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_dmac_flt.c173
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c6
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c419
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c169
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c303
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h1
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c70
-rw-r--r--drivers/net/ethernet/marvell/prestera/Makefile3
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera.h39
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_acl.c376
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_acl.h124
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_devlink.c530
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_devlink.h3
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_dsa.c3
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_dsa.h1
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_flow.c194
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_flow.h14
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_flower.c359
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_flower.h18
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_hw.c661
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_hw.h51
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_main.c301
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_pci.c104
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_rxtx.c7
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_span.c239
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_span.h20
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_switchdev.c186
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_switchdev.h7
-rw-r--r--drivers/net/ethernet/marvell/pxa168_eth.c2
-rw-r--r--drivers/net/ethernet/marvell/skge.h2
-rw-r--r--drivers/net/ethernet/marvell/sky2.c32
-rw-r--r--drivers/net/ethernet/marvell/sky2.h8
-rw-r--r--drivers/net/ethernet/mellanox/Kconfig1
-rw-r--r--drivers/net/ethernet/mellanox/Makefile1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/Kconfig19
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/Makefile3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/devlink.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en.h8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/params.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c427
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.h21
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c58
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.h23
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c38
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c65
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h37
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c11
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h24
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_txrx.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.c6
-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.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_stats.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c34
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rep.c18
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rep.h6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rx.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tc.c88
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tc.h8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tx.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eq.c179
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c1299
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h53
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_priv.h53
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/diag/bridge_tracepoint.h113
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.h7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c19
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c58
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_core.c70
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_core.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c85
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h21
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fw.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag.c295
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag.h3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h10
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c94
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/sf.h45
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h25
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mlx5_irq.h35
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c608
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c24
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h37
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/sriov.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c242
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c40
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c120
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h37
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c43
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h6
-rw-r--r--drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig13
-rw-r--r--drivers/net/ethernet/mellanox/mlxbf_gige/Makefile11
-rw-r--r--drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h190
-rw-r--r--drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c137
-rw-r--r--drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c212
-rw-r--r--drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c142
-rw-r--r--drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c452
-rw-r--r--drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c187
-rw-r--r--drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h78
-rw-r--r--drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c320
-rw-r--r--drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c284
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/Kconfig22
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/Makefile4
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_env.c99
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_env.h7
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_thermal.c97
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/ib.h9
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/minimal.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/pci.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/pci.h3
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/reg.h124
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c14
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c378
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/switchib.c595
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/switchx2.c1691
-rw-r--r--drivers/net/ethernet/micrel/ks8842.c4
-rw-r--r--drivers/net/ethernet/micrel/ks8851_common.c15
-rw-r--r--drivers/net/ethernet/micrel/ksz884x.c111
-rw-r--r--drivers/net/ethernet/microchip/Kconfig2
-rw-r--r--drivers/net/ethernet/microchip/Makefile2
-rw-r--r--drivers/net/ethernet/microchip/sparx5/Kconfig10
-rw-r--r--drivers/net/ethernet/microchip/sparx5/Makefile10
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c596
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c1227
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c500
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_main.c853
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_main.h375
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h4642
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c264
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_packet.c320
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_phylink.c210
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_port.c1146
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_port.h93
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c510
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c224
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c9
-rw-r--r--drivers/net/ethernet/moxa/moxart_ether.c9
-rw-r--r--drivers/net/ethernet/mscc/ocelot_net.c38
-rw-r--r--drivers/net/ethernet/natsemi/natsemi.c6
-rw-r--r--drivers/net/ethernet/neterion/s2io.c10
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-config.c3
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-main.c36
-rw-r--r--drivers/net/ethernet/netronome/nfp/Makefile3
-rw-r--r--drivers/net/ethernet/netronome/nfp/ccm_mbox.c2
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/conntrack.c1168
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/conntrack.h231
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/main.h6
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/metadata.c129
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/offload.c40
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c2
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_common.c2
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_repr.c1
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c3
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c2
-rw-r--r--drivers/net/ethernet/ni/nixge.c8
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h2
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c2
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c102
-rw-r--r--drivers/net/ethernet/qlogic/Kconfig3
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c1
-rw-r--r--drivers/net/ethernet/qlogic/qed/Makefile5
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed.h14
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_cxt.c45
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_cxt.h2
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_dev.c140
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_hsi.h6
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_iscsi.c22
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_ll2.c40
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_mcp.c3
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_mng_tlv.c3
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_nvmetcp.c829
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_nvmetcp.h103
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_nvmetcp_fw_funcs.c376
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_nvmetcp_fw_funcs.h39
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_nvmetcp_ip_services.c238
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_ooo.c5
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_sp.h5
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_sp_commands.c3
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede_fp.c6
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede_rdma.c6
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c8
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c8
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac.c3
-rw-r--r--drivers/net/ethernet/qualcomm/qca_debug.c1
-rw-r--r--drivers/net/ethernet/qualcomm/qca_spi.c16
-rw-r--r--drivers/net/ethernet/qualcomm/qca_spi.h1
-rw-r--r--drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c6
-rw-r--r--drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h5
-rw-r--r--drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c43
-rw-r--r--drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h11
-rw-r--r--drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c434
-rw-r--r--drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c2
-rw-r--r--drivers/net/ethernet/rdc/r6040.c9
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c6
-rw-r--r--drivers/net/ethernet/realtek/8139too.c6
-rw-r--r--drivers/net/ethernet/realtek/atp.c4
-rw-r--r--drivers/net/ethernet/realtek/r8169_main.c10
-rw-r--r--drivers/net/ethernet/renesas/ravb_main.c15
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.c5
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c4
-rw-r--r--drivers/net/ethernet/seeq/ether3.c10
-rw-r--r--drivers/net/ethernet/sfc/ef10.c20
-rw-r--r--drivers/net/ethernet/sfc/ef10_sriov.c36
-rw-r--r--drivers/net/ethernet/sfc/efx.c19
-rw-r--r--drivers/net/ethernet/sfc/efx_channels.c22
-rw-r--r--drivers/net/ethernet/sfc/efx_common.c12
-rw-r--r--drivers/net/ethernet/sfc/falcon/efx.c4
-rw-r--r--drivers/net/ethernet/sfc/falcon/falcon_boards.c10
-rw-r--r--drivers/net/ethernet/sfc/farch.c13
-rw-r--r--drivers/net/ethernet/sfc/rx.c9
-rw-r--r--drivers/net/ethernet/sgi/ioc3-eth.c4
-rw-r--r--drivers/net/ethernet/sis/sis900.c22
-rw-r--r--drivers/net/ethernet/smsc/smc9194.c42
-rw-r--r--drivers/net/ethernet/smsc/smc91x.c14
-rw-r--r--drivers/net/ethernet/socionext/netsec.c3
-rw-r--r--drivers/net/ethernet/socionext/sni_ave.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig21
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c398
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c105
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h29
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c220
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c207
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac5.c30
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac5.h3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.h15
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h10
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c96
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c74
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c16
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c17
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c41
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c60
-rw-r--r--drivers/net/ethernet/sun/cassini.c2
-rw-r--r--drivers/net/ethernet/sun/ldmvsw.c4
-rw-r--r--drivers/net/ethernet/sun/sungem.c20
-rw-r--r--drivers/net/ethernet/sun/sunhme.c6
-rw-r--r--drivers/net/ethernet/sun/sunvnet.c3
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.c18
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-switchdev.c6
-rw-r--r--drivers/net/ethernet/ti/am65-cpts.c4
-rw-r--r--drivers/net/ethernet/ti/cpsw-phy-sel.c4
-rw-r--r--drivers/net/ethernet/ti/cpsw.c7
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.c2
-rw-r--r--drivers/net/ethernet/ti/cpsw_new.c7
-rw-r--r--drivers/net/ethernet/ti/cpsw_priv.c10
-rw-r--r--drivers/net/ethernet/ti/cpsw_switchdev.c6
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c5
-rw-r--r--drivers/net/ethernet/ti/tlan.c3
-rw-r--r--drivers/net/ethernet/via/via-velocity.c6
-rw-r--r--drivers/net/ethernet/wiznet/w5100.c7
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_main.c4
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c8
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_emaclite.c5
-rw-r--r--drivers/net/ethernet/xircom/xirc2ps_cs.c2
-rw-r--r--drivers/net/ethernet/xscale/ixp4xx_eth.c12
-rw-r--r--drivers/net/ethernet/xscale/ptp_ixp46x.c3
-rw-r--r--drivers/net/fddi/defza.c3
-rw-r--r--drivers/net/fddi/skfp/ess.c6
-rw-r--r--drivers/net/fddi/skfp/h/supern_2.h2
-rw-r--r--drivers/net/fjes/fjes_main.c16
-rw-r--r--drivers/net/fjes/fjes_trace.h4
-rw-r--r--drivers/net/gtp.c3
-rw-r--r--drivers/net/hamradio/6pack.c24
-rw-r--r--drivers/net/hamradio/baycom_epp.c4
-rw-r--r--drivers/net/hamradio/bpqether.c4
-rw-r--r--drivers/net/hamradio/hdlcdrv.c2
-rw-r--r--drivers/net/hamradio/mkiss.c19
-rw-r--r--drivers/net/hamradio/scc.c20
-rw-r--r--drivers/net/hamradio/yam.c2
-rw-r--r--drivers/net/hyperv/hyperv_net.h8
-rw-r--r--drivers/net/hyperv/netvsc.c10
-rw-r--r--drivers/net/hyperv/netvsc_drv.c5
-rw-r--r--drivers/net/hyperv/rndis_filter.c10
-rw-r--r--drivers/net/ieee802154/mac802154_hwsim.c11
-rw-r--r--drivers/net/ifb.c4
-rw-r--r--drivers/net/ipa/Makefile9
-rw-r--r--drivers/net/ipa/gsi.c90
-rw-r--r--drivers/net/ipa/gsi.h2
-rw-r--r--drivers/net/ipa/gsi_reg.h3
-rw-r--r--drivers/net/ipa/ipa_cmd.c40
-rw-r--r--drivers/net/ipa/ipa_data-v3.1.c533
-rw-r--r--drivers/net/ipa/ipa_data-v3.5.1.c45
-rw-r--r--drivers/net/ipa/ipa_data-v4.11.c66
-rw-r--r--drivers/net/ipa/ipa_data-v4.2.c54
-rw-r--r--drivers/net/ipa/ipa_data-v4.5.c69
-rw-r--r--drivers/net/ipa/ipa_data-v4.9.c70
-rw-r--r--drivers/net/ipa/ipa_data.h1
-rw-r--r--drivers/net/ipa/ipa_endpoint.c90
-rw-r--r--drivers/net/ipa/ipa_main.c55
-rw-r--r--drivers/net/ipa/ipa_mem.c264
-rw-r--r--drivers/net/ipa/ipa_mem.h26
-rw-r--r--drivers/net/ipa/ipa_qmi.c32
-rw-r--r--drivers/net/ipa/ipa_reg.h1
-rw-r--r--drivers/net/ipa/ipa_smp2p.c6
-rw-r--r--drivers/net/ipa/ipa_sysfs.c136
-rw-r--r--drivers/net/ipa/ipa_sysfs.h15
-rw-r--r--drivers/net/ipa/ipa_table.c94
-rw-r--r--drivers/net/ipa/ipa_uc.c3
-rw-r--r--drivers/net/ipa/ipa_version.h2
-rw-r--r--drivers/net/macsec.c4
-rw-r--r--drivers/net/macvlan.c2
-rw-r--r--drivers/net/mdio/Kconfig14
-rw-r--r--drivers/net/mdio/Makefile4
-rw-r--r--drivers/net/mdio/acpi_mdio.c58
-rw-r--r--drivers/net/mdio/fwnode_mdio.c144
-rw-r--r--drivers/net/mdio/mdio-bcm-unimac.c2
-rw-r--r--drivers/net/mdio/mdio-ipq8064.c70
-rw-r--r--drivers/net/mdio/mdio-mscc-miim.c6
-rw-r--r--drivers/net/mdio/mdio-mux-bcm-iproc.c9
-rw-r--r--drivers/net/mdio/mdio-mux-meson-g12a.c2
-rw-r--r--drivers/net/mdio/of_mdio.c149
-rw-r--r--drivers/net/mhi/net.c133
-rw-r--r--drivers/net/mhi/proto_mbim.c5
-rw-r--r--drivers/net/mii.c2
-rw-r--r--drivers/net/netdevsim/bus.c129
-rw-r--r--drivers/net/netdevsim/dev.c404
-rw-r--r--drivers/net/netdevsim/ipsec.c8
-rw-r--r--drivers/net/netdevsim/netdev.c95
-rw-r--r--drivers/net/netdevsim/netdevsim.h49
-rw-r--r--drivers/net/pcs/Makefile4
-rw-r--r--drivers/net/pcs/pcs-xpcs-nxp.c185
-rw-r--r--drivers/net/pcs/pcs-xpcs.c659
-rw-r--r--drivers/net/pcs/pcs-xpcs.h115
-rw-r--r--drivers/net/phy/Kconfig16
-rw-r--r--drivers/net/phy/Makefile2
-rw-r--r--drivers/net/phy/adin.c2
-rw-r--r--drivers/net/phy/at803x.c192
-rw-r--r--drivers/net/phy/ax88796b.c74
-rw-r--r--drivers/net/phy/bcm87xx.c4
-rw-r--r--drivers/net/phy/davicom.c6
-rw-r--r--drivers/net/phy/dp83640.c5
-rw-r--r--drivers/net/phy/et1011c.c15
-rw-r--r--drivers/net/phy/fixed_phy.c4
-rw-r--r--drivers/net/phy/lxt.c4
-rw-r--r--drivers/net/phy/marvell.c40
-rw-r--r--drivers/net/phy/marvell10g.c40
-rw-r--r--drivers/net/phy/mdio_bus.c4
-rw-r--r--drivers/net/phy/mdio_device.c4
-rw-r--r--drivers/net/phy/mediatek-ge.c112
-rw-r--r--drivers/net/phy/micrel.c410
-rw-r--r--drivers/net/phy/mii_timestamper.c3
-rw-r--r--drivers/net/phy/motorcomm.c137
-rw-r--r--drivers/net/phy/mscc/mscc_macsec.c2
-rw-r--r--drivers/net/phy/mscc/mscc_macsec.h2
-rw-r--r--drivers/net/phy/national.c6
-rw-r--r--drivers/net/phy/nxp-c45-tja11xx.c537
-rw-r--r--drivers/net/phy/phy-c45.c2
-rw-r--r--drivers/net/phy/phy-core.c3
-rw-r--r--drivers/net/phy/phy.c6
-rw-r--r--drivers/net/phy/phy_device.c132
-rw-r--r--drivers/net/phy/phylink.c60
-rw-r--r--drivers/net/phy/qsemi.c1
-rw-r--r--drivers/net/phy/realtek.c76
-rw-r--r--drivers/net/phy/rockchip.c2
-rw-r--r--drivers/net/phy/sfp-bus.c33
-rw-r--r--drivers/net/phy/sfp.c2
-rw-r--r--drivers/net/phy/spi_ks8995.c10
-rw-r--r--drivers/net/phy/ste10Xp.c6
-rw-r--r--drivers/net/phy/vitesse.c3
-rw-r--r--drivers/net/ppp/bsd_comp.c2
-rw-r--r--drivers/net/ppp/ppp_async.c12
-rw-r--r--drivers/net/ppp/ppp_synctty.c12
-rw-r--r--drivers/net/slip/slhc.c2
-rw-r--r--drivers/net/slip/slip.c9
-rw-r--r--drivers/net/tun.c16
-rw-r--r--drivers/net/usb/Kconfig12
-rw-r--r--drivers/net/usb/asix.h13
-rw-r--r--drivers/net/usb/asix_common.c106
-rw-r--r--drivers/net/usb/asix_devices.c203
-rw-r--r--drivers/net/usb/ax88172a.c21
-rw-r--r--drivers/net/usb/cdc_ether.c2
-rw-r--r--drivers/net/usb/cdc_mbim.c7
-rw-r--r--drivers/net/usb/cdc_ncm.c40
-rw-r--r--drivers/net/usb/hso.c15
-rw-r--r--drivers/net/usb/huawei_cdc_ncm.c1
-rw-r--r--drivers/net/usb/int51x1.c2
-rw-r--r--drivers/net/usb/lan78xx.c2
-rw-r--r--drivers/net/usb/lg-vl600.c4
-rw-r--r--drivers/net/usb/mcs7830.c2
-rw-r--r--drivers/net/usb/qmi_wwan.c3
-rw-r--r--drivers/net/usb/r8152.c97
-rw-r--r--drivers/net/usb/rndis_host.c2
-rw-r--r--drivers/net/usb/usbnet.c27
-rw-r--r--drivers/net/virtio_net.c114
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c22
-rw-r--r--drivers/net/vrf.c16
-rw-r--r--drivers/net/vxlan.c2
-rw-r--r--drivers/net/wan/Kconfig4
-rw-r--r--drivers/net/wan/c101.c46
-rw-r--r--drivers/net/wan/cosa.c493
-rw-r--r--drivers/net/wan/farsync.c487
-rw-r--r--drivers/net/wan/fsl_ucc_hdlc.c3
-rw-r--r--drivers/net/wan/hd64570.c124
-rw-r--r--drivers/net/wan/hd64572.c95
-rw-r--r--drivers/net/wan/hdlc.c63
-rw-r--r--drivers/net/wan/hdlc_cisco.c57
-rw-r--r--drivers/net/wan/hdlc_fr.c109
-rw-r--r--drivers/net/wan/hdlc_ppp.c46
-rw-r--r--drivers/net/wan/hdlc_raw.c8
-rw-r--r--drivers/net/wan/hdlc_raw_eth.c8
-rw-r--r--drivers/net/wan/hdlc_x25.c85
-rw-r--r--drivers/net/wan/hostess_sv11.c113
-rw-r--r--drivers/net/wan/ixp4xx_hss.c145
-rw-r--r--drivers/net/wan/lapbether.c65
-rw-r--r--drivers/net/wan/lmc/lmc.h2
-rw-r--r--drivers/net/wan/n2.c56
-rw-r--r--drivers/net/wan/pc300too.c52
-rw-r--r--drivers/net/wan/pci200syn.c51
-rw-r--r--drivers/net/wan/sealevel.c126
-rw-r--r--drivers/net/wan/wanxl.c190
-rw-r--r--drivers/net/wan/z85230.c995
-rw-r--r--drivers/net/wireless/ath/ath10k/ahb.c9
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c4
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h4
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c14
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c8
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h9
-rw-r--r--drivers/net/wireless/ath/ath11k/core.c47
-rw-r--r--drivers/net/wireless/ath/ath11k/core.h5
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h2
-rw-r--r--drivers/net/wireless/ath/ath11k/dp.c16
-rw-r--r--drivers/net/wireless/ath/ath11k/hal.c10
-rw-r--r--drivers/net/wireless/ath/ath11k/hal.h3
-rw-r--r--drivers/net/wireless/ath/ath11k/hal_rx.c42
-rw-r--r--drivers/net/wireless/ath/ath11k/hal_rx.h8
-rw-r--r--drivers/net/wireless/ath/ath11k/hw.c391
-rw-r--r--drivers/net/wireless/ath/ath11k/hw.h5
-rw-r--r--drivers/net/wireless/ath/ath11k/mac.c24
-rw-r--r--drivers/net/wireless/ath/ath11k/mhi.c1
-rw-r--r--drivers/net/wireless/ath/ath11k/pci.c49
-rw-r--r--drivers/net/wireless/ath/ath11k/rx_desc.h87
-rw-r--r--drivers/net/wireless/ath/ath11k/wmi.c4
-rw-r--r--drivers/net/wireless/ath/ath11k/wmi.h4
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c7
-rw-r--r--drivers/net/wireless/ath/carl9170/Kconfig8
-rw-r--r--drivers/net/wireless/ath/hw.c2
-rw-r--r--drivers/net/wireless/ath/wcn36xx/dxe.c2
-rw-r--r--drivers/net/wireless/ath/wcn36xx/hal.h20
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c131
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c288
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.h17
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx.h14
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c6
-rw-r--r--drivers/net/wireless/broadcom/b43/debugfs.c34
-rw-r--r--drivers/net/wireless/broadcom/b43/debugfs.h3
-rw-r--r--drivers/net/wireless/broadcom/b43/phy_n.c47
-rw-r--r--drivers/net/wireless/broadcom/b43legacy/debugfs.c29
-rw-r--r--drivers/net/wireless/broadcom/b43legacy/debugfs.h3
-rw-r--r--drivers/net/wireless/broadcom/b43legacy/dma.c13
-rw-r--r--drivers/net/wireless/broadcom/b43legacy/main.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c70
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c11
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h7
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c57
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c19
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/aiutils.c3
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c8
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c3
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.h1
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2100.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/Makefile3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/22000.c16
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/9000.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/acpi.c86
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/acpi.h10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/commands.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/d3.h110
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h26
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h19
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dbg.c47
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dbg.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dump.c418
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/file.h25
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/pnvm.c120
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/pnvm.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/uefi.c262
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/uefi.h42
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-config.h6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h20
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-csr.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c13
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-drv.c11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c138
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-prph.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-trans.h20
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/d3.c118
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c44
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c31
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h20
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/offloading.c26
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c40
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c26
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/scan.c14
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/time-event.c45
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/utils.c357
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c90
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/drv.c19
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/internal.h24
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/rx.c34
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c78
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans.c39
-rw-r--r--drivers/net/wireless/intersil/orinoco/hw.c18
-rw-r--r--drivers/net/wireless/intersil/orinoco/hw.h5
-rw-r--r--drivers/net/wireless/intersil/orinoco/wext.c2
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c55
-rw-r--r--drivers/net/wireless/marvell/libertas/main.c2
-rw-r--r--drivers/net/wireless/marvell/libertas/mesh.c149
-rw-r--r--drivers/net/wireless/marvell/libertas_tf/if_usb.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/fw.h6
-rw-r--r--drivers/net/wireless/marvell/mwifiex/main.c13
-rw-r--r--drivers/net/wireless/marvell/mwifiex/pcie.c10
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sta_cmd.c11
-rw-r--r--drivers/net/wireless/marvell/mwl8k.c4
-rw-r--r--drivers/net/wireless/mediatek/mt76/dma.c19
-rw-r--r--drivers/net/wireless/mediatek/mt76/mac80211.c64
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76.h56
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/init.c32
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mac.c43
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/regs.h12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/Makefile2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c22
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/dma.c13
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/init.c85
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mac.c156
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mac.h42
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/main.c60
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mcu.c99
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mmio.c11
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h19
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c10
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/regs.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/sdio.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c39
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c16
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/soc.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c11
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac.h19
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c10
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c228
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h72
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mac.c36
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mac.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_regs.h18
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_util.c16
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/Makefile2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c78
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/dma.c45
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c44
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h13
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/init.c179
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mac.c384
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mac.h56
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/main.c103
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mcu.c673
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mcu.h80
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h39
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/pci.c41
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/regs.h32
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/testmode.c21
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/testmode.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/Makefile2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c37
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/dma.c22
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/init.c99
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mac.c248
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mac.h14
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/main.c173
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mcu.c206
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mcu.h166
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h20
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/pci.c34
-rw-r--r--drivers/net/wireless/mediatek/mt76/sdio.c17
-rw-r--r--drivers/net/wireless/mediatek/mt76/testmode.c35
-rw-r--r--drivers/net/wireless/mediatek/mt76/tx.c82
-rw-r--r--drivers/net/wireless/mediatek/mt76/usb.c1
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/usb.c1
-rw-r--r--drivers/net/wireless/microchip/wilc1000/spi.c2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800lib.c2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00queue.c5
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h11
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c59
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c11
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c20
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/cam.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/coex.c45
-rw-r--r--drivers/net/wireless/realtek/rtw88/debug.c7
-rw-r--r--drivers/net/wireless/realtek/rtw88/debug.h1
-rw-r--r--drivers/net/wireless/realtek/rtw88/fw.c114
-rw-r--r--drivers/net/wireless/realtek/rtw88/fw.h55
-rw-r--r--drivers/net/wireless/realtek/rtw88/mac80211.c11
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.c196
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.h57
-rw-r--r--drivers/net/wireless/realtek/rtw88/pci.c32
-rw-r--r--drivers/net/wireless/realtek/rtw88/phy.c81
-rw-r--r--drivers/net/wireless/realtek/rtw88/phy.h1
-rw-r--r--drivers/net/wireless/realtek/rtw88/ps.c4
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822c.c113
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822c_table.c1008
-rw-r--r--drivers/net/wireless/rndis_wlan.c5
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_hal.c6
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mac80211.c20
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mgmt.c7
-rw-r--r--drivers/net/wireless/rsi/rsi_main.h1
-rw-r--r--drivers/net/wireless/st/cw1200/cw1200_sdio.c1
-rw-r--r--drivers/net/wireless/st/cw1200/scan.c17
-rw-r--r--drivers/net/wireless/ti/wl1251/cmd.c17
-rw-r--r--drivers/net/wireless/ti/wl12xx/main.c7
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.c6
-rw-r--r--drivers/net/wireless/ti/wlcore/event.c67
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c6
-rw-r--r--drivers/net/wireless/ti/wlcore/sysfs.c24
-rw-r--r--drivers/net/wireless/zydas/zd1211rw/zd_usb.c4
-rw-r--r--drivers/net/wwan/Kconfig53
-rw-r--r--drivers/net/wwan/Makefile6
-rw-r--r--drivers/net/wwan/iosm/Makefile23
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.c88
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.h59
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_imem.c1363
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_imem.h579
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_imem_ops.c333
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_imem_ops.h101
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_irq.c90
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_irq.h33
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_mmio.c223
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_mmio.h183
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_mux.c455
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_mux.h343
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_mux_codec.c910
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_mux_codec.h193
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_pcie.c580
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_pcie.h209
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_pm.c333
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_pm.h207
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_port.c85
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_port.h50
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_protocol.c283
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_protocol.h237
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c552
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_protocol_ops.h444
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_task_queue.c202
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_task_queue.h97
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_uevent.c44
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_uevent.h41
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_wwan.c345
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_wwan.h55
-rw-r--r--drivers/net/wwan/rpmsg_wwan_ctrl.c166
-rw-r--r--drivers/net/wwan/wwan_core.c638
-rw-r--r--drivers/net/wwan/wwan_hwsim.c547
-rw-r--r--drivers/nfc/fdp/fdp.c42
-rw-r--r--drivers/nfc/fdp/fdp.h1
-rw-r--r--drivers/nfc/fdp/i2c.c14
-rw-r--r--drivers/nfc/mei_phy.c8
-rw-r--r--drivers/nfc/microread/microread.c1
-rw-r--r--drivers/nfc/nfcmrvl/fw_dnld.c25
-rw-r--r--drivers/nfc/nfcmrvl/fw_dnld.h15
-rw-r--r--drivers/nfc/nfcmrvl/i2c.c22
-rw-r--r--drivers/nfc/nfcmrvl/main.c13
-rw-r--r--drivers/nfc/nfcmrvl/nfcmrvl.h27
-rw-r--r--drivers/nfc/nfcmrvl/spi.c17
-rw-r--r--drivers/nfc/nfcmrvl/uart.c47
-rw-r--r--drivers/nfc/nfcmrvl/usb.c29
-rw-r--r--drivers/nfc/nxp-nci/core.c39
-rw-r--r--drivers/nfc/nxp-nci/firmware.c7
-rw-r--r--drivers/nfc/pn533/i2c.c10
-rw-r--r--drivers/nfc/pn533/pn533.c46
-rw-r--r--drivers/nfc/pn533/uart.c2
-rw-r--r--drivers/nfc/pn533/usb.c4
-rw-r--r--drivers/nfc/pn544/i2c.c11
-rw-r--r--drivers/nfc/port100.c4
-rw-r--r--drivers/nfc/s3fwrn5/i2c.c32
-rw-r--r--drivers/nfc/st-nci/i2c.c9
-rw-r--r--drivers/nfc/st-nci/se.c14
-rw-r--r--drivers/nfc/st-nci/spi.c9
-rw-r--r--drivers/nfc/st-nci/vendor_cmds.c15
-rw-r--r--drivers/nfc/st21nfca/dep.c59
-rw-r--r--drivers/nfc/st21nfca/i2c.c9
-rw-r--r--drivers/nfc/st95hf/core.c13
-rw-r--r--drivers/nvdimm/blk.c27
-rw-r--r--drivers/nvdimm/btt.c25
-rw-r--r--drivers/nvdimm/btt.h2
-rw-r--r--drivers/nvdimm/bus.c64
-rw-r--r--drivers/nvdimm/dimm_devs.c18
-rw-r--r--drivers/nvdimm/pmem.c21
-rw-r--r--drivers/nvme/host/Kconfig2
-rw-r--r--drivers/nvme/host/core.c258
-rw-r--r--drivers/nvme/host/fabrics.c71
-rw-r--r--drivers/nvme/host/fabrics.h8
-rw-r--r--drivers/nvme/host/fc.c76
-rw-r--r--drivers/nvme/host/ioctl.c67
-rw-r--r--drivers/nvme/host/multipath.c79
-rw-r--r--drivers/nvme/host/nvme.h21
-rw-r--r--drivers/nvme/host/pci.c149
-rw-r--r--drivers/nvme/host/rdma.c5
-rw-r--r--drivers/nvme/host/tcp.c31
-rw-r--r--drivers/nvme/host/zns.c27
-rw-r--r--drivers/nvme/target/Makefile1
-rw-r--r--drivers/nvme/target/admin-cmd.c155
-rw-r--r--drivers/nvme/target/configfs.c102
-rw-r--r--drivers/nvme/target/core.c100
-rw-r--r--drivers/nvme/target/discovery.c8
-rw-r--r--drivers/nvme/target/fc.c10
-rw-r--r--drivers/nvme/target/io-cmd-bdev.c36
-rw-r--r--drivers/nvme/target/io-cmd-file.c4
-rw-r--r--drivers/nvme/target/loop.c2
-rw-r--r--drivers/nvme/target/nvmet.h41
-rw-r--r--drivers/nvme/target/passthru.c11
-rw-r--r--drivers/nvme/target/rdma.c3
-rw-r--r--drivers/nvme/target/tcp.c1
-rw-r--r--drivers/nvme/target/zns.c615
-rw-r--r--drivers/nvmem/core.c27
-rw-r--r--drivers/nvmem/qfprom.c9
-rw-r--r--drivers/nvmem/sprd-efuse.c2
-rw-r--r--drivers/nvmem/sunxi_sid.c1
-rw-r--r--drivers/of/Kconfig4
-rw-r--r--drivers/of/address.c128
-rw-r--r--drivers/of/fdt.c14
-rw-r--r--drivers/of/of_private.h4
-rw-r--r--drivers/of/of_reserved_mem.c17
-rw-r--r--drivers/of/platform.c1
-rw-r--r--drivers/of/unittest.c6
-rw-r--r--drivers/opp/core.c10
-rw-r--r--drivers/opp/of.c27
-rw-r--r--drivers/parisc/power.c1
-rw-r--r--drivers/parport/probe.c11
-rw-r--r--drivers/pci/controller/Kconfig8
-rw-r--r--drivers/pci/controller/Makefile1
-rw-r--r--drivers/pci/controller/cadence/pcie-cadence.h7
-rw-r--r--drivers/pci/controller/dwc/pci-imx6.c25
-rw-r--r--drivers/pci/controller/dwc/pcie-intel-gw.c10
-rw-r--r--drivers/pci/controller/dwc/pcie-tegra194.c4
-rw-r--r--drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c11
-rw-r--r--drivers/pci/controller/pci-aardvark.c13
-rw-r--r--drivers/pci/controller/pci-ftpci100.c30
-rw-r--r--drivers/pci/controller/pci-hyperv.c67
-rw-r--r--drivers/pci/controller/pci-ixp4xx.c671
-rw-r--r--drivers/pci/controller/pci-tegra.c1
-rw-r--r--drivers/pci/controller/pci-xgene.c4
-rw-r--r--drivers/pci/controller/pcie-iproc-msi.c33
-rw-r--r--drivers/pci/controller/pcie-iproc.c24
-rw-r--r--drivers/pci/controller/pcie-iproc.h16
-rw-r--r--drivers/pci/controller/pcie-mediatek-gen3.c1
-rw-r--r--drivers/pci/controller/pcie-mediatek.c4
-rw-r--r--drivers/pci/controller/pcie-microchip-host.c2
-rw-r--r--drivers/pci/controller/pcie-rockchip-host.c12
-rw-r--r--drivers/pci/ecam.c54
-rw-r--r--drivers/pci/hotplug/cpci_hotplug.h3
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_pci.c2
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c7
-rw-r--r--drivers/pci/hotplug/cpqphp_ctrl.c2
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c8
-rw-r--r--drivers/pci/hotplug/pciehp.h3
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c36
-rw-r--r--drivers/pci/hotplug/rpadlpar_sysfs.c4
-rw-r--r--drivers/pci/hotplug/shpchp_sysfs.c38
-rw-r--r--drivers/pci/iov.c23
-rw-r--r--drivers/pci/msi.c8
-rw-r--r--drivers/pci/p2pdma.c376
-rw-r--r--drivers/pci/pci-label.c22
-rw-r--r--drivers/pci/pci-sysfs.c2
-rw-r--r--drivers/pci/pci.c76
-rw-r--r--drivers/pci/pci.h8
-rw-r--r--drivers/pci/pcie/aer.c24
-rw-r--r--drivers/pci/pcie/aspm.c4
-rw-r--r--drivers/pci/pcie/dpc.c74
-rw-r--r--drivers/pci/probe.c23
-rw-r--r--drivers/pci/proc.c2
-rw-r--r--drivers/pci/quirks.c11
-rw-r--r--drivers/pci/slot.c18
-rw-r--r--drivers/pci/switch/switchtec.c18
-rw-r--r--drivers/perf/arm-cci.c4
-rw-r--r--drivers/perf/arm-ccn.c6
-rw-r--r--drivers/perf/arm-cmn.c13
-rw-r--r--drivers/perf/arm_dmc620_pmu.c5
-rw-r--r--drivers/perf/arm_dsu_pmu.c8
-rw-r--r--drivers/perf/arm_pmu.c16
-rw-r--r--drivers/perf/arm_smmuv3_pmu.c35
-rw-r--r--drivers/perf/arm_spe_pmu.c12
-rw-r--r--drivers/perf/fsl_imx8_ddr_perf.c18
-rw-r--r--drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c5
-rw-r--r--drivers/perf/hisilicon/hisi_uncore_hha_pmu.c9
-rw-r--r--drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c5
-rw-r--r--drivers/perf/hisilicon/hisi_uncore_pa_pmu.c5
-rw-r--r--drivers/perf/hisilicon/hisi_uncore_pmu.c6
-rw-r--r--drivers/perf/hisilicon/hisi_uncore_pmu.h2
-rw-r--r--drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c7
-rw-r--r--drivers/perf/qcom_l2_pmu.c11
-rw-r--r--drivers/perf/qcom_l3_pmu.c15
-rw-r--r--drivers/perf/thunderx2_pmu.c4
-rw-r--r--drivers/perf/xgene_pmu.c17
-rw-r--r--drivers/phy/Kconfig9
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/broadcom/phy-bcm-ns-usb3.c4
-rw-r--r--drivers/phy/hisilicon/Kconfig10
-rw-r--r--drivers/phy/hisilicon/Makefile1
-rw-r--r--drivers/phy/hisilicon/phy-hi3670-usb3.c (renamed from drivers/staging/hikey9xx/phy-hi3670-usb3.c)19
-rw-r--r--drivers/phy/intel/phy-intel-keembay-emmc.c3
-rw-r--r--drivers/phy/marvell/phy-mmp3-hsic.c4
-rw-r--r--drivers/phy/mediatek/phy-mtk-hdmi.c4
-rw-r--r--drivers/phy/mediatek/phy-mtk-mipi-dsi.c4
-rw-r--r--drivers/phy/phy-can-transceiver.c146
-rw-r--r--drivers/phy/phy-core-mipi-dphy.c2
-rw-r--r--drivers/phy/phy-core.c16
-rw-r--r--drivers/phy/phy-xgene.c3
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp.c315
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp.h189
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qusb2.c34
-rw-r--r--drivers/phy/ralink/Kconfig2
-rw-r--r--drivers/phy/ralink/phy-mt7621-pci.c37
-rw-r--r--drivers/phy/rockchip/Kconfig9
-rw-r--r--drivers/phy/rockchip/Makefile1
-rw-r--r--drivers/phy/rockchip/phy-rockchip-inno-csidphy.c459
-rw-r--r--drivers/phy/rockchip/phy-rockchip-inno-hdmi.c4
-rw-r--r--drivers/phy/rockchip/phy-rockchip-inno-usb2.c44
-rw-r--r--drivers/phy/socionext/phy-uniphier-pcie.c11
-rw-r--r--drivers/phy/st/phy-stm32-usbphyc.c31
-rw-r--r--drivers/phy/tegra/xusb-tegra186.c550
-rw-r--r--drivers/phy/tegra/xusb-tegra210.c1533
-rw-r--r--drivers/phy/tegra/xusb.c92
-rw-r--r--drivers/phy/tegra/xusb.h22
-rw-r--r--drivers/phy/ti/phy-dm816x-usb.c17
-rw-r--r--drivers/phy/ti/phy-twl4030-usb.c6
-rw-r--r--drivers/pinctrl/Kconfig2
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c24
-rw-r--r--drivers/pinctrl/aspeed/pinmux-aspeed.h9
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm2835.c8
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm6318.c4
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm63268.c4
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm6328.c4
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm6358.c4
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm6362.c4
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm6368.c4
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm63xx.h4
-rw-r--r--drivers/pinctrl/bcm/pinctrl-iproc-gpio.c4
-rw-r--r--drivers/pinctrl/intel/pinctrl-tigerlake.c1
-rw-r--r--drivers/pinctrl/mediatek/Kconfig7
-rw-r--r--drivers/pinctrl/mediatek/Makefile1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt2701.c3
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt2712.c3
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt6397.c3
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8127.c3
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8135.c3
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8167.c3
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8173.c3
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8365.c502
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8516.c3
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c21
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.h3
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-mt8365.h1511
-rw-r--r--drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c4
-rw-r--r--drivers/pinctrl/pinctrl-amd.c33
-rw-r--r--drivers/pinctrl/pinctrl-at91.c14
-rw-r--r--drivers/pinctrl/pinctrl-equilibrium.c1
-rw-r--r--drivers/pinctrl/pinctrl-mcp23s08.c13
-rw-r--r--drivers/pinctrl/pinctrl-mcp23s08.h1
-rw-r--r--drivers/pinctrl/pinctrl-microchip-sgpio.c4
-rw-r--r--drivers/pinctrl/pinctrl-ocelot.c4
-rw-r--r--drivers/pinctrl/pinctrl-single.c5
-rw-r--r--drivers/pinctrl/pinctrl-zynqmp.c50
-rw-r--r--drivers/pinctrl/qcom/Kconfig9
-rw-r--r--drivers/pinctrl/qcom/Makefile1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm6125.c1277
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-gpio.c1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-mpp.c1
-rw-r--r--drivers/pinctrl/ralink/Kconfig25
-rw-r--r--drivers/pinctrl/ralink/Makefile6
-rw-r--r--drivers/pinctrl/ralink/pinctrl-mt7620.c390
-rw-r--r--drivers/pinctrl/ralink/pinctrl-mt7621.c116
-rw-r--r--drivers/pinctrl/ralink/pinctrl-rt2880.c30
-rw-r--r--drivers/pinctrl/ralink/pinctrl-rt288x.c60
-rw-r--r--drivers/pinctrl/ralink/pinctrl-rt305x.c137
-rw-r--r--drivers/pinctrl/ralink/pinctrl-rt3883.c107
-rw-r--r--drivers/pinctrl/ralink/pinmux.h53
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a77470.c346
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a7778.c3
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a7790.c301
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a7792.c533
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a7794.c360
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a77951.c4
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a7796.c10
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a77965.c79
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a77970.c175
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a77980.c209
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a77990.c16
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32.c88
-rw-r--r--drivers/platform/chrome/cros_ec_ishtp.c4
-rw-r--r--drivers/platform/surface/aggregator/Kconfig2
-rw-r--r--drivers/platform/surface/aggregator/Makefile2
-rw-r--r--drivers/platform/surface/aggregator/bus.c2
-rw-r--r--drivers/platform/surface/aggregator/bus.h2
-rw-r--r--drivers/platform/surface/aggregator/controller.c332
-rw-r--r--drivers/platform/surface/aggregator/controller.h2
-rw-r--r--drivers/platform/surface/aggregator/core.c8
-rw-r--r--drivers/platform/surface/aggregator/ssh_msgb.h2
-rw-r--r--drivers/platform/surface/aggregator/ssh_packet_layer.c12
-rw-r--r--drivers/platform/surface/aggregator/ssh_packet_layer.h2
-rw-r--r--drivers/platform/surface/aggregator/ssh_parser.c2
-rw-r--r--drivers/platform/surface/aggregator/ssh_parser.h2
-rw-r--r--drivers/platform/surface/aggregator/ssh_request_layer.c12
-rw-r--r--drivers/platform/surface/aggregator/ssh_request_layer.h2
-rw-r--r--drivers/platform/surface/aggregator/trace.h2
-rw-r--r--drivers/platform/surface/surface3_power.c22
-rw-r--r--drivers/platform/surface/surface_acpi_notify.c7
-rw-r--r--drivers/platform/surface/surface_aggregator_cdev.c534
-rw-r--r--drivers/platform/surface/surface_aggregator_registry.c47
-rw-r--r--drivers/platform/x86/Kconfig49
-rw-r--r--drivers/platform/x86/Makefile10
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c77
-rw-r--r--drivers/platform/x86/dell/Kconfig11
-rw-r--r--drivers/platform/x86/dell/Makefile2
-rw-r--r--drivers/platform/x86/dell/dcdbas.c3
-rw-r--r--drivers/platform/x86/dell/dell-laptop.c13
-rw-r--r--drivers/platform/x86/dell/dell-wmi-base.c (renamed from drivers/platform/x86/dell/dell-wmi.c)14
-rw-r--r--drivers/platform/x86/dell/dell-wmi-privacy.c391
-rw-r--r--drivers/platform/x86/dell/dell-wmi-privacy.h36
-rw-r--r--drivers/platform/x86/dell/dell-wmi-sysman/dell-wmi-sysman.h5
-rw-r--r--drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c39
-rw-r--r--drivers/platform/x86/dell/dell-wmi-sysman/int-attributes.c16
-rw-r--r--drivers/platform/x86/dell/dell-wmi-sysman/passobj-attributes.c6
-rw-r--r--drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c4
-rw-r--r--drivers/platform/x86/dell/dell-wmi-sysman/string-attributes.c16
-rw-r--r--drivers/platform/x86/dell/dell-wmi-sysman/sysman.c21
-rw-r--r--drivers/platform/x86/dell/dell_rbu.c2
-rw-r--r--drivers/platform/x86/firmware_attributes_class.c52
-rw-r--r--drivers/platform/x86/firmware_attributes_class.h11
-rw-r--r--drivers/platform/x86/hdaps.c2
-rw-r--r--drivers/platform/x86/hp-wireless.c102
-rw-r--r--drivers/platform/x86/ideapad-laptop.c12
-rw-r--r--drivers/platform/x86/intel/Kconfig22
-rw-r--r--drivers/platform/x86/intel/Makefile8
-rw-r--r--drivers/platform/x86/intel/int33fe/Kconfig24
-rw-r--r--drivers/platform/x86/intel/int33fe/Makefile5
-rw-r--r--drivers/platform/x86/intel/int33fe/intel_cht_int33fe_common.c (renamed from drivers/platform/x86/intel_cht_int33fe_common.c)0
-rw-r--r--drivers/platform/x86/intel/int33fe/intel_cht_int33fe_common.h (renamed from drivers/platform/x86/intel_cht_int33fe_common.h)0
-rw-r--r--drivers/platform/x86/intel/int33fe/intel_cht_int33fe_microb.c (renamed from drivers/platform/x86/intel_cht_int33fe_microb.c)0
-rw-r--r--drivers/platform/x86/intel/int33fe/intel_cht_int33fe_typec.c (renamed from drivers/platform/x86/intel_cht_int33fe_typec.c)4
-rw-r--r--drivers/platform/x86/intel/int3472/Kconfig30
-rw-r--r--drivers/platform/x86/intel/int3472/Makefile5
-rw-r--r--drivers/platform/x86/intel/int3472/intel_skl_int3472_clk_and_regulator.c207
-rw-r--r--drivers/platform/x86/intel/int3472/intel_skl_int3472_common.c106
-rw-r--r--drivers/platform/x86/intel/int3472/intel_skl_int3472_common.h122
-rw-r--r--drivers/platform/x86/intel/int3472/intel_skl_int3472_discrete.c413
-rw-r--r--drivers/platform/x86/intel/int3472/intel_skl_int3472_tps68470.c137
-rw-r--r--drivers/platform/x86/intel_ips.c2
-rw-r--r--drivers/platform/x86/intel_pmt_crashlog.c2
-rw-r--r--drivers/platform/x86/intel_speed_select_if/isst_if_common.c73
-rw-r--r--drivers/platform/x86/samsung-laptop.c35
-rw-r--r--drivers/platform/x86/tc1100-wmi.c2
-rw-r--r--drivers/platform/x86/think-lmi.c904
-rw-r--r--drivers/platform/x86/think-lmi.h72
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c2
-rw-r--r--drivers/platform/x86/toshiba_acpi.c1
-rw-r--r--drivers/platform/x86/toshiba_haps.c2
-rw-r--r--drivers/platform/x86/touchscreen_dmi.c87
-rw-r--r--drivers/platform/x86/uv_sysfs.c4
-rw-r--r--drivers/platform/x86/wireless-hotkey.c103
-rw-r--r--drivers/pnp/base.h1
-rw-r--r--drivers/pnp/card.c21
-rw-r--r--drivers/pnp/core.c17
-rw-r--r--drivers/pnp/driver.c9
-rw-r--r--drivers/pnp/interface.c4
-rw-r--r--drivers/pnp/isapnp/compat.c1
-rw-r--r--drivers/pnp/isapnp/proc.c13
-rw-r--r--drivers/pnp/manager.c7
-rw-r--r--drivers/pnp/pnpbios/core.c4
-rw-r--r--drivers/pnp/resource.c2
-rw-r--r--drivers/pnp/support.c1
-rw-r--r--drivers/power/reset/at91-sama5d2_shdwc.c4
-rw-r--r--drivers/power/reset/gpio-poweroff.c1
-rw-r--r--drivers/power/reset/keystone-reset.c1
-rw-r--r--drivers/power/reset/ltc2952-poweroff.c1
-rw-r--r--drivers/power/reset/regulator-poweroff.c1
-rw-r--r--drivers/power/supply/Kconfig12
-rw-r--r--drivers/power/supply/Makefile3
-rw-r--r--drivers/power/supply/ab8500-bm.h7
-rw-r--r--drivers/power/supply/ab8500-chargalg.h2
-rw-r--r--drivers/power/supply/ab8500_btemp.c126
-rw-r--r--drivers/power/supply/ab8500_charger.c381
-rw-r--r--drivers/power/supply/ab8500_fg.c147
-rw-r--r--drivers/power/supply/abx500_chargalg.c118
-rw-r--r--drivers/power/supply/axp20x_battery.c17
-rw-r--r--drivers/power/supply/axp288_fuel_gauge.c26
-rw-r--r--drivers/power/supply/bd70528-charger.c710
-rw-r--r--drivers/power/supply/bq24190_charger.c11
-rw-r--r--drivers/power/supply/charger-manager.c1
-rw-r--r--drivers/power/supply/cpcap-battery.c19
-rw-r--r--drivers/power/supply/cpcap-charger.c39
-rw-r--r--drivers/power/supply/max17040_battery.c42
-rw-r--r--drivers/power/supply/max17042_battery.c2
-rw-r--r--drivers/power/supply/pm2301_charger.c1249
-rw-r--r--drivers/power/supply/rn5t618_power.c235
-rw-r--r--drivers/power/supply/rt5033_battery.c7
-rw-r--r--drivers/power/supply/sbs-battery.c153
-rw-r--r--drivers/power/supply/sc2731_charger.c1
-rw-r--r--drivers/power/supply/sc27xx_fuel_gauge.c1
-rw-r--r--drivers/power/supply/smb347-charger.c1
-rw-r--r--drivers/power/supply/surface_battery.c14
-rw-r--r--drivers/power/supply/surface_charger.c2
-rw-r--r--drivers/pps/clients/pps-ldisc.c11
-rw-r--r--drivers/ps3/ps3-vuart.c2
-rw-r--r--drivers/ps3/ps3av.c22
-rw-r--r--drivers/ptp/Makefile2
-rw-r--r--drivers/ptp/ptp_clock.c64
-rw-r--r--drivers/ptp/ptp_private.h39
-rw-r--r--drivers/ptp/ptp_sysfs.c160
-rw-r--r--drivers/ptp/ptp_vclock.c219
-rw-r--r--drivers/pwm/core.c222
-rw-r--r--drivers/pwm/pwm-atmel-hlcdc.c2
-rw-r--r--drivers/pwm/pwm-atmel-tcb.c2
-rw-r--r--drivers/pwm/pwm-atmel.c2
-rw-r--r--drivers/pwm/pwm-bcm-iproc.c2
-rw-r--r--drivers/pwm/pwm-bcm-kona.c2
-rw-r--r--drivers/pwm/pwm-bcm2835.c2
-rw-r--r--drivers/pwm/pwm-berlin.c162
-rw-r--r--drivers/pwm/pwm-clps711x.c12
-rw-r--r--drivers/pwm/pwm-crc.c12
-rw-r--r--drivers/pwm/pwm-ep93xx.c102
-rw-r--r--drivers/pwm/pwm-fsl-ftm.c2
-rw-r--r--drivers/pwm/pwm-hibvt.c2
-rw-r--r--drivers/pwm/pwm-img.c2
-rw-r--r--drivers/pwm/pwm-imx-tpm.c2
-rw-r--r--drivers/pwm/pwm-imx1.c14
-rw-r--r--drivers/pwm/pwm-imx27.c3
-rw-r--r--drivers/pwm/pwm-jz4740.c2
-rw-r--r--drivers/pwm/pwm-lpc18xx-sct.c2
-rw-r--r--drivers/pwm/pwm-lpss-pci.c4
-rw-r--r--drivers/pwm/pwm-lpss-platform.c4
-rw-r--r--drivers/pwm/pwm-lpss.c8
-rw-r--r--drivers/pwm/pwm-lpss.h1
-rw-r--r--drivers/pwm/pwm-meson.c14
-rw-r--r--drivers/pwm/pwm-mxs.c2
-rw-r--r--drivers/pwm/pwm-omap-dmtimer.c2
-rw-r--r--drivers/pwm/pwm-pca9685.c198
-rw-r--r--drivers/pwm/pwm-pxa.c40
-rw-r--r--drivers/pwm/pwm-renesas-tpu.c2
-rw-r--r--drivers/pwm/pwm-rockchip.c5
-rw-r--r--drivers/pwm/pwm-samsung.c3
-rw-r--r--drivers/pwm/pwm-sifive.c2
-rw-r--r--drivers/pwm/pwm-spear.c37
-rw-r--r--drivers/pwm/pwm-sprd.c15
-rw-r--r--drivers/pwm/pwm-stm32-lp.c2
-rw-r--r--drivers/pwm/pwm-stm32.c2
-rw-r--r--drivers/pwm/pwm-sun4i.c2
-rw-r--r--drivers/pwm/pwm-tegra.c24
-rw-r--r--drivers/pwm/pwm-tiecap.c55
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c2
-rw-r--r--drivers/pwm/pwm-visconti.c17
-rw-r--r--drivers/pwm/pwm-vt8500.c10
-rw-r--r--drivers/regulator/Kconfig55
-rw-r--r--drivers/regulator/Makefile8
-rw-r--r--drivers/regulator/bd70528-regulator.c283
-rw-r--r--drivers/regulator/bd71815-regulator.c60
-rw-r--r--drivers/regulator/bd9576-regulator.c1084
-rw-r--r--drivers/regulator/core.c316
-rw-r--r--drivers/regulator/da9052-regulator.c3
-rw-r--r--drivers/regulator/devres.c52
-rw-r--r--drivers/regulator/fan53555.c118
-rw-r--r--drivers/regulator/fan53880.c7
-rw-r--r--drivers/regulator/fixed.c3
-rw-r--r--drivers/regulator/hi6421-regulator.c8
-rw-r--r--drivers/regulator/hi6421v600-regulator.c59
-rw-r--r--drivers/regulator/hi655x-regulator.c16
-rw-r--r--drivers/regulator/internal.h11
-rw-r--r--drivers/regulator/irq_helpers.c397
-rw-r--r--drivers/regulator/lp8755.c55
-rw-r--r--drivers/regulator/lp87565-regulator.c11
-rw-r--r--drivers/regulator/ltc3589.c73
-rw-r--r--drivers/regulator/max77686-regulator.c42
-rw-r--r--drivers/regulator/max77802-regulator.c70
-rw-r--r--drivers/regulator/max8893.c183
-rw-r--r--drivers/regulator/max8973-regulator.c37
-rw-r--r--drivers/regulator/mcp16502.c79
-rw-r--r--drivers/regulator/mp5416.c44
-rw-r--r--drivers/regulator/mp886x.c32
-rw-r--r--drivers/regulator/mt6315-regulator.c21
-rw-r--r--drivers/regulator/mt6358-regulator.c24
-rw-r--r--drivers/regulator/mt6359-regulator.c997
-rw-r--r--drivers/regulator/of_regulator.c58
-rw-r--r--drivers/regulator/pca9450-regulator.c51
-rw-r--r--drivers/regulator/qcom-labibb-regulator.c10
-rw-r--r--drivers/regulator/qcom-rpmh-regulator.c62
-rw-r--r--drivers/regulator/qcom_smd-regulator.c85
-rw-r--r--drivers/regulator/qcom_spmi-regulator.c6
-rw-r--r--drivers/regulator/qcom_usb_vbus-regulator.c12
-rw-r--r--drivers/regulator/rk808-regulator.c116
-rw-r--r--drivers/regulator/rt4831-regulator.c3
-rw-r--r--drivers/regulator/rt6160-regulator.c319
-rw-r--r--drivers/regulator/rt6245-regulator.c254
-rw-r--r--drivers/regulator/stpmic1_regulator.c20
-rw-r--r--drivers/regulator/sy7636a-regulator.c128
-rw-r--r--drivers/regulator/uniphier-regulator.c1
-rw-r--r--drivers/regulator/userspace-consumer.c14
-rw-r--r--drivers/remoteproc/Kconfig1
-rw-r--r--drivers/remoteproc/imx_rproc.c209
-rw-r--r--drivers/remoteproc/pru_rproc.c3
-rw-r--r--drivers/remoteproc/qcom_q6v5.c2
-rw-r--r--drivers/remoteproc/qcom_q6v5_pas.c22
-rw-r--r--drivers/remoteproc/qcom_wcnss.c5
-rw-r--r--drivers/remoteproc/remoteproc_cdev.c2
-rw-r--r--drivers/remoteproc/remoteproc_core.c75
-rw-r--r--drivers/remoteproc/remoteproc_elf_loader.c12
-rw-r--r--drivers/remoteproc/remoteproc_virtio.c6
-rw-r--r--drivers/remoteproc/stm32_rproc.c16
-rw-r--r--drivers/remoteproc/ti_k3_r5_remoteproc.c151
-rw-r--r--drivers/reset/Kconfig23
-rw-r--r--drivers/reset/Makefile2
-rw-r--r--drivers/reset/core.c25
-rw-r--r--drivers/reset/hisilicon/hi6220_reset.c2
-rw-r--r--drivers/reset/reset-a10sr.c1
-rw-r--r--drivers/reset/reset-bcm6345.c2
-rw-r--r--drivers/reset/reset-berlin.c12
-rw-r--r--drivers/reset/reset-brcmstb.c1
-rw-r--r--drivers/reset/reset-lantiq.c2
-rw-r--r--drivers/reset/reset-microchip-sparx5.c146
-rw-r--r--drivers/reset/reset-oxnas.c2
-rw-r--r--drivers/reset/reset-stm32mp1.c115
-rw-r--r--drivers/reset/reset-ti-syscon.c4
-rw-r--r--drivers/reset/reset-uniphier.c2
-rw-r--r--drivers/reset/reset-zynqmp.c4
-rw-r--r--drivers/reset/sti/reset-syscfg.c2
-rw-r--r--drivers/rpmsg/rpmsg_core.c4
-rw-r--r--drivers/rtc/Kconfig6
-rw-r--r--drivers/rtc/proc.c4
-rw-r--r--drivers/rtc/rtc-at91sam9.c2
-rw-r--r--drivers/rtc/rtc-au1xxx.c5
-rw-r--r--drivers/rtc/rtc-bd70528.c316
-rw-r--r--drivers/rtc/rtc-ds1374.c7
-rw-r--r--drivers/rtc/rtc-efi.c1
-rw-r--r--drivers/rtc/rtc-hid-sensor-time.c1
-rw-r--r--drivers/rtc/rtc-imxdi.c4
-rw-r--r--drivers/rtc/rtc-m41t80.c32
-rw-r--r--drivers/rtc/rtc-max6900.c8
-rw-r--r--drivers/rtc/rtc-max77686.c4
-rw-r--r--drivers/rtc/rtc-mt6397.c2
-rw-r--r--drivers/rtc/rtc-mxc_v2.c1
-rw-r--r--drivers/rtc/rtc-palmas.c15
-rw-r--r--drivers/rtc/rtc-pcf2127.c194
-rw-r--r--drivers/rtc/rtc-pcf85063.c6
-rw-r--r--drivers/rtc/rtc-pcf8523.c146
-rw-r--r--drivers/rtc/rtc-pcf8563.c2
-rw-r--r--drivers/rtc/rtc-rtd119x.c3
-rw-r--r--drivers/rtc/rtc-s5m.c4
-rw-r--r--drivers/rtc/rtc-sc27xx.c2
-rw-r--r--drivers/rtc/rtc-spear.c5
-rw-r--r--drivers/rtc/rtc-stm32.c6
-rw-r--r--drivers/rtc/rtc-tps6586x.c15
-rw-r--r--drivers/rtc/rtc-tps80031.c15
-rw-r--r--drivers/rtc/rtc-v3020.c2
-rw-r--r--drivers/rtc/sysfs.c2
-rw-r--r--drivers/s390/block/dasd.c1
-rw-r--r--drivers/s390/block/dasd_diag.c21
-rw-r--r--drivers/s390/block/dasd_eckd.c2
-rw-r--r--drivers/s390/block/dasd_eckd.h6
-rw-r--r--drivers/s390/block/dasd_genhd.c12
-rw-r--r--drivers/s390/block/dcssblk.c132
-rw-r--r--drivers/s390/block/scm_blk.c21
-rw-r--r--drivers/s390/block/xpram.c89
-rw-r--r--drivers/s390/char/con3215.c5
-rw-r--r--drivers/s390/char/con3270.c1
-rw-r--r--drivers/s390/char/monreader.c125
-rw-r--r--drivers/s390/char/monwriter.c90
-rw-r--r--drivers/s390/char/sclp.c175
-rw-r--r--drivers/s390/char/sclp.h13
-rw-r--r--drivers/s390/char/sclp_cmd.c34
-rw-r--r--drivers/s390/char/sclp_con.c54
-rw-r--r--drivers/s390/char/sclp_ftp.c1
-rw-r--r--drivers/s390/char/sclp_quiesce.c37
-rw-r--r--drivers/s390/char/sclp_rw.c11
-rw-r--r--drivers/s390/char/sclp_rw.h8
-rw-r--r--drivers/s390/char/sclp_tty.c13
-rw-r--r--drivers/s390/char/sclp_vt220.c66
-rw-r--r--drivers/s390/char/tape_char.c2
-rw-r--r--drivers/s390/char/tty3270.c22
-rw-r--r--drivers/s390/char/vmlogrdr.c24
-rw-r--r--drivers/s390/char/zcore.c1
-rw-r--r--drivers/s390/cio/airq.c2
-rw-r--r--drivers/s390/cio/ccwgroup.c60
-rw-r--r--drivers/s390/cio/chp.c3
-rw-r--r--drivers/s390/cio/chsc.c2
-rw-r--r--drivers/s390/cio/cio.c2
-rw-r--r--drivers/s390/cio/cio.h13
-rw-r--r--drivers/s390/cio/cmf.c13
-rw-r--r--drivers/s390/cio/ioasm.c143
-rw-r--r--drivers/s390/cio/qdio.h25
-rw-r--r--drivers/s390/cio/qdio_main.c62
-rw-r--r--drivers/s390/cio/trace.h6
-rw-r--r--drivers/s390/crypto/ap_bus.c134
-rw-r--r--drivers/s390/crypto/ap_bus.h14
-rw-r--r--drivers/s390/crypto/ap_card.c18
-rw-r--r--drivers/s390/crypto/ap_queue.c28
-rw-r--r--drivers/s390/crypto/vfio_ap_drv.c13
-rw-r--r--drivers/s390/crypto/vfio_ap_ops.c10
-rw-r--r--drivers/s390/crypto/zcrypt_api.c7
-rw-r--r--drivers/s390/crypto/zcrypt_api.h3
-rw-r--r--drivers/s390/crypto/zcrypt_card.c30
-rw-r--r--drivers/s390/crypto/zcrypt_ccamisc.c14
-rw-r--r--drivers/s390/crypto/zcrypt_ccamisc.h4
-rw-r--r--drivers/s390/crypto/zcrypt_cex4.c9
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype50.c28
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype6.c59
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype6.h2
-rw-r--r--drivers/s390/crypto/zcrypt_queue.c22
-rw-r--r--drivers/s390/net/ctcm_fsms.c1
-rw-r--r--drivers/s390/net/netiucv.c28
-rw-r--r--drivers/s390/net/qeth_core.h42
-rw-r--r--drivers/s390/net/qeth_core_main.c349
-rw-r--r--drivers/s390/net/qeth_ethtool.c7
-rw-r--r--drivers/s390/net/qeth_l2_main.c12
-rw-r--r--drivers/s390/net/qeth_l3_main.c1
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c5
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c1
-rw-r--r--drivers/s390/virtio/virtio_ccw.c30
-rw-r--r--drivers/scsi/3w-9xxx.c74
-rw-r--r--drivers/scsi/3w-9xxx.h121
-rw-r--r--drivers/scsi/3w-xxxx.c6
-rw-r--r--drivers/scsi/53c700.c6
-rw-r--r--drivers/scsi/FlashPoint.c197
-rw-r--r--drivers/scsi/Kconfig5
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/NCR5380.c10
-rw-r--r--drivers/scsi/aacraid/aachba.c10
-rw-r--r--drivers/scsi/aacraid/aacraid.h2
-rw-r--r--drivers/scsi/advansys.c4
-rw-r--r--drivers/scsi/aha152x.c33
-rw-r--r--drivers/scsi/aha1740.c7
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c19
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_core.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c1
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c1
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sds.c4
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c2
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h2
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c43
-rw-r--r--drivers/scsi/arm/acornscsi.c46
-rw-r--r--drivers/scsi/arm/fas216.c19
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c25
-rw-r--r--drivers/scsi/be2iscsi/be_main.c110
-rw-r--r--drivers/scsi/bfa/bfa_defs_svc.h2
-rw-r--r--drivers/scsi/bfa/bfa_svc.c8
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c32
-rw-r--r--drivers/scsi/ch.c5
-rw-r--r--drivers/scsi/constants.c17
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/cxgb3i.c1
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c1
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.c17
-rw-r--r--drivers/scsi/cxlflash/superpipe.c3
-rw-r--r--drivers/scsi/dc395x.c80
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c81
-rw-r--r--drivers/scsi/elx/Kconfig9
-rw-r--r--drivers/scsi/elx/Makefile18
-rw-r--r--drivers/scsi/elx/efct/efct_driver.c786
-rw-r--r--drivers/scsi/elx/efct/efct_driver.h109
-rw-r--r--drivers/scsi/elx/efct/efct_hw.c3581
-rw-r--r--drivers/scsi/elx/efct/efct_hw.h764
-rw-r--r--drivers/scsi/elx/efct/efct_hw_queues.c677
-rw-r--r--drivers/scsi/elx/efct/efct_io.c191
-rw-r--r--drivers/scsi/elx/efct/efct_io.h174
-rw-r--r--drivers/scsi/elx/efct/efct_lio.c1698
-rw-r--r--drivers/scsi/elx/efct/efct_lio.h189
-rw-r--r--drivers/scsi/elx/efct/efct_scsi.c1159
-rw-r--r--drivers/scsi/elx/efct/efct_scsi.h203
-rw-r--r--drivers/scsi/elx/efct/efct_unsol.c492
-rw-r--r--drivers/scsi/elx/efct/efct_unsol.h17
-rw-r--r--drivers/scsi/elx/efct/efct_xport.c1111
-rw-r--r--drivers/scsi/elx/efct/efct_xport.h186
-rw-r--r--drivers/scsi/elx/include/efc_common.h37
-rw-r--r--drivers/scsi/elx/libefc/efc.h52
-rw-r--r--drivers/scsi/elx/libefc/efc_cmds.c777
-rw-r--r--drivers/scsi/elx/libefc/efc_cmds.h35
-rw-r--r--drivers/scsi/elx/libefc/efc_device.c1603
-rw-r--r--drivers/scsi/elx/libefc/efc_device.h72
-rw-r--r--drivers/scsi/elx/libefc/efc_domain.c1088
-rw-r--r--drivers/scsi/elx/libefc/efc_domain.h54
-rw-r--r--drivers/scsi/elx/libefc/efc_els.c1098
-rw-r--r--drivers/scsi/elx/libefc/efc_els.h107
-rw-r--r--drivers/scsi/elx/libefc/efc_fabric.c1564
-rw-r--r--drivers/scsi/elx/libefc/efc_fabric.h116
-rw-r--r--drivers/scsi/elx/libefc/efc_node.c1102
-rw-r--r--drivers/scsi/elx/libefc/efc_node.h191
-rw-r--r--drivers/scsi/elx/libefc/efc_nport.c777
-rw-r--r--drivers/scsi/elx/libefc/efc_nport.h50
-rw-r--r--drivers/scsi/elx/libefc/efc_sm.c54
-rw-r--r--drivers/scsi/elx/libefc/efc_sm.h197
-rw-r--r--drivers/scsi/elx/libefc/efclib.c81
-rw-r--r--drivers/scsi/elx/libefc/efclib.h620
-rw-r--r--drivers/scsi/elx/libefc_sli/sli4.c5160
-rw-r--r--drivers/scsi/elx/libefc_sli/sli4.h4132
-rw-r--r--drivers/scsi/esas2r/atioctl.h2
-rw-r--r--drivers/scsi/esas2r/esas2r_main.c2
-rw-r--r--drivers/scsi/esp_scsi.c4
-rw-r--r--drivers/scsi/fcoe/fcoe.c6
-rw-r--r--drivers/scsi/fdomain.c22
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas.h7
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c99
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v1_hw.c21
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v2_hw.c11
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v3_hw.c11
-rw-r--r--drivers/scsi/hosts.c14
-rw-r--r--drivers/scsi/hptiop.c2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c61
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.h3
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c2
-rw-r--r--drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c1
-rw-r--r--drivers/scsi/imm.c15
-rw-r--r--drivers/scsi/ipr.c4
-rw-r--r--drivers/scsi/ipr.h1
-rw-r--r--drivers/scsi/ips.c10
-rw-r--r--drivers/scsi/isci/init.c1
-rw-r--r--drivers/scsi/isci/request.c10
-rw-r--r--drivers/scsi/isci/task.c6
-rw-r--r--drivers/scsi/iscsi_tcp.c7
-rw-r--r--drivers/scsi/libfc/fc_encode.h256
-rw-r--r--drivers/scsi/libfc/fc_lport.c88
-rw-r--r--drivers/scsi/libfc/fc_rport.c13
-rw-r--r--drivers/scsi/libiscsi.c234
-rw-r--r--drivers/scsi/libsas/sas_ata.c7
-rw-r--r--drivers/scsi/libsas/sas_discover.c2
-rw-r--r--drivers/scsi/libsas/sas_expander.c2
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c9
-rw-r--r--drivers/scsi/libsas/sas_task.c4
-rw-r--r--drivers/scsi/lpfc/lpfc.h124
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c59
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h12
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c298
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c11
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c665
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c229
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h124
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h12
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c111
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c9
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c40
-rw-r--r--drivers/scsi/lpfc/lpfc_nvme.c14
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c416
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c66
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h11
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/megaraid.c20
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c45
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h16
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c102
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c6
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c21
-rw-r--r--drivers/scsi/mesh.c9
-rw-r--r--drivers/scsi/mpi3mr/Kconfig7
-rw-r--r--drivers/scsi/mpi3mr/Makefile4
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h1880
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_image.h216
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_init.h159
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_ioc.h1004
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_sas.h33
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_transport.h463
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr.h901
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_debug.h60
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_fw.c3957
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_os.c4046
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c349
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.h8
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_config.c18
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_scsih.c193
-rw-r--r--drivers/scsi/mvsas/mv_init.c27
-rw-r--r--drivers/scsi/mvsas/mv_sas.c10
-rw-r--r--drivers/scsi/mvumi.c10
-rw-r--r--drivers/scsi/myrb.c64
-rw-r--r--drivers/scsi/myrs.c9
-rw-r--r--drivers/scsi/nsp32.c419
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c2
-rw-r--r--drivers/scsi/pm8001/pm8001_ctl.c48
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c34
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c30
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c51
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c64
-rw-r--r--drivers/scsi/pmcraid.h4
-rw-r--r--drivers/scsi/ppa.c14
-rw-r--r--drivers/scsi/ps3rom.c7
-rw-r--r--drivers/scsi/qedf/qedf_attr.c14
-rw-r--r--drivers/scsi/qedf/qedf_dbg.c3
-rw-r--r--drivers/scsi/qedf/qedf_io.c27
-rw-r--r--drivers/scsi/qedf/qedf_main.c9
-rw-r--r--drivers/scsi/qedi/qedi.h1
-rw-r--r--drivers/scsi/qedi/qedi_fw.c291
-rw-r--r--drivers/scsi/qedi/qedi_gbl.h4
-rw-r--r--drivers/scsi/qedi/qedi_iscsi.c105
-rw-r--r--drivers/scsi/qedi/qedi_iscsi.h5
-rw-r--r--drivers/scsi/qedi/qedi_main.c9
-rw-r--r--drivers/scsi/qedi/qedi_sysfs.c14
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h5
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c8
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c19
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c27
-rw-r--r--drivers/scsi/qla2xxx/qla_nvme.c6
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c68
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c3
-rw-r--r--drivers/scsi/qla4xxx/ql4_83xx.c3
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c4
-rw-r--r--drivers/scsi/qlogicfas408.c138
-rw-r--r--drivers/scsi/scsi.c11
-rw-r--r--drivers/scsi/scsi_debug.c20
-rw-r--r--drivers/scsi/scsi_error.c72
-rw-r--r--drivers/scsi/scsi_ioctl.c7
-rw-r--r--drivers/scsi/scsi_lib.c142
-rw-r--r--drivers/scsi/scsi_logging.c10
-rw-r--r--drivers/scsi/scsi_priv.h1
-rw-r--r--drivers/scsi/scsi_scan.c18
-rw-r--r--drivers/scsi/scsi_transport_fc.c2
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c499
-rw-r--r--drivers/scsi/scsi_transport_sas.c9
-rw-r--r--drivers/scsi/scsi_transport_spi.c2
-rw-r--r--drivers/scsi/sd.c93
-rw-r--r--drivers/scsi/sd_zbc.c3
-rw-r--r--drivers/scsi/sg.c11
-rw-r--r--drivers/scsi/smartpqi/smartpqi_init.c3
-rw-r--r--drivers/scsi/snic/snic_ctl.c5
-rw-r--r--drivers/scsi/snic/snic_debugfs.c23
-rw-r--r--drivers/scsi/snic/snic_trc.h3
-rw-r--r--drivers/scsi/sr.c6
-rw-r--r--drivers/scsi/sr_ioctl.c6
-rw-r--r--drivers/scsi/st.c10
-rw-r--r--drivers/scsi/stex.c9
-rw-r--r--drivers/scsi/storvsc_drv.c223
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c6
-rw-r--r--drivers/scsi/ufs/Kconfig1
-rw-r--r--drivers/scsi/ufs/cdns-pltfrm.c2
-rw-r--r--drivers/scsi/ufs/tc-dwc-g210-pci.c2
-rw-r--r--drivers/scsi/ufs/ufs-debugfs.c6
-rw-r--r--drivers/scsi/ufs/ufs-debugfs.h2
-rw-r--r--drivers/scsi/ufs/ufs-exynos.c31
-rw-r--r--drivers/scsi/ufs/ufs-exynos.h26
-rw-r--r--drivers/scsi/ufs/ufs-hisi.c4
-rw-r--r--drivers/scsi/ufs/ufs-mediatek.c45
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c2
-rw-r--r--drivers/scsi/ufs/ufs-sysfs.c269
-rw-r--r--drivers/scsi/ufs/ufs_bsg.c6
-rw-r--r--drivers/scsi/ufs/ufshcd-pci.c36
-rw-r--r--drivers/scsi/ufs/ufshcd.c1167
-rw-r--r--drivers/scsi/ufs/ufshcd.h91
-rw-r--r--drivers/scsi/ufs/ufshci.h1
-rw-r--r--drivers/scsi/virtio_scsi.c8
-rw-r--r--drivers/scsi/vmw_pvscsi.c6
-rw-r--r--drivers/scsi/wd33c93.c43
-rw-r--r--drivers/scsi/xen-scsifront.c8
-rw-r--r--drivers/siox/siox-bus-gpio.c19
-rw-r--r--drivers/soc/amlogic/meson-ee-pwrc.c46
-rw-r--r--drivers/soc/bcm/brcmstb/common.c5
-rw-r--r--drivers/soc/bcm/brcmstb/pm/pm-arm.c1
-rw-r--r--drivers/soc/imx/gpcv2.c634
-rw-r--r--drivers/soc/imx/soc-imx.c3
-rw-r--r--drivers/soc/ixp4xx/ixp4xx-npe.c9
-rw-r--r--drivers/soc/ixp4xx/ixp4xx-qmgr.c2
-rw-r--r--drivers/soc/litex/Kconfig12
-rw-r--r--drivers/soc/litex/litex_soc_ctrl.c3
-rw-r--r--drivers/soc/mediatek/mtk-devapc.c1
-rw-r--r--drivers/soc/mediatek/mtk-pm-domains.c42
-rw-r--r--drivers/soc/mediatek/mtk-pmic-wrap.c35
-rw-r--r--drivers/soc/qcom/rpmhpd.c21
-rw-r--r--drivers/soc/qcom/rpmpd.c22
-rw-r--r--drivers/soc/qcom/smd-rpm.c2
-rw-r--r--drivers/soc/qcom/smem_state.c36
-rw-r--r--drivers/soc/qcom/socinfo.c56
-rw-r--r--drivers/soc/renesas/Kconfig5
-rw-r--r--drivers/soc/renesas/renesas-soc.c33
-rw-r--r--drivers/soc/rockchip/pm_domains.c252
-rw-r--r--drivers/soc/tegra/Kconfig2
-rw-r--r--drivers/soc/tegra/common.c97
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra.c6
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra30.c3
-rw-r--r--drivers/soc/tegra/pmc.c149
-rw-r--r--drivers/soc/tegra/regulators-tegra20.c94
-rw-r--r--drivers/soc/tegra/regulators-tegra30.c93
-rw-r--r--drivers/soc/ti/smartreflex.c4
-rw-r--r--drivers/soc/ti/wkup_m3_ipc.c4
-rw-r--r--drivers/soundwire/Kconfig1
-rw-r--r--drivers/soundwire/bus.c180
-rw-r--r--drivers/soundwire/bus.h13
-rw-r--r--drivers/soundwire/cadence_master.c21
-rw-r--r--drivers/soundwire/cadence_master.h3
-rw-r--r--drivers/soundwire/dmi-quirks.c2
-rw-r--r--drivers/soundwire/generic_bandwidth_allocation.c14
-rw-r--r--drivers/soundwire/intel.c56
-rw-r--r--drivers/soundwire/intel.h14
-rw-r--r--drivers/soundwire/intel_init.c232
-rw-r--r--drivers/soundwire/slave.c4
-rw-r--r--drivers/soundwire/stream.c13
-rw-r--r--drivers/spi/Kconfig1
-rw-r--r--drivers/spi/spi-altera-dfl.c4
-rw-r--r--drivers/spi/spi-ath79.c9
-rw-r--r--drivers/spi/spi-atmel.c139
-rw-r--r--drivers/spi/spi-bcm2835.c204
-rw-r--r--drivers/spi/spi-bcm2835aux.c2
-rw-r--r--drivers/spi/spi-dw-mmio.c2
-rw-r--r--drivers/spi/spi-geni-qcom.c4
-rw-r--r--drivers/spi/spi-hisi-kunpeng.c51
-rw-r--r--drivers/spi/spi-lm70llp.c2
-rw-r--r--drivers/spi/spi-loopback-test.c2
-rw-r--r--drivers/spi/spi-mem.c88
-rw-r--r--drivers/spi/spi-meson-spicc.c8
-rw-r--r--drivers/spi/spi-mpc512x-psc.c4
-rw-r--r--drivers/spi/spi-mpc52xx-psc.c4
-rw-r--r--drivers/spi/spi-mpc52xx.c2
-rw-r--r--drivers/spi/spi-npcm-pspi.c2
-rw-r--r--drivers/spi/spi-nxp-fspi.c11
-rw-r--r--drivers/spi/spi-oc-tiny.c2
-rw-r--r--drivers/spi/spi-omap-100k.c6
-rw-r--r--drivers/spi/spi-omap-uwire.c4
-rw-r--r--drivers/spi/spi-omap2-mcspi.c4
-rw-r--r--drivers/spi/spi-pl022.c4
-rw-r--r--drivers/spi/spi-ppc4xx.c10
-rw-r--r--drivers/spi/spi-pxa2xx-dma.c41
-rw-r--r--drivers/spi/spi-pxa2xx-pci.c11
-rw-r--r--drivers/spi/spi-pxa2xx.c387
-rw-r--r--drivers/spi/spi-pxa2xx.h68
-rw-r--r--drivers/spi/spi-rockchip.c55
-rw-r--r--drivers/spi/spi-rspi.c6
-rw-r--r--drivers/spi/spi-sh-msiof.c4
-rw-r--r--drivers/spi/spi-stm32-qspi.c88
-rw-r--r--drivers/spi/spi-sun6i.c6
-rw-r--r--drivers/spi/spi-tegra114.c3
-rw-r--r--drivers/spi/spi-tegra20-slink.c5
-rw-r--r--drivers/spi/spi-tegra210-quad.c2
-rw-r--r--drivers/spi/spi-topcliff-pch.c4
-rw-r--r--drivers/spi/spi-uniphier.c2
-rw-r--r--drivers/spi/spi.c275
-rw-r--r--drivers/spi/spidev.c2
-rw-r--r--drivers/spmi/Kconfig9
-rw-r--r--drivers/spmi/Makefile1
-rw-r--r--drivers/spmi/hisi-spmi-controller.c (renamed from drivers/staging/hikey9xx/hisi-spmi-controller.c)2
-rw-r--r--drivers/ssb/driver_gpio.c6
-rw-r--r--drivers/ssb/driver_pcicore.c18
-rw-r--r--drivers/ssb/main.c36
-rw-r--r--drivers/ssb/pci.c16
-rw-r--r--drivers/ssb/pcmcia.c16
-rw-r--r--drivers/ssb/scan.c1
-rw-r--r--drivers/ssb/sdio.c1
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/android/ashmem.c3
-rw-r--r--drivers/staging/axis-fifo/axis-fifo.c18
-rw-r--r--drivers/staging/board/Kconfig2
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.c11
-rw-r--r--drivers/staging/fbtft/TODO5
-rw-r--r--drivers/staging/fbtft/fb_agm1264k-fl.c30
-rw-r--r--drivers/staging/fbtft/fb_bd663474.c4
-rw-r--r--drivers/staging/fbtft/fb_hx8347d.c29
-rw-r--r--drivers/staging/fbtft/fb_ili9163.c4
-rw-r--r--drivers/staging/fbtft/fb_ili9320.c4
-rw-r--r--drivers/staging/fbtft/fb_ili9325.c4
-rw-r--r--drivers/staging/fbtft/fb_ili9340.c1
-rw-r--r--drivers/staging/fbtft/fb_s6d1121.c4
-rw-r--r--drivers/staging/fbtft/fb_sh1106.c1
-rw-r--r--drivers/staging/fbtft/fb_ssd1289.c4
-rw-r--r--drivers/staging/fbtft/fb_ssd1325.c2
-rw-r--r--drivers/staging/fbtft/fb_ssd1331.c6
-rw-r--r--drivers/staging/fbtft/fb_ssd1351.c1
-rw-r--r--drivers/staging/fbtft/fb_upd161704.c4
-rw-r--r--drivers/staging/fbtft/fb_watterott.c1
-rw-r--r--drivers/staging/fbtft/fbtft-bus.c3
-rw-r--r--drivers/staging/fbtft/fbtft-core.c25
-rw-r--r--drivers/staging/fbtft/fbtft-io.c12
-rw-r--r--drivers/staging/fieldbus/anybuss/anybuss-client.h2
-rw-r--r--drivers/staging/fieldbus/anybuss/hms-profinet.c3
-rw-r--r--drivers/staging/fieldbus/anybuss/host.c8
-rw-r--r--drivers/staging/fwserial/fwserial.c60
-rw-r--r--drivers/staging/gdm724x/gdm_lte.c21
-rw-r--r--drivers/staging/gdm724x/gdm_tty.c2
-rw-r--r--drivers/staging/greybus/audio_topology.c4
-rw-r--r--drivers/staging/greybus/gbphy.c4
-rw-r--r--drivers/staging/greybus/spilib.c1
-rw-r--r--drivers/staging/greybus/uart.c22
-rw-r--r--drivers/staging/gs_fpgaboot/README2
-rw-r--r--drivers/staging/hikey9xx/Kconfig22
-rw-r--r--drivers/staging/hikey9xx/Makefile3
-rw-r--r--drivers/staging/hikey9xx/hi6421-spmi-pmic.c116
-rw-r--r--drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml7
-rw-r--r--drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml71
-rw-r--r--drivers/staging/hikey9xx/phy-hi3670-usb3.yaml73
-rw-r--r--drivers/staging/iio/accel/adis16203.c6
-rw-r--r--drivers/staging/iio/accel/adis16240.c6
-rw-r--r--drivers/staging/iio/addac/adt7316.c12
-rw-r--r--drivers/staging/iio/cdc/ad7746.c114
-rw-r--r--drivers/staging/iio/cdc/ad7746.h28
-rw-r--r--drivers/staging/iio/frequency/ad9834.c5
-rw-r--r--drivers/staging/kpc2000/Kconfig59
-rw-r--r--drivers/staging/kpc2000/Makefile6
-rw-r--r--drivers/staging/kpc2000/TODO2
-rw-r--r--drivers/staging/kpc2000/kpc.h23
-rw-r--r--drivers/staging/kpc2000/kpc2000/Makefile4
-rw-r--r--drivers/staging/kpc2000/kpc2000/cell_probe.c548
-rw-r--r--drivers/staging/kpc2000/kpc2000/core.c565
-rw-r--r--drivers/staging/kpc2000/kpc2000/dma_common_defs.h23
-rw-r--r--drivers/staging/kpc2000/kpc2000/pcie.h90
-rw-r--r--drivers/staging/kpc2000/kpc2000/uapi.h22
-rw-r--r--drivers/staging/kpc2000/kpc2000_i2c.c731
-rw-r--r--drivers/staging/kpc2000/kpc2000_spi.c517
-rw-r--r--drivers/staging/kpc2000/kpc_dma/Makefile6
-rw-r--r--drivers/staging/kpc2000/kpc_dma/dma.c270
-rw-r--r--drivers/staging/kpc2000/kpc_dma/fileops.c363
-rw-r--r--drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.c249
-rw-r--r--drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.h222
-rw-r--r--drivers/staging/kpc2000/kpc_dma/uapi.h11
-rw-r--r--drivers/staging/ks7010/ks_hostif.c14
-rw-r--r--drivers/staging/ks7010/ks_hostif.h24
-rw-r--r--drivers/staging/media/Kconfig2
-rw-r--r--drivers/staging/media/Makefile1
-rw-r--r--drivers/staging/media/atomisp/Makefile1
-rw-r--r--drivers/staging/media/atomisp/TODO5
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-gc0310.c57
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-gc2235.c37
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c6
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c120
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-ov2680.c36
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-ov2722.c28
-rw-r--r--drivers/staging/media/atomisp/i2c/mt9m114.h6
-rw-r--r--drivers/staging/media/atomisp/i2c/ov2680.h10
-rw-r--r--drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c10
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_acc.c12
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_cmd.c52
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_cmd.h161
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_compat_css20.c4
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.c1202
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_csi2.c28
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_csi2.h2
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_file.c14
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_fops.c18
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_subdev.c68
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_subdev.h9
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_tpg.c12
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_v4l2.c6
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css.c2089
-rw-r--r--drivers/staging/media/av7110/Kconfig94
-rw-r--r--drivers/staging/media/av7110/Makefile22
-rw-r--r--drivers/staging/media/av7110/TODO3
-rw-r--r--drivers/staging/media/av7110/audio-bilingual-channel-select.rst58
-rw-r--r--drivers/staging/media/av7110/audio-channel-select.rst57
-rw-r--r--drivers/staging/media/av7110/audio-clear-buffer.rst48
-rw-r--r--drivers/staging/media/av7110/audio-continue.rst48
-rw-r--r--drivers/staging/media/av7110/audio-fclose.rst51
-rw-r--r--drivers/staging/media/av7110/audio-fopen.rst103
-rw-r--r--drivers/staging/media/av7110/audio-fwrite.rst79
-rw-r--r--drivers/staging/media/av7110/audio-get-capabilities.rst54
-rw-r--r--drivers/staging/media/av7110/audio-get-status.rst54
-rw-r--r--drivers/staging/media/av7110/audio-pause.rst49
-rw-r--r--drivers/staging/media/av7110/audio-play.rst48
-rw-r--r--drivers/staging/media/av7110/audio-select-source.rst56
-rw-r--r--drivers/staging/media/av7110/audio-set-av-sync.rst58
-rw-r--r--drivers/staging/media/av7110/audio-set-bypass-mode.rst62
-rw-r--r--drivers/staging/media/av7110/audio-set-id.rst59
-rw-r--r--drivers/staging/media/av7110/audio-set-mixer.rst53
-rw-r--r--drivers/staging/media/av7110/audio-set-mute.rst62
-rw-r--r--drivers/staging/media/av7110/audio-set-streamtype.rst66
-rw-r--r--drivers/staging/media/av7110/audio-stop.rst48
-rw-r--r--drivers/staging/media/av7110/audio.h101
-rw-r--r--drivers/staging/media/av7110/audio.rst27
-rw-r--r--drivers/staging/media/av7110/audio_data_types.rst116
-rw-r--r--drivers/staging/media/av7110/audio_function_calls.rst30
-rw-r--r--drivers/staging/media/av7110/av7110.c (renamed from drivers/media/pci/ttpci/av7110.c)0
-rw-r--r--drivers/staging/media/av7110/av7110.h (renamed from drivers/media/pci/ttpci/av7110.h)7
-rw-r--r--drivers/staging/media/av7110/av7110_av.c (renamed from drivers/media/pci/ttpci/av7110_av.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_av.h (renamed from drivers/media/pci/ttpci/av7110_av.h)0
-rw-r--r--drivers/staging/media/av7110/av7110_ca.c (renamed from drivers/media/pci/ttpci/av7110_ca.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_ca.h (renamed from drivers/media/pci/ttpci/av7110_ca.h)0
-rw-r--r--drivers/staging/media/av7110/av7110_hw.c (renamed from drivers/media/pci/ttpci/av7110_hw.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_hw.h (renamed from drivers/media/pci/ttpci/av7110_hw.h)0
-rw-r--r--drivers/staging/media/av7110/av7110_ipack.c (renamed from drivers/media/pci/ttpci/av7110_ipack.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_ipack.h (renamed from drivers/media/pci/ttpci/av7110_ipack.h)0
-rw-r--r--drivers/staging/media/av7110/av7110_ir.c (renamed from drivers/media/pci/ttpci/av7110_ir.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_v4l.c (renamed from drivers/media/pci/ttpci/av7110_v4l.c)0
-rw-r--r--drivers/staging/media/av7110/budget-patch.c (renamed from drivers/media/pci/ttpci/budget-patch.c)0
-rw-r--r--drivers/staging/media/av7110/dvb_filter.c (renamed from drivers/media/pci/ttpci/dvb_filter.c)0
-rw-r--r--drivers/staging/media/av7110/dvb_filter.h (renamed from drivers/media/pci/ttpci/dvb_filter.h)0
-rw-r--r--drivers/staging/media/av7110/osd.h181
-rw-r--r--drivers/staging/media/av7110/sp8870.c (renamed from drivers/media/dvb-frontends/sp8870.c)0
-rw-r--r--drivers/staging/media/av7110/sp8870.h (renamed from drivers/media/dvb-frontends/sp8870.h)0
-rw-r--r--drivers/staging/media/av7110/video-clear-buffer.rst54
-rw-r--r--drivers/staging/media/av7110/video-command.rst96
-rw-r--r--drivers/staging/media/av7110/video-continue.rst57
-rw-r--r--drivers/staging/media/av7110/video-fast-forward.rst72
-rw-r--r--drivers/staging/media/av7110/video-fclose.rst51
-rw-r--r--drivers/staging/media/av7110/video-fopen.rst111
-rw-r--r--drivers/staging/media/av7110/video-freeze.rst61
-rw-r--r--drivers/staging/media/av7110/video-fwrite.rst79
-rw-r--r--drivers/staging/media/av7110/video-get-capabilities.rst61
-rw-r--r--drivers/staging/media/av7110/video-get-event.rst105
-rw-r--r--drivers/staging/media/av7110/video-get-frame-count.rst65
-rw-r--r--drivers/staging/media/av7110/video-get-pts.rst69
-rw-r--r--drivers/staging/media/av7110/video-get-size.rst69
-rw-r--r--drivers/staging/media/av7110/video-get-status.rst72
-rw-r--r--drivers/staging/media/av7110/video-play.rst57
-rw-r--r--drivers/staging/media/av7110/video-select-source.rst76
-rw-r--r--drivers/staging/media/av7110/video-set-blank.rst64
-rw-r--r--drivers/staging/media/av7110/video-set-display-format.rst60
-rw-r--r--drivers/staging/media/av7110/video-set-format.rst82
-rw-r--r--drivers/staging/media/av7110/video-set-streamtype.rst61
-rw-r--r--drivers/staging/media/av7110/video-slowmotion.rst72
-rw-r--r--drivers/staging/media/av7110/video-stillpicture.rst61
-rw-r--r--drivers/staging/media/av7110/video-stop.rst74
-rw-r--r--drivers/staging/media/av7110/video-try-command.rst66
-rw-r--r--drivers/staging/media/av7110/video.h220
-rw-r--r--drivers/staging/media/av7110/video.rst36
-rw-r--r--drivers/staging/media/av7110/video_function_calls.rst35
-rw-r--r--drivers/staging/media/av7110/video_types.rst248
-rw-r--r--drivers/staging/media/hantro/Kconfig10
-rw-r--r--drivers/staging/media/hantro/Makefile15
-rw-r--r--drivers/staging/media/hantro/hantro.h13
-rw-r--r--drivers/staging/media/hantro/hantro_drv.c185
-rw-r--r--drivers/staging/media/hantro/hantro_g1.c39
-rw-r--r--drivers/staging/media/hantro/hantro_g1_h264_dec.c10
-rw-r--r--drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c119
-rw-r--r--drivers/staging/media/hantro/hantro_g1_vp8_dec.c6
-rw-r--r--drivers/staging/media/hantro/hantro_g2_hevc_dec.c586
-rw-r--r--drivers/staging/media/hantro/hantro_g2_regs.h198
-rw-r--r--drivers/staging/media/hantro/hantro_h1_jpeg_enc.c4
-rw-r--r--drivers/staging/media/hantro/hantro_hevc.c333
-rw-r--r--drivers/staging/media/hantro/hantro_hw.h101
-rw-r--r--drivers/staging/media/hantro/hantro_mpeg2.c2
-rw-r--r--drivers/staging/media/hantro/hantro_postproc.c14
-rw-r--r--drivers/staging/media/hantro/hantro_v4l2.c14
-rw-r--r--drivers/staging/media/hantro/imx8m_vpu_hw.c79
-rw-r--r--drivers/staging/media/hantro/rk3288_vpu_hw.c236
-rw-r--r--drivers/staging/media/hantro/rk3399_vpu_hw.c222
-rw-r--r--drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c (renamed from drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c)32
-rw-r--r--drivers/staging/media/hantro/rockchip_vpu2_hw_mpeg2_dec.c (renamed from drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c)123
-rw-r--r--drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c (renamed from drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c)6
-rw-r--r--drivers/staging/media/hantro/rockchip_vpu2_regs.h (renamed from drivers/staging/media/hantro/rk3399_vpu_regs.h)6
-rw-r--r--drivers/staging/media/hantro/rockchip_vpu_hw.c526
-rw-r--r--drivers/staging/media/hantro/sama5d4_vdec_hw.c117
-rw-r--r--drivers/staging/media/imx/imx-ic-prp.c19
-rw-r--r--drivers/staging/media/imx/imx-ic-prpencvf.c31
-rw-r--r--drivers/staging/media/imx/imx-media-csi.c96
-rw-r--r--drivers/staging/media/imx/imx-media-utils.c4
-rw-r--r--drivers/staging/media/imx/imx-media-vdic.c24
-rw-r--r--drivers/staging/media/imx/imx-media.h2
-rw-r--r--drivers/staging/media/imx/imx6-mipi-csi2.c12
-rw-r--r--drivers/staging/media/imx/imx7-media-csi.c33
-rw-r--r--drivers/staging/media/imx/imx7-mipi-csis.c1020
-rw-r--r--drivers/staging/media/ipu3/include/uapi/intel-ipu3.h (renamed from drivers/staging/media/ipu3/include/intel-ipu3.h)13
-rw-r--r--drivers/staging/media/ipu3/ipu3-abi.h2
-rw-r--r--drivers/staging/media/ipu3/ipu3-css-pool.h1
-rw-r--r--drivers/staging/media/ipu3/ipu3-v4l2.c26
-rw-r--r--drivers/staging/media/ipu3/ipu3.c3
-rw-r--r--drivers/staging/media/meson/vdec/vdec_helpers.c2
-rw-r--r--drivers/staging/media/omap4iss/iss.h3
-rw-r--r--drivers/staging/media/omap4iss/iss_csi2.c37
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipe.c37
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipeif.c47
-rw-r--r--drivers/staging/media/omap4iss/iss_resizer.c39
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c4
-rw-r--r--drivers/staging/media/rkvdec/rkvdec.c12
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.c16
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus.h6
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_dec.c12
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_h265.c16
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c97
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_video.c14
-rw-r--r--drivers/staging/media/tegra-vde/vde.c22
-rw-r--r--drivers/staging/media/tegra-video/csi.c13
-rw-r--r--drivers/staging/media/tegra-video/vi.c31
-rw-r--r--drivers/staging/media/zoran/zoran.h1
-rw-r--r--drivers/staging/media/zoran/zoran_card.c7
-rw-r--r--drivers/staging/media/zoran/zoran_device.c65
-rw-r--r--drivers/staging/media/zoran/zoran_device.h2
-rw-r--r--drivers/staging/media/zoran/zoran_driver.c6
-rw-r--r--drivers/staging/media/zoran/zr36016.c3
-rw-r--r--drivers/staging/media/zoran/zr36050.c5
-rw-r--r--drivers/staging/media/zoran/zr36057.h14
-rw-r--r--drivers/staging/media/zoran/zr36060.c3
-rw-r--r--drivers/staging/most/dim2/dim2.c23
-rw-r--r--drivers/staging/most/dim2/hal.c10
-rw-r--r--drivers/staging/most/i2c/i2c.c12
-rw-r--r--drivers/staging/most/net/net.c6
-rw-r--r--drivers/staging/mt7621-dts/gbpc1.dts6
-rw-r--r--drivers/staging/mt7621-dts/mt7621.dtsi79
-rw-r--r--drivers/staging/mt7621-pci/pci-mt7621.c328
-rw-r--r--drivers/staging/nvec/nvec.c7
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.c2
-rw-r--r--drivers/staging/octeon/ethernet-tx.c1
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon.c1
-rw-r--r--drivers/staging/qlge/qlge_ethtool.c2
-rw-r--r--drivers/staging/qlge/qlge_main.c10
-rw-r--r--drivers/staging/rtl8188eu/Makefile1
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ap.c144
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_cmd.c153
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_debug.c187
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_efuse.c62
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ieee80211.c111
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ioctl_set.c112
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_led.c53
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme.c236
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme_ext.c483
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_pwrctrl.c76
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_recv.c289
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_security.c33
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_sta_mgt.c59
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_wlan_util.c111
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_xmit.c210
-rw-r--r--drivers/staging/rtl8188eu/hal/hal8188e_rate_adaptive.c123
-rw-r--r--drivers/staging/rtl8188eu/hal/hal_intf.c6
-rw-r--r--drivers/staging/rtl8188eu/hal/odm.c161
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_rtl8188e.c6
-rw-r--r--drivers/staging/rtl8188eu/hal/phy.c53
-rw-r--r--drivers/staging/rtl8188eu/hal/pwrseqcmd.c28
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c57
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_dm.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c65
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_xmit.c32
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_led.c4
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c10
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c28
-rw-r--r--drivers/staging/rtl8188eu/hal/usb_halinit.c117
-rw-r--r--drivers/staging/rtl8188eu/include/drv_types.h1
-rw-r--r--drivers/staging/rtl8188eu/include/hal_intf.h1
-rw-r--r--drivers/staging/rtl8188eu/include/ieee80211.h14
-rw-r--r--drivers/staging/rtl8188eu/include/odm.h2
-rw-r--r--drivers/staging/rtl8188eu/include/odm_debug.h96
-rw-r--r--drivers/staging/rtl8188eu/include/odm_precomp.h4
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_hal.h32
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_spec.h284
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_xmit.h3
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_android.h1
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_cmd.h5
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_debug.h131
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_efuse.h7
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_led.h2
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme.h4
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme_ext.h5
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_recv.h3
-rw-r--r--drivers/staging/rtl8188eu/include/wifi.h36
-rw-r--r--drivers/staging/rtl8188eu/os_dep/ioctl_linux.c353
-rw-r--r--drivers/staging/rtl8188eu/os_dep/mlme_linux.c8
-rw-r--r--drivers/staging/rtl8188eu/os_dep/mon.c19
-rw-r--r--drivers/staging/rtl8188eu/os_dep/os_intfs.c97
-rw-r--r--drivers/staging/rtl8188eu/os_dep/recv_linux.c8
-rw-r--r--drivers/staging/rtl8188eu/os_dep/rtw_android.c18
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_intf.c30
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c135
-rw-r--r--drivers/staging/rtl8188eu/os_dep/xmit_linux.c28
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c5
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_cam.c12
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.c2
-rw-r--r--drivers/staging/rtl8192e/rtl819x_HTProc.c10
-rw-r--r--drivers/staging/rtl8192e/rtllib.h2
-rw-r--r--drivers/staging/rtl8192e/rtllib_rx.c3
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac.c1
-rw-r--r--drivers/staging/rtl8192e/rtllib_tx.c2
-rw-r--r--drivers/staging/rtl8192e/rtllib_wx.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211.h2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c25
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c2
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c15
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.c6
-rw-r--r--drivers/staging/rtl8192u/r8192U_hw.h19
-rw-r--r--drivers/staging/rtl8192u/r819xU_cmdpkt.c41
-rw-r--r--drivers/staging/rtl8192u/r819xU_phy.c48
-rw-r--r--drivers/staging/rtl8712/hal_init.c3
-rw-r--r--drivers/staging/rtl8712/os_intfs.c4
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmd.c2
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.c5
-rw-r--r--drivers/staging/rtl8712/rtl8712_xmit.c6
-rw-r--r--drivers/staging/rtl8712/rtl871x_debug.h23
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.c6
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_ioctl.c31
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_ioctl.h127
-rw-r--r--drivers/staging/rtl8712/rtl871x_recv.c2
-rw-r--r--drivers/staging/rtl8712/rtl871x_security.c12
-rw-r--r--drivers/staging/rtl8712/rtl871x_sta_mgt.c1
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.c1
-rw-r--r--drivers/staging/rtl8712/usb_intf.c33
-rw-r--r--drivers/staging/rtl8712/xmit_linux.c1
-rw-r--r--drivers/staging/rtl8723bs/Makefile2
-rw-r--r--drivers/staging/rtl8723bs/TODO2
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ap.c244
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_cmd.c41
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_debug.c74
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_eeprom.c210
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_efuse.c14
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ieee80211.c28
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_io.c35
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme.c103
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme_ext.c440
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_pwrctrl.c2
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_recv.c26
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_security.c672
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_sta_mgt.c43
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_wlan_util.c194
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_xmit.c68
-rw-r--r--drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c959
-rw-r--r--drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c519
-rw-r--r--drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h68
-rw-r--r--drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c79
-rw-r--r--drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c49
-rw-r--r--drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c658
-rw-r--r--drivers/staging/rtl8723bs/hal/HalPhyRf.c340
-rw-r--r--drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c221
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_btcoex.c175
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_com.c261
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_com_phycfg.c1059
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_intf.c3
-rw-r--r--drivers/staging/rtl8723bs/hal/odm.c103
-rw-r--r--drivers/staging/rtl8723bs/hal/odm.h46
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_CfoTracking.c107
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_DIG.c322
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c22
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_HWConfig.c38
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_NoiseMonitor.c36
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_PathDiv.c34
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_PathDiv.h21
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_RTL8723B.c1
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.c71
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h2
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_debug.c44
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_debug.h165
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_precomp.h2
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c21
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_dm.c1
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c65
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c69
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c2
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c9
-rw-r--r--drivers/staging/rtl8723bs/hal/sdio_halinit.c35
-rw-r--r--drivers/staging/rtl8723bs/hal/sdio_ops.c16
-rw-r--r--drivers/staging/rtl8723bs/include/Hal8192CPhyReg.h2
-rw-r--r--drivers/staging/rtl8723bs/include/autoconf.h50
-rw-r--r--drivers/staging/rtl8723bs/include/drv_conf.h19
-rw-r--r--drivers/staging/rtl8723bs/include/drv_types.h12
-rw-r--r--drivers/staging/rtl8723bs/include/hal_btcoex.h4
-rw-r--r--drivers/staging/rtl8723bs/include/hal_com.h62
-rw-r--r--drivers/staging/rtl8723bs/include/hal_com_phycfg.h198
-rw-r--r--drivers/staging/rtl8723bs/include/hal_com_reg.h1
-rw-r--r--drivers/staging/rtl8723bs/include/hal_data.h40
-rw-r--r--drivers/staging/rtl8723bs/include/hal_pg.h2
-rw-r--r--drivers/staging/rtl8723bs/include/hal_phy.h24
-rw-r--r--drivers/staging/rtl8723bs/include/ieee80211.h67
-rw-r--r--drivers/staging/rtl8723bs/include/osdep_intf.h2
-rw-r--r--drivers/staging/rtl8723bs/include/rtl8723b_spec.h2
-rw-r--r--drivers/staging/rtl8723bs/include/rtl8723b_xmit.h21
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_ap.h2
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_debug.h170
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_ht.h4
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_io.h44
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_mlme_ext.h84
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_mp.h1
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_rf.h33
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_security.h104
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_xmit.h2
-rw-r--r--drivers/staging/rtl8723bs/include/sdio_ops_linux.h2
-rw-r--r--drivers/staging/rtl8723bs/include/wifi.h3
-rw-r--r--drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c32
-rw-r--r--drivers/staging/rtl8723bs/os_dep/ioctl_linux.c67
-rw-r--r--drivers/staging/rtl8723bs/os_dep/mlme_linux.c4
-rw-r--r--drivers/staging/rtl8723bs/os_dep/os_intfs.c36
-rw-r--r--drivers/staging/rtl8723bs/os_dep/osdep_service.c4
-rw-r--r--drivers/staging/rtl8723bs/os_dep/recv_linux.c2
-rw-r--r--drivers/staging/rtl8723bs/os_dep/sdio_intf.c6
-rw-r--r--drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c28
-rw-r--r--drivers/staging/rtl8723bs/os_dep/wifi_regd.c4
-rw-r--r--drivers/staging/rtl8723bs/os_dep/xmit_linux.c10
-rw-r--r--drivers/staging/rts5208/ms.c1
-rw-r--r--drivers/staging/sm750fb/sm750_accel.c4
-rw-r--r--drivers/staging/unisys/visorhba/visorhba_main.c101
-rw-r--r--drivers/staging/unisys/visorinput/visorinput.c1
-rw-r--r--drivers/staging/vc04_services/Makefile2
-rw-r--r--drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h2
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c27
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c307
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h2
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c2
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h8
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c1636
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h93
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c6
-rw-r--r--drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c2
-rw-r--r--drivers/staging/vt6655/upc.h2
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c30
-rw-r--r--drivers/staging/wlan-ng/p80211ioctl.h2
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c6
-rw-r--r--drivers/target/iscsi/cxgbit/cxgbit_ddp.c19
-rw-r--r--drivers/target/iscsi/cxgbit/cxgbit_target.c21
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.c11
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c4
-rw-r--r--drivers/target/loopback/tcm_loop.c1
-rw-r--r--drivers/target/sbp/sbp_target.c1
-rw-r--r--drivers/target/target_core_alua.c6
-rw-r--r--drivers/target/target_core_configfs.c50
-rw-r--r--drivers/target/target_core_device.c5
-rw-r--r--drivers/target/target_core_iblock.c2
-rw-r--r--drivers/target/target_core_pr.c8
-rw-r--r--drivers/target/target_core_pr.h2
-rw-r--r--drivers/target/target_core_pscsi.c4
-rw-r--r--drivers/target/target_core_sbc.c10
-rw-r--r--drivers/target/target_core_spc.c97
-rw-r--r--drivers/target/target_core_user.c10
-rw-r--r--drivers/target/target_core_xcopy.c19
-rw-r--r--drivers/tee/tee_core.c1
-rw-r--r--drivers/thermal/cpufreq_cooling.c2
-rw-r--r--drivers/thermal/devfreq_cooling.c2
-rw-r--r--drivers/thermal/imx_sc_thermal.c3
-rw-r--r--drivers/thermal/intel/int340x_thermal/Makefile3
-rw-r--r--drivers/thermal/intel/int340x_thermal/int3401_thermal.c82
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_device.c309
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_device.h9
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c373
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c163
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c12
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c55
-rw-r--r--drivers/thermal/intel/intel_soc_dts_iosf.c15
-rw-r--r--drivers/thermal/mtk_thermal.c6
-rw-r--r--drivers/thermal/rcar_gen3_thermal.c7
-rw-r--r--drivers/thermal/rockchip_thermal.c121
-rw-r--r--drivers/thermal/sprd_thermal.c16
-rw-r--r--drivers/thermal/st/st_thermal_memmap.c13
-rw-r--r--drivers/thermal/thermal_core.c65
-rw-r--r--drivers/thermal/thermal_of.c3
-rw-r--r--drivers/thunderbolt/Makefile2
-rw-r--r--drivers/thunderbolt/acpi.c206
-rw-r--r--drivers/thunderbolt/dma_port.c94
-rw-r--r--drivers/thunderbolt/domain.c9
-rw-r--r--drivers/thunderbolt/eeprom.c19
-rw-r--r--drivers/thunderbolt/icm.c20
-rw-r--r--drivers/thunderbolt/lc.c6
-rw-r--r--drivers/thunderbolt/nhi.c71
-rw-r--r--drivers/thunderbolt/nhi.h2
-rw-r--r--drivers/thunderbolt/nvm.c95
-rw-r--r--drivers/thunderbolt/path.c4
-rw-r--r--drivers/thunderbolt/quirks.c30
-rw-r--r--drivers/thunderbolt/retimer.c108
-rw-r--r--drivers/thunderbolt/sb_regs.h2
-rw-r--r--drivers/thunderbolt/switch.c274
-rw-r--r--drivers/thunderbolt/tb.c71
-rw-r--r--drivers/thunderbolt/tb.h116
-rw-r--r--drivers/thunderbolt/tb_regs.h4
-rw-r--r--drivers/thunderbolt/test.c645
-rw-r--r--drivers/thunderbolt/tunnel.c401
-rw-r--r--drivers/thunderbolt/tunnel.h2
-rw-r--r--drivers/thunderbolt/usb4.c438
-rw-r--r--drivers/thunderbolt/usb4_port.c280
-rw-r--r--drivers/thunderbolt/xdomain.c10
-rw-r--r--drivers/tty/Kconfig7
-rw-r--r--drivers/tty/Makefile1
-rw-r--r--drivers/tty/amiserial.c12
-rw-r--r--drivers/tty/ehv_bytechan.c4
-rw-r--r--drivers/tty/goldfish.c4
-rw-r--r--drivers/tty/hvc/hvc_console.c8
-rw-r--r--drivers/tty/hvc/hvc_iucv.c53
-rw-r--r--drivers/tty/hvc/hvc_vio.c2
-rw-r--r--drivers/tty/hvc/hvcs.c4
-rw-r--r--drivers/tty/hvc/hvsi.c6
-rw-r--r--drivers/tty/ipwireless/tty.c6
-rw-r--r--drivers/tty/mips_ejtag_fdc.c8
-rw-r--r--drivers/tty/moxa.c22
-rw-r--r--drivers/tty/mxser.c1958
-rw-r--r--drivers/tty/mxser.h151
-rw-r--r--drivers/tty/n_gsm.c34
-rw-r--r--drivers/tty/n_hdlc.c18
-rw-r--r--drivers/tty/n_null.c7
-rw-r--r--drivers/tty/n_r3964.c1283
-rw-r--r--drivers/tty/n_tty.c201
-rw-r--r--drivers/tty/nozomi.c26
-rw-r--r--drivers/tty/pty.c89
-rw-r--r--drivers/tty/serdev/core.c2
-rw-r--r--drivers/tty/serial/8250/8250_aspeed_vuart.c54
-rw-r--r--drivers/tty/serial/8250/8250_core.c27
-rw-r--r--drivers/tty/serial/8250/8250_exar.c20
-rw-r--r--drivers/tty/serial/8250/8250_of.c4
-rw-r--r--drivers/tty/serial/8250/8250_omap.c22
-rw-r--r--drivers/tty/serial/8250/8250_pci.c172
-rw-r--r--drivers/tty/serial/8250/8250_port.c57
-rw-r--r--drivers/tty/serial/8250/serial_cs.c13
-rw-r--r--drivers/tty/serial/Kconfig1
-rw-r--r--drivers/tty/serial/amba-pl011.c2
-rw-r--r--drivers/tty/serial/arc_uart.c2
-rw-r--r--drivers/tty/serial/atmel_serial.c2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c19
-rw-r--r--drivers/tty/serial/dz.c4
-rw-r--r--drivers/tty/serial/fsl_lpuart.c135
-rw-r--r--drivers/tty/serial/icom.c2
-rw-r--r--drivers/tty/serial/imx.c27
-rw-r--r--drivers/tty/serial/ip22zilog.c2
-rw-r--r--drivers/tty/serial/kgdb_nmi.c4
-rw-r--r--drivers/tty/serial/liteuart.c21
-rw-r--r--drivers/tty/serial/max310x.c40
-rw-r--r--drivers/tty/serial/meson_uart.c8
-rw-r--r--drivers/tty/serial/mux.c2
-rw-r--r--drivers/tty/serial/mvebu-uart.c21
-rw-r--r--drivers/tty/serial/mxs-auart.c26
-rw-r--r--drivers/tty/serial/omap-serial.c10
-rw-r--r--drivers/tty/serial/pmac_zilog.c2
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c22
-rw-r--r--drivers/tty/serial/samsung_tty.c3
-rw-r--r--drivers/tty/serial/sb1250-duart.c2
-rw-r--r--drivers/tty/serial/sc16is7xx.c26
-rw-r--r--drivers/tty/serial/serial_core.c58
-rw-r--r--drivers/tty/serial/serial_txx9.c2
-rw-r--r--drivers/tty/serial/sh-sci.c41
-rw-r--r--drivers/tty/serial/sh-sci.h1
-rw-r--r--drivers/tty/serial/st-asc.c4
-rw-r--r--drivers/tty/serial/stm32-usart.c197
-rw-r--r--drivers/tty/serial/sunsab.c2
-rw-r--r--drivers/tty/serial/sunsu.c2
-rw-r--r--drivers/tty/serial/sunzilog.c2
-rw-r--r--drivers/tty/serial/tegra-tcu.c26
-rw-r--r--drivers/tty/serial/uartlite.c27
-rw-r--r--drivers/tty/serial/ucc_uart.c2
-rw-r--r--drivers/tty/serial/vr41xx_siu.c2
-rw-r--r--drivers/tty/serial/xilinx_uartps.c12
-rw-r--r--drivers/tty/synclink_gt.c27
-rw-r--r--drivers/tty/tty_baudrate.c13
-rw-r--r--drivers/tty/tty_buffer.c28
-rw-r--r--drivers/tty/tty_io.c198
-rw-r--r--drivers/tty/tty_ioctl.c96
-rw-r--r--drivers/tty/tty_jobctrl.c88
-rw-r--r--drivers/tty/tty_ldisc.c29
-rw-r--r--drivers/tty/tty_port.c18
-rw-r--r--drivers/tty/ttynull.c2
-rw-r--r--drivers/tty/vcc.c28
-rw-r--r--drivers/tty/vt/keyboard.c2
-rw-r--r--drivers/tty/vt/selection.c20
-rw-r--r--drivers/tty/vt/vt.c18
-rw-r--r--drivers/uio/Kconfig2
-rw-r--r--drivers/uio/uio_aec.c2
-rw-r--r--drivers/uio/uio_pci_generic.c32
-rw-r--r--drivers/usb/atm/cxacru.c2
-rw-r--r--drivers/usb/cdns3/cdns3-ep0.c6
-rw-r--r--drivers/usb/cdns3/cdns3-gadget.c40
-rw-r--r--drivers/usb/cdns3/cdns3-imx.c2
-rw-r--r--drivers/usb/cdns3/cdns3-plat.c2
-rw-r--r--drivers/usb/cdns3/cdns3-ti.c2
-rw-r--r--drivers/usb/cdns3/cdnsp-gadget.c7
-rw-r--r--drivers/usb/cdns3/cdnsp-mem.c5
-rw-r--r--drivers/usb/cdns3/cdnsp-trace.h2
-rw-r--r--drivers/usb/cdns3/core.c4
-rw-r--r--drivers/usb/chipidea/ci.h2
-rw-r--r--drivers/usb/chipidea/core.c2
-rw-r--r--drivers/usb/chipidea/debug.c34
-rw-r--r--drivers/usb/chipidea/otg.c9
-rw-r--r--drivers/usb/chipidea/udc.c2
-rw-r--r--drivers/usb/class/cdc-acm.c26
-rw-r--r--drivers/usb/class/cdc-wdm.c186
-rw-r--r--drivers/usb/common/ulpi.c2
-rw-r--r--drivers/usb/common/usb-conn-gpio.c62
-rw-r--r--drivers/usb/core/devio.c2
-rw-r--r--drivers/usb/core/hcd.c130
-rw-r--r--drivers/usb/core/hub.c34
-rw-r--r--drivers/usb/core/message.c6
-rw-r--r--drivers/usb/core/quirks.c1
-rw-r--r--drivers/usb/core/sysfs.c24
-rw-r--r--drivers/usb/core/urb.c9
-rw-r--r--drivers/usb/dwc2/core.c30
-rw-r--r--drivers/usb/dwc2/gadget.c14
-rw-r--r--drivers/usb/dwc2/hcd_queue.c2
-rw-r--r--drivers/usb/dwc2/params.c4
-rw-r--r--drivers/usb/dwc2/pci.c2
-rw-r--r--drivers/usb/dwc2/platform.c2
-rw-r--r--drivers/usb/dwc3/core.c7
-rw-r--r--drivers/usb/dwc3/core.h2
-rw-r--r--drivers/usb/dwc3/debugfs.c8
-rw-r--r--drivers/usb/dwc3/drd.c1
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c8
-rw-r--r--drivers/usb/dwc3/gadget.c4
-rw-r--r--drivers/usb/dwc3/trace.h2
-rw-r--r--drivers/usb/gadget/function/f_eem.c43
-rw-r--r--drivers/usb/gadget/function/f_fs.c65
-rw-r--r--drivers/usb/gadget/function/f_hid.c4
-rw-r--r--drivers/usb/gadget/function/f_printer.c3
-rw-r--r--drivers/usb/gadget/function/f_uac2.c144
-rw-r--r--drivers/usb/gadget/function/u_audio.c225
-rw-r--r--drivers/usb/gadget/function/u_audio.h12
-rw-r--r--drivers/usb/gadget/function/u_hid.h4
-rw-r--r--drivers/usb/gadget/function/u_midi.h4
-rw-r--r--drivers/usb/gadget/function/u_serial.c12
-rw-r--r--drivers/usb/gadget/function/u_uac2.h4
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.c5
-rw-r--r--drivers/usb/gadget/legacy/hid.c4
-rw-r--r--drivers/usb/gadget/udc/bcm63xx_udc.c7
-rw-r--r--drivers/usb/gadget/udc/core.c49
-rw-r--r--drivers/usb/gadget/udc/dummy_hcd.c11
-rw-r--r--drivers/usb/gadget/udc/fsl_qe_udc.c6
-rw-r--r--drivers/usb/gadget/udc/fsl_udc_core.c44
-rw-r--r--drivers/usb/gadget/udc/fsl_usb2_udc.h19
-rw-r--r--drivers/usb/gadget/udc/gr_udc.c7
-rw-r--r--drivers/usb/gadget/udc/gr_udc.h2
-rw-r--r--drivers/usb/gadget/udc/lpc32xx_udc.c5
-rw-r--r--drivers/usb/gadget/udc/max3420_udc.c15
-rw-r--r--drivers/usb/gadget/udc/mv_u3d_core.c2
-rw-r--r--drivers/usb/gadget/udc/mv_udc_core.c2
-rw-r--r--drivers/usb/gadget/udc/net2272.c41
-rw-r--r--drivers/usb/gadget/udc/net2272.h1
-rw-r--r--drivers/usb/gadget/udc/net2280.c51
-rw-r--r--drivers/usb/gadget/udc/net2280.h1
-rw-r--r--drivers/usb/gadget/udc/pxa25x_udc.c4
-rw-r--r--drivers/usb/gadget/udc/pxa25x_udc.h4
-rw-r--r--drivers/usb/gadget/udc/pxa27x_udc.c6
-rw-r--r--drivers/usb/gadget/udc/pxa27x_udc.h4
-rw-r--r--drivers/usb/gadget/udc/s3c-hsudc.c5
-rw-r--r--drivers/usb/gadget/udc/s3c2410_udc.c9
-rw-r--r--drivers/usb/gadget/udc/s3c2410_udc.h1
-rw-r--r--drivers/usb/gadget/udc/tegra-xudc.c30
-rw-r--r--drivers/usb/gadget/udc/trace.c2
-rw-r--r--drivers/usb/gadget/udc/trace.h2
-rw-r--r--drivers/usb/gadget/udc/udc-xilinx.c4
-rw-r--r--drivers/usb/host/ehci-fsl.c8
-rw-r--r--drivers/usb/host/ehci-hcd.c8
-rw-r--r--drivers/usb/host/ehci-hub.c139
-rw-r--r--drivers/usb/host/ehci-q.c2
-rw-r--r--drivers/usb/host/fotg210-hcd.c5
-rw-r--r--drivers/usb/host/fotg210.h3
-rw-r--r--drivers/usb/host/max3421-hcd.c3
-rw-r--r--drivers/usb/host/u132-hcd.c6
-rw-r--r--drivers/usb/host/xhci-dbgtty.c8
-rw-r--r--drivers/usb/host/xhci-mem.c3
-rw-r--r--drivers/usb/host/xhci-mtk-sch.c60
-rw-r--r--drivers/usb/host/xhci-mtk.c2
-rw-r--r--drivers/usb/host/xhci-mtk.h10
-rw-r--r--drivers/usb/host/xhci-pci-renesas.c18
-rw-r--r--drivers/usb/host/xhci-ring.c7
-rw-r--r--drivers/usb/host/xhci-tegra.c627
-rw-r--r--drivers/usb/host/xhci.c10
-rw-r--r--drivers/usb/host/xhci.h11
-rw-r--r--drivers/usb/isp1760/Kconfig5
-rw-r--r--drivers/usb/isp1760/isp1760-core.c513
-rw-r--r--drivers/usb/isp1760/isp1760-core.h44
-rw-r--r--drivers/usb/isp1760/isp1760-hcd.c1020
-rw-r--r--drivers/usb/isp1760/isp1760-hcd.h57
-rw-r--r--drivers/usb/isp1760/isp1760-if.c41
-rw-r--r--drivers/usb/isp1760/isp1760-regs.h435
-rw-r--r--drivers/usb/isp1760/isp1760-udc.c251
-rw-r--r--drivers/usb/isp1760/isp1760-udc.h13
-rw-r--r--drivers/usb/misc/ftdi-elan.c1
-rw-r--r--drivers/usb/mtu3/mtu3.h30
-rw-r--r--drivers/usb/mtu3/mtu3_core.c20
-rw-r--r--drivers/usb/mtu3/mtu3_debugfs.c1
-rw-r--r--drivers/usb/mtu3/mtu3_dr.c169
-rw-r--r--drivers/usb/mtu3/mtu3_gadget.c2
-rw-r--r--drivers/usb/mtu3/mtu3_host.c6
-rw-r--r--drivers/usb/mtu3/mtu3_plat.c95
-rw-r--r--drivers/usb/musb/musb_core.c71
-rw-r--r--drivers/usb/musb/musb_gadget.c2
-rw-r--r--drivers/usb/musb/musb_host.c18
-rw-r--r--drivers/usb/musb/musb_host.h4
-rw-r--r--drivers/usb/musb/musb_trace.h17
-rw-r--r--drivers/usb/musb/omap2430.c32
-rw-r--r--drivers/usb/phy/phy-isp1301-omap.c2
-rw-r--r--drivers/usb/phy/phy-isp1301.c25
-rw-r--r--drivers/usb/phy/phy-tegra-usb.c15
-rw-r--r--drivers/usb/phy/phy.c55
-rw-r--r--drivers/usb/roles/class.c9
-rw-r--r--drivers/usb/serial/belkin_sa.c20
-rw-r--r--drivers/usb/serial/cp210x.c189
-rw-r--r--drivers/usb/serial/cyberjack.c4
-rw-r--r--drivers/usb/serial/cypress_m8.c37
-rw-r--r--drivers/usb/serial/digi_acceleport.c46
-rw-r--r--drivers/usb/serial/garmin_gps.c2
-rw-r--r--drivers/usb/serial/generic.c12
-rw-r--r--drivers/usb/serial/io_edgeport.c39
-rw-r--r--drivers/usb/serial/io_ti.c12
-rw-r--r--drivers/usb/serial/ir-usb.c6
-rw-r--r--drivers/usb/serial/keyspan.c4
-rw-r--r--drivers/usb/serial/kobil_sct.c4
-rw-r--r--drivers/usb/serial/metro-usb.c12
-rw-r--r--drivers/usb/serial/mos7720.c29
-rw-r--r--drivers/usb/serial/mos7840.c17
-rw-r--r--drivers/usb/serial/opticon.c6
-rw-r--r--drivers/usb/serial/oti6858.c12
-rw-r--r--drivers/usb/serial/pl2303.c15
-rw-r--r--drivers/usb/serial/quatech2.c6
-rw-r--r--drivers/usb/serial/sierra.c8
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c16
-rw-r--r--drivers/usb/serial/usb-serial.c4
-rw-r--r--drivers/usb/serial/usb-wwan.h4
-rw-r--r--drivers/usb/serial/usb_wwan.c12
-rw-r--r--drivers/usb/serial/whiteheat.c9
-rw-r--r--drivers/usb/storage/cypress_atacb.c4
-rw-r--r--drivers/usb/typec/class.c4
-rw-r--r--drivers/usb/typec/mux.c39
-rw-r--r--drivers/usb/typec/mux.h6
-rw-r--r--drivers/usb/typec/mux/intel_pmc_mux.c28
-rw-r--r--drivers/usb/typec/tcpm/tcpci.c46
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c86
-rw-r--r--drivers/usb/typec/tcpm/wcove.c2
-rw-r--r--drivers/usb/typec/ucsi/ucsi.c4
-rw-r--r--drivers/vdpa/ifcvf/ifcvf_base.c4
-rw-r--r--drivers/vdpa/ifcvf/ifcvf_base.h14
-rw-r--r--drivers/vdpa/ifcvf/ifcvf_main.c43
-rw-r--r--drivers/vdpa/mlx5/core/mlx5_vdpa.h2
-rw-r--r--drivers/vdpa/mlx5/core/mr.c95
-rw-r--r--drivers/vdpa/mlx5/core/resources.c7
-rw-r--r--drivers/vdpa/mlx5/net/mlx5_vnet.c67
-rw-r--r--drivers/vdpa/vdpa_sim/vdpa_sim.c4
-rw-r--r--drivers/vdpa/vdpa_sim/vdpa_sim_blk.c1
-rw-r--r--drivers/vdpa/virtio_pci/vp_vdpa.c43
-rw-r--r--drivers/vfio/fsl-mc/vfio_fsl_mc.c16
-rw-r--r--drivers/vfio/mdev/Kconfig7
-rw-r--r--drivers/vfio/mdev/Makefile3
-rw-r--r--drivers/vfio/mdev/mdev_core.c46
-rw-r--r--drivers/vfio/mdev/mdev_driver.c10
-rw-r--r--drivers/vfio/mdev/mdev_private.h2
-rw-r--r--drivers/vfio/mdev/vfio_mdev.c37
-rw-r--r--drivers/vfio/pci/vfio_pci.c47
-rw-r--r--drivers/vfio/platform/vfio_amba.c1
-rw-r--r--drivers/vfio/platform/vfio_platform.c1
-rw-r--r--drivers/vfio/platform/vfio_platform_common.c6
-rw-r--r--drivers/vfio/platform/vfio_platform_private.h1
-rw-r--r--drivers/vfio/vfio.c10
-rw-r--r--drivers/vfio/vfio_iommu_type1.c36
-rw-r--r--drivers/vhost/iotlb.c2
-rw-r--r--drivers/vhost/net.c6
-rw-r--r--drivers/vhost/scsi.c21
-rw-r--r--drivers/vhost/vdpa.c4
-rw-r--r--drivers/vhost/vhost.c8
-rw-r--r--drivers/vhost/vhost.h21
-rw-r--r--drivers/vhost/vsock.c60
-rw-r--r--drivers/video/backlight/Kconfig30
-rw-r--r--drivers/video/backlight/Makefile1
-rw-r--r--drivers/video/backlight/lm3630a_bl.c54
-rw-r--r--drivers/video/backlight/qcom-wled.c1
-rw-r--r--drivers/video/backlight/rt4831-backlight.c203
-rw-r--r--drivers/video/console/Kconfig2
-rw-r--r--drivers/video/fbdev/Kconfig1
-rw-r--r--drivers/video/fbdev/core/fbmem.c12
-rw-r--r--drivers/video/fbdev/hyperv_fb.c1
-rw-r--r--drivers/video/fbdev/xilinxfb.c2
-rw-r--r--drivers/virt/nitro_enclaves/ne_pci_dev.c2
-rw-r--r--drivers/virtio/virtio_balloon.c17
-rw-r--r--drivers/virtio/virtio_mem.c340
-rw-r--r--drivers/virtio/virtio_pci_modern_dev.c21
-rw-r--r--drivers/virtio/virtio_ring.c229
-rw-r--r--drivers/virtio/virtio_vdpa.c15
-rw-r--r--drivers/visorbus/visorchipset.c6
-rw-r--r--drivers/w1/masters/ds2482.c94
-rw-r--r--drivers/w1/slaves/w1_ds2438.c122
-rw-r--r--drivers/w1/slaves/w1_therm.c5
-rw-r--r--drivers/watchdog/Kconfig77
-rw-r--r--drivers/watchdog/Makefile3
-rw-r--r--drivers/watchdog/aspeed_wdt.c6
-rw-r--r--drivers/watchdog/bcm7038_wdt.c31
-rw-r--r--drivers/watchdog/booke_wdt.c2
-rw-r--r--drivers/watchdog/diag288_wdt.c4
-rw-r--r--drivers/watchdog/dw_wdt.c9
-rw-r--r--drivers/watchdog/eurotechwdt.c2
-rw-r--r--drivers/watchdog/hpwdt.c1
-rw-r--r--drivers/watchdog/iTCO_wdt.c16
-rw-r--r--drivers/watchdog/imx2_wdt.c10
-rw-r--r--drivers/watchdog/imx_sc_wdt.c11
-rw-r--r--drivers/watchdog/it87_wdt.c8
-rw-r--r--drivers/watchdog/jz4740_wdt.c4
-rw-r--r--drivers/watchdog/keembay_wdt.c34
-rw-r--r--drivers/watchdog/lpc18xx_wdt.c2
-rw-r--r--drivers/watchdog/machzwd.c1
-rw-r--r--drivers/watchdog/mei_wdt.c8
-rw-r--r--drivers/watchdog/meson_wdt.c8
-rw-r--r--drivers/watchdog/msc313e_wdt.c166
-rw-r--r--drivers/watchdog/mtk_wdt.c77
-rw-r--r--drivers/watchdog/mtx-1_wdt.c2
-rw-r--r--drivers/watchdog/mv64x60_wdt.c324
-rw-r--r--drivers/watchdog/octeon-wdt-main.c13
-rw-r--r--drivers/watchdog/of_xilinx_wdt.c38
-rw-r--r--drivers/watchdog/orion_wdt.c2
-rw-r--r--drivers/watchdog/pc87413_wdt.c2
-rw-r--r--drivers/watchdog/qcom-wdt.c4
-rw-r--r--drivers/watchdog/sama5d4_wdt.c10
-rw-r--r--drivers/watchdog/sbc60xxwdt.c2
-rw-r--r--drivers/watchdog/sbsa_gwdt.c54
-rw-r--r--drivers/watchdog/sc520_wdt.c2
-rw-r--r--drivers/watchdog/sl28cpld_wdt.c2
-rw-r--r--drivers/watchdog/sp805_wdt.c43
-rw-r--r--drivers/watchdog/w83877f_wdt.c2
-rw-r--r--drivers/watchdog/watchdog_core.h48
-rw-r--r--drivers/watchdog/watchdog_dev.c86
-rw-r--r--drivers/watchdog/watchdog_hrtimer_pretimeout.c44
-rw-r--r--drivers/watchdog/watchdog_pretimeout.c9
-rw-r--r--drivers/watchdog/wdat_wdt.c4
-rw-r--r--drivers/watchdog/wdt.c4
-rw-r--r--drivers/watchdog/wdt_pci.c2
-rw-r--r--drivers/watchdog/ziirave_wdt.c21
-rw-r--r--drivers/xen/events/events_base.c11
-rw-r--r--drivers/xen/pcpu.c6
-rw-r--r--drivers/xen/xen-balloon.c28
-rw-r--r--drivers/xen/xen-scsiback.c17
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c15
4973 files changed, 302907 insertions, 168861 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 47980c6b1945..8bad63417a50 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -33,8 +33,6 @@ source "drivers/nvme/Kconfig"
source "drivers/misc/Kconfig"
-source "drivers/ide/Kconfig"
-
source "drivers/scsi/Kconfig"
source "drivers/ata/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 5a6d613e868d..27c018bdf4de 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -78,7 +78,6 @@ obj-$(CONFIG_CXL_BUS) += cxl/
obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/
obj-$(CONFIG_NUBUS) += nubus/
obj-y += macintosh/
-obj-$(CONFIG_IDE) += ide/
obj-y += scsi/
obj-y += nvme/
obj-$(CONFIG_ATA) += ata/
@@ -161,7 +160,7 @@ obj-$(CONFIG_SOUNDWIRE) += soundwire/
# Virtualization drivers
obj-$(CONFIG_VIRT_DRIVERS) += virt/
-obj-$(CONFIG_HYPERV) += hv/
+obj-$(subst m,y,$(CONFIG_HYPERV)) += hv/
obj-$(CONFIG_PM_DEVFREQ) += devfreq/
obj-$(CONFIG_EXTCON) += extcon/
diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c
index 9861302cc7db..fdc6b593f500 100644
--- a/drivers/accessibility/braille/braille_console.c
+++ b/drivers/accessibility/braille/braille_console.c
@@ -225,6 +225,7 @@ static int keyboard_notifier_call(struct notifier_block *blk,
case KBD_POST_KEYSYM:
{
unsigned char type = KTYP(param->value) - 0xf0;
+
if (type == KT_SPEC) {
unsigned char val = KVAL(param->value);
int on_off = -1;
@@ -246,6 +247,7 @@ static int keyboard_notifier_call(struct notifier_block *blk,
beep(440);
}
}
+ break;
case KBD_UNBOUND_KEYCODE:
case KBD_UNICODE:
case KBD_KEYSYM:
@@ -264,6 +266,7 @@ static int vt_notifier_call(struct notifier_block *blk,
{
struct vt_notifier_param *param = _param;
struct vc_data *vc = param->vc;
+
switch (code) {
case VT_ALLOCATE:
break;
@@ -272,6 +275,7 @@ static int vt_notifier_call(struct notifier_block *blk,
case VT_WRITE:
{
unsigned char c = param->c;
+
if (vc->vc_num != fg_console)
break;
switch (c) {
diff --git a/drivers/accessibility/speakup/i18n.c b/drivers/accessibility/speakup/i18n.c
index 46bd50f3c3a4..bc7b47d1876f 100644
--- a/drivers/accessibility/speakup/i18n.c
+++ b/drivers/accessibility/speakup/i18n.c
@@ -90,6 +90,13 @@ static char *speakup_default_msgs[MSG_LAST_INDEX] = {
[MSG_COLOR_YELLOW] = "yellow",
[MSG_COLOR_WHITE] = "white",
[MSG_COLOR_GREY] = "grey",
+ [MSG_COLOR_BRIGHTBLUE] "bright blue",
+ [MSG_COLOR_BRIGHTGREEN] "bright green",
+ [MSG_COLOR_BRIGHTCYAN] "bright cyan",
+ [MSG_COLOR_BRIGHTRED] "bright red",
+ [MSG_COLOR_BRIGHTMAGENTA] "bright magenta",
+ [MSG_COLOR_BRIGHTYELLOW] "bright yellow",
+ [MSG_COLOR_BRIGHTWHITE] "bright white",
/* Names of key states. */
[MSG_STATE_DOUBLE] = "double",
diff --git a/drivers/accessibility/speakup/i18n.h b/drivers/accessibility/speakup/i18n.h
index 2a607d263234..51e3260995d9 100644
--- a/drivers/accessibility/speakup/i18n.h
+++ b/drivers/accessibility/speakup/i18n.h
@@ -99,7 +99,14 @@ enum msg_index_t {
MSG_COLOR_YELLOW,
MSG_COLOR_WHITE,
MSG_COLOR_GREY,
- MSG_COLORS_END = MSG_COLOR_GREY,
+ MSG_COLOR_BRIGHTBLUE,
+ MSG_COLOR_BRIGHTGREEN,
+ MSG_COLOR_BRIGHTCYAN,
+ MSG_COLOR_BRIGHTRED,
+ MSG_COLOR_BRIGHTMAGENTA,
+ MSG_COLOR_BRIGHTYELLOW,
+ MSG_COLOR_BRIGHTWHITE,
+ MSG_COLORS_END = MSG_COLOR_BRIGHTWHITE,
MSG_STATES_START,
MSG_STATE_DOUBLE = MSG_STATES_START,
diff --git a/drivers/accessibility/speakup/main.c b/drivers/accessibility/speakup/main.c
index 428fceaf9d50..d726537fa16c 100644
--- a/drivers/accessibility/speakup/main.c
+++ b/drivers/accessibility/speakup/main.c
@@ -389,10 +389,6 @@ static void say_attributes(struct vc_data *vc)
int fg = spk_attr & 0x0f;
int bg = spk_attr >> 4;
- if (fg > 8) {
- synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
- fg -= 8;
- }
synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
if (bg > 7) {
synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
diff --git a/drivers/accessibility/speakup/spk_ttyio.c b/drivers/accessibility/speakup/spk_ttyio.c
index 2e39fcf492d8..0d1f397cd896 100644
--- a/drivers/accessibility/speakup/spk_ttyio.c
+++ b/drivers/accessibility/speakup/spk_ttyio.c
@@ -72,7 +72,8 @@ static void spk_ttyio_ldisc_close(struct tty_struct *tty)
}
static int spk_ttyio_receive_buf2(struct tty_struct *tty,
- const unsigned char *cp, char *fp, int count)
+ const unsigned char *cp,
+ const char *fp, int count)
{
struct spk_ldisc_data *ldisc_data = tty->disc_data;
struct spk_synth *synth = ldisc_data->synth;
@@ -104,6 +105,7 @@ static int spk_ttyio_receive_buf2(struct tty_struct *tty,
static struct tty_ldisc_ops spk_ttyio_ldisc_ops = {
.owner = THIS_MODULE,
+ .num = N_SPEAKUP,
.name = "speakup_ldisc",
.open = spk_ttyio_ldisc_open,
.close = spk_ttyio_ldisc_close,
@@ -211,14 +213,13 @@ static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
void spk_ttyio_register_ldisc(void)
{
- if (tty_register_ldisc(N_SPEAKUP, &spk_ttyio_ldisc_ops))
+ if (tty_register_ldisc(&spk_ttyio_ldisc_ops))
pr_warn("speakup: Error registering line discipline. Most synths won't work.\n");
}
void spk_ttyio_unregister_ldisc(void)
{
- if (tty_unregister_ldisc(N_SPEAKUP))
- pr_warn("speakup: Couldn't unregister ldisc\n");
+ tty_unregister_ldisc(&spk_ttyio_ldisc_ops);
}
static int spk_ttyio_out(struct spk_synth *in_synth, const char ch)
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index eedec61e3476..9d872ea477a6 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -526,6 +526,9 @@ endif
source "drivers/acpi/pmic/Kconfig"
+config ACPI_VIOT
+ bool
+
endif # ACPI
config X86_PM_TIMER
@@ -543,3 +546,18 @@ config X86_PM_TIMER
You should nearly always say Y here because many modern
systems require this timer.
+
+config ACPI_PRMT
+ bool "Platform Runtime Mechanism Support"
+ depends on EFI && X86_64
+ default y
+ help
+ Platform Runtime Mechanism (PRM) is a firmware interface exposing a
+ set of binary executables that can be called from the AML interpreter
+ or directly from device drivers.
+
+ Say Y to enable the AML interpreter to execute the PRM code.
+
+ While this feature is optional in principle, leaving it out may
+ substantially increase computational overhead related to the
+ initialization of some server systems.
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 700b41adf2db..3018714e87d9 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -8,6 +8,11 @@ ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT
#
# ACPI Boot-Time Table Parsing
#
+ifeq ($(CONFIG_ACPI_CUSTOM_DSDT),y)
+tables.o: $(src)/../../include/$(subst $\",,$(CONFIG_ACPI_CUSTOM_DSDT_FILE)) ;
+
+endif
+
obj-$(CONFIG_ACPI) += tables.o
obj-$(CONFIG_X86) += blacklist.o
@@ -61,6 +66,7 @@ acpi-$(CONFIG_ACPI_FPDT) += acpi_fpdt.o
acpi-$(CONFIG_ACPI_LPIT) += acpi_lpit.o
acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
acpi-$(CONFIG_ACPI_WATCHDOG) += acpi_watchdog.o
+acpi-$(CONFIG_ACPI_PRMT) += prmt.o
# Address translation
acpi-$(CONFIG_ACPI_ADXL) += acpi_adxl.o
@@ -118,3 +124,5 @@ video-objs += acpi_video.o video_detect.o
obj-y += dptf/
obj-$(CONFIG_ARM64) += arm64/
+
+obj-$(CONFIG_ACPI_VIOT) += viot.o
diff --git a/drivers/acpi/acpi_amba.c b/drivers/acpi/acpi_amba.c
index 49b781a9cd97..ab8a4e0191b1 100644
--- a/drivers/acpi/acpi_amba.c
+++ b/drivers/acpi/acpi_amba.c
@@ -76,6 +76,7 @@ static int amba_handler_attach(struct acpi_device *adev,
case IORESOURCE_MEM:
if (!address_found) {
dev->res = *rentry->res;
+ dev->res.name = dev_name(&dev->dev);
address_found = true;
}
break;
diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c
index 67f1d33d15c4..4cf4aef7ce0c 100644
--- a/drivers/acpi/acpi_cmos_rtc.c
+++ b/drivers/acpi/acpi_cmos_rtc.c
@@ -6,6 +6,8 @@
* Authors: Lan Tianyu <tianyu.lan@intel.com>
*/
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -59,7 +61,7 @@ static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev,
&acpi_cmos_rtc_space_handler,
NULL, NULL);
if (ACPI_FAILURE(status)) {
- pr_err(PREFIX "Error installing CMOS-RTC region handler\n");
+ pr_err("Error installing CMOS-RTC region handler\n");
return -ENODEV;
}
@@ -70,7 +72,7 @@ static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev)
{
if (ACPI_FAILURE(acpi_remove_address_space_handler(adev->handle,
ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler)))
- pr_err(PREFIX "Error removing CMOS-RTC region handler\n");
+ pr_err("Error removing CMOS-RTC region handler\n");
}
static struct acpi_scan_handler cmos_rtc_handler = {
diff --git a/drivers/acpi/acpi_configfs.c b/drivers/acpi/acpi_configfs.c
index 3a14859dbb75..76b83b181356 100644
--- a/drivers/acpi/acpi_configfs.c
+++ b/drivers/acpi/acpi_configfs.c
@@ -13,9 +13,6 @@
#include <linux/acpi.h>
#include <linux/security.h>
-#include "acpica/accommon.h"
-#include "acpica/actables.h"
-
static struct config_group *acpi_table_group;
struct acpi_table {
@@ -226,7 +223,7 @@ static void acpi_table_drop_item(struct config_group *group,
{
struct acpi_table *table = container_of(cfg, struct acpi_table, cfg);
- ACPI_INFO(("Host-directed Dynamic ACPI Table Unload"));
+ pr_debug("Host-directed Dynamic ACPI Table Unload\n");
acpi_unload_table(table->index);
config_item_put(cfg);
}
diff --git a/drivers/acpi/acpi_fpdt.c b/drivers/acpi/acpi_fpdt.c
index a89a806a7a2a..4ee2ad234e3d 100644
--- a/drivers/acpi/acpi_fpdt.c
+++ b/drivers/acpi/acpi_fpdt.c
@@ -240,8 +240,10 @@ static int __init acpi_init_fpdt(void)
return 0;
fpdt_kobj = kobject_create_and_add("fpdt", acpi_kobj);
- if (!fpdt_kobj)
+ if (!fpdt_kobj) {
+ acpi_put_table(header);
return -ENOMEM;
+ }
while (offset < header->length) {
subtable = (void *)header + offset;
diff --git a/drivers/acpi/acpi_ipmi.c b/drivers/acpi/acpi_ipmi.c
index bbd00d96b7a8..a5fe2926bf50 100644
--- a/drivers/acpi/acpi_ipmi.c
+++ b/drivers/acpi/acpi_ipmi.c
@@ -597,9 +597,14 @@ static int __init acpi_ipmi_init(void)
pr_warn("Can't register IPMI opregion space handle\n");
return -EINVAL;
}
+
result = ipmi_smi_watcher_register(&driver_data.bmc_events);
- if (result)
+ if (result) {
+ acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
+ ACPI_ADR_SPACE_IPMI,
+ &acpi_ipmi_space_handler);
pr_err("Can't register IPMI system interface watcher\n");
+ }
return result;
}
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index ca742f16a507..894b7e6ae144 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -186,13 +186,12 @@ static void byt_i2c_setup(struct lpss_private_data *pdata)
long uid = 0;
/* Expected to always be true, but better safe then sorry */
- if (uid_str)
- uid = simple_strtol(uid_str, NULL, 10);
-
- /* Detect I2C bus shared with PUNIT and ignore its d3 status */
- status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
- if (ACPI_SUCCESS(status) && shared_host && uid)
- pmc_atom_d3_mask &= ~(BIT_LPSS2_F1_I2C1 << (uid - 1));
+ if (uid_str && !kstrtol(uid_str, 10, &uid) && uid) {
+ /* Detect I2C bus shared with PUNIT and ignore its d3 status */
+ status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
+ if (ACPI_SUCCESS(status) && shared_host)
+ pmc_atom_d3_mask &= ~(BIT_LPSS2_F1_I2C1 << (uid - 1));
+ }
lpss_deassert_reset(pdata);
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index 0c884020f74b..42ede059728c 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -540,6 +540,15 @@ static const struct dmi_system_id video_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
},
},
+ {
+ .callback = video_set_report_key_events,
+ .driver_data = (void *)((uintptr_t)REPORT_BRIGHTNESS_KEY_EVENTS),
+ .ident = "Dell Vostro 3350",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"),
+ },
+ },
/*
* Some machines change the brightness themselves when a brightness
* hotkey gets pressed, despite us telling them not to. In this case
@@ -1619,8 +1628,6 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
input_report_key(input, keycode, 0);
input_sync(input);
}
-
- return;
}
static void brightness_switch_event(struct acpi_video_device *video_device,
@@ -1690,8 +1697,6 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
input_report_key(input, keycode, 0);
input_sync(input);
}
-
- return;
}
static int acpi_video_resume(struct notifier_block *nb,
@@ -2308,8 +2313,6 @@ static void __exit acpi_video_exit(void)
{
acpi_video_detect_exit();
acpi_video_unregister();
-
- return;
}
module_init(acpi_video_init);
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index bccae0d3db75..59d6ded01614 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -737,6 +737,8 @@ const char *acpi_ah_match_uuid(u8 *data);
*/
#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP || defined ACPI_HELP_APP)
void acpi_ut_convert_string_to_uuid(char *in_string, u8 *uuid_buffer);
+
+acpi_status acpi_ut_convert_uuid_to_string(char *uuid_buffer, char *out_string);
#endif
#endif /* _ACUTILS_H */
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index 32f03ee81785..06f3c9df1e22 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -139,7 +139,9 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
|| obj_desc->field.region_obj->region.space_id ==
ACPI_ADR_SPACE_GSBUS
|| obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_IPMI)) {
+ ACPI_ADR_SPACE_IPMI
+ || obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_PLATFORM_RT)) {
/* SMBus, GSBus, IPMI serial */
@@ -301,7 +303,9 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
|| obj_desc->field.region_obj->region.space_id ==
ACPI_ADR_SPACE_GSBUS
|| obj_desc->field.region_obj->region.space_id ==
- ACPI_ADR_SPACE_IPMI)) {
+ ACPI_ADR_SPACE_IPMI
+ || obj_desc->field.region_obj->region.space_id ==
+ ACPI_ADR_SPACE_PLATFORM_RT)) {
/* SMBus, GSBus, IPMI serial */
diff --git a/drivers/acpi/acpica/exserial.c b/drivers/acpi/acpica/exserial.c
index 8e8d95f7947b..10d68a5f76a3 100644
--- a/drivers/acpi/acpica/exserial.c
+++ b/drivers/acpi/acpica/exserial.c
@@ -195,6 +195,12 @@ acpi_ex_read_serial_bus(union acpi_operand_object *obj_desc,
function = ACPI_READ | (accessor_type << 16);
break;
+ case ACPI_ADR_SPACE_PLATFORM_RT:
+
+ buffer_length = ACPI_PRM_INPUT_BUFFER_SIZE;
+ function = ACPI_READ;
+ break;
+
default:
return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
}
@@ -311,6 +317,12 @@ acpi_ex_write_serial_bus(union acpi_operand_object *source_desc,
function = ACPI_WRITE | (accessor_type << 16);
break;
+ case ACPI_ADR_SPACE_PLATFORM_RT:
+
+ buffer_length = ACPI_PRM_INPUT_BUFFER_SIZE;
+ function = ACPI_WRITE;
+ break;
+
default:
return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
}
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index 14b71b41e845..38e10ab976e6 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -379,6 +379,13 @@ acpi_ns_repair_CID(struct acpi_evaluate_info *info,
(*element_ptr)->common.reference_count =
original_ref_count;
+
+ /*
+ * The original_element holds a reference from the package object
+ * that represents _HID. Since a new element was created by _HID,
+ * remove the reference from the _CID package.
+ */
+ acpi_ut_remove_reference(original_element);
}
element_ptr++;
diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c
index e37d612e8db5..05426596d1f4 100644
--- a/drivers/acpi/acpica/utprint.c
+++ b/drivers/acpi/acpica/utprint.c
@@ -475,7 +475,7 @@ int vsnprintf(char *string, acpi_size size, const char *format, va_list args)
case 'X':
type |= ACPI_FORMAT_UPPER;
- /* FALLTHROUGH */
+ ACPI_FALLTHROUGH;
case 'x':
diff --git a/drivers/acpi/acpica/utuuid.c b/drivers/acpi/acpica/utuuid.c
index 090e44b6b6c7..dca9061518ab 100644
--- a/drivers/acpi/acpica/utuuid.c
+++ b/drivers/acpi/acpica/utuuid.c
@@ -61,4 +61,45 @@ void acpi_ut_convert_string_to_uuid(char *in_string, u8 *uuid_buffer)
1]);
}
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_convert_uuid_to_string
+ *
+ * PARAMETERS: uuid_buffer - 16-byte UUID buffer
+ * out_string - 36-byte formatted UUID string
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert 16-byte UUID buffer to 36-byte formatted UUID string
+ * out_string must be 37 bytes to include null terminator.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_convert_uuid_to_string(char *uuid_buffer, char *out_string)
+{
+ u32 i;
+
+ if (!uuid_buffer || !out_string) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ for (i = 0; i < UUID_BUFFER_LENGTH; i++) {
+ out_string[acpi_gbl_map_to_uuid_offset[i]] =
+ acpi_ut_hex_to_ascii_char(uuid_buffer[i], 4);
+
+ out_string[acpi_gbl_map_to_uuid_offset[i] + 1] =
+ acpi_ut_hex_to_ascii_char(uuid_buffer[i], 0);
+ }
+
+ /* Insert required hyphens (dashes) */
+
+ out_string[UUID_HYPHEN1_OFFSET] =
+ out_string[UUID_HYPHEN2_OFFSET] =
+ out_string[UUID_HYPHEN3_OFFSET] =
+ out_string[UUID_HYPHEN4_OFFSET] = '-';
+
+ out_string[UUID_STRING_LENGTH] = 0; /* Null terminate */
+ return (AE_OK);
+}
#endif
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index 328e8aeece6c..2882450c443e 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -673,7 +673,7 @@ static int __init einj_init(void)
struct apei_exec_context ctx;
if (acpi_disabled) {
- pr_warn("ACPI disabled.\n");
+ pr_info("ACPI disabled.\n");
return -ENODEV;
}
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index fce7ade2aba9..0c8330ed1ffd 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -441,28 +441,35 @@ static void ghes_kick_task_work(struct callback_head *head)
gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node, node_len);
}
-static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
- int sev)
+static bool ghes_do_memory_failure(u64 physical_addr, int flags)
{
unsigned long pfn;
- int flags = -1;
- int sec_sev = ghes_severity(gdata->error_severity);
- struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
if (!IS_ENABLED(CONFIG_ACPI_APEI_MEMORY_FAILURE))
return false;
- if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
- return false;
-
- pfn = mem_err->physical_addr >> PAGE_SHIFT;
+ pfn = PHYS_PFN(physical_addr);
if (!pfn_valid(pfn)) {
pr_warn_ratelimited(FW_WARN GHES_PFX
"Invalid address in generic error data: %#llx\n",
- mem_err->physical_addr);
+ physical_addr);
return false;
}
+ memory_failure_queue(pfn, flags);
+ return true;
+}
+
+static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
+ int sev)
+{
+ int flags = -1;
+ int sec_sev = ghes_severity(gdata->error_severity);
+ struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
+
+ if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
+ return false;
+
/* iff following two events can be handled properly by now */
if (sec_sev == GHES_SEV_CORRECTED &&
(gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED))
@@ -470,14 +477,56 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE)
flags = 0;
- if (flags != -1) {
- memory_failure_queue(pfn, flags);
- return true;
- }
+ if (flags != -1)
+ return ghes_do_memory_failure(mem_err->physical_addr, flags);
return false;
}
+static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int sev)
+{
+ struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata);
+ bool queued = false;
+ int sec_sev, i;
+ char *p;
+
+ log_arm_hw_error(err);
+
+ sec_sev = ghes_severity(gdata->error_severity);
+ if (sev != GHES_SEV_RECOVERABLE || sec_sev != GHES_SEV_RECOVERABLE)
+ return false;
+
+ p = (char *)(err + 1);
+ for (i = 0; i < err->err_info_num; i++) {
+ struct cper_arm_err_info *err_info = (struct cper_arm_err_info *)p;
+ bool is_cache = (err_info->type == CPER_ARM_CACHE_ERROR);
+ bool has_pa = (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR);
+ const char *error_type = "unknown error";
+
+ /*
+ * The field (err_info->error_info & BIT(26)) is fixed to set to
+ * 1 in some old firmware of HiSilicon Kunpeng920. We assume that
+ * firmware won't mix corrected errors in an uncorrected section,
+ * and don't filter out 'corrected' error here.
+ */
+ if (is_cache && has_pa) {
+ queued = ghes_do_memory_failure(err_info->physical_fault_addr, 0);
+ p += err_info->length;
+ continue;
+ }
+
+ if (err_info->type < ARRAY_SIZE(cper_proc_error_type_strs))
+ error_type = cper_proc_error_type_strs[err_info->type];
+
+ pr_warn_ratelimited(FW_WARN GHES_PFX
+ "Unhandled processor error type: %s\n",
+ error_type);
+ p += err_info->length;
+ }
+
+ return queued;
+}
+
/*
* PCIe AER errors need to be sent to the AER driver for reporting and
* recovery. The GHES severities map to the following AER severities and
@@ -605,9 +654,7 @@ static bool ghes_do_proc(struct ghes *ghes,
ghes_handle_aer(gdata);
}
else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
- struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata);
-
- log_arm_hw_error(err);
+ queued = ghes_handle_arm_hw_error(gdata, sev);
} else {
void *err = acpi_hest_get_payload(gdata);
diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
index 6ff50f4ed947..66acbe77f46e 100644
--- a/drivers/acpi/arm64/Makefile
+++ b/drivers/acpi/arm64/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_ACPI_IORT) += iort.o
obj-$(CONFIG_ACPI_GTDT) += gtdt.o
+obj-y += dma.o
diff --git a/drivers/acpi/arm64/dma.c b/drivers/acpi/arm64/dma.c
new file mode 100644
index 000000000000..f16739ad3cc0
--- /dev/null
+++ b/drivers/acpi/arm64/dma.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
+#include <linux/device.h>
+#include <linux/dma-direct.h>
+
+void acpi_arch_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size)
+{
+ int ret;
+ u64 end, mask;
+ u64 dmaaddr = 0, size = 0, offset = 0;
+
+ /*
+ * If @dev is expected to be DMA-capable then the bus code that created
+ * it should have initialised its dma_mask pointer by this point. For
+ * now, we'll continue the legacy behaviour of coercing it to the
+ * coherent mask if not, but we'll no longer do so quietly.
+ */
+ if (!dev->dma_mask) {
+ dev_warn(dev, "DMA mask not set\n");
+ dev->dma_mask = &dev->coherent_dma_mask;
+ }
+
+ if (dev->coherent_dma_mask)
+ size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);
+ else
+ size = 1ULL << 32;
+
+ ret = acpi_dma_get_range(dev, &dmaaddr, &offset, &size);
+ if (ret == -ENODEV)
+ ret = iort_dma_get_ranges(dev, &size);
+ if (!ret) {
+ /*
+ * Limit coherent and dma mask based on size retrieved from
+ * firmware.
+ */
+ end = dmaaddr + size - 1;
+ mask = DMA_BIT_MASK(ilog2(end) + 1);
+ dev->bus_dma_limit = end;
+ dev->coherent_dma_mask = min(dev->coherent_dma_mask, mask);
+ *dev->dma_mask = min(*dev->dma_mask, mask);
+ }
+
+ *dma_addr = dmaaddr;
+ *dma_size = size;
+
+ ret = dma_direct_set_offset(dev, dmaaddr + offset, dmaaddr, size);
+
+ dev_dbg(dev, "dma_offset(%#08llx)%s\n", offset, ret ? " failed!" : "");
+}
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 3912a1f6058e..3b23fb775ac4 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -806,23 +806,6 @@ static struct acpi_iort_node *iort_get_msi_resv_iommu(struct device *dev)
return NULL;
}
-static inline const struct iommu_ops *iort_fwspec_iommu_ops(struct device *dev)
-{
- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-
- return (fwspec && fwspec->ops) ? fwspec->ops : NULL;
-}
-
-static inline int iort_add_device_replay(struct device *dev)
-{
- int err = 0;
-
- if (dev->bus && !device_iommu_mapped(dev))
- err = iommu_probe_device(dev);
-
- return err;
-}
-
/**
* iort_iommu_msi_get_resv_regions - Reserved region driver helper
* @dev: Device from iommu_get_resv_regions()
@@ -900,18 +883,6 @@ static inline bool iort_iommu_driver_enabled(u8 type)
}
}
-static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
- struct fwnode_handle *fwnode,
- const struct iommu_ops *ops)
-{
- int ret = iommu_fwspec_init(dev, fwnode, ops);
-
- if (!ret)
- ret = iommu_fwspec_add_ids(dev, &streamid, 1);
-
- return ret;
-}
-
static bool iort_pci_rc_supports_ats(struct acpi_iort_node *node)
{
struct acpi_iort_root_complex *pci_rc;
@@ -946,7 +917,7 @@ static int iort_iommu_xlate(struct device *dev, struct acpi_iort_node *node,
return iort_iommu_driver_enabled(node->type) ?
-EPROBE_DEFER : -ENODEV;
- return arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops);
+ return acpi_iommu_fwspec_init(dev, streamid, iort_fwnode, ops);
}
struct iort_pci_alias_info {
@@ -968,15 +939,17 @@ static int iort_pci_iommu_init(struct pci_dev *pdev, u16 alias, void *data)
static void iort_named_component_init(struct device *dev,
struct acpi_iort_node *node)
{
- struct property_entry props[2] = {};
+ struct property_entry props[3] = {};
struct acpi_iort_named_component *nc;
nc = (struct acpi_iort_named_component *)node->node_data;
props[0] = PROPERTY_ENTRY_U32("pasid-num-bits",
FIELD_GET(ACPI_IORT_NC_PASID_BITS,
nc->node_flags));
+ if (nc->node_flags & ACPI_IORT_NC_STALL_SUPPORTED)
+ props[1] = PROPERTY_ENTRY_BOOL("dma-can-stall");
- if (device_add_properties(dev, props))
+ if (device_create_managed_software_node(dev, props, NULL))
dev_warn(dev, "Could not add device properties\n");
}
@@ -1020,24 +993,13 @@ static int iort_nc_iommu_map_id(struct device *dev,
* @dev: device to configure
* @id_in: optional input id const value pointer
*
- * Returns: iommu_ops pointer on configuration success
- * NULL on configuration failure
+ * Returns: 0 on success, <0 on failure
*/
-const struct iommu_ops *iort_iommu_configure_id(struct device *dev,
- const u32 *id_in)
+int iort_iommu_configure_id(struct device *dev, const u32 *id_in)
{
struct acpi_iort_node *node;
- const struct iommu_ops *ops;
int err = -ENODEV;
- /*
- * If we already translated the fwspec there
- * is nothing left to do, return the iommu_ops.
- */
- ops = iort_fwspec_iommu_ops(dev);
- if (ops)
- return ops;
-
if (dev_is_pci(dev)) {
struct iommu_fwspec *fwspec;
struct pci_bus *bus = to_pci_dev(dev)->bus;
@@ -1046,7 +1008,7 @@ const struct iommu_ops *iort_iommu_configure_id(struct device *dev,
node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
iort_match_node_callback, &bus->dev);
if (!node)
- return NULL;
+ return -ENODEV;
info.node = node;
err = pci_for_each_dma_alias(to_pci_dev(dev),
@@ -1059,7 +1021,7 @@ const struct iommu_ops *iort_iommu_configure_id(struct device *dev,
node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
iort_match_node_callback, dev);
if (!node)
- return NULL;
+ return -ENODEV;
err = id_in ? iort_nc_iommu_map_id(dev, node, id_in) :
iort_nc_iommu_map(dev, node);
@@ -1068,32 +1030,14 @@ const struct iommu_ops *iort_iommu_configure_id(struct device *dev,
iort_named_component_init(dev, node);
}
- /*
- * If we have reason to believe the IOMMU driver missed the initial
- * add_device callback for dev, replay it to get things in order.
- */
- if (!err) {
- ops = iort_fwspec_iommu_ops(dev);
- err = iort_add_device_replay(dev);
- }
-
- /* Ignore all other errors apart from EPROBE_DEFER */
- if (err == -EPROBE_DEFER) {
- ops = ERR_PTR(err);
- } else if (err) {
- dev_dbg(dev, "Adding to IOMMU failed: %d\n", err);
- ops = NULL;
- }
-
- return ops;
+ return err;
}
#else
int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
{ return 0; }
-const struct iommu_ops *iort_iommu_configure_id(struct device *dev,
- const u32 *input_id)
-{ return NULL; }
+int iort_iommu_configure_id(struct device *dev, const u32 *input_id)
+{ return -ENODEV; }
#endif
static int nc_dma_get_range(struct device *dev, u64 *size)
@@ -1144,56 +1088,18 @@ static int rc_dma_get_range(struct device *dev, u64 *size)
}
/**
- * iort_dma_setup() - Set-up device DMA parameters.
+ * iort_dma_get_ranges() - Look up DMA addressing limit for the device
+ * @dev: device to lookup
+ * @size: DMA range size result pointer
*
- * @dev: device to configure
- * @dma_addr: device DMA address result pointer
- * @dma_size: DMA range size result pointer
+ * Return: 0 on success, an error otherwise.
*/
-void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size)
+int iort_dma_get_ranges(struct device *dev, u64 *size)
{
- u64 end, mask, dmaaddr = 0, size = 0, offset = 0;
- int ret;
-
- /*
- * If @dev is expected to be DMA-capable then the bus code that created
- * it should have initialised its dma_mask pointer by this point. For
- * now, we'll continue the legacy behaviour of coercing it to the
- * coherent mask if not, but we'll no longer do so quietly.
- */
- if (!dev->dma_mask) {
- dev_warn(dev, "DMA mask not set\n");
- dev->dma_mask = &dev->coherent_dma_mask;
- }
-
- if (dev->coherent_dma_mask)
- size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);
+ if (dev_is_pci(dev))
+ return rc_dma_get_range(dev, size);
else
- size = 1ULL << 32;
-
- ret = acpi_dma_get_range(dev, &dmaaddr, &offset, &size);
- if (ret == -ENODEV)
- ret = dev_is_pci(dev) ? rc_dma_get_range(dev, &size)
- : nc_dma_get_range(dev, &size);
-
- if (!ret) {
- /*
- * Limit coherent and dma mask based on size retrieved from
- * firmware.
- */
- end = dmaaddr + size - 1;
- mask = DMA_BIT_MASK(ilog2(end) + 1);
- dev->bus_dma_limit = end;
- dev->coherent_dma_mask = min(dev->coherent_dma_mask, mask);
- *dev->dma_mask = min(*dev->dma_mask, mask);
- }
-
- *dma_addr = dmaaddr;
- *dma_size = size;
-
- ret = dma_direct_set_offset(dev, dmaaddr + offset, dmaaddr, size);
-
- dev_dbg(dev, "dma_offset(%#08llx)%s\n", offset, ret ? " failed!" : "");
+ return nc_dma_get_range(dev, size);
}
static void __init acpi_iort_register_irq(int hwirq, const char *name,
diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c
index 19bb7f870204..02d208732f9a 100644
--- a/drivers/acpi/bgrt.c
+++ b/drivers/acpi/bgrt.c
@@ -15,40 +15,19 @@
static void *bgrt_image;
static struct kobject *bgrt_kobj;
-static ssize_t version_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.version);
-}
-static DEVICE_ATTR_RO(version);
-
-static ssize_t status_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.status);
-}
-static DEVICE_ATTR_RO(status);
-
-static ssize_t type_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.image_type);
-}
-static DEVICE_ATTR_RO(type);
-
-static ssize_t xoffset_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.image_offset_x);
-}
-static DEVICE_ATTR_RO(xoffset);
-
-static ssize_t yoffset_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.image_offset_y);
-}
-static DEVICE_ATTR_RO(yoffset);
+#define BGRT_SHOW(_name, _member) \
+ static ssize_t _name##_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, char *buf) \
+ { \
+ return sysfs_emit(buf, "%d\n", bgrt_tab._member); \
+ } \
+ struct kobj_attribute bgrt_attr_##_name = __ATTR_RO(_name)
+
+BGRT_SHOW(version, version);
+BGRT_SHOW(status, status);
+BGRT_SHOW(type, image_type);
+BGRT_SHOW(xoffset, image_offset_x);
+BGRT_SHOW(yoffset, image_offset_y);
static ssize_t image_read(struct file *file, struct kobject *kobj,
struct bin_attribute *attr, char *buf, loff_t off, size_t count)
@@ -60,11 +39,11 @@ static ssize_t image_read(struct file *file, struct kobject *kobj,
static BIN_ATTR_RO(image, 0); /* size gets filled in later */
static struct attribute *bgrt_attributes[] = {
- &dev_attr_version.attr,
- &dev_attr_status.attr,
- &dev_attr_type.attr,
- &dev_attr_xoffset.attr,
- &dev_attr_yoffset.attr,
+ &bgrt_attr_version.attr,
+ &bgrt_attr_status.attr,
+ &bgrt_attr_type.attr,
+ &bgrt_attr_xoffset.attr,
+ &bgrt_attr_yoffset.attr,
NULL,
};
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index a86a770c9b79..a558d24fb788 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -10,6 +10,8 @@
* Copyright (C) 2002 Andy Grover <andrew.grover@intel.com>
*/
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/acpi.h>
@@ -49,12 +51,12 @@ int __init acpi_blacklisted(void)
i = acpi_match_platform_list(acpi_blacklist);
if (i >= 0) {
- pr_err(PREFIX "Vendor \"%6.6s\" System \"%8.8s\" Revision 0x%x has a known ACPI BIOS problem.\n",
+ pr_err("Vendor \"%6.6s\" System \"%8.8s\" Revision 0x%x has a known ACPI BIOS problem.\n",
acpi_blacklist[i].oem_id,
acpi_blacklist[i].oem_table_id,
acpi_blacklist[i].oem_revision);
- pr_err(PREFIX "Reason: %s. This is a %s error\n",
+ pr_err("Reason: %s. This is a %s error\n",
acpi_blacklist[i].reason,
(acpi_blacklist[i].data ?
"non-recoverable" : "recoverable"));
@@ -73,8 +75,7 @@ int __init acpi_blacklisted(void)
#ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE
static int __init dmi_enable_rev_override(const struct dmi_system_id *d)
{
- printk(KERN_NOTICE PREFIX "DMI detected: %s (force ACPI _REV to 5)\n",
- d->ident);
+ pr_notice("DMI detected: %s (force ACPI _REV to 5)\n", d->ident);
acpi_rev_override_setup(NULL);
return 0;
}
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a4bd673934c0..f854bcb8d010 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -27,9 +27,11 @@
#include <linux/dmi.h>
#endif
#include <linux/acpi_iort.h>
+#include <linux/acpi_viot.h>
#include <linux/pci.h>
#include <acpi/apei.h>
#include <linux/suspend.h>
+#include <linux/prmt.h>
#include "internal.h"
@@ -262,8 +264,6 @@ out_success:
out_kfree:
kfree(output.pointer);
- if (status != AE_OK)
- context->ret.pointer = NULL;
return status;
}
EXPORT_SYMBOL(acpi_run_osc);
@@ -304,6 +304,8 @@ static void acpi_bus_osc_negotiate_platform_control(void)
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT;
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PCLPI_SUPPORT;
+ if (IS_ENABLED(CONFIG_ACPI_PRMT))
+ capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PRM_SUPPORT;
#ifdef CONFIG_ARM64
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_GENERIC_INITIATOR_SUPPORT;
@@ -359,7 +361,7 @@ EXPORT_SYMBOL_GPL(osc_sb_native_usb4_control);
static void acpi_bus_decode_usb_osc(const char *msg, u32 bits)
{
- printk(KERN_INFO PREFIX "%s USB3%c DisplayPort%c PCIe%c XDomain%c\n", msg,
+ pr_info("%s USB3%c DisplayPort%c PCIe%c XDomain%c\n", msg,
(bits & OSC_USB_USB3_TUNNELING) ? '+' : '-',
(bits & OSC_USB_DP_TUNNELING) ? '+' : '-',
(bits & OSC_USB_PCIE_TUNNELING) ? '+' : '-',
@@ -398,7 +400,7 @@ static void acpi_bus_osc_negotiate_usb_control(void)
return;
if (context.ret.length != sizeof(capbuf)) {
- printk(KERN_INFO PREFIX "USB4 _OSC: returned invalid length buffer\n");
+ pr_info("USB4 _OSC: returned invalid length buffer\n");
goto out_free;
}
@@ -1195,7 +1197,8 @@ void __init acpi_subsystem_init(void)
static acpi_status acpi_bus_table_handler(u32 event, void *table, void *context)
{
- acpi_scan_table_handler(event, table, context);
+ if (event == ACPI_TABLE_EVENT_LOAD)
+ acpi_scan_table_notify();
return acpi_sysfs_table_handler(event, table, context);
}
@@ -1314,13 +1317,13 @@ static int __init acpi_init(void)
}
acpi_kobj = kobject_create_and_add("acpi", firmware_kobj);
- if (!acpi_kobj) {
+ if (!acpi_kobj)
pr_debug("%s: kset create error\n", __func__);
- acpi_kobj = NULL;
- }
+ init_prmt();
result = acpi_bus_init();
if (result) {
+ kobject_put(acpi_kobj);
disable_acpi();
return result;
}
@@ -1334,6 +1337,7 @@ static int __init acpi_init(void)
acpi_wakeup_device_init();
acpi_debugger_init();
acpi_setup_sb_notify_handler();
+ acpi_viot_init();
return 0;
}
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index d260bc1f3e6e..0028b6b51c87 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -20,6 +20,7 @@
#include <linux/pm_runtime.h>
#include <linux/suspend.h>
+#include "fan.h"
#include "internal.h"
/**
@@ -1133,20 +1134,49 @@ static int acpi_subsys_resume_noirq(struct device *dev)
*
* Use ACPI to put the given device into the full-power state and carry out the
* generic early resume procedure for it during system transition into the
- * working state.
+ * working state, but only do that if device either defines early resume
+ * handler, or does not define power operations at all. Otherwise powering up
+ * of the device is postponed to the normal resume phase.
*/
static int acpi_subsys_resume_early(struct device *dev)
{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int ret;
if (dev_pm_skip_resume(dev))
return 0;
+ if (pm && !pm->resume_early) {
+ dev_dbg(dev, "postponing D0 transition to normal resume stage\n");
+ return 0;
+ }
+
ret = acpi_dev_resume(dev);
return ret ? ret : pm_generic_resume_early(dev);
}
/**
+ * acpi_subsys_resume - Resume device using ACPI.
+ * @dev: Device to Resume.
+ *
+ * Use ACPI to put the given device into the full-power state if it has not been
+ * powered up during early resume phase, and carry out the generic resume
+ * procedure for it during system transition into the working state.
+ */
+static int acpi_subsys_resume(struct device *dev)
+{
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+ int ret = 0;
+
+ if (!dev_pm_skip_resume(dev) && pm && !pm->resume_early) {
+ dev_dbg(dev, "executing postponed D0 transition\n");
+ ret = acpi_dev_resume(dev);
+ }
+
+ return ret ? ret : pm_generic_resume(dev);
+}
+
+/**
* acpi_subsys_freeze - Run the device driver's freeze callback.
* @dev: Device to handle.
*/
@@ -1239,6 +1269,7 @@ static struct dev_pm_domain acpi_general_pm_domain = {
.prepare = acpi_subsys_prepare,
.complete = acpi_subsys_complete,
.suspend = acpi_subsys_suspend,
+ .resume = acpi_subsys_resume,
.suspend_late = acpi_subsys_suspend_late,
.suspend_noirq = acpi_subsys_suspend_noirq,
.resume_noirq = acpi_subsys_resume_noirq,
@@ -1310,10 +1341,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
* with the generic ACPI PM domain.
*/
static const struct acpi_device_id special_pm_ids[] = {
- {"PNP0C0B", }, /* Generic ACPI fan */
- {"INT3404", }, /* Fan */
- {"INTC1044", }, /* Fan for Tiger Lake generation */
- {"INTC1048", }, /* Fan for Alder Lake generation */
+ ACPI_FAN_DEVICE_IDS,
{}
};
struct acpi_device *adev = ACPI_COMPANION(dev);
@@ -1340,4 +1368,36 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
return 1;
}
EXPORT_SYMBOL_GPL(acpi_dev_pm_attach);
+
+/**
+ * acpi_storage_d3 - Check if D3 should be used in the suspend path
+ * @dev: Device to check
+ *
+ * Return %true if the platform firmware wants @dev to be programmed
+ * into D3hot or D3cold (if supported) in the suspend path, or %false
+ * when there is no specific preference. On some platforms, if this
+ * hint is ignored, @dev may remain unresponsive after suspending the
+ * platform as a whole.
+ *
+ * Although the property has storage in the name it actually is
+ * applied to the PCIe slot and plugging in a non-storage device the
+ * same platform restrictions will likely apply.
+ */
+bool acpi_storage_d3(struct device *dev)
+{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ u8 val;
+
+ if (force_storage_d3())
+ return true;
+
+ if (!adev)
+ return false;
+ if (fwnode_property_read_u8(acpi_fwnode_handle(adev), "StorageD3Enable",
+ &val))
+ return false;
+ return val == 1;
+}
+EXPORT_SYMBOL_GPL(acpi_storage_d3);
+
#endif /* CONFIG_PM */
diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c
index fa2c1c93072c..61271e61c307 100644
--- a/drivers/acpi/device_sysfs.c
+++ b/drivers/acpi/device_sysfs.c
@@ -268,6 +268,8 @@ int __acpi_device_uevent_modalias(struct acpi_device *adev,
/**
* acpi_device_uevent_modalias - uevent modalias for ACPI-enumerated devices.
+ * @dev: Struct device to get ACPI device node.
+ * @env: Environment variables of the kobject uevent.
*
* Create the uevent modalias field for ACPI-enumerated devices.
*
@@ -313,6 +315,9 @@ static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size)
/**
* acpi_device_modalias - modalias sysfs attribute for ACPI-enumerated devices.
+ * @dev: Struct device to get ACPI device node.
+ * @buf: The buffer to save pnp_modalias and of_modalias.
+ * @size: Size of buffer.
*
* Create the modalias sysfs attribute for ACPI-enumerated devices.
*
@@ -448,7 +453,7 @@ static ssize_t description_show(struct device *dev,
(wchar_t *)acpi_dev->pnp.str_obj->buffer.pointer,
acpi_dev->pnp.str_obj->buffer.length,
UTF16_LITTLE_ENDIAN, buf,
- PAGE_SIZE);
+ PAGE_SIZE - 1);
buf[result++] = '\n';
diff --git a/drivers/acpi/dptf/int340x_thermal.c b/drivers/acpi/dptf/int340x_thermal.c
index d14025a85ce8..da5d5f0be2f2 100644
--- a/drivers/acpi/dptf/int340x_thermal.c
+++ b/drivers/acpi/dptf/int340x_thermal.c
@@ -24,6 +24,7 @@ static const struct acpi_device_id int340x_thermal_device_ids[] = {
{"INT3409"},
{"INT340A"},
{"INT340B"},
+ {"INT3532"},
{"INTC1040"},
{"INTC1041"},
{"INTC1043"},
@@ -33,6 +34,7 @@ static const struct acpi_device_id int340x_thermal_device_ids[] = {
{"INTC1047"},
{"INTC1048"},
{"INTC1049"},
+ {"INTC1050"},
{"INTC1060"},
{"INTC1061"},
{""},
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 13565629ce0a..e629e891d1bb 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -183,6 +183,7 @@ static struct workqueue_struct *ec_query_wq;
static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */
static int EC_FLAGS_IGNORE_DSDT_GPE; /* Needs ECDT GPE as correction setting */
+static int EC_FLAGS_TRUST_DSDT_GPE; /* Needs DSDT GPE as correction setting */
static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
/* --------------------------------------------------------------------------
@@ -1593,7 +1594,8 @@ static int acpi_ec_add(struct acpi_device *device)
}
if (boot_ec && ec->command_addr == boot_ec->command_addr &&
- ec->data_addr == boot_ec->data_addr) {
+ ec->data_addr == boot_ec->data_addr &&
+ !EC_FLAGS_TRUST_DSDT_GPE) {
/*
* Trust PNP0C09 namespace location rather than
* ECDT ID. But trust ECDT GPE rather than _GPE
@@ -1627,7 +1629,7 @@ static int acpi_ec_add(struct acpi_device *device)
WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr);
/* Reprobe devices depending on the EC */
- acpi_walk_dep_device_list(ec->handle);
+ acpi_dev_clear_dependencies(device);
acpi_handle_debug(ec->handle, "enumerated.\n");
return 0;
@@ -1817,6 +1819,18 @@ static int ec_correct_ecdt(const struct dmi_system_id *id)
}
/*
+ * Some ECDTs contain wrong GPE setting, but they share the same port addresses
+ * with DSDT EC, don't duplicate the DSDT EC with ECDT EC in this case.
+ * https://bugzilla.kernel.org/show_bug.cgi?id=209989
+ */
+static int ec_honor_dsdt_gpe(const struct dmi_system_id *id)
+{
+ pr_debug("Detected system needing DSDT GPE setting.\n");
+ EC_FLAGS_TRUST_DSDT_GPE = 1;
+ return 0;
+}
+
+/*
* Some DSDTs contain wrong GPE setting.
* Asus FX502VD/VE, GL702VMK, X550VXK, X580VD
* https://bugzilla.kernel.org/show_bug.cgi?id=195651
@@ -1846,6 +1860,22 @@ static const struct dmi_system_id ec_dmi_table[] __initconst = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "GL702VMK"),}, NULL},
{
+ ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X505BA", {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "X505BA"),}, NULL},
+ {
+ ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X505BP", {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "X505BP"),}, NULL},
+ {
+ ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X542BA", {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "X542BA"),}, NULL},
+ {
+ ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X542BP", {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "X542BP"),}, NULL},
+ {
ec_honor_ecdt_gpe, "ASUS X550VXK", {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X550VXK"),}, NULL},
@@ -1854,6 +1884,11 @@ static const struct dmi_system_id ec_dmi_table[] __initconst = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X580VD"),}, NULL},
{
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=209989 */
+ ec_honor_dsdt_gpe, "HP Pavilion Gaming Laptop 15-cx0xxx", {
+ DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Gaming Laptop 15-cx0xxx"),}, NULL},
+ {
ec_clear_on_resume, "Samsung hardware", {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
{},
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index 92e59f45329b..d199a19bb292 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -7,6 +7,8 @@
*
*/
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/spinlock.h>
#include <linux/export.h>
#include <linux/proc_fs.h>
@@ -165,7 +167,7 @@ static int acpi_event_genetlink_init(void)
static int __init acpi_event_init(void)
{
- int error = 0;
+ int error;
if (acpi_disabled)
return 0;
@@ -173,8 +175,8 @@ static int __init acpi_event_init(void)
/* create genetlink for acpi event */
error = acpi_event_genetlink_init();
if (error)
- printk(KERN_WARNING PREFIX
- "Failed to create genetlink family for ACPI event\n");
+ pr_warn("Failed to create genetlink family for ACPI event\n");
+
return 0;
}
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 66c3983f0ccc..5cd0ceb50bc8 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -16,6 +16,8 @@
#include <linux/platform_device.h>
#include <linux/sort.h>
+#include "fan.h"
+
MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION("ACPI Fan Driver");
MODULE_LICENSE("GPL");
@@ -24,10 +26,7 @@ static int acpi_fan_probe(struct platform_device *pdev);
static int acpi_fan_remove(struct platform_device *pdev);
static const struct acpi_device_id fan_device_ids[] = {
- {"PNP0C0B", 0},
- {"INT3404", 0},
- {"INTC1044", 0},
- {"INTC1048", 0},
+ ACPI_FAN_DEVICE_IDS,
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, fan_device_ids);
diff --git a/drivers/acpi/fan.h b/drivers/acpi/fan.h
new file mode 100644
index 000000000000..dc9a6efa514b
--- /dev/null
+++ b/drivers/acpi/fan.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/*
+ * ACPI fan device IDs are shared between the fan driver and the device power
+ * management code.
+ *
+ * Add new device IDs before the generic ACPI fan one.
+ */
+#define ACPI_FAN_DEVICE_IDS \
+ {"INT3404", }, /* Fan */ \
+ {"INTC1044", }, /* Fan for Tiger Lake generation */ \
+ {"INTC1048", }, /* Fan for Alder Lake generation */ \
+ {"PNP0C0B", } /* Generic ACPI fan */
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 0715e3be99a0..fce3f3bba714 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -6,6 +6,8 @@
* Copyright (c) 2005 Intel Corp.
*/
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/acpi_iort.h>
#include <linux/export.h>
#include <linux/init.h>
@@ -19,17 +21,6 @@
#include "internal.h"
-#define ACPI_GLUE_DEBUG 0
-#if ACPI_GLUE_DEBUG
-#define DBG(fmt, ...) \
- printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__)
-#else
-#define DBG(fmt, ...) \
-do { \
- if (0) \
- printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__); \
-} while (0)
-#endif
static LIST_HEAD(bus_type_list);
static DECLARE_RWSEM(bus_type_sem);
@@ -44,7 +35,7 @@ int register_acpi_bus_type(struct acpi_bus_type *type)
down_write(&bus_type_sem);
list_add_tail(&type->list, &bus_type_list);
up_write(&bus_type_sem);
- printk(KERN_INFO PREFIX "bus type %s registered\n", type->name);
+ pr_info("bus type %s registered\n", type->name);
return 0;
}
return -ENODEV;
@@ -59,8 +50,7 @@ int unregister_acpi_bus_type(struct acpi_bus_type *type)
down_write(&bus_type_sem);
list_del_init(&type->list);
up_write(&bus_type_sem);
- printk(KERN_INFO PREFIX "bus type %s unregistered\n",
- type->name);
+ pr_info("bus type %s unregistered\n", type->name);
return 0;
}
return -ENODEV;
@@ -307,7 +297,7 @@ static int acpi_device_notify(struct device *dev)
adev = type->find_companion(dev);
if (!adev) {
- DBG("Unable to get handle for %s\n", dev_name(dev));
+ pr_debug("Unable to get handle for %s\n", dev_name(dev));
ret = -ENODEV;
goto out;
}
@@ -328,16 +318,15 @@ static int acpi_device_notify(struct device *dev)
adev->handler->bind(dev);
out:
-#if ACPI_GLUE_DEBUG
if (!ret) {
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_get_name(ACPI_HANDLE(dev), ACPI_FULL_PATHNAME, &buffer);
- DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer);
+ pr_debug("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer);
kfree(buffer.pointer);
- } else
- DBG("Device %s -> No ACPI support\n", dev_name(dev));
-#endif
+ } else {
+ pr_debug("Device %s -> No ACPI support\n", dev_name(dev));
+ }
return ret;
}
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index e21611c9a170..d91b560e8867 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -11,8 +11,6 @@
#include <linux/idr.h>
-#define PREFIX "ACPI: "
-
int early_acpi_osi_init(void);
int acpi_osi_init(void);
acpi_status acpi_os_initialize1(void);
@@ -88,7 +86,7 @@ void acpi_device_hotplug(struct acpi_device *adev, u32 src);
bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent);
acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context);
-void acpi_scan_table_handler(u32 event, void *table, void *context);
+void acpi_scan_table_notify(void);
/* --------------------------------------------------------------------------
Device Node Initialization / Removal
@@ -142,7 +140,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev,
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);
-void acpi_turn_off_unused_power_resources(bool init);
+void acpi_turn_off_unused_power_resources(void);
/* --------------------------------------------------------------------------
Device Power Management
@@ -236,6 +234,15 @@ static inline int suspend_nvs_save(void) { return 0; }
static inline void suspend_nvs_restore(void) {}
#endif
+#ifdef CONFIG_X86
+bool force_storage_d3(void);
+#else
+static inline bool force_storage_d3(void)
+{
+ return false;
+}
+#endif
+
/*--------------------------------------------------------------------------
Device properties
-------------------------------------------------------------------------- */
diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c
index 9f8712a557b3..a2b11069e792 100644
--- a/drivers/acpi/nvs.c
+++ b/drivers/acpi/nvs.c
@@ -5,6 +5,8 @@
* Copyright (C) 2008-2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
*/
+#define pr_fmt(fmt) "ACPI: PM: " fmt
+
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -82,19 +84,19 @@ struct nvs_page {
static LIST_HEAD(nvs_list);
/**
- * suspend_nvs_register - register platform NVS memory region to save
- * @start - physical address of the region
- * @size - size of the region
+ * suspend_nvs_register - register platform NVS memory region to save
+ * @start: Physical address of the region.
+ * @size: Size of the region.
*
- * The NVS region need not be page-aligned (both ends) and we arrange
- * things so that the data from page-aligned addresses in this region will
- * be copied into separate RAM pages.
+ * The NVS region need not be page-aligned (both ends) and we arrange
+ * things so that the data from page-aligned addresses in this region will
+ * be copied into separate RAM pages.
*/
static int suspend_nvs_register(unsigned long start, unsigned long size)
{
struct nvs_page *entry, *next;
- pr_info("PM: Registering ACPI NVS region [mem %#010lx-%#010lx] (%ld bytes)\n",
+ pr_info("Registering ACPI NVS region [mem %#010lx-%#010lx] (%ld bytes)\n",
start, start + size - 1, size);
while (size > 0) {
@@ -123,7 +125,7 @@ static int suspend_nvs_register(unsigned long start, unsigned long size)
}
/**
- * suspend_nvs_free - free data pages allocated for saving NVS regions
+ * suspend_nvs_free - free data pages allocated for saving NVS regions
*/
void suspend_nvs_free(void)
{
@@ -147,7 +149,7 @@ void suspend_nvs_free(void)
}
/**
- * suspend_nvs_alloc - allocate memory necessary for saving NVS regions
+ * suspend_nvs_alloc - allocate memory necessary for saving NVS regions
*/
int suspend_nvs_alloc(void)
{
@@ -164,13 +166,13 @@ int suspend_nvs_alloc(void)
}
/**
- * suspend_nvs_save - save NVS memory regions
+ * suspend_nvs_save - save NVS memory regions
*/
int suspend_nvs_save(void)
{
struct nvs_page *entry;
- printk(KERN_INFO "PM: Saving platform NVS memory\n");
+ pr_info("Saving platform NVS memory\n");
list_for_each_entry(entry, &nvs_list, node)
if (entry->data) {
@@ -193,16 +195,16 @@ int suspend_nvs_save(void)
}
/**
- * suspend_nvs_restore - restore NVS memory regions
+ * suspend_nvs_restore - restore NVS memory regions
*
- * This function is going to be called with interrupts disabled, so it
- * cannot iounmap the virtual addresses used to access the NVS region.
+ * This function is going to be called with interrupts disabled, so it
+ * cannot iounmap the virtual addresses used to access the NVS region.
*/
void suspend_nvs_restore(void)
{
struct nvs_page *entry;
- printk(KERN_INFO "PM: Restoring platform NVS memory\n");
+ pr_info("Restoring platform NVS memory\n");
list_for_each_entry(entry, &nvs_list, node)
if (entry->data)
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 327e1b4eb6b0..45c5c0e45e33 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -212,7 +212,7 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
return efi.acpi20;
if (efi.acpi != EFI_INVALID_TABLE_ADDR)
return efi.acpi;
- pr_err(PREFIX "System description tables not found\n");
+ pr_err("System description tables not found\n");
} else if (IS_ENABLED(CONFIG_ACPI_LEGACY_TABLES_LOOKUP)) {
acpi_find_root_pointer(&pa);
}
@@ -430,7 +430,7 @@ void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
map = acpi_map_lookup_virt(virt, size);
if (!map) {
mutex_unlock(&acpi_ioremap_lock);
- WARN(true, PREFIX "%s: bad address %p\n", __func__, virt);
+ WARN(true, "ACPI: %s: bad address %p\n", __func__, virt);
return;
}
acpi_os_drop_map_ref(map);
@@ -1487,12 +1487,7 @@ EXPORT_SYMBOL(acpi_check_resource_conflict);
int acpi_check_region(resource_size_t start, resource_size_t n,
const char *name)
{
- struct resource res = {
- .start = start,
- .end = start + n - 1,
- .name = name,
- .flags = IORESOURCE_IO,
- };
+ struct resource res = DEFINE_RES_IO_NAMED(start, n, name);
return acpi_check_resource_conflict(&res);
}
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index dcd593766a64..d7deedf3548e 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -6,6 +6,8 @@
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
*/
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -574,7 +576,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
goto end;
}
- pr_info(PREFIX "%s [%s] (domain %04x %pR)\n",
+ pr_info("%s [%s] (domain %04x %pR)\n",
acpi_device_name(device), acpi_device_bid(device),
root->segment, &root->secondary);
diff --git a/drivers/acpi/pmic/Kconfig b/drivers/acpi/pmic/Kconfig
index 56bbcb2ce61b..f84b8f6038dc 100644
--- a/drivers/acpi/pmic/Kconfig
+++ b/drivers/acpi/pmic/Kconfig
@@ -52,7 +52,7 @@ endif # PMIC_OPREGION
config TPS68470_PMIC_OPREGION
bool "ACPI operation region support for TPS68470 PMIC"
- depends on MFD_TPS68470
+ depends on INTEL_SKL_INT3472
help
This config adds ACPI operation region support for TI TPS68470 PMIC.
TPS68470 device is an advanced power management unit that powers
diff --git a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c
index a5101b07611a..fef7831d0d63 100644
--- a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c
+++ b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c
@@ -117,7 +117,7 @@ static int chtdc_ti_pmic_opregion_probe(struct platform_device *pdev)
return err;
/* Re-enumerate devices depending on PMIC */
- acpi_walk_dep_device_list(ACPI_HANDLE(pdev->dev.parent));
+ acpi_dev_clear_dependencies(ACPI_COMPANION(pdev->dev.parent));
return 0;
}
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 97c9a94a1a30..eba7785047ca 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -52,7 +52,7 @@ struct acpi_power_resource {
u32 system_level;
u32 order;
unsigned int ref_count;
- unsigned int users;
+ u8 state;
bool wakeup_enabled;
struct mutex resource_lock;
struct list_head dependents;
@@ -173,8 +173,6 @@ int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
err = acpi_power_resources_list_add(rhandle, list);
if (err)
break;
-
- to_power_resource(rdev)->users++;
}
if (err)
acpi_power_resources_list_free(list);
@@ -182,44 +180,54 @@ int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
return err;
}
-static int acpi_power_get_state(acpi_handle handle, int *state)
+static int __get_state(acpi_handle handle, u8 *state)
{
acpi_status status = AE_OK;
unsigned long long sta = 0;
-
- if (!handle || !state)
- return -EINVAL;
+ u8 cur_state;
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status))
return -ENODEV;
- *state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON:
- ACPI_POWER_RESOURCE_STATE_OFF;
+ cur_state = sta & ACPI_POWER_RESOURCE_STATE_ON;
acpi_handle_debug(handle, "Power resource is %s\n",
- *state ? "on" : "off");
+ cur_state ? "on" : "off");
+
+ *state = cur_state;
+ return 0;
+}
+
+static int acpi_power_get_state(struct acpi_power_resource *resource, u8 *state)
+{
+ if (resource->state == ACPI_POWER_RESOURCE_STATE_UNKNOWN) {
+ int ret;
+ ret = __get_state(resource->device.handle, &resource->state);
+ if (ret)
+ return ret;
+ }
+
+ *state = resource->state;
return 0;
}
-static int acpi_power_get_list_state(struct list_head *list, int *state)
+static int acpi_power_get_list_state(struct list_head *list, u8 *state)
{
struct acpi_power_resource_entry *entry;
- int cur_state;
+ u8 cur_state = ACPI_POWER_RESOURCE_STATE_OFF;
if (!list || !state)
return -EINVAL;
/* The state of the list is 'on' IFF all resources are 'on'. */
- cur_state = 0;
list_for_each_entry(entry, list, node) {
struct acpi_power_resource *resource = entry->resource;
- acpi_handle handle = resource->device.handle;
int result;
mutex_lock(&resource->resource_lock);
- result = acpi_power_get_state(handle, &cur_state);
+ result = acpi_power_get_state(resource, &cur_state);
mutex_unlock(&resource->resource_lock);
if (result)
return result;
@@ -352,8 +360,12 @@ static int __acpi_power_on(struct acpi_power_resource *resource)
acpi_status status = AE_OK;
status = acpi_evaluate_object(resource->device.handle, "_ON", NULL, NULL);
- if (ACPI_FAILURE(status))
+ if (ACPI_FAILURE(status)) {
+ resource->state = ACPI_POWER_RESOURCE_STATE_UNKNOWN;
return -ENODEV;
+ }
+
+ resource->state = ACPI_POWER_RESOURCE_STATE_ON;
pr_debug("Power resource [%s] turned on\n", resource->name);
@@ -405,8 +417,12 @@ static int __acpi_power_off(struct acpi_power_resource *resource)
status = acpi_evaluate_object(resource->device.handle, "_OFF",
NULL, NULL);
- if (ACPI_FAILURE(status))
+ if (ACPI_FAILURE(status)) {
+ resource->state = ACPI_POWER_RESOURCE_STATE_UNKNOWN;
return -ENODEV;
+ }
+
+ resource->state = ACPI_POWER_RESOURCE_STATE_OFF;
pr_debug("Power resource [%s] turned off\n", resource->name);
@@ -590,13 +606,12 @@ int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p)
list_for_each_entry(entry, list, node) {
struct acpi_power_resource *resource = entry->resource;
- acpi_handle handle = resource->device.handle;
int result;
- int state;
+ u8 state;
mutex_lock(&resource->resource_lock);
- result = acpi_power_get_state(handle, &state);
+ result = acpi_power_get_state(resource, &state);
if (result) {
mutex_unlock(&resource->resource_lock);
return result;
@@ -789,8 +804,8 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
{
+ u8 list_state = ACPI_POWER_RESOURCE_STATE_OFF;
int result = 0;
- int list_state = 0;
int i = 0;
if (!device || !state)
@@ -919,7 +934,7 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle)
union acpi_object acpi_object;
struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object };
acpi_status status;
- int state, result = -ENODEV;
+ int result;
acpi_bus_get_device(handle, &device);
if (device)
@@ -946,13 +961,9 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle)
resource->system_level = acpi_object.power_resource.system_level;
resource->order = acpi_object.power_resource.resource_order;
+ resource->state = ACPI_POWER_RESOURCE_STATE_UNKNOWN;
- result = acpi_power_get_state(handle, &state);
- if (result)
- goto err;
-
- pr_info("%s [%s] (%s)\n", acpi_device_name(device),
- acpi_device_bid(device), state ? "on" : "off");
+ pr_info("%s [%s]\n", acpi_device_name(device), acpi_device_bid(device));
device->flags.match_driver = true;
result = acpi_device_add(device, acpi_release_power_resource);
@@ -979,11 +990,13 @@ void acpi_resume_power_resources(void)
mutex_lock(&power_resource_list_lock);
list_for_each_entry(resource, &acpi_power_resource_list, list_node) {
- int result, state;
+ int result;
+ u8 state;
mutex_lock(&resource->resource_lock);
- result = acpi_power_get_state(resource->device.handle, &state);
+ resource->state = ACPI_POWER_RESOURCE_STATE_UNKNOWN;
+ result = acpi_power_get_state(resource, &state);
if (result) {
mutex_unlock(&resource->resource_lock);
continue;
@@ -991,7 +1004,7 @@ void acpi_resume_power_resources(void)
if (state == ACPI_POWER_RESOURCE_STATE_OFF
&& resource->ref_count) {
- dev_info(&resource->device.dev, "Turning ON\n");
+ dev_dbg(&resource->device.dev, "Turning ON\n");
__acpi_power_on(resource);
}
@@ -1002,38 +1015,10 @@ void acpi_resume_power_resources(void)
}
#endif
-static void acpi_power_turn_off_if_unused(struct acpi_power_resource *resource,
- bool init)
-{
- if (resource->ref_count > 0)
- return;
-
- if (init) {
- if (resource->users > 0)
- return;
- } else {
- int result, state;
-
- result = acpi_power_get_state(resource->device.handle, &state);
- if (result || state == ACPI_POWER_RESOURCE_STATE_OFF)
- return;
- }
-
- dev_info(&resource->device.dev, "Turning OFF\n");
- __acpi_power_off(resource);
-}
-
/**
* acpi_turn_off_unused_power_resources - Turn off power resources not in use.
- * @init: Control switch.
- *
- * If @ainit is set, unconditionally turn off all of the ACPI power resources
- * without any users.
- *
- * Otherwise, turn off all ACPI power resources without active references (that
- * is, the ones that should be "off" at the moment) that are "on".
*/
-void acpi_turn_off_unused_power_resources(bool init)
+void acpi_turn_off_unused_power_resources(void)
{
struct acpi_power_resource *resource;
@@ -1042,7 +1027,16 @@ void acpi_turn_off_unused_power_resources(bool init)
list_for_each_entry_reverse(resource, &acpi_power_resource_list, list_node) {
mutex_lock(&resource->resource_lock);
- acpi_power_turn_off_if_unused(resource, init);
+ /*
+ * Turn off power resources in an unknown state too, because the
+ * platform firmware on some system expects the OS to turn off
+ * power resources without any users unconditionally.
+ */
+ if (!resource->ref_count &&
+ resource->state != ACPI_POWER_RESOURCE_STATE_OFF) {
+ dev_dbg(&resource->device.dev, "Turning OFF\n");
+ __acpi_power_off(resource);
+ }
mutex_unlock(&resource->resource_lock);
}
diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c
index 4ae93350b70d..fe69dc518f31 100644
--- a/drivers/acpi/pptt.c
+++ b/drivers/acpi/pptt.c
@@ -347,6 +347,7 @@ static struct acpi_pptt_cache *acpi_find_cache_node(struct acpi_table_header *ta
* @this_leaf: Kernel cache info structure being updated
* @found_cache: The PPTT node describing this cache instance
* @cpu_node: A unique reference to describe this cache instance
+ * @revision: The revision of the PPTT table
*
* The ACPI spec implies that the fields in the cache structures are used to
* extend and correct the information probed from the hardware. Lets only
@@ -356,8 +357,11 @@ static struct acpi_pptt_cache *acpi_find_cache_node(struct acpi_table_header *ta
*/
static void update_cache_properties(struct cacheinfo *this_leaf,
struct acpi_pptt_cache *found_cache,
- struct acpi_pptt_processor *cpu_node)
+ struct acpi_pptt_processor *cpu_node,
+ u8 revision)
{
+ struct acpi_pptt_cache_v1* found_cache_v1;
+
this_leaf->fw_token = cpu_node;
if (found_cache->flags & ACPI_PPTT_SIZE_PROPERTY_VALID)
this_leaf->size = found_cache->size;
@@ -405,6 +409,13 @@ static void update_cache_properties(struct cacheinfo *this_leaf,
if (this_leaf->type == CACHE_TYPE_NOCACHE &&
found_cache->flags & ACPI_PPTT_CACHE_TYPE_VALID)
this_leaf->type = CACHE_TYPE_UNIFIED;
+
+ if (revision >= 3 && (found_cache->flags & ACPI_PPTT_CACHE_ID_VALID)) {
+ found_cache_v1 = ACPI_ADD_PTR(struct acpi_pptt_cache_v1,
+ found_cache, sizeof(struct acpi_pptt_cache));
+ this_leaf->id = found_cache_v1->cache_id;
+ this_leaf->attributes |= CACHE_ID;
+ }
}
static void cache_setup_acpi_cpu(struct acpi_table_header *table,
@@ -425,9 +436,8 @@ static void cache_setup_acpi_cpu(struct acpi_table_header *table,
&cpu_node);
pr_debug("found = %p %p\n", found_cache, cpu_node);
if (found_cache)
- update_cache_properties(this_leaf,
- found_cache,
- cpu_node);
+ update_cache_properties(this_leaf, found_cache,
+ cpu_node, table->revision);
index++;
}
diff --git a/drivers/acpi/prmt.c b/drivers/acpi/prmt.c
new file mode 100644
index 000000000000..31cf9aee5edd
--- /dev/null
+++ b/drivers/acpi/prmt.c
@@ -0,0 +1,303 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Author: Erik Kaneda <erik.kaneda@intel.com>
+ * Copyright 2020 Intel Corporation
+ *
+ * prmt.c
+ *
+ * Each PRM service is an executable that is run in a restricted environment
+ * that is invoked by writing to the PlatformRtMechanism OperationRegion from
+ * AML bytecode.
+ *
+ * init_prmt initializes the Platform Runtime Mechanism (PRM) services by
+ * processing data in the PRMT as well as registering an ACPI OperationRegion
+ * handler for the PlatformRtMechanism subtype.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/efi.h>
+#include <linux/acpi.h>
+#include <linux/prmt.h>
+#include <asm/efi.h>
+
+#pragma pack(1)
+struct prm_mmio_addr_range {
+ u64 phys_addr;
+ u64 virt_addr;
+ u32 length;
+};
+
+struct prm_mmio_info {
+ u64 mmio_count;
+ struct prm_mmio_addr_range addr_ranges[];
+};
+
+struct prm_buffer {
+ u8 prm_status;
+ u64 efi_status;
+ u8 prm_cmd;
+ guid_t handler_guid;
+};
+
+struct prm_context_buffer {
+ char signature[ACPI_NAMESEG_SIZE];
+ u16 revision;
+ u16 reserved;
+ guid_t identifier;
+ u64 static_data_buffer;
+ struct prm_mmio_info *mmio_ranges;
+};
+#pragma pack()
+
+
+static LIST_HEAD(prm_module_list);
+
+struct prm_handler_info {
+ guid_t guid;
+ u64 handler_addr;
+ u64 static_data_buffer_addr;
+ u64 acpi_param_buffer_addr;
+
+ struct list_head handler_list;
+};
+
+struct prm_module_info {
+ guid_t guid;
+ u16 major_rev;
+ u16 minor_rev;
+ u16 handler_count;
+ struct prm_mmio_info *mmio_info;
+ bool updatable;
+
+ struct list_head module_list;
+ struct prm_handler_info handlers[];
+};
+
+
+static u64 efi_pa_va_lookup(u64 pa)
+{
+ efi_memory_desc_t *md;
+ u64 pa_offset = pa & ~PAGE_MASK;
+ u64 page = pa & PAGE_MASK;
+
+ for_each_efi_memory_desc(md) {
+ if (md->phys_addr < pa && pa < md->phys_addr + PAGE_SIZE * md->num_pages)
+ return pa_offset + md->virt_addr + page - md->phys_addr;
+ }
+
+ return 0;
+}
+
+
+#define get_first_handler(a) ((struct acpi_prmt_handler_info *) ((char *) (a) + a->handler_info_offset))
+#define get_next_handler(a) ((struct acpi_prmt_handler_info *) (sizeof(struct acpi_prmt_handler_info) + (char *) a))
+
+static int __init
+acpi_parse_prmt(union acpi_subtable_headers *header, const unsigned long end)
+{
+ struct acpi_prmt_module_info *module_info;
+ struct acpi_prmt_handler_info *handler_info;
+ struct prm_handler_info *th;
+ struct prm_module_info *tm;
+ u64 mmio_count = 0;
+ u64 cur_handler = 0;
+ u32 module_info_size = 0;
+ u64 mmio_range_size = 0;
+ void *temp_mmio;
+
+ module_info = (struct acpi_prmt_module_info *) header;
+ module_info_size = struct_size(tm, handlers, module_info->handler_info_count);
+ tm = kmalloc(module_info_size, GFP_KERNEL);
+
+ guid_copy(&tm->guid, (guid_t *) module_info->module_guid);
+ tm->major_rev = module_info->major_rev;
+ tm->minor_rev = module_info->minor_rev;
+ tm->handler_count = module_info->handler_info_count;
+ tm->updatable = true;
+
+ if (module_info->mmio_list_pointer) {
+ /*
+ * Each module is associated with a list of addr
+ * ranges that it can use during the service
+ */
+ mmio_count = *(u64 *) memremap(module_info->mmio_list_pointer, 8, MEMREMAP_WB);
+ mmio_range_size = struct_size(tm->mmio_info, addr_ranges, mmio_count);
+ tm->mmio_info = kmalloc(mmio_range_size, GFP_KERNEL);
+ temp_mmio = memremap(module_info->mmio_list_pointer, mmio_range_size, MEMREMAP_WB);
+ memmove(tm->mmio_info, temp_mmio, mmio_range_size);
+ } else {
+ mmio_range_size = struct_size(tm->mmio_info, addr_ranges, mmio_count);
+ tm->mmio_info = kmalloc(mmio_range_size, GFP_KERNEL);
+ tm->mmio_info->mmio_count = 0;
+ }
+
+ INIT_LIST_HEAD(&tm->module_list);
+ list_add(&tm->module_list, &prm_module_list);
+
+ handler_info = get_first_handler(module_info);
+ do {
+ th = &tm->handlers[cur_handler];
+
+ guid_copy(&th->guid, (guid_t *)handler_info->handler_guid);
+ th->handler_addr = efi_pa_va_lookup(handler_info->handler_address);
+ th->static_data_buffer_addr = efi_pa_va_lookup(handler_info->static_data_buffer_address);
+ th->acpi_param_buffer_addr = efi_pa_va_lookup(handler_info->acpi_param_buffer_address);
+ } while (++cur_handler < tm->handler_count && (handler_info = get_next_handler(handler_info)));
+
+ return 0;
+}
+
+#define GET_MODULE 0
+#define GET_HANDLER 1
+
+static void *find_guid_info(const guid_t *guid, u8 mode)
+{
+ struct prm_handler_info *cur_handler;
+ struct prm_module_info *cur_module;
+ int i = 0;
+
+ list_for_each_entry(cur_module, &prm_module_list, module_list) {
+ for (i = 0; i < cur_module->handler_count; ++i) {
+ cur_handler = &cur_module->handlers[i];
+ if (guid_equal(guid, &cur_handler->guid)) {
+ if (mode == GET_MODULE)
+ return (void *)cur_module;
+ else
+ return (void *)cur_handler;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+static struct prm_module_info *find_prm_module(const guid_t *guid)
+{
+ return (struct prm_module_info *)find_guid_info(guid, GET_MODULE);
+}
+
+static struct prm_handler_info *find_prm_handler(const guid_t *guid)
+{
+ return (struct prm_handler_info *) find_guid_info(guid, GET_HANDLER);
+}
+
+/* In-coming PRM commands */
+
+#define PRM_CMD_RUN_SERVICE 0
+#define PRM_CMD_START_TRANSACTION 1
+#define PRM_CMD_END_TRANSACTION 2
+
+/* statuses that can be passed back to ASL */
+
+#define PRM_HANDLER_SUCCESS 0
+#define PRM_HANDLER_ERROR 1
+#define INVALID_PRM_COMMAND 2
+#define PRM_HANDLER_GUID_NOT_FOUND 3
+#define UPDATE_LOCK_ALREADY_HELD 4
+#define UPDATE_UNLOCK_WITHOUT_LOCK 5
+
+/*
+ * This is the PlatformRtMechanism opregion space handler.
+ * @function: indicates the read/write. In fact as the PlatformRtMechanism
+ * message is driven by command, only write is meaningful.
+ *
+ * @addr : not used
+ * @bits : not used.
+ * @value : it is an in/out parameter. It points to the PRM message buffer.
+ * @handler_context: not used
+ */
+static acpi_status acpi_platformrt_space_handler(u32 function,
+ acpi_physical_address addr,
+ u32 bits, acpi_integer *value,
+ void *handler_context,
+ void *region_context)
+{
+ struct prm_buffer *buffer = ACPI_CAST_PTR(struct prm_buffer, value);
+ struct prm_handler_info *handler;
+ struct prm_module_info *module;
+ efi_status_t status;
+ struct prm_context_buffer context;
+
+ /*
+ * The returned acpi_status will always be AE_OK. Error values will be
+ * saved in the first byte of the PRM message buffer to be used by ASL.
+ */
+ switch (buffer->prm_cmd) {
+ case PRM_CMD_RUN_SERVICE:
+
+ handler = find_prm_handler(&buffer->handler_guid);
+ module = find_prm_module(&buffer->handler_guid);
+ if (!handler || !module)
+ goto invalid_guid;
+
+ ACPI_COPY_NAMESEG(context.signature, "PRMC");
+ context.revision = 0x0;
+ context.reserved = 0x0;
+ context.identifier = handler->guid;
+ context.static_data_buffer = handler->static_data_buffer_addr;
+ context.mmio_ranges = module->mmio_info;
+
+ status = efi_call_virt_pointer(handler, handler_addr,
+ handler->acpi_param_buffer_addr,
+ &context);
+ if (status == EFI_SUCCESS) {
+ buffer->prm_status = PRM_HANDLER_SUCCESS;
+ } else {
+ buffer->prm_status = PRM_HANDLER_ERROR;
+ buffer->efi_status = status;
+ }
+ break;
+
+ case PRM_CMD_START_TRANSACTION:
+
+ module = find_prm_module(&buffer->handler_guid);
+ if (!module)
+ goto invalid_guid;
+
+ if (module->updatable)
+ module->updatable = false;
+ else
+ buffer->prm_status = UPDATE_LOCK_ALREADY_HELD;
+ break;
+
+ case PRM_CMD_END_TRANSACTION:
+
+ module = find_prm_module(&buffer->handler_guid);
+ if (!module)
+ goto invalid_guid;
+
+ if (module->updatable)
+ buffer->prm_status = UPDATE_UNLOCK_WITHOUT_LOCK;
+ else
+ module->updatable = true;
+ break;
+
+ default:
+
+ buffer->prm_status = INVALID_PRM_COMMAND;
+ break;
+ }
+
+ return AE_OK;
+
+invalid_guid:
+ buffer->prm_status = PRM_HANDLER_GUID_NOT_FOUND;
+ return AE_OK;
+}
+
+void __init init_prmt(void)
+{
+ acpi_status status;
+ int mc = acpi_table_parse_entries(ACPI_SIG_PRMT, sizeof(struct acpi_table_prmt) +
+ sizeof (struct acpi_table_prmt_header),
+ 0, acpi_parse_prmt, 0);
+ pr_info("PRM: found %u modules\n", mc);
+
+ status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
+ ACPI_ADR_SPACE_PLATFORM_RT,
+ &acpi_platformrt_space_handler,
+ NULL, NULL);
+ if (ACPI_FAILURE(status))
+ pr_alert("PRM: OperationRegion handler could not be installed\n");
+}
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 45a019619e4a..095c8aca141e 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -16,6 +16,7 @@
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/sched.h> /* need_resched() */
+#include <linux/sort.h>
#include <linux/tick.h>
#include <linux/cpuidle.h>
#include <linux/cpu.h>
@@ -384,10 +385,37 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
return;
}
+static int acpi_cst_latency_cmp(const void *a, const void *b)
+{
+ const struct acpi_processor_cx *x = a, *y = b;
+
+ if (!(x->valid && y->valid))
+ return 0;
+ if (x->latency > y->latency)
+ return 1;
+ if (x->latency < y->latency)
+ return -1;
+ return 0;
+}
+static void acpi_cst_latency_swap(void *a, void *b, int n)
+{
+ struct acpi_processor_cx *x = a, *y = b;
+ u32 tmp;
+
+ if (!(x->valid && y->valid))
+ return;
+ tmp = x->latency;
+ x->latency = y->latency;
+ y->latency = tmp;
+}
+
static int acpi_processor_power_verify(struct acpi_processor *pr)
{
unsigned int i;
unsigned int working = 0;
+ unsigned int last_latency = 0;
+ unsigned int last_type = 0;
+ bool buggy_latency = false;
pr->power.timer_broadcast_on_state = INT_MAX;
@@ -411,12 +439,24 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
}
if (!cx->valid)
continue;
+ if (cx->type >= last_type && cx->latency < last_latency)
+ buggy_latency = true;
+ last_latency = cx->latency;
+ last_type = cx->type;
lapic_timer_check_state(i, pr, cx);
tsc_check_state(cx->type);
working++;
}
+ if (buggy_latency) {
+ pr_notice("FW issue: working around C-state latencies out of order\n");
+ sort(&pr->power.states[1], max_cstate,
+ sizeof(struct acpi_processor_cx),
+ acpi_cst_latency_cmp,
+ acpi_cst_latency_swap);
+ }
+
lapic_timer_propagate_broadcast(pr);
return (working);
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index d088a0089ee9..757a98f6d7a2 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -9,6 +9,8 @@
* - Added processor hotplug support
*/
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -20,8 +22,6 @@
#include <asm/cpufeature.h>
#endif
-#define PREFIX "ACPI: "
-
#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance"
static DEFINE_MUTEX(performance_mutex);
@@ -194,7 +194,6 @@ static int acpi_processor_get_performance_control(struct acpi_processor *pr)
union acpi_object *pct = NULL;
union acpi_object obj = { 0 };
-
status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer);
if (ACPI_FAILURE(status)) {
acpi_evaluation_failure_warn(pr->handle, "_PCT", status);
@@ -204,7 +203,7 @@ static int acpi_processor_get_performance_control(struct acpi_processor *pr)
pct = (union acpi_object *)buffer.pointer;
if (!pct || (pct->type != ACPI_TYPE_PACKAGE)
|| (pct->package.count != 2)) {
- printk(KERN_ERR PREFIX "Invalid _PCT data\n");
+ pr_err("Invalid _PCT data\n");
result = -EFAULT;
goto end;
}
@@ -218,7 +217,7 @@ static int acpi_processor_get_performance_control(struct acpi_processor *pr)
if ((obj.type != ACPI_TYPE_BUFFER)
|| (obj.buffer.length < sizeof(struct acpi_pct_register))
|| (obj.buffer.pointer == NULL)) {
- printk(KERN_ERR PREFIX "Invalid _PCT data (control_register)\n");
+ pr_err("Invalid _PCT data (control_register)\n");
result = -EFAULT;
goto end;
}
@@ -234,7 +233,7 @@ static int acpi_processor_get_performance_control(struct acpi_processor *pr)
if ((obj.type != ACPI_TYPE_BUFFER)
|| (obj.buffer.length < sizeof(struct acpi_pct_register))
|| (obj.buffer.pointer == NULL)) {
- printk(KERN_ERR PREFIX "Invalid _PCT data (status_register)\n");
+ pr_err("Invalid _PCT data (status_register)\n");
result = -EFAULT;
goto end;
}
@@ -242,7 +241,7 @@ static int acpi_processor_get_performance_control(struct acpi_processor *pr)
memcpy(&pr->performance->status_register, obj.buffer.pointer,
sizeof(struct acpi_pct_register));
- end:
+end:
kfree(buffer.pointer);
return result;
@@ -294,7 +293,6 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
int i;
int last_invalid = -1;
-
status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer);
if (ACPI_FAILURE(status)) {
acpi_evaluation_failure_warn(pr->handle, "_PSS", status);
@@ -303,7 +301,7 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
pss = buffer.pointer;
if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) {
- printk(KERN_ERR PREFIX "Invalid _PSS data\n");
+ pr_err("Invalid _PSS data\n");
result = -EFAULT;
goto end;
}
@@ -357,7 +355,7 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
if (!px->core_frequency ||
((u32)(px->core_frequency * 1000) !=
(px->core_frequency * 1000))) {
- printk(KERN_ERR FW_BUG PREFIX
+ pr_err(FW_BUG
"Invalid BIOS _PSS frequency found for processor %d: 0x%llx MHz\n",
pr->id, px->core_frequency);
if (last_invalid == -1)
@@ -375,8 +373,8 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
}
if (last_invalid == 0) {
- printk(KERN_ERR FW_BUG PREFIX
- "No valid BIOS _PSS frequency found for processor %d\n", pr->id);
+ pr_err(FW_BUG
+ "No valid BIOS _PSS frequency found for processor %d\n", pr->id);
result = -EFAULT;
kfree(pr->performance->states);
pr->performance->states = NULL;
@@ -385,7 +383,7 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
if (last_invalid > 0)
pr->performance->state_count = last_invalid;
- end:
+end:
kfree(buffer.pointer);
return result;
@@ -426,7 +424,7 @@ int acpi_processor_get_performance_info(struct acpi_processor *pr)
#ifdef CONFIG_X86
if (acpi_has_method(pr->handle, "_PPC")) {
if(boot_cpu_has(X86_FEATURE_EST))
- printk(KERN_WARNING FW_BUG "BIOS needs update for CPU "
+ pr_warn(FW_BUG "BIOS needs update for CPU "
"frequency support\n");
}
#endif
@@ -520,13 +518,13 @@ int acpi_processor_get_psd(acpi_handle handle, struct acpi_psd_package *pdomain)
psd = buffer.pointer;
if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) {
- printk(KERN_ERR PREFIX "Invalid _PSD data\n");
+ pr_err("Invalid _PSD data\n");
result = -EFAULT;
goto end;
}
if (psd->package.count != 1) {
- printk(KERN_ERR PREFIX "Invalid _PSD data\n");
+ pr_err("Invalid _PSD data\n");
result = -EFAULT;
goto end;
}
@@ -537,19 +535,19 @@ int acpi_processor_get_psd(acpi_handle handle, struct acpi_psd_package *pdomain)
status = acpi_extract_package(&(psd->package.elements[0]),
&format, &state);
if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Invalid _PSD data\n");
+ pr_err("Invalid _PSD data\n");
result = -EFAULT;
goto end;
}
if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) {
- printk(KERN_ERR PREFIX "Unknown _PSD:num_entries\n");
+ pr_err("Unknown _PSD:num_entries\n");
result = -EFAULT;
goto end;
}
if (pdomain->revision != ACPI_PSD_REV0_REVISION) {
- printk(KERN_ERR PREFIX "Unknown _PSD:revision\n");
+ pr_err("Unknown _PSD:revision\n");
result = -EFAULT;
goto end;
}
@@ -557,7 +555,7 @@ int acpi_processor_get_psd(acpi_handle handle, struct acpi_psd_package *pdomain)
if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
- printk(KERN_ERR PREFIX "Invalid _PSD:coord_type\n");
+ pr_err("Invalid _PSD:coord_type\n");
result = -EFAULT;
goto end;
}
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 677a132be242..a3d34e3f9f94 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -17,8 +17,6 @@
#include <acpi/processor.h>
#include <linux/uaccess.h>
-#define PREFIX "ACPI: "
-
#ifdef CONFIG_CPU_FREQ
/* If a passive cooling situation is detected, primarily CPUfreq is used, as it
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index e61b8f038364..a822fe410dda 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -6,9 +6,11 @@
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
* Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
* Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
- * - Added processor hotplug support
+ * - Added processor hotplug support
*/
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -20,8 +22,6 @@
#include <asm/io.h>
#include <linux/uaccess.h>
-#define PREFIX "ACPI: "
-
/* ignore_tpc:
* 0 -> acpi processor driver doesn't ignore _TPC values
* 1 -> acpi processor driver ignores _TPC values
@@ -195,15 +195,13 @@ void acpi_processor_throttling_init(void)
{
if (acpi_processor_update_tsd_coord())
pr_debug("Assume no T-state coordination\n");
-
- return;
}
static int acpi_processor_throttling_notifier(unsigned long event, void *data)
{
struct throttling_tstate *p_tstate = data;
struct acpi_processor *pr;
- unsigned int cpu ;
+ unsigned int cpu;
int target_state;
struct acpi_processor_limit *p_limit;
struct acpi_processor_throttling *p_throttling;
@@ -236,8 +234,7 @@ static int acpi_processor_throttling_notifier(unsigned long event, void *data)
if (pr->throttling_platform_limit > target_state)
target_state = pr->throttling_platform_limit;
if (target_state >= p_throttling->state_count) {
- printk(KERN_WARNING
- "Exceed the limit of T-state \n");
+ pr_warn("Exceed the limit of T-state \n");
target_state = p_throttling->state_count - 1;
}
p_tstate->target_state = target_state;
@@ -256,8 +253,7 @@ static int acpi_processor_throttling_notifier(unsigned long event, void *data)
cpu, target_state);
break;
default:
- printk(KERN_WARNING
- "Unsupported Throttling notifier event\n");
+ pr_warn("Unsupported Throttling notifier event\n");
break;
}
@@ -408,7 +404,7 @@ static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
acpi_status status = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *ptc = NULL;
- union acpi_object obj = { 0 };
+ union acpi_object obj;
struct acpi_processor_throttling *throttling;
status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer);
@@ -422,7 +418,7 @@ static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
ptc = (union acpi_object *)buffer.pointer;
if (!ptc || (ptc->type != ACPI_TYPE_PACKAGE)
|| (ptc->package.count != 2)) {
- printk(KERN_ERR PREFIX "Invalid _PTC data\n");
+ pr_err("Invalid _PTC data\n");
result = -EFAULT;
goto end;
}
@@ -436,8 +432,7 @@ static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
if ((obj.type != ACPI_TYPE_BUFFER)
|| (obj.buffer.length < sizeof(struct acpi_ptc_register))
|| (obj.buffer.pointer == NULL)) {
- printk(KERN_ERR PREFIX
- "Invalid _PTC data (control_register)\n");
+ pr_err("Invalid _PTC data (control_register)\n");
result = -EFAULT;
goto end;
}
@@ -453,7 +448,7 @@ static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
if ((obj.type != ACPI_TYPE_BUFFER)
|| (obj.buffer.length < sizeof(struct acpi_ptc_register))
|| (obj.buffer.pointer == NULL)) {
- printk(KERN_ERR PREFIX "Invalid _PTC data (status_register)\n");
+ pr_err("Invalid _PTC data (status_register)\n");
result = -EFAULT;
goto end;
}
@@ -465,19 +460,19 @@ static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
if ((throttling->control_register.bit_width +
throttling->control_register.bit_offset) > 32) {
- printk(KERN_ERR PREFIX "Invalid _PTC control register\n");
+ pr_err("Invalid _PTC control register\n");
result = -EFAULT;
goto end;
}
if ((throttling->status_register.bit_width +
throttling->status_register.bit_offset) > 32) {
- printk(KERN_ERR PREFIX "Invalid _PTC status register\n");
+ pr_err("Invalid _PTC status register\n");
result = -EFAULT;
goto end;
}
- end:
+end:
kfree(buffer.pointer);
return result;
@@ -506,7 +501,7 @@ static int acpi_processor_get_throttling_states(struct acpi_processor *pr)
tss = buffer.pointer;
if (!tss || (tss->type != ACPI_TYPE_PACKAGE)) {
- printk(KERN_ERR PREFIX "Invalid _TSS data\n");
+ pr_err("Invalid _TSS data\n");
result = -EFAULT;
goto end;
}
@@ -546,15 +541,14 @@ static int acpi_processor_get_throttling_states(struct acpi_processor *pr)
}
if (!tx->freqpercentage) {
- printk(KERN_ERR PREFIX
- "Invalid _TSS data: freq is zero\n");
+ pr_err("Invalid _TSS data: freq is zero\n");
result = -EFAULT;
kfree(pr->throttling.states_tss);
goto end;
}
}
- end:
+end:
kfree(buffer.pointer);
return result;
@@ -587,13 +581,13 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
tsd = buffer.pointer;
if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) {
- printk(KERN_ERR PREFIX "Invalid _TSD data\n");
+ pr_err("Invalid _TSD data\n");
result = -EFAULT;
goto end;
}
if (tsd->package.count != 1) {
- printk(KERN_ERR PREFIX "Invalid _TSD data\n");
+ pr_err("Invalid _TSD data\n");
result = -EFAULT;
goto end;
}
@@ -606,19 +600,19 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
status = acpi_extract_package(&(tsd->package.elements[0]),
&format, &state);
if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Invalid _TSD data\n");
+ pr_err("Invalid _TSD data\n");
result = -EFAULT;
goto end;
}
if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) {
- printk(KERN_ERR PREFIX "Unknown _TSD:num_entries\n");
+ pr_err("Unknown _TSD:num_entries\n");
result = -EFAULT;
goto end;
}
if (pdomain->revision != ACPI_TSD_REV0_REVISION) {
- printk(KERN_ERR PREFIX "Unknown _TSD:revision\n");
+ pr_err("Unknown _TSD:revision\n");
result = -EFAULT;
goto end;
}
@@ -639,7 +633,7 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
}
- end:
+end:
kfree(buffer.pointer);
return result;
}
@@ -711,13 +705,12 @@ static int acpi_throttling_rdmsr(u64 *value)
if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
!this_cpu_has(X86_FEATURE_ACPI)) {
- printk(KERN_ERR PREFIX
- "HARDWARE addr space,NOT supported yet\n");
+ pr_err("HARDWARE addr space,NOT supported yet\n");
} else {
msr_low = 0;
msr_high = 0;
rdmsr_safe(MSR_IA32_THERM_CONTROL,
- (u32 *)&msr_low , (u32 *) &msr_high);
+ (u32 *)&msr_low, (u32 *) &msr_high);
msr = (msr_high << 32) | msr_low;
*value = (u64) msr;
ret = 0;
@@ -732,8 +725,7 @@ static int acpi_throttling_wrmsr(u64 value)
if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
!this_cpu_has(X86_FEATURE_ACPI)) {
- printk(KERN_ERR PREFIX
- "HARDWARE addr space,NOT supported yet\n");
+ pr_err("HARDWARE addr space,NOT supported yet\n");
} else {
msr = value;
wrmsr_safe(MSR_IA32_THERM_CONTROL,
@@ -745,15 +737,13 @@ static int acpi_throttling_wrmsr(u64 value)
#else
static int acpi_throttling_rdmsr(u64 *value)
{
- printk(KERN_ERR PREFIX
- "HARDWARE addr space,NOT supported yet\n");
+ pr_err("HARDWARE addr space,NOT supported yet\n");
return -1;
}
static int acpi_throttling_wrmsr(u64 value)
{
- printk(KERN_ERR PREFIX
- "HARDWARE addr space,NOT supported yet\n");
+ pr_err("HARDWARE addr space,NOT supported yet\n");
return -1;
}
#endif
@@ -784,7 +774,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr,
ret = acpi_throttling_rdmsr(value);
break;
default:
- printk(KERN_ERR PREFIX "Unknown addr space %d\n",
+ pr_err("Unknown addr space %d\n",
(u32) (throttling->status_register.space_id));
}
return ret;
@@ -817,7 +807,7 @@ static int acpi_write_throttling_state(struct acpi_processor *pr,
ret = acpi_throttling_wrmsr(value);
break;
default:
- printk(KERN_ERR PREFIX "Unknown addr space %d\n",
+ pr_err("Unknown addr space %d\n",
(u32) (throttling->control_register.space_id));
}
return ret;
@@ -926,7 +916,7 @@ static int acpi_processor_get_fadt_info(struct acpi_processor *pr)
}
/* TBD: Support duty_cycle values that span bit 4. */
else if ((pr->throttling.duty_offset + pr->throttling.duty_width) > 4) {
- printk(KERN_WARNING PREFIX "duty_cycle spans bit 4\n");
+ pr_warn("duty_cycle spans bit 4\n");
return -EINVAL;
}
@@ -1185,8 +1175,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
*/
if (acpi_processor_get_throttling_control(pr) ||
acpi_processor_get_throttling_states(pr) ||
- acpi_processor_get_platform_limit(pr))
- {
+ acpi_processor_get_platform_limit(pr)) {
pr->throttling.acpi_processor_get_throttling =
&acpi_processor_get_throttling_fadt;
pr->throttling.acpi_processor_set_throttling =
@@ -1246,7 +1235,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
goto end;
}
- end:
+end:
if (result)
pr->flags.throttling = 0;
diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c
index 2a61f884e222..b79b7c99c237 100644
--- a/drivers/acpi/reboot.c
+++ b/drivers/acpi/reboot.c
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/pci.h>
#include <linux/acpi.h>
#include <acpi/reboot.h>
@@ -63,7 +65,7 @@ void acpi_reboot(void)
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
case ACPI_ADR_SPACE_SYSTEM_IO:
- printk(KERN_DEBUG "ACPI MEMORY or I/O RESET_REG.\n");
+ pr_debug("ACPI MEMORY or I/O RESET_REG.\n");
acpi_reset();
break;
}
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index ee78a210c606..dc01fb550b28 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -423,6 +423,13 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi,
}
}
+static bool irq_is_legacy(struct acpi_resource_irq *irq)
+{
+ return irq->triggering == ACPI_EDGE_SENSITIVE &&
+ irq->polarity == ACPI_ACTIVE_HIGH &&
+ irq->shareable == ACPI_EXCLUSIVE;
+}
+
/**
* acpi_dev_resource_interrupt - Extract ACPI interrupt resource information.
* @ares: Input ACPI resource object.
@@ -461,7 +468,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
}
acpi_dev_get_irqresource(res, irq->interrupts[index],
irq->triggering, irq->polarity,
- irq->shareable, true);
+ irq->shareable, irq_is_legacy(irq));
break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
ext_irq = &ares->data.extended_irq;
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 3b0b6dd34914..4938010fcac7 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -7,6 +7,8 @@
* Copyright (c) 2005 Rich Townsend <rhdt@bartol.udel.edu>
*/
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -23,8 +25,6 @@
#include "sbshc.h"
-#define PREFIX "ACPI: "
-
#define ACPI_SBS_CLASS "sbs"
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_SBS_DEVICE_NAME "Smart Battery System"
@@ -544,7 +544,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
goto end;
battery->have_sysfs_alarm = 1;
end:
- printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
+ pr_info("%s [%s]: Battery Slot [%s] (battery %s)\n",
ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
battery->name, battery->present ? "present" : "absent");
return result;
@@ -577,10 +577,10 @@ static int acpi_charger_add(struct acpi_sbs *sbs)
result = PTR_ERR(sbs->charger);
sbs->charger = NULL;
}
- printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n",
+ pr_info("%s [%s]: AC Adapter [%s] (%s)\n",
ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line");
- end:
+end:
return result;
}
@@ -658,7 +658,7 @@ static int acpi_sbs_add(struct acpi_device *device)
acpi_battery_add(sbs, 0);
acpi_smbus_register_callback(sbs->hc, acpi_sbs_callback, sbs);
- end:
+end:
if (result)
acpi_sbs_remove(device);
return result;
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index 53c2862c4c75..7c62e149a7a1 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -5,6 +5,8 @@
* Copyright (c) 2007 Alexey Starikovskiy
*/
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/acpi.h>
#include <linux/wait.h>
#include <linux/slab.h>
@@ -13,8 +15,6 @@
#include <linux/interrupt.h>
#include "sbshc.h"
-#define PREFIX "ACPI: "
-
#define ACPI_SMB_HC_CLASS "smbus_host_ctl"
#define ACPI_SMB_HC_DEVICE_NAME "ACPI SMBus HC"
@@ -109,7 +109,7 @@ static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol,
u8 temp, sz = 0;
if (!hc) {
- printk(KERN_ERR PREFIX "host controller is not configured\n");
+ pr_err("host controller is not configured\n");
return ret;
}
@@ -231,7 +231,6 @@ static int smbus_alarm(void *context)
case ACPI_SBS_BATTERY:
acpi_os_execute(OSL_NOTIFY_HANDLER,
acpi_smbus_callback, hc);
- default:;
}
mutex_unlock(&hc->lock);
return 0;
@@ -254,7 +253,7 @@ static int acpi_smbus_hc_add(struct acpi_device *device)
status = acpi_evaluate_integer(device->handle, "_EC", NULL, &val);
if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "error obtaining _EC.\n");
+ pr_err("error obtaining _EC.\n");
return -EIO;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index e10d38ac7cf2..b24513ec3fae 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -3,12 +3,16 @@
* scan.c - support for transforming the ACPI namespace into individual objects
*/
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/acpi_iort.h>
+#include <linux/acpi_viot.h>
+#include <linux/iommu.h>
#include <linux/signal.h>
#include <linux/kthread.h>
#include <linux/dmi.h>
@@ -47,12 +51,6 @@ static DEFINE_MUTEX(acpi_hp_context_lock);
*/
static u64 spcr_uart_addr;
-struct acpi_dep_data {
- struct list_head node;
- acpi_handle supplier;
- acpi_handle consumer;
-};
-
void acpi_scan_lock_acquire(void)
{
mutex_lock(&acpi_scan_lock);
@@ -612,11 +610,6 @@ struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle)
return handle_to_device(handle, get_acpi_device);
}
-void acpi_bus_put_acpi_device(struct acpi_device *adev)
-{
- acpi_dev_put(adev);
-}
-
static struct acpi_device_bus_id *acpi_device_bus_id_match(const char *dev_id)
{
struct acpi_device_bus_id *acpi_device_bus_id;
@@ -644,24 +637,29 @@ static int acpi_device_set_name(struct acpi_device *device,
return 0;
}
-int acpi_device_add(struct acpi_device *device,
- void (*release)(struct device *))
+static int acpi_tie_acpi_dev(struct acpi_device *adev)
{
- struct acpi_device_bus_id *acpi_device_bus_id;
- int result;
+ acpi_handle handle = adev->handle;
+ acpi_status status;
- if (device->handle) {
- acpi_status status;
+ if (!handle)
+ return 0;
- status = acpi_attach_data(device->handle, acpi_scan_drop_device,
- device);
- if (ACPI_FAILURE(status)) {
- acpi_handle_err(device->handle,
- "Unable to attach device data\n");
- return -ENODEV;
- }
+ status = acpi_attach_data(handle, acpi_scan_drop_device, adev);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_err(handle, "Unable to attach device data\n");
+ return -ENODEV;
}
+ return 0;
+}
+
+static int __acpi_device_add(struct acpi_device *device,
+ void (*release)(struct device *))
+{
+ struct acpi_device_bus_id *acpi_device_bus_id;
+ int result;
+
/*
* Linkage
* -------
@@ -729,7 +727,7 @@ int acpi_device_add(struct acpi_device *device,
result = acpi_device_setup_files(device);
if (result)
- printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n",
+ pr_err("Error creating sysfs interface for device %s\n",
dev_name(&device->dev));
return 0;
@@ -750,6 +748,17 @@ err_unlock:
return result;
}
+int acpi_device_add(struct acpi_device *adev, void (*release)(struct device *))
+{
+ int ret;
+
+ ret = acpi_tie_acpi_dev(adev);
+ if (ret)
+ return ret;
+
+ return __acpi_device_add(adev, release);
+}
+
/* --------------------------------------------------------------------------
Device Enumeration
-------------------------------------------------------------------------- */
@@ -1320,8 +1329,7 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
acpi_get_object_info(handle, &info);
if (!info) {
- pr_err(PREFIX "%s: Error reading device info\n",
- __func__);
+ pr_err("%s: Error reading device info\n", __func__);
return;
}
@@ -1405,7 +1413,7 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp)
*
* Return false if DMA is not supported. Otherwise, return true
*/
-bool acpi_dma_supported(struct acpi_device *adev)
+bool acpi_dma_supported(const struct acpi_device *adev)
{
if (!adev)
return false;
@@ -1520,6 +1528,78 @@ int acpi_dma_get_range(struct device *dev, u64 *dma_addr, u64 *offset,
return ret >= 0 ? 0 : ret;
}
+#ifdef CONFIG_IOMMU_API
+int acpi_iommu_fwspec_init(struct device *dev, u32 id,
+ struct fwnode_handle *fwnode,
+ const struct iommu_ops *ops)
+{
+ int ret = iommu_fwspec_init(dev, fwnode, ops);
+
+ if (!ret)
+ ret = iommu_fwspec_add_ids(dev, &id, 1);
+
+ return ret;
+}
+
+static inline const struct iommu_ops *acpi_iommu_fwspec_ops(struct device *dev)
+{
+ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+
+ return fwspec ? fwspec->ops : NULL;
+}
+
+static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev,
+ const u32 *id_in)
+{
+ int err;
+ const struct iommu_ops *ops;
+
+ /*
+ * If we already translated the fwspec there is nothing left to do,
+ * return the iommu_ops.
+ */
+ ops = acpi_iommu_fwspec_ops(dev);
+ if (ops)
+ return ops;
+
+ err = iort_iommu_configure_id(dev, id_in);
+ if (err && err != -EPROBE_DEFER)
+ err = viot_iommu_configure(dev);
+
+ /*
+ * If we have reason to believe the IOMMU driver missed the initial
+ * iommu_probe_device() call for dev, replay it to get things in order.
+ */
+ if (!err && dev->bus && !device_iommu_mapped(dev))
+ err = iommu_probe_device(dev);
+
+ /* Ignore all other errors apart from EPROBE_DEFER */
+ if (err == -EPROBE_DEFER) {
+ return ERR_PTR(err);
+ } else if (err) {
+ dev_dbg(dev, "Adding to IOMMU failed: %d\n", err);
+ return NULL;
+ }
+ return acpi_iommu_fwspec_ops(dev);
+}
+
+#else /* !CONFIG_IOMMU_API */
+
+int acpi_iommu_fwspec_init(struct device *dev, u32 id,
+ struct fwnode_handle *fwnode,
+ const struct iommu_ops *ops)
+{
+ return -ENODEV;
+}
+
+static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev,
+ const u32 *id_in)
+{
+ return NULL;
+}
+
+#endif /* !CONFIG_IOMMU_API */
+
/**
* acpi_dma_configure_id - Set-up DMA configuration for the device.
* @dev: The pointer to the device
@@ -1537,9 +1617,9 @@ int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr,
return 0;
}
- iort_dma_setup(dev, &dma_addr, &size);
+ acpi_arch_dma_setup(dev, &dma_addr, &size);
- iommu = iort_iommu_configure_id(dev, input_id);
+ iommu = acpi_iommu_configure_id(dev, input_id);
if (PTR_ERR(iommu) == -EPROBE_DEFER)
return -EPROBE_DEFER;
@@ -1671,8 +1751,16 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
device_initialize(&device->dev);
dev_set_uevent_suppress(&device->dev, true);
acpi_init_coherency(device);
- /* Assume there are unmet deps to start with. */
- device->dep_unmet = 1;
+}
+
+static void acpi_scan_dep_init(struct acpi_device *adev)
+{
+ struct acpi_dep_data *dep;
+
+ list_for_each_entry(dep, &acpi_dep_list, node) {
+ if (dep->consumer == adev->handle)
+ adev->dep_unmet++;
+ }
}
void acpi_device_add_finalize(struct acpi_device *device)
@@ -1688,9 +1776,10 @@ static void acpi_scan_init_status(struct acpi_device *adev)
}
static int acpi_add_single_object(struct acpi_device **child,
- acpi_handle handle, int type)
+ acpi_handle handle, int type, bool dep_init)
{
struct acpi_device *device;
+ bool release_dep_lock = false;
int result;
device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL);
@@ -1703,13 +1792,32 @@ static int acpi_add_single_object(struct acpi_device **child,
* acpi_bus_get_status() and use its quirk handling. Note that
* this must be done before the get power-/wakeup_dev-flags calls.
*/
- if (type == ACPI_BUS_TYPE_DEVICE || type == ACPI_BUS_TYPE_PROCESSOR)
+ if (type == ACPI_BUS_TYPE_DEVICE || type == ACPI_BUS_TYPE_PROCESSOR) {
+ if (dep_init) {
+ mutex_lock(&acpi_dep_list_lock);
+ /*
+ * Hold the lock until the acpi_tie_acpi_dev() call
+ * below to prevent concurrent acpi_scan_clear_dep()
+ * from deleting a dependency list entry without
+ * updating dep_unmet for the device.
+ */
+ release_dep_lock = true;
+ acpi_scan_dep_init(device);
+ }
acpi_scan_init_status(device);
+ }
acpi_bus_get_power_flags(device);
acpi_bus_get_wakeup_device_flags(device);
- result = acpi_device_add(device, acpi_device_release);
+ result = acpi_tie_acpi_dev(device);
+
+ if (release_dep_lock)
+ mutex_unlock(&acpi_dep_list_lock);
+
+ if (!result)
+ result = __acpi_device_add(device, acpi_device_release);
+
if (result) {
acpi_device_release(&device->dev);
return result;
@@ -1886,22 +1994,6 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep)
return count;
}
-static void acpi_scan_dep_init(struct acpi_device *adev)
-{
- struct acpi_dep_data *dep;
-
- adev->dep_unmet = 0;
-
- mutex_lock(&acpi_dep_list_lock);
-
- list_for_each_entry(dep, &acpi_dep_list, node) {
- if (dep->consumer == adev->handle)
- adev->dep_unmet++;
- }
-
- mutex_unlock(&acpi_dep_list_lock);
-}
-
static bool acpi_bus_scan_second_pass;
static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep,
@@ -1949,19 +2041,15 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep,
return AE_OK;
}
- acpi_add_single_object(&device, handle, type);
- if (!device)
- return AE_CTRL_DEPTH;
-
- acpi_scan_init_hotplug(device);
/*
* If check_dep is true at this point, the device has no dependencies,
* or the creation of the device object would have been postponed above.
*/
- if (check_dep)
- device->dep_unmet = 0;
- else
- acpi_scan_dep_init(device);
+ acpi_add_single_object(&device, handle, type, !check_dep);
+ if (!device)
+ return AE_CTRL_DEPTH;
+
+ acpi_scan_init_hotplug(device);
out:
if (!*adev_p)
@@ -2111,29 +2199,141 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
device->handler->hotplug.notify_online(device);
}
-void acpi_walk_dep_device_list(acpi_handle handle)
+static int acpi_dev_get_first_consumer_dev_cb(struct acpi_dep_data *dep, void *data)
{
- struct acpi_dep_data *dep, *tmp;
struct acpi_device *adev;
+ adev = acpi_bus_get_acpi_device(dep->consumer);
+ if (adev) {
+ *(struct acpi_device **)data = adev;
+ return 1;
+ }
+ /* Continue parsing if the device object is not present. */
+ return 0;
+}
+
+struct acpi_scan_clear_dep_work {
+ struct work_struct work;
+ struct acpi_device *adev;
+};
+
+static void acpi_scan_clear_dep_fn(struct work_struct *work)
+{
+ struct acpi_scan_clear_dep_work *cdw;
+
+ cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
+
+ acpi_scan_lock_acquire();
+ acpi_bus_attach(cdw->adev, true);
+ acpi_scan_lock_release();
+
+ acpi_dev_put(cdw->adev);
+ kfree(cdw);
+}
+
+static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
+{
+ struct acpi_scan_clear_dep_work *cdw;
+
+ if (adev->dep_unmet)
+ return false;
+
+ cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
+ if (!cdw)
+ return false;
+
+ cdw->adev = adev;
+ INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
+ /*
+ * Since the work function may block on the lock until the entire
+ * initial enumeration of devices is complete, put it into the unbound
+ * workqueue.
+ */
+ queue_work(system_unbound_wq, &cdw->work);
+
+ return true;
+}
+
+static int acpi_scan_clear_dep(struct acpi_dep_data *dep, void *data)
+{
+ struct acpi_device *adev = acpi_bus_get_acpi_device(dep->consumer);
+
+ if (adev) {
+ adev->dep_unmet--;
+ if (!acpi_scan_clear_dep_queue(adev))
+ acpi_dev_put(adev);
+ }
+
+ list_del(&dep->node);
+ kfree(dep);
+
+ return 0;
+}
+
+/**
+ * acpi_walk_dep_device_list - Apply a callback to every entry in acpi_dep_list
+ * @handle: The ACPI handle of the supplier device
+ * @callback: Pointer to the callback function to apply
+ * @data: Pointer to some data to pass to the callback
+ *
+ * The return value of the callback determines this function's behaviour. If 0
+ * is returned we continue to iterate over acpi_dep_list. If a positive value
+ * is returned then the loop is broken but this function returns 0. If a
+ * negative value is returned by the callback then the loop is broken and that
+ * value is returned as the final error.
+ */
+static int acpi_walk_dep_device_list(acpi_handle handle,
+ int (*callback)(struct acpi_dep_data *, void *),
+ void *data)
+{
+ struct acpi_dep_data *dep, *tmp;
+ int ret = 0;
+
mutex_lock(&acpi_dep_list_lock);
list_for_each_entry_safe(dep, tmp, &acpi_dep_list, node) {
if (dep->supplier == handle) {
- acpi_bus_get_device(dep->consumer, &adev);
-
- if (adev) {
- adev->dep_unmet--;
- if (!adev->dep_unmet)
- acpi_bus_attach(adev, true);
- }
-
- list_del(&dep->node);
- kfree(dep);
+ ret = callback(dep, data);
+ if (ret)
+ break;
}
}
mutex_unlock(&acpi_dep_list_lock);
+
+ return ret > 0 ? 0 : ret;
+}
+
+/**
+ * acpi_dev_clear_dependencies - Inform consumers that the device is now active
+ * @supplier: Pointer to the supplier &struct acpi_device
+ *
+ * Clear dependencies on the given device.
+ */
+void acpi_dev_clear_dependencies(struct acpi_device *supplier)
+{
+ acpi_walk_dep_device_list(supplier->handle, acpi_scan_clear_dep, NULL);
+}
+EXPORT_SYMBOL_GPL(acpi_dev_clear_dependencies);
+
+/**
+ * acpi_dev_get_first_consumer_dev - Return ACPI device dependent on @supplier
+ * @supplier: Pointer to the dependee device
+ *
+ * Returns the first &struct acpi_device which declares itself dependent on
+ * @supplier via the _DEP buffer, parsed from the acpi_dep_list.
+ *
+ * The caller is responsible for putting the reference to adev when it is no
+ * longer needed.
+ */
+struct acpi_device *acpi_dev_get_first_consumer_dev(struct acpi_device *supplier)
+{
+ struct acpi_device *adev = NULL;
+
+ acpi_walk_dep_device_list(supplier->handle,
+ acpi_dev_get_first_consumer_dev_cb, &adev);
+
+ return adev;
}
-EXPORT_SYMBOL_GPL(acpi_walk_dep_device_list);
+EXPORT_SYMBOL_GPL(acpi_dev_get_first_consumer_dev);
/**
* acpi_bus_scan - Add ACPI device node objects in a given namespace scope.
@@ -2223,7 +2423,7 @@ int acpi_bus_register_early_device(int type)
struct acpi_device *device = NULL;
int result;
- result = acpi_add_single_object(&device, NULL, type);
+ result = acpi_add_single_object(&device, NULL, type, false);
if (result)
return result;
@@ -2243,7 +2443,7 @@ static int acpi_bus_scan_fixed(void)
struct acpi_device *device = NULL;
result = acpi_add_single_object(&device, NULL,
- ACPI_BUS_TYPE_POWER_BUTTON);
+ ACPI_BUS_TYPE_POWER_BUTTON, false);
if (result)
return result;
@@ -2259,7 +2459,7 @@ static int acpi_bus_scan_fixed(void)
struct acpi_device *device = NULL;
result = acpi_add_single_object(&device, NULL,
- ACPI_BUS_TYPE_SLEEP_BUTTON);
+ ACPI_BUS_TYPE_SLEEP_BUTTON, false);
if (result)
return result;
@@ -2278,7 +2478,7 @@ static void __init acpi_get_spcr_uart_addr(void)
status = acpi_get_table(ACPI_SIG_SPCR, 0,
(struct acpi_table_header **)&spcr_ptr);
if (ACPI_FAILURE(status)) {
- pr_warn(PREFIX "STAO table present, but SPCR is missing\n");
+ pr_warn("STAO table present, but SPCR is missing\n");
return;
}
@@ -2319,7 +2519,7 @@ int __init acpi_scan_init(void)
(struct acpi_table_header **)&stao_ptr);
if (ACPI_SUCCESS(status)) {
if (stao_ptr->header.length > sizeof(struct acpi_table_stao))
- pr_info(PREFIX "STAO Name List not yet supported.\n");
+ pr_info("STAO Name List not yet supported.\n");
if (stao_ptr->ignore_uart)
acpi_get_spcr_uart_addr();
@@ -2360,7 +2560,7 @@ int __init acpi_scan_init(void)
}
}
- acpi_turn_off_unused_power_resources(true);
+ acpi_turn_off_unused_power_resources();
acpi_scan_initialized = true;
@@ -2408,46 +2608,28 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
return count;
}
-struct acpi_table_events_work {
- struct work_struct work;
- void *table;
- u32 event;
-};
-
static void acpi_table_events_fn(struct work_struct *work)
{
- struct acpi_table_events_work *tew;
-
- tew = container_of(work, struct acpi_table_events_work, work);
+ acpi_scan_lock_acquire();
+ acpi_bus_scan(ACPI_ROOT_OBJECT);
+ acpi_scan_lock_release();
- if (tew->event == ACPI_TABLE_EVENT_LOAD) {
- acpi_scan_lock_acquire();
- acpi_bus_scan(ACPI_ROOT_OBJECT);
- acpi_scan_lock_release();
- }
-
- kfree(tew);
+ kfree(work);
}
-void acpi_scan_table_handler(u32 event, void *table, void *context)
+void acpi_scan_table_notify(void)
{
- struct acpi_table_events_work *tew;
+ struct work_struct *work;
if (!acpi_scan_initialized)
return;
- if (event != ACPI_TABLE_EVENT_LOAD)
+ work = kmalloc(sizeof(*work), GFP_KERNEL);
+ if (!work)
return;
- tew = kmalloc(sizeof(*tew), GFP_KERNEL);
- if (!tew)
- return;
-
- INIT_WORK(&tew->work, acpi_table_events_fn);
- tew->table = table;
- tew->event = event;
-
- schedule_work(&tew->work);
+ INIT_WORK(work, acpi_table_events_fn);
+ schedule_work(work);
}
int acpi_reconfig_notifier_register(struct notifier_block *nb)
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 3bb2adef8490..3023224515ab 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -8,6 +8,8 @@
* Copyright (c) 2003 Open Source Development Lab
*/
+#define pr_fmt(fmt) "ACPI: PM: " fmt
+
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/dmi.h>
@@ -41,7 +43,7 @@ static void acpi_sleep_tts_switch(u32 acpi_state)
* OS can't evaluate the _TTS object correctly. Some warning
* message will be printed. But it won't break anything.
*/
- printk(KERN_NOTICE "Failure in evaluating _TTS object\n");
+ pr_notice("Failure in evaluating _TTS object\n");
}
}
@@ -73,8 +75,7 @@ static int acpi_sleep_prepare(u32 acpi_state)
}
ACPI_FLUSH_CPU_CACHE();
#endif
- printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n",
- acpi_state);
+ pr_info("Preparing to enter system sleep state S%d\n", acpi_state);
acpi_enable_wakeup_devices(acpi_state);
acpi_enter_sleep_state_prep(acpi_state);
return 0;
@@ -406,7 +407,7 @@ static int acpi_pm_freeze(void)
}
/**
- * acpi_pre_suspend - Enable wakeup devices, "freeze" EC and save NVS.
+ * acpi_pm_pre_suspend - Enable wakeup devices, "freeze" EC and save NVS.
*/
static int acpi_pm_pre_suspend(void)
{
@@ -459,8 +460,7 @@ static void acpi_pm_finish(void)
if (acpi_state == ACPI_STATE_S0)
return;
- printk(KERN_INFO PREFIX "Waking up from system sleep state S%d\n",
- acpi_state);
+ pr_info("Waking up from system sleep state S%d\n", acpi_state);
acpi_disable_wakeup_devices(acpi_state);
acpi_leave_sleep_state(acpi_state);
@@ -504,7 +504,7 @@ static void acpi_pm_start(u32 acpi_state)
*/
static void acpi_pm_end(void)
{
- acpi_turn_off_unused_power_resources(false);
+ acpi_turn_off_unused_power_resources();
acpi_scan_lock_release();
/*
* This is necessary in case acpi_pm_finish() is not called during a
@@ -581,7 +581,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
error = acpi_suspend_lowlevel();
if (error)
return error;
- pr_info(PREFIX "Low-level resume complete\n");
+ pr_info("Low-level resume complete\n");
pm_set_resume_via_firmware();
break;
}
@@ -921,7 +921,7 @@ static void acpi_hibernation_leave(void)
acpi_leave_sleep_state_prep(ACPI_STATE_S4);
/* Check the hardware signature */
if (facs && s4_hardware_signature != facs->hardware_signature)
- pr_crit("ACPI: Hardware changed while hibernated, success doubtful!\n");
+ pr_crit("Hardware changed while hibernated, success doubtful!\n");
/* Restore the NVS memory area */
suspend_nvs_restore();
/* Allow EC transactions to happen. */
@@ -1027,7 +1027,7 @@ static void acpi_power_off_prepare(void)
static void acpi_power_off(void)
{
/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
- printk(KERN_DEBUG "%s called\n", __func__);
+ pr_debug("%s called\n", __func__);
local_irq_disable();
acpi_enter_sleep_state(ACPI_STATE_S5);
}
@@ -1059,7 +1059,7 @@ int __init acpi_sleep_init(void)
if (sleep_states[i])
pos += sprintf(pos, " S%d", i);
}
- pr_info(PREFIX "(supports%s)\n", supported);
+ pr_info("(supports%s)\n", supported);
/*
* Register the tts_notifier to reboot notifier list so that the _TTS
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index d25927195d6d..00c0ebaab29f 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -5,10 +5,11 @@
#define pr_fmt(fmt) "ACPI: " fmt
+#include <linux/acpi.h>
+#include <linux/bitmap.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
-#include <linux/acpi.h>
#include "internal.h"
@@ -254,16 +255,12 @@ static int param_get_trace_state(char *buffer, const struct kernel_param *kp)
{
if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED))
return sprintf(buffer, "disable\n");
- else {
- if (acpi_gbl_trace_method_name) {
- if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT)
- return sprintf(buffer, "method-once\n");
- else
- return sprintf(buffer, "method\n");
- } else
- return sprintf(buffer, "enable\n");
- }
- return 0;
+ if (!acpi_gbl_trace_method_name)
+ return sprintf(buffer, "enable\n");
+ if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT)
+ return sprintf(buffer, "method-once\n");
+ else
+ return sprintf(buffer, "method\n");
}
module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
@@ -359,8 +356,7 @@ static int acpi_table_attr_init(struct kobject *tables_obj,
}
table_attr->instance++;
if (table_attr->instance > ACPI_MAX_TABLE_INSTANCES) {
- pr_warn("%4.4s: too many table instances\n",
- table_attr->name);
+ pr_warn("%4.4s: too many table instances\n", table_attr->name);
return -ERANGE;
}
@@ -388,8 +384,7 @@ acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context)
switch (event) {
case ACPI_TABLE_EVENT_INSTALL:
- table_attr =
- kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL);
+ table_attr = kzalloc(sizeof(*table_attr), GFP_KERNEL);
if (!table_attr)
return AE_NO_MEMORY;
@@ -420,7 +415,7 @@ static ssize_t acpi_data_show(struct file *filp, struct kobject *kobj,
loff_t offset, size_t count)
{
struct acpi_data_attr *data_attr;
- void __iomem *base;
+ void *base;
ssize_t rc;
data_attr = container_of(bin_attr, struct acpi_data_attr, attr);
@@ -582,8 +577,6 @@ static void delete_gpe_attr_array(void)
kfree(counter_attrs);
}
kfree(all_attrs);
-
- return;
}
static void gpe_count(u32 gpe_number)
@@ -598,8 +591,6 @@ static void gpe_count(u32 gpe_number)
else
all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS +
COUNT_ERROR].count++;
-
- return;
}
static void fixed_event_count(u32 event_number)
@@ -612,8 +603,6 @@ static void fixed_event_count(u32 event_number)
else
all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS +
COUNT_ERROR].count++;
-
- return;
}
static void acpi_global_event_handler(u32 event_type, acpi_handle device,
@@ -737,8 +726,7 @@ static ssize_t counter_set(struct kobject *kobj,
goto end;
if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER)) {
- printk(KERN_WARNING PREFIX
- "Can not change Invalid GPE/Fixed Event status\n");
+ pr_warn("Can not change Invalid GPE/Fixed Event status\n");
return -EINVAL;
}
@@ -796,6 +784,7 @@ end:
* the GPE flooding for GPE 00, they need to specify the following boot
* parameter:
* acpi_mask_gpe=0x00
+ * Note, the parameter can be a list (see bitmap_parselist() for the details).
* The masking status can be modified by the following runtime controlling
* interface:
* echo unmask > /sys/firmware/acpi/interrupts/gpe00
@@ -805,11 +794,16 @@ static DECLARE_BITMAP(acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) __initdata;
static int __init acpi_gpe_set_masked_gpes(char *val)
{
+ int ret;
u8 gpe;
- if (kstrtou8(val, 0, &gpe))
- return -EINVAL;
- set_bit(gpe, acpi_masked_gpes_map);
+ ret = kstrtou8(val, 0, &gpe);
+ if (ret) {
+ ret = bitmap_parselist(val, acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX);
+ if (ret)
+ return ret;
+ } else
+ set_bit(gpe, acpi_masked_gpes_map);
return 1;
}
@@ -841,13 +835,11 @@ void acpi_irq_stats_init(void)
num_gpes = acpi_current_gpe_count;
num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA;
- all_attrs = kcalloc(num_counters + 1, sizeof(struct attribute *),
- GFP_KERNEL);
+ all_attrs = kcalloc(num_counters + 1, sizeof(*all_attrs), GFP_KERNEL);
if (all_attrs == NULL)
return;
- all_counters = kcalloc(num_counters, sizeof(struct event_counter),
- GFP_KERNEL);
+ all_counters = kcalloc(num_counters, sizeof(*all_counters), GFP_KERNEL);
if (all_counters == NULL)
goto fail;
@@ -855,8 +847,7 @@ void acpi_irq_stats_init(void)
if (ACPI_FAILURE(status))
goto fail;
- counter_attrs = kcalloc(num_counters, sizeof(struct kobj_attribute),
- GFP_KERNEL);
+ counter_attrs = kcalloc(num_counters, sizeof(*counter_attrs), GFP_KERNEL);
if (counter_attrs == NULL)
goto fail;
@@ -906,7 +897,6 @@ void acpi_irq_stats_init(void)
fail:
delete_gpe_attr_array();
- return;
}
static void __exit interrupt_stats_exit(void)
@@ -914,31 +904,24 @@ static void __exit interrupt_stats_exit(void)
sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group);
delete_gpe_attr_array();
-
- return;
}
-static ssize_t
-acpi_show_profile(struct kobject *kobj, struct kobj_attribute *attr,
- char *buf)
+static ssize_t pm_profile_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", acpi_gbl_FADT.preferred_profile);
}
-static const struct kobj_attribute pm_profile_attr =
- __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL);
+static const struct kobj_attribute pm_profile_attr = __ATTR_RO(pm_profile);
-static ssize_t hotplug_enabled_show(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf)
+static ssize_t enabled_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
return sprintf(buf, "%d\n", hotplug->enabled);
}
-static ssize_t hotplug_enabled_store(struct kobject *kobj,
- struct kobj_attribute *attr,
- const char *buf, size_t size)
+static ssize_t enabled_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t size)
{
struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
unsigned int val;
@@ -950,9 +933,7 @@ static ssize_t hotplug_enabled_store(struct kobject *kobj,
return size;
}
-static struct kobj_attribute hotplug_enabled_attr =
- __ATTR(enabled, S_IRUGO | S_IWUSR, hotplug_enabled_show,
- hotplug_enabled_store);
+static struct kobj_attribute hotplug_enabled_attr = __ATTR_RW(enabled);
static struct attribute *hotplug_profile_attrs[] = {
&hotplug_enabled_attr.attr,
@@ -983,7 +964,7 @@ void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
return;
err_out:
- pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name);
+ pr_err("Unable to add hotplug profile '%s'\n", name);
}
static ssize_t force_remove_show(struct kobject *kobj,
@@ -1010,9 +991,7 @@ static ssize_t force_remove_store(struct kobject *kobj,
return size;
}
-static const struct kobj_attribute force_remove_attr =
- __ATTR(force_remove, S_IRUGO | S_IWUSR, force_remove_show,
- force_remove_store);
+static const struct kobj_attribute force_remove_attr = __ATTR_RW(force_remove);
int __init acpi_sysfs_init(void)
{
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 9d581045acff..a37a1532a575 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -39,6 +39,7 @@ static int acpi_apic_instance __initdata;
enum acpi_subtable_type {
ACPI_SUBTABLE_COMMON,
ACPI_SUBTABLE_HMAT,
+ ACPI_SUBTABLE_PRMT,
};
struct acpi_subtable_entry {
@@ -222,6 +223,8 @@ acpi_get_entry_type(struct acpi_subtable_entry *entry)
return entry->hdr->common.type;
case ACPI_SUBTABLE_HMAT:
return entry->hdr->hmat.type;
+ case ACPI_SUBTABLE_PRMT:
+ return 0;
}
return 0;
}
@@ -234,6 +237,8 @@ acpi_get_entry_length(struct acpi_subtable_entry *entry)
return entry->hdr->common.length;
case ACPI_SUBTABLE_HMAT:
return entry->hdr->hmat.length;
+ case ACPI_SUBTABLE_PRMT:
+ return entry->hdr->prmt.length;
}
return 0;
}
@@ -246,6 +251,8 @@ acpi_get_subtable_header_length(struct acpi_subtable_entry *entry)
return sizeof(entry->hdr->common);
case ACPI_SUBTABLE_HMAT:
return sizeof(entry->hdr->hmat);
+ case ACPI_SUBTABLE_PRMT:
+ return sizeof(entry->hdr->prmt);
}
return 0;
}
@@ -255,6 +262,8 @@ acpi_get_subtable_type(char *id)
{
if (strncmp(id, ACPI_SIG_HMAT, 4) == 0)
return ACPI_SUBTABLE_HMAT;
+ if (strncmp(id, ACPI_SIG_PRMT, 4) == 0)
+ return ACPI_SUBTABLE_PRMT;
return ACPI_SUBTABLE_COMMON;
}
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 3b54b8fd7396..e7ddd281afff 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -277,6 +277,20 @@ acpi_evaluate_integer(acpi_handle handle,
EXPORT_SYMBOL(acpi_evaluate_integer);
+int acpi_get_local_address(acpi_handle handle, u32 *addr)
+{
+ unsigned long long adr;
+ acpi_status status;
+
+ status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+ if (ACPI_FAILURE(status))
+ return -ENODATA;
+
+ *addr = (u32)adr;
+ return 0;
+}
+EXPORT_SYMBOL(acpi_get_local_address);
+
acpi_status
acpi_evaluate_reference(acpi_handle handle,
acpi_string pathname,
diff --git a/drivers/acpi/viot.c b/drivers/acpi/viot.c
new file mode 100644
index 000000000000..d2256326c73a
--- /dev/null
+++ b/drivers/acpi/viot.c
@@ -0,0 +1,366 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Virtual I/O topology
+ *
+ * The Virtual I/O Translation Table (VIOT) describes the topology of
+ * para-virtual IOMMUs and the endpoints they manage. The OS uses it to
+ * initialize devices in the right order, preventing endpoints from issuing DMA
+ * before their IOMMU is ready.
+ *
+ * When binding a driver to a device, before calling the device driver's probe()
+ * method, the driver infrastructure calls dma_configure(). At that point the
+ * VIOT driver looks for an IOMMU associated to the device in the VIOT table.
+ * If an IOMMU exists and has been initialized, the VIOT driver initializes the
+ * device's IOMMU fwspec, allowing the DMA infrastructure to invoke the IOMMU
+ * ops when the device driver configures DMA mappings. If an IOMMU exists and
+ * hasn't yet been initialized, VIOT returns -EPROBE_DEFER to postpone probing
+ * the device until the IOMMU is available.
+ */
+#define pr_fmt(fmt) "ACPI: VIOT: " fmt
+
+#include <linux/acpi_viot.h>
+#include <linux/dma-iommu.h>
+#include <linux/fwnode.h>
+#include <linux/iommu.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+struct viot_iommu {
+ /* Node offset within the table */
+ unsigned int offset;
+ struct fwnode_handle *fwnode;
+ struct list_head list;
+};
+
+struct viot_endpoint {
+ union {
+ /* PCI range */
+ struct {
+ u16 segment_start;
+ u16 segment_end;
+ u16 bdf_start;
+ u16 bdf_end;
+ };
+ /* MMIO */
+ u64 address;
+ };
+ u32 endpoint_id;
+ struct viot_iommu *viommu;
+ struct list_head list;
+};
+
+static struct acpi_table_viot *viot;
+static LIST_HEAD(viot_iommus);
+static LIST_HEAD(viot_pci_ranges);
+static LIST_HEAD(viot_mmio_endpoints);
+
+static int __init viot_check_bounds(const struct acpi_viot_header *hdr)
+{
+ struct acpi_viot_header *start, *end, *hdr_end;
+
+ start = ACPI_ADD_PTR(struct acpi_viot_header, viot,
+ max_t(size_t, sizeof(*viot), viot->node_offset));
+ end = ACPI_ADD_PTR(struct acpi_viot_header, viot, viot->header.length);
+ hdr_end = ACPI_ADD_PTR(struct acpi_viot_header, hdr, sizeof(*hdr));
+
+ if (hdr < start || hdr_end > end) {
+ pr_err(FW_BUG "Node pointer overflows\n");
+ return -EOVERFLOW;
+ }
+ if (hdr->length < sizeof(*hdr)) {
+ pr_err(FW_BUG "Empty node\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int __init viot_get_pci_iommu_fwnode(struct viot_iommu *viommu,
+ u16 segment, u16 bdf)
+{
+ struct pci_dev *pdev;
+ struct fwnode_handle *fwnode;
+
+ pdev = pci_get_domain_bus_and_slot(segment, PCI_BUS_NUM(bdf),
+ bdf & 0xff);
+ if (!pdev) {
+ pr_err("Could not find PCI IOMMU\n");
+ return -ENODEV;
+ }
+
+ fwnode = pdev->dev.fwnode;
+ if (!fwnode) {
+ /*
+ * PCI devices aren't necessarily described by ACPI. Create a
+ * fwnode so the IOMMU subsystem can identify this device.
+ */
+ fwnode = acpi_alloc_fwnode_static();
+ if (!fwnode) {
+ pci_dev_put(pdev);
+ return -ENOMEM;
+ }
+ set_primary_fwnode(&pdev->dev, fwnode);
+ }
+ viommu->fwnode = pdev->dev.fwnode;
+ pci_dev_put(pdev);
+ return 0;
+}
+
+static int __init viot_get_mmio_iommu_fwnode(struct viot_iommu *viommu,
+ u64 address)
+{
+ struct acpi_device *adev;
+ struct resource res = {
+ .start = address,
+ .end = address,
+ .flags = IORESOURCE_MEM,
+ };
+
+ adev = acpi_resource_consumer(&res);
+ if (!adev) {
+ pr_err("Could not find MMIO IOMMU\n");
+ return -EINVAL;
+ }
+ viommu->fwnode = &adev->fwnode;
+ return 0;
+}
+
+static struct viot_iommu * __init viot_get_iommu(unsigned int offset)
+{
+ int ret;
+ struct viot_iommu *viommu;
+ struct acpi_viot_header *hdr = ACPI_ADD_PTR(struct acpi_viot_header,
+ viot, offset);
+ union {
+ struct acpi_viot_virtio_iommu_pci pci;
+ struct acpi_viot_virtio_iommu_mmio mmio;
+ } *node = (void *)hdr;
+
+ list_for_each_entry(viommu, &viot_iommus, list)
+ if (viommu->offset == offset)
+ return viommu;
+
+ if (viot_check_bounds(hdr))
+ return NULL;
+
+ viommu = kzalloc(sizeof(*viommu), GFP_KERNEL);
+ if (!viommu)
+ return NULL;
+
+ viommu->offset = offset;
+ switch (hdr->type) {
+ case ACPI_VIOT_NODE_VIRTIO_IOMMU_PCI:
+ if (hdr->length < sizeof(node->pci))
+ goto err_free;
+
+ ret = viot_get_pci_iommu_fwnode(viommu, node->pci.segment,
+ node->pci.bdf);
+ break;
+ case ACPI_VIOT_NODE_VIRTIO_IOMMU_MMIO:
+ if (hdr->length < sizeof(node->mmio))
+ goto err_free;
+
+ ret = viot_get_mmio_iommu_fwnode(viommu,
+ node->mmio.base_address);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (ret)
+ goto err_free;
+
+ list_add(&viommu->list, &viot_iommus);
+ return viommu;
+
+err_free:
+ kfree(viommu);
+ return NULL;
+}
+
+static int __init viot_parse_node(const struct acpi_viot_header *hdr)
+{
+ int ret = -EINVAL;
+ struct list_head *list;
+ struct viot_endpoint *ep;
+ union {
+ struct acpi_viot_mmio mmio;
+ struct acpi_viot_pci_range pci;
+ } *node = (void *)hdr;
+
+ if (viot_check_bounds(hdr))
+ return -EINVAL;
+
+ if (hdr->type == ACPI_VIOT_NODE_VIRTIO_IOMMU_PCI ||
+ hdr->type == ACPI_VIOT_NODE_VIRTIO_IOMMU_MMIO)
+ return 0;
+
+ ep = kzalloc(sizeof(*ep), GFP_KERNEL);
+ if (!ep)
+ return -ENOMEM;
+
+ switch (hdr->type) {
+ case ACPI_VIOT_NODE_PCI_RANGE:
+ if (hdr->length < sizeof(node->pci)) {
+ pr_err(FW_BUG "Invalid PCI node size\n");
+ goto err_free;
+ }
+
+ ep->segment_start = node->pci.segment_start;
+ ep->segment_end = node->pci.segment_end;
+ ep->bdf_start = node->pci.bdf_start;
+ ep->bdf_end = node->pci.bdf_end;
+ ep->endpoint_id = node->pci.endpoint_start;
+ ep->viommu = viot_get_iommu(node->pci.output_node);
+ list = &viot_pci_ranges;
+ break;
+ case ACPI_VIOT_NODE_MMIO:
+ if (hdr->length < sizeof(node->mmio)) {
+ pr_err(FW_BUG "Invalid MMIO node size\n");
+ goto err_free;
+ }
+
+ ep->address = node->mmio.base_address;
+ ep->endpoint_id = node->mmio.endpoint;
+ ep->viommu = viot_get_iommu(node->mmio.output_node);
+ list = &viot_mmio_endpoints;
+ break;
+ default:
+ pr_warn("Unsupported node %x\n", hdr->type);
+ ret = 0;
+ goto err_free;
+ }
+
+ if (!ep->viommu) {
+ pr_warn("No IOMMU node found\n");
+ /*
+ * A future version of the table may use the node for other
+ * purposes. Keep parsing.
+ */
+ ret = 0;
+ goto err_free;
+ }
+
+ list_add(&ep->list, list);
+ return 0;
+
+err_free:
+ kfree(ep);
+ return ret;
+}
+
+/**
+ * acpi_viot_init - Parse the VIOT table
+ *
+ * Parse the VIOT table, prepare the list of endpoints to be used during DMA
+ * setup of devices.
+ */
+void __init acpi_viot_init(void)
+{
+ int i;
+ acpi_status status;
+ struct acpi_table_header *hdr;
+ struct acpi_viot_header *node;
+
+ status = acpi_get_table(ACPI_SIG_VIOT, 0, &hdr);
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND) {
+ const char *msg = acpi_format_exception(status);
+
+ pr_err("Failed to get table, %s\n", msg);
+ }
+ return;
+ }
+
+ viot = (void *)hdr;
+
+ node = ACPI_ADD_PTR(struct acpi_viot_header, viot, viot->node_offset);
+ for (i = 0; i < viot->node_count; i++) {
+ if (viot_parse_node(node))
+ return;
+
+ node = ACPI_ADD_PTR(struct acpi_viot_header, node,
+ node->length);
+ }
+
+ acpi_put_table(hdr);
+}
+
+static int viot_dev_iommu_init(struct device *dev, struct viot_iommu *viommu,
+ u32 epid)
+{
+ const struct iommu_ops *ops;
+
+ if (!viommu)
+ return -ENODEV;
+
+ /* We're not translating ourself */
+ if (viommu->fwnode == dev->fwnode)
+ return -EINVAL;
+
+ ops = iommu_ops_from_fwnode(viommu->fwnode);
+ if (!ops)
+ return IS_ENABLED(CONFIG_VIRTIO_IOMMU) ?
+ -EPROBE_DEFER : -ENODEV;
+
+ return acpi_iommu_fwspec_init(dev, epid, viommu->fwnode, ops);
+}
+
+static int viot_pci_dev_iommu_init(struct pci_dev *pdev, u16 dev_id, void *data)
+{
+ u32 epid;
+ struct viot_endpoint *ep;
+ u32 domain_nr = pci_domain_nr(pdev->bus);
+
+ list_for_each_entry(ep, &viot_pci_ranges, list) {
+ if (domain_nr >= ep->segment_start &&
+ domain_nr <= ep->segment_end &&
+ dev_id >= ep->bdf_start &&
+ dev_id <= ep->bdf_end) {
+ epid = ((domain_nr - ep->segment_start) << 16) +
+ dev_id - ep->bdf_start + ep->endpoint_id;
+
+ /*
+ * If we found a PCI range managed by the viommu, we're
+ * the one that has to request ACS.
+ */
+ pci_request_acs();
+
+ return viot_dev_iommu_init(&pdev->dev, ep->viommu,
+ epid);
+ }
+ }
+ return -ENODEV;
+}
+
+static int viot_mmio_dev_iommu_init(struct platform_device *pdev)
+{
+ struct resource *mem;
+ struct viot_endpoint *ep;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem)
+ return -ENODEV;
+
+ list_for_each_entry(ep, &viot_mmio_endpoints, list) {
+ if (ep->address == mem->start)
+ return viot_dev_iommu_init(&pdev->dev, ep->viommu,
+ ep->endpoint_id);
+ }
+ return -ENODEV;
+}
+
+/**
+ * viot_iommu_configure - Setup IOMMU ops for an endpoint described by VIOT
+ * @dev: the endpoint
+ *
+ * Return: 0 on success, <0 on failure
+ */
+int viot_iommu_configure(struct device *dev)
+{
+ if (dev_is_pci(dev))
+ return pci_for_each_dma_alias(to_pci_dev(dev),
+ viot_pci_dev_iommu_init, NULL);
+ else if (dev_is_platform(dev))
+ return viot_mmio_dev_iommu_init(to_platform_device(dev));
+ return -ENODEV;
+}
diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
index 2b69536cdccb..1c507804fb10 100644
--- a/drivers/acpi/x86/s2idle.c
+++ b/drivers/acpi/x86/s2idle.c
@@ -32,6 +32,9 @@ static const struct acpi_device_id lps0_device_ids[] = {
{"", },
};
+/* Microsoft platform agnostic UUID */
+#define ACPI_LPS0_DSM_UUID_MICROSOFT "11e00d56-ce64-47ce-837b-1f898f9aa461"
+
#define ACPI_LPS0_DSM_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66"
#define ACPI_LPS0_GET_DEVICE_CONSTRAINTS 1
@@ -39,15 +42,22 @@ static const struct acpi_device_id lps0_device_ids[] = {
#define ACPI_LPS0_SCREEN_ON 4
#define ACPI_LPS0_ENTRY 5
#define ACPI_LPS0_EXIT 6
+#define ACPI_LPS0_MS_ENTRY 7
+#define ACPI_LPS0_MS_EXIT 8
/* AMD */
#define ACPI_LPS0_DSM_UUID_AMD "e3f32452-febc-43ce-9039-932122d37721"
+#define ACPI_LPS0_ENTRY_AMD 2
+#define ACPI_LPS0_EXIT_AMD 3
#define ACPI_LPS0_SCREEN_OFF_AMD 4
#define ACPI_LPS0_SCREEN_ON_AMD 5
static acpi_handle lps0_device_handle;
static guid_t lps0_dsm_guid;
-static char lps0_dsm_func_mask;
+static int lps0_dsm_func_mask;
+
+static guid_t lps0_dsm_guid_microsoft;
+static int lps0_dsm_func_mask_microsoft;
/* Device constraint entry structure */
struct lpi_device_info {
@@ -68,15 +78,7 @@ struct lpi_constraints {
int min_dstate;
};
-/* AMD */
-/* Device constraint entry structure */
-struct lpi_device_info_amd {
- int revision;
- int count;
- union acpi_object *package;
-};
-
-/* Constraint package structure */
+/* AMD Constraint package structure */
struct lpi_device_constraint_amd {
char *name;
int enabled;
@@ -94,15 +96,15 @@ static void lpi_device_get_constraints_amd(void)
int i, j, k;
out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid,
- 1, ACPI_LPS0_GET_DEVICE_CONSTRAINTS,
+ rev_id, ACPI_LPS0_GET_DEVICE_CONSTRAINTS,
NULL, ACPI_TYPE_PACKAGE);
- if (!out_obj)
- return;
-
acpi_handle_debug(lps0_device_handle, "_DSM function 1 eval %s\n",
out_obj ? "successful" : "failed");
+ if (!out_obj)
+ return;
+
for (i = 0; i < out_obj->package.count; i++) {
union acpi_object *package = &out_obj->package.elements[i];
@@ -315,14 +317,15 @@ static void lpi_check_constraints(void)
}
}
-static void acpi_sleep_run_lps0_dsm(unsigned int func)
+static void acpi_sleep_run_lps0_dsm(unsigned int func, unsigned int func_mask, guid_t dsm_guid)
{
union acpi_object *out_obj;
- if (!(lps0_dsm_func_mask & (1 << func)))
+ if (!(func_mask & (1 << func)))
return;
- out_obj = acpi_evaluate_dsm(lps0_device_handle, &lps0_dsm_guid, rev_id, func, NULL);
+ out_obj = acpi_evaluate_dsm(lps0_device_handle, &dsm_guid,
+ rev_id, func, NULL);
ACPI_FREE(out_obj);
acpi_handle_debug(lps0_device_handle, "_DSM function %u evaluation %s\n",
@@ -334,11 +337,33 @@ static bool acpi_s2idle_vendor_amd(void)
return boot_cpu_data.x86_vendor == X86_VENDOR_AMD;
}
+static int validate_dsm(acpi_handle handle, const char *uuid, int rev, guid_t *dsm_guid)
+{
+ union acpi_object *obj;
+ int ret = -EINVAL;
+
+ guid_parse(uuid, dsm_guid);
+ obj = acpi_evaluate_dsm(handle, dsm_guid, rev, 0, NULL);
+
+ /* Check if the _DSM is present and as expected. */
+ if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length == 0 ||
+ obj->buffer.length > sizeof(u32)) {
+ acpi_handle_debug(handle,
+ "_DSM UUID %s rev %d function 0 evaluation failed\n", uuid, rev);
+ goto out;
+ }
+
+ ret = *(int *)obj->buffer.pointer;
+ acpi_handle_debug(handle, "_DSM UUID %s rev %d function mask: 0x%x\n", uuid, rev, ret);
+
+out:
+ ACPI_FREE(obj);
+ return ret;
+}
+
static int lps0_device_attach(struct acpi_device *adev,
const struct acpi_device_id *not_used)
{
- union acpi_object *out_obj;
-
if (lps0_device_handle)
return 0;
@@ -346,28 +371,36 @@ static int lps0_device_attach(struct acpi_device *adev,
return 0;
if (acpi_s2idle_vendor_amd()) {
- guid_parse(ACPI_LPS0_DSM_UUID_AMD, &lps0_dsm_guid);
- out_obj = acpi_evaluate_dsm(adev->handle, &lps0_dsm_guid, 0, 0, NULL);
+ /* AMD0004, AMDI0005:
+ * - Should use rev_id 0x0
+ * - function mask > 0x3: Should use AMD method, but has off by one bug
+ * - function mask = 0x3: Should use Microsoft method
+ * AMDI0006:
+ * - should use rev_id 0x0
+ * - function mask = 0x3: Should use Microsoft method
+ */
+ const char *hid = acpi_device_hid(adev);
rev_id = 0;
+ lps0_dsm_func_mask = validate_dsm(adev->handle,
+ ACPI_LPS0_DSM_UUID_AMD, rev_id, &lps0_dsm_guid);
+ lps0_dsm_func_mask_microsoft = validate_dsm(adev->handle,
+ ACPI_LPS0_DSM_UUID_MICROSOFT, rev_id,
+ &lps0_dsm_guid_microsoft);
+ if (lps0_dsm_func_mask > 0x3 && (!strcmp(hid, "AMD0004") ||
+ !strcmp(hid, "AMDI0005"))) {
+ lps0_dsm_func_mask = (lps0_dsm_func_mask << 1) | 0x1;
+ acpi_handle_debug(adev->handle, "_DSM UUID %s: Adjusted function mask: 0x%x\n",
+ ACPI_LPS0_DSM_UUID_AMD, lps0_dsm_func_mask);
+ }
} else {
- guid_parse(ACPI_LPS0_DSM_UUID, &lps0_dsm_guid);
- out_obj = acpi_evaluate_dsm(adev->handle, &lps0_dsm_guid, 1, 0, NULL);
rev_id = 1;
+ lps0_dsm_func_mask = validate_dsm(adev->handle,
+ ACPI_LPS0_DSM_UUID, rev_id, &lps0_dsm_guid);
+ lps0_dsm_func_mask_microsoft = -EINVAL;
}
- /* Check if the _DSM is present and as expected. */
- if (!out_obj || out_obj->type != ACPI_TYPE_BUFFER) {
- acpi_handle_debug(adev->handle,
- "_DSM function 0 evaluation failed\n");
- return 0;
- }
-
- lps0_dsm_func_mask = *(char *)out_obj->buffer.pointer;
-
- ACPI_FREE(out_obj);
-
- acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n",
- lps0_dsm_func_mask);
+ if (lps0_dsm_func_mask < 0 && lps0_dsm_func_mask_microsoft < 0)
+ return 0; //function evaluation failed
lps0_device_handle = adev->handle;
@@ -384,11 +417,15 @@ static int lps0_device_attach(struct acpi_device *adev,
mem_sleep_current = PM_SUSPEND_TO_IDLE;
/*
- * Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the
- * EC GPE to be enabled while suspended for certain wakeup devices to
- * work, so mark it as wakeup-capable.
+ * Some Intel based LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U don't
+ * use intel-hid or intel-vbtn but require the EC GPE to be enabled while
+ * suspended for certain wakeup devices to work, so mark it as wakeup-capable.
+ *
+ * Only enable on !AMD as enabling this universally causes problems for a number
+ * of AMD based systems.
*/
- acpi_ec_mark_gpe_for_wake();
+ if (!acpi_s2idle_vendor_amd())
+ acpi_ec_mark_gpe_for_wake();
return 0;
}
@@ -406,11 +443,23 @@ int acpi_s2idle_prepare_late(void)
if (pm_debug_messages_on)
lpi_check_constraints();
- if (acpi_s2idle_vendor_amd()) {
- acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF_AMD);
+ if (lps0_dsm_func_mask_microsoft > 0) {
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
+ lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT,
+ lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
+ lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
+ } else if (acpi_s2idle_vendor_amd()) {
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF_AMD,
+ lps0_dsm_func_mask, lps0_dsm_guid);
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY_AMD,
+ lps0_dsm_func_mask, lps0_dsm_guid);
} else {
- acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF);
- acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY);
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
+ lps0_dsm_func_mask, lps0_dsm_guid);
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
+ lps0_dsm_func_mask, lps0_dsm_guid);
}
return 0;
@@ -421,11 +470,23 @@ void acpi_s2idle_restore_early(void)
if (!lps0_device_handle || sleep_no_lps0)
return;
- if (acpi_s2idle_vendor_amd()) {
- acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON_AMD);
+ if (lps0_dsm_func_mask_microsoft > 0) {
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
+ lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY,
+ lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
+ lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
+ } else if (acpi_s2idle_vendor_amd()) {
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT_AMD,
+ lps0_dsm_func_mask, lps0_dsm_guid);
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON_AMD,
+ lps0_dsm_func_mask, lps0_dsm_guid);
} else {
- acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT);
- acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON);
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
+ lps0_dsm_func_mask, lps0_dsm_guid);
+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
+ lps0_dsm_func_mask, lps0_dsm_guid);
}
}
diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c
index bdc1ba00aee9..f22f23933063 100644
--- a/drivers/acpi/x86/utils.c
+++ b/drivers/acpi/x86/utils.c
@@ -135,3 +135,28 @@ bool acpi_device_always_present(struct acpi_device *adev)
return ret;
}
+
+/*
+ * AMD systems from Renoir and Lucienne *require* that the NVME controller
+ * is put into D3 over a Modern Standby / suspend-to-idle cycle.
+ *
+ * This is "typically" accomplished using the `StorageD3Enable`
+ * property in the _DSD that is checked via the `acpi_storage_d3` function
+ * but this property was introduced after many of these systems launched
+ * and most OEM systems don't have it in their BIOS.
+ *
+ * The Microsoft documentation for StorageD3Enable mentioned that Windows has
+ * a hardcoded allowlist for D3 support, which was used for these platforms.
+ *
+ * This allows quirking on Linux in a similar fashion.
+ */
+static const struct x86_cpu_id storage_d3_cpu_ids[] = {
+ X86_MATCH_VENDOR_FAM_MODEL(AMD, 23, 96, NULL), /* Renoir */
+ X86_MATCH_VENDOR_FAM_MODEL(AMD, 23, 104, NULL), /* Lucienne */
+ {}
+};
+
+bool force_storage_d3(void)
+{
+ return x86_match_cpu(storage_d3_cpu_ids);
+}
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 030cb32da980..a7da8ea7b3ed 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -1015,11 +1015,11 @@ config PATA_CMD640_PCI
If unsure, say N.
config PATA_FALCON
- tristate "Atari Falcon PATA support"
- depends on M68K && ATARI
+ tristate "Atari Falcon and Q40/Q60 PATA support"
+ depends on M68K && (ATARI || Q40)
help
This option enables support for the on-board IDE
- interface on the Atari Falcon.
+ interface on the Atari Falcon and Q40/Q60.
If unsure, say N.
@@ -1058,7 +1058,7 @@ config PATA_ISAPNP
config PATA_IXP4XX_CF
tristate "IXP4XX Compact Flash support"
- depends on ARCH_IXP4XX
+ depends on ARCH_IXP4XX || COMPILE_TEST
help
This option enables support for a Compact Flash connected on
the ixp4xx expansion bus. This driver had been written for
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 33192a8f687d..186cbf90c8ea 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -446,6 +446,10 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
+ /* Dell S140/S150 */
+ { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_SUBVENDOR_ID_DELL, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
+
/* VIA */
{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index d1f284f0c83d..2e89499bd9c3 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -384,12 +384,15 @@ extern struct device_attribute *ahci_sdev_attrs[];
* for ATA_BASE_SHT
*/
#define AHCI_SHT(drv_name) \
- ATA_NCQ_SHT(drv_name), \
+ __ATA_BASE_SHT(drv_name), \
.can_queue = AHCI_MAX_CMDS, \
.sg_tablesize = AHCI_MAX_SG, \
.dma_boundary = AHCI_DMA_BOUNDARY, \
.shost_attrs = ahci_shost_attrs, \
- .sdev_attrs = ahci_sdev_attrs
+ .sdev_attrs = ahci_sdev_attrs, \
+ .change_queue_depth = ata_scsi_change_queue_depth, \
+ .tag_alloc_policy = BLK_TAG_ALLOC_RR, \
+ .slave_configure = ata_scsi_slave_config
extern struct ata_port_operations ahci_ops;
extern struct ata_port_operations ahci_platform_ops;
diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
index cb69b737cb49..56b695136977 100644
--- a/drivers/ata/ahci_sunxi.c
+++ b/drivers/ata/ahci_sunxi.c
@@ -200,7 +200,7 @@ static void ahci_sunxi_start_engine(struct ata_port *ap)
}
static const struct ata_port_info ahci_sunxi_port_info = {
- .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ | ATA_FLAG_NO_DIPM,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_platform_ops,
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index fd8b6febbf70..b9588c52815d 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -196,9 +196,7 @@ void ata_scsi_set_sense(struct ata_device *dev, struct scsi_cmnd *cmd,
if (!cmd)
return;
- cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
-
- scsi_build_sense_buffer(d_sense, cmd->sense_buffer, sk, asc, ascq);
+ scsi_build_sense(cmd, d_sense, sk, asc, ascq);
}
void ata_scsi_set_sense_information(struct ata_device *dev,
@@ -409,13 +407,16 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
cmd_result = scsi_execute(scsidev, scsi_cmd, data_dir, argbuf, argsize,
sensebuf, &sshdr, (10*HZ), 5, 0, 0, NULL);
- if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */
+ if (cmd_result < 0) {
+ rc = cmd_result;
+ goto error;
+ }
+ if (scsi_sense_valid(&sshdr)) {/* sense data available */
u8 *desc = sensebuf + 8;
- cmd_result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */
/* If we set cc then ATA pass-through will cause a
* check condition even if no error. Filter that. */
- if (cmd_result & SAM_STAT_CHECK_CONDITION) {
+ if (scsi_status_is_check_condition(cmd_result)) {
if (sshdr.sense_key == RECOVERED_ERROR &&
sshdr.asc == 0 && sshdr.ascq == 0x1d)
cmd_result &= ~SAM_STAT_CHECK_CONDITION;
@@ -490,9 +491,12 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
cmd_result = scsi_execute(scsidev, scsi_cmd, DMA_NONE, NULL, 0,
sensebuf, &sshdr, (10*HZ), 5, 0, 0, NULL);
- if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */
+ if (cmd_result < 0) {
+ rc = cmd_result;
+ goto error;
+ }
+ if (scsi_sense_valid(&sshdr)) {/* sense data available */
u8 *desc = sensebuf + 8;
- cmd_result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */
/* If we set cc then ATA pass-through will cause a
* check condition even if no error. Filter that. */
@@ -638,7 +642,7 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
if (cmd->request->rq_flags & RQF_QUIET)
qc->flags |= ATA_QCFLAG_QUIET;
} else {
- cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
+ cmd->result = (DID_OK << 16) | SAM_STAT_TASK_SET_FULL;
cmd->scsi_done(cmd);
}
@@ -858,8 +862,6 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc)
memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
- cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
-
/*
* Use ata_to_sense_error() to map status register bits
* onto sense key, asc & ascq.
@@ -874,8 +876,7 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc)
* ATA PASS-THROUGH INFORMATION AVAILABLE
* Always in descriptor format sense.
*/
- scsi_build_sense_buffer(1, cmd->sense_buffer,
- RECOVERED_ERROR, 0, 0x1D);
+ scsi_build_sense(cmd, 1, RECOVERED_ERROR, 0, 0x1D);
}
if ((cmd->sense_buffer[0] & 0x7f) >= 0x72) {
@@ -957,8 +958,6 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc)
memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
- cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
-
if (ata_dev_disabled(dev)) {
/* Device disabled after error recovery */
/* LOGICAL UNIT NOT READY, HARD RESET REQUIRED */
@@ -4196,7 +4195,6 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
case REQUEST_SENSE:
ata_scsi_set_sense(dev, cmd, 0, 0, 0);
- cmd->result = (DRIVER_SENSE << 24);
break;
/* if we reach this, then writeback caching is disabled,
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index d671d33ef287..c3a65ccd4b79 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -252,8 +252,9 @@ static void atiixp_bmdma_stop(struct ata_queued_cmd *qc)
}
static struct scsi_host_template atiixp_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
+ ATA_BASE_SHT(DRV_NAME),
.sg_tablesize = LIBATA_DUMB_MAX_PRD,
+ .dma_boundary = ATA_DMA_BOUNDARY,
};
static struct ata_port_operations atiixp_port_ops = {
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index d09d432d3c44..247c14702624 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -95,8 +95,9 @@ static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev)
}
static struct scsi_host_template cs5520_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
+ ATA_BASE_SHT(DRV_NAME),
.sg_tablesize = LIBATA_DUMB_MAX_PRD,
+ .dma_boundary = ATA_DMA_BOUNDARY,
};
static struct ata_port_operations cs5520_port_ops = {
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index a1b4aaccaa50..d5b7ac14e78f 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -147,8 +147,9 @@ static unsigned int cs5530_qc_issue(struct ata_queued_cmd *qc)
}
static struct scsi_host_template cs5530_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
+ ATA_BASE_SHT(DRV_NAME),
.sg_tablesize = LIBATA_DUMB_MAX_PRD,
+ .dma_boundary = ATA_DMA_BOUNDARY,
};
static struct ata_port_operations cs5530_port_ops = {
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index e1486fe298ae..5b3a7a8ebef6 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -41,6 +41,10 @@ enum {
CY82_INDEX_TIMEOUT = 0x32
};
+static bool enable_dma = true;
+module_param(enable_dma, bool, 0);
+MODULE_PARM_DESC(enable_dma, "Enable bus master DMA operations");
+
/**
* cy82c693_set_piomode - set initial PIO mode data
* @ap: ATA interface
@@ -124,14 +128,16 @@ static struct ata_port_operations cy82c693_port_ops = {
static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
- static const struct ata_port_info info = {
+ static struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
.port_ops = &cy82c693_port_ops
};
const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
+ if (enable_dma)
+ info.mwdma_mask = ATA_MWDMA2;
+
/* Devfn 1 is the ATA primary. The secondary is magic and on devfn2.
For the moment we don't handle the secondary. FIXME */
diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c
index badab6708893..46208ececbb6 100644
--- a/drivers/ata/pata_ep93xx.c
+++ b/drivers/ata/pata_ep93xx.c
@@ -928,7 +928,7 @@ static int ep93xx_pata_probe(struct platform_device *pdev)
/* INT[3] (IRQ_EP93XX_EXT3) line connected as pull down */
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
- err = -ENXIO;
+ err = irq;
goto err_rel_gpio;
}
diff --git a/drivers/ata/pata_falcon.c b/drivers/ata/pata_falcon.c
index 27b0952fde6b..9d0dd8f4c21c 100644
--- a/drivers/ata/pata_falcon.c
+++ b/drivers/ata/pata_falcon.c
@@ -33,8 +33,6 @@
#define DRV_NAME "pata_falcon"
#define DRV_VERSION "0.1.0"
-#define ATA_HD_CONTROL 0x39
-
static struct scsi_host_template pata_falcon_sht = {
ATA_PIO_SHT(DRV_NAME),
};
@@ -121,23 +119,42 @@ static struct ata_port_operations pata_falcon_ops = {
static int __init pata_falcon_init_one(struct platform_device *pdev)
{
- struct resource *res;
+ struct resource *base_mem_res, *ctl_mem_res;
+ struct resource *base_res, *ctl_res, *irq_res;
struct ata_host *host;
struct ata_port *ap;
void __iomem *base;
+ int irq = 0;
- dev_info(&pdev->dev, "Atari Falcon PATA controller\n");
+ dev_info(&pdev->dev, "Atari Falcon and Q40/Q60 PATA controller\n");
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
+ base_res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (base_res && !devm_request_region(&pdev->dev, base_res->start,
+ resource_size(base_res), DRV_NAME)) {
+ dev_err(&pdev->dev, "resources busy\n");
+ return -EBUSY;
+ }
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), DRV_NAME)) {
+ ctl_res = platform_get_resource(pdev, IORESOURCE_IO, 1);
+ if (ctl_res && !devm_request_region(&pdev->dev, ctl_res->start,
+ resource_size(ctl_res), DRV_NAME)) {
dev_err(&pdev->dev, "resources busy\n");
return -EBUSY;
}
+ base_mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!base_mem_res)
+ return -ENODEV;
+ if (!devm_request_mem_region(&pdev->dev, base_mem_res->start,
+ resource_size(base_mem_res), DRV_NAME)) {
+ dev_err(&pdev->dev, "resources busy\n");
+ return -EBUSY;
+ }
+
+ ctl_mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!ctl_mem_res)
+ return -ENODEV;
+
/* allocate host */
host = ata_host_alloc(&pdev->dev, 1);
if (!host)
@@ -147,10 +164,10 @@ static int __init pata_falcon_init_one(struct platform_device *pdev)
ap->ops = &pata_falcon_ops;
ap->pio_mask = ATA_PIO4;
ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
- ap->flags |= ATA_FLAG_PIO_POLLING;
- base = (void __iomem *)res->start;
- ap->ioaddr.data_addr = base;
+ base = (void __iomem *)base_mem_res->start;
+ /* N.B. this assumes data_addr will be used for word-sized I/O only */
+ ap->ioaddr.data_addr = base + 0 + 0 * 4;
ap->ioaddr.error_addr = base + 1 + 1 * 4;
ap->ioaddr.feature_addr = base + 1 + 1 * 4;
ap->ioaddr.nsect_addr = base + 1 + 2 * 4;
@@ -161,14 +178,25 @@ static int __init pata_falcon_init_one(struct platform_device *pdev)
ap->ioaddr.status_addr = base + 1 + 7 * 4;
ap->ioaddr.command_addr = base + 1 + 7 * 4;
- ap->ioaddr.altstatus_addr = base + ATA_HD_CONTROL;
- ap->ioaddr.ctl_addr = base + ATA_HD_CONTROL;
+ base = (void __iomem *)ctl_mem_res->start;
+ ap->ioaddr.altstatus_addr = base + 1;
+ ap->ioaddr.ctl_addr = base + 1;
- ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", (unsigned long)base,
- (unsigned long)base + ATA_HD_CONTROL);
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx",
+ (unsigned long)base_mem_res->start,
+ (unsigned long)ctl_mem_res->start);
+
+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (irq_res && irq_res->start > 0) {
+ irq = irq_res->start;
+ } else {
+ ap->flags |= ATA_FLAG_PIO_POLLING;
+ ata_port_desc(ap, "no IRQ, using PIO polling");
+ }
/* activate */
- return ata_host_activate(host, 0, NULL, 0, &pata_falcon_sht);
+ return ata_host_activate(host, irq, irq ? ata_sff_interrupt : NULL,
+ IRQF_SHARED, &pata_falcon_sht);
}
static int __exit pata_falcon_remove_one(struct platform_device *pdev)
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index 43215a4c1e54..5881d64af943 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -17,6 +17,7 @@
#include <linux/libata.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
+#include <linux/platform_data/pata_ixp4xx_cf.h>
#include <scsi/scsi_host.h>
#define DRV_NAME "pata_ixp4xx_cf"
diff --git a/drivers/ata/pata_macio.c b/drivers/ata/pata_macio.c
index e47a28271f5b..be0ca8d5b345 100644
--- a/drivers/ata/pata_macio.c
+++ b/drivers/ata/pata_macio.c
@@ -914,7 +914,7 @@ static int pata_macio_do_resume(struct pata_macio_priv *priv)
#endif /* CONFIG_PM_SLEEP */
static struct scsi_host_template pata_macio_sht = {
- ATA_BASE_SHT(DRV_NAME),
+ __ATA_BASE_SHT(DRV_NAME),
.sg_tablesize = MAX_DCMDS,
/* We may not need that strict one */
.dma_boundary = ATA_DMA_BOUNDARY,
@@ -923,6 +923,9 @@ static struct scsi_host_template pata_macio_sht = {
*/
.max_segment_size = MAX_DBDMA_SEG,
.slave_configure = pata_macio_slave_config,
+ .sdev_attrs = ata_common_sdev_attrs,
+ .can_queue = ATA_DEF_QUEUE,
+ .tag_alloc_policy = BLK_TAG_ALLOC_RR,
};
static struct ata_port_operations pata_macio_ops = {
diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c
index bd87476ab481..b5a3f710d76d 100644
--- a/drivers/ata/pata_octeon_cf.c
+++ b/drivers/ata/pata_octeon_cf.c
@@ -898,10 +898,11 @@ static int octeon_cf_probe(struct platform_device *pdev)
return -EINVAL;
}
- irq_handler = octeon_cf_interrupt;
i = platform_get_irq(dma_dev, 0);
- if (i > 0)
+ if (i > 0) {
irq = i;
+ irq_handler = octeon_cf_interrupt;
+ }
}
of_node_put(dma_node);
}
diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c
index 479c4b29b856..2e110aefe59b 100644
--- a/drivers/ata/pata_rb532_cf.c
+++ b/drivers/ata/pata_rb532_cf.c
@@ -115,10 +115,10 @@ static int rb532_pata_driver_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- dev_err(&pdev->dev, "no IRQ resource found\n");
- return -ENOENT;
- }
+ if (irq < 0)
+ return irq;
+ if (!irq)
+ return -EINVAL;
gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_IN);
if (IS_ERR(gpiod)) {
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index 3b8c111140bd..f28daf62a37d 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -193,8 +193,9 @@ static int sc1200_qc_defer(struct ata_queued_cmd *qc)
}
static struct scsi_host_template sc1200_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
+ ATA_BASE_SHT(DRV_NAME),
.sg_tablesize = LIBATA_DUMB_MAX_PRD,
+ .dma_boundary = ATA_DMA_BOUNDARY,
};
static struct ata_port_operations sc1200_port_ops = {
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index 7511e11eef4d..b602e303fb54 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -253,8 +253,9 @@ static void serverworks_set_dmamode(struct ata_port *ap, struct ata_device *adev
}
static struct scsi_host_template serverworks_osb4_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
+ ATA_BASE_SHT(DRV_NAME),
.sg_tablesize = LIBATA_DUMB_MAX_PRD,
+ .dma_boundary = ATA_DMA_BOUNDARY,
};
static struct scsi_host_template serverworks_csb_sht = {
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index d55ee244d693..e5838b23c9e0 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -313,7 +313,7 @@ static void fsl_sata_set_irq_coalescing(struct ata_host *host,
DPRINTK("interrupt coalescing, count = 0x%x, ticks = %x\n",
intr_coalescing_count, intr_coalescing_ticks);
- DPRINTK("ICC register status: (hcr base: 0x%x) = 0x%x\n",
+ DPRINTK("ICC register status: (hcr base: %p) = 0x%x\n",
hcr_base, ioread32(hcr_base + ICC));
}
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index 64b2ef15ec19..8440203e835e 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -469,10 +469,12 @@ static int ahci_highbank_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
+ if (irq < 0) {
dev_err(dev, "no irq\n");
- return -EINVAL;
+ return irq;
}
+ if (!irq)
+ return -EINVAL;
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv) {
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index c8867c12c0b8..9d86203e1e7a 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -666,10 +666,14 @@ static struct scsi_host_template mv5_sht = {
};
#endif
static struct scsi_host_template mv6_sht = {
- ATA_NCQ_SHT(DRV_NAME),
+ __ATA_BASE_SHT(DRV_NAME),
.can_queue = MV_MAX_Q_DEPTH - 1,
.sg_tablesize = MV_MAX_SG_CT / 2,
.dma_boundary = MV_DMA_BOUNDARY,
+ .sdev_attrs = ata_ncq_sdev_attrs,
+ .change_queue_depth = ata_scsi_change_queue_depth,
+ .tag_alloc_policy = BLK_TAG_ALLOC_RR,
+ .slave_configure = ata_scsi_slave_config
};
static struct ata_port_operations mv5_ops = {
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 20190f66ced9..c385d18ce87b 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -375,19 +375,25 @@ static struct scsi_host_template nv_sht = {
};
static struct scsi_host_template nv_adma_sht = {
- ATA_NCQ_SHT(DRV_NAME),
+ __ATA_BASE_SHT(DRV_NAME),
.can_queue = NV_ADMA_MAX_CPBS,
.sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN,
.dma_boundary = NV_ADMA_DMA_BOUNDARY,
.slave_configure = nv_adma_slave_config,
+ .sdev_attrs = ata_ncq_sdev_attrs,
+ .change_queue_depth = ata_scsi_change_queue_depth,
+ .tag_alloc_policy = BLK_TAG_ALLOC_RR,
};
static struct scsi_host_template nv_swncq_sht = {
- ATA_NCQ_SHT(DRV_NAME),
+ __ATA_BASE_SHT(DRV_NAME),
.can_queue = ATA_MAX_QUEUE - 1,
.sg_tablesize = LIBATA_MAX_PRD,
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = nv_swncq_slave_config,
+ .sdev_attrs = ata_ncq_sdev_attrs,
+ .change_queue_depth = ata_scsi_change_queue_depth,
+ .tag_alloc_policy = BLK_TAG_ALLOC_RR,
};
/*
@@ -2118,7 +2124,7 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
*/
lack_dhfis = 1;
- DPRINTK("id 0x%x QC: qc_active 0x%x,"
+ DPRINTK("id 0x%x QC: qc_active 0x%llx,"
"SWNCQ:qc_active 0x%X defer_bits %X "
"dhfis 0x%X dmafis 0x%X last_issue_tag %x\n",
ap->print_id, ap->qc_active, pp->qc_active,
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 560070d4f1d0..06a1e27c4f84 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -374,11 +374,14 @@ static struct pci_driver sil24_pci_driver = {
};
static struct scsi_host_template sil24_sht = {
- ATA_NCQ_SHT(DRV_NAME),
+ __ATA_BASE_SHT(DRV_NAME),
.can_queue = SIL24_MAX_CMDS,
.sg_tablesize = SIL24_MAX_SGE,
.dma_boundary = ATA_DMA_BOUNDARY,
.tag_alloc_policy = BLK_TAG_ALLOC_FIFO,
+ .sdev_attrs = ata_ncq_sdev_attrs,
+ .change_queue_depth = ata_scsi_change_queue_depth,
+ .slave_configure = ata_scsi_slave_config
};
static struct ata_port_operations sil24_ops = {
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index b508df2ecada..fb2be3574c26 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -420,6 +420,7 @@ fore200e_shutdown(struct fore200e* fore200e)
/* XXX shouldn't we *start* by deregistering the device? */
atm_dev_deregister(fore200e->atm_dev);
+ fallthrough;
case FORE200E_STATE_BLANK:
/* nothing to do for that state */
break;
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 933e3ff2ee8d..bc8e8d9f176b 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -47,6 +47,7 @@
#include <linux/errno.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
+#include <linux/ctype.h>
#include <linux/sonet.h>
#include <linux/skbuff.h>
#include <linux/time.h>
@@ -996,10 +997,12 @@ static void xdump( u_char* cp, int length, char* prefix )
}
pBuf += sprintf( pBuf, " " );
for(col = 0;count + col < length && col < 16; col++){
- if (isprint((int)cp[count + col]))
- pBuf += sprintf( pBuf, "%c", cp[count + col] );
- else
- pBuf += sprintf( pBuf, "." );
+ u_char c = cp[count + col];
+
+ if (isascii(c) && isprint(c))
+ pBuf += sprintf(pBuf, "%c", c);
+ else
+ pBuf += sprintf(pBuf, ".");
}
printk("%s\n", prntBuf);
count += col;
@@ -3279,7 +3282,7 @@ static void __exit ia_module_exit(void)
{
pci_unregister_driver(&ia_driver);
- del_timer(&ia_timer);
+ del_timer_sync(&ia_timer);
}
module_init(ia_module_init);
diff --git a/drivers/atm/iphase.h b/drivers/atm/iphase.h
index 2beacf2fc1ec..2f5f8875cbd1 100644
--- a/drivers/atm/iphase.h
+++ b/drivers/atm/iphase.h
@@ -124,7 +124,6 @@
#define IF_RXPKT(A)
#endif /* CONFIG_ATM_IA_DEBUG */
-#define isprint(a) ((a >=' ')&&(a <= '~'))
#define ATM_DESC(skb) (skb->protocol)
#define IA_SKB_STATE(skb) (skb->protocol)
#define IA_DLED 1
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index 5c7e4df159b9..bc5a6ab6fa4b 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -299,7 +299,7 @@ static void __exit nicstar_cleanup(void)
{
XPRINTK("nicstar: nicstar_cleanup() called.\n");
- del_timer(&ns_timer);
+ del_timer_sync(&ns_timer);
pci_unregister_driver(&nicstar_driver);
@@ -527,6 +527,15 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
/* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */
writel(0x00000000, card->membase + VPM);
+ card->intcnt = 0;
+ if (request_irq
+ (pcidev->irq, &ns_irq_handler, IRQF_SHARED, "nicstar", card) != 0) {
+ pr_err("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
+ error = 9;
+ ns_init_card_error(card, error);
+ return error;
+ }
+
/* Initialize TSQ */
card->tsq.org = dma_alloc_coherent(&card->pcidev->dev,
NS_TSQSIZE + NS_TSQ_ALIGNMENT,
@@ -753,15 +762,6 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
card->efbie = 1;
- card->intcnt = 0;
- if (request_irq
- (pcidev->irq, &ns_irq_handler, IRQF_SHARED, "nicstar", card) != 0) {
- printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
- error = 9;
- ns_init_card_error(card, error);
- return error;
- }
-
/* Register device */
card->atmdev = atm_dev_register("nicstar", &card->pcidev->dev, &atm_ops,
-1, NULL);
@@ -839,10 +839,12 @@ static void ns_init_card_error(ns_dev *card, int error)
dev_kfree_skb_any(hb);
}
if (error >= 12) {
- kfree(card->rsq.org);
+ dma_free_coherent(&card->pcidev->dev, NS_RSQSIZE + NS_RSQ_ALIGNMENT,
+ card->rsq.org, card->rsq.dma);
}
if (error >= 11) {
- kfree(card->tsq.org);
+ dma_free_coherent(&card->pcidev->dev, NS_TSQSIZE + NS_TSQ_ALIGNMENT,
+ card->tsq.org, card->tsq.dma);
}
if (error >= 10) {
free_irq(card->pcidev->irq, card);
diff --git a/drivers/atm/zeprom.h b/drivers/atm/zeprom.h
index 88e01f808a86..8e8819a3840d 100644
--- a/drivers/atm/zeprom.h
+++ b/drivers/atm/zeprom.h
@@ -12,7 +12,7 @@
#define ZEPROM_V1_REG PCI_VENDOR_ID /* PCI register */
#define ZEPROM_V2_REG 0x40
-/* Bits in contol register */
+/* Bits in control register */
#define ZEPROM_SK 0x80000000 /* strobe (probably on raising edge) */
#define ZEPROM_CS 0x40000000 /* Chip Select */
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 8b93a7f291ec..ef8e44a7d288 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -30,3 +30,6 @@ obj-y += test/
ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
+# define_trace.h needs to know how to find our header
+CFLAGS_trace.o := -I$(src)
+obj-$(CONFIG_TRACING) += trace.o
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index c1179edc0f3b..921312a8d957 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -18,10 +18,11 @@
#include <linux/cpumask.h>
#include <linux/init.h>
#include <linux/percpu.h>
+#include <linux/rcupdate.h>
#include <linux/sched.h>
#include <linux/smp.h>
-static DEFINE_PER_CPU(struct scale_freq_data *, sft_data);
+static DEFINE_PER_CPU(struct scale_freq_data __rcu *, sft_data);
static struct cpumask scale_freq_counters_mask;
static bool scale_freq_invariant;
@@ -66,16 +67,20 @@ void topology_set_scale_freq_source(struct scale_freq_data *data,
if (cpumask_empty(&scale_freq_counters_mask))
scale_freq_invariant = topology_scale_freq_invariant();
+ rcu_read_lock();
+
for_each_cpu(cpu, cpus) {
- sfd = per_cpu(sft_data, cpu);
+ sfd = rcu_dereference(*per_cpu_ptr(&sft_data, cpu));
/* Use ARCH provided counters whenever possible */
if (!sfd || sfd->source != SCALE_FREQ_SOURCE_ARCH) {
- per_cpu(sft_data, cpu) = data;
+ rcu_assign_pointer(per_cpu(sft_data, cpu), data);
cpumask_set_cpu(cpu, &scale_freq_counters_mask);
}
}
+ rcu_read_unlock();
+
update_scale_freq_invariant(true);
}
EXPORT_SYMBOL_GPL(topology_set_scale_freq_source);
@@ -86,22 +91,32 @@ void topology_clear_scale_freq_source(enum scale_freq_source source,
struct scale_freq_data *sfd;
int cpu;
+ rcu_read_lock();
+
for_each_cpu(cpu, cpus) {
- sfd = per_cpu(sft_data, cpu);
+ sfd = rcu_dereference(*per_cpu_ptr(&sft_data, cpu));
if (sfd && sfd->source == source) {
- per_cpu(sft_data, cpu) = NULL;
+ rcu_assign_pointer(per_cpu(sft_data, cpu), NULL);
cpumask_clear_cpu(cpu, &scale_freq_counters_mask);
}
}
+ rcu_read_unlock();
+
+ /*
+ * Make sure all references to previous sft_data are dropped to avoid
+ * use-after-free races.
+ */
+ synchronize_rcu();
+
update_scale_freq_invariant(false);
}
EXPORT_SYMBOL_GPL(topology_clear_scale_freq_source);
void topology_scale_freq_tick(void)
{
- struct scale_freq_data *sfd = *this_cpu_ptr(&sft_data);
+ struct scale_freq_data *sfd = rcu_dereference_sched(*this_cpu_ptr(&sft_data));
if (sfd)
sfd->set_freq_scale();
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c
index 9c00d203d61e..01ef796c2055 100644
--- a/drivers/base/attribute_container.c
+++ b/drivers/base/attribute_container.c
@@ -284,8 +284,8 @@ fail:
* matching classdev or fail all of them.
*
* @dev: The generic device to run the trigger for
- * @fn the function to execute for each classdev.
- * @undo A function to undo the work previously done in case of error
+ * @fn: the function to execute for each classdev.
+ * @undo: A function to undo the work previously done in case of error
*
* This function is a safe version of
* attribute_container_device_trigger. It stops on the first error and
@@ -343,7 +343,7 @@ attribute_container_device_trigger_safe(struct device *dev,
* attribute_container_device_trigger - execute a trigger for each matching classdev
*
* @dev: The generic device to run the trigger for
- * @fn the function to execute for each classdev.
+ * @fn: the function to execute for each classdev.
*
* This function is for executing a trigger when you need to know both
* the container and the classdev. If you only care about the
diff --git a/drivers/base/base.h b/drivers/base/base.h
index e5f9b7e656c3..404db83ee5ec 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -152,7 +152,6 @@ extern int driver_add_groups(struct device_driver *drv,
const struct attribute_group **groups);
extern void driver_remove_groups(struct device_driver *drv,
const struct attribute_group **groups);
-int device_driver_attach(struct device_driver *drv, struct device *dev);
void device_driver_detach(struct device *dev);
extern char *make_class_name(const char *name, struct kobject *kobj);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 36d0c654ea61..1f6b4bd61056 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -210,15 +210,11 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf,
int err = -ENODEV;
dev = bus_find_device_by_name(bus, NULL, buf);
- if (dev && dev->driver == NULL && driver_match_device(drv, dev)) {
+ if (dev && driver_match_device(drv, dev)) {
err = device_driver_attach(drv, dev);
-
- if (err > 0) {
+ if (!err) {
/* success */
err = count;
- } else if (err == 0) {
- /* driver didn't accept device */
- err = -ENODEV;
}
}
put_device(dev);
diff --git a/drivers/base/component.c b/drivers/base/component.c
index 272ba42392f0..5e79299f6c3f 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -63,7 +63,7 @@ struct master {
bool bound;
const struct component_master_ops *ops;
- struct device *dev;
+ struct device *parent;
struct component_match *match;
};
@@ -95,7 +95,7 @@ static int component_devices_show(struct seq_file *s, void *data)
seq_printf(s, "%-40s %20s\n", "master name", "status");
seq_puts(s, "-------------------------------------------------------------\n");
seq_printf(s, "%-40s %20s\n\n",
- dev_name(m->dev), m->bound ? "bound" : "not bound");
+ dev_name(m->parent), m->bound ? "bound" : "not bound");
seq_printf(s, "%-40s %20s\n", "device name", "status");
seq_puts(s, "-------------------------------------------------------------\n");
@@ -124,13 +124,13 @@ core_initcall(component_debug_init);
static void component_master_debugfs_add(struct master *m)
{
- debugfs_create_file(dev_name(m->dev), 0444, component_debugfs_dir, m,
+ debugfs_create_file(dev_name(m->parent), 0444, component_debugfs_dir, m,
&component_devices_fops);
}
static void component_master_debugfs_del(struct master *m)
{
- debugfs_remove(debugfs_lookup(dev_name(m->dev), component_debugfs_dir));
+ debugfs_remove(debugfs_lookup(dev_name(m->parent), component_debugfs_dir));
}
#else
@@ -143,13 +143,13 @@ static void component_master_debugfs_del(struct master *m)
#endif
-static struct master *__master_find(struct device *dev,
+static struct master *__master_find(struct device *parent,
const struct component_master_ops *ops)
{
struct master *m;
list_for_each_entry(m, &masters, node)
- if (m->dev == dev && (!ops || m->ops == ops))
+ if (m->parent == parent && (!ops || m->ops == ops))
return m;
return NULL;
@@ -189,7 +189,7 @@ static int find_components(struct master *master)
struct component_match_array *mc = &match->compare[i];
struct component *c;
- dev_dbg(master->dev, "Looking for component %zu\n", i);
+ dev_dbg(master->parent, "Looking for component %zu\n", i);
if (match->compare[i].component)
continue;
@@ -200,7 +200,7 @@ static int find_components(struct master *master)
break;
}
- dev_dbg(master->dev, "found component %s, duplicate %u\n", dev_name(c->dev), !!c->master);
+ dev_dbg(master->parent, "found component %s, duplicate %u\n", dev_name(c->dev), !!c->master);
/* Attach this component to the master */
match->compare[i].duplicate = !!c->master;
@@ -233,28 +233,28 @@ static int try_to_bring_up_master(struct master *master,
{
int ret;
- dev_dbg(master->dev, "trying to bring up master\n");
+ dev_dbg(master->parent, "trying to bring up master\n");
if (find_components(master)) {
- dev_dbg(master->dev, "master has incomplete components\n");
+ dev_dbg(master->parent, "master has incomplete components\n");
return 0;
}
if (component && component->master != master) {
- dev_dbg(master->dev, "master is not for this component (%s)\n",
+ dev_dbg(master->parent, "master is not for this component (%s)\n",
dev_name(component->dev));
return 0;
}
- if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
+ if (!devres_open_group(master->parent, NULL, GFP_KERNEL))
return -ENOMEM;
/* Found all components */
- ret = master->ops->bind(master->dev);
+ ret = master->ops->bind(master->parent);
if (ret < 0) {
- devres_release_group(master->dev, NULL);
+ devres_release_group(master->parent, NULL);
if (ret != -EPROBE_DEFER)
- dev_info(master->dev, "master bind failed: %d\n", ret);
+ dev_info(master->parent, "master bind failed: %d\n", ret);
return ret;
}
@@ -281,34 +281,28 @@ static int try_to_bring_up_masters(struct component *component)
static void take_down_master(struct master *master)
{
if (master->bound) {
- master->ops->unbind(master->dev);
- devres_release_group(master->dev, NULL);
+ master->ops->unbind(master->parent);
+ devres_release_group(master->parent, NULL);
master->bound = false;
}
}
-static void component_match_release(struct device *master,
- struct component_match *match)
+static void devm_component_match_release(struct device *parent, void *res)
{
+ struct component_match *match = res;
unsigned int i;
for (i = 0; i < match->num; i++) {
struct component_match_array *mc = &match->compare[i];
if (mc->release)
- mc->release(master, mc->data);
+ mc->release(parent, mc->data);
}
kfree(match->compare);
}
-static void devm_component_match_release(struct device *dev, void *res)
-{
- component_match_release(dev, res);
-}
-
-static int component_match_realloc(struct device *dev,
- struct component_match *match, size_t num)
+static int component_match_realloc(struct component_match *match, size_t num)
{
struct component_match_array *new;
@@ -359,7 +353,7 @@ static void __component_match_add(struct device *master,
size_t new_size = match->alloc + 16;
int ret;
- ret = component_match_realloc(master, match, new_size);
+ ret = component_match_realloc(match, new_size);
if (ret) {
*matchptr = ERR_PTR(ret);
return;
@@ -451,7 +445,7 @@ static void free_master(struct master *master)
/**
* component_master_add_with_match - register an aggregate driver
- * @dev: device with the aggregate driver
+ * @parent: parent device of the aggregate driver
* @ops: callbacks for the aggregate driver
* @match: component match list for the aggregate driver
*
@@ -461,7 +455,7 @@ static void free_master(struct master *master)
* &component_master_ops.bind from @ops. Must be unregistered by calling
* component_master_del().
*/
-int component_master_add_with_match(struct device *dev,
+int component_master_add_with_match(struct device *parent,
const struct component_master_ops *ops,
struct component_match *match)
{
@@ -469,7 +463,7 @@ int component_master_add_with_match(struct device *dev,
int ret;
/* Reallocate the match array for its true size */
- ret = component_match_realloc(dev, match, match->num);
+ ret = component_match_realloc(match, match->num);
if (ret)
return ret;
@@ -477,7 +471,7 @@ int component_master_add_with_match(struct device *dev,
if (!master)
return -ENOMEM;
- master->dev = dev;
+ master->parent = parent;
master->ops = ops;
master->match = match;
@@ -499,20 +493,20 @@ EXPORT_SYMBOL_GPL(component_master_add_with_match);
/**
* component_master_del - unregister an aggregate driver
- * @dev: device with the aggregate driver
+ * @parent: parent device of the aggregate driver
* @ops: callbacks for the aggregate driver
*
* Unregisters an aggregate driver registered with
* component_master_add_with_match(). If necessary the aggregate driver is first
* disassembled by calling &component_master_ops.unbind from @ops.
*/
-void component_master_del(struct device *dev,
+void component_master_del(struct device *parent,
const struct component_master_ops *ops)
{
struct master *master;
mutex_lock(&component_mutex);
- master = __master_find(dev, ops);
+ master = __master_find(parent, ops);
if (master) {
take_down_master(master);
free_master(master);
@@ -527,7 +521,7 @@ static void component_unbind(struct component *component,
WARN_ON(!component->bound);
if (component->ops && component->ops->unbind)
- component->ops->unbind(component->dev, master->dev, data);
+ component->ops->unbind(component->dev, master->parent, data);
component->bound = false;
/* Release all resources claimed in the binding of this component */
@@ -536,14 +530,14 @@ static void component_unbind(struct component *component,
/**
* component_unbind_all - unbind all components of an aggregate driver
- * @master_dev: device with the aggregate driver
+ * @parent: parent device of the aggregate driver
* @data: opaque pointer, passed to all components
*
- * Unbinds all components of the aggregate @dev by passing @data to their
+ * Unbinds all components of the aggregate device by passing @data to their
* &component_ops.unbind functions. Should be called from
* &component_master_ops.unbind.
*/
-void component_unbind_all(struct device *master_dev, void *data)
+void component_unbind_all(struct device *parent, void *data)
{
struct master *master;
struct component *c;
@@ -551,7 +545,7 @@ void component_unbind_all(struct device *master_dev, void *data)
WARN_ON(!mutex_is_locked(&component_mutex));
- master = __master_find(master_dev, NULL);
+ master = __master_find(parent, NULL);
if (!master)
return;
@@ -574,7 +568,7 @@ static int component_bind(struct component *component, struct master *master,
* This allows us to roll-back a failed component without
* affecting anything else.
*/
- if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
+ if (!devres_open_group(master->parent, NULL, GFP_KERNEL))
return -ENOMEM;
/*
@@ -583,14 +577,14 @@ static int component_bind(struct component *component, struct master *master,
* at the appropriate moment.
*/
if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
- devres_release_group(master->dev, NULL);
+ devres_release_group(master->parent, NULL);
return -ENOMEM;
}
- dev_dbg(master->dev, "binding %s (ops %ps)\n",
+ dev_dbg(master->parent, "binding %s (ops %ps)\n",
dev_name(component->dev), component->ops);
- ret = component->ops->bind(component->dev, master->dev, data);
+ ret = component->ops->bind(component->dev, master->parent, data);
if (!ret) {
component->bound = true;
@@ -601,16 +595,16 @@ static int component_bind(struct component *component, struct master *master,
* can clean those resources up independently.
*/
devres_close_group(component->dev, NULL);
- devres_remove_group(master->dev, NULL);
+ devres_remove_group(master->parent, NULL);
- dev_info(master->dev, "bound %s (ops %ps)\n",
+ dev_info(master->parent, "bound %s (ops %ps)\n",
dev_name(component->dev), component->ops);
} else {
devres_release_group(component->dev, NULL);
- devres_release_group(master->dev, NULL);
+ devres_release_group(master->parent, NULL);
if (ret != -EPROBE_DEFER)
- dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
+ dev_err(master->parent, "failed to bind %s (ops %ps): %d\n",
dev_name(component->dev), component->ops, ret);
}
@@ -619,14 +613,14 @@ static int component_bind(struct component *component, struct master *master,
/**
* component_bind_all - bind all components of an aggregate driver
- * @master_dev: device with the aggregate driver
+ * @parent: parent device of the aggregate driver
* @data: opaque pointer, passed to all components
*
* Binds all components of the aggregate @dev by passing @data to their
* &component_ops.bind functions. Should be called from
* &component_master_ops.bind.
*/
-int component_bind_all(struct device *master_dev, void *data)
+int component_bind_all(struct device *parent, void *data)
{
struct master *master;
struct component *c;
@@ -635,7 +629,7 @@ int component_bind_all(struct device *master_dev, void *data)
WARN_ON(!mutex_is_locked(&component_mutex));
- master = __master_find(master_dev, NULL);
+ master = __master_find(parent, NULL);
if (!master)
return -EINVAL;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 54ba506e5a89..cadcade65825 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2409,6 +2409,25 @@ static ssize_t online_store(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RW(online);
+static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ const char *loc;
+
+ switch (dev->removable) {
+ case DEVICE_REMOVABLE:
+ loc = "removable";
+ break;
+ case DEVICE_FIXED:
+ loc = "fixed";
+ break;
+ default:
+ loc = "unknown";
+ }
+ return sysfs_emit(buf, "%s\n", loc);
+}
+static DEVICE_ATTR_RO(removable);
+
int device_add_groups(struct device *dev, const struct attribute_group **groups)
{
return sysfs_create_groups(&dev->kobj, groups);
@@ -2586,8 +2605,16 @@ static int device_add_attrs(struct device *dev)
goto err_remove_dev_online;
}
+ if (dev_removable_is_valid(dev)) {
+ error = device_create_file(dev, &dev_attr_removable);
+ if (error)
+ goto err_remove_dev_waiting_for_supplier;
+ }
+
return 0;
+ err_remove_dev_waiting_for_supplier:
+ device_remove_file(dev, &dev_attr_waiting_for_supplier);
err_remove_dev_online:
device_remove_file(dev, &dev_attr_online);
err_remove_dev_groups:
@@ -2607,6 +2634,7 @@ static void device_remove_attrs(struct device *dev)
struct class *class = dev->class;
const struct device_type *type = dev->type;
+ device_remove_file(dev, &dev_attr_removable);
device_remove_file(dev, &dev_attr_waiting_for_supplier);
device_remove_file(dev, &dev_attr_online);
device_remove_groups(dev, dev->groups);
@@ -3442,7 +3470,7 @@ bool kill_device(struct device *dev)
* to run while we are tearing out the bus/class/sysfs from
* underneath the device.
*/
- lockdep_assert_held(&dev->mutex);
+ device_lock_assert(dev);
if (dev->p->dead)
return false;
@@ -4727,6 +4755,13 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2)
}
EXPORT_SYMBOL_GPL(device_set_of_node_from_dev);
+void device_set_node(struct device *dev, struct fwnode_handle *fwnode)
+{
+ dev->fwnode = fwnode;
+ dev->of_node = to_of_node(fwnode);
+}
+EXPORT_SYMBOL_GPL(device_set_node);
+
int device_match_name(struct device *dev, const void *name)
{
return sysfs_streq(dev_name(dev), name);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 2b9e41377a07..5ef14db97904 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -175,7 +175,7 @@ static struct attribute *crash_note_cpu_attrs[] = {
NULL
};
-static struct attribute_group crash_note_cpu_attr_group = {
+static const struct attribute_group crash_note_cpu_attr_group = {
.attrs = crash_note_cpu_attrs,
};
#endif
@@ -475,7 +475,7 @@ static struct attribute *cpu_root_attrs[] = {
NULL
};
-static struct attribute_group cpu_root_attr_group = {
+static const struct attribute_group cpu_root_attr_group = {
.attrs = cpu_root_attrs,
};
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index ecd7cf848daf..daeb9b5763ae 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -471,6 +471,8 @@ static void driver_sysfs_remove(struct device *dev)
* (It is ok to call with no other effort from a driver's probe() method.)
*
* This function must be called with the device lock held.
+ *
+ * Callers should prefer to use device_driver_attach() instead.
*/
int device_bind_driver(struct device *dev)
{
@@ -491,15 +493,6 @@ EXPORT_SYMBOL_GPL(device_bind_driver);
static atomic_t probe_count = ATOMIC_INIT(0);
static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
-static void driver_deferred_probe_add_trigger(struct device *dev,
- int local_trigger_count)
-{
- driver_deferred_probe_add(dev);
- /* Did a trigger occur while probing? Need to re-trigger if yes */
- if (local_trigger_count != atomic_read(&deferred_trigger_count))
- driver_deferred_probe_trigger();
-}
-
static ssize_t state_synced_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -513,12 +506,43 @@ static ssize_t state_synced_show(struct device *dev,
}
static DEVICE_ATTR_RO(state_synced);
+
+static int call_driver_probe(struct device *dev, struct device_driver *drv)
+{
+ int ret = 0;
+
+ if (dev->bus->probe)
+ ret = dev->bus->probe(dev);
+ else if (drv->probe)
+ ret = drv->probe(dev);
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EPROBE_DEFER:
+ /* Driver requested deferred probing */
+ dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name);
+ break;
+ case -ENODEV:
+ case -ENXIO:
+ pr_debug("%s: probe of %s rejects match %d\n",
+ drv->name, dev_name(dev), ret);
+ break;
+ default:
+ /* driver matched but the probe failed */
+ pr_warn("%s: probe of %s failed with error %d\n",
+ drv->name, dev_name(dev), ret);
+ break;
+ }
+
+ return ret;
+}
+
static int really_probe(struct device *dev, struct device_driver *drv)
{
- int ret = -EPROBE_DEFER;
- int local_trigger_count = atomic_read(&deferred_trigger_count);
bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) &&
!drv->suppress_bind_attrs;
+ int ret;
if (defer_all_probes) {
/*
@@ -527,17 +551,13 @@ static int really_probe(struct device *dev, struct device_driver *drv)
* wait_for_device_probe() right after that to avoid any races.
*/
dev_dbg(dev, "Driver %s force probe deferral\n", drv->name);
- driver_deferred_probe_add(dev);
- return ret;
+ return -EPROBE_DEFER;
}
ret = device_links_check_suppliers(dev);
- if (ret == -EPROBE_DEFER)
- driver_deferred_probe_add_trigger(dev, local_trigger_count);
if (ret)
return ret;
- atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
drv->bus->name, __func__, drv->name, dev_name(dev));
if (!list_empty(&dev->devres_head)) {
@@ -572,14 +592,14 @@ re_probe:
goto probe_failed;
}
- if (dev->bus->probe) {
- ret = dev->bus->probe(dev);
- if (ret)
- goto probe_failed;
- } else if (drv->probe) {
- ret = drv->probe(dev);
- if (ret)
- goto probe_failed;
+ ret = call_driver_probe(dev, drv);
+ if (ret) {
+ /*
+ * Return probe errors as positive values so that the callers
+ * can distinguish them from other errors.
+ */
+ ret = -ret;
+ goto probe_failed;
}
if (device_add_groups(dev, drv->dev_groups)) {
@@ -621,7 +641,6 @@ re_probe:
dev->pm_domain->sync(dev);
driver_bound(dev);
- ret = 1;
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
goto done;
@@ -650,31 +669,7 @@ pinctrl_bind_failed:
dev->pm_domain->dismiss(dev);
pm_runtime_reinit(dev);
dev_pm_set_driver_flags(dev, 0);
-
- switch (ret) {
- case -EPROBE_DEFER:
- /* Driver requested deferred probing */
- dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name);
- driver_deferred_probe_add_trigger(dev, local_trigger_count);
- break;
- case -ENODEV:
- case -ENXIO:
- pr_debug("%s: probe of %s rejects match %d\n",
- drv->name, dev_name(dev), ret);
- break;
- default:
- /* driver matched but the probe failed */
- pr_warn("%s: probe of %s failed with error %d\n",
- drv->name, dev_name(dev), ret);
- }
- /*
- * Ignore errors returned by ->probe so that the next driver can try
- * its luck.
- */
- ret = 0;
done:
- atomic_dec(&probe_count);
- wake_up_all(&probe_waitqueue);
return ret;
}
@@ -728,25 +723,14 @@ void wait_for_device_probe(void)
}
EXPORT_SYMBOL_GPL(wait_for_device_probe);
-/**
- * driver_probe_device - attempt to bind device & driver together
- * @drv: driver to bind a device to
- * @dev: device to try to bind to the driver
- *
- * This function returns -ENODEV if the device is not registered,
- * 1 if the device is bound successfully and 0 otherwise.
- *
- * This function must be called with @dev lock held. When called for a
- * USB interface, @dev->parent lock must be held as well.
- *
- * If the device has a parent, runtime-resume the parent before driver probing.
- */
-static int driver_probe_device(struct device_driver *drv, struct device *dev)
+static int __driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;
- if (!device_is_registered(dev))
+ if (dev->p->dead || !device_is_registered(dev))
return -ENODEV;
+ if (dev->driver)
+ return -EBUSY;
dev->can_match = true;
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
@@ -770,6 +754,42 @@ static int driver_probe_device(struct device_driver *drv, struct device *dev)
return ret;
}
+/**
+ * driver_probe_device - attempt to bind device & driver together
+ * @drv: driver to bind a device to
+ * @dev: device to try to bind to the driver
+ *
+ * This function returns -ENODEV if the device is not registered, -EBUSY if it
+ * already has a driver, 0 if the device is bound successfully and a positive
+ * (inverted) error code for failures from the ->probe method.
+ *
+ * This function must be called with @dev lock held. When called for a
+ * USB interface, @dev->parent lock must be held as well.
+ *
+ * If the device has a parent, runtime-resume the parent before driver probing.
+ */
+static int driver_probe_device(struct device_driver *drv, struct device *dev)
+{
+ int trigger_count = atomic_read(&deferred_trigger_count);
+ int ret;
+
+ atomic_inc(&probe_count);
+ ret = __driver_probe_device(drv, dev);
+ if (ret == -EPROBE_DEFER || ret == EPROBE_DEFER) {
+ driver_deferred_probe_add(dev);
+
+ /*
+ * Did a trigger occur while probing? Need to re-trigger if yes
+ */
+ if (trigger_count != atomic_read(&deferred_trigger_count) &&
+ !defer_all_probes)
+ driver_deferred_probe_trigger();
+ }
+ atomic_dec(&probe_count);
+ wake_up_all(&probe_waitqueue);
+ return ret;
+}
+
static inline bool cmdline_requested_async_probing(const char *drv_name)
{
return parse_option_str(async_probe_drv_names, drv_name);
@@ -867,7 +887,14 @@ static int __device_attach_driver(struct device_driver *drv, void *_data)
if (data->check_async && async_allowed != data->want_async)
return 0;
- return driver_probe_device(drv, dev);
+ /*
+ * Ignore errors returned by ->probe so that the next driver can try
+ * its luck.
+ */
+ ret = driver_probe_device(drv, dev);
+ if (ret < 0)
+ return ret;
+ return ret == 0;
}
static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
@@ -1023,43 +1050,34 @@ static void __device_driver_unlock(struct device *dev, struct device *parent)
* @dev: Device to attach it to
*
* Manually attach driver to a device. Will acquire both @dev lock and
- * @dev->parent lock if needed.
+ * @dev->parent lock if needed. Returns 0 on success, -ERR on failure.
*/
int device_driver_attach(struct device_driver *drv, struct device *dev)
{
- int ret = 0;
+ int ret;
__device_driver_lock(dev, dev->parent);
-
- /*
- * If device has been removed or someone has already successfully
- * bound a driver before us just skip the driver probe call.
- */
- if (!dev->p->dead && !dev->driver)
- ret = driver_probe_device(drv, dev);
-
+ ret = __driver_probe_device(drv, dev);
__device_driver_unlock(dev, dev->parent);
+ /* also return probe errors as normal negative errnos */
+ if (ret > 0)
+ ret = -ret;
+ if (ret == -EPROBE_DEFER)
+ return -EAGAIN;
return ret;
}
+EXPORT_SYMBOL_GPL(device_driver_attach);
static void __driver_attach_async_helper(void *_dev, async_cookie_t cookie)
{
struct device *dev = _dev;
struct device_driver *drv;
- int ret = 0;
+ int ret;
__device_driver_lock(dev, dev->parent);
-
drv = dev->p->async_driver;
-
- /*
- * If device has been removed or someone has already successfully
- * bound a driver before us just skip the driver probe call.
- */
- if (!dev->p->dead && !dev->driver)
- ret = driver_probe_device(drv, dev);
-
+ ret = driver_probe_device(drv, dev);
__device_driver_unlock(dev, dev->parent);
dev_dbg(dev, "driver %s async attach completed: %d\n", drv->name, ret);
@@ -1114,7 +1132,9 @@ static int __driver_attach(struct device *dev, void *data)
return 0;
}
- device_driver_attach(drv, dev);
+ __device_driver_lock(dev, dev->parent);
+ driver_probe_device(drv, dev);
+ __device_driver_unlock(dev, dev->parent);
return 0;
}
diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c
index 8eec0e0ddff7..f4d794d6bb85 100644
--- a/drivers/base/devcoredump.c
+++ b/drivers/base/devcoredump.c
@@ -3,10 +3,6 @@
* Copyright(c) 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 Intel Deutschland GmbH
*
- * Contact Information:
- * Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
* Author: Johannes Berg <johannes@sipsolutions.net>
*/
#include <linux/module.h>
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 8746f2212781..eaa9a5cd1db9 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -14,14 +14,13 @@
#include <asm/sections.h>
#include "base.h"
+#include "trace.h"
struct devres_node {
struct list_head entry;
dr_release_t release;
-#ifdef CONFIG_DEBUG_DEVRES
const char *name;
size_t size;
-#endif
};
struct devres {
@@ -43,10 +42,6 @@ struct devres_group {
/* -- 8 pointers */
};
-#ifdef CONFIG_DEBUG_DEVRES
-static int log_devres = 0;
-module_param_named(log, log_devres, int, S_IRUGO | S_IWUSR);
-
static void set_node_dbginfo(struct devres_node *node, const char *name,
size_t size)
{
@@ -54,7 +49,11 @@ static void set_node_dbginfo(struct devres_node *node, const char *name,
node->size = size;
}
-static void devres_log(struct device *dev, struct devres_node *node,
+#ifdef CONFIG_DEBUG_DEVRES
+static int log_devres = 0;
+module_param_named(log, log_devres, int, S_IRUGO | S_IWUSR);
+
+static void devres_dbg(struct device *dev, struct devres_node *node,
const char *op)
{
if (unlikely(log_devres))
@@ -62,10 +61,16 @@ static void devres_log(struct device *dev, struct devres_node *node,
op, node, node->name, node->size);
}
#else /* CONFIG_DEBUG_DEVRES */
-#define set_node_dbginfo(node, n, s) do {} while (0)
-#define devres_log(dev, node, op) do {} while (0)
+#define devres_dbg(dev, node, op) do {} while (0)
#endif /* CONFIG_DEBUG_DEVRES */
+static void devres_log(struct device *dev, struct devres_node *node,
+ const char *op)
+{
+ trace_devres_log(dev, op, node, node->name, node->size);
+ devres_dbg(dev, node, op);
+}
+
/*
* Release functions for devres group. These callbacks are used only
* for identification.
@@ -134,26 +139,13 @@ static void replace_dr(struct device *dev,
list_replace(&old->entry, &new->entry);
}
-#ifdef CONFIG_DEBUG_DEVRES
-void * __devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid,
- const char *name)
-{
- struct devres *dr;
-
- dr = alloc_dr(release, size, gfp | __GFP_ZERO, nid);
- if (unlikely(!dr))
- return NULL;
- set_node_dbginfo(&dr->node, name, size);
- return dr->data;
-}
-EXPORT_SYMBOL_GPL(__devres_alloc_node);
-#else
/**
- * devres_alloc_node - Allocate device resource data
+ * __devres_alloc_node - Allocate device resource data
* @release: Release function devres will be associated with
* @size: Allocation size
* @gfp: Allocation flags
* @nid: NUMA node
+ * @name: Name of the resource
*
* Allocate devres of @size bytes. The allocated area is zeroed, then
* associated with @release. The returned pointer can be passed to
@@ -162,17 +154,18 @@ EXPORT_SYMBOL_GPL(__devres_alloc_node);
* RETURNS:
* Pointer to allocated devres on success, NULL on failure.
*/
-void * devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid)
+void *__devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid,
+ const char *name)
{
struct devres *dr;
dr = alloc_dr(release, size, gfp | __GFP_ZERO, nid);
if (unlikely(!dr))
return NULL;
+ set_node_dbginfo(&dr->node, name, size);
return dr->data;
}
-EXPORT_SYMBOL_GPL(devres_alloc_node);
-#endif
+EXPORT_SYMBOL_GPL(__devres_alloc_node);
/**
* devres_for_each_res - Resource iterator
@@ -438,20 +431,16 @@ static int remove_nodes(struct device *dev,
struct list_head *first, struct list_head *end,
struct list_head *todo)
{
+ struct devres_node *node, *n;
int cnt = 0, nr_groups = 0;
- struct list_head *cur;
/* First pass - move normal devres entries to @todo and clear
* devres_group colors.
*/
- cur = first;
- while (cur != end) {
- struct devres_node *node;
+ node = list_entry(first, struct devres_node, entry);
+ list_for_each_entry_safe_from(node, n, end, entry) {
struct devres_group *grp;
- node = list_entry(cur, struct devres_node, entry);
- cur = cur->next;
-
grp = node_to_group(node);
if (grp) {
/* clear color of group markers in the first pass */
@@ -471,18 +460,14 @@ static int remove_nodes(struct device *dev,
/* Second pass - Scan groups and color them. A group gets
* color value of two iff the group is wholly contained in
- * [cur, end). That is, for a closed group, both opening and
- * closing markers should be in the range, while just the
+ * [current node, end). That is, for a closed group, both opening
+ * and closing markers should be in the range, while just the
* opening marker is enough for an open group.
*/
- cur = first;
- while (cur != end) {
- struct devres_node *node;
+ node = list_entry(first, struct devres_node, entry);
+ list_for_each_entry_safe_from(node, n, end, entry) {
struct devres_group *grp;
- node = list_entry(cur, struct devres_node, entry);
- cur = cur->next;
-
grp = node_to_group(node);
BUG_ON(!grp || list_empty(&grp->node[0].entry));
@@ -492,7 +477,7 @@ static int remove_nodes(struct device *dev,
BUG_ON(grp->color <= 0 || grp->color > 2);
if (grp->color == 2) {
- /* No need to update cur or end. The removed
+ /* No need to update current node or end. The removed
* nodes are always before both.
*/
list_move_tail(&grp->node[0].entry, todo);
@@ -503,28 +488,18 @@ static int remove_nodes(struct device *dev,
return cnt;
}
-static int release_nodes(struct device *dev, struct list_head *first,
- struct list_head *end, unsigned long flags)
- __releases(&dev->devres_lock)
+static void release_nodes(struct device *dev, struct list_head *todo)
{
- LIST_HEAD(todo);
- int cnt;
struct devres *dr, *tmp;
- cnt = remove_nodes(dev, first, end, &todo);
-
- spin_unlock_irqrestore(&dev->devres_lock, flags);
-
/* Release. Note that both devres and devres_group are
* handled as devres in the following loop. This is safe.
*/
- list_for_each_entry_safe_reverse(dr, tmp, &todo, node.entry) {
+ list_for_each_entry_safe_reverse(dr, tmp, todo, node.entry) {
devres_log(dev, &dr->node, "REL");
dr->node.release(dev, dr->data);
kfree(dr);
}
-
- return cnt;
}
/**
@@ -537,13 +512,23 @@ static int release_nodes(struct device *dev, struct list_head *first,
int devres_release_all(struct device *dev)
{
unsigned long flags;
+ LIST_HEAD(todo);
+ int cnt;
/* Looks like an uninitialized device structure */
if (WARN_ON(dev->devres_head.next == NULL))
return -ENODEV;
+
+ /* Nothing to release if list is empty */
+ if (list_empty(&dev->devres_head))
+ return 0;
+
spin_lock_irqsave(&dev->devres_lock, flags);
- return release_nodes(dev, dev->devres_head.next, &dev->devres_head,
- flags);
+ cnt = remove_nodes(dev, dev->devres_head.next, &dev->devres_head, &todo);
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+
+ release_nodes(dev, &todo);
+ return cnt;
}
/**
@@ -679,6 +664,7 @@ int devres_release_group(struct device *dev, void *id)
{
struct devres_group *grp;
unsigned long flags;
+ LIST_HEAD(todo);
int cnt = 0;
spin_lock_irqsave(&dev->devres_lock, flags);
@@ -691,7 +677,10 @@ int devres_release_group(struct device *dev, void *id)
if (!list_empty(&grp->node[1].entry))
end = grp->node[1].entry.next;
- cnt = release_nodes(dev, first, end, flags);
+ cnt = remove_nodes(dev, first, end, &todo);
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+
+ release_nodes(dev, &todo);
} else {
WARN_ON(1);
spin_unlock_irqrestore(&dev->devres_lock, flags);
diff --git a/drivers/base/firmware_loader/builtin/Makefile b/drivers/base/firmware_loader/builtin/Makefile
index 5fa7ce3745a0..101754ad48d9 100644
--- a/drivers/base/firmware_loader/builtin/Makefile
+++ b/drivers/base/firmware_loader/builtin/Makefile
@@ -8,7 +8,6 @@ fwdir := $(addprefix $(srctree)/,$(filter-out /%,$(fwdir)))$(filter /%,$(fwdir))
obj-y := $(addsuffix .gen.o, $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE)))
FWNAME = $(patsubst $(obj)/%.gen.S,%,$@)
-comma := ,
FWSTR = $(subst $(comma),_,$(subst /,_,$(subst .,_,$(subst -,_,$(FWNAME)))))
ASM_WORD = $(if $(CONFIG_64BIT),.quad,.long)
ASM_ALIGN = $(if $(CONFIG_64BIT),3,2)
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index d5ffaab3cb61..aa31a21f33d7 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -596,7 +596,7 @@ static struct attribute *memory_memblk_attrs[] = {
NULL
};
-static struct attribute_group memory_memblk_attr_group = {
+static const struct attribute_group memory_memblk_attr_group = {
.attrs = memory_memblk_attrs,
};
@@ -772,7 +772,7 @@ static struct attribute *memory_root_attrs[] = {
NULL
};
-static struct attribute_group memory_root_attr_group = {
+static const struct attribute_group memory_root_attr_group = {
.attrs = memory_root_attrs,
};
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 2c36f61d30bc..4a4ae868ad9f 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -233,7 +233,7 @@ static ssize_t name##_show(struct device *dev, \
return sysfs_emit(buf, fmt "\n", \
to_cache_info(dev)->cache_attrs.name); \
} \
-DEVICE_ATTR_RO(name);
+static DEVICE_ATTR_RO(name);
CACHE_ATTR(size, "%llu")
CACHE_ATTR(line_size, "%u")
@@ -482,6 +482,7 @@ static DEVICE_ATTR(meminfo, 0444, node_read_meminfo, NULL);
static ssize_t node_read_numastat(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ fold_vm_numa_events();
return sysfs_emit(buf,
"numa_hit %lu\n"
"numa_miss %lu\n"
@@ -489,12 +490,12 @@ static ssize_t node_read_numastat(struct device *dev,
"interleave_hit %lu\n"
"local_node %lu\n"
"other_node %lu\n",
- sum_zone_numa_state(dev->id, NUMA_HIT),
- sum_zone_numa_state(dev->id, NUMA_MISS),
- sum_zone_numa_state(dev->id, NUMA_FOREIGN),
- sum_zone_numa_state(dev->id, NUMA_INTERLEAVE_HIT),
- sum_zone_numa_state(dev->id, NUMA_LOCAL),
- sum_zone_numa_state(dev->id, NUMA_OTHER));
+ sum_zone_numa_event_state(dev->id, NUMA_HIT),
+ sum_zone_numa_event_state(dev->id, NUMA_MISS),
+ sum_zone_numa_event_state(dev->id, NUMA_FOREIGN),
+ sum_zone_numa_event_state(dev->id, NUMA_INTERLEAVE_HIT),
+ sum_zone_numa_event_state(dev->id, NUMA_LOCAL),
+ sum_zone_numa_event_state(dev->id, NUMA_OTHER));
}
static DEVICE_ATTR(numastat, 0444, node_read_numastat, NULL);
@@ -512,10 +513,11 @@ static ssize_t node_read_vmstat(struct device *dev,
sum_zone_node_page_state(nid, i));
#ifdef CONFIG_NUMA
- for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++)
+ fold_vm_numa_events();
+ for (i = 0; i < NR_VM_NUMA_EVENT_ITEMS; i++)
len += sysfs_emit_at(buf, len, "%s %lu\n",
numa_stat_name(i),
- sum_zone_numa_state(nid, i));
+ sum_zone_numa_event_state(nid, i));
#endif
for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) {
@@ -1036,7 +1038,7 @@ static struct attribute *node_state_attrs[] = {
NULL
};
-static struct attribute_group memory_root_attr_group = {
+static const struct attribute_group memory_root_attr_group = {
.attrs = node_state_attrs,
};
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 9cd34def2237..8640578f45e9 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -125,26 +125,6 @@ void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev,
EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource);
/**
- * devm_platform_ioremap_resource_wc - write-combined variant of
- * devm_platform_ioremap_resource()
- *
- * @pdev: platform device to use both for memory resource lookup as well as
- * resource management
- * @index: resource index
- *
- * Return: a pointer to the remapped memory or an ERR_PTR() encoded error code
- * on failure.
- */
-void __iomem *devm_platform_ioremap_resource_wc(struct platform_device *pdev,
- unsigned int index)
-{
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, index);
- return devm_ioremap_resource_wc(&pdev->dev, res);
-}
-
-/**
* devm_platform_ioremap_resource_byname - call devm_ioremap_resource for
* a platform device, retrieve the
* resource by name
@@ -1355,7 +1335,7 @@ static umode_t platform_dev_attrs_visible(struct kobject *kobj, struct attribute
return a->mode;
}
-static struct attribute_group platform_dev_group = {
+static const struct attribute_group platform_dev_group = {
.attrs = platform_dev_attrs,
.is_visible = platform_dev_attrs_visible,
};
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index b6a782c31613..a934c679e6ce 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -379,6 +379,44 @@ err:
return ret;
}
+static int genpd_set_performance_state(struct device *dev, unsigned int state)
+{
+ struct generic_pm_domain *genpd = dev_to_genpd(dev);
+ struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
+ unsigned int prev_state;
+ int ret;
+
+ prev_state = gpd_data->performance_state;
+ if (prev_state == state)
+ return 0;
+
+ gpd_data->performance_state = state;
+ state = _genpd_reeval_performance_state(genpd, state);
+
+ ret = _genpd_set_performance_state(genpd, state, 0);
+ if (ret)
+ gpd_data->performance_state = prev_state;
+
+ return ret;
+}
+
+static int genpd_drop_performance_state(struct device *dev)
+{
+ unsigned int prev_state = dev_gpd_data(dev)->performance_state;
+
+ if (!genpd_set_performance_state(dev, 0))
+ return prev_state;
+
+ return 0;
+}
+
+static void genpd_restore_performance_state(struct device *dev,
+ unsigned int state)
+{
+ if (state)
+ genpd_set_performance_state(dev, state);
+}
+
/**
* dev_pm_genpd_set_performance_state- Set performance state of device's power
* domain.
@@ -397,8 +435,6 @@ err:
int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
{
struct generic_pm_domain *genpd;
- struct generic_pm_domain_data *gpd_data;
- unsigned int prev;
int ret;
genpd = dev_to_genpd_safe(dev);
@@ -410,16 +446,7 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
return -EINVAL;
genpd_lock(genpd);
-
- gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
- prev = gpd_data->performance_state;
- gpd_data->performance_state = state;
-
- state = _genpd_reeval_performance_state(genpd, state);
- ret = _genpd_set_performance_state(genpd, state, 0);
- if (ret)
- gpd_data->performance_state = prev;
-
+ ret = genpd_set_performance_state(dev, state);
genpd_unlock(genpd);
return ret;
@@ -572,6 +599,7 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
* RPM status of the releated device is in an intermediate state, not yet turned
* into RPM_SUSPENDED. This means genpd_power_off() must allow one device to not
* be RPM_SUSPENDED, while it tries to power off the PM domain.
+ * @depth: nesting count for lockdep.
*
* If all of the @genpd's devices have been suspended and all of its subdomains
* have been powered down, remove power from @genpd.
@@ -832,7 +860,8 @@ static int genpd_runtime_suspend(struct device *dev)
{
struct generic_pm_domain *genpd;
bool (*suspend_ok)(struct device *__dev);
- struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+ struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
+ struct gpd_timing_data *td = &gpd_data->td;
bool runtime_pm = pm_runtime_enabled(dev);
ktime_t time_start;
s64 elapsed_ns;
@@ -889,6 +918,7 @@ static int genpd_runtime_suspend(struct device *dev)
return 0;
genpd_lock(genpd);
+ gpd_data->rpm_pstate = genpd_drop_performance_state(dev);
genpd_power_off(genpd, true, 0);
genpd_unlock(genpd);
@@ -906,7 +936,8 @@ static int genpd_runtime_suspend(struct device *dev)
static int genpd_runtime_resume(struct device *dev)
{
struct generic_pm_domain *genpd;
- struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+ struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev);
+ struct gpd_timing_data *td = &gpd_data->td;
bool runtime_pm = pm_runtime_enabled(dev);
ktime_t time_start;
s64 elapsed_ns;
@@ -930,6 +961,8 @@ static int genpd_runtime_resume(struct device *dev)
genpd_lock(genpd);
ret = genpd_power_on(genpd, 0);
+ if (!ret)
+ genpd_restore_performance_state(dev, gpd_data->rpm_pstate);
genpd_unlock(genpd);
if (ret)
@@ -968,6 +1001,7 @@ err_stop:
err_poweroff:
if (!pm_runtime_is_irq_safe(dev) || genpd_is_irq_safe(genpd)) {
genpd_lock(genpd);
+ gpd_data->rpm_pstate = genpd_drop_performance_state(dev);
genpd_power_off(genpd, true, 0);
genpd_unlock(genpd);
}
@@ -1984,8 +2018,8 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
mutex_lock(&gpd_list_lock);
list_add(&genpd->gpd_list_node, &gpd_list);
- genpd_debug_add(genpd);
mutex_unlock(&gpd_list_lock);
+ genpd_debug_add(genpd);
return 0;
}
@@ -2172,12 +2206,19 @@ static int genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,
static bool genpd_present(const struct generic_pm_domain *genpd)
{
+ bool ret = false;
const struct generic_pm_domain *gpd;
- list_for_each_entry(gpd, &gpd_list, gpd_list_node)
- if (gpd == genpd)
- return true;
- return false;
+ mutex_lock(&gpd_list_lock);
+ list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
+ if (gpd == genpd) {
+ ret = true;
+ break;
+ }
+ }
+ mutex_unlock(&gpd_list_lock);
+
+ return ret;
}
/**
@@ -2188,15 +2229,13 @@ static bool genpd_present(const struct generic_pm_domain *genpd)
int of_genpd_add_provider_simple(struct device_node *np,
struct generic_pm_domain *genpd)
{
- int ret = -EINVAL;
+ int ret;
if (!np || !genpd)
return -EINVAL;
- mutex_lock(&gpd_list_lock);
-
if (!genpd_present(genpd))
- goto unlock;
+ return -EINVAL;
genpd->dev.of_node = np;
@@ -2207,7 +2246,7 @@ int of_genpd_add_provider_simple(struct device_node *np,
if (ret != -EPROBE_DEFER)
dev_err(&genpd->dev, "Failed to add OPP table: %d\n",
ret);
- goto unlock;
+ return ret;
}
/*
@@ -2225,16 +2264,13 @@ int of_genpd_add_provider_simple(struct device_node *np,
dev_pm_opp_of_remove_table(&genpd->dev);
}
- goto unlock;
+ return ret;
}
genpd->provider = &np->fwnode;
genpd->has_provider = true;
-unlock:
- mutex_unlock(&gpd_list_lock);
-
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(of_genpd_add_provider_simple);
@@ -2253,8 +2289,6 @@ int of_genpd_add_provider_onecell(struct device_node *np,
if (!np || !data)
return -EINVAL;
- mutex_lock(&gpd_list_lock);
-
if (!data->xlate)
data->xlate = genpd_xlate_onecell;
@@ -2294,8 +2328,6 @@ int of_genpd_add_provider_onecell(struct device_node *np,
if (ret < 0)
goto error;
- mutex_unlock(&gpd_list_lock);
-
return 0;
error:
@@ -2314,8 +2346,6 @@ error:
}
}
- mutex_unlock(&gpd_list_lock);
-
return ret;
}
EXPORT_SYMBOL_GPL(of_genpd_add_provider_onecell);
@@ -2505,7 +2535,7 @@ EXPORT_SYMBOL_GPL(of_genpd_remove_subdomain);
/**
* of_genpd_remove_last - Remove the last PM domain registered for a provider
- * @provider: Pointer to device structure associated with provider
+ * @np: Pointer to device node associated with provider
*
* Find the last PM domain that was added by a particular provider and
* remove this PM domain from the list of PM domains. The provider is
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index c6c218758f0b..cd08c5885190 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -252,6 +252,7 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
/**
* _default_power_down_ok - Default generic PM domain power off governor routine.
* @pd: PM domain to check.
+ * @now: current ktime.
*
* This routine must be executed under the PM domain's lock.
*/
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index f893c3c5af07..d568772152c2 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -220,16 +220,13 @@ static void initcall_debug_report(struct device *dev, ktime_t calltime,
void *cb, int error)
{
ktime_t rettime;
- s64 nsecs;
if (!pm_print_times_enabled)
return;
rettime = ktime_get();
- nsecs = (s64) ktime_to_ns(ktime_sub(rettime, calltime));
-
dev_info(dev, "%pS returned %d after %Ld usecs\n", cb, error,
- (unsigned long long)nsecs >> 10);
+ (unsigned long long)ktime_us_delta(rettime, calltime));
}
/**
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index b570848d23e0..8a66eaf731e4 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -345,7 +345,7 @@ static void rpm_suspend_suppliers(struct device *dev)
static int __rpm_callback(int (*cb)(struct device *), struct device *dev)
__releases(&dev->power.lock) __acquires(&dev->power.lock)
{
- int retval, idx;
+ int retval = 0, idx;
bool use_links = dev->power.links_count > 0;
if (dev->power.irq_safe) {
@@ -373,7 +373,8 @@ static int __rpm_callback(int (*cb)(struct device *), struct device *dev)
}
}
- retval = cb(dev);
+ if (cb)
+ retval = cb(dev);
if (dev->power.irq_safe) {
spin_lock(&dev->power.lock);
@@ -446,7 +447,10 @@ static int rpm_idle(struct device *dev, int rpmflags)
/* Pending requests need to be canceled. */
dev->power.request = RPM_REQ_NONE;
- if (dev->power.no_callbacks)
+ callback = RPM_GET_CALLBACK(dev, runtime_idle);
+
+ /* If no callback assume success. */
+ if (!callback || dev->power.no_callbacks)
goto out;
/* Carry out an asynchronous or a synchronous idle notification. */
@@ -462,10 +466,7 @@ static int rpm_idle(struct device *dev, int rpmflags)
dev->power.idle_notification = true;
- callback = RPM_GET_CALLBACK(dev, runtime_idle);
-
- if (callback)
- retval = __rpm_callback(callback, dev);
+ retval = __rpm_callback(callback, dev);
dev->power.idle_notification = false;
wake_up_all(&dev->power.wait_queue);
@@ -484,9 +485,6 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
{
int retval;
- if (!cb)
- return -ENOSYS;
-
if (dev->power.memalloc_noio) {
unsigned int noio_flag;
diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c
index 8e021082dba8..3bad3266a2ad 100644
--- a/drivers/base/power/wakeirq.c
+++ b/drivers/base/power/wakeirq.c
@@ -182,7 +182,6 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
wirq->dev = dev;
wirq->irq = irq;
- irq_set_status_flags(irq, IRQ_NOAUTOEN);
/* Prevent deferred spurious wakeirqs with disable_irq_nosync() */
irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
@@ -192,7 +191,8 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
* so we use a threaded irq.
*/
err = request_threaded_irq(irq, NULL, handle_threaded_wake_irq,
- IRQF_ONESHOT, wirq->name, wirq);
+ IRQF_ONESHOT | IRQF_NO_AUTOEN,
+ wirq->name, wirq);
if (err)
goto err_free_name;
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 1421e9548857..d0874f6c29bb 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -21,7 +21,7 @@
struct fwnode_handle *dev_fwnode(struct device *dev)
{
return IS_ENABLED(CONFIG_OF) && dev->of_node ?
- &dev->of_node->fwnode : dev->fwnode;
+ of_fwnode_handle(dev->of_node) : dev->fwnode;
}
EXPORT_SYMBOL_GPL(dev_fwnode);
@@ -627,14 +627,15 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
*/
struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode)
{
- struct device *dev = NULL;
+ struct device *dev;
fwnode_handle_get(fwnode);
do {
fwnode = fwnode_get_next_parent(fwnode);
- if (fwnode)
- dev = get_dev_from_fwnode(fwnode);
- } while (fwnode && !dev);
+ if (!fwnode)
+ return NULL;
+ dev = get_dev_from_fwnode(fwnode);
+ } while (!dev);
fwnode_handle_put(fwnode);
return dev;
}
@@ -742,10 +743,9 @@ fwnode_get_next_available_child_node(const struct fwnode_handle *fwnode,
do {
next_child = fwnode_get_next_child_node(fwnode, next_child);
-
- if (!next_child || fwnode_device_is_available(next_child))
- break;
- } while (next_child);
+ if (!next_child)
+ return NULL;
+ } while (!fwnode_device_is_available(next_child));
return next_child;
}
@@ -759,13 +759,8 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_available_child_node);
struct fwnode_handle *device_get_next_child_node(struct device *dev,
struct fwnode_handle *child)
{
- struct acpi_device *adev = ACPI_COMPANION(dev);
- struct fwnode_handle *fwnode = NULL, *next;
-
- if (dev->of_node)
- fwnode = &dev->of_node->fwnode;
- else if (adev)
- fwnode = acpi_fwnode_handle(adev);
+ const struct fwnode_handle *fwnode = dev_fwnode(dev);
+ struct fwnode_handle *next;
/* Try to find a child in primary fwnode */
next = fwnode_get_next_child_node(fwnode, child);
@@ -868,28 +863,31 @@ EXPORT_SYMBOL_GPL(device_get_child_node_count);
bool device_dma_supported(struct device *dev)
{
+ const struct fwnode_handle *fwnode = dev_fwnode(dev);
+
/* For DT, this is always supported.
* For ACPI, this depends on CCA, which
* is determined by the acpi_dma_supported().
*/
- if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ if (is_of_node(fwnode))
return true;
- return acpi_dma_supported(ACPI_COMPANION(dev));
+ return acpi_dma_supported(to_acpi_device_node(fwnode));
}
EXPORT_SYMBOL_GPL(device_dma_supported);
enum dev_dma_attr device_get_dma_attr(struct device *dev)
{
+ const struct fwnode_handle *fwnode = dev_fwnode(dev);
enum dev_dma_attr attr = DEV_DMA_NOT_SUPPORTED;
- if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
- if (of_dma_is_coherent(dev->of_node))
+ if (is_of_node(fwnode)) {
+ if (of_dma_is_coherent(to_of_node(fwnode)))
attr = DEV_DMA_COHERENT;
else
attr = DEV_DMA_NON_COHERENT;
} else
- attr = acpi_get_dma_attr(ACPI_COMPANION(dev));
+ attr = acpi_get_dma_attr(to_acpi_device_node(fwnode));
return attr;
}
@@ -1007,14 +1005,13 @@ EXPORT_SYMBOL(device_get_mac_address);
* Returns Linux IRQ number on success. Other values are determined
* accordingly to acpi_/of_ irq_get() operation.
*/
-int fwnode_irq_get(struct fwnode_handle *fwnode, unsigned int index)
+int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index)
{
- struct device_node *of_node = to_of_node(fwnode);
struct resource res;
int ret;
- if (IS_ENABLED(CONFIG_OF) && of_node)
- return of_irq_get(of_node, index);
+ if (is_of_node(fwnode))
+ return of_irq_get(to_of_node(fwnode), index);
ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), index, &res);
if (ret)
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index 50b1e2d06a25..159bac6c5046 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -4,8 +4,9 @@
# 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 || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM)
+ default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO)
select IRQ_DOMAIN if REGMAP_IRQ
+ select MDIO_BUS if REGMAP_MDIO
bool
config REGCACHE_COMPRESSED
@@ -36,6 +37,9 @@ config REGMAP_W1
tristate
depends on W1
+config REGMAP_MDIO
+ tristate
+
config REGMAP_MMIO
tristate
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index 33f63adb5b3d..11facb32a027 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_REGMAP_SOUNDWIRE_MBQ) += regmap-sdw-mbq.o
obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o
obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o
obj-$(CONFIG_REGMAP_SPI_AVMM) += regmap-spi-avmm.o
+obj-$(CONFIG_REGMAP_MDIO) += regmap-mdio.o
diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c
index 62b95a9212ae..980e5ce6a3a3 100644
--- a/drivers/base/regmap/regmap-i2c.c
+++ b/drivers/base/regmap/regmap-i2c.c
@@ -306,33 +306,64 @@ static const struct regmap_bus regmap_i2c_smbus_i2c_block_reg16 = {
static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
const struct regmap_config *config)
{
+ const struct i2c_adapter_quirks *quirks;
+ const struct regmap_bus *bus = NULL;
+ struct regmap_bus *ret_bus;
+ u16 max_read = 0, max_write = 0;
+
if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
- return &regmap_i2c;
+ bus = &regmap_i2c;
else if (config->val_bits == 8 && config->reg_bits == 8 &&
i2c_check_functionality(i2c->adapter,
I2C_FUNC_SMBUS_I2C_BLOCK))
- return &regmap_i2c_smbus_i2c_block;
+ bus = &regmap_i2c_smbus_i2c_block;
else if (config->val_bits == 8 && config->reg_bits == 16 &&
i2c_check_functionality(i2c->adapter,
I2C_FUNC_SMBUS_I2C_BLOCK))
- return &regmap_i2c_smbus_i2c_block_reg16;
+ bus = &regmap_i2c_smbus_i2c_block_reg16;
else if (config->val_bits == 16 && config->reg_bits == 8 &&
i2c_check_functionality(i2c->adapter,
I2C_FUNC_SMBUS_WORD_DATA))
switch (regmap_get_val_endian(&i2c->dev, NULL, config)) {
case REGMAP_ENDIAN_LITTLE:
- return &regmap_smbus_word;
+ bus = &regmap_smbus_word;
+ break;
case REGMAP_ENDIAN_BIG:
- return &regmap_smbus_word_swapped;
+ bus = &regmap_smbus_word_swapped;
+ break;
default: /* everything else is not supported */
break;
}
else if (config->val_bits == 8 && config->reg_bits == 8 &&
i2c_check_functionality(i2c->adapter,
I2C_FUNC_SMBUS_BYTE_DATA))
- return &regmap_smbus_byte;
+ bus = &regmap_smbus_byte;
+
+ if (!bus)
+ return ERR_PTR(-ENOTSUPP);
+
+ quirks = i2c->adapter->quirks;
+ if (quirks) {
+ if (quirks->max_read_len &&
+ (bus->max_raw_read == 0 || bus->max_raw_read > quirks->max_read_len))
+ max_read = quirks->max_read_len;
+
+ if (quirks->max_write_len &&
+ (bus->max_raw_write == 0 || bus->max_raw_write > quirks->max_write_len))
+ max_write = quirks->max_write_len;
+
+ if (max_read || max_write) {
+ ret_bus = kmemdup(bus, sizeof(*bus), GFP_KERNEL);
+ if (!ret_bus)
+ return ERR_PTR(-ENOMEM);
+ ret_bus->free_on_exit = true;
+ ret_bus->max_raw_read = max_read;
+ ret_bus->max_raw_write = max_write;
+ bus = ret_bus;
+ }
+ }
- return ERR_PTR(-ENOTSUPP);
+ return bus;
}
struct regmap *__regmap_init_i2c(struct i2c_client *i2c,
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 760296a4b606..d2656581a608 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -531,6 +531,10 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
}
}
+ if (chip->status_invert)
+ for (i = 0; i < data->chip->num_regs; i++)
+ data->status_buf[i] = ~data->status_buf[i];
+
/*
* Ignore masked IRQs and ack if we need to; we ack early so
* there is no race between handling and acknowleding the
@@ -800,6 +804,9 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
goto err_alloc;
}
+ if (chip->status_invert)
+ d->status_buf[i] = ~d->status_buf[i];
+
if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) {
reg = sub_irq_reg(d, d->chip->ack_base, i);
if (chip->ack_invert)
diff --git a/drivers/base/regmap/regmap-mdio.c b/drivers/base/regmap/regmap-mdio.c
new file mode 100644
index 000000000000..6a20201299f5
--- /dev/null
+++ b/drivers/base/regmap/regmap-mdio.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/errno.h>
+#include <linux/mdio.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#define REGVAL_MASK GENMASK(15, 0)
+#define REGNUM_C22_MASK GENMASK(4, 0)
+/* Clause-45 mask includes the device type (5 bit) and actual register number (16 bit) */
+#define REGNUM_C45_MASK GENMASK(20, 0)
+
+static int regmap_mdio_read(struct mdio_device *mdio_dev, u32 reg, unsigned int *val)
+{
+ int ret;
+
+ ret = mdiobus_read(mdio_dev->bus, mdio_dev->addr, reg);
+ if (ret < 0)
+ return ret;
+
+ *val = ret & REGVAL_MASK;
+ return 0;
+}
+
+static int regmap_mdio_write(struct mdio_device *mdio_dev, u32 reg, unsigned int val)
+{
+ return mdiobus_write(mdio_dev->bus, mdio_dev->addr, reg, val);
+}
+
+static int regmap_mdio_c22_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct mdio_device *mdio_dev = context;
+
+ if (unlikely(reg & ~REGNUM_C22_MASK))
+ return -ENXIO;
+
+ return regmap_mdio_read(mdio_dev, reg, val);
+}
+
+static int regmap_mdio_c22_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct mdio_device *mdio_dev = context;
+
+ if (unlikely(reg & ~REGNUM_C22_MASK))
+ return -ENXIO;
+
+ return mdiobus_write(mdio_dev->bus, mdio_dev->addr, reg, val);
+}
+
+static const struct regmap_bus regmap_mdio_c22_bus = {
+ .reg_write = regmap_mdio_c22_write,
+ .reg_read = regmap_mdio_c22_read,
+};
+
+static int regmap_mdio_c45_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct mdio_device *mdio_dev = context;
+
+ if (unlikely(reg & ~REGNUM_C45_MASK))
+ return -ENXIO;
+
+ return regmap_mdio_read(mdio_dev, MII_ADDR_C45 | reg, val);
+}
+
+static int regmap_mdio_c45_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct mdio_device *mdio_dev = context;
+
+ if (unlikely(reg & ~REGNUM_C45_MASK))
+ return -ENXIO;
+
+ return regmap_mdio_write(mdio_dev, MII_ADDR_C45 | reg, val);
+}
+
+static const struct regmap_bus regmap_mdio_c45_bus = {
+ .reg_write = regmap_mdio_c45_write,
+ .reg_read = regmap_mdio_c45_read,
+};
+
+struct regmap *__regmap_init_mdio(struct mdio_device *mdio_dev,
+ const struct regmap_config *config, struct lock_class_key *lock_key,
+ const char *lock_name)
+{
+ const struct regmap_bus *bus;
+
+ if (config->reg_bits == 5 && config->val_bits == 16)
+ bus = &regmap_mdio_c22_bus;
+ else if (config->reg_bits == 21 && config->val_bits == 16)
+ bus = &regmap_mdio_c45_bus;
+ else
+ return ERR_PTR(-EOPNOTSUPP);
+
+ return __regmap_init(&mdio_dev->dev, bus, mdio_dev, config, lock_key, lock_name);
+}
+EXPORT_SYMBOL_GPL(__regmap_init_mdio);
+
+struct regmap *__devm_regmap_init_mdio(struct mdio_device *mdio_dev,
+ const struct regmap_config *config, struct lock_class_key *lock_key,
+ const char *lock_name)
+{
+ const struct regmap_bus *bus;
+
+ if (config->reg_bits == 5 && config->val_bits == 16)
+ bus = &regmap_mdio_c22_bus;
+ else if (config->reg_bits == 21 && config->val_bits == 16)
+ bus = &regmap_mdio_c45_bus;
+ else
+ return ERR_PTR(-EOPNOTSUPP);
+
+ return __devm_regmap_init(&mdio_dev->dev, bus, mdio_dev, config, lock_key, lock_name);
+}
+EXPORT_SYMBOL_GPL(__devm_regmap_init_mdio);
+
+MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
+MODULE_DESCRIPTION("Regmap MDIO Module");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 297e95be25b3..fe3e38dd5324 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -243,6 +243,16 @@ static void regmap_format_7_9_write(struct regmap *map,
*out = cpu_to_be16((reg << 9) | val);
}
+static void regmap_format_7_17_write(struct regmap *map,
+ unsigned int reg, unsigned int val)
+{
+ u8 *out = map->work_buf;
+
+ out[2] = val;
+ out[1] = val >> 8;
+ out[0] = (val >> 16) | (reg << 1);
+}
+
static void regmap_format_10_14_write(struct regmap *map,
unsigned int reg, unsigned int val)
{
@@ -885,6 +895,9 @@ struct regmap *__regmap_init(struct device *dev,
case 9:
map->format.format_write = regmap_format_7_9_write;
break;
+ case 17:
+ map->format.format_write = regmap_format_7_17_write;
+ break;
default:
goto err_hwlock;
}
@@ -1496,6 +1509,8 @@ void regmap_exit(struct regmap *map)
mutex_destroy(&map->mutex);
kfree_const(map->name);
kfree(map->patch);
+ if (map->bus && map->bus->free_on_exit)
+ kfree(map->bus);
kfree(map);
}
EXPORT_SYMBOL_GPL(regmap_exit);
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index 3cc11b813f28..d1f1a8240120 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -1045,7 +1045,15 @@ int device_add_software_node(struct device *dev, const struct software_node *nod
}
set_secondary_fwnode(dev, &swnode->fwnode);
- software_node_notify(dev, KOBJ_ADD);
+
+ /*
+ * If the device has been fully registered by the time this function is
+ * called, software_node_notify() must be called separately so that the
+ * symlinks get created and the reference count of the node is kept in
+ * balance.
+ */
+ if (device_is_registered(dev))
+ software_node_notify(dev, KOBJ_ADD);
return 0;
}
@@ -1065,7 +1073,8 @@ void device_remove_software_node(struct device *dev)
if (!swnode)
return;
- software_node_notify(dev, KOBJ_REMOVE);
+ if (device_is_registered(dev))
+ software_node_notify(dev, KOBJ_REMOVE);
set_secondary_fwnode(dev, NULL);
kobject_put(&swnode->kobj);
}
@@ -1119,8 +1128,7 @@ int software_node_notify(struct device *dev, unsigned long action)
switch (action) {
case KOBJ_ADD:
- ret = sysfs_create_link_nowarn(&dev->kobj, &swnode->kobj,
- "software_node");
+ ret = sysfs_create_link(&dev->kobj, &swnode->kobj, "software_node");
if (ret)
break;
diff --git a/drivers/base/test/property-entry-test.c b/drivers/base/test/property-entry-test.c
index 1106fedcceed..6071d5bc128c 100644
--- a/drivers/base/test/property-entry-test.c
+++ b/drivers/base/test/property-entry-test.c
@@ -32,11 +32,11 @@ static void pe_test_uints(struct kunit *test)
error = fwnode_property_read_u8(node, "prop-u8", &val_u8);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)val_u8, 8);
+ KUNIT_EXPECT_EQ(test, val_u8, 8);
error = fwnode_property_read_u8_array(node, "prop-u8", array_u8, 1);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)array_u8[0], 8);
+ KUNIT_EXPECT_EQ(test, array_u8[0], 8);
error = fwnode_property_read_u8_array(node, "prop-u8", array_u8, 2);
KUNIT_EXPECT_NE(test, error, 0);
@@ -49,14 +49,14 @@ static void pe_test_uints(struct kunit *test)
error = fwnode_property_read_u16(node, "prop-u16", &val_u16);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)val_u16, 16);
+ KUNIT_EXPECT_EQ(test, val_u16, 16);
error = fwnode_property_count_u16(node, "prop-u16");
KUNIT_EXPECT_EQ(test, error, 1);
error = fwnode_property_read_u16_array(node, "prop-u16", array_u16, 1);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)array_u16[0], 16);
+ KUNIT_EXPECT_EQ(test, array_u16[0], 16);
error = fwnode_property_read_u16_array(node, "prop-u16", array_u16, 2);
KUNIT_EXPECT_NE(test, error, 0);
@@ -69,14 +69,14 @@ static void pe_test_uints(struct kunit *test)
error = fwnode_property_read_u32(node, "prop-u32", &val_u32);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)val_u32, 32);
+ KUNIT_EXPECT_EQ(test, val_u32, 32);
error = fwnode_property_count_u32(node, "prop-u32");
KUNIT_EXPECT_EQ(test, error, 1);
error = fwnode_property_read_u32_array(node, "prop-u32", array_u32, 1);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)array_u32[0], 32);
+ KUNIT_EXPECT_EQ(test, array_u32[0], 32);
error = fwnode_property_read_u32_array(node, "prop-u32", array_u32, 2);
KUNIT_EXPECT_NE(test, error, 0);
@@ -89,14 +89,14 @@ static void pe_test_uints(struct kunit *test)
error = fwnode_property_read_u64(node, "prop-u64", &val_u64);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)val_u64, 64);
+ KUNIT_EXPECT_EQ(test, val_u64, 64);
error = fwnode_property_count_u64(node, "prop-u64");
KUNIT_EXPECT_EQ(test, error, 1);
error = fwnode_property_read_u64_array(node, "prop-u64", array_u64, 1);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)array_u64[0], 64);
+ KUNIT_EXPECT_EQ(test, array_u64[0], 64);
error = fwnode_property_read_u64_array(node, "prop-u64", array_u64, 2);
KUNIT_EXPECT_NE(test, error, 0);
@@ -140,19 +140,19 @@ static void pe_test_uint_arrays(struct kunit *test)
error = fwnode_property_read_u8(node, "prop-u8", &val_u8);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)val_u8, 8);
+ KUNIT_EXPECT_EQ(test, val_u8, 8);
error = fwnode_property_count_u8(node, "prop-u8");
KUNIT_EXPECT_EQ(test, error, 10);
error = fwnode_property_read_u8_array(node, "prop-u8", array_u8, 1);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)array_u8[0], 8);
+ KUNIT_EXPECT_EQ(test, array_u8[0], 8);
error = fwnode_property_read_u8_array(node, "prop-u8", array_u8, 2);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)array_u8[0], 8);
- KUNIT_EXPECT_EQ(test, (int)array_u8[1], 9);
+ KUNIT_EXPECT_EQ(test, array_u8[0], 8);
+ KUNIT_EXPECT_EQ(test, array_u8[1], 9);
error = fwnode_property_read_u8_array(node, "prop-u8", array_u8, 17);
KUNIT_EXPECT_NE(test, error, 0);
@@ -165,19 +165,19 @@ static void pe_test_uint_arrays(struct kunit *test)
error = fwnode_property_read_u16(node, "prop-u16", &val_u16);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)val_u16, 16);
+ KUNIT_EXPECT_EQ(test, val_u16, 16);
error = fwnode_property_count_u16(node, "prop-u16");
KUNIT_EXPECT_EQ(test, error, 10);
error = fwnode_property_read_u16_array(node, "prop-u16", array_u16, 1);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)array_u16[0], 16);
+ KUNIT_EXPECT_EQ(test, array_u16[0], 16);
error = fwnode_property_read_u16_array(node, "prop-u16", array_u16, 2);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)array_u16[0], 16);
- KUNIT_EXPECT_EQ(test, (int)array_u16[1], 17);
+ KUNIT_EXPECT_EQ(test, array_u16[0], 16);
+ KUNIT_EXPECT_EQ(test, array_u16[1], 17);
error = fwnode_property_read_u16_array(node, "prop-u16", array_u16, 17);
KUNIT_EXPECT_NE(test, error, 0);
@@ -190,19 +190,19 @@ static void pe_test_uint_arrays(struct kunit *test)
error = fwnode_property_read_u32(node, "prop-u32", &val_u32);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)val_u32, 32);
+ KUNIT_EXPECT_EQ(test, val_u32, 32);
error = fwnode_property_count_u32(node, "prop-u32");
KUNIT_EXPECT_EQ(test, error, 10);
error = fwnode_property_read_u32_array(node, "prop-u32", array_u32, 1);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)array_u32[0], 32);
+ KUNIT_EXPECT_EQ(test, array_u32[0], 32);
error = fwnode_property_read_u32_array(node, "prop-u32", array_u32, 2);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)array_u32[0], 32);
- KUNIT_EXPECT_EQ(test, (int)array_u32[1], 33);
+ KUNIT_EXPECT_EQ(test, array_u32[0], 32);
+ KUNIT_EXPECT_EQ(test, array_u32[1], 33);
error = fwnode_property_read_u32_array(node, "prop-u32", array_u32, 17);
KUNIT_EXPECT_NE(test, error, 0);
@@ -215,19 +215,19 @@ static void pe_test_uint_arrays(struct kunit *test)
error = fwnode_property_read_u64(node, "prop-u64", &val_u64);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)val_u64, 64);
+ KUNIT_EXPECT_EQ(test, val_u64, 64);
error = fwnode_property_count_u64(node, "prop-u64");
KUNIT_EXPECT_EQ(test, error, 10);
error = fwnode_property_read_u64_array(node, "prop-u64", array_u64, 1);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)array_u64[0], 64);
+ KUNIT_EXPECT_EQ(test, array_u64[0], 64);
error = fwnode_property_read_u64_array(node, "prop-u64", array_u64, 2);
KUNIT_EXPECT_EQ(test, error, 0);
- KUNIT_EXPECT_EQ(test, (int)array_u64[0], 64);
- KUNIT_EXPECT_EQ(test, (int)array_u64[1], 65);
+ KUNIT_EXPECT_EQ(test, array_u64[0], 64);
+ KUNIT_EXPECT_EQ(test, array_u64[1], 65);
error = fwnode_property_read_u64_array(node, "prop-u64", array_u64, 17);
KUNIT_EXPECT_NE(test, error, 0);
@@ -358,13 +358,13 @@ static void pe_test_move_inline_u8(struct kunit *test)
KUNIT_EXPECT_TRUE(test, copy[0].is_inline);
data_ptr = (u8 *)&copy[0].value;
- KUNIT_EXPECT_EQ(test, (int)data_ptr[0], 1);
- KUNIT_EXPECT_EQ(test, (int)data_ptr[1], 2);
+ KUNIT_EXPECT_EQ(test, data_ptr[0], 1);
+ KUNIT_EXPECT_EQ(test, data_ptr[1], 2);
KUNIT_EXPECT_FALSE(test, copy[1].is_inline);
data_ptr = copy[1].pointer;
- KUNIT_EXPECT_EQ(test, (int)data_ptr[0], 5);
- KUNIT_EXPECT_EQ(test, (int)data_ptr[1], 6);
+ KUNIT_EXPECT_EQ(test, data_ptr[0], 5);
+ KUNIT_EXPECT_EQ(test, data_ptr[1], 6);
property_entries_free(copy);
}
diff --git a/drivers/base/trace.c b/drivers/base/trace.c
new file mode 100644
index 000000000000..b24b0a309c4a
--- /dev/null
+++ b/drivers/base/trace.c
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Device core Trace Support
+ * Copyright (C) 2021, Intel Corporation
+ *
+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ */
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
diff --git a/drivers/base/trace.h b/drivers/base/trace.h
new file mode 100644
index 000000000000..3192e18f877e
--- /dev/null
+++ b/drivers/base/trace.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Device core Trace Support
+ * Copyright (C) 2021, Intel Corporation
+ *
+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM dev
+
+#if !defined(__DEV_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __DEV_TRACE_H
+
+#include <linux/device.h>
+#include <linux/tracepoint.h>
+#include <linux/types.h>
+
+DECLARE_EVENT_CLASS(devres,
+ TP_PROTO(struct device *dev, const char *op, void *node, const char *name, size_t size),
+ TP_ARGS(dev, op, node, name, size),
+ TP_STRUCT__entry(
+ __string(devname, dev_name(dev))
+ __field(struct device *, dev)
+ __field(const char *, op)
+ __field(void *, node)
+ __field(const char *, name)
+ __field(size_t, size)
+ ),
+ TP_fast_assign(
+ __assign_str(devname, dev_name(dev));
+ __entry->op = op;
+ __entry->node = node;
+ __entry->name = name;
+ __entry->size = size;
+ ),
+ TP_printk("%s %3s %p %s (%zu bytes)", __get_str(devname),
+ __entry->op, __entry->node, __entry->name, __entry->size)
+);
+
+DEFINE_EVENT(devres, devres_log,
+ TP_PROTO(struct device *dev, const char *op, void *node, const char *name, size_t size),
+ TP_ARGS(dev, op, node, name, size)
+);
+
+#endif /* __DEV_TRACE_H */
+
+/* this part has to be here */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 9e2d0c6a3877..8b1714021498 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1781,15 +1781,13 @@ static int fd_alloc_disk(int drive, int system)
{
struct gendisk *disk;
- disk = alloc_disk(1);
- if (!disk)
- goto out;
- disk->queue = blk_mq_init_queue(&unit[drive].tag_set);
- if (IS_ERR(disk->queue))
- goto out_put_disk;
+ disk = blk_mq_alloc_disk(&unit[drive].tag_set, NULL);
+ if (IS_ERR(disk))
+ return PTR_ERR(disk);
disk->major = FLOPPY_MAJOR;
disk->first_minor = drive + system;
+ disk->minors = 1;
disk->fops = &floppy_fops;
disk->events = DISK_EVENT_MEDIA_CHANGE;
if (system)
@@ -1802,12 +1800,6 @@ static int fd_alloc_disk(int drive, int system)
unit[drive].gendisk[system] = disk;
add_disk(disk);
return 0;
-
-out_put_disk:
- disk->queue = NULL;
- put_disk(disk);
-out:
- return -ENOMEM;
}
static int fd_alloc_drive(int drive)
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index c34e71b0c4a9..06b360f7123a 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -338,14 +338,13 @@ static const struct blk_mq_ops aoeblk_mq_ops = {
.queue_rq = aoeblk_queue_rq,
};
-/* alloc_disk and add_disk can sleep */
+/* blk_mq_alloc_disk and add_disk can sleep */
void
aoeblk_gdalloc(void *vp)
{
struct aoedev *d = vp;
struct gendisk *gd;
mempool_t *mp;
- struct request_queue *q;
struct blk_mq_tag_set *set;
ulong flags;
int late = 0;
@@ -362,19 +361,12 @@ aoeblk_gdalloc(void *vp)
if (late)
return;
- gd = alloc_disk(AOE_PARTITIONS);
- if (gd == NULL) {
- pr_err("aoe: cannot allocate disk structure for %ld.%d\n",
- d->aoemajor, d->aoeminor);
- goto err;
- }
-
mp = mempool_create(MIN_BUFS, mempool_alloc_slab, mempool_free_slab,
buf_pool_cache);
if (mp == NULL) {
printk(KERN_ERR "aoe: cannot allocate bufpool for %ld.%d\n",
d->aoemajor, d->aoeminor);
- goto err_disk;
+ goto err;
}
set = &d->tag_set;
@@ -391,12 +383,11 @@ aoeblk_gdalloc(void *vp)
goto err_mempool;
}
- q = blk_mq_init_queue(set);
- if (IS_ERR(q)) {
+ gd = blk_mq_alloc_disk(set, d);
+ if (IS_ERR(gd)) {
pr_err("aoe: cannot allocate block queue for %ld.%d\n",
d->aoemajor, d->aoeminor);
- blk_mq_free_tag_set(set);
- goto err_mempool;
+ goto err_tagset;
}
spin_lock_irqsave(&d->lock, flags);
@@ -405,16 +396,16 @@ aoeblk_gdalloc(void *vp)
WARN_ON(d->flags & DEVFL_TKILL);
WARN_ON(d->gd);
WARN_ON(d->flags & DEVFL_UP);
- blk_queue_max_hw_sectors(q, BLK_DEF_MAX_SECTORS);
- blk_queue_io_opt(q, SZ_2M);
+ blk_queue_max_hw_sectors(gd->queue, BLK_DEF_MAX_SECTORS);
+ blk_queue_io_opt(gd->queue, SZ_2M);
d->bufpool = mp;
- d->blkq = gd->queue = q;
- q->queuedata = d;
+ d->blkq = gd->queue;
d->gd = gd;
if (aoe_maxsectors)
- blk_queue_max_hw_sectors(q, aoe_maxsectors);
+ blk_queue_max_hw_sectors(gd->queue, aoe_maxsectors);
gd->major = AOE_MAJOR;
gd->first_minor = d->sysminor;
+ gd->minors = AOE_PARTITIONS;
gd->fops = &aoe_bdops;
gd->private_data = d;
set_capacity(gd, d->ssize);
@@ -435,10 +426,10 @@ aoeblk_gdalloc(void *vp)
spin_unlock_irqrestore(&d->lock, flags);
return;
+err_tagset:
+ blk_mq_free_tag_set(set);
err_mempool:
mempool_destroy(mp);
-err_disk:
- put_disk(gd);
err:
spin_lock_irqsave(&d->lock, flags);
d->flags &= ~DEVFL_GD_NOW;
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
index ab41be625a53..8eea2529da20 100644
--- a/drivers/block/aoe/aoechr.c
+++ b/drivers/block/aoe/aoechr.c
@@ -140,10 +140,8 @@ bail: spin_unlock_irqrestore(&emsgs_lock, flags);
}
mp = kmemdup(msg, n, GFP_ATOMIC);
- if (mp == NULL) {
- printk(KERN_ERR "aoe: allocation failure, len=%ld\n", n);
+ if (!mp)
goto bail;
- }
em->msg = mp;
em->flags |= EMFL_VALID;
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index ecd77897a761..588889bea7c3 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -1701,8 +1701,6 @@ aoecmd_init(void)
goto ktiowq_fail;
}
- mutex_init(&ktio_spawn_lock);
-
for (i = 0; i < ncpus; i++) {
INIT_LIST_HEAD(&iocq[i].head);
spin_lock_init(&iocq[i].lock);
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index e2ea2356da06..c5753c6bfe80 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -277,9 +277,8 @@ freedev(struct aoedev *d)
if (d->gd) {
aoedisk_rm_debugfs(d);
del_gendisk(d->gd);
- put_disk(d->gd);
+ blk_cleanup_disk(d->gd);
blk_mq_free_tag_set(&d->tag_set);
- blk_cleanup_queue(d->blkq);
}
t = d->targets;
e = t + d->ntargets;
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index d601e49f80e0..a093644ac39f 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1968,22 +1968,14 @@ static const struct blk_mq_ops ataflop_mq_ops = {
static int ataflop_alloc_disk(unsigned int drive, unsigned int type)
{
struct gendisk *disk;
- int ret;
-
- disk = alloc_disk(1);
- if (!disk)
- return -ENOMEM;
- disk->queue = blk_mq_init_queue(&unit[drive].tag_set);
- if (IS_ERR(disk->queue)) {
- ret = PTR_ERR(disk->queue);
- disk->queue = NULL;
- put_disk(disk);
- return ret;
- }
+ disk = blk_mq_alloc_disk(&unit[drive].tag_set, NULL);
+ if (IS_ERR(disk))
+ return PTR_ERR(disk);
disk->major = FLOPPY_MAJOR;
disk->first_minor = drive + (type << 2);
+ disk->minors = 1;
sprintf(disk->disk_name, "fd%d", drive);
disk->fops = &floppy_fops;
disk->events = DISK_EVENT_MEDIA_CHANGE;
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index 7562cf30b14e..95694113e38e 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -38,9 +38,7 @@
* device).
*/
struct brd_device {
- int brd_number;
-
- struct request_queue *brd_queue;
+ int brd_number;
struct gendisk *brd_disk;
struct list_head brd_list;
@@ -372,7 +370,7 @@ static LIST_HEAD(brd_devices);
static DEFINE_MUTEX(brd_devices_mutex);
static struct dentry *brd_debugfs_dir;
-static struct brd_device *brd_alloc(int i)
+static int brd_alloc(int i)
{
struct brd_device *brd;
struct gendisk *disk;
@@ -380,64 +378,55 @@ static struct brd_device *brd_alloc(int i)
brd = kzalloc(sizeof(*brd), GFP_KERNEL);
if (!brd)
- goto out;
+ return -ENOMEM;
brd->brd_number = i;
spin_lock_init(&brd->brd_lock);
INIT_RADIX_TREE(&brd->brd_pages, GFP_ATOMIC);
- brd->brd_queue = blk_alloc_queue(NUMA_NO_NODE);
- if (!brd->brd_queue)
- goto out_free_dev;
-
snprintf(buf, DISK_NAME_LEN, "ram%d", i);
if (!IS_ERR_OR_NULL(brd_debugfs_dir))
debugfs_create_u64(buf, 0444, brd_debugfs_dir,
&brd->brd_nr_pages);
- /* This is so fdisk will align partitions on 4k, because of
- * direct_access API needing 4k alignment, returning a PFN
- * (This is only a problem on very small devices <= 4M,
- * otherwise fdisk will align on 1M. Regardless this call
- * is harmless)
- */
- blk_queue_physical_block_size(brd->brd_queue, PAGE_SIZE);
- disk = brd->brd_disk = alloc_disk(max_part);
+ disk = brd->brd_disk = blk_alloc_disk(NUMA_NO_NODE);
if (!disk)
- goto out_free_queue;
+ goto out_free_dev;
+
disk->major = RAMDISK_MAJOR;
disk->first_minor = i * max_part;
+ disk->minors = max_part;
disk->fops = &brd_fops;
disk->private_data = brd;
disk->flags = GENHD_FL_EXT_DEVT;
strlcpy(disk->disk_name, buf, DISK_NAME_LEN);
set_capacity(disk, rd_size * 2);
+
+ /*
+ * This is so fdisk will align partitions on 4k, because of
+ * direct_access API needing 4k alignment, returning a PFN
+ * (This is only a problem on very small devices <= 4M,
+ * otherwise fdisk will align on 1M. Regardless this call
+ * is harmless)
+ */
+ blk_queue_physical_block_size(disk->queue, PAGE_SIZE);
/* Tell the block layer that this is not a rotational device */
- blk_queue_flag_set(QUEUE_FLAG_NONROT, brd->brd_queue);
- blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, brd->brd_queue);
+ blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue);
+ blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, disk->queue);
+ add_disk(disk);
+ list_add_tail(&brd->brd_list, &brd_devices);
- return brd;
+ return 0;
-out_free_queue:
- blk_cleanup_queue(brd->brd_queue);
out_free_dev:
kfree(brd);
-out:
- return NULL;
-}
-
-static void brd_free(struct brd_device *brd)
-{
- put_disk(brd->brd_disk);
- blk_cleanup_queue(brd->brd_queue);
- brd_free_pages(brd);
- kfree(brd);
+ return -ENOMEM;
}
static void brd_probe(dev_t dev)
{
- struct brd_device *brd;
int i = MINOR(dev) / max_part;
+ struct brd_device *brd;
mutex_lock(&brd_devices_mutex);
list_for_each_entry(brd, &brd_devices, brd_list) {
@@ -445,13 +434,7 @@ static void brd_probe(dev_t dev)
goto out_unlock;
}
- brd = brd_alloc(i);
- if (brd) {
- brd->brd_disk->queue = brd->brd_queue;
- add_disk(brd->brd_disk);
- list_add_tail(&brd->brd_list, &brd_devices);
- }
-
+ brd_alloc(i);
out_unlock:
mutex_unlock(&brd_devices_mutex);
}
@@ -460,7 +443,9 @@ static void brd_del_one(struct brd_device *brd)
{
list_del(&brd->brd_list);
del_gendisk(brd->brd_disk);
- brd_free(brd);
+ blk_cleanup_disk(brd->brd_disk);
+ brd_free_pages(brd);
+ kfree(brd);
}
static inline void brd_check_and_reset_par(void)
@@ -485,7 +470,7 @@ static inline void brd_check_and_reset_par(void)
static int __init brd_init(void)
{
struct brd_device *brd, *next;
- int i;
+ int err, i;
/*
* brd module now has a feature to instantiate underlying device
@@ -511,22 +496,11 @@ static int __init brd_init(void)
mutex_lock(&brd_devices_mutex);
for (i = 0; i < rd_nr; i++) {
- brd = brd_alloc(i);
- if (!brd)
+ err = brd_alloc(i);
+ if (err)
goto out_free;
- list_add_tail(&brd->brd_list, &brd_devices);
}
- /* point of no return */
-
- list_for_each_entry(brd, &brd_devices, brd_list) {
- /*
- * associate with queue just before adding disk for
- * avoiding to mess up failure path
- */
- brd->brd_disk->queue = brd->brd_queue;
- add_disk(brd->brd_disk);
- }
mutex_unlock(&brd_devices_mutex);
pr_info("brd: module loaded\n");
@@ -535,15 +509,13 @@ static int __init brd_init(void)
out_free:
debugfs_remove_recursive(brd_debugfs_dir);
- list_for_each_entry_safe(brd, next, &brd_devices, brd_list) {
- list_del(&brd->brd_list);
- brd_free(brd);
- }
+ list_for_each_entry_safe(brd, next, &brd_devices, brd_list)
+ brd_del_one(brd);
mutex_unlock(&brd_devices_mutex);
unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
pr_info("brd: module NOT loaded !!!\n");
- return -ENOMEM;
+ return err;
}
static void __exit brd_exit(void)
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index de463773b530..55234a558e98 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -2231,8 +2231,7 @@ void drbd_destroy_device(struct kref *kref)
if (device->bitmap) /* should no longer be there. */
drbd_bm_cleanup(device);
__free_page(device->md_io.page);
- put_disk(device->vdisk);
- blk_cleanup_queue(device->rq_queue);
+ blk_cleanup_disk(device->vdisk);
kfree(device->rs_plan_s);
/* not for_each_connection(connection, resource):
@@ -2701,7 +2700,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
struct drbd_device *device;
struct drbd_peer_device *peer_device, *tmp_peer_device;
struct gendisk *disk;
- struct request_queue *q;
int id;
int vnr = adm_ctx->volume;
enum drbd_ret_code err = ERR_NOMEM;
@@ -2723,29 +2721,26 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
drbd_init_set_defaults(device);
- q = blk_alloc_queue(NUMA_NO_NODE);
- if (!q)
- goto out_no_q;
- device->rq_queue = q;
-
- disk = alloc_disk(1);
+ disk = blk_alloc_disk(NUMA_NO_NODE);
if (!disk)
goto out_no_disk;
+
device->vdisk = disk;
+ device->rq_queue = disk->queue;
set_disk_ro(disk, true);
- disk->queue = q;
disk->major = DRBD_MAJOR;
disk->first_minor = minor;
+ disk->minors = 1;
disk->fops = &drbd_ops;
sprintf(disk->disk_name, "drbd%d", minor);
disk->private_data = device;
- blk_queue_write_cache(q, true, true);
+ blk_queue_write_cache(disk->queue, true, true);
/* Setting the max_hw_sectors to an odd value of 8kibyte here
This triggers a max_bio_size message upon first attach or connect */
- blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE_SAFE >> 8);
+ blk_queue_max_hw_sectors(disk->queue, DRBD_MAX_BIO_SIZE_SAFE >> 8);
device->md_io.page = alloc_page(GFP_KERNEL);
if (!device->md_io.page)
@@ -2834,10 +2829,8 @@ out_no_minor_idr:
out_no_bitmap:
__free_page(device->md_io.page);
out_no_io_page:
- put_disk(disk);
+ blk_cleanup_disk(disk);
out_no_disk:
- blk_cleanup_queue(q);
-out_no_q:
kref_put(&resource->kref, drbd_destroy_resource);
kfree(device);
return err;
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 69284ebba786..1f740e42e457 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -3770,10 +3770,8 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in
}
new_net_conf = kmalloc(sizeof(struct net_conf), GFP_KERNEL);
- if (!new_net_conf) {
- drbd_err(connection, "Allocation of new net_conf failed\n");
+ if (!new_net_conf)
goto disconnect;
- }
mutex_lock(&connection->data.mutex);
mutex_lock(&connection->resource->conf_update);
@@ -4020,10 +4018,8 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i
if (verify_tfm || csums_tfm) {
new_net_conf = kzalloc(sizeof(struct net_conf), GFP_KERNEL);
- if (!new_net_conf) {
- drbd_err(device, "Allocation of new net_conf failed\n");
+ if (!new_net_conf)
goto disconnect;
- }
*new_net_conf = *old_net_conf;
@@ -4161,7 +4157,6 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info
new_disk_conf = kzalloc(sizeof(struct disk_conf), GFP_KERNEL);
if (!new_disk_conf) {
- drbd_err(device, "Allocation of new disk_conf failed\n");
put_ldev(device);
return -ENOMEM;
}
@@ -4288,10 +4283,8 @@ static int receive_uuids(struct drbd_connection *connection, struct packet_info
device = peer_device->device;
p_uuid = kmalloc_array(UI_EXTENDED_SIZE, sizeof(*p_uuid), GFP_NOIO);
- if (!p_uuid) {
- drbd_err(device, "kmalloc of p_uuid failed\n");
+ if (!p_uuid)
return false;
- }
for (i = UI_CURRENT; i < UI_EXTENDED_SIZE; i++)
p_uuid[i] = be64_to_cpu(p->uuid[i]);
@@ -5484,8 +5477,7 @@ static int drbd_do_auth(struct drbd_connection *connection)
}
peers_ch = kmalloc(pi.size, GFP_NOIO);
- if (peers_ch == NULL) {
- drbd_err(connection, "kmalloc of peers_ch failed\n");
+ if (!peers_ch) {
rv = -1;
goto fail;
}
@@ -5504,8 +5496,7 @@ static int drbd_do_auth(struct drbd_connection *connection)
resp_size = crypto_shash_digestsize(connection->cram_hmac_tfm);
response = kmalloc(resp_size, GFP_NOIO);
- if (response == NULL) {
- drbd_err(connection, "kmalloc of response failed\n");
+ if (!response) {
rv = -1;
goto fail;
}
@@ -5552,8 +5543,7 @@ static int drbd_do_auth(struct drbd_connection *connection)
}
right_response = kmalloc(resp_size, GFP_NOIO);
- if (right_response == NULL) {
- drbd_err(connection, "kmalloc of right_response failed\n");
+ if (!right_response) {
rv = -1;
goto fail;
}
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 8a9d22207c59..87460e0e5c72 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -2123,6 +2123,7 @@ static void format_interrupt(void)
switch (interpret_errors()) {
case 1:
cont->error();
+ break;
case 2:
break;
case 0:
@@ -2330,7 +2331,6 @@ static void rw_interrupt(void)
if (!drive_state[current_drive].first_read_date)
drive_state[current_drive].first_read_date = jiffies;
- nr_sectors = 0;
ssize = DIV_ROUND_UP(1 << raw_cmd->cmd[SIZECODE], 4);
if (reply_buffer[ST1] & ST1_EOC)
@@ -4491,23 +4491,15 @@ static bool floppy_available(int drive)
static int floppy_alloc_disk(unsigned int drive, unsigned int type)
{
struct gendisk *disk;
- int err;
-
- disk = alloc_disk(1);
- if (!disk)
- return -ENOMEM;
- disk->queue = blk_mq_init_queue(&tag_sets[drive]);
- if (IS_ERR(disk->queue)) {
- err = PTR_ERR(disk->queue);
- disk->queue = NULL;
- put_disk(disk);
- return err;
- }
+ disk = blk_mq_alloc_disk(&tag_sets[drive], NULL);
+ if (IS_ERR(disk))
+ return PTR_ERR(disk);
blk_queue_max_hw_sectors(disk->queue, 64);
disk->major = FLOPPY_MAJOR;
disk->first_minor = TOMINOR(drive) | (type << 2);
+ disk->minors = 1;
disk->fops = &floppy_fops;
disk->events = DISK_EVENT_MEDIA_CHANGE;
if (type)
@@ -4727,10 +4719,8 @@ out_put_disk:
if (!disks[drive][0])
break;
del_timer_sync(&motor_off_timer[drive]);
- blk_cleanup_queue(disks[drive][0]->queue);
- disks[drive][0]->queue = NULL;
+ blk_cleanup_disk(disks[drive][0]);
blk_mq_free_tag_set(&tag_sets[drive]);
- put_disk(disks[drive][0]);
}
return err;
}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 76e12f3482a9..f37b9e3d833c 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -71,7 +71,6 @@
#include <linux/writeback.h>
#include <linux/completion.h>
#include <linux/highmem.h>
-#include <linux/kthread.h>
#include <linux/splice.h>
#include <linux/sysfs.h>
#include <linux/miscdevice.h>
@@ -79,11 +78,14 @@
#include <linux/uio.h>
#include <linux/ioprio.h>
#include <linux/blk-cgroup.h>
+#include <linux/sched/mm.h>
#include "loop.h"
#include <linux/uaccess.h>
+#define LOOP_IDLE_WORKER_TIMEOUT (60 * HZ)
+
static DEFINE_IDR(loop_index_idr);
static DEFINE_MUTEX(loop_ctl_mutex);
@@ -515,8 +517,6 @@ static void lo_rw_aio_complete(struct kiocb *iocb, long ret, long ret2)
{
struct loop_cmd *cmd = container_of(iocb, struct loop_cmd, iocb);
- if (cmd->css)
- css_put(cmd->css);
cmd->ret = ret;
lo_rw_aio_do_completion(cmd);
}
@@ -577,8 +577,6 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
cmd->iocb.ki_complete = lo_rw_aio_complete;
cmd->iocb.ki_flags = IOCB_DIRECT;
cmd->iocb.ki_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, 0);
- if (cmd->css)
- kthread_associate_blkcg(cmd->css);
if (rw == WRITE)
ret = call_write_iter(file, &cmd->iocb, &iter);
@@ -586,7 +584,6 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
ret = call_read_iter(file, &cmd->iocb, &iter);
lo_rw_aio_do_completion(cmd);
- kthread_associate_blkcg(NULL);
if (ret != -EIOCBQUEUED)
cmd->iocb.ki_complete(&cmd->iocb, ret, 0);
@@ -647,14 +644,13 @@ static inline void loop_update_dio(struct loop_device *lo)
lo->use_dio);
}
-static void loop_reread_partitions(struct loop_device *lo,
- struct block_device *bdev)
+static void loop_reread_partitions(struct loop_device *lo)
{
int rc;
- mutex_lock(&bdev->bd_mutex);
- rc = bdev_disk_changed(bdev, false);
- mutex_unlock(&bdev->bd_mutex);
+ mutex_lock(&lo->lo_disk->open_mutex);
+ rc = bdev_disk_changed(lo->lo_disk, false);
+ mutex_unlock(&lo->lo_disk->open_mutex);
if (rc)
pr_warn("%s: partition scan of loop%d (%s) failed (rc=%d)\n",
__func__, lo->lo_number, lo->lo_file_name, rc);
@@ -747,12 +743,12 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
mutex_unlock(&lo->lo_mutex);
/*
* We must drop file reference outside of lo_mutex as dropping
- * the file ref can take bd_mutex which creates circular locking
+ * the file ref can take open_mutex which creates circular locking
* dependency.
*/
fput(old_file);
if (partscan)
- loop_reread_partitions(lo, bdev);
+ loop_reread_partitions(lo);
return 0;
out_err:
@@ -921,27 +917,100 @@ static void loop_config_discard(struct loop_device *lo)
q->limits.discard_alignment = 0;
}
-static void loop_unprepare_queue(struct loop_device *lo)
+struct loop_worker {
+ struct rb_node rb_node;
+ struct work_struct work;
+ struct list_head cmd_list;
+ struct list_head idle_list;
+ struct loop_device *lo;
+ struct cgroup_subsys_state *blkcg_css;
+ unsigned long last_ran_at;
+};
+
+static void loop_workfn(struct work_struct *work);
+static void loop_rootcg_workfn(struct work_struct *work);
+static void loop_free_idle_workers(struct timer_list *timer);
+
+#ifdef CONFIG_BLK_CGROUP
+static inline int queue_on_root_worker(struct cgroup_subsys_state *css)
{
- kthread_flush_worker(&lo->worker);
- kthread_stop(lo->worker_task);
+ return !css || css == blkcg_root_css;
}
-
-static int loop_kthread_worker_fn(void *worker_ptr)
+#else
+static inline int queue_on_root_worker(struct cgroup_subsys_state *css)
{
- current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO;
- return kthread_worker_fn(worker_ptr);
+ return !css;
}
+#endif
-static int loop_prepare_queue(struct loop_device *lo)
+static void loop_queue_work(struct loop_device *lo, struct loop_cmd *cmd)
{
- kthread_init_worker(&lo->worker);
- lo->worker_task = kthread_run(loop_kthread_worker_fn,
- &lo->worker, "loop%d", lo->lo_number);
- if (IS_ERR(lo->worker_task))
- return -ENOMEM;
- set_user_nice(lo->worker_task, MIN_NICE);
- return 0;
+ struct rb_node **node = &(lo->worker_tree.rb_node), *parent = NULL;
+ struct loop_worker *cur_worker, *worker = NULL;
+ struct work_struct *work;
+ struct list_head *cmd_list;
+
+ spin_lock_irq(&lo->lo_work_lock);
+
+ if (queue_on_root_worker(cmd->blkcg_css))
+ goto queue_work;
+
+ node = &lo->worker_tree.rb_node;
+
+ while (*node) {
+ parent = *node;
+ cur_worker = container_of(*node, struct loop_worker, rb_node);
+ if (cur_worker->blkcg_css == cmd->blkcg_css) {
+ worker = cur_worker;
+ break;
+ } else if ((long)cur_worker->blkcg_css < (long)cmd->blkcg_css) {
+ node = &(*node)->rb_left;
+ } else {
+ node = &(*node)->rb_right;
+ }
+ }
+ if (worker)
+ goto queue_work;
+
+ worker = kzalloc(sizeof(struct loop_worker), GFP_NOWAIT | __GFP_NOWARN);
+ /*
+ * In the event we cannot allocate a worker, just queue on the
+ * rootcg worker and issue the I/O as the rootcg
+ */
+ if (!worker) {
+ cmd->blkcg_css = NULL;
+ if (cmd->memcg_css)
+ css_put(cmd->memcg_css);
+ cmd->memcg_css = NULL;
+ goto queue_work;
+ }
+
+ worker->blkcg_css = cmd->blkcg_css;
+ css_get(worker->blkcg_css);
+ INIT_WORK(&worker->work, loop_workfn);
+ INIT_LIST_HEAD(&worker->cmd_list);
+ INIT_LIST_HEAD(&worker->idle_list);
+ worker->lo = lo;
+ rb_link_node(&worker->rb_node, parent, node);
+ rb_insert_color(&worker->rb_node, &lo->worker_tree);
+queue_work:
+ if (worker) {
+ /*
+ * We need to remove from the idle list here while
+ * holding the lock so that the idle timer doesn't
+ * free the worker
+ */
+ if (!list_empty(&worker->idle_list))
+ list_del_init(&worker->idle_list);
+ work = &worker->work;
+ cmd_list = &worker->cmd_list;
+ } else {
+ work = &lo->rootcg_work;
+ cmd_list = &lo->rootcg_cmd_list;
+ }
+ list_add_tail(&cmd->list_entry, cmd_list);
+ queue_work(lo->workqueue, work);
+ spin_unlock_irq(&lo->lo_work_lock);
}
static void loop_update_rotational(struct loop_device *lo)
@@ -1127,12 +1196,23 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
!file->f_op->write_iter)
lo->lo_flags |= LO_FLAGS_READ_ONLY;
- error = loop_prepare_queue(lo);
- if (error)
+ lo->workqueue = alloc_workqueue("loop%d",
+ WQ_UNBOUND | WQ_FREEZABLE,
+ 0,
+ lo->lo_number);
+ if (!lo->workqueue) {
+ error = -ENOMEM;
goto out_unlock;
+ }
set_disk_ro(lo->lo_disk, (lo->lo_flags & LO_FLAGS_READ_ONLY) != 0);
+ INIT_WORK(&lo->rootcg_work, loop_rootcg_workfn);
+ INIT_LIST_HEAD(&lo->rootcg_cmd_list);
+ INIT_LIST_HEAD(&lo->idle_worker_list);
+ lo->worker_tree = RB_ROOT;
+ timer_setup(&lo->timer, loop_free_idle_workers,
+ TIMER_DEFERRABLE);
lo->use_dio = lo->lo_flags & LO_FLAGS_DIRECT_IO;
lo->lo_device = bdev;
lo->lo_backing_file = file;
@@ -1154,6 +1234,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
blk_queue_physical_block_size(lo->lo_queue, bsize);
blk_queue_io_min(lo->lo_queue, bsize);
+ loop_config_discard(lo);
loop_update_rotational(lo);
loop_update_dio(lo);
loop_sysfs_init(lo);
@@ -1174,7 +1255,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
bdgrab(bdev);
mutex_unlock(&lo->lo_mutex);
if (partscan)
- loop_reread_partitions(lo, bdev);
+ loop_reread_partitions(lo);
if (!(mode & FMODE_EXCL))
bd_abort_claiming(bdev, loop_configure);
return 0;
@@ -1200,6 +1281,7 @@ static int __loop_clr_fd(struct loop_device *lo, bool release)
int err = 0;
bool partscan = false;
int lo_number;
+ struct loop_worker *pos, *worker;
mutex_lock(&lo->lo_mutex);
if (WARN_ON_ONCE(lo->lo_state != Lo_rundown)) {
@@ -1219,6 +1301,18 @@ static int __loop_clr_fd(struct loop_device *lo, bool release)
/* freeze request queue during the transition */
blk_mq_freeze_queue(lo->lo_queue);
+ destroy_workqueue(lo->workqueue);
+ spin_lock_irq(&lo->lo_work_lock);
+ list_for_each_entry_safe(worker, pos, &lo->idle_worker_list,
+ idle_list) {
+ list_del(&worker->idle_list);
+ rb_erase(&worker->rb_node, &lo->worker_tree);
+ css_put(worker->blkcg_css);
+ kfree(worker);
+ }
+ spin_unlock_irq(&lo->lo_work_lock);
+ del_timer_sync(&lo->timer);
+
spin_lock_irq(&lo->lo_lock);
lo->lo_backing_file = NULL;
spin_unlock_irq(&lo->lo_lock);
@@ -1255,12 +1349,11 @@ static int __loop_clr_fd(struct loop_device *lo, bool release)
partscan = lo->lo_flags & LO_FLAGS_PARTSCAN && bdev;
lo_number = lo->lo_number;
- loop_unprepare_queue(lo);
out_unlock:
mutex_unlock(&lo->lo_mutex);
if (partscan) {
/*
- * bd_mutex has been held already in release path, so don't
+ * open_mutex has been held already in release path, so don't
* acquire it if this function is called in such case.
*
* If the reread partition isn't from release path, lo_refcnt
@@ -1268,10 +1361,10 @@ out_unlock:
* current holder is released.
*/
if (!release)
- mutex_lock(&bdev->bd_mutex);
- err = bdev_disk_changed(bdev, false);
+ mutex_lock(&lo->lo_disk->open_mutex);
+ err = bdev_disk_changed(lo->lo_disk, false);
if (!release)
- mutex_unlock(&bdev->bd_mutex);
+ mutex_unlock(&lo->lo_disk->open_mutex);
if (err)
pr_warn("%s: partition scan of loop%d failed (rc=%d)\n",
__func__, lo_number, err);
@@ -1298,7 +1391,7 @@ out_unlock:
/*
* Need not hold lo_mutex to fput backing file. Calling fput holding
* lo_mutex triggers a circular lock dependency possibility warning as
- * fput can take bd_mutex which is usually taken before lo_mutex.
+ * fput can take open_mutex which is usually taken before lo_mutex.
*/
if (filp)
fput(filp);
@@ -1341,7 +1434,6 @@ static int
loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
{
int err;
- struct block_device *bdev;
kuid_t uid = current_uid();
int prev_lo_flags;
bool partscan = false;
@@ -1410,13 +1502,12 @@ out_unfreeze:
if (!err && (lo->lo_flags & LO_FLAGS_PARTSCAN) &&
!(prev_lo_flags & LO_FLAGS_PARTSCAN)) {
lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN;
- bdev = lo->lo_device;
partscan = true;
}
out_unlock:
mutex_unlock(&lo->lo_mutex);
if (partscan)
- loop_reread_partitions(lo, bdev);
+ loop_reread_partitions(lo);
return err;
}
@@ -2008,14 +2099,19 @@ static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx,
}
/* always use the first bio's css */
+ cmd->blkcg_css = NULL;
+ cmd->memcg_css = NULL;
#ifdef CONFIG_BLK_CGROUP
- if (cmd->use_aio && rq->bio && rq->bio->bi_blkg) {
- cmd->css = &bio_blkcg(rq->bio)->css;
- css_get(cmd->css);
- } else
+ if (rq->bio && rq->bio->bi_blkg) {
+ cmd->blkcg_css = &bio_blkcg(rq->bio)->css;
+#ifdef CONFIG_MEMCG
+ cmd->memcg_css =
+ cgroup_get_e_css(cmd->blkcg_css->cgroup,
+ &memory_cgrp_subsys);
#endif
- cmd->css = NULL;
- kthread_queue_work(&lo->worker, &cmd->work);
+ }
+#endif
+ loop_queue_work(lo, cmd);
return BLK_STS_OK;
}
@@ -2026,13 +2122,28 @@ static void loop_handle_cmd(struct loop_cmd *cmd)
const bool write = op_is_write(req_op(rq));
struct loop_device *lo = rq->q->queuedata;
int ret = 0;
+ struct mem_cgroup *old_memcg = NULL;
if (write && (lo->lo_flags & LO_FLAGS_READ_ONLY)) {
ret = -EIO;
goto failed;
}
+ if (cmd->blkcg_css)
+ kthread_associate_blkcg(cmd->blkcg_css);
+ if (cmd->memcg_css)
+ old_memcg = set_active_memcg(
+ mem_cgroup_from_css(cmd->memcg_css));
+
ret = do_req_filebacked(lo, rq);
+
+ if (cmd->blkcg_css)
+ kthread_associate_blkcg(NULL);
+
+ if (cmd->memcg_css) {
+ set_active_memcg(old_memcg);
+ css_put(cmd->memcg_css);
+ }
failed:
/* complete non-aio request */
if (!cmd->use_aio || ret) {
@@ -2045,30 +2156,86 @@ static void loop_handle_cmd(struct loop_cmd *cmd)
}
}
-static void loop_queue_work(struct kthread_work *work)
+static void loop_set_timer(struct loop_device *lo)
{
- struct loop_cmd *cmd =
- container_of(work, struct loop_cmd, work);
+ timer_reduce(&lo->timer, jiffies + LOOP_IDLE_WORKER_TIMEOUT);
+}
+
+static void loop_process_work(struct loop_worker *worker,
+ struct list_head *cmd_list, struct loop_device *lo)
+{
+ int orig_flags = current->flags;
+ struct loop_cmd *cmd;
+
+ current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO;
+ spin_lock_irq(&lo->lo_work_lock);
+ while (!list_empty(cmd_list)) {
+ cmd = container_of(
+ cmd_list->next, struct loop_cmd, list_entry);
+ list_del(cmd_list->next);
+ spin_unlock_irq(&lo->lo_work_lock);
+
+ loop_handle_cmd(cmd);
+ cond_resched();
- loop_handle_cmd(cmd);
+ spin_lock_irq(&lo->lo_work_lock);
+ }
+
+ /*
+ * We only add to the idle list if there are no pending cmds
+ * *and* the worker will not run again which ensures that it
+ * is safe to free any worker on the idle list
+ */
+ if (worker && !work_pending(&worker->work)) {
+ worker->last_ran_at = jiffies;
+ list_add_tail(&worker->idle_list, &lo->idle_worker_list);
+ loop_set_timer(lo);
+ }
+ spin_unlock_irq(&lo->lo_work_lock);
+ current->flags = orig_flags;
}
-static int loop_init_request(struct blk_mq_tag_set *set, struct request *rq,
- unsigned int hctx_idx, unsigned int numa_node)
+static void loop_workfn(struct work_struct *work)
{
- struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq);
+ struct loop_worker *worker =
+ container_of(work, struct loop_worker, work);
+ loop_process_work(worker, &worker->cmd_list, worker->lo);
+}
- kthread_init_work(&cmd->work, loop_queue_work);
- return 0;
+static void loop_rootcg_workfn(struct work_struct *work)
+{
+ struct loop_device *lo =
+ container_of(work, struct loop_device, rootcg_work);
+ loop_process_work(NULL, &lo->rootcg_cmd_list, lo);
+}
+
+static void loop_free_idle_workers(struct timer_list *timer)
+{
+ struct loop_device *lo = container_of(timer, struct loop_device, timer);
+ struct loop_worker *pos, *worker;
+
+ spin_lock_irq(&lo->lo_work_lock);
+ list_for_each_entry_safe(worker, pos, &lo->idle_worker_list,
+ idle_list) {
+ if (time_is_after_jiffies(worker->last_ran_at +
+ LOOP_IDLE_WORKER_TIMEOUT))
+ break;
+ list_del(&worker->idle_list);
+ rb_erase(&worker->rb_node, &lo->worker_tree);
+ css_put(worker->blkcg_css);
+ kfree(worker);
+ }
+ if (!list_empty(&lo->idle_worker_list))
+ loop_set_timer(lo);
+ spin_unlock_irq(&lo->lo_work_lock);
}
static const struct blk_mq_ops loop_mq_ops = {
.queue_rq = loop_queue_rq,
- .init_request = loop_init_request,
.complete = lo_complete_rq,
};
-static int loop_add(struct loop_device **l, int i)
+static int loop_add(int i)
{
struct loop_device *lo;
struct gendisk *disk;
@@ -2078,9 +2245,12 @@ static int loop_add(struct loop_device **l, int i)
lo = kzalloc(sizeof(*lo), GFP_KERNEL);
if (!lo)
goto out;
-
lo->lo_state = Lo_unbound;
+ err = mutex_lock_killable(&loop_ctl_mutex);
+ if (err)
+ goto out_free_dev;
+
/* allocate id, if @id >= 0, we're requesting that specific id */
if (i >= 0) {
err = idr_alloc(&loop_index_idr, lo, i, i + 1, GFP_KERNEL);
@@ -2090,7 +2260,7 @@ static int loop_add(struct loop_device **l, int i)
err = idr_alloc(&loop_index_idr, lo, 0, 0, GFP_KERNEL);
}
if (err < 0)
- goto out_free_dev;
+ goto out_unlock;
i = err;
err = -ENOMEM;
@@ -2106,12 +2276,12 @@ static int loop_add(struct loop_device **l, int i)
if (err)
goto out_free_idr;
- lo->lo_queue = blk_mq_init_queue(&lo->tag_set);
- if (IS_ERR(lo->lo_queue)) {
- err = PTR_ERR(lo->lo_queue);
+ disk = lo->lo_disk = blk_mq_alloc_disk(&lo->tag_set, lo);
+ if (IS_ERR(disk)) {
+ err = PTR_ERR(disk);
goto out_cleanup_tags;
}
- lo->lo_queue->queuedata = lo;
+ lo->lo_queue = lo->lo_disk->queue;
blk_queue_max_hw_sectors(lo->lo_queue, BLK_DEF_MAX_SECTORS);
@@ -2123,11 +2293,6 @@ static int loop_add(struct loop_device **l, int i)
*/
blk_queue_flag_set(QUEUE_FLAG_NOMERGES, lo->lo_queue);
- err = -ENOMEM;
- disk = lo->lo_disk = alloc_disk(1 << part_shift);
- if (!disk)
- goto out_free_queue;
-
/*
* Disable partition scanning by default. The in-kernel partition
* scanning can be requested individually per-device during its
@@ -2153,22 +2318,24 @@ static int loop_add(struct loop_device **l, int i)
mutex_init(&lo->lo_mutex);
lo->lo_number = i;
spin_lock_init(&lo->lo_lock);
+ spin_lock_init(&lo->lo_work_lock);
disk->major = LOOP_MAJOR;
disk->first_minor = i << part_shift;
+ disk->minors = 1 << part_shift;
disk->fops = &lo_fops;
disk->private_data = lo;
disk->queue = lo->lo_queue;
sprintf(disk->disk_name, "loop%d", i);
add_disk(disk);
- *l = lo;
- return lo->lo_number;
+ mutex_unlock(&loop_ctl_mutex);
+ return i;
-out_free_queue:
- blk_cleanup_queue(lo->lo_queue);
out_cleanup_tags:
blk_mq_free_tag_set(&lo->tag_set);
out_free_idr:
idr_remove(&loop_index_idr, i);
+out_unlock:
+ mutex_unlock(&loop_ctl_mutex);
out_free_dev:
kfree(lo);
out:
@@ -2178,116 +2345,92 @@ out:
static void loop_remove(struct loop_device *lo)
{
del_gendisk(lo->lo_disk);
- blk_cleanup_queue(lo->lo_queue);
+ blk_cleanup_disk(lo->lo_disk);
blk_mq_free_tag_set(&lo->tag_set);
- put_disk(lo->lo_disk);
mutex_destroy(&lo->lo_mutex);
kfree(lo);
}
-static int find_free_cb(int id, void *ptr, void *data)
+static void loop_probe(dev_t dev)
{
- struct loop_device *lo = ptr;
- struct loop_device **l = data;
+ int idx = MINOR(dev) >> part_shift;
- if (lo->lo_state == Lo_unbound) {
- *l = lo;
- return 1;
- }
- return 0;
+ if (max_loop && idx >= max_loop)
+ return;
+ loop_add(idx);
}
-static int loop_lookup(struct loop_device **l, int i)
+static int loop_control_remove(int idx)
{
struct loop_device *lo;
- int ret = -ENODEV;
+ int ret;
- if (i < 0) {
- int err;
+ if (idx < 0) {
+ pr_warn("deleting an unspecified loop device is not supported.\n");
+ return -EINVAL;
+ }
+
+ ret = mutex_lock_killable(&loop_ctl_mutex);
+ if (ret)
+ return ret;
- err = idr_for_each(&loop_index_idr, &find_free_cb, &lo);
- if (err == 1) {
- *l = lo;
- ret = lo->lo_number;
- }
- goto out;
+ lo = idr_find(&loop_index_idr, idx);
+ if (!lo) {
+ ret = -ENODEV;
+ goto out_unlock_ctrl;
}
- /* lookup and return a specific i */
- lo = idr_find(&loop_index_idr, i);
- if (lo) {
- *l = lo;
- ret = lo->lo_number;
+ ret = mutex_lock_killable(&lo->lo_mutex);
+ if (ret)
+ goto out_unlock_ctrl;
+ if (lo->lo_state != Lo_unbound ||
+ atomic_read(&lo->lo_refcnt) > 0) {
+ mutex_unlock(&lo->lo_mutex);
+ ret = -EBUSY;
+ goto out_unlock_ctrl;
}
-out:
+ lo->lo_state = Lo_deleting;
+ mutex_unlock(&lo->lo_mutex);
+
+ idr_remove(&loop_index_idr, lo->lo_number);
+ loop_remove(lo);
+out_unlock_ctrl:
+ mutex_unlock(&loop_ctl_mutex);
return ret;
}
-static void loop_probe(dev_t dev)
+static int loop_control_get_free(int idx)
{
- int idx = MINOR(dev) >> part_shift;
struct loop_device *lo;
+ int id, ret;
- if (max_loop && idx >= max_loop)
- return;
-
- mutex_lock(&loop_ctl_mutex);
- if (loop_lookup(&lo, idx) < 0)
- loop_add(&lo, idx);
+ ret = mutex_lock_killable(&loop_ctl_mutex);
+ if (ret)
+ return ret;
+ idr_for_each_entry(&loop_index_idr, lo, id) {
+ if (lo->lo_state == Lo_unbound)
+ goto found;
+ }
mutex_unlock(&loop_ctl_mutex);
+ return loop_add(-1);
+found:
+ mutex_unlock(&loop_ctl_mutex);
+ return id;
}
static long loop_control_ioctl(struct file *file, unsigned int cmd,
unsigned long parm)
{
- struct loop_device *lo;
- int ret;
-
- ret = mutex_lock_killable(&loop_ctl_mutex);
- if (ret)
- return ret;
-
- ret = -ENOSYS;
switch (cmd) {
case LOOP_CTL_ADD:
- ret = loop_lookup(&lo, parm);
- if (ret >= 0) {
- ret = -EEXIST;
- break;
- }
- ret = loop_add(&lo, parm);
- break;
+ return loop_add(parm);
case LOOP_CTL_REMOVE:
- ret = loop_lookup(&lo, parm);
- if (ret < 0)
- break;
- ret = mutex_lock_killable(&lo->lo_mutex);
- if (ret)
- break;
- if (lo->lo_state != Lo_unbound) {
- ret = -EBUSY;
- mutex_unlock(&lo->lo_mutex);
- break;
- }
- if (atomic_read(&lo->lo_refcnt) > 0) {
- ret = -EBUSY;
- mutex_unlock(&lo->lo_mutex);
- break;
- }
- lo->lo_state = Lo_deleting;
- mutex_unlock(&lo->lo_mutex);
- idr_remove(&loop_index_idr, lo->lo_number);
- loop_remove(lo);
- break;
+ return loop_control_remove(parm);
case LOOP_CTL_GET_FREE:
- ret = loop_lookup(&lo, -1);
- if (ret >= 0)
- break;
- ret = loop_add(&lo, -1);
+ return loop_control_get_free(parm);
+ default:
+ return -ENOSYS;
}
- mutex_unlock(&loop_ctl_mutex);
-
- return ret;
}
static const struct file_operations loop_ctl_fops = {
@@ -2310,7 +2453,6 @@ MODULE_ALIAS("devname:loop-control");
static int __init loop_init(void)
{
int i, nr;
- struct loop_device *lo;
int err;
part_shift = 0;
@@ -2362,10 +2504,8 @@ static int __init loop_init(void)
}
/* pre-create number of devices given by config or max_loop */
- mutex_lock(&loop_ctl_mutex);
for (i = 0; i < nr; i++)
- loop_add(&lo, i);
- mutex_unlock(&loop_ctl_mutex);
+ loop_add(i);
printk(KERN_INFO "loop: module loaded\n");
return 0;
@@ -2376,26 +2516,20 @@ err_out:
return err;
}
-static int loop_exit_cb(int id, void *ptr, void *data)
-{
- struct loop_device *lo = ptr;
-
- loop_remove(lo);
- return 0;
-}
-
static void __exit loop_exit(void)
{
- mutex_lock(&loop_ctl_mutex);
-
- idr_for_each(&loop_index_idr, &loop_exit_cb, NULL);
- idr_destroy(&loop_index_idr);
+ struct loop_device *lo;
+ int id;
unregister_blkdev(LOOP_MAJOR, "loop");
-
misc_deregister(&loop_misc);
+ mutex_lock(&loop_ctl_mutex);
+ idr_for_each_entry(&loop_index_idr, lo, id)
+ loop_remove(lo);
mutex_unlock(&loop_ctl_mutex);
+
+ idr_destroy(&loop_index_idr);
}
module_init(loop_init);
diff --git a/drivers/block/loop.h b/drivers/block/loop.h
index 5beb959b94d3..1988899db63a 100644
--- a/drivers/block/loop.h
+++ b/drivers/block/loop.h
@@ -14,7 +14,6 @@
#include <linux/blk-mq.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
-#include <linux/kthread.h>
#include <uapi/linux/loop.h>
/* Possible states of device */
@@ -55,8 +54,13 @@ struct loop_device {
spinlock_t lo_lock;
int lo_state;
- struct kthread_worker worker;
- struct task_struct *worker_task;
+ spinlock_t lo_work_lock;
+ struct workqueue_struct *workqueue;
+ struct work_struct rootcg_work;
+ struct list_head rootcg_cmd_list;
+ struct list_head idle_worker_list;
+ struct rb_root worker_tree;
+ struct timer_list timer;
bool use_dio;
bool sysfs_inited;
@@ -67,13 +71,14 @@ struct loop_device {
};
struct loop_cmd {
- struct kthread_work work;
+ struct list_head list_entry;
bool use_aio; /* use AIO interface to handle I/O */
atomic_t ref; /* only for aio */
long ret;
struct kiocb iocb;
struct bio_vec *bvec;
- struct cgroup_subsys_state *css;
+ struct cgroup_subsys_state *blkcg_css;
+ struct cgroup_subsys_state *memcg_css;
};
/* Support for loadable transfer modules */
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 589cb0f1e030..901855717cb5 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -2160,6 +2160,20 @@ static ssize_t mtip_hw_show_status(struct device *dev,
static DEVICE_ATTR(status, 0444, mtip_hw_show_status, NULL);
+static struct attribute *mtip_disk_attrs[] = {
+ &dev_attr_status.attr,
+ NULL,
+};
+
+static const struct attribute_group mtip_disk_attr_group = {
+ .attrs = mtip_disk_attrs,
+};
+
+static const struct attribute_group *mtip_disk_attr_groups[] = {
+ &mtip_disk_attr_group,
+ NULL,
+};
+
/* debugsfs entries */
static ssize_t show_device_status(struct device_driver *drv, char *buf)
@@ -2238,7 +2252,6 @@ static ssize_t show_device_status(struct device_driver *drv, char *buf)
static ssize_t mtip_hw_read_device_status(struct file *f, char __user *ubuf,
size_t len, loff_t *offset)
{
- struct driver_data *dd = (struct driver_data *)f->private_data;
int size = *offset;
char *buf;
int rv = 0;
@@ -2247,11 +2260,8 @@ static ssize_t mtip_hw_read_device_status(struct file *f, char __user *ubuf,
return 0;
buf = kzalloc(MTIP_DFS_MAX_BUF_SIZE, GFP_KERNEL);
- if (!buf) {
- dev_err(&dd->pdev->dev,
- "Memory allocation: status buffer\n");
+ if (!buf)
return -ENOMEM;
- }
size += show_device_status(NULL, buf);
@@ -2277,11 +2287,8 @@ static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf,
return 0;
buf = kzalloc(MTIP_DFS_MAX_BUF_SIZE, GFP_KERNEL);
- if (!buf) {
- dev_err(&dd->pdev->dev,
- "Memory allocation: register buffer\n");
+ if (!buf)
return -ENOMEM;
- }
size += sprintf(&buf[size], "H/ S ACTive : [ 0x");
@@ -2343,11 +2350,8 @@ static ssize_t mtip_hw_read_flags(struct file *f, char __user *ubuf,
return 0;
buf = kzalloc(MTIP_DFS_MAX_BUF_SIZE, GFP_KERNEL);
- if (!buf) {
- dev_err(&dd->pdev->dev,
- "Memory allocation: flag buffer\n");
+ if (!buf)
return -ENOMEM;
- }
size += sprintf(&buf[size], "Flag-port : [ %08lX ]\n",
dd->port->flags);
@@ -2384,47 +2388,6 @@ static const struct file_operations mtip_flags_fops = {
.llseek = no_llseek,
};
-/*
- * Create the sysfs related attributes.
- *
- * @dd Pointer to the driver data structure.
- * @kobj Pointer to the kobj for the block device.
- *
- * return value
- * 0 Operation completed successfully.
- * -EINVAL Invalid parameter.
- */
-static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj)
-{
- if (!kobj || !dd)
- return -EINVAL;
-
- if (sysfs_create_file(kobj, &dev_attr_status.attr))
- dev_warn(&dd->pdev->dev,
- "Error creating 'status' sysfs entry\n");
- return 0;
-}
-
-/*
- * Remove the sysfs related attributes.
- *
- * @dd Pointer to the driver data structure.
- * @kobj Pointer to the kobj for the block device.
- *
- * return value
- * 0 Operation completed successfully.
- * -EINVAL Invalid parameter.
- */
-static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj)
-{
- if (!kobj || !dd)
- return -EINVAL;
-
- sysfs_remove_file(kobj, &dev_attr_status.attr);
-
- return 0;
-}
-
static int mtip_hw_debugfs_init(struct driver_data *dd)
{
if (!dfs_parent)
@@ -2884,11 +2847,8 @@ static int mtip_hw_init(struct driver_data *dd)
dd->port = kzalloc_node(sizeof(struct mtip_port), GFP_KERNEL,
dd->numa_node);
- if (!dd->port) {
- dev_err(&dd->pdev->dev,
- "Memory allocation: port structure\n");
+ if (!dd->port)
return -ENOMEM;
- }
/* Continue workqueue setup */
for (i = 0; i < MTIP_MAX_SLOT_GROUPS; i++)
@@ -3579,7 +3539,6 @@ static int mtip_block_initialize(struct driver_data *dd)
int rv = 0, wait_for_rebuild = 0;
sector_t capacity;
unsigned int index = 0;
- struct kobject *kobj;
if (dd->disk)
goto skip_create_disk; /* hw init done, before rebuild */
@@ -3589,35 +3548,6 @@ static int mtip_block_initialize(struct driver_data *dd)
goto protocol_init_error;
}
- dd->disk = alloc_disk_node(MTIP_MAX_MINORS, dd->numa_node);
- if (dd->disk == NULL) {
- dev_err(&dd->pdev->dev,
- "Unable to allocate gendisk structure\n");
- rv = -EINVAL;
- goto alloc_disk_error;
- }
-
- rv = ida_alloc(&rssd_index_ida, GFP_KERNEL);
- if (rv < 0)
- goto ida_get_error;
- index = rv;
-
- rv = rssd_disk_name_format("rssd",
- index,
- dd->disk->disk_name,
- DISK_NAME_LEN);
- if (rv)
- goto disk_index_error;
-
- dd->disk->major = dd->major;
- dd->disk->first_minor = index * MTIP_MAX_MINORS;
- dd->disk->minors = MTIP_MAX_MINORS;
- dd->disk->fops = &mtip_block_ops;
- dd->disk->private_data = dd;
- dd->index = index;
-
- mtip_hw_debugfs_init(dd);
-
memset(&dd->tags, 0, sizeof(dd->tags));
dd->tags.ops = &mtip_mq_ops;
dd->tags.nr_hw_queues = 1;
@@ -3636,17 +3566,35 @@ static int mtip_block_initialize(struct driver_data *dd)
goto block_queue_alloc_tag_error;
}
- /* Allocate the request queue. */
- dd->queue = blk_mq_init_queue(&dd->tags);
- if (IS_ERR(dd->queue)) {
+ dd->disk = blk_mq_alloc_disk(&dd->tags, dd);
+ if (IS_ERR(dd->disk)) {
dev_err(&dd->pdev->dev,
"Unable to allocate request queue\n");
rv = -ENOMEM;
goto block_queue_alloc_init_error;
}
+ dd->queue = dd->disk->queue;
+
+ rv = ida_alloc(&rssd_index_ida, GFP_KERNEL);
+ if (rv < 0)
+ goto ida_get_error;
+ index = rv;
+
+ rv = rssd_disk_name_format("rssd",
+ index,
+ dd->disk->disk_name,
+ DISK_NAME_LEN);
+ if (rv)
+ goto disk_index_error;
+
+ dd->disk->major = dd->major;
+ dd->disk->first_minor = index * MTIP_MAX_MINORS;
+ dd->disk->minors = MTIP_MAX_MINORS;
+ dd->disk->fops = &mtip_block_ops;
+ dd->disk->private_data = dd;
+ dd->index = index;
- dd->disk->queue = dd->queue;
- dd->queue->queuedata = dd;
+ mtip_hw_debugfs_init(dd);
skip_create_disk:
/* Initialize the protocol layer. */
@@ -3685,17 +3633,7 @@ skip_create_disk:
set_capacity(dd->disk, capacity);
/* Enable the block device and add it to /dev */
- device_add_disk(&dd->pdev->dev, dd->disk, NULL);
-
- /*
- * Now that the disk is active, initialize any sysfs attributes
- * managed by the protocol layer.
- */
- kobj = kobject_get(&disk_to_dev(dd->disk)->kobj);
- if (kobj) {
- mtip_hw_sysfs_init(dd, kobj);
- kobject_put(kobj);
- }
+ device_add_disk(&dd->pdev->dev, dd->disk, mtip_disk_attr_groups);
if (dd->mtip_svc_handler) {
set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag);
@@ -3722,23 +3660,17 @@ start_service_thread:
kthread_run_error:
/* Delete our gendisk. This also removes the device from /dev */
del_gendisk(dd->disk);
-
read_capacity_error:
init_hw_cmds_error:
- blk_cleanup_queue(dd->queue);
-block_queue_alloc_init_error:
- blk_mq_free_tag_set(&dd->tags);
-block_queue_alloc_tag_error:
mtip_hw_debugfs_exit(dd);
disk_index_error:
ida_free(&rssd_index_ida, index);
-
ida_get_error:
- put_disk(dd->disk);
-
-alloc_disk_error:
+ blk_cleanup_disk(dd->disk);
+block_queue_alloc_init_error:
+ blk_mq_free_tag_set(&dd->tags);
+block_queue_alloc_tag_error:
mtip_hw_exit(dd); /* De-initialize the protocol layer. */
-
protocol_init_error:
return rv;
}
@@ -3764,8 +3696,6 @@ static bool mtip_no_dev_cleanup(struct request *rq, void *data, bool reserv)
*/
static int mtip_block_remove(struct driver_data *dd)
{
- struct kobject *kobj;
-
mtip_hw_debugfs_exit(dd);
if (dd->mtip_svc_handler) {
@@ -3774,15 +3704,6 @@ static int mtip_block_remove(struct driver_data *dd)
kthread_stop(dd->mtip_svc_handler);
}
- /* Clean up the sysfs attributes, if created */
- if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) {
- kobj = kobject_get(&disk_to_dev(dd->disk)->kobj);
- if (kobj) {
- mtip_hw_sysfs_exit(dd, kobj);
- kobject_put(kobj);
- }
- }
-
if (!dd->sr) {
/*
* Explicitly wait here for IOs to quiesce,
@@ -4002,11 +3923,8 @@ static int mtip_pci_probe(struct pci_dev *pdev,
cpu_to_node(raw_smp_processor_id()), raw_smp_processor_id());
dd = kzalloc_node(sizeof(struct driver_data), GFP_KERNEL, my_node);
- if (dd == NULL) {
- dev_err(&pdev->dev,
- "Unable to allocate memory for driver data\n");
+ if (!dd)
return -ENOMEM;
- }
/* Attach the private data to this PCI device. */
pci_set_drvdata(pdev, dd);
diff --git a/drivers/block/n64cart.c b/drivers/block/n64cart.c
index 47bdf324e962..7b4dd10af9ec 100644
--- a/drivers/block/n64cart.c
+++ b/drivers/block/n64cart.c
@@ -132,16 +132,12 @@ static int __init n64cart_probe(struct platform_device *pdev)
if (!reg_base)
return -EINVAL;
- disk = alloc_disk(0);
+ disk = blk_alloc_disk(NUMA_NO_NODE);
if (!disk)
return -ENOMEM;
- disk->queue = blk_alloc_queue(NUMA_NO_NODE);
- if (!disk->queue)
- return -ENOMEM;
-
disk->first_minor = 0;
- disk->flags = GENHD_FL_NO_PART_SCAN | GENHD_FL_EXT_DEVT;
+ disk->flags = GENHD_FL_NO_PART_SCAN;
disk->fops = &n64cart_fops;
disk->private_data = &pdev->dev;
strcpy(disk->disk_name, "n64cart");
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 45d2c28c8fc8..c38317979f74 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -79,6 +79,7 @@ struct link_dead_args {
#define NBD_RT_HAS_CONFIG_REF 4
#define NBD_RT_BOUND 5
#define NBD_RT_DISCONNECT_ON_CLOSE 6
+#define NBD_RT_HAS_BACKEND_FILE 7
#define NBD_DESTROY_ON_DISCONNECT 0
#define NBD_DISCONNECT_REQUESTED 1
@@ -119,6 +120,8 @@ struct nbd_device {
struct completion *destroy_complete;
unsigned long flags;
+
+ char *backend;
};
#define NBD_CMD_REQUEUED 1
@@ -216,18 +219,28 @@ static const struct device_attribute pid_attr = {
.show = pid_show,
};
+static ssize_t backend_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct gendisk *disk = dev_to_disk(dev);
+ struct nbd_device *nbd = (struct nbd_device *)disk->private_data;
+
+ return sprintf(buf, "%s\n", nbd->backend ?: "");
+}
+
+static const struct device_attribute backend_attr = {
+ .attr = { .name = "backend", .mode = 0444},
+ .show = backend_show,
+};
+
static void nbd_dev_remove(struct nbd_device *nbd)
{
struct gendisk *disk = nbd->disk;
- struct request_queue *q;
if (disk) {
- q = disk->queue;
del_gendisk(disk);
- blk_cleanup_queue(q);
+ blk_cleanup_disk(disk);
blk_mq_free_tag_set(&nbd->tag_set);
- disk->private_data = NULL;
- put_disk(disk);
}
/*
@@ -1215,6 +1228,12 @@ static void nbd_config_put(struct nbd_device *nbd)
&config->runtime_flags))
device_remove_file(disk_to_dev(nbd->disk), &pid_attr);
nbd->task_recv = NULL;
+ if (test_and_clear_bit(NBD_RT_HAS_BACKEND_FILE,
+ &config->runtime_flags)) {
+ device_remove_file(disk_to_dev(nbd->disk), &backend_attr);
+ kfree(nbd->backend);
+ nbd->backend = NULL;
+ }
nbd_clear_sock(nbd);
if (config->num_connections) {
int i;
@@ -1274,7 +1293,7 @@ static int nbd_start_device(struct nbd_device *nbd)
error = device_create_file(disk_to_dev(nbd->disk), &pid_attr);
if (error) {
- dev_err(disk_to_dev(nbd->disk), "device_create_file failed!\n");
+ dev_err(disk_to_dev(nbd->disk), "device_create_file failed for pid!\n");
return error;
}
set_bit(NBD_RT_HAS_PID_FILE, &config->runtime_flags);
@@ -1646,15 +1665,25 @@ static int nbd_dev_add(int index)
{
struct nbd_device *nbd;
struct gendisk *disk;
- struct request_queue *q;
int err = -ENOMEM;
nbd = kzalloc(sizeof(struct nbd_device), GFP_KERNEL);
if (!nbd)
goto out;
- disk = alloc_disk(1 << part_shift);
- if (!disk)
+ nbd->tag_set.ops = &nbd_mq_ops;
+ nbd->tag_set.nr_hw_queues = 1;
+ nbd->tag_set.queue_depth = 128;
+ nbd->tag_set.numa_node = NUMA_NO_NODE;
+ nbd->tag_set.cmd_size = sizeof(struct nbd_cmd);
+ nbd->tag_set.flags = BLK_MQ_F_SHOULD_MERGE |
+ BLK_MQ_F_BLOCKING;
+ nbd->tag_set.driver_data = nbd;
+ nbd->destroy_complete = NULL;
+ nbd->backend = NULL;
+
+ err = blk_mq_alloc_tag_set(&nbd->tag_set);
+ if (err)
goto out_free_nbd;
if (index >= 0) {
@@ -1668,30 +1697,15 @@ static int nbd_dev_add(int index)
index = err;
}
if (err < 0)
- goto out_free_disk;
-
+ goto out_free_tags;
nbd->index = index;
- nbd->disk = disk;
- nbd->tag_set.ops = &nbd_mq_ops;
- nbd->tag_set.nr_hw_queues = 1;
- nbd->tag_set.queue_depth = 128;
- nbd->tag_set.numa_node = NUMA_NO_NODE;
- nbd->tag_set.cmd_size = sizeof(struct nbd_cmd);
- nbd->tag_set.flags = BLK_MQ_F_SHOULD_MERGE |
- BLK_MQ_F_BLOCKING;
- nbd->tag_set.driver_data = nbd;
- nbd->destroy_complete = NULL;
- err = blk_mq_alloc_tag_set(&nbd->tag_set);
- if (err)
+ disk = blk_mq_alloc_disk(&nbd->tag_set, NULL);
+ if (IS_ERR(disk)) {
+ err = PTR_ERR(disk);
goto out_free_idr;
-
- q = blk_mq_init_queue(&nbd->tag_set);
- if (IS_ERR(q)) {
- err = PTR_ERR(q);
- goto out_free_tags;
}
- disk->queue = q;
+ nbd->disk = disk;
/*
* Tell the block layer that we are not a rotational device
@@ -1712,6 +1726,7 @@ static int nbd_dev_add(int index)
INIT_LIST_HEAD(&nbd->list);
disk->major = NBD_MAJOR;
disk->first_minor = index << part_shift;
+ disk->minors = 1 << part_shift;
disk->fops = &nbd_fops;
disk->private_data = nbd;
sprintf(disk->disk_name, "nbd%d", index);
@@ -1719,12 +1734,10 @@ static int nbd_dev_add(int index)
nbd_total_devices++;
return index;
-out_free_tags:
- blk_mq_free_tag_set(&nbd->tag_set);
out_free_idr:
idr_remove(&nbd_index_idr, index);
-out_free_disk:
- put_disk(disk);
+out_free_tags:
+ blk_mq_free_tag_set(&nbd->tag_set);
out_free_nbd:
kfree(nbd);
out:
@@ -1754,6 +1767,7 @@ static const struct nla_policy nbd_attr_policy[NBD_ATTR_MAX + 1] = {
[NBD_ATTR_SOCKETS] = { .type = NLA_NESTED},
[NBD_ATTR_DEAD_CONN_TIMEOUT] = { .type = NLA_U64 },
[NBD_ATTR_DEVICE_LIST] = { .type = NLA_NESTED},
+ [NBD_ATTR_BACKEND_IDENTIFIER] = { .type = NLA_STRING},
};
static const struct nla_policy nbd_sock_policy[NBD_SOCK_MAX + 1] = {
@@ -1956,6 +1970,23 @@ again:
}
}
ret = nbd_start_device(nbd);
+ if (ret)
+ goto out;
+ if (info->attrs[NBD_ATTR_BACKEND_IDENTIFIER]) {
+ nbd->backend = nla_strdup(info->attrs[NBD_ATTR_BACKEND_IDENTIFIER],
+ GFP_KERNEL);
+ if (!nbd->backend) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+ ret = device_create_file(disk_to_dev(nbd->disk), &backend_attr);
+ if (ret) {
+ dev_err(disk_to_dev(nbd->disk),
+ "device_create_file failed for backend!\n");
+ goto out;
+ }
+ set_bit(NBD_RT_HAS_BACKEND_FILE, &config->runtime_flags);
out:
mutex_unlock(&nbd->config_lock);
if (!ret) {
@@ -2048,6 +2079,22 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
index);
return -EINVAL;
}
+ if (nbd->backend) {
+ if (info->attrs[NBD_ATTR_BACKEND_IDENTIFIER]) {
+ if (nla_strcmp(info->attrs[NBD_ATTR_BACKEND_IDENTIFIER],
+ nbd->backend)) {
+ mutex_unlock(&nbd_index_mutex);
+ dev_err(nbd_to_dev(nbd),
+ "backend image doesn't match with %s\n",
+ nbd->backend);
+ return -EINVAL;
+ }
+ } else {
+ mutex_unlock(&nbd_index_mutex);
+ dev_err(nbd_to_dev(nbd), "must specify backend\n");
+ return -EINVAL;
+ }
+ }
if (!refcount_inc_not_zero(&nbd->refs)) {
mutex_unlock(&nbd_index_mutex);
printk(KERN_ERR "nbd: device at index %d is going down\n",
diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
index 5f006d9e1472..d734e9ee1546 100644
--- a/drivers/block/null_blk/main.c
+++ b/drivers/block/null_blk/main.c
@@ -1597,11 +1597,10 @@ static void null_del_dev(struct nullb *nullb)
null_restart_queue_async(nullb);
}
- blk_cleanup_queue(nullb->q);
+ blk_cleanup_disk(nullb->disk);
if (dev->queue_mode == NULL_Q_MQ &&
nullb->tag_set == &nullb->__tag_set)
blk_mq_free_tag_set(nullb->tag_set);
- put_disk(nullb->disk);
cleanup_queues(nullb);
if (null_cache_active(nullb))
null_free_device_storage(nullb->dev, true);
@@ -1700,22 +1699,19 @@ static int init_driver_queues(struct nullb *nullb)
static int null_gendisk_register(struct nullb *nullb)
{
sector_t size = ((sector_t)nullb->dev->size * SZ_1M) >> SECTOR_SHIFT;
- struct gendisk *disk;
+ struct gendisk *disk = nullb->disk;
- disk = nullb->disk = alloc_disk_node(1, nullb->dev->home_node);
- if (!disk)
- return -ENOMEM;
set_capacity(disk, size);
disk->flags |= GENHD_FL_EXT_DEVT | GENHD_FL_SUPPRESS_PARTITION_INFO;
disk->major = null_major;
disk->first_minor = nullb->index;
+ disk->minors = 1;
if (queue_is_mq(nullb->q))
disk->fops = &null_rq_ops;
else
disk->fops = &null_bio_ops;
disk->private_data = nullb;
- disk->queue = nullb->q;
strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN);
if (nullb->dev->zoned) {
@@ -1851,23 +1847,25 @@ static int null_add_dev(struct nullb_device *dev)
goto out_cleanup_queues;
if (!null_setup_fault())
- goto out_cleanup_queues;
+ goto out_cleanup_tags;
nullb->tag_set->timeout = 5 * HZ;
- nullb->q = blk_mq_init_queue_data(nullb->tag_set, nullb);
- if (IS_ERR(nullb->q)) {
- rv = -ENOMEM;
+ nullb->disk = blk_mq_alloc_disk(nullb->tag_set, nullb);
+ if (IS_ERR(nullb->disk)) {
+ rv = PTR_ERR(nullb->disk);
goto out_cleanup_tags;
}
+ nullb->q = nullb->disk->queue;
} else if (dev->queue_mode == NULL_Q_BIO) {
- nullb->q = blk_alloc_queue(dev->home_node);
- if (!nullb->q) {
- rv = -ENOMEM;
+ rv = -ENOMEM;
+ nullb->disk = blk_alloc_disk(nullb->dev->home_node);
+ if (!nullb->disk)
goto out_cleanup_queues;
- }
+
+ nullb->q = nullb->disk->queue;
rv = init_driver_queues(nullb);
if (rv)
- goto out_cleanup_blk_queue;
+ goto out_cleanup_disk;
}
if (dev->mbps) {
@@ -1883,7 +1881,7 @@ static int null_add_dev(struct nullb_device *dev)
if (dev->zoned) {
rv = null_init_zoned_dev(dev, nullb->q);
if (rv)
- goto out_cleanup_blk_queue;
+ goto out_cleanup_disk;
}
nullb->q->queuedata = nullb;
@@ -1921,8 +1919,8 @@ static int null_add_dev(struct nullb_device *dev)
return 0;
out_cleanup_zone:
null_free_zoned_dev(dev);
-out_cleanup_blk_queue:
- blk_cleanup_queue(nullb->q);
+out_cleanup_disk:
+ blk_cleanup_disk(nullb->disk);
out_cleanup_tags:
if (dev->queue_mode == NULL_Q_MQ && nullb->tag_set == &nullb->__tag_set)
blk_mq_free_tag_set(nullb->tag_set);
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
index 70da8b86ce58..f9cdd11f02f5 100644
--- a/drivers/block/paride/pcd.c
+++ b/drivers/block/paride/pcd.c
@@ -309,21 +309,19 @@ static void pcd_init_units(void)
pcd_drive_count = 0;
for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
- struct gendisk *disk = alloc_disk(1);
+ struct gendisk *disk;
- if (!disk)
+ if (blk_mq_alloc_sq_tag_set(&cd->tag_set, &pcd_mq_ops, 1,
+ BLK_MQ_F_SHOULD_MERGE))
continue;
- disk->queue = blk_mq_init_sq_queue(&cd->tag_set, &pcd_mq_ops,
- 1, BLK_MQ_F_SHOULD_MERGE);
- if (IS_ERR(disk->queue)) {
- disk->queue = NULL;
- put_disk(disk);
+ disk = blk_mq_alloc_disk(&cd->tag_set, cd);
+ if (IS_ERR(disk)) {
+ blk_mq_free_tag_set(&cd->tag_set);
continue;
}
INIT_LIST_HEAD(&cd->rq_list);
- disk->queue->queuedata = cd;
blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH);
cd->disk = disk;
cd->pi = &cd->pia;
@@ -343,6 +341,7 @@ static void pcd_init_units(void)
cd->info.mask = 0;
disk->major = major;
disk->first_minor = unit;
+ disk->minors = 1;
strcpy(disk->disk_name, cd->name); /* umm... */
disk->fops = &pcd_bdops;
disk->flags = GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
@@ -759,10 +758,8 @@ static int pcd_detect(void)
for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
if (!cd->disk)
continue;
- blk_cleanup_queue(cd->disk->queue);
- cd->disk->queue = NULL;
+ blk_cleanup_disk(cd->disk);
blk_mq_free_tag_set(&cd->tag_set);
- put_disk(cd->disk);
}
pi_unregister_driver(par_drv);
return -1;
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 828a45ffe0e7..9b3298926356 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -879,18 +879,6 @@ static void pd_probe_drive(struct pd_unit *disk)
{
struct gendisk *p;
- p = alloc_disk(1 << PD_BITS);
- if (!p)
- return;
-
- strcpy(p->disk_name, disk->name);
- p->fops = &pd_fops;
- p->major = major;
- p->first_minor = (disk - pd) << PD_BITS;
- p->events = DISK_EVENT_MEDIA_CHANGE;
- disk->gd = p;
- p->private_data = disk;
-
memset(&disk->tag_set, 0, sizeof(disk->tag_set));
disk->tag_set.ops = &pd_mq_ops;
disk->tag_set.cmd_size = sizeof(struct pd_req);
@@ -903,14 +891,21 @@ static void pd_probe_drive(struct pd_unit *disk)
if (blk_mq_alloc_tag_set(&disk->tag_set))
return;
- p->queue = blk_mq_init_queue(&disk->tag_set);
- if (IS_ERR(p->queue)) {
+ p = blk_mq_alloc_disk(&disk->tag_set, disk);
+ if (!p) {
blk_mq_free_tag_set(&disk->tag_set);
- p->queue = NULL;
return;
}
+ disk->gd = p;
+
+ strcpy(p->disk_name, disk->name);
+ p->fops = &pd_fops;
+ p->major = major;
+ p->first_minor = (disk - pd) << PD_BITS;
+ p->minors = 1 << PD_BITS;
+ p->events = DISK_EVENT_MEDIA_CHANGE;
+ p->private_data = disk;
- p->queue->queuedata = disk;
blk_queue_max_hw_sectors(p->queue, cluster);
blk_queue_bounce_limit(p->queue, BLK_BOUNCE_HIGH);
@@ -1019,9 +1014,8 @@ static void __exit pd_exit(void)
if (p) {
disk->gd = NULL;
del_gendisk(p);
- blk_cleanup_queue(p->queue);
+ blk_cleanup_disk(p);
blk_mq_free_tag_set(&disk->tag_set);
- put_disk(p);
pi_release(disk->pi);
}
}
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index bb09f21ce21a..d5b9c88ba76f 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -294,20 +294,17 @@ static void __init pf_init_units(void)
for (unit = 0, pf = units; unit < PF_UNITS; unit++, pf++) {
struct gendisk *disk;
- disk = alloc_disk(1);
- if (!disk)
+ if (blk_mq_alloc_sq_tag_set(&pf->tag_set, &pf_mq_ops, 1,
+ BLK_MQ_F_SHOULD_MERGE))
continue;
- disk->queue = blk_mq_init_sq_queue(&pf->tag_set, &pf_mq_ops,
- 1, BLK_MQ_F_SHOULD_MERGE);
- if (IS_ERR(disk->queue)) {
- disk->queue = NULL;
- put_disk(disk);
+ disk = blk_mq_alloc_disk(&pf->tag_set, pf);
+ if (IS_ERR(disk)) {
+ blk_mq_free_tag_set(&pf->tag_set);
continue;
}
INIT_LIST_HEAD(&pf->rq_list);
- disk->queue->queuedata = pf;
blk_queue_max_segments(disk->queue, cluster);
blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH);
pf->disk = disk;
@@ -318,6 +315,7 @@ static void __init pf_init_units(void)
snprintf(pf->name, PF_NAMELEN, "%s%d", name, unit);
disk->major = major;
disk->first_minor = unit;
+ disk->minors = 1;
strcpy(disk->disk_name, pf->name);
disk->fops = &pf_fops;
disk->events = DISK_EVENT_MEDIA_CHANGE;
@@ -766,10 +764,8 @@ static int pf_detect(void)
for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) {
if (!pf->disk)
continue;
- blk_cleanup_queue(pf->disk->queue);
- pf->disk->queue = NULL;
+ blk_cleanup_disk(pf->disk);
blk_mq_free_tag_set(&pf->tag_set);
- put_disk(pf->disk);
}
pi_unregister_driver(par_drv);
return -1;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index bd3556585122..538446b652de 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -704,7 +704,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
int ret = 0;
rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ?
- REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0);
+ REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
if (IS_ERR(rq))
return PTR_ERR(rq);
@@ -2711,19 +2711,17 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
pd->write_congestion_off = write_congestion_off;
ret = -ENOMEM;
- disk = alloc_disk(1);
+ disk = blk_alloc_disk(NUMA_NO_NODE);
if (!disk)
goto out_mem;
pd->disk = disk;
disk->major = pktdev_major;
disk->first_minor = idx;
+ disk->minors = 1;
disk->fops = &pktcdvd_ops;
disk->flags = GENHD_FL_REMOVABLE;
strcpy(disk->disk_name, pd->name);
disk->private_data = pd;
- disk->queue = blk_alloc_queue(NUMA_NO_NODE);
- if (!disk->queue)
- goto out_mem2;
pd->pkt_dev = MKDEV(pktdev_major, idx);
ret = pkt_new_dev(pd, dev);
@@ -2746,7 +2744,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
return 0;
out_mem2:
- put_disk(disk);
+ blk_cleanup_disk(disk);
out_mem:
mempool_exit(&pd->rb_pool);
kfree(pd);
@@ -2796,8 +2794,7 @@ static int pkt_remove_dev(dev_t pkt_dev)
pkt_dbg(1, pd, "writer unmapped\n");
del_gendisk(pd->disk);
- blk_cleanup_queue(pd->disk->queue);
- put_disk(pd->disk);
+ blk_cleanup_disk(pd->disk);
mempool_exit(&pd->rb_pool);
kfree(pd);
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
index ba3ece56cbb3..f374ea2c67ce 100644
--- a/drivers/block/ps3disk.c
+++ b/drivers/block/ps3disk.c
@@ -29,7 +29,6 @@
struct ps3disk_private {
spinlock_t lock; /* Request queue spinlock */
- struct request_queue *queue;
struct blk_mq_tag_set tag_set;
struct gendisk *gendisk;
unsigned int blocking_factor;
@@ -267,7 +266,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
blk_mq_end_request(req, error);
spin_unlock(&priv->lock);
- blk_mq_run_hw_queues(priv->queue, true);
+ blk_mq_run_hw_queues(priv->gendisk->queue, true);
return IRQ_HANDLED;
}
@@ -441,17 +440,20 @@ static int ps3disk_probe(struct ps3_system_bus_device *_dev)
ps3disk_identify(dev);
- queue = blk_mq_init_sq_queue(&priv->tag_set, &ps3disk_mq_ops, 1,
+ error = blk_mq_alloc_sq_tag_set(&priv->tag_set, &ps3disk_mq_ops, 1,
BLK_MQ_F_SHOULD_MERGE);
- if (IS_ERR(queue)) {
- dev_err(&dev->sbd.core, "%s:%u: blk_mq_init_queue failed\n",
- __func__, __LINE__);
- error = PTR_ERR(queue);
+ if (error)
goto fail_teardown;
+
+ gendisk = blk_mq_alloc_disk(&priv->tag_set, dev);
+ if (IS_ERR(gendisk)) {
+ dev_err(&dev->sbd.core, "%s:%u: blk_mq_alloc_disk failed\n",
+ __func__, __LINE__);
+ error = PTR_ERR(gendisk);
+ goto fail_free_tag_set;
}
- priv->queue = queue;
- queue->queuedata = dev;
+ queue = gendisk->queue;
blk_queue_max_hw_sectors(queue, dev->bounce_size >> 9);
blk_queue_dma_alignment(queue, dev->blk_size-1);
@@ -462,19 +464,11 @@ static int ps3disk_probe(struct ps3_system_bus_device *_dev)
blk_queue_max_segments(queue, -1);
blk_queue_max_segment_size(queue, dev->bounce_size);
- gendisk = alloc_disk(PS3DISK_MINORS);
- if (!gendisk) {
- dev_err(&dev->sbd.core, "%s:%u: alloc_disk failed\n", __func__,
- __LINE__);
- error = -ENOMEM;
- goto fail_cleanup_queue;
- }
-
priv->gendisk = gendisk;
gendisk->major = ps3disk_major;
gendisk->first_minor = devidx * PS3DISK_MINORS;
+ gendisk->minors = PS3DISK_MINORS;
gendisk->fops = &ps3disk_fops;
- gendisk->queue = queue;
gendisk->private_data = dev;
snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), PS3DISK_NAME,
devidx+'a');
@@ -490,8 +484,7 @@ static int ps3disk_probe(struct ps3_system_bus_device *_dev)
device_add_disk(&dev->sbd.core, gendisk, NULL);
return 0;
-fail_cleanup_queue:
- blk_cleanup_queue(queue);
+fail_free_tag_set:
blk_mq_free_tag_set(&priv->tag_set);
fail_teardown:
ps3stor_teardown(dev);
@@ -517,9 +510,8 @@ static void ps3disk_remove(struct ps3_system_bus_device *_dev)
&ps3disk_mask);
mutex_unlock(&ps3disk_mask_mutex);
del_gendisk(priv->gendisk);
- blk_cleanup_queue(priv->queue);
+ blk_cleanup_disk(priv->gendisk);
blk_mq_free_tag_set(&priv->tag_set);
- put_disk(priv->gendisk);
dev_notice(&dev->sbd.core, "Synchronizing disk cache\n");
ps3disk_sync_cache(dev);
ps3stor_teardown(dev);
diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c
index 1d738999fb69..7fbf469651c4 100644
--- a/drivers/block/ps3vram.c
+++ b/drivers/block/ps3vram.c
@@ -67,7 +67,6 @@ struct ps3vram_cache {
};
struct ps3vram_priv {
- struct request_queue *queue;
struct gendisk *gendisk;
u64 size;
@@ -613,7 +612,6 @@ static int ps3vram_probe(struct ps3_system_bus_device *dev)
{
struct ps3vram_priv *priv;
int error, status;
- struct request_queue *queue;
struct gendisk *gendisk;
u64 ddr_size, ddr_lpar, ctrl_lpar, info_lpar, reports_lpar,
reports_size, xdr_lpar;
@@ -736,33 +734,23 @@ static int ps3vram_probe(struct ps3_system_bus_device *dev)
ps3vram_proc_init(dev);
- queue = blk_alloc_queue(NUMA_NO_NODE);
- if (!queue) {
- dev_err(&dev->core, "blk_alloc_queue failed\n");
- error = -ENOMEM;
- goto out_cache_cleanup;
- }
-
- priv->queue = queue;
- blk_queue_max_segments(queue, BLK_MAX_SEGMENTS);
- blk_queue_max_segment_size(queue, BLK_MAX_SEGMENT_SIZE);
- blk_queue_max_hw_sectors(queue, BLK_SAFE_MAX_SECTORS);
-
- gendisk = alloc_disk(1);
+ gendisk = blk_alloc_disk(NUMA_NO_NODE);
if (!gendisk) {
- dev_err(&dev->core, "alloc_disk failed\n");
+ dev_err(&dev->core, "blk_alloc_disk failed\n");
error = -ENOMEM;
- goto fail_cleanup_queue;
+ goto out_cache_cleanup;
}
priv->gendisk = gendisk;
gendisk->major = ps3vram_major;
- gendisk->first_minor = 0;
+ gendisk->minors = 1;
gendisk->fops = &ps3vram_fops;
- gendisk->queue = queue;
gendisk->private_data = dev;
strlcpy(gendisk->disk_name, DEVICE_NAME, sizeof(gendisk->disk_name));
set_capacity(gendisk, priv->size >> 9);
+ blk_queue_max_segments(gendisk->queue, BLK_MAX_SEGMENTS);
+ blk_queue_max_segment_size(gendisk->queue, BLK_MAX_SEGMENT_SIZE);
+ blk_queue_max_hw_sectors(gendisk->queue, BLK_SAFE_MAX_SECTORS);
dev_info(&dev->core, "%s: Using %llu MiB of GPU memory\n",
gendisk->disk_name, get_capacity(gendisk) >> 11);
@@ -770,8 +758,6 @@ static int ps3vram_probe(struct ps3_system_bus_device *dev)
device_add_disk(&dev->core, gendisk, NULL);
return 0;
-fail_cleanup_queue:
- blk_cleanup_queue(queue);
out_cache_cleanup:
remove_proc_entry(DEVICE_NAME, NULL);
ps3vram_cache_cleanup(dev);
@@ -802,8 +788,7 @@ static void ps3vram_remove(struct ps3_system_bus_device *dev)
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
del_gendisk(priv->gendisk);
- put_disk(priv->gendisk);
- blk_cleanup_queue(priv->queue);
+ blk_cleanup_disk(priv->gendisk);
remove_proc_entry(DEVICE_NAME, NULL);
ps3vram_cache_cleanup(dev);
iounmap(priv->reports);
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index bbb88eb009e0..531d390902dd 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -4750,9 +4750,8 @@ static blk_status_t rbd_queue_rq(struct blk_mq_hw_ctx *hctx,
static void rbd_free_disk(struct rbd_device *rbd_dev)
{
- blk_cleanup_queue(rbd_dev->disk->queue);
+ blk_cleanup_disk(rbd_dev->disk);
blk_mq_free_tag_set(&rbd_dev->tag_set);
- put_disk(rbd_dev->disk);
rbd_dev->disk = NULL;
}
@@ -4922,22 +4921,6 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
rbd_dev->layout.object_size * rbd_dev->layout.stripe_count;
int err;
- /* create gendisk info */
- disk = alloc_disk(single_major ?
- (1 << RBD_SINGLE_MAJOR_PART_SHIFT) :
- RBD_MINORS_PER_MAJOR);
- if (!disk)
- return -ENOMEM;
-
- snprintf(disk->disk_name, sizeof(disk->disk_name), RBD_DRV_NAME "%d",
- rbd_dev->dev_id);
- disk->major = rbd_dev->major;
- disk->first_minor = rbd_dev->minor;
- if (single_major)
- disk->flags |= GENHD_FL_EXT_DEVT;
- disk->fops = &rbd_bd_ops;
- disk->private_data = rbd_dev;
-
memset(&rbd_dev->tag_set, 0, sizeof(rbd_dev->tag_set));
rbd_dev->tag_set.ops = &rbd_mq_ops;
rbd_dev->tag_set.queue_depth = rbd_dev->opts->queue_depth;
@@ -4948,13 +4931,26 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
err = blk_mq_alloc_tag_set(&rbd_dev->tag_set);
if (err)
- goto out_disk;
+ return err;
- q = blk_mq_init_queue(&rbd_dev->tag_set);
- if (IS_ERR(q)) {
- err = PTR_ERR(q);
+ disk = blk_mq_alloc_disk(&rbd_dev->tag_set, rbd_dev);
+ if (IS_ERR(disk)) {
+ err = PTR_ERR(disk);
goto out_tag_set;
}
+ q = disk->queue;
+
+ snprintf(disk->disk_name, sizeof(disk->disk_name), RBD_DRV_NAME "%d",
+ rbd_dev->dev_id);
+ disk->major = rbd_dev->major;
+ disk->first_minor = rbd_dev->minor;
+ if (single_major) {
+ disk->minors = (1 << RBD_SINGLE_MAJOR_PART_SHIFT);
+ disk->flags |= GENHD_FL_EXT_DEVT;
+ } else {
+ disk->minors = RBD_MINORS_PER_MAJOR;
+ }
+ disk->fops = &rbd_bd_ops;
blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
/* QUEUE_FLAG_ADD_RANDOM is off by default for blk-mq */
@@ -4976,21 +4972,11 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
if (!ceph_test_opt(rbd_dev->rbd_client->client, NOCRC))
blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, q);
- /*
- * disk_release() expects a queue ref from add_disk() and will
- * put it. Hold an extra ref until add_disk() is called.
- */
- WARN_ON(!blk_get_queue(q));
- disk->queue = q;
- q->queuedata = rbd_dev;
-
rbd_dev->disk = disk;
return 0;
out_tag_set:
blk_mq_free_tag_set(&rbd_dev->tag_set);
-out_disk:
- put_disk(disk);
return err;
}
@@ -7088,8 +7074,6 @@ static ssize_t do_rbd_add(struct bus_type *bus,
goto err_out_image_lock;
device_add_disk(&rbd_dev->dev, rbd_dev->disk, NULL);
- /* see rbd_init_disk() */
- blk_put_queue(rbd_dev->disk->queue);
spin_lock(&rbd_dev_list_lock);
list_add_tail(&rbd_dev->node, &rbd_dev_list);
diff --git a/drivers/block/rnbd/rnbd-clt.c b/drivers/block/rnbd/rnbd-clt.c
index c604a402cd5c..e9cc413495f0 100644
--- a/drivers/block/rnbd/rnbd-clt.c
+++ b/drivers/block/rnbd/rnbd-clt.c
@@ -92,7 +92,7 @@ static int rnbd_clt_set_dev_attr(struct rnbd_clt_dev *dev,
dev->fua = !!(rsp->cache_policy & RNBD_FUA);
dev->max_hw_sectors = sess->max_io_size / SECTOR_SIZE;
- dev->max_segments = BMAX_SEGMENTS;
+ dev->max_segments = sess->max_segments;
return 0;
}
@@ -1292,7 +1292,7 @@ find_and_get_or_create_sess(const char *sessname,
sess->rtrs = rtrs_clt_open(&rtrs_ops, sessname,
paths, path_cnt, port_nr,
0, /* Do not use pdu of rtrs */
- RECONNECT_DELAY, BMAX_SEGMENTS,
+ RECONNECT_DELAY,
MAX_RECONNECTS, nr_poll_queues);
if (IS_ERR(sess->rtrs)) {
err = PTR_ERR(sess->rtrs);
@@ -1306,6 +1306,7 @@ find_and_get_or_create_sess(const char *sessname,
sess->max_io_size = attrs.max_io_size;
sess->queue_depth = attrs.queue_depth;
sess->nr_poll_queues = nr_poll_queues;
+ sess->max_segments = attrs.max_segments;
err = setup_mq_tags(sess);
if (err)
@@ -1353,18 +1354,6 @@ static void rnbd_init_mq_hw_queues(struct rnbd_clt_dev *dev)
}
}
-static int setup_mq_dev(struct rnbd_clt_dev *dev)
-{
- dev->queue = blk_mq_init_queue(&dev->sess->tag_set);
- if (IS_ERR(dev->queue)) {
- rnbd_clt_err(dev, "Initializing multiqueue queue failed, err: %ld\n",
- PTR_ERR(dev->queue));
- return PTR_ERR(dev->queue);
- }
- rnbd_init_mq_hw_queues(dev);
- return 0;
-}
-
static void setup_request_queue(struct rnbd_clt_dev *dev)
{
blk_queue_logical_block_size(dev->queue, dev->logical_block_size);
@@ -1393,13 +1382,13 @@ static void setup_request_queue(struct rnbd_clt_dev *dev)
blk_queue_io_opt(dev->queue, dev->sess->max_io_size);
blk_queue_virt_boundary(dev->queue, SZ_4K - 1);
blk_queue_write_cache(dev->queue, dev->wc, dev->fua);
- dev->queue->queuedata = dev;
}
static void rnbd_clt_setup_gen_disk(struct rnbd_clt_dev *dev, int idx)
{
dev->gd->major = rnbd_client_major;
dev->gd->first_minor = idx << RNBD_PART_BITS;
+ dev->gd->minors = 1 << RNBD_PART_BITS;
dev->gd->fops = &rnbd_client_ops;
dev->gd->queue = dev->queue;
dev->gd->private_data = dev;
@@ -1426,24 +1415,18 @@ static void rnbd_clt_setup_gen_disk(struct rnbd_clt_dev *dev, int idx)
static int rnbd_client_setup_device(struct rnbd_clt_dev *dev)
{
- int err, idx = dev->clt_device_id;
+ int idx = dev->clt_device_id;
dev->size = dev->nsectors * dev->logical_block_size;
- err = setup_mq_dev(dev);
- if (err)
- return err;
+ dev->gd = blk_mq_alloc_disk(&dev->sess->tag_set, dev);
+ if (IS_ERR(dev->gd))
+ return PTR_ERR(dev->gd);
+ dev->queue = dev->gd->queue;
+ rnbd_init_mq_hw_queues(dev);
setup_request_queue(dev);
-
- dev->gd = alloc_disk_node(1 << RNBD_PART_BITS, NUMA_NO_NODE);
- if (!dev->gd) {
- blk_cleanup_queue(dev->queue);
- return -ENOMEM;
- }
-
rnbd_clt_setup_gen_disk(dev, idx);
-
return 0;
}
@@ -1650,8 +1633,7 @@ put_sess:
static void destroy_gen_disk(struct rnbd_clt_dev *dev)
{
del_gendisk(dev->gd);
- blk_cleanup_queue(dev->queue);
- put_disk(dev->gd);
+ blk_cleanup_disk(dev->gd);
}
static void destroy_sysfs(struct rnbd_clt_dev *dev,
diff --git a/drivers/block/rnbd/rnbd-clt.h b/drivers/block/rnbd/rnbd-clt.h
index b5322c5aaac0..9ef8c4f306f2 100644
--- a/drivers/block/rnbd/rnbd-clt.h
+++ b/drivers/block/rnbd/rnbd-clt.h
@@ -20,10 +20,6 @@
#include "rnbd-proto.h"
#include "rnbd-log.h"
-/* Max. number of segments per IO request, Mellanox Connect X ~ Connect X5,
- * choose minimial 30 for all, minus 1 for internal protocol, so 29.
- */
-#define BMAX_SEGMENTS 29
/* time in seconds between reconnect tries, default to 30 s */
#define RECONNECT_DELAY 30
/*
@@ -89,6 +85,7 @@ struct rnbd_clt_session {
atomic_t busy;
size_t queue_depth;
u32 max_io_size;
+ u32 max_segments;
struct blk_mq_tag_set tag_set;
u32 nr_poll_queues;
struct mutex lock; /* protects state and devs_list */
diff --git a/drivers/block/rsxx/dev.c b/drivers/block/rsxx/dev.c
index 9a28322a8cd8..1cc40b0ea761 100644
--- a/drivers/block/rsxx/dev.c
+++ b/drivers/block/rsxx/dev.c
@@ -236,47 +236,40 @@ int rsxx_setup_dev(struct rsxx_cardinfo *card)
return -ENOMEM;
}
- card->queue = blk_alloc_queue(NUMA_NO_NODE);
- if (!card->queue) {
- dev_err(CARD_TO_DEV(card), "Failed queue alloc\n");
- unregister_blkdev(card->major, DRIVER_NAME);
- return -ENOMEM;
- }
-
- card->gendisk = alloc_disk(blkdev_minors);
+ card->gendisk = blk_alloc_disk(blkdev_minors);
if (!card->gendisk) {
dev_err(CARD_TO_DEV(card), "Failed disk alloc\n");
- blk_cleanup_queue(card->queue);
unregister_blkdev(card->major, DRIVER_NAME);
return -ENOMEM;
}
if (card->config_valid) {
blk_size = card->config.data.block_size;
- blk_queue_dma_alignment(card->queue, blk_size - 1);
- blk_queue_logical_block_size(card->queue, blk_size);
+ blk_queue_dma_alignment(card->gendisk->queue, blk_size - 1);
+ blk_queue_logical_block_size(card->gendisk->queue, blk_size);
}
- blk_queue_max_hw_sectors(card->queue, blkdev_max_hw_sectors);
- blk_queue_physical_block_size(card->queue, RSXX_HW_BLK_SIZE);
+ blk_queue_max_hw_sectors(card->gendisk->queue, blkdev_max_hw_sectors);
+ blk_queue_physical_block_size(card->gendisk->queue, RSXX_HW_BLK_SIZE);
- blk_queue_flag_set(QUEUE_FLAG_NONROT, card->queue);
- blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, card->queue);
+ blk_queue_flag_set(QUEUE_FLAG_NONROT, card->gendisk->queue);
+ blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, card->gendisk->queue);
if (rsxx_discard_supported(card)) {
- blk_queue_flag_set(QUEUE_FLAG_DISCARD, card->queue);
- blk_queue_max_discard_sectors(card->queue,
+ blk_queue_flag_set(QUEUE_FLAG_DISCARD, card->gendisk->queue);
+ blk_queue_max_discard_sectors(card->gendisk->queue,
RSXX_HW_BLK_SIZE >> 9);
- card->queue->limits.discard_granularity = RSXX_HW_BLK_SIZE;
- card->queue->limits.discard_alignment = RSXX_HW_BLK_SIZE;
+ card->gendisk->queue->limits.discard_granularity =
+ RSXX_HW_BLK_SIZE;
+ card->gendisk->queue->limits.discard_alignment =
+ RSXX_HW_BLK_SIZE;
}
snprintf(card->gendisk->disk_name, sizeof(card->gendisk->disk_name),
"rsxx%d", card->disk_id);
card->gendisk->major = card->major;
- card->gendisk->first_minor = 0;
+ card->gendisk->minors = blkdev_minors;
card->gendisk->fops = &rsxx_fops;
card->gendisk->private_data = card;
- card->gendisk->queue = card->queue;
return 0;
}
@@ -286,10 +279,8 @@ void rsxx_destroy_dev(struct rsxx_cardinfo *card)
if (!enable_blkdev)
return;
- put_disk(card->gendisk);
+ blk_cleanup_disk(card->gendisk);
card->gendisk = NULL;
-
- blk_cleanup_queue(card->queue);
unregister_blkdev(card->major, DRIVER_NAME);
}
diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c
index 0574f4495755..ed182f3dd054 100644
--- a/drivers/block/rsxx/dma.c
+++ b/drivers/block/rsxx/dma.c
@@ -74,9 +74,6 @@ struct dma_tracker {
struct rsxx_dma *dma;
};
-#define DMA_TRACKER_LIST_SIZE8 (sizeof(struct dma_tracker_list) + \
- (sizeof(struct dma_tracker) * RSXX_MAX_OUTSTANDING_CMDS))
-
struct dma_tracker_list {
spinlock_t lock;
int head;
@@ -808,7 +805,8 @@ static int rsxx_dma_ctrl_init(struct pci_dev *dev,
memset(&ctrl->stats, 0, sizeof(ctrl->stats));
- ctrl->trackers = vmalloc(DMA_TRACKER_LIST_SIZE8);
+ ctrl->trackers = vmalloc(struct_size(ctrl->trackers, list,
+ RSXX_MAX_OUTSTANDING_CMDS));
if (!ctrl->trackers)
return -ENOMEM;
diff --git a/drivers/block/rsxx/rsxx_priv.h b/drivers/block/rsxx/rsxx_priv.h
index 6147977994ff..26c320c0d924 100644
--- a/drivers/block/rsxx/rsxx_priv.h
+++ b/drivers/block/rsxx/rsxx_priv.h
@@ -154,7 +154,6 @@ struct rsxx_cardinfo {
bool bdev_attached;
int disk_id;
int major;
- struct request_queue *queue;
struct gendisk *gendisk;
struct {
/* Used to convert a byte address to a device address. */
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 39aeebc6837d..4d4bb810c2ae 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -780,27 +780,6 @@ static const struct blk_mq_ops vdc_mq_ops = {
.queue_rq = vdc_queue_rq,
};
-static void cleanup_queue(struct request_queue *q)
-{
- struct vdc_port *port = q->queuedata;
-
- blk_cleanup_queue(q);
- blk_mq_free_tag_set(&port->tag_set);
-}
-
-static struct request_queue *init_queue(struct vdc_port *port)
-{
- struct request_queue *q;
-
- q = blk_mq_init_sq_queue(&port->tag_set, &vdc_mq_ops, VDC_TX_RING_SIZE,
- BLK_MQ_F_SHOULD_MERGE);
- if (IS_ERR(q))
- return q;
-
- q->queuedata = port;
- return q;
-}
-
static int probe_disk(struct vdc_port *port)
{
struct request_queue *q;
@@ -838,21 +817,21 @@ static int probe_disk(struct vdc_port *port)
(u64)geom.num_sec);
}
- q = init_queue(port);
- if (IS_ERR(q)) {
- printk(KERN_ERR PFX "%s: Could not allocate queue.\n",
- port->vio.name);
- return PTR_ERR(q);
- }
- g = alloc_disk(1 << PARTITION_SHIFT);
- if (!g) {
+ err = blk_mq_alloc_sq_tag_set(&port->tag_set, &vdc_mq_ops,
+ VDC_TX_RING_SIZE, BLK_MQ_F_SHOULD_MERGE);
+ if (err)
+ return err;
+
+ g = blk_mq_alloc_disk(&port->tag_set, port);
+ if (IS_ERR(g)) {
printk(KERN_ERR PFX "%s: Could not allocate gendisk.\n",
port->vio.name);
- cleanup_queue(q);
- return -ENOMEM;
+ blk_mq_free_tag_set(&port->tag_set);
+ return PTR_ERR(g);
}
port->disk = g;
+ q = g->queue;
/* Each segment in a request is up to an aligned page in size. */
blk_queue_segment_boundary(q, PAGE_SIZE - 1);
@@ -862,6 +841,7 @@ static int probe_disk(struct vdc_port *port)
blk_queue_max_hw_sectors(q, port->max_xfer_size);
g->major = vdc_major;
g->first_minor = port->vio.vdev->dev_no << PARTITION_SHIFT;
+ g->minors = 1 << PARTITION_SHIFT;
strcpy(g->disk_name, port->disk_name);
g->fops = &vdc_fops;
@@ -1001,9 +981,8 @@ static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
}
port = kzalloc(sizeof(*port), GFP_KERNEL);
- err = -ENOMEM;
if (!port) {
- printk(KERN_ERR PFX "Cannot allocate vdc_port.\n");
+ err = -ENOMEM;
goto err_out_release_mdesc;
}
@@ -1071,7 +1050,7 @@ err_out_release_mdesc:
return err;
}
-static int vdc_port_remove(struct vio_dev *vdev)
+static void vdc_port_remove(struct vio_dev *vdev)
{
struct vdc_port *port = dev_get_drvdata(&vdev->dev);
@@ -1083,9 +1062,8 @@ static int vdc_port_remove(struct vio_dev *vdev)
del_timer_sync(&port->vio.timer);
del_gendisk(port->disk);
- cleanup_queue(port->disk->queue);
- put_disk(port->disk);
- port->disk = NULL;
+ blk_cleanup_disk(port->disk);
+ blk_mq_free_tag_set(&port->tag_set);
vdc_free_tx_ring(port);
vio_ldc_free(&port->vio);
@@ -1094,7 +1072,6 @@ static int vdc_port_remove(struct vio_dev *vdev)
kfree(port);
}
- return 0;
}
static void vdc_requeue_inflight(struct vdc_port *port)
diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 2917b21f48ff..7ccc8d2a41bc 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -800,23 +800,20 @@ static int swim_floppy_init(struct swim_priv *swd)
spin_lock_init(&swd->lock);
for (drive = 0; drive < swd->floppy_count; drive++) {
- struct request_queue *q;
-
- swd->unit[drive].disk = alloc_disk(1);
- if (swd->unit[drive].disk == NULL) {
- err = -ENOMEM;
+ err = blk_mq_alloc_sq_tag_set(&swd->unit[drive].tag_set,
+ &swim_mq_ops, 2, BLK_MQ_F_SHOULD_MERGE);
+ if (err)
goto exit_put_disks;
- }
- q = blk_mq_init_sq_queue(&swd->unit[drive].tag_set, &swim_mq_ops,
- 2, BLK_MQ_F_SHOULD_MERGE);
- if (IS_ERR(q)) {
- err = PTR_ERR(q);
+ swd->unit[drive].disk =
+ blk_mq_alloc_disk(&swd->unit[drive].tag_set,
+ &swd->unit[drive]);
+ if (IS_ERR(swd->unit[drive].disk)) {
+ blk_mq_free_tag_set(&swd->unit[drive].tag_set);
+ err = PTR_ERR(swd->unit[drive].disk);
goto exit_put_disks;
}
- swd->unit[drive].disk->queue = q;
- swd->unit[drive].disk->queue->queuedata = &swd->unit[drive];
swd->unit[drive].swd = swd;
}
@@ -824,6 +821,7 @@ static int swim_floppy_init(struct swim_priv *swd)
swd->unit[drive].disk->flags = GENHD_FL_REMOVABLE;
swd->unit[drive].disk->major = FLOPPY_MAJOR;
swd->unit[drive].disk->first_minor = drive;
+ swd->unit[drive].disk->minors = 1;
sprintf(swd->unit[drive].disk->disk_name, "fd%d", drive);
swd->unit[drive].disk->fops = &floppy_fops;
swd->unit[drive].disk->events = DISK_EVENT_MEDIA_CHANGE;
@@ -839,14 +837,10 @@ exit_put_disks:
do {
struct gendisk *disk = swd->unit[drive].disk;
- if (disk) {
- if (disk->queue) {
- blk_cleanup_queue(disk->queue);
- disk->queue = NULL;
- }
- blk_mq_free_tag_set(&swd->unit[drive].tag_set);
- put_disk(disk);
- }
+ if (!disk)
+ continue;
+ blk_cleanup_disk(disk);
+ blk_mq_free_tag_set(&swd->unit[drive].tag_set);
} while (drive--);
return err;
}
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index a515d0c1d2cb..965af0a3e95b 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -1202,30 +1202,27 @@ static int swim3_attach(struct macio_dev *mdev,
return rc;
}
- disk = alloc_disk(1);
- if (disk == NULL) {
- rc = -ENOMEM;
- goto out_unregister;
- }
-
fs = &floppy_states[floppy_count];
memset(fs, 0, sizeof(*fs));
- disk->queue = blk_mq_init_sq_queue(&fs->tag_set, &swim3_mq_ops, 2,
- BLK_MQ_F_SHOULD_MERGE);
- if (IS_ERR(disk->queue)) {
- rc = PTR_ERR(disk->queue);
- disk->queue = NULL;
- goto out_put_disk;
+ rc = blk_mq_alloc_sq_tag_set(&fs->tag_set, &swim3_mq_ops, 2,
+ BLK_MQ_F_SHOULD_MERGE);
+ if (rc)
+ goto out_unregister;
+
+ disk = blk_mq_alloc_disk(&fs->tag_set, fs);
+ if (IS_ERR(disk)) {
+ rc = PTR_ERR(disk);
+ goto out_free_tag_set;
}
- disk->queue->queuedata = fs;
rc = swim3_add_device(mdev, floppy_count);
if (rc)
- goto out_cleanup_queue;
+ goto out_cleanup_disk;
disk->major = FLOPPY_MAJOR;
disk->first_minor = floppy_count;
+ disk->minors = 1;
disk->fops = &floppy_fops;
disk->private_data = fs;
disk->events = DISK_EVENT_MEDIA_CHANGE;
@@ -1237,12 +1234,10 @@ static int swim3_attach(struct macio_dev *mdev,
disks[floppy_count++] = disk;
return 0;
-out_cleanup_queue:
- blk_cleanup_queue(disk->queue);
- disk->queue = NULL;
+out_cleanup_disk:
+ blk_cleanup_disk(disk);
+out_free_tag_set:
blk_mq_free_tag_set(&fs->tag_set);
-out_put_disk:
- put_disk(disk);
out_unregister:
if (floppy_count == 0)
unregister_blkdev(FLOPPY_MAJOR, "fd");
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 2cdf2771f8e8..7b54353ee92b 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -1343,32 +1343,25 @@ static int carm_init_disk(struct carm_host *host, unsigned int port_no)
{
struct carm_port *port = &host->port[port_no];
struct gendisk *disk;
- struct request_queue *q;
port->host = host;
port->port_no = port_no;
- disk = alloc_disk(CARM_MINORS_PER_MAJOR);
- if (!disk)
- return -ENOMEM;
+ disk = blk_mq_alloc_disk(&host->tag_set, port);
+ if (IS_ERR(disk))
+ return PTR_ERR(disk);
port->disk = disk;
sprintf(disk->disk_name, DRV_NAME "/%u",
(unsigned int)host->id * CARM_MAX_PORTS + port_no);
disk->major = host->major;
disk->first_minor = port_no * CARM_MINORS_PER_MAJOR;
+ disk->minors = CARM_MINORS_PER_MAJOR;
disk->fops = &carm_bd_ops;
disk->private_data = port;
- q = blk_mq_init_queue(&host->tag_set);
- if (IS_ERR(q))
- return PTR_ERR(q);
-
- blk_queue_max_segments(q, CARM_MAX_REQ_SG);
- blk_queue_segment_boundary(q, CARM_SG_BOUNDARY);
-
- q->queuedata = port;
- disk->queue = q;
+ blk_queue_max_segments(disk->queue, CARM_MAX_REQ_SG);
+ blk_queue_segment_boundary(disk->queue, CARM_SG_BOUNDARY);
return 0;
}
@@ -1382,9 +1375,7 @@ static void carm_free_disk(struct carm_host *host, unsigned int port_no)
if (disk->flags & GENHD_FL_UP)
del_gendisk(disk);
- if (disk->queue)
- blk_cleanup_queue(disk->queue);
- put_disk(disk);
+ blk_cleanup_disk(disk);
}
static int carm_init_shm(struct carm_host *host)
@@ -1429,8 +1420,6 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
host = kzalloc(sizeof(*host), GFP_KERNEL);
if (!host) {
- printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n",
- pci_name(pdev));
rc = -ENOMEM;
goto err_out_regions;
}
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index b9fa3ef5b57c..4b49df2dfd23 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -21,6 +21,9 @@
#define VQ_NAME_LEN 16
#define MAX_DISCARD_SEGMENTS 256u
+/* The maximum number of sg elements that fit into a virtqueue */
+#define VIRTIO_BLK_MAX_SG_ELEMS 32768
+
static int major;
static DEFINE_IDA(vd_index_ida);
@@ -447,13 +450,6 @@ static void virtblk_update_capacity(struct virtio_blk *vblk, bool resize)
/* Host must always specify the capacity. */
virtio_cread(vdev, struct virtio_blk_config, capacity, &capacity);
- /* If capacity is too big, truncate with warning. */
- if ((sector_t)capacity != capacity) {
- dev_warn(&vdev->dev, "Capacity %llu too large: truncating\n",
- (unsigned long long)capacity);
- capacity = (sector_t)-1;
- }
-
nblocks = DIV_ROUND_UP_ULL(capacity, queue_logical_block_size(q) >> 9);
string_get_size(nblocks, queue_logical_block_size(q),
@@ -728,7 +724,10 @@ static int virtblk_probe(struct virtio_device *vdev)
if (err || !sg_elems)
sg_elems = 1;
- /* We need an extra sg elements at head and tail. */
+ /* Prevent integer overflows and honor max vq size */
+ sg_elems = min_t(u32, sg_elems, VIRTIO_BLK_MAX_SG_ELEMS - 2);
+
+ /* We need extra sg elements at head and tail. */
sg_elems += 2;
vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
if (!vblk) {
@@ -749,13 +748,6 @@ static int virtblk_probe(struct virtio_device *vdev)
if (err)
goto out_free_vblk;
- /* FIXME: How many partitions? How long is a piece of string? */
- vblk->disk = alloc_disk(1 << PART_BITS);
- if (!vblk->disk) {
- err = -ENOMEM;
- goto out_free_vq;
- }
-
/* Default queue sizing is to fill the ring. */
if (likely(!virtblk_queue_depth)) {
queue_depth = vblk->vqs[0].vq->num_free;
@@ -779,21 +771,20 @@ static int virtblk_probe(struct virtio_device *vdev)
err = blk_mq_alloc_tag_set(&vblk->tag_set);
if (err)
- goto out_put_disk;
+ goto out_free_vq;
- q = blk_mq_init_queue(&vblk->tag_set);
- if (IS_ERR(q)) {
- err = -ENOMEM;
+ vblk->disk = blk_mq_alloc_disk(&vblk->tag_set, vblk);
+ if (IS_ERR(vblk->disk)) {
+ err = PTR_ERR(vblk->disk);
goto out_free_tags;
}
- vblk->disk->queue = q;
-
- q->queuedata = vblk;
+ q = vblk->disk->queue;
virtblk_name_format("vd", index, vblk->disk->disk_name, DISK_NAME_LEN);
vblk->disk->major = major;
vblk->disk->first_minor = index_to_minor(index);
+ vblk->disk->minors = 1 << PART_BITS;
vblk->disk->private_data = vblk;
vblk->disk->fops = &virtblk_fops;
vblk->disk->flags |= GENHD_FL_EXT_DEVT;
@@ -892,8 +883,6 @@ static int virtblk_probe(struct virtio_device *vdev)
out_free_tags:
blk_mq_free_tag_set(&vblk->tag_set);
-out_put_disk:
- put_disk(vblk->disk);
out_free_vq:
vdev->config->del_vqs(vdev);
kfree(vblk->vqs);
@@ -913,8 +902,7 @@ static void virtblk_remove(struct virtio_device *vdev)
flush_work(&vblk->config_work);
del_gendisk(vblk->disk);
- blk_cleanup_queue(vblk->disk->queue);
-
+ blk_cleanup_disk(vblk->disk);
blk_mq_free_tag_set(&vblk->tag_set);
mutex_lock(&vblk->vdev_mutex);
@@ -925,7 +913,6 @@ static void virtblk_remove(struct virtio_device *vdev)
/* Virtqueues are stopped, nothing can use vblk->vdev anymore. */
vblk->vdev = NULL;
- put_disk(vblk->disk);
vdev->config->del_vqs(vdev);
kfree(vblk->vqs);
@@ -948,6 +935,8 @@ static int virtblk_freeze(struct virtio_device *vdev)
blk_mq_quiesce_queue(vblk->disk->queue);
vdev->config->del_vqs(vdev);
+ kfree(vblk->vqs);
+
return 0;
}
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 10df39a8b18d..d83fee21f6c5 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -502,34 +502,21 @@ static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
static int blkif_ioctl(struct block_device *bdev, fmode_t mode,
unsigned command, unsigned long argument)
{
- struct blkfront_info *info = bdev->bd_disk->private_data;
int i;
- dev_dbg(&info->xbdev->dev, "command: 0x%x, argument: 0x%lx\n",
- command, (long)argument);
-
switch (command) {
case CDROMMULTISESSION:
- dev_dbg(&info->xbdev->dev, "FIXME: support multisession CDs later\n");
for (i = 0; i < sizeof(struct cdrom_multisession); i++)
if (put_user(0, (char __user *)(argument + i)))
return -EFAULT;
return 0;
-
- case CDROM_GET_CAPABILITY: {
- struct gendisk *gd = info->gd;
- if (gd->flags & GENHD_FL_CD)
+ case CDROM_GET_CAPABILITY:
+ if (bdev->bd_disk->flags & GENHD_FL_CD)
return 0;
return -EINVAL;
- }
-
default:
- /*printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n",
- command);*/
- return -EINVAL; /* same return as native Linux */
+ return -EINVAL;
}
-
- return 0;
}
static unsigned long blkif_ring_get_request(struct blkfront_ring_info *rinfo,
@@ -968,48 +955,6 @@ static void blkif_set_queue_limits(struct blkfront_info *info)
blk_queue_dma_alignment(rq, 511);
}
-static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size,
- unsigned int physical_sector_size)
-{
- struct request_queue *rq;
- struct blkfront_info *info = gd->private_data;
-
- memset(&info->tag_set, 0, sizeof(info->tag_set));
- info->tag_set.ops = &blkfront_mq_ops;
- info->tag_set.nr_hw_queues = info->nr_rings;
- if (HAS_EXTRA_REQ && info->max_indirect_segments == 0) {
- /*
- * When indirect descriptior is not supported, the I/O request
- * will be split between multiple request in the ring.
- * To avoid problems when sending the request, divide by
- * 2 the depth of the queue.
- */
- info->tag_set.queue_depth = BLK_RING_SIZE(info) / 2;
- } else
- info->tag_set.queue_depth = BLK_RING_SIZE(info);
- info->tag_set.numa_node = NUMA_NO_NODE;
- info->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
- info->tag_set.cmd_size = sizeof(struct blkif_req);
- info->tag_set.driver_data = info;
-
- if (blk_mq_alloc_tag_set(&info->tag_set))
- return -EINVAL;
- rq = blk_mq_init_queue(&info->tag_set);
- if (IS_ERR(rq)) {
- blk_mq_free_tag_set(&info->tag_set);
- return PTR_ERR(rq);
- }
-
- rq->queuedata = info;
- info->rq = gd->queue = rq;
- info->gd = gd;
- info->sector_size = sector_size;
- info->physical_sector_size = physical_sector_size;
- blkif_set_queue_limits(info);
-
- return 0;
-}
-
static const char *flush_info(struct blkfront_info *info)
{
if (info->feature_flush && info->feature_fua)
@@ -1146,12 +1091,36 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
err = xlbd_reserve_minors(minor, nr_minors);
if (err)
- goto out;
+ return err;
err = -ENODEV;
- gd = alloc_disk(nr_minors);
- if (gd == NULL)
- goto release;
+ memset(&info->tag_set, 0, sizeof(info->tag_set));
+ info->tag_set.ops = &blkfront_mq_ops;
+ info->tag_set.nr_hw_queues = info->nr_rings;
+ if (HAS_EXTRA_REQ && info->max_indirect_segments == 0) {
+ /*
+ * When indirect descriptior is not supported, the I/O request
+ * will be split between multiple request in the ring.
+ * To avoid problems when sending the request, divide by
+ * 2 the depth of the queue.
+ */
+ info->tag_set.queue_depth = BLK_RING_SIZE(info) / 2;
+ } else
+ info->tag_set.queue_depth = BLK_RING_SIZE(info);
+ info->tag_set.numa_node = NUMA_NO_NODE;
+ info->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
+ info->tag_set.cmd_size = sizeof(struct blkif_req);
+ info->tag_set.driver_data = info;
+
+ err = blk_mq_alloc_tag_set(&info->tag_set);
+ if (err)
+ goto out_release_minors;
+
+ gd = blk_mq_alloc_disk(&info->tag_set, info);
+ if (IS_ERR(gd)) {
+ err = PTR_ERR(gd);
+ goto out_free_tag_set;
+ }
strcpy(gd->disk_name, DEV_NAME);
ptr = encode_disk_name(gd->disk_name + sizeof(DEV_NAME) - 1, offset);
@@ -1164,14 +1133,16 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
gd->major = XENVBD_MAJOR;
gd->first_minor = minor;
+ gd->minors = nr_minors;
gd->fops = &xlvbd_block_fops;
gd->private_data = info;
set_capacity(gd, capacity);
- if (xlvbd_init_blk_queue(gd, sector_size, physical_sector_size)) {
- del_gendisk(gd);
- goto release;
- }
+ info->rq = gd->queue;
+ info->gd = gd;
+ info->sector_size = sector_size;
+ info->physical_sector_size = physical_sector_size;
+ blkif_set_queue_limits(info);
xlvbd_flush(info);
@@ -1186,45 +1157,13 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
return 0;
- release:
+out_free_tag_set:
+ blk_mq_free_tag_set(&info->tag_set);
+out_release_minors:
xlbd_release_minors(minor, nr_minors);
- out:
return err;
}
-static void xlvbd_release_gendisk(struct blkfront_info *info)
-{
- unsigned int minor, nr_minors, i;
- struct blkfront_ring_info *rinfo;
-
- if (info->rq == NULL)
- return;
-
- /* No more blkif_request(). */
- blk_mq_stop_hw_queues(info->rq);
-
- for_each_rinfo(info, rinfo, i) {
- /* No more gnttab callback work. */
- gnttab_cancel_free_callback(&rinfo->callback);
-
- /* Flush gnttab callback work. Must be done with no locks held. */
- flush_work(&rinfo->work);
- }
-
- del_gendisk(info->gd);
-
- minor = info->gd->first_minor;
- nr_minors = info->gd->minors;
- xlbd_release_minors(minor, nr_minors);
-
- blk_cleanup_queue(info->rq);
- blk_mq_free_tag_set(&info->tag_set);
- info->rq = NULL;
-
- put_disk(info->gd);
- info->gd = NULL;
-}
-
/* Already hold rinfo->ring_lock. */
static inline void kick_pending_request_queues_locked(struct blkfront_ring_info *rinfo)
{
@@ -1774,12 +1713,6 @@ abort_transaction:
return err;
}
-static void free_info(struct blkfront_info *info)
-{
- list_del(&info->info_list);
- kfree(info);
-}
-
/* Common code used when first setting up, and when resuming. */
static int talk_to_blkback(struct xenbus_device *dev,
struct blkfront_info *info)
@@ -1898,13 +1831,6 @@ again:
xenbus_dev_fatal(dev, err, "%s", message);
destroy_blkring:
blkif_free(info, 0);
-
- mutex_lock(&blkfront_mutex);
- free_info(info);
- mutex_unlock(&blkfront_mutex);
-
- dev_set_drvdata(&dev->dev, NULL);
-
return err;
}
@@ -2144,38 +2070,26 @@ static int blkfront_resume(struct xenbus_device *dev)
static void blkfront_closing(struct blkfront_info *info)
{
struct xenbus_device *xbdev = info->xbdev;
- struct block_device *bdev = NULL;
-
- mutex_lock(&info->mutex);
+ struct blkfront_ring_info *rinfo;
+ unsigned int i;
- if (xbdev->state == XenbusStateClosing) {
- mutex_unlock(&info->mutex);
+ if (xbdev->state == XenbusStateClosing)
return;
- }
-
- if (info->gd)
- bdev = bdgrab(info->gd->part0);
- mutex_unlock(&info->mutex);
-
- if (!bdev) {
- xenbus_frontend_closed(xbdev);
- return;
- }
+ /* No more blkif_request(). */
+ blk_mq_stop_hw_queues(info->rq);
+ blk_set_queue_dying(info->rq);
+ set_capacity(info->gd, 0);
- mutex_lock(&bdev->bd_mutex);
+ for_each_rinfo(info, rinfo, i) {
+ /* No more gnttab callback work. */
+ gnttab_cancel_free_callback(&rinfo->callback);
- if (bdev->bd_openers) {
- xenbus_dev_error(xbdev, -EBUSY,
- "Device in use; refusing to close");
- xenbus_switch_state(xbdev, XenbusStateClosing);
- } else {
- xlvbd_release_gendisk(info);
- xenbus_frontend_closed(xbdev);
+ /* Flush gnttab callback work. Must be done with no locks held. */
+ flush_work(&rinfo->work);
}
- mutex_unlock(&bdev->bd_mutex);
- bdput(bdev);
+ xenbus_frontend_closed(xbdev);
}
static void blkfront_setup_discard(struct blkfront_info *info)
@@ -2490,8 +2404,7 @@ static void blkback_changed(struct xenbus_device *dev,
break;
fallthrough;
case XenbusStateClosing:
- if (info)
- blkfront_closing(info);
+ blkfront_closing(info);
break;
}
}
@@ -2499,56 +2412,21 @@ static void blkback_changed(struct xenbus_device *dev,
static int blkfront_remove(struct xenbus_device *xbdev)
{
struct blkfront_info *info = dev_get_drvdata(&xbdev->dev);
- struct block_device *bdev = NULL;
- struct gendisk *disk;
dev_dbg(&xbdev->dev, "%s removed", xbdev->nodename);
- if (!info)
- return 0;
-
- blkif_free(info, 0);
-
- mutex_lock(&info->mutex);
-
- disk = info->gd;
- if (disk)
- bdev = bdgrab(disk->part0);
-
- info->xbdev = NULL;
- mutex_unlock(&info->mutex);
-
- if (!bdev) {
- mutex_lock(&blkfront_mutex);
- free_info(info);
- mutex_unlock(&blkfront_mutex);
- return 0;
- }
-
- /*
- * The xbdev was removed before we reached the Closed
- * state. See if it's safe to remove the disk. If the bdev
- * isn't closed yet, we let release take care of it.
- */
-
- mutex_lock(&bdev->bd_mutex);
- info = disk->private_data;
-
- dev_warn(disk_to_dev(disk),
- "%s was hot-unplugged, %d stale handles\n",
- xbdev->nodename, bdev->bd_openers);
+ del_gendisk(info->gd);
- if (info && !bdev->bd_openers) {
- xlvbd_release_gendisk(info);
- disk->private_data = NULL;
- mutex_lock(&blkfront_mutex);
- free_info(info);
- mutex_unlock(&blkfront_mutex);
- }
+ mutex_lock(&blkfront_mutex);
+ list_del(&info->info_list);
+ mutex_unlock(&blkfront_mutex);
- mutex_unlock(&bdev->bd_mutex);
- bdput(bdev);
+ blkif_free(info, 0);
+ xlbd_release_minors(info->gd->first_minor, info->gd->minors);
+ blk_cleanup_disk(info->gd);
+ blk_mq_free_tag_set(&info->tag_set);
+ kfree(info);
return 0;
}
@@ -2559,77 +2437,9 @@ static int blkfront_is_ready(struct xenbus_device *dev)
return info->is_ready && info->xbdev;
}
-static int blkif_open(struct block_device *bdev, fmode_t mode)
-{
- struct gendisk *disk = bdev->bd_disk;
- struct blkfront_info *info;
- int err = 0;
-
- mutex_lock(&blkfront_mutex);
-
- info = disk->private_data;
- if (!info) {
- /* xbdev gone */
- err = -ERESTARTSYS;
- goto out;
- }
-
- mutex_lock(&info->mutex);
-
- if (!info->gd)
- /* xbdev is closed */
- err = -ERESTARTSYS;
-
- mutex_unlock(&info->mutex);
-
-out:
- mutex_unlock(&blkfront_mutex);
- return err;
-}
-
-static void blkif_release(struct gendisk *disk, fmode_t mode)
-{
- struct blkfront_info *info = disk->private_data;
- struct xenbus_device *xbdev;
-
- mutex_lock(&blkfront_mutex);
- if (disk->part0->bd_openers)
- goto out_mutex;
-
- /*
- * Check if we have been instructed to close. We will have
- * deferred this request, because the bdev was still open.
- */
-
- mutex_lock(&info->mutex);
- xbdev = info->xbdev;
-
- if (xbdev && xbdev->state == XenbusStateClosing) {
- /* pending switch to state closed */
- dev_info(disk_to_dev(disk), "releasing disk\n");
- xlvbd_release_gendisk(info);
- xenbus_frontend_closed(info->xbdev);
- }
-
- mutex_unlock(&info->mutex);
-
- if (!xbdev) {
- /* sudden device removal */
- dev_info(disk_to_dev(disk), "releasing disk\n");
- xlvbd_release_gendisk(info);
- disk->private_data = NULL;
- free_info(info);
- }
-
-out_mutex:
- mutex_unlock(&blkfront_mutex);
-}
-
static const struct block_device_operations xlvbd_block_fops =
{
.owner = THIS_MODULE,
- .open = blkif_open,
- .release = blkif_release,
.getgeo = blkif_getgeo,
.ioctl = blkif_ioctl,
.compat_ioctl = blkdev_compat_ptr_ioctl,
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index c1d20818e649..4eef218108c6 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -236,11 +236,8 @@ static int z2_open(struct block_device *bdev, fmode_t mode)
case Z2MINOR_Z2ONLY:
z2ram_map = kmalloc(max_z2_map, GFP_KERNEL);
- if (z2ram_map == NULL) {
- printk(KERN_ERR DEVICE_NAME
- ": cannot get mem for z2ram_map\n");
+ if (!z2ram_map)
goto err_out;
- }
get_z2ram();
@@ -253,11 +250,8 @@ static int z2_open(struct block_device *bdev, fmode_t mode)
case Z2MINOR_CHIPONLY:
z2ram_map = kmalloc(max_chip_map, GFP_KERNEL);
- if (z2ram_map == NULL) {
- printk(KERN_ERR DEVICE_NAME
- ": cannot get mem for z2ram_map\n");
+ if (!z2ram_map)
goto err_out;
- }
get_chipram();
@@ -323,27 +317,20 @@ static const struct blk_mq_ops z2_mq_ops = {
static int z2ram_register_disk(int minor)
{
- struct request_queue *q;
struct gendisk *disk;
- disk = alloc_disk(1);
- if (!disk)
- return -ENOMEM;
-
- q = blk_mq_init_queue(&tag_set);
- if (IS_ERR(q)) {
- put_disk(disk);
- return PTR_ERR(q);
- }
+ disk = blk_mq_alloc_disk(&tag_set, NULL);
+ if (IS_ERR(disk))
+ return PTR_ERR(disk);
disk->major = Z2RAM_MAJOR;
disk->first_minor = minor;
+ disk->minors = 1;
disk->fops = &z2_fops;
if (minor)
sprintf(disk->disk_name, "z2ram%d", minor);
else
sprintf(disk->disk_name, "z2ram");
- disk->queue = q;
z2ram_gendisk[minor] = disk;
add_disk(disk);
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index cf8deecc39ef..fcaf2750f68f 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1781,24 +1781,24 @@ static ssize_t reset_store(struct device *dev,
zram = dev_to_zram(dev);
bdev = zram->disk->part0;
- mutex_lock(&bdev->bd_mutex);
+ mutex_lock(&bdev->bd_disk->open_mutex);
/* Do not reset an active device or claimed device */
if (bdev->bd_openers || zram->claim) {
- mutex_unlock(&bdev->bd_mutex);
+ mutex_unlock(&bdev->bd_disk->open_mutex);
return -EBUSY;
}
/* From now on, anyone can't open /dev/zram[0-9] */
zram->claim = true;
- mutex_unlock(&bdev->bd_mutex);
+ mutex_unlock(&bdev->bd_disk->open_mutex);
/* Make sure all the pending I/O are finished */
fsync_bdev(bdev);
zram_reset_device(zram);
- mutex_lock(&bdev->bd_mutex);
+ mutex_lock(&bdev->bd_disk->open_mutex);
zram->claim = false;
- mutex_unlock(&bdev->bd_mutex);
+ mutex_unlock(&bdev->bd_disk->open_mutex);
return len;
}
@@ -1808,7 +1808,7 @@ static int zram_open(struct block_device *bdev, fmode_t mode)
int ret = 0;
struct zram *zram;
- WARN_ON(!mutex_is_locked(&bdev->bd_mutex));
+ WARN_ON(!mutex_is_locked(&bdev->bd_disk->open_mutex));
zram = bdev->bd_disk->private_data;
/* zram was claimed to reset so open request fails */
@@ -1890,7 +1890,6 @@ static const struct attribute_group *zram_disk_attr_groups[] = {
static int zram_add(void)
{
struct zram *zram;
- struct request_queue *queue;
int ret, device_id;
zram = kzalloc(sizeof(struct zram), GFP_KERNEL);
@@ -1906,27 +1905,20 @@ static int zram_add(void)
#ifdef CONFIG_ZRAM_WRITEBACK
spin_lock_init(&zram->wb_limit_lock);
#endif
- queue = blk_alloc_queue(NUMA_NO_NODE);
- if (!queue) {
- pr_err("Error allocating disk queue for device %d\n",
- device_id);
- ret = -ENOMEM;
- goto out_free_idr;
- }
/* gendisk structure */
- zram->disk = alloc_disk(1);
+ zram->disk = blk_alloc_disk(NUMA_NO_NODE);
if (!zram->disk) {
pr_err("Error allocating disk structure for device %d\n",
device_id);
ret = -ENOMEM;
- goto out_free_queue;
+ goto out_free_idr;
}
zram->disk->major = zram_major;
zram->disk->first_minor = device_id;
+ zram->disk->minors = 1;
zram->disk->fops = &zram_devops;
- zram->disk->queue = queue;
zram->disk->private_data = zram;
snprintf(zram->disk->disk_name, 16, "zram%d", device_id);
@@ -1969,8 +1961,6 @@ static int zram_add(void)
pr_info("Added device: %s\n", zram->disk->disk_name);
return device_id;
-out_free_queue:
- blk_cleanup_queue(queue);
out_free_idr:
idr_remove(&zram_index_idr, device_id);
out_free_dev:
@@ -1982,14 +1972,14 @@ static int zram_remove(struct zram *zram)
{
struct block_device *bdev = zram->disk->part0;
- mutex_lock(&bdev->bd_mutex);
+ mutex_lock(&bdev->bd_disk->open_mutex);
if (bdev->bd_openers || zram->claim) {
- mutex_unlock(&bdev->bd_mutex);
+ mutex_unlock(&bdev->bd_disk->open_mutex);
return -EBUSY;
}
zram->claim = true;
- mutex_unlock(&bdev->bd_mutex);
+ mutex_unlock(&bdev->bd_disk->open_mutex);
zram_debugfs_unregister(zram);
@@ -2000,8 +1990,7 @@ static int zram_remove(struct zram *zram)
pr_info("Removed device: %s\n", zram->disk->disk_name);
del_gendisk(zram->disk);
- blk_cleanup_queue(zram->disk->queue);
- put_disk(zram->disk);
+ blk_cleanup_disk(zram->disk);
kfree(zram);
return 0;
}
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index 419a7e8281ee..80c3b43b4828 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -112,9 +112,9 @@ struct zram {
/*
* zram is claimed so open request will be failed
*/
- bool claim; /* Protected by bdev->bd_mutex */
- struct file *backing_dev;
+ bool claim; /* Protected by disk->open_mutex */
#ifdef CONFIG_ZRAM_WRITEBACK
+ struct file *backing_dev;
spinlock_t wb_limit_lock;
bool wb_limit_enable;
u64 bd_wb_limit;
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c
index 1b9743b7f2ef..e5d706ed55ea 100644
--- a/drivers/bluetooth/btbcm.c
+++ b/drivers/bluetooth/btbcm.c
@@ -404,6 +404,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = {
{ 0x4217, "BCM4329B1" }, /* 002.002.023 */
{ 0x6106, "BCM4359C0" }, /* 003.001.006 */
{ 0x4106, "BCM4335A0" }, /* 002.001.006 */
+ { 0x410c, "BCM43430B0" }, /* 002.001.012 */
{ }
};
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 33d58b30c5ac..cddd350beba3 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -1461,9 +1461,7 @@ static void btmrvl_sdio_coredump(struct device *dev)
BT_ERR("Allocated buffer not enough");
}
- if (stat != RDWR_STATUS_DONE) {
- continue;
- } else {
+ if (stat == RDWR_STATUS_DONE) {
BT_INFO("%s done: size=0x%tx",
entry->mem_name,
dbg_ptr - entry->mem_ptr);
diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c
index 6c40bc75fb5b..e9d91d7c0db4 100644
--- a/drivers/bluetooth/btmtkuart.c
+++ b/drivers/bluetooth/btmtkuart.c
@@ -581,11 +581,9 @@ static int btmtkuart_open(struct hci_dev *hdev)
/* Enable the power domain and clock the device requires */
pm_runtime_enable(dev);
- err = pm_runtime_get_sync(dev);
- if (err < 0) {
- pm_runtime_put_noidle(dev);
+ err = pm_runtime_resume_and_get(dev);
+ if (err < 0)
goto err_disable_rpm;
- }
err = clk_prepare_enable(bdev->clk);
if (err < 0)
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 25114f0d1319..be04d74037d2 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -182,8 +182,9 @@ int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
}
EXPORT_SYMBOL_GPL(qca_send_pre_shutdown_cmd);
-static void qca_tlv_check_data(struct qca_fw_config *config,
- const struct firmware *fw, enum qca_btsoc_type soc_type)
+static void qca_tlv_check_data(struct hci_dev *hdev,
+ struct qca_fw_config *config,
+ u8 *fw_data, enum qca_btsoc_type soc_type)
{
const u8 *data;
u32 type_len;
@@ -194,19 +195,21 @@ static void qca_tlv_check_data(struct qca_fw_config *config,
struct tlv_type_nvm *tlv_nvm;
uint8_t nvm_baud_rate = config->user_baud_rate;
- tlv = (struct tlv_type_hdr *)fw->data;
-
- type_len = le32_to_cpu(tlv->type_len);
- length = (type_len >> 8) & 0x00ffffff;
-
- BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff);
- BT_DBG("Length\t\t : %d bytes", length);
-
config->dnld_mode = QCA_SKIP_EVT_NONE;
config->dnld_type = QCA_SKIP_EVT_NONE;
switch (config->type) {
+ case ELF_TYPE_PATCH:
+ config->dnld_mode = QCA_SKIP_EVT_VSE_CC;
+ config->dnld_type = QCA_SKIP_EVT_VSE_CC;
+
+ bt_dev_dbg(hdev, "File Class : 0x%x", fw_data[4]);
+ bt_dev_dbg(hdev, "Data Encoding : 0x%x", fw_data[5]);
+ bt_dev_dbg(hdev, "File version : 0x%x", fw_data[6]);
+ break;
case TLV_TYPE_PATCH:
+ tlv = (struct tlv_type_hdr *)fw_data;
+ type_len = le32_to_cpu(tlv->type_len);
tlv_patch = (struct tlv_type_patch *)tlv->data;
/* For Rome version 1.1 to 3.1, all segment commands
@@ -218,6 +221,7 @@ static void qca_tlv_check_data(struct qca_fw_config *config,
config->dnld_mode = tlv_patch->download_mode;
config->dnld_type = config->dnld_mode;
+ BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff);
BT_DBG("Total Length : %d bytes",
le32_to_cpu(tlv_patch->total_size));
BT_DBG("Patch Data Length : %d bytes",
@@ -243,6 +247,14 @@ static void qca_tlv_check_data(struct qca_fw_config *config,
break;
case TLV_TYPE_NVM:
+ tlv = (struct tlv_type_hdr *)fw_data;
+
+ type_len = le32_to_cpu(tlv->type_len);
+ length = (type_len >> 8) & 0x00ffffff;
+
+ BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff);
+ BT_DBG("Length\t\t : %d bytes", length);
+
idx = 0;
data = tlv->data;
while (idx < length) {
@@ -387,25 +399,57 @@ static int qca_inject_cmd_complete_event(struct hci_dev *hdev)
static int qca_download_firmware(struct hci_dev *hdev,
struct qca_fw_config *config,
- enum qca_btsoc_type soc_type)
+ enum qca_btsoc_type soc_type,
+ u8 rom_ver)
{
const struct firmware *fw;
+ u8 *data;
const u8 *segment;
- int ret, remain, i = 0;
+ int ret, size, remain, i = 0;
bt_dev_info(hdev, "QCA Downloading %s", config->fwname);
ret = request_firmware(&fw, config->fwname, &hdev->dev);
if (ret) {
- bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
- config->fwname, ret);
- return ret;
+ /* For WCN6750, if mbn file is not present then check for
+ * tlv file.
+ */
+ if (soc_type == QCA_WCN6750 && config->type == ELF_TYPE_PATCH) {
+ bt_dev_dbg(hdev, "QCA Failed to request file: %s (%d)",
+ config->fwname, ret);
+ config->type = TLV_TYPE_PATCH;
+ snprintf(config->fwname, sizeof(config->fwname),
+ "qca/msbtfw%02x.tlv", rom_ver);
+ bt_dev_info(hdev, "QCA Downloading %s", config->fwname);
+ ret = request_firmware(&fw, config->fwname, &hdev->dev);
+ if (ret) {
+ bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
+ config->fwname, ret);
+ return ret;
+ }
+ } else {
+ bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
+ config->fwname, ret);
+ return ret;
+ }
}
- qca_tlv_check_data(config, fw, soc_type);
+ size = fw->size;
+ data = vmalloc(fw->size);
+ if (!data) {
+ bt_dev_err(hdev, "QCA Failed to allocate memory for file: %s",
+ config->fwname);
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ memcpy(data, fw->data, size);
+ release_firmware(fw);
+
+ qca_tlv_check_data(hdev, config, data, soc_type);
- segment = fw->data;
- remain = fw->size;
+ segment = data;
+ remain = size;
while (remain > 0) {
int segsize = min(MAX_SIZE_PER_TLV_SEGMENT, remain);
@@ -435,7 +479,7 @@ static int qca_download_firmware(struct hci_dev *hdev,
ret = qca_inject_cmd_complete_event(hdev);
out:
- release_firmware(fw);
+ vfree(data);
return ret;
}
@@ -502,27 +546,32 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
config.user_baud_rate = baudrate;
+ /* Firmware files to download are based on ROM version.
+ * ROM version is derived from last two bytes of soc_ver.
+ */
+ rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);
+
/* Download rampatch file */
config.type = TLV_TYPE_PATCH;
if (qca_is_wcn399x(soc_type)) {
- /* Firmware files to download are based on ROM version.
- * ROM version is derived from last two bytes of soc_ver.
- */
- rom_ver = ((soc_ver & 0x00000f00) >> 0x04) |
- (soc_ver & 0x0000000f);
snprintf(config.fwname, sizeof(config.fwname),
"qca/crbtfw%02x.tlv", rom_ver);
} else if (soc_type == QCA_QCA6390) {
- rom_ver = ((soc_ver & 0x00000f00) >> 0x04) |
- (soc_ver & 0x0000000f);
snprintf(config.fwname, sizeof(config.fwname),
"qca/htbtfw%02x.tlv", rom_ver);
+ } else if (soc_type == QCA_WCN6750) {
+ /* Choose mbn file by default.If mbn file is not found
+ * then choose tlv file
+ */
+ config.type = ELF_TYPE_PATCH;
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/msbtfw%02x.mbn", rom_ver);
} else {
snprintf(config.fwname, sizeof(config.fwname),
"qca/rampatch_%08x.bin", soc_ver);
}
- err = qca_download_firmware(hdev, &config, soc_type);
+ err = qca_download_firmware(hdev, &config, soc_type, rom_ver);
if (err < 0) {
bt_dev_err(hdev, "QCA Failed to download patch (%d)", err);
return err;
@@ -548,11 +597,14 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
else if (soc_type == QCA_QCA6390)
snprintf(config.fwname, sizeof(config.fwname),
"qca/htnv%02x.bin", rom_ver);
+ else if (soc_type == QCA_WCN6750)
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/msnv%02x.bin", rom_ver);
else
snprintf(config.fwname, sizeof(config.fwname),
"qca/nvm_%08x.bin", soc_ver);
- err = qca_download_firmware(hdev, &config, soc_type);
+ err = qca_download_firmware(hdev, &config, soc_type, rom_ver);
if (err < 0) {
bt_dev_err(hdev, "QCA Failed to download NVM (%d)", err);
return err;
@@ -564,13 +616,14 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
return err;
}
- /* WCN399x supports the Microsoft vendor extension with 0xFD70 as the
+ /* WCN399x and WCN6750 supports the Microsoft vendor extension with 0xFD70 as the
* VsMsftOpCode.
*/
switch (soc_type) {
case QCA_WCN3990:
case QCA_WCN3991:
case QCA_WCN3998:
+ case QCA_WCN6750:
hci_set_msft_opcode(hdev, 0xFD70);
break;
default:
@@ -584,7 +637,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
return err;
}
- if (soc_type == QCA_WCN3991) {
+ if (soc_type == QCA_WCN3991 || soc_type == QCA_WCN6750) {
/* get fw build info */
err = qca_read_fw_build_info(hdev);
if (err < 0)
diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
index b19add7675a4..30afa7703afd 100644
--- a/drivers/bluetooth/btqca.h
+++ b/drivers/bluetooth/btqca.h
@@ -80,7 +80,8 @@ enum qca_tlv_dnld_mode {
enum qca_tlv_type {
TLV_TYPE_PATCH = 1,
- TLV_TYPE_NVM
+ TLV_TYPE_NVM,
+ ELF_TYPE_PATCH,
};
struct qca_fw_config {
@@ -143,6 +144,7 @@ enum qca_btsoc_type {
QCA_WCN3998,
QCA_WCN3991,
QCA_QCA6390,
+ QCA_WCN6750,
};
#if IS_ENABLED(CONFIG_BT_QCA)
@@ -160,6 +162,11 @@ static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type)
return soc_type == QCA_WCN3990 || soc_type == QCA_WCN3991 ||
soc_type == QCA_WCN3998;
}
+static inline bool qca_is_wcn6750(enum qca_btsoc_type soc_type)
+{
+ return soc_type == QCA_WCN6750;
+}
+
#else
static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
@@ -192,6 +199,11 @@ static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type)
return false;
}
+static inline bool qca_is_wcn6750(enum qca_btsoc_type soc_type)
+{
+ return false;
+}
+
static inline int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
index e7fe5fb22753..cce0125ec4fd 100644
--- a/drivers/bluetooth/btrtl.c
+++ b/drivers/bluetooth/btrtl.c
@@ -132,12 +132,19 @@ static const struct id_table ic_id_table[] = {
.cfg_name = "rtl_bt/rtl8761a_config" },
/* 8761B */
- { IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_USB),
+ { IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_UART),
.config_needed = false,
.has_rom_version = true,
.fw_name = "rtl_bt/rtl8761b_fw.bin",
.cfg_name = "rtl_bt/rtl8761b_config" },
+ /* 8761BU */
+ { IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_USB),
+ .config_needed = false,
+ .has_rom_version = true,
+ .fw_name = "rtl_bt/rtl8761bu_fw.bin",
+ .cfg_name = "rtl_bt/rtl8761bu_config" },
+
/* 8822C with UART interface */
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_UART),
.config_needed = true,
@@ -719,17 +726,8 @@ int btrtl_download_firmware(struct hci_dev *hdev,
}
EXPORT_SYMBOL_GPL(btrtl_download_firmware);
-int btrtl_setup_realtek(struct hci_dev *hdev)
+void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
{
- struct btrtl_device_info *btrtl_dev;
- int ret;
-
- btrtl_dev = btrtl_initialize(hdev, NULL);
- if (IS_ERR(btrtl_dev))
- return PTR_ERR(btrtl_dev);
-
- ret = btrtl_download_firmware(hdev, btrtl_dev);
-
/* Enable controller to do both LE scan and BR/EDR inquiry
* simultaneously.
*/
@@ -750,6 +748,21 @@ int btrtl_setup_realtek(struct hci_dev *hdev)
rtl_dev_dbg(hdev, "WBS supported not enabled.");
break;
}
+}
+EXPORT_SYMBOL_GPL(btrtl_set_quirks);
+
+int btrtl_setup_realtek(struct hci_dev *hdev)
+{
+ struct btrtl_device_info *btrtl_dev;
+ int ret;
+
+ btrtl_dev = btrtl_initialize(hdev, NULL);
+ if (IS_ERR(btrtl_dev))
+ return PTR_ERR(btrtl_dev);
+
+ ret = btrtl_download_firmware(hdev, btrtl_dev);
+
+ btrtl_set_quirks(hdev, btrtl_dev);
btrtl_free(btrtl_dev);
return ret;
diff --git a/drivers/bluetooth/btrtl.h b/drivers/bluetooth/btrtl.h
index 2a582682136d..2c441bda390a 100644
--- a/drivers/bluetooth/btrtl.h
+++ b/drivers/bluetooth/btrtl.h
@@ -54,6 +54,8 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
void btrtl_free(struct btrtl_device_info *btrtl_dev);
int btrtl_download_firmware(struct hci_dev *hdev,
struct btrtl_device_info *btrtl_dev);
+void btrtl_set_quirks(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,
@@ -79,6 +81,11 @@ static inline int btrtl_download_firmware(struct hci_dev *hdev,
return -EOPNOTSUPP;
}
+static inline void btrtl_set_quirks(struct hci_dev *hdev,
+ struct btrtl_device_info *btrtl_dev)
+{
+}
+
static inline int btrtl_setup_realtek(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 7f6ba2c975ed..a9855a2dd561 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -270,6 +270,8 @@ static const struct usb_device_id blacklist_table[] = {
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x0cf3, 0xe500), .driver_info = BTUSB_QCA_ROME |
+ BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe092), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe09f), .driver_info = BTUSB_QCA_ROME |
@@ -408,6 +410,11 @@ static const struct usb_device_id blacklist_table[] = {
/* Additional MediaTek MT7615E Bluetooth devices */
{ USB_DEVICE(0x13d3, 0x3560), .driver_info = BTUSB_MEDIATEK},
+ /* Additional MediaTek MT7921 Bluetooth devices */
+ { USB_DEVICE(0x04ca, 0x3802), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH |
+ BTUSB_VALID_LE_STATES },
+
/* Additional Realtek 8723AE Bluetooth devices */
{ USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
{ USB_DEVICE(0x13d3, 0x3394), .driver_info = BTUSB_REALTEK },
@@ -427,6 +434,10 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0bda, 0xb009), .driver_info = BTUSB_REALTEK },
{ USB_DEVICE(0x2ff8, 0xb011), .driver_info = BTUSB_REALTEK },
+ /* Additional Realtek 8761BU Bluetooth devices */
+ { USB_DEVICE(0x0b05, 0x190e), .driver_info = BTUSB_REALTEK |
+ BTUSB_WIDEBAND_SPEECH },
+
/* Additional Realtek 8821AE Bluetooth devices */
{ USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK },
{ USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK },
@@ -1749,6 +1760,13 @@ static void btusb_work(struct work_struct *work)
* which work with WBS at all.
*/
new_alts = btusb_find_altsetting(data, 6) ? 6 : 1;
+ /* Because mSBC frames do not need to be aligned to the
+ * SCO packet boundary. If support the Alt 3, use the
+ * Alt 3 for HCI payload >= 60 Bytes let air packet
+ * data satisfy 60 bytes.
+ */
+ if (new_alts == 1 && btusb_find_altsetting(data, 3))
+ new_alts = 3;
}
if (btusb_switch_alt_setting(hdev, new_alts) < 0)
@@ -3312,11 +3330,6 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev,
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)
@@ -3342,6 +3355,11 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev,
goto err_free_wc;
}
+ /* Submit control IN URB on demand to process the WMT event */
+ err = btusb_mtk_submit_wmt_recv_urb(hdev);
+ if (err < 0)
+ goto err_free_wc;
+
/* 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.
@@ -4062,6 +4080,11 @@ static int btusb_setup_qca_download_fw(struct hci_dev *hdev,
sent += size;
count -= size;
+ /* ep2 need time to switch from function acl to function dfu,
+ * so we add 20ms delay here.
+ */
+ msleep(20);
+
while (count) {
size = min_t(size_t, count, QCA_DFU_PACKET_LEN);
@@ -4154,9 +4177,15 @@ static int btusb_setup_qca_load_nvm(struct hci_dev *hdev,
int err;
if (((ver->flag >> 8) & 0xff) == QCA_FLAG_MULTI_NVM) {
- snprintf(fwname, sizeof(fwname), "qca/nvm_usb_%08x_%04x.bin",
- le32_to_cpu(ver->rom_version),
- le16_to_cpu(ver->board_id));
+ /* if boardid equal 0, use default nvm without surfix */
+ if (le16_to_cpu(ver->board_id) == 0x0) {
+ snprintf(fwname, sizeof(fwname), "qca/nvm_usb_%08x.bin",
+ le32_to_cpu(ver->rom_version));
+ } else {
+ snprintf(fwname, sizeof(fwname), "qca/nvm_usb_%08x_%04x.bin",
+ le32_to_cpu(ver->rom_version),
+ le16_to_cpu(ver->board_id));
+ }
} else {
snprintf(fwname, sizeof(fwname), "qca/nvm_usb_%08x.bin",
le32_to_cpu(ver->rom_version));
diff --git a/drivers/bluetooth/hci_ag6xx.c b/drivers/bluetooth/hci_ag6xx.c
index 1f55df93e4ce..2d40302409ff 100644
--- a/drivers/bluetooth/hci_ag6xx.c
+++ b/drivers/bluetooth/hci_ag6xx.c
@@ -199,7 +199,6 @@ static int ag6xx_setup(struct hci_uart *hu)
fwname, err);
goto patch;
}
- fw_ptr = fw->data;
bt_dev_info(hdev, "Applying bddata (%s)", fwname);
diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c
index 27e96681d583..e0520639f4ba 100644
--- a/drivers/bluetooth/hci_h5.c
+++ b/drivers/bluetooth/hci_h5.c
@@ -906,10 +906,7 @@ static int h5_btrtl_setup(struct h5 *h5)
/* Give the device some time before the hci-core sends it a reset */
usleep_range(10000, 20000);
- /* Enable controller to do both LE scan and BR/EDR inquiry
- * simultaneously.
- */
- set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &h5->hu->hdev->quirks);
+ btrtl_set_quirks(h5->hu->hdev, btrtl_dev);
out_free:
btrtl_free(btrtl_dev);
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 71a4ca505e09..5ed2cfa7da1d 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -593,7 +593,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
* Return Value: None
*/
static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
- char *flags, int count)
+ const char *flags, int count)
{
struct hci_uart *hu = tty->disc_data;
@@ -821,6 +821,7 @@ static __poll_t hci_uart_tty_poll(struct tty_struct *tty,
static struct tty_ldisc_ops hci_uart_ldisc = {
.owner = THIS_MODULE,
+ .num = N_HCI,
.name = "n_hci",
.open = hci_uart_tty_open,
.close = hci_uart_tty_close,
@@ -840,7 +841,7 @@ static int __init hci_uart_init(void)
BT_INFO("HCI UART driver ver %s", VERSION);
/* Register the tty discipline */
- err = tty_register_ldisc(N_HCI, &hci_uart_ldisc);
+ err = tty_register_ldisc(&hci_uart_ldisc);
if (err) {
BT_ERR("HCI line discipline registration failed. (%d)", err);
return err;
@@ -882,8 +883,6 @@ static int __init hci_uart_init(void)
static void __exit hci_uart_exit(void)
{
- int err;
-
#ifdef CONFIG_BT_HCIUART_H4
h4_deinit();
#endif
@@ -915,10 +914,7 @@ static void __exit hci_uart_exit(void)
mrvl_deinit();
#endif
- /* Release tty registration of line discipline */
- err = tty_unregister_ldisc(N_HCI);
- if (err)
- BT_ERR("Can't unregister HCI line discipline (%d)", err);
+ tty_unregister_ldisc(&hci_uart_ldisc);
}
module_init(hci_uart_init);
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 0a0056912d51..53deea2eb7b4 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -218,6 +218,7 @@ struct qca_power {
struct qca_serdev {
struct hci_uart serdev_hu;
struct gpio_desc *bt_en;
+ struct gpio_desc *sw_ctrl;
struct clk *susclk;
enum qca_btsoc_type btsoc_type;
struct qca_power *bt_power;
@@ -604,7 +605,8 @@ static int qca_open(struct hci_uart *hu)
if (hu->serdev) {
qcadev = serdev_device_get_drvdata(hu->serdev);
- if (qca_is_wcn399x(qcadev->btsoc_type))
+ if (qca_is_wcn399x(qcadev->btsoc_type) ||
+ qca_is_wcn6750(qcadev->btsoc_type))
hu->init_speed = qcadev->init_speed;
if (qcadev->oper_speed)
@@ -1308,7 +1310,8 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
/* Give the controller time to process the request */
- if (qca_is_wcn399x(qca_soc_type(hu)))
+ if (qca_is_wcn399x(qca_soc_type(hu)) ||
+ qca_is_wcn6750(qca_soc_type(hu)))
usleep_range(1000, 10000);
else
msleep(300);
@@ -1384,7 +1387,8 @@ static unsigned int qca_get_speed(struct hci_uart *hu,
static int qca_check_speeds(struct hci_uart *hu)
{
- if (qca_is_wcn399x(qca_soc_type(hu))) {
+ if (qca_is_wcn399x(qca_soc_type(hu)) ||
+ qca_is_wcn6750(qca_soc_type(hu))) {
if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
!qca_get_speed(hu, QCA_OPER_SPEED))
return -EINVAL;
@@ -1417,7 +1421,8 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
/* Disable flow control for wcn3990 to deassert RTS while
* changing the baudrate of chip and host.
*/
- if (qca_is_wcn399x(soc_type))
+ if (qca_is_wcn399x(soc_type) ||
+ qca_is_wcn6750(soc_type))
hci_uart_set_flow_control(hu, true);
if (soc_type == QCA_WCN3990) {
@@ -1434,7 +1439,8 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
host_set_baudrate(hu, speed);
error:
- if (qca_is_wcn399x(soc_type))
+ if (qca_is_wcn399x(soc_type) ||
+ qca_is_wcn6750(soc_type))
hci_uart_set_flow_control(hu, false);
if (soc_type == QCA_WCN3990) {
@@ -1585,10 +1591,12 @@ static bool qca_prevent_wake(struct hci_dev *hdev)
return !wakeup;
}
-static int qca_wcn3990_init(struct hci_uart *hu)
+static int qca_regulator_init(struct hci_uart *hu)
{
+ enum qca_btsoc_type soc_type = qca_soc_type(hu);
struct qca_serdev *qcadev;
int ret;
+ bool sw_ctrl_state;
/* Check for vregs status, may be hci down has turned
* off the voltage regulator.
@@ -1607,16 +1615,33 @@ static int qca_wcn3990_init(struct hci_uart *hu)
}
}
- /* Forcefully enable wcn3990 to enter in to boot mode. */
- host_set_baudrate(hu, 2400);
- ret = qca_send_power_pulse(hu, false);
- if (ret)
- return ret;
+ if (qca_is_wcn399x(soc_type)) {
+ /* Forcefully enable wcn399x to enter in to boot mode. */
+ host_set_baudrate(hu, 2400);
+ ret = qca_send_power_pulse(hu, false);
+ if (ret)
+ return ret;
+ }
+
+ /* For wcn6750 need to enable gpio bt_en */
+ if (qcadev->bt_en) {
+ gpiod_set_value_cansleep(qcadev->bt_en, 0);
+ msleep(50);
+ gpiod_set_value_cansleep(qcadev->bt_en, 1);
+ msleep(50);
+ if (qcadev->sw_ctrl) {
+ sw_ctrl_state = gpiod_get_value_cansleep(qcadev->sw_ctrl);
+ bt_dev_dbg(hu->hdev, "SW_CTRL is %d", sw_ctrl_state);
+ }
+ }
qca_set_speed(hu, QCA_INIT_SPEED);
- ret = qca_send_power_pulse(hu, true);
- if (ret)
- return ret;
+
+ if (qca_is_wcn399x(soc_type)) {
+ ret = qca_send_power_pulse(hu, true);
+ if (ret)
+ return ret;
+ }
/* Now the device is in ready state to communicate with host.
* To sync host with device we need to reopen port.
@@ -1649,8 +1674,9 @@ static int qca_power_on(struct hci_dev *hdev)
if (!hu->serdev)
return 0;
- if (qca_is_wcn399x(soc_type)) {
- ret = qca_wcn3990_init(hu);
+ if (qca_is_wcn399x(soc_type) ||
+ qca_is_wcn6750(soc_type)) {
+ ret = qca_regulator_init(hu);
} else {
qcadev = serdev_device_get_drvdata(hu->serdev);
if (qcadev->bt_en) {
@@ -1689,7 +1715,8 @@ static int qca_setup(struct hci_uart *hu)
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
bt_dev_info(hdev, "setting up %s",
- qca_is_wcn399x(soc_type) ? "wcn399x" : "ROME/QCA6390");
+ qca_is_wcn399x(soc_type) ? "wcn399x" :
+ (soc_type == QCA_WCN6750) ? "wcn6750" : "ROME/QCA6390");
qca->memdump_state = QCA_MEMDUMP_IDLE;
@@ -1700,7 +1727,8 @@ retry:
clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
- if (qca_is_wcn399x(soc_type)) {
+ if (qca_is_wcn399x(soc_type) ||
+ qca_is_wcn6750(soc_type)) {
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
ret = qca_read_soc_version(hdev, &ver, soc_type);
@@ -1720,7 +1748,8 @@ retry:
qca_baudrate = qca_get_baudrate_value(speed);
}
- if (!qca_is_wcn399x(soc_type)) {
+ if (!(qca_is_wcn399x(soc_type) ||
+ qca_is_wcn6750(soc_type))) {
/* Get QCA version information */
ret = qca_read_soc_version(hdev, &ver, soc_type);
if (ret)
@@ -1828,14 +1857,30 @@ static const struct qca_device_data qca_soc_data_qca6390 = {
.num_vregs = 0,
};
+static const struct qca_device_data qca_soc_data_wcn6750 = {
+ .soc_type = QCA_WCN6750,
+ .vregs = (struct qca_vreg []) {
+ { "vddio", 5000 },
+ { "vddaon", 26000 },
+ { "vddbtcxmx", 126000 },
+ { "vddrfacmn", 12500 },
+ { "vddrfa0p8", 102000 },
+ { "vddrfa1p7", 302000 },
+ { "vddrfa1p2", 257000 },
+ { "vddrfa2p2", 1700000 },
+ { "vddasd", 200 },
+ },
+ .num_vregs = 9,
+ .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
+};
+
static void qca_power_shutdown(struct hci_uart *hu)
{
struct qca_serdev *qcadev;
struct qca_data *qca = hu->priv;
unsigned long flags;
enum qca_btsoc_type soc_type = qca_soc_type(hu);
-
- qcadev = serdev_device_get_drvdata(hu->serdev);
+ bool sw_ctrl_state;
/* From this point we go into power off state. But serial port is
* still open, stop queueing the IBS data and flush all the buffered
@@ -1852,10 +1897,20 @@ static void qca_power_shutdown(struct hci_uart *hu)
if (!hu->serdev)
return;
+ qcadev = serdev_device_get_drvdata(hu->serdev);
+
if (qca_is_wcn399x(soc_type)) {
host_set_baudrate(hu, 2400);
qca_send_power_pulse(hu, false);
qca_regulator_disable(qcadev);
+ } else if (soc_type == QCA_WCN6750) {
+ gpiod_set_value_cansleep(qcadev->bt_en, 0);
+ msleep(100);
+ qca_regulator_disable(qcadev);
+ if (qcadev->sw_ctrl) {
+ sw_ctrl_state = gpiod_get_value_cansleep(qcadev->sw_ctrl);
+ bt_dev_dbg(hu->hdev, "SW_CTRL is %d", sw_ctrl_state);
+ }
} else if (qcadev->bt_en) {
gpiod_set_value_cansleep(qcadev->bt_en, 0);
}
@@ -1978,7 +2033,9 @@ static int qca_serdev_probe(struct serdev_device *serdev)
if (!qcadev->oper_speed)
BT_DBG("UART will pick default operating speed");
- if (data && qca_is_wcn399x(data->soc_type)) {
+ if (data &&
+ (qca_is_wcn399x(data->soc_type) ||
+ qca_is_wcn6750(data->soc_type))) {
qcadev->btsoc_type = data->soc_type;
qcadev->bt_power = devm_kzalloc(&serdev->dev,
sizeof(struct qca_power),
@@ -1996,6 +2053,18 @@ static int qca_serdev_probe(struct serdev_device *serdev)
qcadev->bt_power->vregs_on = false;
+ qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
+ GPIOD_OUT_LOW);
+ if (!qcadev->bt_en && data->soc_type == QCA_WCN6750) {
+ dev_err(&serdev->dev, "failed to acquire BT_EN gpio\n");
+ power_ctrl_enabled = false;
+ }
+
+ qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl",
+ GPIOD_IN);
+ if (!qcadev->sw_ctrl && data->soc_type == QCA_WCN6750)
+ dev_warn(&serdev->dev, "failed to acquire SW_CTRL gpio\n");
+
qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
if (IS_ERR(qcadev->susclk)) {
dev_err(&serdev->dev, "failed to acquire clk\n");
@@ -2068,7 +2137,9 @@ static void qca_serdev_remove(struct serdev_device *serdev)
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
struct qca_power *power = qcadev->bt_power;
- if (qca_is_wcn399x(qcadev->btsoc_type) && power->vregs_on)
+ if ((qca_is_wcn399x(qcadev->btsoc_type) ||
+ qca_is_wcn6750(qcadev->btsoc_type)) &&
+ power->vregs_on)
qca_power_shutdown(&qcadev->serdev_hu);
else if (qcadev->susclk)
clk_disable_unprepare(qcadev->susclk);
@@ -2244,6 +2315,7 @@ static const struct of_device_id qca_bluetooth_of_match[] = {
{ .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data_wcn3990},
{ .compatible = "qcom,wcn3991-bt", .data = &qca_soc_data_wcn3991},
{ .compatible = "qcom,wcn3998-bt", .data = &qca_soc_data_wcn3998},
+ { .compatible = "qcom,wcn6750-bt", .data = &qca_soc_data_wcn6750},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
diff --git a/drivers/bluetooth/virtio_bt.c b/drivers/bluetooth/virtio_bt.c
index c804db7e90f8..57908ce4fae8 100644
--- a/drivers/bluetooth/virtio_bt.c
+++ b/drivers/bluetooth/virtio_bt.c
@@ -34,6 +34,9 @@ static int virtbt_add_inbuf(struct virtio_bluetooth *vbt)
int err;
skb = alloc_skb(1000, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
sg_init_one(sg, skb->data, 1000);
err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_KERNEL);
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index 7355fa2cb439..6551286a60cc 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -6,6 +6,7 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/module.h>
+#include <linux/panic_notifier.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/sysfs.h>
diff --git a/drivers/bus/fsl-mc/dprc-driver.c b/drivers/bus/fsl-mc/dprc-driver.c
index e3e2ae41c22b..315e830b6ecd 100644
--- a/drivers/bus/fsl-mc/dprc-driver.c
+++ b/drivers/bus/fsl-mc/dprc-driver.c
@@ -350,7 +350,8 @@ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
* dprc_scan_container - Scans a physical DPRC and synchronizes Linux bus state
*
* @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
- *
+ * @alloc_interrupts: if true the function allocates the interrupt pool,
+ * otherwise the interrupt allocation is delayed
* Scans the physical DPRC and synchronizes the state of the Linux
* bus driver with the actual state of the MC by adding and removing
* devices as appropriate.
@@ -373,10 +374,11 @@ int dprc_scan_container(struct fsl_mc_device *mc_bus_dev,
return error;
}
EXPORT_SYMBOL_GPL(dprc_scan_container);
+
/**
* dprc_irq0_handler - Regular ISR for DPRC interrupt 0
*
- * @irq: IRQ number of the interrupt being handled
+ * @irq_num: IRQ number of the interrupt being handled
* @arg: Pointer to device structure
*/
static irqreturn_t dprc_irq0_handler(int irq_num, void *arg)
@@ -387,7 +389,7 @@ static irqreturn_t dprc_irq0_handler(int irq_num, void *arg)
/**
* dprc_irq0_handler_thread - Handler thread function for DPRC interrupt 0
*
- * @irq: IRQ number of the interrupt being handled
+ * @irq_num: IRQ number of the interrupt being handled
* @arg: Pointer to device structure
*/
static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg)
diff --git a/drivers/bus/fsl-mc/dprc.c b/drivers/bus/fsl-mc/dprc.c
index 27b0a01bad9b..d129338b8bc0 100644
--- a/drivers/bus/fsl-mc/dprc.c
+++ b/drivers/bus/fsl-mc/dprc.c
@@ -334,7 +334,7 @@ int dprc_clear_irq_status(struct fsl_mc_io *mc_io,
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
* @token: Token of DPRC object
- * @attributes Returned container attributes
+ * @attr: Returned container attributes
*
* Return: '0' on Success; Error code otherwise.
*/
@@ -504,7 +504,7 @@ EXPORT_SYMBOL_GPL(dprc_set_obj_irq);
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
* @token: Token of DPRC object
- * @obj_type; Object type as returned in dprc_get_obj()
+ * @obj_type: Object type as returned in dprc_get_obj()
* @obj_id: Unique object instance as returned in dprc_get_obj()
* @region_index: The specific region to query
* @region_desc: Returns the requested region descriptor
diff --git a/drivers/bus/fsl-mc/fsl-mc-allocator.c b/drivers/bus/fsl-mc/fsl-mc-allocator.c
index 2d7c764bb7dc..6c513556911e 100644
--- a/drivers/bus/fsl-mc/fsl-mc-allocator.c
+++ b/drivers/bus/fsl-mc/fsl-mc-allocator.c
@@ -254,7 +254,7 @@ EXPORT_SYMBOL_GPL(fsl_mc_resource_free);
* @mc_dev: fsl-mc device which is used in conjunction with the
* allocated object
* @pool_type: pool type
- * @new_mc_dev: pointer to area where the pointer to the allocated device
+ * @new_mc_adev: pointer to area where the pointer to the allocated device
* is to be returned
*
* Allocatable objects are always used in conjunction with some functional
@@ -409,7 +409,7 @@ cleanup_msi_irqs:
}
EXPORT_SYMBOL_GPL(fsl_mc_populate_irq_pool);
-/**
+/*
* Teardown the interrupt pool associated with an fsl-mc bus.
* It frees the IRQs that were allocated to the pool, back to the GIC-ITS.
*/
@@ -436,7 +436,7 @@ void fsl_mc_cleanup_irq_pool(struct fsl_mc_device *mc_bus_dev)
}
EXPORT_SYMBOL_GPL(fsl_mc_cleanup_irq_pool);
-/**
+/*
* Allocate the IRQs required by a given fsl-mc device.
*/
int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev)
@@ -578,7 +578,7 @@ void fsl_mc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev)
fsl_mc_cleanup_resource_pool(mc_bus_dev, pool_type);
}
-/**
+/*
* fsl_mc_allocator_probe - callback invoked when an allocatable device is
* being added to the system
*/
@@ -610,7 +610,7 @@ static int fsl_mc_allocator_probe(struct fsl_mc_device *mc_dev)
return 0;
}
-/**
+/*
* fsl_mc_allocator_remove - callback invoked when an allocatable device is
* being removed from the system
*/
diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index 380ad1fdb745..09c8ab5e0959 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -24,7 +24,7 @@
#include "fsl-mc-private.h"
-/**
+/*
* Default DMA mask for devices on a fsl-mc bus
*/
#define FSL_MC_DEFAULT_DMA_MASK (~0ULL)
@@ -36,6 +36,7 @@ static struct fsl_mc_version mc_version;
* @root_mc_bus_dev: fsl-mc device representing the root DPRC
* @num_translation_ranges: number of entries in addr_translation_ranges
* @translation_ranges: array of bus to system address translation ranges
+ * @fsl_mc_regs: base address of register bank
*/
struct fsl_mc {
struct fsl_mc_device *root_mc_bus_dev;
@@ -117,7 +118,7 @@ out:
return found;
}
-/**
+/*
* fsl_mc_bus_uevent - callback invoked when a device is added
*/
static int fsl_mc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
@@ -467,7 +468,7 @@ static void fsl_mc_driver_shutdown(struct device *dev)
mc_drv->shutdown(mc_dev);
}
-/**
+/*
* __fsl_mc_driver_register - registers a child device driver with the
* MC bus
*
@@ -503,7 +504,7 @@ int __fsl_mc_driver_register(struct fsl_mc_driver *mc_driver,
}
EXPORT_SYMBOL_GPL(__fsl_mc_driver_register);
-/**
+/*
* fsl_mc_driver_unregister - unregisters a device driver from the
* MC bus
*/
@@ -563,7 +564,7 @@ struct fsl_mc_version *fsl_mc_get_version(void)
}
EXPORT_SYMBOL_GPL(fsl_mc_get_version);
-/**
+/*
* fsl_mc_get_root_dprc - function to traverse to the root dprc
*/
void fsl_mc_get_root_dprc(struct device *dev,
@@ -732,7 +733,7 @@ error_cleanup_regions:
return error;
}
-/**
+/*
* fsl_mc_is_root_dprc - function to check if a given device is a root dprc
*/
bool fsl_mc_is_root_dprc(struct device *dev)
@@ -757,7 +758,7 @@ static void fsl_mc_device_release(struct device *dev)
kfree(mc_dev);
}
-/**
+/*
* Add a newly discovered fsl-mc device to be visible in Linux
*/
int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc,
@@ -1058,7 +1059,7 @@ static int get_mc_addr_translation_ranges(struct device *dev,
return 0;
}
-/**
+/*
* fsl_mc_bus_probe - callback invoked when the root MC bus is being
* added
*/
@@ -1182,7 +1183,7 @@ error_cleanup_mc_io:
return error;
}
-/**
+/*
* fsl_mc_bus_remove - callback invoked when the root MC bus is being
* removed
*/
diff --git a/drivers/bus/fsl-mc/fsl-mc-msi.c b/drivers/bus/fsl-mc/fsl-mc-msi.c
index 8edadf05cbb7..cf974870ba55 100644
--- a/drivers/bus/fsl-mc/fsl-mc-msi.c
+++ b/drivers/bus/fsl-mc/fsl-mc-msi.c
@@ -148,7 +148,7 @@ static void fsl_mc_msi_update_chip_ops(struct msi_domain_info *info)
/**
* fsl_mc_msi_create_irq_domain - Create a fsl-mc MSI interrupt domain
- * @np: Optional device-tree node of the interrupt controller
+ * @fwnode: Optional firmware node of the interrupt controller
* @info: MSI domain info
* @parent: Parent irq domain
*
diff --git a/drivers/bus/fsl-mc/mc-io.c b/drivers/bus/fsl-mc/mc-io.c
index 305015486b91..95b10a6cf307 100644
--- a/drivers/bus/fsl-mc/mc-io.c
+++ b/drivers/bus/fsl-mc/mc-io.c
@@ -50,12 +50,12 @@ static void fsl_mc_io_unset_dpmcp(struct fsl_mc_io *mc_io)
}
/**
- * Creates an MC I/O object
+ * fsl_create_mc_io() - Creates an MC I/O object
*
* @dev: device to be associated with the MC I/O object
* @mc_portal_phys_addr: physical address of the MC portal to use
* @mc_portal_size: size in bytes of the MC portal
- * @dpmcp-dev: Pointer to the DPMCP object associated with this MC I/O
+ * @dpmcp_dev: Pointer to the DPMCP object associated with this MC I/O
* object or NULL if none.
* @flags: flags for the new MC I/O object
* @new_mc_io: Area to return pointer to newly created MC I/O object
@@ -123,7 +123,7 @@ error_destroy_mc_io:
}
/**
- * Destroys an MC I/O object
+ * fsl_destroy_mc_io() - Destroys an MC I/O object
*
* @mc_io: MC I/O object to destroy
*/
diff --git a/drivers/bus/fsl-mc/mc-sys.c b/drivers/bus/fsl-mc/mc-sys.c
index b291b35e3884..f2052cd0a051 100644
--- a/drivers/bus/fsl-mc/mc-sys.c
+++ b/drivers/bus/fsl-mc/mc-sys.c
@@ -16,7 +16,7 @@
#include "fsl-mc-private.h"
-/**
+/*
* Timeout in milliseconds to wait for the completion of an MC command
*/
#define MC_CMD_COMPLETION_TIMEOUT_MS 500
@@ -148,9 +148,10 @@ static inline enum mc_cmd_status mc_read_response(struct fsl_mc_command __iomem
}
/**
- * Waits for the completion of an MC command doing preemptible polling.
- * uslepp_range() is called between polling iterations.
- *
+ * mc_polling_wait_preemptible() - Waits for the completion of an MC
+ * command doing preemptible polling.
+ * uslepp_range() is called between
+ * polling iterations.
* @mc_io: MC I/O object to be used
* @cmd: command buffer to receive MC response
* @mc_status: MC command completion status
@@ -194,9 +195,9 @@ static int mc_polling_wait_preemptible(struct fsl_mc_io *mc_io,
}
/**
- * Waits for the completion of an MC command doing atomic polling.
- * udelay() is called between polling iterations.
- *
+ * mc_polling_wait_atomic() - Waits for the completion of an MC command
+ * doing atomic polling. udelay() is called
+ * between polling iterations.
* @mc_io: MC I/O object to be used
* @cmd: command buffer to receive MC response
* @mc_status: MC command completion status
@@ -234,8 +235,8 @@ static int mc_polling_wait_atomic(struct fsl_mc_io *mc_io,
}
/**
- * Sends a command to the MC device using the given MC I/O object
- *
+ * mc_send_command() - Sends a command to the MC device using the given
+ * MC I/O object
* @mc_io: MC I/O object to be used
* @cmd: command to be sent
*
diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c
index e2e59a341fef..bbf6cd04861e 100644
--- a/drivers/bus/mhi/core/pm.c
+++ b/drivers/bus/mhi/core/pm.c
@@ -465,23 +465,15 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl)
/* Trigger MHI RESET so that the device will not access host memory */
if (!MHI_PM_IN_FATAL_STATE(mhi_cntrl->pm_state)) {
- u32 in_reset = -1;
- unsigned long timeout = msecs_to_jiffies(mhi_cntrl->timeout_ms);
-
dev_dbg(dev, "Triggering MHI Reset in device\n");
mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET);
/* Wait for the reset bit to be cleared by the device */
- ret = wait_event_timeout(mhi_cntrl->state_event,
- mhi_read_reg_field(mhi_cntrl,
- mhi_cntrl->regs,
- MHICTRL,
- MHICTRL_RESET_MASK,
- MHICTRL_RESET_SHIFT,
- &in_reset) ||
- !in_reset, timeout);
- if (!ret || in_reset)
- dev_err(dev, "Device failed to exit MHI Reset state\n");
+ ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
+ MHICTRL_RESET_MASK, MHICTRL_RESET_SHIFT, 0,
+ 25000);
+ if (ret)
+ dev_err(dev, "Device failed to clear MHI Reset\n");
/*
* Device will clear BHI_INTVEC as a part of RESET processing,
@@ -934,6 +926,7 @@ int mhi_pm_resume(struct mhi_controller *mhi_cntrl)
ret = wait_event_timeout(mhi_cntrl->state_event,
mhi_cntrl->dev_state == MHI_STATE_M0 ||
+ mhi_cntrl->dev_state == MHI_STATE_M2 ||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
msecs_to_jiffies(mhi_cntrl->timeout_ms));
diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c
index b3357a8a2fdb..ca3bc40427f8 100644
--- a/drivers/bus/mhi/pci_generic.c
+++ b/drivers/bus/mhi/pci_generic.c
@@ -665,7 +665,7 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err = mhi_register_controller(mhi_cntrl, mhi_cntrl_config);
if (err)
- return err;
+ goto err_disable_reporting;
/* MHI bus does not power up the controller by default */
err = mhi_prepare_for_power_up(mhi_cntrl);
@@ -699,6 +699,8 @@ err_unprepare:
mhi_unprepare_after_power_down(mhi_cntrl);
err_unregister:
mhi_unregister_controller(mhi_cntrl);
+err_disable_reporting:
+ pci_disable_pcie_error_reporting(pdev);
return err;
}
@@ -721,6 +723,7 @@ static void mhi_pci_remove(struct pci_dev *pdev)
pm_runtime_get_noresume(&pdev->dev);
mhi_unregister_controller(mhi_cntrl);
+ pci_disable_pcie_error_reporting(pdev);
}
static void mhi_pci_shutdown(struct pci_dev *pdev)
diff --git a/drivers/bus/qcom-ebi2.c b/drivers/bus/qcom-ebi2.c
index 0b8f53a688b8..663c82749222 100644
--- a/drivers/bus/qcom-ebi2.c
+++ b/drivers/bus/qcom-ebi2.c
@@ -102,8 +102,8 @@
/**
* struct cs_data - struct with info on a chipselect setting
* @enable_mask: mask to enable the chipselect in the EBI2 config
- * @slow_cfg0: offset to XMEMC slow CS config
- * @fast_cfg1: offset to XMEMC fast CS config
+ * @slow_cfg: offset to XMEMC slow CS config
+ * @fast_cfg: offset to XMEMC fast CS config
*/
struct cs_data {
u32 enable_mask;
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 90ad34c6ef8e..feb827eefd1a 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2186,7 +2186,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
len = nr * CD_FRAMESIZE_RAW;
- rq = blk_get_request(q, REQ_OP_SCSI_IN, 0);
+ rq = blk_get_request(q, REQ_OP_DRV_IN, 0);
if (IS_ERR(rq)) {
ret = PTR_ERR(rq);
break;
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
index c6d8c0f59722..8e1fe75af93f 100644
--- a/drivers/cdrom/gdrom.c
+++ b/drivers/cdrom/gdrom.c
@@ -772,53 +772,50 @@ static int probe_gdrom(struct platform_device *devptr)
goto probe_fail_no_mem;
}
probe_gdrom_setupcd();
- gd.disk = alloc_disk(1);
- if (!gd.disk) {
- err = -ENODEV;
- goto probe_fail_no_disk;
+
+ err = blk_mq_alloc_sq_tag_set(&gd.tag_set, &gdrom_mq_ops, 1,
+ BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING);
+ if (err)
+ goto probe_fail_free_cd_info;
+
+ gd.disk = blk_mq_alloc_disk(&gd.tag_set, NULL);
+ if (IS_ERR(gd.disk)) {
+ err = PTR_ERR(gd.disk);
+ goto probe_fail_free_tag_set;
}
+ gd.gdrom_rq = gd.disk->queue;
probe_gdrom_setupdisk();
if (register_cdrom(gd.disk, gd.cd_info)) {
err = -ENODEV;
- goto probe_fail_cdrom_register;
+ goto probe_fail_cleanup_disk;
}
gd.disk->fops = &gdrom_bdops;
gd.disk->events = DISK_EVENT_MEDIA_CHANGE;
/* latch on to the interrupt */
err = gdrom_set_interrupt_handlers();
if (err)
- goto probe_fail_cmdirq_register;
-
- gd.gdrom_rq = blk_mq_init_sq_queue(&gd.tag_set, &gdrom_mq_ops, 1,
- BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING);
- if (IS_ERR(gd.gdrom_rq)) {
- err = PTR_ERR(gd.gdrom_rq);
- gd.gdrom_rq = NULL;
- goto probe_fail_requestq;
- }
+ goto probe_fail_cleanup_disk;
err = probe_gdrom_setupqueue();
if (err)
- goto probe_fail_toc;
+ goto probe_fail_free_irqs;
gd.toc = kzalloc(sizeof(struct gdromtoc), GFP_KERNEL);
if (!gd.toc) {
err = -ENOMEM;
- goto probe_fail_toc;
+ goto probe_fail_free_irqs;
}
add_disk(gd.disk);
return 0;
-probe_fail_toc:
- blk_cleanup_queue(gd.gdrom_rq);
- blk_mq_free_tag_set(&gd.tag_set);
-probe_fail_requestq:
+probe_fail_free_irqs:
free_irq(HW_EVENT_GDROM_DMA, &gd);
free_irq(HW_EVENT_GDROM_CMD, &gd);
-probe_fail_cmdirq_register:
-probe_fail_cdrom_register:
- del_gendisk(gd.disk);
-probe_fail_no_disk:
+probe_fail_cleanup_disk:
+ blk_cleanup_disk(gd.disk);
+probe_fail_free_tag_set:
+ blk_mq_free_tag_set(&gd.tag_set);
+probe_fail_free_cd_info:
kfree(gd.cd_info);
probe_fail_no_mem:
unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index b151e0fcdeb5..ea3ead00f30f 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -218,19 +218,6 @@ config XILINX_HWICAP
If unsure, say N.
-config R3964
- tristate "Siemens R3964 line discipline"
- depends on TTY && BROKEN
- help
- This driver allows synchronous communication with devices using the
- Siemens R3964 packet protocol. Unless you are dealing with special
- hardware like PLCs, you are unlikely to need this.
-
- To compile this driver as a module, choose M here: the
- module will be called n_r3964.
-
- If unsure, say N.
-
config APPLICOM
tristate "Applicom intelligent fieldbus card support"
depends on PCI
@@ -357,27 +344,6 @@ config NVRAM
To compile this driver as a module, choose M here: the
module will be called nvram.
-config RAW_DRIVER
- tristate "RAW driver (/dev/raw/rawN)"
- depends on BLOCK
- help
- The raw driver permits block devices to be bound to /dev/raw/rawN.
- Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O.
- See the raw(8) manpage for more details.
-
- Applications should preferably open the device (eg /dev/hda1)
- with the O_DIRECT flag.
-
-config MAX_RAW_DEVS
- int "Maximum number of RAW devices to support (1-65536)"
- depends on RAW_DRIVER
- range 1 65536
- default "256"
- help
- The maximum number of RAW devices that are supported.
- Default is 256. Increase this number in case you need lots of
- raw devices.
-
config DEVPORT
bool "/dev/port character device"
depends on ISA || PCI
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index ffce287ef415..264eb398fdd4 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -8,7 +8,6 @@ obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o
obj-y += misc.o
obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
-obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_MSPEC) += mspec.o
obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o
obj-$(CONFIG_IBM_BSR) += bsr.o
@@ -44,6 +43,6 @@ obj-$(CONFIG_TCG_TPM) += tpm/
obj-$(CONFIG_PS3_FLASH) += ps3flash.o
-obj-$(CONFIG_XILLYBUS) += xillybus/
+obj-$(CONFIG_XILLYBUS_CLASS) += xillybus/
obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o
obj-$(CONFIG_ADI) += adi.o
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 8b55085650ad..4e5431f01450 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -156,12 +156,12 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
* This has the effect of treating non-periodic like periodic.
*/
if ((devp->hd_flags & (HPET_IE | HPET_PERIODIC)) == HPET_IE) {
- unsigned long m, t, mc, base, k;
+ unsigned long t, mc, base, k;
struct hpet __iomem *hpet = devp->hd_hpet;
struct hpets *hpetp = devp->hd_hpets;
t = devp->hd_ireqfreq;
- m = read_counter(&devp->hd_timer->hpet_compare);
+ read_counter(&devp->hd_timer->hpet_compare);
mc = read_counter(&hpet->hpet_mc);
/* The time for the next interrupt would logically be t + m,
* however, if we are very unlucky and the interrupt is delayed
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 1fe006f3f12f..3f166c8a4099 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -152,7 +152,7 @@ config HW_RANDOM_VIA
config HW_RANDOM_IXP4XX
tristate "Intel IXP4xx NPU HW Pseudo-Random Number Generator support"
- depends on ARCH_IXP4XX
+ depends on ARCH_IXP4XX || COMPILE_TEST
default HW_RANDOM
help
This driver provides kernel-side support for the Pseudo-Random
@@ -165,17 +165,17 @@ config HW_RANDOM_IXP4XX
config HW_RANDOM_OMAP
tristate "OMAP Random Number Generator support"
- depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS || ARCH_MVEBU
+ depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS || ARCH_MVEBU || ARCH_K3
default HW_RANDOM
help
- This driver provides kernel-side support for the Random Number
+ This driver provides kernel-side support for the Random Number
Generator hardware found on OMAP16xx, OMAP2/3/4/5, AM33xx/AM43xx
multimedia processors, and Marvell Armada 7k/8k SoCs.
To compile this driver as a module, choose M here: the
module will be called omap-rng.
- If unsure, say Y.
+ If unsure, say Y.
config HW_RANDOM_OMAP3_ROM
tristate "OMAP3 ROM Random Number Generator support"
@@ -485,13 +485,13 @@ config HW_RANDOM_NPCM
depends on ARCH_NPCM || COMPILE_TEST
default HW_RANDOM
help
- This driver provides support for the Random Number
+ This driver provides support for the Random Number
Generator hardware available in Nuvoton NPCM SoCs.
To compile this driver as a module, choose M here: the
module will be called npcm-rng.
- If unsure, say Y.
+ If unsure, say Y.
config HW_RANDOM_KEYSTONE
depends on ARCH_KEYSTONE || COMPILE_TEST
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index 9959c762da2f..d8d4ef5214a1 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -126,7 +126,7 @@ static struct hwrng amd_rng = {
static int __init mod_init(void)
{
- int err = -ENODEV;
+ int err;
struct pci_dev *pdev = NULL;
const struct pci_device_id *ent;
u32 pmbase;
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index adb3c2bd7783..a3db27916256 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -319,11 +319,11 @@ static int enable_best_rng(void)
return ret;
}
-static ssize_t hwrng_attr_current_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static ssize_t rng_current_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
- int err = -ENODEV;
+ int err;
struct hwrng *rng, *old_rng, *new_rng;
err = mutex_lock_interruptible(&rng_mutex);
@@ -354,9 +354,9 @@ static ssize_t hwrng_attr_current_store(struct device *dev,
return err ? : len;
}
-static ssize_t hwrng_attr_current_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t rng_current_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
ssize_t ret;
struct hwrng *rng;
@@ -371,9 +371,9 @@ static ssize_t hwrng_attr_current_show(struct device *dev,
return ret;
}
-static ssize_t hwrng_attr_available_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t rng_available_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
int err;
struct hwrng *rng;
@@ -392,22 +392,16 @@ static ssize_t hwrng_attr_available_show(struct device *dev,
return strlen(buf);
}
-static ssize_t hwrng_attr_selected_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t rng_selected_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
return sysfs_emit(buf, "%d\n", cur_rng_set_by_user);
}
-static DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR,
- hwrng_attr_current_show,
- hwrng_attr_current_store);
-static DEVICE_ATTR(rng_available, S_IRUGO,
- hwrng_attr_available_show,
- NULL);
-static DEVICE_ATTR(rng_selected, S_IRUGO,
- hwrng_attr_selected_show,
- NULL);
+static DEVICE_ATTR_RW(rng_current);
+static DEVICE_ATTR_RO(rng_available);
+static DEVICE_ATTR_RO(rng_selected);
static struct attribute *rng_dev_attrs[] = {
&dev_attr_rng_current.attr,
diff --git a/drivers/char/hw_random/exynos-trng.c b/drivers/char/hw_random/exynos-trng.c
index 8e1fe3f8dd2d..9cc3d542dd0f 100644
--- a/drivers/char/hw_random/exynos-trng.c
+++ b/drivers/char/hw_random/exynos-trng.c
@@ -132,7 +132,7 @@ static int exynos_trng_probe(struct platform_device *pdev)
return PTR_ERR(trng->mem);
pm_runtime_enable(&pdev->dev);
- ret = pm_runtime_get_sync(&pdev->dev);
+ ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "Could not get runtime PM.\n");
goto err_pm_get;
@@ -165,7 +165,7 @@ err_register:
clk_disable_unprepare(trng->clk);
err_clock:
- pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
err_pm_get:
pm_runtime_disable(&pdev->dev);
@@ -196,10 +196,9 @@ static int __maybe_unused exynos_trng_resume(struct device *dev)
{
int ret;
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0) {
dev_err(dev, "Could not get runtime PM.\n");
- pm_runtime_put_noidle(dev);
return ret;
}
diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c
index beec1627db3c..188854dd16a9 100644
--- a/drivers/char/hw_random/ixp4xx-rng.c
+++ b/drivers/char/hw_random/ixp4xx-rng.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* drivers/char/hw_random/ixp4xx-rng.c
*
@@ -8,23 +9,20 @@
* Copyright 2005 (c) MontaVista Software, Inc.
*
* Fixes by Michael Buesch
- *
- * 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/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/hw_random.h>
+#include <linux/of.h>
+#include <linux/soc/ixp4xx/cpu.h>
#include <asm/io.h>
-#include <mach/hardware.h>
-
static int ixp4xx_rng_data_read(struct hwrng *rng, u32 *buffer)
{
@@ -40,35 +38,40 @@ static struct hwrng ixp4xx_rng_ops = {
.data_read = ixp4xx_rng_data_read,
};
-static int __init ixp4xx_rng_init(void)
+static int ixp4xx_rng_probe(struct platform_device *pdev)
{
void __iomem * rng_base;
- int err;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
if (!cpu_is_ixp46x()) /* includes IXP455 */
return -ENOSYS;
- rng_base = ioremap(0x70002100, 4);
- if (!rng_base)
- return -ENOMEM;
- ixp4xx_rng_ops.priv = (unsigned long)rng_base;
- err = hwrng_register(&ixp4xx_rng_ops);
- if (err)
- iounmap(rng_base);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rng_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(rng_base))
+ return PTR_ERR(rng_base);
- return err;
+ ixp4xx_rng_ops.priv = (unsigned long)rng_base;
+ return devm_hwrng_register(dev, &ixp4xx_rng_ops);
}
-static void __exit ixp4xx_rng_exit(void)
-{
- void __iomem * rng_base = (void __iomem *)ixp4xx_rng_ops.priv;
-
- hwrng_unregister(&ixp4xx_rng_ops);
- iounmap(rng_base);
-}
+static const struct of_device_id ixp4xx_rng_of_match[] = {
+ {
+ .compatible = "intel,ixp46x-rng",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ixp4xx_rng_of_match);
-module_init(ixp4xx_rng_init);
-module_exit(ixp4xx_rng_exit);
+static struct platform_driver ixp4xx_rng_driver = {
+ .driver = {
+ .name = "ixp4xx-hwrandom",
+ .of_match_table = ixp4xx_rng_of_match,
+ },
+ .probe = ixp4xx_rng_probe,
+};
+module_platform_driver(ixp4xx_rng_driver);
MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
MODULE_DESCRIPTION("H/W Pseudo-Random Number Generator (RNG) driver for IXP45x/46x");
diff --git a/drivers/char/hw_random/ks-sa-rng.c b/drivers/char/hw_random/ks-sa-rng.c
index 8f1d47ff9799..2f2f21f1b659 100644
--- a/drivers/char/hw_random/ks-sa-rng.c
+++ b/drivers/char/hw_random/ks-sa-rng.c
@@ -241,10 +241,9 @@ static int ks_sa_rng_probe(struct platform_device *pdev)
}
pm_runtime_enable(dev);
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0) {
dev_err(dev, "Failed to enable SA power-domain\n");
- pm_runtime_put_noidle(dev);
pm_runtime_disable(dev);
return ret;
}
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index cede9f159102..00ff96703dd2 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -454,10 +454,9 @@ static int omap_rng_probe(struct platform_device *pdev)
}
pm_runtime_enable(&pdev->dev);
- ret = pm_runtime_get_sync(&pdev->dev);
+ ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to runtime_get device: %d\n", ret);
- pm_runtime_put_noidle(&pdev->dev);
goto err_ioremap;
}
@@ -543,10 +542,9 @@ static int __maybe_unused omap_rng_resume(struct device *dev)
struct omap_rng_dev *priv = dev_get_drvdata(dev);
int ret;
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0) {
dev_err(dev, "Failed to runtime_get device: %d\n", ret);
- pm_runtime_put_noidle(dev);
return ret;
}
diff --git a/drivers/char/hw_random/pseries-rng.c b/drivers/char/hw_random/pseries-rng.c
index f4949b689bd5..62bdd5af1339 100644
--- a/drivers/char/hw_random/pseries-rng.c
+++ b/drivers/char/hw_random/pseries-rng.c
@@ -29,7 +29,7 @@ static int pseries_rng_read(struct hwrng *rng, void *data, size_t max, bool wait
return 8;
}
-/**
+/*
* pseries_rng_get_desired_dma - Return desired DMA allocate for CMO operations
*
* This is a required function for a driver to operate in a CMO environment
diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig
index 07847d9a459a..249b31197eea 100644
--- a/drivers/char/ipmi/Kconfig
+++ b/drivers/char/ipmi/Kconfig
@@ -124,6 +124,33 @@ config NPCM7XX_KCS_IPMI_BMC
This support is also available as a module. If so, the module
will be called kcs_bmc_npcm7xx.
+config IPMI_KCS_BMC_CDEV_IPMI
+ depends on IPMI_KCS_BMC
+ tristate "IPMI character device interface for BMC KCS devices"
+ help
+ Provides a BMC-side character device implementing IPMI
+ semantics for KCS IPMI devices.
+
+ Say YES if you wish to expose KCS devices on the BMC for IPMI
+ purposes.
+
+ This support is also available as a module. The module will be
+ called kcs_bmc_cdev_ipmi.
+
+config IPMI_KCS_BMC_SERIO
+ depends on IPMI_KCS_BMC && SERIO
+ tristate "SerIO adaptor for BMC KCS devices"
+ help
+ Adapts the BMC KCS device for the SerIO subsystem. This allows users
+ to take advantage of userspace interfaces provided by SerIO where
+ appropriate.
+
+ Say YES if you wish to expose KCS devices on the BMC via SerIO
+ interfaces.
+
+ This support is also available as a module. The module will be
+ called kcs_bmc_serio.
+
config ASPEED_BT_IPMI_BMC
depends on ARCH_ASPEED || COMPILE_TEST
depends on REGMAP && REGMAP_MMIO && MFD_SYSCON
diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile
index 0822adc2ec41..84f47d18007f 100644
--- a/drivers/char/ipmi/Makefile
+++ b/drivers/char/ipmi/Makefile
@@ -23,6 +23,8 @@ obj-$(CONFIG_IPMI_POWERNV) += ipmi_powernv.o
obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o
obj-$(CONFIG_IPMI_KCS_BMC) += kcs_bmc.o
+obj-$(CONFIG_IPMI_KCS_BMC_SERIO) += kcs_bmc_serio.o
+obj-$(CONFIG_IPMI_KCS_BMC_CDEV_IPMI) += kcs_bmc_cdev_ipmi.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
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 8a0e97b33cae..e96cb5c4f97a 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/errno.h>
+#include <linux/panic_notifier.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 32c334e34d55..e4ff3b50de7f 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -371,16 +371,18 @@ static int __ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
data[0] = 0;
WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
- if ((ipmi_version_major > 1)
- || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5))) {
- /* This is an IPMI 1.5-only feature. */
- data[0] |= WDOG_DONT_STOP_ON_SET;
- } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
- /*
- * In ipmi 1.0, setting the timer stops the watchdog, we
- * need to start it back up again.
- */
- hbnow = 1;
+ if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
+ if ((ipmi_version_major > 1) ||
+ ((ipmi_version_major == 1) && (ipmi_version_minor >= 5))) {
+ /* This is an IPMI 1.5-only feature. */
+ data[0] |= WDOG_DONT_STOP_ON_SET;
+ } else {
+ /*
+ * In ipmi 1.0, setting the timer stops the watchdog, we
+ * need to start it back up again.
+ */
+ hbnow = 1;
+ }
}
data[1] = 0;
diff --git a/drivers/char/ipmi/kcs_bmc.c b/drivers/char/ipmi/kcs_bmc.c
index f292e74bd4a5..03d02a848f3a 100644
--- a/drivers/char/ipmi/kcs_bmc.c
+++ b/drivers/char/ipmi/kcs_bmc.c
@@ -1,458 +1,189 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2015-2018, Intel Corporation.
+ * Copyright (c) 2021, IBM Corp.
*/
-#define pr_fmt(fmt) "kcs-bmc: " fmt
-
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/ipmi_bmc.h>
+#include <linux/device.h>
+#include <linux/list.h>
#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/poll.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
+#include <linux/mutex.h>
#include "kcs_bmc.h"
-#define DEVICE_NAME "ipmi-kcs"
-
-#define KCS_MSG_BUFSIZ 1000
-
-#define KCS_ZERO_DATA 0
+/* Implement both the device and client interfaces here */
+#include "kcs_bmc_device.h"
+#include "kcs_bmc_client.h"
+/* Record registered devices and drivers */
+static DEFINE_MUTEX(kcs_bmc_lock);
+static LIST_HEAD(kcs_bmc_devices);
+static LIST_HEAD(kcs_bmc_drivers);
-/* IPMI 2.0 - Table 9-1, KCS Interface Status Register Bits */
-#define KCS_STATUS_STATE(state) (state << 6)
-#define KCS_STATUS_STATE_MASK GENMASK(7, 6)
-#define KCS_STATUS_CMD_DAT BIT(3)
-#define KCS_STATUS_SMS_ATN BIT(2)
-#define KCS_STATUS_IBF BIT(1)
-#define KCS_STATUS_OBF BIT(0)
+/* Consumer data access */
-/* IPMI 2.0 - Table 9-2, KCS Interface State Bits */
-enum kcs_states {
- IDLE_STATE = 0,
- READ_STATE = 1,
- WRITE_STATE = 2,
- ERROR_STATE = 3,
-};
-
-/* IPMI 2.0 - Table 9-3, KCS Interface Control Codes */
-#define KCS_CMD_GET_STATUS_ABORT 0x60
-#define KCS_CMD_WRITE_START 0x61
-#define KCS_CMD_WRITE_END 0x62
-#define KCS_CMD_READ_BYTE 0x68
-
-static inline u8 read_data(struct kcs_bmc *kcs_bmc)
+u8 kcs_bmc_read_data(struct kcs_bmc_device *kcs_bmc)
{
- return kcs_bmc->io_inputb(kcs_bmc, kcs_bmc->ioreg.idr);
+ return kcs_bmc->ops->io_inputb(kcs_bmc, kcs_bmc->ioreg.idr);
}
+EXPORT_SYMBOL(kcs_bmc_read_data);
-static inline void write_data(struct kcs_bmc *kcs_bmc, u8 data)
+void kcs_bmc_write_data(struct kcs_bmc_device *kcs_bmc, u8 data)
{
- kcs_bmc->io_outputb(kcs_bmc, kcs_bmc->ioreg.odr, data);
+ kcs_bmc->ops->io_outputb(kcs_bmc, kcs_bmc->ioreg.odr, data);
}
+EXPORT_SYMBOL(kcs_bmc_write_data);
-static inline u8 read_status(struct kcs_bmc *kcs_bmc)
+u8 kcs_bmc_read_status(struct kcs_bmc_device *kcs_bmc)
{
- return kcs_bmc->io_inputb(kcs_bmc, kcs_bmc->ioreg.str);
+ return kcs_bmc->ops->io_inputb(kcs_bmc, kcs_bmc->ioreg.str);
}
+EXPORT_SYMBOL(kcs_bmc_read_status);
-static inline void write_status(struct kcs_bmc *kcs_bmc, u8 data)
+void kcs_bmc_write_status(struct kcs_bmc_device *kcs_bmc, u8 data)
{
- kcs_bmc->io_outputb(kcs_bmc, kcs_bmc->ioreg.str, data);
+ kcs_bmc->ops->io_outputb(kcs_bmc, kcs_bmc->ioreg.str, data);
}
+EXPORT_SYMBOL(kcs_bmc_write_status);
-static void update_status_bits(struct kcs_bmc *kcs_bmc, u8 mask, u8 val)
+void kcs_bmc_update_status(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 val)
{
- u8 tmp = read_status(kcs_bmc);
-
- tmp &= ~mask;
- tmp |= val & mask;
-
- write_status(kcs_bmc, tmp);
+ kcs_bmc->ops->io_updateb(kcs_bmc, kcs_bmc->ioreg.str, mask, val);
}
+EXPORT_SYMBOL(kcs_bmc_update_status);
-static inline void set_state(struct kcs_bmc *kcs_bmc, u8 state)
+irqreturn_t kcs_bmc_handle_event(struct kcs_bmc_device *kcs_bmc)
{
- update_status_bits(kcs_bmc, KCS_STATUS_STATE_MASK,
- KCS_STATUS_STATE(state));
-}
+ struct kcs_bmc_client *client;
+ irqreturn_t rc = IRQ_NONE;
-static void kcs_force_abort(struct kcs_bmc *kcs_bmc)
-{
- set_state(kcs_bmc, ERROR_STATE);
- read_data(kcs_bmc);
- write_data(kcs_bmc, KCS_ZERO_DATA);
+ spin_lock(&kcs_bmc->lock);
+ client = kcs_bmc->client;
+ if (client)
+ rc = client->ops->event(client);
+ spin_unlock(&kcs_bmc->lock);
- kcs_bmc->phase = KCS_PHASE_ERROR;
- kcs_bmc->data_in_avail = false;
- kcs_bmc->data_in_idx = 0;
-}
-
-static void kcs_bmc_handle_data(struct kcs_bmc *kcs_bmc)
-{
- u8 data;
-
- switch (kcs_bmc->phase) {
- case KCS_PHASE_WRITE_START:
- kcs_bmc->phase = KCS_PHASE_WRITE_DATA;
- fallthrough;
-
- case KCS_PHASE_WRITE_DATA:
- if (kcs_bmc->data_in_idx < KCS_MSG_BUFSIZ) {
- set_state(kcs_bmc, WRITE_STATE);
- write_data(kcs_bmc, KCS_ZERO_DATA);
- kcs_bmc->data_in[kcs_bmc->data_in_idx++] =
- read_data(kcs_bmc);
- } else {
- kcs_force_abort(kcs_bmc);
- kcs_bmc->error = KCS_LENGTH_ERROR;
- }
- break;
-
- case KCS_PHASE_WRITE_END_CMD:
- if (kcs_bmc->data_in_idx < KCS_MSG_BUFSIZ) {
- set_state(kcs_bmc, READ_STATE);
- kcs_bmc->data_in[kcs_bmc->data_in_idx++] =
- read_data(kcs_bmc);
- kcs_bmc->phase = KCS_PHASE_WRITE_DONE;
- kcs_bmc->data_in_avail = true;
- wake_up_interruptible(&kcs_bmc->queue);
- } else {
- kcs_force_abort(kcs_bmc);
- kcs_bmc->error = KCS_LENGTH_ERROR;
- }
- break;
-
- case KCS_PHASE_READ:
- if (kcs_bmc->data_out_idx == kcs_bmc->data_out_len)
- set_state(kcs_bmc, IDLE_STATE);
-
- data = read_data(kcs_bmc);
- if (data != KCS_CMD_READ_BYTE) {
- set_state(kcs_bmc, ERROR_STATE);
- write_data(kcs_bmc, KCS_ZERO_DATA);
- break;
- }
-
- if (kcs_bmc->data_out_idx == kcs_bmc->data_out_len) {
- write_data(kcs_bmc, KCS_ZERO_DATA);
- kcs_bmc->phase = KCS_PHASE_IDLE;
- break;
- }
-
- write_data(kcs_bmc,
- kcs_bmc->data_out[kcs_bmc->data_out_idx++]);
- break;
-
- case KCS_PHASE_ABORT_ERROR1:
- set_state(kcs_bmc, READ_STATE);
- read_data(kcs_bmc);
- write_data(kcs_bmc, kcs_bmc->error);
- kcs_bmc->phase = KCS_PHASE_ABORT_ERROR2;
- break;
-
- case KCS_PHASE_ABORT_ERROR2:
- set_state(kcs_bmc, IDLE_STATE);
- read_data(kcs_bmc);
- write_data(kcs_bmc, KCS_ZERO_DATA);
- kcs_bmc->phase = KCS_PHASE_IDLE;
- break;
-
- default:
- kcs_force_abort(kcs_bmc);
- break;
- }
-}
-
-static void kcs_bmc_handle_cmd(struct kcs_bmc *kcs_bmc)
-{
- u8 cmd;
-
- set_state(kcs_bmc, WRITE_STATE);
- write_data(kcs_bmc, KCS_ZERO_DATA);
-
- cmd = read_data(kcs_bmc);
- switch (cmd) {
- case KCS_CMD_WRITE_START:
- kcs_bmc->phase = KCS_PHASE_WRITE_START;
- kcs_bmc->error = KCS_NO_ERROR;
- kcs_bmc->data_in_avail = false;
- kcs_bmc->data_in_idx = 0;
- break;
-
- case KCS_CMD_WRITE_END:
- if (kcs_bmc->phase != KCS_PHASE_WRITE_DATA) {
- kcs_force_abort(kcs_bmc);
- break;
- }
-
- kcs_bmc->phase = KCS_PHASE_WRITE_END_CMD;
- break;
-
- case KCS_CMD_GET_STATUS_ABORT:
- if (kcs_bmc->error == KCS_NO_ERROR)
- kcs_bmc->error = KCS_ABORTED_BY_COMMAND;
-
- kcs_bmc->phase = KCS_PHASE_ABORT_ERROR1;
- kcs_bmc->data_in_avail = false;
- kcs_bmc->data_in_idx = 0;
- break;
-
- default:
- kcs_force_abort(kcs_bmc);
- kcs_bmc->error = KCS_ILLEGAL_CONTROL_CODE;
- break;
- }
-}
-
-int kcs_bmc_handle_event(struct kcs_bmc *kcs_bmc)
-{
- unsigned long flags;
- int ret = -ENODATA;
- u8 status;
-
- spin_lock_irqsave(&kcs_bmc->lock, flags);
-
- status = read_status(kcs_bmc);
- if (status & KCS_STATUS_IBF) {
- if (!kcs_bmc->running)
- kcs_force_abort(kcs_bmc);
- else if (status & KCS_STATUS_CMD_DAT)
- kcs_bmc_handle_cmd(kcs_bmc);
- else
- kcs_bmc_handle_data(kcs_bmc);
-
- ret = 0;
- }
-
- spin_unlock_irqrestore(&kcs_bmc->lock, flags);
-
- return ret;
+ return rc;
}
EXPORT_SYMBOL(kcs_bmc_handle_event);
-static inline struct kcs_bmc *to_kcs_bmc(struct file *filp)
-{
- return container_of(filp->private_data, struct kcs_bmc, miscdev);
-}
-
-static int kcs_bmc_open(struct inode *inode, struct file *filp)
+int kcs_bmc_enable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
{
- struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
- int ret = 0;
+ int rc;
spin_lock_irq(&kcs_bmc->lock);
- if (!kcs_bmc->running)
- kcs_bmc->running = 1;
- else
- ret = -EBUSY;
- spin_unlock_irq(&kcs_bmc->lock);
-
- return ret;
-}
-
-static __poll_t kcs_bmc_poll(struct file *filp, poll_table *wait)
-{
- struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
- __poll_t mask = 0;
-
- poll_wait(filp, &kcs_bmc->queue, wait);
+ if (kcs_bmc->client) {
+ rc = -EBUSY;
+ } else {
+ u8 mask = KCS_BMC_EVENT_TYPE_IBF;
- spin_lock_irq(&kcs_bmc->lock);
- if (kcs_bmc->data_in_avail)
- mask |= EPOLLIN;
+ kcs_bmc->client = client;
+ kcs_bmc_update_event_mask(kcs_bmc, mask, mask);
+ rc = 0;
+ }
spin_unlock_irq(&kcs_bmc->lock);
- return mask;
+ return rc;
}
+EXPORT_SYMBOL(kcs_bmc_enable_device);
-static ssize_t kcs_bmc_read(struct file *filp, char __user *buf,
- size_t count, loff_t *ppos)
+void kcs_bmc_disable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
{
- struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
- bool data_avail;
- size_t data_len;
- ssize_t ret;
-
- if (!(filp->f_flags & O_NONBLOCK))
- wait_event_interruptible(kcs_bmc->queue,
- kcs_bmc->data_in_avail);
-
- mutex_lock(&kcs_bmc->mutex);
-
spin_lock_irq(&kcs_bmc->lock);
- data_avail = kcs_bmc->data_in_avail;
- if (data_avail) {
- data_len = kcs_bmc->data_in_idx;
- memcpy(kcs_bmc->kbuffer, kcs_bmc->data_in, data_len);
- }
- spin_unlock_irq(&kcs_bmc->lock);
-
- if (!data_avail) {
- ret = -EAGAIN;
- goto out_unlock;
- }
-
- if (count < data_len) {
- pr_err("channel=%u with too large data : %zu\n",
- kcs_bmc->channel, data_len);
-
- spin_lock_irq(&kcs_bmc->lock);
- kcs_force_abort(kcs_bmc);
- spin_unlock_irq(&kcs_bmc->lock);
+ if (client == kcs_bmc->client) {
+ u8 mask = KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE;
- ret = -EOVERFLOW;
- goto out_unlock;
- }
-
- if (copy_to_user(buf, kcs_bmc->kbuffer, data_len)) {
- ret = -EFAULT;
- goto out_unlock;
- }
-
- ret = data_len;
-
- spin_lock_irq(&kcs_bmc->lock);
- if (kcs_bmc->phase == KCS_PHASE_WRITE_DONE) {
- kcs_bmc->phase = KCS_PHASE_WAIT_READ;
- kcs_bmc->data_in_avail = false;
- kcs_bmc->data_in_idx = 0;
- } else {
- ret = -EAGAIN;
+ kcs_bmc_update_event_mask(kcs_bmc, mask, 0);
+ kcs_bmc->client = NULL;
}
spin_unlock_irq(&kcs_bmc->lock);
-
-out_unlock:
- mutex_unlock(&kcs_bmc->mutex);
-
- return ret;
}
+EXPORT_SYMBOL(kcs_bmc_disable_device);
-static ssize_t kcs_bmc_write(struct file *filp, const char __user *buf,
- size_t count, loff_t *ppos)
+int kcs_bmc_add_device(struct kcs_bmc_device *kcs_bmc)
{
- struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
- ssize_t ret;
-
- /* a minimum response size '3' : netfn + cmd + ccode */
- if (count < 3 || count > KCS_MSG_BUFSIZ)
- return -EINVAL;
-
- mutex_lock(&kcs_bmc->mutex);
-
- if (copy_from_user(kcs_bmc->kbuffer, buf, count)) {
- ret = -EFAULT;
- goto out_unlock;
- }
+ struct kcs_bmc_driver *drv;
+ int error = 0;
+ int rc;
- spin_lock_irq(&kcs_bmc->lock);
- if (kcs_bmc->phase == KCS_PHASE_WAIT_READ) {
- kcs_bmc->phase = KCS_PHASE_READ;
- kcs_bmc->data_out_idx = 1;
- kcs_bmc->data_out_len = count;
- memcpy(kcs_bmc->data_out, kcs_bmc->kbuffer, count);
- write_data(kcs_bmc, kcs_bmc->data_out[0]);
- ret = count;
- } else {
- ret = -EINVAL;
+ spin_lock_init(&kcs_bmc->lock);
+ kcs_bmc->client = NULL;
+
+ mutex_lock(&kcs_bmc_lock);
+ list_add(&kcs_bmc->entry, &kcs_bmc_devices);
+ list_for_each_entry(drv, &kcs_bmc_drivers, entry) {
+ rc = drv->ops->add_device(kcs_bmc);
+ if (!rc)
+ continue;
+
+ dev_err(kcs_bmc->dev, "Failed to add chardev for KCS channel %d: %d",
+ kcs_bmc->channel, rc);
+ error = rc;
}
- spin_unlock_irq(&kcs_bmc->lock);
-
-out_unlock:
- mutex_unlock(&kcs_bmc->mutex);
+ mutex_unlock(&kcs_bmc_lock);
- return ret;
+ return error;
}
+EXPORT_SYMBOL(kcs_bmc_add_device);
-static long kcs_bmc_ioctl(struct file *filp, unsigned int cmd,
- unsigned long arg)
+void kcs_bmc_remove_device(struct kcs_bmc_device *kcs_bmc)
{
- struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
- long ret = 0;
+ struct kcs_bmc_driver *drv;
+ int rc;
- spin_lock_irq(&kcs_bmc->lock);
-
- switch (cmd) {
- case IPMI_BMC_IOCTL_SET_SMS_ATN:
- update_status_bits(kcs_bmc, KCS_STATUS_SMS_ATN,
- KCS_STATUS_SMS_ATN);
- break;
-
- case IPMI_BMC_IOCTL_CLEAR_SMS_ATN:
- update_status_bits(kcs_bmc, KCS_STATUS_SMS_ATN,
- 0);
- break;
-
- case IPMI_BMC_IOCTL_FORCE_ABORT:
- kcs_force_abort(kcs_bmc);
- break;
-
- default:
- ret = -EINVAL;
- break;
+ mutex_lock(&kcs_bmc_lock);
+ list_del(&kcs_bmc->entry);
+ list_for_each_entry(drv, &kcs_bmc_drivers, entry) {
+ rc = drv->ops->remove_device(kcs_bmc);
+ if (rc)
+ dev_err(kcs_bmc->dev, "Failed to remove chardev for KCS channel %d: %d",
+ kcs_bmc->channel, rc);
}
-
- spin_unlock_irq(&kcs_bmc->lock);
-
- return ret;
+ mutex_unlock(&kcs_bmc_lock);
}
+EXPORT_SYMBOL(kcs_bmc_remove_device);
-static int kcs_bmc_release(struct inode *inode, struct file *filp)
+void kcs_bmc_register_driver(struct kcs_bmc_driver *drv)
{
- struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
-
- spin_lock_irq(&kcs_bmc->lock);
- kcs_bmc->running = 0;
- kcs_force_abort(kcs_bmc);
- spin_unlock_irq(&kcs_bmc->lock);
+ struct kcs_bmc_device *kcs_bmc;
+ int rc;
- return 0;
+ mutex_lock(&kcs_bmc_lock);
+ list_add(&drv->entry, &kcs_bmc_drivers);
+ list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) {
+ rc = drv->ops->add_device(kcs_bmc);
+ if (rc)
+ dev_err(kcs_bmc->dev, "Failed to add driver for KCS channel %d: %d",
+ kcs_bmc->channel, rc);
+ }
+ mutex_unlock(&kcs_bmc_lock);
}
+EXPORT_SYMBOL(kcs_bmc_register_driver);
-static const struct file_operations kcs_bmc_fops = {
- .owner = THIS_MODULE,
- .open = kcs_bmc_open,
- .read = kcs_bmc_read,
- .write = kcs_bmc_write,
- .release = kcs_bmc_release,
- .poll = kcs_bmc_poll,
- .unlocked_ioctl = kcs_bmc_ioctl,
-};
-
-struct kcs_bmc *kcs_bmc_alloc(struct device *dev, int sizeof_priv, u32 channel)
+void kcs_bmc_unregister_driver(struct kcs_bmc_driver *drv)
{
- struct kcs_bmc *kcs_bmc;
-
- kcs_bmc = devm_kzalloc(dev, sizeof(*kcs_bmc) + sizeof_priv, GFP_KERNEL);
- if (!kcs_bmc)
- return NULL;
-
- spin_lock_init(&kcs_bmc->lock);
- kcs_bmc->channel = channel;
+ struct kcs_bmc_device *kcs_bmc;
+ int rc;
- mutex_init(&kcs_bmc->mutex);
- init_waitqueue_head(&kcs_bmc->queue);
-
- kcs_bmc->data_in = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
- kcs_bmc->data_out = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
- kcs_bmc->kbuffer = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
-
- kcs_bmc->miscdev.minor = MISC_DYNAMIC_MINOR;
- kcs_bmc->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s%u",
- DEVICE_NAME, channel);
- if (!kcs_bmc->data_in || !kcs_bmc->data_out || !kcs_bmc->kbuffer ||
- !kcs_bmc->miscdev.name)
- return NULL;
- kcs_bmc->miscdev.fops = &kcs_bmc_fops;
+ mutex_lock(&kcs_bmc_lock);
+ list_del(&drv->entry);
+ list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) {
+ rc = drv->ops->remove_device(kcs_bmc);
+ if (rc)
+ dev_err(kcs_bmc->dev, "Failed to remove driver for KCS channel %d: %d",
+ kcs_bmc->channel, rc);
+ }
+ mutex_unlock(&kcs_bmc_lock);
+}
+EXPORT_SYMBOL(kcs_bmc_unregister_driver);
- return kcs_bmc;
+void kcs_bmc_update_event_mask(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 events)
+{
+ kcs_bmc->ops->irq_mask_update(kcs_bmc, mask, events);
}
-EXPORT_SYMBOL(kcs_bmc_alloc);
+EXPORT_SYMBOL(kcs_bmc_update_event_mask);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
+MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
MODULE_DESCRIPTION("KCS BMC to handle the IPMI request from system software");
diff --git a/drivers/char/ipmi/kcs_bmc.h b/drivers/char/ipmi/kcs_bmc.h
index eb9ea4ce78b8..fa408b802c79 100644
--- a/drivers/char/ipmi/kcs_bmc.h
+++ b/drivers/char/ipmi/kcs_bmc.h
@@ -6,54 +6,14 @@
#ifndef __KCS_BMC_H__
#define __KCS_BMC_H__
-#include <linux/miscdevice.h>
+#include <linux/list.h>
-/* Different phases of the KCS BMC module.
- * KCS_PHASE_IDLE:
- * BMC should not be expecting nor sending any data.
- * KCS_PHASE_WRITE_START:
- * BMC is receiving a WRITE_START command from system software.
- * KCS_PHASE_WRITE_DATA:
- * BMC is receiving a data byte from system software.
- * KCS_PHASE_WRITE_END_CMD:
- * BMC is waiting a last data byte from system software.
- * KCS_PHASE_WRITE_DONE:
- * BMC has received the whole request from system software.
- * KCS_PHASE_WAIT_READ:
- * BMC is waiting the response from the upper IPMI service.
- * KCS_PHASE_READ:
- * BMC is transferring the response to system software.
- * KCS_PHASE_ABORT_ERROR1:
- * BMC is waiting error status request from system software.
- * KCS_PHASE_ABORT_ERROR2:
- * BMC is waiting for idle status afer error from system software.
- * KCS_PHASE_ERROR:
- * BMC has detected a protocol violation at the interface level.
- */
-enum kcs_phases {
- KCS_PHASE_IDLE,
-
- KCS_PHASE_WRITE_START,
- KCS_PHASE_WRITE_DATA,
- KCS_PHASE_WRITE_END_CMD,
- KCS_PHASE_WRITE_DONE,
+#define KCS_BMC_EVENT_TYPE_OBE BIT(0)
+#define KCS_BMC_EVENT_TYPE_IBF BIT(1)
- KCS_PHASE_WAIT_READ,
- KCS_PHASE_READ,
-
- KCS_PHASE_ABORT_ERROR1,
- KCS_PHASE_ABORT_ERROR2,
- KCS_PHASE_ERROR
-};
-
-/* IPMI 2.0 - Table 9-4, KCS Interface Status Codes */
-enum kcs_errors {
- KCS_NO_ERROR = 0x00,
- KCS_ABORTED_BY_COMMAND = 0x01,
- KCS_ILLEGAL_CONTROL_CODE = 0x02,
- KCS_LENGTH_ERROR = 0x06,
- KCS_UNSPECIFIED_ERROR = 0xFF
-};
+#define KCS_BMC_STR_OBF BIT(0)
+#define KCS_BMC_STR_IBF BIT(1)
+#define KCS_BMC_STR_CMD_DAT BIT(3)
/* IPMI 2.0 - 9.5, KCS Interface Registers
* @idr: Input Data Register
@@ -66,43 +26,21 @@ struct kcs_ioreg {
u32 str;
};
-struct kcs_bmc {
- spinlock_t lock;
+struct kcs_bmc_device_ops;
+struct kcs_bmc_client;
+struct kcs_bmc_device {
+ struct list_head entry;
+
+ struct device *dev;
u32 channel;
- int running;
- /* Setup by BMC KCS controller driver */
struct kcs_ioreg ioreg;
- u8 (*io_inputb)(struct kcs_bmc *kcs_bmc, u32 reg);
- void (*io_outputb)(struct kcs_bmc *kcs_bmc, u32 reg, u8 b);
-
- enum kcs_phases phase;
- enum kcs_errors error;
-
- wait_queue_head_t queue;
- bool data_in_avail;
- int data_in_idx;
- u8 *data_in;
-
- int data_out_idx;
- int data_out_len;
- u8 *data_out;
- struct mutex mutex;
- u8 *kbuffer;
+ const struct kcs_bmc_device_ops *ops;
- struct miscdevice miscdev;
-
- unsigned long priv[];
+ spinlock_t lock;
+ struct kcs_bmc_client *client;
};
-static inline void *kcs_bmc_priv(struct kcs_bmc *kcs_bmc)
-{
- return kcs_bmc->priv;
-}
-
-int kcs_bmc_handle_event(struct kcs_bmc *kcs_bmc);
-struct kcs_bmc *kcs_bmc_alloc(struct device *dev, int sizeof_priv,
- u32 channel);
#endif /* __KCS_BMC_H__ */
diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c
index eefe362f65f0..92a37b33494c 100644
--- a/drivers/char/ipmi/kcs_bmc_aspeed.c
+++ b/drivers/char/ipmi/kcs_bmc_aspeed.c
@@ -9,10 +9,12 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/irq.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/poll.h>
#include <linux/regmap.h>
@@ -20,24 +22,53 @@
#include <linux/slab.h>
#include <linux/timer.h>
-#include "kcs_bmc.h"
+#include "kcs_bmc_device.h"
#define DEVICE_NAME "ast-kcs-bmc"
#define KCS_CHANNEL_MAX 4
+/*
+ * Field class descriptions
+ *
+ * LPCyE Enable LPC channel y
+ * IBFIEy Input Buffer Full IRQ Enable for LPC channel y
+ * IRQxEy Assert SerIRQ x for LPC channel y (Deprecated, use IDyIRQX, IRQXEy)
+ * IDyIRQX Use the specified 4-bit SerIRQ for LPC channel y
+ * SELyIRQX SerIRQ polarity for LPC channel y (low: 0, high: 1)
+ * IRQXEy Assert the SerIRQ specified in IDyIRQX for LPC channel y
+ */
+
+#define LPC_TYIRQX_LOW 0b00
+#define LPC_TYIRQX_HIGH 0b01
+#define LPC_TYIRQX_RSVD 0b10
+#define LPC_TYIRQX_RISING 0b11
+
#define LPC_HICR0 0x000
#define LPC_HICR0_LPC3E BIT(7)
#define LPC_HICR0_LPC2E BIT(6)
#define LPC_HICR0_LPC1E BIT(5)
#define LPC_HICR2 0x008
-#define LPC_HICR2_IBFIF3 BIT(3)
-#define LPC_HICR2_IBFIF2 BIT(2)
-#define LPC_HICR2_IBFIF1 BIT(1)
+#define LPC_HICR2_IBFIE3 BIT(3)
+#define LPC_HICR2_IBFIE2 BIT(2)
+#define LPC_HICR2_IBFIE1 BIT(1)
#define LPC_HICR4 0x010
#define LPC_HICR4_LADR12AS BIT(7)
#define LPC_HICR4_KCSENBL BIT(2)
+#define LPC_SIRQCR0 0x070
+/* IRQ{12,1}E1 are deprecated as of AST2600 A3 but necessary for prior chips */
+#define LPC_SIRQCR0_IRQ12E1 BIT(1)
+#define LPC_SIRQCR0_IRQ1E1 BIT(0)
+#define LPC_HICR5 0x080
+#define LPC_HICR5_ID3IRQX_MASK GENMASK(23, 20)
+#define LPC_HICR5_ID3IRQX_SHIFT 20
+#define LPC_HICR5_ID2IRQX_MASK GENMASK(19, 16)
+#define LPC_HICR5_ID2IRQX_SHIFT 16
+#define LPC_HICR5_SEL3IRQX BIT(15)
+#define LPC_HICR5_IRQXE3 BIT(14)
+#define LPC_HICR5_SEL2IRQX BIT(13)
+#define LPC_HICR5_IRQXE2 BIT(12)
#define LPC_LADR3H 0x014
#define LPC_LADR3L 0x018
#define LPC_LADR12H 0x01C
@@ -52,21 +83,64 @@
#define LPC_STR2 0x040
#define LPC_STR3 0x044
#define LPC_HICRB 0x100
-#define LPC_HICRB_IBFIF4 BIT(1)
+#define LPC_HICRB_EN16LADR2 BIT(5)
+#define LPC_HICRB_EN16LADR1 BIT(4)
+#define LPC_HICRB_IBFIE4 BIT(1)
#define LPC_HICRB_LPC4E BIT(0)
+#define LPC_HICRC 0x104
+#define LPC_HICRC_ID4IRQX_MASK GENMASK(7, 4)
+#define LPC_HICRC_ID4IRQX_SHIFT 4
+#define LPC_HICRC_TY4IRQX_MASK GENMASK(3, 2)
+#define LPC_HICRC_TY4IRQX_SHIFT 2
+#define LPC_HICRC_OBF4_AUTO_CLR BIT(1)
+#define LPC_HICRC_IRQXE4 BIT(0)
#define LPC_LADR4 0x110
#define LPC_IDR4 0x114
#define LPC_ODR4 0x118
#define LPC_STR4 0x11C
+#define LPC_LSADR12 0x120
+#define LPC_LSADR12_LSADR2_MASK GENMASK(31, 16)
+#define LPC_LSADR12_LSADR2_SHIFT 16
+#define LPC_LSADR12_LSADR1_MASK GENMASK(15, 0)
+#define LPC_LSADR12_LSADR1_SHIFT 0
+
+#define OBE_POLL_PERIOD (HZ / 2)
+
+enum aspeed_kcs_irq_mode {
+ aspeed_kcs_irq_none,
+ aspeed_kcs_irq_serirq,
+};
struct aspeed_kcs_bmc {
+ struct kcs_bmc_device kcs_bmc;
+
struct regmap *map;
+
+ struct {
+ enum aspeed_kcs_irq_mode mode;
+ int id;
+ } upstream_irq;
+
+ struct {
+ spinlock_t lock;
+ bool remove;
+ struct timer_list timer;
+ } obe;
};
+struct aspeed_kcs_of_ops {
+ int (*get_channel)(struct platform_device *pdev);
+ int (*get_io_address)(struct platform_device *pdev, u32 addrs[2]);
+};
-static u8 aspeed_kcs_inb(struct kcs_bmc *kcs_bmc, u32 reg)
+static inline struct aspeed_kcs_bmc *to_aspeed_kcs_bmc(struct kcs_bmc_device *kcs_bmc)
{
- struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
+ return container_of(kcs_bmc, struct aspeed_kcs_bmc, kcs_bmc);
+}
+
+static u8 aspeed_kcs_inb(struct kcs_bmc_device *kcs_bmc, u32 reg)
+{
+ struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc);
u32 val = 0;
int rc;
@@ -76,15 +150,66 @@ static u8 aspeed_kcs_inb(struct kcs_bmc *kcs_bmc, u32 reg)
return rc == 0 ? (u8) val : 0;
}
-static void aspeed_kcs_outb(struct kcs_bmc *kcs_bmc, u32 reg, u8 data)
+static void aspeed_kcs_outb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 data)
{
- struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
+ struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc);
int rc;
rc = regmap_write(priv->map, reg, data);
WARN(rc != 0, "regmap_write() failed: %d\n", rc);
+
+ /* Trigger the upstream IRQ on ODR writes, if enabled */
+
+ switch (reg) {
+ case LPC_ODR1:
+ case LPC_ODR2:
+ case LPC_ODR3:
+ case LPC_ODR4:
+ break;
+ default:
+ return;
+ }
+
+ if (priv->upstream_irq.mode != aspeed_kcs_irq_serirq)
+ return;
+
+ switch (kcs_bmc->channel) {
+ case 1:
+ switch (priv->upstream_irq.id) {
+ case 12:
+ regmap_update_bits(priv->map, LPC_SIRQCR0, LPC_SIRQCR0_IRQ12E1,
+ LPC_SIRQCR0_IRQ12E1);
+ break;
+ case 1:
+ regmap_update_bits(priv->map, LPC_SIRQCR0, LPC_SIRQCR0_IRQ1E1,
+ LPC_SIRQCR0_IRQ1E1);
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2:
+ regmap_update_bits(priv->map, LPC_HICR5, LPC_HICR5_IRQXE2, LPC_HICR5_IRQXE2);
+ break;
+ case 3:
+ regmap_update_bits(priv->map, LPC_HICR5, LPC_HICR5_IRQXE3, LPC_HICR5_IRQXE3);
+ break;
+ case 4:
+ regmap_update_bits(priv->map, LPC_HICRC, LPC_HICRC_IRQXE4, LPC_HICRC_IRQXE4);
+ break;
+ default:
+ break;
+ }
}
+static void aspeed_kcs_updateb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 mask, u8 val)
+{
+ struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc);
+ int rc;
+
+ rc = regmap_update_bits(priv->map, reg, mask, val);
+ WARN(rc != 0, "regmap_update_bits() failed: %d\n", rc);
+}
/*
* AST_usrGuide_KCS.pdf
@@ -99,118 +224,237 @@ static void aspeed_kcs_outb(struct kcs_bmc *kcs_bmc, u32 reg, u8 data)
* C. KCS4
* D / C : CA4h / CA5h
*/
-static void aspeed_kcs_set_address(struct kcs_bmc *kcs_bmc, u16 addr)
+static int aspeed_kcs_set_address(struct kcs_bmc_device *kcs_bmc, u32 addrs[2], int nr_addrs)
{
- struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
+ struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc);
- switch (kcs_bmc->channel) {
+ if (WARN_ON(nr_addrs < 1 || nr_addrs > 2))
+ return -EINVAL;
+
+ switch (priv->kcs_bmc.channel) {
case 1:
- regmap_update_bits(priv->map, LPC_HICR4,
- LPC_HICR4_LADR12AS, 0);
- regmap_write(priv->map, LPC_LADR12H, addr >> 8);
- regmap_write(priv->map, LPC_LADR12L, addr & 0xFF);
+ regmap_update_bits(priv->map, LPC_HICR4, LPC_HICR4_LADR12AS, 0);
+ regmap_write(priv->map, LPC_LADR12H, addrs[0] >> 8);
+ regmap_write(priv->map, LPC_LADR12L, addrs[0] & 0xFF);
+ if (nr_addrs == 2) {
+ regmap_update_bits(priv->map, LPC_LSADR12, LPC_LSADR12_LSADR1_MASK,
+ addrs[1] << LPC_LSADR12_LSADR1_SHIFT);
+
+ regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_EN16LADR1,
+ LPC_HICRB_EN16LADR1);
+ }
break;
case 2:
- regmap_update_bits(priv->map, LPC_HICR4,
- LPC_HICR4_LADR12AS, LPC_HICR4_LADR12AS);
- regmap_write(priv->map, LPC_LADR12H, addr >> 8);
- regmap_write(priv->map, LPC_LADR12L, addr & 0xFF);
+ regmap_update_bits(priv->map, LPC_HICR4, LPC_HICR4_LADR12AS, LPC_HICR4_LADR12AS);
+ regmap_write(priv->map, LPC_LADR12H, addrs[0] >> 8);
+ regmap_write(priv->map, LPC_LADR12L, addrs[0] & 0xFF);
+ if (nr_addrs == 2) {
+ regmap_update_bits(priv->map, LPC_LSADR12, LPC_LSADR12_LSADR2_MASK,
+ addrs[1] << LPC_LSADR12_LSADR2_SHIFT);
+
+ regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_EN16LADR2,
+ LPC_HICRB_EN16LADR2);
+ }
break;
case 3:
- regmap_write(priv->map, LPC_LADR3H, addr >> 8);
- regmap_write(priv->map, LPC_LADR3L, addr & 0xFF);
+ if (nr_addrs == 2) {
+ dev_err(priv->kcs_bmc.dev,
+ "Channel 3 only supports inferred status IO address\n");
+ return -EINVAL;
+ }
+
+ regmap_write(priv->map, LPC_LADR3H, addrs[0] >> 8);
+ regmap_write(priv->map, LPC_LADR3L, addrs[0] & 0xFF);
break;
case 4:
- regmap_write(priv->map, LPC_LADR4, ((addr + 1) << 16) |
- addr);
+ if (nr_addrs == 1)
+ regmap_write(priv->map, LPC_LADR4, ((addrs[0] + 1) << 16) | addrs[0]);
+ else
+ regmap_write(priv->map, LPC_LADR4, (addrs[1] << 16) | addrs[0]);
+
break;
default:
- break;
+ return -EINVAL;
}
+
+ return 0;
}
-static void aspeed_kcs_enable_channel(struct kcs_bmc *kcs_bmc, bool enable)
+static inline int aspeed_kcs_map_serirq_type(u32 dt_type)
{
- struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
+ switch (dt_type) {
+ case IRQ_TYPE_EDGE_RISING:
+ return LPC_TYIRQX_RISING;
+ case IRQ_TYPE_LEVEL_HIGH:
+ return LPC_TYIRQX_HIGH;
+ case IRQ_TYPE_LEVEL_LOW:
+ return LPC_TYIRQX_LOW;
+ default:
+ return -EINVAL;
+ }
+}
- switch (kcs_bmc->channel) {
+static int aspeed_kcs_config_upstream_irq(struct aspeed_kcs_bmc *priv, u32 id, u32 dt_type)
+{
+ unsigned int mask, val, hw_type;
+ int ret;
+
+ if (id > 15)
+ return -EINVAL;
+
+ ret = aspeed_kcs_map_serirq_type(dt_type);
+ if (ret < 0)
+ return ret;
+ hw_type = ret;
+
+ priv->upstream_irq.mode = aspeed_kcs_irq_serirq;
+ priv->upstream_irq.id = id;
+
+ switch (priv->kcs_bmc.channel) {
case 1:
- if (enable) {
- regmap_update_bits(priv->map, LPC_HICR2,
- LPC_HICR2_IBFIF1, LPC_HICR2_IBFIF1);
- regmap_update_bits(priv->map, LPC_HICR0,
- LPC_HICR0_LPC1E, LPC_HICR0_LPC1E);
- } else {
- regmap_update_bits(priv->map, LPC_HICR0,
- LPC_HICR0_LPC1E, 0);
- regmap_update_bits(priv->map, LPC_HICR2,
- LPC_HICR2_IBFIF1, 0);
- }
+ /* Needs IRQxE1 rather than (ID1IRQX, SEL1IRQX, IRQXE1) before AST2600 A3 */
break;
-
case 2:
- if (enable) {
- regmap_update_bits(priv->map, LPC_HICR2,
- LPC_HICR2_IBFIF2, LPC_HICR2_IBFIF2);
- regmap_update_bits(priv->map, LPC_HICR0,
- LPC_HICR0_LPC2E, LPC_HICR0_LPC2E);
- } else {
- regmap_update_bits(priv->map, LPC_HICR0,
- LPC_HICR0_LPC2E, 0);
- regmap_update_bits(priv->map, LPC_HICR2,
- LPC_HICR2_IBFIF2, 0);
- }
- break;
+ if (!(hw_type == LPC_TYIRQX_LOW || hw_type == LPC_TYIRQX_HIGH))
+ return -EINVAL;
+
+ mask = LPC_HICR5_SEL2IRQX | LPC_HICR5_ID2IRQX_MASK;
+ val = (id << LPC_HICR5_ID2IRQX_SHIFT);
+ val |= (hw_type == LPC_TYIRQX_HIGH) ? LPC_HICR5_SEL2IRQX : 0;
+ regmap_update_bits(priv->map, LPC_HICR5, mask, val);
- case 3:
- if (enable) {
- regmap_update_bits(priv->map, LPC_HICR2,
- LPC_HICR2_IBFIF3, LPC_HICR2_IBFIF3);
- regmap_update_bits(priv->map, LPC_HICR0,
- LPC_HICR0_LPC3E, LPC_HICR0_LPC3E);
- regmap_update_bits(priv->map, LPC_HICR4,
- LPC_HICR4_KCSENBL, LPC_HICR4_KCSENBL);
- } else {
- regmap_update_bits(priv->map, LPC_HICR0,
- LPC_HICR0_LPC3E, 0);
- regmap_update_bits(priv->map, LPC_HICR4,
- LPC_HICR4_KCSENBL, 0);
- regmap_update_bits(priv->map, LPC_HICR2,
- LPC_HICR2_IBFIF3, 0);
- }
break;
+ case 3:
+ if (!(hw_type == LPC_TYIRQX_LOW || hw_type == LPC_TYIRQX_HIGH))
+ return -EINVAL;
+
+ mask = LPC_HICR5_SEL3IRQX | LPC_HICR5_ID3IRQX_MASK;
+ val = (id << LPC_HICR5_ID3IRQX_SHIFT);
+ val |= (hw_type == LPC_TYIRQX_HIGH) ? LPC_HICR5_SEL3IRQX : 0;
+ regmap_update_bits(priv->map, LPC_HICR5, mask, val);
+ break;
case 4:
- if (enable)
- regmap_update_bits(priv->map, LPC_HICRB,
- LPC_HICRB_IBFIF4 | LPC_HICRB_LPC4E,
- LPC_HICRB_IBFIF4 | LPC_HICRB_LPC4E);
- else
- regmap_update_bits(priv->map, LPC_HICRB,
- LPC_HICRB_IBFIF4 | LPC_HICRB_LPC4E,
- 0);
+ mask = LPC_HICRC_ID4IRQX_MASK | LPC_HICRC_TY4IRQX_MASK | LPC_HICRC_OBF4_AUTO_CLR;
+ val = (id << LPC_HICRC_ID4IRQX_SHIFT) | (hw_type << LPC_HICRC_TY4IRQX_SHIFT);
+ regmap_update_bits(priv->map, LPC_HICRC, mask, val);
break;
+ default:
+ dev_warn(priv->kcs_bmc.dev,
+ "SerIRQ configuration not supported on KCS channel %d\n",
+ priv->kcs_bmc.channel);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void aspeed_kcs_enable_channel(struct kcs_bmc_device *kcs_bmc, bool enable)
+{
+ struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc);
+ switch (kcs_bmc->channel) {
+ case 1:
+ regmap_update_bits(priv->map, LPC_HICR0, LPC_HICR0_LPC1E, enable * LPC_HICR0_LPC1E);
+ return;
+ case 2:
+ regmap_update_bits(priv->map, LPC_HICR0, LPC_HICR0_LPC2E, enable * LPC_HICR0_LPC2E);
+ return;
+ case 3:
+ regmap_update_bits(priv->map, LPC_HICR0, LPC_HICR0_LPC3E, enable * LPC_HICR0_LPC3E);
+ regmap_update_bits(priv->map, LPC_HICR4,
+ LPC_HICR4_KCSENBL, enable * LPC_HICR4_KCSENBL);
+ return;
+ case 4:
+ regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_LPC4E, enable * LPC_HICRB_LPC4E);
+ return;
default:
- break;
+ pr_warn("%s: Unsupported channel: %d", __func__, kcs_bmc->channel);
+ return;
}
}
-static irqreturn_t aspeed_kcs_irq(int irq, void *arg)
+static void aspeed_kcs_check_obe(struct timer_list *timer)
+{
+ struct aspeed_kcs_bmc *priv = container_of(timer, struct aspeed_kcs_bmc, obe.timer);
+ unsigned long flags;
+ u8 str;
+
+ spin_lock_irqsave(&priv->obe.lock, flags);
+ if (priv->obe.remove) {
+ spin_unlock_irqrestore(&priv->obe.lock, flags);
+ return;
+ }
+
+ str = aspeed_kcs_inb(&priv->kcs_bmc, priv->kcs_bmc.ioreg.str);
+ if (str & KCS_BMC_STR_OBF) {
+ mod_timer(timer, jiffies + OBE_POLL_PERIOD);
+ spin_unlock_irqrestore(&priv->obe.lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&priv->obe.lock, flags);
+
+ kcs_bmc_handle_event(&priv->kcs_bmc);
+}
+
+static void aspeed_kcs_irq_mask_update(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 state)
{
- struct kcs_bmc *kcs_bmc = arg;
+ struct aspeed_kcs_bmc *priv = to_aspeed_kcs_bmc(kcs_bmc);
- if (!kcs_bmc_handle_event(kcs_bmc))
- return IRQ_HANDLED;
+ /* We don't have an OBE IRQ, emulate it */
+ if (mask & KCS_BMC_EVENT_TYPE_OBE) {
+ if (KCS_BMC_EVENT_TYPE_OBE & state)
+ mod_timer(&priv->obe.timer, jiffies + OBE_POLL_PERIOD);
+ else
+ del_timer(&priv->obe.timer);
+ }
- return IRQ_NONE;
+ if (mask & KCS_BMC_EVENT_TYPE_IBF) {
+ const bool enable = !!(state & KCS_BMC_EVENT_TYPE_IBF);
+
+ switch (kcs_bmc->channel) {
+ case 1:
+ regmap_update_bits(priv->map, LPC_HICR2, LPC_HICR2_IBFIE1,
+ enable * LPC_HICR2_IBFIE1);
+ return;
+ case 2:
+ regmap_update_bits(priv->map, LPC_HICR2, LPC_HICR2_IBFIE2,
+ enable * LPC_HICR2_IBFIE2);
+ return;
+ case 3:
+ regmap_update_bits(priv->map, LPC_HICR2, LPC_HICR2_IBFIE3,
+ enable * LPC_HICR2_IBFIE3);
+ return;
+ case 4:
+ regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_IBFIE4,
+ enable * LPC_HICRB_IBFIE4);
+ return;
+ default:
+ pr_warn("%s: Unsupported channel: %d", __func__, kcs_bmc->channel);
+ return;
+ }
+ }
}
-static int aspeed_kcs_config_irq(struct kcs_bmc *kcs_bmc,
+static const struct kcs_bmc_device_ops aspeed_kcs_ops = {
+ .irq_mask_update = aspeed_kcs_irq_mask_update,
+ .io_inputb = aspeed_kcs_inb,
+ .io_outputb = aspeed_kcs_outb,
+ .io_updateb = aspeed_kcs_updateb,
+};
+
+static irqreturn_t aspeed_kcs_irq(int irq, void *arg)
+{
+ struct kcs_bmc_device *kcs_bmc = arg;
+
+ return kcs_bmc_handle_event(kcs_bmc);
+}
+
+static int aspeed_kcs_config_downstream_irq(struct kcs_bmc_device *kcs_bmc,
struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -231,13 +475,10 @@ static const struct kcs_ioreg ast_kcs_bmc_ioregs[KCS_CHANNEL_MAX] = {
{ .idr = LPC_IDR4, .odr = LPC_ODR4, .str = LPC_STR4 },
};
-static struct kcs_bmc *aspeed_kcs_probe_of_v1(struct platform_device *pdev)
+static int aspeed_kcs_of_v1_get_channel(struct platform_device *pdev)
{
- struct aspeed_kcs_bmc *priv;
struct device_node *np;
- struct kcs_bmc *kcs;
u32 channel;
- u32 slave;
int rc;
np = pdev->dev.of_node;
@@ -245,166 +486,213 @@ static struct kcs_bmc *aspeed_kcs_probe_of_v1(struct platform_device *pdev)
rc = of_property_read_u32(np, "kcs_chan", &channel);
if ((rc != 0) || (channel == 0 || channel > KCS_CHANNEL_MAX)) {
dev_err(&pdev->dev, "no valid 'kcs_chan' configured\n");
- return ERR_PTR(-EINVAL);
- }
-
- kcs = kcs_bmc_alloc(&pdev->dev, sizeof(struct aspeed_kcs_bmc), channel);
- if (!kcs)
- return ERR_PTR(-ENOMEM);
-
- priv = kcs_bmc_priv(kcs);
- priv->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
- if (IS_ERR(priv->map)) {
- dev_err(&pdev->dev, "Couldn't get regmap\n");
- return ERR_PTR(-ENODEV);
- }
-
- rc = of_property_read_u32(np, "kcs_addr", &slave);
- if (rc) {
- dev_err(&pdev->dev, "no valid 'kcs_addr' configured\n");
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
- kcs->ioreg = ast_kcs_bmc_ioregs[channel - 1];
- aspeed_kcs_set_address(kcs, slave);
-
- return kcs;
+ return channel;
}
-static int aspeed_kcs_calculate_channel(const struct kcs_ioreg *regs)
+static int
+aspeed_kcs_of_v1_get_io_address(struct platform_device *pdev, u32 addrs[2])
{
- int i;
+ int rc;
- for (i = 0; i < ARRAY_SIZE(ast_kcs_bmc_ioregs); i++) {
- if (!memcmp(&ast_kcs_bmc_ioregs[i], regs, sizeof(*regs)))
- return i + 1;
+ rc = of_property_read_u32(pdev->dev.of_node, "kcs_addr", addrs);
+ if (rc || addrs[0] > 0xffff) {
+ dev_err(&pdev->dev, "no valid 'kcs_addr' configured\n");
+ return -EINVAL;
}
- return -EINVAL;
+ return 1;
}
-static struct kcs_bmc *aspeed_kcs_probe_of_v2(struct platform_device *pdev)
+static int aspeed_kcs_of_v2_get_channel(struct platform_device *pdev)
{
- struct aspeed_kcs_bmc *priv;
struct device_node *np;
struct kcs_ioreg ioreg;
- struct kcs_bmc *kcs;
const __be32 *reg;
- int channel;
- u32 slave;
- int rc;
+ int i;
np = pdev->dev.of_node;
/* Don't translate addresses, we want offsets for the regmaps */
reg = of_get_address(np, 0, NULL, NULL);
if (!reg)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
ioreg.idr = be32_to_cpup(reg);
reg = of_get_address(np, 1, NULL, NULL);
if (!reg)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
ioreg.odr = be32_to_cpup(reg);
reg = of_get_address(np, 2, NULL, NULL);
if (!reg)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
ioreg.str = be32_to_cpup(reg);
- channel = aspeed_kcs_calculate_channel(&ioreg);
- if (channel < 0)
- return ERR_PTR(channel);
+ for (i = 0; i < ARRAY_SIZE(ast_kcs_bmc_ioregs); i++) {
+ if (!memcmp(&ast_kcs_bmc_ioregs[i], &ioreg, sizeof(ioreg)))
+ return i + 1;
+ }
- kcs = kcs_bmc_alloc(&pdev->dev, sizeof(struct aspeed_kcs_bmc), channel);
- if (!kcs)
- return ERR_PTR(-ENOMEM);
+ return -EINVAL;
+}
- kcs->ioreg = ioreg;
+static int
+aspeed_kcs_of_v2_get_io_address(struct platform_device *pdev, u32 addrs[2])
+{
+ int rc;
- priv = kcs_bmc_priv(kcs);
- priv->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
- if (IS_ERR(priv->map)) {
- dev_err(&pdev->dev, "Couldn't get regmap\n");
- return ERR_PTR(-ENODEV);
+ rc = of_property_read_variable_u32_array(pdev->dev.of_node,
+ "aspeed,lpc-io-reg",
+ addrs, 1, 2);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "No valid 'aspeed,lpc-io-reg' configured\n");
+ return rc;
}
- rc = of_property_read_u32(np, "aspeed,lpc-io-reg", &slave);
- if (rc)
- return ERR_PTR(rc);
+ if (addrs[0] > 0xffff) {
+ dev_err(&pdev->dev, "Invalid data address in 'aspeed,lpc-io-reg'\n");
+ return -EINVAL;
+ }
- aspeed_kcs_set_address(kcs, slave);
+ if (rc == 2 && addrs[1] > 0xffff) {
+ dev_err(&pdev->dev, "Invalid status address in 'aspeed,lpc-io-reg'\n");
+ return -EINVAL;
+ }
- return kcs;
+ return rc;
}
static int aspeed_kcs_probe(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct kcs_bmc *kcs_bmc;
+ const struct aspeed_kcs_of_ops *ops;
+ struct kcs_bmc_device *kcs_bmc;
+ struct aspeed_kcs_bmc *priv;
struct device_node *np;
- int rc;
+ bool have_upstream_irq;
+ u32 upstream_irq[2];
+ int rc, channel;
+ int nr_addrs;
+ u32 addrs[2];
- np = dev->of_node->parent;
+ np = pdev->dev.of_node->parent;
if (!of_device_is_compatible(np, "aspeed,ast2400-lpc-v2") &&
!of_device_is_compatible(np, "aspeed,ast2500-lpc-v2") &&
!of_device_is_compatible(np, "aspeed,ast2600-lpc-v2")) {
- dev_err(dev, "unsupported LPC device binding\n");
+ dev_err(&pdev->dev, "unsupported LPC device binding\n");
return -ENODEV;
}
- np = dev->of_node;
- if (of_device_is_compatible(np, "aspeed,ast2400-kcs-bmc") ||
- of_device_is_compatible(np, "aspeed,ast2500-kcs-bmc"))
- kcs_bmc = aspeed_kcs_probe_of_v1(pdev);
- else if (of_device_is_compatible(np, "aspeed,ast2400-kcs-bmc-v2") ||
- of_device_is_compatible(np, "aspeed,ast2500-kcs-bmc-v2"))
- kcs_bmc = aspeed_kcs_probe_of_v2(pdev);
- else
+ ops = of_device_get_match_data(&pdev->dev);
+ if (!ops)
return -EINVAL;
- if (IS_ERR(kcs_bmc))
- return PTR_ERR(kcs_bmc);
+ channel = ops->get_channel(pdev);
+ if (channel < 0)
+ return channel;
- kcs_bmc->io_inputb = aspeed_kcs_inb;
- kcs_bmc->io_outputb = aspeed_kcs_outb;
+ nr_addrs = ops->get_io_address(pdev, addrs);
+ if (nr_addrs < 0)
+ return nr_addrs;
- rc = aspeed_kcs_config_irq(kcs_bmc, pdev);
+ np = pdev->dev.of_node;
+ rc = of_property_read_u32_array(np, "aspeed,lpc-interrupts", upstream_irq, 2);
+ if (rc && rc != -EINVAL)
+ return -EINVAL;
+
+ have_upstream_irq = !rc;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ kcs_bmc = &priv->kcs_bmc;
+ kcs_bmc->dev = &pdev->dev;
+ kcs_bmc->channel = channel;
+ kcs_bmc->ioreg = ast_kcs_bmc_ioregs[channel - 1];
+ kcs_bmc->ops = &aspeed_kcs_ops;
+
+ priv->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
+ if (IS_ERR(priv->map)) {
+ dev_err(&pdev->dev, "Couldn't get regmap\n");
+ return -ENODEV;
+ }
+
+ spin_lock_init(&priv->obe.lock);
+ priv->obe.remove = false;
+ timer_setup(&priv->obe.timer, aspeed_kcs_check_obe, 0);
+
+ rc = aspeed_kcs_set_address(kcs_bmc, addrs, nr_addrs);
if (rc)
return rc;
- dev_set_drvdata(dev, kcs_bmc);
+ /* Host to BMC IRQ */
+ rc = aspeed_kcs_config_downstream_irq(kcs_bmc, pdev);
+ if (rc)
+ return rc;
+
+ /* BMC to Host IRQ */
+ if (have_upstream_irq) {
+ rc = aspeed_kcs_config_upstream_irq(priv, upstream_irq[0], upstream_irq[1]);
+ if (rc < 0)
+ return rc;
+ } else {
+ priv->upstream_irq.mode = aspeed_kcs_irq_none;
+ }
+
+ platform_set_drvdata(pdev, priv);
+ aspeed_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0);
aspeed_kcs_enable_channel(kcs_bmc, true);
- rc = misc_register(&kcs_bmc->miscdev);
+ rc = kcs_bmc_add_device(&priv->kcs_bmc);
if (rc) {
- dev_err(dev, "Unable to register device\n");
+ dev_warn(&pdev->dev, "Failed to register channel %d: %d\n", kcs_bmc->channel, rc);
return rc;
}
- dev_dbg(&pdev->dev,
- "Probed KCS device %d (IDR=0x%x, ODR=0x%x, STR=0x%x)\n",
- kcs_bmc->channel, kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr,
- kcs_bmc->ioreg.str);
+ dev_info(&pdev->dev, "Initialised channel %d at 0x%x\n",
+ kcs_bmc->channel, addrs[0]);
return 0;
}
static int aspeed_kcs_remove(struct platform_device *pdev)
{
- struct kcs_bmc *kcs_bmc = dev_get_drvdata(&pdev->dev);
+ struct aspeed_kcs_bmc *priv = platform_get_drvdata(pdev);
+ struct kcs_bmc_device *kcs_bmc = &priv->kcs_bmc;
+
+ kcs_bmc_remove_device(kcs_bmc);
- misc_deregister(&kcs_bmc->miscdev);
+ aspeed_kcs_enable_channel(kcs_bmc, false);
+ aspeed_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0);
+
+ /* Make sure it's proper dead */
+ spin_lock_irq(&priv->obe.lock);
+ priv->obe.remove = true;
+ spin_unlock_irq(&priv->obe.lock);
+ del_timer_sync(&priv->obe.timer);
return 0;
}
+static const struct aspeed_kcs_of_ops of_v1_ops = {
+ .get_channel = aspeed_kcs_of_v1_get_channel,
+ .get_io_address = aspeed_kcs_of_v1_get_io_address,
+};
+
+static const struct aspeed_kcs_of_ops of_v2_ops = {
+ .get_channel = aspeed_kcs_of_v2_get_channel,
+ .get_io_address = aspeed_kcs_of_v2_get_io_address,
+};
+
static const struct of_device_id ast_kcs_bmc_match[] = {
- { .compatible = "aspeed,ast2400-kcs-bmc" },
- { .compatible = "aspeed,ast2500-kcs-bmc" },
- { .compatible = "aspeed,ast2400-kcs-bmc-v2" },
- { .compatible = "aspeed,ast2500-kcs-bmc-v2" },
+ { .compatible = "aspeed,ast2400-kcs-bmc", .data = &of_v1_ops },
+ { .compatible = "aspeed,ast2500-kcs-bmc", .data = &of_v1_ops },
+ { .compatible = "aspeed,ast2400-kcs-bmc-v2", .data = &of_v2_ops },
+ { .compatible = "aspeed,ast2500-kcs-bmc-v2", .data = &of_v2_ops },
{ }
};
MODULE_DEVICE_TABLE(of, ast_kcs_bmc_match);
@@ -421,4 +709,5 @@ module_platform_driver(ast_kcs_bmc_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
+MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
MODULE_DESCRIPTION("Aspeed device interface to the KCS BMC device");
diff --git a/drivers/char/ipmi/kcs_bmc_cdev_ipmi.c b/drivers/char/ipmi/kcs_bmc_cdev_ipmi.c
new file mode 100644
index 000000000000..486834a962c3
--- /dev/null
+++ b/drivers/char/ipmi/kcs_bmc_cdev_ipmi.c
@@ -0,0 +1,568 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2015-2018, Intel Corporation.
+ */
+
+#define pr_fmt(fmt) "kcs-bmc: " fmt
+
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/ipmi_bmc.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "kcs_bmc_client.h"
+
+/* Different phases of the KCS BMC module.
+ * KCS_PHASE_IDLE:
+ * BMC should not be expecting nor sending any data.
+ * KCS_PHASE_WRITE_START:
+ * BMC is receiving a WRITE_START command from system software.
+ * KCS_PHASE_WRITE_DATA:
+ * BMC is receiving a data byte from system software.
+ * KCS_PHASE_WRITE_END_CMD:
+ * BMC is waiting a last data byte from system software.
+ * KCS_PHASE_WRITE_DONE:
+ * BMC has received the whole request from system software.
+ * KCS_PHASE_WAIT_READ:
+ * BMC is waiting the response from the upper IPMI service.
+ * KCS_PHASE_READ:
+ * BMC is transferring the response to system software.
+ * KCS_PHASE_ABORT_ERROR1:
+ * BMC is waiting error status request from system software.
+ * KCS_PHASE_ABORT_ERROR2:
+ * BMC is waiting for idle status afer error from system software.
+ * KCS_PHASE_ERROR:
+ * BMC has detected a protocol violation at the interface level.
+ */
+enum kcs_ipmi_phases {
+ KCS_PHASE_IDLE,
+
+ KCS_PHASE_WRITE_START,
+ KCS_PHASE_WRITE_DATA,
+ KCS_PHASE_WRITE_END_CMD,
+ KCS_PHASE_WRITE_DONE,
+
+ KCS_PHASE_WAIT_READ,
+ KCS_PHASE_READ,
+
+ KCS_PHASE_ABORT_ERROR1,
+ KCS_PHASE_ABORT_ERROR2,
+ KCS_PHASE_ERROR
+};
+
+/* IPMI 2.0 - Table 9-4, KCS Interface Status Codes */
+enum kcs_ipmi_errors {
+ KCS_NO_ERROR = 0x00,
+ KCS_ABORTED_BY_COMMAND = 0x01,
+ KCS_ILLEGAL_CONTROL_CODE = 0x02,
+ KCS_LENGTH_ERROR = 0x06,
+ KCS_UNSPECIFIED_ERROR = 0xFF
+};
+
+struct kcs_bmc_ipmi {
+ struct list_head entry;
+
+ struct kcs_bmc_client client;
+
+ spinlock_t lock;
+
+ enum kcs_ipmi_phases phase;
+ enum kcs_ipmi_errors error;
+
+ wait_queue_head_t queue;
+ bool data_in_avail;
+ int data_in_idx;
+ u8 *data_in;
+
+ int data_out_idx;
+ int data_out_len;
+ u8 *data_out;
+
+ struct mutex mutex;
+ u8 *kbuffer;
+
+ struct miscdevice miscdev;
+};
+
+#define DEVICE_NAME "ipmi-kcs"
+
+#define KCS_MSG_BUFSIZ 1000
+
+#define KCS_ZERO_DATA 0
+
+/* IPMI 2.0 - Table 9-1, KCS Interface Status Register Bits */
+#define KCS_STATUS_STATE(state) (state << 6)
+#define KCS_STATUS_STATE_MASK GENMASK(7, 6)
+#define KCS_STATUS_CMD_DAT BIT(3)
+#define KCS_STATUS_SMS_ATN BIT(2)
+#define KCS_STATUS_IBF BIT(1)
+#define KCS_STATUS_OBF BIT(0)
+
+/* IPMI 2.0 - Table 9-2, KCS Interface State Bits */
+enum kcs_states {
+ IDLE_STATE = 0,
+ READ_STATE = 1,
+ WRITE_STATE = 2,
+ ERROR_STATE = 3,
+};
+
+/* IPMI 2.0 - Table 9-3, KCS Interface Control Codes */
+#define KCS_CMD_GET_STATUS_ABORT 0x60
+#define KCS_CMD_WRITE_START 0x61
+#define KCS_CMD_WRITE_END 0x62
+#define KCS_CMD_READ_BYTE 0x68
+
+static inline void set_state(struct kcs_bmc_ipmi *priv, u8 state)
+{
+ kcs_bmc_update_status(priv->client.dev, KCS_STATUS_STATE_MASK, KCS_STATUS_STATE(state));
+}
+
+static void kcs_bmc_ipmi_force_abort(struct kcs_bmc_ipmi *priv)
+{
+ set_state(priv, ERROR_STATE);
+ kcs_bmc_read_data(priv->client.dev);
+ kcs_bmc_write_data(priv->client.dev, KCS_ZERO_DATA);
+
+ priv->phase = KCS_PHASE_ERROR;
+ priv->data_in_avail = false;
+ priv->data_in_idx = 0;
+}
+
+static void kcs_bmc_ipmi_handle_data(struct kcs_bmc_ipmi *priv)
+{
+ struct kcs_bmc_device *dev;
+ u8 data;
+
+ dev = priv->client.dev;
+
+ switch (priv->phase) {
+ case KCS_PHASE_WRITE_START:
+ priv->phase = KCS_PHASE_WRITE_DATA;
+ fallthrough;
+
+ case KCS_PHASE_WRITE_DATA:
+ if (priv->data_in_idx < KCS_MSG_BUFSIZ) {
+ set_state(priv, WRITE_STATE);
+ kcs_bmc_write_data(dev, KCS_ZERO_DATA);
+ priv->data_in[priv->data_in_idx++] = kcs_bmc_read_data(dev);
+ } else {
+ kcs_bmc_ipmi_force_abort(priv);
+ priv->error = KCS_LENGTH_ERROR;
+ }
+ break;
+
+ case KCS_PHASE_WRITE_END_CMD:
+ if (priv->data_in_idx < KCS_MSG_BUFSIZ) {
+ set_state(priv, READ_STATE);
+ priv->data_in[priv->data_in_idx++] = kcs_bmc_read_data(dev);
+ priv->phase = KCS_PHASE_WRITE_DONE;
+ priv->data_in_avail = true;
+ wake_up_interruptible(&priv->queue);
+ } else {
+ kcs_bmc_ipmi_force_abort(priv);
+ priv->error = KCS_LENGTH_ERROR;
+ }
+ break;
+
+ case KCS_PHASE_READ:
+ if (priv->data_out_idx == priv->data_out_len)
+ set_state(priv, IDLE_STATE);
+
+ data = kcs_bmc_read_data(dev);
+ if (data != KCS_CMD_READ_BYTE) {
+ set_state(priv, ERROR_STATE);
+ kcs_bmc_write_data(dev, KCS_ZERO_DATA);
+ break;
+ }
+
+ if (priv->data_out_idx == priv->data_out_len) {
+ kcs_bmc_write_data(dev, KCS_ZERO_DATA);
+ priv->phase = KCS_PHASE_IDLE;
+ break;
+ }
+
+ kcs_bmc_write_data(dev, priv->data_out[priv->data_out_idx++]);
+ break;
+
+ case KCS_PHASE_ABORT_ERROR1:
+ set_state(priv, READ_STATE);
+ kcs_bmc_read_data(dev);
+ kcs_bmc_write_data(dev, priv->error);
+ priv->phase = KCS_PHASE_ABORT_ERROR2;
+ break;
+
+ case KCS_PHASE_ABORT_ERROR2:
+ set_state(priv, IDLE_STATE);
+ kcs_bmc_read_data(dev);
+ kcs_bmc_write_data(dev, KCS_ZERO_DATA);
+ priv->phase = KCS_PHASE_IDLE;
+ break;
+
+ default:
+ kcs_bmc_ipmi_force_abort(priv);
+ break;
+ }
+}
+
+static void kcs_bmc_ipmi_handle_cmd(struct kcs_bmc_ipmi *priv)
+{
+ u8 cmd;
+
+ set_state(priv, WRITE_STATE);
+ kcs_bmc_write_data(priv->client.dev, KCS_ZERO_DATA);
+
+ cmd = kcs_bmc_read_data(priv->client.dev);
+ switch (cmd) {
+ case KCS_CMD_WRITE_START:
+ priv->phase = KCS_PHASE_WRITE_START;
+ priv->error = KCS_NO_ERROR;
+ priv->data_in_avail = false;
+ priv->data_in_idx = 0;
+ break;
+
+ case KCS_CMD_WRITE_END:
+ if (priv->phase != KCS_PHASE_WRITE_DATA) {
+ kcs_bmc_ipmi_force_abort(priv);
+ break;
+ }
+
+ priv->phase = KCS_PHASE_WRITE_END_CMD;
+ break;
+
+ case KCS_CMD_GET_STATUS_ABORT:
+ if (priv->error == KCS_NO_ERROR)
+ priv->error = KCS_ABORTED_BY_COMMAND;
+
+ priv->phase = KCS_PHASE_ABORT_ERROR1;
+ priv->data_in_avail = false;
+ priv->data_in_idx = 0;
+ break;
+
+ default:
+ kcs_bmc_ipmi_force_abort(priv);
+ priv->error = KCS_ILLEGAL_CONTROL_CODE;
+ break;
+ }
+}
+
+static inline struct kcs_bmc_ipmi *client_to_kcs_bmc_ipmi(struct kcs_bmc_client *client)
+{
+ return container_of(client, struct kcs_bmc_ipmi, client);
+}
+
+static irqreturn_t kcs_bmc_ipmi_event(struct kcs_bmc_client *client)
+{
+ struct kcs_bmc_ipmi *priv;
+ u8 status;
+ int ret;
+
+ priv = client_to_kcs_bmc_ipmi(client);
+ if (!priv)
+ return IRQ_NONE;
+
+ spin_lock(&priv->lock);
+
+ status = kcs_bmc_read_status(client->dev);
+ if (status & KCS_STATUS_IBF) {
+ if (status & KCS_STATUS_CMD_DAT)
+ kcs_bmc_ipmi_handle_cmd(priv);
+ else
+ kcs_bmc_ipmi_handle_data(priv);
+
+ ret = IRQ_HANDLED;
+ } else {
+ ret = IRQ_NONE;
+ }
+
+ spin_unlock(&priv->lock);
+
+ return ret;
+}
+
+static const struct kcs_bmc_client_ops kcs_bmc_ipmi_client_ops = {
+ .event = kcs_bmc_ipmi_event,
+};
+
+static inline struct kcs_bmc_ipmi *to_kcs_bmc(struct file *filp)
+{
+ return container_of(filp->private_data, struct kcs_bmc_ipmi, miscdev);
+}
+
+static int kcs_bmc_ipmi_open(struct inode *inode, struct file *filp)
+{
+ struct kcs_bmc_ipmi *priv = to_kcs_bmc(filp);
+
+ return kcs_bmc_enable_device(priv->client.dev, &priv->client);
+}
+
+static __poll_t kcs_bmc_ipmi_poll(struct file *filp, poll_table *wait)
+{
+ struct kcs_bmc_ipmi *priv = to_kcs_bmc(filp);
+ __poll_t mask = 0;
+
+ poll_wait(filp, &priv->queue, wait);
+
+ spin_lock_irq(&priv->lock);
+ if (priv->data_in_avail)
+ mask |= EPOLLIN;
+ spin_unlock_irq(&priv->lock);
+
+ return mask;
+}
+
+static ssize_t kcs_bmc_ipmi_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct kcs_bmc_ipmi *priv = to_kcs_bmc(filp);
+ bool data_avail;
+ size_t data_len;
+ ssize_t ret;
+
+ if (!(filp->f_flags & O_NONBLOCK))
+ wait_event_interruptible(priv->queue,
+ priv->data_in_avail);
+
+ mutex_lock(&priv->mutex);
+
+ spin_lock_irq(&priv->lock);
+ data_avail = priv->data_in_avail;
+ if (data_avail) {
+ data_len = priv->data_in_idx;
+ memcpy(priv->kbuffer, priv->data_in, data_len);
+ }
+ spin_unlock_irq(&priv->lock);
+
+ if (!data_avail) {
+ ret = -EAGAIN;
+ goto out_unlock;
+ }
+
+ if (count < data_len) {
+ pr_err("channel=%u with too large data : %zu\n",
+ priv->client.dev->channel, data_len);
+
+ spin_lock_irq(&priv->lock);
+ kcs_bmc_ipmi_force_abort(priv);
+ spin_unlock_irq(&priv->lock);
+
+ ret = -EOVERFLOW;
+ goto out_unlock;
+ }
+
+ if (copy_to_user(buf, priv->kbuffer, data_len)) {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+
+ ret = data_len;
+
+ spin_lock_irq(&priv->lock);
+ if (priv->phase == KCS_PHASE_WRITE_DONE) {
+ priv->phase = KCS_PHASE_WAIT_READ;
+ priv->data_in_avail = false;
+ priv->data_in_idx = 0;
+ } else {
+ ret = -EAGAIN;
+ }
+ spin_unlock_irq(&priv->lock);
+
+out_unlock:
+ mutex_unlock(&priv->mutex);
+
+ return ret;
+}
+
+static ssize_t kcs_bmc_ipmi_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct kcs_bmc_ipmi *priv = to_kcs_bmc(filp);
+ ssize_t ret;
+
+ /* a minimum response size '3' : netfn + cmd + ccode */
+ if (count < 3 || count > KCS_MSG_BUFSIZ)
+ return -EINVAL;
+
+ mutex_lock(&priv->mutex);
+
+ if (copy_from_user(priv->kbuffer, buf, count)) {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+
+ spin_lock_irq(&priv->lock);
+ if (priv->phase == KCS_PHASE_WAIT_READ) {
+ priv->phase = KCS_PHASE_READ;
+ priv->data_out_idx = 1;
+ priv->data_out_len = count;
+ memcpy(priv->data_out, priv->kbuffer, count);
+ kcs_bmc_write_data(priv->client.dev, priv->data_out[0]);
+ ret = count;
+ } else {
+ ret = -EINVAL;
+ }
+ spin_unlock_irq(&priv->lock);
+
+out_unlock:
+ mutex_unlock(&priv->mutex);
+
+ return ret;
+}
+
+static long kcs_bmc_ipmi_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct kcs_bmc_ipmi *priv = to_kcs_bmc(filp);
+ long ret = 0;
+
+ spin_lock_irq(&priv->lock);
+
+ switch (cmd) {
+ case IPMI_BMC_IOCTL_SET_SMS_ATN:
+ kcs_bmc_update_status(priv->client.dev, KCS_STATUS_SMS_ATN, KCS_STATUS_SMS_ATN);
+ break;
+
+ case IPMI_BMC_IOCTL_CLEAR_SMS_ATN:
+ kcs_bmc_update_status(priv->client.dev, KCS_STATUS_SMS_ATN, 0);
+ break;
+
+ case IPMI_BMC_IOCTL_FORCE_ABORT:
+ kcs_bmc_ipmi_force_abort(priv);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ spin_unlock_irq(&priv->lock);
+
+ return ret;
+}
+
+static int kcs_bmc_ipmi_release(struct inode *inode, struct file *filp)
+{
+ struct kcs_bmc_ipmi *priv = to_kcs_bmc(filp);
+
+ kcs_bmc_ipmi_force_abort(priv);
+ kcs_bmc_disable_device(priv->client.dev, &priv->client);
+
+ return 0;
+}
+
+static const struct file_operations kcs_bmc_ipmi_fops = {
+ .owner = THIS_MODULE,
+ .open = kcs_bmc_ipmi_open,
+ .read = kcs_bmc_ipmi_read,
+ .write = kcs_bmc_ipmi_write,
+ .release = kcs_bmc_ipmi_release,
+ .poll = kcs_bmc_ipmi_poll,
+ .unlocked_ioctl = kcs_bmc_ipmi_ioctl,
+};
+
+static DEFINE_SPINLOCK(kcs_bmc_ipmi_instances_lock);
+static LIST_HEAD(kcs_bmc_ipmi_instances);
+
+static int kcs_bmc_ipmi_add_device(struct kcs_bmc_device *kcs_bmc)
+{
+ struct kcs_bmc_ipmi *priv;
+ int rc;
+
+ priv = devm_kzalloc(kcs_bmc->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ spin_lock_init(&priv->lock);
+ mutex_init(&priv->mutex);
+
+ init_waitqueue_head(&priv->queue);
+
+ priv->client.dev = kcs_bmc;
+ priv->client.ops = &kcs_bmc_ipmi_client_ops;
+ priv->data_in = devm_kmalloc(kcs_bmc->dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
+ priv->data_out = devm_kmalloc(kcs_bmc->dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
+ priv->kbuffer = devm_kmalloc(kcs_bmc->dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
+
+ priv->miscdev.minor = MISC_DYNAMIC_MINOR;
+ priv->miscdev.name = devm_kasprintf(kcs_bmc->dev, GFP_KERNEL, "%s%u", DEVICE_NAME,
+ kcs_bmc->channel);
+ if (!priv->data_in || !priv->data_out || !priv->kbuffer || !priv->miscdev.name)
+ return -EINVAL;
+
+ priv->miscdev.fops = &kcs_bmc_ipmi_fops;
+
+ rc = misc_register(&priv->miscdev);
+ if (rc) {
+ dev_err(kcs_bmc->dev, "Unable to register device: %d\n", rc);
+ return rc;
+ }
+
+ spin_lock_irq(&kcs_bmc_ipmi_instances_lock);
+ list_add(&priv->entry, &kcs_bmc_ipmi_instances);
+ spin_unlock_irq(&kcs_bmc_ipmi_instances_lock);
+
+ dev_info(kcs_bmc->dev, "Initialised IPMI client for channel %d", kcs_bmc->channel);
+
+ return 0;
+}
+
+static int kcs_bmc_ipmi_remove_device(struct kcs_bmc_device *kcs_bmc)
+{
+ struct kcs_bmc_ipmi *priv = NULL, *pos;
+
+ spin_lock_irq(&kcs_bmc_ipmi_instances_lock);
+ list_for_each_entry(pos, &kcs_bmc_ipmi_instances, entry) {
+ if (pos->client.dev == kcs_bmc) {
+ priv = pos;
+ list_del(&pos->entry);
+ break;
+ }
+ }
+ spin_unlock_irq(&kcs_bmc_ipmi_instances_lock);
+
+ if (!priv)
+ return -ENODEV;
+
+ misc_deregister(&priv->miscdev);
+ kcs_bmc_disable_device(priv->client.dev, &priv->client);
+ devm_kfree(kcs_bmc->dev, priv->kbuffer);
+ devm_kfree(kcs_bmc->dev, priv->data_out);
+ devm_kfree(kcs_bmc->dev, priv->data_in);
+ devm_kfree(kcs_bmc->dev, priv);
+
+ return 0;
+}
+
+static const struct kcs_bmc_driver_ops kcs_bmc_ipmi_driver_ops = {
+ .add_device = kcs_bmc_ipmi_add_device,
+ .remove_device = kcs_bmc_ipmi_remove_device,
+};
+
+static struct kcs_bmc_driver kcs_bmc_ipmi_driver = {
+ .ops = &kcs_bmc_ipmi_driver_ops,
+};
+
+static int kcs_bmc_ipmi_init(void)
+{
+ kcs_bmc_register_driver(&kcs_bmc_ipmi_driver);
+
+ return 0;
+}
+module_init(kcs_bmc_ipmi_init);
+
+static void kcs_bmc_ipmi_exit(void)
+{
+ kcs_bmc_unregister_driver(&kcs_bmc_ipmi_driver);
+}
+module_exit(kcs_bmc_ipmi_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
+MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
+MODULE_DESCRIPTION("KCS BMC to handle the IPMI request from system software");
diff --git a/drivers/char/ipmi/kcs_bmc_client.h b/drivers/char/ipmi/kcs_bmc_client.h
new file mode 100644
index 000000000000..6fdcde0a7169
--- /dev/null
+++ b/drivers/char/ipmi/kcs_bmc_client.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2021, IBM Corp. */
+
+#ifndef __KCS_BMC_CONSUMER_H__
+#define __KCS_BMC_CONSUMER_H__
+
+#include <linux/irqreturn.h>
+
+#include "kcs_bmc.h"
+
+struct kcs_bmc_driver_ops {
+ int (*add_device)(struct kcs_bmc_device *kcs_bmc);
+ int (*remove_device)(struct kcs_bmc_device *kcs_bmc);
+};
+
+struct kcs_bmc_driver {
+ struct list_head entry;
+
+ const struct kcs_bmc_driver_ops *ops;
+};
+
+struct kcs_bmc_client_ops {
+ irqreturn_t (*event)(struct kcs_bmc_client *client);
+};
+
+struct kcs_bmc_client {
+ const struct kcs_bmc_client_ops *ops;
+
+ struct kcs_bmc_device *dev;
+};
+
+void kcs_bmc_register_driver(struct kcs_bmc_driver *drv);
+void kcs_bmc_unregister_driver(struct kcs_bmc_driver *drv);
+
+int kcs_bmc_enable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client);
+void kcs_bmc_disable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client);
+
+void kcs_bmc_update_event_mask(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 events);
+
+u8 kcs_bmc_read_data(struct kcs_bmc_device *kcs_bmc);
+void kcs_bmc_write_data(struct kcs_bmc_device *kcs_bmc, u8 data);
+u8 kcs_bmc_read_status(struct kcs_bmc_device *kcs_bmc);
+void kcs_bmc_write_status(struct kcs_bmc_device *kcs_bmc, u8 data);
+void kcs_bmc_update_status(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 val);
+#endif
diff --git a/drivers/char/ipmi/kcs_bmc_device.h b/drivers/char/ipmi/kcs_bmc_device.h
new file mode 100644
index 000000000000..17c572f25c54
--- /dev/null
+++ b/drivers/char/ipmi/kcs_bmc_device.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2021, IBM Corp. */
+
+#ifndef __KCS_BMC_DEVICE_H__
+#define __KCS_BMC_DEVICE_H__
+
+#include <linux/irqreturn.h>
+
+#include "kcs_bmc.h"
+
+struct kcs_bmc_device_ops {
+ void (*irq_mask_update)(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 enable);
+ u8 (*io_inputb)(struct kcs_bmc_device *kcs_bmc, u32 reg);
+ void (*io_outputb)(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 b);
+ void (*io_updateb)(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 mask, u8 b);
+};
+
+irqreturn_t kcs_bmc_handle_event(struct kcs_bmc_device *kcs_bmc);
+int kcs_bmc_add_device(struct kcs_bmc_device *kcs_bmc);
+void kcs_bmc_remove_device(struct kcs_bmc_device *kcs_bmc);
+
+#endif
diff --git a/drivers/char/ipmi/kcs_bmc_npcm7xx.c b/drivers/char/ipmi/kcs_bmc_npcm7xx.c
index 722f7391fe1f..7961fec56476 100644
--- a/drivers/char/ipmi/kcs_bmc_npcm7xx.c
+++ b/drivers/char/ipmi/kcs_bmc_npcm7xx.c
@@ -17,7 +17,7 @@
#include <linux/regmap.h>
#include <linux/slab.h>
-#include "kcs_bmc.h"
+#include "kcs_bmc_device.h"
#define DEVICE_NAME "npcm-kcs-bmc"
#define KCS_CHANNEL_MAX 3
@@ -38,6 +38,7 @@
#define KCS2CTL 0x2A
#define KCS3CTL 0x3C
#define KCS_CTL_IBFIE BIT(0)
+#define KCS_CTL_OBEIE BIT(1)
#define KCS1IE 0x1C
#define KCS2IE 0x2E
@@ -65,6 +66,8 @@ struct npcm7xx_kcs_reg {
};
struct npcm7xx_kcs_bmc {
+ struct kcs_bmc_device kcs_bmc;
+
struct regmap *map;
const struct npcm7xx_kcs_reg *reg;
@@ -76,9 +79,14 @@ static const struct npcm7xx_kcs_reg npcm7xx_kcs_reg_tbl[KCS_CHANNEL_MAX] = {
{ .sts = KCS3ST, .dob = KCS3DO, .dib = KCS3DI, .ctl = KCS3CTL, .ie = KCS3IE },
};
-static u8 npcm7xx_kcs_inb(struct kcs_bmc *kcs_bmc, u32 reg)
+static inline struct npcm7xx_kcs_bmc *to_npcm7xx_kcs_bmc(struct kcs_bmc_device *kcs_bmc)
{
- struct npcm7xx_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
+ return container_of(kcs_bmc, struct npcm7xx_kcs_bmc, kcs_bmc);
+}
+
+static u8 npcm7xx_kcs_inb(struct kcs_bmc_device *kcs_bmc, u32 reg)
+{
+ struct npcm7xx_kcs_bmc *priv = to_npcm7xx_kcs_bmc(kcs_bmc);
u32 val = 0;
int rc;
@@ -88,37 +96,53 @@ static u8 npcm7xx_kcs_inb(struct kcs_bmc *kcs_bmc, u32 reg)
return rc == 0 ? (u8)val : 0;
}
-static void npcm7xx_kcs_outb(struct kcs_bmc *kcs_bmc, u32 reg, u8 data)
+static void npcm7xx_kcs_outb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 data)
{
- struct npcm7xx_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
+ struct npcm7xx_kcs_bmc *priv = to_npcm7xx_kcs_bmc(kcs_bmc);
int rc;
rc = regmap_write(priv->map, reg, data);
WARN(rc != 0, "regmap_write() failed: %d\n", rc);
}
-static void npcm7xx_kcs_enable_channel(struct kcs_bmc *kcs_bmc, bool enable)
+static void npcm7xx_kcs_updateb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 mask, u8 data)
{
- struct npcm7xx_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
+ struct npcm7xx_kcs_bmc *priv = to_npcm7xx_kcs_bmc(kcs_bmc);
+ int rc;
- regmap_update_bits(priv->map, priv->reg->ctl, KCS_CTL_IBFIE,
- enable ? KCS_CTL_IBFIE : 0);
+ rc = regmap_update_bits(priv->map, reg, mask, data);
+ WARN(rc != 0, "regmap_update_bits() failed: %d\n", rc);
+}
+
+static void npcm7xx_kcs_enable_channel(struct kcs_bmc_device *kcs_bmc, bool enable)
+{
+ struct npcm7xx_kcs_bmc *priv = to_npcm7xx_kcs_bmc(kcs_bmc);
regmap_update_bits(priv->map, priv->reg->ie, KCS_IE_IRQE | KCS_IE_HIRQE,
enable ? KCS_IE_IRQE | KCS_IE_HIRQE : 0);
}
-static irqreturn_t npcm7xx_kcs_irq(int irq, void *arg)
+static void npcm7xx_kcs_irq_mask_update(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 state)
{
- struct kcs_bmc *kcs_bmc = arg;
+ struct npcm7xx_kcs_bmc *priv = to_npcm7xx_kcs_bmc(kcs_bmc);
+
+ if (mask & KCS_BMC_EVENT_TYPE_OBE)
+ regmap_update_bits(priv->map, priv->reg->ctl, KCS_CTL_OBEIE,
+ !!(state & KCS_BMC_EVENT_TYPE_OBE) * KCS_CTL_OBEIE);
- if (!kcs_bmc_handle_event(kcs_bmc))
- return IRQ_HANDLED;
+ if (mask & KCS_BMC_EVENT_TYPE_IBF)
+ regmap_update_bits(priv->map, priv->reg->ctl, KCS_CTL_IBFIE,
+ !!(state & KCS_BMC_EVENT_TYPE_IBF) * KCS_CTL_IBFIE);
+}
- return IRQ_NONE;
+static irqreturn_t npcm7xx_kcs_irq(int irq, void *arg)
+{
+ struct kcs_bmc_device *kcs_bmc = arg;
+
+ return kcs_bmc_handle_event(kcs_bmc);
}
-static int npcm7xx_kcs_config_irq(struct kcs_bmc *kcs_bmc,
+static int npcm7xx_kcs_config_irq(struct kcs_bmc_device *kcs_bmc,
struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -132,11 +156,18 @@ static int npcm7xx_kcs_config_irq(struct kcs_bmc *kcs_bmc,
dev_name(dev), kcs_bmc);
}
+static const struct kcs_bmc_device_ops npcm7xx_kcs_ops = {
+ .irq_mask_update = npcm7xx_kcs_irq_mask_update,
+ .io_inputb = npcm7xx_kcs_inb,
+ .io_outputb = npcm7xx_kcs_outb,
+ .io_updateb = npcm7xx_kcs_updateb,
+};
+
static int npcm7xx_kcs_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct npcm7xx_kcs_bmc *priv;
- struct kcs_bmc *kcs_bmc;
+ struct kcs_bmc_device *kcs_bmc;
u32 chan;
int rc;
@@ -146,11 +177,10 @@ static int npcm7xx_kcs_probe(struct platform_device *pdev)
return -ENODEV;
}
- kcs_bmc = kcs_bmc_alloc(dev, sizeof(*priv), chan);
- if (!kcs_bmc)
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- priv = kcs_bmc_priv(kcs_bmc);
priv->map = syscon_node_to_regmap(dev->parent->of_node);
if (IS_ERR(priv->map)) {
dev_err(dev, "Couldn't get regmap\n");
@@ -158,22 +188,26 @@ static int npcm7xx_kcs_probe(struct platform_device *pdev)
}
priv->reg = &npcm7xx_kcs_reg_tbl[chan - 1];
+ kcs_bmc = &priv->kcs_bmc;
+ kcs_bmc->dev = &pdev->dev;
+ kcs_bmc->channel = chan;
kcs_bmc->ioreg.idr = priv->reg->dib;
kcs_bmc->ioreg.odr = priv->reg->dob;
kcs_bmc->ioreg.str = priv->reg->sts;
- kcs_bmc->io_inputb = npcm7xx_kcs_inb;
- kcs_bmc->io_outputb = npcm7xx_kcs_outb;
+ kcs_bmc->ops = &npcm7xx_kcs_ops;
- dev_set_drvdata(dev, kcs_bmc);
+ platform_set_drvdata(pdev, priv);
- npcm7xx_kcs_enable_channel(kcs_bmc, true);
rc = npcm7xx_kcs_config_irq(kcs_bmc, pdev);
if (rc)
return rc;
- rc = misc_register(&kcs_bmc->miscdev);
+ npcm7xx_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0);
+ npcm7xx_kcs_enable_channel(kcs_bmc, true);
+
+ rc = kcs_bmc_add_device(kcs_bmc);
if (rc) {
- dev_err(dev, "Unable to register device\n");
+ dev_warn(&pdev->dev, "Failed to register channel %d: %d\n", kcs_bmc->channel, rc);
return rc;
}
@@ -186,9 +220,13 @@ static int npcm7xx_kcs_probe(struct platform_device *pdev)
static int npcm7xx_kcs_remove(struct platform_device *pdev)
{
- struct kcs_bmc *kcs_bmc = dev_get_drvdata(&pdev->dev);
+ struct npcm7xx_kcs_bmc *priv = platform_get_drvdata(pdev);
+ struct kcs_bmc_device *kcs_bmc = &priv->kcs_bmc;
+
+ kcs_bmc_remove_device(kcs_bmc);
- misc_deregister(&kcs_bmc->miscdev);
+ npcm7xx_kcs_enable_channel(kcs_bmc, false);
+ npcm7xx_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0);
return 0;
}
diff --git a/drivers/char/ipmi/kcs_bmc_serio.c b/drivers/char/ipmi/kcs_bmc_serio.c
new file mode 100644
index 000000000000..7948cabde50b
--- /dev/null
+++ b/drivers/char/ipmi/kcs_bmc_serio.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Copyright (c) 2021 IBM Corp. */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/sched/signal.h>
+#include <linux/serio.h>
+#include <linux/slab.h>
+
+#include "kcs_bmc_client.h"
+
+struct kcs_bmc_serio {
+ struct list_head entry;
+
+ struct kcs_bmc_client client;
+ struct serio *port;
+
+ spinlock_t lock;
+};
+
+static inline struct kcs_bmc_serio *client_to_kcs_bmc_serio(struct kcs_bmc_client *client)
+{
+ return container_of(client, struct kcs_bmc_serio, client);
+}
+
+static irqreturn_t kcs_bmc_serio_event(struct kcs_bmc_client *client)
+{
+ struct kcs_bmc_serio *priv;
+ u8 handled = IRQ_NONE;
+ u8 status;
+
+ priv = client_to_kcs_bmc_serio(client);
+
+ spin_lock(&priv->lock);
+
+ status = kcs_bmc_read_status(client->dev);
+
+ if (status & KCS_BMC_STR_IBF)
+ handled = serio_interrupt(priv->port, kcs_bmc_read_data(client->dev), 0);
+
+ spin_unlock(&priv->lock);
+
+ return handled;
+}
+
+static const struct kcs_bmc_client_ops kcs_bmc_serio_client_ops = {
+ .event = kcs_bmc_serio_event,
+};
+
+static int kcs_bmc_serio_open(struct serio *port)
+{
+ struct kcs_bmc_serio *priv = port->port_data;
+
+ return kcs_bmc_enable_device(priv->client.dev, &priv->client);
+}
+
+static void kcs_bmc_serio_close(struct serio *port)
+{
+ struct kcs_bmc_serio *priv = port->port_data;
+
+ kcs_bmc_disable_device(priv->client.dev, &priv->client);
+}
+
+static DEFINE_SPINLOCK(kcs_bmc_serio_instances_lock);
+static LIST_HEAD(kcs_bmc_serio_instances);
+
+static int kcs_bmc_serio_add_device(struct kcs_bmc_device *kcs_bmc)
+{
+ struct kcs_bmc_serio *priv;
+ struct serio *port;
+
+ priv = devm_kzalloc(kcs_bmc->dev, sizeof(*priv), GFP_KERNEL);
+
+ /* Use kzalloc() as the allocation is cleaned up with kfree() via serio_unregister_port() */
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!(priv && port))
+ return -ENOMEM;
+
+ port->id.type = SERIO_8042;
+ port->open = kcs_bmc_serio_open;
+ port->close = kcs_bmc_serio_close;
+ port->port_data = priv;
+ port->dev.parent = kcs_bmc->dev;
+
+ spin_lock_init(&priv->lock);
+ priv->port = port;
+ priv->client.dev = kcs_bmc;
+ priv->client.ops = &kcs_bmc_serio_client_ops;
+
+ spin_lock_irq(&kcs_bmc_serio_instances_lock);
+ list_add(&priv->entry, &kcs_bmc_serio_instances);
+ spin_unlock_irq(&kcs_bmc_serio_instances_lock);
+
+ serio_register_port(port);
+
+ dev_info(kcs_bmc->dev, "Initialised serio client for channel %d", kcs_bmc->channel);
+
+ return 0;
+}
+
+static int kcs_bmc_serio_remove_device(struct kcs_bmc_device *kcs_bmc)
+{
+ struct kcs_bmc_serio *priv = NULL, *pos;
+
+ spin_lock_irq(&kcs_bmc_serio_instances_lock);
+ list_for_each_entry(pos, &kcs_bmc_serio_instances, entry) {
+ if (pos->client.dev == kcs_bmc) {
+ priv = pos;
+ list_del(&pos->entry);
+ break;
+ }
+ }
+ spin_unlock_irq(&kcs_bmc_serio_instances_lock);
+
+ if (!priv)
+ return -ENODEV;
+
+ /* kfree()s priv->port via put_device() */
+ serio_unregister_port(priv->port);
+
+ /* Ensure the IBF IRQ is disabled if we were the active client */
+ kcs_bmc_disable_device(kcs_bmc, &priv->client);
+
+ devm_kfree(priv->client.dev->dev, priv);
+
+ return 0;
+}
+
+static const struct kcs_bmc_driver_ops kcs_bmc_serio_driver_ops = {
+ .add_device = kcs_bmc_serio_add_device,
+ .remove_device = kcs_bmc_serio_remove_device,
+};
+
+static struct kcs_bmc_driver kcs_bmc_serio_driver = {
+ .ops = &kcs_bmc_serio_driver_ops,
+};
+
+static int kcs_bmc_serio_init(void)
+{
+ kcs_bmc_register_driver(&kcs_bmc_serio_driver);
+
+ return 0;
+}
+module_init(kcs_bmc_serio_init);
+
+static void kcs_bmc_serio_exit(void)
+{
+ kcs_bmc_unregister_driver(&kcs_bmc_serio_driver);
+}
+module_exit(kcs_bmc_serio_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
+MODULE_DESCRIPTION("Adapter driver for serio access to BMC KCS devices");
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 15dc54fa1d47..1c596b5cdb27 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -16,7 +16,6 @@
#include <linux/mman.h>
#include <linux/random.h>
#include <linux/init.h>
-#include <linux/raw.h>
#include <linux/tty.h>
#include <linux/capability.h>
#include <linux/ptrace.h>
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 89681f07bc78..8f1bce0b4fe5 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -544,6 +544,10 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq)
io_read_num_rec_bytes(iobase, &num_bytes_read);
if (num_bytes_read >= 4) {
DEBUGP(2, dev, "NumRecBytes = %i\n", num_bytes_read);
+ if (num_bytes_read > 4) {
+ rc = -EIO;
+ goto exit_setprotocol;
+ }
break;
}
usleep_range(10000, 11000);
@@ -1050,7 +1054,6 @@ static ssize_t cmm_write(struct file *filp, const char __user *buf,
struct cm4000_dev *dev = filp->private_data;
unsigned int iobase = dev->p_dev->resource[0]->start;
unsigned short s;
- unsigned char tmp;
unsigned char infolen;
unsigned char sendT0;
unsigned short nsend;
@@ -1148,7 +1151,7 @@ static ssize_t cmm_write(struct file *filp, const char __user *buf,
set_cardparameter(dev);
/* dummy read, reset flag procedure received */
- tmp = inb(REG_FLAGS1(iobase));
+ inb(REG_FLAGS1(iobase));
dev->flags1 = 0x20 /* T_Active */
| (sendT0)
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index d5e43606339c..827711911da4 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -221,7 +221,6 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf,
unsigned long i;
size_t min_bytes_to_read;
int rc;
- unsigned char uc;
DEBUGP(2, dev, "-> cm4040_read(%s,%d)\n", current->comm, current->pid);
@@ -308,7 +307,7 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf,
return -EIO;
}
- uc = xinb(iobase + REG_OFFSET_BULK_IN);
+ xinb(iobase + REG_OFFSET_BULK_IN);
DEBUGP(2, dev, "<- cm4040_read (successfully)\n");
return min_bytes_to_read;
diff --git a/drivers/char/pcmcia/scr24x_cs.c b/drivers/char/pcmcia/scr24x_cs.c
index 47feb39af34c..1bdce08fae3d 100644
--- a/drivers/char/pcmcia/scr24x_cs.c
+++ b/drivers/char/pcmcia/scr24x_cs.c
@@ -265,7 +265,6 @@ static int scr24x_probe(struct pcmcia_device *link)
cdev_init(&dev->c_dev, &scr24x_fops);
dev->c_dev.owner = THIS_MODULE;
- dev->c_dev.ops = &scr24x_fops;
ret = cdev_add(&dev->c_dev, MKDEV(MAJOR(scr24x_devt), dev->devno), 1);
if (ret < 0)
goto err;
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 3287a7627ed0..6eaefea0520e 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -985,7 +985,7 @@ static void tx_done(MGSLPC_INFO *info, struct tty_struct *tty)
else
#endif
{
- if (tty && (tty->stopped || tty->hw_stopped)) {
+ if (tty && (tty->flow.stopped || tty->hw_stopped)) {
tx_stop(info);
return;
}
@@ -1005,7 +1005,7 @@ static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty)
if (!info->tx_active)
return;
} else {
- if (tty && (tty->stopped || tty->hw_stopped)) {
+ if (tty && (tty->flow.stopped || tty->hw_stopped)) {
tx_stop(info);
return;
}
@@ -1419,13 +1419,7 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
/* byte size and parity */
- switch (cflag & CSIZE) {
- case CS5: info->params.data_bits = 5; break;
- case CS6: info->params.data_bits = 6; break;
- case CS7: info->params.data_bits = 7; break;
- case CS8: info->params.data_bits = 8; break;
- default: info->params.data_bits = 7; break;
- }
+ info->params.data_bits = tty_get_char_size(cflag);
if (cflag & CSTOPB)
info->params.stop_bits = 2;
@@ -1525,7 +1519,7 @@ static void mgslpc_flush_chars(struct tty_struct *tty)
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_chars"))
return;
- if (info->tx_count <= 0 || tty->stopped ||
+ if (info->tx_count <= 0 || tty->flow.stopped ||
tty->hw_stopped || !info->tx_buf)
return;
@@ -1594,7 +1588,7 @@ static int mgslpc_write(struct tty_struct * tty,
ret += c;
}
start:
- if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
+ if (info->tx_count && !tty->flow.stopped && !tty->hw_stopped) {
spin_lock_irqsave(&info->lock, flags);
if (!info->tx_active)
tx_start(info, tty);
@@ -1609,7 +1603,7 @@ cleanup:
/* Return the count of free bytes in transmit buffer
*/
-static int mgslpc_write_room(struct tty_struct *tty)
+static unsigned int mgslpc_write_room(struct tty_struct *tty)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
int ret;
@@ -1637,10 +1631,10 @@ static int mgslpc_write_room(struct tty_struct *tty)
/* Return the count of bytes in transmit buffer
*/
-static int mgslpc_chars_in_buffer(struct tty_struct *tty)
+static unsigned int mgslpc_chars_in_buffer(struct tty_struct *tty)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
- int rc;
+ unsigned int rc;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_chars_in_buffer(%s)\n",
@@ -1655,7 +1649,7 @@ static int mgslpc_chars_in_buffer(struct tty_struct *tty)
rc = info->tx_count;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgslpc_chars_in_buffer(%s)=%d\n",
+ printk("%s(%d):mgslpc_chars_in_buffer(%s)=%u\n",
__FILE__, __LINE__, info->device_name, rc);
return rc;
diff --git a/drivers/char/powernv-op-panel.c b/drivers/char/powernv-op-panel.c
index 027484ecfb0d..3c99696b145e 100644
--- a/drivers/char/powernv-op-panel.c
+++ b/drivers/char/powernv-op-panel.c
@@ -75,6 +75,7 @@ static int __op_panel_update_display(void)
rc);
break;
}
+ break;
case OPAL_SUCCESS:
break;
default:
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
deleted file mode 100644
index 5d52a1f4738c..000000000000
--- a/drivers/char/raw.c
+++ /dev/null
@@ -1,362 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * linux/drivers/char/raw.c
- *
- * Front-end raw character devices. These can be bound to any block
- * devices to provide genuine Unix raw character device semantics.
- *
- * We reserve minor number 0 for a control interface. ioctl()s on this
- * device are used to bind the other minor numbers to block devices.
- */
-
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <linux/blkdev.h>
-#include <linux/backing-dev.h>
-#include <linux/module.h>
-#include <linux/raw.h>
-#include <linux/capability.h>
-#include <linux/uio.h>
-#include <linux/cdev.h>
-#include <linux/device.h>
-#include <linux/mutex.h>
-#include <linux/gfp.h>
-#include <linux/compat.h>
-#include <linux/vmalloc.h>
-
-#include <linux/uaccess.h>
-
-struct raw_device_data {
- dev_t binding;
- struct block_device *bdev;
- int inuse;
-};
-
-static struct class *raw_class;
-static struct raw_device_data *raw_devices;
-static DEFINE_MUTEX(raw_mutex);
-static const struct file_operations raw_ctl_fops; /* forward declaration */
-
-static int max_raw_minors = CONFIG_MAX_RAW_DEVS;
-
-module_param(max_raw_minors, int, 0);
-MODULE_PARM_DESC(max_raw_minors, "Maximum number of raw devices (1-65536)");
-
-/*
- * Open/close code for raw IO.
- *
- * We just rewrite the i_mapping for the /dev/raw/rawN file descriptor to
- * point at the blockdev's address_space and set the file handle to use
- * O_DIRECT.
- *
- * Set the device's soft blocksize to the minimum possible. This gives the
- * finest possible alignment and has no adverse impact on performance.
- */
-static int raw_open(struct inode *inode, struct file *filp)
-{
- const int minor = iminor(inode);
- struct block_device *bdev;
- int err;
-
- if (minor == 0) { /* It is the control device */
- filp->f_op = &raw_ctl_fops;
- return 0;
- }
-
- pr_warn_ratelimited(
- "process %s (pid %d) is using the deprecated raw device\n"
- "support will be removed in Linux 5.14.\n",
- current->comm, current->pid);
-
- mutex_lock(&raw_mutex);
-
- /*
- * All we need to do on open is check that the device is bound.
- */
- err = -ENODEV;
- if (!raw_devices[minor].binding)
- goto out;
- bdev = blkdev_get_by_dev(raw_devices[minor].binding,
- filp->f_mode | FMODE_EXCL, raw_open);
- if (IS_ERR(bdev)) {
- err = PTR_ERR(bdev);
- goto out;
- }
- err = set_blocksize(bdev, bdev_logical_block_size(bdev));
- if (err)
- goto out1;
- filp->f_flags |= O_DIRECT;
- filp->f_mapping = bdev->bd_inode->i_mapping;
- if (++raw_devices[minor].inuse == 1)
- file_inode(filp)->i_mapping =
- bdev->bd_inode->i_mapping;
- filp->private_data = bdev;
- raw_devices[minor].bdev = bdev;
- mutex_unlock(&raw_mutex);
- return 0;
-
-out1:
- blkdev_put(bdev, filp->f_mode | FMODE_EXCL);
-out:
- mutex_unlock(&raw_mutex);
- return err;
-}
-
-/*
- * When the final fd which refers to this character-special node is closed, we
- * make its ->mapping point back at its own i_data.
- */
-static int raw_release(struct inode *inode, struct file *filp)
-{
- const int minor= iminor(inode);
- struct block_device *bdev;
-
- mutex_lock(&raw_mutex);
- bdev = raw_devices[minor].bdev;
- if (--raw_devices[minor].inuse == 0)
- /* Here inode->i_mapping == bdev->bd_inode->i_mapping */
- inode->i_mapping = &inode->i_data;
- mutex_unlock(&raw_mutex);
-
- blkdev_put(bdev, filp->f_mode | FMODE_EXCL);
- return 0;
-}
-
-/*
- * Forward ioctls to the underlying block device.
- */
-static long
-raw_ioctl(struct file *filp, unsigned int command, unsigned long arg)
-{
- struct block_device *bdev = filp->private_data;
- return blkdev_ioctl(bdev, 0, command, arg);
-}
-
-static int bind_set(int number, u64 major, u64 minor)
-{
- dev_t dev = MKDEV(major, minor);
- dev_t raw = MKDEV(RAW_MAJOR, number);
- struct raw_device_data *rawdev;
- int err = 0;
-
- if (number <= 0 || number >= max_raw_minors)
- return -EINVAL;
-
- if (MAJOR(dev) != major || MINOR(dev) != minor)
- return -EINVAL;
-
- rawdev = &raw_devices[number];
-
- /*
- * This is like making block devices, so demand the
- * same capability
- */
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- /*
- * For now, we don't need to check that the underlying
- * block device is present or not: we can do that when
- * the raw device is opened. Just check that the
- * major/minor numbers make sense.
- */
-
- if (MAJOR(dev) == 0 && dev != 0)
- return -EINVAL;
-
- mutex_lock(&raw_mutex);
- if (rawdev->inuse) {
- mutex_unlock(&raw_mutex);
- return -EBUSY;
- }
- if (rawdev->binding)
- module_put(THIS_MODULE);
-
- rawdev->binding = dev;
- if (!dev) {
- /* unbind */
- device_destroy(raw_class, raw);
- } else {
- __module_get(THIS_MODULE);
- device_destroy(raw_class, raw);
- device_create(raw_class, NULL, raw, NULL, "raw%d", number);
- }
- mutex_unlock(&raw_mutex);
- return err;
-}
-
-static int bind_get(int number, dev_t *dev)
-{
- if (number <= 0 || number >= max_raw_minors)
- return -EINVAL;
- *dev = raw_devices[number].binding;
- return 0;
-}
-
-/*
- * Deal with ioctls against the raw-device control interface, to bind
- * and unbind other raw devices.
- */
-static long raw_ctl_ioctl(struct file *filp, unsigned int command,
- unsigned long arg)
-{
- struct raw_config_request rq;
- dev_t dev;
- int err;
-
- switch (command) {
- case RAW_SETBIND:
- if (copy_from_user(&rq, (void __user *) arg, sizeof(rq)))
- return -EFAULT;
-
- return bind_set(rq.raw_minor, rq.block_major, rq.block_minor);
-
- case RAW_GETBIND:
- if (copy_from_user(&rq, (void __user *) arg, sizeof(rq)))
- return -EFAULT;
-
- err = bind_get(rq.raw_minor, &dev);
- if (err)
- return err;
-
- rq.block_major = MAJOR(dev);
- rq.block_minor = MINOR(dev);
-
- if (copy_to_user((void __user *)arg, &rq, sizeof(rq)))
- return -EFAULT;
-
- return 0;
- }
-
- return -EINVAL;
-}
-
-#ifdef CONFIG_COMPAT
-struct raw32_config_request {
- compat_int_t raw_minor;
- compat_u64 block_major;
- compat_u64 block_minor;
-};
-
-static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct raw32_config_request __user *user_req = compat_ptr(arg);
- struct raw32_config_request rq;
- dev_t dev;
- int err = 0;
-
- switch (cmd) {
- case RAW_SETBIND:
- if (copy_from_user(&rq, user_req, sizeof(rq)))
- return -EFAULT;
-
- return bind_set(rq.raw_minor, rq.block_major, rq.block_minor);
-
- case RAW_GETBIND:
- if (copy_from_user(&rq, user_req, sizeof(rq)))
- return -EFAULT;
-
- err = bind_get(rq.raw_minor, &dev);
- if (err)
- return err;
-
- rq.block_major = MAJOR(dev);
- rq.block_minor = MINOR(dev);
-
- if (copy_to_user(user_req, &rq, sizeof(rq)))
- return -EFAULT;
-
- return 0;
- }
-
- return -EINVAL;
-}
-#endif
-
-static const struct file_operations raw_fops = {
- .read_iter = blkdev_read_iter,
- .write_iter = blkdev_write_iter,
- .fsync = blkdev_fsync,
- .open = raw_open,
- .release = raw_release,
- .unlocked_ioctl = raw_ioctl,
- .llseek = default_llseek,
- .owner = THIS_MODULE,
-};
-
-static const struct file_operations raw_ctl_fops = {
- .unlocked_ioctl = raw_ctl_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = raw_ctl_compat_ioctl,
-#endif
- .open = raw_open,
- .owner = THIS_MODULE,
- .llseek = noop_llseek,
-};
-
-static struct cdev raw_cdev;
-
-static char *raw_devnode(struct device *dev, umode_t *mode)
-{
- return kasprintf(GFP_KERNEL, "raw/%s", dev_name(dev));
-}
-
-static int __init raw_init(void)
-{
- dev_t dev = MKDEV(RAW_MAJOR, 0);
- int ret;
-
- if (max_raw_minors < 1 || max_raw_minors > 65536) {
- pr_warn("raw: invalid max_raw_minors (must be between 1 and 65536), using %d\n",
- CONFIG_MAX_RAW_DEVS);
- max_raw_minors = CONFIG_MAX_RAW_DEVS;
- }
-
- raw_devices = vzalloc(array_size(max_raw_minors,
- sizeof(struct raw_device_data)));
- if (!raw_devices) {
- printk(KERN_ERR "Not enough memory for raw device structures\n");
- ret = -ENOMEM;
- goto error;
- }
-
- ret = register_chrdev_region(dev, max_raw_minors, "raw");
- if (ret)
- goto error;
-
- cdev_init(&raw_cdev, &raw_fops);
- ret = cdev_add(&raw_cdev, dev, max_raw_minors);
- if (ret)
- goto error_region;
- raw_class = class_create(THIS_MODULE, "raw");
- if (IS_ERR(raw_class)) {
- printk(KERN_ERR "Error creating raw class.\n");
- cdev_del(&raw_cdev);
- ret = PTR_ERR(raw_class);
- goto error_region;
- }
- raw_class->devnode = raw_devnode;
- device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");
-
- return 0;
-
-error_region:
- unregister_chrdev_region(dev, max_raw_minors);
-error:
- vfree(raw_devices);
- return ret;
-}
-
-static void __exit raw_exit(void)
-{
- device_destroy(raw_class, MKDEV(RAW_MAJOR, 0));
- class_destroy(raw_class);
- cdev_del(&raw_cdev);
- unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), max_raw_minors);
-}
-
-module_init(raw_init);
-module_exit(raw_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c
index ca7158fa6e6c..f7dc986fa4a0 100644
--- a/drivers/char/tpm/tpm1-cmd.c
+++ b/drivers/char/tpm/tpm1-cmd.c
@@ -312,7 +312,7 @@ unsigned long tpm1_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
#define TPM_ST_CLEAR 1
/**
- * tpm_startup() - turn on the TPM
+ * tpm1_startup() - turn on the TPM
* @chip: TPM chip to use
*
* Normally the firmware should start the TPM. This function is provided as a
@@ -611,7 +611,7 @@ out:
#define TPM_ORD_CONTINUE_SELFTEST 83
/**
- * tpm_continue_selftest() - run TPM's selftest
+ * tpm1_continue_selftest() - run TPM's selftest
* @chip: TPM chip to use
*
* Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index c84d23951219..a25815a6f625 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -87,7 +87,7 @@ static u8 tpm2_ordinal_duration_index(u32 ordinal)
return TPM_MEDIUM;
case TPM2_CC_VERIFY_SIGNATURE: /* 177 */
- return TPM_LONG;
+ return TPM_LONG_LONG;
case TPM2_CC_PCR_EXTEND: /* 182 */
return TPM_MEDIUM;
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index a9dcf31eadd2..18606651d1aa 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -464,7 +464,7 @@ static void __iomem *crb_map_res(struct device *dev, struct resource *iores,
/* Detect a 64 bit address on a 32 bit system */
if (start != new_res.start)
- return (void __iomem *) ERR_PTR(-EINVAL);
+ return IOMEM_ERR_PTR(-EINVAL);
if (!iores)
return devm_ioremap_resource(dev, &new_res);
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 4ed6e660273a..d3f2e5364c27 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -363,11 +363,7 @@ static int tpm_tis_force_device(void)
{
struct platform_device *pdev;
static const struct resource x86_resources[] = {
- {
- .start = 0xFED40000,
- .end = 0xFED40000 + TIS_MEM_LEN - 1,
- .flags = IORESOURCE_MEM,
- },
+ DEFINE_RES_MEM(0xFED40000, TIS_MEM_LEN)
};
if (!force)
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 55b9d3965ae1..69579efb247b 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -196,13 +196,24 @@ static u8 tpm_tis_status(struct tpm_chip *chip)
return 0;
if (unlikely((status & TPM_STS_READ_ZERO) != 0)) {
- /*
- * If this trips, the chances are the read is
- * returning 0xff because the locality hasn't been
- * acquired. Usually because tpm_try_get_ops() hasn't
- * been called before doing a TPM operation.
- */
- WARN_ONCE(1, "TPM returned invalid status\n");
+ if (!test_and_set_bit(TPM_TIS_INVALID_STATUS, &priv->flags)) {
+ /*
+ * If this trips, the chances are the read is
+ * returning 0xff because the locality hasn't been
+ * acquired. Usually because tpm_try_get_ops() hasn't
+ * been called before doing a TPM operation.
+ */
+ dev_err(&chip->dev, "invalid TPM_STS.x 0x%02x, dumping stack for forensics\n",
+ status);
+
+ /*
+ * Dump stack for forensics, as invalid TPM_STS.x could be
+ * potentially triggered by impaired tpm_try_get_ops() or
+ * tpm_find_get_ops().
+ */
+ dump_stack();
+ }
+
return 0;
}
diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
index 9b2d32a59f67..b2a3c6c72882 100644
--- a/drivers/char/tpm/tpm_tis_core.h
+++ b/drivers/char/tpm/tpm_tis_core.h
@@ -83,6 +83,7 @@ enum tis_defaults {
enum tpm_tis_flags {
TPM_TIS_ITPM_WORKAROUND = BIT(0),
+ TPM_TIS_INVALID_STATUS = BIT(1),
};
struct tpm_tis_data {
@@ -90,7 +91,7 @@ struct tpm_tis_data {
int locality;
int irq;
bool irq_tested;
- unsigned int flags;
+ unsigned long flags;
void __iomem *ilb_base_addr;
u16 clkrun_enabled;
wait_queue_head_t int_queue;
diff --git a/drivers/char/tpm/tpm_tis_i2c_cr50.c b/drivers/char/tpm/tpm_tis_i2c_cr50.c
index f19c227d20f4..44dde2fbe2fb 100644
--- a/drivers/char/tpm/tpm_tis_i2c_cr50.c
+++ b/drivers/char/tpm/tpm_tis_i2c_cr50.c
@@ -706,14 +706,14 @@ static int tpm_cr50_i2c_probe(struct i2c_client *client,
if (client->irq > 0) {
rc = devm_request_irq(dev, client->irq, tpm_cr50_i2c_int_handler,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
+ IRQF_NO_AUTOEN,
dev->driver->name, chip);
if (rc < 0) {
dev_err(dev, "Failed to probe IRQ %d\n", client->irq);
return rc;
}
- disable_irq(client->irq);
priv->irq = client->irq;
} else {
dev_warn(dev, "No IRQ, will use %ums delay for TPM ready\n",
diff --git a/drivers/char/tpm/tpm_tis_spi_main.c b/drivers/char/tpm/tpm_tis_spi_main.c
index 3856f6ebcb34..54584b4b00d1 100644
--- a/drivers/char/tpm/tpm_tis_spi_main.c
+++ b/drivers/char/tpm/tpm_tis_spi_main.c
@@ -240,10 +240,14 @@ static int tpm_tis_spi_driver_probe(struct spi_device *spi)
tpm_tis_spi_probe_func probe_func;
probe_func = of_device_get_match_data(&spi->dev);
- if (!probe_func && spi_dev_id)
- probe_func = (tpm_tis_spi_probe_func)spi_dev_id->driver_data;
- if (!probe_func)
- return -ENODEV;
+ if (!probe_func) {
+ if (spi_dev_id) {
+ probe_func = (tpm_tis_spi_probe_func)spi_dev_id->driver_data;
+ if (!probe_func)
+ return -ENODEV;
+ } else
+ probe_func = tpm_tis_spi_probe;
+ }
return probe_func(spi);
}
@@ -260,6 +264,8 @@ static int tpm_tis_spi_remove(struct spi_device *dev)
}
static const struct spi_device_id tpm_tis_spi_id[] = {
+ { "st33htpm-spi", (unsigned long)tpm_tis_spi_probe },
+ { "slb9670", (unsigned long)tpm_tis_spi_probe },
{ "tpm_tis_spi", (unsigned long)tpm_tis_spi_probe },
{ "cr50", (unsigned long)cr50_spi_probe },
{}
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index 93f5d11c830b..230b2c9b3e3c 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -52,12 +52,7 @@ static void tpk_flush(void)
static int tpk_printk(const unsigned char *buf, int count)
{
- int i = tpk_curr;
-
- if (buf == NULL) {
- tpk_flush();
- return i;
- }
+ int i;
for (i = 0; i < count; i++) {
if (tpk_curr >= TPK_STR_SIZE) {
@@ -100,12 +95,6 @@ static int tpk_open(struct tty_struct *tty, struct file *filp)
static void tpk_close(struct tty_struct *tty, struct file *filp)
{
struct ttyprintk_port *tpkp = tty->driver_data;
- unsigned long flags;
-
- spin_lock_irqsave(&tpkp->spinlock, flags);
- /* flush tpk_printk buffer */
- tpk_printk(NULL, 0);
- spin_unlock_irqrestore(&tpkp->spinlock, flags);
tty_port_close(&tpkp->port, tty, filp);
}
@@ -120,7 +109,6 @@ static int tpk_write(struct tty_struct *tty,
unsigned long flags;
int ret;
-
/* exclusive use of tpk_printk within this tty */
spin_lock_irqsave(&tpkp->spinlock, flags);
ret = tpk_printk(buf, count);
@@ -132,40 +120,33 @@ static int tpk_write(struct tty_struct *tty,
/*
* TTY operations write_room function.
*/
-static int tpk_write_room(struct tty_struct *tty)
+static unsigned int tpk_write_room(struct tty_struct *tty)
{
return TPK_MAX_ROOM;
}
/*
- * TTY operations ioctl function.
+ * TTY operations hangup function.
*/
-static int tpk_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static void tpk_hangup(struct tty_struct *tty)
{
struct ttyprintk_port *tpkp = tty->driver_data;
- if (!tpkp)
- return -EINVAL;
-
- switch (cmd) {
- /* Stop TIOCCONS */
- case TIOCCONS:
- return -EOPNOTSUPP;
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
+ tty_port_hangup(&tpkp->port);
}
/*
- * TTY operations hangup function.
+ * TTY port operations shutdown function.
*/
-static void tpk_hangup(struct tty_struct *tty)
+static void tpk_port_shutdown(struct tty_port *tport)
{
- struct ttyprintk_port *tpkp = tty->driver_data;
+ struct ttyprintk_port *tpkp =
+ container_of(tport, struct ttyprintk_port, port);
+ unsigned long flags;
- tty_port_hangup(&tpkp->port);
+ spin_lock_irqsave(&tpkp->spinlock, flags);
+ tpk_flush();
+ spin_unlock_irqrestore(&tpkp->spinlock, flags);
}
static const struct tty_operations ttyprintk_ops = {
@@ -173,11 +154,12 @@ static const struct tty_operations ttyprintk_ops = {
.close = tpk_close,
.write = tpk_write,
.write_room = tpk_write_room,
- .ioctl = tpk_ioctl,
.hangup = tpk_hangup,
};
-static const struct tty_port_operations null_ops = { };
+static const struct tty_port_operations tpk_port_ops = {
+ .shutdown = tpk_port_shutdown,
+};
static struct tty_driver *ttyprintk_driver;
@@ -195,7 +177,7 @@ static int __init ttyprintk_init(void)
return PTR_ERR(ttyprintk_driver);
tty_port_init(&tpk_port.port);
- tpk_port.port.ops = &null_ops;
+ tpk_port.port.ops = &tpk_port_ops;
ttyprintk_driver->driver_name = "ttyprintk";
ttyprintk_driver->name = "ttyprintk";
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 59dfd9c421a1..7eaf303a7a86 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -475,7 +475,7 @@ static struct port_buffer *get_inbuf(struct port *port)
buf = virtqueue_get_buf(port->in_vq, &len);
if (buf) {
- buf->len = len;
+ buf->len = min_t(size_t, len, buf->size);
buf->offset = 0;
port->stats.bytes_received += len;
}
@@ -1709,7 +1709,7 @@ static void control_work_handler(struct work_struct *work)
while ((buf = virtqueue_get_buf(vq, &len))) {
spin_unlock(&portdev->c_ivq_lock);
- buf->len = len;
+ buf->len = min_t(size_t, len, buf->size);
buf->offset = 0;
handle_control_message(vq->vdev, portdev, buf);
diff --git a/drivers/char/xillybus/Kconfig b/drivers/char/xillybus/Kconfig
index 130dbdce858f..a8036dad437e 100644
--- a/drivers/char/xillybus/Kconfig
+++ b/drivers/char/xillybus/Kconfig
@@ -3,10 +3,14 @@
# Xillybus devices
#
+config XILLYBUS_CLASS
+ tristate
+
config XILLYBUS
tristate "Xillybus generic FPGA interface"
depends on PCI || OF
select CRC32
+ select XILLYBUS_CLASS
help
Xillybus is a generic interface for peripherals designed on
programmable logic (FPGA). The driver probes the hardware for
@@ -21,7 +25,7 @@ config XILLYBUS_PCIE
depends on PCI_MSI
help
Set to M if you want Xillybus to use PCI Express for communicating
- with the FPGA.
+ with the FPGA. The module will be called xillybus_pcie.
config XILLYBUS_OF
tristate "Xillybus over Device Tree"
@@ -29,6 +33,20 @@ config XILLYBUS_OF
help
Set to M if you want Xillybus to find its resources from the
Open Firmware Flattened Device Tree. If the target is an embedded
- system, say M.
+ system, say M. The module will be called xillybus_of.
endif # if XILLYBUS
+
+# XILLYUSB doesn't depend on XILLYBUS
+
+config XILLYUSB
+ tristate "XillyUSB: Xillybus generic FPGA interface for USB"
+ depends on USB
+ select CRC32
+ select XILLYBUS_CLASS
+ help
+ XillyUSB is the Xillybus variant which uses USB for communicating
+ with the FPGA.
+
+ Set to M if you want Xillybus to use USB for communicating with
+ the FPGA. The module will be called xillyusb.
diff --git a/drivers/char/xillybus/Makefile b/drivers/char/xillybus/Makefile
index 099e9a3585fc..16f31d03209d 100644
--- a/drivers/char/xillybus/Makefile
+++ b/drivers/char/xillybus/Makefile
@@ -3,6 +3,8 @@
# Makefile for Xillybus driver
#
+obj-$(CONFIG_XILLYBUS_CLASS) += xillybus_class.o
obj-$(CONFIG_XILLYBUS) += xillybus_core.o
obj-$(CONFIG_XILLYBUS_PCIE) += xillybus_pcie.o
obj-$(CONFIG_XILLYBUS_OF) += xillybus_of.o
+obj-$(CONFIG_XILLYUSB) += xillyusb.o
diff --git a/drivers/char/xillybus/xillybus.h b/drivers/char/xillybus/xillybus.h
index 8e3ed4d1bb7f..c63ffc56637c 100644
--- a/drivers/char/xillybus/xillybus.h
+++ b/drivers/char/xillybus/xillybus.h
@@ -30,7 +30,8 @@ struct xilly_buffer {
struct xilly_idt_handle {
unsigned char *chandesc;
- unsigned char *idt;
+ unsigned char *names;
+ int names_len;
int entries;
};
@@ -94,7 +95,6 @@ struct xilly_endpoint {
struct device *dev;
struct xilly_endpoint_hardware *ephw;
- struct list_head ep_list;
int dma_using_dac; /* =1 if 64-bit DMA is used, =0 otherwise. */
__iomem void *registers;
int fatal_error;
@@ -102,12 +102,6 @@ struct xilly_endpoint {
struct mutex register_mutex;
wait_queue_head_t ep_wait;
- /* Channels and message handling */
- struct cdev cdev;
-
- int major;
- int lowest_minor; /* Highest minor = lowest_minor + num_channels - 1 */
-
int num_channels; /* EXCLUDING message buffer */
struct xilly_channel **channels;
int msg_counter;
diff --git a/drivers/char/xillybus/xillybus_class.c b/drivers/char/xillybus/xillybus_class.c
new file mode 100644
index 000000000000..5046486011c8
--- /dev/null
+++ b/drivers/char/xillybus/xillybus_class.c
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2021 Xillybus Ltd, http://xillybus.com
+ *
+ * Driver for the Xillybus class
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+
+#include "xillybus_class.h"
+
+MODULE_DESCRIPTION("Driver for Xillybus class");
+MODULE_AUTHOR("Eli Billauer, Xillybus Ltd.");
+MODULE_ALIAS("xillybus_class");
+MODULE_LICENSE("GPL v2");
+
+static DEFINE_MUTEX(unit_mutex);
+static LIST_HEAD(unit_list);
+static struct class *xillybus_class;
+
+#define UNITNAMELEN 16
+
+struct xilly_unit {
+ struct list_head list_entry;
+ void *private_data;
+
+ struct cdev *cdev;
+ char name[UNITNAMELEN];
+ int major;
+ int lowest_minor;
+ int num_nodes;
+};
+
+int xillybus_init_chrdev(struct device *dev,
+ const struct file_operations *fops,
+ struct module *owner,
+ void *private_data,
+ unsigned char *idt, unsigned int len,
+ int num_nodes,
+ const char *prefix, bool enumerate)
+{
+ int rc;
+ dev_t mdev;
+ int i;
+ char devname[48];
+
+ struct device *device;
+ size_t namelen;
+ struct xilly_unit *unit, *u;
+
+ unit = kzalloc(sizeof(*unit), GFP_KERNEL);
+
+ if (!unit)
+ return -ENOMEM;
+
+ mutex_lock(&unit_mutex);
+
+ if (!enumerate)
+ snprintf(unit->name, UNITNAMELEN, "%s", prefix);
+
+ for (i = 0; enumerate; i++) {
+ snprintf(unit->name, UNITNAMELEN, "%s_%02d",
+ prefix, i);
+
+ enumerate = false;
+ list_for_each_entry(u, &unit_list, list_entry)
+ if (!strcmp(unit->name, u->name)) {
+ enumerate = true;
+ break;
+ }
+ }
+
+ rc = alloc_chrdev_region(&mdev, 0, num_nodes, unit->name);
+
+ if (rc) {
+ dev_warn(dev, "Failed to obtain major/minors");
+ goto fail_obtain;
+ }
+
+ unit->major = MAJOR(mdev);
+ unit->lowest_minor = MINOR(mdev);
+ unit->num_nodes = num_nodes;
+ unit->private_data = private_data;
+
+ unit->cdev = cdev_alloc();
+ if (!unit->cdev) {
+ rc = -ENOMEM;
+ goto unregister_chrdev;
+ }
+ unit->cdev->ops = fops;
+ unit->cdev->owner = owner;
+
+ rc = cdev_add(unit->cdev, MKDEV(unit->major, unit->lowest_minor),
+ unit->num_nodes);
+ if (rc) {
+ dev_err(dev, "Failed to add cdev.\n");
+ /* kobject_put() is normally done by cdev_del() */
+ kobject_put(&unit->cdev->kobj);
+ goto unregister_chrdev;
+ }
+
+ for (i = 0; i < num_nodes; i++) {
+ namelen = strnlen(idt, len);
+
+ if (namelen == len) {
+ dev_err(dev, "IDT's list of names is too short. This is exceptionally weird, because its CRC is OK\n");
+ rc = -ENODEV;
+ goto unroll_device_create;
+ }
+
+ snprintf(devname, sizeof(devname), "%s_%s",
+ unit->name, idt);
+
+ len -= namelen + 1;
+ idt += namelen + 1;
+
+ device = device_create(xillybus_class,
+ NULL,
+ MKDEV(unit->major,
+ i + unit->lowest_minor),
+ NULL,
+ "%s", devname);
+
+ if (IS_ERR(device)) {
+ dev_err(dev, "Failed to create %s device. Aborting.\n",
+ devname);
+ rc = -ENODEV;
+ goto unroll_device_create;
+ }
+ }
+
+ if (len) {
+ dev_err(dev, "IDT's list of names is too long. This is exceptionally weird, because its CRC is OK\n");
+ rc = -ENODEV;
+ goto unroll_device_create;
+ }
+
+ list_add_tail(&unit->list_entry, &unit_list);
+
+ dev_info(dev, "Created %d device files.\n", num_nodes);
+
+ mutex_unlock(&unit_mutex);
+
+ return 0;
+
+unroll_device_create:
+ for (i--; i >= 0; i--)
+ device_destroy(xillybus_class, MKDEV(unit->major,
+ i + unit->lowest_minor));
+
+ cdev_del(unit->cdev);
+
+unregister_chrdev:
+ unregister_chrdev_region(MKDEV(unit->major, unit->lowest_minor),
+ unit->num_nodes);
+
+fail_obtain:
+ mutex_unlock(&unit_mutex);
+
+ kfree(unit);
+
+ return rc;
+}
+EXPORT_SYMBOL(xillybus_init_chrdev);
+
+void xillybus_cleanup_chrdev(void *private_data,
+ struct device *dev)
+{
+ int minor;
+ struct xilly_unit *unit;
+ bool found = false;
+
+ mutex_lock(&unit_mutex);
+
+ list_for_each_entry(unit, &unit_list, list_entry)
+ if (unit->private_data == private_data) {
+ found = true;
+ break;
+ }
+
+ if (!found) {
+ dev_err(dev, "Weird bug: Failed to find unit\n");
+ mutex_unlock(&unit_mutex);
+ return;
+ }
+
+ for (minor = unit->lowest_minor;
+ minor < (unit->lowest_minor + unit->num_nodes);
+ minor++)
+ device_destroy(xillybus_class, MKDEV(unit->major, minor));
+
+ cdev_del(unit->cdev);
+
+ unregister_chrdev_region(MKDEV(unit->major, unit->lowest_minor),
+ unit->num_nodes);
+
+ dev_info(dev, "Removed %d device files.\n",
+ unit->num_nodes);
+
+ list_del(&unit->list_entry);
+ kfree(unit);
+
+ mutex_unlock(&unit_mutex);
+}
+EXPORT_SYMBOL(xillybus_cleanup_chrdev);
+
+int xillybus_find_inode(struct inode *inode,
+ void **private_data, int *index)
+{
+ int minor = iminor(inode);
+ int major = imajor(inode);
+ struct xilly_unit *unit;
+ bool found = false;
+
+ mutex_lock(&unit_mutex);
+
+ list_for_each_entry(unit, &unit_list, list_entry)
+ if (unit->major == major &&
+ minor >= unit->lowest_minor &&
+ minor < (unit->lowest_minor + unit->num_nodes)) {
+ found = true;
+ break;
+ }
+
+ mutex_unlock(&unit_mutex);
+
+ if (!found)
+ return -ENODEV;
+
+ *private_data = unit->private_data;
+ *index = minor - unit->lowest_minor;
+
+ return 0;
+}
+EXPORT_SYMBOL(xillybus_find_inode);
+
+static int __init xillybus_class_init(void)
+{
+ xillybus_class = class_create(THIS_MODULE, "xillybus");
+
+ if (IS_ERR(xillybus_class)) {
+ pr_warn("Failed to register xillybus class\n");
+
+ return PTR_ERR(xillybus_class);
+ }
+ return 0;
+}
+
+static void __exit xillybus_class_exit(void)
+{
+ class_destroy(xillybus_class);
+}
+
+module_init(xillybus_class_init);
+module_exit(xillybus_class_exit);
diff --git a/drivers/char/xillybus/xillybus_class.h b/drivers/char/xillybus/xillybus_class.h
new file mode 100644
index 000000000000..5dbfdfc95c65
--- /dev/null
+++ b/drivers/char/xillybus/xillybus_class.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright 2021 Xillybus Ltd, http://www.xillybus.com
+ *
+ * Header file for the Xillybus class
+ */
+
+#ifndef __XILLYBUS_CLASS_H
+#define __XILLYBUS_CLASS_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+
+int xillybus_init_chrdev(struct device *dev,
+ const struct file_operations *fops,
+ struct module *owner,
+ void *private_data,
+ unsigned char *idt, unsigned int len,
+ int num_nodes,
+ const char *prefix, bool enumerate);
+
+void xillybus_cleanup_chrdev(void *private_data,
+ struct device *dev);
+
+int xillybus_find_inode(struct inode *inode,
+ void **private_data, int *index);
+
+#endif /* __XILLYBUS_CLASS_H */
diff --git a/drivers/char/xillybus/xillybus_core.c b/drivers/char/xillybus/xillybus_core.c
index 57fa68834981..931d0bf4cec6 100644
--- a/drivers/char/xillybus/xillybus_core.c
+++ b/drivers/char/xillybus/xillybus_core.c
@@ -21,7 +21,6 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/fs.h>
-#include <linux/cdev.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/crc32.h>
@@ -30,10 +29,10 @@
#include <linux/slab.h>
#include <linux/workqueue.h>
#include "xillybus.h"
+#include "xillybus_class.h"
MODULE_DESCRIPTION("Xillybus core functions");
MODULE_AUTHOR("Eli Billauer, Xillybus Ltd.");
-MODULE_VERSION("1.07");
MODULE_ALIAS("xillybus_core");
MODULE_LICENSE("GPL v2");
@@ -58,16 +57,6 @@ MODULE_LICENSE("GPL v2");
static const char xillyname[] = "xillybus";
-static struct class *xillybus_class;
-
-/*
- * ep_list_lock is the last lock to be taken; No other lock requests are
- * allowed while holding it. It merely protects list_of_endpoints, and not
- * the endpoints listed in it.
- */
-
-static LIST_HEAD(list_of_endpoints);
-static struct mutex ep_list_lock;
static struct workqueue_struct *xillybus_wq;
/*
@@ -570,10 +559,8 @@ static int xilly_scan_idt(struct xilly_endpoint *endpoint,
unsigned char *scan;
int len;
- scan = idt;
- idt_handle->idt = idt;
-
- scan++; /* Skip version number */
+ scan = idt + 1;
+ idt_handle->names = scan;
while ((scan <= end_of_idt) && *scan) {
while ((scan <= end_of_idt) && *scan++)
@@ -581,6 +568,8 @@ static int xilly_scan_idt(struct xilly_endpoint *endpoint,
count++;
}
+ idt_handle->names_len = scan - idt_handle->names;
+
scan++;
if (scan > end_of_idt) {
@@ -1407,36 +1396,20 @@ static ssize_t xillybus_write(struct file *filp, const char __user *userbuf,
static int xillybus_open(struct inode *inode, struct file *filp)
{
- int rc = 0;
+ int rc;
unsigned long flags;
- int minor = iminor(inode);
- int major = imajor(inode);
- struct xilly_endpoint *ep_iter, *endpoint = NULL;
+ struct xilly_endpoint *endpoint;
struct xilly_channel *channel;
+ int index;
- mutex_lock(&ep_list_lock);
-
- list_for_each_entry(ep_iter, &list_of_endpoints, ep_list) {
- if ((ep_iter->major == major) &&
- (minor >= ep_iter->lowest_minor) &&
- (minor < (ep_iter->lowest_minor +
- ep_iter->num_channels))) {
- endpoint = ep_iter;
- break;
- }
- }
- mutex_unlock(&ep_list_lock);
-
- if (!endpoint) {
- pr_err("xillybus: open() failed to find a device for major=%d and minor=%d\n",
- major, minor);
- return -ENODEV;
- }
+ rc = xillybus_find_inode(inode, (void **)&endpoint, &index);
+ if (rc)
+ return rc;
if (endpoint->fatal_error)
return -EIO;
- channel = endpoint->channels[1 + minor - endpoint->lowest_minor];
+ channel = endpoint->channels[1 + index];
filp->private_data = channel;
/*
@@ -1799,95 +1772,6 @@ static const struct file_operations xillybus_fops = {
.poll = xillybus_poll,
};
-static int xillybus_init_chrdev(struct xilly_endpoint *endpoint,
- const unsigned char *idt)
-{
- int rc;
- dev_t dev;
- int devnum, i, minor, major;
- char devname[48];
- struct device *device;
-
- rc = alloc_chrdev_region(&dev, 0, /* minor start */
- endpoint->num_channels,
- xillyname);
- if (rc) {
- dev_warn(endpoint->dev, "Failed to obtain major/minors");
- return rc;
- }
-
- endpoint->major = major = MAJOR(dev);
- endpoint->lowest_minor = minor = MINOR(dev);
-
- cdev_init(&endpoint->cdev, &xillybus_fops);
- endpoint->cdev.owner = endpoint->ephw->owner;
- rc = cdev_add(&endpoint->cdev, MKDEV(major, minor),
- endpoint->num_channels);
- if (rc) {
- dev_warn(endpoint->dev, "Failed to add cdev. Aborting.\n");
- goto unregister_chrdev;
- }
-
- idt++;
-
- for (i = minor, devnum = 0;
- devnum < endpoint->num_channels;
- devnum++, i++) {
- snprintf(devname, sizeof(devname)-1, "xillybus_%s", idt);
-
- devname[sizeof(devname)-1] = 0; /* Should never matter */
-
- while (*idt++)
- /* Skip to next */;
-
- device = device_create(xillybus_class,
- NULL,
- MKDEV(major, i),
- NULL,
- "%s", devname);
-
- if (IS_ERR(device)) {
- dev_warn(endpoint->dev,
- "Failed to create %s device. Aborting.\n",
- devname);
- rc = -ENODEV;
- goto unroll_device_create;
- }
- }
-
- dev_info(endpoint->dev, "Created %d device files.\n",
- endpoint->num_channels);
- return 0; /* succeed */
-
-unroll_device_create:
- devnum--; i--;
- for (; devnum >= 0; devnum--, i--)
- device_destroy(xillybus_class, MKDEV(major, i));
-
- cdev_del(&endpoint->cdev);
-unregister_chrdev:
- unregister_chrdev_region(MKDEV(major, minor), endpoint->num_channels);
-
- return rc;
-}
-
-static void xillybus_cleanup_chrdev(struct xilly_endpoint *endpoint)
-{
- int minor;
-
- for (minor = endpoint->lowest_minor;
- minor < (endpoint->lowest_minor + endpoint->num_channels);
- minor++)
- device_destroy(xillybus_class, MKDEV(endpoint->major, minor));
- cdev_del(&endpoint->cdev);
- unregister_chrdev_region(MKDEV(endpoint->major,
- endpoint->lowest_minor),
- endpoint->num_channels);
-
- dev_info(endpoint->dev, "Removed %d device files.\n",
- endpoint->num_channels);
-}
-
struct xilly_endpoint *xillybus_init_endpoint(struct pci_dev *pdev,
struct device *dev,
struct xilly_endpoint_hardware
@@ -2027,28 +1911,20 @@ int xillybus_endpoint_discovery(struct xilly_endpoint *endpoint)
if (rc)
goto failed_idt;
- /*
- * endpoint is now completely configured. We put it on the list
- * available to open() before registering the char device(s)
- */
-
- mutex_lock(&ep_list_lock);
- list_add_tail(&endpoint->ep_list, &list_of_endpoints);
- mutex_unlock(&ep_list_lock);
+ rc = xillybus_init_chrdev(dev, &xillybus_fops,
+ endpoint->ephw->owner, endpoint,
+ idt_handle.names,
+ idt_handle.names_len,
+ endpoint->num_channels,
+ xillyname, false);
- rc = xillybus_init_chrdev(endpoint, idt_handle.idt);
if (rc)
- goto failed_chrdevs;
+ goto failed_idt;
devres_release_group(dev, bootstrap_resources);
return 0;
-failed_chrdevs:
- mutex_lock(&ep_list_lock);
- list_del(&endpoint->ep_list);
- mutex_unlock(&ep_list_lock);
-
failed_idt:
xilly_quiesce(endpoint);
flush_workqueue(xillybus_wq);
@@ -2059,11 +1935,7 @@ EXPORT_SYMBOL(xillybus_endpoint_discovery);
void xillybus_endpoint_remove(struct xilly_endpoint *endpoint)
{
- xillybus_cleanup_chrdev(endpoint);
-
- mutex_lock(&ep_list_lock);
- list_del(&endpoint->ep_list);
- mutex_unlock(&ep_list_lock);
+ xillybus_cleanup_chrdev(endpoint, endpoint->dev);
xilly_quiesce(endpoint);
@@ -2077,17 +1949,9 @@ EXPORT_SYMBOL(xillybus_endpoint_remove);
static int __init xillybus_init(void)
{
- mutex_init(&ep_list_lock);
-
- xillybus_class = class_create(THIS_MODULE, xillyname);
- if (IS_ERR(xillybus_class))
- return PTR_ERR(xillybus_class);
-
xillybus_wq = alloc_workqueue(xillyname, 0, 0);
- if (!xillybus_wq) {
- class_destroy(xillybus_class);
+ if (!xillybus_wq)
return -ENOMEM;
- }
return 0;
}
@@ -2096,8 +1960,6 @@ static void __exit xillybus_exit(void)
{
/* flush_workqueue() was called for each endpoint released */
destroy_workqueue(xillybus_wq);
-
- class_destroy(xillybus_class);
}
module_init(xillybus_init);
diff --git a/drivers/char/xillybus/xillybus_of.c b/drivers/char/xillybus/xillybus_of.c
index 96b6de8a30e5..1a20b286fd1d 100644
--- a/drivers/char/xillybus/xillybus_of.c
+++ b/drivers/char/xillybus/xillybus_of.c
@@ -17,7 +17,6 @@
MODULE_DESCRIPTION("Xillybus driver for Open Firmware");
MODULE_AUTHOR("Eli Billauer, Xillybus Ltd.");
-MODULE_VERSION("1.06");
MODULE_ALIAS("xillybus_of");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/char/xillybus/xillybus_pcie.c b/drivers/char/xillybus/xillybus_pcie.c
index 18b0c392bc93..bdf1c366b4fc 100644
--- a/drivers/char/xillybus/xillybus_pcie.c
+++ b/drivers/char/xillybus/xillybus_pcie.c
@@ -14,7 +14,6 @@
MODULE_DESCRIPTION("Xillybus driver for PCIe");
MODULE_AUTHOR("Eli Billauer, Xillybus Ltd.");
-MODULE_VERSION("1.06");
MODULE_ALIAS("xillybus_pcie");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/char/xillybus/xillyusb.c b/drivers/char/xillybus/xillyusb.c
new file mode 100644
index 000000000000..e7f88f35c702
--- /dev/null
+++ b/drivers/char/xillybus/xillyusb.c
@@ -0,0 +1,2259 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2020 Xillybus Ltd, http://xillybus.com
+ *
+ * Driver for the XillyUSB FPGA/host framework.
+ *
+ * This driver interfaces with a special IP core in an FPGA, setting up
+ * a pipe between a hardware FIFO in the programmable logic and a device
+ * file in the host. The number of such pipes and their attributes are
+ * set up on the logic. This driver detects these automatically and
+ * creates the device files accordingly.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <asm/byteorder.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/crc32.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/usb.h>
+
+#include "xillybus_class.h"
+
+MODULE_DESCRIPTION("Driver for XillyUSB FPGA IP Core");
+MODULE_AUTHOR("Eli Billauer, Xillybus Ltd.");
+MODULE_ALIAS("xillyusb");
+MODULE_LICENSE("GPL v2");
+
+#define XILLY_RX_TIMEOUT (10 * HZ / 1000)
+#define XILLY_RESPONSE_TIMEOUT (500 * HZ / 1000)
+
+#define BUF_SIZE_ORDER 4
+#define BUFNUM 8
+#define LOG2_IDT_FIFO_SIZE 16
+#define LOG2_INITIAL_FIFO_BUF_SIZE 16
+
+#define MSG_EP_NUM 1
+#define IN_EP_NUM 1
+
+static const char xillyname[] = "xillyusb";
+
+static unsigned int fifo_buf_order;
+
+#define USB_VENDOR_ID_XILINX 0x03fd
+#define USB_VENDOR_ID_ALTERA 0x09fb
+
+#define USB_PRODUCT_ID_XILLYUSB 0xebbe
+
+static const struct usb_device_id xillyusb_table[] = {
+ { USB_DEVICE(USB_VENDOR_ID_XILINX, USB_PRODUCT_ID_XILLYUSB) },
+ { USB_DEVICE(USB_VENDOR_ID_ALTERA, USB_PRODUCT_ID_XILLYUSB) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, xillyusb_table);
+
+struct xillyusb_dev;
+
+struct xillyfifo {
+ unsigned int bufsize; /* In bytes, always a power of 2 */
+ unsigned int bufnum;
+ unsigned int size; /* Lazy: Equals bufsize * bufnum */
+ unsigned int buf_order;
+
+ int fill; /* Number of bytes in the FIFO */
+ spinlock_t lock;
+ wait_queue_head_t waitq;
+
+ unsigned int readpos;
+ unsigned int readbuf;
+ unsigned int writepos;
+ unsigned int writebuf;
+ char **mem;
+};
+
+struct xillyusb_channel;
+
+struct xillyusb_endpoint {
+ struct xillyusb_dev *xdev;
+
+ struct mutex ep_mutex; /* serialize operations on endpoint */
+
+ struct list_head buffers;
+ struct list_head filled_buffers;
+ spinlock_t buffers_lock; /* protect these two lists */
+
+ unsigned int order;
+ unsigned int buffer_size;
+
+ unsigned int fill_mask;
+
+ int outstanding_urbs;
+
+ struct usb_anchor anchor;
+
+ struct xillyfifo fifo;
+
+ struct work_struct workitem;
+
+ bool shutting_down;
+ bool drained;
+ bool wake_on_drain;
+
+ u8 ep_num;
+};
+
+struct xillyusb_channel {
+ struct xillyusb_dev *xdev;
+
+ struct xillyfifo *in_fifo;
+ struct xillyusb_endpoint *out_ep;
+ struct mutex lock; /* protect @out_ep, @in_fifo, bit fields below */
+
+ struct mutex in_mutex; /* serialize fops on FPGA to host stream */
+ struct mutex out_mutex; /* serialize fops on host to FPGA stream */
+ wait_queue_head_t flushq;
+
+ int chan_idx;
+
+ u32 in_consumed_bytes;
+ u32 in_current_checkpoint;
+ u32 out_bytes;
+
+ unsigned int in_log2_element_size;
+ unsigned int out_log2_element_size;
+ unsigned int in_log2_fifo_size;
+ unsigned int out_log2_fifo_size;
+
+ unsigned int read_data_ok; /* EOF not arrived (yet) */
+ unsigned int poll_used;
+ unsigned int flushing;
+ unsigned int flushed;
+ unsigned int canceled;
+
+ /* Bit fields protected by @lock except for initialization */
+ unsigned readable:1;
+ unsigned writable:1;
+ unsigned open_for_read:1;
+ unsigned open_for_write:1;
+ unsigned in_synchronous:1;
+ unsigned out_synchronous:1;
+ unsigned in_seekable:1;
+ unsigned out_seekable:1;
+};
+
+struct xillybuffer {
+ struct list_head entry;
+ struct xillyusb_endpoint *ep;
+ void *buf;
+ unsigned int len;
+};
+
+struct xillyusb_dev {
+ struct xillyusb_channel *channels;
+
+ struct usb_device *udev;
+ struct device *dev; /* For dev_err() and such */
+ struct kref kref;
+ struct workqueue_struct *workq;
+
+ int error;
+ spinlock_t error_lock; /* protect @error */
+ struct work_struct wakeup_workitem;
+
+ int num_channels;
+
+ struct xillyusb_endpoint *msg_ep;
+ struct xillyusb_endpoint *in_ep;
+
+ struct mutex msg_mutex; /* serialize opcode transmission */
+ int in_bytes_left;
+ int leftover_chan_num;
+ unsigned int in_counter;
+ struct mutex process_in_mutex; /* synchronize wakeup_all() */
+};
+
+/* FPGA to host opcodes */
+enum {
+ OPCODE_DATA = 0,
+ OPCODE_QUIESCE_ACK = 1,
+ OPCODE_EOF = 2,
+ OPCODE_REACHED_CHECKPOINT = 3,
+ OPCODE_CANCELED_CHECKPOINT = 4,
+};
+
+/* Host to FPGA opcodes */
+enum {
+ OPCODE_QUIESCE = 0,
+ OPCODE_REQ_IDT = 1,
+ OPCODE_SET_CHECKPOINT = 2,
+ OPCODE_CLOSE = 3,
+ OPCODE_SET_PUSH = 4,
+ OPCODE_UPDATE_PUSH = 5,
+ OPCODE_CANCEL_CHECKPOINT = 6,
+ OPCODE_SET_ADDR = 7,
+};
+
+/*
+ * fifo_write() and fifo_read() are NOT reentrant (i.e. concurrent multiple
+ * calls to each on the same FIFO is not allowed) however it's OK to have
+ * threads calling each of the two functions once on the same FIFO, and
+ * at the same time.
+ */
+
+static int fifo_write(struct xillyfifo *fifo,
+ const void *data, unsigned int len,
+ int (*copier)(void *, const void *, int))
+{
+ unsigned int done = 0;
+ unsigned int todo = len;
+ unsigned int nmax;
+ unsigned int writepos = fifo->writepos;
+ unsigned int writebuf = fifo->writebuf;
+ unsigned long flags;
+ int rc;
+
+ nmax = fifo->size - READ_ONCE(fifo->fill);
+
+ while (1) {
+ unsigned int nrail = fifo->bufsize - writepos;
+ unsigned int n = min(todo, nmax);
+
+ if (n == 0) {
+ spin_lock_irqsave(&fifo->lock, flags);
+ fifo->fill += done;
+ spin_unlock_irqrestore(&fifo->lock, flags);
+
+ fifo->writepos = writepos;
+ fifo->writebuf = writebuf;
+
+ return done;
+ }
+
+ if (n > nrail)
+ n = nrail;
+
+ rc = (*copier)(fifo->mem[writebuf] + writepos, data + done, n);
+
+ if (rc)
+ return rc;
+
+ done += n;
+ todo -= n;
+
+ writepos += n;
+ nmax -= n;
+
+ if (writepos == fifo->bufsize) {
+ writepos = 0;
+ writebuf++;
+
+ if (writebuf == fifo->bufnum)
+ writebuf = 0;
+ }
+ }
+}
+
+static int fifo_read(struct xillyfifo *fifo,
+ void *data, unsigned int len,
+ int (*copier)(void *, const void *, int))
+{
+ unsigned int done = 0;
+ unsigned int todo = len;
+ unsigned int fill;
+ unsigned int readpos = fifo->readpos;
+ unsigned int readbuf = fifo->readbuf;
+ unsigned long flags;
+ int rc;
+
+ /*
+ * The spinlock here is necessary, because otherwise fifo->fill
+ * could have been increased by fifo_write() after writing data
+ * to the buffer, but this data would potentially not have been
+ * visible on this thread at the time the updated fifo->fill was.
+ * That could lead to reading invalid data.
+ */
+
+ spin_lock_irqsave(&fifo->lock, flags);
+ fill = fifo->fill;
+ spin_unlock_irqrestore(&fifo->lock, flags);
+
+ while (1) {
+ unsigned int nrail = fifo->bufsize - readpos;
+ unsigned int n = min(todo, fill);
+
+ if (n == 0) {
+ spin_lock_irqsave(&fifo->lock, flags);
+ fifo->fill -= done;
+ spin_unlock_irqrestore(&fifo->lock, flags);
+
+ fifo->readpos = readpos;
+ fifo->readbuf = readbuf;
+
+ return done;
+ }
+
+ if (n > nrail)
+ n = nrail;
+
+ rc = (*copier)(data + done, fifo->mem[readbuf] + readpos, n);
+
+ if (rc)
+ return rc;
+
+ done += n;
+ todo -= n;
+
+ readpos += n;
+ fill -= n;
+
+ if (readpos == fifo->bufsize) {
+ readpos = 0;
+ readbuf++;
+
+ if (readbuf == fifo->bufnum)
+ readbuf = 0;
+ }
+ }
+}
+
+/*
+ * These three wrapper functions are used as the @copier argument to
+ * fifo_write() and fifo_read(), so that they can work directly with
+ * user memory as well.
+ */
+
+static int xilly_copy_from_user(void *dst, const void *src, int n)
+{
+ if (copy_from_user(dst, (const void __user *)src, n))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int xilly_copy_to_user(void *dst, const void *src, int n)
+{
+ if (copy_to_user((void __user *)dst, src, n))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int xilly_memcpy(void *dst, const void *src, int n)
+{
+ memcpy(dst, src, n);
+
+ return 0;
+}
+
+static int fifo_init(struct xillyfifo *fifo,
+ unsigned int log2_size)
+{
+ unsigned int log2_bufnum;
+ unsigned int buf_order;
+ int i;
+
+ unsigned int log2_fifo_buf_size;
+
+retry:
+ log2_fifo_buf_size = fifo_buf_order + PAGE_SHIFT;
+
+ if (log2_size > log2_fifo_buf_size) {
+ log2_bufnum = log2_size - log2_fifo_buf_size;
+ buf_order = fifo_buf_order;
+ fifo->bufsize = 1 << log2_fifo_buf_size;
+ } else {
+ log2_bufnum = 0;
+ buf_order = (log2_size > PAGE_SHIFT) ?
+ log2_size - PAGE_SHIFT : 0;
+ fifo->bufsize = 1 << log2_size;
+ }
+
+ fifo->bufnum = 1 << log2_bufnum;
+ fifo->size = fifo->bufnum * fifo->bufsize;
+ fifo->buf_order = buf_order;
+
+ fifo->mem = kmalloc_array(fifo->bufnum, sizeof(void *), GFP_KERNEL);
+
+ if (!fifo->mem)
+ return -ENOMEM;
+
+ for (i = 0; i < fifo->bufnum; i++) {
+ fifo->mem[i] = (void *)
+ __get_free_pages(GFP_KERNEL, buf_order);
+
+ if (!fifo->mem[i])
+ goto memfail;
+ }
+
+ fifo->fill = 0;
+ fifo->readpos = 0;
+ fifo->readbuf = 0;
+ fifo->writepos = 0;
+ fifo->writebuf = 0;
+ spin_lock_init(&fifo->lock);
+ init_waitqueue_head(&fifo->waitq);
+ return 0;
+
+memfail:
+ for (i--; i >= 0; i--)
+ free_pages((unsigned long)fifo->mem[i], buf_order);
+
+ kfree(fifo->mem);
+ fifo->mem = NULL;
+
+ if (fifo_buf_order) {
+ fifo_buf_order--;
+ goto retry;
+ } else {
+ return -ENOMEM;
+ }
+}
+
+static void fifo_mem_release(struct xillyfifo *fifo)
+{
+ int i;
+
+ if (!fifo->mem)
+ return;
+
+ for (i = 0; i < fifo->bufnum; i++)
+ free_pages((unsigned long)fifo->mem[i], fifo->buf_order);
+
+ kfree(fifo->mem);
+}
+
+/*
+ * When endpoint_quiesce() returns, the endpoint has no URBs submitted,
+ * won't accept any new URB submissions, and its related work item doesn't
+ * and won't run anymore.
+ */
+
+static void endpoint_quiesce(struct xillyusb_endpoint *ep)
+{
+ mutex_lock(&ep->ep_mutex);
+ ep->shutting_down = true;
+ mutex_unlock(&ep->ep_mutex);
+
+ usb_kill_anchored_urbs(&ep->anchor);
+ cancel_work_sync(&ep->workitem);
+}
+
+/*
+ * Note that endpoint_dealloc() also frees fifo memory (if allocated), even
+ * though endpoint_alloc doesn't allocate that memory.
+ */
+
+static void endpoint_dealloc(struct xillyusb_endpoint *ep)
+{
+ struct list_head *this, *next;
+
+ fifo_mem_release(&ep->fifo);
+
+ /* Join @filled_buffers with @buffers to free these entries too */
+ list_splice(&ep->filled_buffers, &ep->buffers);
+
+ list_for_each_safe(this, next, &ep->buffers) {
+ struct xillybuffer *xb =
+ list_entry(this, struct xillybuffer, entry);
+
+ free_pages((unsigned long)xb->buf, ep->order);
+ kfree(xb);
+ }
+
+ kfree(ep);
+}
+
+static struct xillyusb_endpoint
+*endpoint_alloc(struct xillyusb_dev *xdev,
+ u8 ep_num,
+ void (*work)(struct work_struct *),
+ unsigned int order,
+ int bufnum)
+{
+ int i;
+
+ struct xillyusb_endpoint *ep;
+
+ ep = kzalloc(sizeof(*ep), GFP_KERNEL);
+
+ if (!ep)
+ return NULL;
+
+ INIT_LIST_HEAD(&ep->buffers);
+ INIT_LIST_HEAD(&ep->filled_buffers);
+
+ spin_lock_init(&ep->buffers_lock);
+ mutex_init(&ep->ep_mutex);
+
+ init_usb_anchor(&ep->anchor);
+ INIT_WORK(&ep->workitem, work);
+
+ ep->order = order;
+ ep->buffer_size = 1 << (PAGE_SHIFT + order);
+ ep->outstanding_urbs = 0;
+ ep->drained = true;
+ ep->wake_on_drain = false;
+ ep->xdev = xdev;
+ ep->ep_num = ep_num;
+ ep->shutting_down = false;
+
+ for (i = 0; i < bufnum; i++) {
+ struct xillybuffer *xb;
+ unsigned long addr;
+
+ xb = kzalloc(sizeof(*xb), GFP_KERNEL);
+
+ if (!xb) {
+ endpoint_dealloc(ep);
+ return NULL;
+ }
+
+ addr = __get_free_pages(GFP_KERNEL, order);
+
+ if (!addr) {
+ kfree(xb);
+ endpoint_dealloc(ep);
+ return NULL;
+ }
+
+ xb->buf = (void *)addr;
+ xb->ep = ep;
+ list_add_tail(&xb->entry, &ep->buffers);
+ }
+ return ep;
+}
+
+static void cleanup_dev(struct kref *kref)
+{
+ struct xillyusb_dev *xdev =
+ container_of(kref, struct xillyusb_dev, kref);
+
+ if (xdev->in_ep)
+ endpoint_dealloc(xdev->in_ep);
+
+ if (xdev->msg_ep)
+ endpoint_dealloc(xdev->msg_ep);
+
+ if (xdev->workq)
+ destroy_workqueue(xdev->workq);
+
+ kfree(xdev->channels); /* Argument may be NULL, and that's fine */
+ kfree(xdev);
+}
+
+/*
+ * @process_in_mutex is taken to ensure that bulk_in_work() won't call
+ * process_bulk_in() after wakeup_all()'s execution: The latter zeroes all
+ * @read_data_ok entries, which will make process_bulk_in() report false
+ * errors if executed. The mechanism relies on that xdev->error is assigned
+ * a non-zero value by report_io_error() prior to queueing wakeup_all(),
+ * which prevents bulk_in_work() from calling process_bulk_in().
+ *
+ * The fact that wakeup_all() and bulk_in_work() are queued on the same
+ * workqueue makes their concurrent execution very unlikely, however the
+ * kernel's API doesn't seem to ensure this strictly.
+ */
+
+static void wakeup_all(struct work_struct *work)
+{
+ int i;
+ struct xillyusb_dev *xdev = container_of(work, struct xillyusb_dev,
+ wakeup_workitem);
+
+ mutex_lock(&xdev->process_in_mutex);
+
+ for (i = 0; i < xdev->num_channels; i++) {
+ struct xillyusb_channel *chan = &xdev->channels[i];
+
+ mutex_lock(&chan->lock);
+
+ if (chan->in_fifo) {
+ /*
+ * Fake an EOF: Even if such arrives, it won't be
+ * processed.
+ */
+ chan->read_data_ok = 0;
+ wake_up_interruptible(&chan->in_fifo->waitq);
+ }
+
+ if (chan->out_ep)
+ wake_up_interruptible(&chan->out_ep->fifo.waitq);
+
+ mutex_unlock(&chan->lock);
+
+ wake_up_interruptible(&chan->flushq);
+ }
+
+ mutex_unlock(&xdev->process_in_mutex);
+
+ wake_up_interruptible(&xdev->msg_ep->fifo.waitq);
+
+ kref_put(&xdev->kref, cleanup_dev);
+}
+
+static void report_io_error(struct xillyusb_dev *xdev,
+ int errcode)
+{
+ unsigned long flags;
+ bool do_once = false;
+
+ spin_lock_irqsave(&xdev->error_lock, flags);
+ if (!xdev->error) {
+ xdev->error = errcode;
+ do_once = true;
+ }
+ spin_unlock_irqrestore(&xdev->error_lock, flags);
+
+ if (do_once) {
+ kref_get(&xdev->kref); /* xdev is used by work item */
+ queue_work(xdev->workq, &xdev->wakeup_workitem);
+ }
+}
+
+/*
+ * safely_assign_in_fifo() changes the value of chan->in_fifo and ensures
+ * the previous pointer is never used after its return.
+ */
+
+static void safely_assign_in_fifo(struct xillyusb_channel *chan,
+ struct xillyfifo *fifo)
+{
+ mutex_lock(&chan->lock);
+ chan->in_fifo = fifo;
+ mutex_unlock(&chan->lock);
+
+ flush_work(&chan->xdev->in_ep->workitem);
+}
+
+static void bulk_in_completer(struct urb *urb)
+{
+ struct xillybuffer *xb = urb->context;
+ struct xillyusb_endpoint *ep = xb->ep;
+ unsigned long flags;
+
+ if (urb->status) {
+ if (!(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN))
+ report_io_error(ep->xdev, -EIO);
+
+ spin_lock_irqsave(&ep->buffers_lock, flags);
+ list_add_tail(&xb->entry, &ep->buffers);
+ ep->outstanding_urbs--;
+ spin_unlock_irqrestore(&ep->buffers_lock, flags);
+
+ return;
+ }
+
+ xb->len = urb->actual_length;
+
+ spin_lock_irqsave(&ep->buffers_lock, flags);
+ list_add_tail(&xb->entry, &ep->filled_buffers);
+ spin_unlock_irqrestore(&ep->buffers_lock, flags);
+
+ if (!ep->shutting_down)
+ queue_work(ep->xdev->workq, &ep->workitem);
+}
+
+static void bulk_out_completer(struct urb *urb)
+{
+ struct xillybuffer *xb = urb->context;
+ struct xillyusb_endpoint *ep = xb->ep;
+ unsigned long flags;
+
+ if (urb->status &&
+ (!(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN)))
+ report_io_error(ep->xdev, -EIO);
+
+ spin_lock_irqsave(&ep->buffers_lock, flags);
+ list_add_tail(&xb->entry, &ep->buffers);
+ ep->outstanding_urbs--;
+ spin_unlock_irqrestore(&ep->buffers_lock, flags);
+
+ if (!ep->shutting_down)
+ queue_work(ep->xdev->workq, &ep->workitem);
+}
+
+static void try_queue_bulk_in(struct xillyusb_endpoint *ep)
+{
+ struct xillyusb_dev *xdev = ep->xdev;
+ struct xillybuffer *xb;
+ struct urb *urb;
+
+ int rc;
+ unsigned long flags;
+ unsigned int bufsize = ep->buffer_size;
+
+ mutex_lock(&ep->ep_mutex);
+
+ if (ep->shutting_down || xdev->error)
+ goto done;
+
+ while (1) {
+ spin_lock_irqsave(&ep->buffers_lock, flags);
+
+ if (list_empty(&ep->buffers)) {
+ spin_unlock_irqrestore(&ep->buffers_lock, flags);
+ goto done;
+ }
+
+ xb = list_first_entry(&ep->buffers, struct xillybuffer, entry);
+ list_del(&xb->entry);
+ ep->outstanding_urbs++;
+
+ spin_unlock_irqrestore(&ep->buffers_lock, flags);
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ report_io_error(xdev, -ENOMEM);
+ goto relist;
+ }
+
+ usb_fill_bulk_urb(urb, xdev->udev,
+ usb_rcvbulkpipe(xdev->udev, ep->ep_num),
+ xb->buf, bufsize, bulk_in_completer, xb);
+
+ usb_anchor_urb(urb, &ep->anchor);
+
+ rc = usb_submit_urb(urb, GFP_KERNEL);
+
+ if (rc) {
+ report_io_error(xdev, (rc == -ENOMEM) ? -ENOMEM :
+ -EIO);
+ goto unanchor;
+ }
+
+ usb_free_urb(urb); /* This just decrements reference count */
+ }
+
+unanchor:
+ usb_unanchor_urb(urb);
+ usb_free_urb(urb);
+
+relist:
+ spin_lock_irqsave(&ep->buffers_lock, flags);
+ list_add_tail(&xb->entry, &ep->buffers);
+ ep->outstanding_urbs--;
+ spin_unlock_irqrestore(&ep->buffers_lock, flags);
+
+done:
+ mutex_unlock(&ep->ep_mutex);
+}
+
+static void try_queue_bulk_out(struct xillyusb_endpoint *ep)
+{
+ struct xillyfifo *fifo = &ep->fifo;
+ struct xillyusb_dev *xdev = ep->xdev;
+ struct xillybuffer *xb;
+ struct urb *urb;
+
+ int rc;
+ unsigned int fill;
+ unsigned long flags;
+ bool do_wake = false;
+
+ mutex_lock(&ep->ep_mutex);
+
+ if (ep->shutting_down || xdev->error)
+ goto done;
+
+ fill = READ_ONCE(fifo->fill) & ep->fill_mask;
+
+ while (1) {
+ int count;
+ unsigned int max_read;
+
+ spin_lock_irqsave(&ep->buffers_lock, flags);
+
+ /*
+ * Race conditions might have the FIFO filled while the
+ * endpoint is marked as drained here. That doesn't matter,
+ * because the sole purpose of @drained is to ensure that
+ * certain data has been sent on the USB channel before
+ * shutting it down. Hence knowing that the FIFO appears
+ * to be empty with no outstanding URBs at some moment
+ * is good enough.
+ */
+
+ if (!fill) {
+ ep->drained = !ep->outstanding_urbs;
+ if (ep->drained && ep->wake_on_drain)
+ do_wake = true;
+
+ spin_unlock_irqrestore(&ep->buffers_lock, flags);
+ goto done;
+ }
+
+ ep->drained = false;
+
+ if ((fill < ep->buffer_size && ep->outstanding_urbs) ||
+ list_empty(&ep->buffers)) {
+ spin_unlock_irqrestore(&ep->buffers_lock, flags);
+ goto done;
+ }
+
+ xb = list_first_entry(&ep->buffers, struct xillybuffer, entry);
+ list_del(&xb->entry);
+ ep->outstanding_urbs++;
+
+ spin_unlock_irqrestore(&ep->buffers_lock, flags);
+
+ max_read = min(fill, ep->buffer_size);
+
+ count = fifo_read(&ep->fifo, xb->buf, max_read, xilly_memcpy);
+
+ /*
+ * xilly_memcpy always returns 0 => fifo_read can't fail =>
+ * count > 0
+ */
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ report_io_error(xdev, -ENOMEM);
+ goto relist;
+ }
+
+ usb_fill_bulk_urb(urb, xdev->udev,
+ usb_sndbulkpipe(xdev->udev, ep->ep_num),
+ xb->buf, count, bulk_out_completer, xb);
+
+ usb_anchor_urb(urb, &ep->anchor);
+
+ rc = usb_submit_urb(urb, GFP_KERNEL);
+
+ if (rc) {
+ report_io_error(xdev, (rc == -ENOMEM) ? -ENOMEM :
+ -EIO);
+ goto unanchor;
+ }
+
+ usb_free_urb(urb); /* This just decrements reference count */
+
+ fill -= count;
+ do_wake = true;
+ }
+
+unanchor:
+ usb_unanchor_urb(urb);
+ usb_free_urb(urb);
+
+relist:
+ spin_lock_irqsave(&ep->buffers_lock, flags);
+ list_add_tail(&xb->entry, &ep->buffers);
+ ep->outstanding_urbs--;
+ spin_unlock_irqrestore(&ep->buffers_lock, flags);
+
+done:
+ mutex_unlock(&ep->ep_mutex);
+
+ if (do_wake)
+ wake_up_interruptible(&fifo->waitq);
+}
+
+static void bulk_out_work(struct work_struct *work)
+{
+ struct xillyusb_endpoint *ep = container_of(work,
+ struct xillyusb_endpoint,
+ workitem);
+ try_queue_bulk_out(ep);
+}
+
+static int process_in_opcode(struct xillyusb_dev *xdev,
+ int opcode,
+ int chan_num)
+{
+ struct xillyusb_channel *chan;
+ struct device *dev = xdev->dev;
+ int chan_idx = chan_num >> 1;
+
+ if (chan_idx >= xdev->num_channels) {
+ dev_err(dev, "Received illegal channel ID %d from FPGA\n",
+ chan_num);
+ return -EIO;
+ }
+
+ chan = &xdev->channels[chan_idx];
+
+ switch (opcode) {
+ case OPCODE_EOF:
+ if (!chan->read_data_ok) {
+ dev_err(dev, "Received unexpected EOF for channel %d\n",
+ chan_num);
+ return -EIO;
+ }
+
+ /*
+ * A write memory barrier ensures that the FIFO's fill level
+ * is visible before read_data_ok turns zero, so the data in
+ * the FIFO isn't missed by the consumer.
+ */
+ smp_wmb();
+ WRITE_ONCE(chan->read_data_ok, 0);
+ wake_up_interruptible(&chan->in_fifo->waitq);
+ break;
+
+ case OPCODE_REACHED_CHECKPOINT:
+ chan->flushing = 0;
+ wake_up_interruptible(&chan->flushq);
+ break;
+
+ case OPCODE_CANCELED_CHECKPOINT:
+ chan->canceled = 1;
+ wake_up_interruptible(&chan->flushq);
+ break;
+
+ default:
+ dev_err(dev, "Received illegal opcode %d from FPGA\n",
+ opcode);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int process_bulk_in(struct xillybuffer *xb)
+{
+ struct xillyusb_endpoint *ep = xb->ep;
+ struct xillyusb_dev *xdev = ep->xdev;
+ struct device *dev = xdev->dev;
+ int dws = xb->len >> 2;
+ __le32 *p = xb->buf;
+ u32 ctrlword;
+ struct xillyusb_channel *chan;
+ struct xillyfifo *fifo;
+ int chan_num = 0, opcode;
+ int chan_idx;
+ int bytes, count, dwconsume;
+ int in_bytes_left = 0;
+ int rc;
+
+ if ((dws << 2) != xb->len) {
+ dev_err(dev, "Received BULK IN transfer with %d bytes, not a multiple of 4\n",
+ xb->len);
+ return -EIO;
+ }
+
+ if (xdev->in_bytes_left) {
+ bytes = min(xdev->in_bytes_left, dws << 2);
+ in_bytes_left = xdev->in_bytes_left - bytes;
+ chan_num = xdev->leftover_chan_num;
+ goto resume_leftovers;
+ }
+
+ while (dws) {
+ ctrlword = le32_to_cpu(*p++);
+ dws--;
+
+ chan_num = ctrlword & 0xfff;
+ count = (ctrlword >> 12) & 0x3ff;
+ opcode = (ctrlword >> 24) & 0xf;
+
+ if (opcode != OPCODE_DATA) {
+ unsigned int in_counter = xdev->in_counter++ & 0x3ff;
+
+ if (count != in_counter) {
+ dev_err(dev, "Expected opcode counter %d, got %d\n",
+ in_counter, count);
+ return -EIO;
+ }
+
+ rc = process_in_opcode(xdev, opcode, chan_num);
+
+ if (rc)
+ return rc;
+
+ continue;
+ }
+
+ bytes = min(count + 1, dws << 2);
+ in_bytes_left = count + 1 - bytes;
+
+resume_leftovers:
+ chan_idx = chan_num >> 1;
+
+ if (!(chan_num & 1) || chan_idx >= xdev->num_channels ||
+ !xdev->channels[chan_idx].read_data_ok) {
+ dev_err(dev, "Received illegal channel ID %d from FPGA\n",
+ chan_num);
+ return -EIO;
+ }
+ chan = &xdev->channels[chan_idx];
+
+ fifo = chan->in_fifo;
+
+ if (unlikely(!fifo))
+ return -EIO; /* We got really unexpected data */
+
+ if (bytes != fifo_write(fifo, p, bytes, xilly_memcpy)) {
+ dev_err(dev, "Misbehaving FPGA overflowed an upstream FIFO!\n");
+ return -EIO;
+ }
+
+ wake_up_interruptible(&fifo->waitq);
+
+ dwconsume = (bytes + 3) >> 2;
+ dws -= dwconsume;
+ p += dwconsume;
+ }
+
+ xdev->in_bytes_left = in_bytes_left;
+ xdev->leftover_chan_num = chan_num;
+ return 0;
+}
+
+static void bulk_in_work(struct work_struct *work)
+{
+ struct xillyusb_endpoint *ep =
+ container_of(work, struct xillyusb_endpoint, workitem);
+ struct xillyusb_dev *xdev = ep->xdev;
+ unsigned long flags;
+ struct xillybuffer *xb;
+ bool consumed = false;
+ int rc = 0;
+
+ mutex_lock(&xdev->process_in_mutex);
+
+ spin_lock_irqsave(&ep->buffers_lock, flags);
+
+ while (1) {
+ if (rc || list_empty(&ep->filled_buffers)) {
+ spin_unlock_irqrestore(&ep->buffers_lock, flags);
+ mutex_unlock(&xdev->process_in_mutex);
+
+ if (rc)
+ report_io_error(xdev, rc);
+ else if (consumed)
+ try_queue_bulk_in(ep);
+
+ return;
+ }
+
+ xb = list_first_entry(&ep->filled_buffers, struct xillybuffer,
+ entry);
+ list_del(&xb->entry);
+
+ spin_unlock_irqrestore(&ep->buffers_lock, flags);
+
+ consumed = true;
+
+ if (!xdev->error)
+ rc = process_bulk_in(xb);
+
+ spin_lock_irqsave(&ep->buffers_lock, flags);
+ list_add_tail(&xb->entry, &ep->buffers);
+ ep->outstanding_urbs--;
+ }
+}
+
+static int xillyusb_send_opcode(struct xillyusb_dev *xdev,
+ int chan_num, char opcode, u32 data)
+{
+ struct xillyusb_endpoint *ep = xdev->msg_ep;
+ struct xillyfifo *fifo = &ep->fifo;
+ __le32 msg[2];
+
+ int rc = 0;
+
+ msg[0] = cpu_to_le32((chan_num & 0xfff) |
+ ((opcode & 0xf) << 24));
+ msg[1] = cpu_to_le32(data);
+
+ mutex_lock(&xdev->msg_mutex);
+
+ /*
+ * The wait queue is woken with the interruptible variant, so the
+ * wait function matches, however returning because of an interrupt
+ * will mess things up considerably, in particular when the caller is
+ * the release method. And the xdev->error part prevents being stuck
+ * forever in the event of a bizarre hardware bug: Pull the USB plug.
+ */
+
+ while (wait_event_interruptible(fifo->waitq,
+ fifo->fill <= (fifo->size - 8) ||
+ xdev->error))
+ ; /* Empty loop */
+
+ if (xdev->error) {
+ rc = xdev->error;
+ goto unlock_done;
+ }
+
+ fifo_write(fifo, (void *)msg, 8, xilly_memcpy);
+
+ try_queue_bulk_out(ep);
+
+unlock_done:
+ mutex_unlock(&xdev->msg_mutex);
+
+ return rc;
+}
+
+/*
+ * Note that flush_downstream() merely waits for the data to arrive to
+ * the application logic at the FPGA -- unlike PCIe Xillybus' counterpart,
+ * it does nothing to make it happen (and neither is it necessary).
+ *
+ * This function is not reentrant for the same @chan, but this is covered
+ * by the fact that for any given @chan, it's called either by the open,
+ * write, llseek and flush fops methods, which can't run in parallel (and the
+ * write + flush and llseek method handlers are protected with out_mutex).
+ *
+ * chan->flushed is there to avoid multiple flushes at the same position,
+ * in particular as a result of programs that close the file descriptor
+ * e.g. after a dup2() for redirection.
+ */
+
+static int flush_downstream(struct xillyusb_channel *chan,
+ long timeout,
+ bool interruptible)
+{
+ struct xillyusb_dev *xdev = chan->xdev;
+ int chan_num = chan->chan_idx << 1;
+ long deadline, left_to_sleep;
+ int rc;
+
+ if (chan->flushed)
+ return 0;
+
+ deadline = jiffies + 1 + timeout;
+
+ if (chan->flushing) {
+ long cancel_deadline = jiffies + 1 + XILLY_RESPONSE_TIMEOUT;
+
+ chan->canceled = 0;
+ rc = xillyusb_send_opcode(xdev, chan_num,
+ OPCODE_CANCEL_CHECKPOINT, 0);
+
+ if (rc)
+ return rc; /* Only real error, never -EINTR */
+
+ /* Ignoring interrupts. Cancellation must be handled */
+ while (!chan->canceled) {
+ left_to_sleep = cancel_deadline - ((long)jiffies);
+
+ if (left_to_sleep <= 0) {
+ report_io_error(xdev, -EIO);
+ return -EIO;
+ }
+
+ rc = wait_event_interruptible_timeout(chan->flushq,
+ chan->canceled ||
+ xdev->error,
+ left_to_sleep);
+
+ if (xdev->error)
+ return xdev->error;
+ }
+ }
+
+ chan->flushing = 1;
+
+ /*
+ * The checkpoint is given in terms of data elements, not bytes. As
+ * a result, if less than an element's worth of data is stored in the
+ * FIFO, it's not flushed, including the flush before closing, which
+ * means that such data is lost. This is consistent with PCIe Xillybus.
+ */
+
+ rc = xillyusb_send_opcode(xdev, chan_num,
+ OPCODE_SET_CHECKPOINT,
+ chan->out_bytes >>
+ chan->out_log2_element_size);
+
+ if (rc)
+ return rc; /* Only real error, never -EINTR */
+
+ if (!timeout) {
+ while (chan->flushing) {
+ rc = wait_event_interruptible(chan->flushq,
+ !chan->flushing ||
+ xdev->error);
+ if (xdev->error)
+ return xdev->error;
+
+ if (interruptible && rc)
+ return -EINTR;
+ }
+
+ goto done;
+ }
+
+ while (chan->flushing) {
+ left_to_sleep = deadline - ((long)jiffies);
+
+ if (left_to_sleep <= 0)
+ return -ETIMEDOUT;
+
+ rc = wait_event_interruptible_timeout(chan->flushq,
+ !chan->flushing ||
+ xdev->error,
+ left_to_sleep);
+
+ if (xdev->error)
+ return xdev->error;
+
+ if (interruptible && rc < 0)
+ return -EINTR;
+ }
+
+done:
+ chan->flushed = 1;
+ return 0;
+}
+
+/* request_read_anything(): Ask the FPGA for any little amount of data */
+static int request_read_anything(struct xillyusb_channel *chan,
+ char opcode)
+{
+ struct xillyusb_dev *xdev = chan->xdev;
+ unsigned int sh = chan->in_log2_element_size;
+ int chan_num = (chan->chan_idx << 1) | 1;
+ u32 mercy = chan->in_consumed_bytes + (2 << sh) - 1;
+
+ return xillyusb_send_opcode(xdev, chan_num, opcode, mercy >> sh);
+}
+
+static int xillyusb_open(struct inode *inode, struct file *filp)
+{
+ struct xillyusb_dev *xdev;
+ struct xillyusb_channel *chan;
+ struct xillyfifo *in_fifo = NULL;
+ struct xillyusb_endpoint *out_ep = NULL;
+ int rc;
+ int index;
+
+ rc = xillybus_find_inode(inode, (void **)&xdev, &index);
+ if (rc)
+ return rc;
+
+ chan = &xdev->channels[index];
+ filp->private_data = chan;
+
+ mutex_lock(&chan->lock);
+
+ rc = -ENODEV;
+
+ if (xdev->error)
+ goto unmutex_fail;
+
+ if (((filp->f_mode & FMODE_READ) && !chan->readable) ||
+ ((filp->f_mode & FMODE_WRITE) && !chan->writable))
+ goto unmutex_fail;
+
+ if ((filp->f_flags & O_NONBLOCK) && (filp->f_mode & FMODE_READ) &&
+ chan->in_synchronous) {
+ dev_err(xdev->dev,
+ "open() failed: O_NONBLOCK not allowed for read on this device\n");
+ goto unmutex_fail;
+ }
+
+ if ((filp->f_flags & O_NONBLOCK) && (filp->f_mode & FMODE_WRITE) &&
+ chan->out_synchronous) {
+ dev_err(xdev->dev,
+ "open() failed: O_NONBLOCK not allowed for write on this device\n");
+ goto unmutex_fail;
+ }
+
+ rc = -EBUSY;
+
+ if (((filp->f_mode & FMODE_READ) && chan->open_for_read) ||
+ ((filp->f_mode & FMODE_WRITE) && chan->open_for_write))
+ goto unmutex_fail;
+
+ kref_get(&xdev->kref);
+
+ if (filp->f_mode & FMODE_READ)
+ chan->open_for_read = 1;
+
+ if (filp->f_mode & FMODE_WRITE)
+ chan->open_for_write = 1;
+
+ mutex_unlock(&chan->lock);
+
+ if (filp->f_mode & FMODE_WRITE) {
+ out_ep = endpoint_alloc(xdev,
+ (chan->chan_idx + 2) | USB_DIR_OUT,
+ bulk_out_work, BUF_SIZE_ORDER, BUFNUM);
+
+ if (!out_ep) {
+ rc = -ENOMEM;
+ goto unopen;
+ }
+
+ rc = fifo_init(&out_ep->fifo, chan->out_log2_fifo_size);
+
+ if (rc)
+ goto late_unopen;
+
+ out_ep->fill_mask = -(1 << chan->out_log2_element_size);
+ chan->out_bytes = 0;
+ chan->flushed = 0;
+
+ /*
+ * Sending a flush request to a previously closed stream
+ * effectively opens it, and also waits until the command is
+ * confirmed by the FPGA. The latter is necessary because the
+ * data is sent through a separate BULK OUT endpoint, and the
+ * xHCI controller is free to reorder transmissions.
+ *
+ * This can't go wrong unless there's a serious hardware error
+ * (or the computer is stuck for 500 ms?)
+ */
+ rc = flush_downstream(chan, XILLY_RESPONSE_TIMEOUT, false);
+
+ if (rc == -ETIMEDOUT) {
+ rc = -EIO;
+ report_io_error(xdev, rc);
+ }
+
+ if (rc)
+ goto late_unopen;
+ }
+
+ if (filp->f_mode & FMODE_READ) {
+ in_fifo = kzalloc(sizeof(*in_fifo), GFP_KERNEL);
+
+ if (!in_fifo) {
+ rc = -ENOMEM;
+ goto late_unopen;
+ }
+
+ rc = fifo_init(in_fifo, chan->in_log2_fifo_size);
+
+ if (rc) {
+ kfree(in_fifo);
+ goto late_unopen;
+ }
+ }
+
+ mutex_lock(&chan->lock);
+ if (in_fifo) {
+ chan->in_fifo = in_fifo;
+ chan->read_data_ok = 1;
+ }
+ if (out_ep)
+ chan->out_ep = out_ep;
+ mutex_unlock(&chan->lock);
+
+ if (in_fifo) {
+ u32 in_checkpoint = 0;
+
+ if (!chan->in_synchronous)
+ in_checkpoint = in_fifo->size >>
+ chan->in_log2_element_size;
+
+ chan->in_consumed_bytes = 0;
+ chan->poll_used = 0;
+ chan->in_current_checkpoint = in_checkpoint;
+ rc = xillyusb_send_opcode(xdev, (chan->chan_idx << 1) | 1,
+ OPCODE_SET_CHECKPOINT,
+ in_checkpoint);
+
+ if (rc) /* Failure guarantees that opcode wasn't sent */
+ goto unfifo;
+
+ /*
+ * In non-blocking mode, request the FPGA to send any data it
+ * has right away. Otherwise, the first read() will always
+ * return -EAGAIN, which is OK strictly speaking, but ugly.
+ * Checking and unrolling if this fails isn't worth the
+ * effort -- the error is propagated to the first read()
+ * anyhow.
+ */
+ if (filp->f_flags & O_NONBLOCK)
+ request_read_anything(chan, OPCODE_SET_PUSH);
+ }
+
+ return 0;
+
+unfifo:
+ chan->read_data_ok = 0;
+ safely_assign_in_fifo(chan, NULL);
+ fifo_mem_release(in_fifo);
+ kfree(in_fifo);
+
+ if (out_ep) {
+ mutex_lock(&chan->lock);
+ chan->out_ep = NULL;
+ mutex_unlock(&chan->lock);
+ }
+
+late_unopen:
+ if (out_ep)
+ endpoint_dealloc(out_ep);
+
+unopen:
+ mutex_lock(&chan->lock);
+
+ if (filp->f_mode & FMODE_READ)
+ chan->open_for_read = 0;
+
+ if (filp->f_mode & FMODE_WRITE)
+ chan->open_for_write = 0;
+
+ mutex_unlock(&chan->lock);
+
+ kref_put(&xdev->kref, cleanup_dev);
+
+ return rc;
+
+unmutex_fail:
+ mutex_unlock(&chan->lock);
+ return rc;
+}
+
+static ssize_t xillyusb_read(struct file *filp, char __user *userbuf,
+ size_t count, loff_t *f_pos)
+{
+ struct xillyusb_channel *chan = filp->private_data;
+ struct xillyusb_dev *xdev = chan->xdev;
+ struct xillyfifo *fifo = chan->in_fifo;
+ int chan_num = (chan->chan_idx << 1) | 1;
+
+ long deadline, left_to_sleep;
+ int bytes_done = 0;
+ bool sent_set_push = false;
+ int rc;
+
+ deadline = jiffies + 1 + XILLY_RX_TIMEOUT;
+
+ rc = mutex_lock_interruptible(&chan->in_mutex);
+
+ if (rc)
+ return rc;
+
+ while (1) {
+ u32 fifo_checkpoint_bytes, complete_checkpoint_bytes;
+ u32 complete_checkpoint, fifo_checkpoint;
+ u32 checkpoint;
+ s32 diff, leap;
+ unsigned int sh = chan->in_log2_element_size;
+ bool checkpoint_for_complete;
+
+ rc = fifo_read(fifo, (__force void *)userbuf + bytes_done,
+ count - bytes_done, xilly_copy_to_user);
+
+ if (rc < 0)
+ break;
+
+ bytes_done += rc;
+ chan->in_consumed_bytes += rc;
+
+ left_to_sleep = deadline - ((long)jiffies);
+
+ /*
+ * Some 32-bit arithmetic that may wrap. Note that
+ * complete_checkpoint is rounded up to the closest element
+ * boundary, because the read() can't be completed otherwise.
+ * fifo_checkpoint_bytes is rounded down, because it protects
+ * in_fifo from overflowing.
+ */
+
+ fifo_checkpoint_bytes = chan->in_consumed_bytes + fifo->size;
+ complete_checkpoint_bytes =
+ chan->in_consumed_bytes + count - bytes_done;
+
+ fifo_checkpoint = fifo_checkpoint_bytes >> sh;
+ complete_checkpoint =
+ (complete_checkpoint_bytes + (1 << sh) - 1) >> sh;
+
+ diff = (fifo_checkpoint - complete_checkpoint) << sh;
+
+ if (chan->in_synchronous && diff >= 0) {
+ checkpoint = complete_checkpoint;
+ checkpoint_for_complete = true;
+ } else {
+ checkpoint = fifo_checkpoint;
+ checkpoint_for_complete = false;
+ }
+
+ leap = (checkpoint - chan->in_current_checkpoint) << sh;
+
+ /*
+ * To prevent flooding of OPCODE_SET_CHECKPOINT commands as
+ * data is consumed, it's issued only if it moves the
+ * checkpoint by at least an 8th of the FIFO's size, or if
+ * it's necessary to complete the number of bytes requested by
+ * the read() call.
+ *
+ * chan->read_data_ok is checked to spare an unnecessary
+ * submission after receiving EOF, however it's harmless if
+ * such slips away.
+ */
+
+ if (chan->read_data_ok &&
+ (leap > (fifo->size >> 3) ||
+ (checkpoint_for_complete && leap > 0))) {
+ chan->in_current_checkpoint = checkpoint;
+ rc = xillyusb_send_opcode(xdev, chan_num,
+ OPCODE_SET_CHECKPOINT,
+ checkpoint);
+
+ if (rc)
+ break;
+ }
+
+ if (bytes_done == count ||
+ (left_to_sleep <= 0 && bytes_done))
+ break;
+
+ /*
+ * Reaching here means that the FIFO was empty when
+ * fifo_read() returned, but not necessarily right now. Error
+ * and EOF are checked and reported only now, so that no data
+ * that managed its way to the FIFO is lost.
+ */
+
+ if (!READ_ONCE(chan->read_data_ok)) { /* FPGA has sent EOF */
+ /* Has data slipped into the FIFO since fifo_read()? */
+ smp_rmb();
+ if (READ_ONCE(fifo->fill))
+ continue;
+
+ rc = 0;
+ break;
+ }
+
+ if (xdev->error) {
+ rc = xdev->error;
+ break;
+ }
+
+ if (filp->f_flags & O_NONBLOCK) {
+ rc = -EAGAIN;
+ break;
+ }
+
+ if (!sent_set_push) {
+ rc = xillyusb_send_opcode(xdev, chan_num,
+ OPCODE_SET_PUSH,
+ complete_checkpoint);
+
+ if (rc)
+ break;
+
+ sent_set_push = true;
+ }
+
+ if (left_to_sleep > 0) {
+ /*
+ * Note that when xdev->error is set (e.g. when the
+ * device is unplugged), read_data_ok turns zero and
+ * fifo->waitq is awaken.
+ * Therefore no special attention to xdev->error.
+ */
+
+ rc = wait_event_interruptible_timeout
+ (fifo->waitq,
+ fifo->fill || !chan->read_data_ok,
+ left_to_sleep);
+ } else { /* bytes_done == 0 */
+ /* Tell FPGA to send anything it has */
+ rc = request_read_anything(chan, OPCODE_UPDATE_PUSH);
+
+ if (rc)
+ break;
+
+ rc = wait_event_interruptible
+ (fifo->waitq,
+ fifo->fill || !chan->read_data_ok);
+ }
+
+ if (rc < 0) {
+ rc = -EINTR;
+ break;
+ }
+ }
+
+ if (((filp->f_flags & O_NONBLOCK) || chan->poll_used) &&
+ !READ_ONCE(fifo->fill))
+ request_read_anything(chan, OPCODE_SET_PUSH);
+
+ mutex_unlock(&chan->in_mutex);
+
+ if (bytes_done)
+ return bytes_done;
+
+ return rc;
+}
+
+static int xillyusb_flush(struct file *filp, fl_owner_t id)
+{
+ struct xillyusb_channel *chan = filp->private_data;
+ int rc;
+
+ if (!(filp->f_mode & FMODE_WRITE))
+ return 0;
+
+ rc = mutex_lock_interruptible(&chan->out_mutex);
+
+ if (rc)
+ return rc;
+
+ /*
+ * One second's timeout on flushing. Interrupts are ignored, because if
+ * the user pressed CTRL-C, that interrupt will still be in flight by
+ * the time we reach here, and the opportunity to flush is lost.
+ */
+ rc = flush_downstream(chan, HZ, false);
+
+ mutex_unlock(&chan->out_mutex);
+
+ if (rc == -ETIMEDOUT) {
+ /* The things you do to use dev_warn() and not pr_warn() */
+ struct xillyusb_dev *xdev = chan->xdev;
+
+ mutex_lock(&chan->lock);
+ if (!xdev->error)
+ dev_warn(xdev->dev,
+ "Timed out while flushing. Output data may be lost.\n");
+ mutex_unlock(&chan->lock);
+ }
+
+ return rc;
+}
+
+static ssize_t xillyusb_write(struct file *filp, const char __user *userbuf,
+ size_t count, loff_t *f_pos)
+{
+ struct xillyusb_channel *chan = filp->private_data;
+ struct xillyusb_dev *xdev = chan->xdev;
+ struct xillyfifo *fifo = &chan->out_ep->fifo;
+ int rc;
+
+ rc = mutex_lock_interruptible(&chan->out_mutex);
+
+ if (rc)
+ return rc;
+
+ while (1) {
+ if (xdev->error) {
+ rc = xdev->error;
+ break;
+ }
+
+ if (count == 0)
+ break;
+
+ rc = fifo_write(fifo, (__force void *)userbuf, count,
+ xilly_copy_from_user);
+
+ if (rc != 0)
+ break;
+
+ if (filp->f_flags & O_NONBLOCK) {
+ rc = -EAGAIN;
+ break;
+ }
+
+ if (wait_event_interruptible
+ (fifo->waitq,
+ fifo->fill != fifo->size || xdev->error)) {
+ rc = -EINTR;
+ break;
+ }
+ }
+
+ if (rc < 0)
+ goto done;
+
+ chan->out_bytes += rc;
+
+ if (rc) {
+ try_queue_bulk_out(chan->out_ep);
+ chan->flushed = 0;
+ }
+
+ if (chan->out_synchronous) {
+ int flush_rc = flush_downstream(chan, 0, true);
+
+ if (flush_rc && !rc)
+ rc = flush_rc;
+ }
+
+done:
+ mutex_unlock(&chan->out_mutex);
+
+ return rc;
+}
+
+static int xillyusb_release(struct inode *inode, struct file *filp)
+{
+ struct xillyusb_channel *chan = filp->private_data;
+ struct xillyusb_dev *xdev = chan->xdev;
+ int rc_read = 0, rc_write = 0;
+
+ if (filp->f_mode & FMODE_READ) {
+ struct xillyfifo *in_fifo = chan->in_fifo;
+
+ rc_read = xillyusb_send_opcode(xdev, (chan->chan_idx << 1) | 1,
+ OPCODE_CLOSE, 0);
+ /*
+ * If rc_read is nonzero, xdev->error indicates a global
+ * device error. The error is reported later, so that
+ * resources are freed.
+ *
+ * Looping on wait_event_interruptible() kinda breaks the idea
+ * of being interruptible, and this should have been
+ * wait_event(). Only it's being waken with
+ * wake_up_interruptible() for the sake of other uses. If
+ * there's a global device error, chan->read_data_ok is
+ * deasserted and the wait queue is awaken, so this is covered.
+ */
+
+ while (wait_event_interruptible(in_fifo->waitq,
+ !chan->read_data_ok))
+ ; /* Empty loop */
+
+ safely_assign_in_fifo(chan, NULL);
+ fifo_mem_release(in_fifo);
+ kfree(in_fifo);
+
+ mutex_lock(&chan->lock);
+ chan->open_for_read = 0;
+ mutex_unlock(&chan->lock);
+ }
+
+ if (filp->f_mode & FMODE_WRITE) {
+ struct xillyusb_endpoint *ep = chan->out_ep;
+ /*
+ * chan->flushing isn't zeroed. If the pre-release flush timed
+ * out, a cancel request will be sent before the next
+ * OPCODE_SET_CHECKPOINT (i.e. when the file is opened again).
+ * This is despite that the FPGA forgets about the checkpoint
+ * request as the file closes. Still, in an exceptional race
+ * condition, the FPGA could send an OPCODE_REACHED_CHECKPOINT
+ * just before closing that would reach the host after the
+ * file has re-opened.
+ */
+
+ mutex_lock(&chan->lock);
+ chan->out_ep = NULL;
+ mutex_unlock(&chan->lock);
+
+ endpoint_quiesce(ep);
+ endpoint_dealloc(ep);
+
+ /* See comments on rc_read above */
+ rc_write = xillyusb_send_opcode(xdev, chan->chan_idx << 1,
+ OPCODE_CLOSE, 0);
+
+ mutex_lock(&chan->lock);
+ chan->open_for_write = 0;
+ mutex_unlock(&chan->lock);
+ }
+
+ kref_put(&xdev->kref, cleanup_dev);
+
+ return rc_read ? rc_read : rc_write;
+}
+
+/*
+ * Xillybus' API allows device nodes to be seekable, giving the user
+ * application access to a RAM array on the FPGA (or logic emulating it).
+ */
+
+static loff_t xillyusb_llseek(struct file *filp, loff_t offset, int whence)
+{
+ struct xillyusb_channel *chan = filp->private_data;
+ struct xillyusb_dev *xdev = chan->xdev;
+ loff_t pos = filp->f_pos;
+ int rc = 0;
+ unsigned int log2_element_size = chan->readable ?
+ chan->in_log2_element_size : chan->out_log2_element_size;
+
+ /*
+ * Take both mutexes not allowing interrupts, since it seems like
+ * common applications don't expect an -EINTR here. Besides, multiple
+ * access to a single file descriptor on seekable devices is a mess
+ * anyhow.
+ */
+
+ mutex_lock(&chan->out_mutex);
+ mutex_lock(&chan->in_mutex);
+
+ switch (whence) {
+ case SEEK_SET:
+ pos = offset;
+ break;
+ case SEEK_CUR:
+ pos += offset;
+ break;
+ case SEEK_END:
+ pos = offset; /* Going to the end => to the beginning */
+ break;
+ default:
+ rc = -EINVAL;
+ goto end;
+ }
+
+ /* In any case, we must finish on an element boundary */
+ if (pos & ((1 << log2_element_size) - 1)) {
+ rc = -EINVAL;
+ goto end;
+ }
+
+ rc = xillyusb_send_opcode(xdev, chan->chan_idx << 1,
+ OPCODE_SET_ADDR,
+ pos >> log2_element_size);
+
+ if (rc)
+ goto end;
+
+ if (chan->writable) {
+ chan->flushed = 0;
+ rc = flush_downstream(chan, HZ, false);
+ }
+
+end:
+ mutex_unlock(&chan->out_mutex);
+ mutex_unlock(&chan->in_mutex);
+
+ if (rc) /* Return error after releasing mutexes */
+ return rc;
+
+ filp->f_pos = pos;
+
+ return pos;
+}
+
+static __poll_t xillyusb_poll(struct file *filp, poll_table *wait)
+{
+ struct xillyusb_channel *chan = filp->private_data;
+ __poll_t mask = 0;
+
+ if (chan->in_fifo)
+ poll_wait(filp, &chan->in_fifo->waitq, wait);
+
+ if (chan->out_ep)
+ poll_wait(filp, &chan->out_ep->fifo.waitq, wait);
+
+ /*
+ * If this is the first time poll() is called, and the file is
+ * readable, set the relevant flag. Also tell the FPGA to send all it
+ * has, to kickstart the mechanism that ensures there's always some
+ * data in in_fifo unless the stream is dry end-to-end. Note that the
+ * first poll() may not return a EPOLLIN, even if there's data on the
+ * FPGA. Rather, the data will arrive soon, and trigger the relevant
+ * wait queue.
+ */
+
+ if (!chan->poll_used && chan->in_fifo) {
+ chan->poll_used = 1;
+ request_read_anything(chan, OPCODE_SET_PUSH);
+ }
+
+ /*
+ * poll() won't play ball regarding read() channels which
+ * are synchronous. Allowing that will create situations where data has
+ * been delivered at the FPGA, and users expecting select() to wake up,
+ * which it may not. So make it never work.
+ */
+
+ if (chan->in_fifo && !chan->in_synchronous &&
+ (READ_ONCE(chan->in_fifo->fill) || !chan->read_data_ok))
+ mask |= EPOLLIN | EPOLLRDNORM;
+
+ if (chan->out_ep &&
+ (READ_ONCE(chan->out_ep->fifo.fill) != chan->out_ep->fifo.size))
+ mask |= EPOLLOUT | EPOLLWRNORM;
+
+ if (chan->xdev->error)
+ mask |= EPOLLERR;
+
+ return mask;
+}
+
+static const struct file_operations xillyusb_fops = {
+ .owner = THIS_MODULE,
+ .read = xillyusb_read,
+ .write = xillyusb_write,
+ .open = xillyusb_open,
+ .flush = xillyusb_flush,
+ .release = xillyusb_release,
+ .llseek = xillyusb_llseek,
+ .poll = xillyusb_poll,
+};
+
+static int xillyusb_setup_base_eps(struct xillyusb_dev *xdev)
+{
+ xdev->msg_ep = endpoint_alloc(xdev, MSG_EP_NUM | USB_DIR_OUT,
+ bulk_out_work, 1, 2);
+ if (!xdev->msg_ep)
+ return -ENOMEM;
+
+ if (fifo_init(&xdev->msg_ep->fifo, 13)) /* 8 kiB */
+ goto dealloc;
+
+ xdev->msg_ep->fill_mask = -8; /* 8 bytes granularity */
+
+ xdev->in_ep = endpoint_alloc(xdev, IN_EP_NUM | USB_DIR_IN,
+ bulk_in_work, BUF_SIZE_ORDER, BUFNUM);
+ if (!xdev->in_ep)
+ goto dealloc;
+
+ try_queue_bulk_in(xdev->in_ep);
+
+ return 0;
+
+dealloc:
+ endpoint_dealloc(xdev->msg_ep); /* Also frees FIFO mem if allocated */
+ return -ENOMEM;
+}
+
+static int setup_channels(struct xillyusb_dev *xdev,
+ __le16 *chandesc,
+ int num_channels)
+{
+ struct xillyusb_channel *chan;
+ int i;
+
+ chan = kcalloc(num_channels, sizeof(*chan), GFP_KERNEL);
+ if (!chan)
+ return -ENOMEM;
+
+ xdev->channels = chan;
+
+ for (i = 0; i < num_channels; i++, chan++) {
+ unsigned int in_desc = le16_to_cpu(*chandesc++);
+ unsigned int out_desc = le16_to_cpu(*chandesc++);
+
+ chan->xdev = xdev;
+ mutex_init(&chan->in_mutex);
+ mutex_init(&chan->out_mutex);
+ mutex_init(&chan->lock);
+ init_waitqueue_head(&chan->flushq);
+
+ chan->chan_idx = i;
+
+ if (in_desc & 0x80) { /* Entry is valid */
+ chan->readable = 1;
+ chan->in_synchronous = !!(in_desc & 0x40);
+ chan->in_seekable = !!(in_desc & 0x20);
+ chan->in_log2_element_size = in_desc & 0x0f;
+ chan->in_log2_fifo_size = ((in_desc >> 8) & 0x1f) + 16;
+ }
+
+ /*
+ * A downstream channel should never exist above index 13,
+ * as it would request a nonexistent BULK endpoint > 15.
+ * In the peculiar case that it does, it's ignored silently.
+ */
+
+ if ((out_desc & 0x80) && i < 14) { /* Entry is valid */
+ chan->writable = 1;
+ chan->out_synchronous = !!(out_desc & 0x40);
+ chan->out_seekable = !!(out_desc & 0x20);
+ chan->out_log2_element_size = out_desc & 0x0f;
+ chan->out_log2_fifo_size =
+ ((out_desc >> 8) & 0x1f) + 16;
+ }
+ }
+
+ return 0;
+}
+
+static int xillyusb_discovery(struct usb_interface *interface)
+{
+ int rc;
+ struct xillyusb_dev *xdev = usb_get_intfdata(interface);
+ __le16 bogus_chandesc[2];
+ struct xillyfifo idt_fifo;
+ struct xillyusb_channel *chan;
+ unsigned int idt_len, names_offset;
+ unsigned char *idt;
+ int num_channels;
+
+ rc = xillyusb_send_opcode(xdev, ~0, OPCODE_QUIESCE, 0);
+
+ if (rc) {
+ dev_err(&interface->dev, "Failed to send quiesce request. Aborting.\n");
+ return rc;
+ }
+
+ /* Phase I: Set up one fake upstream channel and obtain IDT */
+
+ /* Set up a fake IDT with one async IN stream */
+ bogus_chandesc[0] = cpu_to_le16(0x80);
+ bogus_chandesc[1] = cpu_to_le16(0);
+
+ rc = setup_channels(xdev, bogus_chandesc, 1);
+
+ if (rc)
+ return rc;
+
+ rc = fifo_init(&idt_fifo, LOG2_IDT_FIFO_SIZE);
+
+ if (rc)
+ return rc;
+
+ chan = xdev->channels;
+
+ chan->in_fifo = &idt_fifo;
+ chan->read_data_ok = 1;
+
+ xdev->num_channels = 1;
+
+ rc = xillyusb_send_opcode(xdev, ~0, OPCODE_REQ_IDT, 0);
+
+ if (rc) {
+ dev_err(&interface->dev, "Failed to send IDT request. Aborting.\n");
+ goto unfifo;
+ }
+
+ rc = wait_event_interruptible_timeout(idt_fifo.waitq,
+ !chan->read_data_ok,
+ XILLY_RESPONSE_TIMEOUT);
+
+ if (xdev->error) {
+ rc = xdev->error;
+ goto unfifo;
+ }
+
+ if (rc < 0) {
+ rc = -EINTR; /* Interrupt on probe method? Interesting. */
+ goto unfifo;
+ }
+
+ if (chan->read_data_ok) {
+ rc = -ETIMEDOUT;
+ dev_err(&interface->dev, "No response from FPGA. Aborting.\n");
+ goto unfifo;
+ }
+
+ idt_len = READ_ONCE(idt_fifo.fill);
+ idt = kmalloc(idt_len, GFP_KERNEL);
+
+ if (!idt) {
+ rc = -ENOMEM;
+ goto unfifo;
+ }
+
+ fifo_read(&idt_fifo, idt, idt_len, xilly_memcpy);
+
+ if (crc32_le(~0, idt, idt_len) != 0) {
+ dev_err(&interface->dev, "IDT failed CRC check. Aborting.\n");
+ rc = -ENODEV;
+ goto unidt;
+ }
+
+ if (*idt > 0x90) {
+ dev_err(&interface->dev, "No support for IDT version 0x%02x. Maybe the xillyusb driver needs an upgrade. Aborting.\n",
+ (int)*idt);
+ rc = -ENODEV;
+ goto unidt;
+ }
+
+ /* Phase II: Set up the streams as defined in IDT */
+
+ num_channels = le16_to_cpu(*((__le16 *)(idt + 1)));
+ names_offset = 3 + num_channels * 4;
+ idt_len -= 4; /* Exclude CRC */
+
+ if (idt_len < names_offset) {
+ dev_err(&interface->dev, "IDT too short. This is exceptionally weird, because its CRC is OK\n");
+ rc = -ENODEV;
+ goto unidt;
+ }
+
+ rc = setup_channels(xdev, (void *)idt + 3, num_channels);
+
+ if (rc)
+ goto unidt;
+
+ /*
+ * Except for wildly misbehaving hardware, or if it was disconnected
+ * just after responding with the IDT, there is no reason for any
+ * work item to be running now. To be sure that xdev->channels
+ * is updated on anything that might run in parallel, flush the
+ * workqueue, which rarely does anything.
+ */
+ flush_workqueue(xdev->workq);
+
+ xdev->num_channels = num_channels;
+
+ fifo_mem_release(&idt_fifo);
+ kfree(chan);
+
+ rc = xillybus_init_chrdev(&interface->dev, &xillyusb_fops,
+ THIS_MODULE, xdev,
+ idt + names_offset,
+ idt_len - names_offset,
+ num_channels,
+ xillyname, true);
+
+ kfree(idt);
+
+ return rc;
+
+unidt:
+ kfree(idt);
+
+unfifo:
+ safely_assign_in_fifo(chan, NULL);
+ fifo_mem_release(&idt_fifo);
+
+ return rc;
+}
+
+static int xillyusb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct xillyusb_dev *xdev;
+ int rc;
+
+ xdev = kzalloc(sizeof(*xdev), GFP_KERNEL);
+ if (!xdev)
+ return -ENOMEM;
+
+ kref_init(&xdev->kref);
+ mutex_init(&xdev->process_in_mutex);
+ mutex_init(&xdev->msg_mutex);
+
+ xdev->udev = usb_get_dev(interface_to_usbdev(interface));
+ xdev->dev = &interface->dev;
+ xdev->error = 0;
+ spin_lock_init(&xdev->error_lock);
+ xdev->in_counter = 0;
+ xdev->in_bytes_left = 0;
+ xdev->workq = alloc_workqueue(xillyname, WQ_HIGHPRI, 0);
+
+ if (!xdev->workq) {
+ dev_err(&interface->dev, "Failed to allocate work queue\n");
+ rc = -ENOMEM;
+ goto fail;
+ }
+
+ INIT_WORK(&xdev->wakeup_workitem, wakeup_all);
+
+ usb_set_intfdata(interface, xdev);
+
+ rc = xillyusb_setup_base_eps(xdev);
+ if (rc)
+ goto fail;
+
+ rc = xillyusb_discovery(interface);
+ if (rc)
+ goto latefail;
+
+ return 0;
+
+latefail:
+ endpoint_quiesce(xdev->in_ep);
+ endpoint_quiesce(xdev->msg_ep);
+
+fail:
+ usb_set_intfdata(interface, NULL);
+ kref_put(&xdev->kref, cleanup_dev);
+ return rc;
+}
+
+static void xillyusb_disconnect(struct usb_interface *interface)
+{
+ struct xillyusb_dev *xdev = usb_get_intfdata(interface);
+ struct xillyusb_endpoint *msg_ep = xdev->msg_ep;
+ struct xillyfifo *fifo = &msg_ep->fifo;
+ int rc;
+ int i;
+
+ xillybus_cleanup_chrdev(xdev, &interface->dev);
+
+ /*
+ * Try to send OPCODE_QUIESCE, which will fail silently if the device
+ * was disconnected, but makes sense on module unload.
+ */
+
+ msg_ep->wake_on_drain = true;
+ xillyusb_send_opcode(xdev, ~0, OPCODE_QUIESCE, 0);
+
+ /*
+ * If the device has been disconnected, sending the opcode causes
+ * a global device error with xdev->error, if such error didn't
+ * occur earlier. Hence timing out means that the USB link is fine,
+ * but somehow the message wasn't sent. Should never happen.
+ */
+
+ rc = wait_event_interruptible_timeout(fifo->waitq,
+ msg_ep->drained || xdev->error,
+ XILLY_RESPONSE_TIMEOUT);
+
+ if (!rc)
+ dev_err(&interface->dev,
+ "Weird timeout condition on sending quiesce request.\n");
+
+ report_io_error(xdev, -ENODEV); /* Discourage further activity */
+
+ /*
+ * This device driver is declared with soft_unbind set, or else
+ * sending OPCODE_QUIESCE above would always fail. The price is
+ * that the USB framework didn't kill outstanding URBs, so it has
+ * to be done explicitly before returning from this call.
+ */
+
+ for (i = 0; i < xdev->num_channels; i++) {
+ struct xillyusb_channel *chan = &xdev->channels[i];
+
+ /*
+ * Lock taken to prevent chan->out_ep from changing. It also
+ * ensures xillyusb_open() and xillyusb_flush() don't access
+ * xdev->dev after being nullified below.
+ */
+ mutex_lock(&chan->lock);
+ if (chan->out_ep)
+ endpoint_quiesce(chan->out_ep);
+ mutex_unlock(&chan->lock);
+ }
+
+ endpoint_quiesce(xdev->in_ep);
+ endpoint_quiesce(xdev->msg_ep);
+
+ usb_set_intfdata(interface, NULL);
+
+ xdev->dev = NULL;
+
+ kref_put(&xdev->kref, cleanup_dev);
+}
+
+static struct usb_driver xillyusb_driver = {
+ .name = xillyname,
+ .id_table = xillyusb_table,
+ .probe = xillyusb_probe,
+ .disconnect = xillyusb_disconnect,
+ .soft_unbind = 1,
+};
+
+static int __init xillyusb_init(void)
+{
+ int rc = 0;
+
+ if (LOG2_INITIAL_FIFO_BUF_SIZE > PAGE_SHIFT)
+ fifo_buf_order = LOG2_INITIAL_FIFO_BUF_SIZE - PAGE_SHIFT;
+ else
+ fifo_buf_order = 0;
+
+ rc = usb_register(&xillyusb_driver);
+
+ return rc;
+}
+
+static void __exit xillyusb_exit(void)
+{
+ usb_deregister(&xillyusb_driver);
+}
+
+module_init(xillyusb_init);
+module_exit(xillyusb_exit);
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index e80918be8e9c..e873f9ea2e65 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -6,10 +6,6 @@ config HAVE_CLK
The <linux/clk.h> calls support software clock gating and
thus are a key power management tool on many systems.
-config CLKDEV_LOOKUP
- bool
- select HAVE_CLK
-
config HAVE_CLK_PREPARE
bool
@@ -26,7 +22,7 @@ menuconfig COMMON_CLK
bool "Common Clock Framework"
depends on !HAVE_LEGACY_CLK
select HAVE_CLK_PREPARE
- select CLKDEV_LOOKUP
+ select HAVE_CLK
select SRCU
select RATIONAL
help
@@ -55,6 +51,14 @@ config CLK_HSDK
This driver supports the HSDK core, system, ddr, tunnel and hdmi PLLs
control.
+config LMK04832
+ tristate "Ti LMK04832 JESD204B Compliant Clock Jitter Cleaner"
+ depends on SPI
+ select REGMAP_SPI
+ help
+ Say yes here to build support for Texas Instruments' LMK04832 Ultra
+ Low-Noise JESD204B Compliant Clock Jitter Cleaner With Dual Loop PLLs
+
config COMMON_CLK_MAX77686
tristate "Clock driver for Maxim 77620/77686/77802 MFD"
depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST
@@ -335,6 +339,16 @@ config COMMON_CLK_STM32MP157
help
Support for stm32mp157 SoC family clocks
+config COMMON_CLK_STM32MP157_SCMI
+ bool "stm32mp157 Clock driver with Trusted Firmware"
+ depends on COMMON_CLK_STM32MP157
+ select COMMON_CLK_SCMI
+ select ARM_SCMI_PROTOCOL
+ default y
+ help
+ Support for stm32mp157 SoC family clocks with Trusted Firmware using
+ SCMI protocol.
+
config COMMON_CLK_STM32F
def_bool COMMON_CLK && (MACH_STM32F429 || MACH_STM32F469 || MACH_STM32F746)
help
@@ -358,10 +372,10 @@ config COMMON_CLK_MMP2_AUDIO
config COMMON_CLK_BD718XX
tristate "Clock driver for 32K clk gates on ROHM PMICs"
- depends on MFD_ROHM_BD718XX || MFD_ROHM_BD70528 || MFD_ROHM_BD71828
+ depends on MFD_ROHM_BD718XX || MFD_ROHM_BD71828
help
- This driver supports ROHM BD71837, ROHM BD71847, ROHM BD71828 and
- ROHM BD70528 PMICs clock gates.
+ This driver supports ROHM BD71837, BD71847, BD71850, BD71815
+ and BD71828 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 5f06879d7fe9..2b91d34c582b 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,7 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
# common clock types
-obj-$(CONFIG_HAVE_CLK) += clk-devres.o clk-bulk.o
-obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
+obj-$(CONFIG_HAVE_CLK) += clk-devres.o clk-bulk.o clkdev.o
obj-$(CONFIG_COMMON_CLK) += clk.o
obj-$(CONFIG_COMMON_CLK) += clk-divider.o
obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o
@@ -37,6 +36,7 @@ obj-$(CONFIG_MACH_ASPEED_G6) += clk-ast2600.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
obj-$(CONFIG_COMMON_CLK_K210) += clk-k210.o
+obj-$(CONFIG_LMK04832) += clk-lmk04832.o
obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o
diff --git a/drivers/clk/actions/owl-s500.c b/drivers/clk/actions/owl-s500.c
index 61bb224f6330..57d06e183dff 100644
--- a/drivers/clk/actions/owl-s500.c
+++ b/drivers/clk/actions/owl-s500.c
@@ -113,6 +113,7 @@ static const char * const sensor_clk_mux_p[] = { "hosc", "bisp_clk" };
static const char * const sd_clk_mux_p[] = { "dev_clk", "nand_pll_clk" };
static const char * const pwm_clk_mux_p[] = { "losc", "hosc" };
static const char * const ahbprediv_clk_mux_p[] = { "dev_clk", "display_pll_clk", "nand_pll_clk", "ddr_pll_clk" };
+static const char * const nic_clk_mux_p[] = { "dev_clk", "display_pll_clk", "nand_pll_clk", "ddr_pll_clk" };
static const char * const uart_clk_mux_p[] = { "hosc", "dev_pll_clk" };
static const char * const de_clk_mux_p[] = { "display_pll_clk", "dev_clk" };
static const char * const i2s_clk_mux_p[] = { "audio_pll_clk" };
@@ -127,8 +128,7 @@ static struct clk_factor_table sd_factor_table[] = {
{ 12, 1, 13 }, { 13, 1, 14 }, { 14, 1, 15 }, { 15, 1, 16 },
{ 16, 1, 17 }, { 17, 1, 18 }, { 18, 1, 19 }, { 19, 1, 20 },
{ 20, 1, 21 }, { 21, 1, 22 }, { 22, 1, 23 }, { 23, 1, 24 },
- { 24, 1, 25 }, { 25, 1, 26 }, { 26, 1, 27 }, { 27, 1, 28 },
- { 28, 1, 29 }, { 29, 1, 30 }, { 30, 1, 31 }, { 31, 1, 32 },
+ { 24, 1, 25 },
/* bit8: /128 */
{ 256, 1, 1 * 128 }, { 257, 1, 2 * 128 }, { 258, 1, 3 * 128 }, { 259, 1, 4 * 128 },
@@ -137,19 +137,20 @@ static struct clk_factor_table sd_factor_table[] = {
{ 268, 1, 13 * 128 }, { 269, 1, 14 * 128 }, { 270, 1, 15 * 128 }, { 271, 1, 16 * 128 },
{ 272, 1, 17 * 128 }, { 273, 1, 18 * 128 }, { 274, 1, 19 * 128 }, { 275, 1, 20 * 128 },
{ 276, 1, 21 * 128 }, { 277, 1, 22 * 128 }, { 278, 1, 23 * 128 }, { 279, 1, 24 * 128 },
- { 280, 1, 25 * 128 }, { 281, 1, 26 * 128 }, { 282, 1, 27 * 128 }, { 283, 1, 28 * 128 },
- { 284, 1, 29 * 128 }, { 285, 1, 30 * 128 }, { 286, 1, 31 * 128 }, { 287, 1, 32 * 128 },
+ { 280, 1, 25 * 128 },
{ 0, 0, 0 },
};
-static struct clk_factor_table bisp_factor_table[] = {
- { 0, 1, 1 }, { 1, 1, 2 }, { 2, 1, 3 }, { 3, 1, 4 },
- { 4, 1, 5 }, { 5, 1, 6 }, { 6, 1, 7 }, { 7, 1, 8 },
+static struct clk_factor_table de_factor_table[] = {
+ { 0, 1, 1 }, { 1, 2, 3 }, { 2, 1, 2 }, { 3, 2, 5 },
+ { 4, 1, 3 }, { 5, 1, 4 }, { 6, 1, 6 }, { 7, 1, 8 },
+ { 8, 1, 12 },
{ 0, 0, 0 },
};
-static struct clk_factor_table ahb_factor_table[] = {
- { 1, 1, 2 }, { 2, 1, 3 },
+static struct clk_factor_table hde_factor_table[] = {
+ { 0, 1, 1 }, { 1, 2, 3 }, { 2, 1, 2 }, { 3, 2, 5 },
+ { 4, 1, 3 }, { 5, 1, 4 }, { 6, 1, 6 }, { 7, 1, 8 },
{ 0, 0, 0 },
};
@@ -158,6 +159,13 @@ static struct clk_div_table rmii_ref_div_table[] = {
{ 0, 0 },
};
+static struct clk_div_table std12rate_div_table[] = {
+ { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
+ { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
+ { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
+ { 0, 0 },
+};
+
static struct clk_div_table i2s_div_table[] = {
{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
{ 4, 6 }, { 5, 8 }, { 6, 12 }, { 7, 16 },
@@ -174,7 +182,6 @@ static struct clk_div_table nand_div_table[] = {
/* mux clock */
static OWL_MUX(dev_clk, "dev_clk", dev_clk_mux_p, CMU_DEVPLL, 12, 1, CLK_SET_RATE_PARENT);
-static OWL_MUX(ahbprediv_clk, "ahbprediv_clk", ahbprediv_clk_mux_p, CMU_BUSCLK1, 8, 3, CLK_SET_RATE_PARENT);
/* gate clocks */
static OWL_GATE(gpio_clk, "gpio_clk", "apb_clk", CMU_DEVCLKEN0, 18, 0, 0);
@@ -187,45 +194,60 @@ static OWL_GATE(timer_clk, "timer_clk", "hosc", CMU_DEVCLKEN1, 27, 0, 0);
static OWL_GATE(hdmi_clk, "hdmi_clk", "hosc", CMU_DEVCLKEN1, 3, 0, 0);
/* divider clocks */
-static OWL_DIVIDER(h_clk, "h_clk", "ahbprediv_clk", CMU_BUSCLK1, 12, 2, NULL, 0, 0);
-static OWL_DIVIDER(apb_clk, "apb_clk", "ahb_clk", CMU_BUSCLK1, 14, 2, NULL, 0, 0);
+static OWL_DIVIDER(h_clk, "h_clk", "ahbprediv_clk", CMU_BUSCLK1, 2, 2, NULL, 0, 0);
+static OWL_DIVIDER(apb_clk, "apb_clk", "nic_clk", CMU_BUSCLK1, 14, 2, NULL, 0, 0);
static OWL_DIVIDER(rmii_ref_clk, "rmii_ref_clk", "ethernet_pll_clk", CMU_ETHERNETPLL, 1, 1, rmii_ref_div_table, 0, 0);
/* factor clocks */
-static OWL_FACTOR(ahb_clk, "ahb_clk", "h_clk", CMU_BUSCLK1, 2, 2, ahb_factor_table, 0, 0);
-static OWL_FACTOR(de1_clk, "de_clk1", "de_clk", CMU_DECLK, 0, 3, bisp_factor_table, 0, 0);
-static OWL_FACTOR(de2_clk, "de_clk2", "de_clk", CMU_DECLK, 4, 3, bisp_factor_table, 0, 0);
+static OWL_FACTOR(de1_clk, "de_clk1", "de_clk", CMU_DECLK, 0, 4, de_factor_table, 0, 0);
+static OWL_FACTOR(de2_clk, "de_clk2", "de_clk", CMU_DECLK, 4, 4, de_factor_table, 0, 0);
/* composite clocks */
+static OWL_COMP_DIV(nic_clk, "nic_clk", nic_clk_mux_p,
+ OWL_MUX_HW(CMU_BUSCLK1, 4, 3),
+ { 0 },
+ OWL_DIVIDER_HW(CMU_BUSCLK1, 16, 2, 0, NULL),
+ 0);
+
+static OWL_COMP_DIV(ahbprediv_clk, "ahbprediv_clk", ahbprediv_clk_mux_p,
+ OWL_MUX_HW(CMU_BUSCLK1, 8, 3),
+ { 0 },
+ OWL_DIVIDER_HW(CMU_BUSCLK1, 12, 2, 0, NULL),
+ CLK_SET_RATE_PARENT);
+
+static OWL_COMP_FIXED_FACTOR(ahb_clk, "ahb_clk", "h_clk",
+ { 0 },
+ 1, 1, 0);
+
static OWL_COMP_FACTOR(vce_clk, "vce_clk", hde_clk_mux_p,
OWL_MUX_HW(CMU_VCECLK, 4, 2),
OWL_GATE_HW(CMU_DEVCLKEN0, 26, 0),
- OWL_FACTOR_HW(CMU_VCECLK, 0, 3, 0, bisp_factor_table),
+ OWL_FACTOR_HW(CMU_VCECLK, 0, 3, 0, hde_factor_table),
0);
static OWL_COMP_FACTOR(vde_clk, "vde_clk", hde_clk_mux_p,
OWL_MUX_HW(CMU_VDECLK, 4, 2),
OWL_GATE_HW(CMU_DEVCLKEN0, 25, 0),
- OWL_FACTOR_HW(CMU_VDECLK, 0, 3, 0, bisp_factor_table),
+ OWL_FACTOR_HW(CMU_VDECLK, 0, 3, 0, hde_factor_table),
0);
-static OWL_COMP_FACTOR(bisp_clk, "bisp_clk", bisp_clk_mux_p,
+static OWL_COMP_DIV(bisp_clk, "bisp_clk", bisp_clk_mux_p,
OWL_MUX_HW(CMU_BISPCLK, 4, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0),
- OWL_FACTOR_HW(CMU_BISPCLK, 0, 3, 0, bisp_factor_table),
+ OWL_DIVIDER_HW(CMU_BISPCLK, 0, 4, 0, std12rate_div_table),
0);
-static OWL_COMP_FACTOR(sensor0_clk, "sensor0_clk", sensor_clk_mux_p,
+static OWL_COMP_DIV(sensor0_clk, "sensor0_clk", sensor_clk_mux_p,
OWL_MUX_HW(CMU_SENSORCLK, 4, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0),
- OWL_FACTOR_HW(CMU_SENSORCLK, 0, 3, 0, bisp_factor_table),
- CLK_IGNORE_UNUSED);
+ OWL_DIVIDER_HW(CMU_SENSORCLK, 0, 4, 0, std12rate_div_table),
+ 0);
-static OWL_COMP_FACTOR(sensor1_clk, "sensor1_clk", sensor_clk_mux_p,
+static OWL_COMP_DIV(sensor1_clk, "sensor1_clk", sensor_clk_mux_p,
OWL_MUX_HW(CMU_SENSORCLK, 4, 1),
OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0),
- OWL_FACTOR_HW(CMU_SENSORCLK, 8, 3, 0, bisp_factor_table),
- CLK_IGNORE_UNUSED);
+ OWL_DIVIDER_HW(CMU_SENSORCLK, 8, 4, 0, std12rate_div_table),
+ 0);
static OWL_COMP_FACTOR(sd0_clk, "sd0_clk", sd_clk_mux_p,
OWL_MUX_HW(CMU_SD0CLK, 9, 1),
@@ -302,10 +324,14 @@ static OWL_COMP_FIXED_FACTOR(i2c3_clk, "i2c3_clk", "ethernet_pll_clk",
OWL_GATE_HW(CMU_DEVCLKEN1, 31, 0),
1, 5, 0);
+static OWL_COMP_FIXED_FACTOR(ethernet_clk, "ethernet_clk", "ethernet_pll_clk",
+ OWL_GATE_HW(CMU_DEVCLKEN1, 22, 0),
+ 1, 20, 0);
+
static OWL_COMP_DIV(uart0_clk, "uart0_clk", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART0CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 6, 0),
- OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
+ OWL_DIVIDER_HW(CMU_UART0CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
CLK_IGNORE_UNUSED);
static OWL_COMP_DIV(uart1_clk, "uart1_clk", uart_clk_mux_p,
@@ -317,31 +343,31 @@ static OWL_COMP_DIV(uart1_clk, "uart1_clk", uart_clk_mux_p,
static OWL_COMP_DIV(uart2_clk, "uart2_clk", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART2CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 8, 0),
- OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
+ OWL_DIVIDER_HW(CMU_UART2CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
CLK_IGNORE_UNUSED);
static OWL_COMP_DIV(uart3_clk, "uart3_clk", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART3CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 19, 0),
- OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
+ OWL_DIVIDER_HW(CMU_UART3CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
CLK_IGNORE_UNUSED);
static OWL_COMP_DIV(uart4_clk, "uart4_clk", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART4CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 20, 0),
- OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
+ OWL_DIVIDER_HW(CMU_UART4CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
CLK_IGNORE_UNUSED);
static OWL_COMP_DIV(uart5_clk, "uart5_clk", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART5CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 21, 0),
- OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
+ OWL_DIVIDER_HW(CMU_UART5CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
CLK_IGNORE_UNUSED);
static OWL_COMP_DIV(uart6_clk, "uart6_clk", uart_clk_mux_p,
OWL_MUX_HW(CMU_UART6CLK, 16, 1),
OWL_GATE_HW(CMU_DEVCLKEN1, 18, 0),
- OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
+ OWL_DIVIDER_HW(CMU_UART6CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL),
CLK_IGNORE_UNUSED);
static OWL_COMP_DIV(i2srx_clk, "i2srx_clk", i2s_clk_mux_p,
@@ -436,6 +462,8 @@ static struct owl_clk_common *s500_clks[] = {
&apb_clk.common,
&dmac_clk.common,
&gpio_clk.common,
+ &nic_clk.common,
+ &ethernet_clk.common,
};
static struct clk_hw_onecell_data s500_hw_clks = {
@@ -495,6 +523,8 @@ static struct clk_hw_onecell_data s500_hw_clks = {
[CLK_APB] = &apb_clk.common.hw,
[CLK_DMAC] = &dmac_clk.common.hw,
[CLK_GPIO] = &gpio_clk.common.hw,
+ [CLK_NIC] = &nic_clk.common.hw,
+ [CLK_ETHERNET] = &ethernet_clk.common.hw,
},
.num = CLK_NR_CLKS,
};
diff --git a/drivers/clk/analogbits/wrpll-cln28hpc.c b/drivers/clk/analogbits/wrpll-cln28hpc.c
index 776ead319ae9..09ca82356399 100644
--- a/drivers/clk/analogbits/wrpll-cln28hpc.c
+++ b/drivers/clk/analogbits/wrpll-cln28hpc.c
@@ -23,8 +23,12 @@
#include <linux/bug.h>
#include <linux/err.h>
+#include <linux/limits.h>
#include <linux/log2.h>
#include <linux/math64.h>
+#include <linux/math.h>
+#include <linux/minmax.h>
+
#include <linux/clk/analogbits-wrpll-cln28hpc.h>
/* MIN_INPUT_FREQ: minimum input clock frequency, in Hz (Fref_min) */
@@ -198,7 +202,7 @@ static int __wrpll_update_parent_rate(struct wrpll_cfg *c,
}
/**
- * wrpll_configure() - compute PLL configuration for a target rate
+ * wrpll_configure_for_rate() - compute PLL configuration for a target rate
* @c: ptr to a struct wrpll_cfg record to write into
* @target_rate: target PLL output clock rate (post-Q-divider)
* @parent_rate: PLL input refclk rate (pre-R-divider)
diff --git a/drivers/clk/clk-bd718x7.c b/drivers/clk/clk-bd718x7.c
index d9e70e506d18..ac40b669d60b 100644
--- a/drivers/clk/clk-bd718x7.c
+++ b/drivers/clk/clk-bd718x7.c
@@ -15,15 +15,13 @@
/* clk control registers */
/* BD71815 */
#define BD71815_REG_OUT32K 0x1d
-/* BD70528 */
-#define BD70528_REG_OUT32K 0x2c
/* BD71828 */
#define BD71828_REG_OUT32K 0x4B
/* BD71837 and BD71847 */
#define BD718XX_REG_OUT32K 0x2E
/*
- * BD71837, BD71847, BD70528 and BD71828 all use bit [0] to clk output control
+ * BD71837, BD71847, and BD71828 all use bit [0] to clk output control
*/
#define CLK_OUT_EN_MASK BIT(0)
@@ -116,10 +114,6 @@ static int bd71837_clk_probe(struct platform_device *pdev)
c->reg = BD71828_REG_OUT32K;
c->mask = CLK_OUT_EN_MASK;
break;
- case ROHM_CHIP_TYPE_BD70528:
- c->reg = BD70528_REG_OUT32K;
- c->mask = CLK_OUT_EN_MASK;
- break;
case ROHM_CHIP_TYPE_BD71815:
c->reg = BD71815_REG_OUT32K;
c->mask = CLK_OUT_EN_MASK;
@@ -150,7 +144,6 @@ static int bd71837_clk_probe(struct platform_device *pdev)
static const struct platform_device_id bd718x7_clk_id[] = {
{ "bd71837-clk", ROHM_CHIP_TYPE_BD71837 },
{ "bd71847-clk", ROHM_CHIP_TYPE_BD71847 },
- { "bd70528-clk", ROHM_CHIP_TYPE_BD70528 },
{ "bd71828-clk", ROHM_CHIP_TYPE_BD71828 },
{ "bd71815-clk", ROHM_CHIP_TYPE_BD71815 },
{ },
@@ -168,6 +161,6 @@ static struct platform_driver bd71837_clk = {
module_platform_driver(bd71837_clk);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("BD718(15/18/28/37/47/50) and BD70528 chip clk driver");
+MODULE_DESCRIPTION("BD718(15/18/28/37/47/50) and chip clk driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:bd718xx-clk");
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 344997203f0e..87ba4966b0e8 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -343,16 +343,63 @@ static int clk_divider_bestdiv(struct clk_hw *hw, struct clk_hw *parent,
return bestdiv;
}
+int divider_determine_rate(struct clk_hw *hw, struct clk_rate_request *req,
+ const struct clk_div_table *table, u8 width,
+ unsigned long flags)
+{
+ int div;
+
+ div = clk_divider_bestdiv(hw, req->best_parent_hw, req->rate,
+ &req->best_parent_rate, table, width, flags);
+
+ req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(divider_determine_rate);
+
+int divider_ro_determine_rate(struct clk_hw *hw, struct clk_rate_request *req,
+ const struct clk_div_table *table, u8 width,
+ unsigned long flags, unsigned int val)
+{
+ int div;
+
+ div = _get_div(table, val, flags, width);
+
+ /* Even a read-only clock can propagate a rate change */
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
+ if (!req->best_parent_hw)
+ return -EINVAL;
+
+ req->best_parent_rate = clk_hw_round_rate(req->best_parent_hw,
+ req->rate * div);
+ }
+
+ req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(divider_ro_determine_rate);
+
long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent,
unsigned long rate, unsigned long *prate,
const struct clk_div_table *table,
u8 width, unsigned long flags)
{
- int div;
+ struct clk_rate_request req = {
+ .rate = rate,
+ .best_parent_rate = *prate,
+ .best_parent_hw = parent,
+ };
+ int ret;
- div = clk_divider_bestdiv(hw, parent, rate, prate, table, width, flags);
+ ret = divider_determine_rate(hw, &req, table, width, flags);
+ if (ret)
+ return ret;
- return DIV_ROUND_UP_ULL((u64)*prate, div);
+ *prate = req.best_parent_rate;
+
+ return req.rate;
}
EXPORT_SYMBOL_GPL(divider_round_rate_parent);
@@ -361,23 +408,23 @@ long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent,
const struct clk_div_table *table, u8 width,
unsigned long flags, unsigned int val)
{
- int div;
-
- div = _get_div(table, val, flags, width);
+ struct clk_rate_request req = {
+ .rate = rate,
+ .best_parent_rate = *prate,
+ .best_parent_hw = parent,
+ };
+ int ret;
- /* Even a read-only clock can propagate a rate change */
- if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
- if (!parent)
- return -EINVAL;
+ ret = divider_ro_determine_rate(hw, &req, table, width, flags, val);
+ if (ret)
+ return ret;
- *prate = clk_hw_round_rate(parent, rate * div);
- }
+ *prate = req.best_parent_rate;
- return DIV_ROUND_UP_ULL((u64)*prate, div);
+ return req.rate;
}
EXPORT_SYMBOL_GPL(divider_ro_round_rate_parent);
-
static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
diff --git a/drivers/clk/clk-k210.c b/drivers/clk/clk-k210.c
index 6c84abf5b2e3..67a7cb3503c3 100644
--- a/drivers/clk/clk-k210.c
+++ b/drivers/clk/clk-k210.c
@@ -722,6 +722,7 @@ static int k210_clk_set_parent(struct clk_hw *hw, u8 index)
reg |= BIT(cfg->mux_bit);
else
reg &= ~BIT(cfg->mux_bit);
+ writel(reg, ksc->regs + cfg->mux_reg);
spin_unlock_irqrestore(&ksc->clk_lock, flags);
return 0;
diff --git a/drivers/clk/clk-lmk04832.c b/drivers/clk/clk-lmk04832.c
new file mode 100644
index 000000000000..c7a3a029fb1e
--- /dev/null
+++ b/drivers/clk/clk-lmk04832.c
@@ -0,0 +1,1599 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * LMK04832 Ultra Low-Noise JESD204B Compliant Clock Jitter Cleaner
+ * Pin compatible with the LMK0482x family
+ *
+ * Datasheet: https://www.ti.com/lit/ds/symlink/lmk04832.pdf
+ *
+ * Copyright (c) 2020, Xiphos Systems Corp.
+ *
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/gcd.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+/* 0x000 - 0x00d System Functions */
+#define LMK04832_REG_RST3W 0x000
+#define LMK04832_BIT_RESET BIT(7)
+#define LMK04832_BIT_SPI_3WIRE_DIS BIT(4)
+#define LMK04832_REG_POWERDOWN 0x002
+#define LMK04832_REG_ID_DEV_TYPE 0x003
+#define LMK04832_REG_ID_PROD_MSB 0x004
+#define LMK04832_REG_ID_PROD_LSB 0x005
+#define LMK04832_REG_ID_MASKREV 0x006
+#define LMK04832_REG_ID_VNDR_MSB 0x00c
+#define LMK04832_REG_ID_VNDR_LSB 0x00d
+
+/* 0x100 - 0x137 Device Clock and SYSREF Clock Output Control */
+#define LMK04832_REG_CLKOUT_CTRL0(ch) (0x100 + (ch >> 1) * 8)
+#define LMK04832_BIT_DCLK_DIV_LSB GENMASK(7, 0)
+#define LMK04832_REG_CLKOUT_CTRL1(ch) (0x101 + (ch >> 1) * 8)
+#define LMK04832_BIT_DCLKX_Y_DDLY_LSB GENMASK(7, 0)
+#define LMK04832_REG_CLKOUT_CTRL2(ch) (0x102 + (ch >> 1) * 8)
+#define LMK04832_BIT_CLKOUTX_Y_PD BIT(7)
+#define LMK04832_BIT_DCLKX_Y_DDLY_PD BIT(4)
+#define LMK04832_BIT_DCLKX_Y_DDLY_MSB GENMASK(3, 2)
+#define LMK04832_BIT_DCLK_DIV_MSB GENMASK(1, 0)
+#define LMK04832_REG_CLKOUT_SRC_MUX(ch) (0x103 + (ch % 2) + (ch >> 1) * 8)
+#define LMK04832_BIT_CLKOUT_SRC_MUX BIT(5)
+#define LMK04832_REG_CLKOUT_CTRL3(ch) (0x103 + (ch >> 1) * 8)
+#define LMK04832_BIT_DCLKX_Y_PD BIT(4)
+#define LMK04832_BIT_DCLKX_Y_DCC BIT(2)
+#define LMK04832_BIT_DCLKX_Y_HS BIT(0)
+#define LMK04832_REG_CLKOUT_CTRL4(ch) (0x104 + (ch >> 1) * 8)
+#define LMK04832_BIT_SCLK_PD BIT(4)
+#define LMK04832_BIT_SCLKX_Y_DIS_MODE GENMASK(3, 2)
+#define LMK04832_REG_SCLKX_Y_ADLY(ch) (0x105 + (ch >> 1) * 8)
+#define LMK04832_REG_SCLKX_Y_DDLY(ch) (0x106 + (ch >> 1) * 8)
+#define LMK04832_BIT_SCLKX_Y_DDLY GENMASK(3, 0)
+#define LMK04832_REG_CLKOUT_FMT(ch) (0x107 + (ch >> 1) * 8)
+#define LMK04832_BIT_CLKOUT_FMT(ch) (ch % 2 ? 0xf0 : 0x0f)
+#define LMK04832_VAL_CLKOUT_FMT_POWERDOWN 0x00
+#define LMK04832_VAL_CLKOUT_FMT_LVDS 0x01
+#define LMK04832_VAL_CLKOUT_FMT_HSDS6 0x02
+#define LMK04832_VAL_CLKOUT_FMT_HSDS8 0x03
+#define LMK04832_VAL_CLKOUT_FMT_LVPECL1600 0x04
+#define LMK04832_VAL_CLKOUT_FMT_LVPECL2000 0x05
+#define LMK04832_VAL_CLKOUT_FMT_LCPECL 0x06
+#define LMK04832_VAL_CLKOUT_FMT_CML16 0x07
+#define LMK04832_VAL_CLKOUT_FMT_CML24 0x08
+#define LMK04832_VAL_CLKOUT_FMT_CML32 0x09
+#define LMK04832_VAL_CLKOUT_FMT_CMOS_OFF_INV 0x0a
+#define LMK04832_VAL_CLKOUT_FMT_CMOS_NOR_OFF 0x0b
+#define LMK04832_VAL_CLKOUT_FMT_CMOS_INV_INV 0x0c
+#define LMK04832_VAL_CLKOUT_FMT_CMOS_INV_NOR 0x0d
+#define LMK04832_VAL_CLKOUT_FMT_CMOS_NOR_INV 0x0e
+#define LMK04832_VAL_CLKOUT_FMT_CMOS_NOR_NOR 0x0f
+
+/* 0x138 - 0x145 SYSREF, SYNC, and Device Config */
+#define LMK04832_REG_VCO_OSCOUT 0x138
+#define LMK04832_BIT_VCO_MUX GENMASK(6, 5)
+#define LMK04832_VAL_VCO_MUX_VCO0 0x00
+#define LMK04832_VAL_VCO_MUX_VCO1 0x01
+#define LMK04832_VAL_VCO_MUX_EXT 0x02
+#define LMK04832_REG_SYSREF_OUT 0x139
+#define LMK04832_BIT_SYSREF_REQ_EN BIT(6)
+#define LMK04832_BIT_SYSREF_MUX GENMASK(1, 0)
+#define LMK04832_VAL_SYSREF_MUX_NORMAL_SYNC 0x00
+#define LMK04832_VAL_SYSREF_MUX_RECLK 0x01
+#define LMK04832_VAL_SYSREF_MUX_PULSER 0x02
+#define LMK04832_VAL_SYSREF_MUX_CONTINUOUS 0x03
+#define LMK04832_REG_SYSREF_DIV_MSB 0x13a
+#define LMK04832_BIT_SYSREF_DIV_MSB GENMASK(4, 0)
+#define LMK04832_REG_SYSREF_DIV_LSB 0x13b
+#define LMK04832_REG_SYSREF_DDLY_MSB 0x13c
+#define LMK04832_BIT_SYSREF_DDLY_MSB GENMASK(4, 0)
+#define LMK04832_REG_SYSREF_DDLY_LSB 0x13d
+#define LMK04832_REG_SYSREF_PULSE_CNT 0x13e
+#define LMK04832_REG_FB_CTRL 0x13f
+#define LMK04832_BIT_PLL2_RCLK_MUX BIT(7)
+#define LMK04832_VAL_PLL2_RCLK_MUX_OSCIN 0x00
+#define LMK04832_VAL_PLL2_RCLK_MUX_CLKIN 0x01
+#define LMK04832_BIT_PLL2_NCLK_MUX BIT(5)
+#define LMK04832_VAL_PLL2_NCLK_MUX_PLL2_P 0x00
+#define LMK04832_VAL_PLL2_NCLK_MUX_FB_MUX 0x01
+#define LMK04832_BIT_FB_MUX_EN BIT(0)
+#define LMK04832_REG_MAIN_PD 0x140
+#define LMK04832_BIT_PLL1_PD BIT(7)
+#define LMK04832_BIT_VCO_LDO_PD BIT(6)
+#define LMK04832_BIT_VCO_PD BIT(5)
+#define LMK04832_BIT_OSCIN_PD BIT(4)
+#define LMK04832_BIT_SYSREF_GBL_PD BIT(3)
+#define LMK04832_BIT_SYSREF_PD BIT(2)
+#define LMK04832_BIT_SYSREF_DDLY_PD BIT(1)
+#define LMK04832_BIT_SYSREF_PLSR_PD BIT(0)
+#define LMK04832_REG_SYNC 0x143
+#define LMK04832_BIT_SYNC_CLR BIT(7)
+#define LMK04832_BIT_SYNC_1SHOT_EN BIT(6)
+#define LMK04832_BIT_SYNC_POL BIT(5)
+#define LMK04832_BIT_SYNC_EN BIT(4)
+#define LMK04832_BIT_SYNC_MODE GENMASK(1, 0)
+#define LMK04832_VAL_SYNC_MODE_OFF 0x00
+#define LMK04832_VAL_SYNC_MODE_ON 0x01
+#define LMK04832_VAL_SYNC_MODE_PULSER_PIN 0x02
+#define LMK04832_VAL_SYNC_MODE_PULSER_SPI 0x03
+#define LMK04832_REG_SYNC_DIS 0x144
+
+/* 0x146 - 0x14a CLKin Control */
+#define LMK04832_REG_CLKIN_SEL0 0x148
+#define LMK04832_REG_CLKIN_SEL1 0x149
+#define LMK04832_REG_CLKIN_RST 0x14a
+#define LMK04832_BIT_SDIO_RDBK_TYPE BIT(6)
+#define LMK04832_BIT_CLKIN_SEL_MUX GENMASK(5, 3)
+#define LMK04832_VAL_CLKIN_SEL_MUX_SPI_RDBK 0x06
+#define LMK04832_BIT_CLKIN_SEL_TYPE GENMASK(2, 0)
+#define LMK04832_VAL_CLKIN_SEL_TYPE_OUT 0x03
+
+/* 0x14b - 0x152 Holdover */
+
+/* 0x153 - 0x15f PLL1 Configuration */
+
+/* 0x160 - 0x16e PLL2 Configuration */
+#define LMK04832_REG_PLL2_R_MSB 0x160
+#define LMK04832_BIT_PLL2_R_MSB GENMASK(3, 0)
+#define LMK04832_REG_PLL2_R_LSB 0x161
+#define LMK04832_REG_PLL2_MISC 0x162
+#define LMK04832_BIT_PLL2_MISC_P GENMASK(7, 5)
+#define LMK04832_BIT_PLL2_MISC_REF_2X_EN BIT(0)
+#define LMK04832_REG_PLL2_N_CAL_0 0x163
+#define LMK04832_BIT_PLL2_N_CAL_0 GENMASK(1, 0)
+#define LMK04832_REG_PLL2_N_CAL_1 0x164
+#define LMK04832_REG_PLL2_N_CAL_2 0x165
+#define LMK04832_REG_PLL2_N_0 0x166
+#define LMK04832_BIT_PLL2_N_0 GENMASK(1, 0)
+#define LMK04832_REG_PLL2_N_1 0x167
+#define LMK04832_REG_PLL2_N_2 0x168
+#define LMK04832_REG_PLL2_DLD_CNT_MSB 0x16a
+#define LMK04832_REG_PLL2_DLD_CNT_LSB 0x16b
+#define LMK04832_REG_PLL2_LD 0x16e
+#define LMK04832_BIT_PLL2_LD_MUX GENMASK(7, 3)
+#define LMK04832_VAL_PLL2_LD_MUX_PLL2_DLD 0x02
+#define LMK04832_BIT_PLL2_LD_TYPE GENMASK(2, 0)
+#define LMK04832_VAL_PLL2_LD_TYPE_OUT_PP 0x03
+
+/* 0x16F - 0x555 Misc Registers */
+#define LMK04832_REG_PLL2_PD 0x173
+#define LMK04832_BIT_PLL2_PRE_PD BIT(6)
+#define LMK04832_BIT_PLL2_PD BIT(5)
+#define LMK04832_REG_PLL1R_RST 0x177
+#define LMK04832_REG_CLR_PLL_LOST 0x182
+#define LMK04832_REG_RB_PLL_LD 0x183
+#define LMK04832_REG_RB_CLK_DAC_VAL_MSB 0x184
+#define LMK04832_REG_RB_DAC_VAL_LSB 0x185
+#define LMK04832_REG_RB_HOLDOVER 0x188
+#define LMK04832_REG_SPI_LOCK 0x555
+
+enum lmk04832_device_types {
+ LMK04832,
+};
+
+/**
+ * lmk04832_device_info - Holds static device information that is specific to
+ * the chip revision
+ *
+ * pid: Product Identifier
+ * maskrev: IC version identifier
+ * num_channels: Number of available output channels (clkout count)
+ * vco0_range: {min, max} of the VCO0 operating range (in MHz)
+ * vco1_range: {min, max} of the VCO1 operating range (in MHz)
+ */
+struct lmk04832_device_info {
+ u16 pid;
+ u8 maskrev;
+ size_t num_channels;
+ unsigned int vco0_range[2];
+ unsigned int vco1_range[2];
+};
+
+static const struct lmk04832_device_info lmk04832_device_info[] = {
+ [LMK04832] = {
+ .pid = 0x63d1, /* WARNING PROD_ID is inverted in the datasheet */
+ .maskrev = 0x70,
+ .num_channels = 14,
+ .vco0_range = { 2440, 2580 },
+ .vco1_range = { 2945, 3255 },
+ },
+};
+
+enum lmk04832_rdbk_type {
+ RDBK_CLKIN_SEL0,
+ RDBK_CLKIN_SEL1,
+ RDBK_RESET,
+};
+
+struct lmk_dclk {
+ struct lmk04832 *lmk;
+ struct clk_hw hw;
+ u8 id;
+};
+
+struct lmk_clkout {
+ struct lmk04832 *lmk;
+ struct clk_hw hw;
+ bool sysref;
+ u32 format;
+ u8 id;
+};
+
+/**
+ * struct lmk04832 - The LMK04832 device structure
+ *
+ * @dev: reference to a struct device, linked to the spi_device
+ * @regmap: struct regmap instance use to access the chip
+ * @sync_mode: operational mode for SYNC signal
+ * @sysref_mux: select SYSREF source
+ * @sysref_pulse_cnt: number of SYSREF pulses generated while not in continuous
+ * mode.
+ * @sysref_ddly: SYSREF digital delay value
+ * @oscin: PLL2 input clock
+ * @vco: reference to the internal VCO clock
+ * @sclk: reference to the internal sysref clock (SCLK)
+ * @vco_rate: user provided VCO rate
+ * @reset_gpio: reference to the reset GPIO
+ * @dclk: list of internal device clock references.
+ * Each pair of clkout clocks share a single device clock (DCLKX_Y)
+ * @clkout: list of output clock references
+ * @clk_data: holds clkout related data like clk_hw* and number of clocks
+ */
+struct lmk04832 {
+ struct device *dev;
+ struct regmap *regmap;
+
+ unsigned int sync_mode;
+ unsigned int sysref_mux;
+ unsigned int sysref_pulse_cnt;
+ unsigned int sysref_ddly;
+
+ struct clk *oscin;
+ struct clk_hw vco;
+ struct clk_hw sclk;
+ unsigned int vco_rate;
+
+ struct gpio_desc *reset_gpio;
+
+ struct lmk_dclk *dclk;
+ struct lmk_clkout *clkout;
+ struct clk_hw_onecell_data *clk_data;
+};
+
+static bool lmk04832_regmap_rd_regs(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case LMK04832_REG_RST3W ... LMK04832_REG_ID_MASKREV:
+ fallthrough;
+ case LMK04832_REG_ID_VNDR_MSB:
+ fallthrough;
+ case LMK04832_REG_ID_VNDR_LSB:
+ fallthrough;
+ case LMK04832_REG_CLKOUT_CTRL0(0) ... LMK04832_REG_PLL2_DLD_CNT_LSB:
+ fallthrough;
+ case LMK04832_REG_PLL2_LD:
+ fallthrough;
+ case LMK04832_REG_PLL2_PD:
+ fallthrough;
+ case LMK04832_REG_PLL1R_RST:
+ fallthrough;
+ case LMK04832_REG_CLR_PLL_LOST ... LMK04832_REG_RB_DAC_VAL_LSB:
+ fallthrough;
+ case LMK04832_REG_RB_HOLDOVER:
+ fallthrough;
+ case LMK04832_REG_SPI_LOCK:
+ return true;
+ default:
+ return false;
+ };
+};
+
+static bool lmk04832_regmap_wr_regs(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case LMK04832_REG_RST3W:
+ fallthrough;
+ case LMK04832_REG_POWERDOWN:
+ return true;
+ case LMK04832_REG_ID_DEV_TYPE ... LMK04832_REG_ID_MASKREV:
+ fallthrough;
+ case LMK04832_REG_ID_VNDR_MSB:
+ fallthrough;
+ case LMK04832_REG_ID_VNDR_LSB:
+ return false;
+ case LMK04832_REG_CLKOUT_CTRL0(0) ... LMK04832_REG_PLL2_DLD_CNT_LSB:
+ fallthrough;
+ case LMK04832_REG_PLL2_LD:
+ fallthrough;
+ case LMK04832_REG_PLL2_PD:
+ fallthrough;
+ case LMK04832_REG_PLL1R_RST:
+ fallthrough;
+ case LMK04832_REG_CLR_PLL_LOST ... LMK04832_REG_RB_DAC_VAL_LSB:
+ fallthrough;
+ case LMK04832_REG_RB_HOLDOVER:
+ fallthrough;
+ case LMK04832_REG_SPI_LOCK:
+ return true;
+ default:
+ return false;
+ };
+};
+
+static const struct regmap_config regmap_config = {
+ .name = "lmk04832",
+ .reg_bits = 16,
+ .val_bits = 8,
+ .use_single_read = 1,
+ .use_single_write = 1,
+ .read_flag_mask = 0x80,
+ .write_flag_mask = 0x00,
+ .readable_reg = lmk04832_regmap_rd_regs,
+ .writeable_reg = lmk04832_regmap_wr_regs,
+ .cache_type = REGCACHE_NONE,
+ .max_register = LMK04832_REG_SPI_LOCK,
+};
+
+static int lmk04832_vco_is_enabled(struct clk_hw *hw)
+{
+ struct lmk04832 *lmk = container_of(hw, struct lmk04832, vco);
+ unsigned int tmp;
+ int ret;
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_MAIN_PD, &tmp);
+ if (ret)
+ return ret;
+
+ return !(FIELD_GET(LMK04832_BIT_OSCIN_PD, tmp) |
+ FIELD_GET(LMK04832_BIT_VCO_PD, tmp) |
+ FIELD_GET(LMK04832_BIT_VCO_LDO_PD, tmp));
+}
+
+static int lmk04832_vco_prepare(struct clk_hw *hw)
+{
+ struct lmk04832 *lmk = container_of(hw, struct lmk04832, vco);
+ int ret;
+
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_PLL2_PD,
+ LMK04832_BIT_PLL2_PRE_PD |
+ LMK04832_BIT_PLL2_PD,
+ 0x00);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(lmk->regmap, LMK04832_REG_MAIN_PD,
+ LMK04832_BIT_VCO_LDO_PD |
+ LMK04832_BIT_VCO_PD |
+ LMK04832_BIT_OSCIN_PD, 0x00);
+}
+
+static void lmk04832_vco_unprepare(struct clk_hw *hw)
+{
+ struct lmk04832 *lmk = container_of(hw, struct lmk04832, vco);
+
+ regmap_update_bits(lmk->regmap, LMK04832_REG_PLL2_PD,
+ LMK04832_BIT_PLL2_PRE_PD | LMK04832_BIT_PLL2_PD,
+ 0xff);
+
+ /* Don't set LMK04832_BIT_OSCIN_PD since other clocks depend on it */
+ regmap_update_bits(lmk->regmap, LMK04832_REG_MAIN_PD,
+ LMK04832_BIT_VCO_LDO_PD | LMK04832_BIT_VCO_PD, 0xff);
+}
+
+static unsigned long lmk04832_vco_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ struct lmk04832 *lmk = container_of(hw, struct lmk04832, vco);
+ unsigned int pll2_p[] = {8, 2, 2, 3, 4, 5, 6, 7};
+ unsigned int pll2_n, p, pll2_r;
+ unsigned int pll2_misc;
+ unsigned long vco_rate;
+ u8 tmp[3];
+ int ret;
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_PLL2_MISC, &pll2_misc);
+ if (ret)
+ return ret;
+
+ p = FIELD_GET(LMK04832_BIT_PLL2_MISC_P, pll2_misc);
+
+ ret = regmap_bulk_read(lmk->regmap, LMK04832_REG_PLL2_N_0, &tmp, 3);
+ if (ret)
+ return ret;
+
+ pll2_n = FIELD_PREP(0x030000, tmp[0]) |
+ FIELD_PREP(0x00ff00, tmp[1]) |
+ FIELD_PREP(0x0000ff, tmp[2]);
+
+ ret = regmap_bulk_read(lmk->regmap, LMK04832_REG_PLL2_R_MSB, &tmp, 2);
+ if (ret)
+ return ret;
+
+ pll2_r = FIELD_PREP(0x0f00, tmp[0]) |
+ FIELD_PREP(0x00ff, tmp[1]);
+
+ vco_rate = (prate << FIELD_GET(LMK04832_BIT_PLL2_MISC_REF_2X_EN,
+ pll2_misc)) * pll2_n * pll2_p[p] / pll2_r;
+
+ return vco_rate;
+};
+
+/**
+ * lmk04832_check_vco_ranges - Check requested VCO frequency against VCO ranges
+ *
+ * @lmk: Reference to the lmk device
+ * @rate: Desired output rate for the VCO
+ *
+ * The LMK04832 has 2 internal VCO, each with independent operating ranges.
+ * Use the device_info structure to determine which VCO to use based on rate.
+ *
+ * Returns VCO_MUX value or negative errno.
+ */
+static int lmk04832_check_vco_ranges(struct lmk04832 *lmk, unsigned long rate)
+{
+ struct spi_device *spi = to_spi_device(lmk->dev);
+ const struct lmk04832_device_info *info;
+ unsigned long mhz = rate / 1000000;
+
+ info = &lmk04832_device_info[spi_get_device_id(spi)->driver_data];
+
+ if (mhz >= info->vco0_range[0] && mhz <= info->vco0_range[1])
+ return LMK04832_VAL_VCO_MUX_VCO0;
+
+ if (mhz >= info->vco1_range[0] && mhz <= info->vco1_range[1])
+ return LMK04832_VAL_VCO_MUX_VCO1;
+
+ dev_err(lmk->dev, "%lu Hz is out of VCO ranges\n", rate);
+ return -ERANGE;
+}
+
+/**
+ * lmk04832_calc_pll2_params - Get PLL2 parameters used to set the VCO frequency
+ *
+ * @prate: parent rate to the PLL2, usually OSCin
+ * @rate: Desired output rate for the VCO
+ * @n: reference to PLL2_N
+ * @p: reference to PLL2_P
+ * @r: reference to PLL2_R
+ *
+ * This functions assumes LMK04832_BIT_PLL2_MISC_REF_2X_EN is set since it is
+ * recommended in the datasheet because a higher phase detector frequencies
+ * makes the design of wider loop bandwidth filters possible.
+ *
+ * the VCO rate can be calculated using the following expression:
+ *
+ * VCO = OSCin * 2 * PLL2_N * PLL2_P / PLL2_R
+ *
+ * Returns vco rate or negative errno.
+ */
+static long lmk04832_calc_pll2_params(unsigned long prate, unsigned long rate,
+ unsigned int *n, unsigned int *p,
+ unsigned int *r)
+{
+ unsigned int pll2_n, pll2_p, pll2_r;
+ unsigned long num, div;
+
+ /* Set PLL2_P to a fixed value to simplify optimizations */
+ pll2_p = 2;
+
+ div = gcd(rate, prate);
+
+ num = DIV_ROUND_CLOSEST(rate, div);
+ pll2_r = DIV_ROUND_CLOSEST(prate, div);
+
+ if (num > 4) {
+ pll2_n = num >> 2;
+ } else {
+ pll2_r = pll2_r << 2;
+ pll2_n = num;
+ }
+
+ if (pll2_n < 1 || pll2_n > 0x03ffff)
+ return -EINVAL;
+ if (pll2_r < 1 || pll2_r > 0xfff)
+ return -EINVAL;
+
+ *n = pll2_n;
+ *p = pll2_p;
+ *r = pll2_r;
+
+ return DIV_ROUND_CLOSEST(prate * 2 * pll2_p * pll2_n, pll2_r);
+}
+
+static long lmk04832_vco_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct lmk04832 *lmk = container_of(hw, struct lmk04832, vco);
+ unsigned int n, p, r;
+ long vco_rate;
+ int ret;
+
+ ret = lmk04832_check_vco_ranges(lmk, rate);
+ if (ret < 0)
+ return ret;
+
+ vco_rate = lmk04832_calc_pll2_params(*prate, rate, &n, &p, &r);
+ if (vco_rate < 0) {
+ dev_err(lmk->dev, "PLL2 parameters out of range\n");
+ return vco_rate;
+ }
+
+ if (rate != vco_rate)
+ return -EINVAL;
+
+ return vco_rate;
+};
+
+static int lmk04832_vco_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long prate)
+{
+ struct lmk04832 *lmk = container_of(hw, struct lmk04832, vco);
+ unsigned int n, p, r;
+ long vco_rate;
+ int vco_mux;
+ int ret;
+
+ vco_mux = lmk04832_check_vco_ranges(lmk, rate);
+ if (vco_mux < 0)
+ return vco_mux;
+
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_VCO_OSCOUT,
+ LMK04832_BIT_VCO_MUX,
+ FIELD_PREP(LMK04832_BIT_VCO_MUX, vco_mux));
+ if (ret)
+ return ret;
+
+ vco_rate = lmk04832_calc_pll2_params(prate, rate, &n, &p, &r);
+ if (vco_rate < 0) {
+ dev_err(lmk->dev, "failed to determine PLL2 parameters\n");
+ return vco_rate;
+ }
+
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_PLL2_R_MSB,
+ LMK04832_BIT_PLL2_R_MSB,
+ FIELD_GET(0x000700, r));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(lmk->regmap, LMK04832_REG_PLL2_R_LSB,
+ FIELD_GET(0x0000ff, r));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_PLL2_MISC,
+ LMK04832_BIT_PLL2_MISC_P,
+ FIELD_PREP(LMK04832_BIT_PLL2_MISC_P, p));
+ if (ret)
+ return ret;
+
+ /*
+ * PLL2_N registers must be programmed after other PLL2 dividers are
+ * programmed to ensure proper VCO frequency calibration
+ */
+ ret = regmap_write(lmk->regmap, LMK04832_REG_PLL2_N_0,
+ FIELD_GET(0x030000, n));
+ if (ret)
+ return ret;
+ ret = regmap_write(lmk->regmap, LMK04832_REG_PLL2_N_1,
+ FIELD_GET(0x00ff00, n));
+ if (ret)
+ return ret;
+
+ return regmap_write(lmk->regmap, LMK04832_REG_PLL2_N_2,
+ FIELD_GET(0x0000ff, n));
+};
+
+static const struct clk_ops lmk04832_vco_ops = {
+ .is_enabled = lmk04832_vco_is_enabled,
+ .prepare = lmk04832_vco_prepare,
+ .unprepare = lmk04832_vco_unprepare,
+ .recalc_rate = lmk04832_vco_recalc_rate,
+ .round_rate = lmk04832_vco_round_rate,
+ .set_rate = lmk04832_vco_set_rate,
+};
+
+/*
+ * lmk04832_register_vco - Initialize the internal VCO and clock distribution
+ * path in PLL2 single loop mode.
+ */
+static int lmk04832_register_vco(struct lmk04832 *lmk)
+{
+ const char *parent_names[1];
+ struct clk_init_data init;
+ int ret;
+
+ init.name = "lmk-vco";
+ parent_names[0] = __clk_get_name(lmk->oscin);
+ init.parent_names = parent_names;
+
+ init.ops = &lmk04832_vco_ops;
+ init.num_parents = 1;
+
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_VCO_OSCOUT,
+ LMK04832_BIT_VCO_MUX,
+ FIELD_PREP(LMK04832_BIT_VCO_MUX,
+ LMK04832_VAL_VCO_MUX_VCO1));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_FB_CTRL,
+ LMK04832_BIT_PLL2_RCLK_MUX |
+ LMK04832_BIT_PLL2_NCLK_MUX,
+ FIELD_PREP(LMK04832_BIT_PLL2_RCLK_MUX,
+ LMK04832_VAL_PLL2_RCLK_MUX_OSCIN)|
+ FIELD_PREP(LMK04832_BIT_PLL2_NCLK_MUX,
+ LMK04832_VAL_PLL2_NCLK_MUX_PLL2_P));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_PLL2_MISC,
+ LMK04832_BIT_PLL2_MISC_REF_2X_EN,
+ LMK04832_BIT_PLL2_MISC_REF_2X_EN);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(lmk->regmap, LMK04832_REG_PLL2_LD,
+ FIELD_PREP(LMK04832_BIT_PLL2_LD_MUX,
+ LMK04832_VAL_PLL2_LD_MUX_PLL2_DLD) |
+ FIELD_PREP(LMK04832_BIT_PLL2_LD_TYPE,
+ LMK04832_VAL_PLL2_LD_TYPE_OUT_PP));
+ if (ret)
+ return ret;
+
+ lmk->vco.init = &init;
+ return devm_clk_hw_register(lmk->dev, &lmk->vco);
+}
+
+static int lmk04832_clkout_set_ddly(struct lmk04832 *lmk, int id)
+{
+ int dclk_div_adj[] = {0, 0, -2, -2, 0, 3, -1, 0};
+ unsigned int sclkx_y_ddly = 10;
+ unsigned int dclkx_y_ddly;
+ unsigned int dclkx_y_div;
+ unsigned int sysref_ddly;
+ unsigned int dclkx_y_hs;
+ unsigned int lsb, msb;
+ int ret;
+
+ ret = regmap_update_bits(lmk->regmap,
+ LMK04832_REG_CLKOUT_CTRL2(id),
+ LMK04832_BIT_DCLKX_Y_DDLY_PD,
+ FIELD_PREP(LMK04832_BIT_DCLKX_Y_DDLY_PD, 0));
+ if (ret)
+ return ret;
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_SYSREF_DDLY_LSB, &lsb);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_SYSREF_DDLY_MSB, &msb);
+ if (ret)
+ return ret;
+
+ sysref_ddly = FIELD_GET(LMK04832_BIT_SYSREF_DDLY_MSB, msb) << 8 | lsb;
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_CLKOUT_CTRL0(id), &lsb);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_CLKOUT_CTRL2(id), &msb);
+ if (ret)
+ return ret;
+
+ dclkx_y_div = FIELD_GET(LMK04832_BIT_DCLK_DIV_MSB, msb) << 8 | lsb;
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_CLKOUT_CTRL3(id), &lsb);
+ if (ret)
+ return ret;
+
+ dclkx_y_hs = FIELD_GET(LMK04832_BIT_DCLKX_Y_HS, lsb);
+
+ dclkx_y_ddly = sysref_ddly + 1 -
+ dclk_div_adj[dclkx_y_div < 6 ? dclkx_y_div : 7] -
+ dclkx_y_hs + sclkx_y_ddly;
+
+ if (dclkx_y_ddly < 7 || dclkx_y_ddly > 0x3fff) {
+ dev_err(lmk->dev, "DCLKX_Y_DDLY out of range (%d)\n",
+ dclkx_y_ddly);
+ return -EINVAL;
+ }
+
+ ret = regmap_write(lmk->regmap,
+ LMK04832_REG_SCLKX_Y_DDLY(id),
+ FIELD_GET(LMK04832_BIT_SCLKX_Y_DDLY, sclkx_y_ddly));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(lmk->regmap, LMK04832_REG_CLKOUT_CTRL1(id),
+ FIELD_GET(0x00ff, dclkx_y_ddly));
+ if (ret)
+ return ret;
+
+ dev_dbg(lmk->dev, "clkout%02u: sysref_ddly=%u, dclkx_y_ddly=%u, "
+ "dclk_div_adj=%+d, dclkx_y_hs=%u, sclkx_y_ddly=%u\n",
+ id, sysref_ddly, dclkx_y_ddly,
+ dclk_div_adj[dclkx_y_div < 6 ? dclkx_y_div : 7],
+ dclkx_y_hs, sclkx_y_ddly);
+
+ return regmap_update_bits(lmk->regmap, LMK04832_REG_CLKOUT_CTRL2(id),
+ LMK04832_BIT_DCLKX_Y_DDLY_MSB,
+ FIELD_GET(0x0300, dclkx_y_ddly));
+}
+
+/** lmk04832_sclk_sync - Establish deterministic phase relationship between sclk
+ * and dclk
+ *
+ * @lmk: Reference to the lmk device
+ *
+ * The synchronization sequence:
+ * - in the datasheet https://www.ti.com/lit/ds/symlink/lmk04832.pdf, p.31
+ * (8.3.3.1 How to enable SYSREF)
+ * - Ti forum: https://e2e.ti.com/support/clock-and-timing/f/48/t/970972
+ *
+ * Returns 0 or negative errno.
+ */
+static int lmk04832_sclk_sync_sequence(struct lmk04832 *lmk)
+{
+ int ret;
+ int i;
+
+ /* 1. (optional) mute all sysref_outputs during synchronization */
+ /* 2. Enable and write device clock digital delay to applicable clocks */
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_MAIN_PD,
+ LMK04832_BIT_SYSREF_DDLY_PD,
+ FIELD_PREP(LMK04832_BIT_SYSREF_DDLY_PD, 0));
+ if (ret)
+ return ret;
+
+ for (i = 0; i < lmk->clk_data->num; i += 2) {
+ ret = lmk04832_clkout_set_ddly(lmk, i);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * 3. Configure SYNC_MODE to SYNC_PIN and SYSREF_MUX to Normal SYNC,
+ * and clear SYSREF_REQ_EN (see 6.)
+ */
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_SYSREF_OUT,
+ LMK04832_BIT_SYSREF_REQ_EN |
+ LMK04832_BIT_SYSREF_MUX,
+ FIELD_PREP(LMK04832_BIT_SYSREF_REQ_EN, 0) |
+ FIELD_PREP(LMK04832_BIT_SYSREF_MUX,
+ LMK04832_VAL_SYSREF_MUX_NORMAL_SYNC));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_SYNC,
+ LMK04832_BIT_SYNC_MODE,
+ FIELD_PREP(LMK04832_BIT_SYNC_MODE,
+ LMK04832_VAL_SYNC_MODE_ON));
+ if (ret)
+ return ret;
+
+ /* 4. Clear SYNXC_DISx or applicable clocks and clear SYNC_DISSYSREF */
+ ret = regmap_write(lmk->regmap, LMK04832_REG_SYNC_DIS, 0x00);
+ if (ret)
+ return ret;
+
+ /*
+ * 5. If SCLKX_Y_DDLY != 0, Set SYSREF_CLR=1 for at least 15 clock
+ * distribution path cycles (VCO cycles), then back to 0. In
+ * PLL2-only use case, this will be complete in less than one SPI
+ * transaction. If SYSREF local digital delay is not used, this step
+ * can be skipped.
+ */
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_SYNC,
+ LMK04832_BIT_SYNC_CLR,
+ FIELD_PREP(LMK04832_BIT_SYNC_CLR, 0x01));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_SYNC,
+ LMK04832_BIT_SYNC_CLR,
+ FIELD_PREP(LMK04832_BIT_SYNC_CLR, 0x00));
+ if (ret)
+ return ret;
+
+ /*
+ * 6. Toggle SYNC_POL state between inverted and not inverted.
+ * If you use an external signal on the SYNC pin instead of toggling
+ * SYNC_POL, make sure that SYSREF_REQ_EN=0 so that the SYSREF_MUX
+ * does not shift into continuous SYSREF mode.
+ */
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_SYNC,
+ LMK04832_BIT_SYNC_POL,
+ FIELD_PREP(LMK04832_BIT_SYNC_POL, 0x01));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_SYNC,
+ LMK04832_BIT_SYNC_POL,
+ FIELD_PREP(LMK04832_BIT_SYNC_POL, 0x00));
+ if (ret)
+ return ret;
+
+ /* 7. Set all SYNC_DISx=1, including SYNC_DISSYSREF */
+ ret = regmap_write(lmk->regmap, LMK04832_REG_SYNC_DIS, 0xff);
+ if (ret)
+ return ret;
+
+ /* 8. Restore state of SYNC_MODE and SYSREF_MUX to desired values */
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_SYSREF_OUT,
+ LMK04832_BIT_SYSREF_MUX,
+ FIELD_PREP(LMK04832_BIT_SYSREF_MUX,
+ lmk->sysref_mux));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_SYNC,
+ LMK04832_BIT_SYNC_MODE,
+ FIELD_PREP(LMK04832_BIT_SYNC_MODE,
+ lmk->sync_mode));
+ if (ret)
+ return ret;
+
+ /*
+ * 9. (optional) if SCLKx_y_DIS_MODE was used to mute SYSREF outputs
+ * during the SYNC event, restore SCLKx_y_DIS_MODE=0 for active state,
+ * or set SYSREF_GBL_PD=0 if SCLKx_y_DIS_MODE is set to a conditional
+ * option.
+ */
+
+ /*
+ * 10. (optional) To reduce power consumption, after the synchronization
+ * event is complete, DCLKx_y_DDLY_PD=1 and SYSREF_DDLY_PD=1 disable the
+ * digital delay counters (which are only used immediately after the
+ * SYNC pulse to delay the output by some number of VCO counts).
+ */
+
+ return ret;
+}
+
+static int lmk04832_sclk_is_enabled(struct clk_hw *hw)
+{
+ struct lmk04832 *lmk = container_of(hw, struct lmk04832, sclk);
+ unsigned int tmp;
+ int ret;
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_MAIN_PD, &tmp);
+ if (ret)
+ return ret;
+
+ return FIELD_GET(LMK04832_BIT_SYSREF_PD, tmp);
+}
+
+static int lmk04832_sclk_prepare(struct clk_hw *hw)
+{
+ struct lmk04832 *lmk = container_of(hw, struct lmk04832, sclk);
+
+ return regmap_update_bits(lmk->regmap, LMK04832_REG_MAIN_PD,
+ LMK04832_BIT_SYSREF_PD, 0x00);
+}
+
+static void lmk04832_sclk_unprepare(struct clk_hw *hw)
+{
+ struct lmk04832 *lmk = container_of(hw, struct lmk04832, sclk);
+
+ regmap_update_bits(lmk->regmap, LMK04832_REG_MAIN_PD,
+ LMK04832_BIT_SYSREF_PD, LMK04832_BIT_SYSREF_PD);
+}
+
+static unsigned long lmk04832_sclk_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ struct lmk04832 *lmk = container_of(hw, struct lmk04832, sclk);
+ unsigned int sysref_div;
+ u8 tmp[2];
+ int ret;
+
+ ret = regmap_bulk_read(lmk->regmap, LMK04832_REG_SYSREF_DIV_MSB, &tmp, 2);
+ if (ret)
+ return ret;
+
+ sysref_div = FIELD_GET(LMK04832_BIT_SYSREF_DIV_MSB, tmp[0]) << 8 |
+ tmp[1];
+
+ return DIV_ROUND_CLOSEST(prate, sysref_div);
+}
+
+static long lmk04832_sclk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct lmk04832 *lmk = container_of(hw, struct lmk04832, sclk);
+ unsigned long sclk_rate;
+ unsigned int sysref_div;
+
+ sysref_div = DIV_ROUND_CLOSEST(*prate, rate);
+ sclk_rate = DIV_ROUND_CLOSEST(*prate, sysref_div);
+
+ if (sysref_div < 0x07 || sysref_div > 0x1fff) {
+ dev_err(lmk->dev, "SYSREF divider out of range\n");
+ return -EINVAL;
+ }
+
+ if (rate != sclk_rate)
+ return -EINVAL;
+
+ return sclk_rate;
+}
+
+static int lmk04832_sclk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long prate)
+{
+ struct lmk04832 *lmk = container_of(hw, struct lmk04832, sclk);
+ unsigned int sysref_div;
+ int ret;
+
+ sysref_div = DIV_ROUND_CLOSEST(prate, rate);
+
+ if (sysref_div < 0x07 || sysref_div > 0x1fff) {
+ dev_err(lmk->dev, "SYSREF divider out of range\n");
+ return -EINVAL;
+ }
+
+ ret = regmap_write(lmk->regmap, LMK04832_REG_SYSREF_DIV_MSB,
+ FIELD_GET(0x1f00, sysref_div));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(lmk->regmap, LMK04832_REG_SYSREF_DIV_LSB,
+ FIELD_GET(0x00ff, sysref_div));
+ if (ret)
+ return ret;
+
+ ret = lmk04832_sclk_sync_sequence(lmk);
+ if (ret)
+ dev_err(lmk->dev, "SYNC sequence failed\n");
+
+ return ret;
+}
+
+static const struct clk_ops lmk04832_sclk_ops = {
+ .is_enabled = lmk04832_sclk_is_enabled,
+ .prepare = lmk04832_sclk_prepare,
+ .unprepare = lmk04832_sclk_unprepare,
+ .recalc_rate = lmk04832_sclk_recalc_rate,
+ .round_rate = lmk04832_sclk_round_rate,
+ .set_rate = lmk04832_sclk_set_rate,
+};
+
+static int lmk04832_register_sclk(struct lmk04832 *lmk)
+{
+ const char *parent_names[1];
+ struct clk_init_data init;
+ int ret;
+
+ init.name = "lmk-sclk";
+ parent_names[0] = clk_hw_get_name(&lmk->vco);
+ init.parent_names = parent_names;
+
+ init.ops = &lmk04832_sclk_ops;
+ init.flags = CLK_SET_RATE_PARENT;
+ init.num_parents = 1;
+
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_SYSREF_OUT,
+ LMK04832_BIT_SYSREF_MUX,
+ FIELD_PREP(LMK04832_BIT_SYSREF_MUX,
+ lmk->sysref_mux));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(lmk->regmap, LMK04832_REG_SYSREF_DDLY_LSB,
+ FIELD_GET(0x00ff, lmk->sysref_ddly));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(lmk->regmap, LMK04832_REG_SYSREF_DDLY_MSB,
+ FIELD_GET(0x1f00, lmk->sysref_ddly));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(lmk->regmap, LMK04832_REG_SYSREF_PULSE_CNT,
+ ilog2(lmk->sysref_pulse_cnt));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(lmk->regmap, LMK04832_REG_MAIN_PD,
+ LMK04832_BIT_SYSREF_DDLY_PD |
+ LMK04832_BIT_SYSREF_PLSR_PD,
+ FIELD_PREP(LMK04832_BIT_SYSREF_DDLY_PD, 0) |
+ FIELD_PREP(LMK04832_BIT_SYSREF_PLSR_PD, 0));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(lmk->regmap, LMK04832_REG_SYNC,
+ FIELD_PREP(LMK04832_BIT_SYNC_POL, 0) |
+ FIELD_PREP(LMK04832_BIT_SYNC_EN, 1) |
+ FIELD_PREP(LMK04832_BIT_SYNC_MODE, lmk->sync_mode));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(lmk->regmap, LMK04832_REG_SYNC_DIS, 0xff);
+ if (ret)
+ return ret;
+
+ lmk->sclk.init = &init;
+ return devm_clk_hw_register(lmk->dev, &lmk->sclk);
+}
+
+static int lmk04832_dclk_is_enabled(struct clk_hw *hw)
+{
+ struct lmk_dclk *dclk = container_of(hw, struct lmk_dclk, hw);
+ struct lmk04832 *lmk = dclk->lmk;
+ unsigned int tmp;
+ int ret;
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_CLKOUT_CTRL3(dclk->id),
+ &tmp);
+ if (ret)
+ return ret;
+
+ return !FIELD_GET(LMK04832_BIT_DCLKX_Y_PD, tmp);
+}
+
+static int lmk04832_dclk_prepare(struct clk_hw *hw)
+{
+ struct lmk_dclk *dclk = container_of(hw, struct lmk_dclk, hw);
+ struct lmk04832 *lmk = dclk->lmk;
+
+ return regmap_update_bits(lmk->regmap,
+ LMK04832_REG_CLKOUT_CTRL3(dclk->id),
+ LMK04832_BIT_DCLKX_Y_PD, 0x00);
+}
+
+static void lmk04832_dclk_unprepare(struct clk_hw *hw)
+{
+ struct lmk_dclk *dclk = container_of(hw, struct lmk_dclk, hw);
+ struct lmk04832 *lmk = dclk->lmk;
+
+ regmap_update_bits(lmk->regmap,
+ LMK04832_REG_CLKOUT_CTRL3(dclk->id),
+ LMK04832_BIT_DCLKX_Y_PD, 0xff);
+}
+
+static unsigned long lmk04832_dclk_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ struct lmk_dclk *dclk = container_of(hw, struct lmk_dclk, hw);
+ struct lmk04832 *lmk = dclk->lmk;
+ unsigned int dclk_div;
+ unsigned int lsb, msb;
+ unsigned long rate;
+ int ret;
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_CLKOUT_CTRL0(dclk->id),
+ &lsb);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_CLKOUT_CTRL2(dclk->id),
+ &msb);
+ if (ret)
+ return ret;
+
+ dclk_div = FIELD_GET(LMK04832_BIT_DCLK_DIV_MSB, msb) << 8 | lsb;
+ rate = DIV_ROUND_CLOSEST(prate, dclk_div);
+
+ return rate;
+};
+
+static long lmk04832_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct lmk_dclk *dclk = container_of(hw, struct lmk_dclk, hw);
+ struct lmk04832 *lmk = dclk->lmk;
+ unsigned long dclk_rate;
+ unsigned int dclk_div;
+
+ dclk_div = DIV_ROUND_CLOSEST(*prate, rate);
+ dclk_rate = DIV_ROUND_CLOSEST(*prate, dclk_div);
+
+ if (dclk_div < 1 || dclk_div > 0x3ff) {
+ dev_err(lmk->dev, "%s_div out of range\n", clk_hw_get_name(hw));
+ return -EINVAL;
+ }
+
+ if (rate != dclk_rate)
+ return -EINVAL;
+
+ return dclk_rate;
+};
+
+static int lmk04832_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long prate)
+{
+ struct lmk_dclk *dclk = container_of(hw, struct lmk_dclk, hw);
+ struct lmk04832 *lmk = dclk->lmk;
+ unsigned int dclk_div;
+ int ret;
+
+ dclk_div = DIV_ROUND_CLOSEST(prate, rate);
+
+ if (dclk_div > 0x3ff) {
+ dev_err(lmk->dev, "%s_div out of range\n", clk_hw_get_name(hw));
+ return -EINVAL;
+ }
+
+ /* Enable Duty Cycle Correction */
+ if (dclk_div == 1) {
+ ret = regmap_update_bits(lmk->regmap,
+ LMK04832_REG_CLKOUT_CTRL3(dclk->id),
+ LMK04832_BIT_DCLKX_Y_DCC,
+ FIELD_PREP(LMK04832_BIT_DCLKX_Y_DCC, 1));
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * While using Divide-by-2 or Divide-by-3 for DCLK_X_Y_DIV, SYNC
+ * procedure requires to first program Divide-by-4 and then back to
+ * Divide-by-2 or Divide-by-3 before doing SYNC.
+ */
+ if (dclk_div == 2 || dclk_div == 3) {
+ ret = regmap_update_bits(lmk->regmap,
+ LMK04832_REG_CLKOUT_CTRL2(dclk->id),
+ LMK04832_BIT_DCLK_DIV_MSB, 0x00);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(lmk->regmap,
+ LMK04832_REG_CLKOUT_CTRL0(dclk->id), 0x04);
+ if (ret)
+ return ret;
+ }
+
+ ret = regmap_write(lmk->regmap, LMK04832_REG_CLKOUT_CTRL0(dclk->id),
+ FIELD_GET(0x0ff, dclk_div));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(lmk->regmap,
+ LMK04832_REG_CLKOUT_CTRL2(dclk->id),
+ LMK04832_BIT_DCLK_DIV_MSB,
+ FIELD_GET(0x300, dclk_div));
+ if (ret)
+ return ret;
+
+ ret = lmk04832_sclk_sync_sequence(lmk);
+ if (ret)
+ dev_err(lmk->dev, "SYNC sequence failed\n");
+
+ return ret;
+};
+
+static const struct clk_ops lmk04832_dclk_ops = {
+ .is_enabled = lmk04832_dclk_is_enabled,
+ .prepare = lmk04832_dclk_prepare,
+ .unprepare = lmk04832_dclk_unprepare,
+ .recalc_rate = lmk04832_dclk_recalc_rate,
+ .round_rate = lmk04832_dclk_round_rate,
+ .set_rate = lmk04832_dclk_set_rate,
+};
+
+static int lmk04832_clkout_is_enabled(struct clk_hw *hw)
+{
+ struct lmk_clkout *clkout = container_of(hw, struct lmk_clkout, hw);
+ struct lmk04832 *lmk = clkout->lmk;
+ unsigned int clkoutx_y_pd;
+ unsigned int sclkx_y_pd;
+ unsigned int tmp;
+ u32 enabled;
+ int ret;
+ u8 fmt;
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_CLKOUT_CTRL2(clkout->id),
+ &clkoutx_y_pd);
+ if (ret)
+ return ret;
+
+ enabled = !FIELD_GET(LMK04832_BIT_CLKOUTX_Y_PD, clkoutx_y_pd);
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_CLKOUT_SRC_MUX(clkout->id),
+ &tmp);
+ if (ret)
+ return ret;
+
+ if (FIELD_GET(LMK04832_BIT_CLKOUT_SRC_MUX, tmp)) {
+ ret = regmap_read(lmk->regmap,
+ LMK04832_REG_CLKOUT_CTRL4(clkout->id),
+ &sclkx_y_pd);
+ if (ret)
+ return ret;
+
+ enabled = enabled && !FIELD_GET(LMK04832_BIT_SCLK_PD, sclkx_y_pd);
+ }
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_CLKOUT_FMT(clkout->id),
+ &tmp);
+ if (ret)
+ return ret;
+
+ if (clkout->id % 2)
+ fmt = FIELD_GET(0xf0, tmp);
+ else
+ fmt = FIELD_GET(0x0f, tmp);
+
+ return enabled && !fmt;
+}
+
+static int lmk04832_clkout_prepare(struct clk_hw *hw)
+{
+ struct lmk_clkout *clkout = container_of(hw, struct lmk_clkout, hw);
+ struct lmk04832 *lmk = clkout->lmk;
+ unsigned int tmp;
+ int ret;
+
+ if (clkout->format == LMK04832_VAL_CLKOUT_FMT_POWERDOWN)
+ dev_err(lmk->dev, "prepared %s but format is powerdown\n",
+ clk_hw_get_name(hw));
+
+ ret = regmap_update_bits(lmk->regmap,
+ LMK04832_REG_CLKOUT_CTRL2(clkout->id),
+ LMK04832_BIT_CLKOUTX_Y_PD, 0x00);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_CLKOUT_SRC_MUX(clkout->id),
+ &tmp);
+ if (ret)
+ return ret;
+
+ if (FIELD_GET(LMK04832_BIT_CLKOUT_SRC_MUX, tmp)) {
+ ret = regmap_update_bits(lmk->regmap,
+ LMK04832_REG_CLKOUT_CTRL4(clkout->id),
+ LMK04832_BIT_SCLK_PD, 0x00);
+ if (ret)
+ return ret;
+ }
+
+ return regmap_update_bits(lmk->regmap,
+ LMK04832_REG_CLKOUT_FMT(clkout->id),
+ LMK04832_BIT_CLKOUT_FMT(clkout->id),
+ clkout->format << 4 * (clkout->id % 2));
+}
+
+static void lmk04832_clkout_unprepare(struct clk_hw *hw)
+{
+ struct lmk_clkout *clkout = container_of(hw, struct lmk_clkout, hw);
+ struct lmk04832 *lmk = clkout->lmk;
+
+ regmap_update_bits(lmk->regmap, LMK04832_REG_CLKOUT_FMT(clkout->id),
+ LMK04832_BIT_CLKOUT_FMT(clkout->id),
+ 0x00);
+}
+
+static int lmk04832_clkout_set_parent(struct clk_hw *hw, uint8_t index)
+{
+ struct lmk_clkout *clkout = container_of(hw, struct lmk_clkout, hw);
+ struct lmk04832 *lmk = clkout->lmk;
+
+ return regmap_update_bits(lmk->regmap,
+ LMK04832_REG_CLKOUT_SRC_MUX(clkout->id),
+ LMK04832_BIT_CLKOUT_SRC_MUX,
+ FIELD_PREP(LMK04832_BIT_CLKOUT_SRC_MUX,
+ index));
+}
+
+static uint8_t lmk04832_clkout_get_parent(struct clk_hw *hw)
+{
+ struct lmk_clkout *clkout = container_of(hw, struct lmk_clkout, hw);
+ struct lmk04832 *lmk = clkout->lmk;
+ unsigned int tmp;
+ int ret;
+
+ ret = regmap_read(lmk->regmap, LMK04832_REG_CLKOUT_SRC_MUX(clkout->id),
+ &tmp);
+ if (ret)
+ return ret;
+
+ return FIELD_GET(LMK04832_BIT_CLKOUT_SRC_MUX, tmp);
+}
+
+static const struct clk_ops lmk04832_clkout_ops = {
+ .is_enabled = lmk04832_clkout_is_enabled,
+ .prepare = lmk04832_clkout_prepare,
+ .unprepare = lmk04832_clkout_unprepare,
+ .set_parent = lmk04832_clkout_set_parent,
+ .get_parent = lmk04832_clkout_get_parent,
+};
+
+static int lmk04832_register_clkout(struct lmk04832 *lmk, const int num)
+{
+ char name[] = "lmk-clkoutXX";
+ char dclk_name[] = "lmk-dclkXX_YY";
+ const char *parent_names[2];
+ struct clk_init_data init;
+ int dclk_num = num / 2;
+ int ret;
+
+ if (num % 2 == 0) {
+ sprintf(dclk_name, "lmk-dclk%02d_%02d", num, num + 1);
+ init.name = dclk_name;
+ parent_names[0] = clk_hw_get_name(&lmk->vco);
+ init.ops = &lmk04832_dclk_ops;
+ init.flags = CLK_SET_RATE_PARENT;
+ init.num_parents = 1;
+
+ lmk->dclk[dclk_num].id = num;
+ lmk->dclk[dclk_num].lmk = lmk;
+ lmk->dclk[dclk_num].hw.init = &init;
+
+ ret = devm_clk_hw_register(lmk->dev, &lmk->dclk[dclk_num].hw);
+ if (ret)
+ return ret;
+ } else {
+ sprintf(dclk_name, "lmk-dclk%02d_%02d", num - 1, num);
+ }
+
+ if (of_property_read_string_index(lmk->dev->of_node,
+ "clock-output-names",
+ num, &init.name)) {
+ sprintf(name, "lmk-clkout%02d", num);
+ init.name = name;
+ }
+
+ parent_names[0] = dclk_name;
+ parent_names[1] = clk_hw_get_name(&lmk->sclk);
+ init.parent_names = parent_names;
+ init.ops = &lmk04832_clkout_ops;
+ init.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT;
+ init.num_parents = ARRAY_SIZE(parent_names);
+
+ lmk->clkout[num].id = num;
+ lmk->clkout[num].lmk = lmk;
+ lmk->clkout[num].hw.init = &init;
+ lmk->clk_data->hws[num] = &lmk->clkout[num].hw;
+
+ /* Set initial parent */
+ regmap_update_bits(lmk->regmap,
+ LMK04832_REG_CLKOUT_SRC_MUX(num),
+ LMK04832_BIT_CLKOUT_SRC_MUX,
+ FIELD_PREP(LMK04832_BIT_CLKOUT_SRC_MUX,
+ lmk->clkout[num].sysref));
+
+ return devm_clk_hw_register(lmk->dev, &lmk->clkout[num].hw);
+}
+
+static int lmk04832_set_spi_rdbk(const struct lmk04832 *lmk, const int rdbk_pin)
+{
+ int reg;
+ int ret;
+
+ dev_info(lmk->dev, "setting up 4-wire mode\n");
+ ret = regmap_write(lmk->regmap, LMK04832_REG_RST3W,
+ LMK04832_BIT_SPI_3WIRE_DIS);
+ if (ret)
+ return ret;
+
+ switch (rdbk_pin) {
+ case RDBK_CLKIN_SEL0:
+ reg = LMK04832_REG_CLKIN_SEL0;
+ break;
+ case RDBK_CLKIN_SEL1:
+ reg = LMK04832_REG_CLKIN_SEL1;
+ break;
+ case RDBK_RESET:
+ reg = LMK04832_REG_CLKIN_RST;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_write(lmk->regmap, reg,
+ FIELD_PREP(LMK04832_BIT_CLKIN_SEL_MUX,
+ LMK04832_VAL_CLKIN_SEL_MUX_SPI_RDBK) |
+ FIELD_PREP(LMK04832_BIT_CLKIN_SEL_TYPE,
+ LMK04832_VAL_CLKIN_SEL_TYPE_OUT));
+}
+
+static int lmk04832_probe(struct spi_device *spi)
+{
+ const struct lmk04832_device_info *info;
+ int rdbk_pin = RDBK_CLKIN_SEL1;
+ struct device_node *child;
+ struct lmk04832 *lmk;
+ u8 tmp[3];
+ int ret;
+ int i;
+
+ info = &lmk04832_device_info[spi_get_device_id(spi)->driver_data];
+
+ lmk = devm_kzalloc(&spi->dev, sizeof(struct lmk04832), GFP_KERNEL);
+ if (!lmk)
+ return -ENOMEM;
+
+ lmk->dev = &spi->dev;
+
+ lmk->oscin = devm_clk_get(lmk->dev, "oscin");
+ if (IS_ERR(lmk->oscin)) {
+ dev_err(lmk->dev, "failed to get oscin clock\n");
+ return PTR_ERR(lmk->oscin);
+ }
+
+ ret = clk_prepare_enable(lmk->oscin);
+ if (ret)
+ return ret;
+
+ lmk->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset",
+ GPIOD_OUT_LOW);
+
+ lmk->dclk = devm_kcalloc(lmk->dev, info->num_channels >> 1,
+ sizeof(struct lmk_dclk), GFP_KERNEL);
+ if (!lmk->dclk) {
+ ret = -ENOMEM;
+ goto err_disable_oscin;
+ }
+
+ lmk->clkout = devm_kcalloc(lmk->dev, info->num_channels,
+ sizeof(*lmk->clkout), GFP_KERNEL);
+ if (!lmk->clkout) {
+ ret = -ENOMEM;
+ goto err_disable_oscin;
+ }
+
+ lmk->clk_data = devm_kzalloc(lmk->dev, struct_size(lmk->clk_data, hws,
+ info->num_channels),
+ GFP_KERNEL);
+ if (!lmk->clk_data) {
+ ret = -ENOMEM;
+ goto err_disable_oscin;
+ }
+
+ device_property_read_u32(lmk->dev, "ti,vco-hz", &lmk->vco_rate);
+
+ lmk->sysref_ddly = 8;
+ device_property_read_u32(lmk->dev, "ti,sysref-ddly", &lmk->sysref_ddly);
+
+ lmk->sysref_mux = LMK04832_VAL_SYSREF_MUX_CONTINUOUS;
+ device_property_read_u32(lmk->dev, "ti,sysref-mux",
+ &lmk->sysref_mux);
+
+ lmk->sync_mode = LMK04832_VAL_SYNC_MODE_OFF;
+ device_property_read_u32(lmk->dev, "ti,sync-mode",
+ &lmk->sync_mode);
+
+ lmk->sysref_pulse_cnt = 4;
+ device_property_read_u32(lmk->dev, "ti,sysref-pulse-count",
+ &lmk->sysref_pulse_cnt);
+
+ for_each_child_of_node(lmk->dev->of_node, child) {
+ int reg;
+
+ ret = of_property_read_u32(child, "reg", &reg);
+ if (ret) {
+ dev_err(lmk->dev, "missing reg property in child: %s\n",
+ child->full_name);
+ of_node_put(child);
+ goto err_disable_oscin;
+ }
+
+ of_property_read_u32(child, "ti,clkout-fmt",
+ &lmk->clkout[reg].format);
+
+ if (lmk->clkout[reg].format >= 0x0a && reg % 2 == 0
+ && reg != 8 && reg != 10)
+ dev_err(lmk->dev, "invalid format for clkout%02d\n",
+ reg);
+
+ lmk->clkout[reg].sysref =
+ of_property_read_bool(child, "ti,clkout-sysref");
+ }
+
+ lmk->regmap = devm_regmap_init_spi(spi, &regmap_config);
+ if (IS_ERR(lmk->regmap)) {
+ dev_err(lmk->dev, "%s: regmap allocation failed: %ld\n",
+
+ __func__, PTR_ERR(lmk->regmap));
+ ret = PTR_ERR(lmk->regmap);
+ goto err_disable_oscin;
+ }
+
+ regmap_write(lmk->regmap, LMK04832_REG_RST3W, LMK04832_BIT_RESET);
+
+ if (!(spi->mode & SPI_3WIRE)) {
+ device_property_read_u32(lmk->dev, "ti,spi-4wire-rdbk",
+ &rdbk_pin);
+ ret = lmk04832_set_spi_rdbk(lmk, rdbk_pin);
+ if (ret)
+ goto err_disable_oscin;
+ }
+
+ regmap_bulk_read(lmk->regmap, LMK04832_REG_ID_PROD_MSB, &tmp, 3);
+ if ((tmp[0] << 8 | tmp[1]) != info->pid || tmp[2] != info->maskrev) {
+ dev_err(lmk->dev, "unsupported device type: pid 0x%04x, maskrev 0x%02x\n",
+ tmp[0] << 8 | tmp[1], tmp[2]);
+ ret = -EINVAL;
+ goto err_disable_oscin;
+ }
+
+ ret = lmk04832_register_vco(lmk);
+ if (ret) {
+ dev_err(lmk->dev, "failed to init device clock path\n");
+ goto err_disable_oscin;
+ }
+
+ if (lmk->vco_rate) {
+ dev_info(lmk->dev, "setting VCO rate to %u Hz\n", lmk->vco_rate);
+ ret = clk_set_rate(lmk->vco.clk, lmk->vco_rate);
+ if (ret) {
+ dev_err(lmk->dev, "failed to set VCO rate\n");
+ goto err_disable_vco;
+ }
+ }
+
+ ret = lmk04832_register_sclk(lmk);
+ if (ret) {
+ dev_err(lmk->dev, "failed to init SYNC/SYSREF clock path\n");
+ goto err_disable_vco;
+ }
+
+ for (i = 0; i < info->num_channels; i++) {
+ ret = lmk04832_register_clkout(lmk, i);
+ if (ret) {
+ dev_err(lmk->dev, "failed to register clk %d\n", i);
+ goto err_disable_vco;
+ }
+ }
+
+ lmk->clk_data->num = info->num_channels;
+ ret = of_clk_add_hw_provider(lmk->dev->of_node, of_clk_hw_onecell_get,
+ lmk->clk_data);
+ if (ret) {
+ dev_err(lmk->dev, "failed to add provider (%d)\n", ret);
+ goto err_disable_vco;
+ }
+
+ spi_set_drvdata(spi, lmk);
+
+ return 0;
+
+err_disable_vco:
+ clk_disable_unprepare(lmk->vco.clk);
+
+err_disable_oscin:
+ clk_disable_unprepare(lmk->oscin);
+
+ return ret;
+}
+
+static int lmk04832_remove(struct spi_device *spi)
+{
+ struct lmk04832 *lmk = spi_get_drvdata(spi);
+
+ clk_disable_unprepare(lmk->oscin);
+ of_clk_del_provider(spi->dev.of_node);
+
+ return 0;
+}
+static const struct spi_device_id lmk04832_id[] = {
+ { "lmk04832", LMK04832 },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, lmk04832_id);
+
+static const struct of_device_id lmk04832_of_id[] = {
+ { .compatible = "ti,lmk04832" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, lmk04832_of_id);
+
+static struct spi_driver lmk04832_driver = {
+ .driver = {
+ .name = "lmk04832",
+ .of_match_table = lmk04832_of_id,
+ },
+ .probe = lmk04832_probe,
+ .remove = lmk04832_remove,
+ .id_table = lmk04832_id,
+};
+module_spi_driver(lmk04832_driver);
+
+MODULE_AUTHOR("Liam Beguin <lvb@xiphos.com>");
+MODULE_DESCRIPTION("Texas Instruments LMK04832");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index e0446e66fa64..57ae183982d8 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -19,6 +19,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
@@ -59,6 +60,7 @@ struct clk_si5341_synth {
struct clk_si5341_output {
struct clk_hw hw;
struct clk_si5341 *data;
+ struct regulator *vddo_reg;
u8 index;
};
#define to_clk_si5341_output(_hw) \
@@ -78,12 +80,15 @@ struct clk_si5341 {
u8 num_outputs;
u8 num_synth;
u16 chip_id;
+ bool xaxb_ext_clk;
+ bool iovdd_33;
};
#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;
+ u8 vdd_sel_bits;
bool synth_master;
bool always_on;
};
@@ -92,12 +97,23 @@ struct clk_si5341_output_config {
#define SI5341_PN_BASE 0x0002
#define SI5341_DEVICE_REV 0x0005
#define SI5341_STATUS 0x000C
+#define SI5341_LOS 0x000D
+#define SI5341_STATUS_STICKY 0x0011
+#define SI5341_LOS_STICKY 0x0012
#define SI5341_SOFT_RST 0x001C
#define SI5341_IN_SEL 0x0021
+#define SI5341_DEVICE_READY 0x00FE
#define SI5341_XAXB_CFG 0x090E
+#define SI5341_IO_VDD_SEL 0x0943
#define SI5341_IN_EN 0x0949
#define SI5341_INX_TO_PFD_EN 0x094A
+/* Status bits */
+#define SI5341_STATUS_SYSINCAL BIT(0)
+#define SI5341_STATUS_LOSXAXB BIT(1)
+#define SI5341_STATUS_LOSREF BIT(2)
+#define SI5341_STATUS_LOL BIT(3)
+
/* Input selection */
#define SI5341_IN_SEL_MASK 0x06
#define SI5341_IN_SEL_SHIFT 1
@@ -126,6 +142,8 @@ struct clk_si5341_output_config {
#define SI5341_OUT_R_REG(output) \
((output)->data->reg_rdiv_offset[(output)->index])
+#define SI5341_OUT_MUX_VDD_SEL_MASK 0x38
+
/* Synthesize N divider */
#define SI5341_SYNTH_N_NUM(x) (0x0302 + ((x) * 11))
#define SI5341_SYNTH_N_DEN(x) (0x0308 + ((x) * 11))
@@ -335,11 +353,12 @@ static const struct si5341_reg_default si5341_reg_defaults[] = {
{ 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) */
+ { 0x0B57, 0x10 }, /* VCO_RESET_CALCODE (not described in datasheet) */
+ { 0x0B58, 0x05 }, /* VCO_RESET_CALCODE (not described in datasheet) */
};
/* Read and interpret a 44-bit followed by a 32-bit value in the regmap */
@@ -512,9 +531,11 @@ static int si5341_clk_reparent(struct clk_si5341 *data, u8 index)
if (err < 0)
return err;
- /* Power up XTAL oscillator and buffer */
+ /* Power up XTAL oscillator and buffer, select clock mode */
err = regmap_update_bits(data->regmap, SI5341_XAXB_CFG,
- SI5341_XAXB_CFG_PDNB, SI5341_XAXB_CFG_PDNB);
+ SI5341_XAXB_CFG_PDNB | SI5341_XAXB_CFG_EXTCLK_EN,
+ SI5341_XAXB_CFG_PDNB | (data->xaxb_ext_clk ?
+ SI5341_XAXB_CFG_EXTCLK_EN : 0));
if (err < 0)
return err;
}
@@ -623,6 +644,9 @@ static unsigned long si5341_synth_clk_recalc_rate(struct clk_hw *hw,
SI5341_SYNTH_N_NUM(synth->index), &n_num, &n_den);
if (err < 0)
return err;
+ /* Check for bogus/uninitialized settings */
+ if (!n_num || !n_den)
+ return 0;
/*
* n_num and n_den are shifted left as much as possible, so to prevent
@@ -806,6 +830,9 @@ static long si5341_output_clk_round_rate(struct clk_hw *hw, unsigned long rate,
{
unsigned long r;
+ if (!rate)
+ return 0;
+
r = *parent_rate >> 1;
/* If rate is an even divisor, no changes to parent required */
@@ -834,11 +861,16 @@ 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;
+ u32 r_div;
int err;
u8 r[3];
+ if (!rate)
+ return -EINVAL;
+
+ /* Frequency divider is (r_div + 1) * 2 */
+ r_div = (parent_rate / rate) >> 1;
+
if (r_div <= 1)
r_div = 0;
else if (r_div >= BIT(24))
@@ -1083,7 +1115,7 @@ static const struct si5341_reg_default si5341_preamble[] = {
{ 0x0B25, 0x00 },
{ 0x0502, 0x01 },
{ 0x0505, 0x03 },
- { 0x0957, 0x1F },
+ { 0x0957, 0x17 },
{ 0x0B4E, 0x1A },
};
@@ -1129,6 +1161,11 @@ static int si5341_finalize_defaults(struct clk_si5341 *data)
int res;
u32 revision;
+ res = regmap_write(data->regmap, SI5341_IO_VDD_SEL,
+ data->iovdd_33 ? 1 : 0);
+ if (res < 0)
+ return res;
+
res = regmap_read(data->regmap, SI5341_DEVICE_REV, &revision);
if (res < 0)
return res;
@@ -1189,6 +1226,32 @@ static const struct regmap_range_cfg si5341_regmap_ranges[] = {
},
};
+static int si5341_wait_device_ready(struct i2c_client *client)
+{
+ int count;
+
+ /* Datasheet warns: Any attempt to read or write any register other
+ * than DEVICE_READY before DEVICE_READY reads as 0x0F may corrupt the
+ * NVM programming and may corrupt the register contents, as they are
+ * read from NVM. Note that this includes accesses to the PAGE register.
+ * Also: DEVICE_READY is available on every register page, so no page
+ * change is needed to read it.
+ * Do this outside regmap to avoid automatic PAGE register access.
+ * May take up to 300ms to complete.
+ */
+ for (count = 0; count < 15; ++count) {
+ s32 result = i2c_smbus_read_byte_data(client,
+ SI5341_DEVICE_READY);
+ if (result < 0)
+ return result;
+ if (result == 0x0F)
+ return 0;
+ msleep(20);
+ }
+ dev_err(&client->dev, "timeout waiting for DEVICE_READY\n");
+ return -EIO;
+}
+
static const struct regmap_config si5341_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -1199,11 +1262,11 @@ static const struct regmap_config si5341_regmap_config = {
.volatile_table = &si5341_regmap_volatile,
};
-static int si5341_dt_parse_dt(struct i2c_client *client,
- struct clk_si5341_output_config *config)
+static int si5341_dt_parse_dt(struct clk_si5341 *data,
+ struct clk_si5341_output_config *config)
{
struct device_node *child;
- struct device_node *np = client->dev.of_node;
+ struct device_node *np = data->i2c_client->dev.of_node;
u32 num;
u32 val;
@@ -1212,13 +1275,13 @@ static int si5341_dt_parse_dt(struct i2c_client *client,
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",
+ dev_err(&data->i2c_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);
+ dev_err(&data->i2c_client->dev, "invalid clkout %d\n", num);
goto put_child;
}
@@ -1237,7 +1300,7 @@ static int si5341_dt_parse_dt(struct i2c_client *client,
config[num].out_format_drv_bits |= 0xc0;
break;
default:
- dev_err(&client->dev,
+ dev_err(&data->i2c_client->dev,
"invalid silabs,format %u for %u\n",
val, num);
goto put_child;
@@ -1250,7 +1313,7 @@ static int si5341_dt_parse_dt(struct i2c_client *client,
if (!of_property_read_u32(child, "silabs,common-mode", &val)) {
if (val > 0xf) {
- dev_err(&client->dev,
+ dev_err(&data->i2c_client->dev,
"invalid silabs,common-mode %u\n",
val);
goto put_child;
@@ -1261,7 +1324,7 @@ static int si5341_dt_parse_dt(struct i2c_client *client,
if (!of_property_read_u32(child, "silabs,amplitude", &val)) {
if (val > 0xf) {
- dev_err(&client->dev,
+ dev_err(&data->i2c_client->dev,
"invalid silabs,amplitude %u\n",
val);
goto put_child;
@@ -1278,6 +1341,34 @@ static int si5341_dt_parse_dt(struct i2c_client *client,
config[num].always_on =
of_property_read_bool(child, "always-on");
+
+ config[num].vdd_sel_bits = 0x08;
+ if (data->clk[num].vddo_reg) {
+ int vdd = regulator_get_voltage(data->clk[num].vddo_reg);
+
+ switch (vdd) {
+ case 3300000:
+ config[num].vdd_sel_bits |= 0 << 4;
+ break;
+ case 1800000:
+ config[num].vdd_sel_bits |= 1 << 4;
+ break;
+ case 2500000:
+ config[num].vdd_sel_bits |= 2 << 4;
+ break;
+ default:
+ dev_err(&data->i2c_client->dev,
+ "unsupported vddo voltage %d for %s\n",
+ vdd, child->name);
+ goto put_child;
+ }
+ } else {
+ /* chip seems to default to 2.5V when not set */
+ dev_warn(&data->i2c_client->dev,
+ "no regulator set, defaulting vdd_sel to 2.5V for %s\n",
+ child->name);
+ config[num].vdd_sel_bits |= 2 << 4;
+ }
}
return 0;
@@ -1366,6 +1457,94 @@ static int si5341_clk_select_active_input(struct clk_si5341 *data)
return res;
}
+static ssize_t input_present_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct clk_si5341 *data = dev_get_drvdata(dev);
+ u32 status;
+ int res = regmap_read(data->regmap, SI5341_STATUS, &status);
+
+ if (res < 0)
+ return res;
+ res = !(status & SI5341_STATUS_LOSREF);
+ return snprintf(buf, PAGE_SIZE, "%d\n", res);
+}
+static DEVICE_ATTR_RO(input_present);
+
+static ssize_t input_present_sticky_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct clk_si5341 *data = dev_get_drvdata(dev);
+ u32 status;
+ int res = regmap_read(data->regmap, SI5341_STATUS_STICKY, &status);
+
+ if (res < 0)
+ return res;
+ res = !(status & SI5341_STATUS_LOSREF);
+ return snprintf(buf, PAGE_SIZE, "%d\n", res);
+}
+static DEVICE_ATTR_RO(input_present_sticky);
+
+static ssize_t pll_locked_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct clk_si5341 *data = dev_get_drvdata(dev);
+ u32 status;
+ int res = regmap_read(data->regmap, SI5341_STATUS, &status);
+
+ if (res < 0)
+ return res;
+ res = !(status & SI5341_STATUS_LOL);
+ return snprintf(buf, PAGE_SIZE, "%d\n", res);
+}
+static DEVICE_ATTR_RO(pll_locked);
+
+static ssize_t pll_locked_sticky_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct clk_si5341 *data = dev_get_drvdata(dev);
+ u32 status;
+ int res = regmap_read(data->regmap, SI5341_STATUS_STICKY, &status);
+
+ if (res < 0)
+ return res;
+ res = !(status & SI5341_STATUS_LOL);
+ return snprintf(buf, PAGE_SIZE, "%d\n", res);
+}
+static DEVICE_ATTR_RO(pll_locked_sticky);
+
+static ssize_t clear_sticky_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct clk_si5341 *data = dev_get_drvdata(dev);
+ long val;
+
+ if (kstrtol(buf, 10, &val))
+ return -EINVAL;
+ if (val) {
+ int res = regmap_write(data->regmap, SI5341_STATUS_STICKY, 0);
+
+ if (res < 0)
+ return res;
+ }
+ return count;
+}
+static DEVICE_ATTR_WO(clear_sticky);
+
+static const struct attribute *si5341_attributes[] = {
+ &dev_attr_input_present.attr,
+ &dev_attr_input_present_sticky.attr,
+ &dev_attr_pll_locked.attr,
+ &dev_attr_pll_locked_sticky.attr,
+ &dev_attr_clear_sticky.attr,
+ NULL
+};
+
static int si5341_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1378,6 +1557,7 @@ static int si5341_probe(struct i2c_client *client,
unsigned int i;
struct clk_si5341_output_config config[SI5341_MAX_NUM_OUTPUTS];
bool initialization_required;
+ u32 status;
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -1385,6 +1565,11 @@ static int si5341_probe(struct i2c_client *client,
data->i2c_client = client;
+ /* Must be done before otherwise touching hardware */
+ err = si5341_wait_device_ready(client);
+ if (err)
+ return err;
+
for (i = 0; i < SI5341_NUM_INPUTS; ++i) {
input = devm_clk_get(&client->dev, si5341_input_clock_names[i]);
if (IS_ERR(input)) {
@@ -1397,9 +1582,33 @@ static int si5341_probe(struct i2c_client *client,
}
}
- err = si5341_dt_parse_dt(client, config);
+ for (i = 0; i < SI5341_MAX_NUM_OUTPUTS; ++i) {
+ char reg_name[10];
+
+ snprintf(reg_name, sizeof(reg_name), "vddo%d", i);
+ data->clk[i].vddo_reg = devm_regulator_get_optional(
+ &client->dev, reg_name);
+ if (IS_ERR(data->clk[i].vddo_reg)) {
+ err = PTR_ERR(data->clk[i].vddo_reg);
+ data->clk[i].vddo_reg = NULL;
+ if (err == -ENODEV)
+ continue;
+ goto cleanup;
+ } else {
+ err = regulator_enable(data->clk[i].vddo_reg);
+ if (err) {
+ dev_err(&client->dev,
+ "failed to enable %s regulator: %d\n",
+ reg_name, err);
+ data->clk[i].vddo_reg = NULL;
+ goto cleanup;
+ }
+ }
+ }
+
+ err = si5341_dt_parse_dt(data, config);
if (err)
- return err;
+ goto cleanup;
if (of_property_read_string(client->dev.of_node, "clock-output-names",
&init.name))
@@ -1407,34 +1616,40 @@ static int si5341_probe(struct i2c_client *client,
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);
+ if (IS_ERR(data->regmap)) {
+ err = PTR_ERR(data->regmap);
+ goto cleanup;
+ }
i2c_set_clientdata(client, data);
err = si5341_probe_chip_id(data);
if (err < 0)
- return err;
+ goto cleanup;
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;
+ goto cleanup;
initialization_required = !err;
}
+ data->xaxb_ext_clk = of_property_read_bool(client->dev.of_node,
+ "silabs,xaxb-ext-clk");
+ data->iovdd_33 = of_property_read_bool(client->dev.of_node,
+ "silabs,iovdd-33");
if (initialization_required) {
/* Populate the regmap cache in preparation for "cache only" */
err = si5341_read_settings(data);
if (err < 0)
- return err;
+ goto cleanup;
err = si5341_send_preamble(data);
if (err < 0)
- return err;
+ goto cleanup;
/*
* We intend to send all 'final' register values in a single
@@ -1447,19 +1662,19 @@ static int si5341_probe(struct i2c_client *client,
err = si5341_write_multiple(data, si5341_reg_defaults,
ARRAY_SIZE(si5341_reg_defaults));
if (err < 0)
- return err;
+ goto cleanup;
}
/* Input must be up and running at this point */
err = si5341_clk_select_active_input(data);
if (err < 0)
- return err;
+ goto cleanup;
if (initialization_required) {
/* PLL configuration is required */
err = si5341_initialize_pll(data);
if (err < 0)
- return err;
+ goto cleanup;
}
/* Register the PLL */
@@ -1472,7 +1687,7 @@ static int si5341_probe(struct i2c_client *client,
err = devm_clk_hw_register(&client->dev, &data->hw);
if (err) {
dev_err(&client->dev, "clock registration failed\n");
- return err;
+ goto cleanup;
}
init.num_parents = 1;
@@ -1509,13 +1724,17 @@ static int si5341_probe(struct i2c_client *client,
regmap_write(data->regmap,
SI5341_OUT_CM(&data->clk[i]),
config[i].out_cm_ampl_bits);
+ regmap_update_bits(data->regmap,
+ SI5341_OUT_MUX_SEL(&data->clk[i]),
+ SI5341_OUT_MUX_VDD_SEL_MASK,
+ config[i].vdd_sel_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;
+ goto cleanup;
}
if (config[i].always_on)
clk_prepare(data->clk[i].hw.clk);
@@ -1525,7 +1744,7 @@ static int si5341_probe(struct i2c_client *client,
data);
if (err) {
dev_err(&client->dev, "unable to add clk provider\n");
- return err;
+ goto cleanup;
}
if (initialization_required) {
@@ -1533,11 +1752,33 @@ static int si5341_probe(struct i2c_client *client,
regcache_cache_only(data->regmap, false);
err = regcache_sync(data->regmap);
if (err < 0)
- return err;
+ goto cleanup;
err = si5341_finalize_defaults(data);
if (err < 0)
- return err;
+ goto cleanup;
+ }
+
+ /* wait for device to report input clock present and PLL lock */
+ err = regmap_read_poll_timeout(data->regmap, SI5341_STATUS, status,
+ !(status & (SI5341_STATUS_LOSREF | SI5341_STATUS_LOL)),
+ 10000, 250000);
+ if (err) {
+ dev_err(&client->dev, "Error waiting for input clock or PLL lock\n");
+ goto cleanup;
+ }
+
+ /* clear sticky alarm bits from initialization */
+ err = regmap_write(data->regmap, SI5341_STATUS_STICKY, 0);
+ if (err) {
+ dev_err(&client->dev, "unable to clear sticky status\n");
+ goto cleanup;
+ }
+
+ err = sysfs_create_files(&client->dev.kobj, si5341_attributes);
+ if (err) {
+ dev_err(&client->dev, "unable to create sysfs files\n");
+ goto cleanup;
}
/* Free the names, clk framework makes copies */
@@ -1545,6 +1786,28 @@ static int si5341_probe(struct i2c_client *client,
devm_kfree(&client->dev, (void *)synth_clock_names[i]);
return 0;
+
+cleanup:
+ for (i = 0; i < SI5341_MAX_NUM_OUTPUTS; ++i) {
+ if (data->clk[i].vddo_reg)
+ regulator_disable(data->clk[i].vddo_reg);
+ }
+ return err;
+}
+
+static int si5341_remove(struct i2c_client *client)
+{
+ struct clk_si5341 *data = i2c_get_clientdata(client);
+ int i;
+
+ sysfs_remove_files(&client->dev.kobj, si5341_attributes);
+
+ for (i = 0; i < SI5341_MAX_NUM_OUTPUTS; ++i) {
+ if (data->clk[i].vddo_reg)
+ regulator_disable(data->clk[i].vddo_reg);
+ }
+
+ return 0;
}
static const struct i2c_device_id si5341_id[] = {
@@ -1573,6 +1836,7 @@ static struct i2c_driver si5341_driver = {
.of_match_table = clk_si5341_of_match,
},
.probe = si5341_probe,
+ .remove = si5341_remove,
.id_table = si5341_id,
};
module_i2c_driver(si5341_driver);
diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index a875649df8b8..256575bd29b9 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -10,8 +10,11 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -245,7 +248,7 @@ static const char * const dsi_src[] = {
};
static const char * const rtc_src[] = {
- "off", "ck_lse", "ck_lsi", "ck_hse_rtc"
+ "off", "ck_lse", "ck_lsi", "ck_hse"
};
static const char * const mco1_src[] = {
@@ -469,7 +472,7 @@ static const struct clk_ops mp1_gate_clk_ops = {
.is_enabled = clk_gate_is_enabled,
};
-static struct clk_hw *_get_stm32_mux(void __iomem *base,
+static struct clk_hw *_get_stm32_mux(struct device *dev, void __iomem *base,
const struct stm32_mux_cfg *cfg,
spinlock_t *lock)
{
@@ -478,7 +481,7 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base,
struct clk_hw *mux_hw;
if (cfg->mmux) {
- mmux = kzalloc(sizeof(*mmux), GFP_KERNEL);
+ mmux = devm_kzalloc(dev, sizeof(*mmux), GFP_KERNEL);
if (!mmux)
return ERR_PTR(-ENOMEM);
@@ -493,7 +496,7 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base,
cfg->mmux->hws[cfg->mmux->nbr_clk++] = mux_hw;
} else {
- mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
if (!mux)
return ERR_PTR(-ENOMEM);
@@ -509,13 +512,13 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base,
return mux_hw;
}
-static struct clk_hw *_get_stm32_div(void __iomem *base,
+static struct clk_hw *_get_stm32_div(struct device *dev, void __iomem *base,
const struct stm32_div_cfg *cfg,
spinlock_t *lock)
{
struct clk_divider *div;
- div = kzalloc(sizeof(*div), GFP_KERNEL);
+ div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL);
if (!div)
return ERR_PTR(-ENOMEM);
@@ -530,16 +533,16 @@ static struct clk_hw *_get_stm32_div(void __iomem *base,
return &div->hw;
}
-static struct clk_hw *
-_get_stm32_gate(void __iomem *base,
- const struct stm32_gate_cfg *cfg, spinlock_t *lock)
+static struct clk_hw *_get_stm32_gate(struct device *dev, void __iomem *base,
+ const struct stm32_gate_cfg *cfg,
+ spinlock_t *lock)
{
struct stm32_clk_mgate *mgate;
struct clk_gate *gate;
struct clk_hw *gate_hw;
if (cfg->mgate) {
- mgate = kzalloc(sizeof(*mgate), GFP_KERNEL);
+ mgate = devm_kzalloc(dev, sizeof(*mgate), GFP_KERNEL);
if (!mgate)
return ERR_PTR(-ENOMEM);
@@ -554,7 +557,7 @@ _get_stm32_gate(void __iomem *base,
gate_hw = &mgate->gate.hw;
} else {
- gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
if (!gate)
return ERR_PTR(-ENOMEM);
@@ -592,7 +595,7 @@ clk_stm32_register_gate_ops(struct device *dev,
if (cfg->ops)
init.ops = cfg->ops;
- hw = _get_stm32_gate(base, cfg, lock);
+ hw = _get_stm32_gate(dev, base, cfg, lock);
if (IS_ERR(hw))
return ERR_PTR(-ENOMEM);
@@ -623,7 +626,7 @@ clk_stm32_register_composite(struct device *dev,
gate_ops = NULL;
if (cfg->mux) {
- mux_hw = _get_stm32_mux(base, cfg->mux, lock);
+ mux_hw = _get_stm32_mux(dev, base, cfg->mux, lock);
if (!IS_ERR(mux_hw)) {
mux_ops = &clk_mux_ops;
@@ -634,7 +637,7 @@ clk_stm32_register_composite(struct device *dev,
}
if (cfg->div) {
- div_hw = _get_stm32_div(base, cfg->div, lock);
+ div_hw = _get_stm32_div(dev, base, cfg->div, lock);
if (!IS_ERR(div_hw)) {
div_ops = &clk_divider_ops;
@@ -645,7 +648,7 @@ clk_stm32_register_composite(struct device *dev,
}
if (cfg->gate) {
- gate_hw = _get_stm32_gate(base, cfg->gate, lock);
+ gate_hw = _get_stm32_gate(dev, base, cfg->gate, lock);
if (!IS_ERR(gate_hw)) {
gate_ops = &clk_gate_ops;
@@ -731,6 +734,7 @@ struct stm32_pll_obj {
spinlock_t *lock;
void __iomem *reg;
struct clk_hw hw;
+ struct clk_mux mux;
};
#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw)
@@ -745,6 +749,8 @@ struct stm32_pll_obj {
#define FRAC_MASK 0x1FFF
#define FRAC_SHIFT 3
#define FRACLE BIT(16)
+#define PLL_MUX_SHIFT 0
+#define PLL_MUX_MASK 3
static int __pll_is_enabled(struct clk_hw *hw)
{
@@ -856,16 +862,29 @@ static int pll_is_enabled(struct clk_hw *hw)
return ret;
}
+static u8 pll_get_parent(struct clk_hw *hw)
+{
+ struct stm32_pll_obj *clk_elem = to_pll(hw);
+ struct clk_hw *mux_hw = &clk_elem->mux.hw;
+
+ __clk_hw_set_clk(mux_hw, hw);
+
+ return clk_mux_ops.get_parent(mux_hw);
+}
+
static const struct clk_ops pll_ops = {
.enable = pll_enable,
.disable = pll_disable,
.recalc_rate = pll_recalc_rate,
.is_enabled = pll_is_enabled,
+ .get_parent = pll_get_parent,
};
static struct clk_hw *clk_register_pll(struct device *dev, const char *name,
- const char *parent_name,
+ const char * const *parent_names,
+ int num_parents,
void __iomem *reg,
+ void __iomem *mux_reg,
unsigned long flags,
spinlock_t *lock)
{
@@ -874,15 +893,22 @@ static struct clk_hw *clk_register_pll(struct device *dev, const char *name,
struct clk_hw *hw;
int err;
- element = kzalloc(sizeof(*element), GFP_KERNEL);
+ element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL);
if (!element)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &pll_ops;
init.flags = flags;
- init.parent_names = &parent_name;
- init.num_parents = 1;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+
+ element->mux.lock = lock;
+ element->mux.reg = mux_reg;
+ element->mux.shift = PLL_MUX_SHIFT;
+ element->mux.mask = PLL_MUX_MASK;
+ element->mux.flags = CLK_MUX_READ_ONLY;
+ element->mux.reg = mux_reg;
element->hw.init = &init;
element->reg = reg;
@@ -891,10 +917,8 @@ static struct clk_hw *clk_register_pll(struct device *dev, const char *name,
hw = &element->hw;
err = clk_hw_register(dev, hw);
- if (err) {
- kfree(element);
+ if (err)
return ERR_PTR(err);
- }
return hw;
}
@@ -1005,7 +1029,7 @@ static struct clk_hw *clk_register_cktim(struct device *dev, const char *name,
struct clk_hw *hw;
int err;
- tim_ker = kzalloc(sizeof(*tim_ker), GFP_KERNEL);
+ tim_ker = devm_kzalloc(dev, sizeof(*tim_ker), GFP_KERNEL);
if (!tim_ker)
return ERR_PTR(-ENOMEM);
@@ -1023,16 +1047,56 @@ static struct clk_hw *clk_register_cktim(struct device *dev, const char *name,
hw = &tim_ker->hw;
err = clk_hw_register(dev, hw);
- if (err) {
- kfree(tim_ker);
+ if (err)
return ERR_PTR(err);
- }
return hw;
}
+/* The divider of RTC clock concerns only ck_hse clock */
+#define HSE_RTC 3
+
+static unsigned long clk_divider_rtc_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ if (clk_hw_get_parent(hw) == clk_hw_get_parent_by_index(hw, HSE_RTC))
+ return clk_divider_ops.recalc_rate(hw, parent_rate);
+
+ return parent_rate;
+}
+
+static int clk_divider_rtc_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ if (clk_hw_get_parent(hw) == clk_hw_get_parent_by_index(hw, HSE_RTC))
+ return clk_divider_ops.set_rate(hw, rate, parent_rate);
+
+ return parent_rate;
+}
+
+static int clk_divider_rtc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ unsigned long best_parent_rate = req->best_parent_rate;
+
+ if (req->best_parent_hw == clk_hw_get_parent_by_index(hw, HSE_RTC)) {
+ req->rate = clk_divider_ops.round_rate(hw, req->rate, &best_parent_rate);
+ req->best_parent_rate = best_parent_rate;
+ } else {
+ req->rate = best_parent_rate;
+ }
+
+ return 0;
+}
+
+static const struct clk_ops rtc_div_clk_ops = {
+ .recalc_rate = clk_divider_rtc_recalc_rate,
+ .set_rate = clk_divider_rtc_set_rate,
+ .determine_rate = clk_divider_rtc_determine_rate
+};
+
struct stm32_pll_cfg {
u32 offset;
+ u32 muxoff;
};
static struct clk_hw *_clk_register_pll(struct device *dev,
@@ -1042,8 +1106,11 @@ static struct clk_hw *_clk_register_pll(struct device *dev,
{
struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg;
- return clk_register_pll(dev, cfg->name, cfg->parent_name,
- base + stm_pll_cfg->offset, cfg->flags, lock);
+ return clk_register_pll(dev, cfg->name, cfg->parent_names,
+ cfg->num_parents,
+ base + stm_pll_cfg->offset,
+ base + stm_pll_cfg->muxoff,
+ cfg->flags, lock);
}
struct stm32_cktim_cfg {
@@ -1153,14 +1220,16 @@ _clk_stm32_register_composite(struct device *dev,
.func = _clk_hw_register_mux,\
}
-#define PLL(_id, _name, _parent, _flags, _offset)\
+#define PLL(_id, _name, _parents, _flags, _offset_p, _offset_mux)\
{\
.id = _id,\
.name = _name,\
- .parent_name = _parent,\
- .flags = _flags,\
+ .parent_names = _parents,\
+ .num_parents = ARRAY_SIZE(_parents),\
+ .flags = CLK_IGNORE_UNUSED | (_flags),\
.cfg = &(struct stm32_pll_cfg) {\
- .offset = _offset,\
+ .offset = _offset_p,\
+ .muxoff = _offset_mux,\
},\
.func = _clk_register_pll,\
}
@@ -1243,6 +1312,10 @@ _clk_stm32_register_composite(struct device *dev,
_STM32_DIV(_div_offset, _div_shift, _div_width,\
_div_flags, _div_table, NULL)\
+#define _DIV_RTC(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\
+ _STM32_DIV(_div_offset, _div_shift, _div_width,\
+ _div_flags, _div_table, &rtc_div_clk_ops)
+
#define _STM32_MUX(_offset, _shift, _width, _mux_flags, _mmux, _ops)\
.mux = &(struct stm32_mux_cfg) {\
&(struct mux_cfg) {\
@@ -1657,36 +1730,26 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = {
};
static const struct clock_config stm32mp1_clock_cfg[] = {
- /* Oscillator divider */
- DIV(NO_ID, "clk-hsi-div", "clk-hsi", CLK_DIVIDER_POWER_OF_TWO,
- RCC_HSICFGR, 0, 2, CLK_DIVIDER_READ_ONLY),
-
/* External / Internal Oscillators */
GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0),
/* ck_csi is used by IO compensation and should be critical */
GATE_MP1(CK_CSI, "ck_csi", "clk-csi", CLK_IS_CRITICAL,
RCC_OCENSETR, 4, 0),
- GATE_MP1(CK_HSI, "ck_hsi", "clk-hsi-div", 0, RCC_OCENSETR, 0, 0),
+ COMPOSITE(CK_HSI, "ck_hsi", PARENT("clk-hsi"), 0,
+ _GATE_MP1(RCC_OCENSETR, 0, 0),
+ _NO_MUX,
+ _DIV(RCC_HSICFGR, 0, 2, CLK_DIVIDER_POWER_OF_TWO |
+ CLK_DIVIDER_READ_ONLY, NULL)),
GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0),
GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0),
FIXED_FACTOR(CK_HSE_DIV2, "clk-hse-div2", "ck_hse", 0, 1, 2),
- /* ref clock pll */
- MUX(NO_ID, "ref1", ref12_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK12SELR,
- 0, 2, CLK_MUX_READ_ONLY),
-
- MUX(NO_ID, "ref3", ref3_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK3SELR,
- 0, 2, CLK_MUX_READ_ONLY),
-
- MUX(NO_ID, "ref4", ref4_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK4SELR,
- 0, 2, CLK_MUX_READ_ONLY),
-
/* PLLs */
- PLL(PLL1, "pll1", "ref1", CLK_IGNORE_UNUSED, RCC_PLL1CR),
- PLL(PLL2, "pll2", "ref1", CLK_IGNORE_UNUSED, RCC_PLL2CR),
- PLL(PLL3, "pll3", "ref3", CLK_IGNORE_UNUSED, RCC_PLL3CR),
- PLL(PLL4, "pll4", "ref4", CLK_IGNORE_UNUSED, RCC_PLL4CR),
+ PLL(PLL1, "pll1", ref12_parents, 0, RCC_PLL1CR, RCC_RCK12SELR),
+ PLL(PLL2, "pll2", ref12_parents, 0, RCC_PLL2CR, RCC_RCK12SELR),
+ PLL(PLL3, "pll3", ref3_parents, 0, RCC_PLL3CR, RCC_RCK3SELR),
+ PLL(PLL4, "pll4", ref4_parents, 0, RCC_PLL4CR, RCC_RCK4SELR),
/* ODF */
COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0,
@@ -1965,13 +2028,10 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
_DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)),
/* RTC clock */
- DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 6, 0),
-
- COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE |
- CLK_SET_RATE_PARENT,
+ COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE,
_GATE(RCC_BDCR, 20, 0),
_MUX(RCC_BDCR, 16, 2, 0),
- _NO_DIV),
+ _DIV_RTC(RCC_RTCDIVR, 0, 6, 0, NULL)),
/* MCO clocks */
COMPOSITE(CK_MCO1, "ck_mco1", mco1_src, CLK_OPS_PARENT_ENABLE |
@@ -1996,16 +2056,76 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
_DIV(RCC_DBGCFGR, 0, 3, 0, ck_trace_div_table)),
};
-struct stm32_clock_match_data {
+static const u32 stm32mp1_clock_secured[] = {
+ CK_HSE,
+ CK_HSI,
+ CK_CSI,
+ CK_LSI,
+ CK_LSE,
+ PLL1,
+ PLL2,
+ PLL1_P,
+ PLL2_P,
+ PLL2_Q,
+ PLL2_R,
+ CK_MPU,
+ CK_AXI,
+ SPI6,
+ I2C4,
+ I2C6,
+ USART1,
+ RTCAPB,
+ TZC1,
+ TZC2,
+ TZPC,
+ IWDG1,
+ BSEC,
+ STGEN,
+ GPIOZ,
+ CRYP1,
+ HASH1,
+ RNG1,
+ BKPSRAM,
+ RNG1_K,
+ STGEN_K,
+ SPI6_K,
+ I2C4_K,
+ I2C6_K,
+ USART1_K,
+ RTC,
+};
+
+static bool stm32_check_security(const struct clock_config *cfg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(stm32mp1_clock_secured); i++)
+ if (cfg->id == stm32mp1_clock_secured[i])
+ return true;
+ return false;
+}
+
+struct stm32_rcc_match_data {
const struct clock_config *cfg;
unsigned int num;
unsigned int maxbinding;
+ u32 clear_offset;
+ bool (*check_security)(const struct clock_config *cfg);
};
-static struct stm32_clock_match_data stm32mp1_data = {
+static struct stm32_rcc_match_data stm32mp1_data = {
.cfg = stm32mp1_clock_cfg,
.num = ARRAY_SIZE(stm32mp1_clock_cfg),
.maxbinding = STM32MP1_LAST_CLK,
+ .clear_offset = RCC_CLR,
+};
+
+static struct stm32_rcc_match_data stm32mp1_data_secure = {
+ .cfg = stm32mp1_clock_cfg,
+ .num = ARRAY_SIZE(stm32mp1_clock_cfg),
+ .maxbinding = STM32MP1_LAST_CLK,
+ .clear_offset = RCC_CLR,
+ .check_security = &stm32_check_security
};
static const struct of_device_id stm32mp1_match_data[] = {
@@ -2013,8 +2133,13 @@ static const struct of_device_id stm32mp1_match_data[] = {
.compatible = "st,stm32mp1-rcc",
.data = &stm32mp1_data,
},
+ {
+ .compatible = "st,stm32mp1-rcc-secure",
+ .data = &stm32mp1_data_secure,
+ },
{ }
};
+MODULE_DEVICE_TABLE(of, stm32mp1_match_data);
static int stm32_register_hw_clk(struct device *dev,
struct clk_hw_onecell_data *clk_data,
@@ -2040,28 +2165,127 @@ static int stm32_register_hw_clk(struct device *dev,
return 0;
}
-static int stm32_rcc_init(struct device_node *np,
- void __iomem *base,
- const struct of_device_id *match_data)
+#define STM32_RESET_ID_MASK GENMASK(15, 0)
+
+struct stm32_reset_data {
+ /* reset lock */
+ spinlock_t lock;
+ struct reset_controller_dev rcdev;
+ void __iomem *membase;
+ u32 clear_offset;
+};
+
+static inline struct stm32_reset_data *
+to_stm32_reset_data(struct reset_controller_dev *rcdev)
{
- struct clk_hw_onecell_data *clk_data;
- struct clk_hw **hws;
- const struct of_device_id *match;
- const struct stm32_clock_match_data *data;
- int err, n, max_binding;
+ return container_of(rcdev, struct stm32_reset_data, rcdev);
+}
- match = of_match_node(match_data, np);
- if (!match) {
- pr_err("%s: match data not found\n", __func__);
- return -ENODEV;
+static int stm32_reset_update(struct reset_controller_dev *rcdev,
+ unsigned long id, bool assert)
+{
+ struct stm32_reset_data *data = to_stm32_reset_data(rcdev);
+ int reg_width = sizeof(u32);
+ int bank = id / (reg_width * BITS_PER_BYTE);
+ int offset = id % (reg_width * BITS_PER_BYTE);
+
+ if (data->clear_offset) {
+ void __iomem *addr;
+
+ addr = data->membase + (bank * reg_width);
+ if (!assert)
+ addr += data->clear_offset;
+
+ writel(BIT(offset), addr);
+
+ } else {
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&data->lock, flags);
+
+ reg = readl(data->membase + (bank * reg_width));
+
+ if (assert)
+ reg |= BIT(offset);
+ else
+ reg &= ~BIT(offset);
+
+ writel(reg, data->membase + (bank * reg_width));
+
+ spin_unlock_irqrestore(&data->lock, flags);
}
+ return 0;
+}
+
+static int stm32_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return stm32_reset_update(rcdev, id, true);
+}
+
+static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return stm32_reset_update(rcdev, id, false);
+}
+
+static int stm32_reset_status(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct stm32_reset_data *data = to_stm32_reset_data(rcdev);
+ int reg_width = sizeof(u32);
+ int bank = id / (reg_width * BITS_PER_BYTE);
+ int offset = id % (reg_width * BITS_PER_BYTE);
+ u32 reg;
+
+ reg = readl(data->membase + (bank * reg_width));
+
+ return !!(reg & BIT(offset));
+}
+
+static const struct reset_control_ops stm32_reset_ops = {
+ .assert = stm32_reset_assert,
+ .deassert = stm32_reset_deassert,
+ .status = stm32_reset_status,
+};
+
+static int stm32_rcc_reset_init(struct device *dev, void __iomem *base,
+ const struct of_device_id *match)
+{
+ const struct stm32_rcc_match_data *data = match->data;
+ struct stm32_reset_data *reset_data = NULL;
+
data = match->data;
+ reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
+ if (!reset_data)
+ return -ENOMEM;
+
+ spin_lock_init(&reset_data->lock);
+ reset_data->membase = base;
+ reset_data->rcdev.owner = THIS_MODULE;
+ reset_data->rcdev.ops = &stm32_reset_ops;
+ reset_data->rcdev.of_node = dev_of_node(dev);
+ reset_data->rcdev.nr_resets = STM32_RESET_ID_MASK;
+ reset_data->clear_offset = data->clear_offset;
+
+ return reset_controller_register(&reset_data->rcdev);
+}
+
+static int stm32_rcc_clock_init(struct device *dev, void __iomem *base,
+ const struct of_device_id *match)
+{
+ const struct stm32_rcc_match_data *data = match->data;
+ struct clk_hw_onecell_data *clk_data;
+ struct clk_hw **hws;
+ int err, n, max_binding;
+
max_binding = data->maxbinding;
- clk_data = kzalloc(struct_size(clk_data, hws, max_binding),
- GFP_KERNEL);
+ clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, max_binding),
+ GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
@@ -2073,36 +2297,139 @@ static int stm32_rcc_init(struct device_node *np,
hws[n] = ERR_PTR(-ENOENT);
for (n = 0; n < data->num; n++) {
- err = stm32_register_hw_clk(NULL, clk_data, base, &rlock,
+ if (data->check_security && data->check_security(&data->cfg[n]))
+ continue;
+
+ err = stm32_register_hw_clk(dev, clk_data, base, &rlock,
&data->cfg[n]);
if (err) {
- pr_err("%s: can't register %s\n", __func__,
- data->cfg[n].name);
-
- kfree(clk_data);
+ dev_err(dev, "Can't register clk %s: %d\n",
+ data->cfg[n].name, err);
return err;
}
}
- return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
+ return of_clk_add_hw_provider(dev_of_node(dev), of_clk_hw_onecell_get, clk_data);
}
-static void stm32mp1_rcc_init(struct device_node *np)
+static int stm32_rcc_init(struct device *dev, void __iomem *base,
+ const struct of_device_id *match_data)
+{
+ const struct of_device_id *match;
+ int err;
+
+ match = of_match_node(match_data, dev_of_node(dev));
+ if (!match) {
+ dev_err(dev, "match data not found\n");
+ return -ENODEV;
+ }
+
+ /* RCC Reset Configuration */
+ err = stm32_rcc_reset_init(dev, base, match);
+ if (err) {
+ pr_err("stm32mp1 reset failed to initialize\n");
+ return err;
+ }
+
+ /* RCC Clock Configuration */
+ err = stm32_rcc_clock_init(dev, base, match);
+ if (err) {
+ pr_err("stm32mp1 clock failed to initialize\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int stm32mp1_rcc_init(struct device *dev)
{
void __iomem *base;
+ int ret;
- base = of_iomap(np, 0);
+ base = of_iomap(dev_of_node(dev), 0);
if (!base) {
- pr_err("%pOFn: unable to map resource", np);
- of_node_put(np);
- return;
+ pr_err("%pOFn: unable to map resource", dev_of_node(dev));
+ ret = -ENOMEM;
+ goto out;
}
- if (stm32_rcc_init(np, base, stm32mp1_match_data)) {
- iounmap(base);
- of_node_put(np);
+ ret = stm32_rcc_init(dev, base, stm32mp1_match_data);
+
+out:
+ if (ret) {
+ if (base)
+ iounmap(base);
+
+ of_node_put(dev_of_node(dev));
}
+
+ return ret;
}
-CLK_OF_DECLARE_DRIVER(stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_rcc_init);
+static int get_clock_deps(struct device *dev)
+{
+ static const char * const clock_deps_name[] = {
+ "hsi", "hse", "csi", "lsi", "lse",
+ };
+ size_t deps_size = sizeof(struct clk *) * ARRAY_SIZE(clock_deps_name);
+ struct clk **clk_deps;
+ int i;
+
+ clk_deps = devm_kzalloc(dev, deps_size, GFP_KERNEL);
+ if (!clk_deps)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(clock_deps_name); i++) {
+ struct clk *clk = of_clk_get_by_name(dev_of_node(dev),
+ clock_deps_name[i]);
+
+ if (IS_ERR(clk)) {
+ if (PTR_ERR(clk) != -EINVAL && PTR_ERR(clk) != -ENOENT)
+ return PTR_ERR(clk);
+ } else {
+ /* Device gets a reference count on the clock */
+ clk_deps[i] = devm_clk_get(dev, __clk_get_name(clk));
+ clk_put(clk);
+ }
+ }
+
+ return 0;
+}
+
+static int stm32mp1_rcc_clocks_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int ret = get_clock_deps(dev);
+
+ if (!ret)
+ ret = stm32mp1_rcc_init(dev);
+
+ return ret;
+}
+
+static int stm32mp1_rcc_clocks_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *child, *np = dev_of_node(dev);
+
+ for_each_available_child_of_node(np, child)
+ of_clk_del_provider(child);
+
+ return 0;
+}
+
+static struct platform_driver stm32mp1_rcc_clocks_driver = {
+ .driver = {
+ .name = "stm32mp1_rcc",
+ .of_match_table = stm32mp1_match_data,
+ },
+ .probe = stm32mp1_rcc_clocks_probe,
+ .remove = stm32mp1_rcc_clocks_remove,
+};
+
+static int __init stm32mp1_clocks_init(void)
+{
+ return platform_driver_register(&stm32mp1_rcc_clocks_driver);
+}
+core_initcall(stm32mp1_clocks_init);
diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c
index 344cd6c61188..3c737742c2a9 100644
--- a/drivers/clk/clk-versaclock5.c
+++ b/drivers/clk/clk-versaclock5.c
@@ -69,7 +69,10 @@
#define VC5_FEEDBACK_FRAC_DIV(n) (0x19 + (n))
#define VC5_RC_CONTROL0 0x1e
#define VC5_RC_CONTROL1 0x1f
-/* Register 0x20 is factory reserved */
+
+/* These registers are named "Unused Factory Reserved Registers" */
+#define VC5_RESERVED_X0(idx) (0x20 + ((idx) * 0x10))
+#define VC5_RESERVED_X0_BYPASS_SYNC BIT(7) /* bypass_sync<idx> bit */
/* Output divider control for divider 1,2,3,4 */
#define VC5_OUT_DIV_CONTROL(idx) (0x21 + ((idx) * 0x10))
@@ -87,7 +90,6 @@
#define VC5_OUT_DIV_SKEW_INT(idx, n) (0x2b + ((idx) * 0x10) + (n))
#define VC5_OUT_DIV_INT(idx, n) (0x2d + ((idx) * 0x10) + (n))
#define VC5_OUT_DIV_SKEW_FRAC(idx) (0x2f + ((idx) * 0x10))
-/* Registers 0x30, 0x40, 0x50 are factory reserved */
/* Clock control register for clock 1,2 */
#define VC5_CLK_OUTPUT_CFG(idx, n) (0x60 + ((idx) * 0x2) + (n))
@@ -140,6 +142,8 @@
#define VC5_HAS_INTERNAL_XTAL BIT(0)
/* chip has PFD requency doubler */
#define VC5_HAS_PFD_FREQ_DBL BIT(1)
+/* chip has bits to disable FOD sync */
+#define VC5_HAS_BYPASS_SYNC_BIT BIT(2)
/* Supported IDT VC5 models. */
enum vc5_model {
@@ -582,6 +586,23 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
int ret;
/*
+ * When enabling a FOD, all currently enabled FODs are briefly
+ * stopped in order to synchronize all of them. This causes a clock
+ * disruption to any unrelated chips that might be already using
+ * other clock outputs. Bypass the sync feature to avoid the issue,
+ * which is possible on the VersaClock 6E family via reserved
+ * registers.
+ */
+ if (vc5->chip_info->flags & VC5_HAS_BYPASS_SYNC_BIT) {
+ ret = regmap_update_bits(vc5->regmap,
+ VC5_RESERVED_X0(hwdata->num),
+ VC5_RESERVED_X0_BYPASS_SYNC,
+ VC5_RESERVED_X0_BYPASS_SYNC);
+ if (ret)
+ return ret;
+ }
+
+ /*
* If the input mux is disabled, enable it first and
* select source from matching FOD.
*/
@@ -1166,7 +1187,7 @@ static const struct vc5_chip_info idt_5p49v6965_info = {
.model = IDT_VC6_5P49V6965,
.clk_fod_cnt = 4,
.clk_out_cnt = 5,
- .flags = 0,
+ .flags = VC5_HAS_BYPASS_SYNC_BIT,
};
static const struct i2c_device_id vc5_id[] = {
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 0f2e3fcf0f19..67f601a41023 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -190,34 +190,6 @@ vclkdev_create(struct clk_hw *hw, const char *con_id, const char *dev_fmt,
return cl;
}
-struct clk_lookup * __ref
-clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...)
-{
- struct clk_lookup *cl;
- va_list ap;
-
- va_start(ap, dev_fmt);
- cl = vclkdev_alloc(__clk_get_hw(clk), con_id, dev_fmt, ap);
- va_end(ap);
-
- return cl;
-}
-EXPORT_SYMBOL(clkdev_alloc);
-
-struct clk_lookup *
-clkdev_hw_alloc(struct clk_hw *hw, const char *con_id, const char *dev_fmt, ...)
-{
- struct clk_lookup *cl;
- va_list ap;
-
- va_start(ap, dev_fmt);
- cl = vclkdev_alloc(hw, con_id, dev_fmt, ap);
- va_end(ap);
-
- return cl;
-}
-EXPORT_SYMBOL(clkdev_hw_alloc);
-
/**
* clkdev_create - allocate and add a clkdev lookup structure
* @clk: struct clk to associate with all clk_lookups
diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig
index 6a9e93a0bb95..5ecc37aaa118 100644
--- a/drivers/clk/hisilicon/Kconfig
+++ b/drivers/clk/hisilicon/Kconfig
@@ -15,6 +15,13 @@ config COMMON_CLK_HI3519
help
Build the clock driver for hi3519.
+config COMMON_CLK_HI3559A
+ bool "Hi3559A Clock Driver"
+ depends on ARCH_HISI || COMPILE_TEST
+ default ARCH_HISI
+ help
+ Build the clock driver for hi3559a.
+
config COMMON_CLK_HI3660
bool "Hi3660 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
index b2441b99f3d5..2978e56cb876 100644
--- a/drivers/clk/hisilicon/Makefile
+++ b/drivers/clk/hisilicon/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
obj-$(CONFIG_COMMON_CLK_HI3516CV300) += crg-hi3516cv300.o
obj-$(CONFIG_COMMON_CLK_HI3519) += clk-hi3519.o
+obj-$(CONFIG_COMMON_CLK_HI3559A) += clk-hi3559a.o
obj-$(CONFIG_COMMON_CLK_HI3660) += clk-hi3660.o
obj-$(CONFIG_COMMON_CLK_HI3670) += clk-hi3670.o
obj-$(CONFIG_COMMON_CLK_HI3798CV200) += crg-hi3798cv200.o
diff --git a/drivers/clk/hisilicon/clk-hi3559a.c b/drivers/clk/hisilicon/clk-hi3559a.c
new file mode 100644
index 000000000000..56012a3d0219
--- /dev/null
+++ b/drivers/clk/hisilicon/clk-hi3559a.c
@@ -0,0 +1,845 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Hisilicon Hi3559A clock driver
+ *
+ * Copyright (c) 2019-2020, Huawei Tech. Co., Ltd.
+ *
+ * Author: Dongjiu Geng <gengdongjiu@huawei.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/hi3559av100-clock.h>
+
+#include "clk.h"
+#include "crg.h"
+#include "reset.h"
+
+#define CRG_BASE_ADDR 0x18020000
+#define PLL_MASK_WIDTH 24
+
+struct hi3559av100_pll_clock {
+ u32 id;
+ const char *name;
+ const char *parent_name;
+ const u32 ctrl_reg1;
+ const u8 frac_shift;
+ const u8 frac_width;
+ const u8 postdiv1_shift;
+ const u8 postdiv1_width;
+ const u8 postdiv2_shift;
+ const u8 postdiv2_width;
+ const u32 ctrl_reg2;
+ const u8 fbdiv_shift;
+ const u8 fbdiv_width;
+ const u8 refdiv_shift;
+ const u8 refdiv_width;
+};
+
+struct hi3559av100_clk_pll {
+ struct clk_hw hw;
+ u32 id;
+ void __iomem *ctrl_reg1;
+ u8 frac_shift;
+ u8 frac_width;
+ u8 postdiv1_shift;
+ u8 postdiv1_width;
+ u8 postdiv2_shift;
+ u8 postdiv2_width;
+ void __iomem *ctrl_reg2;
+ u8 fbdiv_shift;
+ u8 fbdiv_width;
+ u8 refdiv_shift;
+ u8 refdiv_width;
+};
+
+/* soc clk config */
+static const struct hisi_fixed_rate_clock hi3559av100_fixed_rate_clks_crg[] = {
+ { HI3559AV100_FIXED_1188M, "1188m", NULL, 0, 1188000000, },
+ { HI3559AV100_FIXED_1000M, "1000m", NULL, 0, 1000000000, },
+ { HI3559AV100_FIXED_842M, "842m", NULL, 0, 842000000, },
+ { HI3559AV100_FIXED_792M, "792m", NULL, 0, 792000000, },
+ { HI3559AV100_FIXED_750M, "750m", NULL, 0, 750000000, },
+ { HI3559AV100_FIXED_710M, "710m", NULL, 0, 710000000, },
+ { HI3559AV100_FIXED_680M, "680m", NULL, 0, 680000000, },
+ { HI3559AV100_FIXED_667M, "667m", NULL, 0, 667000000, },
+ { HI3559AV100_FIXED_631M, "631m", NULL, 0, 631000000, },
+ { HI3559AV100_FIXED_600M, "600m", NULL, 0, 600000000, },
+ { HI3559AV100_FIXED_568M, "568m", NULL, 0, 568000000, },
+ { HI3559AV100_FIXED_500M, "500m", NULL, 0, 500000000, },
+ { HI3559AV100_FIXED_475M, "475m", NULL, 0, 475000000, },
+ { HI3559AV100_FIXED_428M, "428m", NULL, 0, 428000000, },
+ { HI3559AV100_FIXED_400M, "400m", NULL, 0, 400000000, },
+ { HI3559AV100_FIXED_396M, "396m", NULL, 0, 396000000, },
+ { HI3559AV100_FIXED_300M, "300m", NULL, 0, 300000000, },
+ { HI3559AV100_FIXED_250M, "250m", NULL, 0, 250000000, },
+ { HI3559AV100_FIXED_200M, "200m", NULL, 0, 200000000, },
+ { HI3559AV100_FIXED_198M, "198m", NULL, 0, 198000000, },
+ { HI3559AV100_FIXED_187p5M, "187p5m", NULL, 0, 187500000, },
+ { HI3559AV100_FIXED_150M, "150m", NULL, 0, 150000000, },
+ { HI3559AV100_FIXED_148p5M, "148p5m", NULL, 0, 1485000000, },
+ { HI3559AV100_FIXED_125M, "125m", NULL, 0, 125000000, },
+ { HI3559AV100_FIXED_107M, "107m", NULL, 0, 107000000, },
+ { HI3559AV100_FIXED_100M, "100m", NULL, 0, 100000000, },
+ { HI3559AV100_FIXED_99M, "99m", NULL, 0, 99000000, },
+ { HI3559AV100_FIXED_75M, "75m", NULL, 0, 75000000, },
+ { HI3559AV100_FIXED_74p25M, "74p25m", NULL, 0, 74250000, },
+ { HI3559AV100_FIXED_72M, "72m", NULL, 0, 72000000, },
+ { HI3559AV100_FIXED_60M, "60m", NULL, 0, 60000000, },
+ { HI3559AV100_FIXED_54M, "54m", NULL, 0, 54000000, },
+ { HI3559AV100_FIXED_50M, "50m", NULL, 0, 50000000, },
+ { HI3559AV100_FIXED_49p5M, "49p5m", NULL, 0, 49500000, },
+ { HI3559AV100_FIXED_37p125M, "37p125m", NULL, 0, 37125000, },
+ { HI3559AV100_FIXED_36M, "36m", NULL, 0, 36000000, },
+ { HI3559AV100_FIXED_32p4M, "32p4m", NULL, 0, 32400000, },
+ { HI3559AV100_FIXED_27M, "27m", NULL, 0, 27000000, },
+ { HI3559AV100_FIXED_25M, "25m", NULL, 0, 25000000, },
+ { HI3559AV100_FIXED_24M, "24m", NULL, 0, 24000000, },
+ { HI3559AV100_FIXED_12M, "12m", NULL, 0, 12000000, },
+ { HI3559AV100_FIXED_3M, "3m", NULL, 0, 3000000, },
+ { HI3559AV100_FIXED_1p6M, "1p6m", NULL, 0, 1600000, },
+ { HI3559AV100_FIXED_400K, "400k", NULL, 0, 400000, },
+ { HI3559AV100_FIXED_100K, "100k", NULL, 0, 100000, },
+};
+
+
+static const char *fmc_mux_p[] = {
+ "24m", "75m", "125m", "150m", "200m", "250m", "300m", "400m"
+};
+
+static const char *mmc_mux_p[] = {
+ "100k", "25m", "49p5m", "99m", "187p5m", "150m", "198m", "400k"
+};
+
+static const char *sysapb_mux_p[] = {
+ "24m", "50m",
+};
+
+static const char *sysbus_mux_p[] = {
+ "24m", "300m"
+};
+
+static const char *uart_mux_p[] = { "50m", "24m", "3m" };
+
+static const char *a73_clksel_mux_p[] = {
+ "24m", "apll", "1000m"
+};
+
+static const u32 fmc_mux_table[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+static const u32 mmc_mux_table[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+static const u32 sysapb_mux_table[] = { 0, 1 };
+static const u32 sysbus_mux_table[] = { 0, 1 };
+static const u32 uart_mux_table[] = { 0, 1, 2 };
+static const u32 a73_clksel_mux_table[] = { 0, 1, 2 };
+
+static struct hisi_mux_clock hi3559av100_mux_clks_crg[] = {
+ {
+ HI3559AV100_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p),
+ CLK_SET_RATE_PARENT, 0x170, 2, 3, 0, fmc_mux_table,
+ },
+ {
+ HI3559AV100_MMC0_MUX, "mmc0_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
+ CLK_SET_RATE_PARENT, 0x1a8, 24, 3, 0, mmc_mux_table,
+ },
+ {
+ HI3559AV100_MMC1_MUX, "mmc1_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
+ CLK_SET_RATE_PARENT, 0x1ec, 24, 3, 0, mmc_mux_table,
+ },
+
+ {
+ HI3559AV100_MMC2_MUX, "mmc2_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
+ CLK_SET_RATE_PARENT, 0x214, 24, 3, 0, mmc_mux_table,
+ },
+
+ {
+ HI3559AV100_MMC3_MUX, "mmc3_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
+ CLK_SET_RATE_PARENT, 0x23c, 24, 3, 0, mmc_mux_table,
+ },
+
+ {
+ HI3559AV100_SYSAPB_MUX, "sysapb_mux", sysapb_mux_p, ARRAY_SIZE(sysapb_mux_p),
+ CLK_SET_RATE_PARENT, 0xe8, 3, 1, 0, sysapb_mux_table
+ },
+
+ {
+ HI3559AV100_SYSBUS_MUX, "sysbus_mux", sysbus_mux_p, ARRAY_SIZE(sysbus_mux_p),
+ CLK_SET_RATE_PARENT, 0xe8, 0, 1, 0, sysbus_mux_table
+ },
+
+ {
+ HI3559AV100_UART_MUX, "uart_mux", uart_mux_p, ARRAY_SIZE(uart_mux_p),
+ CLK_SET_RATE_PARENT, 0x198, 28, 2, 0, uart_mux_table
+ },
+
+ {
+ HI3559AV100_A73_MUX, "a73_mux", a73_clksel_mux_p, ARRAY_SIZE(a73_clksel_mux_p),
+ CLK_SET_RATE_PARENT, 0xe4, 0, 2, 0, a73_clksel_mux_table
+ },
+};
+
+static struct hisi_gate_clock hi3559av100_gate_clks[] = {
+ {
+ HI3559AV100_FMC_CLK, "clk_fmc", "fmc_mux",
+ CLK_SET_RATE_PARENT, 0x170, 1, 0,
+ },
+ {
+ HI3559AV100_MMC0_CLK, "clk_mmc0", "mmc0_mux",
+ CLK_SET_RATE_PARENT, 0x1a8, 28, 0,
+ },
+ {
+ HI3559AV100_MMC1_CLK, "clk_mmc1", "mmc1_mux",
+ CLK_SET_RATE_PARENT, 0x1ec, 28, 0,
+ },
+ {
+ HI3559AV100_MMC2_CLK, "clk_mmc2", "mmc2_mux",
+ CLK_SET_RATE_PARENT, 0x214, 28, 0,
+ },
+ {
+ HI3559AV100_MMC3_CLK, "clk_mmc3", "mmc3_mux",
+ CLK_SET_RATE_PARENT, 0x23c, 28, 0,
+ },
+ {
+ HI3559AV100_UART0_CLK, "clk_uart0", "uart_mux",
+ CLK_SET_RATE_PARENT, 0x198, 23, 0,
+ },
+ {
+ HI3559AV100_UART1_CLK, "clk_uart1", "uart_mux",
+ CLK_SET_RATE_PARENT, 0x198, 24, 0,
+ },
+ {
+ HI3559AV100_UART2_CLK, "clk_uart2", "uart_mux",
+ CLK_SET_RATE_PARENT, 0x198, 25, 0,
+ },
+ {
+ HI3559AV100_UART3_CLK, "clk_uart3", "uart_mux",
+ CLK_SET_RATE_PARENT, 0x198, 26, 0,
+ },
+ {
+ HI3559AV100_UART4_CLK, "clk_uart4", "uart_mux",
+ CLK_SET_RATE_PARENT, 0x198, 27, 0,
+ },
+ {
+ HI3559AV100_ETH_CLK, "clk_eth", NULL,
+ CLK_SET_RATE_PARENT, 0x0174, 1, 0,
+ },
+ {
+ HI3559AV100_ETH_MACIF_CLK, "clk_eth_macif", NULL,
+ CLK_SET_RATE_PARENT, 0x0174, 5, 0,
+ },
+ {
+ HI3559AV100_ETH1_CLK, "clk_eth1", NULL,
+ CLK_SET_RATE_PARENT, 0x0174, 3, 0,
+ },
+ {
+ HI3559AV100_ETH1_MACIF_CLK, "clk_eth1_macif", NULL,
+ CLK_SET_RATE_PARENT, 0x0174, 7, 0,
+ },
+ {
+ HI3559AV100_I2C0_CLK, "clk_i2c0", "50m",
+ CLK_SET_RATE_PARENT, 0x01a0, 16, 0,
+ },
+ {
+ HI3559AV100_I2C1_CLK, "clk_i2c1", "50m",
+ CLK_SET_RATE_PARENT, 0x01a0, 17, 0,
+ },
+ {
+ HI3559AV100_I2C2_CLK, "clk_i2c2", "50m",
+ CLK_SET_RATE_PARENT, 0x01a0, 18, 0,
+ },
+ {
+ HI3559AV100_I2C3_CLK, "clk_i2c3", "50m",
+ CLK_SET_RATE_PARENT, 0x01a0, 19, 0,
+ },
+ {
+ HI3559AV100_I2C4_CLK, "clk_i2c4", "50m",
+ CLK_SET_RATE_PARENT, 0x01a0, 20, 0,
+ },
+ {
+ HI3559AV100_I2C5_CLK, "clk_i2c5", "50m",
+ CLK_SET_RATE_PARENT, 0x01a0, 21, 0,
+ },
+ {
+ HI3559AV100_I2C6_CLK, "clk_i2c6", "50m",
+ CLK_SET_RATE_PARENT, 0x01a0, 22, 0,
+ },
+ {
+ HI3559AV100_I2C7_CLK, "clk_i2c7", "50m",
+ CLK_SET_RATE_PARENT, 0x01a0, 23, 0,
+ },
+ {
+ HI3559AV100_I2C8_CLK, "clk_i2c8", "50m",
+ CLK_SET_RATE_PARENT, 0x01a0, 24, 0,
+ },
+ {
+ HI3559AV100_I2C9_CLK, "clk_i2c9", "50m",
+ CLK_SET_RATE_PARENT, 0x01a0, 25, 0,
+ },
+ {
+ HI3559AV100_I2C10_CLK, "clk_i2c10", "50m",
+ CLK_SET_RATE_PARENT, 0x01a0, 26, 0,
+ },
+ {
+ HI3559AV100_I2C11_CLK, "clk_i2c11", "50m",
+ CLK_SET_RATE_PARENT, 0x01a0, 27, 0,
+ },
+ {
+ HI3559AV100_SPI0_CLK, "clk_spi0", "100m",
+ CLK_SET_RATE_PARENT, 0x0198, 16, 0,
+ },
+ {
+ HI3559AV100_SPI1_CLK, "clk_spi1", "100m",
+ CLK_SET_RATE_PARENT, 0x0198, 17, 0,
+ },
+ {
+ HI3559AV100_SPI2_CLK, "clk_spi2", "100m",
+ CLK_SET_RATE_PARENT, 0x0198, 18, 0,
+ },
+ {
+ HI3559AV100_SPI3_CLK, "clk_spi3", "100m",
+ CLK_SET_RATE_PARENT, 0x0198, 19, 0,
+ },
+ {
+ HI3559AV100_SPI4_CLK, "clk_spi4", "100m",
+ CLK_SET_RATE_PARENT, 0x0198, 20, 0,
+ },
+ {
+ HI3559AV100_SPI5_CLK, "clk_spi5", "100m",
+ CLK_SET_RATE_PARENT, 0x0198, 21, 0,
+ },
+ {
+ HI3559AV100_SPI6_CLK, "clk_spi6", "100m",
+ CLK_SET_RATE_PARENT, 0x0198, 22, 0,
+ },
+ {
+ HI3559AV100_EDMAC_AXICLK, "axi_clk_edmac", NULL,
+ CLK_SET_RATE_PARENT, 0x16c, 6, 0,
+ },
+ {
+ HI3559AV100_EDMAC_CLK, "clk_edmac", NULL,
+ CLK_SET_RATE_PARENT, 0x16c, 5, 0,
+ },
+ {
+ HI3559AV100_EDMAC1_AXICLK, "axi_clk_edmac1", NULL,
+ CLK_SET_RATE_PARENT, 0x16c, 9, 0,
+ },
+ {
+ HI3559AV100_EDMAC1_CLK, "clk_edmac1", NULL,
+ CLK_SET_RATE_PARENT, 0x16c, 8, 0,
+ },
+ {
+ HI3559AV100_VDMAC_CLK, "clk_vdmac", NULL,
+ CLK_SET_RATE_PARENT, 0x14c, 5, 0,
+ },
+};
+
+static struct hi3559av100_pll_clock hi3559av100_pll_clks[] = {
+ {
+ HI3559AV100_APLL_CLK, "apll", NULL, 0x0, 0, 24, 24, 3, 28, 3,
+ 0x4, 0, 12, 12, 6
+ },
+ {
+ HI3559AV100_GPLL_CLK, "gpll", NULL, 0x20, 0, 24, 24, 3, 28, 3,
+ 0x24, 0, 12, 12, 6
+ },
+};
+
+#define to_pll_clk(_hw) container_of(_hw, struct hi3559av100_clk_pll, hw)
+static void hi3559av100_calc_pll(u32 *frac_val, u32 *postdiv1_val,
+ u32 *postdiv2_val,
+ u32 *fbdiv_val, u32 *refdiv_val, u64 rate)
+{
+ u64 rem;
+
+ *postdiv1_val = 2;
+ *postdiv2_val = 1;
+
+ rate = rate * ((*postdiv1_val) * (*postdiv2_val));
+
+ *frac_val = 0;
+ rem = do_div(rate, 1000000);
+ rem = do_div(rate, PLL_MASK_WIDTH);
+ *fbdiv_val = rate;
+ *refdiv_val = 1;
+ rem = rem * (1 << PLL_MASK_WIDTH);
+ do_div(rem, PLL_MASK_WIDTH);
+ *frac_val = rem;
+}
+
+static int clk_pll_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct hi3559av100_clk_pll *clk = to_pll_clk(hw);
+ u32 frac_val, postdiv1_val, postdiv2_val, fbdiv_val, refdiv_val;
+ u32 val;
+
+ postdiv1_val = postdiv2_val = 0;
+
+ hi3559av100_calc_pll(&frac_val, &postdiv1_val, &postdiv2_val,
+ &fbdiv_val, &refdiv_val, (u64)rate);
+
+ val = readl_relaxed(clk->ctrl_reg1);
+ val &= ~(((1 << clk->frac_width) - 1) << clk->frac_shift);
+ val &= ~(((1 << clk->postdiv1_width) - 1) << clk->postdiv1_shift);
+ val &= ~(((1 << clk->postdiv2_width) - 1) << clk->postdiv2_shift);
+
+ val |= frac_val << clk->frac_shift;
+ val |= postdiv1_val << clk->postdiv1_shift;
+ val |= postdiv2_val << clk->postdiv2_shift;
+ writel_relaxed(val, clk->ctrl_reg1);
+
+ val = readl_relaxed(clk->ctrl_reg2);
+ val &= ~(((1 << clk->fbdiv_width) - 1) << clk->fbdiv_shift);
+ val &= ~(((1 << clk->refdiv_width) - 1) << clk->refdiv_shift);
+
+ val |= fbdiv_val << clk->fbdiv_shift;
+ val |= refdiv_val << clk->refdiv_shift;
+ writel_relaxed(val, clk->ctrl_reg2);
+
+ return 0;
+}
+
+static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct hi3559av100_clk_pll *clk = to_pll_clk(hw);
+ u64 frac_val, fbdiv_val, refdiv_val;
+ u32 postdiv1_val, postdiv2_val;
+ u32 val;
+ u64 tmp, rate;
+
+ val = readl_relaxed(clk->ctrl_reg1);
+ val = val >> clk->frac_shift;
+ val &= ((1 << clk->frac_width) - 1);
+ frac_val = val;
+
+ val = readl_relaxed(clk->ctrl_reg1);
+ val = val >> clk->postdiv1_shift;
+ val &= ((1 << clk->postdiv1_width) - 1);
+ postdiv1_val = val;
+
+ val = readl_relaxed(clk->ctrl_reg1);
+ val = val >> clk->postdiv2_shift;
+ val &= ((1 << clk->postdiv2_width) - 1);
+ postdiv2_val = val;
+
+ val = readl_relaxed(clk->ctrl_reg2);
+ val = val >> clk->fbdiv_shift;
+ val &= ((1 << clk->fbdiv_width) - 1);
+ fbdiv_val = val;
+
+ val = readl_relaxed(clk->ctrl_reg2);
+ val = val >> clk->refdiv_shift;
+ val &= ((1 << clk->refdiv_width) - 1);
+ refdiv_val = val;
+
+ /* rate = 24000000 * (fbdiv + frac / (1<<24) ) / refdiv */
+ rate = 0;
+ tmp = 24000000 * fbdiv_val + (24000000 * frac_val) / (1 << 24);
+ rate += tmp;
+ do_div(rate, refdiv_val);
+ do_div(rate, postdiv1_val * postdiv2_val);
+
+ return rate;
+}
+
+static const struct clk_ops hisi_clk_pll_ops = {
+ .set_rate = clk_pll_set_rate,
+ .recalc_rate = clk_pll_recalc_rate,
+};
+
+static void hisi_clk_register_pll(struct hi3559av100_pll_clock *clks,
+ int nums, struct hisi_clock_data *data, struct device *dev)
+{
+ void __iomem *base = data->base;
+ struct hi3559av100_clk_pll *p_clk = NULL;
+ struct clk *clk = NULL;
+ struct clk_init_data init;
+ int i;
+
+ p_clk = devm_kzalloc(dev, sizeof(*p_clk) * nums, GFP_KERNEL);
+
+ if (!p_clk)
+ return;
+
+ for (i = 0; i < nums; i++) {
+ init.name = clks[i].name;
+ init.flags = 0;
+ init.parent_names =
+ (clks[i].parent_name ? &clks[i].parent_name : NULL);
+ init.num_parents = (clks[i].parent_name ? 1 : 0);
+ init.ops = &hisi_clk_pll_ops;
+
+ p_clk->ctrl_reg1 = base + clks[i].ctrl_reg1;
+ p_clk->frac_shift = clks[i].frac_shift;
+ p_clk->frac_width = clks[i].frac_width;
+ p_clk->postdiv1_shift = clks[i].postdiv1_shift;
+ p_clk->postdiv1_width = clks[i].postdiv1_width;
+ p_clk->postdiv2_shift = clks[i].postdiv2_shift;
+ p_clk->postdiv2_width = clks[i].postdiv2_width;
+
+ p_clk->ctrl_reg2 = base + clks[i].ctrl_reg2;
+ p_clk->fbdiv_shift = clks[i].fbdiv_shift;
+ p_clk->fbdiv_width = clks[i].fbdiv_width;
+ p_clk->refdiv_shift = clks[i].refdiv_shift;
+ p_clk->refdiv_width = clks[i].refdiv_width;
+ p_clk->hw.init = &init;
+
+ clk = clk_register(NULL, &p_clk->hw);
+ if (IS_ERR(clk)) {
+ devm_kfree(dev, p_clk);
+ dev_err(dev, "%s: failed to register clock %s\n",
+ __func__, clks[i].name);
+ continue;
+ }
+
+ data->clk_data.clks[clks[i].id] = clk;
+ p_clk++;
+ }
+}
+
+static struct hisi_clock_data *hi3559av100_clk_register(
+ struct platform_device *pdev)
+{
+ struct hisi_clock_data *clk_data;
+ int ret;
+
+ clk_data = hisi_clk_alloc(pdev, HI3559AV100_CRG_NR_CLKS);
+ if (!clk_data)
+ return ERR_PTR(-ENOMEM);
+
+ ret = hisi_clk_register_fixed_rate(hi3559av100_fixed_rate_clks_crg,
+ ARRAY_SIZE(hi3559av100_fixed_rate_clks_crg), clk_data);
+ if (ret)
+ return ERR_PTR(ret);
+
+ hisi_clk_register_pll(hi3559av100_pll_clks,
+ ARRAY_SIZE(hi3559av100_pll_clks), clk_data, &pdev->dev);
+
+ ret = hisi_clk_register_mux(hi3559av100_mux_clks_crg,
+ ARRAY_SIZE(hi3559av100_mux_clks_crg), clk_data);
+ if (ret)
+ goto unregister_fixed_rate;
+
+ ret = hisi_clk_register_gate(hi3559av100_gate_clks,
+ ARRAY_SIZE(hi3559av100_gate_clks), clk_data);
+ if (ret)
+ goto unregister_mux;
+
+ ret = of_clk_add_provider(pdev->dev.of_node,
+ of_clk_src_onecell_get, &clk_data->clk_data);
+ if (ret)
+ goto unregister_gate;
+
+ return clk_data;
+
+unregister_gate:
+ hisi_clk_unregister_gate(hi3559av100_gate_clks,
+ ARRAY_SIZE(hi3559av100_gate_clks), clk_data);
+unregister_mux:
+ hisi_clk_unregister_mux(hi3559av100_mux_clks_crg,
+ ARRAY_SIZE(hi3559av100_mux_clks_crg), clk_data);
+unregister_fixed_rate:
+ hisi_clk_unregister_fixed_rate(hi3559av100_fixed_rate_clks_crg,
+ ARRAY_SIZE(hi3559av100_fixed_rate_clks_crg), clk_data);
+ return ERR_PTR(ret);
+}
+
+static void hi3559av100_clk_unregister(struct platform_device *pdev)
+{
+ struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
+
+ of_clk_del_provider(pdev->dev.of_node);
+
+ hisi_clk_unregister_gate(hi3559av100_gate_clks,
+ ARRAY_SIZE(hi3559av100_gate_clks), crg->clk_data);
+ hisi_clk_unregister_mux(hi3559av100_mux_clks_crg,
+ ARRAY_SIZE(hi3559av100_mux_clks_crg), crg->clk_data);
+ hisi_clk_unregister_fixed_rate(hi3559av100_fixed_rate_clks_crg,
+ ARRAY_SIZE(hi3559av100_fixed_rate_clks_crg), crg->clk_data);
+}
+
+static const struct hisi_crg_funcs hi3559av100_crg_funcs = {
+ .register_clks = hi3559av100_clk_register,
+ .unregister_clks = hi3559av100_clk_unregister,
+};
+
+static struct hisi_fixed_rate_clock hi3559av100_shub_fixed_rate_clks[] = {
+ { HI3559AV100_SHUB_SOURCE_SOC_24M, "clk_source_24M", NULL, 0, 24000000UL, },
+ { HI3559AV100_SHUB_SOURCE_SOC_200M, "clk_source_200M", NULL, 0, 200000000UL, },
+ { HI3559AV100_SHUB_SOURCE_SOC_300M, "clk_source_300M", NULL, 0, 300000000UL, },
+ { HI3559AV100_SHUB_SOURCE_PLL, "clk_source_PLL", NULL, 0, 192000000UL, },
+ { HI3559AV100_SHUB_I2C0_CLK, "clk_shub_i2c0", NULL, 0, 48000000UL, },
+ { HI3559AV100_SHUB_I2C1_CLK, "clk_shub_i2c1", NULL, 0, 48000000UL, },
+ { HI3559AV100_SHUB_I2C2_CLK, "clk_shub_i2c2", NULL, 0, 48000000UL, },
+ { HI3559AV100_SHUB_I2C3_CLK, "clk_shub_i2c3", NULL, 0, 48000000UL, },
+ { HI3559AV100_SHUB_I2C4_CLK, "clk_shub_i2c4", NULL, 0, 48000000UL, },
+ { HI3559AV100_SHUB_I2C5_CLK, "clk_shub_i2c5", NULL, 0, 48000000UL, },
+ { HI3559AV100_SHUB_I2C6_CLK, "clk_shub_i2c6", NULL, 0, 48000000UL, },
+ { HI3559AV100_SHUB_I2C7_CLK, "clk_shub_i2c7", NULL, 0, 48000000UL, },
+ { HI3559AV100_SHUB_UART_CLK_32K, "clk_uart_32K", NULL, 0, 32000UL, },
+};
+
+/* shub mux clk */
+static u32 shub_source_clk_mux_table[] = {0, 1, 2, 3};
+static const char *shub_source_clk_mux_p[] = {
+ "clk_source_24M", "clk_source_200M", "clk_source_300M", "clk_source_PLL"
+};
+
+static u32 shub_uart_source_clk_mux_table[] = {0, 1, 2, 3};
+static const char *shub_uart_source_clk_mux_p[] = {
+ "clk_uart_32K", "clk_uart_div_clk", "clk_uart_div_clk", "clk_source_24M"
+};
+
+static struct hisi_mux_clock hi3559av100_shub_mux_clks[] = {
+ {
+ HI3559AV100_SHUB_SOURCE_CLK, "shub_clk", shub_source_clk_mux_p,
+ ARRAY_SIZE(shub_source_clk_mux_p),
+ 0, 0x0, 0, 2, 0, shub_source_clk_mux_table,
+ },
+
+ {
+ HI3559AV100_SHUB_UART_SOURCE_CLK, "shub_uart_source_clk",
+ shub_uart_source_clk_mux_p, ARRAY_SIZE(shub_uart_source_clk_mux_p),
+ 0, 0x1c, 28, 2, 0, shub_uart_source_clk_mux_table,
+ },
+};
+
+
+/* shub div clk */
+static struct clk_div_table shub_spi_clk_table[] = {{0, 8}, {1, 4}, {2, 2}};
+static struct clk_div_table shub_uart_div_clk_table[] = {{1, 8}, {2, 4}};
+
+static struct hisi_divider_clock hi3559av100_shub_div_clks[] = {
+ { HI3559AV100_SHUB_SPI_SOURCE_CLK, "clk_spi_clk", "shub_clk", 0, 0x20, 24, 2,
+ CLK_DIVIDER_ALLOW_ZERO, shub_spi_clk_table,
+ },
+ { HI3559AV100_SHUB_UART_DIV_CLK, "clk_uart_div_clk", "shub_clk", 0, 0x1c, 28, 2,
+ CLK_DIVIDER_ALLOW_ZERO, shub_uart_div_clk_table,
+ },
+};
+
+/* shub gate clk */
+static struct hisi_gate_clock hi3559av100_shub_gate_clks[] = {
+ {
+ HI3559AV100_SHUB_SPI0_CLK, "clk_shub_spi0", "clk_spi_clk",
+ 0, 0x20, 1, 0,
+ },
+ {
+ HI3559AV100_SHUB_SPI1_CLK, "clk_shub_spi1", "clk_spi_clk",
+ 0, 0x20, 5, 0,
+ },
+ {
+ HI3559AV100_SHUB_SPI2_CLK, "clk_shub_spi2", "clk_spi_clk",
+ 0, 0x20, 9, 0,
+ },
+
+ {
+ HI3559AV100_SHUB_UART0_CLK, "clk_shub_uart0", "shub_uart_source_clk",
+ 0, 0x1c, 1, 0,
+ },
+ {
+ HI3559AV100_SHUB_UART1_CLK, "clk_shub_uart1", "shub_uart_source_clk",
+ 0, 0x1c, 5, 0,
+ },
+ {
+ HI3559AV100_SHUB_UART2_CLK, "clk_shub_uart2", "shub_uart_source_clk",
+ 0, 0x1c, 9, 0,
+ },
+ {
+ HI3559AV100_SHUB_UART3_CLK, "clk_shub_uart3", "shub_uart_source_clk",
+ 0, 0x1c, 13, 0,
+ },
+ {
+ HI3559AV100_SHUB_UART4_CLK, "clk_shub_uart4", "shub_uart_source_clk",
+ 0, 0x1c, 17, 0,
+ },
+ {
+ HI3559AV100_SHUB_UART5_CLK, "clk_shub_uart5", "shub_uart_source_clk",
+ 0, 0x1c, 21, 0,
+ },
+ {
+ HI3559AV100_SHUB_UART6_CLK, "clk_shub_uart6", "shub_uart_source_clk",
+ 0, 0x1c, 25, 0,
+ },
+
+ {
+ HI3559AV100_SHUB_EDMAC_CLK, "clk_shub_dmac", "shub_clk",
+ 0, 0x24, 4, 0,
+ },
+};
+
+static int hi3559av100_shub_default_clk_set(void)
+{
+ void __iomem *crg_base;
+ unsigned int val;
+
+ crg_base = ioremap(CRG_BASE_ADDR, SZ_4K);
+
+ /* SSP: 192M/2 */
+ val = readl_relaxed(crg_base + 0x20);
+ val |= (0x2 << 24);
+ writel_relaxed(val, crg_base + 0x20);
+
+ /* UART: 192M/8 */
+ val = readl_relaxed(crg_base + 0x1C);
+ val |= (0x1 << 28);
+ writel_relaxed(val, crg_base + 0x1C);
+
+ iounmap(crg_base);
+ crg_base = NULL;
+
+ return 0;
+}
+
+static struct hisi_clock_data *hi3559av100_shub_clk_register(
+ struct platform_device *pdev)
+{
+ struct hisi_clock_data *clk_data = NULL;
+ int ret;
+
+ hi3559av100_shub_default_clk_set();
+
+ clk_data = hisi_clk_alloc(pdev, HI3559AV100_SHUB_NR_CLKS);
+ if (!clk_data)
+ return ERR_PTR(-ENOMEM);
+
+ ret = hisi_clk_register_fixed_rate(hi3559av100_shub_fixed_rate_clks,
+ ARRAY_SIZE(hi3559av100_shub_fixed_rate_clks), clk_data);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = hisi_clk_register_mux(hi3559av100_shub_mux_clks,
+ ARRAY_SIZE(hi3559av100_shub_mux_clks), clk_data);
+ if (ret)
+ goto unregister_fixed_rate;
+
+ ret = hisi_clk_register_divider(hi3559av100_shub_div_clks,
+ ARRAY_SIZE(hi3559av100_shub_div_clks), clk_data);
+ if (ret)
+ goto unregister_mux;
+
+ ret = hisi_clk_register_gate(hi3559av100_shub_gate_clks,
+ ARRAY_SIZE(hi3559av100_shub_gate_clks), clk_data);
+ if (ret)
+ goto unregister_factor;
+
+ ret = of_clk_add_provider(pdev->dev.of_node,
+ of_clk_src_onecell_get, &clk_data->clk_data);
+ if (ret)
+ goto unregister_gate;
+
+ return clk_data;
+
+unregister_gate:
+ hisi_clk_unregister_gate(hi3559av100_shub_gate_clks,
+ ARRAY_SIZE(hi3559av100_shub_gate_clks), clk_data);
+unregister_factor:
+ hisi_clk_unregister_divider(hi3559av100_shub_div_clks,
+ ARRAY_SIZE(hi3559av100_shub_div_clks), clk_data);
+unregister_mux:
+ hisi_clk_unregister_mux(hi3559av100_shub_mux_clks,
+ ARRAY_SIZE(hi3559av100_shub_mux_clks), clk_data);
+unregister_fixed_rate:
+ hisi_clk_unregister_fixed_rate(hi3559av100_shub_fixed_rate_clks,
+ ARRAY_SIZE(hi3559av100_shub_fixed_rate_clks), clk_data);
+ return ERR_PTR(ret);
+}
+
+static void hi3559av100_shub_clk_unregister(struct platform_device *pdev)
+{
+ struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
+
+ of_clk_del_provider(pdev->dev.of_node);
+
+ hisi_clk_unregister_gate(hi3559av100_shub_gate_clks,
+ ARRAY_SIZE(hi3559av100_shub_gate_clks), crg->clk_data);
+ hisi_clk_unregister_divider(hi3559av100_shub_div_clks,
+ ARRAY_SIZE(hi3559av100_shub_div_clks), crg->clk_data);
+ hisi_clk_unregister_mux(hi3559av100_shub_mux_clks,
+ ARRAY_SIZE(hi3559av100_shub_mux_clks), crg->clk_data);
+ hisi_clk_unregister_fixed_rate(hi3559av100_shub_fixed_rate_clks,
+ ARRAY_SIZE(hi3559av100_shub_fixed_rate_clks), crg->clk_data);
+}
+
+static const struct hisi_crg_funcs hi3559av100_shub_crg_funcs = {
+ .register_clks = hi3559av100_shub_clk_register,
+ .unregister_clks = hi3559av100_shub_clk_unregister,
+};
+
+static const struct of_device_id hi3559av100_crg_match_table[] = {
+ {
+ .compatible = "hisilicon,hi3559av100-clock",
+ .data = &hi3559av100_crg_funcs
+ },
+ {
+ .compatible = "hisilicon,hi3559av100-shub-clock",
+ .data = &hi3559av100_shub_crg_funcs
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, hi3559av100_crg_match_table);
+
+static int hi3559av100_crg_probe(struct platform_device *pdev)
+{
+ struct hisi_crg_dev *crg;
+
+ crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL);
+ if (!crg)
+ return -ENOMEM;
+
+ crg->funcs = of_device_get_match_data(&pdev->dev);
+ if (!crg->funcs)
+ return -ENOENT;
+
+ crg->rstc = hisi_reset_init(pdev);
+ if (!crg->rstc)
+ return -ENOMEM;
+
+ crg->clk_data = crg->funcs->register_clks(pdev);
+ if (IS_ERR(crg->clk_data)) {
+ hisi_reset_exit(crg->rstc);
+ return PTR_ERR(crg->clk_data);
+ }
+
+ platform_set_drvdata(pdev, crg);
+ return 0;
+}
+
+static int hi3559av100_crg_remove(struct platform_device *pdev)
+{
+ struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
+
+ hisi_reset_exit(crg->rstc);
+ crg->funcs->unregister_clks(pdev);
+ return 0;
+}
+
+static struct platform_driver hi3559av100_crg_driver = {
+ .probe = hi3559av100_crg_probe,
+ .remove = hi3559av100_crg_remove,
+ .driver = {
+ .name = "hi3559av100-clock",
+ .of_match_table = hi3559av100_crg_match_table,
+ },
+};
+
+static int __init hi3559av100_crg_init(void)
+{
+ return platform_driver_register(&hi3559av100_crg_driver);
+}
+core_initcall(hi3559av100_crg_init);
+
+static void __exit hi3559av100_crg_exit(void)
+{
+ platform_driver_unregister(&hi3559av100_crg_driver);
+}
+module_exit(hi3559av100_crg_exit);
+
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("HiSilicon Hi3559AV100 CRG Driver");
diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c
index 54d9fdc93599..9361fba7cd4c 100644
--- a/drivers/clk/hisilicon/clk.c
+++ b/drivers/clk/hisilicon/clk.c
@@ -162,7 +162,7 @@ int hisi_clk_register_mux(const struct hisi_mux_clock *clks,
clks[i].num_parents, clks[i].flags,
base + clks[i].offset, clks[i].shift,
mask, clks[i].mux_flags,
- clks[i].table, &hisi_clk_lock);
+ (u32 *)clks[i].table, &hisi_clk_lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h
index 61cbd90d1213..7a9b42e1b027 100644
--- a/drivers/clk/hisilicon/clk.h
+++ b/drivers/clk/hisilicon/clk.h
@@ -50,7 +50,7 @@ struct hisi_mux_clock {
u8 shift;
u8 width;
u8 mux_flags;
- u32 *table;
+ const u32 *table;
const char *alias;
};
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index dd6a737d060b..c24a2acbfa56 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -27,7 +27,8 @@ obj-$(CONFIG_CLK_IMX8MP) += clk-imx8mp.o
obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o
obj-$(CONFIG_MXC_CLK_SCU) += clk-imx-scu.o clk-imx-lpcg-scu.o
-clk-imx-scu-$(CONFIG_CLK_IMX8QXP) += clk-scu.o clk-imx8qxp.o
+clk-imx-scu-$(CONFIG_CLK_IMX8QXP) += clk-scu.o clk-imx8qxp.o \
+ clk-imx8qxp-rsrc.o clk-imx8qm-rsrc.o
clk-imx-lpcg-scu-$(CONFIG_CLK_IMX8QXP) += clk-lpcg-scu.o clk-imx8qxp-lpcg.o
obj-$(CONFIG_CLK_IMX1) += clk-imx1.o
diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c
index e39c9c907c38..12837304545d 100644
--- a/drivers/clk/imx/clk-imx8mp.c
+++ b/drivers/clk/imx/clk-imx8mp.c
@@ -556,7 +556,6 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
hws[IMX8MP_CLK_MIPI_DSI_ESC_RX] = imx8m_clk_hw_composite_bus("mipi_dsi_esc_rx", imx8mp_mipi_dsi_esc_rx_sels, ccm_base + 0x9200);
hws[IMX8MP_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb_root", ccm_base + 0x9080, 0, 1);
- hws[IMX8MP_CLK_IPG_AUDIO_ROOT] = imx_clk_hw_divider2("ipg_audio_root", "audio_ahb", ccm_base + 0x9180, 0, 1);
hws[IMX8MP_CLK_DRAM_ALT] = imx8m_clk_hw_composite("dram_alt", imx8mp_dram_alt_sels, ccm_base + 0xa000);
hws[IMX8MP_CLK_DRAM_APB] = imx8m_clk_hw_composite_critical("dram_apb", imx8mp_dram_apb_sels, ccm_base + 0xa080);
diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c
index b08019e1faf9..c491bc9c61ce 100644
--- a/drivers/clk/imx/clk-imx8mq.c
+++ b/drivers/clk/imx/clk-imx8mq.c
@@ -358,46 +358,26 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
hws[IMX8MQ_VIDEO2_PLL_OUT] = imx_clk_hw_sscg_pll("video2_pll_out", video2_pll_out_sels, ARRAY_SIZE(video2_pll_out_sels), 0, 0, 0, base + 0x54, 0);
/* SYS PLL1 fixed output */
- hws[IMX8MQ_SYS1_PLL_40M_CG] = imx_clk_hw_gate("sys1_pll_40m_cg", "sys1_pll_out", base + 0x30, 9);
- hws[IMX8MQ_SYS1_PLL_80M_CG] = imx_clk_hw_gate("sys1_pll_80m_cg", "sys1_pll_out", base + 0x30, 11);
- hws[IMX8MQ_SYS1_PLL_100M_CG] = imx_clk_hw_gate("sys1_pll_100m_cg", "sys1_pll_out", base + 0x30, 13);
- hws[IMX8MQ_SYS1_PLL_133M_CG] = imx_clk_hw_gate("sys1_pll_133m_cg", "sys1_pll_out", base + 0x30, 15);
- hws[IMX8MQ_SYS1_PLL_160M_CG] = imx_clk_hw_gate("sys1_pll_160m_cg", "sys1_pll_out", base + 0x30, 17);
- hws[IMX8MQ_SYS1_PLL_200M_CG] = imx_clk_hw_gate("sys1_pll_200m_cg", "sys1_pll_out", base + 0x30, 19);
- hws[IMX8MQ_SYS1_PLL_266M_CG] = imx_clk_hw_gate("sys1_pll_266m_cg", "sys1_pll_out", base + 0x30, 21);
- hws[IMX8MQ_SYS1_PLL_400M_CG] = imx_clk_hw_gate("sys1_pll_400m_cg", "sys1_pll_out", base + 0x30, 23);
- hws[IMX8MQ_SYS1_PLL_800M_CG] = imx_clk_hw_gate("sys1_pll_800m_cg", "sys1_pll_out", base + 0x30, 25);
-
- hws[IMX8MQ_SYS1_PLL_40M] = imx_clk_hw_fixed_factor("sys1_pll_40m", "sys1_pll_40m_cg", 1, 20);
- hws[IMX8MQ_SYS1_PLL_80M] = imx_clk_hw_fixed_factor("sys1_pll_80m", "sys1_pll_80m_cg", 1, 10);
- hws[IMX8MQ_SYS1_PLL_100M] = imx_clk_hw_fixed_factor("sys1_pll_100m", "sys1_pll_100m_cg", 1, 8);
- hws[IMX8MQ_SYS1_PLL_133M] = imx_clk_hw_fixed_factor("sys1_pll_133m", "sys1_pll_133m_cg", 1, 6);
- hws[IMX8MQ_SYS1_PLL_160M] = imx_clk_hw_fixed_factor("sys1_pll_160m", "sys1_pll_160m_cg", 1, 5);
- hws[IMX8MQ_SYS1_PLL_200M] = imx_clk_hw_fixed_factor("sys1_pll_200m", "sys1_pll_200m_cg", 1, 4);
- hws[IMX8MQ_SYS1_PLL_266M] = imx_clk_hw_fixed_factor("sys1_pll_266m", "sys1_pll_266m_cg", 1, 3);
- hws[IMX8MQ_SYS1_PLL_400M] = imx_clk_hw_fixed_factor("sys1_pll_400m", "sys1_pll_400m_cg", 1, 2);
- hws[IMX8MQ_SYS1_PLL_800M] = imx_clk_hw_fixed_factor("sys1_pll_800m", "sys1_pll_800m_cg", 1, 1);
+ hws[IMX8MQ_SYS1_PLL_40M] = imx_clk_hw_fixed_factor("sys1_pll_40m", "sys1_pll_out", 1, 20);
+ hws[IMX8MQ_SYS1_PLL_80M] = imx_clk_hw_fixed_factor("sys1_pll_80m", "sys1_pll_out", 1, 10);
+ hws[IMX8MQ_SYS1_PLL_100M] = imx_clk_hw_fixed_factor("sys1_pll_100m", "sys1_pll_out", 1, 8);
+ hws[IMX8MQ_SYS1_PLL_133M] = imx_clk_hw_fixed_factor("sys1_pll_133m", "sys1_pll_out", 1, 6);
+ hws[IMX8MQ_SYS1_PLL_160M] = imx_clk_hw_fixed_factor("sys1_pll_160m", "sys1_pll_out", 1, 5);
+ hws[IMX8MQ_SYS1_PLL_200M] = imx_clk_hw_fixed_factor("sys1_pll_200m", "sys1_pll_out", 1, 4);
+ hws[IMX8MQ_SYS1_PLL_266M] = imx_clk_hw_fixed_factor("sys1_pll_266m", "sys1_pll_out", 1, 3);
+ hws[IMX8MQ_SYS1_PLL_400M] = imx_clk_hw_fixed_factor("sys1_pll_400m", "sys1_pll_out", 1, 2);
+ hws[IMX8MQ_SYS1_PLL_800M] = imx_clk_hw_fixed_factor("sys1_pll_800m", "sys1_pll_out", 1, 1);
/* SYS PLL2 fixed output */
- hws[IMX8MQ_SYS2_PLL_50M_CG] = imx_clk_hw_gate("sys2_pll_50m_cg", "sys2_pll_out", base + 0x3c, 9);
- hws[IMX8MQ_SYS2_PLL_100M_CG] = imx_clk_hw_gate("sys2_pll_100m_cg", "sys2_pll_out", base + 0x3c, 11);
- hws[IMX8MQ_SYS2_PLL_125M_CG] = imx_clk_hw_gate("sys2_pll_125m_cg", "sys2_pll_out", base + 0x3c, 13);
- hws[IMX8MQ_SYS2_PLL_166M_CG] = imx_clk_hw_gate("sys2_pll_166m_cg", "sys2_pll_out", base + 0x3c, 15);
- hws[IMX8MQ_SYS2_PLL_200M_CG] = imx_clk_hw_gate("sys2_pll_200m_cg", "sys2_pll_out", base + 0x3c, 17);
- hws[IMX8MQ_SYS2_PLL_250M_CG] = imx_clk_hw_gate("sys2_pll_250m_cg", "sys2_pll_out", base + 0x3c, 19);
- hws[IMX8MQ_SYS2_PLL_333M_CG] = imx_clk_hw_gate("sys2_pll_333m_cg", "sys2_pll_out", base + 0x3c, 21);
- hws[IMX8MQ_SYS2_PLL_500M_CG] = imx_clk_hw_gate("sys2_pll_500m_cg", "sys2_pll_out", base + 0x3c, 23);
- hws[IMX8MQ_SYS2_PLL_1000M_CG] = imx_clk_hw_gate("sys2_pll_1000m_cg", "sys2_pll_out", base + 0x3c, 25);
-
- hws[IMX8MQ_SYS2_PLL_50M] = imx_clk_hw_fixed_factor("sys2_pll_50m", "sys2_pll_50m_cg", 1, 20);
- hws[IMX8MQ_SYS2_PLL_100M] = imx_clk_hw_fixed_factor("sys2_pll_100m", "sys2_pll_100m_cg", 1, 10);
- hws[IMX8MQ_SYS2_PLL_125M] = imx_clk_hw_fixed_factor("sys2_pll_125m", "sys2_pll_125m_cg", 1, 8);
- hws[IMX8MQ_SYS2_PLL_166M] = imx_clk_hw_fixed_factor("sys2_pll_166m", "sys2_pll_166m_cg", 1, 6);
- hws[IMX8MQ_SYS2_PLL_200M] = imx_clk_hw_fixed_factor("sys2_pll_200m", "sys2_pll_200m_cg", 1, 5);
- hws[IMX8MQ_SYS2_PLL_250M] = imx_clk_hw_fixed_factor("sys2_pll_250m", "sys2_pll_250m_cg", 1, 4);
- hws[IMX8MQ_SYS2_PLL_333M] = imx_clk_hw_fixed_factor("sys2_pll_333m", "sys2_pll_333m_cg", 1, 3);
- hws[IMX8MQ_SYS2_PLL_500M] = imx_clk_hw_fixed_factor("sys2_pll_500m", "sys2_pll_500m_cg", 1, 2);
- hws[IMX8MQ_SYS2_PLL_1000M] = imx_clk_hw_fixed_factor("sys2_pll_1000m", "sys2_pll_1000m_cg", 1, 1);
+ hws[IMX8MQ_SYS2_PLL_50M] = imx_clk_hw_fixed_factor("sys2_pll_50m", "sys2_pll_out", 1, 20);
+ hws[IMX8MQ_SYS2_PLL_100M] = imx_clk_hw_fixed_factor("sys2_pll_100m", "sys2_pll_out", 1, 10);
+ hws[IMX8MQ_SYS2_PLL_125M] = imx_clk_hw_fixed_factor("sys2_pll_125m", "sys2_pll_out", 1, 8);
+ hws[IMX8MQ_SYS2_PLL_166M] = imx_clk_hw_fixed_factor("sys2_pll_166m", "sys2_pll_out", 1, 6);
+ hws[IMX8MQ_SYS2_PLL_200M] = imx_clk_hw_fixed_factor("sys2_pll_200m", "sys2_pll_out", 1, 5);
+ hws[IMX8MQ_SYS2_PLL_250M] = imx_clk_hw_fixed_factor("sys2_pll_250m", "sys2_pll_out", 1, 4);
+ hws[IMX8MQ_SYS2_PLL_333M] = imx_clk_hw_fixed_factor("sys2_pll_333m", "sys2_pll_out", 1, 3);
+ hws[IMX8MQ_SYS2_PLL_500M] = imx_clk_hw_fixed_factor("sys2_pll_500m", "sys2_pll_out", 1, 2);
+ hws[IMX8MQ_SYS2_PLL_1000M] = imx_clk_hw_fixed_factor("sys2_pll_1000m", "sys2_pll_out", 1, 1);
hws[IMX8MQ_CLK_MON_AUDIO_PLL1_DIV] = imx_clk_hw_divider("audio_pll1_out_monitor", "audio_pll1_bypass", base + 0x78, 0, 3);
hws[IMX8MQ_CLK_MON_AUDIO_PLL2_DIV] = imx_clk_hw_divider("audio_pll2_out_monitor", "audio_pll2_bypass", base + 0x78, 4, 3);
diff --git a/drivers/clk/imx/clk-imx8qm-rsrc.c b/drivers/clk/imx/clk-imx8qm-rsrc.c
new file mode 100644
index 000000000000..87e0b6ac027e
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8qm-rsrc.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019-2021 NXP
+ * Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <dt-bindings/firmware/imx/rsrc.h>
+
+#include "clk-scu.h"
+
+/* Keep sorted in the ascending order */
+static const u32 imx8qm_clk_scu_rsrc_table[] = {
+ IMX_SC_R_A53,
+ IMX_SC_R_A72,
+ IMX_SC_R_DC_0_VIDEO0,
+ IMX_SC_R_DC_0_VIDEO1,
+ IMX_SC_R_DC_0,
+ IMX_SC_R_DC_0_PLL_0,
+ IMX_SC_R_DC_0_PLL_1,
+ IMX_SC_R_DC_1_VIDEO0,
+ IMX_SC_R_DC_1_VIDEO1,
+ IMX_SC_R_DC_1,
+ IMX_SC_R_DC_1_PLL_0,
+ IMX_SC_R_DC_1_PLL_1,
+ IMX_SC_R_SPI_0,
+ IMX_SC_R_SPI_1,
+ IMX_SC_R_SPI_2,
+ IMX_SC_R_SPI_3,
+ IMX_SC_R_UART_0,
+ IMX_SC_R_UART_1,
+ IMX_SC_R_UART_2,
+ IMX_SC_R_UART_3,
+ IMX_SC_R_UART_4,
+ IMX_SC_R_EMVSIM_0,
+ IMX_SC_R_EMVSIM_1,
+ IMX_SC_R_I2C_0,
+ IMX_SC_R_I2C_1,
+ IMX_SC_R_I2C_2,
+ IMX_SC_R_I2C_3,
+ IMX_SC_R_I2C_4,
+ IMX_SC_R_ADC_0,
+ IMX_SC_R_ADC_1,
+ IMX_SC_R_FTM_0,
+ IMX_SC_R_FTM_1,
+ IMX_SC_R_CAN_0,
+ IMX_SC_R_GPU_0_PID0,
+ IMX_SC_R_GPU_1_PID0,
+ IMX_SC_R_PWM_0,
+ IMX_SC_R_PWM_1,
+ IMX_SC_R_PWM_2,
+ IMX_SC_R_PWM_3,
+ IMX_SC_R_PWM_4,
+ IMX_SC_R_PWM_5,
+ IMX_SC_R_PWM_6,
+ IMX_SC_R_PWM_7,
+ IMX_SC_R_GPT_0,
+ IMX_SC_R_GPT_1,
+ IMX_SC_R_GPT_2,
+ IMX_SC_R_GPT_3,
+ IMX_SC_R_GPT_4,
+ IMX_SC_R_FSPI_0,
+ IMX_SC_R_FSPI_1,
+ IMX_SC_R_SDHC_0,
+ IMX_SC_R_SDHC_1,
+ IMX_SC_R_SDHC_2,
+ IMX_SC_R_ENET_0,
+ IMX_SC_R_ENET_1,
+ IMX_SC_R_MLB_0,
+ IMX_SC_R_USB_2,
+ IMX_SC_R_NAND,
+ IMX_SC_R_LVDS_0,
+ IMX_SC_R_LVDS_0_PWM_0,
+ IMX_SC_R_LVDS_0_I2C_0,
+ IMX_SC_R_LVDS_0_I2C_1,
+ IMX_SC_R_LVDS_1,
+ IMX_SC_R_LVDS_1_PWM_0,
+ IMX_SC_R_LVDS_1_I2C_0,
+ IMX_SC_R_LVDS_1_I2C_1,
+ IMX_SC_R_M4_0_I2C,
+ IMX_SC_R_M4_1_I2C,
+ IMX_SC_R_AUDIO_PLL_0,
+ IMX_SC_R_VPU_UART,
+ IMX_SC_R_VPUCORE,
+ IMX_SC_R_MIPI_0,
+ IMX_SC_R_MIPI_0_PWM_0,
+ IMX_SC_R_MIPI_0_I2C_0,
+ IMX_SC_R_MIPI_0_I2C_1,
+ IMX_SC_R_MIPI_1,
+ IMX_SC_R_MIPI_1_PWM_0,
+ IMX_SC_R_MIPI_1_I2C_0,
+ IMX_SC_R_MIPI_1_I2C_1,
+ IMX_SC_R_CSI_0,
+ IMX_SC_R_CSI_0_PWM_0,
+ IMX_SC_R_CSI_0_I2C_0,
+ IMX_SC_R_CSI_1,
+ IMX_SC_R_CSI_1_PWM_0,
+ IMX_SC_R_CSI_1_I2C_0,
+ IMX_SC_R_HDMI,
+ IMX_SC_R_HDMI_I2S,
+ IMX_SC_R_HDMI_I2C_0,
+ IMX_SC_R_HDMI_PLL_0,
+ IMX_SC_R_HDMI_RX,
+ IMX_SC_R_HDMI_RX_BYPASS,
+ IMX_SC_R_HDMI_RX_I2C_0,
+ IMX_SC_R_AUDIO_PLL_1,
+ IMX_SC_R_AUDIO_CLK_0,
+ IMX_SC_R_AUDIO_CLK_1,
+ IMX_SC_R_HDMI_RX_PWM_0,
+ IMX_SC_R_HDMI_PLL_1,
+ IMX_SC_R_VPU,
+};
+
+const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qm = {
+ .rsrc = imx8qm_clk_scu_rsrc_table,
+ .num = ARRAY_SIZE(imx8qm_clk_scu_rsrc_table),
+};
diff --git a/drivers/clk/imx/clk-imx8qxp-rsrc.c b/drivers/clk/imx/clk-imx8qxp-rsrc.c
new file mode 100644
index 000000000000..df09f2a7996d
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8qxp-rsrc.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019-2021 NXP
+ * Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+#include <dt-bindings/firmware/imx/rsrc.h>
+
+#include "clk-scu.h"
+
+/* Keep sorted in the ascending order */
+static const u32 imx8qxp_clk_scu_rsrc_table[] = {
+ IMX_SC_R_DC_0_VIDEO0,
+ IMX_SC_R_DC_0_VIDEO1,
+ IMX_SC_R_DC_0,
+ IMX_SC_R_DC_0_PLL_0,
+ IMX_SC_R_DC_0_PLL_1,
+ IMX_SC_R_SPI_0,
+ IMX_SC_R_SPI_1,
+ IMX_SC_R_SPI_2,
+ IMX_SC_R_SPI_3,
+ IMX_SC_R_UART_0,
+ IMX_SC_R_UART_1,
+ IMX_SC_R_UART_2,
+ IMX_SC_R_UART_3,
+ IMX_SC_R_I2C_0,
+ IMX_SC_R_I2C_1,
+ IMX_SC_R_I2C_2,
+ IMX_SC_R_I2C_3,
+ IMX_SC_R_ADC_0,
+ IMX_SC_R_FTM_0,
+ IMX_SC_R_FTM_1,
+ IMX_SC_R_CAN_0,
+ IMX_SC_R_GPU_0_PID0,
+ IMX_SC_R_LCD_0,
+ IMX_SC_R_LCD_0_PWM_0,
+ IMX_SC_R_PWM_0,
+ IMX_SC_R_PWM_1,
+ IMX_SC_R_PWM_2,
+ IMX_SC_R_PWM_3,
+ IMX_SC_R_PWM_4,
+ IMX_SC_R_PWM_5,
+ IMX_SC_R_PWM_6,
+ IMX_SC_R_PWM_7,
+ IMX_SC_R_GPT_0,
+ IMX_SC_R_GPT_1,
+ IMX_SC_R_GPT_2,
+ IMX_SC_R_GPT_3,
+ IMX_SC_R_GPT_4,
+ IMX_SC_R_FSPI_0,
+ IMX_SC_R_FSPI_1,
+ IMX_SC_R_SDHC_0,
+ IMX_SC_R_SDHC_1,
+ IMX_SC_R_SDHC_2,
+ IMX_SC_R_ENET_0,
+ IMX_SC_R_ENET_1,
+ IMX_SC_R_MLB_0,
+ IMX_SC_R_USB_2,
+ IMX_SC_R_NAND,
+ IMX_SC_R_LVDS_0,
+ IMX_SC_R_LVDS_1,
+ IMX_SC_R_M4_0_I2C,
+ IMX_SC_R_ELCDIF_PLL,
+ IMX_SC_R_AUDIO_PLL_0,
+ IMX_SC_R_PI_0,
+ IMX_SC_R_PI_0_PLL,
+ IMX_SC_R_MIPI_0,
+ IMX_SC_R_MIPI_0_PWM_0,
+ IMX_SC_R_MIPI_0_I2C_0,
+ IMX_SC_R_MIPI_0_I2C_1,
+ IMX_SC_R_MIPI_1,
+ IMX_SC_R_MIPI_1_PWM_0,
+ IMX_SC_R_MIPI_1_I2C_0,
+ IMX_SC_R_MIPI_1_I2C_1,
+ IMX_SC_R_CSI_0,
+ IMX_SC_R_CSI_0_PWM_0,
+ IMX_SC_R_CSI_0_I2C_0,
+ IMX_SC_R_AUDIO_PLL_1,
+ IMX_SC_R_AUDIO_CLK_0,
+ IMX_SC_R_AUDIO_CLK_1,
+ IMX_SC_R_A35,
+ IMX_SC_R_VPU_DEC_0,
+ IMX_SC_R_VPU_ENC_0,
+};
+
+const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qxp = {
+ .rsrc = imx8qxp_clk_scu_rsrc_table,
+ .num = ARRAY_SIZE(imx8qxp_clk_scu_rsrc_table),
+};
diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c
index fbf1170c09ed..c53a688d8ccc 100644
--- a/drivers/clk/imx/clk-imx8qxp.c
+++ b/drivers/clk/imx/clk-imx8qxp.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright 2018 NXP
+ * Copyright 2018-2021 NXP
* Dong Aisheng <aisheng.dong@nxp.com>
*/
@@ -9,12 +9,12 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "clk-scu.h"
-#include <dt-bindings/clock/imx8-clock.h>
#include <dt-bindings/firmware/imx/rsrc.h>
static const char *dc0_sels[] = {
@@ -25,159 +25,278 @@ static const char *dc0_sels[] = {
"dc0_bypass0_clk",
};
+static const char * const dc1_sels[] = {
+ "clk_dummy",
+ "clk_dummy",
+ "dc1_pll0_clk",
+ "dc1_pll1_clk",
+ "dc1_bypass0_clk",
+};
+
+static const char * const enet0_rgmii_txc_sels[] = {
+ "enet0_ref_div",
+ "clk_dummy",
+};
+
+static const char * const enet1_rgmii_txc_sels[] = {
+ "enet1_ref_div",
+ "clk_dummy",
+};
+
+static const char * const hdmi_sels[] = {
+ "clk_dummy",
+ "hdmi_dig_pll_clk",
+ "clk_dummy",
+ "clk_dummy",
+ "hdmi_av_pll_clk",
+};
+
+static const char * const hdmi_rx_sels[] = {
+ "clk_dummy",
+ "hdmi_rx_dig_pll_clk",
+ "clk_dummy",
+ "clk_dummy",
+ "hdmi_rx_bypass_clk",
+};
+
+static const char * const lcd_pxl_sels[] = {
+ "clk_dummy",
+ "clk_dummy",
+ "clk_dummy",
+ "clk_dummy",
+ "lcd_pxl_bypass_div_clk",
+};
+
+static const char * const mipi_sels[] = {
+ "clk_dummy",
+ "clk_dummy",
+ "mipi_pll_div2_clk",
+ "clk_dummy",
+ "clk_dummy",
+};
+
+static const char * const lcd_sels[] = {
+ "clk_dummy",
+ "clk_dummy",
+ "clk_dummy",
+ "clk_dummy",
+ "elcdif_pll",
+};
+
+static const char * const pi_pll0_sels[] = {
+ "clk_dummy",
+ "pi_dpll_clk",
+ "clk_dummy",
+ "clk_dummy",
+ "clk_dummy",
+};
+
static int imx8qxp_clk_probe(struct platform_device *pdev)
{
struct device_node *ccm_node = pdev->dev.of_node;
- struct clk_hw_onecell_data *clk_data;
- struct clk_hw **clks;
- u32 clk_cells;
- int ret, i;
+ const struct imx_clk_scu_rsrc_table *rsrc_table;
+ int ret;
- ret = imx_clk_scu_init(ccm_node);
+ rsrc_table = of_device_get_match_data(&pdev->dev);
+ ret = imx_clk_scu_init(ccm_node, rsrc_table);
if (ret)
return ret;
- clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws,
- IMX_SCU_CLK_END), GFP_KERNEL);
- if (!clk_data)
- return -ENOMEM;
-
- if (of_property_read_u32(ccm_node, "#clock-cells", &clk_cells))
- return -EINVAL;
-
- clk_data->num = IMX_SCU_CLK_END;
- clks = clk_data->hws;
-
- /* Fixed clocks */
- clks[IMX_CLK_DUMMY] = clk_hw_register_fixed_rate(NULL, "dummy", NULL, 0, 0);
- clks[IMX_ADMA_IPG_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "dma_ipg_clk_root", NULL, 0, 120000000);
- clks[IMX_CONN_AXI_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "conn_axi_clk_root", NULL, 0, 333333333);
- clks[IMX_CONN_AHB_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "conn_ahb_clk_root", NULL, 0, 166666666);
- clks[IMX_CONN_IPG_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "conn_ipg_clk_root", NULL, 0, 83333333);
- clks[IMX_DC_AXI_EXT_CLK] = clk_hw_register_fixed_rate(NULL, "dc_axi_ext_clk_root", NULL, 0, 800000000);
- clks[IMX_DC_AXI_INT_CLK] = clk_hw_register_fixed_rate(NULL, "dc_axi_int_clk_root", NULL, 0, 400000000);
- clks[IMX_DC_CFG_CLK] = clk_hw_register_fixed_rate(NULL, "dc_cfg_clk_root", NULL, 0, 100000000);
- clks[IMX_MIPI_IPG_CLK] = clk_hw_register_fixed_rate(NULL, "mipi_ipg_clk_root", NULL, 0, 120000000);
- clks[IMX_IMG_AXI_CLK] = clk_hw_register_fixed_rate(NULL, "img_axi_clk_root", NULL, 0, 400000000);
- clks[IMX_IMG_IPG_CLK] = clk_hw_register_fixed_rate(NULL, "img_ipg_clk_root", NULL, 0, 200000000);
- clks[IMX_IMG_PXL_CLK] = clk_hw_register_fixed_rate(NULL, "img_pxl_clk_root", NULL, 0, 600000000);
- clks[IMX_HSIO_AXI_CLK] = clk_hw_register_fixed_rate(NULL, "hsio_axi_clk_root", NULL, 0, 400000000);
- clks[IMX_HSIO_PER_CLK] = clk_hw_register_fixed_rate(NULL, "hsio_per_clk_root", NULL, 0, 133333333);
- clks[IMX_LSIO_MEM_CLK] = clk_hw_register_fixed_rate(NULL, "lsio_mem_clk_root", NULL, 0, 200000000);
- clks[IMX_LSIO_BUS_CLK] = clk_hw_register_fixed_rate(NULL, "lsio_bus_clk_root", NULL, 0, 100000000);
-
/* ARM core */
- clks[IMX_A35_CLK] = imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU, clk_cells);
+ imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU);
+ imx_clk_scu("a53_clk", IMX_SC_R_A53, IMX_SC_PM_CLK_CPU);
+ imx_clk_scu("a72_clk", IMX_SC_R_A72, IMX_SC_PM_CLK_CPU);
/* LSIO SS */
- clks[IMX_LSIO_PWM0_CLK] = imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_LSIO_PWM1_CLK] = imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_LSIO_PWM2_CLK] = imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_LSIO_PWM3_CLK] = imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_LSIO_PWM4_CLK] = imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_LSIO_PWM5_CLK] = imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_LSIO_PWM6_CLK] = imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_LSIO_PWM7_CLK] = imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_LSIO_GPT0_CLK] = imx_clk_scu("gpt0_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_LSIO_GPT1_CLK] = imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_LSIO_GPT2_CLK] = imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_LSIO_GPT3_CLK] = imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_LSIO_GPT4_CLK] = imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_LSIO_FSPI0_CLK] = imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_LSIO_FSPI1_CLK] = imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER, clk_cells);
-
- /* ADMA SS */
- clks[IMX_ADMA_UART0_CLK] = imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_UART1_CLK] = imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_UART2_CLK] = imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_UART3_CLK] = imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_SPI0_CLK] = imx_clk_scu("spi0_clk", IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_SPI1_CLK] = imx_clk_scu("spi1_clk", IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_SPI2_CLK] = imx_clk_scu("spi2_clk", IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_SPI3_CLK] = imx_clk_scu("spi3_clk", IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_CAN0_CLK] = imx_clk_scu("can0_clk", IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_I2C0_CLK] = imx_clk_scu("i2c0_clk", IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_I2C1_CLK] = imx_clk_scu("i2c1_clk", IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_I2C2_CLK] = imx_clk_scu("i2c2_clk", IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_I2C3_CLK] = imx_clk_scu("i2c3_clk", IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_FTM0_CLK] = imx_clk_scu("ftm0_clk", IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_FTM1_CLK] = imx_clk_scu("ftm1_clk", IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_ADC0_CLK] = imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_PWM_CLK] = imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_ADMA_LCD_CLK] = imx_clk_scu("lcd_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER, clk_cells);
+ imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("gpt0_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER);
+
+ /* DMA SS */
+ imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("uart4_clk", IMX_SC_R_UART_4, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("sim0_clk", IMX_SC_R_EMVSIM_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("spi0_clk", IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("spi1_clk", IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("spi2_clk", IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("spi3_clk", IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("can0_clk", IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("can1_clk", IMX_SC_R_CAN_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("can2_clk", IMX_SC_R_CAN_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("i2c0_clk", IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("i2c1_clk", IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("i2c2_clk", IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("i2c3_clk", IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("i2c4_clk", IMX_SC_R_I2C_4, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("ftm0_clk", IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("ftm1_clk", IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("adc1_clk", IMX_SC_R_ADC_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu2("lcd_clk", lcd_sels, ARRAY_SIZE(lcd_sels), IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu2("lcd_pxl_clk", lcd_pxl_sels, ARRAY_SIZE(lcd_pxl_sels), IMX_SC_R_LCD_0, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu("lcd_pxl_bypass_div_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("elcdif_pll", IMX_SC_R_ELCDIF_PLL, IMX_SC_PM_CLK_PLL);
+
+ /* Audio SS */
+ imx_clk_scu("audio_pll0_clk", IMX_SC_R_AUDIO_PLL_0, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu("audio_pll1_clk", IMX_SC_R_AUDIO_PLL_1, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu("audio_pll_div_clk0_clk", IMX_SC_R_AUDIO_PLL_0, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu("audio_pll_div_clk1_clk", IMX_SC_R_AUDIO_PLL_1, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu("audio_rec_clk0_clk", IMX_SC_R_AUDIO_PLL_0, IMX_SC_PM_CLK_MISC1);
+ imx_clk_scu("audio_rec_clk1_clk", IMX_SC_R_AUDIO_PLL_1, IMX_SC_PM_CLK_MISC1);
/* Connectivity */
- clks[IMX_CONN_SDHC0_CLK] = imx_clk_scu("sdhc0_clk", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_CONN_SDHC1_CLK] = imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_CONN_SDHC2_CLK] = imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_CONN_ENET0_ROOT_CLK] = imx_clk_scu("enet0_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_CONN_ENET0_BYPASS_CLK] = imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS, clk_cells);
- clks[IMX_CONN_ENET0_RGMII_CLK] = imx_clk_scu("enet0_rgmii_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0, clk_cells);
- clks[IMX_CONN_ENET1_ROOT_CLK] = imx_clk_scu("enet1_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_CONN_ENET1_BYPASS_CLK] = imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS, clk_cells);
- clks[IMX_CONN_ENET1_RGMII_CLK] = imx_clk_scu("enet1_rgmii_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0, clk_cells);
- clks[IMX_CONN_GPMI_BCH_IO_CLK] = imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS, clk_cells);
- clks[IMX_CONN_GPMI_BCH_CLK] = imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_CONN_USB2_ACLK] = imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_CONN_USB2_BUS_CLK] = imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS, clk_cells);
- clks[IMX_CONN_USB2_LPM_CLK] = imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC, clk_cells);
+ imx_clk_scu("sdhc0_clk", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("enet0_root_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER);
+ imx_clk_divider_gpr_scu("enet0_ref_div", "enet0_root_clk", IMX_SC_R_ENET_0, IMX_SC_C_CLKDIV);
+ imx_clk_mux_gpr_scu("enet0_rgmii_txc_sel", enet0_rgmii_txc_sels, ARRAY_SIZE(enet0_rgmii_txc_sels), IMX_SC_R_ENET_0, IMX_SC_C_TXCLK);
+ imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_gate_gpr_scu("enet0_ref_50_clk", "clk_dummy", IMX_SC_R_ENET_0, IMX_SC_C_DISABLE_50, true);
+ imx_clk_scu("enet0_rgmii_rx_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu("enet1_root_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER);
+ imx_clk_divider_gpr_scu("enet1_ref_div", "enet1_root_clk", IMX_SC_R_ENET_1, IMX_SC_C_CLKDIV);
+ imx_clk_mux_gpr_scu("enet1_rgmii_txc_sel", enet1_rgmii_txc_sels, ARRAY_SIZE(enet1_rgmii_txc_sels), IMX_SC_R_ENET_1, IMX_SC_C_TXCLK);
+ imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_gate_gpr_scu("enet1_ref_50_clk", "clk_dummy", IMX_SC_R_ENET_1, IMX_SC_C_DISABLE_50, true);
+ imx_clk_scu("enet1_rgmii_rx_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS);
+ imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS);
+ imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC);
/* Display controller SS */
- clks[IMX_DC0_DISP0_CLK] = imx_clk_scu2("dc0_disp0_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0, clk_cells);
- clks[IMX_DC0_DISP1_CLK] = imx_clk_scu2("dc0_disp1_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1, clk_cells);
- clks[IMX_DC0_PLL0_CLK] = imx_clk_scu("dc0_pll0_clk", IMX_SC_R_DC_0_PLL_0, IMX_SC_PM_CLK_PLL, clk_cells);
- clks[IMX_DC0_PLL1_CLK] = imx_clk_scu("dc0_pll1_clk", IMX_SC_R_DC_0_PLL_1, IMX_SC_PM_CLK_PLL, clk_cells);
- clks[IMX_DC0_BYPASS0_CLK] = imx_clk_scu("dc0_bypass0_clk", IMX_SC_R_DC_0_VIDEO0, IMX_SC_PM_CLK_BYPASS, clk_cells);
- clks[IMX_DC0_BYPASS1_CLK] = imx_clk_scu("dc0_bypass1_clk", IMX_SC_R_DC_0_VIDEO1, IMX_SC_PM_CLK_BYPASS, clk_cells);
+ imx_clk_scu2("dc0_disp0_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu2("dc0_disp1_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1);
+ imx_clk_scu("dc0_pll0_clk", IMX_SC_R_DC_0_PLL_0, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu("dc0_pll1_clk", IMX_SC_R_DC_0_PLL_1, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu("dc0_bypass0_clk", IMX_SC_R_DC_0_VIDEO0, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("dc0_bypass1_clk", IMX_SC_R_DC_0_VIDEO1, IMX_SC_PM_CLK_BYPASS);
+
+ imx_clk_scu2("dc1_disp0_clk", dc1_sels, ARRAY_SIZE(dc1_sels), IMX_SC_R_DC_1, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu2("dc1_disp1_clk", dc1_sels, ARRAY_SIZE(dc1_sels), IMX_SC_R_DC_1, IMX_SC_PM_CLK_MISC1);
+ imx_clk_scu("dc1_pll0_clk", IMX_SC_R_DC_1_PLL_0, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu("dc1_pll1_clk", IMX_SC_R_DC_1_PLL_1, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu("dc1_bypass0_clk", IMX_SC_R_DC_1_VIDEO0, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("dc1_bypass1_clk", IMX_SC_R_DC_1_VIDEO1, IMX_SC_PM_CLK_BYPASS);
/* MIPI-LVDS SS */
- clks[IMX_MIPI0_LVDS_PIXEL_CLK] = imx_clk_scu("mipi0_lvds_pixel_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC2, clk_cells);
- clks[IMX_MIPI0_LVDS_BYPASS_CLK] = imx_clk_scu("mipi0_lvds_bypass_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_BYPASS, clk_cells);
- clks[IMX_MIPI0_LVDS_PHY_CLK] = imx_clk_scu("mipi0_lvds_phy_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC3, clk_cells);
- clks[IMX_MIPI0_I2C0_CLK] = imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2, clk_cells);
- clks[IMX_MIPI0_I2C1_CLK] = imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2, clk_cells);
- clks[IMX_MIPI0_PWM0_CLK] = imx_clk_scu("mipi0_pwm0_clk", IMX_SC_R_MIPI_0_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_MIPI1_LVDS_PIXEL_CLK] = imx_clk_scu("mipi1_lvds_pixel_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC2, clk_cells);
- clks[IMX_MIPI1_LVDS_BYPASS_CLK] = imx_clk_scu("mipi1_lvds_bypass_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_BYPASS, clk_cells);
- clks[IMX_MIPI1_LVDS_PHY_CLK] = imx_clk_scu("mipi1_lvds_phy_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC3, clk_cells);
- clks[IMX_MIPI1_I2C0_CLK] = imx_clk_scu("mipi1_i2c0_clk", IMX_SC_R_MIPI_1_I2C_0, IMX_SC_PM_CLK_MISC2, clk_cells);
- clks[IMX_MIPI1_I2C1_CLK] = imx_clk_scu("mipi1_i2c1_clk", IMX_SC_R_MIPI_1_I2C_1, IMX_SC_PM_CLK_MISC2, clk_cells);
- clks[IMX_MIPI1_PWM0_CLK] = imx_clk_scu("mipi1_pwm0_clk", IMX_SC_R_MIPI_1_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
+ imx_clk_scu("mipi0_bypass_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("mipi0_pixel_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("mipi0_lvds_pixel_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("mipi0_lvds_bypass_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("mipi0_lvds_phy_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC3);
+ imx_clk_scu2("mipi0_dsi_tx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_MST_BUS);
+ imx_clk_scu2("mipi0_dsi_rx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_SLV_BUS);
+ imx_clk_scu2("mipi0_dsi_phy_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PHY);
+ imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("mipi0_pwm0_clk", IMX_SC_R_MIPI_0_PWM_0, IMX_SC_PM_CLK_PER);
+
+ imx_clk_scu("mipi1_bypass_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("mipi1_pixel_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("mipi1_lvds_pixel_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("mipi1_lvds_bypass_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("mipi1_lvds_phy_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC3);
+
+ imx_clk_scu2("mipi1_dsi_tx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_MST_BUS);
+ imx_clk_scu2("mipi1_dsi_rx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_SLV_BUS);
+ imx_clk_scu2("mipi1_dsi_phy_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_PHY);
+ imx_clk_scu("mipi1_i2c0_clk", IMX_SC_R_MIPI_1_I2C_0, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("mipi1_i2c1_clk", IMX_SC_R_MIPI_1_I2C_1, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("mipi1_pwm0_clk", IMX_SC_R_MIPI_1_PWM_0, IMX_SC_PM_CLK_PER);
+
+ imx_clk_scu("lvds0_i2c0_clk", IMX_SC_R_LVDS_0_I2C_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("lvds0_i2c1_clk", IMX_SC_R_LVDS_0_I2C_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("lvds0_pwm0_clk", IMX_SC_R_LVDS_0_PWM_0, IMX_SC_PM_CLK_PER);
+
+ imx_clk_scu("lvds1_i2c0_clk", IMX_SC_R_LVDS_1_I2C_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("lvds1_i2c1_clk", IMX_SC_R_LVDS_1_I2C_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("lvds1_pwm0_clk", IMX_SC_R_LVDS_1_PWM_0, IMX_SC_PM_CLK_PER);
/* MIPI CSI SS */
- clks[IMX_CSI0_CORE_CLK] = imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_CSI0_ESC_CLK] = imx_clk_scu("mipi_csi0_esc_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC, clk_cells);
- clks[IMX_CSI0_I2C0_CLK] = imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_CSI0_PWM0_CLK] = imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER, clk_cells);
+ imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("mipi_csi0_esc_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC);
+ imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("mipi_csi1_core_clk", IMX_SC_R_CSI_1, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("mipi_csi1_esc_clk", IMX_SC_R_CSI_1, IMX_SC_PM_CLK_MISC);
+ imx_clk_scu("mipi_csi1_i2c0_clk", IMX_SC_R_CSI_1_I2C_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("mipi_csi1_pwm0_clk", IMX_SC_R_CSI_1_PWM_0, IMX_SC_PM_CLK_PER);
+
+ /* Parallel Interface SS */
+ imx_clk_scu("pi_dpll_clk", IMX_SC_R_PI_0_PLL, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu2("pi_per_div_clk", pi_pll0_sels, ARRAY_SIZE(pi_pll0_sels), IMX_SC_R_PI_0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("pi_mclk_div_clk", IMX_SC_R_PI_0, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu("pi_i2c0_div_clk", IMX_SC_R_PI_0_I2C_0, IMX_SC_PM_CLK_PER);
/* GPU SS */
- clks[IMX_GPU0_CORE_CLK] = imx_clk_scu("gpu_core0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER, clk_cells);
- clks[IMX_GPU0_SHADER_CLK] = imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC, clk_cells);
-
- for (i = 0; i < clk_data->num; i++) {
- if (IS_ERR(clks[i]))
- pr_warn("i.MX clk %u: register failed with %ld\n",
- i, PTR_ERR(clks[i]));
- }
-
- if (clk_cells == 2) {
- ret = of_clk_add_hw_provider(ccm_node, imx_scu_of_clk_src_get, imx_scu_clks);
- if (ret)
- imx_clk_scu_unregister();
- } else {
- /*
- * legacy binding code path doesn't unregister here because
- * it will be removed later.
- */
- ret = of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get, clk_data);
- }
+ imx_clk_scu("gpu_core0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC);
+
+ imx_clk_scu("gpu_core1_clk", IMX_SC_R_GPU_1_PID0, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("gpu_shader1_clk", IMX_SC_R_GPU_1_PID0, IMX_SC_PM_CLK_MISC);
+
+ /* CM40 SS */
+ imx_clk_scu("cm40_i2c_div", IMX_SC_R_M4_0_I2C, IMX_SC_PM_CLK_PER);
+ imx_clk_scu("cm40_lpuart_div", IMX_SC_R_M4_0_UART, IMX_SC_PM_CLK_PER);
+
+ /* CM41 SS */
+ imx_clk_scu("cm41_i2c_div", IMX_SC_R_M4_1_I2C, IMX_SC_PM_CLK_PER);
+
+ /* HDMI TX SS */
+ imx_clk_scu("hdmi_dig_pll_clk", IMX_SC_R_HDMI_PLL_0, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu("hdmi_av_pll_clk", IMX_SC_R_HDMI_PLL_1, IMX_SC_PM_CLK_PLL);
+ imx_clk_scu2("hdmi_pixel_mux_clk", hdmi_sels, ARRAY_SIZE(hdmi_sels), IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu2("hdmi_pixel_link_clk", hdmi_sels, ARRAY_SIZE(hdmi_sels), IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC1);
+ imx_clk_scu("hdmi_ipg_clk", IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC4);
+ imx_clk_scu("hdmi_i2c0_clk", IMX_SC_R_HDMI_I2C_0, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("hdmi_hdp_core_clk", IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu2("hdmi_pxl_clk", hdmi_sels, ARRAY_SIZE(hdmi_sels), IMX_SC_R_HDMI, IMX_SC_PM_CLK_MISC3);
+ imx_clk_scu("hdmi_i2s_bypass_clk", IMX_SC_R_HDMI_I2S, IMX_SC_PM_CLK_BYPASS);
+ imx_clk_scu("hdmi_i2s_clk", IMX_SC_R_HDMI_I2S, IMX_SC_PM_CLK_MISC0);
+
+ /* HDMI RX SS */
+ imx_clk_scu("hdmi_rx_i2s_bypass_clk", IMX_SC_R_HDMI_RX_BYPASS, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu("hdmi_rx_spdif_bypass_clk", IMX_SC_R_HDMI_RX_BYPASS, IMX_SC_PM_CLK_MISC1);
+ imx_clk_scu("hdmi_rx_bypass_clk", IMX_SC_R_HDMI_RX_BYPASS, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("hdmi_rx_i2c0_clk", IMX_SC_R_HDMI_RX_I2C_0, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("hdmi_rx_pwm_clk", IMX_SC_R_HDMI_RX_PWM_0, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu("hdmi_rx_spdif_clk", IMX_SC_R_HDMI_RX, IMX_SC_PM_CLK_MISC0);
+ imx_clk_scu2("hdmi_rx_hd_ref_clk", hdmi_rx_sels, ARRAY_SIZE(hdmi_rx_sels), IMX_SC_R_HDMI_RX, IMX_SC_PM_CLK_MISC1);
+ imx_clk_scu2("hdmi_rx_hd_core_clk", hdmi_rx_sels, ARRAY_SIZE(hdmi_rx_sels), IMX_SC_R_HDMI_RX, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu2("hdmi_rx_pxl_clk", hdmi_rx_sels, ARRAY_SIZE(hdmi_rx_sels), IMX_SC_R_HDMI_RX, IMX_SC_PM_CLK_MISC3);
+ imx_clk_scu("hdmi_rx_i2s_clk", IMX_SC_R_HDMI_RX, IMX_SC_PM_CLK_MISC4);
+
+ ret = of_clk_add_hw_provider(ccm_node, imx_scu_of_clk_src_get, imx_scu_clks);
+ if (ret)
+ imx_clk_scu_unregister();
return ret;
}
static const struct of_device_id imx8qxp_match[] = {
{ .compatible = "fsl,scu-clk", },
- { .compatible = "fsl,imx8qxp-clk", },
+ { .compatible = "fsl,imx8qxp-clk", &imx_clk_scu_rsrc_imx8qxp, },
+ { .compatible = "fsl,imx8qm-clk", &imx_clk_scu_rsrc_imx8qm, },
{ /* sentinel */ }
};
diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c
index f89b4da10e80..083da31dc3ea 100644
--- a/drivers/clk/imx/clk-scu.c
+++ b/drivers/clk/imx/clk-scu.c
@@ -1,11 +1,12 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright 2018 NXP
+ * Copyright 2018-2021 NXP
* Dong Aisheng <aisheng.dong@nxp.com>
*/
#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/arm-smccc.h>
+#include <linux/bsearch.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/of_platform.h>
@@ -22,6 +23,7 @@
static struct imx_sc_ipc *ccm_ipc_handle;
static struct device_node *pd_np;
static struct platform_driver imx_clk_scu_driver;
+static const struct imx_clk_scu_rsrc_table *rsrc_table;
struct imx_scu_clk_node {
const char *name;
@@ -48,11 +50,29 @@ struct clk_scu {
u8 clk_type;
/* for state save&restore */
+ struct clk_hw *parent;
+ u8 parent_index;
bool is_enabled;
u32 rate;
};
/*
+ * struct clk_gpr_scu - Description of one SCU GPR clock
+ * @hw: the common clk_hw
+ * @rsrc_id: resource ID of this SCU clock
+ * @gpr_id: GPR ID index to control the divider
+ */
+struct clk_gpr_scu {
+ struct clk_hw hw;
+ u16 rsrc_id;
+ u8 gpr_id;
+ u8 flags;
+ bool gate_invert;
+};
+
+#define to_clk_gpr_scu(_hw) container_of(_hw, struct clk_gpr_scu, hw)
+
+/*
* struct imx_sc_msg_req_set_clock_rate - clock set rate protocol
* @hdr: SCU protocol header
* @rate: rate to set
@@ -151,7 +171,26 @@ static inline struct clk_scu *to_clk_scu(struct clk_hw *hw)
return container_of(hw, struct clk_scu, hw);
}
-int imx_clk_scu_init(struct device_node *np)
+static inline int imx_scu_clk_search_cmp(const void *rsrc, const void *rsrc_p)
+{
+ return *(u32 *)rsrc - *(u32 *)rsrc_p;
+}
+
+static bool imx_scu_clk_is_valid(u32 rsrc_id)
+{
+ void *p;
+
+ if (!rsrc_table)
+ return true;
+
+ p = bsearch(&rsrc_id, rsrc_table->rsrc, rsrc_table->num,
+ sizeof(rsrc_table->rsrc[0]), imx_scu_clk_search_cmp);
+
+ return p != NULL;
+}
+
+int imx_clk_scu_init(struct device_node *np,
+ const struct imx_clk_scu_rsrc_table *data)
{
u32 clk_cells;
int ret, i;
@@ -170,6 +209,8 @@ int imx_clk_scu_init(struct device_node *np)
pd_np = of_find_compatible_node(NULL, NULL, "fsl,scu-pd");
if (!pd_np)
return -EINVAL;
+
+ rsrc_table = data;
}
return platform_driver_register(&imx_clk_scu_driver);
@@ -234,8 +275,10 @@ static int clk_scu_atf_set_cpu_rate(struct clk_hw *hw, unsigned long rate,
struct arm_smccc_res res;
unsigned long cluster_id;
- if (clk->rsrc_id == IMX_SC_R_A35)
+ if (clk->rsrc_id == IMX_SC_R_A35 || clk->rsrc_id == IMX_SC_R_A53)
cluster_id = 0;
+ else if (clk->rsrc_id == IMX_SC_R_A72)
+ cluster_id = 1;
else
return -EINVAL;
@@ -296,6 +339,8 @@ static u8 clk_scu_get_parent(struct clk_hw *hw)
return 0;
}
+ clk->parent_index = msg.data.resp.parent;
+
return msg.data.resp.parent;
}
@@ -304,6 +349,7 @@ static int clk_scu_set_parent(struct clk_hw *hw, u8 index)
struct clk_scu *clk = to_clk_scu(hw);
struct imx_sc_msg_set_clock_parent msg;
struct imx_sc_rpc_msg *hdr = &msg.hdr;
+ int ret;
hdr->ver = IMX_SC_RPC_VERSION;
hdr->svc = IMX_SC_RPC_SVC_PM;
@@ -314,7 +360,16 @@ static int clk_scu_set_parent(struct clk_hw *hw, u8 index)
msg.clk = clk->clk_type;
msg.parent = index;
- return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
+ ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
+ if (ret) {
+ pr_err("%s: failed to set clock parent %d\n",
+ clk_hw_get_name(hw), ret);
+ return ret;
+ }
+
+ clk->parent_index = index;
+
+ return 0;
}
static int sc_pm_clock_enable(struct imx_sc_ipc *ipc, u16 resource,
@@ -386,6 +441,12 @@ static const struct clk_ops clk_scu_cpu_ops = {
.unprepare = clk_scu_unprepare,
};
+static const struct clk_ops clk_scu_pi_ops = {
+ .recalc_rate = clk_scu_recalc_rate,
+ .round_rate = clk_scu_round_rate,
+ .set_rate = clk_scu_set_rate,
+};
+
struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
const char * const *parents, int num_parents,
u32 rsrc_id, u8 clk_type)
@@ -404,8 +465,10 @@ struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
init.name = name;
init.ops = &clk_scu_ops;
- if (rsrc_id == IMX_SC_R_A35)
+ if (rsrc_id == IMX_SC_R_A35 || rsrc_id == IMX_SC_R_A53 || rsrc_id == IMX_SC_R_A72)
init.ops = &clk_scu_cpu_ops;
+ else if (rsrc_id == IMX_SC_R_PI_0_PLL)
+ init.ops = &clk_scu_pi_ops;
else
init.ops = &clk_scu_ops;
init.parent_names = parents;
@@ -458,15 +521,19 @@ static int imx_clk_scu_probe(struct platform_device *pdev)
struct clk_hw *hw;
int ret;
- pm_runtime_set_suspended(dev);
- pm_runtime_set_autosuspend_delay(dev, 50);
- pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_enable(dev);
-
- ret = pm_runtime_get_sync(dev);
- if (ret) {
- pm_runtime_disable(dev);
- return ret;
+ if (!((clk->rsrc == IMX_SC_R_A35) || (clk->rsrc == IMX_SC_R_A53) ||
+ (clk->rsrc == IMX_SC_R_A72))) {
+ pm_runtime_set_suspended(dev);
+ pm_runtime_set_autosuspend_delay(dev, 50);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(dev);
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret) {
+ pm_genpd_remove_device(dev);
+ pm_runtime_disable(dev);
+ return ret;
+ }
}
hw = __imx_clk_scu(dev, clk->name, clk->parents, clk->num_parents,
@@ -479,8 +546,11 @@ static int imx_clk_scu_probe(struct platform_device *pdev)
clk->hw = hw;
list_add_tail(&clk->node, &imx_scu_clks[clk->rsrc]);
- pm_runtime_mark_last_busy(&pdev->dev);
- pm_runtime_put_autosuspend(&pdev->dev);
+ if (!((clk->rsrc == IMX_SC_R_A35) || (clk->rsrc == IMX_SC_R_A53) ||
+ (clk->rsrc == IMX_SC_R_A72))) {
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+ }
dev_dbg(dev, "register SCU clock rsrc:%d type:%d\n", clk->rsrc,
clk->clk_type);
@@ -491,10 +561,28 @@ static int imx_clk_scu_probe(struct platform_device *pdev)
static int __maybe_unused imx_clk_scu_suspend(struct device *dev)
{
struct clk_scu *clk = dev_get_drvdata(dev);
+ u32 rsrc_id = clk->rsrc_id;
+
+ if ((rsrc_id == IMX_SC_R_A35) || (rsrc_id == IMX_SC_R_A53) ||
+ (rsrc_id == IMX_SC_R_A72))
+ return 0;
+
+ clk->parent = clk_hw_get_parent(&clk->hw);
- clk->rate = clk_hw_get_rate(&clk->hw);
+ /* DC SS needs to handle bypass clock using non-cached clock rate */
+ if (clk->rsrc_id == IMX_SC_R_DC_0_VIDEO0 ||
+ clk->rsrc_id == IMX_SC_R_DC_0_VIDEO1 ||
+ clk->rsrc_id == IMX_SC_R_DC_1_VIDEO0 ||
+ clk->rsrc_id == IMX_SC_R_DC_1_VIDEO1)
+ clk->rate = clk_scu_recalc_rate(&clk->hw, 0);
+ else
+ clk->rate = clk_hw_get_rate(&clk->hw);
clk->is_enabled = clk_hw_is_enabled(&clk->hw);
+ if (clk->parent)
+ dev_dbg(dev, "save parent %s idx %u\n", clk_hw_get_name(clk->parent),
+ clk->parent_index);
+
if (clk->rate)
dev_dbg(dev, "save rate %d\n", clk->rate);
@@ -507,15 +595,27 @@ static int __maybe_unused imx_clk_scu_suspend(struct device *dev)
static int __maybe_unused imx_clk_scu_resume(struct device *dev)
{
struct clk_scu *clk = dev_get_drvdata(dev);
+ u32 rsrc_id = clk->rsrc_id;
int ret = 0;
+ if ((rsrc_id == IMX_SC_R_A35) || (rsrc_id == IMX_SC_R_A53) ||
+ (rsrc_id == IMX_SC_R_A72))
+ return 0;
+
+ if (clk->parent) {
+ ret = clk_scu_set_parent(&clk->hw, clk->parent_index);
+ dev_dbg(dev, "restore parent %s idx %u %s\n",
+ clk_hw_get_name(clk->parent),
+ clk->parent_index, !ret ? "success" : "failed");
+ }
+
if (clk->rate) {
ret = clk_scu_set_rate(&clk->hw, clk->rate, 0);
dev_dbg(dev, "restore rate %d %s\n", clk->rate,
!ret ? "success" : "failed");
}
- if (clk->is_enabled) {
+ if (clk->is_enabled && rsrc_id != IMX_SC_R_PI_0_PLL) {
ret = clk_scu_prepare(&clk->hw);
dev_dbg(dev, "restore enabled state %s\n",
!ret ? "success" : "failed");
@@ -567,6 +667,9 @@ struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
struct platform_device *pdev;
int ret;
+ if (!imx_scu_clk_is_valid(rsrc_id))
+ return ERR_PTR(-EINVAL);
+
pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE);
if (!pdev) {
pr_err("%s: failed to allocate scu clk dev rsrc %d type %d\n",
@@ -605,3 +708,176 @@ void imx_clk_scu_unregister(void)
}
}
}
+
+static unsigned long clk_gpr_div_scu_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_gpr_scu *clk = to_clk_gpr_scu(hw);
+ unsigned long rate = 0;
+ u32 val;
+ int err;
+
+ err = imx_sc_misc_get_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, &val);
+
+ rate = val ? parent_rate / 2 : parent_rate;
+
+ return err ? 0 : rate;
+}
+
+static long clk_gpr_div_scu_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ if (rate < *prate)
+ rate = *prate / 2;
+ else
+ rate = *prate;
+
+ return rate;
+}
+
+static int clk_gpr_div_scu_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_gpr_scu *clk = to_clk_gpr_scu(hw);
+ uint32_t val;
+ int err;
+
+ val = (rate < parent_rate) ? 1 : 0;
+ err = imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, val);
+
+ return err ? -EINVAL : 0;
+}
+
+static const struct clk_ops clk_gpr_div_scu_ops = {
+ .recalc_rate = clk_gpr_div_scu_recalc_rate,
+ .round_rate = clk_gpr_div_scu_round_rate,
+ .set_rate = clk_gpr_div_scu_set_rate,
+};
+
+static u8 clk_gpr_mux_scu_get_parent(struct clk_hw *hw)
+{
+ struct clk_gpr_scu *clk = to_clk_gpr_scu(hw);
+ u32 val = 0;
+
+ imx_sc_misc_get_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, &val);
+
+ return (u8)val;
+}
+
+static int clk_gpr_mux_scu_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_gpr_scu *clk = to_clk_gpr_scu(hw);
+
+ return imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, index);
+}
+
+static const struct clk_ops clk_gpr_mux_scu_ops = {
+ .get_parent = clk_gpr_mux_scu_get_parent,
+ .set_parent = clk_gpr_mux_scu_set_parent,
+};
+
+static int clk_gpr_gate_scu_prepare(struct clk_hw *hw)
+{
+ struct clk_gpr_scu *clk = to_clk_gpr_scu(hw);
+
+ return imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, !clk->gate_invert);
+}
+
+static void clk_gpr_gate_scu_unprepare(struct clk_hw *hw)
+{
+ struct clk_gpr_scu *clk = to_clk_gpr_scu(hw);
+ int ret;
+
+ ret = imx_sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, clk->gate_invert);
+ if (ret)
+ pr_err("%s: clk unprepare failed %d\n", clk_hw_get_name(hw),
+ ret);
+}
+
+static int clk_gpr_gate_scu_is_prepared(struct clk_hw *hw)
+{
+ struct clk_gpr_scu *clk = to_clk_gpr_scu(hw);
+ int ret;
+ u32 val;
+
+ ret = imx_sc_misc_get_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, &val);
+ if (ret)
+ return ret;
+
+ return clk->gate_invert ? !val : val;
+}
+
+static const struct clk_ops clk_gpr_gate_scu_ops = {
+ .prepare = clk_gpr_gate_scu_prepare,
+ .unprepare = clk_gpr_gate_scu_unprepare,
+ .is_prepared = clk_gpr_gate_scu_is_prepared,
+};
+
+struct clk_hw *__imx_clk_gpr_scu(const char *name, const char * const *parent_name,
+ int num_parents, u32 rsrc_id, u8 gpr_id, u8 flags,
+ bool invert)
+{
+ struct imx_scu_clk_node *clk_node;
+ struct clk_gpr_scu *clk;
+ struct clk_hw *hw;
+ struct clk_init_data init;
+ int ret;
+
+ if (rsrc_id >= IMX_SC_R_LAST || gpr_id >= IMX_SC_C_LAST)
+ return ERR_PTR(-EINVAL);
+
+ clk_node = kzalloc(sizeof(*clk_node), GFP_KERNEL);
+ if (!clk_node)
+ return ERR_PTR(-ENOMEM);
+
+ if (!imx_scu_clk_is_valid(rsrc_id))
+ return ERR_PTR(-EINVAL);
+
+ clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+ if (!clk) {
+ kfree(clk_node);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ clk->rsrc_id = rsrc_id;
+ clk->gpr_id = gpr_id;
+ clk->flags = flags;
+ clk->gate_invert = invert;
+
+ if (flags & IMX_SCU_GPR_CLK_GATE)
+ init.ops = &clk_gpr_gate_scu_ops;
+
+ if (flags & IMX_SCU_GPR_CLK_DIV)
+ init.ops = &clk_gpr_div_scu_ops;
+
+ if (flags & IMX_SCU_GPR_CLK_MUX)
+ init.ops = &clk_gpr_mux_scu_ops;
+
+ init.flags = 0;
+ init.name = name;
+ init.parent_names = parent_name;
+ init.num_parents = num_parents;
+
+ clk->hw.init = &init;
+
+ hw = &clk->hw;
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
+ kfree(clk);
+ kfree(clk_node);
+ hw = ERR_PTR(ret);
+ } else {
+ clk_node->hw = hw;
+ clk_node->clk_type = gpr_id;
+ list_add_tail(&clk_node->node, &imx_scu_clks[rsrc_id]);
+ }
+
+ return hw;
+}
diff --git a/drivers/clk/imx/clk-scu.h b/drivers/clk/imx/clk-scu.h
index e8352164923e..22156e93b85d 100644
--- a/drivers/clk/imx/clk-scu.h
+++ b/drivers/clk/imx/clk-scu.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * Copyright 2018 NXP
+ * Copyright 2018-2021 NXP
* Dong Aisheng <aisheng.dong@nxp.com>
*/
@@ -10,10 +10,22 @@
#include <linux/firmware/imx/sci.h>
#include <linux/of.h>
+#define IMX_SCU_GPR_CLK_GATE BIT(0)
+#define IMX_SCU_GPR_CLK_DIV BIT(1)
+#define IMX_SCU_GPR_CLK_MUX BIT(2)
+
+struct imx_clk_scu_rsrc_table {
+ const u32 *rsrc;
+ u8 num;
+};
+
extern struct list_head imx_scu_clks[];
extern const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops;
+extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qxp;
+extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qm;
-int imx_clk_scu_init(struct device_node *np);
+int imx_clk_scu_init(struct device_node *np,
+ const struct imx_clk_scu_rsrc_table *data);
struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec,
void *data);
struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
@@ -31,23 +43,20 @@ struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name,
void __iomem *reg, u8 bit_idx, bool hw_gate);
void imx_clk_lpcg_scu_unregister(struct clk_hw *hw);
+struct clk_hw *__imx_clk_gpr_scu(const char *name, const char * const *parent_name,
+ int num_parents, u32 rsrc_id, u8 gpr_id, u8 flags,
+ bool invert);
+
static inline struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id,
- u8 clk_type, u8 clk_cells)
+ u8 clk_type)
{
- if (clk_cells == 2)
- return imx_clk_scu_alloc_dev(name, NULL, 0, rsrc_id, clk_type);
- else
- return __imx_clk_scu(NULL, name, NULL, 0, rsrc_id, clk_type);
+ return imx_clk_scu_alloc_dev(name, NULL, 0, rsrc_id, clk_type);
}
static inline struct clk_hw *imx_clk_scu2(const char *name, const char * const *parents,
- int num_parents, u32 rsrc_id, u8 clk_type,
- u8 clk_cells)
+ int num_parents, u32 rsrc_id, u8 clk_type)
{
- if (clk_cells == 2)
- return imx_clk_scu_alloc_dev(name, parents, num_parents, rsrc_id, clk_type);
- else
- return __imx_clk_scu(NULL, name, parents, num_parents, rsrc_id, clk_type);
+ return imx_clk_scu_alloc_dev(name, parents, num_parents, rsrc_id, clk_type);
}
static inline struct clk_hw *imx_clk_lpcg_scu_dev(struct device *dev, const char *name,
@@ -65,4 +74,25 @@ static inline struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *pare
return __imx_clk_lpcg_scu(NULL, name, parent_name, flags, reg,
bit_idx, hw_gate);
}
+
+static inline struct clk_hw *imx_clk_gate_gpr_scu(const char *name, const char *parent_name,
+ u32 rsrc_id, u8 gpr_id, bool invert)
+{
+ return __imx_clk_gpr_scu(name, &parent_name, 1, rsrc_id, gpr_id,
+ IMX_SCU_GPR_CLK_GATE, invert);
+}
+
+static inline struct clk_hw *imx_clk_divider_gpr_scu(const char *name, const char *parent_name,
+ u32 rsrc_id, u8 gpr_id)
+{
+ return __imx_clk_gpr_scu(name, &parent_name, 1, rsrc_id, gpr_id,
+ IMX_SCU_GPR_CLK_DIV, 0);
+}
+
+static inline struct clk_hw *imx_clk_mux_gpr_scu(const char *name, const char * const *parent_names,
+ int num_parents, u32 rsrc_id, u8 gpr_id)
+{
+ return __imx_clk_gpr_scu(name, parent_names, num_parents, rsrc_id,
+ gpr_id, IMX_SCU_GPR_CLK_MUX, 0);
+}
#endif
diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig
index 580b0cf69ed5..898f1bc478c9 100644
--- a/drivers/clk/ingenic/Kconfig
+++ b/drivers/clk/ingenic/Kconfig
@@ -25,6 +25,16 @@ config INGENIC_CGU_JZ4725B
If building for a JZ4725B SoC, you want to say Y here.
+config INGENIC_CGU_JZ4760
+ bool "Ingenic JZ4760 CGU driver"
+ default MACH_JZ4760
+ select INGENIC_CGU_COMMON
+ help
+ Support the clocks provided by the CGU hardware on Ingenic JZ4760
+ and compatible SoCs.
+
+ If building for a JZ4760 SoC, you want to say Y here.
+
config INGENIC_CGU_JZ4770
bool "Ingenic JZ4770 CGU driver"
default MACH_JZ4770
diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
index aaa4bffe03c6..9edfaf4610b9 100644
--- a/drivers/clk/ingenic/Makefile
+++ b/drivers/clk/ingenic/Makefile
@@ -2,6 +2,7 @@
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_JZ4760) += jz4760-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4770) += jz4770-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4780) += jz4780-cgu.o
obj-$(CONFIG_INGENIC_CGU_X1000) += x1000-cgu.o
diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index c8e9cb6c8e39..266c7595d330 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -99,13 +99,14 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
od_enc = ctl >> pll_info->od_shift;
od_enc &= GENMASK(pll_info->od_bits - 1, 0);
- ctl = readl(cgu->base + pll_info->bypass_reg);
+ if (pll_info->bypass_bit >= 0) {
+ ctl = readl(cgu->base + pll_info->bypass_reg);
- bypass = !pll_info->no_bypass_bit &&
- !!(ctl & BIT(pll_info->bypass_bit));
+ bypass = !!(ctl & BIT(pll_info->bypass_bit));
- if (bypass)
- return parent_rate;
+ if (bypass)
+ return parent_rate;
+ }
for (od = 0; od < pll_info->od_max; od++) {
if (pll_info->od_encoding[od] == od_enc)
@@ -118,28 +119,42 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
n * od);
}
-static unsigned long
-ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
- unsigned long rate, unsigned long parent_rate,
- unsigned *pm, unsigned *pn, unsigned *pod)
+static void
+ingenic_pll_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
+ unsigned long rate, unsigned long parent_rate,
+ unsigned int *pm, unsigned int *pn, unsigned int *pod)
{
- const struct ingenic_cgu_pll_info *pll_info;
- unsigned m, n, od;
-
- pll_info = &clk_info->pll;
- od = 1;
+ unsigned int m, n, od = 1;
/*
* The frequency after the input divider must be between 10 and 50 MHz.
* The highest divider yields the best resolution.
*/
n = parent_rate / (10 * MHZ);
- n = min_t(unsigned, n, 1 << clk_info->pll.n_bits);
- n = max_t(unsigned, n, pll_info->n_offset);
+ n = min_t(unsigned int, n, 1 << pll_info->n_bits);
+ n = max_t(unsigned int, n, pll_info->n_offset);
m = (rate / MHZ) * od * n / (parent_rate / MHZ);
- m = min_t(unsigned, m, 1 << clk_info->pll.m_bits);
- m = max_t(unsigned, m, pll_info->m_offset);
+ m = min_t(unsigned int, m, 1 << pll_info->m_bits);
+ m = max_t(unsigned int, m, pll_info->m_offset);
+
+ *pm = m;
+ *pn = n;
+ *pod = od;
+}
+
+static unsigned long
+ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
+ unsigned long rate, unsigned long parent_rate,
+ unsigned int *pm, unsigned int *pn, unsigned int *pod)
+{
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
+ unsigned int m, n, od;
+
+ if (pll_info->calc_m_n_od)
+ (*pll_info->calc_m_n_od)(pll_info, rate, parent_rate, &m, &n, &od);
+ else
+ ingenic_pll_calc_m_n_od(pll_info, rate, parent_rate, &m, &n, &od);
if (pm)
*pm = m;
@@ -225,11 +240,13 @@ static int ingenic_pll_enable(struct clk_hw *hw)
u32 ctl;
spin_lock_irqsave(&cgu->lock, flags);
- ctl = readl(cgu->base + pll_info->bypass_reg);
+ if (pll_info->bypass_bit >= 0) {
+ ctl = readl(cgu->base + pll_info->bypass_reg);
- ctl &= ~BIT(pll_info->bypass_bit);
+ ctl &= ~BIT(pll_info->bypass_bit);
- writel(ctl, cgu->base + pll_info->bypass_reg);
+ writel(ctl, cgu->base + pll_info->bypass_reg);
+ }
ctl = readl(cgu->base + pll_info->reg);
@@ -369,18 +386,23 @@ ingenic_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
struct ingenic_cgu *cgu = ingenic_clk->cgu;
unsigned long rate = parent_rate;
u32 div_reg, div;
+ u8 parent;
if (clk_info->type & CGU_CLK_DIV) {
- div_reg = readl(cgu->base + clk_info->div.reg);
- div = (div_reg >> clk_info->div.shift) &
- GENMASK(clk_info->div.bits - 1, 0);
+ parent = ingenic_clk_get_parent(hw);
- if (clk_info->div.div_table)
- div = clk_info->div.div_table[div];
- else
- div = (div + 1) * clk_info->div.div;
+ if (!(clk_info->div.bypass_mask & BIT(parent))) {
+ div_reg = readl(cgu->base + clk_info->div.reg);
+ div = (div_reg >> clk_info->div.shift) &
+ GENMASK(clk_info->div.bits - 1, 0);
- rate /= 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) {
rate /= clk_info->fixdiv.div;
}
@@ -410,10 +432,16 @@ ingenic_clk_calc_hw_div(const struct ingenic_cgu_clk_info *clk_info,
}
static unsigned
-ingenic_clk_calc_div(const struct ingenic_cgu_clk_info *clk_info,
+ingenic_clk_calc_div(struct clk_hw *hw,
+ const struct ingenic_cgu_clk_info *clk_info,
unsigned long parent_rate, unsigned long req_rate)
{
unsigned int div, hw_div;
+ u8 parent;
+
+ parent = ingenic_clk_get_parent(hw);
+ if (clk_info->div.bypass_mask & BIT(parent))
+ return 1;
/* calculate the divide */
div = DIV_ROUND_UP(parent_rate, req_rate);
@@ -448,7 +476,7 @@ ingenic_clk_round_rate(struct clk_hw *hw, unsigned long req_rate,
unsigned int div = 1;
if (clk_info->type & CGU_CLK_DIV)
- div = ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
+ div = ingenic_clk_calc_div(hw, clk_info, *parent_rate, req_rate);
else if (clk_info->type & CGU_CLK_FIXDIV)
div = clk_info->fixdiv.div;
else if (clk_hw_can_set_rate_parent(hw))
@@ -480,7 +508,7 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
int ret = 0;
if (clk_info->type & CGU_CLK_DIV) {
- div = ingenic_clk_calc_div(clk_info, parent_rate, req_rate);
+ div = ingenic_clk_calc_div(hw, clk_info, parent_rate, req_rate);
rate = DIV_ROUND_UP(parent_rate, div);
if (rate != req_rate)
diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h
index 2c75ef4a36f5..bfc2b9c38a41 100644
--- a/drivers/clk/ingenic/cgu.h
+++ b/drivers/clk/ingenic/cgu.h
@@ -39,10 +39,10 @@
* their encoded values in the PLL control register, or -1 for
* unsupported values
* @bypass_reg: the offset of the bypass control register within the CGU
- * @bypass_bit: the index of the bypass bit in the PLL control register
+ * @bypass_bit: the index of the bypass bit in the PLL control register, or
+ * -1 if there is no bypass bit
* @enable_bit: the index of the enable bit in the PLL control register
* @stable_bit: the index of the stable bit in the PLL control register
- * @no_bypass_bit: if set, the PLL has no bypass functionality
*/
struct ingenic_cgu_pll_info {
unsigned reg;
@@ -52,10 +52,12 @@ struct ingenic_cgu_pll_info {
u8 n_shift, n_bits, n_offset;
u8 od_shift, od_bits, od_max;
unsigned bypass_reg;
- u8 bypass_bit;
+ s8 bypass_bit;
u8 enable_bit;
u8 stable_bit;
- bool no_bypass_bit;
+ void (*calc_m_n_od)(const struct ingenic_cgu_pll_info *pll_info,
+ unsigned long rate, unsigned long parent_rate,
+ unsigned int *m, unsigned int *n, unsigned int *od);
};
/**
@@ -84,6 +86,7 @@ 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
+ * @bypass_mask: mask of parent clocks for which the divider does not apply
* @div_table: optional table to map the value read from the register to the
* actual divider value
*/
@@ -95,6 +98,7 @@ struct ingenic_cgu_div_info {
s8 ce_bit;
s8 busy_bit;
s8 stop_bit;
+ u8 bypass_mask;
const u8 *div_table;
};
diff --git a/drivers/clk/ingenic/jz4725b-cgu.c b/drivers/clk/ingenic/jz4725b-cgu.c
index 8c38e72d14a7..5154b0cf8ad6 100644
--- a/drivers/clk/ingenic/jz4725b-cgu.c
+++ b/drivers/clk/ingenic/jz4725b-cgu.c
@@ -80,7 +80,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
"pll half", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
.div = {
- CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1,
+ CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0,
jz4725b_cgu_pll_half_div_table,
},
},
@@ -89,7 +89,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
"cclk", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
.div = {
- CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
jz4725b_cgu_cpccr_div_table,
},
},
@@ -98,7 +98,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
"hclk", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
.div = {
- CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
jz4725b_cgu_cpccr_div_table,
},
},
@@ -107,7 +107,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
"pclk", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
.div = {
- CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
jz4725b_cgu_cpccr_div_table,
},
},
@@ -116,7 +116,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
"mclk", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
.div = {
- CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
jz4725b_cgu_cpccr_div_table,
},
},
@@ -125,7 +125,7 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
"ipu", CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
.div = {
- CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
jz4725b_cgu_cpccr_div_table,
},
.gate = { CGU_REG_CLKGR, 13 },
diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c
index c0ac9196a581..cd878f08aca3 100644
--- a/drivers/clk/ingenic/jz4740-cgu.c
+++ b/drivers/clk/ingenic/jz4740-cgu.c
@@ -95,7 +95,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
"pll half", CGU_CLK_DIV,
.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
.div = {
- CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1,
+ CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0,
jz4740_cgu_pll_half_div_table,
},
},
@@ -104,7 +104,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
"cclk", CGU_CLK_DIV,
.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
.div = {
- CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
jz4740_cgu_cpccr_div_table,
},
},
@@ -113,7 +113,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
"hclk", CGU_CLK_DIV,
.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
.div = {
- CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
jz4740_cgu_cpccr_div_table,
},
},
@@ -122,7 +122,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
"pclk", CGU_CLK_DIV,
.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
.div = {
- CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
jz4740_cgu_cpccr_div_table,
},
},
@@ -131,7 +131,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
"mclk", CGU_CLK_DIV,
.parents = { JZ4740_CLK_PLL, -1, -1, -1 },
.div = {
- CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
jz4740_cgu_cpccr_div_table,
},
},
@@ -140,7 +140,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
"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,
+ CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1, 0,
jz4740_cgu_cpccr_div_table,
},
.gate = { CGU_REG_CLKGR, 10 },
diff --git a/drivers/clk/ingenic/jz4760-cgu.c b/drivers/clk/ingenic/jz4760-cgu.c
new file mode 100644
index 000000000000..14483797a4db
--- /dev/null
+++ b/drivers/clk/ingenic/jz4760-cgu.c
@@ -0,0 +1,428 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * JZ4760 SoC CGU driver
+ * Copyright 2018, Paul Cercueil <paul@crapouillou.net>
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <linux/clk.h>
+
+#include <dt-bindings/clock/jz4760-cgu.h>
+
+#include "cgu.h"
+#include "pm.h"
+
+#define MHZ (1000 * 1000)
+
+/*
+ * CPM registers offset address definition
+ */
+#define CGU_REG_CPCCR 0x00
+#define CGU_REG_LCR 0x04
+#define CGU_REG_CPPCR0 0x10
+#define CGU_REG_CLKGR0 0x20
+#define CGU_REG_OPCR 0x24
+#define CGU_REG_CLKGR1 0x28
+#define CGU_REG_CPPCR1 0x30
+#define CGU_REG_USBPCR 0x3c
+#define CGU_REG_USBCDR 0x50
+#define CGU_REG_I2SCDR 0x60
+#define CGU_REG_LPCDR 0x64
+#define CGU_REG_MSCCDR 0x68
+#define CGU_REG_UHCCDR 0x6c
+#define CGU_REG_SSICDR 0x74
+#define CGU_REG_CIMCDR 0x7c
+#define CGU_REG_GPSCDR 0x80
+#define CGU_REG_PCMCDR 0x84
+#define CGU_REG_GPUCDR 0x88
+
+static const s8 pll_od_encoding[8] = {
+ 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
+};
+
+static const u8 jz4760_cgu_cpccr_div_table[] = {
+ 1, 2, 3, 4, 6, 8,
+};
+
+static const u8 jz4760_cgu_pll_half_div_table[] = {
+ 2, 1,
+};
+
+static void
+jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
+ unsigned long rate, unsigned long parent_rate,
+ unsigned int *pm, unsigned int *pn, unsigned int *pod)
+{
+ unsigned int m, n, od, m_max = (1 << pll_info->m_bits) - 2;
+
+ /* The frequency after the N divider must be between 1 and 50 MHz. */
+ n = parent_rate / (1 * MHZ);
+
+ /* The N divider must be >= 2. */
+ n = clamp_val(n, 2, 1 << pll_info->n_bits);
+
+ for (;; n >>= 1) {
+ od = (unsigned int)-1;
+
+ do {
+ m = (rate / MHZ) * (1 << ++od) * n / (parent_rate / MHZ);
+ } while ((m > m_max || m & 1) && (od < 4));
+
+ if (od < 4 && m >= 4 && m <= m_max)
+ break;
+ }
+
+ *pm = m;
+ *pn = n;
+ *pod = 1 << od;
+}
+
+static const struct ingenic_cgu_clk_info jz4760_cgu_clocks[] = {
+
+ /* External clocks */
+
+ [JZ4760_CLK_EXT] = { "ext", CGU_CLK_EXT },
+ [JZ4760_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
+
+ /* PLLs */
+
+ [JZ4760_CLK_PLL0] = {
+ "pll0", CGU_CLK_PLL,
+ .parents = { JZ4760_CLK_EXT },
+ .pll = {
+ .reg = CGU_REG_CPPCR0,
+ .rate_multiplier = 1,
+ .m_shift = 23,
+ .m_bits = 8,
+ .m_offset = 0,
+ .n_shift = 18,
+ .n_bits = 4,
+ .n_offset = 0,
+ .od_shift = 16,
+ .od_bits = 2,
+ .od_max = 8,
+ .od_encoding = pll_od_encoding,
+ .bypass_reg = CGU_REG_CPPCR0,
+ .bypass_bit = 9,
+ .enable_bit = 8,
+ .stable_bit = 10,
+ .calc_m_n_od = jz4760_cgu_calc_m_n_od,
+ },
+ },
+
+ [JZ4760_CLK_PLL1] = {
+ /* TODO: PLL1 can depend on PLL0 */
+ "pll1", CGU_CLK_PLL,
+ .parents = { JZ4760_CLK_EXT },
+ .pll = {
+ .reg = CGU_REG_CPPCR1,
+ .rate_multiplier = 1,
+ .m_shift = 23,
+ .m_bits = 8,
+ .m_offset = 0,
+ .n_shift = 18,
+ .n_bits = 4,
+ .n_offset = 0,
+ .od_shift = 16,
+ .od_bits = 2,
+ .od_max = 8,
+ .od_encoding = pll_od_encoding,
+ .bypass_bit = -1,
+ .enable_bit = 7,
+ .stable_bit = 6,
+ .calc_m_n_od = jz4760_cgu_calc_m_n_od,
+ },
+ },
+
+ /* Main clocks */
+
+ [JZ4760_CLK_CCLK] = {
+ "cclk", CGU_CLK_DIV,
+ .parents = { JZ4760_CLK_PLL0, },
+ .div = {
+ CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
+ jz4760_cgu_cpccr_div_table,
+ },
+ },
+ [JZ4760_CLK_HCLK] = {
+ "hclk", CGU_CLK_DIV,
+ .parents = { JZ4760_CLK_PLL0, },
+ .div = {
+ CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
+ jz4760_cgu_cpccr_div_table,
+ },
+ },
+ [JZ4760_CLK_SCLK] = {
+ "sclk", CGU_CLK_DIV,
+ .parents = { JZ4760_CLK_PLL0, },
+ .div = {
+ CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
+ jz4760_cgu_cpccr_div_table,
+ },
+ },
+ [JZ4760_CLK_H2CLK] = {
+ "h2clk", CGU_CLK_DIV,
+ .parents = { JZ4760_CLK_PLL0, },
+ .div = {
+ CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
+ jz4760_cgu_cpccr_div_table,
+ },
+ },
+ [JZ4760_CLK_MCLK] = {
+ "mclk", CGU_CLK_DIV,
+ .parents = { JZ4760_CLK_PLL0, },
+ .div = {
+ CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
+ jz4760_cgu_cpccr_div_table,
+ },
+ },
+ [JZ4760_CLK_PCLK] = {
+ "pclk", CGU_CLK_DIV,
+ .parents = { JZ4760_CLK_PLL0, },
+ .div = {
+ CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
+ jz4760_cgu_cpccr_div_table,
+ },
+ },
+
+ /* Divided clocks */
+
+ [JZ4760_CLK_PLL0_HALF] = {
+ "pll0_half", CGU_CLK_DIV,
+ .parents = { JZ4760_CLK_PLL0 },
+ .div = {
+ CGU_REG_CPCCR, 21, 1, 1, 22, -1, -1, 0,
+ jz4760_cgu_pll_half_div_table,
+ },
+ },
+
+ /* Those divided clocks can connect to PLL0 or PLL1 */
+
+ [JZ4760_CLK_UHC] = {
+ "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
+ .mux = { CGU_REG_UHCCDR, 31, 1 },
+ .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 24 },
+ },
+ [JZ4760_CLK_GPU] = {
+ "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
+ .mux = { CGU_REG_GPUCDR, 31, 1 },
+ .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR1, 9 },
+ },
+ [JZ4760_CLK_LPCLK_DIV] = {
+ "lpclk_div", CGU_CLK_DIV | CGU_CLK_MUX,
+ .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
+ .mux = { CGU_REG_LPCDR, 29, 1 },
+ .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
+ },
+ [JZ4760_CLK_TVE] = {
+ "tve", CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_EXT, },
+ .mux = { CGU_REG_LPCDR, 31, 1 },
+ .gate = { CGU_REG_CLKGR0, 27 },
+ },
+ [JZ4760_CLK_LPCLK] = {
+ "lpclk", CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_TVE, },
+ .mux = { CGU_REG_LPCDR, 30, 1 },
+ .gate = { CGU_REG_CLKGR0, 28 },
+ },
+ [JZ4760_CLK_GPS] = {
+ "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
+ .mux = { CGU_REG_GPSCDR, 31, 1 },
+ .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 22 },
+ },
+
+ /* Those divided clocks can connect to EXT, PLL0 or PLL1 */
+
+ [JZ4760_CLK_PCM] = {
+ "pcm", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4760_CLK_EXT, -1,
+ JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
+ .mux = { CGU_REG_PCMCDR, 30, 2 },
+ .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
+ .gate = { CGU_REG_CLKGR1, 8 },
+ },
+ [JZ4760_CLK_I2S] = {
+ "i2s", CGU_CLK_DIV | CGU_CLK_MUX,
+ .parents = { JZ4760_CLK_EXT, -1,
+ JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
+ .mux = { CGU_REG_I2SCDR, 30, 2 },
+ .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
+ },
+ [JZ4760_CLK_OTG] = {
+ "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
+ .parents = { JZ4760_CLK_EXT, -1,
+ JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
+ .mux = { CGU_REG_USBCDR, 30, 2 },
+ .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 2 },
+ },
+
+ /* Those divided clocks can connect to EXT or PLL0 */
+ [JZ4760_CLK_MMC_MUX] = {
+ "mmc_mux", CGU_CLK_MUX | CGU_CLK_DIV,
+ .parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
+ .mux = { CGU_REG_MSCCDR, 31, 1 },
+ .div = { CGU_REG_MSCCDR, 0, 1, 6, -1, -1, -1, BIT(0) },
+ },
+ [JZ4760_CLK_SSI_MUX] = {
+ "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
+ .parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
+ .mux = { CGU_REG_SSICDR, 31, 1 },
+ .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1, BIT(0) },
+ },
+
+ /* These divided clock can connect to PLL0 only */
+ [JZ4760_CLK_CIM] = {
+ "cim", CGU_CLK_DIV | CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_PLL0_HALF },
+ .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
+ .gate = { CGU_REG_CLKGR0, 26 },
+ },
+
+ /* Gate-only clocks */
+
+ [JZ4760_CLK_SSI0] = {
+ "ssi0", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 4 },
+ },
+ [JZ4760_CLK_SSI1] = {
+ "ssi1", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 19 },
+ },
+ [JZ4760_CLK_SSI2] = {
+ "ssi2", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_SSI_MUX, },
+ .gate = { CGU_REG_CLKGR0, 20 },
+ },
+ [JZ4760_CLK_DMA] = {
+ "dma", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_H2CLK, },
+ .gate = { CGU_REG_CLKGR0, 21 },
+ },
+ [JZ4760_CLK_I2C0] = {
+ "i2c0", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 5 },
+ },
+ [JZ4760_CLK_I2C1] = {
+ "i2c1", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 6 },
+ },
+ [JZ4760_CLK_UART0] = {
+ "uart0", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 15 },
+ },
+ [JZ4760_CLK_UART1] = {
+ "uart1", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 16 },
+ },
+ [JZ4760_CLK_UART2] = {
+ "uart2", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 17 },
+ },
+ [JZ4760_CLK_UART3] = {
+ "uart3", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 18 },
+ },
+ [JZ4760_CLK_IPU] = {
+ "ipu", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_HCLK, },
+ .gate = { CGU_REG_CLKGR0, 29 },
+ },
+ [JZ4760_CLK_ADC] = {
+ "adc", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 14 },
+ },
+ [JZ4760_CLK_AIC] = {
+ "aic", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_EXT, },
+ .gate = { CGU_REG_CLKGR0, 8 },
+ },
+ [JZ4760_CLK_VPU] = {
+ "vpu", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_HCLK, },
+ .gate = { CGU_REG_LCR, 30, false, 150 },
+ },
+ [JZ4760_CLK_MMC0] = {
+ "mmc0", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_MMC_MUX, },
+ .gate = { CGU_REG_CLKGR0, 3 },
+ },
+ [JZ4760_CLK_MMC1] = {
+ "mmc1", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_MMC_MUX, },
+ .gate = { CGU_REG_CLKGR0, 11 },
+ },
+ [JZ4760_CLK_MMC2] = {
+ "mmc2", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_MMC_MUX, },
+ .gate = { CGU_REG_CLKGR0, 12 },
+ },
+ [JZ4760_CLK_UHC_PHY] = {
+ "uhc_phy", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_UHC, },
+ .gate = { CGU_REG_OPCR, 5 },
+ },
+ [JZ4760_CLK_OTG_PHY] = {
+ "usb_phy", CGU_CLK_GATE,
+ .parents = { JZ4760_CLK_OTG },
+ .gate = { CGU_REG_OPCR, 7, true, 50 },
+ },
+
+ /* Custom clocks */
+ [JZ4760_CLK_EXT512] = {
+ "ext/512", CGU_CLK_FIXDIV,
+ .parents = { JZ4760_CLK_EXT },
+ .fixdiv = { 512 },
+ },
+ [JZ4760_CLK_RTC] = {
+ "rtc", CGU_CLK_MUX,
+ .parents = { JZ4760_CLK_EXT512, JZ4760_CLK_OSC32K, },
+ .mux = { CGU_REG_OPCR, 2, 1},
+ },
+};
+
+static void __init jz4760_cgu_init(struct device_node *np)
+{
+ struct ingenic_cgu *cgu;
+ int retval;
+
+ cgu = ingenic_cgu_new(jz4760_cgu_clocks,
+ ARRAY_SIZE(jz4760_cgu_clocks), np);
+ if (!cgu) {
+ pr_err("%s: failed to initialise CGU\n", __func__);
+ return;
+ }
+
+ retval = ingenic_cgu_register_clocks(cgu);
+ if (retval)
+ pr_err("%s: failed to register CGU Clocks\n", __func__);
+
+ ingenic_cgu_register_syscore_ops(cgu);
+}
+
+/* We only probe via devicetree, no need for a platform driver */
+CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", jz4760_cgu_init);
+
+/* JZ4760B has some small differences, but we don't implement them. */
+CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", jz4760_cgu_init);
diff --git a/drivers/clk/ingenic/jz4770-cgu.c b/drivers/clk/ingenic/jz4770-cgu.c
index 9ea4490ecb7f..2321742b3471 100644
--- a/drivers/clk/ingenic/jz4770-cgu.c
+++ b/drivers/clk/ingenic/jz4770-cgu.c
@@ -139,8 +139,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
.od_bits = 2,
.od_max = 8,
.od_encoding = pll_od_encoding,
- .bypass_reg = CGU_REG_CPPCR1,
- .no_bypass_bit = true,
+ .bypass_bit = -1,
.enable_bit = 7,
.stable_bit = 6,
},
@@ -152,7 +151,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
"cclk", CGU_CLK_DIV,
.parents = { JZ4770_CLK_PLL0, },
.div = {
- CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
jz4770_cgu_cpccr_div_table,
},
},
@@ -160,7 +159,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
"h0clk", CGU_CLK_DIV,
.parents = { JZ4770_CLK_PLL0, },
.div = {
- CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
jz4770_cgu_cpccr_div_table,
},
},
@@ -168,7 +167,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
"h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4770_CLK_PLL0, },
.div = {
- CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
jz4770_cgu_cpccr_div_table,
},
.gate = { CGU_REG_CLKGR1, 7 },
@@ -177,7 +176,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
"h2clk", CGU_CLK_DIV,
.parents = { JZ4770_CLK_PLL0, },
.div = {
- CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
jz4770_cgu_cpccr_div_table,
},
},
@@ -185,7 +184,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
"c1clk", CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4770_CLK_PLL0, },
.div = {
- CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
jz4770_cgu_cpccr_div_table,
},
.gate = { CGU_REG_OPCR, 31, true }, // disable CCLK stop on idle
@@ -194,7 +193,7 @@ static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
"pclk", CGU_CLK_DIV,
.parents = { JZ4770_CLK_PLL0, },
.div = {
- CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
+ CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
jz4770_cgu_cpccr_div_table,
},
},
diff --git a/drivers/clk/ingenic/tcu.c b/drivers/clk/ingenic/tcu.c
index 9382dc3aa27e..77acfbeb4830 100644
--- a/drivers/clk/ingenic/tcu.c
+++ b/drivers/clk/ingenic/tcu.c
@@ -326,6 +326,7 @@ static const struct ingenic_soc_info x1000_soc_info = {
static const struct of_device_id __maybe_unused ingenic_tcu_of_match[] __initconst = {
{ .compatible = "ingenic,jz4740-tcu", .data = &jz4740_soc_info, },
{ .compatible = "ingenic,jz4725b-tcu", .data = &jz4725b_soc_info, },
+ { .compatible = "ingenic,jz4760-tcu", .data = &jz4770_soc_info, },
{ .compatible = "ingenic,jz4770-tcu", .data = &jz4770_soc_info, },
{ .compatible = "ingenic,x1000-tcu", .data = &x1000_soc_info, },
{ /* sentinel */ }
@@ -477,5 +478,6 @@ static void __init ingenic_tcu_init(struct device_node *np)
CLK_OF_DECLARE_DRIVER(jz4740_cgu, "ingenic,jz4740-tcu", ingenic_tcu_init);
CLK_OF_DECLARE_DRIVER(jz4725b_cgu, "ingenic,jz4725b-tcu", ingenic_tcu_init);
+CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-tcu", ingenic_tcu_init);
CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-tcu", ingenic_tcu_init);
CLK_OF_DECLARE_DRIVER(x1000_cgu, "ingenic,x1000-tcu", ingenic_tcu_init);
diff --git a/drivers/clk/keystone/syscon-clk.c b/drivers/clk/keystone/syscon-clk.c
index 5b3d36462174..aae1a4076281 100644
--- a/drivers/clk/keystone/syscon-clk.c
+++ b/drivers/clk/keystone/syscon-clk.c
@@ -149,11 +149,28 @@ static const struct ti_syscon_gate_clk_data am654_clk_data[] = {
{ /* Sentinel */ },
};
+static const struct ti_syscon_gate_clk_data am64_clk_data[] = {
+ TI_SYSCON_CLK_GATE("epwm_tbclk0", 0x0, 0),
+ TI_SYSCON_CLK_GATE("epwm_tbclk1", 0x0, 1),
+ TI_SYSCON_CLK_GATE("epwm_tbclk2", 0x0, 2),
+ TI_SYSCON_CLK_GATE("epwm_tbclk3", 0x0, 3),
+ TI_SYSCON_CLK_GATE("epwm_tbclk4", 0x0, 4),
+ TI_SYSCON_CLK_GATE("epwm_tbclk5", 0x0, 5),
+ TI_SYSCON_CLK_GATE("epwm_tbclk6", 0x0, 6),
+ TI_SYSCON_CLK_GATE("epwm_tbclk7", 0x0, 7),
+ TI_SYSCON_CLK_GATE("epwm_tbclk8", 0x0, 8),
+ { /* Sentinel */ },
+};
+
static const struct of_device_id ti_syscon_gate_clk_ids[] = {
{
.compatible = "ti,am654-ehrpwm-tbclk",
.data = &am654_clk_data,
},
+ {
+ .compatible = "ti,am64-epwm-tbclk",
+ .data = &am64_clk_data,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, ti_syscon_gate_clk_ids);
diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c
index 7c8d02164443..bfe36bd41339 100644
--- a/drivers/clk/meson/axg-audio.c
+++ b/drivers/clk/meson/axg-audio.c
@@ -1665,8 +1665,7 @@ static int devm_clk_get_enable(struct device *dev, char *id)
clk = devm_clk_get(dev, id);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "failed to get %s", id);
+ dev_err_probe(dev, ret, "failed to get %s", id);
return ret;
}
@@ -1811,7 +1810,7 @@ static int axg_audio_clkc_probe(struct platform_device *pdev)
ret = device_reset(dev);
if (ret) {
- dev_err(dev, "failed to reset device\n");
+ dev_err_probe(dev, ret, "failed to reset device\n");
return ret;
}
diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c
index 49f27fe53213..9e55617bc3b4 100644
--- a/drivers/clk/meson/clk-pll.c
+++ b/drivers/clk/meson/clk-pll.c
@@ -242,8 +242,8 @@ static int meson_clk_get_pll_settings(unsigned long rate,
return best ? 0 : -EINVAL;
}
-static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int meson_clk_pll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
@@ -251,22 +251,26 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long round;
int ret;
- ret = meson_clk_get_pll_settings(rate, *parent_rate, &m, &n, pll);
+ ret = meson_clk_get_pll_settings(req->rate, req->best_parent_rate,
+ &m, &n, pll);
if (ret)
- return meson_clk_pll_recalc_rate(hw, *parent_rate);
+ return ret;
- round = __pll_params_to_rate(*parent_rate, m, n, 0, pll);
+ round = __pll_params_to_rate(req->best_parent_rate, m, n, 0, pll);
- if (!MESON_PARM_APPLICABLE(&pll->frac) || rate == round)
- return round;
+ if (!MESON_PARM_APPLICABLE(&pll->frac) || req->rate == round) {
+ req->rate = round;
+ return 0;
+ }
/*
* The rate provided by the setting is not an exact match, let's
* try to improve the result using the fractional parameter
*/
- frac = __pll_params_with_frac(rate, *parent_rate, m, n, pll);
+ frac = __pll_params_with_frac(req->rate, req->best_parent_rate, m, n, pll);
+ req->rate = __pll_params_to_rate(req->best_parent_rate, m, n, frac, pll);
- return __pll_params_to_rate(*parent_rate, m, n, frac, pll);
+ return 0;
}
static int meson_clk_pll_wait_lock(struct clk_hw *hw)
@@ -419,7 +423,7 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
*/
const struct clk_ops meson_clk_pcie_pll_ops = {
.recalc_rate = meson_clk_pll_recalc_rate,
- .round_rate = meson_clk_pll_round_rate,
+ .determine_rate = meson_clk_pll_determine_rate,
.is_enabled = meson_clk_pll_is_enabled,
.enable = meson_clk_pcie_pll_enable,
.disable = meson_clk_pll_disable
@@ -429,7 +433,7 @@ EXPORT_SYMBOL_GPL(meson_clk_pcie_pll_ops);
const struct clk_ops meson_clk_pll_ops = {
.init = meson_clk_pll_init,
.recalc_rate = meson_clk_pll_recalc_rate,
- .round_rate = meson_clk_pll_round_rate,
+ .determine_rate = meson_clk_pll_determine_rate,
.set_rate = meson_clk_pll_set_rate,
.is_enabled = meson_clk_pll_is_enabled,
.enable = meson_clk_pll_enable,
diff --git a/drivers/clk/meson/clk-regmap.c b/drivers/clk/meson/clk-regmap.c
index dcd1757cc5df..8ad8977cf1c2 100644
--- a/drivers/clk/meson/clk-regmap.c
+++ b/drivers/clk/meson/clk-regmap.c
@@ -75,8 +75,8 @@ static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw,
div->width);
}
-static long clk_regmap_div_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int clk_regmap_div_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk);
@@ -87,18 +87,17 @@ static long clk_regmap_div_round_rate(struct clk_hw *hw, unsigned long rate,
if (div->flags & CLK_DIVIDER_READ_ONLY) {
ret = regmap_read(clk->map, div->offset, &val);
if (ret)
- /* Gives a hint that something is wrong */
- return 0;
+ return ret;
val >>= div->shift;
val &= clk_div_mask(div->width);
- return divider_ro_round_rate(hw, rate, prate, div->table,
- div->width, div->flags, val);
+ return divider_ro_determine_rate(hw, req, div->table,
+ div->width, div->flags, val);
}
- return divider_round_rate(hw, rate, prate, div->table, div->width,
- div->flags);
+ return divider_determine_rate(hw, req, div->table, div->width,
+ div->flags);
}
static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -123,14 +122,14 @@ static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops clk_regmap_divider_ops = {
.recalc_rate = clk_regmap_div_recalc_rate,
- .round_rate = clk_regmap_div_round_rate,
+ .determine_rate = clk_regmap_div_determine_rate,
.set_rate = clk_regmap_div_set_rate,
};
EXPORT_SYMBOL_GPL(clk_regmap_divider_ops);
const struct clk_ops clk_regmap_divider_ro_ops = {
.recalc_rate = clk_regmap_div_recalc_rate,
- .round_rate = clk_regmap_div_round_rate,
+ .determine_rate = clk_regmap_div_determine_rate,
};
EXPORT_SYMBOL_GPL(clk_regmap_divider_ro_ops);
diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c
index b080359b4645..310accf94830 100644
--- a/drivers/clk/meson/g12a.c
+++ b/drivers/clk/meson/g12a.c
@@ -1603,7 +1603,7 @@ static struct clk_regmap g12b_cpub_clk_trace = {
};
static const struct pll_mult_range g12a_gp0_pll_mult_range = {
- .min = 55,
+ .min = 125,
.max = 255,
};
@@ -4723,6 +4723,12 @@ static struct clk_hw_onecell_data g12b_hw_onecell_data = {
[CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw,
[CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw,
[CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw,
+ [CLKID_NNA_AXI_CLK_SEL] = &sm1_nna_axi_clk_sel.hw,
+ [CLKID_NNA_AXI_CLK_DIV] = &sm1_nna_axi_clk_div.hw,
+ [CLKID_NNA_AXI_CLK] = &sm1_nna_axi_clk.hw,
+ [CLKID_NNA_CORE_CLK_SEL] = &sm1_nna_core_clk_sel.hw,
+ [CLKID_NNA_CORE_CLK_DIV] = &sm1_nna_core_clk_div.hw,
+ [CLKID_NNA_CORE_CLK] = &sm1_nna_core_clk.hw,
[CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw,
[CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw,
[CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw,
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 45646b867cdb..62e00e15495c 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -210,6 +210,13 @@ config MSM_LCC_8960
Say Y if you want to use audio devices such as i2s, pcm,
SLIMBus, etc.
+config MDM_GCC_9607
+ tristate "MDM9607 Global Clock Controller"
+ help
+ Support for the global clock controller on mdm9607 devices.
+ Say Y if you want to use peripheral devices such as UART, SPI,
+ I2C, USB, SD/eMMC, etc.
+
config MDM_GCC_9615
tristate "MDM9615 Global Clock Controller"
help
@@ -483,6 +490,13 @@ config SDX_GCC_55
Say Y if you want to use peripheral devices such as UART,
SPI, I2C, USB, SD/UFS, PCIe etc.
+config SM_CAMCC_8250
+ tristate "SM8250 Camera Clock Controller"
+ select SM_GCC_8250
+ help
+ Support for the camera clock controller on SM8250 devices.
+ Say Y if you want to support camera devices and camera functionality.
+
config SM_DISPCC_8250
tristate "SM8150 and SM8250 Display Clock Controller"
depends on SM_GCC_8150 || SM_GCC_8250
@@ -492,6 +506,13 @@ config SM_DISPCC_8250
Say Y if you want to support display devices and functionality such as
splash screen.
+config SM_GCC_6125
+ tristate "SM6125 Global Clock Controller"
+ help
+ Support for the global clock controller on SM6125 devices.
+ Say Y if you want to use peripheral devices such as UART,
+ SPI, I2C, USB, SD/UFS, PCIe etc.
+
config SM_GCC_8150
tristate "SM8150 Global Clock Controller"
help
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index c8291312e723..c2a1cafb31bc 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_IPQ_GCC_6018) += gcc-ipq6018.o
obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o
obj-$(CONFIG_IPQ_GCC_8074) += gcc-ipq8074.o
obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o
+obj-$(CONFIG_MDM_GCC_9607) += gcc-mdm9607.o
obj-$(CONFIG_MDM_GCC_9615) += gcc-mdm9615.o
obj-$(CONFIG_MDM_LCC_9615) += lcc-mdm9615.o
obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o
@@ -73,7 +74,9 @@ obj-$(CONFIG_SDM_GPUCC_845) += gpucc-sdm845.o
obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o
obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
obj-$(CONFIG_SDX_GCC_55) += gcc-sdx55.o
+obj-$(CONFIG_SM_CAMCC_8250) += camcc-sm8250.o
obj-$(CONFIG_SM_DISPCC_8250) += dispcc-sm8250.o
+obj-$(CONFIG_SM_GCC_6125) += gcc-sm6125.o
obj-$(CONFIG_SM_GCC_8150) += gcc-sm8150.o
obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o
obj-$(CONFIG_SM_GCC_8350) += gcc-sm8350.o
diff --git a/drivers/clk/qcom/apcs-sdx55.c b/drivers/clk/qcom/apcs-sdx55.c
index d0edabebf9c2..e599f862ec44 100644
--- a/drivers/clk/qcom/apcs-sdx55.c
+++ b/drivers/clk/qcom/apcs-sdx55.c
@@ -57,7 +57,7 @@ static int qcom_apcs_sdx55_clk_probe(struct platform_device *pdev)
regmap = dev_get_regmap(parent, NULL);
if (!regmap) {
- dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n");
+ dev_err(dev, "Failed to get parent regmap\n");
return -ENODEV;
}
@@ -80,19 +80,15 @@ static int qcom_apcs_sdx55_clk_probe(struct platform_device *pdev)
a7cc->parent_map = apcs_mux_clk_parent_map;
a7cc->pclk = devm_clk_get(parent, "pll");
- if (IS_ERR(a7cc->pclk)) {
- ret = PTR_ERR(a7cc->pclk);
- if (ret != -EPROBE_DEFER)
- dev_err_probe(dev, ret, "Failed to get PLL clk\n");
- return ret;
- }
+ if (IS_ERR(a7cc->pclk))
+ return dev_err_probe(dev, PTR_ERR(a7cc->pclk),
+ "Failed to get PLL clk\n");
a7cc->clk_nb.notifier_call = a7cc_notifier_cb;
ret = clk_notifier_register(a7cc->pclk, &a7cc->clk_nb);
- if (ret) {
- dev_err_probe(dev, ret, "Failed to register clock notifier\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to register clock notifier\n");
ret = devm_clk_register_regmap(dev, &a7cc->clkr);
if (ret) {
diff --git a/drivers/clk/qcom/camcc-sm8250.c b/drivers/clk/qcom/camcc-sm8250.c
new file mode 100644
index 000000000000..439eaafdcc86
--- /dev/null
+++ b/drivers/clk/qcom/camcc-sm8250.c
@@ -0,0 +1,2456 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/clock/qcom,camcc-sm8250.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap-divider.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+ P_BI_TCXO,
+ P_CAM_CC_PLL0_OUT_EVEN,
+ P_CAM_CC_PLL0_OUT_MAIN,
+ P_CAM_CC_PLL0_OUT_ODD,
+ P_CAM_CC_PLL1_OUT_EVEN,
+ P_CAM_CC_PLL2_OUT_EARLY,
+ P_CAM_CC_PLL2_OUT_MAIN,
+ P_CAM_CC_PLL3_OUT_EVEN,
+ P_CAM_CC_PLL4_OUT_EVEN,
+ P_SLEEP_CLK,
+};
+
+static struct pll_vco lucid_vco[] = {
+ { 249600000, 2000000000, 0 },
+};
+
+static struct pll_vco zonda_vco[] = {
+ { 595200000UL, 3600000000UL, 0 },
+};
+
+static const struct alpha_pll_config cam_cc_pll0_config = {
+ .l = 0x3e,
+ .alpha = 0x8000,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002261,
+ .config_ctl_hi1_val = 0x329A699c,
+ .user_ctl_val = 0x00003100,
+ .user_ctl_hi_val = 0x00000805,
+ .user_ctl_hi1_val = 0x00000000,
+};
+
+static struct clk_alpha_pll cam_cc_pll0 = {
+ .offset = 0x0,
+ .vco_table = lucid_vco,
+ .num_vco = ARRAY_SIZE(lucid_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll0",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "bi_tcxo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll0_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll0_out_even = {
+ .offset = 0x0,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_cam_cc_pll0_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll0_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll0_out_even",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_pll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ops,
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll0_out_odd[] = {
+ { 0x3, 3 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll0_out_odd = {
+ .offset = 0x0,
+ .post_div_shift = 12,
+ .post_div_table = post_div_table_cam_cc_pll0_out_odd,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll0_out_odd),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll0_out_odd",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_pll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ops,
+ },
+};
+
+static const struct alpha_pll_config cam_cc_pll1_config = {
+ .l = 0x1f,
+ .alpha = 0x4000,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002261,
+ .config_ctl_hi1_val = 0x329A699c,
+ .user_ctl_val = 0x00000100,
+ .user_ctl_hi_val = 0x00000805,
+ .user_ctl_hi1_val = 0x00000000,
+};
+
+static struct clk_alpha_pll cam_cc_pll1 = {
+ .offset = 0x1000,
+ .vco_table = lucid_vco,
+ .num_vco = ARRAY_SIZE(lucid_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll1",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "bi_tcxo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll1_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll1_out_even = {
+ .offset = 0x1000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_cam_cc_pll1_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll1_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll1_out_even",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_pll1.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ops,
+ },
+};
+
+static const struct alpha_pll_config cam_cc_pll2_config = {
+ .l = 0x4b,
+ .alpha = 0x0,
+ .config_ctl_val = 0x08200920,
+ .config_ctl_hi_val = 0x05002015,
+ .config_ctl_hi1_val = 0x00000000,
+ .user_ctl_val = 0x00000100,
+ .user_ctl_hi_val = 0x00000000,
+ .user_ctl_hi1_val = 0x00000000,
+};
+
+static struct clk_alpha_pll cam_cc_pll2 = {
+ .offset = 0x2000,
+ .vco_table = zonda_vco,
+ .num_vco = ARRAY_SIZE(zonda_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_ZONDA],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll2",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "bi_tcxo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_zonda_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll2_out_main[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll2_out_main = {
+ .offset = 0x2000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_cam_cc_pll2_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll2_out_main),
+ .width = 2,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_ZONDA],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll2_out_main",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_pll2.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_zonda_ops,
+ },
+};
+
+static const struct alpha_pll_config cam_cc_pll3_config = {
+ .l = 0x24,
+ .alpha = 0x7555,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002261,
+ .config_ctl_hi1_val = 0x329A699c,
+ .user_ctl_val = 0x00000100,
+ .user_ctl_hi_val = 0x00000805,
+ .user_ctl_hi1_val = 0x00000000,
+};
+
+static struct clk_alpha_pll cam_cc_pll3 = {
+ .offset = 0x3000,
+ .vco_table = lucid_vco,
+ .num_vco = ARRAY_SIZE(lucid_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll3",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "bi_tcxo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll3_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll3_out_even = {
+ .offset = 0x3000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_cam_cc_pll3_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll3_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll3_out_even",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_pll3.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ops,
+ },
+};
+
+static const struct alpha_pll_config cam_cc_pll4_config = {
+ .l = 0x24,
+ .alpha = 0x7555,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002261,
+ .config_ctl_hi1_val = 0x329A699c,
+ .user_ctl_val = 0x00000100,
+ .user_ctl_hi_val = 0x00000805,
+ .user_ctl_hi1_val = 0x00000000,
+};
+
+static struct clk_alpha_pll cam_cc_pll4 = {
+ .offset = 0x4000,
+ .vco_table = lucid_vco,
+ .num_vco = ARRAY_SIZE(lucid_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll4",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "bi_tcxo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll4_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll4_out_even = {
+ .offset = 0x4000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_cam_cc_pll4_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll4_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_pll4_out_even",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_pll4.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ops,
+ },
+};
+
+static const struct parent_map cam_cc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL0_OUT_MAIN, 1 },
+ { P_CAM_CC_PLL0_OUT_EVEN, 2 },
+ { P_CAM_CC_PLL0_OUT_ODD, 3 },
+ { P_CAM_CC_PLL2_OUT_MAIN, 5 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_0[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &cam_cc_pll0.clkr.hw },
+ { .hw = &cam_cc_pll0_out_even.clkr.hw },
+ { .hw = &cam_cc_pll0_out_odd.clkr.hw },
+ { .hw = &cam_cc_pll2_out_main.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL2_OUT_EARLY, 5 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_1[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &cam_cc_pll2.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL3_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_2[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &cam_cc_pll3_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL4_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_3[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &cam_cc_pll4_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_4[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL1_OUT_EVEN, 4 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_4[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &cam_cc_pll1_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_5[] = {
+ { P_SLEEP_CLK, 0 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_5[] = {
+ { .fw_name = "sleep_clk" },
+};
+
+static const struct parent_map cam_cc_parent_map_6[] = {
+ { P_BI_TCXO, 0 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_6[] = {
+ { .fw_name = "bi_tcxo" },
+};
+
+static const struct freq_tbl ftbl_cam_cc_bps_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0),
+ F(200000000, P_CAM_CC_PLL0_OUT_ODD, 2, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ F(480000000, P_CAM_CC_PLL2_OUT_MAIN, 1.5, 0, 0),
+ F(600000000, P_CAM_CC_PLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_bps_clk_src = {
+ .cmd_rcgr = 0x7010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_bps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_bps_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_camnoc_axi_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_camnoc_axi_clk_src = {
+ .cmd_rcgr = 0xc0f8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_camnoc_axi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_camnoc_axi_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_cci_0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(37500000, P_CAM_CC_PLL0_OUT_EVEN, 16, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_cci_0_clk_src = {
+ .cmd_rcgr = 0xc0bc,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_cci_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_cci_0_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_cci_1_clk_src = {
+ .cmd_rcgr = 0xc0d8,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_cci_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_cci_1_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_cphy_rx_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_cphy_rx_clk_src = {
+ .cmd_rcgr = 0xa068,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_cphy_rx_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_csi0phytimer_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_csi0phytimer_clk_src = {
+ .cmd_rcgr = 0x6000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi0phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi1phytimer_clk_src = {
+ .cmd_rcgr = 0x6020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi1phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi2phytimer_clk_src = {
+ .cmd_rcgr = 0x6040,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi2phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = {
+ .cmd_rcgr = 0x6060,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi3phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi4phytimer_clk_src = {
+ .cmd_rcgr = 0x6080,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi4phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi5phytimer_clk_src = {
+ .cmd_rcgr = 0x60a0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi5phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_fast_ahb_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(50000000, P_CAM_CC_PLL0_OUT_EVEN, 12, 0, 0),
+ F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0),
+ F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0),
+ F(300000000, P_CAM_CC_PLL0_OUT_MAIN, 4, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_fast_ahb_clk_src = {
+ .cmd_rcgr = 0x703c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_fast_ahb_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_fast_ahb_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_fd_core_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ F(480000000, P_CAM_CC_PLL2_OUT_MAIN, 1.5, 0, 0),
+ F(600000000, P_CAM_CC_PLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_fd_core_clk_src = {
+ .cmd_rcgr = 0xc098,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_fd_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_fd_core_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_icp_clk_src = {
+ .cmd_rcgr = 0xc074,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_fd_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_icp_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ife_0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(350000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(475000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(576000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(680000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_ife_0_clk_src = {
+ .cmd_rcgr = 0xa010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_2,
+ .freq_tbl = ftbl_cam_cc_ife_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_0_clk_src",
+ .parent_data = cam_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_regmap_div cam_cc_sbi_div_clk_src = {
+ .reg = 0x9010,
+ .shift = 0,
+ .width = 3,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "cam_cc_sbi_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_ife_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ife_0_csid_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(75000000, P_CAM_CC_PLL0_OUT_EVEN, 8, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_ife_0_csid_clk_src = {
+ .cmd_rcgr = 0xa040,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_ife_0_csid_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_0_csid_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ife_1_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(350000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0),
+ F(475000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0),
+ F(576000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0),
+ F(680000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_ife_1_clk_src = {
+ .cmd_rcgr = 0xb010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_3,
+ .freq_tbl = ftbl_cam_cc_ife_1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_clk_src",
+ .parent_data = cam_cc_parent_data_3,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_ife_1_csid_clk_src = {
+ .cmd_rcgr = 0xb040,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_ife_0_csid_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_csid_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ife_lite_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ F(480000000, P_CAM_CC_PLL2_OUT_MAIN, 1.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_ife_lite_clk_src = {
+ .cmd_rcgr = 0xc000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_ife_lite_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_lite_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = {
+ .cmd_rcgr = 0xc01c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_lite_csid_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ipe_0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(300000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(475000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(525000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(700000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_ipe_0_clk_src = {
+ .cmd_rcgr = 0x8010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_4,
+ .freq_tbl = ftbl_cam_cc_ipe_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ipe_0_clk_src",
+ .parent_data = cam_cc_parent_data_4,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_jpeg_clk_src = {
+ .cmd_rcgr = 0xc048,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_bps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_jpeg_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_mclk0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(24000000, P_CAM_CC_PLL2_OUT_EARLY, 10, 1, 6),
+ F(68571429, P_CAM_CC_PLL2_OUT_EARLY, 1, 1, 21),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_mclk0_clk_src = {
+ .cmd_rcgr = 0x5000,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk0_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk1_clk_src = {
+ .cmd_rcgr = 0x501c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk1_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk2_clk_src = {
+ .cmd_rcgr = 0x5038,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk2_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk3_clk_src = {
+ .cmd_rcgr = 0x5054,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk3_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk4_clk_src = {
+ .cmd_rcgr = 0x5070,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk4_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk5_clk_src = {
+ .cmd_rcgr = 0x508c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk5_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk6_clk_src = {
+ .cmd_rcgr = 0x50a8,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk6_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_sbi_csid_clk_src = {
+ .cmd_rcgr = 0x901c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_sbi_csid_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_sleep_clk_src[] = {
+ F(32768, P_SLEEP_CLK, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_sleep_clk_src = {
+ .cmd_rcgr = 0xc170,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_5,
+ .freq_tbl = ftbl_cam_cc_sleep_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_sleep_clk_src",
+ .parent_data = cam_cc_parent_data_5,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_slow_ahb_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(80000000, P_CAM_CC_PLL0_OUT_EVEN, 7.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_slow_ahb_clk_src = {
+ .cmd_rcgr = 0x7058,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_slow_ahb_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_slow_ahb_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_xo_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_xo_clk_src = {
+ .cmd_rcgr = 0xc154,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_6,
+ .freq_tbl = ftbl_cam_cc_xo_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cam_cc_xo_clk_src",
+ .parent_data = cam_cc_parent_data_6,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_6),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_branch cam_cc_bps_ahb_clk = {
+ .halt_reg = 0x7070,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7070,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_bps_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_slow_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_bps_areg_clk = {
+ .halt_reg = 0x7054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_bps_areg_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_fast_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_bps_axi_clk = {
+ .halt_reg = 0x7038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_bps_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_camnoc_axi_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_bps_clk = {
+ .halt_reg = 0x7028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_bps_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_bps_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_axi_clk = {
+ .halt_reg = 0xc114,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc114,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_camnoc_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_camnoc_axi_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_dcd_xo_clk = {
+ .halt_reg = 0xc11c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc11c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_camnoc_dcd_xo_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_xo_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cci_0_clk = {
+ .halt_reg = 0xc0d4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc0d4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_cci_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_cci_0_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cci_1_clk = {
+ .halt_reg = 0xc0f0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc0f0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_cci_1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_cci_1_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_core_ahb_clk = {
+ .halt_reg = 0xc150,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0xc150,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_core_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_slow_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cpas_ahb_clk = {
+ .halt_reg = 0xc0f4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc0f4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_cpas_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_slow_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi0phytimer_clk = {
+ .halt_reg = 0x6018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi0phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_csi0phytimer_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi1phytimer_clk = {
+ .halt_reg = 0x6038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi1phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_csi1phytimer_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi2phytimer_clk = {
+ .halt_reg = 0x6058,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6058,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi2phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_csi2phytimer_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi3phytimer_clk = {
+ .halt_reg = 0x6078,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6078,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi3phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_csi3phytimer_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi4phytimer_clk = {
+ .halt_reg = 0x6098,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6098,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi4phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_csi4phytimer_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi5phytimer_clk = {
+ .halt_reg = 0x60b8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x60b8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csi5phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_csi5phytimer_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy0_clk = {
+ .halt_reg = 0x601c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x601c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csiphy0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy1_clk = {
+ .halt_reg = 0x603c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x603c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csiphy1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy2_clk = {
+ .halt_reg = 0x605c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x605c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csiphy2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy3_clk = {
+ .halt_reg = 0x607c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x607c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csiphy3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy4_clk = {
+ .halt_reg = 0x609c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x609c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csiphy4_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy5_clk = {
+ .halt_reg = 0x60bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x60bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_csiphy5_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_fd_core_clk = {
+ .halt_reg = 0xc0b0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc0b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_fd_core_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_fd_core_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_fd_core_uar_clk = {
+ .halt_reg = 0xc0b8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc0b8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_fd_core_uar_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_fd_core_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_gdsc_clk = {
+ .halt_reg = 0xc16c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc16c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_gdsc_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_xo_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_icp_ahb_clk = {
+ .halt_reg = 0xc094,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc094,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_icp_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_slow_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_icp_clk = {
+ .halt_reg = 0xc08c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc08c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_icp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_icp_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_0_ahb_clk = {
+ .halt_reg = 0xa088,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa088,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_0_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_slow_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_0_areg_clk = {
+ .halt_reg = 0xa030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa030,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_0_areg_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_fast_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_0_axi_clk = {
+ .halt_reg = 0xa084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa084,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_0_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_camnoc_axi_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_0_clk = {
+ .halt_reg = 0xa028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_ife_0_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_0_cphy_rx_clk = {
+ .halt_reg = 0xa080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa080,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_0_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_0_csid_clk = {
+ .halt_reg = 0xa058,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa058,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_0_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_ife_0_csid_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_0_dsp_clk = {
+ .halt_reg = 0xa03c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa03c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_0_dsp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_ife_0_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_1_ahb_clk = {
+ .halt_reg = 0xb068,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb068,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_slow_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_1_areg_clk = {
+ .halt_reg = 0xb030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb030,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_areg_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_fast_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_1_axi_clk = {
+ .halt_reg = 0xb064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb064,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_camnoc_axi_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_1_clk = {
+ .halt_reg = 0xb028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_ife_1_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_1_cphy_rx_clk = {
+ .halt_reg = 0xb060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb060,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_1_csid_clk = {
+ .halt_reg = 0xb058,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb058,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_ife_1_csid_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_1_dsp_clk = {
+ .halt_reg = 0xb03c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb03c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_1_dsp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_ife_1_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_ahb_clk = {
+ .halt_reg = 0xc040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_lite_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_slow_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_axi_clk = {
+ .halt_reg = 0xc044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_lite_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_camnoc_axi_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_clk = {
+ .halt_reg = 0xc018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_lite_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_ife_lite_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_cphy_rx_clk = {
+ .halt_reg = 0xc03c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc03c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_lite_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_csid_clk = {
+ .halt_reg = 0xc034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ife_lite_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_ife_lite_csid_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_0_ahb_clk = {
+ .halt_reg = 0x8040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ipe_0_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_slow_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_0_areg_clk = {
+ .halt_reg = 0x803c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x803c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ipe_0_areg_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_fast_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_0_axi_clk = {
+ .halt_reg = 0x8038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ipe_0_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_camnoc_axi_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_0_clk = {
+ .halt_reg = 0x8028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_ipe_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_ipe_0_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_jpeg_clk = {
+ .halt_reg = 0xc060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc060,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_jpeg_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_jpeg_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk0_clk = {
+ .halt_reg = 0x5018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_mclk0_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk1_clk = {
+ .halt_reg = 0x5034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_mclk1_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk2_clk = {
+ .halt_reg = 0x5050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5050,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_mclk2_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk3_clk = {
+ .halt_reg = 0x506c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x506c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_mclk3_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk4_clk = {
+ .halt_reg = 0x5088,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5088,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk4_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_mclk4_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk5_clk = {
+ .halt_reg = 0x50a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x50a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk5_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_mclk5_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk6_clk = {
+ .halt_reg = 0x50c0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x50c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_mclk6_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_mclk6_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_sbi_ahb_clk = {
+ .halt_reg = 0x9040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_sbi_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_slow_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_sbi_axi_clk = {
+ .halt_reg = 0x903c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x903c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_sbi_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_camnoc_axi_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_sbi_clk = {
+ .halt_reg = 0x9014,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_sbi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_sbi_div_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_sbi_cphy_rx_clk = {
+ .halt_reg = 0x9038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_sbi_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_sbi_csid_clk = {
+ .halt_reg = 0x9034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_sbi_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_sbi_csid_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_sbi_ife_0_clk = {
+ .halt_reg = 0x9044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_sbi_ife_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_ife_0_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_sbi_ife_1_clk = {
+ .halt_reg = 0x9048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9048,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_sbi_ife_1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_ife_1_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_sleep_clk = {
+ .halt_reg = 0xc188,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc188,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "cam_cc_sleep_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &cam_cc_sleep_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc bps_gdsc = {
+ .gdscr = 0x7004,
+ .pd = {
+ .name = "bps_gdsc",
+ },
+ .flags = HW_CTRL | POLL_CFG_GDSCR,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ipe_0_gdsc = {
+ .gdscr = 0x8004,
+ .pd = {
+ .name = "ipe_0_gdsc",
+ },
+ .flags = HW_CTRL | POLL_CFG_GDSCR,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc sbi_gdsc = {
+ .gdscr = 0x9004,
+ .pd = {
+ .name = "sbi_gdsc",
+ },
+ .flags = HW_CTRL | POLL_CFG_GDSCR,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ife_0_gdsc = {
+ .gdscr = 0xa004,
+ .pd = {
+ .name = "ife_0_gdsc",
+ },
+ .flags = POLL_CFG_GDSCR,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ife_1_gdsc = {
+ .gdscr = 0xb004,
+ .pd = {
+ .name = "ife_1_gdsc",
+ },
+ .flags = POLL_CFG_GDSCR,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc titan_top_gdsc = {
+ .gdscr = 0xc144,
+ .pd = {
+ .name = "titan_top_gdsc",
+ },
+ .flags = POLL_CFG_GDSCR,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct clk_regmap *cam_cc_sm8250_clocks[] = {
+ [CAM_CC_BPS_AHB_CLK] = &cam_cc_bps_ahb_clk.clkr,
+ [CAM_CC_BPS_AREG_CLK] = &cam_cc_bps_areg_clk.clkr,
+ [CAM_CC_BPS_AXI_CLK] = &cam_cc_bps_axi_clk.clkr,
+ [CAM_CC_BPS_CLK] = &cam_cc_bps_clk.clkr,
+ [CAM_CC_BPS_CLK_SRC] = &cam_cc_bps_clk_src.clkr,
+ [CAM_CC_CAMNOC_AXI_CLK] = &cam_cc_camnoc_axi_clk.clkr,
+ [CAM_CC_CAMNOC_AXI_CLK_SRC] = &cam_cc_camnoc_axi_clk_src.clkr,
+ [CAM_CC_CAMNOC_DCD_XO_CLK] = &cam_cc_camnoc_dcd_xo_clk.clkr,
+ [CAM_CC_CCI_0_CLK] = &cam_cc_cci_0_clk.clkr,
+ [CAM_CC_CCI_0_CLK_SRC] = &cam_cc_cci_0_clk_src.clkr,
+ [CAM_CC_CCI_1_CLK] = &cam_cc_cci_1_clk.clkr,
+ [CAM_CC_CCI_1_CLK_SRC] = &cam_cc_cci_1_clk_src.clkr,
+ [CAM_CC_CORE_AHB_CLK] = &cam_cc_core_ahb_clk.clkr,
+ [CAM_CC_CPAS_AHB_CLK] = &cam_cc_cpas_ahb_clk.clkr,
+ [CAM_CC_CPHY_RX_CLK_SRC] = &cam_cc_cphy_rx_clk_src.clkr,
+ [CAM_CC_CSI0PHYTIMER_CLK] = &cam_cc_csi0phytimer_clk.clkr,
+ [CAM_CC_CSI0PHYTIMER_CLK_SRC] = &cam_cc_csi0phytimer_clk_src.clkr,
+ [CAM_CC_CSI1PHYTIMER_CLK] = &cam_cc_csi1phytimer_clk.clkr,
+ [CAM_CC_CSI1PHYTIMER_CLK_SRC] = &cam_cc_csi1phytimer_clk_src.clkr,
+ [CAM_CC_CSI2PHYTIMER_CLK] = &cam_cc_csi2phytimer_clk.clkr,
+ [CAM_CC_CSI2PHYTIMER_CLK_SRC] = &cam_cc_csi2phytimer_clk_src.clkr,
+ [CAM_CC_CSI3PHYTIMER_CLK] = &cam_cc_csi3phytimer_clk.clkr,
+ [CAM_CC_CSI3PHYTIMER_CLK_SRC] = &cam_cc_csi3phytimer_clk_src.clkr,
+ [CAM_CC_CSI4PHYTIMER_CLK] = &cam_cc_csi4phytimer_clk.clkr,
+ [CAM_CC_CSI4PHYTIMER_CLK_SRC] = &cam_cc_csi4phytimer_clk_src.clkr,
+ [CAM_CC_CSI5PHYTIMER_CLK] = &cam_cc_csi5phytimer_clk.clkr,
+ [CAM_CC_CSI5PHYTIMER_CLK_SRC] = &cam_cc_csi5phytimer_clk_src.clkr,
+ [CAM_CC_CSIPHY0_CLK] = &cam_cc_csiphy0_clk.clkr,
+ [CAM_CC_CSIPHY1_CLK] = &cam_cc_csiphy1_clk.clkr,
+ [CAM_CC_CSIPHY2_CLK] = &cam_cc_csiphy2_clk.clkr,
+ [CAM_CC_CSIPHY3_CLK] = &cam_cc_csiphy3_clk.clkr,
+ [CAM_CC_CSIPHY4_CLK] = &cam_cc_csiphy4_clk.clkr,
+ [CAM_CC_CSIPHY5_CLK] = &cam_cc_csiphy5_clk.clkr,
+ [CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr,
+ [CAM_CC_FD_CORE_CLK] = &cam_cc_fd_core_clk.clkr,
+ [CAM_CC_FD_CORE_CLK_SRC] = &cam_cc_fd_core_clk_src.clkr,
+ [CAM_CC_FD_CORE_UAR_CLK] = &cam_cc_fd_core_uar_clk.clkr,
+ [CAM_CC_GDSC_CLK] = &cam_cc_gdsc_clk.clkr,
+ [CAM_CC_ICP_AHB_CLK] = &cam_cc_icp_ahb_clk.clkr,
+ [CAM_CC_ICP_CLK] = &cam_cc_icp_clk.clkr,
+ [CAM_CC_ICP_CLK_SRC] = &cam_cc_icp_clk_src.clkr,
+ [CAM_CC_IFE_0_AHB_CLK] = &cam_cc_ife_0_ahb_clk.clkr,
+ [CAM_CC_IFE_0_AREG_CLK] = &cam_cc_ife_0_areg_clk.clkr,
+ [CAM_CC_IFE_0_AXI_CLK] = &cam_cc_ife_0_axi_clk.clkr,
+ [CAM_CC_IFE_0_CLK] = &cam_cc_ife_0_clk.clkr,
+ [CAM_CC_IFE_0_CLK_SRC] = &cam_cc_ife_0_clk_src.clkr,
+ [CAM_CC_IFE_0_CPHY_RX_CLK] = &cam_cc_ife_0_cphy_rx_clk.clkr,
+ [CAM_CC_IFE_0_CSID_CLK] = &cam_cc_ife_0_csid_clk.clkr,
+ [CAM_CC_IFE_0_CSID_CLK_SRC] = &cam_cc_ife_0_csid_clk_src.clkr,
+ [CAM_CC_IFE_0_DSP_CLK] = &cam_cc_ife_0_dsp_clk.clkr,
+ [CAM_CC_IFE_1_AHB_CLK] = &cam_cc_ife_1_ahb_clk.clkr,
+ [CAM_CC_IFE_1_AREG_CLK] = &cam_cc_ife_1_areg_clk.clkr,
+ [CAM_CC_IFE_1_AXI_CLK] = &cam_cc_ife_1_axi_clk.clkr,
+ [CAM_CC_IFE_1_CLK] = &cam_cc_ife_1_clk.clkr,
+ [CAM_CC_IFE_1_CLK_SRC] = &cam_cc_ife_1_clk_src.clkr,
+ [CAM_CC_IFE_1_CPHY_RX_CLK] = &cam_cc_ife_1_cphy_rx_clk.clkr,
+ [CAM_CC_IFE_1_CSID_CLK] = &cam_cc_ife_1_csid_clk.clkr,
+ [CAM_CC_IFE_1_CSID_CLK_SRC] = &cam_cc_ife_1_csid_clk_src.clkr,
+ [CAM_CC_IFE_1_DSP_CLK] = &cam_cc_ife_1_dsp_clk.clkr,
+ [CAM_CC_IFE_LITE_AHB_CLK] = &cam_cc_ife_lite_ahb_clk.clkr,
+ [CAM_CC_IFE_LITE_AXI_CLK] = &cam_cc_ife_lite_axi_clk.clkr,
+ [CAM_CC_IFE_LITE_CLK] = &cam_cc_ife_lite_clk.clkr,
+ [CAM_CC_IFE_LITE_CLK_SRC] = &cam_cc_ife_lite_clk_src.clkr,
+ [CAM_CC_IFE_LITE_CPHY_RX_CLK] = &cam_cc_ife_lite_cphy_rx_clk.clkr,
+ [CAM_CC_IFE_LITE_CSID_CLK] = &cam_cc_ife_lite_csid_clk.clkr,
+ [CAM_CC_IFE_LITE_CSID_CLK_SRC] = &cam_cc_ife_lite_csid_clk_src.clkr,
+ [CAM_CC_IPE_0_AHB_CLK] = &cam_cc_ipe_0_ahb_clk.clkr,
+ [CAM_CC_IPE_0_AREG_CLK] = &cam_cc_ipe_0_areg_clk.clkr,
+ [CAM_CC_IPE_0_AXI_CLK] = &cam_cc_ipe_0_axi_clk.clkr,
+ [CAM_CC_IPE_0_CLK] = &cam_cc_ipe_0_clk.clkr,
+ [CAM_CC_IPE_0_CLK_SRC] = &cam_cc_ipe_0_clk_src.clkr,
+ [CAM_CC_JPEG_CLK] = &cam_cc_jpeg_clk.clkr,
+ [CAM_CC_JPEG_CLK_SRC] = &cam_cc_jpeg_clk_src.clkr,
+ [CAM_CC_MCLK0_CLK] = &cam_cc_mclk0_clk.clkr,
+ [CAM_CC_MCLK0_CLK_SRC] = &cam_cc_mclk0_clk_src.clkr,
+ [CAM_CC_MCLK1_CLK] = &cam_cc_mclk1_clk.clkr,
+ [CAM_CC_MCLK1_CLK_SRC] = &cam_cc_mclk1_clk_src.clkr,
+ [CAM_CC_MCLK2_CLK] = &cam_cc_mclk2_clk.clkr,
+ [CAM_CC_MCLK2_CLK_SRC] = &cam_cc_mclk2_clk_src.clkr,
+ [CAM_CC_MCLK3_CLK] = &cam_cc_mclk3_clk.clkr,
+ [CAM_CC_MCLK3_CLK_SRC] = &cam_cc_mclk3_clk_src.clkr,
+ [CAM_CC_MCLK4_CLK] = &cam_cc_mclk4_clk.clkr,
+ [CAM_CC_MCLK4_CLK_SRC] = &cam_cc_mclk4_clk_src.clkr,
+ [CAM_CC_MCLK5_CLK] = &cam_cc_mclk5_clk.clkr,
+ [CAM_CC_MCLK5_CLK_SRC] = &cam_cc_mclk5_clk_src.clkr,
+ [CAM_CC_MCLK6_CLK] = &cam_cc_mclk6_clk.clkr,
+ [CAM_CC_MCLK6_CLK_SRC] = &cam_cc_mclk6_clk_src.clkr,
+ [CAM_CC_PLL0] = &cam_cc_pll0.clkr,
+ [CAM_CC_PLL0_OUT_EVEN] = &cam_cc_pll0_out_even.clkr,
+ [CAM_CC_PLL0_OUT_ODD] = &cam_cc_pll0_out_odd.clkr,
+ [CAM_CC_PLL1] = &cam_cc_pll1.clkr,
+ [CAM_CC_PLL1_OUT_EVEN] = &cam_cc_pll1_out_even.clkr,
+ [CAM_CC_PLL2] = &cam_cc_pll2.clkr,
+ [CAM_CC_PLL2_OUT_MAIN] = &cam_cc_pll2_out_main.clkr,
+ [CAM_CC_PLL3] = &cam_cc_pll3.clkr,
+ [CAM_CC_PLL3_OUT_EVEN] = &cam_cc_pll3_out_even.clkr,
+ [CAM_CC_PLL4] = &cam_cc_pll4.clkr,
+ [CAM_CC_PLL4_OUT_EVEN] = &cam_cc_pll4_out_even.clkr,
+ [CAM_CC_SBI_AHB_CLK] = &cam_cc_sbi_ahb_clk.clkr,
+ [CAM_CC_SBI_AXI_CLK] = &cam_cc_sbi_axi_clk.clkr,
+ [CAM_CC_SBI_CLK] = &cam_cc_sbi_clk.clkr,
+ [CAM_CC_SBI_CPHY_RX_CLK] = &cam_cc_sbi_cphy_rx_clk.clkr,
+ [CAM_CC_SBI_CSID_CLK] = &cam_cc_sbi_csid_clk.clkr,
+ [CAM_CC_SBI_CSID_CLK_SRC] = &cam_cc_sbi_csid_clk_src.clkr,
+ [CAM_CC_SBI_DIV_CLK_SRC] = &cam_cc_sbi_div_clk_src.clkr,
+ [CAM_CC_SBI_IFE_0_CLK] = &cam_cc_sbi_ife_0_clk.clkr,
+ [CAM_CC_SBI_IFE_1_CLK] = &cam_cc_sbi_ife_1_clk.clkr,
+ [CAM_CC_SLEEP_CLK] = &cam_cc_sleep_clk.clkr,
+ [CAM_CC_SLEEP_CLK_SRC] = &cam_cc_sleep_clk_src.clkr,
+ [CAM_CC_SLOW_AHB_CLK_SRC] = &cam_cc_slow_ahb_clk_src.clkr,
+ [CAM_CC_XO_CLK_SRC] = &cam_cc_xo_clk_src.clkr,
+};
+
+static struct gdsc *cam_cc_sm8250_gdscs[] = {
+ [BPS_GDSC] = &bps_gdsc,
+ [IPE_0_GDSC] = &ipe_0_gdsc,
+ [SBI_GDSC] = &sbi_gdsc,
+ [IFE_0_GDSC] = &ife_0_gdsc,
+ [IFE_1_GDSC] = &ife_1_gdsc,
+ [TITAN_TOP_GDSC] = &titan_top_gdsc,
+};
+
+static const struct qcom_reset_map cam_cc_sm8250_resets[] = {
+ [CAM_CC_BPS_BCR] = { 0x7000 },
+ [CAM_CC_ICP_BCR] = { 0xc070 },
+ [CAM_CC_IFE_0_BCR] = { 0xa000 },
+ [CAM_CC_IFE_1_BCR] = { 0xb000 },
+ [CAM_CC_IPE_0_BCR] = { 0x8000 },
+ [CAM_CC_SBI_BCR] = { 0x9000 },
+};
+
+static const struct regmap_config cam_cc_sm8250_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xe004,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc cam_cc_sm8250_desc = {
+ .config = &cam_cc_sm8250_regmap_config,
+ .clks = cam_cc_sm8250_clocks,
+ .num_clks = ARRAY_SIZE(cam_cc_sm8250_clocks),
+ .resets = cam_cc_sm8250_resets,
+ .num_resets = ARRAY_SIZE(cam_cc_sm8250_resets),
+ .gdscs = cam_cc_sm8250_gdscs,
+ .num_gdscs = ARRAY_SIZE(cam_cc_sm8250_gdscs),
+};
+
+static const struct of_device_id cam_cc_sm8250_match_table[] = {
+ { .compatible = "qcom,sm8250-camcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cam_cc_sm8250_match_table);
+
+static int cam_cc_sm8250_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &cam_cc_sm8250_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ clk_lucid_pll_configure(&cam_cc_pll0, regmap, &cam_cc_pll0_config);
+ clk_lucid_pll_configure(&cam_cc_pll1, regmap, &cam_cc_pll1_config);
+ clk_zonda_pll_configure(&cam_cc_pll2, regmap, &cam_cc_pll2_config);
+ clk_lucid_pll_configure(&cam_cc_pll3, regmap, &cam_cc_pll3_config);
+ clk_lucid_pll_configure(&cam_cc_pll4, regmap, &cam_cc_pll4_config);
+
+ return qcom_cc_really_probe(pdev, &cam_cc_sm8250_desc, regmap);
+}
+
+static struct platform_driver cam_cc_sm8250_driver = {
+ .probe = cam_cc_sm8250_probe,
+ .driver = {
+ .name = "cam_cc-sm8250",
+ .of_match_table = cam_cc_sm8250_match_table,
+ },
+};
+
+static int __init cam_cc_sm8250_init(void)
+{
+ return platform_driver_register(&cam_cc_sm8250_driver);
+}
+subsys_initcall(cam_cc_sm8250_init);
+
+static void __exit cam_cc_sm8250_exit(void)
+{
+ platform_driver_unregister(&cam_cc_sm8250_driver);
+}
+module_exit(cam_cc_sm8250_exit);
+
+MODULE_DESCRIPTION("QTI CAMCC SM8250 Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index c6eb99169ddc..eaedcceb766f 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -126,6 +126,19 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = {
[PLL_OFF_TEST_CTL_U] = 0x1c,
[PLL_OFF_STATUS] = 0x2c,
},
+ [CLK_ALPHA_PLL_TYPE_ZONDA] = {
+ [PLL_OFF_L_VAL] = 0x04,
+ [PLL_OFF_ALPHA_VAL] = 0x08,
+ [PLL_OFF_USER_CTL] = 0x0c,
+ [PLL_OFF_CONFIG_CTL] = 0x10,
+ [PLL_OFF_CONFIG_CTL_U] = 0x14,
+ [PLL_OFF_CONFIG_CTL_U1] = 0x18,
+ [PLL_OFF_TEST_CTL] = 0x1c,
+ [PLL_OFF_TEST_CTL_U] = 0x20,
+ [PLL_OFF_TEST_CTL_U1] = 0x24,
+ [PLL_OFF_OPMODE] = 0x28,
+ [PLL_OFF_STATUS] = 0x38,
+ },
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
@@ -162,6 +175,11 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
#define LUCID_5LPE_PLL_LATCH_INPUT BIT(14)
#define LUCID_5LPE_ENABLE_VOTE_RUN BIT(21)
+/* ZONDA PLL specific */
+#define ZONDA_PLL_OUT_MASK 0xf
+#define ZONDA_STAY_IN_CFA BIT(16)
+#define ZONDA_PLL_FREQ_LOCK_DET BIT(29)
+
#define pll_alpha_width(p) \
((PLL_ALPHA_VAL_U(p) - PLL_ALPHA_VAL(p) == 4) ? \
ALPHA_REG_BITWIDTH : ALPHA_REG_16BIT_WIDTH)
@@ -208,6 +226,9 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse,
#define wait_for_pll_enable_lock(pll) \
wait_for_pll(pll, PLL_LOCK_DET, 0, "enable")
+#define wait_for_zonda_pll_freq_lock(pll) \
+ wait_for_pll(pll, ZONDA_PLL_FREQ_LOCK_DET, 0, "freq enable")
+
#define wait_for_pll_disable(pll) \
wait_for_pll(pll, PLL_ACTIVE_FLAG, 1, "disable")
@@ -1234,7 +1255,7 @@ static int alpha_pll_fabia_prepare(struct clk_hw *hw)
return ret;
/* Setup PLL for calibration frequency */
- regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), cal_l);
+ regmap_write(pll->clkr.regmap, PLL_CAL_L_VAL(pll), cal_l);
/* Bringup the PLL at calibration frequency */
ret = clk_alpha_pll_enable(hw);
@@ -1777,3 +1798,156 @@ const struct clk_ops clk_alpha_pll_postdiv_lucid_5lpe_ops = {
.set_rate = clk_lucid_5lpe_pll_postdiv_set_rate,
};
EXPORT_SYMBOL(clk_alpha_pll_postdiv_lucid_5lpe_ops);
+
+void clk_zonda_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
+ const struct alpha_pll_config *config)
+{
+ clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l);
+ clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha);
+ clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll), config->config_ctl_val);
+ clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll), config->config_ctl_hi_val);
+ clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U1(pll), config->config_ctl_hi1_val);
+ clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll), config->user_ctl_val);
+ clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U(pll), config->user_ctl_hi_val);
+ clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U1(pll), config->user_ctl_hi1_val);
+ clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll), config->test_ctl_val);
+ clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll), config->test_ctl_hi_val);
+ clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U1(pll), config->test_ctl_hi1_val);
+
+ regmap_update_bits(regmap, PLL_MODE(pll), PLL_BYPASSNL, 0);
+
+ /* Disable PLL output */
+ regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, 0);
+
+ /* Set operation mode to OFF */
+ regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY);
+
+ /* Place the PLL in STANDBY mode */
+ regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N);
+}
+EXPORT_SYMBOL_GPL(clk_zonda_pll_configure);
+
+static int clk_zonda_pll_enable(struct clk_hw *hw)
+{
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+ struct regmap *regmap = pll->clkr.regmap;
+ u32 val;
+ int ret;
+
+ regmap_read(regmap, PLL_MODE(pll), &val);
+
+ /* If in FSM mode, just vote for it */
+ if (val & PLL_VOTE_FSM_ENA) {
+ ret = clk_enable_regmap(hw);
+ if (ret)
+ return ret;
+ return wait_for_pll_enable_active(pll);
+ }
+
+ /* Get the PLL out of bypass mode */
+ regmap_update_bits(regmap, PLL_MODE(pll), PLL_BYPASSNL, PLL_BYPASSNL);
+
+ /*
+ * H/W requires a 1us delay between disabling the bypass and
+ * de-asserting the reset.
+ */
+ udelay(1);
+
+ regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N);
+
+ /* Set operation mode to RUN */
+ regmap_write(regmap, PLL_OPMODE(pll), PLL_RUN);
+
+ regmap_read(regmap, PLL_TEST_CTL(pll), &val);
+
+ /* If cfa mode then poll for freq lock */
+ if (val & ZONDA_STAY_IN_CFA)
+ ret = wait_for_zonda_pll_freq_lock(pll);
+ else
+ ret = wait_for_pll_enable_lock(pll);
+ if (ret)
+ return ret;
+
+ /* Enable the PLL outputs */
+ regmap_update_bits(regmap, PLL_USER_CTL(pll), ZONDA_PLL_OUT_MASK, ZONDA_PLL_OUT_MASK);
+
+ /* Enable the global PLL outputs */
+ regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, PLL_OUTCTRL);
+
+ return 0;
+}
+
+static void clk_zonda_pll_disable(struct clk_hw *hw)
+{
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+ struct regmap *regmap = pll->clkr.regmap;
+ u32 val;
+
+ regmap_read(regmap, PLL_MODE(pll), &val);
+
+ /* If in FSM mode, just unvote it */
+ if (val & PLL_VOTE_FSM_ENA) {
+ clk_disable_regmap(hw);
+ return;
+ }
+
+ /* Disable the global PLL output */
+ regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, 0);
+
+ /* Disable the PLL outputs */
+ regmap_update_bits(regmap, PLL_USER_CTL(pll), ZONDA_PLL_OUT_MASK, 0);
+
+ /* Put the PLL in bypass and reset */
+ regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N | PLL_BYPASSNL, 0);
+
+ /* Place the PLL mode in OFF state */
+ regmap_write(regmap, PLL_OPMODE(pll), 0x0);
+}
+
+static int clk_zonda_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long prate)
+{
+ struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
+ unsigned long rrate;
+ u32 test_ctl_val;
+ u32 l, alpha_width = pll_alpha_width(pll);
+ u64 a;
+ int ret;
+
+ rrate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width);
+
+ ret = alpha_pll_check_rate_margin(hw, rrate, rate);
+ if (ret < 0)
+ return ret;
+
+ regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a);
+ regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l);
+
+ /* Wait before polling for the frequency latch */
+ udelay(5);
+
+ /* Read stay in cfa mode */
+ regmap_read(pll->clkr.regmap, PLL_TEST_CTL(pll), &test_ctl_val);
+
+ /* If cfa mode then poll for freq lock */
+ if (test_ctl_val & ZONDA_STAY_IN_CFA)
+ ret = wait_for_zonda_pll_freq_lock(pll);
+ else
+ ret = wait_for_pll_enable_lock(pll);
+ if (ret)
+ return ret;
+
+ /* Wait for PLL output to stabilize */
+ udelay(100);
+ return 0;
+}
+
+const struct clk_ops clk_alpha_pll_zonda_ops = {
+ .enable = clk_zonda_pll_enable,
+ .disable = clk_zonda_pll_disable,
+ .is_enabled = clk_trion_pll_is_enabled,
+ .recalc_rate = clk_trion_pll_recalc_rate,
+ .round_rate = clk_alpha_pll_round_rate,
+ .set_rate = clk_zonda_pll_set_rate,
+};
+EXPORT_SYMBOL(clk_alpha_pll_zonda_ops);
diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h
index 6943e933be0f..55e4fa47912f 100644
--- a/drivers/clk/qcom/clk-alpha-pll.h
+++ b/drivers/clk/qcom/clk-alpha-pll.h
@@ -16,6 +16,7 @@ enum {
CLK_ALPHA_PLL_TYPE_TRION,
CLK_ALPHA_PLL_TYPE_LUCID = CLK_ALPHA_PLL_TYPE_TRION,
CLK_ALPHA_PLL_TYPE_AGERA,
+ CLK_ALPHA_PLL_TYPE_ZONDA,
CLK_ALPHA_PLL_TYPE_MAX,
};
@@ -148,6 +149,9 @@ extern const struct clk_ops clk_alpha_pll_lucid_5lpe_ops;
extern const struct clk_ops clk_alpha_pll_fixed_lucid_5lpe_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_lucid_5lpe_ops;
+extern const struct clk_ops clk_alpha_pll_zonda_ops;
+#define clk_alpha_pll_postdiv_zonda_ops clk_alpha_pll_postdiv_fabia_ops
+
void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config);
void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
@@ -159,6 +163,8 @@ void clk_agera_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
#define clk_lucid_pll_configure(pll, regmap, config) \
clk_trion_pll_configure(pll, regmap, config)
+void clk_zonda_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
+ const struct alpha_pll_config *config);
#endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 05ff3b0d233e..e1b1b426fae4 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -357,6 +357,83 @@ static int clk_rcg2_set_floor_rate_and_parent(struct clk_hw *hw,
return __clk_rcg2_set_rate(hw, rate, FLOOR);
}
+static int clk_rcg2_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ u32 notn_m, n, m, d, not2d, mask;
+
+ if (!rcg->mnd_width) {
+ /* 50 % duty-cycle for Non-MND RCGs */
+ duty->num = 1;
+ duty->den = 2;
+ return 0;
+ }
+
+ regmap_read(rcg->clkr.regmap, RCG_D_OFFSET(rcg), &not2d);
+ regmap_read(rcg->clkr.regmap, RCG_M_OFFSET(rcg), &m);
+ regmap_read(rcg->clkr.regmap, RCG_N_OFFSET(rcg), &notn_m);
+
+ if (!not2d && !m && !notn_m) {
+ /* 50 % duty-cycle always */
+ duty->num = 1;
+ duty->den = 2;
+ return 0;
+ }
+
+ mask = BIT(rcg->mnd_width) - 1;
+
+ d = ~(not2d) & mask;
+ d = DIV_ROUND_CLOSEST(d, 2);
+
+ n = (~(notn_m) + m) & mask;
+
+ duty->num = d;
+ duty->den = n;
+
+ return 0;
+}
+
+static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ u32 notn_m, n, m, d, not2d, mask, duty_per;
+ int ret;
+
+ /* Duty-cycle cannot be modified for non-MND RCGs */
+ if (!rcg->mnd_width)
+ return -EINVAL;
+
+ mask = BIT(rcg->mnd_width) - 1;
+
+ regmap_read(rcg->clkr.regmap, RCG_N_OFFSET(rcg), &notn_m);
+ regmap_read(rcg->clkr.regmap, RCG_M_OFFSET(rcg), &m);
+
+ n = (~(notn_m) + m) & mask;
+
+ duty_per = (duty->num * 100) / duty->den;
+
+ /* Calculate 2d value */
+ d = DIV_ROUND_CLOSEST(n * duty_per * 2, 100);
+
+ /* Check bit widths of 2d. If D is too big reduce duty cycle. */
+ if (d > mask)
+ d = mask;
+
+ if ((d / 2) > (n - m))
+ d = (n - m) * 2;
+ else if ((d / 2) < (m / 2))
+ d = m;
+
+ not2d = ~d & mask;
+
+ ret = regmap_update_bits(rcg->clkr.regmap, RCG_D_OFFSET(rcg), mask,
+ not2d);
+ if (ret)
+ return ret;
+
+ return update_config(rcg);
+}
+
const struct clk_ops clk_rcg2_ops = {
.is_enabled = clk_rcg2_is_enabled,
.get_parent = clk_rcg2_get_parent,
@@ -365,6 +442,8 @@ const struct clk_ops clk_rcg2_ops = {
.determine_rate = clk_rcg2_determine_rate,
.set_rate = clk_rcg2_set_rate,
.set_rate_and_parent = clk_rcg2_set_rate_and_parent,
+ .get_duty_cycle = clk_rcg2_get_duty_cycle,
+ .set_duty_cycle = clk_rcg2_set_duty_cycle,
};
EXPORT_SYMBOL_GPL(clk_rcg2_ops);
@@ -376,6 +455,8 @@ const struct clk_ops clk_rcg2_floor_ops = {
.determine_rate = clk_rcg2_determine_floor_rate,
.set_rate = clk_rcg2_set_floor_rate,
.set_rate_and_parent = clk_rcg2_set_floor_rate_and_parent,
+ .get_duty_cycle = clk_rcg2_get_duty_cycle,
+ .set_duty_cycle = clk_rcg2_set_duty_cycle,
};
EXPORT_SYMBOL_GPL(clk_rcg2_floor_ops);
diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c
index 0e1dfa89489e..800b2fef1887 100644
--- a/drivers/clk/qcom/clk-smd-rpm.c
+++ b/drivers/clk/qcom/clk-smd-rpm.c
@@ -39,7 +39,10 @@
.hw.init = &(struct clk_init_data){ \
.ops = &clk_smd_rpm_ops, \
.name = #_name, \
- .parent_names = (const char *[]){ "xo_board" }, \
+ .parent_data = &(const struct clk_parent_data){ \
+ .fw_name = "xo", \
+ .name = "xo_board", \
+ }, \
.num_parents = 1, \
}, \
}; \
@@ -54,7 +57,10 @@
.hw.init = &(struct clk_init_data){ \
.ops = &clk_smd_rpm_ops, \
.name = #_active, \
- .parent_names = (const char *[]){ "xo_board" }, \
+ .parent_data = &(const struct clk_parent_data){ \
+ .fw_name = "xo", \
+ .name = "xo_board", \
+ }, \
.num_parents = 1, \
}, \
}
@@ -73,7 +79,10 @@
.hw.init = &(struct clk_init_data){ \
.ops = &clk_smd_rpm_branch_ops, \
.name = #_name, \
- .parent_names = (const char *[]){ "xo_board" }, \
+ .parent_data = &(const struct clk_parent_data){ \
+ .fw_name = "xo", \
+ .name = "xo_board", \
+ }, \
.num_parents = 1, \
}, \
}; \
@@ -89,7 +98,10 @@
.hw.init = &(struct clk_init_data){ \
.ops = &clk_smd_rpm_branch_ops, \
.name = #_active, \
- .parent_names = (const char *[]){ "xo_board" }, \
+ .parent_data = &(const struct clk_parent_data){ \
+ .fw_name = "xo", \
+ .name = "xo_board", \
+ }, \
.num_parents = 1, \
}, \
}
@@ -406,7 +418,6 @@ static const struct clk_ops clk_smd_rpm_branch_ops = {
.unprepare = clk_smd_rpm_unprepare,
};
-/* msm8916 */
DEFINE_CLK_SMD_RPM(msm8916, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8916, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
DEFINE_CLK_SMD_RPM(msm8916, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
@@ -452,48 +463,35 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8916 = {
.num_clks = ARRAY_SIZE(msm8916_clks),
};
-/* msm8936 */
-DEFINE_CLK_SMD_RPM(msm8936, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8936, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
-DEFINE_CLK_SMD_RPM(msm8936, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8936, sysmmnoc_clk, sysmmnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
-DEFINE_CLK_SMD_RPM_QDSS(msm8936, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8936, bb_clk1, bb_clk1_a, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8936, bb_clk2, bb_clk2_a, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8936, rf_clk1, rf_clk1_a, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8936, rf_clk2, rf_clk2_a, 5);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8936, bb_clk1_pin, bb_clk1_a_pin, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8936, bb_clk2_pin, bb_clk2_a_pin, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8936, rf_clk1_pin, rf_clk1_a_pin, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8936, rf_clk2_pin, rf_clk2_a_pin, 5);
static struct clk_smd_rpm *msm8936_clks[] = {
- [RPM_SMD_PCNOC_CLK] = &msm8936_pcnoc_clk,
- [RPM_SMD_PCNOC_A_CLK] = &msm8936_pcnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &msm8936_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8936_snoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8936_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8936_bimc_a_clk,
+ [RPM_SMD_PCNOC_CLK] = &msm8916_pcnoc_clk,
+ [RPM_SMD_PCNOC_A_CLK] = &msm8916_pcnoc_clk,
+ [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
[RPM_SMD_SYSMMNOC_CLK] = &msm8936_sysmmnoc_clk,
[RPM_SMD_SYSMMNOC_A_CLK] = &msm8936_sysmmnoc_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8936_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8936_qdss_a_clk,
- [RPM_SMD_BB_CLK1] = &msm8936_bb_clk1,
- [RPM_SMD_BB_CLK1_A] = &msm8936_bb_clk1_a,
- [RPM_SMD_BB_CLK2] = &msm8936_bb_clk2,
- [RPM_SMD_BB_CLK2_A] = &msm8936_bb_clk2_a,
- [RPM_SMD_RF_CLK1] = &msm8936_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8936_rf_clk1_a,
- [RPM_SMD_RF_CLK2] = &msm8936_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8936_rf_clk2_a,
- [RPM_SMD_BB_CLK1_PIN] = &msm8936_bb_clk1_pin,
- [RPM_SMD_BB_CLK1_A_PIN] = &msm8936_bb_clk1_a_pin,
- [RPM_SMD_BB_CLK2_PIN] = &msm8936_bb_clk2_pin,
- [RPM_SMD_BB_CLK2_A_PIN] = &msm8936_bb_clk2_a_pin,
- [RPM_SMD_RF_CLK1_PIN] = &msm8936_rf_clk1_pin,
- [RPM_SMD_RF_CLK1_A_PIN] = &msm8936_rf_clk1_a_pin,
- [RPM_SMD_RF_CLK2_PIN] = &msm8936_rf_clk2_pin,
- [RPM_SMD_RF_CLK2_A_PIN] = &msm8936_rf_clk2_a_pin,
+ [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
+ [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1,
+ [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a,
+ [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2,
+ [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a,
+ [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
+ [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
+ [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
+ [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
+ [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
+ [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
+ [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin,
+ [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin,
+ [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin,
+ [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8936 = {
@@ -501,15 +499,10 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8936 = {
.num_clks = ARRAY_SIZE(msm8936_clks),
};
-/* msm8974 */
-DEFINE_CLK_SMD_RPM(msm8974, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8974, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
DEFINE_CLK_SMD_RPM(msm8974, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
DEFINE_CLK_SMD_RPM(msm8974, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk, QCOM_SMD_RPM_BUS_CLK, 3);
-DEFINE_CLK_SMD_RPM(msm8974, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8974, gfx3d_clk_src, gfx3d_a_clk_src, QCOM_SMD_RPM_MEM_CLK, 1);
DEFINE_CLK_SMD_RPM(msm8974, ocmemgx_clk, ocmemgx_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
-DEFINE_CLK_SMD_RPM_QDSS(msm8974, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_d0, cxo_d0_a, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_d1, cxo_d1_a, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a0, cxo_a0_a, 4);
@@ -525,22 +518,22 @@ DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a1_pin, cxo_a1_a_pin, 5);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a2_pin, cxo_a2_a_pin, 6);
static struct clk_smd_rpm *msm8974_clks[] = {
- [RPM_SMD_PNOC_CLK] = &msm8974_pnoc_clk,
- [RPM_SMD_PNOC_A_CLK] = &msm8974_pnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &msm8974_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8974_snoc_a_clk,
+ [RPM_SMD_PNOC_CLK] = &msm8916_pcnoc_clk,
+ [RPM_SMD_PNOC_A_CLK] = &msm8916_pcnoc_a_clk,
+ [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
[RPM_SMD_CNOC_CLK] = &msm8974_cnoc_clk,
[RPM_SMD_CNOC_A_CLK] = &msm8974_cnoc_a_clk,
[RPM_SMD_MMSSNOC_AHB_CLK] = &msm8974_mmssnoc_ahb_clk,
[RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8974_mmssnoc_ahb_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8974_bimc_clk,
+ [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
[RPM_SMD_GFX3D_CLK_SRC] = &msm8974_gfx3d_clk_src,
[RPM_SMD_GFX3D_A_CLK_SRC] = &msm8974_gfx3d_a_clk_src,
- [RPM_SMD_BIMC_A_CLK] = &msm8974_bimc_a_clk,
+ [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
[RPM_SMD_OCMEMGX_CLK] = &msm8974_ocmemgx_clk,
[RPM_SMD_OCMEMGX_A_CLK] = &msm8974_ocmemgx_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8974_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8974_qdss_a_clk,
+ [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
[RPM_SMD_CXO_D0] = &msm8974_cxo_d0,
[RPM_SMD_CXO_D0_A] = &msm8974_cxo_d0_a,
[RPM_SMD_CXO_D1] = &msm8974_cxo_d1,
@@ -574,46 +567,33 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8974 = {
.num_clks = ARRAY_SIZE(msm8974_clks),
};
-
-/* msm8976 */
-DEFINE_CLK_SMD_RPM(msm8976, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8976, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
DEFINE_CLK_SMD_RPM(msm8976, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk,
QCOM_SMD_RPM_BUS_CLK, 2);
-DEFINE_CLK_SMD_RPM(msm8976, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8976, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
-DEFINE_CLK_SMD_RPM_QDSS(msm8976, qdss_clk, qdss_a_clk,
- QCOM_SMD_RPM_MISC_CLK, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8976, bb_clk1, bb_clk1_a, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8976, bb_clk2, bb_clk2_a, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8976, rf_clk2, rf_clk2_a, 5);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8976, div_clk2, div_clk2_a, 12);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8976, bb_clk1_pin, bb_clk1_a_pin, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8976, bb_clk2_pin, bb_clk2_a_pin, 2);
static struct clk_smd_rpm *msm8976_clks[] = {
- [RPM_SMD_PCNOC_CLK] = &msm8976_pcnoc_clk,
- [RPM_SMD_PCNOC_A_CLK] = &msm8976_pcnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &msm8976_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8976_snoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8976_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8976_bimc_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8976_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8976_qdss_a_clk,
- [RPM_SMD_BB_CLK1] = &msm8976_bb_clk1,
- [RPM_SMD_BB_CLK1_A] = &msm8976_bb_clk1_a,
- [RPM_SMD_BB_CLK2] = &msm8976_bb_clk2,
- [RPM_SMD_BB_CLK2_A] = &msm8976_bb_clk2_a,
- [RPM_SMD_RF_CLK2] = &msm8976_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8976_rf_clk2_a,
- [RPM_SMD_BB_CLK1_PIN] = &msm8976_bb_clk1_pin,
- [RPM_SMD_BB_CLK1_A_PIN] = &msm8976_bb_clk1_a_pin,
- [RPM_SMD_BB_CLK2_PIN] = &msm8976_bb_clk2_pin,
- [RPM_SMD_BB_CLK2_A_PIN] = &msm8976_bb_clk2_a_pin,
+ [RPM_SMD_PCNOC_CLK] = &msm8916_pcnoc_clk,
+ [RPM_SMD_PCNOC_A_CLK] = &msm8916_pcnoc_a_clk,
+ [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
+ [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
+ [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1,
+ [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a,
+ [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2,
+ [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a,
+ [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
+ [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
+ [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
+ [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
+ [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
[RPM_SMD_MMSSNOC_AHB_CLK] = &msm8976_mmssnoc_ahb_clk,
[RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8976_mmssnoc_ahb_a_clk,
- [RPM_SMD_DIV_CLK2] = &msm8976_div_clk2,
- [RPM_SMD_DIV_A_CLK2] = &msm8976_div_clk2_a,
+ [RPM_SMD_DIV_CLK2] = &msm8974_div_clk2,
+ [RPM_SMD_DIV_A_CLK2] = &msm8974_div_a_clk2,
[RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
[RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
};
@@ -623,78 +603,55 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8976 = {
.num_clks = ARRAY_SIZE(msm8976_clks),
};
-/* msm8992 */
-DEFINE_CLK_SMD_RPM(msm8992, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8992, ocmemgx_clk, ocmemgx_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
-DEFINE_CLK_SMD_RPM(msm8992, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8992, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
-DEFINE_CLK_SMD_RPM(msm8992, gfx3d_clk_src, gfx3d_a_clk_src, QCOM_SMD_RPM_MEM_CLK, 1);
-DEFINE_CLK_SMD_RPM(msm8992, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, bb_clk1, bb_clk1_a, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8992, bb_clk1_pin, bb_clk1_a_pin, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, bb_clk2, bb_clk2_a, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8992, bb_clk2_pin, bb_clk2_a_pin, 2);
-
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, div_clk1, div_clk1_a, 11);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, div_clk2, div_clk2_a, 12);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, div_clk3, div_clk3_a, 13);
-DEFINE_CLK_SMD_RPM(msm8992, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, ln_bb_clk, ln_bb_a_clk, 8);
-DEFINE_CLK_SMD_RPM(msm8992, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk,
- QCOM_SMD_RPM_BUS_CLK, 3);
-DEFINE_CLK_SMD_RPM_QDSS(msm8992, qdss_clk, qdss_a_clk,
- QCOM_SMD_RPM_MISC_CLK, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, rf_clk1, rf_clk1_a, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, rf_clk2, rf_clk2_a, 5);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8992, rf_clk1_pin, rf_clk1_a_pin, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8992, rf_clk2_pin, rf_clk2_a_pin, 5);
DEFINE_CLK_SMD_RPM(msm8992, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8992, ce2_clk, ce2_a_clk, QCOM_SMD_RPM_CE_CLK, 1);
static struct clk_smd_rpm *msm8992_clks[] = {
- [RPM_SMD_PNOC_CLK] = &msm8992_pnoc_clk,
- [RPM_SMD_PNOC_A_CLK] = &msm8992_pnoc_a_clk,
- [RPM_SMD_OCMEMGX_CLK] = &msm8992_ocmemgx_clk,
- [RPM_SMD_OCMEMGX_A_CLK] = &msm8992_ocmemgx_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8992_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8992_bimc_a_clk,
- [RPM_SMD_CNOC_CLK] = &msm8992_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &msm8992_cnoc_a_clk,
- [RPM_SMD_GFX3D_CLK_SRC] = &msm8992_gfx3d_clk_src,
- [RPM_SMD_GFX3D_A_CLK_SRC] = &msm8992_gfx3d_a_clk_src,
- [RPM_SMD_SNOC_CLK] = &msm8992_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8992_snoc_a_clk,
- [RPM_SMD_BB_CLK1] = &msm8992_bb_clk1,
- [RPM_SMD_BB_CLK1_A] = &msm8992_bb_clk1_a,
- [RPM_SMD_BB_CLK1_PIN] = &msm8992_bb_clk1_pin,
- [RPM_SMD_BB_CLK1_A_PIN] = &msm8992_bb_clk1_a_pin,
- [RPM_SMD_BB_CLK2] = &msm8992_bb_clk2,
- [RPM_SMD_BB_CLK2_A] = &msm8992_bb_clk2_a,
- [RPM_SMD_BB_CLK2_PIN] = &msm8992_bb_clk2_pin,
- [RPM_SMD_BB_CLK2_A_PIN] = &msm8992_bb_clk2_a_pin,
- [RPM_SMD_DIV_CLK1] = &msm8992_div_clk1,
- [RPM_SMD_DIV_A_CLK1] = &msm8992_div_clk1_a,
- [RPM_SMD_DIV_CLK2] = &msm8992_div_clk2,
- [RPM_SMD_DIV_A_CLK2] = &msm8992_div_clk2_a,
+ [RPM_SMD_PNOC_CLK] = &msm8916_pcnoc_clk,
+ [RPM_SMD_PNOC_A_CLK] = &msm8916_pcnoc_a_clk,
+ [RPM_SMD_OCMEMGX_CLK] = &msm8974_ocmemgx_clk,
+ [RPM_SMD_OCMEMGX_A_CLK] = &msm8974_ocmemgx_a_clk,
+ [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
+ [RPM_SMD_CNOC_CLK] = &msm8974_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &msm8974_cnoc_a_clk,
+ [RPM_SMD_GFX3D_CLK_SRC] = &msm8974_gfx3d_clk_src,
+ [RPM_SMD_GFX3D_A_CLK_SRC] = &msm8974_gfx3d_a_clk_src,
+ [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
+ [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1,
+ [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a,
+ [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
+ [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
+ [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2,
+ [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a,
+ [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
+ [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
+ [RPM_SMD_DIV_CLK1] = &msm8974_div_clk1,
+ [RPM_SMD_DIV_A_CLK1] = &msm8974_div_a_clk1,
+ [RPM_SMD_DIV_CLK2] = &msm8974_div_clk2,
+ [RPM_SMD_DIV_A_CLK2] = &msm8974_div_a_clk2,
[RPM_SMD_DIV_CLK3] = &msm8992_div_clk3,
[RPM_SMD_DIV_A_CLK3] = &msm8992_div_clk3_a,
- [RPM_SMD_IPA_CLK] = &msm8992_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8992_ipa_a_clk,
+ [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
[RPM_SMD_LN_BB_CLK] = &msm8992_ln_bb_clk,
[RPM_SMD_LN_BB_A_CLK] = &msm8992_ln_bb_a_clk,
- [RPM_SMD_MMSSNOC_AHB_CLK] = &msm8992_mmssnoc_ahb_clk,
- [RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8992_mmssnoc_ahb_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8992_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8992_qdss_a_clk,
- [RPM_SMD_RF_CLK1] = &msm8992_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8992_rf_clk1_a,
- [RPM_SMD_RF_CLK2] = &msm8992_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8992_rf_clk2_a,
- [RPM_SMD_RF_CLK1_PIN] = &msm8992_rf_clk1_pin,
- [RPM_SMD_RF_CLK1_A_PIN] = &msm8992_rf_clk1_a_pin,
- [RPM_SMD_RF_CLK2_PIN] = &msm8992_rf_clk2_pin,
- [RPM_SMD_RF_CLK2_A_PIN] = &msm8992_rf_clk2_a_pin,
+ [RPM_SMD_MMSSNOC_AHB_CLK] = &msm8974_mmssnoc_ahb_clk,
+ [RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8974_mmssnoc_ahb_a_clk,
+ [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
+ [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
+ [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
+ [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin,
+ [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin,
+ [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin,
+ [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin,
[RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
[RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
[RPM_SMD_CE2_CLK] = &msm8992_ce2_clk,
@@ -706,83 +663,55 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8992 = {
.num_clks = ARRAY_SIZE(msm8992_clks),
};
-/* msm8994 */
-DEFINE_CLK_SMD_RPM(msm8994, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8994, ocmemgx_clk, ocmemgx_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
-DEFINE_CLK_SMD_RPM(msm8994, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8994, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
-DEFINE_CLK_SMD_RPM(msm8994, gfx3d_clk_src, gfx3d_a_clk_src, QCOM_SMD_RPM_MEM_CLK, 1);
-DEFINE_CLK_SMD_RPM(msm8994, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, bb_clk1, bb_clk1_a, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8994, bb_clk1_pin, bb_clk1_a_pin, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, bb_clk2, bb_clk2_a, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8994, bb_clk2_pin, bb_clk2_a_pin, 2);
-
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, div_clk1, div_clk1_a, 11);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, div_clk2, div_clk2_a, 12);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, div_clk3, div_clk3_a, 13);
-DEFINE_CLK_SMD_RPM(msm8994, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, ln_bb_clk, ln_bb_a_clk, 8);
-DEFINE_CLK_SMD_RPM(msm8994, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk,
- QCOM_SMD_RPM_BUS_CLK, 3);
-DEFINE_CLK_SMD_RPM_QDSS(msm8994, qdss_clk, qdss_a_clk,
- QCOM_SMD_RPM_MISC_CLK, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, rf_clk1, rf_clk1_a, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8994, rf_clk2, rf_clk2_a, 5);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8994, rf_clk1_pin, rf_clk1_a_pin, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8994, rf_clk2_pin, rf_clk2_a_pin, 5);
-
-DEFINE_CLK_SMD_RPM(msm8994, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8994, ce2_clk, ce2_a_clk, QCOM_SMD_RPM_CE_CLK, 1);
DEFINE_CLK_SMD_RPM(msm8994, ce3_clk, ce3_a_clk, QCOM_SMD_RPM_CE_CLK, 2);
static struct clk_smd_rpm *msm8994_clks[] = {
- [RPM_SMD_PNOC_CLK] = &msm8994_pnoc_clk,
- [RPM_SMD_PNOC_A_CLK] = &msm8994_pnoc_a_clk,
- [RPM_SMD_OCMEMGX_CLK] = &msm8994_ocmemgx_clk,
- [RPM_SMD_OCMEMGX_A_CLK] = &msm8994_ocmemgx_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8994_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8994_bimc_a_clk,
- [RPM_SMD_CNOC_CLK] = &msm8994_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &msm8994_cnoc_a_clk,
- [RPM_SMD_GFX3D_CLK_SRC] = &msm8994_gfx3d_clk_src,
- [RPM_SMD_GFX3D_A_CLK_SRC] = &msm8994_gfx3d_a_clk_src,
- [RPM_SMD_SNOC_CLK] = &msm8994_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8994_snoc_a_clk,
- [RPM_SMD_BB_CLK1] = &msm8994_bb_clk1,
- [RPM_SMD_BB_CLK1_A] = &msm8994_bb_clk1_a,
- [RPM_SMD_BB_CLK1_PIN] = &msm8994_bb_clk1_pin,
- [RPM_SMD_BB_CLK1_A_PIN] = &msm8994_bb_clk1_a_pin,
- [RPM_SMD_BB_CLK2] = &msm8994_bb_clk2,
- [RPM_SMD_BB_CLK2_A] = &msm8994_bb_clk2_a,
- [RPM_SMD_BB_CLK2_PIN] = &msm8994_bb_clk2_pin,
- [RPM_SMD_BB_CLK2_A_PIN] = &msm8994_bb_clk2_a_pin,
- [RPM_SMD_DIV_CLK1] = &msm8994_div_clk1,
- [RPM_SMD_DIV_A_CLK1] = &msm8994_div_clk1_a,
- [RPM_SMD_DIV_CLK2] = &msm8994_div_clk2,
- [RPM_SMD_DIV_A_CLK2] = &msm8994_div_clk2_a,
- [RPM_SMD_DIV_CLK3] = &msm8994_div_clk3,
- [RPM_SMD_DIV_A_CLK3] = &msm8994_div_clk3_a,
- [RPM_SMD_IPA_CLK] = &msm8994_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8994_ipa_a_clk,
- [RPM_SMD_LN_BB_CLK] = &msm8994_ln_bb_clk,
- [RPM_SMD_LN_BB_A_CLK] = &msm8994_ln_bb_a_clk,
- [RPM_SMD_MMSSNOC_AHB_CLK] = &msm8994_mmssnoc_ahb_clk,
- [RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8994_mmssnoc_ahb_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8994_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8994_qdss_a_clk,
- [RPM_SMD_RF_CLK1] = &msm8994_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8994_rf_clk1_a,
- [RPM_SMD_RF_CLK2] = &msm8994_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8994_rf_clk2_a,
- [RPM_SMD_RF_CLK1_PIN] = &msm8994_rf_clk1_pin,
- [RPM_SMD_RF_CLK1_A_PIN] = &msm8994_rf_clk1_a_pin,
- [RPM_SMD_RF_CLK2_PIN] = &msm8994_rf_clk2_pin,
- [RPM_SMD_RF_CLK2_A_PIN] = &msm8994_rf_clk2_a_pin,
- [RPM_SMD_CE1_CLK] = &msm8994_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &msm8994_ce1_a_clk,
- [RPM_SMD_CE2_CLK] = &msm8994_ce2_clk,
- [RPM_SMD_CE2_A_CLK] = &msm8994_ce2_a_clk,
+ [RPM_SMD_PNOC_CLK] = &msm8916_pcnoc_clk,
+ [RPM_SMD_PNOC_A_CLK] = &msm8916_pcnoc_a_clk,
+ [RPM_SMD_OCMEMGX_CLK] = &msm8974_ocmemgx_clk,
+ [RPM_SMD_OCMEMGX_A_CLK] = &msm8974_ocmemgx_a_clk,
+ [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
+ [RPM_SMD_CNOC_CLK] = &msm8974_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &msm8974_cnoc_a_clk,
+ [RPM_SMD_GFX3D_CLK_SRC] = &msm8974_gfx3d_clk_src,
+ [RPM_SMD_GFX3D_A_CLK_SRC] = &msm8974_gfx3d_a_clk_src,
+ [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
+ [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1,
+ [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a,
+ [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
+ [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
+ [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2,
+ [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a,
+ [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
+ [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
+ [RPM_SMD_DIV_CLK1] = &msm8974_div_clk1,
+ [RPM_SMD_DIV_A_CLK1] = &msm8974_div_a_clk1,
+ [RPM_SMD_DIV_CLK2] = &msm8974_div_clk2,
+ [RPM_SMD_DIV_A_CLK2] = &msm8974_div_a_clk2,
+ [RPM_SMD_DIV_CLK3] = &msm8992_div_clk3,
+ [RPM_SMD_DIV_A_CLK3] = &msm8992_div_clk3_a,
+ [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
+ [RPM_SMD_LN_BB_CLK] = &msm8992_ln_bb_clk,
+ [RPM_SMD_LN_BB_A_CLK] = &msm8992_ln_bb_a_clk,
+ [RPM_SMD_MMSSNOC_AHB_CLK] = &msm8974_mmssnoc_ahb_clk,
+ [RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8974_mmssnoc_ahb_a_clk,
+ [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
+ [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
+ [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
+ [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin,
+ [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin,
+ [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin,
+ [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin,
+ [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
+ [RPM_SMD_CE2_CLK] = &msm8992_ce2_clk,
+ [RPM_SMD_CE2_A_CLK] = &msm8992_ce2_a_clk,
[RPM_SMD_CE3_CLK] = &msm8994_ce3_clk,
[RPM_SMD_CE3_A_CLK] = &msm8994_ce3_a_clk,
};
@@ -792,79 +721,58 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8994 = {
.num_clks = ARRAY_SIZE(msm8994_clks),
};
-/* msm8996 */
-DEFINE_CLK_SMD_RPM(msm8996, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8996, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
-DEFINE_CLK_SMD_RPM(msm8996, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
-DEFINE_CLK_SMD_RPM(msm8996, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8996, mmssnoc_axi_rpm_clk, mmssnoc_axi_rpm_a_clk,
QCOM_SMD_RPM_MMAXI_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8996, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8996, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre1_noc_clk, aggre1_noc_a_clk,
QCOM_SMD_RPM_AGGR_CLK, 1, 1000);
DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre2_noc_clk, aggre2_noc_a_clk,
QCOM_SMD_RPM_AGGR_CLK, 2, 1000);
-DEFINE_CLK_SMD_RPM_QDSS(msm8996, qdss_clk, qdss_a_clk,
- QCOM_SMD_RPM_MISC_CLK, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, bb_clk1, bb_clk1_a, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, bb_clk2, bb_clk2_a, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, rf_clk1, rf_clk1_a, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, rf_clk2, rf_clk2_a, 5);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, ln_bb_clk, ln_bb_a_clk, 8);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk1, div_clk1_a, 0xb);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk2, div_clk2_a, 0xc);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk3, div_clk3_a, 0xd);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, bb_clk1_pin, bb_clk1_a_pin, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, bb_clk2_pin, bb_clk2_a_pin, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, rf_clk1_pin, rf_clk1_a_pin, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, rf_clk2_pin, rf_clk2_a_pin, 5);
static struct clk_smd_rpm *msm8996_clks[] = {
- [RPM_SMD_PCNOC_CLK] = &msm8996_pcnoc_clk,
- [RPM_SMD_PCNOC_A_CLK] = &msm8996_pcnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &msm8996_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8996_snoc_a_clk,
- [RPM_SMD_CNOC_CLK] = &msm8996_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &msm8996_cnoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8996_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8996_bimc_a_clk,
+ [RPM_SMD_PCNOC_CLK] = &msm8916_pcnoc_clk,
+ [RPM_SMD_PCNOC_A_CLK] = &msm8916_pcnoc_a_clk,
+ [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
+ [RPM_SMD_CNOC_CLK] = &msm8974_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &msm8974_cnoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
[RPM_SMD_MMAXI_CLK] = &msm8996_mmssnoc_axi_rpm_clk,
[RPM_SMD_MMAXI_A_CLK] = &msm8996_mmssnoc_axi_rpm_a_clk,
- [RPM_SMD_IPA_CLK] = &msm8996_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8996_ipa_a_clk,
- [RPM_SMD_CE1_CLK] = &msm8996_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &msm8996_ce1_a_clk,
+ [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
+ [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
[RPM_SMD_AGGR1_NOC_CLK] = &msm8996_aggre1_noc_clk,
[RPM_SMD_AGGR1_NOC_A_CLK] = &msm8996_aggre1_noc_a_clk,
[RPM_SMD_AGGR2_NOC_CLK] = &msm8996_aggre2_noc_clk,
[RPM_SMD_AGGR2_NOC_A_CLK] = &msm8996_aggre2_noc_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8996_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8996_qdss_a_clk,
- [RPM_SMD_BB_CLK1] = &msm8996_bb_clk1,
- [RPM_SMD_BB_CLK1_A] = &msm8996_bb_clk1_a,
- [RPM_SMD_BB_CLK2] = &msm8996_bb_clk2,
- [RPM_SMD_BB_CLK2_A] = &msm8996_bb_clk2_a,
- [RPM_SMD_RF_CLK1] = &msm8996_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8996_rf_clk1_a,
- [RPM_SMD_RF_CLK2] = &msm8996_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8996_rf_clk2_a,
- [RPM_SMD_LN_BB_CLK] = &msm8996_ln_bb_clk,
- [RPM_SMD_LN_BB_A_CLK] = &msm8996_ln_bb_a_clk,
- [RPM_SMD_DIV_CLK1] = &msm8996_div_clk1,
- [RPM_SMD_DIV_A_CLK1] = &msm8996_div_clk1_a,
- [RPM_SMD_DIV_CLK2] = &msm8996_div_clk2,
- [RPM_SMD_DIV_A_CLK2] = &msm8996_div_clk2_a,
- [RPM_SMD_DIV_CLK3] = &msm8996_div_clk3,
- [RPM_SMD_DIV_A_CLK3] = &msm8996_div_clk3_a,
- [RPM_SMD_BB_CLK1_PIN] = &msm8996_bb_clk1_pin,
- [RPM_SMD_BB_CLK1_A_PIN] = &msm8996_bb_clk1_a_pin,
- [RPM_SMD_BB_CLK2_PIN] = &msm8996_bb_clk2_pin,
- [RPM_SMD_BB_CLK2_A_PIN] = &msm8996_bb_clk2_a_pin,
- [RPM_SMD_RF_CLK1_PIN] = &msm8996_rf_clk1_pin,
- [RPM_SMD_RF_CLK1_A_PIN] = &msm8996_rf_clk1_a_pin,
- [RPM_SMD_RF_CLK2_PIN] = &msm8996_rf_clk2_pin,
- [RPM_SMD_RF_CLK2_A_PIN] = &msm8996_rf_clk2_a_pin,
+ [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
+ [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1,
+ [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a,
+ [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2,
+ [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a,
+ [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
+ [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
+ [RPM_SMD_LN_BB_CLK] = &msm8992_ln_bb_clk,
+ [RPM_SMD_LN_BB_A_CLK] = &msm8992_ln_bb_a_clk,
+ [RPM_SMD_DIV_CLK1] = &msm8974_div_clk1,
+ [RPM_SMD_DIV_A_CLK1] = &msm8974_div_a_clk1,
+ [RPM_SMD_DIV_CLK2] = &msm8974_div_clk2,
+ [RPM_SMD_DIV_A_CLK2] = &msm8974_div_a_clk2,
+ [RPM_SMD_DIV_CLK3] = &msm8992_div_clk3,
+ [RPM_SMD_DIV_A_CLK3] = &msm8992_div_clk3_a,
+ [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
+ [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
+ [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
+ [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
+ [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin,
+ [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin,
+ [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin,
+ [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8996 = {
@@ -872,43 +780,29 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8996 = {
.num_clks = ARRAY_SIZE(msm8996_clks),
};
-/* QCS404 */
-DEFINE_CLK_SMD_RPM_QDSS(qcs404, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
-
-DEFINE_CLK_SMD_RPM(qcs404, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(qcs404, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
-
-DEFINE_CLK_SMD_RPM(qcs404, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
DEFINE_CLK_SMD_RPM(qcs404, bimc_gpu_clk, bimc_gpu_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
-
DEFINE_CLK_SMD_RPM(qcs404, qpic_clk, qpic_a_clk, QCOM_SMD_RPM_QPIC_CLK, 0);
-DEFINE_CLK_SMD_RPM(qcs404, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
-
-DEFINE_CLK_SMD_RPM_XO_BUFFER(qcs404, rf_clk1, rf_clk1_a, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(qcs404, rf_clk1_pin, rf_clk1_a_pin, 4);
-
-DEFINE_CLK_SMD_RPM_XO_BUFFER(qcs404, ln_bb_clk, ln_bb_a_clk, 8);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(qcs404, ln_bb_clk_pin, ln_bb_clk_a_pin, 8);
static struct clk_smd_rpm *qcs404_clks[] = {
- [RPM_SMD_QDSS_CLK] = &qcs404_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &qcs404_qdss_a_clk,
- [RPM_SMD_PNOC_CLK] = &qcs404_pnoc_clk,
- [RPM_SMD_PNOC_A_CLK] = &qcs404_pnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &qcs404_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &qcs404_snoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &qcs404_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &qcs404_bimc_a_clk,
+ [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
+ [RPM_SMD_PNOC_CLK] = &msm8916_pcnoc_clk,
+ [RPM_SMD_PNOC_A_CLK] = &msm8916_pcnoc_a_clk,
+ [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
[RPM_SMD_BIMC_GPU_CLK] = &qcs404_bimc_gpu_clk,
[RPM_SMD_BIMC_GPU_A_CLK] = &qcs404_bimc_gpu_a_clk,
[RPM_SMD_QPIC_CLK] = &qcs404_qpic_clk,
[RPM_SMD_QPIC_CLK_A] = &qcs404_qpic_a_clk,
- [RPM_SMD_CE1_CLK] = &qcs404_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &qcs404_ce1_a_clk,
- [RPM_SMD_RF_CLK1] = &qcs404_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &qcs404_rf_clk1_a,
- [RPM_SMD_LN_BB_CLK] = &qcs404_ln_bb_clk,
- [RPM_SMD_LN_BB_A_CLK] = &qcs404_ln_bb_a_clk,
+ [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
+ [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
+ [RPM_SMD_LN_BB_CLK] = &msm8992_ln_bb_clk,
+ [RPM_SMD_LN_BB_A_CLK] = &msm8992_ln_bb_a_clk,
};
static const struct rpm_smd_clk_desc rpm_clk_qcs404 = {
@@ -916,63 +810,47 @@ static const struct rpm_smd_clk_desc rpm_clk_qcs404 = {
.num_clks = ARRAY_SIZE(qcs404_clks),
};
-/* msm8998 */
-DEFINE_CLK_SMD_RPM(msm8998, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8998, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8998, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
-DEFINE_CLK_SMD_RPM(msm8998, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
-DEFINE_CLK_SMD_RPM(msm8998, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, div_clk1, div_clk1_a, 0xb);
-DEFINE_CLK_SMD_RPM(msm8998, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, ln_bb_clk1, ln_bb_clk1_a, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, ln_bb_clk2, ln_bb_clk2_a, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, ln_bb_clk3_pin, ln_bb_clk3_a_pin,
3);
-DEFINE_CLK_SMD_RPM(msm8998, mmssnoc_axi_rpm_clk, mmssnoc_axi_rpm_a_clk,
- QCOM_SMD_RPM_MMAXI_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8998, aggre1_noc_clk, aggre1_noc_a_clk,
QCOM_SMD_RPM_AGGR_CLK, 1);
DEFINE_CLK_SMD_RPM(msm8998, aggre2_noc_clk, aggre2_noc_a_clk,
QCOM_SMD_RPM_AGGR_CLK, 2);
-DEFINE_CLK_SMD_RPM_QDSS(msm8998, qdss_clk, qdss_a_clk,
- QCOM_SMD_RPM_MISC_CLK, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, rf_clk1, rf_clk1_a, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, rf_clk2_pin, rf_clk2_a_pin, 5);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, rf_clk3, rf_clk3_a, 6);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, rf_clk3_pin, rf_clk3_a_pin, 6);
static struct clk_smd_rpm *msm8998_clks[] = {
- [RPM_SMD_BIMC_CLK] = &msm8998_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8998_bimc_a_clk,
- [RPM_SMD_PCNOC_CLK] = &msm8998_pcnoc_clk,
- [RPM_SMD_PCNOC_A_CLK] = &msm8998_pcnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &msm8998_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8998_snoc_a_clk,
- [RPM_SMD_CNOC_CLK] = &msm8998_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &msm8998_cnoc_a_clk,
- [RPM_SMD_CE1_CLK] = &msm8998_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &msm8998_ce1_a_clk,
- [RPM_SMD_DIV_CLK1] = &msm8998_div_clk1,
- [RPM_SMD_DIV_A_CLK1] = &msm8998_div_clk1_a,
- [RPM_SMD_IPA_CLK] = &msm8998_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8998_ipa_a_clk,
- [RPM_SMD_LN_BB_CLK1] = &msm8998_ln_bb_clk1,
- [RPM_SMD_LN_BB_CLK1_A] = &msm8998_ln_bb_clk1_a,
- [RPM_SMD_LN_BB_CLK2] = &msm8998_ln_bb_clk2,
- [RPM_SMD_LN_BB_CLK2_A] = &msm8998_ln_bb_clk2_a,
+ [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
+ [RPM_SMD_PCNOC_CLK] = &msm8916_pcnoc_clk,
+ [RPM_SMD_PCNOC_A_CLK] = &msm8916_pcnoc_a_clk,
+ [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
+ [RPM_SMD_CNOC_CLK] = &msm8974_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &msm8974_cnoc_a_clk,
+ [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
+ [RPM_SMD_DIV_CLK1] = &msm8974_div_clk1,
+ [RPM_SMD_DIV_A_CLK1] = &msm8974_div_a_clk1,
+ [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
+ [RPM_SMD_LN_BB_CLK1] = &msm8916_bb_clk1,
+ [RPM_SMD_LN_BB_CLK1_A] = &msm8916_bb_clk1_a,
+ [RPM_SMD_LN_BB_CLK2] = &msm8916_bb_clk2,
+ [RPM_SMD_LN_BB_CLK2_A] = &msm8916_bb_clk2_a,
[RPM_SMD_LN_BB_CLK3_PIN] = &msm8998_ln_bb_clk3_pin,
[RPM_SMD_LN_BB_CLK3_A_PIN] = &msm8998_ln_bb_clk3_a_pin,
- [RPM_SMD_MMAXI_CLK] = &msm8998_mmssnoc_axi_rpm_clk,
- [RPM_SMD_MMAXI_A_CLK] = &msm8998_mmssnoc_axi_rpm_a_clk,
+ [RPM_SMD_MMAXI_CLK] = &msm8996_mmssnoc_axi_rpm_clk,
+ [RPM_SMD_MMAXI_A_CLK] = &msm8996_mmssnoc_axi_rpm_a_clk,
[RPM_SMD_AGGR1_NOC_CLK] = &msm8998_aggre1_noc_clk,
[RPM_SMD_AGGR1_NOC_A_CLK] = &msm8998_aggre1_noc_a_clk,
[RPM_SMD_AGGR2_NOC_CLK] = &msm8998_aggre2_noc_clk,
[RPM_SMD_AGGR2_NOC_A_CLK] = &msm8998_aggre2_noc_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8998_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8998_qdss_a_clk,
- [RPM_SMD_RF_CLK1] = &msm8998_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8998_rf_clk1_a,
- [RPM_SMD_RF_CLK2_PIN] = &msm8998_rf_clk2_pin,
- [RPM_SMD_RF_CLK2_A_PIN] = &msm8998_rf_clk2_a_pin,
+ [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
+ [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
+ [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin,
+ [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin,
[RPM_SMD_RF_CLK3] = &msm8998_rf_clk3,
[RPM_SMD_RF_CLK3_A] = &msm8998_rf_clk3_a,
[RPM_SMD_RF_CLK3_PIN] = &msm8998_rf_clk3_pin,
@@ -984,72 +862,48 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8998 = {
.num_clks = ARRAY_SIZE(msm8998_clks),
};
-/* sdm660 */
DEFINE_CLK_SMD_RPM_BRANCH(sdm660, bi_tcxo, bi_tcxo_a, QCOM_SMD_RPM_MISC_CLK, 0,
19200000);
-DEFINE_CLK_SMD_RPM(sdm660, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
-DEFINE_CLK_SMD_RPM(sdm660, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
-DEFINE_CLK_SMD_RPM(sdm660, cnoc_periph_clk, cnoc_periph_a_clk,
- QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(sdm660, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
-DEFINE_CLK_SMD_RPM(sdm660, mmssnoc_axi_clk, mmssnoc_axi_a_clk,
- QCOM_SMD_RPM_MMAXI_CLK, 0);
-DEFINE_CLK_SMD_RPM(sdm660, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
-DEFINE_CLK_SMD_RPM(sdm660, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
-DEFINE_CLK_SMD_RPM(sdm660, aggre2_noc_clk, aggre2_noc_a_clk,
- QCOM_SMD_RPM_AGGR_CLK, 2);
-DEFINE_CLK_SMD_RPM_QDSS(sdm660, qdss_clk, qdss_a_clk,
- QCOM_SMD_RPM_MISC_CLK, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(sdm660, rf_clk1, rf_clk1_a, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(sdm660, div_clk1, div_clk1_a, 11);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(sdm660, ln_bb_clk1, ln_bb_clk1_a, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(sdm660, ln_bb_clk2, ln_bb_clk2_a, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER(sdm660, ln_bb_clk3, ln_bb_clk3_a, 3);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(sdm660, ln_bb_clk3_pin, ln_bb_clk3_pin_a, 3);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(sdm660, rf_clk1_pin, rf_clk1_a_pin, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(sdm660, ln_bb_clk1_pin,
- ln_bb_clk1_pin_a, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(sdm660, ln_bb_clk2_pin,
- ln_bb_clk2_pin_a, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(sdm660, ln_bb_clk3_pin,
- ln_bb_clk3_pin_a, 3);
static struct clk_smd_rpm *sdm660_clks[] = {
[RPM_SMD_XO_CLK_SRC] = &sdm660_bi_tcxo,
[RPM_SMD_XO_A_CLK_SRC] = &sdm660_bi_tcxo_a,
- [RPM_SMD_SNOC_CLK] = &sdm660_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &sdm660_snoc_a_clk,
- [RPM_SMD_CNOC_CLK] = &sdm660_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &sdm660_cnoc_a_clk,
- [RPM_SMD_CNOC_PERIPH_CLK] = &sdm660_cnoc_periph_clk,
- [RPM_SMD_CNOC_PERIPH_A_CLK] = &sdm660_cnoc_periph_a_clk,
- [RPM_SMD_BIMC_CLK] = &sdm660_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &sdm660_bimc_a_clk,
- [RPM_SMD_MMSSNOC_AXI_CLK] = &sdm660_mmssnoc_axi_clk,
- [RPM_SMD_MMSSNOC_AXI_CLK_A] = &sdm660_mmssnoc_axi_a_clk,
- [RPM_SMD_IPA_CLK] = &sdm660_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &sdm660_ipa_a_clk,
- [RPM_SMD_CE1_CLK] = &sdm660_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &sdm660_ce1_a_clk,
- [RPM_SMD_AGGR2_NOC_CLK] = &sdm660_aggre2_noc_clk,
- [RPM_SMD_AGGR2_NOC_A_CLK] = &sdm660_aggre2_noc_a_clk,
- [RPM_SMD_QDSS_CLK] = &sdm660_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &sdm660_qdss_a_clk,
- [RPM_SMD_RF_CLK1] = &sdm660_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &sdm660_rf_clk1_a,
- [RPM_SMD_DIV_CLK1] = &sdm660_div_clk1,
- [RPM_SMD_DIV_A_CLK1] = &sdm660_div_clk1_a,
- [RPM_SMD_LN_BB_CLK] = &sdm660_ln_bb_clk1,
- [RPM_SMD_LN_BB_A_CLK] = &sdm660_ln_bb_clk1_a,
- [RPM_SMD_LN_BB_CLK2] = &sdm660_ln_bb_clk2,
- [RPM_SMD_LN_BB_CLK2_A] = &sdm660_ln_bb_clk2_a,
+ [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
+ [RPM_SMD_CNOC_CLK] = &msm8974_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &msm8974_cnoc_a_clk,
+ [RPM_SMD_CNOC_PERIPH_CLK] = &msm8916_pcnoc_clk,
+ [RPM_SMD_CNOC_PERIPH_A_CLK] = &msm8916_pcnoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
+ [RPM_SMD_MMSSNOC_AXI_CLK] = &msm8996_mmssnoc_axi_rpm_clk,
+ [RPM_SMD_MMSSNOC_AXI_CLK_A] = &msm8996_mmssnoc_axi_rpm_a_clk,
+ [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
+ [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
+ [RPM_SMD_AGGR2_NOC_CLK] = &msm8998_aggre2_noc_clk,
+ [RPM_SMD_AGGR2_NOC_A_CLK] = &msm8998_aggre2_noc_a_clk,
+ [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
+ [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
+ [RPM_SMD_DIV_CLK1] = &msm8974_div_clk1,
+ [RPM_SMD_DIV_A_CLK1] = &msm8974_div_a_clk1,
+ [RPM_SMD_LN_BB_CLK] = &msm8916_bb_clk1,
+ [RPM_SMD_LN_BB_A_CLK] = &msm8916_bb_clk1_a,
+ [RPM_SMD_LN_BB_CLK2] = &msm8916_bb_clk2,
+ [RPM_SMD_LN_BB_CLK2_A] = &msm8916_bb_clk2_a,
[RPM_SMD_LN_BB_CLK3] = &sdm660_ln_bb_clk3,
[RPM_SMD_LN_BB_CLK3_A] = &sdm660_ln_bb_clk3_a,
- [RPM_SMD_RF_CLK1_PIN] = &sdm660_rf_clk1_pin,
- [RPM_SMD_RF_CLK1_A_PIN] = &sdm660_rf_clk1_a_pin,
- [RPM_SMD_LN_BB_CLK1_PIN] = &sdm660_ln_bb_clk1_pin,
- [RPM_SMD_LN_BB_CLK1_A_PIN] = &sdm660_ln_bb_clk1_pin_a,
- [RPM_SMD_LN_BB_CLK2_PIN] = &sdm660_ln_bb_clk2_pin,
- [RPM_SMD_LN_BB_CLK2_A_PIN] = &sdm660_ln_bb_clk2_pin_a,
+ [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin,
+ [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin,
+ [RPM_SMD_LN_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
+ [RPM_SMD_LN_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
+ [RPM_SMD_LN_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
+ [RPM_SMD_LN_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
[RPM_SMD_LN_BB_CLK3_PIN] = &sdm660_ln_bb_clk3_pin,
[RPM_SMD_LN_BB_CLK3_A_PIN] = &sdm660_ln_bb_clk3_pin_a,
};
@@ -1060,6 +914,7 @@ static const struct rpm_smd_clk_desc rpm_clk_sdm660 = {
};
static const struct of_device_id rpm_smd_clk_match_table[] = {
+ { .compatible = "qcom,rpmcc-msm8226", .data = &rpm_clk_msm8974 },
{ .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 },
{ .compatible = "qcom,rpmcc-msm8936", .data = &rpm_clk_msm8936 },
{ .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974 },
diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c
index de09cd5c209f..601c7c0ba483 100644
--- a/drivers/clk/qcom/dispcc-sm8250.c
+++ b/drivers/clk/qcom/dispcc-sm8250.c
@@ -26,6 +26,8 @@ enum {
P_DISP_CC_PLL1_OUT_MAIN,
P_DP_PHY_PLL_LINK_CLK,
P_DP_PHY_PLL_VCO_DIV_CLK,
+ P_EDP_PHY_PLL_LINK_CLK,
+ P_EDP_PHY_PLL_VCO_DIV_CLK,
P_DSI0_PHY_PLL_OUT_BYTECLK,
P_DSI0_PHY_PLL_OUT_DSICLK,
P_DSI1_PHY_PLL_OUT_BYTECLK,
@@ -134,6 +136,18 @@ static const struct clk_parent_data disp_cc_parent_data_3[] = {
{ .hw = &disp_cc_pll1.clkr.hw },
};
+static const struct parent_map disp_cc_parent_map_4[] = {
+ { P_BI_TCXO, 0 },
+ { P_EDP_PHY_PLL_LINK_CLK, 1 },
+ { P_EDP_PHY_PLL_VCO_DIV_CLK, 2},
+};
+
+static const struct clk_parent_data disp_cc_parent_data_4[] = {
+ { .fw_name = "bi_tcxo" },
+ { .fw_name = "edp_phy_pll_link_clk" },
+ { .fw_name = "edp_phy_pll_vco_div_clk" },
+};
+
static const struct parent_map disp_cc_parent_map_5[] = {
{ P_BI_TCXO, 0 },
{ P_DISP_CC_PLL0_OUT_MAIN, 1 },
@@ -158,6 +172,18 @@ static const struct clk_parent_data disp_cc_parent_data_6[] = {
{ .fw_name = "dsi1_phy_pll_out_dsiclk" },
};
+static const struct parent_map disp_cc_parent_map_7[] = {
+ { P_BI_TCXO, 0 },
+ { P_DISP_CC_PLL1_OUT_MAIN, 4 },
+ /* { P_DISP_CC_PLL1_OUT_EVEN, 5 }, */
+};
+
+static const struct clk_parent_data disp_cc_parent_data_7[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &disp_cc_pll1.clkr.hw },
+ /* { .hw = &disp_cc_pll1_out_even.clkr.hw }, */
+};
+
static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src[] = {
F(19200000, P_BI_TCXO, 1, 0, 0),
F(37500000, P_DISP_CC_PLL1_OUT_MAIN, 16, 0, 0),
@@ -261,7 +287,7 @@ static struct clk_rcg2 disp_cc_mdss_dp_link1_clk_src = {
.name = "disp_cc_mdss_dp_link1_clk_src",
.parent_data = disp_cc_parent_data_0,
.num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
- .ops = &clk_rcg2_ops,
+ .ops = &clk_byte2_ops,
},
};
@@ -275,7 +301,7 @@ static struct clk_rcg2 disp_cc_mdss_dp_link_clk_src = {
.name = "disp_cc_mdss_dp_link_clk_src",
.parent_data = disp_cc_parent_data_0,
.num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
- .ops = &clk_rcg2_ops,
+ .ops = &clk_byte2_ops,
},
};
@@ -318,6 +344,153 @@ static struct clk_rcg2 disp_cc_mdss_dp_pixel_clk_src = {
},
};
+static struct clk_rcg2 disp_cc_mdss_edp_aux_clk_src = {
+ .cmd_rcgr = 0x228c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_1,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "disp_cc_mdss_edp_aux_clk_src",
+ .parent_data = disp_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_edp_gtc_clk_src = {
+ .cmd_rcgr = 0x22a4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_7,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "disp_cc_mdss_edp_gtc_clk_src",
+ .parent_data = disp_cc_parent_data_7,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_7),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_edp_link_clk_src = {
+ .cmd_rcgr = 0x2270,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_4,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "disp_cc_mdss_edp_link_clk_src",
+ .parent_data = disp_cc_parent_data_4,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_byte2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_edp_pixel_clk_src = {
+ .cmd_rcgr = 0x2258,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_4,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "disp_cc_mdss_edp_pixel_clk_src",
+ .parent_data = disp_cc_parent_data_4,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_4),
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_branch disp_cc_mdss_edp_aux_clk = {
+ .halt_reg = 0x2078,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2078,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "disp_cc_mdss_edp_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &disp_cc_mdss_edp_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_edp_gtc_clk = {
+ .halt_reg = 0x207c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x207c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "disp_cc_mdss_edp_gtc_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &disp_cc_mdss_edp_gtc_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_edp_link_clk = {
+ .halt_reg = 0x2070,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2070,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "disp_cc_mdss_edp_link_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &disp_cc_mdss_edp_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_edp_link_intf_clk = {
+ .halt_reg = 0x2074,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2074,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "disp_cc_mdss_edp_link_intf_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &disp_cc_mdss_edp_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_edp_pixel_clk = {
+ .halt_reg = 0x206c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x206c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "disp_cc_mdss_edp_pixel_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &disp_cc_mdss_edp_pixel_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = {
.cmd_rcgr = 0x2148,
.mnd_width = 0,
@@ -987,6 +1160,15 @@ static struct clk_regmap *disp_cc_sm8250_clocks[] = {
[DISP_CC_MDSS_DP_PIXEL2_CLK_SRC] = &disp_cc_mdss_dp_pixel2_clk_src.clkr,
[DISP_CC_MDSS_DP_PIXEL_CLK] = &disp_cc_mdss_dp_pixel_clk.clkr,
[DISP_CC_MDSS_DP_PIXEL_CLK_SRC] = &disp_cc_mdss_dp_pixel_clk_src.clkr,
+ [DISP_CC_MDSS_EDP_AUX_CLK] = &disp_cc_mdss_edp_aux_clk.clkr,
+ [DISP_CC_MDSS_EDP_AUX_CLK_SRC] = &disp_cc_mdss_edp_aux_clk_src.clkr,
+ [DISP_CC_MDSS_EDP_GTC_CLK] = &disp_cc_mdss_edp_gtc_clk.clkr,
+ [DISP_CC_MDSS_EDP_GTC_CLK_SRC] = &disp_cc_mdss_edp_gtc_clk_src.clkr,
+ [DISP_CC_MDSS_EDP_LINK_CLK] = &disp_cc_mdss_edp_link_clk.clkr,
+ [DISP_CC_MDSS_EDP_LINK_CLK_SRC] = &disp_cc_mdss_edp_link_clk_src.clkr,
+ [DISP_CC_MDSS_EDP_LINK_INTF_CLK] = &disp_cc_mdss_edp_link_intf_clk.clkr,
+ [DISP_CC_MDSS_EDP_PIXEL_CLK] = &disp_cc_mdss_edp_pixel_clk.clkr,
+ [DISP_CC_MDSS_EDP_PIXEL_CLK_SRC] = &disp_cc_mdss_edp_pixel_clk_src.clkr,
[DISP_CC_MDSS_ESC0_CLK] = &disp_cc_mdss_esc0_clk.clkr,
[DISP_CC_MDSS_ESC0_CLK_SRC] = &disp_cc_mdss_esc0_clk_src.clkr,
[DISP_CC_MDSS_ESC1_CLK] = &disp_cc_mdss_esc1_clk.clkr,
@@ -1037,6 +1219,7 @@ static const struct qcom_cc_desc disp_cc_sm8250_desc = {
};
static const struct of_device_id disp_cc_sm8250_match_table[] = {
+ { .compatible = "qcom,sc8180x-dispcc" },
{ .compatible = "qcom,sm8150-dispcc" },
{ .compatible = "qcom,sm8250-dispcc" },
{ }
@@ -1053,7 +1236,8 @@ static int disp_cc_sm8250_probe(struct platform_device *pdev)
/* note: trion == lucid, except for the prepare() op */
BUILD_BUG_ON(CLK_ALPHA_PLL_TYPE_TRION != CLK_ALPHA_PLL_TYPE_LUCID);
- if (of_device_is_compatible(pdev->dev.of_node, "qcom,sm8150-dispcc")) {
+ if (of_device_is_compatible(pdev->dev.of_node, "qcom,sc8180x-dispcc") ||
+ of_device_is_compatible(pdev->dev.of_node, "qcom,sm8150-dispcc")) {
disp_cc_pll0_config.config_ctl_hi_val = 0x00002267;
disp_cc_pll0_config.config_ctl_hi1_val = 0x00000024;
disp_cc_pll0_config.user_ctl_hi1_val = 0x000000D0;
diff --git a/drivers/clk/qcom/gcc-mdm9607.c b/drivers/clk/qcom/gcc-mdm9607.c
new file mode 100644
index 000000000000..4c9078e99bb3
--- /dev/null
+++ b/drivers/clk/qcom/gcc-mdm9607.c
@@ -0,0 +1,1632 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, Konrad Dybcio <konrad.dybcio@somainline.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/clock/qcom,gcc-mdm9607.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-alpha-pll.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "reset.h"
+#include "gdsc.h"
+
+enum {
+ P_XO,
+ P_BIMC,
+ P_GPLL0,
+ P_GPLL1,
+ P_GPLL2,
+ P_SLEEP_CLK,
+};
+
+static struct clk_alpha_pll gpll0_early = {
+ .offset = 0x21000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x45000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data)
+ {
+ .name = "gpll0_early",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "xo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll_postdiv gpll0 = {
+ .offset = 0x21000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr.hw.init = &(struct clk_init_data)
+ {
+ .name = "gpll0",
+ .parent_hws = (const struct clk_hw *[]){ &gpll0_early.clkr.hw },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ },
+};
+
+static const struct parent_map gcc_xo_gpll0_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+};
+
+static const struct clk_parent_data gcc_xo_gpll0[] = {
+ { .fw_name = "xo" },
+ { .hw = &gpll0.clkr.hw },
+};
+
+static struct clk_pll gpll1 = {
+ .l_reg = 0x20004,
+ .m_reg = 0x20008,
+ .n_reg = 0x2000c,
+ .config_reg = 0x20010,
+ .mode_reg = 0x20000,
+ .status_reg = 0x2001c,
+ .status_bit = 17,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll1",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "xo",
+ },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+static struct clk_regmap gpll1_vote = {
+ .enable_reg = 0x45000,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll1_vote",
+ .parent_hws = (const struct clk_hw *[]){ &gpll1.clkr.hw },
+ .num_parents = 1,
+ .ops = &clk_pll_vote_ops,
+ },
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll1_sleep_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL1, 2 },
+ { P_SLEEP_CLK, 6 },
+};
+
+static const struct clk_parent_data gcc_xo_gpll0_gpll1_sleep[] = {
+ { .fw_name = "xo" },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll1_vote.hw },
+ { .fw_name = "sleep_clk" },
+};
+
+static struct clk_alpha_pll gpll2_early = {
+ .offset = 0x25000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x45000,
+ .enable_mask = BIT(3), /* Yeah, apparently it's not 2 */
+ .hw.init = &(struct clk_init_data)
+ {
+ .name = "gpll2_early",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "xo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll_postdiv gpll2 = {
+ .offset = 0x25000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr.hw.init = &(struct clk_init_data)
+ {
+ .name = "gpll2",
+ .parent_hws = (const struct clk_hw *[]){ &gpll2_early.clkr.hw },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ },
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll2_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL2, 2 },
+};
+
+static const struct clk_parent_data gcc_xo_gpll0_gpll2[] = {
+ { .fw_name = "xo" },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll2.clkr.hw },
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll1_gpll2_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL1, 2 },
+ { P_GPLL2, 3 },
+};
+
+static const struct clk_parent_data gcc_xo_gpll0_gpll1_gpll2[] = {
+ { .fw_name = "xo" },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll1_vote.hw },
+ { .hw = &gpll2.clkr.hw },
+};
+
+static const struct freq_tbl ftbl_apss_ahb_clk[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(50000000, P_GPLL0, 16, 0, 0),
+ F(100000000, P_GPLL0, 8, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 apss_ahb_clk_src = {
+ .cmd_rcgr = 0x46000,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_apss_ahb_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "apss_ahb_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_pll bimc_pll = {
+ .l_reg = 0x23004,
+ .m_reg = 0x23008,
+ .n_reg = 0x2300c,
+ .config_reg = 0x23010,
+ .mode_reg = 0x23000,
+ .status_reg = 0x2301c,
+ .status_bit = 17,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "bimc_pll",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "xo",
+ },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+static struct clk_regmap bimc_pll_vote = {
+ .enable_reg = 0x45000,
+ .enable_mask = BIT(3),
+ .hw.init = &(struct clk_init_data){
+ .name = "bimc_pll_vote",
+ .parent_hws = (const struct clk_hw *[]){ &bimc_pll.clkr.hw },
+ .num_parents = 1,
+ .ops = &clk_pll_vote_ops,
+ },
+};
+
+static const struct parent_map gcc_xo_gpll0_bimc_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_BIMC, 2 },
+};
+
+static const struct clk_parent_data gcc_xo_gpll0_bimc[] = {
+ { .fw_name = "xo" },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &bimc_pll_vote.hw },
+};
+
+static const struct freq_tbl ftbl_pcnoc_bfdcd_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(50000000, P_GPLL0, 16, 0, 0),
+ F(100000000, P_GPLL0, 8, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 pcnoc_bfdcd_clk_src = {
+ .cmd_rcgr = 0x27000,
+ .freq_tbl = ftbl_pcnoc_bfdcd_clk_src,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_bimc_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pcnoc_bfdcd_clk_src",
+ .parent_data = gcc_xo_gpll0_bimc,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0_bimc),
+ .ops = &clk_rcg2_ops,
+ .flags = CLK_IS_CRITICAL,
+ },
+};
+
+static struct clk_rcg2 system_noc_bfdcd_clk_src = {
+ .cmd_rcgr = 0x26004,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_bimc_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "system_noc_bfdcd_clk_src",
+ .parent_data = gcc_xo_gpll0_bimc,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0_bimc),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_blsp1_qup1_6_i2c_apps_clk[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(50000000, P_GPLL0, 16, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x200c,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup1_i2c_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_blsp1_qup1_6_spi_apps_clk[] = {
+ F(960000, P_XO, 10, 1, 2),
+ F(4800000, P_XO, 4, 0, 0),
+ F(9600000, P_XO, 2, 0, 0),
+ F(16000000, P_GPLL0, 10, 1, 5),
+ F(19200000, P_XO, 1, 0, 0),
+ F(25000000, P_GPLL0, 16, 1, 2),
+ F(50000000, P_GPLL0, 16, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
+ .cmd_rcgr = 0x2024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup1_spi_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x3000,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup2_i2c_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
+ .cmd_rcgr = 0x3014,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup2_spi_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x4000,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup3_i2c_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = {
+ .cmd_rcgr = 0x4024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup3_spi_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x5000,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup4_i2c_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = {
+ .cmd_rcgr = 0x5024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup4_spi_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup5_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x6000,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup5_i2c_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup5_spi_apps_clk_src = {
+ .cmd_rcgr = 0x6024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup5_spi_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup6_i2c_apps_clk_src = {
+ .cmd_rcgr = 0x7000,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup6_i2c_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_qup6_spi_apps_clk_src = {
+ .cmd_rcgr = 0x7024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_qup6_spi_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_blsp1_uart1_6_apps_clk[] = {
+ F(3686400, P_GPLL0, 1, 72, 15625),
+ F(7372800, P_GPLL0, 1, 144, 15625),
+ F(14745600, P_GPLL0, 1, 288, 15625),
+ F(16000000, P_GPLL0, 10, 1, 5),
+ F(19200000, P_XO, 1, 0, 0),
+ F(24000000, P_GPLL0, 1, 3, 100),
+ F(25000000, P_GPLL0, 16, 1, 2),
+ F(32000000, P_GPLL0, 1, 1, 25),
+ F(40000000, P_GPLL0, 1, 1, 20),
+ F(46400000, P_GPLL0, 1, 29, 500),
+ F(48000000, P_GPLL0, 1, 3, 50),
+ F(51200000, P_GPLL0, 1, 8, 125),
+ F(56000000, P_GPLL0, 1, 7, 100),
+ F(58982400, P_GPLL0, 1, 1152, 15625),
+ F(60000000, P_GPLL0, 1, 3, 40),
+ { }
+};
+
+static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
+ .cmd_rcgr = 0x2044,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart1_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_uart2_apps_clk_src = {
+ .cmd_rcgr = 0x3034,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart2_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_uart3_apps_clk_src = {
+ .cmd_rcgr = 0x4044,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart3_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_uart4_apps_clk_src = {
+ .cmd_rcgr = 0x5044,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart4_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_uart5_apps_clk_src = {
+ .cmd_rcgr = 0x6044,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart5_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 blsp1_uart6_apps_clk_src = {
+ .cmd_rcgr = 0x6044,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "blsp1_uart6_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_crypto_clk[] = {
+ F(50000000, P_GPLL0, 16, 0, 0),
+ F(80000000, P_GPLL0, 10, 0, 0),
+ F(100000000, P_GPLL0, 8, 0, 0),
+ F(160000000, P_GPLL0, 5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 crypto_clk_src = {
+ .cmd_rcgr = 0x16004,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_crypto_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "crypto_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_gp1_3_clk[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gp1_clk_src = {
+ .cmd_rcgr = 0x8004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll1_sleep_map,
+ .freq_tbl = ftbl_gcc_gp1_3_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gp1_clk_src",
+ .parent_data = gcc_xo_gpll0_gpll1_sleep,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll1_sleep),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gp2_clk_src = {
+ .cmd_rcgr = 0x09004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll1_sleep_map,
+ .freq_tbl = ftbl_gcc_gp1_3_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gp2_clk_src",
+ .parent_data = gcc_xo_gpll0_gpll1_sleep,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll1_sleep),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gp3_clk_src = {
+ .cmd_rcgr = 0x0a004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll1_sleep_map,
+ .freq_tbl = ftbl_gcc_gp1_3_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gp3_clk_src",
+ .parent_data = gcc_xo_gpll0_gpll1_sleep,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll1_sleep),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pdm2_clk[] = {
+ F(64000000, P_GPLL0, 12.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 pdm2_clk_src = {
+ .cmd_rcgr = 0x44010,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_pdm2_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pdm2_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc_apps_clk[] = {
+ F(144000, P_XO, 16, 3, 25),
+ F(400000, P_XO, 12, 1, 4),
+ F(20000000, P_GPLL0, 10, 1, 4),
+ F(25000000, P_GPLL0, 16, 1, 2),
+ F(50000000, P_GPLL0, 16, 0, 0),
+ F(100000000, P_GPLL0, 8, 0, 0),
+ F(177770000, P_GPLL0, 4.5, 0, 0),
+ F(200000000, P_GPLL0, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 sdcc1_apps_clk_src = {
+ .cmd_rcgr = 0x42004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_sdcc_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "sdcc1_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_floor_ops,
+ },
+};
+
+static struct clk_rcg2 sdcc2_apps_clk_src = {
+ .cmd_rcgr = 0x43004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_sdcc_apps_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "sdcc2_apps_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_floor_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_apss_tcu_clk[] = {
+ F(155000000, P_GPLL2, 6, 0, 0),
+ F(310000000, P_GPLL2, 3, 0, 0),
+ F(400000000, P_GPLL0, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 apss_tcu_clk_src = {
+ .cmd_rcgr = 0x1207c,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll1_gpll2_map,
+ .freq_tbl = ftbl_gcc_apss_tcu_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "apss_tcu_clk_src",
+ .parent_data = gcc_xo_gpll0_gpll1_gpll2,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb_hs_system_clk[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(57140000, P_GPLL0, 14, 0, 0),
+ F(69565000, P_GPLL0, 11.5, 0, 0),
+ F(133330000, P_GPLL0, 6, 0, 0),
+ F(177778000, P_GPLL0, 4.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb_hs_system_clk_src = {
+ .cmd_rcgr = 0x41010,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_usb_hs_system_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb_hs_system_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = 2,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_usb_hsic_clk_src[] = {
+ F(480000000, P_GPLL2, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb_hsic_clk_src = {
+ .cmd_rcgr = 0x3d018,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_gpll2_map,
+ .freq_tbl = ftbl_usb_hsic_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb_hsic_clk_src",
+ .parent_data = gcc_xo_gpll0_gpll2,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_usb_hsic_io_cal_clk_src[] = {
+ F(9600000, P_XO, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb_hsic_io_cal_clk_src = {
+ .cmd_rcgr = 0x3d030,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_usb_hsic_io_cal_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb_hsic_io_cal_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_usb_hsic_system_clk_src[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ F(57140000, P_GPLL0, 14, 0, 0),
+ F(133330000, P_GPLL0, 6, 0, 0),
+ F(177778000, P_GPLL0, 4.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 usb_hsic_system_clk_src = {
+ .cmd_rcgr = 0x3d000,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_usb_hsic_system_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb_hsic_system_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_branch gcc_blsp1_ahb_clk = {
+ .halt_reg = 0x1008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(10),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_ahb_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_sleep_clk = {
+ .halt_reg = 0x1004,
+ .clkr = {
+ .enable_reg = 0x1004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_sleep_clk",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "sleep_clk",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = {
+ .halt_reg = 0x2008,
+ .clkr = {
+ .enable_reg = 0x2008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup1_i2c_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_qup1_i2c_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = {
+ .halt_reg = 0x2004,
+ .clkr = {
+ .enable_reg = 0x2004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup1_spi_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_qup1_spi_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = {
+ .halt_reg = 0x3010,
+ .clkr = {
+ .enable_reg = 0x3010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup2_i2c_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_qup2_i2c_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = {
+ .halt_reg = 0x300c,
+ .clkr = {
+ .enable_reg = 0x300c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup2_spi_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_qup2_spi_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = {
+ .halt_reg = 0x4020,
+ .clkr = {
+ .enable_reg = 0x4020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup3_i2c_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_qup3_i2c_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = {
+ .halt_reg = 0x401c,
+ .clkr = {
+ .enable_reg = 0x401c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup3_spi_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_qup3_spi_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = {
+ .halt_reg = 0x5020,
+ .clkr = {
+ .enable_reg = 0x5020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup4_i2c_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_qup4_i2c_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = {
+ .halt_reg = 0x501c,
+ .clkr = {
+ .enable_reg = 0x501c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup4_spi_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_qup4_spi_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup5_i2c_apps_clk = {
+ .halt_reg = 0x6020,
+ .clkr = {
+ .enable_reg = 0x6020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup5_i2c_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_qup5_i2c_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup5_spi_apps_clk = {
+ .halt_reg = 0x601c,
+ .clkr = {
+ .enable_reg = 0x601c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup5_spi_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_qup5_spi_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup6_i2c_apps_clk = {
+ .halt_reg = 0x7020,
+ .clkr = {
+ .enable_reg = 0x7020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup6_i2c_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_qup6_i2c_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_qup6_spi_apps_clk = {
+ .halt_reg = 0x701c,
+ .clkr = {
+ .enable_reg = 0x701c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_qup6_spi_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_qup6_spi_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart1_apps_clk = {
+ .halt_reg = 0x203c,
+ .clkr = {
+ .enable_reg = 0x203c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart1_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_uart1_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart2_apps_clk = {
+ .halt_reg = 0x302c,
+ .clkr = {
+ .enable_reg = 0x302c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart2_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_uart2_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart3_apps_clk = {
+ .halt_reg = 0x403c,
+ .clkr = {
+ .enable_reg = 0x403c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart3_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_uart3_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart4_apps_clk = {
+ .halt_reg = 0x503c,
+ .clkr = {
+ .enable_reg = 0x503c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart4_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_uart4_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart5_apps_clk = {
+ .halt_reg = 0x603c,
+ .clkr = {
+ .enable_reg = 0x603c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart5_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_uart5_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_blsp1_uart6_apps_clk = {
+ .halt_reg = 0x703c,
+ .clkr = {
+ .enable_reg = 0x703c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_blsp1_uart6_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &blsp1_uart6_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+ .halt_reg = 0x1300c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(7),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_boot_rom_ahb_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_crypto_ahb_clk = {
+ .halt_reg = 0x16024,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_crypto_ahb_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_crypto_axi_clk = {
+ .halt_reg = 0x16020,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_crypto_axi_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_crypto_clk = {
+ .halt_reg = 0x1601c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(2),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_crypto_clk",
+ .parent_hws = (const struct clk_hw *[]){ &crypto_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp1_clk = {
+ .halt_reg = 0x08000,
+ .clkr = {
+ .enable_reg = 0x08000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp1_clk",
+ .parent_hws = (const struct clk_hw *[]){ &gp1_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp2_clk = {
+ .halt_reg = 0x09000,
+ .clkr = {
+ .enable_reg = 0x09000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp2_clk",
+ .parent_hws = (const struct clk_hw *[]){ &gp2_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp3_clk = {
+ .halt_reg = 0x0a000,
+ .clkr = {
+ .enable_reg = 0x0a000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp3_clk",
+ .parent_hws = (const struct clk_hw *[]){ &gp3_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mss_cfg_ahb_clk = {
+ .halt_reg = 0x49000,
+ .clkr = {
+ .enable_reg = 0x49000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_cfg_ahb_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+ .halt_reg = 0x4400c,
+ .clkr = {
+ .enable_reg = 0x4400c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm2_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pdm2_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+ .halt_reg = 0x44004,
+ .clkr = {
+ .enable_reg = 0x44004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm_ahb_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_prng_ahb_clk = {
+ .halt_reg = 0x13004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(8),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_prng_ahb_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+ .halt_reg = 0x4201c,
+ .clkr = {
+ .enable_reg = 0x4201c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_ahb_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_apps_clk = {
+ .halt_reg = 0x42018,
+ .clkr = {
+ .enable_reg = 0x42018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &sdcc1_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_ahb_clk = {
+ .halt_reg = 0x4301c,
+ .clkr = {
+ .enable_reg = 0x4301c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc2_ahb_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_apps_clk = {
+ .halt_reg = 0x43018,
+ .clkr = {
+ .enable_reg = 0x43018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc2_apps_clk",
+ .parent_hws = (const struct clk_hw *[]){ &sdcc2_apps_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_rcg2 bimc_ddr_clk_src = {
+ .cmd_rcgr = 0x32004,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_bimc_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "bimc_ddr_clk_src",
+ .parent_data = gcc_xo_gpll0_bimc,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ .flags = CLK_GET_RATE_NOCACHE,
+ },
+};
+
+static struct clk_branch gcc_mss_q6_bimc_axi_clk = {
+ .halt_reg = 0x49004,
+ .clkr = {
+ .enable_reg = 0x49004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_q6_bimc_axi_clk",
+ .parent_hws = (const struct clk_hw *[]){ &bimc_ddr_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_apss_tcu_clk = {
+ .halt_reg = 0x12018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4500c,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_apss_tcu_clk",
+ .parent_hws = (const struct clk_hw *[]){ &bimc_ddr_clk_src.clkr.hw },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_smmu_cfg_clk = {
+ .halt_reg = 0x12038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4500c,
+ .enable_mask = BIT(12),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_smmu_cfg_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qdss_dap_clk = {
+ .halt_reg = 0x29084,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(19),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qdss_dap_clk",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "xo",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb2a_phy_sleep_clk = {
+ .halt_reg = 0x4102c,
+ .clkr = {
+ .enable_reg = 0x4102c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb2a_phy_sleep_clk",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "sleep_clk",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb_hs_phy_cfg_ahb_clk = {
+ .halt_reg = 0x41030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x41030,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb_hs_phy_cfg_ahb_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb_hs_ahb_clk = {
+ .halt_reg = 0x41008,
+ .clkr = {
+ .enable_reg = 0x41008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb_hs_ahb_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb_hs_system_clk = {
+ .halt_reg = 0x41004,
+ .clkr = {
+ .enable_reg = 0x41004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb_hs_system_clk",
+ .parent_hws = (const struct clk_hw *[]){ &usb_hs_system_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_apss_ahb_clk = {
+ .halt_reg = 0x4601c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(14),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_apss_ahb_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_apss_axi_clk = {
+ .halt_reg = 0x4601c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x45004,
+ .enable_mask = BIT(13),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_apss_axi_clk",
+ .parent_hws = (const struct clk_hw *[]){ &pcnoc_bfdcd_clk_src.clkr.hw },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap *gcc_mdm9607_clocks[] = {
+ [GPLL0] = &gpll0.clkr,
+ [GPLL0_EARLY] = &gpll0_early.clkr,
+ [GPLL1] = &gpll1.clkr,
+ [GPLL1_VOTE] = &gpll1_vote,
+ [GPLL2] = &gpll2.clkr,
+ [GPLL2_EARLY] = &gpll2_early.clkr,
+ [BIMC_PLL] = &bimc_pll.clkr,
+ [BIMC_PLL_VOTE] = &bimc_pll_vote,
+ [BIMC_DDR_CLK_SRC] = &bimc_ddr_clk_src.clkr,
+ [PCNOC_BFDCD_CLK_SRC] = &pcnoc_bfdcd_clk_src.clkr,
+ [SYSTEM_NOC_BFDCD_CLK_SRC] = &system_noc_bfdcd_clk_src.clkr,
+ [APSS_AHB_CLK_SRC] = &apss_ahb_clk_src.clkr,
+ [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
+ [BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
+ [BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr,
+ [BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr,
+ [BLSP1_QUP3_I2C_APPS_CLK_SRC] = &blsp1_qup3_i2c_apps_clk_src.clkr,
+ [BLSP1_QUP3_SPI_APPS_CLK_SRC] = &blsp1_qup3_spi_apps_clk_src.clkr,
+ [BLSP1_QUP4_I2C_APPS_CLK_SRC] = &blsp1_qup4_i2c_apps_clk_src.clkr,
+ [BLSP1_QUP4_SPI_APPS_CLK_SRC] = &blsp1_qup4_spi_apps_clk_src.clkr,
+ [BLSP1_QUP5_I2C_APPS_CLK_SRC] = &blsp1_qup5_i2c_apps_clk_src.clkr,
+ [BLSP1_QUP5_SPI_APPS_CLK_SRC] = &blsp1_qup5_spi_apps_clk_src.clkr,
+ [BLSP1_QUP6_I2C_APPS_CLK_SRC] = &blsp1_qup6_i2c_apps_clk_src.clkr,
+ [BLSP1_QUP6_SPI_APPS_CLK_SRC] = &blsp1_qup6_spi_apps_clk_src.clkr,
+ [BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr,
+ [BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr,
+ [BLSP1_UART3_APPS_CLK_SRC] = &blsp1_uart3_apps_clk_src.clkr,
+ [BLSP1_UART4_APPS_CLK_SRC] = &blsp1_uart4_apps_clk_src.clkr,
+ [BLSP1_UART5_APPS_CLK_SRC] = &blsp1_uart5_apps_clk_src.clkr,
+ [BLSP1_UART6_APPS_CLK_SRC] = &blsp1_uart6_apps_clk_src.clkr,
+ [CRYPTO_CLK_SRC] = &crypto_clk_src.clkr,
+ [GP1_CLK_SRC] = &gp1_clk_src.clkr,
+ [GP2_CLK_SRC] = &gp2_clk_src.clkr,
+ [GP3_CLK_SRC] = &gp3_clk_src.clkr,
+ [PDM2_CLK_SRC] = &pdm2_clk_src.clkr,
+ [SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr,
+ [SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr,
+ [APSS_TCU_CLK_SRC] = &apss_tcu_clk_src.clkr,
+ [USB_HS_SYSTEM_CLK_SRC] = &usb_hs_system_clk_src.clkr,
+ [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr,
+ [GCC_BLSP1_SLEEP_CLK] = &gcc_blsp1_sleep_clk.clkr,
+ [GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr,
+ [GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr,
+ [GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr,
+ [GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr,
+ [GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP5_I2C_APPS_CLK] = &gcc_blsp1_qup5_i2c_apps_clk.clkr,
+ [GCC_BLSP1_QUP5_SPI_APPS_CLK] = &gcc_blsp1_qup5_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP6_I2C_APPS_CLK] = &gcc_blsp1_qup6_i2c_apps_clk.clkr,
+ [GCC_BLSP1_QUP6_SPI_APPS_CLK] = &gcc_blsp1_qup6_spi_apps_clk.clkr,
+ [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr,
+ [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr,
+ [GCC_BLSP1_UART3_APPS_CLK] = &gcc_blsp1_uart3_apps_clk.clkr,
+ [GCC_BLSP1_UART4_APPS_CLK] = &gcc_blsp1_uart4_apps_clk.clkr,
+ [GCC_BLSP1_UART5_APPS_CLK] = &gcc_blsp1_uart5_apps_clk.clkr,
+ [GCC_BLSP1_UART6_APPS_CLK] = &gcc_blsp1_uart6_apps_clk.clkr,
+ [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+ [GCC_CRYPTO_AHB_CLK] = &gcc_crypto_ahb_clk.clkr,
+ [GCC_CRYPTO_AXI_CLK] = &gcc_crypto_axi_clk.clkr,
+ [GCC_CRYPTO_CLK] = &gcc_crypto_clk.clkr,
+ [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+ [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+ [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+ [GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr,
+ [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+ [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+ [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr,
+ [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+ [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+ [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+ [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+ [GCC_SMMU_CFG_CLK] = &gcc_smmu_cfg_clk.clkr,
+ [GCC_USB2A_PHY_SLEEP_CLK] = &gcc_usb2a_phy_sleep_clk.clkr,
+ [GCC_USB_HS_PHY_CFG_AHB_CLK] = &gcc_usb_hs_phy_cfg_ahb_clk.clkr,
+ [GCC_USB_HS_AHB_CLK] = &gcc_usb_hs_ahb_clk.clkr,
+ [GCC_USB_HS_SYSTEM_CLK] = &gcc_usb_hs_system_clk.clkr,
+ [GCC_APSS_TCU_CLK] = &gcc_apss_tcu_clk.clkr,
+ [GCC_MSS_Q6_BIMC_AXI_CLK] = &gcc_mss_q6_bimc_axi_clk.clkr,
+ [GCC_QDSS_DAP_CLK] = &gcc_qdss_dap_clk.clkr,
+ [GCC_APSS_AHB_CLK] = &gcc_apss_ahb_clk.clkr,
+ [GCC_APSS_AXI_CLK] = &gcc_apss_axi_clk.clkr,
+ [GCC_USB_HSIC_CLK_SRC] = &usb_hsic_clk_src.clkr,
+ [GCC_USB_HSIC_IO_CAL_CLK_SRC] = &usb_hsic_io_cal_clk_src.clkr,
+ [GCC_USB_HSIC_SYSTEM_CLK_SRC] = &usb_hsic_system_clk_src.clkr,
+};
+
+static const struct qcom_reset_map gcc_mdm9607_resets[] = {
+ [USB_HS_HSIC_BCR] = { 0x3d05c },
+ [GCC_MSS_RESTART] = { 0x3e000 },
+ [USB_HS_BCR] = { 0x41000 },
+ [USB2_HS_PHY_ONLY_BCR] = { 0x41034 },
+ [QUSB2_PHY_BCR] = { 0x4103c },
+};
+
+static const struct regmap_config gcc_mdm9607_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x80000,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc gcc_mdm9607_desc = {
+ .config = &gcc_mdm9607_regmap_config,
+ .clks = gcc_mdm9607_clocks,
+ .num_clks = ARRAY_SIZE(gcc_mdm9607_clocks),
+ .resets = gcc_mdm9607_resets,
+ .num_resets = ARRAY_SIZE(gcc_mdm9607_resets),
+};
+
+static const struct of_device_id gcc_mdm9607_match_table[] = {
+ { .compatible = "qcom,gcc-mdm9607" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gcc_mdm9607_match_table);
+
+static int gcc_mdm9607_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &gcc_mdm9607_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Vote for GPLL0 to turn on. Needed by acpuclock. */
+ regmap_update_bits(regmap, 0x45000, BIT(0), BIT(0));
+
+ return qcom_cc_really_probe(pdev, &gcc_mdm9607_desc, regmap);
+}
+
+static struct platform_driver gcc_mdm9607_driver = {
+ .probe = gcc_mdm9607_probe,
+ .driver = {
+ .name = "gcc-mdm9607",
+ .of_match_table = gcc_mdm9607_match_table,
+ },
+};
+
+static int __init gcc_mdm9607_init(void)
+{
+ return platform_driver_register(&gcc_mdm9607_driver);
+}
+core_initcall(gcc_mdm9607_init);
+
+static void __exit gcc_mdm9607_exit(void)
+{
+ platform_driver_unregister(&gcc_mdm9607_driver);
+}
+module_exit(gcc_mdm9607_exit);
+
+MODULE_DESCRIPTION("Qualcomm GCC mdm9607 Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c
index 740d3c44c04b..bf305fa9e522 100644
--- a/drivers/clk/qcom/gcc-msm8974.c
+++ b/drivers/clk/qcom/gcc-msm8974.c
@@ -719,6 +719,12 @@ static struct clk_rcg2 blsp2_uart6_apps_clk_src = {
},
};
+static const struct freq_tbl ftbl_gcc_ce1_clk_msm8226[] = {
+ F(50000000, P_GPLL0, 12, 0, 0),
+ F(100000000, P_GPLL0, 6, 0, 0),
+ { }
+};
+
static const struct freq_tbl ftbl_gcc_ce1_clk[] = {
F(50000000, P_GPLL0, 12, 0, 0),
F(75000000, P_GPLL0, 8, 0, 0),
@@ -761,6 +767,11 @@ static struct clk_rcg2 ce2_clk_src = {
},
};
+static const struct freq_tbl ftbl_gcc_gp_clk_msm8226[] = {
+ F(19200000, P_XO, 1, 0, 0),
+ { }
+};
+
static const struct freq_tbl ftbl_gcc_gp_clk[] = {
F(4800000, P_XO, 4, 0, 0),
F(6000000, P_GPLL0, 10, 1, 10),
@@ -1955,6 +1966,10 @@ static struct clk_branch gcc_mss_q6_bimc_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_mss_q6_bimc_axi_clk",
+ .parent_names = (const char *[]){
+ "system_noc_clk_src",
+ },
+ .num_parents = 1,
.ops = &clk_branch2_ops,
},
},
@@ -1993,6 +2008,20 @@ static struct clk_branch gcc_pdm_ahb_clk = {
},
};
+static struct clk_branch gcc_pdm_xo4_clk = {
+ .halt_reg = 0x0cc8,
+ .clkr = {
+ .enable_reg = 0x0cc8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm_xo4_clk",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_prng_ahb_clk = {
.halt_reg = 0x0d04,
.halt_check = BRANCH_HALT_VOTED,
@@ -2430,6 +2459,121 @@ static struct gdsc usb_hs_hsic_gdsc = {
.pwrsts = PWRSTS_OFF_ON,
};
+static struct clk_regmap *gcc_msm8226_clocks[] = {
+ [GPLL0] = &gpll0.clkr,
+ [GPLL0_VOTE] = &gpll0_vote,
+ [GPLL1] = &gpll1.clkr,
+ [GPLL1_VOTE] = &gpll1_vote,
+ [CONFIG_NOC_CLK_SRC] = &config_noc_clk_src.clkr,
+ [PERIPH_NOC_CLK_SRC] = &periph_noc_clk_src.clkr,
+ [SYSTEM_NOC_CLK_SRC] = &system_noc_clk_src.clkr,
+ [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
+ [BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
+ [BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr,
+ [BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr,
+ [BLSP1_QUP3_I2C_APPS_CLK_SRC] = &blsp1_qup3_i2c_apps_clk_src.clkr,
+ [BLSP1_QUP3_SPI_APPS_CLK_SRC] = &blsp1_qup3_spi_apps_clk_src.clkr,
+ [BLSP1_QUP4_I2C_APPS_CLK_SRC] = &blsp1_qup4_i2c_apps_clk_src.clkr,
+ [BLSP1_QUP4_SPI_APPS_CLK_SRC] = &blsp1_qup4_spi_apps_clk_src.clkr,
+ [BLSP1_QUP5_I2C_APPS_CLK_SRC] = &blsp1_qup5_i2c_apps_clk_src.clkr,
+ [BLSP1_QUP5_SPI_APPS_CLK_SRC] = &blsp1_qup5_spi_apps_clk_src.clkr,
+ [BLSP1_QUP6_I2C_APPS_CLK_SRC] = &blsp1_qup6_i2c_apps_clk_src.clkr,
+ [BLSP1_QUP6_SPI_APPS_CLK_SRC] = &blsp1_qup6_spi_apps_clk_src.clkr,
+ [BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr,
+ [BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr,
+ [BLSP1_UART3_APPS_CLK_SRC] = &blsp1_uart3_apps_clk_src.clkr,
+ [BLSP1_UART4_APPS_CLK_SRC] = &blsp1_uart4_apps_clk_src.clkr,
+ [BLSP1_UART5_APPS_CLK_SRC] = &blsp1_uart5_apps_clk_src.clkr,
+ [BLSP1_UART6_APPS_CLK_SRC] = &blsp1_uart6_apps_clk_src.clkr,
+ [CE1_CLK_SRC] = &ce1_clk_src.clkr,
+ [GP1_CLK_SRC] = &gp1_clk_src.clkr,
+ [GP2_CLK_SRC] = &gp2_clk_src.clkr,
+ [GP3_CLK_SRC] = &gp3_clk_src.clkr,
+ [PDM2_CLK_SRC] = &pdm2_clk_src.clkr,
+ [SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr,
+ [SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr,
+ [SDCC3_APPS_CLK_SRC] = &sdcc3_apps_clk_src.clkr,
+ [USB_HS_SYSTEM_CLK_SRC] = &usb_hs_system_clk_src.clkr,
+ [USB_HSIC_CLK_SRC] = &usb_hsic_clk_src.clkr,
+ [USB_HSIC_IO_CAL_CLK_SRC] = &usb_hsic_io_cal_clk_src.clkr,
+ [USB_HSIC_SYSTEM_CLK_SRC] = &usb_hsic_system_clk_src.clkr,
+ [GCC_BAM_DMA_AHB_CLK] = &gcc_bam_dma_ahb_clk.clkr,
+ [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr,
+ [GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr,
+ [GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr,
+ [GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr,
+ [GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr,
+ [GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP5_I2C_APPS_CLK] = &gcc_blsp1_qup5_i2c_apps_clk.clkr,
+ [GCC_BLSP1_QUP5_SPI_APPS_CLK] = &gcc_blsp1_qup5_spi_apps_clk.clkr,
+ [GCC_BLSP1_QUP6_I2C_APPS_CLK] = &gcc_blsp1_qup6_i2c_apps_clk.clkr,
+ [GCC_BLSP1_QUP6_SPI_APPS_CLK] = &gcc_blsp1_qup6_spi_apps_clk.clkr,
+ [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr,
+ [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr,
+ [GCC_BLSP1_UART3_APPS_CLK] = &gcc_blsp1_uart3_apps_clk.clkr,
+ [GCC_BLSP1_UART4_APPS_CLK] = &gcc_blsp1_uart4_apps_clk.clkr,
+ [GCC_BLSP1_UART5_APPS_CLK] = &gcc_blsp1_uart5_apps_clk.clkr,
+ [GCC_BLSP1_UART6_APPS_CLK] = &gcc_blsp1_uart6_apps_clk.clkr,
+ [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+ [GCC_CE1_AHB_CLK] = &gcc_ce1_ahb_clk.clkr,
+ [GCC_CE1_AXI_CLK] = &gcc_ce1_axi_clk.clkr,
+ [GCC_CE1_CLK] = &gcc_ce1_clk.clkr,
+ [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+ [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+ [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+ [GCC_LPASS_Q6_AXI_CLK] = &gcc_lpass_q6_axi_clk.clkr,
+ [GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr,
+ [GCC_MSS_Q6_BIMC_AXI_CLK] = &gcc_mss_q6_bimc_axi_clk.clkr,
+ [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+ [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+ [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr,
+ [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr,
+ [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+ [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+ [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+ [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+ [GCC_SDCC3_AHB_CLK] = &gcc_sdcc3_ahb_clk.clkr,
+ [GCC_SDCC3_APPS_CLK] = &gcc_sdcc3_apps_clk.clkr,
+ [GCC_USB2A_PHY_SLEEP_CLK] = &gcc_usb2a_phy_sleep_clk.clkr,
+ [GCC_USB_HS_AHB_CLK] = &gcc_usb_hs_ahb_clk.clkr,
+ [GCC_USB_HS_SYSTEM_CLK] = &gcc_usb_hs_system_clk.clkr,
+ [GCC_USB_HSIC_AHB_CLK] = &gcc_usb_hsic_ahb_clk.clkr,
+ [GCC_USB_HSIC_CLK] = &gcc_usb_hsic_clk.clkr,
+ [GCC_USB_HSIC_IO_CAL_CLK] = &gcc_usb_hsic_io_cal_clk.clkr,
+ [GCC_USB_HSIC_SYSTEM_CLK] = &gcc_usb_hsic_system_clk.clkr,
+};
+
+static const struct qcom_reset_map gcc_msm8226_resets[] = {
+ [GCC_USB_HS_HSIC_BCR] = { 0x0400 },
+ [GCC_USB_HS_BCR] = { 0x0480 },
+ [GCC_USB2A_PHY_BCR] = { 0x04a8 },
+};
+
+static struct gdsc *gcc_msm8226_gdscs[] = {
+ [USB_HS_HSIC_GDSC] = &usb_hs_hsic_gdsc,
+};
+
+static const struct regmap_config gcc_msm8226_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x1a80,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc gcc_msm8226_desc = {
+ .config = &gcc_msm8226_regmap_config,
+ .clks = gcc_msm8226_clocks,
+ .num_clks = ARRAY_SIZE(gcc_msm8226_clocks),
+ .resets = gcc_msm8226_resets,
+ .num_resets = ARRAY_SIZE(gcc_msm8226_resets),
+ .gdscs = gcc_msm8226_gdscs,
+ .num_gdscs = ARRAY_SIZE(gcc_msm8226_gdscs),
+};
+
static struct clk_regmap *gcc_msm8974_clocks[] = {
[GPLL0] = &gpll0.clkr,
[GPLL0_VOTE] = &gpll0_vote,
@@ -2682,13 +2826,22 @@ static const struct qcom_cc_desc gcc_msm8974_desc = {
};
static const struct of_device_id gcc_msm8974_match_table[] = {
- { .compatible = "qcom,gcc-msm8974" },
- { .compatible = "qcom,gcc-msm8974pro" , .data = (void *)1UL },
- { .compatible = "qcom,gcc-msm8974pro-ac", .data = (void *)1UL },
+ { .compatible = "qcom,gcc-msm8226", .data = &gcc_msm8226_desc },
+ { .compatible = "qcom,gcc-msm8974", .data = &gcc_msm8974_desc },
+ { .compatible = "qcom,gcc-msm8974pro", .data = &gcc_msm8974_desc },
+ { .compatible = "qcom,gcc-msm8974pro-ac", .data = &gcc_msm8974_desc },
{ }
};
MODULE_DEVICE_TABLE(of, gcc_msm8974_match_table);
+static void msm8226_clock_override(void)
+{
+ ce1_clk_src.freq_tbl = ftbl_gcc_ce1_clk_msm8226;
+ gp1_clk_src.freq_tbl = ftbl_gcc_gp_clk_msm8226;
+ gp2_clk_src.freq_tbl = ftbl_gcc_gp_clk_msm8226;
+ gp3_clk_src.freq_tbl = ftbl_gcc_gp_clk_msm8226;
+}
+
static void msm8974_pro_clock_override(void)
{
sdcc1_apps_clk_src_init.parent_names = gcc_xo_gpll0_gpll4;
@@ -2708,16 +2861,18 @@ static int gcc_msm8974_probe(struct platform_device *pdev)
{
int ret;
struct device *dev = &pdev->dev;
- bool pro;
const struct of_device_id *id;
id = of_match_device(gcc_msm8974_match_table, dev);
if (!id)
return -ENODEV;
- pro = !!(id->data);
- if (pro)
- msm8974_pro_clock_override();
+ if (!of_device_is_compatible(dev->of_node, "qcom,gcc-msm8974")) {
+ if (id->data == &gcc_msm8226_desc)
+ msm8226_clock_override();
+ else
+ msm8974_pro_clock_override();
+ }
ret = qcom_cc_register_board_clk(dev, "xo_board", "xo", 19200000);
if (ret)
diff --git a/drivers/clk/qcom/gcc-sc7280.c b/drivers/clk/qcom/gcc-sc7280.c
index ef734db316df..6cefcdc86990 100644
--- a/drivers/clk/qcom/gcc-sc7280.c
+++ b/drivers/clk/qcom/gcc-sc7280.c
@@ -716,6 +716,7 @@ static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s2_clk_src[] = {
F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(52174000, P_GCC_GPLL0_OUT_MAIN, 1, 2, 23),
F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
diff --git a/drivers/clk/qcom/gcc-sm6125.c b/drivers/clk/qcom/gcc-sm6125.c
new file mode 100644
index 000000000000..543cfab7561f
--- /dev/null
+++ b/drivers/clk/qcom/gcc-sm6125.c
@@ -0,0 +1,4190 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, Konrad Dybcio <konrad.dybcio@somainline.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/clock/qcom,gcc-sm6125.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+ P_BI_TCXO,
+ P_GPLL0_OUT_AUX2,
+ P_GPLL0_OUT_EARLY,
+ P_GPLL3_OUT_EARLY,
+ P_GPLL4_OUT_MAIN,
+ P_GPLL5_OUT_MAIN,
+ P_GPLL6_OUT_EARLY,
+ P_GPLL6_OUT_MAIN,
+ P_GPLL7_OUT_MAIN,
+ P_GPLL8_OUT_EARLY,
+ P_GPLL8_OUT_MAIN,
+ P_GPLL9_OUT_MAIN,
+ P_SLEEP_CLK,
+};
+
+static struct clk_alpha_pll gpll0_out_early = {
+ .offset = 0x0,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll0_out_early",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "bi_tcxo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor gpll0_out_aux2 = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll0_out_aux2",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpll0_out_early.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_fixed_factor gpll0_out_main = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll0_out_main",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpll0_out_early.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll3_out_early = {
+ .offset = 0x3000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(3),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll3_out_early",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "bi_tcxo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gpll4_out_main = {
+ .offset = 0x4000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll4_out_main",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "bi_tcxo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gpll5_out_main = {
+ .offset = 0x5000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(5),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll5_out_main",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "bi_tcxo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gpll6_out_early = {
+ .offset = 0x6000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(6),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll6_out_early",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "bi_tcxo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor gpll6_out_main = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll6_out_main",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpll6_out_early.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll7_out_early = {
+ .offset = 0x7000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(7),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll7_out_early",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "bi_tcxo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor gpll7_out_main = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll7_out_main",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpll7_out_early.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll8_out_early = {
+ .offset = 0x8000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(8),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll8_out_early",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "bi_tcxo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor gpll8_out_main = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll8_out_main",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpll8_out_early.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll9_out_early = {
+ .offset = 0x9000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll9_out_early",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "bi_tcxo",
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor gpll9_out_main = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll9_out_main",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpll9_out_early.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static const struct parent_map gcc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_0[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &gpll0_out_early.clkr.hw },
+ { .hw = &gpll0_out_aux2.hw },
+};
+
+static const struct parent_map gcc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_GPLL6_OUT_MAIN, 4 },
+};
+
+static const struct clk_parent_data gcc_parent_data_1[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &gpll0_out_early.clkr.hw },
+ { .hw = &gpll0_out_aux2.hw },
+ { .hw = &gpll6_out_main.hw },
+};
+
+static const struct parent_map gcc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_2[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &gpll0_out_early.clkr.hw },
+ { .hw = &gpll0_out_aux2.hw },
+ { .fw_name = "sleep_clk" },
+};
+
+static const struct parent_map gcc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL5_OUT_MAIN, 3 },
+ { P_GPLL4_OUT_MAIN, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_3[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &gpll0_out_early.clkr.hw },
+ { .hw = &gpll5_out_main.clkr.hw },
+ { .hw = &gpll4_out_main.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_4[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL9_OUT_MAIN, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_4[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &gpll0_out_early.clkr.hw },
+ { .hw = &gpll9_out_main.hw },
+};
+
+static const struct parent_map gcc_parent_map_5[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+};
+
+static const struct clk_parent_data gcc_parent_data_5[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &gpll0_out_early.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_6[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL4_OUT_MAIN, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_6[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &gpll0_out_early.clkr.hw },
+ { .hw = &gpll4_out_main.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_7[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_7[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &gpll0_out_early.clkr.hw },
+ { .fw_name = "sleep_clk" },
+};
+
+static const struct parent_map gcc_parent_map_8[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL9_OUT_MAIN, 2 },
+ { P_GPLL6_OUT_EARLY, 3 },
+ { P_GPLL8_OUT_MAIN, 4 },
+ { P_GPLL4_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_EARLY, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_8[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &gpll0_out_early.clkr.hw },
+ { .hw = &gpll9_out_main.hw },
+ { .hw = &gpll6_out_early.clkr.hw },
+ { .hw = &gpll8_out_main.hw },
+ { .hw = &gpll4_out_main.clkr.hw },
+ { .hw = &gpll3_out_early.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_9[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL8_OUT_MAIN, 4 },
+};
+
+static const struct clk_parent_data gcc_parent_data_9[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &gpll0_out_early.clkr.hw },
+ { .hw = &gpll8_out_main.hw },
+};
+
+static const struct parent_map gcc_parent_map_10[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL9_OUT_MAIN, 2 },
+ { P_GPLL6_OUT_EARLY, 3 },
+ { P_GPLL8_OUT_MAIN, 4 },
+ { P_GPLL3_OUT_EARLY, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_10[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &gpll0_out_early.clkr.hw },
+ { .hw = &gpll9_out_main.hw },
+ { .hw = &gpll6_out_early.clkr.hw },
+ { .hw = &gpll8_out_main.hw },
+ { .hw = &gpll3_out_early.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_11[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL8_OUT_EARLY, 4 },
+ { P_GPLL4_OUT_MAIN, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_11[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &gpll0_out_early.clkr.hw },
+ { .hw = &gpll8_out_early.clkr.hw },
+ { .hw = &gpll4_out_main.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_12[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL6_OUT_EARLY, 3 },
+ { P_GPLL8_OUT_EARLY, 4 },
+};
+
+static const struct clk_parent_data gcc_parent_data_12[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &gpll0_out_early.clkr.hw },
+ { .hw = &gpll6_out_early.clkr.hw },
+ { .hw = &gpll8_out_early.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_13[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_GPLL7_OUT_MAIN, 3 },
+ { P_GPLL4_OUT_MAIN, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_13[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &gpll0_out_early.clkr.hw },
+ { .hw = &gpll0_out_aux2.hw },
+ { .hw = &gpll7_out_main.hw },
+ { .hw = &gpll4_out_main.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_14[] = {
+ { P_BI_TCXO, 0 },
+ { P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_14[] = {
+ { .fw_name = "bi_tcxo" },
+ { .fw_name = "sleep_clk" },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_ahb_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(40000000, P_GPLL8_OUT_MAIN, 12, 0, 0),
+ F(80000000, P_GPLL8_OUT_MAIN, 6, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_ahb_clk_src = {
+ .cmd_rcgr = 0x56088,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_9,
+ .freq_tbl = ftbl_gcc_camss_ahb_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_ahb_clk_src",
+ .parent_data = gcc_parent_data_9,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_9),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_cci_clk_src[] = {
+ F(37500000, P_GPLL0_OUT_EARLY, 16, 0, 0),
+ F(50000000, P_GPLL0_OUT_EARLY, 12, 0, 0),
+ F(100000000, P_GPLL0_OUT_EARLY, 6, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_cci_clk_src = {
+ .cmd_rcgr = 0x52004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_camss_cci_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cci_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_cpp_clk_src[] = {
+ F(120000000, P_GPLL8_OUT_MAIN, 4, 0, 0),
+ F(240000000, P_GPLL8_OUT_MAIN, 2, 0, 0),
+ F(320000000, P_GPLL8_OUT_MAIN, 1.5, 0, 0),
+ F(480000000, P_GPLL8_OUT_MAIN, 1, 0, 0),
+ F(576000000, P_GPLL9_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_cpp_clk_src = {
+ .cmd_rcgr = 0x560c8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_10,
+ .freq_tbl = ftbl_gcc_camss_cpp_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cpp_clk_src",
+ .parent_data = gcc_parent_data_10,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_10),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_csi0_clk_src[] = {
+ F(100000000, P_GPLL0_OUT_EARLY, 6, 0, 0),
+ F(200000000, P_GPLL0_OUT_EARLY, 3, 0, 0),
+ F(311000000, P_GPLL5_OUT_MAIN, 3, 0, 0),
+ F(403200000, P_GPLL4_OUT_MAIN, 2, 0, 0),
+ F(466500000, P_GPLL5_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_csi0_clk_src = {
+ .cmd_rcgr = 0x55030,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_camss_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi0_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_csi0phytimer_clk_src[] = {
+ F(100000000, P_GPLL0_OUT_EARLY, 6, 0, 0),
+ F(200000000, P_GPLL0_OUT_EARLY, 3, 0, 0),
+ F(268800000, P_GPLL4_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_csi0phytimer_clk_src = {
+ .cmd_rcgr = 0x53004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_camss_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi0phytimer_clk_src",
+ .parent_data = gcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_6),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_csi1_clk_src = {
+ .cmd_rcgr = 0x5506c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_camss_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi1_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_csi1phytimer_clk_src = {
+ .cmd_rcgr = 0x53024,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_camss_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi1phytimer_clk_src",
+ .parent_data = gcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_6),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_csi2_clk_src = {
+ .cmd_rcgr = 0x550a4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_camss_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi2_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_csi2phytimer_clk_src = {
+ .cmd_rcgr = 0x53044,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_camss_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi2phytimer_clk_src",
+ .parent_data = gcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_6),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_csi3_clk_src = {
+ .cmd_rcgr = 0x550e0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_camss_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi3_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_csiphy_clk_src[] = {
+ F(100000000, P_GPLL0_OUT_EARLY, 6, 0, 0),
+ F(200000000, P_GPLL0_OUT_EARLY, 3, 0, 0),
+ F(268800000, P_GPLL4_OUT_MAIN, 3, 0, 0),
+ F(320000000, P_GPLL8_OUT_EARLY, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_csiphy_clk_src = {
+ .cmd_rcgr = 0x55000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_11,
+ .freq_tbl = ftbl_gcc_camss_csiphy_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csiphy_clk_src",
+ .parent_data = gcc_parent_data_11,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_11),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_gp0_clk_src[] = {
+ F(50000000, P_GPLL0_OUT_EARLY, 12, 0, 0),
+ F(100000000, P_GPLL0_OUT_EARLY, 6, 0, 0),
+ F(200000000, P_GPLL0_OUT_EARLY, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_gp0_clk_src = {
+ .cmd_rcgr = 0x50000,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_7,
+ .freq_tbl = ftbl_gcc_camss_gp0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_gp0_clk_src",
+ .parent_data = gcc_parent_data_7,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_7),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_gp1_clk_src = {
+ .cmd_rcgr = 0x5001c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_7,
+ .freq_tbl = ftbl_gcc_camss_gp0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_gp1_clk_src",
+ .parent_data = gcc_parent_data_7,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_7),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_jpeg_clk_src[] = {
+ F(66666667, P_GPLL0_OUT_EARLY, 9, 0, 0),
+ F(133333333, P_GPLL0_OUT_EARLY, 4.5, 0, 0),
+ F(219428571, P_GPLL6_OUT_EARLY, 3.5, 0, 0),
+ F(320000000, P_GPLL8_OUT_EARLY, 3, 0, 0),
+ F(480000000, P_GPLL8_OUT_EARLY, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_jpeg_clk_src = {
+ .cmd_rcgr = 0x52028,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_12,
+ .freq_tbl = ftbl_gcc_camss_jpeg_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_jpeg_clk_src",
+ .parent_data = gcc_parent_data_12,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_12),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_mclk0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(24000000, P_GPLL9_OUT_MAIN, 1, 1, 24),
+ F(64000000, P_GPLL9_OUT_MAIN, 1, 1, 9),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_mclk0_clk_src = {
+ .cmd_rcgr = 0x51000,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_camss_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk0_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_mclk1_clk_src = {
+ .cmd_rcgr = 0x5101c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_camss_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk1_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_mclk2_clk_src = {
+ .cmd_rcgr = 0x51038,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_camss_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk2_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_mclk3_clk_src = {
+ .cmd_rcgr = 0x51054,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_camss_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk3_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_vfe0_clk_src[] = {
+ F(120000000, P_GPLL8_OUT_MAIN, 4, 0, 0),
+ F(256000000, P_GPLL6_OUT_EARLY, 3, 0, 0),
+ F(403200000, P_GPLL4_OUT_MAIN, 2, 0, 0),
+ F(480000000, P_GPLL8_OUT_MAIN, 1, 0, 0),
+ F(533000000, P_GPLL3_OUT_EARLY, 2, 0, 0),
+ F(576000000, P_GPLL9_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_vfe0_clk_src = {
+ .cmd_rcgr = 0x54010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_8,
+ .freq_tbl = ftbl_gcc_camss_vfe0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_vfe0_clk_src",
+ .parent_data = gcc_parent_data_8,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_8),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_camss_vfe1_clk_src = {
+ .cmd_rcgr = 0x54048,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_8,
+ .freq_tbl = ftbl_gcc_camss_vfe0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_vfe1_clk_src",
+ .parent_data = gcc_parent_data_8,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_8),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = {
+ F(25000000, P_GPLL0_OUT_AUX2, 12, 0, 0),
+ F(50000000, P_GPLL0_OUT_AUX2, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_EARLY, 6, 0, 0),
+ F(200000000, P_GPLL0_OUT_EARLY, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_gp1_clk_src = {
+ .cmd_rcgr = 0x4d004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_gp1_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp2_clk_src = {
+ .cmd_rcgr = 0x4e004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_gp2_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp3_clk_src = {
+ .cmd_rcgr = 0x4f004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_gp3_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(60000000, P_GPLL0_OUT_EARLY, 10, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pdm2_clk_src = {
+ .cmd_rcgr = 0x20010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pdm2_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
+ F(7372800, P_GPLL0_OUT_AUX2, 1, 384, 15625),
+ F(14745600, P_GPLL0_OUT_AUX2, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GPLL0_OUT_AUX2, 1, 1536, 15625),
+ F(32000000, P_GPLL0_OUT_AUX2, 1, 8, 75),
+ F(48000000, P_GPLL0_OUT_AUX2, 1, 4, 25),
+ F(64000000, P_GPLL0_OUT_AUX2, 1, 16, 75),
+ F(75000000, P_GPLL0_OUT_AUX2, 4, 0, 0),
+ F(80000000, P_GPLL0_OUT_AUX2, 1, 4, 15),
+ F(96000000, P_GPLL0_OUT_AUX2, 1, 8, 25),
+ F(100000000, P_GPLL0_OUT_EARLY, 6, 0, 0),
+ F(102400000, P_GPLL0_OUT_AUX2, 1, 128, 375),
+ F(112000000, P_GPLL0_OUT_AUX2, 1, 28, 75),
+ F(117964800, P_GPLL0_OUT_AUX2, 1, 6144, 15625),
+ F(120000000, P_GPLL0_OUT_AUX2, 2.5, 0, 0),
+ F(128000000, P_GPLL6_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s0_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = {
+ .cmd_rcgr = 0x1f148,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s1_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
+ .cmd_rcgr = 0x1f278,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s2_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
+ .cmd_rcgr = 0x1f3a8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s3_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
+ .cmd_rcgr = 0x1f4d8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s4_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
+ .cmd_rcgr = 0x1f608,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s5_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
+ .cmd_rcgr = 0x1f738,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s0_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
+ .cmd_rcgr = 0x39148,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s1_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
+ .cmd_rcgr = 0x39278,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s2_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = {
+ .cmd_rcgr = 0x393a8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s3_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
+ .cmd_rcgr = 0x394d8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s4_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
+ .cmd_rcgr = 0x39608,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s5_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
+ .cmd_rcgr = 0x39738,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = {
+ F(144000, P_BI_TCXO, 16, 3, 25),
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(20000000, P_GPLL0_OUT_AUX2, 5, 1, 3),
+ F(25000000, P_GPLL0_OUT_AUX2, 6, 1, 2),
+ F(50000000, P_GPLL0_OUT_AUX2, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(192000000, P_GPLL6_OUT_MAIN, 2, 0, 0),
+ F(384000000, P_GPLL6_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc1_apps_clk_src = {
+ .cmd_rcgr = 0x38028,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_sdcc1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_apps_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = {
+ F(75000000, P_GPLL0_OUT_AUX2, 4, 0, 0),
+ F(150000000, P_GPLL0_OUT_EARLY, 4, 0, 0),
+ F(200000000, P_GPLL0_OUT_EARLY, 3, 0, 0),
+ F(300000000, P_GPLL0_OUT_EARLY, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = {
+ .cmd_rcgr = 0x38010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_sdcc1_ice_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_ice_core_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_floor_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(25000000, P_GPLL0_OUT_AUX2, 12, 0, 0),
+ F(50000000, P_GPLL0_OUT_AUX2, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(202000000, P_GPLL7_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
+ .cmd_rcgr = 0x1e00c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_13,
+ .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc2_apps_clk_src",
+ .parent_data = gcc_parent_data_13,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_13),
+ .ops = &clk_rcg2_floor_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = {
+ F(25000000, P_GPLL0_OUT_AUX2, 12, 0, 0),
+ F(50000000, P_GPLL0_OUT_AUX2, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_EARLY, 6, 0, 0),
+ F(200000000, P_GPLL0_OUT_EARLY, 3, 0, 0),
+ F(240000000, P_GPLL0_OUT_EARLY, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = {
+ .cmd_rcgr = 0x45020,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_axi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = {
+ F(37500000, P_GPLL0_OUT_AUX2, 8, 0, 0),
+ F(75000000, P_GPLL0_OUT_AUX2, 4, 0, 0),
+ F(150000000, P_GPLL0_OUT_EARLY, 4, 0, 0),
+ F(300000000, P_GPLL0_OUT_EARLY, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = {
+ .cmd_rcgr = 0x45048,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_ice_core_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_phy_aux_clk_src[] = {
+ F(9600000, P_BI_TCXO, 2, 0, 0),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = {
+ .cmd_rcgr = 0x4507c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_phy_phy_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_core_clk_src[] = {
+ F(37500000, P_GPLL0_OUT_AUX2, 8, 0, 0),
+ F(75000000, P_GPLL0_OUT_EARLY, 8, 0, 0),
+ F(150000000, P_GPLL0_OUT_EARLY, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = {
+ .cmd_rcgr = 0x45060,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_phy_unipro_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_unipro_core_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = {
+ F(66666667, P_GPLL0_OUT_AUX2, 4.5, 0, 0),
+ F(133333333, P_GPLL0_OUT_EARLY, 4.5, 0, 0),
+ F(200000000, P_GPLL0_OUT_EARLY, 3, 0, 0),
+ F(240000000, P_GPLL0_OUT_EARLY, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb30_prim_master_clk_src = {
+ .cmd_rcgr = 0x1a01c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_prim_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_prim_mock_utmi_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(20000000, P_GPLL0_OUT_AUX2, 15, 0, 0),
+ F(40000000, P_GPLL0_OUT_AUX2, 7.5, 0, 0),
+ F(60000000, P_GPLL0_OUT_EARLY, 10, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x1a034,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb30_prim_mock_utmi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_prim_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb3_prim_phy_aux_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = {
+ .cmd_rcgr = 0x1a060,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_14,
+ .freq_tbl = ftbl_gcc_usb3_prim_phy_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_prim_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_14,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_14),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_vs_ctrl_clk_src = {
+ .cmd_rcgr = 0x42030,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_usb3_prim_phy_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_vs_ctrl_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_vsensor_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(400000000, P_GPLL0_OUT_EARLY, 1.5, 0, 0),
+ F(600000000, P_GPLL0_OUT_EARLY, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_vsensor_clk_src = {
+ .cmd_rcgr = 0x42018,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_vsensor_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_vsensor_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_branch gcc_ahb2phy_csi_clk = {
+ .halt_reg = 0x1d004,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x1d004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1d004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ahb2phy_csi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ahb2phy_usb_clk = {
+ .halt_reg = 0x1d008,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x1d008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1d008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ahb2phy_usb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_apc_vs_clk = {
+ .halt_reg = 0x4204c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4204c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_apc_vs_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_vsensor_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_bimc_gpu_axi_clk = {
+ .halt_reg = 0x71154,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x71154,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_bimc_gpu_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+ .halt_reg = 0x23004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(10),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camera_ahb_clk = {
+ .halt_reg = 0x17008,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x17008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x17008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camera_ahb_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camera_xo_clk = {
+ .halt_reg = 0x17028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camera_xo_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cci_ahb_clk = {
+ .halt_reg = 0x52020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cci_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cci_clk = {
+ .halt_reg = 0x5201c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5201c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cci_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_cci_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cphy_csid0_clk = {
+ .halt_reg = 0x5504c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5504c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cphy_csid0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csiphy_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cphy_csid1_clk = {
+ .halt_reg = 0x55088,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x55088,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cphy_csid1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csiphy_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cphy_csid2_clk = {
+ .halt_reg = 0x550c0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x550c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cphy_csid2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csiphy_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cphy_csid3_clk = {
+ .halt_reg = 0x550fc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x550fc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cphy_csid3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csiphy_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cpp_ahb_clk = {
+ .halt_reg = 0x560e8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x560e8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cpp_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cpp_axi_clk = {
+ .halt_reg = 0x560f4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x560f4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cpp_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cpp_clk = {
+ .halt_reg = 0x560e0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x560e0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cpp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_cpp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cpp_vbif_ahb_clk = {
+ .halt_reg = 0x560f0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x560f0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cpp_vbif_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi0_ahb_clk = {
+ .halt_reg = 0x55050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x55050,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi0_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi0_clk = {
+ .halt_reg = 0x55048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x55048,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi0phytimer_clk = {
+ .halt_reg = 0x5301c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5301c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi0phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi0phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi0pix_clk = {
+ .halt_reg = 0x55060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x55060,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi0pix_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi0rdi_clk = {
+ .halt_reg = 0x55058,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x55058,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi0rdi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi1_ahb_clk = {
+ .halt_reg = 0x5508c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5508c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi1_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi1_clk = {
+ .halt_reg = 0x55084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x55084,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi1phytimer_clk = {
+ .halt_reg = 0x5303c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5303c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi1phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi1phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi1pix_clk = {
+ .halt_reg = 0x5509c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5509c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi1pix_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi1rdi_clk = {
+ .halt_reg = 0x55094,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x55094,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi1rdi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi2_ahb_clk = {
+ .halt_reg = 0x550c4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x550c4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi2_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi2_clk = {
+ .halt_reg = 0x550bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x550bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi2phytimer_clk = {
+ .halt_reg = 0x5305c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5305c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi2phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi2phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi2pix_clk = {
+ .halt_reg = 0x550d4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x550d4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi2pix_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi2rdi_clk = {
+ .halt_reg = 0x550cc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x550cc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi2rdi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi3_ahb_clk = {
+ .halt_reg = 0x55100,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x55100,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi3_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi3_clk = {
+ .halt_reg = 0x550f8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x550f8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi3pix_clk = {
+ .halt_reg = 0x55110,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x55110,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi3pix_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi3rdi_clk = {
+ .halt_reg = 0x55108,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x55108,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi3rdi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csi3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi_vfe0_clk = {
+ .halt_reg = 0x54074,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x54074,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi_vfe0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_vfe0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi_vfe1_clk = {
+ .halt_reg = 0x54080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x54080,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi_vfe1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_vfe1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csiphy0_clk = {
+ .halt_reg = 0x55018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x55018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csiphy0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csiphy_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csiphy1_clk = {
+ .halt_reg = 0x5501c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5501c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csiphy1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csiphy_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csiphy2_clk = {
+ .halt_reg = 0x55020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x55020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csiphy2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_csiphy_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_gp0_clk = {
+ .halt_reg = 0x50018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x50018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_gp0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_gp0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_gp1_clk = {
+ .halt_reg = 0x50034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x50034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_gp1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_gp1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_ispif_ahb_clk = {
+ .halt_reg = 0x540a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x540a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_ispif_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_jpeg_ahb_clk = {
+ .halt_reg = 0x52048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x52048,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_jpeg_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_jpeg_axi_clk = {
+ .halt_reg = 0x5204c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5204c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_jpeg_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_jpeg_clk = {
+ .halt_reg = 0x52040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x52040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_jpeg_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_jpeg_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_mclk0_clk = {
+ .halt_reg = 0x51018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x51018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_mclk0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_mclk1_clk = {
+ .halt_reg = 0x51034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x51034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_mclk1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_mclk2_clk = {
+ .halt_reg = 0x51050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x51050,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_mclk2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_mclk3_clk = {
+ .halt_reg = 0x5106c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5106c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_mclk3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_micro_ahb_clk = {
+ .halt_reg = 0x560b0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x560b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_micro_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_throttle_nrt_axi_clk = {
+ .halt_reg = 0x560a4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(27),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_throttle_nrt_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_throttle_rt_axi_clk = {
+ .halt_reg = 0x560a8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(26),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_throttle_rt_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_top_ahb_clk = {
+ .halt_reg = 0x560a0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x560a0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_top_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_vfe0_ahb_clk = {
+ .halt_reg = 0x54034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x54034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_vfe0_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_vfe0_clk = {
+ .halt_reg = 0x54028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x54028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_vfe0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_vfe0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_vfe0_stream_clk = {
+ .halt_reg = 0x54030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x54030,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_vfe0_stream_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_vfe0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_vfe1_ahb_clk = {
+ .halt_reg = 0x5406c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5406c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_vfe1_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_vfe1_clk = {
+ .halt_reg = 0x54060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x54060,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_vfe1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_vfe1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_vfe1_stream_clk = {
+ .halt_reg = 0x54068,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x54068,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_vfe1_stream_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_vfe1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_vfe_tsctr_clk = {
+ .halt_reg = 0x5409c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5409c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_vfe_tsctr_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_vfe_vbif_ahb_clk = {
+ .halt_reg = 0x5408c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5408c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_vfe_vbif_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_vfe_vbif_axi_clk = {
+ .halt_reg = 0x54090,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x54090,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_vfe_vbif_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ce1_ahb_clk = {
+ .halt_reg = 0x2700c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2700c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(3),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ce1_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ce1_axi_clk = {
+ .halt_reg = 0x27008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ce1_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ce1_clk = {
+ .halt_reg = 0x27004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(5),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ce1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = {
+ .halt_reg = 0x1a084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1a084,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_cfg_noc_usb3_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cpuss_gnoc_clk = {
+ .halt_reg = 0x2b004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2b004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(22),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_cpuss_gnoc_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_ahb_clk = {
+ .halt_reg = 0x1700c,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x1700c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1700c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_disp_ahb_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_gpll0_div_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(20),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_disp_gpll0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpll0_out_early.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_hf_axi_clk = {
+ .halt_reg = 0x17020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_disp_hf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_throttle_core_clk = {
+ .halt_reg = 0x17064,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(5),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_disp_throttle_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_xo_clk = {
+ .halt_reg = 0x1702c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1702c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_disp_xo_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp1_clk = {
+ .halt_reg = 0x4d000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4d000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_gp1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp2_clk = {
+ .halt_reg = 0x4e000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4e000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_gp2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp3_clk = {
+ .halt_reg = 0x4f000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4f000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_gp3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_cfg_ahb_clk = {
+ .halt_reg = 0x36004,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x36004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x36004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_cfg_ahb_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_gpll0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpll0_out_early.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_div_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(16),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_gpll0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpll0_out_aux2.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_memnoc_gfx_clk = {
+ .halt_reg = 0x3600c,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x3600c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_memnoc_gfx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = {
+ .halt_reg = 0x36018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_snoc_dvm_gfx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_throttle_core_clk = {
+ .halt_reg = 0x36048,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(31),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_throttle_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_throttle_xo_clk = {
+ .halt_reg = 0x36044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_throttle_xo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mss_vs_clk = {
+ .halt_reg = 0x42048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x42048,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_vs_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_vsensor_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+ .halt_reg = 0x2000c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2000c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_pdm2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+ .halt_reg = 0x20004,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x20004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x20004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_xo4_clk = {
+ .halt_reg = 0x20008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x20008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm_xo4_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_prng_ahb_clk = {
+ .halt_reg = 0x21004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x21004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(13),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_prng_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_camera_nrt_ahb_clk = {
+ .halt_reg = 0x17014,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x17014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qmip_camera_nrt_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_camera_rt_ahb_clk = {
+ .halt_reg = 0x17060,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17060,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(2),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qmip_camera_rt_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_disp_ahb_clk = {
+ .halt_reg = 0x17018,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x17018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qmip_disp_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_gpu_cfg_ahb_clk = {
+ .halt_reg = 0x36040,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x36040,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qmip_gpu_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_video_vcodec_ahb_clk = {
+ .halt_reg = 0x17010,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x17010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(25),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qmip_video_vcodec_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_core_2x_clk = {
+ .halt_reg = 0x1f014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_core_clk = {
+ .halt_reg = 0x1f00c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(8),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s0_clk = {
+ .halt_reg = 0x1f144,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(10),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap0_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s1_clk = {
+ .halt_reg = 0x1f274,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(11),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap0_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s2_clk = {
+ .halt_reg = 0x1f3a4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(12),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap0_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s3_clk = {
+ .halt_reg = 0x1f4d4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(13),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap0_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s4_clk = {
+ .halt_reg = 0x1f604,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(14),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s4_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap0_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s5_clk = {
+ .halt_reg = 0x1f734,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s5_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap0_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_core_2x_clk = {
+ .halt_reg = 0x39014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(18),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_core_clk = {
+ .halt_reg = 0x3900c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(19),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s0_clk = {
+ .halt_reg = 0x39144,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(22),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_s0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap1_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s1_clk = {
+ .halt_reg = 0x39274,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(23),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_s1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap1_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s2_clk = {
+ .halt_reg = 0x393a4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(24),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_s2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap1_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s3_clk = {
+ .halt_reg = 0x394d4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(25),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_s3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap1_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s4_clk = {
+ .halt_reg = 0x39604,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(26),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_s4_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap1_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s5_clk = {
+ .halt_reg = 0x39734,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(27),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_s5_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap1_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_0_m_ahb_clk = {
+ .halt_reg = 0x1f004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(6),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap_0_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_0_s_ahb_clk = {
+ .halt_reg = 0x1f008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1f008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(7),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap_0_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_1_m_ahb_clk = {
+ .halt_reg = 0x39004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(20),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap_1_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = {
+ .halt_reg = 0x39008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x39008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(21),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap_1_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+ .halt_reg = 0x38008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x38008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_apps_clk = {
+ .halt_reg = 0x38004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x38004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_apps_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_sdcc1_apps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ice_core_clk = {
+ .halt_reg = 0x3800c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3800c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_ice_core_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_sdcc1_ice_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_ahb_clk = {
+ .halt_reg = 0x1e008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1e008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc2_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_apps_clk = {
+ .halt_reg = 0x1e004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1e004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc2_apps_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_sdcc2_apps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sys_noc_compute_sf_axi_clk = {
+ .halt_reg = 0x1050c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1050c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sys_noc_compute_sf_axi_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sys_noc_cpuss_ahb_clk = {
+ .halt_reg = 0x2b06c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sys_noc_cpuss_ahb_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sys_noc_ufs_phy_axi_clk = {
+ .halt_reg = 0x45098,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x45098,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sys_noc_ufs_phy_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sys_noc_usb3_prim_axi_clk = {
+ .halt_reg = 0x1a080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1a080,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sys_noc_usb3_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_mem_clkref_clk = {
+ .halt_reg = 0x8c000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8c000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_mem_clkref_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_ahb_clk = {
+ .halt_reg = 0x45014,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x45014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x45014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_axi_clk = {
+ .halt_reg = 0x45010,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x45010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x45010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_ice_core_clk = {
+ .halt_reg = 0x45044,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x45044,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x45044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_ice_core_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_phy_aux_clk = {
+ .halt_reg = 0x45078,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x45078,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x45078,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = {
+ .halt_reg = 0x4501c,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x4501c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_rx_symbol_0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = {
+ .halt_reg = 0x45018,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x45018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_tx_symbol_0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_unipro_core_clk = {
+ .halt_reg = 0x45040,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x45040,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x45040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_unipro_core_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_master_clk = {
+ .halt_reg = 0x1a010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1a010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_prim_master_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_mock_utmi_clk = {
+ .halt_reg = 0x1a018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1a018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_prim_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_sleep_clk = {
+ .halt_reg = 0x1a014,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1a014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_prim_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_clkref_clk = {
+ .halt_reg = 0x80278,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80278,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_prim_clkref_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = {
+ .halt_reg = 0x1a054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1a054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_prim_phy_com_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_pipe_clk = {
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x1a058,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_prim_phy_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_vdda_vs_clk = {
+ .halt_reg = 0x4200c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4200c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_vdda_vs_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_vsensor_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_vddcx_vs_clk = {
+ .halt_reg = 0x42004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x42004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_vddcx_vs_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_vsensor_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_vddmx_vs_clk = {
+ .halt_reg = 0x42008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x42008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_vddmx_vs_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_vsensor_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_ahb_clk = {
+ .halt_reg = 0x17004,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x17004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x17004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_video_ahb_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_axi0_clk = {
+ .halt_reg = 0x1701c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1701c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_video_axi0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_throttle_core_clk = {
+ .halt_reg = 0x17068,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(28),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_video_throttle_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_xo_clk = {
+ .halt_reg = 0x17024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_video_xo_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_vs_ctrl_ahb_clk = {
+ .halt_reg = 0x42014,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x42014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x42014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_vs_ctrl_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_vs_ctrl_clk = {
+ .halt_reg = 0x42010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x42010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_vs_ctrl_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_vs_ctrl_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_wcss_vs_clk = {
+ .halt_reg = 0x42050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x42050,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_wcss_vs_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_vsensor_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc usb30_prim_gdsc = {
+ .gdscr = 0x1a004,
+ .pd = {
+ .name = "usb30_prim_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ufs_phy_gdsc = {
+ .gdscr = 0x45004,
+ .pd = {
+ .name = "ufs_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc camss_vfe0_gdsc = {
+ .gdscr = 0x54004,
+ .pd = {
+ .name = "camss_vfe0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc camss_vfe1_gdsc = {
+ .gdscr = 0x5403c,
+ .pd = {
+ .name = "camss_vfe1_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc camss_top_gdsc = {
+ .gdscr = 0x5607c,
+ .pd = {
+ .name = "camss_top_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc cam_cpp_gdsc = {
+ .gdscr = 0x560bc,
+ .pd = {
+ .name = "cam_cpp_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc hlos1_vote_turing_mmu_tbu1_gdsc = {
+ .gdscr = 0x7d060,
+ .pd = {
+ .name = "hlos1_vote_turing_mmu_tbu1_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
+static struct gdsc hlos1_vote_mm_snoc_mmu_tbu_rt_gdsc = {
+ .gdscr = 0x80074,
+ .pd = {
+ .name = "hlos1_vote_mm_snoc_mmu_tbu_rt_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
+static struct gdsc hlos1_vote_mm_snoc_mmu_tbu_nrt_gdsc = {
+ .gdscr = 0x80084,
+ .pd = {
+ .name = "hlos1_vote_mm_snoc_mmu_tbu_nrt_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
+
+static struct gdsc hlos1_vote_turing_mmu_tbu0_gdsc = {
+ .gdscr = 0x80094,
+ .pd = {
+ .name = "hlos1_vote_turing_mmu_tbu0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
+static struct gdsc *gcc_sm6125_gdscs[] = {
+ [USB30_PRIM_GDSC] = &usb30_prim_gdsc,
+ [UFS_PHY_GDSC] = &ufs_phy_gdsc,
+ [CAMSS_VFE0_GDSC] = &camss_vfe0_gdsc,
+ [CAMSS_VFE1_GDSC] = &camss_vfe1_gdsc,
+ [CAMSS_TOP_GDSC] = &camss_top_gdsc,
+ [CAM_CPP_GDSC] = &cam_cpp_gdsc,
+ [HLOS1_VOTE_TURING_MMU_TBU1_GDSC] = &hlos1_vote_turing_mmu_tbu1_gdsc,
+ [HLOS1_VOTE_MM_SNOC_MMU_TBU_RT_GDSC] = &hlos1_vote_mm_snoc_mmu_tbu_rt_gdsc,
+ [HLOS1_VOTE_MM_SNOC_MMU_TBU_NRT_GDSC] = &hlos1_vote_mm_snoc_mmu_tbu_nrt_gdsc,
+ [HLOS1_VOTE_TURING_MMU_TBU0_GDSC] = &hlos1_vote_turing_mmu_tbu0_gdsc,
+};
+
+static struct clk_hw *gcc_sm6125_hws[] = {
+ [GPLL0_OUT_AUX2] = &gpll0_out_aux2.hw,
+ [GPLL0_OUT_MAIN] = &gpll0_out_main.hw,
+ [GPLL6_OUT_MAIN] = &gpll6_out_main.hw,
+ [GPLL7_OUT_MAIN] = &gpll7_out_main.hw,
+ [GPLL8_OUT_MAIN] = &gpll8_out_main.hw,
+ [GPLL9_OUT_MAIN] = &gpll9_out_main.hw,
+};
+
+static struct clk_regmap *gcc_sm6125_clocks[] = {
+ [GCC_AHB2PHY_CSI_CLK] = &gcc_ahb2phy_csi_clk.clkr,
+ [GCC_AHB2PHY_USB_CLK] = &gcc_ahb2phy_usb_clk.clkr,
+ [GCC_APC_VS_CLK] = &gcc_apc_vs_clk.clkr,
+ [GCC_BIMC_GPU_AXI_CLK] = &gcc_bimc_gpu_axi_clk.clkr,
+ [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+ [GCC_CAMERA_AHB_CLK] = &gcc_camera_ahb_clk.clkr,
+ [GCC_CAMERA_XO_CLK] = &gcc_camera_xo_clk.clkr,
+ [GCC_CAMSS_AHB_CLK_SRC] = &gcc_camss_ahb_clk_src.clkr,
+ [GCC_CAMSS_CCI_AHB_CLK] = &gcc_camss_cci_ahb_clk.clkr,
+ [GCC_CAMSS_CCI_CLK] = &gcc_camss_cci_clk.clkr,
+ [GCC_CAMSS_CCI_CLK_SRC] = &gcc_camss_cci_clk_src.clkr,
+ [GCC_CAMSS_CPHY_CSID0_CLK] = &gcc_camss_cphy_csid0_clk.clkr,
+ [GCC_CAMSS_CPHY_CSID1_CLK] = &gcc_camss_cphy_csid1_clk.clkr,
+ [GCC_CAMSS_CPHY_CSID2_CLK] = &gcc_camss_cphy_csid2_clk.clkr,
+ [GCC_CAMSS_CPHY_CSID3_CLK] = &gcc_camss_cphy_csid3_clk.clkr,
+ [GCC_CAMSS_CPP_AHB_CLK] = &gcc_camss_cpp_ahb_clk.clkr,
+ [GCC_CAMSS_CPP_AXI_CLK] = &gcc_camss_cpp_axi_clk.clkr,
+ [GCC_CAMSS_CPP_CLK] = &gcc_camss_cpp_clk.clkr,
+ [GCC_CAMSS_CPP_CLK_SRC] = &gcc_camss_cpp_clk_src.clkr,
+ [GCC_CAMSS_CPP_VBIF_AHB_CLK] = &gcc_camss_cpp_vbif_ahb_clk.clkr,
+ [GCC_CAMSS_CSI0_AHB_CLK] = &gcc_camss_csi0_ahb_clk.clkr,
+ [GCC_CAMSS_CSI0_CLK] = &gcc_camss_csi0_clk.clkr,
+ [GCC_CAMSS_CSI0_CLK_SRC] = &gcc_camss_csi0_clk_src.clkr,
+ [GCC_CAMSS_CSI0PHYTIMER_CLK] = &gcc_camss_csi0phytimer_clk.clkr,
+ [GCC_CAMSS_CSI0PHYTIMER_CLK_SRC] = &gcc_camss_csi0phytimer_clk_src.clkr,
+ [GCC_CAMSS_CSI0PIX_CLK] = &gcc_camss_csi0pix_clk.clkr,
+ [GCC_CAMSS_CSI0RDI_CLK] = &gcc_camss_csi0rdi_clk.clkr,
+ [GCC_CAMSS_CSI1_AHB_CLK] = &gcc_camss_csi1_ahb_clk.clkr,
+ [GCC_CAMSS_CSI1_CLK] = &gcc_camss_csi1_clk.clkr,
+ [GCC_CAMSS_CSI1_CLK_SRC] = &gcc_camss_csi1_clk_src.clkr,
+ [GCC_CAMSS_CSI1PHYTIMER_CLK] = &gcc_camss_csi1phytimer_clk.clkr,
+ [GCC_CAMSS_CSI1PHYTIMER_CLK_SRC] = &gcc_camss_csi1phytimer_clk_src.clkr,
+ [GCC_CAMSS_CSI1PIX_CLK] = &gcc_camss_csi1pix_clk.clkr,
+ [GCC_CAMSS_CSI1RDI_CLK] = &gcc_camss_csi1rdi_clk.clkr,
+ [GCC_CAMSS_CSI2_AHB_CLK] = &gcc_camss_csi2_ahb_clk.clkr,
+ [GCC_CAMSS_CSI2_CLK] = &gcc_camss_csi2_clk.clkr,
+ [GCC_CAMSS_CSI2_CLK_SRC] = &gcc_camss_csi2_clk_src.clkr,
+ [GCC_CAMSS_CSI2PHYTIMER_CLK] = &gcc_camss_csi2phytimer_clk.clkr,
+ [GCC_CAMSS_CSI2PHYTIMER_CLK_SRC] = &gcc_camss_csi2phytimer_clk_src.clkr,
+ [GCC_CAMSS_CSI2PIX_CLK] = &gcc_camss_csi2pix_clk.clkr,
+ [GCC_CAMSS_CSI2RDI_CLK] = &gcc_camss_csi2rdi_clk.clkr,
+ [GCC_CAMSS_CSI3_AHB_CLK] = &gcc_camss_csi3_ahb_clk.clkr,
+ [GCC_CAMSS_CSI3_CLK] = &gcc_camss_csi3_clk.clkr,
+ [GCC_CAMSS_CSI3_CLK_SRC] = &gcc_camss_csi3_clk_src.clkr,
+ [GCC_CAMSS_CSI3PIX_CLK] = &gcc_camss_csi3pix_clk.clkr,
+ [GCC_CAMSS_CSI3RDI_CLK] = &gcc_camss_csi3rdi_clk.clkr,
+ [GCC_CAMSS_CSI_VFE0_CLK] = &gcc_camss_csi_vfe0_clk.clkr,
+ [GCC_CAMSS_CSI_VFE1_CLK] = &gcc_camss_csi_vfe1_clk.clkr,
+ [GCC_CAMSS_CSIPHY0_CLK] = &gcc_camss_csiphy0_clk.clkr,
+ [GCC_CAMSS_CSIPHY1_CLK] = &gcc_camss_csiphy1_clk.clkr,
+ [GCC_CAMSS_CSIPHY2_CLK] = &gcc_camss_csiphy2_clk.clkr,
+ [GCC_CAMSS_CSIPHY_CLK_SRC] = &gcc_camss_csiphy_clk_src.clkr,
+ [GCC_CAMSS_GP0_CLK] = &gcc_camss_gp0_clk.clkr,
+ [GCC_CAMSS_GP0_CLK_SRC] = &gcc_camss_gp0_clk_src.clkr,
+ [GCC_CAMSS_GP1_CLK] = &gcc_camss_gp1_clk.clkr,
+ [GCC_CAMSS_GP1_CLK_SRC] = &gcc_camss_gp1_clk_src.clkr,
+ [GCC_CAMSS_ISPIF_AHB_CLK] = &gcc_camss_ispif_ahb_clk.clkr,
+ [GCC_CAMSS_JPEG_AHB_CLK] = &gcc_camss_jpeg_ahb_clk.clkr,
+ [GCC_CAMSS_JPEG_AXI_CLK] = &gcc_camss_jpeg_axi_clk.clkr,
+ [GCC_CAMSS_JPEG_CLK] = &gcc_camss_jpeg_clk.clkr,
+ [GCC_CAMSS_JPEG_CLK_SRC] = &gcc_camss_jpeg_clk_src.clkr,
+ [GCC_CAMSS_MCLK0_CLK] = &gcc_camss_mclk0_clk.clkr,
+ [GCC_CAMSS_MCLK0_CLK_SRC] = &gcc_camss_mclk0_clk_src.clkr,
+ [GCC_CAMSS_MCLK1_CLK] = &gcc_camss_mclk1_clk.clkr,
+ [GCC_CAMSS_MCLK1_CLK_SRC] = &gcc_camss_mclk1_clk_src.clkr,
+ [GCC_CAMSS_MCLK2_CLK] = &gcc_camss_mclk2_clk.clkr,
+ [GCC_CAMSS_MCLK2_CLK_SRC] = &gcc_camss_mclk2_clk_src.clkr,
+ [GCC_CAMSS_MCLK3_CLK] = &gcc_camss_mclk3_clk.clkr,
+ [GCC_CAMSS_MCLK3_CLK_SRC] = &gcc_camss_mclk3_clk_src.clkr,
+ [GCC_CAMSS_MICRO_AHB_CLK] = &gcc_camss_micro_ahb_clk.clkr,
+ [GCC_CAMSS_THROTTLE_NRT_AXI_CLK] = &gcc_camss_throttle_nrt_axi_clk.clkr,
+ [GCC_CAMSS_THROTTLE_RT_AXI_CLK] = &gcc_camss_throttle_rt_axi_clk.clkr,
+ [GCC_CAMSS_TOP_AHB_CLK] = &gcc_camss_top_ahb_clk.clkr,
+ [GCC_CAMSS_VFE0_AHB_CLK] = &gcc_camss_vfe0_ahb_clk.clkr,
+ [GCC_CAMSS_VFE0_CLK] = &gcc_camss_vfe0_clk.clkr,
+ [GCC_CAMSS_VFE0_CLK_SRC] = &gcc_camss_vfe0_clk_src.clkr,
+ [GCC_CAMSS_VFE0_STREAM_CLK] = &gcc_camss_vfe0_stream_clk.clkr,
+ [GCC_CAMSS_VFE1_AHB_CLK] = &gcc_camss_vfe1_ahb_clk.clkr,
+ [GCC_CAMSS_VFE1_CLK] = &gcc_camss_vfe1_clk.clkr,
+ [GCC_CAMSS_VFE1_CLK_SRC] = &gcc_camss_vfe1_clk_src.clkr,
+ [GCC_CAMSS_VFE1_STREAM_CLK] = &gcc_camss_vfe1_stream_clk.clkr,
+ [GCC_CAMSS_VFE_TSCTR_CLK] = &gcc_camss_vfe_tsctr_clk.clkr,
+ [GCC_CAMSS_VFE_VBIF_AHB_CLK] = &gcc_camss_vfe_vbif_ahb_clk.clkr,
+ [GCC_CAMSS_VFE_VBIF_AXI_CLK] = &gcc_camss_vfe_vbif_axi_clk.clkr,
+ [GCC_CE1_AHB_CLK] = &gcc_ce1_ahb_clk.clkr,
+ [GCC_CE1_AXI_CLK] = &gcc_ce1_axi_clk.clkr,
+ [GCC_CE1_CLK] = &gcc_ce1_clk.clkr,
+ [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr,
+ [GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr,
+ [GCC_DISP_AHB_CLK] = &gcc_disp_ahb_clk.clkr,
+ [GCC_DISP_GPLL0_DIV_CLK_SRC] = &gcc_disp_gpll0_div_clk_src.clkr,
+ [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr,
+ [GCC_DISP_THROTTLE_CORE_CLK] = &gcc_disp_throttle_core_clk.clkr,
+ [GCC_DISP_XO_CLK] = &gcc_disp_xo_clk.clkr,
+ [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+ [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr,
+ [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+ [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr,
+ [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+ [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr,
+ [GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr,
+ [GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr,
+ [GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr,
+ [GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr,
+ [GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr,
+ [GCC_GPU_THROTTLE_CORE_CLK] = &gcc_gpu_throttle_core_clk.clkr,
+ [GCC_GPU_THROTTLE_XO_CLK] = &gcc_gpu_throttle_xo_clk.clkr,
+ [GCC_MSS_VS_CLK] = &gcc_mss_vs_clk.clkr,
+ [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+ [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr,
+ [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+ [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr,
+ [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr,
+ [GCC_QMIP_CAMERA_NRT_AHB_CLK] = &gcc_qmip_camera_nrt_ahb_clk.clkr,
+ [GCC_QMIP_CAMERA_RT_AHB_CLK] = &gcc_qmip_camera_rt_ahb_clk.clkr,
+ [GCC_QMIP_DISP_AHB_CLK] = &gcc_qmip_disp_ahb_clk.clkr,
+ [GCC_QMIP_GPU_CFG_AHB_CLK] = &gcc_qmip_gpu_cfg_ahb_clk.clkr,
+ [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP0_CORE_2X_CLK] = &gcc_qupv3_wrap0_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP0_CORE_CLK] = &gcc_qupv3_wrap0_core_clk.clkr,
+ [GCC_QUPV3_WRAP0_S0_CLK] = &gcc_qupv3_wrap0_s0_clk.clkr,
+ [GCC_QUPV3_WRAP0_S0_CLK_SRC] = &gcc_qupv3_wrap0_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S1_CLK] = &gcc_qupv3_wrap0_s1_clk.clkr,
+ [GCC_QUPV3_WRAP0_S1_CLK_SRC] = &gcc_qupv3_wrap0_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S2_CLK] = &gcc_qupv3_wrap0_s2_clk.clkr,
+ [GCC_QUPV3_WRAP0_S2_CLK_SRC] = &gcc_qupv3_wrap0_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S3_CLK] = &gcc_qupv3_wrap0_s3_clk.clkr,
+ [GCC_QUPV3_WRAP0_S3_CLK_SRC] = &gcc_qupv3_wrap0_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S4_CLK] = &gcc_qupv3_wrap0_s4_clk.clkr,
+ [GCC_QUPV3_WRAP0_S4_CLK_SRC] = &gcc_qupv3_wrap0_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S5_CLK] = &gcc_qupv3_wrap0_s5_clk.clkr,
+ [GCC_QUPV3_WRAP0_S5_CLK_SRC] = &gcc_qupv3_wrap0_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_CORE_2X_CLK] = &gcc_qupv3_wrap1_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP1_CORE_CLK] = &gcc_qupv3_wrap1_core_clk.clkr,
+ [GCC_QUPV3_WRAP1_S0_CLK] = &gcc_qupv3_wrap1_s0_clk.clkr,
+ [GCC_QUPV3_WRAP1_S0_CLK_SRC] = &gcc_qupv3_wrap1_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S1_CLK] = &gcc_qupv3_wrap1_s1_clk.clkr,
+ [GCC_QUPV3_WRAP1_S1_CLK_SRC] = &gcc_qupv3_wrap1_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S2_CLK] = &gcc_qupv3_wrap1_s2_clk.clkr,
+ [GCC_QUPV3_WRAP1_S2_CLK_SRC] = &gcc_qupv3_wrap1_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S3_CLK] = &gcc_qupv3_wrap1_s3_clk.clkr,
+ [GCC_QUPV3_WRAP1_S3_CLK_SRC] = &gcc_qupv3_wrap1_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S4_CLK] = &gcc_qupv3_wrap1_s4_clk.clkr,
+ [GCC_QUPV3_WRAP1_S4_CLK_SRC] = &gcc_qupv3_wrap1_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S5_CLK] = &gcc_qupv3_wrap1_s5_clk.clkr,
+ [GCC_QUPV3_WRAP1_S5_CLK_SRC] = &gcc_qupv3_wrap1_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP_0_M_AHB_CLK] = &gcc_qupv3_wrap_0_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_0_S_AHB_CLK] = &gcc_qupv3_wrap_0_s_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_1_M_AHB_CLK] = &gcc_qupv3_wrap_1_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr,
+ [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+ [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+ [GCC_SDCC1_APPS_CLK_SRC] = &gcc_sdcc1_apps_clk_src.clkr,
+ [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr,
+ [GCC_SDCC1_ICE_CORE_CLK_SRC] = &gcc_sdcc1_ice_core_clk_src.clkr,
+ [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+ [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+ [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr,
+ [GCC_SYS_NOC_COMPUTE_SF_AXI_CLK] = &gcc_sys_noc_compute_sf_axi_clk.clkr,
+ [GCC_SYS_NOC_CPUSS_AHB_CLK] = &gcc_sys_noc_cpuss_ahb_clk.clkr,
+ [GCC_SYS_NOC_UFS_PHY_AXI_CLK] = &gcc_sys_noc_ufs_phy_axi_clk.clkr,
+ [GCC_SYS_NOC_USB3_PRIM_AXI_CLK] = &gcc_sys_noc_usb3_prim_axi_clk.clkr,
+ [GCC_UFS_MEM_CLKREF_CLK] = &gcc_ufs_mem_clkref_clk.clkr,
+ [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr,
+ [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr,
+ [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr,
+ [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr,
+ [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr,
+ [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr,
+ [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr,
+ [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr,
+ [GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr,
+ [GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] =
+ &gcc_ufs_phy_unipro_core_clk_src.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] =
+ &gcc_usb30_prim_mock_utmi_clk_src.clkr,
+ [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr,
+ [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr,
+ [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr,
+ [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr,
+ [GCC_VDDA_VS_CLK] = &gcc_vdda_vs_clk.clkr,
+ [GCC_VDDCX_VS_CLK] = &gcc_vddcx_vs_clk.clkr,
+ [GCC_VDDMX_VS_CLK] = &gcc_vddmx_vs_clk.clkr,
+ [GCC_VIDEO_AHB_CLK] = &gcc_video_ahb_clk.clkr,
+ [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr,
+ [GCC_VIDEO_THROTTLE_CORE_CLK] = &gcc_video_throttle_core_clk.clkr,
+ [GCC_VIDEO_XO_CLK] = &gcc_video_xo_clk.clkr,
+ [GCC_VS_CTRL_AHB_CLK] = &gcc_vs_ctrl_ahb_clk.clkr,
+ [GCC_VS_CTRL_CLK] = &gcc_vs_ctrl_clk.clkr,
+ [GCC_VS_CTRL_CLK_SRC] = &gcc_vs_ctrl_clk_src.clkr,
+ [GCC_VSENSOR_CLK_SRC] = &gcc_vsensor_clk_src.clkr,
+ [GCC_WCSS_VS_CLK] = &gcc_wcss_vs_clk.clkr,
+ [GPLL0_OUT_EARLY] = &gpll0_out_early.clkr,
+ [GPLL3_OUT_EARLY] = &gpll3_out_early.clkr,
+ [GPLL4_OUT_MAIN] = &gpll4_out_main.clkr,
+ [GPLL5_OUT_MAIN] = &gpll5_out_main.clkr,
+ [GPLL6_OUT_EARLY] = &gpll6_out_early.clkr,
+ [GPLL7_OUT_EARLY] = &gpll7_out_early.clkr,
+ [GPLL8_OUT_EARLY] = &gpll8_out_early.clkr,
+ [GPLL9_OUT_EARLY] = &gpll9_out_early.clkr,
+ [GCC_USB3_PRIM_CLKREF_CLK] = &gcc_usb3_prim_clkref_clk.clkr,
+};
+
+static const struct qcom_reset_map gcc_sm6125_resets[] = {
+ [GCC_QUSB2PHY_PRIM_BCR] = { 0x1c000 },
+ [GCC_QUSB2PHY_SEC_BCR] = { 0x1c004 },
+ [GCC_UFS_PHY_BCR] = { 0x45000 },
+ [GCC_USB30_PRIM_BCR] = { 0x1a000 },
+ [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x1d000 },
+ [GCC_USB3PHY_PHY_PRIM_SP0_BCR] = { 0x1b008 },
+ [GCC_USB3_PHY_PRIM_SP0_BCR] = { 0x1b000 },
+ [GCC_CAMSS_MICRO_BCR] = { 0x560ac },
+};
+
+static struct clk_rcg_dfs_data gcc_dfs_clocks[] = {
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk_src),
+};
+
+static const struct regmap_config gcc_sm6125_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xc7000,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc gcc_sm6125_desc = {
+ .config = &gcc_sm6125_regmap_config,
+ .clks = gcc_sm6125_clocks,
+ .num_clks = ARRAY_SIZE(gcc_sm6125_clocks),
+ .clk_hws = gcc_sm6125_hws,
+ .num_clk_hws = ARRAY_SIZE(gcc_sm6125_hws),
+ .resets = gcc_sm6125_resets,
+ .num_resets = ARRAY_SIZE(gcc_sm6125_resets),
+ .gdscs = gcc_sm6125_gdscs,
+ .num_gdscs = ARRAY_SIZE(gcc_sm6125_gdscs),
+};
+
+static const struct of_device_id gcc_sm6125_match_table[] = {
+ { .compatible = "qcom,gcc-sm6125" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gcc_sm6125_match_table);
+
+static int gcc_sm6125_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+ int ret;
+
+ regmap = qcom_cc_map(pdev, &gcc_sm6125_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /*
+ * Disable the GPLL0 active input to video block via
+ * MISC registers.
+ */
+ regmap_update_bits(regmap, 0x80258, 0x1, 0x1);
+
+ /*
+ * Enable DUAL_EDGE mode for MCLK RCGs
+ * This is requierd to enable MND divider mode
+ */
+ regmap_update_bits(regmap, 0x51004, 0x3000, 0x2000);
+ regmap_update_bits(regmap, 0x51020, 0x3000, 0x2000);
+ regmap_update_bits(regmap, 0x5103c, 0x3000, 0x2000);
+ regmap_update_bits(regmap, 0x51058, 0x3000, 0x2000);
+
+ ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks,
+ ARRAY_SIZE(gcc_dfs_clocks));
+ if (ret)
+ return ret;
+
+ return qcom_cc_really_probe(pdev, &gcc_sm6125_desc, regmap);
+}
+
+static struct platform_driver gcc_sm6125_driver = {
+ .probe = gcc_sm6125_probe,
+ .driver = {
+ .name = "gcc-sm6125",
+ .of_match_table = gcc_sm6125_match_table,
+ },
+};
+
+static int __init gcc_sm6125_init(void)
+{
+ return platform_driver_register(&gcc_sm6125_driver);
+}
+subsys_initcall(gcc_sm6125_init);
+
+static void __exit gcc_sm6125_exit(void)
+{
+ platform_driver_unregister(&gcc_sm6125_driver);
+}
+module_exit(gcc_sm6125_exit);
+
+MODULE_DESCRIPTION("QTI GCC SM6125 Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
index 607e64a17d72..7b450650bcae 100644
--- a/drivers/clk/renesas/Kconfig
+++ b/drivers/clk/renesas/Kconfig
@@ -32,6 +32,7 @@ config CLK_RENESAS
select CLK_R8A77995 if ARCH_R8A77995
select CLK_R8A779A0 if ARCH_R8A779A0
select CLK_R9A06G032 if ARCH_R9A06G032
+ select CLK_R9A07G044 if ARCH_R9A07G044
select CLK_SH73A0 if ARCH_SH73A0
if CLK_RENESAS
@@ -156,6 +157,10 @@ config CLK_R9A06G032
help
This is a driver for R9A06G032 clocks
+config CLK_R9A07G044
+ bool "RZ/G2L clock support" if COMPILE_TEST
+ select CLK_RZG2L
+
config CLK_SH73A0
bool "SH-Mobile AG5 clock support" if COMPILE_TEST
select CLK_RENESAS_CPG_MSTP
@@ -182,6 +187,10 @@ config CLK_RCAR_USB2_CLOCK_SEL
help
This is a driver for R-Car USB2 clock selector
+config CLK_RZG2L
+ bool "Renesas RZ/G2L family clock support" if COMPILE_TEST
+ select RESET_CONTROLLER
+
# Generic
config CLK_RENESAS_CPG_MSSR
bool "CPG/MSSR clock support" if COMPILE_TEST
diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile
index ef0d2bba92bf..5c6c5c721d98 100644
--- a/drivers/clk/renesas/Makefile
+++ b/drivers/clk/renesas/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_CLK_R8A77990) += r8a77990-cpg-mssr.o
obj-$(CONFIG_CLK_R8A77995) += r8a77995-cpg-mssr.o
obj-$(CONFIG_CLK_R8A779A0) += r8a779a0-cpg-mssr.o
obj-$(CONFIG_CLK_R9A06G032) += r9a06g032-clocks.o
+obj-$(CONFIG_CLK_R9A07G044) += r9a07g044-cpg.o
obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o
# Family
@@ -36,6 +37,7 @@ obj-$(CONFIG_CLK_RCAR_CPG_LIB) += rcar-cpg-lib.o
obj-$(CONFIG_CLK_RCAR_GEN2_CPG) += rcar-gen2-cpg.o
obj-$(CONFIG_CLK_RCAR_GEN3_CPG) += rcar-gen3-cpg.o
obj-$(CONFIG_CLK_RCAR_USB2_CLOCK_SEL) += rcar-usb2-clock-sel.o
+obj-$(CONFIG_CLK_RZG2L) += renesas-rzg2l-cpg.o
# Generic
obj-$(CONFIG_CLK_RENESAS_CPG_MSSR) += renesas-cpg-mssr.o
diff --git a/drivers/clk/renesas/clk-div6.c b/drivers/clk/renesas/clk-div6.c
index 8fb68e703a6b..3abd6e5400ad 100644
--- a/drivers/clk/renesas/clk-div6.c
+++ b/drivers/clk/renesas/clk-div6.c
@@ -28,8 +28,7 @@
* @hw: handle between common and hardware-specific interfaces
* @reg: IO-remapped register
* @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)
+ * @src_mask: Bitmask covering the register bits to select the parent clock
* @nb: Notifier block to save/restore clock state for system resume
* @parents: Array to map from valid parent clocks indices to hardware indices
*/
@@ -37,8 +36,7 @@ struct div6_clock {
struct clk_hw hw;
void __iomem *reg;
unsigned int div;
- u32 src_shift;
- u32 src_width;
+ u32 src_mask;
struct notifier_block nb;
u8 parents[];
};
@@ -99,15 +97,52 @@ static unsigned int cpg_div6_clock_calc_div(unsigned long rate,
rate = 1;
div = DIV_ROUND_CLOSEST(parent_rate, rate);
- return clamp_t(unsigned int, div, 1, 64);
+ return clamp(div, 1U, 64U);
}
-static long cpg_div6_clock_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int cpg_div6_clock_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- unsigned int div = cpg_div6_clock_calc_div(rate, *parent_rate);
+ unsigned long prate, calc_rate, diff, best_rate, best_prate;
+ unsigned int num_parents = clk_hw_get_num_parents(hw);
+ struct clk_hw *parent, *best_parent = NULL;
+ unsigned int i, min_div, max_div, div;
+ unsigned long min_diff = ULONG_MAX;
+
+ for (i = 0; i < num_parents; i++) {
+ parent = clk_hw_get_parent_by_index(hw, i);
+ if (!parent)
+ continue;
+
+ prate = clk_hw_get_rate(parent);
+ if (!prate)
+ continue;
+
+ min_div = max(DIV_ROUND_UP(prate, req->max_rate), 1UL);
+ max_div = req->min_rate ? min(prate / req->min_rate, 64UL) : 64;
+ if (max_div < min_div)
+ continue;
+
+ div = cpg_div6_clock_calc_div(req->rate, prate);
+ div = clamp(div, min_div, max_div);
+ calc_rate = prate / div;
+ diff = calc_rate > req->rate ? calc_rate - req->rate
+ : req->rate - calc_rate;
+ if (diff < min_diff) {
+ best_rate = calc_rate;
+ best_parent = parent;
+ best_prate = prate;
+ min_diff = diff;
+ }
+ }
+
+ if (!best_parent)
+ return -EINVAL;
- return *parent_rate / div;
+ req->best_parent_rate = best_prate;
+ req->best_parent_hw = best_parent;
+ req->rate = best_rate;
+ return 0;
}
static int cpg_div6_clock_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -133,11 +168,11 @@ static u8 cpg_div6_clock_get_parent(struct clk_hw *hw)
unsigned int i;
u8 hw_index;
- if (clock->src_width == 0)
+ if (clock->src_mask == 0)
return 0;
- hw_index = (readl(clock->reg) >> clock->src_shift) &
- (BIT(clock->src_width) - 1);
+ hw_index = (readl(clock->reg) & clock->src_mask) >>
+ __ffs(clock->src_mask);
for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
if (clock->parents[i] == hw_index)
return i;
@@ -151,18 +186,13 @@ static u8 cpg_div6_clock_get_parent(struct clk_hw *hw)
static int cpg_div6_clock_set_parent(struct clk_hw *hw, u8 index)
{
struct div6_clock *clock = to_div6_clock(hw);
- u8 hw_index;
- u32 mask;
+ u32 src;
if (index >= clk_hw_get_num_parents(hw))
return -EINVAL;
- mask = ~((BIT(clock->src_width) - 1) << clock->src_shift);
- hw_index = clock->parents[index];
-
- writel((readl(clock->reg) & mask) | (hw_index << clock->src_shift),
- clock->reg);
-
+ src = clock->parents[index] << __ffs(clock->src_mask);
+ writel((readl(clock->reg) & ~clock->src_mask) | src, clock->reg);
return 0;
}
@@ -173,7 +203,7 @@ static const struct clk_ops cpg_div6_clock_ops = {
.get_parent = cpg_div6_clock_get_parent,
.set_parent = cpg_div6_clock_set_parent,
.recalc_rate = cpg_div6_clock_recalc_rate,
- .round_rate = cpg_div6_clock_round_rate,
+ .determine_rate = cpg_div6_clock_determine_rate,
.set_rate = cpg_div6_clock_set_rate,
};
@@ -236,17 +266,15 @@ struct clk * __init cpg_div6_register(const char *name,
switch (num_parents) {
case 1:
/* fixed parent clock */
- clock->src_shift = clock->src_width = 0;
+ clock->src_mask = 0;
break;
case 4:
/* clock with EXSRC bits 6-7 */
- clock->src_shift = 6;
- clock->src_width = 2;
+ clock->src_mask = GENMASK(7, 6);
break;
case 8:
/* VCLK with EXSRC bits 12-14 */
- clock->src_shift = 12;
- clock->src_width = 3;
+ clock->src_mask = GENMASK(14, 12);
break;
default:
pr_err("%s: invalid number of parents for DIV6 clock %s\n",
diff --git a/drivers/clk/renesas/r8a77995-cpg-mssr.c b/drivers/clk/renesas/r8a77995-cpg-mssr.c
index 9cfd00cf4e69..81c0bc1e78af 100644
--- a/drivers/clk/renesas/r8a77995-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a77995-cpg-mssr.c
@@ -75,6 +75,7 @@ static const struct cpg_core_clk r8a77995_core_clks[] __initconst = {
DEF_RATE(".oco", CLK_OCO, 8 * 1000 * 1000),
/* Core Clock Outputs */
+ DEF_FIXED("za2", R8A77995_CLK_ZA2, CLK_PLL0D3, 2, 1),
DEF_FIXED("z2", R8A77995_CLK_Z2, CLK_PLL0D3, 1, 1),
DEF_FIXED("ztr", R8A77995_CLK_ZTR, CLK_PLL1, 6, 1),
DEF_FIXED("zt", R8A77995_CLK_ZT, CLK_PLL1, 4, 1),
diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c
index 867c565cb58f..acaf5a93f1d3 100644
--- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c
@@ -180,6 +180,10 @@ static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = {
DEF_MOD("i2c4", 522, R8A779A0_CLK_S1D4),
DEF_MOD("i2c5", 523, R8A779A0_CLK_S1D4),
DEF_MOD("i2c6", 524, R8A779A0_CLK_S1D4),
+ DEF_MOD("ispcs0", 612, R8A779A0_CLK_S1D1),
+ DEF_MOD("ispcs1", 613, R8A779A0_CLK_S1D1),
+ DEF_MOD("ispcs2", 614, R8A779A0_CLK_S1D1),
+ DEF_MOD("ispcs3", 615, R8A779A0_CLK_S1D1),
DEF_MOD("msi0", 618, R8A779A0_CLK_MSO),
DEF_MOD("msi1", 619, R8A779A0_CLK_MSO),
DEF_MOD("msi2", 620, R8A779A0_CLK_MSO),
diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c
index 71b11443f6fc..c99942f0e4d4 100644
--- a/drivers/clk/renesas/r9a06g032-clocks.c
+++ b/drivers/clk/renesas/r9a06g032-clocks.c
@@ -604,20 +604,19 @@ r9a06g032_div_clamp_div(struct r9a06g032_clk_div *clk,
return div;
}
-static long
-r9a06g032_div_round_rate(struct clk_hw *hw,
- unsigned long rate, unsigned long *prate)
+static int
+r9a06g032_div_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
{
struct r9a06g032_clk_div *clk = to_r9a06g032_div(hw);
- u32 div = DIV_ROUND_UP(*prate, rate);
+ u32 div = DIV_ROUND_UP(req->best_parent_rate, req->rate);
pr_devel("%s %pC %ld (prate %ld) (wanted div %u)\n", __func__,
- hw->clk, rate, *prate, div);
+ hw->clk, req->rate, req->best_parent_rate, div);
pr_devel(" min %d (%ld) max %d (%ld)\n",
- clk->min, DIV_ROUND_UP(*prate, clk->min),
- clk->max, DIV_ROUND_UP(*prate, clk->max));
+ clk->min, DIV_ROUND_UP(req->best_parent_rate, clk->min),
+ clk->max, DIV_ROUND_UP(req->best_parent_rate, clk->max));
- div = r9a06g032_div_clamp_div(clk, rate, *prate);
+ div = r9a06g032_div_clamp_div(clk, req->rate, req->best_parent_rate);
/*
* this is a hack. Currently the serial driver asks for a clock rate
* that is 16 times the baud rate -- and that is wildly outside the
@@ -630,11 +629,13 @@ r9a06g032_div_round_rate(struct clk_hw *hw,
if (clk->index == R9A06G032_DIV_UART ||
clk->index == R9A06G032_DIV_P2_PG) {
pr_devel("%s div uart hack!\n", __func__);
- return clk_get_rate(hw->clk);
+ req->rate = clk_get_rate(hw->clk);
+ return 0;
}
+ req->rate = DIV_ROUND_UP(req->best_parent_rate, div);
pr_devel("%s %pC %ld / %u = %ld\n", __func__, hw->clk,
- *prate, div, DIV_ROUND_UP(*prate, div));
- return DIV_ROUND_UP(*prate, div);
+ req->best_parent_rate, div, req->rate);
+ return 0;
}
static int
@@ -663,7 +664,7 @@ r9a06g032_div_set_rate(struct clk_hw *hw,
static const struct clk_ops r9a06g032_clk_div_ops = {
.recalc_rate = r9a06g032_div_recalc_rate,
- .round_rate = r9a06g032_div_round_rate,
+ .determine_rate = r9a06g032_div_determine_rate,
.set_rate = r9a06g032_div_set_rate,
};
diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c
new file mode 100644
index 000000000000..ae24e0397d3c
--- /dev/null
+++ b/drivers/clk/renesas/r9a07g044-cpg.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G2L CPG driver
+ *
+ * Copyright (C) 2021 Renesas Electronics Corp.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <dt-bindings/clock/r9a07g044-cpg.h>
+
+#include "renesas-rzg2l-cpg.h"
+
+enum clk_ids {
+ /* Core Clock Outputs exported to DT */
+ LAST_DT_CORE_CLK = R9A07G044_OSCCLK,
+
+ /* External Input Clocks */
+ CLK_EXTAL,
+
+ /* Internal Core Clocks */
+ CLK_OSC_DIV1000,
+ CLK_PLL1,
+ CLK_PLL2,
+ CLK_PLL2_DIV2,
+ CLK_PLL2_DIV16,
+ CLK_PLL2_DIV20,
+ CLK_PLL3,
+ CLK_PLL3_DIV2,
+ CLK_PLL3_DIV2_4,
+ CLK_PLL3_DIV2_4_2,
+ CLK_PLL3_DIV4,
+ CLK_PLL4,
+ CLK_PLL5,
+ CLK_PLL5_DIV2,
+ CLK_PLL6,
+
+ /* Module Clocks */
+ MOD_CLK_BASE,
+};
+
+/* Divider tables */
+static const struct clk_div_table dtable_1_32[] = {
+ {0, 1},
+ {1, 2},
+ {2, 4},
+ {3, 8},
+ {4, 32},
+ {0, 0},
+};
+
+static const struct cpg_core_clk r9a07g044_core_clks[] __initconst = {
+ /* External Clock Inputs */
+ DEF_INPUT("extal", CLK_EXTAL),
+
+ /* Internal Core Clocks */
+ DEF_FIXED(".osc", R9A07G044_OSCCLK, CLK_EXTAL, 1, 1),
+ DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000),
+ DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, PLL146_CONF(0)),
+ DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 133, 2),
+ DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 133, 2),
+
+ DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2),
+ DEF_FIXED(".pll2_div16", CLK_PLL2_DIV16, CLK_PLL2, 1, 16),
+ DEF_FIXED(".pll2_div20", CLK_PLL2_DIV20, CLK_PLL2, 1, 20),
+
+ DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 1, 2),
+ DEF_FIXED(".pll3_div2_4", CLK_PLL3_DIV2_4, CLK_PLL3_DIV2, 1, 4),
+ DEF_FIXED(".pll3_div2_4_2", CLK_PLL3_DIV2_4_2, CLK_PLL3_DIV2_4, 1, 2),
+ DEF_FIXED(".pll3_div4", CLK_PLL3_DIV4, CLK_PLL3, 1, 4),
+
+ /* Core output clk */
+ DEF_FIXED("I", R9A07G044_CLK_I, CLK_PLL1, 1, 1),
+ DEF_DIV("P0", R9A07G044_CLK_P0, CLK_PLL2_DIV16, DIVPL2A,
+ dtable_1_32, CLK_DIVIDER_HIWORD_MASK),
+ DEF_FIXED("TSU", R9A07G044_CLK_TSU, CLK_PLL2_DIV20, 1, 1),
+ DEF_DIV("P1", R9A07G044_CLK_P1, CLK_PLL3_DIV2_4,
+ DIVPL3B, dtable_1_32, CLK_DIVIDER_HIWORD_MASK),
+ DEF_DIV("P2", R9A07G044_CLK_P2, CLK_PLL3_DIV2_4_2,
+ DIVPL3A, dtable_1_32, CLK_DIVIDER_HIWORD_MASK),
+};
+
+static struct rzg2l_mod_clk r9a07g044_mod_clks[] = {
+ DEF_MOD("gic", R9A07G044_GIC600_GICCLK, R9A07G044_CLK_P1,
+ 0x514, 0),
+ DEF_MOD("ia55_pclk", R9A07G044_IA55_PCLK, R9A07G044_CLK_P2,
+ 0x518, 0),
+ DEF_MOD("ia55_clk", R9A07G044_IA55_CLK, R9A07G044_CLK_P1,
+ 0x518, 1),
+ DEF_MOD("scif0", R9A07G044_SCIF0_CLK_PCK, R9A07G044_CLK_P0,
+ 0x584, 0),
+ DEF_MOD("scif1", R9A07G044_SCIF1_CLK_PCK, R9A07G044_CLK_P0,
+ 0x584, 1),
+ DEF_MOD("scif2", R9A07G044_SCIF2_CLK_PCK, R9A07G044_CLK_P0,
+ 0x584, 2),
+ DEF_MOD("scif3", R9A07G044_SCIF3_CLK_PCK, R9A07G044_CLK_P0,
+ 0x584, 3),
+ DEF_MOD("scif4", R9A07G044_SCIF4_CLK_PCK, R9A07G044_CLK_P0,
+ 0x584, 4),
+ DEF_MOD("sci0", R9A07G044_SCI0_CLKP, R9A07G044_CLK_P0,
+ 0x588, 0),
+};
+
+static struct rzg2l_reset r9a07g044_resets[] = {
+ DEF_RST(R9A07G044_GIC600_GICRESET_N, 0x814, 0),
+ DEF_RST(R9A07G044_GIC600_DBG_GICRESET_N, 0x814, 1),
+ DEF_RST(R9A07G044_IA55_RESETN, 0x818, 0),
+ DEF_RST(R9A07G044_SCIF0_RST_SYSTEM_N, 0x884, 0),
+ DEF_RST(R9A07G044_SCIF1_RST_SYSTEM_N, 0x884, 1),
+ DEF_RST(R9A07G044_SCIF2_RST_SYSTEM_N, 0x884, 2),
+ DEF_RST(R9A07G044_SCIF3_RST_SYSTEM_N, 0x884, 3),
+ DEF_RST(R9A07G044_SCIF4_RST_SYSTEM_N, 0x884, 4),
+ DEF_RST(R9A07G044_SCI0_RST, 0x888, 0),
+};
+
+static const unsigned int r9a07g044_crit_mod_clks[] __initconst = {
+ MOD_CLK_BASE + R9A07G044_GIC600_GICCLK,
+};
+
+const struct rzg2l_cpg_info r9a07g044_cpg_info = {
+ /* Core Clocks */
+ .core_clks = r9a07g044_core_clks,
+ .num_core_clks = ARRAY_SIZE(r9a07g044_core_clks),
+ .last_dt_core_clk = LAST_DT_CORE_CLK,
+ .num_total_core_clks = MOD_CLK_BASE,
+
+ /* Critical Module Clocks */
+ .crit_mod_clks = r9a07g044_crit_mod_clks,
+ .num_crit_mod_clks = ARRAY_SIZE(r9a07g044_crit_mod_clks),
+
+ /* Module Clocks */
+ .mod_clks = r9a07g044_mod_clks,
+ .num_mod_clks = ARRAY_SIZE(r9a07g044_mod_clks),
+ .num_hw_mod_clks = R9A07G044_TSU_PCLK + 1,
+
+ /* Resets */
+ .resets = r9a07g044_resets,
+ .num_resets = ARRAY_SIZE(r9a07g044_resets),
+};
diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c
index caa0f9414e45..558191c99b48 100644
--- a/drivers/clk/renesas/rcar-gen3-cpg.c
+++ b/drivers/clk/renesas/rcar-gen3-cpg.c
@@ -26,19 +26,135 @@
#include "rcar-cpg-lib.h"
#include "rcar-gen3-cpg.h"
-#define CPG_PLL0CR 0x00d8
+#define CPG_PLLECR 0x00d0 /* PLL Enable Control Register */
+
+#define CPG_PLLECR_PLLST(n) BIT(8 + (n)) /* PLLn Circuit Status */
+
+#define CPG_PLL0CR 0x00d8 /* PLLn Control Registers */
#define CPG_PLL2CR 0x002c
#define CPG_PLL4CR 0x01f4
+#define CPG_PLLnCR_STC_MASK GENMASK(30, 24) /* PLL Circuit Mult. Ratio */
+
#define CPG_RCKCR_CKSEL BIT(15) /* RCLK Clock Source Select */
+/* PLL Clocks */
+struct cpg_pll_clk {
+ struct clk_hw hw;
+ void __iomem *pllcr_reg;
+ void __iomem *pllecr_reg;
+ unsigned int fixed_mult;
+ u32 pllecr_pllst_mask;
+};
+
+#define to_pll_clk(_hw) container_of(_hw, struct cpg_pll_clk, hw)
+
+static unsigned long cpg_pll_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct cpg_pll_clk *pll_clk = to_pll_clk(hw);
+ unsigned int mult;
+ u32 val;
+
+ val = readl(pll_clk->pllcr_reg) & CPG_PLLnCR_STC_MASK;
+ mult = (val >> __ffs(CPG_PLLnCR_STC_MASK)) + 1;
+
+ return parent_rate * mult * pll_clk->fixed_mult;
+}
+
+static int cpg_pll_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct cpg_pll_clk *pll_clk = to_pll_clk(hw);
+ unsigned int min_mult, max_mult, mult;
+ unsigned long prate;
+
+ prate = req->best_parent_rate * pll_clk->fixed_mult;
+ min_mult = max(div64_ul(req->min_rate, prate), 1ULL);
+ max_mult = min(div64_ul(req->max_rate, prate), 128ULL);
+ if (max_mult < min_mult)
+ return -EINVAL;
+
+ mult = DIV_ROUND_CLOSEST_ULL(req->rate, prate);
+ mult = clamp(mult, min_mult, max_mult);
+
+ req->rate = prate * mult;
+ return 0;
+}
+
+static int cpg_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct cpg_pll_clk *pll_clk = to_pll_clk(hw);
+ unsigned int mult, i;
+ u32 val;
+
+ mult = DIV_ROUND_CLOSEST_ULL(rate, parent_rate * pll_clk->fixed_mult);
+ mult = clamp(mult, 1U, 128U);
+
+ val = readl(pll_clk->pllcr_reg);
+ val &= ~CPG_PLLnCR_STC_MASK;
+ val |= (mult - 1) << __ffs(CPG_PLLnCR_STC_MASK);
+ writel(val, pll_clk->pllcr_reg);
+
+ for (i = 1000; i; i--) {
+ if (readl(pll_clk->pllecr_reg) & pll_clk->pllecr_pllst_mask)
+ return 0;
+
+ cpu_relax();
+ }
+
+ return -ETIMEDOUT;
+}
+
+static const struct clk_ops cpg_pll_clk_ops = {
+ .recalc_rate = cpg_pll_clk_recalc_rate,
+ .determine_rate = cpg_pll_clk_determine_rate,
+ .set_rate = cpg_pll_clk_set_rate,
+};
+
+static struct clk * __init cpg_pll_clk_register(const char *name,
+ const char *parent_name,
+ void __iomem *base,
+ unsigned int mult,
+ unsigned int offset,
+ unsigned int index)
+
+{
+ struct cpg_pll_clk *pll_clk;
+ struct clk_init_data init = {};
+ struct clk *clk;
+
+ pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
+ if (!pll_clk)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &cpg_pll_clk_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ pll_clk->hw.init = &init;
+ pll_clk->pllcr_reg = base + offset;
+ pll_clk->pllecr_reg = base + CPG_PLLECR;
+ pll_clk->fixed_mult = mult; /* PLL refclk x (setting + 1) x mult */
+ pll_clk->pllecr_pllst_mask = CPG_PLLECR_PLLST(index);
+
+ clk = clk_register(NULL, &pll_clk->hw);
+ if (IS_ERR(clk))
+ kfree(pll_clk);
+
+ return clk;
+}
+
/*
* Z Clock & Z2 Clock
*
* Traits of this clock:
* prepare - clk_prepare only ensures that parents are prepared
* enable - clk_enable only ensures that parents are enabled
- * rate - rate is adjustable. clk->rate = (parent->rate * mult / 32 ) / 2
+ * rate - rate is adjustable.
+ * clk->rate = (parent->rate * mult / 32 ) / fixed_div
* parent - fixed parent. No clk_set_parent support
*/
#define CPG_FRQCRB 0x00000004
@@ -49,8 +165,9 @@ struct cpg_z_clk {
struct clk_hw hw;
void __iomem *reg;
void __iomem *kick_reg;
- unsigned long mask;
+ unsigned long max_rate; /* Maximum rate for normal mode */
unsigned int fixed_div;
+ u32 mask;
};
#define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw)
@@ -74,7 +191,18 @@ static int cpg_z_clk_determine_rate(struct clk_hw *hw,
{
struct cpg_z_clk *zclk = to_z_clk(hw);
unsigned int min_mult, max_mult, mult;
- unsigned long prate;
+ unsigned long rate, prate;
+
+ rate = min(req->rate, req->max_rate);
+ if (rate <= zclk->max_rate) {
+ /* Set parent rate to initial value for normal modes */
+ prate = zclk->max_rate;
+ } else {
+ /* Set increased parent rate for boost modes */
+ prate = rate;
+ }
+ req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
+ prate * zclk->fixed_div);
prate = req->best_parent_rate / zclk->fixed_div;
min_mult = max(div64_ul(req->min_rate * 32ULL, prate), 1ULL);
@@ -82,10 +210,10 @@ static int cpg_z_clk_determine_rate(struct clk_hw *hw,
if (max_mult < min_mult)
return -EINVAL;
- mult = div64_ul(req->rate * 32ULL, prate);
+ mult = DIV_ROUND_CLOSEST_ULL(rate * 32ULL, prate);
mult = clamp(mult, min_mult, max_mult);
- req->rate = div_u64((u64)prate * mult, 32);
+ req->rate = DIV_ROUND_CLOSEST_ULL((u64)prate * mult, 32);
return 0;
}
@@ -103,8 +231,7 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
return -EBUSY;
- cpg_reg_modify(zclk->reg, zclk->mask,
- ((32 - mult) << __ffs(zclk->mask)) & zclk->mask);
+ cpg_reg_modify(zclk->reg, zclk->mask, (32 - mult) << __ffs(zclk->mask));
/*
* Set KICK bit in FRQCRB to update hardware setting and wait for
@@ -117,7 +244,7 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
*
* Using experimental measurements, it seems that no more than
* ~10 iterations are needed, independently of the CPU rate.
- * Since this value might be dependent of external xtal rate, pll1
+ * Since this value might be dependent on external xtal rate, pll1
* rate or even the other emulation clocks rate, use 1000 as a
* "super" safe value.
*/
@@ -153,7 +280,7 @@ static struct clk * __init cpg_z_clk_register(const char *name,
init.name = name;
init.ops = &cpg_z_clk_ops;
- init.flags = 0;
+ init.flags = CLK_SET_RATE_PARENT;
init.parent_names = &parent_name;
init.num_parents = 1;
@@ -164,9 +291,13 @@ static struct clk * __init cpg_z_clk_register(const char *name,
zclk->fixed_div = div; /* PLLVCO x 1/div x SYS-CPU divider */
clk = clk_register(NULL, &zclk->hw);
- if (IS_ERR(clk))
+ if (IS_ERR(clk)) {
kfree(zclk);
+ return clk;
+ }
+ zclk->max_rate = clk_hw_get_rate(clk_hw_get_parent(&zclk->hw)) /
+ zclk->fixed_div;
return clk;
}
@@ -314,16 +445,13 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
case CLK_TYPE_GEN3_PLL0:
/*
- * PLL0 is a configurable multiplier clock. Register it as a
- * fixed factor clock for now as there's no generic multiplier
- * clock implementation and we currently have no need to change
- * the multiplier value.
+ * PLL0 is implemented as a custom clock, to change the
+ * multiplier when cpufreq changes between normal and boost
+ * modes.
*/
- value = readl(base + CPG_PLL0CR);
- mult = (((value >> 24) & 0x7f) + 1) * 2;
- if (cpg_quirks & PLL_ERRATA)
- mult *= 2;
- break;
+ mult = (cpg_quirks & PLL_ERRATA) ? 4 : 2;
+ return cpg_pll_clk_register(core->name, __clk_get_name(parent),
+ base, mult, CPG_PLL0CR, 0);
case CLK_TYPE_GEN3_PLL1:
mult = cpg_pll_config->pll1_mult;
@@ -332,16 +460,13 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
case CLK_TYPE_GEN3_PLL2:
/*
- * PLL2 is a configurable multiplier clock. Register it as a
- * fixed factor clock for now as there's no generic multiplier
- * clock implementation and we currently have no need to change
- * the multiplier value.
+ * PLL2 is implemented as a custom clock, to change the
+ * multiplier when cpufreq changes between normal and boost
+ * modes.
*/
- value = readl(base + CPG_PLL2CR);
- mult = (((value >> 24) & 0x7f) + 1) * 2;
- if (cpg_quirks & PLL_ERRATA)
- mult *= 2;
- break;
+ mult = (cpg_quirks & PLL_ERRATA) ? 4 : 2;
+ return cpg_pll_clk_register(core->name, __clk_get_name(parent),
+ base, mult, CPG_PLL2CR, 2);
case CLK_TYPE_GEN3_PLL3:
mult = cpg_pll_config->pll3_mult;
diff --git a/drivers/clk/renesas/rcar-usb2-clock-sel.c b/drivers/clk/renesas/rcar-usb2-clock-sel.c
index 34a85dc95beb..9fb79bd79435 100644
--- a/drivers/clk/renesas/rcar-usb2-clock-sel.c
+++ b/drivers/clk/renesas/rcar-usb2-clock-sel.c
@@ -128,10 +128,8 @@ static int rcar_usb2_clock_sel_resume(struct device *dev)
static int rcar_usb2_clock_sel_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct usb2_clock_sel_priv *priv = platform_get_drvdata(pdev);
of_clk_del_provider(dev->of_node);
- clk_hw_unregister(&priv->hw);
pm_runtime_put(dev);
pm_runtime_disable(dev);
@@ -164,9 +162,6 @@ static int rcar_usb2_clock_sel_probe(struct platform_device *pdev)
if (IS_ERR(priv->rsts))
return PTR_ERR(priv->rsts);
- pm_runtime_enable(dev);
- pm_runtime_get_sync(dev);
-
clk = devm_clk_get(dev, "usb_extal");
if (!IS_ERR(clk) && !clk_prepare_enable(clk)) {
priv->extal = !!clk_get_rate(clk);
@@ -183,6 +178,8 @@ static int rcar_usb2_clock_sel_probe(struct platform_device *pdev)
return -ENOENT;
}
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
platform_set_drvdata(pdev, priv);
dev_set_drvdata(dev, priv);
@@ -190,11 +187,20 @@ static int rcar_usb2_clock_sel_probe(struct platform_device *pdev)
init.ops = &usb2_clock_sel_clock_ops;
priv->hw.init = &init;
- clk = clk_register(NULL, &priv->hw);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = devm_clk_hw_register(NULL, &priv->hw);
+ if (ret)
+ goto pm_put;
+
+ ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &priv->hw);
+ if (ret)
+ goto pm_put;
+
+ return 0;
- return of_clk_add_hw_provider(np, of_clk_hw_simple_get, &priv->hw);
+pm_put:
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+ return ret;
}
static const struct dev_pm_ops rcar_usb2_clock_sel_pm_ops = {
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c
index fc531d35b269..21f762aa2131 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.c
+++ b/drivers/clk/renesas/renesas-cpg-mssr.c
@@ -100,13 +100,9 @@ static const u16 srcr_for_v3u[] = {
0x2C20, 0x2C24, 0x2C28, 0x2C2C, 0x2C30, 0x2C34, 0x2C38,
};
-/* Realtime Module Stop Control Register offsets */
-#define RMSTPCR(i) (smstpcr[i] - 0x20)
-
-/* Modem Module Stop Control Register offsets (r8a73a4) */
-#define MMSTPCR(i) (smstpcr[i] + 0x20)
-
-/* Software Reset Clearing Register offsets */
+/*
+ * Software Reset Clearing Register offsets
+ */
static const u16 srstclr[] = {
0x940, 0x944, 0x948, 0x94C, 0x950, 0x954, 0x958, 0x95C,
diff --git a/drivers/clk/renesas/renesas-rzg2l-cpg.c b/drivers/clk/renesas/renesas-rzg2l-cpg.c
new file mode 100644
index 000000000000..e7c59af2a1d8
--- /dev/null
+++ b/drivers/clk/renesas/renesas-rzg2l-cpg.c
@@ -0,0 +1,758 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G2L Clock Pulse Generator
+ *
+ * Copyright (C) 2021 Renesas Electronics Corp.
+ *
+ * Based on renesas-cpg-mssr.c
+ *
+ * Copyright (C) 2015 Glider bvba
+ * Copyright (C) 2013 Ideas On Board SPRL
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/renesas.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_domain.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+#include "renesas-rzg2l-cpg.h"
+
+#ifdef DEBUG
+#define WARN_DEBUG(x) WARN_ON(x)
+#else
+#define WARN_DEBUG(x) do { } while (0)
+#endif
+
+#define DIV_RSMASK(v, s, m) ((v >> s) & m)
+#define GET_SHIFT(val) ((val >> 12) & 0xff)
+#define GET_WIDTH(val) ((val >> 8) & 0xf)
+
+#define KDIV(val) DIV_RSMASK(val, 16, 0xffff)
+#define MDIV(val) DIV_RSMASK(val, 6, 0x3ff)
+#define PDIV(val) DIV_RSMASK(val, 0, 0x3f)
+#define SDIV(val) DIV_RSMASK(val, 0, 0x7)
+
+#define CLK_ON_R(reg) (reg)
+#define CLK_MON_R(reg) (0x180 + (reg))
+#define CLK_RST_R(reg) (reg)
+#define CLK_MRST_R(reg) (0x180 + (reg))
+
+#define GET_REG_OFFSET(val) ((val >> 20) & 0xfff)
+#define GET_REG_SAMPLL_CLK1(val) ((val >> 22) & 0xfff)
+#define GET_REG_SAMPLL_CLK2(val) ((val >> 12) & 0xfff)
+
+/**
+ * struct rzg2l_cpg_priv - Clock Pulse Generator Private Data
+ *
+ * @rcdev: Reset controller entity
+ * @dev: CPG device
+ * @base: CPG register block base address
+ * @rmw_lock: protects register accesses
+ * @clks: Array containing all Core and Module Clocks
+ * @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
+ * @notifiers: Notifier chain to save/restore clock state for system resume
+ * @info: Pointer to platform data
+ */
+struct rzg2l_cpg_priv {
+ struct reset_controller_dev rcdev;
+ struct device *dev;
+ void __iomem *base;
+ spinlock_t rmw_lock;
+
+ struct clk **clks;
+ unsigned int num_core_clks;
+ unsigned int num_mod_clks;
+ unsigned int num_resets;
+ unsigned int last_dt_core_clk;
+
+ struct raw_notifier_head notifiers;
+ const struct rzg2l_cpg_info *info;
+};
+
+static void rzg2l_cpg_del_clk_provider(void *data)
+{
+ of_clk_del_provider(data);
+}
+
+static struct clk * __init
+rzg2l_cpg_div_clk_register(const struct cpg_core_clk *core,
+ struct clk **clks,
+ void __iomem *base,
+ struct rzg2l_cpg_priv *priv)
+{
+ struct device *dev = priv->dev;
+ const struct clk *parent;
+ const char *parent_name;
+ struct clk_hw *clk_hw;
+
+ parent = clks[core->parent & 0xffff];
+ if (IS_ERR(parent))
+ return ERR_CAST(parent);
+
+ parent_name = __clk_get_name(parent);
+
+ if (core->dtable)
+ clk_hw = clk_hw_register_divider_table(dev, core->name,
+ parent_name, 0,
+ base + GET_REG_OFFSET(core->conf),
+ GET_SHIFT(core->conf),
+ GET_WIDTH(core->conf),
+ core->flag,
+ core->dtable,
+ &priv->rmw_lock);
+ else
+ clk_hw = clk_hw_register_divider(dev, core->name,
+ parent_name, 0,
+ base + GET_REG_OFFSET(core->conf),
+ GET_SHIFT(core->conf),
+ GET_WIDTH(core->conf),
+ core->flag, &priv->rmw_lock);
+
+ if (IS_ERR(clk_hw))
+ return NULL;
+
+ return clk_hw->clk;
+}
+
+struct pll_clk {
+ struct clk_hw hw;
+ unsigned int conf;
+ unsigned int type;
+ void __iomem *base;
+ struct rzg2l_cpg_priv *priv;
+};
+
+#define to_pll(_hw) container_of(_hw, struct pll_clk, hw)
+
+static unsigned long rzg2l_cpg_pll_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct pll_clk *pll_clk = to_pll(hw);
+ struct rzg2l_cpg_priv *priv = pll_clk->priv;
+ unsigned int val1, val2;
+ unsigned int mult = 1;
+ unsigned int div = 1;
+
+ if (pll_clk->type != CLK_TYPE_SAM_PLL)
+ return parent_rate;
+
+ val1 = readl(priv->base + GET_REG_SAMPLL_CLK1(pll_clk->conf));
+ val2 = readl(priv->base + GET_REG_SAMPLL_CLK2(pll_clk->conf));
+ mult = MDIV(val1) + KDIV(val1) / 65536;
+ div = PDIV(val1) * (1 << SDIV(val2));
+
+ return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, div);
+}
+
+static const struct clk_ops rzg2l_cpg_pll_ops = {
+ .recalc_rate = rzg2l_cpg_pll_clk_recalc_rate,
+};
+
+static struct clk * __init
+rzg2l_cpg_pll_clk_register(const struct cpg_core_clk *core,
+ struct clk **clks,
+ void __iomem *base,
+ struct rzg2l_cpg_priv *priv)
+{
+ struct device *dev = priv->dev;
+ const struct clk *parent;
+ struct clk_init_data init;
+ const char *parent_name;
+ struct pll_clk *pll_clk;
+ struct clk *clk;
+
+ parent = clks[core->parent & 0xffff];
+ if (IS_ERR(parent))
+ return ERR_CAST(parent);
+
+ pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
+ if (!pll_clk) {
+ clk = ERR_PTR(-ENOMEM);
+ return NULL;
+ }
+
+ parent_name = __clk_get_name(parent);
+ init.name = core->name;
+ init.ops = &rzg2l_cpg_pll_ops;
+ init.flags = 0;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ pll_clk->hw.init = &init;
+ pll_clk->conf = core->conf;
+ pll_clk->base = base;
+ pll_clk->priv = priv;
+ pll_clk->type = core->type;
+
+ clk = clk_register(NULL, &pll_clk->hw);
+ if (IS_ERR(clk))
+ kfree(pll_clk);
+
+ return clk;
+}
+
+static struct clk
+*rzg2l_cpg_clk_src_twocell_get(struct of_phandle_args *clkspec,
+ void *data)
+{
+ unsigned int clkidx = clkspec->args[1];
+ struct rzg2l_cpg_priv *priv = data;
+ struct device *dev = priv->dev;
+ const char *type;
+ struct clk *clk;
+
+ switch (clkspec->args[0]) {
+ case CPG_CORE:
+ type = "core";
+ if (clkidx > priv->last_dt_core_clk) {
+ dev_err(dev, "Invalid %s clock index %u\n", type, clkidx);
+ return ERR_PTR(-EINVAL);
+ }
+ clk = priv->clks[clkidx];
+ break;
+
+ case CPG_MOD:
+ type = "module";
+ if (clkidx > priv->num_mod_clks) {
+ dev_err(dev, "Invalid %s clock index %u\n", type,
+ clkidx);
+ return ERR_PTR(-EINVAL);
+ }
+ clk = priv->clks[priv->num_core_clks + clkidx];
+ break;
+
+ default:
+ dev_err(dev, "Invalid CPG clock type %u\n", clkspec->args[0]);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (IS_ERR(clk))
+ dev_err(dev, "Cannot get %s clock %u: %ld", type, clkidx,
+ PTR_ERR(clk));
+ else
+ dev_dbg(dev, "clock (%u, %u) is %pC at %lu Hz\n",
+ clkspec->args[0], clkspec->args[1], clk,
+ clk_get_rate(clk));
+ return clk;
+}
+
+static void __init
+rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core,
+ const struct rzg2l_cpg_info *info,
+ struct rzg2l_cpg_priv *priv)
+{
+ struct clk *clk = ERR_PTR(-EOPNOTSUPP), *parent;
+ struct device *dev = priv->dev;
+ unsigned int id = core->id, div = core->div;
+ const char *parent_name;
+
+ WARN_DEBUG(id >= priv->num_core_clks);
+ WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
+
+ if (!core->name) {
+ /* Skip NULLified clock */
+ return;
+ }
+
+ switch (core->type) {
+ case CLK_TYPE_IN:
+ clk = of_clk_get_by_name(priv->dev->of_node, core->name);
+ break;
+ case CLK_TYPE_FF:
+ WARN_DEBUG(core->parent >= priv->num_core_clks);
+ parent = priv->clks[core->parent];
+ if (IS_ERR(parent)) {
+ clk = parent;
+ goto fail;
+ }
+
+ parent_name = __clk_get_name(parent);
+ clk = clk_register_fixed_factor(NULL, core->name,
+ parent_name, CLK_SET_RATE_PARENT,
+ core->mult, div);
+ break;
+ case CLK_TYPE_SAM_PLL:
+ clk = rzg2l_cpg_pll_clk_register(core, priv->clks,
+ priv->base, priv);
+ break;
+ case CLK_TYPE_DIV:
+ clk = rzg2l_cpg_div_clk_register(core, priv->clks,
+ priv->base, priv);
+ break;
+ default:
+ goto fail;
+ };
+
+ if (IS_ERR_OR_NULL(clk))
+ goto fail;
+
+ dev_dbg(dev, "Core clock %pC at %lu Hz\n", clk, clk_get_rate(clk));
+ priv->clks[id] = clk;
+ return;
+
+fail:
+ dev_err(dev, "Failed to register %s clock %s: %ld\n", "core",
+ core->name, PTR_ERR(clk));
+}
+
+/**
+ * struct mstp_clock - MSTP gating clock
+ *
+ * @hw: handle between common and hardware-specific interfaces
+ * @off: register offset
+ * @bit: ON/MON bit
+ * @priv: CPG/MSTP private data
+ */
+struct mstp_clock {
+ struct clk_hw hw;
+ u16 off;
+ u8 bit;
+ struct rzg2l_cpg_priv *priv;
+};
+
+#define to_mod_clock(_hw) container_of(_hw, struct mstp_clock, hw)
+
+static int rzg2l_mod_clock_endisable(struct clk_hw *hw, bool enable)
+{
+ struct mstp_clock *clock = to_mod_clock(hw);
+ struct rzg2l_cpg_priv *priv = clock->priv;
+ unsigned int reg = clock->off;
+ struct device *dev = priv->dev;
+ unsigned long flags;
+ unsigned int i;
+ u32 bitmask = BIT(clock->bit);
+ u32 value;
+
+ if (!clock->off) {
+ dev_dbg(dev, "%pC does not support ON/OFF\n", hw->clk);
+ return 0;
+ }
+
+ dev_dbg(dev, "CLK_ON %u/%pC %s\n", CLK_ON_R(reg), hw->clk,
+ enable ? "ON" : "OFF");
+ spin_lock_irqsave(&priv->rmw_lock, flags);
+
+ if (enable)
+ value = (bitmask << 16) | bitmask;
+ else
+ value = bitmask << 16;
+ writel(value, priv->base + CLK_ON_R(reg));
+
+ spin_unlock_irqrestore(&priv->rmw_lock, flags);
+
+ if (!enable)
+ return 0;
+
+ for (i = 1000; i > 0; --i) {
+ if (((readl(priv->base + CLK_MON_R(reg))) & bitmask))
+ break;
+ cpu_relax();
+ }
+
+ if (!i) {
+ dev_err(dev, "Failed to enable CLK_ON %p\n",
+ priv->base + CLK_ON_R(reg));
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int rzg2l_mod_clock_enable(struct clk_hw *hw)
+{
+ return rzg2l_mod_clock_endisable(hw, true);
+}
+
+static void rzg2l_mod_clock_disable(struct clk_hw *hw)
+{
+ rzg2l_mod_clock_endisable(hw, false);
+}
+
+static int rzg2l_mod_clock_is_enabled(struct clk_hw *hw)
+{
+ struct mstp_clock *clock = to_mod_clock(hw);
+ struct rzg2l_cpg_priv *priv = clock->priv;
+ u32 bitmask = BIT(clock->bit);
+ u32 value;
+
+ if (!clock->off) {
+ dev_dbg(priv->dev, "%pC does not support ON/OFF\n", hw->clk);
+ return 1;
+ }
+
+ value = readl(priv->base + CLK_MON_R(clock->off));
+
+ return !(value & bitmask);
+}
+
+static const struct clk_ops rzg2l_mod_clock_ops = {
+ .enable = rzg2l_mod_clock_enable,
+ .disable = rzg2l_mod_clock_disable,
+ .is_enabled = rzg2l_mod_clock_is_enabled,
+};
+
+static void __init
+rzg2l_cpg_register_mod_clk(const struct rzg2l_mod_clk *mod,
+ const struct rzg2l_cpg_info *info,
+ struct rzg2l_cpg_priv *priv)
+{
+ struct mstp_clock *clock = NULL;
+ struct device *dev = priv->dev;
+ unsigned int id = mod->id;
+ struct clk_init_data init;
+ struct clk *parent, *clk;
+ const char *parent_name;
+ unsigned int i;
+
+ WARN_DEBUG(id < priv->num_core_clks);
+ WARN_DEBUG(id >= priv->num_core_clks + priv->num_mod_clks);
+ WARN_DEBUG(mod->parent >= priv->num_core_clks + priv->num_mod_clks);
+ WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
+
+ if (!mod->name) {
+ /* Skip NULLified clock */
+ return;
+ }
+
+ parent = priv->clks[mod->parent];
+ if (IS_ERR(parent)) {
+ clk = parent;
+ goto fail;
+ }
+
+ clock = devm_kzalloc(dev, sizeof(*clock), GFP_KERNEL);
+ if (!clock) {
+ clk = ERR_PTR(-ENOMEM);
+ goto fail;
+ }
+
+ init.name = mod->name;
+ init.ops = &rzg2l_mod_clock_ops;
+ init.flags = CLK_SET_RATE_PARENT;
+ for (i = 0; i < info->num_crit_mod_clks; i++)
+ if (id == info->crit_mod_clks[i]) {
+ dev_dbg(dev, "CPG %s setting CLK_IS_CRITICAL\n",
+ mod->name);
+ init.flags |= CLK_IS_CRITICAL;
+ break;
+ }
+
+ parent_name = __clk_get_name(parent);
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ clock->off = mod->off;
+ clock->bit = mod->bit;
+ clock->priv = priv;
+ clock->hw.init = &init;
+
+ clk = clk_register(NULL, &clock->hw);
+ if (IS_ERR(clk))
+ goto fail;
+
+ dev_dbg(dev, "Module clock %pC at %lu Hz\n", clk, clk_get_rate(clk));
+ priv->clks[id] = clk;
+ return;
+
+fail:
+ dev_err(dev, "Failed to register %s clock %s: %ld\n", "module",
+ mod->name, PTR_ERR(clk));
+ kfree(clock);
+}
+
+#define rcdev_to_priv(x) container_of(x, struct rzg2l_cpg_priv, rcdev)
+
+static int rzg2l_cpg_reset(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev);
+ const struct rzg2l_cpg_info *info = priv->info;
+ unsigned int reg = info->resets[id].off;
+ u32 dis = BIT(info->resets[id].bit);
+ u32 we = dis << 16;
+
+ dev_dbg(rcdev->dev, "reset id:%ld offset:0x%x\n", id, CLK_RST_R(reg));
+
+ /* Reset module */
+ writel(we, priv->base + CLK_RST_R(reg));
+
+ /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */
+ udelay(35);
+
+ /* Release module from reset state */
+ writel(we | dis, priv->base + CLK_RST_R(reg));
+
+ return 0;
+}
+
+static int rzg2l_cpg_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev);
+ const struct rzg2l_cpg_info *info = priv->info;
+ unsigned int reg = info->resets[id].off;
+ u32 value = BIT(info->resets[id].bit) << 16;
+
+ dev_dbg(rcdev->dev, "assert id:%ld offset:0x%x\n", id, CLK_RST_R(reg));
+
+ writel(value, priv->base + CLK_RST_R(reg));
+ return 0;
+}
+
+static int rzg2l_cpg_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev);
+ const struct rzg2l_cpg_info *info = priv->info;
+ unsigned int reg = info->resets[id].off;
+ u32 dis = BIT(info->resets[id].bit);
+ u32 value = (dis << 16) | dis;
+
+ dev_dbg(rcdev->dev, "deassert id:%ld offset:0x%x\n", id,
+ CLK_RST_R(reg));
+
+ writel(value, priv->base + CLK_RST_R(reg));
+ return 0;
+}
+
+static int rzg2l_cpg_status(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev);
+ const struct rzg2l_cpg_info *info = priv->info;
+ unsigned int reg = info->resets[id].off;
+ u32 bitmask = BIT(info->resets[id].bit);
+
+ return !(readl(priv->base + CLK_MRST_R(reg)) & bitmask);
+}
+
+static const struct reset_control_ops rzg2l_cpg_reset_ops = {
+ .reset = rzg2l_cpg_reset,
+ .assert = rzg2l_cpg_assert,
+ .deassert = rzg2l_cpg_deassert,
+ .status = rzg2l_cpg_status,
+};
+
+static int rzg2l_cpg_reset_xlate(struct reset_controller_dev *rcdev,
+ const struct of_phandle_args *reset_spec)
+{
+ struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev);
+ const struct rzg2l_cpg_info *info = priv->info;
+ unsigned int id = reset_spec->args[0];
+
+ if (id >= rcdev->nr_resets || !info->resets[id].off) {
+ dev_err(rcdev->dev, "Invalid reset index %u\n", id);
+ return -EINVAL;
+ }
+
+ return id;
+}
+
+static int rzg2l_cpg_reset_controller_register(struct rzg2l_cpg_priv *priv)
+{
+ priv->rcdev.ops = &rzg2l_cpg_reset_ops;
+ priv->rcdev.of_node = priv->dev->of_node;
+ priv->rcdev.dev = priv->dev;
+ priv->rcdev.of_reset_n_cells = 1;
+ priv->rcdev.of_xlate = rzg2l_cpg_reset_xlate;
+ priv->rcdev.nr_resets = priv->num_resets;
+
+ return devm_reset_controller_register(priv->dev, &priv->rcdev);
+}
+
+static bool rzg2l_cpg_is_pm_clk(const struct of_phandle_args *clkspec)
+{
+ if (clkspec->args_count != 2)
+ return false;
+
+ switch (clkspec->args[0]) {
+ case CPG_MOD:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static int rzg2l_cpg_attach_dev(struct generic_pm_domain *unused, struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct of_phandle_args clkspec;
+ bool once = true;
+ struct clk *clk;
+ int error;
+ int i = 0;
+
+ while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
+ &clkspec)) {
+ if (rzg2l_cpg_is_pm_clk(&clkspec)) {
+ if (once) {
+ once = false;
+ error = pm_clk_create(dev);
+ if (error) {
+ of_node_put(clkspec.np);
+ goto err;
+ }
+ }
+ clk = of_clk_get_from_provider(&clkspec);
+ of_node_put(clkspec.np);
+ if (IS_ERR(clk)) {
+ error = PTR_ERR(clk);
+ goto fail_destroy;
+ }
+
+ error = pm_clk_add_clk(dev, clk);
+ if (error) {
+ dev_err(dev, "pm_clk_add_clk failed %d\n",
+ error);
+ goto fail_put;
+ }
+ } else {
+ of_node_put(clkspec.np);
+ }
+ i++;
+ }
+
+ return 0;
+
+fail_put:
+ clk_put(clk);
+
+fail_destroy:
+ pm_clk_destroy(dev);
+err:
+ return error;
+}
+
+static void rzg2l_cpg_detach_dev(struct generic_pm_domain *unused, struct device *dev)
+{
+ if (!pm_clk_no_clocks(dev))
+ pm_clk_destroy(dev);
+}
+
+static int __init rzg2l_cpg_add_clk_domain(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct generic_pm_domain *genpd;
+
+ genpd = devm_kzalloc(dev, sizeof(*genpd), GFP_KERNEL);
+ if (!genpd)
+ return -ENOMEM;
+
+ genpd->name = np->name;
+ genpd->flags = GENPD_FLAG_PM_CLK | GENPD_FLAG_ALWAYS_ON |
+ GENPD_FLAG_ACTIVE_WAKEUP;
+ genpd->attach_dev = rzg2l_cpg_attach_dev;
+ genpd->detach_dev = rzg2l_cpg_detach_dev;
+ pm_genpd_init(genpd, &pm_domain_always_on_gov, false);
+
+ of_genpd_add_provider_simple(np, genpd);
+ return 0;
+}
+
+static int __init rzg2l_cpg_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ const struct rzg2l_cpg_info *info;
+ struct rzg2l_cpg_priv *priv;
+ unsigned int nclks, i;
+ struct clk **clks;
+ int error;
+
+ info = of_device_get_match_data(dev);
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->info = info;
+ spin_lock_init(&priv->rmw_lock);
+
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ nclks = info->num_total_core_clks + info->num_hw_mod_clks;
+ clks = devm_kmalloc_array(dev, nclks, sizeof(*clks), GFP_KERNEL);
+ if (!clks)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->clks = clks;
+ priv->num_core_clks = info->num_total_core_clks;
+ priv->num_mod_clks = info->num_hw_mod_clks;
+ priv->num_resets = info->num_resets;
+ priv->last_dt_core_clk = info->last_dt_core_clk;
+
+ for (i = 0; i < nclks; i++)
+ clks[i] = ERR_PTR(-ENOENT);
+
+ for (i = 0; i < info->num_core_clks; i++)
+ rzg2l_cpg_register_core_clk(&info->core_clks[i], info, priv);
+
+ for (i = 0; i < info->num_mod_clks; i++)
+ rzg2l_cpg_register_mod_clk(&info->mod_clks[i], info, priv);
+
+ error = of_clk_add_provider(np, rzg2l_cpg_clk_src_twocell_get, priv);
+ if (error)
+ return error;
+
+ error = devm_add_action_or_reset(dev, rzg2l_cpg_del_clk_provider, np);
+ if (error)
+ return error;
+
+ error = rzg2l_cpg_add_clk_domain(dev);
+ if (error)
+ return error;
+
+ error = rzg2l_cpg_reset_controller_register(priv);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static const struct of_device_id rzg2l_cpg_match[] = {
+#ifdef CONFIG_CLK_R9A07G044
+ {
+ .compatible = "renesas,r9a07g044-cpg",
+ .data = &r9a07g044_cpg_info,
+ },
+#endif
+ { /* sentinel */ }
+};
+
+static struct platform_driver rzg2l_cpg_driver = {
+ .driver = {
+ .name = "rzg2l-cpg",
+ .of_match_table = rzg2l_cpg_match,
+ },
+};
+
+static int __init rzg2l_cpg_init(void)
+{
+ return platform_driver_probe(&rzg2l_cpg_driver, rzg2l_cpg_probe);
+}
+
+subsys_initcall(rzg2l_cpg_init);
+
+MODULE_DESCRIPTION("Renesas RZ/G2L CPG Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/renesas/renesas-rzg2l-cpg.h b/drivers/clk/renesas/renesas-rzg2l-cpg.h
new file mode 100644
index 000000000000..63695280ce8b
--- /dev/null
+++ b/drivers/clk/renesas/renesas-rzg2l-cpg.h
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * RZ/G2L Clock Pulse Generator
+ *
+ * Copyright (C) 2021 Renesas Electronics Corp.
+ *
+ */
+
+#ifndef __RENESAS_RZG2L_CPG_H__
+#define __RENESAS_RZG2L_CPG_H__
+
+#define CPG_PL2_DDIV (0x204)
+#define CPG_PL3A_DDIV (0x208)
+
+/* n = 0/1/2 for PLL1/4/6 */
+#define CPG_SAMPLL_CLK1(n) (0x04 + (16 * n))
+#define CPG_SAMPLL_CLK2(n) (0x08 + (16 * n))
+
+#define PLL146_CONF(n) (CPG_SAMPLL_CLK1(n) << 22 | CPG_SAMPLL_CLK2(n) << 12)
+
+#define DDIV_PACK(offset, bitpos, size) \
+ (((offset) << 20) | ((bitpos) << 12) | ((size) << 8))
+#define DIVPL2A DDIV_PACK(CPG_PL2_DDIV, 0, 3)
+#define DIVPL3A DDIV_PACK(CPG_PL3A_DDIV, 0, 3)
+#define DIVPL3B DDIV_PACK(CPG_PL3A_DDIV, 4, 3)
+
+/**
+ * Definitions of CPG Core Clocks
+ *
+ * These include:
+ * - Clock outputs exported to DT
+ * - External input clocks
+ * - Internal CPG clocks
+ */
+struct cpg_core_clk {
+ const char *name;
+ unsigned int id;
+ unsigned int parent;
+ unsigned int div;
+ unsigned int mult;
+ unsigned int type;
+ unsigned int conf;
+ const struct clk_div_table *dtable;
+ const char * const *parent_names;
+ int flag;
+ int num_parents;
+};
+
+enum clk_types {
+ /* Generic */
+ CLK_TYPE_IN, /* External Clock Input */
+ CLK_TYPE_FF, /* Fixed Factor Clock */
+ CLK_TYPE_SAM_PLL,
+
+ /* Clock with divider */
+ CLK_TYPE_DIV,
+};
+
+#define DEF_TYPE(_name, _id, _type...) \
+ { .name = _name, .id = _id, .type = _type }
+#define DEF_BASE(_name, _id, _type, _parent...) \
+ DEF_TYPE(_name, _id, _type, .parent = _parent)
+#define DEF_SAMPLL(_name, _id, _parent, _conf) \
+ DEF_TYPE(_name, _id, CLK_TYPE_SAM_PLL, .parent = _parent, .conf = _conf)
+#define DEF_INPUT(_name, _id) \
+ DEF_TYPE(_name, _id, CLK_TYPE_IN)
+#define DEF_FIXED(_name, _id, _parent, _mult, _div) \
+ DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult)
+#define DEF_DIV(_name, _id, _parent, _conf, _dtable, _flag) \
+ DEF_TYPE(_name, _id, CLK_TYPE_DIV, .conf = _conf, \
+ .parent = _parent, .dtable = _dtable, .flag = _flag)
+
+/**
+ * struct rzg2l_mod_clk - Module Clocks definitions
+ *
+ * @name: handle between common and hardware-specific interfaces
+ * @id: clock index in array containing all Core and Module Clocks
+ * @parent: id of parent clock
+ * @off: register offset
+ * @bit: ON/MON bit
+ */
+struct rzg2l_mod_clk {
+ const char *name;
+ unsigned int id;
+ unsigned int parent;
+ u16 off;
+ u8 bit;
+};
+
+#define DEF_MOD(_name, _id, _parent, _off, _bit) \
+ { \
+ .name = _name, \
+ .id = MOD_CLK_BASE + (_id), \
+ .parent = (_parent), \
+ .off = (_off), \
+ .bit = (_bit), \
+ }
+
+/**
+ * struct rzg2l_reset - Reset definitions
+ *
+ * @off: register offset
+ * @bit: reset bit
+ */
+struct rzg2l_reset {
+ u16 off;
+ u8 bit;
+};
+
+#define DEF_RST(_id, _off, _bit) \
+ [_id] = { \
+ .off = (_off), \
+ .bit = (_bit) \
+ }
+
+/**
+ * struct rzg2l_cpg_info - SoC-specific CPG Description
+ *
+ * @core_clks: Array of Core Clock definitions
+ * @num_core_clks: Number of entries in core_clks[]
+ * @last_dt_core_clk: ID of the last Core Clock exported to DT
+ * @num_total_core_clks: Total number of Core Clocks (exported + internal)
+ *
+ * @mod_clks: Array of Module Clock definitions
+ * @num_mod_clks: Number of entries in mod_clks[]
+ * @num_hw_mod_clks: Number of Module Clocks supported by the hardware
+ *
+ * @crit_mod_clks: Array with Module Clock IDs of critical clocks that
+ * should not be disabled without a knowledgeable driver
+ * @num_crit_mod_clks: Number of entries in crit_mod_clks[]
+ */
+struct rzg2l_cpg_info {
+ /* Core Clocks */
+ const struct cpg_core_clk *core_clks;
+ unsigned int num_core_clks;
+ unsigned int last_dt_core_clk;
+ unsigned int num_total_core_clks;
+
+ /* Module Clocks */
+ const struct rzg2l_mod_clk *mod_clks;
+ unsigned int num_mod_clks;
+ unsigned int num_hw_mod_clks;
+
+ /* Resets */
+ const struct rzg2l_reset *resets;
+ unsigned int num_resets;
+
+ /* Critical Module Clocks that should not be disabled */
+ const unsigned int *crit_mod_clks;
+ unsigned int num_crit_mod_clks;
+};
+
+extern const struct rzg2l_cpg_info r9a07g044_cpg_info;
+
+#endif
diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c
index 91d56ad45817..614845cc5b4a 100644
--- a/drivers/clk/rockchip/clk-rk3036.c
+++ b/drivers/clk/rockchip/clk-rk3036.c
@@ -259,7 +259,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
RK2928_CLKGATE_CON(1), 13, GFLAGS,
&rk3036_uart2_fracmux),
- COMPOSITE(0, "aclk_vcodec", mux_pll_src_3plls_p, 0,
+ COMPOSITE(ACLK_VCODEC, "aclk_vcodec", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS,
RK2928_CLKGATE_CON(3), 11, GFLAGS),
FACTOR_GATE(HCLK_VCODEC, "hclk_vcodec", "aclk_vcodec", 0, 1, 4,
diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c
index 946ea2f45bf3..75ca855e720d 100644
--- a/drivers/clk/rockchip/clk-rk3568.c
+++ b/drivers/clk/rockchip/clk-rk3568.c
@@ -454,17 +454,17 @@ static struct rockchip_clk_branch rk3568_clk_branches[] __initdata = {
COMPOSITE_NOMUX(CPLL_125M, "cpll_125m", "cpll", CLK_IGNORE_UNUSED,
RK3568_CLKSEL_CON(80), 0, 5, DFLAGS,
RK3568_CLKGATE_CON(35), 10, GFLAGS),
+ COMPOSITE_NOMUX(CPLL_100M, "cpll_100m", "cpll", CLK_IGNORE_UNUSED,
+ RK3568_CLKSEL_CON(82), 0, 5, DFLAGS,
+ RK3568_CLKGATE_CON(35), 11, GFLAGS),
COMPOSITE_NOMUX(CPLL_62P5M, "cpll_62p5", "cpll", CLK_IGNORE_UNUSED,
RK3568_CLKSEL_CON(80), 8, 5, DFLAGS,
- RK3568_CLKGATE_CON(35), 11, GFLAGS),
+ RK3568_CLKGATE_CON(35), 12, GFLAGS),
COMPOSITE_NOMUX(CPLL_50M, "cpll_50m", "cpll", CLK_IGNORE_UNUSED,
RK3568_CLKSEL_CON(81), 0, 5, DFLAGS,
- RK3568_CLKGATE_CON(35), 12, GFLAGS),
+ RK3568_CLKGATE_CON(35), 13, GFLAGS),
COMPOSITE_NOMUX(CPLL_25M, "cpll_25m", "cpll", CLK_IGNORE_UNUSED,
RK3568_CLKSEL_CON(81), 8, 6, DFLAGS,
- RK3568_CLKGATE_CON(35), 13, GFLAGS),
- COMPOSITE_NOMUX(CPLL_100M, "cpll_100m", "cpll", CLK_IGNORE_UNUSED,
- RK3568_CLKSEL_CON(82), 0, 5, DFLAGS,
RK3568_CLKGATE_CON(35), 14, GFLAGS),
COMPOSITE_NOMUX(0, "clk_osc0_div_750k", "xin24m", CLK_IGNORE_UNUSED,
RK3568_CLKSEL_CON(82), 8, 6, DFLAGS,
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index 571cee7bbfdc..7aa45cc70287 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -271,17 +271,24 @@ struct rockchip_clk_provider {
struct rockchip_pll_rate_table {
unsigned long rate;
- unsigned int nr;
- unsigned int nf;
- unsigned int no;
- unsigned int nb;
- /* for RK3036/RK3399 */
- unsigned int fbdiv;
- unsigned int postdiv1;
- unsigned int refdiv;
- unsigned int postdiv2;
- unsigned int dsmpd;
- unsigned int frac;
+ union {
+ struct {
+ /* for RK3066 */
+ unsigned int nr;
+ unsigned int nf;
+ unsigned int no;
+ unsigned int nb;
+ };
+ struct {
+ /* for RK3036/RK3399 */
+ unsigned int fbdiv;
+ unsigned int postdiv1;
+ unsigned int refdiv;
+ unsigned int postdiv2;
+ unsigned int dsmpd;
+ unsigned int frac;
+ };
+ };
};
/**
diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c
index 0d79ba31a793..80a288c59e56 100644
--- a/drivers/clk/sifive/sifive-prci.c
+++ b/drivers/clk/sifive/sifive-prci.c
@@ -564,7 +564,7 @@ static int __prci_register_clocks(struct device *dev, struct __prci_data *pd,
}
/**
- * sifive_prci_init() - initialize prci data and check parent count
+ * sifive_prci_probe() - initialize prci data and check parent count
* @pdev: platform device pointer for the prci
*
* Return: 0 upon success or a negative error code upon failure.
diff --git a/drivers/clk/socfpga/clk-agilex.c b/drivers/clk/socfpga/clk-agilex.c
index 92a6d740a799..1cb21ea79c64 100644
--- a/drivers/clk/socfpga/clk-agilex.c
+++ b/drivers/clk/socfpga/clk-agilex.c
@@ -177,6 +177,8 @@ static const struct clk_parent_data emac_mux[] = {
.name = "emaca_free_clk", },
{ .fw_name = "emacb_free_clk",
.name = "emacb_free_clk", },
+ { .fw_name = "boot_clk",
+ .name = "boot_clk", },
};
static const struct clk_parent_data noc_mux[] = {
@@ -186,6 +188,41 @@ static const struct clk_parent_data noc_mux[] = {
.name = "boot_clk", },
};
+static const struct clk_parent_data sdmmc_mux[] = {
+ { .fw_name = "sdmmc_free_clk",
+ .name = "sdmmc_free_clk", },
+ { .fw_name = "boot_clk",
+ .name = "boot_clk", },
+};
+
+static const struct clk_parent_data s2f_user1_mux[] = {
+ { .fw_name = "s2f_user1_free_clk",
+ .name = "s2f_user1_free_clk", },
+ { .fw_name = "boot_clk",
+ .name = "boot_clk", },
+};
+
+static const struct clk_parent_data psi_mux[] = {
+ { .fw_name = "psi_ref_free_clk",
+ .name = "psi_ref_free_clk", },
+ { .fw_name = "boot_clk",
+ .name = "boot_clk", },
+};
+
+static const struct clk_parent_data gpio_db_mux[] = {
+ { .fw_name = "gpio_db_free_clk",
+ .name = "gpio_db_free_clk", },
+ { .fw_name = "boot_clk",
+ .name = "boot_clk", },
+};
+
+static const struct clk_parent_data emac_ptp_mux[] = {
+ { .fw_name = "emac_ptp_free_clk",
+ .name = "emac_ptp_free_clk", },
+ { .fw_name = "boot_clk",
+ .name = "boot_clk", },
+};
+
/* clocks in AO (always on) controller */
static const struct stratix10_pll_clock agilex_pll_clks[] = {
{ AGILEX_BOOT_CLK, "boot_clk", boot_mux, ARRAY_SIZE(boot_mux), 0,
@@ -222,11 +259,9 @@ static const struct stratix10_perip_cnt_clock agilex_main_perip_cnt_clks[] = {
{ AGILEX_MPU_FREE_CLK, "mpu_free_clk", NULL, mpu_free_mux, ARRAY_SIZE(mpu_free_mux),
0, 0x3C, 0, 0, 0},
{ AGILEX_NOC_FREE_CLK, "noc_free_clk", NULL, noc_free_mux, ARRAY_SIZE(noc_free_mux),
- 0, 0x40, 0, 0, 1},
- { AGILEX_L4_SYS_FREE_CLK, "l4_sys_free_clk", "noc_free_clk", NULL, 1, 0,
- 0, 4, 0, 0},
- { AGILEX_NOC_CLK, "noc_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux),
- 0, 0, 0, 0x30, 1},
+ 0, 0x40, 0, 0, 0},
+ { AGILEX_L4_SYS_FREE_CLK, "l4_sys_free_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0,
+ 0, 4, 0x30, 1},
{ AGILEX_EMAC_A_FREE_CLK, "emaca_free_clk", NULL, emaca_free_mux, ARRAY_SIZE(emaca_free_mux),
0, 0xD4, 0, 0x88, 0},
{ AGILEX_EMAC_B_FREE_CLK, "emacb_free_clk", NULL, emacb_free_mux, ARRAY_SIZE(emacb_free_mux),
@@ -236,7 +271,7 @@ static const struct stratix10_perip_cnt_clock agilex_main_perip_cnt_clks[] = {
{ AGILEX_GPIO_DB_FREE_CLK, "gpio_db_free_clk", NULL, gpio_db_free_mux,
ARRAY_SIZE(gpio_db_free_mux), 0, 0xE0, 0, 0x88, 3},
{ AGILEX_SDMMC_FREE_CLK, "sdmmc_free_clk", NULL, sdmmc_free_mux,
- ARRAY_SIZE(sdmmc_free_mux), 0, 0xE4, 0, 0x88, 4},
+ ARRAY_SIZE(sdmmc_free_mux), 0, 0xE4, 0, 0, 0},
{ AGILEX_S2F_USER0_FREE_CLK, "s2f_user0_free_clk", NULL, s2f_usr0_free_mux,
ARRAY_SIZE(s2f_usr0_free_mux), 0, 0xE8, 0, 0, 0},
{ AGILEX_S2F_USER1_FREE_CLK, "s2f_user1_free_clk", NULL, s2f_usr1_free_mux,
@@ -252,24 +287,24 @@ static const struct stratix10_gate_clock agilex_gate_clks[] = {
0, 0, 0, 0, 0, 0, 4},
{ AGILEX_MPU_CCU_CLK, "mpu_ccu_clk", "mpu_clk", NULL, 1, 0, 0x24,
0, 0, 0, 0, 0, 0, 2},
- { AGILEX_L4_MAIN_CLK, "l4_main_clk", "noc_clk", NULL, 1, 0, 0x24,
- 1, 0x44, 0, 2, 0, 0, 0},
- { AGILEX_L4_MP_CLK, "l4_mp_clk", "noc_clk", NULL, 1, 0, 0x24,
- 2, 0x44, 8, 2, 0, 0, 0},
+ { AGILEX_L4_MAIN_CLK, "l4_main_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x24,
+ 1, 0x44, 0, 2, 0x30, 1, 0},
+ { AGILEX_L4_MP_CLK, "l4_mp_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x24,
+ 2, 0x44, 8, 2, 0x30, 1, 0},
/*
* The l4_sp_clk feeds a 100 MHz clock to various peripherals, one of them
* being the SP timers, thus cannot get gated.
*/
- { AGILEX_L4_SP_CLK, "l4_sp_clk", "noc_clk", NULL, 1, CLK_IS_CRITICAL, 0x24,
- 3, 0x44, 16, 2, 0, 0, 0},
- { AGILEX_CS_AT_CLK, "cs_at_clk", "noc_clk", NULL, 1, 0, 0x24,
- 4, 0x44, 24, 2, 0, 0, 0},
- { AGILEX_CS_TRACE_CLK, "cs_trace_clk", "noc_clk", NULL, 1, 0, 0x24,
- 4, 0x44, 26, 2, 0, 0, 0},
+ { AGILEX_L4_SP_CLK, "l4_sp_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), CLK_IS_CRITICAL, 0x24,
+ 3, 0x44, 16, 2, 0x30, 1, 0},
+ { AGILEX_CS_AT_CLK, "cs_at_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x24,
+ 4, 0x44, 24, 2, 0x30, 1, 0},
+ { AGILEX_CS_TRACE_CLK, "cs_trace_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x24,
+ 4, 0x44, 26, 2, 0x30, 1, 0},
{ AGILEX_CS_PDBG_CLK, "cs_pdbg_clk", "cs_at_clk", NULL, 1, 0, 0x24,
4, 0x44, 28, 1, 0, 0, 0},
- { AGILEX_CS_TIMER_CLK, "cs_timer_clk", "noc_clk", NULL, 1, 0, 0x24,
- 5, 0, 0, 0, 0, 0, 0},
+ { AGILEX_CS_TIMER_CLK, "cs_timer_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x24,
+ 5, 0, 0, 0, 0x30, 1, 0},
{ AGILEX_S2F_USER0_CLK, "s2f_user0_clk", NULL, s2f_usr0_mux, ARRAY_SIZE(s2f_usr0_mux), 0, 0x24,
6, 0, 0, 0, 0, 0, 0},
{ AGILEX_EMAC0_CLK, "emac0_clk", NULL, emac_mux, ARRAY_SIZE(emac_mux), 0, 0x7C,
@@ -278,16 +313,16 @@ static const struct stratix10_gate_clock agilex_gate_clks[] = {
1, 0, 0, 0, 0x94, 27, 0},
{ AGILEX_EMAC2_CLK, "emac2_clk", NULL, emac_mux, ARRAY_SIZE(emac_mux), 0, 0x7C,
2, 0, 0, 0, 0x94, 28, 0},
- { AGILEX_EMAC_PTP_CLK, "emac_ptp_clk", "emac_ptp_free_clk", NULL, 1, 0, 0x7C,
- 3, 0, 0, 0, 0, 0, 0},
- { AGILEX_GPIO_DB_CLK, "gpio_db_clk", "gpio_db_free_clk", NULL, 1, 0, 0x7C,
- 4, 0x98, 0, 16, 0, 0, 0},
- { AGILEX_SDMMC_CLK, "sdmmc_clk", "sdmmc_free_clk", NULL, 1, 0, 0x7C,
- 5, 0, 0, 0, 0, 0, 4},
- { AGILEX_S2F_USER1_CLK, "s2f_user1_clk", "s2f_user1_free_clk", NULL, 1, 0, 0x7C,
- 6, 0, 0, 0, 0, 0, 0},
- { AGILEX_PSI_REF_CLK, "psi_ref_clk", "psi_ref_free_clk", NULL, 1, 0, 0x7C,
- 7, 0, 0, 0, 0, 0, 0},
+ { AGILEX_EMAC_PTP_CLK, "emac_ptp_clk", NULL, emac_ptp_mux, ARRAY_SIZE(emac_ptp_mux), 0, 0x7C,
+ 3, 0, 0, 0, 0x88, 2, 0},
+ { AGILEX_GPIO_DB_CLK, "gpio_db_clk", NULL, gpio_db_mux, ARRAY_SIZE(gpio_db_mux), 0, 0x7C,
+ 4, 0x98, 0, 16, 0x88, 3, 0},
+ { AGILEX_SDMMC_CLK, "sdmmc_clk", NULL, sdmmc_mux, ARRAY_SIZE(sdmmc_mux), 0, 0x7C,
+ 5, 0, 0, 0, 0x88, 4, 4},
+ { AGILEX_S2F_USER1_CLK, "s2f_user1_clk", NULL, s2f_user1_mux, ARRAY_SIZE(s2f_user1_mux), 0, 0x7C,
+ 6, 0, 0, 0, 0x88, 5, 0},
+ { AGILEX_PSI_REF_CLK, "psi_ref_clk", NULL, psi_mux, ARRAY_SIZE(psi_mux), 0, 0x7C,
+ 7, 0, 0, 0, 0x88, 6, 0},
{ AGILEX_USB_CLK, "usb_clk", "l4_mp_clk", NULL, 1, 0, 0x7C,
8, 0, 0, 0, 0, 0, 0},
{ AGILEX_SPI_M_CLK, "spi_m_clk", "l4_mp_clk", NULL, 1, 0, 0x7C,
@@ -366,7 +401,7 @@ static int agilex_clk_register_gate(const struct stratix10_gate_clock *clks,
int i;
for (i = 0; i < nums; i++) {
- hw_clk = s10_register_gate(&clks[i], base);
+ hw_clk = agilex_register_gate(&clks[i], base);
if (IS_ERR(hw_clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
diff --git a/drivers/clk/socfpga/clk-gate-s10.c b/drivers/clk/socfpga/clk-gate-s10.c
index b84f2627551e..32567795765f 100644
--- a/drivers/clk/socfpga/clk-gate-s10.c
+++ b/drivers/clk/socfpga/clk-gate-s10.c
@@ -11,6 +11,13 @@
#define SOCFPGA_CS_PDBG_CLK "cs_pdbg_clk"
#define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw.hw)
+#define SOCFPGA_EMAC0_CLK "emac0_clk"
+#define SOCFPGA_EMAC1_CLK "emac1_clk"
+#define SOCFPGA_EMAC2_CLK "emac2_clk"
+#define AGILEX_BYPASS_OFFSET 0xC
+#define STRATIX10_BYPASS_OFFSET 0x2C
+#define BOOTCLK_BYPASS 2
+
static unsigned long socfpga_gate_clk_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
@@ -44,14 +51,61 @@ static unsigned long socfpga_dbg_clk_recalc_rate(struct clk_hw *hwclk,
static u8 socfpga_gate_get_parent(struct clk_hw *hwclk)
{
struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
- u32 mask;
+ u32 mask, second_bypass;
+ u8 parent = 0;
+ const char *name = clk_hw_get_name(hwclk);
+
+ if (socfpgaclk->bypass_reg) {
+ mask = (0x1 << socfpgaclk->bypass_shift);
+ parent = ((readl(socfpgaclk->bypass_reg) & mask) >>
+ socfpgaclk->bypass_shift);
+ }
+
+ if (streq(name, SOCFPGA_EMAC0_CLK) ||
+ streq(name, SOCFPGA_EMAC1_CLK) ||
+ streq(name, SOCFPGA_EMAC2_CLK)) {
+ second_bypass = readl(socfpgaclk->bypass_reg -
+ STRATIX10_BYPASS_OFFSET);
+ /* EMACA bypass to bootclk @0xB0 offset */
+ if (second_bypass & 0x1)
+ if (parent == 0) /* only applicable if parent is maca */
+ parent = BOOTCLK_BYPASS;
+
+ if (second_bypass & 0x2)
+ if (parent == 1) /* only applicable if parent is macb */
+ parent = BOOTCLK_BYPASS;
+ }
+ return parent;
+}
+
+static u8 socfpga_agilex_gate_get_parent(struct clk_hw *hwclk)
+{
+ struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
+ u32 mask, second_bypass;
u8 parent = 0;
+ const char *name = clk_hw_get_name(hwclk);
if (socfpgaclk->bypass_reg) {
mask = (0x1 << socfpgaclk->bypass_shift);
parent = ((readl(socfpgaclk->bypass_reg) & mask) >>
socfpgaclk->bypass_shift);
}
+
+ if (streq(name, SOCFPGA_EMAC0_CLK) ||
+ streq(name, SOCFPGA_EMAC1_CLK) ||
+ streq(name, SOCFPGA_EMAC2_CLK)) {
+ second_bypass = readl(socfpgaclk->bypass_reg -
+ AGILEX_BYPASS_OFFSET);
+ /* EMACA bypass to bootclk @0x88 offset */
+ if (second_bypass & 0x1)
+ if (parent == 0) /* only applicable if parent is maca */
+ parent = BOOTCLK_BYPASS;
+
+ if (second_bypass & 0x2)
+ if (parent == 1) /* only applicable if parent is macb */
+ parent = BOOTCLK_BYPASS;
+ }
+
return parent;
}
@@ -60,6 +114,11 @@ static struct clk_ops gateclk_ops = {
.get_parent = socfpga_gate_get_parent,
};
+static const struct clk_ops agilex_gateclk_ops = {
+ .recalc_rate = socfpga_gate_clk_recalc_rate,
+ .get_parent = socfpga_agilex_gate_get_parent,
+};
+
static const struct clk_ops dbgclk_ops = {
.recalc_rate = socfpga_dbg_clk_recalc_rate,
.get_parent = socfpga_gate_get_parent,
@@ -122,3 +181,61 @@ struct clk_hw *s10_register_gate(const struct stratix10_gate_clock *clks, void _
}
return hw_clk;
}
+
+struct clk_hw *agilex_register_gate(const struct stratix10_gate_clock *clks, void __iomem *regbase)
+{
+ struct clk_hw *hw_clk;
+ struct socfpga_gate_clk *socfpga_clk;
+ struct clk_init_data init;
+ const char *parent_name = clks->parent_name;
+ int ret;
+
+ socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
+ if (!socfpga_clk)
+ return NULL;
+
+ socfpga_clk->hw.reg = regbase + clks->gate_reg;
+ socfpga_clk->hw.bit_idx = clks->gate_idx;
+
+ gateclk_ops.enable = clk_gate_ops.enable;
+ gateclk_ops.disable = clk_gate_ops.disable;
+
+ socfpga_clk->fixed_div = clks->fixed_div;
+
+ if (clks->div_reg)
+ socfpga_clk->div_reg = regbase + clks->div_reg;
+ else
+ socfpga_clk->div_reg = NULL;
+
+ socfpga_clk->width = clks->div_width;
+ socfpga_clk->shift = clks->div_offset;
+
+ if (clks->bypass_reg)
+ socfpga_clk->bypass_reg = regbase + clks->bypass_reg;
+ else
+ socfpga_clk->bypass_reg = NULL;
+ socfpga_clk->bypass_shift = clks->bypass_shift;
+
+ if (streq(clks->name, "cs_pdbg_clk"))
+ init.ops = &dbgclk_ops;
+ else
+ init.ops = &agilex_gateclk_ops;
+
+ init.name = clks->name;
+ init.flags = clks->flags;
+
+ init.num_parents = clks->num_parents;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ if (init.parent_names == NULL)
+ init.parent_data = clks->parent_data;
+ socfpga_clk->hw.hw.init = &init;
+
+ hw_clk = &socfpga_clk->hw.hw;
+
+ ret = clk_hw_register(NULL, &socfpga_clk->hw.hw);
+ if (ret) {
+ kfree(socfpga_clk);
+ return ERR_PTR(ret);
+ }
+ return hw_clk;
+}
diff --git a/drivers/clk/socfpga/clk-periph-s10.c b/drivers/clk/socfpga/clk-periph-s10.c
index e5a5fef76df7..cbabde2b476b 100644
--- a/drivers/clk/socfpga/clk-periph-s10.c
+++ b/drivers/clk/socfpga/clk-periph-s10.c
@@ -64,16 +64,21 @@ static u8 clk_periclk_get_parent(struct clk_hw *hwclk)
{
struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
u32 clk_src, mask;
- u8 parent;
+ u8 parent = 0;
+ /* handle the bypass first */
if (socfpgaclk->bypass_reg) {
mask = (0x1 << socfpgaclk->bypass_shift);
parent = ((readl(socfpgaclk->bypass_reg) & mask) >>
socfpgaclk->bypass_shift);
- } else {
+ if (parent)
+ return parent;
+ }
+
+ if (socfpgaclk->hw.reg) {
clk_src = readl(socfpgaclk->hw.reg);
parent = (clk_src >> CLK_MGR_FREE_SHIFT) &
- CLK_MGR_FREE_MASK;
+ CLK_MGR_FREE_MASK;
}
return parent;
}
diff --git a/drivers/clk/socfpga/clk-pll.c b/drivers/clk/socfpga/clk-pll.c
index dcb573d44034..127cc849c5ee 100644
--- a/drivers/clk/socfpga/clk-pll.c
+++ b/drivers/clk/socfpga/clk-pll.c
@@ -80,7 +80,6 @@ static __init struct clk_hw *__socfpga_pll_init(struct device_node *node,
const char *parent_name[SOCFPGA_MAX_PARENTS];
struct clk_init_data init;
struct device_node *clkmgr_np;
- int rc;
int err;
of_property_read_u32(node, "reg", &reg);
@@ -114,7 +113,7 @@ static __init struct clk_hw *__socfpga_pll_init(struct device_node *node,
kfree(pll_clk);
return ERR_PTR(err);
}
- rc = of_clk_add_provider(node, of_clk_src_simple_get, hw_clk);
+ of_clk_add_provider(node, of_clk_src_simple_get, hw_clk);
return hw_clk;
}
diff --git a/drivers/clk/socfpga/clk-s10.c b/drivers/clk/socfpga/clk-s10.c
index f0bd77138ecb..b532d51faaee 100644
--- a/drivers/clk/socfpga/clk-s10.c
+++ b/drivers/clk/socfpga/clk-s10.c
@@ -144,6 +144,41 @@ static const struct clk_parent_data mpu_free_mux[] = {
.name = "f2s-free-clk", },
};
+static const struct clk_parent_data sdmmc_mux[] = {
+ { .fw_name = "sdmmc_free_clk",
+ .name = "sdmmc_free_clk", },
+ { .fw_name = "boot_clk",
+ .name = "boot_clk", },
+};
+
+static const struct clk_parent_data s2f_user1_mux[] = {
+ { .fw_name = "s2f_user1_free_clk",
+ .name = "s2f_user1_free_clk", },
+ { .fw_name = "boot_clk",
+ .name = "boot_clk", },
+};
+
+static const struct clk_parent_data psi_mux[] = {
+ { .fw_name = "psi_ref_free_clk",
+ .name = "psi_ref_free_clk", },
+ { .fw_name = "boot_clk",
+ .name = "boot_clk", },
+};
+
+static const struct clk_parent_data gpio_db_mux[] = {
+ { .fw_name = "gpio_db_free_clk",
+ .name = "gpio_db_free_clk", },
+ { .fw_name = "boot_clk",
+ .name = "boot_clk", },
+};
+
+static const struct clk_parent_data emac_ptp_mux[] = {
+ { .fw_name = "emac_ptp_free_clk",
+ .name = "emac_ptp_free_clk", },
+ { .fw_name = "boot_clk",
+ .name = "boot_clk", },
+};
+
/* clocks in AO (always on) controller */
static const struct stratix10_pll_clock s10_pll_clks[] = {
{ STRATIX10_BOOT_CLK, "boot_clk", boot_mux, ARRAY_SIZE(boot_mux), 0,
@@ -167,7 +202,7 @@ static const struct stratix10_perip_cnt_clock s10_main_perip_cnt_clks[] = {
{ STRATIX10_MPU_FREE_CLK, "mpu_free_clk", NULL, mpu_free_mux, ARRAY_SIZE(mpu_free_mux),
0, 0x48, 0, 0, 0},
{ STRATIX10_NOC_FREE_CLK, "noc_free_clk", NULL, noc_free_mux, ARRAY_SIZE(noc_free_mux),
- 0, 0x4C, 0, 0, 0},
+ 0, 0x4C, 0, 0x3C, 1},
{ STRATIX10_MAIN_EMACA_CLK, "main_emaca_clk", "main_noc_base_clk", NULL, 1, 0,
0x50, 0, 0, 0},
{ STRATIX10_MAIN_EMACB_CLK, "main_emacb_clk", "main_noc_base_clk", NULL, 1, 0,
@@ -200,10 +235,8 @@ static const struct stratix10_perip_cnt_clock s10_main_perip_cnt_clks[] = {
0, 0xD4, 0, 0, 0},
{ STRATIX10_PERI_PSI_REF_CLK, "peri_psi_ref_clk", "peri_noc_base_clk", NULL, 1, 0,
0xD8, 0, 0, 0},
- { STRATIX10_L4_SYS_FREE_CLK, "l4_sys_free_clk", "noc_free_clk", NULL, 1, 0,
- 0, 4, 0, 0},
- { STRATIX10_NOC_CLK, "noc_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux),
- 0, 0, 0, 0x3C, 1},
+ { STRATIX10_L4_SYS_FREE_CLK, "l4_sys_free_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0,
+ 0, 4, 0x3C, 1},
{ STRATIX10_EMAC_A_FREE_CLK, "emaca_free_clk", NULL, emaca_free_mux, ARRAY_SIZE(emaca_free_mux),
0, 0, 2, 0xB0, 0},
{ STRATIX10_EMAC_B_FREE_CLK, "emacb_free_clk", NULL, emacb_free_mux, ARRAY_SIZE(emacb_free_mux),
@@ -227,20 +260,20 @@ static const struct stratix10_gate_clock s10_gate_clks[] = {
0, 0, 0, 0, 0, 0, 4},
{ STRATIX10_MPU_L2RAM_CLK, "mpu_l2ram_clk", "mpu_clk", NULL, 1, 0, 0x30,
0, 0, 0, 0, 0, 0, 2},
- { STRATIX10_L4_MAIN_CLK, "l4_main_clk", "noc_clk", NULL, 1, 0, 0x30,
- 1, 0x70, 0, 2, 0, 0, 0},
- { STRATIX10_L4_MP_CLK, "l4_mp_clk", "noc_clk", NULL, 1, 0, 0x30,
- 2, 0x70, 8, 2, 0, 0, 0},
- { STRATIX10_L4_SP_CLK, "l4_sp_clk", "noc_clk", NULL, 1, CLK_IS_CRITICAL, 0x30,
- 3, 0x70, 16, 2, 0, 0, 0},
- { STRATIX10_CS_AT_CLK, "cs_at_clk", "noc_clk", NULL, 1, 0, 0x30,
- 4, 0x70, 24, 2, 0, 0, 0},
- { STRATIX10_CS_TRACE_CLK, "cs_trace_clk", "noc_clk", NULL, 1, 0, 0x30,
- 4, 0x70, 26, 2, 0, 0, 0},
+ { STRATIX10_L4_MAIN_CLK, "l4_main_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x30,
+ 1, 0x70, 0, 2, 0x3C, 1, 0},
+ { STRATIX10_L4_MP_CLK, "l4_mp_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x30,
+ 2, 0x70, 8, 2, 0x3C, 1, 0},
+ { STRATIX10_L4_SP_CLK, "l4_sp_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), CLK_IS_CRITICAL, 0x30,
+ 3, 0x70, 16, 2, 0x3C, 1, 0},
+ { STRATIX10_CS_AT_CLK, "cs_at_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x30,
+ 4, 0x70, 24, 2, 0x3C, 1, 0},
+ { STRATIX10_CS_TRACE_CLK, "cs_trace_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x30,
+ 4, 0x70, 26, 2, 0x3C, 1, 0},
{ STRATIX10_CS_PDBG_CLK, "cs_pdbg_clk", "cs_at_clk", NULL, 1, 0, 0x30,
4, 0x70, 28, 1, 0, 0, 0},
- { STRATIX10_CS_TIMER_CLK, "cs_timer_clk", "noc_clk", NULL, 1, 0, 0x30,
- 5, 0, 0, 0, 0, 0, 0},
+ { STRATIX10_CS_TIMER_CLK, "cs_timer_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0, 0x30,
+ 5, 0, 0, 0, 0x3C, 1, 0},
{ STRATIX10_S2F_USER0_CLK, "s2f_user0_clk", NULL, s2f_usr0_mux, ARRAY_SIZE(s2f_usr0_mux), 0, 0x30,
6, 0, 0, 0, 0, 0, 0},
{ STRATIX10_EMAC0_CLK, "emac0_clk", NULL, emac_mux, ARRAY_SIZE(emac_mux), 0, 0xA4,
@@ -249,16 +282,16 @@ static const struct stratix10_gate_clock s10_gate_clks[] = {
1, 0, 0, 0, 0xDC, 27, 0},
{ STRATIX10_EMAC2_CLK, "emac2_clk", NULL, emac_mux, ARRAY_SIZE(emac_mux), 0, 0xA4,
2, 0, 0, 0, 0xDC, 28, 0},
- { STRATIX10_EMAC_PTP_CLK, "emac_ptp_clk", "emac_ptp_free_clk", NULL, 1, 0, 0xA4,
- 3, 0, 0, 0, 0, 0, 0},
- { STRATIX10_GPIO_DB_CLK, "gpio_db_clk", "gpio_db_free_clk", NULL, 1, 0, 0xA4,
- 4, 0xE0, 0, 16, 0, 0, 0},
- { STRATIX10_SDMMC_CLK, "sdmmc_clk", "sdmmc_free_clk", NULL, 1, 0, 0xA4,
- 5, 0, 0, 0, 0, 0, 4},
- { STRATIX10_S2F_USER1_CLK, "s2f_user1_clk", "s2f_user1_free_clk", NULL, 1, 0, 0xA4,
- 6, 0, 0, 0, 0, 0, 0},
- { STRATIX10_PSI_REF_CLK, "psi_ref_clk", "psi_ref_free_clk", NULL, 1, 0, 0xA4,
- 7, 0, 0, 0, 0, 0, 0},
+ { STRATIX10_EMAC_PTP_CLK, "emac_ptp_clk", NULL, emac_ptp_mux, ARRAY_SIZE(emac_ptp_mux), 0, 0xA4,
+ 3, 0, 0, 0, 0xB0, 2, 0},
+ { STRATIX10_GPIO_DB_CLK, "gpio_db_clk", NULL, gpio_db_mux, ARRAY_SIZE(gpio_db_mux), 0, 0xA4,
+ 4, 0xE0, 0, 16, 0xB0, 3, 0},
+ { STRATIX10_SDMMC_CLK, "sdmmc_clk", NULL, sdmmc_mux, ARRAY_SIZE(sdmmc_mux), 0, 0xA4,
+ 5, 0, 0, 0, 0xB0, 4, 4},
+ { STRATIX10_S2F_USER1_CLK, "s2f_user1_clk", NULL, s2f_user1_mux, ARRAY_SIZE(s2f_user1_mux), 0, 0xA4,
+ 6, 0, 0, 0, 0xB0, 5, 0},
+ { STRATIX10_PSI_REF_CLK, "psi_ref_clk", NULL, psi_mux, ARRAY_SIZE(psi_mux), 0, 0xA4,
+ 7, 0, 0, 0, 0xB0, 6, 0},
{ STRATIX10_USB_CLK, "usb_clk", "l4_mp_clk", NULL, 1, 0, 0xA4,
8, 0, 0, 0, 0, 0, 0},
{ STRATIX10_SPI_M_CLK, "spi_m_clk", "l4_mp_clk", NULL, 1, 0, 0xA4,
diff --git a/drivers/clk/socfpga/stratix10-clk.h b/drivers/clk/socfpga/stratix10-clk.h
index 61eaf3a41fbb..75234e0783e1 100644
--- a/drivers/clk/socfpga/stratix10-clk.h
+++ b/drivers/clk/socfpga/stratix10-clk.h
@@ -85,4 +85,6 @@ struct clk_hw *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *c
void __iomem *reg);
struct clk_hw *s10_register_gate(const struct stratix10_gate_clock *clks,
void __iomem *reg);
+struct clk_hw *agilex_register_gate(const struct stratix10_gate_clock *clks,
+ void __iomem *reg);
#endif /* __STRATIX10_CLK_H */
diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c
index 55873d4b7603..7ae4f656191e 100644
--- a/drivers/clk/st/clk-flexgen.c
+++ b/drivers/clk/st/clk-flexgen.c
@@ -16,9 +16,16 @@
#include <linux/of.h>
#include <linux/of_address.h>
+struct clkgen_clk_out {
+ const char *name;
+ unsigned long flags;
+};
+
struct clkgen_data {
unsigned long flags;
bool mode;
+ const struct clkgen_clk_out *outputs;
+ const unsigned int outputs_nb;
};
struct flexgen {
@@ -295,6 +302,290 @@ static const struct clkgen_data clkgen_video = {
.mode = 1,
};
+static const struct clkgen_clk_out clkgen_stih407_a0_clk_out[] = {
+ /* This clk needs to be on so that memory interface is accessible */
+ { .name = "clk-ic-lmi0", .flags = CLK_IS_CRITICAL },
+};
+
+static const struct clkgen_data clkgen_stih407_a0 = {
+ .outputs = clkgen_stih407_a0_clk_out,
+ .outputs_nb = ARRAY_SIZE(clkgen_stih407_a0_clk_out),
+};
+
+static const struct clkgen_clk_out clkgen_stih410_a0_clk_out[] = {
+ /* Those clks need to be on so that memory interface is accessible */
+ { .name = "clk-ic-lmi0", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-ic-lmi1", .flags = CLK_IS_CRITICAL },
+};
+
+static const struct clkgen_data clkgen_stih410_a0 = {
+ .outputs = clkgen_stih410_a0_clk_out,
+ .outputs_nb = ARRAY_SIZE(clkgen_stih410_a0_clk_out),
+};
+
+static const struct clkgen_clk_out clkgen_stih407_c0_clk_out[] = {
+ { .name = "clk-icn-gpu", },
+ { .name = "clk-fdma", },
+ { .name = "clk-nand", },
+ { .name = "clk-hva", },
+ { .name = "clk-proc-stfe", },
+ { .name = "clk-proc-tp", },
+ { .name = "clk-rx-icn-dmu", },
+ { .name = "clk-rx-icn-hva", },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-icn-cpu", .flags = CLK_IS_CRITICAL },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-tx-icn-dmu", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-mmc-0", },
+ { .name = "clk-mmc-1", },
+ { .name = "clk-jpegdec", },
+ /* This clk needs to be on to keep A9 running */
+ { .name = "clk-ext2fa9", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-ic-bdisp-0", },
+ { .name = "clk-ic-bdisp-1", },
+ { .name = "clk-pp-dmu", },
+ { .name = "clk-vid-dmu", },
+ { .name = "clk-dss-lpc", },
+ { .name = "clk-st231-aud-0", },
+ { .name = "clk-st231-gp-1", },
+ { .name = "clk-st231-dmu", },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-icn-lmi", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-tx-icn-disp-1", },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-icn-sbc", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-stfe-frc2", },
+ { .name = "clk-eth-phy", },
+ { .name = "clk-eth-ref-phyclk", },
+ { .name = "clk-flash-promip", },
+ { .name = "clk-main-disp", },
+ { .name = "clk-aux-disp", },
+ { .name = "clk-compo-dvp", },
+};
+
+static const struct clkgen_data clkgen_stih407_c0 = {
+ .outputs = clkgen_stih407_c0_clk_out,
+ .outputs_nb = ARRAY_SIZE(clkgen_stih407_c0_clk_out),
+};
+
+static const struct clkgen_clk_out clkgen_stih410_c0_clk_out[] = {
+ { .name = "clk-icn-gpu", },
+ { .name = "clk-fdma", },
+ { .name = "clk-nand", },
+ { .name = "clk-hva", },
+ { .name = "clk-proc-stfe", },
+ { .name = "clk-proc-tp", },
+ { .name = "clk-rx-icn-dmu", },
+ { .name = "clk-rx-icn-hva", },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-icn-cpu", .flags = CLK_IS_CRITICAL },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-tx-icn-dmu", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-mmc-0", },
+ { .name = "clk-mmc-1", },
+ { .name = "clk-jpegdec", },
+ /* This clk needs to be on to keep A9 running */
+ { .name = "clk-ext2fa9", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-ic-bdisp-0", },
+ { .name = "clk-ic-bdisp-1", },
+ { .name = "clk-pp-dmu", },
+ { .name = "clk-vid-dmu", },
+ { .name = "clk-dss-lpc", },
+ { .name = "clk-st231-aud-0", },
+ { .name = "clk-st231-gp-1", },
+ { .name = "clk-st231-dmu", },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-icn-lmi", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-tx-icn-disp-1", },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-icn-sbc", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-stfe-frc2", },
+ { .name = "clk-eth-phy", },
+ { .name = "clk-eth-ref-phyclk", },
+ { .name = "clk-flash-promip", },
+ { .name = "clk-main-disp", },
+ { .name = "clk-aux-disp", },
+ { .name = "clk-compo-dvp", },
+ { .name = "clk-tx-icn-hades", },
+ { .name = "clk-rx-icn-hades", },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-icn-reg-16", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-pp-hades", },
+ { .name = "clk-clust-hades", },
+ { .name = "clk-hwpe-hades", },
+ { .name = "clk-fc-hades", },
+};
+
+static const struct clkgen_data clkgen_stih410_c0 = {
+ .outputs = clkgen_stih410_c0_clk_out,
+ .outputs_nb = ARRAY_SIZE(clkgen_stih410_c0_clk_out),
+};
+
+static const struct clkgen_clk_out clkgen_stih418_c0_clk_out[] = {
+ { .name = "clk-icn-gpu", },
+ { .name = "clk-fdma", },
+ { .name = "clk-nand", },
+ { .name = "clk-hva", },
+ { .name = "clk-proc-stfe", },
+ { .name = "clk-tp", },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-rx-icn-dmu", .flags = CLK_IS_CRITICAL },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-rx-icn-hva", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-icn-cpu", .flags = CLK_IS_CRITICAL },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-tx-icn-dmu", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-mmc-0", },
+ { .name = "clk-mmc-1", },
+ { .name = "clk-jpegdec", },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-icn-reg", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-proc-bdisp-0", },
+ { .name = "clk-proc-bdisp-1", },
+ { .name = "clk-pp-dmu", },
+ { .name = "clk-vid-dmu", },
+ { .name = "clk-dss-lpc", },
+ { .name = "clk-st231-aud-0", },
+ { .name = "clk-st231-gp-1", },
+ { .name = "clk-st231-dmu", },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-icn-lmi", .flags = CLK_IS_CRITICAL },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-tx-icn-1", .flags = CLK_IS_CRITICAL },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-icn-sbc", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-stfe-frc2", },
+ { .name = "clk-eth-phyref", },
+ { .name = "clk-eth-ref-phyclk", },
+ { .name = "clk-flash-promip", },
+ { .name = "clk-main-disp", },
+ { .name = "clk-aux-disp", },
+ { .name = "clk-compo-dvp", },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-tx-icn-hades", .flags = CLK_IS_CRITICAL },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-rx-icn-hades", .flags = CLK_IS_CRITICAL },
+ /* This clk needs to be on to keep bus interconnect alive */
+ { .name = "clk-icn-reg-16", .flags = CLK_IS_CRITICAL },
+ { .name = "clk-pp-hevc", },
+ { .name = "clk-clust-hevc", },
+ { .name = "clk-hwpe-hevc", },
+ { .name = "clk-fc-hevc", },
+ { .name = "clk-proc-mixer", },
+ { .name = "clk-proc-sc", },
+ { .name = "clk-avsp-hevc", },
+};
+
+static const struct clkgen_data clkgen_stih418_c0 = {
+ .outputs = clkgen_stih418_c0_clk_out,
+ .outputs_nb = ARRAY_SIZE(clkgen_stih418_c0_clk_out),
+};
+
+static const struct clkgen_clk_out clkgen_stih407_d0_clk_out[] = {
+ { .name = "clk-pcm-0", },
+ { .name = "clk-pcm-1", },
+ { .name = "clk-pcm-2", },
+ { .name = "clk-spdiff", },
+};
+
+static const struct clkgen_data clkgen_stih407_d0 = {
+ .flags = CLK_SET_RATE_PARENT,
+ .outputs = clkgen_stih407_d0_clk_out,
+ .outputs_nb = ARRAY_SIZE(clkgen_stih407_d0_clk_out),
+};
+
+static const struct clkgen_clk_out clkgen_stih410_d0_clk_out[] = {
+ { .name = "clk-pcm-0", },
+ { .name = "clk-pcm-1", },
+ { .name = "clk-pcm-2", },
+ { .name = "clk-spdiff", },
+ { .name = "clk-pcmr10-master", },
+ { .name = "clk-usb2-phy", },
+};
+
+static const struct clkgen_data clkgen_stih410_d0 = {
+ .flags = CLK_SET_RATE_PARENT,
+ .outputs = clkgen_stih410_d0_clk_out,
+ .outputs_nb = ARRAY_SIZE(clkgen_stih410_d0_clk_out),
+};
+
+static const struct clkgen_clk_out clkgen_stih407_d2_clk_out[] = {
+ { .name = "clk-pix-main-disp", },
+ { .name = "clk-pix-pip", },
+ { .name = "clk-pix-gdp1", },
+ { .name = "clk-pix-gdp2", },
+ { .name = "clk-pix-gdp3", },
+ { .name = "clk-pix-gdp4", },
+ { .name = "clk-pix-aux-disp", },
+ { .name = "clk-denc", },
+ { .name = "clk-pix-hddac", },
+ { .name = "clk-hddac", },
+ { .name = "clk-sddac", },
+ { .name = "clk-pix-dvo", },
+ { .name = "clk-dvo", },
+ { .name = "clk-pix-hdmi", },
+ { .name = "clk-tmds-hdmi", },
+ { .name = "clk-ref-hdmiphy", },
+};
+
+static const struct clkgen_data clkgen_stih407_d2 = {
+ .outputs = clkgen_stih407_d2_clk_out,
+ .outputs_nb = ARRAY_SIZE(clkgen_stih407_d2_clk_out),
+ .flags = CLK_SET_RATE_PARENT,
+ .mode = 1,
+};
+
+static const struct clkgen_clk_out clkgen_stih418_d2_clk_out[] = {
+ { .name = "clk-pix-main-disp", },
+ { .name = "", },
+ { .name = "", },
+ { .name = "", },
+ { .name = "", },
+ { .name = "clk-tmds-hdmi-div2", },
+ { .name = "clk-pix-aux-disp", },
+ { .name = "clk-denc", },
+ { .name = "clk-pix-hddac", },
+ { .name = "clk-hddac", },
+ { .name = "clk-sddac", },
+ { .name = "clk-pix-dvo", },
+ { .name = "clk-dvo", },
+ { .name = "clk-pix-hdmi", },
+ { .name = "clk-tmds-hdmi", },
+ { .name = "clk-ref-hdmiphy", },
+ { .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
+ { .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
+ { .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
+ { .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
+ { .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
+ { .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
+ { .name = "", }, { .name = "", }, { .name = "", }, { .name = "", },
+ { .name = "", }, { .name = "", }, { .name = "", },
+ { .name = "clk-vp9", },
+};
+
+static const struct clkgen_data clkgen_stih418_d2 = {
+ .outputs = clkgen_stih418_d2_clk_out,
+ .outputs_nb = ARRAY_SIZE(clkgen_stih418_d2_clk_out),
+ .flags = CLK_SET_RATE_PARENT,
+ .mode = 1,
+};
+
+static const struct clkgen_clk_out clkgen_stih407_d3_clk_out[] = {
+ { .name = "clk-stfe-frc1", },
+ { .name = "clk-tsout-0", },
+ { .name = "clk-tsout-1", },
+ { .name = "clk-mchi", },
+ { .name = "clk-vsens-compo", },
+ { .name = "clk-frc1-remote", },
+ { .name = "clk-lpc-0", },
+ { .name = "clk-lpc-1", },
+};
+
+static const struct clkgen_data clkgen_stih407_d3 = {
+ .outputs = clkgen_stih407_d3_clk_out,
+ .outputs_nb = ARRAY_SIZE(clkgen_stih407_d3_clk_out),
+};
+
static const struct of_device_id flexgen_of_match[] = {
{
.compatible = "st,flexgen-audio",
@@ -304,6 +595,46 @@ static const struct of_device_id flexgen_of_match[] = {
.compatible = "st,flexgen-video",
.data = &clkgen_video,
},
+ {
+ .compatible = "st,flexgen-stih407-a0",
+ .data = &clkgen_stih407_a0,
+ },
+ {
+ .compatible = "st,flexgen-stih410-a0",
+ .data = &clkgen_stih410_a0,
+ },
+ {
+ .compatible = "st,flexgen-stih407-c0",
+ .data = &clkgen_stih407_c0,
+ },
+ {
+ .compatible = "st,flexgen-stih410-c0",
+ .data = &clkgen_stih410_c0,
+ },
+ {
+ .compatible = "st,flexgen-stih418-c0",
+ .data = &clkgen_stih418_c0,
+ },
+ {
+ .compatible = "st,flexgen-stih407-d0",
+ .data = &clkgen_stih407_d0,
+ },
+ {
+ .compatible = "st,flexgen-stih410-d0",
+ .data = &clkgen_stih410_d0,
+ },
+ {
+ .compatible = "st,flexgen-stih407-d2",
+ .data = &clkgen_stih407_d2,
+ },
+ {
+ .compatible = "st,flexgen-stih418-d2",
+ .data = &clkgen_stih418_d2,
+ },
+ {
+ .compatible = "st,flexgen-stih407-d3",
+ .data = &clkgen_stih407_d3,
+ },
{}
};
@@ -320,6 +651,7 @@ static void __init st_of_flexgen_setup(struct device_node *np)
unsigned long flex_flags = 0;
int ret;
bool clk_mode = 0;
+ const char *clk_name;
pnode = of_get_parent(np);
if (!pnode)
@@ -347,13 +679,17 @@ static void __init st_of_flexgen_setup(struct device_node *np)
if (!clk_data)
goto err;
- ret = of_property_count_strings(np, "clock-output-names");
- if (ret <= 0) {
- pr_err("%s: Failed to get number of output clocks (%d)",
- __func__, clk_data->clk_num);
- goto err;
- }
- clk_data->clk_num = ret;
+ /* First try to get output information from the compatible data */
+ if (!data || !data->outputs_nb || !data->outputs) {
+ ret = of_property_count_strings(np, "clock-output-names");
+ if (ret <= 0) {
+ pr_err("%s: Failed to get number of output clocks (%d)",
+ __func__, clk_data->clk_num);
+ goto err;
+ }
+ clk_data->clk_num = ret;
+ } else
+ clk_data->clk_num = data->outputs_nb;
clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *),
GFP_KERNEL);
@@ -368,16 +704,19 @@ static void __init st_of_flexgen_setup(struct device_node *np)
for (i = 0; i < clk_data->clk_num; i++) {
struct clk *clk;
- const char *clk_name;
- if (of_property_read_string_index(np, "clock-output-names",
- i, &clk_name)) {
- break;
+ if (!data || !data->outputs_nb || !data->outputs) {
+ if (of_property_read_string_index(np,
+ "clock-output-names",
+ i, &clk_name))
+ break;
+ flex_flags &= ~CLK_IS_CRITICAL;
+ of_clk_detect_critical(np, i, &flex_flags);
+ } else {
+ clk_name = data->outputs[i].name;
+ flex_flags = data->flags | data->outputs[i].flags;
}
- flex_flags &= ~CLK_IS_CRITICAL;
- of_clk_detect_critical(np, i, &flex_flags);
-
/*
* If we read an empty clock name then the output is unused
*/
diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c
index dd6062e043e0..164285d6be97 100644
--- a/drivers/clk/st/clkgen-fsyn.c
+++ b/drivers/clk/st/clkgen-fsyn.c
@@ -66,6 +66,16 @@ struct clkgen_quadfs_data {
unsigned long *);
};
+struct clkgen_clk_out {
+ const char *name;
+ unsigned long flags;
+};
+
+struct clkgen_quadfs_data_clks {
+ struct clkgen_quadfs_data *data;
+ const struct clkgen_clk_out *outputs;
+};
+
static const struct clk_ops st_quadfs_pll_c32_ops;
static int clk_fs660c32_dig_get_params(unsigned long input,
@@ -115,6 +125,18 @@ static const struct clkgen_quadfs_data st_fs660c32_C = {
.get_rate = clk_fs660c32_dig_get_rate,
};
+static const struct clkgen_clk_out st_fs660c32_C_clks[] = {
+ { .name = "clk-s-c0-fs0-ch0", },
+ { .name = "clk-s-c0-fs0-ch1", },
+ { .name = "clk-s-c0-fs0-ch2", },
+ { .name = "clk-s-c0-fs0-ch3", },
+};
+
+static const struct clkgen_quadfs_data_clks st_fs660c32_C_data = {
+ .data = (struct clkgen_quadfs_data *)&st_fs660c32_C,
+ .outputs = st_fs660c32_C_clks,
+};
+
static const struct clkgen_quadfs_data st_fs660c32_D = {
.nrst_present = true,
.nrst = { CLKGEN_FIELD(0x2a0, 0x1, 0),
@@ -156,6 +178,46 @@ static const struct clkgen_quadfs_data st_fs660c32_D = {
.get_params = clk_fs660c32_dig_get_params,
.get_rate = clk_fs660c32_dig_get_rate,};
+static const struct clkgen_quadfs_data_clks st_fs660c32_D_data = {
+ .data = (struct clkgen_quadfs_data *)&st_fs660c32_D,
+};
+
+static const struct clkgen_clk_out st_fs660c32_D0_clks[] = {
+ { .name = "clk-s-d0-fs0-ch0", },
+ { .name = "clk-s-d0-fs0-ch1", },
+ { .name = "clk-s-d0-fs0-ch2", },
+ { .name = "clk-s-d0-fs0-ch3", },
+};
+
+static const struct clkgen_quadfs_data_clks st_fs660c32_D0_data = {
+ .data = (struct clkgen_quadfs_data *)&st_fs660c32_D,
+ .outputs = st_fs660c32_D0_clks,
+};
+
+static const struct clkgen_clk_out st_fs660c32_D2_clks[] = {
+ { .name = "clk-s-d2-fs0-ch0", },
+ { .name = "clk-s-d2-fs0-ch1", },
+ { .name = "clk-s-d2-fs0-ch2", },
+ { .name = "clk-s-d2-fs0-ch3", },
+};
+
+static const struct clkgen_quadfs_data_clks st_fs660c32_D2_data = {
+ .data = (struct clkgen_quadfs_data *)&st_fs660c32_D,
+ .outputs = st_fs660c32_D2_clks,
+};
+
+static const struct clkgen_clk_out st_fs660c32_D3_clks[] = {
+ { .name = "clk-s-d3-fs0-ch0", },
+ { .name = "clk-s-d3-fs0-ch1", },
+ { .name = "clk-s-d3-fs0-ch2", },
+ { .name = "clk-s-d3-fs0-ch3", },
+};
+
+static const struct clkgen_quadfs_data_clks st_fs660c32_D3_data = {
+ .data = (struct clkgen_quadfs_data *)&st_fs660c32_D,
+ .outputs = st_fs660c32_D3_clks,
+};
+
/**
* DOC: A Frequency Synthesizer that multiples its input clock by a fixed factor
*
@@ -857,7 +919,7 @@ static struct clk * __init st_clk_register_quadfs_fsynth(
static void __init st_of_create_quadfs_fsynths(
struct device_node *np, const char *pll_name,
- struct clkgen_quadfs_data *quadfs, void __iomem *reg,
+ struct clkgen_quadfs_data_clks *quadfs, void __iomem *reg,
spinlock_t *lock)
{
struct clk_onecell_data *clk_data;
@@ -881,9 +943,15 @@ static void __init st_of_create_quadfs_fsynths(
const char *clk_name;
unsigned long flags = 0;
- if (of_property_read_string_index(np, "clock-output-names",
- fschan, &clk_name)) {
- break;
+ if (quadfs->outputs) {
+ clk_name = quadfs->outputs[fschan].name;
+ flags = quadfs->outputs[fschan].flags;
+ } else {
+ if (of_property_read_string_index(np,
+ "clock-output-names",
+ fschan, &clk_name))
+ break;
+ of_clk_detect_critical(np, fschan, &flags);
}
/*
@@ -892,10 +960,8 @@ static void __init st_of_create_quadfs_fsynths(
if (*clk_name == '\0')
continue;
- of_clk_detect_critical(np, fschan, &flags);
-
clk = st_clk_register_quadfs_fsynth(clk_name, pll_name,
- quadfs, reg, fschan,
+ quadfs->data, reg, fschan,
flags, lock);
/*
@@ -915,7 +981,7 @@ static void __init st_of_create_quadfs_fsynths(
}
static void __init st_of_quadfs_setup(struct device_node *np,
- struct clkgen_quadfs_data *data)
+ struct clkgen_quadfs_data_clks *datac)
{
struct clk *clk;
const char *pll_name, *clk_parent_name;
@@ -940,7 +1006,7 @@ static void __init st_of_quadfs_setup(struct device_node *np,
spin_lock_init(lock);
- clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name, data,
+ clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name, datac->data,
reg, lock);
if (IS_ERR(clk))
goto err_exit;
@@ -950,7 +1016,7 @@ static void __init st_of_quadfs_setup(struct device_node *np,
__clk_get_name(clk_get_parent(clk)),
(unsigned int)clk_get_rate(clk));
- st_of_create_quadfs_fsynths(np, pll_name, data, reg, lock);
+ st_of_create_quadfs_fsynths(np, pll_name, datac, reg, lock);
err_exit:
kfree(pll_name); /* No longer need local copy of the PLL name */
@@ -958,12 +1024,35 @@ err_exit:
static void __init st_of_quadfs660C_setup(struct device_node *np)
{
- st_of_quadfs_setup(np, (struct clkgen_quadfs_data *) &st_fs660c32_C);
+ st_of_quadfs_setup(np,
+ (struct clkgen_quadfs_data_clks *) &st_fs660c32_C_data);
}
CLK_OF_DECLARE(quadfs660C, "st,quadfs-pll", st_of_quadfs660C_setup);
static void __init st_of_quadfs660D_setup(struct device_node *np)
{
- st_of_quadfs_setup(np, (struct clkgen_quadfs_data *) &st_fs660c32_D);
+ st_of_quadfs_setup(np,
+ (struct clkgen_quadfs_data_clks *) &st_fs660c32_D_data);
}
CLK_OF_DECLARE(quadfs660D, "st,quadfs", st_of_quadfs660D_setup);
+
+static void __init st_of_quadfs660D0_setup(struct device_node *np)
+{
+ st_of_quadfs_setup(np,
+ (struct clkgen_quadfs_data_clks *) &st_fs660c32_D0_data);
+}
+CLK_OF_DECLARE(quadfs660D0, "st,quadfs-d0", st_of_quadfs660D0_setup);
+
+static void __init st_of_quadfs660D2_setup(struct device_node *np)
+{
+ st_of_quadfs_setup(np,
+ (struct clkgen_quadfs_data_clks *) &st_fs660c32_D2_data);
+}
+CLK_OF_DECLARE(quadfs660D2, "st,quadfs-d2", st_of_quadfs660D2_setup);
+
+static void __init st_of_quadfs660D3_setup(struct device_node *np)
+{
+ st_of_quadfs_setup(np,
+ (struct clkgen_quadfs_data_clks *) &st_fs660c32_D3_data);
+}
+CLK_OF_DECLARE(quadfs660D3, "st,quadfs-d3", st_of_quadfs660D3_setup);
diff --git a/drivers/clk/st/clkgen-pll.c b/drivers/clk/st/clkgen-pll.c
index 119c5b33080c..b36e4d803636 100644
--- a/drivers/clk/st/clkgen-pll.c
+++ b/drivers/clk/st/clkgen-pll.c
@@ -57,6 +57,17 @@ struct clkgen_pll_data {
const struct clk_ops *ops;
};
+struct clkgen_clk_out {
+ const char *name;
+ unsigned long flags;
+};
+
+struct clkgen_pll_data_clks {
+ struct clkgen_pll_data *data;
+ const struct clkgen_clk_out *outputs;
+};
+
+
static const struct clk_ops stm_pll3200c32_ops;
static const struct clk_ops stm_pll3200c32_a9_ops;
static const struct clk_ops stm_pll4600c28_ops;
@@ -74,6 +85,28 @@ static const struct clkgen_pll_data st_pll3200c32_cx_0 = {
.ops = &stm_pll3200c32_ops,
};
+static const struct clkgen_pll_data_clks st_pll3200c32_cx_0_legacy_data = {
+ .data = (struct clkgen_pll_data *)&st_pll3200c32_cx_0,
+};
+
+static const struct clkgen_clk_out st_pll3200c32_ax_0_clks[] = {
+ { .name = "clk-s-a0-pll-odf-0", },
+};
+
+static const struct clkgen_pll_data_clks st_pll3200c32_a0_data = {
+ .data = (struct clkgen_pll_data *)&st_pll3200c32_cx_0,
+ .outputs = st_pll3200c32_ax_0_clks,
+};
+
+static const struct clkgen_clk_out st_pll3200c32_cx_0_clks[] = {
+ { .name = "clk-s-c0-pll0-odf-0", },
+};
+
+static const struct clkgen_pll_data_clks st_pll3200c32_c0_data = {
+ .data = (struct clkgen_pll_data *)&st_pll3200c32_cx_0,
+ .outputs = st_pll3200c32_cx_0_clks,
+};
+
static const struct clkgen_pll_data st_pll3200c32_cx_1 = {
/* 407 C0 PLL1 */
.pdn_status = CLKGEN_FIELD(0x2c8, 0x1, 8),
@@ -87,6 +120,19 @@ static const struct clkgen_pll_data st_pll3200c32_cx_1 = {
.ops = &stm_pll3200c32_ops,
};
+static const struct clkgen_pll_data_clks st_pll3200c32_cx_1_legacy_data = {
+ .data = (struct clkgen_pll_data *)&st_pll3200c32_cx_1,
+};
+
+static const struct clkgen_clk_out st_pll3200c32_cx_1_clks[] = {
+ { .name = "clk-s-c0-pll1-odf-0", },
+};
+
+static const struct clkgen_pll_data_clks st_pll3200c32_c1_data = {
+ .data = (struct clkgen_pll_data *)&st_pll3200c32_cx_1,
+ .outputs = st_pll3200c32_cx_1_clks,
+};
+
static const struct clkgen_pll_data st_pll3200c32_407_a9 = {
/* 407 A9 */
.pdn_status = CLKGEN_FIELD(0x1a8, 0x1, 0),
@@ -104,6 +150,15 @@ static const struct clkgen_pll_data st_pll3200c32_407_a9 = {
.ops = &stm_pll3200c32_a9_ops,
};
+static const struct clkgen_clk_out st_pll3200c32_407_a9_clks[] = {
+ { .name = "clockgen-a9-pll-odf", },
+};
+
+static const struct clkgen_pll_data_clks st_pll3200c32_407_a9_data = {
+ .data = (struct clkgen_pll_data *)&st_pll3200c32_407_a9,
+ .outputs = st_pll3200c32_407_a9_clks,
+};
+
static struct clkgen_pll_data st_pll4600c28_418_a9 = {
/* 418 A9 */
.pdn_status = CLKGEN_FIELD(0x1a8, 0x1, 0),
@@ -120,6 +175,15 @@ static struct clkgen_pll_data st_pll4600c28_418_a9 = {
.ops = &stm_pll4600c28_ops,
};
+static const struct clkgen_clk_out st_pll4600c28_418_a9_clks[] = {
+ { .name = "clockgen-a9-pll-odf", },
+};
+
+static const struct clkgen_pll_data_clks st_pll4600c28_418_a9_data = {
+ .data = (struct clkgen_pll_data *)&st_pll4600c28_418_a9,
+ .outputs = st_pll4600c28_418_a9_clks,
+};
+
/**
* DOC: Clock Generated by PLL, rate set and enabled by bootloader
*
@@ -146,7 +210,6 @@ struct clkgen_pll {
u32 ndiv;
u32 idf;
- u32 odf;
u32 cp;
};
@@ -685,7 +748,7 @@ static struct clk * __init clkgen_odf_register(const char *parent_name,
static void __init clkgen_c32_pll_setup(struct device_node *np,
- struct clkgen_pll_data *data)
+ struct clkgen_pll_data_clks *datac)
{
struct clk *clk;
const char *parent_name, *pll_name;
@@ -705,14 +768,14 @@ static void __init clkgen_c32_pll_setup(struct device_node *np,
of_clk_detect_critical(np, 0, &pll_flags);
- clk = clkgen_pll_register(parent_name, data, pll_base, pll_flags,
- np->name, data->lock);
+ clk = clkgen_pll_register(parent_name, datac->data, pll_base, pll_flags,
+ np->name, datac->data->lock);
if (IS_ERR(clk))
return;
pll_name = __clk_get_name(clk);
- num_odfs = data->num_odfs;
+ num_odfs = datac->data->num_odfs;
clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
if (!clk_data)
@@ -730,14 +793,21 @@ static void __init clkgen_c32_pll_setup(struct device_node *np,
const char *clk_name;
unsigned long odf_flags = 0;
- if (of_property_read_string_index(np, "clock-output-names",
- odf, &clk_name))
- return;
+ if (datac->outputs) {
+ clk_name = datac->outputs[odf].name;
+ odf_flags = datac->outputs[odf].flags;
+ } else {
+ if (of_property_read_string_index(np,
+ "clock-output-names",
+ odf, &clk_name))
+ return;
- of_clk_detect_critical(np, odf, &odf_flags);
+ of_clk_detect_critical(np, odf, &odf_flags);
+ }
- clk = clkgen_odf_register(pll_name, pll_base, data, odf_flags,
- odf, &clkgena_c32_odf_lock, clk_name);
+ clk = clkgen_odf_register(pll_name, pll_base, datac->data,
+ odf_flags, odf, &clkgena_c32_odf_lock,
+ clk_name);
if (IS_ERR(clk))
goto err;
@@ -755,27 +825,48 @@ err:
static void __init clkgen_c32_pll0_setup(struct device_node *np)
{
clkgen_c32_pll_setup(np,
- (struct clkgen_pll_data *) &st_pll3200c32_cx_0);
+ (struct clkgen_pll_data_clks *) &st_pll3200c32_cx_0_legacy_data);
}
CLK_OF_DECLARE(c32_pll0, "st,clkgen-pll0", clkgen_c32_pll0_setup);
+static void __init clkgen_c32_pll0_a0_setup(struct device_node *np)
+{
+ clkgen_c32_pll_setup(np,
+ (struct clkgen_pll_data_clks *) &st_pll3200c32_a0_data);
+}
+CLK_OF_DECLARE(c32_pll0_a0, "st,clkgen-pll0-a0", clkgen_c32_pll0_a0_setup);
+
+static void __init clkgen_c32_pll0_c0_setup(struct device_node *np)
+{
+ clkgen_c32_pll_setup(np,
+ (struct clkgen_pll_data_clks *) &st_pll3200c32_c0_data);
+}
+CLK_OF_DECLARE(c32_pll0_c0, "st,clkgen-pll0-c0", clkgen_c32_pll0_c0_setup);
+
static void __init clkgen_c32_pll1_setup(struct device_node *np)
{
clkgen_c32_pll_setup(np,
- (struct clkgen_pll_data *) &st_pll3200c32_cx_1);
+ (struct clkgen_pll_data_clks *) &st_pll3200c32_cx_1_legacy_data);
}
CLK_OF_DECLARE(c32_pll1, "st,clkgen-pll1", clkgen_c32_pll1_setup);
+static void __init clkgen_c32_pll1_c0_setup(struct device_node *np)
+{
+ clkgen_c32_pll_setup(np,
+ (struct clkgen_pll_data_clks *) &st_pll3200c32_c1_data);
+}
+CLK_OF_DECLARE(c32_pll1_c0, "st,clkgen-pll1-c0", clkgen_c32_pll1_c0_setup);
+
static void __init clkgen_c32_plla9_setup(struct device_node *np)
{
clkgen_c32_pll_setup(np,
- (struct clkgen_pll_data *) &st_pll3200c32_407_a9);
+ (struct clkgen_pll_data_clks *) &st_pll3200c32_407_a9_data);
}
CLK_OF_DECLARE(c32_plla9, "st,stih407-clkgen-plla9", clkgen_c32_plla9_setup);
static void __init clkgen_c28_plla9_setup(struct device_node *np)
{
clkgen_c32_pll_setup(np,
- (struct clkgen_pll_data *) &st_pll4600c28_418_a9);
+ (struct clkgen_pll_data_clks *) &st_pll4600c28_418_a9_data);
}
CLK_OF_DECLARE(c28_plla9, "st,stih418-clkgen-plla9", clkgen_c28_plla9_setup);
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
index a774942cb153..f49724a22540 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
@@ -817,10 +817,10 @@ static void __init sun8i_v3_v3s_ccu_init(struct device_node *node,
return;
}
- /* Force the PLL-Audio-1x divider to 4 */
+ /* Force the PLL-Audio-1x divider to 1 */
val = readl(reg + SUN8I_V3S_PLL_AUDIO_REG);
val &= ~GENMASK(19, 16);
- writel(val | (3 << 16), reg + SUN8I_V3S_PLL_AUDIO_REG);
+ writel(val, reg + SUN8I_V3S_PLL_AUDIO_REG);
sunxi_ccu_probe(node, reg, ccu_desc);
}
diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c
index 4b31beefc9fc..2091fc9b0ca9 100644
--- a/drivers/clk/tegra/clk-periph-gate.c
+++ b/drivers/clk/tegra/clk-periph-gate.c
@@ -48,36 +48,45 @@ static int clk_periph_is_enabled(struct clk_hw *hw)
return state;
}
-static int clk_periph_enable(struct clk_hw *hw)
+static void clk_periph_enable_locked(struct clk_hw *hw)
{
struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
- unsigned long flags = 0;
-
- spin_lock_irqsave(&periph_ref_lock, flags);
-
- gate->enable_refcnt[gate->clk_num]++;
- if (gate->enable_refcnt[gate->clk_num] > 1) {
- spin_unlock_irqrestore(&periph_ref_lock, flags);
- return 0;
- }
write_enb_set(periph_clk_to_bit(gate), gate);
udelay(2);
- if (!(gate->flags & TEGRA_PERIPH_NO_RESET) &&
- !(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) {
- if (read_rst(gate) & periph_clk_to_bit(gate)) {
- udelay(5); /* reset propogation delay */
- write_rst_clr(periph_clk_to_bit(gate), gate);
- }
- }
-
if (gate->flags & TEGRA_PERIPH_WAR_1005168) {
writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE);
writel_relaxed(BIT(22), gate->clk_base + LVL2_CLK_GATE_OVRE);
udelay(1);
writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE);
}
+}
+
+static void clk_periph_disable_locked(struct clk_hw *hw)
+{
+ struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
+
+ /*
+ * If peripheral is in the APB bus then read the APB bus to
+ * flush the write operation in apb bus. This will avoid the
+ * peripheral access after disabling clock
+ */
+ if (gate->flags & TEGRA_PERIPH_ON_APB)
+ tegra_read_chipid();
+
+ write_enb_clr(periph_clk_to_bit(gate), gate);
+}
+
+static int clk_periph_enable(struct clk_hw *hw)
+{
+ struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&periph_ref_lock, flags);
+
+ if (!gate->enable_refcnt[gate->clk_num]++)
+ clk_periph_enable_locked(hw);
spin_unlock_irqrestore(&periph_ref_lock, flags);
@@ -91,21 +100,28 @@ static void clk_periph_disable(struct clk_hw *hw)
spin_lock_irqsave(&periph_ref_lock, flags);
- gate->enable_refcnt[gate->clk_num]--;
- if (gate->enable_refcnt[gate->clk_num] > 0) {
- spin_unlock_irqrestore(&periph_ref_lock, flags);
- return;
- }
+ WARN_ON(!gate->enable_refcnt[gate->clk_num]);
+
+ if (--gate->enable_refcnt[gate->clk_num] == 0)
+ clk_periph_disable_locked(hw);
+
+ spin_unlock_irqrestore(&periph_ref_lock, flags);
+}
+
+static void clk_periph_disable_unused(struct clk_hw *hw)
+{
+ struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&periph_ref_lock, flags);
/*
- * If peripheral is in the APB bus then read the APB bus to
- * flush the write operation in apb bus. This will avoid the
- * peripheral access after disabling clock
+ * Some clocks are duplicated and some of them are marked as critical,
+ * like fuse and fuse_burn for example, thus the enable_refcnt will
+ * be non-zero here if the "unused" duplicate is disabled by CCF.
*/
- if (gate->flags & TEGRA_PERIPH_ON_APB)
- tegra_read_chipid();
-
- write_enb_clr(periph_clk_to_bit(gate), gate);
+ if (!gate->enable_refcnt[gate->clk_num])
+ clk_periph_disable_locked(hw);
spin_unlock_irqrestore(&periph_ref_lock, flags);
}
@@ -114,6 +130,7 @@ const struct clk_ops tegra_clk_periph_gate_ops = {
.is_enabled = clk_periph_is_enabled,
.enable = clk_periph_enable,
.disable = clk_periph_disable,
+ .disable_unused = clk_periph_disable_unused,
};
struct clk *tegra_clk_register_periph_gate(const char *name,
@@ -148,9 +165,6 @@ struct clk *tegra_clk_register_periph_gate(const char *name,
gate->enable_refcnt = enable_refcnt;
gate->regs = pregs;
- if (read_enb(gate) & periph_clk_to_bit(gate))
- enable_refcnt[clk_num]++;
-
/* Data in .init is copied by clk_register(), so stack variable OK */
gate->hw.init = &init;
diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
index 67620c7ecd9e..79ca3aa072b7 100644
--- a/drivers/clk/tegra/clk-periph.c
+++ b/drivers/clk/tegra/clk-periph.c
@@ -100,6 +100,15 @@ static void clk_periph_disable(struct clk_hw *hw)
gate_ops->disable(gate_hw);
}
+static void clk_periph_disable_unused(struct clk_hw *hw)
+{
+ struct tegra_clk_periph *periph = to_clk_periph(hw);
+ const struct clk_ops *gate_ops = periph->gate_ops;
+ struct clk_hw *gate_hw = &periph->gate.hw;
+
+ gate_ops->disable_unused(gate_hw);
+}
+
static void clk_periph_restore_context(struct clk_hw *hw)
{
struct tegra_clk_periph *periph = to_clk_periph(hw);
@@ -126,6 +135,7 @@ const struct clk_ops tegra_clk_periph_ops = {
.is_enabled = clk_periph_is_enabled,
.enable = clk_periph_enable,
.disable = clk_periph_disable,
+ .disable_unused = clk_periph_disable_unused,
.restore_context = clk_periph_restore_context,
};
@@ -135,6 +145,7 @@ static const struct clk_ops tegra_clk_periph_nodiv_ops = {
.is_enabled = clk_periph_is_enabled,
.enable = clk_periph_enable,
.disable = clk_periph_disable,
+ .disable_unused = clk_periph_disable_unused,
.restore_context = clk_periph_restore_context,
};
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 0193cebe8c5a..eaa079c177c3 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -558,6 +558,9 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
u32 p_div = 0;
int ret;
+ if (!rate)
+ return -EINVAL;
+
switch (parent_rate) {
case 12000000:
case 26000000:
@@ -1131,7 +1134,8 @@ static int clk_pllu_enable(struct clk_hw *hw)
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);
- _clk_pll_enable(hw);
+ if (!clk_pll_is_enabled(hw))
+ _clk_pll_enable(hw);
ret = clk_pll_wait_for_lock(pll);
if (ret < 0)
@@ -1748,15 +1752,13 @@ static int clk_pllu_tegra114_enable(struct clk_hw *hw)
return -EINVAL;
}
- if (clk_pll_is_enabled(hw))
- return 0;
-
input_rate = clk_hw_get_rate(__clk_get_hw(osc));
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);
- _clk_pll_enable(hw);
+ if (!clk_pll_is_enabled(hw))
+ _clk_pll_enable(hw);
ret = clk_pll_wait_for_lock(pll);
if (ret < 0)
diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index 60cc34f90cb9..292d6269daf1 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -712,9 +712,9 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX8("ndflash", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDFLASH, 13, TEGRA_PERIPH_ON_APB, tegra_clk_ndflash_8),
MUX8("ndspeed", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDSPEED, 80, TEGRA_PERIPH_ON_APB, tegra_clk_ndspeed_8),
MUX8("hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, 0, tegra_clk_hdmi),
- MUX8("extern1", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, 0, tegra_clk_extern1),
- MUX8("extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, 0, tegra_clk_extern2),
- MUX8("extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, 0, tegra_clk_extern3),
+ MUX8("extern1", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, TEGRA_PERIPH_NO_RESET, tegra_clk_extern1),
+ MUX8("extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, TEGRA_PERIPH_NO_RESET, tegra_clk_extern2),
+ MUX8("extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, TEGRA_PERIPH_NO_RESET, tegra_clk_extern3),
MUX8("soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm),
MUX8("soc_therm", mux_clkm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm_8),
MUX8("vi_sensor", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 164, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor_8),
diff --git a/drivers/clk/tegra/clk-tegra-super-cclk.c b/drivers/clk/tegra/clk-tegra-super-cclk.c
index a03119c30456..68d7bcd5fc8a 100644
--- a/drivers/clk/tegra/clk-tegra-super-cclk.c
+++ b/drivers/clk/tegra/clk-tegra-super-cclk.c
@@ -25,6 +25,8 @@
#define SUPER_CDIV_ENB BIT(31)
+#define TSENSOR_SLOWDOWN BIT(23)
+
static struct tegra_clk_super_mux *cclk_super;
static bool cclk_on_pllx;
@@ -47,10 +49,20 @@ static int cclk_super_set_rate(struct clk_hw *hw, unsigned long rate,
static unsigned long cclk_super_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
+ struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
+ u32 val = readl_relaxed(super->reg);
+ unsigned int div2;
+
+ /* check whether thermal throttling is active */
+ if (val & TSENSOR_SLOWDOWN)
+ div2 = 1;
+ else
+ div2 = 0;
+
if (cclk_super_get_parent(hw) == PLLX_INDEX)
- return parent_rate;
+ return parent_rate >> div2;
- return tegra_clk_super_ops.recalc_rate(hw, parent_rate);
+ return tegra_clk_super_ops.recalc_rate(hw, parent_rate) >> div2;
}
static int cclk_super_determine_rate(struct clk_hw *hw,
diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
index 2ac2679d696d..5e339ad0a97c 100644
--- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
+++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
@@ -537,7 +537,7 @@ static void get_alignment_from_dt(struct device *dev,
static int get_alignment_from_regulator(struct device *dev,
struct rail_alignment *align)
{
- struct regulator *reg = devm_regulator_get(dev, "vdd-cpu");
+ struct regulator *reg = regulator_get(dev, "vdd-cpu");
if (IS_ERR(reg))
return PTR_ERR(reg);
@@ -545,7 +545,7 @@ static int get_alignment_from_regulator(struct device *dev,
align->offset_uv = regulator_list_voltage(reg, 0);
align->step_uv = regulator_get_linear_step(reg);
- devm_regulator_put(reg);
+ regulator_put(reg);
return 0;
}
diff --git a/drivers/clk/tegra/clk-tegra124-emc.c b/drivers/clk/tegra/clk-tegra124-emc.c
index bdf6f4a51617..74c1d894cca8 100644
--- a/drivers/clk/tegra/clk-tegra124-emc.c
+++ b/drivers/clk/tegra/clk-tegra124-emc.c
@@ -249,8 +249,10 @@ static int emc_set_timing(struct tegra_clk_emc *tegra,
div = timing->parent_rate / (timing->rate / 2) - 2;
err = tegra->prepare_timing_change(emc, timing->rate);
- if (err)
+ if (err) {
+ clk_disable_unprepare(timing->parent);
return err;
+ }
spin_lock_irqsave(tegra->lock, flags);
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index 3efc651b42e3..3664593a5ba4 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -1021,9 +1021,9 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{ TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1 },
{ TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1 },
{ TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 0 },
- { TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 240000000, 0 },
- { TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 240000000, 0 },
- { TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 240000000, 0 },
+ { TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 120000000, 0 },
+ { TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 120000000, 0 },
+ { TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 120000000, 0 },
{ TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 0 },
{ TEGRA20_CLK_CSITE, TEGRA20_CLK_CLK_MAX, 0, 1 },
{ TEGRA20_CLK_CCLK, TEGRA20_CLK_CLK_MAX, 0, 1 },
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 16dbf83d2f62..64121bc66d85 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -930,7 +930,7 @@ static void __init tegra30_super_clk_init(void)
/* CCLKG */
clk = tegra_clk_register_super_cclk("cclk_g", cclk_g_parents,
ARRAY_SIZE(cclk_g_parents),
- CLK_SET_RATE_PARENT,
+ CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
clk_base + CCLKG_BURST_POLICY,
0, NULL);
clks[TEGRA30_CLK_CCLK_G] = clk;
@@ -1006,7 +1006,7 @@ static struct tegra_periph_init_data tegra_periph_clk_list[] = {
TEGRA_INIT_DATA_MUX("dam0", mux_pllacp_clkm, CLK_SOURCE_DAM0, 108, 0, TEGRA30_CLK_DAM0),
TEGRA_INIT_DATA_MUX("dam1", mux_pllacp_clkm, CLK_SOURCE_DAM1, 109, 0, TEGRA30_CLK_DAM1),
TEGRA_INIT_DATA_MUX("dam2", mux_pllacp_clkm, CLK_SOURCE_DAM2, 110, 0, TEGRA30_CLK_DAM2),
- TEGRA_INIT_DATA_INT("3d2", mux_pllmcpa, CLK_SOURCE_3D2, 98, TEGRA_PERIPH_MANUAL_RESET, TEGRA30_CLK_GR3D2),
+ TEGRA_INIT_DATA_INT("3d2", mux_pllmcpa, CLK_SOURCE_3D2, 98, 0, TEGRA30_CLK_GR3D2),
TEGRA_INIT_DATA_INT("se", mux_pllpcm_clkm, CLK_SOURCE_SE, 127, 0, TEGRA30_CLK_SE),
TEGRA_INIT_DATA_MUX8("hdmi", mux_pllpmdacd2_clkm, CLK_SOURCE_HDMI, 51, 0, TEGRA30_CLK_HDMI),
TEGRA_INIT_DATA("pwm", NULL, NULL, pwm_parents, CLK_SOURCE_PWM, 28, 2, 0, 0, 8, 1, 0, 17, TEGRA_PERIPH_ON_APB, TEGRA30_CLK_PWM),
@@ -1245,7 +1245,7 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{ TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0 },
{ TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0 },
{ TEGRA30_CLK_PLL_U, TEGRA30_CLK_CLK_MAX, 480000000, 0 },
- { TEGRA30_CLK_VDE, TEGRA30_CLK_PLL_C, 600000000, 0 },
+ { TEGRA30_CLK_VDE, TEGRA30_CLK_PLL_C, 300000000, 0 },
{ TEGRA30_CLK_SPDIF_IN_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
{ TEGRA30_CLK_I2S0_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
{ TEGRA30_CLK_I2S1_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index c3e36b5dcc75..0c3ba0ccce1a 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -553,9 +553,6 @@ struct tegra_clk_periph_regs {
* Flags:
* TEGRA_PERIPH_NO_RESET - This flag indicates that reset is not allowed
* for this module.
- * TEGRA_PERIPH_MANUAL_RESET - This flag indicates not to reset module
- * after clock enable and driver for the module is responsible for
- * doing reset.
* TEGRA_PERIPH_ON_APB - If peripheral is in the APB bus then read the
* bus to flush the write operation in apb bus. This flag indicates
* that this peripheral is in apb bus.
@@ -577,7 +574,6 @@ struct tegra_clk_periph_gate {
#define TEGRA_CLK_PERIPH_GATE_MAGIC 0x17760309
#define TEGRA_PERIPH_NO_RESET BIT(0)
-#define TEGRA_PERIPH_MANUAL_RESET BIT(1)
#define TEGRA_PERIPH_ON_APB BIT(2)
#define TEGRA_PERIPH_WAR_1005168 BIT(3)
#define TEGRA_PERIPH_NO_DIV BIT(4)
diff --git a/drivers/clk/ti/adpll.c b/drivers/clk/ti/adpll.c
index bb2f2836dab2..b341cd990be7 100644
--- a/drivers/clk/ti/adpll.c
+++ b/drivers/clk/ti/adpll.c
@@ -896,11 +896,8 @@ static int ti_adpll_probe(struct platform_device *pdev)
d->pa = res->start;
d->iobase = devm_ioremap_resource(dev, res);
- if (IS_ERR(d->iobase)) {
- dev_err(dev, "could not get IO base: %li\n",
- PTR_ERR(d->iobase));
+ if (IS_ERR(d->iobase))
return PTR_ERR(d->iobase);
- }
err = ti_adpll_init_registers(d);
if (err)
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c
index d6f1ac5b53e1..e9f9aee936ae 100644
--- a/drivers/clk/ti/dpll.c
+++ b/drivers/clk/ti/dpll.c
@@ -290,7 +290,9 @@ static void __init of_ti_dpll_setup(struct device_node *node,
struct clk_init_data *init = NULL;
const char **parent_names = NULL;
struct dpll_data *dd = NULL;
+ int ssc_clk_index;
u8 dpll_mode = 0;
+ u32 min_div;
dd = kmemdup(ddt, sizeof(*dd), GFP_KERNEL);
clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
@@ -345,6 +347,27 @@ static void __init of_ti_dpll_setup(struct device_node *node,
if (dd->autoidle_mask) {
if (ti_clk_get_reg_addr(node, 3, &dd->autoidle_reg))
goto cleanup;
+
+ ssc_clk_index = 4;
+ } else {
+ ssc_clk_index = 3;
+ }
+
+ if (dd->ssc_deltam_int_mask && dd->ssc_deltam_frac_mask &&
+ dd->ssc_modfreq_mant_mask && dd->ssc_modfreq_exp_mask) {
+ if (ti_clk_get_reg_addr(node, ssc_clk_index++,
+ &dd->ssc_deltam_reg))
+ goto cleanup;
+
+ if (ti_clk_get_reg_addr(node, ssc_clk_index++,
+ &dd->ssc_modfreq_reg))
+ goto cleanup;
+
+ of_property_read_u32(node, "ti,ssc-modfreq-hz",
+ &dd->ssc_modfreq);
+ of_property_read_u32(node, "ti,ssc-deltam", &dd->ssc_deltam);
+ dd->ssc_downspread =
+ of_property_read_bool(node, "ti,ssc-downspread");
}
if (of_property_read_bool(node, "ti,low-power-stop"))
@@ -356,6 +379,10 @@ static void __init of_ti_dpll_setup(struct device_node *node,
if (of_property_read_bool(node, "ti,lock"))
dpll_mode |= 1 << DPLL_LOCKED;
+ if (!of_property_read_u32(node, "ti,min-div", &min_div) &&
+ min_div > dd->min_divider)
+ dd->min_divider = min_div;
+
if (dpll_mode)
dd->modes = dpll_mode;
@@ -585,8 +612,14 @@ static void __init of_ti_am3_no_gate_dpll_setup(struct device_node *node)
const struct dpll_data dd = {
.idlest_mask = 0x1,
.enable_mask = 0x7,
+ .ssc_enable_mask = 0x1 << 12,
+ .ssc_downspread_mask = 0x1 << 14,
.mult_mask = 0x7ff << 8,
.div1_mask = 0x7f,
+ .ssc_deltam_int_mask = 0x3 << 18,
+ .ssc_deltam_frac_mask = 0x3ffff,
+ .ssc_modfreq_mant_mask = 0x7f,
+ .ssc_modfreq_exp_mask = 0x7 << 8,
.max_multiplier = 2047,
.max_divider = 128,
.min_divider = 1,
@@ -645,8 +678,14 @@ static void __init of_ti_am3_dpll_setup(struct device_node *node)
const struct dpll_data dd = {
.idlest_mask = 0x1,
.enable_mask = 0x7,
+ .ssc_enable_mask = 0x1 << 12,
+ .ssc_downspread_mask = 0x1 << 14,
.mult_mask = 0x7ff << 8,
.div1_mask = 0x7f,
+ .ssc_deltam_int_mask = 0x3 << 18,
+ .ssc_deltam_frac_mask = 0x3ffff,
+ .ssc_modfreq_mant_mask = 0x7f,
+ .ssc_modfreq_exp_mask = 0x7 << 8,
.max_multiplier = 2047,
.max_divider = 128,
.min_divider = 1,
diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c
index 6097b099a5df..e32b3515f9e7 100644
--- a/drivers/clk/ti/dpll3xxx.c
+++ b/drivers/clk/ti/dpll3xxx.c
@@ -292,7 +292,89 @@ static void _lookup_sddiv(struct clk_hw_omap *clk, u8 *sd_div, u16 m, u8 n)
}
/**
- * _omap3_noncore_dpll_program - set non-core DPLL M,N values directly
+ * omap3_noncore_dpll_ssc_program - set spread-spectrum clocking registers
+ * @clk: struct clk * of DPLL to set
+ *
+ * Enable the DPLL spread spectrum clocking if frequency modulation and
+ * frequency spreading have been set, otherwise disable it.
+ */
+static void omap3_noncore_dpll_ssc_program(struct clk_hw_omap *clk)
+{
+ struct dpll_data *dd = clk->dpll_data;
+ unsigned long ref_rate;
+ u32 v, ctrl, mod_freq_divider, exponent, mantissa;
+ u32 deltam_step, deltam_ceil;
+
+ ctrl = ti_clk_ll_ops->clk_readl(&dd->control_reg);
+
+ if (dd->ssc_modfreq && dd->ssc_deltam) {
+ ctrl |= dd->ssc_enable_mask;
+
+ if (dd->ssc_downspread)
+ ctrl |= dd->ssc_downspread_mask;
+ else
+ ctrl &= ~dd->ssc_downspread_mask;
+
+ ref_rate = clk_hw_get_rate(dd->clk_ref);
+ mod_freq_divider =
+ (ref_rate / dd->last_rounded_n) / (4 * dd->ssc_modfreq);
+ if (dd->ssc_modfreq > (ref_rate / 70))
+ pr_warn("clock: SSC modulation frequency of DPLL %s greater than %ld\n",
+ __clk_get_name(clk->hw.clk), ref_rate / 70);
+
+ exponent = 0;
+ mantissa = mod_freq_divider;
+ while ((mantissa > 127) && (exponent < 7)) {
+ exponent++;
+ mantissa /= 2;
+ }
+ if (mantissa > 127)
+ mantissa = 127;
+
+ v = ti_clk_ll_ops->clk_readl(&dd->ssc_modfreq_reg);
+ v &= ~(dd->ssc_modfreq_mant_mask | dd->ssc_modfreq_exp_mask);
+ v |= mantissa << __ffs(dd->ssc_modfreq_mant_mask);
+ v |= exponent << __ffs(dd->ssc_modfreq_exp_mask);
+ ti_clk_ll_ops->clk_writel(v, &dd->ssc_modfreq_reg);
+
+ deltam_step = dd->last_rounded_m * dd->ssc_deltam;
+ deltam_step /= 10;
+ if (dd->ssc_downspread)
+ deltam_step /= 2;
+
+ deltam_step <<= __ffs(dd->ssc_deltam_int_mask);
+ deltam_step /= 100;
+ deltam_step /= mod_freq_divider;
+ if (deltam_step > 0xFFFFF)
+ deltam_step = 0xFFFFF;
+
+ deltam_ceil = (deltam_step & dd->ssc_deltam_int_mask) >>
+ __ffs(dd->ssc_deltam_int_mask);
+ if (deltam_step & dd->ssc_deltam_frac_mask)
+ deltam_ceil++;
+
+ if ((dd->ssc_downspread &&
+ ((dd->last_rounded_m - (2 * deltam_ceil)) < 20 ||
+ dd->last_rounded_m > 2045)) ||
+ ((dd->last_rounded_m - deltam_ceil) < 20 ||
+ (dd->last_rounded_m + deltam_ceil) > 2045))
+ pr_warn("clock: SSC multiplier of DPLL %s is out of range\n",
+ __clk_get_name(clk->hw.clk));
+
+ v = ti_clk_ll_ops->clk_readl(&dd->ssc_deltam_reg);
+ v &= ~(dd->ssc_deltam_int_mask | dd->ssc_deltam_frac_mask);
+ v |= deltam_step << __ffs(dd->ssc_deltam_int_mask |
+ dd->ssc_deltam_frac_mask);
+ ti_clk_ll_ops->clk_writel(v, &dd->ssc_deltam_reg);
+ } else {
+ ctrl &= ~dd->ssc_enable_mask;
+ }
+
+ ti_clk_ll_ops->clk_writel(ctrl, &dd->control_reg);
+}
+
+/**
+ * omap3_noncore_dpll_program - set non-core DPLL M,N values directly
* @clk: struct clk * of DPLL to set
* @freqsel: FREQSEL value to set
*
@@ -390,6 +472,9 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
ti_clk_ll_ops->clk_writel(v, &dd->control_reg);
}
+ if (dd->ssc_enable_mask)
+ omap3_noncore_dpll_ssc_program(clk);
+
/* We let the clock framework set the other output dividers later */
/* REVISIT: Set ramp-up delay? */
diff --git a/drivers/clk/versatile/Kconfig b/drivers/clk/versatile/Kconfig
index 91f0ff54237d..481de5657d85 100644
--- a/drivers/clk/versatile/Kconfig
+++ b/drivers/clk/versatile/Kconfig
@@ -1,8 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "Clock driver for ARM Reference designs"
- depends on ARCH_INTEGRATOR || ARCH_REALVIEW || \
- ARCH_VERSATILE || ARCH_VEXPRESS || COMPILE_TEST
+ depends on HAS_IOMEM
config ICST
bool "Clock driver for ARM Reference designs ICST"
diff --git a/drivers/clk/zynqmp/clk-gate-zynqmp.c b/drivers/clk/zynqmp/clk-gate-zynqmp.c
index 10c9b889324f..695feaa82da5 100644
--- a/drivers/clk/zynqmp/clk-gate-zynqmp.c
+++ b/drivers/clk/zynqmp/clk-gate-zynqmp.c
@@ -121,7 +121,9 @@ struct clk_hw *zynqmp_clk_register_gate(const char *name, u32 clk_id,
init.name = name;
init.ops = &zynqmp_clk_gate_ops;
- init.flags = nodes->flag;
+
+ init.flags = zynqmp_clk_map_common_ccf_flags(nodes->flag);
+
init.parent_names = parents;
init.num_parents = 1;
diff --git a/drivers/clk/zynqmp/clk-mux-zynqmp.c b/drivers/clk/zynqmp/clk-mux-zynqmp.c
index 06194149be83..157d4a960bf4 100644
--- a/drivers/clk/zynqmp/clk-mux-zynqmp.c
+++ b/drivers/clk/zynqmp/clk-mux-zynqmp.c
@@ -38,7 +38,7 @@ struct zynqmp_clk_mux {
* zynqmp_clk_mux_get_parent() - Get parent of clock
* @hw: handle between common and hardware-specific interfaces
*
- * Return: Parent index
+ * Return: Parent index on success or number of parents in case of error
*/
static u8 zynqmp_clk_mux_get_parent(struct clk_hw *hw)
{
@@ -50,9 +50,15 @@ static u8 zynqmp_clk_mux_get_parent(struct clk_hw *hw)
ret = zynqmp_pm_clock_getparent(clk_id, &val);
- if (ret)
+ if (ret) {
pr_warn_once("%s() getparent failed for clock: %s, ret = %d\n",
__func__, clk_name, ret);
+ /*
+ * clk_core_get_parent_by_index() takes num_parents as incorrect
+ * index which is exactly what I want to return here
+ */
+ return clk_hw_get_num_parents(hw);
+ }
return val;
}
@@ -90,6 +96,27 @@ static const struct clk_ops zynqmp_clk_mux_ro_ops = {
.get_parent = zynqmp_clk_mux_get_parent,
};
+static inline unsigned long zynqmp_clk_map_mux_ccf_flags(
+ const u32 zynqmp_type_flag)
+{
+ unsigned long ccf_flag = 0;
+
+ if (zynqmp_type_flag & ZYNQMP_CLK_MUX_INDEX_ONE)
+ ccf_flag |= CLK_MUX_INDEX_ONE;
+ if (zynqmp_type_flag & ZYNQMP_CLK_MUX_INDEX_BIT)
+ ccf_flag |= CLK_MUX_INDEX_BIT;
+ if (zynqmp_type_flag & ZYNQMP_CLK_MUX_HIWORD_MASK)
+ ccf_flag |= CLK_MUX_HIWORD_MASK;
+ if (zynqmp_type_flag & ZYNQMP_CLK_MUX_READ_ONLY)
+ ccf_flag |= CLK_MUX_READ_ONLY;
+ if (zynqmp_type_flag & ZYNQMP_CLK_MUX_ROUND_CLOSEST)
+ ccf_flag |= CLK_MUX_ROUND_CLOSEST;
+ if (zynqmp_type_flag & ZYNQMP_CLK_MUX_BIG_ENDIAN)
+ ccf_flag |= CLK_MUX_BIG_ENDIAN;
+
+ return ccf_flag;
+}
+
/**
* zynqmp_clk_register_mux() - Register a mux table with the clock
* framework
@@ -120,10 +147,12 @@ struct clk_hw *zynqmp_clk_register_mux(const char *name, u32 clk_id,
init.ops = &zynqmp_clk_mux_ro_ops;
else
init.ops = &zynqmp_clk_mux_ops;
- init.flags = nodes->flag;
+
+ init.flags = zynqmp_clk_map_common_ccf_flags(nodes->flag);
+
init.parent_names = parents;
init.num_parents = num_parents;
- mux->flags = nodes->type_flag;
+ mux->flags = zynqmp_clk_map_mux_ccf_flags(nodes->type_flag);
mux->hw.init = &init;
mux->clk_id = clk_id;
diff --git a/drivers/clk/zynqmp/clk-zynqmp.h b/drivers/clk/zynqmp/clk-zynqmp.h
index 5beeb41b29fa..84fa80a969a9 100644
--- a/drivers/clk/zynqmp/clk-zynqmp.h
+++ b/drivers/clk/zynqmp/clk-zynqmp.h
@@ -10,6 +10,37 @@
#include <linux/firmware/xlnx-zynqmp.h>
+/* Common Flags */
+/* must be gated across rate change */
+#define ZYNQMP_CLK_SET_RATE_GATE BIT(0)
+/* must be gated across re-parent */
+#define ZYNQMP_CLK_SET_PARENT_GATE BIT(1)
+/* propagate rate change up one level */
+#define ZYNQMP_CLK_SET_RATE_PARENT BIT(2)
+/* do not gate even if unused */
+#define ZYNQMP_CLK_IGNORE_UNUSED BIT(3)
+/* don't re-parent on rate change */
+#define ZYNQMP_CLK_SET_RATE_NO_REPARENT BIT(7)
+/* do not gate, ever */
+#define ZYNQMP_CLK_IS_CRITICAL BIT(11)
+
+/* Type Flags for divider clock */
+#define ZYNQMP_CLK_DIVIDER_ONE_BASED BIT(0)
+#define ZYNQMP_CLK_DIVIDER_POWER_OF_TWO BIT(1)
+#define ZYNQMP_CLK_DIVIDER_ALLOW_ZERO BIT(2)
+#define ZYNQMP_CLK_DIVIDER_HIWORD_MASK BIT(3)
+#define ZYNQMP_CLK_DIVIDER_ROUND_CLOSEST BIT(4)
+#define ZYNQMP_CLK_DIVIDER_READ_ONLY BIT(5)
+#define ZYNQMP_CLK_DIVIDER_MAX_AT_ZERO BIT(6)
+
+/* Type Flags for mux clock */
+#define ZYNQMP_CLK_MUX_INDEX_ONE BIT(0)
+#define ZYNQMP_CLK_MUX_INDEX_BIT BIT(1)
+#define ZYNQMP_CLK_MUX_HIWORD_MASK BIT(2)
+#define ZYNQMP_CLK_MUX_READ_ONLY BIT(3)
+#define ZYNQMP_CLK_MUX_ROUND_CLOSEST BIT(4)
+#define ZYNQMP_CLK_MUX_BIG_ENDIAN BIT(5)
+
enum topology_type {
TYPE_INVALID,
TYPE_MUX,
@@ -33,6 +64,8 @@ struct clock_topology {
u8 custom_type_flag;
};
+unsigned long zynqmp_clk_map_common_ccf_flags(const u32 zynqmp_flag);
+
struct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id,
const char * const *parents,
u8 num_parents,
diff --git a/drivers/clk/zynqmp/clkc.c b/drivers/clk/zynqmp/clkc.c
index db8d0d7161ce..871184e406e1 100644
--- a/drivers/clk/zynqmp/clkc.c
+++ b/drivers/clk/zynqmp/clkc.c
@@ -271,6 +271,26 @@ static int zynqmp_pm_clock_get_topology(u32 clock_id, u32 index,
return ret;
}
+unsigned long zynqmp_clk_map_common_ccf_flags(const u32 zynqmp_flag)
+{
+ unsigned long ccf_flag = 0;
+
+ if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_GATE)
+ ccf_flag |= CLK_SET_RATE_GATE;
+ if (zynqmp_flag & ZYNQMP_CLK_SET_PARENT_GATE)
+ ccf_flag |= CLK_SET_PARENT_GATE;
+ if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_PARENT)
+ ccf_flag |= CLK_SET_RATE_PARENT;
+ if (zynqmp_flag & ZYNQMP_CLK_IGNORE_UNUSED)
+ ccf_flag |= CLK_IGNORE_UNUSED;
+ if (zynqmp_flag & ZYNQMP_CLK_SET_RATE_NO_REPARENT)
+ ccf_flag |= CLK_SET_RATE_NO_REPARENT;
+ if (zynqmp_flag & ZYNQMP_CLK_IS_CRITICAL)
+ ccf_flag |= CLK_IS_CRITICAL;
+
+ return ccf_flag;
+}
+
/**
* zynqmp_clk_register_fixed_factor() - Register fixed factor with the
* clock framework
@@ -292,6 +312,7 @@ struct clk_hw *zynqmp_clk_register_fixed_factor(const char *name, u32 clk_id,
struct zynqmp_pm_query_data qdata = {0};
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
+ unsigned long flag;
qdata.qid = PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS;
qdata.arg1 = clk_id;
@@ -303,9 +324,11 @@ struct clk_hw *zynqmp_clk_register_fixed_factor(const char *name, u32 clk_id,
mult = ret_payload[1];
div = ret_payload[2];
+ flag = zynqmp_clk_map_common_ccf_flags(nodes->flag);
+
hw = clk_hw_register_fixed_factor(NULL, name,
parents[0],
- nodes->flag, mult,
+ flag, mult,
div);
return hw;
diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c
index e9bf7958b821..cb49281f9cf9 100644
--- a/drivers/clk/zynqmp/divider.c
+++ b/drivers/clk/zynqmp/divider.c
@@ -256,6 +256,11 @@ static const struct clk_ops zynqmp_clk_divider_ops = {
.set_rate = zynqmp_clk_divider_set_rate,
};
+static const struct clk_ops zynqmp_clk_divider_ro_ops = {
+ .recalc_rate = zynqmp_clk_divider_recalc_rate,
+ .round_rate = zynqmp_clk_divider_round_rate,
+};
+
/**
* zynqmp_clk_get_max_divisor() - Get maximum supported divisor from firmware.
* @clk_id: Id of clock
@@ -284,6 +289,29 @@ static u32 zynqmp_clk_get_max_divisor(u32 clk_id, u32 type)
return ret_payload[1];
}
+static inline unsigned long zynqmp_clk_map_divider_ccf_flags(
+ const u32 zynqmp_type_flag)
+{
+ unsigned long ccf_flag = 0;
+
+ if (zynqmp_type_flag & ZYNQMP_CLK_DIVIDER_ONE_BASED)
+ ccf_flag |= CLK_DIVIDER_ONE_BASED;
+ if (zynqmp_type_flag & ZYNQMP_CLK_DIVIDER_POWER_OF_TWO)
+ ccf_flag |= CLK_DIVIDER_POWER_OF_TWO;
+ if (zynqmp_type_flag & ZYNQMP_CLK_DIVIDER_ALLOW_ZERO)
+ ccf_flag |= CLK_DIVIDER_ALLOW_ZERO;
+ if (zynqmp_type_flag & ZYNQMP_CLK_DIVIDER_POWER_OF_TWO)
+ ccf_flag |= CLK_DIVIDER_HIWORD_MASK;
+ if (zynqmp_type_flag & ZYNQMP_CLK_DIVIDER_ROUND_CLOSEST)
+ ccf_flag |= CLK_DIVIDER_ROUND_CLOSEST;
+ if (zynqmp_type_flag & ZYNQMP_CLK_DIVIDER_READ_ONLY)
+ ccf_flag |= CLK_DIVIDER_READ_ONLY;
+ if (zynqmp_type_flag & ZYNQMP_CLK_DIVIDER_MAX_AT_ZERO)
+ ccf_flag |= CLK_DIVIDER_MAX_AT_ZERO;
+
+ return ccf_flag;
+}
+
/**
* zynqmp_clk_register_divider() - Register a divider clock
* @name: Name of this clock
@@ -311,16 +339,20 @@ struct clk_hw *zynqmp_clk_register_divider(const char *name,
return ERR_PTR(-ENOMEM);
init.name = name;
- init.ops = &zynqmp_clk_divider_ops;
- /* CLK_FRAC is not defined in the common clk framework */
- init.flags = nodes->flag & ~CLK_FRAC;
+ if (nodes->type_flag & CLK_DIVIDER_READ_ONLY)
+ init.ops = &zynqmp_clk_divider_ro_ops;
+ else
+ init.ops = &zynqmp_clk_divider_ops;
+
+ init.flags = zynqmp_clk_map_common_ccf_flags(nodes->flag);
+
init.parent_names = parents;
init.num_parents = 1;
/* struct clk_divider assignments */
div->is_frac = !!((nodes->flag & CLK_FRAC) |
(nodes->custom_type_flag & CUSTOM_FLAG_CLK_FRAC));
- div->flags = nodes->type_flag;
+ div->flags = zynqmp_clk_map_divider_ccf_flags(nodes->type_flag);
div->hw.init = &init;
div->clk_id = clk_id;
div->div_type = nodes->type;
diff --git a/drivers/clk/zynqmp/pll.c b/drivers/clk/zynqmp/pll.c
index abe6afbf3407..036e4ff64a2f 100644
--- a/drivers/clk/zynqmp/pll.c
+++ b/drivers/clk/zynqmp/pll.c
@@ -31,8 +31,9 @@ struct zynqmp_pll {
#define PS_PLL_VCO_MAX 3000000000UL
enum pll_mode {
- PLL_MODE_INT,
- PLL_MODE_FRAC,
+ PLL_MODE_INT = 0,
+ PLL_MODE_FRAC = 1,
+ PLL_MODE_ERROR = 2,
};
#define FRAC_OFFSET 0x8
@@ -54,9 +55,11 @@ static inline enum pll_mode zynqmp_pll_get_mode(struct clk_hw *hw)
int ret;
ret = zynqmp_pm_get_pll_frac_mode(clk_id, ret_payload);
- if (ret)
+ if (ret) {
pr_warn_once("%s() PLL get frac mode failed for %s, ret = %d\n",
__func__, clk_name, ret);
+ return PLL_MODE_ERROR;
+ }
return ret_payload[1];
}
@@ -126,7 +129,7 @@ static long zynqmp_pll_round_rate(struct clk_hw *hw, unsigned long rate,
* @hw: Handle between common and hardware-specific interfaces
* @parent_rate: Clock frequency of parent clock
*
- * Return: Current clock frequency
+ * Return: Current clock frequency or 0 in case of error
*/
static unsigned long zynqmp_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
@@ -138,14 +141,21 @@ static unsigned long zynqmp_pll_recalc_rate(struct clk_hw *hw,
unsigned long rate, frac;
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
+ enum pll_mode mode;
ret = zynqmp_pm_clock_getdivider(clk_id, &fbdiv);
- if (ret)
+ if (ret) {
pr_warn_once("%s() get divider failed for %s, ret = %d\n",
__func__, clk_name, ret);
+ return 0ul;
+ }
+
+ mode = zynqmp_pll_get_mode(hw);
+ if (mode == PLL_MODE_ERROR)
+ return 0ul;
rate = parent_rate * fbdiv;
- if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) {
+ if (mode == PLL_MODE_FRAC) {
zynqmp_pm_get_pll_frac_data(clk_id, ret_payload);
data = ret_payload[1];
frac = (parent_rate * data) / FRAC_DIV;
@@ -312,7 +322,9 @@ struct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id,
init.name = name;
init.ops = &zynqmp_pll_ops;
- init.flags = nodes->flag;
+
+ init.flags = zynqmp_clk_map_common_ccf_flags(nodes->flag);
+
init.parent_names = parents;
init.num_parents = 1;
@@ -331,8 +343,6 @@ struct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id,
}
clk_hw_set_rate_range(hw, PS_PLL_VCO_MIN, PS_PLL_VCO_MAX);
- if (ret < 0)
- pr_err("%s:ERROR clk_set_rate_range failed %d\n", name, ret);
return hw;
}
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 39aa21d01e05..eb661b539a3e 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -358,9 +358,23 @@ config ARM_GLOBAL_TIMER
help
This option enables support for the ARM global timer unit.
+config ARM_GT_INITIAL_PRESCALER_VAL
+ int "ARM global timer initial prescaler value"
+ default 2 if ARCH_ZYNQ
+ default 1
+ depends on ARM_GLOBAL_TIMER
+ help
+ When the ARM global timer initializes, its current rate is declared
+ to the kernel and maintained forever. Should it's parent clock
+ change, the driver tries to fix the timer's internal prescaler.
+ On some machs (i.e. Zynq) the initial prescaler value thus poses
+ bounds about how much the parent clock is allowed to decrease or
+ increase wrt the initial clock value.
+ This affects CPU_FREQ max delta from the initial frequency.
+
config ARM_TIMER_SP804
bool "Support for Dual Timer SP804 module" if COMPILE_TEST
- depends on GENERIC_SCHED_CLOCK && CLKDEV_LOOKUP
+ depends on GENERIC_SCHED_CLOCK && HAVE_CLK
select CLKSRC_MMIO
select TIMER_OF if OF
@@ -570,12 +584,12 @@ config H8300_TPU
config CLKSRC_IMX_GPT
bool "Clocksource using i.MX GPT" if COMPILE_TEST
- depends on (ARM || ARM64) && CLKDEV_LOOKUP
+ depends on (ARM || ARM64) && HAVE_CLK
select CLKSRC_MMIO
config CLKSRC_IMX_TPM
bool "Clocksource using i.MX TPM" if COMPILE_TEST
- depends on (ARM || ARM64) && CLKDEV_LOOKUP
+ depends on (ARM || ARM64) && HAVE_CLK
select CLKSRC_MMIO
select TIMER_OF
help
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index fe1a82627d57..be6d741d404c 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -64,7 +64,6 @@ struct arch_timer {
#define to_arch_timer(e) container_of(e, struct arch_timer, evt)
static u32 arch_timer_rate __ro_after_init;
-u32 arch_timer_rate1 __ro_after_init;
static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI] __ro_after_init;
static const char *arch_timer_ppi_names[ARCH_TIMER_MAX_TIMER_PPI] = {
@@ -365,7 +364,7 @@ static u64 notrace arm64_858921_read_cntvct_el0(void)
do { \
_val = read_sysreg(reg); \
_retries--; \
- } while (((_val + 1) & GENMASK(9, 0)) <= 1 && _retries); \
+ } while (((_val + 1) & GENMASK(8, 0)) <= 1 && _retries); \
\
WARN_ON_ONCE(!_retries); \
_val; \
diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c
index 88b2d38a7a61..44a61dc6f932 100644
--- a/drivers/clocksource/arm_global_timer.c
+++ b/drivers/clocksource/arm_global_timer.c
@@ -31,6 +31,10 @@
#define GT_CONTROL_COMP_ENABLE BIT(1) /* banked */
#define GT_CONTROL_IRQ_ENABLE BIT(2) /* banked */
#define GT_CONTROL_AUTO_INC BIT(3) /* banked */
+#define GT_CONTROL_PRESCALER_SHIFT 8
+#define GT_CONTROL_PRESCALER_MAX 0xF
+#define GT_CONTROL_PRESCALER_MASK (GT_CONTROL_PRESCALER_MAX << \
+ GT_CONTROL_PRESCALER_SHIFT)
#define GT_INT_STATUS 0x0c
#define GT_INT_STATUS_EVENT_FLAG BIT(0)
@@ -39,6 +43,7 @@
#define GT_COMP1 0x14
#define GT_AUTO_INC 0x18
+#define MAX_F_ERR 50
/*
* We are expecting to be clocked by the ARM peripheral clock.
*
@@ -46,7 +51,8 @@
* the units for all operations.
*/
static void __iomem *gt_base;
-static unsigned long gt_clk_rate;
+static struct notifier_block gt_clk_rate_change_nb;
+static u32 gt_psv_new, gt_psv_bck, gt_target_rate;
static int gt_ppi;
static struct clock_event_device __percpu *gt_evt;
@@ -96,7 +102,10 @@ static void gt_compare_set(unsigned long delta, int periodic)
unsigned long ctrl;
counter += delta;
- ctrl = GT_CONTROL_TIMER_ENABLE;
+ ctrl = readl(gt_base + GT_CONTROL);
+ ctrl &= ~(GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE |
+ GT_CONTROL_AUTO_INC);
+ ctrl |= GT_CONTROL_TIMER_ENABLE;
writel_relaxed(ctrl, gt_base + GT_CONTROL);
writel_relaxed(lower_32_bits(counter), gt_base + GT_COMP0);
writel_relaxed(upper_32_bits(counter), gt_base + GT_COMP1);
@@ -123,7 +132,7 @@ static int gt_clockevent_shutdown(struct clock_event_device *evt)
static int gt_clockevent_set_periodic(struct clock_event_device *evt)
{
- gt_compare_set(DIV_ROUND_CLOSEST(gt_clk_rate, HZ), 1);
+ gt_compare_set(DIV_ROUND_CLOSEST(gt_target_rate, HZ), 1);
return 0;
}
@@ -177,7 +186,7 @@ static int gt_starting_cpu(unsigned int cpu)
clk->cpumask = cpumask_of(cpu);
clk->rating = 300;
clk->irq = gt_ppi;
- clockevents_config_and_register(clk, gt_clk_rate,
+ clockevents_config_and_register(clk, gt_target_rate,
1, 0xffffffff);
enable_percpu_irq(clk->irq, IRQ_TYPE_NONE);
return 0;
@@ -232,9 +241,28 @@ static struct delay_timer gt_delay_timer = {
.read_current_timer = gt_read_long,
};
+static void gt_write_presc(u32 psv)
+{
+ u32 reg;
+
+ reg = readl(gt_base + GT_CONTROL);
+ reg &= ~GT_CONTROL_PRESCALER_MASK;
+ reg |= psv << GT_CONTROL_PRESCALER_SHIFT;
+ writel(reg, gt_base + GT_CONTROL);
+}
+
+static u32 gt_read_presc(void)
+{
+ u32 reg;
+
+ reg = readl(gt_base + GT_CONTROL);
+ reg &= GT_CONTROL_PRESCALER_MASK;
+ return reg >> GT_CONTROL_PRESCALER_SHIFT;
+}
+
static void __init gt_delay_timer_init(void)
{
- gt_delay_timer.freq = gt_clk_rate;
+ gt_delay_timer.freq = gt_target_rate;
register_current_timer_delay(&gt_delay_timer);
}
@@ -243,18 +271,81 @@ static int __init gt_clocksource_init(void)
writel(0, gt_base + GT_CONTROL);
writel(0, gt_base + GT_COUNTER0);
writel(0, gt_base + GT_COUNTER1);
- /* enables timer on all the cores */
- writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
+ /* set prescaler and enable timer on all the cores */
+ writel(((CONFIG_ARM_GT_INITIAL_PRESCALER_VAL - 1) <<
+ GT_CONTROL_PRESCALER_SHIFT)
+ | GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
#ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
- sched_clock_register(gt_sched_clock_read, 64, gt_clk_rate);
+ sched_clock_register(gt_sched_clock_read, 64, gt_target_rate);
#endif
- return clocksource_register_hz(&gt_clocksource, gt_clk_rate);
+ return clocksource_register_hz(&gt_clocksource, gt_target_rate);
+}
+
+static int gt_clk_rate_change_cb(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct clk_notifier_data *ndata = data;
+
+ switch (event) {
+ case PRE_RATE_CHANGE:
+ {
+ int psv;
+
+ psv = DIV_ROUND_CLOSEST(ndata->new_rate,
+ gt_target_rate);
+
+ if (abs(gt_target_rate - (ndata->new_rate / psv)) > MAX_F_ERR)
+ return NOTIFY_BAD;
+
+ psv--;
+
+ /* prescaler within legal range? */
+ if (psv < 0 || psv > GT_CONTROL_PRESCALER_MAX)
+ return NOTIFY_BAD;
+
+ /*
+ * store timer clock ctrl register so we can restore it in case
+ * of an abort.
+ */
+ gt_psv_bck = gt_read_presc();
+ gt_psv_new = psv;
+ /* scale down: adjust divider in post-change notification */
+ if (ndata->new_rate < ndata->old_rate)
+ return NOTIFY_DONE;
+
+ /* scale up: adjust divider now - before frequency change */
+ gt_write_presc(psv);
+ break;
+ }
+ case POST_RATE_CHANGE:
+ /* scale up: pre-change notification did the adjustment */
+ if (ndata->new_rate > ndata->old_rate)
+ return NOTIFY_OK;
+
+ /* scale down: adjust divider now - after frequency change */
+ gt_write_presc(gt_psv_new);
+ break;
+
+ case ABORT_RATE_CHANGE:
+ /* we have to undo the adjustment in case we scale up */
+ if (ndata->new_rate < ndata->old_rate)
+ return NOTIFY_OK;
+
+ /* restore original register value */
+ gt_write_presc(gt_psv_bck);
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ return NOTIFY_DONE;
}
static int __init global_timer_of_register(struct device_node *np)
{
struct clk *gt_clk;
+ static unsigned long gt_clk_rate;
int err = 0;
/*
@@ -292,11 +383,20 @@ static int __init global_timer_of_register(struct device_node *np)
}
gt_clk_rate = clk_get_rate(gt_clk);
+ gt_target_rate = gt_clk_rate / CONFIG_ARM_GT_INITIAL_PRESCALER_VAL;
+ gt_clk_rate_change_nb.notifier_call =
+ gt_clk_rate_change_cb;
+ err = clk_notifier_register(gt_clk, &gt_clk_rate_change_nb);
+ if (err) {
+ pr_warn("Unable to register clock notifier\n");
+ goto out_clk;
+ }
+
gt_evt = alloc_percpu(struct clock_event_device);
if (!gt_evt) {
pr_warn("global-timer: can't allocate memory\n");
err = -ENOMEM;
- goto out_clk;
+ goto out_clk_nb;
}
err = request_percpu_irq(gt_ppi, gt_clockevent_interrupt,
@@ -326,6 +426,8 @@ out_irq:
free_percpu_irq(gt_ppi, gt_evt);
out_free:
free_percpu(gt_evt);
+out_clk_nb:
+ clk_notifier_unregister(gt_clk, &gt_clk_rate_change_nb);
out_clk:
clk_disable_unprepare(gt_clk);
out_unmap:
diff --git a/drivers/clocksource/ingenic-sysost.c b/drivers/clocksource/ingenic-sysost.c
index e77d58449005..a129840f14f9 100644
--- a/drivers/clocksource/ingenic-sysost.c
+++ b/drivers/clocksource/ingenic-sysost.c
@@ -186,7 +186,7 @@ static const struct clk_ops ingenic_ost_global_timer_ops = {
static const char * const ingenic_ost_clk_parents[] = { "ext" };
-static const struct ingenic_ost_clk_info ingenic_ost_clk_info[] = {
+static const struct ingenic_ost_clk_info x1000_ost_clk_info[] = {
[OST_CLK_PERCPU_TIMER] = {
.init_data = {
.name = "percpu timer",
@@ -414,14 +414,14 @@ static const struct ingenic_soc_info x1000_soc_info = {
.num_channels = 2,
};
-static const struct of_device_id __maybe_unused ingenic_ost_of_match[] __initconst = {
- { .compatible = "ingenic,x1000-ost", .data = &x1000_soc_info, },
+static const struct of_device_id __maybe_unused ingenic_ost_of_matches[] __initconst = {
+ { .compatible = "ingenic,x1000-ost", .data = &x1000_soc_info },
{ /* sentinel */ }
};
static int __init ingenic_ost_probe(struct device_node *np)
{
- const struct of_device_id *id = of_match_node(ingenic_ost_of_match, np);
+ const struct of_device_id *id = of_match_node(ingenic_ost_of_matches, np);
struct ingenic_ost *ost;
unsigned int i;
int ret;
@@ -462,7 +462,7 @@ static int __init ingenic_ost_probe(struct device_node *np)
ost->clocks->num = ost->soc_info->num_channels;
for (i = 0; i < ost->clocks->num; i++) {
- ret = ingenic_ost_register_clock(ost, i, &ingenic_ost_clk_info[i], ost->clocks);
+ ret = ingenic_ost_register_clock(ost, i, &x1000_ost_clk_info[i], ost->clocks);
if (ret) {
pr_crit("%s: Cannot register clock %d\n", __func__, i);
goto err_unregister_ost_clocks;
diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c
index f760229d0c7f..6e46781bc9ac 100644
--- a/drivers/clocksource/samsung_pwm_timer.c
+++ b/drivers/clocksource/samsung_pwm_timer.c
@@ -4,7 +4,7 @@
* http://www.samsung.com/
*
* samsung - Common hr-timer support (s3c and s5p)
-*/
+ */
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -22,7 +22,6 @@
#include <clocksource/samsung_pwm.h>
-
/*
* Clocksource driver
*/
@@ -38,8 +37,8 @@
#define TCFG0_PRESCALER_MASK 0xff
#define TCFG0_PRESCALER1_SHIFT 8
-#define TCFG1_SHIFT(x) ((x) * 4)
-#define TCFG1_MUX_MASK 0xf
+#define TCFG1_SHIFT(x) ((x) * 4)
+#define TCFG1_MUX_MASK 0xf
/*
* Each channel occupies 4 bits in TCON register, but there is a gap of 4
@@ -62,7 +61,7 @@ EXPORT_SYMBOL(samsung_pwm_lock);
struct samsung_pwm_clocksource {
void __iomem *base;
- void __iomem *source_reg;
+ const void __iomem *source_reg;
unsigned int irq[SAMSUNG_PWM_NUM];
struct samsung_pwm_variant variant;
@@ -183,7 +182,7 @@ static void samsung_time_start(unsigned int channel, bool periodic)
}
static int samsung_set_next_event(unsigned long cycles,
- struct clock_event_device *evt)
+ struct clock_event_device *evt)
{
/*
* This check is needed to account for internal rounding
@@ -225,6 +224,7 @@ static void samsung_clockevent_resume(struct clock_event_device *cev)
if (pwm.variant.has_tint_cstat) {
u32 mask = (1 << pwm.event_id);
+
writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT);
}
}
@@ -248,6 +248,7 @@ static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id)
if (pwm.variant.has_tint_cstat) {
u32 mask = (1 << pwm.event_id);
+
writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT);
}
@@ -272,7 +273,7 @@ static void __init samsung_clockevent_init(void)
time_event_device.cpumask = cpumask_of(0);
clockevents_config_and_register(&time_event_device,
- clock_rate, 1, pwm.tcnt_max);
+ clock_rate, 1, pwm.tcnt_max);
irq_number = pwm.irq[pwm.event_id];
if (request_irq(irq_number, samsung_clock_event_isr,
@@ -282,6 +283,7 @@ static void __init samsung_clockevent_init(void)
if (pwm.variant.has_tint_cstat) {
u32 mask = (1 << pwm.event_id);
+
writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT);
}
}
@@ -347,7 +349,7 @@ static int __init samsung_clocksource_init(void)
pwm.source_reg = pwm.base + pwm.source_id * 0x0c + 0x14;
sched_clock_register(samsung_read_sched_clock,
- pwm.variant.bits, clock_rate);
+ pwm.variant.bits, clock_rate);
samsung_clocksource.mask = CLOCKSOURCE_MASK(pwm.variant.bits);
return clocksource_register_hz(&samsung_clocksource, clock_rate);
@@ -398,7 +400,8 @@ static int __init _samsung_pwm_clocksource_init(void)
}
void __init samsung_pwm_clocksource_init(void __iomem *base,
- unsigned int *irqs, struct samsung_pwm_variant *variant)
+ unsigned int *irqs,
+ const struct samsung_pwm_variant *variant)
{
pwm.base = base;
memcpy(&pwm.variant, variant, sizeof(pwm.variant));
@@ -418,7 +421,7 @@ static int __init samsung_pwm_alloc(struct device_node *np,
struct property *prop;
const __be32 *cur;
u32 val;
- int i;
+ int i, ret;
memcpy(&pwm.variant, variant, sizeof(pwm.variant));
for (i = 0; i < SAMSUNG_PWM_NUM; ++i)
@@ -441,10 +444,24 @@ static int __init samsung_pwm_alloc(struct device_node *np,
pwm.timerclk = of_clk_get_by_name(np, "timers");
if (IS_ERR(pwm.timerclk)) {
pr_crit("failed to get timers clock for timer\n");
- return PTR_ERR(pwm.timerclk);
+ ret = PTR_ERR(pwm.timerclk);
+ goto err_clk;
}
- return _samsung_pwm_clocksource_init();
+ ret = _samsung_pwm_clocksource_init();
+ if (ret)
+ goto err_clocksource;
+
+ return 0;
+
+err_clocksource:
+ clk_put(pwm.timerclk);
+ pwm.timerclk = NULL;
+err_clk:
+ iounmap(pwm.base);
+ pwm.base = NULL;
+
+ return ret;
}
static const struct samsung_pwm_variant s3c24xx_variant = {
diff --git a/drivers/clocksource/timer-mediatek.c b/drivers/clocksource/timer-mediatek.c
index 9318edcd8963..ab63b95e414f 100644
--- a/drivers/clocksource/timer-mediatek.c
+++ b/drivers/clocksource/timer-mediatek.c
@@ -241,6 +241,28 @@ static void mtk_gpt_enable_irq(struct timer_of *to, u8 timer)
timer_of_base(to) + GPT_IRQ_EN_REG);
}
+static void mtk_gpt_resume(struct clock_event_device *clk)
+{
+ struct timer_of *to = to_timer_of(clk);
+
+ mtk_gpt_enable_irq(to, TIMER_CLK_EVT);
+}
+
+static void mtk_gpt_suspend(struct clock_event_device *clk)
+{
+ struct timer_of *to = to_timer_of(clk);
+
+ /* Disable all interrupts */
+ writel(0x0, timer_of_base(to) + GPT_IRQ_EN_REG);
+
+ /*
+ * This is called with interrupts disabled,
+ * so we need to ack any interrupt that is pending
+ * or for example ATF will prevent a suspend from completing.
+ */
+ writel(0x3f, timer_of_base(to) + GPT_IRQ_ACK_REG);
+}
+
static struct timer_of to = {
.flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
@@ -286,6 +308,8 @@ static int __init mtk_gpt_init(struct device_node *node)
to.clkevt.set_state_oneshot = mtk_gpt_clkevt_shutdown;
to.clkevt.tick_resume = mtk_gpt_clkevt_shutdown;
to.clkevt.set_next_event = mtk_gpt_clkevt_next_event;
+ to.clkevt.suspend = mtk_gpt_suspend;
+ to.clkevt.resume = mtk_gpt_resume;
to.of_irq.handler = mtk_gpt_interrupt;
ret = timer_of_init(node, &to);
diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c
index 33eeabf9c3d1..3e52c5226c4d 100644
--- a/drivers/clocksource/timer-ti-dm.c
+++ b/drivers/clocksource/timer-ti-dm.c
@@ -78,6 +78,9 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
static void omap_timer_restore_context(struct omap_dm_timer *timer)
{
+ __omap_dm_timer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET,
+ timer->context.ocp_cfg, 0);
+
omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
timer->context.twer);
omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
@@ -95,6 +98,9 @@ static void omap_timer_restore_context(struct omap_dm_timer *timer)
static void omap_timer_save_context(struct omap_dm_timer *timer)
{
+ timer->context.ocp_cfg =
+ __omap_dm_timer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET, 0);
+
timer->context.tclr =
omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
timer->context.twer =
@@ -122,7 +128,8 @@ static int omap_timer_context_notifier(struct notifier_block *nb,
break;
omap_timer_save_context(timer);
break;
- case CPU_CLUSTER_PM_ENTER_FAILED:
+ case CPU_CLUSTER_PM_ENTER_FAILED: /* No need to restore context */
+ break;
case CPU_CLUSTER_PM_EXIT:
if ((timer->capability & OMAP_TIMER_ALWON) ||
!atomic_read(&timer->enabled))
diff --git a/drivers/comedi/drivers/comedi_8254.c b/drivers/comedi/drivers/comedi_8254.c
index d1d509e9add9..4bf5daa9e885 100644
--- a/drivers/comedi/drivers/comedi_8254.c
+++ b/drivers/comedi/drivers/comedi_8254.c
@@ -555,6 +555,7 @@ static int comedi_8254_insn_config(struct comedi_device *dev,
/**
* comedi_8254_subdevice_init - initialize a comedi_subdevice for the 8254 timer
* @s: comedi_subdevice struct
+ * @i8254: comedi_8254 struct
*/
void comedi_8254_subdevice_init(struct comedi_subdevice *s,
struct comedi_8254 *i8254)
@@ -607,7 +608,7 @@ static struct comedi_8254 *__i8254_init(unsigned long iobase,
/**
* comedi_8254_init - allocate and initialize the 8254 device for pio access
- * @mmio: port I/O base address
+ * @iobase: port I/O base address
* @osc_base: base time of the counter in ns
* OPTIONAL - only used by comedi_8254_cascade_ns_to_timer()
* @iosize: I/O register size
diff --git a/drivers/comedi/drivers/comedi_isadma.c b/drivers/comedi/drivers/comedi_isadma.c
index c729094298c2..479b58e209ba 100644
--- a/drivers/comedi/drivers/comedi_isadma.c
+++ b/drivers/comedi/drivers/comedi_isadma.c
@@ -143,7 +143,7 @@ EXPORT_SYMBOL_GPL(comedi_isadma_set_mode);
* comedi_isadma_alloc - allocate and initialize the ISA DMA
* @dev: comedi_device struct
* @n_desc: the number of cookies to allocate
- * @dma_chan: DMA channel for the first cookie
+ * @dma_chan1: DMA channel for the first cookie
* @dma_chan2: DMA channel for the second cookie
* @maxsize: the size of the buffer to allocate for each cookie
* @dma_dir: the DMA direction
diff --git a/drivers/comedi/drivers/jr3_pci.c b/drivers/comedi/drivers/jr3_pci.c
index 7a02c4fa3cda..f963080dd61f 100644
--- a/drivers/comedi/drivers/jr3_pci.c
+++ b/drivers/comedi/drivers/jr3_pci.c
@@ -186,19 +186,6 @@ static void set_full_scales(struct jr3_sensor __iomem *sensor,
set_s16(&sensor->command_word0, 0x0a00);
}
-static struct six_axis_t get_min_full_scales(struct jr3_sensor __iomem *sensor)
-{
- struct six_axis_t result;
-
- result.fx = get_s16(&sensor->min_full_scale.fx);
- result.fy = get_s16(&sensor->min_full_scale.fy);
- result.fz = get_s16(&sensor->min_full_scale.fz);
- result.mx = get_s16(&sensor->min_full_scale.mx);
- result.my = get_s16(&sensor->min_full_scale.my);
- result.mz = get_s16(&sensor->min_full_scale.mz);
- return result;
-}
-
static struct six_axis_t get_max_full_scales(struct jr3_sensor __iomem *sensor)
{
struct six_axis_t result;
@@ -504,10 +491,8 @@ jr3_pci_poll_subdevice(struct comedi_subdevice *s)
result = poll_delay_min_max(20, 100);
} else {
/* Set full scale */
- struct six_axis_t min_full_scale;
struct six_axis_t max_full_scale;
- min_full_scale = get_min_full_scales(sensor);
max_full_scale = get_max_full_scales(sensor);
set_full_scales(sensor, max_full_scale);
diff --git a/drivers/comedi/drivers/ni_routes.c b/drivers/comedi/drivers/ni_routes.c
index c426a9286f15..f0f8cd424b30 100644
--- a/drivers/comedi/drivers/ni_routes.c
+++ b/drivers/comedi/drivers/ni_routes.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routes.c
* Route information for NI boards.
@@ -246,7 +245,7 @@ unsigned int ni_get_valid_routes(const struct ni_route_tables *tables,
}
EXPORT_SYMBOL_GPL(ni_get_valid_routes);
-/**
+/*
* List of NI global signal names that, as destinations, are only routeable
* indirectly through the *_arg elements of the comedi_cmd structure.
*/
@@ -388,7 +387,7 @@ ni_find_route_set(const int destination,
}
EXPORT_SYMBOL_GPL(ni_find_route_set);
-/**
+/*
* ni_route_set_has_source() - Determines whether the given source is in
* included given route_set.
*
@@ -507,7 +506,7 @@ s8 ni_route_to_register(const int src, const int dest,
}
EXPORT_SYMBOL_GPL(ni_route_to_register);
-/**
+/*
* ni_find_route_source() - Finds the signal source corresponding to a signal
* route (src-->dest) of the specified routing register
* value and the specified route destination on the
diff --git a/drivers/comedi/drivers/ni_routes.h b/drivers/comedi/drivers/ni_routes.h
index b7680fd2afe1..036982315584 100644
--- a/drivers/comedi/drivers/ni_routes.h
+++ b/drivers/comedi/drivers/ni_routes.h
@@ -1,5 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routes.h
* Route information for NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes.c b/drivers/comedi/drivers/ni_routing/ni_device_routes.c
index 7b6a74dfe48b..58654c2b12d6 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes.h b/drivers/comedi/drivers/ni_routing/ni_device_routes.h
index b9f1c47d19e1..09e4e172c659 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes.h
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes.h
@@ -1,5 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/all.h b/drivers/comedi/drivers/ni_routing/ni_device_routes/all.h
index 78b24138acb7..001dbb88a874 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/all.h
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/all.h
@@ -1,5 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/all.h
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6070e.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6070e.c
index f1126a0cb285..7d3064c92643 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6070e.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6070e.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pci-6070e.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6220.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6220.c
index 74a59222963f..e2c462edb8ec 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6220.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6220.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pci-6220.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6221.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6221.c
index 44dcbabf2a99..9e02ec0a66ad 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6221.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6221.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pci-6221.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6229.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6229.c
index fa5794e4e2b3..33f7fff61f74 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6229.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6229.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pci-6229.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6251.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6251.c
index 645fd1cd2de4..dde676b73624 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6251.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6251.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pci-6251.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6254.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6254.c
index 056a240cd3a2..167a2da97c14 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6254.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6254.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pci-6254.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6259.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6259.c
index e0b5fa78c3bc..ba990f98590c 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6259.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6259.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pci-6259.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6534.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6534.c
index a2472ed288cf..f8d2a91b6c0a 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6534.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6534.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pci-6534.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6602.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6602.c
index 91de9dac2d6a..2eee91f590eb 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6602.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6602.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pci-6602.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6713.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6713.c
index d378b36d2084..c07ef3584a4b 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6713.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6713.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pci-6713.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6723.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6723.c
index e0cc57ab06e7..c37373f8f0e1 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6723.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6723.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pci-6723.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6733.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6733.c
index f6e1e17ab854..f252fbe19638 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6733.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pci-6733.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pci-6733.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6030e.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6030e.c
index 9978d632117f..4ccba4fdf3bc 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6030e.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6030e.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pxi-6030e.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6224.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6224.c
index 1b89e27d7aa5..84fdfa2ef9a7 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6224.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6224.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pxi-6224.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6225.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6225.c
index 10dfc34bc87c..2b99ce0f87a4 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6225.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6225.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pxi-6225.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6251.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6251.c
index 25db4b7363de..1c5164c46306 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6251.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6251.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pxi-6251.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6733.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6733.c
index 27da4433fc4a..a3402b1ca6e8 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6733.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxi-6733.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pxi-6733.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6251.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6251.c
index 8354fe971d59..defcc4cfe1e4 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6251.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6251.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pxie-6251.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6535.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6535.c
index 2ebb679e0129..d2013b9e6767 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6535.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6535.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pxie-6535.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6738.c b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6738.c
index d88504314d7f..89aff39a4fc2 100644
--- a/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6738.c
+++ b/drivers/comedi/drivers/ni_routing/ni_device_routes/pxie-6738.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_device_routes/pxie-6738.c
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_route_values.c b/drivers/comedi/drivers/ni_routing/ni_route_values.c
index 5901762734ed..54a740b39819 100644
--- a/drivers/comedi/drivers/ni_routing/ni_route_values.c
+++ b/drivers/comedi/drivers/ni_routing/ni_route_values.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_route_values.c
* Route information for NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_route_values.h b/drivers/comedi/drivers/ni_routing/ni_route_values.h
index 80e0145fb82b..6e358efa6f7f 100644
--- a/drivers/comedi/drivers/ni_routing/ni_route_values.h
+++ b/drivers/comedi/drivers/ni_routing/ni_route_values.h
@@ -1,5 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_route_values.h
* Route information for NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_route_values/all.h b/drivers/comedi/drivers/ni_routing/ni_route_values/all.h
index 7227461500b5..30761e55f746 100644
--- a/drivers/comedi/drivers/ni_routing/ni_route_values/all.h
+++ b/drivers/comedi/drivers/ni_routing/ni_route_values/all.h
@@ -1,5 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_route_values/all.h
* List of valid routes for specific NI boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_route_values/ni_660x.c b/drivers/comedi/drivers/ni_routing/ni_route_values/ni_660x.c
index f1c7e6646261..aace60e49507 100644
--- a/drivers/comedi/drivers/ni_routing/ni_route_values/ni_660x.c
+++ b/drivers/comedi/drivers/ni_routing/ni_route_values/ni_660x.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_route_values/ni_660x.c
* Route information for NI_660X boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_route_values/ni_eseries.c b/drivers/comedi/drivers/ni_routing/ni_route_values/ni_eseries.c
index d1ab3c9ce585..7a52f024cdbd 100644
--- a/drivers/comedi/drivers/ni_routing/ni_route_values/ni_eseries.c
+++ b/drivers/comedi/drivers/ni_routing/ni_route_values/ni_eseries.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_route_values/ni_eseries.c
* Route information for NI_ESERIES boards.
diff --git a/drivers/comedi/drivers/ni_routing/ni_route_values/ni_mseries.c b/drivers/comedi/drivers/ni_routing/ni_route_values/ni_mseries.c
index c59d8afe0ae9..d1ddd13b33b5 100644
--- a/drivers/comedi/drivers/ni_routing/ni_route_values/ni_mseries.c
+++ b/drivers/comedi/drivers/ni_routing/ni_route_values/ni_mseries.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/ni_route_values/ni_mseries.c
* Route information for NI_MSERIES boards.
diff --git a/drivers/comedi/drivers/ni_routing/tools/convert_c_to_py.c b/drivers/comedi/drivers/ni_routing/tools/convert_c_to_py.c
index dedb6f2fc678..d55521b5bdcb 100644
--- a/drivers/comedi/drivers/ni_routing/tools/convert_c_to_py.c
+++ b/drivers/comedi/drivers/ni_routing/tools/convert_c_to_py.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
#include <stdint.h>
#include <stdbool.h>
diff --git a/drivers/comedi/drivers/ni_routing/tools/convert_csv_to_c.py b/drivers/comedi/drivers/ni_routing/tools/convert_csv_to_c.py
index 532eb6372a5a..90378fb50580 100755
--- a/drivers/comedi/drivers/ni_routing/tools/convert_csv_to_c.py
+++ b/drivers/comedi/drivers/ni_routing/tools/convert_csv_to_c.py
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0+
-# vim: ts=2:sw=2:et:tw=80:nowrap
# This is simply to aide in creating the entries in the order of the value of
# the device-global NI signal/terminal constants defined in comedi.h
@@ -123,7 +122,6 @@ class DeviceRoutes(CSVCollection):
output_file_top = """\
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/{filename}
* List of valid routes for specific NI boards.
@@ -155,7 +153,6 @@ class DeviceRoutes(CSVCollection):
extern_header = """\
/* SPDX-License-Identifier: GPL-2.0+ */
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/{filename}
* List of valid routes for specific NI boards.
@@ -193,7 +190,6 @@ class DeviceRoutes(CSVCollection):
single_output_file_top = """\
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/{filename}
* List of valid routes for specific NI boards.
@@ -299,7 +295,6 @@ class RouteValues(CSVCollection):
output_file_top = """\
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/{filename}
* Route information for NI boards.
@@ -337,7 +332,6 @@ class RouteValues(CSVCollection):
extern_header = """\
/* SPDX-License-Identifier: GPL-2.0+ */
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/{filename}
* List of valid routes for specific NI boards.
@@ -375,7 +369,6 @@ class RouteValues(CSVCollection):
single_output_file_top = """\
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/ni_routing/{filename}
* Route information for {sheet} boards.
diff --git a/drivers/comedi/drivers/ni_routing/tools/convert_py_to_csv.py b/drivers/comedi/drivers/ni_routing/tools/convert_py_to_csv.py
index b3e6472bac22..a273b33edb8f 100755
--- a/drivers/comedi/drivers/ni_routing/tools/convert_py_to_csv.py
+++ b/drivers/comedi/drivers/ni_routing/tools/convert_py_to_csv.py
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0+
-# vim: ts=2:sw=2:et:tw=80:nowrap
from os import path
import os, csv
diff --git a/drivers/comedi/drivers/ni_routing/tools/csv_collection.py b/drivers/comedi/drivers/ni_routing/tools/csv_collection.py
index 12617329a928..db977ecb4307 100644
--- a/drivers/comedi/drivers/ni_routing/tools/csv_collection.py
+++ b/drivers/comedi/drivers/ni_routing/tools/csv_collection.py
@@ -1,5 +1,4 @@
# SPDX-License-Identifier: GPL-2.0+
-# vim: ts=2:sw=2:et:tw=80:nowrap
import os, csv, glob
diff --git a/drivers/comedi/drivers/ni_routing/tools/make_blank_csv.py b/drivers/comedi/drivers/ni_routing/tools/make_blank_csv.py
index 89c90a0ba24d..c00eaf803299 100755
--- a/drivers/comedi/drivers/ni_routing/tools/make_blank_csv.py
+++ b/drivers/comedi/drivers/ni_routing/tools/make_blank_csv.py
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0+
-# vim: ts=2:sw=2:et:tw=80:nowrap
from os import path
import os, csv
diff --git a/drivers/comedi/drivers/ni_routing/tools/ni_names.py b/drivers/comedi/drivers/ni_routing/tools/ni_names.py
index 5f9b825968b1..d4df5f29e3e5 100644
--- a/drivers/comedi/drivers/ni_routing/tools/ni_names.py
+++ b/drivers/comedi/drivers/ni_routing/tools/ni_names.py
@@ -1,5 +1,4 @@
# SPDX-License-Identifier: GPL-2.0+
-# vim: ts=2:sw=2:et:tw=80:nowrap
"""
This file helps to extract string names of NI signals as included in comedi.h
between NI_NAMES_BASE and NI_NAMES_BASE+NI_NUM_NAMES.
diff --git a/drivers/comedi/drivers/ni_tio.c b/drivers/comedi/drivers/ni_tio.c
index f6154addaa95..da6826d77e60 100644
--- a/drivers/comedi/drivers/ni_tio.c
+++ b/drivers/comedi/drivers/ni_tio.c
@@ -1501,7 +1501,7 @@ int ni_tio_insn_config(struct comedi_device *dev,
}
EXPORT_SYMBOL_GPL(ni_tio_insn_config);
-/**
+/*
* Retrieves the register value of the current source of the output selector for
* the given destination.
*
@@ -1541,10 +1541,10 @@ int ni_tio_get_routing(struct ni_gpct_device *counter_dev, unsigned int dest)
EXPORT_SYMBOL_GPL(ni_tio_get_routing);
/**
- * Sets the register value of the selector MUX for the given destination.
- * @counter_dev:Pointer to general counter device.
- * @destination:Device-global identifier of route destination.
- * @register_value:
+ * ni_tio_set_routing() - Sets the register value of the selector MUX for the given destination.
+ * @counter_dev: Pointer to general counter device.
+ * @dest: Device-global identifier of route destination.
+ * @reg:
* The first several bits of this value should store the desired
* value to write to the register. All other bits are for
* transmitting information that modify the mode of the particular
@@ -1580,7 +1580,7 @@ int ni_tio_set_routing(struct ni_gpct_device *counter_dev, unsigned int dest,
}
EXPORT_SYMBOL_GPL(ni_tio_set_routing);
-/**
+/*
* Sets the given destination MUX to its default value or disable it.
*
* Return: 0 if successful; -EINVAL if terminal is unknown.
diff --git a/drivers/comedi/drivers/tests/comedi_example_test.c b/drivers/comedi/drivers/tests/comedi_example_test.c
index e5aaaeab7bdd..81d074bcdea5 100644
--- a/drivers/comedi/drivers/tests/comedi_example_test.c
+++ b/drivers/comedi/drivers/tests/comedi_example_test.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/tests/comedi_example_test.c
* Example set of unit tests.
diff --git a/drivers/comedi/drivers/tests/ni_routes_test.c b/drivers/comedi/drivers/tests/ni_routes_test.c
index 32073850d545..652362486ff6 100644
--- a/drivers/comedi/drivers/tests/ni_routes_test.c
+++ b/drivers/comedi/drivers/tests/ni_routes_test.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/tests/ni_routes_test.c
* Unit tests for NI routes (ni_routes.c module).
diff --git a/drivers/comedi/drivers/tests/unittest.h b/drivers/comedi/drivers/tests/unittest.h
index 2da3beea2479..b0b34e058aad 100644
--- a/drivers/comedi/drivers/tests/unittest.h
+++ b/drivers/comedi/drivers/tests/unittest.h
@@ -1,5 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/* vim: set ts=8 sw=8 noet tw=80 nowrap: */
/*
* comedi/drivers/tests/unittest.h
* Simple framework for unittests for comedi drivers.
diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c
index 9691f8612be8..09a9a77cce06 100644
--- a/drivers/counter/104-quad-8.c
+++ b/drivers/counter/104-quad-8.c
@@ -21,7 +21,7 @@
static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)];
static unsigned int num_quad8;
-module_param_array(base, uint, &num_quad8, 0);
+module_param_hw_array(base, uint, ioport, &num_quad8, 0);
MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
#define QUAD8_NUM_COUNTERS 8
@@ -193,7 +193,7 @@ enum quad8_count_function {
QUAD8_COUNT_FUNCTION_QUADRATURE_X4
};
-static enum counter_count_function quad8_count_functions_list[] = {
+static const enum counter_count_function quad8_count_functions_list[] = {
[QUAD8_COUNT_FUNCTION_PULSE_DIRECTION] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION,
[QUAD8_COUNT_FUNCTION_QUADRATURE_X1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A,
[QUAD8_COUNT_FUNCTION_QUADRATURE_X2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A,
@@ -305,12 +305,12 @@ enum quad8_synapse_action {
QUAD8_SYNAPSE_ACTION_BOTH_EDGES
};
-static enum counter_synapse_action quad8_index_actions_list[] = {
+static const enum counter_synapse_action quad8_index_actions_list[] = {
[QUAD8_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
[QUAD8_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE
};
-static enum counter_synapse_action quad8_synapse_actions_list[] = {
+static const enum counter_synapse_action quad8_synapse_actions_list[] = {
[QUAD8_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
[QUAD8_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE,
[QUAD8_SYNAPSE_ACTION_FALLING_EDGE] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
@@ -632,8 +632,8 @@ static ssize_t quad8_count_preset_read(struct counter_device *counter,
return sprintf(buf, "%u\n", priv->preset[count->id]);
}
-static void quad8_preset_register_set(struct quad8 *priv, int id,
- unsigned int preset)
+static void quad8_preset_register_set(struct quad8 *const priv, const int id,
+ const unsigned int preset)
{
const unsigned int base_offset = priv->base + 2 * id;
int i;
@@ -1082,7 +1082,6 @@ static int quad8_probe(struct device *dev, unsigned int id)
/* Enable all counters */
outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
- /* Register Counter device */
return devm_counter_register(dev, &priv->counter);
}
diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
index 5328705aa09c..d5d2540b30c2 100644
--- a/drivers/counter/Kconfig
+++ b/drivers/counter/Kconfig
@@ -91,4 +91,14 @@ config MICROCHIP_TCB_CAPTURE
To compile this driver as a module, choose M here: the
module will be called microchip-tcb-capture.
+config INTEL_QEP
+ tristate "Intel Quadrature Encoder Peripheral driver"
+ depends on PCI
+ help
+ Select this option to enable the Intel Quadrature Encoder Peripheral
+ driver.
+
+ To compile this driver as a module, choose M here: the module
+ will be called intel-qep.
+
endif # COUNTER
diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile
index cb646ed2f039..19742e6f5e3e 100644
--- a/drivers/counter/Makefile
+++ b/drivers/counter/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o
obj-$(CONFIG_TI_EQEP) += ti-eqep.o
obj-$(CONFIG_FTM_QUADDEC) += ftm-quaddec.o
obj-$(CONFIG_MICROCHIP_TCB_CAPTURE) += microchip-tcb-capture.o
+obj-$(CONFIG_INTEL_QEP) += intel-qep.o
diff --git a/drivers/counter/ftm-quaddec.c b/drivers/counter/ftm-quaddec.c
index c2b3fdfd8b77..9371532406ca 100644
--- a/drivers/counter/ftm-quaddec.c
+++ b/drivers/counter/ftm-quaddec.c
@@ -162,7 +162,7 @@ enum ftm_quaddec_synapse_action {
FTM_QUADDEC_SYNAPSE_ACTION_BOTH_EDGES,
};
-static enum counter_synapse_action ftm_quaddec_synapse_actions[] = {
+static const enum counter_synapse_action ftm_quaddec_synapse_actions[] = {
[FTM_QUADDEC_SYNAPSE_ACTION_BOTH_EDGES] =
COUNTER_SYNAPSE_ACTION_BOTH_EDGES
};
diff --git a/drivers/counter/intel-qep.c b/drivers/counter/intel-qep.c
new file mode 100644
index 000000000000..8d7ae28fbd67
--- /dev/null
+++ b/drivers/counter/intel-qep.c
@@ -0,0 +1,544 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Quadrature Encoder Peripheral driver
+ *
+ * Copyright (C) 2019-2021 Intel Corporation
+ *
+ * Author: Felipe Balbi (Intel)
+ * Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
+ * Author: Raymond Tan <raymond.tan@intel.com>
+ */
+#include <linux/bitops.h>
+#include <linux/counter.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+
+#define INTEL_QEPCON 0x00
+#define INTEL_QEPFLT 0x04
+#define INTEL_QEPCOUNT 0x08
+#define INTEL_QEPMAX 0x0c
+#define INTEL_QEPWDT 0x10
+#define INTEL_QEPCAPDIV 0x14
+#define INTEL_QEPCNTR 0x18
+#define INTEL_QEPCAPBUF 0x1c
+#define INTEL_QEPINT_STAT 0x20
+#define INTEL_QEPINT_MASK 0x24
+
+/* QEPCON */
+#define INTEL_QEPCON_EN BIT(0)
+#define INTEL_QEPCON_FLT_EN BIT(1)
+#define INTEL_QEPCON_EDGE_A BIT(2)
+#define INTEL_QEPCON_EDGE_B BIT(3)
+#define INTEL_QEPCON_EDGE_INDX BIT(4)
+#define INTEL_QEPCON_SWPAB BIT(5)
+#define INTEL_QEPCON_OP_MODE BIT(6)
+#define INTEL_QEPCON_PH_ERR BIT(7)
+#define INTEL_QEPCON_COUNT_RST_MODE BIT(8)
+#define INTEL_QEPCON_INDX_GATING_MASK GENMASK(10, 9)
+#define INTEL_QEPCON_INDX_GATING(n) (((n) & 3) << 9)
+#define INTEL_QEPCON_INDX_PAL_PBL INTEL_QEPCON_INDX_GATING(0)
+#define INTEL_QEPCON_INDX_PAL_PBH INTEL_QEPCON_INDX_GATING(1)
+#define INTEL_QEPCON_INDX_PAH_PBL INTEL_QEPCON_INDX_GATING(2)
+#define INTEL_QEPCON_INDX_PAH_PBH INTEL_QEPCON_INDX_GATING(3)
+#define INTEL_QEPCON_CAP_MODE BIT(11)
+#define INTEL_QEPCON_FIFO_THRE_MASK GENMASK(14, 12)
+#define INTEL_QEPCON_FIFO_THRE(n) ((((n) - 1) & 7) << 12)
+#define INTEL_QEPCON_FIFO_EMPTY BIT(15)
+
+/* QEPFLT */
+#define INTEL_QEPFLT_MAX_COUNT(n) ((n) & 0x1fffff)
+
+/* QEPINT */
+#define INTEL_QEPINT_FIFOCRIT BIT(5)
+#define INTEL_QEPINT_FIFOENTRY BIT(4)
+#define INTEL_QEPINT_QEPDIR BIT(3)
+#define INTEL_QEPINT_QEPRST_UP BIT(2)
+#define INTEL_QEPINT_QEPRST_DOWN BIT(1)
+#define INTEL_QEPINT_WDT BIT(0)
+
+#define INTEL_QEPINT_MASK_ALL GENMASK(5, 0)
+
+#define INTEL_QEP_CLK_PERIOD_NS 10
+
+#define INTEL_QEP_COUNTER_EXT_RW(_name) \
+{ \
+ .name = #_name, \
+ .read = _name##_read, \
+ .write = _name##_write, \
+}
+
+struct intel_qep {
+ struct counter_device counter;
+ struct mutex lock;
+ struct device *dev;
+ void __iomem *regs;
+ bool enabled;
+ /* Context save registers */
+ u32 qepcon;
+ u32 qepflt;
+ u32 qepmax;
+};
+
+static inline u32 intel_qep_readl(struct intel_qep *qep, u32 offset)
+{
+ return readl(qep->regs + offset);
+}
+
+static inline void intel_qep_writel(struct intel_qep *qep,
+ u32 offset, u32 value)
+{
+ writel(value, qep->regs + offset);
+}
+
+static void intel_qep_init(struct intel_qep *qep)
+{
+ u32 reg;
+
+ reg = intel_qep_readl(qep, INTEL_QEPCON);
+ reg &= ~INTEL_QEPCON_EN;
+ intel_qep_writel(qep, INTEL_QEPCON, reg);
+ qep->enabled = false;
+ /*
+ * Make sure peripheral is disabled by flushing the write with
+ * a dummy read
+ */
+ reg = intel_qep_readl(qep, INTEL_QEPCON);
+
+ reg &= ~(INTEL_QEPCON_OP_MODE | INTEL_QEPCON_FLT_EN);
+ reg |= INTEL_QEPCON_EDGE_A | INTEL_QEPCON_EDGE_B |
+ INTEL_QEPCON_EDGE_INDX | INTEL_QEPCON_COUNT_RST_MODE;
+ intel_qep_writel(qep, INTEL_QEPCON, reg);
+ intel_qep_writel(qep, INTEL_QEPINT_MASK, INTEL_QEPINT_MASK_ALL);
+}
+
+static int intel_qep_count_read(struct counter_device *counter,
+ struct counter_count *count,
+ unsigned long *val)
+{
+ struct intel_qep *const qep = counter->priv;
+
+ pm_runtime_get_sync(qep->dev);
+ *val = intel_qep_readl(qep, INTEL_QEPCOUNT);
+ pm_runtime_put(qep->dev);
+
+ return 0;
+}
+
+static const enum counter_count_function intel_qep_count_functions[] = {
+ COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
+};
+
+static int intel_qep_function_get(struct counter_device *counter,
+ struct counter_count *count,
+ size_t *function)
+{
+ *function = 0;
+
+ return 0;
+}
+
+static const enum counter_synapse_action intel_qep_synapse_actions[] = {
+ COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
+};
+
+static int intel_qep_action_get(struct counter_device *counter,
+ struct counter_count *count,
+ struct counter_synapse *synapse,
+ size_t *action)
+{
+ *action = 0;
+ return 0;
+}
+
+static const struct counter_ops intel_qep_counter_ops = {
+ .count_read = intel_qep_count_read,
+ .function_get = intel_qep_function_get,
+ .action_get = intel_qep_action_get,
+};
+
+#define INTEL_QEP_SIGNAL(_id, _name) { \
+ .id = (_id), \
+ .name = (_name), \
+}
+
+static struct counter_signal intel_qep_signals[] = {
+ INTEL_QEP_SIGNAL(0, "Phase A"),
+ INTEL_QEP_SIGNAL(1, "Phase B"),
+ INTEL_QEP_SIGNAL(2, "Index"),
+};
+
+#define INTEL_QEP_SYNAPSE(_signal_id) { \
+ .actions_list = intel_qep_synapse_actions, \
+ .num_actions = ARRAY_SIZE(intel_qep_synapse_actions), \
+ .signal = &intel_qep_signals[(_signal_id)], \
+}
+
+static struct counter_synapse intel_qep_count_synapses[] = {
+ INTEL_QEP_SYNAPSE(0),
+ INTEL_QEP_SYNAPSE(1),
+ INTEL_QEP_SYNAPSE(2),
+};
+
+static ssize_t ceiling_read(struct counter_device *counter,
+ struct counter_count *count,
+ void *priv, char *buf)
+{
+ struct intel_qep *qep = counter->priv;
+ u32 reg;
+
+ pm_runtime_get_sync(qep->dev);
+ reg = intel_qep_readl(qep, INTEL_QEPMAX);
+ pm_runtime_put(qep->dev);
+
+ return sysfs_emit(buf, "%u\n", reg);
+}
+
+static ssize_t ceiling_write(struct counter_device *counter,
+ struct counter_count *count,
+ void *priv, const char *buf, size_t len)
+{
+ struct intel_qep *qep = counter->priv;
+ u32 max;
+ int ret;
+
+ ret = kstrtou32(buf, 0, &max);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&qep->lock);
+ if (qep->enabled) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ pm_runtime_get_sync(qep->dev);
+ intel_qep_writel(qep, INTEL_QEPMAX, max);
+ pm_runtime_put(qep->dev);
+ ret = len;
+
+out:
+ mutex_unlock(&qep->lock);
+ return ret;
+}
+
+static ssize_t enable_read(struct counter_device *counter,
+ struct counter_count *count,
+ void *priv, char *buf)
+{
+ struct intel_qep *qep = counter->priv;
+
+ return sysfs_emit(buf, "%u\n", qep->enabled);
+}
+
+static ssize_t enable_write(struct counter_device *counter,
+ struct counter_count *count,
+ void *priv, const char *buf, size_t len)
+{
+ struct intel_qep *qep = counter->priv;
+ u32 reg;
+ bool val, changed;
+ int ret;
+
+ ret = kstrtobool(buf, &val);
+ if (ret)
+ return ret;
+
+ mutex_lock(&qep->lock);
+ changed = val ^ qep->enabled;
+ if (!changed)
+ goto out;
+
+ pm_runtime_get_sync(qep->dev);
+ reg = intel_qep_readl(qep, INTEL_QEPCON);
+ if (val) {
+ /* Enable peripheral and keep runtime PM always on */
+ reg |= INTEL_QEPCON_EN;
+ pm_runtime_get_noresume(qep->dev);
+ } else {
+ /* Let runtime PM be idle and disable peripheral */
+ pm_runtime_put_noidle(qep->dev);
+ reg &= ~INTEL_QEPCON_EN;
+ }
+ intel_qep_writel(qep, INTEL_QEPCON, reg);
+ pm_runtime_put(qep->dev);
+ qep->enabled = val;
+
+out:
+ mutex_unlock(&qep->lock);
+ return len;
+}
+
+static ssize_t spike_filter_ns_read(struct counter_device *counter,
+ struct counter_count *count,
+ void *priv, char *buf)
+{
+ struct intel_qep *qep = counter->priv;
+ u32 reg;
+
+ pm_runtime_get_sync(qep->dev);
+ reg = intel_qep_readl(qep, INTEL_QEPCON);
+ if (!(reg & INTEL_QEPCON_FLT_EN)) {
+ pm_runtime_put(qep->dev);
+ return sysfs_emit(buf, "0\n");
+ }
+ reg = INTEL_QEPFLT_MAX_COUNT(intel_qep_readl(qep, INTEL_QEPFLT));
+ pm_runtime_put(qep->dev);
+
+ return sysfs_emit(buf, "%u\n", (reg + 2) * INTEL_QEP_CLK_PERIOD_NS);
+}
+
+static ssize_t spike_filter_ns_write(struct counter_device *counter,
+ struct counter_count *count,
+ void *priv, const char *buf, size_t len)
+{
+ struct intel_qep *qep = counter->priv;
+ u32 reg, length;
+ bool enable;
+ int ret;
+
+ ret = kstrtou32(buf, 0, &length);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Spike filter length is (MAX_COUNT + 2) clock periods.
+ * Disable filter when userspace writes 0, enable for valid
+ * nanoseconds values and error out otherwise.
+ */
+ length /= INTEL_QEP_CLK_PERIOD_NS;
+ if (length == 0) {
+ enable = false;
+ length = 0;
+ } else if (length >= 2) {
+ enable = true;
+ length -= 2;
+ } else {
+ return -EINVAL;
+ }
+
+ if (length > INTEL_QEPFLT_MAX_COUNT(length))
+ return -EINVAL;
+
+ mutex_lock(&qep->lock);
+ if (qep->enabled) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ pm_runtime_get_sync(qep->dev);
+ reg = intel_qep_readl(qep, INTEL_QEPCON);
+ if (enable)
+ reg |= INTEL_QEPCON_FLT_EN;
+ else
+ reg &= ~INTEL_QEPCON_FLT_EN;
+ intel_qep_writel(qep, INTEL_QEPFLT, length);
+ intel_qep_writel(qep, INTEL_QEPCON, reg);
+ pm_runtime_put(qep->dev);
+ ret = len;
+
+out:
+ mutex_unlock(&qep->lock);
+ return ret;
+}
+
+static ssize_t preset_enable_read(struct counter_device *counter,
+ struct counter_count *count,
+ void *priv, char *buf)
+{
+ struct intel_qep *qep = counter->priv;
+ u32 reg;
+
+ pm_runtime_get_sync(qep->dev);
+ reg = intel_qep_readl(qep, INTEL_QEPCON);
+ pm_runtime_put(qep->dev);
+ return sysfs_emit(buf, "%u\n", !(reg & INTEL_QEPCON_COUNT_RST_MODE));
+}
+
+static ssize_t preset_enable_write(struct counter_device *counter,
+ struct counter_count *count,
+ void *priv, const char *buf, size_t len)
+{
+ struct intel_qep *qep = counter->priv;
+ u32 reg;
+ bool val;
+ int ret;
+
+ ret = kstrtobool(buf, &val);
+ if (ret)
+ return ret;
+
+ mutex_lock(&qep->lock);
+ if (qep->enabled) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ pm_runtime_get_sync(qep->dev);
+ reg = intel_qep_readl(qep, INTEL_QEPCON);
+ if (val)
+ reg &= ~INTEL_QEPCON_COUNT_RST_MODE;
+ else
+ reg |= INTEL_QEPCON_COUNT_RST_MODE;
+
+ intel_qep_writel(qep, INTEL_QEPCON, reg);
+ pm_runtime_put(qep->dev);
+ ret = len;
+
+out:
+ mutex_unlock(&qep->lock);
+
+ return ret;
+}
+
+static const struct counter_count_ext intel_qep_count_ext[] = {
+ INTEL_QEP_COUNTER_EXT_RW(ceiling),
+ INTEL_QEP_COUNTER_EXT_RW(enable),
+ INTEL_QEP_COUNTER_EXT_RW(spike_filter_ns),
+ INTEL_QEP_COUNTER_EXT_RW(preset_enable)
+};
+
+static struct counter_count intel_qep_counter_count[] = {
+ {
+ .id = 0,
+ .name = "Channel 1 Count",
+ .functions_list = intel_qep_count_functions,
+ .num_functions = ARRAY_SIZE(intel_qep_count_functions),
+ .synapses = intel_qep_count_synapses,
+ .num_synapses = ARRAY_SIZE(intel_qep_count_synapses),
+ .ext = intel_qep_count_ext,
+ .num_ext = ARRAY_SIZE(intel_qep_count_ext),
+ },
+};
+
+static int intel_qep_probe(struct pci_dev *pci, const struct pci_device_id *id)
+{
+ struct intel_qep *qep;
+ struct device *dev = &pci->dev;
+ void __iomem *regs;
+ int ret;
+
+ qep = devm_kzalloc(dev, sizeof(*qep), GFP_KERNEL);
+ if (!qep)
+ return -ENOMEM;
+
+ ret = pcim_enable_device(pci);
+ if (ret)
+ return ret;
+
+ pci_set_master(pci);
+
+ ret = pcim_iomap_regions(pci, BIT(0), pci_name(pci));
+ if (ret)
+ return ret;
+
+ regs = pcim_iomap_table(pci)[0];
+ if (!regs)
+ return -ENOMEM;
+
+ qep->dev = dev;
+ qep->regs = regs;
+ mutex_init(&qep->lock);
+
+ intel_qep_init(qep);
+ pci_set_drvdata(pci, qep);
+
+ qep->counter.name = pci_name(pci);
+ qep->counter.parent = dev;
+ qep->counter.ops = &intel_qep_counter_ops;
+ qep->counter.counts = intel_qep_counter_count;
+ qep->counter.num_counts = ARRAY_SIZE(intel_qep_counter_count);
+ qep->counter.signals = intel_qep_signals;
+ qep->counter.num_signals = ARRAY_SIZE(intel_qep_signals);
+ qep->counter.priv = qep;
+ qep->enabled = false;
+
+ pm_runtime_put(dev);
+ pm_runtime_allow(dev);
+
+ return devm_counter_register(&pci->dev, &qep->counter);
+}
+
+static void intel_qep_remove(struct pci_dev *pci)
+{
+ struct intel_qep *qep = pci_get_drvdata(pci);
+ struct device *dev = &pci->dev;
+
+ pm_runtime_forbid(dev);
+ if (!qep->enabled)
+ pm_runtime_get(dev);
+
+ intel_qep_writel(qep, INTEL_QEPCON, 0);
+}
+
+static int __maybe_unused intel_qep_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct intel_qep *qep = pci_get_drvdata(pdev);
+
+ qep->qepcon = intel_qep_readl(qep, INTEL_QEPCON);
+ qep->qepflt = intel_qep_readl(qep, INTEL_QEPFLT);
+ qep->qepmax = intel_qep_readl(qep, INTEL_QEPMAX);
+
+ return 0;
+}
+
+static int __maybe_unused intel_qep_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct intel_qep *qep = pci_get_drvdata(pdev);
+
+ /*
+ * Make sure peripheral is disabled when restoring registers and
+ * control register bits that are writable only when the peripheral
+ * is disabled
+ */
+ intel_qep_writel(qep, INTEL_QEPCON, 0);
+ intel_qep_readl(qep, INTEL_QEPCON);
+
+ intel_qep_writel(qep, INTEL_QEPFLT, qep->qepflt);
+ intel_qep_writel(qep, INTEL_QEPMAX, qep->qepmax);
+ intel_qep_writel(qep, INTEL_QEPINT_MASK, INTEL_QEPINT_MASK_ALL);
+
+ /* Restore all other control register bits except enable status */
+ intel_qep_writel(qep, INTEL_QEPCON, qep->qepcon & ~INTEL_QEPCON_EN);
+ intel_qep_readl(qep, INTEL_QEPCON);
+
+ /* Restore enable status */
+ intel_qep_writel(qep, INTEL_QEPCON, qep->qepcon);
+
+ return 0;
+}
+
+static UNIVERSAL_DEV_PM_OPS(intel_qep_pm_ops,
+ intel_qep_suspend, intel_qep_resume, NULL);
+
+static const struct pci_device_id intel_qep_id_table[] = {
+ /* EHL */
+ { PCI_VDEVICE(INTEL, 0x4bc3), },
+ { PCI_VDEVICE(INTEL, 0x4b81), },
+ { PCI_VDEVICE(INTEL, 0x4b82), },
+ { PCI_VDEVICE(INTEL, 0x4b83), },
+ { } /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(pci, intel_qep_id_table);
+
+static struct pci_driver intel_qep_driver = {
+ .name = "intel-qep",
+ .id_table = intel_qep_id_table,
+ .probe = intel_qep_probe,
+ .remove = intel_qep_remove,
+ .driver = {
+ .pm = &intel_qep_pm_ops,
+ }
+};
+
+module_pci_driver(intel_qep_driver);
+
+MODULE_AUTHOR("Felipe Balbi (Intel)");
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
+MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel Quadrature Encoder Peripheral driver");
diff --git a/drivers/counter/interrupt-cnt.c b/drivers/counter/interrupt-cnt.c
index a99ee7996977..5df7cd13d4c7 100644
--- a/drivers/counter/interrupt-cnt.c
+++ b/drivers/counter/interrupt-cnt.c
@@ -77,7 +77,7 @@ static const struct counter_count_ext interrupt_cnt_ext[] = {
},
};
-static enum counter_synapse_action interrupt_cnt_synapse_actionss[] = {
+static const enum counter_synapse_action interrupt_cnt_synapse_actions[] = {
COUNTER_SYNAPSE_ACTION_RISING_EDGE,
};
@@ -112,7 +112,7 @@ static int interrupt_cnt_write(struct counter_device *counter,
return 0;
}
-static enum counter_count_function interrupt_cnt_functions[] = {
+static const enum counter_count_function interrupt_cnt_functions[] = {
COUNTER_COUNT_FUNCTION_INCREASE,
};
@@ -194,8 +194,8 @@ static int interrupt_cnt_probe(struct platform_device *pdev)
priv->counter.signals = &priv->signals;
priv->counter.num_signals = 1;
- priv->synapses.actions_list = interrupt_cnt_synapse_actionss;
- priv->synapses.num_actions = ARRAY_SIZE(interrupt_cnt_synapse_actionss);
+ priv->synapses.actions_list = interrupt_cnt_synapse_actions;
+ priv->synapses.num_actions = ARRAY_SIZE(interrupt_cnt_synapse_actions);
priv->synapses.signal = &priv->signals;
priv->cnts.name = "Channel 0 Count";
diff --git a/drivers/counter/microchip-tcb-capture.c b/drivers/counter/microchip-tcb-capture.c
index 710acc0a3704..51b8af80f98b 100644
--- a/drivers/counter/microchip-tcb-capture.c
+++ b/drivers/counter/microchip-tcb-capture.c
@@ -37,7 +37,7 @@ enum mchp_tc_count_function {
MCHP_TC_FUNCTION_QUADRATURE,
};
-static enum counter_count_function mchp_tc_count_functions[] = {
+static const enum counter_count_function mchp_tc_count_functions[] = {
[MCHP_TC_FUNCTION_INCREASE] = COUNTER_COUNT_FUNCTION_INCREASE,
[MCHP_TC_FUNCTION_QUADRATURE] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
};
@@ -49,7 +49,7 @@ enum mchp_tc_synapse_action {
MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE
};
-static enum counter_synapse_action mchp_tc_synapse_actions[] = {
+static const enum counter_synapse_action mchp_tc_synapse_actions[] = {
[MCHP_TC_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
[MCHP_TC_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE,
[MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
diff --git a/drivers/counter/stm32-lptimer-cnt.c b/drivers/counter/stm32-lptimer-cnt.c
index 937439635d53..c19d998df5ba 100644
--- a/drivers/counter/stm32-lptimer-cnt.c
+++ b/drivers/counter/stm32-lptimer-cnt.c
@@ -134,7 +134,7 @@ enum stm32_lptim_cnt_function {
STM32_LPTIM_ENCODER_BOTH_EDGE,
};
-static enum counter_count_function stm32_lptim_cnt_functions[] = {
+static const enum counter_count_function stm32_lptim_cnt_functions[] = {
[STM32_LPTIM_COUNTER_INCREASE] = COUNTER_COUNT_FUNCTION_INCREASE,
[STM32_LPTIM_ENCODER_BOTH_EDGE] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
};
@@ -146,7 +146,7 @@ enum stm32_lptim_synapse_action {
STM32_LPTIM_SYNAPSE_ACTION_NONE,
};
-static enum counter_synapse_action stm32_lptim_cnt_synapse_actions[] = {
+static const enum counter_synapse_action stm32_lptim_cnt_synapse_actions[] = {
/* Index must match with stm32_lptim_cnt_polarity[] (priv->polarity) */
[STM32_LPTIM_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE,
[STM32_LPTIM_SYNAPSE_ACTION_FALLING_EDGE] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c
index 75bc401fdd18..603b30ada839 100644
--- a/drivers/counter/stm32-timer-cnt.c
+++ b/drivers/counter/stm32-timer-cnt.c
@@ -50,7 +50,7 @@ enum stm32_count_function {
STM32_COUNT_ENCODER_MODE_3,
};
-static enum counter_count_function stm32_count_functions[] = {
+static const enum counter_count_function stm32_count_functions[] = {
[STM32_COUNT_SLAVE_MODE_DISABLED] = COUNTER_COUNT_FUNCTION_INCREASE,
[STM32_COUNT_ENCODER_MODE_1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A,
[STM32_COUNT_ENCODER_MODE_2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_B,
@@ -267,7 +267,7 @@ enum stm32_synapse_action {
STM32_SYNAPSE_ACTION_BOTH_EDGES
};
-static enum counter_synapse_action stm32_synapse_actions[] = {
+static const enum counter_synapse_action stm32_synapse_actions[] = {
[STM32_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
[STM32_SYNAPSE_ACTION_BOTH_EDGES] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES
};
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index e65e0a43be64..a5c5f70acfc9 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -19,6 +19,16 @@ config ACPI_CPPC_CPUFREQ
If in doubt, say N.
+config ACPI_CPPC_CPUFREQ_FIE
+ bool "Frequency Invariance support for CPPC cpufreq driver"
+ depends on ACPI_CPPC_CPUFREQ && GENERIC_ARCH_TOPOLOGY
+ default y
+ help
+ This extends frequency invariance support in the CPPC cpufreq driver,
+ by using CPPC delivered and reference performance counters.
+
+ If in doubt, say N.
+
config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM
tristate "Allwinner nvmem based SUN50I CPUFreq driver"
depends on ARCH_SUNXI
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 2f769b1630c5..d4c27022b9c9 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -10,14 +10,18 @@
#define pr_fmt(fmt) "CPPC Cpufreq:" fmt
+#include <linux/arch_topology.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/dmi.h>
+#include <linux/irq_work.h>
+#include <linux/kthread.h>
#include <linux/time.h>
#include <linux/vmalloc.h>
+#include <uapi/linux/sched/types.h>
#include <asm/unaligned.h>
@@ -57,6 +61,216 @@ static struct cppc_workaround_oem_info wa_info[] = {
}
};
+#ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE
+
+/* Frequency invariance support */
+struct cppc_freq_invariance {
+ int cpu;
+ struct irq_work irq_work;
+ struct kthread_work work;
+ struct cppc_perf_fb_ctrs prev_perf_fb_ctrs;
+ struct cppc_cpudata *cpu_data;
+};
+
+static DEFINE_PER_CPU(struct cppc_freq_invariance, cppc_freq_inv);
+static struct kthread_worker *kworker_fie;
+
+static struct cpufreq_driver cppc_cpufreq_driver;
+static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpu);
+static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data,
+ struct cppc_perf_fb_ctrs *fb_ctrs_t0,
+ struct cppc_perf_fb_ctrs *fb_ctrs_t1);
+
+/**
+ * cppc_scale_freq_workfn - CPPC arch_freq_scale updater for frequency invariance
+ * @work: The work item.
+ *
+ * The CPPC driver register itself with the topology core to provide its own
+ * implementation (cppc_scale_freq_tick()) of topology_scale_freq_tick() which
+ * gets called by the scheduler on every tick.
+ *
+ * Note that the arch specific counters have higher priority than CPPC counters,
+ * if available, though the CPPC driver doesn't need to have any special
+ * handling for that.
+ *
+ * On an invocation of cppc_scale_freq_tick(), we schedule an irq work (since we
+ * reach here from hard-irq context), which then schedules a normal work item
+ * and cppc_scale_freq_workfn() updates the per_cpu arch_freq_scale variable
+ * based on the counter updates since the last tick.
+ */
+static void cppc_scale_freq_workfn(struct kthread_work *work)
+{
+ struct cppc_freq_invariance *cppc_fi;
+ struct cppc_perf_fb_ctrs fb_ctrs = {0};
+ struct cppc_cpudata *cpu_data;
+ unsigned long local_freq_scale;
+ u64 perf;
+
+ cppc_fi = container_of(work, struct cppc_freq_invariance, work);
+ cpu_data = cppc_fi->cpu_data;
+
+ if (cppc_get_perf_ctrs(cppc_fi->cpu, &fb_ctrs)) {
+ pr_warn("%s: failed to read perf counters\n", __func__);
+ return;
+ }
+
+ perf = cppc_perf_from_fbctrs(cpu_data, &cppc_fi->prev_perf_fb_ctrs,
+ &fb_ctrs);
+ cppc_fi->prev_perf_fb_ctrs = fb_ctrs;
+
+ perf <<= SCHED_CAPACITY_SHIFT;
+ local_freq_scale = div64_u64(perf, cpu_data->perf_caps.highest_perf);
+
+ /* This can happen due to counter's overflow */
+ if (unlikely(local_freq_scale > 1024))
+ local_freq_scale = 1024;
+
+ per_cpu(arch_freq_scale, cppc_fi->cpu) = local_freq_scale;
+}
+
+static void cppc_irq_work(struct irq_work *irq_work)
+{
+ struct cppc_freq_invariance *cppc_fi;
+
+ cppc_fi = container_of(irq_work, struct cppc_freq_invariance, irq_work);
+ kthread_queue_work(kworker_fie, &cppc_fi->work);
+}
+
+static void cppc_scale_freq_tick(void)
+{
+ struct cppc_freq_invariance *cppc_fi = &per_cpu(cppc_freq_inv, smp_processor_id());
+
+ /*
+ * cppc_get_perf_ctrs() can potentially sleep, call that from the right
+ * context.
+ */
+ irq_work_queue(&cppc_fi->irq_work);
+}
+
+static struct scale_freq_data cppc_sftd = {
+ .source = SCALE_FREQ_SOURCE_CPPC,
+ .set_freq_scale = cppc_scale_freq_tick,
+};
+
+static void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy)
+{
+ struct cppc_freq_invariance *cppc_fi;
+ int cpu, ret;
+
+ if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
+ return;
+
+ for_each_cpu(cpu, policy->cpus) {
+ cppc_fi = &per_cpu(cppc_freq_inv, cpu);
+ cppc_fi->cpu = cpu;
+ cppc_fi->cpu_data = policy->driver_data;
+ kthread_init_work(&cppc_fi->work, cppc_scale_freq_workfn);
+ init_irq_work(&cppc_fi->irq_work, cppc_irq_work);
+
+ ret = cppc_get_perf_ctrs(cpu, &cppc_fi->prev_perf_fb_ctrs);
+ if (ret) {
+ pr_warn("%s: failed to read perf counters for cpu:%d: %d\n",
+ __func__, cpu, ret);
+
+ /*
+ * Don't abort if the CPU was offline while the driver
+ * was getting registered.
+ */
+ if (cpu_online(cpu))
+ return;
+ }
+ }
+
+ /* Register for freq-invariance */
+ topology_set_scale_freq_source(&cppc_sftd, policy->cpus);
+}
+
+/*
+ * We free all the resources on policy's removal and not on CPU removal as the
+ * irq-work are per-cpu and the hotplug core takes care of flushing the pending
+ * irq-works (hint: smpcfd_dying_cpu()) on CPU hotplug. Even if the kthread-work
+ * fires on another CPU after the concerned CPU is removed, it won't harm.
+ *
+ * We just need to make sure to remove them all on policy->exit().
+ */
+static void cppc_cpufreq_cpu_fie_exit(struct cpufreq_policy *policy)
+{
+ struct cppc_freq_invariance *cppc_fi;
+ int cpu;
+
+ if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
+ return;
+
+ /* policy->cpus will be empty here, use related_cpus instead */
+ topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_CPPC, policy->related_cpus);
+
+ for_each_cpu(cpu, policy->related_cpus) {
+ cppc_fi = &per_cpu(cppc_freq_inv, cpu);
+ irq_work_sync(&cppc_fi->irq_work);
+ kthread_cancel_work_sync(&cppc_fi->work);
+ }
+}
+
+static void __init cppc_freq_invariance_init(void)
+{
+ struct sched_attr attr = {
+ .size = sizeof(struct sched_attr),
+ .sched_policy = SCHED_DEADLINE,
+ .sched_nice = 0,
+ .sched_priority = 0,
+ /*
+ * Fake (unused) bandwidth; workaround to "fix"
+ * priority inheritance.
+ */
+ .sched_runtime = 1000000,
+ .sched_deadline = 10000000,
+ .sched_period = 10000000,
+ };
+ int ret;
+
+ if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
+ return;
+
+ kworker_fie = kthread_create_worker(0, "cppc_fie");
+ if (IS_ERR(kworker_fie))
+ return;
+
+ ret = sched_setattr_nocheck(kworker_fie->task, &attr);
+ if (ret) {
+ pr_warn("%s: failed to set SCHED_DEADLINE: %d\n", __func__,
+ ret);
+ kthread_destroy_worker(kworker_fie);
+ return;
+ }
+}
+
+static void cppc_freq_invariance_exit(void)
+{
+ if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
+ return;
+
+ kthread_destroy_worker(kworker_fie);
+ kworker_fie = NULL;
+}
+
+#else
+static inline void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy)
+{
+}
+
+static inline void cppc_cpufreq_cpu_fie_exit(struct cpufreq_policy *policy)
+{
+}
+
+static inline void cppc_freq_invariance_init(void)
+{
+}
+
+static inline void cppc_freq_invariance_exit(void)
+{
+}
+#endif /* CONFIG_ACPI_CPPC_CPUFREQ_FIE */
+
/* Callback function used to retrieve the max frequency from DMI */
static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private)
{
@@ -182,27 +396,6 @@ static int cppc_verify_policy(struct cpufreq_policy_data *policy)
return 0;
}
-static void cppc_cpufreq_stop_cpu(struct cpufreq_policy *policy)
-{
- struct cppc_cpudata *cpu_data = policy->driver_data;
- struct cppc_perf_caps *caps = &cpu_data->perf_caps;
- unsigned int cpu = policy->cpu;
- int ret;
-
- cpu_data->perf_ctrls.desired_perf = caps->lowest_perf;
-
- ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
- if (ret)
- pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
- caps->lowest_perf, cpu, ret);
-
- /* Remove CPU node from list and free driver data for policy */
- free_cpumask_var(cpu_data->shared_cpu_map);
- list_del(&cpu_data->node);
- kfree(policy->driver_data);
- policy->driver_data = NULL;
-}
-
/*
* The PCC subspace describes the rate at which platform can accept commands
* on the shared PCC channel (including READs which do not count towards freq
@@ -277,6 +470,16 @@ out:
return NULL;
}
+static void cppc_cpufreq_put_cpu_data(struct cpufreq_policy *policy)
+{
+ struct cppc_cpudata *cpu_data = policy->driver_data;
+
+ list_del(&cpu_data->node);
+ free_cpumask_var(cpu_data->shared_cpu_map);
+ kfree(cpu_data);
+ policy->driver_data = NULL;
+}
+
static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
unsigned int cpu = policy->cpu;
@@ -330,7 +533,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
default:
pr_debug("Unsupported CPU co-ord type: %d\n",
policy->shared_type);
- return -EFAULT;
+ ret = -EFAULT;
+ goto out;
}
/*
@@ -345,13 +549,40 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
cpu_data->perf_ctrls.desired_perf = caps->highest_perf;
ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
- if (ret)
+ if (ret) {
pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
caps->highest_perf, cpu, ret);
+ goto out;
+ }
+
+ cppc_cpufreq_cpu_fie_init(policy);
+ return 0;
+out:
+ cppc_cpufreq_put_cpu_data(policy);
return ret;
}
+static int cppc_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+ struct cppc_cpudata *cpu_data = policy->driver_data;
+ struct cppc_perf_caps *caps = &cpu_data->perf_caps;
+ unsigned int cpu = policy->cpu;
+ int ret;
+
+ cppc_cpufreq_cpu_fie_exit(policy);
+
+ cpu_data->perf_ctrls.desired_perf = caps->lowest_perf;
+
+ ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
+ if (ret)
+ pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
+ caps->lowest_perf, cpu, ret);
+
+ cppc_cpufreq_put_cpu_data(policy);
+ return 0;
+}
+
static inline u64 get_delta(u64 t1, u64 t0)
{
if (t1 > t0 || t0 > ~(u32)0)
@@ -360,28 +591,25 @@ static inline u64 get_delta(u64 t1, u64 t0)
return (u32)t1 - (u32)t0;
}
-static int cppc_get_rate_from_fbctrs(struct cppc_cpudata *cpu_data,
- struct cppc_perf_fb_ctrs fb_ctrs_t0,
- struct cppc_perf_fb_ctrs fb_ctrs_t1)
+static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data,
+ struct cppc_perf_fb_ctrs *fb_ctrs_t0,
+ struct cppc_perf_fb_ctrs *fb_ctrs_t1)
{
u64 delta_reference, delta_delivered;
- u64 reference_perf, delivered_perf;
+ u64 reference_perf;
- reference_perf = fb_ctrs_t0.reference_perf;
+ reference_perf = fb_ctrs_t0->reference_perf;
- delta_reference = get_delta(fb_ctrs_t1.reference,
- fb_ctrs_t0.reference);
- delta_delivered = get_delta(fb_ctrs_t1.delivered,
- fb_ctrs_t0.delivered);
+ delta_reference = get_delta(fb_ctrs_t1->reference,
+ fb_ctrs_t0->reference);
+ delta_delivered = get_delta(fb_ctrs_t1->delivered,
+ fb_ctrs_t0->delivered);
- /* Check to avoid divide-by zero */
- if (delta_reference || delta_delivered)
- delivered_perf = (reference_perf * delta_delivered) /
- delta_reference;
- else
- delivered_perf = cpu_data->perf_ctrls.desired_perf;
+ /* Check to avoid divide-by zero and invalid delivered_perf */
+ if (!delta_reference || !delta_delivered)
+ return cpu_data->perf_ctrls.desired_perf;
- return cppc_cpufreq_perf_to_khz(cpu_data, delivered_perf);
+ return (reference_perf * delta_delivered) / delta_reference;
}
static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
@@ -389,6 +617,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0};
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
struct cppc_cpudata *cpu_data = policy->driver_data;
+ u64 delivered_perf;
int ret;
cpufreq_cpu_put(policy);
@@ -403,7 +632,10 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
if (ret)
return ret;
- return cppc_get_rate_from_fbctrs(cpu_data, fb_ctrs_t0, fb_ctrs_t1);
+ delivered_perf = cppc_perf_from_fbctrs(cpu_data, &fb_ctrs_t0,
+ &fb_ctrs_t1);
+
+ return cppc_cpufreq_perf_to_khz(cpu_data, delivered_perf);
}
static int cppc_cpufreq_set_boost(struct cpufreq_policy *policy, int state)
@@ -451,7 +683,7 @@ static struct cpufreq_driver cppc_cpufreq_driver = {
.target = cppc_cpufreq_set_target,
.get = cppc_cpufreq_get_rate,
.init = cppc_cpufreq_cpu_init,
- .stop_cpu = cppc_cpufreq_stop_cpu,
+ .exit = cppc_cpufreq_cpu_exit,
.set_boost = cppc_cpufreq_set_boost,
.attr = cppc_cpufreq_attr,
.name = "cppc_cpufreq",
@@ -504,14 +736,21 @@ static void cppc_check_hisi_workaround(void)
static int __init cppc_cpufreq_init(void)
{
+ int ret;
+
if ((acpi_disabled) || !acpi_cpc_valid())
return -ENODEV;
INIT_LIST_HEAD(&cpu_data_list);
cppc_check_hisi_workaround();
+ cppc_freq_invariance_init();
+
+ ret = cpufreq_register_driver(&cppc_cpufreq_driver);
+ if (ret)
+ cppc_freq_invariance_exit();
- return cpufreq_register_driver(&cppc_cpufreq_driver);
+ return ret;
}
static inline void free_cpu_data(void)
@@ -529,6 +768,7 @@ static inline void free_cpu_data(void)
static void __exit cppc_cpufreq_exit(void)
{
cpufreq_unregister_driver(&cppc_cpufreq_driver);
+ cppc_freq_invariance_exit();
free_cpu_data();
}
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index 5e07065ec22f..bef7528aecd3 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -15,7 +15,7 @@
* Machines for which the cpufreq device is *always* created, mostly used for
* platforms using "operating-points" (V1) property.
*/
-static const struct of_device_id whitelist[] __initconst = {
+static const struct of_device_id allowlist[] __initconst = {
{ .compatible = "allwinner,sun4i-a10", },
{ .compatible = "allwinner,sun5i-a10s", },
{ .compatible = "allwinner,sun5i-a13", },
@@ -100,7 +100,7 @@ static const struct of_device_id whitelist[] __initconst = {
* Machines for which the cpufreq device is *not* created, mostly used for
* platforms using "operating-points-v2" property.
*/
-static const struct of_device_id blacklist[] __initconst = {
+static const struct of_device_id blocklist[] __initconst = {
{ .compatible = "allwinner,sun50i-h6", },
{ .compatible = "arm,vexpress", },
@@ -126,6 +126,7 @@ static const struct of_device_id blacklist[] __initconst = {
{ .compatible = "mediatek,mt8173", },
{ .compatible = "mediatek,mt8176", },
{ .compatible = "mediatek,mt8183", },
+ { .compatible = "mediatek,mt8365", },
{ .compatible = "mediatek,mt8516", },
{ .compatible = "nvidia,tegra20", },
@@ -137,6 +138,7 @@ static const struct of_device_id blacklist[] __initconst = {
{ .compatible = "qcom,msm8996", },
{ .compatible = "qcom,qcs404", },
{ .compatible = "qcom,sc7180", },
+ { .compatible = "qcom,sc7280", },
{ .compatible = "qcom,sdm845", },
{ .compatible = "st,stih407", },
@@ -177,13 +179,13 @@ static int __init cpufreq_dt_platdev_init(void)
if (!np)
return -ENODEV;
- match = of_match_node(whitelist, np);
+ match = of_match_node(allowlist, np);
if (match) {
data = match->data;
goto create_pdev;
}
- if (cpu0_node_has_opp_v2_prop() && !of_match_node(blacklist, np))
+ if (cpu0_node_has_opp_v2_prop() && !of_match_node(blocklist, np))
goto create_pdev;
of_node_put(np);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 802abc925b2a..45f3416988f1 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -524,6 +524,22 @@ void cpufreq_disable_fast_switch(struct cpufreq_policy *policy)
}
EXPORT_SYMBOL_GPL(cpufreq_disable_fast_switch);
+static unsigned int __resolve_freq(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
+{
+ unsigned int idx;
+
+ target_freq = clamp_val(target_freq, policy->min, policy->max);
+
+ if (!cpufreq_driver->target_index)
+ return target_freq;
+
+ idx = cpufreq_frequency_table_target(policy, target_freq, relation);
+ policy->cached_resolved_idx = idx;
+ policy->cached_target_freq = target_freq;
+ return policy->freq_table[idx].frequency;
+}
+
/**
* cpufreq_driver_resolve_freq - Map a target frequency to a driver-supported
* one.
@@ -538,22 +554,7 @@ EXPORT_SYMBOL_GPL(cpufreq_disable_fast_switch);
unsigned int cpufreq_driver_resolve_freq(struct cpufreq_policy *policy,
unsigned int target_freq)
{
- target_freq = clamp_val(target_freq, policy->min, policy->max);
- policy->cached_target_freq = target_freq;
-
- if (cpufreq_driver->target_index) {
- unsigned int idx;
-
- idx = cpufreq_frequency_table_target(policy, target_freq,
- CPUFREQ_RELATION_L);
- policy->cached_resolved_idx = idx;
- return policy->freq_table[idx].frequency;
- }
-
- if (cpufreq_driver->resolve_freq)
- return cpufreq_driver->resolve_freq(policy, target_freq);
-
- return target_freq;
+ return __resolve_freq(policy, target_freq, CPUFREQ_RELATION_L);
}
EXPORT_SYMBOL_GPL(cpufreq_driver_resolve_freq);
@@ -1367,9 +1368,14 @@ static int cpufreq_online(unsigned int cpu)
goto out_free_policy;
}
+ /*
+ * The initialization has succeeded and the policy is online.
+ * If there is a problem with its frequency table, take it
+ * offline and drop it.
+ */
ret = cpufreq_table_validate_and_sort(policy);
if (ret)
- goto out_exit_policy;
+ goto out_offline_policy;
/* related_cpus should at least include policy->cpus. */
cpumask_copy(policy->related_cpus, policy->cpus);
@@ -1515,6 +1521,10 @@ out_destroy_policy:
up_write(&policy->rwsem);
+out_offline_policy:
+ if (cpufreq_driver->offline)
+ cpufreq_driver->offline(policy);
+
out_exit_policy:
if (cpufreq_driver->exit)
cpufreq_driver->exit(policy);
@@ -1597,9 +1607,6 @@ static int cpufreq_offline(unsigned int cpu)
policy->cdev = NULL;
}
- if (cpufreq_driver->stop_cpu)
- cpufreq_driver->stop_cpu(policy);
-
if (has_target())
cpufreq_exit_governor(policy);
@@ -2225,13 +2232,11 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int relation)
{
unsigned int old_target_freq = target_freq;
- int index;
if (cpufreq_disabled())
return -ENODEV;
- /* Make sure that target_freq is within supported range */
- target_freq = clamp_val(target_freq, policy->min, policy->max);
+ target_freq = __resolve_freq(policy, target_freq, relation);
pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n",
policy->cpu, target_freq, relation, old_target_freq);
@@ -2252,9 +2257,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
if (!cpufreq_driver->target_index)
return -EINVAL;
- index = cpufreq_frequency_table_target(policy, target_freq, relation);
-
- return __target_index(policy, index);
+ return __target_index(policy, policy->cached_resolved_idx);
}
EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index da717f7cd9a9..1570d6f3e75d 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -211,7 +211,7 @@ void cpufreq_stats_free_table(struct cpufreq_policy *policy)
void cpufreq_stats_create_table(struct cpufreq_policy *policy)
{
- unsigned int i = 0, count = 0, ret = -ENOMEM;
+ unsigned int i = 0, count;
struct cpufreq_stats *stats;
unsigned int alloc_size;
struct cpufreq_frequency_table *pos;
@@ -253,8 +253,7 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy)
stats->last_index = freq_table_get_index(stats, policy->cur);
policy->stats = stats;
- ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
- if (!ret)
+ if (!sysfs_create_group(&policy->kobj, &stats_attr_group))
return;
/* We failed, release resources */
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 0e69dffd5a76..bb4549959b11 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -121,9 +121,10 @@ struct sample {
* @max_pstate_physical:This is physical Max P state for a processor
* This can be higher than the max_pstate which can
* be limited by platform thermal design power limits
- * @scaling: Scaling factor to convert frequency to cpufreq
- * frequency units
+ * @perf_ctl_scaling: PERF_CTL P-state to frequency scaling factor
+ * @scaling: Scaling factor between performance and frequency
* @turbo_pstate: Max Turbo P state possible for this platform
+ * @min_freq: @min_pstate frequency in cpufreq units
* @max_freq: @max_pstate frequency in cpufreq units
* @turbo_freq: @turbo_pstate frequency in cpufreq units
*
@@ -134,8 +135,10 @@ struct pstate_data {
int min_pstate;
int max_pstate;
int max_pstate_physical;
+ int perf_ctl_scaling;
int scaling;
int turbo_pstate;
+ unsigned int min_freq;
unsigned int max_freq;
unsigned int turbo_freq;
};
@@ -366,7 +369,7 @@ static void intel_pstate_set_itmt_prio(int cpu)
}
}
-static int intel_pstate_get_cppc_guranteed(int cpu)
+static int intel_pstate_get_cppc_guaranteed(int cpu)
{
struct cppc_perf_caps cppc_perf;
int ret;
@@ -382,7 +385,7 @@ static int intel_pstate_get_cppc_guranteed(int cpu)
}
#else /* CONFIG_ACPI_CPPC_LIB */
-static void intel_pstate_set_itmt_prio(int cpu)
+static inline void intel_pstate_set_itmt_prio(int cpu)
{
}
#endif /* CONFIG_ACPI_CPPC_LIB */
@@ -467,6 +470,20 @@ static void intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
acpi_processor_unregister_performance(policy->cpu);
}
+
+static bool intel_pstate_cppc_perf_valid(u32 perf, struct cppc_perf_caps *caps)
+{
+ return perf && perf <= caps->highest_perf && perf >= caps->lowest_perf;
+}
+
+static bool intel_pstate_cppc_perf_caps(struct cpudata *cpu,
+ struct cppc_perf_caps *caps)
+{
+ if (cppc_get_perf_caps(cpu->cpu, caps))
+ return false;
+
+ return caps->highest_perf && caps->lowest_perf <= caps->highest_perf;
+}
#else /* CONFIG_ACPI */
static inline void intel_pstate_init_acpi_perf_limits(struct cpufreq_policy *policy)
{
@@ -483,12 +500,146 @@ static inline bool intel_pstate_acpi_pm_profile_server(void)
#endif /* CONFIG_ACPI */
#ifndef CONFIG_ACPI_CPPC_LIB
-static int intel_pstate_get_cppc_guranteed(int cpu)
+static inline int intel_pstate_get_cppc_guaranteed(int cpu)
{
return -ENOTSUPP;
}
#endif /* CONFIG_ACPI_CPPC_LIB */
+static void intel_pstate_hybrid_hwp_perf_ctl_parity(struct cpudata *cpu)
+{
+ pr_debug("CPU%d: Using PERF_CTL scaling for HWP\n", cpu->cpu);
+
+ cpu->pstate.scaling = cpu->pstate.perf_ctl_scaling;
+}
+
+/**
+ * intel_pstate_hybrid_hwp_calibrate - Calibrate HWP performance levels.
+ * @cpu: Target CPU.
+ *
+ * On hybrid processors, HWP may expose more performance levels than there are
+ * P-states accessible through the PERF_CTL interface. If that happens, the
+ * scaling factor between HWP performance levels and CPU frequency will be less
+ * than the scaling factor between P-state values and CPU frequency.
+ *
+ * In that case, the scaling factor between HWP performance levels and CPU
+ * frequency needs to be determined which can be done with the help of the
+ * observation that certain HWP performance levels should correspond to certain
+ * P-states, like for example the HWP highest performance should correspond
+ * to the maximum turbo P-state of the CPU.
+ */
+static void intel_pstate_hybrid_hwp_calibrate(struct cpudata *cpu)
+{
+ int perf_ctl_max_phys = cpu->pstate.max_pstate_physical;
+ int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
+ int perf_ctl_turbo = pstate_funcs.get_turbo();
+ int turbo_freq = perf_ctl_turbo * perf_ctl_scaling;
+ int perf_ctl_max = pstate_funcs.get_max();
+ int max_freq = perf_ctl_max * perf_ctl_scaling;
+ int scaling = INT_MAX;
+ int freq;
+
+ pr_debug("CPU%d: perf_ctl_max_phys = %d\n", cpu->cpu, perf_ctl_max_phys);
+ pr_debug("CPU%d: perf_ctl_max = %d\n", cpu->cpu, perf_ctl_max);
+ pr_debug("CPU%d: perf_ctl_turbo = %d\n", cpu->cpu, perf_ctl_turbo);
+ pr_debug("CPU%d: perf_ctl_scaling = %d\n", cpu->cpu, perf_ctl_scaling);
+
+ pr_debug("CPU%d: HWP_CAP guaranteed = %d\n", cpu->cpu, cpu->pstate.max_pstate);
+ pr_debug("CPU%d: HWP_CAP highest = %d\n", cpu->cpu, cpu->pstate.turbo_pstate);
+
+#ifdef CONFIG_ACPI
+ if (IS_ENABLED(CONFIG_ACPI_CPPC_LIB)) {
+ struct cppc_perf_caps caps;
+
+ if (intel_pstate_cppc_perf_caps(cpu, &caps)) {
+ if (intel_pstate_cppc_perf_valid(caps.nominal_perf, &caps)) {
+ pr_debug("CPU%d: Using CPPC nominal\n", cpu->cpu);
+
+ /*
+ * If the CPPC nominal performance is valid, it
+ * can be assumed to correspond to cpu_khz.
+ */
+ if (caps.nominal_perf == perf_ctl_max_phys) {
+ intel_pstate_hybrid_hwp_perf_ctl_parity(cpu);
+ return;
+ }
+ scaling = DIV_ROUND_UP(cpu_khz, caps.nominal_perf);
+ } else if (intel_pstate_cppc_perf_valid(caps.guaranteed_perf, &caps)) {
+ pr_debug("CPU%d: Using CPPC guaranteed\n", cpu->cpu);
+
+ /*
+ * If the CPPC guaranteed performance is valid,
+ * it can be assumed to correspond to max_freq.
+ */
+ if (caps.guaranteed_perf == perf_ctl_max) {
+ intel_pstate_hybrid_hwp_perf_ctl_parity(cpu);
+ return;
+ }
+ scaling = DIV_ROUND_UP(max_freq, caps.guaranteed_perf);
+ }
+ }
+ }
+#endif
+ /*
+ * If using the CPPC data to compute the HWP-to-frequency scaling factor
+ * doesn't work, use the HWP_CAP gauranteed perf for this purpose with
+ * the assumption that it corresponds to max_freq.
+ */
+ if (scaling > perf_ctl_scaling) {
+ pr_debug("CPU%d: Using HWP_CAP guaranteed\n", cpu->cpu);
+
+ if (cpu->pstate.max_pstate == perf_ctl_max) {
+ intel_pstate_hybrid_hwp_perf_ctl_parity(cpu);
+ return;
+ }
+ scaling = DIV_ROUND_UP(max_freq, cpu->pstate.max_pstate);
+ if (scaling > perf_ctl_scaling) {
+ /*
+ * This should not happen, because it would mean that
+ * the number of HWP perf levels was less than the
+ * number of P-states, so use the PERF_CTL scaling in
+ * that case.
+ */
+ pr_debug("CPU%d: scaling (%d) out of range\n", cpu->cpu,
+ scaling);
+
+ intel_pstate_hybrid_hwp_perf_ctl_parity(cpu);
+ return;
+ }
+ }
+
+ /*
+ * If the product of the HWP performance scaling factor obtained above
+ * and the HWP_CAP highest performance is greater than the maximum turbo
+ * frequency corresponding to the pstate_funcs.get_turbo() return value,
+ * the scaling factor is too high, so recompute it so that the HWP_CAP
+ * highest performance corresponds to the maximum turbo frequency.
+ */
+ if (turbo_freq < cpu->pstate.turbo_pstate * scaling) {
+ pr_debug("CPU%d: scaling too high (%d)\n", cpu->cpu, scaling);
+
+ cpu->pstate.turbo_freq = turbo_freq;
+ scaling = DIV_ROUND_UP(turbo_freq, cpu->pstate.turbo_pstate);
+ }
+
+ cpu->pstate.scaling = scaling;
+
+ pr_debug("CPU%d: HWP-to-frequency scaling factor: %d\n", cpu->cpu, scaling);
+
+ cpu->pstate.max_freq = rounddown(cpu->pstate.max_pstate * scaling,
+ perf_ctl_scaling);
+
+ freq = perf_ctl_max_phys * perf_ctl_scaling;
+ cpu->pstate.max_pstate_physical = DIV_ROUND_UP(freq, scaling);
+
+ cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling;
+ /*
+ * Cast the min P-state value retrieved via pstate_funcs.get_min() to
+ * the effective range of HWP performance levels.
+ */
+ cpu->pstate.min_pstate = DIV_ROUND_UP(cpu->pstate.min_freq, scaling);
+}
+
static inline void update_turbo_state(void)
{
u64 misc_en;
@@ -795,19 +946,22 @@ cpufreq_freq_attr_rw(energy_performance_preference);
static ssize_t show_base_frequency(struct cpufreq_policy *policy, char *buf)
{
- struct cpudata *cpu;
- u64 cap;
- int ratio;
+ struct cpudata *cpu = all_cpu_data[policy->cpu];
+ int ratio, freq;
- ratio = intel_pstate_get_cppc_guranteed(policy->cpu);
+ ratio = intel_pstate_get_cppc_guaranteed(policy->cpu);
if (ratio <= 0) {
+ u64 cap;
+
rdmsrl_on_cpu(policy->cpu, MSR_HWP_CAPABILITIES, &cap);
ratio = HWP_GUARANTEED_PERF(cap);
}
- cpu = all_cpu_data[policy->cpu];
+ freq = ratio * cpu->pstate.scaling;
+ if (cpu->pstate.scaling != cpu->pstate.perf_ctl_scaling)
+ freq = rounddown(freq, cpu->pstate.perf_ctl_scaling);
- return sprintf(buf, "%d\n", ratio * cpu->pstate.scaling);
+ return sprintf(buf, "%d\n", freq);
}
cpufreq_freq_attr_ro(base_frequency);
@@ -831,9 +985,20 @@ static void __intel_pstate_get_hwp_cap(struct cpudata *cpu)
static void intel_pstate_get_hwp_cap(struct cpudata *cpu)
{
+ int scaling = cpu->pstate.scaling;
+
__intel_pstate_get_hwp_cap(cpu);
- cpu->pstate.max_freq = cpu->pstate.max_pstate * cpu->pstate.scaling;
- cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * cpu->pstate.scaling;
+
+ cpu->pstate.max_freq = cpu->pstate.max_pstate * scaling;
+ cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * scaling;
+ if (scaling != cpu->pstate.perf_ctl_scaling) {
+ int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
+
+ cpu->pstate.max_freq = rounddown(cpu->pstate.max_freq,
+ perf_ctl_scaling);
+ cpu->pstate.turbo_freq = rounddown(cpu->pstate.turbo_freq,
+ perf_ctl_scaling);
+ }
}
static void intel_pstate_hwp_set(unsigned int cpu)
@@ -1365,8 +1530,6 @@ define_one_global_rw(energy_efficiency);
static struct attribute *intel_pstate_attributes[] = {
&status.attr,
&no_turbo.attr,
- &turbo_pct.attr,
- &num_pstates.attr,
NULL
};
@@ -1391,6 +1554,14 @@ static void __init intel_pstate_sysfs_expose_params(void)
if (WARN_ON(rc))
return;
+ if (!boot_cpu_has(X86_FEATURE_HYBRID_CPU)) {
+ rc = sysfs_create_file(intel_pstate_kobject, &turbo_pct.attr);
+ WARN_ON(rc);
+
+ rc = sysfs_create_file(intel_pstate_kobject, &num_pstates.attr);
+ WARN_ON(rc);
+ }
+
/*
* If per cpu limits are enforced there are no global limits, so
* return without creating max/min_perf_pct attributes
@@ -1417,6 +1588,11 @@ static void __init intel_pstate_sysfs_remove(void)
sysfs_remove_group(intel_pstate_kobject, &intel_pstate_attr_group);
+ if (!boot_cpu_has(X86_FEATURE_HYBRID_CPU)) {
+ sysfs_remove_file(intel_pstate_kobject, &num_pstates.attr);
+ sysfs_remove_file(intel_pstate_kobject, &turbo_pct.attr);
+ }
+
if (!per_cpu_limits) {
sysfs_remove_file(intel_pstate_kobject, &max_perf_pct.attr);
sysfs_remove_file(intel_pstate_kobject, &min_perf_pct.attr);
@@ -1713,19 +1889,33 @@ static void intel_pstate_max_within_limits(struct cpudata *cpu)
static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
{
+ bool hybrid_cpu = boot_cpu_has(X86_FEATURE_HYBRID_CPU);
+ int perf_ctl_max_phys = pstate_funcs.get_max_physical();
+ int perf_ctl_scaling = hybrid_cpu ? cpu_khz / perf_ctl_max_phys :
+ pstate_funcs.get_scaling();
+
cpu->pstate.min_pstate = pstate_funcs.get_min();
- cpu->pstate.max_pstate_physical = pstate_funcs.get_max_physical();
- cpu->pstate.scaling = pstate_funcs.get_scaling();
+ cpu->pstate.max_pstate_physical = perf_ctl_max_phys;
+ cpu->pstate.perf_ctl_scaling = perf_ctl_scaling;
if (hwp_active && !hwp_mode_bdw) {
__intel_pstate_get_hwp_cap(cpu);
+
+ if (hybrid_cpu)
+ intel_pstate_hybrid_hwp_calibrate(cpu);
+ else
+ cpu->pstate.scaling = perf_ctl_scaling;
} else {
+ cpu->pstate.scaling = perf_ctl_scaling;
cpu->pstate.max_pstate = pstate_funcs.get_max();
cpu->pstate.turbo_pstate = pstate_funcs.get_turbo();
}
- cpu->pstate.max_freq = cpu->pstate.max_pstate * cpu->pstate.scaling;
- cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * cpu->pstate.scaling;
+ if (cpu->pstate.scaling == perf_ctl_scaling) {
+ cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling;
+ cpu->pstate.max_freq = cpu->pstate.max_pstate * perf_ctl_scaling;
+ cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * perf_ctl_scaling;
+ }
if (pstate_funcs.get_aperf_mperf_shift)
cpu->aperf_mperf_shift = pstate_funcs.get_aperf_mperf_shift();
@@ -2087,6 +2277,8 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
X86_MATCH(ATOM_GOLDMONT, core_funcs),
X86_MATCH(ATOM_GOLDMONT_PLUS, core_funcs),
X86_MATCH(SKYLAKE_X, core_funcs),
+ X86_MATCH(COMETLAKE, core_funcs),
+ X86_MATCH(ICELAKE_X, core_funcs),
{}
};
MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
@@ -2195,23 +2387,34 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu,
unsigned int policy_min,
unsigned int policy_max)
{
- int scaling = cpu->pstate.scaling;
+ int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
int32_t max_policy_perf, min_policy_perf;
+ max_policy_perf = policy_max / perf_ctl_scaling;
+ if (policy_max == policy_min) {
+ min_policy_perf = max_policy_perf;
+ } else {
+ min_policy_perf = policy_min / perf_ctl_scaling;
+ min_policy_perf = clamp_t(int32_t, min_policy_perf,
+ 0, max_policy_perf);
+ }
+
/*
* HWP needs some special consideration, because HWP_REQUEST uses
* abstract values to represent performance rather than pure ratios.
*/
- if (hwp_active)
+ if (hwp_active) {
intel_pstate_get_hwp_cap(cpu);
- max_policy_perf = policy_max / scaling;
- if (policy_max == policy_min) {
- min_policy_perf = max_policy_perf;
- } else {
- min_policy_perf = policy_min / scaling;
- min_policy_perf = clamp_t(int32_t, min_policy_perf,
- 0, max_policy_perf);
+ if (cpu->pstate.scaling != perf_ctl_scaling) {
+ int scaling = cpu->pstate.scaling;
+ int freq;
+
+ freq = max_policy_perf * perf_ctl_scaling;
+ max_policy_perf = DIV_ROUND_UP(freq, scaling);
+ freq = min_policy_perf * perf_ctl_scaling;
+ min_policy_perf = DIV_ROUND_UP(freq, scaling);
+ }
}
pr_debug("cpu:%d min_policy_perf:%d max_policy_perf:%d\n",
@@ -2329,7 +2532,7 @@ static int intel_pstate_verify_policy(struct cpufreq_policy_data *policy)
return 0;
}
-static int intel_pstate_cpu_offline(struct cpufreq_policy *policy)
+static int intel_cpufreq_cpu_offline(struct cpufreq_policy *policy)
{
struct cpudata *cpu = all_cpu_data[policy->cpu];
@@ -2374,11 +2577,11 @@ static int intel_pstate_cpu_online(struct cpufreq_policy *policy)
return 0;
}
-static void intel_pstate_stop_cpu(struct cpufreq_policy *policy)
+static int intel_pstate_cpu_offline(struct cpufreq_policy *policy)
{
- pr_debug("CPU %d stopping\n", policy->cpu);
-
intel_pstate_clear_update_util_hook(policy->cpu);
+
+ return intel_cpufreq_cpu_offline(policy);
}
static int intel_pstate_cpu_exit(struct cpufreq_policy *policy)
@@ -2405,7 +2608,7 @@ static int __intel_pstate_cpu_init(struct cpufreq_policy *policy)
cpu->min_perf_ratio = 0;
/* cpuinfo and default policy values */
- policy->cpuinfo.min_freq = cpu->pstate.min_pstate * cpu->pstate.scaling;
+ policy->cpuinfo.min_freq = cpu->pstate.min_freq;
update_turbo_state();
global.turbo_disabled_mf = global.turbo_disabled;
policy->cpuinfo.max_freq = global.turbo_disabled ?
@@ -2451,7 +2654,6 @@ static struct cpufreq_driver intel_pstate = {
.resume = intel_pstate_resume,
.init = intel_pstate_cpu_init,
.exit = intel_pstate_cpu_exit,
- .stop_cpu = intel_pstate_stop_cpu,
.offline = intel_pstate_cpu_offline,
.online = intel_pstate_cpu_online,
.update_limits = intel_pstate_update_limits,
@@ -2753,7 +2955,7 @@ static struct cpufreq_driver intel_cpufreq = {
.fast_switch = intel_cpufreq_fast_switch,
.init = intel_cpufreq_cpu_init,
.exit = intel_cpufreq_cpu_exit,
- .offline = intel_pstate_cpu_offline,
+ .offline = intel_cpufreq_cpu_offline,
.online = intel_pstate_cpu_online,
.suspend = intel_pstate_suspend,
.resume = intel_pstate_resume,
@@ -3135,6 +3337,8 @@ hwp_cpu_matched:
}
pr_info("HWP enabled\n");
+ } else if (boot_cpu_has(X86_FEATURE_HYBRID_CPU)) {
+ pr_warn("Problematic setup: Hybrid processor with disabled HWP\n");
}
return 0;
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index 182a4dbca095..c538a153ee82 100644
--- a/drivers/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -942,8 +942,6 @@ static int __init longhaul_init(void)
return cpufreq_register_driver(&longhaul_driver);
case 10:
pr_err("Use acpi-cpufreq driver for VIA C7\n");
- default:
- ;
}
return -ENODEV;
diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c
index d05e761d9572..afc59b292153 100644
--- a/drivers/cpufreq/loongson2_cpufreq.c
+++ b/drivers/cpufreq/loongson2_cpufreq.c
@@ -16,7 +16,6 @@
#include <linux/cpufreq.h>
#include <linux/module.h>
#include <linux/err.h>
-#include <linux/sched.h> /* set_cpus_allowed() */
#include <linux/delay.h>
#include <linux/platform_device.h>
diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
index f2e491b25b07..87019d5a9547 100644
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -537,6 +537,7 @@ static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
{ .compatible = "mediatek,mt8173", },
{ .compatible = "mediatek,mt8176", },
{ .compatible = "mediatek,mt8183", },
+ { .compatible = "mediatek,mt8365", },
{ .compatible = "mediatek,mt8516", },
{ }
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c
index e439b43c19eb..005600cef273 100644
--- a/drivers/cpufreq/powernv-cpufreq.c
+++ b/drivers/cpufreq/powernv-cpufreq.c
@@ -875,7 +875,15 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy)
static int powernv_cpufreq_cpu_exit(struct cpufreq_policy *policy)
{
- /* timer is deleted in cpufreq_cpu_stop() */
+ struct powernv_smp_call_data freq_data;
+ struct global_pstate_info *gpstates = policy->driver_data;
+
+ freq_data.pstate_id = idx_to_pstate(powernv_pstate_info.min);
+ freq_data.gpstate_id = idx_to_pstate(powernv_pstate_info.min);
+ smp_call_function_single(policy->cpu, set_pstate, &freq_data, 1);
+ if (gpstates)
+ del_timer_sync(&gpstates->timer);
+
kfree(policy->driver_data);
return 0;
@@ -1007,18 +1015,6 @@ static struct notifier_block powernv_cpufreq_opal_nb = {
.priority = 0,
};
-static void powernv_cpufreq_stop_cpu(struct cpufreq_policy *policy)
-{
- struct powernv_smp_call_data freq_data;
- struct global_pstate_info *gpstates = policy->driver_data;
-
- freq_data.pstate_id = idx_to_pstate(powernv_pstate_info.min);
- freq_data.gpstate_id = idx_to_pstate(powernv_pstate_info.min);
- smp_call_function_single(policy->cpu, set_pstate, &freq_data, 1);
- if (gpstates)
- del_timer_sync(&gpstates->timer);
-}
-
static unsigned int powernv_fast_switch(struct cpufreq_policy *policy,
unsigned int target_freq)
{
@@ -1042,7 +1038,6 @@ static struct cpufreq_driver powernv_cpufreq_driver = {
.target_index = powernv_cpufreq_target_index,
.fast_switch = powernv_fast_switch,
.get = powernv_cpufreq_get,
- .stop_cpu = powernv_cpufreq_stop_cpu,
.attr = powernv_cpu_freq_attr,
};
diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c
index 73a208559fe2..330c8d6cf93c 100644
--- a/drivers/cpufreq/sc520_freq.c
+++ b/drivers/cpufreq/sc520_freq.c
@@ -42,6 +42,7 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
default:
pr_err("error: cpuctl register has unexpected value %02x\n",
clockspeed_reg);
+ fallthrough;
case 0x01:
return 100000;
case 0x02:
diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c
index c8a4364ad3c2..ec9a87ca2dbb 100644
--- a/drivers/cpufreq/scmi-cpufreq.c
+++ b/drivers/cpufreq/scmi-cpufreq.c
@@ -174,7 +174,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
nr_opp = dev_pm_opp_get_opp_count(cpu_dev);
if (nr_opp <= 0) {
dev_err(cpu_dev, "%s: No OPPs for this device: %d\n",
- __func__, ret);
+ __func__, nr_opp);
ret = -ENODEV;
goto out_free_opp;
diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c
index 0ac265d47ef0..1a251e635ebd 100644
--- a/drivers/cpufreq/sh-cpufreq.c
+++ b/drivers/cpufreq/sh-cpufreq.c
@@ -23,7 +23,6 @@
#include <linux/cpumask.h>
#include <linux/cpu.h>
#include <linux/smp.h>
-#include <linux/sched.h> /* set_cpus_allowed() */
#include <linux/clk.h>
#include <linux/percpu.h>
#include <linux/sh_clk.h>
diff --git a/drivers/cpuidle/cpuidle-qcom-spm.c b/drivers/cpuidle/cpuidle-qcom-spm.c
index adf91a6e4d7d..c0e7971da2da 100644
--- a/drivers/cpuidle/cpuidle-qcom-spm.c
+++ b/drivers/cpuidle/cpuidle-qcom-spm.c
@@ -87,6 +87,18 @@ static const struct spm_reg_data spm_reg_8974_8084_cpu = {
.start_index[PM_SLEEP_MODE_SPC] = 3,
};
+/* SPM register data for 8226 */
+static const struct spm_reg_data spm_reg_8226_cpu = {
+ .reg_offset = spm_reg_offset_v2_1,
+ .spm_cfg = 0x0,
+ .spm_dly = 0x3C102800,
+ .seq = { 0x60, 0x03, 0x60, 0x0B, 0x0F, 0x20, 0x10, 0x80, 0x30, 0x90,
+ 0x5B, 0x60, 0x03, 0x60, 0x3B, 0x76, 0x76, 0x0B, 0x94, 0x5B,
+ 0x80, 0x10, 0x26, 0x30, 0x0F },
+ .start_index[PM_SLEEP_MODE_STBY] = 0,
+ .start_index[PM_SLEEP_MODE_SPC] = 5,
+};
+
static const u8 spm_reg_offset_v1_1[SPM_REG_NR] = {
[SPM_REG_CFG] = 0x08,
[SPM_REG_SPM_CTL] = 0x20,
@@ -259,6 +271,8 @@ static struct spm_driver_data *spm_get_drv(struct platform_device *pdev,
}
static const struct of_device_id spm_match_table[] = {
+ { .compatible = "qcom,msm8226-saw2-v2.1-cpu",
+ .data = &spm_reg_8226_cpu },
{ .compatible = "qcom,msm8974-saw2-v2.1-cpu",
.data = &spm_reg_8974_8084_cpu },
{ .compatible = "qcom,apq8084-saw2-v2.1-cpu",
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index c3aa8d6ccee3..2e5670446991 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -117,7 +117,7 @@ struct menu_device {
int interval_ptr;
};
-static inline int which_bucket(u64 duration_ns, unsigned long nr_iowaiters)
+static inline int which_bucket(u64 duration_ns, unsigned int nr_iowaiters)
{
int bucket = 0;
@@ -150,7 +150,7 @@ static inline int which_bucket(u64 duration_ns, unsigned long nr_iowaiters)
* to be, the higher this multiplier, and thus the higher
* the barrier to go to an expensive C state.
*/
-static inline int performance_multiplier(unsigned long nr_iowaiters)
+static inline int performance_multiplier(unsigned int nr_iowaiters)
{
/* for IO wait tasks (per cpu!) we add 10x each */
return 1 + 10 * nr_iowaiters;
@@ -270,7 +270,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
unsigned int predicted_us;
u64 predicted_ns;
u64 interactivity_req;
- unsigned long nr_iowaiters;
+ unsigned int nr_iowaiters;
ktime_t delta, delta_tick;
int i, idx;
diff --git a/drivers/cpuidle/governors/teo.c b/drivers/cpuidle/governors/teo.c
index ac4bb27d69b0..7b91060e82f6 100644
--- a/drivers/cpuidle/governors/teo.c
+++ b/drivers/cpuidle/governors/teo.c
@@ -2,47 +2,103 @@
/*
* Timer events oriented CPU idle governor
*
- * Copyright (C) 2018 Intel Corporation
+ * Copyright (C) 2018 - 2021 Intel Corporation
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ */
+
+/**
+ * DOC: teo-description
*
* The idea of this governor is based on the observation that on many systems
* timer events are two or more orders of magnitude more frequent than any
- * other interrupts, so they are likely to be the most significant source of CPU
+ * other interrupts, so they are likely to be the most significant cause of CPU
* wakeups from idle states. Moreover, information about what happened in the
* (relatively recent) past can be used to estimate whether or not the deepest
- * idle state with target residency within the time to the closest timer is
- * likely to be suitable for the upcoming idle time of the CPU and, if not, then
- * which of the shallower idle states to choose.
+ * idle state with target residency within the (known) time till the closest
+ * timer event, referred to as the sleep length, is likely to be suitable for
+ * the upcoming CPU idle period and, if not, then which of the shallower idle
+ * states to choose instead of it.
+ *
+ * Of course, non-timer wakeup sources are more important in some use cases
+ * which can be covered by taking a few most recent idle time intervals of the
+ * CPU into account. However, even in that context it is not necessary to
+ * consider idle duration values greater than the sleep length, because the
+ * closest timer will ultimately wake up the CPU anyway unless it is woken up
+ * earlier.
+ *
+ * Thus this governor estimates whether or not the prospective idle duration of
+ * a CPU is likely to be significantly shorter than the sleep length and selects
+ * an idle state for it accordingly.
+ *
+ * The computations carried out by this governor are based on using bins whose
+ * boundaries are aligned with the target residency parameter values of the CPU
+ * idle states provided by the %CPUIdle driver in the ascending order. That is,
+ * the first bin spans from 0 up to, but not including, the target residency of
+ * the second idle state (idle state 1), the second bin spans from the target
+ * residency of idle state 1 up to, but not including, the target residency of
+ * idle state 2, the third bin spans from the target residency of idle state 2
+ * up to, but not including, the target residency of idle state 3 and so on.
+ * The last bin spans from the target residency of the deepest idle state
+ * supplied by the driver to infinity.
+ *
+ * Two metrics called "hits" and "intercepts" are associated with each bin.
+ * They are updated every time before selecting an idle state for the given CPU
+ * in accordance with what happened last time.
+ *
+ * The "hits" metric reflects the relative frequency of situations in which the
+ * sleep length and the idle duration measured after CPU wakeup fall into the
+ * same bin (that is, the CPU appears to wake up "on time" relative to the sleep
+ * length). In turn, the "intercepts" metric reflects the relative frequency of
+ * situations in which the measured idle duration is so much shorter than the
+ * sleep length that the bin it falls into corresponds to an idle state
+ * shallower than the one whose bin is fallen into by the sleep length (these
+ * situations are referred to as "intercepts" below).
+ *
+ * In addition to the metrics described above, the governor counts recent
+ * intercepts (that is, intercepts that have occurred during the last
+ * %NR_RECENT invocations of it for the given CPU) for each bin.
*
- * Of course, non-timer wakeup sources are more important in some use cases and
- * they can be covered by taking a few most recent idle time intervals of the
- * CPU into account. However, even in that case it is not necessary to consider
- * idle duration values greater than the time till the closest timer, as the
- * patterns that they may belong to produce average values close enough to
- * the time till the closest timer (sleep length) anyway.
+ * In order to select an idle state for a CPU, the governor takes the following
+ * steps (modulo the possible latency constraint that must be taken into account
+ * too):
*
- * Thus this governor estimates whether or not the upcoming idle time of the CPU
- * is likely to be significantly shorter than the sleep length and selects an
- * idle state for it in accordance with that, as follows:
+ * 1. Find the deepest CPU idle state whose target residency does not exceed
+ * the current sleep length (the candidate idle state) and compute 3 sums as
+ * follows:
*
- * - Find an idle state on the basis of the sleep length and state statistics
- * collected over time:
+ * - The sum of the "hits" and "intercepts" metrics for the candidate state
+ * and all of the deeper idle states (it represents the cases in which the
+ * CPU was idle long enough to avoid being intercepted if the sleep length
+ * had been equal to the current one).
*
- * o Find the deepest idle state whose target residency is less than or equal
- * to the sleep length.
+ * - The sum of the "intercepts" metrics for all of the idle states shallower
+ * than the candidate one (it represents the cases in which the CPU was not
+ * idle long enough to avoid being intercepted if the sleep length had been
+ * equal to the current one).
*
- * o Select it if it matched both the sleep length and the observed idle
- * duration in the past more often than it matched the sleep length alone
- * (i.e. the observed idle duration was significantly shorter than the sleep
- * length matched by it).
+ * - The sum of the numbers of recent intercepts for all of the idle states
+ * shallower than the candidate one.
*
- * o Otherwise, select the shallower state with the greatest matched "early"
- * wakeups metric.
+ * 2. If the second sum is greater than the first one or the third sum is
+ * greater than %NR_RECENT / 2, the CPU is likely to wake up early, so look
+ * for an alternative idle state to select.
*
- * - If the majority of the most recent idle duration values are below the
- * target residency of the idle state selected so far, use those values to
- * compute the new expected idle duration and find an idle state matching it
- * (which has to be shallower than the one selected so far).
+ * - Traverse the idle states shallower than the candidate one in the
+ * descending order.
+ *
+ * - For each of them compute the sum of the "intercepts" metrics and the sum
+ * of the numbers of recent intercepts over all of the idle states between
+ * it and the candidate one (including the former and excluding the
+ * latter).
+ *
+ * - If each of these sums that needs to be taken into account (because the
+ * check related to it has indicated that the CPU is likely to wake up
+ * early) is greater than a half of the corresponding sum computed in step
+ * 1 (which means that the target residency of the state in question had
+ * not exceeded the idle duration in over a half of the relevant cases),
+ * select the given idle state instead of the candidate one.
+ *
+ * 3. By default, select the candidate state.
*/
#include <linux/cpuidle.h>
@@ -60,65 +116,51 @@
/*
* Number of the most recent idle duration values to take into consideration for
- * the detection of wakeup patterns.
+ * the detection of recent early wakeup patterns.
*/
-#define INTERVALS 8
+#define NR_RECENT 9
/**
- * struct teo_idle_state - Idle state data used by the TEO cpuidle governor.
- * @early_hits: "Early" CPU wakeups "matching" this state.
- * @hits: "On time" CPU wakeups "matching" this state.
- * @misses: CPU wakeups "missing" this state.
- *
- * A CPU wakeup is "matched" by a given idle state if the idle duration measured
- * after the wakeup is between the target residency of that state and the target
- * residency of the next one (or if this is the deepest available idle state, it
- * "matches" a CPU wakeup when the measured idle duration is at least equal to
- * its target residency).
- *
- * Also, from the TEO governor perspective, a CPU wakeup from idle is "early" if
- * it occurs significantly earlier than the closest expected timer event (that
- * is, early enough to match an idle state shallower than the one matching the
- * time till the closest timer event). Otherwise, the wakeup is "on time", or
- * it is a "hit".
- *
- * A "miss" occurs when the given state doesn't match the wakeup, but it matches
- * the time till the closest timer event used for idle state selection.
+ * struct teo_bin - Metrics used by the TEO cpuidle governor.
+ * @intercepts: The "intercepts" metric.
+ * @hits: The "hits" metric.
+ * @recent: The number of recent "intercepts".
*/
-struct teo_idle_state {
- unsigned int early_hits;
+struct teo_bin {
+ unsigned int intercepts;
unsigned int hits;
- unsigned int misses;
+ unsigned int recent;
};
/**
* struct teo_cpu - CPU data used by the TEO cpuidle governor.
* @time_span_ns: Time between idle state selection and post-wakeup update.
* @sleep_length_ns: Time till the closest timer event (at the selection time).
- * @states: Idle states data corresponding to this CPU.
- * @interval_idx: Index of the most recent saved idle interval.
- * @intervals: Saved idle duration values.
+ * @state_bins: Idle state data bins for this CPU.
+ * @total: Grand total of the "intercepts" and "hits" mertics for all bins.
+ * @next_recent_idx: Index of the next @recent_idx entry to update.
+ * @recent_idx: Indices of bins corresponding to recent "intercepts".
*/
struct teo_cpu {
s64 time_span_ns;
s64 sleep_length_ns;
- struct teo_idle_state states[CPUIDLE_STATE_MAX];
- int interval_idx;
- u64 intervals[INTERVALS];
+ struct teo_bin state_bins[CPUIDLE_STATE_MAX];
+ unsigned int total;
+ int next_recent_idx;
+ int recent_idx[NR_RECENT];
};
static DEFINE_PER_CPU(struct teo_cpu, teo_cpus);
/**
- * teo_update - Update CPU data after wakeup.
+ * teo_update - Update CPU metrics after wakeup.
* @drv: cpuidle driver containing state data.
* @dev: Target CPU.
*/
static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
{
struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
- int i, idx_hit = 0, idx_timer = 0;
- unsigned int hits, misses;
+ int i, idx_timer = 0, idx_duration = 0;
u64 measured_ns;
if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) {
@@ -151,53 +193,52 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
measured_ns /= 2;
}
+ cpu_data->total = 0;
+
/*
- * Decay the "early hits" metric for all of the states and find the
- * states matching the sleep length and the measured idle duration.
+ * Decay the "hits" and "intercepts" metrics for all of the bins and
+ * find the bins that the sleep length and the measured idle duration
+ * fall into.
*/
for (i = 0; i < drv->state_count; i++) {
- unsigned int early_hits = cpu_data->states[i].early_hits;
+ s64 target_residency_ns = drv->states[i].target_residency_ns;
+ struct teo_bin *bin = &cpu_data->state_bins[i];
- cpu_data->states[i].early_hits -= early_hits >> DECAY_SHIFT;
+ bin->hits -= bin->hits >> DECAY_SHIFT;
+ bin->intercepts -= bin->intercepts >> DECAY_SHIFT;
- if (drv->states[i].target_residency_ns <= cpu_data->sleep_length_ns) {
+ cpu_data->total += bin->hits + bin->intercepts;
+
+ if (target_residency_ns <= cpu_data->sleep_length_ns) {
idx_timer = i;
- if (drv->states[i].target_residency_ns <= measured_ns)
- idx_hit = i;
+ if (target_residency_ns <= measured_ns)
+ idx_duration = i;
}
}
- /*
- * Update the "hits" and "misses" data for the state matching the sleep
- * length. If it matches the measured idle duration too, this is a hit,
- * so increase the "hits" metric for it then. Otherwise, this is a
- * miss, so increase the "misses" metric for it. In the latter case
- * also increase the "early hits" metric for the state that actually
- * matches the measured idle duration.
- */
- hits = cpu_data->states[idx_timer].hits;
- hits -= hits >> DECAY_SHIFT;
+ i = cpu_data->next_recent_idx++;
+ if (cpu_data->next_recent_idx >= NR_RECENT)
+ cpu_data->next_recent_idx = 0;
- misses = cpu_data->states[idx_timer].misses;
- misses -= misses >> DECAY_SHIFT;
+ if (cpu_data->recent_idx[i] >= 0)
+ cpu_data->state_bins[cpu_data->recent_idx[i]].recent--;
- if (idx_timer == idx_hit) {
- hits += PULSE;
+ /*
+ * If the measured idle duration falls into the same bin as the sleep
+ * length, this is a "hit", so update the "hits" metric for that bin.
+ * Otherwise, update the "intercepts" metric for the bin fallen into by
+ * the measured idle duration.
+ */
+ if (idx_timer == idx_duration) {
+ cpu_data->state_bins[idx_timer].hits += PULSE;
+ cpu_data->recent_idx[i] = -1;
} else {
- misses += PULSE;
- cpu_data->states[idx_hit].early_hits += PULSE;
+ cpu_data->state_bins[idx_duration].intercepts += PULSE;
+ cpu_data->state_bins[idx_duration].recent++;
+ cpu_data->recent_idx[i] = idx_duration;
}
- cpu_data->states[idx_timer].misses = misses;
- cpu_data->states[idx_timer].hits = hits;
-
- /*
- * Save idle duration values corresponding to non-timer wakeups for
- * pattern detection.
- */
- cpu_data->intervals[cpu_data->interval_idx++] = measured_ns;
- if (cpu_data->interval_idx >= INTERVALS)
- cpu_data->interval_idx = 0;
+ cpu_data->total += PULSE;
}
static bool teo_time_ok(u64 interval_ns)
@@ -205,6 +246,12 @@ static bool teo_time_ok(u64 interval_ns)
return !tick_nohz_tick_stopped() || interval_ns >= TICK_NSEC;
}
+static s64 teo_middle_of_bin(int idx, struct cpuidle_driver *drv)
+{
+ return (drv->states[idx].target_residency_ns +
+ drv->states[idx+1].target_residency_ns) / 2;
+}
+
/**
* teo_find_shallower_state - Find shallower idle state matching given duration.
* @drv: cpuidle driver containing state data.
@@ -240,10 +287,18 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
{
struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
s64 latency_req = cpuidle_governor_latency_req(dev->cpu);
- int max_early_idx, prev_max_early_idx, constraint_idx, idx0, idx, i;
- unsigned int hits, misses, early_hits;
+ unsigned int idx_intercept_sum = 0;
+ unsigned int intercept_sum = 0;
+ unsigned int idx_recent_sum = 0;
+ unsigned int recent_sum = 0;
+ unsigned int idx_hit_sum = 0;
+ unsigned int hit_sum = 0;
+ int constraint_idx = 0;
+ int idx0 = 0, idx = -1;
+ bool alt_intercepts, alt_recent;
ktime_t delta_tick;
s64 duration_ns;
+ int i;
if (dev->last_state_idx >= 0) {
teo_update(drv, dev);
@@ -255,171 +310,136 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
duration_ns = tick_nohz_get_sleep_length(&delta_tick);
cpu_data->sleep_length_ns = duration_ns;
- hits = 0;
- misses = 0;
- early_hits = 0;
- max_early_idx = -1;
- prev_max_early_idx = -1;
- constraint_idx = drv->state_count;
- idx = -1;
- idx0 = idx;
+ /* Check if there is any choice in the first place. */
+ if (drv->state_count < 2) {
+ idx = 0;
+ goto end;
+ }
+ if (!dev->states_usage[0].disable) {
+ idx = 0;
+ if (drv->states[1].target_residency_ns > duration_ns)
+ goto end;
+ }
- for (i = 0; i < drv->state_count; i++) {
+ /*
+ * Find the deepest idle state whose target residency does not exceed
+ * the current sleep length and the deepest idle state not deeper than
+ * the former whose exit latency does not exceed the current latency
+ * constraint. Compute the sums of metrics for early wakeup pattern
+ * detection.
+ */
+ for (i = 1; i < drv->state_count; i++) {
+ struct teo_bin *prev_bin = &cpu_data->state_bins[i-1];
struct cpuidle_state *s = &drv->states[i];
- if (dev->states_usage[i].disable) {
- /*
- * Ignore disabled states with target residencies beyond
- * the anticipated idle duration.
- */
- if (s->target_residency_ns > duration_ns)
- continue;
-
- /*
- * This state is disabled, so the range of idle duration
- * values corresponding to it is covered by the current
- * candidate state, but still the "hits" and "misses"
- * metrics of the disabled state need to be used to
- * decide whether or not the state covering the range in
- * question is good enough.
- */
- hits = cpu_data->states[i].hits;
- misses = cpu_data->states[i].misses;
-
- if (early_hits >= cpu_data->states[i].early_hits ||
- idx < 0)
- continue;
-
- /*
- * If the current candidate state has been the one with
- * the maximum "early hits" metric so far, the "early
- * hits" metric of the disabled state replaces the
- * current "early hits" count to avoid selecting a
- * deeper state with lower "early hits" metric.
- */
- if (max_early_idx == idx) {
- early_hits = cpu_data->states[i].early_hits;
- continue;
- }
-
- /*
- * The current candidate state is closer to the disabled
- * one than the current maximum "early hits" state, so
- * replace the latter with it, but in case the maximum
- * "early hits" state index has not been set so far,
- * check if the current candidate state is not too
- * shallow for that role.
- */
- if (teo_time_ok(drv->states[idx].target_residency_ns)) {
- prev_max_early_idx = max_early_idx;
- early_hits = cpu_data->states[i].early_hits;
- max_early_idx = idx;
- }
+ /*
+ * Update the sums of idle state mertics for all of the states
+ * shallower than the current one.
+ */
+ intercept_sum += prev_bin->intercepts;
+ hit_sum += prev_bin->hits;
+ recent_sum += prev_bin->recent;
+ if (dev->states_usage[i].disable)
continue;
- }
if (idx < 0) {
idx = i; /* first enabled state */
- hits = cpu_data->states[i].hits;
- misses = cpu_data->states[i].misses;
idx0 = i;
}
if (s->target_residency_ns > duration_ns)
break;
- if (s->exit_latency_ns > latency_req && constraint_idx > i)
+ idx = i;
+
+ if (s->exit_latency_ns <= latency_req)
constraint_idx = i;
- idx = i;
- hits = cpu_data->states[i].hits;
- misses = cpu_data->states[i].misses;
-
- if (early_hits < cpu_data->states[i].early_hits &&
- teo_time_ok(drv->states[i].target_residency_ns)) {
- prev_max_early_idx = max_early_idx;
- early_hits = cpu_data->states[i].early_hits;
- max_early_idx = i;
- }
+ idx_intercept_sum = intercept_sum;
+ idx_hit_sum = hit_sum;
+ idx_recent_sum = recent_sum;
}
- /*
- * If the "hits" metric of the idle state matching the sleep length is
- * greater than its "misses" metric, that is the one to use. Otherwise,
- * it is more likely that one of the shallower states will match the
- * idle duration observed after wakeup, so take the one with the maximum
- * "early hits" metric, but if that cannot be determined, just use the
- * state selected so far.
- */
- if (hits <= misses) {
- /*
- * The current candidate state is not suitable, so take the one
- * whose "early hits" metric is the maximum for the range of
- * shallower states.
- */
- if (idx == max_early_idx)
- max_early_idx = prev_max_early_idx;
-
- if (max_early_idx >= 0) {
- idx = max_early_idx;
- duration_ns = drv->states[idx].target_residency_ns;
- }
+ /* Avoid unnecessary overhead. */
+ if (idx < 0) {
+ idx = 0; /* No states enabled, must use 0. */
+ goto end;
+ } else if (idx == idx0) {
+ goto end;
}
/*
- * If there is a latency constraint, it may be necessary to use a
- * shallower idle state than the one selected so far.
+ * If the sum of the intercepts metric for all of the idle states
+ * shallower than the current candidate one (idx) is greater than the
+ * sum of the intercepts and hits metrics for the candidate state and
+ * all of the deeper states, or the sum of the numbers of recent
+ * intercepts over all of the states shallower than the candidate one
+ * is greater than a half of the number of recent events taken into
+ * account, the CPU is likely to wake up early, so find an alternative
+ * idle state to select.
*/
- if (constraint_idx < idx)
- idx = constraint_idx;
-
- if (idx < 0) {
- idx = 0; /* No states enabled. Must use 0. */
- } else if (idx > idx0) {
- unsigned int count = 0;
- u64 sum = 0;
+ alt_intercepts = 2 * idx_intercept_sum > cpu_data->total - idx_hit_sum;
+ alt_recent = idx_recent_sum > NR_RECENT / 2;
+ if (alt_recent || alt_intercepts) {
+ s64 last_enabled_span_ns = duration_ns;
+ int last_enabled_idx = idx;
/*
- * The target residencies of at least two different enabled idle
- * states are less than or equal to the current expected idle
- * duration. Try to refine the selection using the most recent
- * measured idle duration values.
+ * Look for the deepest idle state whose target residency had
+ * not exceeded the idle duration in over a half of the relevant
+ * cases (both with respect to intercepts overall and with
+ * respect to the recent intercepts only) in the past.
*
- * Count and sum the most recent idle duration values less than
- * the current expected idle duration value.
+ * Take the possible latency constraint and duration limitation
+ * present if the tick has been stopped already into account.
*/
- for (i = 0; i < INTERVALS; i++) {
- u64 val = cpu_data->intervals[i];
+ intercept_sum = 0;
+ recent_sum = 0;
+
+ for (i = idx - 1; i >= idx0; i--) {
+ struct teo_bin *bin = &cpu_data->state_bins[i];
+ s64 span_ns;
- if (val >= duration_ns)
+ intercept_sum += bin->intercepts;
+ recent_sum += bin->recent;
+
+ if (dev->states_usage[i].disable)
continue;
- count++;
- sum += val;
- }
+ span_ns = teo_middle_of_bin(i, drv);
+ if (!teo_time_ok(span_ns)) {
+ /*
+ * The current state is too shallow, so select
+ * the first enabled deeper state.
+ */
+ duration_ns = last_enabled_span_ns;
+ idx = last_enabled_idx;
+ break;
+ }
- /*
- * Give up unless the majority of the most recent idle duration
- * values are in the interesting range.
- */
- if (count > INTERVALS / 2) {
- u64 avg_ns = div64_u64(sum, count);
-
- /*
- * Avoid spending too much time in an idle state that
- * would be too shallow.
- */
- if (teo_time_ok(avg_ns)) {
- duration_ns = avg_ns;
- if (drv->states[idx].target_residency_ns > avg_ns)
- idx = teo_find_shallower_state(drv, dev,
- idx, avg_ns);
+ if ((!alt_recent || 2 * recent_sum > idx_recent_sum) &&
+ (!alt_intercepts ||
+ 2 * intercept_sum > idx_intercept_sum)) {
+ idx = i;
+ duration_ns = span_ns;
+ break;
}
+
+ last_enabled_span_ns = span_ns;
+ last_enabled_idx = i;
}
}
/*
+ * If there is a latency constraint, it may be necessary to select an
+ * idle state shallower than the current candidate one.
+ */
+ if (idx > constraint_idx)
+ idx = constraint_idx;
+
+end:
+ /*
* Don't stop the tick if the selected state is a polling one or if the
* expected idle duration is shorter than the tick period length.
*/
@@ -478,8 +498,8 @@ static int teo_enable_device(struct cpuidle_driver *drv,
memset(cpu_data, 0, sizeof(*cpu_data));
- for (i = 0; i < INTERVALS; i++)
- cpu_data->intervals[i] = U64_MAX;
+ for (i = 0; i < NR_RECENT; i++)
+ cpu_data->recent_idx[i] = -1;
return 0;
}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 9a4c275a1335..51690e73153a 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -266,6 +266,27 @@ config CRYPTO_DEV_NIAGARA2
Group, which can perform encryption, decryption, hashing,
checksumming, and raw copies.
+config CRYPTO_DEV_SL3516
+ tristate "Storlink SL3516 crypto offloader"
+ depends on ARCH_GEMINI || COMPILE_TEST
+ depends on HAS_IOMEM && PM
+ select CRYPTO_SKCIPHER
+ select CRYPTO_ENGINE
+ select CRYPTO_ECB
+ select CRYPTO_AES
+ select HW_RANDOM
+ help
+ This option allows you to have support for SL3516 crypto offloader.
+
+config CRYPTO_DEV_SL3516_DEBUG
+ bool "Enable SL3516 stats"
+ depends on CRYPTO_DEV_SL3516
+ depends on DEBUG_FS
+ help
+ Say y to enable SL3516 debug stats.
+ This will create /sys/kernel/debug/sl3516/stats for displaying
+ the number of requests per algorithm and other internal stats.
+
config CRYPTO_DEV_HIFN_795X
tristate "Driver HIFN 795x crypto accelerator chips"
select CRYPTO_LIB_DES
@@ -325,6 +346,11 @@ config CRYPTO_DEV_TALITOS2
config CRYPTO_DEV_IXP4XX
tristate "Driver for IXP4xx crypto hardware acceleration"
depends on ARCH_IXP4XX && IXP4XX_QMGR && IXP4XX_NPE
+ select CRYPTO_AES
+ select CRYPTO_DES
+ select CRYPTO_ECB
+ select CRYPTO_CBC
+ select CRYPTO_CTR
select CRYPTO_LIB_DES
select CRYPTO_AEAD
select CRYPTO_AUTHENC
@@ -627,6 +653,12 @@ config CRYPTO_DEV_QCE_SHA
select CRYPTO_SHA1
select CRYPTO_SHA256
+config CRYPTO_DEV_QCE_AEAD
+ bool
+ depends on CRYPTO_DEV_QCE
+ select CRYPTO_AUTHENC
+ select CRYPTO_LIB_DES
+
choice
prompt "Algorithms enabled for QCE acceleration"
default CRYPTO_DEV_QCE_ENABLE_ALL
@@ -647,6 +679,7 @@ choice
bool "All supported algorithms"
select CRYPTO_DEV_QCE_SKCIPHER
select CRYPTO_DEV_QCE_SHA
+ select CRYPTO_DEV_QCE_AEAD
help
Enable all supported algorithms:
- AES (CBC, CTR, ECB, XTS)
@@ -672,6 +705,14 @@ choice
- SHA1, HMAC-SHA1
- SHA256, HMAC-SHA256
+ config CRYPTO_DEV_QCE_ENABLE_AEAD
+ bool "AEAD algorithms only"
+ select CRYPTO_DEV_QCE_AEAD
+ help
+ Enable AEAD algorithms only:
+ - authenc()
+ - ccm(aes)
+ - rfc4309(ccm(aes))
endchoice
config CRYPTO_DEV_QCE_SW_MAX_LEN
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index fa22cb19e242..1fe5120eb966 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rockchip/
obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
obj-$(CONFIG_CRYPTO_DEV_SA2UL) += sa2ul.o
obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
+obj-$(CONFIG_CRYPTO_DEV_SL3516) += gemini/
obj-$(CONFIG_ARCH_STM32) += stm32/
obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
diff --git a/drivers/crypto/cavium/cpt/cptpf_main.c b/drivers/crypto/cavium/cpt/cptpf_main.c
index 06ee42e8a245..8c32d0eb8fcf 100644
--- a/drivers/crypto/cavium/cpt/cptpf_main.c
+++ b/drivers/crypto/cavium/cpt/cptpf_main.c
@@ -401,7 +401,7 @@ static void cpt_disable_all_cores(struct cpt_device *cpt)
cpt_write_csr64(cpt->reg_base, CPTX_PF_EXE_CTL(0), 0);
}
-/**
+/*
* Ensure all cores are disengaged from all groups by
* calling cpt_disable_all_cores() before calling this
* function.
diff --git a/drivers/crypto/cavium/cpt/cptvf_reqmanager.c b/drivers/crypto/cavium/cpt/cptvf_reqmanager.c
index 4fe7898c8561..153004bdfb5c 100644
--- a/drivers/crypto/cavium/cpt/cptvf_reqmanager.c
+++ b/drivers/crypto/cavium/cpt/cptvf_reqmanager.c
@@ -9,8 +9,8 @@
/**
* get_free_pending_entry - get free entry from pending queue
- * @param pqinfo: pending_qinfo structure
- * @param qno: queue number
+ * @q: pending queue
+ * @qlen: queue length
*/
static struct pending_entry *get_free_pending_entry(struct pending_queue *q,
int qlen)
@@ -244,11 +244,7 @@ static int send_cpt_command(struct cpt_vf *cptvf, union cpt_inst_s *cmd,
memcpy(ent, (void *)cmd, qinfo->cmd_size);
if (++queue->idx >= queue->qhead->size / 64) {
- struct hlist_node *node;
-
- hlist_for_each(node, &queue->chead) {
- chunk = hlist_entry(node, struct command_chunk,
- nextchunk);
+ hlist_for_each_entry(chunk, &queue->chead, nextchunk) {
if (chunk == queue->qhead) {
continue;
} else {
diff --git a/drivers/crypto/cavium/nitrox/nitrox_isr.c b/drivers/crypto/cavium/nitrox/nitrox_isr.c
index c288c4b51783..f19e520da6d0 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_isr.c
+++ b/drivers/crypto/cavium/nitrox/nitrox_isr.c
@@ -307,6 +307,10 @@ int nitrox_register_interrupts(struct nitrox_device *ndev)
* Entry 192: NPS_CORE_INT_ACTIVE
*/
nr_vecs = pci_msix_vec_count(pdev);
+ if (nr_vecs < 0) {
+ dev_err(DEV(ndev), "Error in getting vec count %d\n", nr_vecs);
+ return nr_vecs;
+ }
/* Enable MSI-X */
ret = pci_alloc_irq_vectors(pdev, nr_vecs, nr_vecs, PCI_IRQ_MSIX);
diff --git a/drivers/crypto/cavium/nitrox/nitrox_main.c b/drivers/crypto/cavium/nitrox/nitrox_main.c
index d385daf2c71c..96bc7b5c6532 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_main.c
+++ b/drivers/crypto/cavium/nitrox/nitrox_main.c
@@ -35,7 +35,7 @@ static LIST_HEAD(ndevlist);
static DEFINE_MUTEX(devlist_lock);
static unsigned int num_devices;
-/**
+/*
* nitrox_pci_tbl - PCI Device ID Table
*/
static const struct pci_device_id nitrox_pci_tbl[] = {
@@ -65,7 +65,7 @@ struct ucode {
u64 code[];
};
-/**
+/*
* write_to_ucd_unit - Write Firmware to NITROX UCD unit
*/
static void write_to_ucd_unit(struct nitrox_device *ndev, u32 ucode_size,
@@ -424,8 +424,7 @@ static int nitrox_probe(struct pci_dev *pdev,
err = nitrox_device_flr(pdev);
if (err) {
dev_err(&pdev->dev, "FLR failed\n");
- pci_disable_device(pdev);
- return err;
+ goto flr_fail;
}
if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
@@ -434,16 +433,13 @@ static int nitrox_probe(struct pci_dev *pdev,
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (err) {
dev_err(&pdev->dev, "DMA configuration failed\n");
- pci_disable_device(pdev);
- return err;
+ goto flr_fail;
}
}
err = pci_request_mem_regions(pdev, nitrox_driver_name);
- if (err) {
- pci_disable_device(pdev);
- return err;
- }
+ if (err)
+ goto flr_fail;
pci_set_master(pdev);
ndev = kzalloc(sizeof(*ndev), GFP_KERNEL);
@@ -479,7 +475,7 @@ static int nitrox_probe(struct pci_dev *pdev,
err = nitrox_pf_sw_init(ndev);
if (err)
- goto ioremap_err;
+ goto pf_sw_fail;
err = nitrox_pf_hw_init(ndev);
if (err)
@@ -509,12 +505,15 @@ crypto_fail:
smp_mb__after_atomic();
pf_hw_fail:
nitrox_pf_sw_cleanup(ndev);
+pf_sw_fail:
+ iounmap(ndev->bar_addr);
ioremap_err:
nitrox_remove_from_devlist(ndev);
kfree(ndev);
pci_set_drvdata(pdev, NULL);
ndev_fail:
pci_release_mem_regions(pdev);
+flr_fail:
pci_disable_device(pdev);
return err;
}
diff --git a/drivers/crypto/cavium/nitrox/nitrox_mbx.c b/drivers/crypto/cavium/nitrox/nitrox_mbx.c
index c1af9d4fca6e..2e9c0d214363 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_mbx.c
+++ b/drivers/crypto/cavium/nitrox/nitrox_mbx.c
@@ -8,7 +8,7 @@
#define RING_TO_VFNO(_x, _y) ((_x) / (_y))
-/**
+/*
* mbx_msg_type - Mailbox message types
*/
enum mbx_msg_type {
@@ -18,7 +18,7 @@ enum mbx_msg_type {
MBX_MSG_TYPE_NACK,
};
-/**
+/*
* mbx_msg_opcode - Mailbox message opcodes
*/
enum mbx_msg_opcode {
diff --git a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c
index df95ba26b414..55c18da4a500 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c
+++ b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c
@@ -19,7 +19,7 @@
#define REQ_BACKLOG 2
#define REQ_POSTED 3
-/**
+/*
* Response codes from SE microcode
* 0x00 - Success
* Completion with no error
@@ -159,7 +159,7 @@ static int dma_map_inbufs(struct nitrox_softreq *sr,
struct se_crypto_request *req)
{
struct device *dev = DEV(sr->ndev);
- struct scatterlist *sg = req->src;
+ struct scatterlist *sg;
int i, nents, ret = 0;
nents = dma_map_sg(dev, req->src, sg_nents(req->src),
@@ -279,6 +279,7 @@ static inline bool cmdq_full(struct nitrox_cmdq *cmdq, int qlen)
/**
* post_se_instr - Post SE instruction to Packet Input ring
* @sr: Request structure
+ * @cmdq: Command queue structure
*
* Returns 0 if successful or a negative error code,
* if no space in ring.
@@ -369,9 +370,11 @@ static int nitrox_enqueue_request(struct nitrox_softreq *sr)
}
/**
- * nitrox_se_request - Send request to SE core
+ * nitrox_process_se_request - Send request to SE core
* @ndev: NITROX device
* @req: Crypto request
+ * @callback: Completion callback
+ * @cb_arg: Completion callback arguments
*
* Returns 0 on success, or a negative error code.
*/
@@ -526,9 +529,8 @@ static bool sr_completed(struct nitrox_softreq *sr)
}
/**
- * process_request_list - process completed requests
- * @ndev: N5 device
- * @qno: queue to operate
+ * process_response_list - process completed requests
+ * @cmdq: Command queue structure
*
* Returns the number of responses processed.
*/
@@ -578,7 +580,7 @@ static void process_response_list(struct nitrox_cmdq *cmdq)
}
}
-/**
+/*
* pkt_slc_resp_tasklet - post processing of SE responses
*/
void pkt_slc_resp_tasklet(unsigned long data)
diff --git a/drivers/crypto/cavium/nitrox/nitrox_skcipher.c b/drivers/crypto/cavium/nitrox/nitrox_skcipher.c
index a553ac65f324..248b4fff1c72 100644
--- a/drivers/crypto/cavium/nitrox/nitrox_skcipher.c
+++ b/drivers/crypto/cavium/nitrox/nitrox_skcipher.c
@@ -20,7 +20,7 @@ struct nitrox_cipher {
enum flexi_cipher value;
};
-/**
+/*
* supported cipher list
*/
static const struct nitrox_cipher flexi_cipher_table[] = {
diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c
index 6777582aa1ce..9ce4b68e9c48 100644
--- a/drivers/crypto/ccp/ccp-dev.c
+++ b/drivers/crypto/ccp/ccp-dev.c
@@ -470,7 +470,7 @@ int ccp_cmd_queue_thread(void *data)
/**
* ccp_alloc_struct - allocate and initialize the ccp_device struct
*
- * @dev: device struct of the CCP
+ * @sp: sp_device struct of the CCP
*/
struct ccp_device *ccp_alloc_struct(struct sp_device *sp)
{
diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c
index 0770a83bf1a5..d718db224be4 100644
--- a/drivers/crypto/ccp/ccp-dmaengine.c
+++ b/drivers/crypto/ccp/ccp-dmaengine.c
@@ -307,8 +307,7 @@ static dma_cookie_t ccp_tx_submit(struct dma_async_tx_descriptor *tx_desc)
spin_lock_irqsave(&chan->lock, flags);
cookie = dma_cookie_assign(tx_desc);
- list_del(&desc->entry);
- list_add_tail(&desc->entry, &chan->pending);
+ list_move_tail(&desc->entry, &chan->pending);
spin_unlock_irqrestore(&chan->lock, flags);
diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
index 3506b2050fb8..91808402e0bf 100644
--- a/drivers/crypto/ccp/sev-dev.c
+++ b/drivers/crypto/ccp/sev-dev.c
@@ -43,6 +43,10 @@ static int psp_probe_timeout = 5;
module_param(psp_probe_timeout, int, 0644);
MODULE_PARM_DESC(psp_probe_timeout, " default timeout value, in seconds, during PSP device probe");
+MODULE_FIRMWARE("amd/amd_sev_fam17h_model0xh.sbin"); /* 1st gen EPYC */
+MODULE_FIRMWARE("amd/amd_sev_fam17h_model3xh.sbin"); /* 2nd gen EPYC */
+MODULE_FIRMWARE("amd/amd_sev_fam19h_model0xh.sbin"); /* 3rd gen EPYC */
+
static bool psp_dead;
static int psp_timeout;
diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c
index f468594ef8af..6fb6ba35f89d 100644
--- a/drivers/crypto/ccp/sp-pci.c
+++ b/drivers/crypto/ccp/sp-pci.c
@@ -222,7 +222,7 @@ static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret) {
dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n",
ret);
- goto e_err;
+ goto free_irqs;
}
}
@@ -230,10 +230,12 @@ static int sp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ret = sp_init(sp);
if (ret)
- goto e_err;
+ goto free_irqs;
return 0;
+free_irqs:
+ sp_free_irqs(sp);
e_err:
dev_notice(dev, "initialization failed\n");
return ret;
diff --git a/drivers/crypto/gemini/Makefile b/drivers/crypto/gemini/Makefile
new file mode 100644
index 000000000000..c73c8b69260d
--- /dev/null
+++ b/drivers/crypto/gemini/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_CRYPTO_DEV_SL3516) += sl3516-ce.o
+sl3516-ce-y += sl3516-ce-core.o sl3516-ce-cipher.o sl3516-ce-rng.o
diff --git a/drivers/crypto/gemini/sl3516-ce-cipher.c b/drivers/crypto/gemini/sl3516-ce-cipher.c
new file mode 100644
index 000000000000..c1c2b1d86663
--- /dev/null
+++ b/drivers/crypto/gemini/sl3516-ce-cipher.c
@@ -0,0 +1,387 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sl3516-ce-cipher.c - hardware cryptographic offloader for Storlink SL3516 SoC
+ *
+ * Copyright (C) 2021 Corentin LABBE <clabbe@baylibre.com>
+ *
+ * This file adds support for AES cipher with 128,192,256 bits keysize in
+ * ECB mode.
+ */
+
+#include <linux/crypto.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/internal/skcipher.h>
+#include "sl3516-ce.h"
+
+/* sl3516_ce_need_fallback - check if a request can be handled by the CE */
+static bool sl3516_ce_need_fallback(struct skcipher_request *areq)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+ struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+ struct sl3516_ce_dev *ce = op->ce;
+ struct scatterlist *in_sg = areq->src;
+ struct scatterlist *out_sg = areq->dst;
+ struct scatterlist *sg;
+
+ if (areq->cryptlen == 0 || areq->cryptlen % 16) {
+ ce->fallback_mod16++;
+ return true;
+ }
+
+ /*
+ * check if we have enough descriptors for TX
+ * Note: TX need one control desc for each SG
+ */
+ if (sg_nents(areq->src) > MAXDESC / 2) {
+ ce->fallback_sg_count_tx++;
+ return true;
+ }
+ /* check if we have enough descriptors for RX */
+ if (sg_nents(areq->dst) > MAXDESC) {
+ ce->fallback_sg_count_rx++;
+ return true;
+ }
+
+ sg = areq->src;
+ while (sg) {
+ if ((sg->length % 16) != 0) {
+ ce->fallback_mod16++;
+ return true;
+ }
+ if ((sg_dma_len(sg) % 16) != 0) {
+ ce->fallback_mod16++;
+ return true;
+ }
+ if (!IS_ALIGNED(sg->offset, 16)) {
+ ce->fallback_align16++;
+ return true;
+ }
+ sg = sg_next(sg);
+ }
+ sg = areq->dst;
+ while (sg) {
+ if ((sg->length % 16) != 0) {
+ ce->fallback_mod16++;
+ return true;
+ }
+ if ((sg_dma_len(sg) % 16) != 0) {
+ ce->fallback_mod16++;
+ return true;
+ }
+ if (!IS_ALIGNED(sg->offset, 16)) {
+ ce->fallback_align16++;
+ return true;
+ }
+ sg = sg_next(sg);
+ }
+
+ /* need same numbers of SG (with same length) for source and destination */
+ in_sg = areq->src;
+ out_sg = areq->dst;
+ while (in_sg && out_sg) {
+ if (in_sg->length != out_sg->length) {
+ ce->fallback_not_same_len++;
+ return true;
+ }
+ in_sg = sg_next(in_sg);
+ out_sg = sg_next(out_sg);
+ }
+ if (in_sg || out_sg)
+ return true;
+
+ return false;
+}
+
+static int sl3516_ce_cipher_fallback(struct skcipher_request *areq)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+ struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+ struct sl3516_ce_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ struct sl3516_ce_alg_template *algt;
+ int err;
+
+ algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher);
+ algt->stat_fb++;
+
+ skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm);
+ skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags,
+ areq->base.complete, areq->base.data);
+ skcipher_request_set_crypt(&rctx->fallback_req, areq->src, areq->dst,
+ areq->cryptlen, areq->iv);
+ if (rctx->op_dir == CE_DECRYPTION)
+ err = crypto_skcipher_decrypt(&rctx->fallback_req);
+ else
+ err = crypto_skcipher_encrypt(&rctx->fallback_req);
+ return err;
+}
+
+static int sl3516_ce_cipher(struct skcipher_request *areq)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+ struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+ struct sl3516_ce_dev *ce = op->ce;
+ struct sl3516_ce_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ struct sl3516_ce_alg_template *algt;
+ struct scatterlist *sg;
+ unsigned int todo, len;
+ struct pkt_control_ecb *ecb;
+ int nr_sgs = 0;
+ int nr_sgd = 0;
+ int err = 0;
+ int i;
+
+ algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher);
+
+ dev_dbg(ce->dev, "%s %s %u %x IV(%p %u) key=%u\n", __func__,
+ crypto_tfm_alg_name(areq->base.tfm),
+ areq->cryptlen,
+ rctx->op_dir, areq->iv, crypto_skcipher_ivsize(tfm),
+ op->keylen);
+
+ algt->stat_req++;
+
+ if (areq->src == areq->dst) {
+ nr_sgs = dma_map_sg(ce->dev, areq->src, sg_nents(areq->src),
+ DMA_BIDIRECTIONAL);
+ if (nr_sgs <= 0 || nr_sgs > MAXDESC / 2) {
+ dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs);
+ err = -EINVAL;
+ goto theend;
+ }
+ nr_sgd = nr_sgs;
+ } else {
+ nr_sgs = dma_map_sg(ce->dev, areq->src, sg_nents(areq->src),
+ DMA_TO_DEVICE);
+ if (nr_sgs <= 0 || nr_sgs > MAXDESC / 2) {
+ dev_err(ce->dev, "Invalid sg number %d\n", nr_sgs);
+ err = -EINVAL;
+ goto theend;
+ }
+ nr_sgd = dma_map_sg(ce->dev, areq->dst, sg_nents(areq->dst),
+ DMA_FROM_DEVICE);
+ if (nr_sgd <= 0 || nr_sgd > MAXDESC) {
+ dev_err(ce->dev, "Invalid sg number %d\n", nr_sgd);
+ err = -EINVAL;
+ goto theend_sgs;
+ }
+ }
+
+ len = areq->cryptlen;
+ i = 0;
+ sg = areq->src;
+ while (i < nr_sgs && sg && len) {
+ if (sg_dma_len(sg) == 0)
+ goto sgs_next;
+ rctx->t_src[i].addr = sg_dma_address(sg);
+ todo = min(len, sg_dma_len(sg));
+ rctx->t_src[i].len = todo;
+ dev_dbg(ce->dev, "%s total=%u SGS(%d %u off=%d) todo=%u\n", __func__,
+ areq->cryptlen, i, rctx->t_src[i].len, sg->offset, todo);
+ len -= todo;
+ i++;
+sgs_next:
+ sg = sg_next(sg);
+ }
+ if (len > 0) {
+ dev_err(ce->dev, "remaining len %d/%u nr_sgs=%d\n", len, areq->cryptlen, nr_sgs);
+ err = -EINVAL;
+ goto theend_sgs;
+ }
+
+ len = areq->cryptlen;
+ i = 0;
+ sg = areq->dst;
+ while (i < nr_sgd && sg && len) {
+ if (sg_dma_len(sg) == 0)
+ goto sgd_next;
+ rctx->t_dst[i].addr = sg_dma_address(sg);
+ todo = min(len, sg_dma_len(sg));
+ rctx->t_dst[i].len = todo;
+ dev_dbg(ce->dev, "%s total=%u SGD(%d %u off=%d) todo=%u\n", __func__,
+ areq->cryptlen, i, rctx->t_dst[i].len, sg->offset, todo);
+ len -= todo;
+ i++;
+
+sgd_next:
+ sg = sg_next(sg);
+ }
+ if (len > 0) {
+ dev_err(ce->dev, "remaining len %d\n", len);
+ err = -EINVAL;
+ goto theend_sgs;
+ }
+
+ switch (algt->mode) {
+ case ECB_AES:
+ rctx->pctrllen = sizeof(struct pkt_control_ecb);
+ ecb = (struct pkt_control_ecb *)ce->pctrl;
+
+ rctx->tqflag = TQ0_TYPE_CTRL;
+ rctx->tqflag |= TQ1_CIPHER;
+ ecb->control.op_mode = rctx->op_dir;
+ ecb->control.cipher_algorithm = ECB_AES;
+ ecb->cipher.header_len = 0;
+ ecb->cipher.algorithm_len = areq->cryptlen;
+ cpu_to_be32_array((__be32 *)ecb->key, (u32 *)op->key, op->keylen / 4);
+ rctx->h = &ecb->cipher;
+
+ rctx->tqflag |= TQ4_KEY0;
+ rctx->tqflag |= TQ5_KEY4;
+ rctx->tqflag |= TQ6_KEY6;
+ ecb->control.aesnk = op->keylen / 4;
+ break;
+ }
+
+ rctx->nr_sgs = nr_sgs;
+ rctx->nr_sgd = nr_sgd;
+ err = sl3516_ce_run_task(ce, rctx, crypto_tfm_alg_name(areq->base.tfm));
+
+theend_sgs:
+ if (areq->src == areq->dst) {
+ dma_unmap_sg(ce->dev, areq->src, sg_nents(areq->src),
+ DMA_BIDIRECTIONAL);
+ } else {
+ dma_unmap_sg(ce->dev, areq->src, sg_nents(areq->src),
+ DMA_TO_DEVICE);
+ dma_unmap_sg(ce->dev, areq->dst, sg_nents(areq->dst),
+ DMA_FROM_DEVICE);
+ }
+
+theend:
+
+ return err;
+}
+
+static int sl3516_ce_handle_cipher_request(struct crypto_engine *engine, void *areq)
+{
+ int err;
+ struct skcipher_request *breq = container_of(areq, struct skcipher_request, base);
+
+ err = sl3516_ce_cipher(breq);
+ crypto_finalize_skcipher_request(engine, breq, err);
+
+ return 0;
+}
+
+int sl3516_ce_skdecrypt(struct skcipher_request *areq)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+ struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+ struct sl3516_ce_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
+ struct crypto_engine *engine;
+
+ memset(rctx, 0, sizeof(struct sl3516_ce_cipher_req_ctx));
+ rctx->op_dir = CE_DECRYPTION;
+
+ if (sl3516_ce_need_fallback(areq))
+ return sl3516_ce_cipher_fallback(areq);
+
+ engine = op->ce->engine;
+
+ return crypto_transfer_skcipher_request_to_engine(engine, areq);
+}
+
+int sl3516_ce_skencrypt(struct skcipher_request *areq)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+ struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+ struct sl3516_ce_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
+ struct crypto_engine *engine;
+
+ memset(rctx, 0, sizeof(struct sl3516_ce_cipher_req_ctx));
+ rctx->op_dir = CE_ENCRYPTION;
+
+ if (sl3516_ce_need_fallback(areq))
+ return sl3516_ce_cipher_fallback(areq);
+
+ engine = op->ce->engine;
+
+ return crypto_transfer_skcipher_request_to_engine(engine, areq);
+}
+
+int sl3516_ce_cipher_init(struct crypto_tfm *tfm)
+{
+ struct sl3516_ce_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm);
+ struct sl3516_ce_alg_template *algt;
+ const char *name = crypto_tfm_alg_name(tfm);
+ struct crypto_skcipher *sktfm = __crypto_skcipher_cast(tfm);
+ struct skcipher_alg *alg = crypto_skcipher_alg(sktfm);
+ int err;
+
+ memset(op, 0, sizeof(struct sl3516_ce_cipher_tfm_ctx));
+
+ algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher);
+ op->ce = algt->ce;
+
+ op->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(op->fallback_tfm)) {
+ dev_err(op->ce->dev, "ERROR: Cannot allocate fallback for %s %ld\n",
+ name, PTR_ERR(op->fallback_tfm));
+ return PTR_ERR(op->fallback_tfm);
+ }
+
+ sktfm->reqsize = sizeof(struct sl3516_ce_cipher_req_ctx) +
+ crypto_skcipher_reqsize(op->fallback_tfm);
+
+ dev_info(op->ce->dev, "Fallback for %s is %s\n",
+ crypto_tfm_alg_driver_name(&sktfm->base),
+ crypto_tfm_alg_driver_name(crypto_skcipher_tfm(op->fallback_tfm)));
+
+ op->enginectx.op.do_one_request = sl3516_ce_handle_cipher_request;
+ op->enginectx.op.prepare_request = NULL;
+ op->enginectx.op.unprepare_request = NULL;
+
+ err = pm_runtime_get_sync(op->ce->dev);
+ if (err < 0)
+ goto error_pm;
+
+ return 0;
+error_pm:
+ pm_runtime_put_noidle(op->ce->dev);
+ crypto_free_skcipher(op->fallback_tfm);
+ return err;
+}
+
+void sl3516_ce_cipher_exit(struct crypto_tfm *tfm)
+{
+ struct sl3516_ce_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm);
+
+ kfree_sensitive(op->key);
+ crypto_free_skcipher(op->fallback_tfm);
+ pm_runtime_put_sync_suspend(op->ce->dev);
+}
+
+int sl3516_ce_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct sl3516_ce_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
+ struct sl3516_ce_dev *ce = op->ce;
+
+ switch (keylen) {
+ case 128 / 8:
+ break;
+ case 192 / 8:
+ break;
+ case 256 / 8:
+ break;
+ default:
+ dev_dbg(ce->dev, "ERROR: Invalid keylen %u\n", keylen);
+ return -EINVAL;
+ }
+ kfree_sensitive(op->key);
+ op->keylen = keylen;
+ op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
+ if (!op->key)
+ return -ENOMEM;
+
+ crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
+ crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
+
+ return crypto_skcipher_setkey(op->fallback_tfm, key, keylen);
+}
diff --git a/drivers/crypto/gemini/sl3516-ce-core.c b/drivers/crypto/gemini/sl3516-ce-core.c
new file mode 100644
index 000000000000..b7524b649068
--- /dev/null
+++ b/drivers/crypto/gemini/sl3516-ce-core.c
@@ -0,0 +1,535 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sl3516-ce-core.c - hardware cryptographic offloader for Storlink SL3516 SoC
+ *
+ * Copyright (C) 2021 Corentin Labbe <clabbe@baylibre.com>
+ *
+ * Core file which registers crypto algorithms supported by the CryptoEngine
+ */
+#include <linux/clk.h>
+#include <linux/crypto.h>
+#include <linux/debugfs.h>
+#include <linux/dev_printk.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <crypto/internal/rng.h>
+#include <crypto/internal/skcipher.h>
+
+#include "sl3516-ce.h"
+
+static int sl3516_ce_desc_init(struct sl3516_ce_dev *ce)
+{
+ const size_t sz = sizeof(struct descriptor) * MAXDESC;
+ int i;
+
+ ce->tx = dma_alloc_coherent(ce->dev, sz, &ce->dtx, GFP_KERNEL);
+ if (!ce->tx)
+ return -ENOMEM;
+ ce->rx = dma_alloc_coherent(ce->dev, sz, &ce->drx, GFP_KERNEL);
+ if (!ce->rx)
+ goto err_rx;
+
+ for (i = 0; i < MAXDESC; i++) {
+ ce->tx[i].frame_ctrl.bits.own = CE_CPU;
+ ce->tx[i].next_desc.next_descriptor = ce->dtx + (i + 1) * sizeof(struct descriptor);
+ }
+ ce->tx[MAXDESC - 1].next_desc.next_descriptor = ce->dtx;
+
+ for (i = 0; i < MAXDESC; i++) {
+ ce->rx[i].frame_ctrl.bits.own = CE_CPU;
+ ce->rx[i].next_desc.next_descriptor = ce->drx + (i + 1) * sizeof(struct descriptor);
+ }
+ ce->rx[MAXDESC - 1].next_desc.next_descriptor = ce->drx;
+
+ ce->pctrl = dma_alloc_coherent(ce->dev, sizeof(struct pkt_control_ecb),
+ &ce->dctrl, GFP_KERNEL);
+ if (!ce->pctrl)
+ goto err_pctrl;
+
+ return 0;
+err_pctrl:
+ dma_free_coherent(ce->dev, sz, ce->rx, ce->drx);
+err_rx:
+ dma_free_coherent(ce->dev, sz, ce->tx, ce->dtx);
+ return -ENOMEM;
+}
+
+static void sl3516_ce_free_descs(struct sl3516_ce_dev *ce)
+{
+ const size_t sz = sizeof(struct descriptor) * MAXDESC;
+
+ dma_free_coherent(ce->dev, sz, ce->tx, ce->dtx);
+ dma_free_coherent(ce->dev, sz, ce->rx, ce->drx);
+ dma_free_coherent(ce->dev, sizeof(struct pkt_control_ecb), ce->pctrl,
+ ce->dctrl);
+}
+
+static void start_dma_tx(struct sl3516_ce_dev *ce)
+{
+ u32 v;
+
+ v = TXDMA_CTRL_START | TXDMA_CTRL_CHAIN_MODE | TXDMA_CTRL_CONTINUE | \
+ TXDMA_CTRL_INT_FAIL | TXDMA_CTRL_INT_PERR | TXDMA_CTRL_BURST_UNK;
+
+ writel(v, ce->base + IPSEC_TXDMA_CTRL);
+}
+
+static void start_dma_rx(struct sl3516_ce_dev *ce)
+{
+ u32 v;
+
+ v = RXDMA_CTRL_START | RXDMA_CTRL_CHAIN_MODE | RXDMA_CTRL_CONTINUE | \
+ RXDMA_CTRL_BURST_UNK | RXDMA_CTRL_INT_FINISH | \
+ RXDMA_CTRL_INT_FAIL | RXDMA_CTRL_INT_PERR | \
+ RXDMA_CTRL_INT_EOD | RXDMA_CTRL_INT_EOF;
+
+ writel(v, ce->base + IPSEC_RXDMA_CTRL);
+}
+
+static struct descriptor *get_desc_tx(struct sl3516_ce_dev *ce)
+{
+ struct descriptor *dd;
+
+ dd = &ce->tx[ce->ctx];
+ ce->ctx++;
+ if (ce->ctx >= MAXDESC)
+ ce->ctx = 0;
+ return dd;
+}
+
+static struct descriptor *get_desc_rx(struct sl3516_ce_dev *ce)
+{
+ struct descriptor *rdd;
+
+ rdd = &ce->rx[ce->crx];
+ ce->crx++;
+ if (ce->crx >= MAXDESC)
+ ce->crx = 0;
+ return rdd;
+}
+
+int sl3516_ce_run_task(struct sl3516_ce_dev *ce, struct sl3516_ce_cipher_req_ctx *rctx,
+ const char *name)
+{
+ struct descriptor *dd, *rdd = NULL;
+ u32 v;
+ int i, err = 0;
+
+ ce->stat_req++;
+
+ reinit_completion(&ce->complete);
+ ce->status = 0;
+
+ for (i = 0; i < rctx->nr_sgd; i++) {
+ dev_dbg(ce->dev, "%s handle DST SG %d/%d len=%d\n", __func__,
+ i, rctx->nr_sgd, rctx->t_dst[i].len);
+ rdd = get_desc_rx(ce);
+ rdd->buf_adr = rctx->t_dst[i].addr;
+ rdd->frame_ctrl.bits.buffer_size = rctx->t_dst[i].len;
+ rdd->frame_ctrl.bits.own = CE_DMA;
+ }
+ rdd->next_desc.bits.eofie = 1;
+
+ for (i = 0; i < rctx->nr_sgs; i++) {
+ dev_dbg(ce->dev, "%s handle SRC SG %d/%d len=%d\n", __func__,
+ i, rctx->nr_sgs, rctx->t_src[i].len);
+ rctx->h->algorithm_len = rctx->t_src[i].len;
+
+ dd = get_desc_tx(ce);
+ dd->frame_ctrl.raw = 0;
+ dd->flag_status.raw = 0;
+ dd->frame_ctrl.bits.buffer_size = rctx->pctrllen;
+ dd->buf_adr = ce->dctrl;
+ dd->flag_status.tx_flag.tqflag = rctx->tqflag;
+ dd->next_desc.bits.eofie = 0;
+ dd->next_desc.bits.dec = 0;
+ dd->next_desc.bits.sof_eof = DESC_FIRST | DESC_LAST;
+ dd->frame_ctrl.bits.own = CE_DMA;
+
+ dd = get_desc_tx(ce);
+ dd->frame_ctrl.raw = 0;
+ dd->flag_status.raw = 0;
+ dd->frame_ctrl.bits.buffer_size = rctx->t_src[i].len;
+ dd->buf_adr = rctx->t_src[i].addr;
+ dd->flag_status.tx_flag.tqflag = 0;
+ dd->next_desc.bits.eofie = 0;
+ dd->next_desc.bits.dec = 0;
+ dd->next_desc.bits.sof_eof = DESC_FIRST | DESC_LAST;
+ dd->frame_ctrl.bits.own = CE_DMA;
+ start_dma_tx(ce);
+ start_dma_rx(ce);
+ }
+ wait_for_completion_interruptible_timeout(&ce->complete,
+ msecs_to_jiffies(5000));
+ if (ce->status == 0) {
+ dev_err(ce->dev, "DMA timeout for %s\n", name);
+ err = -EFAULT;
+ }
+ v = readl(ce->base + IPSEC_STATUS_REG);
+ if (v & 0xFFF) {
+ dev_err(ce->dev, "IPSEC_STATUS_REG %x\n", v);
+ err = -EFAULT;
+ }
+
+ return err;
+}
+
+static irqreturn_t ce_irq_handler(int irq, void *data)
+{
+ struct sl3516_ce_dev *ce = (struct sl3516_ce_dev *)data;
+ u32 v;
+
+ ce->stat_irq++;
+
+ v = readl(ce->base + IPSEC_DMA_STATUS);
+ writel(v, ce->base + IPSEC_DMA_STATUS);
+
+ if (v & DMA_STATUS_TS_DERR)
+ dev_err(ce->dev, "AHB bus Error While Tx !!!\n");
+ if (v & DMA_STATUS_TS_PERR)
+ dev_err(ce->dev, "Tx Descriptor Protocol Error !!!\n");
+ if (v & DMA_STATUS_RS_DERR)
+ dev_err(ce->dev, "AHB bus Error While Rx !!!\n");
+ if (v & DMA_STATUS_RS_PERR)
+ dev_err(ce->dev, "Rx Descriptor Protocol Error !!!\n");
+
+ if (v & DMA_STATUS_TS_EOFI)
+ ce->stat_irq_tx++;
+ if (v & DMA_STATUS_RS_EOFI) {
+ ce->status = 1;
+ complete(&ce->complete);
+ ce->stat_irq_rx++;
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct sl3516_ce_alg_template ce_algs[] = {
+{
+ .type = CRYPTO_ALG_TYPE_SKCIPHER,
+ .mode = ECB_AES,
+ .alg.skcipher = {
+ .base = {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "ecb-aes-sl3516",
+ .cra_priority = 400,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |
+ CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
+ .cra_ctxsize = sizeof(struct sl3516_ce_cipher_tfm_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_alignmask = 0xf,
+ .cra_init = sl3516_ce_cipher_init,
+ .cra_exit = sl3516_ce_cipher_exit,
+ },
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = sl3516_ce_aes_setkey,
+ .encrypt = sl3516_ce_skencrypt,
+ .decrypt = sl3516_ce_skdecrypt,
+ }
+},
+};
+
+#ifdef CONFIG_CRYPTO_DEV_SL3516_DEBUG
+static int sl3516_ce_debugfs_show(struct seq_file *seq, void *v)
+{
+ struct sl3516_ce_dev *ce = seq->private;
+ unsigned int i;
+
+ seq_printf(seq, "HWRNG %lu %lu\n",
+ ce->hwrng_stat_req, ce->hwrng_stat_bytes);
+ seq_printf(seq, "IRQ %lu\n", ce->stat_irq);
+ seq_printf(seq, "IRQ TX %lu\n", ce->stat_irq_tx);
+ seq_printf(seq, "IRQ RX %lu\n", ce->stat_irq_rx);
+ seq_printf(seq, "nreq %lu\n", ce->stat_req);
+ seq_printf(seq, "fallback SG count TX %lu\n", ce->fallback_sg_count_tx);
+ seq_printf(seq, "fallback SG count RX %lu\n", ce->fallback_sg_count_rx);
+ seq_printf(seq, "fallback modulo16 %lu\n", ce->fallback_mod16);
+ seq_printf(seq, "fallback align16 %lu\n", ce->fallback_align16);
+ seq_printf(seq, "fallback not same len %lu\n", ce->fallback_not_same_len);
+
+ for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {
+ if (!ce_algs[i].ce)
+ continue;
+ switch (ce_algs[i].type) {
+ case CRYPTO_ALG_TYPE_SKCIPHER:
+ seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
+ ce_algs[i].alg.skcipher.base.cra_driver_name,
+ ce_algs[i].alg.skcipher.base.cra_name,
+ ce_algs[i].stat_req, ce_algs[i].stat_fb);
+ break;
+ }
+ }
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(sl3516_ce_debugfs);
+#endif
+
+static int sl3516_ce_register_algs(struct sl3516_ce_dev *ce)
+{
+ int err;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {
+ ce_algs[i].ce = ce;
+ switch (ce_algs[i].type) {
+ case CRYPTO_ALG_TYPE_SKCIPHER:
+ dev_info(ce->dev, "DEBUG: Register %s\n",
+ ce_algs[i].alg.skcipher.base.cra_name);
+ err = crypto_register_skcipher(&ce_algs[i].alg.skcipher);
+ if (err) {
+ dev_err(ce->dev, "Fail to register %s\n",
+ ce_algs[i].alg.skcipher.base.cra_name);
+ ce_algs[i].ce = NULL;
+ return err;
+ }
+ break;
+ default:
+ ce_algs[i].ce = NULL;
+ dev_err(ce->dev, "ERROR: tried to register an unknown algo\n");
+ }
+ }
+ return 0;
+}
+
+static void sl3516_ce_unregister_algs(struct sl3516_ce_dev *ce)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {
+ if (!ce_algs[i].ce)
+ continue;
+ switch (ce_algs[i].type) {
+ case CRYPTO_ALG_TYPE_SKCIPHER:
+ dev_info(ce->dev, "Unregister %d %s\n", i,
+ ce_algs[i].alg.skcipher.base.cra_name);
+ crypto_unregister_skcipher(&ce_algs[i].alg.skcipher);
+ break;
+ }
+ }
+}
+
+static void sl3516_ce_start(struct sl3516_ce_dev *ce)
+{
+ ce->ctx = 0;
+ ce->crx = 0;
+ writel(ce->dtx, ce->base + IPSEC_TXDMA_CURR_DESC);
+ writel(ce->drx, ce->base + IPSEC_RXDMA_CURR_DESC);
+ writel(0, ce->base + IPSEC_DMA_STATUS);
+}
+
+/*
+ * Power management strategy: The device is suspended unless a TFM exists for
+ * one of the algorithms proposed by this driver.
+ */
+static int sl3516_ce_pm_suspend(struct device *dev)
+{
+ struct sl3516_ce_dev *ce = dev_get_drvdata(dev);
+
+ reset_control_assert(ce->reset);
+ clk_disable_unprepare(ce->clks);
+ return 0;
+}
+
+static int sl3516_ce_pm_resume(struct device *dev)
+{
+ struct sl3516_ce_dev *ce = dev_get_drvdata(dev);
+ int err;
+
+ err = clk_prepare_enable(ce->clks);
+ if (err) {
+ dev_err(ce->dev, "Cannot prepare_enable\n");
+ goto error;
+ }
+ err = reset_control_deassert(ce->reset);
+ if (err) {
+ dev_err(ce->dev, "Cannot deassert reset control\n");
+ goto error;
+ }
+
+ sl3516_ce_start(ce);
+
+ return 0;
+error:
+ sl3516_ce_pm_suspend(dev);
+ return err;
+}
+
+static const struct dev_pm_ops sl3516_ce_pm_ops = {
+ SET_RUNTIME_PM_OPS(sl3516_ce_pm_suspend, sl3516_ce_pm_resume, NULL)
+};
+
+static int sl3516_ce_pm_init(struct sl3516_ce_dev *ce)
+{
+ int err;
+
+ pm_runtime_use_autosuspend(ce->dev);
+ pm_runtime_set_autosuspend_delay(ce->dev, 2000);
+
+ err = pm_runtime_set_suspended(ce->dev);
+ if (err)
+ return err;
+ pm_runtime_enable(ce->dev);
+ return err;
+}
+
+static void sl3516_ce_pm_exit(struct sl3516_ce_dev *ce)
+{
+ pm_runtime_disable(ce->dev);
+}
+
+static int sl3516_ce_probe(struct platform_device *pdev)
+{
+ struct sl3516_ce_dev *ce;
+ int err, irq;
+ u32 v;
+
+ ce = devm_kzalloc(&pdev->dev, sizeof(*ce), GFP_KERNEL);
+ if (!ce)
+ return -ENOMEM;
+
+ ce->dev = &pdev->dev;
+ platform_set_drvdata(pdev, ce);
+
+ ce->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(ce->base))
+ return PTR_ERR(ce->base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ err = devm_request_irq(&pdev->dev, irq, ce_irq_handler, 0, "crypto", ce);
+ if (err) {
+ dev_err(ce->dev, "Cannot request Crypto Engine IRQ (err=%d)\n", err);
+ return err;
+ }
+
+ ce->reset = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(ce->reset))
+ return dev_err_probe(&pdev->dev, PTR_ERR(ce->reset),
+ "No reset control found\n");
+ ce->clks = devm_clk_get(ce->dev, NULL);
+ if (IS_ERR(ce->clks)) {
+ err = PTR_ERR(ce->clks);
+ dev_err(ce->dev, "Cannot get clock err=%d\n", err);
+ return err;
+ }
+
+ err = sl3516_ce_desc_init(ce);
+ if (err)
+ return err;
+
+ err = sl3516_ce_pm_init(ce);
+ if (err)
+ goto error_pm;
+
+ init_completion(&ce->complete);
+
+ ce->engine = crypto_engine_alloc_init(ce->dev, true);
+ if (!ce->engine) {
+ dev_err(ce->dev, "Cannot allocate engine\n");
+ err = -ENOMEM;
+ goto error_engine;
+ }
+
+ err = crypto_engine_start(ce->engine);
+ if (err) {
+ dev_err(ce->dev, "Cannot start engine\n");
+ goto error_engine;
+ }
+
+ err = sl3516_ce_register_algs(ce);
+ if (err)
+ goto error_alg;
+
+ err = sl3516_ce_rng_register(ce);
+ if (err)
+ goto error_rng;
+
+ err = pm_runtime_resume_and_get(ce->dev);
+ if (err < 0)
+ goto error_pmuse;
+
+ v = readl(ce->base + IPSEC_ID);
+ dev_info(ce->dev, "SL3516 dev %lx rev %lx\n",
+ v & GENMASK(31, 4),
+ v & GENMASK(3, 0));
+ v = readl(ce->base + IPSEC_DMA_DEVICE_ID);
+ dev_info(ce->dev, "SL3516 DMA dev %lx rev %lx\n",
+ v & GENMASK(15, 4),
+ v & GENMASK(3, 0));
+
+ pm_runtime_put_sync(ce->dev);
+
+#ifdef CONFIG_CRYPTO_DEV_SL3516_DEBUG
+ /* Ignore error of debugfs */
+ ce->dbgfs_dir = debugfs_create_dir("sl3516", NULL);
+ ce->dbgfs_stats = debugfs_create_file("stats", 0444,
+ ce->dbgfs_dir, ce,
+ &sl3516_ce_debugfs_fops);
+#endif
+
+ return 0;
+error_pmuse:
+ sl3516_ce_rng_unregister(ce);
+error_rng:
+ sl3516_ce_unregister_algs(ce);
+error_alg:
+ crypto_engine_exit(ce->engine);
+error_engine:
+ sl3516_ce_pm_exit(ce);
+error_pm:
+ sl3516_ce_free_descs(ce);
+ return err;
+}
+
+static int sl3516_ce_remove(struct platform_device *pdev)
+{
+ struct sl3516_ce_dev *ce = platform_get_drvdata(pdev);
+
+ sl3516_ce_rng_unregister(ce);
+ sl3516_ce_unregister_algs(ce);
+ crypto_engine_exit(ce->engine);
+ sl3516_ce_pm_exit(ce);
+ sl3516_ce_free_descs(ce);
+
+#ifdef CONFIG_CRYPTO_DEV_SL3516_DEBUG
+ debugfs_remove_recursive(ce->dbgfs_dir);
+#endif
+
+ return 0;
+}
+
+static const struct of_device_id sl3516_ce_crypto_of_match_table[] = {
+ { .compatible = "cortina,sl3516-crypto"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, sl3516_ce_crypto_of_match_table);
+
+static struct platform_driver sl3516_ce_driver = {
+ .probe = sl3516_ce_probe,
+ .remove = sl3516_ce_remove,
+ .driver = {
+ .name = "sl3516-crypto",
+ .pm = &sl3516_ce_pm_ops,
+ .of_match_table = sl3516_ce_crypto_of_match_table,
+ },
+};
+
+module_platform_driver(sl3516_ce_driver);
+
+MODULE_DESCRIPTION("SL3516 cryptographic offloader");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corentin Labbe <clabbe@baylibre.com>");
diff --git a/drivers/crypto/gemini/sl3516-ce-rng.c b/drivers/crypto/gemini/sl3516-ce-rng.c
new file mode 100644
index 000000000000..76931ec1cec5
--- /dev/null
+++ b/drivers/crypto/gemini/sl3516-ce-rng.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sl3516-ce-rng.c - hardware cryptographic offloader for SL3516 SoC.
+ *
+ * Copyright (C) 2021 Corentin Labbe <clabbe@baylibre.com>
+ *
+ * This file handle the RNG found in the SL3516 crypto engine
+ */
+#include "sl3516-ce.h"
+#include <linux/pm_runtime.h>
+#include <linux/hw_random.h>
+
+static int sl3516_ce_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+{
+ struct sl3516_ce_dev *ce;
+ u32 *data = buf;
+ size_t read = 0;
+ int err;
+
+ ce = container_of(rng, struct sl3516_ce_dev, trng);
+
+#ifdef CONFIG_CRYPTO_DEV_SL3516_DEBUG
+ ce->hwrng_stat_req++;
+ ce->hwrng_stat_bytes += max;
+#endif
+
+ err = pm_runtime_get_sync(ce->dev);
+ if (err < 0) {
+ pm_runtime_put_noidle(ce->dev);
+ return err;
+ }
+
+ while (read < max) {
+ *data = readl(ce->base + IPSEC_RAND_NUM_REG);
+ data++;
+ read += 4;
+ }
+
+ pm_runtime_put(ce->dev);
+
+ return read;
+}
+
+int sl3516_ce_rng_register(struct sl3516_ce_dev *ce)
+{
+ int ret;
+
+ ce->trng.name = "SL3516 Crypto Engine RNG";
+ ce->trng.read = sl3516_ce_rng_read;
+ ce->trng.quality = 700;
+
+ ret = hwrng_register(&ce->trng);
+ if (ret)
+ dev_err(ce->dev, "Fail to register the RNG\n");
+ return ret;
+}
+
+void sl3516_ce_rng_unregister(struct sl3516_ce_dev *ce)
+{
+ hwrng_unregister(&ce->trng);
+}
diff --git a/drivers/crypto/gemini/sl3516-ce.h b/drivers/crypto/gemini/sl3516-ce.h
new file mode 100644
index 000000000000..4c0ec6c920d1
--- /dev/null
+++ b/drivers/crypto/gemini/sl3516-ce.h
@@ -0,0 +1,347 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * sl3516-ce.h - hardware cryptographic offloader for cortina/gemini SoC
+ *
+ * Copyright (C) 2021 Corentin LABBE <clabbe@baylibre.com>
+ *
+ * General notes on this driver:
+ * Called either Crypto Acceleration Engine Module, Security Acceleration Engine
+ * or IPSEC module in the datasheet, it will be called Crypto Engine for short
+ * in this driver.
+ * The CE was designed to handle IPSEC and wifi(TKIP WEP) protocol.
+ * It can handle AES, DES, 3DES, MD5, WEP, TKIP, SHA1, HMAC(MD5), HMAC(SHA1),
+ * Michael cipher/digest suites.
+ * It acts the same as a network hw, with both RX and TX chained descriptors.
+ */
+#include <crypto/aes.h>
+#include <crypto/engine.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/skcipher.h>
+#include <linux/crypto.h>
+#include <linux/debugfs.h>
+#include <linux/hw_random.h>
+
+#define TQ0_TYPE_DATA 0
+#define TQ0_TYPE_CTRL BIT(0)
+#define TQ1_CIPHER BIT(1)
+#define TQ2_AUTH BIT(2)
+#define TQ3_IV BIT(3)
+#define TQ4_KEY0 BIT(4)
+#define TQ5_KEY4 BIT(5)
+#define TQ6_KEY6 BIT(6)
+#define TQ7_AKEY0 BIT(7)
+#define TQ8_AKEY2 BIT(8)
+#define TQ9_AKEY2 BIT(9)
+
+#define ECB_AES 0x2
+
+#define DESC_LAST 0x01
+#define DESC_FIRST 0x02
+
+#define IPSEC_ID 0x0000
+#define IPSEC_STATUS_REG 0x00a8
+#define IPSEC_RAND_NUM_REG 0x00ac
+#define IPSEC_DMA_DEVICE_ID 0xff00
+#define IPSEC_DMA_STATUS 0xff04
+#define IPSEC_TXDMA_CTRL 0xff08
+#define IPSEC_TXDMA_FIRST_DESC 0xff0c
+#define IPSEC_TXDMA_CURR_DESC 0xff10
+#define IPSEC_RXDMA_CTRL 0xff14
+#define IPSEC_RXDMA_FIRST_DESC 0xff18
+#define IPSEC_RXDMA_CURR_DESC 0xff1c
+#define IPSEC_TXDMA_BUF_ADDR 0xff28
+#define IPSEC_RXDMA_BUF_ADDR 0xff38
+#define IPSEC_RXDMA_BUF_SIZE 0xff30
+
+#define CE_ENCRYPTION 0x01
+#define CE_DECRYPTION 0x03
+
+#define MAXDESC 6
+
+#define DMA_STATUS_RS_EOFI BIT(22)
+#define DMA_STATUS_RS_PERR BIT(24)
+#define DMA_STATUS_RS_DERR BIT(25)
+#define DMA_STATUS_TS_EOFI BIT(27)
+#define DMA_STATUS_TS_PERR BIT(29)
+#define DMA_STATUS_TS_DERR BIT(30)
+
+#define TXDMA_CTRL_START BIT(31)
+#define TXDMA_CTRL_CONTINUE BIT(30)
+#define TXDMA_CTRL_CHAIN_MODE BIT(29)
+/* the burst value is not documented in the datasheet */
+#define TXDMA_CTRL_BURST_UNK BIT(22)
+#define TXDMA_CTRL_INT_FAIL BIT(17)
+#define TXDMA_CTRL_INT_PERR BIT(16)
+
+#define RXDMA_CTRL_START BIT(31)
+#define RXDMA_CTRL_CONTINUE BIT(30)
+#define RXDMA_CTRL_CHAIN_MODE BIT(29)
+/* the burst value is not documented in the datasheet */
+#define RXDMA_CTRL_BURST_UNK BIT(22)
+#define RXDMA_CTRL_INT_FINISH BIT(18)
+#define RXDMA_CTRL_INT_FAIL BIT(17)
+#define RXDMA_CTRL_INT_PERR BIT(16)
+#define RXDMA_CTRL_INT_EOD BIT(15)
+#define RXDMA_CTRL_INT_EOF BIT(14)
+
+#define CE_CPU 0
+#define CE_DMA 1
+
+/*
+ * struct sl3516_ce_descriptor - descriptor for CE operations
+ * @frame_ctrl: Information for the current descriptor
+ * @flag_status: For send packet, describe flag of operations.
+ * @buf_adr: pointer to a send/recv buffer for data packet
+ * @next_desc: control linking to other descriptors
+ */
+struct descriptor {
+ union {
+ u32 raw;
+ /*
+ * struct desc_frame_ctrl - Information for the current descriptor
+ * @buffer_size: the size of buffer at buf_adr
+ * @desc_count: Upon completion of a DMA operation, DMA
+ * write the number of descriptors used
+ * for the current frame
+ * @checksum: unknown
+ * @authcomp: unknown
+ * @perr: Protocol error during processing this descriptor
+ * @derr: Data error during processing this descriptor
+ * @own: 0 if owned by CPU, 1 for DMA
+ */
+ struct desc_frame_ctrl {
+ u32 buffer_size :16;
+ u32 desc_count :6;
+ u32 checksum :6;
+ u32 authcomp :1;
+ u32 perr :1;
+ u32 derr :1;
+ u32 own :1;
+ } bits;
+ } frame_ctrl;
+
+ union {
+ u32 raw;
+ /*
+ * struct desc_flag_status - flag for this descriptor
+ * @tqflag: list of flag describing the type of operation
+ * to be performed.
+ */
+ struct desc_tx_flag_status {
+ u32 tqflag :10;
+ u32 unused :22;
+ } tx_flag;
+ } flag_status;
+
+ u32 buf_adr;
+
+ union {
+ u32 next_descriptor;
+ /*
+ * struct desc_next - describe chaining of descriptors
+ * @sof_eof: does the descriptor is first (0x11),
+ * the last (0x01), middle of a chan (0x00)
+ * or the only one (0x11)
+ * @dec: AHB bus address increase (0), decrease (1)
+ * @eofie: End of frame interrupt enable
+ * @ndar: Next descriptor address
+ */
+ struct desc_next {
+ u32 sof_eof :2;
+ u32 dec :1;
+ u32 eofie :1;
+ u32 ndar :28;
+ } bits;
+ } next_desc;
+};
+
+/*
+ * struct control - The value of this register is used to set the
+ * operation mode of the IPSec Module.
+ * @process_id: Used to identify the process. The number will be copied
+ * to the descriptor status of the received packet.
+ * @auth_check_len: Number of 32-bit words to be checked or appended by the
+ * authentication module
+ * @auth_algorithm:
+ * @auth_mode: 0:append 1:Check Authentication Result
+ * @fcs_stream_copy: 0:enable 1:disable authentication stream copy
+ * @mix_key_sel: 0:use rCipherKey0-3 1:use Key Mixer
+ * @aesnk: AES Key Size
+ * @cipher_algorithm: choice of CBC/ECE and AES/DES/3DES
+ * @op_mode: Operation Mode for the IPSec Module
+ */
+struct pkt_control_header {
+ u32 process_id :8;
+ u32 auth_check_len :3;
+ u32 un1 :1;
+ u32 auth_algorithm :3;
+ u32 auth_mode :1;
+ u32 fcs_stream_copy :1;
+ u32 un2 :2;
+ u32 mix_key_sel :1;
+ u32 aesnk :4;
+ u32 cipher_algorithm :3;
+ u32 un3 :1;
+ u32 op_mode :4;
+};
+
+struct pkt_control_cipher {
+ u32 algorithm_len :16;
+ u32 header_len :16;
+};
+
+/*
+ * struct pkt_control_ecb - control packet for ECB
+ */
+struct pkt_control_ecb {
+ struct pkt_control_header control;
+ struct pkt_control_cipher cipher;
+ unsigned char key[AES_MAX_KEY_SIZE];
+};
+
+/*
+ * struct sl3516_ce_dev - main container for all this driver information
+ * @base: base address
+ * @clks: clocks used
+ * @reset: pointer to reset controller
+ * @dev: the platform device
+ * @engine: ptr to the crypto/crypto_engine
+ * @complete: completion for the current task on this flow
+ * @status: set to 1 by interrupt if task is done
+ * @dtx: base DMA address for TX descriptors
+ * @tx base address of TX descriptors
+ * @drx: base DMA address for RX descriptors
+ * @rx base address of RX descriptors
+ * @ctx current used TX descriptor
+ * @crx current used RX descriptor
+ * @trng hw_random structure for RNG
+ * @hwrng_stat_req number of HWRNG requests
+ * @hwrng_stat_bytes total number of bytes generated by RNG
+ * @stat_irq number of IRQ handled by CE
+ * @stat_irq_tx number of TX IRQ handled by CE
+ * @stat_irq_rx number of RX IRQ handled by CE
+ * @stat_req number of requests handled by CE
+ * @fallbak_sg_count_tx number of fallback due to destination SG count
+ * @fallbak_sg_count_rx number of fallback due to source SG count
+ * @fallbak_not_same_len number of fallback due to difference in SG length
+ * @dbgfs_dir: Debugfs dentry for statistic directory
+ * @dbgfs_stats: Debugfs dentry for statistic counters
+ */
+struct sl3516_ce_dev {
+ void __iomem *base;
+ struct clk *clks;
+ struct reset_control *reset;
+ struct device *dev;
+ struct crypto_engine *engine;
+ struct completion complete;
+ int status;
+ dma_addr_t dtx;
+ struct descriptor *tx;
+ dma_addr_t drx;
+ struct descriptor *rx;
+ int ctx;
+ int crx;
+ struct hwrng trng;
+ unsigned long hwrng_stat_req;
+ unsigned long hwrng_stat_bytes;
+ unsigned long stat_irq;
+ unsigned long stat_irq_tx;
+ unsigned long stat_irq_rx;
+ unsigned long stat_req;
+ unsigned long fallback_sg_count_tx;
+ unsigned long fallback_sg_count_rx;
+ unsigned long fallback_not_same_len;
+ unsigned long fallback_mod16;
+ unsigned long fallback_align16;
+#ifdef CONFIG_CRYPTO_DEV_SL3516_DEBUG
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_stats;
+#endif
+ void *pctrl;
+ dma_addr_t dctrl;
+};
+
+struct sginfo {
+ u32 addr;
+ u32 len;
+};
+
+/*
+ * struct sl3516_ce_cipher_req_ctx - context for a skcipher request
+ * @t_src: list of mapped SGs with their size
+ * @t_dst: list of mapped SGs with their size
+ * @op_dir: direction (encrypt vs decrypt) for this request
+ * @pctrllen: the length of the ctrl packet
+ * @tqflag: the TQflag to set in data packet
+ * @h pointer to the pkt_control_cipher header
+ * @nr_sgs: number of source SG
+ * @nr_sgd: number of destination SG
+ * @fallback_req: request struct for invoking the fallback skcipher TFM
+ */
+struct sl3516_ce_cipher_req_ctx {
+ struct sginfo t_src[MAXDESC];
+ struct sginfo t_dst[MAXDESC];
+ u32 op_dir;
+ unsigned int pctrllen;
+ u32 tqflag;
+ struct pkt_control_cipher *h;
+ int nr_sgs;
+ int nr_sgd;
+ struct skcipher_request fallback_req; // keep at the end
+};
+
+/*
+ * struct sl3516_ce_cipher_tfm_ctx - context for a skcipher TFM
+ * @enginectx: crypto_engine used by this TFM
+ * @key: pointer to key data
+ * @keylen: len of the key
+ * @ce: pointer to the private data of driver handling this TFM
+ * @fallback_tfm: pointer to the fallback TFM
+ *
+ * enginectx must be the first element
+ */
+struct sl3516_ce_cipher_tfm_ctx {
+ struct crypto_engine_ctx enginectx;
+ u32 *key;
+ u32 keylen;
+ struct sl3516_ce_dev *ce;
+ struct crypto_skcipher *fallback_tfm;
+};
+
+/*
+ * struct sl3516_ce_alg_template - crypto_alg template
+ * @type: the CRYPTO_ALG_TYPE for this template
+ * @mode: value to be used in control packet for this algorithm
+ * @ce: pointer to the sl3516_ce_dev structure associated with
+ * this template
+ * @alg: one of sub struct must be used
+ * @stat_req: number of request done on this template
+ * @stat_fb: number of request which has fallbacked
+ * @stat_bytes: total data size done by this template
+ */
+struct sl3516_ce_alg_template {
+ u32 type;
+ u32 mode;
+ struct sl3516_ce_dev *ce;
+ union {
+ struct skcipher_alg skcipher;
+ } alg;
+ unsigned long stat_req;
+ unsigned long stat_fb;
+ unsigned long stat_bytes;
+};
+
+int sl3516_ce_enqueue(struct crypto_async_request *areq, u32 type);
+
+int sl3516_ce_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen);
+int sl3516_ce_cipher_init(struct crypto_tfm *tfm);
+void sl3516_ce_cipher_exit(struct crypto_tfm *tfm);
+int sl3516_ce_skdecrypt(struct skcipher_request *areq);
+int sl3516_ce_skencrypt(struct skcipher_request *areq);
+
+int sl3516_ce_run_task(struct sl3516_ce_dev *ce,
+ struct sl3516_ce_cipher_req_ctx *rctx, const char *name);
+
+int sl3516_ce_rng_register(struct sl3516_ce_dev *ce);
+void sl3516_ce_rng_unregister(struct sl3516_ce_dev *ce);
diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c
index a380087c83f7..a032c192ef1d 100644
--- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c
+++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c
@@ -5,6 +5,7 @@
#include <crypto/dh.h>
#include <crypto/ecc_curve.h>
#include <crypto/ecdh.h>
+#include <crypto/rng.h>
#include <crypto/internal/akcipher.h>
#include <crypto/internal/kpp.h>
#include <crypto/internal/rsa.h>
@@ -30,7 +31,6 @@ struct hpre_ctx;
#define HPRE_DH_G_FLAG 0x02
#define HPRE_TRY_SEND_TIMES 100
#define HPRE_INVLD_REQ_ID (-1)
-#define HPRE_DEV(ctx) (&((ctx)->qp->qm->pdev->dev))
#define HPRE_SQE_ALG_BITS 5
#define HPRE_SQE_DONE_SHIFT 30
@@ -39,12 +39,17 @@ struct hpre_ctx;
#define HPRE_DFX_SEC_TO_US 1000000
#define HPRE_DFX_US_TO_NS 1000
+/* due to nist p521 */
+#define HPRE_ECC_MAX_KSZ 66
+
/* size in bytes of the n prime */
#define HPRE_ECC_NIST_P192_N_SIZE 24
#define HPRE_ECC_NIST_P256_N_SIZE 32
+#define HPRE_ECC_NIST_P384_N_SIZE 48
/* size in bytes */
#define HPRE_ECC_HW256_KSZ_B 32
+#define HPRE_ECC_HW384_KSZ_B 48
typedef void (*hpre_cb)(struct hpre_ctx *ctx, void *sqe);
@@ -102,6 +107,7 @@ struct hpre_curve25519_ctx {
struct hpre_ctx {
struct hisi_qp *qp;
+ struct device *dev;
struct hpre_asym_request **req_list;
struct hpre *hpre;
spinlock_t req_lock;
@@ -214,8 +220,7 @@ static int hpre_get_data_dma_addr(struct hpre_asym_request *hpre_req,
struct scatterlist *data, unsigned int len,
int is_src, dma_addr_t *tmp)
{
- struct hpre_ctx *ctx = hpre_req->ctx;
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = hpre_req->ctx->dev;
enum dma_data_direction dma_dir;
if (is_src) {
@@ -239,7 +244,7 @@ static int hpre_prepare_dma_buf(struct hpre_asym_request *hpre_req,
int is_src, dma_addr_t *tmp)
{
struct hpre_ctx *ctx = hpre_req->ctx;
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
void *ptr;
int shift;
@@ -293,11 +298,13 @@ static void hpre_hw_data_clr_all(struct hpre_ctx *ctx,
struct scatterlist *dst,
struct scatterlist *src)
{
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
struct hpre_sqe *sqe = &req->req;
dma_addr_t tmp;
tmp = le64_to_cpu(sqe->in);
+ if (unlikely(dma_mapping_error(dev, tmp)))
+ return;
if (src) {
if (req->src)
@@ -307,6 +314,8 @@ static void hpre_hw_data_clr_all(struct hpre_ctx *ctx,
}
tmp = le64_to_cpu(sqe->out);
+ if (unlikely(dma_mapping_error(dev, tmp)))
+ return;
if (req->dst) {
if (dst)
@@ -321,16 +330,15 @@ static void hpre_hw_data_clr_all(struct hpre_ctx *ctx,
static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe,
void **kreq)
{
- struct device *dev = HPRE_DEV(ctx);
struct hpre_asym_request *req;
unsigned int err, done, alg;
int id;
#define HPRE_NO_HW_ERR 0
#define HPRE_HW_TASK_DONE 3
-#define HREE_HW_ERR_MASK 0x7ff
-#define HREE_SQE_DONE_MASK 0x3
-#define HREE_ALG_TYPE_MASK 0x1f
+#define HREE_HW_ERR_MASK GENMASK(10, 0)
+#define HREE_SQE_DONE_MASK GENMASK(1, 0)
+#define HREE_ALG_TYPE_MASK GENMASK(4, 0)
id = (int)le16_to_cpu(sqe->tag);
req = ctx->req_list[id];
hpre_rm_req_from_ctx(req);
@@ -346,7 +354,7 @@ static int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe,
return 0;
alg = le32_to_cpu(sqe->dw0) & HREE_ALG_TYPE_MASK;
- dev_err_ratelimited(dev, "alg[0x%x] error: done[0x%x], etype[0x%x]\n",
+ dev_err_ratelimited(ctx->dev, "alg[0x%x] error: done[0x%x], etype[0x%x]\n",
alg, done, err);
return -EINVAL;
@@ -361,6 +369,7 @@ static int hpre_ctx_set(struct hpre_ctx *ctx, struct hisi_qp *qp, int qlen)
spin_lock_init(&ctx->req_lock);
ctx->qp = qp;
+ ctx->dev = &qp->qm->pdev->dev;
hpre = container_of(ctx->qp->qm, struct hpre, qm);
ctx->hpre = hpre;
@@ -524,6 +533,8 @@ static int hpre_msg_request_set(struct hpre_ctx *ctx, void *req, bool is_rsa)
msg->key = cpu_to_le64(ctx->dh.dma_xa_p);
}
+ msg->in = cpu_to_le64(DMA_MAPPING_ERROR);
+ msg->out = cpu_to_le64(DMA_MAPPING_ERROR);
msg->dw0 |= cpu_to_le32(0x1 << HPRE_SQE_DONE_SHIFT);
msg->task_len1 = (ctx->key_sz >> HPRE_BITS_2_BYTES_SHIFT) - 1;
h_req->ctx = ctx;
@@ -618,14 +629,14 @@ static int hpre_is_dh_params_length_valid(unsigned int key_sz)
case _HPRE_DH_GRP15:
case _HPRE_DH_GRP16:
return 0;
+ default:
+ return -EINVAL;
}
-
- return -EINVAL;
}
static int hpre_dh_set_params(struct hpre_ctx *ctx, struct dh *params)
{
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
unsigned int sz;
if (params->p_size > HPRE_DH_MAX_P_SZ)
@@ -664,7 +675,7 @@ static int hpre_dh_set_params(struct hpre_ctx *ctx, struct dh *params)
static void hpre_dh_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all)
{
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
unsigned int sz = ctx->key_sz;
if (is_clear_all)
@@ -877,18 +888,18 @@ static int hpre_rsa_set_n(struct hpre_ctx *ctx, const char *value,
if (!hpre_rsa_key_size_is_support(ctx->key_sz))
return 0;
- ctx->rsa.pubkey = dma_alloc_coherent(HPRE_DEV(ctx), vlen << 1,
+ ctx->rsa.pubkey = dma_alloc_coherent(ctx->dev, vlen << 1,
&ctx->rsa.dma_pubkey,
GFP_KERNEL);
if (!ctx->rsa.pubkey)
return -ENOMEM;
if (private) {
- ctx->rsa.prikey = dma_alloc_coherent(HPRE_DEV(ctx), vlen << 1,
+ ctx->rsa.prikey = dma_alloc_coherent(ctx->dev, vlen << 1,
&ctx->rsa.dma_prikey,
GFP_KERNEL);
if (!ctx->rsa.prikey) {
- dma_free_coherent(HPRE_DEV(ctx), vlen << 1,
+ dma_free_coherent(ctx->dev, vlen << 1,
ctx->rsa.pubkey,
ctx->rsa.dma_pubkey);
ctx->rsa.pubkey = NULL;
@@ -950,7 +961,7 @@ static int hpre_crt_para_get(char *para, size_t para_sz,
static int hpre_rsa_setkey_crt(struct hpre_ctx *ctx, struct rsa_key *rsa_key)
{
unsigned int hlf_ksz = ctx->key_sz >> 1;
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
u64 offset;
int ret;
@@ -1008,7 +1019,7 @@ free_key:
static void hpre_rsa_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all)
{
unsigned int half_key_sz = ctx->key_sz >> 1;
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
if (is_clear_all)
hisi_qm_stop_qp(ctx->qp);
@@ -1179,7 +1190,7 @@ static void hpre_key_to_big_end(u8 *data, int len)
static void hpre_ecc_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all,
bool is_ecdh)
{
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
unsigned int sz = ctx->key_sz;
unsigned int shift = sz << 1;
@@ -1202,12 +1213,21 @@ static void hpre_ecc_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all,
hpre_ctx_clear(ctx, is_clear_all);
}
+/*
+ * The bits of 192/224/256/384/521 are supported by HPRE,
+ * and convert the bits like:
+ * bits<=256, bits=256; 256<bits<=384, bits=384; 384<bits<=576, bits=576;
+ * If the parameter bit width is insufficient, then we fill in the
+ * high-order zeros by soft, so TASK_LENGTH1 is 0x3/0x5/0x8;
+ */
static unsigned int hpre_ecdh_supported_curve(unsigned short id)
{
switch (id) {
case ECC_CURVE_NIST_P192:
case ECC_CURVE_NIST_P256:
return HPRE_ECC_HW256_KSZ_B;
+ case ECC_CURVE_NIST_P384:
+ return HPRE_ECC_HW384_KSZ_B;
default:
break;
}
@@ -1272,6 +1292,8 @@ static unsigned int hpre_ecdh_get_curvesz(unsigned short id)
return HPRE_ECC_NIST_P192_N_SIZE;
case ECC_CURVE_NIST_P256:
return HPRE_ECC_NIST_P256_N_SIZE;
+ case ECC_CURVE_NIST_P384:
+ return HPRE_ECC_NIST_P384_N_SIZE;
default:
break;
}
@@ -1281,7 +1303,7 @@ static unsigned int hpre_ecdh_get_curvesz(unsigned short id)
static int hpre_ecdh_set_param(struct hpre_ctx *ctx, struct ecdh *params)
{
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
unsigned int sz, shift, curve_sz;
int ret;
@@ -1328,11 +1350,32 @@ static bool hpre_key_is_zero(char *key, unsigned short key_sz)
return true;
}
+static int ecdh_gen_privkey(struct hpre_ctx *ctx, struct ecdh *params)
+{
+ struct device *dev = ctx->dev;
+ int ret;
+
+ ret = crypto_get_default_rng();
+ if (ret) {
+ dev_err(dev, "failed to get default rng, ret = %d!\n", ret);
+ return ret;
+ }
+
+ ret = crypto_rng_get_bytes(crypto_default_rng, (u8 *)params->key,
+ params->key_size);
+ crypto_put_default_rng();
+ if (ret)
+ dev_err(dev, "failed to get rng, ret = %d!\n", ret);
+
+ return ret;
+}
+
static int hpre_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
unsigned int len)
{
struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
+ char key[HPRE_ECC_MAX_KSZ];
unsigned int sz, sz_shift;
struct ecdh params;
int ret;
@@ -1342,6 +1385,15 @@ static int hpre_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
return -EINVAL;
}
+ /* Use stdrng to generate private key */
+ if (!params.key || !params.key_size) {
+ params.key = key;
+ params.key_size = hpre_ecdh_get_curvesz(ctx->curve_id);
+ ret = ecdh_gen_privkey(ctx, &params);
+ if (ret)
+ return ret;
+ }
+
if (hpre_key_is_zero(params.key, params.key_size)) {
dev_err(dev, "Invalid hpre key!\n");
return -EINVAL;
@@ -1367,16 +1419,20 @@ static void hpre_ecdh_hw_data_clr_all(struct hpre_ctx *ctx,
struct scatterlist *dst,
struct scatterlist *src)
{
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
struct hpre_sqe *sqe = &req->req;
dma_addr_t dma;
dma = le64_to_cpu(sqe->in);
+ if (unlikely(dma_mapping_error(dev, dma)))
+ return;
if (src && req->src)
dma_free_coherent(dev, ctx->key_sz << 2, req->src, dma);
dma = le64_to_cpu(sqe->out);
+ if (unlikely(dma_mapping_error(dev, dma)))
+ return;
if (req->dst)
dma_free_coherent(dev, ctx->key_sz << 1, req->dst, dma);
@@ -1431,6 +1487,8 @@ static int hpre_ecdh_msg_request_set(struct hpre_ctx *ctx,
h_req->areq.ecdh = req;
msg = &h_req->req;
memset(msg, 0, sizeof(*msg));
+ msg->in = cpu_to_le64(DMA_MAPPING_ERROR);
+ msg->out = cpu_to_le64(DMA_MAPPING_ERROR);
msg->key = cpu_to_le64(ctx->ecdh.dma_p);
msg->dw0 |= cpu_to_le32(0x1U << HPRE_SQE_DONE_SHIFT);
@@ -1450,7 +1508,7 @@ static int hpre_ecdh_src_data_init(struct hpre_asym_request *hpre_req,
{
struct hpre_sqe *msg = &hpre_req->req;
struct hpre_ctx *ctx = hpre_req->ctx;
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
unsigned int tmpshift;
dma_addr_t dma = 0;
void *ptr;
@@ -1480,8 +1538,8 @@ static int hpre_ecdh_dst_data_init(struct hpre_asym_request *hpre_req,
{
struct hpre_sqe *msg = &hpre_req->req;
struct hpre_ctx *ctx = hpre_req->ctx;
- struct device *dev = HPRE_DEV(ctx);
- dma_addr_t dma = 0;
+ struct device *dev = ctx->dev;
+ dma_addr_t dma;
if (unlikely(!data || !sg_is_last(data) || len != ctx->key_sz << 1)) {
dev_err(dev, "data or data length is illegal!\n");
@@ -1503,7 +1561,7 @@ static int hpre_ecdh_compute_value(struct kpp_request *req)
{
struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
void *tmp = kpp_request_ctx(req);
struct hpre_asym_request *hpre_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ);
struct hpre_sqe *msg = &hpre_req->req;
@@ -1568,6 +1626,15 @@ static int hpre_ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm)
return hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE);
}
+static int hpre_ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm)
+{
+ struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
+
+ ctx->curve_id = ECC_CURVE_NIST_P384;
+
+ return hpre_ctx_init(ctx, HPRE_V3_ECC_ALG_TYPE);
+}
+
static void hpre_ecdh_exit_tfm(struct crypto_kpp *tfm)
{
struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
@@ -1609,7 +1676,7 @@ static void hpre_curve25519_fill_curve(struct hpre_ctx *ctx, const void *buf,
static int hpre_curve25519_set_param(struct hpre_ctx *ctx, const void *buf,
unsigned int len)
{
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
unsigned int sz = ctx->key_sz;
unsigned int shift = sz << 1;
@@ -1634,7 +1701,7 @@ static int hpre_curve25519_set_secret(struct crypto_kpp *tfm, const void *buf,
unsigned int len)
{
struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
int ret = -EINVAL;
if (len != CURVE25519_KEY_SIZE ||
@@ -1662,16 +1729,20 @@ static void hpre_curve25519_hw_data_clr_all(struct hpre_ctx *ctx,
struct scatterlist *dst,
struct scatterlist *src)
{
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
struct hpre_sqe *sqe = &req->req;
dma_addr_t dma;
dma = le64_to_cpu(sqe->in);
+ if (unlikely(dma_mapping_error(dev, dma)))
+ return;
if (src && req->src)
dma_free_coherent(dev, ctx->key_sz, req->src, dma);
dma = le64_to_cpu(sqe->out);
+ if (unlikely(dma_mapping_error(dev, dma)))
+ return;
if (req->dst)
dma_free_coherent(dev, ctx->key_sz, req->dst, dma);
@@ -1722,6 +1793,8 @@ static int hpre_curve25519_msg_request_set(struct hpre_ctx *ctx,
h_req->areq.curve25519 = req;
msg = &h_req->req;
memset(msg, 0, sizeof(*msg));
+ msg->in = cpu_to_le64(DMA_MAPPING_ERROR);
+ msg->out = cpu_to_le64(DMA_MAPPING_ERROR);
msg->key = cpu_to_le64(ctx->curve25519.dma_p);
msg->dw0 |= cpu_to_le32(0x1U << HPRE_SQE_DONE_SHIFT);
@@ -1752,7 +1825,7 @@ static int hpre_curve25519_src_init(struct hpre_asym_request *hpre_req,
{
struct hpre_sqe *msg = &hpre_req->req;
struct hpre_ctx *ctx = hpre_req->ctx;
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
u8 p[CURVE25519_KEY_SIZE] = { 0 };
const struct ecc_curve *curve;
dma_addr_t dma = 0;
@@ -1790,8 +1863,12 @@ static int hpre_curve25519_src_init(struct hpre_asym_request *hpre_req,
* When src_data equals (2^255 - 19) ~ (2^255 - 1), it is out of p,
* we get its modulus to p, and then use it.
*/
- if (memcmp(ptr, p, ctx->key_sz) >= 0)
+ if (memcmp(ptr, p, ctx->key_sz) == 0) {
+ dev_err(dev, "gx is p!\n");
+ return -EINVAL;
+ } else if (memcmp(ptr, p, ctx->key_sz) > 0) {
hpre_curve25519_src_modulo_p(ptr);
+ }
hpre_req->src = ptr;
msg->in = cpu_to_le64(dma);
@@ -1807,8 +1884,8 @@ static int hpre_curve25519_dst_init(struct hpre_asym_request *hpre_req,
{
struct hpre_sqe *msg = &hpre_req->req;
struct hpre_ctx *ctx = hpre_req->ctx;
- struct device *dev = HPRE_DEV(ctx);
- dma_addr_t dma = 0;
+ struct device *dev = ctx->dev;
+ dma_addr_t dma;
if (!data || !sg_is_last(data) || len != ctx->key_sz) {
dev_err(dev, "data or data length is illegal!\n");
@@ -1830,7 +1907,7 @@ static int hpre_curve25519_compute_value(struct kpp_request *req)
{
struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
- struct device *dev = HPRE_DEV(ctx);
+ struct device *dev = ctx->dev;
void *tmp = kpp_request_ctx(req);
struct hpre_asym_request *hpre_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ);
struct hpre_sqe *msg = &hpre_req->req;
@@ -1940,7 +2017,7 @@ static struct kpp_alg ecdh_nist_p192 = {
.cra_ctxsize = sizeof(struct hpre_ctx),
.cra_priority = HPRE_CRYPTO_ALG_PRI,
.cra_name = "ecdh-nist-p192",
- .cra_driver_name = "hpre-ecdh",
+ .cra_driver_name = "hpre-ecdh-nist-p192",
.cra_module = THIS_MODULE,
},
};
@@ -1957,7 +2034,24 @@ static struct kpp_alg ecdh_nist_p256 = {
.cra_ctxsize = sizeof(struct hpre_ctx),
.cra_priority = HPRE_CRYPTO_ALG_PRI,
.cra_name = "ecdh-nist-p256",
- .cra_driver_name = "hpre-ecdh",
+ .cra_driver_name = "hpre-ecdh-nist-p256",
+ .cra_module = THIS_MODULE,
+ },
+};
+
+static struct kpp_alg ecdh_nist_p384 = {
+ .set_secret = hpre_ecdh_set_secret,
+ .generate_public_key = hpre_ecdh_compute_value,
+ .compute_shared_secret = hpre_ecdh_compute_value,
+ .max_size = hpre_ecdh_max_size,
+ .init = hpre_ecdh_nist_p384_init_tfm,
+ .exit = hpre_ecdh_exit_tfm,
+ .reqsize = sizeof(struct hpre_asym_request) + HPRE_ALIGN_SZ,
+ .base = {
+ .cra_ctxsize = sizeof(struct hpre_ctx),
+ .cra_priority = HPRE_CRYPTO_ALG_PRI,
+ .cra_name = "ecdh-nist-p384",
+ .cra_driver_name = "hpre-ecdh-nist-p384",
.cra_module = THIS_MODULE,
},
};
@@ -1989,16 +2083,25 @@ static int hpre_register_ecdh(void)
return ret;
ret = crypto_register_kpp(&ecdh_nist_p256);
- if (ret) {
- crypto_unregister_kpp(&ecdh_nist_p192);
- return ret;
- }
+ if (ret)
+ goto unregister_ecdh_p192;
+
+ ret = crypto_register_kpp(&ecdh_nist_p384);
+ if (ret)
+ goto unregister_ecdh_p256;
return 0;
+
+unregister_ecdh_p256:
+ crypto_unregister_kpp(&ecdh_nist_p256);
+unregister_ecdh_p192:
+ crypto_unregister_kpp(&ecdh_nist_p192);
+ return ret;
}
static void hpre_unregister_ecdh(void)
{
+ crypto_unregister_kpp(&ecdh_nist_p384);
crypto_unregister_kpp(&ecdh_nist_p256);
crypto_unregister_kpp(&ecdh_nist_p192);
}
diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c
index 046bc962c8b2..8b0640fb04be 100644
--- a/drivers/crypto/hisilicon/hpre/hpre_main.c
+++ b/drivers/crypto/hisilicon/hpre/hpre_main.c
@@ -36,7 +36,7 @@
#define HPRE_INT_MASK 0x301400
#define HPRE_INT_STATUS 0x301800
#define HPRE_CORE_INT_ENABLE 0
-#define HPRE_CORE_INT_DISABLE 0x003fffff
+#define HPRE_CORE_INT_DISABLE GENMASK(21, 0)
#define HPRE_RDCHN_INI_ST 0x301a00
#define HPRE_CLSTR_BASE 0x302000
#define HPRE_CORE_EN_OFFSET 0x04
@@ -50,6 +50,7 @@
#define HPRE_RAS_NFE_ENB 0x301414
#define HPRE_HAC_RAS_NFE_ENABLE 0x3ffffe
#define HPRE_RAS_FE_ENB 0x301418
+#define HPRE_OOO_SHUTDOWN_SEL 0x301a3c
#define HPRE_HAC_RAS_FE_ENABLE 0
#define HPRE_CORE_ENB (HPRE_CLSTR_BASE + HPRE_CORE_EN_OFFSET)
@@ -57,7 +58,6 @@
#define HPRE_CORE_INI_STATUS (HPRE_CLSTR_BASE + HPRE_CORE_INI_STATUS_OFFSET)
#define HPRE_HAC_ECC1_CNT 0x301a04
#define HPRE_HAC_ECC2_CNT 0x301a08
-#define HPRE_HAC_INT_STATUS 0x301800
#define HPRE_HAC_SOURCE_INT 0x301600
#define HPRE_CLSTR_ADDR_INTRVL 0x1000
#define HPRE_CLUSTER_INQURY 0x100
@@ -69,13 +69,17 @@
#define HPRE_DBGFS_VAL_MAX_LEN 20
#define HPRE_PCI_DEVICE_ID 0xa258
#define HPRE_PCI_VF_DEVICE_ID 0xa259
-#define HPRE_ADDR(qm, offset) ((qm)->io_base + (offset))
-#define HPRE_QM_USR_CFG_MASK 0xfffffffe
-#define HPRE_QM_AXI_CFG_MASK 0xffff
-#define HPRE_QM_VFG_AX_MASK 0xff
-#define HPRE_BD_USR_MASK 0x3
-#define HPRE_CLUSTER_CORE_MASK_V2 0xf
-#define HPRE_CLUSTER_CORE_MASK_V3 0xff
+#define HPRE_QM_USR_CFG_MASK GENMASK(31, 1)
+#define HPRE_QM_AXI_CFG_MASK GENMASK(15, 0)
+#define HPRE_QM_VFG_AX_MASK GENMASK(7, 0)
+#define HPRE_BD_USR_MASK GENMASK(1, 0)
+#define HPRE_CLUSTER_CORE_MASK_V2 GENMASK(3, 0)
+#define HPRE_CLUSTER_CORE_MASK_V3 GENMASK(7, 0)
+#define HPRE_PREFETCH_CFG 0x301130
+#define HPRE_SVA_PREFTCH_DFX 0x30115C
+#define HPRE_PREFETCH_ENABLE (~(BIT(0) | BIT(30)))
+#define HPRE_PREFETCH_DISABLE BIT(30)
+#define HPRE_SVA_DISABLE_READY (BIT(4) | BIT(8))
#define HPRE_AM_OOO_SHUTDOWN_ENB 0x301044
#define HPRE_AM_OOO_SHUTDOWN_ENABLE BIT(0)
@@ -88,11 +92,7 @@
#define HPRE_QM_PM_FLR BIT(11)
#define HPRE_QM_SRIOV_FLR BIT(12)
-#define HPRE_CLUSTERS_NUM(qm) \
- (((qm)->ver >= QM_HW_V3) ? HPRE_CLUSTERS_NUM_V3 : HPRE_CLUSTERS_NUM_V2)
-#define HPRE_CLUSTER_CORE_MASK(qm) \
- (((qm)->ver >= QM_HW_V3) ? HPRE_CLUSTER_CORE_MASK_V3 :\
- HPRE_CLUSTER_CORE_MASK_V2)
+#define HPRE_SHAPER_TYPE_RATE 128
#define HPRE_VIA_MSI_DSM 1
#define HPRE_SQE_MASK_OFFSET 8
#define HPRE_SQE_MASK_LEN 24
@@ -123,21 +123,49 @@ static const char * const hpre_debug_file_name[] = {
};
static const struct hpre_hw_error hpre_hw_errors[] = {
- { .int_msk = BIT(0), .msg = "core_ecc_1bit_err_int_set" },
- { .int_msk = BIT(1), .msg = "core_ecc_2bit_err_int_set" },
- { .int_msk = BIT(2), .msg = "dat_wb_poison_int_set" },
- { .int_msk = BIT(3), .msg = "dat_rd_poison_int_set" },
- { .int_msk = BIT(4), .msg = "bd_rd_poison_int_set" },
- { .int_msk = BIT(5), .msg = "ooo_ecc_2bit_err_int_set" },
- { .int_msk = BIT(6), .msg = "cluster1_shb_timeout_int_set" },
- { .int_msk = BIT(7), .msg = "cluster2_shb_timeout_int_set" },
- { .int_msk = BIT(8), .msg = "cluster3_shb_timeout_int_set" },
- { .int_msk = BIT(9), .msg = "cluster4_shb_timeout_int_set" },
- { .int_msk = GENMASK(15, 10), .msg = "ooo_rdrsp_err_int_set" },
- { .int_msk = GENMASK(21, 16), .msg = "ooo_wrrsp_err_int_set" },
- { .int_msk = BIT(22), .msg = "pt_rng_timeout_int_set"},
- { .int_msk = BIT(23), .msg = "sva_fsm_timeout_int_set"},
{
+ .int_msk = BIT(0),
+ .msg = "core_ecc_1bit_err_int_set"
+ }, {
+ .int_msk = BIT(1),
+ .msg = "core_ecc_2bit_err_int_set"
+ }, {
+ .int_msk = BIT(2),
+ .msg = "dat_wb_poison_int_set"
+ }, {
+ .int_msk = BIT(3),
+ .msg = "dat_rd_poison_int_set"
+ }, {
+ .int_msk = BIT(4),
+ .msg = "bd_rd_poison_int_set"
+ }, {
+ .int_msk = BIT(5),
+ .msg = "ooo_ecc_2bit_err_int_set"
+ }, {
+ .int_msk = BIT(6),
+ .msg = "cluster1_shb_timeout_int_set"
+ }, {
+ .int_msk = BIT(7),
+ .msg = "cluster2_shb_timeout_int_set"
+ }, {
+ .int_msk = BIT(8),
+ .msg = "cluster3_shb_timeout_int_set"
+ }, {
+ .int_msk = BIT(9),
+ .msg = "cluster4_shb_timeout_int_set"
+ }, {
+ .int_msk = GENMASK(15, 10),
+ .msg = "ooo_rdrsp_err_int_set"
+ }, {
+ .int_msk = GENMASK(21, 16),
+ .msg = "ooo_wrrsp_err_int_set"
+ }, {
+ .int_msk = BIT(22),
+ .msg = "pt_rng_timeout_int_set"
+ }, {
+ .int_msk = BIT(23),
+ .msg = "sva_fsm_timeout_int_set"
+ }, {
/* sentinel */
}
};
@@ -224,6 +252,18 @@ static u32 vfs_num;
module_param_cb(vfs_num, &vfs_num_ops, &vfs_num, 0444);
MODULE_PARM_DESC(vfs_num, "Number of VFs to enable(1-63), 0(default)");
+static inline int hpre_cluster_num(struct hisi_qm *qm)
+{
+ return (qm->ver >= QM_HW_V3) ? HPRE_CLUSTERS_NUM_V3 :
+ HPRE_CLUSTERS_NUM_V2;
+}
+
+static inline int hpre_cluster_core_mask(struct hisi_qm *qm)
+{
+ return (qm->ver >= QM_HW_V3) ?
+ HPRE_CLUSTER_CORE_MASK_V3 : HPRE_CLUSTER_CORE_MASK_V2;
+}
+
struct hisi_qp *hpre_create_qp(u8 type)
{
int node = cpu_to_node(smp_processor_id());
@@ -290,8 +330,8 @@ static int hpre_cfg_by_dsm(struct hisi_qm *qm)
static int hpre_set_cluster(struct hisi_qm *qm)
{
- u32 cluster_core_mask = HPRE_CLUSTER_CORE_MASK(qm);
- u8 clusters_num = HPRE_CLUSTERS_NUM(qm);
+ u32 cluster_core_mask = hpre_cluster_core_mask(qm);
+ u8 clusters_num = hpre_cluster_num(qm);
struct device *dev = &qm->pdev->dev;
unsigned long offset;
u32 val = 0;
@@ -302,10 +342,10 @@ static int hpre_set_cluster(struct hisi_qm *qm)
/* clusters initiating */
writel(cluster_core_mask,
- HPRE_ADDR(qm, offset + HPRE_CORE_ENB));
- writel(0x1, HPRE_ADDR(qm, offset + HPRE_CORE_INI_CFG));
- ret = readl_relaxed_poll_timeout(HPRE_ADDR(qm, offset +
- HPRE_CORE_INI_STATUS), val,
+ qm->io_base + offset + HPRE_CORE_ENB);
+ writel(0x1, qm->io_base + offset + HPRE_CORE_INI_CFG);
+ ret = readl_relaxed_poll_timeout(qm->io_base + offset +
+ HPRE_CORE_INI_STATUS, val,
((val & cluster_core_mask) ==
cluster_core_mask),
HPRE_REG_RD_INTVRL_US,
@@ -329,11 +369,52 @@ static void disable_flr_of_bme(struct hisi_qm *qm)
{
u32 val;
- val = readl(HPRE_ADDR(qm, QM_PEH_AXUSER_CFG));
+ val = readl(qm->io_base + QM_PEH_AXUSER_CFG);
val &= ~(HPRE_QM_BME_FLR | HPRE_QM_SRIOV_FLR);
val |= HPRE_QM_PM_FLR;
- writel(val, HPRE_ADDR(qm, QM_PEH_AXUSER_CFG));
- writel(PEH_AXUSER_CFG_ENABLE, HPRE_ADDR(qm, QM_PEH_AXUSER_CFG_ENABLE));
+ writel(val, qm->io_base + QM_PEH_AXUSER_CFG);
+ writel(PEH_AXUSER_CFG_ENABLE, qm->io_base + QM_PEH_AXUSER_CFG_ENABLE);
+}
+
+static void hpre_open_sva_prefetch(struct hisi_qm *qm)
+{
+ u32 val;
+ int ret;
+
+ if (qm->ver < QM_HW_V3)
+ return;
+
+ /* Enable prefetch */
+ val = readl_relaxed(qm->io_base + HPRE_PREFETCH_CFG);
+ val &= HPRE_PREFETCH_ENABLE;
+ writel(val, qm->io_base + HPRE_PREFETCH_CFG);
+
+ ret = readl_relaxed_poll_timeout(qm->io_base + HPRE_PREFETCH_CFG,
+ val, !(val & HPRE_PREFETCH_DISABLE),
+ HPRE_REG_RD_INTVRL_US,
+ HPRE_REG_RD_TMOUT_US);
+ if (ret)
+ pci_err(qm->pdev, "failed to open sva prefetch\n");
+}
+
+static void hpre_close_sva_prefetch(struct hisi_qm *qm)
+{
+ u32 val;
+ int ret;
+
+ if (qm->ver < QM_HW_V3)
+ return;
+
+ val = readl_relaxed(qm->io_base + HPRE_PREFETCH_CFG);
+ val |= HPRE_PREFETCH_DISABLE;
+ writel(val, qm->io_base + HPRE_PREFETCH_CFG);
+
+ ret = readl_relaxed_poll_timeout(qm->io_base + HPRE_SVA_PREFTCH_DFX,
+ val, !(val & HPRE_SVA_DISABLE_READY),
+ HPRE_REG_RD_INTVRL_US,
+ HPRE_REG_RD_TMOUT_US);
+ if (ret)
+ pci_err(qm->pdev, "failed to close sva prefetch\n");
}
static int hpre_set_user_domain_and_cache(struct hisi_qm *qm)
@@ -342,33 +423,33 @@ static int hpre_set_user_domain_and_cache(struct hisi_qm *qm)
u32 val;
int ret;
- writel(HPRE_QM_USR_CFG_MASK, HPRE_ADDR(qm, QM_ARUSER_M_CFG_ENABLE));
- writel(HPRE_QM_USR_CFG_MASK, HPRE_ADDR(qm, QM_AWUSER_M_CFG_ENABLE));
- writel_relaxed(HPRE_QM_AXI_CFG_MASK, HPRE_ADDR(qm, QM_AXI_M_CFG));
+ writel(HPRE_QM_USR_CFG_MASK, qm->io_base + QM_ARUSER_M_CFG_ENABLE);
+ writel(HPRE_QM_USR_CFG_MASK, qm->io_base + QM_AWUSER_M_CFG_ENABLE);
+ writel_relaxed(HPRE_QM_AXI_CFG_MASK, qm->io_base + QM_AXI_M_CFG);
/* HPRE need more time, we close this interrupt */
- val = readl_relaxed(HPRE_ADDR(qm, HPRE_QM_ABNML_INT_MASK));
+ val = readl_relaxed(qm->io_base + HPRE_QM_ABNML_INT_MASK);
val |= BIT(HPRE_TIMEOUT_ABNML_BIT);
- writel_relaxed(val, HPRE_ADDR(qm, HPRE_QM_ABNML_INT_MASK));
+ writel_relaxed(val, qm->io_base + HPRE_QM_ABNML_INT_MASK);
if (qm->ver >= QM_HW_V3)
writel(HPRE_RSA_ENB | HPRE_ECC_ENB,
- HPRE_ADDR(qm, HPRE_TYPES_ENB));
+ qm->io_base + HPRE_TYPES_ENB);
else
- writel(HPRE_RSA_ENB, HPRE_ADDR(qm, HPRE_TYPES_ENB));
-
- writel(HPRE_QM_VFG_AX_MASK, HPRE_ADDR(qm, HPRE_VFG_AXCACHE));
- writel(0x0, HPRE_ADDR(qm, HPRE_BD_ENDIAN));
- writel(0x0, HPRE_ADDR(qm, HPRE_INT_MASK));
- writel(0x0, HPRE_ADDR(qm, HPRE_POISON_BYPASS));
- writel(0x0, HPRE_ADDR(qm, HPRE_COMM_CNT_CLR_CE));
- writel(0x0, HPRE_ADDR(qm, HPRE_ECC_BYPASS));
-
- writel(HPRE_BD_USR_MASK, HPRE_ADDR(qm, HPRE_BD_ARUSR_CFG));
- writel(HPRE_BD_USR_MASK, HPRE_ADDR(qm, HPRE_BD_AWUSR_CFG));
- writel(0x1, HPRE_ADDR(qm, HPRE_RDCHN_INI_CFG));
- ret = readl_relaxed_poll_timeout(HPRE_ADDR(qm, HPRE_RDCHN_INI_ST), val,
- val & BIT(0),
+ writel(HPRE_RSA_ENB, qm->io_base + HPRE_TYPES_ENB);
+
+ writel(HPRE_QM_VFG_AX_MASK, qm->io_base + HPRE_VFG_AXCACHE);
+ writel(0x0, qm->io_base + HPRE_BD_ENDIAN);
+ writel(0x0, qm->io_base + HPRE_INT_MASK);
+ writel(0x0, qm->io_base + HPRE_POISON_BYPASS);
+ writel(0x0, qm->io_base + HPRE_COMM_CNT_CLR_CE);
+ writel(0x0, qm->io_base + HPRE_ECC_BYPASS);
+
+ writel(HPRE_BD_USR_MASK, qm->io_base + HPRE_BD_ARUSR_CFG);
+ writel(HPRE_BD_USR_MASK, qm->io_base + HPRE_BD_AWUSR_CFG);
+ writel(0x1, qm->io_base + HPRE_RDCHN_INI_CFG);
+ ret = readl_relaxed_poll_timeout(qm->io_base + HPRE_RDCHN_INI_ST, val,
+ val & BIT(0),
HPRE_REG_RD_INTVRL_US,
HPRE_REG_RD_TMOUT_US);
if (ret) {
@@ -397,7 +478,7 @@ static int hpre_set_user_domain_and_cache(struct hisi_qm *qm)
static void hpre_cnt_regs_clear(struct hisi_qm *qm)
{
- u8 clusters_num = HPRE_CLUSTERS_NUM(qm);
+ u8 clusters_num = hpre_cluster_num(qm);
unsigned long offset;
int i;
@@ -413,36 +494,49 @@ static void hpre_cnt_regs_clear(struct hisi_qm *qm)
hisi_qm_debug_regs_clear(qm);
}
-static void hpre_hw_error_disable(struct hisi_qm *qm)
+static void hpre_master_ooo_ctrl(struct hisi_qm *qm, bool enable)
{
- u32 val;
+ u32 val1, val2;
+
+ val1 = readl(qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
+ if (enable) {
+ val1 |= HPRE_AM_OOO_SHUTDOWN_ENABLE;
+ val2 = HPRE_HAC_RAS_NFE_ENABLE;
+ } else {
+ val1 &= ~HPRE_AM_OOO_SHUTDOWN_ENABLE;
+ val2 = 0x0;
+ }
+
+ if (qm->ver > QM_HW_V2)
+ writel(val2, qm->io_base + HPRE_OOO_SHUTDOWN_SEL);
+
+ writel(val1, qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
+}
+static void hpre_hw_error_disable(struct hisi_qm *qm)
+{
/* disable hpre hw error interrupts */
writel(HPRE_CORE_INT_DISABLE, qm->io_base + HPRE_INT_MASK);
- /* disable HPRE block master OOO when m-bit error occur */
- val = readl(qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
- val &= ~HPRE_AM_OOO_SHUTDOWN_ENABLE;
- writel(val, qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
+ /* disable HPRE block master OOO when nfe occurs on Kunpeng930 */
+ hpre_master_ooo_ctrl(qm, false);
}
static void hpre_hw_error_enable(struct hisi_qm *qm)
{
- u32 val;
-
/* clear HPRE hw error source if having */
writel(HPRE_CORE_INT_DISABLE, qm->io_base + HPRE_HAC_SOURCE_INT);
- /* enable hpre hw error interrupts */
- writel(HPRE_CORE_INT_ENABLE, qm->io_base + HPRE_INT_MASK);
+ /* configure error type */
writel(HPRE_HAC_RAS_CE_ENABLE, qm->io_base + HPRE_RAS_CE_ENB);
writel(HPRE_HAC_RAS_NFE_ENABLE, qm->io_base + HPRE_RAS_NFE_ENB);
writel(HPRE_HAC_RAS_FE_ENABLE, qm->io_base + HPRE_RAS_FE_ENB);
- /* enable HPRE block master OOO when m-bit error occur */
- val = readl(qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
- val |= HPRE_AM_OOO_SHUTDOWN_ENABLE;
- writel(val, qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
+ /* enable HPRE block master OOO when nfe occurs on Kunpeng930 */
+ hpre_master_ooo_ctrl(qm, true);
+
+ /* enable hpre hw error interrupts */
+ writel(HPRE_CORE_INT_ENABLE, qm->io_base + HPRE_INT_MASK);
}
static inline struct hisi_qm *hpre_file_to_qm(struct hpre_debugfs_file *file)
@@ -650,7 +744,7 @@ static int hpre_pf_comm_regs_debugfs_init(struct hisi_qm *qm)
static int hpre_cluster_debugfs_init(struct hisi_qm *qm)
{
- u8 clusters_num = HPRE_CLUSTERS_NUM(qm);
+ u8 clusters_num = hpre_cluster_num(qm);
struct device *dev = &qm->pdev->dev;
char buf[HPRE_DBGFS_VAL_MAX_LEN];
struct debugfs_regset32 *regset;
@@ -788,7 +882,7 @@ static void hpre_log_hw_error(struct hisi_qm *qm, u32 err_sts)
static u32 hpre_get_hw_err_status(struct hisi_qm *qm)
{
- return readl(qm->io_base + HPRE_HAC_INT_STATUS);
+ return readl(qm->io_base + HPRE_INT_STATUS);
}
static void hpre_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts)
@@ -802,9 +896,9 @@ static void hpre_open_axi_master_ooo(struct hisi_qm *qm)
value = readl(qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
writel(value & ~HPRE_AM_OOO_SHUTDOWN_ENABLE,
- HPRE_ADDR(qm, HPRE_AM_OOO_SHUTDOWN_ENB));
+ qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
writel(value | HPRE_AM_OOO_SHUTDOWN_ENABLE,
- HPRE_ADDR(qm, HPRE_AM_OOO_SHUTDOWN_ENB));
+ qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB);
}
static void hpre_err_info_init(struct hisi_qm *qm)
@@ -829,6 +923,8 @@ static const struct hisi_qm_err_ini hpre_err_ini = {
.clear_dev_hw_err_status = hpre_clear_hw_err_status,
.log_dev_hw_err = hpre_log_hw_error,
.open_axi_master_ooo = hpre_open_axi_master_ooo,
+ .open_sva_prefetch = hpre_open_sva_prefetch,
+ .close_sva_prefetch = hpre_close_sva_prefetch,
.err_info_init = hpre_err_info_init,
};
@@ -841,6 +937,8 @@ static int hpre_pf_probe_init(struct hpre *hpre)
if (ret)
return ret;
+ hpre_open_sva_prefetch(qm);
+
qm->err_ini = &hpre_err_ini;
qm->err_ini->err_info_init(qm);
hisi_qm_dev_err_init(qm);
@@ -850,6 +948,7 @@ static int hpre_pf_probe_init(struct hpre *hpre)
static int hpre_probe_init(struct hpre *hpre)
{
+ u32 type_rate = HPRE_SHAPER_TYPE_RATE;
struct hisi_qm *qm = &hpre->qm;
int ret;
@@ -857,6 +956,11 @@ static int hpre_probe_init(struct hpre *hpre)
ret = hpre_pf_probe_init(hpre);
if (ret)
return ret;
+ /* Enable shaper type 0 */
+ if (qm->ver >= QM_HW_V3) {
+ type_rate |= QM_SHAPER_ENABLE;
+ qm->type_rate = type_rate;
+ }
}
return 0;
diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c
index ce439a0c66c9..1d67f94a1d56 100644
--- a/drivers/crypto/hisilicon/qm.c
+++ b/drivers/crypto/hisilicon/qm.c
@@ -25,9 +25,11 @@
#define QM_IRQ_NUM_V1 1
#define QM_IRQ_NUM_PF_V2 4
#define QM_IRQ_NUM_VF_V2 2
+#define QM_IRQ_NUM_VF_V3 3
#define QM_EQ_EVENT_IRQ_VECTOR 0
#define QM_AEQ_EVENT_IRQ_VECTOR 1
+#define QM_CMD_EVENT_IRQ_VECTOR 2
#define QM_ABNORMAL_EVENT_IRQ_VECTOR 3
/* mailbox */
@@ -39,6 +41,8 @@
#define QM_MB_CMD_CQC_BT 0x5
#define QM_MB_CMD_SQC_VFT_V2 0x6
#define QM_MB_CMD_STOP_QP 0x8
+#define QM_MB_CMD_SRC 0xc
+#define QM_MB_CMD_DST 0xd
#define QM_MB_CMD_SEND_BASE 0x300
#define QM_MB_EVENT_SHIFT 8
@@ -46,6 +50,9 @@
#define QM_MB_OP_SHIFT 14
#define QM_MB_CMD_DATA_ADDR_L 0x304
#define QM_MB_CMD_DATA_ADDR_H 0x308
+#define QM_MB_PING_ALL_VFS 0xffff
+#define QM_MB_CMD_DATA_SHIFT 32
+#define QM_MB_CMD_DATA_MASK GENMASK(31, 0)
/* sqc shift */
#define QM_SQ_HOP_NUM_SHIFT 0
@@ -95,6 +102,7 @@
#define QM_DOORBELL_SQ_CQ_BASE_V2 0x1000
#define QM_DOORBELL_EQ_AEQ_BASE_V2 0x2000
#define QM_QUE_ISO_CFG_V 0x0030
+#define QM_PAGE_SIZE 0x0034
#define QM_QUE_ISO_EN 0x100154
#define QM_CAPBILITY 0x100158
#define QM_QP_NUN_MASK GENMASK(10, 0)
@@ -155,11 +163,15 @@
#define QM_RAS_CE_THRESHOLD 0x1000f8
#define QM_RAS_CE_TIMES_PER_IRQ 1
#define QM_RAS_MSI_INT_SEL 0x1040f4
+#define QM_OOO_SHUTDOWN_SEL 0x1040f8
#define QM_RESET_WAIT_TIMEOUT 400
#define QM_PEH_VENDOR_ID 0x1000d8
#define ACC_VENDOR_ID_VALUE 0x5a5a
#define QM_PEH_DFX_INFO0 0x1000fc
+#define QM_PEH_DFX_INFO1 0x100100
+#define QM_PEH_DFX_MASK (BIT(0) | BIT(2))
+#define QM_PEH_MSI_FINISH_MASK GENMASK(19, 16)
#define ACC_PEH_SRIOV_CTRL_VF_MSE_SHIFT 3
#define ACC_PEH_MSI_DISABLE GENMASK(31, 0)
#define ACC_MASTER_GLOBAL_CTRL_SHUTDOWN 0x1
@@ -170,6 +182,31 @@
#define QM_RAS_NFE_MBIT_DISABLE ~QM_ECC_MBIT
#define ACC_AM_ROB_ECC_INT_STS 0x300104
#define ACC_ROB_ECC_ERR_MULTPL BIT(1)
+#define QM_MSI_CAP_ENABLE BIT(16)
+
+/* interfunction communication */
+#define QM_IFC_READY_STATUS 0x100128
+#define QM_IFC_C_STS_M 0x10012C
+#define QM_IFC_INT_SET_P 0x100130
+#define QM_IFC_INT_CFG 0x100134
+#define QM_IFC_INT_SOURCE_P 0x100138
+#define QM_IFC_INT_SOURCE_V 0x0020
+#define QM_IFC_INT_MASK 0x0024
+#define QM_IFC_INT_STATUS 0x0028
+#define QM_IFC_INT_SET_V 0x002C
+#define QM_IFC_SEND_ALL_VFS GENMASK(6, 0)
+#define QM_IFC_INT_SOURCE_CLR GENMASK(63, 0)
+#define QM_IFC_INT_SOURCE_MASK BIT(0)
+#define QM_IFC_INT_DISABLE BIT(0)
+#define QM_IFC_INT_STATUS_MASK BIT(0)
+#define QM_IFC_INT_SET_MASK BIT(0)
+#define QM_WAIT_DST_ACK 10
+#define QM_MAX_PF_WAIT_COUNT 10
+#define QM_MAX_VF_WAIT_COUNT 40
+#define QM_VF_RESET_WAIT_US 20000
+#define QM_VF_RESET_WAIT_CNT 3000
+#define QM_VF_RESET_WAIT_TIMEOUT_US \
+ (QM_VF_RESET_WAIT_US * QM_VF_RESET_WAIT_CNT)
#define QM_DFX_MB_CNT_VF 0x104010
#define QM_DFX_DB_CNT_VF 0x104020
@@ -205,6 +242,33 @@
#define QM_DRIVER_REMOVING 0
#define QM_RST_SCHED 1
#define QM_RESETTING 2
+#define QM_QOS_PARAM_NUM 2
+#define QM_QOS_VAL_NUM 1
+#define QM_QOS_BDF_PARAM_NUM 4
+#define QM_QOS_MAX_VAL 1000
+#define QM_QOS_RATE 100
+#define QM_QOS_EXPAND_RATE 1000
+#define QM_SHAPER_CIR_B_MASK GENMASK(7, 0)
+#define QM_SHAPER_CIR_U_MASK GENMASK(10, 8)
+#define QM_SHAPER_CIR_S_MASK GENMASK(14, 11)
+#define QM_SHAPER_FACTOR_CIR_U_SHIFT 8
+#define QM_SHAPER_FACTOR_CIR_S_SHIFT 11
+#define QM_SHAPER_FACTOR_CBS_B_SHIFT 15
+#define QM_SHAPER_FACTOR_CBS_S_SHIFT 19
+#define QM_SHAPER_CBS_B 1
+#define QM_SHAPER_CBS_S 16
+#define QM_SHAPER_VFT_OFFSET 6
+#define WAIT_FOR_QOS_VF 100
+#define QM_QOS_MIN_ERROR_RATE 5
+#define QM_QOS_TYPICAL_NUM 8
+#define QM_SHAPER_MIN_CBS_S 8
+#define QM_QOS_TICK 0x300U
+#define QM_QOS_DIVISOR_CLK 0x1f40U
+#define QM_QOS_MAX_CIR_B 200
+#define QM_QOS_MIN_CIR_B 100
+#define QM_QOS_MAX_CIR_U 6
+#define QM_QOS_MAX_CIR_S 11
+#define QM_QOS_VAL_MAX_LEN 32
#define QM_MK_CQC_DW3_V1(hop_num, pg_sz, buf_sz, cqe_sz) \
(((hop_num) << QM_CQ_HOP_NUM_SHIFT) | \
@@ -245,6 +309,7 @@
enum vft_type {
SQC_VFT = 0,
CQC_VFT,
+ SHAPER_VFT,
};
enum acc_err_result {
@@ -253,6 +318,23 @@ enum acc_err_result {
ACC_ERR_RECOVERED,
};
+enum qm_alg_type {
+ ALG_TYPE_0,
+ ALG_TYPE_1,
+};
+
+enum qm_mb_cmd {
+ QM_PF_FLR_PREPARE = 0x01,
+ QM_PF_SRST_PREPARE,
+ QM_PF_RESET_DONE,
+ QM_VF_PREPARE_DONE,
+ QM_VF_PREPARE_FAIL,
+ QM_VF_START_DONE,
+ QM_VF_START_FAIL,
+ QM_PF_SET_QOS,
+ QM_VF_GET_QOS,
+};
+
struct qm_cqe {
__le32 rsvd0;
__le16 cmd_id;
@@ -351,6 +433,9 @@ struct hisi_qm_hw_ops {
void (*hw_error_uninit)(struct hisi_qm *qm);
enum acc_err_result (*hw_error_handle)(struct hisi_qm *qm);
int (*stop_qp)(struct hisi_qp *qp);
+ int (*set_msi)(struct hisi_qm *qm, bool set);
+ int (*ping_all_vfs)(struct hisi_qm *qm, u64 cmd);
+ int (*ping_pf)(struct hisi_qm *qm, u64 cmd);
};
struct qm_dfx_item {
@@ -412,6 +497,11 @@ static const char * const qp_s[] = {
"none", "init", "start", "stop", "close",
};
+static const u32 typical_qos_val[QM_QOS_TYPICAL_NUM] = {100, 250, 500, 1000,
+ 10000, 25000, 50000, 100000};
+static const u32 typical_qos_cbs_s[QM_QOS_TYPICAL_NUM] = {9, 10, 11, 12, 16,
+ 17, 18, 19};
+
static bool qm_avail_state(struct hisi_qm *qm, enum qm_state new)
{
enum qm_state curr = atomic_read(&qm->status.flags);
@@ -491,6 +581,18 @@ static bool qm_qp_avail_state(struct hisi_qm *qm, struct hisi_qp *qp,
return avail;
}
+static void qm_mb_pre_init(struct qm_mailbox *mailbox, u8 cmd,
+ u64 base, u16 queue, bool op)
+{
+ mailbox->w0 = cpu_to_le16((cmd) |
+ ((op) ? 0x1 << QM_MB_OP_SHIFT : 0) |
+ (0x1 << QM_MB_BUSY_SHIFT));
+ mailbox->queue_num = cpu_to_le16(queue);
+ mailbox->base_l = cpu_to_le32(lower_32_bits(base));
+ mailbox->base_h = cpu_to_le32(upper_32_bits(base));
+ mailbox->rsvd = 0;
+}
+
/* return 0 mailbox ready, -ETIMEDOUT hardware timeout */
static int qm_wait_mb_ready(struct hisi_qm *qm)
{
@@ -523,44 +625,42 @@ static void qm_mb_write(struct hisi_qm *qm, const void *src)
: "memory");
}
-static int qm_mb(struct hisi_qm *qm, u8 cmd, dma_addr_t dma_addr, u16 queue,
- bool op)
+static int qm_mb_nolock(struct hisi_qm *qm, struct qm_mailbox *mailbox)
{
- struct qm_mailbox mailbox;
- int ret = 0;
-
- dev_dbg(&qm->pdev->dev, "QM mailbox request to q%u: %u-%llx\n",
- queue, cmd, (unsigned long long)dma_addr);
-
- mailbox.w0 = cpu_to_le16(cmd |
- (op ? 0x1 << QM_MB_OP_SHIFT : 0) |
- (0x1 << QM_MB_BUSY_SHIFT));
- mailbox.queue_num = cpu_to_le16(queue);
- mailbox.base_l = cpu_to_le32(lower_32_bits(dma_addr));
- mailbox.base_h = cpu_to_le32(upper_32_bits(dma_addr));
- mailbox.rsvd = 0;
-
- mutex_lock(&qm->mailbox_lock);
-
if (unlikely(qm_wait_mb_ready(qm))) {
- ret = -EBUSY;
dev_err(&qm->pdev->dev, "QM mailbox is busy to start!\n");
- goto busy_unlock;
+ goto mb_busy;
}
- qm_mb_write(qm, &mailbox);
+ qm_mb_write(qm, mailbox);
if (unlikely(qm_wait_mb_ready(qm))) {
- ret = -EBUSY;
dev_err(&qm->pdev->dev, "QM mailbox operation timeout!\n");
- goto busy_unlock;
+ goto mb_busy;
}
-busy_unlock:
+ return 0;
+
+mb_busy:
+ atomic64_inc(&qm->debug.dfx.mb_err_cnt);
+ return -EBUSY;
+}
+
+static int qm_mb(struct hisi_qm *qm, u8 cmd, dma_addr_t dma_addr, u16 queue,
+ bool op)
+{
+ struct qm_mailbox mailbox;
+ int ret;
+
+ dev_dbg(&qm->pdev->dev, "QM mailbox request to q%u: %u-%llx\n",
+ queue, cmd, (unsigned long long)dma_addr);
+
+ qm_mb_pre_init(&mailbox, cmd, dma_addr, queue, op);
+
+ mutex_lock(&qm->mailbox_lock);
+ ret = qm_mb_nolock(qm, &mailbox);
mutex_unlock(&qm->mailbox_lock);
- if (ret)
- atomic64_inc(&qm->debug.dfx.mb_err_cnt);
return ret;
}
@@ -626,6 +726,14 @@ static u32 qm_get_irq_num_v2(struct hisi_qm *qm)
return QM_IRQ_NUM_VF_V2;
}
+static u32 qm_get_irq_num_v3(struct hisi_qm *qm)
+{
+ if (qm->fun_type == QM_HW_PF)
+ return QM_IRQ_NUM_PF_V2;
+
+ return QM_IRQ_NUM_VF_V3;
+}
+
static struct hisi_qp *qm_to_hisi_qp(struct hisi_qm *qm, struct qm_eqe *eqe)
{
u16 cqn = le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK;
@@ -730,6 +838,21 @@ static irqreturn_t qm_irq(int irq, void *data)
return IRQ_NONE;
}
+static irqreturn_t qm_mb_cmd_irq(int irq, void *data)
+{
+ struct hisi_qm *qm = data;
+ u32 val;
+
+ val = readl(qm->io_base + QM_IFC_INT_STATUS);
+ val &= QM_IFC_INT_STATUS_MASK;
+ if (!val)
+ return IRQ_NONE;
+
+ schedule_work(&qm->cmd_process);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t qm_aeq_irq(int irq, void *data)
{
struct hisi_qm *qm = data;
@@ -770,14 +893,16 @@ static void qm_irq_unregister(struct hisi_qm *qm)
free_irq(pci_irq_vector(pdev, QM_EQ_EVENT_IRQ_VECTOR), qm);
- if (qm->ver == QM_HW_V1)
- return;
+ if (qm->ver > QM_HW_V1) {
+ free_irq(pci_irq_vector(pdev, QM_AEQ_EVENT_IRQ_VECTOR), qm);
- free_irq(pci_irq_vector(pdev, QM_AEQ_EVENT_IRQ_VECTOR), qm);
+ if (qm->fun_type == QM_HW_PF)
+ free_irq(pci_irq_vector(pdev,
+ QM_ABNORMAL_EVENT_IRQ_VECTOR), qm);
+ }
- if (qm->fun_type == QM_HW_PF)
- free_irq(pci_irq_vector(pdev,
- QM_ABNORMAL_EVENT_IRQ_VECTOR), qm);
+ if (qm->ver > QM_HW_V2)
+ free_irq(pci_irq_vector(pdev, QM_CMD_EVENT_IRQ_VECTOR), qm);
}
static void qm_init_qp_status(struct hisi_qp *qp)
@@ -790,8 +915,95 @@ static void qm_init_qp_status(struct hisi_qp *qp)
atomic_set(&qp_status->used, 0);
}
+static void qm_init_prefetch(struct hisi_qm *qm)
+{
+ struct device *dev = &qm->pdev->dev;
+ u32 page_type = 0x0;
+
+ if (qm->ver < QM_HW_V3)
+ return;
+
+ switch (PAGE_SIZE) {
+ case SZ_4K:
+ page_type = 0x0;
+ break;
+ case SZ_16K:
+ page_type = 0x1;
+ break;
+ case SZ_64K:
+ page_type = 0x2;
+ break;
+ default:
+ dev_err(dev, "system page size is not support: %lu, default set to 4KB",
+ PAGE_SIZE);
+ }
+
+ writel(page_type, qm->io_base + QM_PAGE_SIZE);
+}
+
+/*
+ * the formula:
+ * IR = X Mbps if ir = 1 means IR = 100 Mbps, if ir = 10000 means = 10Gbps
+ *
+ * IR_b * (2 ^ IR_u) * 8
+ * IR(Mbps) * 10 ^ -3 = -------------------------
+ * Tick * (2 ^ IR_s)
+ */
+static u32 acc_shaper_para_calc(u64 cir_b, u64 cir_u, u64 cir_s)
+{
+ return ((cir_b * QM_QOS_DIVISOR_CLK) * (1 << cir_u)) /
+ (QM_QOS_TICK * (1 << cir_s));
+}
+
+static u32 acc_shaper_calc_cbs_s(u32 ir)
+{
+ int i;
+
+ if (ir < typical_qos_val[0])
+ return QM_SHAPER_MIN_CBS_S;
+
+ for (i = 1; i < QM_QOS_TYPICAL_NUM; i++) {
+ if (ir >= typical_qos_val[i - 1] && ir < typical_qos_val[i])
+ return typical_qos_cbs_s[i - 1];
+ }
+
+ return typical_qos_cbs_s[QM_QOS_TYPICAL_NUM - 1];
+}
+
+static int qm_get_shaper_para(u32 ir, struct qm_shaper_factor *factor)
+{
+ u32 cir_b, cir_u, cir_s, ir_calc;
+ u32 error_rate;
+
+ factor->cbs_s = acc_shaper_calc_cbs_s(ir);
+
+ for (cir_b = QM_QOS_MIN_CIR_B; cir_b <= QM_QOS_MAX_CIR_B; cir_b++) {
+ for (cir_u = 0; cir_u <= QM_QOS_MAX_CIR_U; cir_u++) {
+ for (cir_s = 0; cir_s <= QM_QOS_MAX_CIR_S; cir_s++) {
+ /** the formula is changed to:
+ * IR_b * (2 ^ IR_u) * DIVISOR_CLK
+ * IR(Mbps) = -------------------------
+ * 768 * (2 ^ IR_s)
+ */
+ ir_calc = acc_shaper_para_calc(cir_b, cir_u,
+ cir_s);
+ error_rate = QM_QOS_EXPAND_RATE * (u32)abs(ir_calc - ir) / ir;
+ if (error_rate <= QM_QOS_MIN_ERROR_RATE) {
+ factor->cir_b = cir_b;
+ factor->cir_u = cir_u;
+ factor->cir_s = cir_s;
+
+ return 0;
+ }
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
static void qm_vft_data_cfg(struct hisi_qm *qm, enum vft_type type, u32 base,
- u32 number)
+ u32 number, struct qm_shaper_factor *factor)
{
u64 tmp = 0;
@@ -820,6 +1032,15 @@ static void qm_vft_data_cfg(struct hisi_qm *qm, enum vft_type type, u32 base,
tmp = QM_CQC_VFT_VALID;
}
break;
+ case SHAPER_VFT:
+ if (qm->ver >= QM_HW_V3) {
+ tmp = factor->cir_b |
+ (factor->cir_u << QM_SHAPER_FACTOR_CIR_U_SHIFT) |
+ (factor->cir_s << QM_SHAPER_FACTOR_CIR_S_SHIFT) |
+ (QM_SHAPER_CBS_B << QM_SHAPER_FACTOR_CBS_B_SHIFT) |
+ (factor->cbs_s << QM_SHAPER_FACTOR_CBS_S_SHIFT);
+ }
+ break;
}
}
@@ -830,6 +1051,7 @@ static void qm_vft_data_cfg(struct hisi_qm *qm, enum vft_type type, u32 base,
static int qm_set_vft_common(struct hisi_qm *qm, enum vft_type type,
u32 fun_num, u32 base, u32 number)
{
+ struct qm_shaper_factor *factor = &qm->factor[fun_num];
unsigned int val;
int ret;
@@ -841,9 +1063,12 @@ static int qm_set_vft_common(struct hisi_qm *qm, enum vft_type type,
writel(0x0, qm->io_base + QM_VFT_CFG_OP_WR);
writel(type, qm->io_base + QM_VFT_CFG_TYPE);
+ if (type == SHAPER_VFT)
+ fun_num |= base << QM_SHAPER_VFT_OFFSET;
+
writel(fun_num, qm->io_base + QM_VFT_CFG);
- qm_vft_data_cfg(qm, type, base, number);
+ qm_vft_data_cfg(qm, type, base, number, factor);
writel(0x0, qm->io_base + QM_VFT_CFG_RDY);
writel(0x1, qm->io_base + QM_VFT_CFG_OP_ENABLE);
@@ -853,6 +1078,27 @@ static int qm_set_vft_common(struct hisi_qm *qm, enum vft_type type,
POLL_TIMEOUT);
}
+static int qm_shaper_init_vft(struct hisi_qm *qm, u32 fun_num)
+{
+ int ret, i;
+
+ qm->factor[fun_num].func_qos = QM_QOS_MAX_VAL;
+ ret = qm_get_shaper_para(QM_QOS_MAX_VAL * QM_QOS_RATE, &qm->factor[fun_num]);
+ if (ret) {
+ dev_err(&qm->pdev->dev, "failed to calculate shaper parameter!\n");
+ return ret;
+ }
+ writel(qm->type_rate, qm->io_base + QM_SHAPER_CFG);
+ for (i = ALG_TYPE_0; i <= ALG_TYPE_1; i++) {
+ /* The base number of queue reuse for different alg type */
+ ret = qm_set_vft_common(qm, SHAPER_VFT, fun_num, i, 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
/* The config should be conducted after qm_dev_mem_reset() */
static int qm_set_sqc_cqc_vft(struct hisi_qm *qm, u32 fun_num, u32 base,
u32 number)
@@ -865,7 +1111,21 @@ static int qm_set_sqc_cqc_vft(struct hisi_qm *qm, u32 fun_num, u32 base,
return ret;
}
+ /* init default shaper qos val */
+ if (qm->ver >= QM_HW_V3) {
+ ret = qm_shaper_init_vft(qm, fun_num);
+ if (ret)
+ goto back_sqc_cqc;
+ }
+
return 0;
+back_sqc_cqc:
+ for (i = SQC_VFT; i <= CQC_VFT; i++) {
+ ret = qm_set_vft_common(qm, i, fun_num, 0, 0);
+ if (ret)
+ return ret;
+ }
+ return ret;
}
static int qm_get_vft_v2(struct hisi_qm *qm, u32 *base, u32 *number)
@@ -1570,16 +1830,9 @@ static ssize_t qm_cmd_write(struct file *filp, const char __user *buffer,
if (count > QM_DBG_WRITE_LEN)
return -ENOSPC;
- cmd_buf = kzalloc(count + 1, GFP_KERNEL);
- if (!cmd_buf)
- return -ENOMEM;
-
- if (copy_from_user(cmd_buf, buffer, count)) {
- kfree(cmd_buf);
- return -EFAULT;
- }
-
- cmd_buf[count] = '\0';
+ cmd_buf = memdup_user_nul(buffer, count);
+ if (IS_ERR(cmd_buf))
+ return PTR_ERR(cmd_buf);
cmd_buf_tmp = strchr(cmd_buf, '\n');
if (cmd_buf_tmp) {
@@ -1623,13 +1876,9 @@ static void qm_hw_error_init_v1(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe)
writel(QM_ABNORMAL_INT_MASK_VALUE, qm->io_base + QM_ABNORMAL_INT_MASK);
}
-static void qm_hw_error_init_v2(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe)
+static void qm_hw_error_cfg(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe)
{
- u32 irq_enable = ce | nfe | fe;
- u32 irq_unmask = ~irq_enable;
-
qm->error_mask = ce | nfe | fe;
-
/* clear QM hw residual error source */
writel(QM_ABNORMAL_INT_SOURCE_CLR,
qm->io_base + QM_ABNORMAL_INT_SOURCE);
@@ -1639,6 +1888,14 @@ static void qm_hw_error_init_v2(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe)
writel(QM_RAS_CE_TIMES_PER_IRQ, qm->io_base + QM_RAS_CE_THRESHOLD);
writel(nfe, qm->io_base + QM_RAS_NFE_ENABLE);
writel(fe, qm->io_base + QM_RAS_FE_ENABLE);
+}
+
+static void qm_hw_error_init_v2(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe)
+{
+ u32 irq_enable = ce | nfe | fe;
+ u32 irq_unmask = ~irq_enable;
+
+ qm_hw_error_cfg(qm, ce, nfe, fe);
irq_unmask &= readl(qm->io_base + QM_ABNORMAL_INT_MASK);
writel(irq_unmask, qm->io_base + QM_ABNORMAL_INT_MASK);
@@ -1649,6 +1906,28 @@ static void qm_hw_error_uninit_v2(struct hisi_qm *qm)
writel(QM_ABNORMAL_INT_MASK_VALUE, qm->io_base + QM_ABNORMAL_INT_MASK);
}
+static void qm_hw_error_init_v3(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe)
+{
+ u32 irq_enable = ce | nfe | fe;
+ u32 irq_unmask = ~irq_enable;
+
+ qm_hw_error_cfg(qm, ce, nfe, fe);
+
+ /* enable close master ooo when hardware error happened */
+ writel(nfe & (~QM_DB_RANDOM_INVALID), qm->io_base + QM_OOO_SHUTDOWN_SEL);
+
+ irq_unmask &= readl(qm->io_base + QM_ABNORMAL_INT_MASK);
+ writel(irq_unmask, qm->io_base + QM_ABNORMAL_INT_MASK);
+}
+
+static void qm_hw_error_uninit_v3(struct hisi_qm *qm)
+{
+ writel(QM_ABNORMAL_INT_MASK_VALUE, qm->io_base + QM_ABNORMAL_INT_MASK);
+
+ /* disable close master ooo when hardware error happened */
+ writel(0x0, qm->io_base + QM_OOO_SHUTDOWN_SEL);
+}
+
static void qm_log_hw_error(struct hisi_qm *qm, u32 error_status)
{
const struct hisi_qm_hw_error *err;
@@ -1715,15 +1994,371 @@ static enum acc_err_result qm_hw_error_handle_v2(struct hisi_qm *qm)
return ACC_ERR_RECOVERED;
}
+static u32 qm_get_hw_error_status(struct hisi_qm *qm)
+{
+ return readl(qm->io_base + QM_ABNORMAL_INT_STATUS);
+}
+
+static u32 qm_get_dev_err_status(struct hisi_qm *qm)
+{
+ return qm->err_ini->get_dev_hw_err_status(qm);
+}
+
+/* Check if the error causes the master ooo block */
+static int qm_check_dev_error(struct hisi_qm *qm)
+{
+ u32 val, dev_val;
+
+ if (qm->fun_type == QM_HW_VF)
+ return 0;
+
+ val = qm_get_hw_error_status(qm);
+ dev_val = qm_get_dev_err_status(qm);
+
+ if (qm->ver < QM_HW_V3)
+ return (val & QM_ECC_MBIT) ||
+ (dev_val & qm->err_info.ecc_2bits_mask);
+
+ return (val & readl(qm->io_base + QM_OOO_SHUTDOWN_SEL)) ||
+ (dev_val & (~qm->err_info.dev_ce_mask));
+}
+
+static int qm_get_mb_cmd(struct hisi_qm *qm, u64 *msg, u16 fun_num)
+{
+ struct qm_mailbox mailbox;
+ int ret;
+
+ qm_mb_pre_init(&mailbox, QM_MB_CMD_DST, 0, fun_num, 0);
+ mutex_lock(&qm->mailbox_lock);
+ ret = qm_mb_nolock(qm, &mailbox);
+ if (ret)
+ goto err_unlock;
+
+ *msg = readl(qm->io_base + QM_MB_CMD_DATA_ADDR_L) |
+ ((u64)readl(qm->io_base + QM_MB_CMD_DATA_ADDR_H) << 32);
+
+err_unlock:
+ mutex_unlock(&qm->mailbox_lock);
+ return ret;
+}
+
+static void qm_clear_cmd_interrupt(struct hisi_qm *qm, u64 vf_mask)
+{
+ u32 val;
+
+ if (qm->fun_type == QM_HW_PF)
+ writeq(vf_mask, qm->io_base + QM_IFC_INT_SOURCE_P);
+
+ val = readl(qm->io_base + QM_IFC_INT_SOURCE_V);
+ val |= QM_IFC_INT_SOURCE_MASK;
+ writel(val, qm->io_base + QM_IFC_INT_SOURCE_V);
+}
+
+static void qm_handle_vf_msg(struct hisi_qm *qm, u32 vf_id)
+{
+ struct device *dev = &qm->pdev->dev;
+ u32 cmd;
+ u64 msg;
+ int ret;
+
+ ret = qm_get_mb_cmd(qm, &msg, vf_id);
+ if (ret) {
+ dev_err(dev, "failed to get msg from VF(%u)!\n", vf_id);
+ return;
+ }
+
+ cmd = msg & QM_MB_CMD_DATA_MASK;
+ switch (cmd) {
+ case QM_VF_PREPARE_FAIL:
+ dev_err(dev, "failed to stop VF(%u)!\n", vf_id);
+ break;
+ case QM_VF_START_FAIL:
+ dev_err(dev, "failed to start VF(%u)!\n", vf_id);
+ break;
+ case QM_VF_PREPARE_DONE:
+ case QM_VF_START_DONE:
+ break;
+ default:
+ dev_err(dev, "unsupported cmd %u sent by VF(%u)!\n", cmd, vf_id);
+ break;
+ }
+}
+
+static int qm_wait_vf_prepare_finish(struct hisi_qm *qm)
+{
+ struct device *dev = &qm->pdev->dev;
+ u32 vfs_num = qm->vfs_num;
+ int cnt = 0;
+ int ret = 0;
+ u64 val;
+ u32 i;
+
+ if (!qm->vfs_num || qm->ver < QM_HW_V3)
+ return 0;
+
+ while (true) {
+ val = readq(qm->io_base + QM_IFC_INT_SOURCE_P);
+ /* All VFs send command to PF, break */
+ if ((val & GENMASK(vfs_num, 1)) == GENMASK(vfs_num, 1))
+ break;
+
+ if (++cnt > QM_MAX_PF_WAIT_COUNT) {
+ ret = -EBUSY;
+ break;
+ }
+
+ msleep(QM_WAIT_DST_ACK);
+ }
+
+ /* PF check VFs msg */
+ for (i = 1; i <= vfs_num; i++) {
+ if (val & BIT(i))
+ qm_handle_vf_msg(qm, i);
+ else
+ dev_err(dev, "VF(%u) not ping PF!\n", i);
+ }
+
+ /* PF clear interrupt to ack VFs */
+ qm_clear_cmd_interrupt(qm, val);
+
+ return ret;
+}
+
+static void qm_trigger_vf_interrupt(struct hisi_qm *qm, u32 fun_num)
+{
+ u32 val;
+
+ val = readl(qm->io_base + QM_IFC_INT_CFG);
+ val &= ~QM_IFC_SEND_ALL_VFS;
+ val |= fun_num;
+ writel(val, qm->io_base + QM_IFC_INT_CFG);
+
+ val = readl(qm->io_base + QM_IFC_INT_SET_P);
+ val |= QM_IFC_INT_SET_MASK;
+ writel(val, qm->io_base + QM_IFC_INT_SET_P);
+}
+
+static void qm_trigger_pf_interrupt(struct hisi_qm *qm)
+{
+ u32 val;
+
+ val = readl(qm->io_base + QM_IFC_INT_SET_V);
+ val |= QM_IFC_INT_SET_MASK;
+ writel(val, qm->io_base + QM_IFC_INT_SET_V);
+}
+
+static int qm_ping_single_vf(struct hisi_qm *qm, u64 cmd, u32 fun_num)
+{
+ struct device *dev = &qm->pdev->dev;
+ struct qm_mailbox mailbox;
+ int cnt = 0;
+ u64 val;
+ int ret;
+
+ qm_mb_pre_init(&mailbox, QM_MB_CMD_SRC, cmd, fun_num, 0);
+ mutex_lock(&qm->mailbox_lock);
+ ret = qm_mb_nolock(qm, &mailbox);
+ if (ret) {
+ dev_err(dev, "failed to send command to vf(%u)!\n", fun_num);
+ goto err_unlock;
+ }
+
+ qm_trigger_vf_interrupt(qm, fun_num);
+ while (true) {
+ msleep(QM_WAIT_DST_ACK);
+ val = readq(qm->io_base + QM_IFC_READY_STATUS);
+ /* if VF respond, PF notifies VF successfully. */
+ if (!(val & BIT(fun_num)))
+ goto err_unlock;
+
+ if (++cnt > QM_MAX_PF_WAIT_COUNT) {
+ dev_err(dev, "failed to get response from VF(%u)!\n", fun_num);
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+
+err_unlock:
+ mutex_unlock(&qm->mailbox_lock);
+ return ret;
+}
+
+static int qm_ping_all_vfs(struct hisi_qm *qm, u64 cmd)
+{
+ struct device *dev = &qm->pdev->dev;
+ u32 vfs_num = qm->vfs_num;
+ struct qm_mailbox mailbox;
+ u64 val = 0;
+ int cnt = 0;
+ int ret;
+ u32 i;
+
+ qm_mb_pre_init(&mailbox, QM_MB_CMD_SRC, cmd, QM_MB_PING_ALL_VFS, 0);
+ mutex_lock(&qm->mailbox_lock);
+ /* PF sends command to all VFs by mailbox */
+ ret = qm_mb_nolock(qm, &mailbox);
+ if (ret) {
+ dev_err(dev, "failed to send command to VFs!\n");
+ mutex_unlock(&qm->mailbox_lock);
+ return ret;
+ }
+
+ qm_trigger_vf_interrupt(qm, QM_IFC_SEND_ALL_VFS);
+ while (true) {
+ msleep(QM_WAIT_DST_ACK);
+ val = readq(qm->io_base + QM_IFC_READY_STATUS);
+ /* If all VFs acked, PF notifies VFs successfully. */
+ if (!(val & GENMASK(vfs_num, 1))) {
+ mutex_unlock(&qm->mailbox_lock);
+ return 0;
+ }
+
+ if (++cnt > QM_MAX_PF_WAIT_COUNT)
+ break;
+ }
+
+ mutex_unlock(&qm->mailbox_lock);
+
+ /* Check which vf respond timeout. */
+ for (i = 1; i <= vfs_num; i++) {
+ if (val & BIT(i))
+ dev_err(dev, "failed to get response from VF(%u)!\n", i);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int qm_ping_pf(struct hisi_qm *qm, u64 cmd)
+{
+ struct qm_mailbox mailbox;
+ int cnt = 0;
+ u32 val;
+ int ret;
+
+ qm_mb_pre_init(&mailbox, QM_MB_CMD_SRC, cmd, 0, 0);
+ mutex_lock(&qm->mailbox_lock);
+ ret = qm_mb_nolock(qm, &mailbox);
+ if (ret) {
+ dev_err(&qm->pdev->dev, "failed to send command to PF!\n");
+ goto unlock;
+ }
+
+ qm_trigger_pf_interrupt(qm);
+ /* Waiting for PF response */
+ while (true) {
+ msleep(QM_WAIT_DST_ACK);
+ val = readl(qm->io_base + QM_IFC_INT_SET_V);
+ if (!(val & QM_IFC_INT_STATUS_MASK))
+ break;
+
+ if (++cnt > QM_MAX_VF_WAIT_COUNT) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+
+unlock:
+ mutex_unlock(&qm->mailbox_lock);
+ return ret;
+}
+
static int qm_stop_qp(struct hisi_qp *qp)
{
return qm_mb(qp->qm, QM_MB_CMD_STOP_QP, 0, qp->qp_id, 0);
}
+static int qm_set_msi(struct hisi_qm *qm, bool set)
+{
+ struct pci_dev *pdev = qm->pdev;
+
+ if (set) {
+ pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_MASK_64,
+ 0);
+ } else {
+ pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_MASK_64,
+ ACC_PEH_MSI_DISABLE);
+ if (qm->err_status.is_qm_ecc_mbit ||
+ qm->err_status.is_dev_ecc_mbit)
+ return 0;
+
+ mdelay(1);
+ if (readl(qm->io_base + QM_PEH_DFX_INFO0))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static void qm_wait_msi_finish(struct hisi_qm *qm)
+{
+ struct pci_dev *pdev = qm->pdev;
+ u32 cmd = ~0;
+ int cnt = 0;
+ u32 val;
+ int ret;
+
+ while (true) {
+ pci_read_config_dword(pdev, pdev->msi_cap +
+ PCI_MSI_PENDING_64, &cmd);
+ if (!cmd)
+ break;
+
+ if (++cnt > MAX_WAIT_COUNTS) {
+ pci_warn(pdev, "failed to empty MSI PENDING!\n");
+ break;
+ }
+
+ udelay(1);
+ }
+
+ ret = readl_relaxed_poll_timeout(qm->io_base + QM_PEH_DFX_INFO0,
+ val, !(val & QM_PEH_DFX_MASK),
+ POLL_PERIOD, POLL_TIMEOUT);
+ if (ret)
+ pci_warn(pdev, "failed to empty PEH MSI!\n");
+
+ ret = readl_relaxed_poll_timeout(qm->io_base + QM_PEH_DFX_INFO1,
+ val, !(val & QM_PEH_MSI_FINISH_MASK),
+ POLL_PERIOD, POLL_TIMEOUT);
+ if (ret)
+ pci_warn(pdev, "failed to finish MSI operation!\n");
+}
+
+static int qm_set_msi_v3(struct hisi_qm *qm, bool set)
+{
+ struct pci_dev *pdev = qm->pdev;
+ int ret = -ETIMEDOUT;
+ u32 cmd, i;
+
+ pci_read_config_dword(pdev, pdev->msi_cap, &cmd);
+ if (set)
+ cmd |= QM_MSI_CAP_ENABLE;
+ else
+ cmd &= ~QM_MSI_CAP_ENABLE;
+
+ pci_write_config_dword(pdev, pdev->msi_cap, cmd);
+ if (set) {
+ for (i = 0; i < MAX_WAIT_COUNTS; i++) {
+ pci_read_config_dword(pdev, pdev->msi_cap, &cmd);
+ if (cmd & QM_MSI_CAP_ENABLE)
+ return 0;
+
+ udelay(1);
+ }
+ } else {
+ udelay(WAIT_PERIOD_US_MIN);
+ qm_wait_msi_finish(qm);
+ ret = 0;
+ }
+
+ return ret;
+}
+
static const struct hisi_qm_hw_ops qm_hw_ops_v1 = {
.qm_db = qm_db_v1,
.get_irq_num = qm_get_irq_num_v1,
.hw_error_init = qm_hw_error_init_v1,
+ .set_msi = qm_set_msi,
};
static const struct hisi_qm_hw_ops qm_hw_ops_v2 = {
@@ -1733,16 +2368,20 @@ static const struct hisi_qm_hw_ops qm_hw_ops_v2 = {
.hw_error_init = qm_hw_error_init_v2,
.hw_error_uninit = qm_hw_error_uninit_v2,
.hw_error_handle = qm_hw_error_handle_v2,
+ .set_msi = qm_set_msi,
};
static const struct hisi_qm_hw_ops qm_hw_ops_v3 = {
.get_vft = qm_get_vft_v2,
.qm_db = qm_db_v2,
- .get_irq_num = qm_get_irq_num_v2,
- .hw_error_init = qm_hw_error_init_v2,
- .hw_error_uninit = qm_hw_error_uninit_v2,
+ .get_irq_num = qm_get_irq_num_v3,
+ .hw_error_init = qm_hw_error_init_v3,
+ .hw_error_uninit = qm_hw_error_uninit_v3,
.hw_error_handle = qm_hw_error_handle_v2,
.stop_qp = qm_stop_qp,
+ .set_msi = qm_set_msi_v3,
+ .ping_all_vfs = qm_ping_all_vfs,
+ .ping_pf = qm_ping_pf,
};
static void *qm_get_avail_sqe(struct hisi_qp *qp)
@@ -2017,11 +2656,8 @@ static int qm_drain_qp(struct hisi_qp *qp)
int ret = 0, i = 0;
void *addr;
- /*
- * No need to judge if ECC multi-bit error occurs because the
- * master OOO will be blocked.
- */
- if (qm->err_status.is_qm_ecc_mbit || qm->err_status.is_dev_ecc_mbit)
+ /* No need to judge if master OOO is blocked. */
+ if (qm_check_dev_error(qm))
return 0;
/* Kunpeng930 supports drain qp by device */
@@ -2290,6 +2926,23 @@ static void hisi_qm_uacce_stop_queue(struct uacce_queue *q)
hisi_qm_stop_qp(q->priv);
}
+static int hisi_qm_is_q_updated(struct uacce_queue *q)
+{
+ struct hisi_qp *qp = q->priv;
+ struct qm_cqe *cqe = qp->cqe + qp->qp_status.cq_head;
+ int updated = 0;
+
+ while (QM_CQE_PHASE(cqe) == qp->qp_status.cqc_phase) {
+ /* make sure to read data from memory */
+ dma_rmb();
+ qm_cq_head_update(qp);
+ cqe = qp->cqe + qp->qp_status.cq_head;
+ updated = 1;
+ }
+
+ return updated;
+}
+
static void qm_set_sqctype(struct uacce_queue *q, u16 type)
{
struct hisi_qm *qm = q->uacce->priv;
@@ -2335,6 +2988,7 @@ static const struct uacce_ops uacce_qm_ops = {
.stop_queue = hisi_qm_uacce_stop_queue,
.mmap = hisi_qm_uacce_mmap,
.ioctl = hisi_qm_uacce_ioctl,
+ .is_q_updated = hisi_qm_is_q_updated,
};
static int qm_alloc_uacce(struct hisi_qm *qm)
@@ -2530,62 +3184,6 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id)
return 0;
}
-static int hisi_qm_memory_init(struct hisi_qm *qm)
-{
- struct device *dev = &qm->pdev->dev;
- size_t qp_dma_size, off = 0;
- int i, ret = 0;
-
-#define QM_INIT_BUF(qm, type, num) do { \
- (qm)->type = ((qm)->qdma.va + (off)); \
- (qm)->type##_dma = (qm)->qdma.dma + (off); \
- off += QMC_ALIGN(sizeof(struct qm_##type) * (num)); \
-} while (0)
-
- idr_init(&qm->qp_idr);
- qm->qdma.size = QMC_ALIGN(sizeof(struct qm_eqe) * QM_EQ_DEPTH) +
- QMC_ALIGN(sizeof(struct qm_aeqe) * QM_Q_DEPTH) +
- QMC_ALIGN(sizeof(struct qm_sqc) * qm->qp_num) +
- QMC_ALIGN(sizeof(struct qm_cqc) * qm->qp_num);
- qm->qdma.va = dma_alloc_coherent(dev, qm->qdma.size, &qm->qdma.dma,
- GFP_ATOMIC);
- dev_dbg(dev, "allocate qm dma buf size=%zx)\n", qm->qdma.size);
- if (!qm->qdma.va)
- return -ENOMEM;
-
- QM_INIT_BUF(qm, eqe, QM_EQ_DEPTH);
- QM_INIT_BUF(qm, aeqe, QM_Q_DEPTH);
- QM_INIT_BUF(qm, sqc, qm->qp_num);
- QM_INIT_BUF(qm, cqc, qm->qp_num);
-
- qm->qp_array = kcalloc(qm->qp_num, sizeof(struct hisi_qp), GFP_KERNEL);
- if (!qm->qp_array) {
- ret = -ENOMEM;
- goto err_alloc_qp_array;
- }
-
- /* one more page for device or qp statuses */
- qp_dma_size = qm->sqe_size * QM_Q_DEPTH +
- sizeof(struct qm_cqe) * QM_Q_DEPTH;
- qp_dma_size = PAGE_ALIGN(qp_dma_size);
- for (i = 0; i < qm->qp_num; i++) {
- ret = hisi_qp_memory_init(qm, qp_dma_size, i);
- if (ret)
- goto err_init_qp_mem;
-
- dev_dbg(dev, "allocate qp dma buf size=%zx)\n", qp_dma_size);
- }
-
- return ret;
-
-err_init_qp_mem:
- hisi_qp_memory_uninit(qm, i);
-err_alloc_qp_array:
- dma_free_coherent(dev, qm->qdma.size, qm->qdma.va, qm->qdma.dma);
-
- return ret;
-}
-
static void hisi_qm_pre_init(struct hisi_qm *qm)
{
struct pci_dev *pdev = qm->pdev;
@@ -2604,6 +3202,34 @@ static void hisi_qm_pre_init(struct hisi_qm *qm)
qm->misc_ctl = false;
}
+static void qm_cmd_uninit(struct hisi_qm *qm)
+{
+ u32 val;
+
+ if (qm->ver < QM_HW_V3)
+ return;
+
+ val = readl(qm->io_base + QM_IFC_INT_MASK);
+ val |= QM_IFC_INT_DISABLE;
+ writel(val, qm->io_base + QM_IFC_INT_MASK);
+}
+
+static void qm_cmd_init(struct hisi_qm *qm)
+{
+ u32 val;
+
+ if (qm->ver < QM_HW_V3)
+ return;
+
+ /* Clear communication interrupt source */
+ qm_clear_cmd_interrupt(qm, QM_IFC_INT_SOURCE_CLR);
+
+ /* Enable pf to vf communication reg. */
+ val = readl(qm->io_base + QM_IFC_INT_MASK);
+ val &= ~QM_IFC_INT_DISABLE;
+ writel(val, qm->io_base + QM_IFC_INT_MASK);
+}
+
static void qm_put_pci_res(struct hisi_qm *qm)
{
struct pci_dev *pdev = qm->pdev;
@@ -2635,6 +3261,8 @@ void hisi_qm_uninit(struct hisi_qm *qm)
struct pci_dev *pdev = qm->pdev;
struct device *dev = &pdev->dev;
+ qm_cmd_uninit(qm);
+ kfree(qm->factor);
down_write(&qm->qps_lock);
if (!qm_avail_state(qm, QM_CLOSE)) {
@@ -2826,6 +3454,8 @@ static int __hisi_qm_start(struct hisi_qm *qm)
if (ret)
return ret;
+ qm_init_prefetch(qm);
+
writel(0x0, qm->io_base + QM_VF_EQ_INT_MASK);
writel(0x0, qm->io_base + QM_VF_AEQ_INT_MASK);
@@ -3034,79 +3664,6 @@ static int qm_debugfs_atomic64_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(qm_atomic64_ops, qm_debugfs_atomic64_get,
qm_debugfs_atomic64_set, "%llu\n");
-/**
- * hisi_qm_debug_init() - Initialize qm related debugfs files.
- * @qm: The qm for which we want to add debugfs files.
- *
- * Create qm related debugfs files.
- */
-void hisi_qm_debug_init(struct hisi_qm *qm)
-{
- struct qm_dfx *dfx = &qm->debug.dfx;
- struct dentry *qm_d;
- void *data;
- int i;
-
- qm_d = debugfs_create_dir("qm", qm->debug.debug_root);
- qm->debug.qm_d = qm_d;
-
- /* only show this in PF */
- if (qm->fun_type == QM_HW_PF) {
- qm_create_debugfs_file(qm, qm->debug.debug_root, CURRENT_QM);
- for (i = CURRENT_Q; i < DEBUG_FILE_NUM; i++)
- qm_create_debugfs_file(qm, qm_d, i);
- }
-
- debugfs_create_file("regs", 0444, qm->debug.qm_d, qm, &qm_regs_fops);
-
- debugfs_create_file("cmd", 0444, qm->debug.qm_d, qm, &qm_cmd_fops);
-
- debugfs_create_file("status", 0444, qm->debug.qm_d, qm,
- &qm_status_fops);
- for (i = 0; i < ARRAY_SIZE(qm_dfx_files); i++) {
- data = (atomic64_t *)((uintptr_t)dfx + qm_dfx_files[i].offset);
- debugfs_create_file(qm_dfx_files[i].name,
- 0644,
- qm_d,
- data,
- &qm_atomic64_ops);
- }
-}
-EXPORT_SYMBOL_GPL(hisi_qm_debug_init);
-
-/**
- * hisi_qm_debug_regs_clear() - clear qm debug related registers.
- * @qm: The qm for which we want to clear its debug registers.
- */
-void hisi_qm_debug_regs_clear(struct hisi_qm *qm)
-{
- struct qm_dfx_registers *regs;
- int i;
-
- /* clear current_qm */
- writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF);
- writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF);
-
- /* clear current_q */
- writel(0x0, qm->io_base + QM_DFX_SQE_CNT_VF_SQN);
- writel(0x0, qm->io_base + QM_DFX_CQE_CNT_VF_CQN);
-
- /*
- * these registers are reading and clearing, so clear them after
- * reading them.
- */
- writel(0x1, qm->io_base + QM_DFX_CNT_CLR_CE);
-
- regs = qm_dfx_regs;
- for (i = 0; i < CNT_CYC_REGS_NUM; i++) {
- readl(qm->io_base + regs->reg_offset);
- regs++;
- }
-
- writel(0x0, qm->io_base + QM_DFX_CNT_CLR_CE);
-}
-EXPORT_SYMBOL_GPL(hisi_qm_debug_regs_clear);
-
static void qm_hw_error_init(struct hisi_qm *qm)
{
struct hisi_qm_err_info *err_info = &qm->err_info;
@@ -3362,6 +3919,360 @@ static int qm_clear_vft_config(struct hisi_qm *qm)
return 0;
}
+static int qm_func_shaper_enable(struct hisi_qm *qm, u32 fun_index, u32 qos)
+{
+ struct device *dev = &qm->pdev->dev;
+ u32 ir = qos * QM_QOS_RATE;
+ int ret, total_vfs, i;
+
+ total_vfs = pci_sriov_get_totalvfs(qm->pdev);
+ if (fun_index > total_vfs)
+ return -EINVAL;
+
+ qm->factor[fun_index].func_qos = qos;
+
+ ret = qm_get_shaper_para(ir, &qm->factor[fun_index]);
+ if (ret) {
+ dev_err(dev, "failed to calculate shaper parameter!\n");
+ return -EINVAL;
+ }
+
+ for (i = ALG_TYPE_0; i <= ALG_TYPE_1; i++) {
+ /* The base number of queue reuse for different alg type */
+ ret = qm_set_vft_common(qm, SHAPER_VFT, fun_index, i, 1);
+ if (ret) {
+ dev_err(dev, "type: %d, failed to set shaper vft!\n", i);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static u32 qm_get_shaper_vft_qos(struct hisi_qm *qm, u32 fun_index)
+{
+ u64 cir_u = 0, cir_b = 0, cir_s = 0;
+ u64 shaper_vft, ir_calc, ir;
+ unsigned int val;
+ u32 error_rate;
+ int ret;
+
+ ret = readl_relaxed_poll_timeout(qm->io_base + QM_VFT_CFG_RDY, val,
+ val & BIT(0), POLL_PERIOD,
+ POLL_TIMEOUT);
+ if (ret)
+ return 0;
+
+ writel(0x1, qm->io_base + QM_VFT_CFG_OP_WR);
+ writel(SHAPER_VFT, qm->io_base + QM_VFT_CFG_TYPE);
+ writel(fun_index, qm->io_base + QM_VFT_CFG);
+
+ writel(0x0, qm->io_base + QM_VFT_CFG_RDY);
+ writel(0x1, qm->io_base + QM_VFT_CFG_OP_ENABLE);
+
+ ret = readl_relaxed_poll_timeout(qm->io_base + QM_VFT_CFG_RDY, val,
+ val & BIT(0), POLL_PERIOD,
+ POLL_TIMEOUT);
+ if (ret)
+ return 0;
+
+ shaper_vft = readl(qm->io_base + QM_VFT_CFG_DATA_L) |
+ ((u64)readl(qm->io_base + QM_VFT_CFG_DATA_H) << 32);
+
+ cir_b = shaper_vft & QM_SHAPER_CIR_B_MASK;
+ cir_u = shaper_vft & QM_SHAPER_CIR_U_MASK;
+ cir_u = cir_u >> QM_SHAPER_FACTOR_CIR_U_SHIFT;
+
+ cir_s = shaper_vft & QM_SHAPER_CIR_S_MASK;
+ cir_s = cir_s >> QM_SHAPER_FACTOR_CIR_S_SHIFT;
+
+ ir_calc = acc_shaper_para_calc(cir_b, cir_u, cir_s);
+
+ ir = qm->factor[fun_index].func_qos * QM_QOS_RATE;
+
+ error_rate = QM_QOS_EXPAND_RATE * (u32)abs(ir_calc - ir) / ir;
+ if (error_rate > QM_QOS_MIN_ERROR_RATE) {
+ pci_err(qm->pdev, "error_rate: %u, get function qos is error!\n", error_rate);
+ return 0;
+ }
+
+ return ir;
+}
+
+static void qm_vf_get_qos(struct hisi_qm *qm, u32 fun_num)
+{
+ struct device *dev = &qm->pdev->dev;
+ u64 mb_cmd;
+ u32 qos;
+ int ret;
+
+ qos = qm_get_shaper_vft_qos(qm, fun_num);
+ if (!qos) {
+ dev_err(dev, "function(%u) failed to get qos by PF!\n", fun_num);
+ return;
+ }
+
+ mb_cmd = QM_PF_SET_QOS | (u64)qos << QM_MB_CMD_DATA_SHIFT;
+ ret = qm_ping_single_vf(qm, mb_cmd, fun_num);
+ if (ret)
+ dev_err(dev, "failed to send cmd to VF(%u)!\n", fun_num);
+}
+
+static int qm_vf_read_qos(struct hisi_qm *qm)
+{
+ int cnt = 0;
+ int ret;
+
+ /* reset mailbox qos val */
+ qm->mb_qos = 0;
+
+ /* vf ping pf to get function qos */
+ if (qm->ops->ping_pf) {
+ ret = qm->ops->ping_pf(qm, QM_VF_GET_QOS);
+ if (ret) {
+ pci_err(qm->pdev, "failed to send cmd to PF to get qos!\n");
+ return ret;
+ }
+ }
+
+ while (true) {
+ msleep(QM_WAIT_DST_ACK);
+ if (qm->mb_qos)
+ break;
+
+ if (++cnt > QM_MAX_VF_WAIT_COUNT) {
+ pci_err(qm->pdev, "PF ping VF timeout!\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return ret;
+}
+
+static ssize_t qm_algqos_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct hisi_qm *qm = filp->private_data;
+ char tbuf[QM_DBG_READ_LEN];
+ u32 qos_val, ir;
+ int ret;
+
+ /* Mailbox and reset cannot be operated at the same time */
+ if (test_and_set_bit(QM_RESETTING, &qm->misc_ctl)) {
+ pci_err(qm->pdev, "dev resetting, read alg qos failed!\n");
+ return -EAGAIN;
+ }
+
+ if (qm->fun_type == QM_HW_PF) {
+ ir = qm_get_shaper_vft_qos(qm, 0);
+ } else {
+ ret = qm_vf_read_qos(qm);
+ if (ret)
+ goto err_get_status;
+ ir = qm->mb_qos;
+ }
+
+ qos_val = ir / QM_QOS_RATE;
+ ret = scnprintf(tbuf, QM_DBG_READ_LEN, "%u\n", qos_val);
+
+ ret = simple_read_from_buffer(buf, count, pos, tbuf, ret);
+
+err_get_status:
+ clear_bit(QM_RESETTING, &qm->misc_ctl);
+ return ret;
+}
+
+static ssize_t qm_qos_value_init(const char *buf, unsigned long *val)
+{
+ int buflen = strlen(buf);
+ int ret, i;
+
+ for (i = 0; i < buflen; i++) {
+ if (!isdigit(buf[i]))
+ return -EINVAL;
+ }
+
+ ret = sscanf(buf, "%ld", val);
+ if (ret != QM_QOS_VAL_NUM)
+ return -EINVAL;
+
+ return 0;
+}
+
+static ssize_t qm_algqos_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct hisi_qm *qm = filp->private_data;
+ char tbuf[QM_DBG_READ_LEN];
+ int tmp1, bus, device, function;
+ char tbuf_bdf[QM_DBG_READ_LEN] = {0};
+ char val_buf[QM_QOS_VAL_MAX_LEN] = {0};
+ unsigned int fun_index;
+ unsigned long val = 0;
+ int len, ret;
+
+ if (qm->fun_type == QM_HW_VF)
+ return -EINVAL;
+
+ /* Mailbox and reset cannot be operated at the same time */
+ if (test_and_set_bit(QM_RESETTING, &qm->misc_ctl)) {
+ pci_err(qm->pdev, "dev resetting, write alg qos failed!\n");
+ return -EAGAIN;
+ }
+
+ if (*pos != 0) {
+ ret = 0;
+ goto err_get_status;
+ }
+
+ if (count >= QM_DBG_READ_LEN) {
+ ret = -ENOSPC;
+ goto err_get_status;
+ }
+
+ len = simple_write_to_buffer(tbuf, QM_DBG_READ_LEN - 1, pos, buf, count);
+ if (len < 0) {
+ ret = len;
+ goto err_get_status;
+ }
+
+ tbuf[len] = '\0';
+ ret = sscanf(tbuf, "%s %s", tbuf_bdf, val_buf);
+ if (ret != QM_QOS_PARAM_NUM) {
+ ret = -EINVAL;
+ goto err_get_status;
+ }
+
+ ret = qm_qos_value_init(val_buf, &val);
+ if (val == 0 || val > QM_QOS_MAX_VAL || ret) {
+ pci_err(qm->pdev, "input qos value is error, please set 1~1000!\n");
+ ret = -EINVAL;
+ goto err_get_status;
+ }
+
+ ret = sscanf(tbuf_bdf, "%d:%x:%d.%d", &tmp1, &bus, &device, &function);
+ if (ret != QM_QOS_BDF_PARAM_NUM) {
+ pci_err(qm->pdev, "input pci bdf value is error!\n");
+ ret = -EINVAL;
+ goto err_get_status;
+ }
+
+ fun_index = device * 8 + function;
+
+ ret = qm_func_shaper_enable(qm, fun_index, val);
+ if (ret) {
+ pci_err(qm->pdev, "failed to enable function shaper!\n");
+ ret = -EINVAL;
+ goto err_get_status;
+ }
+
+ ret = count;
+
+err_get_status:
+ clear_bit(QM_RESETTING, &qm->misc_ctl);
+ return ret;
+}
+
+static const struct file_operations qm_algqos_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = qm_algqos_read,
+ .write = qm_algqos_write,
+};
+
+/**
+ * hisi_qm_set_algqos_init() - Initialize function qos debugfs files.
+ * @qm: The qm for which we want to add debugfs files.
+ *
+ * Create function qos debugfs files.
+ */
+static void hisi_qm_set_algqos_init(struct hisi_qm *qm)
+{
+ if (qm->fun_type == QM_HW_PF)
+ debugfs_create_file("alg_qos", 0644, qm->debug.debug_root,
+ qm, &qm_algqos_fops);
+ else
+ debugfs_create_file("alg_qos", 0444, qm->debug.debug_root,
+ qm, &qm_algqos_fops);
+}
+
+/**
+ * hisi_qm_debug_init() - Initialize qm related debugfs files.
+ * @qm: The qm for which we want to add debugfs files.
+ *
+ * Create qm related debugfs files.
+ */
+void hisi_qm_debug_init(struct hisi_qm *qm)
+{
+ struct qm_dfx *dfx = &qm->debug.dfx;
+ struct dentry *qm_d;
+ void *data;
+ int i;
+
+ qm_d = debugfs_create_dir("qm", qm->debug.debug_root);
+ qm->debug.qm_d = qm_d;
+
+ /* only show this in PF */
+ if (qm->fun_type == QM_HW_PF) {
+ qm_create_debugfs_file(qm, qm->debug.debug_root, CURRENT_QM);
+ for (i = CURRENT_Q; i < DEBUG_FILE_NUM; i++)
+ qm_create_debugfs_file(qm, qm->debug.qm_d, i);
+ }
+
+ debugfs_create_file("regs", 0444, qm->debug.qm_d, qm, &qm_regs_fops);
+
+ debugfs_create_file("cmd", 0600, qm->debug.qm_d, qm, &qm_cmd_fops);
+
+ debugfs_create_file("status", 0444, qm->debug.qm_d, qm,
+ &qm_status_fops);
+ for (i = 0; i < ARRAY_SIZE(qm_dfx_files); i++) {
+ data = (atomic64_t *)((uintptr_t)dfx + qm_dfx_files[i].offset);
+ debugfs_create_file(qm_dfx_files[i].name,
+ 0644,
+ qm_d,
+ data,
+ &qm_atomic64_ops);
+ }
+
+ if (qm->ver >= QM_HW_V3)
+ hisi_qm_set_algqos_init(qm);
+}
+EXPORT_SYMBOL_GPL(hisi_qm_debug_init);
+
+/**
+ * hisi_qm_debug_regs_clear() - clear qm debug related registers.
+ * @qm: The qm for which we want to clear its debug registers.
+ */
+void hisi_qm_debug_regs_clear(struct hisi_qm *qm)
+{
+ struct qm_dfx_registers *regs;
+ int i;
+
+ /* clear current_qm */
+ writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF);
+ writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF);
+
+ /* clear current_q */
+ writel(0x0, qm->io_base + QM_DFX_SQE_CNT_VF_SQN);
+ writel(0x0, qm->io_base + QM_DFX_CQE_CNT_VF_CQN);
+
+ /*
+ * these registers are reading and clearing, so clear them after
+ * reading them.
+ */
+ writel(0x1, qm->io_base + QM_DFX_CNT_CLR_CE);
+
+ regs = qm_dfx_regs;
+ for (i = 0; i < CNT_CYC_REGS_NUM; i++) {
+ readl(qm->io_base + regs->reg_offset);
+ regs++;
+ }
+
+ /* clear clear_enable */
+ writel(0x0, qm->io_base + QM_DFX_CNT_CLR_CE);
+}
+EXPORT_SYMBOL_GPL(hisi_qm_debug_regs_clear);
+
/**
* hisi_qm_sriov_enable() - enable virtual functions
* @pdev: the PCIe device
@@ -3416,6 +4327,7 @@ EXPORT_SYMBOL_GPL(hisi_qm_sriov_enable);
int hisi_qm_sriov_disable(struct pci_dev *pdev, bool is_frozen)
{
struct hisi_qm *qm = pci_get_drvdata(pdev);
+ int total_vfs = pci_sriov_get_totalvfs(qm->pdev);
if (pci_vfs_assigned(pdev)) {
pci_err(pdev, "Failed to disable VFs as VFs are assigned!\n");
@@ -3429,6 +4341,9 @@ int hisi_qm_sriov_disable(struct pci_dev *pdev, bool is_frozen)
}
pci_disable_sriov(pdev);
+ /* clear vf function shaper configure array */
+ memset(qm->factor + 1, 0, sizeof(struct qm_shaper_factor) * total_vfs);
+
return qm_clear_vft_config(qm);
}
EXPORT_SYMBOL_GPL(hisi_qm_sriov_disable);
@@ -3527,17 +4442,15 @@ pci_ers_result_t hisi_qm_dev_err_detected(struct pci_dev *pdev,
}
EXPORT_SYMBOL_GPL(hisi_qm_dev_err_detected);
-static u32 qm_get_hw_error_status(struct hisi_qm *qm)
-{
- return readl(qm->io_base + QM_ABNORMAL_INT_STATUS);
-}
-
static int qm_check_req_recv(struct hisi_qm *qm)
{
struct pci_dev *pdev = qm->pdev;
int ret;
u32 val;
+ if (qm->ver >= QM_HW_V3)
+ return 0;
+
writel(ACC_VENDOR_ID_VALUE, qm->io_base + QM_PEH_VENDOR_ID);
ret = readl_relaxed_poll_timeout(qm->io_base + QM_PEH_VENDOR_ID, val,
(val == ACC_VENDOR_ID_VALUE),
@@ -3608,28 +4521,6 @@ static int qm_set_vf_mse(struct hisi_qm *qm, bool set)
return -ETIMEDOUT;
}
-static int qm_set_msi(struct hisi_qm *qm, bool set)
-{
- struct pci_dev *pdev = qm->pdev;
-
- if (set) {
- pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_MASK_64,
- 0);
- } else {
- pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_MASK_64,
- ACC_PEH_MSI_DISABLE);
- if (qm->err_status.is_qm_ecc_mbit ||
- qm->err_status.is_dev_ecc_mbit)
- return 0;
-
- mdelay(1);
- if (readl(qm->io_base + QM_PEH_DFX_INFO0))
- return -EFAULT;
- }
-
- return 0;
-}
-
static int qm_vf_reset_prepare(struct hisi_qm *qm,
enum qm_stop_reason stop_reason)
{
@@ -3660,14 +4551,35 @@ stop_fail:
return ret;
}
-static int qm_reset_prepare_ready(struct hisi_qm *qm)
+static int qm_try_stop_vfs(struct hisi_qm *qm, u64 cmd,
+ enum qm_stop_reason stop_reason)
{
struct pci_dev *pdev = qm->pdev;
- struct hisi_qm *pf_qm = pci_get_drvdata(pci_physfn(pdev));
+ int ret;
+
+ if (!qm->vfs_num)
+ return 0;
+
+ /* Kunpeng930 supports to notify VFs to stop before PF reset */
+ if (qm->ops->ping_all_vfs) {
+ ret = qm->ops->ping_all_vfs(qm, cmd);
+ if (ret)
+ pci_err(pdev, "failed to send cmd to all VFs before PF reset!\n");
+ } else {
+ ret = qm_vf_reset_prepare(qm, stop_reason);
+ if (ret)
+ pci_err(pdev, "failed to prepare reset, ret = %d.\n", ret);
+ }
+
+ return ret;
+}
+
+static int qm_wait_reset_finish(struct hisi_qm *qm)
+{
int delay = 0;
/* All reset requests need to be queued for processing */
- while (test_and_set_bit(QM_RESETTING, &pf_qm->misc_ctl)) {
+ while (test_and_set_bit(QM_RESETTING, &qm->misc_ctl)) {
msleep(++delay);
if (delay > QM_RESET_WAIT_TIMEOUT)
return -EBUSY;
@@ -3676,6 +4588,32 @@ static int qm_reset_prepare_ready(struct hisi_qm *qm)
return 0;
}
+static int qm_reset_prepare_ready(struct hisi_qm *qm)
+{
+ struct pci_dev *pdev = qm->pdev;
+ struct hisi_qm *pf_qm = pci_get_drvdata(pci_physfn(pdev));
+
+ /*
+ * PF and VF on host doesnot support resetting at the
+ * same time on Kunpeng920.
+ */
+ if (qm->ver < QM_HW_V3)
+ return qm_wait_reset_finish(pf_qm);
+
+ return qm_wait_reset_finish(qm);
+}
+
+static void qm_reset_bit_clear(struct hisi_qm *qm)
+{
+ struct pci_dev *pdev = qm->pdev;
+ struct hisi_qm *pf_qm = pci_get_drvdata(pci_physfn(pdev));
+
+ if (qm->ver < QM_HW_V3)
+ clear_bit(QM_RESETTING, &pf_qm->misc_ctl);
+
+ clear_bit(QM_RESETTING, &qm->misc_ctl);
+}
+
static int qm_controller_reset_prepare(struct hisi_qm *qm)
{
struct pci_dev *pdev = qm->pdev;
@@ -3687,22 +4625,25 @@ static int qm_controller_reset_prepare(struct hisi_qm *qm)
return ret;
}
- if (qm->vfs_num) {
- ret = qm_vf_reset_prepare(qm, QM_SOFT_RESET);
- if (ret) {
- pci_err(pdev, "Fails to stop VFs!\n");
- clear_bit(QM_RESETTING, &qm->misc_ctl);
- return ret;
- }
- }
+ /* PF obtains the information of VF by querying the register. */
+ qm_cmd_uninit(qm);
+
+ /* Whether VFs stop successfully, soft reset will continue. */
+ ret = qm_try_stop_vfs(qm, QM_PF_SRST_PREPARE, QM_SOFT_RESET);
+ if (ret)
+ pci_err(pdev, "failed to stop vfs by pf in soft reset.\n");
ret = hisi_qm_stop(qm, QM_SOFT_RESET);
if (ret) {
pci_err(pdev, "Fails to stop QM!\n");
- clear_bit(QM_RESETTING, &qm->misc_ctl);
+ qm_reset_bit_clear(qm);
return ret;
}
+ ret = qm_wait_vf_prepare_finish(qm);
+ if (ret)
+ pci_err(pdev, "failed to stop by vfs in soft reset!\n");
+
clear_bit(QM_RST_SCHED, &qm->misc_ctl);
return 0;
@@ -3712,6 +4653,10 @@ static void qm_dev_ecc_mbit_handle(struct hisi_qm *qm)
{
u32 nfe_enb = 0;
+ /* Kunpeng930 hardware automatically close master ooo when NFE occurs */
+ if (qm->ver >= QM_HW_V3)
+ return;
+
if (!qm->err_status.is_dev_ecc_mbit &&
qm->err_status.is_qm_ecc_mbit &&
qm->err_ini->close_axi_master_ooo) {
@@ -3748,7 +4693,7 @@ static int qm_soft_reset(struct hisi_qm *qm)
}
}
- ret = qm_set_msi(qm, false);
+ ret = qm->ops->set_msi(qm, false);
if (ret) {
pci_err(pdev, "Fails to disable PEH MSI bit.\n");
return ret;
@@ -3770,6 +4715,9 @@ static int qm_soft_reset(struct hisi_qm *qm)
return ret;
}
+ if (qm->err_ini->close_sva_prefetch)
+ qm->err_ini->close_sva_prefetch(qm);
+
ret = qm_set_pf_mse(qm, false);
if (ret) {
pci_err(pdev, "Fails to disable pf MSE bit.\n");
@@ -3830,9 +4778,32 @@ restart_fail:
return ret;
}
-static u32 qm_get_dev_err_status(struct hisi_qm *qm)
+static int qm_try_start_vfs(struct hisi_qm *qm, enum qm_mb_cmd cmd)
{
- return qm->err_ini->get_dev_hw_err_status(qm);
+ struct pci_dev *pdev = qm->pdev;
+ int ret;
+
+ if (!qm->vfs_num)
+ return 0;
+
+ ret = qm_vf_q_assign(qm, qm->vfs_num);
+ if (ret) {
+ pci_err(pdev, "failed to assign VFs, ret = %d.\n", ret);
+ return ret;
+ }
+
+ /* Kunpeng930 supports to notify VFs to start after PF reset. */
+ if (qm->ops->ping_all_vfs) {
+ ret = qm->ops->ping_all_vfs(qm, cmd);
+ if (ret)
+ pci_warn(pdev, "failed to send cmd to all VFs after PF reset!\n");
+ } else {
+ ret = qm_vf_reset_done(qm);
+ if (ret)
+ pci_warn(pdev, "failed to start vfs, ret = %d.\n", ret);
+ }
+
+ return ret;
}
static int qm_dev_hw_init(struct hisi_qm *qm)
@@ -3844,6 +4815,12 @@ static void qm_restart_prepare(struct hisi_qm *qm)
{
u32 value;
+ if (qm->err_ini->open_sva_prefetch)
+ qm->err_ini->open_sva_prefetch(qm);
+
+ if (qm->ver >= QM_HW_V3)
+ return;
+
if (!qm->err_status.is_qm_ecc_mbit &&
!qm->err_status.is_dev_ecc_mbit)
return;
@@ -3863,15 +4840,15 @@ static void qm_restart_prepare(struct hisi_qm *qm)
/* clear AM Reorder Buffer ecc mbit source */
writel(ACC_ROB_ECC_ERR_MULTPL, qm->io_base + ACC_AM_ROB_ECC_INT_STS);
-
- if (qm->err_ini->open_axi_master_ooo)
- qm->err_ini->open_axi_master_ooo(qm);
}
static void qm_restart_done(struct hisi_qm *qm)
{
u32 value;
+ if (qm->ver >= QM_HW_V3)
+ goto clear_flags;
+
if (!qm->err_status.is_qm_ecc_mbit &&
!qm->err_status.is_dev_ecc_mbit)
return;
@@ -3881,6 +4858,7 @@ static void qm_restart_done(struct hisi_qm *qm)
value |= qm->err_info.msi_wr_port;
writel(value, qm->io_base + ACC_AM_CFG_PORT_WR_EN);
+clear_flags:
qm->err_status.is_qm_ecc_mbit = false;
qm->err_status.is_dev_ecc_mbit = false;
}
@@ -3890,7 +4868,7 @@ static int qm_controller_reset_done(struct hisi_qm *qm)
struct pci_dev *pdev = qm->pdev;
int ret;
- ret = qm_set_msi(qm, true);
+ ret = qm->ops->set_msi(qm, true);
if (ret) {
pci_err(pdev, "Fails to enable PEH MSI bit!\n");
return ret;
@@ -3917,6 +4895,9 @@ static int qm_controller_reset_done(struct hisi_qm *qm)
}
qm_restart_prepare(qm);
+ hisi_qm_dev_err_init(qm);
+ if (qm->err_ini->open_axi_master_ooo)
+ qm->err_ini->open_axi_master_ooo(qm);
ret = qm_restart(qm);
if (ret) {
@@ -3924,24 +4905,18 @@ static int qm_controller_reset_done(struct hisi_qm *qm)
return ret;
}
- if (qm->vfs_num) {
- ret = qm_vf_q_assign(qm, qm->vfs_num);
- if (ret) {
- pci_err(pdev, "Failed to assign queue!\n");
- return ret;
- }
- }
+ ret = qm_try_start_vfs(qm, QM_PF_RESET_DONE);
+ if (ret)
+ pci_err(pdev, "failed to start vfs by pf in soft reset.\n");
- ret = qm_vf_reset_done(qm);
- if (ret) {
- pci_err(pdev, "Failed to start VFs!\n");
- return -EPERM;
- }
+ ret = qm_wait_vf_prepare_finish(qm);
+ if (ret)
+ pci_err(pdev, "failed to start by vfs in soft reset!\n");
- hisi_qm_dev_err_init(qm);
+ qm_cmd_init(qm);
qm_restart_done(qm);
- clear_bit(QM_RESETTING, &qm->misc_ctl);
+ qm_reset_bit_clear(qm);
return 0;
}
@@ -3962,13 +4937,13 @@ static int qm_controller_reset(struct hisi_qm *qm)
ret = qm_soft_reset(qm);
if (ret) {
pci_err(pdev, "Controller reset failed (%d)\n", ret);
- clear_bit(QM_RESETTING, &qm->misc_ctl);
+ qm_reset_bit_clear(qm);
return ret;
}
ret = qm_controller_reset_done(qm);
if (ret) {
- clear_bit(QM_RESETTING, &qm->misc_ctl);
+ qm_reset_bit_clear(qm);
return ret;
}
@@ -4005,21 +4980,6 @@ pci_ers_result_t hisi_qm_dev_slot_reset(struct pci_dev *pdev)
}
EXPORT_SYMBOL_GPL(hisi_qm_dev_slot_reset);
-/* check the interrupt is ecc-mbit error or not */
-static int qm_check_dev_error(struct hisi_qm *qm)
-{
- int ret;
-
- if (qm->fun_type == QM_HW_VF)
- return 0;
-
- ret = qm_get_hw_error_status(qm) & QM_ECC_MBIT;
- if (ret)
- return ret;
-
- return (qm_get_dev_err_status(qm) & qm->err_info.ecc_2bits_mask);
-}
-
void hisi_qm_reset_prepare(struct pci_dev *pdev)
{
struct hisi_qm *pf_qm = pci_get_drvdata(pci_physfn(pdev));
@@ -4045,14 +5005,13 @@ void hisi_qm_reset_prepare(struct pci_dev *pdev)
return;
}
- if (qm->vfs_num) {
- ret = qm_vf_reset_prepare(qm, QM_FLR);
- if (ret) {
- pci_err(pdev, "Failed to prepare reset, ret = %d.\n",
- ret);
- return;
- }
- }
+ /* PF obtains the information of VF by querying the register. */
+ if (qm->fun_type == QM_HW_PF)
+ qm_cmd_uninit(qm);
+
+ ret = qm_try_stop_vfs(qm, QM_PF_FLR_PREPARE, QM_FLR);
+ if (ret)
+ pci_err(pdev, "failed to stop vfs by pf in FLR.\n");
ret = hisi_qm_stop(qm, QM_FLR);
if (ret) {
@@ -4060,6 +5019,10 @@ void hisi_qm_reset_prepare(struct pci_dev *pdev)
return;
}
+ ret = qm_wait_vf_prepare_finish(qm);
+ if (ret)
+ pci_err(pdev, "failed to stop by vfs in FLR!\n");
+
pci_info(pdev, "FLR resetting...\n");
}
EXPORT_SYMBOL_GPL(hisi_qm_reset_prepare);
@@ -4085,42 +5048,38 @@ void hisi_qm_reset_done(struct pci_dev *pdev)
struct hisi_qm *qm = pci_get_drvdata(pdev);
int ret;
- hisi_qm_dev_err_init(pf_qm);
-
- ret = qm_restart(qm);
- if (ret) {
- pci_err(pdev, "Failed to start QM, ret = %d.\n", ret);
- goto flr_done;
- }
-
if (qm->fun_type == QM_HW_PF) {
ret = qm_dev_hw_init(qm);
if (ret) {
pci_err(pdev, "Failed to init PF, ret = %d.\n", ret);
goto flr_done;
}
+ }
- if (!qm->vfs_num)
- goto flr_done;
-
- ret = qm_vf_q_assign(qm, qm->vfs_num);
- if (ret) {
- pci_err(pdev, "Failed to assign VFs, ret = %d.\n", ret);
- goto flr_done;
- }
+ hisi_qm_dev_err_init(pf_qm);
- ret = qm_vf_reset_done(qm);
- if (ret) {
- pci_err(pdev, "Failed to start VFs, ret = %d.\n", ret);
- goto flr_done;
- }
+ ret = qm_restart(qm);
+ if (ret) {
+ pci_err(pdev, "Failed to start QM, ret = %d.\n", ret);
+ goto flr_done;
}
+ ret = qm_try_start_vfs(qm, QM_PF_RESET_DONE);
+ if (ret)
+ pci_err(pdev, "failed to start vfs by pf in FLR.\n");
+
+ ret = qm_wait_vf_prepare_finish(qm);
+ if (ret)
+ pci_err(pdev, "failed to start by vfs in FLR!\n");
+
flr_done:
+ if (qm->fun_type == QM_HW_PF)
+ qm_cmd_init(qm);
+
if (qm_flr_reset_complete(pdev))
pci_info(pdev, "FLR reset complete\n");
- clear_bit(QM_RESETTING, &qm->misc_ctl);
+ qm_reset_bit_clear(qm);
}
EXPORT_SYMBOL_GPL(hisi_qm_reset_done);
@@ -4149,7 +5108,7 @@ static int qm_irq_register(struct hisi_qm *qm)
if (ret)
return ret;
- if (qm->ver != QM_HW_V1) {
+ if (qm->ver > QM_HW_V1) {
ret = request_irq(pci_irq_vector(pdev, QM_AEQ_EVENT_IRQ_VECTOR),
qm_aeq_irq, 0, qm->dev_name, qm);
if (ret)
@@ -4164,8 +5123,18 @@ static int qm_irq_register(struct hisi_qm *qm)
}
}
+ if (qm->ver > QM_HW_V2) {
+ ret = request_irq(pci_irq_vector(pdev, QM_CMD_EVENT_IRQ_VECTOR),
+ qm_mb_cmd_irq, 0, qm->dev_name, qm);
+ if (ret)
+ goto err_mb_cmd_irq;
+ }
+
return 0;
+err_mb_cmd_irq:
+ if (qm->fun_type == QM_HW_PF)
+ free_irq(pci_irq_vector(pdev, QM_ABNORMAL_EVENT_IRQ_VECTOR), qm);
err_abonormal_irq:
free_irq(pci_irq_vector(pdev, QM_AEQ_EVENT_IRQ_VECTOR), qm);
err_aeq_irq:
@@ -4202,6 +5171,183 @@ static void hisi_qm_controller_reset(struct work_struct *rst_work)
}
+static void qm_pf_reset_vf_prepare(struct hisi_qm *qm,
+ enum qm_stop_reason stop_reason)
+{
+ enum qm_mb_cmd cmd = QM_VF_PREPARE_DONE;
+ struct pci_dev *pdev = qm->pdev;
+ int ret;
+
+ ret = qm_reset_prepare_ready(qm);
+ if (ret) {
+ dev_err(&pdev->dev, "reset prepare not ready!\n");
+ atomic_set(&qm->status.flags, QM_STOP);
+ cmd = QM_VF_PREPARE_FAIL;
+ goto err_prepare;
+ }
+
+ ret = hisi_qm_stop(qm, stop_reason);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to stop QM, ret = %d.\n", ret);
+ atomic_set(&qm->status.flags, QM_STOP);
+ cmd = QM_VF_PREPARE_FAIL;
+ goto err_prepare;
+ }
+
+err_prepare:
+ pci_save_state(pdev);
+ ret = qm->ops->ping_pf(qm, cmd);
+ if (ret)
+ dev_warn(&pdev->dev, "PF responds timeout in reset prepare!\n");
+}
+
+static void qm_pf_reset_vf_done(struct hisi_qm *qm)
+{
+ enum qm_mb_cmd cmd = QM_VF_START_DONE;
+ struct pci_dev *pdev = qm->pdev;
+ int ret;
+
+ pci_restore_state(pdev);
+ ret = hisi_qm_start(qm);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to start QM, ret = %d.\n", ret);
+ cmd = QM_VF_START_FAIL;
+ }
+
+ ret = qm->ops->ping_pf(qm, cmd);
+ if (ret)
+ dev_warn(&pdev->dev, "PF responds timeout in reset done!\n");
+
+ qm_reset_bit_clear(qm);
+}
+
+static int qm_wait_pf_reset_finish(struct hisi_qm *qm)
+{
+ struct device *dev = &qm->pdev->dev;
+ u32 val, cmd;
+ u64 msg;
+ int ret;
+
+ /* Wait for reset to finish */
+ ret = readl_relaxed_poll_timeout(qm->io_base + QM_IFC_INT_SOURCE_V, val,
+ val == BIT(0), QM_VF_RESET_WAIT_US,
+ QM_VF_RESET_WAIT_TIMEOUT_US);
+ /* hardware completion status should be available by this time */
+ if (ret) {
+ dev_err(dev, "couldn't get reset done status from PF, timeout!\n");
+ return -ETIMEDOUT;
+ }
+
+ /*
+ * Whether message is got successfully,
+ * VF needs to ack PF by clearing the interrupt.
+ */
+ ret = qm_get_mb_cmd(qm, &msg, 0);
+ qm_clear_cmd_interrupt(qm, 0);
+ if (ret) {
+ dev_err(dev, "failed to get msg from PF in reset done!\n");
+ return ret;
+ }
+
+ cmd = msg & QM_MB_CMD_DATA_MASK;
+ if (cmd != QM_PF_RESET_DONE) {
+ dev_err(dev, "the cmd(%u) is not reset done!\n", cmd);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void qm_pf_reset_vf_process(struct hisi_qm *qm,
+ enum qm_stop_reason stop_reason)
+{
+ struct device *dev = &qm->pdev->dev;
+ int ret;
+
+ dev_info(dev, "device reset start...\n");
+
+ /* The message is obtained by querying the register during resetting */
+ qm_cmd_uninit(qm);
+ qm_pf_reset_vf_prepare(qm, stop_reason);
+
+ ret = qm_wait_pf_reset_finish(qm);
+ if (ret)
+ goto err_get_status;
+
+ qm_pf_reset_vf_done(qm);
+ qm_cmd_init(qm);
+
+ dev_info(dev, "device reset done.\n");
+
+ return;
+
+err_get_status:
+ qm_cmd_init(qm);
+ qm_reset_bit_clear(qm);
+}
+
+static void qm_handle_cmd_msg(struct hisi_qm *qm, u32 fun_num)
+{
+ struct device *dev = &qm->pdev->dev;
+ u64 msg;
+ u32 cmd;
+ int ret;
+
+ /*
+ * Get the msg from source by sending mailbox. Whether message is got
+ * successfully, destination needs to ack source by clearing the interrupt.
+ */
+ ret = qm_get_mb_cmd(qm, &msg, fun_num);
+ qm_clear_cmd_interrupt(qm, BIT(fun_num));
+ if (ret) {
+ dev_err(dev, "failed to get msg from source!\n");
+ return;
+ }
+
+ cmd = msg & QM_MB_CMD_DATA_MASK;
+ switch (cmd) {
+ case QM_PF_FLR_PREPARE:
+ qm_pf_reset_vf_process(qm, QM_FLR);
+ break;
+ case QM_PF_SRST_PREPARE:
+ qm_pf_reset_vf_process(qm, QM_SOFT_RESET);
+ break;
+ case QM_VF_GET_QOS:
+ qm_vf_get_qos(qm, fun_num);
+ break;
+ case QM_PF_SET_QOS:
+ qm->mb_qos = msg >> QM_MB_CMD_DATA_SHIFT;
+ break;
+ default:
+ dev_err(dev, "unsupported cmd %u sent by function(%u)!\n", cmd, fun_num);
+ break;
+ }
+}
+
+static void qm_cmd_process(struct work_struct *cmd_process)
+{
+ struct hisi_qm *qm = container_of(cmd_process,
+ struct hisi_qm, cmd_process);
+ u32 vfs_num = qm->vfs_num;
+ u64 val;
+ u32 i;
+
+ if (qm->fun_type == QM_HW_PF) {
+ val = readq(qm->io_base + QM_IFC_INT_SOURCE_P);
+ if (!val)
+ return;
+
+ for (i = 1; i <= vfs_num; i++) {
+ if (val & BIT(i))
+ qm_handle_cmd_msg(qm, i);
+ }
+
+ return;
+ }
+
+ qm_handle_cmd_msg(qm, 0);
+}
+
/**
* hisi_qm_alg_register() - Register alg to crypto and add qm to qm_list.
* @qm: The qm needs add.
@@ -4212,11 +5358,9 @@ static void hisi_qm_controller_reset(struct work_struct *rst_work)
*/
int hisi_qm_alg_register(struct hisi_qm *qm, struct hisi_qm_list *qm_list)
{
+ struct device *dev = &qm->pdev->dev;
int flag = 0;
int ret = 0;
- /* HW V2 not support both use uacce sva mode and hardware crypto algs */
- if (qm->ver <= QM_HW_V2 && qm->use_sva)
- return 0;
mutex_lock(&qm_list->lock);
if (list_empty(&qm_list->list))
@@ -4224,6 +5368,11 @@ int hisi_qm_alg_register(struct hisi_qm *qm, struct hisi_qm_list *qm_list)
list_add_tail(&qm->list, &qm_list->list);
mutex_unlock(&qm_list->lock);
+ if (qm->ver <= QM_HW_V2 && qm->use_sva) {
+ dev_info(dev, "HW V2 not both use uacce sva mode and hardware crypto algs.\n");
+ return 0;
+ }
+
if (flag) {
ret = qm_list->register_to_crypto(qm);
if (ret) {
@@ -4248,13 +5397,13 @@ EXPORT_SYMBOL_GPL(hisi_qm_alg_register);
*/
void hisi_qm_alg_unregister(struct hisi_qm *qm, struct hisi_qm_list *qm_list)
{
- if (qm->ver <= QM_HW_V2 && qm->use_sva)
- return;
-
mutex_lock(&qm_list->lock);
list_del(&qm->list);
mutex_unlock(&qm_list->lock);
+ if (qm->ver <= QM_HW_V2 && qm->use_sva)
+ return;
+
if (list_empty(&qm_list->list))
qm_list->unregister_from_crypto(qm);
}
@@ -4389,6 +5538,94 @@ err_disable_pcidev:
return ret;
}
+static void hisi_qm_init_work(struct hisi_qm *qm)
+{
+ INIT_WORK(&qm->work, qm_work_process);
+ if (qm->fun_type == QM_HW_PF)
+ INIT_WORK(&qm->rst_work, hisi_qm_controller_reset);
+
+ if (qm->ver > QM_HW_V2)
+ INIT_WORK(&qm->cmd_process, qm_cmd_process);
+}
+
+static int hisi_qp_alloc_memory(struct hisi_qm *qm)
+{
+ struct device *dev = &qm->pdev->dev;
+ size_t qp_dma_size;
+ int i, ret;
+
+ qm->qp_array = kcalloc(qm->qp_num, sizeof(struct hisi_qp), GFP_KERNEL);
+ if (!qm->qp_array)
+ return -ENOMEM;
+
+ /* one more page for device or qp statuses */
+ qp_dma_size = qm->sqe_size * QM_Q_DEPTH +
+ sizeof(struct qm_cqe) * QM_Q_DEPTH;
+ qp_dma_size = PAGE_ALIGN(qp_dma_size) + PAGE_SIZE;
+ for (i = 0; i < qm->qp_num; i++) {
+ ret = hisi_qp_memory_init(qm, qp_dma_size, i);
+ if (ret)
+ goto err_init_qp_mem;
+
+ dev_dbg(dev, "allocate qp dma buf size=%zx)\n", qp_dma_size);
+ }
+
+ return 0;
+err_init_qp_mem:
+ hisi_qp_memory_uninit(qm, i);
+
+ return ret;
+}
+
+static int hisi_qm_memory_init(struct hisi_qm *qm)
+{
+ struct device *dev = &qm->pdev->dev;
+ int ret, total_vfs;
+ size_t off = 0;
+
+ total_vfs = pci_sriov_get_totalvfs(qm->pdev);
+ qm->factor = kcalloc(total_vfs + 1, sizeof(struct qm_shaper_factor), GFP_KERNEL);
+ if (!qm->factor)
+ return -ENOMEM;
+
+#define QM_INIT_BUF(qm, type, num) do { \
+ (qm)->type = ((qm)->qdma.va + (off)); \
+ (qm)->type##_dma = (qm)->qdma.dma + (off); \
+ off += QMC_ALIGN(sizeof(struct qm_##type) * (num)); \
+} while (0)
+
+ idr_init(&qm->qp_idr);
+ qm->qdma.size = QMC_ALIGN(sizeof(struct qm_eqe) * QM_EQ_DEPTH) +
+ QMC_ALIGN(sizeof(struct qm_aeqe) * QM_Q_DEPTH) +
+ QMC_ALIGN(sizeof(struct qm_sqc) * qm->qp_num) +
+ QMC_ALIGN(sizeof(struct qm_cqc) * qm->qp_num);
+ qm->qdma.va = dma_alloc_coherent(dev, qm->qdma.size, &qm->qdma.dma,
+ GFP_ATOMIC);
+ dev_dbg(dev, "allocate qm dma buf size=%zx)\n", qm->qdma.size);
+ if (!qm->qdma.va) {
+ ret = -ENOMEM;
+ goto err_alloc_qdma;
+ }
+
+ QM_INIT_BUF(qm, eqe, QM_EQ_DEPTH);
+ QM_INIT_BUF(qm, aeqe, QM_Q_DEPTH);
+ QM_INIT_BUF(qm, sqc, qm->qp_num);
+ QM_INIT_BUF(qm, cqc, qm->qp_num);
+
+ ret = hisi_qp_alloc_memory(qm);
+ if (ret)
+ goto err_alloc_qp_array;
+
+ return 0;
+
+err_alloc_qp_array:
+ dma_free_coherent(dev, qm->qdma.size, qm->qdma.va, qm->qdma.dma);
+err_alloc_qdma:
+ kfree(qm->factor);
+
+ return ret;
+}
+
/**
* hisi_qm_init() - Initialize configures about qm.
* @qm: The qm needing init.
@@ -4426,10 +5663,8 @@ int hisi_qm_init(struct hisi_qm *qm)
if (ret)
goto err_alloc_uacce;
- INIT_WORK(&qm->work, qm_work_process);
- if (qm->fun_type == QM_HW_PF)
- INIT_WORK(&qm->rst_work, hisi_qm_controller_reset);
-
+ hisi_qm_init_work(qm);
+ qm_cmd_init(qm);
atomic_set(&qm->status.flags, QM_INIT);
return 0;
diff --git a/drivers/crypto/hisilicon/qm.h b/drivers/crypto/hisilicon/qm.h
index acefdf8b3a50..035eaf8c442d 100644
--- a/drivers/crypto/hisilicon/qm.h
+++ b/drivers/crypto/hisilicon/qm.h
@@ -76,6 +76,9 @@
#define QM_Q_DEPTH 1024
#define QM_MIN_QNUM 2
#define HISI_ACC_SGL_SGE_NR_MAX 255
+#define QM_SHAPER_CFG 0x100164
+#define QM_SHAPER_ENABLE BIT(30)
+#define QM_SHAPER_TYPE1_OFFSET 10
/* page number for queue file region */
#define QM_DOORBELL_PAGE_NR 1
@@ -148,6 +151,14 @@ struct qm_debug {
struct debugfs_file files[DEBUG_FILE_NUM];
};
+struct qm_shaper_factor {
+ u32 func_qos;
+ u64 cir_b;
+ u64 cir_u;
+ u64 cir_s;
+ u64 cbs_s;
+};
+
struct qm_dma {
void *va;
dma_addr_t dma;
@@ -188,6 +199,8 @@ struct hisi_qm_err_ini {
void (*clear_dev_hw_err_status)(struct hisi_qm *qm, u32 err_sts);
void (*open_axi_master_ooo)(struct hisi_qm *qm);
void (*close_axi_master_ooo)(struct hisi_qm *qm);
+ void (*open_sva_prefetch)(struct hisi_qm *qm);
+ void (*close_sva_prefetch)(struct hisi_qm *qm);
void (*log_dev_hw_err)(struct hisi_qm *qm, u32 err_sts);
void (*err_info_init)(struct hisi_qm *qm);
};
@@ -248,6 +261,7 @@ struct hisi_qm {
struct workqueue_struct *wq;
struct work_struct work;
struct work_struct rst_work;
+ struct work_struct cmd_process;
const char *algs;
bool use_sva;
@@ -259,6 +273,9 @@ struct hisi_qm {
resource_size_t db_phys_base;
struct uacce_device *uacce;
int mode;
+ struct qm_shaper_factor *factor;
+ u32 mb_qos;
+ u32 type_rate;
};
struct hisi_qp_status {
diff --git a/drivers/crypto/hisilicon/sec2/sec.h b/drivers/crypto/hisilicon/sec2/sec.h
index dfdce2f21e65..018415b9840a 100644
--- a/drivers/crypto/hisilicon/sec2/sec.h
+++ b/drivers/crypto/hisilicon/sec2/sec.h
@@ -13,14 +13,14 @@ struct sec_alg_res {
dma_addr_t pbuf_dma;
u8 *c_ivin;
dma_addr_t c_ivin_dma;
+ u8 *a_ivin;
+ dma_addr_t a_ivin_dma;
u8 *out_mac;
dma_addr_t out_mac_dma;
};
/* Cipher request of SEC private */
struct sec_cipher_req {
- struct hisi_acc_hw_sgl *c_in;
- dma_addr_t c_in_dma;
struct hisi_acc_hw_sgl *c_out;
dma_addr_t c_out_dma;
u8 *c_ivin;
@@ -33,15 +33,25 @@ struct sec_cipher_req {
struct sec_aead_req {
u8 *out_mac;
dma_addr_t out_mac_dma;
+ u8 *a_ivin;
+ dma_addr_t a_ivin_dma;
struct aead_request *aead_req;
};
/* SEC request of Crypto */
struct sec_req {
- struct sec_sqe sec_sqe;
+ union {
+ struct sec_sqe sec_sqe;
+ struct sec_sqe3 sec_sqe3;
+ };
struct sec_ctx *ctx;
struct sec_qp_ctx *qp_ctx;
+ /**
+ * Common parameter of the SEC request.
+ */
+ struct hisi_acc_hw_sgl *in;
+ dma_addr_t in_dma;
struct sec_cipher_req c_req;
struct sec_aead_req aead_req;
struct list_head backlog_head;
@@ -81,7 +91,9 @@ struct sec_auth_ctx {
u8 a_key_len;
u8 mac_len;
u8 a_alg;
+ bool fallback;
struct crypto_shash *hash_tfm;
+ struct crypto_aead *fallback_aead_tfm;
};
/* SEC cipher context which cipher's relatives */
@@ -94,6 +106,10 @@ struct sec_cipher_ctx {
u8 c_mode;
u8 c_alg;
u8 c_key_len;
+
+ /* add software support */
+ bool fallback;
+ struct crypto_sync_skcipher *fbtfm;
};
/* SEC queue context which defines queue's relatives */
@@ -137,6 +153,7 @@ struct sec_ctx {
bool pbuf_supported;
struct sec_cipher_ctx c_ctx;
struct sec_auth_ctx a_ctx;
+ u8 type_supported;
struct device *dev;
};
diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c
index 133aede8bf07..6a45bd23b363 100644
--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c
+++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c
@@ -2,6 +2,7 @@
/* Copyright (c) 2019 HiSilicon Limited. */
#include <crypto/aes.h>
+#include <crypto/aead.h>
#include <crypto/algapi.h>
#include <crypto/authenc.h>
#include <crypto/des.h>
@@ -21,6 +22,7 @@
#define SEC_PRIORITY 4001
#define SEC_XTS_MIN_KEY_SIZE (2 * AES_MIN_KEY_SIZE)
+#define SEC_XTS_MID_KEY_SIZE (3 * AES_MIN_KEY_SIZE)
#define SEC_XTS_MAX_KEY_SIZE (2 * AES_MAX_KEY_SIZE)
#define SEC_DES3_2KEY_SIZE (2 * DES_KEY_SIZE)
#define SEC_DES3_3KEY_SIZE (3 * DES_KEY_SIZE)
@@ -37,10 +39,23 @@
#define SEC_AEAD_ALG_OFFSET 11
#define SEC_AUTH_OFFSET 6
+#define SEC_DE_OFFSET_V3 9
+#define SEC_SCENE_OFFSET_V3 5
+#define SEC_CKEY_OFFSET_V3 13
+#define SEC_SRC_SGL_OFFSET_V3 11
+#define SEC_DST_SGL_OFFSET_V3 14
+#define SEC_CALG_OFFSET_V3 4
+#define SEC_AKEY_OFFSET_V3 9
+#define SEC_MAC_OFFSET_V3 4
+#define SEC_AUTH_ALG_OFFSET_V3 15
+#define SEC_CIPHER_AUTH_V3 0xbf
+#define SEC_AUTH_CIPHER_V3 0x40
#define SEC_FLAG_OFFSET 7
#define SEC_FLAG_MASK 0x0780
#define SEC_TYPE_MASK 0x0F
#define SEC_DONE_MASK 0x0001
+#define SEC_ICV_MASK 0x000E
+#define SEC_SQE_LEN_RATE_MASK 0x3
#define SEC_TOTAL_IV_SZ (SEC_IV_SIZE * QM_Q_DEPTH)
#define SEC_SGL_SGE_NR 128
@@ -66,6 +81,25 @@
#define SEC_SQE_CFLAG 2
#define SEC_SQE_AEAD_FLAG 3
#define SEC_SQE_DONE 0x1
+#define SEC_ICV_ERR 0x2
+#define MIN_MAC_LEN 4
+#define MAC_LEN_MASK 0x1U
+#define MAX_INPUT_DATA_LEN 0xFFFE00
+#define BITS_MASK 0xFF
+#define BYTE_BITS 0x8
+#define SEC_XTS_NAME_SZ 0x3
+#define IV_CM_CAL_NUM 2
+#define IV_CL_MASK 0x7
+#define IV_CL_MIN 2
+#define IV_CL_MID 4
+#define IV_CL_MAX 8
+#define IV_FLAGS_OFFSET 0x6
+#define IV_CM_OFFSET 0x3
+#define IV_LAST_BYTE1 1
+#define IV_LAST_BYTE2 2
+#define IV_LAST_BYTE_MASK 0xFF
+#define IV_CTR_INIT 0x1
+#define IV_BYTE_OFFSET 0x8
/* Get an en/de-cipher queue cyclically to balance load over queues of TFM */
static inline int sec_alloc_queue_id(struct sec_ctx *ctx, struct sec_req *req)
@@ -124,22 +158,59 @@ static void sec_free_req_id(struct sec_req *req)
mutex_unlock(&qp_ctx->req_lock);
}
-static int sec_aead_verify(struct sec_req *req)
+static u8 pre_parse_finished_bd(struct bd_status *status, void *resp)
{
- struct aead_request *aead_req = req->aead_req.aead_req;
- struct crypto_aead *tfm = crypto_aead_reqtfm(aead_req);
- size_t authsize = crypto_aead_authsize(tfm);
- u8 *mac_out = req->aead_req.out_mac;
- u8 *mac = mac_out + SEC_MAX_MAC_LEN;
- struct scatterlist *sgl = aead_req->src;
- size_t sz;
+ struct sec_sqe *bd = resp;
+
+ status->done = le16_to_cpu(bd->type2.done_flag) & SEC_DONE_MASK;
+ status->icv = (le16_to_cpu(bd->type2.done_flag) & SEC_ICV_MASK) >> 1;
+ status->flag = (le16_to_cpu(bd->type2.done_flag) &
+ SEC_FLAG_MASK) >> SEC_FLAG_OFFSET;
+ status->tag = le16_to_cpu(bd->type2.tag);
+ status->err_type = bd->type2.error_type;
+
+ return bd->type_cipher_auth & SEC_TYPE_MASK;
+}
+
+static u8 pre_parse_finished_bd3(struct bd_status *status, void *resp)
+{
+ struct sec_sqe3 *bd3 = resp;
+
+ status->done = le16_to_cpu(bd3->done_flag) & SEC_DONE_MASK;
+ status->icv = (le16_to_cpu(bd3->done_flag) & SEC_ICV_MASK) >> 1;
+ status->flag = (le16_to_cpu(bd3->done_flag) &
+ SEC_FLAG_MASK) >> SEC_FLAG_OFFSET;
+ status->tag = le64_to_cpu(bd3->tag);
+ status->err_type = bd3->error_type;
+
+ return le32_to_cpu(bd3->bd_param) & SEC_TYPE_MASK;
+}
+
+static int sec_cb_status_check(struct sec_req *req,
+ struct bd_status *status)
+{
+ struct sec_ctx *ctx = req->ctx;
- sz = sg_pcopy_to_buffer(sgl, sg_nents(sgl), mac, authsize,
- aead_req->cryptlen + aead_req->assoclen -
- authsize);
- if (unlikely(sz != authsize || memcmp(mac_out, mac, sz))) {
- dev_err(req->ctx->dev, "aead verify failure!\n");
- return -EBADMSG;
+ if (unlikely(req->err_type || status->done != SEC_SQE_DONE)) {
+ dev_err_ratelimited(ctx->dev, "err_type[%d], done[%u]\n",
+ req->err_type, status->done);
+ return -EIO;
+ }
+
+ if (unlikely(ctx->alg_type == SEC_SKCIPHER)) {
+ if (unlikely(status->flag != SEC_SQE_CFLAG)) {
+ dev_err_ratelimited(ctx->dev, "flag[%u]\n",
+ status->flag);
+ return -EIO;
+ }
+ } else if (unlikely(ctx->alg_type == SEC_AEAD)) {
+ if (unlikely(status->flag != SEC_SQE_AEAD_FLAG ||
+ status->icv == SEC_ICV_ERR)) {
+ dev_err_ratelimited(ctx->dev,
+ "flag[%u], icv[%u]\n",
+ status->flag, status->icv);
+ return -EBADMSG;
+ }
}
return 0;
@@ -149,43 +220,38 @@ static void sec_req_cb(struct hisi_qp *qp, void *resp)
{
struct sec_qp_ctx *qp_ctx = qp->qp_ctx;
struct sec_dfx *dfx = &qp_ctx->ctx->sec->debug.dfx;
- struct sec_sqe *bd = resp;
+ u8 type_supported = qp_ctx->ctx->type_supported;
+ struct bd_status status;
struct sec_ctx *ctx;
struct sec_req *req;
- u16 done, flag;
- int err = 0;
+ int err;
u8 type;
- type = bd->type_cipher_auth & SEC_TYPE_MASK;
- if (unlikely(type != SEC_BD_TYPE2)) {
+ if (type_supported == SEC_BD_TYPE2) {
+ type = pre_parse_finished_bd(&status, resp);
+ req = qp_ctx->req_list[status.tag];
+ } else {
+ type = pre_parse_finished_bd3(&status, resp);
+ req = (void *)(uintptr_t)status.tag;
+ }
+
+ if (unlikely(type != type_supported)) {
atomic64_inc(&dfx->err_bd_cnt);
pr_err("err bd type [%d]\n", type);
return;
}
- req = qp_ctx->req_list[le16_to_cpu(bd->type2.tag)];
if (unlikely(!req)) {
atomic64_inc(&dfx->invalid_req_cnt);
atomic_inc(&qp->qp_status.used);
return;
}
- req->err_type = bd->type2.error_type;
+
+ req->err_type = status.err_type;
ctx = req->ctx;
- done = le16_to_cpu(bd->type2.done_flag) & SEC_DONE_MASK;
- flag = (le16_to_cpu(bd->type2.done_flag) &
- SEC_FLAG_MASK) >> SEC_FLAG_OFFSET;
- if (unlikely(req->err_type || done != SEC_SQE_DONE ||
- (ctx->alg_type == SEC_SKCIPHER && flag != SEC_SQE_CFLAG) ||
- (ctx->alg_type == SEC_AEAD && flag != SEC_SQE_AEAD_FLAG))) {
- dev_err_ratelimited(ctx->dev,
- "err_type[%d],done[%d],flag[%d]\n",
- req->err_type, done, flag);
- err = -EIO;
+ err = sec_cb_status_check(req, &status);
+ if (err)
atomic64_inc(&dfx->done_flag_cnt);
- }
-
- if (ctx->alg_type == SEC_AEAD && !req->c_req.encrypt)
- err = sec_aead_verify(req);
atomic64_inc(&dfx->recv_cnt);
@@ -253,6 +319,30 @@ static void sec_free_civ_resource(struct device *dev, struct sec_alg_res *res)
res->c_ivin, res->c_ivin_dma);
}
+static int sec_alloc_aiv_resource(struct device *dev, struct sec_alg_res *res)
+{
+ int i;
+
+ res->a_ivin = dma_alloc_coherent(dev, SEC_TOTAL_IV_SZ,
+ &res->a_ivin_dma, GFP_KERNEL);
+ if (!res->a_ivin)
+ return -ENOMEM;
+
+ for (i = 1; i < QM_Q_DEPTH; i++) {
+ res[i].a_ivin_dma = res->a_ivin_dma + i * SEC_IV_SIZE;
+ res[i].a_ivin = res->a_ivin + i * SEC_IV_SIZE;
+ }
+
+ return 0;
+}
+
+static void sec_free_aiv_resource(struct device *dev, struct sec_alg_res *res)
+{
+ if (res->a_ivin)
+ dma_free_coherent(dev, SEC_TOTAL_IV_SZ,
+ res->a_ivin, res->a_ivin_dma);
+}
+
static int sec_alloc_mac_resource(struct device *dev, struct sec_alg_res *res)
{
int i;
@@ -335,9 +425,13 @@ static int sec_alg_resource_alloc(struct sec_ctx *ctx,
return ret;
if (ctx->alg_type == SEC_AEAD) {
+ ret = sec_alloc_aiv_resource(dev, res);
+ if (ret)
+ goto alloc_aiv_fail;
+
ret = sec_alloc_mac_resource(dev, res);
if (ret)
- goto alloc_fail;
+ goto alloc_mac_fail;
}
if (ctx->pbuf_supported) {
ret = sec_alloc_pbuf_resource(dev, res);
@@ -352,7 +446,10 @@ static int sec_alg_resource_alloc(struct sec_ctx *ctx,
alloc_pbuf_fail:
if (ctx->alg_type == SEC_AEAD)
sec_free_mac_resource(dev, qp_ctx->res);
-alloc_fail:
+alloc_mac_fail:
+ if (ctx->alg_type == SEC_AEAD)
+ sec_free_aiv_resource(dev, res);
+alloc_aiv_fail:
sec_free_civ_resource(dev, res);
return ret;
}
@@ -382,10 +479,11 @@ static int sec_create_qp_ctx(struct hisi_qm *qm, struct sec_ctx *ctx,
qp = ctx->qps[qp_ctx_id];
qp->req_type = 0;
qp->qp_ctx = qp_ctx;
- qp->req_cb = sec_req_cb;
qp_ctx->qp = qp;
qp_ctx->ctx = ctx;
+ qp->req_cb = sec_req_cb;
+
mutex_init(&qp_ctx->req_lock);
idr_init(&qp_ctx->req_idr);
INIT_LIST_HEAD(&qp_ctx->backlog);
@@ -536,6 +634,26 @@ static void sec_auth_uninit(struct sec_ctx *ctx)
a_ctx->a_key, a_ctx->a_key_dma);
}
+static int sec_skcipher_fbtfm_init(struct crypto_skcipher *tfm)
+{
+ const char *alg = crypto_tfm_alg_name(&tfm->base);
+ struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
+
+ c_ctx->fallback = false;
+ if (likely(strncmp(alg, "xts", SEC_XTS_NAME_SZ)))
+ return 0;
+
+ c_ctx->fbtfm = crypto_alloc_sync_skcipher(alg, 0,
+ CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(c_ctx->fbtfm)) {
+ pr_err("failed to alloc fallback tfm!\n");
+ return PTR_ERR(c_ctx->fbtfm);
+ }
+
+ return 0;
+}
+
static int sec_skcipher_init(struct crypto_skcipher *tfm)
{
struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
@@ -557,8 +675,14 @@ static int sec_skcipher_init(struct crypto_skcipher *tfm)
if (ret)
goto err_cipher_init;
+ ret = sec_skcipher_fbtfm_init(tfm);
+ if (ret)
+ goto err_fbtfm_init;
+
return 0;
+err_fbtfm_init:
+ sec_cipher_uninit(ctx);
err_cipher_init:
sec_ctx_base_uninit(ctx);
return ret;
@@ -568,6 +692,9 @@ static void sec_skcipher_uninit(struct crypto_skcipher *tfm)
{
struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
+ if (ctx->c_ctx.fbtfm)
+ crypto_free_sync_skcipher(ctx->c_ctx.fbtfm);
+
sec_cipher_uninit(ctx);
sec_ctx_base_uninit(ctx);
}
@@ -607,6 +734,9 @@ static int sec_skcipher_aes_sm4_setkey(struct sec_cipher_ctx *c_ctx,
case SEC_XTS_MIN_KEY_SIZE:
c_ctx->c_key_len = SEC_CKEY_128BIT;
break;
+ case SEC_XTS_MID_KEY_SIZE:
+ c_ctx->fallback = true;
+ break;
case SEC_XTS_MAX_KEY_SIZE:
c_ctx->c_key_len = SEC_CKEY_256BIT;
break;
@@ -615,19 +745,25 @@ static int sec_skcipher_aes_sm4_setkey(struct sec_cipher_ctx *c_ctx,
return -EINVAL;
}
} else {
- switch (keylen) {
- case AES_KEYSIZE_128:
- c_ctx->c_key_len = SEC_CKEY_128BIT;
- break;
- case AES_KEYSIZE_192:
- c_ctx->c_key_len = SEC_CKEY_192BIT;
- break;
- case AES_KEYSIZE_256:
- c_ctx->c_key_len = SEC_CKEY_256BIT;
- break;
- default:
- pr_err("hisi_sec2: aes key error!\n");
+ if (c_ctx->c_alg == SEC_CALG_SM4 &&
+ keylen != AES_KEYSIZE_128) {
+ pr_err("hisi_sec2: sm4 key error!\n");
return -EINVAL;
+ } else {
+ switch (keylen) {
+ case AES_KEYSIZE_128:
+ c_ctx->c_key_len = SEC_CKEY_128BIT;
+ break;
+ case AES_KEYSIZE_192:
+ c_ctx->c_key_len = SEC_CKEY_192BIT;
+ break;
+ case AES_KEYSIZE_256:
+ c_ctx->c_key_len = SEC_CKEY_256BIT;
+ break;
+ default:
+ pr_err("hisi_sec2: aes key error!\n");
+ return -EINVAL;
+ }
}
}
@@ -672,7 +808,13 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key,
}
memcpy(c_ctx->c_key, key, keylen);
-
+ if (c_ctx->fallback) {
+ ret = crypto_sync_skcipher_setkey(c_ctx->fbtfm, key, keylen);
+ if (ret) {
+ dev_err(dev, "failed to set fallback skcipher key!\n");
+ return ret;
+ }
+ }
return 0;
}
@@ -686,22 +828,30 @@ static int sec_setkey_##name(struct crypto_skcipher *tfm, const u8 *key,\
GEN_SEC_SETKEY_FUNC(aes_ecb, SEC_CALG_AES, SEC_CMODE_ECB)
GEN_SEC_SETKEY_FUNC(aes_cbc, SEC_CALG_AES, SEC_CMODE_CBC)
GEN_SEC_SETKEY_FUNC(aes_xts, SEC_CALG_AES, SEC_CMODE_XTS)
-
+GEN_SEC_SETKEY_FUNC(aes_ofb, SEC_CALG_AES, SEC_CMODE_OFB)
+GEN_SEC_SETKEY_FUNC(aes_cfb, SEC_CALG_AES, SEC_CMODE_CFB)
+GEN_SEC_SETKEY_FUNC(aes_ctr, SEC_CALG_AES, SEC_CMODE_CTR)
GEN_SEC_SETKEY_FUNC(3des_ecb, SEC_CALG_3DES, SEC_CMODE_ECB)
GEN_SEC_SETKEY_FUNC(3des_cbc, SEC_CALG_3DES, SEC_CMODE_CBC)
-
GEN_SEC_SETKEY_FUNC(sm4_xts, SEC_CALG_SM4, SEC_CMODE_XTS)
GEN_SEC_SETKEY_FUNC(sm4_cbc, SEC_CALG_SM4, SEC_CMODE_CBC)
+GEN_SEC_SETKEY_FUNC(sm4_ofb, SEC_CALG_SM4, SEC_CMODE_OFB)
+GEN_SEC_SETKEY_FUNC(sm4_cfb, SEC_CALG_SM4, SEC_CMODE_CFB)
+GEN_SEC_SETKEY_FUNC(sm4_ctr, SEC_CALG_SM4, SEC_CMODE_CTR)
static int sec_cipher_pbuf_map(struct sec_ctx *ctx, struct sec_req *req,
struct scatterlist *src)
{
- struct aead_request *aead_req = req->aead_req.aead_req;
+ struct sec_aead_req *a_req = &req->aead_req;
+ struct aead_request *aead_req = a_req->aead_req;
struct sec_cipher_req *c_req = &req->c_req;
struct sec_qp_ctx *qp_ctx = req->qp_ctx;
struct device *dev = ctx->dev;
int copy_size, pbuf_length;
int req_id = req->req_id;
+ struct crypto_aead *tfm;
+ size_t authsize;
+ u8 *mac_offset;
if (ctx->alg_type == SEC_AEAD)
copy_size = aead_req->cryptlen + aead_req->assoclen;
@@ -709,15 +859,20 @@ static int sec_cipher_pbuf_map(struct sec_ctx *ctx, struct sec_req *req,
copy_size = c_req->c_len;
pbuf_length = sg_copy_to_buffer(src, sg_nents(src),
- qp_ctx->res[req_id].pbuf,
- copy_size);
+ qp_ctx->res[req_id].pbuf, copy_size);
if (unlikely(pbuf_length != copy_size)) {
dev_err(dev, "copy src data to pbuf error!\n");
return -EINVAL;
}
+ if (!c_req->encrypt && ctx->alg_type == SEC_AEAD) {
+ tfm = crypto_aead_reqtfm(aead_req);
+ authsize = crypto_aead_authsize(tfm);
+ mac_offset = qp_ctx->res[req_id].pbuf + copy_size - authsize;
+ memcpy(a_req->out_mac, mac_offset, authsize);
+ }
- c_req->c_in_dma = qp_ctx->res[req_id].pbuf_dma;
- c_req->c_out_dma = c_req->c_in_dma;
+ req->in_dma = qp_ctx->res[req_id].pbuf_dma;
+ c_req->c_out_dma = req->in_dma;
return 0;
}
@@ -728,7 +883,6 @@ static void sec_cipher_pbuf_unmap(struct sec_ctx *ctx, struct sec_req *req,
struct aead_request *aead_req = req->aead_req.aead_req;
struct sec_cipher_req *c_req = &req->c_req;
struct sec_qp_ctx *qp_ctx = req->qp_ctx;
- struct device *dev = ctx->dev;
int copy_size, pbuf_length;
int req_id = req->req_id;
@@ -738,10 +892,29 @@ static void sec_cipher_pbuf_unmap(struct sec_ctx *ctx, struct sec_req *req,
copy_size = c_req->c_len;
pbuf_length = sg_copy_from_buffer(dst, sg_nents(dst),
- qp_ctx->res[req_id].pbuf,
- copy_size);
+ qp_ctx->res[req_id].pbuf, copy_size);
if (unlikely(pbuf_length != copy_size))
- dev_err(dev, "copy pbuf data to dst error!\n");
+ dev_err(ctx->dev, "copy pbuf data to dst error!\n");
+}
+
+static int sec_aead_mac_init(struct sec_aead_req *req)
+{
+ struct aead_request *aead_req = req->aead_req;
+ struct crypto_aead *tfm = crypto_aead_reqtfm(aead_req);
+ size_t authsize = crypto_aead_authsize(tfm);
+ u8 *mac_out = req->out_mac;
+ struct scatterlist *sgl = aead_req->src;
+ size_t copy_size;
+ off_t skip_size;
+
+ /* Copy input mac */
+ skip_size = aead_req->assoclen + aead_req->cryptlen - authsize;
+ copy_size = sg_pcopy_to_buffer(sgl, sg_nents(sgl), mac_out,
+ authsize, skip_size);
+ if (unlikely(copy_size != authsize))
+ return -EINVAL;
+
+ return 0;
}
static int sec_cipher_map(struct sec_ctx *ctx, struct sec_req *req,
@@ -755,37 +928,48 @@ static int sec_cipher_map(struct sec_ctx *ctx, struct sec_req *req,
int ret;
if (req->use_pbuf) {
- ret = sec_cipher_pbuf_map(ctx, req, src);
c_req->c_ivin = res->pbuf + SEC_PBUF_IV_OFFSET;
c_req->c_ivin_dma = res->pbuf_dma + SEC_PBUF_IV_OFFSET;
if (ctx->alg_type == SEC_AEAD) {
+ a_req->a_ivin = res->a_ivin;
+ a_req->a_ivin_dma = res->a_ivin_dma;
a_req->out_mac = res->pbuf + SEC_PBUF_MAC_OFFSET;
a_req->out_mac_dma = res->pbuf_dma +
SEC_PBUF_MAC_OFFSET;
}
+ ret = sec_cipher_pbuf_map(ctx, req, src);
return ret;
}
c_req->c_ivin = res->c_ivin;
c_req->c_ivin_dma = res->c_ivin_dma;
if (ctx->alg_type == SEC_AEAD) {
+ a_req->a_ivin = res->a_ivin;
+ a_req->a_ivin_dma = res->a_ivin_dma;
a_req->out_mac = res->out_mac;
a_req->out_mac_dma = res->out_mac_dma;
}
- c_req->c_in = hisi_acc_sg_buf_map_to_hw_sgl(dev, src,
- qp_ctx->c_in_pool,
- req->req_id,
- &c_req->c_in_dma);
-
- if (IS_ERR(c_req->c_in)) {
+ req->in = hisi_acc_sg_buf_map_to_hw_sgl(dev, src,
+ qp_ctx->c_in_pool,
+ req->req_id,
+ &req->in_dma);
+ if (IS_ERR(req->in)) {
dev_err(dev, "fail to dma map input sgl buffers!\n");
- return PTR_ERR(c_req->c_in);
+ return PTR_ERR(req->in);
+ }
+
+ if (!c_req->encrypt && ctx->alg_type == SEC_AEAD) {
+ ret = sec_aead_mac_init(a_req);
+ if (unlikely(ret)) {
+ dev_err(dev, "fail to init mac data for ICV!\n");
+ return ret;
+ }
}
if (dst == src) {
- c_req->c_out = c_req->c_in;
- c_req->c_out_dma = c_req->c_in_dma;
+ c_req->c_out = req->in;
+ c_req->c_out_dma = req->in_dma;
} else {
c_req->c_out = hisi_acc_sg_buf_map_to_hw_sgl(dev, dst,
qp_ctx->c_out_pool,
@@ -794,7 +978,7 @@ static int sec_cipher_map(struct sec_ctx *ctx, struct sec_req *req,
if (IS_ERR(c_req->c_out)) {
dev_err(dev, "fail to dma map output sgl buffers!\n");
- hisi_acc_sg_buf_unmap(dev, src, c_req->c_in);
+ hisi_acc_sg_buf_unmap(dev, src, req->in);
return PTR_ERR(c_req->c_out);
}
}
@@ -812,7 +996,7 @@ static void sec_cipher_unmap(struct sec_ctx *ctx, struct sec_req *req,
sec_cipher_pbuf_unmap(ctx, req, dst);
} else {
if (dst != src)
- hisi_acc_sg_buf_unmap(dev, src, c_req->c_in);
+ hisi_acc_sg_buf_unmap(dev, src, req->in);
hisi_acc_sg_buf_unmap(dev, dst, c_req->c_out);
}
@@ -883,6 +1067,28 @@ static int sec_aead_auth_set_key(struct sec_auth_ctx *ctx,
return 0;
}
+static int sec_aead_setauthsize(struct crypto_aead *aead, unsigned int authsize)
+{
+ struct crypto_tfm *tfm = crypto_aead_tfm(aead);
+ struct sec_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+
+ if (unlikely(a_ctx->fallback_aead_tfm))
+ return crypto_aead_setauthsize(a_ctx->fallback_aead_tfm, authsize);
+
+ return 0;
+}
+
+static int sec_aead_fallback_setkey(struct sec_auth_ctx *a_ctx,
+ struct crypto_aead *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ crypto_aead_clear_flags(a_ctx->fallback_aead_tfm, CRYPTO_TFM_REQ_MASK);
+ crypto_aead_set_flags(a_ctx->fallback_aead_tfm,
+ crypto_aead_get_flags(tfm) & CRYPTO_TFM_REQ_MASK);
+ return crypto_aead_setkey(a_ctx->fallback_aead_tfm, key, keylen);
+}
+
static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key,
const u32 keylen, const enum sec_hash_alg a_alg,
const enum sec_calg c_alg,
@@ -891,6 +1097,7 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key,
{
struct sec_ctx *ctx = crypto_aead_ctx(tfm);
struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
+ struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
struct device *dev = ctx->dev;
struct crypto_authenc_keys keys;
int ret;
@@ -900,6 +1107,23 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key,
ctx->a_ctx.mac_len = mac_len;
c_ctx->c_mode = c_mode;
+ if (c_mode == SEC_CMODE_CCM || c_mode == SEC_CMODE_GCM) {
+ ret = sec_skcipher_aes_sm4_setkey(c_ctx, keylen, c_mode);
+ if (ret) {
+ dev_err(dev, "set sec aes ccm cipher key err!\n");
+ return ret;
+ }
+ memcpy(c_ctx->c_key, key, keylen);
+
+ if (unlikely(a_ctx->fallback_aead_tfm)) {
+ ret = sec_aead_fallback_setkey(a_ctx, tfm, key, keylen);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+ }
+
if (crypto_authenc_extractkeys(&keys, key, keylen))
goto bad_key;
@@ -915,6 +1139,12 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key,
goto bad_key;
}
+ if ((ctx->a_ctx.mac_len & SEC_SQE_LEN_RATE_MASK) ||
+ (ctx->a_ctx.a_key_len & SEC_SQE_LEN_RATE_MASK)) {
+ dev_err(dev, "MAC or AUTH key length error!\n");
+ goto bad_key;
+ }
+
return 0;
bad_key:
@@ -936,6 +1166,14 @@ GEN_SEC_AEAD_SETKEY_FUNC(aes_cbc_sha256, SEC_A_HMAC_SHA256,
SEC_CALG_AES, SEC_HMAC_SHA256_MAC, SEC_CMODE_CBC)
GEN_SEC_AEAD_SETKEY_FUNC(aes_cbc_sha512, SEC_A_HMAC_SHA512,
SEC_CALG_AES, SEC_HMAC_SHA512_MAC, SEC_CMODE_CBC)
+GEN_SEC_AEAD_SETKEY_FUNC(aes_ccm, 0, SEC_CALG_AES,
+ SEC_HMAC_CCM_MAC, SEC_CMODE_CCM)
+GEN_SEC_AEAD_SETKEY_FUNC(aes_gcm, 0, SEC_CALG_AES,
+ SEC_HMAC_GCM_MAC, SEC_CMODE_GCM)
+GEN_SEC_AEAD_SETKEY_FUNC(sm4_ccm, 0, SEC_CALG_SM4,
+ SEC_HMAC_CCM_MAC, SEC_CMODE_CCM)
+GEN_SEC_AEAD_SETKEY_FUNC(sm4_gcm, 0, SEC_CALG_SM4,
+ SEC_HMAC_GCM_MAC, SEC_CMODE_GCM)
static int sec_aead_sgl_map(struct sec_ctx *ctx, struct sec_req *req)
{
@@ -998,7 +1236,7 @@ static int sec_skcipher_bd_fill(struct sec_ctx *ctx, struct sec_req *req)
sec_sqe->type2.c_key_addr = cpu_to_le64(c_ctx->c_key_dma);
sec_sqe->type2.c_ivin_addr = cpu_to_le64(c_req->c_ivin_dma);
- sec_sqe->type2.data_src_addr = cpu_to_le64(c_req->c_in_dma);
+ sec_sqe->type2.data_src_addr = cpu_to_le64(req->in_dma);
sec_sqe->type2.data_dst_addr = cpu_to_le64(c_req->c_out_dma);
sec_sqe->type2.icvw_kmode |= cpu_to_le16(((u16)c_ctx->c_mode) <<
@@ -1014,29 +1252,86 @@ static int sec_skcipher_bd_fill(struct sec_ctx *ctx, struct sec_req *req)
cipher = SEC_CIPHER_DEC << SEC_CIPHER_OFFSET;
sec_sqe->type_cipher_auth = bd_type | cipher;
- if (req->use_pbuf)
+ /* Set destination and source address type */
+ if (req->use_pbuf) {
sa_type = SEC_PBUF << SEC_SRC_SGL_OFFSET;
- else
+ da_type = SEC_PBUF << SEC_DST_SGL_OFFSET;
+ } else {
sa_type = SEC_SGL << SEC_SRC_SGL_OFFSET;
+ da_type = SEC_SGL << SEC_DST_SGL_OFFSET;
+ }
+
+ sec_sqe->sdm_addr_type |= da_type;
scene = SEC_COMM_SCENE << SEC_SCENE_OFFSET;
- if (c_req->c_in_dma != c_req->c_out_dma)
+ if (req->in_dma != c_req->c_out_dma)
de = 0x1 << SEC_DE_OFFSET;
sec_sqe->sds_sa_type = (de | scene | sa_type);
- /* Just set DST address type */
- if (req->use_pbuf)
- da_type = SEC_PBUF << SEC_DST_SGL_OFFSET;
- else
- da_type = SEC_SGL << SEC_DST_SGL_OFFSET;
- sec_sqe->sdm_addr_type |= da_type;
-
sec_sqe->type2.clen_ivhlen |= cpu_to_le32(c_req->c_len);
sec_sqe->type2.tag = cpu_to_le16((u16)req->req_id);
return 0;
}
+static int sec_skcipher_bd_fill_v3(struct sec_ctx *ctx, struct sec_req *req)
+{
+ struct sec_sqe3 *sec_sqe3 = &req->sec_sqe3;
+ struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
+ struct sec_cipher_req *c_req = &req->c_req;
+ u32 bd_param = 0;
+ u16 cipher;
+
+ memset(sec_sqe3, 0, sizeof(struct sec_sqe3));
+
+ sec_sqe3->c_key_addr = cpu_to_le64(c_ctx->c_key_dma);
+ sec_sqe3->no_scene.c_ivin_addr = cpu_to_le64(c_req->c_ivin_dma);
+ sec_sqe3->data_src_addr = cpu_to_le64(req->in_dma);
+ sec_sqe3->data_dst_addr = cpu_to_le64(c_req->c_out_dma);
+
+ sec_sqe3->c_mode_alg = ((u8)c_ctx->c_alg << SEC_CALG_OFFSET_V3) |
+ c_ctx->c_mode;
+ sec_sqe3->c_icv_key |= cpu_to_le16(((u16)c_ctx->c_key_len) <<
+ SEC_CKEY_OFFSET_V3);
+
+ if (c_req->encrypt)
+ cipher = SEC_CIPHER_ENC;
+ else
+ cipher = SEC_CIPHER_DEC;
+ sec_sqe3->c_icv_key |= cpu_to_le16(cipher);
+
+ if (req->use_pbuf) {
+ bd_param |= SEC_PBUF << SEC_SRC_SGL_OFFSET_V3;
+ bd_param |= SEC_PBUF << SEC_DST_SGL_OFFSET_V3;
+ } else {
+ bd_param |= SEC_SGL << SEC_SRC_SGL_OFFSET_V3;
+ bd_param |= SEC_SGL << SEC_DST_SGL_OFFSET_V3;
+ }
+
+ bd_param |= SEC_COMM_SCENE << SEC_SCENE_OFFSET_V3;
+ if (req->in_dma != c_req->c_out_dma)
+ bd_param |= 0x1 << SEC_DE_OFFSET_V3;
+
+ bd_param |= SEC_BD_TYPE3;
+ sec_sqe3->bd_param = cpu_to_le32(bd_param);
+
+ sec_sqe3->c_len_ivin |= cpu_to_le32(c_req->c_len);
+ sec_sqe3->tag = cpu_to_le64(req);
+
+ return 0;
+}
+
+/* increment counter (128-bit int) */
+static void ctr_iv_inc(__u8 *counter, __u8 bits, __u32 nums)
+{
+ do {
+ --bits;
+ nums += counter[bits];
+ counter[bits] = nums & BITS_MASK;
+ nums >>= BYTE_BITS;
+ } while (bits && nums);
+}
+
static void sec_update_iv(struct sec_req *req, enum sec_alg_type alg_type)
{
struct aead_request *aead_req = req->aead_req.aead_req;
@@ -1060,10 +1355,17 @@ static void sec_update_iv(struct sec_req *req, enum sec_alg_type alg_type)
cryptlen = aead_req->cryptlen;
}
- sz = sg_pcopy_to_buffer(sgl, sg_nents(sgl), iv, iv_size,
- cryptlen - iv_size);
- if (unlikely(sz != iv_size))
- dev_err(req->ctx->dev, "copy output iv error!\n");
+ if (req->ctx->c_ctx.c_mode == SEC_CMODE_CBC) {
+ sz = sg_pcopy_to_buffer(sgl, sg_nents(sgl), iv, iv_size,
+ cryptlen - iv_size);
+ if (unlikely(sz != iv_size))
+ dev_err(req->ctx->dev, "copy output iv error!\n");
+ } else {
+ sz = cryptlen / iv_size;
+ if (cryptlen % iv_size)
+ sz += 1;
+ ctr_iv_inc(iv, iv_size, sz);
+ }
}
static struct sec_req *sec_back_req_clear(struct sec_ctx *ctx,
@@ -1094,8 +1396,9 @@ static void sec_skcipher_callback(struct sec_ctx *ctx, struct sec_req *req,
sec_free_req_id(req);
- /* IV output at encrypto of CBC mode */
- if (!err && ctx->c_ctx.c_mode == SEC_CMODE_CBC && req->c_req.encrypt)
+ /* IV output at encrypto of CBC/CTR mode */
+ if (!err && (ctx->c_ctx.c_mode == SEC_CMODE_CBC ||
+ ctx->c_ctx.c_mode == SEC_CMODE_CTR) && req->c_req.encrypt)
sec_update_iv(req, SEC_SKCIPHER);
while (1) {
@@ -1112,12 +1415,125 @@ static void sec_skcipher_callback(struct sec_ctx *ctx, struct sec_req *req,
sk_req->base.complete(&sk_req->base, err);
}
-static void sec_aead_copy_iv(struct sec_ctx *ctx, struct sec_req *req)
+static void set_aead_auth_iv(struct sec_ctx *ctx, struct sec_req *req)
+{
+ struct aead_request *aead_req = req->aead_req.aead_req;
+ struct sec_cipher_req *c_req = &req->c_req;
+ struct sec_aead_req *a_req = &req->aead_req;
+ size_t authsize = ctx->a_ctx.mac_len;
+ u32 data_size = aead_req->cryptlen;
+ u8 flage = 0;
+ u8 cm, cl;
+
+ /* the specification has been checked in aead_iv_demension_check() */
+ cl = c_req->c_ivin[0] + 1;
+ c_req->c_ivin[ctx->c_ctx.ivsize - cl] = 0x00;
+ memset(&c_req->c_ivin[ctx->c_ctx.ivsize - cl], 0, cl);
+ c_req->c_ivin[ctx->c_ctx.ivsize - IV_LAST_BYTE1] = IV_CTR_INIT;
+
+ /* the last 3bit is L' */
+ flage |= c_req->c_ivin[0] & IV_CL_MASK;
+
+ /* the M' is bit3~bit5, the Flags is bit6 */
+ cm = (authsize - IV_CM_CAL_NUM) / IV_CM_CAL_NUM;
+ flage |= cm << IV_CM_OFFSET;
+ if (aead_req->assoclen)
+ flage |= 0x01 << IV_FLAGS_OFFSET;
+
+ memcpy(a_req->a_ivin, c_req->c_ivin, ctx->c_ctx.ivsize);
+ a_req->a_ivin[0] = flage;
+
+ /*
+ * the last 32bit is counter's initial number,
+ * but the nonce uses the first 16bit
+ * the tail 16bit fill with the cipher length
+ */
+ if (!c_req->encrypt)
+ data_size = aead_req->cryptlen - authsize;
+
+ a_req->a_ivin[ctx->c_ctx.ivsize - IV_LAST_BYTE1] =
+ data_size & IV_LAST_BYTE_MASK;
+ data_size >>= IV_BYTE_OFFSET;
+ a_req->a_ivin[ctx->c_ctx.ivsize - IV_LAST_BYTE2] =
+ data_size & IV_LAST_BYTE_MASK;
+}
+
+static void sec_aead_set_iv(struct sec_ctx *ctx, struct sec_req *req)
{
struct aead_request *aead_req = req->aead_req.aead_req;
+ struct crypto_aead *tfm = crypto_aead_reqtfm(aead_req);
+ size_t authsize = crypto_aead_authsize(tfm);
struct sec_cipher_req *c_req = &req->c_req;
+ struct sec_aead_req *a_req = &req->aead_req;
memcpy(c_req->c_ivin, aead_req->iv, ctx->c_ctx.ivsize);
+
+ if (ctx->c_ctx.c_mode == SEC_CMODE_CCM) {
+ /*
+ * CCM 16Byte Cipher_IV: {1B_Flage,13B_IV,2B_counter},
+ * the counter must set to 0x01
+ */
+ ctx->a_ctx.mac_len = authsize;
+ /* CCM 16Byte Auth_IV: {1B_AFlage,13B_IV,2B_Ptext_length} */
+ set_aead_auth_iv(ctx, req);
+ }
+
+ /* GCM 12Byte Cipher_IV == Auth_IV */
+ if (ctx->c_ctx.c_mode == SEC_CMODE_GCM) {
+ ctx->a_ctx.mac_len = authsize;
+ memcpy(a_req->a_ivin, c_req->c_ivin, SEC_AIV_SIZE);
+ }
+}
+
+static void sec_auth_bd_fill_xcm(struct sec_auth_ctx *ctx, int dir,
+ struct sec_req *req, struct sec_sqe *sec_sqe)
+{
+ struct sec_aead_req *a_req = &req->aead_req;
+ struct aead_request *aq = a_req->aead_req;
+
+ /* C_ICV_Len is MAC size, 0x4 ~ 0x10 */
+ sec_sqe->type2.icvw_kmode |= cpu_to_le16((u16)ctx->mac_len);
+
+ /* mode set to CCM/GCM, don't set {A_Alg, AKey_Len, MAC_Len} */
+ sec_sqe->type2.a_key_addr = sec_sqe->type2.c_key_addr;
+ sec_sqe->type2.a_ivin_addr = cpu_to_le64(a_req->a_ivin_dma);
+ sec_sqe->type_cipher_auth |= SEC_NO_AUTH << SEC_AUTH_OFFSET;
+
+ if (dir)
+ sec_sqe->sds_sa_type &= SEC_CIPHER_AUTH;
+ else
+ sec_sqe->sds_sa_type |= SEC_AUTH_CIPHER;
+
+ sec_sqe->type2.alen_ivllen = cpu_to_le32(aq->assoclen);
+ sec_sqe->type2.auth_src_offset = cpu_to_le16(0x0);
+ sec_sqe->type2.cipher_src_offset = cpu_to_le16((u16)aq->assoclen);
+
+ sec_sqe->type2.mac_addr = cpu_to_le64(a_req->out_mac_dma);
+}
+
+static void sec_auth_bd_fill_xcm_v3(struct sec_auth_ctx *ctx, int dir,
+ struct sec_req *req, struct sec_sqe3 *sqe3)
+{
+ struct sec_aead_req *a_req = &req->aead_req;
+ struct aead_request *aq = a_req->aead_req;
+
+ /* C_ICV_Len is MAC size, 0x4 ~ 0x10 */
+ sqe3->c_icv_key |= cpu_to_le16((u16)ctx->mac_len << SEC_MAC_OFFSET_V3);
+
+ /* mode set to CCM/GCM, don't set {A_Alg, AKey_Len, MAC_Len} */
+ sqe3->a_key_addr = sqe3->c_key_addr;
+ sqe3->auth_ivin.a_ivin_addr = cpu_to_le64(a_req->a_ivin_dma);
+ sqe3->auth_mac_key |= SEC_NO_AUTH;
+
+ if (dir)
+ sqe3->huk_iv_seq &= SEC_CIPHER_AUTH_V3;
+ else
+ sqe3->huk_iv_seq |= SEC_AUTH_CIPHER_V3;
+
+ sqe3->a_len_key = cpu_to_le32(aq->assoclen);
+ sqe3->auth_src_offset = cpu_to_le16(0x0);
+ sqe3->cipher_src_offset = cpu_to_le16((u16)aq->assoclen);
+ sqe3->mac_addr = cpu_to_le64(a_req->out_mac_dma);
}
static void sec_auth_bd_fill_ex(struct sec_auth_ctx *ctx, int dir,
@@ -1139,13 +1555,13 @@ static void sec_auth_bd_fill_ex(struct sec_auth_ctx *ctx, int dir,
sec_sqe->type2.mac_key_alg |=
cpu_to_le32((u32)(ctx->a_alg) << SEC_AEAD_ALG_OFFSET);
- sec_sqe->type_cipher_auth |= SEC_AUTH_TYPE1 << SEC_AUTH_OFFSET;
-
- if (dir)
+ if (dir) {
+ sec_sqe->type_cipher_auth |= SEC_AUTH_TYPE1 << SEC_AUTH_OFFSET;
sec_sqe->sds_sa_type &= SEC_CIPHER_AUTH;
- else
+ } else {
+ sec_sqe->type_cipher_auth |= SEC_AUTH_TYPE2 << SEC_AUTH_OFFSET;
sec_sqe->sds_sa_type |= SEC_AUTH_CIPHER;
-
+ }
sec_sqe->type2.alen_ivllen = cpu_to_le32(c_req->c_len + aq->assoclen);
sec_sqe->type2.cipher_src_offset = cpu_to_le16((u16)aq->assoclen);
@@ -1165,7 +1581,68 @@ static int sec_aead_bd_fill(struct sec_ctx *ctx, struct sec_req *req)
return ret;
}
- sec_auth_bd_fill_ex(auth_ctx, req->c_req.encrypt, req, sec_sqe);
+ if (ctx->c_ctx.c_mode == SEC_CMODE_CCM ||
+ ctx->c_ctx.c_mode == SEC_CMODE_GCM)
+ sec_auth_bd_fill_xcm(auth_ctx, req->c_req.encrypt, req, sec_sqe);
+ else
+ sec_auth_bd_fill_ex(auth_ctx, req->c_req.encrypt, req, sec_sqe);
+
+ return 0;
+}
+
+static void sec_auth_bd_fill_ex_v3(struct sec_auth_ctx *ctx, int dir,
+ struct sec_req *req, struct sec_sqe3 *sqe3)
+{
+ struct sec_aead_req *a_req = &req->aead_req;
+ struct sec_cipher_req *c_req = &req->c_req;
+ struct aead_request *aq = a_req->aead_req;
+
+ sqe3->a_key_addr = cpu_to_le64(ctx->a_key_dma);
+
+ sqe3->auth_mac_key |=
+ cpu_to_le32((u32)(ctx->mac_len /
+ SEC_SQE_LEN_RATE) << SEC_MAC_OFFSET_V3);
+
+ sqe3->auth_mac_key |=
+ cpu_to_le32((u32)(ctx->a_key_len /
+ SEC_SQE_LEN_RATE) << SEC_AKEY_OFFSET_V3);
+
+ sqe3->auth_mac_key |=
+ cpu_to_le32((u32)(ctx->a_alg) << SEC_AUTH_ALG_OFFSET_V3);
+
+ if (dir) {
+ sqe3->auth_mac_key |= cpu_to_le32((u32)SEC_AUTH_TYPE1);
+ sqe3->huk_iv_seq &= SEC_CIPHER_AUTH_V3;
+ } else {
+ sqe3->auth_mac_key |= cpu_to_le32((u32)SEC_AUTH_TYPE1);
+ sqe3->huk_iv_seq |= SEC_AUTH_CIPHER_V3;
+ }
+ sqe3->a_len_key = cpu_to_le32(c_req->c_len + aq->assoclen);
+
+ sqe3->cipher_src_offset = cpu_to_le16((u16)aq->assoclen);
+
+ sqe3->mac_addr = cpu_to_le64(a_req->out_mac_dma);
+}
+
+static int sec_aead_bd_fill_v3(struct sec_ctx *ctx, struct sec_req *req)
+{
+ struct sec_auth_ctx *auth_ctx = &ctx->a_ctx;
+ struct sec_sqe3 *sec_sqe3 = &req->sec_sqe3;
+ int ret;
+
+ ret = sec_skcipher_bd_fill_v3(ctx, req);
+ if (unlikely(ret)) {
+ dev_err(ctx->dev, "skcipher bd3 fill is error!\n");
+ return ret;
+ }
+
+ if (ctx->c_ctx.c_mode == SEC_CMODE_CCM ||
+ ctx->c_ctx.c_mode == SEC_CMODE_GCM)
+ sec_auth_bd_fill_xcm_v3(auth_ctx, req->c_req.encrypt,
+ req, sec_sqe3);
+ else
+ sec_auth_bd_fill_ex_v3(auth_ctx, req->c_req.encrypt,
+ req, sec_sqe3);
return 0;
}
@@ -1254,7 +1731,8 @@ static int sec_process(struct sec_ctx *ctx, struct sec_req *req)
goto err_uninit_req;
/* Output IV as decrypto */
- if (ctx->c_ctx.c_mode == SEC_CMODE_CBC && !req->c_req.encrypt)
+ if (!req->c_req.encrypt && (ctx->c_ctx.c_mode == SEC_CMODE_CBC ||
+ ctx->c_ctx.c_mode == SEC_CMODE_CTR))
sec_update_iv(req, ctx->alg_type);
ret = ctx->req_op->bd_send(ctx, req);
@@ -1296,20 +1774,51 @@ static const struct sec_req_op sec_skcipher_req_ops = {
static const struct sec_req_op sec_aead_req_ops = {
.buf_map = sec_aead_sgl_map,
.buf_unmap = sec_aead_sgl_unmap,
- .do_transfer = sec_aead_copy_iv,
+ .do_transfer = sec_aead_set_iv,
.bd_fill = sec_aead_bd_fill,
.bd_send = sec_bd_send,
.callback = sec_aead_callback,
.process = sec_process,
};
+static const struct sec_req_op sec_skcipher_req_ops_v3 = {
+ .buf_map = sec_skcipher_sgl_map,
+ .buf_unmap = sec_skcipher_sgl_unmap,
+ .do_transfer = sec_skcipher_copy_iv,
+ .bd_fill = sec_skcipher_bd_fill_v3,
+ .bd_send = sec_bd_send,
+ .callback = sec_skcipher_callback,
+ .process = sec_process,
+};
+
+static const struct sec_req_op sec_aead_req_ops_v3 = {
+ .buf_map = sec_aead_sgl_map,
+ .buf_unmap = sec_aead_sgl_unmap,
+ .do_transfer = sec_aead_set_iv,
+ .bd_fill = sec_aead_bd_fill_v3,
+ .bd_send = sec_bd_send,
+ .callback = sec_aead_callback,
+ .process = sec_process,
+};
+
static int sec_skcipher_ctx_init(struct crypto_skcipher *tfm)
{
struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
+ int ret;
- ctx->req_op = &sec_skcipher_req_ops;
+ ret = sec_skcipher_init(tfm);
+ if (ret)
+ return ret;
- return sec_skcipher_init(tfm);
+ if (ctx->sec->qm.ver < QM_HW_V3) {
+ ctx->type_supported = SEC_BD_TYPE2;
+ ctx->req_op = &sec_skcipher_req_ops;
+ } else {
+ ctx->type_supported = SEC_BD_TYPE3;
+ ctx->req_op = &sec_skcipher_req_ops_v3;
+ }
+
+ return ret;
}
static void sec_skcipher_ctx_exit(struct crypto_skcipher *tfm)
@@ -1325,15 +1834,22 @@ static int sec_aead_init(struct crypto_aead *tfm)
crypto_aead_set_reqsize(tfm, sizeof(struct sec_req));
ctx->alg_type = SEC_AEAD;
ctx->c_ctx.ivsize = crypto_aead_ivsize(tfm);
- if (ctx->c_ctx.ivsize > SEC_IV_SIZE) {
- dev_err(ctx->dev, "get error aead iv size!\n");
+ if (ctx->c_ctx.ivsize < SEC_AIV_SIZE ||
+ ctx->c_ctx.ivsize > SEC_IV_SIZE) {
+ pr_err("get error aead iv size!\n");
return -EINVAL;
}
- ctx->req_op = &sec_aead_req_ops;
ret = sec_ctx_base_init(ctx);
if (ret)
return ret;
+ if (ctx->sec->qm.ver < QM_HW_V3) {
+ ctx->type_supported = SEC_BD_TYPE2;
+ ctx->req_op = &sec_aead_req_ops;
+ } else {
+ ctx->type_supported = SEC_BD_TYPE3;
+ ctx->req_op = &sec_aead_req_ops_v3;
+ }
ret = sec_auth_init(ctx);
if (ret)
@@ -1391,6 +1907,41 @@ static void sec_aead_ctx_exit(struct crypto_aead *tfm)
sec_aead_exit(tfm);
}
+static int sec_aead_xcm_ctx_init(struct crypto_aead *tfm)
+{
+ struct aead_alg *alg = crypto_aead_alg(tfm);
+ struct sec_ctx *ctx = crypto_aead_ctx(tfm);
+ struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+ const char *aead_name = alg->base.cra_name;
+ int ret;
+
+ ret = sec_aead_init(tfm);
+ if (ret) {
+ dev_err(ctx->dev, "hisi_sec2: aead xcm init error!\n");
+ return ret;
+ }
+
+ a_ctx->fallback_aead_tfm = crypto_alloc_aead(aead_name, 0,
+ CRYPTO_ALG_NEED_FALLBACK |
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(a_ctx->fallback_aead_tfm)) {
+ dev_err(ctx->dev, "aead driver alloc fallback tfm error!\n");
+ sec_aead_exit(tfm);
+ return PTR_ERR(a_ctx->fallback_aead_tfm);
+ }
+ a_ctx->fallback = false;
+
+ return 0;
+}
+
+static void sec_aead_xcm_ctx_exit(struct crypto_aead *tfm)
+{
+ struct sec_ctx *ctx = crypto_aead_ctx(tfm);
+
+ crypto_free_aead(ctx->a_ctx.fallback_aead_tfm);
+ sec_aead_exit(tfm);
+}
+
static int sec_aead_sha1_ctx_init(struct crypto_aead *tfm)
{
return sec_aead_ctx_init(tfm, "sha1");
@@ -1429,6 +1980,14 @@ static int sec_skcipher_cryptlen_ckeck(struct sec_ctx *ctx,
ret = -EINVAL;
}
break;
+ case SEC_CMODE_CFB:
+ case SEC_CMODE_OFB:
+ case SEC_CMODE_CTR:
+ if (unlikely(ctx->sec->qm.ver < QM_HW_V3)) {
+ dev_err(dev, "skcipher HW version error!\n");
+ ret = -EINVAL;
+ }
+ break;
default:
ret = -EINVAL;
}
@@ -1442,7 +2001,8 @@ static int sec_skcipher_param_check(struct sec_ctx *ctx, struct sec_req *sreq)
struct device *dev = ctx->dev;
u8 c_alg = ctx->c_ctx.c_alg;
- if (unlikely(!sk_req->src || !sk_req->dst)) {
+ if (unlikely(!sk_req->src || !sk_req->dst ||
+ sk_req->cryptlen > MAX_INPUT_DATA_LEN)) {
dev_err(dev, "skcipher input param error!\n");
return -EINVAL;
}
@@ -1468,6 +2028,37 @@ static int sec_skcipher_param_check(struct sec_ctx *ctx, struct sec_req *sreq)
return -EINVAL;
}
+static int sec_skcipher_soft_crypto(struct sec_ctx *ctx,
+ struct skcipher_request *sreq, bool encrypt)
+{
+ struct sec_cipher_ctx *c_ctx = &ctx->c_ctx;
+ struct device *dev = ctx->dev;
+ int ret;
+
+ SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, c_ctx->fbtfm);
+
+ if (!c_ctx->fbtfm) {
+ dev_err(dev, "failed to check fallback tfm\n");
+ return -EINVAL;
+ }
+
+ skcipher_request_set_sync_tfm(subreq, c_ctx->fbtfm);
+
+ /* software need sync mode to do crypto */
+ skcipher_request_set_callback(subreq, sreq->base.flags,
+ NULL, NULL);
+ skcipher_request_set_crypt(subreq, sreq->src, sreq->dst,
+ sreq->cryptlen, sreq->iv);
+ if (encrypt)
+ ret = crypto_skcipher_encrypt(subreq);
+ else
+ ret = crypto_skcipher_decrypt(subreq);
+
+ skcipher_request_zero(subreq);
+
+ return ret;
+}
+
static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(sk_req);
@@ -1475,8 +2066,11 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt)
struct sec_ctx *ctx = crypto_skcipher_ctx(tfm);
int ret;
- if (!sk_req->cryptlen)
+ if (!sk_req->cryptlen) {
+ if (ctx->c_ctx.c_mode == SEC_CMODE_XTS)
+ return -EINVAL;
return 0;
+ }
req->flag = sk_req->base.flags;
req->c_req.sk_req = sk_req;
@@ -1487,6 +2081,9 @@ static int sec_skcipher_crypto(struct skcipher_request *sk_req, bool encrypt)
if (unlikely(ret))
return -EINVAL;
+ if (unlikely(ctx->c_ctx.fallback))
+ return sec_skcipher_soft_crypto(ctx, sk_req, encrypt);
+
return ctx->req_op->process(ctx, req);
}
@@ -1507,7 +2104,9 @@ static int sec_skcipher_decrypt(struct skcipher_request *sk_req)
.cra_name = sec_cra_name,\
.cra_driver_name = "hisi_sec_"sec_cra_name,\
.cra_priority = SEC_PRIORITY,\
- .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY,\
+ .cra_flags = CRYPTO_ALG_ASYNC |\
+ CRYPTO_ALG_ALLOCATES_MEMORY |\
+ CRYPTO_ALG_NEED_FALLBACK,\
.cra_blocksize = blk_size,\
.cra_ctxsize = sizeof(struct sec_ctx),\
.cra_module = THIS_MODULE,\
@@ -1541,11 +2140,11 @@ static struct skcipher_alg sec_skciphers[] = {
AES_BLOCK_SIZE, AES_BLOCK_SIZE)
SEC_SKCIPHER_ALG("ecb(des3_ede)", sec_setkey_3des_ecb,
- SEC_DES3_2KEY_SIZE, SEC_DES3_3KEY_SIZE,
+ SEC_DES3_3KEY_SIZE, SEC_DES3_3KEY_SIZE,
DES3_EDE_BLOCK_SIZE, 0)
SEC_SKCIPHER_ALG("cbc(des3_ede)", sec_setkey_3des_cbc,
- SEC_DES3_2KEY_SIZE, SEC_DES3_3KEY_SIZE,
+ SEC_DES3_3KEY_SIZE, SEC_DES3_3KEY_SIZE,
DES3_EDE_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE)
SEC_SKCIPHER_ALG("xts(sm4)", sec_setkey_sm4_xts,
@@ -1557,6 +2156,90 @@ static struct skcipher_alg sec_skciphers[] = {
AES_BLOCK_SIZE, AES_BLOCK_SIZE)
};
+static struct skcipher_alg sec_skciphers_v3[] = {
+ SEC_SKCIPHER_ALG("ofb(aes)", sec_setkey_aes_ofb,
+ AES_MIN_KEY_SIZE, AES_MAX_KEY_SIZE,
+ SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE)
+
+ SEC_SKCIPHER_ALG("cfb(aes)", sec_setkey_aes_cfb,
+ AES_MIN_KEY_SIZE, AES_MAX_KEY_SIZE,
+ SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE)
+
+ SEC_SKCIPHER_ALG("ctr(aes)", sec_setkey_aes_ctr,
+ AES_MIN_KEY_SIZE, AES_MAX_KEY_SIZE,
+ SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE)
+
+ SEC_SKCIPHER_ALG("ofb(sm4)", sec_setkey_sm4_ofb,
+ AES_MIN_KEY_SIZE, AES_MIN_KEY_SIZE,
+ SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE)
+
+ SEC_SKCIPHER_ALG("cfb(sm4)", sec_setkey_sm4_cfb,
+ AES_MIN_KEY_SIZE, AES_MIN_KEY_SIZE,
+ SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE)
+
+ SEC_SKCIPHER_ALG("ctr(sm4)", sec_setkey_sm4_ctr,
+ AES_MIN_KEY_SIZE, AES_MIN_KEY_SIZE,
+ SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE)
+};
+
+static int aead_iv_demension_check(struct aead_request *aead_req)
+{
+ u8 cl;
+
+ cl = aead_req->iv[0] + 1;
+ if (cl < IV_CL_MIN || cl > IV_CL_MAX)
+ return -EINVAL;
+
+ if (cl < IV_CL_MID && aead_req->cryptlen >> (BYTE_BITS * cl))
+ return -EOVERFLOW;
+
+ return 0;
+}
+
+static int sec_aead_spec_check(struct sec_ctx *ctx, struct sec_req *sreq)
+{
+ struct aead_request *req = sreq->aead_req.aead_req;
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ size_t authsize = crypto_aead_authsize(tfm);
+ u8 c_mode = ctx->c_ctx.c_mode;
+ struct device *dev = ctx->dev;
+ int ret;
+
+ if (unlikely(req->cryptlen + req->assoclen > MAX_INPUT_DATA_LEN ||
+ req->assoclen > SEC_MAX_AAD_LEN)) {
+ dev_err(dev, "aead input spec error!\n");
+ return -EINVAL;
+ }
+
+ if (unlikely((c_mode == SEC_CMODE_GCM && authsize < DES_BLOCK_SIZE) ||
+ (c_mode == SEC_CMODE_CCM && (authsize < MIN_MAC_LEN ||
+ authsize & MAC_LEN_MASK)))) {
+ dev_err(dev, "aead input mac length error!\n");
+ return -EINVAL;
+ }
+
+ if (c_mode == SEC_CMODE_CCM) {
+ ret = aead_iv_demension_check(req);
+ if (ret) {
+ dev_err(dev, "aead input iv param error!\n");
+ return ret;
+ }
+ }
+
+ if (sreq->c_req.encrypt)
+ sreq->c_req.c_len = req->cryptlen;
+ else
+ sreq->c_req.c_len = req->cryptlen - authsize;
+ if (c_mode == SEC_CMODE_CBC) {
+ if (unlikely(sreq->c_req.c_len & (AES_BLOCK_SIZE - 1))) {
+ dev_err(dev, "aead crypto length error!\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int sec_aead_param_check(struct sec_ctx *ctx, struct sec_req *sreq)
{
struct aead_request *req = sreq->aead_req.aead_req;
@@ -1565,34 +2248,61 @@ static int sec_aead_param_check(struct sec_ctx *ctx, struct sec_req *sreq)
struct device *dev = ctx->dev;
u8 c_alg = ctx->c_ctx.c_alg;
- if (unlikely(!req->src || !req->dst || !req->cryptlen ||
- req->assoclen > SEC_MAX_AAD_LEN)) {
+ if (unlikely(!req->src || !req->dst)) {
dev_err(dev, "aead input param error!\n");
return -EINVAL;
}
+ if (ctx->sec->qm.ver == QM_HW_V2) {
+ if (unlikely(!req->cryptlen || (!sreq->c_req.encrypt &&
+ req->cryptlen <= authsize))) {
+ dev_err(dev, "Kunpeng920 not support 0 length!\n");
+ ctx->a_ctx.fallback = true;
+ return -EINVAL;
+ }
+ }
+
+ /* Support AES or SM4 */
+ if (unlikely(c_alg != SEC_CALG_AES && c_alg != SEC_CALG_SM4)) {
+ dev_err(dev, "aead crypto alg error!\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(sec_aead_spec_check(ctx, sreq)))
+ return -EINVAL;
+
if (ctx->pbuf_supported && (req->cryptlen + req->assoclen) <=
SEC_PBUF_SZ)
sreq->use_pbuf = true;
else
sreq->use_pbuf = false;
- /* Support AES only */
- if (unlikely(c_alg != SEC_CALG_AES)) {
- dev_err(dev, "aead crypto alg error!\n");
- return -EINVAL;
- }
- if (sreq->c_req.encrypt)
- sreq->c_req.c_len = req->cryptlen;
- else
- sreq->c_req.c_len = req->cryptlen - authsize;
+ return 0;
+}
- if (unlikely(sreq->c_req.c_len & (AES_BLOCK_SIZE - 1))) {
- dev_err(dev, "aead crypto length error!\n");
+static int sec_aead_soft_crypto(struct sec_ctx *ctx,
+ struct aead_request *aead_req,
+ bool encrypt)
+{
+ struct aead_request *subreq = aead_request_ctx(aead_req);
+ struct sec_auth_ctx *a_ctx = &ctx->a_ctx;
+ struct device *dev = ctx->dev;
+
+ /* Kunpeng920 aead mode not support input 0 size */
+ if (!a_ctx->fallback_aead_tfm) {
+ dev_err(dev, "aead fallback tfm is NULL!\n");
return -EINVAL;
}
- return 0;
+ aead_request_set_tfm(subreq, a_ctx->fallback_aead_tfm);
+ aead_request_set_callback(subreq, aead_req->base.flags,
+ aead_req->base.complete, aead_req->base.data);
+ aead_request_set_crypt(subreq, aead_req->src, aead_req->dst,
+ aead_req->cryptlen, aead_req->iv);
+ aead_request_set_ad(subreq, aead_req->assoclen);
+
+ return encrypt ? crypto_aead_encrypt(subreq) :
+ crypto_aead_decrypt(subreq);
}
static int sec_aead_crypto(struct aead_request *a_req, bool encrypt)
@@ -1608,8 +2318,11 @@ static int sec_aead_crypto(struct aead_request *a_req, bool encrypt)
req->ctx = ctx;
ret = sec_aead_param_check(ctx, req);
- if (unlikely(ret))
+ if (unlikely(ret)) {
+ if (ctx->a_ctx.fallback)
+ return sec_aead_soft_crypto(ctx, a_req, encrypt);
return -EINVAL;
+ }
return ctx->req_op->process(ctx, req);
}
@@ -1624,14 +2337,16 @@ static int sec_aead_decrypt(struct aead_request *a_req)
return sec_aead_crypto(a_req, false);
}
-#define SEC_AEAD_GEN_ALG(sec_cra_name, sec_set_key, ctx_init,\
+#define SEC_AEAD_ALG(sec_cra_name, sec_set_key, ctx_init,\
ctx_exit, blk_size, iv_size, max_authsize)\
{\
.base = {\
.cra_name = sec_cra_name,\
.cra_driver_name = "hisi_sec_"sec_cra_name,\
.cra_priority = SEC_PRIORITY,\
- .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY,\
+ .cra_flags = CRYPTO_ALG_ASYNC |\
+ CRYPTO_ALG_ALLOCATES_MEMORY |\
+ CRYPTO_ALG_NEED_FALLBACK,\
.cra_blocksize = blk_size,\
.cra_ctxsize = sizeof(struct sec_ctx),\
.cra_module = THIS_MODULE,\
@@ -1639,28 +2354,46 @@ static int sec_aead_decrypt(struct aead_request *a_req)
.init = ctx_init,\
.exit = ctx_exit,\
.setkey = sec_set_key,\
+ .setauthsize = sec_aead_setauthsize,\
.decrypt = sec_aead_decrypt,\
.encrypt = sec_aead_encrypt,\
.ivsize = iv_size,\
.maxauthsize = max_authsize,\
}
-#define SEC_AEAD_ALG(algname, keyfunc, aead_init, blksize, ivsize, authsize)\
- SEC_AEAD_GEN_ALG(algname, keyfunc, aead_init,\
- sec_aead_ctx_exit, blksize, ivsize, authsize)
-
static struct aead_alg sec_aeads[] = {
SEC_AEAD_ALG("authenc(hmac(sha1),cbc(aes))",
sec_setkey_aes_cbc_sha1, sec_aead_sha1_ctx_init,
- AES_BLOCK_SIZE, AES_BLOCK_SIZE, SHA1_DIGEST_SIZE),
+ sec_aead_ctx_exit, AES_BLOCK_SIZE,
+ AES_BLOCK_SIZE, SHA1_DIGEST_SIZE),
SEC_AEAD_ALG("authenc(hmac(sha256),cbc(aes))",
sec_setkey_aes_cbc_sha256, sec_aead_sha256_ctx_init,
- AES_BLOCK_SIZE, AES_BLOCK_SIZE, SHA256_DIGEST_SIZE),
+ sec_aead_ctx_exit, AES_BLOCK_SIZE,
+ AES_BLOCK_SIZE, SHA256_DIGEST_SIZE),
SEC_AEAD_ALG("authenc(hmac(sha512),cbc(aes))",
sec_setkey_aes_cbc_sha512, sec_aead_sha512_ctx_init,
- AES_BLOCK_SIZE, AES_BLOCK_SIZE, SHA512_DIGEST_SIZE),
+ sec_aead_ctx_exit, AES_BLOCK_SIZE,
+ AES_BLOCK_SIZE, SHA512_DIGEST_SIZE),
+
+ SEC_AEAD_ALG("ccm(aes)", sec_setkey_aes_ccm, sec_aead_xcm_ctx_init,
+ sec_aead_xcm_ctx_exit, SEC_MIN_BLOCK_SZ,
+ AES_BLOCK_SIZE, AES_BLOCK_SIZE),
+
+ SEC_AEAD_ALG("gcm(aes)", sec_setkey_aes_gcm, sec_aead_xcm_ctx_init,
+ sec_aead_xcm_ctx_exit, SEC_MIN_BLOCK_SZ,
+ SEC_AIV_SIZE, AES_BLOCK_SIZE)
+};
+
+static struct aead_alg sec_aeads_v3[] = {
+ SEC_AEAD_ALG("ccm(sm4)", sec_setkey_sm4_ccm, sec_aead_xcm_ctx_init,
+ sec_aead_xcm_ctx_exit, SEC_MIN_BLOCK_SZ,
+ AES_BLOCK_SIZE, AES_BLOCK_SIZE),
+
+ SEC_AEAD_ALG("gcm(sm4)", sec_setkey_sm4_gcm, sec_aead_xcm_ctx_init,
+ sec_aead_xcm_ctx_exit, SEC_MIN_BLOCK_SZ,
+ SEC_AIV_SIZE, AES_BLOCK_SIZE)
};
int sec_register_to_crypto(struct hisi_qm *qm)
@@ -1673,16 +2406,45 @@ int sec_register_to_crypto(struct hisi_qm *qm)
if (ret)
return ret;
+ if (qm->ver > QM_HW_V2) {
+ ret = crypto_register_skciphers(sec_skciphers_v3,
+ ARRAY_SIZE(sec_skciphers_v3));
+ if (ret)
+ goto reg_skcipher_fail;
+ }
+
ret = crypto_register_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
if (ret)
- crypto_unregister_skciphers(sec_skciphers,
- ARRAY_SIZE(sec_skciphers));
+ goto reg_aead_fail;
+ if (qm->ver > QM_HW_V2) {
+ ret = crypto_register_aeads(sec_aeads_v3, ARRAY_SIZE(sec_aeads_v3));
+ if (ret)
+ goto reg_aead_v3_fail;
+ }
+ return ret;
+
+reg_aead_v3_fail:
+ crypto_unregister_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
+reg_aead_fail:
+ if (qm->ver > QM_HW_V2)
+ crypto_unregister_skciphers(sec_skciphers_v3,
+ ARRAY_SIZE(sec_skciphers_v3));
+reg_skcipher_fail:
+ crypto_unregister_skciphers(sec_skciphers,
+ ARRAY_SIZE(sec_skciphers));
return ret;
}
void sec_unregister_from_crypto(struct hisi_qm *qm)
{
+ if (qm->ver > QM_HW_V2)
+ crypto_unregister_aeads(sec_aeads_v3,
+ ARRAY_SIZE(sec_aeads_v3));
+ crypto_unregister_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
+
+ if (qm->ver > QM_HW_V2)
+ crypto_unregister_skciphers(sec_skciphers_v3,
+ ARRAY_SIZE(sec_skciphers_v3));
crypto_unregister_skciphers(sec_skciphers,
ARRAY_SIZE(sec_skciphers));
- crypto_unregister_aeads(sec_aeads, ARRAY_SIZE(sec_aeads));
}
diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.h b/drivers/crypto/hisilicon/sec2/sec_crypto.h
index 9c78edac56a4..9f71c358a6d3 100644
--- a/drivers/crypto/hisilicon/sec2/sec_crypto.h
+++ b/drivers/crypto/hisilicon/sec2/sec_crypto.h
@@ -4,9 +4,11 @@
#ifndef __HISI_SEC_V2_CRYPTO_H
#define __HISI_SEC_V2_CRYPTO_H
+#define SEC_AIV_SIZE 12
#define SEC_IV_SIZE 24
#define SEC_MAX_KEY_SIZE 64
#define SEC_COMM_SCENE 0
+#define SEC_MIN_BLOCK_SZ 1
enum sec_calg {
SEC_CALG_3DES = 0x1,
@@ -21,6 +23,11 @@ enum sec_hash_alg {
};
enum sec_mac_len {
+ SEC_HMAC_CCM_MAC = 16,
+ SEC_HMAC_GCM_MAC = 16,
+ SEC_SM3_MAC = 32,
+ SEC_HMAC_SM3_MAC = 32,
+ SEC_HMAC_MD5_MAC = 16,
SEC_HMAC_SHA1_MAC = 20,
SEC_HMAC_SHA256_MAC = 32,
SEC_HMAC_SHA512_MAC = 64,
@@ -29,7 +36,11 @@ enum sec_mac_len {
enum sec_cmode {
SEC_CMODE_ECB = 0x0,
SEC_CMODE_CBC = 0x1,
+ SEC_CMODE_CFB = 0x2,
+ SEC_CMODE_OFB = 0x3,
SEC_CMODE_CTR = 0x4,
+ SEC_CMODE_CCM = 0x5,
+ SEC_CMODE_GCM = 0x6,
SEC_CMODE_XTS = 0x7,
};
@@ -44,6 +55,7 @@ enum sec_ckey_type {
enum sec_bd_type {
SEC_BD_TYPE1 = 0x1,
SEC_BD_TYPE2 = 0x2,
+ SEC_BD_TYPE3 = 0x3,
};
enum sec_auth {
@@ -63,6 +75,24 @@ enum sec_addr_type {
SEC_PRP = 0x2,
};
+struct bd_status {
+ u64 tag;
+ u8 done;
+ u8 err_type;
+ u16 flag;
+ u16 icv;
+};
+
+enum {
+ AUTHPAD_PAD,
+ AUTHPAD_NOPAD,
+};
+
+enum {
+ AIGEN_GEN,
+ AIGEN_NOGEN,
+};
+
struct sec_sqe_type2 {
/*
* mac_len: 0~4 bits
@@ -209,6 +239,169 @@ struct sec_sqe {
struct sec_sqe_type2 type2;
};
+struct bd3_auth_ivin {
+ __le64 a_ivin_addr;
+ __le32 rsvd0;
+ __le32 rsvd1;
+} __packed __aligned(4);
+
+struct bd3_skip_data {
+ __le32 rsvd0;
+
+ /*
+ * gran_num: 0~15 bits
+ * reserved: 16~31 bits
+ */
+ __le32 gran_num;
+
+ /*
+ * src_skip_data_len: 0~24 bits
+ * reserved: 25~31 bits
+ */
+ __le32 src_skip_data_len;
+
+ /*
+ * dst_skip_data_len: 0~24 bits
+ * reserved: 25~31 bits
+ */
+ __le32 dst_skip_data_len;
+};
+
+struct bd3_stream_scene {
+ __le64 c_ivin_addr;
+ __le64 long_a_data_len;
+
+ /*
+ * auth_pad: 0~1 bits
+ * stream_protocol: 2~4 bits
+ * reserved: 5~7 bits
+ */
+ __u8 stream_auth_pad;
+ __u8 plaintext_type;
+ __le16 pad_len_1p3;
+} __packed __aligned(4);
+
+struct bd3_no_scene {
+ __le64 c_ivin_addr;
+ __le32 rsvd0;
+ __le32 rsvd1;
+ __le32 rsvd2;
+} __packed __aligned(4);
+
+struct bd3_check_sum {
+ __u8 rsvd0;
+ __u8 hac_sva_status;
+ __le16 check_sum_i;
+};
+
+struct bd3_tls_type_back {
+ __u8 tls_1p3_type_back;
+ __u8 hac_sva_status;
+ __le16 pad_len_1p3_back;
+};
+
+struct sec_sqe3 {
+ /*
+ * type: 0~3 bit
+ * bd_invalid: 4 bit
+ * scene: 5~8 bit
+ * de: 9~10 bit
+ * src_addr_type: 11~13 bit
+ * dst_addr_type: 14~16 bit
+ * mac_addr_type: 17~19 bit
+ * reserved: 20~31 bits
+ */
+ __le32 bd_param;
+
+ /*
+ * cipher: 0~1 bits
+ * ci_gen: 2~3 bit
+ * c_icv_len: 4~9 bit
+ * c_width: 10~12 bits
+ * c_key_len: 13~15 bits
+ */
+ __le16 c_icv_key;
+
+ /*
+ * c_mode : 0~3 bits
+ * c_alg : 4~7 bits
+ */
+ __u8 c_mode_alg;
+
+ /*
+ * nonce_len : 0~3 bits
+ * huk : 4 bits
+ * cal_iv_addr_en : 5 bits
+ * seq : 6 bits
+ * reserved : 7 bits
+ */
+ __u8 huk_iv_seq;
+
+ __le64 tag;
+ __le64 data_src_addr;
+ __le64 a_key_addr;
+ union {
+ struct bd3_auth_ivin auth_ivin;
+ struct bd3_skip_data skip_data;
+ };
+
+ __le64 c_key_addr;
+
+ /*
+ * auth: 0~1 bits
+ * ai_gen: 2~3 bits
+ * mac_len: 4~8 bits
+ * akey_len: 9~14 bits
+ * a_alg: 15~20 bits
+ * key_sel: 21~24 bits
+ * updata_key: 25 bits
+ * reserved: 26~31 bits
+ */
+ __le32 auth_mac_key;
+ __le32 salt;
+ __le16 auth_src_offset;
+ __le16 cipher_src_offset;
+
+ /*
+ * auth_len: 0~23 bit
+ * auth_key_offset: 24~31 bits
+ */
+ __le32 a_len_key;
+
+ /*
+ * cipher_len: 0~23 bit
+ * auth_ivin_offset: 24~31 bits
+ */
+ __le32 c_len_ivin;
+ __le64 data_dst_addr;
+ __le64 mac_addr;
+ union {
+ struct bd3_stream_scene stream_scene;
+ struct bd3_no_scene no_scene;
+ };
+
+ /*
+ * done: 0 bit
+ * icv: 1~3 bit
+ * csc: 4~6 bit
+ * flag: 7~10 bit
+ * reserved: 11~15 bit
+ */
+ __le16 done_flag;
+ __u8 error_type;
+ __u8 warning_type;
+ union {
+ __le32 mac_i;
+ __le32 kek_key_addr_l;
+ };
+ union {
+ __le32 kek_key_addr_h;
+ struct bd3_check_sum check_sum;
+ struct bd3_tls_type_back tls_type_back;
+ };
+ __le32 counter;
+} __packed __aligned(4);
+
int sec_register_to_crypto(struct hisi_qm *qm);
void sec_unregister_from_crypto(struct hisi_qm *qm);
#endif
diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c
index 6f0062d4408c..490db7bccf61 100644
--- a/drivers/crypto/hisilicon/sec2/sec_main.c
+++ b/drivers/crypto/hisilicon/sec2/sec_main.c
@@ -52,6 +52,7 @@
#define SEC_RAS_CE_ENB_MSK 0x88
#define SEC_RAS_FE_ENB_MSK 0x0
#define SEC_RAS_NFE_ENB_MSK 0x7c177
+#define SEC_OOO_SHUTDOWN_SEL 0x301014
#define SEC_RAS_DISABLE 0x0
#define SEC_MEM_START_INIT_REG 0x301100
#define SEC_MEM_INIT_DONE_REG 0x301104
@@ -84,6 +85,12 @@
#define SEC_USER1_SMMU_MASK (~SEC_USER1_SVA_SET)
#define SEC_CORE_INT_STATUS_M_ECC BIT(2)
+#define SEC_PREFETCH_CFG 0x301130
+#define SEC_SVA_TRANS 0x301EC4
+#define SEC_PREFETCH_ENABLE (~(BIT(0) | BIT(1) | BIT(11)))
+#define SEC_PREFETCH_DISABLE BIT(1)
+#define SEC_SVA_DISABLE_READY (BIT(7) | BIT(11))
+
#define SEC_DELAY_10_US 10
#define SEC_POLL_TIMEOUT_US 1000
#define SEC_DBGFS_VAL_MAX_LEN 20
@@ -91,6 +98,7 @@
#define SEC_SQE_MASK_OFFSET 64
#define SEC_SQE_MASK_LEN 48
+#define SEC_SHAPER_TYPE_RATE 128
struct sec_hw_error {
u32 int_msk;
@@ -331,6 +339,45 @@ static u8 sec_get_endian(struct hisi_qm *qm)
return SEC_64BE;
}
+static void sec_open_sva_prefetch(struct hisi_qm *qm)
+{
+ u32 val;
+ int ret;
+
+ if (qm->ver < QM_HW_V3)
+ return;
+
+ /* Enable prefetch */
+ val = readl_relaxed(qm->io_base + SEC_PREFETCH_CFG);
+ val &= SEC_PREFETCH_ENABLE;
+ writel(val, qm->io_base + SEC_PREFETCH_CFG);
+
+ ret = readl_relaxed_poll_timeout(qm->io_base + SEC_PREFETCH_CFG,
+ val, !(val & SEC_PREFETCH_DISABLE),
+ SEC_DELAY_10_US, SEC_POLL_TIMEOUT_US);
+ if (ret)
+ pci_err(qm->pdev, "failed to open sva prefetch\n");
+}
+
+static void sec_close_sva_prefetch(struct hisi_qm *qm)
+{
+ u32 val;
+ int ret;
+
+ if (qm->ver < QM_HW_V3)
+ return;
+
+ val = readl_relaxed(qm->io_base + SEC_PREFETCH_CFG);
+ val |= SEC_PREFETCH_DISABLE;
+ writel(val, qm->io_base + SEC_PREFETCH_CFG);
+
+ ret = readl_relaxed_poll_timeout(qm->io_base + SEC_SVA_TRANS,
+ val, !(val & SEC_SVA_DISABLE_READY),
+ SEC_DELAY_10_US, SEC_POLL_TIMEOUT_US);
+ if (ret)
+ pci_err(qm->pdev, "failed to close sva prefetch\n");
+}
+
static int sec_engine_init(struct hisi_qm *qm)
{
int ret;
@@ -430,53 +477,60 @@ static void sec_debug_regs_clear(struct hisi_qm *qm)
hisi_qm_debug_regs_clear(qm);
}
-static void sec_hw_error_enable(struct hisi_qm *qm)
+static void sec_master_ooo_ctrl(struct hisi_qm *qm, bool enable)
{
- u32 val;
+ u32 val1, val2;
+
+ val1 = readl(qm->io_base + SEC_CONTROL_REG);
+ if (enable) {
+ val1 |= SEC_AXI_SHUTDOWN_ENABLE;
+ val2 = SEC_RAS_NFE_ENB_MSK;
+ } else {
+ val1 &= SEC_AXI_SHUTDOWN_DISABLE;
+ val2 = 0x0;
+ }
+
+ if (qm->ver > QM_HW_V2)
+ writel(val2, qm->io_base + SEC_OOO_SHUTDOWN_SEL);
+ writel(val1, qm->io_base + SEC_CONTROL_REG);
+}
+
+static void sec_hw_error_enable(struct hisi_qm *qm)
+{
if (qm->ver == QM_HW_V1) {
writel(SEC_CORE_INT_DISABLE, qm->io_base + SEC_CORE_INT_MASK);
pci_info(qm->pdev, "V1 not support hw error handle\n");
return;
}
- val = readl(qm->io_base + SEC_CONTROL_REG);
-
/* clear SEC hw error source if having */
writel(SEC_CORE_INT_CLEAR, qm->io_base + SEC_CORE_INT_SOURCE);
- /* enable SEC hw error interrupts */
- writel(SEC_CORE_INT_ENABLE, qm->io_base + SEC_CORE_INT_MASK);
-
/* enable RAS int */
writel(SEC_RAS_CE_ENB_MSK, qm->io_base + SEC_RAS_CE_REG);
writel(SEC_RAS_FE_ENB_MSK, qm->io_base + SEC_RAS_FE_REG);
writel(SEC_RAS_NFE_ENB_MSK, qm->io_base + SEC_RAS_NFE_REG);
- /* enable SEC block master OOO when m-bit error occur */
- val = val | SEC_AXI_SHUTDOWN_ENABLE;
+ /* enable SEC block master OOO when nfe occurs on Kunpeng930 */
+ sec_master_ooo_ctrl(qm, true);
- writel(val, qm->io_base + SEC_CONTROL_REG);
+ /* enable SEC hw error interrupts */
+ writel(SEC_CORE_INT_ENABLE, qm->io_base + SEC_CORE_INT_MASK);
}
static void sec_hw_error_disable(struct hisi_qm *qm)
{
- u32 val;
+ /* disable SEC hw error interrupts */
+ writel(SEC_CORE_INT_DISABLE, qm->io_base + SEC_CORE_INT_MASK);
- val = readl(qm->io_base + SEC_CONTROL_REG);
+ /* disable SEC block master OOO when nfe occurs on Kunpeng930 */
+ sec_master_ooo_ctrl(qm, false);
/* disable RAS int */
writel(SEC_RAS_DISABLE, qm->io_base + SEC_RAS_CE_REG);
writel(SEC_RAS_DISABLE, qm->io_base + SEC_RAS_FE_REG);
writel(SEC_RAS_DISABLE, qm->io_base + SEC_RAS_NFE_REG);
-
- /* disable SEC hw error interrupts */
- writel(SEC_CORE_INT_DISABLE, qm->io_base + SEC_CORE_INT_MASK);
-
- /* disable SEC block master OOO when m-bit error occur */
- val = val & SEC_AXI_SHUTDOWN_DISABLE;
-
- writel(val, qm->io_base + SEC_CONTROL_REG);
}
static u32 sec_clear_enable_read(struct sec_debug_file *file)
@@ -743,6 +797,8 @@ static const struct hisi_qm_err_ini sec_err_ini = {
.clear_dev_hw_err_status = sec_clear_hw_err_status,
.log_dev_hw_err = sec_log_hw_error,
.open_axi_master_ooo = sec_open_axi_master_ooo,
+ .open_sva_prefetch = sec_open_sva_prefetch,
+ .close_sva_prefetch = sec_close_sva_prefetch,
.err_info_init = sec_err_info_init,
};
@@ -758,6 +814,7 @@ static int sec_pf_probe_init(struct sec_dev *sec)
if (ret)
return ret;
+ sec_open_sva_prefetch(qm);
hisi_qm_dev_err_init(qm);
sec_debug_regs_clear(qm);
@@ -821,6 +878,7 @@ static void sec_qm_uninit(struct hisi_qm *qm)
static int sec_probe_init(struct sec_dev *sec)
{
+ u32 type_rate = SEC_SHAPER_TYPE_RATE;
struct hisi_qm *qm = &sec->qm;
int ret;
@@ -828,6 +886,11 @@ static int sec_probe_init(struct sec_dev *sec)
ret = sec_pf_probe_init(sec);
if (ret)
return ret;
+ /* enable shaper type 0 */
+ if (qm->ver >= QM_HW_V3) {
+ type_rate |= QM_SHAPER_ENABLE;
+ qm->type_rate = type_rate;
+ }
}
return 0;
diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c
index 2178b40e9f82..f8482ceebf2a 100644
--- a/drivers/crypto/hisilicon/zip/zip_main.c
+++ b/drivers/crypto/hisilicon/zip/zip_main.c
@@ -68,6 +68,7 @@
#define HZIP_CORE_INT_RAS_CE_ENABLE 0x1
#define HZIP_CORE_INT_RAS_NFE_ENB 0x301164
#define HZIP_CORE_INT_RAS_FE_ENB 0x301168
+#define HZIP_OOO_SHUTDOWN_SEL 0x30120C
#define HZIP_CORE_INT_RAS_NFE_ENABLE 0x1FFE
#define HZIP_SRAM_ECC_ERR_NUM_SHIFT 16
#define HZIP_SRAM_ECC_ERR_ADDR_SHIFT 24
@@ -96,6 +97,16 @@
#define HZIP_RD_CNT_CLR_CE_EN (HZIP_CNT_CLR_CE_EN | \
HZIP_RO_CNT_CLR_CE_EN)
+#define HZIP_PREFETCH_CFG 0x3011B0
+#define HZIP_SVA_TRANS 0x3011C4
+#define HZIP_PREFETCH_ENABLE (~(BIT(26) | BIT(17) | BIT(0)))
+#define HZIP_SVA_PREFETCH_DISABLE BIT(26)
+#define HZIP_SVA_DISABLE_READY (BIT(26) | BIT(30))
+#define HZIP_SHAPER_RATE_COMPRESS 252
+#define HZIP_SHAPER_RATE_DECOMPRESS 229
+#define HZIP_DELAY_1_US 1
+#define HZIP_POLL_TIMEOUT_US 1000
+
static const char hisi_zip_name[] = "hisi_zip";
static struct dentry *hzip_debugfs_root;
@@ -262,6 +273,45 @@ int zip_create_qps(struct hisi_qp **qps, int qp_num, int node)
return hisi_qm_alloc_qps_node(&zip_devices, qp_num, 0, node, qps);
}
+static void hisi_zip_open_sva_prefetch(struct hisi_qm *qm)
+{
+ u32 val;
+ int ret;
+
+ if (qm->ver < QM_HW_V3)
+ return;
+
+ /* Enable prefetch */
+ val = readl_relaxed(qm->io_base + HZIP_PREFETCH_CFG);
+ val &= HZIP_PREFETCH_ENABLE;
+ writel(val, qm->io_base + HZIP_PREFETCH_CFG);
+
+ ret = readl_relaxed_poll_timeout(qm->io_base + HZIP_PREFETCH_CFG,
+ val, !(val & HZIP_SVA_PREFETCH_DISABLE),
+ HZIP_DELAY_1_US, HZIP_POLL_TIMEOUT_US);
+ if (ret)
+ pci_err(qm->pdev, "failed to open sva prefetch\n");
+}
+
+static void hisi_zip_close_sva_prefetch(struct hisi_qm *qm)
+{
+ u32 val;
+ int ret;
+
+ if (qm->ver < QM_HW_V3)
+ return;
+
+ val = readl_relaxed(qm->io_base + HZIP_PREFETCH_CFG);
+ val |= HZIP_SVA_PREFETCH_DISABLE;
+ writel(val, qm->io_base + HZIP_PREFETCH_CFG);
+
+ ret = readl_relaxed_poll_timeout(qm->io_base + HZIP_SVA_TRANS,
+ val, !(val & HZIP_SVA_DISABLE_READY),
+ HZIP_DELAY_1_US, HZIP_POLL_TIMEOUT_US);
+ if (ret)
+ pci_err(qm->pdev, "failed to close sva prefetch\n");
+}
+
static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm)
{
void __iomem *base = qm->io_base;
@@ -312,10 +362,27 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm)
return 0;
}
-static void hisi_zip_hw_error_enable(struct hisi_qm *qm)
+static void hisi_zip_master_ooo_ctrl(struct hisi_qm *qm, bool enable)
{
- u32 val;
+ u32 val1, val2;
+
+ val1 = readl(qm->io_base + HZIP_SOFT_CTRL_ZIP_CONTROL);
+ if (enable) {
+ val1 |= HZIP_AXI_SHUTDOWN_ENABLE;
+ val2 = HZIP_CORE_INT_RAS_NFE_ENABLE;
+ } else {
+ val1 &= ~HZIP_AXI_SHUTDOWN_ENABLE;
+ val2 = 0x0;
+ }
+
+ if (qm->ver > QM_HW_V2)
+ writel(val2, qm->io_base + HZIP_OOO_SHUTDOWN_SEL);
+ writel(val1, qm->io_base + HZIP_SOFT_CTRL_ZIP_CONTROL);
+}
+
+static void hisi_zip_hw_error_enable(struct hisi_qm *qm)
+{
if (qm->ver == QM_HW_V1) {
writel(HZIP_CORE_INT_MASK_ALL,
qm->io_base + HZIP_CORE_INT_MASK_REG);
@@ -333,26 +400,20 @@ static void hisi_zip_hw_error_enable(struct hisi_qm *qm)
writel(HZIP_CORE_INT_RAS_NFE_ENABLE,
qm->io_base + HZIP_CORE_INT_RAS_NFE_ENB);
+ /* enable ZIP block master OOO when nfe occurs on Kunpeng930 */
+ hisi_zip_master_ooo_ctrl(qm, true);
+
/* enable ZIP hw error interrupts */
writel(0, qm->io_base + HZIP_CORE_INT_MASK_REG);
-
- /* enable ZIP block master OOO when m-bit error occur */
- val = readl(qm->io_base + HZIP_SOFT_CTRL_ZIP_CONTROL);
- val = val | HZIP_AXI_SHUTDOWN_ENABLE;
- writel(val, qm->io_base + HZIP_SOFT_CTRL_ZIP_CONTROL);
}
static void hisi_zip_hw_error_disable(struct hisi_qm *qm)
{
- u32 val;
-
/* disable ZIP hw error interrupts */
writel(HZIP_CORE_INT_MASK_ALL, qm->io_base + HZIP_CORE_INT_MASK_REG);
- /* disable ZIP block master OOO when m-bit error occur */
- val = readl(qm->io_base + HZIP_SOFT_CTRL_ZIP_CONTROL);
- val = val & ~HZIP_AXI_SHUTDOWN_ENABLE;
- writel(val, qm->io_base + HZIP_SOFT_CTRL_ZIP_CONTROL);
+ /* disable ZIP block master OOO when nfe occurs on Kunpeng930 */
+ hisi_zip_master_ooo_ctrl(qm, false);
}
static inline struct hisi_qm *file_to_qm(struct ctrl_debug_file *file)
@@ -684,6 +745,8 @@ static const struct hisi_qm_err_ini hisi_zip_err_ini = {
.log_dev_hw_err = hisi_zip_log_hw_error,
.open_axi_master_ooo = hisi_zip_open_axi_master_ooo,
.close_axi_master_ooo = hisi_zip_close_axi_master_ooo,
+ .open_sva_prefetch = hisi_zip_open_sva_prefetch,
+ .close_sva_prefetch = hisi_zip_close_sva_prefetch,
.err_info_init = hisi_zip_err_info_init,
};
@@ -702,6 +765,7 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip)
qm->err_ini->err_info_init(qm);
hisi_zip_set_user_domain_and_cache(qm);
+ hisi_zip_open_sva_prefetch(qm);
hisi_qm_dev_err_init(qm);
hisi_zip_debug_regs_clear(qm);
@@ -761,6 +825,7 @@ static void hisi_zip_qm_uninit(struct hisi_qm *qm)
static int hisi_zip_probe_init(struct hisi_zip *hisi_zip)
{
+ u32 type_rate = HZIP_SHAPER_RATE_COMPRESS;
struct hisi_qm *qm = &hisi_zip->qm;
int ret;
@@ -768,6 +833,14 @@ static int hisi_zip_probe_init(struct hisi_zip *hisi_zip)
ret = hisi_zip_pf_probe_init(hisi_zip);
if (ret)
return ret;
+ /* enable shaper type 0 */
+ if (qm->ver >= QM_HW_V3) {
+ type_rate |= QM_SHAPER_ENABLE;
+
+ /* ZIP need to enable shaper type 1 */
+ type_rate |= HZIP_SHAPER_RATE_DECOMPRESS << QM_SHAPER_TYPE1_OFFSET;
+ qm->type_rate = type_rate;
+ }
}
return 0;
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
index 0616e369522e..98730aab287c 100644
--- a/drivers/crypto/ixp4xx_crypto.c
+++ b/drivers/crypto/ixp4xx_crypto.c
@@ -15,6 +15,7 @@
#include <linux/spinlock.h>
#include <linux/gfp.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <crypto/ctr.h>
#include <crypto/internal/des.h>
@@ -30,6 +31,10 @@
#include <linux/soc/ixp4xx/npe.h>
#include <linux/soc/ixp4xx/qmgr.h>
+/* Intermittent includes, delete this after v5.14-rc1 */
+#include <linux/soc/ixp4xx/cpu.h>
+#include <mach/ixp4xx-regs.h>
+
#define MAX_KEYLEN 32
/* hash: cfgword + 2 * digestlen; crypt: keylen + cfgword */
@@ -71,15 +76,11 @@
#define MOD_AES256 (0x0a00 | KEYLEN_256)
#define MAX_IVLEN 16
-#define NPE_ID 2 /* NPE C */
#define NPE_QLEN 16
/* Space for registering when the first
* NPE_QLEN crypt_ctl are busy */
#define NPE_QLEN_TOTAL 64
-#define SEND_QID 29
-#define RECV_QID 30
-
#define CTL_FLAG_UNUSED 0x0000
#define CTL_FLAG_USED 0x1000
#define CTL_FLAG_PERFORM_ABLK 0x0001
@@ -136,7 +137,7 @@ struct crypt_ctl {
u32 crypto_ctx; /* NPE Crypto Param structure address */
/* Used by Host: 4*4 bytes*/
- unsigned ctl_flags;
+ unsigned int ctl_flags;
union {
struct skcipher_request *ablk_req;
struct aead_request *aead_req;
@@ -149,6 +150,9 @@ struct crypt_ctl {
struct ablk_ctx {
struct buffer_desc *src;
struct buffer_desc *dst;
+ u8 iv[MAX_IVLEN];
+ bool encrypt;
+ struct skcipher_request fallback_req; // keep at the end
};
struct aead_ctx {
@@ -181,9 +185,10 @@ struct ixp_ctx {
u8 enckey[MAX_KEYLEN];
u8 salt[MAX_IVLEN];
u8 nonce[CTR_RFC3686_NONCE_SIZE];
- unsigned salted;
+ unsigned int salted;
atomic_t configuring;
struct completion completion;
+ struct crypto_skcipher *fallback_tfm;
};
struct ixp_alg {
@@ -209,6 +214,7 @@ static const struct ix_hash_algo hash_alg_md5 = {
.icv = "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
"\xFE\xDC\xBA\x98\x76\x54\x32\x10",
};
+
static const struct ix_hash_algo hash_alg_sha1 = {
.cfgword = 0x00000005,
.icv = "\x67\x45\x23\x01\xEF\xCD\xAB\x89\x98\xBA"
@@ -216,16 +222,17 @@ static const struct ix_hash_algo hash_alg_sha1 = {
};
static struct npe *npe_c;
-static struct dma_pool *buffer_pool = NULL;
-static struct dma_pool *ctx_pool = NULL;
-static struct crypt_ctl *crypt_virt = NULL;
+static unsigned int send_qid;
+static unsigned int recv_qid;
+static struct dma_pool *buffer_pool;
+static struct dma_pool *ctx_pool;
+
+static struct crypt_ctl *crypt_virt;
static dma_addr_t crypt_phys;
static int support_aes = 1;
-#define DRIVER_NAME "ixp4xx_crypto"
-
static struct platform_device *pdev;
static inline dma_addr_t crypt_virt2phys(struct crypt_ctl *virt)
@@ -240,12 +247,12 @@ static inline struct crypt_ctl *crypt_phys2virt(dma_addr_t phys)
static inline u32 cipher_cfg_enc(struct crypto_tfm *tfm)
{
- return container_of(tfm->__crt_alg, struct ixp_alg,crypto.base)->cfg_enc;
+ return container_of(tfm->__crt_alg, struct ixp_alg, crypto.base)->cfg_enc;
}
static inline u32 cipher_cfg_dec(struct crypto_tfm *tfm)
{
- return container_of(tfm->__crt_alg, struct ixp_alg,crypto.base)->cfg_dec;
+ return container_of(tfm->__crt_alg, struct ixp_alg, crypto.base)->cfg_dec;
}
static inline const struct ix_hash_algo *ix_hash(struct crypto_tfm *tfm)
@@ -256,6 +263,7 @@ static inline const struct ix_hash_algo *ix_hash(struct crypto_tfm *tfm)
static int setup_crypt_desc(void)
{
struct device *dev = &pdev->dev;
+
BUILD_BUG_ON(sizeof(struct crypt_ctl) != 64);
crypt_virt = dma_alloc_coherent(dev,
NPE_QLEN * sizeof(struct crypt_ctl),
@@ -269,7 +277,7 @@ static DEFINE_SPINLOCK(desc_lock);
static struct crypt_ctl *get_crypt_desc(void)
{
int i;
- static int idx = 0;
+ static int idx;
unsigned long flags;
spin_lock_irqsave(&desc_lock, flags);
@@ -286,7 +294,7 @@ static struct crypt_ctl *get_crypt_desc(void)
idx = 0;
crypt_virt[i].ctl_flags = CTL_FLAG_USED;
spin_unlock_irqrestore(&desc_lock, flags);
- return crypt_virt +i;
+ return crypt_virt + i;
} else {
spin_unlock_irqrestore(&desc_lock, flags);
return NULL;
@@ -314,7 +322,7 @@ static struct crypt_ctl *get_crypt_desc_emerg(void)
idx = NPE_QLEN;
crypt_virt[i].ctl_flags = CTL_FLAG_USED;
spin_unlock_irqrestore(&emerg_lock, flags);
- return crypt_virt +i;
+ return crypt_virt + i;
} else {
spin_unlock_irqrestore(&emerg_lock, flags);
return NULL;
@@ -330,7 +338,7 @@ static void free_buf_chain(struct device *dev, struct buffer_desc *buf,
buf1 = buf->next;
phys1 = buf->phys_next;
- dma_unmap_single(dev, buf->phys_next, buf->buf_len, buf->dir);
+ dma_unmap_single(dev, buf->phys_addr, buf->buf_len, buf->dir);
dma_pool_free(buffer_pool, buf, phys);
buf = buf1;
phys = phys1;
@@ -348,8 +356,8 @@ static void finish_scattered_hmac(struct crypt_ctl *crypt)
int decryptlen = req->assoclen + req->cryptlen - authsize;
if (req_ctx->encrypt) {
- scatterwalk_map_and_copy(req_ctx->hmac_virt,
- req->dst, decryptlen, authsize, 1);
+ scatterwalk_map_and_copy(req_ctx->hmac_virt, req->dst,
+ decryptlen, authsize, 1);
}
dma_pool_free(buffer_pool, req_ctx->hmac_virt, crypt->icv_rev_aes);
}
@@ -372,19 +380,33 @@ static void one_packet(dma_addr_t phys)
free_buf_chain(dev, req_ctx->src, crypt->src_buf);
free_buf_chain(dev, req_ctx->dst, crypt->dst_buf);
- if (req_ctx->hmac_virt) {
+ if (req_ctx->hmac_virt)
finish_scattered_hmac(crypt);
- }
+
req->base.complete(&req->base, failed);
break;
}
case CTL_FLAG_PERFORM_ABLK: {
struct skcipher_request *req = crypt->data.ablk_req;
struct ablk_ctx *req_ctx = skcipher_request_ctx(req);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ unsigned int ivsize = crypto_skcipher_ivsize(tfm);
+ unsigned int offset;
+
+ if (ivsize > 0) {
+ offset = req->cryptlen - ivsize;
+ if (req_ctx->encrypt) {
+ scatterwalk_map_and_copy(req->iv, req->dst,
+ offset, ivsize, 0);
+ } else {
+ memcpy(req->iv, req_ctx->iv, ivsize);
+ memzero_explicit(req_ctx->iv, ivsize);
+ }
+ }
- if (req_ctx->dst) {
+ if (req_ctx->dst)
free_buf_chain(dev, req_ctx->dst, crypt->dst_buf);
- }
+
free_buf_chain(dev, req_ctx->src, crypt->src_buf);
req->base.complete(&req->base, failed);
break;
@@ -392,14 +414,14 @@ static void one_packet(dma_addr_t phys)
case CTL_FLAG_GEN_ICV:
ctx = crypto_tfm_ctx(crypt->data.tfm);
dma_pool_free(ctx_pool, crypt->regist_ptr,
- crypt->regist_buf->phys_addr);
+ crypt->regist_buf->phys_addr);
dma_pool_free(buffer_pool, crypt->regist_buf, crypt->src_buf);
if (atomic_dec_and_test(&ctx->configuring))
complete(&ctx->completion);
break;
case CTL_FLAG_GEN_REVAES:
ctx = crypto_tfm_ctx(crypt->data.tfm);
- *(u32*)ctx->decrypt.npe_ctx &= cpu_to_be32(~CIPH_ENCR);
+ *(u32 *)ctx->decrypt.npe_ctx &= cpu_to_be32(~CIPH_ENCR);
if (atomic_dec_and_test(&ctx->configuring))
complete(&ctx->completion);
break;
@@ -418,8 +440,8 @@ static void crypto_done_action(unsigned long arg)
{
int i;
- for(i=0; i<4; i++) {
- dma_addr_t phys = qmgr_get_entry(RECV_QID);
+ for (i = 0; i < 4; i++) {
+ dma_addr_t phys = qmgr_get_entry(recv_qid);
if (!phys)
return;
one_packet(phys);
@@ -429,15 +451,52 @@ static void crypto_done_action(unsigned long arg)
static int init_ixp_crypto(struct device *dev)
{
- int ret = -ENODEV;
+ struct device_node *np = dev->of_node;
u32 msg[2] = { 0, 0 };
+ int ret = -ENODEV;
+ u32 npe_id;
- if (! ( ~(*IXP4XX_EXP_CFG2) & (IXP4XX_FEATURE_HASH |
- IXP4XX_FEATURE_AES | IXP4XX_FEATURE_DES))) {
- printk(KERN_ERR "ixp_crypto: No HW crypto available\n");
- return ret;
+ dev_info(dev, "probing...\n");
+
+ /* Locate the NPE and queue manager to use from device tree */
+ if (IS_ENABLED(CONFIG_OF) && np) {
+ struct of_phandle_args queue_spec;
+ struct of_phandle_args npe_spec;
+
+ ret = of_parse_phandle_with_fixed_args(np, "intel,npe-handle",
+ 1, 0, &npe_spec);
+ if (ret) {
+ dev_err(dev, "no NPE engine specified\n");
+ return -ENODEV;
+ }
+ npe_id = npe_spec.args[0];
+
+ ret = of_parse_phandle_with_fixed_args(np, "queue-rx", 1, 0,
+ &queue_spec);
+ if (ret) {
+ dev_err(dev, "no rx queue phandle\n");
+ return -ENODEV;
+ }
+ recv_qid = queue_spec.args[0];
+
+ ret = of_parse_phandle_with_fixed_args(np, "queue-txready", 1, 0,
+ &queue_spec);
+ if (ret) {
+ dev_err(dev, "no txready queue phandle\n");
+ return -ENODEV;
+ }
+ send_qid = queue_spec.args[0];
+ } else {
+ /*
+ * Hardcoded engine when using platform data, this goes away
+ * when we switch to using DT only.
+ */
+ npe_id = 2;
+ send_qid = 29;
+ recv_qid = 30;
}
- npe_c = npe_request(NPE_ID);
+
+ npe_c = npe_request(npe_id);
if (!npe_c)
return ret;
@@ -455,10 +514,9 @@ static int init_ixp_crypto(struct device *dev)
goto npe_error;
}
- switch ((msg[1]>>16) & 0xff) {
+ switch ((msg[1] >> 16) & 0xff) {
case 3:
- printk(KERN_WARNING "Firmware of %s lacks AES support\n",
- npe_name(npe_c));
+ dev_warn(dev, "Firmware of %s lacks AES support\n", npe_name(npe_c));
support_aes = 0;
break;
case 4:
@@ -466,8 +524,7 @@ static int init_ixp_crypto(struct device *dev)
support_aes = 1;
break;
default:
- printk(KERN_ERR "Firmware of %s lacks crypto support\n",
- npe_name(npe_c));
+ dev_err(dev, "Firmware of %s lacks crypto support\n", npe_name(npe_c));
ret = -ENODEV;
goto npe_release;
}
@@ -475,35 +532,34 @@ static int init_ixp_crypto(struct device *dev)
* so assure it is large enough
*/
BUILD_BUG_ON(SHA1_DIGEST_SIZE > sizeof(struct buffer_desc));
- buffer_pool = dma_pool_create("buffer", dev,
- sizeof(struct buffer_desc), 32, 0);
+ buffer_pool = dma_pool_create("buffer", dev, sizeof(struct buffer_desc),
+ 32, 0);
ret = -ENOMEM;
- if (!buffer_pool) {
+ if (!buffer_pool)
goto err;
- }
- ctx_pool = dma_pool_create("context", dev,
- NPE_CTX_LEN, 16, 0);
- if (!ctx_pool) {
+
+ ctx_pool = dma_pool_create("context", dev, NPE_CTX_LEN, 16, 0);
+ if (!ctx_pool)
goto err;
- }
- ret = qmgr_request_queue(SEND_QID, NPE_QLEN_TOTAL, 0, 0,
+
+ ret = qmgr_request_queue(send_qid, NPE_QLEN_TOTAL, 0, 0,
"ixp_crypto:out", NULL);
if (ret)
goto err;
- ret = qmgr_request_queue(RECV_QID, NPE_QLEN, 0, 0,
+ ret = qmgr_request_queue(recv_qid, NPE_QLEN, 0, 0,
"ixp_crypto:in", NULL);
if (ret) {
- qmgr_release_queue(SEND_QID);
+ qmgr_release_queue(send_qid);
goto err;
}
- qmgr_set_irq(RECV_QID, QUEUE_IRQ_SRC_NOT_EMPTY, irqhandler, NULL);
+ qmgr_set_irq(recv_qid, QUEUE_IRQ_SRC_NOT_EMPTY, irqhandler, NULL);
tasklet_init(&crypto_done_tasklet, crypto_done_action, 0);
- qmgr_enable_irq(RECV_QID);
+ qmgr_enable_irq(recv_qid);
return 0;
npe_error:
- printk(KERN_ERR "%s not responding\n", npe_name(npe_c));
+ dev_err(dev, "%s not responding\n", npe_name(npe_c));
ret = -EIO;
err:
dma_pool_destroy(ctx_pool);
@@ -515,22 +571,20 @@ npe_release:
static void release_ixp_crypto(struct device *dev)
{
- qmgr_disable_irq(RECV_QID);
+ qmgr_disable_irq(recv_qid);
tasklet_kill(&crypto_done_tasklet);
- qmgr_release_queue(SEND_QID);
- qmgr_release_queue(RECV_QID);
+ qmgr_release_queue(send_qid);
+ qmgr_release_queue(recv_qid);
dma_pool_destroy(ctx_pool);
dma_pool_destroy(buffer_pool);
npe_release(npe_c);
- if (crypt_virt) {
- dma_free_coherent(dev,
- NPE_QLEN * sizeof(struct crypt_ctl),
- crypt_virt, crypt_phys);
- }
+ if (crypt_virt)
+ dma_free_coherent(dev, NPE_QLEN * sizeof(struct crypt_ctl),
+ crypt_virt, crypt_phys);
}
static void reset_sa_dir(struct ix_sa_dir *dir)
@@ -543,9 +597,9 @@ static void reset_sa_dir(struct ix_sa_dir *dir)
static int init_sa_dir(struct ix_sa_dir *dir)
{
dir->npe_ctx = dma_pool_alloc(ctx_pool, GFP_KERNEL, &dir->npe_ctx_phys);
- if (!dir->npe_ctx) {
+ if (!dir->npe_ctx)
return -ENOMEM;
- }
+
reset_sa_dir(dir);
return 0;
}
@@ -566,15 +620,31 @@ static int init_tfm(struct crypto_tfm *tfm)
if (ret)
return ret;
ret = init_sa_dir(&ctx->decrypt);
- if (ret) {
+ if (ret)
free_sa_dir(&ctx->encrypt);
- }
+
return ret;
}
static int init_tfm_ablk(struct crypto_skcipher *tfm)
{
- crypto_skcipher_set_reqsize(tfm, sizeof(struct ablk_ctx));
+ struct crypto_tfm *ctfm = crypto_skcipher_tfm(tfm);
+ struct ixp_ctx *ctx = crypto_tfm_ctx(ctfm);
+ const char *name = crypto_tfm_alg_name(ctfm);
+
+ ctx->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(ctx->fallback_tfm)) {
+ pr_err("ERROR: Cannot allocate fallback for %s %ld\n",
+ name, PTR_ERR(ctx->fallback_tfm));
+ return PTR_ERR(ctx->fallback_tfm);
+ }
+
+ pr_info("Fallback for %s is %s\n",
+ crypto_tfm_alg_driver_name(&tfm->base),
+ crypto_tfm_alg_driver_name(crypto_skcipher_tfm(ctx->fallback_tfm))
+ );
+
+ crypto_skcipher_set_reqsize(tfm, sizeof(struct ablk_ctx) + crypto_skcipher_reqsize(ctx->fallback_tfm));
return init_tfm(crypto_skcipher_tfm(tfm));
}
@@ -587,12 +657,17 @@ static int init_tfm_aead(struct crypto_aead *tfm)
static void exit_tfm(struct crypto_tfm *tfm)
{
struct ixp_ctx *ctx = crypto_tfm_ctx(tfm);
+
free_sa_dir(&ctx->encrypt);
free_sa_dir(&ctx->decrypt);
}
static void exit_tfm_ablk(struct crypto_skcipher *tfm)
{
+ struct crypto_tfm *ctfm = crypto_skcipher_tfm(tfm);
+ struct ixp_ctx *ctx = crypto_tfm_ctx(ctfm);
+
+ crypto_free_skcipher(ctx->fallback_tfm);
exit_tfm(crypto_skcipher_tfm(tfm));
}
@@ -602,7 +677,8 @@ static void exit_tfm_aead(struct crypto_aead *tfm)
}
static int register_chain_var(struct crypto_tfm *tfm, u8 xpad, u32 target,
- int init_len, u32 ctx_addr, const u8 *key, int key_len)
+ int init_len, u32 ctx_addr, const u8 *key,
+ int key_len)
{
struct ixp_ctx *ctx = crypto_tfm_ctx(tfm);
struct crypt_ctl *crypt;
@@ -629,9 +705,8 @@ static int register_chain_var(struct crypto_tfm *tfm, u8 xpad, u32 target,
memcpy(pad, key, key_len);
memset(pad + key_len, 0, HMAC_PAD_BLOCKLEN - key_len);
- for (i = 0; i < HMAC_PAD_BLOCKLEN; i++) {
+ for (i = 0; i < HMAC_PAD_BLOCKLEN; i++)
pad[i] ^= xpad;
- }
crypt->data.tfm = tfm;
crypt->regist_ptr = pad;
@@ -652,13 +727,13 @@ static int register_chain_var(struct crypto_tfm *tfm, u8 xpad, u32 target,
buf->phys_addr = pad_phys;
atomic_inc(&ctx->configuring);
- qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
- BUG_ON(qmgr_stat_overflow(SEND_QID));
+ qmgr_put_entry(send_qid, crypt_virt2phys(crypt));
+ BUG_ON(qmgr_stat_overflow(send_qid));
return 0;
}
-static int setup_auth(struct crypto_tfm *tfm, int encrypt, unsigned authsize,
- const u8 *key, int key_len, unsigned digest_len)
+static int setup_auth(struct crypto_tfm *tfm, int encrypt, unsigned int authsize,
+ const u8 *key, int key_len, unsigned int digest_len)
{
u32 itarget, otarget, npe_ctx_addr;
unsigned char *cinfo;
@@ -673,11 +748,11 @@ static int setup_auth(struct crypto_tfm *tfm, int encrypt, unsigned authsize,
algo = ix_hash(tfm);
/* write cfg word to cryptinfo */
- cfgword = algo->cfgword | ( authsize << 6); /* (authsize/4) << 8 */
+ cfgword = algo->cfgword | (authsize << 6); /* (authsize/4) << 8 */
#ifndef __ARMEB__
cfgword ^= 0xAA000000; /* change the "byte swap" flags */
#endif
- *(u32*)cinfo = cpu_to_be32(cfgword);
+ *(u32 *)cinfo = cpu_to_be32(cfgword);
cinfo += sizeof(cfgword);
/* write ICV to cryptinfo */
@@ -697,11 +772,11 @@ static int setup_auth(struct crypto_tfm *tfm, int encrypt, unsigned authsize,
dir->npe_mode |= NPE_OP_HASH_VERIFY;
ret = register_chain_var(tfm, HMAC_OPAD_VALUE, otarget,
- init_len, npe_ctx_addr, key, key_len);
+ init_len, npe_ctx_addr, key, key_len);
if (ret)
return ret;
return register_chain_var(tfm, HMAC_IPAD_VALUE, itarget,
- init_len, npe_ctx_addr, key, key_len);
+ init_len, npe_ctx_addr, key, key_len);
}
static int gen_rev_aes_key(struct crypto_tfm *tfm)
@@ -711,10 +786,10 @@ static int gen_rev_aes_key(struct crypto_tfm *tfm)
struct ix_sa_dir *dir = &ctx->decrypt;
crypt = get_crypt_desc_emerg();
- if (!crypt) {
+ if (!crypt)
return -EAGAIN;
- }
- *(u32*)dir->npe_ctx |= cpu_to_be32(CIPH_ENCR);
+
+ *(u32 *)dir->npe_ctx |= cpu_to_be32(CIPH_ENCR);
crypt->data.tfm = tfm;
crypt->crypt_offs = 0;
@@ -727,13 +802,13 @@ static int gen_rev_aes_key(struct crypto_tfm *tfm)
crypt->ctl_flags |= CTL_FLAG_GEN_REVAES;
atomic_inc(&ctx->configuring);
- qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
- BUG_ON(qmgr_stat_overflow(SEND_QID));
+ qmgr_put_entry(send_qid, crypt_virt2phys(crypt));
+ BUG_ON(qmgr_stat_overflow(send_qid));
return 0;
}
-static int setup_cipher(struct crypto_tfm *tfm, int encrypt,
- const u8 *key, int key_len)
+static int setup_cipher(struct crypto_tfm *tfm, int encrypt, const u8 *key,
+ int key_len)
{
u8 *cinfo;
u32 cipher_cfg;
@@ -753,9 +828,15 @@ static int setup_cipher(struct crypto_tfm *tfm, int encrypt,
}
if (cipher_cfg & MOD_AES) {
switch (key_len) {
- case 16: keylen_cfg = MOD_AES128; break;
- case 24: keylen_cfg = MOD_AES192; break;
- case 32: keylen_cfg = MOD_AES256; break;
+ case 16:
+ keylen_cfg = MOD_AES128;
+ break;
+ case 24:
+ keylen_cfg = MOD_AES192;
+ break;
+ case 32:
+ keylen_cfg = MOD_AES256;
+ break;
default:
return -EINVAL;
}
@@ -766,31 +847,31 @@ static int setup_cipher(struct crypto_tfm *tfm, int encrypt,
return err;
}
/* write cfg word to cryptinfo */
- *(u32*)cinfo = cpu_to_be32(cipher_cfg);
+ *(u32 *)cinfo = cpu_to_be32(cipher_cfg);
cinfo += sizeof(cipher_cfg);
/* write cipher key to cryptinfo */
memcpy(cinfo, key, key_len);
/* NPE wants keylen set to DES3_EDE_KEY_SIZE even for single DES */
if (key_len < DES3_EDE_KEY_SIZE && !(cipher_cfg & MOD_AES)) {
- memset(cinfo + key_len, 0, DES3_EDE_KEY_SIZE -key_len);
+ memset(cinfo + key_len, 0, DES3_EDE_KEY_SIZE - key_len);
key_len = DES3_EDE_KEY_SIZE;
}
dir->npe_ctx_idx = sizeof(cipher_cfg) + key_len;
dir->npe_mode |= NPE_OP_CRYPT_ENABLE;
- if ((cipher_cfg & MOD_AES) && !encrypt) {
+ if ((cipher_cfg & MOD_AES) && !encrypt)
return gen_rev_aes_key(tfm);
- }
+
return 0;
}
static struct buffer_desc *chainup_buffers(struct device *dev,
- struct scatterlist *sg, unsigned nbytes,
+ struct scatterlist *sg, unsigned int nbytes,
struct buffer_desc *buf, gfp_t flags,
enum dma_data_direction dir)
{
for (; nbytes > 0; sg = sg_next(sg)) {
- unsigned len = min(nbytes, sg->length);
+ unsigned int len = min(nbytes, sg->length);
struct buffer_desc *next_buf;
dma_addr_t next_buf_phys;
void *ptr;
@@ -817,7 +898,7 @@ static struct buffer_desc *chainup_buffers(struct device *dev,
}
static int ablk_setkey(struct crypto_skcipher *tfm, const u8 *key,
- unsigned int key_len)
+ unsigned int key_len)
{
struct ixp_ctx *ctx = crypto_skcipher_ctx(tfm);
int ret;
@@ -838,7 +919,12 @@ static int ablk_setkey(struct crypto_skcipher *tfm, const u8 *key,
out:
if (!atomic_dec_and_test(&ctx->configuring))
wait_for_completion(&ctx->completion);
- return ret;
+ if (ret)
+ return ret;
+ crypto_skcipher_clear_flags(ctx->fallback_tfm, CRYPTO_TFM_REQ_MASK);
+ crypto_skcipher_set_flags(ctx->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
+
+ return crypto_skcipher_setkey(ctx->fallback_tfm, key, key_len);
}
static int ablk_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
@@ -849,7 +935,7 @@ static int ablk_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
}
static int ablk_rfc3686_setkey(struct crypto_skcipher *tfm, const u8 *key,
- unsigned int key_len)
+ unsigned int key_len)
{
struct ixp_ctx *ctx = crypto_skcipher_ctx(tfm);
@@ -858,17 +944,36 @@ static int ablk_rfc3686_setkey(struct crypto_skcipher *tfm, const u8 *key,
return -EINVAL;
memcpy(ctx->nonce, key + (key_len - CTR_RFC3686_NONCE_SIZE),
- CTR_RFC3686_NONCE_SIZE);
+ CTR_RFC3686_NONCE_SIZE);
key_len -= CTR_RFC3686_NONCE_SIZE;
return ablk_setkey(tfm, key, key_len);
}
+static int ixp4xx_cipher_fallback(struct skcipher_request *areq, int encrypt)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+ struct ixp_ctx *op = crypto_skcipher_ctx(tfm);
+ struct ablk_ctx *rctx = skcipher_request_ctx(areq);
+ int err;
+
+ skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm);
+ skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags,
+ areq->base.complete, areq->base.data);
+ skcipher_request_set_crypt(&rctx->fallback_req, areq->src, areq->dst,
+ areq->cryptlen, areq->iv);
+ if (encrypt)
+ err = crypto_skcipher_encrypt(&rctx->fallback_req);
+ else
+ err = crypto_skcipher_decrypt(&rctx->fallback_req);
+ return err;
+}
+
static int ablk_perform(struct skcipher_request *req, int encrypt)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
struct ixp_ctx *ctx = crypto_skcipher_ctx(tfm);
- unsigned ivsize = crypto_skcipher_ivsize(tfm);
+ unsigned int ivsize = crypto_skcipher_ivsize(tfm);
struct ix_sa_dir *dir;
struct crypt_ctl *crypt;
unsigned int nbytes = req->cryptlen;
@@ -876,15 +981,20 @@ static int ablk_perform(struct skcipher_request *req, int encrypt)
struct ablk_ctx *req_ctx = skcipher_request_ctx(req);
struct buffer_desc src_hook;
struct device *dev = &pdev->dev;
+ unsigned int offset;
gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
GFP_KERNEL : GFP_ATOMIC;
- if (qmgr_stat_full(SEND_QID))
+ if (sg_nents(req->src) > 1 || sg_nents(req->dst) > 1)
+ return ixp4xx_cipher_fallback(req, encrypt);
+
+ if (qmgr_stat_full(send_qid))
return -EAGAIN;
if (atomic_read(&ctx->configuring))
return -EAGAIN;
dir = encrypt ? &ctx->encrypt : &ctx->decrypt;
+ req_ctx->encrypt = encrypt;
crypt = get_crypt_desc();
if (!crypt)
@@ -900,14 +1010,19 @@ static int ablk_perform(struct skcipher_request *req, int encrypt)
BUG_ON(ivsize && !req->iv);
memcpy(crypt->iv, req->iv, ivsize);
+ if (ivsize > 0 && !encrypt) {
+ offset = req->cryptlen - ivsize;
+ scatterwalk_map_and_copy(req_ctx->iv, req->src, offset, ivsize, 0);
+ }
if (req->src != req->dst) {
struct buffer_desc dst_hook;
+
crypt->mode |= NPE_OP_NOT_IN_PLACE;
/* This was never tested by Intel
* for more than one dst buffer, I think. */
req_ctx->dst = NULL;
if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook,
- flags, DMA_FROM_DEVICE))
+ flags, DMA_FROM_DEVICE))
goto free_buf_dest;
src_direction = DMA_TO_DEVICE;
req_ctx->dst = dst_hook.next;
@@ -916,23 +1031,23 @@ static int ablk_perform(struct skcipher_request *req, int encrypt)
req_ctx->dst = NULL;
}
req_ctx->src = NULL;
- if (!chainup_buffers(dev, req->src, nbytes, &src_hook,
- flags, src_direction))
+ if (!chainup_buffers(dev, req->src, nbytes, &src_hook, flags,
+ src_direction))
goto free_buf_src;
req_ctx->src = src_hook.next;
crypt->src_buf = src_hook.phys_next;
crypt->ctl_flags |= CTL_FLAG_PERFORM_ABLK;
- qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
- BUG_ON(qmgr_stat_overflow(SEND_QID));
+ qmgr_put_entry(send_qid, crypt_virt2phys(crypt));
+ BUG_ON(qmgr_stat_overflow(send_qid));
return -EINPROGRESS;
free_buf_src:
free_buf_chain(dev, req_ctx->src, crypt->src_buf);
free_buf_dest:
- if (req->src != req->dst) {
+ if (req->src != req->dst)
free_buf_chain(dev, req_ctx->dst, crypt->dst_buf);
- }
+
crypt->ctl_flags = CTL_FLAG_UNUSED;
return -ENOMEM;
}
@@ -956,7 +1071,7 @@ static int ablk_rfc3686_crypt(struct skcipher_request *req)
int ret;
/* set up counter block */
- memcpy(iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE);
+ memcpy(iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE);
memcpy(iv + CTR_RFC3686_NONCE_SIZE, info, CTR_RFC3686_IV_SIZE);
/* initialize counter portion of counter block */
@@ -970,12 +1085,12 @@ static int ablk_rfc3686_crypt(struct skcipher_request *req)
}
static int aead_perform(struct aead_request *req, int encrypt,
- int cryptoffset, int eff_cryptlen, u8 *iv)
+ int cryptoffset, int eff_cryptlen, u8 *iv)
{
struct crypto_aead *tfm = crypto_aead_reqtfm(req);
struct ixp_ctx *ctx = crypto_aead_ctx(tfm);
- unsigned ivsize = crypto_aead_ivsize(tfm);
- unsigned authsize = crypto_aead_authsize(tfm);
+ unsigned int ivsize = crypto_aead_ivsize(tfm);
+ unsigned int authsize = crypto_aead_authsize(tfm);
struct ix_sa_dir *dir;
struct crypt_ctl *crypt;
unsigned int cryptlen;
@@ -987,7 +1102,7 @@ static int aead_perform(struct aead_request *req, int encrypt,
enum dma_data_direction src_direction = DMA_BIDIRECTIONAL;
unsigned int lastlen;
- if (qmgr_stat_full(SEND_QID))
+ if (qmgr_stat_full(send_qid))
return -EAGAIN;
if (atomic_read(&ctx->configuring))
return -EAGAIN;
@@ -998,7 +1113,7 @@ static int aead_perform(struct aead_request *req, int encrypt,
} else {
dir = &ctx->decrypt;
/* req->cryptlen includes the authsize when decrypting */
- cryptlen = req->cryptlen -authsize;
+ cryptlen = req->cryptlen - authsize;
eff_cryptlen -= authsize;
}
crypt = get_crypt_desc();
@@ -1058,12 +1173,12 @@ static int aead_perform(struct aead_request *req, int encrypt,
/* The 12 hmac bytes are scattered,
* we need to copy them into a safe buffer */
req_ctx->hmac_virt = dma_pool_alloc(buffer_pool, flags,
- &crypt->icv_rev_aes);
+ &crypt->icv_rev_aes);
if (unlikely(!req_ctx->hmac_virt))
goto free_buf_dst;
if (!encrypt) {
scatterwalk_map_and_copy(req_ctx->hmac_virt,
- req->src, cryptlen, authsize, 0);
+ req->src, cryptlen, authsize, 0);
}
req_ctx->encrypt = encrypt;
} else {
@@ -1071,8 +1186,8 @@ static int aead_perform(struct aead_request *req, int encrypt,
}
crypt->ctl_flags |= CTL_FLAG_PERFORM_AEAD;
- qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
- BUG_ON(qmgr_stat_overflow(SEND_QID));
+ qmgr_put_entry(send_qid, crypt_virt2phys(crypt));
+ BUG_ON(qmgr_stat_overflow(send_qid));
return -EINPROGRESS;
free_buf_dst:
@@ -1086,7 +1201,7 @@ free_buf_src:
static int aead_setup(struct crypto_aead *tfm, unsigned int authsize)
{
struct ixp_ctx *ctx = crypto_aead_ctx(tfm);
- unsigned digest_len = crypto_aead_maxauthsize(tfm);
+ unsigned int digest_len = crypto_aead_maxauthsize(tfm);
int ret;
if (!ctx->enckey_len && !ctx->authkey_len)
@@ -1104,11 +1219,11 @@ static int aead_setup(struct crypto_aead *tfm, unsigned int authsize)
if (ret)
goto out;
ret = setup_auth(&tfm->base, 0, authsize, ctx->authkey,
- ctx->authkey_len, digest_len);
+ ctx->authkey_len, digest_len);
if (ret)
goto out;
ret = setup_auth(&tfm->base, 1, authsize, ctx->authkey,
- ctx->authkey_len, digest_len);
+ ctx->authkey_len, digest_len);
out:
if (!atomic_dec_and_test(&ctx->configuring))
wait_for_completion(&ctx->completion);
@@ -1119,13 +1234,13 @@ static int aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
{
int max = crypto_aead_maxauthsize(tfm) >> 2;
- if ((authsize>>2) < 1 || (authsize>>2) > max || (authsize & 3))
+ if ((authsize >> 2) < 1 || (authsize >> 2) > max || (authsize & 3))
return -EINVAL;
return aead_setup(tfm, authsize);
}
static int aead_setkey(struct crypto_aead *tfm, const u8 *key,
- unsigned int keylen)
+ unsigned int keylen)
{
struct ixp_ctx *ctx = crypto_aead_ctx(tfm);
struct crypto_authenc_keys keys;
@@ -1364,43 +1479,33 @@ static struct ixp_aead_alg ixp4xx_aeads[] = {
#define IXP_POSTFIX "-ixp4xx"
-static const struct platform_device_info ixp_dev_info __initdata = {
- .name = DRIVER_NAME,
- .id = 0,
- .dma_mask = DMA_BIT_MASK(32),
-};
-
-static int __init ixp_module_init(void)
+static int ixp_crypto_probe(struct platform_device *_pdev)
{
+ struct device *dev = &_pdev->dev;
int num = ARRAY_SIZE(ixp4xx_algos);
int i, err;
- pdev = platform_device_register_full(&ixp_dev_info);
- if (IS_ERR(pdev))
- return PTR_ERR(pdev);
+ pdev = _pdev;
- err = init_ixp_crypto(&pdev->dev);
- if (err) {
- platform_device_unregister(pdev);
+ err = init_ixp_crypto(dev);
+ if (err)
return err;
- }
- for (i=0; i< num; i++) {
+
+ for (i = 0; i < num; i++) {
struct skcipher_alg *cra = &ixp4xx_algos[i].crypto;
if (snprintf(cra->base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
- "%s"IXP_POSTFIX, cra->base.cra_name) >=
- CRYPTO_MAX_ALG_NAME)
- {
+ "%s"IXP_POSTFIX, cra->base.cra_name) >=
+ CRYPTO_MAX_ALG_NAME)
continue;
- }
- if (!support_aes && (ixp4xx_algos[i].cfg_enc & MOD_AES)) {
+ if (!support_aes && (ixp4xx_algos[i].cfg_enc & MOD_AES))
continue;
- }
/* block ciphers */
cra->base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_ALLOCATES_MEMORY;
+ CRYPTO_ALG_ALLOCATES_MEMORY |
+ CRYPTO_ALG_NEED_FALLBACK;
if (!cra->setkey)
cra->setkey = ablk_setkey;
if (!cra->encrypt)
@@ -1415,7 +1520,7 @@ static int __init ixp_module_init(void)
cra->base.cra_alignmask = 3;
cra->base.cra_priority = 300;
if (crypto_register_skcipher(cra))
- printk(KERN_ERR "Failed to register '%s'\n",
+ dev_err(&pdev->dev, "Failed to register '%s'\n",
cra->base.cra_name);
else
ixp4xx_algos[i].registered = 1;
@@ -1448,7 +1553,7 @@ static int __init ixp_module_init(void)
cra->base.cra_priority = 300;
if (crypto_register_aead(cra))
- printk(KERN_ERR "Failed to register '%s'\n",
+ dev_err(&pdev->dev, "Failed to register '%s'\n",
cra->base.cra_driver_name);
else
ixp4xx_aeads[i].registered = 1;
@@ -1456,7 +1561,7 @@ static int __init ixp_module_init(void)
return 0;
}
-static void __exit ixp_module_exit(void)
+static int ixp_crypto_remove(struct platform_device *pdev)
{
int num = ARRAY_SIZE(ixp4xx_algos);
int i;
@@ -1466,16 +1571,30 @@ static void __exit ixp_module_exit(void)
crypto_unregister_aead(&ixp4xx_aeads[i].crypto);
}
- for (i=0; i< num; i++) {
+ for (i = 0; i < num; i++) {
if (ixp4xx_algos[i].registered)
crypto_unregister_skcipher(&ixp4xx_algos[i].crypto);
}
release_ixp_crypto(&pdev->dev);
- platform_device_unregister(pdev);
+
+ return 0;
}
+static const struct of_device_id ixp4xx_crypto_of_match[] = {
+ {
+ .compatible = "intel,ixp4xx-crypto",
+ },
+ {},
+};
-module_init(ixp_module_init);
-module_exit(ixp_module_exit);
+static struct platform_driver ixp_crypto_driver = {
+ .probe = ixp_crypto_probe,
+ .remove = ixp_crypto_remove,
+ .driver = {
+ .name = "ixp4xx_crypto",
+ .of_match_table = ixp4xx_crypto_of_match,
+ },
+};
+module_platform_driver(ixp_crypto_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Christian Hohnstaedt <chohnstaedt@innominate.com>");
diff --git a/drivers/crypto/marvell/cesa/cesa.h b/drivers/crypto/marvell/cesa/cesa.h
index c1007f2ba79c..d215a6bed6bc 100644
--- a/drivers/crypto/marvell/cesa/cesa.h
+++ b/drivers/crypto/marvell/cesa/cesa.h
@@ -66,7 +66,7 @@
#define CESA_SA_ST_ACT_1 BIT(1)
/*
- * CESA_SA_FPGA_INT_STATUS looks like a FPGA leftover and is documented only
+ * CESA_SA_FPGA_INT_STATUS looks like an FPGA leftover and is documented only
* in Errata 4.12. It looks like that it was part of an IRQ-controller in FPGA
* and someone forgot to remove it while switching to the core and moving to
* CESA_SA_INT_STATUS.
diff --git a/drivers/crypto/marvell/octeontx2/Makefile b/drivers/crypto/marvell/octeontx2/Makefile
index b9c6201019e0..c242d22008c3 100644
--- a/drivers/crypto/marvell/octeontx2/Makefile
+++ b/drivers/crypto/marvell/octeontx2/Makefile
@@ -1,10 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_CRYPTO_DEV_OCTEONTX2_CPT) += octeontx2-cpt.o octeontx2-cptvf.o
+obj-$(CONFIG_CRYPTO_DEV_OCTEONTX2_CPT) += rvu_cptpf.o rvu_cptvf.o
-octeontx2-cpt-objs := otx2_cptpf_main.o otx2_cptpf_mbox.o \
- otx2_cpt_mbox_common.o otx2_cptpf_ucode.o otx2_cptlf.o
-octeontx2-cptvf-objs := otx2_cptvf_main.o otx2_cptvf_mbox.o otx2_cptlf.o \
- otx2_cpt_mbox_common.o otx2_cptvf_reqmgr.o \
- otx2_cptvf_algs.o
+rvu_cptpf-objs := otx2_cptpf_main.o otx2_cptpf_mbox.o \
+ otx2_cpt_mbox_common.o otx2_cptpf_ucode.o otx2_cptlf.o \
+ cn10k_cpt.o
+rvu_cptvf-objs := otx2_cptvf_main.o otx2_cptvf_mbox.o otx2_cptlf.o \
+ otx2_cpt_mbox_common.o otx2_cptvf_reqmgr.o \
+ otx2_cptvf_algs.o cn10k_cpt.o
ccflags-y += -I$(srctree)/drivers/net/ethernet/marvell/octeontx2/af
diff --git a/drivers/crypto/marvell/octeontx2/cn10k_cpt.c b/drivers/crypto/marvell/octeontx2/cn10k_cpt.c
new file mode 100644
index 000000000000..1499ef75b5c2
--- /dev/null
+++ b/drivers/crypto/marvell/octeontx2/cn10k_cpt.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2021 Marvell. */
+
+#include <linux/soc/marvell/octeontx2/asm.h>
+#include "otx2_cptpf.h"
+#include "otx2_cptvf.h"
+#include "otx2_cptlf.h"
+#include "cn10k_cpt.h"
+
+static struct cpt_hw_ops otx2_hw_ops = {
+ .send_cmd = otx2_cpt_send_cmd,
+ .cpt_get_compcode = otx2_cpt_get_compcode,
+ .cpt_get_uc_compcode = otx2_cpt_get_uc_compcode,
+};
+
+static struct cpt_hw_ops cn10k_hw_ops = {
+ .send_cmd = cn10k_cpt_send_cmd,
+ .cpt_get_compcode = cn10k_cpt_get_compcode,
+ .cpt_get_uc_compcode = cn10k_cpt_get_uc_compcode,
+};
+
+void cn10k_cpt_send_cmd(union otx2_cpt_inst_s *cptinst, u32 insts_num,
+ struct otx2_cptlf_info *lf)
+{
+ void __iomem *lmtline = lf->lmtline;
+ u64 val = (lf->slot & 0x7FF);
+ u64 tar_addr = 0;
+
+ /* tar_addr<6:4> = Size of first LMTST - 1 in units of 128b. */
+ tar_addr |= (__force u64)lf->ioreg |
+ (((OTX2_CPT_INST_SIZE/16) - 1) & 0x7) << 4;
+ /*
+ * Make sure memory areas pointed in CPT_INST_S
+ * are flushed before the instruction is sent to CPT
+ */
+ dma_wmb();
+
+ /* Copy CPT command to LMTLINE */
+ memcpy_toio(lmtline, cptinst, insts_num * OTX2_CPT_INST_SIZE);
+ cn10k_lmt_flush(val, tar_addr);
+}
+
+int cn10k_cptpf_lmtst_init(struct otx2_cptpf_dev *cptpf)
+{
+ struct pci_dev *pdev = cptpf->pdev;
+ resource_size_t size;
+ u64 lmt_base;
+
+ if (!test_bit(CN10K_LMTST, &cptpf->cap_flag)) {
+ cptpf->lfs.ops = &otx2_hw_ops;
+ return 0;
+ }
+
+ cptpf->lfs.ops = &cn10k_hw_ops;
+ lmt_base = readq(cptpf->reg_base + RVU_PF_LMTLINE_ADDR);
+ if (!lmt_base) {
+ dev_err(&pdev->dev, "PF LMTLINE address not configured\n");
+ return -ENOMEM;
+ }
+ size = pci_resource_len(pdev, PCI_MBOX_BAR_NUM);
+ size -= ((1 + cptpf->max_vfs) * MBOX_SIZE);
+ cptpf->lfs.lmt_base = devm_ioremap_wc(&pdev->dev, lmt_base, size);
+ if (!cptpf->lfs.lmt_base) {
+ dev_err(&pdev->dev,
+ "Mapping of PF LMTLINE address failed\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+int cn10k_cptvf_lmtst_init(struct otx2_cptvf_dev *cptvf)
+{
+ struct pci_dev *pdev = cptvf->pdev;
+ resource_size_t offset, size;
+
+ if (!test_bit(CN10K_LMTST, &cptvf->cap_flag)) {
+ cptvf->lfs.ops = &otx2_hw_ops;
+ return 0;
+ }
+
+ cptvf->lfs.ops = &cn10k_hw_ops;
+ offset = pci_resource_start(pdev, PCI_MBOX_BAR_NUM);
+ size = pci_resource_len(pdev, PCI_MBOX_BAR_NUM);
+ /* Map VF LMILINE region */
+ cptvf->lfs.lmt_base = devm_ioremap_wc(&pdev->dev, offset, size);
+ if (!cptvf->lfs.lmt_base) {
+ dev_err(&pdev->dev, "Unable to map BAR4\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
diff --git a/drivers/crypto/marvell/octeontx2/cn10k_cpt.h b/drivers/crypto/marvell/octeontx2/cn10k_cpt.h
new file mode 100644
index 000000000000..c091392b47e0
--- /dev/null
+++ b/drivers/crypto/marvell/octeontx2/cn10k_cpt.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * Copyright (C) 2021 Marvell.
+ */
+#ifndef __CN10K_CPT_H
+#define __CN10K_CPT_H
+
+#include "otx2_cpt_common.h"
+#include "otx2_cptpf.h"
+#include "otx2_cptvf.h"
+
+static inline u8 cn10k_cpt_get_compcode(union otx2_cpt_res_s *result)
+{
+ return ((struct cn10k_cpt_res_s *)result)->compcode;
+}
+
+static inline u8 cn10k_cpt_get_uc_compcode(union otx2_cpt_res_s *result)
+{
+ return ((struct cn10k_cpt_res_s *)result)->uc_compcode;
+}
+
+static inline u8 otx2_cpt_get_compcode(union otx2_cpt_res_s *result)
+{
+ return ((struct cn9k_cpt_res_s *)result)->compcode;
+}
+
+static inline u8 otx2_cpt_get_uc_compcode(union otx2_cpt_res_s *result)
+{
+ return ((struct cn9k_cpt_res_s *)result)->uc_compcode;
+}
+
+void cn10k_cpt_send_cmd(union otx2_cpt_inst_s *cptinst, u32 insts_num,
+ struct otx2_cptlf_info *lf);
+int cn10k_cptpf_lmtst_init(struct otx2_cptpf_dev *cptpf);
+int cn10k_cptvf_lmtst_init(struct otx2_cptvf_dev *cptvf);
+
+#endif /* __CN10K_CPTLF_H */
diff --git a/drivers/crypto/marvell/octeontx2/otx2_cpt_common.h b/drivers/crypto/marvell/octeontx2/otx2_cpt_common.h
index ecedd91a8d85..c5445b05f53c 100644
--- a/drivers/crypto/marvell/octeontx2/otx2_cpt_common.h
+++ b/drivers/crypto/marvell/octeontx2/otx2_cpt_common.h
@@ -25,6 +25,10 @@
#define OTX2_CPT_NAME_LENGTH 64
#define OTX2_CPT_DMA_MINALIGN 128
+/* HW capability flags */
+#define CN10K_MBOX 0
+#define CN10K_LMTST 1
+
#define BAD_OTX2_CPT_ENG_TYPE OTX2_CPT_MAX_ENG_TYPES
enum otx2_cpt_eng_type {
@@ -116,6 +120,25 @@ static inline u64 otx2_cpt_read64(void __iomem *reg_base, u64 blk, u64 slot,
OTX2_CPT_RVU_FUNC_ADDR_S(blk, slot, offs));
}
+static inline bool is_dev_otx2(struct pci_dev *pdev)
+{
+ if (pdev->device == OTX2_CPT_PCI_PF_DEVICE_ID ||
+ pdev->device == OTX2_CPT_PCI_VF_DEVICE_ID)
+ return true;
+
+ return false;
+}
+
+static inline void otx2_cpt_set_hw_caps(struct pci_dev *pdev,
+ unsigned long *cap_flag)
+{
+ if (!is_dev_otx2(pdev)) {
+ __set_bit(CN10K_MBOX, cap_flag);
+ __set_bit(CN10K_LMTST, cap_flag);
+ }
+}
+
+
int otx2_cpt_send_ready_msg(struct otx2_mbox *mbox, struct pci_dev *pdev);
int otx2_cpt_send_mbox_msg(struct otx2_mbox *mbox, struct pci_dev *pdev);
diff --git a/drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h b/drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h
index ecafc42f37a2..6f947978e4e8 100644
--- a/drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h
+++ b/drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h
@@ -10,6 +10,8 @@
/* Device IDs */
#define OTX2_CPT_PCI_PF_DEVICE_ID 0xA0FD
#define OTX2_CPT_PCI_VF_DEVICE_ID 0xA0FE
+#define CN10K_CPT_PCI_PF_DEVICE_ID 0xA0F2
+#define CN10K_CPT_PCI_VF_DEVICE_ID 0xA0F3
/* Mailbox interrupts offset */
#define OTX2_CPT_PF_MBOX_INT 6
@@ -25,6 +27,7 @@
*/
#define OTX2_CPT_VF_MSIX_VECTORS 1
#define OTX2_CPT_VF_INTR_MBOX_MASK BIT(0)
+#define CN10K_CPT_VF_MBOX_REGION (0xC0000)
/* CPT LF MSIX vectors */
#define OTX2_CPT_LF_MSIX_VECTORS 2
@@ -135,7 +138,7 @@ enum otx2_cpt_comp_e {
OTX2_CPT_COMP_E_FAULT = 0x02,
OTX2_CPT_COMP_E_HWERR = 0x04,
OTX2_CPT_COMP_E_INSTERR = 0x05,
- OTX2_CPT_COMP_E_LAST_ENTRY = 0x06
+ OTX2_CPT_COMP_E_WARN = 0x06
};
/*
@@ -266,13 +269,22 @@ union otx2_cpt_inst_s {
union otx2_cpt_res_s {
u64 u[2];
- struct {
+ struct cn9k_cpt_res_s {
u64 compcode:8;
u64 uc_compcode:8;
u64 doneint:1;
u64 reserved_17_63:47;
u64 reserved_64_127;
} s;
+
+ struct cn10k_cpt_res_s {
+ u64 compcode:7;
+ u64 doneint:1;
+ u64 uc_compcode:8;
+ u64 rlen:16;
+ u64 spi:32;
+ u64 esn;
+ } cn10k;
};
/*
diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptlf.c b/drivers/crypto/marvell/octeontx2/otx2_cptlf.c
index 34aba1532761..c8350fcd60fa 100644
--- a/drivers/crypto/marvell/octeontx2/otx2_cptlf.c
+++ b/drivers/crypto/marvell/octeontx2/otx2_cptlf.c
@@ -379,9 +379,14 @@ int otx2_cptlf_init(struct otx2_cptlfs_info *lfs, u8 eng_grp_mask, int pri,
for (slot = 0; slot < lfs->lfs_num; slot++) {
lfs->lf[slot].lfs = lfs;
lfs->lf[slot].slot = slot;
- lfs->lf[slot].lmtline = lfs->reg_base +
- OTX2_CPT_RVU_FUNC_ADDR_S(BLKADDR_LMT, slot,
+ if (lfs->lmt_base)
+ lfs->lf[slot].lmtline = lfs->lmt_base +
+ (slot * LMTLINE_SIZE);
+ else
+ lfs->lf[slot].lmtline = lfs->reg_base +
+ OTX2_CPT_RVU_FUNC_ADDR_S(BLKADDR_LMT, slot,
OTX2_CPT_LMT_LF_LMTLINEX(0));
+
lfs->lf[slot].ioreg = lfs->reg_base +
OTX2_CPT_RVU_FUNC_ADDR_S(BLKADDR_CPT0, slot,
OTX2_CPT_LF_NQX(0));
diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptlf.h b/drivers/crypto/marvell/octeontx2/otx2_cptlf.h
index ab1678fc564d..b691b6c1d5c4 100644
--- a/drivers/crypto/marvell/octeontx2/otx2_cptlf.h
+++ b/drivers/crypto/marvell/octeontx2/otx2_cptlf.h
@@ -84,12 +84,22 @@ struct otx2_cptlf_info {
struct otx2_cptlf_wqe *wqe; /* Tasklet work info */
};
+struct cpt_hw_ops {
+ void (*send_cmd)(union otx2_cpt_inst_s *cptinst, u32 insts_num,
+ struct otx2_cptlf_info *lf);
+ u8 (*cpt_get_compcode)(union otx2_cpt_res_s *result);
+ u8 (*cpt_get_uc_compcode)(union otx2_cpt_res_s *result);
+};
+
struct otx2_cptlfs_info {
/* Registers start address of VF/PF LFs are attached to */
void __iomem *reg_base;
+#define LMTLINE_SIZE 128
+ void __iomem *lmt_base;
struct pci_dev *pdev; /* Device LFs are attached to */
struct otx2_cptlf_info lf[OTX2_CPT_MAX_LFS_NUM];
struct otx2_mbox *mbox;
+ struct cpt_hw_ops *ops;
u8 are_lfs_attached; /* Whether CPT LFs are attached */
u8 lfs_num; /* Number of CPT LFs */
u8 kcrypto_eng_grp_num; /* Kernel crypto engine group number */
diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf.h b/drivers/crypto/marvell/octeontx2/otx2_cptpf.h
index e19af1356f12..5ebba86c65d9 100644
--- a/drivers/crypto/marvell/octeontx2/otx2_cptpf.h
+++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf.h
@@ -47,6 +47,7 @@ struct otx2_cptpf_dev {
struct workqueue_struct *flr_wq;
struct cptpf_flr_work *flr_work;
+ unsigned long cap_flag;
u8 pf_id; /* RVU PF number */
u8 max_vfs; /* Maximum number of VFs supported by CPT */
u8 enabled_vfs; /* Number of enabled VFs */
diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c b/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c
index 58f47e3ab62e..146a55ac4b9b 100644
--- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c
+++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c
@@ -6,10 +6,11 @@
#include "otx2_cpt_common.h"
#include "otx2_cptpf_ucode.h"
#include "otx2_cptpf.h"
+#include "cn10k_cpt.h"
#include "rvu_reg.h"
-#define OTX2_CPT_DRV_NAME "octeontx2-cpt"
-#define OTX2_CPT_DRV_STRING "Marvell OcteonTX2 CPT Physical Function Driver"
+#define OTX2_CPT_DRV_NAME "rvu_cptpf"
+#define OTX2_CPT_DRV_STRING "Marvell RVU CPT Physical Function Driver"
static void cptpf_enable_vfpf_mbox_intr(struct otx2_cptpf_dev *cptpf,
int num_vfs)
@@ -62,45 +63,66 @@ static void cptpf_disable_vfpf_mbox_intr(struct otx2_cptpf_dev *cptpf,
}
}
-static void cptpf_enable_vf_flr_intrs(struct otx2_cptpf_dev *cptpf)
+static void cptpf_enable_vf_flr_me_intrs(struct otx2_cptpf_dev *cptpf,
+ int num_vfs)
{
- /* Clear interrupt if any */
+ /* Clear FLR interrupt if any */
otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INTX(0),
- ~0x0ULL);
- otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INTX(1),
- ~0x0ULL);
+ INTR_MASK(num_vfs));
/* Enable VF FLR interrupts */
otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
- RVU_PF_VFFLR_INT_ENA_W1SX(0), ~0x0ULL);
+ RVU_PF_VFFLR_INT_ENA_W1SX(0), INTR_MASK(num_vfs));
+ /* Clear ME interrupt if any */
+ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFME_INTX(0),
+ INTR_MASK(num_vfs));
+ /* Enable VF ME interrupts */
+ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
+ RVU_PF_VFME_INT_ENA_W1SX(0), INTR_MASK(num_vfs));
+
+ if (num_vfs <= 64)
+ return;
+
+ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INTX(1),
+ INTR_MASK(num_vfs - 64));
+ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
+ RVU_PF_VFFLR_INT_ENA_W1SX(1), INTR_MASK(num_vfs - 64));
+
+ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFME_INTX(1),
+ INTR_MASK(num_vfs - 64));
otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
- RVU_PF_VFFLR_INT_ENA_W1SX(1), ~0x0ULL);
+ RVU_PF_VFME_INT_ENA_W1SX(1), INTR_MASK(num_vfs - 64));
}
-static void cptpf_disable_vf_flr_intrs(struct otx2_cptpf_dev *cptpf,
+static void cptpf_disable_vf_flr_me_intrs(struct otx2_cptpf_dev *cptpf,
int num_vfs)
{
int vector;
/* Disable VF FLR interrupts */
otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
- RVU_PF_VFFLR_INT_ENA_W1CX(0), ~0x0ULL);
+ RVU_PF_VFFLR_INT_ENA_W1CX(0), INTR_MASK(num_vfs));
+ vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFFLR0);
+ free_irq(vector, cptpf);
+
+ /* Disable VF ME interrupts */
otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
- RVU_PF_VFFLR_INT_ENA_W1CX(1), ~0x0ULL);
+ RVU_PF_VFME_INT_ENA_W1CX(0), INTR_MASK(num_vfs));
+ vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFME0);
+ free_irq(vector, cptpf);
- /* Clear interrupt if any */
- otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INTX(0),
- ~0x0ULL);
- otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0, RVU_PF_VFFLR_INTX(1),
- ~0x0ULL);
+ if (num_vfs <= 64)
+ return;
- vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFFLR0);
+ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
+ RVU_PF_VFFLR_INT_ENA_W1CX(1), INTR_MASK(num_vfs - 64));
+ vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFFLR1);
free_irq(vector, cptpf);
- if (num_vfs > 64) {
- vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFFLR1);
- free_irq(vector, cptpf);
- }
+ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
+ RVU_PF_VFME_INT_ENA_W1CX(1), INTR_MASK(num_vfs - 64));
+ vector = pci_irq_vector(cptpf->pdev, RVU_PF_INT_VEC_VFME1);
+ free_irq(vector, cptpf);
}
static void cptpf_flr_wq_handler(struct work_struct *work)
@@ -172,11 +194,38 @@ static irqreturn_t cptpf_vf_flr_intr(int __always_unused irq, void *arg)
return IRQ_HANDLED;
}
+static irqreturn_t cptpf_vf_me_intr(int __always_unused irq, void *arg)
+{
+ struct otx2_cptpf_dev *cptpf = arg;
+ int reg, vf, num_reg = 1;
+ u64 intr;
+
+ if (cptpf->max_vfs > 64)
+ num_reg = 2;
+
+ for (reg = 0; reg < num_reg; reg++) {
+ intr = otx2_cpt_read64(cptpf->reg_base, BLKADDR_RVUM, 0,
+ RVU_PF_VFME_INTX(reg));
+ if (!intr)
+ continue;
+ for (vf = 0; vf < 64; vf++) {
+ if (!(intr & BIT_ULL(vf)))
+ continue;
+ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
+ RVU_PF_VFTRPENDX(reg), BIT_ULL(vf));
+ /* Clear interrupt */
+ otx2_cpt_write64(cptpf->reg_base, BLKADDR_RVUM, 0,
+ RVU_PF_VFME_INTX(reg), BIT_ULL(vf));
+ }
+ }
+ return IRQ_HANDLED;
+}
+
static void cptpf_unregister_vfpf_intr(struct otx2_cptpf_dev *cptpf,
int num_vfs)
{
cptpf_disable_vfpf_mbox_intr(cptpf, num_vfs);
- cptpf_disable_vf_flr_intrs(cptpf, num_vfs);
+ cptpf_disable_vf_flr_me_intrs(cptpf, num_vfs);
}
static int cptpf_register_vfpf_intr(struct otx2_cptpf_dev *cptpf, int num_vfs)
@@ -202,6 +251,15 @@ static int cptpf_register_vfpf_intr(struct otx2_cptpf_dev *cptpf, int num_vfs)
"IRQ registration failed for VFFLR0 irq\n");
goto free_mbox0_irq;
}
+ vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFME0);
+ /* Register VF ME interrupt handler */
+ ret = request_irq(vector, cptpf_vf_me_intr, 0, "CPTPF ME0", cptpf);
+ if (ret) {
+ dev_err(dev,
+ "IRQ registration failed for PFVF mbox0 irq\n");
+ goto free_flr0_irq;
+ }
+
if (num_vfs > 64) {
vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFPF_MBOX1);
ret = request_irq(vector, otx2_cptpf_vfpf_mbox_intr, 0,
@@ -209,7 +267,7 @@ static int cptpf_register_vfpf_intr(struct otx2_cptpf_dev *cptpf, int num_vfs)
if (ret) {
dev_err(dev,
"IRQ registration failed for PFVF mbox1 irq\n");
- goto free_flr0_irq;
+ goto free_me0_irq;
}
vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFFLR1);
/* Register VF FLR interrupt handler */
@@ -220,15 +278,30 @@ static int cptpf_register_vfpf_intr(struct otx2_cptpf_dev *cptpf, int num_vfs)
"IRQ registration failed for VFFLR1 irq\n");
goto free_mbox1_irq;
}
+ vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFME1);
+ /* Register VF FLR interrupt handler */
+ ret = request_irq(vector, cptpf_vf_me_intr, 0, "CPTPF ME1",
+ cptpf);
+ if (ret) {
+ dev_err(dev,
+ "IRQ registration failed for VFFLR1 irq\n");
+ goto free_flr1_irq;
+ }
}
cptpf_enable_vfpf_mbox_intr(cptpf, num_vfs);
- cptpf_enable_vf_flr_intrs(cptpf);
+ cptpf_enable_vf_flr_me_intrs(cptpf, num_vfs);
return 0;
+free_flr1_irq:
+ vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFFLR1);
+ free_irq(vector, cptpf);
free_mbox1_irq:
vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFPF_MBOX1);
free_irq(vector, cptpf);
+free_me0_irq:
+ vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFME0);
+ free_irq(vector, cptpf);
free_flr0_irq:
vector = pci_irq_vector(pdev, RVU_PF_INT_VEC_VFFLR0);
free_irq(vector, cptpf);
@@ -284,7 +357,11 @@ static int cptpf_vfpf_mbox_init(struct otx2_cptpf_dev *cptpf, int num_vfs)
return -ENOMEM;
/* Map VF-PF mailbox memory */
- vfpf_mbox_base = readq(cptpf->reg_base + RVU_PF_VF_BAR4_ADDR);
+ if (test_bit(CN10K_MBOX, &cptpf->cap_flag))
+ vfpf_mbox_base = readq(cptpf->reg_base + RVU_PF_VF_MBOX_ADDR);
+ else
+ vfpf_mbox_base = readq(cptpf->reg_base + RVU_PF_VF_BAR4_ADDR);
+
if (!vfpf_mbox_base) {
dev_err(dev, "VF-PF mailbox address not configured\n");
err = -ENOMEM;
@@ -365,6 +442,8 @@ static int cptpf_register_afpf_mbox_intr(struct otx2_cptpf_dev *cptpf)
static int cptpf_afpf_mbox_init(struct otx2_cptpf_dev *cptpf)
{
+ struct pci_dev *pdev = cptpf->pdev;
+ resource_size_t offset;
int err;
cptpf->afpf_mbox_wq = alloc_workqueue("cpt_afpf_mailbox",
@@ -373,8 +452,17 @@ static int cptpf_afpf_mbox_init(struct otx2_cptpf_dev *cptpf)
if (!cptpf->afpf_mbox_wq)
return -ENOMEM;
+ offset = pci_resource_start(pdev, PCI_MBOX_BAR_NUM);
+ /* Map AF-PF mailbox memory */
+ cptpf->afpf_mbox_base = devm_ioremap_wc(&pdev->dev, offset, MBOX_SIZE);
+ if (!cptpf->afpf_mbox_base) {
+ dev_err(&pdev->dev, "Unable to map BAR4\n");
+ err = -ENOMEM;
+ goto error;
+ }
+
err = otx2_mbox_init(&cptpf->afpf_mbox, cptpf->afpf_mbox_base,
- cptpf->pdev, cptpf->reg_base, MBOX_DIR_PFAF, 1);
+ pdev, cptpf->reg_base, MBOX_DIR_PFAF, 1);
if (err)
goto error;
@@ -570,7 +658,7 @@ static int cptpf_sriov_enable(struct pci_dev *pdev, int num_vfs)
if (ret)
goto disable_intr;
- ret = otx2_cpt_create_eng_grps(cptpf->pdev, &cptpf->eng_grps);
+ ret = otx2_cpt_create_eng_grps(cptpf, &cptpf->eng_grps);
if (ret)
goto disable_intr;
@@ -607,7 +695,6 @@ static int otx2_cptpf_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct device *dev = &pdev->dev;
- resource_size_t offset, size;
struct otx2_cptpf_dev *cptpf;
int err;
@@ -644,15 +731,6 @@ static int otx2_cptpf_probe(struct pci_dev *pdev,
if (err)
goto clear_drvdata;
- offset = pci_resource_start(pdev, PCI_MBOX_BAR_NUM);
- size = pci_resource_len(pdev, PCI_MBOX_BAR_NUM);
- /* Map AF-PF mailbox memory */
- cptpf->afpf_mbox_base = devm_ioremap_wc(dev, offset, size);
- if (!cptpf->afpf_mbox_base) {
- dev_err(&pdev->dev, "Unable to map BAR4\n");
- err = -ENODEV;
- goto clear_drvdata;
- }
err = pci_alloc_irq_vectors(pdev, RVU_PF_INT_VEC_CNT,
RVU_PF_INT_VEC_CNT, PCI_IRQ_MSIX);
if (err < 0) {
@@ -660,6 +738,7 @@ static int otx2_cptpf_probe(struct pci_dev *pdev,
RVU_PF_INT_VEC_CNT);
goto clear_drvdata;
}
+ otx2_cpt_set_hw_caps(pdev, &cptpf->cap_flag);
/* Initialize AF-PF mailbox */
err = cptpf_afpf_mbox_init(cptpf);
if (err)
@@ -671,6 +750,10 @@ static int otx2_cptpf_probe(struct pci_dev *pdev,
cptpf->max_vfs = pci_sriov_get_totalvfs(pdev);
+ err = cn10k_cptpf_lmtst_init(cptpf);
+ if (err)
+ goto unregister_intr;
+
/* Initialize CPT PF device */
err = cptpf_device_init(cptpf);
if (err)
@@ -719,6 +802,7 @@ static void otx2_cptpf_remove(struct pci_dev *pdev)
/* Supported devices */
static const struct pci_device_id otx2_cpt_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OTX2_CPT_PCI_PF_DEVICE_ID) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, CN10K_CPT_PCI_PF_DEVICE_ID) },
{ 0, } /* end of table */
};
diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c
index a531f4c8b441..dff34b3ec09e 100644
--- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c
+++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c
@@ -16,6 +16,8 @@
#define LOADFVC_MAJOR_OP 0x01
#define LOADFVC_MINOR_OP 0x08
+#define CTX_FLUSH_TIMER_CNT 0xFFFFFF
+
struct fw_info_t {
struct list_head ucodes;
};
@@ -666,7 +668,8 @@ static int reserve_engines(struct device *dev,
static void ucode_unload(struct device *dev, struct otx2_cpt_ucode *ucode)
{
if (ucode->va) {
- dma_free_coherent(dev, ucode->size, ucode->va, ucode->dma);
+ dma_free_coherent(dev, OTX2_CPT_UCODE_SZ, ucode->va,
+ ucode->dma);
ucode->va = NULL;
ucode->dma = 0;
ucode->size = 0;
@@ -685,7 +688,7 @@ static int copy_ucode_to_dma_mem(struct device *dev,
u32 i;
/* Allocate DMAable space */
- ucode->va = dma_alloc_coherent(dev, ucode->size, &ucode->dma,
+ ucode->va = dma_alloc_coherent(dev, OTX2_CPT_UCODE_SZ, &ucode->dma,
GFP_KERNEL);
if (!ucode->va)
return -ENOMEM;
@@ -1100,11 +1103,12 @@ int otx2_cpt_get_eng_grp(struct otx2_cpt_eng_grps *eng_grps, int eng_type)
return eng_grp_num;
}
-int otx2_cpt_create_eng_grps(struct pci_dev *pdev,
+int otx2_cpt_create_eng_grps(struct otx2_cptpf_dev *cptpf,
struct otx2_cpt_eng_grps *eng_grps)
{
struct otx2_cpt_uc_info_t *uc_info[OTX2_CPT_MAX_ETYPES_PER_GRP] = { };
struct otx2_cpt_engines engs[OTX2_CPT_MAX_ETYPES_PER_GRP] = { {0} };
+ struct pci_dev *pdev = cptpf->pdev;
struct fw_info_t fw_info;
int ret;
@@ -1180,6 +1184,23 @@ int otx2_cpt_create_eng_grps(struct pci_dev *pdev,
eng_grps->is_grps_created = true;
cpt_ucode_release_fw(&fw_info);
+
+ if (is_dev_otx2(pdev))
+ return 0;
+ /*
+ * Configure engine group mask to allow context prefetching
+ * for the groups.
+ */
+ otx2_cpt_write_af_reg(&cptpf->afpf_mbox, pdev, CPT_AF_CTL,
+ OTX2_CPT_ALL_ENG_GRPS_MASK << 3 | BIT_ULL(16),
+ BLKADDR_CPT0);
+ /*
+ * Set interval to periodically flush dirty data for the next
+ * CTX cache entry. Set the interval count to maximum supported
+ * value.
+ */
+ otx2_cpt_write_af_reg(&cptpf->afpf_mbox, pdev, CPT_AF_CTX_FLUSH_TIMER,
+ CTX_FLUSH_TIMER_CNT, BLKADDR_CPT0);
return 0;
delete_eng_grp:
@@ -1460,9 +1481,10 @@ int otx2_cpt_discover_eng_capabilities(struct otx2_cptpf_dev *cptpf)
iq_cmd.cptr.s.grp = otx2_cpt_get_eng_grp(&cptpf->eng_grps,
etype);
otx2_cpt_fill_inst(&inst, &iq_cmd, rptr_baddr);
- otx2_cpt_send_cmd(&inst, 1, &cptpf->lfs.lf[0]);
+ lfs->ops->send_cmd(&inst, 1, &cptpf->lfs.lf[0]);
- while (result->s.compcode == OTX2_CPT_COMPLETION_CODE_INIT)
+ while (lfs->ops->cpt_get_compcode(result) ==
+ OTX2_CPT_COMPLETION_CODE_INIT)
cpu_relax();
cptpf->eng_caps[etype].u = be64_to_cpup(rptr);
diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.h b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.h
index 6b0d432de0af..fe019ab730b2 100644
--- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.h
+++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.h
@@ -23,11 +23,13 @@
/* Microcode version string length */
#define OTX2_CPT_UCODE_VER_STR_SZ 44
-/* Maximum number of supported engines/cores on OcteonTX2 platform */
-#define OTX2_CPT_MAX_ENGINES 128
+/* Maximum number of supported engines/cores on OcteonTX2/CN10K platform */
+#define OTX2_CPT_MAX_ENGINES 144
#define OTX2_CPT_ENGS_BITMASK_LEN BITS_TO_LONGS(OTX2_CPT_MAX_ENGINES)
+#define OTX2_CPT_UCODE_SZ (64 * 1024)
+
/* Microcode types */
enum otx2_cpt_ucode_type {
OTX2_CPT_AE_UC_TYPE = 1, /* AE-MAIN */
@@ -153,7 +155,7 @@ int otx2_cpt_init_eng_grps(struct pci_dev *pdev,
struct otx2_cpt_eng_grps *eng_grps);
void otx2_cpt_cleanup_eng_grps(struct pci_dev *pdev,
struct otx2_cpt_eng_grps *eng_grps);
-int otx2_cpt_create_eng_grps(struct pci_dev *pdev,
+int otx2_cpt_create_eng_grps(struct otx2_cptpf_dev *cptpf,
struct otx2_cpt_eng_grps *eng_grps);
int otx2_cpt_disable_all_cores(struct otx2_cptpf_dev *cptpf);
int otx2_cpt_get_eng_grp(struct otx2_cpt_eng_grps *eng_grps, int eng_type);
diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf.h b/drivers/crypto/marvell/octeontx2/otx2_cptvf.h
index 4f0a169fddbd..4207e2236903 100644
--- a/drivers/crypto/marvell/octeontx2/otx2_cptvf.h
+++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf.h
@@ -19,11 +19,14 @@ struct otx2_cptvf_dev {
struct otx2_mbox pfvf_mbox;
struct work_struct pfvf_mbox_work;
struct workqueue_struct *pfvf_mbox_wq;
+ void *bbuf_base;
+ unsigned long cap_flag;
};
irqreturn_t otx2_cptvf_pfvf_mbox_intr(int irq, void *arg);
void otx2_cptvf_pfvf_mbox_handler(struct work_struct *work);
int otx2_cptvf_send_eng_grp_num_msg(struct otx2_cptvf_dev *cptvf, int eng_type);
int otx2_cptvf_send_kvf_limits_msg(struct otx2_cptvf_dev *cptvf);
+int otx2_cpt_mbox_bbuf_init(struct otx2_cptvf_dev *cptvf, struct pci_dev *pdev);
#endif /* __OTX2_CPTVF_H */
diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c
index 47f378731024..3411e664cf50 100644
--- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c
+++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c
@@ -5,9 +5,10 @@
#include "otx2_cptvf.h"
#include "otx2_cptlf.h"
#include "otx2_cptvf_algs.h"
+#include "cn10k_cpt.h"
#include <rvu_reg.h>
-#define OTX2_CPTVF_DRV_NAME "octeontx2-cptvf"
+#define OTX2_CPTVF_DRV_NAME "rvu_cptvf"
static void cptvf_enable_pfvf_mbox_intrs(struct otx2_cptvf_dev *cptvf)
{
@@ -70,6 +71,8 @@ static int cptvf_register_interrupts(struct otx2_cptvf_dev *cptvf)
static int cptvf_pfvf_mbox_init(struct otx2_cptvf_dev *cptvf)
{
+ struct pci_dev *pdev = cptvf->pdev;
+ resource_size_t offset, size;
int ret;
cptvf->pfvf_mbox_wq = alloc_workqueue("cpt_pfvf_mailbox",
@@ -78,14 +81,39 @@ static int cptvf_pfvf_mbox_init(struct otx2_cptvf_dev *cptvf)
if (!cptvf->pfvf_mbox_wq)
return -ENOMEM;
+ if (test_bit(CN10K_MBOX, &cptvf->cap_flag)) {
+ /* For cn10k platform, VF mailbox region is in its BAR2
+ * register space
+ */
+ cptvf->pfvf_mbox_base = cptvf->reg_base +
+ CN10K_CPT_VF_MBOX_REGION;
+ } else {
+ offset = pci_resource_start(pdev, PCI_MBOX_BAR_NUM);
+ size = pci_resource_len(pdev, PCI_MBOX_BAR_NUM);
+ /* Map PF-VF mailbox memory */
+ cptvf->pfvf_mbox_base = devm_ioremap_wc(&pdev->dev, offset,
+ size);
+ if (!cptvf->pfvf_mbox_base) {
+ dev_err(&pdev->dev, "Unable to map BAR4\n");
+ ret = -ENOMEM;
+ goto free_wqe;
+ }
+ }
+
ret = otx2_mbox_init(&cptvf->pfvf_mbox, cptvf->pfvf_mbox_base,
- cptvf->pdev, cptvf->reg_base, MBOX_DIR_VFPF, 1);
+ pdev, cptvf->reg_base, MBOX_DIR_VFPF, 1);
if (ret)
goto free_wqe;
+ ret = otx2_cpt_mbox_bbuf_init(cptvf, pdev);
+ if (ret)
+ goto destroy_mbox;
+
INIT_WORK(&cptvf->pfvf_mbox_work, otx2_cptvf_pfvf_mbox_handler);
return 0;
+destroy_mbox:
+ otx2_mbox_destroy(&cptvf->pfvf_mbox);
free_wqe:
destroy_workqueue(cptvf->pfvf_mbox_wq);
return ret;
@@ -305,7 +333,6 @@ static int otx2_cptvf_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct device *dev = &pdev->dev;
- resource_size_t offset, size;
struct otx2_cptvf_dev *cptvf;
int ret;
@@ -337,15 +364,12 @@ static int otx2_cptvf_probe(struct pci_dev *pdev,
cptvf->reg_base = pcim_iomap_table(pdev)[PCI_PF_REG_BAR_NUM];
- offset = pci_resource_start(pdev, PCI_MBOX_BAR_NUM);
- size = pci_resource_len(pdev, PCI_MBOX_BAR_NUM);
- /* Map PF-VF mailbox memory */
- cptvf->pfvf_mbox_base = devm_ioremap_wc(dev, offset, size);
- if (!cptvf->pfvf_mbox_base) {
- dev_err(&pdev->dev, "Unable to map BAR4\n");
- ret = -ENODEV;
+ otx2_cpt_set_hw_caps(pdev, &cptvf->cap_flag);
+
+ ret = cn10k_cptvf_lmtst_init(cptvf);
+ if (ret)
goto clear_drvdata;
- }
+
/* Initialize PF<=>VF mailbox */
ret = cptvf_pfvf_mbox_init(cptvf);
if (ret)
@@ -392,6 +416,7 @@ static void otx2_cptvf_remove(struct pci_dev *pdev)
/* Supported devices */
static const struct pci_device_id otx2_cptvf_id_table[] = {
{PCI_VDEVICE(CAVIUM, OTX2_CPT_PCI_VF_DEVICE_ID), 0},
+ {PCI_VDEVICE(CAVIUM, CN10K_CPT_PCI_VF_DEVICE_ID), 0},
{ 0, } /* end of table */
};
@@ -405,6 +430,6 @@ static struct pci_driver otx2_cptvf_pci_driver = {
module_pci_driver(otx2_cptvf_pci_driver);
MODULE_AUTHOR("Marvell");
-MODULE_DESCRIPTION("Marvell OcteonTX2 CPT Virtual Function Driver");
+MODULE_DESCRIPTION("Marvell RVU CPT Virtual Function Driver");
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(pci, otx2_cptvf_id_table);
diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_mbox.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_mbox.c
index 5d73b711cba6..02cb9e44afd8 100644
--- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_mbox.c
+++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_mbox.c
@@ -5,6 +5,48 @@
#include "otx2_cptvf.h"
#include <rvu_reg.h>
+int otx2_cpt_mbox_bbuf_init(struct otx2_cptvf_dev *cptvf, struct pci_dev *pdev)
+{
+ struct otx2_mbox_dev *mdev;
+ struct otx2_mbox *otx2_mbox;
+
+ cptvf->bbuf_base = devm_kmalloc(&pdev->dev, MBOX_SIZE, GFP_KERNEL);
+ if (!cptvf->bbuf_base)
+ return -ENOMEM;
+ /*
+ * Overwrite mbox mbase to point to bounce buffer, so that PF/VF
+ * prepare all mbox messages in bounce buffer instead of directly
+ * in hw mbox memory.
+ */
+ otx2_mbox = &cptvf->pfvf_mbox;
+ mdev = &otx2_mbox->dev[0];
+ mdev->mbase = cptvf->bbuf_base;
+
+ return 0;
+}
+
+static void otx2_cpt_sync_mbox_bbuf(struct otx2_mbox *mbox, int devid)
+{
+ u16 msgs_offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
+ void *hw_mbase = mbox->hwbase + (devid * MBOX_SIZE);
+ struct otx2_mbox_dev *mdev = &mbox->dev[devid];
+ struct mbox_hdr *hdr;
+ u64 msg_size;
+
+ if (mdev->mbase == hw_mbase)
+ return;
+
+ hdr = hw_mbase + mbox->rx_start;
+ msg_size = hdr->msg_size;
+
+ if (msg_size > mbox->rx_size - msgs_offset)
+ msg_size = mbox->rx_size - msgs_offset;
+
+ /* Copy mbox messages from mbox memory to bounce buffer */
+ memcpy(mdev->mbase + mbox->rx_start,
+ hw_mbase + mbox->rx_start, msg_size + msgs_offset);
+}
+
irqreturn_t otx2_cptvf_pfvf_mbox_intr(int __always_unused irq, void *arg)
{
struct otx2_cptvf_dev *cptvf = arg;
@@ -106,6 +148,7 @@ void otx2_cptvf_pfvf_mbox_handler(struct work_struct *work)
cptvf = container_of(work, struct otx2_cptvf_dev, pfvf_mbox_work);
pfvf_mbox = &cptvf->pfvf_mbox;
+ otx2_cpt_sync_mbox_bbuf(pfvf_mbox, 0);
mdev = &pfvf_mbox->dev[0];
rsp_hdr = (struct mbox_hdr *)(mdev->mbase + pfvf_mbox->rx_start);
if (rsp_hdr->num_msgs == 0)
diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c
index d5c1c1b7c7e4..811ded72ce5f 100644
--- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c
+++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c
@@ -320,7 +320,7 @@ static int process_request(struct pci_dev *pdev, struct otx2_cpt_req_info *req,
cpt_req->dlen, false);
/* Send CPT command */
- otx2_cpt_send_cmd(&cptinst, 1, lf);
+ lf->lfs->ops->send_cmd(&cptinst, 1, lf);
/*
* We allocate and prepare pending queue entry in critical section
@@ -349,13 +349,14 @@ int otx2_cpt_do_request(struct pci_dev *pdev, struct otx2_cpt_req_info *req,
&lfs->lf[cpu_num]);
}
-static int cpt_process_ccode(struct pci_dev *pdev,
+static int cpt_process_ccode(struct otx2_cptlfs_info *lfs,
union otx2_cpt_res_s *cpt_status,
struct otx2_cpt_inst_info *info,
u32 *res_code)
{
- u8 uc_ccode = cpt_status->s.uc_compcode;
- u8 ccode = cpt_status->s.compcode;
+ u8 uc_ccode = lfs->ops->cpt_get_uc_compcode(cpt_status);
+ u8 ccode = lfs->ops->cpt_get_compcode(cpt_status);
+ struct pci_dev *pdev = lfs->pdev;
switch (ccode) {
case OTX2_CPT_COMP_E_FAULT:
@@ -389,6 +390,7 @@ static int cpt_process_ccode(struct pci_dev *pdev,
return 1;
case OTX2_CPT_COMP_E_GOOD:
+ case OTX2_CPT_COMP_E_WARN:
/*
* Check microcode completion code, it is only valid
* when completion code is CPT_COMP_E::GOOD
@@ -426,7 +428,7 @@ static int cpt_process_ccode(struct pci_dev *pdev,
return 0;
}
-static inline void process_pending_queue(struct pci_dev *pdev,
+static inline void process_pending_queue(struct otx2_cptlfs_info *lfs,
struct otx2_cpt_pending_queue *pqueue)
{
struct otx2_cpt_pending_entry *resume_pentry = NULL;
@@ -436,6 +438,7 @@ static inline void process_pending_queue(struct pci_dev *pdev,
struct otx2_cpt_inst_info *info = NULL;
struct otx2_cpt_req_info *req = NULL;
struct crypto_async_request *areq;
+ struct pci_dev *pdev = lfs->pdev;
u32 res_code, resume_index;
while (1) {
@@ -476,7 +479,7 @@ static inline void process_pending_queue(struct pci_dev *pdev,
goto process_pentry;
}
- if (cpt_process_ccode(pdev, cpt_status, info, &res_code)) {
+ if (cpt_process_ccode(lfs, cpt_status, info, &res_code)) {
spin_unlock_bh(&pqueue->lock);
return;
}
@@ -529,7 +532,7 @@ process_pentry:
void otx2_cpt_post_process(struct otx2_cptlf_wqe *wqe)
{
- process_pending_queue(wqe->lfs->pdev,
+ process_pending_queue(wqe->lfs,
&wqe->lfs->lf[wqe->lf_num].pqueue);
}
diff --git a/drivers/crypto/nx/Kconfig b/drivers/crypto/nx/Kconfig
index 23e3d0160e67..2a35e0e785bd 100644
--- a/drivers/crypto/nx/Kconfig
+++ b/drivers/crypto/nx/Kconfig
@@ -29,6 +29,7 @@ if CRYPTO_DEV_NX_COMPRESS
config CRYPTO_DEV_NX_COMPRESS_PSERIES
tristate "Compression acceleration support on pSeries platform"
depends on PPC_PSERIES && IBMVIO
+ depends on PPC_VAS
default y
help
Support for PowerPC Nest (NX) compression acceleration. This
diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile
index bc89a20e5d9d..d00181a26dd6 100644
--- a/drivers/crypto/nx/Makefile
+++ b/drivers/crypto/nx/Makefile
@@ -14,5 +14,5 @@ nx-crypto-objs := nx.o \
obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_PSERIES) += nx-compress-pseries.o nx-compress.o
obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_POWERNV) += nx-compress-powernv.o nx-compress.o
nx-compress-objs := nx-842.o
-nx-compress-pseries-objs := nx-842-pseries.o
+nx-compress-pseries-objs := nx-common-pseries.o
nx-compress-powernv-objs := nx-common-powernv.o
diff --git a/drivers/crypto/nx/nx-aes-cbc.c b/drivers/crypto/nx/nx-aes-cbc.c
index d6314ea9ae89..0e440f704a8f 100644
--- a/drivers/crypto/nx/nx-aes-cbc.c
+++ b/drivers/crypto/nx/nx-aes-cbc.c
@@ -88,7 +88,7 @@ static int cbc_aes_nx_crypt(struct skcipher_request *req,
memcpy(req->iv, csbcpb->cpb.aes_cbc.cv, AES_BLOCK_SIZE);
atomic_inc(&(nx_ctx->stats->aes_ops));
- atomic64_add(csbcpb->csb.processed_byte_count,
+ atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
&(nx_ctx->stats->aes_bytes));
processed += to_process;
diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c
index e7384d107573..3793885f928d 100644
--- a/drivers/crypto/nx/nx-aes-ccm.c
+++ b/drivers/crypto/nx/nx-aes-ccm.c
@@ -391,7 +391,7 @@ static int ccm_nx_decrypt(struct aead_request *req,
/* update stats */
atomic_inc(&(nx_ctx->stats->aes_ops));
- atomic64_add(csbcpb->csb.processed_byte_count,
+ atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
&(nx_ctx->stats->aes_bytes));
processed += to_process;
@@ -460,7 +460,7 @@ static int ccm_nx_encrypt(struct aead_request *req,
/* update stats */
atomic_inc(&(nx_ctx->stats->aes_ops));
- atomic64_add(csbcpb->csb.processed_byte_count,
+ atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
&(nx_ctx->stats->aes_bytes));
processed += to_process;
diff --git a/drivers/crypto/nx/nx-aes-ctr.c b/drivers/crypto/nx/nx-aes-ctr.c
index 13f518802343..dfa3ad1a12f2 100644
--- a/drivers/crypto/nx/nx-aes-ctr.c
+++ b/drivers/crypto/nx/nx-aes-ctr.c
@@ -102,7 +102,7 @@ static int ctr_aes_nx_crypt(struct skcipher_request *req, u8 *iv)
memcpy(iv, csbcpb->cpb.aes_cbc.cv, AES_BLOCK_SIZE);
atomic_inc(&(nx_ctx->stats->aes_ops));
- atomic64_add(csbcpb->csb.processed_byte_count,
+ atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
&(nx_ctx->stats->aes_bytes));
processed += to_process;
@@ -118,7 +118,7 @@ static int ctr3686_aes_nx_crypt(struct skcipher_request *req)
struct nx_crypto_ctx *nx_ctx = crypto_skcipher_ctx(tfm);
u8 iv[16];
- memcpy(iv, nx_ctx->priv.ctr.nonce, CTR_RFC3686_IV_SIZE);
+ memcpy(iv, nx_ctx->priv.ctr.nonce, CTR_RFC3686_NONCE_SIZE);
memcpy(iv + CTR_RFC3686_NONCE_SIZE, req->iv, CTR_RFC3686_IV_SIZE);
iv[12] = iv[13] = iv[14] = 0;
iv[15] = 1;
diff --git a/drivers/crypto/nx/nx-aes-ecb.c b/drivers/crypto/nx/nx-aes-ecb.c
index 7a729dc2bc17..502a565074e9 100644
--- a/drivers/crypto/nx/nx-aes-ecb.c
+++ b/drivers/crypto/nx/nx-aes-ecb.c
@@ -86,7 +86,7 @@ static int ecb_aes_nx_crypt(struct skcipher_request *req,
goto out;
atomic_inc(&(nx_ctx->stats->aes_ops));
- atomic64_add(csbcpb->csb.processed_byte_count,
+ atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
&(nx_ctx->stats->aes_bytes));
processed += to_process;
diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c
index fc9baca13920..4a796318b430 100644
--- a/drivers/crypto/nx/nx-aes-gcm.c
+++ b/drivers/crypto/nx/nx-aes-gcm.c
@@ -382,7 +382,7 @@ static int gcm_aes_nx_crypt(struct aead_request *req, int enc,
NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
atomic_inc(&(nx_ctx->stats->aes_ops));
- atomic64_add(csbcpb->csb.processed_byte_count,
+ atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
&(nx_ctx->stats->aes_bytes));
processed += to_process;
diff --git a/drivers/crypto/nx/nx-common-powernv.c b/drivers/crypto/nx/nx-common-powernv.c
index 446f611726df..32a036ada5d0 100644
--- a/drivers/crypto/nx/nx-common-powernv.c
+++ b/drivers/crypto/nx/nx-common-powernv.c
@@ -660,8 +660,8 @@ static int nx842_powernv_compress(const unsigned char *in, unsigned int inlen,
* @inlen: input buffer size
* @out: output buffer pointer
* @outlenp: output buffer size pointer
- * @workmem: working memory buffer pointer, size determined by
- * nx842_powernv_driver.workmem_size
+ * @wmem: working memory buffer pointer, size determined by
+ * nx842_powernv_driver.workmem_size
*
* Returns: see @nx842_powernv_exec()
*/
@@ -1092,8 +1092,8 @@ static __init int nx_compress_powernv_init(void)
* normal FIFO priority is assigned for userspace.
* 842 compression is supported only in kernel.
*/
- ret = vas_register_coproc_api(THIS_MODULE, VAS_COP_TYPE_GZIP,
- "nx-gzip");
+ ret = vas_register_api_powernv(THIS_MODULE, VAS_COP_TYPE_GZIP,
+ "nx-gzip");
/*
* GZIP is not supported in kernel right now.
@@ -1129,7 +1129,7 @@ static void __exit nx_compress_powernv_exit(void)
* use. So delete this API use for GZIP engine.
*/
if (!nx842_ct)
- vas_unregister_coproc_api();
+ vas_unregister_api_powernv();
crypto_unregister_alg(&nx842_powernv_alg);
diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-common-pseries.c
index cc8dd3072b8b..4e304f6081e4 100644
--- a/drivers/crypto/nx/nx-842-pseries.c
+++ b/drivers/crypto/nx/nx-common-pseries.c
@@ -9,6 +9,8 @@
*/
#include <asm/vio.h>
+#include <asm/hvcall.h>
+#include <asm/vas.h>
#include "nx-842.h"
#include "nx_csbcpb.h" /* struct nx_csbcpb */
@@ -19,6 +21,29 @@ MODULE_DESCRIPTION("842 H/W Compression driver for IBM Power processors");
MODULE_ALIAS_CRYPTO("842");
MODULE_ALIAS_CRYPTO("842-nx");
+/*
+ * Coprocessor type specific capabilities from the hypervisor.
+ */
+struct hv_nx_cop_caps {
+ __be64 descriptor;
+ __be64 req_max_processed_len; /* Max bytes in one GZIP request */
+ __be64 min_compress_len; /* Min compression size in bytes */
+ __be64 min_decompress_len; /* Min decompression size in bytes */
+} __packed __aligned(0x1000);
+
+/*
+ * Coprocessor type specific capabilities.
+ */
+struct nx_cop_caps {
+ u64 descriptor;
+ u64 req_max_processed_len; /* Max bytes in one GZIP request */
+ u64 min_compress_len; /* Min compression in bytes */
+ u64 min_decompress_len; /* Min decompression in bytes */
+};
+
+static u64 caps_feat;
+static struct nx_cop_caps nx_cop_caps;
+
static struct nx842_constraints nx842_pseries_constraints = {
.alignment = DDE_BUFFER_ALIGN,
.multiple = DDE_BUFFER_LAST_MULT,
@@ -264,8 +289,8 @@ static int nx842_validate_result(struct device *dev,
* @inlen: Length of input buffer
* @out: Pointer to output buffer
* @outlen: Length of output buffer
- * @wrkmem: ptr to buffer for working memory, size determined by
- * nx842_pseries_driver.workmem_size
+ * @wmem: ptr to buffer for working memory, size determined by
+ * nx842_pseries_driver.workmem_size
*
* Returns:
* 0 Success, output of length @outlen stored in the buffer at @out
@@ -393,8 +418,8 @@ unlock:
* @inlen: Length of input buffer
* @out: Pointer to output buffer
* @outlen: Length of output buffer
- * @wrkmem: ptr to buffer for working memory, size determined by
- * nx842_pseries_driver.workmem_size
+ * @wmem: ptr to buffer for working memory, size determined by
+ * nx842_pseries_driver.workmem_size
*
* Returns:
* 0 Success, output of length @outlen stored in the buffer at @out
@@ -513,7 +538,7 @@ unlock:
/**
* nx842_OF_set_defaults -- Set default (disabled) values for devdata
*
- * @devdata - struct nx842_devdata to update
+ * @devdata: struct nx842_devdata to update
*
* Returns:
* 0 on success
@@ -538,13 +563,15 @@ static int nx842_OF_set_defaults(struct nx842_devdata *devdata)
* The status field indicates if the device is enabled when the status
* is 'okay'. Otherwise the device driver will be disabled.
*
- * @prop - struct property point containing the maxsyncop for the update
+ * @devdata: struct nx842_devdata to use for dev_info
+ * @prop: struct property point containing the maxsyncop for the update
*
* Returns:
* 0 - Device is available
* -ENODEV - Device is not available
*/
-static int nx842_OF_upd_status(struct property *prop)
+static int nx842_OF_upd_status(struct nx842_devdata *devdata,
+ struct property *prop)
{
const char *status = (const char *)prop->value;
@@ -571,8 +598,8 @@ static int nx842_OF_upd_status(struct property *prop)
* In this example, the maximum byte length of a scatter list is
* 0x0ff0 (4,080).
*
- * @devdata - struct nx842_devdata to update
- * @prop - struct property point containing the maxsyncop for the update
+ * @devdata: struct nx842_devdata to update
+ * @prop: struct property point containing the maxsyncop for the update
*
* Returns:
* 0 on success
@@ -619,8 +646,8 @@ static int nx842_OF_upd_maxsglen(struct nx842_devdata *devdata,
* 0x1000 (4,096) data byte length and 0x1f3 (510) total scatter list
* elements.
*
- * @devdata - struct nx842_devdata to update
- * @prop - struct property point containing the maxsyncop for the update
+ * @devdata: struct nx842_devdata to update
+ * @prop: struct property point containing the maxsyncop for the update
*
* Returns:
* 0 on success
@@ -689,7 +716,6 @@ out:
}
/**
- *
* nx842_OF_upd -- Handle OF properties updates for the device.
*
* Set all properties from the OF tree. Optionally, a new property
@@ -758,7 +784,7 @@ static int nx842_OF_upd(struct property *new_prop)
goto out;
/* Perform property updates */
- ret = nx842_OF_upd_status(status);
+ ret = nx842_OF_upd_status(new_devdata, status);
if (ret)
goto error_out;
@@ -812,8 +838,7 @@ error_out:
*
* @np: notifier block
* @action: notifier action
- * @update: struct pSeries_reconfig_prop_update pointer if action is
- * PSERIES_UPDATE_PROPERTY
+ * @data: struct of_reconfig_data pointer
*
* Returns:
* NOTIFY_OK on success
@@ -942,6 +967,36 @@ static struct attribute_group nx842_attribute_group = {
.attrs = nx842_sysfs_entries,
};
+#define nxcop_caps_read(_name) \
+static ssize_t nxcop_##_name##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ return sprintf(buf, "%lld\n", nx_cop_caps._name); \
+}
+
+#define NXCT_ATTR_RO(_name) \
+ nxcop_caps_read(_name); \
+ static struct device_attribute dev_attr_##_name = __ATTR(_name, \
+ 0444, \
+ nxcop_##_name##_show, \
+ NULL);
+
+NXCT_ATTR_RO(req_max_processed_len);
+NXCT_ATTR_RO(min_compress_len);
+NXCT_ATTR_RO(min_decompress_len);
+
+static struct attribute *nxcop_caps_sysfs_entries[] = {
+ &dev_attr_req_max_processed_len.attr,
+ &dev_attr_min_compress_len.attr,
+ &dev_attr_min_decompress_len.attr,
+ NULL,
+};
+
+static struct attribute_group nxcop_caps_attr_group = {
+ .name = "nx_gzip_caps",
+ .attrs = nxcop_caps_sysfs_entries,
+};
+
static struct nx842_driver nx842_pseries_driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
@@ -1031,6 +1086,16 @@ static int nx842_probe(struct vio_dev *viodev,
goto error;
}
+ if (caps_feat) {
+ if (sysfs_create_group(&viodev->dev.kobj,
+ &nxcop_caps_attr_group)) {
+ dev_err(&viodev->dev,
+ "Could not create sysfs NX capability entries\n");
+ ret = -1;
+ goto error;
+ }
+ }
+
return 0;
error_unlock:
@@ -1050,6 +1115,9 @@ static void nx842_remove(struct vio_dev *viodev)
pr_info("Removing IBM Power 842 compression device\n");
sysfs_remove_group(&viodev->dev.kobj, &nx842_attribute_group);
+ if (caps_feat)
+ sysfs_remove_group(&viodev->dev.kobj, &nxcop_caps_attr_group);
+
crypto_unregister_alg(&nx842_pseries_alg);
spin_lock_irqsave(&devdata_mutex, flags);
@@ -1065,10 +1133,69 @@ static void nx842_remove(struct vio_dev *viodev)
kfree(old_devdata);
}
+/*
+ * Get NX capabilities from the hypervisor.
+ * Only NXGZIP capabilities are provided by the hypersvisor right
+ * now and these values are available to user space with sysfs.
+ */
+static void __init nxcop_get_capabilities(void)
+{
+ struct hv_vas_all_caps *hv_caps;
+ struct hv_nx_cop_caps *hv_nxc;
+ int rc;
+
+ hv_caps = kmalloc(sizeof(*hv_caps), GFP_KERNEL);
+ if (!hv_caps)
+ return;
+ /*
+ * Get NX overall capabilities with feature type=0
+ */
+ rc = h_query_vas_capabilities(H_QUERY_NX_CAPABILITIES, 0,
+ (u64)virt_to_phys(hv_caps));
+ if (rc)
+ goto out;
+
+ caps_feat = be64_to_cpu(hv_caps->feat_type);
+ /*
+ * NX-GZIP feature available
+ */
+ if (caps_feat & VAS_NX_GZIP_FEAT_BIT) {
+ hv_nxc = kmalloc(sizeof(*hv_nxc), GFP_KERNEL);
+ if (!hv_nxc)
+ goto out;
+ /*
+ * Get capabilities for NX-GZIP feature
+ */
+ rc = h_query_vas_capabilities(H_QUERY_NX_CAPABILITIES,
+ VAS_NX_GZIP_FEAT,
+ (u64)virt_to_phys(hv_nxc));
+ } else {
+ pr_err("NX-GZIP feature is not available\n");
+ rc = -EINVAL;
+ }
+
+ if (!rc) {
+ nx_cop_caps.descriptor = be64_to_cpu(hv_nxc->descriptor);
+ nx_cop_caps.req_max_processed_len =
+ be64_to_cpu(hv_nxc->req_max_processed_len);
+ nx_cop_caps.min_compress_len =
+ be64_to_cpu(hv_nxc->min_compress_len);
+ nx_cop_caps.min_decompress_len =
+ be64_to_cpu(hv_nxc->min_decompress_len);
+ } else {
+ caps_feat = 0;
+ }
+
+ kfree(hv_nxc);
+out:
+ kfree(hv_caps);
+}
+
static const struct vio_device_id nx842_vio_driver_ids[] = {
{"ibm,compression-v1", "ibm,compression"},
{"", ""},
};
+MODULE_DEVICE_TABLE(vio, nx842_vio_driver_ids);
static struct vio_driver nx842_vio_driver = {
.name = KBUILD_MODNAME,
@@ -1092,6 +1219,10 @@ static int __init nx842_pseries_init(void)
return -ENOMEM;
RCU_INIT_POINTER(devdata, new_devdata);
+ /*
+ * Get NX capabilities from the hypervisor.
+ */
+ nxcop_get_capabilities();
ret = vio_register_driver(&nx842_vio_driver);
if (ret) {
@@ -1101,6 +1232,12 @@ static int __init nx842_pseries_init(void)
return ret;
}
+ ret = vas_register_api_pseries(THIS_MODULE, VAS_COP_TYPE_GZIP,
+ "nx-gzip");
+
+ if (ret)
+ pr_err("NX-GZIP is not supported. Returned=%d\n", ret);
+
return 0;
}
@@ -1111,6 +1248,8 @@ static void __exit nx842_pseries_exit(void)
struct nx842_devdata *old_devdata;
unsigned long flags;
+ vas_unregister_api_pseries();
+
crypto_unregister_alg(&nx842_pseries_alg);
spin_lock_irqsave(&devdata_mutex, flags);
diff --git a/drivers/crypto/nx/nx-sha256.c b/drivers/crypto/nx/nx-sha256.c
index b0ad665e4bda..c3bebf0feabe 100644
--- a/drivers/crypto/nx/nx-sha256.c
+++ b/drivers/crypto/nx/nx-sha256.c
@@ -16,6 +16,11 @@
#include "nx_csbcpb.h"
#include "nx.h"
+struct sha256_state_be {
+ __be32 state[SHA256_DIGEST_SIZE / 4];
+ u64 count;
+ u8 buf[SHA256_BLOCK_SIZE];
+};
static int nx_crypto_ctx_sha256_init(struct crypto_tfm *tfm)
{
@@ -36,7 +41,7 @@ static int nx_crypto_ctx_sha256_init(struct crypto_tfm *tfm)
}
static int nx_sha256_init(struct shash_desc *desc) {
- struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct sha256_state_be *sctx = shash_desc_ctx(desc);
memset(sctx, 0, sizeof *sctx);
@@ -56,7 +61,7 @@ static int nx_sha256_init(struct shash_desc *desc) {
static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
unsigned int len)
{
- struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct sha256_state_be *sctx = shash_desc_ctx(desc);
struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
struct nx_sg *out_sg;
@@ -175,7 +180,7 @@ out:
static int nx_sha256_final(struct shash_desc *desc, u8 *out)
{
- struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct sha256_state_be *sctx = shash_desc_ctx(desc);
struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
struct nx_sg *in_sg, *out_sg;
@@ -245,7 +250,7 @@ out:
static int nx_sha256_export(struct shash_desc *desc, void *out)
{
- struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct sha256_state_be *sctx = shash_desc_ctx(desc);
memcpy(out, sctx, sizeof(*sctx));
@@ -254,7 +259,7 @@ static int nx_sha256_export(struct shash_desc *desc, void *out)
static int nx_sha256_import(struct shash_desc *desc, const void *in)
{
- struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct sha256_state_be *sctx = shash_desc_ctx(desc);
memcpy(sctx, in, sizeof(*sctx));
@@ -268,8 +273,8 @@ struct shash_alg nx_shash_sha256_alg = {
.final = nx_sha256_final,
.export = nx_sha256_export,
.import = nx_sha256_import,
- .descsize = sizeof(struct sha256_state),
- .statesize = sizeof(struct sha256_state),
+ .descsize = sizeof(struct sha256_state_be),
+ .statesize = sizeof(struct sha256_state_be),
.base = {
.cra_name = "sha256",
.cra_driver_name = "sha256-nx",
diff --git a/drivers/crypto/nx/nx-sha512.c b/drivers/crypto/nx/nx-sha512.c
index c29103a1a0b6..1ffb40d2c324 100644
--- a/drivers/crypto/nx/nx-sha512.c
+++ b/drivers/crypto/nx/nx-sha512.c
@@ -15,6 +15,11 @@
#include "nx_csbcpb.h"
#include "nx.h"
+struct sha512_state_be {
+ __be64 state[SHA512_DIGEST_SIZE / 8];
+ u64 count[2];
+ u8 buf[SHA512_BLOCK_SIZE];
+};
static int nx_crypto_ctx_sha512_init(struct crypto_tfm *tfm)
{
@@ -36,7 +41,7 @@ static int nx_crypto_ctx_sha512_init(struct crypto_tfm *tfm)
static int nx_sha512_init(struct shash_desc *desc)
{
- struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct sha512_state_be *sctx = shash_desc_ctx(desc);
memset(sctx, 0, sizeof *sctx);
@@ -56,7 +61,7 @@ static int nx_sha512_init(struct shash_desc *desc)
static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
unsigned int len)
{
- struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct sha512_state_be *sctx = shash_desc_ctx(desc);
struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
struct nx_sg *out_sg;
@@ -178,7 +183,7 @@ out:
static int nx_sha512_final(struct shash_desc *desc, u8 *out)
{
- struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct sha512_state_be *sctx = shash_desc_ctx(desc);
struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
struct nx_sg *in_sg, *out_sg;
@@ -251,7 +256,7 @@ out:
static int nx_sha512_export(struct shash_desc *desc, void *out)
{
- struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct sha512_state_be *sctx = shash_desc_ctx(desc);
memcpy(out, sctx, sizeof(*sctx));
@@ -260,7 +265,7 @@ static int nx_sha512_export(struct shash_desc *desc, void *out)
static int nx_sha512_import(struct shash_desc *desc, const void *in)
{
- struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct sha512_state_be *sctx = shash_desc_ctx(desc);
memcpy(sctx, in, sizeof(*sctx));
@@ -274,8 +279,8 @@ struct shash_alg nx_shash_sha512_alg = {
.final = nx_sha512_final,
.export = nx_sha512_export,
.import = nx_sha512_import,
- .descsize = sizeof(struct sha512_state),
- .statesize = sizeof(struct sha512_state),
+ .descsize = sizeof(struct sha512_state_be),
+ .statesize = sizeof(struct sha512_state_be),
.base = {
.cra_name = "sha512",
.cra_driver_name = "sha512-nx",
diff --git a/drivers/crypto/nx/nx_csbcpb.h b/drivers/crypto/nx/nx_csbcpb.h
index 493f8490ff94..e64f7e36fb92 100644
--- a/drivers/crypto/nx/nx_csbcpb.h
+++ b/drivers/crypto/nx/nx_csbcpb.h
@@ -140,8 +140,8 @@ struct cop_status_block {
u8 crb_seq_number;
u8 completion_code;
u8 completion_extension;
- u32 processed_byte_count;
- u64 address;
+ __be32 processed_byte_count;
+ __be64 address;
} __packed;
/* Nest accelerator workbook section 4.4 */
diff --git a/drivers/crypto/omap-crypto.c b/drivers/crypto/omap-crypto.c
index 94b2dba90f0d..31bdb1d76d11 100644
--- a/drivers/crypto/omap-crypto.c
+++ b/drivers/crypto/omap-crypto.c
@@ -183,8 +183,7 @@ static void omap_crypto_copy_data(struct scatterlist *src,
memcpy(dstb, srcb, amt);
- if (!PageSlab(sg_page(dst)))
- flush_kernel_dcache_page(sg_page(dst));
+ flush_dcache_page(sg_page(dst));
kunmap_atomic(srcb);
kunmap_atomic(dstb);
diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c
index c9d38bcfd1c7..bc8631363d72 100644
--- a/drivers/crypto/omap-des.c
+++ b/drivers/crypto/omap-des.c
@@ -229,9 +229,8 @@ static int omap_des_hw_init(struct omap_des_dev *dd)
* It may be long delays between requests.
* Device might go to off mode to save power.
*/
- err = pm_runtime_get_sync(dd->dev);
+ err = pm_runtime_resume_and_get(dd->dev);
if (err < 0) {
- pm_runtime_put_noidle(dd->dev);
dev_err(dd->dev, "%s: failed to get_sync(%d)\n", __func__, err);
return err;
}
@@ -994,9 +993,8 @@ static int omap_des_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(dev, DEFAULT_AUTOSUSPEND_DELAY);
pm_runtime_enable(dev);
- err = pm_runtime_get_sync(dev);
+ err = pm_runtime_resume_and_get(dev);
if (err < 0) {
- pm_runtime_put_noidle(dev);
dev_err(dd->dev, "%s: failed to get_sync(%d)\n", __func__, err);
goto err_get;
}
@@ -1124,9 +1122,8 @@ static int omap_des_resume(struct device *dev)
{
int err;
- err = pm_runtime_get_sync(dev);
+ err = pm_runtime_resume_and_get(dev);
if (err < 0) {
- pm_runtime_put_noidle(dev);
dev_err(dev, "%s: failed to get_sync(%d)\n", __func__, err);
return err;
}
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index ae0d320d3c60..dd53ad9987b0 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -372,7 +372,7 @@ static int omap_sham_hw_init(struct omap_sham_dev *dd)
{
int err;
- err = pm_runtime_get_sync(dd->dev);
+ err = pm_runtime_resume_and_get(dd->dev);
if (err < 0) {
dev_err(dd->dev, "failed to get sync: %d\n", err);
return err;
@@ -2244,7 +2244,7 @@ static int omap_sham_suspend(struct device *dev)
static int omap_sham_resume(struct device *dev)
{
- int err = pm_runtime_get_sync(dev);
+ int err = pm_runtime_resume_and_get(dev);
if (err < 0) {
dev_err(dev, "failed to get sync: %d\n", err);
return err;
diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c
index 96b437bfe3de..6f64aa693146 100644
--- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c
+++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c
@@ -406,7 +406,7 @@ static long adf_ctl_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
ret = adf_ctl_ioctl_get_status(fp, cmd, arg);
break;
default:
- pr_err("QAT: Invalid ioctl\n");
+ pr_err_ratelimited("QAT: Invalid ioctl %d\n", cmd);
ret = -EFAULT;
break;
}
diff --git a/drivers/crypto/qat/qat_common/icp_qat_fw_loader_handle.h b/drivers/crypto/qat/qat_common/icp_qat_fw_loader_handle.h
index b8f3463be6ef..7eb5daef4f88 100644
--- a/drivers/crypto/qat/qat_common/icp_qat_fw_loader_handle.h
+++ b/drivers/crypto/qat/qat_common/icp_qat_fw_loader_handle.h
@@ -24,7 +24,7 @@ struct icp_qat_fw_loader_hal_handle {
};
struct icp_qat_fw_loader_chip_info {
- bool sram_visible;
+ int mmp_sram_size;
bool nn;
bool lm2lm3;
u32 lm_size;
diff --git a/drivers/crypto/qat/qat_common/qat_hal.c b/drivers/crypto/qat/qat_common/qat_hal.c
index bd3028126cbe..12ca6b8764aa 100644
--- a/drivers/crypto/qat/qat_common/qat_hal.c
+++ b/drivers/crypto/qat/qat_common/qat_hal.c
@@ -696,7 +696,7 @@ static int qat_hal_chip_init(struct icp_qat_fw_loader_handle *handle,
handle->pci_dev = pci_info->pci_dev;
switch (handle->pci_dev->device) {
case ADF_4XXX_PCI_DEVICE_ID:
- handle->chip_info->sram_visible = false;
+ handle->chip_info->mmp_sram_size = 0;
handle->chip_info->nn = false;
handle->chip_info->lm2lm3 = true;
handle->chip_info->lm_size = ICP_QAT_UCLO_MAX_LMEM_REG_2X;
@@ -730,7 +730,7 @@ static int qat_hal_chip_init(struct icp_qat_fw_loader_handle *handle,
break;
case PCI_DEVICE_ID_INTEL_QAT_C62X:
case PCI_DEVICE_ID_INTEL_QAT_C3XXX:
- handle->chip_info->sram_visible = false;
+ handle->chip_info->mmp_sram_size = 0;
handle->chip_info->nn = true;
handle->chip_info->lm2lm3 = false;
handle->chip_info->lm_size = ICP_QAT_UCLO_MAX_LMEM_REG;
@@ -763,7 +763,7 @@ static int qat_hal_chip_init(struct icp_qat_fw_loader_handle *handle,
+ LOCAL_TO_XFER_REG_OFFSET);
break;
case PCI_DEVICE_ID_INTEL_QAT_DH895XCC:
- handle->chip_info->sram_visible = true;
+ handle->chip_info->mmp_sram_size = 0x40000;
handle->chip_info->nn = true;
handle->chip_info->lm2lm3 = false;
handle->chip_info->lm_size = ICP_QAT_UCLO_MAX_LMEM_REG;
@@ -800,7 +800,7 @@ static int qat_hal_chip_init(struct icp_qat_fw_loader_handle *handle,
goto out_err;
}
- if (handle->chip_info->sram_visible) {
+ if (handle->chip_info->mmp_sram_size > 0) {
sram_bar =
&pci_info->pci_bars[hw_data->get_sram_bar_id(hw_data)];
handle->hal_sram_addr_v = sram_bar->virt_addr;
@@ -1417,7 +1417,11 @@ static int qat_hal_put_rel_wr_xfer(struct icp_qat_fw_loader_handle *handle,
pr_err("QAT: bad xfrAddr=0x%x\n", xfr_addr);
return -EINVAL;
}
- qat_hal_rd_rel_reg(handle, ae, ctx, ICP_GPB_REL, gprnum, &gprval);
+ status = qat_hal_rd_rel_reg(handle, ae, ctx, ICP_GPB_REL, gprnum, &gprval);
+ if (status) {
+ pr_err("QAT: failed to read register");
+ return status;
+ }
gpr_addr = qat_hal_get_reg_addr(ICP_GPB_REL, gprnum);
data16low = 0xffff & data;
data16hi = 0xffff & (data >> 0x10);
diff --git a/drivers/crypto/qat/qat_common/qat_uclo.c b/drivers/crypto/qat/qat_common/qat_uclo.c
index 1fb5fc852f6b..2026cc6be8f0 100644
--- a/drivers/crypto/qat/qat_common/qat_uclo.c
+++ b/drivers/crypto/qat/qat_common/qat_uclo.c
@@ -342,7 +342,6 @@ static int qat_uclo_init_umem_seg(struct icp_qat_fw_loader_handle *handle,
return 0;
}
-#define ICP_DH895XCC_PESRAM_BAR_SIZE 0x80000
static int qat_uclo_init_ae_memory(struct icp_qat_fw_loader_handle *handle,
struct icp_qat_uof_initmem *init_mem)
{
@@ -1546,15 +1545,14 @@ int qat_uclo_wr_mimage(struct icp_qat_fw_loader_handle *handle,
int status = 0;
if (handle->chip_info->fw_auth) {
- if (!qat_uclo_map_auth_fw(handle, addr_ptr, mem_size, &desc))
+ status = qat_uclo_map_auth_fw(handle, addr_ptr, mem_size, &desc);
+ if (!status)
status = qat_uclo_auth_fw(handle, desc);
qat_uclo_ummap_auth_fw(handle, &desc);
} else {
- if (!handle->chip_info->sram_visible) {
- dev_dbg(&handle->pci_dev->dev,
- "QAT MMP fw not loaded for device 0x%x",
- handle->pci_dev->device);
- return status;
+ if (handle->chip_info->mmp_sram_size < mem_size) {
+ pr_err("QAT: MMP size is too large: 0x%x\n", mem_size);
+ return -EFBIG;
}
qat_uclo_wr_sram_by_words(handle, 0, addr_ptr, mem_size);
}
diff --git a/drivers/crypto/qce/Makefile b/drivers/crypto/qce/Makefile
index 14ade8a7d664..2cf8984e1b85 100644
--- a/drivers/crypto/qce/Makefile
+++ b/drivers/crypto/qce/Makefile
@@ -6,3 +6,4 @@ qcrypto-objs := core.o \
qcrypto-$(CONFIG_CRYPTO_DEV_QCE_SHA) += sha.o
qcrypto-$(CONFIG_CRYPTO_DEV_QCE_SKCIPHER) += skcipher.o
+qcrypto-$(CONFIG_CRYPTO_DEV_QCE_AEAD) += aead.o
diff --git a/drivers/crypto/qce/aead.c b/drivers/crypto/qce/aead.c
new file mode 100644
index 000000000000..290e2446a2f3
--- /dev/null
+++ b/drivers/crypto/qce/aead.c
@@ -0,0 +1,847 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (C) 2021, Linaro Limited. All rights reserved.
+ */
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <crypto/gcm.h>
+#include <crypto/authenc.h>
+#include <crypto/internal/aead.h>
+#include <crypto/internal/des.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
+#include <crypto/scatterwalk.h>
+#include "aead.h"
+
+#define CCM_NONCE_ADATA_SHIFT 6
+#define CCM_NONCE_AUTHSIZE_SHIFT 3
+#define MAX_CCM_ADATA_HEADER_LEN 6
+
+static LIST_HEAD(aead_algs);
+
+static void qce_aead_done(void *data)
+{
+ struct crypto_async_request *async_req = data;
+ struct aead_request *req = aead_request_cast(async_req);
+ struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+ struct qce_aead_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
+ struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req));
+ struct qce_device *qce = tmpl->qce;
+ struct qce_result_dump *result_buf = qce->dma.result_buf;
+ enum dma_data_direction dir_src, dir_dst;
+ bool diff_dst;
+ int error;
+ u32 status;
+ unsigned int totallen;
+ unsigned char tag[SHA256_DIGEST_SIZE] = {0};
+ int ret = 0;
+
+ diff_dst = (req->src != req->dst) ? true : false;
+ dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
+ dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
+
+ error = qce_dma_terminate_all(&qce->dma);
+ if (error)
+ dev_dbg(qce->dev, "aead dma termination error (%d)\n",
+ error);
+ if (diff_dst)
+ dma_unmap_sg(qce->dev, rctx->src_sg, rctx->src_nents, dir_src);
+
+ dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
+
+ if (IS_CCM(rctx->flags)) {
+ if (req->assoclen) {
+ sg_free_table(&rctx->src_tbl);
+ if (diff_dst)
+ sg_free_table(&rctx->dst_tbl);
+ } else {
+ if (!(IS_DECRYPT(rctx->flags) && !diff_dst))
+ sg_free_table(&rctx->dst_tbl);
+ }
+ } else {
+ sg_free_table(&rctx->dst_tbl);
+ }
+
+ error = qce_check_status(qce, &status);
+ if (error < 0 && (error != -EBADMSG))
+ dev_err(qce->dev, "aead operation error (%x)\n", status);
+
+ if (IS_ENCRYPT(rctx->flags)) {
+ totallen = req->cryptlen + req->assoclen;
+ if (IS_CCM(rctx->flags))
+ scatterwalk_map_and_copy(rctx->ccmresult_buf, req->dst,
+ totallen, ctx->authsize, 1);
+ else
+ scatterwalk_map_and_copy(result_buf->auth_iv, req->dst,
+ totallen, ctx->authsize, 1);
+
+ } else if (!IS_CCM(rctx->flags)) {
+ totallen = req->cryptlen + req->assoclen - ctx->authsize;
+ scatterwalk_map_and_copy(tag, req->src, totallen, ctx->authsize, 0);
+ ret = memcmp(result_buf->auth_iv, tag, ctx->authsize);
+ if (ret) {
+ pr_err("Bad message error\n");
+ error = -EBADMSG;
+ }
+ }
+
+ qce->async_req_done(qce, error);
+}
+
+static struct scatterlist *
+qce_aead_prepare_result_buf(struct sg_table *tbl, struct aead_request *req)
+{
+ struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+ struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req));
+ struct qce_device *qce = tmpl->qce;
+
+ sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ);
+ return qce_sgtable_add(tbl, &rctx->result_sg, QCE_RESULT_BUF_SZ);
+}
+
+static struct scatterlist *
+qce_aead_prepare_ccm_result_buf(struct sg_table *tbl, struct aead_request *req)
+{
+ struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+
+ sg_init_one(&rctx->result_sg, rctx->ccmresult_buf, QCE_BAM_BURST_SIZE);
+ return qce_sgtable_add(tbl, &rctx->result_sg, QCE_BAM_BURST_SIZE);
+}
+
+static struct scatterlist *
+qce_aead_prepare_dst_buf(struct aead_request *req)
+{
+ struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+ struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req));
+ struct qce_device *qce = tmpl->qce;
+ struct scatterlist *sg, *msg_sg, __sg[2];
+ gfp_t gfp;
+ unsigned int assoclen = req->assoclen;
+ unsigned int totallen;
+ int ret;
+
+ totallen = rctx->cryptlen + assoclen;
+ rctx->dst_nents = sg_nents_for_len(req->dst, totallen);
+ if (rctx->dst_nents < 0) {
+ dev_err(qce->dev, "Invalid numbers of dst SG.\n");
+ return ERR_PTR(-EINVAL);
+ }
+ if (IS_CCM(rctx->flags))
+ rctx->dst_nents += 2;
+ else
+ rctx->dst_nents += 1;
+
+ gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+ ret = sg_alloc_table(&rctx->dst_tbl, rctx->dst_nents, gfp);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (IS_CCM(rctx->flags) && assoclen) {
+ /* Get the dst buffer */
+ msg_sg = scatterwalk_ffwd(__sg, req->dst, assoclen);
+
+ sg = qce_sgtable_add(&rctx->dst_tbl, &rctx->adata_sg,
+ rctx->assoclen);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto dst_tbl_free;
+ }
+ /* dst buffer */
+ sg = qce_sgtable_add(&rctx->dst_tbl, msg_sg, rctx->cryptlen);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto dst_tbl_free;
+ }
+ totallen = rctx->cryptlen + rctx->assoclen;
+ } else {
+ if (totallen) {
+ sg = qce_sgtable_add(&rctx->dst_tbl, req->dst, totallen);
+ if (IS_ERR(sg))
+ goto dst_tbl_free;
+ }
+ }
+ if (IS_CCM(rctx->flags))
+ sg = qce_aead_prepare_ccm_result_buf(&rctx->dst_tbl, req);
+ else
+ sg = qce_aead_prepare_result_buf(&rctx->dst_tbl, req);
+
+ if (IS_ERR(sg))
+ goto dst_tbl_free;
+
+ sg_mark_end(sg);
+ rctx->dst_sg = rctx->dst_tbl.sgl;
+ rctx->dst_nents = sg_nents_for_len(rctx->dst_sg, totallen) + 1;
+
+ return sg;
+
+dst_tbl_free:
+ sg_free_table(&rctx->dst_tbl);
+ return sg;
+}
+
+static int
+qce_aead_ccm_prepare_buf_assoclen(struct aead_request *req)
+{
+ struct scatterlist *sg, *msg_sg, __sg[2];
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+ struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ unsigned int assoclen = rctx->assoclen;
+ unsigned int adata_header_len, cryptlen, totallen;
+ gfp_t gfp;
+ bool diff_dst;
+ int ret;
+
+ if (IS_DECRYPT(rctx->flags))
+ cryptlen = rctx->cryptlen + ctx->authsize;
+ else
+ cryptlen = rctx->cryptlen;
+ totallen = cryptlen + req->assoclen;
+
+ /* Get the msg */
+ msg_sg = scatterwalk_ffwd(__sg, req->src, req->assoclen);
+
+ rctx->adata = kzalloc((ALIGN(assoclen, 16) + MAX_CCM_ADATA_HEADER_LEN) *
+ sizeof(unsigned char), GFP_ATOMIC);
+ if (!rctx->adata)
+ return -ENOMEM;
+
+ /*
+ * Format associated data (RFC3610 and NIST 800-38C)
+ * Even though specification allows for AAD to be up to 2^64 - 1 bytes,
+ * the assoclen field in aead_request is unsigned int and thus limits
+ * the AAD to be up to 2^32 - 1 bytes. So we handle only two scenarios
+ * while forming the header for AAD.
+ */
+ if (assoclen < 0xff00) {
+ adata_header_len = 2;
+ *(__be16 *)rctx->adata = cpu_to_be16(assoclen);
+ } else {
+ adata_header_len = 6;
+ *(__be16 *)rctx->adata = cpu_to_be16(0xfffe);
+ *(__be32 *)(rctx->adata + 2) = cpu_to_be32(assoclen);
+ }
+
+ /* Copy the associated data */
+ if (sg_copy_to_buffer(req->src, sg_nents_for_len(req->src, assoclen),
+ rctx->adata + adata_header_len,
+ assoclen) != assoclen)
+ return -EINVAL;
+
+ /* Pad associated data to block size */
+ rctx->assoclen = ALIGN(assoclen + adata_header_len, 16);
+
+ diff_dst = (req->src != req->dst) ? true : false;
+
+ if (diff_dst)
+ rctx->src_nents = sg_nents_for_len(req->src, totallen) + 1;
+ else
+ rctx->src_nents = sg_nents_for_len(req->src, totallen) + 2;
+
+ gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC;
+ ret = sg_alloc_table(&rctx->src_tbl, rctx->src_nents, gfp);
+ if (ret)
+ return ret;
+
+ /* Associated Data */
+ sg_init_one(&rctx->adata_sg, rctx->adata, rctx->assoclen);
+ sg = qce_sgtable_add(&rctx->src_tbl, &rctx->adata_sg,
+ rctx->assoclen);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto err_free;
+ }
+ /* src msg */
+ sg = qce_sgtable_add(&rctx->src_tbl, msg_sg, cryptlen);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto err_free;
+ }
+ if (!diff_dst) {
+ /*
+ * For decrypt, when src and dst buffers are same, there is already space
+ * in the buffer for padded 0's which is output in lieu of
+ * the MAC that is input. So skip the below.
+ */
+ if (!IS_DECRYPT(rctx->flags)) {
+ sg = qce_aead_prepare_ccm_result_buf(&rctx->src_tbl, req);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto err_free;
+ }
+ }
+ }
+ sg_mark_end(sg);
+ rctx->src_sg = rctx->src_tbl.sgl;
+ totallen = cryptlen + rctx->assoclen;
+ rctx->src_nents = sg_nents_for_len(rctx->src_sg, totallen);
+
+ if (diff_dst) {
+ sg = qce_aead_prepare_dst_buf(req);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto err_free;
+ }
+ } else {
+ if (IS_ENCRYPT(rctx->flags))
+ rctx->dst_nents = rctx->src_nents + 1;
+ else
+ rctx->dst_nents = rctx->src_nents;
+ rctx->dst_sg = rctx->src_sg;
+ }
+
+ return 0;
+err_free:
+ sg_free_table(&rctx->src_tbl);
+ return ret;
+}
+
+static int qce_aead_prepare_buf(struct aead_request *req)
+{
+ struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+ struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req));
+ struct qce_device *qce = tmpl->qce;
+ struct scatterlist *sg;
+ bool diff_dst = (req->src != req->dst) ? true : false;
+ unsigned int totallen;
+
+ totallen = rctx->cryptlen + rctx->assoclen;
+
+ sg = qce_aead_prepare_dst_buf(req);
+ if (IS_ERR(sg))
+ return PTR_ERR(sg);
+ if (diff_dst) {
+ rctx->src_nents = sg_nents_for_len(req->src, totallen);
+ if (rctx->src_nents < 0) {
+ dev_err(qce->dev, "Invalid numbers of src SG.\n");
+ return -EINVAL;
+ }
+ rctx->src_sg = req->src;
+ } else {
+ rctx->src_nents = rctx->dst_nents - 1;
+ rctx->src_sg = rctx->dst_sg;
+ }
+ return 0;
+}
+
+static int qce_aead_ccm_prepare_buf(struct aead_request *req)
+{
+ struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct scatterlist *sg;
+ bool diff_dst = (req->src != req->dst) ? true : false;
+ unsigned int cryptlen;
+
+ if (rctx->assoclen)
+ return qce_aead_ccm_prepare_buf_assoclen(req);
+
+ if (IS_ENCRYPT(rctx->flags))
+ return qce_aead_prepare_buf(req);
+
+ cryptlen = rctx->cryptlen + ctx->authsize;
+ if (diff_dst) {
+ rctx->src_nents = sg_nents_for_len(req->src, cryptlen);
+ rctx->src_sg = req->src;
+ sg = qce_aead_prepare_dst_buf(req);
+ if (IS_ERR(sg))
+ return PTR_ERR(sg);
+ } else {
+ rctx->src_nents = sg_nents_for_len(req->src, cryptlen);
+ rctx->src_sg = req->src;
+ rctx->dst_nents = rctx->src_nents;
+ rctx->dst_sg = rctx->src_sg;
+ }
+
+ return 0;
+}
+
+static int qce_aead_create_ccm_nonce(struct qce_aead_reqctx *rctx, struct qce_aead_ctx *ctx)
+{
+ unsigned int msglen_size, ivsize;
+ u8 msg_len[4];
+ int i;
+
+ if (!rctx || !rctx->iv)
+ return -EINVAL;
+
+ msglen_size = rctx->iv[0] + 1;
+
+ /* Verify that msg len size is valid */
+ if (msglen_size < 2 || msglen_size > 8)
+ return -EINVAL;
+
+ ivsize = rctx->ivsize;
+
+ /*
+ * Clear the msglen bytes in IV.
+ * Else the h/w engine and nonce will use any stray value pending there.
+ */
+ if (!IS_CCM_RFC4309(rctx->flags)) {
+ for (i = 0; i < msglen_size; i++)
+ rctx->iv[ivsize - i - 1] = 0;
+ }
+
+ /*
+ * The crypto framework encodes cryptlen as unsigned int. Thus, even though
+ * spec allows for upto 8 bytes to encode msg_len only 4 bytes are needed.
+ */
+ if (msglen_size > 4)
+ msglen_size = 4;
+
+ memcpy(&msg_len[0], &rctx->cryptlen, 4);
+
+ memcpy(&rctx->ccm_nonce[0], rctx->iv, rctx->ivsize);
+ if (rctx->assoclen)
+ rctx->ccm_nonce[0] |= 1 << CCM_NONCE_ADATA_SHIFT;
+ rctx->ccm_nonce[0] |= ((ctx->authsize - 2) / 2) <<
+ CCM_NONCE_AUTHSIZE_SHIFT;
+ for (i = 0; i < msglen_size; i++)
+ rctx->ccm_nonce[QCE_MAX_NONCE - i - 1] = msg_len[i];
+
+ return 0;
+}
+
+static int
+qce_aead_async_req_handle(struct crypto_async_request *async_req)
+{
+ struct aead_request *req = aead_request_cast(async_req);
+ struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct qce_aead_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
+ struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req));
+ struct qce_device *qce = tmpl->qce;
+ enum dma_data_direction dir_src, dir_dst;
+ bool diff_dst;
+ int dst_nents, src_nents, ret;
+
+ if (IS_CCM_RFC4309(rctx->flags)) {
+ memset(rctx->ccm_rfc4309_iv, 0, QCE_MAX_IV_SIZE);
+ rctx->ccm_rfc4309_iv[0] = 3;
+ memcpy(&rctx->ccm_rfc4309_iv[1], ctx->ccm4309_salt, QCE_CCM4309_SALT_SIZE);
+ memcpy(&rctx->ccm_rfc4309_iv[4], req->iv, 8);
+ rctx->iv = rctx->ccm_rfc4309_iv;
+ rctx->ivsize = AES_BLOCK_SIZE;
+ } else {
+ rctx->iv = req->iv;
+ rctx->ivsize = crypto_aead_ivsize(tfm);
+ }
+ if (IS_CCM_RFC4309(rctx->flags))
+ rctx->assoclen = req->assoclen - 8;
+ else
+ rctx->assoclen = req->assoclen;
+
+ diff_dst = (req->src != req->dst) ? true : false;
+ dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
+ dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;
+
+ if (IS_CCM(rctx->flags)) {
+ ret = qce_aead_create_ccm_nonce(rctx, ctx);
+ if (ret)
+ return ret;
+ }
+ if (IS_CCM(rctx->flags))
+ ret = qce_aead_ccm_prepare_buf(req);
+ else
+ ret = qce_aead_prepare_buf(req);
+
+ if (ret)
+ return ret;
+ dst_nents = dma_map_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
+ if (dst_nents < 0) {
+ ret = dst_nents;
+ goto error_free;
+ }
+
+ if (diff_dst) {
+ src_nents = dma_map_sg(qce->dev, rctx->src_sg, rctx->src_nents, dir_src);
+ if (src_nents < 0) {
+ ret = src_nents;
+ goto error_unmap_dst;
+ }
+ } else {
+ if (IS_CCM(rctx->flags) && IS_DECRYPT(rctx->flags))
+ src_nents = dst_nents;
+ else
+ src_nents = dst_nents - 1;
+ }
+
+ ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, src_nents, rctx->dst_sg, dst_nents,
+ qce_aead_done, async_req);
+ if (ret)
+ goto error_unmap_src;
+
+ qce_dma_issue_pending(&qce->dma);
+
+ ret = qce_start(async_req, tmpl->crypto_alg_type);
+ if (ret)
+ goto error_terminate;
+
+ return 0;
+
+error_terminate:
+ qce_dma_terminate_all(&qce->dma);
+error_unmap_src:
+ if (diff_dst)
+ dma_unmap_sg(qce->dev, req->src, rctx->src_nents, dir_src);
+error_unmap_dst:
+ dma_unmap_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
+error_free:
+ if (IS_CCM(rctx->flags) && rctx->assoclen) {
+ sg_free_table(&rctx->src_tbl);
+ if (diff_dst)
+ sg_free_table(&rctx->dst_tbl);
+ } else {
+ sg_free_table(&rctx->dst_tbl);
+ }
+ return ret;
+}
+
+static int qce_aead_crypt(struct aead_request *req, int encrypt)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+ struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct qce_alg_template *tmpl = to_aead_tmpl(tfm);
+ unsigned int blocksize = crypto_aead_blocksize(tfm);
+
+ rctx->flags = tmpl->alg_flags;
+ rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT;
+
+ if (encrypt)
+ rctx->cryptlen = req->cryptlen;
+ else
+ rctx->cryptlen = req->cryptlen - ctx->authsize;
+
+ /* CE does not handle 0 length messages */
+ if (!rctx->cryptlen) {
+ if (!(IS_CCM(rctx->flags) && IS_DECRYPT(rctx->flags)))
+ ctx->need_fallback = true;
+ }
+
+ /* If fallback is needed, schedule and exit */
+ if (ctx->need_fallback) {
+ /* Reset need_fallback in case the same ctx is used for another transaction */
+ ctx->need_fallback = false;
+
+ aead_request_set_tfm(&rctx->fallback_req, ctx->fallback);
+ aead_request_set_callback(&rctx->fallback_req, req->base.flags,
+ req->base.complete, req->base.data);
+ aead_request_set_crypt(&rctx->fallback_req, req->src,
+ req->dst, req->cryptlen, req->iv);
+ aead_request_set_ad(&rctx->fallback_req, req->assoclen);
+
+ return encrypt ? crypto_aead_encrypt(&rctx->fallback_req) :
+ crypto_aead_decrypt(&rctx->fallback_req);
+ }
+
+ /*
+ * CBC algorithms require message lengths to be
+ * multiples of block size.
+ */
+ if (IS_CBC(rctx->flags) && !IS_ALIGNED(rctx->cryptlen, blocksize))
+ return -EINVAL;
+
+ /* RFC4309 supported AAD size 16 bytes/20 bytes */
+ if (IS_CCM_RFC4309(rctx->flags))
+ if (crypto_ipsec_check_assoclen(req->assoclen))
+ return -EINVAL;
+
+ return tmpl->qce->async_req_enqueue(tmpl->qce, &req->base);
+}
+
+static int qce_aead_encrypt(struct aead_request *req)
+{
+ return qce_aead_crypt(req, 1);
+}
+
+static int qce_aead_decrypt(struct aead_request *req)
+{
+ return qce_aead_crypt(req, 0);
+}
+
+static int qce_aead_ccm_setkey(struct crypto_aead *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ unsigned long flags = to_aead_tmpl(tfm)->alg_flags;
+
+ if (IS_CCM_RFC4309(flags)) {
+ if (keylen < QCE_CCM4309_SALT_SIZE)
+ return -EINVAL;
+ keylen -= QCE_CCM4309_SALT_SIZE;
+ memcpy(ctx->ccm4309_salt, key + keylen, QCE_CCM4309_SALT_SIZE);
+ }
+
+ if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_256 && keylen != AES_KEYSIZE_192)
+ return -EINVAL;
+
+ ctx->enc_keylen = keylen;
+ ctx->auth_keylen = keylen;
+
+ memcpy(ctx->enc_key, key, keylen);
+ memcpy(ctx->auth_key, key, keylen);
+
+ if (keylen == AES_KEYSIZE_192)
+ ctx->need_fallback = true;
+
+ return IS_CCM_RFC4309(flags) ?
+ crypto_aead_setkey(ctx->fallback, key, keylen + QCE_CCM4309_SALT_SIZE) :
+ crypto_aead_setkey(ctx->fallback, key, keylen);
+}
+
+static int qce_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
+{
+ struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct crypto_authenc_keys authenc_keys;
+ unsigned long flags = to_aead_tmpl(tfm)->alg_flags;
+ u32 _key[6];
+ int err;
+
+ err = crypto_authenc_extractkeys(&authenc_keys, key, keylen);
+ if (err)
+ return err;
+
+ if (authenc_keys.enckeylen > QCE_MAX_KEY_SIZE ||
+ authenc_keys.authkeylen > QCE_MAX_KEY_SIZE)
+ return -EINVAL;
+
+ if (IS_DES(flags)) {
+ err = verify_aead_des_key(tfm, authenc_keys.enckey, authenc_keys.enckeylen);
+ if (err)
+ return err;
+ } else if (IS_3DES(flags)) {
+ err = verify_aead_des3_key(tfm, authenc_keys.enckey, authenc_keys.enckeylen);
+ if (err)
+ return err;
+ /*
+ * The crypto engine does not support any two keys
+ * being the same for triple des algorithms. The
+ * verify_skcipher_des3_key does not check for all the
+ * below conditions. Schedule fallback in this case.
+ */
+ memcpy(_key, authenc_keys.enckey, DES3_EDE_KEY_SIZE);
+ if (!((_key[0] ^ _key[2]) | (_key[1] ^ _key[3])) ||
+ !((_key[2] ^ _key[4]) | (_key[3] ^ _key[5])) ||
+ !((_key[0] ^ _key[4]) | (_key[1] ^ _key[5])))
+ ctx->need_fallback = true;
+ } else if (IS_AES(flags)) {
+ /* No random key sizes */
+ if (authenc_keys.enckeylen != AES_KEYSIZE_128 &&
+ authenc_keys.enckeylen != AES_KEYSIZE_192 &&
+ authenc_keys.enckeylen != AES_KEYSIZE_256)
+ return -EINVAL;
+ if (authenc_keys.enckeylen == AES_KEYSIZE_192)
+ ctx->need_fallback = true;
+ }
+
+ ctx->enc_keylen = authenc_keys.enckeylen;
+ ctx->auth_keylen = authenc_keys.authkeylen;
+
+ memcpy(ctx->enc_key, authenc_keys.enckey, authenc_keys.enckeylen);
+
+ memset(ctx->auth_key, 0, sizeof(ctx->auth_key));
+ memcpy(ctx->auth_key, authenc_keys.authkey, authenc_keys.authkeylen);
+
+ return crypto_aead_setkey(ctx->fallback, key, keylen);
+}
+
+static int qce_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
+{
+ struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ unsigned long flags = to_aead_tmpl(tfm)->alg_flags;
+
+ if (IS_CCM(flags)) {
+ if (authsize < 4 || authsize > 16 || authsize % 2)
+ return -EINVAL;
+ if (IS_CCM_RFC4309(flags) && (authsize < 8 || authsize % 4))
+ return -EINVAL;
+ }
+ ctx->authsize = authsize;
+
+ return crypto_aead_setauthsize(ctx->fallback, authsize);
+}
+
+static int qce_aead_init(struct crypto_aead *tfm)
+{
+ struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+
+ ctx->need_fallback = false;
+ ctx->fallback = crypto_alloc_aead(crypto_tfm_alg_name(&tfm->base),
+ 0, CRYPTO_ALG_NEED_FALLBACK);
+
+ if (IS_ERR(ctx->fallback))
+ return PTR_ERR(ctx->fallback);
+
+ crypto_aead_set_reqsize(tfm, sizeof(struct qce_aead_reqctx) +
+ crypto_aead_reqsize(ctx->fallback));
+ return 0;
+}
+
+static void qce_aead_exit(struct crypto_aead *tfm)
+{
+ struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
+
+ crypto_free_aead(ctx->fallback);
+}
+
+struct qce_aead_def {
+ unsigned long flags;
+ const char *name;
+ const char *drv_name;
+ unsigned int blocksize;
+ unsigned int chunksize;
+ unsigned int ivsize;
+ unsigned int maxauthsize;
+};
+
+static const struct qce_aead_def aead_def[] = {
+ {
+ .flags = QCE_ALG_DES | QCE_MODE_CBC | QCE_HASH_SHA1_HMAC,
+ .name = "authenc(hmac(sha1),cbc(des))",
+ .drv_name = "authenc-hmac-sha1-cbc-des-qce",
+ .blocksize = DES_BLOCK_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ {
+ .flags = QCE_ALG_3DES | QCE_MODE_CBC | QCE_HASH_SHA1_HMAC,
+ .name = "authenc(hmac(sha1),cbc(des3_ede))",
+ .drv_name = "authenc-hmac-sha1-cbc-3des-qce",
+ .blocksize = DES3_EDE_BLOCK_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ {
+ .flags = QCE_ALG_DES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC,
+ .name = "authenc(hmac(sha256),cbc(des))",
+ .drv_name = "authenc-hmac-sha256-cbc-des-qce",
+ .blocksize = DES_BLOCK_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ {
+ .flags = QCE_ALG_3DES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC,
+ .name = "authenc(hmac(sha256),cbc(des3_ede))",
+ .drv_name = "authenc-hmac-sha256-cbc-3des-qce",
+ .blocksize = DES3_EDE_BLOCK_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ {
+ .flags = QCE_ALG_AES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC,
+ .name = "authenc(hmac(sha256),cbc(aes))",
+ .drv_name = "authenc-hmac-sha256-cbc-aes-qce",
+ .blocksize = AES_BLOCK_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ {
+ .flags = QCE_ALG_AES | QCE_MODE_CCM,
+ .name = "ccm(aes)",
+ .drv_name = "ccm-aes-qce",
+ .blocksize = 1,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ {
+ .flags = QCE_ALG_AES | QCE_MODE_CCM | QCE_MODE_CCM_RFC4309,
+ .name = "rfc4309(ccm(aes))",
+ .drv_name = "rfc4309-ccm-aes-qce",
+ .blocksize = 1,
+ .ivsize = 8,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+};
+
+static int qce_aead_register_one(const struct qce_aead_def *def, struct qce_device *qce)
+{
+ struct qce_alg_template *tmpl;
+ struct aead_alg *alg;
+ int ret;
+
+ tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
+ if (!tmpl)
+ return -ENOMEM;
+
+ alg = &tmpl->alg.aead;
+
+ snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);
+ snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+ def->drv_name);
+
+ alg->base.cra_blocksize = def->blocksize;
+ alg->chunksize = def->chunksize;
+ alg->ivsize = def->ivsize;
+ alg->maxauthsize = def->maxauthsize;
+ if (IS_CCM(def->flags))
+ alg->setkey = qce_aead_ccm_setkey;
+ else
+ alg->setkey = qce_aead_setkey;
+ alg->setauthsize = qce_aead_setauthsize;
+ alg->encrypt = qce_aead_encrypt;
+ alg->decrypt = qce_aead_decrypt;
+ alg->init = qce_aead_init;
+ alg->exit = qce_aead_exit;
+
+ alg->base.cra_priority = 300;
+ alg->base.cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_ALLOCATES_MEMORY |
+ CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_NEED_FALLBACK;
+ alg->base.cra_ctxsize = sizeof(struct qce_aead_ctx);
+ alg->base.cra_alignmask = 0;
+ alg->base.cra_module = THIS_MODULE;
+
+ INIT_LIST_HEAD(&tmpl->entry);
+ tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_AEAD;
+ tmpl->alg_flags = def->flags;
+ tmpl->qce = qce;
+
+ ret = crypto_register_aead(alg);
+ if (ret) {
+ kfree(tmpl);
+ dev_err(qce->dev, "%s registration failed\n", alg->base.cra_name);
+ return ret;
+ }
+
+ list_add_tail(&tmpl->entry, &aead_algs);
+ dev_dbg(qce->dev, "%s is registered\n", alg->base.cra_name);
+ return 0;
+}
+
+static void qce_aead_unregister(struct qce_device *qce)
+{
+ struct qce_alg_template *tmpl, *n;
+
+ list_for_each_entry_safe(tmpl, n, &aead_algs, entry) {
+ crypto_unregister_aead(&tmpl->alg.aead);
+ list_del(&tmpl->entry);
+ kfree(tmpl);
+ }
+}
+
+static int qce_aead_register(struct qce_device *qce)
+{
+ int ret, i;
+
+ for (i = 0; i < ARRAY_SIZE(aead_def); i++) {
+ ret = qce_aead_register_one(&aead_def[i], qce);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+err:
+ qce_aead_unregister(qce);
+ return ret;
+}
+
+const struct qce_algo_ops aead_ops = {
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .register_algs = qce_aead_register,
+ .unregister_algs = qce_aead_unregister,
+ .async_req_handle = qce_aead_async_req_handle,
+};
diff --git a/drivers/crypto/qce/aead.h b/drivers/crypto/qce/aead.h
new file mode 100644
index 000000000000..efb8477cc088
--- /dev/null
+++ b/drivers/crypto/qce/aead.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021, Linaro Limited. All rights reserved.
+ */
+
+#ifndef _AEAD_H_
+#define _AEAD_H_
+
+#include "common.h"
+#include "core.h"
+
+#define QCE_MAX_KEY_SIZE 64
+#define QCE_CCM4309_SALT_SIZE 3
+
+struct qce_aead_ctx {
+ u8 enc_key[QCE_MAX_KEY_SIZE];
+ u8 auth_key[QCE_MAX_KEY_SIZE];
+ u8 ccm4309_salt[QCE_CCM4309_SALT_SIZE];
+ unsigned int enc_keylen;
+ unsigned int auth_keylen;
+ unsigned int authsize;
+ bool need_fallback;
+ struct crypto_aead *fallback;
+};
+
+struct qce_aead_reqctx {
+ unsigned long flags;
+ u8 *iv;
+ unsigned int ivsize;
+ int src_nents;
+ int dst_nents;
+ struct scatterlist result_sg;
+ struct scatterlist adata_sg;
+ struct sg_table dst_tbl;
+ struct sg_table src_tbl;
+ struct scatterlist *dst_sg;
+ struct scatterlist *src_sg;
+ unsigned int cryptlen;
+ unsigned int assoclen;
+ unsigned char *adata;
+ u8 ccm_nonce[QCE_MAX_NONCE];
+ u8 ccmresult_buf[QCE_BAM_BURST_SIZE];
+ u8 ccm_rfc4309_iv[QCE_MAX_IV_SIZE];
+ struct aead_request fallback_req;
+};
+
+static inline struct qce_alg_template *to_aead_tmpl(struct crypto_aead *tfm)
+{
+ struct aead_alg *alg = crypto_aead_alg(tfm);
+
+ return container_of(alg, struct qce_alg_template, alg.aead);
+}
+
+extern const struct qce_algo_ops aead_ops;
+
+#endif /* _AEAD_H_ */
diff --git a/drivers/crypto/qce/common.c b/drivers/crypto/qce/common.c
index dceb9579d87a..7c612ba5068f 100644
--- a/drivers/crypto/qce/common.c
+++ b/drivers/crypto/qce/common.c
@@ -15,6 +15,7 @@
#include "core.h"
#include "regs-v5.h"
#include "sha.h"
+#include "aead.h"
static inline u32 qce_read(struct qce_device *qce, u32 offset)
{
@@ -88,17 +89,20 @@ static void qce_setup_config(struct qce_device *qce)
qce_write(qce, REG_CONFIG, config);
}
-static inline void qce_crypto_go(struct qce_device *qce)
+static inline void qce_crypto_go(struct qce_device *qce, bool result_dump)
{
- qce_write(qce, REG_GOPROC, BIT(GO_SHIFT) | BIT(RESULTS_DUMP_SHIFT));
+ if (result_dump)
+ qce_write(qce, REG_GOPROC, BIT(GO_SHIFT) | BIT(RESULTS_DUMP_SHIFT));
+ else
+ qce_write(qce, REG_GOPROC, BIT(GO_SHIFT));
}
-#ifdef CONFIG_CRYPTO_DEV_QCE_SHA
-static u32 qce_auth_cfg(unsigned long flags, u32 key_size)
+#if defined(CONFIG_CRYPTO_DEV_QCE_SHA) || defined(CONFIG_CRYPTO_DEV_QCE_AEAD)
+static u32 qce_auth_cfg(unsigned long flags, u32 key_size, u32 auth_size)
{
u32 cfg = 0;
- if (IS_AES(flags) && (IS_CCM(flags) || IS_CMAC(flags)))
+ if (IS_CCM(flags) || IS_CMAC(flags))
cfg |= AUTH_ALG_AES << AUTH_ALG_SHIFT;
else
cfg |= AUTH_ALG_SHA << AUTH_ALG_SHIFT;
@@ -116,15 +120,16 @@ static u32 qce_auth_cfg(unsigned long flags, u32 key_size)
cfg |= AUTH_SIZE_SHA256 << AUTH_SIZE_SHIFT;
else if (IS_CMAC(flags))
cfg |= AUTH_SIZE_ENUM_16_BYTES << AUTH_SIZE_SHIFT;
+ else if (IS_CCM(flags))
+ cfg |= (auth_size - 1) << AUTH_SIZE_SHIFT;
if (IS_SHA1(flags) || IS_SHA256(flags))
cfg |= AUTH_MODE_HASH << AUTH_MODE_SHIFT;
- else if (IS_SHA1_HMAC(flags) || IS_SHA256_HMAC(flags) ||
- IS_CBC(flags) || IS_CTR(flags))
+ else if (IS_SHA1_HMAC(flags) || IS_SHA256_HMAC(flags))
cfg |= AUTH_MODE_HMAC << AUTH_MODE_SHIFT;
- else if (IS_AES(flags) && IS_CCM(flags))
+ else if (IS_CCM(flags))
cfg |= AUTH_MODE_CCM << AUTH_MODE_SHIFT;
- else if (IS_AES(flags) && IS_CMAC(flags))
+ else if (IS_CMAC(flags))
cfg |= AUTH_MODE_CMAC << AUTH_MODE_SHIFT;
if (IS_SHA(flags) || IS_SHA_HMAC(flags))
@@ -133,13 +138,11 @@ static u32 qce_auth_cfg(unsigned long flags, u32 key_size)
if (IS_CCM(flags))
cfg |= QCE_MAX_NONCE_WORDS << AUTH_NONCE_NUM_WORDS_SHIFT;
- if (IS_CBC(flags) || IS_CTR(flags) || IS_CCM(flags) ||
- IS_CMAC(flags))
- cfg |= BIT(AUTH_LAST_SHIFT) | BIT(AUTH_FIRST_SHIFT);
-
return cfg;
}
+#endif
+#ifdef CONFIG_CRYPTO_DEV_QCE_SHA
static int qce_setup_regs_ahash(struct crypto_async_request *async_req)
{
struct ahash_request *req = ahash_request_cast(async_req);
@@ -168,7 +171,7 @@ static int qce_setup_regs_ahash(struct crypto_async_request *async_req)
qce_clear_array(qce, REG_AUTH_KEY0, 16);
qce_clear_array(qce, REG_AUTH_BYTECNT0, 4);
- auth_cfg = qce_auth_cfg(rctx->flags, rctx->authklen);
+ auth_cfg = qce_auth_cfg(rctx->flags, rctx->authklen, digestsize);
}
if (IS_SHA_HMAC(rctx->flags) || IS_CMAC(rctx->flags)) {
@@ -196,7 +199,7 @@ static int qce_setup_regs_ahash(struct crypto_async_request *async_req)
qce_write_array(qce, REG_AUTH_BYTECNT0,
(u32 *)rctx->byte_count, 2);
- auth_cfg = qce_auth_cfg(rctx->flags, 0);
+ auth_cfg = qce_auth_cfg(rctx->flags, 0, digestsize);
if (rctx->last_blk)
auth_cfg |= BIT(AUTH_LAST_SHIFT);
@@ -219,13 +222,13 @@ go_proc:
config = qce_config_reg(qce, 1);
qce_write(qce, REG_CONFIG, config);
- qce_crypto_go(qce);
+ qce_crypto_go(qce, true);
return 0;
}
#endif
-#ifdef CONFIG_CRYPTO_DEV_QCE_SKCIPHER
+#if defined(CONFIG_CRYPTO_DEV_QCE_SKCIPHER) || defined(CONFIG_CRYPTO_DEV_QCE_AEAD)
static u32 qce_encr_cfg(unsigned long flags, u32 aes_key_size)
{
u32 cfg = 0;
@@ -271,7 +274,9 @@ static u32 qce_encr_cfg(unsigned long flags, u32 aes_key_size)
return cfg;
}
+#endif
+#ifdef CONFIG_CRYPTO_DEV_QCE_SKCIPHER
static void qce_xts_swapiv(__be32 *dst, const u8 *src, unsigned int ivsize)
{
u8 swap[QCE_AES_IV_LENGTH];
@@ -380,7 +385,156 @@ static int qce_setup_regs_skcipher(struct crypto_async_request *async_req)
config = qce_config_reg(qce, 1);
qce_write(qce, REG_CONFIG, config);
- qce_crypto_go(qce);
+ qce_crypto_go(qce, true);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_CRYPTO_DEV_QCE_AEAD
+static const u32 std_iv_sha1[SHA256_DIGEST_SIZE / sizeof(u32)] = {
+ SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4, 0, 0, 0
+};
+
+static const u32 std_iv_sha256[SHA256_DIGEST_SIZE / sizeof(u32)] = {
+ SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3,
+ SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7
+};
+
+static unsigned int qce_be32_to_cpu_array(u32 *dst, const u8 *src, unsigned int len)
+{
+ u32 *d = dst;
+ const u8 *s = src;
+ unsigned int n;
+
+ n = len / sizeof(u32);
+ for (; n > 0; n--) {
+ *d = be32_to_cpup((const __be32 *)s);
+ s += sizeof(u32);
+ d++;
+ }
+ return DIV_ROUND_UP(len, sizeof(u32));
+}
+
+static int qce_setup_regs_aead(struct crypto_async_request *async_req)
+{
+ struct aead_request *req = aead_request_cast(async_req);
+ struct qce_aead_reqctx *rctx = aead_request_ctx(req);
+ struct qce_aead_ctx *ctx = crypto_tfm_ctx(async_req->tfm);
+ struct qce_alg_template *tmpl = to_aead_tmpl(crypto_aead_reqtfm(req));
+ struct qce_device *qce = tmpl->qce;
+ u32 enckey[QCE_MAX_CIPHER_KEY_SIZE / sizeof(u32)] = {0};
+ u32 enciv[QCE_MAX_IV_SIZE / sizeof(u32)] = {0};
+ u32 authkey[QCE_SHA_HMAC_KEY_SIZE / sizeof(u32)] = {0};
+ u32 authiv[SHA256_DIGEST_SIZE / sizeof(u32)] = {0};
+ u32 authnonce[QCE_MAX_NONCE / sizeof(u32)] = {0};
+ unsigned int enc_keylen = ctx->enc_keylen;
+ unsigned int auth_keylen = ctx->auth_keylen;
+ unsigned int enc_ivsize = rctx->ivsize;
+ unsigned int auth_ivsize = 0;
+ unsigned int enckey_words, enciv_words;
+ unsigned int authkey_words, authiv_words, authnonce_words;
+ unsigned long flags = rctx->flags;
+ u32 encr_cfg, auth_cfg, config, totallen;
+ u32 iv_last_word;
+
+ qce_setup_config(qce);
+
+ /* Write encryption key */
+ enckey_words = qce_be32_to_cpu_array(enckey, ctx->enc_key, enc_keylen);
+ qce_write_array(qce, REG_ENCR_KEY0, enckey, enckey_words);
+
+ /* Write encryption iv */
+ enciv_words = qce_be32_to_cpu_array(enciv, rctx->iv, enc_ivsize);
+ qce_write_array(qce, REG_CNTR0_IV0, enciv, enciv_words);
+
+ if (IS_CCM(rctx->flags)) {
+ iv_last_word = enciv[enciv_words - 1];
+ qce_write(qce, REG_CNTR3_IV3, iv_last_word + 1);
+ qce_write_array(qce, REG_ENCR_CCM_INT_CNTR0, (u32 *)enciv, enciv_words);
+ qce_write(qce, REG_CNTR_MASK, ~0);
+ qce_write(qce, REG_CNTR_MASK0, ~0);
+ qce_write(qce, REG_CNTR_MASK1, ~0);
+ qce_write(qce, REG_CNTR_MASK2, ~0);
+ }
+
+ /* Clear authentication IV and KEY registers of previous values */
+ qce_clear_array(qce, REG_AUTH_IV0, 16);
+ qce_clear_array(qce, REG_AUTH_KEY0, 16);
+
+ /* Clear byte count */
+ qce_clear_array(qce, REG_AUTH_BYTECNT0, 4);
+
+ /* Write authentication key */
+ authkey_words = qce_be32_to_cpu_array(authkey, ctx->auth_key, auth_keylen);
+ qce_write_array(qce, REG_AUTH_KEY0, (u32 *)authkey, authkey_words);
+
+ /* Write initial authentication IV only for HMAC algorithms */
+ if (IS_SHA_HMAC(rctx->flags)) {
+ /* Write default authentication iv */
+ if (IS_SHA1_HMAC(rctx->flags)) {
+ auth_ivsize = SHA1_DIGEST_SIZE;
+ memcpy(authiv, std_iv_sha1, auth_ivsize);
+ } else if (IS_SHA256_HMAC(rctx->flags)) {
+ auth_ivsize = SHA256_DIGEST_SIZE;
+ memcpy(authiv, std_iv_sha256, auth_ivsize);
+ }
+ authiv_words = auth_ivsize / sizeof(u32);
+ qce_write_array(qce, REG_AUTH_IV0, (u32 *)authiv, authiv_words);
+ } else if (IS_CCM(rctx->flags)) {
+ /* Write nonce for CCM algorithms */
+ authnonce_words = qce_be32_to_cpu_array(authnonce, rctx->ccm_nonce, QCE_MAX_NONCE);
+ qce_write_array(qce, REG_AUTH_INFO_NONCE0, authnonce, authnonce_words);
+ }
+
+ /* Set up ENCR_SEG_CFG */
+ encr_cfg = qce_encr_cfg(flags, enc_keylen);
+ if (IS_ENCRYPT(flags))
+ encr_cfg |= BIT(ENCODE_SHIFT);
+ qce_write(qce, REG_ENCR_SEG_CFG, encr_cfg);
+
+ /* Set up AUTH_SEG_CFG */
+ auth_cfg = qce_auth_cfg(rctx->flags, auth_keylen, ctx->authsize);
+ auth_cfg |= BIT(AUTH_LAST_SHIFT);
+ auth_cfg |= BIT(AUTH_FIRST_SHIFT);
+ if (IS_ENCRYPT(flags)) {
+ if (IS_CCM(rctx->flags))
+ auth_cfg |= AUTH_POS_BEFORE << AUTH_POS_SHIFT;
+ else
+ auth_cfg |= AUTH_POS_AFTER << AUTH_POS_SHIFT;
+ } else {
+ if (IS_CCM(rctx->flags))
+ auth_cfg |= AUTH_POS_AFTER << AUTH_POS_SHIFT;
+ else
+ auth_cfg |= AUTH_POS_BEFORE << AUTH_POS_SHIFT;
+ }
+ qce_write(qce, REG_AUTH_SEG_CFG, auth_cfg);
+
+ totallen = rctx->cryptlen + rctx->assoclen;
+
+ /* Set the encryption size and start offset */
+ if (IS_CCM(rctx->flags) && IS_DECRYPT(rctx->flags))
+ qce_write(qce, REG_ENCR_SEG_SIZE, rctx->cryptlen + ctx->authsize);
+ else
+ qce_write(qce, REG_ENCR_SEG_SIZE, rctx->cryptlen);
+ qce_write(qce, REG_ENCR_SEG_START, rctx->assoclen & 0xffff);
+
+ /* Set the authentication size and start offset */
+ qce_write(qce, REG_AUTH_SEG_SIZE, totallen);
+ qce_write(qce, REG_AUTH_SEG_START, 0);
+
+ /* Write total length */
+ if (IS_CCM(rctx->flags) && IS_DECRYPT(rctx->flags))
+ qce_write(qce, REG_SEG_SIZE, totallen + ctx->authsize);
+ else
+ qce_write(qce, REG_SEG_SIZE, totallen);
+
+ /* get little endianness */
+ config = qce_config_reg(qce, 1);
+ qce_write(qce, REG_CONFIG, config);
+
+ /* Start the process */
+ qce_crypto_go(qce, !IS_CCM(flags));
return 0;
}
@@ -397,6 +551,10 @@ int qce_start(struct crypto_async_request *async_req, u32 type)
case CRYPTO_ALG_TYPE_AHASH:
return qce_setup_regs_ahash(async_req);
#endif
+#ifdef CONFIG_CRYPTO_DEV_QCE_AEAD
+ case CRYPTO_ALG_TYPE_AEAD:
+ return qce_setup_regs_aead(async_req);
+#endif
default:
return -EINVAL;
}
@@ -419,6 +577,8 @@ int qce_check_status(struct qce_device *qce, u32 *status)
*/
if (*status & STATUS_ERRORS || !(*status & BIT(OPERATION_DONE_SHIFT)))
ret = -ENXIO;
+ else if (*status & BIT(MAC_FAILED_SHIFT))
+ ret = -EBADMSG;
return ret;
}
diff --git a/drivers/crypto/qce/common.h b/drivers/crypto/qce/common.h
index 3bc244bcca2d..02e63ad9f245 100644
--- a/drivers/crypto/qce/common.h
+++ b/drivers/crypto/qce/common.h
@@ -11,6 +11,7 @@
#include <crypto/aes.h>
#include <crypto/hash.h>
#include <crypto/internal/skcipher.h>
+#include <crypto/internal/aead.h>
/* xts du size */
#define QCE_SECTOR_SIZE 512
@@ -51,9 +52,11 @@
#define QCE_MODE_CCM BIT(12)
#define QCE_MODE_MASK GENMASK(12, 8)
+#define QCE_MODE_CCM_RFC4309 BIT(13)
+
/* cipher encryption/decryption operations */
-#define QCE_ENCRYPT BIT(13)
-#define QCE_DECRYPT BIT(14)
+#define QCE_ENCRYPT BIT(30)
+#define QCE_DECRYPT BIT(31)
#define IS_DES(flags) (flags & QCE_ALG_DES)
#define IS_3DES(flags) (flags & QCE_ALG_3DES)
@@ -73,6 +76,7 @@
#define IS_CTR(mode) (mode & QCE_MODE_CTR)
#define IS_XTS(mode) (mode & QCE_MODE_XTS)
#define IS_CCM(mode) (mode & QCE_MODE_CCM)
+#define IS_CCM_RFC4309(mode) ((mode) & QCE_MODE_CCM_RFC4309)
#define IS_ENCRYPT(dir) (dir & QCE_ENCRYPT)
#define IS_DECRYPT(dir) (dir & QCE_DECRYPT)
@@ -85,6 +89,7 @@ struct qce_alg_template {
union {
struct skcipher_alg skcipher;
struct ahash_alg ahash;
+ struct aead_alg aead;
} alg;
struct qce_device *qce;
const u8 *hash_zero;
diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c
index 80b75085c265..d3780be44a76 100644
--- a/drivers/crypto/qce/core.c
+++ b/drivers/crypto/qce/core.c
@@ -17,6 +17,7 @@
#include "core.h"
#include "cipher.h"
#include "sha.h"
+#include "aead.h"
#define QCE_MAJOR_VERSION5 0x05
#define QCE_QUEUE_LENGTH 1
@@ -28,6 +29,9 @@ static const struct qce_algo_ops *qce_ops[] = {
#ifdef CONFIG_CRYPTO_DEV_QCE_SHA
&ahash_ops,
#endif
+#ifdef CONFIG_CRYPTO_DEV_QCE_AEAD
+ &aead_ops,
+#endif
};
static void qce_unregister_algs(struct qce_device *qce)
diff --git a/drivers/crypto/qce/skcipher.c b/drivers/crypto/qce/skcipher.c
index c0a0d8c4fce1..8ff10928f581 100644
--- a/drivers/crypto/qce/skcipher.c
+++ b/drivers/crypto/qce/skcipher.c
@@ -72,7 +72,7 @@ qce_skcipher_async_req_handle(struct crypto_async_request *async_req)
struct scatterlist *sg;
bool diff_dst;
gfp_t gfp;
- int ret;
+ int dst_nents, src_nents, ret;
rctx->iv = req->iv;
rctx->ivsize = crypto_skcipher_ivsize(skcipher);
@@ -123,21 +123,26 @@ qce_skcipher_async_req_handle(struct crypto_async_request *async_req)
sg_mark_end(sg);
rctx->dst_sg = rctx->dst_tbl.sgl;
- ret = dma_map_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
- if (ret < 0)
+ dst_nents = dma_map_sg(qce->dev, rctx->dst_sg, rctx->dst_nents, dir_dst);
+ if (dst_nents < 0) {
+ ret = dst_nents;
goto error_free;
+ }
if (diff_dst) {
- ret = dma_map_sg(qce->dev, req->src, rctx->src_nents, dir_src);
- if (ret < 0)
+ src_nents = dma_map_sg(qce->dev, req->src, rctx->src_nents, dir_src);
+ if (src_nents < 0) {
+ ret = src_nents;
goto error_unmap_dst;
+ }
rctx->src_sg = req->src;
} else {
rctx->src_sg = rctx->dst_sg;
+ src_nents = dst_nents - 1;
}
- ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, rctx->src_nents,
- rctx->dst_sg, rctx->dst_nents,
+ ret = qce_dma_prep_sgs(&qce->dma, rctx->src_sg, src_nents,
+ rctx->dst_sg, dst_nents,
qce_skcipher_done, async_req);
if (ret)
goto error_unmap_src;
diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c
index 1c6929fb3a13..544d7040cfc5 100644
--- a/drivers/crypto/sa2ul.c
+++ b/drivers/crypto/sa2ul.c
@@ -1698,7 +1698,6 @@ static void sa_aead_dma_in_callback(void *data)
size_t pl, ml;
int i;
int err = 0;
- u16 auth_len;
u32 *mdptr;
sa_sync_from_device(rxd);
@@ -1711,13 +1710,10 @@ static void sa_aead_dma_in_callback(void *data)
for (i = 0; i < (authsize / 4); i++)
mdptr[i + 4] = swab32(mdptr[i + 4]);
- auth_len = req->assoclen + req->cryptlen;
-
if (rxd->enc) {
scatterwalk_map_and_copy(&mdptr[4], req->dst, start, authsize,
1);
} else {
- auth_len -= authsize;
start -= authsize;
scatterwalk_map_and_copy(auth_tag, req->src, start, authsize,
0);
@@ -2300,9 +2296,9 @@ static int sa_dma_init(struct sa_crypto_data *dd)
dd->dma_rx2 = dma_request_chan(dd->dev, "rx2");
if (IS_ERR(dd->dma_rx2)) {
- dma_release_channel(dd->dma_rx1);
- return dev_err_probe(dd->dev, PTR_ERR(dd->dma_rx2),
- "Unable to request rx2 DMA channel\n");
+ ret = dev_err_probe(dd->dev, PTR_ERR(dd->dma_rx2),
+ "Unable to request rx2 DMA channel\n");
+ goto err_dma_rx2;
}
dd->dma_tx = dma_request_chan(dd->dev, "tx");
@@ -2323,28 +2319,31 @@ static int sa_dma_init(struct sa_crypto_data *dd)
if (ret) {
dev_err(dd->dev, "can't configure IN dmaengine slave: %d\n",
ret);
- return ret;
+ goto err_dma_config;
}
ret = dmaengine_slave_config(dd->dma_rx2, &cfg);
if (ret) {
dev_err(dd->dev, "can't configure IN dmaengine slave: %d\n",
ret);
- return ret;
+ goto err_dma_config;
}
ret = dmaengine_slave_config(dd->dma_tx, &cfg);
if (ret) {
dev_err(dd->dev, "can't configure OUT dmaengine slave: %d\n",
ret);
- return ret;
+ goto err_dma_config;
}
return 0;
+err_dma_config:
+ dma_release_channel(dd->dma_tx);
err_dma_tx:
- dma_release_channel(dd->dma_rx1);
dma_release_channel(dd->dma_rx2);
+err_dma_rx2:
+ dma_release_channel(dd->dma_rx1);
return ret;
}
@@ -2385,10 +2384,8 @@ MODULE_DEVICE_TABLE(of, of_match);
static int sa_ul_probe(struct platform_device *pdev)
{
- const struct of_device_id *match;
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
- struct resource *res;
static void __iomem *saul_base;
struct sa_crypto_data *dev_data;
int ret;
@@ -2397,9 +2394,18 @@ static int sa_ul_probe(struct platform_device *pdev)
if (!dev_data)
return -ENOMEM;
+ dev_data->match_data = of_device_get_match_data(dev);
+ if (!dev_data->match_data)
+ return -ENODEV;
+
+ saul_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(saul_base))
+ return PTR_ERR(saul_base);
+
sa_k3_dev = dev;
dev_data->dev = dev;
dev_data->pdev = pdev;
+ dev_data->base = saul_base;
platform_set_drvdata(pdev, dev_data);
dev_set_drvdata(sa_k3_dev, dev_data);
@@ -2408,26 +2414,16 @@ static int sa_ul_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "%s: failed to get sync: %d\n", __func__,
ret);
+ pm_runtime_disable(dev);
return ret;
}
sa_init_mem(dev_data);
ret = sa_dma_init(dev_data);
if (ret)
- goto disable_pm_runtime;
-
- match = of_match_node(of_match, dev->of_node);
- if (!match) {
- dev_err(dev, "No compatible match found\n");
- return -ENODEV;
- }
- dev_data->match_data = match->data;
+ goto destroy_dma_pool;
spin_lock_init(&dev_data->scid_lock);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- saul_base = devm_ioremap_resource(dev, res);
-
- dev_data->base = saul_base;
if (!dev_data->match_data->skip_engine_control) {
u32 val = SA_EEC_ENCSS_EN | SA_EEC_AUTHSS_EN | SA_EEC_CTXCACH_EN |
@@ -2454,9 +2450,9 @@ release_dma:
dma_release_channel(dev_data->dma_rx1);
dma_release_channel(dev_data->dma_tx);
+destroy_dma_pool:
dma_pool_destroy(dev_data->sc_pool);
-disable_pm_runtime:
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -2467,6 +2463,8 @@ static int sa_ul_remove(struct platform_device *pdev)
{
struct sa_crypto_data *dev_data = platform_get_drvdata(pdev);
+ of_platform_depopulate(&pdev->dev);
+
sa_unregister_algos(&pdev->dev);
dma_release_channel(dev_data->dma_rx2);
diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c
index ecb7412e84e3..51a6e1a42434 100644
--- a/drivers/crypto/ux500/hash/hash_core.c
+++ b/drivers/crypto/ux500/hash/hash_core.c
@@ -1011,6 +1011,7 @@ static int hash_hw_final(struct ahash_request *req)
goto out;
}
} else if (req->nbytes == 0 && ctx->keylen > 0) {
+ ret = -EPERM;
dev_err(device_data->dev, "%s: Empty message with keylength > 0, NOT supported\n",
__func__);
goto out;
diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index 97dc4d751651..e6de221cc568 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -15,21 +15,17 @@ if CXL_BUS
config CXL_MEM
tristate "CXL.mem: Memory Devices"
+ default CXL_BUS
help
The CXL.mem protocol allows a device to act as a provider of
"System RAM" and/or "Persistent Memory" that is fully coherent
as if the memory was attached to the typical CPU memory
controller.
- Say 'y/m' to enable a driver (named "cxl_mem.ko" when built as
- a module) that will attach to CXL.mem devices for
- configuration, provisioning, and health monitoring. This
- driver is required for dynamic provisioning of CXL.mem
- attached memory which is a prerequisite for persistent memory
- support. Typically volatile memory is mapped by platform
- firmware and included in the platform memory map, but in some
- cases the OS is responsible for mapping that memory. See
- Chapter 2.3 Type 3 CXL Device in the CXL 2.0 specification.
+ Say 'y/m' to enable a driver that will attach to CXL.mem devices for
+ configuration and management primarily via the mailbox interface. See
+ Chapter 2.3 Type 3 CXL Device in the CXL 2.0 specification for more
+ details.
If unsure say 'm'.
@@ -50,4 +46,33 @@ config CXL_MEM_RAW_COMMANDS
potential impact to memory currently in use by the kernel.
If developing CXL hardware or the driver say Y, otherwise say N.
+
+config CXL_ACPI
+ tristate "CXL ACPI: Platform Support"
+ depends on ACPI
+ default CXL_BUS
+ help
+ Enable support for host managed device memory (HDM) resources
+ published by a platform's ACPI CXL memory layout description. See
+ Chapter 9.14.1 CXL Early Discovery Table (CEDT) in the CXL 2.0
+ specification, and CXL Fixed Memory Window Structures (CEDT.CFMWS)
+ (https://www.computeexpresslink.org/spec-landing). The CXL core
+ consumes these resource to publish the root of a cxl_port decode
+ hierarchy to map regions that represent System RAM, or Persistent
+ Memory regions to be managed by LIBNVDIMM.
+
+ If unsure say 'm'.
+
+config CXL_PMEM
+ tristate "CXL PMEM: Persistent Memory Support"
+ depends on LIBNVDIMM
+ default CXL_BUS
+ help
+ In addition to typical memory resources a platform may also advertise
+ support for persistent memory attached via CXL. This support is
+ managed via a bridge driver from CXL to the LIBNVDIMM system
+ subsystem. Say 'y/m' to enable support for enumerating and
+ provisioning the persistent memory capacity of CXL memory expanders.
+
+ If unsure say 'm'.
endif
diff --git a/drivers/cxl/Makefile b/drivers/cxl/Makefile
index a314a1891f4d..32954059b37b 100644
--- a/drivers/cxl/Makefile
+++ b/drivers/cxl/Makefile
@@ -1,7 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_CXL_BUS) += cxl_bus.o
-obj-$(CONFIG_CXL_MEM) += cxl_mem.o
+obj-$(CONFIG_CXL_BUS) += cxl_core.o
+obj-$(CONFIG_CXL_MEM) += cxl_pci.o
+obj-$(CONFIG_CXL_ACPI) += cxl_acpi.o
+obj-$(CONFIG_CXL_PMEM) += cxl_pmem.o
ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CXL
-cxl_bus-y := bus.o
-cxl_mem-y := mem.o
+cxl_core-y := core.o
+cxl_pci-y := pci.o
+cxl_acpi-y := acpi.o
+cxl_pmem-y := pmem.o
diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
new file mode 100644
index 000000000000..8ae89273f58e
--- /dev/null
+++ b/drivers/cxl/acpi.c
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2021 Intel Corporation. All rights reserved. */
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/pci.h>
+#include "cxl.h"
+
+static struct acpi_table_header *acpi_cedt;
+
+/* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */
+#define CFMWS_INTERLEAVE_WAYS(x) (1 << (x)->interleave_ways)
+#define CFMWS_INTERLEAVE_GRANULARITY(x) ((x)->granularity + 8)
+
+static unsigned long cfmws_to_decoder_flags(int restrictions)
+{
+ unsigned long flags = 0;
+
+ if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_TYPE2)
+ flags |= CXL_DECODER_F_TYPE2;
+ if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_TYPE3)
+ flags |= CXL_DECODER_F_TYPE3;
+ if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_VOLATILE)
+ flags |= CXL_DECODER_F_RAM;
+ if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_PMEM)
+ flags |= CXL_DECODER_F_PMEM;
+ if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_FIXED)
+ flags |= CXL_DECODER_F_LOCK;
+
+ return flags;
+}
+
+static int cxl_acpi_cfmws_verify(struct device *dev,
+ struct acpi_cedt_cfmws *cfmws)
+{
+ int expected_len;
+
+ if (cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_MODULO) {
+ dev_err(dev, "CFMWS Unsupported Interleave Arithmetic\n");
+ return -EINVAL;
+ }
+
+ if (!IS_ALIGNED(cfmws->base_hpa, SZ_256M)) {
+ dev_err(dev, "CFMWS Base HPA not 256MB aligned\n");
+ return -EINVAL;
+ }
+
+ if (!IS_ALIGNED(cfmws->window_size, SZ_256M)) {
+ dev_err(dev, "CFMWS Window Size not 256MB aligned\n");
+ return -EINVAL;
+ }
+
+ expected_len = struct_size((cfmws), interleave_targets,
+ CFMWS_INTERLEAVE_WAYS(cfmws));
+
+ if (cfmws->header.length < expected_len) {
+ dev_err(dev, "CFMWS length %d less than expected %d\n",
+ cfmws->header.length, expected_len);
+ return -EINVAL;
+ }
+
+ if (cfmws->header.length > expected_len)
+ dev_dbg(dev, "CFMWS length %d greater than expected %d\n",
+ cfmws->header.length, expected_len);
+
+ return 0;
+}
+
+static void cxl_add_cfmws_decoders(struct device *dev,
+ struct cxl_port *root_port)
+{
+ struct acpi_cedt_cfmws *cfmws;
+ struct cxl_decoder *cxld;
+ acpi_size len, cur = 0;
+ void *cedt_subtable;
+ unsigned long flags;
+ int rc;
+
+ len = acpi_cedt->length - sizeof(*acpi_cedt);
+ cedt_subtable = acpi_cedt + 1;
+
+ while (cur < len) {
+ struct acpi_cedt_header *c = cedt_subtable + cur;
+
+ if (c->type != ACPI_CEDT_TYPE_CFMWS) {
+ cur += c->length;
+ continue;
+ }
+
+ cfmws = cedt_subtable + cur;
+
+ if (cfmws->header.length < sizeof(*cfmws)) {
+ dev_warn_once(dev,
+ "CFMWS entry skipped:invalid length:%u\n",
+ cfmws->header.length);
+ cur += c->length;
+ continue;
+ }
+
+ rc = cxl_acpi_cfmws_verify(dev, cfmws);
+ if (rc) {
+ dev_err(dev, "CFMWS range %#llx-%#llx not registered\n",
+ cfmws->base_hpa, cfmws->base_hpa +
+ cfmws->window_size - 1);
+ cur += c->length;
+ continue;
+ }
+
+ flags = cfmws_to_decoder_flags(cfmws->restrictions);
+ cxld = devm_cxl_add_decoder(dev, root_port,
+ CFMWS_INTERLEAVE_WAYS(cfmws),
+ cfmws->base_hpa, cfmws->window_size,
+ CFMWS_INTERLEAVE_WAYS(cfmws),
+ CFMWS_INTERLEAVE_GRANULARITY(cfmws),
+ CXL_DECODER_EXPANDER,
+ flags);
+
+ if (IS_ERR(cxld)) {
+ dev_err(dev, "Failed to add decoder for %#llx-%#llx\n",
+ cfmws->base_hpa, cfmws->base_hpa +
+ cfmws->window_size - 1);
+ } else {
+ dev_dbg(dev, "add: %s range %#llx-%#llx\n",
+ dev_name(&cxld->dev), cfmws->base_hpa,
+ cfmws->base_hpa + cfmws->window_size - 1);
+ }
+ cur += c->length;
+ }
+}
+
+static struct acpi_cedt_chbs *cxl_acpi_match_chbs(struct device *dev, u32 uid)
+{
+ struct acpi_cedt_chbs *chbs, *chbs_match = NULL;
+ acpi_size len, cur = 0;
+ void *cedt_subtable;
+
+ len = acpi_cedt->length - sizeof(*acpi_cedt);
+ cedt_subtable = acpi_cedt + 1;
+
+ while (cur < len) {
+ struct acpi_cedt_header *c = cedt_subtable + cur;
+
+ if (c->type != ACPI_CEDT_TYPE_CHBS) {
+ cur += c->length;
+ continue;
+ }
+
+ chbs = cedt_subtable + cur;
+
+ if (chbs->header.length < sizeof(*chbs)) {
+ dev_warn_once(dev,
+ "CHBS entry skipped: invalid length:%u\n",
+ chbs->header.length);
+ cur += c->length;
+ continue;
+ }
+
+ if (chbs->uid != uid) {
+ cur += c->length;
+ continue;
+ }
+
+ if (chbs_match) {
+ dev_warn_once(dev,
+ "CHBS entry skipped: duplicate UID:%u\n",
+ uid);
+ cur += c->length;
+ continue;
+ }
+
+ chbs_match = chbs;
+ cur += c->length;
+ }
+
+ return chbs_match ? chbs_match : ERR_PTR(-ENODEV);
+}
+
+static resource_size_t get_chbcr(struct acpi_cedt_chbs *chbs)
+{
+ return IS_ERR(chbs) ? CXL_RESOURCE_NONE : chbs->base;
+}
+
+struct cxl_walk_context {
+ struct device *dev;
+ struct pci_bus *root;
+ struct cxl_port *port;
+ int error;
+ int count;
+};
+
+static int match_add_root_ports(struct pci_dev *pdev, void *data)
+{
+ struct cxl_walk_context *ctx = data;
+ struct pci_bus *root_bus = ctx->root;
+ struct cxl_port *port = ctx->port;
+ int type = pci_pcie_type(pdev);
+ struct device *dev = ctx->dev;
+ u32 lnkcap, port_num;
+ int rc;
+
+ if (pdev->bus != root_bus)
+ return 0;
+ if (!pci_is_pcie(pdev))
+ return 0;
+ if (type != PCI_EXP_TYPE_ROOT_PORT)
+ return 0;
+ if (pci_read_config_dword(pdev, pci_pcie_cap(pdev) + PCI_EXP_LNKCAP,
+ &lnkcap) != PCIBIOS_SUCCESSFUL)
+ return 0;
+
+ /* TODO walk DVSEC to find component register base */
+ port_num = FIELD_GET(PCI_EXP_LNKCAP_PN, lnkcap);
+ rc = cxl_add_dport(port, &pdev->dev, port_num, CXL_RESOURCE_NONE);
+ if (rc) {
+ ctx->error = rc;
+ return rc;
+ }
+ ctx->count++;
+
+ dev_dbg(dev, "add dport%d: %s\n", port_num, dev_name(&pdev->dev));
+
+ return 0;
+}
+
+static struct cxl_dport *find_dport_by_dev(struct cxl_port *port, struct device *dev)
+{
+ struct cxl_dport *dport;
+
+ device_lock(&port->dev);
+ list_for_each_entry(dport, &port->dports, list)
+ if (dport->dport == dev) {
+ device_unlock(&port->dev);
+ return dport;
+ }
+
+ device_unlock(&port->dev);
+ return NULL;
+}
+
+static struct acpi_device *to_cxl_host_bridge(struct device *dev)
+{
+ struct acpi_device *adev = to_acpi_device(dev);
+
+ if (strcmp(acpi_device_hid(adev), "ACPI0016") == 0)
+ return adev;
+ return NULL;
+}
+
+/*
+ * A host bridge is a dport to a CFMWS decode and it is a uport to the
+ * dport (PCIe Root Ports) in the host bridge.
+ */
+static int add_host_bridge_uport(struct device *match, void *arg)
+{
+ struct acpi_device *bridge = to_cxl_host_bridge(match);
+ struct cxl_port *root_port = arg;
+ struct device *host = root_port->dev.parent;
+ struct acpi_pci_root *pci_root;
+ struct cxl_walk_context ctx;
+ struct cxl_decoder *cxld;
+ struct cxl_dport *dport;
+ struct cxl_port *port;
+
+ if (!bridge)
+ return 0;
+
+ pci_root = acpi_pci_find_root(bridge->handle);
+ if (!pci_root)
+ return -ENXIO;
+
+ dport = find_dport_by_dev(root_port, match);
+ if (!dport) {
+ dev_dbg(host, "host bridge expected and not found\n");
+ return -ENODEV;
+ }
+
+ port = devm_cxl_add_port(host, match, dport->component_reg_phys,
+ root_port);
+ if (IS_ERR(port))
+ return PTR_ERR(port);
+ dev_dbg(host, "%s: add: %s\n", dev_name(match), dev_name(&port->dev));
+
+ ctx = (struct cxl_walk_context){
+ .dev = host,
+ .root = pci_root->bus,
+ .port = port,
+ };
+ pci_walk_bus(pci_root->bus, match_add_root_ports, &ctx);
+
+ if (ctx.count == 0)
+ return -ENODEV;
+ if (ctx.error)
+ return ctx.error;
+
+ /* TODO: Scan CHBCR for HDM Decoder resources */
+
+ /*
+ * In the single-port host-bridge case there are no HDM decoders
+ * in the CHBCR and a 1:1 passthrough decode is implied.
+ */
+ if (ctx.count == 1) {
+ cxld = devm_cxl_add_passthrough_decoder(host, port);
+ if (IS_ERR(cxld))
+ return PTR_ERR(cxld);
+
+ dev_dbg(host, "add: %s\n", dev_name(&cxld->dev));
+ }
+
+ return 0;
+}
+
+static int add_host_bridge_dport(struct device *match, void *arg)
+{
+ int rc;
+ acpi_status status;
+ unsigned long long uid;
+ struct acpi_cedt_chbs *chbs;
+ struct cxl_port *root_port = arg;
+ struct device *host = root_port->dev.parent;
+ struct acpi_device *bridge = to_cxl_host_bridge(match);
+
+ if (!bridge)
+ return 0;
+
+ status = acpi_evaluate_integer(bridge->handle, METHOD_NAME__UID, NULL,
+ &uid);
+ if (status != AE_OK) {
+ dev_err(host, "unable to retrieve _UID of %s\n",
+ dev_name(match));
+ return -ENODEV;
+ }
+
+ chbs = cxl_acpi_match_chbs(host, uid);
+ if (IS_ERR(chbs))
+ dev_dbg(host, "No CHBS found for Host Bridge: %s\n",
+ dev_name(match));
+
+ rc = cxl_add_dport(root_port, match, uid, get_chbcr(chbs));
+ if (rc) {
+ dev_err(host, "failed to add downstream port: %s\n",
+ dev_name(match));
+ return rc;
+ }
+ dev_dbg(host, "add dport%llu: %s\n", uid, dev_name(match));
+ return 0;
+}
+
+static int add_root_nvdimm_bridge(struct device *match, void *data)
+{
+ struct cxl_decoder *cxld;
+ struct cxl_port *root_port = data;
+ struct cxl_nvdimm_bridge *cxl_nvb;
+ struct device *host = root_port->dev.parent;
+
+ if (!is_root_decoder(match))
+ return 0;
+
+ cxld = to_cxl_decoder(match);
+ if (!(cxld->flags & CXL_DECODER_F_PMEM))
+ return 0;
+
+ cxl_nvb = devm_cxl_add_nvdimm_bridge(host, root_port);
+ if (IS_ERR(cxl_nvb)) {
+ dev_dbg(host, "failed to register pmem\n");
+ return PTR_ERR(cxl_nvb);
+ }
+ dev_dbg(host, "%s: add: %s\n", dev_name(&root_port->dev),
+ dev_name(&cxl_nvb->dev));
+ return 1;
+}
+
+static int cxl_acpi_probe(struct platform_device *pdev)
+{
+ int rc;
+ acpi_status status;
+ struct cxl_port *root_port;
+ struct device *host = &pdev->dev;
+ struct acpi_device *adev = ACPI_COMPANION(host);
+
+ root_port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL);
+ if (IS_ERR(root_port))
+ return PTR_ERR(root_port);
+ dev_dbg(host, "add: %s\n", dev_name(&root_port->dev));
+
+ status = acpi_get_table(ACPI_SIG_CEDT, 0, &acpi_cedt);
+ if (ACPI_FAILURE(status))
+ return -ENXIO;
+
+ rc = bus_for_each_dev(adev->dev.bus, NULL, root_port,
+ add_host_bridge_dport);
+ if (rc)
+ goto out;
+
+ cxl_add_cfmws_decoders(host, root_port);
+
+ /*
+ * Root level scanned with host-bridge as dports, now scan host-bridges
+ * for their role as CXL uports to their CXL-capable PCIe Root Ports.
+ */
+ rc = bus_for_each_dev(adev->dev.bus, NULL, root_port,
+ add_host_bridge_uport);
+ if (rc)
+ goto out;
+
+ if (IS_ENABLED(CONFIG_CXL_PMEM))
+ rc = device_for_each_child(&root_port->dev, root_port,
+ add_root_nvdimm_bridge);
+
+out:
+ acpi_put_table(acpi_cedt);
+ if (rc < 0)
+ return rc;
+ return 0;
+}
+
+static const struct acpi_device_id cxl_acpi_ids[] = {
+ { "ACPI0017", 0 },
+ { "", 0 },
+};
+MODULE_DEVICE_TABLE(acpi, cxl_acpi_ids);
+
+static struct platform_driver cxl_acpi_driver = {
+ .probe = cxl_acpi_probe,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .acpi_match_table = cxl_acpi_ids,
+ },
+};
+
+module_platform_driver(cxl_acpi_driver);
+MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(CXL);
diff --git a/drivers/cxl/bus.c b/drivers/cxl/bus.c
deleted file mode 100644
index 58f74796d525..000000000000
--- a/drivers/cxl/bus.c
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright(c) 2020 Intel Corporation. All rights reserved. */
-#include <linux/device.h>
-#include <linux/module.h>
-
-/**
- * DOC: cxl bus
- *
- * The CXL bus provides namespace for control devices and a rendezvous
- * point for cross-device interleave coordination.
- */
-struct bus_type cxl_bus_type = {
- .name = "cxl",
-};
-EXPORT_SYMBOL_GPL(cxl_bus_type);
-
-static __init int cxl_bus_init(void)
-{
- return bus_register(&cxl_bus_type);
-}
-
-static void cxl_bus_exit(void)
-{
- bus_unregister(&cxl_bus_type);
-}
-
-module_init(cxl_bus_init);
-module_exit(cxl_bus_exit);
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/cxl/core.c b/drivers/cxl/core.c
new file mode 100644
index 000000000000..a2e4d54fc7bc
--- /dev/null
+++ b/drivers/cxl/core.c
@@ -0,0 +1,1067 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2020 Intel Corporation. All rights reserved. */
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include "cxl.h"
+#include "mem.h"
+
+/**
+ * DOC: cxl core
+ *
+ * The CXL core provides a sysfs hierarchy for control devices and a rendezvous
+ * point for cross-device interleave coordination through cxl ports.
+ */
+
+static DEFINE_IDA(cxl_port_ida);
+
+static ssize_t devtype_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%s\n", dev->type->name);
+}
+static DEVICE_ATTR_RO(devtype);
+
+static struct attribute *cxl_base_attributes[] = {
+ &dev_attr_devtype.attr,
+ NULL,
+};
+
+static struct attribute_group cxl_base_attribute_group = {
+ .attrs = cxl_base_attributes,
+};
+
+static ssize_t start_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_decoder *cxld = to_cxl_decoder(dev);
+
+ return sysfs_emit(buf, "%#llx\n", cxld->range.start);
+}
+static DEVICE_ATTR_RO(start);
+
+static ssize_t size_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_decoder *cxld = to_cxl_decoder(dev);
+
+ return sysfs_emit(buf, "%#llx\n", range_len(&cxld->range));
+}
+static DEVICE_ATTR_RO(size);
+
+#define CXL_DECODER_FLAG_ATTR(name, flag) \
+static ssize_t name##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct cxl_decoder *cxld = to_cxl_decoder(dev); \
+ \
+ return sysfs_emit(buf, "%s\n", \
+ (cxld->flags & (flag)) ? "1" : "0"); \
+} \
+static DEVICE_ATTR_RO(name)
+
+CXL_DECODER_FLAG_ATTR(cap_pmem, CXL_DECODER_F_PMEM);
+CXL_DECODER_FLAG_ATTR(cap_ram, CXL_DECODER_F_RAM);
+CXL_DECODER_FLAG_ATTR(cap_type2, CXL_DECODER_F_TYPE2);
+CXL_DECODER_FLAG_ATTR(cap_type3, CXL_DECODER_F_TYPE3);
+CXL_DECODER_FLAG_ATTR(locked, CXL_DECODER_F_LOCK);
+
+static ssize_t target_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cxl_decoder *cxld = to_cxl_decoder(dev);
+
+ switch (cxld->target_type) {
+ case CXL_DECODER_ACCELERATOR:
+ return sysfs_emit(buf, "accelerator\n");
+ case CXL_DECODER_EXPANDER:
+ return sysfs_emit(buf, "expander\n");
+ }
+ return -ENXIO;
+}
+static DEVICE_ATTR_RO(target_type);
+
+static ssize_t target_list_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cxl_decoder *cxld = to_cxl_decoder(dev);
+ ssize_t offset = 0;
+ int i, rc = 0;
+
+ device_lock(dev);
+ for (i = 0; i < cxld->interleave_ways; i++) {
+ struct cxl_dport *dport = cxld->target[i];
+ struct cxl_dport *next = NULL;
+
+ if (!dport)
+ break;
+
+ if (i + 1 < cxld->interleave_ways)
+ next = cxld->target[i + 1];
+ rc = sysfs_emit_at(buf, offset, "%d%s", dport->port_id,
+ next ? "," : "");
+ if (rc < 0)
+ break;
+ offset += rc;
+ }
+ device_unlock(dev);
+
+ if (rc < 0)
+ return rc;
+
+ rc = sysfs_emit_at(buf, offset, "\n");
+ if (rc < 0)
+ return rc;
+
+ return offset + rc;
+}
+static DEVICE_ATTR_RO(target_list);
+
+static struct attribute *cxl_decoder_base_attrs[] = {
+ &dev_attr_start.attr,
+ &dev_attr_size.attr,
+ &dev_attr_locked.attr,
+ &dev_attr_target_list.attr,
+ NULL,
+};
+
+static struct attribute_group cxl_decoder_base_attribute_group = {
+ .attrs = cxl_decoder_base_attrs,
+};
+
+static struct attribute *cxl_decoder_root_attrs[] = {
+ &dev_attr_cap_pmem.attr,
+ &dev_attr_cap_ram.attr,
+ &dev_attr_cap_type2.attr,
+ &dev_attr_cap_type3.attr,
+ NULL,
+};
+
+static struct attribute_group cxl_decoder_root_attribute_group = {
+ .attrs = cxl_decoder_root_attrs,
+};
+
+static const struct attribute_group *cxl_decoder_root_attribute_groups[] = {
+ &cxl_decoder_root_attribute_group,
+ &cxl_decoder_base_attribute_group,
+ &cxl_base_attribute_group,
+ NULL,
+};
+
+static struct attribute *cxl_decoder_switch_attrs[] = {
+ &dev_attr_target_type.attr,
+ NULL,
+};
+
+static struct attribute_group cxl_decoder_switch_attribute_group = {
+ .attrs = cxl_decoder_switch_attrs,
+};
+
+static const struct attribute_group *cxl_decoder_switch_attribute_groups[] = {
+ &cxl_decoder_switch_attribute_group,
+ &cxl_decoder_base_attribute_group,
+ &cxl_base_attribute_group,
+ NULL,
+};
+
+static void cxl_decoder_release(struct device *dev)
+{
+ struct cxl_decoder *cxld = to_cxl_decoder(dev);
+ struct cxl_port *port = to_cxl_port(dev->parent);
+
+ ida_free(&port->decoder_ida, cxld->id);
+ kfree(cxld);
+}
+
+static const struct device_type cxl_decoder_switch_type = {
+ .name = "cxl_decoder_switch",
+ .release = cxl_decoder_release,
+ .groups = cxl_decoder_switch_attribute_groups,
+};
+
+static const struct device_type cxl_decoder_root_type = {
+ .name = "cxl_decoder_root",
+ .release = cxl_decoder_release,
+ .groups = cxl_decoder_root_attribute_groups,
+};
+
+bool is_root_decoder(struct device *dev)
+{
+ return dev->type == &cxl_decoder_root_type;
+}
+EXPORT_SYMBOL_GPL(is_root_decoder);
+
+struct cxl_decoder *to_cxl_decoder(struct device *dev)
+{
+ if (dev_WARN_ONCE(dev, dev->type->release != cxl_decoder_release,
+ "not a cxl_decoder device\n"))
+ return NULL;
+ return container_of(dev, struct cxl_decoder, dev);
+}
+EXPORT_SYMBOL_GPL(to_cxl_decoder);
+
+static void cxl_dport_release(struct cxl_dport *dport)
+{
+ list_del(&dport->list);
+ put_device(dport->dport);
+ kfree(dport);
+}
+
+static void cxl_port_release(struct device *dev)
+{
+ struct cxl_port *port = to_cxl_port(dev);
+ struct cxl_dport *dport, *_d;
+
+ device_lock(dev);
+ list_for_each_entry_safe(dport, _d, &port->dports, list)
+ cxl_dport_release(dport);
+ device_unlock(dev);
+ ida_free(&cxl_port_ida, port->id);
+ kfree(port);
+}
+
+static const struct attribute_group *cxl_port_attribute_groups[] = {
+ &cxl_base_attribute_group,
+ NULL,
+};
+
+static const struct device_type cxl_port_type = {
+ .name = "cxl_port",
+ .release = cxl_port_release,
+ .groups = cxl_port_attribute_groups,
+};
+
+struct cxl_port *to_cxl_port(struct device *dev)
+{
+ if (dev_WARN_ONCE(dev, dev->type != &cxl_port_type,
+ "not a cxl_port device\n"))
+ return NULL;
+ return container_of(dev, struct cxl_port, dev);
+}
+
+static void unregister_port(void *_port)
+{
+ struct cxl_port *port = _port;
+ struct cxl_dport *dport;
+
+ device_lock(&port->dev);
+ list_for_each_entry(dport, &port->dports, list) {
+ char link_name[CXL_TARGET_STRLEN];
+
+ if (snprintf(link_name, CXL_TARGET_STRLEN, "dport%d",
+ dport->port_id) >= CXL_TARGET_STRLEN)
+ continue;
+ sysfs_remove_link(&port->dev.kobj, link_name);
+ }
+ device_unlock(&port->dev);
+ device_unregister(&port->dev);
+}
+
+static void cxl_unlink_uport(void *_port)
+{
+ struct cxl_port *port = _port;
+
+ sysfs_remove_link(&port->dev.kobj, "uport");
+}
+
+static int devm_cxl_link_uport(struct device *host, struct cxl_port *port)
+{
+ int rc;
+
+ rc = sysfs_create_link(&port->dev.kobj, &port->uport->kobj, "uport");
+ if (rc)
+ return rc;
+ return devm_add_action_or_reset(host, cxl_unlink_uport, port);
+}
+
+static struct cxl_port *cxl_port_alloc(struct device *uport,
+ resource_size_t component_reg_phys,
+ struct cxl_port *parent_port)
+{
+ struct cxl_port *port;
+ struct device *dev;
+ int rc;
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return ERR_PTR(-ENOMEM);
+
+ rc = ida_alloc(&cxl_port_ida, GFP_KERNEL);
+ if (rc < 0)
+ goto err;
+ port->id = rc;
+
+ /*
+ * The top-level cxl_port "cxl_root" does not have a cxl_port as
+ * its parent and it does not have any corresponding component
+ * registers as its decode is described by a fixed platform
+ * description.
+ */
+ dev = &port->dev;
+ if (parent_port)
+ dev->parent = &parent_port->dev;
+ else
+ dev->parent = uport;
+
+ port->uport = uport;
+ port->component_reg_phys = component_reg_phys;
+ ida_init(&port->decoder_ida);
+ INIT_LIST_HEAD(&port->dports);
+
+ device_initialize(dev);
+ device_set_pm_not_required(dev);
+ dev->bus = &cxl_bus_type;
+ dev->type = &cxl_port_type;
+
+ return port;
+
+err:
+ kfree(port);
+ return ERR_PTR(rc);
+}
+
+/**
+ * devm_cxl_add_port - register a cxl_port in CXL memory decode hierarchy
+ * @host: host device for devm operations
+ * @uport: "physical" device implementing this upstream port
+ * @component_reg_phys: (optional) for configurable cxl_port instances
+ * @parent_port: next hop up in the CXL memory decode hierarchy
+ */
+struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
+ resource_size_t component_reg_phys,
+ struct cxl_port *parent_port)
+{
+ struct cxl_port *port;
+ struct device *dev;
+ int rc;
+
+ port = cxl_port_alloc(uport, component_reg_phys, parent_port);
+ if (IS_ERR(port))
+ return port;
+
+ dev = &port->dev;
+ if (parent_port)
+ rc = dev_set_name(dev, "port%d", port->id);
+ else
+ rc = dev_set_name(dev, "root%d", port->id);
+ if (rc)
+ goto err;
+
+ rc = device_add(dev);
+ if (rc)
+ goto err;
+
+ rc = devm_add_action_or_reset(host, unregister_port, port);
+ if (rc)
+ return ERR_PTR(rc);
+
+ rc = devm_cxl_link_uport(host, port);
+ if (rc)
+ return ERR_PTR(rc);
+
+ return port;
+
+err:
+ put_device(dev);
+ return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(devm_cxl_add_port);
+
+static struct cxl_dport *find_dport(struct cxl_port *port, int id)
+{
+ struct cxl_dport *dport;
+
+ device_lock_assert(&port->dev);
+ list_for_each_entry (dport, &port->dports, list)
+ if (dport->port_id == id)
+ return dport;
+ return NULL;
+}
+
+static int add_dport(struct cxl_port *port, struct cxl_dport *new)
+{
+ struct cxl_dport *dup;
+
+ device_lock(&port->dev);
+ dup = find_dport(port, new->port_id);
+ if (dup)
+ dev_err(&port->dev,
+ "unable to add dport%d-%s non-unique port id (%s)\n",
+ new->port_id, dev_name(new->dport),
+ dev_name(dup->dport));
+ else
+ list_add_tail(&new->list, &port->dports);
+ device_unlock(&port->dev);
+
+ return dup ? -EEXIST : 0;
+}
+
+/**
+ * cxl_add_dport - append downstream port data to a cxl_port
+ * @port: the cxl_port that references this dport
+ * @dport_dev: firmware or PCI device representing the dport
+ * @port_id: identifier for this dport in a decoder's target list
+ * @component_reg_phys: optional location of CXL component registers
+ *
+ * Note that all allocations and links are undone by cxl_port deletion
+ * and release.
+ */
+int cxl_add_dport(struct cxl_port *port, struct device *dport_dev, int port_id,
+ resource_size_t component_reg_phys)
+{
+ char link_name[CXL_TARGET_STRLEN];
+ struct cxl_dport *dport;
+ int rc;
+
+ if (snprintf(link_name, CXL_TARGET_STRLEN, "dport%d", port_id) >=
+ CXL_TARGET_STRLEN)
+ return -EINVAL;
+
+ dport = kzalloc(sizeof(*dport), GFP_KERNEL);
+ if (!dport)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&dport->list);
+ dport->dport = get_device(dport_dev);
+ dport->port_id = port_id;
+ dport->component_reg_phys = component_reg_phys;
+ dport->port = port;
+
+ rc = add_dport(port, dport);
+ if (rc)
+ goto err;
+
+ rc = sysfs_create_link(&port->dev.kobj, &dport_dev->kobj, link_name);
+ if (rc)
+ goto err;
+
+ return 0;
+err:
+ cxl_dport_release(dport);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(cxl_add_dport);
+
+static struct cxl_decoder *
+cxl_decoder_alloc(struct cxl_port *port, int nr_targets, resource_size_t base,
+ resource_size_t len, int interleave_ways,
+ int interleave_granularity, enum cxl_decoder_type type,
+ unsigned long flags)
+{
+ struct cxl_decoder *cxld;
+ struct device *dev;
+ int rc = 0;
+
+ if (interleave_ways < 1)
+ return ERR_PTR(-EINVAL);
+
+ device_lock(&port->dev);
+ if (list_empty(&port->dports))
+ rc = -EINVAL;
+ device_unlock(&port->dev);
+ if (rc)
+ return ERR_PTR(rc);
+
+ cxld = kzalloc(struct_size(cxld, target, nr_targets), GFP_KERNEL);
+ if (!cxld)
+ return ERR_PTR(-ENOMEM);
+
+ rc = ida_alloc(&port->decoder_ida, GFP_KERNEL);
+ if (rc < 0)
+ goto err;
+
+ *cxld = (struct cxl_decoder) {
+ .id = rc,
+ .range = {
+ .start = base,
+ .end = base + len - 1,
+ },
+ .flags = flags,
+ .interleave_ways = interleave_ways,
+ .interleave_granularity = interleave_granularity,
+ .target_type = type,
+ };
+
+ /* handle implied target_list */
+ if (interleave_ways == 1)
+ cxld->target[0] =
+ list_first_entry(&port->dports, struct cxl_dport, list);
+ dev = &cxld->dev;
+ device_initialize(dev);
+ device_set_pm_not_required(dev);
+ dev->parent = &port->dev;
+ dev->bus = &cxl_bus_type;
+
+ /* root ports do not have a cxl_port_type parent */
+ if (port->dev.parent->type == &cxl_port_type)
+ dev->type = &cxl_decoder_switch_type;
+ else
+ dev->type = &cxl_decoder_root_type;
+
+ return cxld;
+err:
+ kfree(cxld);
+ return ERR_PTR(rc);
+}
+
+static void unregister_dev(void *dev)
+{
+ device_unregister(dev);
+}
+
+struct cxl_decoder *
+devm_cxl_add_decoder(struct device *host, struct cxl_port *port, int nr_targets,
+ resource_size_t base, resource_size_t len,
+ int interleave_ways, int interleave_granularity,
+ enum cxl_decoder_type type, unsigned long flags)
+{
+ struct cxl_decoder *cxld;
+ struct device *dev;
+ int rc;
+
+ cxld = cxl_decoder_alloc(port, nr_targets, base, len, interleave_ways,
+ interleave_granularity, type, flags);
+ if (IS_ERR(cxld))
+ return cxld;
+
+ dev = &cxld->dev;
+ rc = dev_set_name(dev, "decoder%d.%d", port->id, cxld->id);
+ if (rc)
+ goto err;
+
+ rc = device_add(dev);
+ if (rc)
+ goto err;
+
+ rc = devm_add_action_or_reset(host, unregister_dev, dev);
+ if (rc)
+ return ERR_PTR(rc);
+ return cxld;
+
+err:
+ put_device(dev);
+ return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(devm_cxl_add_decoder);
+
+/**
+ * cxl_probe_component_regs() - Detect CXL Component register blocks
+ * @dev: Host device of the @base mapping
+ * @base: Mapping containing the HDM Decoder Capability Header
+ * @map: Map object describing the register block information found
+ *
+ * See CXL 2.0 8.2.4 Component Register Layout and Definition
+ * See CXL 2.0 8.2.5.5 CXL Device Register Interface
+ *
+ * Probe for component register information and return it in map object.
+ */
+void cxl_probe_component_regs(struct device *dev, void __iomem *base,
+ struct cxl_component_reg_map *map)
+{
+ int cap, cap_count;
+ u64 cap_array;
+
+ *map = (struct cxl_component_reg_map) { 0 };
+
+ /*
+ * CXL.cache and CXL.mem registers are at offset 0x1000 as defined in
+ * CXL 2.0 8.2.4 Table 141.
+ */
+ base += CXL_CM_OFFSET;
+
+ cap_array = readq(base + CXL_CM_CAP_HDR_OFFSET);
+
+ if (FIELD_GET(CXL_CM_CAP_HDR_ID_MASK, cap_array) != CM_CAP_HDR_CAP_ID) {
+ dev_err(dev,
+ "Couldn't locate the CXL.cache and CXL.mem capability array header./n");
+ return;
+ }
+
+ /* It's assumed that future versions will be backward compatible */
+ cap_count = FIELD_GET(CXL_CM_CAP_HDR_ARRAY_SIZE_MASK, cap_array);
+
+ for (cap = 1; cap <= cap_count; cap++) {
+ void __iomem *register_block;
+ u32 hdr;
+ int decoder_cnt;
+ u16 cap_id, offset;
+ u32 length;
+
+ hdr = readl(base + cap * 0x4);
+
+ cap_id = FIELD_GET(CXL_CM_CAP_HDR_ID_MASK, hdr);
+ offset = FIELD_GET(CXL_CM_CAP_PTR_MASK, hdr);
+ register_block = base + offset;
+
+ switch (cap_id) {
+ case CXL_CM_CAP_CAP_ID_HDM:
+ dev_dbg(dev, "found HDM decoder capability (0x%x)\n",
+ offset);
+
+ hdr = readl(register_block);
+
+ decoder_cnt = cxl_hdm_decoder_count(hdr);
+ length = 0x20 * decoder_cnt + 0x10;
+
+ map->hdm_decoder.valid = true;
+ map->hdm_decoder.offset = CXL_CM_OFFSET + offset;
+ map->hdm_decoder.size = length;
+ break;
+ default:
+ dev_dbg(dev, "Unknown CM cap ID: %d (0x%x)\n", cap_id,
+ offset);
+ break;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(cxl_probe_component_regs);
+
+static void cxl_nvdimm_bridge_release(struct device *dev)
+{
+ struct cxl_nvdimm_bridge *cxl_nvb = to_cxl_nvdimm_bridge(dev);
+
+ kfree(cxl_nvb);
+}
+
+static const struct attribute_group *cxl_nvdimm_bridge_attribute_groups[] = {
+ &cxl_base_attribute_group,
+ NULL,
+};
+
+static const struct device_type cxl_nvdimm_bridge_type = {
+ .name = "cxl_nvdimm_bridge",
+ .release = cxl_nvdimm_bridge_release,
+ .groups = cxl_nvdimm_bridge_attribute_groups,
+};
+
+struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev)
+{
+ if (dev_WARN_ONCE(dev, dev->type != &cxl_nvdimm_bridge_type,
+ "not a cxl_nvdimm_bridge device\n"))
+ return NULL;
+ return container_of(dev, struct cxl_nvdimm_bridge, dev);
+}
+EXPORT_SYMBOL_GPL(to_cxl_nvdimm_bridge);
+
+static struct cxl_nvdimm_bridge *
+cxl_nvdimm_bridge_alloc(struct cxl_port *port)
+{
+ struct cxl_nvdimm_bridge *cxl_nvb;
+ struct device *dev;
+
+ cxl_nvb = kzalloc(sizeof(*cxl_nvb), GFP_KERNEL);
+ if (!cxl_nvb)
+ return ERR_PTR(-ENOMEM);
+
+ dev = &cxl_nvb->dev;
+ cxl_nvb->port = port;
+ cxl_nvb->state = CXL_NVB_NEW;
+ device_initialize(dev);
+ device_set_pm_not_required(dev);
+ dev->parent = &port->dev;
+ dev->bus = &cxl_bus_type;
+ dev->type = &cxl_nvdimm_bridge_type;
+
+ return cxl_nvb;
+}
+
+static void unregister_nvb(void *_cxl_nvb)
+{
+ struct cxl_nvdimm_bridge *cxl_nvb = _cxl_nvb;
+ bool flush;
+
+ /*
+ * If the bridge was ever activated then there might be in-flight state
+ * work to flush. Once the state has been changed to 'dead' then no new
+ * work can be queued by user-triggered bind.
+ */
+ device_lock(&cxl_nvb->dev);
+ flush = cxl_nvb->state != CXL_NVB_NEW;
+ cxl_nvb->state = CXL_NVB_DEAD;
+ device_unlock(&cxl_nvb->dev);
+
+ /*
+ * Even though the device core will trigger device_release_driver()
+ * before the unregister, it does not know about the fact that
+ * cxl_nvdimm_bridge_driver defers ->remove() work. So, do the driver
+ * release not and flush it before tearing down the nvdimm device
+ * hierarchy.
+ */
+ device_release_driver(&cxl_nvb->dev);
+ if (flush)
+ flush_work(&cxl_nvb->state_work);
+ device_unregister(&cxl_nvb->dev);
+}
+
+struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
+ struct cxl_port *port)
+{
+ struct cxl_nvdimm_bridge *cxl_nvb;
+ struct device *dev;
+ int rc;
+
+ if (!IS_ENABLED(CONFIG_CXL_PMEM))
+ return ERR_PTR(-ENXIO);
+
+ cxl_nvb = cxl_nvdimm_bridge_alloc(port);
+ if (IS_ERR(cxl_nvb))
+ return cxl_nvb;
+
+ dev = &cxl_nvb->dev;
+ rc = dev_set_name(dev, "nvdimm-bridge");
+ if (rc)
+ goto err;
+
+ rc = device_add(dev);
+ if (rc)
+ goto err;
+
+ rc = devm_add_action_or_reset(host, unregister_nvb, cxl_nvb);
+ if (rc)
+ return ERR_PTR(rc);
+
+ return cxl_nvb;
+
+err:
+ put_device(dev);
+ return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(devm_cxl_add_nvdimm_bridge);
+
+static void cxl_nvdimm_release(struct device *dev)
+{
+ struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev);
+
+ kfree(cxl_nvd);
+}
+
+static const struct attribute_group *cxl_nvdimm_attribute_groups[] = {
+ &cxl_base_attribute_group,
+ NULL,
+};
+
+static const struct device_type cxl_nvdimm_type = {
+ .name = "cxl_nvdimm",
+ .release = cxl_nvdimm_release,
+ .groups = cxl_nvdimm_attribute_groups,
+};
+
+bool is_cxl_nvdimm(struct device *dev)
+{
+ return dev->type == &cxl_nvdimm_type;
+}
+EXPORT_SYMBOL_GPL(is_cxl_nvdimm);
+
+struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev)
+{
+ if (dev_WARN_ONCE(dev, !is_cxl_nvdimm(dev),
+ "not a cxl_nvdimm device\n"))
+ return NULL;
+ return container_of(dev, struct cxl_nvdimm, dev);
+}
+EXPORT_SYMBOL_GPL(to_cxl_nvdimm);
+
+static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_memdev *cxlmd)
+{
+ struct cxl_nvdimm *cxl_nvd;
+ struct device *dev;
+
+ cxl_nvd = kzalloc(sizeof(*cxl_nvd), GFP_KERNEL);
+ if (!cxl_nvd)
+ return ERR_PTR(-ENOMEM);
+
+ dev = &cxl_nvd->dev;
+ cxl_nvd->cxlmd = cxlmd;
+ device_initialize(dev);
+ device_set_pm_not_required(dev);
+ dev->parent = &cxlmd->dev;
+ dev->bus = &cxl_bus_type;
+ dev->type = &cxl_nvdimm_type;
+
+ return cxl_nvd;
+}
+
+int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd)
+{
+ struct cxl_nvdimm *cxl_nvd;
+ struct device *dev;
+ int rc;
+
+ cxl_nvd = cxl_nvdimm_alloc(cxlmd);
+ if (IS_ERR(cxl_nvd))
+ return PTR_ERR(cxl_nvd);
+
+ dev = &cxl_nvd->dev;
+ rc = dev_set_name(dev, "pmem%d", cxlmd->id);
+ if (rc)
+ goto err;
+
+ rc = device_add(dev);
+ if (rc)
+ goto err;
+
+ dev_dbg(host, "%s: register %s\n", dev_name(dev->parent),
+ dev_name(dev));
+
+ return devm_add_action_or_reset(host, unregister_dev, dev);
+
+err:
+ put_device(dev);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(devm_cxl_add_nvdimm);
+
+/**
+ * cxl_probe_device_regs() - Detect CXL Device register blocks
+ * @dev: Host device of the @base mapping
+ * @base: Mapping of CXL 2.0 8.2.8 CXL Device Register Interface
+ * @map: Map object describing the register block information found
+ *
+ * Probe for device register information and return it in map object.
+ */
+void cxl_probe_device_regs(struct device *dev, void __iomem *base,
+ struct cxl_device_reg_map *map)
+{
+ int cap, cap_count;
+ u64 cap_array;
+
+ *map = (struct cxl_device_reg_map){ 0 };
+
+ cap_array = readq(base + CXLDEV_CAP_ARRAY_OFFSET);
+ if (FIELD_GET(CXLDEV_CAP_ARRAY_ID_MASK, cap_array) !=
+ CXLDEV_CAP_ARRAY_CAP_ID)
+ return;
+
+ cap_count = FIELD_GET(CXLDEV_CAP_ARRAY_COUNT_MASK, cap_array);
+
+ for (cap = 1; cap <= cap_count; cap++) {
+ u32 offset, length;
+ u16 cap_id;
+
+ cap_id = FIELD_GET(CXLDEV_CAP_HDR_CAP_ID_MASK,
+ readl(base + cap * 0x10));
+ offset = readl(base + cap * 0x10 + 0x4);
+ length = readl(base + cap * 0x10 + 0x8);
+
+ switch (cap_id) {
+ case CXLDEV_CAP_CAP_ID_DEVICE_STATUS:
+ dev_dbg(dev, "found Status capability (0x%x)\n", offset);
+
+ map->status.valid = true;
+ map->status.offset = offset;
+ map->status.size = length;
+ break;
+ case CXLDEV_CAP_CAP_ID_PRIMARY_MAILBOX:
+ dev_dbg(dev, "found Mailbox capability (0x%x)\n", offset);
+ map->mbox.valid = true;
+ map->mbox.offset = offset;
+ map->mbox.size = length;
+ break;
+ case CXLDEV_CAP_CAP_ID_SECONDARY_MAILBOX:
+ dev_dbg(dev, "found Secondary Mailbox capability (0x%x)\n", offset);
+ break;
+ case CXLDEV_CAP_CAP_ID_MEMDEV:
+ dev_dbg(dev, "found Memory Device capability (0x%x)\n", offset);
+ map->memdev.valid = true;
+ map->memdev.offset = offset;
+ map->memdev.size = length;
+ break;
+ default:
+ if (cap_id >= 0x8000)
+ dev_dbg(dev, "Vendor cap ID: %#x offset: %#x\n", cap_id, offset);
+ else
+ dev_dbg(dev, "Unknown cap ID: %#x offset: %#x\n", cap_id, offset);
+ break;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(cxl_probe_device_regs);
+
+static void __iomem *devm_cxl_iomap_block(struct device *dev,
+ resource_size_t addr,
+ resource_size_t length)
+{
+ void __iomem *ret_val;
+ struct resource *res;
+
+ res = devm_request_mem_region(dev, addr, length, dev_name(dev));
+ if (!res) {
+ resource_size_t end = addr + length - 1;
+
+ dev_err(dev, "Failed to request region %pa-%pa\n", &addr, &end);
+ return NULL;
+ }
+
+ ret_val = devm_ioremap(dev, addr, length);
+ if (!ret_val)
+ dev_err(dev, "Failed to map region %pr\n", res);
+
+ return ret_val;
+}
+
+int cxl_map_component_regs(struct pci_dev *pdev,
+ struct cxl_component_regs *regs,
+ struct cxl_register_map *map)
+{
+ struct device *dev = &pdev->dev;
+ resource_size_t phys_addr;
+ resource_size_t length;
+
+ phys_addr = pci_resource_start(pdev, map->barno);
+ phys_addr += map->block_offset;
+
+ phys_addr += map->component_map.hdm_decoder.offset;
+ length = map->component_map.hdm_decoder.size;
+ regs->hdm_decoder = devm_cxl_iomap_block(dev, phys_addr, length);
+ if (!regs->hdm_decoder)
+ return -ENOMEM;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cxl_map_component_regs);
+
+int cxl_map_device_regs(struct pci_dev *pdev,
+ struct cxl_device_regs *regs,
+ struct cxl_register_map *map)
+{
+ struct device *dev = &pdev->dev;
+ resource_size_t phys_addr;
+
+ phys_addr = pci_resource_start(pdev, map->barno);
+ phys_addr += map->block_offset;
+
+ if (map->device_map.status.valid) {
+ resource_size_t addr;
+ resource_size_t length;
+
+ addr = phys_addr + map->device_map.status.offset;
+ length = map->device_map.status.size;
+ regs->status = devm_cxl_iomap_block(dev, addr, length);
+ if (!regs->status)
+ return -ENOMEM;
+ }
+
+ if (map->device_map.mbox.valid) {
+ resource_size_t addr;
+ resource_size_t length;
+
+ addr = phys_addr + map->device_map.mbox.offset;
+ length = map->device_map.mbox.size;
+ regs->mbox = devm_cxl_iomap_block(dev, addr, length);
+ if (!regs->mbox)
+ return -ENOMEM;
+ }
+
+ if (map->device_map.memdev.valid) {
+ resource_size_t addr;
+ resource_size_t length;
+
+ addr = phys_addr + map->device_map.memdev.offset;
+ length = map->device_map.memdev.size;
+ regs->memdev = devm_cxl_iomap_block(dev, addr, length);
+ if (!regs->memdev)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cxl_map_device_regs);
+
+/**
+ * __cxl_driver_register - register a driver for the cxl bus
+ * @cxl_drv: cxl driver structure to attach
+ * @owner: owning module/driver
+ * @modname: KBUILD_MODNAME for parent driver
+ */
+int __cxl_driver_register(struct cxl_driver *cxl_drv, struct module *owner,
+ const char *modname)
+{
+ if (!cxl_drv->probe) {
+ pr_debug("%s ->probe() must be specified\n", modname);
+ return -EINVAL;
+ }
+
+ if (!cxl_drv->name) {
+ pr_debug("%s ->name must be specified\n", modname);
+ return -EINVAL;
+ }
+
+ if (!cxl_drv->id) {
+ pr_debug("%s ->id must be specified\n", modname);
+ return -EINVAL;
+ }
+
+ cxl_drv->drv.bus = &cxl_bus_type;
+ cxl_drv->drv.owner = owner;
+ cxl_drv->drv.mod_name = modname;
+ cxl_drv->drv.name = cxl_drv->name;
+
+ return driver_register(&cxl_drv->drv);
+}
+EXPORT_SYMBOL_GPL(__cxl_driver_register);
+
+void cxl_driver_unregister(struct cxl_driver *cxl_drv)
+{
+ driver_unregister(&cxl_drv->drv);
+}
+EXPORT_SYMBOL_GPL(cxl_driver_unregister);
+
+static int cxl_device_id(struct device *dev)
+{
+ if (dev->type == &cxl_nvdimm_bridge_type)
+ return CXL_DEVICE_NVDIMM_BRIDGE;
+ if (dev->type == &cxl_nvdimm_type)
+ return CXL_DEVICE_NVDIMM;
+ return 0;
+}
+
+static int cxl_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ return add_uevent_var(env, "MODALIAS=" CXL_MODALIAS_FMT,
+ cxl_device_id(dev));
+}
+
+static int cxl_bus_match(struct device *dev, struct device_driver *drv)
+{
+ return cxl_device_id(dev) == to_cxl_drv(drv)->id;
+}
+
+static int cxl_bus_probe(struct device *dev)
+{
+ return to_cxl_drv(dev->driver)->probe(dev);
+}
+
+static int cxl_bus_remove(struct device *dev)
+{
+ struct cxl_driver *cxl_drv = to_cxl_drv(dev->driver);
+
+ if (cxl_drv->remove)
+ cxl_drv->remove(dev);
+ return 0;
+}
+
+struct bus_type cxl_bus_type = {
+ .name = "cxl",
+ .uevent = cxl_bus_uevent,
+ .match = cxl_bus_match,
+ .probe = cxl_bus_probe,
+ .remove = cxl_bus_remove,
+};
+EXPORT_SYMBOL_GPL(cxl_bus_type);
+
+static __init int cxl_core_init(void)
+{
+ return bus_register(&cxl_bus_type);
+}
+
+static void cxl_core_exit(void)
+{
+ bus_unregister(&cxl_bus_type);
+}
+
+module_init(cxl_core_init);
+module_exit(cxl_core_exit);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 6f14838c2d25..b6bda39a59e3 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -4,10 +4,51 @@
#ifndef __CXL_H__
#define __CXL_H__
+#include <linux/libnvdimm.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/io.h>
+/**
+ * DOC: cxl objects
+ *
+ * The CXL core objects like ports, decoders, and regions are shared
+ * between the subsystem drivers cxl_acpi, cxl_pci, and core drivers
+ * (port-driver, region-driver, nvdimm object-drivers... etc).
+ */
+
+/* CXL 2.0 8.2.5 CXL.cache and CXL.mem Registers*/
+#define CXL_CM_OFFSET 0x1000
+#define CXL_CM_CAP_HDR_OFFSET 0x0
+#define CXL_CM_CAP_HDR_ID_MASK GENMASK(15, 0)
+#define CM_CAP_HDR_CAP_ID 1
+#define CXL_CM_CAP_HDR_VERSION_MASK GENMASK(19, 16)
+#define CM_CAP_HDR_CAP_VERSION 1
+#define CXL_CM_CAP_HDR_CACHE_MEM_VERSION_MASK GENMASK(23, 20)
+#define CM_CAP_HDR_CACHE_MEM_VERSION 1
+#define CXL_CM_CAP_HDR_ARRAY_SIZE_MASK GENMASK(31, 24)
+#define CXL_CM_CAP_PTR_MASK GENMASK(31, 20)
+
+#define CXL_CM_CAP_CAP_ID_HDM 0x5
+#define CXL_CM_CAP_CAP_HDM_VERSION 1
+
+/* HDM decoders CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure */
+#define CXL_HDM_DECODER_CAP_OFFSET 0x0
+#define CXL_HDM_DECODER_COUNT_MASK GENMASK(3, 0)
+#define CXL_HDM_DECODER_TARGET_COUNT_MASK GENMASK(7, 4)
+#define CXL_HDM_DECODER0_BASE_LOW_OFFSET 0x10
+#define CXL_HDM_DECODER0_BASE_HIGH_OFFSET 0x14
+#define CXL_HDM_DECODER0_SIZE_LOW_OFFSET 0x18
+#define CXL_HDM_DECODER0_SIZE_HIGH_OFFSET 0x1c
+#define CXL_HDM_DECODER0_CTRL_OFFSET 0x20
+
+static inline int cxl_hdm_decoder_count(u32 cap_hdr)
+{
+ int val = FIELD_GET(CXL_HDM_DECODER_COUNT_MASK, cap_hdr);
+
+ return val ? val * 2 : 1;
+}
+
/* CXL 2.0 8.2.8.1 Device Capabilities Array Register */
#define CXLDEV_CAP_ARRAY_OFFSET 0x0
#define CXLDEV_CAP_ARRAY_CAP_ID 0
@@ -34,62 +75,253 @@
#define CXLDEV_MBOX_BG_CMD_STATUS_OFFSET 0x18
#define CXLDEV_MBOX_PAYLOAD_OFFSET 0x20
-/* CXL 2.0 8.2.8.5.1.1 Memory Device Status Register */
-#define CXLMDEV_STATUS_OFFSET 0x0
-#define CXLMDEV_DEV_FATAL BIT(0)
-#define CXLMDEV_FW_HALT BIT(1)
-#define CXLMDEV_STATUS_MEDIA_STATUS_MASK GENMASK(3, 2)
-#define CXLMDEV_MS_NOT_READY 0
-#define CXLMDEV_MS_READY 1
-#define CXLMDEV_MS_ERROR 2
-#define CXLMDEV_MS_DISABLED 3
-#define CXLMDEV_READY(status) \
- (FIELD_GET(CXLMDEV_STATUS_MEDIA_STATUS_MASK, status) == \
- CXLMDEV_MS_READY)
-#define CXLMDEV_MBOX_IF_READY BIT(4)
-#define CXLMDEV_RESET_NEEDED_MASK GENMASK(7, 5)
-#define CXLMDEV_RESET_NEEDED_NOT 0
-#define CXLMDEV_RESET_NEEDED_COLD 1
-#define CXLMDEV_RESET_NEEDED_WARM 2
-#define CXLMDEV_RESET_NEEDED_HOT 3
-#define CXLMDEV_RESET_NEEDED_CXL 4
-#define CXLMDEV_RESET_NEEDED(status) \
- (FIELD_GET(CXLMDEV_RESET_NEEDED_MASK, status) != \
- CXLMDEV_RESET_NEEDED_NOT)
-
-struct cxl_memdev;
+#define CXL_COMPONENT_REGS() \
+ void __iomem *hdm_decoder
+
+#define CXL_DEVICE_REGS() \
+ void __iomem *status; \
+ void __iomem *mbox; \
+ void __iomem *memdev
+
+/* See note for 'struct cxl_regs' for the rationale of this organization */
+/*
+ * CXL_COMPONENT_REGS - Common set of CXL Component register block base pointers
+ * @hdm_decoder: CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure
+ */
+struct cxl_component_regs {
+ CXL_COMPONENT_REGS();
+};
+
+/* See note for 'struct cxl_regs' for the rationale of this organization */
+/*
+ * CXL_DEVICE_REGS - Common set of CXL Device register block base pointers
+ * @status: CXL 2.0 8.2.8.3 Device Status Registers
+ * @mbox: CXL 2.0 8.2.8.4 Mailbox Registers
+ * @memdev: CXL 2.0 8.2.8.5 Memory Device Registers
+ */
+struct cxl_device_regs {
+ CXL_DEVICE_REGS();
+};
+
+/*
+ * Note, the anonymous union organization allows for per
+ * register-block-type helper routines, without requiring block-type
+ * agnostic code to include the prefix.
+ */
+struct cxl_regs {
+ union {
+ struct {
+ CXL_COMPONENT_REGS();
+ };
+ struct cxl_component_regs component;
+ };
+ union {
+ struct {
+ CXL_DEVICE_REGS();
+ };
+ struct cxl_device_regs device_regs;
+ };
+};
+
+struct cxl_reg_map {
+ bool valid;
+ unsigned long offset;
+ unsigned long size;
+};
+
+struct cxl_component_reg_map {
+ struct cxl_reg_map hdm_decoder;
+};
+
+struct cxl_device_reg_map {
+ struct cxl_reg_map status;
+ struct cxl_reg_map mbox;
+ struct cxl_reg_map memdev;
+};
+
+struct cxl_register_map {
+ struct list_head list;
+ u64 block_offset;
+ u8 reg_type;
+ u8 barno;
+ union {
+ struct cxl_component_reg_map component_map;
+ struct cxl_device_reg_map device_map;
+ };
+};
+
+void cxl_probe_component_regs(struct device *dev, void __iomem *base,
+ struct cxl_component_reg_map *map);
+void cxl_probe_device_regs(struct device *dev, void __iomem *base,
+ struct cxl_device_reg_map *map);
+int cxl_map_component_regs(struct pci_dev *pdev,
+ struct cxl_component_regs *regs,
+ struct cxl_register_map *map);
+int cxl_map_device_regs(struct pci_dev *pdev,
+ struct cxl_device_regs *regs,
+ struct cxl_register_map *map);
+
+#define CXL_RESOURCE_NONE ((resource_size_t) -1)
+#define CXL_TARGET_STRLEN 20
+
+/*
+ * cxl_decoder flags that define the type of memory / devices this
+ * decoder supports as well as configuration lock status See "CXL 2.0
+ * 8.2.5.12.7 CXL HDM Decoder 0 Control Register" for details.
+ */
+#define CXL_DECODER_F_RAM BIT(0)
+#define CXL_DECODER_F_PMEM BIT(1)
+#define CXL_DECODER_F_TYPE2 BIT(2)
+#define CXL_DECODER_F_TYPE3 BIT(3)
+#define CXL_DECODER_F_LOCK BIT(4)
+#define CXL_DECODER_F_MASK GENMASK(4, 0)
+
+enum cxl_decoder_type {
+ CXL_DECODER_ACCELERATOR = 2,
+ CXL_DECODER_EXPANDER = 3,
+};
+
/**
- * struct cxl_mem - A CXL memory device
- * @pdev: The PCI device associated with this CXL device.
- * @regs: IO mappings to the device's MMIO
- * @status_regs: CXL 2.0 8.2.8.3 Device Status Registers
- * @mbox_regs: CXL 2.0 8.2.8.4 Mailbox Registers
- * @memdev_regs: CXL 2.0 8.2.8.5 Memory Device Registers
- * @payload_size: Size of space for payload
- * (CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register)
- * @mbox_mutex: Mutex to synchronize mailbox access.
- * @firmware_version: Firmware version for the memory device.
- * @enabled_commands: Hardware commands found enabled in CEL.
- * @pmem_range: Persistent memory capacity information.
- * @ram_range: Volatile memory capacity information.
+ * struct cxl_decoder - CXL address range decode configuration
+ * @dev: this decoder's device
+ * @id: kernel device name id
+ * @range: address range considered by this decoder
+ * @interleave_ways: number of cxl_dports in this decode
+ * @interleave_granularity: data stride per dport
+ * @target_type: accelerator vs expander (type2 vs type3) selector
+ * @flags: memory type capabilities and locking
+ * @target: active ordered target list in current decoder configuration
*/
-struct cxl_mem {
- struct pci_dev *pdev;
- void __iomem *regs;
- struct cxl_memdev *cxlmd;
+struct cxl_decoder {
+ struct device dev;
+ int id;
+ struct range range;
+ int interleave_ways;
+ int interleave_granularity;
+ enum cxl_decoder_type target_type;
+ unsigned long flags;
+ struct cxl_dport *target[];
+};
- void __iomem *status_regs;
- void __iomem *mbox_regs;
- void __iomem *memdev_regs;
- size_t payload_size;
- struct mutex mbox_mutex; /* Protects device mailbox and firmware */
- char firmware_version[0x10];
- unsigned long *enabled_cmds;
+enum cxl_nvdimm_brige_state {
+ CXL_NVB_NEW,
+ CXL_NVB_DEAD,
+ CXL_NVB_ONLINE,
+ CXL_NVB_OFFLINE,
+};
- struct range pmem_range;
- struct range ram_range;
+struct cxl_nvdimm_bridge {
+ struct device dev;
+ struct cxl_port *port;
+ struct nvdimm_bus *nvdimm_bus;
+ struct nvdimm_bus_descriptor nd_desc;
+ struct work_struct state_work;
+ enum cxl_nvdimm_brige_state state;
};
+struct cxl_nvdimm {
+ struct device dev;
+ struct cxl_memdev *cxlmd;
+ struct nvdimm *nvdimm;
+};
+
+/**
+ * struct cxl_port - logical collection of upstream port devices and
+ * downstream port devices to construct a CXL memory
+ * decode hierarchy.
+ * @dev: this port's device
+ * @uport: PCI or platform device implementing the upstream port capability
+ * @id: id for port device-name
+ * @dports: cxl_dport instances referenced by decoders
+ * @decoder_ida: allocator for decoder ids
+ * @component_reg_phys: component register capability base address (optional)
+ */
+struct cxl_port {
+ struct device dev;
+ struct device *uport;
+ int id;
+ struct list_head dports;
+ struct ida decoder_ida;
+ resource_size_t component_reg_phys;
+};
+
+/**
+ * struct cxl_dport - CXL downstream port
+ * @dport: PCI bridge or firmware device representing the downstream link
+ * @port_id: unique hardware identifier for dport in decoder target list
+ * @component_reg_phys: downstream port component registers
+ * @port: reference to cxl_port that contains this downstream port
+ * @list: node for a cxl_port's list of cxl_dport instances
+ */
+struct cxl_dport {
+ struct device *dport;
+ int port_id;
+ resource_size_t component_reg_phys;
+ struct cxl_port *port;
+ struct list_head list;
+};
+
+struct cxl_port *to_cxl_port(struct device *dev);
+struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
+ resource_size_t component_reg_phys,
+ struct cxl_port *parent_port);
+
+int cxl_add_dport(struct cxl_port *port, struct device *dport, int port_id,
+ resource_size_t component_reg_phys);
+
+struct cxl_decoder *to_cxl_decoder(struct device *dev);
+bool is_root_decoder(struct device *dev);
+struct cxl_decoder *
+devm_cxl_add_decoder(struct device *host, struct cxl_port *port, int nr_targets,
+ resource_size_t base, resource_size_t len,
+ int interleave_ways, int interleave_granularity,
+ enum cxl_decoder_type type, unsigned long flags);
+
+/*
+ * Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability Structure)
+ * single ported host-bridges need not publish a decoder capability when a
+ * passthrough decode can be assumed, i.e. all transactions that the uport sees
+ * are claimed and passed to the single dport. Default the range a 0-base
+ * 0-length until the first CXL region is activated.
+ */
+static inline struct cxl_decoder *
+devm_cxl_add_passthrough_decoder(struct device *host, struct cxl_port *port)
+{
+ return devm_cxl_add_decoder(host, port, 1, 0, 0, 1, PAGE_SIZE,
+ CXL_DECODER_EXPANDER, 0);
+}
+
extern struct bus_type cxl_bus_type;
+
+struct cxl_driver {
+ const char *name;
+ int (*probe)(struct device *dev);
+ void (*remove)(struct device *dev);
+ struct device_driver drv;
+ int id;
+};
+
+static inline struct cxl_driver *to_cxl_drv(struct device_driver *drv)
+{
+ return container_of(drv, struct cxl_driver, drv);
+}
+
+int __cxl_driver_register(struct cxl_driver *cxl_drv, struct module *owner,
+ const char *modname);
+#define cxl_driver_register(x) __cxl_driver_register(x, THIS_MODULE, KBUILD_MODNAME)
+void cxl_driver_unregister(struct cxl_driver *cxl_drv);
+
+#define CXL_DEVICE_NVDIMM_BRIDGE 1
+#define CXL_DEVICE_NVDIMM 2
+
+#define MODULE_ALIAS_CXL(type) MODULE_ALIAS("cxl:t" __stringify(type) "*")
+#define CXL_MODALIAS_FMT "cxl:t%d"
+
+struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev);
+struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
+ struct cxl_port *port);
+struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev);
+bool is_cxl_nvdimm(struct device *dev);
+int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd);
#endif /* __CXL_H__ */
diff --git a/drivers/cxl/mem.h b/drivers/cxl/mem.h
new file mode 100644
index 000000000000..8f02d02b26b4
--- /dev/null
+++ b/drivers/cxl/mem.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(c) 2020-2021 Intel Corporation. */
+#ifndef __CXL_MEM_H__
+#define __CXL_MEM_H__
+#include <linux/cdev.h>
+#include "cxl.h"
+
+/* CXL 2.0 8.2.8.5.1.1 Memory Device Status Register */
+#define CXLMDEV_STATUS_OFFSET 0x0
+#define CXLMDEV_DEV_FATAL BIT(0)
+#define CXLMDEV_FW_HALT BIT(1)
+#define CXLMDEV_STATUS_MEDIA_STATUS_MASK GENMASK(3, 2)
+#define CXLMDEV_MS_NOT_READY 0
+#define CXLMDEV_MS_READY 1
+#define CXLMDEV_MS_ERROR 2
+#define CXLMDEV_MS_DISABLED 3
+#define CXLMDEV_READY(status) \
+ (FIELD_GET(CXLMDEV_STATUS_MEDIA_STATUS_MASK, status) == \
+ CXLMDEV_MS_READY)
+#define CXLMDEV_MBOX_IF_READY BIT(4)
+#define CXLMDEV_RESET_NEEDED_MASK GENMASK(7, 5)
+#define CXLMDEV_RESET_NEEDED_NOT 0
+#define CXLMDEV_RESET_NEEDED_COLD 1
+#define CXLMDEV_RESET_NEEDED_WARM 2
+#define CXLMDEV_RESET_NEEDED_HOT 3
+#define CXLMDEV_RESET_NEEDED_CXL 4
+#define CXLMDEV_RESET_NEEDED(status) \
+ (FIELD_GET(CXLMDEV_RESET_NEEDED_MASK, status) != \
+ CXLMDEV_RESET_NEEDED_NOT)
+
+/*
+ * An entire PCI topology full of devices should be enough for any
+ * config
+ */
+#define CXL_MEM_MAX_DEVS 65536
+
+/**
+ * struct cxl_memdev - CXL bus object representing a Type-3 Memory Device
+ * @dev: driver core device object
+ * @cdev: char dev core object for ioctl operations
+ * @cxlm: pointer to the parent device driver data
+ * @id: id number of this memdev instance.
+ */
+struct cxl_memdev {
+ struct device dev;
+ struct cdev cdev;
+ struct cxl_mem *cxlm;
+ int id;
+};
+
+/**
+ * struct cxl_mem - A CXL memory device
+ * @pdev: The PCI device associated with this CXL device.
+ * @cxlmd: Logical memory device chardev / interface
+ * @regs: Parsed register blocks
+ * @payload_size: Size of space for payload
+ * (CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register)
+ * @lsa_size: Size of Label Storage Area
+ * (CXL 2.0 8.2.9.5.1.1 Identify Memory Device)
+ * @mbox_mutex: Mutex to synchronize mailbox access.
+ * @firmware_version: Firmware version for the memory device.
+ * @enabled_cmds: Hardware commands found enabled in CEL.
+ * @pmem_range: Persistent memory capacity information.
+ * @ram_range: Volatile memory capacity information.
+ */
+struct cxl_mem {
+ struct pci_dev *pdev;
+ struct cxl_memdev *cxlmd;
+
+ struct cxl_regs regs;
+
+ size_t payload_size;
+ size_t lsa_size;
+ struct mutex mbox_mutex; /* Protects device mailbox and firmware */
+ char firmware_version[0x10];
+ unsigned long *enabled_cmds;
+
+ struct range pmem_range;
+ struct range ram_range;
+};
+#endif /* __CXL_MEM_H__ */
diff --git a/drivers/cxl/mem.c b/drivers/cxl/pci.c
index 2acc6173da36..4cf351a3cf99 100644
--- a/drivers/cxl/mem.c
+++ b/drivers/cxl/pci.c
@@ -6,6 +6,7 @@
#include <linux/module.h>
#include <linux/sizes.h>
#include <linux/mutex.h>
+#include <linux/list.h>
#include <linux/cdev.h>
#include <linux/idr.h>
#include <linux/pci.h>
@@ -13,12 +14,14 @@
#include <linux/io-64-nonatomic-lo-hi.h>
#include "pci.h"
#include "cxl.h"
+#include "mem.h"
/**
- * DOC: cxl mem
+ * DOC: cxl pci
*
- * This implements a CXL memory device ("type-3") as it is defined by the
- * Compute Express Link specification.
+ * This implements the PCI exclusive functionality for a CXL device as it is
+ * defined by the Compute Express Link specification. CXL devices may surface
+ * certain functionality even if it isn't CXL enabled.
*
* The driver has several responsibilities, mainly:
* - Create the memX device and register on the CXL bus.
@@ -26,18 +29,10 @@
* - Probe the device attributes to establish sysfs interface.
* - Provide an IOCTL interface to userspace to communicate with the device for
* things like firmware update.
- * - Support management of interleave sets.
- * - Handle and manage error conditions.
*/
-/*
- * An entire PCI topology full of devices should be enough for any
- * config
- */
-#define CXL_MEM_MAX_DEVS 65536
-
#define cxl_doorbell_busy(cxlm) \
- (readl((cxlm)->mbox_regs + CXLDEV_MBOX_CTRL_OFFSET) & \
+ (readl((cxlm)->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET) & \
CXLDEV_MBOX_CTRL_DOORBELL)
/* CXL 2.0 - 8.2.8.4 */
@@ -56,7 +51,14 @@ enum opcode {
CXL_MBOX_OP_GET_LSA = 0x4102,
CXL_MBOX_OP_SET_LSA = 0x4103,
CXL_MBOX_OP_GET_HEALTH_INFO = 0x4200,
+ CXL_MBOX_OP_GET_ALERT_CONFIG = 0x4201,
+ CXL_MBOX_OP_SET_ALERT_CONFIG = 0x4202,
+ CXL_MBOX_OP_GET_SHUTDOWN_STATE = 0x4203,
CXL_MBOX_OP_SET_SHUTDOWN_STATE = 0x4204,
+ CXL_MBOX_OP_GET_POISON = 0x4300,
+ CXL_MBOX_OP_INJECT_POISON = 0x4301,
+ CXL_MBOX_OP_CLEAR_POISON = 0x4302,
+ CXL_MBOX_OP_GET_SCAN_MEDIA_CAPS = 0x4303,
CXL_MBOX_OP_SCAN_MEDIA = 0x4304,
CXL_MBOX_OP_GET_SCAN_MEDIA = 0x4305,
CXL_MBOX_OP_MAX = 0x10000
@@ -92,20 +94,6 @@ struct mbox_cmd {
#define CXL_MBOX_SUCCESS 0
};
-/**
- * struct cxl_memdev - CXL bus object representing a Type-3 Memory Device
- * @dev: driver core device object
- * @cdev: char dev core object for ioctl operations
- * @cxlm: pointer to the parent device driver data
- * @id: id number of this memdev instance.
- */
-struct cxl_memdev {
- struct device dev;
- struct cdev cdev;
- struct cxl_mem *cxlm;
- int id;
-};
-
static int cxl_mem_major;
static DEFINE_IDA(cxl_memdev_ida);
static DECLARE_RWSEM(cxl_memdev_rwsem);
@@ -178,6 +166,18 @@ static struct cxl_mem_command mem_commands[CXL_MEM_COMMAND_ID_MAX] = {
CXL_CMD(GET_LSA, 0x8, ~0, 0),
CXL_CMD(GET_HEALTH_INFO, 0, 0x12, 0),
CXL_CMD(GET_LOG, 0x18, ~0, CXL_CMD_FLAG_FORCE_ENABLE),
+ CXL_CMD(SET_PARTITION_INFO, 0x0a, 0, 0),
+ CXL_CMD(SET_LSA, ~0, 0, 0),
+ CXL_CMD(GET_ALERT_CONFIG, 0, 0x10, 0),
+ CXL_CMD(SET_ALERT_CONFIG, 0xc, 0, 0),
+ CXL_CMD(GET_SHUTDOWN_STATE, 0, 0x1, 0),
+ CXL_CMD(SET_SHUTDOWN_STATE, 0x1, 0, 0),
+ CXL_CMD(GET_POISON, 0x10, ~0, 0),
+ CXL_CMD(INJECT_POISON, 0x8, 0, 0),
+ CXL_CMD(CLEAR_POISON, 0x48, 0, 0),
+ CXL_CMD(GET_SCAN_MEDIA_CAPS, 0x10, 0x4, 0),
+ CXL_CMD(SCAN_MEDIA, 0x11, 0, 0),
+ CXL_CMD(GET_SCAN_MEDIA, 0, ~0, 0),
};
/*
@@ -292,7 +292,7 @@ static void cxl_mem_mbox_timeout(struct cxl_mem *cxlm,
static int __cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm,
struct mbox_cmd *mbox_cmd)
{
- void __iomem *payload = cxlm->mbox_regs + CXLDEV_MBOX_PAYLOAD_OFFSET;
+ void __iomem *payload = cxlm->regs.mbox + CXLDEV_MBOX_PAYLOAD_OFFSET;
u64 cmd_reg, status_reg;
size_t out_len;
int rc;
@@ -335,12 +335,12 @@ static int __cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm,
}
/* #2, #3 */
- writeq(cmd_reg, cxlm->mbox_regs + CXLDEV_MBOX_CMD_OFFSET);
+ writeq(cmd_reg, cxlm->regs.mbox + CXLDEV_MBOX_CMD_OFFSET);
/* #4 */
dev_dbg(&cxlm->pdev->dev, "Sending command\n");
writel(CXLDEV_MBOX_CTRL_DOORBELL,
- cxlm->mbox_regs + CXLDEV_MBOX_CTRL_OFFSET);
+ cxlm->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET);
/* #5 */
rc = cxl_mem_wait_for_doorbell(cxlm);
@@ -350,7 +350,7 @@ static int __cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm,
}
/* #6 */
- status_reg = readq(cxlm->mbox_regs + CXLDEV_MBOX_STATUS_OFFSET);
+ status_reg = readq(cxlm->regs.mbox + CXLDEV_MBOX_STATUS_OFFSET);
mbox_cmd->return_code =
FIELD_GET(CXLDEV_MBOX_STATUS_RET_CODE_MASK, status_reg);
@@ -360,7 +360,7 @@ static int __cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm,
}
/* #7 */
- cmd_reg = readq(cxlm->mbox_regs + CXLDEV_MBOX_CMD_OFFSET);
+ cmd_reg = readq(cxlm->regs.mbox + CXLDEV_MBOX_CMD_OFFSET);
out_len = FIELD_GET(CXLDEV_MBOX_CMD_PAYLOAD_LENGTH_MASK, cmd_reg);
/* #8 */
@@ -421,7 +421,7 @@ static int cxl_mem_mbox_get(struct cxl_mem *cxlm)
goto out;
}
- md_status = readq(cxlm->memdev_regs + CXLMDEV_STATUS_OFFSET);
+ md_status = readq(cxlm->regs.memdev + CXLMDEV_STATUS_OFFSET);
if (!(md_status & CXLMDEV_MBOX_IF_READY && CXLMDEV_READY(md_status))) {
dev_err(dev, "mbox: reported doorbell ready, but not mbox ready\n");
rc = -EBUSY;
@@ -890,75 +890,9 @@ static int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode,
return 0;
}
-/**
- * cxl_mem_setup_regs() - Setup necessary MMIO.
- * @cxlm: The CXL memory device to communicate with.
- *
- * Return: 0 if all necessary registers mapped.
- *
- * A memory device is required by spec to implement a certain set of MMIO
- * regions. The purpose of this function is to enumerate and map those
- * registers.
- */
-static int cxl_mem_setup_regs(struct cxl_mem *cxlm)
-{
- struct device *dev = &cxlm->pdev->dev;
- int cap, cap_count;
- u64 cap_array;
-
- cap_array = readq(cxlm->regs + CXLDEV_CAP_ARRAY_OFFSET);
- if (FIELD_GET(CXLDEV_CAP_ARRAY_ID_MASK, cap_array) !=
- CXLDEV_CAP_ARRAY_CAP_ID)
- return -ENODEV;
-
- cap_count = FIELD_GET(CXLDEV_CAP_ARRAY_COUNT_MASK, cap_array);
-
- for (cap = 1; cap <= cap_count; cap++) {
- void __iomem *register_block;
- u32 offset;
- u16 cap_id;
-
- cap_id = FIELD_GET(CXLDEV_CAP_HDR_CAP_ID_MASK,
- readl(cxlm->regs + cap * 0x10));
- offset = readl(cxlm->regs + cap * 0x10 + 0x4);
- register_block = cxlm->regs + offset;
-
- switch (cap_id) {
- case CXLDEV_CAP_CAP_ID_DEVICE_STATUS:
- dev_dbg(dev, "found Status capability (0x%x)\n", offset);
- cxlm->status_regs = register_block;
- break;
- case CXLDEV_CAP_CAP_ID_PRIMARY_MAILBOX:
- dev_dbg(dev, "found Mailbox capability (0x%x)\n", offset);
- cxlm->mbox_regs = register_block;
- break;
- case CXLDEV_CAP_CAP_ID_SECONDARY_MAILBOX:
- dev_dbg(dev, "found Secondary Mailbox capability (0x%x)\n", offset);
- break;
- case CXLDEV_CAP_CAP_ID_MEMDEV:
- dev_dbg(dev, "found Memory Device capability (0x%x)\n", offset);
- cxlm->memdev_regs = register_block;
- break;
- default:
- dev_dbg(dev, "Unknown cap ID: %d (0x%x)\n", cap_id, offset);
- break;
- }
- }
-
- if (!cxlm->status_regs || !cxlm->mbox_regs || !cxlm->memdev_regs) {
- dev_err(dev, "registers not found: %s%s%s\n",
- !cxlm->status_regs ? "status " : "",
- !cxlm->mbox_regs ? "mbox " : "",
- !cxlm->memdev_regs ? "memdev" : "");
- return -ENXIO;
- }
-
- return 0;
-}
-
static int cxl_mem_setup_mailbox(struct cxl_mem *cxlm)
{
- const int cap = readl(cxlm->mbox_regs + CXLDEV_MBOX_CAPS_OFFSET);
+ const int cap = readl(cxlm->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET);
cxlm->payload_size =
1 << FIELD_GET(CXLDEV_MBOX_CAP_PAYLOAD_SIZE_MASK, cap);
@@ -983,55 +917,62 @@ static int cxl_mem_setup_mailbox(struct cxl_mem *cxlm)
return 0;
}
-static struct cxl_mem *cxl_mem_create(struct pci_dev *pdev, u32 reg_lo,
- u32 reg_hi)
+static struct cxl_mem *cxl_mem_create(struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;
struct cxl_mem *cxlm;
- void __iomem *regs;
- u64 offset;
- u8 bar;
- int rc;
- cxlm = devm_kzalloc(&pdev->dev, sizeof(*cxlm), GFP_KERNEL);
+ cxlm = devm_kzalloc(dev, sizeof(*cxlm), GFP_KERNEL);
if (!cxlm) {
dev_err(dev, "No memory available\n");
- return NULL;
- }
-
- offset = ((u64)reg_hi << 32) | (reg_lo & CXL_REGLOC_ADDR_MASK);
- bar = FIELD_GET(CXL_REGLOC_BIR_MASK, reg_lo);
-
- /* Basic sanity check that BAR is big enough */
- if (pci_resource_len(pdev, bar) < offset) {
- dev_err(dev, "BAR%d: %pr: too small (offset: %#llx)\n", bar,
- &pdev->resource[bar], (unsigned long long)offset);
- return NULL;
- }
-
- rc = pcim_iomap_regions(pdev, BIT(bar), pci_name(pdev));
- if (rc) {
- dev_err(dev, "failed to map registers\n");
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
- regs = pcim_iomap_table(pdev)[bar];
mutex_init(&cxlm->mbox_mutex);
cxlm->pdev = pdev;
- cxlm->regs = regs + offset;
cxlm->enabled_cmds =
devm_kmalloc_array(dev, BITS_TO_LONGS(cxl_cmd_count),
sizeof(unsigned long),
GFP_KERNEL | __GFP_ZERO);
if (!cxlm->enabled_cmds) {
dev_err(dev, "No memory available for bitmap\n");
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
- dev_dbg(dev, "Mapped CXL Memory Device resource\n");
return cxlm;
}
+static void __iomem *cxl_mem_map_regblock(struct cxl_mem *cxlm,
+ u8 bar, u64 offset)
+{
+ struct pci_dev *pdev = cxlm->pdev;
+ struct device *dev = &pdev->dev;
+ void __iomem *addr;
+
+ /* Basic sanity check that BAR is big enough */
+ if (pci_resource_len(pdev, bar) < offset) {
+ dev_err(dev, "BAR%d: %pr: too small (offset: %#llx)\n", bar,
+ &pdev->resource[bar], (unsigned long long)offset);
+ return IOMEM_ERR_PTR(-ENXIO);
+ }
+
+ addr = pci_iomap(pdev, bar, 0);
+ if (!addr) {
+ dev_err(dev, "failed to map registers\n");
+ return addr;
+ }
+
+ dev_dbg(dev, "Mapped CXL Memory Device resource bar %u @ %#llx\n",
+ bar, offset);
+
+ return addr;
+}
+
+static void cxl_mem_unmap_regblock(struct cxl_mem *cxlm, void __iomem *base)
+{
+ pci_iounmap(cxlm->pdev, base);
+}
+
static int cxl_mem_dvsec(struct pci_dev *pdev, int dvsec)
{
int pos;
@@ -1055,6 +996,171 @@ static int cxl_mem_dvsec(struct pci_dev *pdev, int dvsec)
return 0;
}
+static int cxl_probe_regs(struct cxl_mem *cxlm, void __iomem *base,
+ struct cxl_register_map *map)
+{
+ struct pci_dev *pdev = cxlm->pdev;
+ struct device *dev = &pdev->dev;
+ struct cxl_component_reg_map *comp_map;
+ struct cxl_device_reg_map *dev_map;
+
+ switch (map->reg_type) {
+ case CXL_REGLOC_RBI_COMPONENT:
+ comp_map = &map->component_map;
+ cxl_probe_component_regs(dev, base, comp_map);
+ if (!comp_map->hdm_decoder.valid) {
+ dev_err(dev, "HDM decoder registers not found\n");
+ return -ENXIO;
+ }
+
+ dev_dbg(dev, "Set up component registers\n");
+ break;
+ case CXL_REGLOC_RBI_MEMDEV:
+ dev_map = &map->device_map;
+ cxl_probe_device_regs(dev, base, dev_map);
+ if (!dev_map->status.valid || !dev_map->mbox.valid ||
+ !dev_map->memdev.valid) {
+ dev_err(dev, "registers not found: %s%s%s\n",
+ !dev_map->status.valid ? "status " : "",
+ !dev_map->mbox.valid ? "status " : "",
+ !dev_map->memdev.valid ? "status " : "");
+ return -ENXIO;
+ }
+
+ dev_dbg(dev, "Probing device registers...\n");
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int cxl_map_regs(struct cxl_mem *cxlm, struct cxl_register_map *map)
+{
+ struct pci_dev *pdev = cxlm->pdev;
+ struct device *dev = &pdev->dev;
+
+ switch (map->reg_type) {
+ case CXL_REGLOC_RBI_COMPONENT:
+ cxl_map_component_regs(pdev, &cxlm->regs.component, map);
+ dev_dbg(dev, "Mapping component registers...\n");
+ break;
+ case CXL_REGLOC_RBI_MEMDEV:
+ cxl_map_device_regs(pdev, &cxlm->regs.device_regs, map);
+ dev_dbg(dev, "Probing device registers...\n");
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void cxl_decode_register_block(u32 reg_lo, u32 reg_hi,
+ u8 *bar, u64 *offset, u8 *reg_type)
+{
+ *offset = ((u64)reg_hi << 32) | (reg_lo & CXL_REGLOC_ADDR_MASK);
+ *bar = FIELD_GET(CXL_REGLOC_BIR_MASK, reg_lo);
+ *reg_type = FIELD_GET(CXL_REGLOC_RBI_MASK, reg_lo);
+}
+
+/**
+ * cxl_mem_setup_regs() - Setup necessary MMIO.
+ * @cxlm: The CXL memory device to communicate with.
+ *
+ * Return: 0 if all necessary registers mapped.
+ *
+ * A memory device is required by spec to implement a certain set of MMIO
+ * regions. The purpose of this function is to enumerate and map those
+ * registers.
+ */
+static int cxl_mem_setup_regs(struct cxl_mem *cxlm)
+{
+ struct pci_dev *pdev = cxlm->pdev;
+ struct device *dev = &pdev->dev;
+ u32 regloc_size, regblocks;
+ void __iomem *base;
+ int regloc, i;
+ struct cxl_register_map *map, *n;
+ LIST_HEAD(register_maps);
+ int ret = 0;
+
+ regloc = cxl_mem_dvsec(pdev, PCI_DVSEC_ID_CXL_REGLOC_DVSEC_ID);
+ if (!regloc) {
+ dev_err(dev, "register location dvsec not found\n");
+ return -ENXIO;
+ }
+
+ if (pci_request_mem_regions(pdev, pci_name(pdev)))
+ return -ENODEV;
+
+ /* Get the size of the Register Locator DVSEC */
+ pci_read_config_dword(pdev, regloc + PCI_DVSEC_HEADER1, &regloc_size);
+ regloc_size = FIELD_GET(PCI_DVSEC_HEADER1_LENGTH_MASK, regloc_size);
+
+ regloc += PCI_DVSEC_ID_CXL_REGLOC_BLOCK1_OFFSET;
+ regblocks = (regloc_size - PCI_DVSEC_ID_CXL_REGLOC_BLOCK1_OFFSET) / 8;
+
+ for (i = 0; i < regblocks; i++, regloc += 8) {
+ u32 reg_lo, reg_hi;
+ u8 reg_type;
+ u64 offset;
+ u8 bar;
+
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (!map) {
+ ret = -ENOMEM;
+ goto free_maps;
+ }
+
+ list_add(&map->list, &register_maps);
+
+ pci_read_config_dword(pdev, regloc, &reg_lo);
+ pci_read_config_dword(pdev, regloc + 4, &reg_hi);
+
+ cxl_decode_register_block(reg_lo, reg_hi, &bar, &offset,
+ &reg_type);
+
+ dev_dbg(dev, "Found register block in bar %u @ 0x%llx of type %u\n",
+ bar, offset, reg_type);
+
+ base = cxl_mem_map_regblock(cxlm, bar, offset);
+ if (!base) {
+ ret = -ENOMEM;
+ goto free_maps;
+ }
+
+ map->barno = bar;
+ map->block_offset = offset;
+ map->reg_type = reg_type;
+
+ ret = cxl_probe_regs(cxlm, base + offset, map);
+
+ /* Always unmap the regblock regardless of probe success */
+ cxl_mem_unmap_regblock(cxlm, base);
+
+ if (ret)
+ goto free_maps;
+ }
+
+ pci_release_mem_regions(pdev);
+
+ list_for_each_entry(map, &register_maps, list) {
+ ret = cxl_map_regs(cxlm, map);
+ if (ret)
+ goto free_maps;
+ }
+
+free_maps:
+ list_for_each_entry_safe(map, n, &register_maps, list) {
+ list_del(&map->list);
+ kfree(map);
+ }
+
+ return ret;
+}
+
static struct cxl_memdev *to_cxl_memdev(struct device *dev)
{
return container_of(dev, struct cxl_memdev, dev);
@@ -1094,6 +1200,16 @@ static ssize_t payload_max_show(struct device *dev,
}
static DEVICE_ATTR_RO(payload_max);
+static ssize_t label_storage_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+ struct cxl_mem *cxlm = cxlmd->cxlm;
+
+ return sysfs_emit(buf, "%zu\n", cxlm->lsa_size);
+}
+static DEVICE_ATTR_RO(label_storage_size);
+
static ssize_t ram_size_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -1123,6 +1239,7 @@ static struct device_attribute dev_attr_pmem_size =
static struct attribute *cxl_memdev_attributes[] = {
&dev_attr_firmware_version.attr,
&dev_attr_payload_max.attr,
+ &dev_attr_label_storage_size.attr,
NULL,
};
@@ -1215,7 +1332,8 @@ err:
return ERR_PTR(rc);
}
-static int cxl_mem_add_memdev(struct cxl_mem *cxlm)
+static struct cxl_memdev *devm_cxl_add_memdev(struct device *host,
+ struct cxl_mem *cxlm)
{
struct cxl_memdev *cxlmd;
struct device *dev;
@@ -1224,7 +1342,7 @@ static int cxl_mem_add_memdev(struct cxl_mem *cxlm)
cxlmd = cxl_memdev_alloc(cxlm);
if (IS_ERR(cxlmd))
- return PTR_ERR(cxlmd);
+ return cxlmd;
dev = &cxlmd->dev;
rc = dev_set_name(dev, "mem%d", cxlmd->id);
@@ -1242,8 +1360,10 @@ static int cxl_mem_add_memdev(struct cxl_mem *cxlm)
if (rc)
goto err;
- return devm_add_action_or_reset(dev->parent, cxl_memdev_unregister,
- cxlmd);
+ rc = devm_add_action_or_reset(host, cxl_memdev_unregister, cxlmd);
+ if (rc)
+ return ERR_PTR(rc);
+ return cxlmd;
err:
/*
@@ -1252,7 +1372,7 @@ err:
*/
cxl_memdev_shutdown(cxlmd);
put_device(dev);
- return rc;
+ return ERR_PTR(rc);
}
static int cxl_xfer_log(struct cxl_mem *cxlm, uuid_t *uuid, u32 size, u8 *out)
@@ -1455,6 +1575,7 @@ static int cxl_mem_identify(struct cxl_mem *cxlm)
cxlm->pmem_range.end =
le64_to_cpu(id.persistent_capacity) * SZ_256M - 1;
+ cxlm->lsa_size = le32_to_cpu(id.lsa_size);
memcpy(cxlm->firmware_version, id.fw_revision, sizeof(id.fw_revision));
return 0;
@@ -1462,46 +1583,17 @@ static int cxl_mem_identify(struct cxl_mem *cxlm)
static int cxl_mem_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
- struct device *dev = &pdev->dev;
- struct cxl_mem *cxlm = NULL;
- u32 regloc_size, regblocks;
- int rc, regloc, i;
+ struct cxl_memdev *cxlmd;
+ struct cxl_mem *cxlm;
+ int rc;
rc = pcim_enable_device(pdev);
if (rc)
return rc;
- regloc = cxl_mem_dvsec(pdev, PCI_DVSEC_ID_CXL_REGLOC_OFFSET);
- if (!regloc) {
- dev_err(dev, "register location dvsec not found\n");
- return -ENXIO;
- }
-
- /* Get the size of the Register Locator DVSEC */
- pci_read_config_dword(pdev, regloc + PCI_DVSEC_HEADER1, &regloc_size);
- regloc_size = FIELD_GET(PCI_DVSEC_HEADER1_LENGTH_MASK, regloc_size);
-
- regloc += PCI_DVSEC_ID_CXL_REGLOC_BLOCK1_OFFSET;
- regblocks = (regloc_size - PCI_DVSEC_ID_CXL_REGLOC_BLOCK1_OFFSET) / 8;
-
- for (i = 0; i < regblocks; i++, regloc += 8) {
- u32 reg_lo, reg_hi;
- u8 reg_type;
-
- /* "register low and high" contain other bits */
- pci_read_config_dword(pdev, regloc, &reg_lo);
- pci_read_config_dword(pdev, regloc + 4, &reg_hi);
-
- reg_type = FIELD_GET(CXL_REGLOC_RBI_MASK, reg_lo);
-
- if (reg_type == CXL_REGLOC_RBI_MEMDEV) {
- cxlm = cxl_mem_create(pdev, reg_lo, reg_hi);
- break;
- }
- }
-
- if (!cxlm)
- return -ENODEV;
+ cxlm = cxl_mem_create(pdev);
+ if (IS_ERR(cxlm))
+ return PTR_ERR(cxlm);
rc = cxl_mem_setup_regs(cxlm);
if (rc)
@@ -1519,7 +1611,14 @@ static int cxl_mem_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (rc)
return rc;
- return cxl_mem_add_memdev(cxlm);
+ cxlmd = devm_cxl_add_memdev(&pdev->dev, cxlm);
+ if (IS_ERR(cxlmd))
+ return PTR_ERR(cxlmd);
+
+ if (range_len(&cxlm->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM))
+ rc = devm_cxl_add_nvdimm(&pdev->dev, cxlmd);
+
+ return rc;
}
static const struct pci_device_id cxl_mem_pci_tbl[] = {
@@ -1544,6 +1643,10 @@ static __init int cxl_mem_init(void)
dev_t devt;
int rc;
+ /* Double check the anonymous union trickery in struct cxl_regs */
+ BUILD_BUG_ON(offsetof(struct cxl_regs, memdev) !=
+ offsetof(struct cxl_regs, device_regs.memdev));
+
rc = alloc_chrdev_region(&devt, 0, CXL_MEM_MAX_DEVS, "cxl");
if (rc)
return rc;
diff --git a/drivers/cxl/pci.h b/drivers/cxl/pci.h
index af3ec078cf6c..dad7a831f65f 100644
--- a/drivers/cxl/pci.h
+++ b/drivers/cxl/pci.h
@@ -13,7 +13,7 @@
#define PCI_DVSEC_VENDOR_ID_CXL 0x1E98
#define PCI_DVSEC_ID_CXL 0x0
-#define PCI_DVSEC_ID_CXL_REGLOC_OFFSET 0x8
+#define PCI_DVSEC_ID_CXL_REGLOC_DVSEC_ID 0x8
#define PCI_DVSEC_ID_CXL_REGLOC_BLOCK1_OFFSET 0xC
/* BAR Indicator Register (BIR) */
diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c
new file mode 100644
index 000000000000..0088e41dd2f3
--- /dev/null
+++ b/drivers/cxl/pmem.c
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2021 Intel Corporation. All rights reserved. */
+#include <linux/libnvdimm.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/ndctl.h>
+#include <linux/async.h>
+#include <linux/slab.h>
+#include "mem.h"
+#include "cxl.h"
+
+/*
+ * Ordered workqueue for cxl nvdimm device arrival and departure
+ * to coordinate bus rescans when a bridge arrives and trigger remove
+ * operations when the bridge is removed.
+ */
+static struct workqueue_struct *cxl_pmem_wq;
+
+static void unregister_nvdimm(void *nvdimm)
+{
+ nvdimm_delete(nvdimm);
+}
+
+static int match_nvdimm_bridge(struct device *dev, const void *data)
+{
+ return strcmp(dev_name(dev), "nvdimm-bridge") == 0;
+}
+
+static struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(void)
+{
+ struct device *dev;
+
+ dev = bus_find_device(&cxl_bus_type, NULL, NULL, match_nvdimm_bridge);
+ if (!dev)
+ return NULL;
+ return to_cxl_nvdimm_bridge(dev);
+}
+
+static int cxl_nvdimm_probe(struct device *dev)
+{
+ struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev);
+ struct cxl_nvdimm_bridge *cxl_nvb;
+ unsigned long flags = 0;
+ struct nvdimm *nvdimm;
+ int rc = -ENXIO;
+
+ cxl_nvb = cxl_find_nvdimm_bridge();
+ if (!cxl_nvb)
+ return -ENXIO;
+
+ device_lock(&cxl_nvb->dev);
+ if (!cxl_nvb->nvdimm_bus)
+ goto out;
+
+ set_bit(NDD_LABELING, &flags);
+ nvdimm = nvdimm_create(cxl_nvb->nvdimm_bus, cxl_nvd, NULL, flags, 0, 0,
+ NULL);
+ if (!nvdimm)
+ goto out;
+
+ rc = devm_add_action_or_reset(dev, unregister_nvdimm, nvdimm);
+out:
+ device_unlock(&cxl_nvb->dev);
+ put_device(&cxl_nvb->dev);
+
+ return rc;
+}
+
+static struct cxl_driver cxl_nvdimm_driver = {
+ .name = "cxl_nvdimm",
+ .probe = cxl_nvdimm_probe,
+ .id = CXL_DEVICE_NVDIMM,
+};
+
+static int cxl_pmem_ctl(struct nvdimm_bus_descriptor *nd_desc,
+ struct nvdimm *nvdimm, unsigned int cmd, void *buf,
+ unsigned int buf_len, int *cmd_rc)
+{
+ return -ENOTTY;
+}
+
+static bool online_nvdimm_bus(struct cxl_nvdimm_bridge *cxl_nvb)
+{
+ if (cxl_nvb->nvdimm_bus)
+ return true;
+ cxl_nvb->nvdimm_bus =
+ nvdimm_bus_register(&cxl_nvb->dev, &cxl_nvb->nd_desc);
+ return cxl_nvb->nvdimm_bus != NULL;
+}
+
+static int cxl_nvdimm_release_driver(struct device *dev, void *data)
+{
+ if (!is_cxl_nvdimm(dev))
+ return 0;
+ device_release_driver(dev);
+ return 0;
+}
+
+static void offline_nvdimm_bus(struct nvdimm_bus *nvdimm_bus)
+{
+ if (!nvdimm_bus)
+ return;
+
+ /*
+ * Set the state of cxl_nvdimm devices to unbound / idle before
+ * nvdimm_bus_unregister() rips the nvdimm objects out from
+ * underneath them.
+ */
+ bus_for_each_dev(&cxl_bus_type, NULL, NULL, cxl_nvdimm_release_driver);
+ nvdimm_bus_unregister(nvdimm_bus);
+}
+
+static void cxl_nvb_update_state(struct work_struct *work)
+{
+ struct cxl_nvdimm_bridge *cxl_nvb =
+ container_of(work, typeof(*cxl_nvb), state_work);
+ struct nvdimm_bus *victim_bus = NULL;
+ bool release = false, rescan = false;
+
+ device_lock(&cxl_nvb->dev);
+ switch (cxl_nvb->state) {
+ case CXL_NVB_ONLINE:
+ if (!online_nvdimm_bus(cxl_nvb)) {
+ dev_err(&cxl_nvb->dev,
+ "failed to establish nvdimm bus\n");
+ release = true;
+ } else
+ rescan = true;
+ break;
+ case CXL_NVB_OFFLINE:
+ case CXL_NVB_DEAD:
+ victim_bus = cxl_nvb->nvdimm_bus;
+ cxl_nvb->nvdimm_bus = NULL;
+ break;
+ default:
+ break;
+ }
+ device_unlock(&cxl_nvb->dev);
+
+ if (release)
+ device_release_driver(&cxl_nvb->dev);
+ if (rescan) {
+ int rc = bus_rescan_devices(&cxl_bus_type);
+
+ dev_dbg(&cxl_nvb->dev, "rescan: %d\n", rc);
+ }
+ offline_nvdimm_bus(victim_bus);
+
+ put_device(&cxl_nvb->dev);
+}
+
+static void cxl_nvdimm_bridge_remove(struct device *dev)
+{
+ struct cxl_nvdimm_bridge *cxl_nvb = to_cxl_nvdimm_bridge(dev);
+
+ if (cxl_nvb->state == CXL_NVB_ONLINE)
+ cxl_nvb->state = CXL_NVB_OFFLINE;
+ if (queue_work(cxl_pmem_wq, &cxl_nvb->state_work))
+ get_device(&cxl_nvb->dev);
+}
+
+static int cxl_nvdimm_bridge_probe(struct device *dev)
+{
+ struct cxl_nvdimm_bridge *cxl_nvb = to_cxl_nvdimm_bridge(dev);
+
+ if (cxl_nvb->state == CXL_NVB_DEAD)
+ return -ENXIO;
+
+ if (cxl_nvb->state == CXL_NVB_NEW) {
+ cxl_nvb->nd_desc = (struct nvdimm_bus_descriptor) {
+ .provider_name = "CXL",
+ .module = THIS_MODULE,
+ .ndctl = cxl_pmem_ctl,
+ };
+
+ INIT_WORK(&cxl_nvb->state_work, cxl_nvb_update_state);
+ }
+
+ cxl_nvb->state = CXL_NVB_ONLINE;
+ if (queue_work(cxl_pmem_wq, &cxl_nvb->state_work))
+ get_device(&cxl_nvb->dev);
+
+ return 0;
+}
+
+static struct cxl_driver cxl_nvdimm_bridge_driver = {
+ .name = "cxl_nvdimm_bridge",
+ .probe = cxl_nvdimm_bridge_probe,
+ .remove = cxl_nvdimm_bridge_remove,
+ .id = CXL_DEVICE_NVDIMM_BRIDGE,
+};
+
+static __init int cxl_pmem_init(void)
+{
+ int rc;
+
+ cxl_pmem_wq = alloc_ordered_workqueue("cxl_pmem", 0);
+ if (!cxl_pmem_wq)
+ return -ENXIO;
+
+ rc = cxl_driver_register(&cxl_nvdimm_bridge_driver);
+ if (rc)
+ goto err_bridge;
+
+ rc = cxl_driver_register(&cxl_nvdimm_driver);
+ if (rc)
+ goto err_nvdimm;
+
+ return 0;
+
+err_nvdimm:
+ cxl_driver_unregister(&cxl_nvdimm_bridge_driver);
+err_bridge:
+ destroy_workqueue(cxl_pmem_wq);
+ return rc;
+}
+
+static __exit void cxl_pmem_exit(void)
+{
+ cxl_driver_unregister(&cxl_nvdimm_driver);
+ cxl_driver_unregister(&cxl_nvdimm_bridge_driver);
+ destroy_workqueue(cxl_pmem_wq);
+}
+
+MODULE_LICENSE("GPL v2");
+module_init(cxl_pmem_init);
+module_exit(cxl_pmem_exit);
+MODULE_IMPORT_NS(CXL);
+MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM_BRIDGE);
+MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM);
diff --git a/drivers/dax/device.c b/drivers/dax/device.c
index db92573c94e8..dd8222a42808 100644
--- a/drivers/dax/device.c
+++ b/drivers/dax/device.c
@@ -337,7 +337,7 @@ static unsigned long dax_get_unmapped_area(struct file *filp,
}
static const struct address_space_operations dev_dax_aops = {
- .set_page_dirty = noop_set_page_dirty,
+ .set_page_dirty = __set_page_dirty_no_writeback,
.invalidatepage = noop_invalidatepage,
};
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 20373a893b44..e87d01c0b76a 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -103,7 +103,6 @@ config ARM_IMX8M_DDRC_DEVFREQ
tristate "i.MX8M DDRC DEVFREQ Driver"
depends on (ARCH_MXC && HAVE_ARM_SMCCC) || \
(COMPILE_TEST && HAVE_ARM_SMCCC)
- select DEVFREQ_GOV_SIMPLE_ONDEMAND
select DEVFREQ_GOV_USERSPACE
help
This adds the DEVFREQ driver for the i.MX8M DDR Controller. It allows
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index fe08c46642f7..28f3e0ba6cdd 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -823,6 +823,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
if (devfreq->profile->timer < 0
|| devfreq->profile->timer >= DEVFREQ_TIMER_NUM) {
mutex_unlock(&devfreq->lock);
+ err = -EINVAL;
goto err_dev;
}
diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c
index b094132bd20b..fc09324a03e0 100644
--- a/drivers/devfreq/governor_passive.c
+++ b/drivers/devfreq/governor_passive.c
@@ -65,7 +65,7 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
dev_pm_opp_put(p_opp);
if (IS_ERR(opp))
- return PTR_ERR(opp);
+ goto no_required_opp;
*freq = dev_pm_opp_get_freq(opp);
dev_pm_opp_put(opp);
@@ -73,6 +73,7 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
return 0;
}
+no_required_opp:
/*
* Get the OPP table's index of decided frequency by governor
* of parent device.
diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c
index 0fd6c4851071..ab9db7adb3ad 100644
--- a/drivers/devfreq/governor_userspace.c
+++ b/drivers/devfreq/governor_userspace.c
@@ -31,8 +31,8 @@ static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
return 0;
}
-static ssize_t store_freq(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t set_freq_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct devfreq *devfreq = to_devfreq(dev);
struct userspace_data *data;
@@ -52,8 +52,8 @@ static ssize_t store_freq(struct device *dev, struct device_attribute *attr,
return err;
}
-static ssize_t show_freq(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t set_freq_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct devfreq *devfreq = to_devfreq(dev);
struct userspace_data *data;
@@ -70,7 +70,7 @@ static ssize_t show_freq(struct device *dev, struct device_attribute *attr,
return err;
}
-static DEVICE_ATTR(set_freq, 0644, show_freq, store_freq);
+static DEVICE_ATTR_RW(set_freq);
static struct attribute *dev_entries[] = {
&dev_attr_set_freq.attr,
NULL,
diff --git a/drivers/devfreq/imx-bus.c b/drivers/devfreq/imx-bus.c
index 3fc3fd77492d..f3f6e25053ed 100644
--- a/drivers/devfreq/imx-bus.c
+++ b/drivers/devfreq/imx-bus.c
@@ -45,18 +45,6 @@ static int imx_bus_get_cur_freq(struct device *dev, unsigned long *freq)
return 0;
}
-static int imx_bus_get_dev_status(struct device *dev,
- struct devfreq_dev_status *stat)
-{
- struct imx_bus *priv = dev_get_drvdata(dev);
-
- stat->busy_time = 0;
- stat->total_time = 0;
- stat->current_frequency = clk_get_rate(priv->clk);
-
- return 0;
-}
-
static void imx_bus_exit(struct device *dev)
{
struct imx_bus *priv = dev_get_drvdata(dev);
@@ -129,9 +117,7 @@ static int imx_bus_probe(struct platform_device *pdev)
return ret;
}
- priv->profile.polling_ms = 1000;
priv->profile.target = imx_bus_target;
- priv->profile.get_dev_status = imx_bus_get_dev_status;
priv->profile.exit = imx_bus_exit;
priv->profile.get_cur_freq = imx_bus_get_cur_freq;
priv->profile.initial_freq = clk_get_rate(priv->clk);
diff --git a/drivers/devfreq/tegra30-devfreq.c b/drivers/devfreq/tegra30-devfreq.c
index ce83f883ca65..10661eb2aed8 100644
--- a/drivers/devfreq/tegra30-devfreq.c
+++ b/drivers/devfreq/tegra30-devfreq.c
@@ -688,6 +688,7 @@ static struct devfreq_dev_profile tegra_devfreq_profile = {
.polling_ms = ACTMON_SAMPLING_PERIOD,
.target = tegra_devfreq_target,
.get_dev_status = tegra_devfreq_get_dev_status,
+ .is_cooling_device = true,
};
static int tegra_governor_get_target(struct devfreq *devfreq,
diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
index 20d9bddbb985..394e6e1e9686 100644
--- a/drivers/dma-buf/sync_file.c
+++ b/drivers/dma-buf/sync_file.c
@@ -211,8 +211,8 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
struct sync_file *b)
{
struct sync_file *sync_file;
- struct dma_fence **fences, **nfences, **a_fences, **b_fences;
- int i, i_a, i_b, num_fences, a_num_fences, b_num_fences;
+ struct dma_fence **fences = NULL, **nfences, **a_fences, **b_fences;
+ int i = 0, i_a, i_b, num_fences, a_num_fences, b_num_fences;
sync_file = sync_file_alloc();
if (!sync_file)
@@ -236,7 +236,7 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
* If a sync_file can only be created with sync_file_merge
* and sync_file_create, this is a reasonable assumption.
*/
- for (i = i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) {
+ for (i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) {
struct dma_fence *pt_a = a_fences[i_a];
struct dma_fence *pt_b = b_fences[i_b];
@@ -277,15 +277,16 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
fences = nfences;
}
- if (sync_file_set_fence(sync_file, fences, i) < 0) {
- kfree(fences);
+ if (sync_file_set_fence(sync_file, fences, i) < 0)
goto err;
- }
strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
return sync_file;
err:
+ while (i)
+ dma_fence_put(fences[--i]);
+ kfree(fences);
fput(sync_file->file);
return NULL;
diff --git a/drivers/dma/altera-msgdma.c b/drivers/dma/altera-msgdma.c
index 9a841ce5f0c5..0fe0676f8e1d 100644
--- a/drivers/dma/altera-msgdma.c
+++ b/drivers/dma/altera-msgdma.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/of_dma.h>
#include "dmaengine.h"
@@ -888,6 +889,13 @@ static int msgdma_probe(struct platform_device *pdev)
if (ret)
goto fail;
+ ret = of_dma_controller_register(pdev->dev.of_node,
+ of_dma_xlate_by_chan_id, dma_dev);
+ if (ret == -EINVAL)
+ dev_warn(&pdev->dev, "device was not probed from DT");
+ else if (ret && ret != -ENODEV)
+ goto fail;
+
dev_notice(&pdev->dev, "Altera mSGDMA driver probe success\n");
return 0;
@@ -908,6 +916,8 @@ static int msgdma_remove(struct platform_device *pdev)
{
struct msgdma_device *mdev = platform_get_drvdata(pdev);
+ if (pdev->dev.of_node)
+ of_dma_controller_free(pdev->dev.of_node);
dma_async_device_unregister(&mdev->dmadev);
msgdma_dev_remove(mdev);
@@ -916,9 +926,19 @@ static int msgdma_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id msgdma_match[] = {
+ { .compatible = "altr,socfpga-msgdma", },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, msgdma_match);
+#endif
+
static struct platform_driver msgdma_driver = {
.driver = {
.name = "altera-msgdma",
+ .of_match_table = of_match_ptr(msgdma_match),
},
.probe = msgdma_probe,
.remove = msgdma_remove,
diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c
index ed2ab46b15e7..045ead46ec8f 100644
--- a/drivers/dma/fsl-qdma.c
+++ b/drivers/dma/fsl-qdma.c
@@ -1235,7 +1235,11 @@ static int fsl_qdma_probe(struct platform_device *pdev)
fsl_qdma->dma_dev.device_synchronize = fsl_qdma_synchronize;
fsl_qdma->dma_dev.device_terminate_all = fsl_qdma_terminate_all;
- dma_set_mask(&pdev->dev, DMA_BIT_MASK(40));
+ ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(40));
+ if (ret) {
+ dev_err(&pdev->dev, "dma_set_mask failure.\n");
+ return ret;
+ }
platform_set_drvdata(pdev, fsl_qdma);
diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c
index 025d8ad5a63c..92caae55aece 100644
--- a/drivers/dma/hsu/hsu.c
+++ b/drivers/dma/hsu/hsu.c
@@ -201,6 +201,7 @@ EXPORT_SYMBOL_GPL(hsu_dma_get_status);
*/
int hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, u32 status)
{
+ struct dma_chan_percpu *stat;
struct hsu_dma_chan *hsuc;
struct hsu_dma_desc *desc;
unsigned long flags;
@@ -210,6 +211,7 @@ int hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, u32 status)
return 0;
hsuc = &chip->hsu->chan[nr];
+ stat = this_cpu_ptr(hsuc->vchan.chan.local);
spin_lock_irqsave(&hsuc->vchan.lock, flags);
desc = hsuc->desc;
@@ -221,6 +223,7 @@ int hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, u32 status)
} else {
vchan_cookie_complete(&desc->vdesc);
desc->status = DMA_COMPLETE;
+ stat->bytes_transferred += desc->length;
hsu_dma_start_transfer(hsuc);
}
}
diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c
index d4419bf1fede..e9def577c697 100644
--- a/drivers/dma/idxd/cdev.c
+++ b/drivers/dma/idxd/cdev.c
@@ -296,9 +296,7 @@ int idxd_wq_add_cdev(struct idxd_wq *wq)
void idxd_wq_del_cdev(struct idxd_wq *wq)
{
struct idxd_cdev *idxd_cdev;
- struct idxd_cdev_context *cdev_ctx;
- cdev_ctx = &ictx[wq->idxd->data->type];
idxd_cdev = wq->idxd_cdev;
wq->idxd_cdev = NULL;
cdev_device_del(&idxd_cdev->cdev, &idxd_cdev->dev);
diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
index 442d55c11a5f..c8ae41d36040 100644
--- a/drivers/dma/idxd/init.c
+++ b/drivers/dma/idxd/init.c
@@ -351,7 +351,8 @@ static int idxd_setup_internals(struct idxd_device *idxd)
init_waitqueue_head(&idxd->cmd_waitq);
if (idxd->hw.cmd_cap & BIT(IDXD_CMD_REQUEST_INT_HANDLE)) {
- idxd->int_handles = devm_kcalloc(dev, idxd->max_wqs, sizeof(int), GFP_KERNEL);
+ idxd->int_handles = kcalloc_node(idxd->max_wqs, sizeof(int), GFP_KERNEL,
+ dev_to_node(dev));
if (!idxd->int_handles)
return -ENOMEM;
}
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index d5590c08db51..8070fd664bfc 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -35,7 +35,6 @@
#include <linux/workqueue.h>
#include <asm/irq.h>
-#include <linux/platform_data/dma-imx-sdma.h>
#include <linux/platform_data/dma-imx.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
@@ -181,6 +180,61 @@
BIT(DMA_MEM_TO_DEV) | \
BIT(DMA_DEV_TO_DEV))
+/**
+ * struct sdma_script_start_addrs - SDMA script start pointers
+ *
+ * start addresses of the different functions in the physical
+ * address space of the SDMA engine.
+ */
+struct sdma_script_start_addrs {
+ s32 ap_2_ap_addr;
+ s32 ap_2_bp_addr;
+ s32 ap_2_ap_fixed_addr;
+ s32 bp_2_ap_addr;
+ s32 loopback_on_dsp_side_addr;
+ s32 mcu_interrupt_only_addr;
+ s32 firi_2_per_addr;
+ s32 firi_2_mcu_addr;
+ s32 per_2_firi_addr;
+ s32 mcu_2_firi_addr;
+ s32 uart_2_per_addr;
+ s32 uart_2_mcu_addr;
+ s32 per_2_app_addr;
+ s32 mcu_2_app_addr;
+ s32 per_2_per_addr;
+ s32 uartsh_2_per_addr;
+ s32 uartsh_2_mcu_addr;
+ s32 per_2_shp_addr;
+ s32 mcu_2_shp_addr;
+ s32 ata_2_mcu_addr;
+ s32 mcu_2_ata_addr;
+ s32 app_2_per_addr;
+ s32 app_2_mcu_addr;
+ s32 shp_2_per_addr;
+ s32 shp_2_mcu_addr;
+ s32 mshc_2_mcu_addr;
+ s32 mcu_2_mshc_addr;
+ s32 spdif_2_mcu_addr;
+ s32 mcu_2_spdif_addr;
+ s32 asrc_2_mcu_addr;
+ s32 ext_mem_2_ipu_addr;
+ s32 descrambler_addr;
+ s32 dptc_dvfs_addr;
+ s32 utra_addr;
+ s32 ram_code_start_addr;
+ /* End of v1 array */
+ s32 mcu_2_ssish_addr;
+ s32 ssish_2_mcu_addr;
+ s32 hdmi_dma_addr;
+ /* End of v2 array */
+ s32 zcanfd_2_mcu_addr;
+ s32 zqspi_2_mcu_addr;
+ s32 mcu_2_ecspi_addr;
+ /* End of v3 array */
+ s32 mcu_2_zqspi_addr;
+ /* End of v4 array */
+};
+
/*
* Mode/Count of data node descriptors - IPCv2
*/
@@ -1829,7 +1883,7 @@ static int sdma_get_firmware(struct sdma_engine *sdma,
int ret;
ret = request_firmware_nowait(THIS_MODULE,
- FW_ACTION_HOTPLUG, fw_name, sdma->dev,
+ FW_ACTION_UEVENT, fw_name, sdma->dev,
GFP_KERNEL, sdma, sdma_load_firmware);
return ret;
diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c
index 104ad420abbe..baab1ca9f621 100644
--- a/drivers/dma/ipu/ipu_idmac.c
+++ b/drivers/dma/ipu/ipu_idmac.c
@@ -618,6 +618,7 @@ static int ipu_enable_channel(struct idmac *idmac, struct idmac_channel *ichan)
case IDMAC_SDC_1:
case IDMAC_IC_7:
ipu_channel_set_priority(ipu, channel, true);
+ break;
default:
break;
}
@@ -978,6 +979,7 @@ static int ipu_init_channel(struct idmac *idmac, struct idmac_channel *ichan)
case IDMAC_SDC_0:
case IDMAC_SDC_1:
n_desc = 4;
+ break;
default:
break;
}
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index c1a69149c8bf..4a51fdbf5aa9 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -813,6 +813,7 @@ inline bool is_buswidth_valid(u8 buswidth, bool is_mpc8308)
case 16:
if (is_mpc8308)
return false;
+ break;
case 1:
case 2:
case 4:
diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c
index 43ac3ab23d4c..1a1b7d8458c9 100644
--- a/drivers/dma/qcom/gpi.c
+++ b/drivers/dma/qcom/gpi.c
@@ -2282,6 +2282,7 @@ static int gpi_probe(struct platform_device *pdev)
static const struct of_device_id gpi_of_match[] = {
{ .compatible = "qcom,sdm845-gpi-dma" },
{ .compatible = "qcom,sm8150-gpi-dma" },
+ { .compatible = "qcom,sm8250-gpi-dma" },
{ },
};
MODULE_DEVICE_TABLE(of, gpi_of_match);
diff --git a/drivers/dma/sf-pdma/sf-pdma.c b/drivers/dma/sf-pdma/sf-pdma.c
index c4c4e8575764..f12606aeff87 100644
--- a/drivers/dma/sf-pdma/sf-pdma.c
+++ b/drivers/dma/sf-pdma/sf-pdma.c
@@ -94,6 +94,7 @@ sf_pdma_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dest, dma_addr_t src,
{
struct sf_pdma_chan *chan = to_sf_pdma_chan(dchan);
struct sf_pdma_desc *desc;
+ unsigned long iflags;
if (chan && (!len || !dest || !src)) {
dev_err(chan->pdma->dma_dev.dev,
@@ -109,10 +110,10 @@ sf_pdma_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dest, dma_addr_t src,
desc->dirn = DMA_MEM_TO_MEM;
desc->async_tx = vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
- spin_lock_irqsave(&chan->vchan.lock, flags);
+ spin_lock_irqsave(&chan->vchan.lock, iflags);
chan->desc = desc;
sf_pdma_fill_desc(desc, dest, src, len);
- spin_unlock_irqrestore(&chan->vchan.lock, flags);
+ spin_unlock_irqrestore(&chan->vchan.lock, iflags);
return desc->async_tx;
}
diff --git a/drivers/dma/sh/Makefile b/drivers/dma/sh/Makefile
index 112fbd22bb3f..abdf10341725 100644
--- a/drivers/dma/sh/Makefile
+++ b/drivers/dma/sh/Makefile
@@ -3,7 +3,7 @@
# DMA Engine Helpers
#
-obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o shdma-of.o
+obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o
#
# DMA Controllers
diff --git a/drivers/dma/sh/shdma-of.c b/drivers/dma/sh/shdma-of.c
deleted file mode 100644
index be89dd894328..000000000000
--- a/drivers/dma/sh/shdma-of.c
+++ /dev/null
@@ -1,76 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * SHDMA Device Tree glue
- *
- * Copyright (C) 2013 Renesas Electronics Inc.
- * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- */
-
-#include <linux/dmaengine.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_dma.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/shdma-base.h>
-
-#define to_shdma_chan(c) container_of(c, struct shdma_chan, dma_chan)
-
-static struct dma_chan *shdma_of_xlate(struct of_phandle_args *dma_spec,
- struct of_dma *ofdma)
-{
- u32 id = dma_spec->args[0];
- dma_cap_mask_t mask;
- struct dma_chan *chan;
-
- if (dma_spec->args_count != 1)
- return NULL;
-
- dma_cap_zero(mask);
- /* Only slave DMA channels can be allocated via DT */
- dma_cap_set(DMA_SLAVE, mask);
-
- chan = dma_request_channel(mask, shdma_chan_filter,
- (void *)(uintptr_t)id);
- if (chan)
- to_shdma_chan(chan)->hw_req = id;
-
- return chan;
-}
-
-static int shdma_of_probe(struct platform_device *pdev)
-{
- const struct of_dev_auxdata *lookup = dev_get_platdata(&pdev->dev);
- int ret;
-
- ret = of_dma_controller_register(pdev->dev.of_node,
- shdma_of_xlate, pdev);
- if (ret < 0)
- return ret;
-
- ret = of_platform_populate(pdev->dev.of_node, NULL, lookup, &pdev->dev);
- if (ret < 0)
- of_dma_controller_free(pdev->dev.of_node);
-
- return ret;
-}
-
-static const struct of_device_id shdma_of_match[] = {
- { .compatible = "renesas,shdma-mux", },
- { }
-};
-MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
-
-static struct platform_driver shdma_of = {
- .driver = {
- .name = "shdma-of",
- .of_match_table = shdma_of_match,
- },
- .probe = shdma_of_probe,
-};
-
-module_platform_driver(shdma_of);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("SH-DMA driver DT glue");
-MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c
index e8b6633ae661..93f1645ae928 100644
--- a/drivers/dma/sun4i-dma.c
+++ b/drivers/dma/sun4i-dma.c
@@ -1042,9 +1042,8 @@ handle_pending:
* Move the promise into the completed list now that
* we're done with it
*/
- list_del(&vchan->processing->list);
- list_add_tail(&vchan->processing->list,
- &contract->completed_demands);
+ list_move_tail(&vchan->processing->list,
+ &contract->completed_demands);
/*
* Cyclic DMA transfers are special:
diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index 96ad21869ba7..a35858610780 100644
--- a/drivers/dma/ti/k3-udma.c
+++ b/drivers/dma/ti/k3-udma.c
@@ -4948,6 +4948,7 @@ static int setup_resources(struct udma_dev *ud)
ud->tchan_cnt),
ud->rchan_cnt - bitmap_weight(ud->rchan_map,
ud->rchan_cnt));
+ break;
default:
break;
}
diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c
index 268a08058714..7cb577e6587b 100644
--- a/drivers/dma/ti/omap-dma.c
+++ b/drivers/dma/ti/omap-dma.c
@@ -1608,7 +1608,8 @@ static int omap_dma_context_notifier(struct notifier_block *nb,
return NOTIFY_BAD;
omap_dma_context_save(od);
break;
- case CPU_CLUSTER_PM_ENTER_FAILED:
+ case CPU_CLUSTER_PM_ENTER_FAILED: /* No need to restore context */
+ break;
case CPU_CLUSTER_PM_EXIT:
omap_dma_context_restore(od);
break;
diff --git a/drivers/dma/xilinx/xilinx_dpdma.c b/drivers/dma/xilinx/xilinx_dpdma.c
index 6c709803203a..b280a53e8570 100644
--- a/drivers/dma/xilinx/xilinx_dpdma.c
+++ b/drivers/dma/xilinx/xilinx_dpdma.c
@@ -531,7 +531,7 @@ static void xilinx_dpdma_sw_desc_set_dma_addrs(struct xilinx_dpdma_device *xdev,
for (i = 1; i < num_src_addr; i++) {
u32 *addr = &hw_desc->src_addr2;
- addr[i-1] = lower_32_bits(dma_addr[i]);
+ addr[i - 1] = lower_32_bits(dma_addr[i]);
if (xdev->ext_addr) {
u32 *addr_ext = &hw_desc->addr_ext_23;
@@ -703,8 +703,9 @@ xilinx_dpdma_chan_prep_interleaved_dma(struct xilinx_dpdma_chan *chan,
size_t stride = hsize + xt->sgl[0].icg;
if (!IS_ALIGNED(xt->src_start, XILINX_DPDMA_ALIGN_BYTES)) {
- dev_err(chan->xdev->dev, "buffer should be aligned at %d B\n",
- XILINX_DPDMA_ALIGN_BYTES);
+ dev_err(chan->xdev->dev,
+ "chan%u: buffer should be aligned at %d B\n",
+ chan->id, XILINX_DPDMA_ALIGN_BYTES);
return NULL;
}
@@ -917,7 +918,7 @@ static u32 xilinx_dpdma_chan_ostand(struct xilinx_dpdma_chan *chan)
}
/**
- * xilinx_dpdma_chan_no_ostand - Notify no outstanding transaction event
+ * xilinx_dpdma_chan_notify_no_ostand - Notify no outstanding transaction event
* @chan: DPDMA channel
*
* Notify waiters for no outstanding event, so waiters can stop the channel
@@ -936,7 +937,9 @@ static int xilinx_dpdma_chan_notify_no_ostand(struct xilinx_dpdma_chan *chan)
cnt = xilinx_dpdma_chan_ostand(chan);
if (cnt) {
- dev_dbg(chan->xdev->dev, "%d outstanding transactions\n", cnt);
+ dev_dbg(chan->xdev->dev,
+ "chan%u: %d outstanding transactions\n",
+ chan->id, cnt);
return -EWOULDBLOCK;
}
@@ -972,8 +975,8 @@ static int xilinx_dpdma_chan_wait_no_ostand(struct xilinx_dpdma_chan *chan)
return 0;
}
- dev_err(chan->xdev->dev, "not ready to stop: %d trans\n",
- xilinx_dpdma_chan_ostand(chan));
+ dev_err(chan->xdev->dev, "chan%u: not ready to stop: %d trans\n",
+ chan->id, xilinx_dpdma_chan_ostand(chan));
if (ret == 0)
return -ETIMEDOUT;
@@ -1007,8 +1010,8 @@ static int xilinx_dpdma_chan_poll_no_ostand(struct xilinx_dpdma_chan *chan)
return 0;
}
- dev_err(chan->xdev->dev, "not ready to stop: %d trans\n",
- xilinx_dpdma_chan_ostand(chan));
+ dev_err(chan->xdev->dev, "chan%u: not ready to stop: %d trans\n",
+ chan->id, xilinx_dpdma_chan_ostand(chan));
return -ETIMEDOUT;
}
@@ -1062,7 +1065,8 @@ static void xilinx_dpdma_chan_done_irq(struct xilinx_dpdma_chan *chan)
vchan_cyclic_callback(&active->vdesc);
else
dev_warn(chan->xdev->dev,
- "DONE IRQ with no active descriptor!\n");
+ "chan%u: DONE IRQ with no active descriptor!\n",
+ chan->id);
spin_unlock_irqrestore(&chan->lock, flags);
}
@@ -1094,8 +1098,12 @@ static void xilinx_dpdma_chan_vsync_irq(struct xilinx_dpdma_chan *chan)
/* If the retrigger raced with vsync, retry at the next frame. */
sw_desc = list_first_entry(&pending->descriptors,
struct xilinx_dpdma_sw_desc, node);
- if (sw_desc->hw.desc_id != desc_id)
+ if (sw_desc->hw.desc_id != desc_id) {
+ dev_dbg(chan->xdev->dev,
+ "chan%u: vsync race lost (%u != %u), retrying\n",
+ chan->id, sw_desc->hw.desc_id, desc_id);
goto out;
+ }
/*
* Complete the active descriptor, if any, promote the pending
@@ -1151,10 +1159,12 @@ static void xilinx_dpdma_chan_handle_err(struct xilinx_dpdma_chan *chan)
spin_lock_irqsave(&chan->lock, flags);
- dev_dbg(xdev->dev, "cur desc addr = 0x%04x%08x\n",
+ dev_dbg(xdev->dev, "chan%u: cur desc addr = 0x%04x%08x\n",
+ chan->id,
dpdma_read(chan->reg, XILINX_DPDMA_CH_DESC_START_ADDRE),
dpdma_read(chan->reg, XILINX_DPDMA_CH_DESC_START_ADDR));
- dev_dbg(xdev->dev, "cur payload addr = 0x%04x%08x\n",
+ dev_dbg(xdev->dev, "chan%u: cur payload addr = 0x%04x%08x\n",
+ chan->id,
dpdma_read(chan->reg, XILINX_DPDMA_CH_PYLD_CUR_ADDRE),
dpdma_read(chan->reg, XILINX_DPDMA_CH_PYLD_CUR_ADDR));
@@ -1170,7 +1180,8 @@ static void xilinx_dpdma_chan_handle_err(struct xilinx_dpdma_chan *chan)
xilinx_dpdma_chan_dump_tx_desc(chan, active);
if (active->error)
- dev_dbg(xdev->dev, "repeated error on desc\n");
+ dev_dbg(xdev->dev, "chan%u: repeated error on desc\n",
+ chan->id);
/* Reschedule if there's no new descriptor */
if (!chan->desc.pending &&
@@ -1235,7 +1246,8 @@ static int xilinx_dpdma_alloc_chan_resources(struct dma_chan *dchan)
align, 0);
if (!chan->desc_pool) {
dev_err(chan->xdev->dev,
- "failed to allocate a descriptor pool\n");
+ "chan%u: failed to allocate a descriptor pool\n",
+ chan->id);
return -ENOMEM;
}
@@ -1588,7 +1600,7 @@ static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
struct xilinx_dpdma_device *xdev = ofdma->of_dma_data;
- uint32_t chan_id = dma_spec->args[0];
+ u32 chan_id = dma_spec->args[0];
if (chan_id >= ARRAY_SIZE(xdev->chan))
return NULL;
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 1e836e320edd..2fc4c3f91fd5 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -270,7 +270,8 @@ config EDAC_PND2
config EDAC_IGEN6
tristate "Intel client SoC Integrated MC"
- depends on PCI && X86_64 && PCI_MMCONFIG && ARCH_HAVE_NMI_SAFE_CMPXCHG
+ depends on PCI && PCI_MMCONFIG && ARCH_HAVE_NMI_SAFE_CMPXCHG
+ depends on X86_64 && X86_MCE_INTEL
help
Support for error detection and correction on the Intel
client SoC Integrated Memory Controller using In-Band ECC IP.
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 5f7fd79ec82f..61c21bd880a4 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -20,6 +20,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/panic_notifier.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/types.h>
diff --git a/drivers/edac/aspeed_edac.c b/drivers/edac/aspeed_edac.c
index a46da56d6d54..6bd5f8815919 100644
--- a/drivers/edac/aspeed_edac.c
+++ b/drivers/edac/aspeed_edac.c
@@ -254,8 +254,8 @@ static int init_csrows(struct mem_ctl_info *mci)
return rc;
}
- dev_dbg(mci->pdev, "dt: /memory node resources: first page r.start=0x%x, resource_size=0x%x, PAGE_SHIFT macro=0x%x\n",
- r.start, resource_size(&r), PAGE_SHIFT);
+ dev_dbg(mci->pdev, "dt: /memory node resources: first page %pR, PAGE_SHIFT macro=0x%x\n",
+ &r, PAGE_SHIFT);
csrow->first_page = r.start >> PAGE_SHIFT;
nr_pages = resource_size(&r) >> PAGE_SHIFT;
diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
index 238a4ad1e526..6ce0ed2ffaaf 100644
--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -13,7 +13,7 @@
#include "edac_module.h"
#include "skx_common.h"
-#define I10NM_REVISION "v0.0.4"
+#define I10NM_REVISION "v0.0.5"
#define EDAC_MOD_STR "i10nm_edac"
/* Debug macros */
@@ -24,19 +24,39 @@
pci_read_config_dword((d)->uracu, 0xd0, &(reg))
#define I10NM_GET_IMC_BAR(d, i, reg) \
pci_read_config_dword((d)->uracu, 0xd8 + (i) * 4, &(reg))
+#define I10NM_GET_SAD(d, offset, i, reg)\
+ pci_read_config_dword((d)->sad_all, (offset) + (i) * 8, &(reg))
+#define I10NM_GET_HBM_IMC_BAR(d, reg) \
+ pci_read_config_dword((d)->uracu, 0xd4, &(reg))
+#define I10NM_GET_CAPID3_CFG(d, reg) \
+ pci_read_config_dword((d)->pcu_cr3, 0x90, &(reg))
#define I10NM_GET_DIMMMTR(m, i, j) \
- readl((m)->mbase + 0x2080c + (i) * (m)->chan_mmio_sz + (j) * 4)
+ readl((m)->mbase + ((m)->hbm_mc ? 0x80c : 0x2080c) + \
+ (i) * (m)->chan_mmio_sz + (j) * 4)
#define I10NM_GET_MCDDRTCFG(m, i, j) \
- readl((m)->mbase + 0x20970 + (i) * (m)->chan_mmio_sz + (j) * 4)
+ readl((m)->mbase + ((m)->hbm_mc ? 0x970 : 0x20970) + \
+ (i) * (m)->chan_mmio_sz + (j) * 4)
#define I10NM_GET_MCMTR(m, i) \
- readl((m)->mbase + 0x20ef8 + (i) * (m)->chan_mmio_sz)
+ readl((m)->mbase + ((m)->hbm_mc ? 0xef8 : 0x20ef8) + \
+ (i) * (m)->chan_mmio_sz)
#define I10NM_GET_AMAP(m, i) \
- readl((m)->mbase + 0x20814 + (i) * (m)->chan_mmio_sz)
+ readl((m)->mbase + ((m)->hbm_mc ? 0x814 : 0x20814) + \
+ (i) * (m)->chan_mmio_sz)
#define I10NM_GET_SCK_MMIO_BASE(reg) (GET_BITFIELD(reg, 0, 28) << 23)
#define I10NM_GET_IMC_MMIO_OFFSET(reg) (GET_BITFIELD(reg, 0, 10) << 12)
#define I10NM_GET_IMC_MMIO_SIZE(reg) ((GET_BITFIELD(reg, 13, 23) - \
GET_BITFIELD(reg, 0, 10) + 1) << 12)
+#define I10NM_GET_HBM_IMC_MMIO_OFFSET(reg) \
+ ((GET_BITFIELD(reg, 0, 10) << 12) + 0x140000)
+
+#define I10NM_HBM_IMC_MMIO_SIZE 0x9000
+#define I10NM_IS_HBM_PRESENT(reg) GET_BITFIELD(reg, 27, 30)
+#define I10NM_IS_HBM_IMC(reg) GET_BITFIELD(reg, 29, 29)
+
+#define I10NM_MAX_SAD 16
+#define I10NM_SAD_ENABLE(reg) GET_BITFIELD(reg, 0, 0)
+#define I10NM_SAD_NM_CACHEABLE(reg) GET_BITFIELD(reg, 5, 5)
static struct list_head *i10nm_edac_list;
@@ -63,7 +83,32 @@ static struct pci_dev *pci_get_dev_wrapper(int dom, unsigned int bus,
return pdev;
}
-static int i10nm_get_all_munits(void)
+static bool i10nm_check_2lm(struct res_config *cfg)
+{
+ struct skx_dev *d;
+ u32 reg;
+ int i;
+
+ list_for_each_entry(d, i10nm_edac_list, list) {
+ d->sad_all = pci_get_dev_wrapper(d->seg, d->bus[1],
+ PCI_SLOT(cfg->sad_all_devfn),
+ PCI_FUNC(cfg->sad_all_devfn));
+ if (!d->sad_all)
+ continue;
+
+ for (i = 0; i < I10NM_MAX_SAD; i++) {
+ I10NM_GET_SAD(d, cfg->sad_all_offset, i, reg);
+ if (I10NM_SAD_ENABLE(reg) && I10NM_SAD_NM_CACHEABLE(reg)) {
+ edac_dbg(2, "2-level memory configuration.\n");
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static int i10nm_get_ddr_munits(void)
{
struct pci_dev *mdev;
void __iomem *mbase;
@@ -91,7 +136,7 @@ static int i10nm_get_all_munits(void)
edac_dbg(2, "socket%d mmio base 0x%llx (reg 0x%x)\n",
j++, base, reg);
- for (i = 0; i < I10NM_NUM_IMC; i++) {
+ for (i = 0; i < I10NM_NUM_DDR_IMC; i++) {
mdev = pci_get_dev_wrapper(d->seg, d->bus[0],
12 + i, 0);
if (i == 0 && !mdev) {
@@ -127,11 +172,97 @@ static int i10nm_get_all_munits(void)
return 0;
}
+static bool i10nm_check_hbm_imc(struct skx_dev *d)
+{
+ u32 reg;
+
+ if (I10NM_GET_CAPID3_CFG(d, reg)) {
+ i10nm_printk(KERN_ERR, "Failed to get capid3_cfg\n");
+ return false;
+ }
+
+ return I10NM_IS_HBM_PRESENT(reg) != 0;
+}
+
+static int i10nm_get_hbm_munits(void)
+{
+ struct pci_dev *mdev;
+ void __iomem *mbase;
+ u32 reg, off, mcmtr;
+ struct skx_dev *d;
+ int i, lmc;
+ u64 base;
+
+ list_for_each_entry(d, i10nm_edac_list, list) {
+ d->pcu_cr3 = pci_get_dev_wrapper(d->seg, d->bus[1], 30, 3);
+ if (!d->pcu_cr3)
+ return -ENODEV;
+
+ if (!i10nm_check_hbm_imc(d)) {
+ i10nm_printk(KERN_DEBUG, "No hbm memory\n");
+ return -ENODEV;
+ }
+
+ if (I10NM_GET_SCK_BAR(d, reg)) {
+ i10nm_printk(KERN_ERR, "Failed to get socket bar\n");
+ return -ENODEV;
+ }
+ base = I10NM_GET_SCK_MMIO_BASE(reg);
+
+ if (I10NM_GET_HBM_IMC_BAR(d, reg)) {
+ i10nm_printk(KERN_ERR, "Failed to get hbm mc bar\n");
+ return -ENODEV;
+ }
+ base += I10NM_GET_HBM_IMC_MMIO_OFFSET(reg);
+
+ lmc = I10NM_NUM_DDR_IMC;
+
+ for (i = 0; i < I10NM_NUM_HBM_IMC; i++) {
+ mdev = pci_get_dev_wrapper(d->seg, d->bus[0],
+ 12 + i / 4, 1 + i % 4);
+ if (i == 0 && !mdev) {
+ i10nm_printk(KERN_ERR, "No hbm mc found\n");
+ return -ENODEV;
+ }
+ if (!mdev)
+ continue;
+
+ d->imc[lmc].mdev = mdev;
+ off = i * I10NM_HBM_IMC_MMIO_SIZE;
+
+ edac_dbg(2, "hbm mc%d mmio base 0x%llx size 0x%x\n",
+ lmc, base + off, I10NM_HBM_IMC_MMIO_SIZE);
+
+ mbase = ioremap(base + off, I10NM_HBM_IMC_MMIO_SIZE);
+ if (!mbase) {
+ i10nm_printk(KERN_ERR, "Failed to ioremap for hbm mc 0x%llx\n",
+ base + off);
+ return -ENOMEM;
+ }
+
+ d->imc[lmc].mbase = mbase;
+ d->imc[lmc].hbm_mc = true;
+
+ mcmtr = I10NM_GET_MCMTR(&d->imc[lmc], 0);
+ if (!I10NM_IS_HBM_IMC(mcmtr)) {
+ i10nm_printk(KERN_ERR, "This isn't an hbm mc!\n");
+ return -ENODEV;
+ }
+
+ lmc++;
+ }
+ }
+
+ return 0;
+}
+
static struct res_config i10nm_cfg0 = {
.type = I10NM,
.decs_did = 0x3452,
.busno_cfg_offset = 0xcc,
.ddr_chan_mmio_sz = 0x4000,
+ .sad_all_devfn = PCI_DEVFN(29, 0),
+ .sad_all_offset = 0x108,
};
static struct res_config i10nm_cfg1 = {
@@ -139,6 +270,8 @@ static struct res_config i10nm_cfg1 = {
.decs_did = 0x3452,
.busno_cfg_offset = 0xd0,
.ddr_chan_mmio_sz = 0x4000,
+ .sad_all_devfn = PCI_DEVFN(29, 0),
+ .sad_all_offset = 0x108,
};
static struct res_config spr_cfg = {
@@ -146,7 +279,10 @@ static struct res_config spr_cfg = {
.decs_did = 0x3252,
.busno_cfg_offset = 0xd0,
.ddr_chan_mmio_sz = 0x8000,
+ .hbm_chan_mmio_sz = 0x4000,
.support_ddr5 = true,
+ .sad_all_devfn = PCI_DEVFN(10, 0),
+ .sad_all_offset = 0x300,
};
static const struct x86_cpu_id i10nm_cpuids[] = {
@@ -179,13 +315,13 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci,
struct dimm_info *dimm;
int i, j, ndimms;
- for (i = 0; i < I10NM_NUM_CHANNELS; i++) {
+ for (i = 0; i < imc->num_channels; i++) {
if (!imc->mbase)
continue;
ndimms = 0;
amap = I10NM_GET_AMAP(imc, i);
- for (j = 0; j < I10NM_NUM_DIMMS; j++) {
+ for (j = 0; j < imc->num_dimms; j++) {
dimm = edac_get_dimm(mci, i, j, 0);
mtr = I10NM_GET_DIMMMTR(imc, i, j);
mcddrtcfg = I10NM_GET_MCDDRTCFG(imc, i, j);
@@ -278,6 +414,9 @@ static int __init i10nm_init(void)
if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
return -EBUSY;
+ if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
+ return -ENODEV;
+
id = x86_match_cpu(i10nm_cpuids);
if (!id)
return -ENODEV;
@@ -296,8 +435,11 @@ static int __init i10nm_init(void)
return -ENODEV;
}
- rc = i10nm_get_all_munits();
- if (rc < 0)
+ skx_set_mem_cfg(i10nm_check_2lm(cfg));
+
+ rc = i10nm_get_ddr_munits();
+
+ if (i10nm_get_hbm_munits() && rc)
goto fail;
list_for_each_entry(d, i10nm_edac_list, list) {
@@ -318,7 +460,15 @@ static int __init i10nm_init(void)
d->imc[i].lmc = i;
d->imc[i].src_id = src_id;
d->imc[i].node_id = node_id;
- d->imc[i].chan_mmio_sz = cfg->ddr_chan_mmio_sz;
+ if (d->imc[i].hbm_mc) {
+ d->imc[i].chan_mmio_sz = cfg->hbm_chan_mmio_sz;
+ d->imc[i].num_channels = I10NM_NUM_HBM_CHANNELS;
+ d->imc[i].num_dimms = I10NM_NUM_HBM_DIMMS;
+ } else {
+ d->imc[i].chan_mmio_sz = cfg->ddr_chan_mmio_sz;
+ d->imc[i].num_channels = I10NM_NUM_DDR_CHANNELS;
+ d->imc[i].num_dimms = I10NM_NUM_DDR_DIMMS;
+ }
rc = skx_register_mci(&d->imc[i], d->imc[i].mdev,
"Intel_10nm Socket", EDAC_MOD_STR,
diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c
index 6be9986fc6bd..a07bbfd075d0 100644
--- a/drivers/edac/igen6_edac.c
+++ b/drivers/edac/igen6_edac.c
@@ -22,11 +22,12 @@
#include <linux/io.h>
#include <asm/mach_traps.h>
#include <asm/nmi.h>
+#include <asm/mce.h>
#include "edac_mc.h"
#include "edac_module.h"
-#define IGEN6_REVISION "v2.4"
+#define IGEN6_REVISION "v2.5"
#define EDAC_MOD_STR "igen6_edac"
#define IGEN6_NMI_NAME "igen6_ibecc"
@@ -40,7 +41,7 @@
#define GET_BITFIELD(v, lo, hi) (((v) & GENMASK_ULL(hi, lo)) >> (lo))
-#define NUM_IMC 1 /* Max memory controllers */
+#define NUM_IMC 2 /* Max memory controllers */
#define NUM_CHANNELS 2 /* Max channels */
#define NUM_DIMMS 2 /* Max DIMMs per channel */
@@ -54,6 +55,10 @@
#define CAPID_C_OFFSET 0xec
#define CAPID_C_IBECC BIT(15)
+/* Capability register E */
+#define CAPID_E_OFFSET 0xf0
+#define CAPID_E_IBECC BIT(12)
+
/* Error Status */
#define ERRSTS_OFFSET 0xc8
#define ERRSTS_CE BIT_ULL(6)
@@ -70,7 +75,7 @@
#define IBECC_ACTIVATE_EN BIT(0)
/* IBECC error log */
-#define ECC_ERROR_LOG_OFFSET (IBECC_BASE + 0x170)
+#define ECC_ERROR_LOG_OFFSET (IBECC_BASE + res_cfg->ibecc_error_log_offset)
#define ECC_ERROR_LOG_CE BIT_ULL(62)
#define ECC_ERROR_LOG_UE BIT_ULL(63)
#define ECC_ERROR_LOG_ADDR_SHIFT 5
@@ -84,39 +89,54 @@
#define MCHBAR_SIZE 0x10000
/* Parameters for the channel decode stage */
-#define MAD_INTER_CHANNEL_OFFSET 0x5000
+#define IMC_BASE (res_cfg->imc_base)
+#define MAD_INTER_CHANNEL_OFFSET IMC_BASE
#define MAD_INTER_CHANNEL_DDR_TYPE(v) GET_BITFIELD(v, 0, 2)
#define MAD_INTER_CHANNEL_ECHM(v) GET_BITFIELD(v, 3, 3)
#define MAD_INTER_CHANNEL_CH_L_MAP(v) GET_BITFIELD(v, 4, 4)
#define MAD_INTER_CHANNEL_CH_S_SIZE(v) ((u64)GET_BITFIELD(v, 12, 19) << 29)
/* Parameters for DRAM decode stage */
-#define MAD_INTRA_CH0_OFFSET 0x5004
+#define MAD_INTRA_CH0_OFFSET (IMC_BASE + 4)
#define MAD_INTRA_CH_DIMM_L_MAP(v) GET_BITFIELD(v, 0, 0)
/* DIMM characteristics */
-#define MAD_DIMM_CH0_OFFSET 0x500c
+#define MAD_DIMM_CH0_OFFSET (IMC_BASE + 0xc)
#define MAD_DIMM_CH_DIMM_L_SIZE(v) ((u64)GET_BITFIELD(v, 0, 6) << 29)
#define MAD_DIMM_CH_DLW(v) GET_BITFIELD(v, 7, 8)
#define MAD_DIMM_CH_DIMM_S_SIZE(v) ((u64)GET_BITFIELD(v, 16, 22) << 29)
#define MAD_DIMM_CH_DSW(v) GET_BITFIELD(v, 24, 25)
+/* Hash for memory controller selection */
+#define MAD_MC_HASH_OFFSET (IMC_BASE + 0x1b8)
+#define MAC_MC_HASH_LSB(v) GET_BITFIELD(v, 1, 3)
+
/* Hash for channel selection */
-#define CHANNEL_HASH_OFFSET 0X5024
+#define CHANNEL_HASH_OFFSET (IMC_BASE + 0x24)
/* Hash for enhanced channel selection */
-#define CHANNEL_EHASH_OFFSET 0X5028
+#define CHANNEL_EHASH_OFFSET (IMC_BASE + 0x28)
#define CHANNEL_HASH_MASK(v) (GET_BITFIELD(v, 6, 19) << 6)
#define CHANNEL_HASH_LSB_MASK_BIT(v) GET_BITFIELD(v, 24, 26)
#define CHANNEL_HASH_MODE(v) GET_BITFIELD(v, 28, 28)
+/* Parameters for memory slice decode stage */
+#define MEM_SLICE_HASH_MASK(v) (GET_BITFIELD(v, 6, 19) << 6)
+#define MEM_SLICE_HASH_LSB_MASK_BIT(v) GET_BITFIELD(v, 24, 26)
+
static struct res_config {
+ bool machine_check;
int num_imc;
+ u32 imc_base;
+ u32 cmf_base;
+ u32 cmf_size;
+ u32 ms_hash_offset;
u32 ibecc_base;
+ u32 ibecc_error_log_offset;
bool (*ibecc_available)(struct pci_dev *pdev);
/* Convert error address logged in IBECC to system physical address */
- u64 (*err_addr_to_sys_addr)(u64 eaddr);
+ u64 (*err_addr_to_sys_addr)(u64 eaddr, int mc);
/* Convert error address logged in IBECC to integrated memory controller address */
- u64 (*err_addr_to_imc_addr)(u64 eaddr);
+ u64 (*err_addr_to_imc_addr)(u64 eaddr, int mc);
} *res_cfg;
struct igen6_imc {
@@ -125,6 +145,7 @@ struct igen6_imc {
struct pci_dev *pdev;
struct device dev;
void __iomem *window;
+ u64 size;
u64 ch_s_size;
int ch_l_map;
u64 dimm_s_size[NUM_CHANNELS];
@@ -134,6 +155,9 @@ struct igen6_imc {
static struct igen6_pvt {
struct igen6_imc imc[NUM_IMC];
+ u64 ms_hash;
+ u64 ms_s_size;
+ int ms_l_map;
} *igen6_pvt;
/* The top of low usable DRAM */
@@ -183,6 +207,21 @@ static struct work_struct ecclog_work;
#define DID_EHL_SKU14 0x4534
#define DID_EHL_SKU15 0x4536
+/* Compute die IDs for ICL-NNPI with IBECC */
+#define DID_ICL_SKU8 0x4581
+#define DID_ICL_SKU10 0x4585
+#define DID_ICL_SKU11 0x4589
+#define DID_ICL_SKU12 0x458d
+
+/* Compute die IDs for Tiger Lake with IBECC */
+#define DID_TGL_SKU 0x9a14
+
+/* Compute die IDs for Alder Lake with IBECC */
+#define DID_ADL_SKU1 0x4601
+#define DID_ADL_SKU2 0x4602
+#define DID_ADL_SKU3 0x4621
+#define DID_ADL_SKU4 0x4641
+
static bool ehl_ibecc_available(struct pci_dev *pdev)
{
u32 v;
@@ -193,12 +232,12 @@ static bool ehl_ibecc_available(struct pci_dev *pdev)
return !!(CAPID_C_IBECC & v);
}
-static u64 ehl_err_addr_to_sys_addr(u64 eaddr)
+static u64 ehl_err_addr_to_sys_addr(u64 eaddr, int mc)
{
return eaddr;
}
-static u64 ehl_err_addr_to_imc_addr(u64 eaddr)
+static u64 ehl_err_addr_to_imc_addr(u64 eaddr, int mc)
{
if (eaddr < igen6_tolud)
return eaddr;
@@ -212,12 +251,156 @@ static u64 ehl_err_addr_to_imc_addr(u64 eaddr)
return eaddr;
}
+static bool icl_ibecc_available(struct pci_dev *pdev)
+{
+ u32 v;
+
+ if (pci_read_config_dword(pdev, CAPID_C_OFFSET, &v))
+ return false;
+
+ return !(CAPID_C_IBECC & v) &&
+ (boot_cpu_data.x86_stepping >= 1);
+}
+
+static bool tgl_ibecc_available(struct pci_dev *pdev)
+{
+ u32 v;
+
+ if (pci_read_config_dword(pdev, CAPID_E_OFFSET, &v))
+ return false;
+
+ return !(CAPID_E_IBECC & v);
+}
+
+static u64 mem_addr_to_sys_addr(u64 maddr)
+{
+ if (maddr < igen6_tolud)
+ return maddr;
+
+ if (igen6_tom <= _4GB)
+ return maddr - igen6_tolud + _4GB;
+
+ if (maddr < _4GB)
+ return maddr - igen6_tolud + igen6_tom;
+
+ return maddr;
+}
+
+static u64 mem_slice_hash(u64 addr, u64 mask, u64 hash_init, int intlv_bit)
+{
+ u64 hash_addr = addr & mask, hash = hash_init;
+ u64 intlv = (addr >> intlv_bit) & 1;
+ int i;
+
+ for (i = 6; i < 20; i++)
+ hash ^= (hash_addr >> i) & 1;
+
+ return hash ^ intlv;
+}
+
+static u64 tgl_err_addr_to_mem_addr(u64 eaddr, int mc)
+{
+ u64 maddr, hash, mask, ms_s_size;
+ int intlv_bit;
+ u32 ms_hash;
+
+ ms_s_size = igen6_pvt->ms_s_size;
+ if (eaddr >= ms_s_size)
+ return eaddr + ms_s_size;
+
+ ms_hash = igen6_pvt->ms_hash;
+
+ mask = MEM_SLICE_HASH_MASK(ms_hash);
+ intlv_bit = MEM_SLICE_HASH_LSB_MASK_BIT(ms_hash) + 6;
+
+ maddr = GET_BITFIELD(eaddr, intlv_bit, 63) << (intlv_bit + 1) |
+ GET_BITFIELD(eaddr, 0, intlv_bit - 1);
+
+ hash = mem_slice_hash(maddr, mask, mc, intlv_bit);
+
+ return maddr | (hash << intlv_bit);
+}
+
+static u64 tgl_err_addr_to_sys_addr(u64 eaddr, int mc)
+{
+ u64 maddr = tgl_err_addr_to_mem_addr(eaddr, mc);
+
+ return mem_addr_to_sys_addr(maddr);
+}
+
+static u64 tgl_err_addr_to_imc_addr(u64 eaddr, int mc)
+{
+ return eaddr;
+}
+
+static u64 adl_err_addr_to_sys_addr(u64 eaddr, int mc)
+{
+ return mem_addr_to_sys_addr(eaddr);
+}
+
+static u64 adl_err_addr_to_imc_addr(u64 eaddr, int mc)
+{
+ u64 imc_addr, ms_s_size = igen6_pvt->ms_s_size;
+ struct igen6_imc *imc = &igen6_pvt->imc[mc];
+ int intlv_bit;
+ u32 mc_hash;
+
+ if (eaddr >= 2 * ms_s_size)
+ return eaddr - ms_s_size;
+
+ mc_hash = readl(imc->window + MAD_MC_HASH_OFFSET);
+
+ intlv_bit = MAC_MC_HASH_LSB(mc_hash) + 6;
+
+ imc_addr = GET_BITFIELD(eaddr, intlv_bit + 1, 63) << intlv_bit |
+ GET_BITFIELD(eaddr, 0, intlv_bit - 1);
+
+ return imc_addr;
+}
+
static struct res_config ehl_cfg = {
- .num_imc = 1,
- .ibecc_base = 0xdc00,
- .ibecc_available = ehl_ibecc_available,
- .err_addr_to_sys_addr = ehl_err_addr_to_sys_addr,
- .err_addr_to_imc_addr = ehl_err_addr_to_imc_addr,
+ .num_imc = 1,
+ .imc_base = 0x5000,
+ .ibecc_base = 0xdc00,
+ .ibecc_available = ehl_ibecc_available,
+ .ibecc_error_log_offset = 0x170,
+ .err_addr_to_sys_addr = ehl_err_addr_to_sys_addr,
+ .err_addr_to_imc_addr = ehl_err_addr_to_imc_addr,
+};
+
+static struct res_config icl_cfg = {
+ .num_imc = 1,
+ .imc_base = 0x5000,
+ .ibecc_base = 0xd800,
+ .ibecc_error_log_offset = 0x170,
+ .ibecc_available = icl_ibecc_available,
+ .err_addr_to_sys_addr = ehl_err_addr_to_sys_addr,
+ .err_addr_to_imc_addr = ehl_err_addr_to_imc_addr,
+};
+
+static struct res_config tgl_cfg = {
+ .machine_check = true,
+ .num_imc = 2,
+ .imc_base = 0x5000,
+ .cmf_base = 0x11000,
+ .cmf_size = 0x800,
+ .ms_hash_offset = 0xac,
+ .ibecc_base = 0xd400,
+ .ibecc_error_log_offset = 0x170,
+ .ibecc_available = tgl_ibecc_available,
+ .err_addr_to_sys_addr = tgl_err_addr_to_sys_addr,
+ .err_addr_to_imc_addr = tgl_err_addr_to_imc_addr,
+};
+
+static struct res_config adl_cfg = {
+ .machine_check = true,
+ .num_imc = 2,
+ .imc_base = 0xd800,
+ .ibecc_base = 0xd400,
+ .ibecc_error_log_offset = 0x68,
+ .ibecc_available = tgl_ibecc_available,
+ .err_addr_to_sys_addr = adl_err_addr_to_sys_addr,
+ .err_addr_to_imc_addr = adl_err_addr_to_imc_addr,
};
static const struct pci_device_id igen6_pci_tbl[] = {
@@ -232,6 +415,15 @@ static const struct pci_device_id igen6_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, DID_EHL_SKU13), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU14), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU15), (kernel_ulong_t)&ehl_cfg },
+ { PCI_VDEVICE(INTEL, DID_ICL_SKU8), (kernel_ulong_t)&icl_cfg },
+ { PCI_VDEVICE(INTEL, DID_ICL_SKU10), (kernel_ulong_t)&icl_cfg },
+ { PCI_VDEVICE(INTEL, DID_ICL_SKU11), (kernel_ulong_t)&icl_cfg },
+ { PCI_VDEVICE(INTEL, DID_ICL_SKU12), (kernel_ulong_t)&icl_cfg },
+ { PCI_VDEVICE(INTEL, DID_TGL_SKU), (kernel_ulong_t)&tgl_cfg },
+ { PCI_VDEVICE(INTEL, DID_ADL_SKU1), (kernel_ulong_t)&adl_cfg },
+ { PCI_VDEVICE(INTEL, DID_ADL_SKU2), (kernel_ulong_t)&adl_cfg },
+ { PCI_VDEVICE(INTEL, DID_ADL_SKU3), (kernel_ulong_t)&adl_cfg },
+ { PCI_VDEVICE(INTEL, DID_ADL_SKU4), (kernel_ulong_t)&adl_cfg },
{ },
};
MODULE_DEVICE_TABLE(pci, igen6_pci_tbl);
@@ -490,8 +682,8 @@ static void ecclog_work_cb(struct work_struct *work)
eaddr = ECC_ERROR_LOG_ADDR(node->ecclog) <<
ECC_ERROR_LOG_ADDR_SHIFT;
res.mc = node->mc;
- res.sys_addr = res_cfg->err_addr_to_sys_addr(eaddr);
- res.imc_addr = res_cfg->err_addr_to_imc_addr(eaddr);
+ res.sys_addr = res_cfg->err_addr_to_sys_addr(eaddr, res.mc);
+ res.imc_addr = res_cfg->err_addr_to_imc_addr(eaddr, res.mc);
mci = igen6_pvt->imc[res.mc].mci;
@@ -540,6 +732,57 @@ static int ecclog_nmi_handler(unsigned int cmd, struct pt_regs *regs)
return NMI_HANDLED;
}
+static int ecclog_mce_handler(struct notifier_block *nb, unsigned long val,
+ void *data)
+{
+ struct mce *mce = (struct mce *)data;
+ char *type;
+
+ if (mce->kflags & MCE_HANDLED_CEC)
+ return NOTIFY_DONE;
+
+ /*
+ * Ignore unless this is a memory related error.
+ * We don't check the bit MCI_STATUS_ADDRV of MCi_STATUS here,
+ * since this bit isn't set on some CPU (e.g., Tiger Lake UP3).
+ */
+ if ((mce->status & 0xefff) >> 7 != 1)
+ return NOTIFY_DONE;
+
+ if (mce->mcgstatus & MCG_STATUS_MCIP)
+ type = "Exception";
+ else
+ type = "Event";
+
+ edac_dbg(0, "CPU %d: Machine Check %s: 0x%llx Bank %d: 0x%llx\n",
+ mce->extcpu, type, mce->mcgstatus,
+ mce->bank, mce->status);
+ edac_dbg(0, "TSC 0x%llx\n", mce->tsc);
+ edac_dbg(0, "ADDR 0x%llx\n", mce->addr);
+ edac_dbg(0, "MISC 0x%llx\n", mce->misc);
+ edac_dbg(0, "PROCESSOR %u:0x%x TIME %llu SOCKET %u APIC 0x%x\n",
+ mce->cpuvendor, mce->cpuid, mce->time,
+ mce->socketid, mce->apicid);
+ /*
+ * We just use the Machine Check for the memory error notification.
+ * Each memory controller is associated with an IBECC instance.
+ * Directly read and clear the error information(error address and
+ * error type) on all the IBECC instances so that we know on which
+ * memory controller the memory error(s) occurred.
+ */
+ if (!ecclog_handler())
+ return NOTIFY_DONE;
+
+ mce->kflags |= MCE_HANDLED_EDAC;
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block ecclog_mce_dec = {
+ .notifier_call = ecclog_mce_handler,
+ .priority = MCE_PRIO_EDAC,
+};
+
static bool igen6_check_ecc(struct igen6_imc *imc)
{
u32 activate = readl(imc->window + IBECC_ACTIVATE_OFFSET);
@@ -573,6 +816,8 @@ static int igen6_get_dimm_config(struct mem_ctl_info *mci)
imc->dimm_l_size[i] = MAD_DIMM_CH_DIMM_L_SIZE(mad_dimm);
imc->dimm_s_size[i] = MAD_DIMM_CH_DIMM_S_SIZE(mad_dimm);
imc->dimm_l_map[i] = MAD_INTRA_CH_DIMM_L_MAP(mad_intra);
+ imc->size += imc->dimm_s_size[i];
+ imc->size += imc->dimm_l_size[i];
ndimms = 0;
for (j = 0; j < NUM_DIMMS; j++) {
@@ -608,6 +853,8 @@ static int igen6_get_dimm_config(struct mem_ctl_info *mci)
}
}
+ edac_dbg(0, "MC %d, total size %llu MiB\n", mc, imc->size >> 20);
+
return 0;
}
@@ -857,6 +1104,80 @@ static void igen6_unregister_mcis(void)
}
}
+static int igen6_mem_slice_setup(u64 mchbar)
+{
+ struct igen6_imc *imc = &igen6_pvt->imc[0];
+ u64 base = mchbar + res_cfg->cmf_base;
+ u32 offset = res_cfg->ms_hash_offset;
+ u32 size = res_cfg->cmf_size;
+ u64 ms_s_size, ms_hash;
+ void __iomem *cmf;
+ int ms_l_map;
+
+ edac_dbg(2, "\n");
+
+ if (imc[0].size < imc[1].size) {
+ ms_s_size = imc[0].size;
+ ms_l_map = 1;
+ } else {
+ ms_s_size = imc[1].size;
+ ms_l_map = 0;
+ }
+
+ igen6_pvt->ms_s_size = ms_s_size;
+ igen6_pvt->ms_l_map = ms_l_map;
+
+ edac_dbg(0, "ms_s_size: %llu MiB, ms_l_map %d\n",
+ ms_s_size >> 20, ms_l_map);
+
+ if (!size)
+ return 0;
+
+ cmf = ioremap(base, size);
+ if (!cmf) {
+ igen6_printk(KERN_ERR, "Failed to ioremap cmf 0x%llx\n", base);
+ return -ENODEV;
+ }
+
+ ms_hash = readq(cmf + offset);
+ igen6_pvt->ms_hash = ms_hash;
+
+ edac_dbg(0, "MEM_SLICE_HASH: 0x%llx\n", ms_hash);
+
+ iounmap(cmf);
+
+ return 0;
+}
+
+static int register_err_handler(void)
+{
+ int rc;
+
+ if (res_cfg->machine_check) {
+ mce_register_decode_chain(&ecclog_mce_dec);
+ return 0;
+ }
+
+ rc = register_nmi_handler(NMI_SERR, ecclog_nmi_handler,
+ 0, IGEN6_NMI_NAME);
+ if (rc) {
+ igen6_printk(KERN_ERR, "Failed to register NMI handler\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static void unregister_err_handler(void)
+{
+ if (res_cfg->machine_check) {
+ mce_unregister_decode_chain(&ecclog_mce_dec);
+ return;
+ }
+
+ unregister_nmi_handler(NMI_SERR, IGEN6_NMI_NAME);
+}
+
static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
u64 mchbar;
@@ -880,6 +1201,12 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto fail2;
}
+ if (res_cfg->num_imc > 1) {
+ rc = igen6_mem_slice_setup(mchbar);
+ if (rc)
+ goto fail2;
+ }
+
ecclog_pool = ecclog_gen_pool_create();
if (!ecclog_pool) {
rc = -ENOMEM;
@@ -892,12 +1219,9 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Check if any pending errors before registering the NMI handler */
ecclog_handler();
- rc = register_nmi_handler(NMI_SERR, ecclog_nmi_handler,
- 0, IGEN6_NMI_NAME);
- if (rc) {
- igen6_printk(KERN_ERR, "Failed to register NMI handler\n");
+ rc = register_err_handler();
+ if (rc)
goto fail3;
- }
/* Enable error reporting */
rc = errcmd_enable_error_reporting(true);
@@ -925,7 +1249,7 @@ static void igen6_remove(struct pci_dev *pdev)
igen6_debug_teardown();
errcmd_enable_error_reporting(false);
- unregister_nmi_handler(NMI_SERR, IGEN6_NMI_NAME);
+ unregister_err_handler();
irq_work_sync(&ecclog_irq_work);
flush_work(&ecclog_work);
gen_pool_destroy(ecclog_pool);
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index 5dd905a3f30c..27d56920b469 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -323,6 +323,21 @@ static const char * const smca_umc_mce_desc[] = {
"AES SRAM ECC error",
};
+static const char * const smca_umc2_mce_desc[] = {
+ "DRAM ECC error",
+ "Data poison error",
+ "SDP parity error",
+ "Reserved",
+ "Address/Command parity error",
+ "Write data parity error",
+ "DCQ SRAM ECC error",
+ "Reserved",
+ "Read data parity error",
+ "Rdb SRAM ECC error",
+ "RdRsp SRAM ECC error",
+ "LM32 MP errors",
+};
+
static const char * const smca_pb_mce_desc[] = {
"An ECC error in the Parameter Block RAM array",
};
@@ -400,6 +415,56 @@ static const char * const smca_pcie_mce_desc[] = {
"CCIX Non-okay write response with data error",
};
+static const char * const smca_pcie2_mce_desc[] = {
+ "SDP Parity Error logging",
+};
+
+static const char * const smca_xgmipcs_mce_desc[] = {
+ "Data Loss Error",
+ "Training Error",
+ "Flow Control Acknowledge Error",
+ "Rx Fifo Underflow Error",
+ "Rx Fifo Overflow Error",
+ "CRC Error",
+ "BER Exceeded Error",
+ "Tx Vcid Data Error",
+ "Replay Buffer Parity Error",
+ "Data Parity Error",
+ "Replay Fifo Overflow Error",
+ "Replay Fifo Underflow Error",
+ "Elastic Fifo Overflow Error",
+ "Deskew Error",
+ "Flow Control CRC Error",
+ "Data Startup Limit Error",
+ "FC Init Timeout Error",
+ "Recovery Timeout Error",
+ "Ready Serial Timeout Error",
+ "Ready Serial Attempt Error",
+ "Recovery Attempt Error",
+ "Recovery Relock Attempt Error",
+ "Replay Attempt Error",
+ "Sync Header Error",
+ "Tx Replay Timeout Error",
+ "Rx Replay Timeout Error",
+ "LinkSub Tx Timeout Error",
+ "LinkSub Rx Timeout Error",
+ "Rx CMD Pocket Error",
+};
+
+static const char * const smca_xgmiphy_mce_desc[] = {
+ "RAM ECC Error",
+ "ARC instruction buffer parity error",
+ "ARC data buffer parity error",
+ "PHY APB error",
+};
+
+static const char * const smca_waflphy_mce_desc[] = {
+ "RAM ECC Error",
+ "ARC instruction buffer parity error",
+ "ARC data buffer parity error",
+ "PHY APB error",
+};
+
struct smca_mce_desc {
const char * const *descs;
unsigned int num_descs;
@@ -418,6 +483,7 @@ static struct smca_mce_desc smca_mce_descs[] = {
[SMCA_CS_V2] = { smca_cs2_mce_desc, ARRAY_SIZE(smca_cs2_mce_desc) },
[SMCA_PIE] = { smca_pie_mce_desc, ARRAY_SIZE(smca_pie_mce_desc) },
[SMCA_UMC] = { smca_umc_mce_desc, ARRAY_SIZE(smca_umc_mce_desc) },
+ [SMCA_UMC_V2] = { smca_umc2_mce_desc, ARRAY_SIZE(smca_umc2_mce_desc) },
[SMCA_PB] = { smca_pb_mce_desc, ARRAY_SIZE(smca_pb_mce_desc) },
[SMCA_PSP] = { smca_psp_mce_desc, ARRAY_SIZE(smca_psp_mce_desc) },
[SMCA_PSP_V2] = { smca_psp2_mce_desc, ARRAY_SIZE(smca_psp2_mce_desc) },
@@ -426,6 +492,10 @@ static struct smca_mce_desc smca_mce_descs[] = {
[SMCA_MP5] = { smca_mp5_mce_desc, ARRAY_SIZE(smca_mp5_mce_desc) },
[SMCA_NBIO] = { smca_nbio_mce_desc, ARRAY_SIZE(smca_nbio_mce_desc) },
[SMCA_PCIE] = { smca_pcie_mce_desc, ARRAY_SIZE(smca_pcie_mce_desc) },
+ [SMCA_PCIE_V2] = { smca_pcie2_mce_desc, ARRAY_SIZE(smca_pcie2_mce_desc) },
+ [SMCA_XGMI_PCS] = { smca_xgmipcs_mce_desc, ARRAY_SIZE(smca_xgmipcs_mce_desc) },
+ [SMCA_XGMI_PHY] = { smca_xgmiphy_mce_desc, ARRAY_SIZE(smca_xgmiphy_mce_desc) },
+ [SMCA_WAFL_PHY] = { smca_waflphy_mce_desc, ARRAY_SIZE(smca_waflphy_mce_desc) },
};
static bool f12h_mc0_mce(u16 ec, u8 xec)
diff --git a/drivers/edac/pnd2_edac.c b/drivers/edac/pnd2_edac.c
index 928f63a374c7..c94ca1f790c4 100644
--- a/drivers/edac/pnd2_edac.c
+++ b/drivers/edac/pnd2_edac.c
@@ -1554,6 +1554,9 @@ static int __init pnd2_init(void)
if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
return -EBUSY;
+ if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
+ return -ENODEV;
+
id = x86_match_cpu(pnd2_cpuids);
if (!id)
return -ENODEV;
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 93daa4297f2e..4c626fcd4dcb 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -3510,6 +3510,9 @@ static int __init sbridge_init(void)
if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
return -EBUSY;
+ if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
+ return -ENODEV;
+
id = x86_match_cpu(sbridge_cpuids);
if (!id)
return -ENODEV;
diff --git a/drivers/edac/skx_base.c b/drivers/edac/skx_base.c
index 6a4f0b27c654..4dbd46575bfb 100644
--- a/drivers/edac/skx_base.c
+++ b/drivers/edac/skx_base.c
@@ -656,6 +656,9 @@ static int __init skx_init(void)
if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
return -EBUSY;
+ if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
+ return -ENODEV;
+
id = x86_match_cpu(skx_cpuids);
if (!id)
return -ENODEV;
diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c
index 81c3e2ec6f56..5e83f59bef8a 100644
--- a/drivers/edac/skx_common.c
+++ b/drivers/edac/skx_common.c
@@ -23,10 +23,13 @@
#include "skx_common.h"
static const char * const component_names[] = {
- [INDEX_SOCKET] = "ProcessorSocketId",
- [INDEX_MEMCTRL] = "MemoryControllerId",
- [INDEX_CHANNEL] = "ChannelId",
- [INDEX_DIMM] = "DimmSlotId",
+ [INDEX_SOCKET] = "ProcessorSocketId",
+ [INDEX_MEMCTRL] = "MemoryControllerId",
+ [INDEX_CHANNEL] = "ChannelId",
+ [INDEX_DIMM] = "DimmSlotId",
+ [INDEX_NM_MEMCTRL] = "NmMemoryControllerId",
+ [INDEX_NM_CHANNEL] = "NmChannelId",
+ [INDEX_NM_DIMM] = "NmDimmSlotId",
};
static int component_indices[ARRAY_SIZE(component_names)];
@@ -34,12 +37,14 @@ static int adxl_component_count;
static const char * const *adxl_component_names;
static u64 *adxl_values;
static char *adxl_msg;
+static unsigned long adxl_nm_bitmap;
static char skx_msg[MSG_SIZE];
static skx_decode_f skx_decode;
static skx_show_retry_log_f skx_show_retry_rd_err_log;
static u64 skx_tolm, skx_tohm;
static LIST_HEAD(dev_edac_list);
+static bool skx_mem_cfg_2lm;
int __init skx_adxl_get(void)
{
@@ -56,14 +61,25 @@ int __init skx_adxl_get(void)
for (j = 0; names[j]; j++) {
if (!strcmp(component_names[i], names[j])) {
component_indices[i] = j;
+
+ if (i >= INDEX_NM_FIRST)
+ adxl_nm_bitmap |= 1 << i;
+
break;
}
}
- if (!names[j])
+ if (!names[j] && i < INDEX_NM_FIRST)
goto err;
}
+ if (skx_mem_cfg_2lm) {
+ if (!adxl_nm_bitmap)
+ skx_printk(KERN_NOTICE, "Not enough ADXL components for 2-level memory.\n");
+ else
+ edac_dbg(2, "adxl_nm_bitmap: 0x%lx\n", adxl_nm_bitmap);
+ }
+
adxl_component_names = names;
while (*names++)
adxl_component_count++;
@@ -99,7 +115,7 @@ void __exit skx_adxl_put(void)
kfree(adxl_msg);
}
-static bool skx_adxl_decode(struct decoded_addr *res)
+static bool skx_adxl_decode(struct decoded_addr *res, bool error_in_1st_level_mem)
{
struct skx_dev *d;
int i, len = 0;
@@ -116,11 +132,20 @@ static bool skx_adxl_decode(struct decoded_addr *res)
}
res->socket = (int)adxl_values[component_indices[INDEX_SOCKET]];
- res->imc = (int)adxl_values[component_indices[INDEX_MEMCTRL]];
- res->channel = (int)adxl_values[component_indices[INDEX_CHANNEL]];
- res->dimm = (int)adxl_values[component_indices[INDEX_DIMM]];
+ if (error_in_1st_level_mem) {
+ res->imc = (adxl_nm_bitmap & BIT_NM_MEMCTRL) ?
+ (int)adxl_values[component_indices[INDEX_NM_MEMCTRL]] : -1;
+ res->channel = (adxl_nm_bitmap & BIT_NM_CHANNEL) ?
+ (int)adxl_values[component_indices[INDEX_NM_CHANNEL]] : -1;
+ res->dimm = (adxl_nm_bitmap & BIT_NM_DIMM) ?
+ (int)adxl_values[component_indices[INDEX_NM_DIMM]] : -1;
+ } else {
+ res->imc = (int)adxl_values[component_indices[INDEX_MEMCTRL]];
+ res->channel = (int)adxl_values[component_indices[INDEX_CHANNEL]];
+ res->dimm = (int)adxl_values[component_indices[INDEX_DIMM]];
+ }
- if (res->imc > NUM_IMC - 1) {
+ if (res->imc > NUM_IMC - 1 || res->imc < 0) {
skx_printk(KERN_ERR, "Bad imc %d\n", res->imc);
return false;
}
@@ -151,6 +176,11 @@ static bool skx_adxl_decode(struct decoded_addr *res)
return true;
}
+void skx_set_mem_cfg(bool mem_cfg_2lm)
+{
+ skx_mem_cfg_2lm = mem_cfg_2lm;
+}
+
void skx_set_decode(skx_decode_f decode, skx_show_retry_log_f show_retry_log)
{
skx_decode = decode;
@@ -313,9 +343,9 @@ int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm,
ranks = numrank(mtr);
rows = numrow(mtr);
- cols = numcol(mtr);
+ cols = imc->hbm_mc ? 6 : numcol(mtr);
- if (cfg->support_ddr5 && (amap & 0x8)) {
+ if (cfg->support_ddr5 && ((amap & 0x8) || imc->hbm_mc)) {
banks = 32;
mtype = MEM_DDR5;
} else {
@@ -344,8 +374,13 @@ int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm,
dimm->dtype = get_width(mtr);
dimm->mtype = mtype;
dimm->edac_mode = EDAC_SECDED; /* likely better than this */
- snprintf(dimm->label, sizeof(dimm->label), "CPU_SrcID#%u_MC#%u_Chan#%u_DIMM#%u",
- imc->src_id, imc->lmc, chan, dimmno);
+
+ if (imc->hbm_mc)
+ snprintf(dimm->label, sizeof(dimm->label), "CPU_SrcID#%u_HBMC#%u_Chan#%u",
+ imc->src_id, imc->lmc, chan);
+ else
+ snprintf(dimm->label, sizeof(dimm->label), "CPU_SrcID#%u_MC#%u_Chan#%u_DIMM#%u",
+ imc->src_id, imc->lmc, chan, dimmno);
return 1;
}
@@ -578,6 +613,21 @@ static void skx_mce_output_error(struct mem_ctl_info *mci,
optype, skx_msg);
}
+static bool skx_error_in_1st_level_mem(const struct mce *m)
+{
+ u32 errcode;
+
+ if (!skx_mem_cfg_2lm)
+ return false;
+
+ errcode = GET_BITFIELD(m->status, 0, 15);
+
+ if ((errcode & 0xef80) != 0x280)
+ return false;
+
+ return true;
+}
+
int skx_mce_check_error(struct notifier_block *nb, unsigned long val,
void *data)
{
@@ -597,7 +647,7 @@ int skx_mce_check_error(struct notifier_block *nb, unsigned long val,
res.addr = mce->addr;
if (adxl_component_count) {
- if (!skx_adxl_decode(&res))
+ if (!skx_adxl_decode(&res, skx_error_in_1st_level_mem(mce)))
return NOTIFY_DONE;
} else if (!skx_decode || !skx_decode(&res)) {
return NOTIFY_DONE;
@@ -658,6 +708,8 @@ void skx_remove(void)
}
if (d->util_all)
pci_dev_put(d->util_all);
+ if (d->pcu_cr3)
+ pci_dev_put(d->pcu_cr3);
if (d->sad_all)
pci_dev_put(d->sad_all);
if (d->uracu)
diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h
index bf56bebff138..01f67e731766 100644
--- a/drivers/edac/skx_common.h
+++ b/drivers/edac/skx_common.h
@@ -9,6 +9,8 @@
#ifndef _SKX_COMM_EDAC_H
#define _SKX_COMM_EDAC_H
+#include <linux/bits.h>
+
#define MSG_SIZE 1024
/*
@@ -30,9 +32,17 @@
#define SKX_NUM_CHANNELS 3 /* Channels per memory controller */
#define SKX_NUM_DIMMS 2 /* Max DIMMS per channel */
-#define I10NM_NUM_IMC 4
-#define I10NM_NUM_CHANNELS 2
-#define I10NM_NUM_DIMMS 2
+#define I10NM_NUM_DDR_IMC 4
+#define I10NM_NUM_DDR_CHANNELS 2
+#define I10NM_NUM_DDR_DIMMS 2
+
+#define I10NM_NUM_HBM_IMC 16
+#define I10NM_NUM_HBM_CHANNELS 2
+#define I10NM_NUM_HBM_DIMMS 1
+
+#define I10NM_NUM_IMC (I10NM_NUM_DDR_IMC + I10NM_NUM_HBM_IMC)
+#define I10NM_NUM_CHANNELS MAX(I10NM_NUM_DDR_CHANNELS, I10NM_NUM_HBM_CHANNELS)
+#define I10NM_NUM_DIMMS MAX(I10NM_NUM_DDR_DIMMS, I10NM_NUM_HBM_DIMMS)
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define NUM_IMC MAX(SKX_NUM_IMC, I10NM_NUM_IMC)
@@ -54,12 +64,16 @@ struct skx_dev {
struct pci_dev *sad_all;
struct pci_dev *util_all;
struct pci_dev *uracu; /* for i10nm CPU */
+ struct pci_dev *pcu_cr3; /* for HBM memory detection */
u32 mcroute;
struct skx_imc {
struct mem_ctl_info *mci;
struct pci_dev *mdev; /* for i10nm CPU */
void __iomem *mbase; /* for i10nm CPU */
int chan_mmio_sz; /* for i10nm CPU */
+ int num_channels; /* channels per memory controller */
+ int num_dimms; /* dimms per channel */
+ bool hbm_mc;
u8 mc; /* system wide mc# */
u8 lmc; /* socket relative mc# */
u8 src_id, node_id;
@@ -92,9 +106,17 @@ enum {
INDEX_MEMCTRL,
INDEX_CHANNEL,
INDEX_DIMM,
+ INDEX_NM_FIRST,
+ INDEX_NM_MEMCTRL = INDEX_NM_FIRST,
+ INDEX_NM_CHANNEL,
+ INDEX_NM_DIMM,
INDEX_MAX
};
+#define BIT_NM_MEMCTRL BIT_ULL(INDEX_NM_MEMCTRL)
+#define BIT_NM_CHANNEL BIT_ULL(INDEX_NM_CHANNEL)
+#define BIT_NM_DIMM BIT_ULL(INDEX_NM_DIMM)
+
struct decoded_addr {
struct skx_dev *dev;
u64 addr;
@@ -122,7 +144,12 @@ struct res_config {
int busno_cfg_offset;
/* Per DDR channel memory-mapped I/O size */
int ddr_chan_mmio_sz;
+ /* Per HBM channel memory-mapped I/O size */
+ int hbm_chan_mmio_sz;
bool support_ddr5;
+ /* SAD device number and function number */
+ unsigned int sad_all_devfn;
+ int sad_all_offset;
};
typedef int (*get_dimm_config_f)(struct mem_ctl_info *mci,
@@ -133,6 +160,7 @@ typedef void (*skx_show_retry_log_f)(struct decoded_addr *res, char *msg, int le
int __init skx_adxl_get(void);
void __exit skx_adxl_put(void);
void skx_set_decode(skx_decode_f decode, skx_show_retry_log_f show_retry_log);
+void skx_set_mem_cfg(bool mem_cfg_2lm);
int skx_get_src_id(struct skx_dev *d, int off, u8 *id);
int skx_get_node_id(struct skx_dev *d, u8 *id);
diff --git a/drivers/edac/thunderx_edac.c b/drivers/edac/thunderx_edac.c
index 0eb5eb97fd74..f13674081cb6 100644
--- a/drivers/edac/thunderx_edac.c
+++ b/drivers/edac/thunderx_edac.c
@@ -1368,7 +1368,7 @@ static int thunderx_ocx_probe(struct pci_dev *pdev,
name, 1, "CCPI", 1,
0, NULL, 0, idx);
if (!edac_dev) {
- dev_err(&pdev->dev, "Cannot allocate EDAC device: %d\n", ret);
+ dev_err(&pdev->dev, "Cannot allocate EDAC device\n");
return -ENOMEM;
}
ocx = edac_dev->pvt_info;
@@ -1380,7 +1380,7 @@ static int thunderx_ocx_probe(struct pci_dev *pdev,
ocx->regs = pcim_iomap_table(pdev)[0];
if (!ocx->regs) {
- dev_err(&pdev->dev, "Cannot map PCI resources: %d\n", ret);
+ dev_err(&pdev->dev, "Cannot map PCI resources\n");
ret = -ENODEV;
goto err_free;
}
diff --git a/drivers/edac/ti_edac.c b/drivers/edac/ti_edac.c
index e7eae20f83d1..169f96e51c29 100644
--- a/drivers/edac/ti_edac.c
+++ b/drivers/edac/ti_edac.c
@@ -197,6 +197,7 @@ static const struct of_device_id ti_edac_of_match[] = {
{ .compatible = "ti,emif-dra7xx", .data = (void *)EMIF_TYPE_DRA7 },
{},
};
+MODULE_DEVICE_TABLE(of, ti_edac_of_match);
static int _emif_get_id(struct device_node *node)
{
diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
index d9a16ba2ccc2..65bffde137e3 100644
--- a/drivers/eisa/eisa-bus.c
+++ b/drivers/eisa/eisa-bus.c
@@ -155,34 +155,29 @@ void eisa_driver_unregister(struct eisa_driver *edrv)
}
EXPORT_SYMBOL(eisa_driver_unregister);
-static ssize_t eisa_show_sig(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t signature_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct eisa_device *edev = to_eisa_device(dev);
return sprintf(buf, "%s\n", edev->id.sig);
}
+static DEVICE_ATTR_RO(signature);
-static DEVICE_ATTR(signature, S_IRUGO, eisa_show_sig, NULL);
-
-static ssize_t eisa_show_state(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t enabled_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct eisa_device *edev = to_eisa_device(dev);
return sprintf(buf, "%d\n", edev->state & EISA_CONFIG_ENABLED);
}
+static DEVICE_ATTR_RO(enabled);
-static DEVICE_ATTR(enabled, S_IRUGO, eisa_show_state, NULL);
-
-static ssize_t eisa_show_modalias(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t modalias_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct eisa_device *edev = to_eisa_device(dev);
return sprintf(buf, EISA_DEVICE_MODALIAS_FMT "\n", edev->id.sig);
}
-
-static DEVICE_ATTR(modalias, S_IRUGO, eisa_show_modalias, NULL);
+static DEVICE_ATTR_RO(modalias);
static int __init eisa_init_device(struct eisa_root_device *root,
struct eisa_device *edev,
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index e3db936becfd..c69d40ae5619 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -154,7 +154,7 @@ config EXTCON_RT8973A
from abnormal high input voltage (up to 28V).
config EXTCON_SM5502
- tristate "Silicon Mitus SM5502 EXTCON support"
+ tristate "Silicon Mitus SM5502/SM5504 EXTCON support"
depends on I2C
select IRQ_DOMAIN
select REGMAP_I2C
diff --git a/drivers/extcon/extcon-intel-mrfld.c b/drivers/extcon/extcon-intel-mrfld.c
index f47016fb28a8..cd1a5f230077 100644
--- a/drivers/extcon/extcon-intel-mrfld.c
+++ b/drivers/extcon/extcon-intel-mrfld.c
@@ -197,6 +197,7 @@ static int mrfld_extcon_probe(struct platform_device *pdev)
struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent);
struct regmap *regmap = pmic->regmap;
struct mrfld_extcon_data *data;
+ unsigned int status;
unsigned int id;
int irq, ret;
@@ -244,6 +245,14 @@ static int mrfld_extcon_probe(struct platform_device *pdev)
/* Get initial state */
mrfld_extcon_role_detect(data);
+ /*
+ * Cached status value is used for cable detection, see comments
+ * in mrfld_extcon_cable_detect(), we need to sync cached value
+ * with a real state of the hardware.
+ */
+ regmap_read(regmap, BCOVE_SCHGRIRQ1, &status);
+ data->status = status;
+
mrfld_extcon_clear(data, BCOVE_MIRQLVL1, BCOVE_LVL1_CHGR);
mrfld_extcon_clear(data, BCOVE_MCHGRIRQ1, BCOVE_CHGRIRQ_ALL);
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index ace523924e58..5476f48ed74b 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -6,6 +6,7 @@
// Chanwoo Choi <cw00.choi@samsung.com>
// Krzysztof Kozlowski <krzk@kernel.org>
+#include <linux/devm-helpers.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
@@ -673,7 +674,10 @@ static int max14577_muic_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);
mutex_init(&info->mutex);
- INIT_WORK(&info->irq_work, max14577_muic_irq_work);
+ ret = devm_work_autocancel(&pdev->dev, &info->irq_work,
+ max14577_muic_irq_work);
+ if (ret)
+ return ret;
switch (max14577->dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
@@ -766,15 +770,6 @@ static int max14577_muic_probe(struct platform_device *pdev)
return ret;
}
-static int max14577_muic_remove(struct platform_device *pdev)
-{
- struct max14577_muic_info *info = platform_get_drvdata(pdev);
-
- cancel_work_sync(&info->irq_work);
-
- return 0;
-}
-
static const struct platform_device_id max14577_muic_id[] = {
{ "max14577-muic", MAXIM_DEVICE_TYPE_MAX14577, },
{ "max77836-muic", MAXIM_DEVICE_TYPE_MAX77836, },
@@ -797,7 +792,6 @@ static struct platform_driver max14577_muic_driver = {
.of_match_table = of_max14577_muic_dt_match,
},
.probe = max14577_muic_probe,
- .remove = max14577_muic_remove,
.id_table = max14577_muic_id,
};
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 92af97e00828..1f1d9ab0c5c7 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -5,6 +5,7 @@
// Copyright (C) 2012 Samsung Electrnoics
// Chanwoo Choi <cw00.choi@samsung.com>
+#include <linux/devm-helpers.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
@@ -1127,7 +1128,10 @@ static int max77693_muic_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);
mutex_init(&info->mutex);
- INIT_WORK(&info->irq_work, max77693_muic_irq_work);
+ ret = devm_work_autocancel(&pdev->dev, &info->irq_work,
+ max77693_muic_irq_work);
+ if (ret)
+ return ret;
/* Support irq domain for MAX77693 MUIC device */
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
@@ -1254,22 +1258,11 @@ static int max77693_muic_probe(struct platform_device *pdev)
return ret;
}
-static int max77693_muic_remove(struct platform_device *pdev)
-{
- struct max77693_muic_info *info = platform_get_drvdata(pdev);
-
- cancel_work_sync(&info->irq_work);
- input_unregister_device(info->dock);
-
- return 0;
-}
-
static struct platform_driver max77693_muic_driver = {
.driver = {
.name = DEV_NAME,
},
.probe = max77693_muic_probe,
- .remove = max77693_muic_remove,
};
module_platform_driver(max77693_muic_driver);
diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c
index e1408075ef7d..9cddf08e0696 100644
--- a/drivers/extcon/extcon-max8997.c
+++ b/drivers/extcon/extcon-max8997.c
@@ -5,6 +5,7 @@
// Copyright (C) 2012 Samsung Electronics
// Donggeun Kim <dg77.kim@samsung.com>
+#include <linux/devm-helpers.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
@@ -650,27 +651,30 @@ static int max8997_muic_probe(struct platform_device *pdev)
mutex_init(&info->mutex);
INIT_WORK(&info->irq_work, max8997_muic_irq_work);
+ ret = devm_work_autocancel(&pdev->dev, &info->irq_work,
+ max8997_muic_irq_work);
+ if (ret)
+ return ret;
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
struct max8997_muic_irq *muic_irq = &muic_irqs[i];
unsigned int virq = 0;
virq = irq_create_mapping(max8997->irq_domain, muic_irq->irq);
- if (!virq) {
- ret = -EINVAL;
- goto err_irq;
- }
+ if (!virq)
+ return -EINVAL;
+
muic_irq->virq = virq;
- ret = request_threaded_irq(virq, NULL,
- max8997_muic_irq_handler,
- IRQF_NO_SUSPEND,
- muic_irq->name, info);
+ ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
+ max8997_muic_irq_handler,
+ IRQF_NO_SUSPEND,
+ muic_irq->name, info);
if (ret) {
dev_err(&pdev->dev,
"failed: irq request (IRQ: %d, error :%d)\n",
muic_irq->irq, ret);
- goto err_irq;
+ return ret;
}
}
@@ -678,14 +682,13 @@ static int max8997_muic_probe(struct platform_device *pdev)
info->edev = devm_extcon_dev_allocate(&pdev->dev, max8997_extcon_cable);
if (IS_ERR(info->edev)) {
dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
- ret = PTR_ERR(info->edev);
- goto err_irq;
+ return PTR_ERR(info->edev);
}
ret = devm_extcon_dev_register(&pdev->dev, info->edev);
if (ret) {
dev_err(&pdev->dev, "failed to register extcon device\n");
- goto err_irq;
+ return ret;
}
if (pdata && pdata->muic_pdata) {
@@ -756,23 +759,6 @@ static int max8997_muic_probe(struct platform_device *pdev)
delay_jiffies);
return 0;
-
-err_irq:
- while (--i >= 0)
- free_irq(muic_irqs[i].virq, info);
- return ret;
-}
-
-static int max8997_muic_remove(struct platform_device *pdev)
-{
- struct max8997_muic_info *info = platform_get_drvdata(pdev);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
- free_irq(muic_irqs[i].virq, info);
- cancel_work_sync(&info->irq_work);
-
- return 0;
}
static struct platform_driver max8997_muic_driver = {
@@ -780,7 +766,6 @@ static struct platform_driver max8997_muic_driver = {
.name = DEV_NAME,
},
.probe = max8997_muic_probe,
- .remove = max8997_muic_remove,
};
module_platform_driver(max8997_muic_driver);
@@ -788,3 +773,4 @@ module_platform_driver(max8997_muic_driver);
MODULE_DESCRIPTION("Maxim MAX8997 Extcon driver");
MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:max8997-muic");
diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c
index db41d1c58efd..93da2d8379b1 100644
--- a/drivers/extcon/extcon-sm5502.c
+++ b/drivers/extcon/extcon-sm5502.c
@@ -40,17 +40,13 @@ struct sm5502_muic_info {
struct i2c_client *i2c;
struct regmap *regmap;
+ const struct sm5502_type *type;
struct regmap_irq_chip_data *irq_data;
- struct muic_irq *muic_irqs;
- unsigned int num_muic_irqs;
int irq;
bool irq_attach;
bool irq_detach;
struct work_struct irq_work;
- struct reg_data *reg_data;
- unsigned int num_reg_data;
-
struct mutex mutex;
/*
@@ -62,6 +58,18 @@ struct sm5502_muic_info {
struct delayed_work wq_detcable;
};
+struct sm5502_type {
+ struct muic_irq *muic_irqs;
+ unsigned int num_muic_irqs;
+ const struct regmap_irq_chip *irq_chip;
+
+ struct reg_data *reg_data;
+ unsigned int num_reg_data;
+
+ unsigned int otg_dev_type1;
+ int (*parse_irq)(struct sm5502_muic_info *info, int irq_type);
+};
+
/* Default value of SM5502 register to bring up MUIC device. */
static struct reg_data sm5502_reg_data[] = {
{
@@ -88,7 +96,33 @@ static struct reg_data sm5502_reg_data[] = {
| SM5502_REG_INTM2_MHL_MASK,
.invert = true,
},
- { }
+};
+
+/* Default value of SM5504 register to bring up MUIC device. */
+static struct reg_data sm5504_reg_data[] = {
+ {
+ .reg = SM5502_REG_RESET,
+ .val = SM5502_REG_RESET_MASK,
+ .invert = true,
+ }, {
+ .reg = SM5502_REG_INTMASK1,
+ .val = SM5504_REG_INTM1_ATTACH_MASK
+ | SM5504_REG_INTM1_DETACH_MASK,
+ .invert = false,
+ }, {
+ .reg = SM5502_REG_INTMASK2,
+ .val = SM5504_REG_INTM2_RID_CHG_MASK
+ | SM5504_REG_INTM2_UVLO_MASK
+ | SM5504_REG_INTM2_POR_MASK,
+ .invert = true,
+ }, {
+ .reg = SM5502_REG_CONTROL,
+ .val = SM5502_REG_CONTROL_MANUAL_SW_MASK
+ | SM5504_REG_CONTROL_CHGTYP_MASK
+ | SM5504_REG_CONTROL_USBCHDEN_MASK
+ | SM5504_REG_CONTROL_ADC_EN_MASK,
+ .invert = true,
+ },
};
/* List of detectable cables */
@@ -199,6 +233,55 @@ static const struct regmap_irq_chip sm5502_muic_irq_chip = {
.num_irqs = ARRAY_SIZE(sm5502_irqs),
};
+/* List of supported interrupt for SM5504 */
+static struct muic_irq sm5504_muic_irqs[] = {
+ { SM5504_IRQ_INT1_ATTACH, "muic-attach" },
+ { SM5504_IRQ_INT1_DETACH, "muic-detach" },
+ { SM5504_IRQ_INT1_CHG_DET, "muic-chg-det" },
+ { SM5504_IRQ_INT1_DCD_OUT, "muic-dcd-out" },
+ { SM5504_IRQ_INT1_OVP_EVENT, "muic-ovp-event" },
+ { SM5504_IRQ_INT1_CONNECT, "muic-connect" },
+ { SM5504_IRQ_INT1_ADC_CHG, "muic-adc-chg" },
+ { SM5504_IRQ_INT2_RID_CHG, "muic-rid-chg" },
+ { SM5504_IRQ_INT2_UVLO, "muic-uvlo" },
+ { SM5504_IRQ_INT2_POR, "muic-por" },
+ { SM5504_IRQ_INT2_OVP_FET, "muic-ovp-fet" },
+ { SM5504_IRQ_INT2_OCP_LATCH, "muic-ocp-latch" },
+ { SM5504_IRQ_INT2_OCP_EVENT, "muic-ocp-event" },
+ { SM5504_IRQ_INT2_OVP_OCP_EVENT, "muic-ovp-ocp-event" },
+};
+
+/* Define interrupt list of SM5504 to register regmap_irq */
+static const struct regmap_irq sm5504_irqs[] = {
+ /* INT1 interrupts */
+ { .reg_offset = 0, .mask = SM5504_IRQ_INT1_ATTACH_MASK, },
+ { .reg_offset = 0, .mask = SM5504_IRQ_INT1_DETACH_MASK, },
+ { .reg_offset = 0, .mask = SM5504_IRQ_INT1_CHG_DET_MASK, },
+ { .reg_offset = 0, .mask = SM5504_IRQ_INT1_DCD_OUT_MASK, },
+ { .reg_offset = 0, .mask = SM5504_IRQ_INT1_OVP_MASK, },
+ { .reg_offset = 0, .mask = SM5504_IRQ_INT1_CONNECT_MASK, },
+ { .reg_offset = 0, .mask = SM5504_IRQ_INT1_ADC_CHG_MASK, },
+
+ /* INT2 interrupts */
+ { .reg_offset = 1, .mask = SM5504_IRQ_INT2_RID_CHG_MASK,},
+ { .reg_offset = 1, .mask = SM5504_IRQ_INT2_UVLO_MASK, },
+ { .reg_offset = 1, .mask = SM5504_IRQ_INT2_POR_MASK, },
+ { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OVP_FET_MASK, },
+ { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OCP_LATCH_MASK, },
+ { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OCP_EVENT_MASK, },
+ { .reg_offset = 1, .mask = SM5504_IRQ_INT2_OVP_OCP_EVENT_MASK, },
+};
+
+static const struct regmap_irq_chip sm5504_muic_irq_chip = {
+ .name = "sm5504",
+ .status_base = SM5502_REG_INT1,
+ .mask_base = SM5502_REG_INTMASK1,
+ .mask_invert = false,
+ .num_regs = 2,
+ .irqs = sm5504_irqs,
+ .num_irqs = ARRAY_SIZE(sm5504_irqs),
+};
+
/* Define regmap configuration of SM5502 for I2C communication */
static bool sm5502_muic_volatile_reg(struct device *dev, unsigned int reg)
{
@@ -302,11 +385,9 @@ static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info)
return ret;
}
- switch (dev_type1) {
- case SM5502_REG_DEV_TYPE1_USB_OTG_MASK:
+ if (dev_type1 == info->type->otg_dev_type1) {
cable_type = SM5502_MUIC_ADC_GROUND_USB_OTG;
- break;
- default:
+ } else {
dev_dbg(info->dev,
"cannot identify the cable type: adc(0x%x), dev_type1(0x%x)\n",
adc, dev_type1);
@@ -359,6 +440,11 @@ static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info)
return ret;
}
+ if (dev_type1 == info->type->otg_dev_type1) {
+ cable_type = SM5502_MUIC_ADC_OPEN_USB_OTG;
+ break;
+ }
+
switch (dev_type1) {
case SM5502_REG_DEV_TYPE1_USB_SDP_MASK:
cable_type = SM5502_MUIC_ADC_OPEN_USB;
@@ -366,9 +452,6 @@ static unsigned int sm5502_muic_get_cable_type(struct sm5502_muic_info *info)
case SM5502_REG_DEV_TYPE1_DEDICATED_CHG_MASK:
cable_type = SM5502_MUIC_ADC_OPEN_TA;
break;
- case SM5502_REG_DEV_TYPE1_USB_OTG_MASK:
- cable_type = SM5502_MUIC_ADC_OPEN_USB_OTG;
- break;
default:
dev_dbg(info->dev,
"cannot identify the cable type: adc(0x%x)\n",
@@ -498,16 +581,44 @@ static int sm5502_parse_irq(struct sm5502_muic_info *info, int irq_type)
return 0;
}
+static int sm5504_parse_irq(struct sm5502_muic_info *info, int irq_type)
+{
+ switch (irq_type) {
+ case SM5504_IRQ_INT1_ATTACH:
+ info->irq_attach = true;
+ break;
+ case SM5504_IRQ_INT1_DETACH:
+ info->irq_detach = true;
+ break;
+ case SM5504_IRQ_INT1_CHG_DET:
+ case SM5504_IRQ_INT1_DCD_OUT:
+ case SM5504_IRQ_INT1_OVP_EVENT:
+ case SM5504_IRQ_INT1_CONNECT:
+ case SM5504_IRQ_INT1_ADC_CHG:
+ case SM5504_IRQ_INT2_RID_CHG:
+ case SM5504_IRQ_INT2_UVLO:
+ case SM5504_IRQ_INT2_POR:
+ case SM5504_IRQ_INT2_OVP_FET:
+ case SM5504_IRQ_INT2_OCP_LATCH:
+ case SM5504_IRQ_INT2_OCP_EVENT:
+ case SM5504_IRQ_INT2_OVP_OCP_EVENT:
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static irqreturn_t sm5502_muic_irq_handler(int irq, void *data)
{
struct sm5502_muic_info *info = data;
int i, irq_type = -1, ret;
- for (i = 0; i < info->num_muic_irqs; i++)
- if (irq == info->muic_irqs[i].virq)
- irq_type = info->muic_irqs[i].irq;
+ for (i = 0; i < info->type->num_muic_irqs; i++)
+ if (irq == info->type->muic_irqs[i].virq)
+ irq_type = info->type->muic_irqs[i].irq;
- ret = sm5502_parse_irq(info, irq_type);
+ ret = info->type->parse_irq(info, irq_type);
if (ret < 0) {
dev_warn(info->dev, "cannot handle is interrupt:%d\n",
irq_type);
@@ -552,19 +663,18 @@ static void sm5502_init_dev_type(struct sm5502_muic_info *info)
version_id, vendor_id);
/* Initiazle the register of SM5502 device to bring-up */
- for (i = 0; i < info->num_reg_data; i++) {
+ for (i = 0; i < info->type->num_reg_data; i++) {
unsigned int val = 0;
- if (!info->reg_data[i].invert)
- val |= ~info->reg_data[i].val;
+ if (!info->type->reg_data[i].invert)
+ val |= ~info->type->reg_data[i].val;
else
- val = info->reg_data[i].val;
- regmap_write(info->regmap, info->reg_data[i].reg, val);
+ val = info->type->reg_data[i].val;
+ regmap_write(info->regmap, info->type->reg_data[i].reg, val);
}
}
-static int sm5022_muic_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int sm5022_muic_i2c_probe(struct i2c_client *i2c)
{
struct device_node *np = i2c->dev.of_node;
struct sm5502_muic_info *info;
@@ -581,10 +691,13 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c,
info->dev = &i2c->dev;
info->i2c = i2c;
info->irq = i2c->irq;
- info->muic_irqs = sm5502_muic_irqs;
- info->num_muic_irqs = ARRAY_SIZE(sm5502_muic_irqs);
- info->reg_data = sm5502_reg_data;
- info->num_reg_data = ARRAY_SIZE(sm5502_reg_data);
+ info->type = device_get_match_data(info->dev);
+ if (!info->type)
+ return -EINVAL;
+ if (!info->type->parse_irq) {
+ dev_err(info->dev, "parse_irq missing in struct sm5502_type\n");
+ return -EINVAL;
+ }
mutex_init(&info->mutex);
@@ -600,16 +713,17 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c,
/* Support irq domain for SM5502 MUIC device */
irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED;
- ret = regmap_add_irq_chip(info->regmap, info->irq, irq_flags, 0,
- &sm5502_muic_irq_chip, &info->irq_data);
+ ret = devm_regmap_add_irq_chip(info->dev, info->regmap, info->irq,
+ irq_flags, 0, info->type->irq_chip,
+ &info->irq_data);
if (ret != 0) {
dev_err(info->dev, "failed to request IRQ %d: %d\n",
info->irq, ret);
return ret;
}
- for (i = 0; i < info->num_muic_irqs; i++) {
- struct muic_irq *muic_irq = &info->muic_irqs[i];
+ for (i = 0; i < info->type->num_muic_irqs; i++) {
+ struct muic_irq *muic_irq = &info->type->muic_irqs[i];
int virq = 0;
virq = regmap_irq_get_virq(info->irq_data, muic_irq->irq);
@@ -661,17 +775,29 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c,
return 0;
}
-static int sm5502_muic_i2c_remove(struct i2c_client *i2c)
-{
- struct sm5502_muic_info *info = i2c_get_clientdata(i2c);
-
- regmap_del_irq_chip(info->irq, info->irq_data);
+static const struct sm5502_type sm5502_data = {
+ .muic_irqs = sm5502_muic_irqs,
+ .num_muic_irqs = ARRAY_SIZE(sm5502_muic_irqs),
+ .irq_chip = &sm5502_muic_irq_chip,
+ .reg_data = sm5502_reg_data,
+ .num_reg_data = ARRAY_SIZE(sm5502_reg_data),
+ .otg_dev_type1 = SM5502_REG_DEV_TYPE1_USB_OTG_MASK,
+ .parse_irq = sm5502_parse_irq,
+};
- return 0;
-}
+static const struct sm5502_type sm5504_data = {
+ .muic_irqs = sm5504_muic_irqs,
+ .num_muic_irqs = ARRAY_SIZE(sm5504_muic_irqs),
+ .irq_chip = &sm5504_muic_irq_chip,
+ .reg_data = sm5504_reg_data,
+ .num_reg_data = ARRAY_SIZE(sm5504_reg_data),
+ .otg_dev_type1 = SM5504_REG_DEV_TYPE1_USB_OTG_MASK,
+ .parse_irq = sm5504_parse_irq,
+};
static const struct of_device_id sm5502_dt_match[] = {
- { .compatible = "siliconmitus,sm5502-muic" },
+ { .compatible = "siliconmitus,sm5502-muic", .data = &sm5502_data },
+ { .compatible = "siliconmitus,sm5504-muic", .data = &sm5504_data },
{ },
};
MODULE_DEVICE_TABLE(of, sm5502_dt_match);
@@ -702,7 +828,8 @@ static SIMPLE_DEV_PM_OPS(sm5502_muic_pm_ops,
sm5502_muic_suspend, sm5502_muic_resume);
static const struct i2c_device_id sm5502_i2c_id[] = {
- { "sm5502", TYPE_SM5502 },
+ { "sm5502", (kernel_ulong_t)&sm5502_data },
+ { "sm5504", (kernel_ulong_t)&sm5504_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, sm5502_i2c_id);
@@ -713,8 +840,7 @@ static struct i2c_driver sm5502_muic_i2c_driver = {
.pm = &sm5502_muic_pm_ops,
.of_match_table = sm5502_dt_match,
},
- .probe = sm5022_muic_i2c_probe,
- .remove = sm5502_muic_i2c_remove,
+ .probe_new = sm5022_muic_i2c_probe,
.id_table = sm5502_i2c_id,
};
diff --git a/drivers/extcon/extcon-sm5502.h b/drivers/extcon/extcon-sm5502.h
index ce1f1ec310c4..9c04315d48e2 100644
--- a/drivers/extcon/extcon-sm5502.h
+++ b/drivers/extcon/extcon-sm5502.h
@@ -8,10 +8,6 @@
#ifndef __LINUX_EXTCON_SM5502_H
#define __LINUX_EXTCON_SM5502_H
-enum sm5502_types {
- TYPE_SM5502,
-};
-
/* SM5502 registers */
enum sm5502_reg {
SM5502_REG_DEVICE_ID = 0x01,
@@ -93,6 +89,13 @@ enum sm5502_reg {
#define SM5502_REG_CONTROL_RAW_DATA_MASK (0x1 << SM5502_REG_CONTROL_RAW_DATA_SHIFT)
#define SM5502_REG_CONTROL_SW_OPEN_MASK (0x1 << SM5502_REG_CONTROL_SW_OPEN_SHIFT)
+#define SM5504_REG_CONTROL_CHGTYP_SHIFT 5
+#define SM5504_REG_CONTROL_USBCHDEN_SHIFT 6
+#define SM5504_REG_CONTROL_ADC_EN_SHIFT 7
+#define SM5504_REG_CONTROL_CHGTYP_MASK (0x1 << SM5504_REG_CONTROL_CHGTYP_SHIFT)
+#define SM5504_REG_CONTROL_USBCHDEN_MASK (0x1 << SM5504_REG_CONTROL_USBCHDEN_SHIFT)
+#define SM5504_REG_CONTROL_ADC_EN_MASK (0x1 << SM5504_REG_CONTROL_ADC_EN_SHIFT)
+
#define SM5502_REG_INTM1_ATTACH_SHIFT 0
#define SM5502_REG_INTM1_DETACH_SHIFT 1
#define SM5502_REG_INTM1_KP_SHIFT 2
@@ -123,6 +126,36 @@ enum sm5502_reg {
#define SM5502_REG_INTM2_STUCK_KEY_RCV_MASK (0x1 << SM5502_REG_INTM2_STUCK_KEY_RCV_SHIFT)
#define SM5502_REG_INTM2_MHL_MASK (0x1 << SM5502_REG_INTM2_MHL_SHIFT)
+#define SM5504_REG_INTM1_ATTACH_SHIFT 0
+#define SM5504_REG_INTM1_DETACH_SHIFT 1
+#define SM5504_REG_INTM1_CHG_DET_SHIFT 2
+#define SM5504_REG_INTM1_DCD_OUT_SHIFT 3
+#define SM5504_REG_INTM1_OVP_EVENT_SHIFT 4
+#define SM5504_REG_INTM1_CONNECT_SHIFT 5
+#define SM5504_REG_INTM1_ADC_CHG_SHIFT 6
+#define SM5504_REG_INTM1_ATTACH_MASK (0x1 << SM5504_REG_INTM1_ATTACH_SHIFT)
+#define SM5504_REG_INTM1_DETACH_MASK (0x1 << SM5504_REG_INTM1_DETACH_SHIFT)
+#define SM5504_REG_INTM1_CHG_DET_MASK (0x1 << SM5504_REG_INTM1_CHG_DET_SHIFT)
+#define SM5504_REG_INTM1_DCD_OUT_MASK (0x1 << SM5504_REG_INTM1_DCD_OUT_SHIFT)
+#define SM5504_REG_INTM1_OVP_EVENT_MASK (0x1 << SM5504_REG_INTM1_OVP_EVENT_SHIFT)
+#define SM5504_REG_INTM1_CONNECT_MASK (0x1 << SM5504_REG_INTM1_CONNECT_SHIFT)
+#define SM5504_REG_INTM1_ADC_CHG_MASK (0x1 << SM5504_REG_INTM1_ADC_CHG_SHIFT)
+
+#define SM5504_REG_INTM2_RID_CHG_SHIFT 0
+#define SM5504_REG_INTM2_UVLO_SHIFT 1
+#define SM5504_REG_INTM2_POR_SHIFT 2
+#define SM5504_REG_INTM2_OVP_FET_SHIFT 4
+#define SM5504_REG_INTM2_OCP_LATCH_SHIFT 5
+#define SM5504_REG_INTM2_OCP_EVENT_SHIFT 6
+#define SM5504_REG_INTM2_OVP_OCP_EVENT_SHIFT 7
+#define SM5504_REG_INTM2_RID_CHG_MASK (0x1 << SM5504_REG_INTM2_RID_CHG_SHIFT)
+#define SM5504_REG_INTM2_UVLO_MASK (0x1 << SM5504_REG_INTM2_UVLO_SHIFT)
+#define SM5504_REG_INTM2_POR_MASK (0x1 << SM5504_REG_INTM2_POR_SHIFT)
+#define SM5504_REG_INTM2_OVP_FET_MASK (0x1 << SM5504_REG_INTM2_OVP_FET_SHIFT)
+#define SM5504_REG_INTM2_OCP_LATCH_MASK (0x1 << SM5504_REG_INTM2_OCP_LATCH_SHIFT)
+#define SM5504_REG_INTM2_OCP_EVENT_MASK (0x1 << SM5504_REG_INTM2_OCP_EVENT_SHIFT)
+#define SM5504_REG_INTM2_OVP_OCP_EVENT_MASK (0x1 << SM5504_REG_INTM2_OVP_OCP_EVENT_SHIFT)
+
#define SM5502_REG_ADC_SHIFT 0
#define SM5502_REG_ADC_MASK (0x1f << SM5502_REG_ADC_SHIFT)
@@ -199,6 +232,9 @@ enum sm5502_reg {
#define SM5502_REG_DEV_TYPE1_DEDICATED_CHG_MASK (0x1 << SM5502_REG_DEV_TYPE1_DEDICATED_CHG_SHIFT)
#define SM5502_REG_DEV_TYPE1_USB_OTG_MASK (0x1 << SM5502_REG_DEV_TYPE1_USB_OTG_SHIFT)
+#define SM5504_REG_DEV_TYPE1_USB_OTG_SHIFT 0
+#define SM5504_REG_DEV_TYPE1_USB_OTG_MASK (0x1 << SM5504_REG_DEV_TYPE1_USB_OTG_SHIFT)
+
#define SM5502_REG_DEV_TYPE2_JIG_USB_ON_SHIFT 0
#define SM5502_REG_DEV_TYPE2_JIG_USB_OFF_SHIFT 1
#define SM5502_REG_DEV_TYPE2_JIG_UART_ON_SHIFT 2
@@ -277,4 +313,42 @@ enum sm5502_irq {
#define SM5502_IRQ_INT2_STUCK_KEY_RCV_MASK BIT(4)
#define SM5502_IRQ_INT2_MHL_MASK BIT(5)
+/* SM5504 Interrupts */
+enum sm5504_irq {
+ /* INT1 */
+ SM5504_IRQ_INT1_ATTACH,
+ SM5504_IRQ_INT1_DETACH,
+ SM5504_IRQ_INT1_CHG_DET,
+ SM5504_IRQ_INT1_DCD_OUT,
+ SM5504_IRQ_INT1_OVP_EVENT,
+ SM5504_IRQ_INT1_CONNECT,
+ SM5504_IRQ_INT1_ADC_CHG,
+
+ /* INT2 */
+ SM5504_IRQ_INT2_RID_CHG,
+ SM5504_IRQ_INT2_UVLO,
+ SM5504_IRQ_INT2_POR,
+ SM5504_IRQ_INT2_OVP_FET,
+ SM5504_IRQ_INT2_OCP_LATCH,
+ SM5504_IRQ_INT2_OCP_EVENT,
+ SM5504_IRQ_INT2_OVP_OCP_EVENT,
+
+ SM5504_IRQ_NUM,
+};
+
+#define SM5504_IRQ_INT1_ATTACH_MASK BIT(0)
+#define SM5504_IRQ_INT1_DETACH_MASK BIT(1)
+#define SM5504_IRQ_INT1_CHG_DET_MASK BIT(2)
+#define SM5504_IRQ_INT1_DCD_OUT_MASK BIT(3)
+#define SM5504_IRQ_INT1_OVP_MASK BIT(4)
+#define SM5504_IRQ_INT1_CONNECT_MASK BIT(5)
+#define SM5504_IRQ_INT1_ADC_CHG_MASK BIT(6)
+#define SM5504_IRQ_INT2_RID_CHG_MASK BIT(0)
+#define SM5504_IRQ_INT2_UVLO_MASK BIT(1)
+#define SM5504_IRQ_INT2_POR_MASK BIT(2)
+#define SM5504_IRQ_INT2_OVP_FET_MASK BIT(4)
+#define SM5504_IRQ_INT2_OCP_LATCH_MASK BIT(5)
+#define SM5504_IRQ_INT2_OCP_EVENT_MASK BIT(6)
+#define SM5504_IRQ_INT2_OVP_OCP_EVENT_MASK BIT(7)
+
#endif /* __LINUX_EXTCON_SM5502_H */
diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c
index ec68ed27b0a5..b63d55f5ebd3 100644
--- a/drivers/firewire/core-topology.c
+++ b/drivers/firewire/core-topology.c
@@ -58,6 +58,7 @@ static u32 *count_ports(u32 *sid, int *total_port_count, int *child_port_count)
case SELFID_PORT_PARENT:
case SELFID_PORT_NCONN:
(*total_port_count)++;
+ fallthrough;
case SELFID_PORT_NONE:
break;
}
diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c
index 88ed971e32c0..b0d671db178a 100644
--- a/drivers/firewire/nosy.c
+++ b/drivers/firewire/nosy.c
@@ -511,12 +511,12 @@ remove_card(struct pci_dev *dev)
wake_up_interruptible(&client->buffer.wait);
spin_unlock_irq(&lynx->client_list_lock);
- pci_free_consistent(lynx->pci_device, sizeof(struct pcl),
- lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus);
- pci_free_consistent(lynx->pci_device, sizeof(struct pcl),
- lynx->rcv_pcl, lynx->rcv_pcl_bus);
- pci_free_consistent(lynx->pci_device, PAGE_SIZE,
- lynx->rcv_buffer, lynx->rcv_buffer_bus);
+ dma_free_coherent(&lynx->pci_device->dev, sizeof(struct pcl),
+ lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus);
+ dma_free_coherent(&lynx->pci_device->dev, sizeof(struct pcl),
+ lynx->rcv_pcl, lynx->rcv_pcl_bus);
+ dma_free_coherent(&lynx->pci_device->dev, PAGE_SIZE, lynx->rcv_buffer,
+ lynx->rcv_buffer_bus);
iounmap(lynx->registers);
pci_disable_device(dev);
@@ -532,7 +532,7 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused)
u32 p, end;
int ret, i;
- if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) {
+ if (dma_set_mask(&dev->dev, DMA_BIT_MASK(32))) {
dev_err(&dev->dev,
"DMA address limits not supported for PCILynx hardware\n");
return -ENXIO;
@@ -564,12 +564,16 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused)
goto fail_deallocate_lynx;
}
- lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device,
- sizeof(struct pcl), &lynx->rcv_start_pcl_bus);
- lynx->rcv_pcl = pci_alloc_consistent(lynx->pci_device,
- sizeof(struct pcl), &lynx->rcv_pcl_bus);
- lynx->rcv_buffer = pci_alloc_consistent(lynx->pci_device,
- RCV_BUFFER_SIZE, &lynx->rcv_buffer_bus);
+ lynx->rcv_start_pcl = dma_alloc_coherent(&lynx->pci_device->dev,
+ sizeof(struct pcl),
+ &lynx->rcv_start_pcl_bus,
+ GFP_KERNEL);
+ lynx->rcv_pcl = dma_alloc_coherent(&lynx->pci_device->dev,
+ sizeof(struct pcl),
+ &lynx->rcv_pcl_bus, GFP_KERNEL);
+ lynx->rcv_buffer = dma_alloc_coherent(&lynx->pci_device->dev,
+ RCV_BUFFER_SIZE,
+ &lynx->rcv_buffer_bus, GFP_KERNEL);
if (lynx->rcv_start_pcl == NULL ||
lynx->rcv_pcl == NULL ||
lynx->rcv_buffer == NULL) {
@@ -667,14 +671,15 @@ fail_free_irq:
fail_deallocate_buffers:
if (lynx->rcv_start_pcl)
- pci_free_consistent(lynx->pci_device, sizeof(struct pcl),
- lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus);
+ dma_free_coherent(&lynx->pci_device->dev, sizeof(struct pcl),
+ lynx->rcv_start_pcl,
+ lynx->rcv_start_pcl_bus);
if (lynx->rcv_pcl)
- pci_free_consistent(lynx->pci_device, sizeof(struct pcl),
- lynx->rcv_pcl, lynx->rcv_pcl_bus);
+ dma_free_coherent(&lynx->pci_device->dev, sizeof(struct pcl),
+ lynx->rcv_pcl, lynx->rcv_pcl_bus);
if (lynx->rcv_buffer)
- pci_free_consistent(lynx->pci_device, PAGE_SIZE,
- lynx->rcv_buffer, lynx->rcv_buffer_bus);
+ dma_free_coherent(&lynx->pci_device->dev, PAGE_SIZE,
+ lynx->rcv_buffer, lynx->rcv_buffer_bus);
iounmap(lynx->registers);
fail_deallocate_lynx:
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index db0ea2d2d75a..1db738d5b301 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -9,7 +9,7 @@ menu "Firmware Drivers"
config ARM_SCMI_PROTOCOL
tristate "ARM System Control and Management Interface (SCMI) Message Protocol"
depends on ARM || ARM64 || COMPILE_TEST
- depends on MAILBOX
+ depends on MAILBOX || HAVE_ARM_SMCCC_DISCOVERY
help
ARM System Control and Management Interface (SCMI) protocol is a
set of operating system-independent software interfaces that are
@@ -296,6 +296,7 @@ config TURRIS_MOX_RWTM
other manufacturing data and also utilize the Entropy Bit Generator
for hardware random number generation.
+source "drivers/firmware/arm_ffa/Kconfig"
source "drivers/firmware/broadcom/Kconfig"
source "drivers/firmware/google/Kconfig"
source "drivers/firmware/efi/Kconfig"
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 5e013b6a3692..546ac8e7f6d0 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o
+obj-y += arm_ffa/
obj-y += arm_scmi/
obj-y += broadcom/
obj-y += meson/
diff --git a/drivers/firmware/arm_ffa/Kconfig b/drivers/firmware/arm_ffa/Kconfig
new file mode 100644
index 000000000000..5e3ae5cf82e8
--- /dev/null
+++ b/drivers/firmware/arm_ffa/Kconfig
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config ARM_FFA_TRANSPORT
+ tristate "Arm Firmware Framework for Armv8-A"
+ depends on OF
+ depends on ARM64
+ default n
+ help
+ This Firmware Framework(FF) for Arm A-profile processors describes
+ interfaces that standardize communication between the various
+ software images which includes communication between images in
+ the Secure world and Normal world. It also leverages the
+ virtualization extension to isolate software images provided
+ by an ecosystem of vendors from each other.
+
+ This driver provides interface for all the client drivers making
+ use of the features offered by ARM FF-A.
+
+config ARM_FFA_SMCCC
+ bool
+ default ARM_FFA_TRANSPORT
+ depends on ARM64 && HAVE_ARM_SMCCC_DISCOVERY
diff --git a/drivers/firmware/arm_ffa/Makefile b/drivers/firmware/arm_ffa/Makefile
new file mode 100644
index 000000000000..9d9f37523200
--- /dev/null
+++ b/drivers/firmware/arm_ffa/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+ffa-bus-y = bus.o
+ffa-driver-y = driver.o
+ffa-transport-$(CONFIG_ARM_FFA_SMCCC) += smccc.o
+ffa-module-objs := $(ffa-bus-y) $(ffa-driver-y) $(ffa-transport-y)
+obj-$(CONFIG_ARM_FFA_TRANSPORT) = ffa-module.o
diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c
new file mode 100644
index 000000000000..00fe595a5bc8
--- /dev/null
+++ b/drivers/firmware/arm_ffa/bus.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 ARM Ltd.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/arm_ffa.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "common.h"
+
+static int ffa_device_match(struct device *dev, struct device_driver *drv)
+{
+ const struct ffa_device_id *id_table;
+ struct ffa_device *ffa_dev;
+
+ id_table = to_ffa_driver(drv)->id_table;
+ ffa_dev = to_ffa_dev(dev);
+
+ while (!uuid_is_null(&id_table->uuid)) {
+ /*
+ * FF-A v1.0 doesn't provide discovery of UUIDs, just the
+ * partition IDs, so fetch the partitions IDs for this
+ * id_table UUID and assign the UUID to the device if the
+ * partition ID matches
+ */
+ if (uuid_is_null(&ffa_dev->uuid))
+ ffa_device_match_uuid(ffa_dev, &id_table->uuid);
+
+ if (uuid_equal(&ffa_dev->uuid, &id_table->uuid))
+ return 1;
+ id_table++;
+ }
+
+ return 0;
+}
+
+static int ffa_device_probe(struct device *dev)
+{
+ struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver);
+ struct ffa_device *ffa_dev = to_ffa_dev(dev);
+
+ return ffa_drv->probe(ffa_dev);
+}
+
+static int ffa_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct ffa_device *ffa_dev = to_ffa_dev(dev);
+
+ return add_uevent_var(env, "MODALIAS=arm_ffa:%04x:%pUb",
+ ffa_dev->vm_id, &ffa_dev->uuid);
+}
+
+static ssize_t partition_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ffa_device *ffa_dev = to_ffa_dev(dev);
+
+ return sprintf(buf, "0x%04x\n", ffa_dev->vm_id);
+}
+static DEVICE_ATTR_RO(partition_id);
+
+static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ffa_device *ffa_dev = to_ffa_dev(dev);
+
+ return sprintf(buf, "%pUb\n", &ffa_dev->uuid);
+}
+static DEVICE_ATTR_RO(uuid);
+
+static struct attribute *ffa_device_attributes_attrs[] = {
+ &dev_attr_partition_id.attr,
+ &dev_attr_uuid.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(ffa_device_attributes);
+
+struct bus_type ffa_bus_type = {
+ .name = "arm_ffa",
+ .match = ffa_device_match,
+ .probe = ffa_device_probe,
+ .uevent = ffa_device_uevent,
+ .dev_groups = ffa_device_attributes_groups,
+};
+EXPORT_SYMBOL_GPL(ffa_bus_type);
+
+int ffa_driver_register(struct ffa_driver *driver, struct module *owner,
+ const char *mod_name)
+{
+ int ret;
+
+ if (!driver->probe)
+ return -EINVAL;
+
+ driver->driver.bus = &ffa_bus_type;
+ driver->driver.name = driver->name;
+ driver->driver.owner = owner;
+ driver->driver.mod_name = mod_name;
+
+ ret = driver_register(&driver->driver);
+ if (!ret)
+ pr_debug("registered new ffa driver %s\n", driver->name);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ffa_driver_register);
+
+void ffa_driver_unregister(struct ffa_driver *driver)
+{
+ driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL_GPL(ffa_driver_unregister);
+
+static void ffa_release_device(struct device *dev)
+{
+ struct ffa_device *ffa_dev = to_ffa_dev(dev);
+
+ kfree(ffa_dev);
+}
+
+static int __ffa_devices_unregister(struct device *dev, void *data)
+{
+ ffa_release_device(dev);
+
+ return 0;
+}
+
+static void ffa_devices_unregister(void)
+{
+ bus_for_each_dev(&ffa_bus_type, NULL, NULL,
+ __ffa_devices_unregister);
+}
+
+bool ffa_device_is_valid(struct ffa_device *ffa_dev)
+{
+ bool valid = false;
+ struct device *dev = NULL;
+ struct ffa_device *tmp_dev;
+
+ do {
+ dev = bus_find_next_device(&ffa_bus_type, dev);
+ tmp_dev = to_ffa_dev(dev);
+ if (tmp_dev == ffa_dev) {
+ valid = true;
+ break;
+ }
+ put_device(dev);
+ } while (dev);
+
+ put_device(dev);
+
+ return valid;
+}
+
+struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id)
+{
+ int ret;
+ struct device *dev;
+ struct ffa_device *ffa_dev;
+
+ ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL);
+ if (!ffa_dev)
+ return NULL;
+
+ dev = &ffa_dev->dev;
+ dev->bus = &ffa_bus_type;
+ dev->release = ffa_release_device;
+ dev_set_name(&ffa_dev->dev, "arm-ffa-%04x", vm_id);
+
+ ffa_dev->vm_id = vm_id;
+ uuid_copy(&ffa_dev->uuid, uuid);
+
+ ret = device_register(&ffa_dev->dev);
+ if (ret) {
+ dev_err(dev, "unable to register device %s err=%d\n",
+ dev_name(dev), ret);
+ put_device(dev);
+ return NULL;
+ }
+
+ return ffa_dev;
+}
+EXPORT_SYMBOL_GPL(ffa_device_register);
+
+void ffa_device_unregister(struct ffa_device *ffa_dev)
+{
+ if (!ffa_dev)
+ return;
+
+ device_unregister(&ffa_dev->dev);
+}
+EXPORT_SYMBOL_GPL(ffa_device_unregister);
+
+int arm_ffa_bus_init(void)
+{
+ return bus_register(&ffa_bus_type);
+}
+
+void arm_ffa_bus_exit(void)
+{
+ ffa_devices_unregister();
+ bus_unregister(&ffa_bus_type);
+}
diff --git a/drivers/firmware/arm_ffa/common.h b/drivers/firmware/arm_ffa/common.h
new file mode 100644
index 000000000000..d6eccf1fd3f6
--- /dev/null
+++ b/drivers/firmware/arm_ffa/common.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 ARM Ltd.
+ */
+
+#ifndef _FFA_COMMON_H
+#define _FFA_COMMON_H
+
+#include <linux/arm_ffa.h>
+#include <linux/arm-smccc.h>
+#include <linux/err.h>
+
+typedef struct arm_smccc_1_2_regs ffa_value_t;
+
+typedef void (ffa_fn)(ffa_value_t, ffa_value_t *);
+
+int arm_ffa_bus_init(void);
+void arm_ffa_bus_exit(void);
+bool ffa_device_is_valid(struct ffa_device *ffa_dev);
+void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid);
+
+#ifdef CONFIG_ARM_FFA_SMCCC
+int __init ffa_transport_init(ffa_fn **invoke_ffa_fn);
+#else
+static inline int __init ffa_transport_init(ffa_fn **invoke_ffa_fn)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
+#endif /* _FFA_COMMON_H */
diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
new file mode 100644
index 000000000000..c9fb56afbcb4
--- /dev/null
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -0,0 +1,733 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Arm Firmware Framework for ARMv8-A(FFA) interface driver
+ *
+ * The Arm FFA specification[1] describes a software architecture to
+ * leverages the virtualization extension to isolate software images
+ * provided by an ecosystem of vendors from each other and describes
+ * interfaces that standardize communication between the various software
+ * images including communication between images in the Secure world and
+ * Normal world. Any Hypervisor could use the FFA interfaces to enable
+ * communication between VMs it manages.
+ *
+ * The Hypervisor a.k.a Partition managers in FFA terminology can assign
+ * system resources(Memory regions, Devices, CPU cycles) to the partitions
+ * and manage isolation amongst them.
+ *
+ * [1] https://developer.arm.com/docs/den0077/latest
+ *
+ * Copyright (C) 2021 ARM Ltd.
+ */
+
+#define DRIVER_NAME "ARM FF-A"
+#define pr_fmt(fmt) DRIVER_NAME ": " fmt
+
+#include <linux/arm_ffa.h>
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/uuid.h>
+
+#include "common.h"
+
+#define FFA_DRIVER_VERSION FFA_VERSION_1_0
+
+#define FFA_SMC(calling_convention, func_num) \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, (calling_convention), \
+ ARM_SMCCC_OWNER_STANDARD, (func_num))
+
+#define FFA_SMC_32(func_num) FFA_SMC(ARM_SMCCC_SMC_32, (func_num))
+#define FFA_SMC_64(func_num) FFA_SMC(ARM_SMCCC_SMC_64, (func_num))
+
+#define FFA_ERROR FFA_SMC_32(0x60)
+#define FFA_SUCCESS FFA_SMC_32(0x61)
+#define FFA_INTERRUPT FFA_SMC_32(0x62)
+#define FFA_VERSION FFA_SMC_32(0x63)
+#define FFA_FEATURES FFA_SMC_32(0x64)
+#define FFA_RX_RELEASE FFA_SMC_32(0x65)
+#define FFA_RXTX_MAP FFA_SMC_32(0x66)
+#define FFA_FN64_RXTX_MAP FFA_SMC_64(0x66)
+#define FFA_RXTX_UNMAP FFA_SMC_32(0x67)
+#define FFA_PARTITION_INFO_GET FFA_SMC_32(0x68)
+#define FFA_ID_GET FFA_SMC_32(0x69)
+#define FFA_MSG_POLL FFA_SMC_32(0x6A)
+#define FFA_MSG_WAIT FFA_SMC_32(0x6B)
+#define FFA_YIELD FFA_SMC_32(0x6C)
+#define FFA_RUN FFA_SMC_32(0x6D)
+#define FFA_MSG_SEND FFA_SMC_32(0x6E)
+#define FFA_MSG_SEND_DIRECT_REQ FFA_SMC_32(0x6F)
+#define FFA_FN64_MSG_SEND_DIRECT_REQ FFA_SMC_64(0x6F)
+#define FFA_MSG_SEND_DIRECT_RESP FFA_SMC_32(0x70)
+#define FFA_FN64_MSG_SEND_DIRECT_RESP FFA_SMC_64(0x70)
+#define FFA_MEM_DONATE FFA_SMC_32(0x71)
+#define FFA_FN64_MEM_DONATE FFA_SMC_64(0x71)
+#define FFA_MEM_LEND FFA_SMC_32(0x72)
+#define FFA_FN64_MEM_LEND FFA_SMC_64(0x72)
+#define FFA_MEM_SHARE FFA_SMC_32(0x73)
+#define FFA_FN64_MEM_SHARE FFA_SMC_64(0x73)
+#define FFA_MEM_RETRIEVE_REQ FFA_SMC_32(0x74)
+#define FFA_FN64_MEM_RETRIEVE_REQ FFA_SMC_64(0x74)
+#define FFA_MEM_RETRIEVE_RESP FFA_SMC_32(0x75)
+#define FFA_MEM_RELINQUISH FFA_SMC_32(0x76)
+#define FFA_MEM_RECLAIM FFA_SMC_32(0x77)
+#define FFA_MEM_OP_PAUSE FFA_SMC_32(0x78)
+#define FFA_MEM_OP_RESUME FFA_SMC_32(0x79)
+#define FFA_MEM_FRAG_RX FFA_SMC_32(0x7A)
+#define FFA_MEM_FRAG_TX FFA_SMC_32(0x7B)
+#define FFA_NORMAL_WORLD_RESUME FFA_SMC_32(0x7C)
+
+/*
+ * For some calls it is necessary to use SMC64 to pass or return 64-bit values.
+ * For such calls FFA_FN_NATIVE(name) will choose the appropriate
+ * (native-width) function ID.
+ */
+#ifdef CONFIG_64BIT
+#define FFA_FN_NATIVE(name) FFA_FN64_##name
+#else
+#define FFA_FN_NATIVE(name) FFA_##name
+#endif
+
+/* FFA error codes. */
+#define FFA_RET_SUCCESS (0)
+#define FFA_RET_NOT_SUPPORTED (-1)
+#define FFA_RET_INVALID_PARAMETERS (-2)
+#define FFA_RET_NO_MEMORY (-3)
+#define FFA_RET_BUSY (-4)
+#define FFA_RET_INTERRUPTED (-5)
+#define FFA_RET_DENIED (-6)
+#define FFA_RET_RETRY (-7)
+#define FFA_RET_ABORTED (-8)
+
+#define MAJOR_VERSION_MASK GENMASK(30, 16)
+#define MINOR_VERSION_MASK GENMASK(15, 0)
+#define MAJOR_VERSION(x) ((u16)(FIELD_GET(MAJOR_VERSION_MASK, (x))))
+#define MINOR_VERSION(x) ((u16)(FIELD_GET(MINOR_VERSION_MASK, (x))))
+#define PACK_VERSION_INFO(major, minor) \
+ (FIELD_PREP(MAJOR_VERSION_MASK, (major)) | \
+ FIELD_PREP(MINOR_VERSION_MASK, (minor)))
+#define FFA_VERSION_1_0 PACK_VERSION_INFO(1, 0)
+#define FFA_MIN_VERSION FFA_VERSION_1_0
+
+#define SENDER_ID_MASK GENMASK(31, 16)
+#define RECEIVER_ID_MASK GENMASK(15, 0)
+#define SENDER_ID(x) ((u16)(FIELD_GET(SENDER_ID_MASK, (x))))
+#define RECEIVER_ID(x) ((u16)(FIELD_GET(RECEIVER_ID_MASK, (x))))
+#define PACK_TARGET_INFO(s, r) \
+ (FIELD_PREP(SENDER_ID_MASK, (s)) | FIELD_PREP(RECEIVER_ID_MASK, (r)))
+
+/*
+ * FF-A specification mentions explicitly about '4K pages'. This should
+ * not be confused with the kernel PAGE_SIZE, which is the translation
+ * granule kernel is configured and may be one among 4K, 16K and 64K.
+ */
+#define FFA_PAGE_SIZE SZ_4K
+/*
+ * Keeping RX TX buffer size as 4K for now
+ * 64K may be preferred to keep it min a page in 64K PAGE_SIZE config
+ */
+#define RXTX_BUFFER_SIZE SZ_4K
+
+static ffa_fn *invoke_ffa_fn;
+
+static const int ffa_linux_errmap[] = {
+ /* better than switch case as long as return value is continuous */
+ 0, /* FFA_RET_SUCCESS */
+ -EOPNOTSUPP, /* FFA_RET_NOT_SUPPORTED */
+ -EINVAL, /* FFA_RET_INVALID_PARAMETERS */
+ -ENOMEM, /* FFA_RET_NO_MEMORY */
+ -EBUSY, /* FFA_RET_BUSY */
+ -EINTR, /* FFA_RET_INTERRUPTED */
+ -EACCES, /* FFA_RET_DENIED */
+ -EAGAIN, /* FFA_RET_RETRY */
+ -ECANCELED, /* FFA_RET_ABORTED */
+};
+
+static inline int ffa_to_linux_errno(int errno)
+{
+ int err_idx = -errno;
+
+ if (err_idx >= 0 && err_idx < ARRAY_SIZE(ffa_linux_errmap))
+ return ffa_linux_errmap[err_idx];
+ return -EINVAL;
+}
+
+struct ffa_drv_info {
+ u32 version;
+ u16 vm_id;
+ struct mutex rx_lock; /* lock to protect Rx buffer */
+ struct mutex tx_lock; /* lock to protect Tx buffer */
+ void *rx_buffer;
+ void *tx_buffer;
+};
+
+static struct ffa_drv_info *drv_info;
+
+static int ffa_version_check(u32 *version)
+{
+ ffa_value_t ver;
+
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = FFA_VERSION, .a1 = FFA_DRIVER_VERSION,
+ }, &ver);
+
+ if (ver.a0 == FFA_RET_NOT_SUPPORTED) {
+ pr_info("FFA_VERSION returned not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (ver.a0 < FFA_MIN_VERSION || ver.a0 > FFA_DRIVER_VERSION) {
+ pr_err("Incompatible version %d.%d found\n",
+ MAJOR_VERSION(ver.a0), MINOR_VERSION(ver.a0));
+ return -EINVAL;
+ }
+
+ *version = ver.a0;
+ pr_info("Version %d.%d found\n", MAJOR_VERSION(ver.a0),
+ MINOR_VERSION(ver.a0));
+ return 0;
+}
+
+static int ffa_rx_release(void)
+{
+ ffa_value_t ret;
+
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = FFA_RX_RELEASE,
+ }, &ret);
+
+ if (ret.a0 == FFA_ERROR)
+ return ffa_to_linux_errno((int)ret.a2);
+
+ /* check for ret.a0 == FFA_RX_RELEASE ? */
+
+ return 0;
+}
+
+static int ffa_rxtx_map(phys_addr_t tx_buf, phys_addr_t rx_buf, u32 pg_cnt)
+{
+ ffa_value_t ret;
+
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = FFA_FN_NATIVE(RXTX_MAP),
+ .a1 = tx_buf, .a2 = rx_buf, .a3 = pg_cnt,
+ }, &ret);
+
+ if (ret.a0 == FFA_ERROR)
+ return ffa_to_linux_errno((int)ret.a2);
+
+ return 0;
+}
+
+static int ffa_rxtx_unmap(u16 vm_id)
+{
+ ffa_value_t ret;
+
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = FFA_RXTX_UNMAP, .a1 = PACK_TARGET_INFO(vm_id, 0),
+ }, &ret);
+
+ if (ret.a0 == FFA_ERROR)
+ return ffa_to_linux_errno((int)ret.a2);
+
+ return 0;
+}
+
+/* buffer must be sizeof(struct ffa_partition_info) * num_partitions */
+static int
+__ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
+ struct ffa_partition_info *buffer, int num_partitions)
+{
+ int count;
+ ffa_value_t partition_info;
+
+ mutex_lock(&drv_info->rx_lock);
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = FFA_PARTITION_INFO_GET,
+ .a1 = uuid0, .a2 = uuid1, .a3 = uuid2, .a4 = uuid3,
+ }, &partition_info);
+
+ if (partition_info.a0 == FFA_ERROR) {
+ mutex_unlock(&drv_info->rx_lock);
+ return ffa_to_linux_errno((int)partition_info.a2);
+ }
+
+ count = partition_info.a2;
+
+ if (buffer && count <= num_partitions)
+ memcpy(buffer, drv_info->rx_buffer, sizeof(*buffer) * count);
+
+ ffa_rx_release();
+
+ mutex_unlock(&drv_info->rx_lock);
+
+ return count;
+}
+
+/* buffer is allocated and caller must free the same if returned count > 0 */
+static int
+ffa_partition_probe(const uuid_t *uuid, struct ffa_partition_info **buffer)
+{
+ int count;
+ u32 uuid0_4[4];
+ struct ffa_partition_info *pbuf;
+
+ export_uuid((u8 *)uuid0_4, uuid);
+ count = __ffa_partition_info_get(uuid0_4[0], uuid0_4[1], uuid0_4[2],
+ uuid0_4[3], NULL, 0);
+ if (count <= 0)
+ return count;
+
+ pbuf = kcalloc(count, sizeof(*pbuf), GFP_KERNEL);
+ if (!pbuf)
+ return -ENOMEM;
+
+ count = __ffa_partition_info_get(uuid0_4[0], uuid0_4[1], uuid0_4[2],
+ uuid0_4[3], pbuf, count);
+ if (count <= 0)
+ kfree(pbuf);
+ else
+ *buffer = pbuf;
+
+ return count;
+}
+
+#define VM_ID_MASK GENMASK(15, 0)
+static int ffa_id_get(u16 *vm_id)
+{
+ ffa_value_t id;
+
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = FFA_ID_GET,
+ }, &id);
+
+ if (id.a0 == FFA_ERROR)
+ return ffa_to_linux_errno((int)id.a2);
+
+ *vm_id = FIELD_GET(VM_ID_MASK, (id.a2));
+
+ return 0;
+}
+
+static int ffa_msg_send_direct_req(u16 src_id, u16 dst_id, bool mode_32bit,
+ struct ffa_send_direct_data *data)
+{
+ u32 req_id, resp_id, src_dst_ids = PACK_TARGET_INFO(src_id, dst_id);
+ ffa_value_t ret;
+
+ if (mode_32bit) {
+ req_id = FFA_MSG_SEND_DIRECT_REQ;
+ resp_id = FFA_MSG_SEND_DIRECT_RESP;
+ } else {
+ req_id = FFA_FN_NATIVE(MSG_SEND_DIRECT_REQ);
+ resp_id = FFA_FN_NATIVE(MSG_SEND_DIRECT_RESP);
+ }
+
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = req_id, .a1 = src_dst_ids, .a2 = 0,
+ .a3 = data->data0, .a4 = data->data1, .a5 = data->data2,
+ .a6 = data->data3, .a7 = data->data4,
+ }, &ret);
+
+ while (ret.a0 == FFA_INTERRUPT)
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = FFA_RUN, .a1 = ret.a1,
+ }, &ret);
+
+ if (ret.a0 == FFA_ERROR)
+ return ffa_to_linux_errno((int)ret.a2);
+
+ if (ret.a0 == resp_id) {
+ data->data0 = ret.a3;
+ data->data1 = ret.a4;
+ data->data2 = ret.a5;
+ data->data3 = ret.a6;
+ data->data4 = ret.a7;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int ffa_mem_first_frag(u32 func_id, phys_addr_t buf, u32 buf_sz,
+ u32 frag_len, u32 len, u64 *handle)
+{
+ ffa_value_t ret;
+
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = func_id, .a1 = len, .a2 = frag_len,
+ .a3 = buf, .a4 = buf_sz,
+ }, &ret);
+
+ while (ret.a0 == FFA_MEM_OP_PAUSE)
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = FFA_MEM_OP_RESUME,
+ .a1 = ret.a1, .a2 = ret.a2,
+ }, &ret);
+
+ if (ret.a0 == FFA_ERROR)
+ return ffa_to_linux_errno((int)ret.a2);
+
+ if (ret.a0 != FFA_SUCCESS)
+ return -EOPNOTSUPP;
+
+ if (handle)
+ *handle = PACK_HANDLE(ret.a2, ret.a3);
+
+ return frag_len;
+}
+
+static int ffa_mem_next_frag(u64 handle, u32 frag_len)
+{
+ ffa_value_t ret;
+
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = FFA_MEM_FRAG_TX,
+ .a1 = HANDLE_LOW(handle), .a2 = HANDLE_HIGH(handle),
+ .a3 = frag_len,
+ }, &ret);
+
+ while (ret.a0 == FFA_MEM_OP_PAUSE)
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = FFA_MEM_OP_RESUME,
+ .a1 = ret.a1, .a2 = ret.a2,
+ }, &ret);
+
+ if (ret.a0 == FFA_ERROR)
+ return ffa_to_linux_errno((int)ret.a2);
+
+ if (ret.a0 != FFA_MEM_FRAG_RX)
+ return -EOPNOTSUPP;
+
+ return ret.a3;
+}
+
+static int
+ffa_transmit_fragment(u32 func_id, phys_addr_t buf, u32 buf_sz, u32 frag_len,
+ u32 len, u64 *handle, bool first)
+{
+ if (!first)
+ return ffa_mem_next_frag(*handle, frag_len);
+
+ return ffa_mem_first_frag(func_id, buf, buf_sz, frag_len, len, handle);
+}
+
+static u32 ffa_get_num_pages_sg(struct scatterlist *sg)
+{
+ u32 num_pages = 0;
+
+ do {
+ num_pages += sg->length / FFA_PAGE_SIZE;
+ } while ((sg = sg_next(sg)));
+
+ return num_pages;
+}
+
+static int
+ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
+ struct ffa_mem_ops_args *args)
+{
+ int rc = 0;
+ bool first = true;
+ phys_addr_t addr = 0;
+ struct ffa_composite_mem_region *composite;
+ struct ffa_mem_region_addr_range *constituents;
+ struct ffa_mem_region_attributes *ep_mem_access;
+ struct ffa_mem_region *mem_region = buffer;
+ u32 idx, frag_len, length, buf_sz = 0, num_entries = sg_nents(args->sg);
+
+ mem_region->tag = args->tag;
+ mem_region->flags = args->flags;
+ mem_region->sender_id = drv_info->vm_id;
+ mem_region->attributes = FFA_MEM_NORMAL | FFA_MEM_WRITE_BACK |
+ FFA_MEM_INNER_SHAREABLE;
+ ep_mem_access = &mem_region->ep_mem_access[0];
+
+ for (idx = 0; idx < args->nattrs; idx++, ep_mem_access++) {
+ ep_mem_access->receiver = args->attrs[idx].receiver;
+ ep_mem_access->attrs = args->attrs[idx].attrs;
+ ep_mem_access->composite_off = COMPOSITE_OFFSET(args->nattrs);
+ }
+ mem_region->ep_count = args->nattrs;
+
+ composite = buffer + COMPOSITE_OFFSET(args->nattrs);
+ composite->total_pg_cnt = ffa_get_num_pages_sg(args->sg);
+ composite->addr_range_cnt = num_entries;
+
+ length = COMPOSITE_CONSTITUENTS_OFFSET(args->nattrs, num_entries);
+ frag_len = COMPOSITE_CONSTITUENTS_OFFSET(args->nattrs, 0);
+ if (frag_len > max_fragsize)
+ return -ENXIO;
+
+ if (!args->use_txbuf) {
+ addr = virt_to_phys(buffer);
+ buf_sz = max_fragsize / FFA_PAGE_SIZE;
+ }
+
+ constituents = buffer + frag_len;
+ idx = 0;
+ do {
+ if (frag_len == max_fragsize) {
+ rc = ffa_transmit_fragment(func_id, addr, buf_sz,
+ frag_len, length,
+ &args->g_handle, first);
+ if (rc < 0)
+ return -ENXIO;
+
+ first = false;
+ idx = 0;
+ frag_len = 0;
+ constituents = buffer;
+ }
+
+ if ((void *)constituents - buffer > max_fragsize) {
+ pr_err("Memory Region Fragment > Tx Buffer size\n");
+ return -EFAULT;
+ }
+
+ constituents->address = sg_phys(args->sg);
+ constituents->pg_cnt = args->sg->length / FFA_PAGE_SIZE;
+ constituents++;
+ frag_len += sizeof(struct ffa_mem_region_addr_range);
+ } while ((args->sg = sg_next(args->sg)));
+
+ return ffa_transmit_fragment(func_id, addr, buf_sz, frag_len,
+ length, &args->g_handle, first);
+}
+
+static int ffa_memory_ops(u32 func_id, struct ffa_mem_ops_args *args)
+{
+ int ret;
+ void *buffer;
+
+ if (!args->use_txbuf) {
+ buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ } else {
+ buffer = drv_info->tx_buffer;
+ mutex_lock(&drv_info->tx_lock);
+ }
+
+ ret = ffa_setup_and_transmit(func_id, buffer, RXTX_BUFFER_SIZE, args);
+
+ if (args->use_txbuf)
+ mutex_unlock(&drv_info->tx_lock);
+ else
+ free_pages_exact(buffer, RXTX_BUFFER_SIZE);
+
+ return ret < 0 ? ret : 0;
+}
+
+static int ffa_memory_reclaim(u64 g_handle, u32 flags)
+{
+ ffa_value_t ret;
+
+ invoke_ffa_fn((ffa_value_t){
+ .a0 = FFA_MEM_RECLAIM,
+ .a1 = HANDLE_LOW(g_handle), .a2 = HANDLE_HIGH(g_handle),
+ .a3 = flags,
+ }, &ret);
+
+ if (ret.a0 == FFA_ERROR)
+ return ffa_to_linux_errno((int)ret.a2);
+
+ return 0;
+}
+
+static u32 ffa_api_version_get(void)
+{
+ return drv_info->version;
+}
+
+static int ffa_partition_info_get(const char *uuid_str,
+ struct ffa_partition_info *buffer)
+{
+ int count;
+ uuid_t uuid;
+ struct ffa_partition_info *pbuf;
+
+ if (uuid_parse(uuid_str, &uuid)) {
+ pr_err("invalid uuid (%s)\n", uuid_str);
+ return -ENODEV;
+ }
+
+ count = ffa_partition_probe(&uuid_null, &pbuf);
+ if (count <= 0)
+ return -ENOENT;
+
+ memcpy(buffer, pbuf, sizeof(*pbuf) * count);
+ kfree(pbuf);
+ return 0;
+}
+
+static void ffa_mode_32bit_set(struct ffa_device *dev)
+{
+ dev->mode_32bit = true;
+}
+
+static int ffa_sync_send_receive(struct ffa_device *dev,
+ struct ffa_send_direct_data *data)
+{
+ return ffa_msg_send_direct_req(drv_info->vm_id, dev->vm_id,
+ dev->mode_32bit, data);
+}
+
+static int
+ffa_memory_share(struct ffa_device *dev, struct ffa_mem_ops_args *args)
+{
+ if (dev->mode_32bit)
+ return ffa_memory_ops(FFA_MEM_SHARE, args);
+
+ return ffa_memory_ops(FFA_FN_NATIVE(MEM_SHARE), args);
+}
+
+static const struct ffa_dev_ops ffa_ops = {
+ .api_version_get = ffa_api_version_get,
+ .partition_info_get = ffa_partition_info_get,
+ .mode_32bit_set = ffa_mode_32bit_set,
+ .sync_send_receive = ffa_sync_send_receive,
+ .memory_reclaim = ffa_memory_reclaim,
+ .memory_share = ffa_memory_share,
+};
+
+const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev)
+{
+ if (ffa_device_is_valid(dev))
+ return &ffa_ops;
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(ffa_dev_ops_get);
+
+void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid)
+{
+ int count, idx;
+ struct ffa_partition_info *pbuf, *tpbuf;
+
+ count = ffa_partition_probe(uuid, &pbuf);
+ if (count <= 0)
+ return;
+
+ for (idx = 0, tpbuf = pbuf; idx < count; idx++, tpbuf++)
+ if (tpbuf->id == ffa_dev->vm_id)
+ uuid_copy(&ffa_dev->uuid, uuid);
+ kfree(pbuf);
+}
+
+static void ffa_setup_partitions(void)
+{
+ int count, idx;
+ struct ffa_device *ffa_dev;
+ struct ffa_partition_info *pbuf, *tpbuf;
+
+ count = ffa_partition_probe(&uuid_null, &pbuf);
+ if (count <= 0) {
+ pr_info("%s: No partitions found, error %d\n", __func__, count);
+ return;
+ }
+
+ for (idx = 0, tpbuf = pbuf; idx < count; idx++, tpbuf++) {
+ /* Note that the &uuid_null parameter will require
+ * ffa_device_match() to find the UUID of this partition id
+ * with help of ffa_device_match_uuid(). Once the FF-A spec
+ * is updated to provide correct UUID here for each partition
+ * as part of the discovery API, we need to pass the
+ * discovered UUID here instead.
+ */
+ ffa_dev = ffa_device_register(&uuid_null, tpbuf->id);
+ if (!ffa_dev) {
+ pr_err("%s: failed to register partition ID 0x%x\n",
+ __func__, tpbuf->id);
+ continue;
+ }
+
+ ffa_dev_set_drvdata(ffa_dev, drv_info);
+ }
+ kfree(pbuf);
+}
+
+static int __init ffa_init(void)
+{
+ int ret;
+
+ ret = ffa_transport_init(&invoke_ffa_fn);
+ if (ret)
+ return ret;
+
+ ret = arm_ffa_bus_init();
+ if (ret)
+ return ret;
+
+ drv_info = kzalloc(sizeof(*drv_info), GFP_KERNEL);
+ if (!drv_info) {
+ ret = -ENOMEM;
+ goto ffa_bus_exit;
+ }
+
+ ret = ffa_version_check(&drv_info->version);
+ if (ret)
+ goto free_drv_info;
+
+ if (ffa_id_get(&drv_info->vm_id)) {
+ pr_err("failed to obtain VM id for self\n");
+ ret = -ENODEV;
+ goto free_drv_info;
+ }
+
+ drv_info->rx_buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL);
+ if (!drv_info->rx_buffer) {
+ ret = -ENOMEM;
+ goto free_pages;
+ }
+
+ drv_info->tx_buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL);
+ if (!drv_info->tx_buffer) {
+ ret = -ENOMEM;
+ goto free_pages;
+ }
+
+ ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer),
+ virt_to_phys(drv_info->rx_buffer),
+ RXTX_BUFFER_SIZE / FFA_PAGE_SIZE);
+ if (ret) {
+ pr_err("failed to register FFA RxTx buffers\n");
+ goto free_pages;
+ }
+
+ mutex_init(&drv_info->rx_lock);
+ mutex_init(&drv_info->tx_lock);
+
+ ffa_setup_partitions();
+
+ return 0;
+free_pages:
+ if (drv_info->tx_buffer)
+ free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE);
+ free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE);
+free_drv_info:
+ kfree(drv_info);
+ffa_bus_exit:
+ arm_ffa_bus_exit();
+ return ret;
+}
+subsys_initcall(ffa_init);
+
+static void __exit ffa_exit(void)
+{
+ ffa_rxtx_unmap(drv_info->vm_id);
+ free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE);
+ free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE);
+ kfree(drv_info);
+ arm_ffa_bus_exit();
+}
+module_exit(ffa_exit);
+
+MODULE_ALIAS("arm-ffa");
+MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
+MODULE_DESCRIPTION("Arm FF-A interface driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/firmware/arm_ffa/smccc.c b/drivers/firmware/arm_ffa/smccc.c
new file mode 100644
index 000000000000..4d85bfff0a4e
--- /dev/null
+++ b/drivers/firmware/arm_ffa/smccc.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 ARM Ltd.
+ */
+
+#include <linux/printk.h>
+
+#include "common.h"
+
+static void __arm_ffa_fn_smc(ffa_value_t args, ffa_value_t *res)
+{
+ arm_smccc_1_2_smc(&args, res);
+}
+
+static void __arm_ffa_fn_hvc(ffa_value_t args, ffa_value_t *res)
+{
+ arm_smccc_1_2_hvc(&args, res);
+}
+
+int __init ffa_transport_init(ffa_fn **invoke_ffa_fn)
+{
+ enum arm_smccc_conduit conduit;
+
+ if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
+ return -EOPNOTSUPP;
+
+ conduit = arm_smccc_1_1_get_conduit();
+ if (conduit == SMCCC_CONDUIT_NONE) {
+ pr_err("%s: invalid SMCCC conduit\n", __func__);
+ return -EOPNOTSUPP;
+ }
+
+ if (conduit == SMCCC_CONDUIT_SMC)
+ *invoke_ffa_fn = __arm_ffa_fn_smc;
+ else
+ *invoke_ffa_fn = __arm_ffa_fn_hvc;
+
+ return 0;
+}
diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c
index 784cf0027da3..6c7e24935eca 100644
--- a/drivers/firmware/arm_scmi/bus.c
+++ b/drivers/firmware/arm_scmi/bus.c
@@ -104,11 +104,6 @@ static int scmi_dev_probe(struct device *dev)
{
struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver);
struct scmi_device *scmi_dev = to_scmi_dev(dev);
- const struct scmi_device_id *id;
-
- id = scmi_dev_match_id(scmi_dev, scmi_drv);
- if (!id)
- return -ENODEV;
if (!scmi_dev->handle)
return -EPROBE_DEFER;
@@ -139,6 +134,9 @@ int scmi_driver_register(struct scmi_driver *driver, struct module *owner,
{
int retval;
+ if (!driver->probe)
+ return -EINVAL;
+
retval = scmi_protocol_device_request(driver->id_table);
if (retval)
return retval;
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 228bf4a71d23..8685619d38f9 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -331,7 +331,7 @@ struct scmi_desc {
};
extern const struct scmi_desc scmi_mailbox_desc;
-#ifdef CONFIG_HAVE_ARM_SMCCC
+#ifdef CONFIG_HAVE_ARM_SMCCC_DISCOVERY
extern const struct scmi_desc scmi_smc_desc;
#endif
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 66eb3f0e5daf..9b2e8d42a992 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -47,7 +47,6 @@ enum scmi_error_codes {
SCMI_ERR_GENERIC = -8, /* Generic Error */
SCMI_ERR_HARDWARE = -9, /* Hardware Error */
SCMI_ERR_PROTOCOL = -10,/* Protocol Error */
- SCMI_ERR_MAX
};
/* List of all SCMI devices active in system */
@@ -166,8 +165,10 @@ static const int scmi_linux_errmap[] = {
static inline int scmi_to_linux_errno(int errno)
{
- if (errno < SCMI_SUCCESS && errno > SCMI_ERR_MAX)
- return scmi_linux_errmap[-errno];
+ int err_idx = -errno;
+
+ if (err_idx >= SCMI_SUCCESS && err_idx < ARRAY_SIZE(scmi_linux_errmap))
+ return scmi_linux_errmap[err_idx];
return -EIO;
}
@@ -241,7 +242,6 @@ static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle,
xfer = &minfo->xfer_block[xfer_id];
xfer->hdr.seq = xfer_id;
- reinit_completion(&xfer->done);
xfer->transfer_id = atomic_inc_return(&transfer_last_id);
return xfer;
@@ -335,6 +335,10 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo,
return;
}
+ /* rx.len could be shrunk in the sync do_xfer, so reset to maxsz */
+ if (msg_type == MSG_TYPE_DELAYED_RESP)
+ xfer->rx.len = info->desc->max_msg_size;
+
scmi_dump_header_dbg(dev, &xfer->hdr);
info->desc->ops->fetch_response(cinfo, xfer);
@@ -429,11 +433,12 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
struct scmi_chan_info *cinfo;
/*
- * Re-instate protocol id here from protocol handle so that cannot be
+ * Initialise protocol id now from protocol handle to avoid it being
* overridden by mistake (or malice) by the protocol code mangling with
- * the scmi_xfer structure.
+ * the scmi_xfer structure prior to this.
*/
xfer->hdr.protocol_id = pi->proto->id;
+ reinit_completion(&xfer->done);
cinfo = idr_find(&info->tx_idr, xfer->hdr.protocol_id);
if (unlikely(!cinfo))
@@ -505,16 +510,17 @@ static int do_xfer_with_response(const struct scmi_protocol_handle *ph,
struct scmi_xfer *xfer)
{
int ret, timeout = msecs_to_jiffies(SCMI_MAX_RESPONSE_TIMEOUT);
- const struct scmi_protocol_instance *pi = ph_to_pi(ph);
DECLARE_COMPLETION_ONSTACK(async_response);
- xfer->hdr.protocol_id = pi->proto->id;
-
xfer->async_done = &async_response;
ret = do_xfer(ph, xfer);
- if (!ret && !wait_for_completion_timeout(xfer->async_done, timeout))
- ret = -ETIMEDOUT;
+ if (!ret) {
+ if (!wait_for_completion_timeout(xfer->async_done, timeout))
+ ret = -ETIMEDOUT;
+ else if (xfer->hdr.status)
+ ret = scmi_to_linux_errno(xfer->hdr.status);
+ }
xfer->async_done = NULL;
return ret;
@@ -561,7 +567,6 @@ static int xfer_get_init(const struct scmi_protocol_handle *ph,
xfer->tx.len = tx_size;
xfer->rx.len = rx_size ? : info->desc->max_msg_size;
xfer->hdr.id = msg_id;
- xfer->hdr.protocol_id = pi->proto->id;
xfer->hdr.poll_completion = false;
*p = xfer;
@@ -1021,8 +1026,9 @@ static int __scmi_xfer_info_init(struct scmi_info *sinfo,
const struct scmi_desc *desc = sinfo->desc;
/* Pre-allocated messages, no more than what hdr.seq can support */
- if (WARN_ON(desc->max_msg >= MSG_TOKEN_MAX)) {
- dev_err(dev, "Maximum message of %d exceeds supported %ld\n",
+ if (WARN_ON(!desc->max_msg || desc->max_msg > MSG_TOKEN_MAX)) {
+ dev_err(dev,
+ "Invalid maximum messages %d, not in range [1 - %lu]\n",
desc->max_msg, MSG_TOKEN_MAX);
return -EINVAL;
}
@@ -1133,6 +1139,8 @@ scmi_txrx_setup(struct scmi_info *info, struct device *dev, int prot_id)
* @proto_id and @name: if device was still not existent it is created as a
* child of the specified SCMI instance @info and its transport properly
* initialized as usual.
+ *
+ * Return: A properly initialized scmi device, NULL otherwise.
*/
static inline struct scmi_device *
scmi_get_protocol_device(struct device_node *np, struct scmi_info *info,
@@ -1567,7 +1575,9 @@ ATTRIBUTE_GROUPS(versions);
/* Each compatible listed below must have descriptor associated with it */
static const struct of_device_id scmi_of_match[] = {
+#ifdef CONFIG_MAILBOX
{ .compatible = "arm,scmi", .data = &scmi_mailbox_desc },
+#endif
#ifdef CONFIG_HAVE_ARM_SMCCC_DISCOVERY
{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
#endif
diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c
index 4626404be541..e3dcb58314ae 100644
--- a/drivers/firmware/arm_scmi/mailbox.c
+++ b/drivers/firmware/arm_scmi/mailbox.c
@@ -69,6 +69,9 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
return -ENOMEM;
shmem = of_parse_phandle(cdev->of_node, "shmem", idx);
+ if (!of_device_is_compatible(shmem, "arm,scmi-shmem"))
+ return -ENXIO;
+
ret = of_address_to_resource(shmem, 0, &res);
of_node_put(shmem);
if (ret) {
diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c
index d860bebd984a..0efd20cd9d69 100644
--- a/drivers/firmware/arm_scmi/notify.c
+++ b/drivers/firmware/arm_scmi/notify.c
@@ -1457,6 +1457,8 @@ static void scmi_devm_release_notifier(struct device *dev, void *res)
*
* Generic devres managed helper to register a notifier_block against a
* protocol event.
+ *
+ * Return: 0 on Success
*/
static int scmi_devm_notifier_register(struct scmi_device *sdev,
u8 proto_id, u8 evt_id,
@@ -1523,6 +1525,8 @@ static int scmi_devm_notifier_match(struct device *dev, void *res, void *data)
* Generic devres managed helper to explicitly un-register a notifier_block
* against a protocol event, which was previously registered using the above
* @scmi_devm_notifier_register.
+ *
+ * Return: 0 on Success
*/
static int scmi_devm_notifier_unregister(struct scmi_device *sdev,
u8 proto_id, u8 evt_id,
diff --git a/drivers/firmware/arm_scmi/scmi_pm_domain.c b/drivers/firmware/arm_scmi/scmi_pm_domain.c
index 9d36d5c0622d..4371fdcd5a73 100644
--- a/drivers/firmware/arm_scmi/scmi_pm_domain.c
+++ b/drivers/firmware/arm_scmi/scmi_pm_domain.c
@@ -8,6 +8,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/pm_clock.h>
#include <linux/pm_domain.h>
#include <linux/scmi_protocol.h>
@@ -52,6 +53,27 @@ static int scmi_pd_power_off(struct generic_pm_domain *domain)
return scmi_pd_power(domain, false);
}
+static int scmi_pd_attach_dev(struct generic_pm_domain *pd, struct device *dev)
+{
+ int ret;
+
+ ret = pm_clk_create(dev);
+ if (ret)
+ return ret;
+
+ ret = of_pm_clk_add_clks(dev);
+ if (ret >= 0)
+ return 0;
+
+ pm_clk_destroy(dev);
+ return ret;
+}
+
+static void scmi_pd_detach_dev(struct generic_pm_domain *pd, struct device *dev)
+{
+ pm_clk_destroy(dev);
+}
+
static int scmi_pm_domain_probe(struct scmi_device *sdev)
{
int num_domains, i;
@@ -102,6 +124,10 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
scmi_pd->genpd.name = scmi_pd->name;
scmi_pd->genpd.power_off = scmi_pd_power_off;
scmi_pd->genpd.power_on = scmi_pd_power_on;
+ scmi_pd->genpd.attach_dev = scmi_pd_attach_dev;
+ scmi_pd->genpd.detach_dev = scmi_pd_detach_dev;
+ scmi_pd->genpd.flags = GENPD_FLAG_PM_CLK |
+ GENPD_FLAG_ACTIVE_WAKEUP;
pm_genpd_init(&scmi_pd->genpd, NULL,
state == SCMI_POWER_STATE_GENERIC_OFF);
diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
index 2c88aa221559..308471586381 100644
--- a/drivers/firmware/arm_scmi/sensors.c
+++ b/drivers/firmware/arm_scmi/sensors.c
@@ -166,7 +166,8 @@ struct scmi_msg_sensor_reading_get {
struct scmi_resp_sensor_reading_complete {
__le32 id;
- __le64 readings;
+ __le32 readings_low;
+ __le32 readings_high;
};
struct scmi_sensor_reading_resp {
@@ -717,7 +718,8 @@ static int scmi_sensor_reading_get(const struct scmi_protocol_handle *ph,
resp = t->rx.buf;
if (le32_to_cpu(resp->id) == sensor_id)
- *value = get_unaligned_le64(&resp->readings);
+ *value =
+ get_unaligned_le64(&resp->readings_low);
else
ret = -EPROTO;
}
diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c
index fcbe2677f84b..bed5596c7209 100644
--- a/drivers/firmware/arm_scmi/smc.c
+++ b/drivers/firmware/arm_scmi/smc.c
@@ -76,6 +76,9 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
return -ENOMEM;
np = of_parse_phandle(cdev->of_node, "shmem", 0);
+ if (!of_device_is_compatible(np, "arm,scmi-shmem"))
+ return -ENXIO;
+
ret = of_address_to_resource(np, 0, &res);
of_node_put(np);
if (ret) {
diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
index 4ceba5ef7895..ddf0b9ff9e15 100644
--- a/drivers/firmware/arm_scpi.c
+++ b/drivers/firmware/arm_scpi.c
@@ -899,6 +899,14 @@ static const struct of_device_id legacy_scpi_of_match[] = {
{},
};
+static const struct of_device_id shmem_of_match[] __maybe_unused = {
+ { .compatible = "amlogic,meson-gxbb-scp-shmem", },
+ { .compatible = "amlogic,meson-axg-scp-shmem", },
+ { .compatible = "arm,juno-scp-shmem", },
+ { .compatible = "arm,scp-shmem", },
+ { }
+};
+
static int scpi_probe(struct platform_device *pdev)
{
int count, idx, ret;
@@ -935,6 +943,9 @@ static int scpi_probe(struct platform_device *pdev)
struct mbox_client *cl = &pchan->cl;
struct device_node *shmem = of_parse_phandle(np, "shmem", idx);
+ if (!of_match_node(shmem_of_match, shmem))
+ return -ENXIO;
+
ret = of_address_to_resource(shmem, 0, &res);
of_node_put(shmem);
if (ret) {
diff --git a/drivers/firmware/efi/apple-properties.c b/drivers/firmware/efi/apple-properties.c
index e1926483ae2f..4c3201e290e2 100644
--- a/drivers/firmware/efi/apple-properties.c
+++ b/drivers/firmware/efi/apple-properties.c
@@ -157,7 +157,7 @@ static int __init unmarshal_devices(struct properties_header *properties)
if (!entry[0].name)
goto skip_device;
- ret = device_add_properties(dev, entry); /* makes deep copy */
+ ret = device_create_managed_software_node(dev, entry, NULL);
if (ret)
dev_err(dev, "error %d assigning properties\n", ret);
diff --git a/drivers/firmware/efi/dev-path-parser.c b/drivers/firmware/efi/dev-path-parser.c
index 5c9625e552f4..10d4457417a4 100644
--- a/drivers/firmware/efi/dev-path-parser.c
+++ b/drivers/firmware/efi/dev-path-parser.c
@@ -12,52 +12,39 @@
#include <linux/efi.h>
#include <linux/pci.h>
-struct acpi_hid_uid {
- struct acpi_device_id hid[2];
- char uid[11]; /* UINT_MAX + null byte */
-};
-
-static int __init match_acpi_dev(struct device *dev, const void *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))
- return 0;
-
- if (adev->pnp.unique_id)
- return !strcmp(adev->pnp.unique_id, hid_uid.uid);
- else
- return !strcmp("0", hid_uid.uid);
-}
-
static long __init parse_acpi_path(const struct efi_dev_path *node,
struct device *parent, struct device **child)
{
- struct acpi_hid_uid hid_uid = {};
+ char hid[ACPI_ID_LEN], uid[11]; /* UINT_MAX + null byte */
+ struct acpi_device *adev;
struct device *phys_dev;
if (node->header.length != 12)
return -EINVAL;
- sprintf(hid_uid.hid[0].id, "%c%c%c%04X",
+ sprintf(hid, "%c%c%c%04X",
'A' + ((node->acpi.hid >> 10) & 0x1f) - 1,
'A' + ((node->acpi.hid >> 5) & 0x1f) - 1,
'A' + ((node->acpi.hid >> 0) & 0x1f) - 1,
node->acpi.hid >> 16);
- sprintf(hid_uid.uid, "%u", node->acpi.uid);
-
- *child = bus_find_device(&acpi_bus_type, NULL, &hid_uid,
- match_acpi_dev);
- if (!*child)
+ sprintf(uid, "%u", node->acpi.uid);
+
+ for_each_acpi_dev_match(adev, hid, NULL, -1) {
+ if (adev->pnp.unique_id && !strcmp(adev->pnp.unique_id, uid))
+ break;
+ if (!adev->pnp.unique_id && node->acpi.uid == 0)
+ break;
+ acpi_dev_put(adev);
+ }
+ if (!adev)
return -ENODEV;
- phys_dev = acpi_get_first_physical_node(to_acpi_device(*child));
+ phys_dev = acpi_get_first_physical_node(adev);
if (phys_dev) {
- get_device(phys_dev);
- put_device(*child);
- *child = phys_dev;
- }
+ *child = get_device(phys_dev);
+ acpi_dev_put(adev);
+ } else
+ *child = &adev->dev;
return 0;
}
diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c
index bb6e77ee3898..adaa492c3d2d 100644
--- a/drivers/firmware/google/gsmi.c
+++ b/drivers/firmware/google/gsmi.c
@@ -19,6 +19,7 @@
#include <linux/dma-mapping.h>
#include <linux/fs.h>
#include <linux/slab.h>
+#include <linux/panic_notifier.h>
#include <linux/ioctl.h>
#include <linux/acpi.h>
#include <linux/io.h>
diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
index 3c1c5daf6df2..cfb448eabdaa 100644
--- a/drivers/firmware/psci/psci.c
+++ b/drivers/firmware/psci/psci.c
@@ -296,7 +296,8 @@ static int get_set_conduit_method(struct device_node *np)
return 0;
}
-static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd)
+static int psci_sys_reset(struct notifier_block *nb, unsigned long action,
+ void *data)
{
if ((reboot_mode == REBOOT_WARM || reboot_mode == REBOOT_SOFT) &&
psci_system_reset2_supported) {
@@ -309,8 +310,15 @@ static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd)
} else {
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);
}
+
+ return NOTIFY_DONE;
}
+static struct notifier_block psci_sys_reset_nb = {
+ .notifier_call = psci_sys_reset,
+ .priority = 129,
+};
+
static void psci_sys_poweroff(void)
{
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
@@ -335,10 +343,15 @@ int psci_cpu_suspend_enter(u32 state)
{
int ret;
- if (!psci_power_state_loses_context(state))
+ if (!psci_power_state_loses_context(state)) {
+ struct arm_cpuidle_irq_context context;
+
+ arm_cpuidle_save_irq_context(&context);
ret = psci_ops.cpu_suspend(state, 0);
- else
+ arm_cpuidle_restore_irq_context(&context);
+ } else {
ret = cpu_suspend(state, psci_suspend_finisher);
+ }
return ret;
}
@@ -472,7 +485,7 @@ static void __init psci_0_2_set_functions(void)
.migrate_info_type = psci_migrate_info_type,
};
- arm_pm_restart = psci_sys_reset;
+ register_restart_handler(&psci_sys_reset_nb);
pm_power_off = psci_sys_poweroff;
}
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index ee9cb545e73b..47ea2bd42b10 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -1281,6 +1281,9 @@ static const struct of_device_id qcom_scm_dt_match[] = {
SCM_HAS_BUS_CLK)
},
{ .compatible = "qcom,scm-ipq4019" },
+ { .compatible = "qcom,scm-mdm9607", .data = (void *)(SCM_HAS_CORE_CLK |
+ SCM_HAS_IFACE_CLK |
+ SCM_HAS_BUS_CLK) },
{ .compatible = "qcom,scm-msm8660", .data = (void *) SCM_HAS_CORE_CLK },
{ .compatible = "qcom,scm-msm8960", .data = (void *) SCM_HAS_CORE_CLK },
{ .compatible = "qcom,scm-msm8916", .data = (void *)(SCM_HAS_CORE_CLK |
diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 0078260fbabe..172c751a4f6c 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -299,15 +299,13 @@ static int fw_cfg_do_platform_probe(struct platform_device *pdev)
return 0;
}
-static ssize_t fw_cfg_showrev(struct kobject *k, struct attribute *a, char *buf)
+static ssize_t fw_cfg_showrev(struct kobject *k, struct kobj_attribute *a,
+ char *buf)
{
return sprintf(buf, "%u\n", fw_cfg_rev);
}
-static const struct {
- struct attribute attr;
- ssize_t (*show)(struct kobject *k, struct attribute *a, char *buf);
-} fw_cfg_rev_attr = {
+static const struct kobj_attribute fw_cfg_rev_attr = {
.attr = { .name = "rev", .mode = S_IRUSR },
.show = fw_cfg_showrev,
};
diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c
index 028f81d702cc..9f937b125ab0 100644
--- a/drivers/firmware/smccc/smccc.c
+++ b/drivers/firmware/smccc/smccc.c
@@ -15,6 +15,7 @@ static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE;
bool __ro_after_init smccc_trng_available = false;
+u64 __ro_after_init smccc_has_sve_hint = false;
void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
{
@@ -22,6 +23,9 @@ void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
smccc_conduit = conduit;
smccc_trng_available = smccc_probe_trng();
+ if (IS_ENABLED(CONFIG_ARM64_SVE) &&
+ smccc_version >= ARM_SMCCC_VERSION_1_3)
+ smccc_has_sve_hint = true;
}
enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void)
diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c
index 3aa489dba30a..2a7687911c09 100644
--- a/drivers/firmware/stratix10-svc.c
+++ b/drivers/firmware/stratix10-svc.c
@@ -1034,24 +1034,32 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
/* add svc client device(s) */
svc = devm_kzalloc(dev, sizeof(*svc), GFP_KERNEL);
- if (!svc)
- return -ENOMEM;
+ if (!svc) {
+ ret = -ENOMEM;
+ goto err_free_kfifo;
+ }
svc->stratix10_svc_rsu = platform_device_alloc(STRATIX10_RSU, 0);
if (!svc->stratix10_svc_rsu) {
dev_err(dev, "failed to allocate %s device\n", STRATIX10_RSU);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_free_kfifo;
}
ret = platform_device_add(svc->stratix10_svc_rsu);
- if (ret) {
- platform_device_put(svc->stratix10_svc_rsu);
- return ret;
- }
+ if (ret)
+ goto err_put_device;
+
dev_set_drvdata(dev, svc);
pr_info("Intel Service Layer Driver Initialized\n");
+ return 0;
+
+err_put_device:
+ platform_device_put(svc->stratix10_svc_rsu);
+err_free_kfifo:
+ kfifo_free(&controller->svc_fifo);
return ret;
}
diff --git a/drivers/firmware/tegra/Makefile b/drivers/firmware/tegra/Makefile
index 49c87e00fafb..620cf3fdd607 100644
--- a/drivers/firmware/tegra/Makefile
+++ b/drivers/firmware/tegra/Makefile
@@ -3,6 +3,7 @@ tegra-bpmp-y = bpmp.o
tegra-bpmp-$(CONFIG_ARCH_TEGRA_210_SOC) += bpmp-tegra210.o
tegra-bpmp-$(CONFIG_ARCH_TEGRA_186_SOC) += bpmp-tegra186.o
tegra-bpmp-$(CONFIG_ARCH_TEGRA_194_SOC) += bpmp-tegra186.o
+tegra-bpmp-$(CONFIG_ARCH_TEGRA_234_SOC) += bpmp-tegra186.o
tegra-bpmp-$(CONFIG_DEBUG_FS) += bpmp-debugfs.o
obj-$(CONFIG_TEGRA_BPMP) += tegra-bpmp.o
obj-$(CONFIG_TEGRA_IVC) += ivc.o
diff --git a/drivers/firmware/tegra/bpmp-private.h b/drivers/firmware/tegra/bpmp-private.h
index 54d560c48398..182bfe396516 100644
--- a/drivers/firmware/tegra/bpmp-private.h
+++ b/drivers/firmware/tegra/bpmp-private.h
@@ -24,7 +24,8 @@ struct tegra_bpmp_ops {
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \
- IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
+ IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
+ IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
extern const struct tegra_bpmp_ops tegra186_bpmp_ops;
#endif
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
diff --git a/drivers/firmware/tegra/bpmp-tegra210.c b/drivers/firmware/tegra/bpmp-tegra210.c
index ae15940a078e..c32754055c60 100644
--- a/drivers/firmware/tegra/bpmp-tegra210.c
+++ b/drivers/firmware/tegra/bpmp-tegra210.c
@@ -210,7 +210,7 @@ static int tegra210_bpmp_init(struct tegra_bpmp *bpmp)
priv->tx_irq_data = irq_get_irq_data(err);
if (!priv->tx_irq_data) {
dev_err(&pdev->dev, "failed to get IRQ data for TX IRQ\n");
- return err;
+ return -ENOENT;
}
err = platform_get_irq_byname(pdev, "rx");
diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c
index 0742a90cb844..5654c5e9862b 100644
--- a/drivers/firmware/tegra/bpmp.c
+++ b/drivers/firmware/tegra/bpmp.c
@@ -809,7 +809,8 @@ static const struct dev_pm_ops tegra_bpmp_pm_ops = {
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \
- IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
+ IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
+ IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
static const struct tegra_bpmp_soc tegra186_soc = {
.channels = {
.cpu_tx = {
diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c
index 62f0d1a5dd32..c2d34dc8ba46 100644
--- a/drivers/firmware/turris-mox-rwtm.c
+++ b/drivers/firmware/turris-mox-rwtm.c
@@ -147,11 +147,14 @@ MOX_ATTR_RO(pubkey, "%s\n", pubkey);
static int mox_get_status(enum mbox_cmd cmd, u32 retval)
{
- if (MBOX_STS_CMD(retval) != cmd ||
- MBOX_STS_ERROR(retval) != MBOX_STS_SUCCESS)
+ if (MBOX_STS_CMD(retval) != cmd)
return -EIO;
else if (MBOX_STS_ERROR(retval) == MBOX_STS_FAIL)
return -(int)MBOX_STS_VALUE(retval);
+ else if (MBOX_STS_ERROR(retval) == MBOX_STS_BADCMD)
+ return -ENOSYS;
+ else if (MBOX_STS_ERROR(retval) != MBOX_STS_SUCCESS)
+ return -EIO;
else
return MBOX_STS_VALUE(retval);
}
@@ -201,11 +204,14 @@ static int mox_get_board_info(struct mox_rwtm *rwtm)
return ret;
ret = mox_get_status(MBOX_CMD_BOARD_INFO, reply->retval);
- if (ret < 0 && ret != -ENODATA) {
- return ret;
- } else if (ret == -ENODATA) {
+ if (ret == -ENODATA) {
dev_warn(rwtm->dev,
"Board does not have manufacturing information burned!\n");
+ } else if (ret == -ENOSYS) {
+ dev_notice(rwtm->dev,
+ "Firmware does not support the BOARD_INFO command\n");
+ } else if (ret < 0) {
+ return ret;
} else {
rwtm->serial_number = reply->status[1];
rwtm->serial_number <<= 32;
@@ -234,10 +240,13 @@ static int mox_get_board_info(struct mox_rwtm *rwtm)
return ret;
ret = mox_get_status(MBOX_CMD_ECDSA_PUB_KEY, reply->retval);
- if (ret < 0 && ret != -ENODATA) {
- return ret;
- } else if (ret == -ENODATA) {
+ if (ret == -ENODATA) {
dev_warn(rwtm->dev, "Board has no public key burned!\n");
+ } else if (ret == -ENOSYS) {
+ dev_notice(rwtm->dev,
+ "Firmware does not support the ECDSA_PUB_KEY command\n");
+ } else if (ret < 0) {
+ return ret;
} else {
u32 *s = reply->status;
@@ -251,6 +260,27 @@ static int mox_get_board_info(struct mox_rwtm *rwtm)
return 0;
}
+static int check_get_random_support(struct mox_rwtm *rwtm)
+{
+ struct armada_37xx_rwtm_tx_msg msg;
+ int ret;
+
+ msg.command = MBOX_CMD_GET_RANDOM;
+ msg.args[0] = 1;
+ msg.args[1] = rwtm->buf_phys;
+ msg.args[2] = 4;
+
+ ret = mbox_send_message(rwtm->mbox, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2);
+ if (ret < 0)
+ return ret;
+
+ return mox_get_status(MBOX_CMD_GET_RANDOM, rwtm->reply.retval);
+}
+
static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
struct mox_rwtm *rwtm = (struct mox_rwtm *) rng->priv;
@@ -488,6 +518,13 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev)
if (ret < 0)
dev_warn(dev, "Cannot read board information: %i\n", ret);
+ ret = check_get_random_support(rwtm);
+ if (ret < 0) {
+ dev_notice(dev,
+ "Firmware does not support the GET_RANDOM command\n");
+ goto free_channel;
+ }
+
rwtm->hwrng.name = DRIVER_NAME "_hwrng";
rwtm->hwrng.read = mox_hwrng_read;
rwtm->hwrng.priv = (unsigned long) rwtm;
@@ -505,6 +542,8 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev)
goto free_channel;
}
+ dev_info(dev, "HWRNG successfully registered\n");
+
return 0;
free_channel:
@@ -530,6 +569,7 @@ static int turris_mox_rwtm_remove(struct platform_device *pdev)
static const struct of_device_id turris_mox_rwtm_match[] = {
{ .compatible = "cznic,turris-mox-rwtm", },
+ { .compatible = "marvell,armada-3700-rwtm-firmware", },
{ },
};
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 33e15058d0dc..8cd454ee20c0 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -7,7 +7,7 @@ menuconfig FPGA
tristate "FPGA Configuration Framework"
help
Say Y here if you want support for configuring FPGAs from the
- kernel. The FPGA framework adds a FPGA manager class and FPGA
+ kernel. The FPGA framework adds an FPGA manager class and FPGA
manager drivers.
if FPGA
@@ -134,7 +134,7 @@ config FPGA_REGION
tristate "FPGA Region"
depends on FPGA_BRIDGE
help
- FPGA Region common code. A FPGA Region controls a FPGA Manager
+ FPGA Region common code. An FPGA Region controls an FPGA Manager
and the FPGA Bridges associated with either a reconfigurable
region of an FPGA or a whole FPGA.
diff --git a/drivers/fpga/altera-pr-ip-core.c b/drivers/fpga/altera-pr-ip-core.c
index 5b130c4d9882..dfdf21ed34c4 100644
--- a/drivers/fpga/altera-pr-ip-core.c
+++ b/drivers/fpga/altera-pr-ip-core.c
@@ -199,16 +199,6 @@ int alt_pr_register(struct device *dev, void __iomem *reg_base)
}
EXPORT_SYMBOL_GPL(alt_pr_register);
-void alt_pr_unregister(struct device *dev)
-{
- struct fpga_manager *mgr = dev_get_drvdata(dev);
-
- dev_dbg(dev, "%s\n", __func__);
-
- fpga_mgr_unregister(mgr);
-}
-EXPORT_SYMBOL_GPL(alt_pr_unregister);
-
MODULE_AUTHOR("Matthew Gerlach <matthew.gerlach@linux.intel.com>");
MODULE_DESCRIPTION("Altera Partial Reconfiguration IP Core");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c
index e9266b2a357f..2bfb2ff86930 100644
--- a/drivers/fpga/fpga-bridge.c
+++ b/drivers/fpga/fpga-bridge.c
@@ -85,14 +85,14 @@ err_dev:
}
/**
- * of_fpga_bridge_get - get an exclusive reference to a fpga bridge
+ * of_fpga_bridge_get - get an exclusive reference to an fpga bridge
*
- * @np: node pointer of a FPGA bridge
+ * @np: node pointer of an FPGA bridge
* @info: fpga image specific information
*
* Return fpga_bridge struct if successful.
* Return -EBUSY if someone already has a reference to the bridge.
- * Return -ENODEV if @np is not a FPGA Bridge.
+ * Return -ENODEV if @np is not an FPGA Bridge.
*/
struct fpga_bridge *of_fpga_bridge_get(struct device_node *np,
struct fpga_image_info *info)
@@ -113,11 +113,11 @@ static int fpga_bridge_dev_match(struct device *dev, const void *data)
}
/**
- * fpga_bridge_get - get an exclusive reference to a fpga bridge
+ * fpga_bridge_get - get an exclusive reference to an fpga bridge
* @dev: parent device that fpga bridge was registered with
* @info: fpga manager info
*
- * Given a device, get an exclusive reference to a fpga bridge.
+ * Given a device, get an exclusive reference to an fpga bridge.
*
* Return: fpga bridge struct or IS_ERR() condition containing error code.
*/
@@ -224,7 +224,7 @@ EXPORT_SYMBOL_GPL(fpga_bridges_put);
/**
* of_fpga_bridge_get_to_list - get a bridge, add it to a list
*
- * @np: node pointer of a FPGA bridge
+ * @np: node pointer of an FPGA bridge
* @info: fpga image specific information
* @bridge_list: list of FPGA bridges
*
@@ -313,7 +313,7 @@ ATTRIBUTE_GROUPS(fpga_bridge);
/**
* fpga_bridge_create - create and initialize a struct fpga_bridge
- * @dev: FPGA bridge device from pdev
+ * @parent: FPGA bridge device from pdev
* @name: FPGA bridge name
* @br_ops: pointer to structure of fpga bridge ops
* @priv: FPGA bridge private data
@@ -323,7 +323,7 @@ ATTRIBUTE_GROUPS(fpga_bridge);
*
* Return: struct fpga_bridge or NULL
*/
-struct fpga_bridge *fpga_bridge_create(struct device *dev, const char *name,
+struct fpga_bridge *fpga_bridge_create(struct device *parent, const char *name,
const struct fpga_bridge_ops *br_ops,
void *priv)
{
@@ -331,7 +331,7 @@ struct fpga_bridge *fpga_bridge_create(struct device *dev, const char *name,
int id, ret;
if (!name || !strlen(name)) {
- dev_err(dev, "Attempt to register with no name!\n");
+ dev_err(parent, "Attempt to register with no name!\n");
return NULL;
}
@@ -353,8 +353,8 @@ struct fpga_bridge *fpga_bridge_create(struct device *dev, const char *name,
device_initialize(&bridge->dev);
bridge->dev.groups = br_ops->groups;
bridge->dev.class = fpga_bridge_class;
- bridge->dev.parent = dev;
- bridge->dev.of_node = dev->of_node;
+ bridge->dev.parent = parent;
+ bridge->dev.of_node = parent->of_node;
bridge->dev.id = id;
ret = dev_set_name(&bridge->dev, "br%d", id);
@@ -373,7 +373,7 @@ error_kfree:
EXPORT_SYMBOL_GPL(fpga_bridge_create);
/**
- * fpga_bridge_free - free a fpga bridge created by fpga_bridge_create()
+ * fpga_bridge_free - free an fpga bridge created by fpga_bridge_create()
* @bridge: FPGA bridge struct
*/
void fpga_bridge_free(struct fpga_bridge *bridge)
@@ -392,12 +392,12 @@ static void devm_fpga_bridge_release(struct device *dev, void *res)
/**
* devm_fpga_bridge_create - create and init a managed struct fpga_bridge
- * @dev: FPGA bridge device from pdev
+ * @parent: FPGA bridge device from pdev
* @name: FPGA bridge name
* @br_ops: pointer to structure of fpga bridge ops
* @priv: FPGA bridge private data
*
- * This function is intended for use in a FPGA bridge driver's probe function.
+ * This function is intended for use in an FPGA bridge driver's probe function.
* After the bridge driver creates the struct with devm_fpga_bridge_create(), it
* should register the bridge with fpga_bridge_register(). The bridge driver's
* remove function should call fpga_bridge_unregister(). The bridge struct
@@ -408,7 +408,7 @@ static void devm_fpga_bridge_release(struct device *dev, void *res)
* Return: struct fpga_bridge or NULL
*/
struct fpga_bridge
-*devm_fpga_bridge_create(struct device *dev, const char *name,
+*devm_fpga_bridge_create(struct device *parent, const char *name,
const struct fpga_bridge_ops *br_ops, void *priv)
{
struct fpga_bridge **ptr, *bridge;
@@ -417,12 +417,12 @@ struct fpga_bridge
if (!ptr)
return NULL;
- bridge = fpga_bridge_create(dev, name, br_ops, priv);
+ bridge = fpga_bridge_create(parent, name, br_ops, priv);
if (!bridge) {
devres_free(ptr);
} else {
*ptr = bridge;
- devres_add(dev, ptr);
+ devres_add(parent, ptr);
}
return bridge;
@@ -430,7 +430,7 @@ struct fpga_bridge
EXPORT_SYMBOL_GPL(devm_fpga_bridge_create);
/**
- * fpga_bridge_register - register a FPGA bridge
+ * fpga_bridge_register - register an FPGA bridge
*
* @bridge: FPGA bridge struct
*
@@ -454,11 +454,11 @@ int fpga_bridge_register(struct fpga_bridge *bridge)
EXPORT_SYMBOL_GPL(fpga_bridge_register);
/**
- * fpga_bridge_unregister - unregister a FPGA bridge
+ * fpga_bridge_unregister - unregister an FPGA bridge
*
* @bridge: FPGA bridge struct
*
- * This function is intended for use in a FPGA bridge driver's remove function.
+ * This function is intended for use in an FPGA bridge driver's remove function.
*/
void fpga_bridge_unregister(struct fpga_bridge *bridge)
{
diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
index b85bc47c91a9..ecb4c3c795fa 100644
--- a/drivers/fpga/fpga-mgr.c
+++ b/drivers/fpga/fpga-mgr.c
@@ -26,7 +26,7 @@ struct fpga_mgr_devres {
};
/**
- * fpga_image_info_alloc - Allocate a FPGA image info struct
+ * fpga_image_info_alloc - Allocate an FPGA image info struct
* @dev: owning device
*
* Return: struct fpga_image_info or NULL
@@ -50,7 +50,7 @@ struct fpga_image_info *fpga_image_info_alloc(struct device *dev)
EXPORT_SYMBOL_GPL(fpga_image_info_alloc);
/**
- * fpga_image_info_free - Free a FPGA image info struct
+ * fpga_image_info_free - Free an FPGA image info struct
* @info: FPGA image info struct to free
*/
void fpga_image_info_free(struct fpga_image_info *info)
@@ -470,7 +470,7 @@ static int fpga_mgr_dev_match(struct device *dev, const void *data)
}
/**
- * fpga_mgr_get - Given a device, get a reference to a fpga mgr.
+ * fpga_mgr_get - Given a device, get a reference to an fpga mgr.
* @dev: parent device that fpga mgr was registered with
*
* Return: fpga manager struct or IS_ERR() condition containing error code.
@@ -487,7 +487,7 @@ struct fpga_manager *fpga_mgr_get(struct device *dev)
EXPORT_SYMBOL_GPL(fpga_mgr_get);
/**
- * of_fpga_mgr_get - Given a device node, get a reference to a fpga mgr.
+ * of_fpga_mgr_get - Given a device node, get a reference to an fpga mgr.
*
* @node: device node
*
@@ -506,7 +506,7 @@ struct fpga_manager *of_fpga_mgr_get(struct device_node *node)
EXPORT_SYMBOL_GPL(of_fpga_mgr_get);
/**
- * fpga_mgr_put - release a reference to a fpga manager
+ * fpga_mgr_put - release a reference to an fpga manager
* @mgr: fpga manager structure
*/
void fpga_mgr_put(struct fpga_manager *mgr)
@@ -550,8 +550,8 @@ void fpga_mgr_unlock(struct fpga_manager *mgr)
EXPORT_SYMBOL_GPL(fpga_mgr_unlock);
/**
- * fpga_mgr_create - create and initialize a FPGA manager struct
- * @dev: fpga manager device from pdev
+ * fpga_mgr_create - create and initialize an FPGA manager struct
+ * @parent: fpga manager device from pdev
* @name: fpga manager name
* @mops: pointer to structure of fpga manager ops
* @priv: fpga manager private data
@@ -561,7 +561,7 @@ EXPORT_SYMBOL_GPL(fpga_mgr_unlock);
*
* Return: pointer to struct fpga_manager or NULL
*/
-struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name,
+struct fpga_manager *fpga_mgr_create(struct device *parent, const char *name,
const struct fpga_manager_ops *mops,
void *priv)
{
@@ -571,12 +571,12 @@ struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name,
if (!mops || !mops->write_complete || !mops->state ||
!mops->write_init || (!mops->write && !mops->write_sg) ||
(mops->write && mops->write_sg)) {
- dev_err(dev, "Attempt to register without fpga_manager_ops\n");
+ dev_err(parent, "Attempt to register without fpga_manager_ops\n");
return NULL;
}
if (!name || !strlen(name)) {
- dev_err(dev, "Attempt to register with no name!\n");
+ dev_err(parent, "Attempt to register with no name!\n");
return NULL;
}
@@ -597,8 +597,8 @@ struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name,
device_initialize(&mgr->dev);
mgr->dev.class = fpga_mgr_class;
mgr->dev.groups = mops->groups;
- mgr->dev.parent = dev;
- mgr->dev.of_node = dev->of_node;
+ mgr->dev.parent = parent;
+ mgr->dev.of_node = parent->of_node;
mgr->dev.id = id;
ret = dev_set_name(&mgr->dev, "fpga%d", id);
@@ -617,7 +617,7 @@ error_kfree:
EXPORT_SYMBOL_GPL(fpga_mgr_create);
/**
- * fpga_mgr_free - free a FPGA manager created with fpga_mgr_create()
+ * fpga_mgr_free - free an FPGA manager created with fpga_mgr_create()
* @mgr: fpga manager struct
*/
void fpga_mgr_free(struct fpga_manager *mgr)
@@ -636,12 +636,12 @@ static void devm_fpga_mgr_release(struct device *dev, void *res)
/**
* devm_fpga_mgr_create - create and initialize a managed FPGA manager struct
- * @dev: fpga manager device from pdev
+ * @parent: fpga manager device from pdev
* @name: fpga manager name
* @mops: pointer to structure of fpga manager ops
* @priv: fpga manager private data
*
- * This function is intended for use in a FPGA manager driver's probe function.
+ * This function is intended for use in an FPGA manager driver's probe function.
* After the manager driver creates the manager struct with
* devm_fpga_mgr_create(), it should register it with fpga_mgr_register(). The
* manager driver's remove function should call fpga_mgr_unregister(). The
@@ -651,7 +651,7 @@ static void devm_fpga_mgr_release(struct device *dev, void *res)
*
* Return: pointer to struct fpga_manager or NULL
*/
-struct fpga_manager *devm_fpga_mgr_create(struct device *dev, const char *name,
+struct fpga_manager *devm_fpga_mgr_create(struct device *parent, const char *name,
const struct fpga_manager_ops *mops,
void *priv)
{
@@ -661,20 +661,20 @@ struct fpga_manager *devm_fpga_mgr_create(struct device *dev, const char *name,
if (!dr)
return NULL;
- dr->mgr = fpga_mgr_create(dev, name, mops, priv);
+ dr->mgr = fpga_mgr_create(parent, name, mops, priv);
if (!dr->mgr) {
devres_free(dr);
return NULL;
}
- devres_add(dev, dr);
+ devres_add(parent, dr);
return dr->mgr;
}
EXPORT_SYMBOL_GPL(devm_fpga_mgr_create);
/**
- * fpga_mgr_register - register a FPGA manager
+ * fpga_mgr_register - register an FPGA manager
* @mgr: fpga manager struct
*
* Return: 0 on success, negative error code otherwise.
@@ -706,10 +706,10 @@ error_device:
EXPORT_SYMBOL_GPL(fpga_mgr_register);
/**
- * fpga_mgr_unregister - unregister a FPGA manager
+ * fpga_mgr_unregister - unregister an FPGA manager
* @mgr: fpga manager struct
*
- * This function is intended for use in a FPGA manager driver's remove function.
+ * This function is intended for use in an FPGA manager driver's remove function.
*/
void fpga_mgr_unregister(struct fpga_manager *mgr)
{
diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c
index c3134b89c3fe..a4838715221f 100644
--- a/drivers/fpga/fpga-region.c
+++ b/drivers/fpga/fpga-region.c
@@ -33,14 +33,14 @@ struct fpga_region *fpga_region_class_find(
EXPORT_SYMBOL_GPL(fpga_region_class_find);
/**
- * fpga_region_get - get an exclusive reference to a fpga region
+ * fpga_region_get - get an exclusive reference to an fpga region
* @region: FPGA Region struct
*
* Caller should call fpga_region_put() when done with region.
*
* Return fpga_region struct if successful.
* Return -EBUSY if someone already has a reference to the region.
- * Return -ENODEV if @np is not a FPGA Region.
+ * Return -ENODEV if @np is not an FPGA Region.
*/
static struct fpga_region *fpga_region_get(struct fpga_region *region)
{
@@ -181,7 +181,7 @@ ATTRIBUTE_GROUPS(fpga_region);
/**
* fpga_region_create - alloc and init a struct fpga_region
- * @dev: device parent
+ * @parent: device parent
* @mgr: manager that programs this region
* @get_bridges: optional function to get bridges to a list
*
@@ -192,7 +192,7 @@ ATTRIBUTE_GROUPS(fpga_region);
* Return: struct fpga_region or NULL
*/
struct fpga_region
-*fpga_region_create(struct device *dev,
+*fpga_region_create(struct device *parent,
struct fpga_manager *mgr,
int (*get_bridges)(struct fpga_region *))
{
@@ -214,8 +214,8 @@ struct fpga_region
device_initialize(&region->dev);
region->dev.class = fpga_region_class;
- region->dev.parent = dev;
- region->dev.of_node = dev->of_node;
+ region->dev.parent = parent;
+ region->dev.of_node = parent->of_node;
region->dev.id = id;
ret = dev_set_name(&region->dev, "region%d", id);
@@ -234,7 +234,7 @@ err_free:
EXPORT_SYMBOL_GPL(fpga_region_create);
/**
- * fpga_region_free - free a FPGA region created by fpga_region_create()
+ * fpga_region_free - free an FPGA region created by fpga_region_create()
* @region: FPGA region
*/
void fpga_region_free(struct fpga_region *region)
@@ -253,11 +253,11 @@ static void devm_fpga_region_release(struct device *dev, void *res)
/**
* devm_fpga_region_create - create and initialize a managed FPGA region struct
- * @dev: device parent
+ * @parent: device parent
* @mgr: manager that programs this region
* @get_bridges: optional function to get bridges to a list
*
- * This function is intended for use in a FPGA region driver's probe function.
+ * This function is intended for use in an FPGA region driver's probe function.
* After the region driver creates the region struct with
* devm_fpga_region_create(), it should register it with fpga_region_register().
* The region driver's remove function should call fpga_region_unregister().
@@ -268,7 +268,7 @@ static void devm_fpga_region_release(struct device *dev, void *res)
* Return: struct fpga_region or NULL
*/
struct fpga_region
-*devm_fpga_region_create(struct device *dev,
+*devm_fpga_region_create(struct device *parent,
struct fpga_manager *mgr,
int (*get_bridges)(struct fpga_region *))
{
@@ -278,12 +278,12 @@ struct fpga_region
if (!ptr)
return NULL;
- region = fpga_region_create(dev, mgr, get_bridges);
+ region = fpga_region_create(parent, mgr, get_bridges);
if (!region) {
devres_free(ptr);
} else {
*ptr = region;
- devres_add(dev, ptr);
+ devres_add(parent, ptr);
}
return region;
@@ -291,7 +291,7 @@ struct fpga_region
EXPORT_SYMBOL_GPL(devm_fpga_region_create);
/**
- * fpga_region_register - register a FPGA region
+ * fpga_region_register - register an FPGA region
* @region: FPGA region
*
* Return: 0 or -errno
@@ -303,10 +303,10 @@ int fpga_region_register(struct fpga_region *region)
EXPORT_SYMBOL_GPL(fpga_region_register);
/**
- * fpga_region_unregister - unregister a FPGA region
+ * fpga_region_unregister - unregister an FPGA region
* @region: FPGA region
*
- * This function is intended for use in a FPGA region driver's remove function.
+ * This function is intended for use in an FPGA region driver's remove function.
*/
void fpga_region_unregister(struct fpga_region *region)
{
diff --git a/drivers/fpga/machxo2-spi.c b/drivers/fpga/machxo2-spi.c
index 114a64d2b7a4..1afb41aa20d7 100644
--- a/drivers/fpga/machxo2-spi.c
+++ b/drivers/fpga/machxo2-spi.c
@@ -374,11 +374,13 @@ static int machxo2_spi_probe(struct spi_device *spi)
return devm_fpga_mgr_register(dev, mgr);
}
+#ifdef CONFIG_OF
static const struct of_device_id of_match[] = {
{ .compatible = "lattice,machxo2-slave-spi", },
{}
};
MODULE_DEVICE_TABLE(of, of_match);
+#endif
static const struct spi_device_id lattice_ids[] = {
{ "machxo2-slave-spi", 0 },
diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c
index e405309baadc..e3c25576b6b9 100644
--- a/drivers/fpga/of-fpga-region.c
+++ b/drivers/fpga/of-fpga-region.c
@@ -181,7 +181,7 @@ static int child_regions_with_firmware(struct device_node *overlay)
* @region: FPGA region
* @overlay: overlay applied to the FPGA region
*
- * Given an overlay applied to a FPGA region, parse the FPGA image specific
+ * Given an overlay applied to an FPGA region, parse the FPGA image specific
* info in the overlay and do some checking.
*
* Returns:
@@ -273,7 +273,7 @@ ret_no_info:
* @region: FPGA region that the overlay was applied to
* @nd: overlay notification data
*
- * Called when an overlay targeted to a FPGA Region is about to be applied.
+ * Called when an overlay targeted to an FPGA Region is about to be applied.
* Parses the overlay for properties that influence how the FPGA will be
* programmed and does some checking. If the checks pass, programs the FPGA.
* If the checks fail, overlay is rejected and does not get added to the
@@ -336,8 +336,8 @@ static void of_fpga_region_notify_post_remove(struct fpga_region *region,
* @action: notifier action
* @arg: reconfig data
*
- * This notifier handles programming a FPGA when a "firmware-name" property is
- * added to a fpga-region.
+ * This notifier handles programming an FPGA when a "firmware-name" property is
+ * added to an fpga-region.
*
* Returns NOTIFY_OK or error if FPGA programming fails.
*/
diff --git a/drivers/fpga/stratix10-soc.c b/drivers/fpga/stratix10-soc.c
index 657a70c5fc99..a2cea500f7cc 100644
--- a/drivers/fpga/stratix10-soc.c
+++ b/drivers/fpga/stratix10-soc.c
@@ -271,7 +271,7 @@ static int s10_send_buf(struct fpga_manager *mgr, const char *buf, size_t count)
}
/*
- * Send a FPGA image to privileged layers to write to the FPGA. When done
+ * Send an FPGA image to privileged layers to write to the FPGA. When done
* sending, free all service layer buffers we allocated in write_init.
*/
static int s10_ops_write(struct fpga_manager *mgr, const char *buf,
@@ -454,6 +454,7 @@ static int s10_remove(struct platform_device *pdev)
struct s10_priv *priv = mgr->priv;
fpga_mgr_unregister(mgr);
+ fpga_mgr_free(mgr);
stratix10_svc_free_channel(priv->chan);
return 0;
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 4e60e84cd17a..59ddc9fd5bca 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -724,7 +724,7 @@ static ssize_t cfam_read(struct file *filep, char __user *buf, size_t count,
rc = count;
fail:
*offset = off;
- return count;
+ return rc;
}
static ssize_t cfam_write(struct file *filep, const char __user *buf,
@@ -761,7 +761,7 @@ static ssize_t cfam_write(struct file *filep, const char __user *buf,
rc = count;
fail:
*offset = off;
- return count;
+ return rc;
}
static loff_t cfam_llseek(struct file *file, loff_t offset, int whence)
diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c
index 90dbe58ca1ed..8606e55c1721 100644
--- a/drivers/fsi/fsi-master-aspeed.c
+++ b/drivers/fsi/fsi-master-aspeed.c
@@ -92,7 +92,7 @@ static const u32 fsi_base = 0xa0000000;
static u16 aspeed_fsi_divisor = FSI_DIVISOR_DEFAULT;
module_param_named(bus_div,aspeed_fsi_divisor, ushort, 0);
-#define OPB_POLL_TIMEOUT 10000
+#define OPB_POLL_TIMEOUT 500
static int __opb_write(struct fsi_master_aspeed *aspeed, u32 addr,
u32 val, u32 transfer_size)
@@ -101,11 +101,15 @@ static int __opb_write(struct fsi_master_aspeed *aspeed, u32 addr,
u32 reg, status;
int ret;
- writel(CMD_WRITE, base + OPB0_RW);
- writel(transfer_size, base + OPB0_XFER_SIZE);
- writel(addr, base + OPB0_FSI_ADDR);
- writel(val, base + OPB0_FSI_DATA_W);
- writel(0x1, base + OPB_IRQ_CLEAR);
+ /*
+ * The ordering of these writes up until the trigger
+ * write does not matter, so use writel_relaxed.
+ */
+ writel_relaxed(CMD_WRITE, base + OPB0_RW);
+ writel_relaxed(transfer_size, base + OPB0_XFER_SIZE);
+ writel_relaxed(addr, base + OPB0_FSI_ADDR);
+ writel_relaxed(val, base + OPB0_FSI_DATA_W);
+ writel_relaxed(0x1, base + OPB_IRQ_CLEAR);
writel(0x1, base + OPB_TRIGGER);
ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg,
@@ -149,10 +153,14 @@ static int __opb_read(struct fsi_master_aspeed *aspeed, uint32_t addr,
u32 result, reg;
int status, ret;
- writel(CMD_READ, base + OPB0_RW);
- writel(transfer_size, base + OPB0_XFER_SIZE);
- writel(addr, base + OPB0_FSI_ADDR);
- writel(0x1, base + OPB_IRQ_CLEAR);
+ /*
+ * The ordering of these writes up until the trigger
+ * write does not matter, so use writel_relaxed.
+ */
+ writel_relaxed(CMD_READ, base + OPB0_RW);
+ writel_relaxed(transfer_size, base + OPB0_XFER_SIZE);
+ writel_relaxed(addr, base + OPB0_FSI_ADDR);
+ writel_relaxed(0x1, base + OPB_IRQ_CLEAR);
writel(0x1, base + OPB_TRIGGER);
ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg,
@@ -525,7 +533,6 @@ static int tacoma_cabled_fsi_fixup(struct device *dev)
static int fsi_master_aspeed_probe(struct platform_device *pdev)
{
struct fsi_master_aspeed *aspeed;
- struct resource *res;
int rc, links, reg;
__be32 raw;
@@ -541,8 +548,7 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev)
aspeed->dev = &pdev->dev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- aspeed->base = devm_ioremap_resource(&pdev->dev, res);
+ aspeed->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(aspeed->base))
return PTR_ERR(aspeed->base);
@@ -645,6 +651,7 @@ static const struct of_device_id fsi_master_aspeed_match[] = {
{ .compatible = "aspeed,ast2600-fsi-master" },
{ },
};
+MODULE_DEVICE_TABLE(of, fsi_master_aspeed_match);
static struct platform_driver fsi_master_aspeed_driver = {
.driver = {
diff --git a/drivers/fsi/fsi-master-ast-cf.c b/drivers/fsi/fsi-master-ast-cf.c
index 57a779a89b07..24292acdbaf8 100644
--- a/drivers/fsi/fsi-master-ast-cf.c
+++ b/drivers/fsi/fsi-master-ast-cf.c
@@ -1309,7 +1309,6 @@ static int fsi_master_acf_probe(struct platform_device *pdev)
master->cf_mem = devm_ioremap_resource(&pdev->dev, &res);
if (IS_ERR(master->cf_mem)) {
rc = PTR_ERR(master->cf_mem);
- dev_err(&pdev->dev, "Error %d mapping coldfire memory\n", rc);
goto err_free;
}
dev_dbg(&pdev->dev, "DRAM allocation @%x\n", master->cf_mem_addr);
@@ -1427,6 +1426,7 @@ static const struct of_device_id fsi_master_acf_match[] = {
{ .compatible = "aspeed,ast2500-cf-fsi-master" },
{ },
};
+MODULE_DEVICE_TABLE(of, fsi_master_acf_match);
static struct platform_driver fsi_master_acf = {
.driver = {
diff --git a/drivers/fsi/fsi-master-gpio.c b/drivers/fsi/fsi-master-gpio.c
index aa97c4a250cb..7d5f29b4b595 100644
--- a/drivers/fsi/fsi-master-gpio.c
+++ b/drivers/fsi/fsi-master-gpio.c
@@ -882,6 +882,7 @@ static const struct of_device_id fsi_master_gpio_match[] = {
{ .compatible = "fsi-master-gpio" },
{ },
};
+MODULE_DEVICE_TABLE(of, fsi_master_gpio_match);
static struct platform_driver fsi_master_gpio_driver = {
.driver = {
diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c
index 10ca2e290655..b223f0ef337b 100644
--- a/drivers/fsi/fsi-occ.c
+++ b/drivers/fsi/fsi-occ.c
@@ -223,7 +223,8 @@ static const struct file_operations occ_fops = {
.release = occ_release,
};
-static int occ_verify_checksum(struct occ_response *resp, u16 data_length)
+static int occ_verify_checksum(struct occ *occ, struct occ_response *resp,
+ u16 data_length)
{
/* Fetch the two bytes after the data for the checksum. */
u16 checksum_resp = get_unaligned_be16(&resp->data[data_length]);
@@ -238,8 +239,11 @@ static int occ_verify_checksum(struct occ_response *resp, u16 data_length)
for (i = 0; i < data_length; ++i)
checksum += resp->data[i];
- if (checksum != checksum_resp)
+ if (checksum != checksum_resp) {
+ dev_err(occ->dev, "Bad checksum: %04x!=%04x\n", checksum,
+ checksum_resp);
return -EBADMSG;
+ }
return 0;
}
@@ -495,6 +499,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
goto done;
if (resp->return_status == OCC_RESP_CMD_IN_PRG ||
+ resp->return_status == OCC_RESP_CRIT_INIT ||
resp->seq_no != seq_no) {
rc = -ETIMEDOUT;
@@ -532,7 +537,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
}
*resp_len = resp_data_length + 7;
- rc = occ_verify_checksum(resp, resp_data_length);
+ rc = occ_verify_checksum(occ, resp, resp_data_length);
done:
mutex_unlock(&occ->occ_lock);
@@ -635,6 +640,7 @@ static const struct of_device_id occ_match[] = {
},
{ },
};
+MODULE_DEVICE_TABLE(of, occ_match);
static struct platform_driver occ_driver = {
.driver = {
diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c
index bfd5e5da8020..84cb965bfed5 100644
--- a/drivers/fsi/fsi-sbefifo.c
+++ b/drivers/fsi/fsi-sbefifo.c
@@ -325,7 +325,8 @@ static int sbefifo_up_write(struct sbefifo *sbefifo, __be32 word)
static int sbefifo_request_reset(struct sbefifo *sbefifo)
{
struct device *dev = &sbefifo->fsi_dev->dev;
- u32 status, timeout;
+ unsigned long end_time;
+ u32 status;
int rc;
dev_dbg(dev, "Requesting FIFO reset\n");
@@ -341,7 +342,8 @@ static int sbefifo_request_reset(struct sbefifo *sbefifo)
}
/* Wait for it to complete */
- for (timeout = 0; timeout < SBEFIFO_RESET_TIMEOUT; timeout++) {
+ end_time = jiffies + msecs_to_jiffies(SBEFIFO_RESET_TIMEOUT);
+ while (!time_after(jiffies, end_time)) {
rc = sbefifo_regr(sbefifo, SBEFIFO_UP | SBEFIFO_STS, &status);
if (rc) {
dev_err(dev, "Failed to read UP fifo status during reset"
@@ -355,7 +357,7 @@ static int sbefifo_request_reset(struct sbefifo *sbefifo)
return 0;
}
- msleep(1);
+ cond_resched();
}
dev_err(dev, "FIFO reset timed out\n");
@@ -400,7 +402,7 @@ static int sbefifo_cleanup_hw(struct sbefifo *sbefifo)
/* The FIFO already contains a reset request from the SBE ? */
if (down_status & SBEFIFO_STS_RESET_REQ) {
dev_info(dev, "Cleanup: FIFO reset request set, resetting\n");
- rc = sbefifo_regw(sbefifo, SBEFIFO_UP, SBEFIFO_PERFORM_RESET);
+ rc = sbefifo_regw(sbefifo, SBEFIFO_DOWN, SBEFIFO_PERFORM_RESET);
if (rc) {
sbefifo->broken = true;
dev_err(dev, "Cleanup: Reset reg write failed, rc=%d\n", rc);
diff --git a/drivers/fsi/fsi-scom.c b/drivers/fsi/fsi-scom.c
index b45bfab7b7f5..da1486bb6a14 100644
--- a/drivers/fsi/fsi-scom.c
+++ b/drivers/fsi/fsi-scom.c
@@ -38,9 +38,10 @@
#define SCOM_STATUS_PIB_RESP_MASK 0x00007000
#define SCOM_STATUS_PIB_RESP_SHIFT 12
-#define SCOM_STATUS_ANY_ERR (SCOM_STATUS_PROTECTION | \
- SCOM_STATUS_PARITY | \
- SCOM_STATUS_PIB_ABORT | \
+#define SCOM_STATUS_FSI2PIB_ERROR (SCOM_STATUS_PROTECTION | \
+ SCOM_STATUS_PARITY | \
+ SCOM_STATUS_PIB_ABORT)
+#define SCOM_STATUS_ANY_ERR (SCOM_STATUS_FSI2PIB_ERROR | \
SCOM_STATUS_PIB_RESP_MASK)
/* SCOM address encodings */
#define XSCOM_ADDR_IND_FLAG BIT_ULL(63)
@@ -60,7 +61,6 @@
#define XSCOM_ADDR_FORM1_HI_SHIFT 20
/* Retries */
-#define SCOM_MAX_RETRIES 100 /* Retries on busy */
#define SCOM_MAX_IND_RETRIES 10 /* Retries indirect not ready */
struct scom_device {
@@ -240,14 +240,15 @@ static int handle_fsi2pib_status(struct scom_device *scom, uint32_t status)
{
uint32_t dummy = -1;
- if (status & SCOM_STATUS_PROTECTION)
- return -EPERM;
- if (status & SCOM_STATUS_PARITY) {
+ if (status & SCOM_STATUS_FSI2PIB_ERROR)
fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
sizeof(uint32_t));
+
+ if (status & SCOM_STATUS_PROTECTION)
+ return -EPERM;
+ if (status & SCOM_STATUS_PARITY)
return -EIO;
- }
- /* Return -EBUSY on PIB abort to force a retry */
+
if (status & SCOM_STATUS_PIB_ABORT)
return -EBUSY;
return 0;
@@ -284,69 +285,39 @@ static int handle_pib_status(struct scom_device *scom, uint8_t status)
static int put_scom(struct scom_device *scom, uint64_t value,
uint64_t addr)
{
- uint32_t status, dummy = -1;
- int rc, retries;
-
- for (retries = 0; retries < SCOM_MAX_RETRIES; retries++) {
- rc = raw_put_scom(scom, value, addr, &status);
- if (rc) {
- /* Try resetting the bridge if FSI fails */
- if (rc != -ENODEV && retries == 0) {
- fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG,
- &dummy, sizeof(uint32_t));
- rc = -EBUSY;
- } else
- return rc;
- } else
- rc = handle_fsi2pib_status(scom, status);
- if (rc && rc != -EBUSY)
- break;
- if (rc == 0) {
- rc = handle_pib_status(scom,
- (status & SCOM_STATUS_PIB_RESP_MASK)
- >> SCOM_STATUS_PIB_RESP_SHIFT);
- if (rc && rc != -EBUSY)
- break;
- }
- if (rc == 0)
- break;
- msleep(1);
- }
- return rc;
+ uint32_t status;
+ int rc;
+
+ rc = raw_put_scom(scom, value, addr, &status);
+ if (rc == -ENODEV)
+ return rc;
+
+ rc = handle_fsi2pib_status(scom, status);
+ if (rc)
+ return rc;
+
+ return handle_pib_status(scom,
+ (status & SCOM_STATUS_PIB_RESP_MASK)
+ >> SCOM_STATUS_PIB_RESP_SHIFT);
}
static int get_scom(struct scom_device *scom, uint64_t *value,
uint64_t addr)
{
- uint32_t status, dummy = -1;
- int rc, retries;
-
- for (retries = 0; retries < SCOM_MAX_RETRIES; retries++) {
- rc = raw_get_scom(scom, value, addr, &status);
- if (rc) {
- /* Try resetting the bridge if FSI fails */
- if (rc != -ENODEV && retries == 0) {
- fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG,
- &dummy, sizeof(uint32_t));
- rc = -EBUSY;
- } else
- return rc;
- } else
- rc = handle_fsi2pib_status(scom, status);
- if (rc && rc != -EBUSY)
- break;
- if (rc == 0) {
- rc = handle_pib_status(scom,
- (status & SCOM_STATUS_PIB_RESP_MASK)
- >> SCOM_STATUS_PIB_RESP_SHIFT);
- if (rc && rc != -EBUSY)
- break;
- }
- if (rc == 0)
- break;
- msleep(1);
- }
- return rc;
+ uint32_t status;
+ int rc;
+
+ rc = raw_get_scom(scom, value, addr, &status);
+ if (rc == -ENODEV)
+ return rc;
+
+ rc = handle_fsi2pib_status(scom, status);
+ if (rc)
+ return rc;
+
+ return handle_pib_status(scom,
+ (status & SCOM_STATUS_PIB_RESP_MASK)
+ >> SCOM_STATUS_PIB_RESP_SHIFT);
}
static ssize_t scom_read(struct file *filep, char __user *buf, size_t len,
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 1dd0ec6727fd..fab571016adf 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -782,6 +782,18 @@ config GPIO_MSC313
Say Y here to support the main GPIO block on MStar/SigmaStar
ARMv7 based SoCs.
+config GPIO_IDT3243X
+ tristate "IDT 79RC3243X GPIO support"
+ depends on MIKROTIK_RB532 || COMPILE_TEST
+ select GPIO_GENERIC
+ select GPIOLIB_IRQCHIP
+ help
+ Select this option to enable GPIO driver for
+ IDT 79RC3243X based devices like Mikrotik RB532.
+
+ To compile this driver as a module, choose M here: the module will
+ be called gpio-idt3243x.
+
endmenu
menu "Port-mapped I/O GPIO drivers"
@@ -1367,7 +1379,7 @@ config GPIO_TPS65912
config GPIO_TPS68470
bool "TPS68470 GPIO"
- depends on MFD_TPS68470
+ depends on INTEL_SKL_INT3472
help
Select this option to enable GPIO driver for the TPS68470
chip family.
@@ -1383,6 +1395,7 @@ config GPIO_TPS68470
config GPIO_TQMX86
tristate "TQ-Systems QTMX86 GPIO"
depends on MFD_TQMX86 || COMPILE_TEST
+ depends on HAS_IOPORT_MAP
select GPIOLIB_IRQCHIP
help
This driver supports GPIO on the TQMX86 IO controller.
@@ -1450,6 +1463,7 @@ menu "PCI GPIO expanders"
config GPIO_AMD8111
tristate "AMD 8111 GPIO driver"
depends on X86 || COMPILE_TEST
+ depends on HAS_IOPORT_MAP
help
The AMD 8111 south bridge contains 32 GPIO pins which can be used.
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index d7c81e1611a4..32a32659866a 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_GPIO_HISI) += gpio-hisi.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_IDT3243X) += gpio-idt3243x.o
obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c
index 50ad0280fd78..55b40299ebfa 100644
--- a/drivers/gpio/gpio-104-idio-16.c
+++ b/drivers/gpio/gpio-104-idio-16.c
@@ -44,11 +44,12 @@ struct idio_16_gpio {
struct gpio_chip chip;
raw_spinlock_t lock;
unsigned long irq_mask;
- unsigned base;
- unsigned out_state;
+ unsigned int base;
+ unsigned int out_state;
};
-static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+static int idio_16_gpio_get_direction(struct gpio_chip *chip,
+ unsigned int offset)
{
if (offset > 15)
return GPIO_LINE_DIRECTION_IN;
@@ -56,22 +57,23 @@ static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
return GPIO_LINE_DIRECTION_OUT;
}
-static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+static int idio_16_gpio_direction_input(struct gpio_chip *chip,
+ unsigned int offset)
{
return 0;
}
static int idio_16_gpio_direction_output(struct gpio_chip *chip,
- unsigned offset, int value)
+ unsigned int offset, int value)
{
chip->set(chip, offset, value);
return 0;
}
-static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
+static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
- const unsigned mask = BIT(offset-16);
+ const unsigned int mask = BIT(offset-16);
if (offset < 16)
return -EINVAL;
@@ -96,10 +98,11 @@ static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
return 0;
}
-static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
- const unsigned mask = BIT(offset);
+ const unsigned int mask = BIT(offset);
unsigned long flags;
if (offset > 15)
@@ -180,7 +183,7 @@ static void idio_16_irq_unmask(struct irq_data *data)
}
}
-static int idio_16_irq_set_type(struct irq_data *data, unsigned flow_type)
+static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type)
{
/* The only valid irq types are none and both-edges */
if (flow_type != IRQ_TYPE_NONE &&
diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c
index 0386ede53f3a..c55e821c63b6 100644
--- a/drivers/gpio/gpio-adp5520.c
+++ b/drivers/gpio/gpio-adp5520.c
@@ -113,10 +113,8 @@ static int adp5520_gpio_probe(struct platform_device *pdev)
if (pdata->gpio_en_mask & (1 << i))
dev->lut[gpios++] = 1 << i;
- if (gpios < 1) {
- ret = -EINVAL;
- goto err;
- }
+ if (gpios < 1)
+ return -EINVAL;
gc = &dev->gpio_chip;
gc->direction_input = adp5520_gpio_direction_input;
@@ -148,18 +146,10 @@ static int adp5520_gpio_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "failed to write\n");
- goto err;
+ return ret;
}
- ret = devm_gpiochip_add_data(&pdev->dev, &dev->gpio_chip, dev);
- if (ret)
- goto err;
-
- platform_set_drvdata(pdev, dev);
- return 0;
-
-err:
- return ret;
+ return devm_gpiochip_add_data(&pdev->dev, &dev->gpio_chip, dev);
}
static struct platform_driver adp5520_gpio_driver = {
diff --git a/drivers/gpio/gpio-altera-a10sr.c b/drivers/gpio/gpio-altera-a10sr.c
index b5917c48e4dc..6af51feda06f 100644
--- a/drivers/gpio/gpio-altera-a10sr.c
+++ b/drivers/gpio/gpio-altera-a10sr.c
@@ -78,7 +78,6 @@ static const struct gpio_chip altr_a10sr_gc = {
static int altr_a10sr_gpio_probe(struct platform_device *pdev)
{
struct altr_a10sr_gpio *gpio;
- int ret;
struct altr_a10sr *a10sr = dev_get_drvdata(pdev->dev.parent);
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
@@ -91,15 +90,7 @@ static int altr_a10sr_gpio_probe(struct platform_device *pdev)
gpio->gp.parent = pdev->dev.parent;
gpio->gp.of_node = pdev->dev.of_node;
- ret = devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio);
- if (ret < 0) {
- dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, gpio);
-
- return 0;
+ return devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio);
}
static const struct of_device_id altr_a10sr_gpio_of_match[] = {
diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index 678ddd375891..9b780dc5d390 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -234,7 +234,6 @@ static int ath79_gpio_probe(struct platform_device *pdev)
ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
return -ENOMEM;
- platform_set_drvdata(pdev, ctrl);
if (np) {
err = of_property_read_u32(np, "ngpios", &ath79_gpio_count);
@@ -290,13 +289,7 @@ static int ath79_gpio_probe(struct platform_device *pdev)
girq->handler = handle_simple_irq;
}
- err = devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
- if (err) {
- dev_err(dev,
- "cannot add AR71xx GPIO chip, error=%d", err);
- return err;
- }
- return 0;
+ return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
}
static struct platform_driver ath79_gpio_driver = {
diff --git a/drivers/gpio/gpio-bd9571mwv.c b/drivers/gpio/gpio-bd9571mwv.c
index df6102b57734..9a4d55f703bb 100644
--- a/drivers/gpio/gpio-bd9571mwv.c
+++ b/drivers/gpio/gpio-bd9571mwv.c
@@ -97,25 +97,16 @@ static const struct gpio_chip template_chip = {
static int bd9571mwv_gpio_probe(struct platform_device *pdev)
{
struct bd9571mwv_gpio *gpio;
- int ret;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
return -ENOMEM;
- platform_set_drvdata(pdev, gpio);
-
gpio->regmap = dev_get_regmap(pdev->dev.parent, NULL);
gpio->chip = template_chip;
gpio->chip.parent = pdev->dev.parent;
- ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
- if (ret < 0) {
- dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
- return ret;
- }
-
- return 0;
+ return devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
}
static const struct platform_device_id bd9571mwv_gpio_id_table[] = {
diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c
index 2ba225720086..5a909f3c79e8 100644
--- a/drivers/gpio/gpio-crystalcove.c
+++ b/drivers/gpio/gpio-crystalcove.c
@@ -339,8 +339,6 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
if (!cg)
return -ENOMEM;
- platform_set_drvdata(pdev, cg);
-
mutex_init(&cg->buslock);
cg->chip.label = KBUILD_MODNAME;
cg->chip.direction_input = crystalcove_gpio_dir_in;
@@ -372,13 +370,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
return retval;
}
- retval = devm_gpiochip_add_data(&pdev->dev, &cg->chip, cg);
- if (retval) {
- dev_warn(&pdev->dev, "add gpio chip error: %d\n", retval);
- return retval;
- }
-
- return 0;
+ return devm_gpiochip_add_data(&pdev->dev, &cg->chip, cg);
}
static struct platform_driver crystalcove_gpio_driver = {
diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c
index 9aa59afdcbbf..559188d80c2b 100644
--- a/drivers/gpio/gpio-da9052.c
+++ b/drivers/gpio/gpio-da9052.c
@@ -196,7 +196,6 @@ static int da9052_gpio_probe(struct platform_device *pdev)
{
struct da9052_gpio *gpio;
struct da9052_pdata *pdata;
- int ret;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
@@ -209,15 +208,7 @@ static int da9052_gpio_probe(struct platform_device *pdev)
if (pdata && pdata->gpio_base)
gpio->gp.base = pdata->gpio_base;
- ret = devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio);
- if (ret < 0) {
- dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, gpio);
-
- return 0;
+ return devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio);
}
static struct platform_driver da9052_gpio_driver = {
diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c
index 6ad0c37b862e..49446a030f10 100644
--- a/drivers/gpio/gpio-da9055.c
+++ b/drivers/gpio/gpio-da9055.c
@@ -133,7 +133,6 @@ static int da9055_gpio_probe(struct platform_device *pdev)
{
struct da9055_gpio *gpio;
struct da9055_pdata *pdata;
- int ret;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
@@ -146,15 +145,7 @@ static int da9055_gpio_probe(struct platform_device *pdev)
if (pdata && pdata->gpio_base)
gpio->gp.base = pdata->gpio_base;
- ret = devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio);
- if (ret < 0) {
- dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, gpio);
-
- return 0;
+ return devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio);
}
static struct platform_driver da9055_gpio_driver = {
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index d3233cc4b76b..3eb13d6d31ef 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -13,17 +13,15 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/irq.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
+#include <linux/platform_data/gpio-dwapb.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/reset.h>
-#include <linux/spinlock.h>
-#include <linux/platform_data/gpio-dwapb.h>
#include <linux/slab.h>
+#include <linux/spinlock.h>
#include "gpiolib.h"
#include "gpiolib-acpi.h"
@@ -297,9 +295,6 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
irq_hw_number_t bit = irqd_to_hwirq(d);
unsigned long level, polarity, flags;
- if (type & ~IRQ_TYPE_SENSE_MASK)
- return -EINVAL;
-
spin_lock_irqsave(&gc->bgpio_lock, flags);
level = dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
polarity = dwapb_read(gpio, GPIO_INT_POLARITY);
@@ -531,17 +526,13 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
static void dwapb_get_irq(struct device *dev, struct fwnode_handle *fwnode,
struct dwapb_port_property *pp)
{
- struct device_node *np = NULL;
- int irq = -ENXIO, j;
-
- if (fwnode_property_read_bool(fwnode, "interrupt-controller"))
- np = to_of_node(fwnode);
+ int irq, j;
for (j = 0; j < pp->ngpio; j++) {
- if (np)
- irq = of_irq_get(np, j);
- else if (has_acpi_companion(dev))
+ if (has_acpi_companion(dev))
irq = platform_get_irq_optional(to_platform_device(dev), j);
+ else
+ irq = fwnode_irq_get(fwnode, j);
if (irq > 0)
pp->irq[j] = irq;
}
diff --git a/drivers/gpio/gpio-idt3243x.c b/drivers/gpio/gpio-idt3243x.c
new file mode 100644
index 000000000000..50003ad2e589
--- /dev/null
+++ b/drivers/gpio/gpio-idt3243x.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Driver for IDT/Renesas 79RC3243x Interrupt Controller */
+
+#include <linux/bitops.h>
+#include <linux/gpio/driver.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#define IDT_PIC_IRQ_PEND 0x00
+#define IDT_PIC_IRQ_MASK 0x08
+
+#define IDT_GPIO_DIR 0x00
+#define IDT_GPIO_DATA 0x04
+#define IDT_GPIO_ILEVEL 0x08
+#define IDT_GPIO_ISTAT 0x0C
+
+struct idt_gpio_ctrl {
+ struct gpio_chip gc;
+ void __iomem *pic;
+ void __iomem *gpio;
+ u32 mask_cache;
+};
+
+static void idt_gpio_dispatch(struct irq_desc *desc)
+{
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+ struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc);
+ struct irq_chip *host_chip = irq_desc_get_chip(desc);
+ unsigned int bit, virq;
+ unsigned long pending;
+
+ chained_irq_enter(host_chip, desc);
+
+ pending = readl(ctrl->pic + IDT_PIC_IRQ_PEND);
+ pending &= ~ctrl->mask_cache;
+ for_each_set_bit(bit, &pending, gc->ngpio) {
+ virq = irq_linear_revmap(gc->irq.domain, bit);
+ if (virq)
+ generic_handle_irq(virq);
+ }
+
+ chained_irq_exit(host_chip, desc);
+}
+
+static int idt_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc);
+ unsigned int sense = flow_type & IRQ_TYPE_SENSE_MASK;
+ unsigned long flags;
+ u32 ilevel;
+
+ /* hardware only supports level triggered */
+ if (sense == IRQ_TYPE_NONE || (sense & IRQ_TYPE_EDGE_BOTH))
+ return -EINVAL;
+
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
+
+ ilevel = readl(ctrl->gpio + IDT_GPIO_ILEVEL);
+ if (sense & IRQ_TYPE_LEVEL_HIGH)
+ ilevel |= BIT(d->hwirq);
+ else if (sense & IRQ_TYPE_LEVEL_LOW)
+ ilevel &= ~BIT(d->hwirq);
+
+ writel(ilevel, ctrl->gpio + IDT_GPIO_ILEVEL);
+ irq_set_handler_locked(d, handle_level_irq);
+
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+ return 0;
+}
+
+static void idt_gpio_ack(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc);
+
+ writel(~BIT(d->hwirq), ctrl->gpio + IDT_GPIO_ISTAT);
+}
+
+static void idt_gpio_mask(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
+
+ ctrl->mask_cache |= BIT(d->hwirq);
+ writel(ctrl->mask_cache, ctrl->pic + IDT_PIC_IRQ_MASK);
+
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+}
+
+static void idt_gpio_unmask(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
+
+ ctrl->mask_cache &= ~BIT(d->hwirq);
+ writel(ctrl->mask_cache, ctrl->pic + IDT_PIC_IRQ_MASK);
+
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+}
+
+static int idt_gpio_irq_init_hw(struct gpio_chip *gc)
+{
+ struct idt_gpio_ctrl *ctrl = gpiochip_get_data(gc);
+
+ /* Mask interrupts. */
+ ctrl->mask_cache = 0xffffffff;
+ writel(ctrl->mask_cache, ctrl->pic + IDT_PIC_IRQ_MASK);
+
+ return 0;
+}
+
+static struct irq_chip idt_gpio_irqchip = {
+ .name = "IDTGPIO",
+ .irq_mask = idt_gpio_mask,
+ .irq_ack = idt_gpio_ack,
+ .irq_unmask = idt_gpio_unmask,
+ .irq_set_type = idt_gpio_irq_set_type
+};
+
+static int idt_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct gpio_irq_chip *girq;
+ struct idt_gpio_ctrl *ctrl;
+ unsigned int parent_irq;
+ int ngpios;
+ int ret;
+
+
+ ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl)
+ return -ENOMEM;
+
+ ctrl->gpio = devm_platform_ioremap_resource_byname(pdev, "gpio");
+ if (IS_ERR(ctrl->gpio))
+ return PTR_ERR(ctrl->gpio);
+
+ ctrl->gc.parent = dev;
+
+ ret = bgpio_init(&ctrl->gc, &pdev->dev, 4, ctrl->gpio + IDT_GPIO_DATA,
+ NULL, NULL, ctrl->gpio + IDT_GPIO_DIR, NULL, 0);
+ if (ret) {
+ dev_err(dev, "bgpio_init failed\n");
+ return ret;
+ }
+
+ ret = device_property_read_u32(dev, "ngpios", &ngpios);
+ if (!ret)
+ ctrl->gc.ngpio = ngpios;
+
+ if (device_property_read_bool(dev, "interrupt-controller")) {
+ ctrl->pic = devm_platform_ioremap_resource_byname(pdev, "pic");
+ if (IS_ERR(ctrl->pic))
+ return PTR_ERR(ctrl->pic);
+
+ parent_irq = platform_get_irq(pdev, 0);
+ if (!parent_irq)
+ return -EINVAL;
+
+ girq = &ctrl->gc.irq;
+ girq->chip = &idt_gpio_irqchip;
+ girq->init_hw = idt_gpio_irq_init_hw;
+ girq->parent_handler = idt_gpio_dispatch;
+ girq->num_parents = 1;
+ girq->parents = devm_kcalloc(dev, girq->num_parents,
+ sizeof(*girq->parents),
+ GFP_KERNEL);
+ if (!girq->parents)
+ return -ENOMEM;
+
+ girq->parents[0] = parent_irq;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_bad_irq;
+ }
+
+ return devm_gpiochip_add_data(&pdev->dev, &ctrl->gc, ctrl);
+}
+
+static const struct of_device_id idt_gpio_of_match[] = {
+ { .compatible = "idt,32434-gpio" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, idt_gpio_of_match);
+
+static struct platform_driver idt_gpio_driver = {
+ .probe = idt_gpio_probe,
+ .driver = {
+ .name = "idt3243x-gpio",
+ .of_match_table = idt_gpio_of_match,
+ },
+};
+module_platform_driver(idt_gpio_driver);
+
+MODULE_DESCRIPTION("IDT 79RC3243x GPIO/PIC Driver");
+MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-logicvc.c b/drivers/gpio/gpio-logicvc.c
index 015632cf159f..992cc958a43f 100644
--- a/drivers/gpio/gpio-logicvc.c
+++ b/drivers/gpio/gpio-logicvc.c
@@ -114,10 +114,8 @@ static int logicvc_gpio_probe(struct platform_device *pdev)
}
base = devm_ioremap_resource(dev, &res);
- if (IS_ERR(base)) {
- dev_err(dev, "Failed to map I/O base\n");
+ if (IS_ERR(base))
return PTR_ERR(base);
- }
logicvc_gpio_regmap_config.max_register = resource_size(&res) -
logicvc_gpio_regmap_config.reg_stride;
diff --git a/drivers/gpio/gpio-lp87565.c b/drivers/gpio/gpio-lp87565.c
index e1244520cf7d..fcde6708b5df 100644
--- a/drivers/gpio/gpio-lp87565.c
+++ b/drivers/gpio/gpio-lp87565.c
@@ -123,14 +123,14 @@ static int lp87565_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
return regmap_update_bits(gpio->map,
LP87565_REG_GPIO_CONFIG,
BIT(offset +
- __ffs(LP87565_GOIO1_OD)),
+ __ffs(LP87565_GPIO1_OD)),
BIT(offset +
- __ffs(LP87565_GOIO1_OD)));
+ __ffs(LP87565_GPIO1_OD)));
case PIN_CONFIG_DRIVE_PUSH_PULL:
return regmap_update_bits(gpio->map,
LP87565_REG_GPIO_CONFIG,
BIT(offset +
- __ffs(LP87565_GOIO1_OD)), 0);
+ __ffs(LP87565_GPIO1_OD)), 0);
default:
return -ENOTSUPP;
}
diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c
index d7e73876a3b9..0a9d746a0fe0 100644
--- a/drivers/gpio/gpio-mockup.c
+++ b/drivers/gpio/gpio-mockup.c
@@ -144,12 +144,9 @@ static void gpio_mockup_set_multiple(struct gpio_chip *gc,
static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip,
unsigned int offset, int value)
{
+ struct gpio_chip *gc = &chip->gc;
+ struct gpio_desc *desc = gpiochip_get_desc(gc, offset);
int curr, irq, irq_type, ret = 0;
- struct gpio_desc *desc;
- struct gpio_chip *gc;
-
- gc = &chip->gc;
- desc = &gc->gpiodev->descs[offset];
mutex_lock(&chip->lock);
@@ -369,7 +366,7 @@ static void gpio_mockup_debugfs_setup(struct device *dev,
priv->chip = chip;
priv->offset = i;
- priv->desc = &gc->gpiodev->descs[i];
+ priv->desc = gpiochip_get_desc(gc, i);
debugfs_create_file(name, 0200, chip->dbg_dir, priv,
&gpio_mockup_debugfs_ops);
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 157106e1e438..b9fdf05d7669 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -334,7 +334,7 @@ static int mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base)
ct->chip.irq_unmask = irq_gc_mask_set_bit;
ct->chip.irq_set_type = gpio_set_irq_type;
ct->chip.irq_set_wake = gpio_set_wake_irq;
- ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND;
+ ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND;
ct->regs.ack = GPIO_ISR;
ct->regs.mask = GPIO_IMR;
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index 524b668eb1ac..31a336b86ff2 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -229,14 +229,14 @@ static int mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
return rv;
}
-static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
{
struct mxs_gpio_port *port = gpiochip_get_data(gc);
return irq_find_mapping(port->domain, offset);
}
-static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
+static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{
struct mxs_gpio_port *port = gpiochip_get_data(gc);
u32 mask = 1 << offset;
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index c91d05651596..f5cfc0698799 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -1241,6 +1241,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "onnn,cat9554", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "onnn,pca9654", .data = OF_953X( 8, PCA_INT), },
+ { .compatible = "onnn,pca9655", .data = OF_953X(16, PCA_INT), },
{ .compatible = "exar,xra1202", .data = OF_953X( 8, 0), },
{ }
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index 134cedf151a7..69c219742083 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -178,12 +178,6 @@ static int gpio_regmap_direction_output(struct gpio_chip *chip,
return gpio_regmap_set_direction(chip, offset, true);
}
-void gpio_regmap_set_drvdata(struct gpio_regmap *gpio, void *data)
-{
- gpio->driver_data = data;
-}
-EXPORT_SYMBOL_GPL(gpio_regmap_set_drvdata);
-
void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio)
{
return gpio->driver_data;
@@ -226,6 +220,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
return ERR_PTR(-ENOMEM);
gpio->parent = config->parent;
+ gpio->driver_data = config->drvdata;
gpio->regmap = config->regmap;
gpio->ngpio_per_reg = config->ngpio_per_reg;
gpio->reg_stride = config->reg_stride;
@@ -311,9 +306,9 @@ void gpio_regmap_unregister(struct gpio_regmap *gpio)
}
EXPORT_SYMBOL_GPL(gpio_regmap_unregister);
-static void devm_gpio_regmap_unregister(struct device *dev, void *res)
+static void devm_gpio_regmap_unregister(void *res)
{
- gpio_regmap_unregister(*(struct gpio_regmap **)res);
+ gpio_regmap_unregister(res);
}
/**
@@ -330,20 +325,17 @@ static void devm_gpio_regmap_unregister(struct device *dev, void *res)
struct gpio_regmap *devm_gpio_regmap_register(struct device *dev,
const struct gpio_regmap_config *config)
{
- struct gpio_regmap **ptr, *gpio;
-
- ptr = devres_alloc(devm_gpio_regmap_unregister, sizeof(*ptr),
- GFP_KERNEL);
- if (!ptr)
- return ERR_PTR(-ENOMEM);
+ struct gpio_regmap *gpio;
+ int ret;
gpio = gpio_regmap_register(config);
- if (!IS_ERR(gpio)) {
- *ptr = gpio;
- devres_add(dev, ptr);
- } else {
- devres_free(ptr);
- }
+
+ if (IS_ERR(gpio))
+ return gpio;
+
+ ret = devm_add_action_or_reset(dev, devm_gpio_regmap_unregister, gpio);
+ if (ret)
+ return ERR_PTR(ret);
return gpio;
}
diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c
index 6eca531b7d96..49aac2bb8d2c 100644
--- a/drivers/gpio/gpio-spear-spics.c
+++ b/drivers/gpio/gpio-spear-spics.c
@@ -122,7 +122,6 @@ static int spics_gpio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct spear_spics *spics;
- int ret;
spics = devm_kzalloc(&pdev->dev, sizeof(*spics), GFP_KERNEL);
if (!spics)
@@ -148,8 +147,6 @@ static int spics_gpio_probe(struct platform_device *pdev)
&spics->cs_enable_shift))
goto err_dt_data;
- platform_set_drvdata(pdev, spics);
-
spics->chip.ngpio = NUM_OF_GPIO;
spics->chip.base = -1;
spics->chip.request = spics_request;
@@ -163,14 +160,7 @@ static int spics_gpio_probe(struct platform_device *pdev)
spics->chip.owner = THIS_MODULE;
spics->last_off = -1;
- ret = devm_gpiochip_add_data(&pdev->dev, &spics->chip, spics);
- if (ret) {
- dev_err(&pdev->dev, "unable to add gpio chip\n");
- return ret;
- }
-
- dev_info(&pdev->dev, "spear spics registered\n");
- return 0;
+ return devm_gpiochip_add_data(&pdev->dev, &spics->chip, spics);
err_dt_data:
dev_err(&pdev->dev, "DT probe failed\n");
diff --git a/drivers/gpio/gpio-sprd.c b/drivers/gpio/gpio-sprd.c
index 36ea8a3bd451..25c37edcbc6c 100644
--- a/drivers/gpio/gpio-sprd.c
+++ b/drivers/gpio/gpio-sprd.c
@@ -222,7 +222,6 @@ static int sprd_gpio_probe(struct platform_device *pdev)
{
struct gpio_irq_chip *irq;
struct sprd_gpio *sprd_gpio;
- int ret;
sprd_gpio = devm_kzalloc(&pdev->dev, sizeof(*sprd_gpio), GFP_KERNEL);
if (!sprd_gpio)
@@ -259,14 +258,7 @@ static int sprd_gpio_probe(struct platform_device *pdev)
irq->num_parents = 1;
irq->parents = &sprd_gpio->irq;
- ret = devm_gpiochip_add_data(&pdev->dev, &sprd_gpio->chip, sprd_gpio);
- if (ret < 0) {
- dev_err(&pdev->dev, "Could not register gpiochip %d\n", ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, sprd_gpio);
- return 0;
+ return devm_gpiochip_add_data(&pdev->dev, &sprd_gpio->chip, sprd_gpio);
}
static const struct of_device_id sprd_gpio_of_match[] = {
diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c
index a74bb97a41e2..392fcab06ab8 100644
--- a/drivers/gpio/gpio-sta2x11.c
+++ b/drivers/gpio/gpio-sta2x11.c
@@ -398,15 +398,7 @@ static int gsta_probe(struct platform_device *dev)
return err;
}
- err = devm_gpiochip_add_data(&dev->dev, &chip->gpio, chip);
- if (err < 0) {
- dev_err(&dev->dev, "sta2x11 gpio: Can't register (%i)\n",
- -err);
- return err;
- }
-
- platform_set_drvdata(dev, chip);
- return 0;
+ return devm_gpiochip_add_data(&dev->dev, &chip->gpio, chip);
}
static struct platform_driver sta2x11_gpio_platform_driver = {
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index b94ef8181428..dd4d58b4ae49 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -449,6 +449,11 @@ static void stmpe_init_irq_valid_mask(struct gpio_chip *gc,
}
}
+static void stmpe_gpio_disable(void *stmpe)
+{
+ stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
+}
+
static int stmpe_gpio_probe(struct platform_device *pdev)
{
struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
@@ -461,7 +466,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
return -EINVAL;
}
- stmpe_gpio = kzalloc(sizeof(*stmpe_gpio), GFP_KERNEL);
+ stmpe_gpio = devm_kzalloc(&pdev->dev, sizeof(*stmpe_gpio), GFP_KERNEL);
if (!stmpe_gpio)
return -ENOMEM;
@@ -489,7 +494,11 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
if (ret)
- goto out_free;
+ return ret;
+
+ ret = devm_add_action_or_reset(&pdev->dev, stmpe_gpio_disable, stmpe);
+ if (ret)
+ return ret;
if (irq > 0) {
struct gpio_irq_chip *girq;
@@ -499,7 +508,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
"stmpe-gpio", stmpe_gpio);
if (ret) {
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
- goto out_disable;
+ return ret;
}
girq = &stmpe_gpio->chip.irq;
@@ -514,22 +523,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
girq->init_valid_mask = stmpe_init_irq_valid_mask;
}
- ret = gpiochip_add_data(&stmpe_gpio->chip, stmpe_gpio);
- if (ret) {
- dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
- goto out_disable;
- }
-
- platform_set_drvdata(pdev, stmpe_gpio);
-
- return 0;
-
-out_disable:
- stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
- gpiochip_remove(&stmpe_gpio->chip);
-out_free:
- kfree(stmpe_gpio);
- return ret;
+ return devm_gpiochip_add_data(&pdev->dev, &stmpe_gpio->chip, stmpe_gpio);
}
static struct platform_driver stmpe_gpio_driver = {
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index 55b8dbd13d11..8d158492488f 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -357,16 +357,7 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
return ret;
}
- ret = devm_gpiochip_add_data(&pdev->dev, &tc3589x_gpio->chip,
- tc3589x_gpio);
- if (ret) {
- dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, tc3589x_gpio);
-
- return 0;
+ return devm_gpiochip_add_data(&pdev->dev, &tc3589x_gpio->chip, tc3589x_gpio);
}
static struct platform_driver tc3589x_gpio_driver = {
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index 05974b760796..d38980b9923a 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -730,18 +730,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
offset += port->pins;
}
- platform_set_drvdata(pdev, gpio);
-
- err = devm_gpiochip_add_data(&pdev->dev, &gpio->gpio, gpio);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int tegra186_gpio_remove(struct platform_device *pdev)
-{
- return 0;
+ return devm_gpiochip_add_data(&pdev->dev, &gpio->gpio, gpio);
}
#define TEGRA186_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
@@ -913,7 +902,6 @@ static struct platform_driver tegra186_gpio_driver = {
.of_match_table = tegra186_gpio_of_match,
},
.probe = tegra186_gpio_probe,
- .remove = tegra186_gpio_remove,
};
module_platform_driver(tegra186_gpio_driver);
diff --git a/drivers/gpio/gpio-tps65218.c b/drivers/gpio/gpio-tps65218.c
index 43a1150055ce..3517debe2b0b 100644
--- a/drivers/gpio/gpio-tps65218.c
+++ b/drivers/gpio/gpio-tps65218.c
@@ -187,7 +187,6 @@ static int tps65218_gpio_probe(struct platform_device *pdev)
{
struct tps65218 *tps65218 = dev_get_drvdata(pdev->dev.parent);
struct tps65218_gpio *tps65218_gpio;
- int ret;
tps65218_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps65218_gpio),
GFP_KERNEL);
@@ -201,16 +200,8 @@ static int tps65218_gpio_probe(struct platform_device *pdev)
tps65218_gpio->gpio_chip.of_node = pdev->dev.of_node;
#endif
- ret = devm_gpiochip_add_data(&pdev->dev, &tps65218_gpio->gpio_chip,
- tps65218_gpio);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to register gpiochip, %d\n", ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, tps65218_gpio);
-
- return ret;
+ return devm_gpiochip_add_data(&pdev->dev, &tps65218_gpio->gpio_chip,
+ tps65218_gpio);
}
static const struct of_device_id tps65218_dt_match[] = {
diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c
index 9b6cc74f47c8..da0304b764a5 100644
--- a/drivers/gpio/gpio-tps6586x.c
+++ b/drivers/gpio/gpio-tps6586x.c
@@ -76,7 +76,6 @@ static int tps6586x_gpio_probe(struct platform_device *pdev)
{
struct tps6586x_platform_data *pdata;
struct tps6586x_gpio *tps6586x_gpio;
- int ret;
pdata = dev_get_platdata(pdev->dev.parent);
tps6586x_gpio = devm_kzalloc(&pdev->dev,
@@ -106,16 +105,8 @@ static int tps6586x_gpio_probe(struct platform_device *pdev)
else
tps6586x_gpio->gpio_chip.base = -1;
- ret = devm_gpiochip_add_data(&pdev->dev, &tps6586x_gpio->gpio_chip,
- tps6586x_gpio);
- if (ret < 0) {
- dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, tps6586x_gpio);
-
- return ret;
+ return devm_gpiochip_add_data(&pdev->dev, &tps6586x_gpio->gpio_chip,
+ tps6586x_gpio);
}
static struct platform_driver tps6586x_gpio_driver = {
diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c
index 0c0b445c75c0..7fa8c841081f 100644
--- a/drivers/gpio/gpio-tps65910.c
+++ b/drivers/gpio/gpio-tps65910.c
@@ -165,16 +165,8 @@ static int tps65910_gpio_probe(struct platform_device *pdev)
}
skip_init:
- ret = devm_gpiochip_add_data(&pdev->dev, &tps65910_gpio->gpio_chip,
- tps65910_gpio);
- if (ret < 0) {
- dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, tps65910_gpio);
-
- return ret;
+ return devm_gpiochip_add_data(&pdev->dev, &tps65910_gpio->gpio_chip,
+ tps65910_gpio);
}
static struct platform_driver tps65910_gpio_driver = {
diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c
index 510d9ed9fd2a..fab771cb6a87 100644
--- a/drivers/gpio/gpio-tps65912.c
+++ b/drivers/gpio/gpio-tps65912.c
@@ -99,7 +99,6 @@ static int tps65912_gpio_probe(struct platform_device *pdev)
{
struct tps65912 *tps = dev_get_drvdata(pdev->dev.parent);
struct tps65912_gpio *gpio;
- int ret;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
@@ -109,16 +108,7 @@ static int tps65912_gpio_probe(struct platform_device *pdev)
gpio->gpio_chip = template_chip;
gpio->gpio_chip.parent = tps->dev;
- ret = devm_gpiochip_add_data(&pdev->dev, &gpio->gpio_chip,
- gpio);
- if (ret < 0) {
- dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, gpio);
-
- return 0;
+ return devm_gpiochip_add_data(&pdev->dev, &gpio->gpio_chip, gpio);
}
static const struct platform_device_id tps65912_gpio_id_table[] = {
diff --git a/drivers/gpio/gpio-tps68470.c b/drivers/gpio/gpio-tps68470.c
index f7f5f770e0fb..423b7bc30ae8 100644
--- a/drivers/gpio/gpio-tps68470.c
+++ b/drivers/gpio/gpio-tps68470.c
@@ -125,7 +125,6 @@ static const char *tps68470_names[TPS68470_N_GPIO] = {
static int tps68470_gpio_probe(struct platform_device *pdev)
{
struct tps68470_gpio_data *tps68470_gpio;
- int ret;
tps68470_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps68470_gpio),
GFP_KERNEL);
@@ -146,16 +145,7 @@ static int tps68470_gpio_probe(struct platform_device *pdev)
tps68470_gpio->gc.base = -1;
tps68470_gpio->gc.parent = &pdev->dev;
- ret = devm_gpiochip_add_data(&pdev->dev, &tps68470_gpio->gc,
- tps68470_gpio);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to register gpio_chip: %d\n", ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, tps68470_gpio);
-
- return ret;
+ return devm_gpiochip_add_data(&pdev->dev, &tps68470_gpio->gc, tps68470_gpio);
}
static struct platform_driver tps68470_gpio_driver = {
diff --git a/drivers/gpio/gpio-visconti.c b/drivers/gpio/gpio-visconti.c
index 0e3d19828eb1..47455810bdb9 100644
--- a/drivers/gpio/gpio-visconti.c
+++ b/drivers/gpio/gpio-visconti.c
@@ -187,15 +187,7 @@ static int visconti_gpio_probe(struct platform_device *pdev)
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_level_irq;
- ret = devm_gpiochip_add_data(dev, &priv->gpio_chip, priv);
- if (ret) {
- dev_err(dev, "failed to add GPIO chip\n");
- return ret;
- }
-
- platform_set_drvdata(pdev, priv);
-
- return ret;
+ return devm_gpiochip_add_data(dev, &priv->gpio_chip, priv);
}
static const struct of_device_id visconti_gpio_of_match[] = {
diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c
index a19eeef6cf1e..16a0fae1e32e 100644
--- a/drivers/gpio/gpio-wcove.c
+++ b/drivers/gpio/gpio-wcove.c
@@ -99,19 +99,14 @@ struct wcove_gpio {
bool set_irq_mask;
};
-static inline int to_reg(int gpio, enum ctrl_register reg_type)
+static inline int to_reg(int gpio, enum ctrl_register type)
{
- unsigned int reg;
+ unsigned int reg = type == CTRL_IN ? GPIO_IN_CTRL_BASE : GPIO_OUT_CTRL_BASE;
if (gpio >= WCOVE_GPIO_NUM)
return -EOPNOTSUPP;
- if (reg_type == CTRL_IN)
- reg = GPIO_IN_CTRL_BASE + gpio;
- else
- reg = GPIO_OUT_CTRL_BASE + gpio;
-
- return reg;
+ return reg + gpio;
}
static inline int to_ireg(int gpio, enum ctrl_register type, unsigned int *mask)
@@ -129,7 +124,7 @@ static inline int to_ireg(int gpio, enum ctrl_register type, unsigned int *mask)
return reg;
}
-static void wcove_update_irq_mask(struct wcove_gpio *wg, int gpio)
+static void wcove_update_irq_mask(struct wcove_gpio *wg, irq_hw_number_t gpio)
{
unsigned int mask, reg = to_ireg(gpio, IRQ_MASK, &mask);
@@ -139,13 +134,10 @@ static void wcove_update_irq_mask(struct wcove_gpio *wg, int gpio)
regmap_clear_bits(wg->regmap, reg, mask);
}
-static void wcove_update_irq_ctrl(struct wcove_gpio *wg, int gpio)
+static void wcove_update_irq_ctrl(struct wcove_gpio *wg, irq_hw_number_t gpio)
{
int reg = to_reg(gpio, CTRL_IN);
- if (reg < 0)
- return;
-
regmap_update_bits(wg->regmap, reg, CTLI_INTCNT_BE, wg->intcnt);
}
@@ -248,8 +240,9 @@ static int wcove_irq_type(struct irq_data *data, unsigned int type)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct wcove_gpio *wg = gpiochip_get_data(chip);
+ irq_hw_number_t gpio = irqd_to_hwirq(data);
- if (data->hwirq >= WCOVE_GPIO_NUM)
+ if (gpio >= WCOVE_GPIO_NUM)
return 0;
switch (type) {
@@ -286,7 +279,7 @@ static void wcove_bus_sync_unlock(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct wcove_gpio *wg = gpiochip_get_data(chip);
- int gpio = data->hwirq;
+ irq_hw_number_t gpio = irqd_to_hwirq(data);
if (wg->update & UPDATE_IRQ_TYPE)
wcove_update_irq_ctrl(wg, gpio);
@@ -301,8 +294,9 @@ static void wcove_irq_unmask(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct wcove_gpio *wg = gpiochip_get_data(chip);
+ irq_hw_number_t gpio = irqd_to_hwirq(data);
- if (data->hwirq >= WCOVE_GPIO_NUM)
+ if (gpio >= WCOVE_GPIO_NUM)
return;
wg->set_irq_mask = false;
@@ -313,8 +307,9 @@ static void wcove_irq_mask(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct wcove_gpio *wg = gpiochip_get_data(chip);
+ irq_hw_number_t gpio = irqd_to_hwirq(data);
- if (data->hwirq >= WCOVE_GPIO_NUM)
+ if (gpio >= WCOVE_GPIO_NUM)
return;
wg->set_irq_mask = true;
@@ -369,8 +364,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static void wcove_gpio_dbg_show(struct seq_file *s,
- struct gpio_chip *chip)
+static void wcove_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
unsigned int ctlo, ctli, irq_mask, irq_status;
struct wcove_gpio *wg = gpiochip_get_data(chip);
@@ -379,10 +373,15 @@ static void wcove_gpio_dbg_show(struct seq_file *s,
for (gpio = 0; gpio < WCOVE_GPIO_NUM; gpio++) {
ret += regmap_read(wg->regmap, to_reg(gpio, CTRL_OUT), &ctlo);
ret += regmap_read(wg->regmap, to_reg(gpio, CTRL_IN), &ctli);
+ if (ret) {
+ dev_err(wg->dev, "Failed to read registers: CTRL out/in\n");
+ break;
+ }
+
ret += regmap_read(wg->regmap, to_ireg(gpio, IRQ_MASK, &mask), &irq_mask);
ret += regmap_read(wg->regmap, to_ireg(gpio, IRQ_STATUS, &mask), &irq_status);
if (ret) {
- pr_err("Failed to read registers: ctrl out/in or irq status/mask\n");
+ dev_err(wg->dev, "Failed to read registers: IRQ status/mask\n");
break;
}
diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c
index a3a32a77041f..9cf1e5ebb352 100644
--- a/drivers/gpio/gpio-wm831x.c
+++ b/drivers/gpio/gpio-wm831x.c
@@ -261,7 +261,6 @@ static int wm831x_gpio_probe(struct platform_device *pdev)
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *pdata = &wm831x->pdata;
struct wm831x_gpio *wm831x_gpio;
- int ret;
wm831x_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm831x_gpio),
GFP_KERNEL);
@@ -280,16 +279,7 @@ static int wm831x_gpio_probe(struct platform_device *pdev)
wm831x_gpio->gpio_chip.of_node = wm831x->dev->of_node;
#endif
- ret = devm_gpiochip_add_data(&pdev->dev, &wm831x_gpio->gpio_chip,
- wm831x_gpio);
- if (ret < 0) {
- dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, wm831x_gpio);
-
- return ret;
+ return devm_gpiochip_add_data(&pdev->dev, &wm831x_gpio->gpio_chip, wm831x_gpio);
}
static struct platform_driver wm831x_gpio_driver = {
diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c
index 460f0a4b04bd..b1b131fb9804 100644
--- a/drivers/gpio/gpio-wm8350.c
+++ b/drivers/gpio/gpio-wm8350.c
@@ -105,7 +105,6 @@ static int wm8350_gpio_probe(struct platform_device *pdev)
struct wm8350 *wm8350 = dev_get_drvdata(pdev->dev.parent);
struct wm8350_platform_data *pdata = dev_get_platdata(wm8350->dev);
struct wm8350_gpio_data *wm8350_gpio;
- int ret;
wm8350_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm8350_gpio),
GFP_KERNEL);
@@ -121,16 +120,7 @@ static int wm8350_gpio_probe(struct platform_device *pdev)
else
wm8350_gpio->gpio_chip.base = -1;
- ret = devm_gpiochip_add_data(&pdev->dev, &wm8350_gpio->gpio_chip,
- wm8350_gpio);
- if (ret < 0) {
- dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, wm8350_gpio);
-
- return ret;
+ return devm_gpiochip_add_data(&pdev->dev, &wm8350_gpio->gpio_chip, wm8350_gpio);
}
static struct platform_driver wm8350_gpio_driver = {
diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c
index 9af89cf7f6bc..f4a474cef32d 100644
--- a/drivers/gpio/gpio-wm8994.c
+++ b/drivers/gpio/gpio-wm8994.c
@@ -263,7 +263,6 @@ static int wm8994_gpio_probe(struct platform_device *pdev)
struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent);
struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev);
struct wm8994_gpio *wm8994_gpio;
- int ret;
wm8994_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm8994_gpio),
GFP_KERNEL);
@@ -279,17 +278,7 @@ static int wm8994_gpio_probe(struct platform_device *pdev)
else
wm8994_gpio->gpio_chip.base = -1;
- ret = devm_gpiochip_add_data(&pdev->dev, &wm8994_gpio->gpio_chip,
- wm8994_gpio);
- if (ret < 0) {
- dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
- ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, wm8994_gpio);
-
- return ret;
+ return devm_gpiochip_add_data(&pdev->dev, &wm8994_gpio->gpio_chip, wm8994_gpio);
}
static struct platform_driver wm8994_gpio_driver = {
diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c
index 532b0df8a1f2..fb4b0c67aeef 100644
--- a/drivers/gpio/gpio-xgene.c
+++ b/drivers/gpio/gpio-xgene.c
@@ -159,7 +159,6 @@ static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
static int xgene_gpio_probe(struct platform_device *pdev)
{
struct xgene_gpio *gpio;
- int err = 0;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
@@ -183,15 +182,7 @@ static int xgene_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, gpio);
- err = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
- if (err) {
- dev_err(&pdev->dev,
- "failed to register gpiochip.\n");
- return err;
- }
-
- dev_info(&pdev->dev, "X-Gene GPIO driver registered.\n");
- return 0;
+ return devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
}
static const struct of_device_id xgene_gpio_of_match[] = {
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index 136557e7dd3c..c329c3a606e8 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -5,6 +5,7 @@
* Copyright 2008 - 2013 Xilinx, Inc.
*/
+#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/errno.h>
@@ -23,7 +24,8 @@
#define XGPIO_DATA_OFFSET (0x0) /* Data register */
#define XGPIO_TRI_OFFSET (0x4) /* I/O direction register */
-#define XGPIO_CHANNEL_OFFSET 0x8
+#define XGPIO_CHANNEL0_OFFSET 0x0
+#define XGPIO_CHANNEL1_OFFSET 0x8
#define XGPIO_GIER_OFFSET 0x11c /* Global Interrupt Enable */
#define XGPIO_GIER_IE BIT(31)
@@ -43,56 +45,101 @@
* struct xgpio_instance - Stores information about GPIO device
* @gc: GPIO chip
* @regs: register block
- * @gpio_width: GPIO width for every channel
- * @gpio_state: GPIO write state shadow register
- * @gpio_last_irq_read: GPIO read state register from last interrupt
- * @gpio_dir: GPIO direction shadow register
+ * @hw_map: GPIO pin mapping on hardware side
+ * @sw_map: GPIO pin mapping on software side
+ * @state: GPIO write state shadow register
+ * @last_irq_read: GPIO read state register from last interrupt
+ * @dir: GPIO direction shadow register
* @gpio_lock: Lock used for synchronization
* @irq: IRQ used by GPIO device
* @irqchip: IRQ chip
- * @irq_enable: GPIO IRQ enable/disable bitfield
- * @irq_rising_edge: GPIO IRQ rising edge enable/disable bitfield
- * @irq_falling_edge: GPIO IRQ falling edge enable/disable bitfield
+ * @enable: GPIO IRQ enable/disable bitfield
+ * @rising_edge: GPIO IRQ rising edge enable/disable bitfield
+ * @falling_edge: GPIO IRQ falling edge enable/disable bitfield
* @clk: clock resource for this driver
*/
struct xgpio_instance {
struct gpio_chip gc;
void __iomem *regs;
- unsigned int gpio_width[2];
- u32 gpio_state[2];
- u32 gpio_last_irq_read[2];
- u32 gpio_dir[2];
+ DECLARE_BITMAP(hw_map, 64);
+ DECLARE_BITMAP(sw_map, 64);
+ DECLARE_BITMAP(state, 64);
+ DECLARE_BITMAP(last_irq_read, 64);
+ DECLARE_BITMAP(dir, 64);
spinlock_t gpio_lock; /* For serializing operations */
int irq;
struct irq_chip irqchip;
- u32 irq_enable[2];
- u32 irq_rising_edge[2];
- u32 irq_falling_edge[2];
+ DECLARE_BITMAP(enable, 64);
+ DECLARE_BITMAP(rising_edge, 64);
+ DECLARE_BITMAP(falling_edge, 64);
struct clk *clk;
};
-static inline int xgpio_index(struct xgpio_instance *chip, int gpio)
+static inline int xgpio_from_bit(struct xgpio_instance *chip, int bit)
{
- if (gpio >= chip->gpio_width[0])
- return 1;
+ return bitmap_bitremap(bit, chip->hw_map, chip->sw_map, 64);
+}
- return 0;
+static inline int xgpio_to_bit(struct xgpio_instance *chip, int gpio)
+{
+ return bitmap_bitremap(gpio, chip->sw_map, chip->hw_map, 64);
}
-static inline int xgpio_regoffset(struct xgpio_instance *chip, int gpio)
+static inline u32 xgpio_get_value32(const unsigned long *map, int bit)
{
- if (xgpio_index(chip, gpio))
- return XGPIO_CHANNEL_OFFSET;
+ const size_t index = BIT_WORD(bit);
+ const unsigned long offset = (bit % BITS_PER_LONG) & BIT(5);
- return 0;
+ return (map[index] >> offset) & 0xFFFFFFFFul;
+}
+
+static inline void xgpio_set_value32(unsigned long *map, int bit, u32 v)
+{
+ const size_t index = BIT_WORD(bit);
+ const unsigned long offset = (bit % BITS_PER_LONG) & BIT(5);
+
+ map[index] &= ~(0xFFFFFFFFul << offset);
+ map[index] |= v << offset;
+}
+
+static inline int xgpio_regoffset(struct xgpio_instance *chip, int ch)
+{
+ switch (ch) {
+ case 0:
+ return XGPIO_CHANNEL0_OFFSET;
+ case 1:
+ return XGPIO_CHANNEL1_OFFSET;
+ default:
+ return -EINVAL;
+ }
}
-static inline int xgpio_offset(struct xgpio_instance *chip, int gpio)
+static void xgpio_read_ch(struct xgpio_instance *chip, int reg, int bit, unsigned long *a)
{
- if (xgpio_index(chip, gpio))
- return gpio - chip->gpio_width[0];
+ void __iomem *addr = chip->regs + reg + xgpio_regoffset(chip, bit / 32);
+ xgpio_set_value32(a, bit, xgpio_readreg(addr));
+}
+
+static void xgpio_write_ch(struct xgpio_instance *chip, int reg, int bit, unsigned long *a)
+{
+ void __iomem *addr = chip->regs + reg + xgpio_regoffset(chip, bit / 32);
+ xgpio_writereg(addr, xgpio_get_value32(a, bit));
+}
+
+static void xgpio_read_ch_all(struct xgpio_instance *chip, int reg, unsigned long *a)
+{
+ int bit, lastbit = xgpio_to_bit(chip, chip->gc.ngpio - 1);
+
+ for (bit = 0; bit <= lastbit ; bit += 32)
+ xgpio_read_ch(chip, reg, bit, a);
+}
+
+static void xgpio_write_ch_all(struct xgpio_instance *chip, int reg, unsigned long *a)
+{
+ int bit, lastbit = xgpio_to_bit(chip, chip->gc.ngpio - 1);
- return gpio;
+ for (bit = 0; bit <= lastbit ; bit += 32)
+ xgpio_write_ch(chip, reg, bit, a);
}
/**
@@ -109,12 +156,12 @@ static inline int xgpio_offset(struct xgpio_instance *chip, int gpio)
static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct xgpio_instance *chip = gpiochip_get_data(gc);
- u32 val;
+ int bit = xgpio_to_bit(chip, gpio);
+ DECLARE_BITMAP(state, 64);
- val = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET +
- xgpio_regoffset(chip, gpio));
+ xgpio_read_ch(chip, XGPIO_DATA_OFFSET, bit, state);
- return !!(val & BIT(xgpio_offset(chip, gpio)));
+ return test_bit(bit, state);
}
/**
@@ -130,19 +177,14 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
unsigned long flags;
struct xgpio_instance *chip = gpiochip_get_data(gc);
- int index = xgpio_index(chip, gpio);
- int offset = xgpio_offset(chip, gpio);
+ int bit = xgpio_to_bit(chip, gpio);
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Write to GPIO signal and set its direction to output */
- if (val)
- chip->gpio_state[index] |= BIT(offset);
- else
- chip->gpio_state[index] &= ~BIT(offset);
+ __assign_bit(bit, chip->state, val);
- xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
- xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
+ xgpio_write_ch(chip, XGPIO_DATA_OFFSET, bit, chip->state);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
}
@@ -159,37 +201,22 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
unsigned long *bits)
{
+ DECLARE_BITMAP(hw_mask, 64);
+ DECLARE_BITMAP(hw_bits, 64);
+ DECLARE_BITMAP(state, 64);
unsigned long flags;
struct xgpio_instance *chip = gpiochip_get_data(gc);
- int index = xgpio_index(chip, 0);
- int offset, i;
+
+ bitmap_remap(hw_mask, mask, chip->sw_map, chip->hw_map, 64);
+ bitmap_remap(hw_bits, bits, chip->sw_map, chip->hw_map, 64);
spin_lock_irqsave(&chip->gpio_lock, flags);
- /* Write to GPIO signals */
- for (i = 0; i < gc->ngpio; i++) {
- if (*mask == 0)
- break;
- /* Once finished with an index write it out to the register */
- if (index != xgpio_index(chip, i)) {
- xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
- index * XGPIO_CHANNEL_OFFSET,
- chip->gpio_state[index]);
- spin_unlock_irqrestore(&chip->gpio_lock, flags);
- index = xgpio_index(chip, i);
- spin_lock_irqsave(&chip->gpio_lock, flags);
- }
- if (__test_and_clear_bit(i, mask)) {
- offset = xgpio_offset(chip, i);
- if (test_bit(i, bits))
- chip->gpio_state[index] |= BIT(offset);
- else
- chip->gpio_state[index] &= ~BIT(offset);
- }
- }
+ bitmap_replace(state, chip->state, hw_bits, hw_mask, 64);
+
+ xgpio_write_ch_all(chip, XGPIO_DATA_OFFSET, state);
- xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
- index * XGPIO_CHANNEL_OFFSET, chip->gpio_state[index]);
+ bitmap_copy(chip->state, state, 64);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
}
@@ -207,15 +234,13 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
unsigned long flags;
struct xgpio_instance *chip = gpiochip_get_data(gc);
- int index = xgpio_index(chip, gpio);
- int offset = xgpio_offset(chip, gpio);
+ int bit = xgpio_to_bit(chip, gpio);
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Set the GPIO bit in shadow register and set direction as input */
- chip->gpio_dir[index] |= BIT(offset);
- xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET +
- xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
+ __set_bit(bit, chip->dir);
+ xgpio_write_ch(chip, XGPIO_TRI_OFFSET, bit, chip->dir);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
@@ -238,23 +263,17 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
unsigned long flags;
struct xgpio_instance *chip = gpiochip_get_data(gc);
- int index = xgpio_index(chip, gpio);
- int offset = xgpio_offset(chip, gpio);
+ int bit = xgpio_to_bit(chip, gpio);
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Write state of GPIO signal */
- if (val)
- chip->gpio_state[index] |= BIT(offset);
- else
- chip->gpio_state[index] &= ~BIT(offset);
- xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
- xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
+ __assign_bit(bit, chip->state, val);
+ xgpio_write_ch(chip, XGPIO_DATA_OFFSET, bit, chip->state);
/* Clear the GPIO bit in shadow register and set direction as output */
- chip->gpio_dir[index] &= ~BIT(offset);
- xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET +
- xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
+ __clear_bit(bit, chip->dir);
+ xgpio_write_ch(chip, XGPIO_TRI_OFFSET, bit, chip->dir);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
@@ -267,16 +286,8 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
*/
static void xgpio_save_regs(struct xgpio_instance *chip)
{
- 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(chip->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET,
- chip->gpio_state[1]);
- xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET,
- chip->gpio_dir[1]);
+ xgpio_write_ch_all(chip, XGPIO_DATA_OFFSET, chip->state);
+ xgpio_write_ch_all(chip, XGPIO_TRI_OFFSET, chip->dir);
}
static int xgpio_request(struct gpio_chip *chip, unsigned int offset)
@@ -302,8 +313,8 @@ static int __maybe_unused xgpio_suspend(struct device *dev)
struct irq_data *data = irq_get_irq_data(gpio->irq);
if (!data) {
- dev_err(dev, "irq_get_irq_data() failed\n");
- return -EINVAL;
+ dev_dbg(dev, "IRQ not connected\n");
+ return pm_runtime_force_suspend(dev);
}
if (!irqd_is_wakeup_set(data))
@@ -348,8 +359,8 @@ static int __maybe_unused xgpio_resume(struct device *dev)
struct irq_data *data = irq_get_irq_data(gpio->irq);
if (!data) {
- dev_err(dev, "irq_get_irq_data() failed\n");
- return -EINVAL;
+ dev_dbg(dev, "IRQ not connected\n");
+ return pm_runtime_force_resume(dev);
}
if (!irqd_is_wakeup_set(data))
@@ -391,18 +402,17 @@ static void xgpio_irq_mask(struct irq_data *irq_data)
unsigned long flags;
struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data);
int irq_offset = irqd_to_hwirq(irq_data);
- int index = xgpio_index(chip, irq_offset);
- int offset = xgpio_offset(chip, irq_offset);
+ int bit = xgpio_to_bit(chip, irq_offset);
+ u32 mask = BIT(bit / 32), temp;
spin_lock_irqsave(&chip->gpio_lock, flags);
- chip->irq_enable[index] &= ~BIT(offset);
+ __clear_bit(bit, chip->enable);
- if (!chip->irq_enable[index]) {
+ if (xgpio_get_value32(chip->enable, bit) == 0) {
/* Disable per channel interrupt */
- u32 temp = xgpio_readreg(chip->regs + XGPIO_IPIER_OFFSET);
-
- temp &= ~BIT(index);
+ temp = xgpio_readreg(chip->regs + XGPIO_IPIER_OFFSET);
+ temp &= ~mask;
xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, temp);
}
spin_unlock_irqrestore(&chip->gpio_lock, flags);
@@ -417,30 +427,26 @@ static void xgpio_irq_unmask(struct irq_data *irq_data)
unsigned long flags;
struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data);
int irq_offset = irqd_to_hwirq(irq_data);
- int index = xgpio_index(chip, irq_offset);
- int offset = xgpio_offset(chip, irq_offset);
- u32 old_enable = chip->irq_enable[index];
+ int bit = xgpio_to_bit(chip, irq_offset);
+ u32 old_enable = xgpio_get_value32(chip->enable, bit);
+ u32 mask = BIT(bit / 32), val;
spin_lock_irqsave(&chip->gpio_lock, flags);
- chip->irq_enable[index] |= BIT(offset);
+ __set_bit(bit, chip->enable);
- if (!old_enable) {
+ if (old_enable == 0) {
/* Clear any existing per-channel interrupts */
- u32 val = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET) &
- BIT(index);
-
- if (val)
- xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, val);
+ val = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET);
+ val &= mask;
+ xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, val);
/* Update GPIO IRQ read data before enabling interrupt*/
- val = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET +
- index * XGPIO_CHANNEL_OFFSET);
- chip->gpio_last_irq_read[index] = val;
+ xgpio_read_ch(chip, XGPIO_DATA_OFFSET, bit, chip->last_irq_read);
/* Enable per channel interrupt */
val = xgpio_readreg(chip->regs + XGPIO_IPIER_OFFSET);
- val |= BIT(index);
+ val |= mask;
xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, val);
}
@@ -459,8 +465,7 @@ static int xgpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
{
struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data);
int irq_offset = irqd_to_hwirq(irq_data);
- int index = xgpio_index(chip, irq_offset);
- int offset = xgpio_offset(chip, irq_offset);
+ int bit = xgpio_to_bit(chip, irq_offset);
/*
* The Xilinx GPIO hardware provides a single interrupt status
@@ -470,16 +475,16 @@ static int xgpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
*/
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_BOTH:
- chip->irq_rising_edge[index] |= BIT(offset);
- chip->irq_falling_edge[index] |= BIT(offset);
+ __set_bit(bit, chip->rising_edge);
+ __set_bit(bit, chip->falling_edge);
break;
case IRQ_TYPE_EDGE_RISING:
- chip->irq_rising_edge[index] |= BIT(offset);
- chip->irq_falling_edge[index] &= ~BIT(offset);
+ __set_bit(bit, chip->rising_edge);
+ __clear_bit(bit, chip->falling_edge);
break;
case IRQ_TYPE_EDGE_FALLING:
- chip->irq_rising_edge[index] &= ~BIT(offset);
- chip->irq_falling_edge[index] |= BIT(offset);
+ __clear_bit(bit, chip->rising_edge);
+ __set_bit(bit, chip->falling_edge);
break;
default:
return -EINVAL;
@@ -496,46 +501,44 @@ static int xgpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
static void xgpio_irqhandler(struct irq_desc *desc)
{
struct xgpio_instance *chip = irq_desc_get_handler_data(desc);
+ struct gpio_chip *gc = &chip->gc;
struct irq_chip *irqchip = irq_desc_get_chip(desc);
- u32 num_channels = chip->gpio_width[1] ? 2 : 1;
- u32 offset = 0, index;
- u32 status = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET);
-
+ DECLARE_BITMAP(rising, 64);
+ DECLARE_BITMAP(falling, 64);
+ DECLARE_BITMAP(all, 64);
+ int irq_offset;
+ u32 status;
+ u32 bit;
+
+ status = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET);
xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, status);
chained_irq_enter(irqchip, desc);
- for (index = 0; index < num_channels; index++) {
- if ((status & BIT(index))) {
- unsigned long rising_events, falling_events, all_events;
- unsigned long flags;
- u32 data, bit;
- unsigned int irq;
-
- spin_lock_irqsave(&chip->gpio_lock, flags);
- data = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET +
- index * XGPIO_CHANNEL_OFFSET);
- rising_events = data &
- ~chip->gpio_last_irq_read[index] &
- chip->irq_enable[index] &
- chip->irq_rising_edge[index];
- falling_events = ~data &
- chip->gpio_last_irq_read[index] &
- chip->irq_enable[index] &
- chip->irq_falling_edge[index];
- dev_dbg(chip->gc.parent,
- "IRQ chan %u rising 0x%lx falling 0x%lx\n",
- index, rising_events, falling_events);
- all_events = rising_events | falling_events;
- chip->gpio_last_irq_read[index] = data;
- spin_unlock_irqrestore(&chip->gpio_lock, flags);
-
- for_each_set_bit(bit, &all_events, 32) {
- irq = irq_find_mapping(chip->gc.irq.domain,
- offset + bit);
- generic_handle_irq(irq);
- }
- }
- offset += chip->gpio_width[index];
+
+ spin_lock(&chip->gpio_lock);
+
+ xgpio_read_ch_all(chip, XGPIO_DATA_OFFSET, all);
+
+ bitmap_complement(rising, chip->last_irq_read, 64);
+ bitmap_and(rising, rising, all, 64);
+ bitmap_and(rising, rising, chip->enable, 64);
+ bitmap_and(rising, rising, chip->rising_edge, 64);
+
+ bitmap_complement(falling, all, 64);
+ bitmap_and(falling, falling, chip->last_irq_read, 64);
+ bitmap_and(falling, falling, chip->enable, 64);
+ bitmap_and(falling, falling, chip->falling_edge, 64);
+
+ bitmap_copy(chip->last_irq_read, all, 64);
+ bitmap_or(all, rising, falling, 64);
+
+ spin_unlock(&chip->gpio_lock);
+
+ dev_dbg(gc->parent, "IRQ rising %*pb falling %*pb\n", 64, rising, 64, falling);
+
+ for_each_set_bit(bit, all, 64) {
+ irq_offset = xgpio_from_bit(chip, bit);
+ generic_handle_irq(irq_find_mapping(gc->irq.domain, irq_offset));
}
chained_irq_exit(irqchip, desc);
@@ -556,6 +559,9 @@ static int xgpio_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
u32 is_dual = 0;
u32 cells = 2;
+ u32 width[2];
+ u32 state[2];
+ u32 dir[2];
struct gpio_irq_chip *girq;
u32 temp;
@@ -565,13 +571,25 @@ static int xgpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, chip);
+ /* First, check if the device is dual-channel */
+ of_property_read_u32(np, "xlnx,is-dual", &is_dual);
+
+ /* Setup defaults */
+ memset32(width, 0, ARRAY_SIZE(width));
+ memset32(state, 0, ARRAY_SIZE(state));
+ memset32(dir, 0xFFFFFFFF, ARRAY_SIZE(dir));
+
/* Update GPIO state shadow register with default value */
- if (of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state[0]))
- chip->gpio_state[0] = 0x0;
+ of_property_read_u32(np, "xlnx,dout-default", &state[0]);
+ of_property_read_u32(np, "xlnx,dout-default-2", &state[1]);
+
+ bitmap_from_arr32(chip->state, state, 64);
/* Update GPIO direction shadow register with default value */
- if (of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir[0]))
- chip->gpio_dir[0] = 0xFFFFFFFF;
+ of_property_read_u32(np, "xlnx,tri-default", &dir[0]);
+ of_property_read_u32(np, "xlnx,tri-default-2", &dir[1]);
+
+ bitmap_from_arr32(chip->dir, dir, 64);
/* Update cells with gpio-cells value */
if (of_property_read_u32(np, "#gpio-cells", &cells))
@@ -586,42 +604,29 @@ static int xgpio_probe(struct platform_device *pdev)
* Check device node and parent device node for device width
* and assume default width of 32
*/
- if (of_property_read_u32(np, "xlnx,gpio-width", &chip->gpio_width[0]))
- chip->gpio_width[0] = 32;
+ if (of_property_read_u32(np, "xlnx,gpio-width", &width[0]))
+ width[0] = 32;
- if (chip->gpio_width[0] > 32)
+ if (width[0] > 32)
return -EINVAL;
- spin_lock_init(&chip->gpio_lock);
+ if (is_dual && of_property_read_u32(np, "xlnx,gpio2-width", &width[1]))
+ width[1] = 32;
- if (of_property_read_u32(np, "xlnx,is-dual", &is_dual))
- is_dual = 0;
-
- if (is_dual) {
- /* Update GPIO state shadow register with default value */
- if (of_property_read_u32(np, "xlnx,dout-default-2",
- &chip->gpio_state[1]))
- chip->gpio_state[1] = 0x0;
-
- /* Update GPIO direction shadow register with default value */
- if (of_property_read_u32(np, "xlnx,tri-default-2",
- &chip->gpio_dir[1]))
- chip->gpio_dir[1] = 0xFFFFFFFF;
-
- /*
- * Check device node and parent device node for device width
- * and assume default width of 32
- */
- if (of_property_read_u32(np, "xlnx,gpio2-width",
- &chip->gpio_width[1]))
- chip->gpio_width[1] = 32;
-
- if (chip->gpio_width[1] > 32)
- return -EINVAL;
- }
+ if (width[1] > 32)
+ return -EINVAL;
+
+ /* Setup software pin mapping */
+ bitmap_set(chip->sw_map, 0, width[0] + width[1]);
+
+ /* Setup hardware pin mapping */
+ bitmap_set(chip->hw_map, 0, width[0]);
+ bitmap_set(chip->hw_map, 32, width[1]);
+
+ spin_lock_init(&chip->gpio_lock);
chip->gc.base = -1;
- chip->gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1];
+ chip->gc.ngpio = bitmap_weight(chip->hw_map, 64);
chip->gc.parent = &pdev->dev;
chip->gc.direction_input = xgpio_dir_in;
chip->gc.direction_output = xgpio_dir_out;
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 3521c1dc3ac0..f0cb8ccd03ed 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -736,6 +736,11 @@ static int __maybe_unused zynq_gpio_suspend(struct device *dev)
struct zynq_gpio *gpio = dev_get_drvdata(dev);
struct irq_data *data = irq_get_irq_data(gpio->irq);
+ if (!data) {
+ dev_err(dev, "irq_get_irq_data() failed\n");
+ return -EINVAL;
+ }
+
if (!device_may_wakeup(dev))
disable_irq(gpio->irq);
@@ -753,6 +758,11 @@ static int __maybe_unused zynq_gpio_resume(struct device *dev)
struct irq_data *data = irq_get_irq_data(gpio->irq);
int ret;
+ if (!data) {
+ dev_err(dev, "irq_get_irq_data() failed\n");
+ return -EINVAL;
+ }
+
if (!device_may_wakeup(dev))
enable_irq(gpio->irq);
@@ -1001,8 +1011,11 @@ err_pm_dis:
static int zynq_gpio_remove(struct platform_device *pdev)
{
struct zynq_gpio *gpio = platform_get_drvdata(pdev);
+ int ret;
- pm_runtime_get_sync(&pdev->dev);
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
+ dev_warn(&pdev->dev, "pm_runtime_get_sync() Failed\n");
gpiochip_remove(&gpio->chip);
clk_disable_unprepare(gpio->clk);
device_set_wakeup_capable(&pdev->dev, 0);
@@ -1020,22 +1033,7 @@ static struct platform_driver zynq_gpio_driver = {
.remove = zynq_gpio_remove,
};
-/**
- * zynq_gpio_init - Initial driver registration call
- *
- * Return: value from platform_driver_register
- */
-static int __init zynq_gpio_init(void)
-{
- return platform_driver_register(&zynq_gpio_driver);
-}
-postcore_initcall(zynq_gpio_init);
-
-static void __exit zynq_gpio_exit(void)
-{
- platform_driver_unregister(&zynq_gpio_driver);
-}
-module_exit(zynq_gpio_exit);
+module_platform_driver(zynq_gpio_driver);
MODULE_AUTHOR("Xilinx Inc.");
MODULE_DESCRIPTION("Zynq GPIO driver");
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 3ef22a3c104d..411525ac4cc4 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -128,6 +128,34 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
return gpiochip_get_desc(chip, pin);
}
+/**
+ * acpi_get_and_request_gpiod - Translate ACPI GPIO pin to GPIO descriptor and
+ * hold a refcount to the GPIO device.
+ * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
+ * @pin: ACPI GPIO pin number (0-based, controller-relative)
+ * @label: Label to pass to gpiod_request()
+ *
+ * This function is a simple pass-through to acpi_get_gpiod(), except that
+ * as it is intended for use outside of the GPIO layer (in a similar fashion to
+ * gpiod_get_index() for example) it also holds a reference to the GPIO device.
+ */
+struct gpio_desc *acpi_get_and_request_gpiod(char *path, int pin, char *label)
+{
+ struct gpio_desc *gpio;
+ int ret;
+
+ gpio = acpi_get_gpiod(path, pin);
+ if (IS_ERR(gpio))
+ return gpio;
+
+ ret = gpiod_request(gpio, label);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return gpio;
+}
+EXPORT_SYMBOL_GPL(acpi_get_and_request_gpiod);
+
static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
{
struct acpi_gpio_event *event = data;
@@ -168,6 +196,29 @@ bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
}
EXPORT_SYMBOL_GPL(acpi_gpio_get_irq_resource);
+/**
+ * acpi_gpio_get_io_resource - Fetch details of an ACPI resource if it is a GPIO
+ * I/O resource or return False if not.
+ * @ares: Pointer to the ACPI resource to fetch
+ * @agpio: Pointer to a &struct acpi_resource_gpio to store the output pointer
+ */
+bool acpi_gpio_get_io_resource(struct acpi_resource *ares,
+ struct acpi_resource_gpio **agpio)
+{
+ struct acpi_resource_gpio *gpio;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
+ return false;
+
+ gpio = &ares->data.gpio;
+ if (gpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_IO)
+ return false;
+
+ *agpio = gpio;
+ return true;
+}
+EXPORT_SYMBOL_GPL(acpi_gpio_get_io_resource);
+
static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio,
struct acpi_gpio_event *event)
{
@@ -1233,14 +1284,14 @@ static void acpi_gpiochip_scan_gpios(struct acpi_gpio_chip *achip)
void acpi_gpiochip_add(struct gpio_chip *chip)
{
struct acpi_gpio_chip *acpi_gpio;
- acpi_handle handle;
+ struct acpi_device *adev;
acpi_status status;
if (!chip || !chip->parent)
return;
- handle = ACPI_HANDLE(chip->parent);
- if (!handle)
+ adev = ACPI_COMPANION(chip->parent);
+ if (!adev)
return;
acpi_gpio = kzalloc(sizeof(*acpi_gpio), GFP_KERNEL);
@@ -1254,7 +1305,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip)
INIT_LIST_HEAD(&acpi_gpio->events);
INIT_LIST_HEAD(&acpi_gpio->deferred_req_irqs_list_entry);
- status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio);
+ status = acpi_attach_data(adev->handle, acpi_gpio_chip_dh, acpi_gpio);
if (ACPI_FAILURE(status)) {
dev_err(chip->parent, "Failed to attach ACPI GPIO chip\n");
kfree(acpi_gpio);
@@ -1263,7 +1314,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip)
acpi_gpiochip_request_regions(acpi_gpio);
acpi_gpiochip_scan_gpios(acpi_gpio);
- acpi_walk_dep_device_list(handle);
+ acpi_dev_clear_dependencies(adev);
}
void acpi_gpiochip_remove(struct gpio_chip *chip)
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index 1631727bf0da..c7b5446d01fd 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -1880,6 +1880,7 @@ static void gpio_v2_line_info_changed_to_v1(
struct gpio_v2_line_info_changed *lic_v2,
struct gpioline_info_changed *lic_v1)
{
+ memset(lic_v1, 0, sizeof(*lic_v1));
gpio_v2_line_info_to_v1(&lic_v2->info, &lic_v1->info);
lic_v1->timestamp = lic_v2->timestamp_ns;
lic_v1->event_type = lic_v2->event_type;
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index ae49bb23c6ed..4098bc7f88b7 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -66,9 +66,8 @@ static ssize_t direction_show(struct device *dev,
mutex_lock(&data->mutex);
gpiod_get_direction(desc);
- status = sprintf(buf, "%s\n",
- test_bit(FLAG_IS_OUT, &desc->flags)
- ? "out" : "in");
+ status = sysfs_emit(buf, "%s\n",
+ test_bit(FLAG_IS_OUT, &desc->flags) ? "out" : "in");
mutex_unlock(&data->mutex);
@@ -109,13 +108,9 @@ static ssize_t value_show(struct device *dev,
mutex_lock(&data->mutex);
status = gpiod_get_value_cansleep(desc);
- if (status < 0)
- goto err;
+ if (status >= 0)
+ status = sysfs_emit(buf, "%zd\n", status);
- buf[0] = '0' + status;
- buf[1] = '\n';
- status = 2;
-err:
mutex_unlock(&data->mutex);
return status;
@@ -249,11 +244,11 @@ static ssize_t edge_show(struct device *dev,
mutex_lock(&data->mutex);
for (i = 0; i < ARRAY_SIZE(trigger_types); i++) {
- if (data->irq_flags == trigger_types[i].flags) {
- status = sprintf(buf, "%s\n", trigger_types[i].name);
+ if (data->irq_flags == trigger_types[i].flags)
break;
- }
}
+ if (i < ARRAY_SIZE(trigger_types))
+ status = sysfs_emit(buf, "%s\n", trigger_types[i].name);
mutex_unlock(&data->mutex);
@@ -312,10 +307,7 @@ static int gpio_sysfs_set_active_low(struct device *dev, int value)
if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value)
return 0;
- if (value)
- set_bit(FLAG_ACTIVE_LOW, &desc->flags);
- else
- clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
+ assign_bit(FLAG_ACTIVE_LOW, &desc->flags, value);
/* reconfigure poll(2) support if enabled on one edge only */
if (flags == GPIO_IRQF_TRIGGER_FALLING ||
@@ -336,8 +328,8 @@ static ssize_t active_low_show(struct device *dev,
mutex_lock(&data->mutex);
- status = sprintf(buf, "%d\n",
- !!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
+ status = sysfs_emit(buf, "%d\n",
+ !!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
mutex_unlock(&data->mutex);
@@ -415,7 +407,7 @@ static ssize_t base_show(struct device *dev,
{
const struct gpio_chip *chip = dev_get_drvdata(dev);
- return sprintf(buf, "%d\n", chip->base);
+ return sysfs_emit(buf, "%d\n", chip->base);
}
static DEVICE_ATTR_RO(base);
@@ -424,7 +416,7 @@ static ssize_t label_show(struct device *dev,
{
const struct gpio_chip *chip = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", chip->label ? : "");
+ return sysfs_emit(buf, "%s\n", chip->label ?: "");
}
static DEVICE_ATTR_RO(label);
@@ -433,7 +425,7 @@ static ssize_t ngpio_show(struct device *dev,
{
const struct gpio_chip *chip = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", chip->ngpio);
+ return sysfs_emit(buf, "%u\n", chip->ngpio);
}
static DEVICE_ATTR_RO(ngpio);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 1427c1be749b..27c07108496d 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2004,9 +2004,6 @@ const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset)
{
struct gpio_desc *desc;
- if (offset >= gc->ngpio)
- return NULL;
-
desc = gpiochip_get_desc(gc, offset);
if (IS_ERR(desc))
return NULL;
@@ -2543,21 +2540,28 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
while (i < array_size) {
struct gpio_chip *gc = desc_array[i]->gdev->chip;
- unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)];
+ DECLARE_BITMAP(fastpath_mask, FASTPATH_NGPIO);
+ DECLARE_BITMAP(fastpath_bits, FASTPATH_NGPIO);
unsigned long *mask, *bits;
int first, j;
if (likely(gc->ngpio <= FASTPATH_NGPIO)) {
- mask = fastpath;
+ mask = fastpath_mask;
+ bits = fastpath_bits;
} else {
- mask = kmalloc_array(2 * BITS_TO_LONGS(gc->ngpio),
- sizeof(*mask),
- can_sleep ? GFP_KERNEL : GFP_ATOMIC);
+ gfp_t flags = can_sleep ? GFP_KERNEL : GFP_ATOMIC;
+
+ mask = bitmap_alloc(gc->ngpio, flags);
if (!mask)
return -ENOMEM;
+
+ bits = bitmap_alloc(gc->ngpio, flags);
+ if (!bits) {
+ bitmap_free(mask);
+ return -ENOMEM;
+ }
}
- bits = mask + BITS_TO_LONGS(gc->ngpio);
bitmap_zero(mask, gc->ngpio);
if (!can_sleep)
@@ -2580,8 +2584,10 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
ret = gpio_chip_get_multiple(gc, mask, bits);
if (ret) {
- if (mask != fastpath)
- kfree(mask);
+ if (mask != fastpath_mask)
+ bitmap_free(mask);
+ if (bits != fastpath_bits)
+ bitmap_free(bits);
return ret;
}
@@ -2601,8 +2607,10 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
j);
}
- if (mask != fastpath)
- kfree(mask);
+ if (mask != fastpath_mask)
+ bitmap_free(mask);
+ if (bits != fastpath_bits)
+ bitmap_free(bits);
}
return 0;
}
@@ -2826,21 +2834,28 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
while (i < array_size) {
struct gpio_chip *gc = desc_array[i]->gdev->chip;
- unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)];
+ DECLARE_BITMAP(fastpath_mask, FASTPATH_NGPIO);
+ DECLARE_BITMAP(fastpath_bits, FASTPATH_NGPIO);
unsigned long *mask, *bits;
int count = 0;
if (likely(gc->ngpio <= FASTPATH_NGPIO)) {
- mask = fastpath;
+ mask = fastpath_mask;
+ bits = fastpath_bits;
} else {
- mask = kmalloc_array(2 * BITS_TO_LONGS(gc->ngpio),
- sizeof(*mask),
- can_sleep ? GFP_KERNEL : GFP_ATOMIC);
+ gfp_t flags = can_sleep ? GFP_KERNEL : GFP_ATOMIC;
+
+ mask = bitmap_alloc(gc->ngpio, flags);
if (!mask)
return -ENOMEM;
+
+ bits = bitmap_alloc(gc->ngpio, flags);
+ if (!bits) {
+ bitmap_free(mask);
+ return -ENOMEM;
+ }
}
- bits = mask + BITS_TO_LONGS(gc->ngpio);
bitmap_zero(mask, gc->ngpio);
if (!can_sleep)
@@ -2885,8 +2900,10 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
if (count != 0)
gpio_chip_set_multiple(gc, mask, bits);
- if (mask != fastpath)
- kfree(mask);
+ if (mask != fastpath_mask)
+ bitmap_free(mask);
+ if (bits != fastpath_bits)
+ bitmap_free(bits);
}
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
index db16b3e83694..cf62f43a03da 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
@@ -269,7 +269,7 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu(
struct kgd_dev *kgd, struct kgd_mem *mem, void *drm_priv,
uint64_t *size);
int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(
- struct kgd_dev *kgd, struct kgd_mem *mem, void *drm_priv, bool *table_freed);
+ struct kgd_dev *kgd, struct kgd_mem *mem, void *drm_priv);
int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(
struct kgd_dev *kgd, struct kgd_mem *mem, void *drm_priv);
int amdgpu_amdkfd_gpuvm_sync_memory(
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index 3b8e1ee8c475..4fb15750b9bb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -1057,8 +1057,7 @@ static void unmap_bo_from_gpuvm(struct kgd_mem *mem,
static int update_gpuvm_pte(struct kgd_mem *mem,
struct kfd_mem_attachment *entry,
- struct amdgpu_sync *sync,
- bool *table_freed)
+ struct amdgpu_sync *sync)
{
struct amdgpu_bo_va *bo_va = entry->bo_va;
struct amdgpu_device *adev = entry->adev;
@@ -1069,7 +1068,7 @@ static int update_gpuvm_pte(struct kgd_mem *mem,
return ret;
/* Update the page tables */
- ret = amdgpu_vm_bo_update(adev, bo_va, false, table_freed);
+ ret = amdgpu_vm_bo_update(adev, bo_va, false);
if (ret) {
pr_err("amdgpu_vm_bo_update failed\n");
return ret;
@@ -1081,8 +1080,7 @@ static int update_gpuvm_pte(struct kgd_mem *mem,
static int map_bo_to_gpuvm(struct kgd_mem *mem,
struct kfd_mem_attachment *entry,
struct amdgpu_sync *sync,
- bool no_update_pte,
- bool *table_freed)
+ bool no_update_pte)
{
int ret;
@@ -1099,7 +1097,7 @@ static int map_bo_to_gpuvm(struct kgd_mem *mem,
if (no_update_pte)
return 0;
- ret = update_gpuvm_pte(mem, entry, sync, table_freed);
+ ret = update_gpuvm_pte(mem, entry, sync);
if (ret) {
pr_err("update_gpuvm_pte() failed\n");
goto update_gpuvm_pte_failed;
@@ -1393,8 +1391,7 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
domain = alloc_domain = AMDGPU_GEM_DOMAIN_VRAM;
alloc_flags = AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE;
alloc_flags |= (flags & KFD_IOC_ALLOC_MEM_FLAGS_PUBLIC) ?
- AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED :
- AMDGPU_GEM_CREATE_NO_CPU_ACCESS;
+ AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED : 0;
} else if (flags & KFD_IOC_ALLOC_MEM_FLAGS_GTT) {
domain = alloc_domain = AMDGPU_GEM_DOMAIN_GTT;
alloc_flags = 0;
@@ -1597,8 +1594,7 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu(
}
int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(
- struct kgd_dev *kgd, struct kgd_mem *mem,
- void *drm_priv, bool *table_freed)
+ struct kgd_dev *kgd, struct kgd_mem *mem, void *drm_priv)
{
struct amdgpu_device *adev = get_amdgpu_device(kgd);
struct amdgpu_vm *avm = drm_priv_to_vm(drm_priv);
@@ -1686,7 +1682,7 @@ int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(
entry->va, entry->va + bo_size, entry);
ret = map_bo_to_gpuvm(mem, entry, ctx.sync,
- is_invalid_userptr, table_freed);
+ is_invalid_userptr);
if (ret) {
pr_err("Failed to map bo to gpuvm\n");
goto out_unreserve;
@@ -2136,7 +2132,7 @@ static int validate_invalid_user_pages(struct amdkfd_process_info *process_info)
continue;
kfd_mem_dmaunmap_attachment(mem, attachment);
- ret = update_gpuvm_pte(mem, attachment, &sync, NULL);
+ ret = update_gpuvm_pte(mem, attachment, &sync);
if (ret) {
pr_err("%s: update PTE failed\n", __func__);
/* make sure this gets validated again */
@@ -2342,7 +2338,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef)
continue;
kfd_mem_dmaunmap_attachment(mem, attachment);
- ret = update_gpuvm_pte(mem, attachment, &sync_obj, NULL);
+ ret = update_gpuvm_pte(mem, attachment, &sync_obj);
if (ret) {
pr_debug("Memory eviction: update PTE failed. Try again\n");
goto validate_map_fail;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 76fe5b71e35d..30fa1f61e0e5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -781,7 +781,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
if (r)
return r;
- r = amdgpu_vm_bo_update(adev, fpriv->prt_va, false, NULL);
+ r = amdgpu_vm_bo_update(adev, fpriv->prt_va, false);
if (r)
return r;
@@ -792,7 +792,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
if (amdgpu_mcbp || amdgpu_sriov_vf(adev)) {
bo_va = fpriv->csa_va;
BUG_ON(!bo_va);
- r = amdgpu_vm_bo_update(adev, bo_va, false, NULL);
+ r = amdgpu_vm_bo_update(adev, bo_va, false);
if (r)
return r;
@@ -811,7 +811,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
if (bo_va == NULL)
continue;
- r = amdgpu_vm_bo_update(adev, bo_va, false, NULL);
+ r = amdgpu_vm_bo_update(adev, bo_va, false);
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 130a9adf09ef..d303e88e3c23 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -1369,6 +1369,38 @@ def_value:
adev->pm.smu_prv_buffer_size = 0;
}
+static int amdgpu_device_init_apu_flags(struct amdgpu_device *adev)
+{
+ if (!(adev->flags & AMD_IS_APU) ||
+ adev->asic_type < CHIP_RAVEN)
+ return 0;
+
+ switch (adev->asic_type) {
+ case CHIP_RAVEN:
+ if (adev->pdev->device == 0x15dd)
+ adev->apu_flags |= AMD_APU_IS_RAVEN;
+ if (adev->pdev->device == 0x15d8)
+ adev->apu_flags |= AMD_APU_IS_PICASSO;
+ break;
+ case CHIP_RENOIR:
+ if ((adev->pdev->device == 0x1636) ||
+ (adev->pdev->device == 0x164c))
+ adev->apu_flags |= AMD_APU_IS_RENOIR;
+ else
+ adev->apu_flags |= AMD_APU_IS_GREEN_SARDINE;
+ break;
+ case CHIP_VANGOGH:
+ adev->apu_flags |= AMD_APU_IS_VANGOGH;
+ break;
+ case CHIP_YELLOW_CARP:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/**
* amdgpu_device_check_arguments - validate module params
*
@@ -3386,6 +3418,10 @@ int amdgpu_device_init(struct amdgpu_device *adev,
mutex_init(&adev->psp.mutex);
mutex_init(&adev->notifier_lock);
+ r = amdgpu_device_init_apu_flags(adev);
+ if (r)
+ return r;
+
r = amdgpu_device_check_arguments(adev);
if (r)
return r;
@@ -4304,6 +4340,7 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev)
case CHIP_SIENNA_CICHLID:
case CHIP_NAVY_FLOUNDER:
case CHIP_DIMGREY_CAVEFISH:
+ case CHIP_BEIGE_GOBY:
case CHIP_VANGOGH:
case CHIP_ALDEBARAN:
break;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
index a3daaa89330c..a9475b207510 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
@@ -168,9 +168,21 @@ static int amdgpu_dma_buf_pin(struct dma_buf_attachment *attach)
{
struct drm_gem_object *obj = attach->dmabuf->priv;
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
+ int r;
/* pin buffer into GTT */
- return amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT);
+ r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT);
+ if (r)
+ return r;
+
+ if (bo->tbo.moving) {
+ r = dma_fence_wait(bo->tbo.moving, true);
+ if (r) {
+ amdgpu_bo_unpin(bo);
+ return r;
+ }
+ }
+ return 0;
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 6f30c525caac..abb928894eac 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -160,6 +160,7 @@ int amdgpu_smu_pptable_id = -1;
* highest. That helps saving some idle power.
* DISABLE_FRACTIONAL_PWM (bit 2) disabled by default
* PSR (bit 3) disabled by default
+ * EDP NO POWER SEQUENCING (bit 4) disabled by default
*/
uint amdgpu_dc_feature_mask = 2;
uint amdgpu_dc_debug_mask;
@@ -1167,6 +1168,7 @@ static const struct pci_device_id pciidlist[] = {
{0x1002, 0x734F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_NAVI14},
/* Renoir */
+ {0x1002, 0x15E7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RENOIR|AMD_IS_APU},
{0x1002, 0x1636, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RENOIR|AMD_IS_APU},
{0x1002, 0x1638, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RENOIR|AMD_IS_APU},
{0x1002, 0x164C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RENOIR|AMD_IS_APU},
@@ -1198,6 +1200,7 @@ static const struct pci_device_id pciidlist[] = {
{0x1002, 0x73E0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_DIMGREY_CAVEFISH},
{0x1002, 0x73E1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_DIMGREY_CAVEFISH},
{0x1002, 0x73E2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_DIMGREY_CAVEFISH},
+ {0x1002, 0x73E3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_DIMGREY_CAVEFISH},
{0x1002, 0x73FF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_DIMGREY_CAVEFISH},
/* Aldebaran */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index b3404c43a911..d0d9bc445d7b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -612,7 +612,7 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
if (operation == AMDGPU_VA_OP_MAP ||
operation == AMDGPU_VA_OP_REPLACE) {
- r = amdgpu_vm_bo_update(adev, bo_va, false, NULL);
+ r = amdgpu_vm_bo_update(adev, bo_va, false);
if (r)
goto error;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
index 0174f7817ce2..d0b8d415b63b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
@@ -562,6 +562,7 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev)
case CHIP_NAVI14:
case CHIP_NAVI12:
case CHIP_VANGOGH:
+ case CHIP_YELLOW_CARP:
/* Don't enable it by default yet.
*/
if (amdgpu_tmz < 1) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
index 32ce0e679dc7..83af307e97cd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
@@ -278,6 +278,21 @@ static bool amdgpu_msi_ok(struct amdgpu_device *adev)
return true;
}
+static void amdgpu_restore_msix(struct amdgpu_device *adev)
+{
+ u16 ctrl;
+
+ pci_read_config_word(adev->pdev, adev->pdev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
+ if (!(ctrl & PCI_MSIX_FLAGS_ENABLE))
+ return;
+
+ /* VF FLR */
+ ctrl &= ~PCI_MSIX_FLAGS_ENABLE;
+ pci_write_config_word(adev->pdev, adev->pdev->msix_cap + PCI_MSIX_FLAGS, ctrl);
+ ctrl |= PCI_MSIX_FLAGS_ENABLE;
+ pci_write_config_word(adev->pdev, adev->pdev->msix_cap + PCI_MSIX_FLAGS, ctrl);
+}
+
/**
* amdgpu_irq_init - initialize interrupt handling
*
@@ -569,6 +584,9 @@ void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device *adev)
{
int i, j, k;
+ if (amdgpu_sriov_vf(adev))
+ amdgpu_restore_msix(adev);
+
for (i = 0; i < AMDGPU_IRQ_CLIENTID_MAX; ++i) {
if (!adev->irq.client[i].sources)
continue;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
index d6c54c7f7679..4b153daf283d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
@@ -160,7 +160,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
struct mm_struct *mm, struct page **pages,
uint64_t start, uint64_t npages,
struct hmm_range **phmm_range, bool readonly,
- bool mmap_locked)
+ bool mmap_locked, void *owner)
{
struct hmm_range *hmm_range;
unsigned long timeout;
@@ -185,6 +185,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
hmm_range->hmm_pfns = pfns;
hmm_range->start = start;
hmm_range->end = start + npages * PAGE_SIZE;
+ hmm_range->dev_private_owner = owner;
/* Assuming 512MB takes maxmium 1 second to fault page address */
timeout = max(npages >> 17, 1ULL) * HMM_RANGE_DEFAULT_TIMEOUT;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h
index 7f7d37a457c3..14a3c1864085 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.h
@@ -34,7 +34,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
struct mm_struct *mm, struct page **pages,
uint64_t start, uint64_t npages,
struct hmm_range **phmm_range, bool readonly,
- bool mmap_locked);
+ bool mmap_locked, void *owner);
int amdgpu_hmm_range_get_pages_done(struct hmm_range *hmm_range);
#if defined(CONFIG_HMM_MIRROR)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h
index 25ee53545837..45295dce5c3e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h
@@ -93,6 +93,8 @@ struct amdgpu_nbio_funcs {
void (*enable_aspm)(struct amdgpu_device *adev,
bool enable);
void (*program_aspm)(struct amdgpu_device *adev);
+ void (*apply_lc_spc_mode_wa)(struct amdgpu_device *adev);
+ void (*apply_l1_link_width_reconfig_wa)(struct amdgpu_device *adev);
};
struct amdgpu_nbio {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
index c13b02caf8c3..fc66aca28594 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
@@ -809,7 +809,7 @@ static int amdgpu_ras_enable_all_features(struct amdgpu_device *adev,
/* query/inject/cure begin */
int amdgpu_ras_query_error_status(struct amdgpu_device *adev,
- struct ras_query_if *info)
+ struct ras_query_if *info)
{
struct ras_manager *obj = amdgpu_ras_find_obj(adev, &info->head);
struct ras_err_data err_data = {0, 0, 0, NULL};
@@ -1043,17 +1043,32 @@ int amdgpu_ras_error_inject(struct amdgpu_device *adev,
return ret;
}
-/* get the total error counts on all IPs */
-void amdgpu_ras_query_error_count(struct amdgpu_device *adev,
- unsigned long *ce_count,
- unsigned long *ue_count)
+/**
+ * amdgpu_ras_query_error_count -- Get error counts of all IPs
+ * adev: pointer to AMD GPU device
+ * ce_count: pointer to an integer to be set to the count of correctible errors.
+ * ue_count: pointer to an integer to be set to the count of uncorrectible
+ * errors.
+ *
+ * If set, @ce_count or @ue_count, count and return the corresponding
+ * error counts in those integer pointers. Return 0 if the device
+ * supports RAS. Return -EOPNOTSUPP if the device doesn't support RAS.
+ */
+int amdgpu_ras_query_error_count(struct amdgpu_device *adev,
+ unsigned long *ce_count,
+ unsigned long *ue_count)
{
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct ras_manager *obj;
unsigned long ce, ue;
if (!adev->ras_enabled || !con)
- return;
+ return -EOPNOTSUPP;
+
+ /* Don't count since no reporting.
+ */
+ if (!ce_count && !ue_count)
+ return 0;
ce = 0;
ue = 0;
@@ -1061,9 +1076,11 @@ void amdgpu_ras_query_error_count(struct amdgpu_device *adev,
struct ras_query_if info = {
.head = obj->head,
};
+ int res;
- if (amdgpu_ras_query_error_status(adev, &info))
- return;
+ res = amdgpu_ras_query_error_status(adev, &info);
+ if (res)
+ return res;
ce += info.ce_count;
ue += info.ue_count;
@@ -1074,6 +1091,8 @@ void amdgpu_ras_query_error_count(struct amdgpu_device *adev,
if (ue_count)
*ue_count = ue;
+
+ return 0;
}
/* query/inject/cure end */
@@ -2137,9 +2156,10 @@ static void amdgpu_ras_counte_dw(struct work_struct *work)
/* Cache new values.
*/
- amdgpu_ras_query_error_count(adev, &ce_count, &ue_count);
- atomic_set(&con->ras_ce_count, ce_count);
- atomic_set(&con->ras_ue_count, ue_count);
+ if (amdgpu_ras_query_error_count(adev, &ce_count, &ue_count) == 0) {
+ atomic_set(&con->ras_ce_count, ce_count);
+ atomic_set(&con->ras_ue_count, ue_count);
+ }
pm_runtime_mark_last_busy(dev->dev);
Out:
@@ -2312,9 +2332,10 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev,
/* Those are the cached values at init.
*/
- amdgpu_ras_query_error_count(adev, &ce_count, &ue_count);
- atomic_set(&con->ras_ce_count, ce_count);
- atomic_set(&con->ras_ue_count, ue_count);
+ if (amdgpu_ras_query_error_count(adev, &ce_count, &ue_count) == 0) {
+ atomic_set(&con->ras_ce_count, ce_count);
+ atomic_set(&con->ras_ue_count, ue_count);
+ }
return 0;
cleanup:
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
index 256cea5d34f2..b504ed8c9b50 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
@@ -490,9 +490,9 @@ int amdgpu_ras_request_reset_on_boot(struct amdgpu_device *adev,
void amdgpu_ras_resume(struct amdgpu_device *adev);
void amdgpu_ras_suspend(struct amdgpu_device *adev);
-void amdgpu_ras_query_error_count(struct amdgpu_device *adev,
- unsigned long *ce_count,
- unsigned long *ue_count);
+int amdgpu_ras_query_error_count(struct amdgpu_device *adev,
+ unsigned long *ce_count,
+ unsigned long *ue_count);
/* error handling functions */
int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
index 0527772fe1b8..d855cb53c7e0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
@@ -176,10 +176,10 @@ TRACE_EVENT(amdgpu_cs_ioctl,
TP_fast_assign(
__entry->sched_job_id = job->base.id;
- __assign_str(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job))
+ __assign_str(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job));
__entry->context = job->base.s_fence->finished.context;
__entry->seqno = job->base.s_fence->finished.seqno;
- __assign_str(ring, to_amdgpu_ring(job->base.sched)->name)
+ __assign_str(ring, to_amdgpu_ring(job->base.sched)->name);
__entry->num_ibs = job->num_ibs;
),
TP_printk("sched_job=%llu, timeline=%s, context=%u, seqno=%u, ring_name=%s, num_ibs=%u",
@@ -201,10 +201,10 @@ TRACE_EVENT(amdgpu_sched_run_job,
TP_fast_assign(
__entry->sched_job_id = job->base.id;
- __assign_str(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job))
+ __assign_str(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job));
__entry->context = job->base.s_fence->finished.context;
__entry->seqno = job->base.s_fence->finished.seqno;
- __assign_str(ring, to_amdgpu_ring(job->base.sched)->name)
+ __assign_str(ring, to_amdgpu_ring(job->base.sched)->name);
__entry->num_ibs = job->num_ibs;
),
TP_printk("sched_job=%llu, timeline=%s, context=%u, seqno=%u, ring_name=%s, num_ibs=%u",
@@ -229,7 +229,7 @@ TRACE_EVENT(amdgpu_vm_grab_id,
TP_fast_assign(
__entry->pasid = vm->pasid;
- __assign_str(ring, ring->name)
+ __assign_str(ring, ring->name);
__entry->vmid = job->vmid;
__entry->vm_hub = ring->funcs->vmhub,
__entry->pd_addr = job->vm_pd_addr;
@@ -424,7 +424,7 @@ TRACE_EVENT(amdgpu_vm_flush,
),
TP_fast_assign(
- __assign_str(ring, ring->name)
+ __assign_str(ring, ring->name);
__entry->vmid = vmid;
__entry->vm_hub = ring->funcs->vmhub;
__entry->pd_addr = pd_addr;
@@ -525,7 +525,7 @@ TRACE_EVENT(amdgpu_ib_pipe_sync,
),
TP_fast_assign(
- __assign_str(ring, sched_job->base.sched->name)
+ __assign_str(ring, sched_job->base.sched->name);
__entry->id = sched_job->base.id;
__entry->fence = fence;
__entry->ctx = fence->context;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 6a214a4dfe04..3a55f08e00e1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -590,10 +590,6 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_device *bdev,
mem->bus.offset += adev->gmc.aper_base;
mem->bus.is_iomem = true;
- if (adev->gmc.xgmi.connected_to_cpu)
- mem->bus.caching = ttm_cached;
- else
- mem->bus.caching = ttm_write_combined;
break;
default:
return -EINVAL;
@@ -681,23 +677,23 @@ int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages)
return -ESRCH;
mmap_read_lock(mm);
- vma = find_vma(mm, start);
- mmap_read_unlock(mm);
- if (unlikely(!vma || start < vma->vm_start)) {
+ vma = vma_lookup(mm, start);
+ if (unlikely(!vma)) {
r = -EFAULT;
- goto out_putmm;
+ goto out_unlock;
}
if (unlikely((gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) &&
vma->vm_file)) {
r = -EPERM;
- goto out_putmm;
+ goto out_unlock;
}
readonly = amdgpu_ttm_tt_is_readonly(ttm);
r = amdgpu_hmm_range_get_pages(&bo->notifier, mm, pages, start,
ttm->num_pages, &gtt->range, readonly,
- false);
-out_putmm:
+ true, NULL);
+out_unlock:
+ mmap_read_unlock(mm);
mmput(mm);
return r;
@@ -923,7 +919,8 @@ static int amdgpu_ttm_backend_bind(struct ttm_device *bdev,
bo_mem->mem_type == AMDGPU_PL_OA)
return -EINVAL;
- if (!amdgpu_gtt_mgr_has_gart_addr(bo_mem)) {
+ if (bo_mem->mem_type != TTM_PL_TT ||
+ !amdgpu_gtt_mgr_has_gart_addr(bo_mem)) {
gtt->offset = AMDGPU_BO_INVALID_OFFSET;
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 79cfa2d68487..078c068937fe 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -1758,7 +1758,7 @@ int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
r = vm->update_funcs->commit(&params, fence);
if (table_freed)
- *table_freed = *table_freed || params.table_freed;
+ *table_freed = params.table_freed;
error_unlock:
amdgpu_vm_eviction_unlock(vm);
@@ -1816,7 +1816,6 @@ void amdgpu_vm_get_memory(struct amdgpu_vm *vm, uint64_t *vram_mem,
* @adev: amdgpu_device pointer
* @bo_va: requested BO and VM object
* @clear: if true clear the entries
- * @table_freed: return true if page table is freed
*
* Fill in the page table entries for @bo_va.
*
@@ -1824,7 +1823,7 @@ void amdgpu_vm_get_memory(struct amdgpu_vm *vm, uint64_t *vram_mem,
* 0 for success, -EINVAL for failure.
*/
int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va,
- bool clear, bool *table_freed)
+ bool clear)
{
struct amdgpu_bo *bo = bo_va->base.bo;
struct amdgpu_vm *vm = bo_va->base.vm;
@@ -1903,7 +1902,7 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va,
resv, mapping->start,
mapping->last, update_flags,
mapping->offset, mem,
- pages_addr, last_update, table_freed);
+ pages_addr, last_update, NULL);
if (r)
return r;
}
@@ -2155,7 +2154,7 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev,
list_for_each_entry_safe(bo_va, tmp, &vm->moved, base.vm_status) {
/* Per VM BOs never need to bo cleared in the page tables */
- r = amdgpu_vm_bo_update(adev, bo_va, false, NULL);
+ r = amdgpu_vm_bo_update(adev, bo_va, false);
if (r)
return r;
}
@@ -2174,7 +2173,7 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev,
else
clear = true;
- r = amdgpu_vm_bo_update(adev, bo_va, clear, NULL);
+ r = amdgpu_vm_bo_update(adev, bo_va, clear);
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
index ddb85a85cbba..f8fa653d4da7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -406,7 +406,7 @@ int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
struct dma_fence **fence, bool *free_table);
int amdgpu_vm_bo_update(struct amdgpu_device *adev,
struct amdgpu_bo_va *bo_va,
- bool clear, bool *table_freed);
+ bool clear);
bool amdgpu_vm_evictable(struct amdgpu_bo *bo);
void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev,
struct amdgpu_bo *bo, bool evicted);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
index 436ec246a7da..2fd77c36a1ff 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
@@ -463,6 +463,11 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
if (i == 1)
node->base.placement |= TTM_PL_FLAG_CONTIGUOUS;
+ if (adev->gmc.xgmi.connected_to_cpu)
+ node->base.bus.caching = ttm_cached;
+ else
+ node->base.bus.caching = ttm_write_combined;
+
atomic64_add(vis_usage, &mgr->vis_usage);
*res = &node->base;
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/athub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/athub_v2_0.c
index 5b90efd6f6d0..3ac505d954c4 100644
--- a/drivers/gpu/drm/amd/amdgpu/athub_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/athub_v2_0.c
@@ -36,9 +36,12 @@ athub_v2_0_update_medium_grain_clock_gating(struct amdgpu_device *adev,
{
uint32_t def, data;
+ if (!(adev->cg_flags & AMD_CG_SUPPORT_MC_MGCG))
+ return;
+
def = data = RREG32_SOC15(ATHUB, 0, mmATHUB_MISC_CNTL);
- if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_MGCG))
+ if (enable)
data |= ATHUB_MISC_CNTL__CG_ENABLE_MASK;
else
data &= ~ATHUB_MISC_CNTL__CG_ENABLE_MASK;
@@ -53,10 +56,13 @@ athub_v2_0_update_medium_grain_light_sleep(struct amdgpu_device *adev,
{
uint32_t def, data;
+ if (!((adev->cg_flags & AMD_CG_SUPPORT_MC_LS) &&
+ (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS)))
+ return;
+
def = data = RREG32_SOC15(ATHUB, 0, mmATHUB_MISC_CNTL);
- if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_LS) &&
- (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS))
+ if (enable)
data |= ATHUB_MISC_CNTL__CG_MEM_LS_ENABLE_MASK;
else
data &= ~ATHUB_MISC_CNTL__CG_MEM_LS_ENABLE_MASK;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c
index 33324427b555..7e0d8c092c7e 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c
@@ -766,7 +766,7 @@ static const struct amdgpu_irq_src_funcs dce_virtual_crtc_irq_funcs = {
static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev)
{
- adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_VBLANK6 + 1;
+ adev->crtc_irq.num_types = adev->mode_info.num_crtc;
adev->crtc_irq.funcs = &dce_virtual_crtc_irq_funcs;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
index 2d56b60bc058..f5e9c022960b 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
@@ -5086,47 +5086,44 @@ static void gfx_v10_0_tcp_harvest(struct amdgpu_device *adev)
4 + /* RMI */
1); /* SQG */
- if (adev->asic_type == CHIP_NAVI10 ||
- adev->asic_type == CHIP_NAVI14 ||
- adev->asic_type == CHIP_NAVI12) {
- mutex_lock(&adev->grbm_idx_mutex);
- for (i = 0; i < adev->gfx.config.max_shader_engines; i++) {
- for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) {
- gfx_v10_0_select_se_sh(adev, i, j, 0xffffffff);
- wgp_active_bitmap = gfx_v10_0_get_wgp_active_bitmap_per_sh(adev);
- /*
- * Set corresponding TCP bits for the inactive WGPs in
- * GCRD_SA_TARGETS_DISABLE
- */
- gcrd_targets_disable_tcp = 0;
- /* Set TCP & SQC bits in UTCL1_UTCL0_INVREQ_DISABLE */
- utcl_invreq_disable = 0;
-
- for (k = 0; k < max_wgp_per_sh; k++) {
- if (!(wgp_active_bitmap & (1 << k))) {
- gcrd_targets_disable_tcp |= 3 << (2 * k);
- utcl_invreq_disable |= (3 << (2 * k)) |
- (3 << (2 * (max_wgp_per_sh + k)));
- }
+ mutex_lock(&adev->grbm_idx_mutex);
+ for (i = 0; i < adev->gfx.config.max_shader_engines; i++) {
+ for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) {
+ gfx_v10_0_select_se_sh(adev, i, j, 0xffffffff);
+ wgp_active_bitmap = gfx_v10_0_get_wgp_active_bitmap_per_sh(adev);
+ /*
+ * Set corresponding TCP bits for the inactive WGPs in
+ * GCRD_SA_TARGETS_DISABLE
+ */
+ gcrd_targets_disable_tcp = 0;
+ /* Set TCP & SQC bits in UTCL1_UTCL0_INVREQ_DISABLE */
+ utcl_invreq_disable = 0;
+
+ for (k = 0; k < max_wgp_per_sh; k++) {
+ if (!(wgp_active_bitmap & (1 << k))) {
+ gcrd_targets_disable_tcp |= 3 << (2 * k);
+ gcrd_targets_disable_tcp |= 1 << (k + (max_wgp_per_sh * 2));
+ utcl_invreq_disable |= (3 << (2 * k)) |
+ (3 << (2 * (max_wgp_per_sh + k)));
}
-
- tmp = RREG32_SOC15(GC, 0, mmUTCL1_UTCL0_INVREQ_DISABLE);
- /* only override TCP & SQC bits */
- tmp &= 0xffffffff << (4 * max_wgp_per_sh);
- tmp |= (utcl_invreq_disable & utcl_invreq_disable_mask);
- WREG32_SOC15(GC, 0, mmUTCL1_UTCL0_INVREQ_DISABLE, tmp);
-
- tmp = RREG32_SOC15(GC, 0, mmGCRD_SA_TARGETS_DISABLE);
- /* only override TCP bits */
- tmp &= 0xffffffff << (2 * max_wgp_per_sh);
- tmp |= (gcrd_targets_disable_tcp & gcrd_targets_disable_mask);
- WREG32_SOC15(GC, 0, mmGCRD_SA_TARGETS_DISABLE, tmp);
}
- }
- gfx_v10_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
- mutex_unlock(&adev->grbm_idx_mutex);
+ tmp = RREG32_SOC15(GC, 0, mmUTCL1_UTCL0_INVREQ_DISABLE);
+ /* only override TCP & SQC bits */
+ tmp &= (0xffffffffU << (4 * max_wgp_per_sh));
+ tmp |= (utcl_invreq_disable & utcl_invreq_disable_mask);
+ WREG32_SOC15(GC, 0, mmUTCL1_UTCL0_INVREQ_DISABLE, tmp);
+
+ tmp = RREG32_SOC15(GC, 0, mmGCRD_SA_TARGETS_DISABLE);
+ /* only override TCP & SQC bits */
+ tmp &= (0xffffffffU << (3 * max_wgp_per_sh));
+ tmp |= (gcrd_targets_disable_tcp & gcrd_targets_disable_mask);
+ WREG32_SOC15(GC, 0, mmGCRD_SA_TARGETS_DISABLE, tmp);
+ }
}
+
+ gfx_v10_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
+ mutex_unlock(&adev->grbm_idx_mutex);
}
static void gfx_v10_0_get_tcc_info(struct amdgpu_device *adev)
@@ -7404,7 +7401,10 @@ static int gfx_v10_0_hw_init(void *handle)
* init golden registers and rlc resume may override some registers,
* reconfig them here
*/
- gfx_v10_0_tcp_harvest(adev);
+ if (adev->asic_type == CHIP_NAVI10 ||
+ adev->asic_type == CHIP_NAVI14 ||
+ adev->asic_type == CHIP_NAVI12)
+ gfx_v10_0_tcp_harvest(adev);
r = gfx_v10_0_cp_resume(adev);
if (r)
@@ -7777,6 +7777,9 @@ static void gfx_v10_0_update_medium_grain_clock_gating(struct amdgpu_device *ade
{
uint32_t data, def;
+ if (!(adev->cg_flags & (AMD_CG_SUPPORT_GFX_MGCG | AMD_CG_SUPPORT_GFX_MGLS)))
+ return;
+
/* It is disabled by HW by default */
if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) {
/* 0 - Disable some blocks' MGCG */
@@ -7791,6 +7794,7 @@ static void gfx_v10_0_update_medium_grain_clock_gating(struct amdgpu_device *ade
RLC_CGTT_MGCG_OVERRIDE__RLC_CGTT_SCLK_OVERRIDE_MASK |
RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGCG_OVERRIDE_MASK |
RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGLS_OVERRIDE_MASK |
+ RLC_CGTT_MGCG_OVERRIDE__GFXIP_FGCG_OVERRIDE_MASK |
RLC_CGTT_MGCG_OVERRIDE__ENABLE_CGTS_LEGACY_MASK);
if (def != data)
@@ -7813,13 +7817,15 @@ static void gfx_v10_0_update_medium_grain_clock_gating(struct amdgpu_device *ade
WREG32_SOC15(GC, 0, mmCP_MEM_SLP_CNTL, data);
}
}
- } else {
+ } else if (!enable || !(adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) {
/* 1 - MGCG_OVERRIDE */
def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE);
data |= (RLC_CGTT_MGCG_OVERRIDE__RLC_CGTT_SCLK_OVERRIDE_MASK |
RLC_CGTT_MGCG_OVERRIDE__GRBM_CGTT_SCLK_OVERRIDE_MASK |
RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGCG_OVERRIDE_MASK |
- RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGLS_OVERRIDE_MASK);
+ RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGLS_OVERRIDE_MASK |
+ RLC_CGTT_MGCG_OVERRIDE__GFXIP_FGCG_OVERRIDE_MASK |
+ RLC_CGTT_MGCG_OVERRIDE__ENABLE_CGTS_LEGACY_MASK);
if (def != data)
WREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE, data);
@@ -7845,22 +7851,34 @@ static void gfx_v10_0_update_3d_clock_gating(struct amdgpu_device *adev,
{
uint32_t data, def;
+ if (!(adev->cg_flags & (AMD_CG_SUPPORT_GFX_3D_CGCG | AMD_CG_SUPPORT_GFX_3D_CGLS)))
+ return;
+
/* Enable 3D CGCG/CGLS */
- if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGCG)) {
+ if (enable) {
/* write cmd to clear cgcg/cgls ov */
def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE);
+
/* unset CGCG override */
- data &= ~RLC_CGTT_MGCG_OVERRIDE__GFXIP_GFX3D_CG_OVERRIDE_MASK;
+ if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGCG)
+ data &= ~RLC_CGTT_MGCG_OVERRIDE__GFXIP_GFX3D_CG_OVERRIDE_MASK;
+
/* update CGCG and CGLS override bits */
if (def != data)
WREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE, data);
+
/* enable 3Dcgcg FSM(0x0000363f) */
def = RREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL_3D);
- data = (0x36 << RLC_CGCG_CGLS_CTRL_3D__CGCG_GFX_IDLE_THRESHOLD__SHIFT) |
- RLC_CGCG_CGLS_CTRL_3D__CGCG_EN_MASK;
+ data = 0;
+
+ if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGCG)
+ data = (0x36 << RLC_CGCG_CGLS_CTRL_3D__CGCG_GFX_IDLE_THRESHOLD__SHIFT) |
+ RLC_CGCG_CGLS_CTRL_3D__CGCG_EN_MASK;
+
if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGLS)
data |= (0x000F << RLC_CGCG_CGLS_CTRL_3D__CGLS_REP_COMPANSAT_DELAY__SHIFT) |
RLC_CGCG_CGLS_CTRL_3D__CGLS_EN_MASK;
+
if (def != data)
WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL_3D, data);
@@ -7873,9 +7891,14 @@ static void gfx_v10_0_update_3d_clock_gating(struct amdgpu_device *adev,
} else {
/* Disable CGCG/CGLS */
def = data = RREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL_3D);
+
/* disable cgcg, cgls should be disabled */
- data &= ~(RLC_CGCG_CGLS_CTRL_3D__CGCG_EN_MASK |
- RLC_CGCG_CGLS_CTRL_3D__CGLS_EN_MASK);
+ if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGCG)
+ data &= ~RLC_CGCG_CGLS_CTRL_3D__CGCG_EN_MASK;
+
+ if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGLS)
+ data &= ~RLC_CGCG_CGLS_CTRL_3D__CGLS_EN_MASK;
+
/* disable cgcg and cgls in FSM */
if (def != data)
WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL_3D, data);
@@ -7887,25 +7910,35 @@ static void gfx_v10_0_update_coarse_grain_clock_gating(struct amdgpu_device *ade
{
uint32_t def, data;
- if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)) {
+ if (!(adev->cg_flags & (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_CGLS)))
+ return;
+
+ if (enable) {
def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE);
+
/* unset CGCG override */
- data &= ~RLC_CGTT_MGCG_OVERRIDE__GFXIP_CGCG_OVERRIDE_MASK;
+ if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)
+ data &= ~RLC_CGTT_MGCG_OVERRIDE__GFXIP_CGCG_OVERRIDE_MASK;
+
if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGLS)
data &= ~RLC_CGTT_MGCG_OVERRIDE__GFXIP_CGLS_OVERRIDE_MASK;
- else
- data |= RLC_CGTT_MGCG_OVERRIDE__GFXIP_CGLS_OVERRIDE_MASK;
+
/* update CGCG and CGLS override bits */
if (def != data)
WREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE, data);
/* enable cgcg FSM(0x0000363F) */
def = RREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL);
- data = (0x36 << RLC_CGCG_CGLS_CTRL__CGCG_GFX_IDLE_THRESHOLD__SHIFT) |
- RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK;
+ data = 0;
+
+ if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)
+ data = (0x36 << RLC_CGCG_CGLS_CTRL__CGCG_GFX_IDLE_THRESHOLD__SHIFT) |
+ RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK;
+
if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGLS)
data |= (0x000F << RLC_CGCG_CGLS_CTRL__CGLS_REP_COMPANSAT_DELAY__SHIFT) |
RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK;
+
if (def != data)
WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL, data);
@@ -7917,8 +7950,14 @@ static void gfx_v10_0_update_coarse_grain_clock_gating(struct amdgpu_device *ade
WREG32_SOC15(GC, 0, mmCP_RB_WPTR_POLL_CNTL, data);
} else {
def = data = RREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL);
+
/* reset CGCG/CGLS bits */
- data &= ~(RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK | RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK);
+ if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)
+ data &= ~RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK;
+
+ if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGLS)
+ data &= ~RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK;
+
/* disable cgcg and cgls in FSM */
if (def != data)
WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL, data);
@@ -7930,7 +7969,10 @@ static void gfx_v10_0_update_fine_grain_clock_gating(struct amdgpu_device *adev,
{
uint32_t def, data;
- if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_FGCG)) {
+ if (!(adev->cg_flags & AMD_CG_SUPPORT_GFX_FGCG))
+ return;
+
+ if (enable) {
def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE);
/* unset FGCG override */
data &= ~RLC_CGTT_MGCG_OVERRIDE__GFXIP_FGCG_OVERRIDE_MASK;
@@ -7961,6 +8003,97 @@ static void gfx_v10_0_update_fine_grain_clock_gating(struct amdgpu_device *adev,
}
}
+static void gfx_v10_0_apply_medium_grain_clock_gating_workaround(struct amdgpu_device *adev)
+{
+ uint32_t reg_data = 0;
+ uint32_t reg_idx = 0;
+ uint32_t i;
+
+ const uint32_t tcp_ctrl_regs[] = {
+ mmCGTS_SA0_WGP00_CU0_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP00_CU1_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP01_CU0_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP01_CU1_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP02_CU0_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP02_CU1_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP10_CU0_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP10_CU1_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP11_CU0_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP11_CU1_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP12_CU0_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP12_CU1_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP00_CU0_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP00_CU1_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP01_CU0_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP01_CU1_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP02_CU0_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP02_CU1_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP10_CU0_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP10_CU1_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP11_CU0_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP11_CU1_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP12_CU0_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP12_CU1_TCP_CTRL_REG
+ };
+
+ const uint32_t tcp_ctrl_regs_nv12[] = {
+ mmCGTS_SA0_WGP00_CU0_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP00_CU1_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP01_CU0_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP01_CU1_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP02_CU0_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP02_CU1_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP10_CU0_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP10_CU1_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP11_CU0_TCP_CTRL_REG,
+ mmCGTS_SA0_WGP11_CU1_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP00_CU0_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP00_CU1_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP01_CU0_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP01_CU1_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP02_CU0_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP02_CU1_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP10_CU0_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP10_CU1_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP11_CU0_TCP_CTRL_REG,
+ mmCGTS_SA1_WGP11_CU1_TCP_CTRL_REG,
+ };
+
+ const uint32_t sm_ctlr_regs[] = {
+ mmCGTS_SA0_QUAD0_SM_CTRL_REG,
+ mmCGTS_SA0_QUAD1_SM_CTRL_REG,
+ mmCGTS_SA1_QUAD0_SM_CTRL_REG,
+ mmCGTS_SA1_QUAD1_SM_CTRL_REG
+ };
+
+ if (adev->asic_type == CHIP_NAVI12) {
+ for (i = 0; i < ARRAY_SIZE(tcp_ctrl_regs_nv12); i++) {
+ reg_idx = adev->reg_offset[GC_HWIP][0][mmCGTS_SA0_WGP00_CU0_TCP_CTRL_REG_BASE_IDX] +
+ tcp_ctrl_regs_nv12[i];
+ reg_data = RREG32(reg_idx);
+ reg_data |= CGTS_SA0_WGP00_CU0_TCP_CTRL_REG__TCPI_LS_OVERRIDE_MASK;
+ WREG32(reg_idx, reg_data);
+ }
+ } else {
+ for (i = 0; i < ARRAY_SIZE(tcp_ctrl_regs); i++) {
+ reg_idx = adev->reg_offset[GC_HWIP][0][mmCGTS_SA0_WGP00_CU0_TCP_CTRL_REG_BASE_IDX] +
+ tcp_ctrl_regs[i];
+ reg_data = RREG32(reg_idx);
+ reg_data |= CGTS_SA0_WGP00_CU0_TCP_CTRL_REG__TCPI_LS_OVERRIDE_MASK;
+ WREG32(reg_idx, reg_data);
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sm_ctlr_regs); i++) {
+ reg_idx = adev->reg_offset[GC_HWIP][0][mmCGTS_SA0_QUAD0_SM_CTRL_REG_BASE_IDX] +
+ sm_ctlr_regs[i];
+ reg_data = RREG32(reg_idx);
+ reg_data &= ~CGTS_SA0_QUAD0_SM_CTRL_REG__SM_MODE_MASK;
+ reg_data |= 2 << CGTS_SA0_QUAD0_SM_CTRL_REG__SM_MODE__SHIFT;
+ WREG32(reg_idx, reg_data);
+ }
+}
+
static int gfx_v10_0_update_gfx_clock_gating(struct amdgpu_device *adev,
bool enable)
{
@@ -7977,6 +8110,10 @@ static int gfx_v10_0_update_gfx_clock_gating(struct amdgpu_device *adev,
gfx_v10_0_update_3d_clock_gating(adev, enable);
/* === CGCG + CGLS === */
gfx_v10_0_update_coarse_grain_clock_gating(adev, enable);
+
+ if ((adev->asic_type >= CHIP_NAVI10) &&
+ (adev->asic_type <= CHIP_NAVI12))
+ gfx_v10_0_apply_medium_grain_clock_gating_workaround(adev);
} else {
/* CGCG/CGLS should be disabled before MGCG/MGLS
* === CGCG + CGLS ===
@@ -9324,17 +9461,22 @@ static void gfx_v10_0_set_user_wgp_inactive_bitmap_per_sh(struct amdgpu_device *
static u32 gfx_v10_0_get_wgp_active_bitmap_per_sh(struct amdgpu_device *adev)
{
- u32 data, wgp_bitmask;
- data = RREG32_SOC15(GC, 0, mmCC_GC_SHADER_ARRAY_CONFIG);
- data |= RREG32_SOC15(GC, 0, mmGC_USER_SHADER_ARRAY_CONFIG);
+ u32 disabled_mask =
+ ~amdgpu_gfx_create_bitmask(adev->gfx.config.max_cu_per_sh >> 1);
+ u32 efuse_setting = 0;
+ u32 vbios_setting = 0;
+
+ efuse_setting = RREG32_SOC15(GC, 0, mmCC_GC_SHADER_ARRAY_CONFIG);
+ efuse_setting &= CC_GC_SHADER_ARRAY_CONFIG__INACTIVE_WGPS_MASK;
+ efuse_setting >>= CC_GC_SHADER_ARRAY_CONFIG__INACTIVE_WGPS__SHIFT;
- data &= CC_GC_SHADER_ARRAY_CONFIG__INACTIVE_WGPS_MASK;
- data >>= CC_GC_SHADER_ARRAY_CONFIG__INACTIVE_WGPS__SHIFT;
+ vbios_setting = RREG32_SOC15(GC, 0, mmGC_USER_SHADER_ARRAY_CONFIG);
+ vbios_setting &= GC_USER_SHADER_ARRAY_CONFIG__INACTIVE_WGPS_MASK;
+ vbios_setting >>= GC_USER_SHADER_ARRAY_CONFIG__INACTIVE_WGPS__SHIFT;
- wgp_bitmask =
- amdgpu_gfx_create_bitmask(adev->gfx.config.max_cu_per_sh >> 1);
+ disabled_mask |= efuse_setting | vbios_setting;
- return (~data) & wgp_bitmask;
+ return (~disabled_mask);
}
static u32 gfx_v10_0_get_cu_active_bitmap_per_sh(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c b/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c
index 7a15e669b68d..5793977953cc 100644
--- a/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c
@@ -90,45 +90,56 @@ static void hdp_v5_0_update_mem_power_gating(struct amdgpu_device *adev,
RC_MEM_POWER_SD_EN, 0);
WREG32_SOC15(HDP, 0, mmHDP_MEM_POWER_CTRL, hdp_mem_pwr_cntl);
- /* only one clock gating mode (LS/DS/SD) can be enabled */
- if (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS) {
- hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
- HDP_MEM_POWER_CTRL,
- IPH_MEM_POWER_LS_EN, enable);
- hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
- HDP_MEM_POWER_CTRL,
- RC_MEM_POWER_LS_EN, enable);
- } else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_DS) {
- hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
- HDP_MEM_POWER_CTRL,
- IPH_MEM_POWER_DS_EN, enable);
- hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
- HDP_MEM_POWER_CTRL,
- RC_MEM_POWER_DS_EN, enable);
- } else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_SD) {
- hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
- HDP_MEM_POWER_CTRL,
- IPH_MEM_POWER_SD_EN, enable);
- /* RC should not use shut down mode, fallback to ds */
- hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
- HDP_MEM_POWER_CTRL,
- RC_MEM_POWER_DS_EN, enable);
- }
-
- /* confirmed that IPH_MEM_POWER_CTRL_EN and RC_MEM_POWER_CTRL_EN have to
- * be set for SRAM LS/DS/SD */
- if (adev->cg_flags & (AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_HDP_DS |
- AMD_CG_SUPPORT_HDP_SD)) {
- hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
- IPH_MEM_POWER_CTRL_EN, 1);
- hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
- RC_MEM_POWER_CTRL_EN, 1);
+ /* Already disabled above. The actions below are for "enabled" only */
+ if (enable) {
+ /* only one clock gating mode (LS/DS/SD) can be enabled */
+ if (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS) {
+ hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
+ HDP_MEM_POWER_CTRL,
+ IPH_MEM_POWER_LS_EN, 1);
+ hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
+ HDP_MEM_POWER_CTRL,
+ RC_MEM_POWER_LS_EN, 1);
+ } else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_DS) {
+ hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
+ HDP_MEM_POWER_CTRL,
+ IPH_MEM_POWER_DS_EN, 1);
+ hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
+ HDP_MEM_POWER_CTRL,
+ RC_MEM_POWER_DS_EN, 1);
+ } else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_SD) {
+ hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
+ HDP_MEM_POWER_CTRL,
+ IPH_MEM_POWER_SD_EN, 1);
+ /* RC should not use shut down mode, fallback to ds or ls if allowed */
+ if (adev->cg_flags & AMD_CG_SUPPORT_HDP_DS)
+ hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
+ HDP_MEM_POWER_CTRL,
+ RC_MEM_POWER_DS_EN, 1);
+ else if (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS)
+ hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl,
+ HDP_MEM_POWER_CTRL,
+ RC_MEM_POWER_LS_EN, 1);
+ }
+
+ /* confirmed that IPH_MEM_POWER_CTRL_EN and RC_MEM_POWER_CTRL_EN have to
+ * be set for SRAM LS/DS/SD */
+ if (adev->cg_flags & (AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_HDP_DS |
+ AMD_CG_SUPPORT_HDP_SD)) {
+ hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
+ IPH_MEM_POWER_CTRL_EN, 1);
+ hdp_mem_pwr_cntl = REG_SET_FIELD(hdp_mem_pwr_cntl, HDP_MEM_POWER_CTRL,
+ RC_MEM_POWER_CTRL_EN, 1);
+ WREG32_SOC15(HDP, 0, mmHDP_MEM_POWER_CTRL, hdp_mem_pwr_cntl);
+ }
}
- WREG32_SOC15(HDP, 0, mmHDP_MEM_POWER_CTRL, hdp_mem_pwr_cntl);
-
- /* restore IPH & RC clock override after clock/power mode changing */
- WREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL, hdp_clk_cntl1);
+ /* disable IPH & RC clock override after clock/power mode changing */
+ hdp_clk_cntl = REG_SET_FIELD(hdp_clk_cntl, HDP_CLK_CNTL,
+ IPH_MEM_CLK_SOFT_OVERRIDE, 0);
+ hdp_clk_cntl = REG_SET_FIELD(hdp_clk_cntl, HDP_CLK_CNTL,
+ RC_MEM_CLK_SOFT_OVERRIDE, 0);
+ WREG32_SOC15(HDP, 0, mmHDP_CLK_CNTL, hdp_clk_cntl);
}
static void hdp_v5_0_update_medium_grain_clock_gating(struct amdgpu_device *adev,
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
index f7e93bbc4e15..7ded6b2f058e 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
@@ -568,6 +568,9 @@ static void mmhub_v2_0_update_medium_grain_clock_gating(struct amdgpu_device *ad
{
uint32_t def, data, def1, data1;
+ if (!(adev->cg_flags & AMD_CG_SUPPORT_MC_MGCG))
+ return;
+
switch (adev->asic_type) {
case CHIP_SIENNA_CICHLID:
case CHIP_NAVY_FLOUNDER:
@@ -582,7 +585,7 @@ static void mmhub_v2_0_update_medium_grain_clock_gating(struct amdgpu_device *ad
break;
}
- if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_MGCG)) {
+ if (enable) {
data |= MM_ATC_L2_MISC_CG__ENABLE_MASK;
data1 &= ~(DAGB0_CNTL_MISC2__DISABLE_WRREQ_CG_MASK |
@@ -627,6 +630,9 @@ static void mmhub_v2_0_update_medium_grain_light_sleep(struct amdgpu_device *ade
{
uint32_t def, data;
+ if (!(adev->cg_flags & AMD_CG_SUPPORT_MC_LS))
+ return;
+
switch (adev->asic_type) {
case CHIP_SIENNA_CICHLID:
case CHIP_NAVY_FLOUNDER:
@@ -639,7 +645,7 @@ static void mmhub_v2_0_update_medium_grain_light_sleep(struct amdgpu_device *ade
break;
}
- if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_LS))
+ if (enable)
data |= MM_ATC_L2_MISC_CG__MEM_LS_ENABLE_MASK;
else
data &= ~MM_ATC_L2_MISC_CG__MEM_LS_ENABLE_MASK;
diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c
index 3ee481557fc9..ff2307d7ee0f 100644
--- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c
+++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c
@@ -252,7 +252,7 @@ static void xgpu_ai_mailbox_flr_work(struct work_struct *work)
* otherwise the mailbox msg will be ruined/reseted by
* the VF FLR.
*/
- if (!down_read_trylock(&adev->reset_sem))
+ if (!down_write_trylock(&adev->reset_sem))
return;
amdgpu_virt_fini_data_exchange(adev);
@@ -268,7 +268,7 @@ static void xgpu_ai_mailbox_flr_work(struct work_struct *work)
flr_done:
atomic_set(&adev->in_gpu_reset, 0);
- up_read(&adev->reset_sem);
+ up_write(&adev->reset_sem);
/* Trigger recovery for world switch failure if no TDR */
if (amdgpu_device_should_recover_gpu(adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c
index 48e588d3c409..9f7aac435d69 100644
--- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c
+++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c
@@ -273,7 +273,7 @@ static void xgpu_nv_mailbox_flr_work(struct work_struct *work)
* otherwise the mailbox msg will be ruined/reseted by
* the VF FLR.
*/
- if (!down_read_trylock(&adev->reset_sem))
+ if (!down_write_trylock(&adev->reset_sem))
return;
amdgpu_virt_fini_data_exchange(adev);
@@ -289,7 +289,7 @@ static void xgpu_nv_mailbox_flr_work(struct work_struct *work)
flr_done:
atomic_set(&adev->in_gpu_reset, 0);
- up_read(&adev->reset_sem);
+ up_write(&adev->reset_sem);
/* Trigger recovery for world switch failure if no TDR */
if (amdgpu_device_should_recover_gpu(adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c b/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c
index 05ddec7ba7e2..7b79eeaa88aa 100644
--- a/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c
@@ -51,6 +51,8 @@
#define mmBIF_MMSCH1_DOORBELL_RANGE 0x01d8
#define mmBIF_MMSCH1_DOORBELL_RANGE_BASE_IDX 2
+#define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288
+
static void nbio_v2_3_remap_hdp_registers(struct amdgpu_device *adev)
{
WREG32_SOC15(NBIO, 0, mmREMAP_HDP_MEM_FLUSH_CNTL,
@@ -218,8 +220,11 @@ static void nbio_v2_3_update_medium_grain_clock_gating(struct amdgpu_device *ade
{
uint32_t def, data;
+ if (!(adev->cg_flags & AMD_CG_SUPPORT_BIF_MGCG))
+ return;
+
def = data = RREG32_PCIE(smnCPM_CONTROL);
- if (enable && (adev->cg_flags & AMD_CG_SUPPORT_BIF_MGCG)) {
+ if (enable) {
data |= (CPM_CONTROL__LCLK_DYN_GATE_ENABLE_MASK |
CPM_CONTROL__TXCLK_DYN_GATE_ENABLE_MASK |
CPM_CONTROL__TXCLK_LCNT_GATE_ENABLE_MASK |
@@ -244,8 +249,11 @@ static void nbio_v2_3_update_medium_grain_light_sleep(struct amdgpu_device *adev
{
uint32_t def, data;
+ if (!(adev->cg_flags & AMD_CG_SUPPORT_BIF_LS))
+ return;
+
def = data = RREG32_PCIE(smnPCIE_CNTL2);
- if (enable && (adev->cg_flags & AMD_CG_SUPPORT_BIF_LS)) {
+ if (enable) {
data |= (PCIE_CNTL2__SLV_MEM_LS_EN_MASK |
PCIE_CNTL2__MST_MEM_LS_EN_MASK |
PCIE_CNTL2__REPLAY_MEM_LS_EN_MASK);
@@ -463,6 +471,43 @@ static void nbio_v2_3_program_aspm(struct amdgpu_device *adev)
WREG32_PCIE(smnPCIE_LC_CNTL3, data);
}
+static void nbio_v2_3_apply_lc_spc_mode_wa(struct amdgpu_device *adev)
+{
+ uint32_t reg_data = 0;
+ uint32_t link_width = 0;
+
+ if (!((adev->asic_type >= CHIP_NAVI10) &&
+ (adev->asic_type <= CHIP_NAVI12)))
+ return;
+
+ reg_data = RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL);
+ link_width = (reg_data & PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK)
+ >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT;
+
+ /*
+ * Program PCIE_LC_CNTL6.LC_SPC_MODE_8GT to 0x2 (4 symbols per clock data)
+ * if link_width is 0x3 (x4)
+ */
+ if (0x3 == link_width) {
+ reg_data = RREG32_PCIE(smnPCIE_LC_CNTL6);
+ reg_data &= ~PCIE_LC_CNTL6__LC_SPC_MODE_8GT_MASK;
+ reg_data |= (0x2 << PCIE_LC_CNTL6__LC_SPC_MODE_8GT__SHIFT);
+ WREG32_PCIE(smnPCIE_LC_CNTL6, reg_data);
+ }
+}
+
+static void nbio_v2_3_apply_l1_link_width_reconfig_wa(struct amdgpu_device *adev)
+{
+ uint32_t reg_data = 0;
+
+ if (adev->asic_type != CHIP_NAVI10)
+ return;
+
+ reg_data = RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL);
+ reg_data |= PCIE_LC_LINK_WIDTH_CNTL__LC_L1_RECONFIG_EN_MASK;
+ WREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL, reg_data);
+}
+
const struct amdgpu_nbio_funcs nbio_v2_3_funcs = {
.get_hdp_flush_req_offset = nbio_v2_3_get_hdp_flush_req_offset,
.get_hdp_flush_done_offset = nbio_v2_3_get_hdp_flush_done_offset,
@@ -484,4 +529,6 @@ const struct amdgpu_nbio_funcs nbio_v2_3_funcs = {
.remap_hdp_registers = nbio_v2_3_remap_hdp_registers,
.enable_aspm = nbio_v2_3_enable_aspm,
.program_aspm = nbio_v2_3_program_aspm,
+ .apply_lc_spc_mode_wa = nbio_v2_3_apply_lc_spc_mode_wa,
+ .apply_l1_link_width_reconfig_wa = nbio_v2_3_apply_l1_link_width_reconfig_wa,
};
diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c
index 455d0425787c..94a2c0742ee5 100644
--- a/drivers/gpu/drm/amd/amdgpu/nv.c
+++ b/drivers/gpu/drm/amd/amdgpu/nv.c
@@ -64,6 +64,13 @@
#include "smuio_v11_0.h"
#include "smuio_v11_0_6.h"
+#define codec_info_build(type, width, height, level) \
+ .codec_type = type,\
+ .max_width = width,\
+ .max_height = height,\
+ .max_pixels_per_frame = height * width,\
+ .max_level = level,
+
static const struct amd_ip_funcs nv_common_ip_funcs;
/* Navi */
@@ -309,6 +316,23 @@ static struct amdgpu_video_codecs sriov_sc_video_codecs_decode =
.codec_array = sriov_sc_video_codecs_decode_array,
};
+/* Beige Goby*/
+static const struct amdgpu_video_codec_info bg_video_codecs_decode_array[] = {
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4906, 52)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
+};
+
+static const struct amdgpu_video_codecs bg_video_codecs_decode = {
+ .codec_count = ARRAY_SIZE(bg_video_codecs_decode_array),
+ .codec_array = bg_video_codecs_decode_array,
+};
+
+static const struct amdgpu_video_codecs bg_video_codecs_encode = {
+ .codec_count = 0,
+ .codec_array = NULL,
+};
+
static int nv_query_video_codecs(struct amdgpu_device *adev, bool encode,
const struct amdgpu_video_codecs **codecs)
{
@@ -335,6 +359,12 @@ static int nv_query_video_codecs(struct amdgpu_device *adev, bool encode,
else
*codecs = &sc_video_codecs_decode;
return 0;
+ case CHIP_BEIGE_GOBY:
+ if (encode)
+ *codecs = &bg_video_codecs_encode;
+ else
+ *codecs = &bg_video_codecs_decode;
+ return 0;
case CHIP_NAVI10:
case CHIP_NAVI14:
case CHIP_NAVI12:
@@ -1275,7 +1305,6 @@ static int nv_common_early_init(void *handle)
break;
case CHIP_VANGOGH:
- adev->apu_flags |= AMD_APU_IS_VANGOGH;
adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG |
AMD_CG_SUPPORT_GFX_MGLS |
AMD_CG_SUPPORT_GFX_CP_LS |
@@ -1411,6 +1440,12 @@ static int nv_common_hw_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ if (adev->nbio.funcs->apply_lc_spc_mode_wa)
+ adev->nbio.funcs->apply_lc_spc_mode_wa(adev);
+
+ if (adev->nbio.funcs->apply_l1_link_width_reconfig_wa)
+ adev->nbio.funcs->apply_l1_link_width_reconfig_wa(adev);
+
/* enable pcie gen2/3 link */
nv_pcie_gen3_enable(adev);
/* enable aspm */
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
index ae5464e2535a..8931000dcd41 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
@@ -144,7 +144,7 @@ static const struct soc15_reg_golden golden_settings_sdma_4_1[] = {
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_RLC0_RB_WPTR_POLL_CNTL, 0xfffffff7, 0x00403000),
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_RLC1_IB_CNTL, 0x800f0111, 0x00000100),
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_RLC1_RB_WPTR_POLL_CNTL, 0xfffffff7, 0x00403000),
- SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_PAGE, 0x000003ff, 0x000003c0),
+ SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_PAGE, 0x000003ff, 0x000003e0),
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_WATERMK, 0xfc000000, 0x00000000)
};
@@ -288,7 +288,7 @@ static const struct soc15_reg_golden golden_settings_sdma_4_3[] = {
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_POWER_CNTL, 0x003fff07, 0x40000051),
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_RLC0_RB_WPTR_POLL_CNTL, 0xfffffff7, 0x00403000),
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_RLC1_RB_WPTR_POLL_CNTL, 0xfffffff7, 0x00403000),
- SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_PAGE, 0x000003ff, 0x000003c0),
+ SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_PAGE, 0x000003ff, 0x000003e0),
SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_WATERMK, 0xfc000000, 0x03fbe1fe)
};
@@ -1896,8 +1896,11 @@ static int sdma_v4_0_late_init(void *handle)
sdma_v4_0_setup_ulv(adev);
- if (adev->sdma.funcs && adev->sdma.funcs->reset_ras_error_count)
- adev->sdma.funcs->reset_ras_error_count(adev);
+ if (!amdgpu_persistent_edc_harvesting_supported(adev)) {
+ if (adev->sdma.funcs &&
+ adev->sdma.funcs->reset_ras_error_count)
+ adev->sdma.funcs->reset_ras_error_count(adev);
+ }
if (adev->sdma.funcs && adev->sdma.funcs->ras_late_init)
return adev->sdma.funcs->ras_late_init(adev, &ih_info);
diff --git a/drivers/gpu/drm/amd/amdgpu/smuio_v11_0.c b/drivers/gpu/drm/amd/amdgpu/smuio_v11_0.c
index e9c474c217ec..b6f1322f908c 100644
--- a/drivers/gpu/drm/amd/amdgpu/smuio_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/smuio_v11_0.c
@@ -43,9 +43,12 @@ static void smuio_v11_0_update_rom_clock_gating(struct amdgpu_device *adev, bool
if (adev->flags & AMD_IS_APU)
return;
+ if (!(adev->cg_flags & AMD_CG_SUPPORT_ROM_MGCG))
+ return;
+
def = data = RREG32_SOC15(SMUIO, 0, mmCGTT_ROM_CLK_CTRL0);
- if (enable && (adev->cg_flags & AMD_CG_SUPPORT_ROM_MGCG))
+ if (enable)
data &= ~(CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE0_MASK |
CGTT_ROM_CLK_CTRL0__SOFT_OVERRIDE1_MASK);
else
diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c
index de85577c9cfd..b02436401d46 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc15.c
+++ b/drivers/gpu/drm/amd/amdgpu/soc15.c
@@ -1360,10 +1360,7 @@ static int soc15_common_early_init(void *handle)
break;
case CHIP_RAVEN:
adev->asic_funcs = &soc15_asic_funcs;
- if (adev->pdev->device == 0x15dd)
- adev->apu_flags |= AMD_APU_IS_RAVEN;
- if (adev->pdev->device == 0x15d8)
- adev->apu_flags |= AMD_APU_IS_PICASSO;
+
if (adev->rev_id >= 0x8)
adev->apu_flags |= AMD_APU_IS_RAVEN2;
@@ -1455,11 +1452,6 @@ static int soc15_common_early_init(void *handle)
break;
case CHIP_RENOIR:
adev->asic_funcs = &soc15_asic_funcs;
- if ((adev->pdev->device == 0x1636) ||
- (adev->pdev->device == 0x164c))
- adev->apu_flags |= AMD_APU_IS_RENOIR;
- else
- adev->apu_flags |= AMD_APU_IS_GREEN_SARDINE;
if (adev->apu_flags & AMD_APU_IS_RENOIR)
adev->external_rev_id = adev->rev_id + 0x91;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index 67541c30327a..e48acdd03c1a 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -1393,7 +1393,6 @@ static int kfd_ioctl_map_memory_to_gpu(struct file *filep,
long err = 0;
int i;
uint32_t *devices_arr = NULL;
- bool table_freed = false;
dev = kfd_device_by_id(GET_GPU_ID(args->handle));
if (!dev)
@@ -1451,8 +1450,7 @@ static int kfd_ioctl_map_memory_to_gpu(struct file *filep,
goto get_mem_obj_from_handle_failed;
}
err = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(
- peer->kgd, (struct kgd_mem *)mem,
- peer_pdd->drm_priv, &table_freed);
+ peer->kgd, (struct kgd_mem *)mem, peer_pdd->drm_priv);
if (err) {
pr_err("Failed to map to gpu %d/%d\n",
i, args->n_devices);
@@ -1470,17 +1468,16 @@ static int kfd_ioctl_map_memory_to_gpu(struct file *filep,
}
/* Flush TLBs after waiting for the page table updates to complete */
- if (table_freed) {
- for (i = 0; i < args->n_devices; i++) {
- peer = kfd_device_by_id(devices_arr[i]);
- if (WARN_ON_ONCE(!peer))
- continue;
- peer_pdd = kfd_get_process_device_data(peer, p);
- if (WARN_ON_ONCE(!peer_pdd))
- continue;
- kfd_flush_tlb(peer_pdd, TLB_FLUSH_LEGACY);
- }
+ for (i = 0; i < args->n_devices; i++) {
+ peer = kfd_device_by_id(devices_arr[i]);
+ if (WARN_ON_ONCE(!peer))
+ continue;
+ peer_pdd = kfd_get_process_device_data(peer, p);
+ if (WARN_ON_ONCE(!peer_pdd))
+ continue;
+ kfd_flush_tlb(peer_pdd, TLB_FLUSH_LEGACY);
}
+
kfree(devices_arr);
return err;
@@ -1568,27 +1565,10 @@ static int kfd_ioctl_unmap_memory_from_gpu(struct file *filep,
}
args->n_success = i+1;
}
- mutex_unlock(&p->mutex);
-
- err = amdgpu_amdkfd_gpuvm_sync_memory(dev->kgd, (struct kgd_mem *) mem, true);
- if (err) {
- pr_debug("Sync memory failed, wait interrupted by user signal\n");
- goto sync_memory_failed;
- }
-
- /* Flush TLBs after waiting for the page table updates to complete */
- for (i = 0; i < args->n_devices; i++) {
- peer = kfd_device_by_id(devices_arr[i]);
- if (WARN_ON_ONCE(!peer))
- continue;
- peer_pdd = kfd_get_process_device_data(peer, p);
- if (WARN_ON_ONCE(!peer_pdd))
- continue;
- kfd_flush_tlb(peer_pdd, TLB_FLUSH_HEAVYWEIGHT);
- }
-
kfree(devices_arr);
+ mutex_unlock(&p->mutex);
+
return 0;
bind_process_to_device_failed:
@@ -1596,7 +1576,6 @@ get_mem_obj_from_handle_failed:
unmap_memory_from_gpu_failed:
mutex_unlock(&p->mutex);
copy_from_user_failed:
-sync_memory_failed:
kfree(devices_arr);
return err;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index 2660f03e63a7..dab290a4d19d 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -218,7 +218,8 @@ svm_migrate_get_vram_page(struct svm_range *prange, unsigned long pfn)
struct page *page;
page = pfn_to_page(pfn);
- page->zone_device_data = prange;
+ svm_range_bo_ref(prange->svm_bo);
+ page->zone_device_data = prange->svm_bo;
get_page(page);
lock_page(page);
}
@@ -293,15 +294,13 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange,
for (i = j = 0; i < npages; i++) {
struct page *spage;
- dst[i] = cursor.start + (j << PAGE_SHIFT);
- migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]);
- svm_migrate_get_vram_page(prange, migrate->dst[i]);
-
- migrate->dst[i] = migrate_pfn(migrate->dst[i]);
- migrate->dst[i] |= MIGRATE_PFN_LOCKED;
-
- if (migrate->src[i] & MIGRATE_PFN_VALID) {
- spage = migrate_pfn_to_page(migrate->src[i]);
+ spage = migrate_pfn_to_page(migrate->src[i]);
+ if (spage && !is_zone_device_page(spage)) {
+ dst[i] = cursor.start + (j << PAGE_SHIFT);
+ migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]);
+ svm_migrate_get_vram_page(prange, migrate->dst[i]);
+ migrate->dst[i] = migrate_pfn(migrate->dst[i]);
+ migrate->dst[i] |= MIGRATE_PFN_LOCKED;
src[i] = dma_map_page(dev, spage, 0, PAGE_SIZE,
DMA_TO_DEVICE);
r = dma_mapping_error(dev, src[i]);
@@ -355,6 +354,20 @@ out_free_vram_pages:
}
}
+#ifdef DEBUG_FORCE_MIXED_DOMAINS
+ for (i = 0, j = 0; i < npages; i += 4, j++) {
+ if (j & 1)
+ continue;
+ svm_migrate_put_vram_page(adev, dst[i]);
+ migrate->dst[i] = 0;
+ svm_migrate_put_vram_page(adev, dst[i + 1]);
+ migrate->dst[i + 1] = 0;
+ svm_migrate_put_vram_page(adev, dst[i + 2]);
+ migrate->dst[i + 2] = 0;
+ svm_migrate_put_vram_page(adev, dst[i + 3]);
+ migrate->dst[i + 3] = 0;
+ }
+#endif
out:
return r;
}
@@ -365,20 +378,20 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange,
uint64_t end)
{
uint64_t npages = (end - start) >> PAGE_SHIFT;
+ struct kfd_process_device *pdd;
struct dma_fence *mfence = NULL;
struct migrate_vma migrate;
dma_addr_t *scratch;
size_t size;
void *buf;
int r = -ENOMEM;
- int retry = 0;
memset(&migrate, 0, sizeof(migrate));
migrate.vma = vma;
migrate.start = start;
migrate.end = end;
migrate.flags = MIGRATE_VMA_SELECT_SYSTEM;
- migrate.pgmap_owner = adev;
+ migrate.pgmap_owner = SVM_ADEV_PGMAP_OWNER(adev);
size = 2 * sizeof(*migrate.src) + sizeof(uint64_t) + sizeof(dma_addr_t);
size *= npages;
@@ -390,7 +403,6 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange,
migrate.dst = migrate.src + npages;
scratch = (dma_addr_t *)(migrate.dst + npages);
-retry:
r = migrate_vma_setup(&migrate);
if (r) {
pr_debug("failed %d prepare migrate svms 0x%p [0x%lx 0x%lx]\n",
@@ -398,17 +410,9 @@ retry:
goto out_free;
}
if (migrate.cpages != npages) {
- pr_debug("collect 0x%lx/0x%llx pages, retry\n", migrate.cpages,
+ pr_debug("Partial migration. 0x%lx/0x%llx pages can be migrated\n",
+ migrate.cpages,
npages);
- migrate_vma_finalize(&migrate);
- if (retry++ >= 3) {
- r = -ENOMEM;
- pr_debug("failed %d migrate svms 0x%p [0x%lx 0x%lx]\n",
- r, prange->svms, prange->start, prange->last);
- goto out_free;
- }
-
- goto retry;
}
if (migrate.cpages) {
@@ -425,6 +429,12 @@ retry:
out_free:
kvfree(buf);
out:
+ if (!r) {
+ pdd = svm_range_get_pdd_by_adev(prange, adev);
+ if (pdd)
+ WRITE_ONCE(pdd->page_in, pdd->page_in + migrate.cpages);
+ }
+
return r;
}
@@ -464,7 +474,7 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc,
prange->start, prange->last, best_loc);
/* FIXME: workaround for page locking bug with invalid pages */
- svm_range_prefault(prange, mm);
+ svm_range_prefault(prange, mm, SVM_ADEV_PGMAP_OWNER(adev));
start = prange->start << PAGE_SHIFT;
end = (prange->last + 1) << PAGE_SHIFT;
@@ -493,15 +503,19 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc,
static void svm_migrate_page_free(struct page *page)
{
- /* Keep this function to avoid warning */
+ struct svm_range_bo *svm_bo = page->zone_device_data;
+
+ if (svm_bo) {
+ pr_debug("svm_bo ref left: %d\n", kref_read(&svm_bo->kref));
+ svm_range_bo_unref(svm_bo);
+ }
}
static int
svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
struct migrate_vma *migrate, struct dma_fence **mfence,
- dma_addr_t *scratch)
+ dma_addr_t *scratch, uint64_t npages)
{
- uint64_t npages = migrate->cpages;
struct device *dev = adev->dev;
uint64_t *src;
dma_addr_t *dst;
@@ -518,15 +532,23 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
src = (uint64_t *)(scratch + npages);
dst = scratch;
- for (i = 0, j = 0; i < npages; i++, j++, addr += PAGE_SIZE) {
+ for (i = 0, j = 0; i < npages; i++, addr += PAGE_SIZE) {
struct page *spage;
spage = migrate_pfn_to_page(migrate->src[i]);
- if (!spage) {
- pr_debug("failed get spage svms 0x%p [0x%lx 0x%lx]\n",
+ if (!spage || !is_zone_device_page(spage)) {
+ pr_debug("invalid page. Could be in CPU already svms 0x%p [0x%lx 0x%lx]\n",
prange->svms, prange->start, prange->last);
- r = -ENOMEM;
- goto out_oom;
+ if (j) {
+ r = svm_migrate_copy_memory_gart(adev, dst + i - j,
+ src + i - j, j,
+ FROM_VRAM_TO_RAM,
+ mfence);
+ if (r)
+ goto out_oom;
+ j = 0;
+ }
+ continue;
}
src[i] = svm_migrate_addr(adev, spage);
if (i > 0 && src[i] != src[i - 1] + PAGE_SIZE) {
@@ -559,6 +581,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
migrate->dst[i] = migrate_pfn(page_to_pfn(dpage));
migrate->dst[i] |= MIGRATE_PFN_LOCKED;
+ j++;
}
r = svm_migrate_copy_memory_gart(adev, dst + i - j, src + i - j, j,
@@ -581,6 +604,7 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
struct vm_area_struct *vma, uint64_t start, uint64_t end)
{
uint64_t npages = (end - start) >> PAGE_SHIFT;
+ struct kfd_process_device *pdd;
struct dma_fence *mfence = NULL;
struct migrate_vma migrate;
dma_addr_t *scratch;
@@ -593,7 +617,7 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
migrate.start = start;
migrate.end = end;
migrate.flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE;
- migrate.pgmap_owner = adev;
+ migrate.pgmap_owner = SVM_ADEV_PGMAP_OWNER(adev);
size = 2 * sizeof(*migrate.src) + sizeof(uint64_t) + sizeof(dma_addr_t);
size *= npages;
@@ -616,7 +640,7 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
if (migrate.cpages) {
r = svm_migrate_copy_to_ram(adev, prange, &migrate, &mfence,
- scratch);
+ scratch, npages);
migrate_vma_pages(&migrate);
svm_migrate_copy_done(adev, mfence);
migrate_vma_finalize(&migrate);
@@ -630,6 +654,12 @@ svm_migrate_vma_to_ram(struct amdgpu_device *adev, struct svm_range *prange,
out_free:
kvfree(buf);
out:
+ if (!r) {
+ pdd = svm_range_get_pdd_by_adev(prange, adev);
+ if (pdd)
+ WRITE_ONCE(pdd->page_out,
+ pdd->page_out + migrate.cpages);
+ }
return r;
}
@@ -859,7 +889,7 @@ int svm_migrate_init(struct amdgpu_device *adev)
pgmap->range.start = res->start;
pgmap->range.end = res->end;
pgmap->ops = &svm_migrate_pgmap_ops;
- pgmap->owner = adev;
+ pgmap->owner = SVM_ADEV_PGMAP_OWNER(adev);
pgmap->flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE;
r = devm_memremap_pages(adev->dev, pgmap);
if (IS_ERR(r)) {
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index 6dc22fa1e555..3426743ed228 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -730,6 +730,15 @@ struct kfd_process_device {
* number of CU's a device has along with number of other competing processes
*/
struct attribute attr_cu_occupancy;
+
+ /* sysfs counters for GPU retry fault and page migration tracking */
+ struct kobject *kobj_counters;
+ struct attribute attr_faults;
+ struct attribute attr_page_in;
+ struct attribute attr_page_out;
+ uint64_t faults;
+ uint64_t page_in;
+ uint64_t page_out;
};
#define qpd_to_pdd(x) container_of(x, struct kfd_process_device, qpd)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index 09b98a83f670..8a2c6fc438c0 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -416,6 +416,29 @@ static ssize_t kfd_procfs_stats_show(struct kobject *kobj,
return 0;
}
+static ssize_t kfd_sysfs_counters_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct kfd_process_device *pdd;
+
+ if (!strcmp(attr->name, "faults")) {
+ pdd = container_of(attr, struct kfd_process_device,
+ attr_faults);
+ return sysfs_emit(buf, "%llu\n", READ_ONCE(pdd->faults));
+ }
+ if (!strcmp(attr->name, "page_in")) {
+ pdd = container_of(attr, struct kfd_process_device,
+ attr_page_in);
+ return sysfs_emit(buf, "%llu\n", READ_ONCE(pdd->page_in));
+ }
+ if (!strcmp(attr->name, "page_out")) {
+ pdd = container_of(attr, struct kfd_process_device,
+ attr_page_out);
+ return sysfs_emit(buf, "%llu\n", READ_ONCE(pdd->page_out));
+ }
+ return 0;
+}
+
static struct attribute attr_queue_size = {
.name = "size",
.mode = KFD_SYSFS_FILE_MODE
@@ -451,13 +474,18 @@ static const struct sysfs_ops procfs_stats_ops = {
.show = kfd_procfs_stats_show,
};
-static struct attribute *procfs_stats_attrs[] = {
- NULL
-};
-
static struct kobj_type procfs_stats_type = {
.sysfs_ops = &procfs_stats_ops,
- .default_attrs = procfs_stats_attrs,
+ .release = kfd_procfs_kobj_release,
+};
+
+static const struct sysfs_ops sysfs_counters_ops = {
+ .show = kfd_sysfs_counters_show,
+};
+
+static struct kobj_type sysfs_counters_type = {
+ .sysfs_ops = &sysfs_counters_ops,
+ .release = kfd_procfs_kobj_release,
};
int kfd_procfs_add_queue(struct queue *q)
@@ -484,34 +512,31 @@ int kfd_procfs_add_queue(struct queue *q)
return 0;
}
-static int kfd_sysfs_create_file(struct kfd_process *p, struct attribute *attr,
+static void kfd_sysfs_create_file(struct kobject *kobj, struct attribute *attr,
char *name)
{
- int ret = 0;
+ int ret;
- if (!p || !attr || !name)
- return -EINVAL;
+ if (!kobj || !attr || !name)
+ return;
attr->name = name;
attr->mode = KFD_SYSFS_FILE_MODE;
sysfs_attr_init(attr);
- ret = sysfs_create_file(p->kobj, attr);
-
- return ret;
+ ret = sysfs_create_file(kobj, attr);
+ if (ret)
+ pr_warn("Create sysfs %s/%s failed %d", kobj->name, name, ret);
}
-static int kfd_procfs_add_sysfs_stats(struct kfd_process *p)
+static void kfd_procfs_add_sysfs_stats(struct kfd_process *p)
{
- int ret = 0;
+ int ret;
int i;
char stats_dir_filename[MAX_SYSFS_FILENAME_LEN];
- if (!p)
- return -EINVAL;
-
- if (!p->kobj)
- return -EFAULT;
+ if (!p || !p->kobj)
+ return;
/*
* Create sysfs files for each GPU:
@@ -521,63 +546,87 @@ static int kfd_procfs_add_sysfs_stats(struct kfd_process *p)
*/
for (i = 0; i < p->n_pdds; i++) {
struct kfd_process_device *pdd = p->pdds[i];
- struct kobject *kobj_stats;
snprintf(stats_dir_filename, MAX_SYSFS_FILENAME_LEN,
"stats_%u", pdd->dev->id);
- kobj_stats = kfd_alloc_struct(kobj_stats);
- if (!kobj_stats)
- return -ENOMEM;
+ pdd->kobj_stats = kfd_alloc_struct(pdd->kobj_stats);
+ if (!pdd->kobj_stats)
+ return;
- ret = kobject_init_and_add(kobj_stats,
- &procfs_stats_type,
- p->kobj,
- stats_dir_filename);
+ ret = kobject_init_and_add(pdd->kobj_stats,
+ &procfs_stats_type,
+ p->kobj,
+ stats_dir_filename);
if (ret) {
pr_warn("Creating KFD proc/stats_%s folder failed",
- stats_dir_filename);
- kobject_put(kobj_stats);
- goto err;
+ stats_dir_filename);
+ kobject_put(pdd->kobj_stats);
+ pdd->kobj_stats = NULL;
+ return;
}
- pdd->kobj_stats = kobj_stats;
- pdd->attr_evict.name = "evicted_ms";
- pdd->attr_evict.mode = KFD_SYSFS_FILE_MODE;
- sysfs_attr_init(&pdd->attr_evict);
- ret = sysfs_create_file(kobj_stats, &pdd->attr_evict);
- if (ret)
- pr_warn("Creating eviction stats for gpuid %d failed",
- (int)pdd->dev->id);
-
+ kfd_sysfs_create_file(pdd->kobj_stats, &pdd->attr_evict,
+ "evicted_ms");
/* Add sysfs file to report compute unit occupancy */
- if (pdd->dev->kfd2kgd->get_cu_occupancy != NULL) {
- pdd->attr_cu_occupancy.name = "cu_occupancy";
- pdd->attr_cu_occupancy.mode = KFD_SYSFS_FILE_MODE;
- sysfs_attr_init(&pdd->attr_cu_occupancy);
- ret = sysfs_create_file(kobj_stats,
- &pdd->attr_cu_occupancy);
- if (ret)
- pr_warn("Creating %s failed for gpuid: %d",
- pdd->attr_cu_occupancy.name,
- (int)pdd->dev->id);
- }
+ if (pdd->dev->kfd2kgd->get_cu_occupancy)
+ kfd_sysfs_create_file(pdd->kobj_stats,
+ &pdd->attr_cu_occupancy,
+ "cu_occupancy");
}
-err:
- return ret;
}
-
-static int kfd_procfs_add_sysfs_files(struct kfd_process *p)
+static void kfd_procfs_add_sysfs_counters(struct kfd_process *p)
{
int ret = 0;
int i;
+ char counters_dir_filename[MAX_SYSFS_FILENAME_LEN];
- if (!p)
- return -EINVAL;
+ if (!p || !p->kobj)
+ return;
- if (!p->kobj)
- return -EFAULT;
+ /*
+ * Create sysfs files for each GPU which supports SVM
+ * - proc/<pid>/counters_<gpuid>/
+ * - proc/<pid>/counters_<gpuid>/faults
+ * - proc/<pid>/counters_<gpuid>/page_in
+ * - proc/<pid>/counters_<gpuid>/page_out
+ */
+ for_each_set_bit(i, p->svms.bitmap_supported, p->n_pdds) {
+ struct kfd_process_device *pdd = p->pdds[i];
+ struct kobject *kobj_counters;
+
+ snprintf(counters_dir_filename, MAX_SYSFS_FILENAME_LEN,
+ "counters_%u", pdd->dev->id);
+ kobj_counters = kfd_alloc_struct(kobj_counters);
+ if (!kobj_counters)
+ return;
+
+ ret = kobject_init_and_add(kobj_counters, &sysfs_counters_type,
+ p->kobj, counters_dir_filename);
+ if (ret) {
+ pr_warn("Creating KFD proc/%s folder failed",
+ counters_dir_filename);
+ kobject_put(kobj_counters);
+ return;
+ }
+
+ pdd->kobj_counters = kobj_counters;
+ kfd_sysfs_create_file(kobj_counters, &pdd->attr_faults,
+ "faults");
+ kfd_sysfs_create_file(kobj_counters, &pdd->attr_page_in,
+ "page_in");
+ kfd_sysfs_create_file(kobj_counters, &pdd->attr_page_out,
+ "page_out");
+ }
+}
+
+static void kfd_procfs_add_sysfs_files(struct kfd_process *p)
+{
+ int i;
+
+ if (!p || !p->kobj)
+ return;
/*
* Create sysfs files for each GPU:
@@ -589,20 +638,14 @@ static int kfd_procfs_add_sysfs_files(struct kfd_process *p)
snprintf(pdd->vram_filename, MAX_SYSFS_FILENAME_LEN, "vram_%u",
pdd->dev->id);
- ret = kfd_sysfs_create_file(p, &pdd->attr_vram, pdd->vram_filename);
- if (ret)
- pr_warn("Creating vram usage for gpu id %d failed",
- (int)pdd->dev->id);
+ kfd_sysfs_create_file(p->kobj, &pdd->attr_vram,
+ pdd->vram_filename);
snprintf(pdd->sdma_filename, MAX_SYSFS_FILENAME_LEN, "sdma_%u",
pdd->dev->id);
- ret = kfd_sysfs_create_file(p, &pdd->attr_sdma, pdd->sdma_filename);
- if (ret)
- pr_warn("Creating sdma usage for gpu id %d failed",
- (int)pdd->dev->id);
+ kfd_sysfs_create_file(p->kobj, &pdd->attr_sdma,
+ pdd->sdma_filename);
}
-
- return ret;
}
void kfd_procfs_del_queue(struct queue *q)
@@ -671,8 +714,7 @@ static int kfd_process_alloc_gpuvm(struct kfd_process_device *pdd,
if (err)
goto err_alloc_mem;
- err = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(kdev->kgd, mem,
- pdd->drm_priv, NULL);
+ err = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(kdev->kgd, mem, pdd->drm_priv);
if (err)
goto err_map_mem;
@@ -800,28 +842,17 @@ struct kfd_process *kfd_create_process(struct file *filep)
goto out;
}
- process->attr_pasid.name = "pasid";
- process->attr_pasid.mode = KFD_SYSFS_FILE_MODE;
- sysfs_attr_init(&process->attr_pasid);
- ret = sysfs_create_file(process->kobj, &process->attr_pasid);
- if (ret)
- pr_warn("Creating pasid for pid %d failed",
- (int)process->lead_thread->pid);
+ kfd_sysfs_create_file(process->kobj, &process->attr_pasid,
+ "pasid");
process->kobj_queues = kobject_create_and_add("queues",
process->kobj);
if (!process->kobj_queues)
pr_warn("Creating KFD proc/queues folder failed");
- ret = kfd_procfs_add_sysfs_stats(process);
- if (ret)
- pr_warn("Creating sysfs stats dir for pid %d failed",
- (int)process->lead_thread->pid);
-
- ret = kfd_procfs_add_sysfs_files(process);
- if (ret)
- pr_warn("Creating sysfs usage file for pid %d failed",
- (int)process->lead_thread->pid);
+ kfd_procfs_add_sysfs_stats(process);
+ kfd_procfs_add_sysfs_files(process);
+ kfd_procfs_add_sysfs_counters(process);
}
out:
if (!IS_ERR(process))
@@ -964,6 +995,50 @@ static void kfd_process_destroy_pdds(struct kfd_process *p)
p->n_pdds = 0;
}
+static void kfd_process_remove_sysfs(struct kfd_process *p)
+{
+ struct kfd_process_device *pdd;
+ int i;
+
+ if (!p->kobj)
+ return;
+
+ sysfs_remove_file(p->kobj, &p->attr_pasid);
+ kobject_del(p->kobj_queues);
+ kobject_put(p->kobj_queues);
+ p->kobj_queues = NULL;
+
+ for (i = 0; i < p->n_pdds; i++) {
+ pdd = p->pdds[i];
+
+ sysfs_remove_file(p->kobj, &pdd->attr_vram);
+ sysfs_remove_file(p->kobj, &pdd->attr_sdma);
+
+ sysfs_remove_file(pdd->kobj_stats, &pdd->attr_evict);
+ if (pdd->dev->kfd2kgd->get_cu_occupancy)
+ sysfs_remove_file(pdd->kobj_stats,
+ &pdd->attr_cu_occupancy);
+ kobject_del(pdd->kobj_stats);
+ kobject_put(pdd->kobj_stats);
+ pdd->kobj_stats = NULL;
+ }
+
+ for_each_set_bit(i, p->svms.bitmap_supported, p->n_pdds) {
+ pdd = p->pdds[i];
+
+ sysfs_remove_file(pdd->kobj_counters, &pdd->attr_faults);
+ sysfs_remove_file(pdd->kobj_counters, &pdd->attr_page_in);
+ sysfs_remove_file(pdd->kobj_counters, &pdd->attr_page_out);
+ kobject_del(pdd->kobj_counters);
+ kobject_put(pdd->kobj_counters);
+ pdd->kobj_counters = NULL;
+ }
+
+ kobject_del(p->kobj);
+ kobject_put(p->kobj);
+ p->kobj = NULL;
+}
+
/* No process locking is needed in this function, because the process
* is not findable any more. We must assume that no other thread is
* using it any more, otherwise we couldn't safely free the process
@@ -973,33 +1048,7 @@ static void kfd_process_wq_release(struct work_struct *work)
{
struct kfd_process *p = container_of(work, struct kfd_process,
release_work);
- int i;
-
- /* Remove the procfs files */
- if (p->kobj) {
- sysfs_remove_file(p->kobj, &p->attr_pasid);
- kobject_del(p->kobj_queues);
- kobject_put(p->kobj_queues);
- p->kobj_queues = NULL;
-
- for (i = 0; i < p->n_pdds; i++) {
- struct kfd_process_device *pdd = p->pdds[i];
-
- sysfs_remove_file(p->kobj, &pdd->attr_vram);
- sysfs_remove_file(p->kobj, &pdd->attr_sdma);
- sysfs_remove_file(p->kobj, &pdd->attr_evict);
- if (pdd->dev->kfd2kgd->get_cu_occupancy != NULL)
- sysfs_remove_file(p->kobj, &pdd->attr_cu_occupancy);
- kobject_del(pdd->kobj_stats);
- kobject_put(pdd->kobj_stats);
- pdd->kobj_stats = NULL;
- }
-
- kobject_del(p->kobj);
- kobject_put(p->kobj);
- p->kobj = NULL;
- }
-
+ kfd_process_remove_sysfs(p);
kfd_iommu_unbind_process(p);
kfd_process_free_outstanding_kfd_bos(p);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
index 95a6c36cea4c..243dd1efcdbf 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -153,6 +153,7 @@ void pqm_uninit(struct process_queue_manager *pqm)
if (pqn->q && pqn->q->gws)
amdgpu_amdkfd_remove_gws_from_process(pqm->process->kgd_process_info,
pqn->q->gws);
+ kfd_procfs_del_queue(pqn->q);
uninit_queue(pqn->q);
list_del(&pqn->process_queue_list);
kfree(pqn);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index dff1011dd7ee..c7b364e4a287 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -119,28 +119,40 @@ static void svm_range_remove_notifier(struct svm_range *prange)
}
static int
-svm_range_dma_map_dev(struct device *dev, dma_addr_t **dma_addr,
- unsigned long *hmm_pfns, uint64_t npages)
+svm_range_dma_map_dev(struct amdgpu_device *adev, struct svm_range *prange,
+ unsigned long *hmm_pfns, uint32_t gpuidx)
{
enum dma_data_direction dir = DMA_BIDIRECTIONAL;
- dma_addr_t *addr = *dma_addr;
+ dma_addr_t *addr = prange->dma_addr[gpuidx];
+ struct device *dev = adev->dev;
struct page *page;
int i, r;
if (!addr) {
- addr = kvmalloc_array(npages, sizeof(*addr),
+ addr = kvmalloc_array(prange->npages, sizeof(*addr),
GFP_KERNEL | __GFP_ZERO);
if (!addr)
return -ENOMEM;
- *dma_addr = addr;
+ prange->dma_addr[gpuidx] = addr;
}
- for (i = 0; i < npages; i++) {
+ for (i = 0; i < prange->npages; i++) {
if (WARN_ONCE(addr[i] && !dma_mapping_error(dev, addr[i]),
"leaking dma mapping\n"))
dma_unmap_page(dev, addr[i], PAGE_SIZE, dir);
page = hmm_pfn_to_page(hmm_pfns[i]);
+ if (is_zone_device_page(page)) {
+ struct amdgpu_device *bo_adev =
+ amdgpu_ttm_adev(prange->svm_bo->bo->tbo.bdev);
+
+ addr[i] = (hmm_pfns[i] << PAGE_SHIFT) +
+ bo_adev->vm_manager.vram_base_offset -
+ bo_adev->kfd.dev->pgmap.range.start;
+ addr[i] |= SVM_RANGE_VRAM_DOMAIN;
+ pr_debug("vram address detected: 0x%llx\n", addr[i]);
+ continue;
+ }
addr[i] = dma_map_page(dev, page, 0, PAGE_SIZE, dir);
r = dma_mapping_error(dev, addr[i]);
if (r) {
@@ -175,8 +187,7 @@ svm_range_dma_map(struct svm_range *prange, unsigned long *bitmap,
}
adev = (struct amdgpu_device *)pdd->dev->kgd;
- r = svm_range_dma_map_dev(adev->dev, &prange->dma_addr[gpuidx],
- hmm_pfns, prange->npages);
+ r = svm_range_dma_map_dev(adev, prange, hmm_pfns, gpuidx);
if (r)
break;
}
@@ -301,14 +312,6 @@ static bool svm_bo_ref_unless_zero(struct svm_range_bo *svm_bo)
return true;
}
-static struct svm_range_bo *svm_range_bo_ref(struct svm_range_bo *svm_bo)
-{
- if (svm_bo)
- kref_get(&svm_bo->kref);
-
- return svm_bo;
-}
-
static void svm_range_bo_release(struct kref *kref)
{
struct svm_range_bo *svm_bo;
@@ -347,7 +350,7 @@ static void svm_range_bo_release(struct kref *kref)
kfree(svm_bo);
}
-static void svm_range_bo_unref(struct svm_range_bo *svm_bo)
+void svm_range_bo_unref(struct svm_range_bo *svm_bo)
{
if (!svm_bo)
return;
@@ -564,6 +567,24 @@ svm_range_get_adev_by_id(struct svm_range *prange, uint32_t gpu_id)
return (struct amdgpu_device *)pdd->dev->kgd;
}
+struct kfd_process_device *
+svm_range_get_pdd_by_adev(struct svm_range *prange, struct amdgpu_device *adev)
+{
+ struct kfd_process *p;
+ int32_t gpu_idx, gpuid;
+ int r;
+
+ p = container_of(prange->svms, struct kfd_process, svms);
+
+ r = kfd_process_gpuid_from_kgd(p, adev, &gpuid, &gpu_idx);
+ if (r) {
+ pr_debug("failed to get device id by adev %p\n", adev);
+ return NULL;
+ }
+
+ return kfd_process_device_from_gpuidx(p, gpu_idx);
+}
+
static int svm_range_bo_validate(void *param, struct amdgpu_bo *bo)
{
struct ttm_operation_ctx ctx = { false, false };
@@ -1002,21 +1023,22 @@ svm_range_split_by_granularity(struct kfd_process *p, struct mm_struct *mm,
}
static uint64_t
-svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange)
+svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange,
+ int domain)
{
struct amdgpu_device *bo_adev;
uint32_t flags = prange->flags;
uint32_t mapping_flags = 0;
uint64_t pte_flags;
- bool snoop = !prange->ttm_res;
+ bool snoop = (domain != SVM_RANGE_VRAM_DOMAIN);
bool coherent = flags & KFD_IOCTL_SVM_FLAG_COHERENT;
- if (prange->svm_bo && prange->ttm_res)
+ if (domain == SVM_RANGE_VRAM_DOMAIN)
bo_adev = amdgpu_ttm_adev(prange->svm_bo->bo->tbo.bdev);
switch (adev->asic_type) {
case CHIP_ARCTURUS:
- if (prange->svm_bo && prange->ttm_res) {
+ if (domain == SVM_RANGE_VRAM_DOMAIN) {
if (bo_adev == adev) {
mapping_flags |= coherent ?
AMDGPU_VM_MTYPE_CC : AMDGPU_VM_MTYPE_RW;
@@ -1032,7 +1054,7 @@ svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange)
}
break;
case CHIP_ALDEBARAN:
- if (prange->svm_bo && prange->ttm_res) {
+ if (domain == SVM_RANGE_VRAM_DOMAIN) {
if (bo_adev == adev) {
mapping_flags |= coherent ?
AMDGPU_VM_MTYPE_CC : AMDGPU_VM_MTYPE_RW;
@@ -1062,14 +1084,14 @@ svm_range_get_pte_flags(struct amdgpu_device *adev, struct svm_range *prange)
mapping_flags |= AMDGPU_VM_PAGE_EXECUTABLE;
pte_flags = AMDGPU_PTE_VALID;
- pte_flags |= prange->ttm_res ? 0 : AMDGPU_PTE_SYSTEM;
+ pte_flags |= (domain == SVM_RANGE_VRAM_DOMAIN) ? 0 : AMDGPU_PTE_SYSTEM;
pte_flags |= snoop ? AMDGPU_PTE_SNOOPED : 0;
pte_flags |= amdgpu_gem_va_map_flags(adev, mapping_flags);
pr_debug("svms 0x%p [0x%lx 0x%lx] vram %d PTE 0x%llx mapping 0x%x\n",
prange->svms, prange->start, prange->last,
- prange->ttm_res ? 1:0, pte_flags, mapping_flags);
+ (domain == SVM_RANGE_VRAM_DOMAIN) ? 1:0, pte_flags, mapping_flags);
return pte_flags;
}
@@ -1140,31 +1162,41 @@ svm_range_map_to_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm,
struct amdgpu_bo_va bo_va;
bool table_freed = false;
uint64_t pte_flags;
+ unsigned long last_start;
+ int last_domain;
int r = 0;
+ int64_t i;
pr_debug("svms 0x%p [0x%lx 0x%lx]\n", prange->svms, prange->start,
prange->last);
- if (prange->svm_bo && prange->ttm_res) {
+ if (prange->svm_bo && prange->ttm_res)
bo_va.is_xgmi = amdgpu_xgmi_same_hive(adev, bo_adev);
- prange->mapping.bo_va = &bo_va;
- }
- prange->mapping.start = prange->start;
- prange->mapping.last = prange->last;
- prange->mapping.offset = prange->ttm_res ? prange->offset : 0;
- pte_flags = svm_range_get_pte_flags(adev, prange);
+ last_start = prange->start;
+ for (i = 0; i < prange->npages; i++) {
+ last_domain = dma_addr[i] & SVM_RANGE_VRAM_DOMAIN;
+ dma_addr[i] &= ~SVM_RANGE_VRAM_DOMAIN;
+ if ((prange->start + i) < prange->last &&
+ last_domain == (dma_addr[i + 1] & SVM_RANGE_VRAM_DOMAIN))
+ continue;
- r = amdgpu_vm_bo_update_mapping(adev, bo_adev, vm, false, false, NULL,
- prange->mapping.start,
- prange->mapping.last, pte_flags,
- prange->mapping.offset,
- prange->ttm_res,
- dma_addr, &vm->last_update,
- &table_freed);
- if (r) {
- pr_debug("failed %d to map to gpu 0x%lx\n", r, prange->start);
- goto out;
+ pr_debug("Mapping range [0x%lx 0x%llx] on domain: %s\n",
+ last_start, prange->start + i, last_domain ? "GPU" : "CPU");
+ pte_flags = svm_range_get_pte_flags(adev, prange, last_domain);
+ r = amdgpu_vm_bo_update_mapping(adev, bo_adev, vm, false, false, NULL,
+ last_start,
+ prange->start + i, pte_flags,
+ last_start - prange->start,
+ NULL,
+ dma_addr,
+ &vm->last_update,
+ &table_freed);
+ if (r) {
+ pr_debug("failed %d to map to gpu 0x%lx\n", r, prange->start);
+ goto out;
+ }
+ last_start = prange->start + i + 1;
}
r = amdgpu_vm_update_pdes(adev, vm, false);
@@ -1185,7 +1217,6 @@ svm_range_map_to_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm,
p->pasid, TLB_FLUSH_LEGACY);
}
out:
- prange->mapping.bo_va = NULL;
return r;
}
@@ -1319,6 +1350,17 @@ static void svm_range_unreserve_bos(struct svm_validate_context *ctx)
ttm_eu_backoff_reservation(&ctx->ticket, &ctx->validate_list);
}
+static void *kfd_svm_page_owner(struct kfd_process *p, int32_t gpuidx)
+{
+ struct kfd_process_device *pdd;
+ struct amdgpu_device *adev;
+
+ pdd = kfd_process_device_from_gpuidx(p, gpuidx);
+ adev = (struct amdgpu_device *)pdd->dev->kgd;
+
+ return SVM_ADEV_PGMAP_OWNER(adev);
+}
+
/*
* Validation+GPU mapping with concurrent invalidation (MMU notifiers)
*
@@ -1349,6 +1391,9 @@ static int svm_range_validate_and_map(struct mm_struct *mm,
{
struct svm_validate_context ctx;
struct hmm_range *hmm_range;
+ struct kfd_process *p;
+ void *owner;
+ int32_t idx;
int r = 0;
ctx.process = container_of(prange->svms, struct kfd_process, svms);
@@ -1394,33 +1439,38 @@ static int svm_range_validate_and_map(struct mm_struct *mm,
svm_range_reserve_bos(&ctx);
- if (!prange->actual_loc) {
- r = amdgpu_hmm_range_get_pages(&prange->notifier, mm, NULL,
- prange->start << PAGE_SHIFT,
- prange->npages, &hmm_range,
- false, true);
- if (r) {
- pr_debug("failed %d to get svm range pages\n", r);
- goto unreserve_out;
- }
-
- r = svm_range_dma_map(prange, ctx.bitmap,
- hmm_range->hmm_pfns);
- if (r) {
- pr_debug("failed %d to dma map range\n", r);
- goto unreserve_out;
+ p = container_of(prange->svms, struct kfd_process, svms);
+ owner = kfd_svm_page_owner(p, find_first_bit(ctx.bitmap,
+ MAX_GPU_INSTANCE));
+ for_each_set_bit(idx, ctx.bitmap, MAX_GPU_INSTANCE) {
+ if (kfd_svm_page_owner(p, idx) != owner) {
+ owner = NULL;
+ break;
}
+ }
+ r = amdgpu_hmm_range_get_pages(&prange->notifier, mm, NULL,
+ prange->start << PAGE_SHIFT,
+ prange->npages, &hmm_range,
+ false, true, owner);
+ if (r) {
+ pr_debug("failed %d to get svm range pages\n", r);
+ goto unreserve_out;
+ }
- prange->validated_once = true;
+ r = svm_range_dma_map(prange, ctx.bitmap,
+ hmm_range->hmm_pfns);
+ if (r) {
+ pr_debug("failed %d to dma map range\n", r);
+ goto unreserve_out;
}
+ prange->validated_once = true;
+
svm_range_lock(prange);
- if (!prange->actual_loc) {
- if (amdgpu_hmm_range_get_pages_done(hmm_range)) {
- pr_debug("hmm update the range, need validate again\n");
- r = -EAGAIN;
- goto unlock_out;
- }
+ if (amdgpu_hmm_range_get_pages_done(hmm_range)) {
+ pr_debug("hmm update the range, need validate again\n");
+ r = -EAGAIN;
+ goto unlock_out;
}
if (!list_empty(&prange->child_list)) {
pr_debug("range split by unmap in parallel, validate again\n");
@@ -1572,6 +1622,7 @@ svm_range_evict(struct svm_range *prange, struct mm_struct *mm,
unsigned long start, unsigned long last)
{
struct svm_range_list *svms = prange->svms;
+ struct svm_range *pchild;
struct kfd_process *p;
int r = 0;
@@ -1583,7 +1634,19 @@ svm_range_evict(struct svm_range *prange, struct mm_struct *mm,
if (!p->xnack_enabled) {
int evicted_ranges;
- atomic_inc(&prange->invalid);
+ list_for_each_entry(pchild, &prange->child_list, child_list) {
+ mutex_lock_nested(&pchild->lock, 1);
+ if (pchild->start <= last && pchild->last >= start) {
+ pr_debug("increment pchild invalid [0x%lx 0x%lx]\n",
+ pchild->start, pchild->last);
+ atomic_inc(&pchild->invalid);
+ }
+ mutex_unlock(&pchild->lock);
+ }
+
+ if (prange->start <= last && prange->last >= start)
+ atomic_inc(&prange->invalid);
+
evicted_ranges = atomic_inc_return(&svms->evicted_ranges);
if (evicted_ranges != 1)
return r;
@@ -1600,7 +1663,6 @@ svm_range_evict(struct svm_range *prange, struct mm_struct *mm,
schedule_delayed_work(&svms->restore_work,
msecs_to_jiffies(AMDGPU_SVM_RANGE_RESTORE_DELAY_MS));
} else {
- struct svm_range *pchild;
unsigned long s, l;
pr_debug("invalidate unmap svms 0x%p [0x%lx 0x%lx] from GPUs\n",
@@ -2311,6 +2373,33 @@ static bool svm_range_skip_recover(struct svm_range *prange)
return false;
}
+static void
+svm_range_count_fault(struct amdgpu_device *adev, struct kfd_process *p,
+ int32_t gpuidx)
+{
+ struct kfd_process_device *pdd;
+
+ /* fault is on different page of same range
+ * or fault is skipped to recover later
+ * or fault is on invalid virtual address
+ */
+ if (gpuidx == MAX_GPU_INSTANCE) {
+ uint32_t gpuid;
+ int r;
+
+ r = kfd_process_gpuid_from_kgd(p, adev, &gpuid, &gpuidx);
+ if (r < 0)
+ return;
+ }
+
+ /* fault is recovered
+ * or fault cannot recover because GPU no access on the range
+ */
+ pdd = kfd_process_device_from_gpuidx(p, gpuidx);
+ if (pdd)
+ WRITE_ONCE(pdd->faults, pdd->faults + 1);
+}
+
int
svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
uint64_t addr)
@@ -2320,7 +2409,8 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
struct svm_range *prange;
struct kfd_process *p;
uint64_t timestamp;
- int32_t best_loc, gpuidx;
+ int32_t best_loc;
+ int32_t gpuidx = MAX_GPU_INSTANCE;
bool write_locked = false;
int r = 0;
@@ -2440,6 +2530,9 @@ out_unlock_range:
out_unlock_svms:
mutex_unlock(&svms->lock);
mmap_read_unlock(mm);
+
+ svm_range_count_fault(adev, p, gpuidx);
+
mmput(mm);
out:
kfd_unref_process(p);
@@ -2662,7 +2755,8 @@ out:
/* FIXME: This is a workaround for page locking bug when some pages are
* invalid during migration to VRAM
*/
-void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm)
+void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm,
+ void *owner)
{
struct hmm_range *hmm_range;
int r;
@@ -2673,7 +2767,7 @@ void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm)
r = amdgpu_hmm_range_get_pages(&prange->notifier, mm, NULL,
prange->start << PAGE_SHIFT,
prange->npages, &hmm_range,
- false, true);
+ false, true, owner);
if (!r) {
amdgpu_hmm_range_get_pages_done(hmm_range);
prange->validated_once = true;
@@ -2718,16 +2812,6 @@ svm_range_trigger_migration(struct mm_struct *mm, struct svm_range *prange,
best_loc == prange->actual_loc)
return 0;
- /*
- * Prefetch to GPU without host access flag, set actual_loc to gpu, then
- * validate on gpu and map to gpus will be handled afterwards.
- */
- if (best_loc && !prange->actual_loc &&
- !(prange->flags & KFD_IOCTL_SVM_FLAG_HOST_ACCESS)) {
- prange->actual_loc = best_loc;
- return 0;
- }
-
if (!best_loc) {
r = svm_migrate_vram_to_ram(prange, mm);
*migrated = !r;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h
index 0c0fc399395e..3fc1fd8b4fbc 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h
@@ -35,6 +35,10 @@
#include "amdgpu.h"
#include "kfd_priv.h"
+#define SVM_RANGE_VRAM_DOMAIN (1UL << 0)
+#define SVM_ADEV_PGMAP_OWNER(adev)\
+ ((adev)->hive ? (void *)(adev)->hive : (void *)(adev))
+
struct svm_range_bo {
struct amdgpu_bo *bo;
struct kref kref;
@@ -110,7 +114,6 @@ struct svm_range {
struct list_head update_list;
struct list_head remove_list;
struct list_head insert_list;
- struct amdgpu_bo_va_mapping mapping;
uint64_t npages;
dma_addr_t *dma_addr[MAX_GPU_INSTANCE];
struct ttm_resource *ttm_res;
@@ -147,6 +150,14 @@ static inline void svm_range_unlock(struct svm_range *prange)
mutex_unlock(&prange->lock);
}
+static inline struct svm_range_bo *svm_range_bo_ref(struct svm_range_bo *svm_bo)
+{
+ if (svm_bo)
+ kref_get(&svm_bo->kref);
+
+ return svm_bo;
+}
+
int svm_range_list_init(struct kfd_process *p);
void svm_range_list_fini(struct kfd_process *p);
int svm_ioctl(struct kfd_process *p, enum kfd_ioctl_svm_op op, uint64_t start,
@@ -173,13 +184,17 @@ void schedule_deferred_list_work(struct svm_range_list *svms);
void svm_range_dma_unmap(struct device *dev, dma_addr_t *dma_addr,
unsigned long offset, unsigned long npages);
void svm_range_free_dma_mappings(struct svm_range *prange);
-void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm);
+void svm_range_prefault(struct svm_range *prange, struct mm_struct *mm,
+ void *owner);
+struct kfd_process_device *
+svm_range_get_pdd_by_adev(struct svm_range *prange, struct amdgpu_device *adev);
/* SVM API and HMM page migration work together, device memory type
* is initialized to not 0 when page migration register device memory.
*/
#define KFD_IS_SVM_API_SUPPORTED(dev) ((dev)->pgmap.type != 0)
+void svm_range_bo_unref(struct svm_range_bo *svm_bo);
#else
struct kfd_process;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index b5b5ccf0ed71..d3a2a5ff57e9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -1160,6 +1160,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
if (amdgpu_dc_feature_mask & DC_DISABLE_FRACTIONAL_PWM_MASK)
init_data.flags.disable_fractional_pwm = true;
+ if (amdgpu_dc_feature_mask & DC_EDP_NO_POWER_SEQUENCING)
+ init_data.flags.edp_no_power_sequencing = true;
+
init_data.flags.power_down_display_on_boot = true;
INIT_LIST_HEAD(&adev->dm.da_list);
@@ -9188,7 +9191,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || \
defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
/* restore the backlight level */
- if (dm->backlight_dev)
+ if (dm->backlight_dev && (amdgpu_dm_backlight_get_level(dm) != dm->brightness[0]))
amdgpu_dm_backlight_set_level(dm, dm->brightness[0]);
#endif
/*
@@ -10118,7 +10121,7 @@ static int validate_overlay(struct drm_atomic_state *state)
int i;
struct drm_plane *plane;
struct drm_plane_state *new_plane_state;
- struct drm_plane_state *primary_state, *cursor_state, *overlay_state = NULL;
+ struct drm_plane_state *primary_state, *overlay_state = NULL;
/* Check if primary plane is contained inside overlay */
for_each_new_plane_in_state_reverse(state, plane, new_plane_state, i) {
@@ -10148,14 +10151,6 @@ static int validate_overlay(struct drm_atomic_state *state)
if (!primary_state->crtc)
return 0;
- /* check if cursor plane is enabled */
- cursor_state = drm_atomic_get_plane_state(state, overlay_state->crtc->cursor);
- if (IS_ERR(cursor_state))
- return PTR_ERR(cursor_state);
-
- if (drm_atomic_plane_disabling(plane->state, cursor_state))
- return 0;
-
/* Perform the bounds check to ensure the overlay plane covers the primary */
if (primary_state->crtc_x < overlay_state->crtc_x ||
primary_state->crtc_y < overlay_state->crtc_y ||
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c
index 66db5e988bc1..dad4a4c18bcf 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c
@@ -31,8 +31,8 @@
#include "dcn31_smu.h"
#include "yellow_carp_offset.h"
-#include "mp/mp_13_0_1_offset.h"
-#include "mp/mp_13_0_1_sh_mask.h"
+#include "mp/mp_13_0_2_offset.h"
+#include "mp/mp_13_0_2_sh_mask.h"
#define REG(reg_name) \
(MP0_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
index b8832bdde2bc..6da226bf11d5 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
@@ -1620,11 +1620,12 @@ enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_train
{
enum dc_status status = DC_OK;
- if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
- status = configure_lttpr_mode_non_transparent(link, lt_settings);
- else
+ if (lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT)
status = configure_lttpr_mode_transparent(link);
+ else if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
+ status = configure_lttpr_mode_non_transparent(link, lt_settings);
+
return status;
}
@@ -1784,7 +1785,6 @@ bool perform_link_training_with_retries(
link_enc = stream->link_enc;
else
link_enc = link->link_enc;
- ASSERT(link_enc);
/* We need to do this before the link training to ensure the idle pattern in SST
* mode will be sent right after the link training
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 5101a4f8f69f..45640f1c26c4 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -297,6 +297,7 @@ struct dc_config {
bool allow_seamless_boot_optimization;
bool power_down_display_on_boot;
bool edp_not_connected;
+ bool edp_no_power_sequencing;
bool force_enum_edp;
bool forced_clocks;
bool allow_lttpr_non_transparent_mode;
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
index 2938caaa2299..62d595ded866 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
@@ -1022,8 +1022,20 @@ void dce110_edp_backlight_control(
/* dc_service_sleep_in_milliseconds(50); */
/*edp 1.2*/
panel_instance = link->panel_cntl->inst;
- if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON)
- edp_receiver_ready_T7(link);
+
+ if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) {
+ if (!link->dc->config.edp_no_power_sequencing)
+ /*
+ * Sometimes, DP receiver chip power-controlled externally by an
+ * Embedded Controller could be treated and used as eDP,
+ * if it drives mobile display. In this case,
+ * we shouldn't be doing power-sequencing, hence we can skip
+ * waiting for T7-ready.
+ */
+ edp_receiver_ready_T7(link);
+ else
+ DC_LOG_DC("edp_receiver_ready_T7 skipped\n");
+ }
if (ctx->dc->ctx->dmub_srv &&
ctx->dc->debug.dmub_command_table) {
@@ -1048,8 +1060,19 @@ void dce110_edp_backlight_control(
dc_link_backlight_enable_aux(link, enable);
/*edp 1.2*/
- if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF)
- edp_add_delay_for_T9(link);
+ if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) {
+ if (!link->dc->config.edp_no_power_sequencing)
+ /*
+ * Sometimes, DP receiver chip power-controlled externally by an
+ * Embedded Controller could be treated and used as eDP,
+ * if it drives mobile display. In this case,
+ * we shouldn't be doing power-sequencing, hence we can skip
+ * waiting for T9-ready.
+ */
+ edp_add_delay_for_T9(link);
+ else
+ DC_LOG_DC("edp_receiver_ready_T9 skipped\n");
+ }
if (!enable && link->dpcd_sink_ext_caps.bits.oled)
msleep(OLED_PRE_T11_DELAY);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
index 5dcdc5a858fe..4bab97acb155 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
@@ -28,6 +28,7 @@ endif
CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o += -mhard-float
endif
+ifdef CONFIG_X86
ifdef IS_OLD_GCC
# Stack alignment mismatch, proceed with caution.
# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
@@ -36,6 +37,7 @@ CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o += -mpreferred-stack-boundary=4
else
CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o += -msse2
endif
+endif
AMD_DAL_DCN31 = $(addprefix $(AMDDALPATH)/dc/dcn31/,$(DCN31))
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
index fc1fc1a4bf8b..836864a5a5dc 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
@@ -390,7 +390,7 @@ void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx)
is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal);
is_dp = dc_is_dp_signal(pipe_ctx->stream->signal);
- if (!is_hdmi_tmds)
+ if (!is_hdmi_tmds && !is_dp)
return;
if (is_hdmi_tmds)
diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile
index d34024fd798a..45862167e6ce 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile
@@ -50,6 +50,10 @@ dml_ccflags += -msse2
endif
endif
+ifneq ($(CONFIG_FRAME_WARN),0)
+frame_warn_flag := -Wframe-larger-than=2048
+endif
+
CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags)
ifdef CONFIG_DRM_AMD_DC_DCN
@@ -60,9 +64,9 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20v2.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20v2.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_mode_vba_21.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/dcn21/display_rq_dlg_calc_21.o := $(dml_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) -Wframe-larger-than=2048
+CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) $(frame_warn_flag)
CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_ccflags) -Wframe-larger-than=2048
+CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_ccflags) $(frame_warn_flag)
CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_rcflags)
diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
index 5f245bde54ff..a2a4fbeb83f8 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
@@ -119,7 +119,7 @@ bool dal_irq_service_set(
dal_irq_service_ack(irq_service, source);
- if (info->funcs->set)
+ if (info->funcs && info->funcs->set)
return info->funcs->set(irq_service, info, enable);
dal_irq_service_set_generic(irq_service, info, enable);
@@ -153,7 +153,7 @@ bool dal_irq_service_ack(
return false;
}
- if (info->funcs->ack)
+ if (info->funcs && info->funcs->ack)
return info->funcs->ack(irq_service, info);
dal_irq_service_ack_generic(irq_service, info);
diff --git a/drivers/gpu/drm/amd/display/dc/irq_types.h b/drivers/gpu/drm/amd/display/dc/irq_types.h
index 5f9346622301..1139b9eb9f6f 100644
--- a/drivers/gpu/drm/amd/display/dc/irq_types.h
+++ b/drivers/gpu/drm/amd/display/dc/irq_types.h
@@ -165,7 +165,7 @@ enum irq_type
};
#define DAL_VALID_IRQ_SRC_NUM(src) \
- ((src) <= DAL_IRQ_SOURCES_NUMBER && (src) > DC_IRQ_SOURCE_INVALID)
+ ((src) < DAL_IRQ_SOURCES_NUMBER && (src) > DC_IRQ_SOURCE_INVALID)
/* Number of Page Flip IRQ Sources. */
#define DAL_PFLIP_IRQ_SRC_NUM \
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c
index 8c886ece71f6..973de346410d 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c
@@ -352,3 +352,63 @@ uint32_t dmub_dcn31_get_current_time(struct dmub_srv *dmub)
{
return REG_READ(DMCUB_TIMER_CURRENT);
}
+
+void dmub_dcn31_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data)
+{
+ uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset;
+ uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled;
+
+ if (!dmub || !diag_data)
+ return;
+
+ memset(diag_data, 0, sizeof(*diag_data));
+
+ diag_data->dmcub_version = dmub->fw_version;
+
+ diag_data->scratch[0] = REG_READ(DMCUB_SCRATCH0);
+ diag_data->scratch[1] = REG_READ(DMCUB_SCRATCH1);
+ diag_data->scratch[2] = REG_READ(DMCUB_SCRATCH2);
+ diag_data->scratch[3] = REG_READ(DMCUB_SCRATCH3);
+ diag_data->scratch[4] = REG_READ(DMCUB_SCRATCH4);
+ diag_data->scratch[5] = REG_READ(DMCUB_SCRATCH5);
+ diag_data->scratch[6] = REG_READ(DMCUB_SCRATCH6);
+ diag_data->scratch[7] = REG_READ(DMCUB_SCRATCH7);
+ diag_data->scratch[8] = REG_READ(DMCUB_SCRATCH8);
+ diag_data->scratch[9] = REG_READ(DMCUB_SCRATCH9);
+ diag_data->scratch[10] = REG_READ(DMCUB_SCRATCH10);
+ diag_data->scratch[11] = REG_READ(DMCUB_SCRATCH11);
+ diag_data->scratch[12] = REG_READ(DMCUB_SCRATCH12);
+ diag_data->scratch[13] = REG_READ(DMCUB_SCRATCH13);
+ diag_data->scratch[14] = REG_READ(DMCUB_SCRATCH14);
+ diag_data->scratch[15] = REG_READ(DMCUB_SCRATCH15);
+
+ diag_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR);
+ diag_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR);
+ diag_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR);
+
+ diag_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR);
+ diag_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR);
+ diag_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE);
+
+ diag_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR);
+ diag_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR);
+ diag_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE);
+
+ REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled);
+ diag_data->is_dmcub_enabled = is_dmub_enabled;
+
+ REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset);
+ diag_data->is_dmcub_soft_reset = is_soft_reset;
+
+ REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset);
+ diag_data->is_dmcub_secure_reset = is_sec_reset;
+
+ REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled);
+ diag_data->is_traceport_en = is_traceport_enabled;
+
+ REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled);
+ diag_data->is_cw0_enabled = is_cw0_enabled;
+
+ REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled);
+ diag_data->is_cw6_enabled = is_cw6_enabled;
+}
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h
index 2829c3e9a310..9456a6a2d518 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h
@@ -36,6 +36,9 @@ struct dmub_srv;
DMUB_SR(DMCUB_CNTL) \
DMUB_SR(DMCUB_CNTL2) \
DMUB_SR(DMCUB_SEC_CNTL) \
+ DMUB_SR(DMCUB_INBOX0_SIZE) \
+ DMUB_SR(DMCUB_INBOX0_RPTR) \
+ DMUB_SR(DMCUB_INBOX0_WPTR) \
DMUB_SR(DMCUB_INBOX1_BASE_ADDRESS) \
DMUB_SR(DMCUB_INBOX1_SIZE) \
DMUB_SR(DMCUB_INBOX1_RPTR) \
@@ -103,11 +106,15 @@ struct dmub_srv;
DMUB_SR(DMCUB_SCRATCH14) \
DMUB_SR(DMCUB_SCRATCH15) \
DMUB_SR(DMCUB_GPINT_DATAIN1) \
+ DMUB_SR(DMCUB_GPINT_DATAOUT) \
DMUB_SR(CC_DC_PIPE_DIS) \
DMUB_SR(MMHUBBUB_SOFT_RESET) \
DMUB_SR(DCN_VM_FB_LOCATION_BASE) \
DMUB_SR(DCN_VM_FB_OFFSET) \
- DMUB_SR(DMCUB_TIMER_CURRENT)
+ DMUB_SR(DMCUB_TIMER_CURRENT) \
+ DMUB_SR(DMCUB_INST_FETCH_FAULT_ADDR) \
+ DMUB_SR(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR) \
+ DMUB_SR(DMCUB_DATA_WRITE_FAULT_ADDR)
#define DMUB_DCN31_FIELDS() \
DMUB_SF(DMCUB_CNTL, DMCUB_ENABLE) \
@@ -115,6 +122,7 @@ struct dmub_srv;
DMUB_SF(DMCUB_CNTL2, DMCUB_SOFT_RESET) \
DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET) \
DMUB_SF(DMCUB_SEC_CNTL, DMCUB_MEM_UNIT_ID) \
+ DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS) \
DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_TOP_ADDRESS) \
DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE) \
DMUB_SF(DMCUB_REGION3_CW1_TOP_ADDRESS, DMCUB_REGION3_CW1_TOP_ADDRESS) \
@@ -138,11 +146,13 @@ struct dmub_srv;
DMUB_SF(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE) \
DMUB_SF(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET) \
DMUB_SF(DCN_VM_FB_LOCATION_BASE, FB_BASE) \
- DMUB_SF(DCN_VM_FB_OFFSET, FB_OFFSET)
+ DMUB_SF(DCN_VM_FB_OFFSET, FB_OFFSET) \
+ DMUB_SF(DMCUB_INBOX0_WPTR, DMCUB_INBOX0_WPTR)
struct dmub_srv_dcn31_reg_offset {
#define DMUB_SR(reg) uint32_t reg;
DMUB_DCN31_REGS()
+ DMCUB_INTERNAL_REGS()
#undef DMUB_SR
};
@@ -227,4 +237,6 @@ void dmub_dcn31_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset);
uint32_t dmub_dcn31_get_current_time(struct dmub_srv *dmub);
+void dmub_dcn31_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data);
+
#endif /* _DMUB_DCN31_H_ */
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
index fd7e996ab1d7..2bdbd7406f56 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
@@ -208,6 +208,7 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
break;
case DMUB_ASIC_DCN31:
+ dmub->regs_dcn31 = &dmub_srv_dcn31_regs;
funcs->reset = dmub_dcn31_reset;
funcs->reset_release = dmub_dcn31_reset_release;
funcs->backdoor_load = dmub_dcn31_backdoor_load;
@@ -231,9 +232,7 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
funcs->get_outbox0_wptr = dmub_dcn31_get_outbox0_wptr;
funcs->set_outbox0_rptr = dmub_dcn31_set_outbox0_rptr;
- if (asic == DMUB_ASIC_DCN31) {
- dmub->regs_dcn31 = &dmub_srv_dcn31_regs;
- }
+ funcs->get_diagnostic_data = dmub_dcn31_get_diagnostic_data;
funcs->get_current_time = dmub_dcn31_get_current_time;
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h
index 332b0df53e52..ff1d3d4a6488 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -223,10 +223,12 @@ enum amd_harvest_ip_mask {
};
enum DC_FEATURE_MASK {
- DC_FBC_MASK = 0x1,
- DC_MULTI_MON_PP_MCLK_SWITCH_MASK = 0x2,
- DC_DISABLE_FRACTIONAL_PWM_MASK = 0x4,
- DC_PSR_MASK = 0x8,
+ //Default value can be found at "uint amdgpu_dc_feature_mask"
+ DC_FBC_MASK = (1 << 0), //0x1, disabled by default
+ DC_MULTI_MON_PP_MCLK_SWITCH_MASK = (1 << 1), //0x2, enabled by default
+ DC_DISABLE_FRACTIONAL_PWM_MASK = (1 << 2), //0x4, disabled by default
+ DC_PSR_MASK = (1 << 3), //0x8, disabled by default
+ DC_EDP_NO_POWER_SEQUENCING = (1 << 4), //0x10, disabled by default
};
enum DC_DEBUG_MASK {
diff --git a/drivers/gpu/drm/amd/include/asic_reg/mp/mp_13_0_1_offset.h b/drivers/gpu/drm/amd/include/asic_reg/mp/mp_13_0_1_offset.h
deleted file mode 100644
index dfacc6b5d89d..000000000000
--- a/drivers/gpu/drm/amd/include/asic_reg/mp/mp_13_0_1_offset.h
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Copyright 2020 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _mp_13_0_1_OFFSET_HEADER
-#define _mp_13_0_1_OFFSET_HEADER
-
-
-
-// addressBlock: mp_SmuMp0_SmnDec
-// base address: 0x0
-#define regMP0_SMN_C2PMSG_32 0x0060
-#define regMP0_SMN_C2PMSG_32_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_33 0x0061
-#define regMP0_SMN_C2PMSG_33_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_34 0x0062
-#define regMP0_SMN_C2PMSG_34_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_35 0x0063
-#define regMP0_SMN_C2PMSG_35_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_36 0x0064
-#define regMP0_SMN_C2PMSG_36_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_37 0x0065
-#define regMP0_SMN_C2PMSG_37_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_38 0x0066
-#define regMP0_SMN_C2PMSG_38_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_39 0x0067
-#define regMP0_SMN_C2PMSG_39_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_40 0x0068
-#define regMP0_SMN_C2PMSG_40_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_41 0x0069
-#define regMP0_SMN_C2PMSG_41_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_42 0x006a
-#define regMP0_SMN_C2PMSG_42_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_43 0x006b
-#define regMP0_SMN_C2PMSG_43_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_44 0x006c
-#define regMP0_SMN_C2PMSG_44_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_45 0x006d
-#define regMP0_SMN_C2PMSG_45_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_46 0x006e
-#define regMP0_SMN_C2PMSG_46_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_47 0x006f
-#define regMP0_SMN_C2PMSG_47_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_48 0x0070
-#define regMP0_SMN_C2PMSG_48_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_49 0x0071
-#define regMP0_SMN_C2PMSG_49_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_50 0x0072
-#define regMP0_SMN_C2PMSG_50_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_51 0x0073
-#define regMP0_SMN_C2PMSG_51_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_52 0x0074
-#define regMP0_SMN_C2PMSG_52_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_53 0x0075
-#define regMP0_SMN_C2PMSG_53_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_54 0x0076
-#define regMP0_SMN_C2PMSG_54_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_55 0x0077
-#define regMP0_SMN_C2PMSG_55_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_56 0x0078
-#define regMP0_SMN_C2PMSG_56_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_57 0x0079
-#define regMP0_SMN_C2PMSG_57_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_58 0x007a
-#define regMP0_SMN_C2PMSG_58_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_59 0x007b
-#define regMP0_SMN_C2PMSG_59_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_60 0x007c
-#define regMP0_SMN_C2PMSG_60_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_61 0x007d
-#define regMP0_SMN_C2PMSG_61_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_62 0x007e
-#define regMP0_SMN_C2PMSG_62_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_63 0x007f
-#define regMP0_SMN_C2PMSG_63_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_64 0x0080
-#define regMP0_SMN_C2PMSG_64_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_65 0x0081
-#define regMP0_SMN_C2PMSG_65_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_66 0x0082
-#define regMP0_SMN_C2PMSG_66_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_67 0x0083
-#define regMP0_SMN_C2PMSG_67_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_68 0x0084
-#define regMP0_SMN_C2PMSG_68_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_69 0x0085
-#define regMP0_SMN_C2PMSG_69_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_70 0x0086
-#define regMP0_SMN_C2PMSG_70_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_71 0x0087
-#define regMP0_SMN_C2PMSG_71_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_72 0x0088
-#define regMP0_SMN_C2PMSG_72_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_73 0x0089
-#define regMP0_SMN_C2PMSG_73_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_74 0x008a
-#define regMP0_SMN_C2PMSG_74_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_75 0x008b
-#define regMP0_SMN_C2PMSG_75_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_76 0x008c
-#define regMP0_SMN_C2PMSG_76_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_77 0x008d
-#define regMP0_SMN_C2PMSG_77_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_78 0x008e
-#define regMP0_SMN_C2PMSG_78_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_79 0x008f
-#define regMP0_SMN_C2PMSG_79_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_80 0x0090
-#define regMP0_SMN_C2PMSG_80_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_81 0x0091
-#define regMP0_SMN_C2PMSG_81_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_82 0x0092
-#define regMP0_SMN_C2PMSG_82_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_83 0x0093
-#define regMP0_SMN_C2PMSG_83_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_84 0x0094
-#define regMP0_SMN_C2PMSG_84_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_85 0x0095
-#define regMP0_SMN_C2PMSG_85_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_86 0x0096
-#define regMP0_SMN_C2PMSG_86_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_87 0x0097
-#define regMP0_SMN_C2PMSG_87_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_88 0x0098
-#define regMP0_SMN_C2PMSG_88_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_89 0x0099
-#define regMP0_SMN_C2PMSG_89_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_90 0x009a
-#define regMP0_SMN_C2PMSG_90_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_91 0x009b
-#define regMP0_SMN_C2PMSG_91_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_92 0x009c
-#define regMP0_SMN_C2PMSG_92_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_93 0x009d
-#define regMP0_SMN_C2PMSG_93_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_94 0x009e
-#define regMP0_SMN_C2PMSG_94_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_95 0x009f
-#define regMP0_SMN_C2PMSG_95_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_96 0x00a0
-#define regMP0_SMN_C2PMSG_96_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_97 0x00a1
-#define regMP0_SMN_C2PMSG_97_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_98 0x00a2
-#define regMP0_SMN_C2PMSG_98_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_99 0x00a3
-#define regMP0_SMN_C2PMSG_99_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_100 0x00a4
-#define regMP0_SMN_C2PMSG_100_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_101 0x00a5
-#define regMP0_SMN_C2PMSG_101_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_102 0x00a6
-#define regMP0_SMN_C2PMSG_102_BASE_IDX 0
-#define regMP0_SMN_C2PMSG_103 0x00a7
-#define regMP0_SMN_C2PMSG_103_BASE_IDX 0
-#define regMP0_SMN_IH_CREDIT 0x00c1
-#define regMP0_SMN_IH_CREDIT_BASE_IDX 0
-#define regMP0_SMN_IH_SW_INT 0x00c2
-#define regMP0_SMN_IH_SW_INT_BASE_IDX 0
-#define regMP0_SMN_IH_SW_INT_CTRL 0x00c3
-#define regMP0_SMN_IH_SW_INT_CTRL_BASE_IDX 0
-
-
-// addressBlock: mp_SmuMp1_SmnDec
-// base address: 0x0
-#define regMP1_SMN_C2PMSG_32 0x0260
-#define regMP1_SMN_C2PMSG_32_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_33 0x0261
-#define regMP1_SMN_C2PMSG_33_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_34 0x0262
-#define regMP1_SMN_C2PMSG_34_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_35 0x0263
-#define regMP1_SMN_C2PMSG_35_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_36 0x0264
-#define regMP1_SMN_C2PMSG_36_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_37 0x0265
-#define regMP1_SMN_C2PMSG_37_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_38 0x0266
-#define regMP1_SMN_C2PMSG_38_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_39 0x0267
-#define regMP1_SMN_C2PMSG_39_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_40 0x0268
-#define regMP1_SMN_C2PMSG_40_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_41 0x0269
-#define regMP1_SMN_C2PMSG_41_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_42 0x026a
-#define regMP1_SMN_C2PMSG_42_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_43 0x026b
-#define regMP1_SMN_C2PMSG_43_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_44 0x026c
-#define regMP1_SMN_C2PMSG_44_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_45 0x026d
-#define regMP1_SMN_C2PMSG_45_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_46 0x026e
-#define regMP1_SMN_C2PMSG_46_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_47 0x026f
-#define regMP1_SMN_C2PMSG_47_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_48 0x0270
-#define regMP1_SMN_C2PMSG_48_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_49 0x0271
-#define regMP1_SMN_C2PMSG_49_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_50 0x0272
-#define regMP1_SMN_C2PMSG_50_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_51 0x0273
-#define regMP1_SMN_C2PMSG_51_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_52 0x0274
-#define regMP1_SMN_C2PMSG_52_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_53 0x0275
-#define regMP1_SMN_C2PMSG_53_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_54 0x0276
-#define regMP1_SMN_C2PMSG_54_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_55 0x0277
-#define regMP1_SMN_C2PMSG_55_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_56 0x0278
-#define regMP1_SMN_C2PMSG_56_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_57 0x0279
-#define regMP1_SMN_C2PMSG_57_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_58 0x027a
-#define regMP1_SMN_C2PMSG_58_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_59 0x027b
-#define regMP1_SMN_C2PMSG_59_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_60 0x027c
-#define regMP1_SMN_C2PMSG_60_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_61 0x027d
-#define regMP1_SMN_C2PMSG_61_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_62 0x027e
-#define regMP1_SMN_C2PMSG_62_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_63 0x027f
-#define regMP1_SMN_C2PMSG_63_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_64 0x0280
-#define regMP1_SMN_C2PMSG_64_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_65 0x0281
-#define regMP1_SMN_C2PMSG_65_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_66 0x0282
-#define regMP1_SMN_C2PMSG_66_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_67 0x0283
-#define regMP1_SMN_C2PMSG_67_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_68 0x0284
-#define regMP1_SMN_C2PMSG_68_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_69 0x0285
-#define regMP1_SMN_C2PMSG_69_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_70 0x0286
-#define regMP1_SMN_C2PMSG_70_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_71 0x0287
-#define regMP1_SMN_C2PMSG_71_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_72 0x0288
-#define regMP1_SMN_C2PMSG_72_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_73 0x0289
-#define regMP1_SMN_C2PMSG_73_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_74 0x028a
-#define regMP1_SMN_C2PMSG_74_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_75 0x028b
-#define regMP1_SMN_C2PMSG_75_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_76 0x028c
-#define regMP1_SMN_C2PMSG_76_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_77 0x028d
-#define regMP1_SMN_C2PMSG_77_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_78 0x028e
-#define regMP1_SMN_C2PMSG_78_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_79 0x028f
-#define regMP1_SMN_C2PMSG_79_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_80 0x0290
-#define regMP1_SMN_C2PMSG_80_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_81 0x0291
-#define regMP1_SMN_C2PMSG_81_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_82 0x0292
-#define regMP1_SMN_C2PMSG_82_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_83 0x0293
-#define regMP1_SMN_C2PMSG_83_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_84 0x0294
-#define regMP1_SMN_C2PMSG_84_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_85 0x0295
-#define regMP1_SMN_C2PMSG_85_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_86 0x0296
-#define regMP1_SMN_C2PMSG_86_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_87 0x0297
-#define regMP1_SMN_C2PMSG_87_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_88 0x0298
-#define regMP1_SMN_C2PMSG_88_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_89 0x0299
-#define regMP1_SMN_C2PMSG_89_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_90 0x029a
-#define regMP1_SMN_C2PMSG_90_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_91 0x029b
-#define regMP1_SMN_C2PMSG_91_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_92 0x029c
-#define regMP1_SMN_C2PMSG_92_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_93 0x029d
-#define regMP1_SMN_C2PMSG_93_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_94 0x029e
-#define regMP1_SMN_C2PMSG_94_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_95 0x029f
-#define regMP1_SMN_C2PMSG_95_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_96 0x02a0
-#define regMP1_SMN_C2PMSG_96_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_97 0x02a1
-#define regMP1_SMN_C2PMSG_97_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_98 0x02a2
-#define regMP1_SMN_C2PMSG_98_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_99 0x02a3
-#define regMP1_SMN_C2PMSG_99_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_100 0x02a4
-#define regMP1_SMN_C2PMSG_100_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_101 0x02a5
-#define regMP1_SMN_C2PMSG_101_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_102 0x02a6
-#define regMP1_SMN_C2PMSG_102_BASE_IDX 0
-#define regMP1_SMN_C2PMSG_103 0x02a7
-#define regMP1_SMN_C2PMSG_103_BASE_IDX 0
-#define regMP1_SMN_IH_CREDIT 0x02c1
-#define regMP1_SMN_IH_CREDIT_BASE_IDX 0
-#define regMP1_SMN_IH_SW_INT 0x02c2
-#define regMP1_SMN_IH_SW_INT_BASE_IDX 0
-#define regMP1_SMN_IH_SW_INT_CTRL 0x02c3
-#define regMP1_SMN_IH_SW_INT_CTRL_BASE_IDX 0
-#define regMP1_SMN_FPS_CNT 0x02c4
-#define regMP1_SMN_FPS_CNT_BASE_IDX 0
-#define regMP1_SMN_EXT_SCRATCH0 0x0340
-#define regMP1_SMN_EXT_SCRATCH0_BASE_IDX 0
-#define regMP1_SMN_EXT_SCRATCH1 0x0341
-#define regMP1_SMN_EXT_SCRATCH1_BASE_IDX 0
-#define regMP1_SMN_EXT_SCRATCH2 0x0342
-#define regMP1_SMN_EXT_SCRATCH2_BASE_IDX 0
-#define regMP1_SMN_EXT_SCRATCH3 0x0343
-#define regMP1_SMN_EXT_SCRATCH3_BASE_IDX 0
-#define regMP1_SMN_EXT_SCRATCH4 0x0344
-#define regMP1_SMN_EXT_SCRATCH4_BASE_IDX 0
-#define regMP1_SMN_EXT_SCRATCH5 0x0345
-#define regMP1_SMN_EXT_SCRATCH5_BASE_IDX 0
-#define regMP1_SMN_EXT_SCRATCH6 0x0346
-#define regMP1_SMN_EXT_SCRATCH6_BASE_IDX 0
-#define regMP1_SMN_EXT_SCRATCH7 0x0347
-#define regMP1_SMN_EXT_SCRATCH7_BASE_IDX 0
-
-
-#endif
diff --git a/drivers/gpu/drm/amd/include/asic_reg/mp/mp_13_0_1_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/mp/mp_13_0_1_sh_mask.h
deleted file mode 100644
index 2d5e8b58e693..000000000000
--- a/drivers/gpu/drm/amd/include/asic_reg/mp/mp_13_0_1_sh_mask.h
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * Copyright 2020 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _mp_13_0_1_SH_MASK_HEADER
-#define _mp_13_0_1_SH_MASK_HEADER
-
-
-// addressBlock: mp_SmuMp0_SmnDec
-//MP0_SMN_C2PMSG_32
-#define MP0_SMN_C2PMSG_32__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_32__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_33
-#define MP0_SMN_C2PMSG_33__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_33__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_34
-#define MP0_SMN_C2PMSG_34__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_34__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_35
-#define MP0_SMN_C2PMSG_35__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_35__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_36
-#define MP0_SMN_C2PMSG_36__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_36__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_37
-#define MP0_SMN_C2PMSG_37__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_37__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_38
-#define MP0_SMN_C2PMSG_38__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_38__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_39
-#define MP0_SMN_C2PMSG_39__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_39__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_40
-#define MP0_SMN_C2PMSG_40__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_40__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_41
-#define MP0_SMN_C2PMSG_41__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_41__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_42
-#define MP0_SMN_C2PMSG_42__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_42__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_43
-#define MP0_SMN_C2PMSG_43__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_43__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_44
-#define MP0_SMN_C2PMSG_44__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_44__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_45
-#define MP0_SMN_C2PMSG_45__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_45__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_46
-#define MP0_SMN_C2PMSG_46__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_46__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_47
-#define MP0_SMN_C2PMSG_47__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_47__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_48
-#define MP0_SMN_C2PMSG_48__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_48__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_49
-#define MP0_SMN_C2PMSG_49__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_49__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_50
-#define MP0_SMN_C2PMSG_50__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_50__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_51
-#define MP0_SMN_C2PMSG_51__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_51__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_52
-#define MP0_SMN_C2PMSG_52__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_52__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_53
-#define MP0_SMN_C2PMSG_53__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_53__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_54
-#define MP0_SMN_C2PMSG_54__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_54__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_55
-#define MP0_SMN_C2PMSG_55__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_55__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_56
-#define MP0_SMN_C2PMSG_56__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_56__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_57
-#define MP0_SMN_C2PMSG_57__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_57__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_58
-#define MP0_SMN_C2PMSG_58__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_58__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_59
-#define MP0_SMN_C2PMSG_59__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_59__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_60
-#define MP0_SMN_C2PMSG_60__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_60__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_61
-#define MP0_SMN_C2PMSG_61__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_61__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_62
-#define MP0_SMN_C2PMSG_62__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_62__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_63
-#define MP0_SMN_C2PMSG_63__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_63__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_64
-#define MP0_SMN_C2PMSG_64__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_64__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_65
-#define MP0_SMN_C2PMSG_65__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_65__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_66
-#define MP0_SMN_C2PMSG_66__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_66__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_67
-#define MP0_SMN_C2PMSG_67__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_67__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_68
-#define MP0_SMN_C2PMSG_68__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_68__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_69
-#define MP0_SMN_C2PMSG_69__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_69__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_70
-#define MP0_SMN_C2PMSG_70__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_70__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_71
-#define MP0_SMN_C2PMSG_71__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_71__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_72
-#define MP0_SMN_C2PMSG_72__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_72__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_73
-#define MP0_SMN_C2PMSG_73__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_73__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_74
-#define MP0_SMN_C2PMSG_74__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_74__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_75
-#define MP0_SMN_C2PMSG_75__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_75__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_76
-#define MP0_SMN_C2PMSG_76__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_76__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_77
-#define MP0_SMN_C2PMSG_77__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_77__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_78
-#define MP0_SMN_C2PMSG_78__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_78__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_79
-#define MP0_SMN_C2PMSG_79__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_79__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_80
-#define MP0_SMN_C2PMSG_80__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_80__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_81
-#define MP0_SMN_C2PMSG_81__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_81__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_82
-#define MP0_SMN_C2PMSG_82__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_82__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_83
-#define MP0_SMN_C2PMSG_83__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_83__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_84
-#define MP0_SMN_C2PMSG_84__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_84__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_85
-#define MP0_SMN_C2PMSG_85__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_85__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_86
-#define MP0_SMN_C2PMSG_86__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_86__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_87
-#define MP0_SMN_C2PMSG_87__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_87__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_88
-#define MP0_SMN_C2PMSG_88__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_88__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_89
-#define MP0_SMN_C2PMSG_89__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_89__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_90
-#define MP0_SMN_C2PMSG_90__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_90__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_91
-#define MP0_SMN_C2PMSG_91__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_91__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_92
-#define MP0_SMN_C2PMSG_92__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_92__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_93
-#define MP0_SMN_C2PMSG_93__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_93__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_94
-#define MP0_SMN_C2PMSG_94__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_94__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_95
-#define MP0_SMN_C2PMSG_95__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_95__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_96
-#define MP0_SMN_C2PMSG_96__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_96__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_97
-#define MP0_SMN_C2PMSG_97__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_97__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_98
-#define MP0_SMN_C2PMSG_98__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_98__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_99
-#define MP0_SMN_C2PMSG_99__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_99__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_100
-#define MP0_SMN_C2PMSG_100__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_100__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_101
-#define MP0_SMN_C2PMSG_101__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_101__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_102
-#define MP0_SMN_C2PMSG_102__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_102__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_C2PMSG_103
-#define MP0_SMN_C2PMSG_103__CONTENT__SHIFT 0x0
-#define MP0_SMN_C2PMSG_103__CONTENT_MASK 0xFFFFFFFFL
-//MP0_SMN_IH_CREDIT
-#define MP0_SMN_IH_CREDIT__CREDIT_VALUE__SHIFT 0x0
-#define MP0_SMN_IH_CREDIT__CLIENT_ID__SHIFT 0x10
-#define MP0_SMN_IH_CREDIT__CREDIT_VALUE_MASK 0x00000003L
-#define MP0_SMN_IH_CREDIT__CLIENT_ID_MASK 0x00FF0000L
-//MP0_SMN_IH_SW_INT
-#define MP0_SMN_IH_SW_INT__ID__SHIFT 0x0
-#define MP0_SMN_IH_SW_INT__VALID__SHIFT 0x8
-#define MP0_SMN_IH_SW_INT__ID_MASK 0x000000FFL
-#define MP0_SMN_IH_SW_INT__VALID_MASK 0x00000100L
-//MP0_SMN_IH_SW_INT_CTRL
-#define MP0_SMN_IH_SW_INT_CTRL__INT_MASK__SHIFT 0x0
-#define MP0_SMN_IH_SW_INT_CTRL__INT_ACK__SHIFT 0x8
-#define MP0_SMN_IH_SW_INT_CTRL__INT_MASK_MASK 0x00000001L
-#define MP0_SMN_IH_SW_INT_CTRL__INT_ACK_MASK 0x00000100L
-
-
-// addressBlock: mp_SmuMp1Pub_CruDec
-//MP1_FIRMWARE_FLAGS
-#define MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT 0x0
-#define MP1_FIRMWARE_FLAGS__RESERVED__SHIFT 0x1
-#define MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK 0x00000001L
-#define MP1_FIRMWARE_FLAGS__RESERVED_MASK 0xFFFFFFFEL
-
-
-// addressBlock: mp_SmuMp1_SmnDec
-//MP1_SMN_C2PMSG_32
-#define MP1_SMN_C2PMSG_32__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_32__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_33
-#define MP1_SMN_C2PMSG_33__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_33__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_34
-#define MP1_SMN_C2PMSG_34__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_34__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_35
-#define MP1_SMN_C2PMSG_35__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_35__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_36
-#define MP1_SMN_C2PMSG_36__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_36__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_37
-#define MP1_SMN_C2PMSG_37__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_37__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_38
-#define MP1_SMN_C2PMSG_38__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_38__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_39
-#define MP1_SMN_C2PMSG_39__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_39__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_40
-#define MP1_SMN_C2PMSG_40__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_40__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_41
-#define MP1_SMN_C2PMSG_41__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_41__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_42
-#define MP1_SMN_C2PMSG_42__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_42__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_43
-#define MP1_SMN_C2PMSG_43__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_43__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_44
-#define MP1_SMN_C2PMSG_44__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_44__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_45
-#define MP1_SMN_C2PMSG_45__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_45__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_46
-#define MP1_SMN_C2PMSG_46__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_46__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_47
-#define MP1_SMN_C2PMSG_47__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_47__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_48
-#define MP1_SMN_C2PMSG_48__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_48__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_49
-#define MP1_SMN_C2PMSG_49__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_49__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_50
-#define MP1_SMN_C2PMSG_50__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_50__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_51
-#define MP1_SMN_C2PMSG_51__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_51__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_52
-#define MP1_SMN_C2PMSG_52__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_52__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_53
-#define MP1_SMN_C2PMSG_53__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_53__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_54
-#define MP1_SMN_C2PMSG_54__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_54__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_55
-#define MP1_SMN_C2PMSG_55__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_55__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_56
-#define MP1_SMN_C2PMSG_56__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_56__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_57
-#define MP1_SMN_C2PMSG_57__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_57__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_58
-#define MP1_SMN_C2PMSG_58__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_58__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_59
-#define MP1_SMN_C2PMSG_59__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_59__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_60
-#define MP1_SMN_C2PMSG_60__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_60__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_61
-#define MP1_SMN_C2PMSG_61__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_61__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_62
-#define MP1_SMN_C2PMSG_62__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_62__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_63
-#define MP1_SMN_C2PMSG_63__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_63__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_64
-#define MP1_SMN_C2PMSG_64__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_64__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_65
-#define MP1_SMN_C2PMSG_65__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_65__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_66
-#define MP1_SMN_C2PMSG_66__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_66__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_67
-#define MP1_SMN_C2PMSG_67__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_67__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_68
-#define MP1_SMN_C2PMSG_68__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_68__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_69
-#define MP1_SMN_C2PMSG_69__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_69__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_70
-#define MP1_SMN_C2PMSG_70__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_70__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_71
-#define MP1_SMN_C2PMSG_71__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_71__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_72
-#define MP1_SMN_C2PMSG_72__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_72__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_73
-#define MP1_SMN_C2PMSG_73__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_73__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_74
-#define MP1_SMN_C2PMSG_74__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_74__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_75
-#define MP1_SMN_C2PMSG_75__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_75__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_76
-#define MP1_SMN_C2PMSG_76__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_76__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_77
-#define MP1_SMN_C2PMSG_77__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_77__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_78
-#define MP1_SMN_C2PMSG_78__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_78__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_79
-#define MP1_SMN_C2PMSG_79__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_79__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_80
-#define MP1_SMN_C2PMSG_80__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_80__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_81
-#define MP1_SMN_C2PMSG_81__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_81__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_82
-#define MP1_SMN_C2PMSG_82__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_82__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_83
-#define MP1_SMN_C2PMSG_83__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_83__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_84
-#define MP1_SMN_C2PMSG_84__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_84__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_85
-#define MP1_SMN_C2PMSG_85__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_85__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_86
-#define MP1_SMN_C2PMSG_86__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_86__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_87
-#define MP1_SMN_C2PMSG_87__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_87__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_88
-#define MP1_SMN_C2PMSG_88__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_88__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_89
-#define MP1_SMN_C2PMSG_89__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_89__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_90
-#define MP1_SMN_C2PMSG_90__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_90__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_91
-#define MP1_SMN_C2PMSG_91__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_91__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_92
-#define MP1_SMN_C2PMSG_92__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_92__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_93
-#define MP1_SMN_C2PMSG_93__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_93__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_94
-#define MP1_SMN_C2PMSG_94__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_94__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_95
-#define MP1_SMN_C2PMSG_95__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_95__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_96
-#define MP1_SMN_C2PMSG_96__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_96__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_97
-#define MP1_SMN_C2PMSG_97__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_97__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_98
-#define MP1_SMN_C2PMSG_98__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_98__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_99
-#define MP1_SMN_C2PMSG_99__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_99__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_100
-#define MP1_SMN_C2PMSG_100__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_100__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_101
-#define MP1_SMN_C2PMSG_101__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_101__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_102
-#define MP1_SMN_C2PMSG_102__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_102__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_C2PMSG_103
-#define MP1_SMN_C2PMSG_103__CONTENT__SHIFT 0x0
-#define MP1_SMN_C2PMSG_103__CONTENT_MASK 0xFFFFFFFFL
-//MP1_SMN_IH_CREDIT
-#define MP1_SMN_IH_CREDIT__CREDIT_VALUE__SHIFT 0x0
-#define MP1_SMN_IH_CREDIT__CLIENT_ID__SHIFT 0x10
-#define MP1_SMN_IH_CREDIT__CREDIT_VALUE_MASK 0x00000003L
-#define MP1_SMN_IH_CREDIT__CLIENT_ID_MASK 0x00FF0000L
-//MP1_SMN_IH_SW_INT
-#define MP1_SMN_IH_SW_INT__ID__SHIFT 0x0
-#define MP1_SMN_IH_SW_INT__VALID__SHIFT 0x8
-#define MP1_SMN_IH_SW_INT__ID_MASK 0x000000FFL
-#define MP1_SMN_IH_SW_INT__VALID_MASK 0x00000100L
-//MP1_SMN_IH_SW_INT_CTRL
-#define MP1_SMN_IH_SW_INT_CTRL__INT_MASK__SHIFT 0x0
-#define MP1_SMN_IH_SW_INT_CTRL__INT_ACK__SHIFT 0x8
-#define MP1_SMN_IH_SW_INT_CTRL__INT_MASK_MASK 0x00000001L
-#define MP1_SMN_IH_SW_INT_CTRL__INT_ACK_MASK 0x00000100L
-//MP1_SMN_FPS_CNT
-#define MP1_SMN_FPS_CNT__COUNT__SHIFT 0x0
-#define MP1_SMN_FPS_CNT__COUNT_MASK 0xFFFFFFFFL
-//MP1_SMN_EXT_SCRATCH0
-#define MP1_SMN_EXT_SCRATCH0__DATA__SHIFT 0x0
-#define MP1_SMN_EXT_SCRATCH0__DATA_MASK 0xFFFFFFFFL
-//MP1_SMN_EXT_SCRATCH1
-#define MP1_SMN_EXT_SCRATCH1__DATA__SHIFT 0x0
-#define MP1_SMN_EXT_SCRATCH1__DATA_MASK 0xFFFFFFFFL
-//MP1_SMN_EXT_SCRATCH2
-#define MP1_SMN_EXT_SCRATCH2__DATA__SHIFT 0x0
-#define MP1_SMN_EXT_SCRATCH2__DATA_MASK 0xFFFFFFFFL
-//MP1_SMN_EXT_SCRATCH3
-#define MP1_SMN_EXT_SCRATCH3__DATA__SHIFT 0x0
-#define MP1_SMN_EXT_SCRATCH3__DATA_MASK 0xFFFFFFFFL
-//MP1_SMN_EXT_SCRATCH4
-#define MP1_SMN_EXT_SCRATCH4__DATA__SHIFT 0x0
-#define MP1_SMN_EXT_SCRATCH4__DATA_MASK 0xFFFFFFFFL
-//MP1_SMN_EXT_SCRATCH5
-#define MP1_SMN_EXT_SCRATCH5__DATA__SHIFT 0x0
-#define MP1_SMN_EXT_SCRATCH5__DATA_MASK 0xFFFFFFFFL
-//MP1_SMN_EXT_SCRATCH6
-#define MP1_SMN_EXT_SCRATCH6__DATA__SHIFT 0x0
-#define MP1_SMN_EXT_SCRATCH6__DATA_MASK 0xFFFFFFFFL
-//MP1_SMN_EXT_SCRATCH7
-#define MP1_SMN_EXT_SCRATCH7__DATA__SHIFT 0x0
-#define MP1_SMN_EXT_SCRATCH7__DATA_MASK 0xFFFFFFFFL
-
-
-#endif
diff --git a/drivers/gpu/drm/amd/include/navi10_enum.h b/drivers/gpu/drm/amd/include/navi10_enum.h
index d5ead9680c6e..84bcb96f76ea 100644
--- a/drivers/gpu/drm/amd/include/navi10_enum.h
+++ b/drivers/gpu/drm/amd/include/navi10_enum.h
@@ -430,7 +430,7 @@ ARRAY_2D_DEPTH = 0x00000001,
*/
typedef enum ENUM_NUM_SIMD_PER_CU {
-NUM_SIMD_PER_CU = 0x00000004,
+NUM_SIMD_PER_CU = 0x00000002,
} ENUM_NUM_SIMD_PER_CU;
/*
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
index a276ebad47e6..769f58d5ae1a 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
@@ -2902,14 +2902,15 @@ static ssize_t amdgpu_hwmon_show_power_cap_min(struct device *dev,
return sprintf(buf, "%i\n", 0);
}
-static ssize_t amdgpu_hwmon_show_power_cap_max(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+
+static ssize_t amdgpu_hwmon_show_power_cap_generic(struct device *dev,
+ struct device_attribute *attr,
+ char *buf,
+ enum pp_power_limit_level pp_limit_level)
{
struct amdgpu_device *adev = dev_get_drvdata(dev);
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
enum pp_power_type power_type = to_sensor_dev_attr(attr)->index;
- enum pp_power_limit_level pp_limit_level = PP_PWR_LIMIT_MAX;
uint32_t limit;
ssize_t size;
int r;
@@ -2919,17 +2920,17 @@ static ssize_t amdgpu_hwmon_show_power_cap_max(struct device *dev,
if (adev->in_suspend && !adev->in_runpm)
return -EPERM;
+ if ( !(pp_funcs && pp_funcs->get_power_limit))
+ return -ENODATA;
+
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (r < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
return r;
}
- if (pp_funcs && pp_funcs->get_power_limit)
- r = pp_funcs->get_power_limit(adev->powerplay.pp_handle, &limit,
- pp_limit_level, power_type);
- else
- r = -ENODATA;
+ r = pp_funcs->get_power_limit(adev->powerplay.pp_handle, &limit,
+ pp_limit_level, power_type);
if (!r)
size = sysfs_emit(buf, "%u\n", limit * 1000000);
@@ -2942,85 +2943,31 @@ static ssize_t amdgpu_hwmon_show_power_cap_max(struct device *dev,
return size;
}
-static ssize_t amdgpu_hwmon_show_power_cap(struct device *dev,
+
+static ssize_t amdgpu_hwmon_show_power_cap_max(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct amdgpu_device *adev = dev_get_drvdata(dev);
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
- enum pp_power_type power_type = to_sensor_dev_attr(attr)->index;
- enum pp_power_limit_level pp_limit_level = PP_PWR_LIMIT_CURRENT;
- uint32_t limit;
- ssize_t size;
- int r;
-
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
- if (r < 0) {
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
- return r;
- }
-
- if (pp_funcs && pp_funcs->get_power_limit)
- r = pp_funcs->get_power_limit(adev->powerplay.pp_handle, &limit,
- pp_limit_level, power_type);
- else
- r = -ENODATA;
+ return amdgpu_hwmon_show_power_cap_generic(dev, attr, buf, PP_PWR_LIMIT_MAX);
- if (!r)
- size = sysfs_emit(buf, "%u\n", limit * 1000000);
- else
- size = sysfs_emit(buf, "\n");
+}
- pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+static ssize_t amdgpu_hwmon_show_power_cap(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return amdgpu_hwmon_show_power_cap_generic(dev, attr, buf, PP_PWR_LIMIT_CURRENT);
- return size;
}
static ssize_t amdgpu_hwmon_show_power_cap_default(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct amdgpu_device *adev = dev_get_drvdata(dev);
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
- enum pp_power_type power_type = to_sensor_dev_attr(attr)->index;
- enum pp_power_limit_level pp_limit_level = PP_PWR_LIMIT_DEFAULT;
- uint32_t limit;
- ssize_t size;
- int r;
+ return amdgpu_hwmon_show_power_cap_generic(dev, attr, buf, PP_PWR_LIMIT_DEFAULT);
- if (amdgpu_in_reset(adev))
- return -EPERM;
- if (adev->in_suspend && !adev->in_runpm)
- return -EPERM;
-
- r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
- if (r < 0) {
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
- return r;
- }
-
- if (pp_funcs && pp_funcs->get_power_limit)
- r = pp_funcs->get_power_limit(adev->powerplay.pp_handle, &limit,
- pp_limit_level, power_type);
- else
- r = -ENODATA;
-
- if (!r)
- size = sysfs_emit(buf, "%u\n", limit * 1000000);
- else
- size = sysfs_emit(buf, "\n");
-
- pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
- pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
-
- return size;
}
+
static ssize_t amdgpu_hwmon_show_power_label(struct device *dev,
struct device_attribute *attr,
char *buf)
diff --git a/drivers/gpu/drm/amd/pm/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/inc/smu_v13_0.h
index 6119a36b2cba..3fea2430dec0 100644
--- a/drivers/gpu/drm/amd/pm/inc/smu_v13_0.h
+++ b/drivers/gpu/drm/amd/pm/inc/smu_v13_0.h
@@ -26,6 +26,7 @@
#include "amdgpu_smu.h"
#define SMU13_DRIVER_IF_VERSION_INV 0xFFFFFFFF
+#define SMU13_DRIVER_IF_VERSION_YELLOW_CARP 0x03
#define SMU13_DRIVER_IF_VERSION_ALDE 0x07
/* MP Apertures */
diff --git a/drivers/gpu/drm/amd/pm/inc/smu_v13_0_1.h b/drivers/gpu/drm/amd/pm/inc/smu_v13_0_1.h
deleted file mode 100644
index b6c976a4d578..000000000000
--- a/drivers/gpu/drm/amd/pm/inc/smu_v13_0_1.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2020 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 __SMU_V13_0_1_H__
-#define __SMU_V13_0_1_H__
-
-#include "amdgpu_smu.h"
-
-#define SMU13_0_1_DRIVER_IF_VERSION_INV 0xFFFFFFFF
-#define SMU13_0_1_DRIVER_IF_VERSION_YELLOW_CARP 0x3
-
-/* MP Apertures */
-#define MP0_Public 0x03800000
-#define MP0_SRAM 0x03900000
-#define MP1_Public 0x03b00000
-#define MP1_SRAM 0x03c00004
-
-/* address block */
-#define smnMP1_FIRMWARE_FLAGS 0x3010024
-
-
-#if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3)
-
-int smu_v13_0_1_check_fw_status(struct smu_context *smu);
-
-int smu_v13_0_1_check_fw_version(struct smu_context *smu);
-
-int smu_v13_0_1_fini_smc_tables(struct smu_context *smu);
-
-int smu_v13_0_1_get_vbios_bootup_values(struct smu_context *smu);
-
-int smu_v13_0_1_set_default_dpm_tables(struct smu_context *smu);
-
-int smu_v13_0_1_set_driver_table_location(struct smu_context *smu);
-
-int smu_v13_0_1_gfx_off_control(struct smu_context *smu, bool enable);
-#endif
-#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index cb375f1beebd..ebe672142808 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -1453,10 +1453,14 @@ static int smu_hw_fini(void *handle)
if (smu->is_apu) {
smu_powergate_sdma(&adev->smu, true);
- smu_dpm_set_vcn_enable(smu, false);
- smu_dpm_set_jpeg_enable(smu, false);
}
+ smu_dpm_set_vcn_enable(smu, false);
+ smu_dpm_set_jpeg_enable(smu, false);
+
+ adev->vcn.cur_state = AMD_PG_STATE_GATE;
+ adev->jpeg.cur_state = AMD_PG_STATE_GATE;
+
if (!smu->pm_enabled)
return 0;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
index 388c5cb5c647..0a5d46ac9ccd 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
@@ -1528,6 +1528,7 @@ int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state)
case CHIP_SIENNA_CICHLID:
case CHIP_NAVY_FLOUNDER:
case CHIP_DIMGREY_CAVEFISH:
+ case CHIP_BEIGE_GOBY:
if (amdgpu_runtime_pm == 2)
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_EnterBaco,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile b/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile
index 9b3a8503f5cd..d4c4c495762c 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/Makefile
@@ -23,7 +23,7 @@
# Makefile for the 'smu manager' sub-component of powerplay.
# It provides the smu management services for the driver.
-SMU13_MGR = smu_v13_0.o aldebaran_ppt.o smu_v13_0_1.o yellow_carp_ppt.o
+SMU13_MGR = smu_v13_0.o aldebaran_ppt.o yellow_carp_ppt.o
AMD_SWSMU_SMU13MGR = $(addprefix $(AMD_SWSMU_PATH)/smu13/,$(SMU13_MGR))
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
index a3dc7194aaf8..a421ba85bd6d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
@@ -210,6 +210,9 @@ int smu_v13_0_check_fw_version(struct smu_context *smu)
case CHIP_ALDEBARAN:
smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_ALDE;
break;
+ case CHIP_YELLOW_CARP:
+ smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_YELLOW_CARP;
+ break;
default:
dev_err(smu->adev->dev, "smu unsupported asic type:%d.\n", smu->adev->asic_type);
smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_INV;
@@ -694,6 +697,27 @@ failed:
return ret;
}
+int smu_v13_0_gfx_off_control(struct smu_context *smu, bool enable)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = smu->adev;
+
+ switch (adev->asic_type) {
+ case CHIP_YELLOW_CARP:
+ if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))
+ return 0;
+ if (enable)
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_AllowGfxOff, NULL);
+ else
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_DisallowGfxOff, NULL);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
int smu_v13_0_system_features_control(struct smu_context *smu,
bool en)
{
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_1.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_1.c
deleted file mode 100644
index 61917b49f2bf..000000000000
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_1.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Copyright 2020 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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/reboot.h>
-
-#define SWSMU_CODE_LAYER_L3
-
-#include "amdgpu.h"
-#include "amdgpu_smu.h"
-#include "smu_v13_0_1.h"
-#include "soc15_common.h"
-#include "smu_cmn.h"
-#include "atomfirmware.h"
-#include "amdgpu_atomfirmware.h"
-#include "amdgpu_atombios.h"
-#include "atom.h"
-
-#include "asic_reg/mp/mp_13_0_1_offset.h"
-#include "asic_reg/mp/mp_13_0_1_sh_mask.h"
-
-/*
- * DO NOT use these for err/warn/info/debug messages.
- * Use dev_err, dev_warn, dev_info and dev_dbg instead.
- * They are more MGPU friendly.
- */
-#undef pr_err
-#undef pr_warn
-#undef pr_info
-#undef pr_debug
-
-int smu_v13_0_1_check_fw_status(struct smu_context *smu)
-{
- struct amdgpu_device *adev = smu->adev;
- uint32_t mp1_fw_flags;
-
- mp1_fw_flags = RREG32_PCIE(MP1_Public |
- (smnMP1_FIRMWARE_FLAGS & 0xffffffff));
-
- if ((mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >>
- MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT)
- return 0;
-
- return -EIO;
-}
-
-int smu_v13_0_1_check_fw_version(struct smu_context *smu)
-{
- uint32_t if_version = 0xff, smu_version = 0xff;
- uint16_t smu_major;
- uint8_t smu_minor, smu_debug;
- int ret = 0;
-
- ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version);
- if (ret)
- return ret;
-
- smu_major = (smu_version >> 16) & 0xffff;
- smu_minor = (smu_version >> 8) & 0xff;
- smu_debug = (smu_version >> 0) & 0xff;
-
- switch (smu->adev->asic_type) {
- case CHIP_YELLOW_CARP:
- smu->smc_driver_if_version = SMU13_0_1_DRIVER_IF_VERSION_YELLOW_CARP;
- break;
-
- default:
- dev_err(smu->adev->dev, "smu unsupported asic type:%d.\n", smu->adev->asic_type);
- smu->smc_driver_if_version = SMU13_0_1_DRIVER_IF_VERSION_INV;
- break;
- }
-
- dev_info(smu->adev->dev, "smu fw reported version = 0x%08x (%d.%d.%d)\n",
- smu_version, smu_major, smu_minor, smu_debug);
-
- /*
- * 1. if_version mismatch is not critical as our fw is designed
- * to be backward compatible.
- * 2. New fw usually brings some optimizations. But that's visible
- * only on the paired driver.
- * Considering above, we just leave user a warning message instead
- * of halt driver loading.
- */
- if (if_version != smu->smc_driver_if_version) {
- dev_info(smu->adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, "
- "smu fw version = 0x%08x (%d.%d.%d)\n",
- smu->smc_driver_if_version, if_version,
- smu_version, smu_major, smu_minor, smu_debug);
- dev_warn(smu->adev->dev, "SMU driver if version not matched\n");
- }
-
- return ret;
-}
-
-int smu_v13_0_1_fini_smc_tables(struct smu_context *smu)
-{
- struct smu_table_context *smu_table = &smu->smu_table;
-
- kfree(smu_table->clocks_table);
- smu_table->clocks_table = NULL;
-
- kfree(smu_table->metrics_table);
- smu_table->metrics_table = NULL;
-
- kfree(smu_table->watermarks_table);
- smu_table->watermarks_table = NULL;
-
- return 0;
-}
-
-static int smu_v13_0_1_atom_get_smu_clockinfo(struct amdgpu_device *adev,
- uint8_t clk_id,
- uint8_t syspll_id,
- uint32_t *clk_freq)
-{
- struct atom_get_smu_clock_info_parameters_v3_1 input = {0};
- struct atom_get_smu_clock_info_output_parameters_v3_1 *output;
- int ret, index;
-
- input.clk_id = clk_id;
- input.syspll_id = syspll_id;
- input.command = GET_SMU_CLOCK_INFO_V3_1_GET_CLOCK_FREQ;
- index = get_index_into_master_table(atom_master_list_of_command_functions_v2_1,
- getsmuclockinfo);
-
- ret = amdgpu_atom_execute_table(adev->mode_info.atom_context, index,
- (uint32_t *)&input);
- if (ret)
- return -EINVAL;
-
- output = (struct atom_get_smu_clock_info_output_parameters_v3_1 *)&input;
- *clk_freq = le32_to_cpu(output->atom_smu_outputclkfreq.smu_clock_freq_hz) / 10000;
-
- return 0;
-}
-
-int smu_v13_0_1_get_vbios_bootup_values(struct smu_context *smu)
-{
- int ret, index;
- uint16_t size;
- uint8_t frev, crev;
- struct atom_common_table_header *header;
- struct atom_firmware_info_v3_4 *v_3_4;
- struct atom_firmware_info_v3_3 *v_3_3;
- struct atom_firmware_info_v3_1 *v_3_1;
-
- index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
- firmwareinfo);
-
- ret = amdgpu_atombios_get_data_table(smu->adev, index, &size, &frev, &crev,
- (uint8_t **)&header);
- if (ret)
- return ret;
-
- if (header->format_revision != 3) {
- dev_err(smu->adev->dev, "unknown atom_firmware_info version! for smu13\n");
- return -EINVAL;
- }
-
- switch (header->content_revision) {
- case 0:
- case 1:
- case 2:
- v_3_1 = (struct atom_firmware_info_v3_1 *)header;
- smu->smu_table.boot_values.revision = v_3_1->firmware_revision;
- smu->smu_table.boot_values.gfxclk = v_3_1->bootup_sclk_in10khz;
- smu->smu_table.boot_values.uclk = v_3_1->bootup_mclk_in10khz;
- smu->smu_table.boot_values.socclk = 0;
- smu->smu_table.boot_values.dcefclk = 0;
- smu->smu_table.boot_values.vddc = v_3_1->bootup_vddc_mv;
- smu->smu_table.boot_values.vddci = v_3_1->bootup_vddci_mv;
- smu->smu_table.boot_values.mvddc = v_3_1->bootup_mvddc_mv;
- smu->smu_table.boot_values.vdd_gfx = v_3_1->bootup_vddgfx_mv;
- smu->smu_table.boot_values.cooling_id = v_3_1->coolingsolution_id;
- break;
- case 3:
- v_3_3 = (struct atom_firmware_info_v3_3 *)header;
- smu->smu_table.boot_values.revision = v_3_3->firmware_revision;
- smu->smu_table.boot_values.gfxclk = v_3_3->bootup_sclk_in10khz;
- smu->smu_table.boot_values.uclk = v_3_3->bootup_mclk_in10khz;
- smu->smu_table.boot_values.socclk = 0;
- smu->smu_table.boot_values.dcefclk = 0;
- smu->smu_table.boot_values.vddc = v_3_3->bootup_vddc_mv;
- smu->smu_table.boot_values.vddci = v_3_3->bootup_vddci_mv;
- smu->smu_table.boot_values.mvddc = v_3_3->bootup_mvddc_mv;
- smu->smu_table.boot_values.vdd_gfx = v_3_3->bootup_vddgfx_mv;
- smu->smu_table.boot_values.cooling_id = v_3_3->coolingsolution_id;
- break;
- case 4:
- default:
- v_3_4 = (struct atom_firmware_info_v3_4 *)header;
- smu->smu_table.boot_values.revision = v_3_4->firmware_revision;
- smu->smu_table.boot_values.gfxclk = v_3_4->bootup_sclk_in10khz;
- smu->smu_table.boot_values.uclk = v_3_4->bootup_mclk_in10khz;
- smu->smu_table.boot_values.socclk = 0;
- smu->smu_table.boot_values.dcefclk = 0;
- smu->smu_table.boot_values.vddc = v_3_4->bootup_vddc_mv;
- smu->smu_table.boot_values.vddci = v_3_4->bootup_vddci_mv;
- smu->smu_table.boot_values.mvddc = v_3_4->bootup_mvddc_mv;
- smu->smu_table.boot_values.vdd_gfx = v_3_4->bootup_vddgfx_mv;
- smu->smu_table.boot_values.cooling_id = v_3_4->coolingsolution_id;
- break;
- }
-
- smu->smu_table.boot_values.format_revision = header->format_revision;
- smu->smu_table.boot_values.content_revision = header->content_revision;
-
- smu_v13_0_1_atom_get_smu_clockinfo(smu->adev,
- (uint8_t)SMU11_SYSPLL0_SOCCLK_ID,
- (uint8_t)0,
- &smu->smu_table.boot_values.socclk);
-
- smu_v13_0_1_atom_get_smu_clockinfo(smu->adev,
- (uint8_t)SMU11_SYSPLL0_DCEFCLK_ID,
- (uint8_t)0,
- &smu->smu_table.boot_values.dcefclk);
-
- smu_v13_0_1_atom_get_smu_clockinfo(smu->adev,
- (uint8_t)SMU11_SYSPLL0_ECLK_ID,
- (uint8_t)0,
- &smu->smu_table.boot_values.eclk);
-
- smu_v13_0_1_atom_get_smu_clockinfo(smu->adev,
- (uint8_t)SMU11_SYSPLL0_VCLK_ID,
- (uint8_t)0,
- &smu->smu_table.boot_values.vclk);
-
- smu_v13_0_1_atom_get_smu_clockinfo(smu->adev,
- (uint8_t)SMU11_SYSPLL0_DCLK_ID,
- (uint8_t)0,
- &smu->smu_table.boot_values.dclk);
-
- if ((smu->smu_table.boot_values.format_revision == 3) &&
- (smu->smu_table.boot_values.content_revision >= 2))
- smu_v13_0_1_atom_get_smu_clockinfo(smu->adev,
- (uint8_t)SMU11_SYSPLL1_0_FCLK_ID,
- (uint8_t)SMU11_SYSPLL1_2_ID,
- &smu->smu_table.boot_values.fclk);
-
- return 0;
-}
-
-int smu_v13_0_1_set_default_dpm_tables(struct smu_context *smu)
-{
- struct smu_table_context *smu_table = &smu->smu_table;
-
- return smu_cmn_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false);
-}
-
-int smu_v13_0_1_set_driver_table_location(struct smu_context *smu)
-{
- struct smu_table *driver_table = &smu->smu_table.driver_table;
- int ret = 0;
-
- if (!driver_table->mc_address)
- return 0;
-
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetDriverDramAddrHigh,
- upper_32_bits(driver_table->mc_address),
- NULL);
-
- if (ret)
- return ret;
-
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetDriverDramAddrLow,
- lower_32_bits(driver_table->mc_address),
- NULL);
-
- return ret;
-}
-
-int smu_v13_0_1_gfx_off_control(struct smu_context *smu, bool enable)
-{
- int ret = 0;
- struct amdgpu_device *adev = smu->adev;
-
- switch (adev->asic_type) {
- case CHIP_YELLOW_CARP:
- if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))
- return 0;
- if (enable)
- ret = smu_cmn_send_smc_msg(smu, SMU_MSG_AllowGfxOff, NULL);
- else
- ret = smu_cmn_send_smc_msg(smu, SMU_MSG_DisallowGfxOff, NULL);
- break;
- default:
- break;
- }
-
- return ret;
-}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
index 7664334d8144..0cfeb9fc7c03 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
@@ -25,7 +25,7 @@
#include "amdgpu.h"
#include "amdgpu_smu.h"
-#include "smu_v13_0_1.h"
+#include "smu_v13_0.h"
#include "smu13_driver_if_yellow_carp.h"
#include "yellow_carp_ppt.h"
#include "smu_v13_0_1_ppsmc.h"
@@ -186,13 +186,30 @@ err0_out:
return -ENOMEM;
}
+static int yellow_carp_fini_smc_tables(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+
+ kfree(smu_table->clocks_table);
+ smu_table->clocks_table = NULL;
+
+ kfree(smu_table->metrics_table);
+ smu_table->metrics_table = NULL;
+
+ kfree(smu_table->watermarks_table);
+ smu_table->watermarks_table = NULL;
+
+ return 0;
+}
+
static int yellow_carp_system_features_control(struct smu_context *smu, bool en)
{
struct smu_feature *feature = &smu->smu_feature;
+ struct amdgpu_device *adev = smu->adev;
uint32_t feature_mask[2];
int ret = 0;
- if (!en)
+ if (!en && !adev->in_s0ix)
ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL);
bitmap_zero(feature->enabled, feature->feature_num);
@@ -281,13 +298,9 @@ static int yellow_carp_mode_reset(struct smu_context *smu, int type)
if (index < 0)
return index == -EACCES ? 0 : index;
- mutex_lock(&smu->message_lock);
-
- ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, type);
-
- mutex_unlock(&smu->message_lock);
-
- mdelay(10);
+ ret = smu_cmn_send_smc_msg_with_param(smu, (uint16_t)index, type, NULL);
+ if (ret)
+ dev_err(smu->adev->dev, "Failed to mode reset!\n");
return ret;
}
@@ -658,6 +671,13 @@ static ssize_t yellow_carp_get_gpu_metrics(struct smu_context *smu,
return sizeof(struct gpu_metrics_v2_1);
}
+static int yellow_carp_set_default_dpm_tables(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+
+ return smu_cmn_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false);
+}
+
static int yellow_carp_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type,
long input[], uint32_t size)
{
@@ -1202,17 +1222,17 @@ static int yellow_carp_set_fine_grain_gfx_freq_parameters(struct smu_context *sm
}
static const struct pptable_funcs yellow_carp_ppt_funcs = {
- .check_fw_status = smu_v13_0_1_check_fw_status,
- .check_fw_version = smu_v13_0_1_check_fw_version,
+ .check_fw_status = smu_v13_0_check_fw_status,
+ .check_fw_version = smu_v13_0_check_fw_version,
.init_smc_tables = yellow_carp_init_smc_tables,
- .fini_smc_tables = smu_v13_0_1_fini_smc_tables,
- .get_vbios_bootup_values = smu_v13_0_1_get_vbios_bootup_values,
+ .fini_smc_tables = yellow_carp_fini_smc_tables,
+ .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values,
.system_features_control = yellow_carp_system_features_control,
.send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
.send_smc_msg = smu_cmn_send_smc_msg,
.dpm_set_vcn_enable = yellow_carp_dpm_set_vcn_enable,
.dpm_set_jpeg_enable = yellow_carp_dpm_set_jpeg_enable,
- .set_default_dpm_table = smu_v13_0_1_set_default_dpm_tables,
+ .set_default_dpm_table = yellow_carp_set_default_dpm_tables,
.read_sensor = yellow_carp_read_sensor,
.is_dpm_running = yellow_carp_is_dpm_running,
.set_watermarks_table = yellow_carp_set_watermarks_table,
@@ -1221,8 +1241,8 @@ static const struct pptable_funcs yellow_carp_ppt_funcs = {
.get_gpu_metrics = yellow_carp_get_gpu_metrics,
.get_enabled_mask = smu_cmn_get_enabled_32_bits_mask,
.get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
- .set_driver_table_location = smu_v13_0_1_set_driver_table_location,
- .gfx_off_control = smu_v13_0_1_gfx_off_control,
+ .set_driver_table_location = smu_v13_0_set_driver_table_location,
+ .gfx_off_control = smu_v13_0_gfx_off_control,
.post_init = yellow_carp_post_smu_init,
.mode2_reset = yellow_carp_mode2_reset,
.get_dpm_ultimate_freq = yellow_carp_get_dpm_ultimate_freq,
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index 05ad75d155e8..cfe4fc69277e 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -232,7 +232,6 @@ static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
pm_runtime_put_sync(dev->dev);
- drm_crtc_vblank_on(c);
}
#define ATMEL_HLCDC_RGB444_OUTPUT BIT(0)
@@ -344,7 +343,16 @@ static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c,
static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c,
struct drm_atomic_state *state)
{
+ drm_crtc_vblank_on(c);
+}
+
+static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *c,
+ struct drm_atomic_state *state)
+{
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->dev->event_lock, flags);
if (c->state->event) {
c->state->event->pipe = drm_crtc_index(c);
@@ -354,12 +362,7 @@ static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c,
crtc->event = c->state->event;
c->state->event = NULL;
}
-}
-
-static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
-{
- /* TODO: write common plane control register if available */
+ spin_unlock_irqrestore(&c->dev->event_lock, flags);
}
static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index 65af56e47129..f09b6dd8754c 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -593,6 +593,7 @@ static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
dev->mode_config.max_width = dc->desc->max_width;
dev->mode_config.max_height = dc->desc->max_height;
dev->mode_config.funcs = &mode_config_funcs;
+ dev->mode_config.async_page_flip = true;
return 0;
}
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index ebe9dccf2d83..0b8648396fb2 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -352,6 +352,7 @@ static struct drm_framebuffer *psb_user_framebuffer_create
const struct drm_mode_fb_cmd2 *cmd)
{
struct drm_gem_object *obj;
+ struct drm_framebuffer *fb;
/*
* Find the GEM object and thus the gtt range object that is
@@ -362,7 +363,11 @@ static struct drm_framebuffer *psb_user_framebuffer_create
return ERR_PTR(-ENOENT);
/* Let the core code do all the work */
- return psb_framebuffer_create(dev, cmd, obj);
+ fb = psb_framebuffer_create(dev, cmd, obj);
+ if (IS_ERR(fb))
+ drm_gem_object_put(obj);
+
+ return fb;
}
static int psbfb_probe(struct drm_fb_helper *fb_helper,
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index b63d374dff23..f960f5d7664e 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -125,7 +125,7 @@ config DRM_I915_GVT_KVMGT
tristate "Enable KVM/VFIO support for Intel GVT-g"
depends on DRM_I915_GVT
depends on KVM
- depends on VFIO_MDEV && VFIO_MDEV_DEVICE
+ depends on VFIO_MDEV
default n
help
Choose this option if you want to enable KVMGT support for
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
index f4fb68e8955a..e382b7f2353b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
@@ -62,6 +62,7 @@ static void try_to_writeback(struct drm_i915_gem_object *obj,
switch (obj->mm.madv) {
case I915_MADV_DONTNEED:
i915_gem_object_truncate(obj);
+ return;
case __I915_MADV_PURGED:
return;
}
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
index 3a30955285d6..5575172c66f5 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
@@ -889,7 +889,7 @@ static int __igt_mmap(struct drm_i915_private *i915,
pr_debug("igt_mmap(%s, %d) @ %lx\n", obj->mm.region->name, type, addr);
- area = find_vma(current->mm, addr);
+ area = vma_lookup(current->mm, addr);
if (!area) {
pr_err("%s: Did not create a vm_area_struct for the mmap\n",
obj->mm.region->name);
diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c
index 21c8b7350b7a..da4f5eb43ac2 100644
--- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c
+++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c
@@ -303,10 +303,7 @@ static void __gen8_ppgtt_alloc(struct i915_address_space * const vm,
__i915_gem_object_pin_pages(pt->base);
i915_gem_object_make_unshrinkable(pt->base);
- if (lvl ||
- gen8_pt_count(*start, end) < I915_PDES ||
- intel_vgpu_active(vm->i915))
- fill_px(pt, vm->scratch[lvl]->encode);
+ fill_px(pt, vm->scratch[lvl]->encode);
spin_lock(&pd->lock);
if (likely(!pd->entry[idx])) {
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
index 9ceddfbb1687..7f03df236613 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
@@ -1279,7 +1279,7 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine)
return true;
/* Waiting to drain ELSP? */
- synchronize_hardirq(to_pci_dev(engine->i915->drm.dev)->irq);
+ intel_synchronize_hardirq(engine->i915);
intel_engine_flush_submission(engine);
/* ELSP is empty, but there are ready requests? E.g. after reset */
diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c b/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
index cac7f3f44642..f8948de72036 100644
--- a/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
+++ b/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
@@ -348,7 +348,7 @@ static struct i915_fence_reg *fence_find(struct i915_ggtt *ggtt)
if (intel_has_pending_fb_unpin(ggtt->vm.i915))
return ERR_PTR(-EAGAIN);
- return ERR_PTR(-EDEADLK);
+ return ERR_PTR(-ENOBUFS);
}
int __i915_vma_pin_fence(struct i915_vma *vma)
diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
index 0c423f096e2b..37d74d4ed59b 100644
--- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
@@ -184,8 +184,11 @@ static int xcs_resume(struct intel_engine_cs *engine)
ENGINE_TRACE(engine, "ring:{HEAD:%04x, TAIL:%04x}\n",
ring->head, ring->tail);
- /* Double check the ring is empty & disabled before we resume */
- synchronize_hardirq(engine->i915->drm.irq);
+ /*
+ * Double check the ring is empty & disabled before we resume. Called
+ * from atomic context during PCI probe, so _hardirq().
+ */
+ intel_synchronize_hardirq(engine->i915);
if (!stop_ring(engine))
goto err;
diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c
index 48b4d4cf805d..1ac98f8aba31 100644
--- a/drivers/gpu/drm/i915/gvt/kvmgt.c
+++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
@@ -88,6 +88,7 @@ struct kvmgt_pgfn {
struct hlist_node hnode;
};
+#define KVMGT_DEBUGFS_FILENAME "kvmgt_nr_cache_entries"
struct kvmgt_guest_info {
struct kvm *kvm;
struct intel_vgpu *vgpu;
@@ -95,7 +96,6 @@ struct kvmgt_guest_info {
#define NR_BKT (1 << 18)
struct hlist_head ptable[NR_BKT];
#undef NR_BKT
- struct dentry *debugfs_cache_entries;
};
struct gvt_dma {
@@ -1947,16 +1947,15 @@ static int kvmgt_guest_init(struct mdev_device *mdev)
info->track_node.track_flush_slot = kvmgt_page_track_flush_slot;
kvm_page_track_register_notifier(kvm, &info->track_node);
- info->debugfs_cache_entries = debugfs_create_ulong(
- "kvmgt_nr_cache_entries",
- 0444, vgpu->debugfs,
- &vdev->nr_cache_entries);
+ debugfs_create_ulong(KVMGT_DEBUGFS_FILENAME, 0444, vgpu->debugfs,
+ &vdev->nr_cache_entries);
return 0;
}
static bool kvmgt_guest_exit(struct kvmgt_guest_info *info)
{
- debugfs_remove(info->debugfs_cache_entries);
+ debugfs_remove(debugfs_lookup(KVMGT_DEBUGFS_FILENAME,
+ info->vgpu->debugfs));
kvm_page_track_unregister_notifier(info->kvm, &info->track_node);
kvm_put_kvm(info->kvm);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 850b499c71c8..73de45472f60 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -42,7 +42,6 @@
#include <drm/drm_aperture.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_ioctl.h>
-#include <drm/drm_irq.h>
#include <drm/drm_managed.h>
#include <drm/drm_probe_helper.h>
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 3cb0a65a996b..47b484976919 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -33,7 +33,6 @@
#include <linux/sysrq.h>
#include <drm/drm_drv.h>
-#include <drm/drm_irq.h>
#include "display/intel_de.h"
#include "display/intel_display_types.h"
@@ -4564,10 +4563,6 @@ void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv)
bool intel_irqs_enabled(struct drm_i915_private *dev_priv)
{
- /*
- * We only use drm_irq_uninstall() at unload and VT switch, so
- * this is the only thing we need to check.
- */
return dev_priv->runtime_pm.irqs_enabled;
}
@@ -4575,3 +4570,8 @@ void intel_synchronize_irq(struct drm_i915_private *i915)
{
synchronize_irq(to_pci_dev(i915->drm.dev)->irq);
}
+
+void intel_synchronize_hardirq(struct drm_i915_private *i915)
+{
+ synchronize_hardirq(to_pci_dev(i915->drm.dev)->irq);
+}
diff --git a/drivers/gpu/drm/i915/i915_irq.h b/drivers/gpu/drm/i915/i915_irq.h
index db34d5dbe402..e43b6734f21b 100644
--- a/drivers/gpu/drm/i915/i915_irq.h
+++ b/drivers/gpu/drm/i915/i915_irq.h
@@ -94,6 +94,7 @@ void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv);
void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv);
bool intel_irqs_enabled(struct drm_i915_private *dev_priv);
void intel_synchronize_irq(struct drm_i915_private *i915);
+void intel_synchronize_hardirq(struct drm_i915_private *i915);
int intel_get_crtc_scanline(struct intel_crtc *crtc);
void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c
index f64e06e1067d..96ea1a2c11dd 100644
--- a/drivers/gpu/drm/kmb/kmb_drv.c
+++ b/drivers/gpu/drm/kmb/kmb_drv.c
@@ -137,6 +137,7 @@ static int kmb_hw_init(struct drm_device *drm, unsigned long flags)
/* Allocate LCD interrupt resources */
irq_lcd = platform_get_irq(pdev, 0);
if (irq_lcd < 0) {
+ ret = irq_lcd;
drm_err(&kmb->drm, "irq_lcd not found");
goto setup_fail;
}
diff --git a/drivers/gpu/drm/lima/lima_trace.h b/drivers/gpu/drm/lima/lima_trace.h
index 3a430e93d384..494b9790b1da 100644
--- a/drivers/gpu/drm/lima/lima_trace.h
+++ b/drivers/gpu/drm/lima/lima_trace.h
@@ -24,7 +24,7 @@ DECLARE_EVENT_CLASS(lima_task,
__entry->task_id = task->base.id;
__entry->context = task->base.s_fence->finished.context;
__entry->seqno = task->base.s_fence->finished.seqno;
- __assign_str(pipe, task->base.sched->name)
+ __assign_str(pipe, task->base.sched->name);
),
TP_printk("task=%llu, context=%u seqno=%u pipe=%s",
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 141178754231..1e8a971a86f2 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -1169,7 +1169,7 @@ static int msm_gem_new_impl(struct drm_device *dev,
case MSM_BO_CACHED_COHERENT:
if (priv->has_cached_coherent)
break;
- /* fallthrough */
+ fallthrough;
default:
DRM_DEV_ERROR(dev->dev, "invalid cache flag: %x\n",
(flags & MSM_BO_CACHE_MASK));
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if000c.h b/drivers/gpu/drm/nouveau/include/nvif/if000c.h
index d6dd40f21eed..9c7ff56831c5 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/if000c.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/if000c.h
@@ -77,6 +77,7 @@ struct nvif_vmm_pfnmap_v0 {
#define NVIF_VMM_PFNMAP_V0_APER 0x00000000000000f0ULL
#define NVIF_VMM_PFNMAP_V0_HOST 0x0000000000000000ULL
#define NVIF_VMM_PFNMAP_V0_VRAM 0x0000000000000010ULL
+#define NVIF_VMM_PFNMAP_V0_A 0x0000000000000004ULL
#define NVIF_VMM_PFNMAP_V0_W 0x0000000000000002ULL
#define NVIF_VMM_PFNMAP_V0_V 0x0000000000000001ULL
#define NVIF_VMM_PFNMAP_V0_NONE 0x0000000000000000ULL
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 520b1ea9d16c..4f3a5357dd56 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -439,6 +439,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t domain, bool contig)
break;
case TTM_PL_TT:
error |= !(domain & NOUVEAU_GEM_DOMAIN_GART);
+ break;
default:
break;
}
@@ -545,7 +546,7 @@ nouveau_bo_sync_for_device(struct nouveau_bo *nvbo)
struct ttm_tt *ttm_dma = (struct ttm_tt *)nvbo->bo.ttm;
int i, j;
- if (!ttm_dma)
+ if (!ttm_dma || !ttm_dma->dma_address)
return;
if (!ttm_dma->pages) {
NV_DEBUG(drm, "ttm_dma 0x%p: pages NULL\n", ttm_dma);
@@ -581,7 +582,7 @@ nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
struct ttm_tt *ttm_dma = (struct ttm_tt *)nvbo->bo.ttm;
int i, j;
- if (!ttm_dma)
+ if (!ttm_dma || !ttm_dma->dma_address)
return;
if (!ttm_dma->pages) {
NV_DEBUG(drm, "ttm_dma 0x%p: pages NULL\n", ttm_dma);
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 2a298c171d4d..22b83a6577eb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -157,6 +157,7 @@ nouveau_conn_atomic_set_property(struct drm_connector *connector,
default:
break;
}
+ break;
case DRM_MODE_SCALE_FULLSCREEN:
case DRM_MODE_SCALE_CENTER:
case DRM_MODE_SCALE_ASPECT:
diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c
index 347488685f74..60019d0532fc 100644
--- a/drivers/gpu/drm/nouveau/nouveau_prime.c
+++ b/drivers/gpu/drm/nouveau/nouveau_prime.c
@@ -93,7 +93,22 @@ int nouveau_gem_prime_pin(struct drm_gem_object *obj)
if (ret)
return -EINVAL;
- return 0;
+ ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL);
+ if (ret)
+ goto error;
+
+ if (nvbo->bo.moving)
+ ret = dma_fence_wait(nvbo->bo.moving, true);
+
+ ttm_bo_unreserve(&nvbo->bo);
+ if (ret)
+ goto error;
+
+ return ret;
+
+error:
+ nouveau_bo_unpin(nvbo);
+ return ret;
}
void nouveau_gem_prime_unpin(struct drm_gem_object *obj)
diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c
index 1c3f890377d2..82b583f5fca8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_svm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_svm.c
@@ -35,6 +35,7 @@
#include <linux/sched/mm.h>
#include <linux/sort.h>
#include <linux/hmm.h>
+#include <linux/rmap.h>
struct nouveau_svm {
struct nouveau_drm *drm;
@@ -67,6 +68,11 @@ struct nouveau_svm {
} buffer[1];
};
+#define FAULT_ACCESS_READ 0
+#define FAULT_ACCESS_WRITE 1
+#define FAULT_ACCESS_ATOMIC 2
+#define FAULT_ACCESS_PREFETCH 3
+
#define SVM_DBG(s,f,a...) NV_DEBUG((s)->drm, "svm: "f"\n", ##a)
#define SVM_ERR(s,f,a...) NV_WARN((s)->drm, "svm: "f"\n", ##a)
@@ -265,7 +271,7 @@ nouveau_svmm_invalidate_range_start(struct mmu_notifier *mn,
* the invalidation is handled as part of the migration process.
*/
if (update->event == MMU_NOTIFY_MIGRATE &&
- update->migrate_pgmap_owner == svmm->vmm->cli->drm->dev)
+ update->owner == svmm->vmm->cli->drm->dev)
goto out;
if (limit > svmm->unmanaged.start && start < svmm->unmanaged.limit) {
@@ -412,6 +418,24 @@ nouveau_svm_fault_cancel_fault(struct nouveau_svm *svm,
}
static int
+nouveau_svm_fault_priority(u8 fault)
+{
+ switch (fault) {
+ case FAULT_ACCESS_PREFETCH:
+ return 0;
+ case FAULT_ACCESS_READ:
+ return 1;
+ case FAULT_ACCESS_WRITE:
+ return 2;
+ case FAULT_ACCESS_ATOMIC:
+ return 3;
+ default:
+ WARN_ON_ONCE(1);
+ return -1;
+ }
+}
+
+static int
nouveau_svm_fault_cmp(const void *a, const void *b)
{
const struct nouveau_svm_fault *fa = *(struct nouveau_svm_fault **)a;
@@ -421,9 +445,8 @@ nouveau_svm_fault_cmp(const void *a, const void *b)
return ret;
if ((ret = (s64)fa->addr - fb->addr))
return ret;
- /*XXX: atomic? */
- return (fa->access == 0 || fa->access == 3) -
- (fb->access == 0 || fb->access == 3);
+ return nouveau_svm_fault_priority(fa->access) -
+ nouveau_svm_fault_priority(fb->access);
}
static void
@@ -487,6 +510,10 @@ static bool nouveau_svm_range_invalidate(struct mmu_interval_notifier *mni,
struct svm_notifier *sn =
container_of(mni, struct svm_notifier, notifier);
+ if (range->event == MMU_NOTIFY_EXCLUSIVE &&
+ range->owner == sn->svmm->vmm->cli->drm->dev)
+ return true;
+
/*
* serializes the update to mni->invalidate_seq done by caller and
* prevents invalidation of the PTE from progressing while HW is being
@@ -555,6 +582,71 @@ static void nouveau_hmm_convert_pfn(struct nouveau_drm *drm,
args->p.phys[0] |= NVIF_VMM_PFNMAP_V0_W;
}
+static int nouveau_atomic_range_fault(struct nouveau_svmm *svmm,
+ struct nouveau_drm *drm,
+ struct nouveau_pfnmap_args *args, u32 size,
+ struct svm_notifier *notifier)
+{
+ unsigned long timeout =
+ jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
+ struct mm_struct *mm = svmm->notifier.mm;
+ struct page *page;
+ unsigned long start = args->p.addr;
+ unsigned long notifier_seq;
+ int ret = 0;
+
+ ret = mmu_interval_notifier_insert(&notifier->notifier, mm,
+ args->p.addr, args->p.size,
+ &nouveau_svm_mni_ops);
+ if (ret)
+ return ret;
+
+ while (true) {
+ if (time_after(jiffies, timeout)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ notifier_seq = mmu_interval_read_begin(&notifier->notifier);
+ mmap_read_lock(mm);
+ ret = make_device_exclusive_range(mm, start, start + PAGE_SIZE,
+ &page, drm->dev);
+ mmap_read_unlock(mm);
+ if (ret <= 0 || !page) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ mutex_lock(&svmm->mutex);
+ if (!mmu_interval_read_retry(&notifier->notifier,
+ notifier_seq))
+ break;
+ mutex_unlock(&svmm->mutex);
+ }
+
+ /* Map the page on the GPU. */
+ args->p.page = 12;
+ args->p.size = PAGE_SIZE;
+ args->p.addr = start;
+ args->p.phys[0] = page_to_phys(page) |
+ NVIF_VMM_PFNMAP_V0_V |
+ NVIF_VMM_PFNMAP_V0_W |
+ NVIF_VMM_PFNMAP_V0_A |
+ NVIF_VMM_PFNMAP_V0_HOST;
+
+ svmm->vmm->vmm.object.client->super = true;
+ ret = nvif_object_ioctl(&svmm->vmm->vmm.object, args, size, NULL);
+ svmm->vmm->vmm.object.client->super = false;
+ mutex_unlock(&svmm->mutex);
+
+ unlock_page(page);
+ put_page(page);
+
+out:
+ mmu_interval_notifier_remove(&notifier->notifier);
+ return ret;
+}
+
static int nouveau_range_fault(struct nouveau_svmm *svmm,
struct nouveau_drm *drm,
struct nouveau_pfnmap_args *args, u32 size,
@@ -567,18 +659,27 @@ static int nouveau_range_fault(struct nouveau_svmm *svmm,
unsigned long hmm_pfns[1];
struct hmm_range range = {
.notifier = &notifier->notifier,
- .start = notifier->notifier.interval_tree.start,
- .end = notifier->notifier.interval_tree.last + 1,
.default_flags = hmm_flags,
.hmm_pfns = hmm_pfns,
.dev_private_owner = drm->dev,
};
- struct mm_struct *mm = notifier->notifier.mm;
+ struct mm_struct *mm = svmm->notifier.mm;
int ret;
+ ret = mmu_interval_notifier_insert(&notifier->notifier, mm,
+ args->p.addr, args->p.size,
+ &nouveau_svm_mni_ops);
+ if (ret)
+ return ret;
+
+ range.start = notifier->notifier.interval_tree.start;
+ range.end = notifier->notifier.interval_tree.last + 1;
+
while (true) {
- if (time_after(jiffies, timeout))
- return -EBUSY;
+ if (time_after(jiffies, timeout)) {
+ ret = -EBUSY;
+ goto out;
+ }
range.notifier_seq = mmu_interval_read_begin(range.notifier);
mmap_read_lock(mm);
@@ -587,7 +688,7 @@ static int nouveau_range_fault(struct nouveau_svmm *svmm,
if (ret) {
if (ret == -EBUSY)
continue;
- return ret;
+ goto out;
}
mutex_lock(&svmm->mutex);
@@ -606,6 +707,9 @@ static int nouveau_range_fault(struct nouveau_svmm *svmm,
svmm->vmm->vmm.object.client->super = false;
mutex_unlock(&svmm->mutex);
+out:
+ mmu_interval_notifier_remove(&notifier->notifier);
+
return ret;
}
@@ -625,7 +729,7 @@ nouveau_svm_fault(struct nvif_notify *notify)
unsigned long hmm_flags;
u64 inst, start, limit;
int fi, fn;
- int replay = 0, ret;
+ int replay = 0, atomic = 0, ret;
/* Parse available fault buffer entries into a cache, and update
* the GET pointer so HW can reuse the entries.
@@ -706,12 +810,14 @@ nouveau_svm_fault(struct nvif_notify *notify)
/*
* Determine required permissions based on GPU fault
* access flags.
- * XXX: atomic?
*/
switch (buffer->fault[fi]->access) {
case 0: /* READ. */
hmm_flags = HMM_PFN_REQ_FAULT;
break;
+ case 2: /* ATOMIC. */
+ atomic = true;
+ break;
case 3: /* PREFETCH. */
hmm_flags = 0;
break;
@@ -727,14 +833,14 @@ nouveau_svm_fault(struct nvif_notify *notify)
}
notifier.svmm = svmm;
- ret = mmu_interval_notifier_insert(&notifier.notifier, mm,
- args.i.p.addr, args.i.p.size,
- &nouveau_svm_mni_ops);
- if (!ret) {
+ if (atomic)
+ ret = nouveau_atomic_range_fault(svmm, svm->drm,
+ &args.i, sizeof(args),
+ &notifier);
+ else
ret = nouveau_range_fault(svmm, svm->drm, &args.i,
- sizeof(args), hmm_flags, &notifier);
- mmu_interval_notifier_remove(&notifier.notifier);
- }
+ sizeof(args), hmm_flags,
+ &notifier);
mmput(mm);
limit = args.i.p.addr + args.i.p.size;
@@ -750,11 +856,15 @@ nouveau_svm_fault(struct nvif_notify *notify)
*/
if (buffer->fault[fn]->svmm != svmm ||
buffer->fault[fn]->addr >= limit ||
- (buffer->fault[fi]->access == 0 /* READ. */ &&
+ (buffer->fault[fi]->access == FAULT_ACCESS_READ &&
!(args.phys[0] & NVIF_VMM_PFNMAP_V0_V)) ||
- (buffer->fault[fi]->access != 0 /* READ. */ &&
- buffer->fault[fi]->access != 3 /* PREFETCH. */ &&
- !(args.phys[0] & NVIF_VMM_PFNMAP_V0_W)))
+ (buffer->fault[fi]->access != FAULT_ACCESS_READ &&
+ buffer->fault[fi]->access != FAULT_ACCESS_PREFETCH &&
+ !(args.phys[0] & NVIF_VMM_PFNMAP_V0_W)) ||
+ (buffer->fault[fi]->access != FAULT_ACCESS_READ &&
+ buffer->fault[fi]->access != FAULT_ACCESS_WRITE &&
+ buffer->fault[fi]->access != FAULT_ACCESS_PREFETCH &&
+ !(args.phys[0] & NVIF_VMM_PFNMAP_V0_A)))
break;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c
index 83067763c0ec..e1d31c62f9ec 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c
@@ -313,6 +313,7 @@ nv50_clk_read(struct nvkm_clk *base, enum nv_clk_src src)
default:
break;
}
+ break;
default:
break;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h
index a2b179568970..f6188aa9171c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.h
@@ -178,6 +178,7 @@ void nvkm_vmm_unmap_region(struct nvkm_vmm *, struct nvkm_vma *);
#define NVKM_VMM_PFN_APER 0x00000000000000f0ULL
#define NVKM_VMM_PFN_HOST 0x0000000000000000ULL
#define NVKM_VMM_PFN_VRAM 0x0000000000000010ULL
+#define NVKM_VMM_PFN_A 0x0000000000000004ULL
#define NVKM_VMM_PFN_W 0x0000000000000002ULL
#define NVKM_VMM_PFN_V 0x0000000000000001ULL
#define NVKM_VMM_PFN_NONE 0x0000000000000000ULL
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
index 236db5570771..f02abd9cb4dd 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c
@@ -88,6 +88,9 @@ gp100_vmm_pgt_pfn(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
if (!(*map->pfn & NVKM_VMM_PFN_W))
data |= BIT_ULL(6); /* RO. */
+ if (!(*map->pfn & NVKM_VMM_PFN_A))
+ data |= BIT_ULL(7); /* Atomic disable. */
+
if (!(*map->pfn & NVKM_VMM_PFN_VRAM)) {
addr = *map->pfn >> NVKM_VMM_PFN_ADDR_SHIFT;
addr = dma_map_page(dev, pfn_to_page(addr), 0,
@@ -322,6 +325,9 @@ gp100_vmm_pd0_pfn(struct nvkm_vmm *vmm, struct nvkm_mmu_pt *pt,
if (!(*map->pfn & NVKM_VMM_PFN_W))
data |= BIT_ULL(6); /* RO. */
+ if (!(*map->pfn & NVKM_VMM_PFN_A))
+ data |= BIT_ULL(7); /* Atomic disable. */
+
if (!(*map->pfn & NVKM_VMM_PFN_VRAM)) {
addr = *map->pfn >> NVKM_VMM_PFN_ADDR_SHIFT;
addr = dma_map_page(dev, pfn_to_page(addr), 0,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c
index 2b031d4eaeb6..684aff7437ee 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c
@@ -41,6 +41,7 @@ pwm_info(struct nvkm_therm *therm, int line)
default:
break;
}
+ break;
default:
break;
}
diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35510.c b/drivers/gpu/drm/panel/panel-novatek-nt35510.c
index ef70140c5b09..873cbd38e6d3 100644
--- a/drivers/gpu/drm/panel/panel-novatek-nt35510.c
+++ b/drivers/gpu/drm/panel/panel-novatek-nt35510.c
@@ -706,9 +706,7 @@ static int nt35510_power_on(struct nt35510 *nt)
if (ret)
return ret;
- ret = nt35510_read_id(nt);
- if (ret)
- return ret;
+ nt35510_read_id(nt);
/* Set up stuff in manufacturer control, page 1 */
ret = nt35510_send_long(nt, dsi, MCS_CMD_MAUCCTR,
diff --git a/drivers/gpu/drm/panel/panel-samsung-ld9040.c b/drivers/gpu/drm/panel/panel-samsung-ld9040.c
index f484147fc3a6..c4b388850a13 100644
--- a/drivers/gpu/drm/panel/panel-samsung-ld9040.c
+++ b/drivers/gpu/drm/panel/panel-samsung-ld9040.c
@@ -383,6 +383,7 @@ MODULE_DEVICE_TABLE(spi, ld9040_ids);
static struct spi_driver ld9040_driver = {
.probe = ld9040_probe,
.remove = ld9040_remove,
+ .id_table = ld9040_ids,
.driver = {
.name = "panel-samsung-ld9040",
.of_match_table = ld9040_of_match,
diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c
index 19fd39d9a00c..37a1b6a6ad6d 100644
--- a/drivers/gpu/drm/qxl/qxl_ttm.c
+++ b/drivers/gpu/drm/qxl/qxl_ttm.c
@@ -127,7 +127,7 @@ static void qxl_bo_move_notify(struct ttm_buffer_object *bo,
struct qxl_bo *qbo;
struct qxl_device *qdev;
- if (!qxl_ttm_bo_is_qxl_bo(bo))
+ if (!qxl_ttm_bo_is_qxl_bo(bo) || !bo->resource)
return;
qbo = to_qxl_bo(bo);
qdev = to_qxl(qbo->tbo.base.dev);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 406681317419..573154268d43 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -1325,6 +1325,7 @@ radeon_user_framebuffer_create(struct drm_device *dev,
/* Handle is imported dma-buf, so cannot be migrated to VRAM for scanout */
if (obj->import_attach) {
DRM_DEBUG_KMS("Cannot create framebuffer from imported dma_buf\n");
+ drm_gem_object_put(obj);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 8cd135fa6dcd..5c23b77cb81a 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -374,13 +374,13 @@ radeon_pci_shutdown(struct pci_dev *pdev)
if (radeon_device_is_virtual())
radeon_pci_remove(pdev);
-#ifdef CONFIG_PPC64
+#if defined(CONFIG_PPC64) || defined(CONFIG_MACH_LOONGSON64)
/*
* Some adapters need to be suspended before a
* shutdown occurs in order to prevent an error
- * during kexec.
- * Make this power specific becauase it breaks
- * some non-power boards.
+ * during kexec, shutdown or reboot.
+ * Make this power and Loongson specific because
+ * it breaks some other boards.
*/
radeon_suspend_kms(pci_get_drvdata(pdev), true, true, false);
#endif
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index bfaaa3c969a3..56ede9d63b12 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -49,23 +49,23 @@ static void radeon_bo_clear_surface_reg(struct radeon_bo *bo);
* function are calling it.
*/
-static void radeon_update_memory_usage(struct radeon_bo *bo,
- unsigned mem_type, int sign)
+static void radeon_update_memory_usage(struct ttm_buffer_object *bo,
+ unsigned int mem_type, int sign)
{
- struct radeon_device *rdev = bo->rdev;
+ struct radeon_device *rdev = radeon_get_rdev(bo->bdev);
switch (mem_type) {
case TTM_PL_TT:
if (sign > 0)
- atomic64_add(bo->tbo.base.size, &rdev->gtt_usage);
+ atomic64_add(bo->base.size, &rdev->gtt_usage);
else
- atomic64_sub(bo->tbo.base.size, &rdev->gtt_usage);
+ atomic64_sub(bo->base.size, &rdev->gtt_usage);
break;
case TTM_PL_VRAM:
if (sign > 0)
- atomic64_add(bo->tbo.base.size, &rdev->vram_usage);
+ atomic64_add(bo->base.size, &rdev->vram_usage);
else
- atomic64_sub(bo->tbo.base.size, &rdev->vram_usage);
+ atomic64_sub(bo->base.size, &rdev->vram_usage);
break;
}
}
@@ -76,8 +76,6 @@ static void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo)
bo = container_of(tbo, struct radeon_bo, tbo);
- radeon_update_memory_usage(bo, bo->tbo.resource->mem_type, -1);
-
mutex_lock(&bo->rdev->gem.mutex);
list_del_init(&bo->list);
mutex_unlock(&bo->rdev->gem.mutex);
@@ -727,24 +725,21 @@ int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
}
void radeon_bo_move_notify(struct ttm_buffer_object *bo,
- bool evict,
+ unsigned int old_type,
struct ttm_resource *new_mem)
{
struct radeon_bo *rbo;
+ radeon_update_memory_usage(bo, old_type, -1);
+ if (new_mem)
+ radeon_update_memory_usage(bo, new_mem->mem_type, 1);
+
if (!radeon_ttm_bo_is_radeon_bo(bo))
return;
rbo = container_of(bo, struct radeon_bo, tbo);
radeon_bo_check_tiling(rbo, 0, 1);
radeon_vm_bo_invalidate(rbo->rdev, rbo);
-
- /* update statistics */
- if (!new_mem)
- return;
-
- radeon_update_memory_usage(rbo, bo->resource->mem_type, -1);
- radeon_update_memory_usage(rbo, new_mem->mem_type, 1);
}
vm_fault_t radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h
index 1739c6a142cd..1afc7992ef91 100644
--- a/drivers/gpu/drm/radeon/radeon_object.h
+++ b/drivers/gpu/drm/radeon/radeon_object.h
@@ -161,7 +161,7 @@ extern void radeon_bo_get_tiling_flags(struct radeon_bo *bo,
extern int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
bool force_drop);
extern void radeon_bo_move_notify(struct ttm_buffer_object *bo,
- bool evict,
+ unsigned int old_type,
struct ttm_resource *new_mem);
extern vm_fault_t radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
extern int radeon_bo_get_surface_reg(struct radeon_bo *bo);
diff --git a/drivers/gpu/drm/radeon/radeon_prime.c b/drivers/gpu/drm/radeon/radeon_prime.c
index 42a87948e28c..4a90807351e7 100644
--- a/drivers/gpu/drm/radeon/radeon_prime.c
+++ b/drivers/gpu/drm/radeon/radeon_prime.c
@@ -77,9 +77,19 @@ int radeon_gem_prime_pin(struct drm_gem_object *obj)
/* pin buffer into GTT */
ret = radeon_bo_pin(bo, RADEON_GEM_DOMAIN_GTT, NULL);
- if (likely(ret == 0))
- bo->prime_shared_count++;
-
+ if (unlikely(ret))
+ goto error;
+
+ if (bo->tbo.moving) {
+ ret = dma_fence_wait(bo->tbo.moving, false);
+ if (unlikely(ret)) {
+ radeon_bo_unpin(bo);
+ goto error;
+ }
+ }
+
+ bo->prime_shared_count++;
+error:
radeon_bo_unreserve(bo);
return ret;
}
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index ad2a5a791bba..a06d4cc2fb1c 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -199,7 +199,7 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, bool evict,
struct ttm_resource *old_mem = bo->resource;
struct radeon_device *rdev;
struct radeon_bo *rbo;
- int r;
+ int r, old_type;
if (new_mem->mem_type == TTM_PL_TT) {
r = radeon_ttm_tt_bind(bo->bdev, bo->ttm, new_mem);
@@ -216,6 +216,9 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, bool evict,
if (WARN_ON_ONCE(rbo->tbo.pin_count > 0))
return -EINVAL;
+ /* Save old type for statistics update */
+ old_type = old_mem->mem_type;
+
rdev = radeon_get_rdev(bo->bdev);
if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
ttm_bo_move_null(bo, new_mem);
@@ -261,7 +264,7 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, bool evict,
out:
/* update statistics */
atomic64_add(bo->base.size, &rdev->num_bytes_moved);
- radeon_bo_move_notify(bo, evict, new_mem);
+ radeon_bo_move_notify(bo, old_type, new_mem);
return 0;
}
@@ -682,7 +685,11 @@ bool radeon_ttm_tt_is_readonly(struct radeon_device *rdev,
static void
radeon_bo_delete_mem_notify(struct ttm_buffer_object *bo)
{
- radeon_bo_move_notify(bo, false, NULL);
+ unsigned int old_type = TTM_PL_SYSTEM;
+
+ if (bo->resource)
+ old_type = bo->resource->mem_type;
+ radeon_bo_move_notify(bo, old_type, NULL);
}
static struct ttm_device_funcs radeon_bo_driver = {
diff --git a/drivers/gpu/drm/ttm/ttm_range_manager.c b/drivers/gpu/drm/ttm/ttm_range_manager.c
index 03395386e8a7..f4b08a8705b3 100644
--- a/drivers/gpu/drm/ttm/ttm_range_manager.c
+++ b/drivers/gpu/drm/ttm/ttm_range_manager.c
@@ -181,6 +181,9 @@ int ttm_range_man_fini(struct ttm_device *bdev,
struct drm_mm *mm = &rman->mm;
int ret;
+ if (!man)
+ return 0;
+
ttm_resource_manager_set_used(man, false);
ret = ttm_resource_manager_evict_all(bdev, man);
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 3c4cc133e3df..aab1b36ceb3c 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -166,6 +166,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
bool connected = false;
+ WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
+
if (vc4_hdmi->hpd_gpio &&
gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) {
connected = true;
@@ -186,10 +188,12 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
}
}
+ pm_runtime_put(&vc4_hdmi->pdev->dev);
return connector_status_connected;
}
cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
+ pm_runtime_put(&vc4_hdmi->pdev->dev);
return connector_status_disconnected;
}
@@ -631,7 +635,6 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
clk_disable_unprepare(vc4_hdmi->pixel_bvb_clock);
- clk_disable_unprepare(vc4_hdmi->hsm_clock);
clk_disable_unprepare(vc4_hdmi->pixel_clock);
ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
@@ -942,13 +945,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
return;
}
- ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
- if (ret) {
- DRM_ERROR("Failed to turn on HSM clock: %d\n", ret);
- clk_disable_unprepare(vc4_hdmi->pixel_clock);
- return;
- }
-
vc4_hdmi_cec_update_clk_div(vc4_hdmi);
if (pixel_rate > 297000000)
@@ -961,7 +957,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
ret = clk_set_min_rate(vc4_hdmi->pixel_bvb_clock, bvb_rate);
if (ret) {
DRM_ERROR("Failed to set pixel bvb clock rate: %d\n", ret);
- clk_disable_unprepare(vc4_hdmi->hsm_clock);
clk_disable_unprepare(vc4_hdmi->pixel_clock);
return;
}
@@ -969,7 +964,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
ret = clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
if (ret) {
DRM_ERROR("Failed to turn on pixel bvb clock: %d\n", ret);
- clk_disable_unprepare(vc4_hdmi->hsm_clock);
clk_disable_unprepare(vc4_hdmi->pixel_clock);
return;
}
@@ -2096,6 +2090,29 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
return 0;
}
+#ifdef CONFIG_PM
+static int vc4_hdmi_runtime_suspend(struct device *dev)
+{
+ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(vc4_hdmi->hsm_clock);
+
+ return 0;
+}
+
+static int vc4_hdmi_runtime_resume(struct device *dev)
+{
+ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+#endif
+
static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
{
const struct vc4_hdmi_variant *variant = of_device_get_match_data(dev);
@@ -2343,11 +2360,18 @@ static const struct of_device_id vc4_hdmi_dt_match[] = {
{}
};
+static const struct dev_pm_ops vc4_hdmi_pm_ops = {
+ SET_RUNTIME_PM_OPS(vc4_hdmi_runtime_suspend,
+ vc4_hdmi_runtime_resume,
+ NULL)
+};
+
struct platform_driver vc4_hdmi_driver = {
.probe = vc4_hdmi_dev_probe,
.remove = vc4_hdmi_dev_remove,
.driver = {
.name = "vc4_hdmi",
.of_match_table = vc4_hdmi_dt_match,
+ .pm = &vc4_hdmi_pm_ops,
},
};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 6f5ea00973e0..45aeeca9b8f6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -36,6 +36,7 @@
#include <drm/drm_ioctl.h>
#include <drm/drm_sysfs.h>
#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_range_manager.h>
#include <drm/ttm/ttm_placement.h>
#include <generated/utsrelease.h>
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
index 5648664f71bc..f2d625415458 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
@@ -354,7 +354,6 @@ static void vmw_otable_batch_takedown(struct vmw_private *dev_priv,
ttm_bo_unpin(bo);
ttm_bo_unreserve(bo);
- ttm_bo_unpin(batch->otable_bo);
ttm_bo_put(batch->otable_bo);
batch->otable_bo = NULL;
}
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c
index 3589d9945da1..efb849411d25 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c
@@ -77,6 +77,7 @@ int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type)
static void amd_sfh_work(struct work_struct *work)
{
struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work.work);
+ struct amd_input_data *in_data = cli_data->in_data;
struct request_list *req_node;
u8 current_index, sensor_index;
u8 report_id, node_type;
@@ -101,13 +102,11 @@ static void amd_sfh_work(struct work_struct *work)
pr_err("AMDSFH: Invalid report size\n");
} else if (node_type == HID_INPUT_REPORT) {
- report_size = get_input_report(sensor_index, report_id,
- cli_data->input_report[current_index],
- cli_data->sensor_virt_addr[current_index]);
+ report_size = get_input_report(current_index, sensor_index, report_id, in_data);
if (report_size)
hid_input_report(cli_data->hid_sensor_hubs[current_index],
cli_data->report_type[current_index],
- cli_data->input_report[current_index], report_size, 0);
+ in_data->input_report[current_index], report_size, 0);
else
pr_err("AMDSFH: Invalid report size\n");
}
@@ -119,21 +118,22 @@ static void amd_sfh_work(struct work_struct *work)
static void amd_sfh_work_buffer(struct work_struct *work)
{
struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work_buffer.work);
+ struct amd_input_data *in_data = cli_data->in_data;
u8 report_size;
int i;
for (i = 0; i < cli_data->num_hid_devices; i++) {
- report_size = get_input_report(cli_data->sensor_idx[i], cli_data->report_id[i],
- cli_data->input_report[i],
- cli_data->sensor_virt_addr[i]);
+ report_size = get_input_report(i, cli_data->sensor_idx[i], cli_data->report_id[i],
+ in_data);
hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT,
- cli_data->input_report[i], report_size, 0);
+ in_data->input_report[i], report_size, 0);
}
schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
}
int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
{
+ struct amd_input_data *in_data = &privdata->in_data;
struct amdtp_cl_data *cl_data = privdata->cl_data;
struct amd_mp2_sensor_info info;
struct device *dev;
@@ -143,18 +143,16 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
int rc, i;
dev = &privdata->pdev->dev;
- cl_data = devm_kzalloc(dev, sizeof(*cl_data), GFP_KERNEL);
- if (!cl_data)
- return -ENOMEM;
cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]);
INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work);
INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);
INIT_LIST_HEAD(&req_list.list);
+ cl_data->in_data = in_data;
for (i = 0; i < cl_data->num_hid_devices; i++) {
- cl_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8,
+ in_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8,
&cl_data->sensor_dma_addr[i],
GFP_KERNEL);
cl_data->sensor_sts[i] = 0;
@@ -181,8 +179,8 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
rc = -ENOMEM;
goto cleanup;
}
- cl_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL);
- if (!cl_data->input_report[i]) {
+ in_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL);
+ if (!in_data->input_report[i]) {
rc = -ENOMEM;
goto cleanup;
}
@@ -202,44 +200,43 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data);
if (rc)
return rc;
- amd_start_sensor(privdata, info);
+ privdata->mp2_ops->start(privdata, info);
cl_data->sensor_sts[i] = 1;
}
- privdata->cl_data = cl_data;
schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
return 0;
cleanup:
for (i = 0; i < cl_data->num_hid_devices; i++) {
- if (cl_data->sensor_virt_addr[i]) {
+ if (in_data->sensor_virt_addr[i]) {
dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int),
- cl_data->sensor_virt_addr[i],
+ in_data->sensor_virt_addr[i],
cl_data->sensor_dma_addr[i]);
}
devm_kfree(dev, cl_data->feature_report[i]);
- devm_kfree(dev, cl_data->input_report[i]);
+ devm_kfree(dev, in_data->input_report[i]);
devm_kfree(dev, cl_data->report_descr[i]);
}
- devm_kfree(dev, cl_data);
return rc;
}
int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
{
struct amdtp_cl_data *cl_data = privdata->cl_data;
+ struct amd_input_data *in_data = cl_data->in_data;
int i;
for (i = 0; i < cl_data->num_hid_devices; i++)
- amd_stop_sensor(privdata, i);
+ privdata->mp2_ops->stop(privdata, i);
cancel_delayed_work_sync(&cl_data->work);
cancel_delayed_work_sync(&cl_data->work_buffer);
amdtp_hid_remove(cl_data);
for (i = 0; i < cl_data->num_hid_devices; i++) {
- if (cl_data->sensor_virt_addr[i]) {
+ if (in_data->sensor_virt_addr[i]) {
dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int),
- cl_data->sensor_virt_addr[i],
+ in_data->sensor_virt_addr[i],
cl_data->sensor_dma_addr[i]);
}
}
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
index d7eac1728e31..ae2ac9191ba7 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
@@ -9,11 +9,16 @@
#ifndef AMDSFH_HID_H
#define AMDSFH_HID_H
-#define MAX_HID_DEVICES 4
+#define MAX_HID_DEVICES 5
#define BUS_AMD_AMDTP 0x20
#define AMD_SFH_HID_VENDOR 0x1022
#define AMD_SFH_HID_PRODUCT 0x0001
+struct amd_input_data {
+ u32 *sensor_virt_addr[MAX_HID_DEVICES];
+ u8 *input_report[MAX_HID_DEVICES];
+};
+
struct amdtp_cl_data {
u8 init_done;
u32 cur_hid_dev;
@@ -26,7 +31,6 @@ struct amdtp_cl_data {
u8 *hid_descr[MAX_HID_DEVICES];
int hid_descr_size[MAX_HID_DEVICES];
phys_addr_t phys_addr_base;
- u32 *sensor_virt_addr[MAX_HID_DEVICES];
dma_addr_t sensor_dma_addr[MAX_HID_DEVICES];
u32 sensor_sts[MAX_HID_DEVICES];
u32 sensor_requested_cnt[MAX_HID_DEVICES];
@@ -34,8 +38,8 @@ struct amdtp_cl_data {
u8 report_id[MAX_HID_DEVICES];
u8 sensor_idx[MAX_HID_DEVICES];
u8 *feature_report[MAX_HID_DEVICES];
- u8 *input_report[MAX_HID_DEVICES];
u8 request_done[MAX_HID_DEVICES];
+ struct amd_input_data *in_data;
struct delayed_work work;
struct delayed_work work_buffer;
};
@@ -64,4 +68,6 @@ void amdtp_hid_remove(struct amdtp_cl_data *cli_data);
int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type);
void amd_sfh_set_report(struct hid_device *hid, int report_id, int report_type);
void amdtp_hid_wakeup(struct hid_device *hid);
+u8 get_input_report(u8 current_index, int sensor_idx, int report_id,
+ struct amd_input_data *in_data);
#endif
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
index ddecc84fd6f0..96e2577fa37e 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
@@ -24,12 +24,55 @@
#define ACEL_EN BIT(0)
#define GYRO_EN BIT(1)
#define MAGNO_EN BIT(2)
+#define HPD_EN BIT(16)
#define ALS_EN BIT(19)
static int sensor_mask_override = -1;
module_param_named(sensor_mask, sensor_mask_override, int, 0444);
MODULE_PARM_DESC(sensor_mask, "override the detected sensors mask");
+static void amd_start_sensor_v2(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
+{
+ union sfh_cmd_base cmd_base;
+
+ cmd_base.ul = 0;
+ cmd_base.cmd_v2.cmd_id = ENABLE_SENSOR;
+ cmd_base.cmd_v2.period = info.period;
+ cmd_base.cmd_v2.sensor_id = info.sensor_idx;
+ cmd_base.cmd_v2.length = 16;
+
+ if (info.sensor_idx == als_idx)
+ cmd_base.cmd_v2.mem_type = USE_C2P_REG;
+
+ writeq(info.dma_address, privdata->mmio + AMD_C2P_MSG1);
+ writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
+}
+
+static void amd_stop_sensor_v2(struct amd_mp2_dev *privdata, u16 sensor_idx)
+{
+ union sfh_cmd_base cmd_base;
+
+ cmd_base.ul = 0;
+ cmd_base.cmd_v2.cmd_id = DISABLE_SENSOR;
+ cmd_base.cmd_v2.period = 0;
+ cmd_base.cmd_v2.sensor_id = sensor_idx;
+ cmd_base.cmd_v2.length = 16;
+
+ writeq(0x0, privdata->mmio + AMD_C2P_MSG2);
+ writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
+}
+
+static void amd_stop_all_sensor_v2(struct amd_mp2_dev *privdata)
+{
+ union sfh_cmd_base cmd_base;
+
+ cmd_base.cmd_v2.cmd_id = STOP_ALL_SENSORS;
+ cmd_base.cmd_v2.period = 0;
+ cmd_base.cmd_v2.sensor_id = 0;
+
+ writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
+}
+
void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
{
union sfh_cmd_param cmd_param;
@@ -98,7 +141,6 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
{
int activestatus, num_of_sensors = 0;
const struct dmi_system_id *dmi_id;
- u32 activecontrolstatus;
if (sensor_mask_override == -1) {
dmi_id = dmi_first_match(dmi_sensor_mask_overrides);
@@ -109,8 +151,7 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
if (sensor_mask_override >= 0) {
activestatus = sensor_mask_override;
} else {
- activecontrolstatus = readl(privdata->mmio + AMD_P2C_MSG3);
- activestatus = activecontrolstatus >> 4;
+ activestatus = privdata->mp2_acs >> 4;
}
if (ACEL_EN & activestatus)
@@ -125,13 +166,46 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
if (ALS_EN & activestatus)
sensor_id[num_of_sensors++] = als_idx;
+ if (HPD_EN & activestatus)
+ sensor_id[num_of_sensors++] = HPD_IDX;
+
return num_of_sensors;
}
static void amd_mp2_pci_remove(void *privdata)
{
+ struct amd_mp2_dev *mp2 = privdata;
amd_sfh_hid_client_deinit(privdata);
- amd_stop_all_sensors(privdata);
+ mp2->mp2_ops->stop_all(mp2);
+}
+
+static const struct amd_mp2_ops amd_sfh_ops_v2 = {
+ .start = amd_start_sensor_v2,
+ .stop = amd_stop_sensor_v2,
+ .stop_all = amd_stop_all_sensor_v2,
+};
+
+static const struct amd_mp2_ops amd_sfh_ops = {
+ .start = amd_start_sensor,
+ .stop = amd_stop_sensor,
+ .stop_all = amd_stop_all_sensors,
+};
+
+static void mp2_select_ops(struct amd_mp2_dev *privdata)
+{
+ u8 acs;
+
+ privdata->mp2_acs = readl(privdata->mmio + AMD_P2C_MSG3);
+ acs = privdata->mp2_acs & GENMASK(3, 0);
+
+ switch (acs) {
+ case V2_STATUS:
+ privdata->mp2_ops = &amd_sfh_ops_v2;
+ break;
+ default:
+ privdata->mp2_ops = &amd_sfh_ops;
+ break;
+ }
}
static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -160,10 +234,17 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
return rc;
}
+
+ privdata->cl_data = devm_kzalloc(&pdev->dev, sizeof(struct amdtp_cl_data), GFP_KERNEL);
+ if (!privdata->cl_data)
+ return -ENOMEM;
+
rc = devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata);
if (rc)
return rc;
+ mp2_select_ops(privdata);
+
return amd_sfh_hid_client_init(privdata);
}
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
index 489415f7c22c..2d5c57e3782d 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
@@ -10,6 +10,7 @@
#define PCIE_MP2_AMD_H
#include <linux/pci.h>
+#include "amd_sfh_hid.h"
#define PCI_DEVICE_ID_AMD_MP2 0x15E4
@@ -22,9 +23,15 @@
#define AMD_C2P_MSG1 0x10504
#define AMD_C2P_MSG2 0x10508
+#define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4))
+
/* MP2 P2C Message Registers */
#define AMD_P2C_MSG3 0x1068C /* Supported Sensors info */
+#define V2_STATUS 0x2
+
+#define HPD_IDX 16
+
/* SFH Command register */
union sfh_cmd_base {
u32 ul;
@@ -33,6 +40,15 @@ union sfh_cmd_base {
u32 sensor_id : 8;
u32 period : 16;
} s;
+ struct {
+ u32 cmd_id : 4;
+ u32 intr_enable : 1;
+ u32 rsvd1 : 3;
+ u32 length : 7;
+ u32 mem_type : 1;
+ u32 sensor_id : 8;
+ u32 period : 8;
+ } cmd_v2;
};
union sfh_cmd_param {
@@ -61,6 +77,10 @@ struct amd_mp2_dev {
struct pci_dev *pdev;
struct amdtp_cl_data *cl_data;
void __iomem *mmio;
+ const struct amd_mp2_ops *mp2_ops;
+ struct amd_input_data in_data;
+ /* mp2 active control status */
+ u32 mp2_acs;
};
struct amd_mp2_sensor_info {
@@ -69,10 +89,33 @@ struct amd_mp2_sensor_info {
dma_addr_t dma_address;
};
+enum mem_use_type {
+ USE_DRAM,
+ USE_C2P_REG,
+};
+
+struct hpd_status {
+ union {
+ struct {
+ u32 human_presence_report : 4;
+ u32 human_presence_actual : 4;
+ u32 probablity : 8;
+ u32 object_distance : 16;
+ } shpd;
+ u32 val;
+ };
+};
+
void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info);
void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx);
void amd_stop_all_sensors(struct amd_mp2_dev *privdata);
int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id);
int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata);
int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata);
+
+struct amd_mp2_ops {
+ void (*start)(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info);
+ void (*stop)(struct amd_mp2_dev *privdata, u16 sensor_idx);
+ void (*stop_all)(struct amd_mp2_dev *privdata);
+};
#endif
diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
index 6e3ad66e57a4..0c3697219382 100644
--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
@@ -12,6 +12,7 @@
#include "amd_sfh_pcie.h"
#include "amd_sfh_hid_desc.h"
#include "amd_sfh_hid_report_desc.h"
+#include "amd_sfh_hid.h"
#define AMD_SFH_FW_MULTIPLIER (1000)
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x41
@@ -49,6 +50,11 @@ int get_report_descriptor(int sensor_idx, u8 *rep_desc)
memcpy(rep_desc, als_report_descriptor,
sizeof(als_report_descriptor));
break;
+ case HPD_IDX: /* HPD sensor */
+ memset(rep_desc, 0, sizeof(hpd_report_descriptor));
+ memcpy(rep_desc, hpd_report_descriptor,
+ sizeof(hpd_report_descriptor));
+ break;
default:
break;
}
@@ -98,6 +104,17 @@ u32 get_descr_sz(int sensor_idx, int descriptor_name)
return sizeof(struct als_feature_report);
}
break;
+ case HPD_IDX:
+ switch (descriptor_name) {
+ case descr_size:
+ return sizeof(hpd_report_descriptor);
+ case input_size:
+ return sizeof(struct hpd_input_report);
+ case feature_size:
+ return sizeof(struct hpd_feature_report);
+ }
+ break;
+
default:
break;
}
@@ -119,6 +136,7 @@ u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
struct accel3_feature_report acc_feature;
struct gyro_feature_report gyro_feature;
struct magno_feature_report magno_feature;
+ struct hpd_feature_report hpd_feature;
struct als_feature_report als_feature;
u8 report_size = 0;
@@ -161,6 +179,12 @@ u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
memcpy(feature_report, &als_feature, sizeof(als_feature));
report_size = sizeof(als_feature);
break;
+ case HPD_IDX: /* human presence detection sensor */
+ get_common_features(&hpd_feature.common_property, report_id);
+ memcpy(feature_report, &hpd_feature, sizeof(hpd_feature));
+ report_size = sizeof(hpd_feature);
+ break;
+
default:
break;
}
@@ -174,12 +198,18 @@ static void get_common_inputs(struct common_input_property *common, int report_i
common->event_type = HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM;
}
-u8 get_input_report(int sensor_idx, int report_id, u8 *input_report, u32 *sensor_virt_addr)
+u8 get_input_report(u8 current_index, int sensor_idx, int report_id, struct amd_input_data *in_data)
{
+ struct amd_mp2_dev *privdata = container_of(in_data, struct amd_mp2_dev, in_data);
+ u32 *sensor_virt_addr = in_data->sensor_virt_addr[current_index];
+ u8 *input_report = in_data->input_report[current_index];
+ u8 supported_input = privdata->mp2_acs & GENMASK(3, 0);
+ struct magno_input_report magno_input;
struct accel3_input_report acc_input;
struct gyro_input_report gyro_input;
- struct magno_input_report magno_input;
+ struct hpd_input_report hpd_input;
struct als_input_report als_input;
+ struct hpd_status hpdstatus;
u8 report_size = 0;
if (!sensor_virt_addr || !input_report)
@@ -213,10 +243,22 @@ u8 get_input_report(int sensor_idx, int report_id, u8 *input_report, u32 *sensor
break;
case als_idx: /* Als */
get_common_inputs(&als_input.common_property, report_id);
- als_input.illuminance_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER;
+ /* For ALS ,V2 Platforms uses C2P_MSG5 register instead of DRAM access method */
+ if (supported_input == V2_STATUS)
+ als_input.illuminance_value = (int)readl(privdata->mmio + AMD_C2P_MSG(5));
+ else
+ als_input.illuminance_value =
+ (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER;
report_size = sizeof(als_input);
memcpy(input_report, &als_input, sizeof(als_input));
break;
+ case HPD_IDX: /* hpd */
+ get_common_inputs(&hpd_input.common_property, report_id);
+ hpdstatus.val = readl(privdata->mmio + AMD_C2P_MSG(4));
+ hpd_input.human_presence = hpdstatus.shpd.human_presence_actual;
+ report_size = sizeof(hpd_input);
+ memcpy(input_report, &hpd_input, sizeof(hpd_input));
+ break;
default:
break;
}
diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
index 095c471d8fd6..16f563d1823b 100644
--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
@@ -100,8 +100,17 @@ struct als_input_report {
int illuminance_value;
} __packed;
+struct hpd_feature_report {
+ struct common_feature_property common_property;
+} __packed;
+
+struct hpd_input_report {
+ struct common_input_property common_property;
+ /* values specific to human presence sensor */
+ u8 human_presence;
+} __packed;
+
int get_report_descriptor(int sensor_idx, u8 rep_desc[]);
u32 get_descr_sz(int sensor_idx, int descriptor_name);
u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report);
-u8 get_input_report(int sensor_idx, int report_id, u8 *input_report, u32 *sensor_virt_addr);
#endif
diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
index 44271d39b322..66d6b26e4708 100644
--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
@@ -642,4 +642,116 @@ const u8 als_report_descriptor[] = {
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
0xC0 /* HID end collection */
};
+
+/* BIOMETRIC PRESENCE*/
+static const u8 hpd_report_descriptor[] = {
+0x05, 0x20, /* Usage page */
+0x09, 0x11, /* BIOMETRIC PRESENCE */
+0xA1, 0x00, /* HID Collection (Physical) */
+
+//feature reports(xmit/receive)
+0x85, 5, /* HID Report ID */
+0x05, 0x20, /* HID usage page sensor */
+0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */
+0x15, 0, /* HID logical MIN_8(0) */
+0x25, 2, /* HID logical MAX_8(2) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection (logical) */
+0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel*/
+0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */
+0x0A, 0x32, 0x08, /* Sensor property connection type external sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x40, 0x08, /* Sensor property report state no events sel */
+0x0A, 0x41, 0x08, /* Sensor property report state all events sel */
+0x0A, 0x42, 0x08, /* Sensor property report state threshold events sel */
+0x0A, 0x43, 0x08, /* Sensor property report state no events wake sel */
+0x0A, 0x44, 0x08, /* Sensor property report state all events wake sel */
+0x0A, 0x45, 0x08, /* Sensor property report state threshold events wake sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x19, 0x03, /* HID usage sensor property power state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x50, 0x08, /* Sensor property power state undefined sel */
+0x0A, 0x51, 0x08, /* Sensor property power state D0 full power sel */
+0x0A, 0x52, 0x08, /* Sensor property power state D1 low power sel */
+0x0A, 0x53, 0x08, /* Sensor property power state D2 standby with wake sel */
+0x0A, 0x54, 0x08, /* Sensor property power state D3 sleep with wake sel */
+0x0A, 0x55, 0x08, /* Sensor property power state D4 power off sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x01, 0x02, /* HID usage sensor state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 6, /* HID logical Max_8(6) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
+0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
+0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
+0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
+0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
+0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
+0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */
+0x15, 0, /* HID logical Min_8(0) */
+0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */
+
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count(1) */
+0x55, 0, /* HID unit exponent(0) */
+0xB1, 0x02, /* HID feature (Data_Var_Abs) */
+
+//input report (transmit)
+0x05, 0x20, /* HID usage page sensors */
+0x0A, 0x01, 0x02, /* HID usage sensor state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 6, /* HID logical Max_8(6) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count (1) */
+0xA1, 0x02, /* HID end collection (logical) */
+0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
+0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
+0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
+0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
+0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
+0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
+0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
+0X81, 0x00, /* HID Input (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x02, 0x02, /* HID usage sensor event */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count (1) */
+0xA1, 0x02, /* HID end collection (logical) */
+0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */
+0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */
+0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */
+0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */
+0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */
+0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */
+0X81, 0x00, /* HID Input (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0xB1, 0x04, /* HID usage sensor data BIOMETRIC HUMAN PRESENCE */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 1, /* HID logical Max_8(1) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count (1) */
+0X81, 0x02, /* HID Input (Data_Var_Abs) */
+0xC0 /* HID end collection */
+};
#endif
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 0de2788b9814..7db332139f7d 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2306,12 +2306,8 @@ static int hid_device_remove(struct device *dev)
{
struct hid_device *hdev = to_hid_device(dev);
struct hid_driver *hdrv;
- int ret = 0;
- if (down_interruptible(&hdev->driver_input_lock)) {
- ret = -EINTR;
- goto end;
- }
+ down(&hdev->driver_input_lock);
hdev->io_started = false;
hdrv = hdev->driver;
@@ -2326,8 +2322,8 @@ static int hid_device_remove(struct device *dev)
if (!hdev->io_started)
up(&hdev->driver_input_lock);
-end:
- return ret;
+
+ return 0;
}
static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index a311fb87b02a..fa57d05badf7 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -122,6 +122,7 @@ static const struct hid_usage_entry hid_usage_table[] = {
{ 9, 0, "Button" },
{ 10, 0, "Ordinal" },
{ 12, 0, "Consumer" },
+ {0, 0x003, "ProgrammableButtons"},
{0, 0x238, "HorizontalWheel"},
{ 13, 0, "Digitizers" },
{0, 0x01, "Digitizer"},
@@ -942,6 +943,16 @@ static const char *keys[KEY_MAX + 1] = {
[KEY_KBDINPUTASSIST_NEXTGROUP] = "KbdInputAssistNextGroup",
[KEY_KBDINPUTASSIST_ACCEPT] = "KbdInputAssistAccept",
[KEY_KBDINPUTASSIST_CANCEL] = "KbdInputAssistCancel",
+ [KEY_MACRO1] = "Macro1", [KEY_MACRO2] = "Macro2", [KEY_MACRO3] = "Macro3",
+ [KEY_MACRO4] = "Macro4", [KEY_MACRO5] = "Macro5", [KEY_MACRO6] = "Macro6",
+ [KEY_MACRO7] = "Macro7", [KEY_MACRO8] = "Macro8", [KEY_MACRO9] = "Macro9",
+ [KEY_MACRO10] = "Macro10", [KEY_MACRO11] = "Macro11", [KEY_MACRO12] = "Macro12",
+ [KEY_MACRO13] = "Macro13", [KEY_MACRO14] = "Macro14", [KEY_MACRO15] = "Macro15",
+ [KEY_MACRO16] = "Macro16", [KEY_MACRO17] = "Macro17", [KEY_MACRO18] = "Macro18",
+ [KEY_MACRO19] = "Macro19", [KEY_MACRO20] = "Macro20", [KEY_MACRO21] = "Macro21",
+ [KEY_MACRO22] = "Macro22", [KEY_MACRO23] = "Macro23", [KEY_MACRO24] = "Macro24",
+ [KEY_MACRO25] = "Macro25", [KEY_MACRO26] = "Macro26", [KEY_MACRO27] = "Macro27",
+ [KEY_MACRO28] = "Macro28", [KEY_MACRO29] = "Macro29", [KEY_MACRO30] = "Macro30",
};
static const char *relatives[REL_MAX + 1] = {
diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c
index e60c31dd05ff..8123b871a3eb 100644
--- a/drivers/hid/hid-google-hammer.c
+++ b/drivers/hid/hid-google-hammer.c
@@ -17,6 +17,7 @@
#include <linux/hid.h>
#include <linux/leds.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_device.h>
@@ -272,12 +273,21 @@ static const struct acpi_device_id cbas_ec_acpi_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, cbas_ec_acpi_ids);
+#ifdef CONFIG_OF
+static const struct of_device_id cbas_ec_of_match[] = {
+ { .compatible = "google,cros-cbas" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, cbas_ec_of_match);
+#endif
+
static struct platform_driver cbas_ec_driver = {
.probe = cbas_ec_probe,
.remove = cbas_ec_remove,
.driver = {
.name = "cbas_ec",
.acpi_match_table = ACPI_PTR(cbas_ec_acpi_ids),
+ .of_match_table = of_match_ptr(cbas_ec_of_match),
.pm = &cbas_ec_pm_ops,
},
};
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index b84a0a11e05b..8f1893e68112 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -396,6 +396,7 @@
#define USB_DEVICE_ID_HP_X2_10_COVER 0x0755
#define I2C_DEVICE_ID_HP_SPECTRE_X360_15 0x2817
#define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN 0x2706
+#define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN 0x261A
#define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
@@ -763,6 +764,7 @@
#define I2C_DEVICE_ID_LG_7010 0x7010
#define USB_VENDOR_ID_LOGITECH 0x046d
+#define USB_DEVICE_ID_LOGITECH_Z_10_SPK 0x0a07
#define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
#define USB_DEVICE_ID_LOGITECH_T651 0xb00c
#define USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD 0xb309
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index abbfa91e73e4..4286a51f7f16 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -326,6 +326,8 @@ static const struct hid_device_id hid_battery_quirks[] = {
HID_BATTERY_QUIRK_IGNORE },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_15),
HID_BATTERY_QUIRK_IGNORE },
+ { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN),
+ HID_BATTERY_QUIRK_IGNORE },
{}
};
@@ -567,6 +569,16 @@ static void hidinput_update_battery(struct hid_device *dev, int value)
}
#endif /* CONFIG_HID_BATTERY_STRENGTH */
+static bool hidinput_field_in_collection(struct hid_device *device, struct hid_field *field,
+ unsigned int type, unsigned int usage)
+{
+ struct hid_collection *collection;
+
+ collection = &device->collection[field->usage->collection_index];
+
+ return collection->type == type && collection->usage == usage;
+}
+
static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage)
{
@@ -632,6 +644,18 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
else
code += BTN_TRIGGER_HAPPY - 0x10;
break;
+ case HID_CP_CONSUMER_CONTROL:
+ if (hidinput_field_in_collection(device, field,
+ HID_COLLECTION_NAMED_ARRAY,
+ HID_CP_PROGRAMMABLEBUTTONS)) {
+ if (code <= 0x1d)
+ code += KEY_MACRO1;
+ else
+ code += BTN_TRIGGER_HAPPY - 0x1e;
+ } else {
+ goto ignore;
+ }
+ break;
default:
switch (field->physical) {
case HID_GD_MOUSE:
@@ -1316,12 +1340,12 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
}
- if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
+ if (usage->hid == HID_DG_INVERT) {
*quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
return;
}
- if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
+ if (usage->hid == HID_DG_INRANGE) {
if (value) {
input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
return;
@@ -1331,7 +1355,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
}
- if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
+ if (usage->hid == HID_DG_TIPPRESSURE && (*quirks & HID_QUIRK_NOTOUCH)) {
int a = field->logical_minimum;
int b = field->logical_maximum;
input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
diff --git a/drivers/hid/hid-ite.c b/drivers/hid/hid-ite.c
index 14fc068affad..430fa4f52ed3 100644
--- a/drivers/hid/hid-ite.c
+++ b/drivers/hid/hid-ite.c
@@ -135,4 +135,5 @@ static struct hid_driver ite_driver = {
};
module_hid_driver(ite_driver);
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-lg-g15.c b/drivers/hid/hid-lg-g15.c
index bfbba0d41933..b2a08233f8d5 100644
--- a/drivers/hid/hid-lg-g15.c
+++ b/drivers/hid/hid-lg-g15.c
@@ -28,6 +28,7 @@ enum lg_g15_model {
LG_G15_V2,
LG_G510,
LG_G510_USB_AUDIO,
+ LG_Z10,
};
enum lg_g15_led_type {
@@ -457,6 +458,13 @@ static int lg_g15_get_initial_led_brightness(struct lg_g15_data *g15)
return ret;
return lg_g510_update_mkey_led_brightness(g15);
+ case LG_Z10:
+ /*
+ * Getting the LCD backlight brightness is not supported.
+ * Reading Feature(2) fails with -EPIPE and this crashes
+ * the LCD and touch keys part of the speakers.
+ */
+ return 0;
}
return -EINVAL; /* Never reached */
}
@@ -464,7 +472,20 @@ static int lg_g15_get_initial_led_brightness(struct lg_g15_data *g15)
/******** Input functions ********/
/* On the G15 Mark I Logitech has been quite creative with which bit is what */
-static int lg_g15_event(struct lg_g15_data *g15, u8 *data, int size)
+static void lg_g15_handle_lcd_menu_keys(struct lg_g15_data *g15, u8 *data)
+{
+ int i, val;
+
+ /* Most left (round/display) button below the LCD */
+ input_report_key(g15->input, KEY_KBD_LCD_MENU1, data[8] & 0x80);
+ /* 4 other buttons below the LCD */
+ for (i = 0; i < 4; i++) {
+ val = data[i + 2] & 0x80;
+ input_report_key(g15->input, KEY_KBD_LCD_MENU2 + i, val);
+ }
+}
+
+static int lg_g15_event(struct lg_g15_data *g15, u8 *data)
{
int i, val;
@@ -494,13 +515,7 @@ static int lg_g15_event(struct lg_g15_data *g15, u8 *data, int size)
/* MR */
input_report_key(g15->input, KEY_MACRO_RECORD_START, data[7] & 0x40);
- /* Most left (round) button below the LCD */
- input_report_key(g15->input, KEY_KBD_LCD_MENU1, data[8] & 0x80);
- /* 4 other buttons below the LCD */
- for (i = 0; i < 4; i++) {
- val = data[i + 2] & 0x80;
- input_report_key(g15->input, KEY_KBD_LCD_MENU2 + i, val);
- }
+ lg_g15_handle_lcd_menu_keys(g15, data);
/* Backlight cycle button pressed? */
if (data[1] & 0x80)
@@ -510,7 +525,7 @@ static int lg_g15_event(struct lg_g15_data *g15, u8 *data, int size)
return 0;
}
-static int lg_g15_v2_event(struct lg_g15_data *g15, u8 *data, int size)
+static int lg_g15_v2_event(struct lg_g15_data *g15, u8 *data)
{
int i, val;
@@ -542,7 +557,7 @@ static int lg_g15_v2_event(struct lg_g15_data *g15, u8 *data, int size)
return 0;
}
-static int lg_g510_event(struct lg_g15_data *g15, u8 *data, int size)
+static int lg_g510_event(struct lg_g15_data *g15, u8 *data)
{
bool game_mode_enabled;
int i, val;
@@ -586,7 +601,7 @@ static int lg_g510_event(struct lg_g15_data *g15, u8 *data, int size)
return 0;
}
-static int lg_g510_leds_event(struct lg_g15_data *g15, u8 *data, int size)
+static int lg_g510_leds_event(struct lg_g15_data *g15, u8 *data)
{
bool backlight_disabled;
@@ -613,18 +628,24 @@ static int lg_g15_raw_event(struct hid_device *hdev, struct hid_report *report,
switch (g15->model) {
case LG_G15:
if (data[0] == 0x02 && size == 9)
- return lg_g15_event(g15, data, size);
+ return lg_g15_event(g15, data);
break;
case LG_G15_V2:
if (data[0] == 0x02 && size == 5)
- return lg_g15_v2_event(g15, data, size);
+ return lg_g15_v2_event(g15, data);
+ break;
+ case LG_Z10:
+ if (data[0] == 0x02 && size == 9) {
+ lg_g15_handle_lcd_menu_keys(g15, data);
+ input_sync(g15->input);
+ }
break;
case LG_G510:
case LG_G510_USB_AUDIO:
if (data[0] == 0x03 && size == 5)
- return lg_g510_event(g15, data, size);
+ return lg_g510_event(g15, data);
if (data[0] == 0x04 && size == 2)
- return lg_g510_leds_event(g15, data, size);
+ return lg_g510_leds_event(g15, data);
break;
}
@@ -645,25 +666,18 @@ static void lg_g15_input_close(struct input_dev *dev)
hid_hw_close(hdev);
}
-static int lg_g15_register_led(struct lg_g15_data *g15, int i)
+static int lg_g15_register_led(struct lg_g15_data *g15, int i, const char *name)
{
- static const char * const led_names[] = {
- "g15::kbd_backlight",
- "g15::lcd_backlight",
- "g15::macro_preset1",
- "g15::macro_preset2",
- "g15::macro_preset3",
- "g15::macro_record",
- };
-
g15->leds[i].led = i;
- g15->leds[i].cdev.name = led_names[i];
+ g15->leds[i].cdev.name = name;
switch (g15->model) {
case LG_G15:
case LG_G15_V2:
- g15->leds[i].cdev.brightness_set_blocking = lg_g15_led_set;
g15->leds[i].cdev.brightness_get = lg_g15_led_get;
+ fallthrough;
+ case LG_Z10:
+ g15->leds[i].cdev.brightness_set_blocking = lg_g15_led_set;
if (i < LG_G15_BRIGHTNESS_MAX) {
g15->leds[i].cdev.flags = LED_BRIGHT_HW_CHANGED;
g15->leds[i].cdev.max_brightness = 2;
@@ -702,8 +716,38 @@ static int lg_g15_register_led(struct lg_g15_data *g15, int i)
return devm_led_classdev_register(&g15->hdev->dev, &g15->leds[i].cdev);
}
+/* Common input device init code shared between keyboards and Z-10 speaker handling */
+static void lg_g15_init_input_dev(struct hid_device *hdev, struct input_dev *input,
+ const char *name)
+{
+ int i;
+
+ input->name = name;
+ input->phys = hdev->phys;
+ input->uniq = hdev->uniq;
+ input->id.bustype = hdev->bus;
+ input->id.vendor = hdev->vendor;
+ input->id.product = hdev->product;
+ input->id.version = hdev->version;
+ input->dev.parent = &hdev->dev;
+ input->open = lg_g15_input_open;
+ input->close = lg_g15_input_close;
+
+ /* Keys below the LCD, intended for controlling a menu on the LCD */
+ for (i = 0; i < 5; i++)
+ input_set_capability(input, EV_KEY, KEY_KBD_LCD_MENU1 + i);
+}
+
static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
+ static const char * const led_names[] = {
+ "g15::kbd_backlight",
+ "g15::lcd_backlight",
+ "g15::macro_preset1",
+ "g15::macro_preset2",
+ "g15::macro_preset3",
+ "g15::macro_record",
+ };
u8 gkeys_settings_output_report = 0;
u8 gkeys_settings_feature_report = 0;
struct hid_report_enum *rep_enum;
@@ -744,6 +788,8 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
g15->hdev = hdev;
g15->model = id->driver_data;
+ g15->input = input;
+ input_set_drvdata(input, hdev);
hid_set_drvdata(hdev, (void *)g15);
switch (g15->model) {
@@ -772,6 +818,9 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
gkeys_settings_feature_report = 0x01;
gkeys = 18;
break;
+ case LG_Z10:
+ connect_mask = HID_CONNECT_HIDRAW;
+ break;
}
ret = hid_hw_start(hdev, connect_mask);
@@ -814,17 +863,21 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret)
goto error_hw_stop;
+ if (g15->model == LG_Z10) {
+ lg_g15_init_input_dev(hdev, g15->input, "Logitech Z-10 LCD Menu Keys");
+ ret = input_register_device(g15->input);
+ if (ret)
+ goto error_hw_stop;
+
+ ret = lg_g15_register_led(g15, 1, "z-10::lcd_backlight");
+ if (ret)
+ goto error_hw_stop;
+
+ return 0; /* All done */
+ }
+
/* Setup and register input device */
- input->name = "Logitech Gaming Keyboard Gaming Keys";
- input->phys = hdev->phys;
- input->uniq = hdev->uniq;
- input->id.bustype = hdev->bus;
- input->id.vendor = hdev->vendor;
- input->id.product = hdev->product;
- input->id.version = hdev->version;
- input->dev.parent = &hdev->dev;
- input->open = lg_g15_input_open;
- input->close = lg_g15_input_close;
+ lg_g15_init_input_dev(hdev, input, "Logitech Gaming Keyboard Gaming Keys");
/* G-keys */
for (i = 0; i < gkeys; i++)
@@ -835,10 +888,6 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
input_set_capability(input, EV_KEY, KEY_MACRO_PRESET1 + i);
input_set_capability(input, EV_KEY, KEY_MACRO_RECORD_START);
- /* Keys below the LCD, intended for controlling a menu on the LCD */
- for (i = 0; i < 5; i++)
- input_set_capability(input, EV_KEY, KEY_KBD_LCD_MENU1 + i);
-
/*
* On the G510 only report headphone and mic mute keys when *not* using
* the builtin USB audio device. When the builtin audio is used these
@@ -850,16 +899,13 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
input_set_capability(input, EV_KEY, KEY_F20);
}
- g15->input = input;
- input_set_drvdata(input, hdev);
-
ret = input_register_device(input);
if (ret)
goto error_hw_stop;
/* Register LED devices */
for (i = 0; i < LG_G15_LED_MAX; i++) {
- ret = lg_g15_register_led(g15, i);
+ ret = lg_g15_register_led(g15, i, led_names[i]);
if (ret)
goto error_hw_stop;
}
@@ -890,6 +936,10 @@ static const struct hid_device_id lg_g15_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_G510_USB_AUDIO),
.driver_data = LG_G510_USB_AUDIO },
+ /* Z-10 speakers */
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
+ USB_DEVICE_ID_LOGITECH_Z_10_SPK),
+ .driver_data = LG_Z10 },
{ }
};
MODULE_DEVICE_TABLE(hid, lg_g15_devices);
@@ -902,4 +952,5 @@ static struct hid_driver lg_g15_driver = {
};
module_hid_driver(lg_g15_driver);
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index fa835d565982..a0017b010c34 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -100,6 +100,7 @@
#define HIDPP_DEVICE_TYPE_MASK GENMASK(3, 0)
#define HIDPP_LINK_STATUS_MASK BIT(6)
#define HIDPP_MANUFACTURER_MASK BIT(7)
+#define HIDPP_27MHZ_SECURE_MASK BIT(7)
#define HIDPP_DEVICE_TYPE_KEYBOARD 1
#define HIDPP_DEVICE_TYPE_MOUSE 2
@@ -984,6 +985,13 @@ static void logi_hidpp_dev_conn_notif_27mhz(struct hid_device *hdev,
workitem->reports_supported |= STD_MOUSE | HIDPP;
break;
case 3: /* Index 3 is always the keyboard */
+ if (hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] & HIDPP_27MHZ_SECURE_MASK) {
+ hid_info(hdev, "Keyboard connection is encrypted\n");
+ } else {
+ hid_warn(hdev, "Keyboard events are send over the air in plain-text / unencrypted\n");
+ hid_warn(hdev, "See: https://gitlab.freedesktop.org/jwrdegoede/logitech-27mhz-keyboard-encryption-setup/\n");
+ }
+ fallthrough;
case 4: /* Index 4 is used for an optional separate numpad */
workitem->device_type = HIDPP_DEVICE_TYPE_KEYBOARD;
workitem->reports_supported |= STD_KEYBOARD | MULTIMEDIA |
@@ -1489,6 +1497,13 @@ static void logi_dj_ll_stop(struct hid_device *hid)
dbg_hid("%s\n", __func__);
}
+static bool logi_dj_ll_may_wakeup(struct hid_device *hid)
+{
+ struct dj_device *djdev = hid->driver_data;
+ struct dj_receiver_dev *djrcv_dev = djdev->dj_receiver_dev;
+
+ return hid_hw_may_wakeup(djrcv_dev->hidpp);
+}
static struct hid_ll_driver logi_dj_ll_driver = {
.parse = logi_dj_ll_parse,
@@ -1497,6 +1512,7 @@ static struct hid_ll_driver logi_dj_ll_driver = {
.open = logi_dj_ll_open,
.close = logi_dj_ll_close,
.raw_request = logi_dj_ll_raw_request,
+ .may_wakeup = logi_dj_ll_may_wakeup,
};
static int logi_dj_dj_event(struct hid_device *hdev,
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index fee4e54a3ce0..61635e629469 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -56,6 +56,8 @@ MODULE_PARM_DESC(disable_tap_to_click,
#define HIDPP_SUB_ID_CONSUMER_VENDOR_KEYS 0x03
#define HIDPP_SUB_ID_ROLLER 0x05
#define HIDPP_SUB_ID_MOUSE_EXTRA_BTNS 0x06
+#define HIDPP_SUB_ID_USER_IFACE_EVENT 0x08
+#define HIDPP_USER_IFACE_EVENT_ENCRYPTION_KEY_LOST BIT(5)
#define HIDPP_QUIRK_CLASS_WTP BIT(0)
#define HIDPP_QUIRK_CLASS_M560 BIT(1)
@@ -3529,6 +3531,16 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
return 1;
}
+ if (hidpp->hid_dev->group == HID_GROUP_LOGITECH_27MHZ_DEVICE &&
+ data[0] == REPORT_ID_HIDPP_SHORT &&
+ data[2] == HIDPP_SUB_ID_USER_IFACE_EVENT &&
+ (data[3] & HIDPP_USER_IFACE_EVENT_ENCRYPTION_KEY_LOST)) {
+ dev_err_ratelimited(&hidpp->hid_dev->dev,
+ "Error the keyboard's wireless encryption key has been lost, your keyboard will not work unless you re-configure encryption.\n");
+ dev_err_ratelimited(&hidpp->hid_dev->dev,
+ "See: https://gitlab.freedesktop.org/jwrdegoede/logitech-27mhz-keyboard-encryption-setup/\n");
+ }
+
if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) {
ret = hidpp20_battery_event_1000(hidpp, data, size);
if (ret != 0)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 2e4fb76c45f3..3ea7cb1cda84 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -1768,7 +1768,8 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state)
struct mt_device *td = hid_get_drvdata(hdev);
/* High latency is desirable for power savings during S3/S0ix */
- if (td->mtclass.quirks & MT_QUIRK_DISABLE_WAKEUP)
+ if ((td->mtclass.quirks & MT_QUIRK_DISABLE_WAKEUP) ||
+ !hid_hw_may_wakeup(hdev))
mt_set_modes(hdev, HID_LATENCY_HIGH, false, false);
else
mt_set_modes(hdev, HID_LATENCY_HIGH, true, true);
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 8319b0ce385a..b3722c51ec78 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -597,9 +597,8 @@ struct sony_sc {
/* DS4 calibration data */
struct ds4_calibration_data ds4_calib_data[6];
/* GH Live */
+ struct urb *ghl_urb;
struct timer_list ghl_poke_timer;
- struct usb_ctrlrequest *ghl_cr;
- u8 *ghl_databuf;
};
static void sony_set_leds(struct sony_sc *sc);
@@ -625,66 +624,54 @@ static inline void sony_schedule_work(struct sony_sc *sc,
static void ghl_magic_poke_cb(struct urb *urb)
{
- if (urb) {
- /* Free sc->ghl_cr and sc->ghl_databuf allocated in
- * ghl_magic_poke()
- */
- kfree(urb->setup_packet);
- kfree(urb->transfer_buffer);
- }
+ struct sony_sc *sc = urb->context;
+
+ if (urb->status < 0)
+ hid_err(sc->hdev, "URB transfer failed : %d", urb->status);
+
+ mod_timer(&sc->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
}
static void ghl_magic_poke(struct timer_list *t)
{
+ int ret;
struct sony_sc *sc = from_timer(sc, t, ghl_poke_timer);
- int ret;
+ ret = usb_submit_urb(sc->ghl_urb, GFP_ATOMIC);
+ if (ret < 0)
+ hid_err(sc->hdev, "usb_submit_urb failed: %d", ret);
+}
+
+static int ghl_init_urb(struct sony_sc *sc, struct usb_device *usbdev)
+{
+ struct usb_ctrlrequest *cr;
+ u16 poke_size;
+ u8 *databuf;
unsigned int pipe;
- struct urb *urb;
- struct usb_device *usbdev = to_usb_device(sc->hdev->dev.parent->parent);
- const u16 poke_size =
- ARRAY_SIZE(ghl_ps3wiiu_magic_data);
+ poke_size = ARRAY_SIZE(ghl_ps3wiiu_magic_data);
pipe = usb_sndctrlpipe(usbdev, 0);
- if (!sc->ghl_cr) {
- sc->ghl_cr = kzalloc(sizeof(*sc->ghl_cr), GFP_ATOMIC);
- if (!sc->ghl_cr)
- goto resched;
- }
-
- if (!sc->ghl_databuf) {
- sc->ghl_databuf = kzalloc(poke_size, GFP_ATOMIC);
- if (!sc->ghl_databuf)
- goto resched;
- }
+ cr = devm_kzalloc(&sc->hdev->dev, sizeof(*cr), GFP_ATOMIC);
+ if (cr == NULL)
+ return -ENOMEM;
- urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!urb)
- goto resched;
+ databuf = devm_kzalloc(&sc->hdev->dev, poke_size, GFP_ATOMIC);
+ if (databuf == NULL)
+ return -ENOMEM;
- sc->ghl_cr->bRequestType =
+ cr->bRequestType =
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT;
- sc->ghl_cr->bRequest = USB_REQ_SET_CONFIGURATION;
- sc->ghl_cr->wValue = cpu_to_le16(ghl_ps3wiiu_magic_value);
- sc->ghl_cr->wIndex = 0;
- sc->ghl_cr->wLength = cpu_to_le16(poke_size);
- memcpy(sc->ghl_databuf, ghl_ps3wiiu_magic_data, poke_size);
-
+ cr->bRequest = USB_REQ_SET_CONFIGURATION;
+ cr->wValue = cpu_to_le16(ghl_ps3wiiu_magic_value);
+ cr->wIndex = 0;
+ cr->wLength = cpu_to_le16(poke_size);
+ memcpy(databuf, ghl_ps3wiiu_magic_data, poke_size);
usb_fill_control_urb(
- urb, usbdev, pipe,
- (unsigned char *) sc->ghl_cr, sc->ghl_databuf,
- poke_size, ghl_magic_poke_cb, NULL);
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret < 0) {
- kfree(sc->ghl_databuf);
- kfree(sc->ghl_cr);
- }
- usb_free_urb(urb);
-
-resched:
- /* Reschedule for next time */
- mod_timer(&sc->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
+ sc->ghl_urb, usbdev, pipe,
+ (unsigned char *) cr, databuf, poke_size,
+ ghl_magic_poke_cb, sc);
+ return 0;
}
static int guitar_mapping(struct hid_device *hdev, struct hid_input *hi,
@@ -2981,6 +2968,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
int ret;
unsigned long quirks = id->driver_data;
struct sony_sc *sc;
+ struct usb_device *usbdev;
unsigned int connect_mask = HID_CONNECT_DEFAULT;
if (!strcmp(hdev->name, "FutureMax Dance Mat"))
@@ -3000,6 +2988,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
sc->quirks = quirks;
hid_set_drvdata(hdev, sc);
sc->hdev = hdev;
+ usbdev = to_usb_device(sc->hdev->dev.parent->parent);
ret = hid_parse(hdev);
if (ret) {
@@ -3042,6 +3031,15 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
if (sc->quirks & GHL_GUITAR_PS3WIIU) {
+ sc->ghl_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!sc->ghl_urb)
+ return -ENOMEM;
+ ret = ghl_init_urb(sc, usbdev);
+ if (ret) {
+ hid_err(hdev, "error preparing URB\n");
+ return ret;
+ }
+
timer_setup(&sc->ghl_poke_timer, ghl_magic_poke, 0);
mod_timer(&sc->ghl_poke_timer,
jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
@@ -3054,8 +3052,10 @@ static void sony_remove(struct hid_device *hdev)
{
struct sony_sc *sc = hid_get_drvdata(hdev);
- if (sc->quirks & GHL_GUITAR_PS3WIIU)
+ if (sc->quirks & GHL_GUITAR_PS3WIIU) {
del_timer_sync(&sc->ghl_poke_timer);
+ usb_free_urb(sc->ghl_urb);
+ }
hid_hw_close(hdev);
diff --git a/drivers/hid/hid-thrustmaster.c b/drivers/hid/hid-thrustmaster.c
index f643b1cb112d..cdc7d82ae9ed 100644
--- a/drivers/hid/hid-thrustmaster.c
+++ b/drivers/hid/hid-thrustmaster.c
@@ -311,12 +311,13 @@ static int thrustmaster_probe(struct hid_device *hdev, const struct hid_device_i
goto error4;
}
- tm_wheel->change_request = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ tm_wheel->change_request = kmemdup(&change_request,
+ sizeof(struct usb_ctrlrequest),
+ GFP_KERNEL);
if (!tm_wheel->change_request) {
ret = -ENOMEM;
goto error5;
}
- memcpy(tm_wheel->change_request, &change_request, sizeof(struct usb_ctrlrequest));
tm_wheel->usb_dev = interface_to_usbdev(to_usb_interface(hdev->dev.parent));
hid_set_drvdata(hdev, tm_wheel);
diff --git a/drivers/hid/intel-ish-hid/Kconfig b/drivers/hid/intel-ish-hid/Kconfig
index c6c9cfe2475e..689da84a520d 100644
--- a/drivers/hid/intel-ish-hid/Kconfig
+++ b/drivers/hid/intel-ish-hid/Kconfig
@@ -5,6 +5,7 @@ menu "Intel ISH HID support"
config INTEL_ISH_HID
tristate "Intel Integrated Sensor Hub"
default n
+ depends on X86
select HID
help
The Integrated Sensor Hub (ISH) enables the ability to offload
diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c
index 47bbeb8b492b..45e0c7b1c9ec 100644
--- a/drivers/hid/intel-ish-hid/ipc/ipc.c
+++ b/drivers/hid/intel-ish-hid/ipc/ipc.c
@@ -544,7 +544,7 @@ static int ish_fw_reset_handler(struct ishtp_device *dev)
#define TIMEOUT_FOR_HW_RDY_MS 300
/**
- * ish_fw_reset_work_fn() - FW reset worker function
+ * fw_reset_work_fn() - FW reset worker function
* @unused: not used
*
* Call ish_fw_reset_handler to complete FW reset
@@ -889,6 +889,29 @@ static uint32_t ish_ipc_get_header(struct ishtp_device *dev, int length,
return drbl_val;
}
+/**
+ * _dma_no_cache_snooping()
+ *
+ * Check on current platform, DMA supports cache snooping or not.
+ * This callback is used to notify uplayer driver if manully cache
+ * flush is needed when do DMA operation.
+ *
+ * Please pay attention to this callback implementation, if declare
+ * having cache snooping on a cache snooping not supported platform
+ * will cause uplayer driver receiving mismatched data; and if
+ * declare no cache snooping on a cache snooping supported platform
+ * will cause cache be flushed twice and performance hit.
+ *
+ * @dev: ishtp device pointer
+ *
+ * Return: false - has cache snooping capability
+ * true - no cache snooping, need manually cache flush
+ */
+static bool _dma_no_cache_snooping(struct ishtp_device *dev)
+{
+ return dev->pdev->device == EHL_Ax_DEVICE_ID;
+}
+
static const struct ishtp_hw_ops ish_hw_ops = {
.hw_reset = _ish_hw_reset,
.ipc_reset = _ish_ipc_reset,
@@ -897,7 +920,8 @@ static const struct ishtp_hw_ops ish_hw_ops = {
.write = write_ipc_to_queue,
.get_fw_status = _ish_read_fw_sts_reg,
.sync_fw_clock = _ish_sync_fw_clock,
- .ishtp_read_hdr = _ishtp_read_hdr
+ .ishtp_read_hdr = _ishtp_read_hdr,
+ .dma_no_cache_snooping = _dma_no_cache_snooping
};
/**
diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
index a6d5173ac003..1c5039081db2 100644
--- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c
+++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
@@ -263,7 +263,6 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work)
struct pci_dev *pdev = to_pci_dev(ish_resume_device);
struct ishtp_device *dev = pci_get_drvdata(pdev);
uint32_t fwsts = dev->ops->get_fw_status(dev);
- int ret;
if (ish_should_leave_d0i3(pdev) && !dev->suspend_flag
&& IPC_IS_ISH_ILUP(fwsts)) {
@@ -275,7 +274,7 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work)
/* Waiting to get resume response */
if (dev->resume_flag)
- ret = wait_event_interruptible_timeout(dev->resume_wait,
+ wait_event_interruptible_timeout(dev->resume_wait,
!dev->resume_flag,
msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS));
diff --git a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c
index 6cf59fd26ad7..1b486f262747 100644
--- a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c
+++ b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c
@@ -31,13 +31,13 @@
/**
* enum ish_loader_commands - ISH loader host commands.
- * LOADER_CMD_XFER_QUERY Query the Shim firmware loader for
+ * @LOADER_CMD_XFER_QUERY: Query the Shim firmware loader for
* capabilities
- * LOADER_CMD_XFER_FRAGMENT Transfer one firmware image fragment at a
+ * @LOADER_CMD_XFER_FRAGMENT: Transfer one firmware image fragment at a
* time. The command may be executed
* multiple times until the entire firmware
* image is downloaded to SRAM.
- * LOADER_CMD_START Start executing the main firmware.
+ * @LOADER_CMD_START: Start executing the main firmware.
*/
enum ish_loader_commands {
LOADER_CMD_XFER_QUERY = 0,
@@ -95,6 +95,7 @@ static int dma_buf_size_limit = 4 * PAGE_SIZE;
/**
* struct loader_msg_hdr - Header for ISH Loader commands.
* @command: LOADER_CMD* commands. Bit 7 is the response.
+ * @reserved: Reserved space
* @status: Command response status. Non 0, is error
* condition.
*
@@ -173,16 +174,16 @@ struct loader_start {
* struct response_info - Encapsulate firmware response related
* information for passing between function
* loader_cl_send() and process_recv() callback.
- * @data Copy the data received from firmware here.
- * @max_size Max size allocated for the @data buffer. If the
+ * @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 Returns 0 for success, negative error code for a
+ * @size: Actual size of data received from firmware.
+ * @error: Returns 0 for success, negative error code for a
* failure in function process_recv().
- * @received Set to true on receiving a valid firmware
+ * @received: Set to true on receiving a valid firmware
* response to host command
- * @wait_queue Wait queue for Host firmware loading where the
+ * @wait_queue: Wait queue for Host firmware loading where the
* client sends message to ISH firmware and waits
* for response
*/
@@ -195,13 +196,13 @@ struct response_info {
wait_queue_head_t wait_queue;
};
-/**
+/*
* struct ishtp_cl_data - Encapsulate per ISH-TP Client Data.
* @work_ishtp_reset: Work queue for reset handling.
* @work_fw_load: Work queue for host firmware loading.
- * @flag_retry Flag for indicating host firmware loading should
+ * @flag_retry: Flag for indicating host firmware loading should
* be retried.
- * @retry_count Count the number of retries.
+ * @retry_count: Count the number of retries.
*
* This structure is used to store data per client.
*/
@@ -240,8 +241,8 @@ struct ishtp_cl_data {
/**
* get_firmware_variant() - Gets the filename of firmware image to be
* loaded based on platform variant.
- * @client_data Client data instance.
- * @filename Returns firmware filename.
+ * @client_data: Client data instance.
+ * @filename: Returns firmware filename.
*
* Queries the firmware-name device property string.
*
@@ -266,11 +267,11 @@ static int get_firmware_variant(struct ishtp_cl_data *client_data,
/**
* loader_cl_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 copied.
+ * @out_msg: Message buffer to be sent to firmware
+ * @out_size: Size of out going message
+ * @in_msg: Message buffer where the incoming data copied.
* This buffer is allocated by calling
- * @in_size Max size of incoming message
+ * @in_size: Max size of incoming message
*
* Return: Number of bytes copied in the in_msg on success, negative
* error code on failure.
@@ -435,7 +436,7 @@ end:
/**
* loader_cl_event_cb() - bus driver callback for incoming message
- * @device: Pointer to the ishtp client device for which this
+ * @cl_device: Pointer to the ishtp client device for which this
* message is targeted
*
* Remove the packet from the list and process the message by calling
@@ -455,7 +456,7 @@ static void loader_cl_event_cb(struct ishtp_cl_device *cl_device)
/**
* ish_query_loader_prop() - Query ISH Shim firmware loader
* @client_data: Client data instance
- * @fw: Poiner to firmware data struct in host memory
+ * @fw: Pointer to firmware data struct in host memory
* @fw_info: Loader firmware properties
*
* This function queries the ISH Shim firmware loader for capabilities.
@@ -536,7 +537,7 @@ static int ish_query_loader_prop(struct ishtp_cl_data *client_data,
}
/**
- * ish_fw_xfer_ishtp() Loads ISH firmware using ishtp interface
+ * ish_fw_xfer_ishtp() - Loads ISH firmware using ishtp interface
* @client_data: Client data instance
* @fw: Pointer to firmware data struct in host memory
*
@@ -733,7 +734,7 @@ end_err_dma_buf_release:
}
/**
- * ish_fw_start() Start executing ISH main firmware
+ * ish_fw_start() - Start executing ISH main firmware
* @client_data: client data instance
*
* This function sends message to Shim firmware loader to start
@@ -756,7 +757,7 @@ static int ish_fw_start(struct ishtp_cl_data *client_data)
}
/**
- * load_fw_from_host() Loads ISH firmware from host
+ * load_fw_from_host() - Loads ISH firmware from host
* @client_data: Client data instance
*
* This function loads the ISH firmware to ISH SRAM and starts execution
@@ -1015,7 +1016,7 @@ static int loader_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
*
* Return: 0
*/
-static int loader_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
+static void loader_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
{
struct ishtp_cl_data *client_data;
struct ishtp_cl *loader_ishtp_cl = ishtp_get_drvdata(cl_device);
@@ -1032,8 +1033,6 @@ static int loader_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
cancel_work_sync(&client_data->work_ishtp_reset);
loader_deinit(loader_ishtp_cl);
ishtp_put_device(cl_device);
-
- return 0;
}
/**
diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c
index 6ba944b40fdb..6b1fa971b33e 100644
--- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c
+++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c
@@ -11,6 +11,11 @@
#include <linux/sched.h>
#include "ishtp-hid.h"
+/* ISH Transport protocol (ISHTP in short) GUID */
+static const guid_t hid_ishtp_guid =
+ GUID_INIT(0x33AECD58, 0xB679, 0x4E54,
+ 0x9B, 0xD9, 0xA0, 0x4D, 0x34, 0xF0, 0xC2, 0x26);
+
/* Rx ring buffer pool size */
#define HID_CL_RX_RING_SIZE 32
#define HID_CL_TX_RING_SIZE 16
@@ -18,7 +23,7 @@
#define cl_data_to_dev(client_data) ishtp_device(client_data->cl_device)
/**
- * report_bad_packets() - Report bad packets
+ * report_bad_packet() - Report bad packets
* @hid_ishtp_cl: Client instance to get stats
* @recv_buf: Raw received host interface message
* @cur_pos: Current position index in payload
@@ -779,7 +784,7 @@ static void hid_ishtp_cl_reset_handler(struct work_struct *work)
}
}
-void (*hid_print_trace)(void *unused, const char *format, ...);
+ishtp_print_log ishtp_hid_print_trace;
/**
* hid_ishtp_cl_probe() - ISHTP client driver probe
@@ -818,7 +823,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
INIT_WORK(&client_data->work, hid_ishtp_cl_reset_handler);
- hid_print_trace = ishtp_trace_callback(cl_device);
+ ishtp_hid_print_trace = ishtp_trace_callback(cl_device);
rv = hid_ishtp_cl_init(hid_ishtp_cl, 0);
if (rv) {
@@ -838,7 +843,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
*
* Return: 0
*/
-static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
+static void hid_ishtp_cl_remove(struct ishtp_cl_device *cl_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);
@@ -856,8 +861,6 @@ static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
hid_ishtp_cl = NULL;
client_data->num_hid_devices = 0;
-
- return 0;
}
/**
diff --git a/drivers/hid/intel-ish-hid/ishtp-hid.c b/drivers/hid/intel-ish-hid/ishtp-hid.c
index 393bed0abee9..14c271d7d8a9 100644
--- a/drivers/hid/intel-ish-hid/ishtp-hid.c
+++ b/drivers/hid/intel-ish-hid/ishtp-hid.c
@@ -254,7 +254,7 @@ err_hid_data:
}
/**
- * ishtp_hid_probe() - Remove registered hid device
+ * ishtp_hid_remove() - Remove registered hid device
* @client_data: client data pointer
*
* This function is used to destroy allocatd HID device.
diff --git a/drivers/hid/intel-ish-hid/ishtp-hid.h b/drivers/hid/intel-ish-hid/ishtp-hid.h
index 5ffd0da3cf1f..f88443a7d935 100644
--- a/drivers/hid/intel-ish-hid/ishtp-hid.h
+++ b/drivers/hid/intel-ish-hid/ishtp-hid.h
@@ -16,14 +16,9 @@
#define IS_RESPONSE 0x80
/* Used to dump to Linux trace buffer, if enabled */
-extern void (*hid_print_trace)(void *unused, const char *format, ...);
+extern ishtp_print_log ishtp_hid_print_trace;
#define hid_ishtp_trace(client, ...) \
- (hid_print_trace)(NULL, __VA_ARGS__)
-
-/* ISH Transport protocol (ISHTP in short) GUID */
-static const guid_t hid_ishtp_guid =
- GUID_INIT(0x33AECD58, 0xB679, 0x4E54,
- 0x9B, 0xD9, 0xA0, 0x4D, 0x34, 0xF0, 0xC2, 0x26);
+ (ishtp_hid_print_trace)(NULL, __VA_ARGS__)
/* ISH HID message structure */
struct hostif_msg_hdr {
diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c
index bba29cd36d29..f0802b047ed8 100644
--- a/drivers/hid/intel-ish-hid/ishtp/bus.c
+++ b/drivers/hid/intel-ish-hid/ishtp/bus.c
@@ -164,6 +164,7 @@ EXPORT_SYMBOL(ishtp_fw_cl_get_client);
/**
* ishtp_get_fw_client_id() - Get fw client id
+ * @fw_client: firmware client used to fetch the ID
*
* This interface is used to reset HW get FW client id.
*
@@ -257,24 +258,17 @@ static int ishtp_cl_bus_match(struct device *dev, struct device_driver *drv)
static int ishtp_cl_device_remove(struct device *dev)
{
struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
- struct ishtp_cl_driver *driver;
-
- if (!device || !dev->driver)
- return 0;
+ struct ishtp_cl_driver *driver = to_ishtp_cl_driver(dev->driver);
if (device->event_cb) {
device->event_cb = NULL;
cancel_work_sync(&device->event_work);
}
- driver = to_ishtp_cl_driver(dev->driver);
- if (!driver->remove) {
- dev->driver = NULL;
+ if (driver->remove)
+ driver->remove(device);
- return 0;
- }
-
- return driver->remove(device);
+ return 0;
}
/**
@@ -842,6 +836,7 @@ int ishtp_use_dma_transfer(void)
/**
* ishtp_device() - Return device pointer
+ * @device: ISH-TP client device instance
*
* This interface is used to return device pointer from ishtp_cl_device
* instance.
@@ -858,6 +853,7 @@ EXPORT_SYMBOL(ishtp_device);
* ishtp_get_pci_device() - Return PCI device dev pointer
* This interface is used to return PCI device pointer
* from ishtp_cl_device instance.
+ * @device: ISH-TP client device instance
*
* Return: device *.
*/
@@ -869,12 +865,13 @@ EXPORT_SYMBOL(ishtp_get_pci_device);
/**
* ishtp_trace_callback() - Return trace callback
+ * @cl_device: ISH-TP client device instance
*
* This interface is used to return trace callback function pointer.
*
- * Return: void *.
+ * Return: *ishtp_print_log()
*/
-void *ishtp_trace_callback(struct ishtp_cl_device *cl_device)
+ishtp_print_log ishtp_trace_callback(struct ishtp_cl_device *cl_device)
{
return cl_device->ishtp_dev->print_log;
}
@@ -882,6 +879,7 @@ EXPORT_SYMBOL(ishtp_trace_callback);
/**
* ish_hw_reset() - Call HW reset IPC callback
+ * @dev: ISHTP device instance
*
* This interface is used to reset HW in case of error.
*
diff --git a/drivers/hid/intel-ish-hid/ishtp/client.c b/drivers/hid/intel-ish-hid/ishtp/client.c
index 1cc157126fce..405e0d5212cc 100644
--- a/drivers/hid/intel-ish-hid/ishtp/client.c
+++ b/drivers/hid/intel-ish-hid/ishtp/client.c
@@ -10,6 +10,7 @@
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
#include "hbm.h"
#include "client.h"
@@ -111,7 +112,7 @@ static void ishtp_cl_init(struct ishtp_cl *cl, struct ishtp_device *dev)
/**
* ishtp_cl_allocate() - allocates client structure and sets it up.
- * @dev: ishtp device
+ * @cl_device: ishtp client device
*
* Allocate memory for new client device and call to initialize each field.
*
@@ -263,7 +264,6 @@ EXPORT_SYMBOL(ishtp_cl_unlink);
int ishtp_cl_disconnect(struct ishtp_cl *cl)
{
struct ishtp_device *dev;
- int err;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
@@ -283,7 +283,7 @@ int ishtp_cl_disconnect(struct ishtp_cl *cl)
return -ENODEV;
}
- err = wait_event_interruptible_timeout(cl->wait_ctrl_res,
+ wait_event_interruptible_timeout(cl->wait_ctrl_res,
(dev->dev_state != ISHTP_DEV_ENABLED ||
cl->state == ISHTP_CL_DISCONNECTED),
ishtp_secs_to_jiffies(ISHTP_CL_CONNECT_TIMEOUT));
@@ -773,6 +773,14 @@ static void ishtp_cl_send_msg_dma(struct ishtp_device *dev,
/* write msg to dma buf */
memcpy(msg_addr, cl_msg->send_buf.data, cl_msg->send_buf.size);
+ /*
+ * if current fw don't support cache snooping, driver have to
+ * flush the cache manually.
+ */
+ if (dev->ops->dma_no_cache_snooping &&
+ dev->ops->dma_no_cache_snooping(dev))
+ clflush_cache_range(msg_addr, cl_msg->send_buf.size);
+
/* send dma_xfer hbm msg */
off = msg_addr - (unsigned char *)dev->ishtp_host_dma_tx_buf;
ishtp_hbm_hdr(&hdr, sizeof(struct dma_xfer_hbm));
@@ -997,6 +1005,15 @@ void recv_ishtp_cl_msg_dma(struct ishtp_device *dev, void *msg,
}
buffer = rb->buffer.data;
+
+ /*
+ * if current fw don't support cache snooping, driver have to
+ * flush the cache manually.
+ */
+ if (dev->ops->dma_no_cache_snooping &&
+ dev->ops->dma_no_cache_snooping(dev))
+ clflush_cache_range(msg, hbm->msg_length);
+
memcpy(buffer, msg, hbm->msg_length);
rb->buf_idx = hbm->msg_length;
diff --git a/drivers/hid/intel-ish-hid/ishtp/hbm.c b/drivers/hid/intel-ish-hid/ishtp/hbm.c
index 30a91d068306..9c031a06e4c4 100644
--- a/drivers/hid/intel-ish-hid/ishtp/hbm.c
+++ b/drivers/hid/intel-ish-hid/ishtp/hbm.c
@@ -398,7 +398,7 @@ static void ishtp_hbm_cl_connect_res(struct ishtp_device *dev,
}
/**
- * ishtp_client_disconnect_request() - Receive disconnect request
+ * ishtp_hbm_fw_disconnect_req() - Receive disconnect request
* @dev: ISHTP device instance
* @disconnect_req: disconnect request structure
*
@@ -430,7 +430,7 @@ static void ishtp_hbm_fw_disconnect_req(struct ishtp_device *dev,
}
/**
- * ishtp_hbm_dma_xfer_ack(() - Receive transfer ACK
+ * ishtp_hbm_dma_xfer_ack() - Receive transfer ACK
* @dev: ISHTP device instance
* @dma_xfer: HBM transfer message
*
@@ -914,7 +914,7 @@ static inline void fix_cl_hdr(struct ishtp_msg_hdr *hdr, size_t length,
/*** Suspend and resume notification ***/
static uint32_t current_state;
-static uint32_t supported_states = 0 | SUSPEND_STATE_BIT;
+static uint32_t supported_states = SUSPEND_STATE_BIT | CONNECTED_STANDBY_STATE_BIT;
/**
* ishtp_send_suspend() - Send suspend message to FW
@@ -933,7 +933,7 @@ void ishtp_send_suspend(struct ishtp_device *dev)
memset(&state_status_msg, 0, len);
state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
state_status_msg.supported_states = supported_states;
- current_state |= SUSPEND_STATE_BIT;
+ current_state |= (SUSPEND_STATE_BIT | CONNECTED_STANDBY_STATE_BIT);
dev->print_log(dev, "%s() sends SUSPEND notification\n", __func__);
state_status_msg.states_status = current_state;
@@ -959,7 +959,7 @@ void ishtp_send_resume(struct ishtp_device *dev)
memset(&state_status_msg, 0, len);
state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
state_status_msg.supported_states = supported_states;
- current_state &= ~SUSPEND_STATE_BIT;
+ current_state &= ~(CONNECTED_STANDBY_STATE_BIT | SUSPEND_STATE_BIT);
dev->print_log(dev, "%s() sends RESUME notification\n", __func__);
state_status_msg.states_status = current_state;
diff --git a/drivers/hid/intel-ish-hid/ishtp/hbm.h b/drivers/hid/intel-ish-hid/ishtp/hbm.h
index 7c445b203f2a..08f3f3ceb18c 100644
--- a/drivers/hid/intel-ish-hid/ishtp/hbm.h
+++ b/drivers/hid/intel-ish-hid/ishtp/hbm.h
@@ -235,6 +235,7 @@ struct dma_xfer_hbm {
#define SYSTEM_STATE_QUERY_SUBSCRIBERS 0x3
#define SYSTEM_STATE_STATE_CHANGE_REQ 0x4
/*indicates suspend and resume states*/
+#define CONNECTED_STANDBY_STATE_BIT (1<<0)
#define SUSPEND_STATE_BIT (1<<1)
struct ish_system_states_header {
diff --git a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h
index 1cc6364aa957..32142c7d9a04 100644
--- a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h
+++ b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h
@@ -10,6 +10,7 @@
#include <linux/types.h>
#include <linux/spinlock.h>
+#include <linux/intel-ish-client-if.h>
#include "bus.h"
#include "hbm.h"
@@ -118,6 +119,7 @@ struct ishtp_hw_ops {
unsigned long buffer_length);
uint32_t (*get_fw_status)(struct ishtp_device *dev);
void (*sync_fw_clock)(struct ishtp_device *dev);
+ bool (*dma_no_cache_snooping)(struct ishtp_device *dev);
};
/**
@@ -202,8 +204,7 @@ struct ishtp_device {
uint64_t ishtp_host_dma_rx_buf_phys;
/* Dump to trace buffers if enabled*/
- __printf(2, 3) void (*print_log)(struct ishtp_device *dev,
- const char *format, ...);
+ ishtp_print_log print_log;
/* Debug stats */
unsigned int ipc_rx_cnt;
diff --git a/drivers/hid/surface-hid/surface_hid.c b/drivers/hid/surface-hid/surface_hid.c
index 3477b31611ae..a3a70e4f3f6c 100644
--- a/drivers/hid/surface-hid/surface_hid.c
+++ b/drivers/hid/surface-hid/surface_hid.c
@@ -143,7 +143,7 @@ static int ssam_hid_get_raw_report(struct surface_hid_device *shid, u8 rprt_id,
rqst.target_id = shid->uid.target;
rqst.instance_id = shid->uid.instance;
rqst.command_id = SURFACE_HID_CID_GET_FEATURE_REPORT;
- rqst.flags = 0;
+ rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
rqst.length = sizeof(rprt_id);
rqst.payload = &rprt_id;
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 4e9077363c96..06130dc431a0 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -1304,6 +1304,13 @@ static int usbhid_idle(struct hid_device *hid, int report, int idle,
return hid_set_idle(dev, ifnum, report, idle);
}
+static bool usbhid_may_wakeup(struct hid_device *hid)
+{
+ struct usb_device *dev = hid_to_usb_dev(hid);
+
+ return device_may_wakeup(&dev->dev);
+}
+
struct hid_ll_driver usb_hid_driver = {
.parse = usbhid_parse,
.start = usbhid_start,
@@ -1316,6 +1323,7 @@ struct hid_ll_driver usb_hid_driver = {
.raw_request = usbhid_raw_request,
.output_report = usbhid_output_report,
.idle = usbhid_idle,
+ .may_wakeup = usbhid_may_wakeup,
};
EXPORT_SYMBOL_GPL(usb_hid_driver);
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index e22434dfc9ef..df02002066ce 100644
--- a/drivers/hid/usbhid/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -239,11 +239,11 @@ static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
return -1;
if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
return -1;
- if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
+ if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_KERNEL, &kbd->new_dma)))
return -1;
if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
return -1;
- if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
+ if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_KERNEL, &kbd->leds_dma)))
return -1;
return 0;
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index 073127e65ac1..c89332017d5d 100644
--- a/drivers/hid/usbhid/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -130,7 +130,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
if (!mouse || !input_dev)
goto fail1;
- mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma);
+ mouse->data = usb_alloc_coherent(dev, 8, GFP_KERNEL, &mouse->data_dma);
if (!mouse->data)
goto fail1;
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index 71c886245dbf..8f16654eca09 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -122,7 +122,7 @@
#define WACOM_HID_WD_TOUCHONOFF (WACOM_HID_UP_WACOMDIGITIZER | 0x0454)
#define WACOM_HID_WD_BATTERY_LEVEL (WACOM_HID_UP_WACOMDIGITIZER | 0x043b)
#define WACOM_HID_WD_EXPRESSKEY00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0910)
-#define WACOM_HID_WD_EXPRESSKEYCAP00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0950)
+#define WACOM_HID_WD_EXPRESSKEYCAP00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0940)
#define WACOM_HID_WD_MODE_CHANGE (WACOM_HID_UP_WACOMDIGITIZER | 0x0980)
#define WACOM_HID_WD_MUTE_DEVICE (WACOM_HID_UP_WACOMDIGITIZER | 0x0981)
#define WACOM_HID_WD_CONTROLPANEL (WACOM_HID_UP_WACOMDIGITIZER | 0x0982)
diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile
index 94daf8240c95..d76df5c8c2a9 100644
--- a/drivers/hv/Makefile
+++ b/drivers/hv/Makefile
@@ -11,3 +11,6 @@ hv_vmbus-y := vmbus_drv.o \
channel_mgmt.o ring_buffer.o hv_trace.o
hv_vmbus-$(CONFIG_HYPERV_TESTING) += hv_debugfs.o
hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_fcopy.o hv_utils_transport.o
+
+# Code that must be built-in
+obj-$(subst m,y,$(CONFIG_HYPERV)) += hv_common.o
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index c2635e913a92..f3761c73b074 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -662,12 +662,15 @@ static int __vmbus_open(struct vmbus_channel *newchannel,
newchannel->onchannel_callback = onchannelcallback;
newchannel->channel_callback_context = context;
- err = hv_ringbuffer_init(&newchannel->outbound, page, send_pages);
+ if (!newchannel->max_pkt_size)
+ newchannel->max_pkt_size = VMBUS_DEFAULT_MAX_PKT_SIZE;
+
+ err = hv_ringbuffer_init(&newchannel->outbound, page, send_pages, 0);
if (err)
goto error_clean_ring;
- err = hv_ringbuffer_init(&newchannel->inbound,
- &page[send_pages], recv_pages);
+ err = hv_ringbuffer_init(&newchannel->inbound, &page[send_pages],
+ recv_pages, newchannel->max_pkt_size);
if (err)
goto error_clean_ring;
@@ -1186,15 +1189,14 @@ EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw);
* vmbus_next_request_id - Returns a new request id. It is also
* the index at which the guest memory address is stored.
* Uses a spin lock to avoid race conditions.
- * @rqstor: Pointer to the requestor struct
+ * @channel: Pointer to the VMbus channel struct
* @rqst_add: Guest memory address to be stored in the array
*/
-u64 vmbus_next_request_id(struct vmbus_requestor *rqstor, u64 rqst_addr)
+u64 vmbus_next_request_id(struct vmbus_channel *channel, u64 rqst_addr)
{
+ struct vmbus_requestor *rqstor = &channel->requestor;
unsigned long flags;
u64 current_id;
- const struct vmbus_channel *channel =
- container_of(rqstor, const struct vmbus_channel, requestor);
/* Check rqstor has been initialized */
if (!channel->rqstor_size)
@@ -1228,16 +1230,15 @@ EXPORT_SYMBOL_GPL(vmbus_next_request_id);
/*
* vmbus_request_addr - Returns the memory address stored at @trans_id
* in @rqstor. Uses a spin lock to avoid race conditions.
- * @rqstor: Pointer to the requestor struct
+ * @channel: Pointer to the VMbus channel struct
* @trans_id: Request id sent back from Hyper-V. Becomes the requestor's
* next request id.
*/
-u64 vmbus_request_addr(struct vmbus_requestor *rqstor, u64 trans_id)
+u64 vmbus_request_addr(struct vmbus_channel *channel, u64 trans_id)
{
+ struct vmbus_requestor *rqstor = &channel->requestor;
unsigned long flags;
u64 req_addr;
- const struct vmbus_channel *channel =
- container_of(rqstor, const struct vmbus_channel, requestor);
/* Check rqstor has been initialized */
if (!channel->rqstor_size)
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index 311cd005b3be..5e479d54918c 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -232,8 +232,10 @@ int vmbus_connect(void)
*/
for (i = 0; ; i++) {
- if (i == ARRAY_SIZE(vmbus_versions))
+ if (i == ARRAY_SIZE(vmbus_versions)) {
+ ret = -EDOM;
goto cleanup;
+ }
version = vmbus_versions[i];
if (version > max_version)
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index 58af84e30144..7f11ea07d698 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -1010,7 +1010,6 @@ static void hot_add_req(struct work_struct *dummy)
* that need to be hot-added while ensuring the alignment
* and size requirements of Linux as it relates to hot-add.
*/
- region_start = pg_start;
region_size = (pfn_cnt / HA_CHUNK) * HA_CHUNK;
if (pfn_cnt % HA_CHUNK)
region_size += HA_CHUNK;
diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c
new file mode 100644
index 000000000000..7f42da98d377
--- /dev/null
+++ b/drivers/hv/hv_common.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Architecture neutral utility routines for interacting with
+ * Hyper-V. This file is specifically for code that must be
+ * built-in to the kernel image when CONFIG_HYPERV is set
+ * (vs. being in a module) because it is called from architecture
+ * specific code under arch/.
+ *
+ * Copyright (C) 2021, Microsoft, Inc.
+ *
+ * Author : Michael Kelley <mikelley@microsoft.com>
+ */
+
+#include <linux/types.h>
+#include <linux/export.h>
+#include <linux/bitfield.h>
+#include <asm/hyperv-tlfs.h>
+#include <asm/mshyperv.h>
+
+
+/* Bit mask of the extended capability to query: see HV_EXT_CAPABILITY_xxx */
+bool hv_query_ext_cap(u64 cap_query)
+{
+ /*
+ * The address of the 'hv_extended_cap' variable will be used as an
+ * output parameter to the hypercall below and so it should be
+ * compatible with 'virt_to_phys'. Which means, it's address should be
+ * directly mapped. Use 'static' to keep it compatible; stack variables
+ * can be virtually mapped, making them incompatible with
+ * 'virt_to_phys'.
+ * Hypercall input/output addresses should also be 8-byte aligned.
+ */
+ static u64 hv_extended_cap __aligned(8);
+ static bool hv_extended_cap_queried;
+ u64 status;
+
+ /*
+ * Querying extended capabilities is an extended hypercall. Check if the
+ * partition supports extended hypercall, first.
+ */
+ if (!(ms_hyperv.priv_high & HV_ENABLE_EXTENDED_HYPERCALLS))
+ return false;
+
+ /* Extended capabilities do not change at runtime. */
+ if (hv_extended_cap_queried)
+ return hv_extended_cap & cap_query;
+
+ status = hv_do_hypercall(HV_EXT_CALL_QUERY_CAPABILITIES, NULL,
+ &hv_extended_cap);
+
+ /*
+ * The query extended capabilities hypercall should not fail under
+ * any normal circumstances. Avoid repeatedly making the hypercall, on
+ * error.
+ */
+ hv_extended_cap_queried = true;
+ if (!hv_result_success(status)) {
+ pr_err("Hyper-V: Extended query capabilities hypercall failed 0x%llx\n",
+ status);
+ return false;
+ }
+
+ return hv_extended_cap & cap_query;
+}
+EXPORT_SYMBOL_GPL(hv_query_ext_cap);
diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index 59ce85e00a02..660036da7449 100644
--- a/drivers/hv/hv_fcopy.c
+++ b/drivers/hv/hv_fcopy.c
@@ -349,6 +349,7 @@ int hv_fcopy_init(struct hv_util_service *srv)
{
recv_buffer = srv->recv_buffer;
fcopy_transaction.recv_channel = srv->channel;
+ fcopy_transaction.recv_channel->max_pkt_size = HV_HYP_PAGE_SIZE * 2;
/*
* When this driver loads, the user level daemon that
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index b49962d312ce..c698592b83e4 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -757,6 +757,7 @@ hv_kvp_init(struct hv_util_service *srv)
{
recv_buffer = srv->recv_buffer;
kvp_transaction.recv_channel = srv->channel;
+ kvp_transaction.recv_channel->max_pkt_size = HV_HYP_PAGE_SIZE * 4;
/*
* When this driver loads, the user level daemon that
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index e4aefeb330da..136576cba26f 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -750,8 +750,8 @@ static int hv_timesync_init(struct hv_util_service *srv)
*/
hv_ptp_clock = ptp_clock_register(&ptp_hyperv_info, NULL);
if (IS_ERR_OR_NULL(hv_ptp_clock)) {
- pr_err("cannot register PTP clock: %ld\n",
- PTR_ERR(hv_ptp_clock));
+ pr_err("cannot register PTP clock: %d\n",
+ PTR_ERR_OR_ZERO(hv_ptp_clock));
hv_ptp_clock = NULL;
}
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 9416e09ebd58..42f3d9d123a1 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -174,7 +174,7 @@ extern int hv_synic_cleanup(unsigned int cpu);
void hv_ringbuffer_pre_init(struct vmbus_channel *channel);
int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
- struct page *pages, u32 pagecnt);
+ struct page *pages, u32 pagecnt, u32 max_pkt_size);
void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
index 374f8afbf8a5..2aee356840a2 100644
--- a/drivers/hv/ring_buffer.c
+++ b/drivers/hv/ring_buffer.c
@@ -181,7 +181,7 @@ void hv_ringbuffer_pre_init(struct vmbus_channel *channel)
/* Initialize the ring buffer. */
int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
- struct page *pages, u32 page_cnt)
+ struct page *pages, u32 page_cnt, u32 max_pkt_size)
{
int i;
struct page **pages_wraparound;
@@ -223,6 +223,14 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
sizeof(struct hv_ring_buffer);
ring_info->priv_read_index = 0;
+ /* Initialize buffer that holds copies of incoming packets */
+ if (max_pkt_size) {
+ ring_info->pkt_buffer = kzalloc(max_pkt_size, GFP_KERNEL);
+ if (!ring_info->pkt_buffer)
+ return -ENOMEM;
+ ring_info->pkt_buffer_size = max_pkt_size;
+ }
+
spin_lock_init(&ring_info->ring_lock);
return 0;
@@ -235,6 +243,9 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
vunmap(ring_info->ring_buffer);
ring_info->ring_buffer = NULL;
mutex_unlock(&ring_info->ring_buffer_mutex);
+
+ kfree(ring_info->pkt_buffer);
+ ring_info->pkt_buffer_size = 0;
}
/* Write to the ring buffer. */
@@ -301,10 +312,12 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
*/
if (desc->flags == VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED) {
- rqst_id = vmbus_next_request_id(&channel->requestor, requestid);
- if (rqst_id == VMBUS_RQST_ERROR) {
- spin_unlock_irqrestore(&outring_info->ring_lock, flags);
- return -EAGAIN;
+ if (channel->next_request_id_callback != NULL) {
+ rqst_id = channel->next_request_id_callback(channel, requestid);
+ if (rqst_id == VMBUS_RQST_ERROR) {
+ spin_unlock_irqrestore(&outring_info->ring_lock, flags);
+ return -EAGAIN;
+ }
}
}
desc = hv_get_ring_buffer(outring_info) + old_write;
@@ -332,7 +345,8 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
if (channel->rescind) {
if (rqst_id != VMBUS_NO_RQSTOR) {
/* Reclaim request ID to avoid leak of IDs */
- vmbus_request_addr(&channel->requestor, rqst_id);
+ if (channel->request_addr_callback != NULL)
+ channel->request_addr_callback(channel, rqst_id);
}
return -ENODEV;
}
@@ -375,7 +389,7 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
memcpy(buffer, (const char *)desc + offset, packetlen);
/* Advance ring index to next packet descriptor */
- __hv_pkt_iter_next(channel, desc);
+ __hv_pkt_iter_next(channel, desc, true);
/* Notify host of update */
hv_pkt_iter_close(channel);
@@ -402,6 +416,22 @@ static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi)
}
/*
+ * Get first vmbus packet without copying it out of the ring buffer
+ */
+struct vmpacket_descriptor *hv_pkt_iter_first_raw(struct vmbus_channel *channel)
+{
+ struct hv_ring_buffer_info *rbi = &channel->inbound;
+
+ hv_debug_delay_test(channel, MESSAGE_DELAY);
+
+ if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
+ return NULL;
+
+ return (struct vmpacket_descriptor *)(hv_get_ring_buffer(rbi) + rbi->priv_read_index);
+}
+EXPORT_SYMBOL_GPL(hv_pkt_iter_first_raw);
+
+/*
* Get first vmbus packet from ring buffer after read_index
*
* If ring buffer is empty, returns NULL and no other action needed.
@@ -409,17 +439,49 @@ static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi)
struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel)
{
struct hv_ring_buffer_info *rbi = &channel->inbound;
- struct vmpacket_descriptor *desc;
+ struct vmpacket_descriptor *desc, *desc_copy;
+ u32 bytes_avail, pkt_len, pkt_offset;
- hv_debug_delay_test(channel, MESSAGE_DELAY);
- if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
+ desc = hv_pkt_iter_first_raw(channel);
+ if (!desc)
return NULL;
- desc = hv_get_ring_buffer(rbi) + rbi->priv_read_index;
- if (desc)
- prefetch((char *)desc + (desc->len8 << 3));
+ bytes_avail = min(rbi->pkt_buffer_size, hv_pkt_iter_avail(rbi));
+
+ /*
+ * Ensure the compiler does not use references to incoming Hyper-V values (which
+ * could change at any moment) when reading local variables later in the code
+ */
+ pkt_len = READ_ONCE(desc->len8) << 3;
+ pkt_offset = READ_ONCE(desc->offset8) << 3;
+
+ /*
+ * If pkt_len is invalid, set it to the smaller of hv_pkt_iter_avail() and
+ * rbi->pkt_buffer_size
+ */
+ if (pkt_len < sizeof(struct vmpacket_descriptor) || pkt_len > bytes_avail)
+ pkt_len = bytes_avail;
+
+ /*
+ * If pkt_offset is invalid, arbitrarily set it to
+ * the size of vmpacket_descriptor
+ */
+ if (pkt_offset < sizeof(struct vmpacket_descriptor) || pkt_offset > pkt_len)
+ pkt_offset = sizeof(struct vmpacket_descriptor);
+
+ /* Copy the Hyper-V packet out of the ring buffer */
+ desc_copy = (struct vmpacket_descriptor *)rbi->pkt_buffer;
+ memcpy(desc_copy, desc, pkt_len);
+
+ /*
+ * Hyper-V could still change len8 and offset8 after the earlier read.
+ * Ensure that desc_copy has legal values for len8 and offset8 that
+ * are consistent with the copy we just made
+ */
+ desc_copy->len8 = pkt_len >> 3;
+ desc_copy->offset8 = pkt_offset >> 3;
- return desc;
+ return desc_copy;
}
EXPORT_SYMBOL_GPL(hv_pkt_iter_first);
@@ -431,7 +493,8 @@ EXPORT_SYMBOL_GPL(hv_pkt_iter_first);
*/
struct vmpacket_descriptor *
__hv_pkt_iter_next(struct vmbus_channel *channel,
- const struct vmpacket_descriptor *desc)
+ const struct vmpacket_descriptor *desc,
+ bool copy)
{
struct hv_ring_buffer_info *rbi = &channel->inbound;
u32 packetlen = desc->len8 << 3;
@@ -444,7 +507,7 @@ __hv_pkt_iter_next(struct vmbus_channel *channel,
rbi->priv_read_index -= dsize;
/* more data? */
- return hv_pkt_iter_first(channel);
+ return copy ? hv_pkt_iter_first(channel) : hv_pkt_iter_first_raw(channel);
}
EXPORT_SYMBOL_GPL(__hv_pkt_iter_next);
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 92cb3f7d21d9..57bbbaa4e8f7 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -25,6 +25,7 @@
#include <linux/delay.h>
#include <linux/notifier.h>
+#include <linux/panic_notifier.h>
#include <linux/ptrace.h>
#include <linux/screen_info.h>
#include <linux/kdebug.h>
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 87624902ea80..e3675377bc5d 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1583,6 +1583,17 @@ config SENSORS_SHT3x
This driver can also be built as a module. If so, the module
will be called sht3x.
+config SENSORS_SHT4x
+ tristate "Sensiron humidity and temperature sensors. SHT4x and compat."
+ depends on I2C
+ select CRC8
+ help
+ If you say yes here you get support for the Sensiron SHT40, SHT41 and
+ SHT45 humidity and temperature sensors.
+
+ This driver can also be built as a module. If so, the module
+ will be called sht4x.
+
config SENSORS_SHTC1
tristate "Sensiron humidity and temperature sensors. SHTC1 and compat."
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 59e78bc212cf..d712c61c1f5e 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -171,6 +171,7 @@ obj-$(CONFIG_SENSORS_SL28CPLD) += sl28cpld-hwmon.o
obj-$(CONFIG_SENSORS_SHT15) += sht15.o
obj-$(CONFIG_SENSORS_SHT21) += sht21.o
obj-$(CONFIG_SENSORS_SHT3x) += sht3x.o
+obj-$(CONFIG_SENSORS_SHT4x) += sht4x.o
obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o
obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
obj-$(CONFIG_SENSORS_SMM665) += smm665.o
diff --git a/drivers/hwmon/bt1-pvt.c b/drivers/hwmon/bt1-pvt.c
index 3e1d56585b91..74ce5211eb75 100644
--- a/drivers/hwmon/bt1-pvt.c
+++ b/drivers/hwmon/bt1-pvt.c
@@ -924,10 +924,8 @@ static int pvt_request_regs(struct pvt_hwmon *pvt)
}
pvt->regs = devm_ioremap_resource(pvt->dev, res);
- if (IS_ERR(pvt->regs)) {
- dev_err(pvt->dev, "Couldn't map PVT registers\n");
+ if (IS_ERR(pvt->regs))
return PTR_ERR(pvt->regs);
- }
return 0;
}
diff --git a/drivers/hwmon/corsair-cpro.c b/drivers/hwmon/corsair-cpro.c
index 591929ec217a..fa6aa4fc8b52 100644
--- a/drivers/hwmon/corsair-cpro.c
+++ b/drivers/hwmon/corsair-cpro.c
@@ -310,6 +310,7 @@ static int ccp_write(struct device *dev, enum hwmon_sensor_types type,
default:
break;
}
+ break;
default:
break;
}
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index fd47ab4e6892..8d3b1dae31df 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -153,8 +153,44 @@ static int hwmon_thermal_get_temp(void *data, int *temp)
return 0;
}
+static int hwmon_thermal_set_trips(void *data, int low, int high)
+{
+ struct hwmon_thermal_data *tdata = data;
+ struct hwmon_device *hwdev = to_hwmon_device(tdata->dev);
+ const struct hwmon_chip_info *chip = hwdev->chip;
+ const struct hwmon_channel_info **info = chip->info;
+ unsigned int i;
+ int err;
+
+ if (!chip->ops->write)
+ return 0;
+
+ for (i = 0; info[i] && info[i]->type != hwmon_temp; i++)
+ continue;
+
+ if (!info[i])
+ return 0;
+
+ if (info[i]->config[tdata->index] & HWMON_T_MIN) {
+ err = chip->ops->write(tdata->dev, hwmon_temp,
+ hwmon_temp_min, tdata->index, low);
+ if (err && err != -EOPNOTSUPP)
+ return err;
+ }
+
+ if (info[i]->config[tdata->index] & HWMON_T_MAX) {
+ err = chip->ops->write(tdata->dev, hwmon_temp,
+ hwmon_temp_max, tdata->index, high);
+ if (err && err != -EOPNOTSUPP)
+ return err;
+ }
+
+ return 0;
+}
+
static const struct thermal_zone_of_device_ops hwmon_thermal_ops = {
.get_temp = hwmon_thermal_get_temp,
+ .set_trips = hwmon_thermal_set_trips,
};
static void hwmon_thermal_remove_sensor(void *data)
diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c
index c602583d19f3..58d3828e2ec0 100644
--- a/drivers/hwmon/ina3221.c
+++ b/drivers/hwmon/ina3221.c
@@ -196,13 +196,11 @@ static inline u32 ina3221_reg_to_interval_us(u16 config)
u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK);
u32 vbus_ct_idx = INA3221_CONFIG_VBUS_CT(config);
u32 vsh_ct_idx = INA3221_CONFIG_VSH_CT(config);
- u32 samples_idx = INA3221_CONFIG_AVG(config);
- u32 samples = ina3221_avg_samples[samples_idx];
u32 vbus_ct = ina3221_conv_time[vbus_ct_idx];
u32 vsh_ct = ina3221_conv_time[vsh_ct_idx];
/* Calculate total conversion time */
- return channels * (vbus_ct + vsh_ct) * samples;
+ return channels * (vbus_ct + vsh_ct);
}
static inline int ina3221_wait_for_data(struct ina3221_data *ina)
@@ -288,13 +286,14 @@ static int ina3221_read_in(struct device *dev, u32 attr, int channel, long *val)
return -ENODATA;
/* Write CONFIG register to trigger a single-shot measurement */
- if (ina->single_shot)
+ if (ina->single_shot) {
regmap_write(ina->regmap, INA3221_CONFIG,
ina->reg_config);
- ret = ina3221_wait_for_data(ina);
- if (ret)
- return ret;
+ ret = ina3221_wait_for_data(ina);
+ if (ret)
+ return ret;
+ }
ret = ina3221_read_value(ina, reg, &regval);
if (ret)
@@ -344,13 +343,14 @@ static int ina3221_read_curr(struct device *dev, u32 attr,
return -ENODATA;
/* Write CONFIG register to trigger a single-shot measurement */
- if (ina->single_shot)
+ if (ina->single_shot) {
regmap_write(ina->regmap, INA3221_CONFIG,
ina->reg_config);
- ret = ina3221_wait_for_data(ina);
- if (ret)
- return ret;
+ ret = ina3221_wait_for_data(ina);
+ if (ret)
+ return ret;
+ }
fallthrough;
case hwmon_curr_crit:
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c
index 40eab3349904..d2a60de5b8de 100644
--- a/drivers/hwmon/lm70.c
+++ b/drivers/hwmon/lm70.c
@@ -22,10 +22,10 @@
#include <linux/hwmon.h>
#include <linux/mutex.h>
#include <linux/mod_devicetable.h>
+#include <linux/of.h>
#include <linux/property.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include <linux/acpi.h>
#define DRVNAME "lm70"
@@ -148,29 +148,6 @@ static const struct of_device_id lm70_of_ids[] = {
MODULE_DEVICE_TABLE(of, lm70_of_ids);
#endif
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id lm70_acpi_ids[] = {
- {
- .id = "LM000070",
- .driver_data = LM70_CHIP_LM70,
- },
- {
- .id = "TMP00121",
- .driver_data = LM70_CHIP_TMP121,
- },
- {
- .id = "LM000071",
- .driver_data = LM70_CHIP_LM71,
- },
- {
- .id = "LM000074",
- .driver_data = LM70_CHIP_LM74,
- },
- {},
-};
-MODULE_DEVICE_TABLE(acpi, lm70_acpi_ids);
-#endif
-
static int lm70_probe(struct spi_device *spi)
{
struct device *hwmon_dev;
@@ -184,7 +161,7 @@ static int lm70_probe(struct spi_device *spi)
/* signaling is SPI_MODE_0 */
- if (spi->mode & (SPI_CPOL | SPI_CPHA))
+ if ((spi->mode & SPI_MODE_X_MASK) != SPI_MODE_0)
return -EINVAL;
/* NOTE: we assume 8-bit words, and convert to 16 bits manually */
@@ -217,7 +194,6 @@ static struct spi_driver lm70_driver = {
.driver = {
.name = "lm70",
.of_match_table = of_match_ptr(lm70_of_ids),
- .acpi_match_table = ACPI_PTR(lm70_acpi_ids),
},
.id_table = lm70_ids,
.probe = lm70_probe,
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index e447febd121a..afdbb63237b9 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -50,6 +50,7 @@ enum lm75_type { /* keep sorted in alphabetical order */
tmp75,
tmp75b,
tmp75c,
+ tmp1075,
};
/**
@@ -293,6 +294,13 @@ static const struct lm75_params device_params[] = {
.clr_mask = 1 << 5, /*not one-shot mode*/
.default_resolution = 12,
.default_sample_time = MSEC_PER_SEC / 12,
+ },
+ [tmp1075] = { /* not one-shot mode, 27.5 ms sample rate */
+ .clr_mask = 1 << 5 | 1 << 6 | 1 << 7,
+ .default_resolution = 12,
+ .default_sample_time = 28,
+ .num_sample_times = 4,
+ .sample_times = (unsigned int []){ 28, 55, 110, 220 },
}
};
@@ -662,6 +670,7 @@ static const struct i2c_device_id lm75_ids[] = {
{ "tmp75", tmp75, },
{ "tmp75b", tmp75b, },
{ "tmp75c", tmp75c, },
+ { "tmp1075", tmp1075, },
{ /* LIST END */ }
};
MODULE_DEVICE_TABLE(i2c, lm75_ids);
@@ -771,6 +780,10 @@ static const struct of_device_id __maybe_unused lm75_of_match[] = {
.compatible = "ti,tmp75c",
.data = (void *)tmp75c
},
+ {
+ .compatible = "ti,tmp1075",
+ .data = (void *)tmp1075
+ },
{ },
};
MODULE_DEVICE_TABLE(of, lm75_of_match);
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index ebbfd5f352c0..567b7c521f38 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -465,6 +465,7 @@ enum lm90_temp11_reg_index {
struct lm90_data {
struct i2c_client *client;
+ struct device *hwmon_dev;
u32 channel_config[4];
struct hwmon_channel_info temp_info;
const struct hwmon_channel_info *info[3];
@@ -1028,8 +1029,11 @@ static int lm90_set_temp11(struct lm90_data *data, int index, long val)
int err;
/* +16 degrees offset for temp2 for the LM99 */
- if (data->kind == lm99 && index <= 2)
+ if (data->kind == lm99 && index <= 2) {
+ /* prevent integer underflow */
+ val = max(val, -128000l);
val -= 16000;
+ }
if (data->kind == adt7461 || data->kind == tmp451)
data->temp11[index] = temp_to_u16_adt7461(data, val);
@@ -1088,8 +1092,11 @@ static int lm90_set_temp8(struct lm90_data *data, int index, long val)
int err;
/* +16 degrees offset for temp2 for the LM99 */
- if (data->kind == lm99 && index == 3)
+ if (data->kind == lm99 && index == 3) {
+ /* prevent integer underflow */
+ val = max(val, -128000l);
val -= 16000;
+ }
if (data->kind == adt7461 || data->kind == tmp451)
data->temp8[index] = temp_to_u8_adt7461(data, val);
@@ -1136,6 +1143,9 @@ static int lm90_set_temphyst(struct lm90_data *data, long val)
else
temp = temp_from_s8(data->temp8[LOCAL_CRIT]);
+ /* prevent integer underflow */
+ val = max(val, -128000l);
+
data->temp_hyst = hyst_to_reg(temp - val);
err = i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST,
data->temp_hyst);
@@ -1703,6 +1713,13 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
if (data->kind == max6696)
config &= ~0x08;
+ /*
+ * Interrupt is enabled by default on reset, but it may be disabled
+ * by bootloader, unmask it.
+ */
+ if (client->irq)
+ config &= ~0x80;
+
config &= 0xBF; /* run */
lm90_update_confreg(data, config);
@@ -1731,22 +1748,41 @@ static bool lm90_is_tripped(struct i2c_client *client, u16 *status)
if ((st & (LM90_STATUS_LLOW | LM90_STATUS_LHIGH | LM90_STATUS_LTHRM)) ||
(st2 & MAX6696_STATUS2_LOT2))
- dev_warn(&client->dev,
- "temp%d out of range, please check!\n", 1);
+ dev_dbg(&client->dev,
+ "temp%d out of range, please check!\n", 1);
if ((st & (LM90_STATUS_RLOW | LM90_STATUS_RHIGH | LM90_STATUS_RTHRM)) ||
(st2 & MAX6696_STATUS2_ROT2))
- dev_warn(&client->dev,
- "temp%d out of range, please check!\n", 2);
+ dev_dbg(&client->dev,
+ "temp%d out of range, please check!\n", 2);
if (st & LM90_STATUS_ROPEN)
- dev_warn(&client->dev,
- "temp%d diode open, please check!\n", 2);
+ dev_dbg(&client->dev,
+ "temp%d diode open, please check!\n", 2);
if (st2 & (MAX6696_STATUS2_R2LOW | MAX6696_STATUS2_R2HIGH |
MAX6696_STATUS2_R2THRM | MAX6696_STATUS2_R2OT2))
- dev_warn(&client->dev,
- "temp%d out of range, please check!\n", 3);
+ dev_dbg(&client->dev,
+ "temp%d out of range, please check!\n", 3);
if (st2 & MAX6696_STATUS2_R2OPEN)
- dev_warn(&client->dev,
- "temp%d diode open, please check!\n", 3);
+ dev_dbg(&client->dev,
+ "temp%d diode open, please check!\n", 3);
+
+ if (st & LM90_STATUS_LLOW)
+ hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+ hwmon_temp_min, 0);
+ if (st & LM90_STATUS_RLOW)
+ hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+ hwmon_temp_min, 1);
+ if (st2 & MAX6696_STATUS2_R2LOW)
+ hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+ hwmon_temp_min, 2);
+ if (st & LM90_STATUS_LHIGH)
+ hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+ hwmon_temp_max, 0);
+ if (st & LM90_STATUS_RHIGH)
+ hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+ hwmon_temp_max, 1);
+ if (st2 & MAX6696_STATUS2_R2HIGH)
+ hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+ hwmon_temp_max, 2);
return true;
}
@@ -1904,12 +1940,13 @@ static int lm90_probe(struct i2c_client *client)
if (IS_ERR(hwmon_dev))
return PTR_ERR(hwmon_dev);
+ data->hwmon_dev = hwmon_dev;
+
if (client->irq) {
dev_dbg(dev, "IRQ: %d\n", client->irq);
err = devm_request_threaded_irq(dev, client->irq,
NULL, lm90_irq_thread,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- "lm90", client);
+ IRQF_ONESHOT, "lm90", client);
if (err < 0) {
dev_err(dev, "cannot request IRQ %d\n", client->irq);
return err;
@@ -1941,15 +1978,40 @@ static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,
lm90_update_confreg(data, data->config | 0x80);
}
} else {
- dev_info(&client->dev, "Everything OK\n");
+ dev_dbg(&client->dev, "Everything OK\n");
}
}
+static int __maybe_unused lm90_suspend(struct device *dev)
+{
+ struct lm90_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+
+ if (client->irq)
+ disable_irq(client->irq);
+
+ return 0;
+}
+
+static int __maybe_unused lm90_resume(struct device *dev)
+{
+ struct lm90_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+
+ if (client->irq)
+ enable_irq(client->irq);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(lm90_pm_ops, lm90_suspend, lm90_resume);
+
static struct i2c_driver lm90_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "lm90",
.of_match_table = of_match_ptr(lm90_of_match),
+ .pm = &lm90_pm_ops,
},
.probe_new = lm90_probe,
.alert = lm90_alert,
diff --git a/drivers/hwmon/max31722.c b/drivers/hwmon/max31722.c
index 062eceb7be0d..613338cbcb17 100644
--- a/drivers/hwmon/max31722.c
+++ b/drivers/hwmon/max31722.c
@@ -6,7 +6,6 @@
* Copyright (c) 2016, Intel Corporation.
*/
-#include <linux/acpi.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/kernel.h>
@@ -133,20 +132,12 @@ static const struct spi_device_id max31722_spi_id[] = {
{"max31723", 0},
{}
};
-
-static const struct acpi_device_id __maybe_unused max31722_acpi_id[] = {
- {"MAX31722", 0},
- {"MAX31723", 0},
- {}
-};
-
MODULE_DEVICE_TABLE(spi, max31722_spi_id);
static struct spi_driver max31722_driver = {
.driver = {
.name = "max31722",
.pm = &max31722_pm_ops,
- .acpi_match_table = ACPI_PTR(max31722_acpi_id),
},
.probe = max31722_probe,
.remove = max31722_remove,
diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c
index 86e6c71db685..7e9362f6dc29 100644
--- a/drivers/hwmon/max31790.c
+++ b/drivers/hwmon/max31790.c
@@ -27,6 +27,7 @@
/* Fan Config register bits */
#define MAX31790_FAN_CFG_RPM_MODE 0x80
+#define MAX31790_FAN_CFG_CTRL_MON 0x10
#define MAX31790_FAN_CFG_TACH_INPUT_EN 0x08
#define MAX31790_FAN_CFG_TACH_INPUT 0x01
@@ -39,6 +40,8 @@
#define FAN_RPM_MIN 120
#define FAN_RPM_MAX 7864320
+#define FAN_COUNT_REG_MAX 0xffe0
+
#define RPM_FROM_REG(reg, sr) (((reg) >> 4) ? \
((60 * (sr) * 8192) / ((reg) >> 4)) : \
FAN_RPM_MAX)
@@ -79,7 +82,7 @@ static struct max31790_data *max31790_update_device(struct device *dev)
MAX31790_REG_FAN_FAULT_STATUS1);
if (rv < 0)
goto abort;
- data->fault_status = rv & 0x3F;
+ data->fault_status |= rv & 0x3F;
rv = i2c_smbus_read_byte_data(client,
MAX31790_REG_FAN_FAULT_STATUS2);
@@ -104,7 +107,7 @@ static struct max31790_data *max31790_update_device(struct device *dev)
data->tach[NR_CHANNEL + i] = rv;
} else {
rv = i2c_smbus_read_word_swapped(client,
- MAX31790_REG_PWMOUT(i));
+ MAX31790_REG_PWM_DUTY_CYCLE(i));
if (rv < 0)
goto abort;
data->pwm[i] = rv;
@@ -170,8 +173,11 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel,
switch (attr) {
case hwmon_fan_input:
- sr = get_tach_period(data->fan_dynamics[channel]);
- rpm = RPM_FROM_REG(data->tach[channel], sr);
+ sr = get_tach_period(data->fan_dynamics[channel % NR_CHANNEL]);
+ if (data->tach[channel] == FAN_COUNT_REG_MAX)
+ rpm = 0;
+ else
+ rpm = RPM_FROM_REG(data->tach[channel], sr);
*val = rpm;
return 0;
case hwmon_fan_target:
@@ -180,7 +186,21 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel,
*val = rpm;
return 0;
case hwmon_fan_fault:
+ mutex_lock(&data->update_lock);
*val = !!(data->fault_status & (1 << channel));
+ data->fault_status &= ~(1 << channel);
+ /*
+ * If a fault bit is set, we need to write into one of the fan
+ * configuration registers to clear it. Note that this also
+ * clears the fault for the companion channel if enabled.
+ */
+ if (*val) {
+ int reg = MAX31790_REG_TARGET_COUNT(channel % NR_CHANNEL);
+
+ i2c_smbus_write_byte_data(data->client, reg,
+ data->target_count[channel % NR_CHANNEL] >> 8);
+ }
+ mutex_unlock(&data->update_lock);
return 0;
default:
return -EOPNOTSUPP;
@@ -271,12 +291,12 @@ static int max31790_read_pwm(struct device *dev, u32 attr, int channel,
*val = data->pwm[channel] >> 8;
return 0;
case hwmon_pwm_enable:
- if (fan_config & MAX31790_FAN_CFG_RPM_MODE)
+ if (fan_config & MAX31790_FAN_CFG_CTRL_MON)
+ *val = 0;
+ else if (fan_config & MAX31790_FAN_CFG_RPM_MODE)
*val = 2;
- else if (fan_config & MAX31790_FAN_CFG_TACH_INPUT_EN)
- *val = 1;
else
- *val = 0;
+ *val = 1;
return 0;
default:
return -EOPNOTSUPP;
@@ -299,31 +319,41 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel,
err = -EINVAL;
break;
}
- data->pwm[channel] = val << 8;
+ data->valid = false;
err = i2c_smbus_write_word_swapped(client,
MAX31790_REG_PWMOUT(channel),
- data->pwm[channel]);
+ val << 8);
break;
case hwmon_pwm_enable:
fan_config = data->fan_config[channel];
if (val == 0) {
- fan_config &= ~(MAX31790_FAN_CFG_TACH_INPUT_EN |
- MAX31790_FAN_CFG_RPM_MODE);
+ fan_config |= MAX31790_FAN_CFG_CTRL_MON;
+ /*
+ * Disable RPM mode; otherwise disabling fan speed
+ * monitoring is not possible.
+ */
+ fan_config &= ~MAX31790_FAN_CFG_RPM_MODE;
} else if (val == 1) {
- fan_config = (fan_config |
- MAX31790_FAN_CFG_TACH_INPUT_EN) &
- ~MAX31790_FAN_CFG_RPM_MODE;
+ fan_config &= ~(MAX31790_FAN_CFG_CTRL_MON | MAX31790_FAN_CFG_RPM_MODE);
} else if (val == 2) {
- fan_config |= MAX31790_FAN_CFG_TACH_INPUT_EN |
- MAX31790_FAN_CFG_RPM_MODE;
+ fan_config &= ~MAX31790_FAN_CFG_CTRL_MON;
+ /*
+ * The chip sets MAX31790_FAN_CFG_TACH_INPUT_EN on its
+ * own if MAX31790_FAN_CFG_RPM_MODE is set.
+ * Do it here as well to reflect the actual register
+ * value in the cache.
+ */
+ fan_config |= (MAX31790_FAN_CFG_RPM_MODE | MAX31790_FAN_CFG_TACH_INPUT_EN);
} else {
err = -EINVAL;
break;
}
- data->fan_config[channel] = fan_config;
- err = i2c_smbus_write_byte_data(client,
- MAX31790_REG_FAN_CONFIG(channel),
- fan_config);
+ if (fan_config != data->fan_config[channel]) {
+ err = i2c_smbus_write_byte_data(client, MAX31790_REG_FAN_CONFIG(channel),
+ fan_config);
+ if (!err)
+ data->fan_config[channel] = fan_config;
+ }
break;
default:
err = -EOPNOTSUPP;
diff --git a/drivers/hwmon/max6621.c b/drivers/hwmon/max6621.c
index 367855d5edae..7821132e17fa 100644
--- a/drivers/hwmon/max6621.c
+++ b/drivers/hwmon/max6621.c
@@ -156,7 +156,7 @@ max6621_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
default:
break;
}
-
+ break;
default:
break;
}
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index 8587189c7f15..18fd6f12ca16 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -8,7 +8,6 @@
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/pm_runtime.h>
#include <linux/math64.h>
#include <linux/platform_device.h>
#include <linux/err.h>
@@ -17,9 +16,6 @@
#include <linux/platform_data/ntc_thermistor.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/machine.h>
-#include <linux/iio/driver.h>
#include <linux/iio/consumer.h>
#include <linux/hwmon.h>
diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c
index 967532afb1c0..0d68a78be980 100644
--- a/drivers/hwmon/occ/common.c
+++ b/drivers/hwmon/occ/common.c
@@ -1151,6 +1151,8 @@ int occ_setup(struct occ *occ, const char *name)
{
int rc;
+ /* start with 1 to avoid false match with zero-initialized SRAM buffer */
+ occ->seq_no = 1;
mutex_init(&occ->lock);
occ->groups[0] = &occ->group;
@@ -1160,8 +1162,9 @@ int occ_setup(struct occ *occ, const char *name)
dev_info(occ->bus_dev, "host is not ready\n");
return rc;
} else if (rc < 0) {
- dev_err(occ->bus_dev, "failed to get OCC poll response: %d\n",
- rc);
+ dev_err(occ->bus_dev,
+ "failed to get OCC poll response=%02x: %d\n",
+ occ->resp.return_status, rc);
return rc;
}
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index 37a5c39784fa..ffb609cee3a4 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -19,9 +19,10 @@ config SENSORS_PMBUS
default y
help
If you say yes here you get hardware monitoring support for generic
- PMBus devices, including but not limited to ADP4000, BMR453, BMR454,
- MAX20796, MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, TPS40400,
- TPS544B20, TPS544B25, TPS544C20, TPS544C25, and UDT020.
+ PMBus devices, including but not limited to ADP4000, BMR310, BMR453,
+ BMR454, BMR456, BMR457, BMR458, BMR480, BMR490, BMR491, BMR492,
+ MAX20796, MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012,
+ TPS40400, TPS544B20, TPS544B25, TPS544C20, TPS544C25, and UDT020.
This driver can also be built as a module. If so, the module will
be called pmbus.
@@ -85,6 +86,15 @@ config SENSORS_IBM_CFFPS
This driver can also be built as a module. If so, the module will
be called ibm-cffps.
+config SENSORS_DPS920AB
+ tristate "Delta DPS920AB Power Supply"
+ help
+ If you say yes here you get hardware monitoring support for Delta
+ DPS920AB Power Supplies.
+
+ This driver can also be built as a module. If so, the module will
+ be called dps920ab.
+
config SENSORS_INSPUR_IPSPS
tristate "INSPUR Power System Power Supply"
help
@@ -248,6 +258,15 @@ config SENSORS_MAX8688
This driver can also be built as a module. If so, the module will
be called max8688.
+config SENSORS_MP2888
+ tristate "MPS MP2888"
+ help
+ If you say yes here you get hardware monitoring support for MPS
+ MP2888 Digital, Multi-Phase, Pulse-Width Modulation Controller.
+
+ This driver can also be built as a module. If so, the module will
+ be called mp2888.
+
config SENSORS_MP2975
tristate "MPS MP2975"
help
@@ -257,6 +276,15 @@ config SENSORS_MP2975
This driver can also be built as a module. If so, the module will
be called mp2975.
+config SENSORS_PIM4328
+ tristate "Flex PIM4328 and compatibles"
+ help
+ If you say yes here you get hardware monitoring support for Flex
+ PIM4328, PIM4820 and PIM4006 Power Interface Modules.
+
+ This driver can also be built as a module. If so, the module will
+ be called pim4328.
+
config SENSORS_PM6764TR
tristate "ST PM6764TR"
help
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
index f8dcc27cd56a..0ed4d596a948 100644
--- a/drivers/hwmon/pmbus/Makefile
+++ b/drivers/hwmon/pmbus/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_SENSORS_BEL_PFE) += bel-pfe.o
obj-$(CONFIG_SENSORS_BPA_RS600) += bpa-rs600.o
obj-$(CONFIG_SENSORS_FSP_3Y) += fsp-3y.o
obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o
+obj-$(CONFIG_SENSORS_DPS920AB) += dps920ab.o
obj-$(CONFIG_SENSORS_INSPUR_IPSPS) += inspur-ipsps.o
obj-$(CONFIG_SENSORS_IR35221) += ir35221.o
obj-$(CONFIG_SENSORS_IR36021) += ir36021.o
@@ -28,6 +29,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_MP2888) += mp2888.o
obj-$(CONFIG_SENSORS_MP2975) += mp2975.o
obj-$(CONFIG_SENSORS_PM6764TR) += pm6764tr.o
obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o
@@ -39,3 +41,4 @@ obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o
obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o
obj-$(CONFIG_SENSORS_XDPE122) += xdpe12284.o
obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o
+obj-$(CONFIG_SENSORS_PIM4328) += pim4328.o
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c
index 980a3850b2f3..d311e0557401 100644
--- a/drivers/hwmon/pmbus/adm1275.c
+++ b/drivers/hwmon/pmbus/adm1275.c
@@ -611,11 +611,13 @@ static int adm1275_probe(struct i2c_client *client)
tindex = 8;
info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
- PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
- /* Enable VOUT if not enabled (it is disabled by default) */
- if (!(config & ADM1278_VOUT_EN)) {
- config |= ADM1278_VOUT_EN;
+ /* Enable VOUT & TEMP1 if not enabled (disabled by default) */
+ if ((config & (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) !=
+ (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) {
+ config |= ADM1278_VOUT_EN | ADM1278_TEMP1_EN;
ret = i2c_smbus_write_byte_data(client,
ADM1275_PMON_CONFIG,
config);
@@ -625,10 +627,6 @@ static int adm1275_probe(struct i2c_client *client)
return -ENODEV;
}
}
-
- if (config & ADM1278_TEMP1_EN)
- info->func[0] |=
- PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
if (config & ADM1278_VIN_EN)
info->func[0] |= PMBUS_HAVE_VIN;
break;
diff --git a/drivers/hwmon/pmbus/bpa-rs600.c b/drivers/hwmon/pmbus/bpa-rs600.c
index f6558ee9dec3..2be69fedfa36 100644
--- a/drivers/hwmon/pmbus/bpa-rs600.c
+++ b/drivers/hwmon/pmbus/bpa-rs600.c
@@ -46,6 +46,32 @@ static int bpa_rs600_read_byte_data(struct i2c_client *client, int page, int reg
return ret;
}
+/*
+ * The BPA-RS600 violates the PMBus spec. Specifically it treats the
+ * mantissa as unsigned. Deal with this here to allow the PMBus core
+ * to work with correctly encoded data.
+ */
+static int bpa_rs600_read_vin(struct i2c_client *client)
+{
+ int ret, exponent, mantissa;
+
+ ret = pmbus_read_word_data(client, 0, 0xff, PMBUS_READ_VIN);
+ if (ret < 0)
+ return ret;
+
+ if (ret & BIT(10)) {
+ exponent = ret >> 11;
+ mantissa = ret & 0x7ff;
+
+ exponent++;
+ mantissa >>= 1;
+
+ ret = (exponent << 11) | mantissa;
+ }
+
+ return ret;
+}
+
static int bpa_rs600_read_word_data(struct i2c_client *client, int page, int phase, int reg)
{
int ret;
@@ -85,6 +111,9 @@ static int bpa_rs600_read_word_data(struct i2c_client *client, int page, int pha
/* These commands return data but it is invalid/un-documented */
ret = -ENXIO;
break;
+ case PMBUS_READ_VIN:
+ ret = bpa_rs600_read_vin(client);
+ break;
default:
if (reg >= PMBUS_VIRT_BASE)
ret = -ENXIO;
diff --git a/drivers/hwmon/pmbus/dps920ab.c b/drivers/hwmon/pmbus/dps920ab.c
new file mode 100644
index 000000000000..d3941f6eb29a
--- /dev/null
+++ b/drivers/hwmon/pmbus/dps920ab.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Delta DPS920AB PSU
+ *
+ * Copyright (C) 2021 Delta Networks, Inc.
+ * Copyright (C) 2021 Sartura Ltd.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include "pmbus.h"
+
+struct dps920ab_data {
+ char *mfr_model;
+ char *mfr_id;
+};
+
+static int dps920ab_read_word_data(struct i2c_client *client, int page, int phase, int reg)
+{
+ /*
+ * This masks commands which are not supported.
+ * PSU advertises that all features are supported,
+ * in reality that unfortunately is not true.
+ * So enable only those that the datasheet confirms.
+ */
+ switch (reg) {
+ case PMBUS_FAN_COMMAND_1:
+ case PMBUS_IOUT_OC_WARN_LIMIT:
+ case PMBUS_STATUS_WORD:
+ case PMBUS_READ_VIN:
+ case PMBUS_READ_IIN:
+ case PMBUS_READ_VOUT:
+ case PMBUS_READ_IOUT:
+ case PMBUS_READ_TEMPERATURE_1:
+ case PMBUS_READ_TEMPERATURE_2:
+ case PMBUS_READ_TEMPERATURE_3:
+ case PMBUS_READ_FAN_SPEED_1:
+ case PMBUS_READ_POUT:
+ case PMBUS_READ_PIN:
+ case PMBUS_MFR_VOUT_MIN:
+ case PMBUS_MFR_VOUT_MAX:
+ case PMBUS_MFR_IOUT_MAX:
+ case PMBUS_MFR_POUT_MAX:
+ return pmbus_read_word_data(client, page, phase, reg);
+ default:
+ return -ENXIO;
+ }
+}
+
+static int dps920ab_write_word_data(struct i2c_client *client, int page, int reg,
+ u16 word)
+{
+ /*
+ * This masks commands which are not supported.
+ * PSU only has one R/W register and that is
+ * for the fan.
+ */
+ switch (reg) {
+ case PMBUS_FAN_COMMAND_1:
+ return pmbus_write_word_data(client, page, reg, word);
+ default:
+ return -EACCES;
+ }
+}
+
+static struct pmbus_driver_info dps920ab_info = {
+ .pages = 1,
+
+ .format[PSC_VOLTAGE_IN] = linear,
+ .format[PSC_VOLTAGE_OUT] = linear,
+ .format[PSC_CURRENT_IN] = linear,
+ .format[PSC_CURRENT_OUT] = linear,
+ .format[PSC_POWER] = linear,
+ .format[PSC_FAN] = linear,
+ .format[PSC_TEMPERATURE] = linear,
+
+ .func[0] =
+ PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN |
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT |
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
+ PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 |
+ PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
+ PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
+ .read_word_data = dps920ab_read_word_data,
+ .write_word_data = dps920ab_write_word_data,
+};
+
+static int dps920ab_mfr_id_show(struct seq_file *s, void *data)
+{
+ struct dps920ab_data *priv = s->private;
+
+ seq_printf(s, "%s\n", priv->mfr_id);
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(dps920ab_mfr_id);
+
+static int dps920ab_mfr_model_show(struct seq_file *s, void *data)
+{
+ struct dps920ab_data *priv = s->private;
+
+ seq_printf(s, "%s\n", priv->mfr_model);
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(dps920ab_mfr_model);
+
+static void dps920ab_init_debugfs(struct dps920ab_data *data, struct i2c_client *client)
+{
+ struct dentry *debugfs_dir;
+ struct dentry *root;
+
+ root = pmbus_get_debugfs_dir(client);
+ if (!root)
+ return;
+
+ debugfs_dir = debugfs_create_dir(client->name, root);
+
+ debugfs_create_file("mfr_id",
+ 0400,
+ debugfs_dir,
+ data,
+ &dps920ab_mfr_id_fops);
+
+ debugfs_create_file("mfr_model",
+ 0400,
+ debugfs_dir,
+ data,
+ &dps920ab_mfr_model_fops);
+}
+
+static int dps920ab_probe(struct i2c_client *client)
+{
+ u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
+ struct dps920ab_data *data;
+ int ret;
+
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to read Manufacturer ID\n");
+ return ret;
+ }
+
+ buf[ret] = '\0';
+ if (ret != 5 || strncmp(buf, "DELTA", 5)) {
+ buf[ret] = '\0';
+ dev_err(&client->dev, "Unsupported Manufacturer ID '%s'\n", buf);
+ return -ENODEV;
+ }
+ data->mfr_id = devm_kstrdup(&client->dev, buf, GFP_KERNEL);
+ if (!data->mfr_id)
+ return -ENOMEM;
+
+ ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to read Manufacturer Model\n");
+ return ret;
+ }
+
+ buf[ret] = '\0';
+ if (ret != 11 || strncmp(buf, "DPS-920AB", 9)) {
+ dev_err(&client->dev, "Unsupported Manufacturer Model '%s'\n", buf);
+ return -ENODEV;
+ }
+ data->mfr_model = devm_kstrdup(&client->dev, buf, GFP_KERNEL);
+ if (!data->mfr_model)
+ return -ENOMEM;
+
+ ret = pmbus_do_probe(client, &dps920ab_info);
+ if (ret)
+ return ret;
+
+ dps920ab_init_debugfs(data, client);
+
+ return 0;
+}
+
+static const struct of_device_id __maybe_unused dps920ab_of_match[] = {
+ { .compatible = "delta,dps920ab", },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, dps920ab_of_match);
+
+static struct i2c_driver dps920ab_driver = {
+ .driver = {
+ .name = "dps920ab",
+ .of_match_table = of_match_ptr(dps920ab_of_match),
+ },
+ .probe_new = dps920ab_probe,
+};
+
+module_i2c_driver(dps920ab_driver);
+
+MODULE_AUTHOR("Robert Marko <robert.marko@sartura.hr>");
+MODULE_DESCRIPTION("PMBus driver for Delta DPS920AB PSU");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/mp2888.c b/drivers/hwmon/pmbus/mp2888.c
new file mode 100644
index 000000000000..8ecd4adfef40
--- /dev/null
+++ b/drivers/hwmon/pmbus/mp2888.c
@@ -0,0 +1,408 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers
+ *
+ * Copyright (C) 2020 Nvidia Technologies Ltd.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "pmbus.h"
+
+/* Vendor specific registers. */
+#define MP2888_MFR_SYS_CONFIG 0x44
+#define MP2888_MFR_READ_CS1_2 0x73
+#define MP2888_MFR_READ_CS3_4 0x74
+#define MP2888_MFR_READ_CS5_6 0x75
+#define MP2888_MFR_READ_CS7_8 0x76
+#define MP2888_MFR_READ_CS9_10 0x77
+#define MP2888_MFR_VR_CONFIG1 0xe1
+
+#define MP2888_TOTAL_CURRENT_RESOLUTION BIT(3)
+#define MP2888_PHASE_CURRENT_RESOLUTION BIT(4)
+#define MP2888_DRMOS_KCS GENMASK(2, 0)
+#define MP2888_TEMP_UNIT 10
+#define MP2888_MAX_PHASE 10
+
+struct mp2888_data {
+ struct pmbus_driver_info info;
+ int total_curr_resolution;
+ int phase_curr_resolution;
+ int curr_sense_gain;
+};
+
+#define to_mp2888_data(x) container_of(x, struct mp2888_data, info)
+
+static int mp2888_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ switch (reg) {
+ case PMBUS_VOUT_MODE:
+ /* Enforce VOUT direct format. */
+ return PB_VOUT_MODE_DIRECT;
+ default:
+ return -ENODATA;
+ }
+}
+
+static int
+mp2888_current_sense_gain_and_resolution_get(struct i2c_client *client, struct mp2888_data *data)
+{
+ int ret;
+
+ /*
+ * Obtain DrMOS current sense gain of power stage from the register
+ * , bits 0-2. The value is selected as below:
+ * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A. Other
+ * values are reserved.
+ */
+ ret = i2c_smbus_read_word_data(client, MP2888_MFR_SYS_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ switch (ret & MP2888_DRMOS_KCS) {
+ case 0:
+ data->curr_sense_gain = 85;
+ break;
+ case 1:
+ data->curr_sense_gain = 97;
+ break;
+ case 2:
+ data->curr_sense_gain = 100;
+ break;
+ case 3:
+ data->curr_sense_gain = 50;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Obtain resolution selector for total and phase current report and protection.
+ * 0: original resolution; 1: half resolution (in such case phase current value should
+ * be doubled.
+ */
+ data->total_curr_resolution = (ret & MP2888_TOTAL_CURRENT_RESOLUTION) >> 3;
+ data->phase_curr_resolution = (ret & MP2888_PHASE_CURRENT_RESOLUTION) >> 4;
+
+ return 0;
+}
+
+static int
+mp2888_read_phase(struct i2c_client *client, struct mp2888_data *data, int page, int phase, u8 reg)
+{
+ int ret;
+
+ ret = pmbus_read_word_data(client, page, phase, reg);
+ if (ret < 0)
+ return ret;
+
+ if (!((phase + 1) % 2))
+ ret >>= 8;
+ ret &= 0xff;
+
+ /*
+ * Output value is calculated as: (READ_CSx / 80 – 1.23) / (Kcs * Rcs)
+ * where:
+ * - Kcs is the DrMOS current sense gain of power stage, which is obtained from the
+ * register MP2888_MFR_VR_CONFIG1, bits 13-12 with the following selection of DrMOS
+ * (data->curr_sense_gain):
+ * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A.
+ * - Rcs is the internal phase current sense resistor. This parameter depends on hardware
+ * assembly. By default it is set to 1kΩ. In case of different assembly, user should
+ * scale this parameter by dividing it by Rcs.
+ * If phase current resolution bit is set to 1, READ_CSx value should be doubled.
+ * Note, that current phase sensing, providing by the device is not accurate. This is
+ * because sampling of current occurrence of bit weight has a big deviation, especially for
+ * light load.
+ */
+ ret = DIV_ROUND_CLOSEST(ret * 100 - 9800, data->curr_sense_gain);
+ ret = (data->phase_curr_resolution) ? ret * 2 : ret;
+ /* Scale according to total current resolution. */
+ ret = (data->total_curr_resolution) ? ret * 8 : ret * 4;
+ return ret;
+}
+
+static int
+mp2888_read_phases(struct i2c_client *client, struct mp2888_data *data, int page, int phase)
+{
+ int ret;
+
+ switch (phase) {
+ case 0 ... 1:
+ ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS1_2);
+ break;
+ case 2 ... 3:
+ ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS3_4);
+ break;
+ case 4 ... 5:
+ ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS5_6);
+ break;
+ case 6 ... 7:
+ ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS7_8);
+ break;
+ case 8 ... 9:
+ ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS9_10);
+ break;
+ default:
+ return -ENODATA;
+ }
+ return ret;
+}
+
+static int mp2888_read_word_data(struct i2c_client *client, int page, int phase, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct mp2888_data *data = to_mp2888_data(info);
+ int ret;
+
+ switch (reg) {
+ case PMBUS_READ_VIN:
+ ret = pmbus_read_word_data(client, page, phase, reg);
+ if (ret <= 0)
+ return ret;
+
+ /*
+ * READ_VIN requires fixup to scale it to linear11 format. Register data format
+ * provides 10 bits for mantissa and 6 bits for exponent. Bits 15:10 are set with
+ * the fixed value 111011b.
+ */
+ ret = (ret & GENMASK(9, 0)) | ((ret & GENMASK(31, 10)) << 1);
+ break;
+ case PMBUS_OT_WARN_LIMIT:
+ ret = pmbus_read_word_data(client, page, phase, reg);
+ if (ret < 0)
+ return ret;
+ /*
+ * Chip reports limits in degrees C, but the actual temperature in 10th of
+ * degrees C - scaling is needed to match both.
+ */
+ ret *= MP2888_TEMP_UNIT;
+ break;
+ case PMBUS_READ_IOUT:
+ if (phase != 0xff)
+ return mp2888_read_phases(client, data, page, phase);
+
+ ret = pmbus_read_word_data(client, page, phase, reg);
+ if (ret < 0)
+ return ret;
+ /*
+ * READ_IOUT register has unused bits 15:12 with fixed value 1110b. Clear these
+ * bits and scale with total current resolution. Data is provided in direct format.
+ */
+ ret &= GENMASK(11, 0);
+ ret = data->total_curr_resolution ? ret * 2 : ret;
+ break;
+ case PMBUS_IOUT_OC_WARN_LIMIT:
+ ret = pmbus_read_word_data(client, page, phase, reg);
+ if (ret < 0)
+ return ret;
+ ret &= GENMASK(9, 0);
+ /*
+ * Chip reports limits with resolution 1A or 2A, if total current resolution bit is
+ * set 1. Actual current is reported with 0.25A or respectively 0.5A resolution.
+ * Scaling is needed to match both.
+ */
+ ret = data->total_curr_resolution ? ret * 8 : ret * 4;
+ break;
+ case PMBUS_READ_POUT:
+ case PMBUS_READ_PIN:
+ ret = pmbus_read_word_data(client, page, phase, reg);
+ if (ret < 0)
+ return ret;
+ ret = data->total_curr_resolution ? ret * 2 : ret;
+ break;
+ case PMBUS_POUT_OP_WARN_LIMIT:
+ ret = pmbus_read_word_data(client, page, phase, reg);
+ if (ret < 0)
+ return ret;
+ /*
+ * Chip reports limits with resolution 1W or 2W, if total current resolution bit is
+ * set 1. Actual power is reported with 0.5W or 1W respectively resolution. Scaling
+ * is needed to match both.
+ */
+ ret = data->total_curr_resolution ? ret * 4 : ret * 2;
+ break;
+ /*
+ * The below registers are not implemented by device or implemented not according to the
+ * spec. Skip all of them to avoid exposing non-relevant inputs to sysfs.
+ */
+ case PMBUS_OT_FAULT_LIMIT:
+ case PMBUS_UT_WARN_LIMIT:
+ case PMBUS_UT_FAULT_LIMIT:
+ case PMBUS_VIN_UV_FAULT_LIMIT:
+ case PMBUS_VOUT_UV_WARN_LIMIT:
+ case PMBUS_VOUT_OV_WARN_LIMIT:
+ case PMBUS_VOUT_UV_FAULT_LIMIT:
+ case PMBUS_VOUT_OV_FAULT_LIMIT:
+ case PMBUS_VIN_OV_WARN_LIMIT:
+ case PMBUS_IOUT_OC_LV_FAULT_LIMIT:
+ case PMBUS_IOUT_OC_FAULT_LIMIT:
+ case PMBUS_POUT_MAX:
+ case PMBUS_IOUT_UC_FAULT_LIMIT:
+ case PMBUS_POUT_OP_FAULT_LIMIT:
+ case PMBUS_PIN_OP_WARN_LIMIT:
+ case PMBUS_MFR_VIN_MIN:
+ case PMBUS_MFR_VOUT_MIN:
+ case PMBUS_MFR_VIN_MAX:
+ case PMBUS_MFR_VOUT_MAX:
+ case PMBUS_MFR_IIN_MAX:
+ case PMBUS_MFR_IOUT_MAX:
+ case PMBUS_MFR_PIN_MAX:
+ case PMBUS_MFR_POUT_MAX:
+ case PMBUS_MFR_MAX_TEMP_1:
+ return -ENXIO;
+ default:
+ return -ENODATA;
+ }
+
+ return ret;
+}
+
+static int mp2888_write_word_data(struct i2c_client *client, int page, int reg, u16 word)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct mp2888_data *data = to_mp2888_data(info);
+
+ switch (reg) {
+ case PMBUS_OT_WARN_LIMIT:
+ word = DIV_ROUND_CLOSEST(word, MP2888_TEMP_UNIT);
+ /* Drop unused bits 15:8. */
+ word = clamp_val(word, 0, GENMASK(7, 0));
+ break;
+ case PMBUS_IOUT_OC_WARN_LIMIT:
+ /* Fix limit according to total curent resolution. */
+ word = data->total_curr_resolution ? DIV_ROUND_CLOSEST(word, 8) :
+ DIV_ROUND_CLOSEST(word, 4);
+ /* Drop unused bits 15:10. */
+ word = clamp_val(word, 0, GENMASK(9, 0));
+ break;
+ case PMBUS_POUT_OP_WARN_LIMIT:
+ /* Fix limit according to total curent resolution. */
+ word = data->total_curr_resolution ? DIV_ROUND_CLOSEST(word, 4) :
+ DIV_ROUND_CLOSEST(word, 2);
+ /* Drop unused bits 15:10. */
+ word = clamp_val(word, 0, GENMASK(9, 0));
+ break;
+ default:
+ return -ENODATA;
+ }
+ return pmbus_write_word_data(client, page, reg, word);
+}
+
+static int
+mp2888_identify_multiphase(struct i2c_client *client, struct mp2888_data *data,
+ struct pmbus_driver_info *info)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Identify multiphase number - could be from 1 to 10. */
+ ret = i2c_smbus_read_word_data(client, MP2888_MFR_VR_CONFIG1);
+ if (ret <= 0)
+ return ret;
+
+ info->phases[0] = ret & GENMASK(3, 0);
+
+ /*
+ * The device provides a total of 10 PWM pins, and can be configured to different phase
+ * count applications for rail.
+ */
+ if (info->phases[0] > MP2888_MAX_PHASE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct pmbus_driver_info mp2888_info = {
+ .pages = 1,
+ .format[PSC_VOLTAGE_IN] = linear,
+ .format[PSC_VOLTAGE_OUT] = direct,
+ .format[PSC_TEMPERATURE] = direct,
+ .format[PSC_CURRENT_IN] = linear,
+ .format[PSC_CURRENT_OUT] = direct,
+ .format[PSC_POWER] = direct,
+ .m[PSC_TEMPERATURE] = 1,
+ .R[PSC_TEMPERATURE] = 1,
+ .m[PSC_VOLTAGE_OUT] = 1,
+ .R[PSC_VOLTAGE_OUT] = 3,
+ .m[PSC_CURRENT_OUT] = 4,
+ .m[PSC_POWER] = 1,
+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT |
+ PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
+ PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
+ PMBUS_PHASE_VIRTUAL,
+ .pfunc[0] = PMBUS_HAVE_IOUT,
+ .pfunc[1] = PMBUS_HAVE_IOUT,
+ .pfunc[2] = PMBUS_HAVE_IOUT,
+ .pfunc[3] = PMBUS_HAVE_IOUT,
+ .pfunc[4] = PMBUS_HAVE_IOUT,
+ .pfunc[5] = PMBUS_HAVE_IOUT,
+ .pfunc[6] = PMBUS_HAVE_IOUT,
+ .pfunc[7] = PMBUS_HAVE_IOUT,
+ .pfunc[8] = PMBUS_HAVE_IOUT,
+ .pfunc[9] = PMBUS_HAVE_IOUT,
+ .read_byte_data = mp2888_read_byte_data,
+ .read_word_data = mp2888_read_word_data,
+ .write_word_data = mp2888_write_word_data,
+};
+
+static int mp2888_probe(struct i2c_client *client)
+{
+ struct pmbus_driver_info *info;
+ struct mp2888_data *data;
+ int ret;
+
+ data = devm_kzalloc(&client->dev, sizeof(struct mp2888_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ memcpy(&data->info, &mp2888_info, sizeof(*info));
+ info = &data->info;
+
+ /* Identify multiphase configuration. */
+ ret = mp2888_identify_multiphase(client, data, info);
+ if (ret)
+ return ret;
+
+ /* Obtain current sense gain of power stage and current resolution. */
+ ret = mp2888_current_sense_gain_and_resolution_get(client, data);
+ if (ret)
+ return ret;
+
+ return pmbus_do_probe(client, info);
+}
+
+static const struct i2c_device_id mp2888_id[] = {
+ {"mp2888", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, mp2888_id);
+
+static const struct of_device_id __maybe_unused mp2888_of_match[] = {
+ {.compatible = "mps,mp2888"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, mp2888_of_match);
+
+static struct i2c_driver mp2888_driver = {
+ .driver = {
+ .name = "mp2888",
+ .of_match_table = of_match_ptr(mp2888_of_match),
+ },
+ .probe_new = mp2888_probe,
+ .id_table = mp2888_id,
+};
+
+module_i2c_driver(mp2888_driver);
+
+MODULE_AUTHOR("Vadim Pasternak <vadimp@nvidia.com>");
+MODULE_DESCRIPTION("PMBus driver for MPS MP2888 device");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/pim4328.c b/drivers/hwmon/pmbus/pim4328.c
new file mode 100644
index 000000000000..273ff6e57654
--- /dev/null
+++ b/drivers/hwmon/pmbus/pim4328.c
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Hardware monitoring driver for PIM4006, PIM4328 and PIM4820
+ *
+ * Copyright (c) 2021 Flextronics International Sweden AB
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pmbus.h>
+#include <linux/slab.h>
+#include "pmbus.h"
+
+enum chips { pim4006, pim4328, pim4820 };
+
+struct pim4328_data {
+ enum chips id;
+ struct pmbus_driver_info info;
+};
+
+#define to_pim4328_data(x) container_of(x, struct pim4328_data, info)
+
+/* PIM4006 and PIM4328 */
+#define PIM4328_MFR_READ_VINA 0xd3
+#define PIM4328_MFR_READ_VINB 0xd4
+
+/* PIM4006 */
+#define PIM4328_MFR_READ_IINA 0xd6
+#define PIM4328_MFR_READ_IINB 0xd7
+#define PIM4328_MFR_FET_CHECKSTATUS 0xd9
+
+/* PIM4328 */
+#define PIM4328_MFR_STATUS_BITS 0xd5
+
+/* PIM4820 */
+#define PIM4328_MFR_READ_STATUS 0xd0
+
+static const struct i2c_device_id pim4328_id[] = {
+ {"bmr455", pim4328},
+ {"pim4006", pim4006},
+ {"pim4106", pim4006},
+ {"pim4206", pim4006},
+ {"pim4306", pim4006},
+ {"pim4328", pim4328},
+ {"pim4406", pim4006},
+ {"pim4820", pim4820},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, pim4328_id);
+
+static int pim4328_read_word_data(struct i2c_client *client, int page,
+ int phase, int reg)
+{
+ int ret;
+
+ if (page > 0)
+ return -ENXIO;
+
+ if (phase == 0xff)
+ return -ENODATA;
+
+ switch (reg) {
+ case PMBUS_READ_VIN:
+ ret = pmbus_read_word_data(client, page, phase,
+ phase == 0 ? PIM4328_MFR_READ_VINA
+ : PIM4328_MFR_READ_VINB);
+ break;
+ case PMBUS_READ_IIN:
+ ret = pmbus_read_word_data(client, page, phase,
+ phase == 0 ? PIM4328_MFR_READ_IINA
+ : PIM4328_MFR_READ_IINB);
+ break;
+ default:
+ ret = -ENODATA;
+ }
+
+ return ret;
+}
+
+static int pim4328_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct pim4328_data *data = to_pim4328_data(info);
+ int ret, status;
+
+ if (page > 0)
+ return -ENXIO;
+
+ switch (reg) {
+ case PMBUS_STATUS_BYTE:
+ ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_BYTE);
+ if (ret < 0)
+ return ret;
+ if (data->id == pim4006) {
+ status = pmbus_read_word_data(client, page, 0xff,
+ PIM4328_MFR_FET_CHECKSTATUS);
+ if (status < 0)
+ return status;
+ if (status & 0x0630) /* Input UV */
+ ret |= PB_STATUS_VIN_UV;
+ } else if (data->id == pim4328) {
+ status = pmbus_read_byte_data(client, page,
+ PIM4328_MFR_STATUS_BITS);
+ if (status < 0)
+ return status;
+ if (status & 0x04) /* Input UV */
+ ret |= PB_STATUS_VIN_UV;
+ if (status & 0x40) /* Output UV */
+ ret |= PB_STATUS_NONE_ABOVE;
+ } else if (data->id == pim4820) {
+ status = pmbus_read_byte_data(client, page,
+ PIM4328_MFR_READ_STATUS);
+ if (status < 0)
+ return status;
+ if (status & 0x05) /* Input OV or OC */
+ ret |= PB_STATUS_NONE_ABOVE;
+ if (status & 0x1a) /* Input UV */
+ ret |= PB_STATUS_VIN_UV;
+ if (status & 0x40) /* OT */
+ ret |= PB_STATUS_TEMPERATURE;
+ }
+ break;
+ default:
+ ret = -ENODATA;
+ }
+
+ return ret;
+}
+
+static int pim4328_probe(struct i2c_client *client)
+{
+ int status;
+ u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
+ const struct i2c_device_id *mid;
+ struct pim4328_data *data;
+ struct pmbus_driver_info *info;
+ struct pmbus_platform_data *pdata;
+ struct device *dev = &client->dev;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA
+ | I2C_FUNC_SMBUS_BLOCK_DATA))
+ return -ENODEV;
+
+ data = devm_kzalloc(&client->dev, sizeof(struct pim4328_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ status = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, device_id);
+ if (status < 0) {
+ dev_err(&client->dev, "Failed to read Manufacturer Model\n");
+ return status;
+ }
+ for (mid = pim4328_id; mid->name[0]; mid++) {
+ if (!strncasecmp(mid->name, device_id, strlen(mid->name)))
+ break;
+ }
+ if (!mid->name[0]) {
+ dev_err(&client->dev, "Unsupported device\n");
+ return -ENODEV;
+ }
+
+ if (strcmp(client->name, mid->name))
+ dev_notice(&client->dev,
+ "Device mismatch: Configured %s, detected %s\n",
+ client->name, mid->name);
+
+ data->id = mid->driver_data;
+ info = &data->info;
+ info->pages = 1;
+ info->read_byte_data = pim4328_read_byte_data;
+ info->read_word_data = pim4328_read_word_data;
+
+ pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ dev->platform_data = pdata;
+ pdata->flags = PMBUS_NO_CAPABILITY | PMBUS_NO_WRITE_PROTECT;
+
+ switch (data->id) {
+ case pim4006:
+ info->phases[0] = 2;
+ info->func[0] = PMBUS_PHASE_VIRTUAL | PMBUS_HAVE_VIN
+ | PMBUS_HAVE_TEMP | PMBUS_HAVE_IOUT;
+ info->pfunc[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN;
+ info->pfunc[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN;
+ break;
+ case pim4328:
+ info->phases[0] = 2;
+ info->func[0] = PMBUS_PHASE_VIRTUAL
+ | PMBUS_HAVE_VCAP | PMBUS_HAVE_VIN
+ | PMBUS_HAVE_TEMP | PMBUS_HAVE_IOUT;
+ info->pfunc[0] = PMBUS_HAVE_VIN;
+ info->pfunc[1] = PMBUS_HAVE_VIN;
+ info->format[PSC_VOLTAGE_IN] = direct;
+ info->format[PSC_TEMPERATURE] = direct;
+ info->format[PSC_CURRENT_OUT] = direct;
+ pdata->flags |= PMBUS_USE_COEFFICIENTS_CMD;
+ break;
+ case pim4820:
+ info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_TEMP
+ | PMBUS_HAVE_IIN;
+ info->format[PSC_VOLTAGE_IN] = direct;
+ info->format[PSC_TEMPERATURE] = direct;
+ info->format[PSC_CURRENT_IN] = direct;
+ pdata->flags |= PMBUS_USE_COEFFICIENTS_CMD;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ return pmbus_do_probe(client, info);
+}
+
+static struct i2c_driver pim4328_driver = {
+ .driver = {
+ .name = "pim4328",
+ },
+ .probe_new = pim4328_probe,
+ .id_table = pim4328_id,
+};
+
+module_i2c_driver(pim4328_driver);
+
+MODULE_AUTHOR("Erik Rosen <erik.rosen@metormote.com>");
+MODULE_DESCRIPTION("PMBus driver for PIM4006, PIM4328, PIM4820 power interface modules");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c
index 618c377664c4..d0d386990af5 100644
--- a/drivers/hwmon/pmbus/pmbus.c
+++ b/drivers/hwmon/pmbus/pmbus.c
@@ -173,13 +173,13 @@ static int pmbus_probe(struct i2c_client *client)
return -ENOMEM;
device_info = (struct pmbus_device_info *)i2c_match_id(pmbus_id, client)->driver_data;
- if (device_info->flags & PMBUS_SKIP_STATUS_CHECK) {
+ if (device_info->flags) {
pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data),
GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- pdata->flags = PMBUS_SKIP_STATUS_CHECK;
+ pdata->flags = device_info->flags;
}
info->pages = device_info->pages;
@@ -193,22 +193,37 @@ static const struct pmbus_device_info pmbus_info_one = {
.pages = 1,
.flags = 0
};
+
static const struct pmbus_device_info pmbus_info_zero = {
.pages = 0,
.flags = 0
};
+
static const struct pmbus_device_info pmbus_info_one_skip = {
.pages = 1,
.flags = PMBUS_SKIP_STATUS_CHECK
};
+static const struct pmbus_device_info pmbus_info_one_status = {
+ .pages = 1,
+ .flags = PMBUS_READ_STATUS_AFTER_FAILED_CHECK
+};
+
/*
* Use driver_data to set the number of pages supported by the chip.
*/
static const struct i2c_device_id pmbus_id[] = {
{"adp4000", (kernel_ulong_t)&pmbus_info_one},
+ {"bmr310", (kernel_ulong_t)&pmbus_info_one_status},
{"bmr453", (kernel_ulong_t)&pmbus_info_one},
{"bmr454", (kernel_ulong_t)&pmbus_info_one},
+ {"bmr456", (kernel_ulong_t)&pmbus_info_one},
+ {"bmr457", (kernel_ulong_t)&pmbus_info_one},
+ {"bmr458", (kernel_ulong_t)&pmbus_info_one_status},
+ {"bmr480", (kernel_ulong_t)&pmbus_info_one_status},
+ {"bmr490", (kernel_ulong_t)&pmbus_info_one_status},
+ {"bmr491", (kernel_ulong_t)&pmbus_info_one_status},
+ {"bmr492", (kernel_ulong_t)&pmbus_info_one},
{"dps460", (kernel_ulong_t)&pmbus_info_one_skip},
{"dps650ab", (kernel_ulong_t)&pmbus_info_one_skip},
{"dps800", (kernel_ulong_t)&pmbus_info_one_skip},
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index 3968924f8533..e0aa8aa46d8c 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -375,7 +375,7 @@ enum pmbus_sensor_classes {
};
#define PMBUS_PAGES 32 /* Per PMBus specification */
-#define PMBUS_PHASES 8 /* Maximum number of phases per page */
+#define PMBUS_PHASES 10 /* Maximum number of phases per page */
/* Functionality bit mask */
#define PMBUS_HAVE_VIN BIT(0)
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index bbd745178147..776ee2237be2 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -523,6 +523,8 @@ static bool pmbus_check_register(struct i2c_client *client,
rv = func(client, page, reg);
if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
rv = pmbus_check_status_cml(client);
+ if (rv < 0 && (data->flags & PMBUS_READ_STATUS_AFTER_FAILED_CHECK))
+ data->read_status(client, -1);
pmbus_clear_fault_page(client, -1);
return rv >= 0;
}
@@ -1327,14 +1329,14 @@ static int pmbus_add_sensor_attrs(struct i2c_client *client,
pages = paged ? info->pages : 1;
for (page = 0; page < pages; page++) {
- if (!(info->func[page] & attrs->func))
- continue;
- ret = pmbus_add_sensor_attrs_one(client, data, info,
- name, index, page,
- 0xff, attrs, paged);
- if (ret)
- return ret;
- index++;
+ if (info->func[page] & attrs->func) {
+ ret = pmbus_add_sensor_attrs_one(client, data, info,
+ name, index, page,
+ 0xff, attrs, paged);
+ if (ret)
+ return ret;
+ index++;
+ }
if (info->phases[page]) {
int phase;
@@ -2140,6 +2142,111 @@ static int pmbus_find_attributes(struct i2c_client *client,
}
/*
+ * The pmbus_class_attr_map structure maps one sensor class to
+ * it's corresponding sensor attributes array.
+ */
+struct pmbus_class_attr_map {
+ enum pmbus_sensor_classes class;
+ int nattr;
+ const struct pmbus_sensor_attr *attr;
+};
+
+static const struct pmbus_class_attr_map class_attr_map[] = {
+ {
+ .class = PSC_VOLTAGE_IN,
+ .attr = voltage_attributes,
+ .nattr = ARRAY_SIZE(voltage_attributes),
+ }, {
+ .class = PSC_VOLTAGE_OUT,
+ .attr = voltage_attributes,
+ .nattr = ARRAY_SIZE(voltage_attributes),
+ }, {
+ .class = PSC_CURRENT_IN,
+ .attr = current_attributes,
+ .nattr = ARRAY_SIZE(current_attributes),
+ }, {
+ .class = PSC_CURRENT_OUT,
+ .attr = current_attributes,
+ .nattr = ARRAY_SIZE(current_attributes),
+ }, {
+ .class = PSC_POWER,
+ .attr = power_attributes,
+ .nattr = ARRAY_SIZE(power_attributes),
+ }, {
+ .class = PSC_TEMPERATURE,
+ .attr = temp_attributes,
+ .nattr = ARRAY_SIZE(temp_attributes),
+ }
+};
+
+/*
+ * Read the coefficients for direct mode.
+ */
+static int pmbus_read_coefficients(struct i2c_client *client,
+ struct pmbus_driver_info *info,
+ const struct pmbus_sensor_attr *attr)
+{
+ int rv;
+ union i2c_smbus_data data;
+ enum pmbus_sensor_classes class = attr->class;
+ s8 R;
+ s16 m, b;
+
+ data.block[0] = 2;
+ data.block[1] = attr->reg;
+ data.block[2] = 0x01;
+
+ rv = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_WRITE, PMBUS_COEFFICIENTS,
+ I2C_SMBUS_BLOCK_PROC_CALL, &data);
+
+ if (rv < 0)
+ return rv;
+
+ if (data.block[0] != 5)
+ return -EIO;
+
+ m = data.block[1] | (data.block[2] << 8);
+ b = data.block[3] | (data.block[4] << 8);
+ R = data.block[5];
+ info->m[class] = m;
+ info->b[class] = b;
+ info->R[class] = R;
+
+ return rv;
+}
+
+static int pmbus_init_coefficients(struct i2c_client *client,
+ struct pmbus_driver_info *info)
+{
+ int i, n, ret = -EINVAL;
+ const struct pmbus_class_attr_map *map;
+ const struct pmbus_sensor_attr *attr;
+
+ for (i = 0; i < ARRAY_SIZE(class_attr_map); i++) {
+ map = &class_attr_map[i];
+ if (info->format[map->class] != direct)
+ continue;
+ for (n = 0; n < map->nattr; n++) {
+ attr = &map->attr[n];
+ if (map->class != attr->class)
+ continue;
+ ret = pmbus_read_coefficients(client, info, attr);
+ if (ret >= 0)
+ break;
+ }
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "No coefficients found for sensor class %d\n",
+ map->class);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/*
* Identify chip parameters.
* This function is called for all chips.
*/
@@ -2214,11 +2321,14 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
data->has_status_word = true;
}
- /* Enable PEC if the controller supports it */
+ /* Enable PEC if the controller and bus supports it */
if (!(data->flags & PMBUS_NO_CAPABILITY)) {
ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY);
- if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK))
- client->flags |= I2C_CLIENT_PEC;
+ if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) {
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_PEC)) {
+ client->flags |= I2C_CLIENT_PEC;
+ }
+ }
}
/*
@@ -2226,9 +2336,11 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
* faults, and we should not try it. Also, in that case, writes into
* limit registers need to be disabled.
*/
- ret = i2c_smbus_read_byte_data(client, PMBUS_WRITE_PROTECT);
- if (ret > 0 && (ret & PB_WP_ANY))
- data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK;
+ if (!(data->flags & PMBUS_NO_WRITE_PROTECT)) {
+ ret = i2c_smbus_read_byte_data(client, PMBUS_WRITE_PROTECT);
+ if (ret > 0 && (ret & PB_WP_ANY))
+ data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK;
+ }
if (data->info->pages)
pmbus_clear_faults(client);
@@ -2255,6 +2367,17 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
return ret;
}
}
+
+ if (data->flags & PMBUS_USE_COEFFICIENTS_CMD) {
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL))
+ return -ENODEV;
+
+ ret = pmbus_init_coefficients(client, info);
+ if (ret < 0)
+ return ret;
+ }
+
return 0;
}
diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c
index b7d4eacdc3ef..e9df0c56d91e 100644
--- a/drivers/hwmon/pmbus/zl6100.c
+++ b/drivers/hwmon/pmbus/zl6100.c
@@ -18,7 +18,7 @@
#include "pmbus.h"
enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105,
- zl9101, zl9117 };
+ zl8802, zl9101, zl9117, zls1003, zls4009 };
struct zl6100_data {
int id;
@@ -34,6 +34,13 @@ struct zl6100_data {
#define ZL6100_MFR_XTEMP_ENABLE BIT(7)
+#define ZL8802_MFR_USER_GLOBAL_CONFIG 0xe9
+#define ZL8802_MFR_TMON_ENABLE BIT(12)
+#define ZL8802_MFR_USER_CONFIG 0xd1
+#define ZL8802_MFR_XTEMP_ENABLE_2 BIT(1)
+#define ZL8802_MFR_DDC_CONFIG 0xd3
+#define ZL8802_MFR_PHASES_MASK 0x0007
+
#define MFR_VMON_OV_FAULT_LIMIT 0xf5
#define MFR_VMON_UV_FAULT_LIMIT 0xf6
#define MFR_READ_VMON 0xf7
@@ -132,7 +139,7 @@ static int zl6100_read_word_data(struct i2c_client *client, int page,
struct zl6100_data *data = to_zl6100_data(info);
int ret, vreg;
- if (page > 0)
+ if (page >= info->pages)
return -ENXIO;
if (data->id == zl2005) {
@@ -191,7 +198,7 @@ static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg)
struct zl6100_data *data = to_zl6100_data(info);
int ret, status;
- if (page > 0)
+ if (page >= info->pages)
return -ENXIO;
zl6100_wait(data);
@@ -230,7 +237,7 @@ static int zl6100_write_word_data(struct i2c_client *client, int page, int reg,
struct zl6100_data *data = to_zl6100_data(info);
int ret, vreg;
- if (page > 0)
+ if (page >= info->pages)
return -ENXIO;
switch (reg) {
@@ -271,7 +278,7 @@ static int zl6100_write_byte(struct i2c_client *client, int page, u8 value)
struct zl6100_data *data = to_zl6100_data(info);
int ret;
- if (page > 0)
+ if (page >= info->pages)
return -ENXIO;
zl6100_wait(data);
@@ -287,6 +294,10 @@ static const struct i2c_device_id zl6100_id[] = {
{"bmr462", zl2008},
{"bmr463", zl2008},
{"bmr464", zl2008},
+ {"bmr465", zls4009},
+ {"bmr466", zls1003},
+ {"bmr467", zls4009},
+ {"bmr469", zl8802},
{"zl2004", zl2004},
{"zl2005", zl2005},
{"zl2006", zl2006},
@@ -295,15 +306,18 @@ static const struct i2c_device_id zl6100_id[] = {
{"zl2106", zl2106},
{"zl6100", zl6100},
{"zl6105", zl6105},
+ {"zl8802", zl8802},
{"zl9101", zl9101},
{"zl9117", zl9117},
+ {"zls1003", zls1003},
+ {"zls4009", zls4009},
{ }
};
MODULE_DEVICE_TABLE(i2c, zl6100_id);
static int zl6100_probe(struct i2c_client *client)
{
- int ret;
+ int ret, i;
struct zl6100_data *data;
struct pmbus_driver_info *info;
u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
@@ -367,18 +381,70 @@ static int zl6100_probe(struct i2c_client *client)
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
/*
- * ZL2004, ZL9101M, and ZL9117M support monitoring an extra voltage
- * (VMON for ZL2004, VDRV for ZL9101M and ZL9117M). Report it as vmon.
+ * ZL2004, ZL8802, ZL9101M, ZL9117M and ZLS4009 support monitoring
+ * an extra voltage (VMON for ZL2004, ZL8802 and ZLS4009,
+ * VDRV for ZL9101M and ZL9117M). Report it as vmon.
*/
- if (data->id == zl2004 || data->id == zl9101 || data->id == zl9117)
+ if (data->id == zl2004 || data->id == zl8802 || data->id == zl9101 ||
+ data->id == zl9117 || data->id == zls4009)
info->func[0] |= PMBUS_HAVE_VMON | PMBUS_HAVE_STATUS_VMON;
- ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG);
- if (ret < 0)
- return ret;
+ /*
+ * ZL8802 has two outputs that can be used either independently or in
+ * a current sharing configuration. The driver uses the DDC_CONFIG
+ * register to check if the module is running with independent or
+ * shared outputs. If the module is in shared output mode, only one
+ * output voltage will be reported.
+ */
+ if (data->id == zl8802) {
+ info->pages = 2;
+ info->func[0] |= PMBUS_HAVE_IIN;
+
+ ret = i2c_smbus_read_word_data(client, ZL8802_MFR_DDC_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ data->access = ktime_get();
+ zl6100_wait(data);
+
+ if (ret & ZL8802_MFR_PHASES_MASK)
+ info->func[1] |= PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
+ else
+ info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
- if (ret & ZL6100_MFR_XTEMP_ENABLE)
- info->func[0] |= PMBUS_HAVE_TEMP2;
+ for (i = 0; i < 2; i++) {
+ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
+ if (ret < 0)
+ return ret;
+
+ data->access = ktime_get();
+ zl6100_wait(data);
+
+ ret = i2c_smbus_read_word_data(client, ZL8802_MFR_USER_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ if (ret & ZL8802_MFR_XTEMP_ENABLE_2)
+ info->func[i] |= PMBUS_HAVE_TEMP2;
+
+ data->access = ktime_get();
+ zl6100_wait(data);
+ }
+ ret = i2c_smbus_read_word_data(client, ZL8802_MFR_USER_GLOBAL_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ if (ret & ZL8802_MFR_TMON_ENABLE)
+ info->func[0] |= PMBUS_HAVE_TEMP3;
+ } else {
+ ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ if (ret & ZL6100_MFR_XTEMP_ENABLE)
+ info->func[0] |= PMBUS_HAVE_TEMP2;
+ }
data->access = ktime_get();
zl6100_wait(data);
diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c
index 4324a5dbc968..8f1b569c69e7 100644
--- a/drivers/hwmon/sch5627.c
+++ b/drivers/hwmon/sch5627.c
@@ -64,7 +64,6 @@ static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {
struct sch5627_data {
unsigned short addr;
- struct sch56xx_watchdog_data *watchdog;
u8 control;
u8 temp_max[SCH5627_NO_TEMPS];
u8 temp_crit[SCH5627_NO_TEMPS];
@@ -357,16 +356,6 @@ static const struct hwmon_chip_info sch5627_chip_info = {
.info = sch5627_info,
};
-static int sch5627_remove(struct platform_device *pdev)
-{
- struct sch5627_data *data = platform_get_drvdata(pdev);
-
- if (data->watchdog)
- sch56xx_watchdog_unregister(data->watchdog);
-
- return 0;
-}
-
static int sch5627_probe(struct platform_device *pdev)
{
struct sch5627_data *data;
@@ -460,9 +449,9 @@ static int sch5627_probe(struct platform_device *pdev)
return PTR_ERR(hwmon_dev);
/* Note failing to register the watchdog is not a fatal error */
- data->watchdog = sch56xx_watchdog_register(&pdev->dev, data->addr,
- (build_code << 24) | (build_id << 8) | hwmon_rev,
- &data->update_lock, 1);
+ sch56xx_watchdog_register(&pdev->dev, data->addr,
+ (build_code << 24) | (build_id << 8) | hwmon_rev,
+ &data->update_lock, 1);
return 0;
}
@@ -472,7 +461,6 @@ static struct platform_driver sch5627_driver = {
.name = DRVNAME,
},
.probe = sch5627_probe,
- .remove = sch5627_remove,
};
module_platform_driver(sch5627_driver);
diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c
index 5683a38740f6..a5cd4de36575 100644
--- a/drivers/hwmon/sch5636.c
+++ b/drivers/hwmon/sch5636.c
@@ -54,7 +54,6 @@ static const u16 SCH5636_REG_FAN_VAL[SCH5636_NO_FANS] = {
struct sch5636_data {
unsigned short addr;
struct device *hwmon_dev;
- struct sch56xx_watchdog_data *watchdog;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -372,9 +371,6 @@ static int sch5636_remove(struct platform_device *pdev)
struct sch5636_data *data = platform_get_drvdata(pdev);
int i;
- if (data->watchdog)
- sch56xx_watchdog_unregister(data->watchdog);
-
if (data->hwmon_dev)
hwmon_device_unregister(data->hwmon_dev);
@@ -495,9 +491,8 @@ static int sch5636_probe(struct platform_device *pdev)
}
/* Note failing to register the watchdog is not a fatal error */
- data->watchdog = sch56xx_watchdog_register(&pdev->dev, data->addr,
- (revision[0] << 8) | revision[1],
- &data->update_lock, 0);
+ sch56xx_watchdog_register(&pdev->dev, data->addr, (revision[0] << 8) | revision[1],
+ &data->update_lock, 0);
return 0;
diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c
index 6c84780e358e..40cdadad35e5 100644
--- a/drivers/hwmon/sch56xx-common.c
+++ b/drivers/hwmon/sch56xx-common.c
@@ -20,8 +20,8 @@
#include "sch56xx-common.h"
/* Insmod parameters */
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+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) ")");
@@ -378,8 +378,8 @@ static const struct watchdog_ops watchdog_ops = {
.set_timeout = watchdog_set_timeout,
};
-struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
- u16 addr, u32 revision, struct mutex *io_lock, int check_enabled)
+void sch56xx_watchdog_register(struct device *parent, u16 addr, u32 revision,
+ struct mutex *io_lock, int check_enabled)
{
struct sch56xx_watchdog_data *data;
int err, control, output_enable;
@@ -393,23 +393,22 @@ struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
mutex_unlock(io_lock);
if (control < 0)
- return NULL;
+ return;
if (output_enable < 0)
- return NULL;
+ return;
if (check_enabled && !(output_enable & SCH56XX_WDOG_OUTPUT_ENABLE)) {
pr_warn("Watchdog not enabled by BIOS, not registering\n");
- return NULL;
+ return;
}
- data = kzalloc(sizeof(struct sch56xx_watchdog_data), GFP_KERNEL);
+ data = devm_kzalloc(parent, sizeof(struct sch56xx_watchdog_data), GFP_KERNEL);
if (!data)
- return NULL;
+ return;
data->addr = addr;
data->io_lock = io_lock;
- strlcpy(data->wdinfo.identity, "sch56xx watchdog",
- sizeof(data->wdinfo.identity));
+ strscpy(data->wdinfo.identity, "sch56xx watchdog", sizeof(data->wdinfo.identity));
data->wdinfo.firmware_version = revision;
data->wdinfo.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT;
if (!nowayout)
@@ -421,8 +420,7 @@ struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
data->wddev.timeout = 60;
data->wddev.min_timeout = 1;
data->wddev.max_timeout = 255 * 60;
- if (nowayout)
- set_bit(WDOG_NO_WAY_OUT, &data->wddev.status);
+ watchdog_set_nowayout(&data->wddev, nowayout);
if (output_enable & SCH56XX_WDOG_OUTPUT_ENABLE)
set_bit(WDOG_ACTIVE, &data->wddev.status);
@@ -438,24 +436,14 @@ struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
data->watchdog_output_enable = output_enable;
watchdog_set_drvdata(&data->wddev, data);
- err = watchdog_register_device(&data->wddev);
+ err = devm_watchdog_register_device(parent, &data->wddev);
if (err) {
pr_err("Registering watchdog chardev: %d\n", err);
- kfree(data);
- return NULL;
+ devm_kfree(parent, data);
}
-
- return data;
}
EXPORT_SYMBOL(sch56xx_watchdog_register);
-void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data)
-{
- watchdog_unregister_device(&data->wddev);
- kfree(data);
-}
-EXPORT_SYMBOL(sch56xx_watchdog_unregister);
-
/*
* platform dev find, add and remove functions
*/
@@ -516,37 +504,18 @@ static int __init sch56xx_device_add(int address, const char *name)
struct resource res = {
.start = address,
.end = address + REGION_LENGTH - 1,
+ .name = name,
.flags = IORESOURCE_IO,
};
int err;
- sch56xx_pdev = platform_device_alloc(name, address);
- if (!sch56xx_pdev)
- return -ENOMEM;
-
- res.name = sch56xx_pdev->name;
err = acpi_check_resource_conflict(&res);
if (err)
- goto exit_device_put;
-
- err = platform_device_add_resources(sch56xx_pdev, &res, 1);
- if (err) {
- pr_err("Device resource addition failed\n");
- goto exit_device_put;
- }
-
- err = platform_device_add(sch56xx_pdev);
- if (err) {
- pr_err("Device addition failed\n");
- goto exit_device_put;
- }
-
- return 0;
+ return err;
-exit_device_put:
- platform_device_put(sch56xx_pdev);
+ sch56xx_pdev = platform_device_register_simple(name, -1, &res, 1);
- return err;
+ return PTR_ERR_OR_ZERO(sch56xx_pdev);
}
static int __init sch56xx_init(void)
diff --git a/drivers/hwmon/sch56xx-common.h b/drivers/hwmon/sch56xx-common.h
index 75eb73617cf2..e907d9da0dd5 100644
--- a/drivers/hwmon/sch56xx-common.h
+++ b/drivers/hwmon/sch56xx-common.h
@@ -14,6 +14,6 @@ int sch56xx_read_virtual_reg16(u16 addr, u16 reg);
int sch56xx_read_virtual_reg12(u16 addr, u16 msb_reg, u16 lsn_reg,
int high_nibble);
-struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
- u16 addr, u32 revision, struct mutex *io_lock, int check_enabled);
+void sch56xx_watchdog_register(struct device *parent, u16 addr, u32 revision,
+ struct mutex *io_lock, int check_enabled);
void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data);
diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c
new file mode 100644
index 000000000000..09c2a0b06444
--- /dev/null
+++ b/drivers/hwmon/sht4x.c
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (c) Linumiz 2021
+ *
+ * sht4x.c - Linux hwmon driver for SHT4x Temperature and Humidity sensor
+ *
+ * Author: Navin Sankar Velliangiri <navin@linumiz.com>
+ */
+
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/hwmon.h>
+#include <linux/i2c.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+
+/*
+ * Poll intervals (in milliseconds)
+ */
+#define SHT4X_MIN_POLL_INTERVAL 2000
+
+/*
+ * I2C command delays (in microseconds)
+ */
+#define SHT4X_MEAS_DELAY 1000
+#define SHT4X_DELAY_EXTRA 10000
+
+/*
+ * Command Bytes
+ */
+#define SHT4X_CMD_MEASURE_HPM 0b11111101
+#define SHT4X_CMD_RESET 0b10010100
+
+#define SHT4X_CMD_LEN 1
+#define SHT4X_CRC8_LEN 1
+#define SHT4X_WORD_LEN 2
+#define SHT4X_RESPONSE_LENGTH 6
+#define SHT4X_CRC8_POLYNOMIAL 0x31
+#define SHT4X_CRC8_INIT 0xff
+#define SHT4X_MIN_TEMPERATURE -45000
+#define SHT4X_MAX_TEMPERATURE 125000
+#define SHT4X_MIN_HUMIDITY 0
+#define SHT4X_MAX_HUMIDITY 100000
+
+DECLARE_CRC8_TABLE(sht4x_crc8_table);
+
+/**
+ * struct sht4x_data - All the data required to operate an SHT4X chip
+ * @client: the i2c client associated with the SHT4X
+ * @lock: a mutex that is used to prevent parallel access to the i2c client
+ * @update_interval: the minimum poll interval
+ * @last_updated: the previous time that the SHT4X was polled
+ * @temperature: the latest temperature value received from the SHT4X
+ * @humidity: the latest humidity value received from the SHT4X
+ */
+struct sht4x_data {
+ struct i2c_client *client;
+ struct mutex lock; /* atomic read data updates */
+ bool valid; /* validity of fields below */
+ long update_interval; /* in milli-seconds */
+ long last_updated; /* in jiffies */
+ s32 temperature;
+ s32 humidity;
+};
+
+/**
+ * sht4x_read_values() - read and parse the raw data from the SHT4X
+ * @sht4x_data: the struct sht4x_data to use for the lock
+ * Return: 0 if successful, -ERRNO if not
+ */
+static int sht4x_read_values(struct sht4x_data *data)
+{
+ int ret = 0;
+ u16 t_ticks, rh_ticks;
+ unsigned long next_update;
+ struct i2c_client *client = data->client;
+ u8 crc;
+ u8 cmd[SHT4X_CMD_LEN] = {SHT4X_CMD_MEASURE_HPM};
+ u8 raw_data[SHT4X_RESPONSE_LENGTH];
+
+ mutex_lock(&data->lock);
+ next_update = data->last_updated +
+ msecs_to_jiffies(data->update_interval);
+
+ if (data->valid && time_before_eq(jiffies, next_update))
+ goto unlock;
+
+ ret = i2c_master_send(client, cmd, SHT4X_CMD_LEN);
+ if (ret < 0)
+ goto unlock;
+
+ usleep_range(SHT4X_MEAS_DELAY, SHT4X_MEAS_DELAY + SHT4X_DELAY_EXTRA);
+
+ ret = i2c_master_recv(client, raw_data, SHT4X_RESPONSE_LENGTH);
+ if (ret != SHT4X_RESPONSE_LENGTH) {
+ if (ret >= 0)
+ ret = -ENODATA;
+ goto unlock;
+ }
+
+ t_ticks = raw_data[0] << 8 | raw_data[1];
+ rh_ticks = raw_data[3] << 8 | raw_data[4];
+
+ crc = crc8(sht4x_crc8_table, &raw_data[0], SHT4X_WORD_LEN, CRC8_INIT_VALUE);
+ if (crc != raw_data[2]) {
+ dev_err(&client->dev, "data integrity check failed\n");
+ ret = -EIO;
+ goto unlock;
+ }
+
+ crc = crc8(sht4x_crc8_table, &raw_data[3], SHT4X_WORD_LEN, CRC8_INIT_VALUE);
+ if (crc != raw_data[5]) {
+ dev_err(&client->dev, "data integrity check failed\n");
+ ret = -EIO;
+ goto unlock;
+ }
+
+ data->temperature = ((21875 * (int32_t)t_ticks) >> 13) - 45000;
+ data->humidity = ((15625 * (int32_t)rh_ticks) >> 13) - 6000;
+ data->last_updated = jiffies;
+ data->valid = true;
+ ret = 0;
+
+unlock:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static ssize_t sht4x_interval_write(struct sht4x_data *data, long val)
+{
+ data->update_interval = clamp_val(val, SHT4X_MIN_POLL_INTERVAL, UINT_MAX);
+
+ return 0;
+}
+
+/* sht4x_interval_read() - read the minimum poll interval in milliseconds */
+static size_t sht4x_interval_read(struct sht4x_data *data, long *val)
+{
+ *val = data->update_interval;
+ return 0;
+}
+
+/* sht4x_temperature1_read() - read the temperature in millidegrees */
+static int sht4x_temperature1_read(struct sht4x_data *data, long *val)
+{
+ int ret;
+
+ ret = sht4x_read_values(data);
+ if (ret < 0)
+ return ret;
+
+ *val = data->temperature;
+
+ return 0;
+}
+
+/* sht4x_humidity1_read() - read a relative humidity in millipercent */
+static int sht4x_humidity1_read(struct sht4x_data *data, long *val)
+{
+ int ret;
+
+ ret = sht4x_read_values(data);
+ if (ret < 0)
+ return ret;
+
+ *val = data->humidity;
+
+ return 0;
+}
+
+static umode_t sht4x_hwmon_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ switch (type) {
+ case hwmon_temp:
+ case hwmon_humidity:
+ return 0444;
+ case hwmon_chip:
+ return 0644;
+ default:
+ return 0;
+ }
+}
+
+static int sht4x_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct sht4x_data *data = dev_get_drvdata(dev);
+
+ switch (type) {
+ case hwmon_temp:
+ return sht4x_temperature1_read(data, val);
+ case hwmon_humidity:
+ return sht4x_humidity1_read(data, val);
+ case hwmon_chip:
+ return sht4x_interval_read(data, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int sht4x_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
+ struct sht4x_data *data = dev_get_drvdata(dev);
+
+ switch (type) {
+ case hwmon_chip:
+ return sht4x_interval_write(data, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static const struct hwmon_channel_info *sht4x_info[] = {
+ HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL),
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
+ HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT),
+ NULL,
+};
+
+static const struct hwmon_ops sht4x_hwmon_ops = {
+ .is_visible = sht4x_hwmon_visible,
+ .read = sht4x_hwmon_read,
+ .write = sht4x_hwmon_write,
+};
+
+static const struct hwmon_chip_info sht4x_chip_info = {
+ .ops = &sht4x_hwmon_ops,
+ .info = sht4x_info,
+};
+
+static int sht4x_probe(struct i2c_client *client,
+ const struct i2c_device_id *sht4x_id)
+{
+ struct device *device = &client->dev;
+ struct device *hwmon_dev;
+ struct sht4x_data *data;
+ u8 cmd[] = {SHT4X_CMD_RESET};
+ int ret;
+
+ /*
+ * we require full i2c support since the sht4x uses multi-byte read and
+ * writes as well as multi-byte commands which are not supported by
+ * the smbus protocol
+ */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -EOPNOTSUPP;
+
+ data = devm_kzalloc(device, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->update_interval = SHT4X_MIN_POLL_INTERVAL;
+ data->client = client;
+
+ mutex_init(&data->lock);
+
+ crc8_populate_msb(sht4x_crc8_table, SHT4X_CRC8_POLYNOMIAL);
+
+ ret = i2c_master_send(client, cmd, SHT4X_CMD_LEN);
+ if (ret < 0)
+ return ret;
+ if (ret != SHT4X_CMD_LEN)
+ return -EIO;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(device,
+ client->name,
+ data,
+ &sht4x_chip_info,
+ NULL);
+
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct i2c_device_id sht4x_id[] = {
+ { "sht4x", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, sht4x_id);
+
+static struct i2c_driver sht4x_driver = {
+ .driver = {
+ .name = "sht4x",
+ },
+ .probe = sht4x_probe,
+ .id_table = sht4x_id,
+};
+
+module_i2c_driver(sht4x_driver);
+
+MODULE_AUTHOR("Navin Sankar Velliangiri <navin@linumiz.com>");
+MODULE_DESCRIPTION("Sensirion SHT4x humidity and temperature sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig
index 53e13476e831..3874d15b0e9b 100644
--- a/drivers/hwspinlock/Kconfig
+++ b/drivers/hwspinlock/Kconfig
@@ -44,6 +44,15 @@ config HWSPINLOCK_STM32
If unsure, say N.
+config HWSPINLOCK_SUN6I
+ tristate "SUN6I Hardware Spinlock device"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ help
+ Say y here to support the SUN6I Hardware Spinlock device which can be
+ found in most of the sun6i compatible Allwinner SoCs.
+
+ If unsure, say N.
+
config HSEM_U8500
tristate "STE Hardware Semaphore functionality"
depends on ARCH_U8500 || COMPILE_TEST
diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile
index 1f8dd6f5814f..a0f16c9aaa82 100644
--- a/drivers/hwspinlock/Makefile
+++ b/drivers/hwspinlock/Makefile
@@ -8,4 +8,5 @@ obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o
obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o
obj-$(CONFIG_HWSPINLOCK_SPRD) += sprd_hwspinlock.o
obj-$(CONFIG_HWSPINLOCK_STM32) += stm32_hwspinlock.o
+obj-$(CONFIG_HWSPINLOCK_SUN6I) += sun6i_hwspinlock.o
obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o
diff --git a/drivers/hwspinlock/sun6i_hwspinlock.c b/drivers/hwspinlock/sun6i_hwspinlock.c
new file mode 100644
index 000000000000..c2d314588046
--- /dev/null
+++ b/drivers/hwspinlock/sun6i_hwspinlock.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * sun6i_hwspinlock.c - hardware spinlock driver for sun6i compatible Allwinner SoCs
+ * Copyright (C) 2020 Wilken Gottwalt <wilken.gottwalt@posteo.net>
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/errno.h>
+#include <linux/hwspinlock.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "hwspinlock_internal.h"
+
+#define DRIVER_NAME "sun6i_hwspinlock"
+
+#define SPINLOCK_BASE_ID 0 /* there is only one hwspinlock device per SoC */
+#define SPINLOCK_SYSSTATUS_REG 0x0000
+#define SPINLOCK_LOCK_REGN 0x0100
+#define SPINLOCK_NOTTAKEN 0
+
+struct sun6i_hwspinlock_data {
+ struct hwspinlock_device *bank;
+ struct reset_control *reset;
+ struct clk *ahb_clk;
+ struct dentry *debugfs;
+ int nlocks;
+};
+
+#ifdef CONFIG_DEBUG_FS
+
+static int hwlocks_supported_show(struct seq_file *seqf, void *unused)
+{
+ struct sun6i_hwspinlock_data *priv = seqf->private;
+
+ seq_printf(seqf, "%d\n", priv->nlocks);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(hwlocks_supported);
+
+static void sun6i_hwspinlock_debugfs_init(struct sun6i_hwspinlock_data *priv)
+{
+ priv->debugfs = debugfs_create_dir(DRIVER_NAME, NULL);
+ debugfs_create_file("supported", 0444, priv->debugfs, priv, &hwlocks_supported_fops);
+}
+
+#else
+
+static void sun6i_hwspinlock_debugfs_init(struct sun6i_hwspinlock_data *priv)
+{
+}
+
+#endif
+
+static int sun6i_hwspinlock_trylock(struct hwspinlock *lock)
+{
+ void __iomem *lock_addr = lock->priv;
+
+ return (readl(lock_addr) == SPINLOCK_NOTTAKEN);
+}
+
+static void sun6i_hwspinlock_unlock(struct hwspinlock *lock)
+{
+ void __iomem *lock_addr = lock->priv;
+
+ writel(SPINLOCK_NOTTAKEN, lock_addr);
+}
+
+static const struct hwspinlock_ops sun6i_hwspinlock_ops = {
+ .trylock = sun6i_hwspinlock_trylock,
+ .unlock = sun6i_hwspinlock_unlock,
+};
+
+static void sun6i_hwspinlock_disable(void *data)
+{
+ struct sun6i_hwspinlock_data *priv = data;
+
+ debugfs_remove_recursive(priv->debugfs);
+ clk_disable_unprepare(priv->ahb_clk);
+ reset_control_assert(priv->reset);
+}
+
+static int sun6i_hwspinlock_probe(struct platform_device *pdev)
+{
+ struct sun6i_hwspinlock_data *priv;
+ struct hwspinlock *hwlock;
+ void __iomem *io_base;
+ u32 num_banks;
+ int err, i;
+
+ io_base = devm_platform_ioremap_resource(pdev, SPINLOCK_BASE_ID);
+ if (IS_ERR(io_base))
+ return PTR_ERR(io_base);
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->ahb_clk = devm_clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(priv->ahb_clk)) {
+ err = PTR_ERR(priv->ahb_clk);
+ dev_err(&pdev->dev, "unable to get AHB clock (%d)\n", err);
+ return err;
+ }
+
+ priv->reset = devm_reset_control_get(&pdev->dev, "ahb");
+ if (IS_ERR(priv->reset))
+ return dev_err_probe(&pdev->dev, PTR_ERR(priv->reset),
+ "unable to get reset control\n");
+
+ err = reset_control_deassert(priv->reset);
+ if (err) {
+ dev_err(&pdev->dev, "deassert reset control failure (%d)\n", err);
+ return err;
+ }
+
+ err = clk_prepare_enable(priv->ahb_clk);
+ if (err) {
+ dev_err(&pdev->dev, "unable to prepare AHB clk (%d)\n", err);
+ goto clk_fail;
+ }
+
+ /*
+ * bit 28 and 29 represents the hwspinlock setup
+ *
+ * every datasheet (A64, A80, A83T, H3, H5, H6 ...) says the default value is 0x1 and 0x1
+ * to 0x4 represent 32, 64, 128 and 256 locks
+ * but later datasheets (H5, H6) say 00, 01, 10, 11 represent 32, 64, 128 and 256 locks,
+ * but that would mean H5 and H6 have 64 locks, while their datasheets talk about 32 locks
+ * all the time, not a single mentioning of 64 locks
+ * the 0x4 value is also not representable by 2 bits alone, so some datasheets are not
+ * correct
+ * one thing have all in common, default value of the sysstatus register is 0x10000000,
+ * which results in bit 28 being set
+ * this is the reason 0x1 is considered being 32 locks and bit 30 is taken into account
+ * verified on H2+ (datasheet 0x1 = 32 locks) and H5 (datasheet 01 = 64 locks)
+ */
+ num_banks = readl(io_base + SPINLOCK_SYSSTATUS_REG) >> 28;
+ switch (num_banks) {
+ case 1 ... 4:
+ priv->nlocks = 1 << (4 + num_banks);
+ break;
+ default:
+ err = -EINVAL;
+ dev_err(&pdev->dev, "unsupported hwspinlock setup (%d)\n", num_banks);
+ goto bank_fail;
+ }
+
+ priv->bank = devm_kzalloc(&pdev->dev, struct_size(priv->bank, lock, priv->nlocks),
+ GFP_KERNEL);
+ if (!priv->bank) {
+ err = -ENOMEM;
+ goto bank_fail;
+ }
+
+ for (i = 0; i < priv->nlocks; ++i) {
+ hwlock = &priv->bank->lock[i];
+ hwlock->priv = io_base + SPINLOCK_LOCK_REGN + sizeof(u32) * i;
+ }
+
+ /* failure of debugfs is considered non-fatal */
+ sun6i_hwspinlock_debugfs_init(priv);
+ if (IS_ERR(priv->debugfs))
+ priv->debugfs = NULL;
+
+ err = devm_add_action_or_reset(&pdev->dev, sun6i_hwspinlock_disable, priv);
+ if (err) {
+ dev_err(&pdev->dev, "failed to add hwspinlock disable action\n");
+ goto bank_fail;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ return devm_hwspin_lock_register(&pdev->dev, priv->bank, &sun6i_hwspinlock_ops,
+ SPINLOCK_BASE_ID, priv->nlocks);
+
+bank_fail:
+ clk_disable_unprepare(priv->ahb_clk);
+clk_fail:
+ reset_control_assert(priv->reset);
+
+ return err;
+}
+
+static const struct of_device_id sun6i_hwspinlock_ids[] = {
+ { .compatible = "allwinner,sun6i-a31-hwspinlock", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sun6i_hwspinlock_ids);
+
+static struct platform_driver sun6i_hwspinlock_driver = {
+ .probe = sun6i_hwspinlock_probe,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = sun6i_hwspinlock_ids,
+ },
+};
+module_platform_driver(sun6i_hwspinlock_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SUN6I hardware spinlock driver");
+MODULE_AUTHOR("Wilken Gottwalt <wilken.gottwalt@posteo.net>");
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 6c68d34d956e..1002605db8ba 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -608,7 +608,7 @@ static struct coresight_device *
coresight_find_enabled_sink(struct coresight_device *csdev)
{
int i;
- struct coresight_device *sink;
+ struct coresight_device *sink = NULL;
if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
@@ -886,7 +886,6 @@ void coresight_release_path(struct list_head *path)
}
kfree(path);
- path = NULL;
}
/* return true if the device is a suitable type for a default sink */
@@ -1392,7 +1391,7 @@ static int coresight_fixup_device_conns(struct coresight_device *csdev)
}
}
- return 0;
+ return ret;
}
static int coresight_remove_match(struct device *dev, void *data)
@@ -1730,9 +1729,9 @@ char *coresight_alloc_device_name(struct coresight_dev_list *dict,
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);
+ list = krealloc_array(dict->fwnode_list,
+ idx + 1, sizeof(*dict->fwnode_list),
+ GFP_KERNEL);
if (ZERO_OR_NULL_PTR(list)) {
idx = -ENOMEM;
goto done;
diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c
index 2dcf13de751f..9731d3a96073 100644
--- a/drivers/hwtracing/coresight/coresight-cpu-debug.c
+++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/panic_notifier.h>
#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/smp.h>
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index db881993c211..da27cd4a3c38 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -568,11 +568,6 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata,
struct etmv4_config *config = &drvdata->config;
struct perf_event_attr *attr = &event->attr;
- if (!attr) {
- ret = -EINVAL;
- goto out;
- }
-
/* Clear configuration from previous run */
memset(config, 0, sizeof(struct etmv4_config));
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 45b85edfc690..cd0fb7bfba68 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -530,7 +530,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
buf_ptr = buf->data_pages[cur] + offset;
*buf_ptr = readl_relaxed(drvdata->base + TMC_RRD);
- if (lost && *barrier) {
+ if (lost && i < CORESIGHT_BARRIER_PKT_SIZE) {
*buf_ptr = *barrier;
barrier++;
}
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
index 24d0c974bfd5..66eed2dff818 100644
--- a/drivers/hwtracing/intel_th/core.c
+++ b/drivers/hwtracing/intel_th/core.c
@@ -100,16 +100,18 @@ static int intel_th_remove(struct device *dev)
struct intel_th_driver *thdrv = to_intel_th_driver(dev->driver);
struct intel_th_device *thdev = to_intel_th_device(dev);
struct intel_th_device *hub = to_intel_th_hub(thdev);
- int err;
if (thdev->type == INTEL_TH_SWITCH) {
struct intel_th *th = to_intel_th(hub);
int i, lowest;
- /* disconnect outputs */
- err = device_for_each_child(dev, thdev, intel_th_child_remove);
- if (err)
- return err;
+ /*
+ * disconnect outputs
+ *
+ * intel_th_child_remove returns 0 unconditionally, so there is
+ * no need to check the return value of device_for_each_child.
+ */
+ device_for_each_child(dev, thdev, intel_th_child_remove);
/*
* Remove outputs, that is, hub's children: they are created
@@ -215,6 +217,22 @@ static ssize_t port_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RO(port);
+static void intel_th_trace_prepare(struct intel_th_device *thdev)
+{
+ struct intel_th_device *hub = to_intel_th_hub(thdev);
+ struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
+
+ if (hub->type != INTEL_TH_SWITCH)
+ return;
+
+ if (thdev->type != INTEL_TH_OUTPUT)
+ return;
+
+ pm_runtime_get_sync(&thdev->dev);
+ hubdrv->prepare(hub, &thdev->output);
+ pm_runtime_put(&thdev->dev);
+}
+
static int intel_th_output_activate(struct intel_th_device *thdev)
{
struct intel_th_driver *thdrv =
@@ -235,6 +253,7 @@ static int intel_th_output_activate(struct intel_th_device *thdev)
if (ret)
goto fail_put;
+ intel_th_trace_prepare(thdev);
if (thdrv->activate)
ret = thdrv->activate(thdev);
else
diff --git a/drivers/hwtracing/intel_th/gth.c b/drivers/hwtracing/intel_th/gth.c
index 28509b02a0b5..b3308934a687 100644
--- a/drivers/hwtracing/intel_th/gth.c
+++ b/drivers/hwtracing/intel_th/gth.c
@@ -564,6 +564,21 @@ static void gth_tscu_resync(struct gth_device *gth)
iowrite32(reg, gth->base + REG_TSCU_TSUCTRL);
}
+static void intel_th_gth_prepare(struct intel_th_device *thdev,
+ struct intel_th_output *output)
+{
+ struct gth_device *gth = dev_get_drvdata(&thdev->dev);
+ int count;
+
+ /*
+ * Wait until the output port is in reset before we start
+ * programming it.
+ */
+ for (count = GTH_PLE_WAITLOOP_DEPTH;
+ count && !(gth_output_get(gth, output->port) & BIT(5)); count--)
+ cpu_relax();
+}
+
/**
* intel_th_gth_enable() - enable tracing to an output device
* @thdev: GTH device
@@ -815,6 +830,7 @@ static struct intel_th_driver intel_th_gth_driver = {
.assign = intel_th_gth_assign,
.unassign = intel_th_gth_unassign,
.set_output = intel_th_gth_set_output,
+ .prepare = intel_th_gth_prepare,
.enable = intel_th_gth_enable,
.trig_switch = intel_th_gth_switch,
.disable = intel_th_gth_disable,
diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h
index 89c67e0e1d34..0ffb42990175 100644
--- a/drivers/hwtracing/intel_th/intel_th.h
+++ b/drivers/hwtracing/intel_th/intel_th.h
@@ -143,6 +143,7 @@ intel_th_output_assigned(struct intel_th_device *thdev)
* @remove: remove method
* @assign: match a given output type device against available outputs
* @unassign: deassociate an output type device from an output port
+ * @prepare: prepare output port for tracing
* @enable: enable tracing for a given output device
* @disable: disable tracing for a given output device
* @irq: interrupt callback
@@ -164,6 +165,8 @@ struct intel_th_driver {
struct intel_th_device *othdev);
void (*unassign)(struct intel_th_device *thdev,
struct intel_th_device *othdev);
+ void (*prepare)(struct intel_th_device *thdev,
+ struct intel_th_output *output);
void (*enable)(struct intel_th_device *thdev,
struct intel_th_output *output);
void (*trig_switch)(struct intel_th_device *thdev,
diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c
index 2edc4666633d..432ade0842f6 100644
--- a/drivers/hwtracing/intel_th/msu.c
+++ b/drivers/hwtracing/intel_th/msu.c
@@ -1024,33 +1024,49 @@ err_nomem:
}
#ifdef CONFIG_X86
-static void msc_buffer_set_uc(struct msc_window *win, unsigned int nr_segs)
+static void msc_buffer_set_uc(struct msc *msc)
{
struct scatterlist *sg_ptr;
+ struct msc_window *win;
int i;
- for_each_sg(win->sgt->sgl, sg_ptr, nr_segs, i) {
- /* Set the page as uncached */
- set_memory_uc((unsigned long)sg_virt(sg_ptr),
- PFN_DOWN(sg_ptr->length));
+ if (msc->mode == MSC_MODE_SINGLE) {
+ set_memory_uc((unsigned long)msc->base, msc->nr_pages);
+ return;
+ }
+
+ list_for_each_entry(win, &msc->win_list, entry) {
+ for_each_sg(win->sgt->sgl, sg_ptr, win->nr_segs, i) {
+ /* Set the page as uncached */
+ set_memory_uc((unsigned long)sg_virt(sg_ptr),
+ PFN_DOWN(sg_ptr->length));
+ }
}
}
-static void msc_buffer_set_wb(struct msc_window *win)
+static void msc_buffer_set_wb(struct msc *msc)
{
struct scatterlist *sg_ptr;
+ struct msc_window *win;
int i;
- for_each_sg(win->sgt->sgl, sg_ptr, win->nr_segs, i) {
- /* Reset the page to write-back */
- set_memory_wb((unsigned long)sg_virt(sg_ptr),
- PFN_DOWN(sg_ptr->length));
+ if (msc->mode == MSC_MODE_SINGLE) {
+ set_memory_wb((unsigned long)msc->base, msc->nr_pages);
+ return;
+ }
+
+ list_for_each_entry(win, &msc->win_list, entry) {
+ for_each_sg(win->sgt->sgl, sg_ptr, win->nr_segs, i) {
+ /* Reset the page to write-back */
+ set_memory_wb((unsigned long)sg_virt(sg_ptr),
+ PFN_DOWN(sg_ptr->length));
+ }
}
}
#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) {}
+msc_buffer_set_uc(struct msc *msc) {}
+static inline void msc_buffer_set_wb(struct msc *msc) {}
#endif /* CONFIG_X86 */
/**
@@ -1097,8 +1113,6 @@ static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks)
if (ret <= 0)
goto err_nomem;
- msc_buffer_set_uc(win, ret);
-
win->nr_segs = ret;
win->nr_blocks = nr_blocks;
@@ -1152,8 +1166,6 @@ static void msc_buffer_win_free(struct msc *msc, struct msc_window *win)
msc->base_addr = 0;
}
- msc_buffer_set_wb(win);
-
if (msc->mbuf && msc->mbuf->free_window)
msc->mbuf->free_window(msc->mbuf_priv, win->sgt);
else
@@ -1260,6 +1272,8 @@ static int msc_buffer_multi_alloc(struct msc *msc, unsigned long *nr_pages,
*/
static void msc_buffer_free(struct msc *msc)
{
+ msc_buffer_set_wb(msc);
+
if (msc->mode == MSC_MODE_SINGLE)
msc_buffer_contig_free(msc);
else if (msc->mode == MSC_MODE_MULTI)
@@ -1303,6 +1317,8 @@ static int msc_buffer_alloc(struct msc *msc, unsigned long *nr_pages,
}
if (!ret) {
+ msc_buffer_set_uc(msc);
+
/* allocation should be visible before the counter goes to 0 */
smp_mb__before_atomic();
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index fb93152845f4..ee83c4581bce 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -508,6 +508,11 @@ static void ali1535_remove(struct pci_dev *dev)
{
i2c_del_adapter(&ali1535_adapter);
release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
+
+ /*
+ * do not call pci_disable_device(dev) since it can cause hard hangs on
+ * some systems during power-off
+ */
}
static struct pci_driver ali1535_driver = {
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
index 724bf30600d6..67e8b97c0c95 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -727,10 +727,14 @@ static void __aspeed_i2c_reg_slave(struct aspeed_i2c_bus *bus, u16 slave_addr)
{
u32 addr_reg_val, func_ctrl_reg_val;
- /* Set slave addr. */
- addr_reg_val = readl(bus->base + ASPEED_I2C_DEV_ADDR_REG);
- addr_reg_val &= ~ASPEED_I2CD_DEV_ADDR_MASK;
- addr_reg_val |= slave_addr & ASPEED_I2CD_DEV_ADDR_MASK;
+ /*
+ * Set slave addr. Reserved bits can all safely be written with zeros
+ * on all of ast2[456]00, so zero everything else to ensure we only
+ * enable a single slave address (ast2500 has two, ast2600 has three,
+ * the enable bits for which are also in this register) so that we don't
+ * end up with additional phantom devices responding on the bus.
+ */
+ addr_reg_val = slave_addr & ASPEED_I2CD_DEV_ADDR_MASK;
writel(addr_reg_val, bus->base + ASPEED_I2C_DEV_ADDR_REG);
/* Turn on slave mode. */
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 66aafa7d1123..20aa3398e642 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -578,6 +578,11 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
{
unsigned int ctrl_reg;
unsigned int isr_status;
+ unsigned long flags;
+ bool hold_clear = false;
+ bool irq_save = false;
+
+ u32 addr;
id->p_recv_buf = id->p_msg->buf;
id->recv_count = id->p_msg->len;
@@ -618,14 +623,43 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
}
- /* Set the slave address in address register - triggers operation */
- cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
- CDNS_I2C_ADDR_OFFSET);
- /* Clear the bus hold flag if bytes to receive is less than FIFO size */
+ /* Determine hold_clear based on number of bytes to receive and hold flag */
if (!id->bus_hold_flag &&
- ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
- (id->recv_count <= CDNS_I2C_FIFO_DEPTH))
- cdns_i2c_clear_bus_hold(id);
+ ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
+ (id->recv_count <= CDNS_I2C_FIFO_DEPTH)) {
+ if (cdns_i2c_readreg(CDNS_I2C_CR_OFFSET) & CDNS_I2C_CR_HOLD) {
+ hold_clear = true;
+ if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT)
+ irq_save = true;
+ }
+ }
+
+ addr = id->p_msg->addr;
+ addr &= CDNS_I2C_ADDR_MASK;
+
+ if (hold_clear) {
+ ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET) & ~CDNS_I2C_CR_HOLD;
+ /*
+ * In case of Xilinx Zynq SOC, clear the HOLD bit before transfer size
+ * register reaches '0'. This is an IP bug which causes transfer size
+ * register overflow to 0xFF. To satisfy this timing requirement,
+ * disable the interrupts on current processor core between register
+ * writes to slave address register and control register.
+ */
+ if (irq_save)
+ local_irq_save(flags);
+
+ cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET);
+ cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
+ /* Read it back to avoid bufferring and make sure write happens */
+ cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+
+ if (irq_save)
+ local_irq_restore(flags);
+ } else {
+ cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET);
+ }
+
cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
}
@@ -1217,11 +1251,10 @@ static int cdns_i2c_probe(struct platform_device *pdev)
"Cadence I2C at %08lx", (unsigned long)r_mem->start);
id->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(id->clk)) {
- if (PTR_ERR(id->clk) != -EPROBE_DEFER)
- dev_err(&pdev->dev, "input clock not found.\n");
- return PTR_ERR(id->clk);
- }
+ if (IS_ERR(id->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(id->clk),
+ "input clock not found.\n");
+
ret = clk_prepare_enable(id->clk);
if (ret)
dev_err(&pdev->dev, "Unable to enable clock.\n");
diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c
index 08f491ea21ac..1cf68f85b2e1 100644
--- a/drivers/i2c/busses/i2c-cht-wc.c
+++ b/drivers/i2c/busses/i2c-cht-wc.c
@@ -354,8 +354,7 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
return ret;
/* Alloc and register client IRQ */
- adap->irq_domain = irq_domain_add_linear(pdev->dev.of_node, 1,
- &irq_domain_simple_ops, NULL);
+ adap->irq_domain = irq_domain_add_linear(NULL, 1, &irq_domain_simple_ops, NULL);
if (!adap->irq_domain)
return -ENOMEM;
diff --git a/drivers/i2c/busses/i2c-cp2615.c b/drivers/i2c/busses/i2c-cp2615.c
index 78cfecd1ea76..3ded28632e4c 100644
--- a/drivers/i2c/busses/i2c-cp2615.c
+++ b/drivers/i2c/busses/i2c-cp2615.c
@@ -138,17 +138,23 @@ cp2615_i2c_send(struct usb_interface *usbif, struct cp2615_i2c_transfer *i2c_w)
static int
cp2615_i2c_recv(struct usb_interface *usbif, unsigned char tag, void *buf)
{
- struct cp2615_iop_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL);
- struct cp2615_i2c_transfer_result *i2c_r = (struct cp2615_i2c_transfer_result *)&msg->data;
struct usb_device *usbdev = interface_to_usbdev(usbif);
- int res = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, IOP_EP_IN),
- msg, sizeof(struct cp2615_iop_msg), NULL, 0);
+ struct cp2615_iop_msg *msg;
+ struct cp2615_i2c_transfer_result *i2c_r;
+ int res;
+
+ msg = kzalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+ res = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, IOP_EP_IN), msg,
+ sizeof(struct cp2615_iop_msg), NULL, 0);
if (res < 0) {
kfree(msg);
return res;
}
+ i2c_r = (struct cp2615_i2c_transfer_result *)&msg->data;
if (msg->msg != htons(iop_I2cTransferResult) || i2c_r->tag != tag) {
kfree(msg);
return -EIO;
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 232a7679b69b..e9d07323c604 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -768,10 +768,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
if (irq <= 0) {
if (!irq)
irq = -ENXIO;
- if (irq != -EPROBE_DEFER)
- dev_err(&pdev->dev,
- "can't get irq resource ret=%d\n", irq);
- return irq;
+ return dev_err_probe(&pdev->dev, irq, "can't get irq resource\n");
}
dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_i2c_dev),
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index f9e1c2ceaac0..aa3f60e69230 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -88,6 +88,8 @@
* See the file Documentation/i2c/busses/i2c-i801.rst for details.
*/
+#define DRV_NAME "i801_smbus"
+
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -103,7 +105,7 @@
#include <linux/dmi.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/wait.h>
+#include <linux/completion.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/platform_data/itco_wdt.h>
@@ -131,8 +133,6 @@
/* PCI Address Constants */
#define SMBBAR 4
-#define SMBPCICTL 0x004
-#define SMBPCISTS 0x006
#define SMBHSTCFG 0x040
#define TCOBASE 0x050
#define TCOCTL 0x054
@@ -141,12 +141,6 @@
#define SBREG_SMBCTRL 0xc6000c
#define SBREG_SMBCTRL_DNV 0xcf000c
-/* Host status bits for SMBPCISTS */
-#define SMBPCISTS_INTS BIT(3)
-
-/* Control bits for SMBPCICTL */
-#define SMBPCICTL_INTDIS BIT(10)
-
/* Host configuration bits for SMBHSTCFG */
#define SMBHSTCFG_HST_EN BIT(0)
#define SMBHSTCFG_SMB_SMI_EN BIT(1)
@@ -164,9 +158,6 @@
#define SMBAUXCTL_CRC BIT(0)
#define SMBAUXCTL_E32B BIT(1)
-/* Other settings */
-#define MAX_RETRIES 400
-
/* I801 command constants */
#define I801_QUICK 0x00
#define I801_BYTE 0x04
@@ -270,7 +261,7 @@ struct i801_priv {
unsigned int features;
/* isr processing */
- wait_queue_head_t waitq;
+ struct completion done;
u8 status;
/* Command state used by isr for byte-by-byte block transactions */
@@ -453,67 +444,53 @@ static int i801_check_post(struct i801_priv *priv, int status)
/* Wait for BUSY being cleared and either INTR or an error flag being set */
static int i801_wait_intr(struct i801_priv *priv)
{
- int timeout = 0;
- int status;
+ unsigned long timeout = jiffies + priv->adapter.timeout;
+ int status, busy;
- /* 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) ||
- !(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR))) &&
- (timeout++ < MAX_RETRIES));
+ busy = status & SMBHSTSTS_HOST_BUSY;
+ status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR;
+ if (!busy && status)
+ return status;
+ } while (time_is_after_eq_jiffies(timeout));
- if (timeout > MAX_RETRIES) {
- dev_dbg(&priv->pci_dev->dev, "INTR Timeout!\n");
- return -ETIMEDOUT;
- }
- return status & (STATUS_ERROR_FLAGS | SMBHSTSTS_INTR);
+ return -ETIMEDOUT;
}
/* Wait for either BYTE_DONE or an error flag being set */
static int i801_wait_byte_done(struct i801_priv *priv)
{
- int timeout = 0;
+ unsigned long timeout = jiffies + priv->adapter.timeout;
int status;
- /* We will always wait for a fraction of a second! */
do {
usleep_range(250, 500);
status = inb_p(SMBHSTSTS(priv));
- } while (!(status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE)) &&
- (timeout++ < MAX_RETRIES));
+ if (status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE))
+ return status & STATUS_ERROR_FLAGS;
+ } while (time_is_after_eq_jiffies(timeout));
- if (timeout > MAX_RETRIES) {
- dev_dbg(&priv->pci_dev->dev, "BYTE_DONE Timeout!\n");
- return -ETIMEDOUT;
- }
- return status & STATUS_ERROR_FLAGS;
+ return -ETIMEDOUT;
}
static int i801_transaction(struct i801_priv *priv, int xact)
{
int status;
- int result;
+ unsigned long result;
const struct i2c_adapter *adap = &priv->adapter;
- result = i801_check_pre(priv);
- if (result < 0)
- return result;
+ status = i801_check_pre(priv);
+ if (status < 0)
+ return status;
if (priv->features & FEATURE_IRQ) {
+ reinit_completion(&priv->done);
outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
SMBHSTCNT(priv));
- result = wait_event_timeout(priv->waitq,
- (status = priv->status),
- adap->timeout);
- if (!result) {
- status = -ETIMEDOUT;
- dev_warn(&priv->pci_dev->dev,
- "Timeout waiting for interrupt!\n");
- }
- priv->status = 0;
- return i801_check_post(priv, status);
+ result = wait_for_completion_timeout(&priv->done, adap->timeout);
+ return i801_check_post(priv, result ? priv->status : -ETIMEDOUT);
}
/* the current contents of SMBHSTCNT can be overwritten, since PEC,
@@ -638,7 +615,7 @@ static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
* DEV_ERR - Invalid command, NAK or communication timeout
* BUS_ERR - SMI# transaction collision
* FAILED - transaction was canceled due to a KILL request
- * When any of these occur, update ->status and wake up the waitq.
+ * When any of these occur, update ->status and signal completion.
* ->status must be cleared before kicking off the next transaction.
*
* 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt
@@ -653,8 +630,8 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
u8 status;
/* Confirm this is our interrupt */
- pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists);
- if (!(pcists & SMBPCISTS_INTS))
+ pci_read_config_word(priv->pci_dev, PCI_STATUS, &pcists);
+ if (!(pcists & PCI_STATUS_INTERRUPT))
return IRQ_NONE;
if (priv->features & FEATURE_HOST_NOTIFY) {
@@ -675,7 +652,7 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
if (status) {
outb_p(status, SMBHSTSTS(priv));
priv->status = status;
- wake_up(&priv->waitq);
+ complete(&priv->done);
}
return IRQ_HANDLED;
@@ -694,15 +671,15 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
int i, len;
int smbcmd;
int status;
- int result;
+ unsigned long 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;
+ status = i801_check_pre(priv);
+ if (status < 0)
+ return status;
len = data->block[0];
@@ -726,17 +703,10 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
priv->count = 0;
priv->data = &data->block[1];
+ reinit_completion(&priv->done);
outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv));
- result = wait_event_timeout(priv->waitq,
- (status = priv->status),
- adap->timeout);
- if (!result) {
- status = -ETIMEDOUT;
- dev_warn(&priv->pci_dev->dev,
- "Timeout waiting for interrupt!\n");
- }
- priv->status = 0;
- return i801_check_post(priv, status);
+ result = wait_for_completion_timeout(&priv->done, adap->timeout);
+ return i801_check_post(priv, result ? priv->status : -ETIMEDOUT);
}
for (i = 1; i <= len; i++) {
@@ -978,6 +948,9 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
}
out:
+ /* Unlock the SMBus device for use by BIOS/ACPI */
+ outb_p(SMBHSTSTS_INUSE_STS, SMBHSTSTS(priv));
+
pm_runtime_mark_last_busy(&priv->pci_dev->dev);
pm_runtime_put_autosuspend(&priv->pci_dev->dev);
mutex_unlock(&priv->acpi_lock);
@@ -1319,11 +1292,11 @@ static void i801_probe_optional_slaves(struct i801_priv *priv)
return;
if (apanel_addr) {
- struct i2c_board_info info;
+ struct i2c_board_info info = {
+ .addr = apanel_addr,
+ .type = "fujitsu_apanel",
+ };
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = apanel_addr;
- strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
i2c_new_client_device(&priv->adapter, &info);
}
@@ -1712,19 +1685,17 @@ static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; }
static inline void i801_acpi_remove(struct i801_priv *priv) { }
#endif
-static unsigned char i801_setup_hstcfg(struct i801_priv *priv)
+static void i801_setup_hstcfg(struct i801_priv *priv)
{
unsigned char hstcfg = priv->original_hstcfg;
hstcfg &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
hstcfg |= SMBHSTCFG_HST_EN;
pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hstcfg);
- return hstcfg;
}
static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
- unsigned char temp;
int err, i;
struct i801_priv *priv;
@@ -1835,8 +1806,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (i801_acpi_probe(priv))
return -ENODEV;
- err = pcim_iomap_regions(dev, 1 << SMBBAR,
- dev_driver_string(&dev->dev));
+ err = pcim_iomap_regions(dev, 1 << SMBBAR, DRV_NAME);
if (err) {
dev_err(&dev->dev,
"Failed to request SMBus region 0x%lx-0x%Lx\n",
@@ -1847,16 +1817,16 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
}
pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &priv->original_hstcfg);
- temp = i801_setup_hstcfg(priv);
+ i801_setup_hstcfg(priv);
if (!(priv->original_hstcfg & SMBHSTCFG_HST_EN))
dev_info(&dev->dev, "Enabling SMBus device\n");
- if (temp & SMBHSTCFG_SMB_SMI_EN) {
+ if (priv->original_hstcfg & SMBHSTCFG_SMB_SMI_EN) {
dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
/* Disable SMBus interrupt feature if SMBus using SMI# */
priv->features &= ~FEATURE_IRQ;
}
- if (temp & SMBHSTCFG_SPD_WD)
+ if (priv->original_hstcfg & SMBHSTCFG_SPD_WD)
dev_info(&dev->dev, "SPD Write Disable is set\n");
/* Clear special mode bits */
@@ -1878,24 +1848,23 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
u16 pcictl, pcists;
/* Complain if an interrupt is already pending */
- pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists);
- if (pcists & SMBPCISTS_INTS)
+ pci_read_config_word(priv->pci_dev, PCI_STATUS, &pcists);
+ if (pcists & PCI_STATUS_INTERRUPT)
dev_warn(&dev->dev, "An interrupt is pending!\n");
/* Check if interrupts have been disabled */
- pci_read_config_word(priv->pci_dev, SMBPCICTL, &pcictl);
- if (pcictl & SMBPCICTL_INTDIS) {
+ pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pcictl);
+ if (pcictl & PCI_COMMAND_INTX_DISABLE) {
dev_info(&dev->dev, "Interrupts are disabled\n");
priv->features &= ~FEATURE_IRQ;
}
}
if (priv->features & FEATURE_IRQ) {
- init_waitqueue_head(&priv->waitq);
+ init_completion(&priv->done);
err = devm_request_irq(&dev->dev, dev->irq, i801_isr,
- IRQF_SHARED,
- dev_driver_string(&dev->dev), priv);
+ IRQF_SHARED, DRV_NAME, priv);
if (err) {
dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
dev->irq, err);
@@ -1985,7 +1954,7 @@ static int i801_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume);
static struct pci_driver i801_driver = {
- .name = "i801_smbus",
+ .name = DRV_NAME,
.id_table = i801_ids,
.probe = i801_probe,
.remove = i801_remove,
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index dc5ca71906db..d5b5f084a27d 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -170,11 +170,11 @@ enum imx_i2c_type {
struct imx_i2c_hwdata {
enum imx_i2c_type devtype;
- unsigned regshift;
+ unsigned int regshift;
struct imx_i2c_clk_pair *clk_div;
- unsigned ndivs;
- unsigned i2sr_clr_opcode;
- unsigned i2cr_ien_opcode;
+ unsigned int ndivs;
+ unsigned int i2sr_clr_opcode;
+ unsigned int i2cr_ien_opcode;
};
struct imx_i2c_dma {
@@ -452,8 +452,6 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool a
unsigned long orig_jiffies = jiffies;
unsigned int temp;
- dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
-
while (1) {
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
@@ -599,8 +597,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx, bool atomic)
unsigned int temp = 0;
int result;
- dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
-
imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
/* Enable I2C controller */
imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
@@ -635,7 +631,6 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx, bool atomic)
if (!i2c_imx->stopped) {
/* Stop I2C transaction */
- dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
if (!(temp & I2CR_MSTA))
i2c_imx->stopped = 1;
@@ -1167,8 +1162,6 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
bool is_lastmsg = false;
struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
- dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
-
/* Start I2C transfer */
result = i2c_imx_start(i2c_imx, atomic);
if (result) {
@@ -1371,8 +1364,6 @@ static int i2c_imx_probe(struct platform_device *pdev)
dma_addr_t phy_addr;
const struct imx_i2c_hwdata *match;
- dev_dbg(&pdev->dev, "<%s>\n", __func__);
-
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
@@ -1395,7 +1386,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
platform_get_device_id(pdev)->driver_data;
/* Setup i2c_imx driver structure */
- strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
+ strscpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
i2c_imx->adapter.owner = THIS_MODULE;
i2c_imx->adapter.algo = &i2c_imx_algo;
i2c_imx->adapter.dev.parent = &pdev->dev;
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index dcca9c2396db..6d5014ebaab5 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -635,6 +635,8 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
status = readb(i2c->base + MPC_I2C_SR);
if (status & CSR_MIF) {
+ /* Read again to allow register to stabilise */
+ status = readb(i2c->base + MPC_I2C_SR);
writeb(0, i2c->base + MPC_I2C_SR);
mpc_i2c_do_intr(i2c, status);
return IRQ_HANDLED;
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 4e9fb6b44436..4ca716e09149 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -1225,6 +1225,13 @@ static int mtk_i2c_probe(struct platform_device *pdev)
i2c->adap.quirks = i2c->dev_comp->quirks;
i2c->adap.timeout = 2 * HZ;
i2c->adap.retries = 1;
+ i2c->adap.bus_regulator = devm_regulator_get_optional(&pdev->dev, "vbus");
+ if (IS_ERR(i2c->adap.bus_regulator)) {
+ if (PTR_ERR(i2c->adap.bus_regulator) == -ENODEV)
+ i2c->adap.bus_regulator = NULL;
+ else
+ return PTR_ERR(i2c->adap.bus_regulator);
+ }
ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c);
if (ret)
@@ -1286,7 +1293,7 @@ static int mtk_i2c_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, irq, mtk_i2c_irq,
IRQF_NO_SUSPEND | IRQF_TRIGGER_NONE,
- I2C_DRV_NAME, i2c);
+ dev_name(&pdev->dev), i2c);
if (ret < 0) {
dev_err(&pdev->dev,
"Request I2C IRQ %d fail\n", irq);
diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c
index c63d5545fc2a..c1de8eb66169 100644
--- a/drivers/i2c/busses/i2c-qcom-cci.c
+++ b/drivers/i2c/busses/i2c-qcom-cci.c
@@ -769,6 +769,7 @@ static const struct of_device_id cci_dt_match[] = {
{ .compatible = "qcom,msm8916-cci", .data = &cci_v1_data},
{ .compatible = "qcom,msm8996-cci", .data = &cci_v2_data},
{ .compatible = "qcom,sdm845-cci", .data = &cci_v2_data},
+ { .compatible = "qcom,sm8250-cci", .data = &cci_v2_data},
{}
};
MODULE_DEVICE_TABLE(of, cci_dt_match);
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 327c092a4130..bff9913c37b8 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -1013,7 +1013,6 @@ static const struct of_device_id rcar_i2c_dt_ids[] = {
{ .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 },
{ .compatible = "renesas,i2c-r8a7795", .data = (void *)I2C_RCAR_GEN3 },
{ .compatible = "renesas,i2c-r8a7796", .data = (void *)I2C_RCAR_GEN3 },
- { .compatible = "renesas,i2c-rcar", .data = (void *)I2C_RCAR_GEN1 }, /* Deprecated */
{ .compatible = "renesas,rcar-gen1-i2c", .data = (void *)I2C_RCAR_GEN1 },
{ .compatible = "renesas,rcar-gen2-i2c", .data = (void *)I2C_RCAR_GEN2 },
{ .compatible = "renesas,rcar-gen3-i2c", .data = (void *)I2C_RCAR_GEN3 },
diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c
index 4eccc0f69861..78b84445ee6a 100644
--- a/drivers/i2c/busses/i2c-riic.c
+++ b/drivers/i2c/busses/i2c-riic.c
@@ -42,8 +42,10 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#define RIIC_ICCR1 0x00
#define RIIC_ICCR2 0x04
@@ -86,6 +88,11 @@
#define RIIC_INIT_MSG -1
+enum riic_type {
+ RIIC_RZ_A,
+ RIIC_RZ_G2L,
+};
+
struct riic_dev {
void __iomem *base;
u8 *buf;
@@ -395,7 +402,9 @@ static int riic_i2c_probe(struct platform_device *pdev)
struct i2c_adapter *adap;
struct resource *res;
struct i2c_timings i2c_t;
+ struct reset_control *rstc;
int i, ret;
+ enum riic_type type;
riic = devm_kzalloc(&pdev->dev, sizeof(*riic), GFP_KERNEL);
if (!riic)
@@ -412,6 +421,17 @@ static int riic_i2c_probe(struct platform_device *pdev)
return PTR_ERR(riic->clk);
}
+ type = (enum riic_type)of_device_get_match_data(&pdev->dev);
+ if (type == RIIC_RZ_G2L) {
+ rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+ if (IS_ERR(rstc)) {
+ dev_err(&pdev->dev, "Error: missing reset ctrl\n");
+ return PTR_ERR(rstc);
+ }
+
+ reset_control_deassert(rstc);
+ }
+
for (i = 0; i < ARRAY_SIZE(riic_irqs); i++) {
res = platform_get_resource(pdev, IORESOURCE_IRQ, riic_irqs[i].res_num);
if (!res)
@@ -472,7 +492,8 @@ static int riic_i2c_remove(struct platform_device *pdev)
}
static const struct of_device_id riic_i2c_dt_ids[] = {
- { .compatible = "renesas,riic-rz" },
+ { .compatible = "renesas,riic-r9a07g044", .data = (void *)RIIC_RZ_G2L },
+ { .compatible = "renesas,riic-rz", .data = (void *)RIIC_RZ_A },
{ /* Sentinel */ },
};
diff --git a/drivers/i2c/busses/i2c-robotfuzz-osif.c b/drivers/i2c/busses/i2c-robotfuzz-osif.c
index a39f7d092797..66dfa211e736 100644
--- a/drivers/i2c/busses/i2c-robotfuzz-osif.c
+++ b/drivers/i2c/busses/i2c-robotfuzz-osif.c
@@ -83,7 +83,7 @@ static int osif_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
}
}
- ret = osif_usb_read(adapter, OSIFI2C_STOP, 0, 0, NULL, 0);
+ ret = osif_usb_write(adapter, OSIFI2C_STOP, 0, 0, NULL, 0);
if (ret) {
dev_err(&adapter->dev, "failure sending STOP\n");
return -EREMOTEIO;
@@ -153,7 +153,7 @@ static int osif_probe(struct usb_interface *interface,
* Set bus frequency. The frequency is:
* 120,000,000 / ( 16 + 2 * div * 4^prescale).
* Using dev = 52, prescale = 0 give 100KHz */
- ret = osif_usb_read(&priv->adapter, OSIFI2C_SET_BIT_RATE, 52, 0,
+ ret = osif_usb_write(&priv->adapter, OSIFI2C_SET_BIT_RATE, 52, 0,
NULL, 0);
if (ret) {
dev_err(&interface->dev, "failure sending bit rate");
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
index 0138317ea600..b9b19a2a2ffa 100644
--- a/drivers/i2c/busses/i2c-stm32f7.c
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -51,6 +51,7 @@
/* STM32F7 I2C control 1 */
#define STM32F7_I2C_CR1_PECEN BIT(23)
+#define STM32F7_I2C_CR1_ALERTEN BIT(22)
#define STM32F7_I2C_CR1_SMBHEN BIT(20)
#define STM32F7_I2C_CR1_WUPEN BIT(18)
#define STM32F7_I2C_CR1_SBC BIT(16)
@@ -125,6 +126,7 @@
(((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17)
#define STM32F7_I2C_ISR_DIR BIT(16)
#define STM32F7_I2C_ISR_BUSY BIT(15)
+#define STM32F7_I2C_ISR_ALERT BIT(13)
#define STM32F7_I2C_ISR_PECERR BIT(11)
#define STM32F7_I2C_ISR_ARLO BIT(9)
#define STM32F7_I2C_ISR_BERR BIT(8)
@@ -138,6 +140,7 @@
#define STM32F7_I2C_ISR_TXE BIT(0)
/* STM32F7 I2C Interrupt Clear */
+#define STM32F7_I2C_ICR_ALERTCF BIT(13)
#define STM32F7_I2C_ICR_PECCF BIT(11)
#define STM32F7_I2C_ICR_ARLOCF BIT(9)
#define STM32F7_I2C_ICR_BERRCF BIT(8)
@@ -279,6 +282,17 @@ struct stm32f7_i2c_msg {
};
/**
+ * struct stm32f7_i2c_alert - SMBus alert specific data
+ * @setup: platform data for the smbus_alert i2c client
+ * @ara: I2C slave device used to respond to the SMBus Alert with Alert
+ * Response Address
+ */
+struct stm32f7_i2c_alert {
+ struct i2c_smbus_alert_setup setup;
+ struct i2c_client *ara;
+};
+
+/**
* struct stm32f7_i2c_dev - private data of the controller
* @adap: I2C adapter for this controller
* @dev: device for this controller
@@ -310,6 +324,7 @@ struct stm32f7_i2c_msg {
* @analog_filter: boolean to indicate enabling of the analog filter
* @dnf_dt: value of digital filter requested via dt
* @dnf: value of digital filter to apply
+ * @alert: SMBus alert specific data
*/
struct stm32f7_i2c_dev {
struct i2c_adapter adap;
@@ -341,6 +356,7 @@ struct stm32f7_i2c_dev {
bool analog_filter;
u32 dnf_dt;
u32 dnf;
+ struct stm32f7_i2c_alert *alert;
};
/*
@@ -1624,6 +1640,13 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data)
f7_msg->result = -EINVAL;
}
+ if (status & STM32F7_I2C_ISR_ALERT) {
+ dev_dbg(dev, "<%s>: SMBus alert received\n", __func__);
+ writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR);
+ i2c_handle_smbus_alert(i2c_dev->alert->ara);
+ return IRQ_HANDLED;
+ }
+
if (!i2c_dev->slave_running) {
u32 mask;
/* Disable interrupts */
@@ -1990,6 +2013,42 @@ static void stm32f7_i2c_disable_smbus_host(struct stm32f7_i2c_dev *i2c_dev)
}
}
+static int stm32f7_i2c_enable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev)
+{
+ struct stm32f7_i2c_alert *alert;
+ struct i2c_adapter *adap = &i2c_dev->adap;
+ struct device *dev = i2c_dev->dev;
+ void __iomem *base = i2c_dev->base;
+
+ alert = devm_kzalloc(dev, sizeof(*alert), GFP_KERNEL);
+ if (!alert)
+ return -ENOMEM;
+
+ alert->ara = i2c_new_smbus_alert_device(adap, &alert->setup);
+ if (IS_ERR(alert->ara))
+ return PTR_ERR(alert->ara);
+
+ i2c_dev->alert = alert;
+
+ /* Enable SMBus Alert */
+ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_ALERTEN);
+
+ return 0;
+}
+
+static void stm32f7_i2c_disable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev)
+{
+ struct stm32f7_i2c_alert *alert = i2c_dev->alert;
+ void __iomem *base = i2c_dev->base;
+
+ if (alert) {
+ /* Disable SMBus Alert */
+ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1,
+ STM32F7_I2C_CR1_ALERTEN);
+ i2c_unregister_device(alert->ara);
+ }
+}
+
static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
{
struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
@@ -2173,6 +2232,16 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
}
}
+ if (of_property_read_bool(pdev->dev.of_node, "smbus-alert")) {
+ ret = stm32f7_i2c_enable_smbus_alert(i2c_dev);
+ if (ret) {
+ dev_err(i2c_dev->dev,
+ "failed to enable SMBus alert protocol (%d)\n",
+ ret);
+ goto i2c_disable_smbus_host;
+ }
+ }
+
dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr);
pm_runtime_mark_last_busy(i2c_dev->dev);
@@ -2180,6 +2249,9 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
return 0;
+i2c_disable_smbus_host:
+ stm32f7_i2c_disable_smbus_host(i2c_dev);
+
i2c_adapter_remove:
i2c_del_adapter(adap);
@@ -2214,6 +2286,7 @@ static int stm32f7_i2c_remove(struct platform_device *pdev)
{
struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+ stm32f7_i2c_disable_smbus_alert(i2c_dev);
stm32f7_i2c_disable_smbus_host(i2c_dev);
i2c_del_adapter(&i2c_dev->adap);
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index 2a8568b97c14..bb93db98404e 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -798,11 +798,10 @@ static int xiic_i2c_probe(struct platform_device *pdev)
init_waitqueue_head(&i2c->wait);
i2c->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(i2c->clk)) {
- if (PTR_ERR(i2c->clk) != -EPROBE_DEFER)
- dev_err(&pdev->dev, "input clock not found.\n");
- return PTR_ERR(i2c->clk);
- }
+ if (IS_ERR(i2c->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk),
+ "input clock not found.\n");
+
ret = clk_prepare_enable(i2c->clk);
if (ret) {
dev_err(&pdev->dev, "Unable to enable clock.\n");
diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
index 8ceaa88dd78f..6f0aa0ed3241 100644
--- a/drivers/i2c/i2c-core-acpi.c
+++ b/drivers/i2c/i2c-core-acpi.c
@@ -259,8 +259,8 @@ static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level,
*/
void i2c_acpi_register_devices(struct i2c_adapter *adap)
{
+ struct acpi_device *adev;
acpi_status status;
- acpi_handle handle;
if (!has_acpi_companion(&adap->dev))
return;
@@ -275,11 +275,11 @@ void i2c_acpi_register_devices(struct i2c_adapter *adap)
if (!adap->dev.parent)
return;
- handle = ACPI_HANDLE(adap->dev.parent);
- if (!handle)
+ adev = ACPI_COMPANION(adap->dev.parent);
+ if (!adev)
return;
- acpi_walk_dep_device_list(handle);
+ acpi_dev_clear_dependencies(adev);
}
static const struct acpi_device_id i2c_acpi_force_400khz_device_ids[] = {
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 5a97e4a02fa2..84f12bf90644 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -24,6 +24,7 @@
#include <linux/i2c-smbus.h>
#include <linux/idr.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/irqflags.h>
#include <linux/jump_label.h>
#include <linux/kernel.h>
@@ -399,7 +400,8 @@ static int i2c_gpio_init_recovery(struct i2c_adapter *adap)
static int i2c_init_recovery(struct i2c_adapter *adap)
{
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
- char *err_str, *err_level = KERN_ERR;
+ bool is_error_level = true;
+ char *err_str;
if (!bri)
return 0;
@@ -409,7 +411,7 @@ static int i2c_init_recovery(struct i2c_adapter *adap)
if (!bri->recover_bus) {
err_str = "no suitable method provided";
- err_level = KERN_DEBUG;
+ is_error_level = false;
goto err;
}
@@ -436,7 +438,10 @@ static int i2c_init_recovery(struct i2c_adapter *adap)
return 0;
err:
- dev_printk(err_level, &adap->dev, "Not using recovery: %s\n", err_str);
+ if (is_error_level)
+ dev_err(&adap->dev, "Not using recovery: %s\n", err_str);
+ else
+ dev_dbg(&adap->dev, "Not using recovery: %s\n", err_str);
adap->bus_recovery_info = NULL;
return -EINVAL;
@@ -461,12 +466,14 @@ static int i2c_smbus_host_notify_to_irq(const struct i2c_client *client)
static int i2c_device_probe(struct device *dev)
{
struct i2c_client *client = i2c_verify_client(dev);
+ struct i2c_adapter *adap;
struct i2c_driver *driver;
int status;
if (!client)
return 0;
+ adap = client->adapter;
client->irq = client->init_irq;
if (!client->irq) {
@@ -532,6 +539,14 @@ static int i2c_device_probe(struct device *dev)
dev_dbg(dev, "probe\n");
+ if (adap->bus_regulator) {
+ status = regulator_enable(adap->bus_regulator);
+ if (status < 0) {
+ dev_err(&adap->dev, "Failed to enable bus regulator\n");
+ goto err_clear_wakeup_irq;
+ }
+ }
+
status = of_clk_set_defaults(dev->of_node, false);
if (status < 0)
goto err_clear_wakeup_irq;
@@ -589,8 +604,10 @@ put_sync_adapter:
static int i2c_device_remove(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_adapter *adap;
struct i2c_driver *driver;
+ adap = client->adapter;
driver = to_i2c_driver(dev->driver);
if (driver->remove) {
int status;
@@ -605,6 +622,8 @@ static int i2c_device_remove(struct device *dev)
devres_release_group(&client->dev, client->devres_group_id);
dev_pm_domain_detach(&client->dev, true);
+ if (!pm_runtime_status_suspended(&client->dev) && adap->bus_regulator)
+ regulator_disable(adap->bus_regulator);
dev_pm_clear_wake_irq(&client->dev);
device_init_wakeup(&client->dev, false);
@@ -617,6 +636,86 @@ static int i2c_device_remove(struct device *dev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int i2c_resume_early(struct device *dev)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ int err;
+
+ if (!client)
+ return 0;
+
+ if (pm_runtime_status_suspended(&client->dev) &&
+ client->adapter->bus_regulator) {
+ err = regulator_enable(client->adapter->bus_regulator);
+ if (err)
+ return err;
+ }
+
+ return pm_generic_resume_early(&client->dev);
+}
+
+static int i2c_suspend_late(struct device *dev)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ int err;
+
+ if (!client)
+ return 0;
+
+ err = pm_generic_suspend_late(&client->dev);
+ if (err)
+ return err;
+
+ if (!pm_runtime_status_suspended(&client->dev) &&
+ client->adapter->bus_regulator)
+ return regulator_disable(client->adapter->bus_regulator);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int i2c_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ int err;
+
+ if (!client)
+ return 0;
+
+ if (client->adapter->bus_regulator) {
+ err = regulator_enable(client->adapter->bus_regulator);
+ if (err)
+ return err;
+ }
+
+ return pm_generic_runtime_resume(&client->dev);
+}
+
+static int i2c_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ int err;
+
+ if (!client)
+ return 0;
+
+ err = pm_generic_runtime_suspend(&client->dev);
+ if (err)
+ return err;
+
+ if (client->adapter->bus_regulator)
+ return regulator_disable(client->adapter->bus_regulator);
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops i2c_device_pm = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(i2c_suspend_late, i2c_resume_early)
+ SET_RUNTIME_PM_OPS(i2c_runtime_suspend, i2c_runtime_resume, NULL)
+};
+
static void i2c_device_shutdown(struct device *dev)
{
struct i2c_client *client = i2c_verify_client(dev);
@@ -627,6 +726,8 @@ static void i2c_device_shutdown(struct device *dev)
driver = to_i2c_driver(dev->driver);
if (driver->shutdown)
driver->shutdown(client);
+ else if (client->irq > 0)
+ disable_irq(client->irq);
}
static void i2c_client_dev_release(struct device *dev)
@@ -674,6 +775,7 @@ struct bus_type i2c_bus_type = {
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
+ .pm = &i2c_device_pm,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);
diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c
index d2d32c0fd8c3..e5b2d1465e7e 100644
--- a/drivers/i2c/i2c-core-smbus.c
+++ b/drivers/i2c/i2c-core-smbus.c
@@ -37,8 +37,15 @@ static u8 crc8(u16 data)
return (u8)(data >> 8);
}
-/* Incremental CRC8 over count bytes in the array pointed to by p */
-static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
+/**
+ * i2c_smbus_pec - Incremental CRC8 over the given input data array
+ * @crc: previous return crc8 value
+ * @p: pointer to data buffer.
+ * @count: number of bytes in data buffer.
+ *
+ * Incremental CRC8 over count bytes in the array pointed to by p
+ */
+u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
{
int i;
@@ -46,6 +53,7 @@ static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
crc = crc8((crc ^ p[i]) << 8);
return crc;
}
+EXPORT_SYMBOL(i2c_smbus_pec);
/* Assume a 7-bit address, which is reasonable for SMBus */
static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg)
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 6ef38a8ee95c..cb64fe649390 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -526,7 +526,7 @@ static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned lo
return put_user(funcs, (compat_ulong_t __user *)arg);
case I2C_RDWR: {
struct i2c_rdwr_ioctl_data32 rdwr_arg;
- struct i2c_msg32 *p;
+ struct i2c_msg32 __user *p;
struct i2c_msg *rdwr_pa;
int i;
diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c
index 3f2226928fe0..5b37ffe5ad5b 100644
--- a/drivers/i3c/master/i3c-master-cdns.c
+++ b/drivers/i3c/master/i3c-master-cdns.c
@@ -1379,6 +1379,8 @@ static void cnds_i3c_master_demux_ibis(struct cdns_i3c_master *master)
case IBIR_TYPE_MR:
WARN_ON(IBIR_XFER_BYTES(ibir) || (ibir & IBIR_ERROR));
+ break;
+
default:
break;
}
diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 1f6ba4221817..879e5a64acaf 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -195,7 +195,7 @@ struct svc_i3c_master {
};
/**
- * struct svc_i3c_i3c_dev_data - Device specific data
+ * struct svc_i3c_i2c_dev_data - Device specific data
* @index: Index in the master tables corresponding to this device
* @ibi: IBI slot index in the master structure
* @ibi_pool: IBI pool associated to this device
@@ -1448,7 +1448,6 @@ static int svc_i3c_master_remove(struct platform_device *pdev)
if (ret)
return ret;
- free_irq(master->irq, master);
clk_disable_unprepare(master->pclk);
clk_disable_unprepare(master->fclk);
clk_disable_unprepare(master->sclk);
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
deleted file mode 100644
index 19abf11c84c8..000000000000
--- a/drivers/ide/Kconfig
+++ /dev/null
@@ -1,849 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# IDE ATA ATAPI Block device driver configuration
-#
-
-# Select HAVE_IDE if IDE is supported
-config HAVE_IDE
- bool
-
-menuconfig IDE
- tristate "ATA/ATAPI/MFM/RLL support (DEPRECATED)"
- depends on HAVE_IDE
- depends on BLOCK
- select BLK_SCSI_REQUEST
- help
- If you say Y here, your kernel will be able to manage ATA/(E)IDE and
- ATAPI units. The most common cases are IDE hard drives and ATAPI
- CD-ROM drives.
-
- This subsystem is currently in maintenance mode with only bug fix
- changes applied. Users of ATA hardware are encouraged to migrate to
- the newer ATA subsystem ("Serial ATA (prod) and Parallel ATA
- (experimental) drivers") which is more actively maintained.
-
- 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.rst>.
-
- If unsure, say N.
-
-if IDE
-
-comment "Please see Documentation/ide/ide.rst for help/info on IDE drives"
-
-config IDE_XFER_MODE
- bool
-
-config IDE_TIMINGS
- bool
- select IDE_XFER_MODE
-
-config IDE_ATAPI
- bool
-
-config IDE_LEGACY
- bool
-
-config BLK_DEV_IDE_SATA
- bool "Support for SATA (deprecated; conflicts with libata SATA driver)"
- default n
- help
- There are two drivers for Serial ATA controllers.
-
- The main driver, "libata", uses the SCSI subsystem
- and supports most modern SATA controllers. In order to use it
- you may take a look at "Serial ATA (prod) and Parallel ATA
- (experimental) drivers".
-
- The IDE driver (which you are currently configuring) supports
- a few first-generation SATA controllers.
-
- In order to eliminate conflicts between the two subsystems,
- this config option enables the IDE driver's SATA support.
- Normally this is disabled, as it is preferred that libata
- supports SATA controllers, and this (IDE) driver supports
- PATA controllers.
-
- If unsure, say N.
-
-config IDE_GD
- tristate "generic ATA/ATAPI disk support"
- default y
- help
- Support for ATA/ATAPI disks (including ATAPI floppy drives).
-
- To compile this driver as a module, choose M here.
- The module will be called ide-gd_mod.
-
- If unsure, say Y.
-
-config IDE_GD_ATA
- bool "ATA disk support"
- depends on IDE_GD
- default y
- help
- This will include support for ATA hard disks.
-
- If unsure, say Y.
-
-config IDE_GD_ATAPI
- bool "ATAPI floppy support"
- depends on IDE_GD
- select IDE_ATAPI
- help
- This will include support for ATAPI floppy drives
- (i.e. Iomega ZIP or MKE LS-120).
-
- For information about jumper settings and the question
- of when a ZIP drive uses a partition table, see
- <http://www.win.tue.nl/~aeb/linux/zip/zip-1.html>.
-
- If unsure, say N.
-
-config BLK_DEV_IDECS
- tristate "PCMCIA IDE support"
- depends on PCMCIA
- help
- Support for Compact Flash cards, outboard IDE disks, tape drives,
- and CD-ROM drives connected through a PCMCIA card.
-
-config BLK_DEV_DELKIN
- tristate "Cardbus IDE support (Delkin/ASKA/Workbit)"
- depends on CARDBUS && PCI
- help
- Support for Delkin, ASKA, and Workbit Cardbus CompactFlash
- Adapters. This may also work for similar SD and XD adapters.
-
-config BLK_DEV_IDECD
- tristate "Include IDE/ATAPI CDROM support"
- depends on BLK_DEV
- select IDE_ATAPI
- select CDROM
- help
- If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is
- a newer protocol used by IDE CD-ROM and TAPE drives, similar to the
- SCSI protocol. Most new CD-ROM drives use ATAPI, including the
- NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI
- double(2X) or better speed drives.
-
- If you say Y here, the CD-ROM drive will be identified at boot time
- along with other IDE devices, as "hdb" or "hdc", or something
- similar (check the boot messages with dmesg). If this is your only
- CD-ROM drive, you can say N to all other CD-ROM options, but be sure
- to say Y or M to "ISO 9660 CD-ROM file system support".
-
- To compile this driver as a module, choose M here: the
- module will be called ide-cd.
-
-config BLK_DEV_IDECD_VERBOSE_ERRORS
- bool "Verbose error logging for IDE/ATAPI CDROM driver" if EXPERT
- depends on BLK_DEV_IDECD
- default y
- help
- Turn this on to have the driver print out the meanings of the
- ATAPI error codes. This will use up additional 8kB of kernel-space
- memory, though.
-
-config BLK_DEV_IDETAPE
- tristate "Include IDE/ATAPI TAPE support"
- select IDE_ATAPI
- help
- If you have an IDE tape drive using the ATAPI protocol, say Y.
- ATAPI is a newer protocol used by IDE tape and CD-ROM drives,
- similar to the SCSI protocol. If you have an SCSI tape drive
- however, you can say N here.
-
- You should also say Y if you have an OnStream DI-30 tape drive; this
- will not work with the SCSI protocol, until there is support for the
- SC-30 and SC-50 versions.
-
- If you say Y here, the tape drive will be identified at boot time
- 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.rst>
- files for usage information.
-
- To compile this driver as a module, choose M here: the
- module will be called ide-tape.
-
-config BLK_DEV_IDEACPI
- bool "IDE ACPI support"
- depends on ACPI
- help
- Implement ACPI support for generic IDE devices. On modern
- machines ACPI support is required to properly handle ACPI S3 states.
-
-config IDE_TASK_IOCTL
- bool "IDE Taskfile Access"
- help
- This is a direct raw access to the media. It is a complex but
- elegant solution to test and validate the domain of the hardware and
- perform below the driver data recovery if needed. This is the most
- basic form of media-forensics.
-
- If you are unsure, say N here.
-
-config IDE_PROC_FS
- bool "legacy /proc/ide/ support"
- depends on IDE && PROC_FS
- default y
- help
- This option enables support for the various files in
- /proc/ide. In Linux 2.6 this has been superseded by
- files in sysfs but many legacy applications rely on this.
-
- If unsure say Y.
-
-comment "IDE chipset support/bugfixes"
-
-config IDE_GENERIC
- tristate "generic/default IDE chipset support"
- depends on ALPHA || X86 || IA64 || MIPS || ARCH_RPC
- default ARM && ARCH_RPC
- help
- This is the generic IDE driver. This driver attaches to the
- fixed legacy ports (e.g. on PCs 0x1f0/0x170, 0x1e8/0x168 and
- so on). Please note that if this driver is built into the
- kernel or loaded before other ATA (IDE or libata) drivers
- and the controller is located at legacy ports, this driver
- may grab those ports and thus can prevent the controller
- specific driver from attaching.
-
- Also, currently, IDE generic doesn't allow IRQ sharing
- meaning that the IRQs it grabs won't be available to other
- controllers sharing those IRQs which usually makes drivers
- for those controllers fail. Generally, it's not a good idea
- to load IDE generic driver on modern systems.
-
- If unsure, say N.
-
-config BLK_DEV_PLATFORM
- tristate "Platform driver for IDE interfaces"
- help
- This is the platform IDE driver, used mostly for Memory Mapped
- IDE devices, like Compact Flashes running in True IDE mode.
-
- If unsure, say N.
-
-config BLK_DEV_CMD640
- tristate "CMD640 chipset bugfix/support"
- depends on X86
- select IDE_TIMINGS
- help
- The CMD-Technologies CMD640 IDE chip is used on many common 486 and
- Pentium motherboards, usually in combination with a "Neptune" or
- "SiS" chipset. Unfortunately, it has a number of rather nasty
- design flaws that can cause severe data corruption under many common
- conditions. Say Y here to include code which tries to automatically
- detect and correct the problems under Linux. This option also
- enables access to the secondary IDE ports in some CMD640 based
- systems.
-
- This driver will work automatically in PCI based systems (most new
- systems have PCI slots). But if your system uses VESA local bus
- (VLB) instead of PCI, you must also supply a kernel boot parameter
- to enable the CMD640 bugfix/support: "cmd640.probe_vlb". (Try "man
- bootparam" or see the documentation of your boot loader about how to
- pass options to the kernel.)
-
- 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.rst>.
-
-config BLK_DEV_CMD640_ENHANCED
- bool "CMD640 enhanced support"
- depends on BLK_DEV_CMD640
- help
- This option includes support for setting/autotuning PIO modes and
- prefetch on CMD640 IDE interfaces. For details, read
- <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.
-
-config BLK_DEV_IDEPNP
- tristate "PNP EIDE support"
- depends on PNP
- help
- If you have a PnP (Plug and Play) compatible EIDE card and
- would like the kernel to automatically detect and activate
- it, say Y here.
-
-config BLK_DEV_IDEDMA_SFF
- bool
-
-if PCI
-
-comment "PCI IDE chipsets support"
-
-config BLK_DEV_IDEPCI
- bool
-
-config IDEPCI_PCIBUS_ORDER
- bool "Probe IDE PCI devices in the PCI bus order (DEPRECATED)"
- depends on IDE=y && BLK_DEV_IDEPCI
- default y
- help
- Probe IDE PCI devices in the order in which they appear on the
- PCI bus (i.e. 00:1f.1 PCI device before 02:01.0 PCI device)
- instead of the order in which IDE PCI host drivers are loaded.
-
- Please note that this method of assuring stable naming of
- IDE devices is unreliable and use other means for achieving
- it (i.e. udev).
-
- If in doubt, say N.
-
-# TODO: split it on per host driver config options (or module parameters)
-config BLK_DEV_OFFBOARD
- bool "Boot off-board chipsets first support (DEPRECATED)"
- depends on BLK_DEV_IDEPCI && (BLK_DEV_AEC62XX || BLK_DEV_GENERIC || BLK_DEV_HPT366 || BLK_DEV_PDC202XX_NEW || BLK_DEV_PDC202XX_OLD || BLK_DEV_TC86C001)
- help
- Normally, IDE controllers built into the motherboard (on-board
- controllers) are assigned to ide0 and ide1 while those on add-in PCI
- cards (off-board controllers) are relegated to ide2 and ide3.
- Answering Y here will allow you to reverse the situation, with
- off-board controllers on ide0/1 and on-board controllers on ide2/3.
- This can improve the usability of some boot managers such as lilo
- when booting from a drive on an off-board controller.
-
- Note that, if you do this, the order of the hd* devices will be
- rearranged which may require modification of fstab and other files.
-
- Please also note that this method of assuring stable naming of
- IDE devices is unreliable and use other means for achieving it
- (i.e. udev).
-
- If in doubt, say N.
-
-config BLK_DEV_GENERIC
- tristate "Generic PCI IDE Chipset Support"
- select BLK_DEV_IDEPCI
- help
- This option provides generic support for various PCI IDE Chipsets
- which otherwise might not be supported.
-
-config BLK_DEV_OPTI621
- tristate "OPTi 82C621 chipset enhanced support"
- select BLK_DEV_IDEPCI
- help
- This is a driver for the OPTi 82C621 EIDE controller.
- Please read the comments at the top of <file:drivers/ide/opti621.c>.
-
-config BLK_DEV_RZ1000
- tristate "RZ1000 chipset bugfix/support"
- depends on X86
- select BLK_DEV_IDEPCI
- help
- The PC-Technologies RZ1000 IDE chip is used on many common 486 and
- Pentium motherboards, usually along with the "Neptune" chipset.
- Unfortunately, it has a rather nasty design flaw that can cause
- severe data corruption under many conditions. Say Y here to include
- code which automatically detects and corrects the problem under
- Linux. This may slow disk throughput by a few percent, but at least
- things will operate 100% reliably.
-
-config BLK_DEV_IDEDMA_PCI
- bool
- select BLK_DEV_IDEPCI
- select BLK_DEV_IDEDMA_SFF
-
-config BLK_DEV_AEC62XX
- tristate "AEC62XX chipset support"
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds explicit support for Acard AEC62xx (Artop ATP8xx)
- IDE controllers. This allows the kernel to change PIO, DMA and UDMA
- speeds and to configure the chip to optimum performance.
-
-config BLK_DEV_ALI15X3
- tristate "ALI M15x3 chipset support"
- select IDE_TIMINGS
- select BLK_DEV_IDEDMA_PCI
- help
- This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C
- onboard chipsets. It also tests for Simplex mode and enables
- normal dual channel support.
-
- Please read the comments at the top of
- <file:drivers/ide/alim15x3.c>.
-
- If unsure, say N.
-
-config BLK_DEV_AMD74XX
- tristate "AMD and nVidia IDE support"
- depends on !ARM
- select IDE_TIMINGS
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds explicit support for AMD-7xx and AMD-8111 chips
- and also for the nVidia nForce chip. This allows the kernel to
- change PIO, DMA and UDMA speeds and to configure the chip to
- optimum performance.
-
-config BLK_DEV_ATIIXP
- tristate "ATI IXP chipset IDE support"
- depends on X86
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds explicit support for ATI IXP chipset.
- This allows the kernel to change PIO, DMA and UDMA speeds
- and to configure the chip to optimum performance.
-
- Say Y here if you have an ATI IXP chipset IDE controller.
-
-config BLK_DEV_CMD64X
- tristate "CMD64{3|6|8|9} chipset support"
- select IDE_TIMINGS
- select BLK_DEV_IDEDMA_PCI
- help
- Say Y here if you have an IDE controller which uses any of these
- chipsets: CMD643, CMD646, or CMD648.
-
-config BLK_DEV_TRIFLEX
- tristate "Compaq Triflex IDE support"
- select BLK_DEV_IDEDMA_PCI
- help
- Say Y here if you have a Compaq Triflex IDE controller, such
- as those commonly found on Compaq Pentium-Pro systems
-
-config BLK_DEV_CY82C693
- tristate "CY82C693 chipset support"
- depends on ALPHA
- select IDE_TIMINGS
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds detection and support for the CY82C693 chipset
- used on Digital's PC-Alpha 164SX boards.
-
-config BLK_DEV_CS5520
- tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)"
- depends on X86_32 || COMPILE_TEST
- select BLK_DEV_IDEDMA_PCI
- help
- Include support for PIO tuning and virtual DMA on the Cyrix MediaGX
- 5510/5520 chipset. This will automatically be detected and
- configured if found.
-
- It is safe to say Y to this question.
-
-config BLK_DEV_CS5530
- tristate "Cyrix/National Semiconductor CS5530 MediaGX chipset support"
- depends on X86_32 || COMPILE_TEST
- select BLK_DEV_IDEDMA_PCI
- help
- Include support for UDMA on the Cyrix MediaGX 5530 chipset. This
- will automatically be detected and configured if found.
-
- It is safe to say Y to this question.
-
-config BLK_DEV_CS5535
- tristate "AMD CS5535 chipset support"
- depends on X86_32
- select BLK_DEV_IDEDMA_PCI
- help
- Include support for UDMA on the NSC/AMD CS5535 companion chipset.
- This will automatically be detected and configured if found.
-
- It is safe to say Y to this question.
-
-config BLK_DEV_CS5536
- tristate "CS5536 chipset support"
- depends on X86_32
- select BLK_DEV_IDEDMA_PCI
- help
- This option enables support for the AMD CS5536
- companion chip used with the Geode LX processor family.
-
- If unsure, say N.
-
-config BLK_DEV_HPT366
- tristate "HPT36X/37X chipset support"
- select BLK_DEV_IDEDMA_PCI
- help
- HPT366 is an Ultra DMA chipset for ATA-66.
- HPT368 is an Ultra DMA chipset for ATA-66 RAID Based.
- HPT370 is an Ultra DMA chipset for ATA-100.
- HPT372 is an Ultra DMA chipset for ATA-100.
- HPT374 is an Ultra DMA chipset for ATA-100.
-
- This driver adds up to 4 more EIDE devices sharing a single
- interrupt.
-
- The HPT366 chipset in its current form is bootable. One solution
- for this problem are special LILO commands for redirecting the
- reference to device 0x80. The other solution is to say Y to "Boot
- off-board chipsets first support" (CONFIG_BLK_DEV_OFFBOARD) unless
- your mother board has the chipset natively mounted. Regardless one
- should use the fore mentioned option and call at LILO.
-
- This driver requires dynamic tuning of the chipset during the
- ide-probe at boot. It is reported to support DVD II drives, by the
- manufacturer.
-
-config BLK_DEV_JMICRON
- tristate "JMicron JMB36x support"
- select BLK_DEV_IDEDMA_PCI
- help
- Basic support for the JMicron ATA controllers. For full support
- use the libata drivers.
-
-config BLK_DEV_SC1200
- tristate "National SCx200 chipset support"
- depends on X86_32 || COMPILE_TEST
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds support for the on-board IDE controller on the
- National SCx200 series of embedded x86 "Geode" systems.
-
-config BLK_DEV_PIIX
- tristate "Intel PIIX/ICH chipsets support"
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds explicit support for Intel PIIX and ICH chips.
- This allows the kernel to change PIO, DMA and UDMA speeds and to
- configure the chip to optimum performance.
-
-config BLK_DEV_IT8172
- tristate "IT8172 IDE support"
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds support for the IDE controller on the
- IT8172 System Controller.
-
-config BLK_DEV_IT8213
- tristate "IT8213 IDE support"
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds support for the ITE 8213 IDE controller.
-
-config BLK_DEV_IT821X
- tristate "IT821X IDE support"
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds support for the ITE 8211 IDE controller and the
- IT 8212 IDE RAID controller in both RAID and pass-through mode.
-
-config BLK_DEV_NS87415
- tristate "NS87415 chipset support"
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds detection and support for the NS87415 chip
- (used mainly on SPARC64 and PA-RISC machines).
-
- Please read the comments at the top of <file:drivers/ide/ns87415.c>.
-
-config BLK_DEV_PDC202XX_OLD
- tristate "PROMISE PDC202{46|62|65|67} support"
- select BLK_DEV_IDEDMA_PCI
- help
- Promise Ultra33 or PDC20246
- Promise Ultra66 or PDC20262
- Promise Ultra100 or PDC20265/PDC20267/PDC20268
-
- This driver adds up to 4 more EIDE devices sharing a single
- interrupt. This add-on card is a bootable PCI UDMA controller. Since
- multiple cards can be installed and there are BIOS ROM problems that
- happen if the BIOS revisions of all installed cards (three-max) do
- not match, the driver attempts to do dynamic tuning of the chipset
- at boot-time for max-speed. Ultra33 BIOS 1.25 or newer is required
- for more than one card.
-
- Please read the comments at the top of
- <file:drivers/ide/pdc202xx_old.c>.
-
- If unsure, say N.
-
-config BLK_DEV_PDC202XX_NEW
- tristate "PROMISE PDC202{68|69|70|71|75|76|77} support"
- select BLK_DEV_IDEDMA_PCI
-
-config BLK_DEV_SVWKS
- tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support"
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5
- chipsets.
-
-config BLK_DEV_SIIMAGE
- tristate "Silicon Image chipset support"
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds PIO/(U)DMA support for the SI CMD680 and SII
- 3112 (Serial ATA) chips.
-
-config BLK_DEV_SIS5513
- tristate "SiS5513 chipset support"
- depends on X86
- select BLK_DEV_IDEDMA_PCI
- help
- This driver ensures (U)DMA support for SIS5513 chipset family based
- mainboards.
-
- The following chipsets are supported:
- ATA16: SiS5511, SiS5513
- ATA33: SiS5591, SiS5597, SiS5598, SiS5600
- ATA66: SiS530, SiS540, SiS620, SiS630, SiS640
- ATA100: SiS635, SiS645, SiS650, SiS730, SiS735, SiS740,
- SiS745, SiS750
-
- Please read the comments at the top of <file:drivers/ide/sis5513.c>.
-
-config BLK_DEV_SL82C105
- tristate "Winbond SL82c105 support"
- depends on (PPC || ARM)
- select IDE_TIMINGS
- select BLK_DEV_IDEDMA_PCI
- help
- If you have a Winbond SL82c105 IDE controller, say Y here to enable
- special configuration for this chip. This is common on various CHRP
- motherboards, but could be used elsewhere. If in doubt, say Y.
-
-config BLK_DEV_SLC90E66
- tristate "SLC90E66 chipset support"
- select BLK_DEV_IDEDMA_PCI
- help
- This driver ensures (U)DMA support for Victory66 SouthBridges for
- SMsC with Intel NorthBridges. This is an Ultra66 based chipset.
- The nice thing about it is that you can mix Ultra/DMA/PIO devices
- and it will handle timing cycles. Since this is an improved
- look-a-like to the PIIX4 it should be a nice addition.
-
- Please read the comments at the top of
- <file:drivers/ide/slc90e66.c>.
-
-config BLK_DEV_TRM290
- tristate "Tekram TRM290 chipset support"
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds support for bus master DMA transfers
- using the Tekram TRM290 PCI IDE chip. Volunteers are
- needed for further tweaking and development.
- Please read the comments at the top of <file:drivers/ide/trm290.c>.
-
-config BLK_DEV_VIA82CXXX
- tristate "VIA82CXXX chipset support"
- select IDE_TIMINGS
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds explicit support for VIA BusMastering IDE chips.
- This allows the kernel to change PIO, DMA and UDMA speeds and to
- configure the chip to optimum performance.
-
-config BLK_DEV_TC86C001
- tristate "Toshiba TC86C001 support"
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds support for Toshiba TC86C001 GOKU-S chip.
-
-endif
-
-# TODO: BLK_DEV_IDEDMA_PCI -> BLK_DEV_IDEDMA_SFF
-config BLK_DEV_IDE_PMAC
- tristate "PowerMac on-board IDE support"
- depends on PPC_PMAC
- select IDE_TIMINGS
- select BLK_DEV_IDEDMA_PCI
- help
- This driver provides support for the on-board IDE controller on
- most of the recent Apple Power Macintoshes and PowerBooks.
- If unsure, say Y.
-
-config BLK_DEV_IDE_PMAC_ATA100FIRST
- bool "Probe on-board ATA/100 (Kauai) first"
- depends on BLK_DEV_IDE_PMAC
- help
- This option will cause the ATA/100 controller found in UniNorth2
- based machines (Windtunnel PowerMac, Aluminium PowerBooks, ...)
- to be probed before the ATA/66 and ATA/33 controllers. Without
- these, those machine used to have the hard disk on hdc and the
- CD-ROM on hda. This option changes this to more natural hda for
- hard disk and hdc for CD-ROM.
-
-config BLK_DEV_IDE_TX4938
- tristate "TX4938 internal IDE support"
- depends on SOC_TX4938
- select IDE_TIMINGS
-
-config BLK_DEV_IDE_TX4939
- tristate "TX4939 internal IDE support"
- depends on SOC_TX4939
- select BLK_DEV_IDEDMA_SFF
-
-config BLK_DEV_IDE_ICSIDE
- tristate "ICS IDE interface support"
- depends on ARM && ARCH_ACORN
- help
- On Acorn systems, say Y here if you wish to use the ICS IDE
- interface card. This is not required for ICS partition support.
- If you are unsure, say N to this.
-
-config BLK_DEV_IDEDMA_ICS
- bool "ICS DMA support"
- depends on BLK_DEV_IDE_ICSIDE
- help
- Say Y here if you want to add DMA (Direct Memory Access) support to
- the ICS IDE driver.
-
-config BLK_DEV_IDE_RAPIDE
- tristate "RapIDE interface support"
- depends on ARM && ARCH_ACORN
- help
- Say Y here if you want to support the Yellowstone RapIDE controller
- manufactured for use with Acorn computers.
-
-config BLK_DEV_GAYLE
- tristate "Amiga Gayle IDE interface support"
- depends on AMIGA
- help
- This is the IDE driver for the Amiga Gayle IDE interface. It supports
- both the `A1200 style' and `A4000 style' of the Gayle IDE interface,
- This includes on-board IDE interfaces on some Amiga models (A600,
- A1200, A4000, and A4000T), and IDE interfaces on the Zorro expansion
- bus (M-Tech E-Matrix 530 expansion card).
-
- It also provides support for the so-called `IDE doublers' (made
- by various manufacturers, e.g. Eyetech) that can be connected to
- the on-board IDE interface of some Amiga models. Using such an IDE
- doubler, you can connect up to four instead of two IDE devices to
- the Amiga's on-board IDE interface. The feature is enabled at kernel
- runtime using the "gayle.doubler" kernel boot parameter.
-
- Say Y if you have an Amiga with a Gayle IDE interface and want to use
- IDE devices (hard disks, CD-ROM drives, etc.) that are connected to
- it.
-
- Note that you also have to enable Zorro bus support if you want to
- use Gayle IDE interfaces on the Zorro expansion bus.
-
-config BLK_DEV_BUDDHA
- tristate "Buddha/Catweasel/X-Surf IDE interface support"
- depends on ZORRO
- help
- This is the IDE driver for the IDE interfaces on the Buddha, Catweasel
- and X-Surf expansion boards. It supports up to two interfaces on the
- Buddha, three on the Catweasel and two on the X-Surf.
-
- Say Y if you have a Buddha or Catweasel expansion board and want to
- use IDE devices (hard disks, CD-ROM drives, etc.) that are connected
- to one of its IDE interfaces.
-
-config BLK_DEV_FALCON_IDE
- tristate "Falcon IDE interface support"
- depends on ATARI
- help
- This is the IDE driver for the on-board IDE interface on the Atari
- Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
- disks, CD-ROM drives, etc.) that are connected to the on-board IDE
- interface.
-
-config BLK_DEV_MAC_IDE
- tristate "Macintosh Quadra/Powerbook IDE interface support"
- depends on MAC
- help
- This is the IDE driver for the on-board IDE interface on some m68k
- Macintosh models, namely Quadra/Centris 630, Performa 588 and
- Powerbook 150. The IDE interface on the Powerbook 190 is not
- supported by this driver and requires BLK_DEV_PLATFORM or
- PATA_PLATFORM.
-
- Say Y if you have such an Macintosh model and want to use IDE
- devices (hard disks, CD-ROM drives, etc.) that are connected to the
- on-board IDE interface.
-
-config BLK_DEV_Q40IDE
- tristate "Q40/Q60 IDE interface support"
- depends on Q40
- help
- Enable the on-board IDE controller in the Q40/Q60. This should
- normally be on; disable it only if you are running a custom hard
- drive subsystem through an expansion card.
-
-config BLK_DEV_PALMCHIP_BK3710
- tristate "Palmchip bk3710 IDE controller support"
- depends on ARCH_DAVINCI
- select IDE_TIMINGS
- select BLK_DEV_IDEDMA_SFF
- help
- Say Y here if you want to support the onchip IDE controller on the
- TI DaVinci SoC
-
-# no isa -> no vlb
-if ISA && (ALPHA || X86 || MIPS)
-
-comment "Other IDE chipsets support"
-comment "Note: most of these also require special kernel boot parameters"
-
-config BLK_DEV_4DRIVES
- tristate "Generic 4 drives/port support"
- help
- Certain older chipsets, including the Tekram 690CD, use a single set
- of I/O ports at 0x1f0 to control up to four drives, instead of the
- customary two drives per port. Support for this can be enabled at
- runtime using the "ide-4drives.probe" kernel boot parameter if you
- say Y here.
-
-config BLK_DEV_ALI14XX
- tristate "ALI M14xx support"
- select IDE_TIMINGS
- select IDE_LEGACY
- help
- This driver is enabled at runtime using the "ali14xx.probe" kernel
- 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.rst> and
- <file:drivers/ide/ali14xx.c> for more info.
-
-config BLK_DEV_DTC2278
- tristate "DTC-2278 support"
- select IDE_XFER_MODE
- select IDE_LEGACY
- help
- 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.rst> and
- <file:drivers/ide/dtc2278.c> files for more info.
-
-config BLK_DEV_HT6560B
- tristate "Holtek HT6560B support"
- select IDE_TIMINGS
- select IDE_LEGACY
- help
- 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.rst> and
- <file:drivers/ide/ht6560b.c> files for more info.
-
-config BLK_DEV_QD65XX
- tristate "QDI QD65xx support"
- select IDE_TIMINGS
- select IDE_LEGACY
- 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.rst> and <file:drivers/ide/qd65xx.c>
- for more info.
-
-config BLK_DEV_UMC8672
- tristate "UMC-8672 support"
- select IDE_XFER_MODE
- select IDE_LEGACY
- help
- 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.rst> and
- <file:drivers/ide/umc8672.c> for more info.
-
-endif
-
-config BLK_DEV_IDEDMA
- def_bool BLK_DEV_IDEDMA_SFF || BLK_DEV_IDEDMA_ICS
- select IDE_XFER_MODE
-
-endif # IDE
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
deleted file mode 100644
index 2605b3cdaf47..000000000000
--- a/drivers/ide/Makefile
+++ /dev/null
@@ -1,111 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# link order is important here
-#
-
-ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \
- ide-taskfile.o ide-pm.o ide-park.o ide-sysfs.o ide-devsets.o \
- ide-io-std.o ide-eh.o
-
-# core IDE code
-ide-core-$(CONFIG_IDE_XFER_MODE) += ide-pio-blacklist.o ide-xfer-mode.o
-ide-core-$(CONFIG_IDE_TIMINGS) += ide-timings.o
-ide-core-$(CONFIG_IDE_ATAPI) += ide-atapi.o
-ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o
-ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o
-ide-core-$(CONFIG_BLK_DEV_IDEDMA_SFF) += ide-dma-sff.o
-ide-core-$(CONFIG_IDE_PROC_FS) += ide-proc.o
-ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o
-ide-core-$(CONFIG_IDE_LEGACY) += ide-legacy.o
-
-obj-$(CONFIG_IDE) += ide-core.o
-
-obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o
-obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o
-obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o
-obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o
-obj-$(CONFIG_BLK_DEV_QD65XX) += qd65xx.o
-obj-$(CONFIG_BLK_DEV_4DRIVES) += ide-4drives.o
-
-obj-$(CONFIG_BLK_DEV_GAYLE) += gayle.o
-obj-$(CONFIG_BLK_DEV_FALCON_IDE) += falconide.o
-obj-$(CONFIG_BLK_DEV_MAC_IDE) += macide.o
-obj-$(CONFIG_BLK_DEV_Q40IDE) += q40ide.o
-obj-$(CONFIG_BLK_DEV_BUDDHA) += buddha.o
-
-obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o
-obj-$(CONFIG_BLK_DEV_ALI15X3) += alim15x3.o
-obj-$(CONFIG_BLK_DEV_AMD74XX) += amd74xx.o
-obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.o
-obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o
-obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o
-obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o
-obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o
-obj-$(CONFIG_BLK_DEV_CS5536) += cs5536.o
-obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o
-obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o
-obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o
-obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o
-obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o
-obj-$(CONFIG_BLK_DEV_IT8213) += it8213.o
-obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o
-obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o
-obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o
-obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o
-obj-$(CONFIG_BLK_DEV_PDC202XX_OLD) += pdc202xx_old.o
-obj-$(CONFIG_BLK_DEV_PDC202XX_NEW) += pdc202xx_new.o
-obj-$(CONFIG_BLK_DEV_PIIX) += piix.o
-obj-$(CONFIG_BLK_DEV_RZ1000) += rz1000.o
-obj-$(CONFIG_BLK_DEV_SVWKS) += serverworks.o
-obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o
-obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o
-obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o
-obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o
-obj-$(CONFIG_BLK_DEV_TC86C001) += tc86c001.o
-obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o
-obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o
-obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o
-
-# Must appear at the end of the block
-obj-$(CONFIG_BLK_DEV_GENERIC) += ide-pci-generic.o
-
-obj-$(CONFIG_IDEPCI_PCIBUS_ORDER) += ide-scan-pci.o
-
-obj-$(CONFIG_BLK_DEV_CMD640) += cmd640.o
-
-obj-$(CONFIG_BLK_DEV_IDE_PMAC) += pmac.o
-
-obj-$(CONFIG_IDE_GENERIC) += ide-generic.o
-obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
-
-ide-gd_mod-y += ide-gd.o
-ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o
-
-ifeq ($(CONFIG_IDE_GD_ATA), y)
- ide-gd_mod-y += ide-disk.o ide-disk_ioctl.o
-ifeq ($(CONFIG_IDE_PROC_FS), y)
- ide-gd_mod-y += ide-disk_proc.o
-endif
-endif
-
-ifeq ($(CONFIG_IDE_GD_ATAPI), y)
- ide-gd_mod-y += ide-floppy.o ide-floppy_ioctl.o
-ifeq ($(CONFIG_IDE_PROC_FS), y)
- ide-gd_mod-y += ide-floppy_proc.o
-endif
-endif
-
-obj-$(CONFIG_IDE_GD) += ide-gd_mod.o
-obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd_mod.o
-obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o
-
-obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o
-
-obj-$(CONFIG_BLK_DEV_PLATFORM) += ide_platform.o
-
-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o
-obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o
-obj-$(CONFIG_BLK_DEV_PALMCHIP_BK3710) += palm_bk3710.o
-
-obj-$(CONFIG_BLK_DEV_IDE_TX4938) += tx4938ide.o
-obj-$(CONFIG_BLK_DEV_IDE_TX4939) += tx4939ide.o
diff --git a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c
deleted file mode 100644
index 4c959ce41ba9..000000000000
--- a/drivers/ide/aec62xx.c
+++ /dev/null
@@ -1,331 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "aec62xx"
-
-struct chipset_bus_clock_list_entry {
- u8 xfer_speed;
- u8 chipset_settings;
- u8 ultra_settings;
-};
-
-static const struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
- { XFER_UDMA_6, 0x31, 0x07 },
- { XFER_UDMA_5, 0x31, 0x06 },
- { XFER_UDMA_4, 0x31, 0x05 },
- { XFER_UDMA_3, 0x31, 0x04 },
- { XFER_UDMA_2, 0x31, 0x03 },
- { XFER_UDMA_1, 0x31, 0x02 },
- { XFER_UDMA_0, 0x31, 0x01 },
-
- { XFER_MW_DMA_2, 0x31, 0x00 },
- { XFER_MW_DMA_1, 0x31, 0x00 },
- { XFER_MW_DMA_0, 0x0a, 0x00 },
- { XFER_PIO_4, 0x31, 0x00 },
- { XFER_PIO_3, 0x33, 0x00 },
- { XFER_PIO_2, 0x08, 0x00 },
- { XFER_PIO_1, 0x0a, 0x00 },
- { XFER_PIO_0, 0x00, 0x00 },
- { 0, 0x00, 0x00 }
-};
-
-static const struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
- { XFER_UDMA_6, 0x41, 0x06 },
- { XFER_UDMA_5, 0x41, 0x05 },
- { XFER_UDMA_4, 0x41, 0x04 },
- { XFER_UDMA_3, 0x41, 0x03 },
- { XFER_UDMA_2, 0x41, 0x02 },
- { XFER_UDMA_1, 0x41, 0x01 },
- { XFER_UDMA_0, 0x41, 0x01 },
-
- { XFER_MW_DMA_2, 0x41, 0x00 },
- { XFER_MW_DMA_1, 0x42, 0x00 },
- { XFER_MW_DMA_0, 0x7a, 0x00 },
- { XFER_PIO_4, 0x41, 0x00 },
- { XFER_PIO_3, 0x43, 0x00 },
- { XFER_PIO_2, 0x78, 0x00 },
- { XFER_PIO_1, 0x7a, 0x00 },
- { XFER_PIO_0, 0x70, 0x00 },
- { 0, 0x00, 0x00 }
-};
-
-/*
- * TO DO: active tuning and correction of cards without a bios.
- */
-static u8 pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
- for ( ; chipset_table->xfer_speed ; chipset_table++)
- if (chipset_table->xfer_speed == speed) {
- return chipset_table->chipset_settings;
- }
- return chipset_table->chipset_settings;
-}
-
-static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
- for ( ; chipset_table->xfer_speed ; chipset_table++)
- if (chipset_table->xfer_speed == speed) {
- return chipset_table->ultra_settings;
- }
- return chipset_table->ultra_settings;
-}
-
-static void aec6210_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct ide_host *host = pci_get_drvdata(dev);
- struct chipset_bus_clock_list_entry *bus_clock = host->host_priv;
- u16 d_conf = 0;
- u8 ultra = 0, ultra_conf = 0;
- u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
- const u8 speed = drive->dma_mode;
- unsigned long flags;
-
- local_irq_save(flags);
- /* 0x40|(2*drive->dn): Active, 0x41|(2*drive->dn): Recovery */
- pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
- tmp0 = pci_bus_clock_list(speed, bus_clock);
- d_conf = ((tmp0 & 0xf0) << 4) | (tmp0 & 0xf);
- pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
-
- tmp1 = 0x00;
- tmp2 = 0x00;
- pci_read_config_byte(dev, 0x54, &ultra);
- tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
- ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock);
- tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
- pci_write_config_byte(dev, 0x54, tmp2);
- local_irq_restore(flags);
-}
-
-static void aec6260_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct ide_host *host = pci_get_drvdata(dev);
- struct chipset_bus_clock_list_entry *bus_clock = host->host_priv;
- u8 unit = drive->dn & 1;
- u8 tmp1 = 0, tmp2 = 0;
- u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
- const u8 speed = drive->dma_mode;
- unsigned long flags;
-
- local_irq_save(flags);
- /* high 4-bits: Active, low 4-bits: Recovery */
- pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
- drive_conf = pci_bus_clock_list(speed, bus_clock);
- pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
-
- pci_read_config_byte(dev, (0x44|hwif->channel), &ultra);
- tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
- ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock);
- tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
- pci_write_config_byte(dev, (0x44|hwif->channel), tmp2);
- local_irq_restore(flags);
-}
-
-static void aec_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- drive->dma_mode = drive->pio_mode;
- hwif->port_ops->set_dma_mode(hwif, drive);
-}
-
-static int init_chipset_aec62xx(struct pci_dev *dev)
-{
- /* These are necessary to get AEC6280 Macintosh cards to work */
- if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
- (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) {
- u8 reg49h = 0, reg4ah = 0;
- /* Clear reset and test bits. */
- pci_read_config_byte(dev, 0x49, &reg49h);
- pci_write_config_byte(dev, 0x49, reg49h & ~0x30);
- /* Enable chip interrupt output. */
- pci_read_config_byte(dev, 0x4a, &reg4ah);
- pci_write_config_byte(dev, 0x4a, reg4ah & ~0x01);
- /* Enable burst mode. */
- pci_read_config_byte(dev, 0x4a, &reg4ah);
- pci_write_config_byte(dev, 0x4a, reg4ah | 0x80);
- }
-
- return 0;
-}
-
-static u8 atp86x_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01;
-
- pci_read_config_byte(dev, 0x49, &ata66);
-
- return (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-}
-
-static const struct ide_port_ops atp850_port_ops = {
- .set_pio_mode = aec_set_pio_mode,
- .set_dma_mode = aec6210_set_mode,
-};
-
-static const struct ide_port_ops atp86x_port_ops = {
- .set_pio_mode = aec_set_pio_mode,
- .set_dma_mode = aec6260_set_mode,
- .cable_detect = atp86x_cable_detect,
-};
-
-static const struct ide_port_info aec62xx_chipsets[] = {
- { /* 0: AEC6210 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_aec62xx,
- .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
- .port_ops = &atp850_port_ops,
- .host_flags = IDE_HFLAG_SERIALIZE |
- IDE_HFLAG_NO_ATAPI_DMA |
- IDE_HFLAG_NO_DSC |
- IDE_HFLAG_OFF_BOARD,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA2,
- },
- { /* 1: AEC6260 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_aec62xx,
- .port_ops = &atp86x_port_ops,
- .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA |
- IDE_HFLAG_OFF_BOARD,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA4,
- },
- { /* 2: AEC6260R */
- .name = DRV_NAME,
- .init_chipset = init_chipset_aec62xx,
- .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
- .port_ops = &atp86x_port_ops,
- .host_flags = IDE_HFLAG_NO_ATAPI_DMA |
- IDE_HFLAG_NON_BOOTABLE,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA4,
- },
- { /* 3: AEC6280 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_aec62xx,
- .port_ops = &atp86x_port_ops,
- .host_flags = IDE_HFLAG_NO_ATAPI_DMA |
- IDE_HFLAG_OFF_BOARD,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA5,
- },
- { /* 4: AEC6280R */
- .name = DRV_NAME,
- .init_chipset = init_chipset_aec62xx,
- .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
- .port_ops = &atp86x_port_ops,
- .host_flags = IDE_HFLAG_NO_ATAPI_DMA |
- IDE_HFLAG_OFF_BOARD,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA5,
- }
-};
-
-/**
- * aec62xx_init_one - called when a AEC is found
- * @dev: the aec62xx device
- * @id: the matching pci id
- *
- * Called when the PCI registration layer (or the IDE initialization)
- * finds a device matching our IDE device tables.
- *
- * NOTE: since we're going to modify the 'name' field for AEC-6[26]80[R]
- * chips, pass a local copy of 'struct ide_port_info' down the call chain.
- */
-
-static int aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- const struct chipset_bus_clock_list_entry *bus_clock;
- struct ide_port_info d;
- u8 idx = id->driver_data;
- int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
- int err;
-
- if (bus_speed <= 33)
- bus_clock = aec6xxx_33_base;
- else
- bus_clock = aec6xxx_34_base;
-
- err = pci_enable_device(dev);
- if (err)
- return err;
-
- d = aec62xx_chipsets[idx];
-
- if (idx == 3 || idx == 4) {
- unsigned long dma_base = pci_resource_start(dev, 4);
-
- if (inb(dma_base + 2) & 0x10) {
- printk(KERN_INFO DRV_NAME " %s: AEC6880%s card detected"
- "\n", pci_name(dev), (idx == 4) ? "R" : "");
- d.udma_mask = ATA_UDMA6;
- }
- }
-
- err = ide_pci_init_one(dev, &d, (void *)bus_clock);
- if (err)
- pci_disable_device(dev);
-
- return err;
-}
-
-static void aec62xx_remove(struct pci_dev *dev)
-{
- ide_pci_remove(dev);
- pci_disable_device(dev);
-}
-
-static const struct pci_device_id aec62xx_pci_tbl[] = {
- { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF), 0 },
- { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860), 1 },
- { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R), 2 },
- { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865), 3 },
- { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R), 4 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl);
-
-static struct pci_driver aec62xx_pci_driver = {
- .name = "AEC62xx_IDE",
- .id_table = aec62xx_pci_tbl,
- .probe = aec62xx_init_one,
- .remove = aec62xx_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init aec62xx_ide_init(void)
-{
- return ide_pci_register_driver(&aec62xx_pci_driver);
-}
-
-static void __exit aec62xx_ide_exit(void)
-{
- pci_unregister_driver(&aec62xx_pci_driver);
-}
-
-module_init(aec62xx_ide_init);
-module_exit(aec62xx_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c
deleted file mode 100644
index 3268931c2c7a..000000000000
--- a/drivers/ide/ali14xx.c
+++ /dev/null
@@ -1,250 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1996 Linus Torvalds & author (see below)
- */
-
-/*
- * ALI M14xx chipset EIDE controller
- *
- * Works for ALI M1439/1443/1445/1487/1489 chipsets.
- *
- * Adapted from code developed by derekn@vw.ece.cmu.edu. -ml
- * Derek's notes follow:
- *
- * I think the code should be pretty understandable,
- * but I'll be happy to (try to) answer questions.
- *
- * The critical part is in the setupDrive function. The initRegisters
- * function doesn't seem to be necessary, but the DOS driver does it, so
- * I threw it in.
- *
- * I've only tested this on my system, which only has one disk. I posted
- * it to comp.sys.linux.hardware, so maybe some other people will try it
- * out.
- *
- * Derek Noonburg (derekn@ece.cmu.edu)
- * 95-sep-26
- *
- * Update 96-jul-13:
- *
- * I've since upgraded to two disks and a CD-ROM, with no trouble, and
- * I've also heard from several others who have used it successfully.
- * This driver appears to work with both the 1443/1445 and the 1487/1489
- * chipsets. I've added support for PIO mode 4 for the 1487. This
- * seems to work just fine on the 1443 also, although I'm not sure it's
- * advertised as supporting mode 4. (I've been running a WDC AC21200 in
- * mode 4 for a while now with no trouble.) -Derek
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "ali14xx"
-
-/* port addresses for auto-detection */
-#define ALI_NUM_PORTS 4
-static const int ports[ALI_NUM_PORTS] __initconst =
- { 0x074, 0x0f4, 0x034, 0x0e4 };
-
-/* register initialization data */
-typedef struct { u8 reg, data; } RegInitializer;
-
-static const RegInitializer initData[] __initconst = {
- {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
- {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
- {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
- {0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
- {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
- {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
- {0x35, 0x03}, {0x00, 0x00}
-};
-
-/* timing parameter registers for each drive */
-static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = {
- {0x03, 0x26, 0x04, 0x27}, /* drive 0 */
- {0x05, 0x28, 0x06, 0x29}, /* drive 1 */
- {0x2b, 0x30, 0x2c, 0x31}, /* drive 2 */
- {0x2d, 0x32, 0x2e, 0x33}, /* drive 3 */
-};
-
-static int basePort; /* base port address */
-static int regPort; /* port for register number */
-static int dataPort; /* port for register data */
-static u8 regOn; /* output to base port to access registers */
-static u8 regOff; /* output to base port to close registers */
-
-/*------------------------------------------------------------------------*/
-
-/*
- * Read a controller register.
- */
-static inline u8 inReg(u8 reg)
-{
- outb_p(reg, regPort);
- return inb(dataPort);
-}
-
-/*
- * Write a controller register.
- */
-static void outReg(u8 data, u8 reg)
-{
- outb_p(reg, regPort);
- outb_p(data, dataPort);
-}
-
-static DEFINE_SPINLOCK(ali14xx_lock);
-
-/*
- * Set PIO mode for the specified drive.
- * This function computes timing parameters
- * and sets controller registers accordingly.
- */
-static void ali14xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- int driveNum;
- int time1, time2;
- u8 param1, param2, param3, param4;
- unsigned long flags;
- int bus_speed = ide_vlb_clk ? ide_vlb_clk : 50;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
- struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
-
- /* calculate timing, according to PIO mode */
- time1 = ide_pio_cycle_time(drive, pio);
- time2 = t->active;
- param3 = param1 = (time2 * bus_speed + 999) / 1000;
- param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
- if (pio < 3) {
- param3 += 8;
- param4 += 8;
- }
- printk(KERN_DEBUG "%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
- drive->name, pio, time1, time2, param1, param2, param3, param4);
-
- /* stuff timing parameters into controller registers */
- driveNum = (drive->hwif->index << 1) + (drive->dn & 1);
- spin_lock_irqsave(&ali14xx_lock, flags);
- outb_p(regOn, basePort);
- outReg(param1, regTab[driveNum].reg1);
- outReg(param2, regTab[driveNum].reg2);
- outReg(param3, regTab[driveNum].reg3);
- outReg(param4, regTab[driveNum].reg4);
- outb_p(regOff, basePort);
- spin_unlock_irqrestore(&ali14xx_lock, flags);
-}
-
-/*
- * Auto-detect the IDE controller port.
- */
-static int __init findPort(void)
-{
- int i;
- u8 t;
- unsigned long flags;
-
- local_irq_save(flags);
- for (i = 0; i < ALI_NUM_PORTS; ++i) {
- basePort = ports[i];
- regOff = inb(basePort);
- for (regOn = 0x30; regOn <= 0x33; ++regOn) {
- outb_p(regOn, basePort);
- if (inb(basePort) == regOn) {
- regPort = basePort + 4;
- dataPort = basePort + 8;
- t = inReg(0) & 0xf0;
- outb_p(regOff, basePort);
- local_irq_restore(flags);
- if (t != 0x50)
- return 0;
- return 1; /* success */
- }
- }
- outb_p(regOff, basePort);
- }
- local_irq_restore(flags);
- return 0;
-}
-
-/*
- * Initialize controller registers with default values.
- */
-static int __init initRegisters(void)
-{
- const RegInitializer *p;
- u8 t;
- unsigned long flags;
-
- local_irq_save(flags);
- outb_p(regOn, basePort);
- for (p = initData; p->reg != 0; ++p)
- outReg(p->data, p->reg);
- outb_p(0x01, regPort);
- t = inb(regPort) & 0x01;
- outb_p(regOff, basePort);
- local_irq_restore(flags);
- return t;
-}
-
-static const struct ide_port_ops ali14xx_port_ops = {
- .set_pio_mode = ali14xx_set_pio_mode,
-};
-
-static const struct ide_port_info ali14xx_port_info = {
- .name = DRV_NAME,
- .chipset = ide_ali14xx,
- .port_ops = &ali14xx_port_ops,
- .host_flags = IDE_HFLAG_NO_DMA,
- .pio_mask = ATA_PIO4,
-};
-
-static int __init ali14xx_probe(void)
-{
- printk(KERN_DEBUG "ali14xx: base=0x%03x, regOn=0x%02x.\n",
- basePort, regOn);
-
- /* initialize controller registers */
- if (!initRegisters()) {
- printk(KERN_ERR "ali14xx: Chip initialization failed.\n");
- return 1;
- }
-
- return ide_legacy_device_add(&ali14xx_port_info, 0);
-}
-
-static bool probe_ali14xx;
-
-module_param_named(probe, probe_ali14xx, bool, 0);
-MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets");
-
-static int __init ali14xx_init(void)
-{
- if (probe_ali14xx == 0)
- goto out;
-
- /* auto-detect IDE controller port */
- if (findPort()) {
- if (ali14xx_probe())
- return -ENODEV;
- return 0;
- }
- printk(KERN_ERR "ali14xx: not found.\n");
-out:
- return -ENODEV;
-}
-
-module_init(ali14xx_init);
-
-MODULE_AUTHOR("see local file");
-MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
deleted file mode 100644
index 3265970aee34..000000000000
--- a/drivers/ide/alim15x3.c
+++ /dev/null
@@ -1,602 +0,0 @@
-/*
- * Copyright (C) 1998-2000 Michel Aubry, Maintainer
- * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
- * Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
- *
- * Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org)
- * May be copied or modified under the terms of the GNU General Public License
- * Copyright (C) 2002 Alan Cox
- * ALi (now ULi M5228) support by Clear Zhang <Clear.Zhang@ali.com.tw>
- * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
- * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz
- *
- * (U)DMA capable version of ali 1533/1543(C), 1535(D)
- *
- **********************************************************************
- * 9/7/99 --Parts from the above author are included and need to be
- * converted into standard interface, once I finish the thought.
- *
- * Recent changes
- * Don't use LBA48 mode on ALi <= 0xC4
- * Don't poke 0x79 with a non ALi northbridge
- * Don't flip undefined bits on newer chipsets (fix Fujitsu laptop hang)
- * Allow UDMA6 on revisions > 0xC4
- *
- * Documentation
- * Chipset documentation available under NDA only
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/dmi.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "alim15x3"
-
-/*
- * ALi devices are not plug in. Otherwise these static values would
- * need to go. They ought to go away anyway
- */
-
-static u8 m5229_revision;
-static u8 chip_is_1543c_e;
-static struct pci_dev *isa_dev;
-
-static void ali_fifo_control(ide_hwif_t *hwif, ide_drive_t *drive, int on)
-{
- struct pci_dev *pdev = to_pci_dev(hwif->dev);
- int pio_fifo = 0x54 + hwif->channel;
- u8 fifo;
- int shift = 4 * (drive->dn & 1);
-
- pci_read_config_byte(pdev, pio_fifo, &fifo);
- fifo &= ~(0x0F << shift);
- fifo |= (on << shift);
- pci_write_config_byte(pdev, pio_fifo, fifo);
-}
-
-static void ali_program_timings(ide_hwif_t *hwif, ide_drive_t *drive,
- struct ide_timing *t, u8 ultra)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- int port = hwif->channel ? 0x5c : 0x58;
- int udmat = 0x56 + hwif->channel;
- u8 unit = drive->dn & 1, udma;
- int shift = 4 * unit;
-
- /* Set up the UDMA */
- pci_read_config_byte(dev, udmat, &udma);
- udma &= ~(0x0F << shift);
- udma |= ultra << shift;
- pci_write_config_byte(dev, udmat, udma);
-
- if (t == NULL)
- return;
-
- t->setup = clamp_val(t->setup, 1, 8) & 7;
- t->act8b = clamp_val(t->act8b, 1, 8) & 7;
- t->rec8b = clamp_val(t->rec8b, 1, 16) & 15;
- t->active = clamp_val(t->active, 1, 8) & 7;
- t->recover = clamp_val(t->recover, 1, 16) & 15;
-
- pci_write_config_byte(dev, port, t->setup);
- pci_write_config_byte(dev, port + 1, (t->act8b << 4) | t->rec8b);
- pci_write_config_byte(dev, port + unit + 2,
- (t->active << 4) | t->recover);
-}
-
-/**
- * ali_set_pio_mode - set host controller for PIO mode
- * @hwif: port
- * @drive: drive
- *
- * Program the controller for the given PIO mode.
- */
-
-static void ali_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- ide_drive_t *pair = ide_get_pair_dev(drive);
- int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
- unsigned long T = 1000000 / bus_speed; /* PCI clock based */
- struct ide_timing t;
-
- ide_timing_compute(drive, drive->pio_mode, &t, T, 1);
- if (pair) {
- struct ide_timing p;
-
- ide_timing_compute(pair, pair->pio_mode, &p, T, 1);
- ide_timing_merge(&p, &t, &t,
- IDE_TIMING_SETUP | IDE_TIMING_8BIT);
- if (pair->dma_mode) {
- ide_timing_compute(pair, pair->dma_mode, &p, T, 1);
- ide_timing_merge(&p, &t, &t,
- IDE_TIMING_SETUP | IDE_TIMING_8BIT);
- }
- }
-
- /*
- * PIO mode => ATA FIFO on, ATAPI FIFO off
- */
- ali_fifo_control(hwif, drive, (drive->media == ide_disk) ? 0x05 : 0x00);
-
- ali_program_timings(hwif, drive, &t, 0);
-}
-
-/**
- * ali_udma_filter - compute UDMA mask
- * @drive: IDE device
- *
- * Return available UDMA modes.
- *
- * The actual rules for the ALi are:
- * No UDMA on revisions <= 0x20
- * Disk only for revisions < 0xC2
- * Not WDC drives on M1543C-E (?)
- */
-
-static u8 ali_udma_filter(ide_drive_t *drive)
-{
- if (m5229_revision > 0x20 && m5229_revision < 0xC2) {
- if (drive->media != ide_disk)
- return 0;
- if (chip_is_1543c_e &&
- strstr((char *)&drive->id[ATA_ID_PROD], "WDC "))
- return 0;
- }
-
- return drive->hwif->ultra_mask;
-}
-
-/**
- * ali_set_dma_mode - set host controller for DMA mode
- * @hwif: port
- * @drive: drive
- *
- * Configure the hardware for the desired IDE transfer mode.
- */
-
-static void ali_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- static u8 udma_timing[7] = { 0xC, 0xB, 0xA, 0x9, 0x8, 0xF, 0xD };
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- ide_drive_t *pair = ide_get_pair_dev(drive);
- int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
- unsigned long T = 1000000 / bus_speed; /* PCI clock based */
- const u8 speed = drive->dma_mode;
- u8 tmpbyte = 0x00;
- struct ide_timing t;
-
- if (speed < XFER_UDMA_0) {
- ide_timing_compute(drive, drive->dma_mode, &t, T, 1);
- if (pair) {
- struct ide_timing p;
-
- ide_timing_compute(pair, pair->pio_mode, &p, T, 1);
- ide_timing_merge(&p, &t, &t,
- IDE_TIMING_SETUP | IDE_TIMING_8BIT);
- if (pair->dma_mode) {
- ide_timing_compute(pair, pair->dma_mode,
- &p, T, 1);
- ide_timing_merge(&p, &t, &t,
- IDE_TIMING_SETUP | IDE_TIMING_8BIT);
- }
- }
- ali_program_timings(hwif, drive, &t, 0);
- } else {
- ali_program_timings(hwif, drive, NULL,
- udma_timing[speed - XFER_UDMA_0]);
- if (speed >= XFER_UDMA_3) {
- pci_read_config_byte(dev, 0x4b, &tmpbyte);
- tmpbyte |= 1;
- pci_write_config_byte(dev, 0x4b, tmpbyte);
- }
- }
-}
-
-/**
- * ali_dma_check - DMA check
- * @drive: target device
- * @cmd: command
- *
- * Returns 1 if the DMA cannot be performed, zero on success.
- */
-
-static int ali_dma_check(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- if (m5229_revision < 0xC2 && drive->media != ide_disk) {
- if (cmd->tf_flags & IDE_TFLAG_WRITE)
- return 1; /* try PIO instead of DMA */
- }
- return 0;
-}
-
-/**
- * init_chipset_ali15x3 - Initialise an ALi IDE controller
- * @dev: PCI device
- *
- * This function initializes the ALI IDE controller and where
- * appropriate also sets up the 1533 southbridge.
- */
-
-static int init_chipset_ali15x3(struct pci_dev *dev)
-{
- unsigned long flags;
- u8 tmpbyte;
- struct pci_dev *north = pci_get_slot(dev->bus, PCI_DEVFN(0,0));
-
- m5229_revision = dev->revision;
-
- isa_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
-
- local_irq_save(flags);
-
- if (m5229_revision < 0xC2) {
- /*
- * revision 0x20 (1543-E, 1543-F)
- * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
- * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
- */
- pci_read_config_byte(dev, 0x4b, &tmpbyte);
- /*
- * clear bit 7
- */
- pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
- /*
- * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
- */
- if (m5229_revision >= 0x20 && isa_dev) {
- pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
- chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
- }
- goto out;
- }
-
- /*
- * 1543C-B?, 1535, 1535D, 1553
- * Note 1: not all "motherboard" support this detection
- * Note 2: if no udma 66 device, the detection may "error".
- * but in this case, we will not set the device to
- * ultra 66, the detection result is not important
- */
-
- /*
- * enable "Cable Detection", m5229, 0x4b, bit3
- */
- pci_read_config_byte(dev, 0x4b, &tmpbyte);
- pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
-
- /*
- * We should only tune the 1533 enable if we are using an ALi
- * North bridge. We might have no north found on some zany
- * box without a device at 0:0.0. The ALi bridge will be at
- * 0:0.0 so if we didn't find one we know what is cooking.
- */
- if (north && north->vendor != PCI_VENDOR_ID_AL)
- goto out;
-
- if (m5229_revision < 0xC5 && isa_dev)
- {
- /*
- * set south-bridge's enable bit, m1533, 0x79
- */
-
- pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
- if (m5229_revision == 0xC2) {
- /*
- * 1543C-B0 (m1533, 0x79, bit 2)
- */
- pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
- } else if (m5229_revision >= 0xC3) {
- /*
- * 1553/1535 (m1533, 0x79, bit 1)
- */
- pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
- }
- }
-
-out:
- /*
- * CD_ROM DMA on (m5229, 0x53, bit0)
- * Enable this bit even if we want to use PIO.
- * PIO FIFO off (m5229, 0x53, bit1)
- * The hardware will use 0x54h and 0x55h to control PIO FIFO.
- * (Not on later devices it seems)
- *
- * 0x53 changes meaning on later revs - we must no touch
- * bit 1 on them. Need to check if 0x20 is the right break.
- */
- if (m5229_revision >= 0x20) {
- pci_read_config_byte(dev, 0x53, &tmpbyte);
-
- if (m5229_revision <= 0x20)
- tmpbyte = (tmpbyte & (~0x02)) | 0x01;
- else if (m5229_revision == 0xc7 || m5229_revision == 0xc8)
- tmpbyte |= 0x03;
- else
- tmpbyte |= 0x01;
-
- pci_write_config_byte(dev, 0x53, tmpbyte);
- }
- local_irq_restore(flags);
- pci_dev_put(north);
- pci_dev_put(isa_dev);
- return 0;
-}
-
-/*
- * Cable special cases
- */
-
-static const struct dmi_system_id cable_dmi_table[] = {
- {
- .ident = "HP Pavilion N5430",
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"),
- },
- },
- {
- .ident = "Toshiba Satellite S1800-814",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
- DMI_MATCH(DMI_PRODUCT_NAME, "S1800-814"),
- },
- },
- { }
-};
-
-static int ali_cable_override(struct pci_dev *pdev)
-{
- /* Fujitsu P2000 */
- if (pdev->subsystem_vendor == 0x10CF &&
- pdev->subsystem_device == 0x10AF)
- return 1;
-
- /* Mitac 8317 (Winbook-A) and relatives */
- if (pdev->subsystem_vendor == 0x1071 &&
- pdev->subsystem_device == 0x8317)
- return 1;
-
- /* Systems by DMI */
- if (dmi_check_system(cable_dmi_table))
- return 1;
-
- return 0;
-}
-
-/**
- * ali_cable_detect - cable detection
- * @hwif: IDE interface
- *
- * This checks if the controller and the cable are capable
- * of UDMA66 transfers. It doesn't check the drives.
- */
-
-static u8 ali_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 cbl = ATA_CBL_PATA40, tmpbyte;
-
- if (m5229_revision >= 0xC2) {
- /*
- * m5229 80-pin cable detection (from Host View)
- *
- * 0x4a bit0 is 0 => primary channel has 80-pin
- * 0x4a bit1 is 0 => secondary channel has 80-pin
- *
- * Certain laptops use short but suitable cables
- * and don't implement the detect logic.
- */
- if (ali_cable_override(dev))
- cbl = ATA_CBL_PATA40_SHORT;
- else {
- pci_read_config_byte(dev, 0x4a, &tmpbyte);
- if ((tmpbyte & (1 << hwif->channel)) == 0)
- cbl = ATA_CBL_PATA80;
- }
- }
-
- return cbl;
-}
-
-#ifndef CONFIG_SPARC64
-/**
- * init_hwif_ali15x3 - Initialize the ALI IDE x86 stuff
- * @hwif: interface to configure
- *
- * Obtain the IRQ tables for an ALi based IDE solution on the PC
- * class platforms. This part of the code isn't applicable to the
- * Sparc systems.
- */
-
-static void init_hwif_ali15x3(ide_hwif_t *hwif)
-{
- u8 ideic, inmir;
- s8 irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6,
- 1, 11, 0, 12, 0, 14, 0, 15 };
- int irq = -1;
-
- if (isa_dev) {
- /*
- * read IDE interface control
- */
- pci_read_config_byte(isa_dev, 0x58, &ideic);
-
- /* bit0, bit1 */
- ideic = ideic & 0x03;
-
- /* get IRQ for IDE Controller */
- if ((hwif->channel && ideic == 0x03) ||
- (!hwif->channel && !ideic)) {
- /*
- * get SIRQ1 routing table
- */
- pci_read_config_byte(isa_dev, 0x44, &inmir);
- inmir = inmir & 0x0f;
- irq = irq_routing_table[inmir];
- } else if (hwif->channel && !(ideic & 0x01)) {
- /*
- * get SIRQ2 routing table
- */
- pci_read_config_byte(isa_dev, 0x75, &inmir);
- inmir = inmir & 0x0f;
- irq = irq_routing_table[inmir];
- }
- if(irq >= 0)
- hwif->irq = irq;
- }
-}
-#else
-#define init_hwif_ali15x3 NULL
-#endif /* CONFIG_SPARC64 */
-
-/**
- * init_dma_ali15x3 - set up DMA on ALi15x3
- * @hwif: IDE interface
- * @d: IDE port info
- *
- * Set up the DMA functionality on the ALi 15x3.
- */
-
-static int init_dma_ali15x3(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long base = ide_pci_dma_base(hwif, d);
-
- if (base == 0)
- return -1;
-
- hwif->dma_base = base;
-
- if (ide_pci_check_simplex(hwif, d) < 0)
- return -1;
-
- if (ide_pci_set_master(dev, d->name) < 0)
- return -1;
-
- if (!hwif->channel)
- outb(inb(base + 2) & 0x60, base + 2);
-
- printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n",
- hwif->name, base, base + 7);
-
- if (ide_allocate_dma_engine(hwif))
- return -1;
-
- return 0;
-}
-
-static const struct ide_port_ops ali_port_ops = {
- .set_pio_mode = ali_set_pio_mode,
- .set_dma_mode = ali_set_dma_mode,
- .udma_filter = ali_udma_filter,
- .cable_detect = ali_cable_detect,
-};
-
-static const struct ide_dma_ops ali_dma_ops = {
- .dma_host_set = ide_dma_host_set,
- .dma_setup = ide_dma_setup,
- .dma_start = ide_dma_start,
- .dma_end = ide_dma_end,
- .dma_test_irq = ide_dma_test_irq,
- .dma_lost_irq = ide_dma_lost_irq,
- .dma_check = ali_dma_check,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_sff_read_status = ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info ali15x3_chipset = {
- .name = DRV_NAME,
- .init_chipset = init_chipset_ali15x3,
- .init_hwif = init_hwif_ali15x3,
- .init_dma = init_dma_ali15x3,
- .port_ops = &ali_port_ops,
- .dma_ops = &sff_dma_ops,
- .pio_mask = ATA_PIO5,
- .swdma_mask = ATA_SWDMA2,
- .mwdma_mask = ATA_MWDMA2,
-};
-
-/**
- * alim15x3_init_one - set up an ALi15x3 IDE controller
- * @dev: PCI device to set up
- *
- * Perform the actual set up for an ALi15x3 that has been found by the
- * hot plug layer.
- */
-
-static int alim15x3_init_one(struct pci_dev *dev,
- const struct pci_device_id *id)
-{
- struct ide_port_info d = ali15x3_chipset;
- u8 rev = dev->revision, idx = id->driver_data;
-
- /* don't use LBA48 DMA on ALi devices before rev 0xC5 */
- if (rev <= 0xC4)
- d.host_flags |= IDE_HFLAG_NO_LBA48_DMA;
-
- if (rev >= 0x20) {
- if (rev == 0x20)
- d.host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
-
- if (rev < 0xC2)
- d.udma_mask = ATA_UDMA2;
- else if (rev == 0xC2 || rev == 0xC3)
- d.udma_mask = ATA_UDMA4;
- else if (rev == 0xC4)
- d.udma_mask = ATA_UDMA5;
- else
- d.udma_mask = ATA_UDMA6;
-
- d.dma_ops = &ali_dma_ops;
- } else {
- d.host_flags |= IDE_HFLAG_NO_DMA;
-
- d.mwdma_mask = d.swdma_mask = 0;
- }
-
- if (idx == 0)
- d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
-
- return ide_pci_init_one(dev, &d, NULL);
-}
-
-
-static const struct pci_device_id alim15x3_pci_tbl[] = {
- { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), 0 },
- { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), 1 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl);
-
-static struct pci_driver alim15x3_pci_driver = {
- .name = "ALI15x3_IDE",
- .id_table = alim15x3_pci_tbl,
- .probe = alim15x3_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init ali15x3_ide_init(void)
-{
- return ide_pci_register_driver(&alim15x3_pci_driver);
-}
-
-static void __exit ali15x3_ide_exit(void)
-{
- pci_unregister_driver(&alim15x3_pci_driver);
-}
-
-module_init(ali15x3_ide_init);
-module_exit(ali15x3_ide_exit);
-
-MODULE_AUTHOR("Michael Aubry, Andrzej Krzysztofowicz, CJ, Andre Hedrick, Alan Cox, Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("PCI driver module for ALi 15x3 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
deleted file mode 100644
index 7340597a373e..000000000000
--- a/drivers/ide/amd74xx.c
+++ /dev/null
@@ -1,343 +0,0 @@
-// 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.
- *
- * Copyright (c) 2000-2002 Vojtech Pavlik
- * Copyright (c) 2007-2010 Bartlomiej Zolnierkiewicz
- *
- * Based on the work of:
- * Andre Hedrick
- */
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#define DRV_NAME "amd74xx"
-
-enum {
- AMD_IDE_CONFIG = 0x41,
- AMD_CABLE_DETECT = 0x42,
- AMD_DRIVE_TIMING = 0x48,
- AMD_8BIT_TIMING = 0x4e,
- AMD_ADDRESS_SETUP = 0x4c,
- AMD_UDMA_TIMING = 0x50,
-};
-
-static unsigned int amd_80w;
-static unsigned int amd_clock;
-
-static char *amd_dma[] = { "16", "25", "33", "44", "66", "100", "133" };
-static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 };
-
-static inline u8 amd_offset(struct pci_dev *dev)
-{
- return (dev->vendor == PCI_VENDOR_ID_NVIDIA) ? 0x10 : 0;
-}
-
-/*
- * amd_set_speed() writes timing values to the chipset registers
- */
-
-static void amd_set_speed(struct pci_dev *dev, u8 dn, u8 udma_mask,
- struct ide_timing *timing)
-{
- u8 t = 0, offset = amd_offset(dev);
-
- pci_read_config_byte(dev, AMD_ADDRESS_SETUP + offset, &t);
- t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
- pci_write_config_byte(dev, AMD_ADDRESS_SETUP + offset, t);
-
- pci_write_config_byte(dev, AMD_8BIT_TIMING + offset + (1 - (dn >> 1)),
- ((clamp_val(timing->act8b, 1, 16) - 1) << 4) | (clamp_val(timing->rec8b, 1, 16) - 1));
-
- pci_write_config_byte(dev, AMD_DRIVE_TIMING + offset + (3 - dn),
- ((clamp_val(timing->active, 1, 16) - 1) << 4) | (clamp_val(timing->recover, 1, 16) - 1));
-
- switch (udma_mask) {
- case ATA_UDMA2: t = timing->udma ? (0xc0 | (clamp_val(timing->udma, 2, 5) - 2)) : 0x03; break;
- case ATA_UDMA4: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 2, 10)]) : 0x03; break;
- case ATA_UDMA5: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 1, 10)]) : 0x03; break;
- case ATA_UDMA6: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 1, 15)]) : 0x03; break;
- default: return;
- }
-
- if (timing->udma)
- pci_write_config_byte(dev, AMD_UDMA_TIMING + offset + 3 - dn, t);
-}
-
-/*
- * amd_set_drive() computes timing values and configures the chipset
- * to a desired transfer mode. It also can be called by upper layers.
- */
-
-static void amd_set_drive(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- ide_drive_t *peer = ide_get_pair_dev(drive);
- struct ide_timing t, p;
- int T, UT;
- u8 udma_mask = hwif->ultra_mask;
- const u8 speed = drive->dma_mode;
-
- T = 1000000000 / amd_clock;
- UT = (udma_mask == ATA_UDMA2) ? T : (T / 2);
-
- ide_timing_compute(drive, speed, &t, T, UT);
-
- if (peer) {
- ide_timing_compute(peer, peer->pio_mode, &p, T, UT);
- ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
- }
-
- if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1;
- if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15;
-
- amd_set_speed(dev, drive->dn, udma_mask, &t);
-}
-
-/*
- * amd_set_pio_mode() is a callback from upper layers for PIO-only tuning.
- */
-
-static void amd_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- drive->dma_mode = drive->pio_mode;
- amd_set_drive(hwif, drive);
-}
-
-static void amd7409_cable_detect(struct pci_dev *dev)
-{
- /* no host side cable detection */
- amd_80w = 0x03;
-}
-
-static void amd7411_cable_detect(struct pci_dev *dev)
-{
- int i;
- u32 u = 0;
- u8 t = 0, offset = amd_offset(dev);
-
- pci_read_config_byte(dev, AMD_CABLE_DETECT + offset, &t);
- pci_read_config_dword(dev, AMD_UDMA_TIMING + offset, &u);
- amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0);
- for (i = 24; i >= 0; i -= 8)
- if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) {
- printk(KERN_WARNING DRV_NAME " %s: BIOS didn't set "
- "cable bits correctly. Enabling workaround.\n",
- pci_name(dev));
- amd_80w |= (1 << (1 - (i >> 4)));
- }
-}
-
-/*
- * The initialization callback. Initialize drive independent registers.
- */
-
-static int init_chipset_amd74xx(struct pci_dev *dev)
-{
- u8 t = 0, offset = amd_offset(dev);
-
-/*
- * Check 80-wire cable presence.
- */
-
- if (dev->vendor == PCI_VENDOR_ID_AMD &&
- dev->device == PCI_DEVICE_ID_AMD_COBRA_7401)
- ; /* no UDMA > 2 */
- else if (dev->vendor == PCI_VENDOR_ID_AMD &&
- dev->device == PCI_DEVICE_ID_AMD_VIPER_7409)
- amd7409_cable_detect(dev);
- else
- amd7411_cable_detect(dev);
-
-/*
- * Take care of prefetch & postwrite.
- */
-
- pci_read_config_byte(dev, AMD_IDE_CONFIG + offset, &t);
- /*
- * Check for broken FIFO support.
- */
- if (dev->vendor == PCI_VENDOR_ID_AMD &&
- dev->device == PCI_DEVICE_ID_AMD_VIPER_7411)
- t &= 0x0f;
- else
- t |= 0xf0;
- pci_write_config_byte(dev, AMD_IDE_CONFIG + offset, t);
-
- return 0;
-}
-
-static u8 amd_cable_detect(ide_hwif_t *hwif)
-{
- if ((amd_80w >> hwif->channel) & 1)
- return ATA_CBL_PATA80;
- else
- return ATA_CBL_PATA40;
-}
-
-static const struct ide_port_ops amd_port_ops = {
- .set_pio_mode = amd_set_pio_mode,
- .set_dma_mode = amd_set_drive,
- .cable_detect = amd_cable_detect,
-};
-
-#define IDE_HFLAGS_AMD \
- (IDE_HFLAG_PIO_NO_BLACKLIST | \
- IDE_HFLAG_POST_SET_MODE | \
- IDE_HFLAG_IO_32BIT | \
- IDE_HFLAG_UNMASK_IRQS)
-
-#define DECLARE_AMD_DEV(swdma, udma) \
- { \
- .name = DRV_NAME, \
- .init_chipset = init_chipset_amd74xx, \
- .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
- .port_ops = &amd_port_ops, \
- .host_flags = IDE_HFLAGS_AMD, \
- .pio_mask = ATA_PIO5, \
- .swdma_mask = swdma, \
- .mwdma_mask = ATA_MWDMA2, \
- .udma_mask = udma, \
- }
-
-#define DECLARE_NV_DEV(udma) \
- { \
- .name = DRV_NAME, \
- .init_chipset = init_chipset_amd74xx, \
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \
- .port_ops = &amd_port_ops, \
- .host_flags = IDE_HFLAGS_AMD, \
- .pio_mask = ATA_PIO5, \
- .swdma_mask = ATA_SWDMA2, \
- .mwdma_mask = ATA_MWDMA2, \
- .udma_mask = udma, \
- }
-
-static const struct ide_port_info amd74xx_chipsets[] = {
- /* 0: AMD7401 */ DECLARE_AMD_DEV(0x00, ATA_UDMA2),
- /* 1: AMD7409 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA4),
- /* 2: AMD7411/7441 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5),
- /* 3: AMD8111 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA6),
-
- /* 4: NFORCE */ DECLARE_NV_DEV(ATA_UDMA5),
- /* 5: >= NFORCE2 */ DECLARE_NV_DEV(ATA_UDMA6),
-
- /* 6: AMD5536 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5),
-};
-
-static int amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct ide_port_info d;
- u8 idx = id->driver_data;
-
- d = amd74xx_chipsets[idx];
-
- /*
- * Check for bad SWDMA and incorrectly wired Serenade mainboards.
- */
- if (idx == 1) {
- if (dev->revision <= 7)
- d.swdma_mask = 0;
- d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
- } else if (idx == 3) {
- if (dev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
- dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
- d.udma_mask = ATA_UDMA5;
- }
-
- /*
- * It seems that on some nVidia controllers using AltStatus
- * register can be unreliable so default to Status register
- * if the device is in Compatibility Mode.
- */
- if (dev->vendor == PCI_VENDOR_ID_NVIDIA &&
- ide_pci_is_in_compatibility_mode(dev))
- d.host_flags |= IDE_HFLAG_BROKEN_ALTSTATUS;
-
- printk(KERN_INFO "%s %s: UDMA%s controller\n",
- d.name, pci_name(dev), amd_dma[fls(d.udma_mask) - 1]);
-
- /*
- * Determine the system bus clock.
- */
- amd_clock = (ide_pci_clk ? ide_pci_clk : 33) * 1000;
-
- switch (amd_clock) {
- case 33000: amd_clock = 33333; break;
- case 37000: amd_clock = 37500; break;
- case 41000: amd_clock = 41666; break;
- }
-
- if (amd_clock < 20000 || amd_clock > 50000) {
- printk(KERN_WARNING "%s: User given PCI clock speed impossible"
- " (%d), using 33 MHz instead.\n",
- d.name, amd_clock);
- amd_clock = 33333;
- }
-
- return ide_pci_init_one(dev, &d, NULL);
-}
-
-static const struct pci_device_id amd74xx_pci_tbl[] = {
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_COBRA_7401), 0 },
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7409), 1 },
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7411), 2 },
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_OPUS_7441), 2 },
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_8111_IDE), 3 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE), 4 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE), 5 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE), 5 },
-#ifdef CONFIG_BLK_DEV_IDE_SATA
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA), 5 },
-#endif
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE), 5 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE), 5 },
-#ifdef CONFIG_BLK_DEV_IDE_SATA
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA), 5 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2), 5 },
-#endif
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE), 5 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE), 5 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE), 5 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE), 5 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE), 5 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE), 5 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE), 5 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE), 5 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE), 5 },
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 6 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
-
-static struct pci_driver amd74xx_pci_driver = {
- .name = "AMD_IDE",
- .id_table = amd74xx_pci_tbl,
- .probe = amd74xx_probe,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init amd74xx_ide_init(void)
-{
- return ide_pci_register_driver(&amd74xx_pci_driver);
-}
-
-static void __exit amd74xx_ide_exit(void)
-{
- pci_unregister_driver(&amd74xx_pci_driver);
-}
-
-module_init(amd74xx_ide_init);
-module_exit(amd74xx_ide_exit);
-
-MODULE_AUTHOR("Vojtech Pavlik, Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("AMD PCI IDE driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/atiixp.c b/drivers/ide/atiixp.c
deleted file mode 100644
index e08b0aac08b9..000000000000
--- a/drivers/ide/atiixp.c
+++ /dev/null
@@ -1,212 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2003 ATI Inc. <hyu@ati.com>
- * Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "atiixp"
-
-#define ATIIXP_IDE_PIO_TIMING 0x40
-#define ATIIXP_IDE_MDMA_TIMING 0x44
-#define ATIIXP_IDE_PIO_CONTROL 0x48
-#define ATIIXP_IDE_PIO_MODE 0x4a
-#define ATIIXP_IDE_UDMA_CONTROL 0x54
-#define ATIIXP_IDE_UDMA_MODE 0x56
-
-struct atiixp_ide_timing {
- u8 command_width;
- u8 recover_width;
-};
-
-static struct atiixp_ide_timing pio_timing[] = {
- { 0x05, 0x0d },
- { 0x04, 0x07 },
- { 0x03, 0x04 },
- { 0x02, 0x02 },
- { 0x02, 0x00 },
-};
-
-static struct atiixp_ide_timing mdma_timing[] = {
- { 0x07, 0x07 },
- { 0x02, 0x01 },
- { 0x02, 0x00 },
-};
-
-static DEFINE_SPINLOCK(atiixp_lock);
-
-/**
- * atiixp_set_pio_mode - set host controller for PIO mode
- * @hwif: port
- * @drive: drive
- *
- * Set the interface PIO mode.
- */
-
-static void atiixp_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long flags;
- int timing_shift = (drive->dn ^ 1) * 8;
- u32 pio_timing_data;
- u16 pio_mode_data;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
-
- spin_lock_irqsave(&atiixp_lock, flags);
-
- pci_read_config_word(dev, ATIIXP_IDE_PIO_MODE, &pio_mode_data);
- pio_mode_data &= ~(0x07 << (drive->dn * 4));
- pio_mode_data |= (pio << (drive->dn * 4));
- pci_write_config_word(dev, ATIIXP_IDE_PIO_MODE, pio_mode_data);
-
- pci_read_config_dword(dev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data);
- pio_timing_data &= ~(0xff << timing_shift);
- pio_timing_data |= (pio_timing[pio].recover_width << timing_shift) |
- (pio_timing[pio].command_width << (timing_shift + 4));
- pci_write_config_dword(dev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
-
- spin_unlock_irqrestore(&atiixp_lock, flags);
-}
-
-/**
- * atiixp_set_dma_mode - set host controller for DMA mode
- * @hwif: port
- * @drive: drive
- *
- * Set a ATIIXP host controller to the desired DMA mode. This involves
- * programming the right timing data into the PCI configuration space.
- */
-
-static void atiixp_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long flags;
- int timing_shift = (drive->dn ^ 1) * 8;
- u32 tmp32;
- u16 tmp16;
- u16 udma_ctl = 0;
- const u8 speed = drive->dma_mode;
-
- spin_lock_irqsave(&atiixp_lock, flags);
-
- pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_ctl);
-
- if (speed >= XFER_UDMA_0) {
- pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16);
- tmp16 &= ~(0x07 << (drive->dn * 4));
- tmp16 |= ((speed & 0x07) << (drive->dn * 4));
- pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16);
-
- udma_ctl |= (1 << drive->dn);
- } else if (speed >= XFER_MW_DMA_0) {
- u8 i = speed & 0x03;
-
- pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
- tmp32 &= ~(0xff << timing_shift);
- tmp32 |= (mdma_timing[i].recover_width << timing_shift) |
- (mdma_timing[i].command_width << (timing_shift + 4));
- pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
-
- udma_ctl &= ~(1 << drive->dn);
- }
-
- pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, udma_ctl);
-
- spin_unlock_irqrestore(&atiixp_lock, flags);
-}
-
-static u8 atiixp_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *pdev = to_pci_dev(hwif->dev);
- u8 udma_mode = 0, ch = hwif->channel;
-
- pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode);
-
- if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40)
- return ATA_CBL_PATA80;
- else
- return ATA_CBL_PATA40;
-}
-
-static const struct ide_port_ops atiixp_port_ops = {
- .set_pio_mode = atiixp_set_pio_mode,
- .set_dma_mode = atiixp_set_dma_mode,
- .cable_detect = atiixp_cable_detect,
-};
-
-static const struct ide_port_info atiixp_pci_info[] = {
- { /* 0: IXP200/300/400/700 */
- .name = DRV_NAME,
- .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
- .port_ops = &atiixp_port_ops,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA5,
- },
- { /* 1: IXP600 */
- .name = DRV_NAME,
- .enablebits = {{0x48,0x01,0x00}, {0x00,0x00,0x00}},
- .port_ops = &atiixp_port_ops,
- .host_flags = IDE_HFLAG_SINGLE,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA5,
- },
-};
-
-/**
- * atiixp_init_one - called when a ATIIXP is found
- * @dev: the atiixp device
- * @id: the matching pci id
- *
- * Called when the PCI registration layer (or the IDE initialization)
- * finds a device matching our IDE device tables.
- */
-
-static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- return ide_pci_init_one(dev, &atiixp_pci_info[id->driver_data], NULL);
-}
-
-static const struct pci_device_id atiixp_pci_tbl[] = {
- { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), 0 },
- { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), 0 },
- { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), 0 },
- { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), 1 },
- { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), 0 },
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_HUDSON2_IDE), 0 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
-
-static struct pci_driver atiixp_pci_driver = {
- .name = "ATIIXP_IDE",
- .id_table = atiixp_pci_tbl,
- .probe = atiixp_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init atiixp_ide_init(void)
-{
- return ide_pci_register_driver(&atiixp_pci_driver);
-}
-
-static void __exit atiixp_ide_exit(void)
-{
- pci_unregister_driver(&atiixp_pci_driver);
-}
-
-module_init(atiixp_ide_init);
-module_exit(atiixp_ide_exit);
-
-MODULE_AUTHOR("HUI YU");
-MODULE_DESCRIPTION("PCI driver module for ATI IXP IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/buddha.c b/drivers/ide/buddha.c
deleted file mode 100644
index 46eaf58d881b..000000000000
--- a/drivers/ide/buddha.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Amiga Buddha, Catweasel and X-Surf IDE Driver
- *
- * Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
- *
- * This driver was written based on the specifications in README.buddha and
- * the X-Surf info from Inside_XSurf.txt available at
- * http://www.jschoenfeld.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 this archive for
- * more details.
- *
- * TODO:
- * - test it :-)
- * - tune the timings using the speed-register
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/zorro.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-
-
- /*
- * The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2
- */
-
-#define BUDDHA_NUM_HWIFS 2
-#define CATWEASEL_NUM_HWIFS 3
-#define XSURF_NUM_HWIFS 2
-
-#define MAX_NUM_HWIFS 3
-
- /*
- * Bases of the IDE interfaces (relative to the board address)
- */
-
-#define BUDDHA_BASE1 0x800
-#define BUDDHA_BASE2 0xa00
-#define BUDDHA_BASE3 0xc00
-
-#define XSURF_BASE1 0xb000 /* 2.5" Interface */
-#define XSURF_BASE2 0xd000 /* 3.5" Interface */
-
-static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
- BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
-};
-
-static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
- XSURF_BASE1, XSURF_BASE2
-};
-
- /*
- * Offsets from one of the above bases
- */
-
-#define BUDDHA_CONTROL 0x11a
-
- /*
- * Other registers
- */
-
-#define BUDDHA_IRQ1 0xf00 /* MSB = 1, Harddisk is source of */
-#define BUDDHA_IRQ2 0xf40 /* interrupt */
-#define BUDDHA_IRQ3 0xf80
-
-#define XSURF_IRQ1 0x7e
-#define XSURF_IRQ2 0x7e
-
-static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
- BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
-};
-
-static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
- XSURF_IRQ1, XSURF_IRQ2
-};
-
-#define BUDDHA_IRQ_MR 0xfc0 /* master interrupt enable */
-
-
- /*
- * Board information
- */
-
-typedef enum BuddhaType_Enum {
- BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
-} BuddhaType;
-
-static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" };
-
- /*
- * Check and acknowledge the interrupt status
- */
-
-static int buddha_test_irq(ide_hwif_t *hwif)
-{
- unsigned char ch;
-
- ch = z_readb(hwif->io_ports.irq_addr);
- if (!(ch & 0x80))
- return 0;
- return 1;
-}
-
-static void xsurf_clear_irq(ide_drive_t *drive)
-{
- /*
- * X-Surf needs 0 written to IRQ register to ensure ISA bit A11 stays at 0
- */
- z_writeb(0, drive->hwif->io_ports.irq_addr);
-}
-
-static void __init buddha_setup_ports(struct ide_hw *hw, unsigned long base,
- unsigned long ctl, unsigned long irq_port)
-{
- int i;
-
- memset(hw, 0, sizeof(*hw));
-
- hw->io_ports.data_addr = base;
-
- for (i = 1; i < 8; i++)
- hw->io_ports_array[i] = base + 2 + i * 4;
-
- hw->io_ports.ctl_addr = ctl;
- hw->io_ports.irq_addr = irq_port;
-
- hw->irq = IRQ_AMIGA_PORTS;
-}
-
-static const struct ide_port_ops buddha_port_ops = {
- .test_irq = buddha_test_irq,
-};
-
-static const struct ide_port_ops xsurf_port_ops = {
- .clear_irq = xsurf_clear_irq,
- .test_irq = buddha_test_irq,
-};
-
-static const struct ide_port_info buddha_port_info = {
- .port_ops = &buddha_port_ops,
- .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
- .irq_flags = IRQF_SHARED,
- .chipset = ide_generic,
-};
-
- /*
- * Probe for a Buddha or Catweasel IDE interface
- */
-
-static int __init buddha_init(void)
-{
- struct zorro_dev *z = NULL;
- u_long buddha_board = 0;
- BuddhaType type;
- int buddha_num_hwifs, i;
-
- while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
- unsigned long board;
- struct ide_hw hw[MAX_NUM_HWIFS], *hws[MAX_NUM_HWIFS];
- struct ide_port_info d = buddha_port_info;
-
- if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
- buddha_num_hwifs = BUDDHA_NUM_HWIFS;
- type=BOARD_BUDDHA;
- } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
- buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
- type=BOARD_CATWEASEL;
- } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
- buddha_num_hwifs = XSURF_NUM_HWIFS;
- type=BOARD_XSURF;
- d.port_ops = &xsurf_port_ops;
- } else
- continue;
-
- board = z->resource.start;
-
- if(type != BOARD_XSURF) {
- if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
- continue;
- } else {
- if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
- continue;
- if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
- goto fail_base2;
- if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
- release_mem_region(board+XSURF_BASE2, 0x1000);
-fail_base2:
- release_mem_region(board+XSURF_BASE1, 0x1000);
- continue;
- }
- }
- buddha_board = (unsigned long)ZTWO_VADDR(board);
-
- /* write to BUDDHA_IRQ_MR to enable the board IRQ */
- /* X-Surf doesn't have this. IRQs are always on */
- if (type != BOARD_XSURF)
- z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
-
- printk(KERN_INFO "ide: %s IDE controller\n",
- buddha_board_name[type]);
-
- for (i = 0; i < buddha_num_hwifs; i++) {
- unsigned long base, ctl, irq_port;
-
- if (type != BOARD_XSURF) {
- base = buddha_board + buddha_bases[i];
- ctl = base + BUDDHA_CONTROL;
- irq_port = buddha_board + buddha_irqports[i];
- } else {
- base = buddha_board + xsurf_bases[i];
- /* X-Surf has no CS1* (Control/AltStat) */
- ctl = 0;
- irq_port = buddha_board + xsurf_irqports[i];
- }
-
- buddha_setup_ports(&hw[i], base, ctl, irq_port);
-
- hws[i] = &hw[i];
- }
-
- ide_host_add(&d, hws, i, NULL);
- }
-
- return 0;
-}
-
-module_init(buddha_init);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c
deleted file mode 100644
index f48decb9fac4..000000000000
--- a/drivers/ide/cmd640.c
+++ /dev/null
@@ -1,848 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1995-1996 Linus Torvalds & authors (see below)
- */
-
-/*
- * Original authors: abramov@cecmow.enet.dec.com (Igor Abramov)
- * mlord@pobox.com (Mark Lord)
- *
- * See linux/MAINTAINERS for address of current maintainer.
- *
- * This file provides support for the advanced features and bugs
- * of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
- *
- * These chips are basically fucked by design, and getting this driver
- * to work on every motherboard design that uses this screwed chip seems
- * bloody well impossible. However, we're still trying.
- *
- * Version 0.97 worked for everybody.
- *
- * User feedback is essential. Many thanks to the beta test team:
- *
- * A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
- * bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
- * chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
- * derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
- * flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
- * j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
- * kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
- * peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
- * s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
- * steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
- * liug@mama.indstate.edu, and others.
- *
- * Version 0.01 Initial version, hacked out of ide.c,
- * and #include'd rather than compiled separately.
- * This will get cleaned up in a subsequent release.
- *
- * Version 0.02 Fixes for vlb initialization code, enable prefetch
- * for versions 'B' and 'C' of chip by default,
- * some code cleanup.
- *
- * Version 0.03 Added reset of secondary interface,
- * and black list for devices which are not compatible
- * with prefetch mode. Separate function for setting
- * prefetch is added, possibly it will be called some
- * day from ioctl processing code.
- *
- * Version 0.04 Now configs/compiles separate from ide.c
- *
- * Version 0.05 Major rewrite of interface timing code.
- * Added new function cmd640_set_mode to set PIO mode
- * from ioctl call. New drives added to black list.
- *
- * Version 0.06 More code cleanup. Prefetch is enabled only for
- * detected hard drives, not included in prefetch
- * black list.
- *
- * Version 0.07 Changed to more conservative drive tuning policy.
- * Unknown drives, which report PIO < 4 are set to
- * (reported_PIO - 1) if it is supported, or to PIO0.
- * List of known drives extended by info provided by
- * CMD at their ftp site.
- *
- * Version 0.08 Added autotune/noautotune support.
- *
- * Version 0.09 Try to be smarter about 2nd port enabling.
- * Version 0.10 Be nice and don't reset 2nd port.
- * Version 0.11 Try to handle more weird situations.
- *
- * Version 0.12 Lots of bug fixes from Laszlo Peter
- * irq unmasking disabled for reliability.
- * try to be even smarter about the second port.
- * tidy up source code formatting.
- * Version 0.13 permit irq unmasking again.
- * Version 0.90 massive code cleanup, some bugs fixed.
- * defaults all drives to PIO mode0, prefetch off.
- * autotune is OFF by default, with compile time flag.
- * prefetch can be turned OFF/ON using "hdparm -p8/-p9"
- * (requires hdparm-3.1 or newer)
- * Version 0.91 first release to linux-kernel list.
- * Version 0.92 move initial reg dump to separate callable function
- * change "readahead" to "prefetch" to avoid confusion
- * Version 0.95 respect original BIOS timings unless autotuning.
- * tons of code cleanup and rearrangement.
- * added CONFIG_BLK_DEV_CMD640_ENHANCED option
- * prevent use of unmask when prefetch is on
- * Version 0.96 prevent use of io_32bit when prefetch is off
- * Version 0.97 fix VLB secondary interface for sjd@slip.net
- * other minor tune-ups: 0.96 was very good.
- * Version 0.98 ignore PCI version when disabled by BIOS
- * Version 0.99 display setup/active/recovery clocks with PIO mode
- * Version 1.00 Mmm.. cannot depend on PCMD_ENA in all systems
- * Version 1.01 slow/fast devsel can be selected with "hdparm -p6/-p7"
- * ("fast" is necessary for 32bit I/O in some systems)
- * Version 1.02 fix bug that resulted in slow "setup times"
- * (patch courtesy of Zoltan Hidvegi)
- */
-
-#define CMD640_PREFETCH_MASKS 1
-
-/*#define CMD640_DUMP_REGS */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "cmd640"
-
-static bool cmd640_vlb;
-
-/*
- * CMD640 specific registers definition.
- */
-
-#define VID 0x00
-#define DID 0x02
-#define PCMD 0x04
-#define PCMD_ENA 0x01
-#define PSTTS 0x06
-#define REVID 0x08
-#define PROGIF 0x09
-#define SUBCL 0x0a
-#define BASCL 0x0b
-#define BaseA0 0x10
-#define BaseA1 0x14
-#define BaseA2 0x18
-#define BaseA3 0x1c
-#define INTLINE 0x3c
-#define INPINE 0x3d
-
-#define CFR 0x50
-#define CFR_DEVREV 0x03
-#define CFR_IDE01INTR 0x04
-#define CFR_DEVID 0x18
-#define CFR_AT_VESA_078h 0x20
-#define CFR_DSA1 0x40
-#define CFR_DSA0 0x80
-
-#define CNTRL 0x51
-#define CNTRL_DIS_RA0 0x40
-#define CNTRL_DIS_RA1 0x80
-#define CNTRL_ENA_2ND 0x08
-
-#define CMDTIM 0x52
-#define ARTTIM0 0x53
-#define DRWTIM0 0x54
-#define ARTTIM1 0x55
-#define DRWTIM1 0x56
-#define ARTTIM23 0x57
-#define ARTTIM23_DIS_RA2 0x04
-#define ARTTIM23_DIS_RA3 0x08
-#define ARTTIM23_IDE23INTR 0x10
-#define DRWTIM23 0x58
-#define BRST 0x59
-
-/*
- * Registers and masks for easy access by drive index:
- */
-static u8 prefetch_regs[4] = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
-
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-
-static u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
-static u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
-
-/*
- * Current cmd640 timing values for each drive.
- * The defaults for each are the slowest possible timings.
- */
-static u8 setup_counts[4] = {4, 4, 4, 4}; /* Address setup count (in clocks) */
-static u8 active_counts[4] = {16, 16, 16, 16}; /* Active count (encoded) */
-static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
-
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-static DEFINE_SPINLOCK(cmd640_lock);
-
-/*
- * Interface to access cmd640x registers
- */
-static unsigned int cmd640_key;
-static void (*__put_cmd640_reg)(u16 reg, u8 val);
-static u8 (*__get_cmd640_reg)(u16 reg);
-
-/*
- * This is read from the CFR reg, and is used in several places.
- */
-static unsigned int cmd640_chip_version;
-
-/*
- * The CMD640x chip does not support DWORD config write cycles, but some
- * of the BIOSes use them to implement the config services.
- * Therefore, we must use direct IO instead.
- */
-
-/* PCI method 1 access */
-
-static void put_cmd640_reg_pci1(u16 reg, u8 val)
-{
- outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
- outb_p(val, (reg & 3) | 0xcfc);
-}
-
-static u8 get_cmd640_reg_pci1(u16 reg)
-{
- outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
- return inb_p((reg & 3) | 0xcfc);
-}
-
-/* PCI method 2 access (from CMD datasheet) */
-
-static void put_cmd640_reg_pci2(u16 reg, u8 val)
-{
- outb_p(0x10, 0xcf8);
- outb_p(val, cmd640_key + reg);
- outb_p(0, 0xcf8);
-}
-
-static u8 get_cmd640_reg_pci2(u16 reg)
-{
- u8 b;
-
- outb_p(0x10, 0xcf8);
- b = inb_p(cmd640_key + reg);
- outb_p(0, 0xcf8);
- return b;
-}
-
-/* VLB access */
-
-static void put_cmd640_reg_vlb(u16 reg, u8 val)
-{
- outb_p(reg, cmd640_key);
- outb_p(val, cmd640_key + 4);
-}
-
-static u8 get_cmd640_reg_vlb(u16 reg)
-{
- outb_p(reg, cmd640_key);
- return inb_p(cmd640_key + 4);
-}
-
-static u8 get_cmd640_reg(u16 reg)
-{
- unsigned long flags;
- u8 b;
-
- spin_lock_irqsave(&cmd640_lock, flags);
- b = __get_cmd640_reg(reg);
- spin_unlock_irqrestore(&cmd640_lock, flags);
- return b;
-}
-
-static void put_cmd640_reg(u16 reg, u8 val)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cmd640_lock, flags);
- __put_cmd640_reg(reg, val);
- spin_unlock_irqrestore(&cmd640_lock, flags);
-}
-
-static int __init match_pci_cmd640_device(void)
-{
- const u8 ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
- unsigned int i;
- for (i = 0; i < 4; i++) {
- if (get_cmd640_reg(i) != ven_dev[i])
- return 0;
- }
-#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT
- if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {
- printk("ide: cmd640 on PCI disabled by BIOS\n");
- return 0;
- }
-#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */
- return 1; /* success */
-}
-
-/*
- * Probe for CMD640x -- pci method 1
- */
-static int __init probe_for_cmd640_pci1(void)
-{
- __get_cmd640_reg = get_cmd640_reg_pci1;
- __put_cmd640_reg = put_cmd640_reg_pci1;
- for (cmd640_key = 0x80000000;
- cmd640_key <= 0x8000f800;
- cmd640_key += 0x800) {
- if (match_pci_cmd640_device())
- return 1; /* success */
- }
- return 0;
-}
-
-/*
- * Probe for CMD640x -- pci method 2
- */
-static int __init probe_for_cmd640_pci2(void)
-{
- __get_cmd640_reg = get_cmd640_reg_pci2;
- __put_cmd640_reg = put_cmd640_reg_pci2;
- for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
- if (match_pci_cmd640_device())
- return 1; /* success */
- }
- return 0;
-}
-
-/*
- * Probe for CMD640x -- vlb
- */
-static int __init probe_for_cmd640_vlb(void)
-{
- u8 b;
-
- __get_cmd640_reg = get_cmd640_reg_vlb;
- __put_cmd640_reg = put_cmd640_reg_vlb;
- cmd640_key = 0x178;
- b = get_cmd640_reg(CFR);
- if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
- cmd640_key = 0x78;
- b = get_cmd640_reg(CFR);
- if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
- return 0;
- }
- return 1; /* success */
-}
-
-/*
- * Returns 1 if an IDE interface/drive exists at 0x170,
- * Returns 0 otherwise.
- */
-static int __init secondary_port_responding(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cmd640_lock, flags);
-
- outb_p(0x0a, 0x176); /* select drive0 */
- udelay(100);
- if ((inb_p(0x176) & 0x1f) != 0x0a) {
- outb_p(0x1a, 0x176); /* select drive1 */
- udelay(100);
- if ((inb_p(0x176) & 0x1f) != 0x1a) {
- spin_unlock_irqrestore(&cmd640_lock, flags);
- return 0; /* nothing responded */
- }
- }
- spin_unlock_irqrestore(&cmd640_lock, flags);
- return 1; /* success */
-}
-
-#ifdef CMD640_DUMP_REGS
-/*
- * Dump out all cmd640 registers. May be called from ide.c
- */
-static void cmd640_dump_regs(void)
-{
- unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
-
- /* Dump current state of chip registers */
- printk("ide: cmd640 internal register dump:");
- for (; reg <= 0x59; reg++) {
- if (!(reg & 0x0f))
- printk("\n%04x:", reg);
- printk(" %02x", get_cmd640_reg(reg));
- }
- printk("\n");
-}
-#endif
-
-static void __set_prefetch_mode(ide_drive_t *drive, int mode)
-{
- if (mode) { /* want prefetch on? */
-#if CMD640_PREFETCH_MASKS
- drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
- drive->dev_flags &= ~IDE_DFLAG_UNMASK;
-#endif
- drive->dev_flags &= ~IDE_DFLAG_NO_IO_32BIT;
- } else {
- drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK;
- drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT;
- drive->io_32bit = 0;
- }
-}
-
-#ifndef CONFIG_BLK_DEV_CMD640_ENHANCED
-/*
- * Check whether prefetch is on for a drive,
- * and initialize the unmask flags for safe operation.
- */
-static void __init check_prefetch(ide_drive_t *drive, unsigned int index)
-{
- u8 b = get_cmd640_reg(prefetch_regs[index]);
-
- __set_prefetch_mode(drive, (b & prefetch_masks[index]) ? 0 : 1);
-}
-#else
-
-/*
- * Sets prefetch mode for a drive.
- */
-static void set_prefetch_mode(ide_drive_t *drive, unsigned int index, int mode)
-{
- unsigned long flags;
- int reg = prefetch_regs[index];
- u8 b;
-
- spin_lock_irqsave(&cmd640_lock, flags);
- b = __get_cmd640_reg(reg);
- __set_prefetch_mode(drive, mode);
- if (mode)
- b &= ~prefetch_masks[index]; /* enable prefetch */
- else
- b |= prefetch_masks[index]; /* disable prefetch */
- __put_cmd640_reg(reg, b);
- spin_unlock_irqrestore(&cmd640_lock, flags);
-}
-
-/*
- * Dump out current drive clocks settings
- */
-static void display_clocks(unsigned int index)
-{
- u8 active_count, recovery_count;
-
- active_count = active_counts[index];
- if (active_count == 1)
- ++active_count;
- recovery_count = recovery_counts[index];
- if (active_count > 3 && recovery_count == 1)
- ++recovery_count;
- if (cmd640_chip_version > 1)
- recovery_count += 1; /* cmd640b uses (count + 1)*/
- printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count);
-}
-
-/*
- * Pack active and recovery counts into single byte representation
- * used by controller
- */
-static inline u8 pack_nibbles(u8 upper, u8 lower)
-{
- return ((upper & 0x0f) << 4) | (lower & 0x0f);
-}
-
-/*
- * This routine writes the prepared setup/active/recovery counts
- * for a drive into the cmd640 chipset registers to active them.
- */
-static void program_drive_counts(ide_drive_t *drive, unsigned int index)
-{
- unsigned long flags;
- u8 setup_count = setup_counts[index];
- u8 active_count = active_counts[index];
- u8 recovery_count = recovery_counts[index];
-
- /*
- * Set up address setup count and drive read/write timing registers.
- * Primary interface has individual count/timing registers for
- * each drive. Secondary interface has one common set of registers,
- * so we merge the timings, using the slowest value for each timing.
- */
- if (index > 1) {
- ide_drive_t *peer = ide_get_pair_dev(drive);
- unsigned int mate = index ^ 1;
-
- if (peer) {
- if (setup_count < setup_counts[mate])
- setup_count = setup_counts[mate];
- if (active_count < active_counts[mate])
- active_count = active_counts[mate];
- if (recovery_count < recovery_counts[mate])
- recovery_count = recovery_counts[mate];
- }
- }
-
- /*
- * Convert setup_count to internal chipset representation
- */
- switch (setup_count) {
- case 4: setup_count = 0x00; break;
- case 3: setup_count = 0x80; break;
- case 1:
- case 2: setup_count = 0x40; break;
- default: setup_count = 0xc0; /* case 5 */
- }
-
- /*
- * Now that everything is ready, program the new timings
- */
- spin_lock_irqsave(&cmd640_lock, flags);
- /*
- * Program the address_setup clocks into ARTTIM reg,
- * and then the active/recovery counts into the DRWTIM reg
- * (this converts counts of 16 into counts of zero -- okay).
- */
- setup_count |= __get_cmd640_reg(arttim_regs[index]) & 0x3f;
- __put_cmd640_reg(arttim_regs[index], setup_count);
- __put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
- spin_unlock_irqrestore(&cmd640_lock, flags);
-}
-
-/*
- * Set a specific pio_mode for a drive
- */
-static void cmd640_set_mode(ide_drive_t *drive, unsigned int index,
- u8 pio_mode, unsigned int cycle_time)
-{
- struct ide_timing *t;
- int setup_time, active_time, recovery_time, clock_time;
- u8 setup_count, active_count, recovery_count, recovery_count2, cycle_count;
- int bus_speed;
-
- if (cmd640_vlb)
- bus_speed = ide_vlb_clk ? ide_vlb_clk : 50;
- else
- bus_speed = ide_pci_clk ? ide_pci_clk : 33;
-
- if (pio_mode > 5)
- pio_mode = 5;
-
- t = ide_timing_find_mode(XFER_PIO_0 + pio_mode);
- setup_time = t->setup;
- active_time = t->active;
-
- recovery_time = cycle_time - (setup_time + active_time);
- clock_time = 1000 / bus_speed;
- cycle_count = DIV_ROUND_UP(cycle_time, clock_time);
-
- setup_count = DIV_ROUND_UP(setup_time, clock_time);
-
- active_count = DIV_ROUND_UP(active_time, clock_time);
- if (active_count < 2)
- active_count = 2; /* minimum allowed by cmd640 */
-
- recovery_count = DIV_ROUND_UP(recovery_time, clock_time);
- recovery_count2 = cycle_count - (setup_count + active_count);
- if (recovery_count2 > recovery_count)
- recovery_count = recovery_count2;
- if (recovery_count < 2)
- recovery_count = 2; /* minimum allowed by cmd640 */
- if (recovery_count > 17) {
- active_count += recovery_count - 17;
- recovery_count = 17;
- }
- if (active_count > 16)
- active_count = 16; /* maximum allowed by cmd640 */
- if (cmd640_chip_version > 1)
- recovery_count -= 1; /* cmd640b uses (count + 1)*/
- if (recovery_count > 16)
- recovery_count = 16; /* maximum allowed by cmd640 */
-
- setup_counts[index] = setup_count;
- active_counts[index] = active_count;
- recovery_counts[index] = recovery_count;
-
- /*
- * In a perfect world, we might set the drive pio mode here
- * (using WIN_SETFEATURE) before continuing.
- *
- * But we do not, because:
- * 1) this is the wrong place to do it (proper is do_special() in ide.c)
- * 2) in practice this is rarely, if ever, necessary
- */
- program_drive_counts(drive, index);
-}
-
-static void cmd640_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- unsigned int index = 0, cycle_time;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
- u8 b;
-
- switch (pio) {
- case 6: /* set fast-devsel off */
- case 7: /* set fast-devsel on */
- b = get_cmd640_reg(CNTRL) & ~0x27;
- if (pio & 1)
- b |= 0x27;
- put_cmd640_reg(CNTRL, b);
- printk("%s: %sabled cmd640 fast host timing (devsel)\n",
- drive->name, (pio & 1) ? "en" : "dis");
- return;
- case 8: /* set prefetch off */
- case 9: /* set prefetch on */
- set_prefetch_mode(drive, index, pio & 1);
- printk("%s: %sabled cmd640 prefetch\n",
- drive->name, (pio & 1) ? "en" : "dis");
- return;
- }
-
- cycle_time = ide_pio_cycle_time(drive, pio);
- cmd640_set_mode(drive, index, pio, cycle_time);
-
- printk("%s: selected cmd640 PIO mode%d (%dns)",
- drive->name, pio, cycle_time);
-
- display_clocks(index);
-}
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-static void __init cmd640_init_dev(ide_drive_t *drive)
-{
- unsigned int i = drive->hwif->channel * 2 + (drive->dn & 1);
-
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
- /*
- * Reset timing to the slowest speed and turn off prefetch.
- * This way, the drive identify code has a better chance.
- */
- setup_counts[i] = 4; /* max possible */
- active_counts[i] = 16; /* max possible */
- recovery_counts[i] = 16; /* max possible */
- program_drive_counts(drive, i);
- set_prefetch_mode(drive, i, 0);
- printk(KERN_INFO DRV_NAME ": drive%d timings/prefetch cleared\n", i);
-#else
- /*
- * Set the drive unmask flags to match the prefetch setting.
- */
- check_prefetch(drive, i);
- printk(KERN_INFO DRV_NAME ": drive%d timings/prefetch(%s) preserved\n",
- i, (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT) ? "off" : "on");
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-}
-
-static int cmd640_test_irq(ide_hwif_t *hwif)
-{
- int irq_reg = hwif->channel ? ARTTIM23 : CFR;
- u8 irq_mask = hwif->channel ? ARTTIM23_IDE23INTR :
- CFR_IDE01INTR;
- u8 irq_stat = get_cmd640_reg(irq_reg);
-
- return (irq_stat & irq_mask) ? 1 : 0;
-}
-
-static const struct ide_port_ops cmd640_port_ops = {
- .init_dev = cmd640_init_dev,
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
- .set_pio_mode = cmd640_set_pio_mode,
-#endif
- .test_irq = cmd640_test_irq,
-};
-
-static int pci_conf1(void)
-{
- unsigned long flags;
- u32 tmp;
-
- spin_lock_irqsave(&cmd640_lock, flags);
- outb(0x01, 0xCFB);
- tmp = inl(0xCF8);
- outl(0x80000000, 0xCF8);
- if (inl(0xCF8) == 0x80000000) {
- outl(tmp, 0xCF8);
- spin_unlock_irqrestore(&cmd640_lock, flags);
- return 1;
- }
- outl(tmp, 0xCF8);
- spin_unlock_irqrestore(&cmd640_lock, flags);
- return 0;
-}
-
-static int pci_conf2(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cmd640_lock, flags);
- outb(0x00, 0xCFB);
- outb(0x00, 0xCF8);
- outb(0x00, 0xCFA);
- if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) {
- spin_unlock_irqrestore(&cmd640_lock, flags);
- return 1;
- }
- spin_unlock_irqrestore(&cmd640_lock, flags);
- return 0;
-}
-
-static const struct ide_port_info cmd640_port_info __initconst = {
- .chipset = ide_cmd640,
- .host_flags = IDE_HFLAG_SERIALIZE |
- IDE_HFLAG_NO_DMA |
- IDE_HFLAG_ABUSE_PREFETCH |
- IDE_HFLAG_ABUSE_FAST_DEVSEL,
- .port_ops = &cmd640_port_ops,
- .pio_mask = ATA_PIO5,
-};
-
-static int __init cmd640x_init_one(unsigned long base, unsigned long ctl)
-{
- if (!request_region(base, 8, DRV_NAME)) {
- printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
- DRV_NAME, base, base + 7);
- return -EBUSY;
- }
-
- if (!request_region(ctl, 1, DRV_NAME)) {
- printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
- DRV_NAME, ctl);
- release_region(base, 8);
- return -EBUSY;
- }
-
- return 0;
-}
-
-/*
- * Probe for a cmd640 chipset, and initialize it if found.
- */
-static int __init cmd640x_init(void)
-{
- int second_port_cmd640 = 0, rc;
- const char *bus_type, *port2;
- u8 b, cfr;
- struct ide_hw hw[2], *hws[2];
-
- if (cmd640_vlb && probe_for_cmd640_vlb()) {
- bus_type = "VLB";
- } else {
- cmd640_vlb = 0;
- /* Find out what kind of PCI probing is supported otherwise
- Justin Gibbs will sulk.. */
- if (pci_conf1() && probe_for_cmd640_pci1())
- bus_type = "PCI (type1)";
- else if (pci_conf2() && probe_for_cmd640_pci2())
- bus_type = "PCI (type2)";
- else
- return 0;
- }
- /*
- * Undocumented magic (there is no 0x5b reg in specs)
- */
- put_cmd640_reg(0x5b, 0xbd);
- if (get_cmd640_reg(0x5b) != 0xbd) {
- printk(KERN_ERR "ide: cmd640 init failed: wrong value in reg 0x5b\n");
- return 0;
- }
- put_cmd640_reg(0x5b, 0);
-
-#ifdef CMD640_DUMP_REGS
- cmd640_dump_regs();
-#endif
-
- /*
- * Documented magic begins here
- */
- cfr = get_cmd640_reg(CFR);
- cmd640_chip_version = cfr & CFR_DEVREV;
- if (cmd640_chip_version == 0) {
- printk("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
- return 0;
- }
-
- rc = cmd640x_init_one(0x1f0, 0x3f6);
- if (rc)
- return rc;
-
- rc = cmd640x_init_one(0x170, 0x376);
- if (rc) {
- release_region(0x3f6, 1);
- release_region(0x1f0, 8);
- return rc;
- }
-
- memset(&hw, 0, sizeof(hw));
-
- ide_std_init_ports(&hw[0], 0x1f0, 0x3f6);
- hw[0].irq = 14;
-
- ide_std_init_ports(&hw[1], 0x170, 0x376);
- hw[1].irq = 15;
-
- printk(KERN_INFO "cmd640: buggy cmd640%c interface on %s, config=0x%02x"
- "\n", 'a' + cmd640_chip_version - 1, bus_type, cfr);
-
- /*
- * Initialize data for primary port
- */
- hws[0] = &hw[0];
-
- /*
- * Ensure compatibility by always using the slowest timings
- * for access to the drive's command register block,
- * and reset the prefetch burstsize to default (512 bytes).
- *
- * Maybe we need a way to NOT do these on *some* systems?
- */
- put_cmd640_reg(CMDTIM, 0);
- put_cmd640_reg(BRST, 0x40);
-
- b = get_cmd640_reg(CNTRL);
-
- /*
- * Try to enable the secondary interface, if not already enabled
- */
- if (secondary_port_responding()) {
- if ((b & CNTRL_ENA_2ND)) {
- second_port_cmd640 = 1;
- port2 = "okay";
- } else if (cmd640_vlb) {
- second_port_cmd640 = 1;
- port2 = "alive";
- } else
- port2 = "not cmd640";
- } else {
- put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
- if (secondary_port_responding()) {
- second_port_cmd640 = 1;
- port2 = "enabled";
- } else {
- put_cmd640_reg(CNTRL, b); /* restore original setting */
- port2 = "not responding";
- }
- }
-
- /*
- * Initialize data for secondary cmd640 port, if enabled
- */
- if (second_port_cmd640)
- hws[1] = &hw[1];
-
- printk(KERN_INFO "cmd640: %sserialized, secondary interface %s\n",
- second_port_cmd640 ? "" : "not ", port2);
-
-#ifdef CMD640_DUMP_REGS
- cmd640_dump_regs();
-#endif
-
- return ide_host_add(&cmd640_port_info, hws, second_port_cmd640 ? 2 : 1,
- NULL);
-}
-
-module_param_named(probe_vlb, cmd640_vlb, bool, 0);
-MODULE_PARM_DESC(probe_vlb, "probe for VLB version of CMD640 chipset");
-
-module_init(cmd640x_init);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
deleted file mode 100644
index 943bf944bf72..000000000000
--- a/drivers/ide/cmd64x.c
+++ /dev/null
@@ -1,452 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
- * Due to massive hardware bugs, UltraDMA is only supported
- * on the 646U2 and not on the 646U.
- *
- * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1998 David S. Miller (davem@redhat.com)
- *
- * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz
- * Copyright (C) 2007,2009 MontaVista Software, Inc. <source@mvista.com>
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "cmd64x"
-
-/*
- * CMD64x specific registers definition.
- */
-#define CFR 0x50
-#define CFR_INTR_CH0 0x04
-
-#define CMDTIM 0x52
-#define ARTTIM0 0x53
-#define DRWTIM0 0x54
-#define ARTTIM1 0x55
-#define DRWTIM1 0x56
-#define ARTTIM23 0x57
-#define ARTTIM23_DIS_RA2 0x04
-#define ARTTIM23_DIS_RA3 0x08
-#define ARTTIM23_INTR_CH1 0x10
-#define DRWTIM2 0x58
-#define BRST 0x59
-#define DRWTIM3 0x5b
-
-#define BMIDECR0 0x70
-#define MRDMODE 0x71
-#define MRDMODE_INTR_CH0 0x04
-#define MRDMODE_INTR_CH1 0x08
-#define UDIDETCR0 0x73
-#define DTPR0 0x74
-#define BMIDECR1 0x78
-#define BMIDECSR 0x79
-#define UDIDETCR1 0x7B
-#define DTPR1 0x7C
-
-static void cmd64x_program_timings(ide_drive_t *drive, u8 mode)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
- const unsigned long T = 1000000 / bus_speed;
- static const u8 recovery_values[] =
- {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
- static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
- static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
- static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3};
- struct ide_timing t;
- u8 arttim = 0;
-
- if (drive->dn >= ARRAY_SIZE(drwtim_regs))
- return;
-
- ide_timing_compute(drive, mode, &t, T, 0);
-
- /*
- * In case we've got too long recovery phase, try to lengthen
- * the active phase
- */
- if (t.recover > 16) {
- t.active += t.recover - 16;
- t.recover = 16;
- }
- if (t.active > 16) /* shouldn't actually happen... */
- t.active = 16;
-
- /*
- * Convert values to internal chipset representation
- */
- t.recover = recovery_values[t.recover];
- t.active &= 0x0f;
-
- /* Program the active/recovery counts into the DRWTIM register */
- pci_write_config_byte(dev, drwtim_regs[drive->dn],
- (t.active << 4) | t.recover);
-
- /*
- * The primary channel has individual address setup timing registers
- * for each drive and the hardware selects the slowest timing itself.
- * The secondary channel has one common register and we have to select
- * the slowest address setup timing ourselves.
- */
- if (hwif->channel) {
- ide_drive_t *pair = ide_get_pair_dev(drive);
-
- if (pair) {
- struct ide_timing tp;
-
- ide_timing_compute(pair, pair->pio_mode, &tp, T, 0);
- ide_timing_merge(&t, &tp, &t, IDE_TIMING_SETUP);
- if (pair->dma_mode) {
- ide_timing_compute(pair, pair->dma_mode,
- &tp, T, 0);
- ide_timing_merge(&tp, &t, &t, IDE_TIMING_SETUP);
- }
- }
- }
-
- if (t.setup > 5) /* shouldn't actually happen... */
- t.setup = 5;
-
- /*
- * Program the address setup clocks into the ARTTIM registers.
- * Avoid clearing the secondary channel's interrupt bit.
- */
- (void) pci_read_config_byte (dev, arttim_regs[drive->dn], &arttim);
- if (hwif->channel)
- arttim &= ~ARTTIM23_INTR_CH1;
- arttim &= ~0xc0;
- arttim |= setup_values[t.setup];
- (void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim);
-}
-
-/*
- * Attempts to set drive's PIO mode.
- * Special cases are 8: prefetch off, 9: prefetch on (both never worked)
- */
-
-static void cmd64x_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- const u8 pio = drive->pio_mode - XFER_PIO_0;
-
- /*
- * Filter out the prefetch control values
- * to prevent PIO5 from being programmed
- */
- if (pio == 8 || pio == 9)
- return;
-
- cmd64x_program_timings(drive, XFER_PIO_0 + pio);
-}
-
-static void cmd64x_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 unit = drive->dn & 0x01;
- u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0;
- const u8 speed = drive->dma_mode;
-
- pci_read_config_byte(dev, pciU, &regU);
- regU &= ~(unit ? 0xCA : 0x35);
-
- switch(speed) {
- case XFER_UDMA_5:
- regU |= unit ? 0x0A : 0x05;
- break;
- case XFER_UDMA_4:
- regU |= unit ? 0x4A : 0x15;
- break;
- case XFER_UDMA_3:
- regU |= unit ? 0x8A : 0x25;
- break;
- case XFER_UDMA_2:
- regU |= unit ? 0x42 : 0x11;
- break;
- case XFER_UDMA_1:
- regU |= unit ? 0x82 : 0x21;
- break;
- case XFER_UDMA_0:
- regU |= unit ? 0xC2 : 0x31;
- break;
- case XFER_MW_DMA_2:
- case XFER_MW_DMA_1:
- case XFER_MW_DMA_0:
- cmd64x_program_timings(drive, speed);
- break;
- }
-
- pci_write_config_byte(dev, pciU, regU);
-}
-
-static void cmd648_clear_irq(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long base = pci_resource_start(dev, 4);
- u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 :
- MRDMODE_INTR_CH0;
- u8 mrdmode = inb(base + 1);
-
- /* clear the interrupt bit */
- outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask,
- base + 1);
-}
-
-static void cmd64x_clear_irq(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- int irq_reg = hwif->channel ? ARTTIM23 : CFR;
- u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 :
- CFR_INTR_CH0;
- u8 irq_stat = 0;
-
- (void) pci_read_config_byte(dev, irq_reg, &irq_stat);
- /* clear the interrupt bit */
- (void) pci_write_config_byte(dev, irq_reg, irq_stat | irq_mask);
-}
-
-static int cmd648_test_irq(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long base = pci_resource_start(dev, 4);
- u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 :
- MRDMODE_INTR_CH0;
- u8 mrdmode = inb(base + 1);
-
- pr_debug("%s: mrdmode: 0x%02x irq_mask: 0x%02x\n",
- hwif->name, mrdmode, irq_mask);
-
- return (mrdmode & irq_mask) ? 1 : 0;
-}
-
-static int cmd64x_test_irq(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- int irq_reg = hwif->channel ? ARTTIM23 : CFR;
- u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 :
- CFR_INTR_CH0;
- u8 irq_stat = 0;
-
- (void) pci_read_config_byte(dev, irq_reg, &irq_stat);
-
- pr_debug("%s: irq_stat: 0x%02x irq_mask: 0x%02x\n",
- hwif->name, irq_stat, irq_mask);
-
- return (irq_stat & irq_mask) ? 1 : 0;
-}
-
-/*
- * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
- * event order for DMA transfers.
- */
-
-static int cmd646_1_dma_end(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 dma_stat = 0, dma_cmd = 0;
-
- /* get DMA status */
- dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
- /* read DMA command state */
- dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
- /* stop DMA */
- outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
- /* clear the INTR & ERROR bits */
- outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
- /* verify good DMA status */
- return (dma_stat & 7) != 4;
-}
-
-static int init_chipset_cmd64x(struct pci_dev *dev)
-{
- u8 mrdmode = 0;
-
- /* Set a good latency timer and cache line size value. */
- (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
- /* FIXME: pci_set_master() to ensure a good latency timer value */
-
- /*
- * Enable interrupts, select MEMORY READ LINE for reads.
- *
- * NOTE: although not mentioned in the PCI0646U specs,
- * bits 0-1 are write only and won't be read back as
- * set or not -- PCI0646U2 specs clarify this point.
- */
- (void) pci_read_config_byte (dev, MRDMODE, &mrdmode);
- mrdmode &= ~0x30;
- (void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02));
-
- return 0;
-}
-
-static u8 cmd64x_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 bmidecsr = 0, mask = hwif->channel ? 0x02 : 0x01;
-
- switch (dev->device) {
- case PCI_DEVICE_ID_CMD_648:
- case PCI_DEVICE_ID_CMD_649:
- pci_read_config_byte(dev, BMIDECSR, &bmidecsr);
- return (bmidecsr & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
- default:
- return ATA_CBL_PATA40;
- }
-}
-
-static const struct ide_port_ops cmd64x_port_ops = {
- .set_pio_mode = cmd64x_set_pio_mode,
- .set_dma_mode = cmd64x_set_dma_mode,
- .clear_irq = cmd64x_clear_irq,
- .test_irq = cmd64x_test_irq,
- .cable_detect = cmd64x_cable_detect,
-};
-
-static const struct ide_port_ops cmd648_port_ops = {
- .set_pio_mode = cmd64x_set_pio_mode,
- .set_dma_mode = cmd64x_set_dma_mode,
- .clear_irq = cmd648_clear_irq,
- .test_irq = cmd648_test_irq,
- .cable_detect = cmd64x_cable_detect,
-};
-
-static const struct ide_dma_ops cmd646_rev1_dma_ops = {
- .dma_host_set = ide_dma_host_set,
- .dma_setup = ide_dma_setup,
- .dma_start = ide_dma_start,
- .dma_end = cmd646_1_dma_end,
- .dma_test_irq = ide_dma_test_irq,
- .dma_lost_irq = ide_dma_lost_irq,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_sff_read_status = ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info cmd64x_chipsets[] = {
- { /* 0: CMD643 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_cmd64x,
- .enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
- .port_ops = &cmd64x_port_ops,
- .host_flags = IDE_HFLAG_CLEAR_SIMPLEX |
- IDE_HFLAG_ABUSE_PREFETCH |
- IDE_HFLAG_SERIALIZE,
- .pio_mask = ATA_PIO5,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = 0x00, /* no udma */
- },
- { /* 1: CMD646 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_cmd64x,
- .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
- .port_ops = &cmd648_port_ops,
- .host_flags = IDE_HFLAG_ABUSE_PREFETCH |
- IDE_HFLAG_SERIALIZE,
- .pio_mask = ATA_PIO5,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA2,
- },
- { /* 2: CMD648 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_cmd64x,
- .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
- .port_ops = &cmd648_port_ops,
- .host_flags = IDE_HFLAG_ABUSE_PREFETCH,
- .pio_mask = ATA_PIO5,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA4,
- },
- { /* 3: CMD649 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_cmd64x,
- .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
- .port_ops = &cmd648_port_ops,
- .host_flags = IDE_HFLAG_ABUSE_PREFETCH,
- .pio_mask = ATA_PIO5,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA5,
- }
-};
-
-static int cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct ide_port_info d;
- u8 idx = id->driver_data;
-
- d = cmd64x_chipsets[idx];
-
- if (idx == 1) {
- /*
- * UltraDMA only supported on PCI646U and PCI646U2, which
- * correspond to revisions 0x03, 0x05 and 0x07 respectively.
- * Actually, although the CMD tech support people won't
- * tell me the details, the 0x03 revision cannot support
- * UDMA correctly without hardware modifications, and even
- * then it only works with Quantum disks due to some
- * hold time assumptions in the 646U part which are fixed
- * in the 646U2.
- *
- * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
- */
- if (dev->revision < 5) {
- d.udma_mask = 0x00;
- /*
- * The original PCI0646 didn't have the primary
- * channel enable bit, it appeared starting with
- * PCI0646U (i.e. revision ID 3).
- */
- if (dev->revision < 3) {
- d.enablebits[0].reg = 0;
- d.port_ops = &cmd64x_port_ops;
- if (dev->revision == 1)
- d.dma_ops = &cmd646_rev1_dma_ops;
- }
- }
- }
-
- return ide_pci_init_one(dev, &d, NULL);
-}
-
-static const struct pci_device_id cmd64x_pci_tbl[] = {
- { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
- { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 },
- { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 2 },
- { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 3 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl);
-
-static struct pci_driver cmd64x_pci_driver = {
- .name = "CMD64x_IDE",
- .id_table = cmd64x_pci_tbl,
- .probe = cmd64x_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init cmd64x_ide_init(void)
-{
- return ide_pci_register_driver(&cmd64x_pci_driver);
-}
-
-static void __exit cmd64x_ide_exit(void)
-{
- pci_unregister_driver(&cmd64x_pci_driver);
-}
-
-module_init(cmd64x_ide_init);
-module_exit(cmd64x_ide_exit);
-
-MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick, Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("PCI driver module for CMD64x IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cs5520.c b/drivers/ide/cs5520.c
deleted file mode 100644
index 89a4ff100b7a..000000000000
--- a/drivers/ide/cs5520.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * IDE tuning and bus mastering support for the CS5510/CS5520
- * chipsets
- *
- * The CS5510/CS5520 are slightly unusual devices. Unlike the
- * typical IDE controllers they do bus mastering with the drive in
- * PIO mode and smarter silicon.
- *
- * The practical upshot of this is that we must always tune the
- * drive for the right PIO mode. We must also ignore all the blacklists
- * and the drive bus mastering DMA information.
- *
- * *** This driver is strictly experimental ***
- *
- * (c) Copyright Red Hat Inc 2002
- *
- * 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, 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.
- *
- * For the avoidance of doubt the "preferred form" of this code is one which
- * is in an open non patent encumbered format. Where cryptographic key signing
- * forms part of the process of creating an executable the information
- * including keys needed to generate an equivalently functional executable
- * are deemed to be part of the source code.
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/dma-mapping.h>
-
-#define DRV_NAME "cs5520"
-
-struct pio_clocks
-{
- int address;
- int assert;
- int recovery;
-};
-
-static struct pio_clocks cs5520_pio_clocks[]={
- {3, 6, 11},
- {2, 5, 6},
- {1, 4, 3},
- {1, 3, 2},
- {1, 2, 1}
-};
-
-static void cs5520_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *pdev = to_pci_dev(hwif->dev);
- int controller = drive->dn > 1 ? 1 : 0;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
-
- /* 8bit CAT/CRT - 8bit command timing for channel */
- pci_write_config_byte(pdev, 0x62 + controller,
- (cs5520_pio_clocks[pio].recovery << 4) |
- (cs5520_pio_clocks[pio].assert));
-
- /* 0x64 - 16bit Primary, 0x68 - 16bit Secondary */
-
- /* FIXME: should these use address ? */
- /* Data read timing */
- pci_write_config_byte(pdev, 0x64 + 4*controller + (drive->dn&1),
- (cs5520_pio_clocks[pio].recovery << 4) |
- (cs5520_pio_clocks[pio].assert));
- /* Write command timing */
- pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1),
- (cs5520_pio_clocks[pio].recovery << 4) |
- (cs5520_pio_clocks[pio].assert));
-}
-
-static void cs5520_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- printk(KERN_ERR "cs55x0: bad ide timing.\n");
-
- drive->pio_mode = XFER_PIO_0 + 0;
- cs5520_set_pio_mode(hwif, drive);
-}
-
-static const struct ide_port_ops cs5520_port_ops = {
- .set_pio_mode = cs5520_set_pio_mode,
- .set_dma_mode = cs5520_set_dma_mode,
-};
-
-static const struct ide_port_info cyrix_chipset = {
- .name = DRV_NAME,
- .enablebits = { { 0x60, 0x01, 0x01 }, { 0x60, 0x02, 0x02 } },
- .port_ops = &cs5520_port_ops,
- .host_flags = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_CS5520,
- .pio_mask = ATA_PIO4,
-};
-
-/*
- * The 5510/5520 are a bit weird. They don't quite set up the way
- * the PCI helper layer expects so we must do much of the set up
- * work longhand.
- */
-
-static int cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- const struct ide_port_info *d = &cyrix_chipset;
- struct ide_hw hw[2], *hws[] = { NULL, NULL };
-
- ide_setup_pci_noise(dev, d);
-
- /* We must not grab the entire device, it has 'ISA' space in its
- * BARS too and we will freak out other bits of the kernel
- */
- if (pci_enable_device_io(dev)) {
- printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name);
- return -ENODEV;
- }
- pci_set_master(dev);
- if (dma_set_mask(&dev->dev, DMA_BIT_MASK(32))) {
- printk(KERN_WARNING "%s: No suitable DMA available.\n",
- d->name);
- return -ENODEV;
- }
-
- /*
- * Now the chipset is configured we can let the core
- * do all the device setup for us
- */
-
- ide_pci_setup_ports(dev, d, &hw[0], &hws[0]);
- hw[0].irq = 14;
- hw[1].irq = 15;
-
- return ide_host_add(d, hws, 2, NULL);
-}
-
-static const struct pci_device_id cs5520_pci_tbl[] = {
- { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), 0 },
- { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), 1 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl);
-
-static struct pci_driver cs5520_pci_driver = {
- .name = "Cyrix_IDE",
- .id_table = cs5520_pci_tbl,
- .probe = cs5520_init_one,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init cs5520_ide_init(void)
-{
- return ide_pci_register_driver(&cs5520_pci_driver);
-}
-
-module_init(cs5520_ide_init);
-
-MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("PCI driver module for Cyrix 5510/5520 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
deleted file mode 100644
index 65371599b976..000000000000
--- a/drivers/ide/cs5530.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2000 Mark Lord <mlord@pobox.com>
- * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- * Development of this chipset driver was funded
- * by the nice folks at National Semiconductor.
- *
- * Documentation:
- * CS5530 documentation available from National Semiconductor.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "cs5530"
-
-/*
- * Here are the standard PIO mode 0-4 timings for each "format".
- * Format-0 uses fast data reg timings, with slower command reg timings.
- * Format-1 uses fast timings for all registers, but won't work with all drives.
- */
-static unsigned int cs5530_pio_timings[2][5] = {
- {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
- {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}
-};
-
-/*
- * After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
- */
-#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
-#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
-
-/**
- * cs5530_set_pio_mode - set host controller for PIO mode
- * @hwif: port
- * @drive: drive
- *
- * Handles setting of PIO mode for the chipset.
- *
- * The init_hwif_cs5530() routine guarantees that all drives
- * will have valid default PIO timings set up before we get here.
- */
-
-static void cs5530_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- unsigned long basereg = CS5530_BASEREG(hwif);
- unsigned int format = (inl(basereg + 4) >> 31) & 1;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
-
- outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3));
-}
-
-/**
- * cs5530_udma_filter - UDMA filter
- * @drive: drive
- *
- * cs5530_udma_filter() does UDMA mask filtering for the given drive
- * taking into the consideration capabilities of the mate device.
- *
- * The CS5530 specifies that two drives sharing a cable cannot mix
- * UDMA/MDMA. It has to be one or the other, for the pair, though
- * different timings can still be chosen for each drive. We could
- * set the appropriate timing bits on the fly, but that might be
- * a bit confusing. So, for now we statically handle this requirement
- * by looking at our mate drive to see what it is capable of, before
- * choosing a mode for our own drive.
- *
- * Note: This relies on the fact we never fail from UDMA to MWDMA2
- * but instead drop to PIO.
- */
-
-static u8 cs5530_udma_filter(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- ide_drive_t *mate = ide_get_pair_dev(drive);
- u16 *mateid;
- u8 mask = hwif->ultra_mask;
-
- if (mate == NULL)
- goto out;
- mateid = mate->id;
-
- if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) {
- if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
- (mateid[ATA_ID_UDMA_MODES] & 7))
- goto out;
- if (mateid[ATA_ID_MWDMA_MODES] & 7)
- mask = 0;
- }
-out:
- return mask;
-}
-
-static void cs5530_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- unsigned long basereg;
- unsigned int reg, timings = 0;
-
- switch (drive->dma_mode) {
- case XFER_UDMA_0: timings = 0x00921250; break;
- case XFER_UDMA_1: timings = 0x00911140; break;
- case XFER_UDMA_2: timings = 0x00911030; break;
- case XFER_MW_DMA_0: timings = 0x00077771; break;
- case XFER_MW_DMA_1: timings = 0x00012121; break;
- case XFER_MW_DMA_2: timings = 0x00002020; break;
- }
- basereg = CS5530_BASEREG(hwif);
- reg = inl(basereg + 4); /* get drive0 config register */
- timings |= reg & 0x80000000; /* preserve PIO format bit */
- if ((drive-> dn & 1) == 0) { /* are we configuring drive0? */
- outl(timings, basereg + 4); /* write drive0 config register */
- } else {
- if (timings & 0x00100000)
- reg |= 0x00100000; /* enable UDMA timings for both drives */
- else
- reg &= ~0x00100000; /* disable UDMA timings for both drives */
- outl(reg, basereg + 4); /* write drive0 config register */
- outl(timings, basereg + 12); /* write drive1 config register */
- }
-}
-
-/**
- * init_chipset_5530 - set up 5530 bridge
- * @dev: PCI device
- *
- * Initialize the cs5530 bridge for reliable IDE DMA operation.
- */
-
-static int init_chipset_cs5530(struct pci_dev *dev)
-{
- struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
-
- if (pci_resource_start(dev, 4) == 0)
- return -EFAULT;
-
- dev = NULL;
- while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) {
- switch (dev->device) {
- case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
- master_0 = pci_dev_get(dev);
- break;
- case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
- cs5530_0 = pci_dev_get(dev);
- break;
- }
- }
- if (!master_0) {
- printk(KERN_ERR DRV_NAME ": unable to locate PCI MASTER function\n");
- goto out;
- }
- if (!cs5530_0) {
- printk(KERN_ERR DRV_NAME ": unable to locate CS5530 LEGACY function\n");
- goto out;
- }
-
- /*
- * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
- * --> OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530
- */
-
- pci_set_master(cs5530_0);
- pci_try_set_mwi(cs5530_0);
-
- /*
- * Set PCI CacheLineSize to 16-bytes:
- * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
- */
-
- pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04);
-
- /*
- * Disable trapping of UDMA register accesses (Win98 hack):
- * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530
- */
-
- pci_write_config_word(cs5530_0, 0xd0, 0x5006);
-
- /*
- * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus:
- * The other settings are what is necessary to get the register
- * into a sane state for IDE DMA operation.
- */
-
- pci_write_config_byte(master_0, 0x40, 0x1e);
-
- /*
- * Set max PCI burst size (16-bytes seems to work best):
- * 16bytes: set bit-1 at 0x41 (reg value of 0x16)
- * all others: clear bit-1 at 0x41, and do:
- * 128bytes: OR 0x00 at 0x41
- * 256bytes: OR 0x04 at 0x41
- * 512bytes: OR 0x08 at 0x41
- * 1024bytes: OR 0x0c at 0x41
- */
-
- pci_write_config_byte(master_0, 0x41, 0x14);
-
- /*
- * These settings are necessary to get the chip
- * into a sane state for IDE DMA operation.
- */
-
- pci_write_config_byte(master_0, 0x42, 0x00);
- pci_write_config_byte(master_0, 0x43, 0xc1);
-
-out:
- pci_dev_put(master_0);
- pci_dev_put(cs5530_0);
- return 0;
-}
-
-/**
- * init_hwif_cs5530 - initialise an IDE channel
- * @hwif: IDE to initialize
- *
- * This gets invoked by the IDE driver once for each channel. It
- * performs channel-specific pre-initialization before drive probing.
- */
-
-static void init_hwif_cs5530 (ide_hwif_t *hwif)
-{
- unsigned long basereg;
- u32 d0_timings;
-
- basereg = CS5530_BASEREG(hwif);
- d0_timings = inl(basereg + 0);
- if (CS5530_BAD_PIO(d0_timings))
- outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 0);
- if (CS5530_BAD_PIO(inl(basereg + 8)))
- outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 8);
-}
-
-static const struct ide_port_ops cs5530_port_ops = {
- .set_pio_mode = cs5530_set_pio_mode,
- .set_dma_mode = cs5530_set_dma_mode,
- .udma_filter = cs5530_udma_filter,
-};
-
-static const struct ide_port_info cs5530_chipset = {
- .name = DRV_NAME,
- .init_chipset = init_chipset_cs5530,
- .init_hwif = init_hwif_cs5530,
- .port_ops = &cs5530_port_ops,
- .host_flags = IDE_HFLAG_SERIALIZE |
- IDE_HFLAG_POST_SET_MODE,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA2,
-};
-
-static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- return ide_pci_init_one(dev, &cs5530_chipset, NULL);
-}
-
-static const struct pci_device_id cs5530_pci_tbl[] = {
- { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), 0 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, cs5530_pci_tbl);
-
-static struct pci_driver cs5530_pci_driver = {
- .name = "CS5530 IDE",
- .id_table = cs5530_pci_tbl,
- .probe = cs5530_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init cs5530_ide_init(void)
-{
- return ide_pci_register_driver(&cs5530_pci_driver);
-}
-
-static void __exit cs5530_ide_exit(void)
-{
- pci_unregister_driver(&cs5530_pci_driver);
-}
-
-module_init(cs5530_ide_init);
-module_exit(cs5530_ide_exit);
-
-MODULE_AUTHOR("Mark Lord");
-MODULE_DESCRIPTION("PCI driver module for Cyrix/NS 5530 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cs5535.c b/drivers/ide/cs5535.c
deleted file mode 100644
index 70fdbe3161f8..000000000000
--- a/drivers/ide/cs5535.c
+++ /dev/null
@@ -1,216 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2004-2005 Advanced Micro Devices, Inc.
- * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
- *
- * History:
- * 09/20/2005 - Jaya Kumar <jayakumar.ide@gmail.com>
- * - Reworked tuneproc, set_drive, misc mods to prep for mainline
- * - Work was sponsored by CIS (M) Sdn Bhd.
- * Ported to Kernel 2.6.11 on June 26, 2005 by
- * Wolfgang Zuleger <wolfgang.zuleger@gmx.de>
- * Alexander Kiausch <alex.kiausch@t-online.de>
- * Originally developed by AMD for 2.4/2.6
- *
- * Development of this chipset driver was funded
- * by the nice folks at National Semiconductor/AMD.
- *
- * Documentation:
- * CS5535 documentation available from AMD
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#define DRV_NAME "cs5535"
-
-#define MSR_ATAC_BASE 0x51300000
-#define ATAC_GLD_MSR_CAP (MSR_ATAC_BASE+0)
-#define ATAC_GLD_MSR_CONFIG (MSR_ATAC_BASE+0x01)
-#define ATAC_GLD_MSR_SMI (MSR_ATAC_BASE+0x02)
-#define ATAC_GLD_MSR_ERROR (MSR_ATAC_BASE+0x03)
-#define ATAC_GLD_MSR_PM (MSR_ATAC_BASE+0x04)
-#define ATAC_GLD_MSR_DIAG (MSR_ATAC_BASE+0x05)
-#define ATAC_IO_BAR (MSR_ATAC_BASE+0x08)
-#define ATAC_RESET (MSR_ATAC_BASE+0x10)
-#define ATAC_CH0D0_PIO (MSR_ATAC_BASE+0x20)
-#define ATAC_CH0D0_DMA (MSR_ATAC_BASE+0x21)
-#define ATAC_CH0D1_PIO (MSR_ATAC_BASE+0x22)
-#define ATAC_CH0D1_DMA (MSR_ATAC_BASE+0x23)
-#define ATAC_PCI_ABRTERR (MSR_ATAC_BASE+0x24)
-#define ATAC_BM0_CMD_PRIM 0x00
-#define ATAC_BM0_STS_PRIM 0x02
-#define ATAC_BM0_PRD 0x04
-#define CS5535_CABLE_DETECT 0x48
-
-/* Format I PIO settings. We separate out cmd and data for safer timings */
-
-static unsigned int cs5535_pio_cmd_timings[5] =
-{ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131 };
-static unsigned int cs5535_pio_dta_timings[5] =
-{ 0xF7F4, 0xF173, 0x8141, 0x5131, 0x1131 };
-
-static unsigned int cs5535_mwdma_timings[3] =
-{ 0x7F0FFFF3, 0x7F035352, 0x7f024241 };
-
-static unsigned int cs5535_udma_timings[5] =
-{ 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061 };
-
-/* Macros to check if the register is the reset value - reset value is an
- invalid timing and indicates the register has not been set previously */
-
-#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL) == 0x00009172 )
-#define CS5535_BAD_DMA(timings) ( (timings & 0x000FFFFF) == 0x00077771 )
-
-/****
- * cs5535_set_speed - Configure the chipset to the new speed
- * @drive: Drive to set up
- * @speed: desired speed
- *
- * cs5535_set_speed() configures the chipset to a new speed.
- */
-static void cs5535_set_speed(ide_drive_t *drive, const u8 speed)
-{
- u32 reg = 0, dummy;
- u8 unit = drive->dn & 1;
-
- /* Set the PIO timings */
- if (speed < XFER_SW_DMA_0) {
- ide_drive_t *pair = ide_get_pair_dev(drive);
- u8 cmd, pioa;
-
- cmd = pioa = speed - XFER_PIO_0;
-
- if (pair) {
- u8 piob = pair->pio_mode - XFER_PIO_0;
-
- if (piob < cmd)
- cmd = piob;
- }
-
- /* Write the speed of the current drive */
- reg = (cs5535_pio_cmd_timings[cmd] << 16) |
- cs5535_pio_dta_timings[pioa];
- wrmsr(unit ? ATAC_CH0D1_PIO : ATAC_CH0D0_PIO, reg, 0);
-
- /* And if nessesary - change the speed of the other drive */
- rdmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, dummy);
-
- if (((reg >> 16) & cs5535_pio_cmd_timings[cmd]) !=
- cs5535_pio_cmd_timings[cmd]) {
- reg &= 0x0000FFFF;
- reg |= cs5535_pio_cmd_timings[cmd] << 16;
- wrmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, 0);
- }
-
- /* Set bit 31 of the DMA register for PIO format 1 timings */
- rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy);
- wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA,
- reg | 0x80000000UL, 0);
- } else {
- rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy);
-
- reg &= 0x80000000UL; /* Preserve the PIO format bit */
-
- if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_4)
- reg |= cs5535_udma_timings[speed - XFER_UDMA_0];
- else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
- reg |= cs5535_mwdma_timings[speed - XFER_MW_DMA_0];
- else
- return;
-
- wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, 0);
- }
-}
-
-/**
- * cs5535_set_dma_mode - set host controller for DMA mode
- * @hwif: port
- * @drive: drive
- *
- * Programs the chipset for DMA mode.
- */
-
-static void cs5535_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- cs5535_set_speed(drive, drive->dma_mode);
-}
-
-/**
- * cs5535_set_pio_mode - set host controller for PIO mode
- * @hwif: port
- * @drive: drive
- *
- * A callback from the upper layers for PIO-only tuning.
- */
-
-static void cs5535_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- cs5535_set_speed(drive, drive->pio_mode);
-}
-
-static u8 cs5535_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 bit;
-
- /* if a 80 wire cable was detected */
- pci_read_config_byte(dev, CS5535_CABLE_DETECT, &bit);
-
- return (bit & 1) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
-}
-
-static const struct ide_port_ops cs5535_port_ops = {
- .set_pio_mode = cs5535_set_pio_mode,
- .set_dma_mode = cs5535_set_dma_mode,
- .cable_detect = cs5535_cable_detect,
-};
-
-static const struct ide_port_info cs5535_chipset = {
- .name = DRV_NAME,
- .port_ops = &cs5535_port_ops,
- .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA4,
-};
-
-static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- return ide_pci_init_one(dev, &cs5535_chipset, NULL);
-}
-
-static const struct pci_device_id cs5535_pci_tbl[] = {
- { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_CS5535_IDE), 0 },
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5535_IDE), },
- { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, cs5535_pci_tbl);
-
-static struct pci_driver cs5535_pci_driver = {
- .name = "CS5535_IDE",
- .id_table = cs5535_pci_tbl,
- .probe = cs5535_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init cs5535_ide_init(void)
-{
- return ide_pci_register_driver(&cs5535_pci_driver);
-}
-
-static void __exit cs5535_ide_exit(void)
-{
- pci_unregister_driver(&cs5535_pci_driver);
-}
-
-module_init(cs5535_ide_init);
-module_exit(cs5535_ide_exit);
-
-MODULE_AUTHOR("AMD");
-MODULE_DESCRIPTION("PCI driver module for AMD/NS CS5535 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cs5536.c b/drivers/ide/cs5536.c
deleted file mode 100644
index 8b5ca145191b..000000000000
--- a/drivers/ide/cs5536.c
+++ /dev/null
@@ -1,294 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * CS5536 PATA support
- * (C) 2007 Martin K. Petersen <mkp@mkp.net>
- * (C) 2009 Bartlomiej Zolnierkiewicz
- *
- * Documentation:
- * Available from AMD web site.
- *
- * The IDE timing registers for the CS5536 live in the Geode Machine
- * Specific Register file and not PCI config space. Most BIOSes
- * virtualize the PCI registers so the chip looks like a standard IDE
- * controller. Unfortunately not all implementations get this right.
- * In particular some have problems with unaligned accesses to the
- * virtualized PCI registers. This driver always does full dword
- * writes to work around the issue. Also, in case of a bad BIOS this
- * driver can be loaded with the "msr=1" parameter which forces using
- * the Machine Specific Registers to configure the device.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <asm/msr.h>
-
-#define DRV_NAME "cs5536"
-
-enum {
- MSR_IDE_CFG = 0x51300010,
- PCI_IDE_CFG = 0x40,
-
- CFG = 0,
- DTC = 2,
- CAST = 3,
- ETC = 4,
-
- IDE_CFG_CHANEN = (1 << 1),
- IDE_CFG_CABLE = (1 << 17) | (1 << 16),
-
- IDE_D0_SHIFT = 24,
- IDE_D1_SHIFT = 16,
- IDE_DRV_MASK = 0xff,
-
- IDE_CAST_D0_SHIFT = 6,
- IDE_CAST_D1_SHIFT = 4,
- IDE_CAST_DRV_MASK = 0x3,
-
- IDE_CAST_CMD_SHIFT = 24,
- IDE_CAST_CMD_MASK = 0xff,
-
- IDE_ETC_UDMA_MASK = 0xc0,
-};
-
-static int use_msr;
-
-static int cs5536_read(struct pci_dev *pdev, int reg, u32 *val)
-{
- if (unlikely(use_msr)) {
- u32 dummy;
-
- rdmsr(MSR_IDE_CFG + reg, *val, dummy);
- return 0;
- }
-
- return pci_read_config_dword(pdev, PCI_IDE_CFG + reg * 4, val);
-}
-
-static int cs5536_write(struct pci_dev *pdev, int reg, int val)
-{
- if (unlikely(use_msr)) {
- wrmsr(MSR_IDE_CFG + reg, val, 0);
- return 0;
- }
-
- return pci_write_config_dword(pdev, PCI_IDE_CFG + reg * 4, val);
-}
-
-static void cs5536_program_dtc(ide_drive_t *drive, u8 tim)
-{
- struct pci_dev *pdev = to_pci_dev(drive->hwif->dev);
- int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT;
- u32 dtc;
-
- cs5536_read(pdev, DTC, &dtc);
- dtc &= ~(IDE_DRV_MASK << dshift);
- dtc |= tim << dshift;
- cs5536_write(pdev, DTC, dtc);
-}
-
-/**
- * cs5536_cable_detect - detect cable type
- * @hwif: Port to detect on
- *
- * Perform cable detection for ATA66 capable cable.
- *
- * Returns a cable type.
- */
-
-static u8 cs5536_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *pdev = to_pci_dev(hwif->dev);
- u32 cfg;
-
- cs5536_read(pdev, CFG, &cfg);
-
- if (cfg & IDE_CFG_CABLE)
- return ATA_CBL_PATA80;
- else
- return ATA_CBL_PATA40;
-}
-
-/**
- * cs5536_set_pio_mode - PIO timing setup
- * @hwif: ATA port
- * @drive: ATA device
- */
-
-static void cs5536_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- static const u8 drv_timings[5] = {
- 0x98, 0x55, 0x32, 0x21, 0x20,
- };
-
- static const u8 addr_timings[5] = {
- 0x2, 0x1, 0x0, 0x0, 0x0,
- };
-
- static const u8 cmd_timings[5] = {
- 0x99, 0x92, 0x90, 0x22, 0x20,
- };
-
- struct pci_dev *pdev = to_pci_dev(hwif->dev);
- ide_drive_t *pair = ide_get_pair_dev(drive);
- int cshift = (drive->dn & 1) ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT;
- unsigned long timings = (unsigned long)ide_get_drivedata(drive);
- u32 cast;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
- u8 cmd_pio = pio;
-
- if (pair)
- cmd_pio = min_t(u8, pio, pair->pio_mode - XFER_PIO_0);
-
- timings &= (IDE_DRV_MASK << 8);
- timings |= drv_timings[pio];
- ide_set_drivedata(drive, (void *)timings);
-
- cs5536_program_dtc(drive, drv_timings[pio]);
-
- cs5536_read(pdev, CAST, &cast);
-
- cast &= ~(IDE_CAST_DRV_MASK << cshift);
- cast |= addr_timings[pio] << cshift;
-
- cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT);
- cast |= cmd_timings[cmd_pio] << IDE_CAST_CMD_SHIFT;
-
- cs5536_write(pdev, CAST, cast);
-}
-
-/**
- * cs5536_set_dma_mode - DMA timing setup
- * @hwif: ATA port
- * @drive: ATA device
- */
-
-static void cs5536_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- static const u8 udma_timings[6] = {
- 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6,
- };
-
- static const u8 mwdma_timings[3] = {
- 0x67, 0x21, 0x20,
- };
-
- struct pci_dev *pdev = to_pci_dev(hwif->dev);
- int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT;
- unsigned long timings = (unsigned long)ide_get_drivedata(drive);
- u32 etc;
- const u8 mode = drive->dma_mode;
-
- cs5536_read(pdev, ETC, &etc);
-
- if (mode >= XFER_UDMA_0) {
- etc &= ~(IDE_DRV_MASK << dshift);
- etc |= udma_timings[mode - XFER_UDMA_0] << dshift;
- } else { /* MWDMA */
- etc &= ~(IDE_ETC_UDMA_MASK << dshift);
- timings &= IDE_DRV_MASK;
- timings |= mwdma_timings[mode - XFER_MW_DMA_0] << 8;
- ide_set_drivedata(drive, (void *)timings);
- }
-
- cs5536_write(pdev, ETC, etc);
-}
-
-static void cs5536_dma_start(ide_drive_t *drive)
-{
- unsigned long timings = (unsigned long)ide_get_drivedata(drive);
-
- if (drive->current_speed < XFER_UDMA_0 &&
- (timings >> 8) != (timings & IDE_DRV_MASK))
- cs5536_program_dtc(drive, timings >> 8);
-
- ide_dma_start(drive);
-}
-
-static int cs5536_dma_end(ide_drive_t *drive)
-{
- int ret = ide_dma_end(drive);
- unsigned long timings = (unsigned long)ide_get_drivedata(drive);
-
- if (drive->current_speed < XFER_UDMA_0 &&
- (timings >> 8) != (timings & IDE_DRV_MASK))
- cs5536_program_dtc(drive, timings & IDE_DRV_MASK);
-
- return ret;
-}
-
-static const struct ide_port_ops cs5536_port_ops = {
- .set_pio_mode = cs5536_set_pio_mode,
- .set_dma_mode = cs5536_set_dma_mode,
- .cable_detect = cs5536_cable_detect,
-};
-
-static const struct ide_dma_ops cs5536_dma_ops = {
- .dma_host_set = ide_dma_host_set,
- .dma_setup = ide_dma_setup,
- .dma_start = cs5536_dma_start,
- .dma_end = cs5536_dma_end,
- .dma_test_irq = ide_dma_test_irq,
- .dma_lost_irq = ide_dma_lost_irq,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_sff_read_status = ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info cs5536_info = {
- .name = DRV_NAME,
- .port_ops = &cs5536_port_ops,
- .dma_ops = &cs5536_dma_ops,
- .host_flags = IDE_HFLAG_SINGLE,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA5,
-};
-
-/**
- * cs5536_init_one
- * @dev: PCI device
- * @id: Entry in match table
- */
-
-static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- u32 cfg;
-
- if (use_msr)
- printk(KERN_INFO DRV_NAME ": Using MSR regs instead of PCI\n");
-
- cs5536_read(dev, CFG, &cfg);
-
- if ((cfg & IDE_CFG_CHANEN) == 0) {
- printk(KERN_ERR DRV_NAME ": disabled by BIOS\n");
- return -ENODEV;
- }
-
- return ide_pci_init_one(dev, &cs5536_info, NULL);
-}
-
-static const struct pci_device_id cs5536_pci_tbl[] = {
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), },
- { },
-};
-
-static struct pci_driver cs5536_pci_driver = {
- .name = DRV_NAME,
- .id_table = cs5536_pci_tbl,
- .probe = cs5536_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-module_pci_driver(cs5536_pci_driver);
-
-MODULE_AUTHOR("Martin K. Petersen, Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, cs5536_pci_tbl);
-
-module_param_named(msr, use_msr, int, 0644);
-MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
deleted file mode 100644
index bc01660ee8fd..000000000000
--- a/drivers/ide/cy82c693.c
+++ /dev/null
@@ -1,234 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
- * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator
- * Copyright (C) 2007-2011 Bartlomiej Zolnierkiewicz
- *
- * CYPRESS CY82C693 chipset IDE controller
- *
- * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "cy82c693"
-
-/*
- * NOTE: the value for busmaster timeout is tricky and I got it by
- * trial and error! By using a to low value will cause DMA timeouts
- * and drop IDE performance, and by using a to high value will cause
- * audio playback to scatter.
- * If you know a better value or how to calc it, please let me know.
- */
-
-/* twice the value written in cy82c693ub datasheet */
-#define BUSMASTER_TIMEOUT 0x50
-/*
- * the value above was tested on my machine and it seems to work okay
- */
-
-/* here are the offset definitions for the registers */
-#define CY82_IDE_CMDREG 0x04
-#define CY82_IDE_ADDRSETUP 0x48
-#define CY82_IDE_MASTER_IOR 0x4C
-#define CY82_IDE_MASTER_IOW 0x4D
-#define CY82_IDE_SLAVE_IOR 0x4E
-#define CY82_IDE_SLAVE_IOW 0x4F
-#define CY82_IDE_MASTER_8BIT 0x50
-#define CY82_IDE_SLAVE_8BIT 0x51
-
-#define CY82_INDEX_PORT 0x22
-#define CY82_DATA_PORT 0x23
-
-#define CY82_INDEX_CHANNEL0 0x30
-#define CY82_INDEX_CHANNEL1 0x31
-#define CY82_INDEX_TIMEOUT 0x32
-
-/*
- * set DMA mode a specific channel for CY82C693
- */
-
-static void cy82c693_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- const u8 mode = drive->dma_mode;
- u8 single = (mode & 0x10) >> 4, index = 0, data = 0;
-
- index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0;
-
- data = (mode & 3) | (single << 2);
-
- outb(index, CY82_INDEX_PORT);
- outb(data, CY82_DATA_PORT);
-
- /*
- * note: below we set the value for Bus Master IDE TimeOut Register
- * I'm not absolutely sure what this does, but it solved my problem
- * with IDE DMA and sound, so I now can play sound and work with
- * my IDE driver at the same time :-)
- *
- * If you know the correct (best) value for this register please
- * let me know - ASK
- */
-
- data = BUSMASTER_TIMEOUT;
- outb(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
- outb(data, CY82_DATA_PORT);
-}
-
-static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
- const unsigned long T = 1000000 / bus_speed;
- unsigned int addrCtrl;
- struct ide_timing t;
- u8 time_16, time_8;
-
- /* select primary or secondary channel */
- if (drive->dn > 1) { /* drive is on the secondary channel */
- dev = pci_get_slot(dev->bus, dev->devfn+1);
- if (!dev) {
- printk(KERN_ERR "%s: tune_drive: "
- "Cannot find secondary interface!\n",
- drive->name);
- return;
- }
- }
-
- ide_timing_compute(drive, drive->pio_mode, &t, T, 1);
-
- time_16 = clamp_val(t.recover - 1, 0, 15) |
- (clamp_val(t.active - 1, 0, 15) << 4);
- time_8 = clamp_val(t.act8b - 1, 0, 15) |
- (clamp_val(t.rec8b - 1, 0, 15) << 4);
-
- /* now let's write the clocks registers */
- if ((drive->dn & 1) == 0) {
- /*
- * set master drive
- * address setup control register
- * is 32 bit !!!
- */
- pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
- addrCtrl &= (~0xF);
- addrCtrl |= clamp_val(t.setup - 1, 0, 15);
- pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
-
- /* now let's set the remaining registers */
- pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, time_16);
- pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, time_16);
- pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, time_8);
- } else {
- /*
- * set slave drive
- * address setup control register
- * is 32 bit !!!
- */
- pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
- addrCtrl &= (~0xF0);
- addrCtrl |= (clamp_val(t.setup - 1, 0, 15) << 4);
- pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
-
- /* now let's set the remaining registers */
- pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, time_16);
- pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, time_16);
- pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, time_8);
- }
- if (drive->dn > 1)
- pci_dev_put(dev);
-}
-
-static void init_iops_cy82c693(ide_hwif_t *hwif)
-{
- static ide_hwif_t *primary;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
-
- if (PCI_FUNC(dev->devfn) == 1)
- primary = hwif;
- else {
- hwif->mate = primary;
- hwif->channel = 1;
- }
-}
-
-static const struct ide_port_ops cy82c693_port_ops = {
- .set_pio_mode = cy82c693_set_pio_mode,
- .set_dma_mode = cy82c693_set_dma_mode,
-};
-
-static const struct ide_port_info cy82c693_chipset = {
- .name = DRV_NAME,
- .init_iops = init_iops_cy82c693,
- .port_ops = &cy82c693_port_ops,
- .host_flags = IDE_HFLAG_SINGLE,
- .pio_mask = ATA_PIO4,
- .swdma_mask = ATA_SWDMA2,
- .mwdma_mask = ATA_MWDMA2,
-};
-
-static int cy82c693_init_one(struct pci_dev *dev,
- const struct pci_device_id *id)
-{
- struct pci_dev *dev2;
- int ret = -ENODEV;
-
- /* CY82C693 is more than only a IDE controller.
- Function 1 is primary IDE channel, function 2 - secondary. */
- if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
- PCI_FUNC(dev->devfn) == 1) {
- dev2 = pci_get_slot(dev->bus, dev->devfn + 1);
- ret = ide_pci_init_two(dev, dev2, &cy82c693_chipset, NULL);
- if (ret)
- pci_dev_put(dev2);
- }
- return ret;
-}
-
-static void cy82c693_remove(struct pci_dev *dev)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
-
- ide_pci_remove(dev);
- pci_dev_put(dev2);
-}
-
-static const struct pci_device_id cy82c693_pci_tbl[] = {
- { PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), 0 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl);
-
-static struct pci_driver cy82c693_pci_driver = {
- .name = "Cypress_IDE",
- .id_table = cy82c693_pci_tbl,
- .probe = cy82c693_init_one,
- .remove = cy82c693_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init cy82c693_ide_init(void)
-{
- return ide_pci_register_driver(&cy82c693_pci_driver);
-}
-
-static void __exit cy82c693_ide_exit(void)
-{
- pci_unregister_driver(&cy82c693_pci_driver);
-}
-
-module_init(cy82c693_ide_init);
-module_exit(cy82c693_ide_exit);
-
-MODULE_AUTHOR("Andreas Krebs, Andre Hedrick, Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/delkin_cb.c b/drivers/ide/delkin_cb.c
deleted file mode 100644
index 300daabaa575..000000000000
--- a/drivers/ide/delkin_cb.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Created 20 Oct 2004 by Mark Lord
- *
- * Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter
- *
- * Modeled after the 16-bit PCMCIA driver: ide-cs.c
- *
- * This is slightly peculiar, in that it is a PCI driver,
- * but is NOT an IDE PCI driver -- the IDE layer does not directly
- * support hot insertion/removal of PCI interfaces, so this driver
- * is unable to use the IDE PCI interfaces. Instead, it uses the
- * same interfaces as the ide-cs (PCMCIA) driver uses.
- * On the plus side, the driver is also smaller/simpler this way.
- *
- * 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.
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-
-#include <asm/io.h>
-
-/*
- * No chip documentation has yet been found,
- * so these configuration values were pulled from
- * a running Win98 system using "debug".
- * This gives around 3MByte/second read performance,
- * which is about 2/3 of what the chip is capable of.
- *
- * There is also a 4KByte mmio region on the card,
- * but its purpose has yet to be reverse-engineered.
- */
-static const u8 setup[] = {
- 0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00,
- 0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13,
-};
-
-static const struct ide_port_ops delkin_cb_port_ops = {
- .quirkproc = ide_undecoded_slave,
-};
-
-static int delkin_cb_init_chipset(struct pci_dev *dev)
-{
- unsigned long base = pci_resource_start(dev, 0);
- int i;
-
- outb(0x02, base + 0x1e); /* set nIEN to block interrupts */
- inb(base + 0x17); /* read status to clear interrupts */
-
- for (i = 0; i < sizeof(setup); ++i) {
- if (setup[i])
- outb(setup[i], base + i);
- }
-
- return 0;
-}
-
-static const struct ide_port_info delkin_cb_port_info = {
- .port_ops = &delkin_cb_port_ops,
- .host_flags = IDE_HFLAG_IO_32BIT | IDE_HFLAG_UNMASK_IRQS |
- IDE_HFLAG_NO_DMA,
- .irq_flags = IRQF_SHARED,
- .init_chipset = delkin_cb_init_chipset,
- .chipset = ide_pci,
-};
-
-static int delkin_cb_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct ide_host *host;
- unsigned long base;
- int rc;
- struct ide_hw hw, *hws[] = { &hw };
-
- rc = pci_enable_device(dev);
- if (rc) {
- printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc);
- return rc;
- }
- rc = pci_request_regions(dev, "delkin_cb");
- if (rc) {
- printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc);
- pci_disable_device(dev);
- return rc;
- }
- base = pci_resource_start(dev, 0);
-
- delkin_cb_init_chipset(dev);
-
- memset(&hw, 0, sizeof(hw));
- ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
- hw.irq = dev->irq;
- hw.dev = &dev->dev;
-
- rc = ide_host_add(&delkin_cb_port_info, hws, 1, &host);
- if (rc)
- goto out_disable;
-
- pci_set_drvdata(dev, host);
-
- return 0;
-
-out_disable:
- pci_release_regions(dev);
- pci_disable_device(dev);
- return rc;
-}
-
-static void
-delkin_cb_remove (struct pci_dev *dev)
-{
- struct ide_host *host = pci_get_drvdata(dev);
-
- ide_host_remove(host);
-
- pci_release_regions(dev);
- pci_disable_device(dev);
-}
-
-#ifdef CONFIG_PM
-static int delkin_cb_suspend(struct pci_dev *dev, pm_message_t state)
-{
- pci_save_state(dev);
- pci_disable_device(dev);
- pci_set_power_state(dev, pci_choose_state(dev, state));
-
- return 0;
-}
-
-static int delkin_cb_resume(struct pci_dev *dev)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- int rc;
-
- pci_set_power_state(dev, PCI_D0);
-
- rc = pci_enable_device(dev);
- if (rc)
- return rc;
-
- pci_restore_state(dev);
- pci_set_master(dev);
-
- if (host->init_chipset)
- host->init_chipset(dev);
-
- return 0;
-}
-#else
-#define delkin_cb_suspend NULL
-#define delkin_cb_resume NULL
-#endif
-
-static struct pci_device_id delkin_cb_pci_tbl[] = {
- { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { 0x1145, 0xf024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl);
-
-static struct pci_driver delkin_cb_pci_driver = {
- .name = "Delkin-ASKA-Workbit Cardbus IDE",
- .id_table = delkin_cb_pci_tbl,
- .probe = delkin_cb_probe,
- .remove = delkin_cb_remove,
- .suspend = delkin_cb_suspend,
- .resume = delkin_cb_resume,
-};
-
-module_pci_driver(delkin_cb_pci_driver);
-
-MODULE_AUTHOR("Mark Lord");
-MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c
deleted file mode 100644
index 714e8cd0fa49..000000000000
--- a/drivers/ide/dtc2278.c
+++ /dev/null
@@ -1,155 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1996 Linus Torvalds & author (see below)
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "dtc2278"
-
-/*
- * Changing this #undef to #define may solve start up problems in some systems.
- */
-#undef ALWAYS_SET_DTC2278_PIO_MODE
-
-/*
- * From: andy@cercle.cts.com (Dyan Wile)
- *
- * Below is a patch for DTC-2278 - alike software-programmable controllers
- * The code enables the secondary IDE controller and the PIO4 (3?) timings on
- * the primary (EIDE). You may probably have to enable the 32-bit support to
- * get the full speed. You better get the disk interrupts disabled ( hdparm -u0
- * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
- * filesystem corrupted with -u1, but under heavy disk load only :-)
- *
- * This card is now forced to use the "serialize" feature,
- * and irq-unmasking is disallowed. If io_32bit is enabled,
- * it must be done for BOTH drives on each interface.
- *
- * This code was written for the DTC2278E, but might work with any of these:
- *
- * DTC2278S has only a single IDE interface.
- * DTC2278D has two IDE interfaces and is otherwise identical to the S version.
- * DTC2278E also has serial ports and a printer port
- * DTC2278EB: has onboard BIOS, and "works like a charm" -- Kent Bradford <kent@theory.caltech.edu>
- *
- * There may be a fourth controller type. The S and D versions use the
- * Winbond chip, and I think the E version does also.
- *
- */
-
-static void sub22 (char b, char c)
-{
- int i;
-
- for(i = 0; i < 3; ++i) {
- inb(0x3f6);
- outb_p(b,0xb0);
- inb(0x3f6);
- outb_p(c,0xb4);
- inb(0x3f6);
- if(inb(0xb4) == c) {
- outb_p(7,0xb0);
- inb(0x3f6);
- return; /* success */
- }
- }
-}
-
-static DEFINE_SPINLOCK(dtc2278_lock);
-
-static void dtc2278_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- unsigned long flags;
-
- if (drive->pio_mode >= XFER_PIO_3) {
- spin_lock_irqsave(&dtc2278_lock, flags);
- /*
- * This enables PIO mode4 (3?) on the first interface
- */
- sub22(1,0xc3);
- sub22(0,0xa0);
- spin_unlock_irqrestore(&dtc2278_lock, flags);
- } else {
- /* we don't know how to set it back again.. */
- /* Actually we do - there is a data sheet available for the
- Winbond but does anyone actually care */
- }
-}
-
-static const struct ide_port_ops dtc2278_port_ops = {
- .set_pio_mode = dtc2278_set_pio_mode,
-};
-
-static const struct ide_port_info dtc2278_port_info __initconst = {
- .name = DRV_NAME,
- .chipset = ide_dtc2278,
- .port_ops = &dtc2278_port_ops,
- .host_flags = IDE_HFLAG_SERIALIZE |
- IDE_HFLAG_NO_UNMASK_IRQS |
- IDE_HFLAG_IO_32BIT |
- /* disallow ->io_32bit changes */
- IDE_HFLAG_NO_IO_32BIT |
- IDE_HFLAG_NO_DMA |
- IDE_HFLAG_DTC2278,
- .pio_mask = ATA_PIO4,
-};
-
-static int __init dtc2278_probe(void)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- /*
- * This enables the second interface
- */
- outb_p(4,0xb0);
- inb(0x3f6);
- outb_p(0x20,0xb4);
- inb(0x3f6);
-#ifdef ALWAYS_SET_DTC2278_PIO_MODE
- /*
- * This enables PIO mode4 (3?) on the first interface
- * and may solve start-up problems for some people.
- */
- sub22(1,0xc3);
- sub22(0,0xa0);
-#endif
- local_irq_restore(flags);
-
- return ide_legacy_device_add(&dtc2278_port_info, 0);
-}
-
-static bool probe_dtc2278;
-
-module_param_named(probe, probe_dtc2278, bool, 0);
-MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets");
-
-static int __init dtc2278_init(void)
-{
- if (probe_dtc2278 == 0)
- return -ENODEV;
-
- if (dtc2278_probe()) {
- printk(KERN_ERR "dtc2278: ide interfaces already in use!\n");
- return -EBUSY;
- }
- return 0;
-}
-
-module_init(dtc2278_init);
-
-MODULE_AUTHOR("See Local File");
-MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/falconide.c b/drivers/ide/falconide.c
deleted file mode 100644
index bb86d84558d9..000000000000
--- a/drivers/ide/falconide.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Atari Falcon IDE Driver
- *
- * Created 12 Jul 1997 by Geert Uytterhoeven
- *
- * 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.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-
-#include <asm/setup.h>
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atari_stdma.h>
-#include <asm/ide.h>
-
-#define DRV_NAME "falconide"
-
- /*
- * Offsets from base address
- */
-
-#define ATA_HD_CONTROL 0x39
-
- /*
- * falconide_intr_lock is used to obtain access to the IDE interrupt,
- * which is shared between several drivers.
- */
-
-static int falconide_intr_lock;
-
-static void falconide_release_lock(void)
-{
- if (falconide_intr_lock == 0) {
- printk(KERN_ERR "%s: bug\n", __func__);
- return;
- }
- falconide_intr_lock = 0;
- stdma_release();
-}
-
-static void falconide_get_lock(irq_handler_t handler, void *data)
-{
- if (falconide_intr_lock == 0) {
- stdma_lock(handler, data);
- falconide_intr_lock = 1;
- }
-}
-
-static void falconide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
- void *buf, unsigned int len)
-{
- unsigned long data_addr = drive->hwif->io_ports.data_addr;
-
- if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
- __ide_mm_insw(data_addr, buf, (len + 1) / 2);
- return;
- }
-
- raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
-}
-
-static void falconide_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
- void *buf, unsigned int len)
-{
- unsigned long data_addr = drive->hwif->io_ports.data_addr;
-
- if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
- __ide_mm_outsw(data_addr, buf, (len + 1) / 2);
- return;
- }
-
- raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
-}
-
-/* Atari has a byte-swapped IDE interface */
-static const struct ide_tp_ops falconide_tp_ops = {
- .exec_command = ide_exec_command,
- .read_status = ide_read_status,
- .read_altstatus = ide_read_altstatus,
- .write_devctl = ide_write_devctl,
-
- .dev_select = ide_dev_select,
- .tf_load = ide_tf_load,
- .tf_read = ide_tf_read,
-
- .input_data = falconide_input_data,
- .output_data = falconide_output_data,
-};
-
-static const struct ide_port_info falconide_port_info = {
- .get_lock = falconide_get_lock,
- .release_lock = falconide_release_lock,
- .tp_ops = &falconide_tp_ops,
- .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
- IDE_HFLAG_NO_DMA,
- .irq_flags = IRQF_SHARED,
- .chipset = ide_generic,
-};
-
-static void __init falconide_setup_ports(struct ide_hw *hw, unsigned long base)
-{
- int i;
-
- memset(hw, 0, sizeof(*hw));
-
- hw->io_ports.data_addr = base;
-
- for (i = 1; i < 8; i++)
- hw->io_ports_array[i] = base + 1 + i * 4;
-
- hw->io_ports.ctl_addr = base + ATA_HD_CONTROL;
-
- hw->irq = IRQ_MFP_IDE;
-}
-
- /*
- * Probe for a Falcon IDE interface
- */
-
-static int __init falconide_init(struct platform_device *pdev)
-{
- struct resource *res;
- struct ide_host *host;
- struct ide_hw hw, *hws[] = { &hw };
- unsigned long base;
- int rc;
-
- dev_info(&pdev->dev, "Atari Falcon IDE controller\n");
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
-
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), DRV_NAME)) {
- dev_err(&pdev->dev, "resources busy\n");
- return -EBUSY;
- }
-
- base = (unsigned long)res->start;
-
- falconide_setup_ports(&hw, base);
-
- host = ide_host_alloc(&falconide_port_info, hws, 1);
- if (host == NULL) {
- rc = -ENOMEM;
- goto err;
- }
-
- falconide_get_lock(NULL, NULL);
- rc = ide_host_register(host, &falconide_port_info, hws);
- falconide_release_lock();
-
- if (rc)
- goto err_free;
-
- platform_set_drvdata(pdev, host);
- return 0;
-err_free:
- ide_host_free(host);
-err:
- release_mem_region(res->start, resource_size(res));
- return rc;
-}
-
-static int falconide_remove(struct platform_device *pdev)
-{
- struct ide_host *host = platform_get_drvdata(pdev);
-
- ide_host_remove(host);
-
- return 0;
-}
-
-static struct platform_driver ide_falcon_driver = {
- .remove = falconide_remove,
- .driver = {
- .name = "atari-falcon-ide",
- },
-};
-
-module_platform_driver_probe(ide_falcon_driver, falconide_init);
-
-MODULE_AUTHOR("Geert Uytterhoeven");
-MODULE_DESCRIPTION("low-level driver for Atari Falcon IDE");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:atari-falcon-ide");
diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c
deleted file mode 100644
index 901e6ebfeb96..000000000000
--- a/drivers/ide/gayle.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Amiga Gayle IDE Driver
- *
- * Created 9 Jul 1997 by Geert Uytterhoeven
- *
- * 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.
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/zorro.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include <asm/setup.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#include <asm/amigayle.h>
-
-
- /*
- * Offsets from one of the above bases
- */
-
-#define GAYLE_CONTROL 0x101a
-
- /*
- * These are at different offsets from the base
- */
-
-#define GAYLE_IRQ_4000 0xdd3020 /* MSB = 1, Harddisk is source of */
-#define GAYLE_IRQ_1200 0xda9000 /* interrupt */
-
-
- /*
- * Offset of the secondary port for IDE doublers
- * Note that GAYLE_CONTROL is NOT available then!
- */
-
-#define GAYLE_NEXT_PORT 0x1000
-
-#define GAYLE_NUM_HWIFS 2
-#define GAYLE_NUM_PROBE_HWIFS (ide_doubler ? GAYLE_NUM_HWIFS : \
- GAYLE_NUM_HWIFS-1)
-#define GAYLE_HAS_CONTROL_REG (!ide_doubler)
-
-static bool ide_doubler;
-module_param_named(doubler, ide_doubler, bool, 0);
-MODULE_PARM_DESC(doubler, "enable support for IDE doublers");
-
- /*
- * Check and acknowledge the interrupt status
- */
-
-static int gayle_test_irq(ide_hwif_t *hwif)
-{
- unsigned char ch;
-
- ch = z_readb(hwif->io_ports.irq_addr);
- if (!(ch & GAYLE_IRQ_IDE))
- return 0;
- return 1;
-}
-
-static void gayle_a1200_clear_irq(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
-
- (void)z_readb(hwif->io_ports.status_addr);
- z_writeb(0x7c, hwif->io_ports.irq_addr);
-}
-
-static void __init gayle_setup_ports(struct ide_hw *hw, unsigned long base,
- unsigned long ctl, unsigned long irq_port)
-{
- int i;
-
- memset(hw, 0, sizeof(*hw));
-
- hw->io_ports.data_addr = base;
-
- for (i = 1; i < 8; i++)
- hw->io_ports_array[i] = base + 2 + i * 4;
-
- hw->io_ports.ctl_addr = ctl;
- hw->io_ports.irq_addr = irq_port;
-
- hw->irq = IRQ_AMIGA_PORTS;
-}
-
-static const struct ide_port_ops gayle_a4000_port_ops = {
- .test_irq = gayle_test_irq,
-};
-
-static const struct ide_port_ops gayle_a1200_port_ops = {
- .clear_irq = gayle_a1200_clear_irq,
- .test_irq = gayle_test_irq,
-};
-
-static const struct ide_port_info gayle_port_info = {
- .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
- IDE_HFLAG_NO_DMA,
- .irq_flags = IRQF_SHARED,
- .chipset = ide_generic,
-};
-
- /*
- * Probe for a Gayle IDE interface (and optionally for an IDE doubler)
- */
-
-static int __init amiga_gayle_ide_probe(struct platform_device *pdev)
-{
- struct resource *res;
- struct gayle_ide_platform_data *pdata;
- unsigned long base, ctrlport, irqport;
- unsigned int i;
- int error;
- struct ide_hw hw[GAYLE_NUM_HWIFS], *hws[GAYLE_NUM_HWIFS];
- struct ide_port_info d = gayle_port_info;
- struct ide_host *host;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
-
- if (!request_mem_region(res->start, resource_size(res), "IDE"))
- return -EBUSY;
-
- pdata = dev_get_platdata(&pdev->dev);
- pr_info("ide: Gayle IDE controller (A%u style%s)\n",
- pdata->explicit_ack ? 1200 : 4000,
- ide_doubler ? ", IDE doubler" : "");
-
- base = (unsigned long)ZTWO_VADDR(pdata->base);
- ctrlport = 0;
- irqport = (unsigned long)ZTWO_VADDR(pdata->irqport);
- if (pdata->explicit_ack)
- d.port_ops = &gayle_a1200_port_ops;
- else
- d.port_ops = &gayle_a4000_port_ops;
-
- for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++, base += GAYLE_NEXT_PORT) {
- if (GAYLE_HAS_CONTROL_REG)
- ctrlport = base + GAYLE_CONTROL;
-
- gayle_setup_ports(&hw[i], base, ctrlport, irqport);
- hws[i] = &hw[i];
- }
-
- error = ide_host_add(&d, hws, i, &host);
- if (error)
- goto out;
-
- platform_set_drvdata(pdev, host);
- return 0;
-
-out:
- release_mem_region(res->start, resource_size(res));
- return error;
-}
-
-static int __exit amiga_gayle_ide_remove(struct platform_device *pdev)
-{
- struct ide_host *host = platform_get_drvdata(pdev);
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- ide_host_remove(host);
- release_mem_region(res->start, resource_size(res));
- return 0;
-}
-
-static struct platform_driver amiga_gayle_ide_driver = {
- .remove = __exit_p(amiga_gayle_ide_remove),
- .driver = {
- .name = "amiga-gayle-ide",
- },
-};
-
-module_platform_driver_probe(amiga_gayle_ide_driver, amiga_gayle_ide_probe);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:amiga-gayle-ide");
diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
deleted file mode 100644
index 50c9a41467c8..000000000000
--- a/drivers/ide/hpt366.c
+++ /dev/null
@@ -1,1545 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
- * Portions Copyright (C) 2001 Sun Microsystems, Inc.
- * Portions Copyright (C) 2003 Red Hat Inc
- * Portions Copyright (C) 2007 Bartlomiej Zolnierkiewicz
- * Portions Copyright (C) 2005-2009 MontaVista Software, Inc.
- *
- * Thanks to HighPoint Technologies for their assistance, and hardware.
- * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
- * donation of an ABit BP6 mainboard, processor, and memory acellerated
- * development and support.
- *
- *
- * HighPoint has its own drivers (open source except for the RAID part)
- * available from http://www.highpoint-tech.com/USA_new/service_support.htm
- * This may be useful to anyone wanting to work on this driver, however do not
- * trust them too much since the code tends to become less and less meaningful
- * as the time passes... :-/
- *
- * Note that final HPT370 support was done by force extraction of GPL.
- *
- * - add function for getting/setting power status of drive
- * - the HPT370's state machine can get confused. reset it before each dma
- * xfer to prevent that from happening.
- * - reset state engine whenever we get an error.
- * - check for busmaster state at end of dma.
- * - use new highpoint timings.
- * - detect bus speed using highpoint register.
- * - use pll if we don't have a clock table. added a 66MHz table that's
- * just 2x the 33MHz table.
- * - removed turnaround. NOTE: we never want to switch between pll and
- * pci clocks as the chip can glitch in those cases. the highpoint
- * approved workaround slows everything down too much to be useful. in
- * addition, we would have to serialize access to each chip.
- * Adrian Sun <a.sun@sun.com>
- *
- * add drive timings for 66MHz PCI bus,
- * fix ATA Cable signal detection, fix incorrect /proc info
- * add /proc display for per-drive PIO/DMA/UDMA mode and
- * per-channel ATA-33/66 Cable detect.
- * Duncan Laurie <void@sun.com>
- *
- * fixup /proc output for multiple controllers
- * Tim Hockin <thockin@sun.com>
- *
- * On hpt366:
- * Reset the hpt366 on error, reset on dma
- * Fix disabling Fast Interrupt hpt366.
- * Mike Waychison <crlf@sun.com>
- *
- * Added support for 372N clocking and clock switching. The 372N needs
- * different clocks on read/write. This requires overloading rw_disk and
- * other deeply crazy things. Thanks to <http://www.hoerstreich.de> for
- * keeping me sane.
- * Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- * - fix the clock turnaround code: it was writing to the wrong ports when
- * called for the secondary channel, caching the current clock mode per-
- * channel caused the cached register value to get out of sync with the
- * actual one, the channels weren't serialized, the turnaround shouldn't
- * be done on 66 MHz PCI bus
- * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used
- * does not allow for this speed anyway
- * - avoid touching disabled channels (e.g. HPT371/N are single channel chips,
- * their primary channel is kind of virtual, it isn't tied to any pins)
- * - fix/remove bad/unused timing tables and use one set of tables for the whole
- * HPT37x chip family; save space by introducing the separate transfer mode
- * table in which the mode lookup is done
- * - use f_CNT value saved by the HighPoint BIOS as reading it directly gives
- * the wrong PCI frequency since DPLL has already been calibrated by BIOS;
- * read it only from the function 0 of HPT374 chips
- * - fix the hotswap code: it caused RESET- to glitch when tristating the bus,
- * and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead
- * - pass to init_chipset() handlers a copy of the IDE PCI device structure as
- * they tamper with its fields
- * - pass to the init_setup handlers a copy of the ide_pci_device_t structure
- * since they may tamper with its fields
- * - prefix the driver startup messages with the real chip name
- * - claim the extra 240 bytes of I/O space for all chips
- * - optimize the UltraDMA filtering and the drive list lookup code
- * - use pci_get_slot() to get to the function 1 of HPT36x/374
- * - cache offset of the channel's misc. control registers (MCRs) being used
- * throughout the driver
- * - only touch the relevant MCR when detecting the cable type on HPT374's
- * function 1
- * - rename all the register related variables consistently
- * - move all the interrupt twiddling code from the speedproc handlers into
- * init_hwif_hpt366(), also grouping all the DMA related code together there
- * - merge HPT36x/HPT37x speedproc handlers, fix PIO timing register mask and
- * separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
- * when setting an UltraDMA mode
- * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
- * the best possible one
- * - clean up DMA timeout handling for HPT370
- * - switch to using the enumeration type to differ between the numerous chip
- * variants, matching PCI device/revision ID with the chip type early, at the
- * init_setup stage
- * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies,
- * stop duplicating it for each channel by storing the pointer in the pci_dev
- * structure: first, at the init_setup stage, point it to a static "template"
- * with only the chip type and its specific base DPLL frequency, the highest
- * UltraDMA mode, and the chip settings table pointer filled, then, at the
- * init_chipset stage, allocate per-chip instance and fill it with the rest
- * of the necessary information
- * - get rid of the constant thresholds in the HPT37x PCI clock detection code,
- * switch to calculating PCI clock frequency based on the chip's base DPLL
- * frequency
- * - switch to using the DPLL clock and enable UltraATA/133 mode by default on
- * anything newer than HPT370/A (except HPT374 that is not capable of this
- * mode according to the manual)
- * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(),
- * also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips;
- * unify HPT36x/37x timing setup code and the speedproc handlers by joining
- * the register setting lists into the table indexed by the clock selected
- * - set the correct hwif->ultra_mask for each individual chip
- * - add Ultra and MW DMA mode filtering for the HPT37[24] based SATA cards
- * - stop resetting HPT370's state machine before each DMA transfer as that has
- * caused more harm than good
- * Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/blkdev.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <linux/slab.h>
-
-#include <linux/uaccess.h>
-#include <asm/io.h>
-
-#define DRV_NAME "hpt366"
-
-/* various tuning parameters */
-#undef HPT_RESET_STATE_ENGINE
-#undef HPT_DELAY_INTERRUPT
-
-static const char *bad_ata100_5[] = {
- "IBM-DTLA-307075",
- "IBM-DTLA-307060",
- "IBM-DTLA-307045",
- "IBM-DTLA-307030",
- "IBM-DTLA-307020",
- "IBM-DTLA-307015",
- "IBM-DTLA-305040",
- "IBM-DTLA-305030",
- "IBM-DTLA-305020",
- "IC35L010AVER07-0",
- "IC35L020AVER07-0",
- "IC35L030AVER07-0",
- "IC35L040AVER07-0",
- "IC35L060AVER07-0",
- "WDC AC310200R",
- NULL
-};
-
-static const char *bad_ata66_4[] = {
- "IBM-DTLA-307075",
- "IBM-DTLA-307060",
- "IBM-DTLA-307045",
- "IBM-DTLA-307030",
- "IBM-DTLA-307020",
- "IBM-DTLA-307015",
- "IBM-DTLA-305040",
- "IBM-DTLA-305030",
- "IBM-DTLA-305020",
- "IC35L010AVER07-0",
- "IC35L020AVER07-0",
- "IC35L030AVER07-0",
- "IC35L040AVER07-0",
- "IC35L060AVER07-0",
- "WDC AC310200R",
- "MAXTOR STM3320620A",
- NULL
-};
-
-static const char *bad_ata66_3[] = {
- "WDC AC310200R",
- NULL
-};
-
-static const char *bad_ata33[] = {
- "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
- "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
- "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
- "Maxtor 90510D4",
- "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
- "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
- "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
- NULL
-};
-
-static u8 xfer_speeds[] = {
- XFER_UDMA_6,
- XFER_UDMA_5,
- XFER_UDMA_4,
- XFER_UDMA_3,
- XFER_UDMA_2,
- XFER_UDMA_1,
- XFER_UDMA_0,
-
- XFER_MW_DMA_2,
- XFER_MW_DMA_1,
- XFER_MW_DMA_0,
-
- XFER_PIO_4,
- XFER_PIO_3,
- XFER_PIO_2,
- XFER_PIO_1,
- XFER_PIO_0
-};
-
-/* Key for bus clock timings
- * 36x 37x
- * bits bits
- * 0:3 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
- * cycles = value + 1
- * 4:7 4:8 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
- * cycles = value + 1
- * 8:11 9:12 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
- * register access.
- * 12:15 13:17 cmd_low_time. Active time of DIOW_/DIOR_ during task file
- * register access.
- * 16:18 18:20 udma_cycle_time. Clock cycles for UDMA xfer.
- * - 21 CLK frequency: 0=ATA clock, 1=dual ATA clock.
- * 19:21 22:24 pre_high_time. Time to initialize the 1st cycle for PIO and
- * MW DMA xfer.
- * 22:24 25:27 cmd_pre_high_time. Time to initialize the 1st PIO cycle for
- * task file register access.
- * 28 28 UDMA enable.
- * 29 29 DMA enable.
- * 30 30 PIO MST enable. If set, the chip is in bus master mode during
- * PIO xfer.
- * 31 31 FIFO enable.
- */
-
-static u32 forty_base_hpt36x[] = {
- /* XFER_UDMA_6 */ 0x900fd943,
- /* XFER_UDMA_5 */ 0x900fd943,
- /* XFER_UDMA_4 */ 0x900fd943,
- /* XFER_UDMA_3 */ 0x900ad943,
- /* XFER_UDMA_2 */ 0x900bd943,
- /* XFER_UDMA_1 */ 0x9008d943,
- /* XFER_UDMA_0 */ 0x9008d943,
-
- /* XFER_MW_DMA_2 */ 0xa008d943,
- /* XFER_MW_DMA_1 */ 0xa010d955,
- /* XFER_MW_DMA_0 */ 0xa010d9fc,
-
- /* XFER_PIO_4 */ 0xc008d963,
- /* XFER_PIO_3 */ 0xc010d974,
- /* XFER_PIO_2 */ 0xc010d997,
- /* XFER_PIO_1 */ 0xc010d9c7,
- /* XFER_PIO_0 */ 0xc018d9d9
-};
-
-static u32 thirty_three_base_hpt36x[] = {
- /* XFER_UDMA_6 */ 0x90c9a731,
- /* XFER_UDMA_5 */ 0x90c9a731,
- /* XFER_UDMA_4 */ 0x90c9a731,
- /* XFER_UDMA_3 */ 0x90cfa731,
- /* XFER_UDMA_2 */ 0x90caa731,
- /* XFER_UDMA_1 */ 0x90cba731,
- /* XFER_UDMA_0 */ 0x90c8a731,
-
- /* XFER_MW_DMA_2 */ 0xa0c8a731,
- /* XFER_MW_DMA_1 */ 0xa0c8a732, /* 0xa0c8a733 */
- /* XFER_MW_DMA_0 */ 0xa0c8a797,
-
- /* XFER_PIO_4 */ 0xc0c8a731,
- /* XFER_PIO_3 */ 0xc0c8a742,
- /* XFER_PIO_2 */ 0xc0d0a753,
- /* XFER_PIO_1 */ 0xc0d0a7a3, /* 0xc0d0a793 */
- /* XFER_PIO_0 */ 0xc0d0a7aa /* 0xc0d0a7a7 */
-};
-
-static u32 twenty_five_base_hpt36x[] = {
- /* XFER_UDMA_6 */ 0x90c98521,
- /* XFER_UDMA_5 */ 0x90c98521,
- /* XFER_UDMA_4 */ 0x90c98521,
- /* XFER_UDMA_3 */ 0x90cf8521,
- /* XFER_UDMA_2 */ 0x90cf8521,
- /* XFER_UDMA_1 */ 0x90cb8521,
- /* XFER_UDMA_0 */ 0x90cb8521,
-
- /* XFER_MW_DMA_2 */ 0xa0ca8521,
- /* XFER_MW_DMA_1 */ 0xa0ca8532,
- /* XFER_MW_DMA_0 */ 0xa0ca8575,
-
- /* XFER_PIO_4 */ 0xc0ca8521,
- /* XFER_PIO_3 */ 0xc0ca8532,
- /* XFER_PIO_2 */ 0xc0ca8542,
- /* XFER_PIO_1 */ 0xc0d08572,
- /* XFER_PIO_0 */ 0xc0d08585
-};
-
-/*
- * The following are the new timing tables with PIO mode data/taskfile transfer
- * overclocking fixed...
- */
-
-/* This table is taken from the HPT370 data manual rev. 1.02 */
-static u32 thirty_three_base_hpt37x[] = {
- /* XFER_UDMA_6 */ 0x16455031, /* 0x16655031 ?? */
- /* XFER_UDMA_5 */ 0x16455031,
- /* XFER_UDMA_4 */ 0x16455031,
- /* XFER_UDMA_3 */ 0x166d5031,
- /* XFER_UDMA_2 */ 0x16495031,
- /* XFER_UDMA_1 */ 0x164d5033,
- /* XFER_UDMA_0 */ 0x16515097,
-
- /* XFER_MW_DMA_2 */ 0x26515031,
- /* XFER_MW_DMA_1 */ 0x26515033,
- /* XFER_MW_DMA_0 */ 0x26515097,
-
- /* XFER_PIO_4 */ 0x06515021,
- /* XFER_PIO_3 */ 0x06515022,
- /* XFER_PIO_2 */ 0x06515033,
- /* XFER_PIO_1 */ 0x06915065,
- /* XFER_PIO_0 */ 0x06d1508a
-};
-
-static u32 fifty_base_hpt37x[] = {
- /* XFER_UDMA_6 */ 0x1a861842,
- /* XFER_UDMA_5 */ 0x1a861842,
- /* XFER_UDMA_4 */ 0x1aae1842,
- /* XFER_UDMA_3 */ 0x1a8e1842,
- /* XFER_UDMA_2 */ 0x1a0e1842,
- /* XFER_UDMA_1 */ 0x1a161854,
- /* XFER_UDMA_0 */ 0x1a1a18ea,
-
- /* XFER_MW_DMA_2 */ 0x2a821842,
- /* XFER_MW_DMA_1 */ 0x2a821854,
- /* XFER_MW_DMA_0 */ 0x2a8218ea,
-
- /* XFER_PIO_4 */ 0x0a821842,
- /* XFER_PIO_3 */ 0x0a821843,
- /* XFER_PIO_2 */ 0x0a821855,
- /* XFER_PIO_1 */ 0x0ac218a8,
- /* XFER_PIO_0 */ 0x0b02190c
-};
-
-static u32 sixty_six_base_hpt37x[] = {
- /* XFER_UDMA_6 */ 0x1c86fe62,
- /* XFER_UDMA_5 */ 0x1caefe62, /* 0x1c8afe62 */
- /* XFER_UDMA_4 */ 0x1c8afe62,
- /* XFER_UDMA_3 */ 0x1c8efe62,
- /* XFER_UDMA_2 */ 0x1c92fe62,
- /* XFER_UDMA_1 */ 0x1c9afe62,
- /* XFER_UDMA_0 */ 0x1c82fe62,
-
- /* XFER_MW_DMA_2 */ 0x2c82fe62,
- /* XFER_MW_DMA_1 */ 0x2c82fe66,
- /* XFER_MW_DMA_0 */ 0x2c82ff2e,
-
- /* XFER_PIO_4 */ 0x0c82fe62,
- /* XFER_PIO_3 */ 0x0c82fe84,
- /* XFER_PIO_2 */ 0x0c82fea6,
- /* XFER_PIO_1 */ 0x0d02ff26,
- /* XFER_PIO_0 */ 0x0d42ff7f
-};
-
-#define HPT371_ALLOW_ATA133_6 1
-#define HPT302_ALLOW_ATA133_6 1
-#define HPT372_ALLOW_ATA133_6 1
-#define HPT370_ALLOW_ATA100_5 0
-#define HPT366_ALLOW_ATA66_4 1
-#define HPT366_ALLOW_ATA66_3 1
-
-/* Supported ATA clock frequencies */
-enum ata_clock {
- ATA_CLOCK_25MHZ,
- ATA_CLOCK_33MHZ,
- ATA_CLOCK_40MHZ,
- ATA_CLOCK_50MHZ,
- ATA_CLOCK_66MHZ,
- NUM_ATA_CLOCKS
-};
-
-struct hpt_timings {
- u32 pio_mask;
- u32 dma_mask;
- u32 ultra_mask;
- u32 *clock_table[NUM_ATA_CLOCKS];
-};
-
-/*
- * Hold all the HighPoint chip information in one place.
- */
-
-struct hpt_info {
- char *chip_name; /* Chip name */
- u8 chip_type; /* Chip type */
- u8 udma_mask; /* Allowed UltraDMA modes mask. */
- u8 dpll_clk; /* DPLL clock in MHz */
- u8 pci_clk; /* PCI clock in MHz */
- struct hpt_timings *timings; /* Chipset timing data */
- u8 clock; /* ATA clock selected */
-};
-
-/* Supported HighPoint chips */
-enum {
- HPT36x,
- HPT370,
- HPT370A,
- HPT374,
- HPT372,
- HPT372A,
- HPT302,
- HPT371,
- HPT372N,
- HPT302N,
- HPT371N
-};
-
-static struct hpt_timings hpt36x_timings = {
- .pio_mask = 0xc1f8ffff,
- .dma_mask = 0x303800ff,
- .ultra_mask = 0x30070000,
- .clock_table = {
- [ATA_CLOCK_25MHZ] = twenty_five_base_hpt36x,
- [ATA_CLOCK_33MHZ] = thirty_three_base_hpt36x,
- [ATA_CLOCK_40MHZ] = forty_base_hpt36x,
- [ATA_CLOCK_50MHZ] = NULL,
- [ATA_CLOCK_66MHZ] = NULL
- }
-};
-
-static struct hpt_timings hpt37x_timings = {
- .pio_mask = 0xcfc3ffff,
- .dma_mask = 0x31c001ff,
- .ultra_mask = 0x303c0000,
- .clock_table = {
- [ATA_CLOCK_25MHZ] = NULL,
- [ATA_CLOCK_33MHZ] = thirty_three_base_hpt37x,
- [ATA_CLOCK_40MHZ] = NULL,
- [ATA_CLOCK_50MHZ] = fifty_base_hpt37x,
- [ATA_CLOCK_66MHZ] = sixty_six_base_hpt37x
- }
-};
-
-static const struct hpt_info hpt36x = {
- .chip_name = "HPT36x",
- .chip_type = HPT36x,
- .udma_mask = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2,
- .dpll_clk = 0, /* no DPLL */
- .timings = &hpt36x_timings
-};
-
-static const struct hpt_info hpt370 = {
- .chip_name = "HPT370",
- .chip_type = HPT370,
- .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
- .dpll_clk = 48,
- .timings = &hpt37x_timings
-};
-
-static const struct hpt_info hpt370a = {
- .chip_name = "HPT370A",
- .chip_type = HPT370A,
- .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
- .dpll_clk = 48,
- .timings = &hpt37x_timings
-};
-
-static const struct hpt_info hpt374 = {
- .chip_name = "HPT374",
- .chip_type = HPT374,
- .udma_mask = ATA_UDMA5,
- .dpll_clk = 48,
- .timings = &hpt37x_timings
-};
-
-static const struct hpt_info hpt372 = {
- .chip_name = "HPT372",
- .chip_type = HPT372,
- .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- .dpll_clk = 55,
- .timings = &hpt37x_timings
-};
-
-static const struct hpt_info hpt372a = {
- .chip_name = "HPT372A",
- .chip_type = HPT372A,
- .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- .dpll_clk = 66,
- .timings = &hpt37x_timings
-};
-
-static const struct hpt_info hpt302 = {
- .chip_name = "HPT302",
- .chip_type = HPT302,
- .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- .dpll_clk = 66,
- .timings = &hpt37x_timings
-};
-
-static const struct hpt_info hpt371 = {
- .chip_name = "HPT371",
- .chip_type = HPT371,
- .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- .dpll_clk = 66,
- .timings = &hpt37x_timings
-};
-
-static const struct hpt_info hpt372n = {
- .chip_name = "HPT372N",
- .chip_type = HPT372N,
- .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- .dpll_clk = 77,
- .timings = &hpt37x_timings
-};
-
-static const struct hpt_info hpt302n = {
- .chip_name = "HPT302N",
- .chip_type = HPT302N,
- .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- .dpll_clk = 77,
- .timings = &hpt37x_timings
-};
-
-static const struct hpt_info hpt371n = {
- .chip_name = "HPT371N",
- .chip_type = HPT371N,
- .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- .dpll_clk = 77,
- .timings = &hpt37x_timings
-};
-
-static bool check_in_drive_list(ide_drive_t *drive, const char **list)
-{
- return match_string(list, -1, (char *)&drive->id[ATA_ID_PROD]) >= 0;
-}
-
-static struct hpt_info *hpt3xx_get_info(struct device *dev)
-{
- struct ide_host *host = dev_get_drvdata(dev);
- struct hpt_info *info = (struct hpt_info *)host->host_priv;
-
- return dev == host->dev[1] ? info + 1 : info;
-}
-
-/*
- * The Marvell bridge chips used on the HighPoint SATA cards do not seem
- * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes...
- */
-
-static u8 hpt3xx_udma_filter(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = hpt3xx_get_info(hwif->dev);
- u8 mask = hwif->ultra_mask;
-
- switch (info->chip_type) {
- case HPT36x:
- if (!HPT366_ALLOW_ATA66_4 ||
- check_in_drive_list(drive, bad_ata66_4))
- mask = ATA_UDMA3;
-
- if (!HPT366_ALLOW_ATA66_3 ||
- check_in_drive_list(drive, bad_ata66_3))
- mask = ATA_UDMA2;
- break;
- case HPT370:
- if (!HPT370_ALLOW_ATA100_5 ||
- check_in_drive_list(drive, bad_ata100_5))
- mask = ATA_UDMA4;
- break;
- case HPT370A:
- if (!HPT370_ALLOW_ATA100_5 ||
- check_in_drive_list(drive, bad_ata100_5))
- return ATA_UDMA4;
- fallthrough;
- case HPT372 :
- case HPT372A:
- case HPT372N:
- case HPT374 :
- if (ata_id_is_sata(drive->id))
- mask &= ~0x0e;
- fallthrough;
- default:
- return mask;
- }
-
- return check_in_drive_list(drive, bad_ata33) ? 0x00 : mask;
-}
-
-static u8 hpt3xx_mdma_filter(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = hpt3xx_get_info(hwif->dev);
-
- switch (info->chip_type) {
- case HPT372 :
- case HPT372A:
- case HPT372N:
- case HPT374 :
- if (ata_id_is_sata(drive->id))
- return 0x00;
- fallthrough;
- default:
- return 0x07;
- }
-}
-
-static u32 get_speed_setting(u8 speed, struct hpt_info *info)
-{
- int i;
-
- /*
- * Lookup the transfer mode table to get the index into
- * the timing table.
- *
- * NOTE: For XFER_PIO_SLOW, PIO mode 0 timings will be used.
- */
- for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
- if (xfer_speeds[i] == speed)
- break;
-
- return info->timings->clock_table[info->clock][i];
-}
-
-static void hpt3xx_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct hpt_info *info = hpt3xx_get_info(hwif->dev);
- struct hpt_timings *t = info->timings;
- u8 itr_addr = 0x40 + (drive->dn * 4);
- u32 old_itr = 0;
- const u8 speed = drive->dma_mode;
- u32 new_itr = get_speed_setting(speed, info);
- u32 itr_mask = speed < XFER_MW_DMA_0 ? t->pio_mask :
- (speed < XFER_UDMA_0 ? t->dma_mask :
- t->ultra_mask);
-
- pci_read_config_dword(dev, itr_addr, &old_itr);
- new_itr = (old_itr & ~itr_mask) | (new_itr & itr_mask);
- /*
- * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
- * to avoid problems handling I/O errors later
- */
- new_itr &= ~0xc0000000;
-
- pci_write_config_dword(dev, itr_addr, new_itr);
-}
-
-static void hpt3xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- drive->dma_mode = drive->pio_mode;
- hpt3xx_set_mode(hwif, drive);
-}
-
-static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct hpt_info *info = hpt3xx_get_info(hwif->dev);
-
- if ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0)
- return;
-
- if (info->chip_type >= HPT370) {
- u8 scr1 = 0;
-
- pci_read_config_byte(dev, 0x5a, &scr1);
- if (((scr1 & 0x10) >> 4) != mask) {
- if (mask)
- scr1 |= 0x10;
- else
- scr1 &= ~0x10;
- pci_write_config_byte(dev, 0x5a, scr1);
- }
- } else if (mask)
- disable_irq(hwif->irq);
- else
- enable_irq(hwif->irq);
-}
-
-/*
- * This is specific to the HPT366 UDMA chipset
- * by HighPoint|Triones Technologies, Inc.
- */
-static void hpt366_dma_lost_irq(ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
-
- pci_read_config_byte(dev, 0x50, &mcr1);
- pci_read_config_byte(dev, 0x52, &mcr3);
- pci_read_config_byte(dev, 0x5a, &scr1);
- printk("%s: (%s) mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n",
- drive->name, __func__, mcr1, mcr3, scr1);
- if (scr1 & 0x10)
- pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
- ide_dma_lost_irq(drive);
-}
-
-static void hpt370_clear_engine(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
-
- pci_write_config_byte(dev, hwif->select_data, 0x37);
- udelay(10);
-}
-
-static void hpt370_irq_timeout(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u16 bfifo = 0;
- u8 dma_cmd;
-
- pci_read_config_word(dev, hwif->select_data + 2, &bfifo);
- printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
-
- /* get DMA command mode */
- dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
- /* stop DMA */
- outb(dma_cmd & ~ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD);
- hpt370_clear_engine(drive);
-}
-
-static void hpt370_dma_start(ide_drive_t *drive)
-{
-#ifdef HPT_RESET_STATE_ENGINE
- hpt370_clear_engine(drive);
-#endif
- ide_dma_start(drive);
-}
-
-static int hpt370_dma_end(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
-
- if (dma_stat & ATA_DMA_ACTIVE) {
- /* wait a little */
- udelay(20);
- dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
- if (dma_stat & ATA_DMA_ACTIVE)
- hpt370_irq_timeout(drive);
- }
- return ide_dma_end(drive);
-}
-
-/* returns 1 if DMA IRQ issued, 0 otherwise */
-static int hpt374_dma_test_irq(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u16 bfifo = 0;
- u8 dma_stat;
-
- pci_read_config_word(dev, hwif->select_data + 2, &bfifo);
- if (bfifo & 0x1FF) {
-// printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
- return 0;
- }
-
- dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
- /* return 1 if INTR asserted */
- if (dma_stat & ATA_DMA_INTR)
- return 1;
-
- return 0;
-}
-
-static int hpt374_dma_end(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 mcr = 0, mcr_addr = hwif->select_data;
- u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01;
-
- pci_read_config_byte(dev, 0x6a, &bwsr);
- pci_read_config_byte(dev, mcr_addr, &mcr);
- if (bwsr & mask)
- pci_write_config_byte(dev, mcr_addr, mcr | 0x30);
- return ide_dma_end(drive);
-}
-
-/**
- * hpt3xxn_set_clock - perform clock switching dance
- * @hwif: hwif to switch
- * @mode: clocking mode (0x21 for write, 0x23 otherwise)
- *
- * Switch the DPLL clock on the HPT3xxN devices. This is a right mess.
- */
-
-static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
-{
- unsigned long base = hwif->extra_base;
- u8 scr2 = inb(base + 0x6b);
-
- if ((scr2 & 0x7f) == mode)
- return;
-
- /* Tristate the bus */
- outb(0x80, base + 0x63);
- outb(0x80, base + 0x67);
-
- /* Switch clock and reset channels */
- outb(mode, base + 0x6b);
- outb(0xc0, base + 0x69);
-
- /*
- * Reset the state machines.
- * NOTE: avoid accidentally enabling the disabled channels.
- */
- outb(inb(base + 0x60) | 0x32, base + 0x60);
- outb(inb(base + 0x64) | 0x32, base + 0x64);
-
- /* Complete reset */
- outb(0x00, base + 0x69);
-
- /* Reconnect channels to bus */
- outb(0x00, base + 0x63);
- outb(0x00, base + 0x67);
-}
-
-/**
- * hpt3xxn_rw_disk - prepare for I/O
- * @drive: drive for command
- * @rq: block request structure
- *
- * This is called when a disk I/O is issued to HPT3xxN.
- * We need it because of the clock switching.
- */
-
-static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
-{
- hpt3xxn_set_clock(drive->hwif, rq_data_dir(rq) ? 0x21 : 0x23);
-}
-
-/**
- * hpt37x_calibrate_dpll - calibrate the DPLL
- * @dev: PCI device
- *
- * Perform a calibration cycle on the DPLL.
- * Returns 1 if this succeeds
- */
-static int hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
-{
- u32 dpll = (f_high << 16) | f_low | 0x100;
- u8 scr2;
- int i;
-
- pci_write_config_dword(dev, 0x5c, dpll);
-
- /* Wait for oscillator ready */
- for(i = 0; i < 0x5000; ++i) {
- udelay(50);
- pci_read_config_byte(dev, 0x5b, &scr2);
- if (scr2 & 0x80)
- break;
- }
- /* See if it stays ready (we'll just bail out if it's not yet) */
- for(i = 0; i < 0x1000; ++i) {
- pci_read_config_byte(dev, 0x5b, &scr2);
- /* DPLL destabilized? */
- if(!(scr2 & 0x80))
- return 0;
- }
- /* Turn off tuning, we have the DPLL set */
- pci_read_config_dword (dev, 0x5c, &dpll);
- pci_write_config_dword(dev, 0x5c, (dpll & ~0x100));
- return 1;
-}
-
-static void hpt3xx_disable_fast_irq(struct pci_dev *dev, u8 mcr_addr)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- struct hpt_info *info = host->host_priv + (&dev->dev == host->dev[1]);
- u8 chip_type = info->chip_type;
- u8 new_mcr, old_mcr = 0;
-
- /*
- * Disable the "fast interrupt" prediction. Don't hold off
- * on interrupts. (== 0x01 despite what the docs say)
- */
- pci_read_config_byte(dev, mcr_addr + 1, &old_mcr);
-
- if (chip_type >= HPT374)
- new_mcr = old_mcr & ~0x07;
- else if (chip_type >= HPT370) {
- new_mcr = old_mcr;
- new_mcr &= ~0x02;
-#ifdef HPT_DELAY_INTERRUPT
- new_mcr &= ~0x01;
-#else
- new_mcr |= 0x01;
-#endif
- } else /* HPT366 and HPT368 */
- new_mcr = old_mcr & ~0x80;
-
- if (new_mcr != old_mcr)
- pci_write_config_byte(dev, mcr_addr + 1, new_mcr);
-}
-
-static int init_chipset_hpt366(struct pci_dev *dev)
-{
- unsigned long io_base = pci_resource_start(dev, 4);
- struct hpt_info *info = hpt3xx_get_info(&dev->dev);
- const char *name = DRV_NAME;
- u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */
- u8 chip_type;
- enum ata_clock clock;
-
- chip_type = info->chip_type;
-
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
- pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
- pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
-
- /*
- * First, try to estimate the PCI clock frequency...
- */
- if (chip_type >= HPT370) {
- u8 scr1 = 0;
- u16 f_cnt = 0;
- u32 temp = 0;
-
- /* Interrupt force enable. */
- pci_read_config_byte(dev, 0x5a, &scr1);
- if (scr1 & 0x10)
- pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
-
- /*
- * HighPoint does this for HPT372A.
- * NOTE: This register is only writeable via I/O space.
- */
- if (chip_type == HPT372A)
- outb(0x0e, io_base + 0x9c);
-
- /*
- * Default to PCI clock. Make sure MA15/16 are set to output
- * to prevent drives having problems with 40-pin cables.
- */
- pci_write_config_byte(dev, 0x5b, 0x23);
-
- /*
- * We'll have to read f_CNT value in order to determine
- * the PCI clock frequency according to the following ratio:
- *
- * f_CNT = Fpci * 192 / Fdpll
- *
- * First try reading the register in which the HighPoint BIOS
- * saves f_CNT value before reprogramming the DPLL from its
- * default setting (which differs for the various chips).
- *
- * NOTE: This register is only accessible via I/O space;
- * HPT374 BIOS only saves it for the function 0, so we have to
- * always read it from there -- no need to check the result of
- * pci_get_slot() for the function 0 as the whole device has
- * been already "pinned" (via function 1) in init_setup_hpt374()
- */
- if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
- struct pci_dev *dev1 = pci_get_slot(dev->bus,
- dev->devfn - 1);
- unsigned long io_base = pci_resource_start(dev1, 4);
-
- temp = inl(io_base + 0x90);
- pci_dev_put(dev1);
- } else
- temp = inl(io_base + 0x90);
-
- /*
- * In case the signature check fails, we'll have to
- * resort to reading the f_CNT register itself in hopes
- * that nobody has touched the DPLL yet...
- */
- if ((temp & 0xFFFFF000) != 0xABCDE000) {
- int i;
-
- printk(KERN_WARNING "%s %s: no clock data saved by "
- "BIOS\n", name, pci_name(dev));
-
- /* Calculate the average value of f_CNT. */
- for (temp = i = 0; i < 128; i++) {
- pci_read_config_word(dev, 0x78, &f_cnt);
- temp += f_cnt & 0x1ff;
- mdelay(1);
- }
- f_cnt = temp / 128;
- } else
- f_cnt = temp & 0x1ff;
-
- dpll_clk = info->dpll_clk;
- pci_clk = (f_cnt * dpll_clk) / 192;
-
- /* Clamp PCI clock to bands. */
- if (pci_clk < 40)
- pci_clk = 33;
- else if(pci_clk < 45)
- pci_clk = 40;
- else if(pci_clk < 55)
- pci_clk = 50;
- else
- pci_clk = 66;
-
- printk(KERN_INFO "%s %s: DPLL base: %d MHz, f_CNT: %d, "
- "assuming %d MHz PCI\n", name, pci_name(dev),
- dpll_clk, f_cnt, pci_clk);
- } else {
- u32 itr1 = 0;
-
- pci_read_config_dword(dev, 0x40, &itr1);
-
- /* Detect PCI clock by looking at cmd_high_time. */
- switch ((itr1 >> 8) & 0x0f) {
- case 0x09:
- pci_clk = 40;
- break;
- case 0x05:
- pci_clk = 25;
- break;
- case 0x07:
- default:
- pci_clk = 33;
- break;
- }
- }
-
- /* Let's assume we'll use PCI clock for the ATA clock... */
- switch (pci_clk) {
- case 25:
- clock = ATA_CLOCK_25MHZ;
- break;
- case 33:
- default:
- clock = ATA_CLOCK_33MHZ;
- break;
- case 40:
- clock = ATA_CLOCK_40MHZ;
- break;
- case 50:
- clock = ATA_CLOCK_50MHZ;
- break;
- case 66:
- clock = ATA_CLOCK_66MHZ;
- break;
- }
-
- /*
- * Only try the DPLL if we don't have a table for the PCI clock that
- * we are running at for HPT370/A, always use it for anything newer...
- *
- * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI.
- * We also don't like using the DPLL because this causes glitches
- * on PRST-/SRST- when the state engine gets reset...
- */
- if (chip_type >= HPT374 || info->timings->clock_table[clock] == NULL) {
- u16 f_low, delta = pci_clk < 50 ? 2 : 4;
- int adjust;
-
- /*
- * Select 66 MHz DPLL clock only if UltraATA/133 mode is
- * supported/enabled, use 50 MHz DPLL clock otherwise...
- */
- if (info->udma_mask == ATA_UDMA6) {
- dpll_clk = 66;
- clock = ATA_CLOCK_66MHZ;
- } else if (dpll_clk) { /* HPT36x chips don't have DPLL */
- dpll_clk = 50;
- clock = ATA_CLOCK_50MHZ;
- }
-
- if (info->timings->clock_table[clock] == NULL) {
- printk(KERN_ERR "%s %s: unknown bus timing!\n",
- name, pci_name(dev));
- return -EIO;
- }
-
- /* Select the DPLL clock. */
- pci_write_config_byte(dev, 0x5b, 0x21);
-
- /*
- * Adjust the DPLL based upon PCI clock, enable it,
- * and wait for stabilization...
- */
- f_low = (pci_clk * 48) / dpll_clk;
-
- for (adjust = 0; adjust < 8; adjust++) {
- if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta))
- break;
-
- /*
- * See if it'll settle at a fractionally different clock
- */
- if (adjust & 1)
- f_low -= adjust >> 1;
- else
- f_low += adjust >> 1;
- }
- if (adjust == 8) {
- printk(KERN_ERR "%s %s: DPLL did not stabilize!\n",
- name, pci_name(dev));
- return -EIO;
- }
-
- printk(KERN_INFO "%s %s: using %d MHz DPLL clock\n",
- name, pci_name(dev), dpll_clk);
- } else {
- /* Mark the fact that we're not using the DPLL. */
- dpll_clk = 0;
-
- printk(KERN_INFO "%s %s: using %d MHz PCI clock\n",
- name, pci_name(dev), pci_clk);
- }
-
- /* Store the clock frequencies. */
- info->dpll_clk = dpll_clk;
- info->pci_clk = pci_clk;
- info->clock = clock;
-
- if (chip_type >= HPT370) {
- u8 mcr1, mcr4;
-
- /*
- * Reset the state engines.
- * NOTE: Avoid accidentally enabling the disabled channels.
- */
- pci_read_config_byte (dev, 0x50, &mcr1);
- pci_read_config_byte (dev, 0x54, &mcr4);
- pci_write_config_byte(dev, 0x50, (mcr1 | 0x32));
- pci_write_config_byte(dev, 0x54, (mcr4 | 0x32));
- udelay(100);
- }
-
- /*
- * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
- * the MISC. register to stretch the UltraDMA Tss timing.
- * NOTE: This register is only writeable via I/O space.
- */
- if (chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
- outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
-
- hpt3xx_disable_fast_irq(dev, 0x50);
- hpt3xx_disable_fast_irq(dev, 0x54);
-
- return 0;
-}
-
-static u8 hpt3xx_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct hpt_info *info = hpt3xx_get_info(hwif->dev);
- u8 chip_type = info->chip_type;
- u8 scr1 = 0, ata66 = hwif->channel ? 0x01 : 0x02;
-
- /*
- * The HPT37x uses the CBLID pins as outputs for MA15/MA16
- * address lines to access an external EEPROM. To read valid
- * cable detect state the pins must be enabled as inputs.
- */
- if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
- /*
- * HPT374 PCI function 1
- * - set bit 15 of reg 0x52 to enable TCBLID as input
- * - set bit 15 of reg 0x56 to enable FCBLID as input
- */
- u8 mcr_addr = hwif->select_data + 2;
- u16 mcr;
-
- pci_read_config_word(dev, mcr_addr, &mcr);
- pci_write_config_word(dev, mcr_addr, mcr | 0x8000);
- /* Debounce, then read cable ID register */
- udelay(10);
- pci_read_config_byte(dev, 0x5a, &scr1);
- pci_write_config_word(dev, mcr_addr, mcr);
- } else if (chip_type >= HPT370) {
- /*
- * HPT370/372 and 374 pcifn 0
- * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
- */
- u8 scr2 = 0;
-
- pci_read_config_byte(dev, 0x5b, &scr2);
- pci_write_config_byte(dev, 0x5b, scr2 & ~1);
- /* Debounce, then read cable ID register */
- udelay(10);
- pci_read_config_byte(dev, 0x5a, &scr1);
- pci_write_config_byte(dev, 0x5b, scr2);
- } else
- pci_read_config_byte(dev, 0x5a, &scr1);
-
- return (scr1 & ata66) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-}
-
-static void init_hwif_hpt366(ide_hwif_t *hwif)
-{
- struct hpt_info *info = hpt3xx_get_info(hwif->dev);
- u8 chip_type = info->chip_type;
-
- /* Cache the channel's MISC. control registers' offset */
- hwif->select_data = hwif->channel ? 0x54 : 0x50;
-
- /*
- * HPT3xxN chips have some complications:
- *
- * - on 33 MHz PCI we must clock switch
- * - on 66 MHz PCI we must NOT use the PCI clock
- */
- if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) {
- /*
- * Clock is shared between the channels,
- * so we'll have to serialize them... :-(
- */
- hwif->host->host_flags |= IDE_HFLAG_SERIALIZE;
- hwif->rw_disk = &hpt3xxn_rw_disk;
- }
-}
-
-static int init_dma_hpt366(ide_hwif_t *hwif,
- const struct ide_port_info *d)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long flags, base = ide_pci_dma_base(hwif, d);
- u8 dma_old, dma_new, masterdma = 0, slavedma = 0;
-
- if (base == 0)
- return -1;
-
- hwif->dma_base = base;
-
- if (ide_pci_check_simplex(hwif, d) < 0)
- return -1;
-
- if (ide_pci_set_master(dev, d->name) < 0)
- return -1;
-
- dma_old = inb(base + 2);
-
- local_irq_save(flags);
-
- dma_new = dma_old;
- pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma);
- pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47, &slavedma);
-
- if (masterdma & 0x30) dma_new |= 0x20;
- if ( slavedma & 0x30) dma_new |= 0x40;
- if (dma_new != dma_old)
- outb(dma_new, base + 2);
-
- local_irq_restore(flags);
-
- printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n",
- hwif->name, base, base + 7);
-
- hwif->extra_base = base + (hwif->channel ? 8 : 16);
-
- if (ide_allocate_dma_engine(hwif))
- return -1;
-
- return 0;
-}
-
-static void hpt374_init(struct pci_dev *dev, struct pci_dev *dev2)
-{
- if (dev2->irq != dev->irq) {
- /* FIXME: we need a core pci_set_interrupt() */
- dev2->irq = dev->irq;
- printk(KERN_INFO DRV_NAME " %s: PCI config space interrupt "
- "fixed\n", pci_name(dev2));
- }
-}
-
-static void hpt371_init(struct pci_dev *dev)
-{
- u8 mcr1 = 0;
-
- /*
- * HPT371 chips physically have only one channel, the secondary one,
- * but the primary channel registers do exist! Go figure...
- * So, we manually disable the non-existing channel here
- * (if the BIOS hasn't done this already).
- */
- pci_read_config_byte(dev, 0x50, &mcr1);
- if (mcr1 & 0x04)
- pci_write_config_byte(dev, 0x50, mcr1 & ~0x04);
-}
-
-static int hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2)
-{
- u8 mcr1 = 0, pin1 = 0, pin2 = 0;
-
- /*
- * Now we'll have to force both channels enabled if
- * at least one of them has been enabled by BIOS...
- */
- pci_read_config_byte(dev, 0x50, &mcr1);
- if (mcr1 & 0x30)
- pci_write_config_byte(dev, 0x50, mcr1 | 0x30);
-
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
- pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
-
- if (pin1 != pin2 && dev->irq == dev2->irq) {
- printk(KERN_INFO DRV_NAME " %s: onboard version of chipset, "
- "pin1=%d pin2=%d\n", pci_name(dev), pin1, pin2);
- return 1;
- }
-
- return 0;
-}
-
-#define IDE_HFLAGS_HPT3XX \
- (IDE_HFLAG_NO_ATAPI_DMA | \
- IDE_HFLAG_OFF_BOARD)
-
-static const struct ide_port_ops hpt3xx_port_ops = {
- .set_pio_mode = hpt3xx_set_pio_mode,
- .set_dma_mode = hpt3xx_set_mode,
- .maskproc = hpt3xx_maskproc,
- .mdma_filter = hpt3xx_mdma_filter,
- .udma_filter = hpt3xx_udma_filter,
- .cable_detect = hpt3xx_cable_detect,
-};
-
-static const struct ide_dma_ops hpt37x_dma_ops = {
- .dma_host_set = ide_dma_host_set,
- .dma_setup = ide_dma_setup,
- .dma_start = ide_dma_start,
- .dma_end = hpt374_dma_end,
- .dma_test_irq = hpt374_dma_test_irq,
- .dma_lost_irq = ide_dma_lost_irq,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_sff_read_status = ide_dma_sff_read_status,
-};
-
-static const struct ide_dma_ops hpt370_dma_ops = {
- .dma_host_set = ide_dma_host_set,
- .dma_setup = ide_dma_setup,
- .dma_start = hpt370_dma_start,
- .dma_end = hpt370_dma_end,
- .dma_test_irq = ide_dma_test_irq,
- .dma_lost_irq = ide_dma_lost_irq,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_clear = hpt370_irq_timeout,
- .dma_sff_read_status = ide_dma_sff_read_status,
-};
-
-static const struct ide_dma_ops hpt36x_dma_ops = {
- .dma_host_set = ide_dma_host_set,
- .dma_setup = ide_dma_setup,
- .dma_start = ide_dma_start,
- .dma_end = ide_dma_end,
- .dma_test_irq = ide_dma_test_irq,
- .dma_lost_irq = hpt366_dma_lost_irq,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_sff_read_status = ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info hpt366_chipsets[] = {
- { /* 0: HPT36x */
- .name = DRV_NAME,
- .init_chipset = init_chipset_hpt366,
- .init_hwif = init_hwif_hpt366,
- .init_dma = init_dma_hpt366,
- /*
- * HPT36x chips have one channel per function and have
- * both channel enable bits located differently and visible
- * to both functions -- really stupid design decision... :-(
- * Bit 4 is for the primary channel, bit 5 for the secondary.
- */
- .enablebits = {{0x50,0x10,0x10}, {0x54,0x04,0x04}},
- .port_ops = &hpt3xx_port_ops,
- .dma_ops = &hpt36x_dma_ops,
- .host_flags = IDE_HFLAGS_HPT3XX | IDE_HFLAG_SINGLE,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- },
- { /* 1: HPT3xx */
- .name = DRV_NAME,
- .init_chipset = init_chipset_hpt366,
- .init_hwif = init_hwif_hpt366,
- .init_dma = init_dma_hpt366,
- .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .port_ops = &hpt3xx_port_ops,
- .dma_ops = &hpt37x_dma_ops,
- .host_flags = IDE_HFLAGS_HPT3XX,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- }
-};
-
-/**
- * hpt366_init_one - called when an HPT366 is found
- * @dev: the hpt366 device
- * @id: the matching pci id
- *
- * Called when the PCI registration layer (or the IDE initialization)
- * finds a device matching our IDE device tables.
- */
-static int hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- const struct hpt_info *info = NULL;
- struct hpt_info *dyn_info;
- struct pci_dev *dev2 = NULL;
- struct ide_port_info d;
- u8 idx = id->driver_data;
- u8 rev = dev->revision;
- int ret;
-
- if ((idx == 0 || idx == 4) && (PCI_FUNC(dev->devfn) & 1))
- return -ENODEV;
-
- switch (idx) {
- case 0:
- if (rev < 3)
- info = &hpt36x;
- else {
- switch (min_t(u8, rev, 6)) {
- case 3: info = &hpt370; break;
- case 4: info = &hpt370a; break;
- case 5: info = &hpt372; break;
- case 6: info = &hpt372n; break;
- }
- idx++;
- }
- break;
- case 1:
- info = (rev > 1) ? &hpt372n : &hpt372a;
- break;
- case 2:
- info = (rev > 1) ? &hpt302n : &hpt302;
- break;
- case 3:
- hpt371_init(dev);
- info = (rev > 1) ? &hpt371n : &hpt371;
- break;
- case 4:
- info = &hpt374;
- break;
- case 5:
- info = &hpt372n;
- break;
- }
-
- printk(KERN_INFO DRV_NAME ": %s chipset detected\n", info->chip_name);
-
- d = hpt366_chipsets[min_t(u8, idx, 1)];
-
- d.udma_mask = info->udma_mask;
-
- /* fixup ->dma_ops for HPT370/HPT370A */
- if (info == &hpt370 || info == &hpt370a)
- d.dma_ops = &hpt370_dma_ops;
-
- if (info == &hpt36x || info == &hpt374)
- dev2 = pci_get_slot(dev->bus, dev->devfn + 1);
-
- dyn_info = kcalloc(dev2 ? 2 : 1, sizeof(*dyn_info), GFP_KERNEL);
- if (dyn_info == NULL) {
- printk(KERN_ERR "%s %s: out of memory!\n",
- d.name, pci_name(dev));
- pci_dev_put(dev2);
- return -ENOMEM;
- }
-
- /*
- * Copy everything from a static "template" structure
- * to just allocated per-chip hpt_info structure.
- */
- memcpy(dyn_info, info, sizeof(*dyn_info));
-
- if (dev2) {
- memcpy(dyn_info + 1, info, sizeof(*dyn_info));
-
- if (info == &hpt374)
- hpt374_init(dev, dev2);
- else {
- if (hpt36x_init(dev, dev2))
- d.host_flags &= ~IDE_HFLAG_NON_BOOTABLE;
- }
-
- ret = ide_pci_init_two(dev, dev2, &d, dyn_info);
- if (ret < 0) {
- pci_dev_put(dev2);
- kfree(dyn_info);
- }
- return ret;
- }
-
- ret = ide_pci_init_one(dev, &d, dyn_info);
- if (ret < 0)
- kfree(dyn_info);
-
- return ret;
-}
-
-static void hpt366_remove(struct pci_dev *dev)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- struct ide_info *info = host->host_priv;
- struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
-
- ide_pci_remove(dev);
- pci_dev_put(dev2);
- kfree(info);
-}
-
-static const struct pci_device_id hpt366_pci_tbl[] = {
- { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), 0 },
- { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), 1 },
- { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), 2 },
- { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371), 3 },
- { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT374), 4 },
- { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), 5 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl);
-
-static struct pci_driver hpt366_pci_driver = {
- .name = "HPT366_IDE",
- .id_table = hpt366_pci_tbl,
- .probe = hpt366_init_one,
- .remove = hpt366_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init hpt366_ide_init(void)
-{
- return ide_pci_register_driver(&hpt366_pci_driver);
-}
-
-static void __exit hpt366_ide_exit(void)
-{
- pci_unregister_driver(&hpt366_pci_driver);
-}
-
-module_init(hpt366_ide_init);
-module_exit(hpt366_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c
deleted file mode 100644
index 743bc3693ac8..000000000000
--- a/drivers/ide/ht6560b.c
+++ /dev/null
@@ -1,383 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1995-2000 Linus Torvalds & author (see below)
- */
-
-/*
- * HT-6560B EIDE-controller support
- * To activate controller support use kernel parameter "ide0=ht6560b".
- * Use hdparm utility to enable PIO mode support.
- *
- * Author: Mikko Ala-Fossi <maf@iki.fi>
- * Jan Evert van Grootheest <j.e.van.grootheest@caiway.nl>
- *
- */
-
-#define DRV_NAME "ht6560b"
-#define HT6560B_VERSION "v0.08"
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-/* #define DEBUG */ /* remove comments for DEBUG messages */
-
-/*
- * The special i/o-port that HT-6560B uses to configuration:
- * bit0 (0x01): "1" selects secondary interface
- * bit2 (0x04): "1" enables FIFO function
- * bit5 (0x20): "1" enables prefetched data read function (???)
- *
- * The special i/o-port that HT-6560A uses to configuration:
- * bit0 (0x01): "1" selects secondary interface
- * bit1 (0x02): "1" enables prefetched data read function
- * bit2 (0x04): "0" enables multi-master system (?)
- * bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time (?)
- */
-#define HT_CONFIG_PORT 0x3e6
-
-static inline u8 HT_CONFIG(ide_drive_t *drive)
-{
- return ((unsigned long)ide_get_drivedata(drive) & 0xff00) >> 8;
-}
-
-/*
- * FIFO + PREFETCH (both a/b-model)
- */
-#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
-/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
-#define HT_SECONDARY_IF 0x01
-#define HT_PREFETCH_MODE 0x20
-
-/*
- * ht6560b Timing values:
- *
- * I reviewed some assembler source listings of htide drivers and found
- * out how they setup those cycle time interfacing values, as they at Holtek
- * call them. IDESETUP.COM that is supplied with the drivers figures out
- * optimal values and fetches those values to drivers. I found out that
- * they use Select register to fetch timings to the ide board right after
- * interface switching. After that it was quite easy to add code to
- * ht6560b.c.
- *
- * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine
- * for hda and hdc. But hdb needed higher values to work, so I guess
- * that sometimes it is necessary to give higher value than IDESETUP
- * gives. [see cmd640.c for an extreme example of this. -ml]
- *
- * Perhaps I should explain something about these timing values:
- * The higher nibble of value is the Recovery Time (rt) and the lower nibble
- * of the value is the Active Time (at). Minimum value 2 is the fastest and
- * the maximum value 15 is the slowest. Default values should be 15 for both.
- * So 0x24 means 2 for rt and 4 for at. Each of the drives should have
- * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or
- * similar. If value is too small there will be all sorts of failures.
- *
- * Timing byte consists of
- * High nibble: Recovery Cycle Time (rt)
- * The valid values range from 2 to 15. The default is 15.
- *
- * Low nibble: Active Cycle Time (at)
- * The valid values range from 2 to 15. The default is 15.
- *
- * You can obtain optimized timing values by running Holtek IDESETUP.COM
- * for DOS. DOS drivers get their timing values from command line, where
- * the first value is the Recovery Time and the second value is the
- * Active Time for each drive. Smaller value gives higher speed.
- * In case of failures you should probably fall back to a higher value.
- */
-static inline u8 HT_TIMING(ide_drive_t *drive)
-{
- return (unsigned long)ide_get_drivedata(drive) & 0x00ff;
-}
-
-#define HT_TIMING_DEFAULT 0xff
-
-/*
- * This routine handles interface switching for the peculiar hardware design
- * on the F.G.I./Holtek HT-6560B VLB IDE interface.
- * The HT-6560B can only enable one IDE port at a time, and requires a
- * silly sequence (below) whenever we switch between primary and secondary.
- */
-
-/*
- * This routine is invoked from ide.c to prepare for access to a given drive.
- */
-static void ht6560b_dev_select(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- unsigned long flags;
- static u8 current_select = 0;
- static u8 current_timing = 0;
- u8 select, timing;
-
- local_irq_save(flags);
-
- select = HT_CONFIG(drive);
- timing = HT_TIMING(drive);
-
- /*
- * Need to enforce prefetch sometimes because otherwise
- * it'll hang (hard).
- */
- if (drive->media != ide_disk ||
- (drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
- select |= HT_PREFETCH_MODE;
-
- if (select != current_select || timing != current_timing) {
- current_select = select;
- current_timing = timing;
- (void)inb(HT_CONFIG_PORT);
- (void)inb(HT_CONFIG_PORT);
- (void)inb(HT_CONFIG_PORT);
- (void)inb(HT_CONFIG_PORT);
- outb(select, HT_CONFIG_PORT);
- /*
- * Set timing for this drive:
- */
- outb(timing, hwif->io_ports.device_addr);
- (void)inb(hwif->io_ports.status_addr);
-#ifdef DEBUG
- printk("ht6560b: %s: select=%#x timing=%#x\n",
- drive->name, select, timing);
-#endif
- }
- local_irq_restore(flags);
-
- outb(drive->select | ATA_DEVICE_OBS, hwif->io_ports.device_addr);
-}
-
-/*
- * Autodetection and initialization of ht6560b
- */
-static int __init try_to_init_ht6560b(void)
-{
- u8 orig_value;
- int i;
-
- /* Autodetect ht6560b */
- if ((orig_value = inb(HT_CONFIG_PORT)) == 0xff)
- return 0;
-
- for (i=3;i>0;i--) {
- outb(0x00, HT_CONFIG_PORT);
- if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
- outb(orig_value, HT_CONFIG_PORT);
- return 0;
- }
- }
- outb(0x00, HT_CONFIG_PORT);
- if ((~inb(HT_CONFIG_PORT))& 0x3f) {
- outb(orig_value, HT_CONFIG_PORT);
- return 0;
- }
- /*
- * Ht6560b autodetected
- */
- outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
- outb(HT_TIMING_DEFAULT, 0x1f6); /* Select register */
- (void)inb(0x1f7); /* Status register */
-
- printk("ht6560b " HT6560B_VERSION
- ": chipset detected and initialized"
-#ifdef DEBUG
- " with debug enabled"
-#endif
- "\n"
- );
- return 1;
-}
-
-static u8 ht_pio2timings(ide_drive_t *drive, const u8 pio)
-{
- int active_time, recovery_time;
- int active_cycles, recovery_cycles;
- int bus_speed = ide_vlb_clk ? ide_vlb_clk : 50;
-
- if (pio) {
- unsigned int cycle_time;
- struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
-
- cycle_time = ide_pio_cycle_time(drive, pio);
-
- /*
- * Just like opti621.c we try to calculate the
- * actual cycle time for recovery and activity
- * according system bus speed.
- */
- active_time = t->active;
- recovery_time = cycle_time - active_time - t->setup;
- /*
- * Cycle times should be Vesa bus cycles
- */
- active_cycles = (active_time * bus_speed + 999) / 1000;
- recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
- /*
- * Upper and lower limits
- */
- if (active_cycles < 2) active_cycles = 2;
- if (recovery_cycles < 2) recovery_cycles = 2;
- if (active_cycles > 15) active_cycles = 15;
- if (recovery_cycles > 15) recovery_cycles = 0; /* 0==16 */
-
-#ifdef DEBUG
- printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time);
-#endif
-
- return (u8)((recovery_cycles << 4) | active_cycles);
- } else {
-
-#ifdef DEBUG
- printk("ht6560b: drive %s setting pio=0\n", drive->name);
-#endif
-
- return HT_TIMING_DEFAULT; /* default setting */
- }
-}
-
-static DEFINE_SPINLOCK(ht6560b_lock);
-
-/*
- * Enable/Disable so called prefetch mode
- */
-static void ht_set_prefetch(ide_drive_t *drive, u8 state)
-{
- unsigned long flags, config;
- int t = HT_PREFETCH_MODE << 8;
-
- spin_lock_irqsave(&ht6560b_lock, flags);
-
- config = (unsigned long)ide_get_drivedata(drive);
-
- /*
- * Prefetch mode and unmask irq seems to conflict
- */
- if (state) {
- config |= t; /* enable prefetch mode */
- drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
- drive->dev_flags &= ~IDE_DFLAG_UNMASK;
- } else {
- config &= ~t; /* disable prefetch mode */
- drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK;
- }
-
- ide_set_drivedata(drive, (void *)config);
-
- spin_unlock_irqrestore(&ht6560b_lock, flags);
-
-#ifdef DEBUG
- printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
-#endif
-}
-
-static void ht6560b_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- unsigned long flags, config;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
- u8 timing;
-
- switch (pio) {
- case 8: /* set prefetch off */
- case 9: /* set prefetch on */
- ht_set_prefetch(drive, pio & 1);
- return;
- }
-
- timing = ht_pio2timings(drive, pio);
-
- spin_lock_irqsave(&ht6560b_lock, flags);
- config = (unsigned long)ide_get_drivedata(drive);
- config &= 0xff00;
- config |= timing;
- ide_set_drivedata(drive, (void *)config);
- spin_unlock_irqrestore(&ht6560b_lock, flags);
-
-#ifdef DEBUG
- printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
-#endif
-}
-
-static void __init ht6560b_init_dev(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- /* Setting default configurations for drives. */
- unsigned long t = (HT_CONFIG_DEFAULT << 8) | HT_TIMING_DEFAULT;
-
- if (hwif->channel)
- t |= (HT_SECONDARY_IF << 8);
-
- ide_set_drivedata(drive, (void *)t);
-}
-
-static bool probe_ht6560b;
-
-module_param_named(probe, probe_ht6560b, bool, 0);
-MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
-
-static const struct ide_tp_ops ht6560b_tp_ops = {
- .exec_command = ide_exec_command,
- .read_status = ide_read_status,
- .read_altstatus = ide_read_altstatus,
- .write_devctl = ide_write_devctl,
-
- .dev_select = ht6560b_dev_select,
- .tf_load = ide_tf_load,
- .tf_read = ide_tf_read,
-
- .input_data = ide_input_data,
- .output_data = ide_output_data,
-};
-
-static const struct ide_port_ops ht6560b_port_ops = {
- .init_dev = ht6560b_init_dev,
- .set_pio_mode = ht6560b_set_pio_mode,
-};
-
-static const struct ide_port_info ht6560b_port_info __initconst = {
- .name = DRV_NAME,
- .chipset = ide_ht6560b,
- .tp_ops = &ht6560b_tp_ops,
- .port_ops = &ht6560b_port_ops,
- .host_flags = IDE_HFLAG_SERIALIZE | /* is this needed? */
- IDE_HFLAG_NO_DMA |
- IDE_HFLAG_ABUSE_PREFETCH,
- .pio_mask = ATA_PIO4,
-};
-
-static int __init ht6560b_init(void)
-{
- if (probe_ht6560b == 0)
- return -ENODEV;
-
- if (!request_region(HT_CONFIG_PORT, 1, DRV_NAME)) {
- printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
- __func__);
- return -ENODEV;
- }
-
- if (!try_to_init_ht6560b()) {
- printk(KERN_NOTICE "%s: HBA not found\n", __func__);
- goto release_region;
- }
-
- return ide_legacy_device_add(&ht6560b_port_info, 0);
-
-release_region:
- release_region(HT_CONFIG_PORT, 1);
- return -ENODEV;
-}
-
-module_init(ht6560b_init);
-
-MODULE_AUTHOR("See Local File");
-MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c
deleted file mode 100644
index 329c7e4bc9d0..000000000000
--- a/drivers/ide/icside.c
+++ /dev/null
@@ -1,692 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 1996-2004 Russell King.
- *
- * Please note that this platform does not support 32-bit IDE IO.
- */
-
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/ide.h>
-#include <linux/dma-mapping.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/scatterlist.h>
-#include <linux/io.h>
-
-#include <asm/dma.h>
-#include <asm/ecard.h>
-
-#define DRV_NAME "icside"
-
-#define ICS_IDENT_OFFSET 0x2280
-
-#define ICS_ARCIN_V5_INTRSTAT 0x0000
-#define ICS_ARCIN_V5_INTROFFSET 0x0004
-#define ICS_ARCIN_V5_IDEOFFSET 0x2800
-#define ICS_ARCIN_V5_IDEALTOFFSET 0x2b80
-#define ICS_ARCIN_V5_IDESTEPPING 6
-
-#define ICS_ARCIN_V6_IDEOFFSET_1 0x2000
-#define ICS_ARCIN_V6_INTROFFSET_1 0x2200
-#define ICS_ARCIN_V6_INTRSTAT_1 0x2290
-#define ICS_ARCIN_V6_IDEALTOFFSET_1 0x2380
-#define ICS_ARCIN_V6_IDEOFFSET_2 0x3000
-#define ICS_ARCIN_V6_INTROFFSET_2 0x3200
-#define ICS_ARCIN_V6_INTRSTAT_2 0x3290
-#define ICS_ARCIN_V6_IDEALTOFFSET_2 0x3380
-#define ICS_ARCIN_V6_IDESTEPPING 6
-
-struct cardinfo {
- unsigned int dataoffset;
- unsigned int ctrloffset;
- unsigned int stepping;
-};
-
-static struct cardinfo icside_cardinfo_v5 = {
- .dataoffset = ICS_ARCIN_V5_IDEOFFSET,
- .ctrloffset = ICS_ARCIN_V5_IDEALTOFFSET,
- .stepping = ICS_ARCIN_V5_IDESTEPPING,
-};
-
-static struct cardinfo icside_cardinfo_v6_1 = {
- .dataoffset = ICS_ARCIN_V6_IDEOFFSET_1,
- .ctrloffset = ICS_ARCIN_V6_IDEALTOFFSET_1,
- .stepping = ICS_ARCIN_V6_IDESTEPPING,
-};
-
-static struct cardinfo icside_cardinfo_v6_2 = {
- .dataoffset = ICS_ARCIN_V6_IDEOFFSET_2,
- .ctrloffset = ICS_ARCIN_V6_IDEALTOFFSET_2,
- .stepping = ICS_ARCIN_V6_IDESTEPPING,
-};
-
-struct icside_state {
- unsigned int channel;
- unsigned int enabled;
- void __iomem *irq_port;
- void __iomem *ioc_base;
- unsigned int sel;
- unsigned int type;
- struct ide_host *host;
-};
-
-#define ICS_TYPE_A3IN 0
-#define ICS_TYPE_A3USER 1
-#define ICS_TYPE_V6 3
-#define ICS_TYPE_V5 15
-#define ICS_TYPE_NOTYPE ((unsigned int)-1)
-
-/* ---------------- Version 5 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose : enable interrupts from card
- */
-static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
- struct icside_state *state = ec->irq_data;
-
- writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
- struct icside_state *state = ec->irq_data;
-
- readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v5 = {
- .irqenable = icside_irqenable_arcin_v5,
- .irqdisable = icside_irqdisable_arcin_v5,
-};
-
-
-/* ---------------- Version 6 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose : enable interrupts from card
- */
-static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
- struct icside_state *state = ec->irq_data;
- void __iomem *base = state->irq_port;
-
- state->enabled = 1;
-
- switch (state->channel) {
- case 0:
- writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
- readb(base + ICS_ARCIN_V6_INTROFFSET_2);
- break;
- case 1:
- writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
- readb(base + ICS_ARCIN_V6_INTROFFSET_1);
- break;
- }
-}
-
-/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
- struct icside_state *state = ec->irq_data;
-
- state->enabled = 0;
-
- readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
- readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
-}
-
-/* Prototype: icside_irqprobe(struct expansion_card *ec)
- * Purpose : detect an active interrupt from card
- */
-static int icside_irqpending_arcin_v6(struct expansion_card *ec)
-{
- struct icside_state *state = ec->irq_data;
-
- return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
- readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v6 = {
- .irqenable = icside_irqenable_arcin_v6,
- .irqdisable = icside_irqdisable_arcin_v6,
- .irqpending = icside_irqpending_arcin_v6,
-};
-
-/*
- * Handle routing of interrupts. This is called before
- * we write the command to the drive.
- */
-static void icside_maskproc(ide_drive_t *drive, int mask)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct expansion_card *ec = ECARD_DEV(hwif->dev);
- struct icside_state *state = ecard_get_drvdata(ec);
- unsigned long flags;
-
- local_irq_save(flags);
-
- state->channel = hwif->channel;
-
- if (state->enabled && !mask) {
- switch (hwif->channel) {
- case 0:
- writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
- readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
- break;
- case 1:
- writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
- readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
- break;
- }
- } else {
- readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
- readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
- }
-
- local_irq_restore(flags);
-}
-
-static const struct ide_port_ops icside_v6_no_dma_port_ops = {
- .maskproc = icside_maskproc,
-};
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
-/*
- * SG-DMA support.
- *
- * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
- * There is only one DMA controller per card, which means that only
- * one drive can be accessed at one time. NOTE! We do not enforce that
- * here, but we rely on the main IDE driver spotting that both
- * interfaces use the same IRQ, which should guarantee this.
- */
-
-/*
- * Configure the IOMD to give the appropriate timings for the transfer
- * mode being requested. We take the advice of the ATA standards, and
- * calculate the cycle time based on the transfer mode, and the EIDE
- * MW DMA specs that the drive provides in the IDENTIFY command.
- *
- * We have the following IOMD DMA modes to choose from:
- *
- * Type Active Recovery Cycle
- * A 250 (250) 312 (550) 562 (800)
- * B 187 250 437
- * C 125 (125) 125 (375) 250 (500)
- * D 62 125 187
- *
- * (figures in brackets are actual measured timings)
- *
- * However, we also need to take care of the read/write active and
- * recovery timings:
- *
- * Read Write
- * Mode Active -- Recovery -- Cycle IOMD type
- * MW0 215 50 215 480 A
- * MW1 80 50 50 150 C
- * MW2 70 25 25 120 C
- */
-static void icside_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- unsigned long cycle_time = 0;
- int use_dma_info = 0;
- const u8 xfer_mode = drive->dma_mode;
-
- switch (xfer_mode) {
- case XFER_MW_DMA_2:
- cycle_time = 250;
- use_dma_info = 1;
- break;
-
- case XFER_MW_DMA_1:
- cycle_time = 250;
- use_dma_info = 1;
- break;
-
- case XFER_MW_DMA_0:
- cycle_time = 480;
- break;
-
- case XFER_SW_DMA_2:
- case XFER_SW_DMA_1:
- case XFER_SW_DMA_0:
- cycle_time = 480;
- break;
- }
-
- /*
- * If we're going to be doing MW_DMA_1 or MW_DMA_2, we should
- * take care to note the values in the ID...
- */
- if (use_dma_info && drive->id[ATA_ID_EIDE_DMA_TIME] > cycle_time)
- cycle_time = drive->id[ATA_ID_EIDE_DMA_TIME];
-
- ide_set_drivedata(drive, (void *)cycle_time);
-
- printk(KERN_INFO "%s: %s selected (peak %luMB/s)\n",
- drive->name, ide_xfer_verbose(xfer_mode),
- 2000 / (cycle_time ? cycle_time : (unsigned long) -1));
-}
-
-static const struct ide_port_ops icside_v6_port_ops = {
- .set_dma_mode = icside_set_dma_mode,
- .maskproc = icside_maskproc,
-};
-
-static void icside_dma_host_set(ide_drive_t *drive, int on)
-{
-}
-
-static int icside_dma_end(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct expansion_card *ec = ECARD_DEV(hwif->dev);
-
- disable_dma(ec->dma);
-
- return get_dma_residue(ec->dma) != 0;
-}
-
-static void icside_dma_start(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct expansion_card *ec = ECARD_DEV(hwif->dev);
-
- /* We can not enable DMA on both channels simultaneously. */
- BUG_ON(dma_channel_active(ec->dma));
- enable_dma(ec->dma);
-}
-
-static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct expansion_card *ec = ECARD_DEV(hwif->dev);
- struct icside_state *state = ecard_get_drvdata(ec);
- unsigned int dma_mode;
-
- if (cmd->tf_flags & IDE_TFLAG_WRITE)
- dma_mode = DMA_MODE_WRITE;
- else
- dma_mode = DMA_MODE_READ;
-
- /*
- * We can not enable DMA on both channels.
- */
- BUG_ON(dma_channel_active(ec->dma));
-
- /*
- * Ensure that we have the right interrupt routed.
- */
- icside_maskproc(drive, 0);
-
- /*
- * Route the DMA signals to the correct interface.
- */
- writeb(state->sel | hwif->channel, state->ioc_base);
-
- /*
- * Select the correct timing for this drive.
- */
- set_dma_speed(ec->dma, (unsigned long)ide_get_drivedata(drive));
-
- /*
- * Tell the DMA engine about the SG table and
- * data direction.
- */
- set_dma_sg(ec->dma, hwif->sg_table, cmd->sg_nents);
- set_dma_mode(ec->dma, dma_mode);
-
- return 0;
-}
-
-static int icside_dma_test_irq(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct expansion_card *ec = ECARD_DEV(hwif->dev);
- struct icside_state *state = ecard_get_drvdata(ec);
-
- return readb(state->irq_port +
- (hwif->channel ?
- ICS_ARCIN_V6_INTRSTAT_2 :
- ICS_ARCIN_V6_INTRSTAT_1)) & 1;
-}
-
-static int icside_dma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
- hwif->dmatable_cpu = NULL;
- hwif->dmatable_dma = 0;
-
- return 0;
-}
-
-static const struct ide_dma_ops icside_v6_dma_ops = {
- .dma_host_set = icside_dma_host_set,
- .dma_setup = icside_dma_setup,
- .dma_start = icside_dma_start,
- .dma_end = icside_dma_end,
- .dma_test_irq = icside_dma_test_irq,
- .dma_lost_irq = ide_dma_lost_irq,
-};
-#endif
-
-static int icside_dma_off_init(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
- return -EOPNOTSUPP;
-}
-
-static void icside_setup_ports(struct ide_hw *hw, void __iomem *base,
- struct cardinfo *info, struct expansion_card *ec)
-{
- unsigned long port = (unsigned long)base + info->dataoffset;
-
- hw->io_ports.data_addr = port;
- hw->io_ports.error_addr = port + (1 << info->stepping);
- hw->io_ports.nsect_addr = port + (2 << info->stepping);
- hw->io_ports.lbal_addr = port + (3 << info->stepping);
- hw->io_ports.lbam_addr = port + (4 << info->stepping);
- hw->io_ports.lbah_addr = port + (5 << info->stepping);
- hw->io_ports.device_addr = port + (6 << info->stepping);
- hw->io_ports.status_addr = port + (7 << info->stepping);
- hw->io_ports.ctl_addr = (unsigned long)base + info->ctrloffset;
-
- hw->irq = ec->irq;
- hw->dev = &ec->dev;
-}
-
-static const struct ide_port_info icside_v5_port_info = {
- .host_flags = IDE_HFLAG_NO_DMA,
- .chipset = ide_acorn,
-};
-
-static int icside_register_v5(struct icside_state *state,
- struct expansion_card *ec)
-{
- void __iomem *base;
- struct ide_host *host;
- struct ide_hw hw, *hws[] = { &hw };
- int ret;
-
- base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
- if (!base)
- return -ENOMEM;
-
- state->irq_port = base;
-
- ec->irqaddr = base + ICS_ARCIN_V5_INTRSTAT;
- ec->irqmask = 1;
-
- ecard_setirq(ec, &icside_ops_arcin_v5, state);
-
- /*
- * Be on the safe side - disable interrupts
- */
- icside_irqdisable_arcin_v5(ec, 0);
-
- icside_setup_ports(&hw, base, &icside_cardinfo_v5, ec);
-
- host = ide_host_alloc(&icside_v5_port_info, hws, 1);
- if (host == NULL)
- return -ENODEV;
-
- state->host = host;
-
- ecard_set_drvdata(ec, state);
-
- ret = ide_host_register(host, &icside_v5_port_info, hws);
- if (ret)
- goto err_free;
-
- return 0;
-err_free:
- ide_host_free(host);
- ecard_set_drvdata(ec, NULL);
- return ret;
-}
-
-static const struct ide_port_info icside_v6_port_info = {
- .init_dma = icside_dma_off_init,
- .port_ops = &icside_v6_no_dma_port_ops,
- .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO,
- .mwdma_mask = ATA_MWDMA2,
- .swdma_mask = ATA_SWDMA2,
- .chipset = ide_acorn,
-};
-
-static int icside_register_v6(struct icside_state *state,
- struct expansion_card *ec)
-{
- void __iomem *ioc_base, *easi_base;
- struct ide_host *host;
- unsigned int sel = 0;
- int ret;
- struct ide_hw hw[2], *hws[] = { &hw[0], &hw[1] };
- struct ide_port_info d = icside_v6_port_info;
-
- ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
- if (!ioc_base) {
- ret = -ENOMEM;
- goto out;
- }
-
- easi_base = ioc_base;
-
- if (ecard_resource_flags(ec, ECARD_RES_EASI)) {
- easi_base = ecardm_iomap(ec, ECARD_RES_EASI, 0, 0);
- if (!easi_base) {
- ret = -ENOMEM;
- goto out;
- }
-
- /*
- * Enable access to the EASI region.
- */
- sel = 1 << 5;
- }
-
- writeb(sel, ioc_base);
-
- ecard_setirq(ec, &icside_ops_arcin_v6, state);
-
- state->irq_port = easi_base;
- state->ioc_base = ioc_base;
- state->sel = sel;
-
- /*
- * Be on the safe side - disable interrupts
- */
- icside_irqdisable_arcin_v6(ec, 0);
-
- icside_setup_ports(&hw[0], easi_base, &icside_cardinfo_v6_1, ec);
- icside_setup_ports(&hw[1], easi_base, &icside_cardinfo_v6_2, ec);
-
- host = ide_host_alloc(&d, hws, 2);
- if (host == NULL)
- return -ENODEV;
-
- state->host = host;
-
- ecard_set_drvdata(ec, state);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
- if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) {
- d.init_dma = icside_dma_init;
- d.port_ops = &icside_v6_port_ops;
- d.dma_ops = &icside_v6_dma_ops;
- }
-#endif
-
- ret = ide_host_register(host, &d, hws);
- if (ret)
- goto err_free;
-
- return 0;
-err_free:
- ide_host_free(host);
- if (d.dma_ops)
- free_dma(ec->dma);
- ecard_set_drvdata(ec, NULL);
-out:
- return ret;
-}
-
-static int icside_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
- struct icside_state *state;
- void __iomem *idmem;
- int ret;
-
- ret = ecard_request_resources(ec);
- if (ret)
- goto out;
-
- state = kzalloc(sizeof(struct icside_state), GFP_KERNEL);
- if (!state) {
- ret = -ENOMEM;
- goto release;
- }
-
- state->type = ICS_TYPE_NOTYPE;
-
- idmem = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
- if (idmem) {
- unsigned int type;
-
- type = readb(idmem + ICS_IDENT_OFFSET) & 1;
- type |= (readb(idmem + ICS_IDENT_OFFSET + 4) & 1) << 1;
- type |= (readb(idmem + ICS_IDENT_OFFSET + 8) & 1) << 2;
- type |= (readb(idmem + ICS_IDENT_OFFSET + 12) & 1) << 3;
- ecardm_iounmap(ec, idmem);
-
- state->type = type;
- }
-
- switch (state->type) {
- case ICS_TYPE_A3IN:
- dev_warn(&ec->dev, "A3IN unsupported\n");
- ret = -ENODEV;
- break;
-
- case ICS_TYPE_A3USER:
- dev_warn(&ec->dev, "A3USER unsupported\n");
- ret = -ENODEV;
- break;
-
- case ICS_TYPE_V5:
- ret = icside_register_v5(state, ec);
- break;
-
- case ICS_TYPE_V6:
- ret = icside_register_v6(state, ec);
- break;
-
- default:
- dev_warn(&ec->dev, "unknown interface type\n");
- ret = -ENODEV;
- break;
- }
-
- if (ret == 0)
- goto out;
-
- kfree(state);
- release:
- ecard_release_resources(ec);
- out:
- return ret;
-}
-
-static void icside_remove(struct expansion_card *ec)
-{
- struct icside_state *state = ecard_get_drvdata(ec);
-
- switch (state->type) {
- case ICS_TYPE_V5:
- /* FIXME: tell IDE to stop using the interface */
-
- /* Disable interrupts */
- icside_irqdisable_arcin_v5(ec, 0);
- break;
-
- case ICS_TYPE_V6:
- /* FIXME: tell IDE to stop using the interface */
- if (ec->dma != NO_DMA)
- free_dma(ec->dma);
-
- /* Disable interrupts */
- icside_irqdisable_arcin_v6(ec, 0);
-
- /* Reset the ROM pointer/EASI selection */
- writeb(0, state->ioc_base);
- break;
- }
-
- ecard_set_drvdata(ec, NULL);
-
- kfree(state);
- ecard_release_resources(ec);
-}
-
-static void icside_shutdown(struct expansion_card *ec)
-{
- struct icside_state *state = ecard_get_drvdata(ec);
- unsigned long flags;
-
- /*
- * Disable interrupts from this card. We need to do
- * this before disabling EASI since we may be accessing
- * this register via that region.
- */
- local_irq_save(flags);
- ec->ops->irqdisable(ec, 0);
- local_irq_restore(flags);
-
- /*
- * Reset the ROM pointer so that we can read the ROM
- * after a soft reboot. This also disables access to
- * the IDE taskfile via the EASI region.
- */
- if (state->ioc_base)
- writeb(0, state->ioc_base);
-}
-
-static const struct ecard_id icside_ids[] = {
- { MANU_ICS, PROD_ICS_IDE },
- { MANU_ICS2, PROD_ICS2_IDE },
- { 0xffff, 0xffff }
-};
-
-static struct ecard_driver icside_driver = {
- .probe = icside_probe,
- .remove = icside_remove,
- .shutdown = icside_shutdown,
- .id_table = icside_ids,
- .drv = {
- .name = "icside",
- },
-};
-
-static int __init icside_init(void)
-{
- return ecard_register_driver(&icside_driver);
-}
-
-static void __exit icside_exit(void)
-{
- ecard_remove_driver(&icside_driver);
-}
-
-MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("ICS IDE driver");
-
-module_init(icside_init);
-module_exit(icside_exit);
diff --git a/drivers/ide/ide-4drives.c b/drivers/ide/ide-4drives.c
deleted file mode 100644
index 06c6215e0cbe..000000000000
--- a/drivers/ide/ide-4drives.c
+++ /dev/null
@@ -1,65 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/ide.h>
-
-#define DRV_NAME "ide-4drives"
-
-static bool probe_4drives;
-
-module_param_named(probe, probe_4drives, bool, 0);
-MODULE_PARM_DESC(probe, "probe for generic IDE chipset with 4 drives/port");
-
-static void ide_4drives_init_dev(ide_drive_t *drive)
-{
- if (drive->hwif->channel)
- drive->select ^= 0x20;
-}
-
-static const struct ide_port_ops ide_4drives_port_ops = {
- .init_dev = ide_4drives_init_dev,
-};
-
-static const struct ide_port_info ide_4drives_port_info = {
- .port_ops = &ide_4drives_port_ops,
- .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA |
- IDE_HFLAG_4DRIVES,
- .chipset = ide_4drives,
-};
-
-static int __init ide_4drives_init(void)
-{
- unsigned long base = 0x1f0, ctl = 0x3f6;
- struct ide_hw hw, *hws[] = { &hw, &hw };
-
- if (probe_4drives == 0)
- return -ENODEV;
-
- if (!request_region(base, 8, DRV_NAME)) {
- printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
- DRV_NAME, base, base + 7);
- return -EBUSY;
- }
-
- if (!request_region(ctl, 1, DRV_NAME)) {
- printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
- DRV_NAME, ctl);
- release_region(base, 8);
- return -EBUSY;
- }
-
- memset(&hw, 0, sizeof(hw));
-
- ide_std_init_ports(&hw, base, ctl);
- hw.irq = 14;
-
- return ide_host_add(&ide_4drives_port_info, hws, 2, NULL);
-}
-
-module_init(ide_4drives_init);
-
-MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("generic IDE chipset with 4 drives/port support");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
deleted file mode 100644
index 05e18d658141..000000000000
--- a/drivers/ide/ide-acpi.c
+++ /dev/null
@@ -1,622 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Provides ACPI support for IDE drives.
- *
- * Copyright (C) 2005 Intel Corp.
- * Copyright (C) 2005 Randy Dunlap
- * Copyright (C) 2006 SUSE Linux Products GmbH
- * Copyright (C) 2006 Hannes Reinecke
- */
-
-#include <linux/acpi.h>
-#include <linux/ata.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/ide.h>
-#include <linux/pci.h>
-#include <linux/dmi.h>
-#include <linux/module.h>
-
-#define REGS_PER_GTF 7
-
-struct GTM_buffer {
- u32 PIO_speed0;
- u32 DMA_speed0;
- u32 PIO_speed1;
- u32 DMA_speed1;
- u32 GTM_flags;
-};
-
-struct ide_acpi_drive_link {
- acpi_handle obj_handle;
- u8 idbuff[512];
-};
-
-struct ide_acpi_hwif_link {
- ide_hwif_t *hwif;
- acpi_handle obj_handle;
- struct GTM_buffer gtm;
- struct ide_acpi_drive_link master;
- struct ide_acpi_drive_link slave;
-};
-
-#undef DEBUGGING
-/* note: adds function name and KERN_DEBUG */
-#ifdef DEBUGGING
-#define DEBPRINT(fmt, args...) \
- printk(KERN_DEBUG "%s: " fmt, __func__, ## args)
-#else
-#define DEBPRINT(fmt, args...) do {} while (0)
-#endif /* DEBUGGING */
-
-static bool ide_noacpi;
-module_param_named(noacpi, ide_noacpi, bool, 0);
-MODULE_PARM_DESC(noacpi, "disable IDE ACPI support");
-
-static bool ide_acpigtf;
-module_param_named(acpigtf, ide_acpigtf, bool, 0);
-MODULE_PARM_DESC(acpigtf, "enable IDE ACPI _GTF support");
-
-static bool ide_acpionboot;
-module_param_named(acpionboot, ide_acpionboot, bool, 0);
-MODULE_PARM_DESC(acpionboot, "call IDE ACPI methods on boot");
-
-static bool ide_noacpi_psx;
-static int no_acpi_psx(const struct dmi_system_id *id)
-{
- ide_noacpi_psx = true;
- printk(KERN_NOTICE"%s detected - disable ACPI _PSx.\n", id->ident);
- return 0;
-}
-
-static const struct dmi_system_id ide_acpi_dmi_table[] = {
- /* Bug 9673. */
- /* We should check if this is because ACPI NVS isn't save/restored. */
- {
- .callback = no_acpi_psx,
- .ident = "HP nx9005",
- .matches = {
- DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies Ltd."),
- DMI_MATCH(DMI_BIOS_VERSION, "KAM1.60")
- },
- },
-
- { } /* terminate list */
-};
-
-int ide_acpi_init(void)
-{
- dmi_check_system(ide_acpi_dmi_table);
- return 0;
-}
-
-bool ide_port_acpi(ide_hwif_t *hwif)
-{
- return ide_noacpi == 0 && hwif->acpidata;
-}
-
-static acpi_handle acpi_get_child(acpi_handle handle, u64 addr)
-{
- struct acpi_device *adev;
-
- if (!handle || acpi_bus_get_device(handle, &adev))
- return NULL;
-
- adev = acpi_find_child_device(adev, addr, false);
- return adev ? adev->handle : NULL;
-}
-
-/**
- * ide_get_dev_handle - finds acpi_handle and PCI device.function
- * @dev: device to locate
- * @handle: returned acpi_handle for @dev
- * @pcidevfn: return PCI device.func for @dev
- *
- * Returns the ACPI object handle to the corresponding PCI device.
- *
- * Returns 0 on success, <0 on error.
- */
-static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
- u64 *pcidevfn)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- unsigned int bus, devnum, func;
- u64 addr;
- acpi_handle dev_handle;
- acpi_status status;
- struct acpi_device_info *dinfo = NULL;
- int ret = -ENODEV;
-
- bus = pdev->bus->number;
- devnum = PCI_SLOT(pdev->devfn);
- func = PCI_FUNC(pdev->devfn);
- /* ACPI _ADR encoding for PCI bus: */
- addr = (u64)(devnum << 16 | func);
-
- DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);
-
- dev_handle = ACPI_HANDLE(dev);
- if (!dev_handle) {
- DEBPRINT("no acpi handle for device\n");
- goto err;
- }
-
- status = acpi_get_object_info(dev_handle, &dinfo);
- if (ACPI_FAILURE(status)) {
- DEBPRINT("get_object_info for device failed\n");
- goto err;
- }
- if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
- dinfo->address == addr) {
- *pcidevfn = addr;
- *handle = dev_handle;
- } else {
- DEBPRINT("get_object_info for device has wrong "
- " address: %llu, should be %u\n",
- dinfo ? (unsigned long long)dinfo->address : -1ULL,
- (unsigned int)addr);
- goto err;
- }
-
- DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n",
- devnum, func, (unsigned long long)addr, *handle);
- ret = 0;
-err:
- kfree(dinfo);
- return ret;
-}
-
-/**
- * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif
- * @hwif: device to locate
- *
- * Retrieves the object handle for a given hwif.
- *
- * Returns handle on success, 0 on error.
- */
-static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
-{
- struct device *dev = hwif->gendev.parent;
- acpi_handle dev_handle;
- u64 pcidevfn;
- acpi_handle chan_handle;
- int err;
-
- DEBPRINT("ENTER: device %s\n", hwif->name);
-
- if (!dev) {
- DEBPRINT("no PCI device for %s\n", hwif->name);
- return NULL;
- }
-
- err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn);
- if (err < 0) {
- DEBPRINT("ide_get_dev_handle failed (%d)\n", err);
- return NULL;
- }
-
- /* get child objects of dev_handle == channel objects,
- * + _their_ children == drive objects */
- /* channel is hwif->channel */
- chan_handle = acpi_get_child(dev_handle, hwif->channel);
- DEBPRINT("chan adr=%d: handle=0x%p\n",
- hwif->channel, chan_handle);
-
- return chan_handle;
-}
-
-/**
- * do_drive_get_GTF - get the drive bootup default taskfile settings
- * @drive: the drive for which the taskfile settings should be retrieved
- * @gtf_length: number of bytes of _GTF data returned at @gtf_address
- * @gtf_address: buffer containing _GTF taskfile arrays
- *
- * The _GTF method has no input parameters.
- * It returns a variable number of register set values (registers
- * hex 1F1..1F7, taskfiles).
- * The <variable number> is not known in advance, so have ACPI-CA
- * allocate the buffer as needed and return it, then free it later.
- *
- * The returned @gtf_length and @gtf_address are only valid if the
- * function return value is 0.
- */
-static int do_drive_get_GTF(ide_drive_t *drive,
- unsigned int *gtf_length, unsigned long *gtf_address,
- unsigned long *obj_loc)
-{
- acpi_status status;
- struct acpi_buffer output;
- union acpi_object *out_obj;
- int err = -ENODEV;
-
- *gtf_length = 0;
- *gtf_address = 0UL;
- *obj_loc = 0UL;
-
- if (!drive->acpidata->obj_handle) {
- DEBPRINT("No ACPI object found for %s\n", drive->name);
- goto out;
- }
-
- /* Setting up output buffer */
- output.length = ACPI_ALLOCATE_BUFFER;
- output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
-
- /* _GTF has no input parameters */
- err = -EIO;
- status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF",
- NULL, &output);
- if (ACPI_FAILURE(status)) {
- printk(KERN_DEBUG
- "%s: Run _GTF error: status = 0x%x\n",
- __func__, status);
- goto out;
- }
-
- if (!output.length || !output.pointer) {
- DEBPRINT("Run _GTF: "
- "length or ptr is NULL (0x%llx, 0x%p)\n",
- (unsigned long long)output.length,
- output.pointer);
- goto out;
- }
-
- out_obj = output.pointer;
- if (out_obj->type != ACPI_TYPE_BUFFER) {
- DEBPRINT("Run _GTF: error: "
- "expected object type of ACPI_TYPE_BUFFER, "
- "got 0x%x\n", out_obj->type);
- err = -ENOENT;
- kfree(output.pointer);
- goto out;
- }
-
- if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
- out_obj->buffer.length % REGS_PER_GTF) {
- printk(KERN_ERR
- "%s: unexpected GTF length (%d) or addr (0x%p)\n",
- __func__, out_obj->buffer.length,
- out_obj->buffer.pointer);
- err = -ENOENT;
- kfree(output.pointer);
- goto out;
- }
-
- *gtf_length = out_obj->buffer.length;
- *gtf_address = (unsigned long)out_obj->buffer.pointer;
- *obj_loc = (unsigned long)out_obj;
- DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",
- *gtf_length, *gtf_address, *obj_loc);
- err = 0;
-out:
- return err;
-}
-
-/**
- * do_drive_set_taskfiles - write the drive taskfile settings from _GTF
- * @drive: the drive to which the taskfile command should be sent
- * @gtf_length: total number of bytes of _GTF taskfiles
- * @gtf_address: location of _GTF taskfile arrays
- *
- * Write {gtf_address, length gtf_length} in groups of
- * REGS_PER_GTF bytes.
- */
-static int do_drive_set_taskfiles(ide_drive_t *drive,
- unsigned int gtf_length,
- unsigned long gtf_address)
-{
- int rc = 0, err;
- int gtf_count = gtf_length / REGS_PER_GTF;
- int ix;
-
- DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n",
- gtf_length, gtf_length, gtf_count, gtf_address);
-
- /* send all taskfile registers (0x1f1-0x1f7) *in*that*order* */
- for (ix = 0; ix < gtf_count; ix++) {
- u8 *gtf = (u8 *)(gtf_address + ix * REGS_PER_GTF);
- struct ide_cmd cmd;
-
- DEBPRINT("(0x1f1-1f7): "
- "hex: %02x %02x %02x %02x %02x %02x %02x\n",
- gtf[0], gtf[1], gtf[2],
- gtf[3], gtf[4], gtf[5], gtf[6]);
-
- if (!ide_acpigtf) {
- DEBPRINT("_GTF execution disabled\n");
- continue;
- }
-
- /* convert GTF to taskfile */
- memset(&cmd, 0, sizeof(cmd));
- memcpy(&cmd.tf.feature, gtf, REGS_PER_GTF);
- cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
-
- err = ide_no_data_taskfile(drive, &cmd);
- if (err) {
- printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
- __func__, err);
- rc = err;
- }
- }
-
- return rc;
-}
-
-/**
- * ide_acpi_exec_tfs - get then write drive taskfile settings
- * @drive: the drive for which the taskfile settings should be
- * written.
- *
- * According to the ACPI spec this should be called after _STM
- * has been evaluated for the interface. Some ACPI vendors interpret
- * that as a hard requirement and modify the taskfile according
- * to the Identify Drive information passed down with _STM.
- * So one should really make sure to call this only after _STM has
- * been executed.
- */
-int ide_acpi_exec_tfs(ide_drive_t *drive)
-{
- int ret;
- unsigned int gtf_length;
- unsigned long gtf_address;
- unsigned long obj_loc;
-
- DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
-
- ret = do_drive_get_GTF(drive, &gtf_length, &gtf_address, &obj_loc);
- if (ret < 0) {
- DEBPRINT("get_GTF error (%d)\n", ret);
- return ret;
- }
-
- DEBPRINT("call set_taskfiles, drive=%s\n", drive->name);
-
- ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address);
- kfree((void *)obj_loc);
- if (ret < 0) {
- DEBPRINT("set_taskfiles error (%d)\n", ret);
- }
-
- DEBPRINT("ret=%d\n", ret);
-
- return ret;
-}
-
-/**
- * ide_acpi_get_timing - get the channel (controller) timings
- * @hwif: target IDE interface (channel)
- *
- * This function executes the _GTM ACPI method for the target channel.
- *
- */
-void ide_acpi_get_timing(ide_hwif_t *hwif)
-{
- acpi_status status;
- struct acpi_buffer output;
- union acpi_object *out_obj;
-
- /* Setting up output buffer for _GTM */
- output.length = ACPI_ALLOCATE_BUFFER;
- output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
-
- /* _GTM has no input parameters */
- status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM",
- NULL, &output);
-
- DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n",
- status, output.pointer,
- (unsigned long long)output.length);
-
- if (ACPI_FAILURE(status)) {
- DEBPRINT("Run _GTM error: status = 0x%x\n", status);
- return;
- }
-
- if (!output.length || !output.pointer) {
- DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n",
- (unsigned long long)output.length,
- output.pointer);
- kfree(output.pointer);
- return;
- }
-
- out_obj = output.pointer;
- if (out_obj->type != ACPI_TYPE_BUFFER) {
- DEBPRINT("Run _GTM: error: "
- "expected object type of ACPI_TYPE_BUFFER, "
- "got 0x%x\n", out_obj->type);
- kfree(output.pointer);
- return;
- }
-
- if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
- out_obj->buffer.length != sizeof(struct GTM_buffer)) {
- printk(KERN_ERR
- "%s: unexpected _GTM length (0x%x)[should be 0x%zx] or "
- "addr (0x%p)\n",
- __func__, out_obj->buffer.length,
- sizeof(struct GTM_buffer), out_obj->buffer.pointer);
- kfree(output.pointer);
- return;
- }
-
- memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer,
- sizeof(struct GTM_buffer));
-
- DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%zx\n",
- out_obj->buffer.pointer, out_obj->buffer.length,
- sizeof(struct GTM_buffer));
-
- DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
- hwif->acpidata->gtm.PIO_speed0,
- hwif->acpidata->gtm.DMA_speed0,
- hwif->acpidata->gtm.PIO_speed1,
- hwif->acpidata->gtm.DMA_speed1,
- hwif->acpidata->gtm.GTM_flags);
-
- kfree(output.pointer);
-}
-
-/**
- * ide_acpi_push_timing - set the channel (controller) timings
- * @hwif: target IDE interface (channel)
- *
- * This function executes the _STM ACPI method for the target channel.
- *
- * _STM requires Identify Drive data, which has to passed as an argument.
- * Unfortunately drive->id is a mangled version which we can't readily
- * use; hence we'll get the information afresh.
- */
-void ide_acpi_push_timing(ide_hwif_t *hwif)
-{
- acpi_status status;
- struct acpi_object_list input;
- union acpi_object in_params[3];
- struct ide_acpi_drive_link *master = &hwif->acpidata->master;
- struct ide_acpi_drive_link *slave = &hwif->acpidata->slave;
-
- /* Give the GTM buffer + drive Identify data to the channel via the
- * _STM method: */
- /* setup input parameters buffer for _STM */
- input.count = 3;
- input.pointer = in_params;
- in_params[0].type = ACPI_TYPE_BUFFER;
- in_params[0].buffer.length = sizeof(struct GTM_buffer);
- in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
- in_params[1].type = ACPI_TYPE_BUFFER;
- in_params[1].buffer.length = ATA_ID_WORDS * 2;
- in_params[1].buffer.pointer = (u8 *)&master->idbuff;
- in_params[2].type = ACPI_TYPE_BUFFER;
- in_params[2].buffer.length = ATA_ID_WORDS * 2;
- in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
- /* Output buffer: _STM has no output */
-
- status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM",
- &input, NULL);
-
- if (ACPI_FAILURE(status)) {
- DEBPRINT("Run _STM error: status = 0x%x\n", status);
- }
- DEBPRINT("_STM status: %d\n", status);
-}
-
-/**
- * ide_acpi_set_state - set the channel power state
- * @hwif: target IDE interface
- * @on: state, on/off
- *
- * This function executes the _PS0/_PS3 ACPI method to set the power state.
- * ACPI spec requires _PS0 when IDE power on and _PS3 when power off
- */
-void ide_acpi_set_state(ide_hwif_t *hwif, int on)
-{
- ide_drive_t *drive;
- int i;
-
- if (ide_noacpi_psx)
- return;
-
- DEBPRINT("ENTER:\n");
-
- /* channel first and then drives for power on and verse versa for power off */
- if (on)
- acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
-
- ide_port_for_each_present_dev(i, drive, hwif) {
- if (drive->acpidata->obj_handle)
- acpi_bus_set_power(drive->acpidata->obj_handle,
- on ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
- }
-
- if (!on)
- acpi_bus_set_power(hwif->acpidata->obj_handle,
- ACPI_STATE_D3_COLD);
-}
-
-/**
- * ide_acpi_init_port - initialize the ACPI link for an IDE interface
- * @hwif: target IDE interface (channel)
- *
- * The ACPI spec is not quite clear when the drive identify buffer
- * should be obtained. Calling IDENTIFY DEVICE during shutdown
- * is not the best of ideas as the drive might already being put to
- * sleep. And obviously we can't call it during resume.
- * So we get the information during startup; but this means that
- * any changes during run-time will be lost after resume.
- */
-void ide_acpi_init_port(ide_hwif_t *hwif)
-{
- hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
- if (!hwif->acpidata)
- return;
-
- hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif);
- if (!hwif->acpidata->obj_handle) {
- DEBPRINT("no ACPI object for %s found\n", hwif->name);
- kfree(hwif->acpidata);
- hwif->acpidata = NULL;
- }
-}
-
-void ide_acpi_port_init_devices(ide_hwif_t *hwif)
-{
- ide_drive_t *drive;
- int i, err;
-
- if (hwif->acpidata == NULL)
- return;
-
- /*
- * The ACPI spec mandates that we send information
- * for both drives, regardless whether they are connected
- * or not.
- */
- hwif->devices[0]->acpidata = &hwif->acpidata->master;
- hwif->devices[1]->acpidata = &hwif->acpidata->slave;
-
- /* get _ADR info for each device */
- ide_port_for_each_present_dev(i, drive, hwif) {
- acpi_handle dev_handle;
-
- DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
- drive->name, hwif->channel, drive->dn & 1);
-
- /* TBD: could also check ACPI object VALID bits */
- dev_handle = acpi_get_child(hwif->acpidata->obj_handle,
- drive->dn & 1);
-
- DEBPRINT("drive %s handle 0x%p\n", drive->name, dev_handle);
-
- drive->acpidata->obj_handle = dev_handle;
- }
-
- /* send IDENTIFY for each device */
- ide_port_for_each_present_dev(i, drive, hwif) {
- err = taskfile_lib_get_identify(drive, drive->acpidata->idbuff);
- if (err)
- DEBPRINT("identify device %s failed (%d)\n",
- drive->name, err);
- }
-
- if (ide_noacpi || ide_acpionboot == 0) {
- DEBPRINT("ACPI methods disabled on boot\n");
- return;
- }
-
- /* ACPI _PS0 before _STM */
- ide_acpi_set_state(hwif, 1);
- /*
- * ACPI requires us to call _STM on startup
- */
- ide_acpi_get_timing(hwif);
- ide_acpi_push_timing(hwif);
-
- ide_port_for_each_present_dev(i, drive, hwif) {
- ide_acpi_exec_tfs(drive);
- }
-}
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c
deleted file mode 100644
index a1ce9f5ac3aa..000000000000
--- a/drivers/ide/ide-atapi.c
+++ /dev/null
@@ -1,756 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * ATAPI support.
- */
-
-#include <linux/kernel.h>
-#include <linux/cdrom.h>
-#include <linux/delay.h>
-#include <linux/export.h>
-#include <linux/ide.h>
-#include <linux/scatterlist.h>
-#include <linux/gfp.h>
-
-#include <scsi/scsi.h>
-
-#define DRV_NAME "ide-atapi"
-#define PFX DRV_NAME ": "
-
-#ifdef DEBUG
-#define debug_log(fmt, args...) \
- printk(KERN_INFO "ide: " fmt, ## args)
-#else
-#define debug_log(fmt, args...) do {} while (0)
-#endif
-
-#define ATAPI_MIN_CDB_BYTES 12
-
-static inline int dev_is_idecd(ide_drive_t *drive)
-{
- return drive->media == ide_cdrom || drive->media == ide_optical;
-}
-
-/*
- * Check whether we can support a device,
- * based on the ATAPI IDENTIFY command results.
- */
-int ide_check_atapi_device(ide_drive_t *drive, const char *s)
-{
- u16 *id = drive->id;
- u8 gcw[2], protocol, device_type, removable, drq_type, packet_size;
-
- *((u16 *)&gcw) = id[ATA_ID_CONFIG];
-
- protocol = (gcw[1] & 0xC0) >> 6;
- device_type = gcw[1] & 0x1F;
- removable = (gcw[0] & 0x80) >> 7;
- drq_type = (gcw[0] & 0x60) >> 5;
- packet_size = gcw[0] & 0x03;
-
-#ifdef CONFIG_PPC
- /* kludge for Apple PowerBook internal zip */
- if (drive->media == ide_floppy && device_type == 5 &&
- !strstr((char *)&id[ATA_ID_PROD], "CD-ROM") &&
- strstr((char *)&id[ATA_ID_PROD], "ZIP"))
- device_type = 0;
-#endif
-
- if (protocol != 2)
- printk(KERN_ERR "%s: %s: protocol (0x%02x) is not ATAPI\n",
- s, drive->name, protocol);
- else if ((drive->media == ide_floppy && device_type != 0) ||
- (drive->media == ide_tape && device_type != 1))
- printk(KERN_ERR "%s: %s: invalid device type (0x%02x)\n",
- s, drive->name, device_type);
- else if (removable == 0)
- printk(KERN_ERR "%s: %s: the removable flag is not set\n",
- s, drive->name);
- else if (drive->media == ide_floppy && drq_type == 3)
- printk(KERN_ERR "%s: %s: sorry, DRQ type (0x%02x) not "
- "supported\n", s, drive->name, drq_type);
- else if (packet_size != 0)
- printk(KERN_ERR "%s: %s: packet size (0x%02x) is not 12 "
- "bytes\n", s, drive->name, packet_size);
- else
- return 1;
- return 0;
-}
-EXPORT_SYMBOL_GPL(ide_check_atapi_device);
-
-void ide_init_pc(struct ide_atapi_pc *pc)
-{
- memset(pc, 0, sizeof(*pc));
-}
-EXPORT_SYMBOL_GPL(ide_init_pc);
-
-/*
- * Add a special packet command request to the tail of the request queue,
- * and wait for it to be serviced.
- */
-int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk,
- struct ide_atapi_pc *pc, void *buf, unsigned int bufflen)
-{
- struct request *rq;
- int error;
-
- rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
- ide_req(rq)->type = ATA_PRIV_MISC;
- ide_req(rq)->special = pc;
-
- if (buf && bufflen) {
- error = blk_rq_map_kern(drive->queue, rq, buf, bufflen,
- GFP_NOIO);
- if (error)
- goto put_req;
- }
-
- memcpy(scsi_req(rq)->cmd, pc->c, 12);
- if (drive->media == ide_tape)
- scsi_req(rq)->cmd[13] = REQ_IDETAPE_PC1;
- blk_execute_rq(disk, rq, 0);
- error = scsi_req(rq)->result ? -EIO : 0;
-put_req:
- blk_put_request(rq);
- return error;
-}
-EXPORT_SYMBOL_GPL(ide_queue_pc_tail);
-
-int ide_do_test_unit_ready(ide_drive_t *drive, struct gendisk *disk)
-{
- struct ide_atapi_pc pc;
-
- ide_init_pc(&pc);
- pc.c[0] = TEST_UNIT_READY;
-
- return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(ide_do_test_unit_ready);
-
-int ide_do_start_stop(ide_drive_t *drive, struct gendisk *disk, int start)
-{
- struct ide_atapi_pc pc;
-
- ide_init_pc(&pc);
- pc.c[0] = START_STOP;
- pc.c[4] = start;
-
- if (drive->media == ide_tape)
- pc.flags |= PC_FLAG_WAIT_FOR_DSC;
-
- return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(ide_do_start_stop);
-
-int ide_set_media_lock(ide_drive_t *drive, struct gendisk *disk, int on)
-{
- struct ide_atapi_pc pc;
-
- if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0)
- return 0;
-
- ide_init_pc(&pc);
- pc.c[0] = ALLOW_MEDIUM_REMOVAL;
- pc.c[4] = on;
-
- return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(ide_set_media_lock);
-
-void ide_create_request_sense_cmd(ide_drive_t *drive, struct ide_atapi_pc *pc)
-{
- ide_init_pc(pc);
- pc->c[0] = REQUEST_SENSE;
- if (drive->media == ide_floppy) {
- pc->c[4] = 255;
- pc->req_xfer = 18;
- } else {
- pc->c[4] = 20;
- pc->req_xfer = 20;
- }
-}
-EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd);
-
-void ide_prep_sense(ide_drive_t *drive, struct request *rq)
-{
- struct request_sense *sense = &drive->sense_data;
- struct request *sense_rq;
- struct scsi_request *req;
- unsigned int cmd_len, sense_len;
- int err;
-
- switch (drive->media) {
- case ide_floppy:
- cmd_len = 255;
- sense_len = 18;
- break;
- case ide_tape:
- cmd_len = 20;
- sense_len = 20;
- break;
- default:
- cmd_len = 18;
- sense_len = 18;
- }
-
- BUG_ON(sense_len > sizeof(*sense));
-
- if (ata_sense_request(rq) || drive->sense_rq_armed)
- return;
-
- sense_rq = drive->sense_rq;
- if (!sense_rq) {
- sense_rq = blk_mq_alloc_request(drive->queue, REQ_OP_DRV_IN,
- BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
- drive->sense_rq = sense_rq;
- }
- req = scsi_req(sense_rq);
-
- memset(sense, 0, sizeof(*sense));
-
- scsi_req_init(req);
-
- err = blk_rq_map_kern(drive->queue, sense_rq, sense, sense_len,
- GFP_NOIO);
- if (unlikely(err)) {
- if (printk_ratelimit())
- printk(KERN_WARNING PFX "%s: failed to map sense "
- "buffer\n", drive->name);
- blk_mq_free_request(sense_rq);
- drive->sense_rq = NULL;
- return;
- }
-
- sense_rq->rq_disk = rq->rq_disk;
- sense_rq->cmd_flags = REQ_OP_DRV_IN;
- ide_req(sense_rq)->type = ATA_PRIV_SENSE;
-
- req->cmd[0] = GPCMD_REQUEST_SENSE;
- req->cmd[4] = cmd_len;
- if (drive->media == ide_tape)
- req->cmd[13] = REQ_IDETAPE_PC1;
-
- drive->sense_rq_armed = true;
-}
-EXPORT_SYMBOL_GPL(ide_prep_sense);
-
-int ide_queue_sense_rq(ide_drive_t *drive, void *special)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct request *sense_rq;
- unsigned long flags;
-
- spin_lock_irqsave(&hwif->lock, flags);
-
- /* deferred failure from ide_prep_sense() */
- if (!drive->sense_rq_armed) {
- printk(KERN_WARNING PFX "%s: error queuing a sense request\n",
- drive->name);
- spin_unlock_irqrestore(&hwif->lock, flags);
- return -ENOMEM;
- }
-
- sense_rq = drive->sense_rq;
- ide_req(sense_rq)->special = special;
- drive->sense_rq_armed = false;
-
- drive->hwif->rq = NULL;
-
- ide_insert_request_head(drive, sense_rq);
- spin_unlock_irqrestore(&hwif->lock, flags);
- return 0;
-}
-EXPORT_SYMBOL_GPL(ide_queue_sense_rq);
-
-/*
- * Called when an error was detected during the last packet command.
- * We queue a request sense packet command at the head of the request
- * queue.
- */
-void ide_retry_pc(ide_drive_t *drive)
-{
- struct request *failed_rq = drive->hwif->rq;
- struct request *sense_rq = drive->sense_rq;
- struct ide_atapi_pc *pc = &drive->request_sense_pc;
-
- (void)ide_read_error(drive);
-
- /* init pc from sense_rq */
- ide_init_pc(pc);
- memcpy(pc->c, scsi_req(sense_rq)->cmd, 12);
-
- if (drive->media == ide_tape)
- drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
-
- /*
- * Push back the failed request and put request sense on top
- * of it. The failed command will be retried after sense data
- * is acquired.
- */
- drive->hwif->rq = NULL;
- ide_requeue_and_plug(drive, failed_rq);
- if (ide_queue_sense_rq(drive, pc))
- ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(failed_rq));
-}
-EXPORT_SYMBOL_GPL(ide_retry_pc);
-
-int ide_cd_expiry(ide_drive_t *drive)
-{
- struct request *rq = drive->hwif->rq;
- unsigned long wait = 0;
-
- debug_log("%s: scsi_req(rq)->cmd[0]: 0x%x\n", __func__, scsi_req(rq)->cmd[0]);
-
- /*
- * Some commands are *slow* and normally take a long time to complete.
- * Usually we can use the ATAPI "disconnect" to bypass this, but not all
- * commands/drives support that. Let ide_timer_expiry keep polling us
- * for these.
- */
- switch (scsi_req(rq)->cmd[0]) {
- case GPCMD_BLANK:
- case GPCMD_FORMAT_UNIT:
- case GPCMD_RESERVE_RZONE_TRACK:
- case GPCMD_CLOSE_TRACK:
- case GPCMD_FLUSH_CACHE:
- wait = ATAPI_WAIT_PC;
- break;
- default:
- if (!(rq->rq_flags & RQF_QUIET))
- printk(KERN_INFO PFX "cmd 0x%x timed out\n",
- scsi_req(rq)->cmd[0]);
- wait = 0;
- break;
- }
- return wait;
-}
-EXPORT_SYMBOL_GPL(ide_cd_expiry);
-
-int ide_cd_get_xferlen(struct request *rq)
-{
- switch (req_op(rq)) {
- default:
- return 32768;
- case REQ_OP_SCSI_IN:
- case REQ_OP_SCSI_OUT:
- return blk_rq_bytes(rq);
- case REQ_OP_DRV_IN:
- case REQ_OP_DRV_OUT:
- switch (ide_req(rq)->type) {
- case ATA_PRIV_PC:
- case ATA_PRIV_SENSE:
- return blk_rq_bytes(rq);
- default:
- return 0;
- }
- }
-}
-EXPORT_SYMBOL_GPL(ide_cd_get_xferlen);
-
-void ide_read_bcount_and_ireason(ide_drive_t *drive, u16 *bcount, u8 *ireason)
-{
- struct ide_taskfile tf;
-
- drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_NSECT |
- IDE_VALID_LBAM | IDE_VALID_LBAH);
-
- *bcount = (tf.lbah << 8) | tf.lbam;
- *ireason = tf.nsect & 3;
-}
-EXPORT_SYMBOL_GPL(ide_read_bcount_and_ireason);
-
-/*
- * Check the contents of the interrupt reason register and attempt to recover if
- * there are problems.
- *
- * Returns:
- * - 0 if everything's ok
- * - 1 if the request has to be terminated.
- */
-int ide_check_ireason(ide_drive_t *drive, struct request *rq, int len,
- int ireason, int rw)
-{
- ide_hwif_t *hwif = drive->hwif;
-
- debug_log("ireason: 0x%x, rw: 0x%x\n", ireason, rw);
-
- if (ireason == (!rw << 1))
- return 0;
- else if (ireason == (rw << 1)) {
- printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n",
- drive->name, __func__);
-
- if (dev_is_idecd(drive))
- ide_pad_transfer(drive, rw, len);
- } else if (!rw && ireason == ATAPI_COD) {
- if (dev_is_idecd(drive)) {
- /*
- * Some drives (ASUS) seem to tell us that status info
- * is available. Just get it and ignore.
- */
- (void)hwif->tp_ops->read_status(hwif);
- return 0;
- }
- } else {
- if (ireason & ATAPI_COD)
- printk(KERN_ERR PFX "%s: CoD != 0 in %s\n", drive->name,
- __func__);
-
- /* drive wants a command packet, or invalid ireason... */
- printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n",
- drive->name, __func__, ireason);
- }
-
- if (dev_is_idecd(drive) && ata_pc_request(rq))
- rq->rq_flags |= RQF_FAILED;
-
- return 1;
-}
-EXPORT_SYMBOL_GPL(ide_check_ireason);
-
-/*
- * This is the usual interrupt handler which will be called during a packet
- * command. We will transfer some of the data (as requested by the drive)
- * and will re-point interrupt handler to us.
- */
-static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
-{
- struct ide_atapi_pc *pc = drive->pc;
- ide_hwif_t *hwif = drive->hwif;
- struct ide_cmd *cmd = &hwif->cmd;
- struct request *rq = hwif->rq;
- const struct ide_tp_ops *tp_ops = hwif->tp_ops;
- unsigned int timeout, done;
- u16 bcount;
- u8 stat, ireason, dsc = 0;
- u8 write = !!(pc->flags & PC_FLAG_WRITING);
-
- debug_log("Enter %s - interrupt handler\n", __func__);
-
- timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
- : WAIT_TAPE_CMD;
-
- /* Clear the interrupt */
- stat = tp_ops->read_status(hwif);
-
- if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
- int rc;
-
- drive->waiting_for_dma = 0;
- rc = hwif->dma_ops->dma_end(drive);
- ide_dma_unmap_sg(drive, cmd);
-
- if (rc || (drive->media == ide_tape && (stat & ATA_ERR))) {
- if (drive->media == ide_floppy)
- printk(KERN_ERR PFX "%s: DMA %s error\n",
- drive->name, rq_data_dir(pc->rq)
- ? "write" : "read");
- pc->flags |= PC_FLAG_DMA_ERROR;
- } else
- scsi_req(rq)->resid_len = 0;
- debug_log("%s: DMA finished\n", drive->name);
- }
-
- /* No more interrupts */
- if ((stat & ATA_DRQ) == 0) {
- int uptodate;
- blk_status_t error;
-
- debug_log("Packet command completed, %d bytes transferred\n",
- blk_rq_bytes(rq));
-
- pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
-
- local_irq_enable_in_hardirq();
-
- if (drive->media == ide_tape &&
- (stat & ATA_ERR) && scsi_req(rq)->cmd[0] == REQUEST_SENSE)
- stat &= ~ATA_ERR;
-
- if ((stat & ATA_ERR) || (pc->flags & PC_FLAG_DMA_ERROR)) {
- /* Error detected */
- debug_log("%s: I/O error\n", drive->name);
-
- if (drive->media != ide_tape)
- scsi_req(pc->rq)->result++;
-
- if (scsi_req(rq)->cmd[0] == REQUEST_SENSE) {
- printk(KERN_ERR PFX "%s: I/O error in request "
- "sense command\n", drive->name);
- return ide_do_reset(drive);
- }
-
- debug_log("[cmd %x]: check condition\n", scsi_req(rq)->cmd[0]);
-
- /* Retry operation */
- ide_retry_pc(drive);
-
- /* queued, but not started */
- return ide_stopped;
- }
- pc->error = 0;
-
- if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0)
- dsc = 1;
-
- /*
- * ->pc_callback() might change rq->data_len for
- * residual count, cache total length.
- */
- done = blk_rq_bytes(rq);
-
- /* Command finished - Call the callback function */
- uptodate = drive->pc_callback(drive, dsc);
-
- if (uptodate == 0)
- drive->failed_pc = NULL;
-
- if (ata_misc_request(rq)) {
- scsi_req(rq)->result = 0;
- error = BLK_STS_OK;
- } else {
-
- if (blk_rq_is_passthrough(rq) && uptodate <= 0) {
- if (scsi_req(rq)->result == 0)
- scsi_req(rq)->result = -EIO;
- }
-
- error = uptodate ? BLK_STS_OK : BLK_STS_IOERR;
- }
-
- ide_complete_rq(drive, error, blk_rq_bytes(rq));
- return ide_stopped;
- }
-
- if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
- pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
- printk(KERN_ERR PFX "%s: The device wants to issue more "
- "interrupts in DMA mode\n", drive->name);
- ide_dma_off(drive);
- return ide_do_reset(drive);
- }
-
- /* Get the number of bytes to transfer on this interrupt. */
- ide_read_bcount_and_ireason(drive, &bcount, &ireason);
-
- if (ide_check_ireason(drive, rq, bcount, ireason, write))
- return ide_do_reset(drive);
-
- done = min_t(unsigned int, bcount, cmd->nleft);
- ide_pio_bytes(drive, cmd, write, done);
-
- /* Update transferred byte count */
- scsi_req(rq)->resid_len -= done;
-
- bcount -= done;
-
- if (bcount)
- ide_pad_transfer(drive, write, bcount);
-
- debug_log("[cmd %x] transferred %d bytes, padded %d bytes, resid: %u\n",
- scsi_req(rq)->cmd[0], done, bcount, scsi_req(rq)->resid_len);
-
- /* And set the interrupt handler again */
- ide_set_handler(drive, ide_pc_intr, timeout);
- return ide_started;
-}
-
-static void ide_init_packet_cmd(struct ide_cmd *cmd, u8 valid_tf,
- u16 bcount, u8 dma)
-{
- cmd->protocol = dma ? ATAPI_PROT_DMA : ATAPI_PROT_PIO;
- cmd->valid.out.tf = IDE_VALID_LBAH | IDE_VALID_LBAM |
- IDE_VALID_FEATURE | valid_tf;
- cmd->tf.command = ATA_CMD_PACKET;
- cmd->tf.feature = dma; /* Use PIO/DMA */
- cmd->tf.lbam = bcount & 0xff;
- cmd->tf.lbah = (bcount >> 8) & 0xff;
-}
-
-static u8 ide_read_ireason(ide_drive_t *drive)
-{
- struct ide_taskfile tf;
-
- drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_NSECT);
-
- return tf.nsect & 3;
-}
-
-static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason)
-{
- int retries = 100;
-
- while (retries-- && ((ireason & ATAPI_COD) == 0 ||
- (ireason & ATAPI_IO))) {
- printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing "
- "a packet command, retrying\n", drive->name);
- udelay(100);
- ireason = ide_read_ireason(drive);
- if (retries == 0) {
- printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing"
- " a packet command, ignoring\n",
- drive->name);
- ireason |= ATAPI_COD;
- ireason &= ~ATAPI_IO;
- }
- }
-
- return ireason;
-}
-
-static int ide_delayed_transfer_pc(ide_drive_t *drive)
-{
- /* Send the actual packet */
- drive->hwif->tp_ops->output_data(drive, NULL, drive->pc->c, 12);
-
- /* Timeout for the packet command */
- return WAIT_FLOPPY_CMD;
-}
-
-static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
-{
- struct ide_atapi_pc *pc;
- ide_hwif_t *hwif = drive->hwif;
- struct request *rq = hwif->rq;
- ide_expiry_t *expiry;
- unsigned int timeout;
- int cmd_len;
- ide_startstop_t startstop;
- u8 ireason;
-
- if (ide_wait_stat(&startstop, drive, ATA_DRQ, ATA_BUSY, WAIT_READY)) {
- printk(KERN_ERR PFX "%s: Strange, packet command initiated yet "
- "DRQ isn't asserted\n", drive->name);
- return startstop;
- }
-
- if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
- if (drive->dma)
- drive->waiting_for_dma = 1;
- }
-
- if (dev_is_idecd(drive)) {
- /* ATAPI commands get padded out to 12 bytes minimum */
- cmd_len = COMMAND_SIZE(scsi_req(rq)->cmd[0]);
- if (cmd_len < ATAPI_MIN_CDB_BYTES)
- cmd_len = ATAPI_MIN_CDB_BYTES;
-
- timeout = rq->timeout;
- expiry = ide_cd_expiry;
- } else {
- pc = drive->pc;
-
- cmd_len = ATAPI_MIN_CDB_BYTES;
-
- /*
- * If necessary schedule the packet transfer to occur 'timeout'
- * milliseconds later in ide_delayed_transfer_pc() after the
- * device says it's ready for a packet.
- */
- if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) {
- timeout = drive->pc_delay;
- expiry = &ide_delayed_transfer_pc;
- } else {
- timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
- : WAIT_TAPE_CMD;
- expiry = NULL;
- }
-
- ireason = ide_read_ireason(drive);
- if (drive->media == ide_tape)
- ireason = ide_wait_ireason(drive, ireason);
-
- if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) {
- printk(KERN_ERR PFX "%s: (IO,CoD) != (0,1) while "
- "issuing a packet command\n", drive->name);
-
- return ide_do_reset(drive);
- }
- }
-
- hwif->expiry = expiry;
-
- /* Set the interrupt routine */
- ide_set_handler(drive,
- (dev_is_idecd(drive) ? drive->irq_handler
- : ide_pc_intr),
- timeout);
-
- /* Send the actual packet */
- if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0)
- hwif->tp_ops->output_data(drive, NULL, scsi_req(rq)->cmd, cmd_len);
-
- /* Begin DMA, if necessary */
- if (dev_is_idecd(drive)) {
- if (drive->dma)
- hwif->dma_ops->dma_start(drive);
- } else {
- if (pc->flags & PC_FLAG_DMA_OK) {
- pc->flags |= PC_FLAG_DMA_IN_PROGRESS;
- hwif->dma_ops->dma_start(drive);
- }
- }
-
- return ide_started;
-}
-
-ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- struct ide_atapi_pc *pc;
- ide_hwif_t *hwif = drive->hwif;
- ide_expiry_t *expiry = NULL;
- struct request *rq = hwif->rq;
- unsigned int timeout, bytes;
- u16 bcount;
- u8 valid_tf;
- u8 drq_int = !!(drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT);
-
- if (dev_is_idecd(drive)) {
- valid_tf = IDE_VALID_NSECT | IDE_VALID_LBAL;
- bcount = ide_cd_get_xferlen(rq);
- expiry = ide_cd_expiry;
- timeout = ATAPI_WAIT_PC;
-
- if (drive->dma)
- drive->dma = !ide_dma_prepare(drive, cmd);
- } else {
- pc = drive->pc;
-
- valid_tf = IDE_VALID_DEVICE;
- bytes = blk_rq_bytes(rq);
- bcount = ((drive->media == ide_tape) ? bytes
- : min_t(unsigned int,
- bytes, 63 * 1024));
-
- /* We haven't transferred any data yet */
- scsi_req(rq)->resid_len = bcount;
-
- if (pc->flags & PC_FLAG_DMA_ERROR) {
- pc->flags &= ~PC_FLAG_DMA_ERROR;
- ide_dma_off(drive);
- }
-
- if (pc->flags & PC_FLAG_DMA_OK)
- drive->dma = !ide_dma_prepare(drive, cmd);
-
- if (!drive->dma)
- pc->flags &= ~PC_FLAG_DMA_OK;
-
- timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
- : WAIT_TAPE_CMD;
- }
-
- ide_init_packet_cmd(cmd, valid_tf, bcount, drive->dma);
-
- (void)do_rw_taskfile(drive, cmd);
-
- if (drq_int) {
- if (drive->dma)
- drive->waiting_for_dma = 0;
- hwif->expiry = expiry;
- }
-
- ide_execute_command(drive, cmd, ide_transfer_pc, timeout);
-
- return drq_int ? ide_started : ide_transfer_pc(drive);
-}
-EXPORT_SYMBOL_GPL(ide_issue_pc);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
deleted file mode 100644
index cffbcc27a34c..000000000000
--- a/drivers/ide/ide-cd.c
+++ /dev/null
@@ -1,1858 +0,0 @@
-/*
- * ATAPI CD-ROM driver.
- *
- * Copyright (C) 1994-1996 Scott Snyder <snyder@fnald0.fnal.gov>
- * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org>
- * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de>
- * Copyright (C) 2005, 2007-2009 Bartlomiej Zolnierkiewicz
- *
- * 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.rst for usage information.
- *
- * Suggestions are welcome. Patches that work are more welcome though. ;-)
- *
- * Documentation:
- * Mt. Fuji (SFF8090 version 4) and ATAPI (SFF-8020i rev 2.6) standards.
- *
- * For historical changelog please see:
- * Documentation/ide/ChangeLog.ide-cd.1994-2004
- */
-
-#define DRV_NAME "ide-cd"
-#define PFX DRV_NAME ": "
-
-#define IDECD_VERSION "5.00"
-
-#include <linux/compat.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched/task_stack.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/cdrom.h>
-#include <linux/ide.h>
-#include <linux/completion.h>
-#include <linux/mutex.h>
-#include <linux/bcd.h>
-
-/* For SCSI -> ATAPI command conversion */
-#include <scsi/scsi.h>
-
-#include <linux/io.h>
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
-
-#include "ide-cd.h"
-
-static DEFINE_MUTEX(ide_cd_mutex);
-static DEFINE_MUTEX(idecd_ref_mutex);
-
-static void ide_cd_release(struct device *);
-
-static struct cdrom_info *ide_cd_get(struct gendisk *disk)
-{
- struct cdrom_info *cd = NULL;
-
- mutex_lock(&idecd_ref_mutex);
- cd = ide_drv_g(disk, cdrom_info);
- if (cd) {
- if (ide_device_get(cd->drive))
- cd = NULL;
- else
- get_device(&cd->dev);
-
- }
- mutex_unlock(&idecd_ref_mutex);
- return cd;
-}
-
-static void ide_cd_put(struct cdrom_info *cd)
-{
- ide_drive_t *drive = cd->drive;
-
- mutex_lock(&idecd_ref_mutex);
- put_device(&cd->dev);
- ide_device_put(drive);
- mutex_unlock(&idecd_ref_mutex);
-}
-
-/*
- * Generic packet command support and error handling routines.
- */
-
-/* Mark that we've seen a media change and invalidate our internal buffers. */
-static void cdrom_saw_media_change(ide_drive_t *drive)
-{
- drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
- drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID;
-}
-
-static int cdrom_log_sense(ide_drive_t *drive, struct request *rq)
-{
- struct request_sense *sense = &drive->sense_data;
- int log = 0;
-
- if (!sense || !rq || (rq->rq_flags & RQF_QUIET))
- return 0;
-
- ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key);
-
- switch (sense->sense_key) {
- case NO_SENSE:
- case RECOVERED_ERROR:
- break;
- case NOT_READY:
- /*
- * don't care about tray state messages for e.g. capacity
- * commands or in-progress or becoming ready
- */
- if (sense->asc == 0x3a || sense->asc == 0x04)
- break;
- log = 1;
- break;
- case ILLEGAL_REQUEST:
- /*
- * don't log START_STOP unit with LoEj set, since we cannot
- * reliably check if drive can auto-close
- */
- if (scsi_req(rq)->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
- break;
- log = 1;
- break;
- case UNIT_ATTENTION:
- /*
- * Make good and sure we've seen this potential media change.
- * Some drives (i.e. Creative) fail to present the correct sense
- * key in the error register.
- */
- cdrom_saw_media_change(drive);
- break;
- default:
- log = 1;
- break;
- }
- return log;
-}
-
-static void cdrom_analyze_sense_data(ide_drive_t *drive,
- struct request *failed_command)
-{
- struct request_sense *sense = &drive->sense_data;
- struct cdrom_info *info = drive->driver_data;
- unsigned long sector;
- unsigned long bio_sectors;
-
- ide_debug_log(IDE_DBG_SENSE, "error_code: 0x%x, sense_key: 0x%x",
- sense->error_code, sense->sense_key);
-
- if (failed_command)
- ide_debug_log(IDE_DBG_SENSE, "failed cmd: 0x%x",
- failed_command->cmd[0]);
-
- if (!cdrom_log_sense(drive, failed_command))
- return;
-
- /*
- * If a read toc is executed for a CD-R or CD-RW medium where the first
- * toc has not been recorded yet, it will fail with 05/24/00 (which is a
- * confusing error)
- */
- if (failed_command && scsi_req(failed_command)->cmd[0] == GPCMD_READ_TOC_PMA_ATIP)
- if (sense->sense_key == 0x05 && sense->asc == 0x24)
- return;
-
- /* current error */
- if (sense->error_code == 0x70) {
- switch (sense->sense_key) {
- case MEDIUM_ERROR:
- case VOLUME_OVERFLOW:
- case ILLEGAL_REQUEST:
- if (!sense->valid)
- break;
- if (failed_command == NULL ||
- blk_rq_is_passthrough(failed_command))
- break;
- sector = (sense->information[0] << 24) |
- (sense->information[1] << 16) |
- (sense->information[2] << 8) |
- (sense->information[3]);
-
- if (queue_logical_block_size(drive->queue) == 2048)
- /* device sector size is 2K */
- sector <<= 2;
-
- bio_sectors = max(bio_sectors(failed_command->bio), 4U);
- sector &= ~(bio_sectors - 1);
-
- /*
- * The SCSI specification allows for the value
- * returned by READ CAPACITY to be up to 75 2K
- * sectors past the last readable block.
- * Therefore, if we hit a medium error within the
- * last 75 2K sectors, we decrease the saved size
- * value.
- */
- if (sector < get_capacity(info->disk) &&
- drive->probed_capacity - sector < 4 * 75)
- set_capacity(info->disk, sector);
- }
- }
-
- ide_cd_log_error(drive->name, failed_command, sense);
-}
-
-static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq)
-{
- /*
- * For ATA_PRIV_SENSE, "ide_req(rq)->special" points to the original
- * failed request. Also, the sense data should be read
- * directly from rq which might be different from the original
- * sense buffer if it got copied during mapping.
- */
- struct request *failed = ide_req(rq)->special;
- void *sense = bio_data(rq->bio);
-
- if (failed) {
- /*
- * Sense is always read into drive->sense_data, copy back to the
- * original request.
- */
- memcpy(scsi_req(failed)->sense, sense, 18);
- scsi_req(failed)->sense_len = scsi_req(rq)->sense_len;
- cdrom_analyze_sense_data(drive, failed);
-
- if (ide_end_rq(drive, failed, BLK_STS_IOERR, blk_rq_bytes(failed)))
- BUG();
- } else
- cdrom_analyze_sense_data(drive, NULL);
-}
-
-
-/*
- * Allow the drive 5 seconds to recover; some devices will return NOT_READY
- * while flushing data from cache.
- *
- * returns: 0 failed (write timeout expired)
- * 1 success
- */
-static int ide_cd_breathe(ide_drive_t *drive, struct request *rq)
-{
-
- struct cdrom_info *info = drive->driver_data;
-
- if (!scsi_req(rq)->result)
- info->write_timeout = jiffies + ATAPI_WAIT_WRITE_BUSY;
-
- scsi_req(rq)->result = 1;
-
- if (time_after(jiffies, info->write_timeout))
- return 0;
- else {
- /*
- * take a breather
- */
- blk_mq_requeue_request(rq, false);
- blk_mq_delay_kick_requeue_list(drive->queue, 1);
- return 1;
- }
-}
-
-static void ide_cd_free_sense(ide_drive_t *drive)
-{
- if (!drive->sense_rq)
- return;
-
- blk_mq_free_request(drive->sense_rq);
- drive->sense_rq = NULL;
- drive->sense_rq_armed = false;
-}
-
-/**
- * Returns:
- * 0: if the request should be continued.
- * 1: if the request will be going through error recovery.
- * 2: if the request should be ended.
- */
-static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct request *rq = hwif->rq;
- int err, sense_key, do_end_request = 0;
-
- /* get the IDE error register */
- err = ide_read_error(drive);
- sense_key = err >> 4;
-
- ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, rq->cmd_type: 0x%x, err: 0x%x, "
- "stat 0x%x",
- rq->cmd[0], rq->cmd_type, err, stat);
-
- if (ata_sense_request(rq)) {
- /*
- * We got an error trying to get sense info from the drive
- * (probably while trying to recover from a former error).
- * Just give up.
- */
- rq->rq_flags |= RQF_FAILED;
- return 2;
- }
-
- /* if we have an error, pass CHECK_CONDITION as the SCSI status byte */
- if (blk_rq_is_scsi(rq) && !scsi_req(rq)->result)
- scsi_req(rq)->result = SAM_STAT_CHECK_CONDITION;
-
- if (blk_noretry_request(rq))
- do_end_request = 1;
-
- switch (sense_key) {
- case NOT_READY:
- if (req_op(rq) == REQ_OP_WRITE) {
- if (ide_cd_breathe(drive, rq))
- return 1;
- } else {
- cdrom_saw_media_change(drive);
-
- if (!blk_rq_is_passthrough(rq) &&
- !(rq->rq_flags & RQF_QUIET))
- printk(KERN_ERR PFX "%s: tray open\n",
- drive->name);
- }
- do_end_request = 1;
- break;
- case UNIT_ATTENTION:
- cdrom_saw_media_change(drive);
-
- if (blk_rq_is_passthrough(rq))
- return 0;
-
- /*
- * Arrange to retry the request but be sure to give up if we've
- * retried too many times.
- */
- if (++scsi_req(rq)->result > ERROR_MAX)
- do_end_request = 1;
- break;
- case ILLEGAL_REQUEST:
- /*
- * Don't print error message for this condition -- SFF8090i
- * indicates that 5/24/00 is the correct response to a request
- * to close the tray if the drive doesn't have that capability.
- *
- * cdrom_log_sense() knows this!
- */
- if (scsi_req(rq)->cmd[0] == GPCMD_START_STOP_UNIT)
- break;
- fallthrough;
- case DATA_PROTECT:
- /*
- * No point in retrying after an illegal request or data
- * protect error.
- */
- if (!(rq->rq_flags & RQF_QUIET))
- ide_dump_status(drive, "command error", stat);
- do_end_request = 1;
- break;
- case MEDIUM_ERROR:
- /*
- * No point in re-trying a zillion times on a bad sector.
- * If we got here the error is not correctable.
- */
- if (!(rq->rq_flags & RQF_QUIET))
- ide_dump_status(drive, "media error "
- "(bad sector)", stat);
- do_end_request = 1;
- break;
- case BLANK_CHECK:
- /* disk appears blank? */
- if (!(rq->rq_flags & RQF_QUIET))
- ide_dump_status(drive, "media error (blank)",
- stat);
- do_end_request = 1;
- break;
- default:
- if (blk_rq_is_passthrough(rq))
- break;
- if (err & ~ATA_ABORTED) {
- /* go to the default handler for other errors */
- ide_error(drive, "cdrom_decode_status", stat);
- return 1;
- } else if (++scsi_req(rq)->result > ERROR_MAX)
- /* we've racked up too many retries, abort */
- do_end_request = 1;
- }
-
- if (blk_rq_is_passthrough(rq)) {
- rq->rq_flags |= RQF_FAILED;
- do_end_request = 1;
- }
-
- /*
- * End a request through request sense analysis when we have sense data.
- * We need this in order to perform end of media processing.
- */
- if (do_end_request)
- goto end_request;
-
- /* if we got a CHECK_CONDITION status, queue a request sense command */
- if (stat & ATA_ERR)
- return ide_queue_sense_rq(drive, NULL) ? 2 : 1;
- return 1;
-
-end_request:
- if (stat & ATA_ERR) {
- hwif->rq = NULL;
- return ide_queue_sense_rq(drive, rq) ? 2 : 1;
- } else
- return 2;
-}
-
-static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- struct request *rq = cmd->rq;
-
- ide_debug_log(IDE_DBG_FUNC, "rq->cmd[0]: 0x%x", rq->cmd[0]);
-
- /*
- * Some of the trailing request sense fields are optional,
- * and some drives don't send them. Sigh.
- */
- if (scsi_req(rq)->cmd[0] == GPCMD_REQUEST_SENSE &&
- cmd->nleft > 0 && cmd->nleft <= 5)
- cmd->nleft = 0;
-}
-
-int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
- int write, void *buffer, unsigned *bufflen,
- struct scsi_sense_hdr *sshdr, int timeout,
- req_flags_t rq_flags)
-{
- struct cdrom_info *info = drive->driver_data;
- struct scsi_sense_hdr local_sshdr;
- int retries = 10;
- bool failed;
-
- ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x, timeout: %d, "
- "rq_flags: 0x%x",
- cmd[0], write, timeout, rq_flags);
-
- if (!sshdr)
- sshdr = &local_sshdr;
-
- /* start of retry loop */
- do {
- struct request *rq;
- int error;
- bool delay = false;
-
- rq = blk_get_request(drive->queue,
- write ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
- memcpy(scsi_req(rq)->cmd, cmd, BLK_MAX_CDB);
- ide_req(rq)->type = ATA_PRIV_PC;
- rq->rq_flags |= rq_flags;
- rq->timeout = timeout;
- if (buffer) {
- error = blk_rq_map_kern(drive->queue, rq, buffer,
- *bufflen, GFP_NOIO);
- if (error) {
- blk_put_request(rq);
- return error;
- }
- }
-
- blk_execute_rq(info->disk, rq, 0);
- error = scsi_req(rq)->result ? -EIO : 0;
-
- if (buffer)
- *bufflen = scsi_req(rq)->resid_len;
- scsi_normalize_sense(scsi_req(rq)->sense,
- scsi_req(rq)->sense_len, sshdr);
-
- /*
- * FIXME: we should probably abort/retry or something in case of
- * failure.
- */
- failed = (rq->rq_flags & RQF_FAILED) != 0;
- if (failed) {
- /*
- * The request failed. Retry if it was due to a unit
- * attention status (usually means media was changed).
- */
- if (sshdr->sense_key == UNIT_ATTENTION)
- cdrom_saw_media_change(drive);
- else if (sshdr->sense_key == NOT_READY &&
- sshdr->asc == 4 && sshdr->ascq != 4) {
- /*
- * The drive is in the process of loading
- * a disk. Retry, but wait a little to give
- * the drive time to complete the load.
- */
- delay = true;
- } else {
- /* otherwise, don't retry */
- retries = 0;
- }
- --retries;
- }
- blk_put_request(rq);
- if (delay)
- ssleep(2);
- } while (failed && retries >= 0);
-
- /* return an error if the command failed */
- return failed ? -EIO : 0;
-}
-
-/*
- * returns true if rq has been completed
- */
-static bool ide_cd_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- unsigned int nr_bytes = cmd->nbytes - cmd->nleft;
-
- if (cmd->tf_flags & IDE_TFLAG_WRITE)
- nr_bytes -= cmd->last_xfer_len;
-
- if (nr_bytes > 0) {
- ide_complete_rq(drive, BLK_STS_OK, nr_bytes);
- return true;
- }
-
- return false;
-}
-
-/* standard prep_rq that builds 10 byte cmds */
-static bool ide_cdrom_prep_fs(struct request_queue *q, struct request *rq)
-{
- int hard_sect = queue_logical_block_size(q);
- long block = (long)blk_rq_pos(rq) / (hard_sect >> 9);
- unsigned long blocks = blk_rq_sectors(rq) / (hard_sect >> 9);
- struct scsi_request *req = scsi_req(rq);
-
- if (rq_data_dir(rq) == READ)
- req->cmd[0] = GPCMD_READ_10;
- else
- req->cmd[0] = GPCMD_WRITE_10;
-
- /*
- * fill in lba
- */
- req->cmd[2] = (block >> 24) & 0xff;
- req->cmd[3] = (block >> 16) & 0xff;
- req->cmd[4] = (block >> 8) & 0xff;
- req->cmd[5] = block & 0xff;
-
- /*
- * and transfer length
- */
- req->cmd[7] = (blocks >> 8) & 0xff;
- req->cmd[8] = blocks & 0xff;
- req->cmd_len = 10;
- return true;
-}
-
-/*
- * Most of the SCSI commands are supported directly by ATAPI devices.
- * This transform handles the few exceptions.
- */
-static bool ide_cdrom_prep_pc(struct request *rq)
-{
- u8 *c = scsi_req(rq)->cmd;
-
- /* transform 6-byte read/write commands to the 10-byte version */
- if (c[0] == READ_6 || c[0] == WRITE_6) {
- c[8] = c[4];
- c[5] = c[3];
- c[4] = c[2];
- c[3] = c[1] & 0x1f;
- c[2] = 0;
- c[1] &= 0xe0;
- c[0] += (READ_10 - READ_6);
- scsi_req(rq)->cmd_len = 10;
- return true;
- }
-
- /*
- * it's silly to pretend we understand 6-byte sense commands, just
- * reject with ILLEGAL_REQUEST and the caller should take the
- * appropriate action
- */
- if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
- scsi_req(rq)->result = ILLEGAL_REQUEST;
- return false;
- }
-
- return true;
-}
-
-static bool ide_cdrom_prep_rq(ide_drive_t *drive, struct request *rq)
-{
- if (!blk_rq_is_passthrough(rq)) {
- scsi_req_init(scsi_req(rq));
-
- return ide_cdrom_prep_fs(drive->queue, rq);
- } else if (blk_rq_is_scsi(rq))
- return ide_cdrom_prep_pc(rq);
-
- return true;
-}
-
-static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct ide_cmd *cmd = &hwif->cmd;
- struct request *rq = hwif->rq;
- ide_expiry_t *expiry = NULL;
- int dma_error = 0, dma, thislen, uptodate = 0;
- int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc = 0;
- int sense = ata_sense_request(rq);
- unsigned int timeout;
- u16 len;
- u8 ireason, stat;
-
- ide_debug_log(IDE_DBG_PC, "cmd: 0x%x, write: 0x%x", rq->cmd[0], write);
-
- /* check for errors */
- dma = drive->dma;
- if (dma) {
- drive->dma = 0;
- drive->waiting_for_dma = 0;
- dma_error = hwif->dma_ops->dma_end(drive);
- ide_dma_unmap_sg(drive, cmd);
- if (dma_error) {
- printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name,
- write ? "write" : "read");
- ide_dma_off(drive);
- }
- }
-
- /* check status */
- stat = hwif->tp_ops->read_status(hwif);
-
- if (!OK_STAT(stat, 0, BAD_R_STAT)) {
- rc = cdrom_decode_status(drive, stat);
- if (rc) {
- if (rc == 2)
- goto out_end;
- return ide_stopped;
- }
- }
-
- /* using dma, transfer is complete now */
- if (dma) {
- if (dma_error)
- return ide_error(drive, "dma error", stat);
- uptodate = 1;
- goto out_end;
- }
-
- ide_read_bcount_and_ireason(drive, &len, &ireason);
-
- thislen = !blk_rq_is_passthrough(rq) ? len : cmd->nleft;
- if (thislen > len)
- thislen = len;
-
- ide_debug_log(IDE_DBG_PC, "DRQ: stat: 0x%x, thislen: %d",
- stat, thislen);
-
- /* If DRQ is clear, the command has completed. */
- if ((stat & ATA_DRQ) == 0) {
- switch (req_op(rq)) {
- default:
- /*
- * If we're not done reading/writing, complain.
- * Otherwise, complete the command normally.
- */
- uptodate = 1;
- if (cmd->nleft > 0) {
- printk(KERN_ERR PFX "%s: %s: data underrun "
- "(%u bytes)\n", drive->name, __func__,
- cmd->nleft);
- if (!write)
- rq->rq_flags |= RQF_FAILED;
- uptodate = 0;
- }
- goto out_end;
- case REQ_OP_DRV_IN:
- case REQ_OP_DRV_OUT:
- ide_cd_request_sense_fixup(drive, cmd);
-
- uptodate = cmd->nleft ? 0 : 1;
-
- /*
- * suck out the remaining bytes from the drive in an
- * attempt to complete the data xfer. (see BZ#13399)
- */
- if (!(stat & ATA_ERR) && !uptodate && thislen) {
- ide_pio_bytes(drive, cmd, write, thislen);
- uptodate = cmd->nleft ? 0 : 1;
- }
-
- if (!uptodate)
- rq->rq_flags |= RQF_FAILED;
- goto out_end;
- case REQ_OP_SCSI_IN:
- case REQ_OP_SCSI_OUT:
- goto out_end;
- }
- }
-
- rc = ide_check_ireason(drive, rq, len, ireason, write);
- if (rc)
- goto out_end;
-
- cmd->last_xfer_len = 0;
-
- ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, "
- "ireason: 0x%x",
- rq->cmd_type, ireason);
-
- /* transfer data */
- while (thislen > 0) {
- int blen = min_t(int, thislen, cmd->nleft);
-
- if (cmd->nleft == 0)
- break;
-
- ide_pio_bytes(drive, cmd, write, blen);
- cmd->last_xfer_len += blen;
-
- thislen -= blen;
- len -= blen;
-
- if (sense && write == 0)
- scsi_req(rq)->sense_len += blen;
- }
-
- /* pad, if necessary */
- if (len > 0) {
- if (blk_rq_is_passthrough(rq) || write == 0)
- ide_pad_transfer(drive, write, len);
- else {
- printk(KERN_ERR PFX "%s: confused, missing data\n",
- drive->name);
- blk_dump_rq_flags(rq, "cdrom_newpc_intr");
- }
- }
-
- switch (req_op(rq)) {
- case REQ_OP_SCSI_IN:
- case REQ_OP_SCSI_OUT:
- timeout = rq->timeout;
- break;
- case REQ_OP_DRV_IN:
- case REQ_OP_DRV_OUT:
- expiry = ide_cd_expiry;
- fallthrough;
- default:
- timeout = ATAPI_WAIT_PC;
- break;
- }
-
- hwif->expiry = expiry;
- ide_set_handler(drive, cdrom_newpc_intr, timeout);
- return ide_started;
-
-out_end:
- if (blk_rq_is_scsi(rq) && rc == 0) {
- scsi_req(rq)->resid_len = 0;
- blk_mq_end_request(rq, BLK_STS_OK);
- hwif->rq = NULL;
- } else {
- if (sense && uptodate)
- ide_cd_complete_failed_rq(drive, rq);
-
- if (!blk_rq_is_passthrough(rq)) {
- if (cmd->nleft == 0)
- uptodate = 1;
- } else {
- if (uptodate <= 0 && scsi_req(rq)->result == 0)
- scsi_req(rq)->result = -EIO;
- }
-
- if (uptodate == 0 && rq->bio)
- if (ide_cd_error_cmd(drive, cmd))
- return ide_stopped;
-
- /* make sure it's fully ended */
- if (blk_rq_is_passthrough(rq)) {
- scsi_req(rq)->resid_len -= cmd->nbytes - cmd->nleft;
- if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE))
- scsi_req(rq)->resid_len += cmd->last_xfer_len;
- }
-
- ide_complete_rq(drive, uptodate ? BLK_STS_OK : BLK_STS_IOERR, blk_rq_bytes(rq));
-
- if (sense && rc == 2)
- ide_error(drive, "request sense failure", stat);
- }
-
- ide_cd_free_sense(drive);
- return ide_stopped;
-}
-
-static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
-{
- struct cdrom_info *cd = drive->driver_data;
- struct request_queue *q = drive->queue;
- int write = rq_data_dir(rq) == WRITE;
- unsigned short sectors_per_frame =
- queue_logical_block_size(q) >> SECTOR_SHIFT;
-
- ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, "
- "secs_per_frame: %u",
- rq->cmd[0], rq->cmd_flags, sectors_per_frame);
-
- if (write) {
- /* disk has become write protected */
- if (get_disk_ro(cd->disk))
- return ide_stopped;
- } else {
- /*
- * We may be retrying this request after an error. Fix up any
- * weirdness which might be present in the request packet.
- */
- ide_cdrom_prep_rq(drive, rq);
- }
-
- /* fs requests *must* be hardware frame aligned */
- if ((blk_rq_sectors(rq) & (sectors_per_frame - 1)) ||
- (blk_rq_pos(rq) & (sectors_per_frame - 1)))
- return ide_stopped;
-
- /* use DMA, if possible */
- drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
-
- if (write)
- cd->devinfo.media_written = 1;
-
- rq->timeout = ATAPI_WAIT_PC;
-
- return ide_started;
-}
-
-static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
-{
-
- ide_debug_log(IDE_DBG_PC, "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x",
- rq->cmd[0], rq->cmd_type);
-
- if (blk_rq_is_scsi(rq))
- rq->rq_flags |= RQF_QUIET;
- else
- rq->rq_flags &= ~RQF_FAILED;
-
- drive->dma = 0;
-
- /* sg request */
- if (rq->bio) {
- struct request_queue *q = drive->queue;
- char *buf = bio_data(rq->bio);
- unsigned int alignment;
-
- drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
-
- /*
- * check if dma is safe
- *
- * NOTE! The "len" and "addr" checks should possibly have
- * separate masks.
- */
- alignment = queue_dma_alignment(q) | q->dma_pad_mask;
- if ((unsigned long)buf & alignment
- || blk_rq_bytes(rq) & q->dma_pad_mask
- || object_is_on_stack(buf))
- drive->dma = 0;
- }
-}
-
-static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
- sector_t block)
-{
- struct ide_cmd cmd;
- int uptodate = 0;
- unsigned int nsectors;
-
- ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, block: %llu",
- rq->cmd[0], (unsigned long long)block);
-
- if (drive->debug_mask & IDE_DBG_RQ)
- blk_dump_rq_flags(rq, "ide_cd_do_request");
-
- switch (req_op(rq)) {
- default:
- if (cdrom_start_rw(drive, rq) == ide_stopped)
- goto out_end;
- break;
- case REQ_OP_SCSI_IN:
- case REQ_OP_SCSI_OUT:
- handle_pc:
- if (!rq->timeout)
- rq->timeout = ATAPI_WAIT_PC;
- cdrom_do_block_pc(drive, rq);
- break;
- case REQ_OP_DRV_IN:
- case REQ_OP_DRV_OUT:
- switch (ide_req(rq)->type) {
- case ATA_PRIV_MISC:
- /* right now this can only be a reset... */
- uptodate = 1;
- goto out_end;
- case ATA_PRIV_SENSE:
- case ATA_PRIV_PC:
- goto handle_pc;
- default:
- BUG();
- }
- }
-
- /* prepare sense request for this command */
- ide_prep_sense(drive, rq);
-
- memset(&cmd, 0, sizeof(cmd));
-
- if (rq_data_dir(rq))
- cmd.tf_flags |= IDE_TFLAG_WRITE;
-
- cmd.rq = rq;
-
- if (!blk_rq_is_passthrough(rq) || blk_rq_bytes(rq)) {
- ide_init_sg_cmd(&cmd, blk_rq_bytes(rq));
- ide_map_sg(drive, &cmd);
- }
-
- return ide_issue_pc(drive, &cmd);
-out_end:
- nsectors = blk_rq_sectors(rq);
-
- if (nsectors == 0)
- nsectors = 1;
-
- ide_complete_rq(drive, uptodate ? BLK_STS_OK : BLK_STS_IOERR, nsectors << 9);
-
- return ide_stopped;
-}
-
-/*
- * Ioctl handling.
- *
- * Routines which queue packet commands take as a final argument a pointer to a
- * request_sense struct. If execution of the command results in an error with a
- * CHECK CONDITION status, this structure will be filled with the results of the
- * subsequent request sense command. The pointer can also be NULL, in which case
- * no sense information is returned.
- */
-static void msf_from_bcd(struct atapi_msf *msf)
-{
- msf->minute = bcd2bin(msf->minute);
- msf->second = bcd2bin(msf->second);
- msf->frame = bcd2bin(msf->frame);
-}
-
-int cdrom_check_status(ide_drive_t *drive, struct scsi_sense_hdr *sshdr)
-{
- struct cdrom_info *info = drive->driver_data;
- struct cdrom_device_info *cdi;
- unsigned char cmd[BLK_MAX_CDB];
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- if (!info)
- return -EIO;
-
- cdi = &info->devinfo;
-
- memset(cmd, 0, BLK_MAX_CDB);
- cmd[0] = GPCMD_TEST_UNIT_READY;
-
- /*
- * Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to switch CDs
- * instead of supporting the LOAD_UNLOAD opcode.
- */
- cmd[7] = cdi->sanyo_slot % 3;
-
- return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, sshdr, 0, RQF_QUIET);
-}
-
-static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
- unsigned long *sectors_per_frame)
-{
- struct {
- __be32 lba;
- __be32 blocklen;
- } capbuf;
-
- int stat;
- unsigned char cmd[BLK_MAX_CDB];
- unsigned len = sizeof(capbuf);
- u32 blocklen;
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- memset(cmd, 0, BLK_MAX_CDB);
- cmd[0] = GPCMD_READ_CDVD_CAPACITY;
-
- stat = ide_cd_queue_pc(drive, cmd, 0, &capbuf, &len, NULL, 0,
- RQF_QUIET);
- if (stat)
- return stat;
-
- /*
- * Sanity check the given block size, in so far as making
- * sure the sectors_per_frame we give to the caller won't
- * end up being bogus.
- */
- blocklen = be32_to_cpu(capbuf.blocklen);
- blocklen = (blocklen >> SECTOR_SHIFT) << SECTOR_SHIFT;
- switch (blocklen) {
- case 512:
- case 1024:
- case 2048:
- case 4096:
- break;
- default:
- printk_once(KERN_ERR PFX "%s: weird block size %u; "
- "setting default block size to 2048\n",
- drive->name, blocklen);
- blocklen = 2048;
- break;
- }
-
- *capacity = 1 + be32_to_cpu(capbuf.lba);
- *sectors_per_frame = blocklen >> SECTOR_SHIFT;
-
- ide_debug_log(IDE_DBG_PROBE, "cap: %lu, sectors_per_frame: %lu",
- *capacity, *sectors_per_frame);
-
- return 0;
-}
-
-static int ide_cdrom_read_tocentry(ide_drive_t *drive, int trackno,
- int msf_flag, int format, char *buf, int buflen)
-{
- unsigned char cmd[BLK_MAX_CDB];
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- memset(cmd, 0, BLK_MAX_CDB);
-
- cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
- cmd[6] = trackno;
- cmd[7] = (buflen >> 8);
- cmd[8] = (buflen & 0xff);
- cmd[9] = (format << 6);
-
- if (msf_flag)
- cmd[1] = 2;
-
- return ide_cd_queue_pc(drive, cmd, 0, buf, &buflen, NULL, 0, RQF_QUIET);
-}
-
-/* Try to read the entire TOC for the disk into our internal buffer. */
-int ide_cd_read_toc(ide_drive_t *drive)
-{
- int stat, ntracks, i;
- struct cdrom_info *info = drive->driver_data;
- struct cdrom_device_info *cdi = &info->devinfo;
- struct atapi_toc *toc = info->toc;
- struct {
- struct atapi_toc_header hdr;
- struct atapi_toc_entry ent;
- } ms_tmp;
- long last_written;
- unsigned long sectors_per_frame = SECTORS_PER_FRAME;
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- if (toc == NULL) {
- /* try to allocate space */
- toc = kmalloc(sizeof(struct atapi_toc), GFP_KERNEL);
- if (toc == NULL) {
- printk(KERN_ERR PFX "%s: No cdrom TOC buffer!\n",
- drive->name);
- return -ENOMEM;
- }
- info->toc = toc;
- }
-
- /*
- * Check to see if the existing data is still valid. If it is,
- * just return.
- */
- (void) cdrom_check_status(drive, NULL);
-
- if (drive->atapi_flags & IDE_AFLAG_TOC_VALID)
- return 0;
-
- /* try to get the total cdrom capacity and sector size */
- stat = cdrom_read_capacity(drive, &toc->capacity, &sectors_per_frame);
- if (stat)
- toc->capacity = 0x1fffff;
-
- set_capacity(info->disk, toc->capacity * sectors_per_frame);
- /* save a private copy of the TOC capacity for error handling */
- drive->probed_capacity = toc->capacity * sectors_per_frame;
-
- blk_queue_logical_block_size(drive->queue,
- sectors_per_frame << SECTOR_SHIFT);
-
- /* first read just the header, so we know how long the TOC is */
- stat = ide_cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr,
- sizeof(struct atapi_toc_header));
- if (stat)
- return stat;
-
- if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) {
- toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
- toc->hdr.last_track = bcd2bin(toc->hdr.last_track);
- }
-
- ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
- if (ntracks <= 0)
- return -EIO;
- if (ntracks > MAX_TRACKS)
- ntracks = MAX_TRACKS;
-
- /* now read the whole schmeer */
- stat = ide_cdrom_read_tocentry(drive, toc->hdr.first_track, 1, 0,
- (char *)&toc->hdr,
- sizeof(struct atapi_toc_header) +
- (ntracks + 1) *
- sizeof(struct atapi_toc_entry));
-
- if (stat && toc->hdr.first_track > 1) {
- /*
- * Cds with CDI tracks only don't have any TOC entries, despite
- * of this the returned values are
- * first_track == last_track = number of CDI tracks + 1,
- * so that this case is indistinguishable from the same layout
- * plus an additional audio track. If we get an error for the
- * regular case, we assume a CDI without additional audio
- * tracks. In this case the readable TOC is empty (CDI tracks
- * are not included) and only holds the Leadout entry.
- *
- * Heiko Eißfeldt.
- */
- ntracks = 0;
- stat = ide_cdrom_read_tocentry(drive, CDROM_LEADOUT, 1, 0,
- (char *)&toc->hdr,
- sizeof(struct atapi_toc_header) +
- (ntracks + 1) *
- sizeof(struct atapi_toc_entry));
- if (stat)
- return stat;
-
- if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) {
- toc->hdr.first_track = (u8)bin2bcd(CDROM_LEADOUT);
- toc->hdr.last_track = (u8)bin2bcd(CDROM_LEADOUT);
- } else {
- toc->hdr.first_track = CDROM_LEADOUT;
- toc->hdr.last_track = CDROM_LEADOUT;
- }
- }
-
- if (stat)
- return stat;
-
- toc->hdr.toc_length = be16_to_cpu(toc->hdr.toc_length);
-
- if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) {
- toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
- toc->hdr.last_track = bcd2bin(toc->hdr.last_track);
- }
-
- for (i = 0; i <= ntracks; i++) {
- if (drive->atapi_flags & IDE_AFLAG_TOCADDR_AS_BCD) {
- if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD)
- toc->ent[i].track = bcd2bin(toc->ent[i].track);
- msf_from_bcd(&toc->ent[i].addr.msf);
- }
- toc->ent[i].addr.lba = msf_to_lba(toc->ent[i].addr.msf.minute,
- toc->ent[i].addr.msf.second,
- toc->ent[i].addr.msf.frame);
- }
-
- if (toc->hdr.first_track != CDROM_LEADOUT) {
- /* read the multisession information */
- stat = ide_cdrom_read_tocentry(drive, 0, 0, 1, (char *)&ms_tmp,
- sizeof(ms_tmp));
- if (stat)
- return stat;
-
- toc->last_session_lba = be32_to_cpu(ms_tmp.ent.addr.lba);
- } else {
- ms_tmp.hdr.last_track = CDROM_LEADOUT;
- ms_tmp.hdr.first_track = ms_tmp.hdr.last_track;
- toc->last_session_lba = msf_to_lba(0, 2, 0); /* 0m 2s 0f */
- }
-
- if (drive->atapi_flags & IDE_AFLAG_TOCADDR_AS_BCD) {
- /* re-read multisession information using MSF format */
- stat = ide_cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp,
- sizeof(ms_tmp));
- if (stat)
- return stat;
-
- msf_from_bcd(&ms_tmp.ent.addr.msf);
- toc->last_session_lba = msf_to_lba(ms_tmp.ent.addr.msf.minute,
- ms_tmp.ent.addr.msf.second,
- ms_tmp.ent.addr.msf.frame);
- }
-
- toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
-
- /* now try to get the total cdrom capacity */
- stat = cdrom_get_last_written(cdi, &last_written);
- if (!stat && (last_written > toc->capacity)) {
- toc->capacity = last_written;
- set_capacity(info->disk, toc->capacity * sectors_per_frame);
- drive->probed_capacity = toc->capacity * sectors_per_frame;
- }
-
- /* Remember that we've read this stuff. */
- drive->atapi_flags |= IDE_AFLAG_TOC_VALID;
-
- return 0;
-}
-
-int ide_cdrom_get_capabilities(ide_drive_t *drive, u8 *buf)
-{
- struct cdrom_info *info = drive->driver_data;
- struct cdrom_device_info *cdi = &info->devinfo;
- struct packet_command cgc;
- int stat, attempts = 3, size = ATAPI_CAPABILITIES_PAGE_SIZE;
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- if ((drive->atapi_flags & IDE_AFLAG_FULL_CAPS_PAGE) == 0)
- size -= ATAPI_CAPABILITIES_PAGE_PAD_SIZE;
-
- init_cdrom_command(&cgc, buf, size, CGC_DATA_UNKNOWN);
- do {
- /* we seem to get stat=0x01,err=0x00 the first time (??) */
- stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
- if (!stat)
- break;
- } while (--attempts);
- return stat;
-}
-
-void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf)
-{
- struct cdrom_info *cd = drive->driver_data;
- u16 curspeed, maxspeed;
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- if (drive->atapi_flags & IDE_AFLAG_LE_SPEED_FIELDS) {
- curspeed = le16_to_cpup((__le16 *)&buf[8 + 14]);
- maxspeed = le16_to_cpup((__le16 *)&buf[8 + 8]);
- } else {
- curspeed = be16_to_cpup((__be16 *)&buf[8 + 14]);
- maxspeed = be16_to_cpup((__be16 *)&buf[8 + 8]);
- }
-
- ide_debug_log(IDE_DBG_PROBE, "curspeed: %u, maxspeed: %u",
- curspeed, maxspeed);
-
- cd->current_speed = DIV_ROUND_CLOSEST(curspeed, 176);
- cd->max_speed = DIV_ROUND_CLOSEST(maxspeed, 176);
-}
-
-#define IDE_CD_CAPABILITIES \
- (CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | \
- CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | \
- CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R | \
- CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET | \
- CDC_MO_DRIVE | CDC_MRW | CDC_MRW_W | CDC_RAM)
-
-static const struct cdrom_device_ops ide_cdrom_dops = {
- .open = ide_cdrom_open_real,
- .release = ide_cdrom_release_real,
- .drive_status = ide_cdrom_drive_status,
- .check_events = ide_cdrom_check_events_real,
- .tray_move = ide_cdrom_tray_move,
- .lock_door = ide_cdrom_lock_door,
- .select_speed = ide_cdrom_select_speed,
- .get_last_session = ide_cdrom_get_last_session,
- .get_mcn = ide_cdrom_get_mcn,
- .reset = ide_cdrom_reset,
- .audio_ioctl = ide_cdrom_audio_ioctl,
- .capability = IDE_CD_CAPABILITIES,
- .generic_packet = ide_cdrom_packet,
-};
-
-static int ide_cdrom_register(ide_drive_t *drive, int nslots)
-{
- struct cdrom_info *info = drive->driver_data;
- struct cdrom_device_info *devinfo = &info->devinfo;
-
- ide_debug_log(IDE_DBG_PROBE, "nslots: %d", nslots);
-
- devinfo->ops = &ide_cdrom_dops;
- devinfo->speed = info->current_speed;
- devinfo->capacity = nslots;
- devinfo->handle = drive;
- strcpy(devinfo->name, drive->name);
-
- if (drive->atapi_flags & IDE_AFLAG_NO_SPEED_SELECT)
- devinfo->mask |= CDC_SELECT_SPEED;
-
- return register_cdrom(info->disk, devinfo);
-}
-
-static int ide_cdrom_probe_capabilities(ide_drive_t *drive)
-{
- struct cdrom_info *cd = drive->driver_data;
- struct cdrom_device_info *cdi = &cd->devinfo;
- u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE];
- mechtype_t mechtype;
- int nslots = 1;
-
- ide_debug_log(IDE_DBG_PROBE, "media: 0x%x, atapi_flags: 0x%lx",
- drive->media, drive->atapi_flags);
-
- cdi->mask = (CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R |
- CDC_DVD_RAM | CDC_SELECT_DISC | CDC_PLAY_AUDIO |
- CDC_MO_DRIVE | CDC_RAM);
-
- if (drive->media == ide_optical) {
- cdi->mask &= ~(CDC_MO_DRIVE | CDC_RAM);
- printk(KERN_ERR PFX "%s: ATAPI magneto-optical drive\n",
- drive->name);
- return nslots;
- }
-
- if (drive->atapi_flags & IDE_AFLAG_PRE_ATAPI12) {
- drive->atapi_flags &= ~IDE_AFLAG_NO_EJECT;
- cdi->mask &= ~CDC_PLAY_AUDIO;
- return nslots;
- }
-
- /*
- * We have to cheat a little here. the packet will eventually be queued
- * with ide_cdrom_packet(), which extracts the drive from cdi->handle.
- * Since this device hasn't been registered with the Uniform layer yet,
- * it can't do this. Same goes for cdi->ops.
- */
- cdi->handle = drive;
- cdi->ops = &ide_cdrom_dops;
-
- if (ide_cdrom_get_capabilities(drive, buf))
- return 0;
-
- if ((buf[8 + 6] & 0x01) == 0)
- drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
- if (buf[8 + 6] & 0x08)
- drive->atapi_flags &= ~IDE_AFLAG_NO_EJECT;
- if (buf[8 + 3] & 0x01)
- cdi->mask &= ~CDC_CD_R;
- if (buf[8 + 3] & 0x02)
- cdi->mask &= ~(CDC_CD_RW | CDC_RAM);
- if (buf[8 + 2] & 0x38)
- cdi->mask &= ~CDC_DVD;
- if (buf[8 + 3] & 0x20)
- cdi->mask &= ~(CDC_DVD_RAM | CDC_RAM);
- if (buf[8 + 3] & 0x10)
- cdi->mask &= ~CDC_DVD_R;
- if ((buf[8 + 4] & 0x01) || (drive->atapi_flags & IDE_AFLAG_PLAY_AUDIO_OK))
- cdi->mask &= ~CDC_PLAY_AUDIO;
-
- mechtype = buf[8 + 6] >> 5;
- if (mechtype == mechtype_caddy ||
- mechtype == mechtype_popup ||
- (drive->atapi_flags & IDE_AFLAG_NO_AUTOCLOSE))
- cdi->mask |= CDC_CLOSE_TRAY;
-
- if (cdi->sanyo_slot > 0) {
- cdi->mask &= ~CDC_SELECT_DISC;
- nslots = 3;
- } else if (mechtype == mechtype_individual_changer ||
- mechtype == mechtype_cartridge_changer) {
- nslots = cdrom_number_of_slots(cdi);
- if (nslots > 1)
- cdi->mask &= ~CDC_SELECT_DISC;
- }
-
- ide_cdrom_update_speed(drive, buf);
-
- printk(KERN_INFO PFX "%s: ATAPI", drive->name);
-
- /* don't print speed if the drive reported 0 */
- if (cd->max_speed)
- printk(KERN_CONT " %dX", cd->max_speed);
-
- printk(KERN_CONT " %s", (cdi->mask & CDC_DVD) ? "CD-ROM" : "DVD-ROM");
-
- if ((cdi->mask & CDC_DVD_R) == 0 || (cdi->mask & CDC_DVD_RAM) == 0)
- printk(KERN_CONT " DVD%s%s",
- (cdi->mask & CDC_DVD_R) ? "" : "-R",
- (cdi->mask & CDC_DVD_RAM) ? "" : "/RAM");
-
- if ((cdi->mask & CDC_CD_R) == 0 || (cdi->mask & CDC_CD_RW) == 0)
- printk(KERN_CONT " CD%s%s",
- (cdi->mask & CDC_CD_R) ? "" : "-R",
- (cdi->mask & CDC_CD_RW) ? "" : "/RW");
-
- if ((cdi->mask & CDC_SELECT_DISC) == 0)
- printk(KERN_CONT " changer w/%d slots", nslots);
- else
- printk(KERN_CONT " drive");
-
- printk(KERN_CONT ", %dkB Cache\n",
- be16_to_cpup((__be16 *)&buf[8 + 12]));
-
- return nslots;
-}
-
-struct cd_list_entry {
- const char *id_model;
- const char *id_firmware;
- unsigned int cd_flags;
-};
-
-#ifdef CONFIG_IDE_PROC_FS
-static sector_t ide_cdrom_capacity(ide_drive_t *drive)
-{
- unsigned long capacity, sectors_per_frame;
-
- if (cdrom_read_capacity(drive, &capacity, &sectors_per_frame))
- return 0;
-
- return capacity * sectors_per_frame;
-}
-
-static int idecd_capacity_proc_show(struct seq_file *m, void *v)
-{
- ide_drive_t *drive = m->private;
-
- seq_printf(m, "%llu\n", (long long)ide_cdrom_capacity(drive));
- return 0;
-}
-
-static ide_proc_entry_t idecd_proc[] = {
- { "capacity", S_IFREG|S_IRUGO, idecd_capacity_proc_show },
- {}
-};
-
-static ide_proc_entry_t *ide_cd_proc_entries(ide_drive_t *drive)
-{
- return idecd_proc;
-}
-
-static const struct ide_proc_devset *ide_cd_proc_devsets(ide_drive_t *drive)
-{
- return NULL;
-}
-#endif
-
-static const struct cd_list_entry ide_cd_quirks_list[] = {
- /* SCR-3231 doesn't support the SET_CD_SPEED command. */
- { "SAMSUNG CD-ROM SCR-3231", NULL, IDE_AFLAG_NO_SPEED_SELECT },
- /* Old NEC260 (not R) was released before ATAPI 1.2 spec. */
- { "NEC CD-ROM DRIVE:260", "1.01", IDE_AFLAG_TOCADDR_AS_BCD |
- IDE_AFLAG_PRE_ATAPI12, },
- /* Vertos 300, some versions of this drive like to talk BCD. */
- { "V003S0DS", NULL, IDE_AFLAG_VERTOS_300_SSD, },
- /* Vertos 600 ESD. */
- { "V006E0DS", NULL, IDE_AFLAG_VERTOS_600_ESD, },
- /*
- * Sanyo 3 CD changer uses a non-standard command for CD changing
- * (by default standard ATAPI support for CD changers is used).
- */
- { "CD-ROM CDR-C3 G", NULL, IDE_AFLAG_SANYO_3CD },
- { "CD-ROM CDR-C3G", NULL, IDE_AFLAG_SANYO_3CD },
- { "CD-ROM CDR_C36", NULL, IDE_AFLAG_SANYO_3CD },
- /* Stingray 8X CD-ROM. */
- { "STINGRAY 8422 IDE 8X CD-ROM 7-27-95", NULL, IDE_AFLAG_PRE_ATAPI12 },
- /*
- * ACER 50X CD-ROM and WPI 32X CD-ROM require the full spec length
- * mode sense page capabilities size, but older drives break.
- */
- { "ATAPI CD ROM DRIVE 50X MAX", NULL, IDE_AFLAG_FULL_CAPS_PAGE },
- { "WPI CDS-32X", NULL, IDE_AFLAG_FULL_CAPS_PAGE },
- /* ACER/AOpen 24X CD-ROM has the speed fields byte-swapped. */
- { "", "241N", IDE_AFLAG_LE_SPEED_FIELDS },
- /*
- * Some drives used by Apple don't advertise audio play
- * but they do support reading TOC & audio datas.
- */
- { "MATSHITADVD-ROM SR-8187", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
- { "MATSHITADVD-ROM SR-8186", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
- { "MATSHITADVD-ROM SR-8176", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
- { "MATSHITADVD-ROM SR-8174", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
- { "Optiarc DVD RW AD-5200A", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
- { "Optiarc DVD RW AD-7200A", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
- { "Optiarc DVD RW AD-7543A", NULL, IDE_AFLAG_NO_AUTOCLOSE },
- { "TEAC CD-ROM CD-224E", NULL, IDE_AFLAG_NO_AUTOCLOSE },
- { NULL, NULL, 0 }
-};
-
-static unsigned int ide_cd_flags(u16 *id)
-{
- const struct cd_list_entry *cle = ide_cd_quirks_list;
-
- while (cle->id_model) {
- if (strcmp(cle->id_model, (char *)&id[ATA_ID_PROD]) == 0 &&
- (cle->id_firmware == NULL ||
- strstr((char *)&id[ATA_ID_FW_REV], cle->id_firmware)))
- return cle->cd_flags;
- cle++;
- }
-
- return 0;
-}
-
-static int ide_cdrom_setup(ide_drive_t *drive)
-{
- struct cdrom_info *cd = drive->driver_data;
- struct cdrom_device_info *cdi = &cd->devinfo;
- struct request_queue *q = drive->queue;
- u16 *id = drive->id;
- char *fw_rev = (char *)&id[ATA_ID_FW_REV];
- int nslots;
-
- ide_debug_log(IDE_DBG_PROBE, "enter");
-
- drive->prep_rq = ide_cdrom_prep_rq;
- blk_queue_dma_alignment(q, 31);
- blk_queue_update_dma_pad(q, 15);
-
- drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
- drive->atapi_flags = IDE_AFLAG_NO_EJECT | ide_cd_flags(id);
-
- if ((drive->atapi_flags & IDE_AFLAG_VERTOS_300_SSD) &&
- fw_rev[4] == '1' && fw_rev[6] <= '2')
- drive->atapi_flags |= (IDE_AFLAG_TOCTRACKS_AS_BCD |
- IDE_AFLAG_TOCADDR_AS_BCD);
- else if ((drive->atapi_flags & IDE_AFLAG_VERTOS_600_ESD) &&
- fw_rev[4] == '1' && fw_rev[6] <= '2')
- drive->atapi_flags |= IDE_AFLAG_TOCTRACKS_AS_BCD;
- else if (drive->atapi_flags & IDE_AFLAG_SANYO_3CD)
- /* 3 => use CD in slot 0 */
- cdi->sanyo_slot = 3;
-
- nslots = ide_cdrom_probe_capabilities(drive);
-
- blk_queue_logical_block_size(q, CD_FRAMESIZE);
-
- if (ide_cdrom_register(drive, nslots)) {
- printk(KERN_ERR PFX "%s: %s failed to register device with the"
- " cdrom driver.\n", drive->name, __func__);
- cd->devinfo.handle = NULL;
- return 1;
- }
-
- ide_proc_register_driver(drive, cd->driver);
- return 0;
-}
-
-static void ide_cd_remove(ide_drive_t *drive)
-{
- struct cdrom_info *info = drive->driver_data;
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- ide_proc_unregister_driver(drive, info->driver);
- device_del(&info->dev);
- del_gendisk(info->disk);
-
- mutex_lock(&idecd_ref_mutex);
- put_device(&info->dev);
- mutex_unlock(&idecd_ref_mutex);
-}
-
-static void ide_cd_release(struct device *dev)
-{
- struct cdrom_info *info = to_ide_drv(dev, cdrom_info);
- struct cdrom_device_info *devinfo = &info->devinfo;
- ide_drive_t *drive = info->drive;
- struct gendisk *g = info->disk;
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- kfree(info->toc);
- if (devinfo->handle == drive)
- unregister_cdrom(devinfo);
- drive->driver_data = NULL;
- drive->prep_rq = NULL;
- g->private_data = NULL;
- put_disk(g);
- kfree(info);
-}
-
-static int ide_cd_probe(ide_drive_t *);
-
-static struct ide_driver ide_cdrom_driver = {
- .gen_driver = {
- .owner = THIS_MODULE,
- .name = "ide-cdrom",
- .bus = &ide_bus_type,
- },
- .probe = ide_cd_probe,
- .remove = ide_cd_remove,
- .version = IDECD_VERSION,
- .do_request = ide_cd_do_request,
-#ifdef CONFIG_IDE_PROC_FS
- .proc_entries = ide_cd_proc_entries,
- .proc_devsets = ide_cd_proc_devsets,
-#endif
-};
-
-static int idecd_open(struct block_device *bdev, fmode_t mode)
-{
- struct cdrom_info *info;
- int rc = -ENXIO;
-
- if (bdev_check_media_change(bdev)) {
- info = ide_drv_g(bdev->bd_disk, cdrom_info);
-
- ide_cd_read_toc(info->drive);
- }
-
- mutex_lock(&ide_cd_mutex);
- info = ide_cd_get(bdev->bd_disk);
- if (!info)
- goto out;
-
- rc = cdrom_open(&info->devinfo, bdev, mode);
- if (rc < 0)
- ide_cd_put(info);
-out:
- mutex_unlock(&ide_cd_mutex);
- return rc;
-}
-
-static void idecd_release(struct gendisk *disk, fmode_t mode)
-{
- struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
-
- mutex_lock(&ide_cd_mutex);
- cdrom_release(&info->devinfo, mode);
-
- ide_cd_put(info);
- mutex_unlock(&ide_cd_mutex);
-}
-
-static int idecd_set_spindown(struct cdrom_device_info *cdi, unsigned long arg)
-{
- struct packet_command cgc;
- char buffer[16];
- int stat;
- char spindown;
-
- if (copy_from_user(&spindown, (void __user *)arg, sizeof(char)))
- return -EFAULT;
-
- init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
-
- stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0);
- if (stat)
- return stat;
-
- buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f);
- return cdrom_mode_select(cdi, &cgc);
-}
-
-static int idecd_get_spindown(struct cdrom_device_info *cdi, unsigned long arg)
-{
- struct packet_command cgc;
- char buffer[16];
- int stat;
- char spindown;
-
- init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
-
- stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0);
- if (stat)
- return stat;
-
- spindown = buffer[11] & 0x0f;
- if (copy_to_user((void __user *)arg, &spindown, sizeof(char)))
- return -EFAULT;
- return 0;
-}
-
-static int idecd_locked_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info);
- int err;
-
- switch (cmd) {
- case CDROMSETSPINDOWN:
- return idecd_set_spindown(&info->devinfo, arg);
- case CDROMGETSPINDOWN:
- return idecd_get_spindown(&info->devinfo, arg);
- default:
- break;
- }
-
- err = generic_ide_ioctl(info->drive, bdev, cmd, arg);
- if (err == -EINVAL)
- err = cdrom_ioctl(&info->devinfo, bdev, mode, cmd, arg);
-
- return err;
-}
-
-static int idecd_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- int ret;
-
- mutex_lock(&ide_cd_mutex);
- ret = idecd_locked_ioctl(bdev, mode, cmd, arg);
- mutex_unlock(&ide_cd_mutex);
-
- return ret;
-}
-
-static int idecd_locked_compat_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info);
- void __user *argp = compat_ptr(arg);
- int err;
-
- switch (cmd) {
- case CDROMSETSPINDOWN:
- return idecd_set_spindown(&info->devinfo, (unsigned long)argp);
- case CDROMGETSPINDOWN:
- return idecd_get_spindown(&info->devinfo, (unsigned long)argp);
- default:
- break;
- }
-
- err = generic_ide_ioctl(info->drive, bdev, cmd, arg);
- if (err == -EINVAL)
- err = cdrom_ioctl(&info->devinfo, bdev, mode, cmd,
- (unsigned long)argp);
-
- return err;
-}
-
-static int idecd_compat_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- int ret;
-
- mutex_lock(&ide_cd_mutex);
- ret = idecd_locked_compat_ioctl(bdev, mode, cmd, arg);
- mutex_unlock(&ide_cd_mutex);
-
- return ret;
-}
-
-static unsigned int idecd_check_events(struct gendisk *disk,
- unsigned int clearing)
-{
- struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
- return cdrom_check_events(&info->devinfo, clearing);
-}
-
-static const struct block_device_operations idecd_ops = {
- .owner = THIS_MODULE,
- .open = idecd_open,
- .release = idecd_release,
- .ioctl = idecd_ioctl,
- .compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ?
- idecd_compat_ioctl : NULL,
- .check_events = idecd_check_events,
-};
-
-/* module options */
-static unsigned long debug_mask;
-module_param(debug_mask, ulong, 0644);
-
-MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
-
-static int ide_cd_probe(ide_drive_t *drive)
-{
- struct cdrom_info *info;
- struct gendisk *g;
-
- ide_debug_log(IDE_DBG_PROBE, "driver_req: %s, media: 0x%x",
- drive->driver_req, drive->media);
-
- if (!strstr("ide-cdrom", drive->driver_req))
- goto failed;
-
- if (drive->media != ide_cdrom && drive->media != ide_optical)
- goto failed;
-
- drive->debug_mask = debug_mask;
- drive->irq_handler = cdrom_newpc_intr;
-
- info = kzalloc(sizeof(struct cdrom_info), GFP_KERNEL);
- if (info == NULL) {
- printk(KERN_ERR PFX "%s: Can't allocate a cdrom structure\n",
- drive->name);
- goto failed;
- }
-
- g = alloc_disk(1 << PARTN_BITS);
- if (!g)
- goto out_free_cd;
-
- ide_init_disk(g, drive);
-
- info->dev.parent = &drive->gendev;
- info->dev.release = ide_cd_release;
- dev_set_name(&info->dev, "%s", dev_name(&drive->gendev));
-
- if (device_register(&info->dev))
- goto out_free_disk;
-
- info->drive = drive;
- info->driver = &ide_cdrom_driver;
- info->disk = g;
-
- g->private_data = &info->driver;
-
- drive->driver_data = info;
-
- g->minors = 1;
- g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
- if (ide_cdrom_setup(drive)) {
- put_device(&info->dev);
- goto failed;
- }
-
- ide_cd_read_toc(drive);
- g->fops = &idecd_ops;
- g->flags |= GENHD_FL_REMOVABLE | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
- g->events = DISK_EVENT_MEDIA_CHANGE;
- device_add_disk(&drive->gendev, g, NULL);
- return 0;
-
-out_free_disk:
- put_disk(g);
-out_free_cd:
- kfree(info);
-failed:
- return -ENODEV;
-}
-
-static void __exit ide_cdrom_exit(void)
-{
- driver_unregister(&ide_cdrom_driver.gen_driver);
-}
-
-static int __init ide_cdrom_init(void)
-{
- printk(KERN_INFO DRV_NAME " driver " IDECD_VERSION "\n");
- return driver_register(&ide_cdrom_driver.gen_driver);
-}
-
-MODULE_ALIAS("ide:*m-cdrom*");
-MODULE_ALIAS("ide-cd");
-module_init(ide_cdrom_init);
-module_exit(ide_cdrom_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
deleted file mode 100644
index a69dc7f61c4d..000000000000
--- a/drivers/ide/ide-cd.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 1996-98 Erik Andersen
- * Copyright (C) 1998-2000 Jens Axboe
- */
-#ifndef _IDE_CD_H
-#define _IDE_CD_H
-
-#include <linux/cdrom.h>
-#include <asm/byteorder.h>
-
-#define IDECD_DEBUG_LOG 0
-
-#if IDECD_DEBUG_LOG
-#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args)
-#else
-#define ide_debug_log(lvl, fmt, args...) do {} while (0)
-#endif
-
-#define ATAPI_WAIT_WRITE_BUSY (10 * HZ)
-
-/************************************************************************/
-
-#define SECTORS_PER_FRAME (CD_FRAMESIZE >> SECTOR_SHIFT)
-#define SECTOR_BUFFER_SIZE (CD_FRAMESIZE * 32)
-
-/* Capabilities Page size including 8 bytes of Mode Page Header */
-#define ATAPI_CAPABILITIES_PAGE_SIZE (8 + 20)
-#define ATAPI_CAPABILITIES_PAGE_PAD_SIZE 4
-
-/* Structure of a MSF cdrom address. */
-struct atapi_msf {
- u8 reserved;
- u8 minute;
- u8 second;
- u8 frame;
-};
-
-/* Space to hold the disk TOC. */
-#define MAX_TRACKS 99
-struct atapi_toc_header {
- unsigned short toc_length;
- u8 first_track;
- u8 last_track;
-};
-
-struct atapi_toc_entry {
- u8 reserved1;
-#if defined(__BIG_ENDIAN_BITFIELD)
- u8 adr : 4;
- u8 control : 4;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- u8 control : 4;
- u8 adr : 4;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u8 track;
- u8 reserved2;
- union {
- unsigned lba;
- struct atapi_msf msf;
- } addr;
-};
-
-struct atapi_toc {
- int last_session_lba;
- int xa_flag;
- unsigned long capacity;
- struct atapi_toc_header hdr;
- struct atapi_toc_entry ent[MAX_TRACKS+1];
- /* One extra for the leadout. */
-};
-
-/* Extra per-device info for cdrom drives. */
-struct cdrom_info {
- ide_drive_t *drive;
- struct ide_driver *driver;
- struct gendisk *disk;
- struct device dev;
-
- /* Buffer for table of contents. NULL if we haven't allocated
- a TOC buffer for this device yet. */
-
- struct atapi_toc *toc;
-
- u8 max_speed; /* Max speed of the drive. */
- u8 current_speed; /* Current speed of the drive. */
-
- /* Per-device info needed by cdrom.c generic driver. */
- struct cdrom_device_info devinfo;
-
- unsigned long write_timeout;
-};
-
-/* ide-cd_verbose.c */
-void ide_cd_log_error(const char *, struct request *, struct request_sense *);
-
-/* ide-cd.c functions used by ide-cd_ioctl.c */
-int ide_cd_queue_pc(ide_drive_t *, const unsigned char *, int, void *,
- unsigned *, struct scsi_sense_hdr *, int, req_flags_t);
-int ide_cd_read_toc(ide_drive_t *);
-int ide_cdrom_get_capabilities(ide_drive_t *, u8 *);
-void ide_cdrom_update_speed(ide_drive_t *, u8 *);
-int cdrom_check_status(ide_drive_t *, struct scsi_sense_hdr *);
-
-/* ide-cd_ioctl.c */
-int ide_cdrom_open_real(struct cdrom_device_info *, int);
-void ide_cdrom_release_real(struct cdrom_device_info *);
-int ide_cdrom_drive_status(struct cdrom_device_info *, int);
-unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *,
- unsigned int clearing, int slot_nr);
-int ide_cdrom_tray_move(struct cdrom_device_info *, int);
-int ide_cdrom_lock_door(struct cdrom_device_info *, int);
-int ide_cdrom_select_speed(struct cdrom_device_info *, int);
-int ide_cdrom_get_last_session(struct cdrom_device_info *,
- struct cdrom_multisession *);
-int ide_cdrom_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *);
-int ide_cdrom_reset(struct cdrom_device_info *cdi);
-int ide_cdrom_audio_ioctl(struct cdrom_device_info *, unsigned int, void *);
-int ide_cdrom_packet(struct cdrom_device_info *, struct packet_command *);
-
-#endif /* _IDE_CD_H */
diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c
deleted file mode 100644
index 011eab9c69b7..000000000000
--- a/drivers/ide/ide-cd_ioctl.c
+++ /dev/null
@@ -1,468 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * cdrom.c IOCTLs handling for ide-cd driver.
- *
- * Copyright (C) 1994-1996 Scott Snyder <snyder@fnald0.fnal.gov>
- * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org>
- * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de>
- */
-
-#include <linux/kernel.h>
-#include <linux/cdrom.h>
-#include <linux/gfp.h>
-#include <linux/ide.h>
-#include <scsi/scsi.h>
-
-#include "ide-cd.h"
-
-/****************************************************************************
- * Other driver requests (open, close, check media change).
- */
-int ide_cdrom_open_real(struct cdrom_device_info *cdi, int purpose)
-{
- return 0;
-}
-
-/*
- * Close down the device. Invalidate all cached blocks.
- */
-void ide_cdrom_release_real(struct cdrom_device_info *cdi)
-{
- ide_drive_t *drive = cdi->handle;
-
- if (!cdi->use_count)
- drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID;
-}
-
-/*
- * add logic to try GET_EVENT command first to check for media and tray
- * status. this should be supported by newer cd-r/w and all DVD etc
- * drives
- */
-int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr)
-{
- ide_drive_t *drive = cdi->handle;
- struct media_event_desc med;
- struct scsi_sense_hdr sshdr;
- int stat;
-
- if (slot_nr != CDSL_CURRENT)
- return -EINVAL;
-
- stat = cdrom_check_status(drive, &sshdr);
- if (!stat || sshdr.sense_key == UNIT_ATTENTION)
- return CDS_DISC_OK;
-
- if (!cdrom_get_media_event(cdi, &med)) {
- if (med.media_present)
- return CDS_DISC_OK;
- else if (med.door_open)
- return CDS_TRAY_OPEN;
- else
- return CDS_NO_DISC;
- }
-
- if (sshdr.sense_key == NOT_READY && sshdr.asc == 0x04
- && sshdr.ascq == 0x04)
- return CDS_DISC_OK;
-
- /*
- * If not using Mt Fuji extended media tray reports,
- * just return TRAY_OPEN since ATAPI doesn't provide
- * any other way to detect this...
- */
- if (sshdr.sense_key == NOT_READY) {
- if (sshdr.asc == 0x3a && sshdr.ascq == 1)
- return CDS_NO_DISC;
- else
- return CDS_TRAY_OPEN;
- }
- return CDS_DRIVE_NOT_READY;
-}
-
-/*
- * ide-cd always generates media changed event if media is missing, which
- * makes it impossible to use for proper event reporting, so
- * DISK_EVENT_FLAG_UEVENT is cleared in disk->event_flags
- * and the following function is used only to trigger
- * revalidation and never propagated to userland.
- */
-unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *cdi,
- unsigned int clearing, int slot_nr)
-{
- ide_drive_t *drive = cdi->handle;
- int retval;
-
- if (slot_nr == CDSL_CURRENT) {
- (void) cdrom_check_status(drive, NULL);
- retval = (drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED) ? 1 : 0;
- drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED;
- return retval ? DISK_EVENT_MEDIA_CHANGE : 0;
- } else {
- return 0;
- }
-}
-
-/* Eject the disk if EJECTFLAG is 0.
- If EJECTFLAG is 1, try to reload the disk. */
-static
-int cdrom_eject(ide_drive_t *drive, int ejectflag)
-{
- struct cdrom_info *cd = drive->driver_data;
- struct cdrom_device_info *cdi = &cd->devinfo;
- char loej = 0x02;
- unsigned char cmd[BLK_MAX_CDB];
-
- if ((drive->atapi_flags & IDE_AFLAG_NO_EJECT) && !ejectflag)
- return -EDRIVE_CANT_DO_THIS;
-
- /* reload fails on some drives, if the tray is locked */
- if ((drive->atapi_flags & IDE_AFLAG_DOOR_LOCKED) && ejectflag)
- return 0;
-
- /* only tell drive to close tray if open, if it can do that */
- if (ejectflag && (cdi->mask & CDC_CLOSE_TRAY))
- loej = 0;
-
- memset(cmd, 0, BLK_MAX_CDB);
-
- cmd[0] = GPCMD_START_STOP_UNIT;
- cmd[4] = loej | (ejectflag != 0);
-
- return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, NULL, 0, 0);
-}
-
-/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
-static
-int ide_cd_lockdoor(ide_drive_t *drive, int lockflag)
-{
- struct scsi_sense_hdr sshdr;
- int stat;
-
- /* If the drive cannot lock the door, just pretend. */
- if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0) {
- stat = 0;
- } else {
- unsigned char cmd[BLK_MAX_CDB];
-
- memset(cmd, 0, BLK_MAX_CDB);
-
- cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
- cmd[4] = lockflag ? 1 : 0;
-
- stat = ide_cd_queue_pc(drive, cmd, 0, NULL, NULL,
- &sshdr, 0, 0);
- }
-
- /* If we got an illegal field error, the drive
- probably cannot lock the door. */
- if (stat != 0 &&
- sshdr.sense_key == ILLEGAL_REQUEST &&
- (sshdr.asc == 0x24 || sshdr.asc == 0x20)) {
- printk(KERN_ERR "%s: door locking not supported\n",
- drive->name);
- drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
- stat = 0;
- }
-
- /* no medium, that's alright. */
- if (stat != 0 && sshdr.sense_key == NOT_READY && sshdr.asc == 0x3a)
- stat = 0;
-
- if (stat == 0) {
- if (lockflag)
- drive->atapi_flags |= IDE_AFLAG_DOOR_LOCKED;
- else
- drive->atapi_flags &= ~IDE_AFLAG_DOOR_LOCKED;
- }
-
- return stat;
-}
-
-int ide_cdrom_tray_move(struct cdrom_device_info *cdi, int position)
-{
- ide_drive_t *drive = cdi->handle;
-
- if (position) {
- int stat = ide_cd_lockdoor(drive, 0);
-
- if (stat)
- return stat;
- }
-
- return cdrom_eject(drive, !position);
-}
-
-int ide_cdrom_lock_door(struct cdrom_device_info *cdi, int lock)
-{
- ide_drive_t *drive = cdi->handle;
-
- return ide_cd_lockdoor(drive, lock);
-}
-
-/*
- * ATAPI devices are free to select the speed you request or any slower
- * rate. :-( Requesting too fast a speed will _not_ produce an error.
- */
-int ide_cdrom_select_speed(struct cdrom_device_info *cdi, int speed)
-{
- ide_drive_t *drive = cdi->handle;
- struct cdrom_info *cd = drive->driver_data;
- u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE];
- int stat;
- unsigned char cmd[BLK_MAX_CDB];
-
- if (speed == 0)
- speed = 0xffff; /* set to max */
- else
- speed *= 177; /* Nx to kbytes/s */
-
- memset(cmd, 0, BLK_MAX_CDB);
-
- cmd[0] = GPCMD_SET_SPEED;
- /* Read Drive speed in kbytes/second MSB/LSB */
- cmd[2] = (speed >> 8) & 0xff;
- cmd[3] = speed & 0xff;
- if ((cdi->mask & (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) !=
- (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) {
- /* Write Drive speed in kbytes/second MSB/LSB */
- cmd[4] = (speed >> 8) & 0xff;
- cmd[5] = speed & 0xff;
- }
-
- stat = ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, NULL, 0, 0);
-
- if (!ide_cdrom_get_capabilities(drive, buf)) {
- ide_cdrom_update_speed(drive, buf);
- cdi->speed = cd->current_speed;
- }
-
- return 0;
-}
-
-int ide_cdrom_get_last_session(struct cdrom_device_info *cdi,
- struct cdrom_multisession *ms_info)
-{
- struct atapi_toc *toc;
- ide_drive_t *drive = cdi->handle;
- struct cdrom_info *info = drive->driver_data;
- int ret;
-
- if ((drive->atapi_flags & IDE_AFLAG_TOC_VALID) == 0 || !info->toc) {
- ret = ide_cd_read_toc(drive);
- if (ret)
- return ret;
- }
-
- toc = info->toc;
- ms_info->addr.lba = toc->last_session_lba;
- ms_info->xa_flag = toc->xa_flag;
-
- return 0;
-}
-
-int ide_cdrom_get_mcn(struct cdrom_device_info *cdi,
- struct cdrom_mcn *mcn_info)
-{
- ide_drive_t *drive = cdi->handle;
- int stat, mcnlen;
- char buf[24];
- unsigned char cmd[BLK_MAX_CDB];
- unsigned len = sizeof(buf);
-
- memset(cmd, 0, BLK_MAX_CDB);
-
- cmd[0] = GPCMD_READ_SUBCHANNEL;
- cmd[1] = 2; /* MSF addressing */
- cmd[2] = 0x40; /* request subQ data */
- cmd[3] = 2; /* format */
- cmd[8] = len;
-
- stat = ide_cd_queue_pc(drive, cmd, 0, buf, &len, NULL, 0, 0);
- if (stat)
- return stat;
-
- mcnlen = sizeof(mcn_info->medium_catalog_number) - 1;
- memcpy(mcn_info->medium_catalog_number, buf + 9, mcnlen);
- mcn_info->medium_catalog_number[mcnlen] = '\0';
-
- return 0;
-}
-
-int ide_cdrom_reset(struct cdrom_device_info *cdi)
-{
- ide_drive_t *drive = cdi->handle;
- struct cdrom_info *cd = drive->driver_data;
- struct request *rq;
- int ret;
-
- rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
- ide_req(rq)->type = ATA_PRIV_MISC;
- rq->rq_flags = RQF_QUIET;
- blk_execute_rq(cd->disk, rq, 0);
- ret = scsi_req(rq)->result ? -EIO : 0;
- blk_put_request(rq);
- /*
- * A reset will unlock the door. If it was previously locked,
- * lock it again.
- */
- if (drive->atapi_flags & IDE_AFLAG_DOOR_LOCKED)
- (void)ide_cd_lockdoor(drive, 1);
-
- return ret;
-}
-
-static int ide_cd_get_toc_entry(ide_drive_t *drive, int track,
- struct atapi_toc_entry **ent)
-{
- struct cdrom_info *info = drive->driver_data;
- struct atapi_toc *toc = info->toc;
- int ntracks;
-
- /*
- * don't serve cached data, if the toc isn't valid
- */
- if ((drive->atapi_flags & IDE_AFLAG_TOC_VALID) == 0)
- return -EINVAL;
-
- /* Check validity of requested track number. */
- ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
-
- if (toc->hdr.first_track == CDROM_LEADOUT)
- ntracks = 0;
-
- if (track == CDROM_LEADOUT)
- *ent = &toc->ent[ntracks];
- else if (track < toc->hdr.first_track || track > toc->hdr.last_track)
- return -EINVAL;
- else
- *ent = &toc->ent[track - toc->hdr.first_track];
-
- return 0;
-}
-
-static int ide_cd_fake_play_trkind(ide_drive_t *drive, void *arg)
-{
- struct cdrom_ti *ti = arg;
- struct atapi_toc_entry *first_toc, *last_toc;
- unsigned long lba_start, lba_end;
- int stat;
- unsigned char cmd[BLK_MAX_CDB];
-
- stat = ide_cd_get_toc_entry(drive, ti->cdti_trk0, &first_toc);
- if (stat)
- return stat;
-
- stat = ide_cd_get_toc_entry(drive, ti->cdti_trk1, &last_toc);
- if (stat)
- return stat;
-
- if (ti->cdti_trk1 != CDROM_LEADOUT)
- ++last_toc;
- lba_start = first_toc->addr.lba;
- lba_end = last_toc->addr.lba;
-
- if (lba_end <= lba_start)
- return -EINVAL;
-
- memset(cmd, 0, BLK_MAX_CDB);
-
- cmd[0] = GPCMD_PLAY_AUDIO_MSF;
- lba_to_msf(lba_start, &cmd[3], &cmd[4], &cmd[5]);
- lba_to_msf(lba_end - 1, &cmd[6], &cmd[7], &cmd[8]);
-
- return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, NULL, 0, 0);
-}
-
-static int ide_cd_read_tochdr(ide_drive_t *drive, void *arg)
-{
- struct cdrom_info *cd = drive->driver_data;
- struct cdrom_tochdr *tochdr = arg;
- struct atapi_toc *toc;
- int stat;
-
- /* Make sure our saved TOC is valid. */
- stat = ide_cd_read_toc(drive);
- if (stat)
- return stat;
-
- toc = cd->toc;
- tochdr->cdth_trk0 = toc->hdr.first_track;
- tochdr->cdth_trk1 = toc->hdr.last_track;
-
- return 0;
-}
-
-static int ide_cd_read_tocentry(ide_drive_t *drive, void *arg)
-{
- struct cdrom_tocentry *tocentry = arg;
- struct atapi_toc_entry *toce;
- int stat;
-
- stat = ide_cd_get_toc_entry(drive, tocentry->cdte_track, &toce);
- if (stat)
- return stat;
-
- tocentry->cdte_ctrl = toce->control;
- tocentry->cdte_adr = toce->adr;
- if (tocentry->cdte_format == CDROM_MSF) {
- lba_to_msf(toce->addr.lba,
- &tocentry->cdte_addr.msf.minute,
- &tocentry->cdte_addr.msf.second,
- &tocentry->cdte_addr.msf.frame);
- } else
- tocentry->cdte_addr.lba = toce->addr.lba;
-
- return 0;
-}
-
-int ide_cdrom_audio_ioctl(struct cdrom_device_info *cdi,
- unsigned int cmd, void *arg)
-{
- ide_drive_t *drive = cdi->handle;
-
- switch (cmd) {
- /*
- * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since
- * atapi doesn't support it
- */
- case CDROMPLAYTRKIND:
- return ide_cd_fake_play_trkind(drive, arg);
- case CDROMREADTOCHDR:
- return ide_cd_read_tochdr(drive, arg);
- case CDROMREADTOCENTRY:
- return ide_cd_read_tocentry(drive, arg);
- default:
- return -EINVAL;
- }
-}
-
-/* the generic packet interface to cdrom.c */
-int ide_cdrom_packet(struct cdrom_device_info *cdi,
- struct packet_command *cgc)
-{
- ide_drive_t *drive = cdi->handle;
- req_flags_t flags = 0;
- unsigned len = cgc->buflen;
-
- if (cgc->timeout <= 0)
- cgc->timeout = ATAPI_WAIT_PC;
-
- /* here we queue the commands from the uniform CD-ROM
- layer. the packet must be complete, as we do not
- touch it at all. */
-
- if (cgc->sshdr)
- memset(cgc->sshdr, 0, sizeof(*cgc->sshdr));
-
- if (cgc->quiet)
- flags |= RQF_QUIET;
-
- cgc->stat = ide_cd_queue_pc(drive, cgc->cmd,
- cgc->data_direction == CGC_DATA_WRITE,
- cgc->buffer, &len,
- cgc->sshdr, cgc->timeout, flags);
- if (!cgc->stat)
- cgc->buflen -= len;
- return cgc->stat;
-}
diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c
deleted file mode 100644
index 5ecd5b2f03a3..000000000000
--- a/drivers/ide/ide-cd_verbose.c
+++ /dev/null
@@ -1,362 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Verbose error logging for ATAPI CD/DVD devices.
- *
- * Copyright (C) 1994-1996 Scott Snyder <snyder@fnald0.fnal.gov>
- * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org>
- * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de>
- */
-
-#include <linux/kernel.h>
-#include <linux/blkdev.h>
-#include <linux/cdrom.h>
-#include <linux/ide.h>
-#include <scsi/scsi.h>
-#include "ide-cd.h"
-
-#ifndef CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS
-void ide_cd_log_error(const char *name, struct request *failed_command,
- struct request_sense *sense)
-{
- /* Suppress printing unit attention and `in progress of becoming ready'
- errors when we're not being verbose. */
- if (sense->sense_key == UNIT_ATTENTION ||
- (sense->sense_key == NOT_READY && (sense->asc == 4 ||
- sense->asc == 0x3a)))
- return;
-
- printk(KERN_ERR "%s: error code: 0x%02x sense_key: 0x%02x "
- "asc: 0x%02x ascq: 0x%02x\n",
- name, sense->error_code, sense->sense_key,
- sense->asc, sense->ascq);
-}
-#else
-/* The generic packet command opcodes for CD/DVD Logical Units,
- * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
-static const struct {
- unsigned short packet_command;
- const char * const text;
-} packet_command_texts[] = {
- { GPCMD_TEST_UNIT_READY, "Test Unit Ready" },
- { GPCMD_REQUEST_SENSE, "Request Sense" },
- { GPCMD_FORMAT_UNIT, "Format Unit" },
- { GPCMD_INQUIRY, "Inquiry" },
- { GPCMD_START_STOP_UNIT, "Start/Stop Unit" },
- { GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" },
- { GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" },
- { GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" },
- { GPCMD_READ_10, "Read 10" },
- { GPCMD_WRITE_10, "Write 10" },
- { GPCMD_SEEK, "Seek" },
- { GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" },
- { GPCMD_VERIFY_10, "Verify 10" },
- { GPCMD_FLUSH_CACHE, "Flush Cache" },
- { GPCMD_READ_SUBCHANNEL, "Read Subchannel" },
- { GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" },
- { GPCMD_READ_HEADER, "Read Header" },
- { GPCMD_PLAY_AUDIO_10, "Play Audio 10" },
- { GPCMD_GET_CONFIGURATION, "Get Configuration" },
- { GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" },
- { GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" },
- { GPCMD_GET_EVENT_STATUS_NOTIFICATION,
- "Get Event Status Notification" },
- { GPCMD_PAUSE_RESUME, "Pause/Resume" },
- { GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" },
- { GPCMD_READ_DISC_INFO, "Read Disc Info" },
- { GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" },
- { GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" },
- { GPCMD_SEND_OPC, "Send OPC" },
- { GPCMD_MODE_SELECT_10, "Mode Select 10" },
- { GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" },
- { GPCMD_MODE_SENSE_10, "Mode Sense 10" },
- { GPCMD_CLOSE_TRACK, "Close Track" },
- { GPCMD_BLANK, "Blank" },
- { GPCMD_SEND_EVENT, "Send Event" },
- { GPCMD_SEND_KEY, "Send Key" },
- { GPCMD_REPORT_KEY, "Report Key" },
- { GPCMD_LOAD_UNLOAD, "Load/Unload" },
- { GPCMD_SET_READ_AHEAD, "Set Read-ahead" },
- { GPCMD_READ_12, "Read 12" },
- { GPCMD_GET_PERFORMANCE, "Get Performance" },
- { GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" },
- { GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" },
- { GPCMD_SET_STREAMING, "Set Streaming" },
- { GPCMD_READ_CD_MSF, "Read CD MSF" },
- { GPCMD_SCAN, "Scan" },
- { GPCMD_SET_SPEED, "Set Speed" },
- { GPCMD_PLAY_CD, "Play CD" },
- { GPCMD_MECHANISM_STATUS, "Mechanism Status" },
- { GPCMD_READ_CD, "Read CD" },
-};
-
-/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
-static const char * const sense_key_texts[16] = {
- "No sense data",
- "Recovered error",
- "Not ready",
- "Medium error",
- "Hardware error",
- "Illegal request",
- "Unit attention",
- "Data protect",
- "Blank check",
- "(reserved)",
- "(reserved)",
- "Aborted command",
- "(reserved)",
- "(reserved)",
- "Miscompare",
- "(reserved)",
-};
-
-/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
-static const struct {
- unsigned long asc_ascq;
- const char * const text;
-} sense_data_texts[] = {
- { 0x000000, "No additional sense information" },
- { 0x000011, "Play operation in progress" },
- { 0x000012, "Play operation paused" },
- { 0x000013, "Play operation successfully completed" },
- { 0x000014, "Play operation stopped due to error" },
- { 0x000015, "No current audio status to return" },
- { 0x010c0a, "Write error - padding blocks added" },
- { 0x011700, "Recovered data with no error correction applied" },
- { 0x011701, "Recovered data with retries" },
- { 0x011702, "Recovered data with positive head offset" },
- { 0x011703, "Recovered data with negative head offset" },
- { 0x011704, "Recovered data with retries and/or CIRC applied" },
- { 0x011705, "Recovered data using previous sector ID" },
- { 0x011800, "Recovered data with error correction applied" },
- { 0x011801, "Recovered data with error correction and retries applied"},
- { 0x011802, "Recovered data - the data was auto-reallocated" },
- { 0x011803, "Recovered data with CIRC" },
- { 0x011804, "Recovered data with L-EC" },
- { 0x015d00, "Failure prediction threshold exceeded"
- " - Predicted logical unit failure" },
- { 0x015d01, "Failure prediction threshold exceeded"
- " - Predicted media failure" },
- { 0x015dff, "Failure prediction threshold exceeded - False" },
- { 0x017301, "Power calibration area almost full" },
- { 0x020400, "Logical unit not ready - cause not reportable" },
- /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */
- { 0x020401, "Logical unit not ready"
- " - in progress [sic] of becoming ready" },
- { 0x020402, "Logical unit not ready - initializing command required" },
- { 0x020403, "Logical unit not ready - manual intervention required" },
- { 0x020404, "Logical unit not ready - format in progress" },
- { 0x020407, "Logical unit not ready - operation in progress" },
- { 0x020408, "Logical unit not ready - long write in progress" },
- { 0x020600, "No reference position found (media may be upside down)" },
- { 0x023000, "Incompatible medium installed" },
- { 0x023a00, "Medium not present" },
- { 0x025300, "Media load or eject failed" },
- { 0x025700, "Unable to recover table of contents" },
- { 0x030300, "Peripheral device write fault" },
- { 0x030301, "No write current" },
- { 0x030302, "Excessive write errors" },
- { 0x030c00, "Write error" },
- { 0x030c01, "Write error - Recovered with auto reallocation" },
- { 0x030c02, "Write error - auto reallocation failed" },
- { 0x030c03, "Write error - recommend reassignment" },
- { 0x030c04, "Compression check miscompare error" },
- { 0x030c05, "Data expansion occurred during compress" },
- { 0x030c06, "Block not compressible" },
- { 0x030c07, "Write error - recovery needed" },
- { 0x030c08, "Write error - recovery failed" },
- { 0x030c09, "Write error - loss of streaming" },
- { 0x031100, "Unrecovered read error" },
- { 0x031106, "CIRC unrecovered error" },
- { 0x033101, "Format command failed" },
- { 0x033200, "No defect spare location available" },
- { 0x033201, "Defect list update failure" },
- { 0x035100, "Erase failure" },
- { 0x037200, "Session fixation error" },
- { 0x037201, "Session fixation error writin lead-in" },
- { 0x037202, "Session fixation error writin lead-out" },
- { 0x037300, "CD control error" },
- { 0x037302, "Power calibration area is full" },
- { 0x037303, "Power calibration area error" },
- { 0x037304, "Program memory area / RMA update failure" },
- { 0x037305, "Program memory area / RMA is full" },
- { 0x037306, "Program memory area / RMA is (almost) full" },
- { 0x040200, "No seek complete" },
- { 0x040300, "Write fault" },
- { 0x040900, "Track following error" },
- { 0x040901, "Tracking servo failure" },
- { 0x040902, "Focus servo failure" },
- { 0x040903, "Spindle servo failure" },
- { 0x041500, "Random positioning error" },
- { 0x041501, "Mechanical positioning or changer error" },
- { 0x041502, "Positioning error detected by read of medium" },
- { 0x043c00, "Mechanical positioning or changer error" },
- { 0x044000, "Diagnostic failure on component (ASCQ)" },
- { 0x044400, "Internal CD/DVD logical unit failure" },
- { 0x04b600, "Media load mechanism failed" },
- { 0x051a00, "Parameter list length error" },
- { 0x052000, "Invalid command operation code" },
- { 0x052100, "Logical block address out of range" },
- { 0x052102, "Invalid address for write" },
- { 0x052400, "Invalid field in command packet" },
- { 0x052600, "Invalid field in parameter list" },
- { 0x052601, "Parameter not supported" },
- { 0x052602, "Parameter value invalid" },
- { 0x052700, "Write protected media" },
- { 0x052c00, "Command sequence error" },
- { 0x052c03, "Current program area is not empty" },
- { 0x052c04, "Current program area is empty" },
- { 0x053001, "Cannot read medium - unknown format" },
- { 0x053002, "Cannot read medium - incompatible format" },
- { 0x053900, "Saving parameters not supported" },
- { 0x054e00, "Overlapped commands attempted" },
- { 0x055302, "Medium removal prevented" },
- { 0x055500, "System resource failure" },
- { 0x056300, "End of user area encountered on this track" },
- { 0x056400, "Illegal mode for this track or incompatible medium" },
- { 0x056f00, "Copy protection key exchange failure"
- " - Authentication failure" },
- { 0x056f01, "Copy protection key exchange failure - Key not present" },
- { 0x056f02, "Copy protection key exchange failure"
- " - Key not established" },
- { 0x056f03, "Read of scrambled sector without authentication" },
- { 0x056f04, "Media region code is mismatched to logical unit" },
- { 0x056f05, "Drive region must be permanent"
- " / region reset count error" },
- { 0x057203, "Session fixation error - incomplete track in session" },
- { 0x057204, "Empty or partially written reserved track" },
- { 0x057205, "No more RZONE reservations are allowed" },
- { 0x05bf00, "Loss of streaming" },
- { 0x062800, "Not ready to ready transition, medium may have changed" },
- { 0x062900, "Power on, reset or hardware reset occurred" },
- { 0x062a00, "Parameters changed" },
- { 0x062a01, "Mode parameters changed" },
- { 0x062e00, "Insufficient time for operation" },
- { 0x063f00, "Logical unit operating conditions have changed" },
- { 0x063f01, "Microcode has been changed" },
- { 0x065a00, "Operator request or state change input (unspecified)" },
- { 0x065a01, "Operator medium removal request" },
- { 0x0bb900, "Play operation aborted" },
- /* Here we use 0xff for the key (not a valid key) to signify
- * that these can have _any_ key value associated with them... */
- { 0xff0401, "Logical unit is in process of becoming ready" },
- { 0xff0400, "Logical unit not ready, cause not reportable" },
- { 0xff0402, "Logical unit not ready, initializing command required" },
- { 0xff0403, "Logical unit not ready, manual intervention required" },
- { 0xff0500, "Logical unit does not respond to selection" },
- { 0xff0800, "Logical unit communication failure" },
- { 0xff0802, "Logical unit communication parity error" },
- { 0xff0801, "Logical unit communication time-out" },
- { 0xff2500, "Logical unit not supported" },
- { 0xff4c00, "Logical unit failed self-configuration" },
- { 0xff3e00, "Logical unit has not self-configured yet" },
-};
-
-void ide_cd_log_error(const char *name, struct request *failed_command,
- struct request_sense *sense)
-{
- int i;
- const char *s = "bad sense key!";
- char buf[80];
-
- printk(KERN_ERR "ATAPI device %s:\n", name);
- if (sense->error_code == 0x70)
- printk(KERN_CONT " Error: ");
- else if (sense->error_code == 0x71)
- printk(" Deferred Error: ");
- else if (sense->error_code == 0x7f)
- printk(KERN_CONT " Vendor-specific Error: ");
- else
- printk(KERN_CONT " Unknown Error Type: ");
-
- if (sense->sense_key < ARRAY_SIZE(sense_key_texts))
- s = sense_key_texts[sense->sense_key];
-
- printk(KERN_CONT "%s -- (Sense key=0x%02x)\n", s, sense->sense_key);
-
- if (sense->asc == 0x40) {
- sprintf(buf, "Diagnostic failure on component 0x%02x",
- sense->ascq);
- s = buf;
- } else {
- int lo = 0, mid, hi = ARRAY_SIZE(sense_data_texts);
- unsigned long key = (sense->sense_key << 16);
-
- key |= (sense->asc << 8);
- if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd))
- key |= sense->ascq;
- s = NULL;
-
- while (hi > lo) {
- mid = (lo + hi) / 2;
- if (sense_data_texts[mid].asc_ascq == key ||
- sense_data_texts[mid].asc_ascq == (0xff0000|key)) {
- s = sense_data_texts[mid].text;
- break;
- } else if (sense_data_texts[mid].asc_ascq > key)
- hi = mid;
- else
- lo = mid + 1;
- }
- }
-
- if (s == NULL) {
- if (sense->asc > 0x80)
- s = "(vendor-specific error)";
- else
- s = "(reserved error code)";
- }
-
- printk(KERN_ERR " %s -- (asc=0x%02x, ascq=0x%02x)\n",
- s, sense->asc, sense->ascq);
-
- if (failed_command != NULL) {
- int lo = 0, mid, hi = ARRAY_SIZE(packet_command_texts);
- s = NULL;
-
- while (hi > lo) {
- mid = (lo + hi) / 2;
- if (packet_command_texts[mid].packet_command ==
- scsi_req(failed_command)->cmd[0]) {
- s = packet_command_texts[mid].text;
- break;
- }
- if (packet_command_texts[mid].packet_command >
- scsi_req(failed_command)->cmd[0])
- hi = mid;
- else
- lo = mid + 1;
- }
-
- printk(KERN_ERR " The failed \"%s\" packet command "
- "was: \n \"", s);
- for (i = 0; i < BLK_MAX_CDB; i++)
- printk(KERN_CONT "%02x ", scsi_req(failed_command)->cmd[i]);
- printk(KERN_CONT "\"\n");
- }
-
- /* The SKSV bit specifies validity of the sense_key_specific
- * in the next two commands. It is bit 7 of the first byte.
- * In the case of NOT_READY, if SKSV is set the drive can
- * give us nice ETA readings.
- */
- if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) {
- int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100;
-
- printk(KERN_ERR " Command is %02d%% complete\n",
- progress / 0xffff);
- }
-
- if (sense->sense_key == ILLEGAL_REQUEST &&
- (sense->sks[0] & 0x80) != 0) {
- printk(KERN_ERR " Error in %s byte %d",
- (sense->sks[0] & 0x40) != 0 ?
- "command packet" : "command data",
- (sense->sks[1] << 8) + sense->sks[2]);
-
- if ((sense->sks[0] & 0x40) != 0)
- printk(KERN_CONT " bit %d", sense->sks[0] & 0x07);
-
- printk(KERN_CONT "\n");
- }
-}
-#endif
diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
deleted file mode 100644
index f1e922e2479a..000000000000
--- a/drivers/ide/ide-cs.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*======================================================================
-
- A driver for PCMCIA IDE/ATA disk 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.
-
- 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 <linux/ide.h>
-#include <linux/major.h>
-#include <linux/delay.h>
-#include <asm/io.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ciscode.h>
-
-#define DRV_NAME "ide-cs"
-
-/*====================================================================*/
-
-/* Module parameters */
-
-MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("PCMCIA ATA/IDE card driver");
-MODULE_LICENSE("Dual MPL/GPL");
-
-/*====================================================================*/
-
-typedef struct ide_info_t {
- struct pcmcia_device *p_dev;
- struct ide_host *host;
- int ndev;
-} ide_info_t;
-
-static void ide_release(struct pcmcia_device *);
-static int ide_config(struct pcmcia_device *);
-
-static void ide_detach(struct pcmcia_device *p_dev);
-
-static int ide_probe(struct pcmcia_device *link)
-{
- ide_info_t *info;
-
- dev_dbg(&link->dev, "ide_attach()\n");
-
- /* Create new ide device */
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- info->p_dev = link;
- link->priv = info;
-
- link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO |
- CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
-
- return ide_config(link);
-} /* ide_attach */
-
-static void ide_detach(struct pcmcia_device *link)
-{
- ide_info_t *info = link->priv;
-
- dev_dbg(&link->dev, "ide_detach(0x%p)\n", link);
-
- ide_release(link);
-
- kfree(info);
-} /* ide_detach */
-
-static const struct ide_port_ops idecs_port_ops = {
- .quirkproc = ide_undecoded_slave,
-};
-
-static const struct ide_port_info idecs_port_info = {
- .port_ops = &idecs_port_ops,
- .host_flags = IDE_HFLAG_NO_DMA,
- .irq_flags = IRQF_SHARED,
- .chipset = ide_pci,
-};
-
-static struct ide_host *idecs_register(unsigned long io, unsigned long ctl,
- unsigned long irq, struct pcmcia_device *handle)
-{
- struct ide_host *host;
- ide_hwif_t *hwif;
- int i, rc;
- struct ide_hw hw, *hws[] = { &hw };
-
- if (!request_region(io, 8, DRV_NAME)) {
- printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
- DRV_NAME, io, io + 7);
- return NULL;
- }
-
- if (!request_region(ctl, 1, DRV_NAME)) {
- printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
- DRV_NAME, ctl);
- release_region(io, 8);
- return NULL;
- }
-
- memset(&hw, 0, sizeof(hw));
- ide_std_init_ports(&hw, io, ctl);
- hw.irq = irq;
- hw.dev = &handle->dev;
-
- rc = ide_host_add(&idecs_port_info, hws, 1, &host);
- if (rc)
- goto out_release;
-
- hwif = host->ports[0];
-
- if (hwif->present)
- return host;
-
- /* retry registration in case device is still spinning up */
- for (i = 0; i < 10; i++) {
- msleep(100);
- ide_port_scan(hwif);
- if (hwif->present)
- return host;
- }
-
- return host;
-
-out_release:
- release_region(ctl, 1);
- release_region(io, 8);
- return NULL;
-}
-
-static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data)
-{
- int *is_kme = priv_data;
-
- if ((pdev->resource[0]->flags & IO_DATA_PATH_WIDTH)
- != IO_DATA_PATH_WIDTH_8) {
- pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
- pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
- }
- pdev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
- pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-
- if (pdev->resource[1]->end) {
- pdev->resource[0]->end = 8;
- pdev->resource[1]->end = (*is_kme) ? 2 : 1;
- } else {
- if (pdev->resource[0]->end < 16)
- return -ENODEV;
- }
-
- return pcmcia_request_io(pdev);
-}
-
-static int ide_config(struct pcmcia_device *link)
-{
- ide_info_t *info = link->priv;
- int ret = 0, is_kme = 0;
- unsigned long io_base, ctl_base;
- struct ide_host *host;
-
- dev_dbg(&link->dev, "ide_config(0x%p)\n", link);
-
- is_kme = ((link->manf_id == MANFID_KME) &&
- ((link->card_id == PRODID_KME_KXLC005_A) ||
- (link->card_id == PRODID_KME_KXLC005_B)));
-
- if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) {
- link->config_flags &= ~CONF_AUTO_CHECK_VCC;
- if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme))
- goto failed; /* No suitable config found */
- }
- io_base = link->resource[0]->start;
- if (link->resource[1]->end)
- ctl_base = link->resource[1]->start;
- else
- ctl_base = link->resource[0]->start + 0x0e;
-
- if (!link->irq)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
- /* disable drive interrupts during IDE probe */
- outb(0x02, ctl_base);
-
- /* special setup for KXLC005 card */
- if (is_kme)
- outb(0x81, ctl_base+1);
-
- host = idecs_register(io_base, ctl_base, link->irq, link);
- if (host == NULL && resource_size(link->resource[0]) == 0x20) {
- outb(0x02, ctl_base + 0x10);
- host = idecs_register(io_base + 0x10, ctl_base + 0x10,
- link->irq, link);
- }
-
- if (host == NULL)
- goto failed;
-
- info->ndev = 1;
- info->host = host;
- dev_info(&link->dev, "ide-cs: hd%c: Vpp = %d.%d\n",
- 'a' + host->ports[0]->index * 2,
- link->vpp / 10, link->vpp % 10);
-
- return 0;
-
-failed:
- ide_release(link);
- return -ENODEV;
-} /* ide_config */
-
-static void ide_release(struct pcmcia_device *link)
-{
- ide_info_t *info = link->priv;
- struct ide_host *host = info->host;
-
- dev_dbg(&link->dev, "ide_release(0x%p)\n", link);
-
- if (info->ndev) {
- ide_hwif_t *hwif = host->ports[0];
- unsigned long data_addr, ctl_addr;
-
- data_addr = hwif->io_ports.data_addr;
- ctl_addr = hwif->io_ports.ctl_addr;
-
- ide_host_remove(host);
- info->ndev = 0;
-
- release_region(ctl_addr, 1);
- release_region(data_addr, 8);
- }
-
- pcmcia_disable_device(link);
-} /* ide_release */
-
-
-static const struct pcmcia_device_id ide_ids[] = {
- PCMCIA_DEVICE_FUNC_ID(4),
- PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000), /* Corsair */
- PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */
- PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000), /* I-O Data CFA */
- PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */
- PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
- PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904),
- PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), /* SanDisk CFA */
- PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000), /* Kingston */
- PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620), /* TI emulated */
- PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */
- PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
- PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */
- PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */
- PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
- PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0100), /* Viking CFA */
- PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar, Viking CFA */
- PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0),
- PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74),
- PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
- PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
- PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
- PCMCIA_DEVICE_PROD_ID12("CNF ", "CD-ROM", 0x46d7db81, 0x66536591),
- PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
- PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
- PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
- PCMCIA_DEVICE_PROD_ID12("EXP", "CD+GAME", 0x6f58c983, 0x63c13aaf),
- PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591),
- PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
- PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
- PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
- PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
- PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
- PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
- PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
- PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x55d5bffb),
- PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 4GB", 0x2e6d1829, 0x531e7d10),
- PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
- PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
- PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
- PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
- PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2 ", 0xe37be2b5, 0x8671043b),
- PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF300", 0x7ed2ad87, 0x7e9e78ee),
- PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
- PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
- PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
- PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728),
- PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1),
- PCMCIA_DEVICE_PROD_ID12("SEAGATE", "ST1", 0x87c1b330, 0xe1f30883),
- PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d),
- PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
- PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
- PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443),
- PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF45", 0x709b1bf1, 0xf68b6f32),
- PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
- PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
- PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
- PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x7558f133),
- PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS8GCF133", 0x709b1bf1, 0xb2f89b47),
- PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
- PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918),
- PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
- PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
- PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6),
- PCMCIA_DEVICE_PROD_ID2("Flash Card", 0x5a362506),
- PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, ide_ids);
-
-static struct pcmcia_driver ide_cs_driver = {
- .owner = THIS_MODULE,
- .name = "ide-cs",
- .probe = ide_probe,
- .remove = ide_detach,
- .id_table = ide_ids,
-};
-
-static int __init init_ide_cs(void)
-{
- return pcmcia_register_driver(&ide_cs_driver);
-}
-
-static void __exit exit_ide_cs(void)
-{
- pcmcia_unregister_driver(&ide_cs_driver);
-}
-
-late_initcall(init_ide_cs);
-module_exit(exit_ide_cs);
diff --git a/drivers/ide/ide-devsets.c b/drivers/ide/ide-devsets.c
deleted file mode 100644
index ca1d4b3d3878..000000000000
--- a/drivers/ide/ide-devsets.c
+++ /dev/null
@@ -1,192 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/ide.h>
-
-DEFINE_MUTEX(ide_setting_mtx);
-
-ide_devset_get(io_32bit, io_32bit);
-
-static int set_io_32bit(ide_drive_t *drive, int arg)
-{
- if (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT)
- return -EPERM;
-
- if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1))
- return -EINVAL;
-
- drive->io_32bit = arg;
-
- return 0;
-}
-
-ide_devset_get_flag(ksettings, IDE_DFLAG_KEEP_SETTINGS);
-
-static int set_ksettings(ide_drive_t *drive, int arg)
-{
- if (arg < 0 || arg > 1)
- return -EINVAL;
-
- if (arg)
- drive->dev_flags |= IDE_DFLAG_KEEP_SETTINGS;
- else
- drive->dev_flags &= ~IDE_DFLAG_KEEP_SETTINGS;
-
- return 0;
-}
-
-ide_devset_get_flag(using_dma, IDE_DFLAG_USING_DMA);
-
-static int set_using_dma(ide_drive_t *drive, int arg)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
- int err = -EPERM;
-
- if (arg < 0 || arg > 1)
- return -EINVAL;
-
- if (ata_id_has_dma(drive->id) == 0)
- goto out;
-
- if (drive->hwif->dma_ops == NULL)
- goto out;
-
- err = 0;
-
- if (arg) {
- if (ide_set_dma(drive))
- err = -EIO;
- } else
- ide_dma_off(drive);
-
-out:
- return err;
-#else
- if (arg < 0 || arg > 1)
- return -EINVAL;
-
- return -EPERM;
-#endif
-}
-
-/*
- * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away
- */
-static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
-{
- switch (req_pio) {
- case 202:
- case 201:
- case 200:
- case 102:
- case 101:
- case 100:
- return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;
- case 9:
- case 8:
- return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;
- case 7:
- case 6:
- return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;
- default:
- return 0;
- }
-}
-
-static int set_pio_mode(ide_drive_t *drive, int arg)
-{
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_port_ops *port_ops = hwif->port_ops;
-
- if (arg < 0 || arg > 255)
- return -EINVAL;
-
- if (port_ops == NULL || port_ops->set_pio_mode == NULL ||
- (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
- return -ENOSYS;
-
- if (set_pio_mode_abuse(drive->hwif, arg)) {
- drive->pio_mode = arg + XFER_PIO_0;
-
- if (arg == 8 || arg == 9) {
- unsigned long flags;
-
- /* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */
- spin_lock_irqsave(&hwif->lock, flags);
- port_ops->set_pio_mode(hwif, drive);
- spin_unlock_irqrestore(&hwif->lock, flags);
- } else
- port_ops->set_pio_mode(hwif, drive);
- } else {
- int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
-
- ide_set_pio(drive, arg);
-
- if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
- if (keep_dma)
- ide_dma_on(drive);
- }
- }
-
- return 0;
-}
-
-ide_devset_get_flag(unmaskirq, IDE_DFLAG_UNMASK);
-
-static int set_unmaskirq(ide_drive_t *drive, int arg)
-{
- if (drive->dev_flags & IDE_DFLAG_NO_UNMASK)
- return -EPERM;
-
- if (arg < 0 || arg > 1)
- return -EINVAL;
-
- if (arg)
- drive->dev_flags |= IDE_DFLAG_UNMASK;
- else
- drive->dev_flags &= ~IDE_DFLAG_UNMASK;
-
- return 0;
-}
-
-ide_ext_devset_rw_sync(io_32bit, io_32bit);
-ide_ext_devset_rw_sync(keepsettings, ksettings);
-ide_ext_devset_rw_sync(unmaskirq, unmaskirq);
-ide_ext_devset_rw_sync(using_dma, using_dma);
-__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode);
-
-int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
- int arg)
-{
- struct request_queue *q = drive->queue;
- struct request *rq;
- int ret = 0;
-
- if (!(setting->flags & DS_SYNC))
- return setting->set(drive, arg);
-
- rq = blk_get_request(q, REQ_OP_DRV_IN, 0);
- ide_req(rq)->type = ATA_PRIV_MISC;
- scsi_req(rq)->cmd_len = 5;
- scsi_req(rq)->cmd[0] = REQ_DEVSET_EXEC;
- *(int *)&scsi_req(rq)->cmd[1] = arg;
- ide_req(rq)->special = setting->set;
-
- blk_execute_rq(NULL, rq, 0);
- ret = scsi_req(rq)->result;
- blk_put_request(rq);
-
- return ret;
-}
-
-ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq)
-{
- int err, (*setfunc)(ide_drive_t *, int) = ide_req(rq)->special;
-
- err = setfunc(drive, *(int *)&scsi_req(rq)->cmd[1]);
- if (err)
- scsi_req(rq)->result = err;
- ide_complete_rq(drive, 0, blk_rq_bytes(rq));
- return ide_stopped;
-}
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
deleted file mode 100644
index 8413731c6259..000000000000
--- a/drivers/ide/ide-disk.c
+++ /dev/null
@@ -1,795 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
- * Copyright (C) 1998-2002 Linux ATA Development
- * Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2003 Red Hat
- * Copyright (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz
- */
-
-/*
- * Mostly written by Mark Lord <mlord@pobox.com>
- * and Gadi Oxman <gadio@netvision.net.il>
- * and Andre Hedrick <andre@linux-ide.org>
- *
- * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
- */
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/leds.h>
-#include <linux/ide.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <linux/uaccess.h>
-#include <asm/io.h>
-#include <asm/div64.h>
-
-#include "ide-disk.h"
-
-static const u8 ide_rw_cmds[] = {
- ATA_CMD_READ_MULTI,
- ATA_CMD_WRITE_MULTI,
- ATA_CMD_READ_MULTI_EXT,
- ATA_CMD_WRITE_MULTI_EXT,
- ATA_CMD_PIO_READ,
- ATA_CMD_PIO_WRITE,
- ATA_CMD_PIO_READ_EXT,
- ATA_CMD_PIO_WRITE_EXT,
- ATA_CMD_READ,
- ATA_CMD_WRITE,
- ATA_CMD_READ_EXT,
- ATA_CMD_WRITE_EXT,
-};
-
-static void ide_tf_set_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 dma)
-{
- u8 index, lba48, write;
-
- lba48 = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
- write = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
-
- if (dma) {
- cmd->protocol = ATA_PROT_DMA;
- index = 8;
- } else {
- cmd->protocol = ATA_PROT_PIO;
- if (drive->mult_count) {
- cmd->tf_flags |= IDE_TFLAG_MULTI_PIO;
- index = 0;
- } else
- index = 4;
- }
-
- cmd->tf.command = ide_rw_cmds[index + lba48 + write];
-}
-
-/*
- * __ide_do_rw_disk() issues READ and WRITE commands to a disk,
- * using LBA if supported, or CHS otherwise, to address sectors.
- */
-static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
- sector_t block)
-{
- ide_hwif_t *hwif = drive->hwif;
- u16 nsectors = (u16)blk_rq_sectors(rq);
- u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48);
- u8 dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
- struct ide_cmd cmd;
- struct ide_taskfile *tf = &cmd.tf;
- ide_startstop_t rc;
-
- if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
- if (block + blk_rq_sectors(rq) > 1ULL << 28)
- dma = 0;
- else
- lba48 = 0;
- }
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
-
- if (drive->dev_flags & IDE_DFLAG_LBA) {
- if (lba48) {
- pr_debug("%s: LBA=0x%012llx\n", drive->name,
- (unsigned long long)block);
-
- tf->nsect = nsectors & 0xff;
- tf->lbal = (u8) block;
- tf->lbam = (u8)(block >> 8);
- tf->lbah = (u8)(block >> 16);
- tf->device = ATA_LBA;
-
- tf = &cmd.hob;
- tf->nsect = (nsectors >> 8) & 0xff;
- tf->lbal = (u8)(block >> 24);
- if (sizeof(block) != 4) {
- tf->lbam = (u8)((u64)block >> 32);
- tf->lbah = (u8)((u64)block >> 40);
- }
-
- cmd.valid.out.hob = IDE_VALID_OUT_HOB;
- cmd.valid.in.hob = IDE_VALID_IN_HOB;
- cmd.tf_flags |= IDE_TFLAG_LBA48;
- } else {
- tf->nsect = nsectors & 0xff;
- tf->lbal = block;
- tf->lbam = block >>= 8;
- tf->lbah = block >>= 8;
- tf->device = ((block >> 8) & 0xf) | ATA_LBA;
- }
- } else {
- unsigned int sect, head, cyl, track;
-
- track = (int)block / drive->sect;
- sect = (int)block % drive->sect + 1;
- head = track % drive->head;
- cyl = track / drive->head;
-
- pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
-
- tf->nsect = nsectors & 0xff;
- tf->lbal = sect;
- tf->lbam = cyl;
- tf->lbah = cyl >> 8;
- tf->device = head;
- }
-
- cmd.tf_flags |= IDE_TFLAG_FS;
-
- if (rq_data_dir(rq))
- cmd.tf_flags |= IDE_TFLAG_WRITE;
-
- ide_tf_set_cmd(drive, &cmd, dma);
- cmd.rq = rq;
-
- if (dma == 0) {
- ide_init_sg_cmd(&cmd, nsectors << 9);
- ide_map_sg(drive, &cmd);
- }
-
- rc = do_rw_taskfile(drive, &cmd);
-
- if (rc == ide_stopped && dma) {
- /* fallback to PIO */
- cmd.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK;
- ide_tf_set_cmd(drive, &cmd, 0);
- ide_init_sg_cmd(&cmd, nsectors << 9);
- rc = do_rw_taskfile(drive, &cmd);
- }
-
- return rc;
-}
-
-/*
- * 268435455 == 137439 MB or 28bit limit
- * 320173056 == 163929 MB or 48bit addressing
- * 1073741822 == 549756 MB or 48bit addressing fake drive
- */
-
-static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
- sector_t block)
-{
- ide_hwif_t *hwif = drive->hwif;
-
- BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED);
- BUG_ON(blk_rq_is_passthrough(rq));
-
- ledtrig_disk_activity(rq_data_dir(rq) == WRITE);
-
- pr_debug("%s: %sing: block=%llu, sectors=%u\n",
- drive->name, rq_data_dir(rq) == READ ? "read" : "writ",
- (unsigned long long)block, blk_rq_sectors(rq));
-
- if (hwif->rw_disk)
- hwif->rw_disk(drive, rq);
-
- return __ide_do_rw_disk(drive, rq, block);
-}
-
-/*
- * Queries for true maximum capacity of the drive.
- * Returns maximum LBA address (> 0) of the drive, 0 if failed.
- */
-static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
-{
- struct ide_cmd cmd;
- struct ide_taskfile *tf = &cmd.tf;
- u64 addr = 0;
-
- memset(&cmd, 0, sizeof(cmd));
- if (lba48)
- tf->command = ATA_CMD_READ_NATIVE_MAX_EXT;
- else
- tf->command = ATA_CMD_READ_NATIVE_MAX;
- tf->device = ATA_LBA;
-
- cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
- if (lba48) {
- cmd.valid.out.hob = IDE_VALID_OUT_HOB;
- cmd.valid.in.hob = IDE_VALID_IN_HOB;
- cmd.tf_flags = IDE_TFLAG_LBA48;
- }
-
- ide_no_data_taskfile(drive, &cmd);
-
- /* if OK, compute maximum address value */
- if (!(tf->status & ATA_ERR))
- addr = ide_get_lba_addr(&cmd, lba48) + 1;
-
- return addr;
-}
-
-/*
- * Sets maximum virtual LBA address of the drive.
- * Returns new maximum virtual LBA address (> 0) or 0 on failure.
- */
-static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
-{
- struct ide_cmd cmd;
- struct ide_taskfile *tf = &cmd.tf;
- u64 addr_set = 0;
-
- addr_req--;
-
- memset(&cmd, 0, sizeof(cmd));
- tf->lbal = (addr_req >> 0) & 0xff;
- tf->lbam = (addr_req >>= 8) & 0xff;
- tf->lbah = (addr_req >>= 8) & 0xff;
- if (lba48) {
- cmd.hob.lbal = (addr_req >>= 8) & 0xff;
- cmd.hob.lbam = (addr_req >>= 8) & 0xff;
- cmd.hob.lbah = (addr_req >>= 8) & 0xff;
- tf->command = ATA_CMD_SET_MAX_EXT;
- } else {
- tf->device = (addr_req >>= 8) & 0x0f;
- tf->command = ATA_CMD_SET_MAX;
- }
- tf->device |= ATA_LBA;
-
- cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
- if (lba48) {
- cmd.valid.out.hob = IDE_VALID_OUT_HOB;
- cmd.valid.in.hob = IDE_VALID_IN_HOB;
- cmd.tf_flags = IDE_TFLAG_LBA48;
- }
-
- ide_no_data_taskfile(drive, &cmd);
-
- /* if OK, compute maximum address value */
- if (!(tf->status & ATA_ERR))
- addr_set = ide_get_lba_addr(&cmd, lba48) + 1;
-
- return addr_set;
-}
-
-static unsigned long long sectors_to_MB(unsigned long long n)
-{
- n <<= 9; /* make it bytes */
- do_div(n, 1000000); /* make it MB */
- return n;
-}
-
-/*
- * Some disks report total number of sectors instead of
- * maximum sector address. We list them here.
- */
-static const struct drive_list_entry hpa_list[] = {
- { "ST340823A", NULL },
- { "ST320413A", NULL },
- { "ST310211A", NULL },
- { NULL, NULL }
-};
-
-static u64 ide_disk_hpa_get_native_capacity(ide_drive_t *drive, int lba48)
-{
- u64 capacity, set_max;
-
- capacity = drive->capacity64;
- set_max = idedisk_read_native_max_address(drive, lba48);
-
- if (ide_in_drive_list(drive->id, hpa_list)) {
- /*
- * Since we are inclusive wrt to firmware revisions do this
- * extra check and apply the workaround only when needed.
- */
- if (set_max == capacity + 1)
- set_max--;
- }
-
- return set_max;
-}
-
-static u64 ide_disk_hpa_set_capacity(ide_drive_t *drive, u64 set_max, int lba48)
-{
- set_max = idedisk_set_max_address(drive, set_max, lba48);
- if (set_max)
- drive->capacity64 = set_max;
-
- return set_max;
-}
-
-static void idedisk_check_hpa(ide_drive_t *drive)
-{
- u64 capacity, set_max;
- int lba48 = ata_id_lba48_enabled(drive->id);
-
- capacity = drive->capacity64;
- set_max = ide_disk_hpa_get_native_capacity(drive, lba48);
-
- if (set_max <= capacity)
- return;
-
- drive->probed_capacity = set_max;
-
- printk(KERN_INFO "%s: Host Protected Area detected.\n"
- "\tcurrent capacity is %llu sectors (%llu MB)\n"
- "\tnative capacity is %llu sectors (%llu MB)\n",
- drive->name,
- capacity, sectors_to_MB(capacity),
- set_max, sectors_to_MB(set_max));
-
- if ((drive->dev_flags & IDE_DFLAG_NOHPA) == 0)
- return;
-
- set_max = ide_disk_hpa_set_capacity(drive, set_max, lba48);
- if (set_max)
- printk(KERN_INFO "%s: Host Protected Area disabled.\n",
- drive->name);
-}
-
-static int ide_disk_get_capacity(ide_drive_t *drive)
-{
- u16 *id = drive->id;
- int lba;
-
- if (ata_id_lba48_enabled(id)) {
- /* drive speaks 48-bit LBA */
- lba = 1;
- drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
- } else if (ata_id_has_lba(id) && ata_id_is_lba_capacity_ok(id)) {
- /* drive speaks 28-bit LBA */
- lba = 1;
- drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
- } else {
- /* drive speaks boring old 28-bit CHS */
- lba = 0;
- drive->capacity64 = drive->cyl * drive->head * drive->sect;
- }
-
- drive->probed_capacity = drive->capacity64;
-
- if (lba) {
- drive->dev_flags |= IDE_DFLAG_LBA;
-
- /*
- * If this device supports the Host Protected Area feature set,
- * then we may need to change our opinion about its capacity.
- */
- if (ata_id_hpa_enabled(id))
- idedisk_check_hpa(drive);
- }
-
- /* limit drive capacity to 137GB if LBA48 cannot be used */
- if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 &&
- drive->capacity64 > 1ULL << 28) {
- printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "
- "%llu sectors (%llu MB)\n",
- drive->name, (unsigned long long)drive->capacity64,
- sectors_to_MB(drive->capacity64));
- drive->probed_capacity = drive->capacity64 = 1ULL << 28;
- }
-
- if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) &&
- (drive->dev_flags & IDE_DFLAG_LBA48)) {
- if (drive->capacity64 > 1ULL << 28) {
- printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode"
- " will be used for accessing sectors "
- "> %u\n", drive->name, 1 << 28);
- } else
- drive->dev_flags &= ~IDE_DFLAG_LBA48;
- }
-
- return 0;
-}
-
-static void ide_disk_unlock_native_capacity(ide_drive_t *drive)
-{
- u16 *id = drive->id;
- int lba48 = ata_id_lba48_enabled(id);
-
- if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 ||
- ata_id_hpa_enabled(id) == 0)
- return;
-
- /*
- * according to the spec the SET MAX ADDRESS command shall be
- * immediately preceded by a READ NATIVE MAX ADDRESS command
- */
- if (!ide_disk_hpa_get_native_capacity(drive, lba48))
- return;
-
- if (ide_disk_hpa_set_capacity(drive, drive->probed_capacity, lba48))
- drive->dev_flags |= IDE_DFLAG_NOHPA; /* disable HPA on resume */
-}
-
-static bool idedisk_prep_rq(ide_drive_t *drive, struct request *rq)
-{
- struct ide_cmd *cmd;
-
- if (req_op(rq) != REQ_OP_FLUSH)
- return true;
-
- if (ide_req(rq)->special) {
- cmd = ide_req(rq)->special;
- memset(cmd, 0, sizeof(*cmd));
- } else {
- cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
- }
-
- /* FIXME: map struct ide_taskfile on rq->cmd[] */
- BUG_ON(cmd == NULL);
-
- if (ata_id_flush_ext_enabled(drive->id) &&
- (drive->capacity64 >= (1UL << 28)))
- cmd->tf.command = ATA_CMD_FLUSH_EXT;
- else
- cmd->tf.command = ATA_CMD_FLUSH;
- cmd->valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd->tf_flags = IDE_TFLAG_DYN;
- cmd->protocol = ATA_PROT_NODATA;
- rq->cmd_flags &= ~REQ_OP_MASK;
- rq->cmd_flags |= REQ_OP_DRV_OUT;
- ide_req(rq)->type = ATA_PRIV_TASKFILE;
- ide_req(rq)->special = cmd;
- cmd->rq = rq;
-
- return true;
-}
-
-ide_devset_get(multcount, mult_count);
-
-/*
- * This is tightly woven into the driver->do_special can not touch.
- * DON'T do it again until a total personality rewrite is committed.
- */
-static int set_multcount(ide_drive_t *drive, int arg)
-{
- struct request *rq;
-
- if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff))
- return -EINVAL;
-
- if (drive->special_flags & IDE_SFLAG_SET_MULTMODE)
- return -EBUSY;
-
- rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
- ide_req(rq)->type = ATA_PRIV_TASKFILE;
-
- drive->mult_req = arg;
- drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
- blk_execute_rq(NULL, rq, 0);
- blk_put_request(rq);
-
- return (drive->mult_count == arg) ? 0 : -EIO;
-}
-
-ide_devset_get_flag(nowerr, IDE_DFLAG_NOWERR);
-
-static int set_nowerr(ide_drive_t *drive, int arg)
-{
- if (arg < 0 || arg > 1)
- return -EINVAL;
-
- if (arg)
- drive->dev_flags |= IDE_DFLAG_NOWERR;
- else
- drive->dev_flags &= ~IDE_DFLAG_NOWERR;
-
- drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
-
- return 0;
-}
-
-static int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect)
-{
- struct ide_cmd cmd;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.tf.feature = feature;
- cmd.tf.nsect = nsect;
- cmd.tf.command = ATA_CMD_SET_FEATURES;
- cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
-
- return ide_no_data_taskfile(drive, &cmd);
-}
-
-static void update_flush(ide_drive_t *drive)
-{
- u16 *id = drive->id;
- bool wc = false;
-
- if (drive->dev_flags & IDE_DFLAG_WCACHE) {
- unsigned long long capacity;
- int barrier;
- /*
- * We must avoid issuing commands a drive does not
- * understand or we may crash it. We check flush cache
- * is supported. We also check we have the LBA48 flush
- * cache if the drive capacity is too large. By this
- * time we have trimmed the drive capacity if LBA48 is
- * not available so we don't need to recheck that.
- */
- capacity = ide_gd_capacity(drive);
- barrier = ata_id_flush_enabled(id) &&
- (drive->dev_flags & IDE_DFLAG_NOFLUSH) == 0 &&
- ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 ||
- capacity <= (1ULL << 28) ||
- ata_id_flush_ext_enabled(id));
-
- printk(KERN_INFO "%s: cache flushes %ssupported\n",
- drive->name, barrier ? "" : "not ");
-
- if (barrier) {
- wc = true;
- drive->prep_rq = idedisk_prep_rq;
- }
- }
-
- blk_queue_write_cache(drive->queue, wc, false);
-}
-
-ide_devset_get_flag(wcache, IDE_DFLAG_WCACHE);
-
-static int set_wcache(ide_drive_t *drive, int arg)
-{
- int err = 1;
-
- if (arg < 0 || arg > 1)
- return -EINVAL;
-
- if (ata_id_flush_enabled(drive->id)) {
- err = ide_do_setfeature(drive,
- arg ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF, 0);
- if (err == 0) {
- if (arg)
- drive->dev_flags |= IDE_DFLAG_WCACHE;
- else
- drive->dev_flags &= ~IDE_DFLAG_WCACHE;
- }
- }
-
- update_flush(drive);
-
- return err;
-}
-
-static int do_idedisk_flushcache(ide_drive_t *drive)
-{
- struct ide_cmd cmd;
-
- memset(&cmd, 0, sizeof(cmd));
- if (ata_id_flush_ext_enabled(drive->id))
- cmd.tf.command = ATA_CMD_FLUSH_EXT;
- else
- cmd.tf.command = ATA_CMD_FLUSH;
- cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
-
- return ide_no_data_taskfile(drive, &cmd);
-}
-
-ide_devset_get(acoustic, acoustic);
-
-static int set_acoustic(ide_drive_t *drive, int arg)
-{
- if (arg < 0 || arg > 254)
- return -EINVAL;
-
- ide_do_setfeature(drive,
- arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF, arg);
-
- drive->acoustic = arg;
-
- return 0;
-}
-
-ide_devset_get_flag(addressing, IDE_DFLAG_LBA48);
-
-/*
- * drive->addressing:
- * 0: 28-bit
- * 1: 48-bit
- * 2: 48-bit capable doing 28-bit
- */
-static int set_addressing(ide_drive_t *drive, int arg)
-{
- if (arg < 0 || arg > 2)
- return -EINVAL;
-
- if (arg && ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
- ata_id_lba48_enabled(drive->id) == 0))
- return -EIO;
-
- if (arg == 2)
- arg = 0;
-
- if (arg)
- drive->dev_flags |= IDE_DFLAG_LBA48;
- else
- drive->dev_flags &= ~IDE_DFLAG_LBA48;
-
- return 0;
-}
-
-ide_ext_devset_rw(acoustic, acoustic);
-ide_ext_devset_rw(address, addressing);
-ide_ext_devset_rw(multcount, multcount);
-ide_ext_devset_rw(wcache, wcache);
-
-ide_ext_devset_rw_sync(nowerr, nowerr);
-
-static int ide_disk_check(ide_drive_t *drive, const char *s)
-{
- return 1;
-}
-
-static void ide_disk_setup(ide_drive_t *drive)
-{
- struct ide_disk_obj *idkp = drive->driver_data;
- struct request_queue *q = drive->queue;
- ide_hwif_t *hwif = drive->hwif;
- u16 *id = drive->id;
- char *m = (char *)&id[ATA_ID_PROD];
- unsigned long long capacity;
-
- ide_proc_register_driver(drive, idkp->driver);
-
- if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0)
- return;
-
- if (drive->dev_flags & IDE_DFLAG_REMOVABLE) {
- /*
- * Removable disks (eg. SYQUEST); ignore 'WD' drives
- */
- if (m[0] != 'W' || m[1] != 'D')
- drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
- }
-
- (void)set_addressing(drive, 1);
-
- if (drive->dev_flags & IDE_DFLAG_LBA48) {
- int max_s = 2048;
-
- if (max_s > hwif->rqsize)
- max_s = hwif->rqsize;
-
- blk_queue_max_hw_sectors(q, max_s);
- }
-
- printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name,
- queue_max_sectors(q) / 2);
-
- if (ata_id_is_ssd(id)) {
- blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
- blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q);
- }
-
- /* calculate drive capacity, and select LBA if possible */
- ide_disk_get_capacity(drive);
-
- /*
- * if possible, give fdisk access to more of the drive,
- * by correcting bios_cyls:
- */
- capacity = ide_gd_capacity(drive);
-
- if ((drive->dev_flags & IDE_DFLAG_FORCED_GEOM) == 0) {
- if (ata_id_lba48_enabled(drive->id)) {
- /* compatibility */
- drive->bios_sect = 63;
- drive->bios_head = 255;
- }
-
- if (drive->bios_sect && drive->bios_head) {
- unsigned int cap0 = capacity; /* truncate to 32 bits */
- unsigned int cylsz, cyl;
-
- if (cap0 != capacity)
- drive->bios_cyl = 65535;
- else {
- cylsz = drive->bios_sect * drive->bios_head;
- cyl = cap0 / cylsz;
- if (cyl > 65535)
- cyl = 65535;
- if (cyl > drive->bios_cyl)
- drive->bios_cyl = cyl;
- }
- }
- }
- printk(KERN_INFO "%s: %llu sectors (%llu MB)",
- drive->name, capacity, sectors_to_MB(capacity));
-
- /* Only print cache size when it was specified */
- if (id[ATA_ID_BUF_SIZE])
- printk(KERN_CONT " w/%dKiB Cache", id[ATA_ID_BUF_SIZE] / 2);
-
- printk(KERN_CONT ", CHS=%d/%d/%d\n",
- drive->bios_cyl, drive->bios_head, drive->bios_sect);
-
- /* write cache enabled? */
- if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id))
- drive->dev_flags |= IDE_DFLAG_WCACHE;
-
- set_wcache(drive, 1);
-
- if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 &&
- (drive->head == 0 || drive->head > 16))
- printk(KERN_ERR "%s: invalid geometry: %d physical heads?\n",
- drive->name, drive->head);
-}
-
-static void ide_disk_flush(ide_drive_t *drive)
-{
- if (ata_id_flush_enabled(drive->id) == 0 ||
- (drive->dev_flags & IDE_DFLAG_WCACHE) == 0)
- return;
-
- if (do_idedisk_flushcache(drive))
- printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
-}
-
-static int ide_disk_init_media(ide_drive_t *drive, struct gendisk *disk)
-{
- return 0;
-}
-
-static int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk,
- int on)
-{
- struct ide_cmd cmd;
- int ret;
-
- if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0)
- return 0;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
- cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
-
- ret = ide_no_data_taskfile(drive, &cmd);
-
- if (ret)
- drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
-
- return ret;
-}
-
-const struct ide_disk_ops ide_ata_disk_ops = {
- .check = ide_disk_check,
- .unlock_native_capacity = ide_disk_unlock_native_capacity,
- .get_capacity = ide_disk_get_capacity,
- .setup = ide_disk_setup,
- .flush = ide_disk_flush,
- .init_media = ide_disk_init_media,
- .set_doorlock = ide_disk_set_doorlock,
- .do_request = ide_do_rw_disk,
- .ioctl = ide_disk_ioctl,
- .compat_ioctl = ide_disk_ioctl,
-};
diff --git a/drivers/ide/ide-disk.h b/drivers/ide/ide-disk.h
deleted file mode 100644
index 0e8cc18bfda6..000000000000
--- a/drivers/ide/ide-disk.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __IDE_DISK_H
-#define __IDE_DISK_H
-
-#include "ide-gd.h"
-
-#ifdef CONFIG_IDE_GD_ATA
-/* ide-disk.c */
-extern const struct ide_disk_ops ide_ata_disk_ops;
-ide_decl_devset(address);
-ide_decl_devset(multcount);
-ide_decl_devset(nowerr);
-ide_decl_devset(wcache);
-ide_decl_devset(acoustic);
-
-/* ide-disk_ioctl.c */
-int ide_disk_ioctl(ide_drive_t *, struct block_device *, fmode_t, unsigned int,
- unsigned long);
-
-#ifdef CONFIG_IDE_PROC_FS
-/* ide-disk_proc.c */
-extern ide_proc_entry_t ide_disk_proc[];
-extern const struct ide_proc_devset ide_disk_settings[];
-#endif
-#else
-#define ide_disk_proc NULL
-#define ide_disk_settings NULL
-#endif
-
-#endif /* __IDE_DISK_H */
diff --git a/drivers/ide/ide-disk_ioctl.c b/drivers/ide/ide-disk_ioctl.c
deleted file mode 100644
index 2c45616cff4f..000000000000
--- a/drivers/ide/ide-disk_ioctl.c
+++ /dev/null
@@ -1,33 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/kernel.h>
-#include <linux/ide.h>
-#include <linux/hdreg.h>
-#include <linux/mutex.h>
-
-#include "ide-disk.h"
-
-static DEFINE_MUTEX(ide_disk_ioctl_mutex);
-static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = {
-{ HDIO_GET_ADDRESS, HDIO_SET_ADDRESS, &ide_devset_address },
-{ HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, &ide_devset_multcount },
-{ HDIO_GET_NOWERR, HDIO_SET_NOWERR, &ide_devset_nowerr },
-{ HDIO_GET_WCACHE, HDIO_SET_WCACHE, &ide_devset_wcache },
-{ HDIO_GET_ACOUSTIC, HDIO_SET_ACOUSTIC, &ide_devset_acoustic },
-{ 0 }
-};
-
-int ide_disk_ioctl(ide_drive_t *drive, struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- int err;
-
- mutex_lock(&ide_disk_ioctl_mutex);
- err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings);
- if (err != -EOPNOTSUPP)
- goto out;
-
- err = generic_ide_ioctl(drive, bdev, cmd, arg);
-out:
- mutex_unlock(&ide_disk_ioctl_mutex);
- return err;
-}
diff --git a/drivers/ide/ide-disk_proc.c b/drivers/ide/ide-disk_proc.c
deleted file mode 100644
index 95d239b2f646..000000000000
--- a/drivers/ide/ide-disk_proc.c
+++ /dev/null
@@ -1,125 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/kernel.h>
-#include <linux/ide.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/seq_file.h>
-
-#include "ide-disk.h"
-
-static int smart_enable(ide_drive_t *drive)
-{
- struct ide_cmd cmd;
- struct ide_taskfile *tf = &cmd.tf;
-
- memset(&cmd, 0, sizeof(cmd));
- tf->feature = ATA_SMART_ENABLE;
- tf->lbam = ATA_SMART_LBAM_PASS;
- tf->lbah = ATA_SMART_LBAH_PASS;
- tf->command = ATA_CMD_SMART;
- cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
-
- return ide_no_data_taskfile(drive, &cmd);
-}
-
-static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
-{
- struct ide_cmd cmd;
- struct ide_taskfile *tf = &cmd.tf;
-
- memset(&cmd, 0, sizeof(cmd));
- tf->feature = sub_cmd;
- tf->nsect = 0x01;
- tf->lbam = ATA_SMART_LBAM_PASS;
- tf->lbah = ATA_SMART_LBAH_PASS;
- tf->command = ATA_CMD_SMART;
- cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
- cmd.protocol = ATA_PROT_PIO;
-
- return ide_raw_taskfile(drive, &cmd, buf, 1);
-}
-
-static int idedisk_cache_proc_show(struct seq_file *m, void *v)
-{
- ide_drive_t *drive = (ide_drive_t *) m->private;
-
- if (drive->dev_flags & IDE_DFLAG_ID_READ)
- seq_printf(m, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2);
- else
- seq_printf(m, "(none)\n");
- return 0;
-}
-
-static int idedisk_capacity_proc_show(struct seq_file *m, void *v)
-{
- ide_drive_t*drive = (ide_drive_t *)m->private;
-
- seq_printf(m, "%llu\n", (long long)ide_gd_capacity(drive));
- return 0;
-}
-
-static int __idedisk_proc_show(struct seq_file *m, ide_drive_t *drive, u8 sub_cmd)
-{
- u8 *buf;
-
- buf = kmalloc(SECTOR_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- (void)smart_enable(drive);
-
- if (get_smart_data(drive, buf, sub_cmd) == 0) {
- __le16 *val = (__le16 *)buf;
- int i;
-
- for (i = 0; i < SECTOR_SIZE / 2; i++) {
- seq_printf(m, "%04x%c", le16_to_cpu(val[i]),
- (i % 8) == 7 ? '\n' : ' ');
- }
- }
- kfree(buf);
- return 0;
-}
-
-static int idedisk_sv_proc_show(struct seq_file *m, void *v)
-{
- return __idedisk_proc_show(m, m->private, ATA_SMART_READ_VALUES);
-}
-
-static int idedisk_st_proc_show(struct seq_file *m, void *v)
-{
- return __idedisk_proc_show(m, m->private, ATA_SMART_READ_THRESHOLDS);
-}
-
-ide_proc_entry_t ide_disk_proc[] = {
- { "cache", S_IFREG|S_IRUGO, idedisk_cache_proc_show },
- { "capacity", S_IFREG|S_IRUGO, idedisk_capacity_proc_show },
- { "geometry", S_IFREG|S_IRUGO, ide_geometry_proc_show },
- { "smart_values", S_IFREG|S_IRUSR, idedisk_sv_proc_show },
- { "smart_thresholds", S_IFREG|S_IRUSR, idedisk_st_proc_show },
- {}
-};
-
-ide_devset_rw_field(bios_cyl, bios_cyl);
-ide_devset_rw_field(bios_head, bios_head);
-ide_devset_rw_field(bios_sect, bios_sect);
-ide_devset_rw_field(failures, failures);
-ide_devset_rw_field(lun, lun);
-ide_devset_rw_field(max_failures, max_failures);
-
-const struct ide_proc_devset ide_disk_settings[] = {
- IDE_PROC_DEVSET(acoustic, 0, 254),
- IDE_PROC_DEVSET(address, 0, 2),
- IDE_PROC_DEVSET(bios_cyl, 0, 65535),
- IDE_PROC_DEVSET(bios_head, 0, 255),
- IDE_PROC_DEVSET(bios_sect, 0, 63),
- IDE_PROC_DEVSET(failures, 0, 65535),
- IDE_PROC_DEVSET(lun, 0, 7),
- IDE_PROC_DEVSET(max_failures, 0, 65535),
- IDE_PROC_DEVSET(multcount, 0, 16),
- IDE_PROC_DEVSET(nowerr, 0, 1),
- IDE_PROC_DEVSET(wcache, 0, 1),
- { NULL },
-};
diff --git a/drivers/ide/ide-dma-sff.c b/drivers/ide/ide-dma-sff.c
deleted file mode 100644
index b7c2c0bd18b5..000000000000
--- a/drivers/ide/ide-dma-sff.c
+++ /dev/null
@@ -1,336 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/ide.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-
-/**
- * config_drive_for_dma - attempt to activate IDE DMA
- * @drive: the drive to place in DMA mode
- *
- * If the drive supports at least mode 2 DMA or UDMA of any kind
- * then attempt to place it into DMA mode. Drives that are known to
- * support DMA but predate the DMA properties or that are known
- * to have DMA handling bugs are also set up appropriately based
- * on the good/bad drive lists.
- */
-
-int config_drive_for_dma(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u16 *id = drive->id;
-
- if (drive->media != ide_disk) {
- if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
- return 0;
- }
-
- /*
- * Enable DMA on any drive that has
- * UltraDMA (mode 0/1/2/3/4/5/6) enabled
- */
- if ((id[ATA_ID_FIELD_VALID] & 4) &&
- ((id[ATA_ID_UDMA_MODES] >> 8) & 0x7f))
- return 1;
-
- /*
- * Enable DMA on any drive that has mode2 DMA
- * (multi or single) enabled
- */
- if ((id[ATA_ID_MWDMA_MODES] & 0x404) == 0x404 ||
- (id[ATA_ID_SWDMA_MODES] & 0x404) == 0x404)
- return 1;
-
- /* Consult the list of known "good" drives */
- if (ide_dma_good_drive(drive))
- return 1;
-
- return 0;
-}
-
-u8 ide_dma_sff_read_status(ide_hwif_t *hwif)
-{
- unsigned long addr = hwif->dma_base + ATA_DMA_STATUS;
-
- if (hwif->host_flags & IDE_HFLAG_MMIO)
- return readb((void __iomem *)addr);
- else
- return inb(addr);
-}
-EXPORT_SYMBOL_GPL(ide_dma_sff_read_status);
-
-static void ide_dma_sff_write_status(ide_hwif_t *hwif, u8 val)
-{
- unsigned long addr = hwif->dma_base + ATA_DMA_STATUS;
-
- if (hwif->host_flags & IDE_HFLAG_MMIO)
- writeb(val, (void __iomem *)addr);
- else
- outb(val, addr);
-}
-
-/**
- * ide_dma_host_set - Enable/disable DMA on a host
- * @drive: drive to control
- *
- * Enable/disable DMA on an IDE controller following generic
- * bus-mastering IDE controller behaviour.
- */
-
-void ide_dma_host_set(ide_drive_t *drive, int on)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 unit = drive->dn & 1;
- u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
-
- if (on)
- dma_stat |= (1 << (5 + unit));
- else
- dma_stat &= ~(1 << (5 + unit));
-
- ide_dma_sff_write_status(hwif, dma_stat);
-}
-EXPORT_SYMBOL_GPL(ide_dma_host_set);
-
-/**
- * ide_build_dmatable - build IDE DMA table
- *
- * ide_build_dmatable() prepares a dma request. We map the command
- * to get the pci bus addresses of the buffers and then build up
- * the PRD table that the IDE layer wants to be fed.
- *
- * Most chipsets correctly interpret a length of 0x0000 as 64KB,
- * but at least one (e.g. CS5530) misinterprets it as zero (!).
- * So we break the 64KB entry into two 32KB entries instead.
- *
- * Returns the number of built PRD entries if all went okay,
- * returns 0 otherwise.
- *
- * May also be invoked from trm290.c
- */
-
-int ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
- __le32 *table = (__le32 *)hwif->dmatable_cpu;
- unsigned int count = 0;
- int i;
- struct scatterlist *sg;
- u8 is_trm290 = !!(hwif->host_flags & IDE_HFLAG_TRM290);
-
- for_each_sg(hwif->sg_table, sg, cmd->sg_nents, i) {
- u32 cur_addr, cur_len, xcount, bcount;
-
- cur_addr = sg_dma_address(sg);
- cur_len = sg_dma_len(sg);
-
- /*
- * Fill in the dma table, without crossing any 64kB boundaries.
- * Most hardware requires 16-bit alignment of all blocks,
- * but the trm290 requires 32-bit alignment.
- */
-
- while (cur_len) {
- if (count++ >= PRD_ENTRIES)
- goto use_pio_instead;
-
- bcount = 0x10000 - (cur_addr & 0xffff);
- if (bcount > cur_len)
- bcount = cur_len;
- *table++ = cpu_to_le32(cur_addr);
- xcount = bcount & 0xffff;
- if (is_trm290)
- xcount = ((xcount >> 2) - 1) << 16;
- else if (xcount == 0x0000) {
- if (count++ >= PRD_ENTRIES)
- goto use_pio_instead;
- *table++ = cpu_to_le32(0x8000);
- *table++ = cpu_to_le32(cur_addr + 0x8000);
- xcount = 0x8000;
- }
- *table++ = cpu_to_le32(xcount);
- cur_addr += bcount;
- cur_len -= bcount;
- }
- }
-
- if (count) {
- if (!is_trm290)
- *--table |= cpu_to_le32(0x80000000);
- return count;
- }
-
-use_pio_instead:
- printk(KERN_ERR "%s: %s\n", drive->name,
- count ? "DMA table too small" : "empty DMA table?");
-
- return 0; /* revert to PIO for this request */
-}
-EXPORT_SYMBOL_GPL(ide_build_dmatable);
-
-/**
- * ide_dma_setup - begin a DMA phase
- * @drive: target device
- * @cmd: command
- *
- * Build an IDE DMA PRD (IDE speak for scatter gather table)
- * and then set up the DMA transfer registers for a device
- * that follows generic IDE PCI DMA behaviour. Controllers can
- * override this function if they need to
- *
- * Returns 0 on success. If a PIO fallback is required then 1
- * is returned.
- */
-
-int ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
- u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR;
- u8 dma_stat;
-
- /* fall back to pio! */
- if (ide_build_dmatable(drive, cmd) == 0) {
- ide_map_sg(drive, cmd);
- return 1;
- }
-
- /* PRD table */
- if (mmio)
- writel(hwif->dmatable_dma,
- (void __iomem *)(hwif->dma_base + ATA_DMA_TABLE_OFS));
- else
- outl(hwif->dmatable_dma, hwif->dma_base + ATA_DMA_TABLE_OFS);
-
- /* specify r/w */
- if (mmio)
- writeb(rw, (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
- else
- outb(rw, hwif->dma_base + ATA_DMA_CMD);
-
- /* read DMA status for INTR & ERROR flags */
- dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
-
- /* clear INTR & ERROR flags */
- ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ide_dma_setup);
-
-/**
- * ide_dma_sff_timer_expiry - handle a DMA timeout
- * @drive: Drive that timed out
- *
- * An IDE DMA transfer timed out. In the event of an error we ask
- * the driver to resolve the problem, if a DMA transfer is still
- * in progress we continue to wait (arguably we need to add a
- * secondary 'I don't care what the drive thinks' timeout here)
- * Finally if we have an interrupt we let it complete the I/O.
- * But only one time - we clear expiry and if it's still not
- * completed after WAIT_CMD, we error and retry in PIO.
- * This can occur if an interrupt is lost or due to hang or bugs.
- */
-
-int ide_dma_sff_timer_expiry(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
-
- printk(KERN_WARNING "%s: %s: DMA status (0x%02x)\n",
- drive->name, __func__, dma_stat);
-
- if ((dma_stat & 0x18) == 0x18) /* BUSY Stupid Early Timer !! */
- return WAIT_CMD;
-
- hwif->expiry = NULL; /* one free ride for now */
-
- if (dma_stat & ATA_DMA_ERR) /* ERROR */
- return -1;
-
- if (dma_stat & ATA_DMA_ACTIVE) /* DMAing */
- return WAIT_CMD;
-
- if (dma_stat & ATA_DMA_INTR) /* Got an Interrupt */
- return WAIT_CMD;
-
- return 0; /* Status is unknown -- reset the bus */
-}
-EXPORT_SYMBOL_GPL(ide_dma_sff_timer_expiry);
-
-void ide_dma_start(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 dma_cmd;
-
- /* Note that this is done *after* the cmd has
- * been issued to the drive, as per the BM-IDE spec.
- * The Promise Ultra33 doesn't work correctly when
- * we do this part before issuing the drive cmd.
- */
- if (hwif->host_flags & IDE_HFLAG_MMIO) {
- dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
- writeb(dma_cmd | ATA_DMA_START,
- (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
- } else {
- dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
- outb(dma_cmd | ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD);
- }
-}
-EXPORT_SYMBOL_GPL(ide_dma_start);
-
-/* returns 1 on error, 0 otherwise */
-int ide_dma_end(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 dma_stat = 0, dma_cmd = 0;
-
- /* stop DMA */
- if (hwif->host_flags & IDE_HFLAG_MMIO) {
- dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
- writeb(dma_cmd & ~ATA_DMA_START,
- (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
- } else {
- dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
- outb(dma_cmd & ~ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD);
- }
-
- /* get DMA status */
- dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
-
- /* clear INTR & ERROR bits */
- ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR);
-
-#define CHECK_DMA_MASK (ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR)
-
- /* verify good DMA status */
- if ((dma_stat & CHECK_DMA_MASK) != ATA_DMA_INTR)
- return 0x10 | dma_stat;
- return 0;
-}
-EXPORT_SYMBOL_GPL(ide_dma_end);
-
-/* returns 1 if dma irq issued, 0 otherwise */
-int ide_dma_test_irq(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
-
- return (dma_stat & ATA_DMA_INTR) ? 1 : 0;
-}
-EXPORT_SYMBOL_GPL(ide_dma_test_irq);
-
-const struct ide_dma_ops sff_dma_ops = {
- .dma_host_set = ide_dma_host_set,
- .dma_setup = ide_dma_setup,
- .dma_start = ide_dma_start,
- .dma_end = ide_dma_end,
- .dma_test_irq = ide_dma_test_irq,
- .dma_lost_irq = ide_dma_lost_irq,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_sff_read_status = ide_dma_sff_read_status,
-};
-EXPORT_SYMBOL_GPL(sff_dma_ops);
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
deleted file mode 100644
index 6f344654ef22..000000000000
--- a/drivers/ide/ide-dma.c
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * IDE DMA support (including IDE PCI BM-DMA).
- *
- * Copyright (C) 1995-1998 Mark Lord
- * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2004, 2007 Bartlomiej Zolnierkiewicz
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- * DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies).
- */
-
-/*
- * Special Thanks to Mark for his Six years of work.
- */
-
-/*
- * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for
- * fixing the problem with the BIOS on some Acer motherboards.
- *
- * Thanks to "Benoit Poulot-Cazajous" <poulot@chorus.fr> for testing
- * "TX" chipset compatibility and for providing patches for the "TX" chipset.
- *
- * Thanks to Christian Brunner <chb@muc.de> for taking a good first crack
- * at generic DMA -- his patches were referred to when preparing this code.
- *
- * Most importantly, thanks to Robert Bringman <rob@mars.trion.com>
- * for supplying a Promise UDMA board & WD UDMA drive for this work!
- */
-
-#include <linux/types.h>
-#include <linux/gfp.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/ide.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-
-static const struct drive_list_entry drive_whitelist[] = {
- { "Micropolis 2112A" , NULL },
- { "CONNER CTMA 4000" , NULL },
- { "CONNER CTT8000-A" , NULL },
- { "ST34342A" , NULL },
- { NULL , NULL }
-};
-
-static const struct drive_list_entry drive_blacklist[] = {
- { "WDC AC11000H" , NULL },
- { "WDC AC22100H" , NULL },
- { "WDC AC32500H" , NULL },
- { "WDC AC33100H" , NULL },
- { "WDC AC31600H" , NULL },
- { "WDC AC32100H" , "24.09P07" },
- { "WDC AC23200L" , "21.10N21" },
- { "Compaq CRD-8241B" , NULL },
- { "CRD-8400B" , NULL },
- { "CRD-8480B", NULL },
- { "CRD-8482B", NULL },
- { "CRD-84" , NULL },
- { "SanDisk SDP3B" , NULL },
- { "SanDisk SDP3B-64" , NULL },
- { "SANYO CD-ROM CRD" , NULL },
- { "HITACHI CDR-8" , NULL },
- { "HITACHI CDR-8335" , NULL },
- { "HITACHI CDR-8435" , NULL },
- { "Toshiba CD-ROM XM-6202B" , NULL },
- { "TOSHIBA CD-ROM XM-1702BC", NULL },
- { "CD-532E-A" , NULL },
- { "E-IDE CD-ROM CR-840", NULL },
- { "CD-ROM Drive/F5A", NULL },
- { "WPI CDD-820", NULL },
- { "SAMSUNG CD-ROM SC-148C", NULL },
- { "SAMSUNG CD-ROM SC", NULL },
- { "ATAPI CD-ROM DRIVE 40X MAXIMUM", NULL },
- { "_NEC DV5800A", NULL },
- { "SAMSUNG CD-ROM SN-124", "N001" },
- { "Seagate STT20000A", NULL },
- { "CD-ROM CDR_U200", "1.09" },
- { NULL , NULL }
-
-};
-
-/**
- * ide_dma_intr - IDE DMA interrupt handler
- * @drive: the drive the interrupt is for
- *
- * Handle an interrupt completing a read/write DMA transfer on an
- * IDE device
- */
-
-ide_startstop_t ide_dma_intr(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct ide_cmd *cmd = &hwif->cmd;
- u8 stat = 0, dma_stat = 0;
-
- drive->waiting_for_dma = 0;
- dma_stat = hwif->dma_ops->dma_end(drive);
- ide_dma_unmap_sg(drive, cmd);
- stat = hwif->tp_ops->read_status(hwif);
-
- if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | ATA_DRQ)) {
- if (!dma_stat) {
- if ((cmd->tf_flags & IDE_TFLAG_FS) == 0)
- ide_finish_cmd(drive, cmd, stat);
- else
- ide_complete_rq(drive, BLK_STS_OK,
- blk_rq_sectors(cmd->rq) << 9);
- return ide_stopped;
- }
- printk(KERN_ERR "%s: %s: bad DMA status (0x%02x)\n",
- drive->name, __func__, dma_stat);
- }
- return ide_error(drive, "dma_intr", stat);
-}
-
-int ide_dma_good_drive(ide_drive_t *drive)
-{
- return ide_in_drive_list(drive->id, drive_whitelist);
-}
-
-/**
- * ide_dma_map_sg - map IDE scatter gather for DMA I/O
- * @drive: the drive to map the DMA table for
- * @cmd: command
- *
- * Perform the DMA mapping magic necessary to access the source or
- * target buffers of a request via DMA. The lower layers of the
- * kernel provide the necessary cache management so that we can
- * operate in a portable fashion.
- */
-
-static int ide_dma_map_sg(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct scatterlist *sg = hwif->sg_table;
- int i;
-
- if (cmd->tf_flags & IDE_TFLAG_WRITE)
- cmd->sg_dma_direction = DMA_TO_DEVICE;
- else
- cmd->sg_dma_direction = DMA_FROM_DEVICE;
-
- i = dma_map_sg(hwif->dev, sg, cmd->sg_nents, cmd->sg_dma_direction);
- if (i) {
- cmd->orig_sg_nents = cmd->sg_nents;
- cmd->sg_nents = i;
- }
-
- return i;
-}
-
-/**
- * ide_dma_unmap_sg - clean up DMA mapping
- * @drive: The drive to unmap
- *
- * Teardown mappings after DMA has completed. This must be called
- * after the completion of each use of ide_build_dmatable and before
- * the next use of ide_build_dmatable. Failure to do so will cause
- * an oops as only one mapping can be live for each target at a given
- * time.
- */
-
-void ide_dma_unmap_sg(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
-
- dma_unmap_sg(hwif->dev, hwif->sg_table, cmd->orig_sg_nents,
- cmd->sg_dma_direction);
-}
-EXPORT_SYMBOL_GPL(ide_dma_unmap_sg);
-
-/**
- * ide_dma_off_quietly - Generic DMA kill
- * @drive: drive to control
- *
- * Turn off the current DMA on this IDE controller.
- */
-
-void ide_dma_off_quietly(ide_drive_t *drive)
-{
- drive->dev_flags &= ~IDE_DFLAG_USING_DMA;
-
- drive->hwif->dma_ops->dma_host_set(drive, 0);
-}
-EXPORT_SYMBOL(ide_dma_off_quietly);
-
-/**
- * ide_dma_off - disable DMA on a device
- * @drive: drive to disable DMA on
- *
- * Disable IDE DMA for a device on this IDE controller.
- * Inform the user that DMA has been disabled.
- */
-
-void ide_dma_off(ide_drive_t *drive)
-{
- printk(KERN_INFO "%s: DMA disabled\n", drive->name);
- ide_dma_off_quietly(drive);
-}
-EXPORT_SYMBOL(ide_dma_off);
-
-/**
- * ide_dma_on - Enable DMA on a device
- * @drive: drive to enable DMA on
- *
- * Enable IDE DMA for a device on this IDE controller.
- */
-
-void ide_dma_on(ide_drive_t *drive)
-{
- drive->dev_flags |= IDE_DFLAG_USING_DMA;
-
- drive->hwif->dma_ops->dma_host_set(drive, 1);
-}
-
-int __ide_dma_bad_drive(ide_drive_t *drive)
-{
- u16 *id = drive->id;
-
- int blacklist = ide_in_drive_list(id, drive_blacklist);
- if (blacklist) {
- printk(KERN_WARNING "%s: Disabling (U)DMA for %s (blacklisted)\n",
- drive->name, (char *)&id[ATA_ID_PROD]);
- return blacklist;
- }
- return 0;
-}
-EXPORT_SYMBOL(__ide_dma_bad_drive);
-
-static const u8 xfer_mode_bases[] = {
- XFER_UDMA_0,
- XFER_MW_DMA_0,
- XFER_SW_DMA_0,
-};
-
-static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
-{
- u16 *id = drive->id;
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_port_ops *port_ops = hwif->port_ops;
- unsigned int mask = 0;
-
- switch (base) {
- case XFER_UDMA_0:
- if ((id[ATA_ID_FIELD_VALID] & 4) == 0)
- break;
- mask = id[ATA_ID_UDMA_MODES];
- if (port_ops && port_ops->udma_filter)
- mask &= port_ops->udma_filter(drive);
- else
- mask &= hwif->ultra_mask;
-
- /*
- * avoid false cable warning from eighty_ninty_three()
- */
- if (req_mode > XFER_UDMA_2) {
- if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
- mask &= 0x07;
- }
- break;
- case XFER_MW_DMA_0:
- mask = id[ATA_ID_MWDMA_MODES];
-
- /* Also look for the CF specific MWDMA modes... */
- if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 0x38)) {
- u8 mode = ((id[ATA_ID_CFA_MODES] & 0x38) >> 3) - 1;
-
- mask |= ((2 << mode) - 1) << 3;
- }
-
- if (port_ops && port_ops->mdma_filter)
- mask &= port_ops->mdma_filter(drive);
- else
- mask &= hwif->mwdma_mask;
- break;
- case XFER_SW_DMA_0:
- mask = id[ATA_ID_SWDMA_MODES];
- if (!(mask & ATA_SWDMA2) && (id[ATA_ID_OLD_DMA_MODES] >> 8)) {
- u8 mode = id[ATA_ID_OLD_DMA_MODES] >> 8;
-
- /*
- * if the mode is valid convert it to the mask
- * (the maximum allowed mode is XFER_SW_DMA_2)
- */
- if (mode <= 2)
- mask = (2 << mode) - 1;
- }
- mask &= hwif->swdma_mask;
- break;
- default:
- BUG();
- break;
- }
-
- return mask;
-}
-
-/**
- * ide_find_dma_mode - compute DMA speed
- * @drive: IDE device
- * @req_mode: requested mode
- *
- * Checks the drive/host capabilities and finds the speed to use for
- * the DMA transfer. The speed is then limited by the requested mode.
- *
- * Returns 0 if the drive/host combination is incapable of DMA transfers
- * or if the requested mode is not a DMA mode.
- */
-
-u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
-{
- ide_hwif_t *hwif = drive->hwif;
- unsigned int mask;
- int x, i;
- u8 mode = 0;
-
- if (drive->media != ide_disk) {
- if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
- return 0;
- }
-
- for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) {
- if (req_mode < xfer_mode_bases[i])
- continue;
- mask = ide_get_mode_mask(drive, xfer_mode_bases[i], req_mode);
- x = fls(mask) - 1;
- if (x >= 0) {
- mode = xfer_mode_bases[i] + x;
- break;
- }
- }
-
- if (hwif->chipset == ide_acorn && mode == 0) {
- /*
- * is this correct?
- */
- if (ide_dma_good_drive(drive) &&
- drive->id[ATA_ID_EIDE_DMA_TIME] < 150)
- mode = XFER_MW_DMA_1;
- }
-
- mode = min(mode, req_mode);
-
- printk(KERN_INFO "%s: %s mode selected\n", drive->name,
- mode ? ide_xfer_verbose(mode) : "no DMA");
-
- return mode;
-}
-
-static int ide_tune_dma(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 speed;
-
- if (ata_id_has_dma(drive->id) == 0 ||
- (drive->dev_flags & IDE_DFLAG_NODMA))
- return 0;
-
- /* consult the list of known "bad" drives */
- if (__ide_dma_bad_drive(drive))
- return 0;
-
- if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
- return config_drive_for_dma(drive);
-
- speed = ide_max_dma_mode(drive);
-
- if (!speed)
- return 0;
-
- if (ide_set_dma_mode(drive, speed))
- return 0;
-
- return 1;
-}
-
-static int ide_dma_check(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
-
- if (ide_tune_dma(drive))
- return 0;
-
- /* TODO: always do PIO fallback */
- if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
- return -1;
-
- ide_set_max_pio(drive);
-
- return -1;
-}
-
-int ide_set_dma(ide_drive_t *drive)
-{
- int rc;
-
- /*
- * Force DMAing for the beginning of the check.
- * Some chipsets appear to do interesting
- * things, if not checked and cleared.
- * PARANOIA!!!
- */
- ide_dma_off_quietly(drive);
-
- rc = ide_dma_check(drive);
- if (rc)
- return rc;
-
- ide_dma_on(drive);
-
- return 0;
-}
-
-void ide_check_dma_crc(ide_drive_t *drive)
-{
- u8 mode;
-
- ide_dma_off_quietly(drive);
- drive->crc_count = 0;
- mode = drive->current_speed;
- /*
- * Don't try non Ultra-DMA modes without iCRC's. Force the
- * device to PIO and make the user enable SWDMA/MWDMA modes.
- */
- if (mode > XFER_UDMA_0 && mode <= XFER_UDMA_7)
- mode--;
- else
- mode = XFER_PIO_4;
- ide_set_xfer_rate(drive, mode);
- if (drive->current_speed >= XFER_SW_DMA_0)
- ide_dma_on(drive);
-}
-
-void ide_dma_lost_irq(ide_drive_t *drive)
-{
- printk(KERN_ERR "%s: DMA interrupt recovery\n", drive->name);
-}
-EXPORT_SYMBOL_GPL(ide_dma_lost_irq);
-
-/*
- * un-busy the port etc, and clear any pending DMA status. we want to
- * retry the current request in pio mode instead of risking tossing it
- * all away
- */
-ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
-{
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_dma_ops *dma_ops = hwif->dma_ops;
- struct ide_cmd *cmd = &hwif->cmd;
- ide_startstop_t ret = ide_stopped;
-
- /*
- * end current dma transaction
- */
-
- if (error < 0) {
- printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
- drive->waiting_for_dma = 0;
- (void)dma_ops->dma_end(drive);
- ide_dma_unmap_sg(drive, cmd);
- ret = ide_error(drive, "dma timeout error",
- hwif->tp_ops->read_status(hwif));
- } else {
- printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
- if (dma_ops->dma_clear)
- dma_ops->dma_clear(drive);
- printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
- if (dma_ops->dma_test_irq(drive) == 0) {
- ide_dump_status(drive, "DMA timeout",
- hwif->tp_ops->read_status(hwif));
- drive->waiting_for_dma = 0;
- (void)dma_ops->dma_end(drive);
- ide_dma_unmap_sg(drive, cmd);
- }
- }
-
- /*
- * disable dma for now, but remember that we did so because of
- * a timeout -- we'll reenable after we finish this next request
- * (or rather the first chunk of it) in pio.
- */
- drive->dev_flags |= IDE_DFLAG_DMA_PIO_RETRY;
- drive->retry_pio++;
- ide_dma_off_quietly(drive);
-
- /*
- * make sure request is sane
- */
- if (hwif->rq)
- scsi_req(hwif->rq)->result = 0;
- return ret;
-}
-
-void ide_release_dma_engine(ide_hwif_t *hwif)
-{
- if (hwif->dmatable_cpu) {
- int prd_size = hwif->prd_max_nents * hwif->prd_ent_size;
-
- dma_free_coherent(hwif->dev, prd_size,
- hwif->dmatable_cpu, hwif->dmatable_dma);
- hwif->dmatable_cpu = NULL;
- }
-}
-EXPORT_SYMBOL_GPL(ide_release_dma_engine);
-
-int ide_allocate_dma_engine(ide_hwif_t *hwif)
-{
- int prd_size;
-
- if (hwif->prd_max_nents == 0)
- hwif->prd_max_nents = PRD_ENTRIES;
- if (hwif->prd_ent_size == 0)
- hwif->prd_ent_size = PRD_BYTES;
-
- prd_size = hwif->prd_max_nents * hwif->prd_ent_size;
-
- hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev, prd_size,
- &hwif->dmatable_dma,
- GFP_ATOMIC);
- if (hwif->dmatable_cpu == NULL) {
- printk(KERN_ERR "%s: unable to allocate PRD table\n",
- hwif->name);
- return -ENOMEM;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ide_allocate_dma_engine);
-
-int ide_dma_prepare(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- const struct ide_dma_ops *dma_ops = drive->hwif->dma_ops;
-
- if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 ||
- (dma_ops->dma_check && dma_ops->dma_check(drive, cmd)))
- goto out;
- ide_map_sg(drive, cmd);
- if (ide_dma_map_sg(drive, cmd) == 0)
- goto out_map;
- if (dma_ops->dma_setup(drive, cmd))
- goto out_dma_unmap;
- drive->waiting_for_dma = 1;
- return 0;
-out_dma_unmap:
- ide_dma_unmap_sg(drive, cmd);
-out_map:
- ide_map_sg(drive, cmd);
-out:
- return 1;
-}
diff --git a/drivers/ide/ide-eh.c b/drivers/ide/ide-eh.c
deleted file mode 100644
index 2f378213e9b5..000000000000
--- a/drivers/ide/ide-eh.c
+++ /dev/null
@@ -1,443 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-
-static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq,
- u8 stat, u8 err)
-{
- ide_hwif_t *hwif = drive->hwif;
-
- if ((stat & ATA_BUSY) ||
- ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
- /* other bits are useless when BUSY */
- scsi_req(rq)->result |= ERROR_RESET;
- } else if (stat & ATA_ERR) {
- /* err has different meaning on cdrom and tape */
- if (err == ATA_ABORTED) {
- if ((drive->dev_flags & IDE_DFLAG_LBA) &&
- /* some newer drives don't support ATA_CMD_INIT_DEV_PARAMS */
- hwif->tp_ops->read_status(hwif) == ATA_CMD_INIT_DEV_PARAMS)
- return ide_stopped;
- } else if ((err & BAD_CRC) == BAD_CRC) {
- /* UDMA crc error, just retry the operation */
- drive->crc_count++;
- } else if (err & (ATA_BBK | ATA_UNC)) {
- /* retries won't help these */
- scsi_req(rq)->result = ERROR_MAX;
- } else if (err & ATA_TRK0NF) {
- /* help it find track zero */
- scsi_req(rq)->result |= ERROR_RECAL;
- }
- }
-
- if ((stat & ATA_DRQ) && rq_data_dir(rq) == READ &&
- (hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0) {
- int nsect = drive->mult_count ? drive->mult_count : 1;
-
- ide_pad_transfer(drive, READ, nsect * SECTOR_SIZE);
- }
-
- if (scsi_req(rq)->result >= ERROR_MAX || blk_noretry_request(rq)) {
- ide_kill_rq(drive, rq);
- return ide_stopped;
- }
-
- if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
- scsi_req(rq)->result |= ERROR_RESET;
-
- if ((scsi_req(rq)->result & ERROR_RESET) == ERROR_RESET) {
- ++scsi_req(rq)->result;
- return ide_do_reset(drive);
- }
-
- if ((scsi_req(rq)->result & ERROR_RECAL) == ERROR_RECAL)
- drive->special_flags |= IDE_SFLAG_RECALIBRATE;
-
- ++scsi_req(rq)->result;
-
- return ide_stopped;
-}
-
-static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq,
- u8 stat, u8 err)
-{
- ide_hwif_t *hwif = drive->hwif;
-
- if ((stat & ATA_BUSY) ||
- ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
- /* other bits are useless when BUSY */
- scsi_req(rq)->result |= ERROR_RESET;
- } else {
- /* add decoding error stuff */
- }
-
- if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
- /* force an abort */
- hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE);
-
- if (scsi_req(rq)->result >= ERROR_MAX) {
- ide_kill_rq(drive, rq);
- } else {
- if ((scsi_req(rq)->result & ERROR_RESET) == ERROR_RESET) {
- ++scsi_req(rq)->result;
- return ide_do_reset(drive);
- }
- ++scsi_req(rq)->result;
- }
-
- return ide_stopped;
-}
-
-static ide_startstop_t __ide_error(ide_drive_t *drive, struct request *rq,
- u8 stat, u8 err)
-{
- if (drive->media == ide_disk)
- return ide_ata_error(drive, rq, stat, err);
- return ide_atapi_error(drive, rq, stat, err);
-}
-
-/**
- * ide_error - handle an error on the IDE
- * @drive: drive the error occurred on
- * @msg: message to report
- * @stat: status bits
- *
- * ide_error() takes action based on the error returned by the drive.
- * For normal I/O that may well include retries. We deal with
- * both new-style (taskfile) and old style command handling here.
- * In the case of taskfile command handling there is work left to
- * do
- */
-
-ide_startstop_t ide_error(ide_drive_t *drive, const char *msg, u8 stat)
-{
- struct request *rq;
- u8 err;
-
- err = ide_dump_status(drive, msg, stat);
-
- rq = drive->hwif->rq;
- if (rq == NULL)
- return ide_stopped;
-
- /* retry only "normal" I/O: */
- if (blk_rq_is_passthrough(rq)) {
- if (ata_taskfile_request(rq)) {
- struct ide_cmd *cmd = ide_req(rq)->special;
-
- if (cmd)
- ide_complete_cmd(drive, cmd, stat, err);
- } else if (ata_pm_request(rq)) {
- scsi_req(rq)->result = 1;
- ide_complete_pm_rq(drive, rq);
- return ide_stopped;
- }
- scsi_req(rq)->result = err;
- ide_complete_rq(drive, err ? BLK_STS_IOERR : BLK_STS_OK, blk_rq_bytes(rq));
- return ide_stopped;
- }
-
- return __ide_error(drive, rq, stat, err);
-}
-EXPORT_SYMBOL_GPL(ide_error);
-
-static inline void ide_complete_drive_reset(ide_drive_t *drive, blk_status_t err)
-{
- struct request *rq = drive->hwif->rq;
-
- if (rq && ata_misc_request(rq) &&
- scsi_req(rq)->cmd[0] == REQ_DRIVE_RESET) {
- if (err <= 0 && scsi_req(rq)->result == 0)
- scsi_req(rq)->result = -EIO;
- ide_complete_rq(drive, err, blk_rq_bytes(rq));
- }
-}
-
-/* needed below */
-static ide_startstop_t do_reset1(ide_drive_t *, int);
-
-/*
- * atapi_reset_pollfunc() gets invoked to poll the interface for completion
- * every 50ms during an atapi drive reset operation. If the drive has not yet
- * responded, and we have not yet hit our maximum waiting time, then the timer
- * is restarted for another 50ms.
- */
-static ide_startstop_t atapi_reset_pollfunc(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_tp_ops *tp_ops = hwif->tp_ops;
- u8 stat;
-
- tp_ops->dev_select(drive);
- udelay(10);
- stat = tp_ops->read_status(hwif);
-
- if (OK_STAT(stat, 0, ATA_BUSY))
- printk(KERN_INFO "%s: ATAPI reset complete\n", drive->name);
- else {
- if (time_before(jiffies, hwif->poll_timeout)) {
- ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20);
- /* continue polling */
- return ide_started;
- }
- /* end of polling */
- hwif->polling = 0;
- printk(KERN_ERR "%s: ATAPI reset timed-out, status=0x%02x\n",
- drive->name, stat);
- /* do it the old fashioned way */
- return do_reset1(drive, 1);
- }
- /* done polling */
- hwif->polling = 0;
- ide_complete_drive_reset(drive, BLK_STS_OK);
- return ide_stopped;
-}
-
-static void ide_reset_report_error(ide_hwif_t *hwif, u8 err)
-{
- static const char *err_master_vals[] =
- { NULL, "passed", "formatter device error",
- "sector buffer error", "ECC circuitry error",
- "controlling MPU error" };
-
- u8 err_master = err & 0x7f;
-
- printk(KERN_ERR "%s: reset: master: ", hwif->name);
- if (err_master && err_master < 6)
- printk(KERN_CONT "%s", err_master_vals[err_master]);
- else
- printk(KERN_CONT "error (0x%02x?)", err);
- if (err & 0x80)
- printk(KERN_CONT "; slave: failed");
- printk(KERN_CONT "\n");
-}
-
-/*
- * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an ide reset operation. If the drives have not yet responded,
- * and we have not yet hit our maximum waiting time, then the timer is restarted
- * for another 50ms.
- */
-static ide_startstop_t reset_pollfunc(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_port_ops *port_ops = hwif->port_ops;
- u8 tmp;
- blk_status_t err = BLK_STS_OK;
-
- if (port_ops && port_ops->reset_poll) {
- err = port_ops->reset_poll(drive);
- if (err) {
- printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
- hwif->name, drive->name);
- goto out;
- }
- }
-
- tmp = hwif->tp_ops->read_status(hwif);
-
- if (!OK_STAT(tmp, 0, ATA_BUSY)) {
- if (time_before(jiffies, hwif->poll_timeout)) {
- ide_set_handler(drive, &reset_pollfunc, HZ/20);
- /* continue polling */
- return ide_started;
- }
- printk(KERN_ERR "%s: reset timed-out, status=0x%02x\n",
- hwif->name, tmp);
- drive->failures++;
- err = BLK_STS_IOERR;
- } else {
- tmp = ide_read_error(drive);
-
- if (tmp == 1) {
- printk(KERN_INFO "%s: reset: success\n", hwif->name);
- drive->failures = 0;
- } else {
- ide_reset_report_error(hwif, tmp);
- drive->failures++;
- err = BLK_STS_IOERR;
- }
- }
-out:
- hwif->polling = 0; /* done polling */
- ide_complete_drive_reset(drive, err);
- return ide_stopped;
-}
-
-static void ide_disk_pre_reset(ide_drive_t *drive)
-{
- int legacy = (drive->id[ATA_ID_CFS_ENABLE_2] & 0x0400) ? 0 : 1;
-
- drive->special_flags =
- legacy ? (IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE) : 0;
-
- drive->mult_count = 0;
- drive->dev_flags &= ~IDE_DFLAG_PARKED;
-
- if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0 &&
- (drive->dev_flags & IDE_DFLAG_USING_DMA) == 0)
- drive->mult_req = 0;
-
- if (drive->mult_req != drive->mult_count)
- drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
-}
-
-static void pre_reset(ide_drive_t *drive)
-{
- const struct ide_port_ops *port_ops = drive->hwif->port_ops;
-
- if (drive->media == ide_disk)
- ide_disk_pre_reset(drive);
- else
- drive->dev_flags |= IDE_DFLAG_POST_RESET;
-
- if (drive->dev_flags & IDE_DFLAG_USING_DMA) {
- if (drive->crc_count)
- ide_check_dma_crc(drive);
- else
- ide_dma_off(drive);
- }
-
- if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0) {
- if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) {
- drive->dev_flags &= ~IDE_DFLAG_UNMASK;
- drive->io_32bit = 0;
- }
- return;
- }
-
- if (port_ops && port_ops->pre_reset)
- port_ops->pre_reset(drive);
-
- if (drive->current_speed != 0xff)
- drive->desired_speed = drive->current_speed;
- drive->current_speed = 0xff;
-}
-
-/*
- * do_reset1() attempts to recover a confused drive by resetting it.
- * Unfortunately, resetting a disk drive actually resets all devices on
- * the same interface, so it can really be thought of as resetting the
- * interface rather than resetting the drive.
- *
- * ATAPI devices have their own reset mechanism which allows them to be
- * individually reset without clobbering other devices on the same interface.
- *
- * Unfortunately, the IDE interface does not generate an interrupt to let
- * us know when the reset operation has finished, so we must poll for this.
- * Equally poor, though, is the fact that this may a very long time to complete,
- * (up to 30 seconds worstcase). So, instead of busy-waiting here for it,
- * we set a timer to poll at 50ms intervals.
- */
-static ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct ide_io_ports *io_ports = &hwif->io_ports;
- const struct ide_tp_ops *tp_ops = hwif->tp_ops;
- const struct ide_port_ops *port_ops;
- ide_drive_t *tdrive;
- unsigned long flags, timeout;
- int i;
- DEFINE_WAIT(wait);
-
- spin_lock_irqsave(&hwif->lock, flags);
-
- /* We must not reset with running handlers */
- BUG_ON(hwif->handler != NULL);
-
- /* For an ATAPI device, first try an ATAPI SRST. */
- if (drive->media != ide_disk && !do_not_try_atapi) {
- pre_reset(drive);
- tp_ops->dev_select(drive);
- udelay(20);
- tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
- ndelay(400);
- hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
- hwif->polling = 1;
- __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20);
- spin_unlock_irqrestore(&hwif->lock, flags);
- return ide_started;
- }
-
- /* We must not disturb devices in the IDE_DFLAG_PARKED state. */
- do {
- unsigned long now;
-
- prepare_to_wait(&ide_park_wq, &wait, TASK_UNINTERRUPTIBLE);
- timeout = jiffies;
- ide_port_for_each_present_dev(i, tdrive, hwif) {
- if ((tdrive->dev_flags & IDE_DFLAG_PARKED) &&
- time_after(tdrive->sleep, timeout))
- timeout = tdrive->sleep;
- }
-
- now = jiffies;
- if (time_before_eq(timeout, now))
- break;
-
- spin_unlock_irqrestore(&hwif->lock, flags);
- timeout = schedule_timeout_uninterruptible(timeout - now);
- spin_lock_irqsave(&hwif->lock, flags);
- } while (timeout);
- finish_wait(&ide_park_wq, &wait);
-
- /*
- * First, reset any device state data we were maintaining
- * for any of the drives on this interface.
- */
- ide_port_for_each_dev(i, tdrive, hwif)
- pre_reset(tdrive);
-
- if (io_ports->ctl_addr == 0) {
- spin_unlock_irqrestore(&hwif->lock, flags);
- ide_complete_drive_reset(drive, BLK_STS_IOERR);
- return ide_stopped;
- }
-
- /*
- * Note that we also set nIEN while resetting the device,
- * to mask unwanted interrupts from the interface during the reset.
- * However, due to the design of PC hardware, this will cause an
- * immediate interrupt due to the edge transition it produces.
- * This single interrupt gives us a "fast poll" for drives that
- * recover from reset very quickly, saving us the first 50ms wait time.
- */
- /* set SRST and nIEN */
- tp_ops->write_devctl(hwif, ATA_SRST | ATA_NIEN | ATA_DEVCTL_OBS);
- /* more than enough time */
- udelay(10);
- /* clear SRST, leave nIEN (unless device is on the quirk list) */
- tp_ops->write_devctl(hwif,
- ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) ? 0 : ATA_NIEN) |
- ATA_DEVCTL_OBS);
- /* more than enough time */
- udelay(10);
- hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
- hwif->polling = 1;
- __ide_set_handler(drive, &reset_pollfunc, HZ/20);
-
- /*
- * Some weird controller like resetting themselves to a strange
- * state when the disks are reset this way. At least, the Winbond
- * 553 documentation says that
- */
- port_ops = hwif->port_ops;
- if (port_ops && port_ops->resetproc)
- port_ops->resetproc(drive);
-
- spin_unlock_irqrestore(&hwif->lock, flags);
- return ide_started;
-}
-
-/*
- * ide_do_reset() is the entry point to the drive/interface reset code.
- */
-
-ide_startstop_t ide_do_reset(ide_drive_t *drive)
-{
- return do_reset1(drive, 0);
-}
-EXPORT_SYMBOL(ide_do_reset);
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
deleted file mode 100644
index f5a2870aaf54..000000000000
--- a/drivers/ide/ide-floppy.c
+++ /dev/null
@@ -1,551 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * IDE ATAPI floppy driver.
- *
- * Copyright (C) 1996-1999 Gadi Oxman <gadio@netvision.net.il>
- * Copyright (C) 2000-2002 Paul Bristow <paul@paulbristow.net>
- * Copyright (C) 2005 Bartlomiej Zolnierkiewicz
- *
- * This driver supports the following IDE floppy drives:
- *
- * LS-120/240 SuperDisk
- * Iomega Zip 100/250
- * Iomega PC Card Clik!/PocketZip
- *
- * For a historical changelog see
- * Documentation/ide/ChangeLog.ide-floppy.1996-2002
- */
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/compat.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/cdrom.h>
-#include <linux/ide.h>
-#include <linux/hdreg.h>
-#include <linux/bitops.h>
-#include <linux/mutex.h>
-#include <linux/scatterlist.h>
-
-#include <scsi/scsi_ioctl.h>
-
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <asm/unaligned.h>
-
-#include "ide-floppy.h"
-
-/*
- * After each failed packet command we issue a request sense command and retry
- * the packet command IDEFLOPPY_MAX_PC_RETRIES times.
- */
-#define IDEFLOPPY_MAX_PC_RETRIES 3
-
-/* format capacities descriptor codes */
-#define CAPACITY_INVALID 0x00
-#define CAPACITY_UNFORMATTED 0x01
-#define CAPACITY_CURRENT 0x02
-#define CAPACITY_NO_CARTRIDGE 0x03
-
-/*
- * The following delay solves a problem with ATAPI Zip 100 drive where BSY bit
- * was apparently being deasserted before the unit was ready to receive data.
- */
-#define IDEFLOPPY_PC_DELAY (HZ/20) /* default delay for ZIP 100 (50ms) */
-
-static int ide_floppy_callback(ide_drive_t *drive, int dsc)
-{
- struct ide_disk_obj *floppy = drive->driver_data;
- struct ide_atapi_pc *pc = drive->pc;
- struct request *rq = pc->rq;
- int uptodate = pc->error ? 0 : 1;
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- if (drive->failed_pc == pc)
- drive->failed_pc = NULL;
-
- if (pc->c[0] == GPCMD_READ_10 || pc->c[0] == GPCMD_WRITE_10 ||
- blk_rq_is_scsi(rq))
- uptodate = 1; /* FIXME */
- else if (pc->c[0] == GPCMD_REQUEST_SENSE) {
-
- u8 *buf = bio_data(rq->bio);
-
- if (!pc->error) {
- floppy->sense_key = buf[2] & 0x0F;
- floppy->asc = buf[12];
- floppy->ascq = buf[13];
- floppy->progress_indication = buf[15] & 0x80 ?
- (u16)get_unaligned((u16 *)&buf[16]) : 0x10000;
-
- if (drive->failed_pc)
- ide_debug_log(IDE_DBG_PC, "pc = %x",
- drive->failed_pc->c[0]);
-
- ide_debug_log(IDE_DBG_SENSE, "sense key = %x, asc = %x,"
- "ascq = %x", floppy->sense_key,
- floppy->asc, floppy->ascq);
- } else
- printk(KERN_ERR PFX "Error in REQUEST SENSE itself - "
- "Aborting request!\n");
- }
-
- if (ata_misc_request(rq))
- scsi_req(rq)->result = uptodate ? 0 : IDE_DRV_ERROR_GENERAL;
-
- return uptodate;
-}
-
-static void ide_floppy_report_error(struct ide_disk_obj *floppy,
- struct ide_atapi_pc *pc)
-{
- /* suppress error messages resulting from Medium not present */
- if (floppy->sense_key == 0x02 &&
- floppy->asc == 0x3a &&
- floppy->ascq == 0x00)
- return;
-
- printk(KERN_ERR PFX "%s: I/O error, pc = %2x, key = %2x, "
- "asc = %2x, ascq = %2x\n",
- floppy->drive->name, pc->c[0], floppy->sense_key,
- floppy->asc, floppy->ascq);
-
-}
-
-static ide_startstop_t ide_floppy_issue_pc(ide_drive_t *drive,
- struct ide_cmd *cmd,
- struct ide_atapi_pc *pc)
-{
- struct ide_disk_obj *floppy = drive->driver_data;
-
- if (drive->failed_pc == NULL &&
- pc->c[0] != GPCMD_REQUEST_SENSE)
- drive->failed_pc = pc;
-
- /* Set the current packet command */
- drive->pc = pc;
-
- if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) {
- unsigned int done = blk_rq_bytes(drive->hwif->rq);
-
- if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR))
- ide_floppy_report_error(floppy, pc);
-
- /* Giving up */
- pc->error = IDE_DRV_ERROR_GENERAL;
-
- drive->failed_pc = NULL;
- drive->pc_callback(drive, 0);
- ide_complete_rq(drive, BLK_STS_IOERR, done);
- return ide_stopped;
- }
-
- ide_debug_log(IDE_DBG_FUNC, "retry #%d", pc->retries);
-
- pc->retries++;
-
- return ide_issue_pc(drive, cmd);
-}
-
-void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *pc)
-{
- ide_init_pc(pc);
- pc->c[0] = GPCMD_READ_FORMAT_CAPACITIES;
- pc->c[7] = 255;
- pc->c[8] = 255;
- pc->req_xfer = 255;
-}
-
-/* A mode sense command is used to "sense" floppy parameters. */
-void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code)
-{
- u16 length = 8; /* sizeof(Mode Parameter Header) = 8 Bytes */
-
- ide_init_pc(pc);
- pc->c[0] = GPCMD_MODE_SENSE_10;
- pc->c[1] = 0;
- pc->c[2] = page_code;
-
- switch (page_code) {
- case IDEFLOPPY_CAPABILITIES_PAGE:
- length += 12;
- break;
- case IDEFLOPPY_FLEXIBLE_DISK_PAGE:
- length += 32;
- break;
- default:
- printk(KERN_ERR PFX "unsupported page code in %s\n", __func__);
- }
- put_unaligned(cpu_to_be16(length), (u16 *) &pc->c[7]);
- pc->req_xfer = length;
-}
-
-static void idefloppy_create_rw_cmd(ide_drive_t *drive,
- struct ide_atapi_pc *pc, struct request *rq,
- unsigned long sector)
-{
- struct ide_disk_obj *floppy = drive->driver_data;
- int block = sector / floppy->bs_factor;
- int blocks = blk_rq_sectors(rq) / floppy->bs_factor;
- int cmd = rq_data_dir(rq);
-
- ide_debug_log(IDE_DBG_FUNC, "block: %d, blocks: %d", block, blocks);
-
- ide_init_pc(pc);
- pc->c[0] = cmd == READ ? GPCMD_READ_10 : GPCMD_WRITE_10;
- put_unaligned(cpu_to_be16(blocks), (unsigned short *)&pc->c[7]);
- put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[2]);
-
- memcpy(scsi_req(rq)->cmd, pc->c, 12);
-
- pc->rq = rq;
- if (cmd == WRITE)
- pc->flags |= PC_FLAG_WRITING;
-
- pc->flags |= PC_FLAG_DMA_OK;
-}
-
-static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy,
- struct ide_atapi_pc *pc, struct request *rq)
-{
- ide_init_pc(pc);
- memcpy(pc->c, scsi_req(rq)->cmd, sizeof(pc->c));
- pc->rq = rq;
- if (blk_rq_bytes(rq)) {
- pc->flags |= PC_FLAG_DMA_OK;
- if (rq_data_dir(rq) == WRITE)
- pc->flags |= PC_FLAG_WRITING;
- }
-}
-
-static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
- struct request *rq, sector_t block)
-{
- struct ide_disk_obj *floppy = drive->driver_data;
- struct ide_cmd cmd;
- struct ide_atapi_pc *pc;
-
- ide_debug_log(IDE_DBG_FUNC, "enter, cmd: 0x%x\n", rq->cmd[0]);
-
- if (drive->debug_mask & IDE_DBG_RQ)
- blk_dump_rq_flags(rq, (rq->rq_disk
- ? rq->rq_disk->disk_name
- : "dev?"));
-
- if (scsi_req(rq)->result >= ERROR_MAX) {
- if (drive->failed_pc) {
- ide_floppy_report_error(floppy, drive->failed_pc);
- drive->failed_pc = NULL;
- } else
- printk(KERN_ERR PFX "%s: I/O error\n", drive->name);
-
- if (ata_misc_request(rq)) {
- scsi_req(rq)->result = 0;
- ide_complete_rq(drive, BLK_STS_OK, blk_rq_bytes(rq));
- return ide_stopped;
- } else
- goto out_end;
- }
-
- switch (req_op(rq)) {
- default:
- if (((long)blk_rq_pos(rq) % floppy->bs_factor) ||
- (blk_rq_sectors(rq) % floppy->bs_factor)) {
- printk(KERN_ERR PFX "%s: unsupported r/w rq size\n",
- drive->name);
- goto out_end;
- }
- pc = &floppy->queued_pc;
- idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block);
- break;
- case REQ_OP_SCSI_IN:
- case REQ_OP_SCSI_OUT:
- pc = &floppy->queued_pc;
- idefloppy_blockpc_cmd(floppy, pc, rq);
- break;
- case REQ_OP_DRV_IN:
- case REQ_OP_DRV_OUT:
- switch (ide_req(rq)->type) {
- case ATA_PRIV_MISC:
- case ATA_PRIV_SENSE:
- pc = (struct ide_atapi_pc *)ide_req(rq)->special;
- break;
- default:
- BUG();
- }
- }
-
- ide_prep_sense(drive, rq);
-
- memset(&cmd, 0, sizeof(cmd));
-
- if (rq_data_dir(rq))
- cmd.tf_flags |= IDE_TFLAG_WRITE;
-
- cmd.rq = rq;
-
- if (!blk_rq_is_passthrough(rq) || blk_rq_bytes(rq)) {
- ide_init_sg_cmd(&cmd, blk_rq_bytes(rq));
- ide_map_sg(drive, &cmd);
- }
-
- pc->rq = rq;
-
- return ide_floppy_issue_pc(drive, &cmd, pc);
-out_end:
- drive->failed_pc = NULL;
- if (blk_rq_is_passthrough(rq) && scsi_req(rq)->result == 0)
- scsi_req(rq)->result = -EIO;
- ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(rq));
- return ide_stopped;
-}
-
-/*
- * Look at the flexible disk page parameters. We ignore the CHS capacity
- * parameters and use the LBA parameters instead.
- */
-static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive,
- struct ide_atapi_pc *pc)
-{
- struct ide_disk_obj *floppy = drive->driver_data;
- struct gendisk *disk = floppy->disk;
- u8 *page, buf[40];
- int capacity, lba_capacity;
- u16 transfer_rate, sector_size, cyls, rpm;
- u8 heads, sectors;
-
- ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE);
-
- if (ide_queue_pc_tail(drive, disk, pc, buf, pc->req_xfer)) {
- printk(KERN_ERR PFX "Can't get flexible disk page params\n");
- return 1;
- }
-
- if (buf[3] & 0x80)
- drive->dev_flags |= IDE_DFLAG_WP;
- else
- drive->dev_flags &= ~IDE_DFLAG_WP;
-
- set_disk_ro(disk, !!(drive->dev_flags & IDE_DFLAG_WP));
-
- page = &buf[8];
-
- transfer_rate = be16_to_cpup((__be16 *)&buf[8 + 2]);
- sector_size = be16_to_cpup((__be16 *)&buf[8 + 6]);
- cyls = be16_to_cpup((__be16 *)&buf[8 + 8]);
- rpm = be16_to_cpup((__be16 *)&buf[8 + 28]);
- heads = buf[8 + 4];
- sectors = buf[8 + 5];
-
- capacity = cyls * heads * sectors * sector_size;
-
- if (memcmp(page, &floppy->flexible_disk_page, 32))
- printk(KERN_INFO PFX "%s: %dkB, %d/%d/%d CHS, %d kBps, "
- "%d sector size, %d rpm\n",
- drive->name, capacity / 1024, cyls, heads,
- sectors, transfer_rate / 8, sector_size, rpm);
-
- memcpy(&floppy->flexible_disk_page, page, 32);
- drive->bios_cyl = cyls;
- drive->bios_head = heads;
- drive->bios_sect = sectors;
- lba_capacity = floppy->blocks * floppy->block_size;
-
- if (capacity < lba_capacity) {
- printk(KERN_NOTICE PFX "%s: The disk reports a capacity of %d "
- "bytes, but the drive only handles %d\n",
- drive->name, lba_capacity, capacity);
- floppy->blocks = floppy->block_size ?
- capacity / floppy->block_size : 0;
- drive->capacity64 = floppy->blocks * floppy->bs_factor;
- }
-
- return 0;
-}
-
-/*
- * Determine if a media is present in the floppy drive, and if so, its LBA
- * capacity.
- */
-static int ide_floppy_get_capacity(ide_drive_t *drive)
-{
- struct ide_disk_obj *floppy = drive->driver_data;
- struct gendisk *disk = floppy->disk;
- struct ide_atapi_pc pc;
- u8 *cap_desc;
- u8 pc_buf[256], header_len, desc_cnt;
- int i, rc = 1, blocks, length;
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- drive->bios_cyl = 0;
- drive->bios_head = drive->bios_sect = 0;
- floppy->blocks = 0;
- floppy->bs_factor = 1;
- drive->capacity64 = 0;
-
- ide_floppy_create_read_capacity_cmd(&pc);
- if (ide_queue_pc_tail(drive, disk, &pc, pc_buf, pc.req_xfer)) {
- printk(KERN_ERR PFX "Can't get floppy parameters\n");
- return 1;
- }
- header_len = pc_buf[3];
- cap_desc = &pc_buf[4];
- desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
-
- for (i = 0; i < desc_cnt; i++) {
- unsigned int desc_start = 4 + i*8;
-
- blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]);
- length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]);
-
- ide_debug_log(IDE_DBG_PROBE, "Descriptor %d: %dkB, %d blocks, "
- "%d sector size",
- i, blocks * length / 1024,
- blocks, length);
-
- if (i)
- continue;
- /*
- * the code below is valid only for the 1st descriptor, ie i=0
- */
-
- switch (pc_buf[desc_start + 4] & 0x03) {
- /* Clik! drive returns this instead of CAPACITY_CURRENT */
- case CAPACITY_UNFORMATTED:
- if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE))
- /*
- * If it is not a clik drive, break out
- * (maintains previous driver behaviour)
- */
- break;
- fallthrough;
- case CAPACITY_CURRENT:
- /* Normal Zip/LS-120 disks */
- if (memcmp(cap_desc, &floppy->cap_desc, 8))
- printk(KERN_INFO PFX "%s: %dkB, %d blocks, %d "
- "sector size\n",
- drive->name, blocks * length / 1024,
- blocks, length);
- memcpy(&floppy->cap_desc, cap_desc, 8);
-
- if (!length || length % 512) {
- printk(KERN_NOTICE PFX "%s: %d bytes block size"
- " not supported\n", drive->name, length);
- } else {
- floppy->blocks = blocks;
- floppy->block_size = length;
- floppy->bs_factor = length / 512;
- if (floppy->bs_factor != 1)
- printk(KERN_NOTICE PFX "%s: Warning: "
- "non 512 bytes block size not "
- "fully supported\n",
- drive->name);
- drive->capacity64 =
- floppy->blocks * floppy->bs_factor;
- rc = 0;
- }
- break;
- case CAPACITY_NO_CARTRIDGE:
- /*
- * This is a KERN_ERR so it appears on screen
- * for the user to see
- */
- printk(KERN_ERR PFX "%s: No disk in drive\n",
- drive->name);
- break;
- case CAPACITY_INVALID:
- printk(KERN_ERR PFX "%s: Invalid capacity for disk "
- "in drive\n", drive->name);
- break;
- }
- ide_debug_log(IDE_DBG_PROBE, "Descriptor 0 Code: %d",
- pc_buf[desc_start + 4] & 0x03);
- }
-
- /* Clik! disk does not support get_flexible_disk_page */
- if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE))
- (void) ide_floppy_get_flexible_disk_page(drive, &pc);
-
- return rc;
-}
-
-static void ide_floppy_setup(ide_drive_t *drive)
-{
- struct ide_disk_obj *floppy = drive->driver_data;
- u16 *id = drive->id;
-
- drive->pc_callback = ide_floppy_callback;
-
- /*
- * We used to check revisions here. At this point however I'm giving up.
- * Just assume they are all broken, its easier.
- *
- * The actual reason for the workarounds was likely a driver bug after
- * all rather than a firmware bug, and the workaround below used to hide
- * it. It should be fixed as of version 1.9, but to be on the safe side
- * we'll leave the limitation below for the 2.2.x tree.
- */
- if (strstarts((char *)&id[ATA_ID_PROD], "IOMEGA ZIP 100 ATAPI")) {
- drive->atapi_flags |= IDE_AFLAG_ZIP_DRIVE;
- /* This value will be visible in the /proc/ide/hdx/settings */
- drive->pc_delay = IDEFLOPPY_PC_DELAY;
- blk_queue_max_hw_sectors(drive->queue, 64);
- }
-
- /*
- * Guess what? The IOMEGA Clik! drive also needs the above fix. It makes
- * nasty clicking noises without it, so please don't remove this.
- */
- if (strstarts((char *)&id[ATA_ID_PROD], "IOMEGA Clik!")) {
- blk_queue_max_hw_sectors(drive->queue, 64);
- drive->atapi_flags |= IDE_AFLAG_CLIK_DRIVE;
- /* IOMEGA Clik! drives do not support lock/unlock commands */
- drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
- }
-
- (void) ide_floppy_get_capacity(drive);
-
- ide_proc_register_driver(drive, floppy->driver);
-}
-
-static void ide_floppy_flush(ide_drive_t *drive)
-{
-}
-
-static int ide_floppy_init_media(ide_drive_t *drive, struct gendisk *disk)
-{
- int ret = 0;
-
- if (ide_do_test_unit_ready(drive, disk))
- ide_do_start_stop(drive, disk, 1);
-
- ret = ide_floppy_get_capacity(drive);
-
- set_capacity(disk, ide_gd_capacity(drive));
-
- return ret;
-}
-
-const struct ide_disk_ops ide_atapi_disk_ops = {
- .check = ide_check_atapi_device,
- .get_capacity = ide_floppy_get_capacity,
- .setup = ide_floppy_setup,
- .flush = ide_floppy_flush,
- .init_media = ide_floppy_init_media,
- .set_doorlock = ide_set_media_lock,
- .do_request = ide_floppy_do_request,
- .ioctl = ide_floppy_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = ide_floppy_compat_ioctl,
-#endif
-};
diff --git a/drivers/ide/ide-floppy.h b/drivers/ide/ide-floppy.h
deleted file mode 100644
index 8505a5f58f4e..000000000000
--- a/drivers/ide/ide-floppy.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __IDE_FLOPPY_H
-#define __IDE_FLOPPY_H
-
-#include "ide-gd.h"
-
-#ifdef CONFIG_IDE_GD_ATAPI
-/*
- * Pages of the SELECT SENSE / MODE SENSE packet commands.
- * See SFF-8070i spec.
- */
-#define IDEFLOPPY_CAPABILITIES_PAGE 0x1b
-#define IDEFLOPPY_FLEXIBLE_DISK_PAGE 0x05
-
-/* IOCTLs used in low-level formatting. */
-#define IDEFLOPPY_IOCTL_FORMAT_SUPPORTED 0x4600
-#define IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY 0x4601
-#define IDEFLOPPY_IOCTL_FORMAT_START 0x4602
-#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS 0x4603
-
-/* ide-floppy.c */
-extern const struct ide_disk_ops ide_atapi_disk_ops;
-void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *, u8);
-void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *);
-
-/* ide-floppy_ioctl.c */
-int ide_floppy_ioctl(ide_drive_t *, struct block_device *, fmode_t,
- unsigned int, unsigned long);
-int ide_floppy_compat_ioctl(ide_drive_t *, struct block_device *, fmode_t,
- unsigned int, unsigned long);
-
-#ifdef CONFIG_IDE_PROC_FS
-/* ide-floppy_proc.c */
-extern ide_proc_entry_t ide_floppy_proc[];
-extern const struct ide_proc_devset ide_floppy_settings[];
-#endif
-#else
-#define ide_floppy_proc NULL
-#define ide_floppy_settings NULL
-#endif
-
-#endif /*__IDE_FLOPPY_H */
diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c
deleted file mode 100644
index 39a790ac6cc3..000000000000
--- a/drivers/ide/ide-floppy_ioctl.c
+++ /dev/null
@@ -1,339 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ide-floppy IOCTLs handling.
- */
-
-#include <linux/kernel.h>
-#include <linux/ide.h>
-#include <linux/compat.h>
-#include <linux/cdrom.h>
-#include <linux/mutex.h>
-
-#include <asm/unaligned.h>
-
-#include <scsi/scsi_ioctl.h>
-
-#include "ide-floppy.h"
-
-/*
- * Obtain the list of formattable capacities.
- * Very similar to ide_floppy_get_capacity, except that we push the capacity
- * descriptors to userland, instead of our own structures.
- *
- * Userland gives us the following structure:
- *
- * struct idefloppy_format_capacities {
- * int nformats;
- * struct {
- * int nblocks;
- * int blocksize;
- * } formats[];
- * };
- *
- * userland initializes nformats to the number of allocated formats[] records.
- * On exit we set nformats to the number of records we've actually initialized.
- */
-
-static DEFINE_MUTEX(ide_floppy_ioctl_mutex);
-static int ide_floppy_get_format_capacities(ide_drive_t *drive,
- struct ide_atapi_pc *pc,
- int __user *arg)
-{
- struct ide_disk_obj *floppy = drive->driver_data;
- int i, blocks, length, u_array_size, u_index;
- int __user *argp;
- u8 pc_buf[256], header_len, desc_cnt;
-
- if (get_user(u_array_size, arg))
- return -EFAULT;
-
- if (u_array_size <= 0)
- return -EINVAL;
-
- ide_floppy_create_read_capacity_cmd(pc);
-
- if (ide_queue_pc_tail(drive, floppy->disk, pc, pc_buf, pc->req_xfer)) {
- printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
- return -EIO;
- }
-
- header_len = pc_buf[3];
- desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
-
- u_index = 0;
- argp = arg + 1;
-
- /*
- * We always skip the first capacity descriptor. That's the current
- * capacity. We are interested in the remaining descriptors, the
- * formattable capacities.
- */
- for (i = 1; i < desc_cnt; i++) {
- unsigned int desc_start = 4 + i*8;
-
- if (u_index >= u_array_size)
- break; /* User-supplied buffer too small */
-
- blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]);
- length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]);
-
- if (put_user(blocks, argp))
- return -EFAULT;
-
- ++argp;
-
- if (put_user(length, argp))
- return -EFAULT;
-
- ++argp;
-
- ++u_index;
- }
-
- if (put_user(u_index, arg))
- return -EFAULT;
-
- return 0;
-}
-
-static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc,
- u8 *buf, int b, int l,
- int flags)
-{
- ide_init_pc(pc);
- pc->c[0] = GPCMD_FORMAT_UNIT;
- pc->c[1] = 0x17;
-
- memset(buf, 0, 12);
- buf[1] = 0xA2;
- /* Default format list header, u8 1: FOV/DCRT/IMM bits set */
-
- if (flags & 1) /* Verify bit on... */
- buf[1] ^= 0x20; /* ... turn off DCRT bit */
- buf[3] = 8;
-
- put_unaligned(cpu_to_be32(b), (unsigned int *)(&buf[4]));
- put_unaligned(cpu_to_be32(l), (unsigned int *)(&buf[8]));
- pc->req_xfer = 12;
- pc->flags |= PC_FLAG_WRITING;
-}
-
-static int ide_floppy_get_sfrp_bit(ide_drive_t *drive, struct ide_atapi_pc *pc)
-{
- struct ide_disk_obj *floppy = drive->driver_data;
- u8 buf[20];
-
- drive->atapi_flags &= ~IDE_AFLAG_SRFP;
-
- ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_CAPABILITIES_PAGE);
- pc->flags |= PC_FLAG_SUPPRESS_ERROR;
-
- if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer))
- return 1;
-
- if (buf[8 + 2] & 0x40)
- drive->atapi_flags |= IDE_AFLAG_SRFP;
-
- return 0;
-}
-
-static int ide_floppy_format_unit(ide_drive_t *drive, struct ide_atapi_pc *pc,
- int __user *arg)
-{
- struct ide_disk_obj *floppy = drive->driver_data;
- u8 buf[12];
- int blocks, length, flags, err = 0;
-
- if (floppy->openers > 1) {
- /* Don't format if someone is using the disk */
- drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
- return -EBUSY;
- }
-
- drive->dev_flags |= IDE_DFLAG_FORMAT_IN_PROGRESS;
-
- /*
- * Send ATAPI_FORMAT_UNIT to the drive.
- *
- * Userland gives us the following structure:
- *
- * struct idefloppy_format_command {
- * int nblocks;
- * int blocksize;
- * int flags;
- * } ;
- *
- * flags is a bitmask, currently, the only defined flag is:
- *
- * 0x01 - verify media after format.
- */
- if (get_user(blocks, arg) ||
- get_user(length, arg+1) ||
- get_user(flags, arg+2)) {
- err = -EFAULT;
- goto out;
- }
-
- ide_floppy_get_sfrp_bit(drive, pc);
- ide_floppy_create_format_unit_cmd(pc, buf, blocks, length, flags);
-
- if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer))
- err = -EIO;
-
-out:
- if (err)
- drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
- return err;
-}
-
-/*
- * Get ATAPI_FORMAT_UNIT progress indication.
- *
- * Userland gives a pointer to an int. The int is set to a progress
- * indicator 0-65536, with 65536=100%.
- *
- * If the drive does not support format progress indication, we just check
- * the dsc bit, and return either 0 or 65536.
- */
-
-static int ide_floppy_get_format_progress(ide_drive_t *drive,
- struct ide_atapi_pc *pc,
- int __user *arg)
-{
- struct ide_disk_obj *floppy = drive->driver_data;
- u8 sense_buf[18];
- int progress_indication = 0x10000;
-
- if (drive->atapi_flags & IDE_AFLAG_SRFP) {
- ide_create_request_sense_cmd(drive, pc);
- if (ide_queue_pc_tail(drive, floppy->disk, pc, sense_buf,
- pc->req_xfer))
- return -EIO;
-
- if (floppy->sense_key == 2 &&
- floppy->asc == 4 &&
- floppy->ascq == 4)
- progress_indication = floppy->progress_indication;
-
- /* Else assume format_unit has finished, and we're at 0x10000 */
- } else {
- ide_hwif_t *hwif = drive->hwif;
- unsigned long flags;
- u8 stat;
-
- local_irq_save(flags);
- stat = hwif->tp_ops->read_status(hwif);
- local_irq_restore(flags);
-
- progress_indication = ((stat & ATA_DSC) == 0) ? 0 : 0x10000;
- }
-
- if (put_user(progress_indication, arg))
- return -EFAULT;
-
- return 0;
-}
-
-static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc,
- unsigned long arg, unsigned int cmd)
-{
- struct ide_disk_obj *floppy = drive->driver_data;
- struct gendisk *disk = floppy->disk;
- int prevent = (arg && cmd != CDROMEJECT) ? 1 : 0;
-
- if (floppy->openers > 1)
- return -EBUSY;
-
- ide_set_media_lock(drive, disk, prevent);
-
- if (cmd == CDROMEJECT)
- ide_do_start_stop(drive, disk, 2);
-
- return 0;
-}
-
-static int ide_floppy_format_ioctl(ide_drive_t *drive, struct ide_atapi_pc *pc,
- fmode_t mode, unsigned int cmd,
- void __user *argp)
-{
- switch (cmd) {
- case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
- return 0;
- case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
- return ide_floppy_get_format_capacities(drive, pc, argp);
- case IDEFLOPPY_IOCTL_FORMAT_START:
- if (!(mode & FMODE_WRITE))
- return -EPERM;
- return ide_floppy_format_unit(drive, pc, (int __user *)argp);
- case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
- return ide_floppy_get_format_progress(drive, pc, argp);
- default:
- return -ENOTTY;
- }
-}
-
-int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev,
- fmode_t mode, unsigned int cmd, unsigned long arg)
-{
- struct ide_atapi_pc pc;
- void __user *argp = (void __user *)arg;
- int err;
-
- mutex_lock(&ide_floppy_ioctl_mutex);
- if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR) {
- err = ide_floppy_lockdoor(drive, &pc, arg, cmd);
- goto out;
- }
-
- err = ide_floppy_format_ioctl(drive, &pc, mode, cmd, argp);
- if (err != -ENOTTY)
- goto out;
-
- /*
- * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
- * and CDROM_SEND_PACKET (legacy) ioctls
- */
- if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
- err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
-
- if (err == -ENOTTY)
- err = generic_ide_ioctl(drive, bdev, cmd, arg);
-
-out:
- mutex_unlock(&ide_floppy_ioctl_mutex);
- return err;
-}
-
-#ifdef CONFIG_COMPAT
-int ide_floppy_compat_ioctl(ide_drive_t *drive, struct block_device *bdev,
- fmode_t mode, unsigned int cmd, unsigned long arg)
-{
- struct ide_atapi_pc pc;
- void __user *argp = compat_ptr(arg);
- int err;
-
- mutex_lock(&ide_floppy_ioctl_mutex);
- if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR) {
- err = ide_floppy_lockdoor(drive, &pc, arg, cmd);
- goto out;
- }
-
- err = ide_floppy_format_ioctl(drive, &pc, mode, cmd, argp);
- if (err != -ENOTTY)
- goto out;
-
- /*
- * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
- * and CDROM_SEND_PACKET (legacy) ioctls
- */
- if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
- err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
-
- if (err == -ENOTTY)
- err = generic_ide_ioctl(drive, bdev, cmd, arg);
-
-out:
- mutex_unlock(&ide_floppy_ioctl_mutex);
- return err;
-}
-#endif
diff --git a/drivers/ide/ide-floppy_proc.c b/drivers/ide/ide-floppy_proc.c
deleted file mode 100644
index 7f697ddb5fe5..000000000000
--- a/drivers/ide/ide-floppy_proc.c
+++ /dev/null
@@ -1,34 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/ide.h>
-#include <linux/seq_file.h>
-
-#include "ide-floppy.h"
-
-static int idefloppy_capacity_proc_show(struct seq_file *m, void *v)
-{
- ide_drive_t*drive = (ide_drive_t *)m->private;
-
- seq_printf(m, "%llu\n", (long long)ide_gd_capacity(drive));
- return 0;
-}
-
-ide_proc_entry_t ide_floppy_proc[] = {
- { "capacity", S_IFREG|S_IRUGO, idefloppy_capacity_proc_show },
- { "geometry", S_IFREG|S_IRUGO, ide_geometry_proc_show },
- {}
-};
-
-ide_devset_rw_field(bios_cyl, bios_cyl);
-ide_devset_rw_field(bios_head, bios_head);
-ide_devset_rw_field(bios_sect, bios_sect);
-ide_devset_rw_field(ticks, pc_delay);
-
-const struct ide_proc_devset ide_floppy_settings[] = {
- IDE_PROC_DEVSET(bios_cyl, 0, 1023),
- IDE_PROC_DEVSET(bios_head, 0, 255),
- IDE_PROC_DEVSET(bios_sect, 0, 63),
- IDE_PROC_DEVSET(ticks, 0, 255),
- { NULL },
-};
diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c
deleted file mode 100644
index e2b6c82586ce..000000000000
--- a/drivers/ide/ide-gd.c
+++ /dev/null
@@ -1,432 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/mutex.h>
-#include <linux/ide.h>
-#include <linux/hdreg.h>
-#include <linux/dmi.h>
-#include <linux/slab.h>
-
-#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
-#define IDE_DISK_MINORS (1 << PARTN_BITS)
-#else
-#define IDE_DISK_MINORS 0
-#endif
-
-#include "ide-disk.h"
-#include "ide-floppy.h"
-
-#define IDE_GD_VERSION "1.18"
-
-/* module parameters */
-static DEFINE_MUTEX(ide_gd_mutex);
-static unsigned long debug_mask;
-module_param(debug_mask, ulong, 0644);
-
-static DEFINE_MUTEX(ide_disk_ref_mutex);
-
-static void ide_disk_release(struct device *);
-
-static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
-{
- struct ide_disk_obj *idkp = NULL;
-
- mutex_lock(&ide_disk_ref_mutex);
- idkp = ide_drv_g(disk, ide_disk_obj);
- if (idkp) {
- if (ide_device_get(idkp->drive))
- idkp = NULL;
- else
- get_device(&idkp->dev);
- }
- mutex_unlock(&ide_disk_ref_mutex);
- return idkp;
-}
-
-static void ide_disk_put(struct ide_disk_obj *idkp)
-{
- ide_drive_t *drive = idkp->drive;
-
- mutex_lock(&ide_disk_ref_mutex);
- put_device(&idkp->dev);
- ide_device_put(drive);
- mutex_unlock(&ide_disk_ref_mutex);
-}
-
-sector_t ide_gd_capacity(ide_drive_t *drive)
-{
- return drive->capacity64;
-}
-
-static int ide_gd_probe(ide_drive_t *);
-
-static void ide_gd_remove(ide_drive_t *drive)
-{
- struct ide_disk_obj *idkp = drive->driver_data;
- struct gendisk *g = idkp->disk;
-
- ide_proc_unregister_driver(drive, idkp->driver);
- device_del(&idkp->dev);
- del_gendisk(g);
- drive->disk_ops->flush(drive);
-
- mutex_lock(&ide_disk_ref_mutex);
- put_device(&idkp->dev);
- mutex_unlock(&ide_disk_ref_mutex);
-}
-
-static void ide_disk_release(struct device *dev)
-{
- struct ide_disk_obj *idkp = to_ide_drv(dev, ide_disk_obj);
- ide_drive_t *drive = idkp->drive;
- struct gendisk *g = idkp->disk;
-
- drive->disk_ops = NULL;
- drive->driver_data = NULL;
- g->private_data = NULL;
- put_disk(g);
- kfree(idkp);
-}
-
-/*
- * On HPA drives the capacity needs to be
- * reinitialized on resume otherwise the disk
- * can not be used and a hard reset is required
- */
-static void ide_gd_resume(ide_drive_t *drive)
-{
- if (ata_id_hpa_enabled(drive->id))
- (void)drive->disk_ops->get_capacity(drive);
-}
-
-static const struct dmi_system_id ide_coldreboot_table[] = {
- {
- /* Acer TravelMate 66x cuts power during reboot */
- .ident = "Acer TravelMate 660",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
- DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"),
- },
- },
-
- { } /* terminate list */
-};
-
-static void ide_gd_shutdown(ide_drive_t *drive)
-{
-#ifdef CONFIG_ALPHA
- /* On Alpha, halt(8) doesn't actually turn the machine off,
- it puts you into the sort of firmware monitor. Typically,
- it's used to boot another kernel image, so it's not much
- different from reboot(8). Therefore, we don't need to
- spin down the disk in this case, especially since Alpha
- firmware doesn't handle disks in standby mode properly.
- On the other hand, it's reasonably safe to turn the power
- off when the shutdown process reaches the firmware prompt,
- as the firmware initialization takes rather long time -
- at least 10 seconds, which should be sufficient for
- the disk to expire its write cache. */
- if (system_state != SYSTEM_POWER_OFF) {
-#else
- if (system_state == SYSTEM_RESTART &&
- !dmi_check_system(ide_coldreboot_table)) {
-#endif
- drive->disk_ops->flush(drive);
- return;
- }
-
- printk(KERN_INFO "Shutdown: %s\n", drive->name);
-
- drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
-}
-
-#ifdef CONFIG_IDE_PROC_FS
-static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive)
-{
- return (drive->media == ide_disk) ? ide_disk_proc : ide_floppy_proc;
-}
-
-static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive)
-{
- return (drive->media == ide_disk) ? ide_disk_settings
- : ide_floppy_settings;
-}
-#endif
-
-static ide_startstop_t ide_gd_do_request(ide_drive_t *drive,
- struct request *rq, sector_t sector)
-{
- return drive->disk_ops->do_request(drive, rq, sector);
-}
-
-static struct ide_driver ide_gd_driver = {
- .gen_driver = {
- .owner = THIS_MODULE,
- .name = "ide-gd",
- .bus = &ide_bus_type,
- },
- .probe = ide_gd_probe,
- .remove = ide_gd_remove,
- .resume = ide_gd_resume,
- .shutdown = ide_gd_shutdown,
- .version = IDE_GD_VERSION,
- .do_request = ide_gd_do_request,
-#ifdef CONFIG_IDE_PROC_FS
- .proc_entries = ide_disk_proc_entries,
- .proc_devsets = ide_disk_proc_devsets,
-#endif
-};
-
-static int ide_gd_open(struct block_device *bdev, fmode_t mode)
-{
- struct gendisk *disk = bdev->bd_disk;
- struct ide_disk_obj *idkp;
- ide_drive_t *drive;
- int ret = 0;
-
- idkp = ide_disk_get(disk);
- if (idkp == NULL)
- return -ENXIO;
-
- drive = idkp->drive;
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- idkp->openers++;
-
- if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
- drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
- /* Just in case */
-
- ret = drive->disk_ops->init_media(drive, disk);
-
- /*
- * Allow O_NDELAY to open a drive without a disk, or with an
- * unreadable disk, so that we can get the format capacity
- * of the drive or begin the format - Sam
- */
- if (ret && (mode & FMODE_NDELAY) == 0) {
- ret = -EIO;
- goto out_put_idkp;
- }
-
- if ((drive->dev_flags & IDE_DFLAG_WP) && (mode & FMODE_WRITE)) {
- ret = -EROFS;
- goto out_put_idkp;
- }
-
- /*
- * Ignore the return code from door_lock,
- * since the open() has already succeeded,
- * and the door_lock is irrelevant at this point.
- */
- drive->disk_ops->set_doorlock(drive, disk, 1);
- if (__invalidate_device(bdev, true))
- pr_warn("VFS: busy inodes on changed media %s\n",
- bdev->bd_disk->disk_name);
- drive->disk_ops->get_capacity(drive);
- set_capacity(disk, ide_gd_capacity(drive));
- set_bit(GD_NEED_PART_SCAN, &disk->state);
- } else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) {
- ret = -EBUSY;
- goto out_put_idkp;
- }
- return 0;
-
-out_put_idkp:
- idkp->openers--;
- ide_disk_put(idkp);
- return ret;
-}
-
-static int ide_gd_unlocked_open(struct block_device *bdev, fmode_t mode)
-{
- int ret;
-
- mutex_lock(&ide_gd_mutex);
- ret = ide_gd_open(bdev, mode);
- mutex_unlock(&ide_gd_mutex);
-
- return ret;
-}
-
-
-static void ide_gd_release(struct gendisk *disk, fmode_t mode)
-{
- struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
- ide_drive_t *drive = idkp->drive;
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- mutex_lock(&ide_gd_mutex);
- if (idkp->openers == 1)
- drive->disk_ops->flush(drive);
-
- if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
- drive->disk_ops->set_doorlock(drive, disk, 0);
- drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
- }
-
- idkp->openers--;
-
- ide_disk_put(idkp);
- mutex_unlock(&ide_gd_mutex);
-}
-
-static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
- struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
- ide_drive_t *drive = idkp->drive;
-
- geo->heads = drive->bios_head;
- geo->sectors = drive->bios_sect;
- geo->cylinders = (u16)drive->bios_cyl; /* truncate */
- return 0;
-}
-
-static void ide_gd_unlock_native_capacity(struct gendisk *disk)
-{
- struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
- ide_drive_t *drive = idkp->drive;
- const struct ide_disk_ops *disk_ops = drive->disk_ops;
-
- if (disk_ops->unlock_native_capacity)
- disk_ops->unlock_native_capacity(drive);
-}
-
-static int ide_gd_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
- ide_drive_t *drive = idkp->drive;
-
- return drive->disk_ops->ioctl(drive, bdev, mode, cmd, arg);
-}
-
-#ifdef CONFIG_COMPAT
-static int ide_gd_compat_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
- ide_drive_t *drive = idkp->drive;
-
- if (!drive->disk_ops->compat_ioctl)
- return -ENOIOCTLCMD;
-
- return drive->disk_ops->compat_ioctl(drive, bdev, mode, cmd, arg);
-}
-#endif
-
-static const struct block_device_operations ide_gd_ops = {
- .owner = THIS_MODULE,
- .open = ide_gd_unlocked_open,
- .release = ide_gd_release,
- .ioctl = ide_gd_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = ide_gd_compat_ioctl,
-#endif
- .getgeo = ide_gd_getgeo,
- .unlock_native_capacity = ide_gd_unlock_native_capacity,
-};
-
-static int ide_gd_probe(ide_drive_t *drive)
-{
- const struct ide_disk_ops *disk_ops = NULL;
- struct ide_disk_obj *idkp;
- struct gendisk *g;
-
- /* strstr("foo", "") is non-NULL */
- if (!strstr("ide-gd", drive->driver_req))
- goto failed;
-
-#ifdef CONFIG_IDE_GD_ATA
- if (drive->media == ide_disk)
- disk_ops = &ide_ata_disk_ops;
-#endif
-#ifdef CONFIG_IDE_GD_ATAPI
- if (drive->media == ide_floppy)
- disk_ops = &ide_atapi_disk_ops;
-#endif
- if (disk_ops == NULL)
- goto failed;
-
- if (disk_ops->check(drive, DRV_NAME) == 0) {
- printk(KERN_ERR PFX "%s: not supported by this driver\n",
- drive->name);
- goto failed;
- }
-
- idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
- if (!idkp) {
- printk(KERN_ERR PFX "%s: can't allocate a disk structure\n",
- drive->name);
- goto failed;
- }
-
- g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
- if (!g)
- goto out_free_idkp;
-
- ide_init_disk(g, drive);
-
- idkp->dev.parent = &drive->gendev;
- idkp->dev.release = ide_disk_release;
- dev_set_name(&idkp->dev, "%s", dev_name(&drive->gendev));
-
- if (device_register(&idkp->dev))
- goto out_free_disk;
-
- idkp->drive = drive;
- idkp->driver = &ide_gd_driver;
- idkp->disk = g;
-
- g->private_data = &idkp->driver;
-
- drive->driver_data = idkp;
- drive->debug_mask = debug_mask;
- drive->disk_ops = disk_ops;
-
- disk_ops->setup(drive);
-
- set_capacity(g, ide_gd_capacity(drive));
-
- g->minors = IDE_DISK_MINORS;
- g->flags |= GENHD_FL_EXT_DEVT;
- if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
- g->flags = GENHD_FL_REMOVABLE;
- g->fops = &ide_gd_ops;
- g->events = DISK_EVENT_MEDIA_CHANGE;
- device_add_disk(&drive->gendev, g, NULL);
- return 0;
-
-out_free_disk:
- put_disk(g);
-out_free_idkp:
- kfree(idkp);
-failed:
- return -ENODEV;
-}
-
-static int __init ide_gd_init(void)
-{
- printk(KERN_INFO DRV_NAME " driver " IDE_GD_VERSION "\n");
- return driver_register(&ide_gd_driver.gen_driver);
-}
-
-static void __exit ide_gd_exit(void)
-{
- driver_unregister(&ide_gd_driver.gen_driver);
-}
-
-MODULE_ALIAS("ide:*m-disk*");
-MODULE_ALIAS("ide-disk");
-MODULE_ALIAS("ide:*m-floppy*");
-MODULE_ALIAS("ide-floppy");
-module_init(ide_gd_init);
-module_exit(ide_gd_exit);
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("generic ATA/ATAPI disk driver");
diff --git a/drivers/ide/ide-gd.h b/drivers/ide/ide-gd.h
deleted file mode 100644
index af3fe1880e9e..000000000000
--- a/drivers/ide/ide-gd.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __IDE_GD_H
-#define __IDE_GD_H
-
-#define DRV_NAME "ide-gd"
-#define PFX DRV_NAME ": "
-
-/* define to see debug info */
-#define IDE_GD_DEBUG_LOG 0
-
-#if IDE_GD_DEBUG_LOG
-#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args)
-#else
-#define ide_debug_log(lvl, fmt, args...) do {} while (0)
-#endif
-
-struct ide_disk_obj {
- ide_drive_t *drive;
- struct ide_driver *driver;
- struct gendisk *disk;
- struct device dev;
- unsigned int openers; /* protected by BKL for now */
-
- /* used for blk_{fs,pc}_request() requests */
- struct ide_atapi_pc queued_pc;
-
- /* Last error information */
- u8 sense_key, asc, ascq;
-
- int progress_indication;
-
- /* Device information */
- /* Current format */
- int blocks, block_size, bs_factor;
- /* Last format capacity descriptor */
- u8 cap_desc[8];
- /* Copy of the flexible disk page */
- u8 flexible_disk_page[32];
-};
-
-sector_t ide_gd_capacity(ide_drive_t *);
-
-#endif /* __IDE_GD_H */
diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
deleted file mode 100644
index 80c0d69b83ac..000000000000
--- a/drivers/ide/ide-generic.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * generic/default IDE host driver
- *
- * Copyright (C) 2004, 2008-2009 Bartlomiej Zolnierkiewicz
- * This code was split off from ide.c. See it for original copyrights.
- *
- * May be copied or modified under the terms of the GNU General Public License.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/ide.h>
-#include <linux/pci_ids.h>
-
-/* FIXME: convert arm to use ide_platform host driver */
-#ifdef CONFIG_ARM
-#include <asm/irq.h>
-#endif
-
-#define DRV_NAME "ide_generic"
-
-static int probe_mask;
-module_param(probe_mask, int, 0);
-MODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports");
-
-static const struct ide_port_info ide_generic_port_info = {
- .host_flags = IDE_HFLAG_NO_DMA,
- .chipset = ide_generic,
-};
-
-#ifdef CONFIG_ARM
-static const u16 legacy_bases[] = { 0x1f0 };
-static const int legacy_irqs[] = { IRQ_HARDDISK };
-#elif defined(CONFIG_ALPHA)
-static const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168 };
-static const int legacy_irqs[] = { 14, 15, 11, 10 };
-#else
-static const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
-static const int legacy_irqs[] = { 14, 15, 11, 10, 8, 12 };
-#endif
-
-static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary)
-{
-#ifdef CONFIG_PCI
- struct pci_dev *p = NULL;
- u16 val;
-
- for_each_pci_dev(p) {
- if (pci_resource_start(p, 0) == 0x1f0)
- *primary = 1;
- if (pci_resource_start(p, 2) == 0x170)
- *secondary = 1;
-
- /* Cyrix CS55{1,2}0 pre SFF MWDMA ATA on the bridge */
- if (p->vendor == PCI_VENDOR_ID_CYRIX &&
- (p->device == PCI_DEVICE_ID_CYRIX_5510 ||
- p->device == PCI_DEVICE_ID_CYRIX_5520))
- *primary = *secondary = 1;
-
- /* Intel MPIIX - PIO ATA on non PCI side of bridge */
- if (p->vendor == PCI_VENDOR_ID_INTEL &&
- p->device == PCI_DEVICE_ID_INTEL_82371MX) {
- pci_read_config_word(p, 0x6C, &val);
- if (val & 0x8000) {
- /* ATA port enabled */
- if (val & 0x4000)
- *secondary = 1;
- else
- *primary = 1;
- }
- }
- }
-#endif
-}
-
-static int __init ide_generic_init(void)
-{
- struct ide_hw hw, *hws[] = { &hw };
- unsigned long io_addr;
- int i, rc = 0, primary = 0, secondary = 0;
-
- ide_generic_check_pci_legacy_iobases(&primary, &secondary);
-
- if (!probe_mask) {
- printk(KERN_INFO DRV_NAME ": please use \"probe_mask=0x3f\" "
- "module parameter for probing all legacy ISA IDE ports\n");
-
- if (primary == 0)
- probe_mask |= 0x1;
-
- if (secondary == 0)
- probe_mask |= 0x2;
- } else
- printk(KERN_INFO DRV_NAME ": enforcing probing of I/O ports "
- "upon user request\n");
-
- for (i = 0; i < ARRAY_SIZE(legacy_bases); i++) {
- io_addr = legacy_bases[i];
-
- if ((probe_mask & (1 << i)) && io_addr) {
- if (!request_region(io_addr, 8, DRV_NAME)) {
- printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX "
- "not free.\n",
- DRV_NAME, io_addr, io_addr + 7);
- rc = -EBUSY;
- continue;
- }
-
- if (!request_region(io_addr + 0x206, 1, DRV_NAME)) {
- printk(KERN_ERR "%s: I/O resource 0x%lX "
- "not free.\n",
- DRV_NAME, io_addr + 0x206);
- release_region(io_addr, 8);
- rc = -EBUSY;
- continue;
- }
-
- memset(&hw, 0, sizeof(hw));
- ide_std_init_ports(&hw, io_addr, io_addr + 0x206);
-#ifdef CONFIG_IA64
- hw.irq = isa_irq_to_vector(legacy_irqs[i]);
-#else
- hw.irq = legacy_irqs[i];
-#endif
- rc = ide_host_add(&ide_generic_port_info, hws, 1, NULL);
- if (rc) {
- release_region(io_addr + 0x206, 1);
- release_region(io_addr, 8);
- }
- }
- }
-
- return rc;
-}
-
-module_init(ide_generic_init);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-io-std.c b/drivers/ide/ide-io-std.c
deleted file mode 100644
index 94bdcf1ea186..000000000000
--- a/drivers/ide/ide-io-std.c
+++ /dev/null
@@ -1,262 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/ide.h>
-
-#if defined(CONFIG_ARM) || defined(CONFIG_M68K) || defined(CONFIG_MIPS) || \
- defined(CONFIG_PARISC) || defined(CONFIG_PPC) || defined(CONFIG_SPARC)
-#include <asm/ide.h>
-#else
-#include <asm-generic/ide_iops.h>
-#endif
-
-/*
- * Conventional PIO operations for ATA devices
- */
-
-static u8 ide_inb(unsigned long port)
-{
- return (u8) inb(port);
-}
-
-static void ide_outb(u8 val, unsigned long port)
-{
- outb(val, port);
-}
-
-/*
- * MMIO operations, typically used for SATA controllers
- */
-
-static u8 ide_mm_inb(unsigned long port)
-{
- return (u8) readb((void __iomem *) port);
-}
-
-static void ide_mm_outb(u8 value, unsigned long port)
-{
- writeb(value, (void __iomem *) port);
-}
-
-void ide_exec_command(ide_hwif_t *hwif, u8 cmd)
-{
- if (hwif->host_flags & IDE_HFLAG_MMIO)
- writeb(cmd, (void __iomem *)hwif->io_ports.command_addr);
- else
- outb(cmd, hwif->io_ports.command_addr);
-}
-EXPORT_SYMBOL_GPL(ide_exec_command);
-
-u8 ide_read_status(ide_hwif_t *hwif)
-{
- if (hwif->host_flags & IDE_HFLAG_MMIO)
- return readb((void __iomem *)hwif->io_ports.status_addr);
- else
- return inb(hwif->io_ports.status_addr);
-}
-EXPORT_SYMBOL_GPL(ide_read_status);
-
-u8 ide_read_altstatus(ide_hwif_t *hwif)
-{
- if (hwif->host_flags & IDE_HFLAG_MMIO)
- return readb((void __iomem *)hwif->io_ports.ctl_addr);
- else
- return inb(hwif->io_ports.ctl_addr);
-}
-EXPORT_SYMBOL_GPL(ide_read_altstatus);
-
-void ide_write_devctl(ide_hwif_t *hwif, u8 ctl)
-{
- if (hwif->host_flags & IDE_HFLAG_MMIO)
- writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
- else
- outb(ctl, hwif->io_ports.ctl_addr);
-}
-EXPORT_SYMBOL_GPL(ide_write_devctl);
-
-void ide_dev_select(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 select = drive->select | ATA_DEVICE_OBS;
-
- if (hwif->host_flags & IDE_HFLAG_MMIO)
- writeb(select, (void __iomem *)hwif->io_ports.device_addr);
- else
- outb(select, hwif->io_ports.device_addr);
-}
-EXPORT_SYMBOL_GPL(ide_dev_select);
-
-void ide_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct ide_io_ports *io_ports = &hwif->io_ports;
- void (*tf_outb)(u8 addr, unsigned long port);
- u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-
- if (mmio)
- tf_outb = ide_mm_outb;
- else
- tf_outb = ide_outb;
-
- if (valid & IDE_VALID_FEATURE)
- tf_outb(tf->feature, io_ports->feature_addr);
- if (valid & IDE_VALID_NSECT)
- tf_outb(tf->nsect, io_ports->nsect_addr);
- if (valid & IDE_VALID_LBAL)
- tf_outb(tf->lbal, io_ports->lbal_addr);
- if (valid & IDE_VALID_LBAM)
- tf_outb(tf->lbam, io_ports->lbam_addr);
- if (valid & IDE_VALID_LBAH)
- tf_outb(tf->lbah, io_ports->lbah_addr);
- if (valid & IDE_VALID_DEVICE)
- tf_outb(tf->device, io_ports->device_addr);
-}
-EXPORT_SYMBOL_GPL(ide_tf_load);
-
-void ide_tf_read(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct ide_io_ports *io_ports = &hwif->io_ports;
- u8 (*tf_inb)(unsigned long port);
- u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-
- if (mmio)
- tf_inb = ide_mm_inb;
- else
- tf_inb = ide_inb;
-
- if (valid & IDE_VALID_ERROR)
- tf->error = tf_inb(io_ports->feature_addr);
- if (valid & IDE_VALID_NSECT)
- tf->nsect = tf_inb(io_ports->nsect_addr);
- if (valid & IDE_VALID_LBAL)
- tf->lbal = tf_inb(io_ports->lbal_addr);
- if (valid & IDE_VALID_LBAM)
- tf->lbam = tf_inb(io_ports->lbam_addr);
- if (valid & IDE_VALID_LBAH)
- tf->lbah = tf_inb(io_ports->lbah_addr);
- if (valid & IDE_VALID_DEVICE)
- tf->device = tf_inb(io_ports->device_addr);
-}
-EXPORT_SYMBOL_GPL(ide_tf_read);
-
-/*
- * Some localbus EIDE interfaces require a special access sequence
- * when using 32-bit I/O instructions to transfer data. We call this
- * the "vlb_sync" sequence, which consists of three successive reads
- * of the sector count register location, with interrupts disabled
- * to ensure that the reads all happen together.
- */
-static void ata_vlb_sync(unsigned long port)
-{
- (void)inb(port);
- (void)inb(port);
- (void)inb(port);
-}
-
-/*
- * This is used for most PIO data transfers *from* the IDE interface
- *
- * These routines will round up any request for an odd number of bytes,
- * so if an odd len is specified, be sure that there's at least one
- * extra byte allocated for the buffer.
- */
-void ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf,
- unsigned int len)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct ide_io_ports *io_ports = &hwif->io_ports;
- unsigned long data_addr = io_ports->data_addr;
- unsigned int words = (len + 1) >> 1;
- u8 io_32bit = drive->io_32bit;
- u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-
- if (io_32bit) {
- unsigned long flags;
-
- if ((io_32bit & 2) && !mmio) {
- local_irq_save(flags);
- ata_vlb_sync(io_ports->nsect_addr);
- }
-
- words >>= 1;
- if (mmio)
- __ide_mm_insl((void __iomem *)data_addr, buf, words);
- else
- insl(data_addr, buf, words);
-
- if ((io_32bit & 2) && !mmio)
- local_irq_restore(flags);
-
- if (((len + 1) & 3) < 2)
- return;
-
- buf += len & ~3;
- words = 1;
- }
-
- if (mmio)
- __ide_mm_insw((void __iomem *)data_addr, buf, words);
- else
- insw(data_addr, buf, words);
-}
-EXPORT_SYMBOL_GPL(ide_input_data);
-
-/*
- * This is used for most PIO data transfers *to* the IDE interface
- */
-void ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf,
- unsigned int len)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct ide_io_ports *io_ports = &hwif->io_ports;
- unsigned long data_addr = io_ports->data_addr;
- unsigned int words = (len + 1) >> 1;
- u8 io_32bit = drive->io_32bit;
- u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-
- if (io_32bit) {
- unsigned long flags;
-
- if ((io_32bit & 2) && !mmio) {
- local_irq_save(flags);
- ata_vlb_sync(io_ports->nsect_addr);
- }
-
- words >>= 1;
- if (mmio)
- __ide_mm_outsl((void __iomem *)data_addr, buf, words);
- else
- outsl(data_addr, buf, words);
-
- if ((io_32bit & 2) && !mmio)
- local_irq_restore(flags);
-
- if (((len + 1) & 3) < 2)
- return;
-
- buf += len & ~3;
- words = 1;
- }
-
- if (mmio)
- __ide_mm_outsw((void __iomem *)data_addr, buf, words);
- else
- outsw(data_addr, buf, words);
-}
-EXPORT_SYMBOL_GPL(ide_output_data);
-
-const struct ide_tp_ops default_tp_ops = {
- .exec_command = ide_exec_command,
- .read_status = ide_read_status,
- .read_altstatus = ide_read_altstatus,
- .write_devctl = ide_write_devctl,
-
- .dev_select = ide_dev_select,
- .tf_load = ide_tf_load,
- .tf_read = ide_tf_read,
-
- .input_data = ide_input_data,
- .output_data = ide_output_data,
-};
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
deleted file mode 100644
index 4867b67b60d6..000000000000
--- a/drivers/ide/ide-io.c
+++ /dev/null
@@ -1,904 +0,0 @@
-/*
- * IDE I/O functions
- *
- * Basic PIO and command management functionality.
- *
- * This code was split off from ide.c. See ide.c for history and original
- * copyrights.
- *
- * 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, 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.
- *
- * For the avoidance of doubt the "preferred form" of this code is one which
- * is in an open non patent encumbered format. Where cryptographic key signing
- * forms part of the process of creating an executable the information
- * including keys needed to generate an equivalently functional executable
- * are deemed to be part of the source code.
- */
-
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/blkpg.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/completion.h>
-#include <linux/reboot.h>
-#include <linux/cdrom.h>
-#include <linux/seq_file.h>
-#include <linux/device.h>
-#include <linux/kmod.h>
-#include <linux/scatterlist.h>
-#include <linux/bitops.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <linux/uaccess.h>
-#include <asm/io.h>
-
-int ide_end_rq(ide_drive_t *drive, struct request *rq, blk_status_t error,
- unsigned int nr_bytes)
-{
- /*
- * decide whether to reenable DMA -- 3 is a random magic for now,
- * if we DMA timeout more than 3 times, just stay in PIO
- */
- if ((drive->dev_flags & IDE_DFLAG_DMA_PIO_RETRY) &&
- drive->retry_pio <= 3) {
- drive->dev_flags &= ~IDE_DFLAG_DMA_PIO_RETRY;
- ide_dma_on(drive);
- }
-
- if (!blk_update_request(rq, error, nr_bytes)) {
- if (rq == drive->sense_rq) {
- drive->sense_rq = NULL;
- drive->sense_rq_active = false;
- }
-
- __blk_mq_end_request(rq, error);
- return 0;
- }
-
- return 1;
-}
-EXPORT_SYMBOL_GPL(ide_end_rq);
-
-void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err)
-{
- const struct ide_tp_ops *tp_ops = drive->hwif->tp_ops;
- struct ide_taskfile *tf = &cmd->tf;
- struct request *rq = cmd->rq;
- u8 tf_cmd = tf->command;
-
- tf->error = err;
- tf->status = stat;
-
- if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {
- u8 data[2];
-
- tp_ops->input_data(drive, cmd, data, 2);
-
- cmd->tf.data = data[0];
- cmd->hob.data = data[1];
- }
-
- ide_tf_readback(drive, cmd);
-
- if ((cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) &&
- tf_cmd == ATA_CMD_IDLEIMMEDIATE) {
- if (tf->lbal != 0xc4) {
- printk(KERN_ERR "%s: head unload failed!\n",
- drive->name);
- ide_tf_dump(drive->name, cmd);
- } else
- drive->dev_flags |= IDE_DFLAG_PARKED;
- }
-
- if (rq && ata_taskfile_request(rq)) {
- struct ide_cmd *orig_cmd = ide_req(rq)->special;
-
- if (cmd->tf_flags & IDE_TFLAG_DYN)
- kfree(orig_cmd);
- else if (cmd != orig_cmd)
- memcpy(orig_cmd, cmd, sizeof(*cmd));
- }
-}
-
-int ide_complete_rq(ide_drive_t *drive, blk_status_t error, unsigned int nr_bytes)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct request *rq = hwif->rq;
- int rc;
-
- /*
- * if failfast is set on a request, override number of sectors
- * and complete the whole request right now
- */
- if (blk_noretry_request(rq) && error)
- nr_bytes = blk_rq_sectors(rq) << 9;
-
- rc = ide_end_rq(drive, rq, error, nr_bytes);
- if (rc == 0)
- hwif->rq = NULL;
-
- return rc;
-}
-EXPORT_SYMBOL(ide_complete_rq);
-
-void ide_kill_rq(ide_drive_t *drive, struct request *rq)
-{
- u8 drv_req = ata_misc_request(rq) && rq->rq_disk;
- u8 media = drive->media;
-
- drive->failed_pc = NULL;
-
- if ((media == ide_floppy || media == ide_tape) && drv_req) {
- scsi_req(rq)->result = 0;
- } else {
- if (media == ide_tape)
- scsi_req(rq)->result = IDE_DRV_ERROR_GENERAL;
- else if (blk_rq_is_passthrough(rq) && scsi_req(rq)->result == 0)
- scsi_req(rq)->result = -EIO;
- }
-
- ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(rq));
-}
-
-static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
-{
- tf->nsect = drive->sect;
- tf->lbal = drive->sect;
- tf->lbam = drive->cyl;
- tf->lbah = drive->cyl >> 8;
- tf->device = (drive->head - 1) | drive->select;
- tf->command = ATA_CMD_INIT_DEV_PARAMS;
-}
-
-static void ide_tf_set_restore_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
-{
- tf->nsect = drive->sect;
- tf->command = ATA_CMD_RESTORE;
-}
-
-static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
-{
- tf->nsect = drive->mult_req;
- tf->command = ATA_CMD_SET_MULTI;
-}
-
-/**
- * do_special - issue some special commands
- * @drive: drive the command is for
- *
- * do_special() is used to issue ATA_CMD_INIT_DEV_PARAMS,
- * ATA_CMD_RESTORE and ATA_CMD_SET_MULTI commands to a drive.
- */
-
-static ide_startstop_t do_special(ide_drive_t *drive)
-{
- struct ide_cmd cmd;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "%s: %s: 0x%02x\n", drive->name, __func__,
- drive->special_flags);
-#endif
- if (drive->media != ide_disk) {
- drive->special_flags = 0;
- drive->mult_req = 0;
- return ide_stopped;
- }
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.protocol = ATA_PROT_NODATA;
-
- if (drive->special_flags & IDE_SFLAG_SET_GEOMETRY) {
- drive->special_flags &= ~IDE_SFLAG_SET_GEOMETRY;
- ide_tf_set_specify_cmd(drive, &cmd.tf);
- } else if (drive->special_flags & IDE_SFLAG_RECALIBRATE) {
- drive->special_flags &= ~IDE_SFLAG_RECALIBRATE;
- ide_tf_set_restore_cmd(drive, &cmd.tf);
- } else if (drive->special_flags & IDE_SFLAG_SET_MULTMODE) {
- drive->special_flags &= ~IDE_SFLAG_SET_MULTMODE;
- ide_tf_set_setmult_cmd(drive, &cmd.tf);
- } else
- BUG();
-
- cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
- cmd.tf_flags = IDE_TFLAG_CUSTOM_HANDLER;
-
- do_rw_taskfile(drive, &cmd);
-
- return ide_started;
-}
-
-void ide_map_sg(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct scatterlist *sg = hwif->sg_table, *last_sg = NULL;
- struct request *rq = cmd->rq;
-
- cmd->sg_nents = __blk_rq_map_sg(drive->queue, rq, sg, &last_sg);
- if (blk_rq_bytes(rq) && (blk_rq_bytes(rq) & rq->q->dma_pad_mask))
- last_sg->length +=
- (rq->q->dma_pad_mask & ~blk_rq_bytes(rq)) + 1;
-}
-EXPORT_SYMBOL_GPL(ide_map_sg);
-
-void ide_init_sg_cmd(struct ide_cmd *cmd, unsigned int nr_bytes)
-{
- cmd->nbytes = cmd->nleft = nr_bytes;
- cmd->cursg_ofs = 0;
- cmd->cursg = NULL;
-}
-EXPORT_SYMBOL_GPL(ide_init_sg_cmd);
-
-/**
- * execute_drive_command - issue special drive command
- * @drive: the drive to issue the command on
- * @rq: the request structure holding the command
- *
- * execute_drive_cmd() issues a special drive command, usually
- * initiated by ioctl() from the external hdparm program. The
- * command can be a drive command, drive task or taskfile
- * operation. Weirdly you can call it with NULL to wait for
- * all commands to finish. Don't do this as that is due to change
- */
-
-static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
- struct request *rq)
-{
- struct ide_cmd *cmd = ide_req(rq)->special;
-
- if (cmd) {
- if (cmd->protocol == ATA_PROT_PIO) {
- ide_init_sg_cmd(cmd, blk_rq_sectors(rq) << 9);
- ide_map_sg(drive, cmd);
- }
-
- return do_rw_taskfile(drive, cmd);
- }
-
- /*
- * NULL is actually a valid way of waiting for
- * all current requests to be flushed from the queue.
- */
-#ifdef DEBUG
- printk("%s: DRIVE_CMD (null)\n", drive->name);
-#endif
- scsi_req(rq)->result = 0;
- ide_complete_rq(drive, BLK_STS_OK, blk_rq_bytes(rq));
-
- return ide_stopped;
-}
-
-static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
-{
- u8 cmd = scsi_req(rq)->cmd[0];
-
- switch (cmd) {
- case REQ_PARK_HEADS:
- case REQ_UNPARK_HEADS:
- return ide_do_park_unpark(drive, rq);
- case REQ_DEVSET_EXEC:
- return ide_do_devset(drive, rq);
- case REQ_DRIVE_RESET:
- return ide_do_reset(drive);
- default:
- BUG();
- }
-}
-
-/**
- * start_request - start of I/O and command issuing for IDE
- *
- * start_request() initiates handling of a new I/O request. It
- * accepts commands and I/O (read/write) requests.
- *
- * FIXME: this function needs a rename
- */
-
-static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
-{
- ide_startstop_t startstop;
-
-#ifdef DEBUG
- printk("%s: start_request: current=0x%08lx\n",
- drive->hwif->name, (unsigned long) rq);
-#endif
-
- /* bail early if we've exceeded max_failures */
- if (drive->max_failures && (drive->failures > drive->max_failures)) {
- rq->rq_flags |= RQF_FAILED;
- goto kill_rq;
- }
-
- if (drive->prep_rq && !drive->prep_rq(drive, rq))
- return ide_stopped;
-
- if (ata_pm_request(rq))
- ide_check_pm_state(drive, rq);
-
- drive->hwif->tp_ops->dev_select(drive);
- if (ide_wait_stat(&startstop, drive, drive->ready_stat,
- ATA_BUSY | ATA_DRQ, WAIT_READY)) {
- printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
- return startstop;
- }
-
- if (drive->special_flags == 0) {
- struct ide_driver *drv;
-
- /*
- * We reset the drive so we need to issue a SETFEATURES.
- * Do it _after_ do_special() restored device parameters.
- */
- if (drive->current_speed == 0xff)
- ide_config_drive_speed(drive, drive->desired_speed);
-
- if (ata_taskfile_request(rq))
- return execute_drive_cmd(drive, rq);
- else if (ata_pm_request(rq)) {
- struct ide_pm_state *pm = ide_req(rq)->special;
-#ifdef DEBUG_PM
- printk("%s: start_power_step(step: %d)\n",
- drive->name, pm->pm_step);
-#endif
- startstop = ide_start_power_step(drive, rq);
- if (startstop == ide_stopped &&
- pm->pm_step == IDE_PM_COMPLETED)
- ide_complete_pm_rq(drive, rq);
- return startstop;
- } else if (!rq->rq_disk && ata_misc_request(rq))
- /*
- * TODO: Once all ULDs have been modified to
- * check for specific op codes rather than
- * blindly accepting any special request, the
- * check for ->rq_disk above may be replaced
- * by a more suitable mechanism or even
- * dropped entirely.
- */
- return ide_special_rq(drive, rq);
-
- drv = *(struct ide_driver **)rq->rq_disk->private_data;
-
- return drv->do_request(drive, rq, blk_rq_pos(rq));
- }
- return do_special(drive);
-kill_rq:
- ide_kill_rq(drive, rq);
- return ide_stopped;
-}
-
-/**
- * ide_stall_queue - pause an IDE device
- * @drive: drive to stall
- * @timeout: time to stall for (jiffies)
- *
- * ide_stall_queue() can be used by a drive to give excess bandwidth back
- * to the port by sleeping for timeout jiffies.
- */
-
-void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
-{
- if (timeout > WAIT_WORSTCASE)
- timeout = WAIT_WORSTCASE;
- drive->sleep = timeout + jiffies;
- drive->dev_flags |= IDE_DFLAG_SLEEPING;
-}
-EXPORT_SYMBOL(ide_stall_queue);
-
-static inline int ide_lock_port(ide_hwif_t *hwif)
-{
- if (hwif->busy)
- return 1;
-
- hwif->busy = 1;
-
- return 0;
-}
-
-static inline void ide_unlock_port(ide_hwif_t *hwif)
-{
- hwif->busy = 0;
-}
-
-static inline int ide_lock_host(struct ide_host *host, ide_hwif_t *hwif)
-{
- int rc = 0;
-
- if (host->host_flags & IDE_HFLAG_SERIALIZE) {
- rc = test_and_set_bit_lock(IDE_HOST_BUSY, &host->host_busy);
- if (rc == 0) {
- if (host->get_lock)
- host->get_lock(ide_intr, hwif);
- }
- }
- return rc;
-}
-
-static inline void ide_unlock_host(struct ide_host *host)
-{
- if (host->host_flags & IDE_HFLAG_SERIALIZE) {
- if (host->release_lock)
- host->release_lock();
- clear_bit_unlock(IDE_HOST_BUSY, &host->host_busy);
- }
-}
-
-void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq)
-{
- struct request_queue *q = drive->queue;
-
- /* Use 3ms as that was the old plug delay */
- if (rq) {
- blk_mq_requeue_request(rq, false);
- blk_mq_delay_kick_requeue_list(q, 3);
- } else
- blk_mq_delay_run_hw_queue(q->queue_hw_ctx[0], 3);
-}
-
-blk_status_t ide_issue_rq(ide_drive_t *drive, struct request *rq,
- bool local_requeue)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct ide_host *host = hwif->host;
- ide_startstop_t startstop;
-
- if (!blk_rq_is_passthrough(rq) && !(rq->rq_flags & RQF_DONTPREP)) {
- rq->rq_flags |= RQF_DONTPREP;
- ide_req(rq)->special = NULL;
- }
-
- /* HLD do_request() callback might sleep, make sure it's okay */
- might_sleep();
-
- if (ide_lock_host(host, hwif))
- return BLK_STS_DEV_RESOURCE;
-
- spin_lock_irq(&hwif->lock);
-
- if (!ide_lock_port(hwif)) {
- ide_hwif_t *prev_port;
-
- WARN_ON_ONCE(hwif->rq);
-repeat:
- prev_port = hwif->host->cur_port;
- if (drive->dev_flags & IDE_DFLAG_SLEEPING &&
- time_after(drive->sleep, jiffies)) {
- ide_unlock_port(hwif);
- goto plug_device;
- }
-
- if ((hwif->host->host_flags & IDE_HFLAG_SERIALIZE) &&
- hwif != prev_port) {
- ide_drive_t *cur_dev =
- prev_port ? prev_port->cur_dev : NULL;
-
- /*
- * set nIEN for previous port, drives in the
- * quirk list may not like intr setups/cleanups
- */
- if (cur_dev &&
- (cur_dev->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0)
- prev_port->tp_ops->write_devctl(prev_port,
- ATA_NIEN |
- ATA_DEVCTL_OBS);
-
- hwif->host->cur_port = hwif;
- }
- hwif->cur_dev = drive;
- drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);
-
- /*
- * Sanity: don't accept a request that isn't a PM request
- * if we are currently power managed. This is very important as
- * blk_stop_queue() doesn't prevent the blk_fetch_request()
- * above to return us whatever is in the queue. Since we call
- * ide_do_request() ourselves, we end up taking requests while
- * the queue is blocked...
- */
- if ((drive->dev_flags & IDE_DFLAG_BLOCKED) &&
- ata_pm_request(rq) == 0 &&
- (rq->rq_flags & RQF_PM) == 0) {
- /* there should be no pending command at this point */
- ide_unlock_port(hwif);
- goto plug_device;
- }
-
- scsi_req(rq)->resid_len = blk_rq_bytes(rq);
- hwif->rq = rq;
-
- spin_unlock_irq(&hwif->lock);
- startstop = start_request(drive, rq);
- spin_lock_irq(&hwif->lock);
-
- if (startstop == ide_stopped) {
- rq = hwif->rq;
- hwif->rq = NULL;
- if (rq)
- goto repeat;
- ide_unlock_port(hwif);
- goto out;
- }
- } else {
-plug_device:
- if (local_requeue)
- list_add(&rq->queuelist, &drive->rq_list);
- spin_unlock_irq(&hwif->lock);
- ide_unlock_host(host);
- if (!local_requeue)
- ide_requeue_and_plug(drive, rq);
- return BLK_STS_OK;
- }
-
-out:
- spin_unlock_irq(&hwif->lock);
- if (rq == NULL)
- ide_unlock_host(host);
- return BLK_STS_OK;
-}
-
-/*
- * Issue a new request to a device.
- */
-blk_status_t ide_queue_rq(struct blk_mq_hw_ctx *hctx,
- const struct blk_mq_queue_data *bd)
-{
- ide_drive_t *drive = hctx->queue->queuedata;
- ide_hwif_t *hwif = drive->hwif;
-
- spin_lock_irq(&hwif->lock);
- if (drive->sense_rq_active) {
- spin_unlock_irq(&hwif->lock);
- return BLK_STS_DEV_RESOURCE;
- }
- spin_unlock_irq(&hwif->lock);
-
- blk_mq_start_request(bd->rq);
- return ide_issue_rq(drive, bd->rq, false);
-}
-
-static int drive_is_ready(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 stat = 0;
-
- if (drive->waiting_for_dma)
- return hwif->dma_ops->dma_test_irq(drive);
-
- if (hwif->io_ports.ctl_addr &&
- (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0)
- stat = hwif->tp_ops->read_altstatus(hwif);
- else
- /* Note: this may clear a pending IRQ!! */
- stat = hwif->tp_ops->read_status(hwif);
-
- if (stat & ATA_BUSY)
- /* drive busy: definitely not interrupting */
- return 0;
-
- /* drive ready: *might* be interrupting */
- return 1;
-}
-
-/**
- * ide_timer_expiry - handle lack of an IDE interrupt
- * @data: timer callback magic (hwif)
- *
- * An IDE command has timed out before the expected drive return
- * occurred. At this point we attempt to clean up the current
- * mess. If the current handler includes an expiry handler then
- * we invoke the expiry handler, and providing it is happy the
- * work is done. If that fails we apply generic recovery rules
- * invoking the handler and checking the drive DMA status. We
- * have an excessively incestuous relationship with the DMA
- * logic that wants cleaning up.
- */
-
-void ide_timer_expiry (struct timer_list *t)
-{
- ide_hwif_t *hwif = from_timer(hwif, t, timer);
- ide_drive_t *drive;
- ide_handler_t *handler;
- unsigned long flags;
- int wait = -1;
- int plug_device = 0;
- struct request *rq_in_flight;
-
- spin_lock_irqsave(&hwif->lock, flags);
-
- handler = hwif->handler;
-
- if (handler == NULL || hwif->req_gen != hwif->req_gen_timer) {
- /*
- * Either a marginal timeout occurred
- * (got the interrupt just as timer expired),
- * or we were "sleeping" to give other devices a chance.
- * Either way, we don't really want to complain about anything.
- */
- } else {
- ide_expiry_t *expiry = hwif->expiry;
- ide_startstop_t startstop = ide_stopped;
-
- drive = hwif->cur_dev;
-
- if (expiry) {
- wait = expiry(drive);
- if (wait > 0) { /* continue */
- /* reset timer */
- hwif->timer.expires = jiffies + wait;
- hwif->req_gen_timer = hwif->req_gen;
- add_timer(&hwif->timer);
- spin_unlock_irqrestore(&hwif->lock, flags);
- return;
- }
- }
- hwif->handler = NULL;
- hwif->expiry = NULL;
- /*
- * We need to simulate a real interrupt when invoking
- * the handler() function, which means we need to
- * globally mask the specific IRQ:
- */
- spin_unlock(&hwif->lock);
- /* disable_irq_nosync ?? */
- disable_irq(hwif->irq);
-
- if (hwif->polling) {
- startstop = handler(drive);
- } else if (drive_is_ready(drive)) {
- if (drive->waiting_for_dma)
- hwif->dma_ops->dma_lost_irq(drive);
- if (hwif->port_ops && hwif->port_ops->clear_irq)
- hwif->port_ops->clear_irq(drive);
-
- printk(KERN_WARNING "%s: lost interrupt\n",
- drive->name);
- startstop = handler(drive);
- } else {
- if (drive->waiting_for_dma)
- startstop = ide_dma_timeout_retry(drive, wait);
- else
- startstop = ide_error(drive, "irq timeout",
- hwif->tp_ops->read_status(hwif));
- }
- /* Disable interrupts again, `handler' might have enabled it */
- spin_lock_irq(&hwif->lock);
- enable_irq(hwif->irq);
- if (startstop == ide_stopped && hwif->polling == 0) {
- rq_in_flight = hwif->rq;
- hwif->rq = NULL;
- ide_unlock_port(hwif);
- plug_device = 1;
- }
- }
- spin_unlock_irqrestore(&hwif->lock, flags);
-
- if (plug_device) {
- ide_unlock_host(hwif->host);
- ide_requeue_and_plug(drive, rq_in_flight);
- }
-}
-
-/**
- * unexpected_intr - handle an unexpected IDE interrupt
- * @irq: interrupt line
- * @hwif: port being processed
- *
- * There's nothing really useful we can do with an unexpected interrupt,
- * other than reading the status register (to clear it), and logging it.
- * There should be no way that an irq can happen before we're ready for it,
- * so we needn't worry much about losing an "important" interrupt here.
- *
- * On laptops (and "green" PCs), an unexpected interrupt occurs whenever
- * the drive enters "idle", "standby", or "sleep" mode, so if the status
- * looks "good", we just ignore the interrupt completely.
- *
- * This routine assumes __cli() is in effect when called.
- *
- * If an unexpected interrupt happens on irq15 while we are handling irq14
- * and if the two interfaces are "serialized" (CMD640), then it looks like
- * we could screw up by interfering with a new request being set up for
- * irq15.
- *
- * In reality, this is a non-issue. The new command is not sent unless
- * the drive is ready to accept one, in which case we know the drive is
- * not trying to interrupt us. And ide_set_handler() is always invoked
- * before completing the issuance of any new drive command, so we will not
- * be accidentally invoked as a result of any valid command completion
- * interrupt.
- */
-
-static void unexpected_intr(int irq, ide_hwif_t *hwif)
-{
- u8 stat = hwif->tp_ops->read_status(hwif);
-
- if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
- /* Try to not flood the console with msgs */
- static unsigned long last_msgtime, count;
- ++count;
-
- if (time_after(jiffies, last_msgtime + HZ)) {
- last_msgtime = jiffies;
- printk(KERN_ERR "%s: unexpected interrupt, "
- "status=0x%02x, count=%ld\n",
- hwif->name, stat, count);
- }
- }
-}
-
-/**
- * ide_intr - default IDE interrupt handler
- * @irq: interrupt number
- * @dev_id: hwif
- * @regs: unused weirdness from the kernel irq layer
- *
- * This is the default IRQ handler for the IDE layer. You should
- * not need to override it. If you do be aware it is subtle in
- * places
- *
- * hwif is the interface in the group currently performing
- * a command. hwif->cur_dev is the drive and hwif->handler is
- * the IRQ handler to call. As we issue a command the handlers
- * step through multiple states, reassigning the handler to the
- * next step in the process. Unlike a smart SCSI controller IDE
- * expects the main processor to sequence the various transfer
- * stages. We also manage a poll timer to catch up with most
- * timeout situations. There are still a few where the handlers
- * don't ever decide to give up.
- *
- * The handler eventually returns ide_stopped to indicate the
- * request completed. At this point we issue the next request
- * on the port and the process begins again.
- */
-
-irqreturn_t ide_intr (int irq, void *dev_id)
-{
- ide_hwif_t *hwif = (ide_hwif_t *)dev_id;
- struct ide_host *host = hwif->host;
- ide_drive_t *drive;
- ide_handler_t *handler;
- unsigned long flags;
- ide_startstop_t startstop;
- irqreturn_t irq_ret = IRQ_NONE;
- int plug_device = 0;
- struct request *rq_in_flight;
-
- if (host->host_flags & IDE_HFLAG_SERIALIZE) {
- if (hwif != host->cur_port)
- goto out_early;
- }
-
- spin_lock_irqsave(&hwif->lock, flags);
-
- if (hwif->port_ops && hwif->port_ops->test_irq &&
- hwif->port_ops->test_irq(hwif) == 0)
- goto out;
-
- handler = hwif->handler;
-
- if (handler == NULL || hwif->polling) {
- /*
- * Not expecting an interrupt from this drive.
- * That means this could be:
- * (1) an interrupt from another PCI device
- * sharing the same PCI INT# as us.
- * or (2) a drive just entered sleep or standby mode,
- * and is interrupting to let us know.
- * or (3) a spurious interrupt of unknown origin.
- *
- * For PCI, we cannot tell the difference,
- * so in that case we just ignore it and hope it goes away.
- */
- if ((host->irq_flags & IRQF_SHARED) == 0) {
- /*
- * Probably not a shared PCI interrupt,
- * so we can safely try to do something about it:
- */
- unexpected_intr(irq, hwif);
- } else {
- /*
- * Whack the status register, just in case
- * we have a leftover pending IRQ.
- */
- (void)hwif->tp_ops->read_status(hwif);
- }
- goto out;
- }
-
- drive = hwif->cur_dev;
-
- if (!drive_is_ready(drive))
- /*
- * This happens regularly when we share a PCI IRQ with
- * another device. Unfortunately, it can also happen
- * with some buggy drives that trigger the IRQ before
- * their status register is up to date. Hopefully we have
- * enough advance overhead that the latter isn't a problem.
- */
- goto out;
-
- hwif->handler = NULL;
- hwif->expiry = NULL;
- hwif->req_gen++;
- del_timer(&hwif->timer);
- spin_unlock(&hwif->lock);
-
- if (hwif->port_ops && hwif->port_ops->clear_irq)
- hwif->port_ops->clear_irq(drive);
-
- if (drive->dev_flags & IDE_DFLAG_UNMASK)
- local_irq_enable_in_hardirq();
-
- /* service this interrupt, may set handler for next interrupt */
- startstop = handler(drive);
-
- spin_lock_irq(&hwif->lock);
- /*
- * Note that handler() may have set things up for another
- * interrupt to occur soon, but it cannot happen until
- * we exit from this routine, because it will be the
- * same irq as is currently being serviced here, and Linux
- * won't allow another of the same (on any CPU) until we return.
- */
- if (startstop == ide_stopped && hwif->polling == 0) {
- BUG_ON(hwif->handler);
- rq_in_flight = hwif->rq;
- hwif->rq = NULL;
- ide_unlock_port(hwif);
- plug_device = 1;
- }
- irq_ret = IRQ_HANDLED;
-out:
- spin_unlock_irqrestore(&hwif->lock, flags);
-out_early:
- if (plug_device) {
- ide_unlock_host(hwif->host);
- ide_requeue_and_plug(drive, rq_in_flight);
- }
-
- return irq_ret;
-}
-EXPORT_SYMBOL_GPL(ide_intr);
-
-void ide_pad_transfer(ide_drive_t *drive, int write, int len)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 buf[4] = { 0 };
-
- while (len > 0) {
- if (write)
- hwif->tp_ops->output_data(drive, NULL, buf, min(4, len));
- else
- hwif->tp_ops->input_data(drive, NULL, buf, min(4, len));
- len -= 4;
- }
-}
-EXPORT_SYMBOL_GPL(ide_pad_transfer);
-
-void ide_insert_request_head(ide_drive_t *drive, struct request *rq)
-{
- drive->sense_rq_active = true;
- list_add_tail(&rq->queuelist, &drive->rq_list);
- kblockd_schedule_work(&drive->rq_work);
-}
-EXPORT_SYMBOL_GPL(ide_insert_request_head);
diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c
deleted file mode 100644
index 43fbc37d85c3..000000000000
--- a/drivers/ide/ide-ioctls.c
+++ /dev/null
@@ -1,306 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * IDE ioctls handling.
- */
-
-#include <linux/compat.h>
-#include <linux/export.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/slab.h>
-
-static int put_user_long(long val, unsigned long arg)
-{
- if (in_compat_syscall())
- return put_user(val, (compat_long_t __user *)compat_ptr(arg));
-
- return put_user(val, (long __user *)arg);
-}
-
-static const struct ide_ioctl_devset ide_ioctl_settings[] = {
-{ HDIO_GET_32BIT, HDIO_SET_32BIT, &ide_devset_io_32bit },
-{ HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, &ide_devset_keepsettings },
-{ HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, &ide_devset_unmaskirq },
-{ HDIO_GET_DMA, HDIO_SET_DMA, &ide_devset_using_dma },
-{ -1, HDIO_SET_PIO_MODE, &ide_devset_pio_mode },
-{ 0 }
-};
-
-int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev,
- unsigned int cmd, unsigned long arg,
- const struct ide_ioctl_devset *s)
-{
- const struct ide_devset *ds;
- int err = -EOPNOTSUPP;
-
- for (; (ds = s->setting); s++) {
- if (ds->get && s->get_ioctl == cmd)
- goto read_val;
- else if (ds->set && s->set_ioctl == cmd)
- goto set_val;
- }
-
- return err;
-
-read_val:
- mutex_lock(&ide_setting_mtx);
- err = ds->get(drive);
- mutex_unlock(&ide_setting_mtx);
- return err >= 0 ? put_user_long(err, arg) : err;
-
-set_val:
- if (bdev_is_partition(bdev))
- err = -EINVAL;
- else {
- if (!capable(CAP_SYS_ADMIN))
- err = -EACCES;
- else {
- mutex_lock(&ide_setting_mtx);
- err = ide_devset_execute(drive, ds, arg);
- mutex_unlock(&ide_setting_mtx);
- }
- }
- return err;
-}
-EXPORT_SYMBOL_GPL(ide_setting_ioctl);
-
-static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
- void __user *argp)
-{
- u16 *id = NULL;
- int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142;
- int rc = 0;
-
- if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
- rc = -ENOMSG;
- goto out;
- }
-
- /* ata_id_to_hd_driveid() relies on 'id' to be fully allocated. */
- id = kmalloc(ATA_ID_WORDS * 2, GFP_KERNEL);
- if (id == NULL) {
- rc = -ENOMEM;
- goto out;
- }
-
- memcpy(id, drive->id, size);
- ata_id_to_hd_driveid(id);
-
- if (copy_to_user(argp, id, size))
- rc = -EFAULT;
-
- kfree(id);
-out:
- return rc;
-}
-
-static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg)
-{
- return put_user_long((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)
- << IDE_NICE_DSC_OVERLAP) |
- (!!(drive->dev_flags & IDE_DFLAG_NICE1)
- << IDE_NICE_1), arg);
-}
-
-static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
-{
- if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
- return -EPERM;
-
- if (((arg >> IDE_NICE_DSC_OVERLAP) & 1) &&
- (drive->media != ide_tape))
- return -EPERM;
-
- if ((arg >> IDE_NICE_DSC_OVERLAP) & 1)
- drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
- else
- drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
-
- if ((arg >> IDE_NICE_1) & 1)
- drive->dev_flags |= IDE_DFLAG_NICE1;
- else
- drive->dev_flags &= ~IDE_DFLAG_NICE1;
-
- return 0;
-}
-
-static int ide_cmd_ioctl(ide_drive_t *drive, void __user *argp)
-{
- u8 *buf = NULL;
- int bufsize = 0, err = 0;
- u8 args[4], xfer_rate = 0;
- struct ide_cmd cmd;
- struct ide_taskfile *tf = &cmd.tf;
-
- if (NULL == argp) {
- struct request *rq;
-
- rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
- ide_req(rq)->type = ATA_PRIV_TASKFILE;
- blk_execute_rq(NULL, rq, 0);
- err = scsi_req(rq)->result ? -EIO : 0;
- blk_put_request(rq);
-
- return err;
- }
-
- if (copy_from_user(args, argp, 4))
- return -EFAULT;
-
- memset(&cmd, 0, sizeof(cmd));
- tf->feature = args[2];
- if (args[0] == ATA_CMD_SMART) {
- tf->nsect = args[3];
- tf->lbal = args[1];
- tf->lbam = ATA_SMART_LBAM_PASS;
- tf->lbah = ATA_SMART_LBAH_PASS;
- cmd.valid.out.tf = IDE_VALID_OUT_TF;
- cmd.valid.in.tf = IDE_VALID_NSECT;
- } else {
- tf->nsect = args[1];
- cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT;
- cmd.valid.in.tf = IDE_VALID_NSECT;
- }
- tf->command = args[0];
- cmd.protocol = args[3] ? ATA_PROT_PIO : ATA_PROT_NODATA;
-
- if (args[3]) {
- cmd.tf_flags |= IDE_TFLAG_IO_16BIT;
- bufsize = SECTOR_SIZE * args[3];
- buf = kzalloc(bufsize, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
- }
-
- if (tf->command == ATA_CMD_SET_FEATURES &&
- tf->feature == SETFEATURES_XFER &&
- tf->nsect >= XFER_SW_DMA_0) {
- xfer_rate = ide_find_dma_mode(drive, tf->nsect);
- if (xfer_rate != tf->nsect) {
- err = -EINVAL;
- goto abort;
- }
-
- cmd.tf_flags |= IDE_TFLAG_SET_XFER;
- }
-
- err = ide_raw_taskfile(drive, &cmd, buf, args[3]);
-
- args[0] = tf->status;
- args[1] = tf->error;
- args[2] = tf->nsect;
-abort:
- if (copy_to_user(argp, &args, 4))
- err = -EFAULT;
- if (buf) {
- if (copy_to_user((argp + 4), buf, bufsize))
- err = -EFAULT;
- kfree(buf);
- }
- return err;
-}
-
-static int ide_task_ioctl(ide_drive_t *drive, void __user *p)
-{
- int err = 0;
- u8 args[7];
- struct ide_cmd cmd;
-
- if (copy_from_user(args, p, 7))
- return -EFAULT;
-
- memset(&cmd, 0, sizeof(cmd));
- memcpy(&cmd.tf.feature, &args[1], 6);
- cmd.tf.command = args[0];
- cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
-
- err = ide_no_data_taskfile(drive, &cmd);
-
- args[0] = cmd.tf.command;
- memcpy(&args[1], &cmd.tf.feature, 6);
-
- if (copy_to_user(p, args, 7))
- err = -EFAULT;
-
- return err;
-}
-
-static int generic_drive_reset(ide_drive_t *drive)
-{
- struct request *rq;
- int ret = 0;
-
- rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
- ide_req(rq)->type = ATA_PRIV_MISC;
- scsi_req(rq)->cmd_len = 1;
- scsi_req(rq)->cmd[0] = REQ_DRIVE_RESET;
- blk_execute_rq(NULL, rq, 1);
- ret = scsi_req(rq)->result;
- blk_put_request(rq);
- return ret;
-}
-
-int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
- unsigned int cmd, unsigned long arg)
-{
- int err;
- void __user *argp = (void __user *)arg;
-
- if (in_compat_syscall())
- argp = compat_ptr(arg);
-
- err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings);
- if (err != -EOPNOTSUPP)
- return err;
-
- switch (cmd) {
- case HDIO_OBSOLETE_IDENTITY:
- case HDIO_GET_IDENTITY:
- if (bdev_is_partition(bdev))
- return -EINVAL;
- return ide_get_identity_ioctl(drive, cmd, argp);
- case HDIO_GET_NICE:
- return ide_get_nice_ioctl(drive, arg);
- case HDIO_SET_NICE:
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- return ide_set_nice_ioctl(drive, arg);
-#ifdef CONFIG_IDE_TASK_IOCTL
- case HDIO_DRIVE_TASKFILE:
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
- return -EACCES;
- /* missing compat handler for HDIO_DRIVE_TASKFILE */
- if (in_compat_syscall())
- return -ENOTTY;
- if (drive->media == ide_disk)
- return ide_taskfile_ioctl(drive, arg);
- return -ENOMSG;
-#endif
- case HDIO_DRIVE_CMD:
- if (!capable(CAP_SYS_RAWIO))
- return -EACCES;
- return ide_cmd_ioctl(drive, argp);
- case HDIO_DRIVE_TASK:
- if (!capable(CAP_SYS_RAWIO))
- return -EACCES;
- return ide_task_ioctl(drive, argp);
- case HDIO_DRIVE_RESET:
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- return generic_drive_reset(drive);
- case HDIO_GET_BUSSTATE:
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- if (put_user_long(BUSSTATE_ON, arg))
- return -EFAULT;
- return 0;
- case HDIO_SET_BUSSTATE:
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- return -EOPNOTSUPP;
- default:
- return -EINVAL;
- }
-}
-EXPORT_SYMBOL(generic_ide_ioctl);
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
deleted file mode 100644
index f2be127ee96e..000000000000
--- a/drivers/ide/ide-iops.c
+++ /dev/null
@@ -1,536 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2003 Red Hat
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/blkpg.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/bitops.h>
-#include <linux/nmi.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <linux/uaccess.h>
-#include <asm/io.h>
-
-void SELECT_MASK(ide_drive_t *drive, int mask)
-{
- const struct ide_port_ops *port_ops = drive->hwif->port_ops;
-
- if (port_ops && port_ops->maskproc)
- port_ops->maskproc(drive, mask);
-}
-
-u8 ide_read_error(ide_drive_t *drive)
-{
- struct ide_taskfile tf;
-
- drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_ERROR);
-
- return tf.error;
-}
-EXPORT_SYMBOL_GPL(ide_read_error);
-
-void ide_fix_driveid(u16 *id)
-{
-#ifndef __LITTLE_ENDIAN
-# ifdef __BIG_ENDIAN
- int i;
-
- for (i = 0; i < 256; i++)
- id[i] = __le16_to_cpu(id[i]);
-# else
-# error "Please fix <asm/byteorder.h>"
-# endif
-#endif
-}
-
-/*
- * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
- * removing leading/trailing blanks and compressing internal blanks.
- * It is primarily used to tidy up the model name/number fields as
- * returned by the ATA_CMD_ID_ATA[PI] commands.
- */
-
-void ide_fixstring(u8 *s, const int bytecount, const int byteswap)
-{
- u8 *p, *end = &s[bytecount & ~1]; /* bytecount must be even */
-
- if (byteswap) {
- /* convert from big-endian to host byte order */
- for (p = s ; p != end ; p += 2)
- be16_to_cpus((u16 *) p);
- }
-
- /* strip leading blanks */
- p = s;
- while (s != end && *s == ' ')
- ++s;
- /* compress internal blanks and strip trailing blanks */
- while (s != end && *s) {
- if (*s++ != ' ' || (s != end && *s && *s != ' '))
- *p++ = *(s-1);
- }
- /* wipe out trailing garbage */
- while (p != end)
- *p++ = '\0';
-}
-EXPORT_SYMBOL(ide_fixstring);
-
-/*
- * This routine busy-waits for the drive status to be not "busy".
- * It then checks the status for all of the "good" bits and none
- * of the "bad" bits, and if all is okay it returns 0. All other
- * cases return error -- caller may then invoke ide_error().
- *
- * This routine should get fixed to not hog the cpu during extra long waits..
- * That could be done by busy-waiting for the first jiffy or two, and then
- * setting a timer to wake up at half second intervals thereafter,
- * until timeout is achieved, before timing out.
- */
-int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad,
- unsigned long timeout, u8 *rstat)
-{
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_tp_ops *tp_ops = hwif->tp_ops;
- unsigned long flags;
- bool irqs_threaded = force_irqthreads;
- int i;
- u8 stat;
-
- udelay(1); /* spec allows drive 400ns to assert "BUSY" */
- stat = tp_ops->read_status(hwif);
-
- if (stat & ATA_BUSY) {
- if (!irqs_threaded) {
- local_save_flags(flags);
- local_irq_enable_in_hardirq();
- }
- timeout += jiffies;
- while ((stat = tp_ops->read_status(hwif)) & ATA_BUSY) {
- if (time_after(jiffies, timeout)) {
- /*
- * One last read after the timeout in case
- * heavy interrupt load made us not make any
- * progress during the timeout..
- */
- stat = tp_ops->read_status(hwif);
- if ((stat & ATA_BUSY) == 0)
- break;
-
- if (!irqs_threaded)
- local_irq_restore(flags);
- *rstat = stat;
- return -EBUSY;
- }
- }
- if (!irqs_threaded)
- local_irq_restore(flags);
- }
- /*
- * Allow status to settle, then read it again.
- * A few rare drives vastly violate the 400ns spec here,
- * so we'll wait up to 10usec for a "good" status
- * rather than expensively fail things immediately.
- * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
- */
- for (i = 0; i < 10; i++) {
- udelay(1);
- stat = tp_ops->read_status(hwif);
-
- if (OK_STAT(stat, good, bad)) {
- *rstat = stat;
- return 0;
- }
- }
- *rstat = stat;
- return -EFAULT;
-}
-
-/*
- * In case of error returns error value after doing "*startstop = ide_error()".
- * The caller should return the updated value of "startstop" in this case,
- * "startstop" is unchanged when the function returns 0.
- */
-int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, u8 good,
- u8 bad, unsigned long timeout)
-{
- int err;
- u8 stat;
-
- /* bail early if we've exceeded max_failures */
- if (drive->max_failures && (drive->failures > drive->max_failures)) {
- *startstop = ide_stopped;
- return 1;
- }
-
- err = __ide_wait_stat(drive, good, bad, timeout, &stat);
-
- if (err) {
- char *s = (err == -EBUSY) ? "status timeout" : "status error";
- *startstop = ide_error(drive, s, stat);
- }
-
- return err;
-}
-EXPORT_SYMBOL(ide_wait_stat);
-
-/**
- * ide_in_drive_list - look for drive in black/white list
- * @id: drive identifier
- * @table: list to inspect
- *
- * Look for a drive in the blacklist and the whitelist tables
- * Returns 1 if the drive is found in the table.
- */
-
-int ide_in_drive_list(u16 *id, const struct drive_list_entry *table)
-{
- for ( ; table->id_model; table++)
- if ((!strcmp(table->id_model, (char *)&id[ATA_ID_PROD])) &&
- (!table->id_firmware ||
- strstr((char *)&id[ATA_ID_FW_REV], table->id_firmware)))
- return 1;
- return 0;
-}
-EXPORT_SYMBOL_GPL(ide_in_drive_list);
-
-/*
- * Early UDMA66 devices don't set bit14 to 1, only bit13 is valid.
- * Some optical devices with the buggy firmwares have the same problem.
- */
-static const struct drive_list_entry ivb_list[] = {
- { "QUANTUM FIREBALLlct10 05" , "A03.0900" },
- { "QUANTUM FIREBALLlct20 30" , "APL.0900" },
- { "TSSTcorp CDDVDW SH-S202J" , "SB00" },
- { "TSSTcorp CDDVDW SH-S202J" , "SB01" },
- { "TSSTcorp CDDVDW SH-S202N" , "SB00" },
- { "TSSTcorp CDDVDW SH-S202N" , "SB01" },
- { "TSSTcorp CDDVDW SH-S202H" , "SB00" },
- { "TSSTcorp CDDVDW SH-S202H" , "SB01" },
- { "SAMSUNG SP0822N" , "WA100-10" },
- { NULL , NULL }
-};
-
-/*
- * All hosts that use the 80c ribbon must use!
- * The name is derived from upper byte of word 93 and the 80c ribbon.
- */
-u8 eighty_ninty_three(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u16 *id = drive->id;
- int ivb = ide_in_drive_list(id, ivb_list);
-
- if (hwif->cbl == ATA_CBL_SATA || hwif->cbl == ATA_CBL_PATA40_SHORT)
- return 1;
-
- if (ivb)
- printk(KERN_DEBUG "%s: skipping word 93 validity check\n",
- drive->name);
-
- if (ata_id_is_sata(id) && !ivb)
- return 1;
-
- if (hwif->cbl != ATA_CBL_PATA80 && !ivb)
- goto no_80w;
-
- /*
- * FIXME:
- * - change master/slave IDENTIFY order
- * - force bit13 (80c cable present) check also for !ivb devices
- * (unless the slave device is pre-ATA3)
- */
- if (id[ATA_ID_HW_CONFIG] & 0x4000)
- return 1;
-
- if (ivb) {
- const char *model = (char *)&id[ATA_ID_PROD];
-
- if (strstr(model, "TSSTcorp CDDVDW SH-S202")) {
- /*
- * These ATAPI devices always report 80c cable
- * so we have to depend on the host in this case.
- */
- if (hwif->cbl == ATA_CBL_PATA80)
- return 1;
- } else {
- /* Depend on the device side cable detection. */
- if (id[ATA_ID_HW_CONFIG] & 0x2000)
- return 1;
- }
- }
-no_80w:
- if (drive->dev_flags & IDE_DFLAG_UDMA33_WARNED)
- return 0;
-
- printk(KERN_WARNING "%s: %s side 80-wire cable detection failed, "
- "limiting max speed to UDMA33\n",
- drive->name,
- hwif->cbl == ATA_CBL_PATA80 ? "drive" : "host");
-
- drive->dev_flags |= IDE_DFLAG_UDMA33_WARNED;
-
- return 0;
-}
-
-static const char *nien_quirk_list[] = {
- "QUANTUM FIREBALLlct08 08",
- "QUANTUM FIREBALLP KA6.4",
- "QUANTUM FIREBALLP KA9.1",
- "QUANTUM FIREBALLP KX13.6",
- "QUANTUM FIREBALLP KX20.5",
- "QUANTUM FIREBALLP KX27.3",
- "QUANTUM FIREBALLP LM20.4",
- "QUANTUM FIREBALLP LM20.5",
- "FUJITSU MHZ2160BH G2",
- NULL
-};
-
-void ide_check_nien_quirk_list(ide_drive_t *drive)
-{
- const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
-
- for (list = nien_quirk_list; *list != NULL; list++)
- if (strstr(m, *list) != NULL) {
- drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK;
- return;
- }
-}
-
-int ide_driveid_update(ide_drive_t *drive)
-{
- u16 *id;
- int rc;
-
- id = kmalloc(SECTOR_SIZE, GFP_ATOMIC);
- if (id == NULL)
- return 0;
-
- SELECT_MASK(drive, 1);
- rc = ide_dev_read_id(drive, ATA_CMD_ID_ATA, id, 1);
- SELECT_MASK(drive, 0);
-
- if (rc)
- goto out_err;
-
- drive->id[ATA_ID_UDMA_MODES] = id[ATA_ID_UDMA_MODES];
- drive->id[ATA_ID_MWDMA_MODES] = id[ATA_ID_MWDMA_MODES];
- drive->id[ATA_ID_SWDMA_MODES] = id[ATA_ID_SWDMA_MODES];
- drive->id[ATA_ID_CFA_MODES] = id[ATA_ID_CFA_MODES];
- /* anything more ? */
-
- kfree(id);
-
- return 1;
-out_err:
- if (rc == 2)
- printk(KERN_ERR "%s: %s: bad status\n", drive->name, __func__);
- kfree(id);
- return 0;
-}
-
-int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
-{
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_tp_ops *tp_ops = hwif->tp_ops;
- struct ide_taskfile tf;
- u16 *id = drive->id, i;
- int error = 0;
- u8 stat;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
- if (hwif->dma_ops) /* check if host supports DMA */
- hwif->dma_ops->dma_host_set(drive, 0);
-#endif
-
- /* Skip setting PIO flow-control modes on pre-EIDE drives */
- if ((speed & 0xf8) == XFER_PIO_0 && ata_id_has_iordy(drive->id) == 0)
- goto skip;
-
- /*
- * Don't use ide_wait_cmd here - it will
- * attempt to set_geometry and recalibrate,
- * but for some reason these don't work at
- * this point (lost interrupt).
- */
-
- udelay(1);
- tp_ops->dev_select(drive);
- SELECT_MASK(drive, 1);
- udelay(1);
- tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS);
-
- memset(&tf, 0, sizeof(tf));
- tf.feature = SETFEATURES_XFER;
- tf.nsect = speed;
-
- tp_ops->tf_load(drive, &tf, IDE_VALID_FEATURE | IDE_VALID_NSECT);
-
- tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES);
-
- if (drive->dev_flags & IDE_DFLAG_NIEN_QUIRK)
- tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
-
- error = __ide_wait_stat(drive, drive->ready_stat,
- ATA_BUSY | ATA_DRQ | ATA_ERR,
- WAIT_CMD, &stat);
-
- SELECT_MASK(drive, 0);
-
- if (error) {
- (void) ide_dump_status(drive, "set_drive_speed_status", stat);
- return error;
- }
-
- if (speed >= XFER_SW_DMA_0) {
- id[ATA_ID_UDMA_MODES] &= ~0xFF00;
- id[ATA_ID_MWDMA_MODES] &= ~0x0700;
- id[ATA_ID_SWDMA_MODES] &= ~0x0700;
- if (ata_id_is_cfa(id))
- id[ATA_ID_CFA_MODES] &= ~0x0E00;
- } else if (ata_id_is_cfa(id))
- id[ATA_ID_CFA_MODES] &= ~0x01C0;
-
- skip:
-#ifdef CONFIG_BLK_DEV_IDEDMA
- if (speed >= XFER_SW_DMA_0 && (drive->dev_flags & IDE_DFLAG_USING_DMA))
- hwif->dma_ops->dma_host_set(drive, 1);
- else if (hwif->dma_ops) /* check if host supports DMA */
- ide_dma_off_quietly(drive);
-#endif
-
- if (speed >= XFER_UDMA_0) {
- i = 1 << (speed - XFER_UDMA_0);
- id[ATA_ID_UDMA_MODES] |= (i << 8 | i);
- } else if (ata_id_is_cfa(id) && speed >= XFER_MW_DMA_3) {
- i = speed - XFER_MW_DMA_2;
- id[ATA_ID_CFA_MODES] |= i << 9;
- } else if (speed >= XFER_MW_DMA_0) {
- i = 1 << (speed - XFER_MW_DMA_0);
- id[ATA_ID_MWDMA_MODES] |= (i << 8 | i);
- } else if (speed >= XFER_SW_DMA_0) {
- i = 1 << (speed - XFER_SW_DMA_0);
- id[ATA_ID_SWDMA_MODES] |= (i << 8 | i);
- } else if (ata_id_is_cfa(id) && speed >= XFER_PIO_5) {
- i = speed - XFER_PIO_4;
- id[ATA_ID_CFA_MODES] |= i << 6;
- }
-
- if (!drive->init_speed)
- drive->init_speed = speed;
- drive->current_speed = speed;
- return error;
-}
-
-/*
- * This should get invoked any time we exit the driver to
- * wait for an interrupt response from a drive. handler() points
- * at the appropriate code to handle the next interrupt, and a
- * timer is started to prevent us from waiting forever in case
- * something goes wrong (see the ide_timer_expiry() handler later on).
- *
- * See also ide_execute_command
- */
-void __ide_set_handler(ide_drive_t *drive, ide_handler_t *handler,
- unsigned int timeout)
-{
- ide_hwif_t *hwif = drive->hwif;
-
- BUG_ON(hwif->handler);
- hwif->handler = handler;
- hwif->timer.expires = jiffies + timeout;
- hwif->req_gen_timer = hwif->req_gen;
- add_timer(&hwif->timer);
-}
-
-void ide_set_handler(ide_drive_t *drive, ide_handler_t *handler,
- unsigned int timeout)
-{
- ide_hwif_t *hwif = drive->hwif;
- unsigned long flags;
-
- spin_lock_irqsave(&hwif->lock, flags);
- __ide_set_handler(drive, handler, timeout);
- spin_unlock_irqrestore(&hwif->lock, flags);
-}
-EXPORT_SYMBOL(ide_set_handler);
-
-/**
- * ide_execute_command - execute an IDE command
- * @drive: IDE drive to issue the command against
- * @cmd: command
- * @handler: handler for next phase
- * @timeout: timeout for command
- *
- * Helper function to issue an IDE command. This handles the
- * atomicity requirements, command timing and ensures that the
- * handler and IRQ setup do not race. All IDE command kick off
- * should go via this function or do equivalent locking.
- */
-
-void ide_execute_command(ide_drive_t *drive, struct ide_cmd *cmd,
- ide_handler_t *handler, unsigned timeout)
-{
- ide_hwif_t *hwif = drive->hwif;
- unsigned long flags;
-
- spin_lock_irqsave(&hwif->lock, flags);
- if ((cmd->protocol != ATAPI_PROT_DMA &&
- cmd->protocol != ATAPI_PROT_PIO) ||
- (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT))
- __ide_set_handler(drive, handler, timeout);
- hwif->tp_ops->exec_command(hwif, cmd->tf.command);
- /*
- * Drive takes 400nS to respond, we must avoid the IRQ being
- * serviced before that.
- *
- * FIXME: we could skip this delay with care on non shared devices
- */
- ndelay(400);
- spin_unlock_irqrestore(&hwif->lock, flags);
-}
-
-/*
- * ide_wait_not_busy() waits for the currently selected device on the hwif
- * to report a non-busy status, see comments in ide_probe_port().
- */
-int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
-{
- u8 stat = 0;
-
- while (timeout--) {
- /*
- * Turn this into a schedule() sleep once I'm sure
- * about locking issues (2.5 work ?).
- */
- mdelay(1);
- stat = hwif->tp_ops->read_status(hwif);
- if ((stat & ATA_BUSY) == 0)
- return 0;
- /*
- * Assume a value of 0xff means nothing is connected to
- * the interface and it doesn't implement the pull-down
- * resistor on D7.
- */
- if (stat == 0xff)
- return -ENODEV;
- touch_nmi_watchdog();
- }
- return -EBUSY;
-}
diff --git a/drivers/ide/ide-legacy.c b/drivers/ide/ide-legacy.c
deleted file mode 100644
index be65b411ab53..000000000000
--- a/drivers/ide/ide-legacy.c
+++ /dev/null
@@ -1,59 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/ide.h>
-
-static void ide_legacy_init_one(struct ide_hw **hws, struct ide_hw *hw,
- u8 port_no, const struct ide_port_info *d,
- unsigned long config)
-{
- unsigned long base, ctl;
- int irq;
-
- if (port_no == 0) {
- base = 0x1f0;
- ctl = 0x3f6;
- irq = 14;
- } else {
- base = 0x170;
- ctl = 0x376;
- irq = 15;
- }
-
- if (!request_region(base, 8, d->name)) {
- printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
- d->name, base, base + 7);
- return;
- }
-
- if (!request_region(ctl, 1, d->name)) {
- printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
- d->name, ctl);
- release_region(base, 8);
- return;
- }
-
- ide_std_init_ports(hw, base, ctl);
- hw->irq = irq;
- hw->config = config;
-
- hws[port_no] = hw;
-}
-
-int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config)
-{
- struct ide_hw hw[2], *hws[] = { NULL, NULL };
-
- memset(&hw, 0, sizeof(hw));
-
- if ((d->host_flags & IDE_HFLAG_QD_2ND_PORT) == 0)
- ide_legacy_init_one(hws, &hw[0], 0, d, config);
- ide_legacy_init_one(hws, &hw[1], 1, d, config);
-
- if (hws[0] == NULL && hws[1] == NULL &&
- (d->host_flags & IDE_HFLAG_SINGLE))
- return -ENOENT;
-
- return ide_host_add(d, hws, 2, NULL);
-}
-EXPORT_SYMBOL_GPL(ide_legacy_device_add);
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
deleted file mode 100644
index 7b9f655adbc2..000000000000
--- a/drivers/ide/ide-lib.c
+++ /dev/null
@@ -1,146 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/interrupt.h>
-#include <linux/ide.h>
-#include <linux/bitops.h>
-
-u64 ide_get_lba_addr(struct ide_cmd *cmd, int lba48)
-{
- struct ide_taskfile *tf = &cmd->tf;
- u32 high, low;
-
- low = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal;
- if (lba48) {
- tf = &cmd->hob;
- high = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal;
- } else
- high = tf->device & 0xf;
-
- return ((u64)high << 24) | low;
-}
-EXPORT_SYMBOL_GPL(ide_get_lba_addr);
-
-static void ide_dump_sector(ide_drive_t *drive)
-{
- struct ide_cmd cmd;
- struct ide_taskfile *tf = &cmd.tf;
- u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48);
-
- memset(&cmd, 0, sizeof(cmd));
- if (lba48) {
- cmd.valid.in.tf = IDE_VALID_LBA;
- cmd.valid.in.hob = IDE_VALID_LBA;
- cmd.tf_flags = IDE_TFLAG_LBA48;
- } else
- cmd.valid.in.tf = IDE_VALID_LBA | IDE_VALID_DEVICE;
-
- ide_tf_readback(drive, &cmd);
-
- if (lba48 || (tf->device & ATA_LBA))
- printk(KERN_CONT ", LBAsect=%llu",
- (unsigned long long)ide_get_lba_addr(&cmd, lba48));
- else
- printk(KERN_CONT ", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam,
- tf->device & 0xf, tf->lbal);
-}
-
-static void ide_dump_ata_error(ide_drive_t *drive, u8 err)
-{
- printk(KERN_CONT "{ ");
- if (err & ATA_ABORTED)
- printk(KERN_CONT "DriveStatusError ");
- if (err & ATA_ICRC)
- printk(KERN_CONT "%s",
- (err & ATA_ABORTED) ? "BadCRC " : "BadSector ");
- if (err & ATA_UNC)
- printk(KERN_CONT "UncorrectableError ");
- if (err & ATA_IDNF)
- printk(KERN_CONT "SectorIdNotFound ");
- if (err & ATA_TRK0NF)
- printk(KERN_CONT "TrackZeroNotFound ");
- if (err & ATA_AMNF)
- printk(KERN_CONT "AddrMarkNotFound ");
- printk(KERN_CONT "}");
- if ((err & (ATA_BBK | ATA_ABORTED)) == ATA_BBK ||
- (err & (ATA_UNC | ATA_IDNF | ATA_AMNF))) {
- struct request *rq = drive->hwif->rq;
-
- ide_dump_sector(drive);
-
- if (rq)
- printk(KERN_CONT ", sector=%llu",
- (unsigned long long)blk_rq_pos(rq));
- }
- printk(KERN_CONT "\n");
-}
-
-static void ide_dump_atapi_error(ide_drive_t *drive, u8 err)
-{
- printk(KERN_CONT "{ ");
- if (err & ATAPI_ILI)
- printk(KERN_CONT "IllegalLengthIndication ");
- if (err & ATAPI_EOM)
- printk(KERN_CONT "EndOfMedia ");
- if (err & ATA_ABORTED)
- printk(KERN_CONT "AbortedCommand ");
- if (err & ATA_MCR)
- printk(KERN_CONT "MediaChangeRequested ");
- if (err & ATAPI_LFS)
- printk(KERN_CONT "LastFailedSense=0x%02x ",
- (err & ATAPI_LFS) >> 4);
- printk(KERN_CONT "}\n");
-}
-
-/**
- * ide_dump_status - translate ATA/ATAPI error
- * @drive: drive that status applies to
- * @msg: text message to print
- * @stat: status byte to decode
- *
- * Error reporting, in human readable form (luxurious, but a memory hog).
- * Combines the drive name, message and status byte to provide a
- * user understandable explanation of the device error.
- */
-
-u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
-{
- u8 err = 0;
-
- printk(KERN_ERR "%s: %s: status=0x%02x { ", drive->name, msg, stat);
- if (stat & ATA_BUSY)
- printk(KERN_CONT "Busy ");
- else {
- if (stat & ATA_DRDY)
- printk(KERN_CONT "DriveReady ");
- if (stat & ATA_DF)
- printk(KERN_CONT "DeviceFault ");
- if (stat & ATA_DSC)
- printk(KERN_CONT "SeekComplete ");
- if (stat & ATA_DRQ)
- printk(KERN_CONT "DataRequest ");
- if (stat & ATA_CORR)
- printk(KERN_CONT "CorrectedError ");
- if (stat & ATA_SENSE)
- printk(KERN_CONT "Sense ");
- if (stat & ATA_ERR)
- printk(KERN_CONT "Error ");
- }
- printk(KERN_CONT "}\n");
- if ((stat & (ATA_BUSY | ATA_ERR)) == ATA_ERR) {
- err = ide_read_error(drive);
- printk(KERN_ERR "%s: %s: error=0x%02x ", drive->name, msg, err);
- if (drive->media == ide_disk)
- ide_dump_ata_error(drive, err);
- else
- ide_dump_atapi_error(drive, err);
- }
-
- printk(KERN_ERR "%s: possibly failed opcode: 0x%02x\n",
- drive->name, drive->hwif->cmd.tf.command);
-
- return err;
-}
-EXPORT_SYMBOL(ide_dump_status);
diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c
deleted file mode 100644
index a80a0f28f7b9..000000000000
--- a/drivers/ide/ide-park.c
+++ /dev/null
@@ -1,155 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/ide.h>
-#include <linux/jiffies.h>
-#include <linux/blkdev.h>
-
-DECLARE_WAIT_QUEUE_HEAD(ide_park_wq);
-
-static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct request_queue *q = drive->queue;
- struct request *rq;
- int rc;
-
- timeout += jiffies;
- spin_lock_irq(&hwif->lock);
- if (drive->dev_flags & IDE_DFLAG_PARKED) {
- int reset_timer = time_before(timeout, drive->sleep);
- int start_queue = 0;
-
- drive->sleep = timeout;
- wake_up_all(&ide_park_wq);
- if (reset_timer && del_timer(&hwif->timer))
- start_queue = 1;
- spin_unlock_irq(&hwif->lock);
-
- if (start_queue)
- blk_mq_run_hw_queues(q, true);
- return;
- }
- spin_unlock_irq(&hwif->lock);
-
- rq = blk_get_request(q, REQ_OP_DRV_IN, 0);
- scsi_req(rq)->cmd[0] = REQ_PARK_HEADS;
- scsi_req(rq)->cmd_len = 1;
- ide_req(rq)->type = ATA_PRIV_MISC;
- ide_req(rq)->special = &timeout;
- blk_execute_rq(NULL, rq, 1);
- rc = scsi_req(rq)->result ? -EIO : 0;
- blk_put_request(rq);
- if (rc)
- goto out;
-
- /*
- * Make sure that *some* command is sent to the drive after the
- * timeout has expired, so power management will be reenabled.
- */
- rq = blk_get_request(q, REQ_OP_DRV_IN, BLK_MQ_REQ_NOWAIT);
- if (IS_ERR(rq))
- goto out;
-
- scsi_req(rq)->cmd[0] = REQ_UNPARK_HEADS;
- scsi_req(rq)->cmd_len = 1;
- ide_req(rq)->type = ATA_PRIV_MISC;
- spin_lock_irq(&hwif->lock);
- ide_insert_request_head(drive, rq);
- spin_unlock_irq(&hwif->lock);
-
-out:
- return;
-}
-
-ide_startstop_t ide_do_park_unpark(ide_drive_t *drive, struct request *rq)
-{
- struct ide_cmd cmd;
- struct ide_taskfile *tf = &cmd.tf;
-
- memset(&cmd, 0, sizeof(cmd));
- if (scsi_req(rq)->cmd[0] == REQ_PARK_HEADS) {
- drive->sleep = *(unsigned long *)ide_req(rq)->special;
- drive->dev_flags |= IDE_DFLAG_SLEEPING;
- tf->command = ATA_CMD_IDLEIMMEDIATE;
- tf->feature = 0x44;
- tf->lbal = 0x4c;
- tf->lbam = 0x4e;
- tf->lbah = 0x55;
- cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
- } else /* cmd == REQ_UNPARK_HEADS */
- tf->command = ATA_CMD_CHK_POWER;
-
- cmd.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER;
- cmd.protocol = ATA_PROT_NODATA;
-
- cmd.rq = rq;
-
- return do_rw_taskfile(drive, &cmd);
-}
-
-ssize_t ide_park_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- ide_drive_t *drive = to_ide_device(dev);
- ide_hwif_t *hwif = drive->hwif;
- unsigned long now;
- unsigned int msecs;
-
- if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
- return -EOPNOTSUPP;
-
- spin_lock_irq(&hwif->lock);
- now = jiffies;
- if (drive->dev_flags & IDE_DFLAG_PARKED &&
- time_after(drive->sleep, now))
- msecs = jiffies_to_msecs(drive->sleep - now);
- else
- msecs = 0;
- spin_unlock_irq(&hwif->lock);
-
- return snprintf(buf, 20, "%u\n", msecs);
-}
-
-ssize_t ide_park_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t len)
-{
-#define MAX_PARK_TIMEOUT 30000
- ide_drive_t *drive = to_ide_device(dev);
- long int input;
- int rc;
-
- rc = kstrtol(buf, 10, &input);
- if (rc)
- return rc;
- if (input < -2)
- return -EINVAL;
- if (input > MAX_PARK_TIMEOUT) {
- input = MAX_PARK_TIMEOUT;
- rc = -EOVERFLOW;
- }
-
- mutex_lock(&ide_setting_mtx);
- if (input >= 0) {
- if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
- rc = -EOPNOTSUPP;
- else if (input || drive->dev_flags & IDE_DFLAG_PARKED)
- issue_park_cmd(drive, msecs_to_jiffies(input));
- } else {
- if (drive->media == ide_disk)
- switch (input) {
- case -1:
- drive->dev_flags &= ~IDE_DFLAG_NO_UNLOAD;
- break;
- case -2:
- drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
- break;
- }
- else
- rc = -EOPNOTSUPP;
- }
- mutex_unlock(&ide_setting_mtx);
-
- return rc ? rc : len;
-}
diff --git a/drivers/ide/ide-pci-generic.c b/drivers/ide/ide-pci-generic.c
deleted file mode 100644
index 673420db953f..000000000000
--- a/drivers/ide/ide-pci-generic.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
- * Portions (C) Copyright 2002 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 as published by the
- * Free Software Foundation; either version 2, 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.
- *
- * For the avoidance of doubt the "preferred form" of this code is one which
- * is in an open non patent encumbered format. Where cryptographic key signing
- * forms part of the process of creating an executable the information
- * including keys needed to generate an equivalently functional executable
- * are deemed to be part of the source code.
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "ide_pci_generic"
-
-static bool ide_generic_all; /* Set to claim all devices */
-
-module_param_named(all_generic_ide, ide_generic_all, bool, 0444);
-MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers.");
-
-static void netcell_quirkproc(ide_drive_t *drive)
-{
- /* mark words 85-87 as valid */
- drive->id[ATA_ID_CSF_DEFAULT] |= 0x4000;
-}
-
-static const struct ide_port_ops netcell_port_ops = {
- .quirkproc = netcell_quirkproc,
-};
-
-#define DECLARE_GENERIC_PCI_DEV(extra_flags) \
- { \
- .name = DRV_NAME, \
- .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA | \
- extra_flags, \
- .swdma_mask = ATA_SWDMA2, \
- .mwdma_mask = ATA_MWDMA2, \
- .udma_mask = ATA_UDMA6, \
- }
-
-static const struct ide_port_info generic_chipsets[] = {
- /* 0: Unknown */
- DECLARE_GENERIC_PCI_DEV(0),
-
- { /* 1: NS87410 */
- .name = DRV_NAME,
- .enablebits = { {0x43, 0x08, 0x08}, {0x47, 0x08, 0x08} },
- .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA,
- .swdma_mask = ATA_SWDMA2,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA6,
- },
-
- /* 2: SAMURAI / HT6565 / HINT_IDE */
- DECLARE_GENERIC_PCI_DEV(0),
- /* 3: UM8673F / UM8886A / UM8886BF */
- DECLARE_GENERIC_PCI_DEV(IDE_HFLAG_NO_DMA),
- /* 4: VIA_IDE / OPTI621V / Piccolo010{2,3,5} */
- DECLARE_GENERIC_PCI_DEV(IDE_HFLAG_NO_AUTODMA),
-
- { /* 5: VIA8237SATA */
- .name = DRV_NAME,
- .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
- IDE_HFLAG_OFF_BOARD,
- .swdma_mask = ATA_SWDMA2,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA6,
- },
-
- { /* 6: Revolution */
- .name = DRV_NAME,
- .port_ops = &netcell_port_ops,
- .host_flags = IDE_HFLAG_CLEAR_SIMPLEX |
- IDE_HFLAG_TRUST_BIOS_FOR_DMA |
- IDE_HFLAG_OFF_BOARD,
- .swdma_mask = ATA_SWDMA2,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA6,
- }
-};
-
-/**
- * generic_init_one - called when a PIIX is found
- * @dev: the generic device
- * @id: the matching pci id
- *
- * Called when the PCI registration layer (or the IDE initialization)
- * finds a device matching our IDE device tables.
- */
-
-static int generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- const struct ide_port_info *d = &generic_chipsets[id->driver_data];
- int ret = -ENODEV;
-
- /* Don't use the generic entry unless instructed to do so */
- if (id->driver_data == 0 && ide_generic_all == 0)
- goto out;
-
- switch (dev->vendor) {
- case PCI_VENDOR_ID_UMC:
- if (dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
- !(PCI_FUNC(dev->devfn) & 1))
- goto out; /* UM8886A/BF pair */
- break;
- case PCI_VENDOR_ID_OPTI:
- if (dev->device == PCI_DEVICE_ID_OPTI_82C558 &&
- !(PCI_FUNC(dev->devfn) & 1))
- goto out;
- break;
- case PCI_VENDOR_ID_JMICRON:
- if (dev->device != PCI_DEVICE_ID_JMICRON_JMB368 &&
- PCI_FUNC(dev->devfn) != 1)
- goto out;
- break;
- case PCI_VENDOR_ID_NS:
- if (dev->device == PCI_DEVICE_ID_NS_87410 &&
- (dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
- goto out;
- break;
- }
-
- if (dev->vendor != PCI_VENDOR_ID_JMICRON) {
- u16 command;
- pci_read_config_word(dev, PCI_COMMAND, &command);
- if (!(command & PCI_COMMAND_IO)) {
- printk(KERN_INFO "%s %s: skipping disabled "
- "controller\n", d->name, pci_name(dev));
- goto out;
- }
- }
- ret = ide_pci_init_one(dev, d, NULL);
-out:
- return ret;
-}
-
-static const struct pci_device_id generic_pci_tbl[] = {
- { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87410), 1 },
- { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE), 2 },
- { PCI_VDEVICE(HOLTEK, PCI_DEVICE_ID_HOLTEK_6565), 2 },
- { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8673F), 3 },
- { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8886A), 3 },
- { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8886BF), 3 },
- { PCI_VDEVICE(HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE), 2 },
- { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C561), 4 },
- { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C558), 4 },
-#ifdef CONFIG_BLK_DEV_IDE_SATA
- { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_8237_SATA), 5 },
-#endif
- { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), 4 },
- { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), 4 },
- { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_3), 4 },
- { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_5), 4 },
- { PCI_VDEVICE(NETCELL, PCI_DEVICE_ID_REVOLUTION), 6 },
- /*
- * Must come last. If you add entries adjust
- * this table and generic_chipsets[] appropriately.
- */
- { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, generic_pci_tbl);
-
-static struct pci_driver generic_pci_driver = {
- .name = "PCI_IDE",
- .id_table = generic_pci_tbl,
- .probe = generic_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init generic_ide_init(void)
-{
- return ide_pci_register_driver(&generic_pci_driver);
-}
-
-static void __exit generic_ide_exit(void)
-{
- pci_unregister_driver(&generic_pci_driver);
-}
-
-module_init(generic_ide_init);
-module_exit(generic_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for generic PCI IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-pio-blacklist.c b/drivers/ide/ide-pio-blacklist.c
deleted file mode 100644
index 1fd24798e5c9..000000000000
--- a/drivers/ide/ide-pio-blacklist.c
+++ /dev/null
@@ -1,96 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * PIO blacklist. Some drives incorrectly report their maximal PIO mode,
- * at least in respect to CMD640. Here we keep info on some known drives.
- *
- * Changes to the ide_pio_blacklist[] should be made with EXTREME CAUTION
- * to avoid breaking the fragile cmd640.c support.
- */
-
-#include <linux/string.h>
-#include <linux/ide.h>
-
-static struct ide_pio_info {
- const char *name;
- int pio;
-} ide_pio_blacklist [] = {
- { "Conner Peripherals 540MB - CFS540A", 3 },
-
- { "WDC AC2700", 3 },
- { "WDC AC2540", 3 },
- { "WDC AC2420", 3 },
- { "WDC AC2340", 3 },
- { "WDC AC2250", 0 },
- { "WDC AC2200", 0 },
- { "WDC AC21200", 4 },
- { "WDC AC2120", 0 },
- { "WDC AC2850", 3 },
- { "WDC AC1270", 3 },
- { "WDC AC1170", 1 },
- { "WDC AC1210", 1 },
- { "WDC AC280", 0 },
- { "WDC AC31000", 3 },
- { "WDC AC31200", 3 },
-
- { "Maxtor 7131 AT", 1 },
- { "Maxtor 7171 AT", 1 },
- { "Maxtor 7213 AT", 1 },
- { "Maxtor 7245 AT", 1 },
- { "Maxtor 7345 AT", 1 },
- { "Maxtor 7546 AT", 3 },
- { "Maxtor 7540 AV", 3 },
-
- { "SAMSUNG SHD-3121A", 1 },
- { "SAMSUNG SHD-3122A", 1 },
- { "SAMSUNG SHD-3172A", 1 },
-
- { "ST5660A", 3 },
- { "ST3660A", 3 },
- { "ST3630A", 3 },
- { "ST3655A", 3 },
- { "ST3391A", 3 },
- { "ST3390A", 1 },
- { "ST3600A", 1 },
- { "ST3290A", 0 },
- { "ST3144A", 0 },
- { "ST3491A", 1 }, /* reports 3, should be 1 or 2 (depending on drive)
- according to Seagate's FIND-ATA program */
-
- { "QUANTUM ELS127A", 0 },
- { "QUANTUM ELS170A", 0 },
- { "QUANTUM LPS240A", 0 },
- { "QUANTUM LPS210A", 3 },
- { "QUANTUM LPS270A", 3 },
- { "QUANTUM LPS365A", 3 },
- { "QUANTUM LPS540A", 3 },
- { "QUANTUM LIGHTNING 540A", 3 },
- { "QUANTUM LIGHTNING 730A", 3 },
-
- { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
- { "QUANTUM FIREBALL_640", 3 },
- { "QUANTUM FIREBALL_1080", 3 },
- { "QUANTUM FIREBALL_1280", 3 },
- { NULL, 0 }
-};
-
-/**
- * ide_scan_pio_blacklist - check for a blacklisted drive
- * @model: Drive model string
- *
- * This routine searches the ide_pio_blacklist for an entry
- * matching the start/whole of the supplied model name.
- *
- * Returns -1 if no match found.
- * Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
- */
-
-int ide_scan_pio_blacklist(char *model)
-{
- struct ide_pio_info *p;
-
- for (p = ide_pio_blacklist; p->name != NULL; p++) {
- if (strncmp(p->name, model, strlen(p->name)) == 0)
- return p->pio;
- }
- return -1;
-}
diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c
deleted file mode 100644
index d680b3e3295f..000000000000
--- a/drivers/ide/ide-pm.c
+++ /dev/null
@@ -1,261 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/ide.h>
-
-int generic_ide_suspend(struct device *dev, pm_message_t mesg)
-{
- ide_drive_t *drive = to_ide_device(dev);
- ide_drive_t *pair = ide_get_pair_dev(drive);
- ide_hwif_t *hwif = drive->hwif;
- struct request *rq;
- struct ide_pm_state rqpm;
- int ret;
-
- if (ide_port_acpi(hwif)) {
- /* call ACPI _GTM only once */
- if ((drive->dn & 1) == 0 || pair == NULL)
- ide_acpi_get_timing(hwif);
- }
-
- memset(&rqpm, 0, sizeof(rqpm));
- rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
- ide_req(rq)->type = ATA_PRIV_PM_SUSPEND;
- ide_req(rq)->special = &rqpm;
- rqpm.pm_step = IDE_PM_START_SUSPEND;
- if (mesg.event == PM_EVENT_PRETHAW)
- mesg.event = PM_EVENT_FREEZE;
- rqpm.pm_state = mesg.event;
-
- blk_execute_rq(NULL, rq, 0);
- ret = scsi_req(rq)->result ? -EIO : 0;
- blk_put_request(rq);
-
- if (ret == 0 && ide_port_acpi(hwif)) {
- /* call ACPI _PS3 only after both devices are suspended */
- if ((drive->dn & 1) || pair == NULL)
- ide_acpi_set_state(hwif, 0);
- }
-
- return ret;
-}
-
-static int ide_pm_execute_rq(struct request *rq)
-{
- struct request_queue *q = rq->q;
-
- if (unlikely(blk_queue_dying(q))) {
- rq->rq_flags |= RQF_QUIET;
- scsi_req(rq)->result = -ENXIO;
- blk_mq_end_request(rq, BLK_STS_OK);
- return -ENXIO;
- }
- blk_execute_rq(NULL, rq, true);
-
- return scsi_req(rq)->result ? -EIO : 0;
-}
-
-int generic_ide_resume(struct device *dev)
-{
- ide_drive_t *drive = to_ide_device(dev);
- ide_drive_t *pair = ide_get_pair_dev(drive);
- ide_hwif_t *hwif = drive->hwif;
- struct request *rq;
- struct ide_pm_state rqpm;
- int err;
-
- blk_mq_start_stopped_hw_queues(drive->queue, true);
-
- if (ide_port_acpi(hwif)) {
- /* call ACPI _PS0 / _STM only once */
- if ((drive->dn & 1) == 0 || pair == NULL) {
- ide_acpi_set_state(hwif, 1);
- ide_acpi_push_timing(hwif);
- }
-
- ide_acpi_exec_tfs(drive);
- }
-
- memset(&rqpm, 0, sizeof(rqpm));
- rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, BLK_MQ_REQ_PM);
- ide_req(rq)->type = ATA_PRIV_PM_RESUME;
- ide_req(rq)->special = &rqpm;
- rqpm.pm_step = IDE_PM_START_RESUME;
- rqpm.pm_state = PM_EVENT_ON;
-
- err = ide_pm_execute_rq(rq);
- blk_put_request(rq);
-
- if (err == 0 && dev->driver) {
- struct ide_driver *drv = to_ide_driver(dev->driver);
-
- if (drv->resume)
- drv->resume(drive);
- }
-
- return err;
-}
-
-void ide_complete_power_step(ide_drive_t *drive, struct request *rq)
-{
- struct ide_pm_state *pm = ide_req(rq)->special;
-
-#ifdef DEBUG_PM
- printk(KERN_INFO "%s: complete_power_step(step: %d)\n",
- drive->name, pm->pm_step);
-#endif
- if (drive->media != ide_disk)
- return;
-
- switch (pm->pm_step) {
- case IDE_PM_FLUSH_CACHE: /* Suspend step 1 (flush cache) */
- if (pm->pm_state == PM_EVENT_FREEZE)
- pm->pm_step = IDE_PM_COMPLETED;
- else
- pm->pm_step = IDE_PM_STANDBY;
- break;
- case IDE_PM_STANDBY: /* Suspend step 2 (standby) */
- pm->pm_step = IDE_PM_COMPLETED;
- break;
- case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */
- pm->pm_step = IDE_PM_IDLE;
- break;
- case IDE_PM_IDLE: /* Resume step 2 (idle)*/
- pm->pm_step = IDE_PM_RESTORE_DMA;
- break;
- }
-}
-
-ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
-{
- struct ide_pm_state *pm = ide_req(rq)->special;
- struct ide_cmd cmd = { };
-
- switch (pm->pm_step) {
- case IDE_PM_FLUSH_CACHE: /* Suspend step 1 (flush cache) */
- if (drive->media != ide_disk)
- break;
- /* Not supported? Switch to next step now. */
- if (ata_id_flush_enabled(drive->id) == 0 ||
- (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) {
- ide_complete_power_step(drive, rq);
- return ide_stopped;
- }
- if (ata_id_flush_ext_enabled(drive->id))
- cmd.tf.command = ATA_CMD_FLUSH_EXT;
- else
- cmd.tf.command = ATA_CMD_FLUSH;
- goto out_do_tf;
- case IDE_PM_STANDBY: /* Suspend step 2 (standby) */
- cmd.tf.command = ATA_CMD_STANDBYNOW1;
- goto out_do_tf;
- case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */
- ide_set_max_pio(drive);
- /*
- * skip IDE_PM_IDLE for ATAPI devices
- */
- if (drive->media != ide_disk)
- pm->pm_step = IDE_PM_RESTORE_DMA;
- else
- ide_complete_power_step(drive, rq);
- return ide_stopped;
- case IDE_PM_IDLE: /* Resume step 2 (idle) */
- cmd.tf.command = ATA_CMD_IDLEIMMEDIATE;
- goto out_do_tf;
- case IDE_PM_RESTORE_DMA: /* Resume step 3 (restore DMA) */
- /*
- * Right now, all we do is call ide_set_dma(drive),
- * we could be smarter and check for current xfer_speed
- * in struct drive etc...
- */
- if (drive->hwif->dma_ops == NULL)
- break;
- /*
- * TODO: respect IDE_DFLAG_USING_DMA
- */
- ide_set_dma(drive);
- break;
- }
-
- pm->pm_step = IDE_PM_COMPLETED;
-
- return ide_stopped;
-
-out_do_tf:
- cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
- cmd.protocol = ATA_PROT_NODATA;
-
- return do_rw_taskfile(drive, &cmd);
-}
-
-/**
- * ide_complete_pm_rq - end the current Power Management request
- * @drive: target drive
- * @rq: request
- *
- * This function cleans up the current PM request and stops the queue
- * if necessary.
- */
-void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq)
-{
- struct request_queue *q = drive->queue;
- struct ide_pm_state *pm = ide_req(rq)->special;
-
- ide_complete_power_step(drive, rq);
- if (pm->pm_step != IDE_PM_COMPLETED)
- return;
-
-#ifdef DEBUG_PM
- printk("%s: completing PM request, %s\n", drive->name,
- (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND) ? "suspend" : "resume");
-#endif
- if (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND)
- blk_mq_stop_hw_queues(q);
- else
- drive->dev_flags &= ~IDE_DFLAG_BLOCKED;
-
- drive->hwif->rq = NULL;
-
- blk_mq_end_request(rq, BLK_STS_OK);
-}
-
-void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
-{
- struct ide_pm_state *pm = ide_req(rq)->special;
-
- if (blk_rq_is_private(rq) &&
- ide_req(rq)->type == ATA_PRIV_PM_SUSPEND &&
- pm->pm_step == IDE_PM_START_SUSPEND)
- /* Mark drive blocked when starting the suspend sequence. */
- drive->dev_flags |= IDE_DFLAG_BLOCKED;
- else if (blk_rq_is_private(rq) &&
- ide_req(rq)->type == ATA_PRIV_PM_RESUME &&
- pm->pm_step == IDE_PM_START_RESUME) {
- /*
- * The first thing we do on wakeup is to wait for BSY bit to
- * go away (with a looong timeout) as a drive on this hwif may
- * just be POSTing itself.
- * We do that before even selecting as the "other" device on
- * the bus may be broken enough to walk on our toes at this
- * point.
- */
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_tp_ops *tp_ops = hwif->tp_ops;
- struct request_queue *q = drive->queue;
- int rc;
-#ifdef DEBUG_PM
- printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name);
-#endif
- rc = ide_wait_not_busy(hwif, 35000);
- if (rc)
- printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
- tp_ops->dev_select(drive);
- tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
- rc = ide_wait_not_busy(hwif, 100000);
- if (rc)
- printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
-
- blk_mq_start_hw_queues(q);
- }
-}
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
deleted file mode 100644
index fc541f1cf8de..000000000000
--- a/drivers/ide/ide-pnp.c
+++ /dev/null
@@ -1,92 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * This file provides autodetection for ISA PnP IDE interfaces.
- * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface.
- *
- * Copyright (C) 2000 Andrey Panin <pazke@donpac.ru>
- */
-
-#include <linux/init.h>
-#include <linux/pnp.h>
-#include <linux/ide.h>
-#include <linux/module.h>
-
-#define DRV_NAME "ide-pnp"
-
-/* Add your devices here :)) */
-static const struct pnp_device_id idepnp_devices[] = {
- /* Generic ESDI/IDE/ATA compatible hard disk controller */
- {.id = "PNP0600", .driver_data = 0},
- {.id = ""}
-};
-
-static const struct ide_port_info ide_pnp_port_info = {
- .host_flags = IDE_HFLAG_NO_DMA,
- .chipset = ide_generic,
-};
-
-static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
-{
- struct ide_host *host;
- unsigned long base, ctl;
- int rc;
- struct ide_hw hw, *hws[] = { &hw };
-
- printk(KERN_INFO DRV_NAME ": generic PnP IDE interface\n");
-
- if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0)))
- return -1;
-
- base = pnp_port_start(dev, 0);
- ctl = pnp_port_start(dev, 1);
-
- if (!request_region(base, 8, DRV_NAME)) {
- printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
- DRV_NAME, base, base + 7);
- return -EBUSY;
- }
-
- if (!request_region(ctl, 1, DRV_NAME)) {
- printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
- DRV_NAME, ctl);
- release_region(base, 8);
- return -EBUSY;
- }
-
- memset(&hw, 0, sizeof(hw));
- ide_std_init_ports(&hw, base, ctl);
- hw.irq = pnp_irq(dev, 0);
-
- rc = ide_host_add(&ide_pnp_port_info, hws, 1, &host);
- if (rc)
- goto out;
-
- pnp_set_drvdata(dev, host);
-
- return 0;
-out:
- release_region(ctl, 1);
- release_region(base, 8);
-
- return rc;
-}
-
-static void idepnp_remove(struct pnp_dev *dev)
-{
- struct ide_host *host = pnp_get_drvdata(dev);
-
- ide_host_remove(host);
-
- release_region(pnp_port_start(dev, 1), 1);
- release_region(pnp_port_start(dev, 0), 8);
-}
-
-static struct pnp_driver idepnp_driver = {
- .name = "ide",
- .id_table = idepnp_devices,
- .probe = idepnp_probe,
- .remove = idepnp_remove,
-};
-
-module_pnp_driver(idepnp_driver);
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
deleted file mode 100644
index aefd74c0d862..000000000000
--- a/drivers/ide/ide-probe.c
+++ /dev/null
@@ -1,1623 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
- * Copyright (C) 2005, 2007 Bartlomiej Zolnierkiewicz
- */
-
-/*
- * Mostly written by Mark Lord <mlord@pobox.com>
- * and Gadi Oxman <gadio@netvision.net.il>
- * and Andre Hedrick <andre@linux-ide.org>
- *
- * See linux/MAINTAINERS for address of current maintainer.
- *
- * This is the IDE probe module, as evolved from hd.c and ide.c.
- *
- * -- increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot
- * by Andrea Arcangeli
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/spinlock.h>
-#include <linux/kmod.h>
-#include <linux/pci.h>
-#include <linux/scatterlist.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <linux/uaccess.h>
-#include <asm/io.h>
-
-/**
- * generic_id - add a generic drive id
- * @drive: drive to make an ID block for
- *
- * Add a fake id field to the drive we are passed. This allows
- * use to skip a ton of NULL checks (which people always miss)
- * and make drive properties unconditional outside of this file
- */
-
-static void generic_id(ide_drive_t *drive)
-{
- u16 *id = drive->id;
-
- id[ATA_ID_CUR_CYLS] = id[ATA_ID_CYLS] = drive->cyl;
- id[ATA_ID_CUR_HEADS] = id[ATA_ID_HEADS] = drive->head;
- id[ATA_ID_CUR_SECTORS] = id[ATA_ID_SECTORS] = drive->sect;
-}
-
-static void ide_disk_init_chs(ide_drive_t *drive)
-{
- u16 *id = drive->id;
-
- /* Extract geometry if we did not already have one for the drive */
- if (!drive->cyl || !drive->head || !drive->sect) {
- drive->cyl = drive->bios_cyl = id[ATA_ID_CYLS];
- drive->head = drive->bios_head = id[ATA_ID_HEADS];
- drive->sect = drive->bios_sect = id[ATA_ID_SECTORS];
- }
-
- /* Handle logical geometry translation by the drive */
- if (ata_id_current_chs_valid(id)) {
- drive->cyl = id[ATA_ID_CUR_CYLS];
- drive->head = id[ATA_ID_CUR_HEADS];
- drive->sect = id[ATA_ID_CUR_SECTORS];
- }
-
- /* Use physical geometry if what we have still makes no sense */
- if (drive->head > 16 && id[ATA_ID_HEADS] && id[ATA_ID_HEADS] <= 16) {
- drive->cyl = id[ATA_ID_CYLS];
- drive->head = id[ATA_ID_HEADS];
- drive->sect = id[ATA_ID_SECTORS];
- }
-}
-
-static void ide_disk_init_mult_count(ide_drive_t *drive)
-{
- u16 *id = drive->id;
- u8 max_multsect = id[ATA_ID_MAX_MULTSECT] & 0xff;
-
- if (max_multsect) {
- if ((max_multsect / 2) > 1)
- id[ATA_ID_MULTSECT] = max_multsect | 0x100;
- else
- id[ATA_ID_MULTSECT] &= ~0x1ff;
-
- drive->mult_req = id[ATA_ID_MULTSECT] & 0xff;
-
- if (drive->mult_req)
- drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
- }
-}
-
-static void ide_classify_ata_dev(ide_drive_t *drive)
-{
- u16 *id = drive->id;
- char *m = (char *)&id[ATA_ID_PROD];
- int is_cfa = ata_id_is_cfa(id);
-
- /* CF devices are *not* removable in Linux definition of the term */
- if (is_cfa == 0 && (id[ATA_ID_CONFIG] & (1 << 7)))
- drive->dev_flags |= IDE_DFLAG_REMOVABLE;
-
- drive->media = ide_disk;
-
- if (!ata_id_has_unload(drive->id))
- drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
-
- printk(KERN_INFO "%s: %s, %s DISK drive\n", drive->name, m,
- is_cfa ? "CFA" : "ATA");
-}
-
-static void ide_classify_atapi_dev(ide_drive_t *drive)
-{
- u16 *id = drive->id;
- char *m = (char *)&id[ATA_ID_PROD];
- u8 type = (id[ATA_ID_CONFIG] >> 8) & 0x1f;
-
- printk(KERN_INFO "%s: %s, ATAPI ", drive->name, m);
- switch (type) {
- case ide_floppy:
- if (!strstr(m, "CD-ROM")) {
- if (!strstr(m, "oppy") &&
- !strstr(m, "poyp") &&
- !strstr(m, "ZIP"))
- printk(KERN_CONT "cdrom or floppy?, assuming ");
- if (drive->media != ide_cdrom) {
- printk(KERN_CONT "FLOPPY");
- drive->dev_flags |= IDE_DFLAG_REMOVABLE;
- break;
- }
- }
- /* Early cdrom models used zero */
- type = ide_cdrom;
- fallthrough;
- case ide_cdrom:
- drive->dev_flags |= IDE_DFLAG_REMOVABLE;
-#ifdef CONFIG_PPC
- /* kludge for Apple PowerBook internal zip */
- if (!strstr(m, "CD-ROM") && strstr(m, "ZIP")) {
- printk(KERN_CONT "FLOPPY");
- type = ide_floppy;
- break;
- }
-#endif
- printk(KERN_CONT "CD/DVD-ROM");
- break;
- case ide_tape:
- printk(KERN_CONT "TAPE");
- break;
- case ide_optical:
- printk(KERN_CONT "OPTICAL");
- drive->dev_flags |= IDE_DFLAG_REMOVABLE;
- break;
- default:
- printk(KERN_CONT "UNKNOWN (type %d)", type);
- break;
- }
-
- printk(KERN_CONT " drive\n");
- drive->media = type;
- /* an ATAPI device ignores DRDY */
- drive->ready_stat = 0;
- if (ata_id_cdb_intr(id))
- drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT;
- drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
- /* we don't do head unloading on ATAPI devices */
- drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
-}
-
-/**
- * do_identify - identify a drive
- * @drive: drive to identify
- * @cmd: command used
- * @id: buffer for IDENTIFY data
- *
- * Called when we have issued a drive identify command to
- * read and parse the results. This function is run with
- * interrupts disabled.
- */
-
-static void do_identify(ide_drive_t *drive, u8 cmd, u16 *id)
-{
- ide_hwif_t *hwif = drive->hwif;
- char *m = (char *)&id[ATA_ID_PROD];
- unsigned long flags;
- int bswap = 1;
-
- /* local CPU only; some systems need this */
- local_irq_save(flags);
- /* read 512 bytes of id info */
- hwif->tp_ops->input_data(drive, NULL, id, SECTOR_SIZE);
- local_irq_restore(flags);
-
- drive->dev_flags |= IDE_DFLAG_ID_READ;
-#ifdef DEBUG
- printk(KERN_INFO "%s: dumping identify data\n", drive->name);
- ide_dump_identify((u8 *)id);
-#endif
- ide_fix_driveid(id);
-
- /*
- * ATA_CMD_ID_ATA returns little-endian info,
- * ATA_CMD_ID_ATAPI *usually* returns little-endian info.
- */
- if (cmd == ATA_CMD_ID_ATAPI) {
- if ((m[0] == 'N' && m[1] == 'E') || /* NEC */
- (m[0] == 'F' && m[1] == 'X') || /* Mitsumi */
- (m[0] == 'P' && m[1] == 'i')) /* Pioneer */
- /* Vertos drives may still be weird */
- bswap ^= 1;
- }
-
- ide_fixstring(m, ATA_ID_PROD_LEN, bswap);
- ide_fixstring((char *)&id[ATA_ID_FW_REV], ATA_ID_FW_REV_LEN, bswap);
- ide_fixstring((char *)&id[ATA_ID_SERNO], ATA_ID_SERNO_LEN, bswap);
-
- /* we depend on this a lot! */
- m[ATA_ID_PROD_LEN - 1] = '\0';
-
- if (strstr(m, "E X A B Y T E N E S T"))
- drive->dev_flags &= ~IDE_DFLAG_PRESENT;
- else
- drive->dev_flags |= IDE_DFLAG_PRESENT;
-}
-
-/**
- * ide_dev_read_id - send ATA/ATAPI IDENTIFY command
- * @drive: drive to identify
- * @cmd: command to use
- * @id: buffer for IDENTIFY data
- * @irq_ctx: flag set when called from the IRQ context
- *
- * Sends an ATA(PI) IDENTIFY request to a drive and waits for a response.
- *
- * Returns: 0 device was identified
- * 1 device timed-out (no response to identify request)
- * 2 device aborted the command (refused to identify itself)
- */
-
-int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id, int irq_ctx)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct ide_io_ports *io_ports = &hwif->io_ports;
- const struct ide_tp_ops *tp_ops = hwif->tp_ops;
- int use_altstatus = 0, rc;
- unsigned long timeout;
- u8 s = 0, a = 0;
-
- /*
- * Disable device IRQ. Otherwise we'll get spurious interrupts
- * during the identify phase that the IRQ handler isn't expecting.
- */
- if (io_ports->ctl_addr)
- tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS);
-
- /* take a deep breath */
- if (irq_ctx)
- mdelay(50);
- else
- msleep(50);
-
- if (io_ports->ctl_addr &&
- (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0) {
- a = tp_ops->read_altstatus(hwif);
- s = tp_ops->read_status(hwif);
- if ((a ^ s) & ~ATA_SENSE)
- /* ancient Seagate drives, broken interfaces */
- printk(KERN_INFO "%s: probing with STATUS(0x%02x) "
- "instead of ALTSTATUS(0x%02x)\n",
- drive->name, s, a);
- else
- /* use non-intrusive polling */
- use_altstatus = 1;
- }
-
- /* set features register for atapi
- * identify command to be sure of reply
- */
- if (cmd == ATA_CMD_ID_ATAPI) {
- struct ide_taskfile tf;
-
- memset(&tf, 0, sizeof(tf));
- /* disable DMA & overlap */
- tp_ops->tf_load(drive, &tf, IDE_VALID_FEATURE);
- }
-
- /* ask drive for ID */
- tp_ops->exec_command(hwif, cmd);
-
- timeout = ((cmd == ATA_CMD_ID_ATA) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
-
- /* wait for IRQ and ATA_DRQ */
- if (irq_ctx) {
- rc = __ide_wait_stat(drive, ATA_DRQ, BAD_R_STAT, timeout, &s);
- if (rc)
- return 1;
- } else {
- rc = ide_busy_sleep(drive, timeout, use_altstatus);
- if (rc)
- return 1;
-
- msleep(50);
- s = tp_ops->read_status(hwif);
- }
-
- if (OK_STAT(s, ATA_DRQ, BAD_R_STAT)) {
- /* drive returned ID */
- do_identify(drive, cmd, id);
- /* drive responded with ID */
- rc = 0;
- /* clear drive IRQ */
- (void)tp_ops->read_status(hwif);
- } else {
- /* drive refused ID */
- rc = 2;
- }
- return rc;
-}
-
-int ide_busy_sleep(ide_drive_t *drive, unsigned long timeout, int altstatus)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 stat;
-
- timeout += jiffies;
-
- do {
- msleep(50); /* give drive a breather */
- stat = altstatus ? hwif->tp_ops->read_altstatus(hwif)
- : hwif->tp_ops->read_status(hwif);
- if ((stat & ATA_BUSY) == 0)
- return 0;
- } while (time_before(jiffies, timeout));
-
- printk(KERN_ERR "%s: timeout in %s\n", drive->name, __func__);
-
- return 1; /* drive timed-out */
-}
-
-static u8 ide_read_device(ide_drive_t *drive)
-{
- struct ide_taskfile tf;
-
- drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_DEVICE);
-
- return tf.device;
-}
-
-/**
- * do_probe - probe an IDE device
- * @drive: drive to probe
- * @cmd: command to use
- *
- * do_probe() has the difficult job of finding a drive if it exists,
- * without getting hung up if it doesn't exist, without trampling on
- * ethernet cards, and without leaving any IRQs dangling to haunt us later.
- *
- * If a drive is "known" to exist (from CMOS or kernel parameters),
- * but does not respond right away, the probe will "hang in there"
- * for the maximum wait time (about 30 seconds), otherwise it will
- * exit much more quickly.
- *
- * Returns: 0 device was identified
- * 1 device timed-out (no response to identify request)
- * 2 device aborted the command (refused to identify itself)
- * 3 bad status from device (possible for ATAPI drives)
- * 4 probe was not attempted because failure was obvious
- */
-
-static int do_probe (ide_drive_t *drive, u8 cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_tp_ops *tp_ops = hwif->tp_ops;
- u16 *id = drive->id;
- int rc;
- u8 present = !!(drive->dev_flags & IDE_DFLAG_PRESENT), stat;
-
- /* avoid waiting for inappropriate probes */
- if (present && drive->media != ide_disk && cmd == ATA_CMD_ID_ATA)
- return 4;
-
-#ifdef DEBUG
- printk(KERN_INFO "probing for %s: present=%d, media=%d, probetype=%s\n",
- drive->name, present, drive->media,
- (cmd == ATA_CMD_ID_ATA) ? "ATA" : "ATAPI");
-#endif
-
- /* needed for some systems
- * (e.g. crw9624 as drive0 with disk as slave)
- */
- msleep(50);
- tp_ops->dev_select(drive);
- msleep(50);
-
- if (ide_read_device(drive) != drive->select && present == 0) {
- if (drive->dn & 1) {
- /* exit with drive0 selected */
- tp_ops->dev_select(hwif->devices[0]);
- /* allow ATA_BUSY to assert & clear */
- msleep(50);
- }
- /* no i/f present: mmm.. this should be a 4 -ml */
- return 3;
- }
-
- stat = tp_ops->read_status(hwif);
-
- if (OK_STAT(stat, ATA_DRDY, ATA_BUSY) ||
- present || cmd == ATA_CMD_ID_ATAPI) {
- rc = ide_dev_read_id(drive, cmd, id, 0);
- if (rc)
- /* failed: try again */
- rc = ide_dev_read_id(drive, cmd, id, 0);
-
- stat = tp_ops->read_status(hwif);
-
- if (stat == (ATA_BUSY | ATA_DRDY))
- return 4;
-
- if (rc == 1 && cmd == ATA_CMD_ID_ATAPI) {
- printk(KERN_ERR "%s: no response (status = 0x%02x), "
- "resetting drive\n", drive->name, stat);
- msleep(50);
- tp_ops->dev_select(drive);
- msleep(50);
- tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
- (void)ide_busy_sleep(drive, WAIT_WORSTCASE, 0);
- rc = ide_dev_read_id(drive, cmd, id, 0);
- }
-
- /* ensure drive IRQ is clear */
- stat = tp_ops->read_status(hwif);
-
- if (rc == 1)
- printk(KERN_ERR "%s: no response (status = 0x%02x)\n",
- drive->name, stat);
- } else {
- /* not present or maybe ATAPI */
- rc = 3;
- }
- if (drive->dn & 1) {
- /* exit with drive0 selected */
- tp_ops->dev_select(hwif->devices[0]);
- msleep(50);
- /* ensure drive irq is clear */
- (void)tp_ops->read_status(hwif);
- }
- return rc;
-}
-
-/**
- * probe_for_drives - upper level drive probe
- * @drive: drive to probe for
- *
- * probe_for_drive() tests for existence of a given drive using do_probe()
- * and presents things to the user as needed.
- *
- * Returns: 0 no device was found
- * 1 device was found
- * (note: IDE_DFLAG_PRESENT might still be not set)
- */
-
-static u8 probe_for_drive(ide_drive_t *drive)
-{
- char *m;
- int rc;
- u8 cmd;
-
- drive->dev_flags &= ~IDE_DFLAG_ID_READ;
-
- m = (char *)&drive->id[ATA_ID_PROD];
- strcpy(m, "UNKNOWN");
-
- /* skip probing? */
- if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0) {
- /* if !(success||timed-out) */
- cmd = ATA_CMD_ID_ATA;
- rc = do_probe(drive, cmd);
- if (rc >= 2) {
- /* look for ATAPI device */
- cmd = ATA_CMD_ID_ATAPI;
- rc = do_probe(drive, cmd);
- }
-
- if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
- return 0;
-
- /* identification failed? */
- if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
- if (drive->media == ide_disk) {
- printk(KERN_INFO "%s: non-IDE drive, CHS=%d/%d/%d\n",
- drive->name, drive->cyl,
- drive->head, drive->sect);
- } else if (drive->media == ide_cdrom) {
- printk(KERN_INFO "%s: ATAPI cdrom (?)\n", drive->name);
- } else {
- /* nuke it */
- printk(KERN_WARNING "%s: Unknown device on bus refused identification. Ignoring.\n", drive->name);
- drive->dev_flags &= ~IDE_DFLAG_PRESENT;
- }
- } else {
- if (cmd == ATA_CMD_ID_ATAPI)
- ide_classify_atapi_dev(drive);
- else
- ide_classify_ata_dev(drive);
- }
- }
-
- if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
- return 0;
-
- /* The drive wasn't being helpful. Add generic info only */
- if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
- generic_id(drive);
- return 1;
- }
-
- if (drive->media == ide_disk) {
- ide_disk_init_chs(drive);
- ide_disk_init_mult_count(drive);
- }
-
- return 1;
-}
-
-static void hwif_release_dev(struct device *dev)
-{
- ide_hwif_t *hwif = container_of(dev, ide_hwif_t, gendev);
-
- complete(&hwif->gendev_rel_comp);
-}
-
-static int ide_register_port(ide_hwif_t *hwif)
-{
- int ret;
-
- /* register with global device tree */
- dev_set_name(&hwif->gendev, "%s", hwif->name);
- dev_set_drvdata(&hwif->gendev, hwif);
- if (hwif->gendev.parent == NULL)
- hwif->gendev.parent = hwif->dev;
- hwif->gendev.release = hwif_release_dev;
-
- ret = device_register(&hwif->gendev);
- if (ret < 0) {
- printk(KERN_WARNING "IDE: %s: device_register error: %d\n",
- __func__, ret);
- goto out;
- }
-
- hwif->portdev = device_create(ide_port_class, &hwif->gendev,
- MKDEV(0, 0), hwif, "%s", hwif->name);
- if (IS_ERR(hwif->portdev)) {
- ret = PTR_ERR(hwif->portdev);
- device_unregister(&hwif->gendev);
- }
-out:
- return ret;
-}
-
-/**
- * ide_port_wait_ready - wait for port to become ready
- * @hwif: IDE port
- *
- * This is needed on some PPCs and a bunch of BIOS-less embedded
- * platforms. Typical cases are:
- *
- * - The firmware hard reset the disk before booting the kernel,
- * the drive is still doing it's poweron-reset sequence, that
- * can take up to 30 seconds.
- *
- * - The firmware does nothing (or no firmware), the device is
- * still in POST state (same as above actually).
- *
- * - Some CD/DVD/Writer combo drives tend to drive the bus during
- * their reset sequence even when they are non-selected slave
- * devices, thus preventing discovery of the main HD.
- *
- * Doing this wait-for-non-busy should not harm any existing
- * configuration and fix some issues like the above.
- *
- * BenH.
- *
- * Returns 0 on success, error code (< 0) otherwise.
- */
-
-static int ide_port_wait_ready(ide_hwif_t *hwif)
-{
- const struct ide_tp_ops *tp_ops = hwif->tp_ops;
- ide_drive_t *drive;
- int i, rc;
-
- printk(KERN_DEBUG "Probing IDE interface %s...\n", hwif->name);
-
- /* Let HW settle down a bit from whatever init state we
- * come from */
- mdelay(2);
-
- /* Wait for BSY bit to go away, spec timeout is 30 seconds,
- * I know of at least one disk who takes 31 seconds, I use 35
- * here to be safe
- */
- rc = ide_wait_not_busy(hwif, 35000);
- if (rc)
- return rc;
-
- /* Now make sure both master & slave are ready */
- ide_port_for_each_dev(i, drive, hwif) {
- /* Ignore disks that we will not probe for later. */
- if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0 ||
- (drive->dev_flags & IDE_DFLAG_PRESENT)) {
- tp_ops->dev_select(drive);
- tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
- mdelay(2);
- rc = ide_wait_not_busy(hwif, 35000);
- if (rc)
- goto out;
- } else
- printk(KERN_DEBUG "%s: ide_wait_not_busy() skipped\n",
- drive->name);
- }
-out:
- /* Exit function with master reselected (let's be sane) */
- if (i)
- tp_ops->dev_select(hwif->devices[0]);
-
- return rc;
-}
-
-/**
- * ide_undecoded_slave - look for bad CF adapters
- * @dev1: slave device
- *
- * Analyse the drives on the interface and attempt to decide if we
- * have the same drive viewed twice. This occurs with crap CF adapters
- * and PCMCIA sometimes.
- */
-
-void ide_undecoded_slave(ide_drive_t *dev1)
-{
- ide_drive_t *dev0 = dev1->hwif->devices[0];
-
- if ((dev1->dn & 1) == 0 || (dev0->dev_flags & IDE_DFLAG_PRESENT) == 0)
- return;
-
- /* If the models don't match they are not the same product */
- if (strcmp((char *)&dev0->id[ATA_ID_PROD],
- (char *)&dev1->id[ATA_ID_PROD]))
- return;
-
- /* Serial numbers do not match */
- if (strncmp((char *)&dev0->id[ATA_ID_SERNO],
- (char *)&dev1->id[ATA_ID_SERNO], ATA_ID_SERNO_LEN))
- return;
-
- /* No serial number, thankfully very rare for CF */
- if (*(char *)&dev0->id[ATA_ID_SERNO] == 0)
- return;
-
- /* Appears to be an IDE flash adapter with decode bugs */
- printk(KERN_WARNING "ide-probe: ignoring undecoded slave\n");
-
- dev1->dev_flags &= ~IDE_DFLAG_PRESENT;
-}
-
-EXPORT_SYMBOL_GPL(ide_undecoded_slave);
-
-static int ide_probe_port(ide_hwif_t *hwif)
-{
- ide_drive_t *drive;
- unsigned int irqd;
- int i, rc = -ENODEV;
-
- BUG_ON(hwif->present);
-
- if ((hwif->devices[0]->dev_flags & IDE_DFLAG_NOPROBE) &&
- (hwif->devices[1]->dev_flags & IDE_DFLAG_NOPROBE))
- return -EACCES;
-
- /*
- * We must always disable IRQ, as probe_for_drive will assert IRQ, but
- * we'll install our IRQ driver much later...
- */
- irqd = hwif->irq;
- if (irqd)
- disable_irq(hwif->irq);
-
- if (ide_port_wait_ready(hwif) == -EBUSY)
- printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name);
-
- /*
- * Second drive should only exist if first drive was found,
- * but a lot of cdrom drives are configured as single slaves.
- */
- ide_port_for_each_dev(i, drive, hwif) {
- (void) probe_for_drive(drive);
- if (drive->dev_flags & IDE_DFLAG_PRESENT)
- rc = 0;
- }
-
- /*
- * Use cached IRQ number. It might be (and is...) changed by probe
- * code above
- */
- if (irqd)
- enable_irq(irqd);
-
- return rc;
-}
-
-static void ide_port_tune_devices(ide_hwif_t *hwif)
-{
- const struct ide_port_ops *port_ops = hwif->port_ops;
- ide_drive_t *drive;
- int i;
-
- ide_port_for_each_present_dev(i, drive, hwif) {
- ide_check_nien_quirk_list(drive);
-
- if (port_ops && port_ops->quirkproc)
- port_ops->quirkproc(drive);
- }
-
- ide_port_for_each_present_dev(i, drive, hwif) {
- ide_set_max_pio(drive);
-
- drive->dev_flags |= IDE_DFLAG_NICE1;
-
- if (hwif->dma_ops)
- ide_set_dma(drive);
- }
-}
-
-static void ide_initialize_rq(struct request *rq)
-{
- struct ide_request *req = blk_mq_rq_to_pdu(rq);
-
- req->special = NULL;
- scsi_req_init(&req->sreq);
- req->sreq.sense = req->sense;
-}
-
-static const struct blk_mq_ops ide_mq_ops = {
- .queue_rq = ide_queue_rq,
- .initialize_rq_fn = ide_initialize_rq,
-};
-
-/*
- * init request queue
- */
-static int ide_init_queue(ide_drive_t *drive)
-{
- struct request_queue *q;
- ide_hwif_t *hwif = drive->hwif;
- int max_sectors = 256;
- int max_sg_entries = PRD_ENTRIES;
- struct blk_mq_tag_set *set;
-
- /*
- * Our default set up assumes the normal IDE case,
- * that is 64K segmenting, standard PRD setup
- * and LBA28. Some drivers then impose their own
- * limits and LBA48 we could raise it but as yet
- * do not.
- */
-
- set = &drive->tag_set;
- set->ops = &ide_mq_ops;
- set->nr_hw_queues = 1;
- set->queue_depth = 32;
- set->reserved_tags = 1;
- set->cmd_size = sizeof(struct ide_request);
- set->numa_node = hwif_to_node(hwif);
- set->flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING;
- if (blk_mq_alloc_tag_set(set))
- return 1;
-
- q = blk_mq_init_queue(set);
- if (IS_ERR(q)) {
- blk_mq_free_tag_set(set);
- return 1;
- }
-
- blk_queue_flag_set(QUEUE_FLAG_SCSI_PASSTHROUGH, q);
-
- q->queuedata = drive;
- blk_queue_segment_boundary(q, 0xffff);
-
- if (hwif->rqsize < max_sectors)
- max_sectors = hwif->rqsize;
- blk_queue_max_hw_sectors(q, max_sectors);
-
-#ifdef CONFIG_PCI
- /* When we have an IOMMU, we may have a problem where pci_map_sg()
- * creates segments that don't completely match our boundary
- * requirements and thus need to be broken up again. Because it
- * doesn't align properly either, we may actually have to break up
- * to more segments than what was we got in the first place, a max
- * worst case is twice as many.
- * This will be fixed once we teach pci_map_sg() about our boundary
- * requirements, hopefully soon. *FIXME*
- */
- max_sg_entries >>= 1;
-#endif /* CONFIG_PCI */
-
- blk_queue_max_segments(q, max_sg_entries);
-
- /* assign drive queue */
- drive->queue = q;
-
- return 0;
-}
-
-static DEFINE_MUTEX(ide_cfg_mtx);
-
-/*
- * For any present drive:
- * - allocate the block device queue
- */
-static int ide_port_setup_devices(ide_hwif_t *hwif)
-{
- ide_drive_t *drive;
- int i, j = 0;
-
- mutex_lock(&ide_cfg_mtx);
- ide_port_for_each_present_dev(i, drive, hwif) {
- if (ide_init_queue(drive)) {
- printk(KERN_ERR "ide: failed to init %s\n",
- drive->name);
- drive->dev_flags &= ~IDE_DFLAG_PRESENT;
- continue;
- }
-
- j++;
- }
- mutex_unlock(&ide_cfg_mtx);
-
- return j;
-}
-
-static void ide_host_enable_irqs(struct ide_host *host)
-{
- ide_hwif_t *hwif;
- int i;
-
- ide_host_for_each_port(i, hwif, host) {
- if (hwif == NULL)
- continue;
-
- /* clear any pending IRQs */
- hwif->tp_ops->read_status(hwif);
-
- /* unmask IRQs */
- if (hwif->io_ports.ctl_addr)
- hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
- }
-}
-
-/*
- * This routine sets up the IRQ for an IDE interface.
- */
-static int init_irq (ide_hwif_t *hwif)
-{
- struct ide_io_ports *io_ports = &hwif->io_ports;
- struct ide_host *host = hwif->host;
- irq_handler_t irq_handler = host->irq_handler;
- int sa = host->irq_flags;
-
- if (irq_handler == NULL)
- irq_handler = ide_intr;
-
- if (!host->get_lock)
- if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif))
- goto out_up;
-
-#if !defined(__mc68000__)
- printk(KERN_INFO "%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
- io_ports->data_addr, io_ports->status_addr,
- io_ports->ctl_addr, hwif->irq);
-#else
- printk(KERN_INFO "%s at 0x%08lx on irq %d", hwif->name,
- io_ports->data_addr, hwif->irq);
-#endif /* __mc68000__ */
- if (hwif->host->host_flags & IDE_HFLAG_SERIALIZE)
- printk(KERN_CONT " (serialized)");
- printk(KERN_CONT "\n");
-
- return 0;
-out_up:
- return 1;
-}
-
-static void ata_probe(dev_t dev)
-{
- request_module("ide-disk");
- request_module("ide-cd");
- request_module("ide-tape");
- request_module("ide-floppy");
-}
-
-void ide_init_disk(struct gendisk *disk, ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- unsigned int unit = drive->dn & 1;
-
- disk->major = hwif->major;
- disk->first_minor = unit << PARTN_BITS;
- sprintf(disk->disk_name, "hd%c", 'a' + hwif->index * MAX_DRIVES + unit);
- disk->queue = drive->queue;
-}
-
-EXPORT_SYMBOL_GPL(ide_init_disk);
-
-static void drive_release_dev (struct device *dev)
-{
- ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
-
- ide_proc_unregister_device(drive);
-
- if (drive->sense_rq)
- blk_mq_free_request(drive->sense_rq);
-
- blk_cleanup_queue(drive->queue);
- drive->queue = NULL;
- blk_mq_free_tag_set(&drive->tag_set);
-
- drive->dev_flags &= ~IDE_DFLAG_PRESENT;
-
- complete(&drive->gendev_rel_comp);
-}
-
-static int hwif_init(ide_hwif_t *hwif)
-{
- if (!hwif->irq) {
- printk(KERN_ERR "%s: disabled, no IRQ\n", hwif->name);
- return 0;
- }
-
- if (__register_blkdev(hwif->major, hwif->name, ata_probe))
- return 0;
-
- if (!hwif->sg_max_nents)
- hwif->sg_max_nents = PRD_ENTRIES;
-
- hwif->sg_table = kmalloc_array(hwif->sg_max_nents,
- sizeof(struct scatterlist),
- GFP_KERNEL);
- if (!hwif->sg_table) {
- printk(KERN_ERR "%s: unable to allocate SG table.\n", hwif->name);
- goto out;
- }
-
- sg_init_table(hwif->sg_table, hwif->sg_max_nents);
-
- if (init_irq(hwif)) {
- printk(KERN_ERR "%s: disabled, unable to get IRQ %d\n",
- hwif->name, hwif->irq);
- goto out;
- }
-
- return 1;
-
-out:
- unregister_blkdev(hwif->major, hwif->name);
- return 0;
-}
-
-static void hwif_register_devices(ide_hwif_t *hwif)
-{
- ide_drive_t *drive;
- unsigned int i;
-
- ide_port_for_each_present_dev(i, drive, hwif) {
- struct device *dev = &drive->gendev;
- int ret;
-
- dev_set_name(dev, "%u.%u", hwif->index, i);
- dev_set_drvdata(dev, drive);
- dev->parent = &hwif->gendev;
- dev->bus = &ide_bus_type;
- dev->release = drive_release_dev;
-
- ret = device_register(dev);
- if (ret < 0)
- printk(KERN_WARNING "IDE: %s: device_register error: "
- "%d\n", __func__, ret);
- }
-}
-
-static void ide_port_init_devices(ide_hwif_t *hwif)
-{
- const struct ide_port_ops *port_ops = hwif->port_ops;
- ide_drive_t *drive;
- int i;
-
- ide_port_for_each_dev(i, drive, hwif) {
- drive->dn = i + hwif->channel * 2;
-
- if (hwif->host_flags & IDE_HFLAG_IO_32BIT)
- drive->io_32bit = 1;
- if (hwif->host_flags & IDE_HFLAG_NO_IO_32BIT)
- drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT;
- if (hwif->host_flags & IDE_HFLAG_UNMASK_IRQS)
- drive->dev_flags |= IDE_DFLAG_UNMASK;
- if (hwif->host_flags & IDE_HFLAG_NO_UNMASK_IRQS)
- drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
-
- drive->pio_mode = XFER_PIO_0;
-
- if (port_ops && port_ops->init_dev)
- port_ops->init_dev(drive);
- }
-}
-
-static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
- const struct ide_port_info *d)
-{
- hwif->channel = port;
-
- hwif->chipset = d->chipset ? d->chipset : ide_pci;
-
- if (d->init_iops)
- d->init_iops(hwif);
-
- /* ->host_flags may be set by ->init_iops (or even earlier...) */
- hwif->host_flags |= d->host_flags;
- hwif->pio_mask = d->pio_mask;
-
- if (d->tp_ops)
- hwif->tp_ops = d->tp_ops;
-
- /* ->set_pio_mode for DTC2278 is currently limited to port 0 */
- if ((hwif->host_flags & IDE_HFLAG_DTC2278) == 0 || hwif->channel == 0)
- hwif->port_ops = d->port_ops;
-
- hwif->swdma_mask = d->swdma_mask;
- hwif->mwdma_mask = d->mwdma_mask;
- hwif->ultra_mask = d->udma_mask;
-
- if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) {
- int rc;
-
- hwif->dma_ops = d->dma_ops;
-
- if (d->init_dma)
- rc = d->init_dma(hwif, d);
- else
- rc = ide_hwif_setup_dma(hwif, d);
-
- if (rc < 0) {
- printk(KERN_INFO "%s: DMA disabled\n", hwif->name);
-
- hwif->dma_ops = NULL;
- hwif->dma_base = 0;
- hwif->swdma_mask = 0;
- hwif->mwdma_mask = 0;
- hwif->ultra_mask = 0;
- }
- }
-
- if ((d->host_flags & IDE_HFLAG_SERIALIZE) ||
- ((d->host_flags & IDE_HFLAG_SERIALIZE_DMA) && hwif->dma_base))
- hwif->host->host_flags |= IDE_HFLAG_SERIALIZE;
-
- if (d->max_sectors)
- hwif->rqsize = d->max_sectors;
- else {
- if ((hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
- (hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA))
- hwif->rqsize = 256;
- else
- hwif->rqsize = 65536;
- }
-
- /* call chipset specific routine for each enabled port */
- if (d->init_hwif)
- d->init_hwif(hwif);
-}
-
-static void ide_port_cable_detect(ide_hwif_t *hwif)
-{
- const struct ide_port_ops *port_ops = hwif->port_ops;
-
- if (port_ops && port_ops->cable_detect && (hwif->ultra_mask & 0x78)) {
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = port_ops->cable_detect(hwif);
- }
-}
-
-/*
- * Deferred request list insertion handler
- */
-static void drive_rq_insert_work(struct work_struct *work)
-{
- ide_drive_t *drive = container_of(work, ide_drive_t, rq_work);
- ide_hwif_t *hwif = drive->hwif;
- struct request *rq;
- blk_status_t ret;
- LIST_HEAD(list);
-
- blk_mq_quiesce_queue(drive->queue);
-
- ret = BLK_STS_OK;
- spin_lock_irq(&hwif->lock);
- while (!list_empty(&drive->rq_list)) {
- rq = list_first_entry(&drive->rq_list, struct request, queuelist);
- list_del_init(&rq->queuelist);
-
- spin_unlock_irq(&hwif->lock);
- ret = ide_issue_rq(drive, rq, true);
- spin_lock_irq(&hwif->lock);
- }
- spin_unlock_irq(&hwif->lock);
-
- blk_mq_unquiesce_queue(drive->queue);
-
- if (ret != BLK_STS_OK)
- kblockd_schedule_work(&drive->rq_work);
-}
-
-static const u8 ide_hwif_to_major[] =
- { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR,
- IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };
-
-static void ide_port_init_devices_data(ide_hwif_t *hwif)
-{
- ide_drive_t *drive;
- int i;
-
- ide_port_for_each_dev(i, drive, hwif) {
- u8 j = (hwif->index * MAX_DRIVES) + i;
- u16 *saved_id = drive->id;
-
- memset(drive, 0, sizeof(*drive));
- memset(saved_id, 0, SECTOR_SIZE);
- drive->id = saved_id;
-
- drive->media = ide_disk;
- drive->select = (i << 4) | ATA_DEVICE_OBS;
- drive->hwif = hwif;
- drive->ready_stat = ATA_DRDY;
- drive->bad_wstat = BAD_W_STAT;
- drive->special_flags = IDE_SFLAG_RECALIBRATE |
- IDE_SFLAG_SET_GEOMETRY;
- drive->name[0] = 'h';
- drive->name[1] = 'd';
- drive->name[2] = 'a' + j;
- drive->max_failures = IDE_DEFAULT_MAX_FAILURES;
-
- INIT_LIST_HEAD(&drive->list);
- init_completion(&drive->gendev_rel_comp);
-
- INIT_WORK(&drive->rq_work, drive_rq_insert_work);
- INIT_LIST_HEAD(&drive->rq_list);
- }
-}
-
-static void ide_init_port_data(ide_hwif_t *hwif, unsigned int index)
-{
- /* fill in any non-zero initial values */
- hwif->index = index;
- hwif->major = ide_hwif_to_major[index];
-
- hwif->name[0] = 'i';
- hwif->name[1] = 'd';
- hwif->name[2] = 'e';
- hwif->name[3] = '0' + index;
-
- spin_lock_init(&hwif->lock);
-
- timer_setup(&hwif->timer, ide_timer_expiry, 0);
-
- init_completion(&hwif->gendev_rel_comp);
-
- hwif->tp_ops = &default_tp_ops;
-
- ide_port_init_devices_data(hwif);
-}
-
-static void ide_init_port_hw(ide_hwif_t *hwif, struct ide_hw *hw)
-{
- memcpy(&hwif->io_ports, &hw->io_ports, sizeof(hwif->io_ports));
- hwif->irq = hw->irq;
- hwif->dev = hw->dev;
- hwif->gendev.parent = hw->parent ? hw->parent : hw->dev;
- hwif->config_data = hw->config;
-}
-
-static unsigned int ide_indexes;
-
-/**
- * ide_find_port_slot - find free port slot
- * @d: IDE port info
- *
- * Return the new port slot index or -ENOENT if we are out of free slots.
- */
-
-static int ide_find_port_slot(const struct ide_port_info *d)
-{
- int idx = -ENOENT;
- u8 bootable = (d && (d->host_flags & IDE_HFLAG_NON_BOOTABLE)) ? 0 : 1;
- u8 i = (d && (d->host_flags & IDE_HFLAG_QD_2ND_PORT)) ? 1 : 0;
-
- /*
- * Claim an unassigned slot.
- *
- * Give preference to claiming other slots before claiming ide0/ide1,
- * just in case there's another interface yet-to-be-scanned
- * which uses ports 0x1f0/0x170 (the ide0/ide1 defaults).
- *
- * Unless there is a bootable card that does not use the standard
- * ports 0x1f0/0x170 (the ide0/ide1 defaults).
- */
- mutex_lock(&ide_cfg_mtx);
- if (bootable) {
- if ((ide_indexes | i) != (1 << MAX_HWIFS) - 1)
- idx = ffz(ide_indexes | i);
- } else {
- if ((ide_indexes | 3) != (1 << MAX_HWIFS) - 1)
- idx = ffz(ide_indexes | 3);
- else if ((ide_indexes & 3) != 3)
- idx = ffz(ide_indexes);
- }
- if (idx >= 0)
- ide_indexes |= (1 << idx);
- mutex_unlock(&ide_cfg_mtx);
-
- return idx;
-}
-
-static void ide_free_port_slot(int idx)
-{
- mutex_lock(&ide_cfg_mtx);
- ide_indexes &= ~(1 << idx);
- mutex_unlock(&ide_cfg_mtx);
-}
-
-static void ide_port_free_devices(ide_hwif_t *hwif)
-{
- ide_drive_t *drive;
- int i;
-
- ide_port_for_each_dev(i, drive, hwif) {
- kfree(drive->id);
- kfree(drive);
- }
-}
-
-static int ide_port_alloc_devices(ide_hwif_t *hwif, int node)
-{
- ide_drive_t *drive;
- int i;
-
- for (i = 0; i < MAX_DRIVES; i++) {
- drive = kzalloc_node(sizeof(*drive), GFP_KERNEL, node);
- if (drive == NULL)
- goto out_nomem;
-
- /*
- * In order to keep things simple we have an id
- * block for all drives at all times. If the device
- * is pre ATA or refuses ATA/ATAPI identify we
- * will add faked data to this.
- *
- * Also note that 0 everywhere means "can't do X"
- */
- drive->id = kzalloc_node(SECTOR_SIZE, GFP_KERNEL, node);
- if (drive->id == NULL)
- goto out_free_drive;
-
- hwif->devices[i] = drive;
- }
- return 0;
-
-out_free_drive:
- kfree(drive);
-out_nomem:
- ide_port_free_devices(hwif);
- return -ENOMEM;
-}
-
-struct ide_host *ide_host_alloc(const struct ide_port_info *d,
- struct ide_hw **hws, unsigned int n_ports)
-{
- struct ide_host *host;
- struct device *dev = hws[0] ? hws[0]->dev : NULL;
- int node = dev ? dev_to_node(dev) : -1;
- int i;
-
- host = kzalloc_node(sizeof(*host), GFP_KERNEL, node);
- if (host == NULL)
- return NULL;
-
- for (i = 0; i < n_ports; i++) {
- ide_hwif_t *hwif;
- int idx;
-
- if (hws[i] == NULL)
- continue;
-
- hwif = kzalloc_node(sizeof(*hwif), GFP_KERNEL, node);
- if (hwif == NULL)
- continue;
-
- if (ide_port_alloc_devices(hwif, node) < 0) {
- kfree(hwif);
- continue;
- }
-
- idx = ide_find_port_slot(d);
- if (idx < 0) {
- printk(KERN_ERR "%s: no free slot for interface\n",
- d ? d->name : "ide");
- ide_port_free_devices(hwif);
- kfree(hwif);
- continue;
- }
-
- ide_init_port_data(hwif, idx);
-
- hwif->host = host;
-
- host->ports[i] = hwif;
- host->n_ports++;
- }
-
- if (host->n_ports == 0) {
- kfree(host);
- return NULL;
- }
-
- host->dev[0] = dev;
-
- if (d) {
- host->init_chipset = d->init_chipset;
- host->get_lock = d->get_lock;
- host->release_lock = d->release_lock;
- host->host_flags = d->host_flags;
- host->irq_flags = d->irq_flags;
- }
-
- return host;
-}
-EXPORT_SYMBOL_GPL(ide_host_alloc);
-
-static void ide_port_free(ide_hwif_t *hwif)
-{
- ide_port_free_devices(hwif);
- ide_free_port_slot(hwif->index);
- kfree(hwif);
-}
-
-static void ide_disable_port(ide_hwif_t *hwif)
-{
- struct ide_host *host = hwif->host;
- int i;
-
- printk(KERN_INFO "%s: disabling port\n", hwif->name);
-
- for (i = 0; i < MAX_HOST_PORTS; i++) {
- if (host->ports[i] == hwif) {
- host->ports[i] = NULL;
- host->n_ports--;
- }
- }
-
- ide_port_free(hwif);
-}
-
-int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
- struct ide_hw **hws)
-{
- ide_hwif_t *hwif, *mate = NULL;
- int i, j = 0;
-
- pr_warn("legacy IDE will be removed in 2021, please switch to libata\n"
- "Report any missing HW support to linux-ide@vger.kernel.org\n");
-
- ide_host_for_each_port(i, hwif, host) {
- if (hwif == NULL) {
- mate = NULL;
- continue;
- }
-
- ide_init_port_hw(hwif, hws[i]);
- ide_port_apply_params(hwif);
-
- if ((i & 1) && mate) {
- hwif->mate = mate;
- mate->mate = hwif;
- }
-
- mate = (i & 1) ? NULL : hwif;
-
- ide_init_port(hwif, i & 1, d);
- ide_port_cable_detect(hwif);
-
- hwif->port_flags |= IDE_PFLAG_PROBING;
-
- ide_port_init_devices(hwif);
- }
-
- ide_host_for_each_port(i, hwif, host) {
- if (hwif == NULL)
- continue;
-
- if (ide_probe_port(hwif) == 0)
- hwif->present = 1;
-
- hwif->port_flags &= ~IDE_PFLAG_PROBING;
-
- if ((hwif->host_flags & IDE_HFLAG_4DRIVES) == 0 ||
- hwif->mate == NULL || hwif->mate->present == 0) {
- if (ide_register_port(hwif)) {
- ide_disable_port(hwif);
- continue;
- }
- }
-
- if (hwif->present)
- ide_port_tune_devices(hwif);
- }
-
- ide_host_enable_irqs(host);
-
- ide_host_for_each_port(i, hwif, host) {
- if (hwif == NULL)
- continue;
-
- if (hwif_init(hwif) == 0) {
- printk(KERN_INFO "%s: failed to initialize IDE "
- "interface\n", hwif->name);
- device_unregister(hwif->portdev);
- device_unregister(&hwif->gendev);
- ide_disable_port(hwif);
- continue;
- }
-
- if (hwif->present)
- if (ide_port_setup_devices(hwif) == 0) {
- hwif->present = 0;
- continue;
- }
-
- j++;
-
- ide_acpi_init_port(hwif);
-
- if (hwif->present)
- ide_acpi_port_init_devices(hwif);
- }
-
- ide_host_for_each_port(i, hwif, host) {
- if (hwif == NULL)
- continue;
-
- ide_sysfs_register_port(hwif);
- ide_proc_register_port(hwif);
-
- if (hwif->present) {
- ide_proc_port_register_devices(hwif);
- hwif_register_devices(hwif);
- }
- }
-
- return j ? 0 : -1;
-}
-EXPORT_SYMBOL_GPL(ide_host_register);
-
-int ide_host_add(const struct ide_port_info *d, struct ide_hw **hws,
- unsigned int n_ports, struct ide_host **hostp)
-{
- struct ide_host *host;
- int rc;
-
- host = ide_host_alloc(d, hws, n_ports);
- if (host == NULL)
- return -ENOMEM;
-
- rc = ide_host_register(host, d, hws);
- if (rc) {
- ide_host_free(host);
- return rc;
- }
-
- if (hostp)
- *hostp = host;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ide_host_add);
-
-static void __ide_port_unregister_devices(ide_hwif_t *hwif)
-{
- ide_drive_t *drive;
- int i;
-
- ide_port_for_each_present_dev(i, drive, hwif) {
- device_unregister(&drive->gendev);
- wait_for_completion(&drive->gendev_rel_comp);
- }
-}
-
-void ide_port_unregister_devices(ide_hwif_t *hwif)
-{
- mutex_lock(&ide_cfg_mtx);
- __ide_port_unregister_devices(hwif);
- hwif->present = 0;
- ide_port_init_devices_data(hwif);
- mutex_unlock(&ide_cfg_mtx);
-}
-EXPORT_SYMBOL_GPL(ide_port_unregister_devices);
-
-/**
- * ide_unregister - free an IDE interface
- * @hwif: IDE interface
- *
- * Perform the final unregister of an IDE interface.
- *
- * Locking:
- * The caller must not hold the IDE locks.
- *
- * It is up to the caller to be sure there is no pending I/O here,
- * and that the interface will not be reopened (present/vanishing
- * locking isn't yet done BTW).
- */
-
-static void ide_unregister(ide_hwif_t *hwif)
-{
- mutex_lock(&ide_cfg_mtx);
-
- if (hwif->present) {
- __ide_port_unregister_devices(hwif);
- hwif->present = 0;
- }
-
- ide_proc_unregister_port(hwif);
-
- if (!hwif->host->get_lock)
- free_irq(hwif->irq, hwif);
-
- device_unregister(hwif->portdev);
- device_unregister(&hwif->gendev);
- wait_for_completion(&hwif->gendev_rel_comp);
-
- /*
- * Remove us from the kernel's knowledge
- */
- kfree(hwif->sg_table);
- unregister_blkdev(hwif->major, hwif->name);
-
- ide_release_dma_engine(hwif);
-
- mutex_unlock(&ide_cfg_mtx);
-}
-
-void ide_host_free(struct ide_host *host)
-{
- ide_hwif_t *hwif;
- int i;
-
- ide_host_for_each_port(i, hwif, host) {
- if (hwif)
- ide_port_free(hwif);
- }
-
- kfree(host);
-}
-EXPORT_SYMBOL_GPL(ide_host_free);
-
-void ide_host_remove(struct ide_host *host)
-{
- ide_hwif_t *hwif;
- int i;
-
- ide_host_for_each_port(i, hwif, host) {
- if (hwif)
- ide_unregister(hwif);
- }
-
- ide_host_free(host);
-}
-EXPORT_SYMBOL_GPL(ide_host_remove);
-
-void ide_port_scan(ide_hwif_t *hwif)
-{
- int rc;
-
- ide_port_apply_params(hwif);
- ide_port_cable_detect(hwif);
-
- hwif->port_flags |= IDE_PFLAG_PROBING;
-
- ide_port_init_devices(hwif);
-
- rc = ide_probe_port(hwif);
-
- hwif->port_flags &= ~IDE_PFLAG_PROBING;
-
- if (rc < 0)
- return;
-
- hwif->present = 1;
-
- ide_port_tune_devices(hwif);
- ide_port_setup_devices(hwif);
- ide_acpi_port_init_devices(hwif);
- hwif_register_devices(hwif);
- ide_proc_port_register_devices(hwif);
-}
-EXPORT_SYMBOL_GPL(ide_port_scan);
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
deleted file mode 100644
index 15c17f3781ee..000000000000
--- a/drivers/ide/ide-proc.c
+++ /dev/null
@@ -1,633 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1997-1998 Mark Lord
- * Copyright (C) 2003 Red Hat
- *
- * Some code was moved here from ide.c, see it for original copyrights.
- */
-
-/*
- * This is the /proc/ide/ filesystem implementation.
- *
- * Drive/Driver settings can be retrieved by reading the drive's
- * "settings" files. e.g. "cat /proc/ide0/hda/settings"
- * To write a new value "val" into a specific setting "name", use:
- * echo "name:val" >/proc/ide/ide0/hda/settings
- */
-
-#include <linux/module.h>
-
-#include <linux/uaccess.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/ctype.h>
-#include <linux/ide.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-
-static struct proc_dir_entry *proc_ide_root;
-
-static int ide_imodel_proc_show(struct seq_file *m, void *v)
-{
- ide_hwif_t *hwif = (ide_hwif_t *) m->private;
- const char *name;
-
- switch (hwif->chipset) {
- case ide_generic: name = "generic"; break;
- case ide_pci: name = "pci"; break;
- case ide_cmd640: name = "cmd640"; break;
- case ide_dtc2278: name = "dtc2278"; break;
- case ide_ali14xx: name = "ali14xx"; break;
- case ide_qd65xx: name = "qd65xx"; break;
- case ide_umc8672: name = "umc8672"; break;
- case ide_ht6560b: name = "ht6560b"; break;
- case ide_4drives: name = "4drives"; break;
- case ide_pmac: name = "mac-io"; break;
- case ide_au1xxx: name = "au1xxx"; break;
- case ide_palm3710: name = "palm3710"; break;
- case ide_acorn: name = "acorn"; break;
- default: name = "(unknown)"; break;
- }
- seq_printf(m, "%s\n", name);
- return 0;
-}
-
-static int ide_mate_proc_show(struct seq_file *m, void *v)
-{
- ide_hwif_t *hwif = (ide_hwif_t *) m->private;
-
- if (hwif && hwif->mate)
- seq_printf(m, "%s\n", hwif->mate->name);
- else
- seq_printf(m, "(none)\n");
- return 0;
-}
-
-static int ide_channel_proc_show(struct seq_file *m, void *v)
-{
- ide_hwif_t *hwif = (ide_hwif_t *) m->private;
-
- seq_printf(m, "%c\n", hwif->channel ? '1' : '0');
- return 0;
-}
-
-static int ide_identify_proc_show(struct seq_file *m, void *v)
-{
- ide_drive_t *drive = (ide_drive_t *)m->private;
- u8 *buf;
-
- if (!drive) {
- seq_putc(m, '\n');
- return 0;
- }
-
- buf = kmalloc(SECTOR_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- if (taskfile_lib_get_identify(drive, buf) == 0) {
- __le16 *val = (__le16 *)buf;
- int i;
-
- for (i = 0; i < SECTOR_SIZE / 2; i++) {
- seq_printf(m, "%04x%c", le16_to_cpu(val[i]),
- (i % 8) == 7 ? '\n' : ' ');
- }
- } else
- seq_putc(m, buf[0]);
- kfree(buf);
- return 0;
-}
-
-/**
- * ide_find_setting - find a specific setting
- * @st: setting table pointer
- * @name: setting name
- *
- * Scan's the setting table for a matching entry and returns
- * this or NULL if no entry is found. The caller must hold the
- * setting semaphore
- */
-
-static
-const struct ide_proc_devset *ide_find_setting(const struct ide_proc_devset *st,
- char *name)
-{
- while (st->name) {
- if (strcmp(st->name, name) == 0)
- break;
- st++;
- }
- return st->name ? st : NULL;
-}
-
-/**
- * ide_read_setting - read an IDE setting
- * @drive: drive to read from
- * @setting: drive setting
- *
- * Read a drive setting and return the value. The caller
- * must hold the ide_setting_mtx when making this call.
- *
- * BUGS: the data return and error are the same return value
- * so an error -EINVAL and true return of the same value cannot
- * be told apart
- */
-
-static int ide_read_setting(ide_drive_t *drive,
- const struct ide_proc_devset *setting)
-{
- const struct ide_devset *ds = setting->setting;
- int val = -EINVAL;
-
- if (ds->get)
- val = ds->get(drive);
-
- return val;
-}
-
-/**
- * ide_write_setting - read an IDE setting
- * @drive: drive to read from
- * @setting: drive setting
- * @val: value
- *
- * Write a drive setting if it is possible. The caller
- * must hold the ide_setting_mtx when making this call.
- *
- * BUGS: the data return and error are the same return value
- * so an error -EINVAL and true return of the same value cannot
- * be told apart
- *
- * FIXME: This should be changed to enqueue a special request
- * to the driver to change settings, and then wait on a sema for completion.
- * The current scheme of polling is kludgy, though safe enough.
- */
-
-static int ide_write_setting(ide_drive_t *drive,
- const struct ide_proc_devset *setting, int val)
-{
- const struct ide_devset *ds = setting->setting;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- if (!ds->set)
- return -EPERM;
- if ((ds->flags & DS_SYNC)
- && (val < setting->min || val > setting->max))
- return -EINVAL;
- return ide_devset_execute(drive, ds, val);
-}
-
-ide_devset_get(xfer_rate, current_speed);
-
-static int set_xfer_rate (ide_drive_t *drive, int arg)
-{
- struct ide_cmd cmd;
-
- if (arg < XFER_PIO_0 || arg > XFER_UDMA_6)
- return -EINVAL;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.tf.command = ATA_CMD_SET_FEATURES;
- cmd.tf.feature = SETFEATURES_XFER;
- cmd.tf.nsect = (u8)arg;
- cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT;
- cmd.valid.in.tf = IDE_VALID_NSECT;
- cmd.tf_flags = IDE_TFLAG_SET_XFER;
-
- return ide_no_data_taskfile(drive, &cmd);
-}
-
-ide_devset_rw(current_speed, xfer_rate);
-ide_devset_rw_field(init_speed, init_speed);
-ide_devset_rw_flag(nice1, IDE_DFLAG_NICE1);
-ide_devset_ro_field(number, dn);
-
-static const struct ide_proc_devset ide_generic_settings[] = {
- IDE_PROC_DEVSET(current_speed, 0, 70),
- IDE_PROC_DEVSET(init_speed, 0, 70),
- IDE_PROC_DEVSET(io_32bit, 0, 1 + (SUPPORT_VLB_SYNC << 1)),
- IDE_PROC_DEVSET(keepsettings, 0, 1),
- IDE_PROC_DEVSET(nice1, 0, 1),
- IDE_PROC_DEVSET(number, 0, 3),
- IDE_PROC_DEVSET(pio_mode, 0, 255),
- IDE_PROC_DEVSET(unmaskirq, 0, 1),
- IDE_PROC_DEVSET(using_dma, 0, 1),
- { NULL },
-};
-
-static void proc_ide_settings_warn(void)
-{
- printk_once(KERN_WARNING "Warning: /proc/ide/hd?/settings interface is "
- "obsolete, and will be removed soon!\n");
-}
-
-static int ide_settings_proc_show(struct seq_file *m, void *v)
-{
- const struct ide_proc_devset *setting, *g, *d;
- const struct ide_devset *ds;
- ide_drive_t *drive = (ide_drive_t *) m->private;
- int rc, mul_factor, div_factor;
-
- proc_ide_settings_warn();
-
- mutex_lock(&ide_setting_mtx);
- g = ide_generic_settings;
- d = drive->settings;
- seq_printf(m, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
- seq_printf(m, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
- while (g->name || (d && d->name)) {
- /* read settings in the alphabetical order */
- if (g->name && d && d->name) {
- if (strcmp(d->name, g->name) < 0)
- setting = d++;
- else
- setting = g++;
- } else if (d && d->name) {
- setting = d++;
- } else
- setting = g++;
- mul_factor = setting->mulf ? setting->mulf(drive) : 1;
- div_factor = setting->divf ? setting->divf(drive) : 1;
- seq_printf(m, "%-24s", setting->name);
- rc = ide_read_setting(drive, setting);
- if (rc >= 0)
- seq_printf(m, "%-16d", rc * mul_factor / div_factor);
- else
- seq_printf(m, "%-16s", "write-only");
- seq_printf(m, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
- ds = setting->setting;
- if (ds->get)
- seq_printf(m, "r");
- if (ds->set)
- seq_printf(m, "w");
- seq_printf(m, "\n");
- }
- mutex_unlock(&ide_setting_mtx);
- return 0;
-}
-
-static int ide_settings_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ide_settings_proc_show, PDE_DATA(inode));
-}
-
-#define MAX_LEN 30
-
-static ssize_t ide_settings_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *pos)
-{
- ide_drive_t *drive = PDE_DATA(file_inode(file));
- char name[MAX_LEN + 1];
- int for_real = 0, mul_factor, div_factor;
- unsigned long n;
-
- const struct ide_proc_devset *setting;
- char *buf, *s;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- proc_ide_settings_warn();
-
- if (count >= PAGE_SIZE)
- return -EINVAL;
-
- s = buf = (char *)__get_free_page(GFP_USER);
- if (!buf)
- return -ENOMEM;
-
- if (copy_from_user(buf, buffer, count)) {
- free_page((unsigned long)buf);
- return -EFAULT;
- }
-
- buf[count] = '\0';
-
- /*
- * Skip over leading whitespace
- */
- while (count && isspace(*s)) {
- --count;
- ++s;
- }
- /*
- * Do one full pass to verify all parameters,
- * then do another to actually write the new settings.
- */
- do {
- char *p = s;
- n = count;
- while (n > 0) {
- unsigned val;
- char *q = p;
-
- while (n > 0 && *p != ':') {
- --n;
- p++;
- }
- if (*p != ':')
- goto parse_error;
- if (p - q > MAX_LEN)
- goto parse_error;
- memcpy(name, q, p - q);
- name[p - q] = 0;
-
- if (n > 0) {
- --n;
- p++;
- } else
- goto parse_error;
-
- val = simple_strtoul(p, &q, 10);
- n -= q - p;
- p = q;
- if (n > 0 && !isspace(*p))
- goto parse_error;
- while (n > 0 && isspace(*p)) {
- --n;
- ++p;
- }
-
- mutex_lock(&ide_setting_mtx);
- /* generic settings first, then driver specific ones */
- setting = ide_find_setting(ide_generic_settings, name);
- if (!setting) {
- if (drive->settings)
- setting = ide_find_setting(drive->settings, name);
- if (!setting) {
- mutex_unlock(&ide_setting_mtx);
- goto parse_error;
- }
- }
- if (for_real) {
- mul_factor = setting->mulf ? setting->mulf(drive) : 1;
- div_factor = setting->divf ? setting->divf(drive) : 1;
- ide_write_setting(drive, setting, val * div_factor / mul_factor);
- }
- mutex_unlock(&ide_setting_mtx);
- }
- } while (!for_real++);
- free_page((unsigned long)buf);
- return count;
-parse_error:
- free_page((unsigned long)buf);
- printk("%s(): parse error\n", __func__);
- return -EINVAL;
-}
-
-static const struct proc_ops ide_settings_proc_ops = {
- .proc_open = ide_settings_proc_open,
- .proc_read = seq_read,
- .proc_lseek = seq_lseek,
- .proc_release = single_release,
- .proc_write = ide_settings_proc_write,
-};
-
-int ide_capacity_proc_show(struct seq_file *m, void *v)
-{
- seq_printf(m, "%llu\n", (long long)0x7fffffff);
- return 0;
-}
-EXPORT_SYMBOL_GPL(ide_capacity_proc_show);
-
-int ide_geometry_proc_show(struct seq_file *m, void *v)
-{
- ide_drive_t *drive = (ide_drive_t *) m->private;
-
- seq_printf(m, "physical %d/%d/%d\n",
- drive->cyl, drive->head, drive->sect);
- seq_printf(m, "logical %d/%d/%d\n",
- drive->bios_cyl, drive->bios_head, drive->bios_sect);
- return 0;
-}
-EXPORT_SYMBOL(ide_geometry_proc_show);
-
-static int ide_dmodel_proc_show(struct seq_file *seq, void *v)
-{
- ide_drive_t *drive = (ide_drive_t *) seq->private;
- char *m = (char *)&drive->id[ATA_ID_PROD];
-
- seq_printf(seq, "%.40s\n", m[0] ? m : "(none)");
- return 0;
-}
-
-static int ide_driver_proc_show(struct seq_file *m, void *v)
-{
- ide_drive_t *drive = (ide_drive_t *)m->private;
- struct device *dev = &drive->gendev;
- struct ide_driver *ide_drv;
-
- if (dev->driver) {
- ide_drv = to_ide_driver(dev->driver);
- seq_printf(m, "%s version %s\n",
- dev->driver->name, ide_drv->version);
- } else
- seq_printf(m, "ide-default version 0.9.newide\n");
- return 0;
-}
-
-static int ide_media_proc_show(struct seq_file *m, void *v)
-{
- ide_drive_t *drive = (ide_drive_t *) m->private;
- const char *media;
-
- switch (drive->media) {
- case ide_disk: media = "disk\n"; break;
- case ide_cdrom: media = "cdrom\n"; break;
- case ide_tape: media = "tape\n"; break;
- case ide_floppy: media = "floppy\n"; break;
- case ide_optical: media = "optical\n"; break;
- default: media = "UNKNOWN\n"; break;
- }
- seq_puts(m, media);
- return 0;
-}
-
-static int ide_media_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ide_media_proc_show, PDE_DATA(inode));
-}
-
-static const struct file_operations ide_media_proc_fops = {
- .owner = THIS_MODULE,
- .open = ide_media_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static ide_proc_entry_t generic_drive_entries[] = {
- { "driver", S_IFREG|S_IRUGO, ide_driver_proc_show },
- { "identify", S_IFREG|S_IRUSR, ide_identify_proc_show },
- { "media", S_IFREG|S_IRUGO, ide_media_proc_show },
- { "model", S_IFREG|S_IRUGO, ide_dmodel_proc_show },
- {}
-};
-
-static void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
-{
- struct proc_dir_entry *ent;
-
- if (!dir || !p)
- return;
- while (p->name != NULL) {
- ent = proc_create_single_data(p->name, p->mode, dir, p->show, data);
- if (!ent) return;
- p++;
- }
-}
-
-static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
-{
- if (!dir || !p)
- return;
- while (p->name != NULL) {
- remove_proc_entry(p->name, dir);
- p++;
- }
-}
-
-void ide_proc_register_driver(ide_drive_t *drive, struct ide_driver *driver)
-{
- mutex_lock(&ide_setting_mtx);
- drive->settings = driver->proc_devsets(drive);
- mutex_unlock(&ide_setting_mtx);
-
- ide_add_proc_entries(drive->proc, driver->proc_entries(drive), drive);
-}
-
-EXPORT_SYMBOL(ide_proc_register_driver);
-
-/**
- * ide_proc_unregister_driver - remove driver specific data
- * @drive: drive
- * @driver: driver
- *
- * Clean up the driver specific /proc files and IDE settings
- * for a given drive.
- *
- * Takes ide_setting_mtx.
- */
-
-void ide_proc_unregister_driver(ide_drive_t *drive, struct ide_driver *driver)
-{
- ide_remove_proc_entries(drive->proc, driver->proc_entries(drive));
-
- mutex_lock(&ide_setting_mtx);
- /*
- * ide_setting_mtx protects both the settings list and the use
- * of settings (we cannot take a setting out that is being used).
- */
- drive->settings = NULL;
- mutex_unlock(&ide_setting_mtx);
-}
-EXPORT_SYMBOL(ide_proc_unregister_driver);
-
-void ide_proc_port_register_devices(ide_hwif_t *hwif)
-{
- struct proc_dir_entry *ent;
- struct proc_dir_entry *parent = hwif->proc;
- ide_drive_t *drive;
- char name[64];
- int i;
-
- ide_port_for_each_dev(i, drive, hwif) {
- if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
- continue;
-
- drive->proc = proc_mkdir(drive->name, parent);
- if (drive->proc) {
- ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
- proc_create_data("settings", S_IFREG|S_IRUSR|S_IWUSR,
- drive->proc, &ide_settings_proc_ops,
- drive);
- }
- sprintf(name, "ide%d/%s", (drive->name[2]-'a')/2, drive->name);
- ent = proc_symlink(drive->name, proc_ide_root, name);
- if (!ent) return;
- }
-}
-
-void ide_proc_unregister_device(ide_drive_t *drive)
-{
- if (drive->proc) {
- remove_proc_entry("settings", drive->proc);
- ide_remove_proc_entries(drive->proc, generic_drive_entries);
- remove_proc_entry(drive->name, proc_ide_root);
- remove_proc_entry(drive->name, drive->hwif->proc);
- drive->proc = NULL;
- }
-}
-
-static ide_proc_entry_t hwif_entries[] = {
- { "channel", S_IFREG|S_IRUGO, ide_channel_proc_show },
- { "mate", S_IFREG|S_IRUGO, ide_mate_proc_show },
- { "model", S_IFREG|S_IRUGO, ide_imodel_proc_show },
- {}
-};
-
-void ide_proc_register_port(ide_hwif_t *hwif)
-{
- if (!hwif->proc) {
- hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
-
- if (!hwif->proc)
- return;
-
- ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
- }
-}
-
-void ide_proc_unregister_port(ide_hwif_t *hwif)
-{
- if (hwif->proc) {
- ide_remove_proc_entries(hwif->proc, hwif_entries);
- remove_proc_entry(hwif->name, proc_ide_root);
- hwif->proc = NULL;
- }
-}
-
-static int proc_print_driver(struct device_driver *drv, void *data)
-{
- struct ide_driver *ide_drv = to_ide_driver(drv);
- struct seq_file *s = data;
-
- seq_printf(s, "%s version %s\n", drv->name, ide_drv->version);
-
- return 0;
-}
-
-static int ide_drivers_show(struct seq_file *s, void *p)
-{
- int err;
-
- err = bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver);
- if (err < 0)
- printk(KERN_WARNING "IDE: %s: bus_for_each_drv error: %d\n",
- __func__, err);
- return 0;
-}
-
-DEFINE_PROC_SHOW_ATTRIBUTE(ide_drivers);
-
-void proc_ide_create(void)
-{
- proc_ide_root = proc_mkdir("ide", NULL);
-
- if (!proc_ide_root)
- return;
-
- proc_create("drivers", 0, proc_ide_root, &ide_drivers_proc_ops);
-}
-
-void proc_ide_destroy(void)
-{
- remove_proc_entry("drivers", proc_ide_root);
- remove_proc_entry("ide", NULL);
-}
diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c
deleted file mode 100644
index b0411a1827a3..000000000000
--- a/drivers/ide/ide-scan-pci.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * support for probing IDE PCI devices in the PCI bus order
- *
- * Copyright (c) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- * Copyright (c) 1995-1998 Mark Lord
- *
- * May be copied or modified under the terms of the GNU General Public License
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/ide.h>
-
-/*
- * Module interfaces
- */
-
-static int pre_init = 1; /* Before first ordered IDE scan */
-static LIST_HEAD(ide_pci_drivers);
-
-/*
- * __ide_pci_register_driver - attach IDE driver
- * @driver: pci driver
- * @module: owner module of the driver
- *
- * Registers a driver with the IDE layer. The IDE layer arranges that
- * boot time setup is done in the expected device order and then
- * hands the controllers off to the core PCI code to do the rest of
- * the work.
- *
- * Returns are the same as for pci_register_driver
- */
-
-int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
- const char *mod_name)
-{
- if (!pre_init)
- return __pci_register_driver(driver, module, mod_name);
- driver->driver.owner = module;
- list_add_tail(&driver->node, &ide_pci_drivers);
- return 0;
-}
-EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
-
-/**
- * ide_scan_pcidev - find an IDE driver for a device
- * @dev: PCI device to check
- *
- * Look for an IDE driver to handle the device we are considering.
- * This is only used during boot up to get the ordering correct. After
- * boot up the pci layer takes over the job.
- */
-
-static int __init ide_scan_pcidev(struct pci_dev *dev)
-{
- struct list_head *l;
- struct pci_driver *d;
- int ret;
-
- list_for_each(l, &ide_pci_drivers) {
- d = list_entry(l, struct pci_driver, node);
- if (d->id_table) {
- const struct pci_device_id *id =
- pci_match_id(d->id_table, dev);
-
- if (id != NULL) {
- pci_assign_irq(dev);
- ret = d->probe(dev, id);
- if (ret >= 0) {
- dev->driver = d;
- pci_dev_get(dev);
- return 1;
- }
- }
- }
- }
- return 0;
-}
-
-/**
- * ide_scan_pcibus - perform the initial IDE driver scan
- *
- * Perform the initial bus rather than driver ordered scan of the
- * PCI drivers. After this all IDE pci handling becomes standard
- * module ordering not traditionally ordered.
- */
-
-static int __init ide_scan_pcibus(void)
-{
- struct pci_dev *dev = NULL;
- struct pci_driver *d, *tmp;
-
- pre_init = 0;
- for_each_pci_dev(dev)
- ide_scan_pcidev(dev);
-
- /*
- * Hand the drivers over to the PCI layer now we
- * are post init.
- */
-
- list_for_each_entry_safe(d, tmp, &ide_pci_drivers, node) {
- list_del(&d->node);
- if (__pci_register_driver(d, d->driver.owner,
- d->driver.mod_name))
- printk(KERN_ERR "%s: failed to register %s driver\n",
- __func__, d->driver.mod_name);
- }
-
- return 0;
-}
-device_initcall(ide_scan_pcibus);
diff --git a/drivers/ide/ide-sysfs.c b/drivers/ide/ide-sysfs.c
deleted file mode 100644
index c08a8a0916e2..000000000000
--- a/drivers/ide/ide-sysfs.c
+++ /dev/null
@@ -1,143 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/kernel.h>
-#include <linux/ide.h>
-
-char *ide_media_string(ide_drive_t *drive)
-{
- switch (drive->media) {
- case ide_disk:
- return "disk";
- case ide_cdrom:
- return "cdrom";
- case ide_tape:
- return "tape";
- case ide_floppy:
- return "floppy";
- case ide_optical:
- return "optical";
- default:
- return "UNKNOWN";
- }
-}
-
-static ssize_t media_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- ide_drive_t *drive = to_ide_device(dev);
- return sprintf(buf, "%s\n", ide_media_string(drive));
-}
-static DEVICE_ATTR_RO(media);
-
-static ssize_t drivename_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- ide_drive_t *drive = to_ide_device(dev);
- return sprintf(buf, "%s\n", drive->name);
-}
-static DEVICE_ATTR_RO(drivename);
-
-static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- ide_drive_t *drive = to_ide_device(dev);
- return sprintf(buf, "ide:m-%s\n", ide_media_string(drive));
-}
-static DEVICE_ATTR_RO(modalias);
-
-static ssize_t model_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- ide_drive_t *drive = to_ide_device(dev);
- return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_PROD]);
-}
-static DEVICE_ATTR_RO(model);
-
-static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- ide_drive_t *drive = to_ide_device(dev);
- return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_FW_REV]);
-}
-static DEVICE_ATTR_RO(firmware);
-
-static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- ide_drive_t *drive = to_ide_device(dev);
- return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_SERNO]);
-}
-static DEVICE_ATTR(serial, 0400, serial_show, NULL);
-
-static DEVICE_ATTR(unload_heads, 0644, ide_park_show, ide_park_store);
-
-static struct attribute *ide_attrs[] = {
- &dev_attr_media.attr,
- &dev_attr_drivename.attr,
- &dev_attr_modalias.attr,
- &dev_attr_model.attr,
- &dev_attr_firmware.attr,
- &dev_attr_serial.attr,
- &dev_attr_unload_heads.attr,
- NULL,
-};
-
-static const struct attribute_group ide_attr_group = {
- .attrs = ide_attrs,
-};
-
-const struct attribute_group *ide_dev_groups[] = {
- &ide_attr_group,
- NULL,
-};
-
-static ssize_t store_delete_devices(struct device *portdev,
- struct device_attribute *attr,
- const char *buf, size_t n)
-{
- ide_hwif_t *hwif = dev_get_drvdata(portdev);
-
- if (strncmp(buf, "1", n))
- return -EINVAL;
-
- ide_port_unregister_devices(hwif);
-
- return n;
-};
-
-static DEVICE_ATTR(delete_devices, S_IWUSR, NULL, store_delete_devices);
-
-static ssize_t store_scan(struct device *portdev,
- struct device_attribute *attr,
- const char *buf, size_t n)
-{
- ide_hwif_t *hwif = dev_get_drvdata(portdev);
-
- if (strncmp(buf, "1", n))
- return -EINVAL;
-
- ide_port_unregister_devices(hwif);
- ide_port_scan(hwif);
-
- return n;
-};
-
-static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);
-
-static struct device_attribute *ide_port_attrs[] = {
- &dev_attr_delete_devices,
- &dev_attr_scan,
- NULL
-};
-
-int ide_sysfs_register_port(ide_hwif_t *hwif)
-{
- int i, rc;
-
- for (i = 0; ide_port_attrs[i]; i++) {
- rc = device_create_file(hwif->portdev, ide_port_attrs[i]);
- if (rc)
- break;
- }
-
- return rc;
-}
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
deleted file mode 100644
index fa05e7e7d609..000000000000
--- a/drivers/ide/ide-tape.c
+++ /dev/null
@@ -1,2083 +0,0 @@
-/*
- * IDE ATAPI streaming tape driver.
- *
- * Copyright (C) 1995-1999 Gadi Oxman <gadio@netvision.net.il>
- * Copyright (C) 2003-2005 Bartlomiej Zolnierkiewicz
- *
- * This driver was constructed as a student project in the software laboratory
- * of the faculty of electrical engineering in the Technion - Israel's
- * Institute Of Technology, with the guide of Avner Lottem and Dr. Ilana David.
- *
- * It is hereby placed under the terms of the GNU general public license.
- * (See linux/COPYING).
- *
- * For a historical changelog see
- * Documentation/ide/ChangeLog.ide-tape.1995-2002
- */
-
-#define DRV_NAME "ide-tape"
-
-#define IDETAPE_VERSION "1.20"
-
-#include <linux/compat.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/jiffies.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/completion.h>
-#include <linux/bitops.h>
-#include <linux/mutex.h>
-#include <scsi/scsi.h>
-
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <asm/unaligned.h>
-#include <linux/mtio.h>
-
-/* define to see debug info */
-#undef IDETAPE_DEBUG_LOG
-
-#ifdef IDETAPE_DEBUG_LOG
-#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args)
-#else
-#define ide_debug_log(lvl, fmt, args...) do {} while (0)
-#endif
-
-/**************************** Tunable parameters *****************************/
-/*
- * After each failed packet command we issue a request sense command and retry
- * the packet command IDETAPE_MAX_PC_RETRIES times.
- *
- * Setting IDETAPE_MAX_PC_RETRIES to 0 will disable retries.
- */
-#define IDETAPE_MAX_PC_RETRIES 3
-
-/*
- * The following parameter is used to select the point in the internal tape fifo
- * in which we will start to refill the buffer. Decreasing the following
- * parameter will improve the system's latency and interactive response, while
- * using a high value might improve system throughput.
- */
-#define IDETAPE_FIFO_THRESHOLD 2
-
-/*
- * DSC polling parameters.
- *
- * Polling for DSC (a single bit in the status register) is a very important
- * function in ide-tape. There are two cases in which we poll for DSC:
- *
- * 1. Before a read/write packet command, to ensure that we can transfer data
- * from/to the tape's data buffers, without causing an actual media access.
- * In case the tape is not ready yet, we take out our request from the device
- * request queue, so that ide.c could service requests from the other device
- * on the same interface in the meantime.
- *
- * 2. After the successful initialization of a "media access packet command",
- * which is a command that can take a long time to complete (the interval can
- * range from several seconds to even an hour). Again, we postpone our request
- * in the middle to free the bus for the other device. The polling frequency
- * here should be lower than the read/write frequency since those media access
- * commands are slow. We start from a "fast" frequency - IDETAPE_DSC_MA_FAST
- * (1 second), and if we don't receive DSC after IDETAPE_DSC_MA_THRESHOLD
- * (5 min), we switch it to a lower frequency - IDETAPE_DSC_MA_SLOW (1 min).
- *
- * We also set a timeout for the timer, in case something goes wrong. The
- * timeout should be longer then the maximum execution time of a tape operation.
- */
-
-/* DSC timings. */
-#define IDETAPE_DSC_RW_MIN 5*HZ/100 /* 50 msec */
-#define IDETAPE_DSC_RW_MAX 40*HZ/100 /* 400 msec */
-#define IDETAPE_DSC_RW_TIMEOUT 2*60*HZ /* 2 minutes */
-#define IDETAPE_DSC_MA_FAST 2*HZ /* 2 seconds */
-#define IDETAPE_DSC_MA_THRESHOLD 5*60*HZ /* 5 minutes */
-#define IDETAPE_DSC_MA_SLOW 30*HZ /* 30 seconds */
-#define IDETAPE_DSC_MA_TIMEOUT 2*60*60*HZ /* 2 hours */
-
-/*************************** End of tunable parameters ***********************/
-
-/* tape directions */
-enum {
- IDETAPE_DIR_NONE = (1 << 0),
- IDETAPE_DIR_READ = (1 << 1),
- IDETAPE_DIR_WRITE = (1 << 2),
-};
-
-/* Tape door status */
-#define DOOR_UNLOCKED 0
-#define DOOR_LOCKED 1
-#define DOOR_EXPLICITLY_LOCKED 2
-
-/* Some defines for the SPACE command */
-#define IDETAPE_SPACE_OVER_FILEMARK 1
-#define IDETAPE_SPACE_TO_EOD 3
-
-/* Some defines for the LOAD UNLOAD command */
-#define IDETAPE_LU_LOAD_MASK 1
-#define IDETAPE_LU_RETENSION_MASK 2
-#define IDETAPE_LU_EOT_MASK 4
-
-/* Structures related to the SELECT SENSE / MODE SENSE packet commands. */
-#define IDETAPE_BLOCK_DESCRIPTOR 0
-#define IDETAPE_CAPABILITIES_PAGE 0x2a
-
-/*
- * Most of our global data which we need to save even as we leave the driver due
- * to an interrupt or a timer event is stored in the struct defined below.
- */
-typedef struct ide_tape_obj {
- ide_drive_t *drive;
- struct ide_driver *driver;
- struct gendisk *disk;
- struct device dev;
-
- /* used by REQ_IDETAPE_{READ,WRITE} requests */
- struct ide_atapi_pc queued_pc;
-
- /*
- * DSC polling variables.
- *
- * While polling for DSC we use postponed_rq to postpone the current
- * request so that ide.c will be able to service pending requests on the
- * other device. Note that at most we will have only one DSC (usually
- * data transfer) request in the device request queue.
- */
- bool postponed_rq;
-
- /* The time in which we started polling for DSC */
- unsigned long dsc_polling_start;
- /* Timer used to poll for dsc */
- struct timer_list dsc_timer;
- /* Read/Write dsc polling frequency */
- unsigned long best_dsc_rw_freq;
- unsigned long dsc_poll_freq;
- unsigned long dsc_timeout;
-
- /* Read position information */
- u8 partition;
- /* Current block */
- unsigned int first_frame;
-
- /* Last error information */
- u8 sense_key, asc, ascq;
-
- /* Character device operation */
- unsigned int minor;
- /* device name */
- char name[4];
- /* Current character device data transfer direction */
- u8 chrdev_dir;
-
- /* tape block size, usually 512 or 1024 bytes */
- unsigned short blk_size;
- int user_bs_factor;
-
- /* Copy of the tape's Capabilities and Mechanical Page */
- u8 caps[20];
-
- /*
- * Active data transfer request parameters.
- *
- * At most, there is only one ide-tape originated data transfer request
- * in the device request queue. This allows ide.c to easily service
- * requests from the other device when we postpone our active request.
- */
-
- /* Data buffer size chosen based on the tape's recommendation */
- int buffer_size;
- /* Staging buffer of buffer_size bytes */
- void *buf;
- /* The read/write cursor */
- void *cur;
- /* The number of valid bytes in buf */
- size_t valid;
-
- /* Measures average tape speed */
- unsigned long avg_time;
- int avg_size;
- int avg_speed;
-
- /* the door is currently locked */
- int door_locked;
- /* the tape hardware is write protected */
- char drv_write_prot;
- /* the tape is write protected (hardware or opened as read-only) */
- char write_prot;
-} idetape_tape_t;
-
-static DEFINE_MUTEX(ide_tape_mutex);
-static DEFINE_MUTEX(idetape_ref_mutex);
-
-static DEFINE_MUTEX(idetape_chrdev_mutex);
-
-static struct class *idetape_sysfs_class;
-
-static void ide_tape_release(struct device *);
-
-static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES];
-
-static struct ide_tape_obj *ide_tape_get(struct gendisk *disk, bool cdev,
- unsigned int i)
-{
- struct ide_tape_obj *tape = NULL;
-
- mutex_lock(&idetape_ref_mutex);
-
- if (cdev)
- tape = idetape_devs[i];
- else
- tape = ide_drv_g(disk, ide_tape_obj);
-
- if (tape) {
- if (ide_device_get(tape->drive))
- tape = NULL;
- else
- get_device(&tape->dev);
- }
-
- mutex_unlock(&idetape_ref_mutex);
- return tape;
-}
-
-static void ide_tape_put(struct ide_tape_obj *tape)
-{
- ide_drive_t *drive = tape->drive;
-
- mutex_lock(&idetape_ref_mutex);
- put_device(&tape->dev);
- ide_device_put(drive);
- mutex_unlock(&idetape_ref_mutex);
-}
-
-/*
- * called on each failed packet command retry to analyze the request sense. We
- * currently do not utilize this information.
- */
-static void idetape_analyze_error(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
- struct ide_atapi_pc *pc = drive->failed_pc;
- struct request *rq = drive->hwif->rq;
- u8 *sense = bio_data(rq->bio);
-
- tape->sense_key = sense[2] & 0xF;
- tape->asc = sense[12];
- tape->ascq = sense[13];
-
- ide_debug_log(IDE_DBG_FUNC,
- "cmd: 0x%x, sense key = %x, asc = %x, ascq = %x",
- rq->cmd[0], tape->sense_key, tape->asc, tape->ascq);
-
- /* correct remaining bytes to transfer */
- if (pc->flags & PC_FLAG_DMA_ERROR)
- scsi_req(rq)->resid_len = tape->blk_size * get_unaligned_be32(&sense[3]);
-
- /*
- * If error was the result of a zero-length read or write command,
- * with sense key=5, asc=0x22, ascq=0, let it slide. Some drives
- * (i.e. Seagate STT3401A Travan) don't support 0-length read/writes.
- */
- if ((pc->c[0] == READ_6 || pc->c[0] == WRITE_6)
- /* length == 0 */
- && pc->c[4] == 0 && pc->c[3] == 0 && pc->c[2] == 0) {
- if (tape->sense_key == 5) {
- /* don't report an error, everything's ok */
- pc->error = 0;
- /* don't retry read/write */
- pc->flags |= PC_FLAG_ABORT;
- }
- }
- if (pc->c[0] == READ_6 && (sense[2] & 0x80)) {
- pc->error = IDE_DRV_ERROR_FILEMARK;
- pc->flags |= PC_FLAG_ABORT;
- }
- if (pc->c[0] == WRITE_6) {
- if ((sense[2] & 0x40) || (tape->sense_key == 0xd
- && tape->asc == 0x0 && tape->ascq == 0x2)) {
- pc->error = IDE_DRV_ERROR_EOD;
- pc->flags |= PC_FLAG_ABORT;
- }
- }
- if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) {
- if (tape->sense_key == 8) {
- pc->error = IDE_DRV_ERROR_EOD;
- pc->flags |= PC_FLAG_ABORT;
- }
- if (!(pc->flags & PC_FLAG_ABORT) &&
- (blk_rq_bytes(rq) - scsi_req(rq)->resid_len))
- pc->retries = IDETAPE_MAX_PC_RETRIES + 1;
- }
-}
-
-static void ide_tape_handle_dsc(ide_drive_t *);
-
-static int ide_tape_callback(ide_drive_t *drive, int dsc)
-{
- idetape_tape_t *tape = drive->driver_data;
- struct ide_atapi_pc *pc = drive->pc;
- struct request *rq = drive->hwif->rq;
- int uptodate = pc->error ? 0 : 1;
- int err = uptodate ? 0 : IDE_DRV_ERROR_GENERAL;
-
- ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, dsc: %d, err: %d", rq->cmd[0],
- dsc, err);
-
- if (dsc)
- ide_tape_handle_dsc(drive);
-
- if (drive->failed_pc == pc)
- drive->failed_pc = NULL;
-
- if (pc->c[0] == REQUEST_SENSE) {
- if (uptodate)
- idetape_analyze_error(drive);
- else
- printk(KERN_ERR "ide-tape: Error in REQUEST SENSE "
- "itself - Aborting request!\n");
- } else if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) {
- unsigned int blocks =
- (blk_rq_bytes(rq) - scsi_req(rq)->resid_len) / tape->blk_size;
-
- tape->avg_size += blocks * tape->blk_size;
-
- if (time_after_eq(jiffies, tape->avg_time + HZ)) {
- tape->avg_speed = tape->avg_size * HZ /
- (jiffies - tape->avg_time) / 1024;
- tape->avg_size = 0;
- tape->avg_time = jiffies;
- }
-
- tape->first_frame += blocks;
-
- if (pc->error) {
- uptodate = 0;
- err = pc->error;
- }
- }
- scsi_req(rq)->result = err;
-
- return uptodate;
-}
-
-/*
- * Postpone the current request so that ide.c will be able to service requests
- * from another device on the same port while we are polling for DSC.
- */
-static void ide_tape_stall_queue(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
-
- ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, dsc_poll_freq: %lu",
- drive->hwif->rq->cmd[0], tape->dsc_poll_freq);
-
- tape->postponed_rq = true;
-
- ide_stall_queue(drive, tape->dsc_poll_freq);
-}
-
-static void ide_tape_handle_dsc(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
-
- /* Media access command */
- tape->dsc_polling_start = jiffies;
- tape->dsc_poll_freq = IDETAPE_DSC_MA_FAST;
- tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
- /* Allow ide.c to handle other requests */
- ide_tape_stall_queue(drive);
-}
-
-/*
- * Packet Command Interface
- *
- * The current Packet Command is available in drive->pc, and will not change
- * until we finish handling it. Each packet command is associated with a
- * callback function that will be called when the command is finished.
- *
- * The handling will be done in three stages:
- *
- * 1. ide_tape_issue_pc will send the packet command to the drive, and will set
- * the interrupt handler to ide_pc_intr.
- *
- * 2. On each interrupt, ide_pc_intr will be called. This step will be
- * repeated until the device signals us that no more interrupts will be issued.
- *
- * 3. ATAPI Tape media access commands have immediate status with a delayed
- * process. In case of a successful initiation of a media access packet command,
- * the DSC bit will be set when the actual execution of the command is finished.
- * Since the tape drive will not issue an interrupt, we have to poll for this
- * event. In this case, we define the request as "low priority request" by
- * setting rq_status to IDETAPE_RQ_POSTPONED, set a timer to poll for DSC and
- * exit the driver.
- *
- * ide.c will then give higher priority to requests which originate from the
- * other device, until will change rq_status to RQ_ACTIVE.
- *
- * 4. When the packet command is finished, it will be checked for errors.
- *
- * 5. In case an error was found, we queue a request sense packet command in
- * front of the request queue and retry the operation up to
- * IDETAPE_MAX_PC_RETRIES times.
- *
- * 6. In case no error was found, or we decided to give up and not to retry
- * again, the callback function will be called and then we will handle the next
- * request.
- */
-
-static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive,
- struct ide_cmd *cmd,
- struct ide_atapi_pc *pc)
-{
- idetape_tape_t *tape = drive->driver_data;
- struct request *rq = drive->hwif->rq;
-
- if (drive->failed_pc == NULL && pc->c[0] != REQUEST_SENSE)
- drive->failed_pc = pc;
-
- /* Set the current packet command */
- drive->pc = pc;
-
- if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
- (pc->flags & PC_FLAG_ABORT)) {
-
- /*
- * We will "abort" retrying a packet command in case legitimate
- * error code was received (crossing a filemark, or end of the
- * media, for example).
- */
- if (!(pc->flags & PC_FLAG_ABORT)) {
- if (!(pc->c[0] == TEST_UNIT_READY &&
- tape->sense_key == 2 && tape->asc == 4 &&
- (tape->ascq == 1 || tape->ascq == 8))) {
- printk(KERN_ERR "ide-tape: %s: I/O error, "
- "pc = %2x, key = %2x, "
- "asc = %2x, ascq = %2x\n",
- tape->name, pc->c[0],
- tape->sense_key, tape->asc,
- tape->ascq);
- }
- /* Giving up */
- pc->error = IDE_DRV_ERROR_GENERAL;
- }
-
- drive->failed_pc = NULL;
- drive->pc_callback(drive, 0);
- ide_complete_rq(drive, BLK_STS_IOERR, blk_rq_bytes(rq));
- return ide_stopped;
- }
- ide_debug_log(IDE_DBG_SENSE, "retry #%d, cmd: 0x%02x", pc->retries,
- pc->c[0]);
-
- pc->retries++;
-
- return ide_issue_pc(drive, cmd);
-}
-
-/* A mode sense command is used to "sense" tape parameters. */
-static void idetape_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code)
-{
- ide_init_pc(pc);
- pc->c[0] = MODE_SENSE;
- if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
- /* DBD = 1 - Don't return block descriptors */
- pc->c[1] = 8;
- pc->c[2] = page_code;
- /*
- * Changed pc->c[3] to 0 (255 will at best return unused info).
- *
- * For SCSI this byte is defined as subpage instead of high byte
- * of length and some IDE drives seem to interpret it this way
- * and return an error when 255 is used.
- */
- pc->c[3] = 0;
- /* We will just discard data in that case */
- pc->c[4] = 255;
- if (page_code == IDETAPE_BLOCK_DESCRIPTOR)
- pc->req_xfer = 12;
- else if (page_code == IDETAPE_CAPABILITIES_PAGE)
- pc->req_xfer = 24;
- else
- pc->req_xfer = 50;
-}
-
-static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- idetape_tape_t *tape = drive->driver_data;
- struct ide_atapi_pc *pc = drive->pc;
- u8 stat;
-
- stat = hwif->tp_ops->read_status(hwif);
-
- if (stat & ATA_DSC) {
- if (stat & ATA_ERR) {
- /* Error detected */
- if (pc->c[0] != TEST_UNIT_READY)
- printk(KERN_ERR "ide-tape: %s: I/O error, ",
- tape->name);
- /* Retry operation */
- ide_retry_pc(drive);
- return ide_stopped;
- }
- pc->error = 0;
- } else {
- pc->error = IDE_DRV_ERROR_GENERAL;
- drive->failed_pc = NULL;
- }
- drive->pc_callback(drive, 0);
- return ide_stopped;
-}
-
-static void ide_tape_create_rw_cmd(idetape_tape_t *tape,
- struct ide_atapi_pc *pc, struct request *rq,
- u8 opcode)
-{
- unsigned int length = blk_rq_sectors(rq) / (tape->blk_size >> 9);
-
- ide_init_pc(pc);
- put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
- pc->c[1] = 1;
-
- if (blk_rq_bytes(rq) == tape->buffer_size)
- pc->flags |= PC_FLAG_DMA_OK;
-
- if (opcode == READ_6)
- pc->c[0] = READ_6;
- else if (opcode == WRITE_6) {
- pc->c[0] = WRITE_6;
- pc->flags |= PC_FLAG_WRITING;
- }
-
- memcpy(scsi_req(rq)->cmd, pc->c, 12);
-}
-
-static ide_startstop_t idetape_do_request(ide_drive_t *drive,
- struct request *rq, sector_t block)
-{
- ide_hwif_t *hwif = drive->hwif;
- idetape_tape_t *tape = drive->driver_data;
- struct ide_atapi_pc *pc = NULL;
- struct ide_cmd cmd;
- struct scsi_request *req = scsi_req(rq);
- u8 stat;
-
- ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, sector: %llu, nr_sectors: %u",
- req->cmd[0], (unsigned long long)blk_rq_pos(rq),
- blk_rq_sectors(rq));
-
- BUG_ON(!blk_rq_is_private(rq));
- BUG_ON(ide_req(rq)->type != ATA_PRIV_MISC &&
- ide_req(rq)->type != ATA_PRIV_SENSE);
-
- /* Retry a failed packet command */
- if (drive->failed_pc && drive->pc->c[0] == REQUEST_SENSE) {
- pc = drive->failed_pc;
- goto out;
- }
-
- /*
- * If the tape is still busy, postpone our request and service
- * the other device meanwhile.
- */
- stat = hwif->tp_ops->read_status(hwif);
-
- if ((drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) == 0 &&
- (req->cmd[13] & REQ_IDETAPE_PC2) == 0)
- drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
-
- if (drive->dev_flags & IDE_DFLAG_POST_RESET) {
- drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
- drive->dev_flags &= ~IDE_DFLAG_POST_RESET;
- }
-
- if (!(drive->atapi_flags & IDE_AFLAG_IGNORE_DSC) &&
- !(stat & ATA_DSC)) {
- if (!tape->postponed_rq) {
- tape->dsc_polling_start = jiffies;
- tape->dsc_poll_freq = tape->best_dsc_rw_freq;
- tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
- } else if (time_after(jiffies, tape->dsc_timeout)) {
- printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
- tape->name);
- if (req->cmd[13] & REQ_IDETAPE_PC2) {
- idetape_media_access_finished(drive);
- return ide_stopped;
- } else {
- return ide_do_reset(drive);
- }
- } else if (time_after(jiffies,
- tape->dsc_polling_start +
- IDETAPE_DSC_MA_THRESHOLD))
- tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW;
- ide_tape_stall_queue(drive);
- return ide_stopped;
- } else {
- drive->atapi_flags &= ~IDE_AFLAG_IGNORE_DSC;
- tape->postponed_rq = false;
- }
-
- if (req->cmd[13] & REQ_IDETAPE_READ) {
- pc = &tape->queued_pc;
- ide_tape_create_rw_cmd(tape, pc, rq, READ_6);
- goto out;
- }
- if (req->cmd[13] & REQ_IDETAPE_WRITE) {
- pc = &tape->queued_pc;
- ide_tape_create_rw_cmd(tape, pc, rq, WRITE_6);
- goto out;
- }
- if (req->cmd[13] & REQ_IDETAPE_PC1) {
- pc = (struct ide_atapi_pc *)ide_req(rq)->special;
- req->cmd[13] &= ~(REQ_IDETAPE_PC1);
- req->cmd[13] |= REQ_IDETAPE_PC2;
- goto out;
- }
- if (req->cmd[13] & REQ_IDETAPE_PC2) {
- idetape_media_access_finished(drive);
- return ide_stopped;
- }
- BUG();
-
-out:
- /* prepare sense request for this command */
- ide_prep_sense(drive, rq);
-
- memset(&cmd, 0, sizeof(cmd));
-
- if (rq_data_dir(rq))
- cmd.tf_flags |= IDE_TFLAG_WRITE;
-
- cmd.rq = rq;
-
- ide_init_sg_cmd(&cmd, blk_rq_bytes(rq));
- ide_map_sg(drive, &cmd);
-
- return ide_tape_issue_pc(drive, &cmd, pc);
-}
-
-/*
- * Write a filemark if write_filemark=1. Flush the device buffers without
- * writing a filemark otherwise.
- */
-static void idetape_create_write_filemark_cmd(ide_drive_t *drive,
- struct ide_atapi_pc *pc, int write_filemark)
-{
- ide_init_pc(pc);
- pc->c[0] = WRITE_FILEMARKS;
- pc->c[4] = write_filemark;
- pc->flags |= PC_FLAG_WAIT_FOR_DSC;
-}
-
-static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
-{
- idetape_tape_t *tape = drive->driver_data;
- struct gendisk *disk = tape->disk;
- int load_attempted = 0;
-
- /* Wait for the tape to become ready */
- set_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), &drive->atapi_flags);
- timeout += jiffies;
- while (time_before(jiffies, timeout)) {
- if (ide_do_test_unit_ready(drive, disk) == 0)
- return 0;
- if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2)
- || (tape->asc == 0x3A)) {
- /* no media */
- if (load_attempted)
- return -ENOMEDIUM;
- ide_do_start_stop(drive, disk, IDETAPE_LU_LOAD_MASK);
- load_attempted = 1;
- /* not about to be ready */
- } else if (!(tape->sense_key == 2 && tape->asc == 4 &&
- (tape->ascq == 1 || tape->ascq == 8)))
- return -EIO;
- msleep(100);
- }
- return -EIO;
-}
-
-static int idetape_flush_tape_buffers(ide_drive_t *drive)
-{
- struct ide_tape_obj *tape = drive->driver_data;
- struct ide_atapi_pc pc;
- int rc;
-
- idetape_create_write_filemark_cmd(drive, &pc, 0);
- rc = ide_queue_pc_tail(drive, tape->disk, &pc, NULL, 0);
- if (rc)
- return rc;
- idetape_wait_ready(drive, 60 * 5 * HZ);
- return 0;
-}
-
-static int ide_tape_read_position(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
- struct ide_atapi_pc pc;
- u8 buf[20];
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- /* prep cmd */
- ide_init_pc(&pc);
- pc.c[0] = READ_POSITION;
- pc.req_xfer = 20;
-
- if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer))
- return -1;
-
- if (!pc.error) {
- ide_debug_log(IDE_DBG_FUNC, "BOP - %s",
- (buf[0] & 0x80) ? "Yes" : "No");
- ide_debug_log(IDE_DBG_FUNC, "EOP - %s",
- (buf[0] & 0x40) ? "Yes" : "No");
-
- if (buf[0] & 0x4) {
- printk(KERN_INFO "ide-tape: Block location is unknown"
- "to the tape\n");
- clear_bit(ilog2(IDE_AFLAG_ADDRESS_VALID),
- &drive->atapi_flags);
- return -1;
- } else {
- ide_debug_log(IDE_DBG_FUNC, "Block Location: %u",
- be32_to_cpup((__be32 *)&buf[4]));
-
- tape->partition = buf[1];
- tape->first_frame = be32_to_cpup((__be32 *)&buf[4]);
- set_bit(ilog2(IDE_AFLAG_ADDRESS_VALID),
- &drive->atapi_flags);
- }
- }
-
- return tape->first_frame;
-}
-
-static void idetape_create_locate_cmd(ide_drive_t *drive,
- struct ide_atapi_pc *pc,
- unsigned int block, u8 partition, int skip)
-{
- ide_init_pc(pc);
- pc->c[0] = POSITION_TO_ELEMENT;
- pc->c[1] = 2;
- put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[3]);
- pc->c[8] = partition;
- pc->flags |= PC_FLAG_WAIT_FOR_DSC;
-}
-
-static void __ide_tape_discard_merge_buffer(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
-
- if (tape->chrdev_dir != IDETAPE_DIR_READ)
- return;
-
- clear_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags);
- tape->valid = 0;
- if (tape->buf != NULL) {
- kfree(tape->buf);
- tape->buf = NULL;
- }
-
- tape->chrdev_dir = IDETAPE_DIR_NONE;
-}
-
-/*
- * Position the tape to the requested block using the LOCATE packet command.
- * A READ POSITION command is then issued to check where we are positioned. Like
- * all higher level operations, we queue the commands at the tail of the request
- * queue and wait for their completion.
- */
-static int idetape_position_tape(ide_drive_t *drive, unsigned int block,
- u8 partition, int skip)
-{
- idetape_tape_t *tape = drive->driver_data;
- struct gendisk *disk = tape->disk;
- int ret;
- struct ide_atapi_pc pc;
-
- if (tape->chrdev_dir == IDETAPE_DIR_READ)
- __ide_tape_discard_merge_buffer(drive);
- idetape_wait_ready(drive, 60 * 5 * HZ);
- idetape_create_locate_cmd(drive, &pc, block, partition, skip);
- ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
- if (ret)
- return ret;
-
- ret = ide_tape_read_position(drive);
- if (ret < 0)
- return ret;
- return 0;
-}
-
-static void ide_tape_discard_merge_buffer(ide_drive_t *drive,
- int restore_position)
-{
- idetape_tape_t *tape = drive->driver_data;
- int seek, position;
-
- __ide_tape_discard_merge_buffer(drive);
- if (restore_position) {
- position = ide_tape_read_position(drive);
- seek = position > 0 ? position : 0;
- if (idetape_position_tape(drive, seek, 0, 0)) {
- printk(KERN_INFO "ide-tape: %s: position_tape failed in"
- " %s\n", tape->name, __func__);
- return;
- }
- }
-}
-
-/*
- * Generate a read/write request for the block device interface and wait for it
- * to be serviced.
- */
-static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size)
-{
- idetape_tape_t *tape = drive->driver_data;
- struct request *rq;
- int ret;
-
- ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, size: %d", cmd, size);
-
- BUG_ON(cmd != REQ_IDETAPE_READ && cmd != REQ_IDETAPE_WRITE);
- BUG_ON(size < 0 || size % tape->blk_size);
-
- rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
- ide_req(rq)->type = ATA_PRIV_MISC;
- scsi_req(rq)->cmd[13] = cmd;
- rq->rq_disk = tape->disk;
- rq->__sector = tape->first_frame;
-
- if (size) {
- ret = blk_rq_map_kern(drive->queue, rq, tape->buf, size,
- GFP_NOIO);
- if (ret)
- goto out_put;
- }
-
- blk_execute_rq(tape->disk, rq, 0);
-
- /* calculate the number of transferred bytes and update buffer state */
- size -= scsi_req(rq)->resid_len;
- tape->cur = tape->buf;
- if (cmd == REQ_IDETAPE_READ)
- tape->valid = size;
- else
- tape->valid = 0;
-
- ret = size;
- if (scsi_req(rq)->result == IDE_DRV_ERROR_GENERAL)
- ret = -EIO;
-out_put:
- blk_put_request(rq);
- return ret;
-}
-
-static void idetape_create_inquiry_cmd(struct ide_atapi_pc *pc)
-{
- ide_init_pc(pc);
- pc->c[0] = INQUIRY;
- pc->c[4] = 254;
- pc->req_xfer = 254;
-}
-
-static void idetape_create_rewind_cmd(ide_drive_t *drive,
- struct ide_atapi_pc *pc)
-{
- ide_init_pc(pc);
- pc->c[0] = REZERO_UNIT;
- pc->flags |= PC_FLAG_WAIT_FOR_DSC;
-}
-
-static void idetape_create_erase_cmd(struct ide_atapi_pc *pc)
-{
- ide_init_pc(pc);
- pc->c[0] = ERASE;
- pc->c[1] = 1;
- pc->flags |= PC_FLAG_WAIT_FOR_DSC;
-}
-
-static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd)
-{
- ide_init_pc(pc);
- pc->c[0] = SPACE;
- put_unaligned(cpu_to_be32(count), (unsigned int *) &pc->c[1]);
- pc->c[1] = cmd;
- pc->flags |= PC_FLAG_WAIT_FOR_DSC;
-}
-
-static void ide_tape_flush_merge_buffer(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
-
- if (tape->chrdev_dir != IDETAPE_DIR_WRITE) {
- printk(KERN_ERR "ide-tape: bug: Trying to empty merge buffer"
- " but we are not writing.\n");
- return;
- }
- if (tape->buf) {
- size_t aligned = roundup(tape->valid, tape->blk_size);
-
- memset(tape->cur, 0, aligned - tape->valid);
- idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, aligned);
- kfree(tape->buf);
- tape->buf = NULL;
- }
- tape->chrdev_dir = IDETAPE_DIR_NONE;
-}
-
-static int idetape_init_rw(ide_drive_t *drive, int dir)
-{
- idetape_tape_t *tape = drive->driver_data;
- int rc;
-
- BUG_ON(dir != IDETAPE_DIR_READ && dir != IDETAPE_DIR_WRITE);
-
- if (tape->chrdev_dir == dir)
- return 0;
-
- if (tape->chrdev_dir == IDETAPE_DIR_READ)
- ide_tape_discard_merge_buffer(drive, 1);
- else if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
- ide_tape_flush_merge_buffer(drive);
- idetape_flush_tape_buffers(drive);
- }
-
- if (tape->buf || tape->valid) {
- printk(KERN_ERR "ide-tape: valid should be 0 now\n");
- tape->valid = 0;
- }
-
- tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL);
- if (!tape->buf)
- return -ENOMEM;
- tape->chrdev_dir = dir;
- tape->cur = tape->buf;
-
- /*
- * Issue a 0 rw command to ensure that DSC handshake is
- * switched from completion mode to buffer available mode. No
- * point in issuing this if DSC overlap isn't supported, some
- * drives (Seagate STT3401A) will return an error.
- */
- if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) {
- int cmd = dir == IDETAPE_DIR_READ ? REQ_IDETAPE_READ
- : REQ_IDETAPE_WRITE;
-
- rc = idetape_queue_rw_tail(drive, cmd, 0);
- if (rc < 0) {
- kfree(tape->buf);
- tape->buf = NULL;
- tape->chrdev_dir = IDETAPE_DIR_NONE;
- return rc;
- }
- }
-
- return 0;
-}
-
-static void idetape_pad_zeros(ide_drive_t *drive, int bcount)
-{
- idetape_tape_t *tape = drive->driver_data;
-
- memset(tape->buf, 0, tape->buffer_size);
-
- while (bcount) {
- unsigned int count = min(tape->buffer_size, bcount);
-
- idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, count);
- bcount -= count;
- }
-}
-
-/*
- * Rewinds the tape to the Beginning Of the current Partition (BOP). We
- * currently support only one partition.
- */
-static int idetape_rewind_tape(ide_drive_t *drive)
-{
- struct ide_tape_obj *tape = drive->driver_data;
- struct gendisk *disk = tape->disk;
- struct ide_atapi_pc pc;
- int ret;
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- idetape_create_rewind_cmd(drive, &pc);
- ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
- if (ret)
- return ret;
-
- ret = ide_tape_read_position(drive);
- if (ret < 0)
- return ret;
- return 0;
-}
-
-/* mtio.h compatible commands should be issued to the chrdev interface. */
-static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd,
- unsigned long arg)
-{
- idetape_tape_t *tape = drive->driver_data;
- void __user *argp = (void __user *)arg;
-
- struct idetape_config {
- int dsc_rw_frequency;
- int dsc_media_access_frequency;
- int nr_stages;
- } config;
-
- ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%04x", cmd);
-
- switch (cmd) {
- case 0x0340:
- if (copy_from_user(&config, argp, sizeof(config)))
- return -EFAULT;
- tape->best_dsc_rw_freq = config.dsc_rw_frequency;
- break;
- case 0x0350:
- memset(&config, 0, sizeof(config));
- config.dsc_rw_frequency = (int) tape->best_dsc_rw_freq;
- config.nr_stages = 1;
- if (copy_to_user(argp, &config, sizeof(config)))
- return -EFAULT;
- break;
- default:
- return -EIO;
- }
- return 0;
-}
-
-static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
- int mt_count)
-{
- idetape_tape_t *tape = drive->driver_data;
- struct gendisk *disk = tape->disk;
- struct ide_atapi_pc pc;
- int retval, count = 0;
- int sprev = !!(tape->caps[4] & 0x20);
-
-
- ide_debug_log(IDE_DBG_FUNC, "mt_op: %d, mt_count: %d", mt_op, mt_count);
-
- if (mt_count == 0)
- return 0;
- if (MTBSF == mt_op || MTBSFM == mt_op) {
- if (!sprev)
- return -EIO;
- mt_count = -mt_count;
- }
-
- if (tape->chrdev_dir == IDETAPE_DIR_READ) {
- tape->valid = 0;
- if (test_and_clear_bit(ilog2(IDE_AFLAG_FILEMARK),
- &drive->atapi_flags))
- ++count;
- ide_tape_discard_merge_buffer(drive, 0);
- }
-
- switch (mt_op) {
- case MTFSF:
- case MTBSF:
- idetape_create_space_cmd(&pc, mt_count - count,
- IDETAPE_SPACE_OVER_FILEMARK);
- return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
- case MTFSFM:
- case MTBSFM:
- if (!sprev)
- return -EIO;
- retval = idetape_space_over_filemarks(drive, MTFSF,
- mt_count - count);
- if (retval)
- return retval;
- count = (MTBSFM == mt_op ? 1 : -1);
- return idetape_space_over_filemarks(drive, MTFSF, count);
- default:
- printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",
- mt_op);
- return -EIO;
- }
-}
-
-/*
- * Our character device read / write functions.
- *
- * The tape is optimized to maximize throughput when it is transferring an
- * integral number of the "continuous transfer limit", which is a parameter of
- * the specific tape (26kB on my particular tape, 32kB for Onstream).
- *
- * As of version 1.3 of the driver, the character device provides an abstract
- * continuous view of the media - any mix of block sizes (even 1 byte) on the
- * same backup/restore procedure is supported. The driver will internally
- * convert the requests to the recommended transfer unit, so that an unmatch
- * between the user's block size to the recommended size will only result in a
- * (slightly) increased driver overhead, but will no longer hit performance.
- * This is not applicable to Onstream.
- */
-static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct ide_tape_obj *tape = file->private_data;
- ide_drive_t *drive = tape->drive;
- size_t done = 0;
- ssize_t ret = 0;
- int rc;
-
- ide_debug_log(IDE_DBG_FUNC, "count %zd", count);
-
- if (tape->chrdev_dir != IDETAPE_DIR_READ) {
- if (test_bit(ilog2(IDE_AFLAG_DETECT_BS), &drive->atapi_flags))
- if (count > tape->blk_size &&
- (count % tape->blk_size) == 0)
- tape->user_bs_factor = count / tape->blk_size;
- }
-
- rc = idetape_init_rw(drive, IDETAPE_DIR_READ);
- if (rc < 0)
- return rc;
-
- while (done < count) {
- size_t todo;
-
- /* refill if staging buffer is empty */
- if (!tape->valid) {
- /* If we are at a filemark, nothing more to read */
- if (test_bit(ilog2(IDE_AFLAG_FILEMARK),
- &drive->atapi_flags))
- break;
- /* read */
- if (idetape_queue_rw_tail(drive, REQ_IDETAPE_READ,
- tape->buffer_size) <= 0)
- break;
- }
-
- /* copy out */
- todo = min_t(size_t, count - done, tape->valid);
- if (copy_to_user(buf + done, tape->cur, todo))
- ret = -EFAULT;
-
- tape->cur += todo;
- tape->valid -= todo;
- done += todo;
- }
-
- if (!done && test_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags)) {
- idetape_space_over_filemarks(drive, MTFSF, 1);
- return 0;
- }
-
- return ret ? ret : done;
-}
-
-static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct ide_tape_obj *tape = file->private_data;
- ide_drive_t *drive = tape->drive;
- size_t done = 0;
- ssize_t ret = 0;
- int rc;
-
- /* The drive is write protected. */
- if (tape->write_prot)
- return -EACCES;
-
- ide_debug_log(IDE_DBG_FUNC, "count %zd", count);
-
- /* Initialize write operation */
- rc = idetape_init_rw(drive, IDETAPE_DIR_WRITE);
- if (rc < 0)
- return rc;
-
- while (done < count) {
- size_t todo;
-
- /* flush if staging buffer is full */
- if (tape->valid == tape->buffer_size &&
- idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE,
- tape->buffer_size) <= 0)
- return rc;
-
- /* copy in */
- todo = min_t(size_t, count - done,
- tape->buffer_size - tape->valid);
- if (copy_from_user(tape->cur, buf + done, todo))
- ret = -EFAULT;
-
- tape->cur += todo;
- tape->valid += todo;
- done += todo;
- }
-
- return ret ? ret : done;
-}
-
-static int idetape_write_filemark(ide_drive_t *drive)
-{
- struct ide_tape_obj *tape = drive->driver_data;
- struct ide_atapi_pc pc;
-
- /* Write a filemark */
- idetape_create_write_filemark_cmd(drive, &pc, 1);
- if (ide_queue_pc_tail(drive, tape->disk, &pc, NULL, 0)) {
- printk(KERN_ERR "ide-tape: Couldn't write a filemark\n");
- return -EIO;
- }
- return 0;
-}
-
-/*
- * Called from idetape_chrdev_ioctl when the general mtio MTIOCTOP ioctl is
- * requested.
- *
- * Note: MTBSF and MTBSFM are not supported when the tape doesn't support
- * spacing over filemarks in the reverse direction. In this case, MTFSFM is also
- * usually not supported.
- *
- * The following commands are currently not supported:
- *
- * MTFSS, MTBSS, MTWSM, MTSETDENSITY, MTSETDRVBUFFER, MT_ST_BOOLEANS,
- * MT_ST_WRITE_THRESHOLD.
- */
-static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
-{
- idetape_tape_t *tape = drive->driver_data;
- struct gendisk *disk = tape->disk;
- struct ide_atapi_pc pc;
- int i, retval;
-
- ide_debug_log(IDE_DBG_FUNC, "MTIOCTOP ioctl: mt_op: %d, mt_count: %d",
- mt_op, mt_count);
-
- switch (mt_op) {
- case MTFSF:
- case MTFSFM:
- case MTBSF:
- case MTBSFM:
- if (!mt_count)
- return 0;
- return idetape_space_over_filemarks(drive, mt_op, mt_count);
- default:
- break;
- }
-
- switch (mt_op) {
- case MTWEOF:
- if (tape->write_prot)
- return -EACCES;
- ide_tape_discard_merge_buffer(drive, 1);
- for (i = 0; i < mt_count; i++) {
- retval = idetape_write_filemark(drive);
- if (retval)
- return retval;
- }
- return 0;
- case MTREW:
- ide_tape_discard_merge_buffer(drive, 0);
- if (idetape_rewind_tape(drive))
- return -EIO;
- return 0;
- case MTLOAD:
- ide_tape_discard_merge_buffer(drive, 0);
- return ide_do_start_stop(drive, disk, IDETAPE_LU_LOAD_MASK);
- case MTUNLOAD:
- case MTOFFL:
- /*
- * If door is locked, attempt to unlock before
- * attempting to eject.
- */
- if (tape->door_locked) {
- if (!ide_set_media_lock(drive, disk, 0))
- tape->door_locked = DOOR_UNLOCKED;
- }
- ide_tape_discard_merge_buffer(drive, 0);
- retval = ide_do_start_stop(drive, disk, !IDETAPE_LU_LOAD_MASK);
- if (!retval)
- clear_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT),
- &drive->atapi_flags);
- return retval;
- case MTNOP:
- ide_tape_discard_merge_buffer(drive, 0);
- return idetape_flush_tape_buffers(drive);
- case MTRETEN:
- ide_tape_discard_merge_buffer(drive, 0);
- return ide_do_start_stop(drive, disk,
- IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
- case MTEOM:
- idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
- return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
- case MTERASE:
- (void)idetape_rewind_tape(drive);
- idetape_create_erase_cmd(&pc);
- return ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
- case MTSETBLK:
- if (mt_count) {
- if (mt_count < tape->blk_size ||
- mt_count % tape->blk_size)
- return -EIO;
- tape->user_bs_factor = mt_count / tape->blk_size;
- clear_bit(ilog2(IDE_AFLAG_DETECT_BS),
- &drive->atapi_flags);
- } else
- set_bit(ilog2(IDE_AFLAG_DETECT_BS),
- &drive->atapi_flags);
- return 0;
- case MTSEEK:
- ide_tape_discard_merge_buffer(drive, 0);
- return idetape_position_tape(drive,
- mt_count * tape->user_bs_factor, tape->partition, 0);
- case MTSETPART:
- ide_tape_discard_merge_buffer(drive, 0);
- return idetape_position_tape(drive, 0, mt_count, 0);
- case MTFSR:
- case MTBSR:
- case MTLOCK:
- retval = ide_set_media_lock(drive, disk, 1);
- if (retval)
- return retval;
- tape->door_locked = DOOR_EXPLICITLY_LOCKED;
- return 0;
- case MTUNLOCK:
- retval = ide_set_media_lock(drive, disk, 0);
- if (retval)
- return retval;
- tape->door_locked = DOOR_UNLOCKED;
- return 0;
- default:
- printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",
- mt_op);
- return -EIO;
- }
-}
-
-/*
- * Our character device ioctls. General mtio.h magnetic io commands are
- * supported here, and not in the corresponding block interface. Our own
- * ide-tape ioctls are supported on both interfaces.
- */
-static long do_idetape_chrdev_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct ide_tape_obj *tape = file->private_data;
- ide_drive_t *drive = tape->drive;
- struct mtop mtop;
- struct mtget mtget;
- struct mtpos mtpos;
- int block_offset = 0, position = tape->first_frame;
- void __user *argp = (void __user *)arg;
-
- ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x", cmd);
-
- if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
- ide_tape_flush_merge_buffer(drive);
- idetape_flush_tape_buffers(drive);
- }
- if (cmd == MTIOCGET || cmd == MTIOCPOS) {
- block_offset = tape->valid /
- (tape->blk_size * tape->user_bs_factor);
- position = ide_tape_read_position(drive);
- if (position < 0)
- return -EIO;
- }
- switch (cmd) {
- case MTIOCTOP:
- if (copy_from_user(&mtop, argp, sizeof(struct mtop)))
- return -EFAULT;
- return idetape_mtioctop(drive, mtop.mt_op, mtop.mt_count);
- case MTIOCGET:
- memset(&mtget, 0, sizeof(struct mtget));
- mtget.mt_type = MT_ISSCSI2;
- mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
- mtget.mt_dsreg =
- ((tape->blk_size * tape->user_bs_factor)
- << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK;
-
- if (tape->drv_write_prot)
- mtget.mt_gstat |= GMT_WR_PROT(0xffffffff);
-
- return put_user_mtget(argp, &mtget);
- case MTIOCPOS:
- mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
- return put_user_mtpos(argp, &mtpos);
- default:
- if (tape->chrdev_dir == IDETAPE_DIR_READ)
- ide_tape_discard_merge_buffer(drive, 1);
- return idetape_blkdev_ioctl(drive, cmd, arg);
- }
-}
-
-static long idetape_chrdev_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- long ret;
- mutex_lock(&ide_tape_mutex);
- ret = do_idetape_chrdev_ioctl(file, cmd, arg);
- mutex_unlock(&ide_tape_mutex);
- return ret;
-}
-
-static long idetape_chrdev_compat_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- long ret;
-
- if (cmd == MTIOCPOS32)
- cmd = MTIOCPOS;
- else if (cmd == MTIOCGET32)
- cmd = MTIOCGET;
-
- mutex_lock(&ide_tape_mutex);
- ret = do_idetape_chrdev_ioctl(file, cmd, arg);
- mutex_unlock(&ide_tape_mutex);
- return ret;
-}
-
-/*
- * Do a mode sense page 0 with block descriptor and if it succeeds set the tape
- * block size with the reported value.
- */
-static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
- struct ide_atapi_pc pc;
- u8 buf[12];
-
- idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
- if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) {
- printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
- if (tape->blk_size == 0) {
- printk(KERN_WARNING "ide-tape: Cannot deal with zero "
- "block size, assuming 32k\n");
- tape->blk_size = 32768;
- }
- return;
- }
- tape->blk_size = (buf[4 + 5] << 16) +
- (buf[4 + 6] << 8) +
- buf[4 + 7];
- tape->drv_write_prot = (buf[2] & 0x80) >> 7;
-
- ide_debug_log(IDE_DBG_FUNC, "blk_size: %d, write_prot: %d",
- tape->blk_size, tape->drv_write_prot);
-}
-
-static int idetape_chrdev_open(struct inode *inode, struct file *filp)
-{
- unsigned int minor = iminor(inode), i = minor & ~0xc0;
- ide_drive_t *drive;
- idetape_tape_t *tape;
- int retval;
-
- if (i >= MAX_HWIFS * MAX_DRIVES)
- return -ENXIO;
-
- mutex_lock(&idetape_chrdev_mutex);
-
- tape = ide_tape_get(NULL, true, i);
- if (!tape) {
- mutex_unlock(&idetape_chrdev_mutex);
- return -ENXIO;
- }
-
- drive = tape->drive;
- filp->private_data = tape;
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- /*
- * 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);
-
-
- if (test_and_set_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags)) {
- retval = -EBUSY;
- goto out_put_tape;
- }
-
- retval = idetape_wait_ready(drive, 60 * HZ);
- if (retval) {
- clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
- printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
- goto out_put_tape;
- }
-
- ide_tape_read_position(drive);
- if (!test_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), &drive->atapi_flags))
- (void)idetape_rewind_tape(drive);
-
- /* Read block size and write protect status from drive. */
- ide_tape_get_bsize_from_bdesc(drive);
-
- /* Set write protect flag if device is opened as read-only. */
- if ((filp->f_flags & O_ACCMODE) == O_RDONLY)
- tape->write_prot = 1;
- else
- tape->write_prot = tape->drv_write_prot;
-
- /* Make sure drive isn't write protected if user wants to write. */
- if (tape->write_prot) {
- if ((filp->f_flags & O_ACCMODE) == O_WRONLY ||
- (filp->f_flags & O_ACCMODE) == O_RDWR) {
- clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
- retval = -EROFS;
- goto out_put_tape;
- }
- }
-
- /* Lock the tape drive door so user can't eject. */
- if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
- if (!ide_set_media_lock(drive, tape->disk, 1)) {
- if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
- tape->door_locked = DOOR_LOCKED;
- }
- }
- mutex_unlock(&idetape_chrdev_mutex);
-
- return 0;
-
-out_put_tape:
- ide_tape_put(tape);
-
- mutex_unlock(&idetape_chrdev_mutex);
-
- return retval;
-}
-
-static void idetape_write_release(ide_drive_t *drive, unsigned int minor)
-{
- idetape_tape_t *tape = drive->driver_data;
-
- ide_tape_flush_merge_buffer(drive);
- tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL);
- if (tape->buf != NULL) {
- idetape_pad_zeros(drive, tape->blk_size *
- (tape->user_bs_factor - 1));
- kfree(tape->buf);
- tape->buf = NULL;
- }
- idetape_write_filemark(drive);
- idetape_flush_tape_buffers(drive);
- idetape_flush_tape_buffers(drive);
-}
-
-static int idetape_chrdev_release(struct inode *inode, struct file *filp)
-{
- struct ide_tape_obj *tape = filp->private_data;
- ide_drive_t *drive = tape->drive;
- unsigned int minor = iminor(inode);
-
- mutex_lock(&idetape_chrdev_mutex);
-
- tape = drive->driver_data;
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- if (tape->chrdev_dir == IDETAPE_DIR_WRITE)
- idetape_write_release(drive, minor);
- if (tape->chrdev_dir == IDETAPE_DIR_READ) {
- if (minor < 128)
- ide_tape_discard_merge_buffer(drive, 1);
- }
-
- if (minor < 128 && test_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT),
- &drive->atapi_flags))
- (void) idetape_rewind_tape(drive);
-
- if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
- if (tape->door_locked == DOOR_LOCKED) {
- if (!ide_set_media_lock(drive, tape->disk, 0))
- tape->door_locked = DOOR_UNLOCKED;
- }
- }
- clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags);
- ide_tape_put(tape);
-
- mutex_unlock(&idetape_chrdev_mutex);
-
- return 0;
-}
-
-static void idetape_get_inquiry_results(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
- struct ide_atapi_pc pc;
- u8 pc_buf[256];
- char fw_rev[4], vendor_id[8], product_id[16];
-
- idetape_create_inquiry_cmd(&pc);
- if (ide_queue_pc_tail(drive, tape->disk, &pc, pc_buf, pc.req_xfer)) {
- printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n",
- tape->name);
- return;
- }
- memcpy(vendor_id, &pc_buf[8], 8);
- memcpy(product_id, &pc_buf[16], 16);
- memcpy(fw_rev, &pc_buf[32], 4);
-
- ide_fixstring(vendor_id, 8, 0);
- ide_fixstring(product_id, 16, 0);
- ide_fixstring(fw_rev, 4, 0);
-
- printk(KERN_INFO "ide-tape: %s <-> %s: %.8s %.16s rev %.4s\n",
- drive->name, tape->name, vendor_id, product_id, fw_rev);
-}
-
-/*
- * Ask the tape about its various parameters. In particular, we will adjust our
- * data transfer buffer size to the recommended value as returned by the tape.
- */
-static void idetape_get_mode_sense_results(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
- struct ide_atapi_pc pc;
- u8 buf[24], *caps;
- u8 speed, max_speed;
-
- idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE);
- if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) {
- printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming"
- " some default values\n");
- tape->blk_size = 512;
- put_unaligned(52, (u16 *)&tape->caps[12]);
- put_unaligned(540, (u16 *)&tape->caps[14]);
- put_unaligned(6*52, (u16 *)&tape->caps[16]);
- return;
- }
- caps = buf + 4 + buf[3];
-
- /* convert to host order and save for later use */
- speed = be16_to_cpup((__be16 *)&caps[14]);
- max_speed = be16_to_cpup((__be16 *)&caps[8]);
-
- *(u16 *)&caps[8] = max_speed;
- *(u16 *)&caps[12] = be16_to_cpup((__be16 *)&caps[12]);
- *(u16 *)&caps[14] = speed;
- *(u16 *)&caps[16] = be16_to_cpup((__be16 *)&caps[16]);
-
- if (!speed) {
- printk(KERN_INFO "ide-tape: %s: invalid tape speed "
- "(assuming 650KB/sec)\n", drive->name);
- *(u16 *)&caps[14] = 650;
- }
- if (!max_speed) {
- printk(KERN_INFO "ide-tape: %s: invalid max_speed "
- "(assuming 650KB/sec)\n", drive->name);
- *(u16 *)&caps[8] = 650;
- }
-
- memcpy(&tape->caps, caps, 20);
-
- /* device lacks locking support according to capabilities page */
- if ((caps[6] & 1) == 0)
- drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
-
- if (caps[7] & 0x02)
- tape->blk_size = 512;
- else if (caps[7] & 0x04)
- tape->blk_size = 1024;
-}
-
-#ifdef CONFIG_IDE_PROC_FS
-#define ide_tape_devset_get(name, field) \
-static int get_##name(ide_drive_t *drive) \
-{ \
- idetape_tape_t *tape = drive->driver_data; \
- return tape->field; \
-}
-
-#define ide_tape_devset_set(name, field) \
-static int set_##name(ide_drive_t *drive, int arg) \
-{ \
- idetape_tape_t *tape = drive->driver_data; \
- tape->field = arg; \
- return 0; \
-}
-
-#define ide_tape_devset_rw_field(_name, _field) \
-ide_tape_devset_get(_name, _field) \
-ide_tape_devset_set(_name, _field) \
-IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name)
-
-#define ide_tape_devset_r_field(_name, _field) \
-ide_tape_devset_get(_name, _field) \
-IDE_DEVSET(_name, 0, get_##_name, NULL)
-
-static int mulf_tdsc(ide_drive_t *drive) { return 1000; }
-static int divf_tdsc(ide_drive_t *drive) { return HZ; }
-static int divf_buffer(ide_drive_t *drive) { return 2; }
-static int divf_buffer_size(ide_drive_t *drive) { return 1024; }
-
-ide_devset_rw_flag(dsc_overlap, IDE_DFLAG_DSC_OVERLAP);
-
-ide_tape_devset_rw_field(tdsc, best_dsc_rw_freq);
-
-ide_tape_devset_r_field(avg_speed, avg_speed);
-ide_tape_devset_r_field(speed, caps[14]);
-ide_tape_devset_r_field(buffer, caps[16]);
-ide_tape_devset_r_field(buffer_size, buffer_size);
-
-static const struct ide_proc_devset idetape_settings[] = {
- __IDE_PROC_DEVSET(avg_speed, 0, 0xffff, NULL, NULL),
- __IDE_PROC_DEVSET(buffer, 0, 0xffff, NULL, divf_buffer),
- __IDE_PROC_DEVSET(buffer_size, 0, 0xffff, NULL, divf_buffer_size),
- __IDE_PROC_DEVSET(dsc_overlap, 0, 1, NULL, NULL),
- __IDE_PROC_DEVSET(speed, 0, 0xffff, NULL, NULL),
- __IDE_PROC_DEVSET(tdsc, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX,
- mulf_tdsc, divf_tdsc),
- { NULL },
-};
-#endif
-
-/*
- * The function below is called to:
- *
- * 1. Initialize our various state variables.
- * 2. Ask the tape for its capabilities.
- * 3. Allocate a buffer which will be used for data transfer. The buffer size
- * is chosen based on the recommendation which we received in step 2.
- *
- * Note that at this point ide.c already assigned us an irq, so that we can
- * queue requests here and wait for their completion.
- */
-static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
-{
- unsigned long t;
- int speed;
- u16 *ctl = (u16 *)&tape->caps[12];
-
- ide_debug_log(IDE_DBG_FUNC, "minor: %d", minor);
-
- drive->pc_callback = ide_tape_callback;
-
- drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
-
- if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) {
- printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n",
- tape->name);
- drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
- }
-
- /* Seagate Travan drives do not support DSC overlap. */
- if (strstr((char *)&drive->id[ATA_ID_PROD], "Seagate STT3401"))
- drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
-
- tape->minor = minor;
- tape->name[0] = 'h';
- tape->name[1] = 't';
- tape->name[2] = '0' + minor;
- tape->chrdev_dir = IDETAPE_DIR_NONE;
-
- idetape_get_inquiry_results(drive);
- idetape_get_mode_sense_results(drive);
- ide_tape_get_bsize_from_bdesc(drive);
- tape->user_bs_factor = 1;
- tape->buffer_size = *ctl * tape->blk_size;
- while (tape->buffer_size > 0xffff) {
- printk(KERN_NOTICE "ide-tape: decreasing stage size\n");
- *ctl /= 2;
- tape->buffer_size = *ctl * tape->blk_size;
- }
-
- /* select the "best" DSC read/write polling freq */
- speed = max(*(u16 *)&tape->caps[14], *(u16 *)&tape->caps[8]);
-
- t = (IDETAPE_FIFO_THRESHOLD * tape->buffer_size * HZ) / (speed * 1000);
-
- /*
- * Ensure that the number we got makes sense; limit it within
- * IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
- */
- tape->best_dsc_rw_freq = clamp_t(unsigned long, t, IDETAPE_DSC_RW_MIN,
- IDETAPE_DSC_RW_MAX);
- printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
- "%ums tDSC%s\n",
- drive->name, tape->name, *(u16 *)&tape->caps[14],
- (*(u16 *)&tape->caps[16] * 512) / tape->buffer_size,
- tape->buffer_size / 1024,
- jiffies_to_msecs(tape->best_dsc_rw_freq),
- (drive->dev_flags & IDE_DFLAG_USING_DMA) ? ", DMA" : "");
-
- ide_proc_register_driver(drive, tape->driver);
-}
-
-static void ide_tape_remove(ide_drive_t *drive)
-{
- idetape_tape_t *tape = drive->driver_data;
-
- ide_proc_unregister_driver(drive, tape->driver);
- device_del(&tape->dev);
-
- mutex_lock(&idetape_ref_mutex);
- put_device(&tape->dev);
- mutex_unlock(&idetape_ref_mutex);
-}
-
-static void ide_tape_release(struct device *dev)
-{
- struct ide_tape_obj *tape = to_ide_drv(dev, ide_tape_obj);
- ide_drive_t *drive = tape->drive;
- struct gendisk *g = tape->disk;
-
- BUG_ON(tape->valid);
-
- drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
- drive->driver_data = NULL;
- device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor));
- device_destroy(idetape_sysfs_class,
- MKDEV(IDETAPE_MAJOR, tape->minor + 128));
- idetape_devs[tape->minor] = NULL;
- g->private_data = NULL;
- put_disk(g);
- kfree(tape);
-}
-
-#ifdef CONFIG_IDE_PROC_FS
-static int idetape_name_proc_show(struct seq_file *m, void *v)
-{
- ide_drive_t *drive = (ide_drive_t *) m->private;
- idetape_tape_t *tape = drive->driver_data;
-
- seq_printf(m, "%s\n", tape->name);
- return 0;
-}
-
-static ide_proc_entry_t idetape_proc[] = {
- { "capacity", S_IFREG|S_IRUGO, ide_capacity_proc_show },
- { "name", S_IFREG|S_IRUGO, idetape_name_proc_show },
- {}
-};
-
-static ide_proc_entry_t *ide_tape_proc_entries(ide_drive_t *drive)
-{
- return idetape_proc;
-}
-
-static const struct ide_proc_devset *ide_tape_proc_devsets(ide_drive_t *drive)
-{
- return idetape_settings;
-}
-#endif
-
-static int ide_tape_probe(ide_drive_t *);
-
-static struct ide_driver idetape_driver = {
- .gen_driver = {
- .owner = THIS_MODULE,
- .name = "ide-tape",
- .bus = &ide_bus_type,
- },
- .probe = ide_tape_probe,
- .remove = ide_tape_remove,
- .version = IDETAPE_VERSION,
- .do_request = idetape_do_request,
-#ifdef CONFIG_IDE_PROC_FS
- .proc_entries = ide_tape_proc_entries,
- .proc_devsets = ide_tape_proc_devsets,
-#endif
-};
-
-/* Our character device supporting functions, passed to register_chrdev. */
-static const struct file_operations idetape_fops = {
- .owner = THIS_MODULE,
- .read = idetape_chrdev_read,
- .write = idetape_chrdev_write,
- .unlocked_ioctl = idetape_chrdev_ioctl,
- .compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ?
- idetape_chrdev_compat_ioctl : NULL,
- .open = idetape_chrdev_open,
- .release = idetape_chrdev_release,
- .llseek = noop_llseek,
-};
-
-static int idetape_open(struct block_device *bdev, fmode_t mode)
-{
- struct ide_tape_obj *tape;
-
- mutex_lock(&ide_tape_mutex);
- tape = ide_tape_get(bdev->bd_disk, false, 0);
- mutex_unlock(&ide_tape_mutex);
-
- if (!tape)
- return -ENXIO;
-
- return 0;
-}
-
-static void idetape_release(struct gendisk *disk, fmode_t mode)
-{
- struct ide_tape_obj *tape = ide_drv_g(disk, ide_tape_obj);
-
- mutex_lock(&ide_tape_mutex);
- ide_tape_put(tape);
- mutex_unlock(&ide_tape_mutex);
-}
-
-static int idetape_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- struct ide_tape_obj *tape = ide_drv_g(bdev->bd_disk, ide_tape_obj);
- ide_drive_t *drive = tape->drive;
- int err;
-
- mutex_lock(&ide_tape_mutex);
- err = generic_ide_ioctl(drive, bdev, cmd, arg);
- if (err == -EINVAL)
- err = idetape_blkdev_ioctl(drive, cmd, arg);
- mutex_unlock(&ide_tape_mutex);
-
- return err;
-}
-
-static int idetape_compat_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- if (cmd == 0x0340 || cmd == 0x350)
- arg = (unsigned long)compat_ptr(arg);
-
- return idetape_ioctl(bdev, mode, cmd, arg);
-}
-
-static const struct block_device_operations idetape_block_ops = {
- .owner = THIS_MODULE,
- .open = idetape_open,
- .release = idetape_release,
- .ioctl = idetape_ioctl,
- .compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ?
- idetape_compat_ioctl : NULL,
-};
-
-static int ide_tape_probe(ide_drive_t *drive)
-{
- idetape_tape_t *tape;
- struct gendisk *g;
- int minor;
-
- ide_debug_log(IDE_DBG_FUNC, "enter");
-
- if (!strstr(DRV_NAME, drive->driver_req))
- goto failed;
-
- if (drive->media != ide_tape)
- goto failed;
-
- if ((drive->dev_flags & IDE_DFLAG_ID_READ) &&
- ide_check_atapi_device(drive, DRV_NAME) == 0) {
- printk(KERN_ERR "ide-tape: %s: not supported by this version of"
- " the driver\n", drive->name);
- goto failed;
- }
- tape = kzalloc(sizeof(idetape_tape_t), GFP_KERNEL);
- if (tape == NULL) {
- printk(KERN_ERR "ide-tape: %s: Can't allocate a tape struct\n",
- drive->name);
- goto failed;
- }
-
- g = alloc_disk(1 << PARTN_BITS);
- if (!g)
- goto out_free_tape;
-
- ide_init_disk(g, drive);
-
- tape->dev.parent = &drive->gendev;
- tape->dev.release = ide_tape_release;
- dev_set_name(&tape->dev, "%s", dev_name(&drive->gendev));
-
- if (device_register(&tape->dev))
- goto out_free_disk;
-
- tape->drive = drive;
- tape->driver = &idetape_driver;
- tape->disk = g;
-
- g->private_data = &tape->driver;
-
- drive->driver_data = tape;
-
- mutex_lock(&idetape_ref_mutex);
- for (minor = 0; idetape_devs[minor]; minor++)
- ;
- idetape_devs[minor] = tape;
- mutex_unlock(&idetape_ref_mutex);
-
- idetape_setup(drive, tape, minor);
-
- device_create(idetape_sysfs_class, &drive->gendev,
- MKDEV(IDETAPE_MAJOR, minor), NULL, "%s", tape->name);
- device_create(idetape_sysfs_class, &drive->gendev,
- MKDEV(IDETAPE_MAJOR, minor + 128), NULL,
- "n%s", tape->name);
-
- g->fops = &idetape_block_ops;
-
- return 0;
-
-out_free_disk:
- put_disk(g);
-out_free_tape:
- kfree(tape);
-failed:
- return -ENODEV;
-}
-
-static void __exit idetape_exit(void)
-{
- driver_unregister(&idetape_driver.gen_driver);
- class_destroy(idetape_sysfs_class);
- unregister_chrdev(IDETAPE_MAJOR, "ht");
-}
-
-static int __init idetape_init(void)
-{
- int error = 1;
- idetape_sysfs_class = class_create(THIS_MODULE, "ide_tape");
- if (IS_ERR(idetape_sysfs_class)) {
- idetape_sysfs_class = NULL;
- printk(KERN_ERR "Unable to create sysfs class for ide tapes\n");
- error = -EBUSY;
- goto out;
- }
-
- if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) {
- printk(KERN_ERR "ide-tape: Failed to register chrdev"
- " interface\n");
- error = -EBUSY;
- goto out_free_class;
- }
-
- error = driver_register(&idetape_driver.gen_driver);
- if (error)
- goto out_free_chrdev;
-
- return 0;
-
-out_free_chrdev:
- unregister_chrdev(IDETAPE_MAJOR, "ht");
-out_free_class:
- class_destroy(idetape_sysfs_class);
-out:
- return error;
-}
-
-MODULE_ALIAS("ide:*m-tape*");
-module_init(idetape_init);
-module_exit(idetape_exit);
-MODULE_ALIAS_CHARDEV_MAJOR(IDETAPE_MAJOR);
-MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
deleted file mode 100644
index 6665fc4724b9..000000000000
--- a/drivers/ide/ide-taskfile.c
+++ /dev/null
@@ -1,668 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2000-2002 Michael Cornwell <cornwell@acm.org>
- * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2001-2002 Klaus Smolin
- * IBM Storage Technology Division
- * Copyright (C) 2003-2004, 2007 Bartlomiej Zolnierkiewicz
- *
- * The big the bad and the ugly.
- */
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/nmi.h>
-#include <linux/scatterlist.h>
-#include <linux/uaccess.h>
-
-#include <asm/io.h>
-
-void ide_tf_readback(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_tp_ops *tp_ops = hwif->tp_ops;
-
- /* Be sure we're looking at the low order bytes */
- tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
-
- tp_ops->tf_read(drive, &cmd->tf, cmd->valid.in.tf);
-
- if (cmd->tf_flags & IDE_TFLAG_LBA48) {
- tp_ops->write_devctl(hwif, ATA_HOB | ATA_DEVCTL_OBS);
-
- tp_ops->tf_read(drive, &cmd->hob, cmd->valid.in.hob);
- }
-}
-
-void ide_tf_dump(const char *s, struct ide_cmd *cmd)
-{
-#ifdef DEBUG
- printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x "
- "lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n",
- s, cmd->tf.feature, cmd->tf.nsect,
- cmd->tf.lbal, cmd->tf.lbam, cmd->tf.lbah,
- cmd->tf.device, cmd->tf.command);
- printk("%s: hob: nsect 0x%02x lbal 0x%02x lbam 0x%02x lbah 0x%02x\n",
- s, cmd->hob.nsect, cmd->hob.lbal, cmd->hob.lbam, cmd->hob.lbah);
-#endif
-}
-
-int taskfile_lib_get_identify(ide_drive_t *drive, u8 *buf)
-{
- struct ide_cmd cmd;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.tf.nsect = 0x01;
- if (drive->media == ide_disk)
- cmd.tf.command = ATA_CMD_ID_ATA;
- else
- cmd.tf.command = ATA_CMD_ID_ATAPI;
- cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE;
- cmd.protocol = ATA_PROT_PIO;
-
- return ide_raw_taskfile(drive, &cmd, buf, 1);
-}
-
-static ide_startstop_t task_no_data_intr(ide_drive_t *);
-static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct ide_cmd *);
-static ide_startstop_t task_pio_intr(ide_drive_t *);
-
-ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct ide_cmd *cmd = &hwif->cmd;
- struct ide_taskfile *tf = &cmd->tf;
- ide_handler_t *handler = NULL;
- const struct ide_tp_ops *tp_ops = hwif->tp_ops;
- const struct ide_dma_ops *dma_ops = hwif->dma_ops;
-
- if (orig_cmd->protocol == ATA_PROT_PIO &&
- (orig_cmd->tf_flags & IDE_TFLAG_MULTI_PIO) &&
- drive->mult_count == 0) {
- pr_err("%s: multimode not set!\n", drive->name);
- return ide_stopped;
- }
-
- if (orig_cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
- orig_cmd->ftf_flags |= IDE_FTFLAG_SET_IN_FLAGS;
-
- memcpy(cmd, orig_cmd, sizeof(*cmd));
-
- if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
- ide_tf_dump(drive->name, cmd);
- tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
-
- if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) {
- u8 data[2] = { cmd->tf.data, cmd->hob.data };
-
- tp_ops->output_data(drive, cmd, data, 2);
- }
-
- if (cmd->valid.out.tf & IDE_VALID_DEVICE) {
- u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ?
- 0xE0 : 0xEF;
-
- if (!(cmd->ftf_flags & IDE_FTFLAG_FLAGGED))
- cmd->tf.device &= HIHI;
- cmd->tf.device |= drive->select;
- }
-
- tp_ops->tf_load(drive, &cmd->hob, cmd->valid.out.hob);
- tp_ops->tf_load(drive, &cmd->tf, cmd->valid.out.tf);
- }
-
- switch (cmd->protocol) {
- case ATA_PROT_PIO:
- if (cmd->tf_flags & IDE_TFLAG_WRITE) {
- tp_ops->exec_command(hwif, tf->command);
- ndelay(400); /* FIXME */
- return pre_task_out_intr(drive, cmd);
- }
- handler = task_pio_intr;
- fallthrough;
- case ATA_PROT_NODATA:
- if (handler == NULL)
- handler = task_no_data_intr;
- ide_execute_command(drive, cmd, handler, WAIT_WORSTCASE);
- return ide_started;
- case ATA_PROT_DMA:
- if (ide_dma_prepare(drive, cmd))
- return ide_stopped;
- hwif->expiry = dma_ops->dma_timer_expiry;
- ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD);
- dma_ops->dma_start(drive);
- fallthrough;
- default:
- return ide_started;
- }
-}
-EXPORT_SYMBOL_GPL(do_rw_taskfile);
-
-static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct ide_cmd *cmd = &hwif->cmd;
- struct ide_taskfile *tf = &cmd->tf;
- int custom = (cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0;
- int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1;
- u8 stat;
-
- local_irq_enable_in_hardirq();
-
- while (1) {
- stat = hwif->tp_ops->read_status(hwif);
- if ((stat & ATA_BUSY) == 0 || retries-- == 0)
- break;
- udelay(10);
- };
-
- if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
- if (custom && tf->command == ATA_CMD_SET_MULTI) {
- drive->mult_req = drive->mult_count = 0;
- drive->special_flags |= IDE_SFLAG_RECALIBRATE;
- (void)ide_dump_status(drive, __func__, stat);
- return ide_stopped;
- } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) {
- if ((stat & (ATA_ERR | ATA_DRQ)) == 0) {
- ide_set_handler(drive, &task_no_data_intr,
- WAIT_WORSTCASE);
- return ide_started;
- }
- }
- return ide_error(drive, "task_no_data_intr", stat);
- }
-
- if (custom && tf->command == ATA_CMD_SET_MULTI)
- drive->mult_count = drive->mult_req;
-
- if (custom == 0 || tf->command == ATA_CMD_IDLEIMMEDIATE ||
- tf->command == ATA_CMD_CHK_POWER) {
- struct request *rq = hwif->rq;
-
- if (ata_pm_request(rq))
- ide_complete_pm_rq(drive, rq);
- else
- ide_finish_cmd(drive, cmd, stat);
- }
-
- return ide_stopped;
-}
-
-static u8 wait_drive_not_busy(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- int retries;
- u8 stat;
-
- /*
- * Last sector was transferred, wait until device is ready. This can
- * take up to 6 ms on some ATAPI devices, so we will wait max 10 ms.
- */
- for (retries = 0; retries < 1000; retries++) {
- stat = hwif->tp_ops->read_status(hwif);
-
- if (stat & ATA_BUSY)
- udelay(10);
- else
- break;
- }
-
- if (stat & ATA_BUSY)
- pr_err("%s: drive still BUSY!\n", drive->name);
-
- return stat;
-}
-
-void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
- unsigned int write, unsigned int len)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct scatterlist *sg = hwif->sg_table;
- struct scatterlist *cursg = cmd->cursg;
- struct page *page;
- unsigned int offset;
- u8 *buf;
-
- if (cursg == NULL)
- cursg = cmd->cursg = sg;
-
- while (len) {
- unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs);
-
- page = sg_page(cursg);
- offset = cursg->offset + cmd->cursg_ofs;
-
- /* get the current page and offset */
- page = nth_page(page, (offset >> PAGE_SHIFT));
- offset %= PAGE_SIZE;
-
- nr_bytes = min_t(unsigned, nr_bytes, (PAGE_SIZE - offset));
-
- buf = kmap_atomic(page) + offset;
-
- cmd->nleft -= nr_bytes;
- cmd->cursg_ofs += nr_bytes;
-
- if (cmd->cursg_ofs == cursg->length) {
- cursg = cmd->cursg = sg_next(cmd->cursg);
- cmd->cursg_ofs = 0;
- }
-
- /* do the actual data transfer */
- if (write)
- hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes);
- else
- hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes);
-
- kunmap_atomic(buf);
-
- len -= nr_bytes;
- }
-}
-EXPORT_SYMBOL_GPL(ide_pio_bytes);
-
-static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd,
- unsigned int write)
-{
- unsigned int nr_bytes;
-
- u8 saved_io_32bit = drive->io_32bit;
-
- if (cmd->tf_flags & IDE_TFLAG_FS)
- scsi_req(cmd->rq)->result = 0;
-
- if (cmd->tf_flags & IDE_TFLAG_IO_16BIT)
- drive->io_32bit = 0;
-
- touch_softlockup_watchdog();
-
- if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO)
- nr_bytes = min_t(unsigned, cmd->nleft, drive->mult_count << 9);
- else
- nr_bytes = SECTOR_SIZE;
-
- ide_pio_bytes(drive, cmd, write, nr_bytes);
-
- drive->io_32bit = saved_io_32bit;
-}
-
-static void ide_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- if (cmd->tf_flags & IDE_TFLAG_FS) {
- int nr_bytes = cmd->nbytes - cmd->nleft;
-
- if (cmd->protocol == ATA_PROT_PIO &&
- ((cmd->tf_flags & IDE_TFLAG_WRITE) || cmd->nleft == 0)) {
- if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO)
- nr_bytes -= drive->mult_count << 9;
- else
- nr_bytes -= SECTOR_SIZE;
- }
-
- if (nr_bytes > 0)
- ide_complete_rq(drive, BLK_STS_OK, nr_bytes);
- }
-}
-
-void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat)
-{
- struct request *rq = drive->hwif->rq;
- u8 err = ide_read_error(drive), nsect = cmd->tf.nsect;
- u8 set_xfer = !!(cmd->tf_flags & IDE_TFLAG_SET_XFER);
-
- ide_complete_cmd(drive, cmd, stat, err);
- scsi_req(rq)->result = err;
-
- if (err == 0 && set_xfer) {
- ide_set_xfer_rate(drive, nsect);
- ide_driveid_update(drive);
- }
-
- ide_complete_rq(drive, err ? BLK_STS_IOERR : BLK_STS_OK, blk_rq_bytes(rq));
-}
-
-/*
- * Handler for command with PIO data phase.
- */
-static ide_startstop_t task_pio_intr(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct ide_cmd *cmd = &drive->hwif->cmd;
- u8 stat = hwif->tp_ops->read_status(hwif);
- u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
-
- if (write == 0) {
- /* Error? */
- if (stat & ATA_ERR)
- goto out_err;
-
- /* Didn't want any data? Odd. */
- if ((stat & ATA_DRQ) == 0) {
- /* Command all done? */
- if (OK_STAT(stat, ATA_DRDY, ATA_BUSY))
- goto out_end;
-
- /* Assume it was a spurious irq */
- goto out_wait;
- }
- } else {
- if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
- goto out_err;
-
- /* Deal with unexpected ATA data phase. */
- if (((stat & ATA_DRQ) == 0) ^ (cmd->nleft == 0))
- goto out_err;
- }
-
- if (write && cmd->nleft == 0)
- goto out_end;
-
- /* Still data left to transfer. */
- ide_pio_datablock(drive, cmd, write);
-
- /* Are we done? Check status and finish transfer. */
- if (write == 0 && cmd->nleft == 0) {
- stat = wait_drive_not_busy(drive);
- if (!OK_STAT(stat, 0, BAD_STAT))
- goto out_err;
-
- goto out_end;
- }
-out_wait:
- /* Still data left to transfer. */
- ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE);
- return ide_started;
-out_end:
- if ((cmd->tf_flags & IDE_TFLAG_FS) == 0)
- ide_finish_cmd(drive, cmd, stat);
- else
- ide_complete_rq(drive, BLK_STS_OK, blk_rq_sectors(cmd->rq) << 9);
- return ide_stopped;
-out_err:
- ide_error_cmd(drive, cmd);
- return ide_error(drive, __func__, stat);
-}
-
-static ide_startstop_t pre_task_out_intr(ide_drive_t *drive,
- struct ide_cmd *cmd)
-{
- ide_startstop_t startstop;
-
- if (ide_wait_stat(&startstop, drive, ATA_DRQ,
- drive->bad_wstat, WAIT_DRQ)) {
- pr_err("%s: no DRQ after issuing %sWRITE%s\n", drive->name,
- (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) ? "MULT" : "",
- (drive->dev_flags & IDE_DFLAG_LBA48) ? "_EXT" : "");
- return startstop;
- }
-
- if (!force_irqthreads && (drive->dev_flags & IDE_DFLAG_UNMASK) == 0)
- local_irq_disable();
-
- ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE);
-
- ide_pio_datablock(drive, cmd, 1);
-
- return ide_started;
-}
-
-int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf,
- u16 nsect)
-{
- struct request *rq;
- int error;
-
- rq = blk_get_request(drive->queue,
- (cmd->tf_flags & IDE_TFLAG_WRITE) ?
- REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
- ide_req(rq)->type = ATA_PRIV_TASKFILE;
-
- /*
- * (ks) We transfer currently only whole sectors.
- * This is suffient for now. But, it would be great,
- * if we would find a solution to transfer any size.
- * To support special commands like READ LONG.
- */
- if (nsect) {
- error = blk_rq_map_kern(drive->queue, rq, buf,
- nsect * SECTOR_SIZE, GFP_NOIO);
- if (error)
- goto put_req;
- }
-
- ide_req(rq)->special = cmd;
- cmd->rq = rq;
-
- blk_execute_rq(NULL, rq, 0);
- error = scsi_req(rq)->result ? -EIO : 0;
-put_req:
- blk_put_request(rq);
- return error;
-}
-EXPORT_SYMBOL(ide_raw_taskfile);
-
-int ide_no_data_taskfile(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- cmd->protocol = ATA_PROT_NODATA;
-
- return ide_raw_taskfile(drive, cmd, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(ide_no_data_taskfile);
-
-#ifdef CONFIG_IDE_TASK_IOCTL
-int ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg)
-{
- ide_task_request_t *req_task;
- struct ide_cmd cmd;
- u8 *outbuf = NULL;
- u8 *inbuf = NULL;
- u8 *data_buf = NULL;
- int err = 0;
- int tasksize = sizeof(struct ide_task_request_s);
- unsigned int taskin = 0;
- unsigned int taskout = 0;
- u16 nsect = 0;
- char __user *buf = (char __user *)arg;
-
- req_task = memdup_user(buf, tasksize);
- if (IS_ERR(req_task))
- return PTR_ERR(req_task);
-
- taskout = req_task->out_size;
- taskin = req_task->in_size;
-
- if (taskin > 65536 || taskout > 65536) {
- err = -EINVAL;
- goto abort;
- }
-
- if (taskout) {
- int outtotal = tasksize;
- outbuf = kzalloc(taskout, GFP_KERNEL);
- if (outbuf == NULL) {
- err = -ENOMEM;
- goto abort;
- }
- if (copy_from_user(outbuf, buf + outtotal, taskout)) {
- err = -EFAULT;
- goto abort;
- }
- }
-
- if (taskin) {
- int intotal = tasksize + taskout;
- inbuf = kzalloc(taskin, GFP_KERNEL);
- if (inbuf == NULL) {
- err = -ENOMEM;
- goto abort;
- }
- if (copy_from_user(inbuf, buf + intotal, taskin)) {
- err = -EFAULT;
- goto abort;
- }
- }
-
- memset(&cmd, 0, sizeof(cmd));
-
- memcpy(&cmd.hob, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2);
- memcpy(&cmd.tf, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
-
- cmd.valid.out.tf = IDE_VALID_DEVICE;
- cmd.valid.in.tf = IDE_VALID_DEVICE | IDE_VALID_IN_TF;
- cmd.tf_flags = IDE_TFLAG_IO_16BIT;
-
- if (drive->dev_flags & IDE_DFLAG_LBA48) {
- cmd.tf_flags |= IDE_TFLAG_LBA48;
- cmd.valid.in.hob = IDE_VALID_IN_HOB;
- }
-
- if (req_task->out_flags.all) {
- cmd.ftf_flags |= IDE_FTFLAG_FLAGGED;
-
- if (req_task->out_flags.b.data)
- cmd.ftf_flags |= IDE_FTFLAG_OUT_DATA;
-
- if (req_task->out_flags.b.nsector_hob)
- cmd.valid.out.hob |= IDE_VALID_NSECT;
- if (req_task->out_flags.b.sector_hob)
- cmd.valid.out.hob |= IDE_VALID_LBAL;
- if (req_task->out_flags.b.lcyl_hob)
- cmd.valid.out.hob |= IDE_VALID_LBAM;
- if (req_task->out_flags.b.hcyl_hob)
- cmd.valid.out.hob |= IDE_VALID_LBAH;
-
- if (req_task->out_flags.b.error_feature)
- cmd.valid.out.tf |= IDE_VALID_FEATURE;
- if (req_task->out_flags.b.nsector)
- cmd.valid.out.tf |= IDE_VALID_NSECT;
- if (req_task->out_flags.b.sector)
- cmd.valid.out.tf |= IDE_VALID_LBAL;
- if (req_task->out_flags.b.lcyl)
- cmd.valid.out.tf |= IDE_VALID_LBAM;
- if (req_task->out_flags.b.hcyl)
- cmd.valid.out.tf |= IDE_VALID_LBAH;
- } else {
- cmd.valid.out.tf |= IDE_VALID_OUT_TF;
- if (cmd.tf_flags & IDE_TFLAG_LBA48)
- cmd.valid.out.hob |= IDE_VALID_OUT_HOB;
- }
-
- if (req_task->in_flags.b.data)
- cmd.ftf_flags |= IDE_FTFLAG_IN_DATA;
-
- if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE) {
- /* fixup data phase if needed */
- if (req_task->data_phase == TASKFILE_IN_DMAQ ||
- req_task->data_phase == TASKFILE_IN_DMA)
- cmd.tf_flags |= IDE_TFLAG_WRITE;
- }
-
- cmd.protocol = ATA_PROT_DMA;
-
- switch (req_task->data_phase) {
- case TASKFILE_MULTI_OUT:
- if (!drive->mult_count) {
- /* (hs): give up if multcount is not set */
- pr_err("%s: %s Multimode Write multcount is not set\n",
- drive->name, __func__);
- err = -EPERM;
- goto abort;
- }
- cmd.tf_flags |= IDE_TFLAG_MULTI_PIO;
- fallthrough;
- case TASKFILE_OUT:
- cmd.protocol = ATA_PROT_PIO;
- fallthrough;
- case TASKFILE_OUT_DMAQ:
- case TASKFILE_OUT_DMA:
- cmd.tf_flags |= IDE_TFLAG_WRITE;
- nsect = taskout / SECTOR_SIZE;
- data_buf = outbuf;
- break;
- case TASKFILE_MULTI_IN:
- if (!drive->mult_count) {
- /* (hs): give up if multcount is not set */
- pr_err("%s: %s Multimode Read multcount is not set\n",
- drive->name, __func__);
- err = -EPERM;
- goto abort;
- }
- cmd.tf_flags |= IDE_TFLAG_MULTI_PIO;
- fallthrough;
- case TASKFILE_IN:
- cmd.protocol = ATA_PROT_PIO;
- fallthrough;
- case TASKFILE_IN_DMAQ:
- case TASKFILE_IN_DMA:
- nsect = taskin / SECTOR_SIZE;
- data_buf = inbuf;
- break;
- case TASKFILE_NO_DATA:
- cmd.protocol = ATA_PROT_NODATA;
- break;
- default:
- err = -EFAULT;
- goto abort;
- }
-
- if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA)
- nsect = 0;
- else if (!nsect) {
- nsect = (cmd.hob.nsect << 8) | cmd.tf.nsect;
-
- if (!nsect) {
- pr_err("%s: in/out command without data\n",
- drive->name);
- err = -EFAULT;
- goto abort;
- }
- }
-
- err = ide_raw_taskfile(drive, &cmd, data_buf, nsect);
-
- memcpy(req_task->hob_ports, &cmd.hob, HDIO_DRIVE_HOB_HDR_SIZE - 2);
- memcpy(req_task->io_ports, &cmd.tf, HDIO_DRIVE_TASK_HDR_SIZE);
-
- if ((cmd.ftf_flags & IDE_FTFLAG_SET_IN_FLAGS) &&
- req_task->in_flags.all == 0) {
- req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
- if (drive->dev_flags & IDE_DFLAG_LBA48)
- req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8);
- }
-
- if (copy_to_user(buf, req_task, tasksize)) {
- err = -EFAULT;
- goto abort;
- }
- if (taskout) {
- int outtotal = tasksize;
- if (copy_to_user(buf + outtotal, outbuf, taskout)) {
- err = -EFAULT;
- goto abort;
- }
- }
- if (taskin) {
- int intotal = tasksize + taskout;
- if (copy_to_user(buf + intotal, inbuf, taskin)) {
- err = -EFAULT;
- goto abort;
- }
- }
-abort:
- kfree(req_task);
- kfree(outbuf);
- kfree(inbuf);
-
- return err;
-}
-#endif
diff --git a/drivers/ide/ide-timings.c b/drivers/ide/ide-timings.c
deleted file mode 100644
index cfe78df74b7d..000000000000
--- a/drivers/ide/ide-timings.c
+++ /dev/null
@@ -1,198 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) 1999-2001 Vojtech Pavlik
- * Copyright (c) 2007-2008 Bartlomiej Zolnierkiewicz
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/ide.h>
-#include <linux/module.h>
-
-/*
- * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
- * These were taken from ATA/ATAPI-6 standard, rev 0a, except
- * for PIO 5, which is a nonstandard extension and UDMA6, which
- * is currently supported only by Maxtor drives.
- */
-
-static struct ide_timing ide_timing[] = {
-
- { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 },
- { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 },
- { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 },
- { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 },
-
- { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 },
- { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 },
- { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 },
-
- { XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 80, 0 },
- { XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 100, 0 },
- { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 },
- { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 },
- { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 },
-
- { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 },
- { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 },
- { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 },
-
- { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 80, 0 },
- { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 100, 0 },
- { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 },
- { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 },
-
- { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 },
- { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 },
- { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 },
-
- { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 },
-
- { 0xff }
-};
-
-struct ide_timing *ide_timing_find_mode(u8 speed)
-{
- struct ide_timing *t;
-
- for (t = ide_timing; t->mode != speed; t++)
- if (t->mode == 0xff)
- return NULL;
- return t;
-}
-EXPORT_SYMBOL_GPL(ide_timing_find_mode);
-
-u16 ide_pio_cycle_time(ide_drive_t *drive, u8 pio)
-{
- u16 *id = drive->id;
- struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
- u16 cycle = 0;
-
- if (id[ATA_ID_FIELD_VALID] & 2) {
- if (ata_id_has_iordy(drive->id))
- cycle = id[ATA_ID_EIDE_PIO_IORDY];
- else
- cycle = id[ATA_ID_EIDE_PIO];
-
- /* conservative "downgrade" for all pre-ATA2 drives */
- if (pio < 3 && cycle < t->cycle)
- cycle = 0; /* use standard timing */
-
- /* Use the standard timing for the CF specific modes too */
- if (pio > 4 && ata_id_is_cfa(id))
- cycle = 0;
- }
-
- return cycle ? cycle : t->cycle;
-}
-EXPORT_SYMBOL_GPL(ide_pio_cycle_time);
-
-#define ENOUGH(v, unit) (((v) - 1) / (unit) + 1)
-#define EZ(v, unit) ((v) ? ENOUGH((v) * 1000, unit) : 0)
-
-static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q,
- int T, int UT)
-{
- q->setup = EZ(t->setup, T);
- q->act8b = EZ(t->act8b, T);
- q->rec8b = EZ(t->rec8b, T);
- q->cyc8b = EZ(t->cyc8b, T);
- q->active = EZ(t->active, T);
- q->recover = EZ(t->recover, T);
- q->cycle = EZ(t->cycle, T);
- q->udma = EZ(t->udma, UT);
-}
-
-void ide_timing_merge(struct ide_timing *a, struct ide_timing *b,
- struct ide_timing *m, unsigned int what)
-{
- if (what & IDE_TIMING_SETUP)
- m->setup = max(a->setup, b->setup);
- if (what & IDE_TIMING_ACT8B)
- m->act8b = max(a->act8b, b->act8b);
- if (what & IDE_TIMING_REC8B)
- m->rec8b = max(a->rec8b, b->rec8b);
- if (what & IDE_TIMING_CYC8B)
- m->cyc8b = max(a->cyc8b, b->cyc8b);
- if (what & IDE_TIMING_ACTIVE)
- m->active = max(a->active, b->active);
- if (what & IDE_TIMING_RECOVER)
- m->recover = max(a->recover, b->recover);
- if (what & IDE_TIMING_CYCLE)
- m->cycle = max(a->cycle, b->cycle);
- if (what & IDE_TIMING_UDMA)
- m->udma = max(a->udma, b->udma);
-}
-EXPORT_SYMBOL_GPL(ide_timing_merge);
-
-int ide_timing_compute(ide_drive_t *drive, u8 speed,
- struct ide_timing *t, int T, int UT)
-{
- u16 *id = drive->id;
- struct ide_timing *s, p;
-
- /*
- * Find the mode.
- */
- s = ide_timing_find_mode(speed);
- if (s == NULL)
- return -EINVAL;
-
- /*
- * Copy the timing from the table.
- */
- *t = *s;
-
- /*
- * If the drive is an EIDE drive, it can tell us it needs extended
- * PIO/MWDMA cycle timing.
- */
- if (id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
- memset(&p, 0, sizeof(p));
-
- if (speed >= XFER_PIO_0 && speed < XFER_SW_DMA_0) {
- if (speed <= XFER_PIO_2)
- p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
- else if ((speed <= XFER_PIO_4) ||
- (speed == XFER_PIO_5 && !ata_id_is_cfa(id)))
- p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
- } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
- p.cycle = id[ATA_ID_EIDE_DMA_MIN];
-
- ide_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B);
- }
-
- /*
- * Convert the timing to bus clock counts.
- */
- ide_timing_quantize(t, t, T, UT);
-
- /*
- * Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
- * S.M.A.R.T and some other commands. We have to ensure that the
- * DMA cycle timing is slower/equal than the current PIO timing.
- */
- if (speed >= XFER_SW_DMA_0) {
- ide_timing_compute(drive, drive->pio_mode, &p, T, UT);
- ide_timing_merge(&p, t, t, IDE_TIMING_ALL);
- }
-
- /*
- * Lengthen active & recovery time so that cycle time is correct.
- */
- if (t->act8b + t->rec8b < t->cyc8b) {
- t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2;
- t->rec8b = t->cyc8b - t->act8b;
- }
-
- if (t->active + t->recover < t->cycle) {
- t->active += (t->cycle - (t->active + t->recover)) / 2;
- t->recover = t->cycle - t->active;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ide_timing_compute);
diff --git a/drivers/ide/ide-xfer-mode.c b/drivers/ide/ide-xfer-mode.c
deleted file mode 100644
index 0b9709b489b7..000000000000
--- a/drivers/ide/ide-xfer-mode.c
+++ /dev/null
@@ -1,267 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/interrupt.h>
-#include <linux/ide.h>
-#include <linux/bitops.h>
-
-static const char *udma_str[] =
- { "UDMA/16", "UDMA/25", "UDMA/33", "UDMA/44",
- "UDMA/66", "UDMA/100", "UDMA/133", "UDMA7" };
-static const char *mwdma_str[] =
- { "MWDMA0", "MWDMA1", "MWDMA2", "MWDMA3", "MWDMA4" };
-static const char *swdma_str[] =
- { "SWDMA0", "SWDMA1", "SWDMA2" };
-static const char *pio_str[] =
- { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5", "PIO6" };
-
-/**
- * ide_xfer_verbose - return IDE mode names
- * @mode: transfer mode
- *
- * Returns a constant string giving the name of the mode
- * requested.
- */
-
-const char *ide_xfer_verbose(u8 mode)
-{
- const char *s;
- u8 i = mode & 0xf;
-
- if (mode >= XFER_UDMA_0 && mode <= XFER_UDMA_7)
- s = udma_str[i];
- else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_4)
- s = mwdma_str[i];
- else if (mode >= XFER_SW_DMA_0 && mode <= XFER_SW_DMA_2)
- s = swdma_str[i];
- else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_6)
- s = pio_str[i & 0x7];
- else if (mode == XFER_PIO_SLOW)
- s = "PIO SLOW";
- else
- s = "XFER ERROR";
-
- return s;
-}
-EXPORT_SYMBOL(ide_xfer_verbose);
-
-/**
- * ide_get_best_pio_mode - get PIO mode from drive
- * @drive: drive to consider
- * @mode_wanted: preferred mode
- * @max_mode: highest allowed mode
- *
- * This routine returns the recommended PIO settings for a given drive,
- * based on the drive->id information and the ide_pio_blacklist[].
- *
- * Drive PIO mode is auto-selected if 255 is passed as mode_wanted.
- * This is used by most chipset support modules when "auto-tuning".
- */
-
-static u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
-{
- u16 *id = drive->id;
- int pio_mode = -1, overridden = 0;
-
- if (mode_wanted != 255)
- return min_t(u8, mode_wanted, max_mode);
-
- if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0)
- pio_mode = ide_scan_pio_blacklist((char *)&id[ATA_ID_PROD]);
-
- if (pio_mode != -1) {
- printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name);
- } else {
- pio_mode = id[ATA_ID_OLD_PIO_MODES] >> 8;
- if (pio_mode > 2) { /* 2 is maximum allowed tPIO value */
- pio_mode = 2;
- overridden = 1;
- }
-
- if (id[ATA_ID_FIELD_VALID] & 2) { /* ATA2? */
- if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 7))
- pio_mode = 4 + min_t(int, 2,
- id[ATA_ID_CFA_MODES] & 7);
- else if (ata_id_has_iordy(id)) {
- if (id[ATA_ID_PIO_MODES] & 7) {
- overridden = 0;
- if (id[ATA_ID_PIO_MODES] & 4)
- pio_mode = 5;
- else if (id[ATA_ID_PIO_MODES] & 2)
- pio_mode = 4;
- else
- pio_mode = 3;
- }
- }
- }
-
- if (overridden)
- printk(KERN_INFO "%s: tPIO > 2, assuming tPIO = 2\n",
- drive->name);
- }
-
- if (pio_mode > max_mode)
- pio_mode = max_mode;
-
- return pio_mode;
-}
-
-int ide_pio_need_iordy(ide_drive_t *drive, const u8 pio)
-{
- /*
- * IORDY may lead to controller lock up on certain controllers
- * if the port is not occupied.
- */
- if (pio == 0 && (drive->hwif->port_flags & IDE_PFLAG_PROBING))
- return 0;
- return ata_id_pio_need_iordy(drive->id, pio);
-}
-EXPORT_SYMBOL_GPL(ide_pio_need_iordy);
-
-int ide_set_pio_mode(ide_drive_t *drive, const u8 mode)
-{
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_port_ops *port_ops = hwif->port_ops;
-
- if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
- return 0;
-
- if (port_ops == NULL || port_ops->set_pio_mode == NULL)
- return -1;
-
- /*
- * TODO: temporary hack for some legacy host drivers that didn't
- * set transfer mode on the device in ->set_pio_mode method...
- */
- if (port_ops->set_dma_mode == NULL) {
- drive->pio_mode = mode;
- port_ops->set_pio_mode(hwif, drive);
- return 0;
- }
-
- if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
- if (ide_config_drive_speed(drive, mode))
- return -1;
- drive->pio_mode = mode;
- port_ops->set_pio_mode(hwif, drive);
- return 0;
- } else {
- drive->pio_mode = mode;
- port_ops->set_pio_mode(hwif, drive);
- return ide_config_drive_speed(drive, mode);
- }
-}
-
-int ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
-{
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_port_ops *port_ops = hwif->port_ops;
-
- if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
- return 0;
-
- if (port_ops == NULL || port_ops->set_dma_mode == NULL)
- return -1;
-
- if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
- if (ide_config_drive_speed(drive, mode))
- return -1;
- drive->dma_mode = mode;
- port_ops->set_dma_mode(hwif, drive);
- return 0;
- } else {
- drive->dma_mode = mode;
- port_ops->set_dma_mode(hwif, drive);
- return ide_config_drive_speed(drive, mode);
- }
-}
-EXPORT_SYMBOL_GPL(ide_set_dma_mode);
-
-/* req_pio == "255" for auto-tune */
-void ide_set_pio(ide_drive_t *drive, u8 req_pio)
-{
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_port_ops *port_ops = hwif->port_ops;
- u8 host_pio, pio;
-
- if (port_ops == NULL || port_ops->set_pio_mode == NULL ||
- (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
- return;
-
- BUG_ON(hwif->pio_mask == 0x00);
-
- host_pio = fls(hwif->pio_mask) - 1;
-
- pio = ide_get_best_pio_mode(drive, req_pio, host_pio);
-
- /*
- * TODO:
- * - report device max PIO mode
- * - check req_pio != 255 against device max PIO mode
- */
- printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d\n",
- drive->name, host_pio, req_pio,
- req_pio == 255 ? "(auto-tune)" : "", pio);
-
- (void)ide_set_pio_mode(drive, XFER_PIO_0 + pio);
-}
-EXPORT_SYMBOL_GPL(ide_set_pio);
-
-/**
- * ide_rate_filter - filter transfer mode
- * @drive: IDE device
- * @speed: desired speed
- *
- * Given the available transfer modes this function returns
- * the best available speed at or below the speed requested.
- *
- * TODO: check device PIO capabilities
- */
-
-static u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 mode = ide_find_dma_mode(drive, speed);
-
- if (mode == 0) {
- if (hwif->pio_mask)
- mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0;
- else
- mode = XFER_PIO_4;
- }
-
-/* printk("%s: mode 0x%02x, speed 0x%02x\n", __func__, mode, speed); */
-
- return min(speed, mode);
-}
-
-/**
- * ide_set_xfer_rate - set transfer rate
- * @drive: drive to set
- * @rate: speed to attempt to set
- *
- * General helper for setting the speed of an IDE device. This
- * function knows about user enforced limits from the configuration
- * which ->set_pio_mode/->set_dma_mode does not.
- */
-
-int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
-{
- ide_hwif_t *hwif = drive->hwif;
- const struct ide_port_ops *port_ops = hwif->port_ops;
-
- if (port_ops == NULL || port_ops->set_dma_mode == NULL ||
- (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
- return -1;
-
- rate = ide_rate_filter(drive, rate);
-
- BUG_ON(rate < XFER_PIO_0);
-
- if (rate >= XFER_PIO_0 && rate <= XFER_PIO_6)
- return ide_set_pio_mode(drive, rate);
-
- return ide_set_dma_mode(drive, rate);
-}
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
deleted file mode 100644
index 9a9c64fd1032..000000000000
--- a/drivers/ide/ide.c
+++ /dev/null
@@ -1,415 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
- * Copyright (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz
- */
-
-/*
- * Mostly written by Mark Lord <mlord@pobox.com>
- * and Gadi Oxman <gadio@netvision.net.il>
- * and Andre Hedrick <andre@linux-ide.org>
- *
- * See linux/MAINTAINERS for address of current maintainer.
- *
- * This is the multiple IDE interface driver, as evolved from hd.c.
- * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs
- * (usually 14 & 15).
- * There can be up to two drives per interface, as per the ATA-2 spec.
- *
- * ...
- *
- * From hd.c:
- * |
- * | It traverses the request-list, using interrupts to jump between functions.
- * | As nearly all functions can be called within interrupts, we may not sleep.
- * | Special care is recommended. Have Fun!
- * |
- * | modified by Drew Eckhardt to check nr of hd's from the CMOS.
- * |
- * | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
- * | in the early extended-partition checks and added DM partitions.
- * |
- * | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI).
- * |
- * | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
- * | and general streamlining by Mark Lord (mlord@pobox.com).
- *
- * October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by:
- *
- * Mark Lord (mlord@pobox.com) (IDE Perf.Pkg)
- * Delman Lee (delman@ieee.org) ("Mr. atdisk2")
- * Scott Snyder (snyder@fnald0.fnal.gov) (ATAPI IDE cd-rom)
- *
- * This was a rewrite of just about everything from hd.c, though some original
- * code is still sprinkled about. Think of it as a major evolution, with
- * inspiration from lots of linux users, esp. hamish@zot.apana.org.au
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/hdreg.h>
-#include <linux/completion.h>
-#include <linux/device.h>
-
-struct class *ide_port_class;
-
-/**
- * ide_device_get - get an additional reference to a ide_drive_t
- * @drive: device to get a reference to
- *
- * Gets a reference to the ide_drive_t and increments the use count of the
- * underlying LLDD module.
- */
-int ide_device_get(ide_drive_t *drive)
-{
- struct device *host_dev;
- struct module *module;
-
- if (!get_device(&drive->gendev))
- return -ENXIO;
-
- host_dev = drive->hwif->host->dev[0];
- module = host_dev ? host_dev->driver->owner : NULL;
-
- if (module && !try_module_get(module)) {
- put_device(&drive->gendev);
- return -ENXIO;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ide_device_get);
-
-/**
- * ide_device_put - release a reference to a ide_drive_t
- * @drive: device to release a reference on
- *
- * Release a reference to the ide_drive_t and decrements the use count of
- * the underlying LLDD module.
- */
-void ide_device_put(ide_drive_t *drive)
-{
-#ifdef CONFIG_MODULE_UNLOAD
- struct device *host_dev = drive->hwif->host->dev[0];
- struct module *module = host_dev ? host_dev->driver->owner : NULL;
-
- module_put(module);
-#endif
- put_device(&drive->gendev);
-}
-EXPORT_SYMBOL_GPL(ide_device_put);
-
-static int ide_bus_match(struct device *dev, struct device_driver *drv)
-{
- return 1;
-}
-
-static int ide_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- ide_drive_t *drive = to_ide_device(dev);
-
- add_uevent_var(env, "MEDIA=%s", ide_media_string(drive));
- add_uevent_var(env, "DRIVENAME=%s", drive->name);
- add_uevent_var(env, "MODALIAS=ide:m-%s", ide_media_string(drive));
- return 0;
-}
-
-static int generic_ide_probe(struct device *dev)
-{
- ide_drive_t *drive = to_ide_device(dev);
- struct ide_driver *drv = to_ide_driver(dev->driver);
-
- return drv->probe ? drv->probe(drive) : -ENODEV;
-}
-
-static int generic_ide_remove(struct device *dev)
-{
- ide_drive_t *drive = to_ide_device(dev);
- struct ide_driver *drv = to_ide_driver(dev->driver);
-
- if (drv->remove)
- drv->remove(drive);
-
- return 0;
-}
-
-static void generic_ide_shutdown(struct device *dev)
-{
- ide_drive_t *drive = to_ide_device(dev);
- struct ide_driver *drv = to_ide_driver(dev->driver);
-
- if (dev->driver && drv->shutdown)
- drv->shutdown(drive);
-}
-
-struct bus_type ide_bus_type = {
- .name = "ide",
- .match = ide_bus_match,
- .uevent = ide_uevent,
- .probe = generic_ide_probe,
- .remove = generic_ide_remove,
- .shutdown = generic_ide_shutdown,
- .dev_groups = ide_dev_groups,
- .suspend = generic_ide_suspend,
- .resume = generic_ide_resume,
-};
-
-EXPORT_SYMBOL_GPL(ide_bus_type);
-
-int ide_vlb_clk;
-EXPORT_SYMBOL_GPL(ide_vlb_clk);
-
-module_param_named(vlb_clock, ide_vlb_clk, int, 0);
-MODULE_PARM_DESC(vlb_clock, "VLB clock frequency (in MHz)");
-
-int ide_pci_clk;
-EXPORT_SYMBOL_GPL(ide_pci_clk);
-
-module_param_named(pci_clock, ide_pci_clk, int, 0);
-MODULE_PARM_DESC(pci_clock, "PCI bus clock frequency (in MHz)");
-
-static int ide_set_dev_param_mask(const char *s, const struct kernel_param *kp)
-{
- unsigned int a, b, i, j = 1;
- unsigned int *dev_param_mask = (unsigned int *)kp->arg;
-
- /* controller . device (0 or 1) [ : 1 (set) | 0 (clear) ] */
- if (sscanf(s, "%u.%u:%u", &a, &b, &j) != 3 &&
- sscanf(s, "%u.%u", &a, &b) != 2)
- return -EINVAL;
-
- i = a * MAX_DRIVES + b;
-
- if (i >= MAX_HWIFS * MAX_DRIVES || j > 1)
- return -EINVAL;
-
- if (j)
- *dev_param_mask |= (1 << i);
- else
- *dev_param_mask &= ~(1 << i);
-
- return 0;
-}
-
-static const struct kernel_param_ops param_ops_ide_dev_mask = {
- .set = ide_set_dev_param_mask
-};
-
-#define param_check_ide_dev_mask(name, p) param_check_uint(name, p)
-
-static unsigned int ide_nodma;
-
-module_param_named(nodma, ide_nodma, ide_dev_mask, 0);
-MODULE_PARM_DESC(nodma, "disallow DMA for a device");
-
-static unsigned int ide_noflush;
-
-module_param_named(noflush, ide_noflush, ide_dev_mask, 0);
-MODULE_PARM_DESC(noflush, "disable flush requests for a device");
-
-static unsigned int ide_nohpa;
-
-module_param_named(nohpa, ide_nohpa, ide_dev_mask, 0);
-MODULE_PARM_DESC(nohpa, "disable Host Protected Area for a device");
-
-static unsigned int ide_noprobe;
-
-module_param_named(noprobe, ide_noprobe, ide_dev_mask, 0);
-MODULE_PARM_DESC(noprobe, "skip probing for a device");
-
-static unsigned int ide_nowerr;
-
-module_param_named(nowerr, ide_nowerr, ide_dev_mask, 0);
-MODULE_PARM_DESC(nowerr, "ignore the ATA_DF bit for a device");
-
-static unsigned int ide_cdroms;
-
-module_param_named(cdrom, ide_cdroms, ide_dev_mask, 0);
-MODULE_PARM_DESC(cdrom, "force device as a CD-ROM");
-
-struct chs_geom {
- unsigned int cyl;
- u8 head;
- u8 sect;
-};
-
-static unsigned int ide_disks;
-static struct chs_geom ide_disks_chs[MAX_HWIFS * MAX_DRIVES];
-
-static int ide_set_disk_chs(const char *str, const struct kernel_param *kp)
-{
- unsigned int a, b, c = 0, h = 0, s = 0, i, j = 1;
-
- /* controller . device (0 or 1) : Cylinders , Heads , Sectors */
- /* controller . device (0 or 1) : 1 (use CHS) | 0 (ignore CHS) */
- if (sscanf(str, "%u.%u:%u,%u,%u", &a, &b, &c, &h, &s) != 5 &&
- sscanf(str, "%u.%u:%u", &a, &b, &j) != 3)
- return -EINVAL;
-
- i = a * MAX_DRIVES + b;
-
- if (i >= MAX_HWIFS * MAX_DRIVES || j > 1)
- return -EINVAL;
-
- if (c > INT_MAX || h > 255 || s > 255)
- return -EINVAL;
-
- if (j)
- ide_disks |= (1 << i);
- else
- ide_disks &= ~(1 << i);
-
- ide_disks_chs[i].cyl = c;
- ide_disks_chs[i].head = h;
- ide_disks_chs[i].sect = s;
-
- return 0;
-}
-
-module_param_call(chs, ide_set_disk_chs, NULL, NULL, 0);
-MODULE_PARM_DESC(chs, "force device as a disk (using CHS)");
-
-static void ide_dev_apply_params(ide_drive_t *drive, u8 unit)
-{
- int i = drive->hwif->index * MAX_DRIVES + unit;
-
- if (ide_nodma & (1 << i)) {
- printk(KERN_INFO "ide: disallowing DMA for %s\n", drive->name);
- drive->dev_flags |= IDE_DFLAG_NODMA;
- }
- if (ide_noflush & (1 << i)) {
- printk(KERN_INFO "ide: disabling flush requests for %s\n",
- drive->name);
- drive->dev_flags |= IDE_DFLAG_NOFLUSH;
- }
- if (ide_nohpa & (1 << i)) {
- printk(KERN_INFO "ide: disabling Host Protected Area for %s\n",
- drive->name);
- drive->dev_flags |= IDE_DFLAG_NOHPA;
- }
- if (ide_noprobe & (1 << i)) {
- printk(KERN_INFO "ide: skipping probe for %s\n", drive->name);
- drive->dev_flags |= IDE_DFLAG_NOPROBE;
- }
- if (ide_nowerr & (1 << i)) {
- printk(KERN_INFO "ide: ignoring the ATA_DF bit for %s\n",
- drive->name);
- drive->bad_wstat = BAD_R_STAT;
- }
- if (ide_cdroms & (1 << i)) {
- printk(KERN_INFO "ide: forcing %s as a CD-ROM\n", drive->name);
- drive->dev_flags |= IDE_DFLAG_PRESENT;
- drive->media = ide_cdrom;
- /* an ATAPI device ignores DRDY */
- drive->ready_stat = 0;
- }
- if (ide_disks & (1 << i)) {
- drive->cyl = drive->bios_cyl = ide_disks_chs[i].cyl;
- drive->head = drive->bios_head = ide_disks_chs[i].head;
- drive->sect = drive->bios_sect = ide_disks_chs[i].sect;
-
- printk(KERN_INFO "ide: forcing %s as a disk (%d/%d/%d)\n",
- drive->name,
- drive->cyl, drive->head, drive->sect);
-
- drive->dev_flags |= IDE_DFLAG_FORCED_GEOM | IDE_DFLAG_PRESENT;
- drive->media = ide_disk;
- drive->ready_stat = ATA_DRDY;
- }
-}
-
-static unsigned int ide_ignore_cable;
-
-static int ide_set_ignore_cable(const char *s, const struct kernel_param *kp)
-{
- int i, j = 1;
-
- /* controller (ignore) */
- /* controller : 1 (ignore) | 0 (use) */
- if (sscanf(s, "%d:%d", &i, &j) != 2 && sscanf(s, "%d", &i) != 1)
- return -EINVAL;
-
- if (i >= MAX_HWIFS || j < 0 || j > 1)
- return -EINVAL;
-
- if (j)
- ide_ignore_cable |= (1 << i);
- else
- ide_ignore_cable &= ~(1 << i);
-
- return 0;
-}
-
-module_param_call(ignore_cable, ide_set_ignore_cable, NULL, NULL, 0);
-MODULE_PARM_DESC(ignore_cable, "ignore cable detection");
-
-void ide_port_apply_params(ide_hwif_t *hwif)
-{
- ide_drive_t *drive;
- int i;
-
- if (ide_ignore_cable & (1 << hwif->index)) {
- printk(KERN_INFO "ide: ignoring cable detection for %s\n",
- hwif->name);
- hwif->cbl = ATA_CBL_PATA40_SHORT;
- }
-
- ide_port_for_each_dev(i, drive, hwif)
- ide_dev_apply_params(drive, i);
-}
-
-/*
- * This is gets invoked once during initialization, to set *everything* up
- */
-static int __init ide_init(void)
-{
- int ret;
-
- printk(KERN_INFO "Uniform Multi-Platform E-IDE driver\n");
-
- ret = bus_register(&ide_bus_type);
- if (ret < 0) {
- printk(KERN_WARNING "IDE: bus_register error: %d\n", ret);
- return ret;
- }
-
- ide_port_class = class_create(THIS_MODULE, "ide_port");
- if (IS_ERR(ide_port_class)) {
- ret = PTR_ERR(ide_port_class);
- goto out_port_class;
- }
-
- ide_acpi_init();
-
- proc_ide_create();
-
- return 0;
-
-out_port_class:
- bus_unregister(&ide_bus_type);
-
- return ret;
-}
-
-static void __exit ide_exit(void)
-{
- proc_ide_destroy();
-
- class_destroy(ide_port_class);
-
- bus_unregister(&ide_bus_type);
-}
-
-module_init(ide_init);
-module_exit(ide_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide_platform.c b/drivers/ide/ide_platform.c
deleted file mode 100644
index 91639fd6c276..000000000000
--- a/drivers/ide/ide_platform.c
+++ /dev/null
@@ -1,133 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Platform IDE driver
- *
- * Copyright (C) 2007 MontaVista Software
- *
- * Maintainer: Kumar Gala <galak@kernel.crashing.org>
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/ide.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/ata_platform.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-
-static void plat_ide_setup_ports(struct ide_hw *hw, void __iomem *base,
- void __iomem *ctrl,
- struct pata_platform_info *pdata, int irq)
-{
- unsigned long port = (unsigned long)base;
- int i;
-
- hw->io_ports.data_addr = port;
-
- port += (1 << pdata->ioport_shift);
- for (i = 1; i <= 7;
- i++, port += (1 << pdata->ioport_shift))
- hw->io_ports_array[i] = port;
-
- hw->io_ports.ctl_addr = (unsigned long)ctrl;
-
- hw->irq = irq;
-}
-
-static const struct ide_port_info platform_ide_port_info = {
- .host_flags = IDE_HFLAG_NO_DMA,
- .chipset = ide_generic,
-};
-
-static int plat_ide_probe(struct platform_device *pdev)
-{
- struct resource *res_base, *res_alt, *res_irq;
- void __iomem *base, *alt_base;
- struct pata_platform_info *pdata;
- struct ide_host *host;
- int ret = 0, mmio = 0;
- struct ide_hw hw, *hws[] = { &hw };
- struct ide_port_info d = platform_ide_port_info;
-
- pdata = dev_get_platdata(&pdev->dev);
-
- /* get a pointer to the register memory */
- res_base = platform_get_resource(pdev, IORESOURCE_IO, 0);
- res_alt = platform_get_resource(pdev, IORESOURCE_IO, 1);
-
- if (!res_base || !res_alt) {
- res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- res_alt = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!res_base || !res_alt) {
- ret = -ENOMEM;
- goto out;
- }
- mmio = 1;
- }
-
- res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res_irq) {
- ret = -EINVAL;
- goto out;
- }
-
- if (mmio) {
- base = devm_ioremap(&pdev->dev,
- res_base->start, resource_size(res_base));
- alt_base = devm_ioremap(&pdev->dev,
- res_alt->start, resource_size(res_alt));
- } else {
- base = devm_ioport_map(&pdev->dev,
- res_base->start, resource_size(res_base));
- alt_base = devm_ioport_map(&pdev->dev,
- res_alt->start, resource_size(res_alt));
- }
-
- memset(&hw, 0, sizeof(hw));
- plat_ide_setup_ports(&hw, base, alt_base, pdata, res_irq->start);
- hw.dev = &pdev->dev;
-
- d.irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
- if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
- d.irq_flags |= IRQF_SHARED;
-
- if (mmio)
- d.host_flags |= IDE_HFLAG_MMIO;
-
- ret = ide_host_add(&d, hws, 1, &host);
- if (ret)
- goto out;
-
- platform_set_drvdata(pdev, host);
-
- return 0;
-
-out:
- return ret;
-}
-
-static int plat_ide_remove(struct platform_device *pdev)
-{
- struct ide_host *host = dev_get_drvdata(&pdev->dev);
-
- ide_host_remove(host);
-
- return 0;
-}
-
-static struct platform_driver platform_ide_driver = {
- .driver = {
- .name = "pata_platform",
- },
- .probe = plat_ide_probe,
- .remove = plat_ide_remove,
-};
-
-module_platform_driver(platform_ide_driver);
-
-MODULE_DESCRIPTION("Platform IDE driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pata_platform");
diff --git a/drivers/ide/it8172.c b/drivers/ide/it8172.c
deleted file mode 100644
index b6f674ab4fb7..000000000000
--- a/drivers/ide/it8172.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * IT8172 IDE controller support
- *
- * Copyright (C) 2000 MontaVista Software Inc.
- * Copyright (C) 2008 Shane McDonald
- *
- * 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.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "IT8172"
-
-static void it8172_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u16 drive_enables;
- u32 drive_timing;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
-
- /*
- * The highest value of DIOR/DIOW pulse width and recovery time
- * that can be set in the IT8172 is 8 PCI clock cycles. As a result,
- * it cannot be configured for PIO mode 0. This table sets these
- * parameters to the maximum supported by the IT8172.
- */
- static const u8 timings[] = { 0x3f, 0x3c, 0x1b, 0x12, 0x0a };
-
- pci_read_config_word(dev, 0x40, &drive_enables);
- pci_read_config_dword(dev, 0x44, &drive_timing);
-
- /*
- * Enable port 0x44. The IT8172 spec is confused; it calls
- * this register the "Slave IDE Timing Register", but in fact,
- * it controls timing for both master and slave drives.
- */
- drive_enables |= 0x4000;
-
- drive_enables &= drive->dn ? 0xc006 : 0xc060;
- if (drive->media == ide_disk)
- /* enable prefetch */
- drive_enables |= 0x0004 << (drive->dn * 4);
- if (ide_pio_need_iordy(drive, pio))
- /* enable IORDY sample-point */
- drive_enables |= 0x0002 << (drive->dn * 4);
-
- drive_timing &= drive->dn ? 0x00003f00 : 0x000fc000;
- drive_timing |= timings[pio] << (drive->dn * 6 + 8);
-
- pci_write_config_word(dev, 0x40, drive_enables);
- pci_write_config_dword(dev, 0x44, drive_timing);
-}
-
-static void it8172_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- int a_speed = 3 << (drive->dn * 4);
- int u_flag = 1 << drive->dn;
- int u_speed = 0;
- u8 reg48, reg4a;
- const u8 speed = drive->dma_mode;
-
- pci_read_config_byte(dev, 0x48, &reg48);
- pci_read_config_byte(dev, 0x4a, &reg4a);
-
- if (speed >= XFER_UDMA_0) {
- u8 udma = speed - XFER_UDMA_0;
- u_speed = udma << (drive->dn * 4);
-
- pci_write_config_byte(dev, 0x48, reg48 | u_flag);
- reg4a &= ~a_speed;
- pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
- } else {
- const u8 mwdma_to_pio[] = { 0, 3, 4 };
-
- pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
- pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
-
- drive->pio_mode =
- mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0;
-
- it8172_set_pio_mode(hwif, drive);
- }
-}
-
-
-static const struct ide_port_ops it8172_port_ops = {
- .set_pio_mode = it8172_set_pio_mode,
- .set_dma_mode = it8172_set_dma_mode,
-};
-
-static const struct ide_port_info it8172_port_info = {
- .name = DRV_NAME,
- .port_ops = &it8172_port_ops,
- .enablebits = { {0x41, 0x80, 0x80}, {0x00, 0x00, 0x00} },
- .host_flags = IDE_HFLAG_SINGLE,
- .pio_mask = ATA_PIO4 & ~ATA_PIO0,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA2,
-};
-
-static int it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
- return -ENODEV; /* IT8172 is more than an IDE controller */
- return ide_pci_init_one(dev, &it8172_port_info, NULL);
-}
-
-static struct pci_device_id it8172_pci_tbl[] = {
- { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8172), 0 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, it8172_pci_tbl);
-
-static struct pci_driver it8172_pci_driver = {
- .name = "IT8172_IDE",
- .id_table = it8172_pci_tbl,
- .probe = it8172_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init it8172_ide_init(void)
-{
- return ide_pci_register_driver(&it8172_pci_driver);
-}
-
-static void __exit it8172_ide_exit(void)
-{
- pci_unregister_driver(&it8172_pci_driver);
-}
-
-module_init(it8172_ide_init);
-module_exit(it8172_ide_exit);
-
-MODULE_AUTHOR("Steve Longerbeam");
-MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/it8213.c b/drivers/ide/it8213.c
deleted file mode 100644
index d0bf4430c437..000000000000
--- a/drivers/ide/it8213.c
+++ /dev/null
@@ -1,217 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * ITE 8213 IDE driver
- *
- * Copyright (C) 2006 Jack Lee
- * Copyright (C) 2006 Alan Cox
- * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "it8213"
-
-/**
- * it8213_set_pio_mode - set host controller for PIO mode
- * @hwif: port
- * @drive: drive
- *
- * Set the interface PIO mode.
- */
-
-static void it8213_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- int is_slave = drive->dn & 1;
- int master_port = 0x40;
- int slave_port = 0x44;
- unsigned long flags;
- u16 master_data;
- u8 slave_data;
- static DEFINE_SPINLOCK(tune_lock);
- int control = 0;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
-
- static const u8 timings[][2] = {
- { 0, 0 },
- { 0, 0 },
- { 1, 0 },
- { 2, 1 },
- { 2, 3 }, };
-
- spin_lock_irqsave(&tune_lock, flags);
- pci_read_config_word(dev, master_port, &master_data);
-
- if (pio > 1)
- control |= 1; /* Programmable timing on */
- if (drive->media != ide_disk)
- control |= 4; /* ATAPI */
- if (ide_pio_need_iordy(drive, pio))
- control |= 2; /* IORDY */
- if (is_slave) {
- master_data |= 0x4000;
- master_data &= ~0x0070;
- if (pio > 1)
- master_data = master_data | (control << 4);
- pci_read_config_byte(dev, slave_port, &slave_data);
- slave_data = slave_data & 0xf0;
- slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1];
- } else {
- master_data &= ~0x3307;
- if (pio > 1)
- master_data = master_data | control;
- master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
- }
- pci_write_config_word(dev, master_port, master_data);
- if (is_slave)
- pci_write_config_byte(dev, slave_port, slave_data);
- spin_unlock_irqrestore(&tune_lock, flags);
-}
-
-/**
- * it8213_set_dma_mode - set host controller for DMA mode
- * @hwif: port
- * @drive: drive
- *
- * Tune the ITE chipset for the DMA mode.
- */
-
-static void it8213_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 maslave = 0x40;
- int a_speed = 3 << (drive->dn * 4);
- int u_flag = 1 << drive->dn;
- int v_flag = 0x01 << drive->dn;
- int w_flag = 0x10 << drive->dn;
- int u_speed = 0;
- u16 reg4042, reg4a;
- u8 reg48, reg54, reg55;
- const u8 speed = drive->dma_mode;
-
- pci_read_config_word(dev, maslave, &reg4042);
- pci_read_config_byte(dev, 0x48, &reg48);
- pci_read_config_word(dev, 0x4a, &reg4a);
- pci_read_config_byte(dev, 0x54, &reg54);
- pci_read_config_byte(dev, 0x55, &reg55);
-
- if (speed >= XFER_UDMA_0) {
- u8 udma = speed - XFER_UDMA_0;
-
- u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4);
-
- if (!(reg48 & u_flag))
- pci_write_config_byte(dev, 0x48, reg48 | u_flag);
- if (speed >= XFER_UDMA_5)
- pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
- else
- pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
-
- if ((reg4a & a_speed) != u_speed)
- pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
- if (speed > XFER_UDMA_2) {
- if (!(reg54 & v_flag))
- pci_write_config_byte(dev, 0x54, reg54 | v_flag);
- } else
- pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
- } else {
- const u8 mwdma_to_pio[] = { 0, 3, 4 };
-
- if (reg48 & u_flag)
- pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
- if (reg4a & a_speed)
- pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
- if (reg54 & v_flag)
- pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
- if (reg55 & w_flag)
- pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
-
- if (speed >= XFER_MW_DMA_0)
- drive->pio_mode =
- mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0;
- else
- drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */
-
- it8213_set_pio_mode(hwif, drive);
- }
-}
-
-static u8 it8213_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 reg42h = 0;
-
- pci_read_config_byte(dev, 0x42, &reg42h);
-
- return (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-}
-
-static const struct ide_port_ops it8213_port_ops = {
- .set_pio_mode = it8213_set_pio_mode,
- .set_dma_mode = it8213_set_dma_mode,
- .cable_detect = it8213_cable_detect,
-};
-
-static const struct ide_port_info it8213_chipset = {
- .name = DRV_NAME,
- .enablebits = { {0x41, 0x80, 0x80} },
- .port_ops = &it8213_port_ops,
- .host_flags = IDE_HFLAG_SINGLE,
- .pio_mask = ATA_PIO4,
- .swdma_mask = ATA_SWDMA2_ONLY,
- .mwdma_mask = ATA_MWDMA12_ONLY,
- .udma_mask = ATA_UDMA6,
-};
-
-/**
- * it8213_init_one - pci layer discovery entry
- * @dev: PCI device
- * @id: ident table entry
- *
- * Called by the PCI code when it finds an ITE8213 controller. As
- * this device follows the standard interfaces we can use the
- * standard helper functions to do almost all the work for us.
- */
-
-static int it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- return ide_pci_init_one(dev, &it8213_chipset, NULL);
-}
-
-static const struct pci_device_id it8213_pci_tbl[] = {
- { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8213), 0 },
- { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
-
-static struct pci_driver it8213_pci_driver = {
- .name = "ITE8213_IDE",
- .id_table = it8213_pci_tbl,
- .probe = it8213_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init it8213_ide_init(void)
-{
- return ide_pci_register_driver(&it8213_pci_driver);
-}
-
-static void __exit it8213_ide_exit(void)
-{
- pci_unregister_driver(&it8213_pci_driver);
-}
-
-module_init(it8213_ide_init);
-module_exit(it8213_ide_exit);
-
-MODULE_AUTHOR("Jack Lee, Alan Cox");
-MODULE_DESCRIPTION("PCI driver module for the ITE 8213");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/it821x.c b/drivers/ide/it821x.c
deleted file mode 100644
index 36a64c8ea575..000000000000
--- a/drivers/ide/it821x.c
+++ /dev/null
@@ -1,715 +0,0 @@
-/*
- * Copyright (C) 2004 Red Hat
- * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
- *
- * May be copied or modified under the terms of the GNU General Public License
- * Based in part on the ITE vendor provided SCSI driver.
- *
- * Documentation:
- * Datasheet is freely available, some other documents under NDA.
- *
- * The ITE8212 isn't exactly a standard IDE controller. It has two
- * modes. In pass through mode then it is an IDE controller. In its smart
- * mode its actually quite a capable hardware raid controller disguised
- * as an IDE controller. Smart mode only understands DMA read/write and
- * identify, none of the fancier commands apply. The IT8211 is identical
- * in other respects but lacks the raid mode.
- *
- * Errata:
- * o Rev 0x10 also requires master/slave hold the same DMA timings and
- * cannot do ATAPI MWDMA.
- * o The identify data for raid volumes lacks CHS info (technically ok)
- * but also fails to set the LBA28 and other bits. We fix these in
- * the IDE probe quirk code.
- * o If you write LBA48 sized I/O's (ie > 256 sector) in smart mode
- * raid then the controller firmware dies
- * o Smart mode without RAID doesn't clear all the necessary identify
- * bits to reduce the command set to the one used
- *
- * This has a few impacts on the driver
- * - In pass through mode we do all the work you would expect
- * - In smart mode the clocking set up is done by the controller generally
- * but we must watch the other limits and filter.
- * - There are a few extra vendor commands that actually talk to the
- * controller but only work PIO with no IRQ.
- *
- * Vendor areas of the identify block in smart mode are used for the
- * timing and policy set up. Each HDD in raid mode also has a serial
- * block on the disk. The hardware extra commands are get/set chip status,
- * rebuild, get rebuild status.
- *
- * In Linux the driver supports pass through mode as if the device was
- * just another IDE controller. If the smart mode is running then
- * volumes are managed by the controller firmware and each IDE "disk"
- * is a raid volume. Even more cute - the controller can do automated
- * hotplug and rebuild.
- *
- * The pass through controller itself is a little demented. It has a
- * flaw that it has a single set of PIO/MWDMA timings per channel so
- * non UDMA devices restrict each others performance. It also has a
- * single clock source per channel so mixed UDMA100/133 performance
- * isn't perfect and we have to pick a clock. Thankfully none of this
- * matters in smart mode. ATAPI DMA is not currently supported.
- *
- * It seems the smart mode is a win for RAID1/RAID10 but otherwise not.
- *
- * TODO
- * - ATAPI UDMA is ok but not MWDMA it seems
- * - RAID configuration ioctls
- * - Move to libata once it grows up
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "it821x"
-
-#define QUIRK_VORTEX86 1
-
-struct it821x_dev
-{
- unsigned int smart:1, /* Are we in smart raid mode */
- timing10:1; /* Rev 0x10 */
- u8 clock_mode; /* 0, ATA_50 or ATA_66 */
- u8 want[2][2]; /* Mode/Pri log for master slave */
- /* We need these for switching the clock when DMA goes on/off
- The high byte is the 66Mhz timing */
- u16 pio[2]; /* Cached PIO values */
- u16 mwdma[2]; /* Cached MWDMA values */
- u16 udma[2]; /* Cached UDMA values (per drive) */
- u16 quirks;
-};
-
-#define ATA_66 0
-#define ATA_50 1
-#define ATA_ANY 2
-
-#define UDMA_OFF 0
-#define MWDMA_OFF 0
-
-/*
- * We allow users to force the card into non raid mode without
- * flashing the alternative BIOS. This is also necessary right now
- * for embedded platforms that cannot run a PC BIOS but are using this
- * device.
- */
-
-static int it8212_noraid;
-
-/**
- * it821x_program - program the PIO/MWDMA registers
- * @drive: drive to tune
- * @timing: timing info
- *
- * Program the PIO/MWDMA timing for this channel according to the
- * current clock.
- */
-
-static void it821x_program(ide_drive_t *drive, u16 timing)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct it821x_dev *itdev = ide_get_hwifdata(hwif);
- int channel = hwif->channel;
- u8 conf;
-
- /* Program PIO/MWDMA timing bits */
- if(itdev->clock_mode == ATA_66)
- conf = timing >> 8;
- else
- conf = timing & 0xFF;
-
- pci_write_config_byte(dev, 0x54 + 4 * channel, conf);
-}
-
-/**
- * it821x_program_udma - program the UDMA registers
- * @drive: drive to tune
- * @timing: timing info
- *
- * Program the UDMA timing for this drive according to the
- * current clock.
- */
-
-static void it821x_program_udma(ide_drive_t *drive, u16 timing)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct it821x_dev *itdev = ide_get_hwifdata(hwif);
- int channel = hwif->channel;
- u8 unit = drive->dn & 1, conf;
-
- /* Program UDMA timing bits */
- if(itdev->clock_mode == ATA_66)
- conf = timing >> 8;
- else
- conf = timing & 0xFF;
-
- if (itdev->timing10 == 0)
- pci_write_config_byte(dev, 0x56 + 4 * channel + unit, conf);
- else {
- pci_write_config_byte(dev, 0x56 + 4 * channel, conf);
- pci_write_config_byte(dev, 0x56 + 4 * channel + 1, conf);
- }
-}
-
-/**
- * it821x_clock_strategy
- * @drive: drive to set up
- *
- * Select between the 50 and 66Mhz base clocks to get the best
- * results for this interface.
- */
-
-static void it821x_clock_strategy(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct it821x_dev *itdev = ide_get_hwifdata(hwif);
- ide_drive_t *pair = ide_get_pair_dev(drive);
- int clock, altclock, sel = 0;
- u8 unit = drive->dn & 1, v;
-
- if(itdev->want[0][0] > itdev->want[1][0]) {
- clock = itdev->want[0][1];
- altclock = itdev->want[1][1];
- } else {
- clock = itdev->want[1][1];
- altclock = itdev->want[0][1];
- }
-
- /*
- * if both clocks can be used for the mode with the higher priority
- * use the clock needed by the mode with the lower priority
- */
- if (clock == ATA_ANY)
- clock = altclock;
-
- /* Nobody cares - keep the same clock */
- if(clock == ATA_ANY)
- return;
- /* No change */
- if(clock == itdev->clock_mode)
- return;
-
- /* Load this into the controller ? */
- if(clock == ATA_66)
- itdev->clock_mode = ATA_66;
- else {
- itdev->clock_mode = ATA_50;
- sel = 1;
- }
-
- pci_read_config_byte(dev, 0x50, &v);
- v &= ~(1 << (1 + hwif->channel));
- v |= sel << (1 + hwif->channel);
- pci_write_config_byte(dev, 0x50, v);
-
- /*
- * Reprogram the UDMA/PIO of the pair drive for the switch
- * MWDMA will be dealt with by the dma switcher
- */
- if(pair && itdev->udma[1-unit] != UDMA_OFF) {
- it821x_program_udma(pair, itdev->udma[1-unit]);
- it821x_program(pair, itdev->pio[1-unit]);
- }
- /*
- * Reprogram the UDMA/PIO of our drive for the switch.
- * MWDMA will be dealt with by the dma switcher
- */
- if(itdev->udma[unit] != UDMA_OFF) {
- it821x_program_udma(drive, itdev->udma[unit]);
- it821x_program(drive, itdev->pio[unit]);
- }
-}
-
-/**
- * it821x_set_pio_mode - set host controller for PIO mode
- * @hwif: port
- * @drive: drive
- *
- * Tune the host to the desired PIO mode taking into the consideration
- * the maximum PIO mode supported by the other device on the cable.
- */
-
-static void it821x_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct it821x_dev *itdev = ide_get_hwifdata(hwif);
- ide_drive_t *pair = ide_get_pair_dev(drive);
- const u8 pio = drive->pio_mode - XFER_PIO_0;
- u8 unit = drive->dn & 1, set_pio = pio;
-
- /* Spec says 89 ref driver uses 88 */
- static u16 pio_timings[]= { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
- static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
-
- /*
- * Compute the best PIO mode we can for a given device. We must
- * pick a speed that does not cause problems with the other device
- * on the cable.
- */
- if (pair) {
- u8 pair_pio = pair->pio_mode - XFER_PIO_0;
- /* trim PIO to the slowest of the master/slave */
- if (pair_pio < set_pio)
- set_pio = pair_pio;
- }
-
- /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
- itdev->want[unit][1] = pio_want[set_pio];
- itdev->want[unit][0] = 1; /* PIO is lowest priority */
- itdev->pio[unit] = pio_timings[set_pio];
- it821x_clock_strategy(drive);
- it821x_program(drive, itdev->pio[unit]);
-}
-
-/**
- * it821x_tune_mwdma - tune a channel for MWDMA
- * @drive: drive to set up
- * @mode_wanted: the target operating mode
- *
- * Load the timing settings for this device mode into the
- * controller when doing MWDMA in pass through mode. The caller
- * must manage the whole lack of per device MWDMA/PIO timings and
- * the shared MWDMA/PIO timing register.
- */
-
-static void it821x_tune_mwdma(ide_drive_t *drive, u8 mode_wanted)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif);
- u8 unit = drive->dn & 1, channel = hwif->channel, conf;
-
- static u16 dma[] = { 0x8866, 0x3222, 0x3121 };
- static u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY };
-
- itdev->want[unit][1] = mwdma_want[mode_wanted];
- itdev->want[unit][0] = 2; /* MWDMA is low priority */
- itdev->mwdma[unit] = dma[mode_wanted];
- itdev->udma[unit] = UDMA_OFF;
-
- /* UDMA bits off - Revision 0x10 do them in pairs */
- pci_read_config_byte(dev, 0x50, &conf);
- if (itdev->timing10)
- conf |= channel ? 0x60: 0x18;
- else
- conf |= 1 << (3 + 2 * channel + unit);
- pci_write_config_byte(dev, 0x50, conf);
-
- it821x_clock_strategy(drive);
- /* FIXME: do we need to program this ? */
- /* it821x_program(drive, itdev->mwdma[unit]); */
-}
-
-/**
- * it821x_tune_udma - tune a channel for UDMA
- * @drive: drive to set up
- * @mode_wanted: the target operating mode
- *
- * Load the timing settings for this device mode into the
- * controller when doing UDMA modes in pass through.
- */
-
-static void it821x_tune_udma(ide_drive_t *drive, u8 mode_wanted)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct it821x_dev *itdev = ide_get_hwifdata(hwif);
- u8 unit = drive->dn & 1, channel = hwif->channel, conf;
-
- static u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 };
- static u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 };
-
- itdev->want[unit][1] = udma_want[mode_wanted];
- itdev->want[unit][0] = 3; /* UDMA is high priority */
- itdev->mwdma[unit] = MWDMA_OFF;
- itdev->udma[unit] = udma[mode_wanted];
- if(mode_wanted >= 5)
- itdev->udma[unit] |= 0x8080; /* UDMA 5/6 select on */
-
- /* UDMA on. Again revision 0x10 must do the pair */
- pci_read_config_byte(dev, 0x50, &conf);
- if (itdev->timing10)
- conf &= channel ? 0x9F: 0xE7;
- else
- conf &= ~ (1 << (3 + 2 * channel + unit));
- pci_write_config_byte(dev, 0x50, conf);
-
- it821x_clock_strategy(drive);
- it821x_program_udma(drive, itdev->udma[unit]);
-
-}
-
-/**
- * it821x_dma_read - DMA hook
- * @drive: drive for DMA
- *
- * The IT821x has a single timing register for MWDMA and for PIO
- * operations. As we flip back and forth we have to reload the
- * clock. In addition the rev 0x10 device only works if the same
- * timing value is loaded into the master and slave UDMA clock
- * so we must also reload that.
- *
- * FIXME: we could figure out in advance if we need to do reloads
- */
-
-static void it821x_dma_start(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct it821x_dev *itdev = ide_get_hwifdata(hwif);
- u8 unit = drive->dn & 1;
-
- if(itdev->mwdma[unit] != MWDMA_OFF)
- it821x_program(drive, itdev->mwdma[unit]);
- else if(itdev->udma[unit] != UDMA_OFF && itdev->timing10)
- it821x_program_udma(drive, itdev->udma[unit]);
- ide_dma_start(drive);
-}
-
-/**
- * it821x_dma_write - DMA hook
- * @drive: drive for DMA stop
- *
- * The IT821x has a single timing register for MWDMA and for PIO
- * operations. As we flip back and forth we have to reload the
- * clock.
- */
-
-static int it821x_dma_end(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct it821x_dev *itdev = ide_get_hwifdata(hwif);
- int ret = ide_dma_end(drive);
- u8 unit = drive->dn & 1;
-
- if(itdev->mwdma[unit] != MWDMA_OFF)
- it821x_program(drive, itdev->pio[unit]);
- return ret;
-}
-
-/**
- * it821x_set_dma_mode - set host controller for DMA mode
- * @hwif: port
- * @drive: drive
- *
- * Tune the ITE chipset for the desired DMA mode.
- */
-
-static void it821x_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- const u8 speed = drive->dma_mode;
-
- /*
- * MWDMA tuning is really hard because our MWDMA and PIO
- * timings are kept in the same place. We can switch in the
- * host dma on/off callbacks.
- */
- if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_6)
- it821x_tune_udma(drive, speed - XFER_UDMA_0);
- else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
- it821x_tune_mwdma(drive, speed - XFER_MW_DMA_0);
-}
-
-/**
- * it821x_cable_detect - cable detection
- * @hwif: interface to check
- *
- * Check for the presence of an ATA66 capable cable on the
- * interface. Problematic as it seems some cards don't have
- * the needed logic onboard.
- */
-
-static u8 it821x_cable_detect(ide_hwif_t *hwif)
-{
- /* The reference driver also only does disk side */
- return ATA_CBL_PATA80;
-}
-
-/**
- * it821x_quirkproc - post init callback
- * @drive: drive
- *
- * This callback is run after the drive has been probed but
- * before anything gets attached. It allows drivers to do any
- * final tuning that is needed, or fixups to work around bugs.
- */
-
-static void it821x_quirkproc(ide_drive_t *drive)
-{
- struct it821x_dev *itdev = ide_get_hwifdata(drive->hwif);
- u16 *id = drive->id;
-
- if (!itdev->smart) {
- /*
- * If we are in pass through mode then not much
- * needs to be done, but we do bother to clear the
- * IRQ mask as we may well be in PIO (eg rev 0x10)
- * for now and we know unmasking is safe on this chipset.
- */
- drive->dev_flags |= IDE_DFLAG_UNMASK;
- } else {
- /*
- * Perform fixups on smart mode. We need to "lose" some
- * capabilities the firmware lacks but does not filter, and
- * also patch up some capability bits that it forgets to set
- * in RAID mode.
- */
-
- /* Check for RAID v native */
- if (strstr((char *)&id[ATA_ID_PROD],
- "Integrated Technology Express")) {
- /* In raid mode the ident block is slightly buggy
- We need to set the bits so that the IDE layer knows
- LBA28. LBA48 and DMA ar valid */
- id[ATA_ID_CAPABILITY] |= (3 << 8); /* LBA28, DMA */
- id[ATA_ID_COMMAND_SET_2] |= 0x0400; /* LBA48 valid */
- id[ATA_ID_CFS_ENABLE_2] |= 0x0400; /* LBA48 on */
- /* Reporting logic */
- printk(KERN_INFO "%s: IT8212 %sRAID %d volume",
- drive->name, id[147] ? "Bootable " : "",
- id[ATA_ID_CSFO]);
- if (id[ATA_ID_CSFO] != 1)
- printk(KERN_CONT "(%dK stripe)", id[146]);
- printk(KERN_CONT ".\n");
- } else {
- /* Non RAID volume. Fixups to stop the core code
- doing unsupported things */
- id[ATA_ID_FIELD_VALID] &= 3;
- id[ATA_ID_QUEUE_DEPTH] = 0;
- id[ATA_ID_COMMAND_SET_1] = 0;
- id[ATA_ID_COMMAND_SET_2] &= 0xC400;
- id[ATA_ID_CFSSE] &= 0xC000;
- id[ATA_ID_CFS_ENABLE_1] = 0;
- id[ATA_ID_CFS_ENABLE_2] &= 0xC400;
- id[ATA_ID_CSF_DEFAULT] &= 0xC000;
- id[127] = 0;
- id[ATA_ID_DLF] = 0;
- id[ATA_ID_CSFO] = 0;
- id[ATA_ID_CFA_POWER] = 0;
- printk(KERN_INFO "%s: Performing identify fixups.\n",
- drive->name);
- }
-
- /*
- * Set MWDMA0 mode as enabled/support - just to tell
- * IDE core that DMA is supported (it821x hardware
- * takes care of DMA mode programming).
- */
- if (ata_id_has_dma(id)) {
- id[ATA_ID_MWDMA_MODES] |= 0x0101;
- drive->current_speed = XFER_MW_DMA_0;
- }
- }
-
-}
-
-static const struct ide_dma_ops it821x_pass_through_dma_ops = {
- .dma_host_set = ide_dma_host_set,
- .dma_setup = ide_dma_setup,
- .dma_start = it821x_dma_start,
- .dma_end = it821x_dma_end,
- .dma_test_irq = ide_dma_test_irq,
- .dma_lost_irq = ide_dma_lost_irq,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_sff_read_status = ide_dma_sff_read_status,
-};
-
-/**
- * init_hwif_it821x - set up hwif structs
- * @hwif: interface to set up
- *
- * We do the basic set up of the interface structure. The IT8212
- * requires several custom handlers so we override the default
- * ide DMA handlers appropriately
- */
-
-static void init_hwif_it821x(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct ide_host *host = pci_get_drvdata(dev);
- struct it821x_dev *itdevs = host->host_priv;
- struct it821x_dev *idev = itdevs + hwif->channel;
- u8 conf;
-
- ide_set_hwifdata(hwif, idev);
-
- pci_read_config_byte(dev, 0x50, &conf);
- if (conf & 1) {
- idev->smart = 1;
- hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
- /* Long I/O's although allowed in LBA48 space cause the
- onboard firmware to enter the twighlight zone */
- hwif->rqsize = 256;
- }
-
- /* Pull the current clocks from 0x50 also */
- if (conf & (1 << (1 + hwif->channel)))
- idev->clock_mode = ATA_50;
- else
- idev->clock_mode = ATA_66;
-
- idev->want[0][1] = ATA_ANY;
- idev->want[1][1] = ATA_ANY;
-
- /*
- * Not in the docs but according to the reference driver
- * this is necessary.
- */
-
- if (dev->revision == 0x10) {
- idev->timing10 = 1;
- hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
- if (idev->smart == 0)
- printk(KERN_WARNING DRV_NAME " %s: revision 0x10, "
- "workarounds activated\n", pci_name(dev));
- }
-
- if (idev->smart == 0) {
- /* MWDMA/PIO clock switching for pass through mode */
- hwif->dma_ops = &it821x_pass_through_dma_ops;
- } else
- hwif->host_flags |= IDE_HFLAG_NO_SET_MODE;
-
- if (hwif->dma_base == 0)
- return;
-
- hwif->ultra_mask = ATA_UDMA6;
- hwif->mwdma_mask = ATA_MWDMA2;
-
- /* Vortex86SX quirk: prevent Ultra-DMA mode to fix BadCRC issue */
- if (idev->quirks & QUIRK_VORTEX86) {
- if (dev->revision == 0x11)
- hwif->ultra_mask = 0;
- }
-}
-
-static void it8212_disable_raid(struct pci_dev *dev)
-{
- /* Reset local CPU, and set BIOS not ready */
- pci_write_config_byte(dev, 0x5E, 0x01);
-
- /* Set to bypass mode, and reset PCI bus */
- pci_write_config_byte(dev, 0x50, 0x00);
- pci_write_config_word(dev, PCI_COMMAND,
- PCI_COMMAND_PARITY | PCI_COMMAND_IO |
- PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
- pci_write_config_word(dev, 0x40, 0xA0F3);
-
- pci_write_config_dword(dev,0x4C, 0x02040204);
- pci_write_config_byte(dev, 0x42, 0x36);
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
-}
-
-static int init_chipset_it821x(struct pci_dev *dev)
-{
- u8 conf;
- static char *mode[2] = { "pass through", "smart" };
-
- /* Force the card into bypass mode if so requested */
- if (it8212_noraid) {
- printk(KERN_INFO DRV_NAME " %s: forcing bypass mode\n",
- pci_name(dev));
- it8212_disable_raid(dev);
- }
- pci_read_config_byte(dev, 0x50, &conf);
- printk(KERN_INFO DRV_NAME " %s: controller in %s mode\n",
- pci_name(dev), mode[conf & 1]);
- return 0;
-}
-
-static const struct ide_port_ops it821x_port_ops = {
- /* it821x_set_{pio,dma}_mode() are only used in pass-through mode */
- .set_pio_mode = it821x_set_pio_mode,
- .set_dma_mode = it821x_set_dma_mode,
- .quirkproc = it821x_quirkproc,
- .cable_detect = it821x_cable_detect,
-};
-
-static const struct ide_port_info it821x_chipset = {
- .name = DRV_NAME,
- .init_chipset = init_chipset_it821x,
- .init_hwif = init_hwif_it821x,
- .port_ops = &it821x_port_ops,
- .pio_mask = ATA_PIO4,
-};
-
-/**
- * it821x_init_one - pci layer discovery entry
- * @dev: PCI device
- * @id: ident table entry
- *
- * Called by the PCI code when it finds an ITE821x controller.
- * We then use the IDE PCI generic helper to do most of the work.
- */
-
-static int it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct it821x_dev *itdevs;
- int rc;
-
- itdevs = kcalloc(2, sizeof(*itdevs), GFP_KERNEL);
- if (itdevs == NULL) {
- printk(KERN_ERR DRV_NAME " %s: out of memory\n", pci_name(dev));
- return -ENOMEM;
- }
-
- itdevs->quirks = id->driver_data;
-
- rc = ide_pci_init_one(dev, &it821x_chipset, itdevs);
- if (rc)
- kfree(itdevs);
-
- return rc;
-}
-
-static void it821x_remove(struct pci_dev *dev)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- struct it821x_dev *itdevs = host->host_priv;
-
- ide_pci_remove(dev);
- kfree(itdevs);
-}
-
-static const struct pci_device_id it821x_pci_tbl[] = {
- { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), 0 },
- { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), 0 },
- { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1010), QUIRK_VORTEX86 },
- { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, it821x_pci_tbl);
-
-static struct pci_driver it821x_pci_driver = {
- .name = "ITE821x IDE",
- .id_table = it821x_pci_tbl,
- .probe = it821x_init_one,
- .remove = it821x_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init it821x_ide_init(void)
-{
- return ide_pci_register_driver(&it821x_pci_driver);
-}
-
-static void __exit it821x_ide_exit(void)
-{
- pci_unregister_driver(&it821x_pci_driver);
-}
-
-module_init(it821x_ide_init);
-module_exit(it821x_ide_exit);
-
-module_param_named(noraid, it8212_noraid, int, S_IRUGO);
-MODULE_PARM_DESC(noraid, "Force card into bypass mode");
-
-MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("PCI driver module for the ITE 821x");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/jmicron.c b/drivers/ide/jmicron.c
deleted file mode 100644
index ae6480dcbadf..000000000000
--- a/drivers/ide/jmicron.c
+++ /dev/null
@@ -1,176 +0,0 @@
-
-/*
- * Copyright (C) 2006 Red Hat
- *
- * May be copied or modified under the terms of the GNU General Public License
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "jmicron"
-
-typedef enum {
- PORT_PATA0 = 0,
- PORT_PATA1 = 1,
- PORT_SATA = 2,
-} port_type;
-
-/**
- * jmicron_cable_detect - cable detection
- * @hwif: IDE port
- *
- * Returns the cable type.
- */
-
-static u8 jmicron_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *pdev = to_pci_dev(hwif->dev);
-
- u32 control;
- u32 control5;
-
- int port = hwif->channel;
- port_type port_map[2];
-
- pci_read_config_dword(pdev, 0x40, &control);
-
- /* There are two basic mappings. One has the two SATA ports merged
- as master/slave and the secondary as PATA, the other has only the
- SATA port mapped */
- if (control & (1 << 23)) {
- port_map[0] = PORT_SATA;
- port_map[1] = PORT_PATA0;
- } else {
- port_map[0] = PORT_SATA;
- port_map[1] = PORT_SATA;
- }
-
- /* The 365/366 may have this bit set to map the second PATA port
- as the internal primary channel */
- pci_read_config_dword(pdev, 0x80, &control5);
- if (control5 & (1<<24))
- port_map[0] = PORT_PATA1;
-
- /* The two ports may then be logically swapped by the firmware */
- if (control & (1 << 22))
- port = port ^ 1;
-
- /*
- * Now we know which physical port we are talking about we can
- * actually do our cable checking etc. Thankfully we don't need
- * to do the plumbing for other cases.
- */
- switch (port_map[port]) {
- case PORT_PATA0:
- if (control & (1 << 3)) /* 40/80 pin primary */
- return ATA_CBL_PATA40;
- return ATA_CBL_PATA80;
- case PORT_PATA1:
- if (control5 & (1 << 19)) /* 40/80 pin secondary */
- return ATA_CBL_PATA40;
- return ATA_CBL_PATA80;
- case PORT_SATA:
- break;
- }
- /* Avoid bogus "control reaches end of non-void function" */
- return ATA_CBL_PATA80;
-}
-
-static void jmicron_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-}
-
-/**
- * jmicron_set_dma_mode - set host controller for DMA mode
- * @hwif: port
- * @drive: drive
- *
- * As the JMicron snoops for timings we don't need to do anything here.
- */
-
-static void jmicron_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-}
-
-static const struct ide_port_ops jmicron_port_ops = {
- .set_pio_mode = jmicron_set_pio_mode,
- .set_dma_mode = jmicron_set_dma_mode,
- .cable_detect = jmicron_cable_detect,
-};
-
-static const struct ide_port_info jmicron_chipset = {
- .name = DRV_NAME,
- .enablebits = { { 0x40, 0x01, 0x01 }, { 0x40, 0x10, 0x10 } },
- .port_ops = &jmicron_port_ops,
- .pio_mask = ATA_PIO5,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA6,
-};
-
-/**
- * jmicron_init_one - pci layer discovery entry
- * @dev: PCI device
- * @id: ident table entry
- *
- * Called by the PCI code when it finds a Jmicron controller.
- * We then use the IDE PCI generic helper to do most of the work.
- */
-
-static int jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- return ide_pci_init_one(dev, &jmicron_chipset, NULL);
-}
-
-/* All JMB PATA controllers have and will continue to have the same
- * interface. Matching vendor and device class is enough for all
- * current and future controllers if the controller is programmed
- * properly.
- *
- * If libata is configured, jmicron PCI quirk programs the controller
- * into the correct mode. If libata isn't configured, match known
- * device IDs too to maintain backward compatibility.
- */
-static struct pci_device_id jmicron_pci_tbl[] = {
-#if !defined(CONFIG_ATA) && !defined(CONFIG_ATA_MODULE)
- { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361) },
- { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363) },
- { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365) },
- { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366) },
- { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368) },
-#endif
- { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 },
- { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, jmicron_pci_tbl);
-
-static struct pci_driver jmicron_pci_driver = {
- .name = "JMicron IDE",
- .id_table = jmicron_pci_tbl,
- .probe = jmicron_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init jmicron_ide_init(void)
-{
- return ide_pci_register_driver(&jmicron_pci_driver);
-}
-
-static void __exit jmicron_ide_exit(void)
-{
- pci_unregister_driver(&jmicron_pci_driver);
-}
-
-module_init(jmicron_ide_init);
-module_exit(jmicron_ide_exit);
-
-MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("PCI driver module for the JMicron in legacy modes");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/macide.c b/drivers/ide/macide.c
deleted file mode 100644
index 8d2bf73bc548..000000000000
--- a/drivers/ide/macide.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Macintosh IDE Driver
- *
- * Copyright (C) 1998 by Michael Schmitz
- *
- * This driver was written based on information obtained from the MacOS IDE
- * driver binary by Mikael Forselius
- *
- * 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.
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include <asm/macintosh.h>
-
-#define DRV_NAME "mac_ide"
-
-#define IDE_BASE 0x50F1A000 /* Base address of IDE controller */
-
-/*
- * Generic IDE registers as offsets from the base
- * These match MkLinux so they should be correct.
- */
-
-#define IDE_CONTROL 0x38 /* control/altstatus */
-
-/*
- * Mac-specific registers
- */
-
-/*
- * this register is odd; it doesn't seem to do much and it's
- * not word-aligned like virtually every other hardware register
- * on the Mac...
- */
-
-#define IDE_IFR 0x101 /* (0x101) IDE interrupt flags on Quadra:
- *
- * Bit 0+1: some interrupt flags
- * Bit 2+3: some interrupt enable
- * Bit 4: ??
- * Bit 5: IDE interrupt flag (any hwif)
- * Bit 6: maybe IDE interrupt enable (any hwif) ??
- * Bit 7: Any interrupt condition
- */
-
-volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR);
-
-int macide_test_irq(ide_hwif_t *hwif)
-{
- if (*ide_ifr & 0x20)
- return 1;
- return 0;
-}
-
-static void macide_clear_irq(ide_drive_t *drive)
-{
- *ide_ifr &= ~0x20;
-}
-
-static void __init macide_setup_ports(struct ide_hw *hw, unsigned long base,
- int irq)
-{
- int i;
-
- memset(hw, 0, sizeof(*hw));
-
- for (i = 0; i < 8; i++)
- hw->io_ports_array[i] = base + i * 4;
-
- hw->io_ports.ctl_addr = base + IDE_CONTROL;
-
- hw->irq = irq;
-}
-
-static const struct ide_port_ops macide_port_ops = {
- .clear_irq = macide_clear_irq,
- .test_irq = macide_test_irq,
-};
-
-static const struct ide_port_info macide_port_info = {
- .port_ops = &macide_port_ops,
- .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
- .irq_flags = IRQF_SHARED,
- .chipset = ide_generic,
-};
-
-static const char *mac_ide_name[] =
- { "Quadra", "Powerbook", "Powerbook Baboon" };
-
-/*
- * Probe for a Macintosh IDE interface
- */
-
-static int mac_ide_probe(struct platform_device *pdev)
-{
- struct resource *mem, *irq;
- struct ide_hw hw, *hws[] = { &hw };
- struct ide_port_info d = macide_port_info;
- struct ide_host *host;
- int rc;
-
- if (!MACH_IS_MAC)
- return -ENODEV;
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem)
- return -ENODEV;
-
- irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!irq)
- return -ENODEV;
-
- if (!devm_request_mem_region(&pdev->dev, mem->start,
- resource_size(mem), DRV_NAME)) {
- dev_err(&pdev->dev, "resources busy\n");
- return -EBUSY;
- }
-
- printk(KERN_INFO "ide: Macintosh %s IDE controller\n",
- mac_ide_name[macintosh_config->ide_type - 1]);
-
- macide_setup_ports(&hw, mem->start, irq->start);
-
- rc = ide_host_add(&d, hws, 1, &host);
- if (rc)
- return rc;
-
- platform_set_drvdata(pdev, host);
- return 0;
-}
-
-static int mac_ide_remove(struct platform_device *pdev)
-{
- struct ide_host *host = platform_get_drvdata(pdev);
-
- ide_host_remove(host);
- return 0;
-}
-
-static struct platform_driver mac_ide_driver = {
- .driver = {
- .name = DRV_NAME,
- },
- .probe = mac_ide_probe,
- .remove = mac_ide_remove,
-};
-
-module_platform_driver(mac_ide_driver);
-
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c
deleted file mode 100644
index 11a672aba6ee..000000000000
--- a/drivers/ide/ns87415.c
+++ /dev/null
@@ -1,350 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1997-1998 Mark Lord <mlord@pobox.com>
- * Copyright (C) 1998 Eddie C. Dost <ecd@skynet.be>
- * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2004 Grant Grundler <grundler at parisc-linux.org>
- *
- * Inspired by an earlier effort from David S. Miller <davem@redhat.com>
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "ns87415"
-
-#ifdef CONFIG_SUPERIO
-/* SUPERIO 87560 is a PoS chip that NatSem denies exists.
- * Unfortunately, it's built-in on all Astro-based PA-RISC workstations
- * which use the integrated NS87514 cell for CD-ROM support.
- * i.e we have to support for CD-ROM installs.
- * See drivers/parisc/superio.c for more gory details.
- */
-#include <asm/superio.h>
-
-#define SUPERIO_IDE_MAX_RETRIES 25
-
-/* Because of a defect in Super I/O, all reads of the PCI DMA status
- * registers, IDE status register and the IDE select register need to be
- * retried
- */
-static u8 superio_ide_inb (unsigned long port)
-{
- u8 tmp;
- int retries = SUPERIO_IDE_MAX_RETRIES;
-
- /* printk(" [ reading port 0x%x with retry ] ", port); */
-
- do {
- tmp = inb(port);
- if (tmp == 0)
- udelay(50);
- } while (tmp == 0 && retries-- > 0);
-
- return tmp;
-}
-
-static u8 superio_read_status(ide_hwif_t *hwif)
-{
- return superio_ide_inb(hwif->io_ports.status_addr);
-}
-
-static u8 superio_dma_sff_read_status(ide_hwif_t *hwif)
-{
- return superio_ide_inb(hwif->dma_base + ATA_DMA_STATUS);
-}
-
-static void superio_tf_read(ide_drive_t *drive, struct ide_taskfile *tf,
- u8 valid)
-{
- struct ide_io_ports *io_ports = &drive->hwif->io_ports;
-
- if (valid & IDE_VALID_ERROR)
- tf->error = inb(io_ports->feature_addr);
- if (valid & IDE_VALID_NSECT)
- tf->nsect = inb(io_ports->nsect_addr);
- if (valid & IDE_VALID_LBAL)
- tf->lbal = inb(io_ports->lbal_addr);
- if (valid & IDE_VALID_LBAM)
- tf->lbam = inb(io_ports->lbam_addr);
- if (valid & IDE_VALID_LBAH)
- tf->lbah = inb(io_ports->lbah_addr);
- if (valid & IDE_VALID_DEVICE)
- tf->device = superio_ide_inb(io_ports->device_addr);
-}
-
-static void ns87415_dev_select(ide_drive_t *drive);
-
-static const struct ide_tp_ops superio_tp_ops = {
- .exec_command = ide_exec_command,
- .read_status = superio_read_status,
- .read_altstatus = ide_read_altstatus,
- .write_devctl = ide_write_devctl,
-
- .dev_select = ns87415_dev_select,
- .tf_load = ide_tf_load,
- .tf_read = superio_tf_read,
-
- .input_data = ide_input_data,
- .output_data = ide_output_data,
-};
-
-static void superio_init_iops(struct hwif_s *hwif)
-{
- struct pci_dev *pdev = to_pci_dev(hwif->dev);
- u32 dma_stat;
- u8 port = hwif->channel, tmp;
-
- dma_stat = (pci_resource_start(pdev, 4) & ~3) + (!port ? 2 : 0xa);
-
- /* Clear error/interrupt, enable dma */
- tmp = superio_ide_inb(dma_stat);
- outb(tmp | 0x66, dma_stat);
-}
-#else
-#define superio_dma_sff_read_status ide_dma_sff_read_status
-#endif
-
-static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
-
-/*
- * This routine either enables/disables (according to IDE_DFLAG_PRESENT)
- * the IRQ associated with the port,
- * and selects either PIO or DMA handshaking for the next I/O operation.
- */
-static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
- unsigned long flags;
-
- local_irq_save(flags);
- new = *old;
-
- /* Adjust IRQ enable bit */
- bit = 1 << (8 + hwif->channel);
-
- if (drive->dev_flags & IDE_DFLAG_PRESENT)
- new &= ~bit;
- else
- new |= bit;
-
- /* Select PIO or DMA, DMA may only be selected for one drive/channel. */
- bit = 1 << (20 + (drive->dn & 1) + (hwif->channel << 1));
- other = 1 << (20 + (1 - (drive->dn & 1)) + (hwif->channel << 1));
- new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
-
- if (new != *old) {
- unsigned char stat;
-
- /*
- * Don't change DMA engine settings while Write Buffers
- * are busy.
- */
- (void) pci_read_config_byte(dev, 0x43, &stat);
- while (stat & 0x03) {
- udelay(1);
- (void) pci_read_config_byte(dev, 0x43, &stat);
- }
-
- *old = new;
- (void) pci_write_config_dword(dev, 0x40, new);
-
- /*
- * And let things settle...
- */
- udelay(10);
- }
-
- local_irq_restore(flags);
-}
-
-static void ns87415_dev_select(ide_drive_t *drive)
-{
- ns87415_prepare_drive(drive,
- !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
-
- outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
-}
-
-static void ns87415_dma_start(ide_drive_t *drive)
-{
- ns87415_prepare_drive(drive, 1);
- ide_dma_start(drive);
-}
-
-static int ns87415_dma_end(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 dma_stat = 0, dma_cmd = 0;
-
- dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
- /* get DMA command mode */
- dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
- /* stop DMA */
- outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
- /* from ERRATA: clear the INTR & ERROR bits */
- dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
- outb(dma_cmd | 6, hwif->dma_base + ATA_DMA_CMD);
-
- ns87415_prepare_drive(drive, 0);
-
- /* verify good DMA status */
- return (dma_stat & 7) != 4;
-}
-
-static void init_hwif_ns87415 (ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned int ctrl, using_inta;
- u8 progif;
-#ifdef __sparc_v9__
- int timeout;
- u8 stat;
-#endif
-
- /*
- * We cannot probe for IRQ: both ports share common IRQ on INTA.
- * Also, leave IRQ masked during drive probing, to prevent infinite
- * interrupts from a potentially floating INTA..
- *
- * IRQs get unmasked in dev_select() when drive is first used.
- */
- (void) pci_read_config_dword(dev, 0x40, &ctrl);
- (void) pci_read_config_byte(dev, 0x09, &progif);
- /* is irq in "native" mode? */
- using_inta = progif & (1 << (hwif->channel << 1));
- if (!using_inta)
- using_inta = ctrl & (1 << (4 + hwif->channel));
- if (hwif->mate) {
- hwif->select_data = hwif->mate->select_data;
- } else {
- hwif->select_data = (unsigned long)
- &ns87415_control[ns87415_count++];
- ctrl |= (1 << 8) | (1 << 9); /* mask both IRQs */
- if (using_inta)
- ctrl &= ~(1 << 6); /* unmask INTA */
- *((unsigned int *)hwif->select_data) = ctrl;
- (void) pci_write_config_dword(dev, 0x40, ctrl);
-
- /*
- * Set prefetch size to 512 bytes for both ports,
- * but don't turn on/off prefetching here.
- */
- pci_write_config_byte(dev, 0x55, 0xee);
-
-#ifdef __sparc_v9__
- /*
- * XXX: Reset the device, if we don't it will not respond to
- * dev_select() properly during first ide_probe_port().
- */
- timeout = 10000;
- outb(12, hwif->io_ports.ctl_addr);
- udelay(10);
- outb(8, hwif->io_ports.ctl_addr);
- do {
- udelay(50);
- stat = hwif->tp_ops->read_status(hwif);
- if (stat == 0xff)
- break;
- } while ((stat & ATA_BUSY) && --timeout);
-#endif
- }
-
- if (!using_inta)
- hwif->irq = pci_get_legacy_ide_irq(dev, hwif->channel);
-
- if (!hwif->dma_base)
- return;
-
- outb(0x60, hwif->dma_base + ATA_DMA_STATUS);
-}
-
-static const struct ide_tp_ops ns87415_tp_ops = {
- .exec_command = ide_exec_command,
- .read_status = ide_read_status,
- .read_altstatus = ide_read_altstatus,
- .write_devctl = ide_write_devctl,
-
- .dev_select = ns87415_dev_select,
- .tf_load = ide_tf_load,
- .tf_read = ide_tf_read,
-
- .input_data = ide_input_data,
- .output_data = ide_output_data,
-};
-
-static const struct ide_dma_ops ns87415_dma_ops = {
- .dma_host_set = ide_dma_host_set,
- .dma_setup = ide_dma_setup,
- .dma_start = ns87415_dma_start,
- .dma_end = ns87415_dma_end,
- .dma_test_irq = ide_dma_test_irq,
- .dma_lost_irq = ide_dma_lost_irq,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_sff_read_status = superio_dma_sff_read_status,
-};
-
-static const struct ide_port_info ns87415_chipset = {
- .name = DRV_NAME,
- .init_hwif = init_hwif_ns87415,
- .tp_ops = &ns87415_tp_ops,
- .dma_ops = &ns87415_dma_ops,
- .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
- IDE_HFLAG_NO_ATAPI_DMA,
-};
-
-static int ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct ide_port_info d = ns87415_chipset;
-
-#ifdef CONFIG_SUPERIO
- if (PCI_SLOT(dev->devfn) == 0xE) {
- /* Built-in - assume it's under superio. */
- d.init_iops = superio_init_iops;
- d.tp_ops = &superio_tp_ops;
- }
-#endif
- return ide_pci_init_one(dev, &d, NULL);
-}
-
-static const struct pci_device_id ns87415_pci_tbl[] = {
- { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), 0 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl);
-
-static struct pci_driver ns87415_pci_driver = {
- .name = "NS87415_IDE",
- .id_table = ns87415_pci_tbl,
- .probe = ns87415_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init ns87415_ide_init(void)
-{
- return ide_pci_register_driver(&ns87415_pci_driver);
-}
-
-static void __exit ns87415_ide_exit(void)
-{
- pci_unregister_driver(&ns87415_pci_driver);
-}
-
-module_init(ns87415_ide_init);
-module_exit(ns87415_ide_exit);
-
-MODULE_AUTHOR("Mark Lord, Eddie Dost, Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for NS87415 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c
deleted file mode 100644
index c374f82333c6..000000000000
--- a/drivers/ide/opti621.c
+++ /dev/null
@@ -1,179 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1996-1998 Linus Torvalds & authors (see below)
- */
-
-/*
- * Authors:
- * Jaromir Koutek <miri@punknet.cz>,
- * Jan Harkes <jaharkes@cwi.nl>,
- * Mark Lord <mlord@pobox.com>
- * Some parts of code are from ali14xx.c and from rz1000.c.
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "opti621"
-
-#define READ_REG 0 /* index of Read cycle timing register */
-#define WRITE_REG 1 /* index of Write cycle timing register */
-#define CNTRL_REG 3 /* index of Control register */
-#define STRAP_REG 5 /* index of Strap register */
-#define MISC_REG 6 /* index of Miscellaneous register */
-
-static int reg_base;
-
-static DEFINE_SPINLOCK(opti621_lock);
-
-/* Write value to register reg, base of register
- * is at reg_base (0x1f0 primary, 0x170 secondary,
- * if not changed by PCI configuration).
- * This is from setupvic.exe program.
- */
-static void write_reg(u8 value, int reg)
-{
- inw(reg_base + 1);
- inw(reg_base + 1);
- outb(3, reg_base + 2);
- outb(value, reg_base + reg);
- outb(0x83, reg_base + 2);
-}
-
-/* Read value from register reg, base of register
- * is at reg_base (0x1f0 primary, 0x170 secondary,
- * if not changed by PCI configuration).
- * This is from setupvic.exe program.
- */
-static u8 read_reg(int reg)
-{
- u8 ret = 0;
-
- inw(reg_base + 1);
- inw(reg_base + 1);
- outb(3, reg_base + 2);
- ret = inb(reg_base + reg);
- outb(0x83, reg_base + 2);
-
- return ret;
-}
-
-static void opti621_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- ide_drive_t *pair = ide_get_pair_dev(drive);
- unsigned long flags;
- unsigned long mode = drive->pio_mode, pair_mode;
- const u8 pio = mode - XFER_PIO_0;
- u8 tim, misc, addr_pio = pio, clk;
-
- /* DRDY is default 2 (by OPTi Databook) */
- static const u8 addr_timings[2][5] = {
- { 0x20, 0x10, 0x00, 0x00, 0x00 }, /* 33 MHz */
- { 0x10, 0x10, 0x00, 0x00, 0x00 }, /* 25 MHz */
- };
- static const u8 data_rec_timings[2][5] = {
- { 0x5b, 0x45, 0x32, 0x21, 0x20 }, /* 33 MHz */
- { 0x48, 0x34, 0x21, 0x10, 0x10 } /* 25 MHz */
- };
-
- ide_set_drivedata(drive, (void *)mode);
-
- if (pair) {
- pair_mode = (unsigned long)ide_get_drivedata(pair);
- if (pair_mode && pair_mode < mode)
- addr_pio = pair_mode - XFER_PIO_0;
- }
-
- spin_lock_irqsave(&opti621_lock, flags);
-
- reg_base = hwif->io_ports.data_addr;
-
- /* allow Register-B */
- outb(0xc0, reg_base + CNTRL_REG);
- /* hmm, setupvic.exe does this ;-) */
- outb(0xff, reg_base + 5);
- /* if reads 0xff, adapter not exist? */
- (void)inb(reg_base + CNTRL_REG);
- /* if reads 0xc0, no interface exist? */
- read_reg(CNTRL_REG);
-
- /* check CLK speed */
- clk = read_reg(STRAP_REG) & 1;
-
- printk(KERN_INFO "%s: CLK = %d MHz\n", hwif->name, clk ? 25 : 33);
-
- tim = data_rec_timings[clk][pio];
- misc = addr_timings[clk][addr_pio];
-
- /* select Index-0/1 for Register-A/B */
- write_reg(drive->dn & 1, MISC_REG);
- /* set read cycle timings */
- write_reg(tim, READ_REG);
- /* set write cycle timings */
- write_reg(tim, WRITE_REG);
-
- /* use Register-A for drive 0 */
- /* use Register-B for drive 1 */
- write_reg(0x85, CNTRL_REG);
-
- /* set address setup, DRDY timings, */
- /* and read prefetch for both drives */
- write_reg(misc, MISC_REG);
-
- spin_unlock_irqrestore(&opti621_lock, flags);
-}
-
-static const struct ide_port_ops opti621_port_ops = {
- .set_pio_mode = opti621_set_pio_mode,
-};
-
-static const struct ide_port_info opti621_chipset = {
- .name = DRV_NAME,
- .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} },
- .port_ops = &opti621_port_ops,
- .host_flags = IDE_HFLAG_NO_DMA,
- .pio_mask = ATA_PIO4,
-};
-
-static int opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- return ide_pci_init_one(dev, &opti621_chipset, NULL);
-}
-
-static const struct pci_device_id opti621_pci_tbl[] = {
- { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 },
- { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 0 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, opti621_pci_tbl);
-
-static struct pci_driver opti621_pci_driver = {
- .name = "Opti621_IDE",
- .id_table = opti621_pci_tbl,
- .probe = opti621_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init opti621_ide_init(void)
-{
- return ide_pci_register_driver(&opti621_pci_driver);
-}
-
-static void __exit opti621_ide_exit(void)
-{
- pci_unregister_driver(&opti621_pci_driver);
-}
-
-module_init(opti621_ide_init);
-module_exit(opti621_ide_exit);
-
-MODULE_AUTHOR("Jaromir Koutek, Jan Harkes, Mark Lord");
-MODULE_DESCRIPTION("PCI driver module for Opti621 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/palm_bk3710.c b/drivers/ide/palm_bk3710.c
deleted file mode 100644
index d1fe4c13e35c..000000000000
--- a/drivers/ide/palm_bk3710.c
+++ /dev/null
@@ -1,387 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Palmchip bk3710 IDE controller
- *
- * Copyright (C) 2006 Texas Instruments.
- * Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com>
- *
- * ----------------------------------------------------------------------------
- *
- * ----------------------------------------------------------------------------
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-
-/* Offset of the primary interface registers */
-#define IDE_PALM_ATA_PRI_REG_OFFSET 0x1F0
-
-/* Primary Control Offset */
-#define IDE_PALM_ATA_PRI_CTL_OFFSET 0x3F6
-
-#define BK3710_BMICP 0x00
-#define BK3710_BMISP 0x02
-#define BK3710_BMIDTP 0x04
-#define BK3710_IDETIMP 0x40
-#define BK3710_IDESTATUS 0x47
-#define BK3710_UDMACTL 0x48
-#define BK3710_MISCCTL 0x50
-#define BK3710_REGSTB 0x54
-#define BK3710_REGRCVR 0x58
-#define BK3710_DATSTB 0x5C
-#define BK3710_DATRCVR 0x60
-#define BK3710_DMASTB 0x64
-#define BK3710_DMARCVR 0x68
-#define BK3710_UDMASTB 0x6C
-#define BK3710_UDMATRP 0x70
-#define BK3710_UDMAENV 0x74
-#define BK3710_IORDYTMP 0x78
-
-static unsigned ideclk_period; /* in nanoseconds */
-
-struct palm_bk3710_udmatiming {
- unsigned int rptime; /* tRP -- Ready to pause time (nsec) */
- unsigned int cycletime; /* tCYCTYP2/2 -- avg Cycle Time (nsec) */
- /* tENV is always a minimum of 20 nsec */
-};
-
-static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings[6] = {
- { 160, 240 / 2 }, /* UDMA Mode 0 */
- { 125, 160 / 2 }, /* UDMA Mode 1 */
- { 100, 120 / 2 }, /* UDMA Mode 2 */
- { 100, 90 / 2 }, /* UDMA Mode 3 */
- { 100, 60 / 2 }, /* UDMA Mode 4 */
- { 85, 40 / 2 }, /* UDMA Mode 5 */
-};
-
-static void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev,
- unsigned int mode)
-{
- u8 tenv, trp, t0;
- u32 val32;
- u16 val16;
-
- /* DMA Data Setup */
- t0 = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].cycletime,
- ideclk_period) - 1;
- tenv = DIV_ROUND_UP(20, ideclk_period) - 1;
- trp = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].rptime,
- ideclk_period) - 1;
-
- /* udmastb Ultra DMA Access Strobe Width */
- val32 = readl(base + BK3710_UDMASTB) & (0xFF << (dev ? 0 : 8));
- val32 |= (t0 << (dev ? 8 : 0));
- writel(val32, base + BK3710_UDMASTB);
-
- /* udmatrp Ultra DMA Ready to Pause Time */
- val32 = readl(base + BK3710_UDMATRP) & (0xFF << (dev ? 0 : 8));
- val32 |= (trp << (dev ? 8 : 0));
- writel(val32, base + BK3710_UDMATRP);
-
- /* udmaenv Ultra DMA envelop Time */
- val32 = readl(base + BK3710_UDMAENV) & (0xFF << (dev ? 0 : 8));
- val32 |= (tenv << (dev ? 8 : 0));
- writel(val32, base + BK3710_UDMAENV);
-
- /* Enable UDMA for Device */
- val16 = readw(base + BK3710_UDMACTL) | (1 << dev);
- writew(val16, base + BK3710_UDMACTL);
-}
-
-static void palm_bk3710_setdmamode(void __iomem *base, unsigned int dev,
- unsigned short min_cycle,
- unsigned int mode)
-{
- u8 td, tkw, t0;
- u32 val32;
- u16 val16;
- struct ide_timing *t;
- int cycletime;
-
- t = ide_timing_find_mode(mode);
- cycletime = max_t(int, t->cycle, min_cycle);
-
- /* DMA Data Setup */
- t0 = DIV_ROUND_UP(cycletime, ideclk_period);
- td = DIV_ROUND_UP(t->active, ideclk_period);
- tkw = t0 - td - 1;
- td -= 1;
-
- val32 = readl(base + BK3710_DMASTB) & (0xFF << (dev ? 0 : 8));
- val32 |= (td << (dev ? 8 : 0));
- writel(val32, base + BK3710_DMASTB);
-
- val32 = readl(base + BK3710_DMARCVR) & (0xFF << (dev ? 0 : 8));
- val32 |= (tkw << (dev ? 8 : 0));
- writel(val32, base + BK3710_DMARCVR);
-
- /* Disable UDMA for Device */
- val16 = readw(base + BK3710_UDMACTL) & ~(1 << dev);
- writew(val16, base + BK3710_UDMACTL);
-}
-
-static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
- unsigned int dev, unsigned int cycletime,
- unsigned int mode)
-{
- u8 t2, t2i, t0;
- u32 val32;
- struct ide_timing *t;
-
- t = ide_timing_find_mode(XFER_PIO_0 + mode);
-
- /* PIO Data Setup */
- t0 = DIV_ROUND_UP(cycletime, ideclk_period);
- t2 = DIV_ROUND_UP(t->active, ideclk_period);
-
- t2i = t0 - t2 - 1;
- t2 -= 1;
-
- val32 = readl(base + BK3710_DATSTB) & (0xFF << (dev ? 0 : 8));
- val32 |= (t2 << (dev ? 8 : 0));
- writel(val32, base + BK3710_DATSTB);
-
- val32 = readl(base + BK3710_DATRCVR) & (0xFF << (dev ? 0 : 8));
- val32 |= (t2i << (dev ? 8 : 0));
- writel(val32, base + BK3710_DATRCVR);
-
- if (mate) {
- u8 mode2 = mate->pio_mode - XFER_PIO_0;
-
- if (mode2 < mode)
- mode = mode2;
- }
-
- /* TASKFILE Setup */
- t0 = DIV_ROUND_UP(t->cyc8b, ideclk_period);
- t2 = DIV_ROUND_UP(t->act8b, ideclk_period);
-
- t2i = t0 - t2 - 1;
- t2 -= 1;
-
- val32 = readl(base + BK3710_REGSTB) & (0xFF << (dev ? 0 : 8));
- val32 |= (t2 << (dev ? 8 : 0));
- writel(val32, base + BK3710_REGSTB);
-
- val32 = readl(base + BK3710_REGRCVR) & (0xFF << (dev ? 0 : 8));
- val32 |= (t2i << (dev ? 8 : 0));
- writel(val32, base + BK3710_REGRCVR);
-}
-
-static void palm_bk3710_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- int is_slave = drive->dn & 1;
- void __iomem *base = (void __iomem *)hwif->dma_base;
- const u8 xferspeed = drive->dma_mode;
-
- if (xferspeed >= XFER_UDMA_0) {
- palm_bk3710_setudmamode(base, is_slave,
- xferspeed - XFER_UDMA_0);
- } else {
- palm_bk3710_setdmamode(base, is_slave,
- drive->id[ATA_ID_EIDE_DMA_MIN],
- xferspeed);
- }
-}
-
-static void palm_bk3710_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- unsigned int cycle_time;
- int is_slave = drive->dn & 1;
- ide_drive_t *mate;
- void __iomem *base = (void __iomem *)hwif->dma_base;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
-
- /*
- * Obtain the drive PIO data for tuning the Palm Chip registers
- */
- cycle_time = ide_pio_cycle_time(drive, pio);
- mate = ide_get_pair_dev(drive);
- palm_bk3710_setpiomode(base, mate, is_slave, cycle_time, pio);
-}
-
-static void palm_bk3710_chipinit(void __iomem *base)
-{
- /*
- * REVISIT: the ATA reset signal needs to be managed through a
- * GPIO, which means it should come from platform_data. Until
- * we get and use such information, we have to trust that things
- * have been reset before we get here.
- */
-
- /*
- * Program the IDETIMP Register Value based on the following assumptions
- *
- * (ATA_IDETIMP_IDEEN , ENABLE ) |
- * (ATA_IDETIMP_PREPOST1 , DISABLE) |
- * (ATA_IDETIMP_PREPOST0 , DISABLE) |
- *
- * DM6446 silicon rev 2.1 and earlier have no observed net benefit
- * from enabling prefetch/postwrite.
- */
- writew(BIT(15), base + BK3710_IDETIMP);
-
- /*
- * UDMACTL Ultra-ATA DMA Control
- * (ATA_UDMACTL_UDMAP1 , 0 ) |
- * (ATA_UDMACTL_UDMAP0 , 0 )
- *
- */
- writew(0, base + BK3710_UDMACTL);
-
- /*
- * MISCCTL Miscellaneous Conrol Register
- * (ATA_MISCCTL_HWNHLD1P , 1 cycle)
- * (ATA_MISCCTL_HWNHLD0P , 1 cycle)
- * (ATA_MISCCTL_TIMORIDE , 1)
- */
- writel(0x001, base + BK3710_MISCCTL);
-
- /*
- * IORDYTMP IORDY Timer for Primary Register
- * (ATA_IORDYTMP_IORDYTMP , 0xffff )
- */
- writel(0xFFFF, base + BK3710_IORDYTMP);
-
- /*
- * Configure BMISP Register
- * (ATA_BMISP_DMAEN1 , DISABLE ) |
- * (ATA_BMISP_DMAEN0 , DISABLE ) |
- * (ATA_BMISP_IORDYINT , CLEAR) |
- * (ATA_BMISP_INTRSTAT , CLEAR) |
- * (ATA_BMISP_DMAERROR , CLEAR)
- */
- writew(0, base + BK3710_BMISP);
-
- palm_bk3710_setpiomode(base, NULL, 0, 600, 0);
- palm_bk3710_setpiomode(base, NULL, 1, 600, 0);
-}
-
-static u8 palm_bk3710_cable_detect(ide_hwif_t *hwif)
-{
- return ATA_CBL_PATA80;
-}
-
-static int palm_bk3710_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
- printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name);
-
- if (ide_allocate_dma_engine(hwif))
- return -1;
-
- hwif->dma_base = hwif->io_ports.data_addr - IDE_PALM_ATA_PRI_REG_OFFSET;
-
- return 0;
-}
-
-static const struct ide_port_ops palm_bk3710_ports_ops = {
- .set_pio_mode = palm_bk3710_set_pio_mode,
- .set_dma_mode = palm_bk3710_set_dma_mode,
- .cable_detect = palm_bk3710_cable_detect,
-};
-
-static struct ide_port_info palm_bk3710_port_info __initdata = {
- .init_dma = palm_bk3710_init_dma,
- .port_ops = &palm_bk3710_ports_ops,
- .dma_ops = &sff_dma_ops,
- .host_flags = IDE_HFLAG_MMIO,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .chipset = ide_palm3710,
-};
-
-static int __init palm_bk3710_probe(struct platform_device *pdev)
-{
- struct clk *clk;
- struct resource *mem, *irq;
- void __iomem *base;
- unsigned long rate, mem_size;
- int i, rc;
- struct ide_hw hw, *hws[] = { &hw };
-
- clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(clk))
- return -ENODEV;
-
- clk_enable(clk);
- rate = clk_get_rate(clk);
- if (!rate)
- return -EINVAL;
-
- /* NOTE: round *down* to meet minimum timings; we count in clocks */
- ideclk_period = 1000000000UL / rate;
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (mem == NULL) {
- printk(KERN_ERR "failed to get memory region resource\n");
- return -ENODEV;
- }
-
- irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (irq == NULL) {
- printk(KERN_ERR "failed to get IRQ resource\n");
- return -ENODEV;
- }
-
- mem_size = resource_size(mem);
- if (request_mem_region(mem->start, mem_size, "palm_bk3710") == NULL) {
- printk(KERN_ERR "failed to request memory region\n");
- return -EBUSY;
- }
-
- base = ioremap(mem->start, mem_size);
- if (!base) {
- printk(KERN_ERR "failed to map IO memory\n");
- release_mem_region(mem->start, mem_size);
- return -ENOMEM;
- }
-
- /* Configure the Palm Chip controller */
- palm_bk3710_chipinit(base);
-
- memset(&hw, 0, sizeof(hw));
- for (i = 0; i < IDE_NR_PORTS - 2; i++)
- hw.io_ports_array[i] = (unsigned long)
- (base + IDE_PALM_ATA_PRI_REG_OFFSET + i);
- hw.io_ports.ctl_addr = (unsigned long)
- (base + IDE_PALM_ATA_PRI_CTL_OFFSET);
- hw.irq = irq->start;
- hw.dev = &pdev->dev;
-
- palm_bk3710_port_info.udma_mask = rate < 100000000 ? ATA_UDMA4 :
- ATA_UDMA5;
-
- /* Register the IDE interface with Linux */
- rc = ide_host_add(&palm_bk3710_port_info, hws, 1, NULL);
- if (rc)
- goto out;
-
- return 0;
-out:
- printk(KERN_WARNING "Palm Chip BK3710 IDE Register Fail\n");
- return rc;
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:palm_bk3710");
-
-static struct platform_driver platform_bk_driver = {
- .driver = {
- .name = "palm_bk3710",
- },
-};
-
-static int __init palm_bk3710_init(void)
-{
- return platform_driver_probe(&platform_bk_driver, palm_bk3710_probe);
-}
-
-module_init(palm_bk3710_init);
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pdc202xx_new.c b/drivers/ide/pdc202xx_new.c
deleted file mode 100644
index 4fcafb9121e0..000000000000
--- a/drivers/ide/pdc202xx_new.c
+++ /dev/null
@@ -1,557 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Promise TX2/TX4/TX2000/133 IDE driver
- *
- * Split from:
- * linux/drivers/ide/pdc202xx.c Version 0.35 Mar. 30, 2002
- * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2005-2007 MontaVista Software, Inc.
- * Portions Copyright (C) 1999 Promise Technology, Inc.
- * Author: Frank Tiernan (frankt@promise.com)
- * Released under terms of General Public License
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <linux/ktime.h>
-
-#include <asm/io.h>
-
-#ifdef CONFIG_PPC_PMAC
-#include <asm/prom.h>
-#endif
-
-#define DRV_NAME "pdc202xx_new"
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(fmt, args...) printk("%s: " fmt, __func__, ## args)
-#else
-#define DBG(fmt, args...)
-#endif
-
-static u8 max_dma_rate(struct pci_dev *pdev)
-{
- u8 mode;
-
- switch(pdev->device) {
- case PCI_DEVICE_ID_PROMISE_20277:
- case PCI_DEVICE_ID_PROMISE_20276:
- case PCI_DEVICE_ID_PROMISE_20275:
- case PCI_DEVICE_ID_PROMISE_20271:
- case PCI_DEVICE_ID_PROMISE_20269:
- mode = 4;
- break;
- case PCI_DEVICE_ID_PROMISE_20270:
- case PCI_DEVICE_ID_PROMISE_20268:
- mode = 3;
- break;
- default:
- return 0;
- }
-
- return mode;
-}
-
-/**
- * get_indexed_reg - Get indexed register
- * @hwif: for the port address
- * @index: index of the indexed register
- */
-static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index)
-{
- u8 value;
-
- outb(index, hwif->dma_base + 1);
- value = inb(hwif->dma_base + 3);
-
- DBG("index[%02X] value[%02X]\n", index, value);
- return value;
-}
-
-/**
- * set_indexed_reg - Set indexed register
- * @hwif: for the port address
- * @index: index of the indexed register
- */
-static void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value)
-{
- outb(index, hwif->dma_base + 1);
- outb(value, hwif->dma_base + 3);
- DBG("index[%02X] value[%02X]\n", index, value);
-}
-
-/*
- * ATA Timing Tables based on 133 MHz PLL output clock.
- *
- * If the PLL outputs 100 MHz clock, the ASIC hardware will set
- * the timing registers automatically when "set features" command is
- * issued to the device. However, if the PLL output clock is 133 MHz,
- * the following tables must be used.
- */
-static struct pio_timing {
- u8 reg0c, reg0d, reg13;
-} pio_timings [] = {
- { 0xfb, 0x2b, 0xac }, /* PIO mode 0, IORDY off, Prefetch off */
- { 0x46, 0x29, 0xa4 }, /* PIO mode 1, IORDY off, Prefetch off */
- { 0x23, 0x26, 0x64 }, /* PIO mode 2, IORDY off, Prefetch off */
- { 0x27, 0x0d, 0x35 }, /* PIO mode 3, IORDY on, Prefetch off */
- { 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */
-};
-
-static struct mwdma_timing {
- u8 reg0e, reg0f;
-} mwdma_timings [] = {
- { 0xdf, 0x5f }, /* MWDMA mode 0 */
- { 0x6b, 0x27 }, /* MWDMA mode 1 */
- { 0x69, 0x25 }, /* MWDMA mode 2 */
-};
-
-static struct udma_timing {
- u8 reg10, reg11, reg12;
-} udma_timings [] = {
- { 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */
- { 0x3a, 0x0a, 0xd0 }, /* UDMA mode 1 */
- { 0x2a, 0x07, 0xcd }, /* UDMA mode 2 */
- { 0x1a, 0x05, 0xcd }, /* UDMA mode 3 */
- { 0x1a, 0x03, 0xcd }, /* UDMA mode 4 */
- { 0x1a, 0x02, 0xcb }, /* UDMA mode 5 */
- { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */
-};
-
-static void pdcnew_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
- const u8 speed = drive->dma_mode;
-
- /*
- * IDE core issues SETFEATURES_XFER to the drive first (thanks to
- * IDE_HFLAG_POST_SET_MODE in ->host_flags). PDC202xx hardware will
- * automatically set the timing registers based on 100 MHz PLL output.
- *
- * As we set up the PLL to output 133 MHz for UltraDMA/133 capable
- * chips, we must override the default register settings...
- */
- if (max_dma_rate(dev) == 4) {
- u8 mode = speed & 0x07;
-
- if (speed >= XFER_UDMA_0) {
- set_indexed_reg(hwif, 0x10 + adj,
- udma_timings[mode].reg10);
- set_indexed_reg(hwif, 0x11 + adj,
- udma_timings[mode].reg11);
- set_indexed_reg(hwif, 0x12 + adj,
- udma_timings[mode].reg12);
- } else {
- set_indexed_reg(hwif, 0x0e + adj,
- mwdma_timings[mode].reg0e);
- set_indexed_reg(hwif, 0x0f + adj,
- mwdma_timings[mode].reg0f);
- }
- } else if (speed == XFER_UDMA_2) {
- /* Set tHOLD bit to 0 if using UDMA mode 2 */
- u8 tmp = get_indexed_reg(hwif, 0x10 + adj);
-
- set_indexed_reg(hwif, 0x10 + adj, tmp & 0x7f);
- }
-}
-
-static void pdcnew_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
-
- if (max_dma_rate(dev) == 4) {
- set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c);
- set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d);
- set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13);
- }
-}
-
-static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
-{
- if (get_indexed_reg(hwif, 0x0b) & 0x04)
- return ATA_CBL_PATA40;
- else
- return ATA_CBL_PATA80;
-}
-
-static void pdcnew_reset(ide_drive_t *drive)
-{
- /*
- * Deleted this because it is redundant from the caller.
- */
- printk(KERN_WARNING "pdc202xx_new: %s channel reset.\n",
- drive->hwif->channel ? "Secondary" : "Primary");
-}
-
-/**
- * read_counter - Read the byte count registers
- * @dma_base: for the port address
- */
-static long read_counter(u32 dma_base)
-{
- u32 pri_dma_base = dma_base, sec_dma_base = dma_base + 0x08;
- u8 cnt0, cnt1, cnt2, cnt3;
- long count = 0, last;
- int retry = 3;
-
- do {
- last = count;
-
- /* Read the current count */
- outb(0x20, pri_dma_base + 0x01);
- cnt0 = inb(pri_dma_base + 0x03);
- outb(0x21, pri_dma_base + 0x01);
- cnt1 = inb(pri_dma_base + 0x03);
- outb(0x20, sec_dma_base + 0x01);
- cnt2 = inb(sec_dma_base + 0x03);
- outb(0x21, sec_dma_base + 0x01);
- cnt3 = inb(sec_dma_base + 0x03);
-
- count = (cnt3 << 23) | (cnt2 << 15) | (cnt1 << 8) | cnt0;
-
- /*
- * The 30-bit decrementing counter is read in 4 pieces.
- * Incorrect value may be read when the most significant bytes
- * are changing...
- */
- } while (retry-- && (((last ^ count) & 0x3fff8000) || last < count));
-
- DBG("cnt0[%02X] cnt1[%02X] cnt2[%02X] cnt3[%02X]\n",
- cnt0, cnt1, cnt2, cnt3);
-
- return count;
-}
-
-/**
- * detect_pll_input_clock - Detect the PLL input clock in Hz.
- * @dma_base: for the port address
- * E.g. 16949000 on 33 MHz PCI bus, i.e. half of the PCI clock.
- */
-static long detect_pll_input_clock(unsigned long dma_base)
-{
- ktime_t start_time, end_time;
- long start_count, end_count;
- long pll_input, usec_elapsed;
- u8 scr1;
-
- start_count = read_counter(dma_base);
- start_time = ktime_get();
-
- /* Start the test mode */
- outb(0x01, dma_base + 0x01);
- scr1 = inb(dma_base + 0x03);
- DBG("scr1[%02X]\n", scr1);
- outb(scr1 | 0x40, dma_base + 0x03);
-
- /* Let the counter run for 10 ms. */
- mdelay(10);
-
- end_count = read_counter(dma_base);
- end_time = ktime_get();
-
- /* Stop the test mode */
- outb(0x01, dma_base + 0x01);
- scr1 = inb(dma_base + 0x03);
- DBG("scr1[%02X]\n", scr1);
- outb(scr1 & ~0x40, dma_base + 0x03);
-
- /*
- * Calculate the input clock in Hz
- * (the clock counter is 30 bit wide and counts down)
- */
- usec_elapsed = ktime_us_delta(end_time, start_time);
- pll_input = ((start_count - end_count) & 0x3fffffff) / 10 *
- (10000000 / usec_elapsed);
-
- DBG("start[%ld] end[%ld]\n", start_count, end_count);
-
- return pll_input;
-}
-
-#ifdef CONFIG_PPC_PMAC
-static void apple_kiwi_init(struct pci_dev *pdev)
-{
- struct device_node *np = pci_device_to_OF_node(pdev);
- u8 conf;
-
- if (np == NULL || !of_device_is_compatible(np, "kiwi-root"))
- return;
-
- if (pdev->revision >= 0x03) {
- /* Setup chip magic config stuff (from darwin) */
- pci_read_config_byte (pdev, 0x40, &conf);
- pci_write_config_byte(pdev, 0x40, (conf | 0x01));
- }
-}
-#endif /* CONFIG_PPC_PMAC */
-
-static int init_chipset_pdcnew(struct pci_dev *dev)
-{
- const char *name = DRV_NAME;
- unsigned long dma_base = pci_resource_start(dev, 4);
- unsigned long sec_dma_base = dma_base + 0x08;
- long pll_input, pll_output, ratio;
- int f, r;
- u8 pll_ctl0, pll_ctl1;
-
- if (dma_base == 0)
- return -EFAULT;
-
-#ifdef CONFIG_PPC_PMAC
- apple_kiwi_init(dev);
-#endif
-
- /* Calculate the required PLL output frequency */
- switch(max_dma_rate(dev)) {
- case 4: /* it's 133 MHz for Ultra133 chips */
- pll_output = 133333333;
- break;
- case 3: /* and 100 MHz for Ultra100 chips */
- default:
- pll_output = 100000000;
- break;
- }
-
- /*
- * Detect PLL input clock.
- * On some systems, where PCI bus is running at non-standard clock rate
- * (e.g. 25 or 40 MHz), we have to adjust the cycle time.
- * PDC20268 and newer chips employ PLL circuit to help correct timing
- * registers setting.
- */
- pll_input = detect_pll_input_clock(dma_base);
- printk(KERN_INFO "%s %s: PLL input clock is %ld kHz\n",
- name, pci_name(dev), pll_input / 1000);
-
- /* Sanity check */
- if (unlikely(pll_input < 5000000L || pll_input > 70000000L)) {
- printk(KERN_ERR "%s %s: Bad PLL input clock %ld Hz, giving up!"
- "\n", name, pci_name(dev), pll_input);
- goto out;
- }
-
-#ifdef DEBUG
- DBG("pll_output is %ld Hz\n", pll_output);
-
- /* Show the current clock value of PLL control register
- * (maybe already configured by the BIOS)
- */
- outb(0x02, sec_dma_base + 0x01);
- pll_ctl0 = inb(sec_dma_base + 0x03);
- outb(0x03, sec_dma_base + 0x01);
- pll_ctl1 = inb(sec_dma_base + 0x03);
-
- DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
-#endif
-
- /*
- * Calculate the ratio of F, R and NO
- * POUT = (F + 2) / (( R + 2) * NO)
- */
- ratio = pll_output / (pll_input / 1000);
- if (ratio < 8600L) { /* 8.6x */
- /* Using NO = 0x01, R = 0x0d */
- r = 0x0d;
- } else if (ratio < 12900L) { /* 12.9x */
- /* Using NO = 0x01, R = 0x08 */
- r = 0x08;
- } else if (ratio < 16100L) { /* 16.1x */
- /* Using NO = 0x01, R = 0x06 */
- r = 0x06;
- } else if (ratio < 64000L) { /* 64x */
- r = 0x00;
- } else {
- /* Invalid ratio */
- printk(KERN_ERR "%s %s: Bad ratio %ld, giving up!\n",
- name, pci_name(dev), ratio);
- goto out;
- }
-
- f = (ratio * (r + 2)) / 1000 - 2;
-
- DBG("F[%d] R[%d] ratio*1000[%ld]\n", f, r, ratio);
-
- if (unlikely(f < 0 || f > 127)) {
- /* Invalid F */
- printk(KERN_ERR "%s %s: F[%d] invalid!\n",
- name, pci_name(dev), f);
- goto out;
- }
-
- pll_ctl0 = (u8) f;
- pll_ctl1 = (u8) r;
-
- DBG("Writing pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
-
- outb(0x02, sec_dma_base + 0x01);
- outb(pll_ctl0, sec_dma_base + 0x03);
- outb(0x03, sec_dma_base + 0x01);
- outb(pll_ctl1, sec_dma_base + 0x03);
-
- /* Wait the PLL circuit to be stable */
- mdelay(30);
-
-#ifdef DEBUG
- /*
- * Show the current clock value of PLL control register
- */
- outb(0x02, sec_dma_base + 0x01);
- pll_ctl0 = inb(sec_dma_base + 0x03);
- outb(0x03, sec_dma_base + 0x01);
- pll_ctl1 = inb(sec_dma_base + 0x03);
-
- DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
-#endif
-
- out:
- return 0;
-}
-
-static struct pci_dev *pdc20270_get_dev2(struct pci_dev *dev)
-{
- struct pci_dev *dev2;
-
- dev2 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn) + 1,
- PCI_FUNC(dev->devfn)));
-
- if (dev2 &&
- dev2->vendor == dev->vendor &&
- dev2->device == dev->device) {
-
- if (dev2->irq != dev->irq) {
- dev2->irq = dev->irq;
- printk(KERN_INFO DRV_NAME " %s: PCI config space "
- "interrupt fixed\n", pci_name(dev));
- }
-
- return dev2;
- }
-
- return NULL;
-}
-
-static const struct ide_port_ops pdcnew_port_ops = {
- .set_pio_mode = pdcnew_set_pio_mode,
- .set_dma_mode = pdcnew_set_dma_mode,
- .resetproc = pdcnew_reset,
- .cable_detect = pdcnew_cable_detect,
-};
-
-#define DECLARE_PDCNEW_DEV(udma) \
- { \
- .name = DRV_NAME, \
- .init_chipset = init_chipset_pdcnew, \
- .port_ops = &pdcnew_port_ops, \
- .host_flags = IDE_HFLAG_POST_SET_MODE | \
- IDE_HFLAG_ERROR_STOPS_FIFO | \
- IDE_HFLAG_OFF_BOARD, \
- .pio_mask = ATA_PIO4, \
- .mwdma_mask = ATA_MWDMA2, \
- .udma_mask = udma, \
- }
-
-static const struct ide_port_info pdcnew_chipsets[] = {
- /* 0: PDC202{68,70} */ DECLARE_PDCNEW_DEV(ATA_UDMA5),
- /* 1: PDC202{69,71,75,76,77} */ DECLARE_PDCNEW_DEV(ATA_UDMA6),
-};
-
-/**
- * pdc202new_init_one - called when a pdc202xx is found
- * @dev: the pdc202new device
- * @id: the matching pci id
- *
- * Called when the PCI registration layer (or the IDE initialization)
- * finds a device matching our IDE device tables.
- */
-
-static int pdc202new_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- const struct ide_port_info *d = &pdcnew_chipsets[id->driver_data];
- struct pci_dev *bridge = dev->bus->self;
-
- if (dev->device == PCI_DEVICE_ID_PROMISE_20270 && bridge &&
- bridge->vendor == PCI_VENDOR_ID_DEC &&
- bridge->device == PCI_DEVICE_ID_DEC_21150) {
- struct pci_dev *dev2;
-
- if (PCI_SLOT(dev->devfn) & 2)
- return -ENODEV;
-
- dev2 = pdc20270_get_dev2(dev);
-
- if (dev2) {
- int ret = ide_pci_init_two(dev, dev2, d, NULL);
- if (ret < 0)
- pci_dev_put(dev2);
- return ret;
- }
- }
-
- if (dev->device == PCI_DEVICE_ID_PROMISE_20276 && bridge &&
- bridge->vendor == PCI_VENDOR_ID_INTEL &&
- (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
- bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
- printk(KERN_INFO DRV_NAME " %s: attached to I2O RAID controller,"
- " skipping\n", pci_name(dev));
- return -ENODEV;
- }
-
- return ide_pci_init_one(dev, d, NULL);
-}
-
-static void pdc202new_remove(struct pci_dev *dev)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
-
- ide_pci_remove(dev);
- pci_dev_put(dev2);
-}
-
-static const struct pci_device_id pdc202new_pci_tbl[] = {
- { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20268), 0 },
- { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20269), 1 },
- { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20270), 0 },
- { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20271), 1 },
- { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20275), 1 },
- { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20276), 1 },
- { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20277), 1 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl);
-
-static struct pci_driver pdc202new_pci_driver = {
- .name = "Promise_IDE",
- .id_table = pdc202new_pci_tbl,
- .probe = pdc202new_init_one,
- .remove = pdc202new_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init pdc202new_ide_init(void)
-{
- return ide_pci_register_driver(&pdc202new_pci_driver);
-}
-
-static void __exit pdc202new_ide_exit(void)
-{
- pci_unregister_driver(&pdc202new_pci_driver);
-}
-
-module_init(pdc202new_ide_init);
-module_exit(pdc202new_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
-MODULE_DESCRIPTION("PCI driver module for Promise PDC20268 and higher");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c
deleted file mode 100644
index 5248ac064e6e..000000000000
--- a/drivers/ide/pdc202xx_old.c
+++ /dev/null
@@ -1,362 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2006-2007, 2009 MontaVista Software, Inc.
- * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz
- *
- * Portions Copyright (C) 1999 Promise Technology, Inc.
- * Author: Frank Tiernan (frankt@promise.com)
- * Released under terms of General Public License
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/blkdev.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "pdc202xx_old"
-
-static void pdc202xx_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 drive_pci = 0x60 + (drive->dn << 2);
- const u8 speed = drive->dma_mode;
-
- u8 AP = 0, BP = 0, CP = 0;
- u8 TA = 0, TB = 0, TC = 0;
-
- pci_read_config_byte(dev, drive_pci, &AP);
- pci_read_config_byte(dev, drive_pci + 1, &BP);
- pci_read_config_byte(dev, drive_pci + 2, &CP);
-
- switch(speed) {
- case XFER_UDMA_5:
- case XFER_UDMA_4: TB = 0x20; TC = 0x01; break;
- case XFER_UDMA_2: TB = 0x20; TC = 0x01; break;
- case XFER_UDMA_3:
- case XFER_UDMA_1: TB = 0x40; TC = 0x02; break;
- case XFER_UDMA_0:
- case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break;
- case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break;
- case XFER_MW_DMA_0: TB = 0xE0; TC = 0x0F; break;
- case XFER_PIO_4: TA = 0x01; TB = 0x04; break;
- case XFER_PIO_3: TA = 0x02; TB = 0x06; break;
- case XFER_PIO_2: TA = 0x03; TB = 0x08; break;
- case XFER_PIO_1: TA = 0x05; TB = 0x0C; break;
- case XFER_PIO_0:
- default: TA = 0x09; TB = 0x13; break;
- }
-
- if (speed < XFER_SW_DMA_0) {
- /*
- * preserve SYNC_INT / ERDDY_EN bits while clearing
- * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A
- */
- AP &= ~0x3f;
- if (ide_pio_need_iordy(drive, speed - XFER_PIO_0))
- AP |= 0x20; /* set IORDY_EN bit */
- if (drive->media == ide_disk)
- AP |= 0x10; /* set Prefetch_EN bit */
- /* clear PB[4:0] bits of register B */
- BP &= ~0x1f;
- pci_write_config_byte(dev, drive_pci, AP | TA);
- pci_write_config_byte(dev, drive_pci + 1, BP | TB);
- } else {
- /* clear MB[2:0] bits of register B */
- BP &= ~0xe0;
- /* clear MC[3:0] bits of register C */
- CP &= ~0x0f;
- pci_write_config_byte(dev, drive_pci + 1, BP | TB);
- pci_write_config_byte(dev, drive_pci + 2, CP | TC);
- }
-}
-
-static void pdc202xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- drive->dma_mode = drive->pio_mode;
- pdc202xx_set_mode(hwif, drive);
-}
-
-static int pdc202xx_test_irq(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long high_16 = pci_resource_start(dev, 4);
- u8 sc1d = inb(high_16 + 0x1d);
-
- if (hwif->channel) {
- /*
- * bit 7: error, bit 6: interrupting,
- * bit 5: FIFO full, bit 4: FIFO empty
- */
- return (sc1d & 0x40) ? 1 : 0;
- } else {
- /*
- * bit 3: error, bit 2: interrupting,
- * bit 1: FIFO full, bit 0: FIFO empty
- */
- return (sc1d & 0x04) ? 1 : 0;
- }
-}
-
-static u8 pdc2026x_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u16 CIS, mask = hwif->channel ? (1 << 11) : (1 << 10);
-
- pci_read_config_word(dev, 0x50, &CIS);
-
- return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-}
-
-/*
- * Set the control register to use the 66MHz system
- * clock for UDMA 3/4/5 mode operation when necessary.
- *
- * FIXME: this register is shared by both channels, some locking is needed
- *
- * It may also be possible to leave the 66MHz clock on
- * and readjust the timing parameters.
- */
-static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
-{
- unsigned long clock_reg = hwif->extra_base + 0x01;
- u8 clock = inb(clock_reg);
-
- outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
-}
-
-static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
-{
- unsigned long clock_reg = hwif->extra_base + 0x01;
- u8 clock = inb(clock_reg);
-
- outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
-}
-
-static void pdc2026x_init_hwif(ide_hwif_t *hwif)
-{
- pdc_old_disable_66MHz_clock(hwif);
-}
-
-static void pdc202xx_dma_start(ide_drive_t *drive)
-{
- if (drive->current_speed > XFER_UDMA_2)
- pdc_old_enable_66MHz_clock(drive->hwif);
- if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) {
- ide_hwif_t *hwif = drive->hwif;
- struct request *rq = hwif->rq;
- unsigned long high_16 = hwif->extra_base - 16;
- unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
- u32 word_count = 0;
- u8 clock = inb(high_16 + 0x11);
-
- outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
- word_count = (blk_rq_sectors(rq) << 8);
- word_count = (rq_data_dir(rq) == READ) ?
- word_count | 0x05000000 :
- word_count | 0x06000000;
- outl(word_count, atapi_reg);
- }
- ide_dma_start(drive);
-}
-
-static int pdc202xx_dma_end(ide_drive_t *drive)
-{
- if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) {
- ide_hwif_t *hwif = drive->hwif;
- unsigned long high_16 = hwif->extra_base - 16;
- unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
- u8 clock = 0;
-
- outl(0, atapi_reg); /* zero out extra */
- clock = inb(high_16 + 0x11);
- outb(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
- }
- if (drive->current_speed > XFER_UDMA_2)
- pdc_old_disable_66MHz_clock(drive->hwif);
- return ide_dma_end(drive);
-}
-
-static int init_chipset_pdc202xx(struct pci_dev *dev)
-{
- unsigned long dmabase = pci_resource_start(dev, 4);
- u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
-
- if (dmabase == 0)
- goto out;
-
- udma_speed_flag = inb(dmabase | 0x1f);
- primary_mode = inb(dmabase | 0x1a);
- secondary_mode = inb(dmabase | 0x1b);
- printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \
- "Primary %s Mode " \
- "Secondary %s Mode.\n", pci_name(dev),
- (udma_speed_flag & 1) ? "EN" : "DIS",
- (primary_mode & 1) ? "MASTER" : "PCI",
- (secondary_mode & 1) ? "MASTER" : "PCI" );
-
- if (!(udma_speed_flag & 1)) {
- printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ",
- pci_name(dev), udma_speed_flag,
- (udma_speed_flag|1));
- outb(udma_speed_flag | 1, dmabase | 0x1f);
- printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN");
- }
-out:
- return 0;
-}
-
-static void pdc202ata4_fixup_irq(struct pci_dev *dev, const char *name)
-{
- if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
- u8 irq = 0, irq2 = 0;
- pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
- /* 0xbc */
- pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);
- if (irq != irq2) {
- pci_write_config_byte(dev,
- (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */
- printk(KERN_INFO "%s %s: PCI config space interrupt "
- "mirror fixed\n", name, pci_name(dev));
- }
- }
-}
-
-#define IDE_HFLAGS_PDC202XX \
- (IDE_HFLAG_ERROR_STOPS_FIFO | \
- IDE_HFLAG_OFF_BOARD)
-
-static const struct ide_port_ops pdc20246_port_ops = {
- .set_pio_mode = pdc202xx_set_pio_mode,
- .set_dma_mode = pdc202xx_set_mode,
- .test_irq = pdc202xx_test_irq,
-};
-
-static const struct ide_port_ops pdc2026x_port_ops = {
- .set_pio_mode = pdc202xx_set_pio_mode,
- .set_dma_mode = pdc202xx_set_mode,
- .test_irq = pdc202xx_test_irq,
- .cable_detect = pdc2026x_cable_detect,
-};
-
-static const struct ide_dma_ops pdc2026x_dma_ops = {
- .dma_host_set = ide_dma_host_set,
- .dma_setup = ide_dma_setup,
- .dma_start = pdc202xx_dma_start,
- .dma_end = pdc202xx_dma_end,
- .dma_test_irq = ide_dma_test_irq,
- .dma_lost_irq = ide_dma_lost_irq,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_sff_read_status = ide_dma_sff_read_status,
-};
-
-#define DECLARE_PDC2026X_DEV(udma, sectors) \
- { \
- .name = DRV_NAME, \
- .init_chipset = init_chipset_pdc202xx, \
- .init_hwif = pdc2026x_init_hwif, \
- .port_ops = &pdc2026x_port_ops, \
- .dma_ops = &pdc2026x_dma_ops, \
- .host_flags = IDE_HFLAGS_PDC202XX, \
- .pio_mask = ATA_PIO4, \
- .mwdma_mask = ATA_MWDMA2, \
- .udma_mask = udma, \
- .max_sectors = sectors, \
- }
-
-static const struct ide_port_info pdc202xx_chipsets[] = {
- { /* 0: PDC20246 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_pdc202xx,
- .port_ops = &pdc20246_port_ops,
- .dma_ops = &sff_dma_ops,
- .host_flags = IDE_HFLAGS_PDC202XX,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA2,
- },
-
- /* 1: PDC2026{2,3} */
- DECLARE_PDC2026X_DEV(ATA_UDMA4, 0),
- /* 2: PDC2026{5,7}: UDMA5, limit LBA48 requests to 256 sectors */
- DECLARE_PDC2026X_DEV(ATA_UDMA5, 256),
-};
-
-/**
- * pdc202xx_init_one - called when a PDC202xx is found
- * @dev: the pdc202xx device
- * @id: the matching pci id
- *
- * Called when the PCI registration layer (or the IDE initialization)
- * finds a device matching our IDE device tables.
- */
-
-static int pdc202xx_init_one(struct pci_dev *dev,
- const struct pci_device_id *id)
-{
- const struct ide_port_info *d;
- u8 idx = id->driver_data;
-
- d = &pdc202xx_chipsets[idx];
-
- if (idx < 2)
- pdc202ata4_fixup_irq(dev, d->name);
-
- if (dev->vendor == PCI_DEVICE_ID_PROMISE_20265) {
- struct pci_dev *bridge = dev->bus->self;
-
- if (bridge &&
- bridge->vendor == PCI_VENDOR_ID_INTEL &&
- (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
- bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
- printk(KERN_INFO DRV_NAME " %s: skipping Promise "
- "PDC20265 attached to I2O RAID controller\n",
- pci_name(dev));
- return -ENODEV;
- }
- }
-
- return ide_pci_init_one(dev, d, NULL);
-}
-
-static const struct pci_device_id pdc202xx_pci_tbl[] = {
- { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 },
- { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 },
- { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 },
- { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2 },
- { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl);
-
-static struct pci_driver pdc202xx_pci_driver = {
- .name = "Promise_Old_IDE",
- .id_table = pdc202xx_pci_tbl,
- .probe = pdc202xx_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init pdc202xx_ide_init(void)
-{
- return ide_pci_register_driver(&pdc202xx_pci_driver);
-}
-
-static void __exit pdc202xx_ide_exit(void)
-{
- pci_unregister_driver(&pdc202xx_pci_driver);
-}
-
-module_init(pdc202xx_ide_init);
-module_exit(pdc202xx_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick, Frank Tiernan, Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c
deleted file mode 100644
index a671cead6ae7..000000000000
--- a/drivers/ide/piix.c
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
- * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2003 Red Hat
- * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- * Documentation:
- *
- * Publicly available from Intel web site. Errata documentation
- * is also publicly available. As an aide to anyone hacking on this
- * driver the list of errata that are relevant is below.going back to
- * PIIX4. Older device documentation is now a bit tricky to find.
- *
- * Errata of note:
- *
- * Unfixable
- * PIIX4 errata #9 - Only on ultra obscure hw
- * ICH3 errata #13 - Not observed to affect real hw
- * by Intel
- *
- * Things we must deal with
- * PIIX4 errata #10 - BM IDE hang with non UDMA
- * (must stop/start dma to recover)
- * 440MX errata #15 - As PIIX4 errata #10
- * PIIX4 errata #15 - Must not read control registers
- * during a PIO transfer
- * 440MX errata #13 - As PIIX4 errata #15
- * ICH2 errata #21 - DMA mode 0 doesn't work right
- * ICH0/1 errata #55 - As ICH2 errata #21
- * ICH2 spec c #9 - Extra operations needed to handle
- * drive hotswap [NOT YET SUPPORTED]
- * ICH2 spec c #20 - IDE PRD must not cross a 64K boundary
- * and must be dword aligned
- * ICH2 spec c #24 - UDMA mode 4,5 t85/86 should be 6ns not 3.3
- *
- * Should have been BIOS fixed:
- * 450NX: errata #19 - DMA hangs on old 450NX
- * 450NX: errata #20 - DMA hangs on old 450NX
- * 450NX: errata #25 - Corruption with DMA on old 450NX
- * ICH3 errata #15 - IDE deadlock under high load
- * (BIOS must set dev 31 fn 0 bit 23)
- * ICH3 errata #18 - Don't use native mode
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "piix"
-
-static int no_piix_dma;
-
-/**
- * piix_set_pio_mode - set host controller for PIO mode
- * @port: port
- * @drive: drive
- *
- * Set the interface PIO mode based upon the settings done by AMI BIOS.
- */
-
-static void piix_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- int is_slave = drive->dn & 1;
- int master_port = hwif->channel ? 0x42 : 0x40;
- int slave_port = 0x44;
- unsigned long flags;
- u16 master_data;
- u8 slave_data;
- static DEFINE_SPINLOCK(tune_lock);
- int control = 0;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
-
- /* ISP RTC */
- static const u8 timings[][2]= {
- { 0, 0 },
- { 0, 0 },
- { 1, 0 },
- { 2, 1 },
- { 2, 3 }, };
-
- /*
- * Master vs slave is synchronized above us but the slave register is
- * shared by the two hwifs so the corner case of two slave timeouts in
- * parallel must be locked.
- */
- spin_lock_irqsave(&tune_lock, flags);
- pci_read_config_word(dev, master_port, &master_data);
-
- if (pio > 1)
- control |= 1; /* Programmable timing on */
- if (drive->media == ide_disk)
- control |= 4; /* Prefetch, post write */
- if (ide_pio_need_iordy(drive, pio))
- control |= 2; /* IORDY */
- if (is_slave) {
- master_data |= 0x4000;
- master_data &= ~0x0070;
- if (pio > 1) {
- /* Set PPE, IE and TIME */
- master_data |= control << 4;
- }
- pci_read_config_byte(dev, slave_port, &slave_data);
- slave_data &= hwif->channel ? 0x0f : 0xf0;
- slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) <<
- (hwif->channel ? 4 : 0);
- } else {
- master_data &= ~0x3307;
- if (pio > 1) {
- /* enable PPE, IE and TIME */
- master_data |= control;
- }
- master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
- }
- pci_write_config_word(dev, master_port, master_data);
- if (is_slave)
- pci_write_config_byte(dev, slave_port, slave_data);
- spin_unlock_irqrestore(&tune_lock, flags);
-}
-
-/**
- * piix_set_dma_mode - set host controller for DMA mode
- * @hwif: port
- * @drive: drive
- *
- * Set a PIIX host controller to the desired DMA mode. This involves
- * programming the right timing data into the PCI configuration space.
- */
-
-static void piix_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 maslave = hwif->channel ? 0x42 : 0x40;
- int a_speed = 3 << (drive->dn * 4);
- int u_flag = 1 << drive->dn;
- int v_flag = 0x01 << drive->dn;
- int w_flag = 0x10 << drive->dn;
- int u_speed = 0;
- int sitre;
- u16 reg4042, reg4a;
- u8 reg48, reg54, reg55;
- const u8 speed = drive->dma_mode;
-
- pci_read_config_word(dev, maslave, &reg4042);
- sitre = (reg4042 & 0x4000) ? 1 : 0;
- pci_read_config_byte(dev, 0x48, &reg48);
- pci_read_config_word(dev, 0x4a, &reg4a);
- pci_read_config_byte(dev, 0x54, &reg54);
- pci_read_config_byte(dev, 0x55, &reg55);
-
- if (speed >= XFER_UDMA_0) {
- u8 udma = speed - XFER_UDMA_0;
-
- u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4);
-
- if (!(reg48 & u_flag))
- pci_write_config_byte(dev, 0x48, reg48 | u_flag);
- if (speed == XFER_UDMA_5) {
- pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
- } else {
- pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
- }
- if ((reg4a & a_speed) != u_speed)
- pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
- if (speed > XFER_UDMA_2) {
- if (!(reg54 & v_flag))
- pci_write_config_byte(dev, 0x54, reg54 | v_flag);
- } else
- pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
- } else {
- const u8 mwdma_to_pio[] = { 0, 3, 4 };
-
- if (reg48 & u_flag)
- pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
- if (reg4a & a_speed)
- pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
- if (reg54 & v_flag)
- pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
- if (reg55 & w_flag)
- pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
-
- if (speed >= XFER_MW_DMA_0)
- drive->pio_mode =
- mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0;
- else
- drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */
-
- piix_set_pio_mode(hwif, drive);
- }
-}
-
-/**
- * init_chipset_ich - set up the ICH chipset
- * @dev: PCI device to set up
- *
- * Initialize the PCI device as required. For the ICH this turns
- * out to be nice and simple.
- */
-
-static int init_chipset_ich(struct pci_dev *dev)
-{
- u32 extra = 0;
-
- pci_read_config_dword(dev, 0x54, &extra);
- pci_write_config_dword(dev, 0x54, extra | 0x400);
-
- return 0;
-}
-
-/**
- * ich_clear_irq - clear BMDMA status
- * @drive: IDE drive
- *
- * ICHx contollers set DMA INTR no matter DMA or PIO.
- * BMDMA status might need to be cleared even for
- * PIO interrupts to prevent spurious/lost IRQ.
- */
-static void ich_clear_irq(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 dma_stat;
-
- /*
- * ide_dma_end() needs BMDMA status for error checking.
- * So, skip clearing BMDMA status here and leave it
- * to ide_dma_end() if this is DMA interrupt.
- */
- if (drive->waiting_for_dma || hwif->dma_base == 0)
- return;
-
- /* clear the INTR & ERROR bits */
- dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
- /* Should we force the bit as well ? */
- outb(dma_stat, hwif->dma_base + ATA_DMA_STATUS);
-}
-
-struct ich_laptop {
- u16 device;
- u16 subvendor;
- u16 subdevice;
-};
-
-/*
- * List of laptops that use short cables rather than 80 wire
- */
-
-static const struct ich_laptop ich_laptop[] = {
- /* devid, subvendor, subdev */
- { 0x27DF, 0x1025, 0x0102 }, /* ICH7 on Acer 5602aWLMi */
- { 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */
- { 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */
- { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
- { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */
- { 0x27DF, 0x1071, 0xD221 }, /* ICH7 on Hercules EC-900 */
- { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on Acer Aspire 2023WLMi */
- { 0x24CA, 0x1025, 0x003d }, /* ICH4 on ACER TM290 */
- { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */
- { 0x2653, 0x1043, 0x82D8 }, /* ICH6M on Asus Eee 701 */
- { 0x27df, 0x104d, 0x900e }, /* ICH7 on Sony TZ-90 */
- /* end marker */
- { 0, }
-};
-
-static u8 piix_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *pdev = to_pci_dev(hwif->dev);
- const struct ich_laptop *lap = &ich_laptop[0];
- u8 reg54h = 0, mask = hwif->channel ? 0xc0 : 0x30;
-
- /* check for specials */
- while (lap->device) {
- if (lap->device == pdev->device &&
- lap->subvendor == pdev->subsystem_vendor &&
- lap->subdevice == pdev->subsystem_device) {
- return ATA_CBL_PATA40_SHORT;
- }
- lap++;
- }
-
- pci_read_config_byte(pdev, 0x54, &reg54h);
-
- return (reg54h & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
-}
-
-/**
- * init_hwif_piix - fill in the hwif for the PIIX
- * @hwif: IDE interface
- *
- * Set up the ide_hwif_t for the PIIX interface according to the
- * capabilities of the hardware.
- */
-
-static void init_hwif_piix(ide_hwif_t *hwif)
-{
- if (!hwif->dma_base)
- return;
-
- if (no_piix_dma)
- hwif->ultra_mask = hwif->mwdma_mask = hwif->swdma_mask = 0;
-}
-
-static const struct ide_port_ops piix_port_ops = {
- .set_pio_mode = piix_set_pio_mode,
- .set_dma_mode = piix_set_dma_mode,
- .cable_detect = piix_cable_detect,
-};
-
-static const struct ide_port_ops ich_port_ops = {
- .set_pio_mode = piix_set_pio_mode,
- .set_dma_mode = piix_set_dma_mode,
- .clear_irq = ich_clear_irq,
- .cable_detect = piix_cable_detect,
-};
-
-#define DECLARE_PIIX_DEV(udma) \
- { \
- .name = DRV_NAME, \
- .init_hwif = init_hwif_piix, \
- .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
- .port_ops = &piix_port_ops, \
- .pio_mask = ATA_PIO4, \
- .swdma_mask = ATA_SWDMA2_ONLY, \
- .mwdma_mask = ATA_MWDMA12_ONLY, \
- .udma_mask = udma, \
- }
-
-#define DECLARE_ICH_DEV(mwdma, udma) \
- { \
- .name = DRV_NAME, \
- .init_chipset = init_chipset_ich, \
- .init_hwif = init_hwif_piix, \
- .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
- .port_ops = &ich_port_ops, \
- .pio_mask = ATA_PIO4, \
- .swdma_mask = ATA_SWDMA2_ONLY, \
- .mwdma_mask = mwdma, \
- .udma_mask = udma, \
- }
-
-static const struct ide_port_info piix_pci_info[] = {
- /* 0: MPIIX */
- { /*
- * MPIIX actually has only a single IDE channel mapped to
- * the primary or secondary ports depending on the value
- * of the bit 14 of the IDETIM register at offset 0x6c
- */
- .name = DRV_NAME,
- .enablebits = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
- .host_flags = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_NO_DMA,
- .pio_mask = ATA_PIO4,
- /* This is a painful system best to let it self tune for now */
- },
- /* 1: PIIXa/PIIXb/PIIX3 */
- DECLARE_PIIX_DEV(0x00), /* no udma */
- /* 2: PIIX4 */
- DECLARE_PIIX_DEV(ATA_UDMA2),
- /* 3: ICH0 */
- DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA2),
- /* 4: ICH */
- DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA4),
- /* 5: PIIX4 */
- DECLARE_PIIX_DEV(ATA_UDMA4),
- /* 6: ICH[2-6]/ICH[2-3]M/C-ICH/ICH5-SATA/ESB2/ICH8M */
- DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA5),
- /* 7: ICH7/7-R, no MWDMA1 */
- DECLARE_ICH_DEV(ATA_MWDMA2_ONLY, ATA_UDMA5),
-};
-
-/**
- * piix_init_one - called when a PIIX is found
- * @dev: the piix device
- * @id: the matching pci id
- *
- * Called when the PCI registration layer (or the IDE initialization)
- * finds a device matching our IDE device tables.
- */
-
-static int piix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- return ide_pci_init_one(dev, &piix_pci_info[id->driver_data], NULL);
-}
-
-/**
- * piix_check_450nx - Check for problem 450NX setup
- *
- * Check for the present of 450NX errata #19 and errata #25. If
- * they are found, disable use of DMA IDE
- */
-
-static void piix_check_450nx(void)
-{
- struct pci_dev *pdev = NULL;
- u16 cfg;
- while((pdev=pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL)
- {
- /* Look for 450NX PXB. Check for problem configurations
- A PCI quirk checks bit 6 already */
- pci_read_config_word(pdev, 0x41, &cfg);
- /* Only on the original revision: IDE DMA can hang */
- if (pdev->revision == 0x00)
- no_piix_dma = 1;
- /* On all revisions below 5 PXB bus lock must be disabled for IDE */
- else if (cfg & (1<<14) && pdev->revision < 5)
- no_piix_dma = 2;
- }
- if(no_piix_dma)
- printk(KERN_WARNING DRV_NAME ": 450NX errata present, disabling IDE DMA.\n");
- if(no_piix_dma == 2)
- printk(KERN_WARNING DRV_NAME ": A BIOS update may resolve this.\n");
-}
-
-static const struct pci_device_id piix_pci_tbl[] = {
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371FB_0), 1 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371FB_1), 1 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), 0 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371SB_1), 1 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371AB), 2 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801AB_1), 3 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82443MX_1), 2 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801AA_1), 4 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82372FB_1), 5 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82451NX), 2 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801BA_9), 6 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801BA_8), 6 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801CA_10), 6 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801CA_11), 6 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_11), 6 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_11), 6 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801E_11), 6 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_10), 6 },
-#ifdef CONFIG_BLK_DEV_IDE_SATA
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_1), 6 },
-#endif
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB_2), 6 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH6_19), 6 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH7_21), 7 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1), 6 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18), 7 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH8_6), 6 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
-
-static struct pci_driver piix_pci_driver = {
- .name = "PIIX_IDE",
- .id_table = piix_pci_tbl,
- .probe = piix_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init piix_ide_init(void)
-{
- piix_check_450nx();
- return ide_pci_register_driver(&piix_pci_driver);
-}
-
-static void __exit piix_ide_exit(void)
-{
- pci_unregister_driver(&piix_pci_driver);
-}
-
-module_init(piix_ide_init);
-module_exit(piix_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick, Andrzej Krzysztofowicz");
-MODULE_DESCRIPTION("PCI driver module for Intel PIIX IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c
deleted file mode 100644
index ea0b064b5f56..000000000000
--- a/drivers/ide/pmac.c
+++ /dev/null
@@ -1,1703 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Support for IDE interfaces on PowerMacs.
- *
- * These IDE interfaces are memory-mapped and have a DBDMA channel
- * for doing DMA.
- *
- * Copyright (C) 1998-2003 Paul Mackerras & Ben. Herrenschmidt
- * Copyright (C) 2007-2008 Bartlomiej Zolnierkiewicz
- *
- * Some code taken from drivers/ide/ide-dma.c:
- *
- * Copyright (c) 1995-1998 Mark Lord
- *
- * TODO: - Use pre-calculated (kauai) timing tables all the time and
- * get rid of the "rounded" tables used previously, so we have the
- * same table format for all controllers and can then just have one
- * big table
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/notifier.h>
-#include <linux/module.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-
-#include <asm/prom.h>
-#include <asm/io.h>
-#include <asm/dbdma.h>
-#include <asm/ide.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/sections.h>
-#include <asm/irq.h>
-#include <asm/mediabay.h>
-
-#define DRV_NAME "ide-pmac"
-
-#undef IDE_PMAC_DEBUG
-
-#define DMA_WAIT_TIMEOUT 50
-
-typedef struct pmac_ide_hwif {
- unsigned long regbase;
- int irq;
- int kind;
- int aapl_bus_id;
- unsigned broken_dma : 1;
- unsigned broken_dma_warn : 1;
- struct device_node* node;
- struct macio_dev *mdev;
- u32 timings[4];
- volatile u32 __iomem * *kauai_fcr;
- ide_hwif_t *hwif;
-
- /* Those fields are duplicating what is in hwif. We currently
- * can't use the hwif ones because of some assumptions that are
- * beeing done by the generic code about the kind of dma controller
- * and format of the dma table. This will have to be fixed though.
- */
- volatile struct dbdma_regs __iomem * dma_regs;
- struct dbdma_cmd* dma_table_cpu;
-} pmac_ide_hwif_t;
-
-enum {
- controller_ohare, /* OHare based */
- controller_heathrow, /* Heathrow/Paddington */
- controller_kl_ata3, /* KeyLargo ATA-3 */
- controller_kl_ata4, /* KeyLargo ATA-4 */
- controller_un_ata6, /* UniNorth2 ATA-6 */
- controller_k2_ata6, /* K2 ATA-6 */
- controller_sh_ata6, /* Shasta ATA-6 */
-};
-
-static const char* model_name[] = {
- "OHare ATA", /* OHare based */
- "Heathrow ATA", /* Heathrow/Paddington */
- "KeyLargo ATA-3", /* KeyLargo ATA-3 (MDMA only) */
- "KeyLargo ATA-4", /* KeyLargo ATA-4 (UDMA/66) */
- "UniNorth ATA-6", /* UniNorth2 ATA-6 (UDMA/100) */
- "K2 ATA-6", /* K2 ATA-6 (UDMA/100) */
- "Shasta ATA-6", /* Shasta ATA-6 (UDMA/133) */
-};
-
-/*
- * Extra registers, both 32-bit little-endian
- */
-#define IDE_TIMING_CONFIG 0x200
-#define IDE_INTERRUPT 0x300
-
-/* Kauai (U2) ATA has different register setup */
-#define IDE_KAUAI_PIO_CONFIG 0x200
-#define IDE_KAUAI_ULTRA_CONFIG 0x210
-#define IDE_KAUAI_POLL_CONFIG 0x220
-
-/*
- * Timing configuration register definitions
- */
-
-/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
-#define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
-#define SYSCLK_TICKS_66(t) (((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS)
-#define IDE_SYSCLK_NS 30 /* 33Mhz cell */
-#define IDE_SYSCLK_66_NS 15 /* 66Mhz cell */
-
-/* 133Mhz cell, found in shasta.
- * See comments about 100 Mhz Uninorth 2...
- * Note that PIO_MASK and MDMA_MASK seem to overlap
- */
-#define TR_133_PIOREG_PIO_MASK 0xff000fff
-#define TR_133_PIOREG_MDMA_MASK 0x00fff800
-#define TR_133_UDMAREG_UDMA_MASK 0x0003ffff
-#define TR_133_UDMAREG_UDMA_EN 0x00000001
-
-/* 100Mhz cell, found in Uninorth 2. I don't have much infos about
- * this one yet, it appears as a pci device (106b/0033) on uninorth
- * internal PCI bus and it's clock is controlled like gem or fw. It
- * appears to be an evolution of keylargo ATA4 with a timing register
- * extended to 2 32bits registers and a similar DBDMA channel. Other
- * registers seem to exist but I can't tell much about them.
- *
- * So far, I'm using pre-calculated tables for this extracted from
- * the values used by the MacOS X driver.
- *
- * The "PIO" register controls PIO and MDMA timings, the "ULTRA"
- * register controls the UDMA timings. At least, it seems bit 0
- * of this one enables UDMA vs. MDMA, and bits 4..7 are the
- * cycle time in units of 10ns. Bits 8..15 are used by I don't
- * know their meaning yet
- */
-#define TR_100_PIOREG_PIO_MASK 0xff000fff
-#define TR_100_PIOREG_MDMA_MASK 0x00fff000
-#define TR_100_UDMAREG_UDMA_MASK 0x0000ffff
-#define TR_100_UDMAREG_UDMA_EN 0x00000001
-
-
-/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
- * 40 connector cable and to 4 on 80 connector one.
- * Clock unit is 15ns (66Mhz)
- *
- * 3 Values can be programmed:
- * - Write data setup, which appears to match the cycle time. They
- * also call it DIOW setup.
- * - Ready to pause time (from spec)
- * - Address setup. That one is weird. I don't see where exactly
- * it fits in UDMA cycles, I got it's name from an obscure piece
- * of commented out code in Darwin. They leave it to 0, we do as
- * well, despite a comment that would lead to think it has a
- * min value of 45ns.
- * Apple also add 60ns to the write data setup (or cycle time ?) on
- * reads.
- */
-#define TR_66_UDMA_MASK 0xfff00000
-#define TR_66_UDMA_EN 0x00100000 /* Enable Ultra mode for DMA */
-#define TR_66_UDMA_ADDRSETUP_MASK 0xe0000000 /* Address setup */
-#define TR_66_UDMA_ADDRSETUP_SHIFT 29
-#define TR_66_UDMA_RDY2PAUS_MASK 0x1e000000 /* Ready 2 pause time */
-#define TR_66_UDMA_RDY2PAUS_SHIFT 25
-#define TR_66_UDMA_WRDATASETUP_MASK 0x01e00000 /* Write data setup time */
-#define TR_66_UDMA_WRDATASETUP_SHIFT 21
-#define TR_66_MDMA_MASK 0x000ffc00
-#define TR_66_MDMA_RECOVERY_MASK 0x000f8000
-#define TR_66_MDMA_RECOVERY_SHIFT 15
-#define TR_66_MDMA_ACCESS_MASK 0x00007c00
-#define TR_66_MDMA_ACCESS_SHIFT 10
-#define TR_66_PIO_MASK 0x000003ff
-#define TR_66_PIO_RECOVERY_MASK 0x000003e0
-#define TR_66_PIO_RECOVERY_SHIFT 5
-#define TR_66_PIO_ACCESS_MASK 0x0000001f
-#define TR_66_PIO_ACCESS_SHIFT 0
-
-/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
- * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
- *
- * The access time and recovery time can be programmed. Some older
- * Darwin code base limit OHare to 150ns cycle time. I decided to do
- * the same here fore safety against broken old hardware ;)
- * The HalfTick bit, when set, adds half a clock (15ns) to the access
- * time and removes one from recovery. It's not supported on KeyLargo
- * implementation afaik. The E bit appears to be set for PIO mode 0 and
- * is used to reach long timings used in this mode.
- */
-#define TR_33_MDMA_MASK 0x003ff800
-#define TR_33_MDMA_RECOVERY_MASK 0x001f0000
-#define TR_33_MDMA_RECOVERY_SHIFT 16
-#define TR_33_MDMA_ACCESS_MASK 0x0000f800
-#define TR_33_MDMA_ACCESS_SHIFT 11
-#define TR_33_MDMA_HALFTICK 0x00200000
-#define TR_33_PIO_MASK 0x000007ff
-#define TR_33_PIO_E 0x00000400
-#define TR_33_PIO_RECOVERY_MASK 0x000003e0
-#define TR_33_PIO_RECOVERY_SHIFT 5
-#define TR_33_PIO_ACCESS_MASK 0x0000001f
-#define TR_33_PIO_ACCESS_SHIFT 0
-
-/*
- * Interrupt register definitions
- */
-#define IDE_INTR_DMA 0x80000000
-#define IDE_INTR_DEVICE 0x40000000
-
-/*
- * FCR Register on Kauai. Not sure what bit 0x4 is ...
- */
-#define KAUAI_FCR_UATA_MAGIC 0x00000004
-#define KAUAI_FCR_UATA_RESET_N 0x00000002
-#define KAUAI_FCR_UATA_ENABLE 0x00000001
-
-/* Rounded Multiword DMA timings
- *
- * I gave up finding a generic formula for all controller
- * types and instead, built tables based on timing values
- * used by Apple in Darwin's implementation.
- */
-struct mdma_timings_t {
- int accessTime;
- int recoveryTime;
- int cycleTime;
-};
-
-struct mdma_timings_t mdma_timings_33[] =
-{
- { 240, 240, 480 },
- { 180, 180, 360 },
- { 135, 135, 270 },
- { 120, 120, 240 },
- { 105, 105, 210 },
- { 90, 90, 180 },
- { 75, 75, 150 },
- { 75, 45, 120 },
- { 0, 0, 0 }
-};
-
-struct mdma_timings_t mdma_timings_33k[] =
-{
- { 240, 240, 480 },
- { 180, 180, 360 },
- { 150, 150, 300 },
- { 120, 120, 240 },
- { 90, 120, 210 },
- { 90, 90, 180 },
- { 90, 60, 150 },
- { 90, 30, 120 },
- { 0, 0, 0 }
-};
-
-struct mdma_timings_t mdma_timings_66[] =
-{
- { 240, 240, 480 },
- { 180, 180, 360 },
- { 135, 135, 270 },
- { 120, 120, 240 },
- { 105, 105, 210 },
- { 90, 90, 180 },
- { 90, 75, 165 },
- { 75, 45, 120 },
- { 0, 0, 0 }
-};
-
-/* KeyLargo ATA-4 Ultra DMA timings (rounded) */
-struct {
- int addrSetup; /* ??? */
- int rdy2pause;
- int wrDataSetup;
-} kl66_udma_timings[] =
-{
- { 0, 180, 120 }, /* Mode 0 */
- { 0, 150, 90 }, /* 1 */
- { 0, 120, 60 }, /* 2 */
- { 0, 90, 45 }, /* 3 */
- { 0, 90, 30 } /* 4 */
-};
-
-/* UniNorth 2 ATA/100 timings */
-struct kauai_timing {
- int cycle_time;
- u32 timing_reg;
-};
-
-static struct kauai_timing kauai_pio_timings[] =
-{
- { 930 , 0x08000fff },
- { 600 , 0x08000a92 },
- { 383 , 0x0800060f },
- { 360 , 0x08000492 },
- { 330 , 0x0800048f },
- { 300 , 0x080003cf },
- { 270 , 0x080003cc },
- { 240 , 0x0800038b },
- { 239 , 0x0800030c },
- { 180 , 0x05000249 },
- { 120 , 0x04000148 },
- { 0 , 0 },
-};
-
-static struct kauai_timing kauai_mdma_timings[] =
-{
- { 1260 , 0x00fff000 },
- { 480 , 0x00618000 },
- { 360 , 0x00492000 },
- { 270 , 0x0038e000 },
- { 240 , 0x0030c000 },
- { 210 , 0x002cb000 },
- { 180 , 0x00249000 },
- { 150 , 0x00209000 },
- { 120 , 0x00148000 },
- { 0 , 0 },
-};
-
-static struct kauai_timing kauai_udma_timings[] =
-{
- { 120 , 0x000070c0 },
- { 90 , 0x00005d80 },
- { 60 , 0x00004a60 },
- { 45 , 0x00003a50 },
- { 30 , 0x00002a30 },
- { 20 , 0x00002921 },
- { 0 , 0 },
-};
-
-static struct kauai_timing shasta_pio_timings[] =
-{
- { 930 , 0x08000fff },
- { 600 , 0x0A000c97 },
- { 383 , 0x07000712 },
- { 360 , 0x040003cd },
- { 330 , 0x040003cd },
- { 300 , 0x040003cd },
- { 270 , 0x040003cd },
- { 240 , 0x040003cd },
- { 239 , 0x040003cd },
- { 180 , 0x0400028b },
- { 120 , 0x0400010a },
- { 0 , 0 },
-};
-
-static struct kauai_timing shasta_mdma_timings[] =
-{
- { 1260 , 0x00fff000 },
- { 480 , 0x00820800 },
- { 360 , 0x00820800 },
- { 270 , 0x00820800 },
- { 240 , 0x00820800 },
- { 210 , 0x00820800 },
- { 180 , 0x00820800 },
- { 150 , 0x0028b000 },
- { 120 , 0x001ca000 },
- { 0 , 0 },
-};
-
-static struct kauai_timing shasta_udma133_timings[] =
-{
- { 120 , 0x00035901, },
- { 90 , 0x000348b1, },
- { 60 , 0x00033881, },
- { 45 , 0x00033861, },
- { 30 , 0x00033841, },
- { 20 , 0x00033031, },
- { 15 , 0x00033021, },
- { 0 , 0 },
-};
-
-
-static inline u32
-kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
-{
- int i;
-
- for (i=0; table[i].cycle_time; i++)
- if (cycle_time > table[i+1].cycle_time)
- return table[i].timing_reg;
- BUG();
- return 0;
-}
-
-/* allow up to 256 DBDMA commands per xfer */
-#define MAX_DCMDS 256
-
-/*
- * Wait 1s for disk to answer on IDE bus after a hard reset
- * of the device (via GPIO/FCR).
- *
- * Some devices seem to "pollute" the bus even after dropping
- * the BSY bit (typically some combo drives slave on the UDMA
- * bus) after a hard reset. Since we hard reset all drives on
- * KeyLargo ATA66, we have to keep that delay around. I may end
- * up not hard resetting anymore on these and keep the delay only
- * for older interfaces instead (we have to reset when coming
- * from MacOS...) --BenH.
- */
-#define IDE_WAKEUP_DELAY (1*HZ)
-
-static int pmac_ide_init_dma(ide_hwif_t *, const struct ide_port_info *);
-
-#define PMAC_IDE_REG(x) \
- ((void __iomem *)((drive)->hwif->io_ports.data_addr + (x)))
-
-/*
- * Apply the timings of the proper unit (master/slave) to the shared
- * timing register when selecting that unit. This version is for
- * ASICs with a single timing register
- */
-static void pmac_ide_apply_timings(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-
- if (drive->dn & 1)
- writel(pmif->timings[1], PMAC_IDE_REG(IDE_TIMING_CONFIG));
- else
- writel(pmif->timings[0], PMAC_IDE_REG(IDE_TIMING_CONFIG));
- (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG));
-}
-
-/*
- * Apply the timings of the proper unit (master/slave) to the shared
- * timing register when selecting that unit. This version is for
- * ASICs with a dual timing register (Kauai)
- */
-static void pmac_ide_kauai_apply_timings(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-
- if (drive->dn & 1) {
- writel(pmif->timings[1], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG));
- writel(pmif->timings[3], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG));
- } else {
- writel(pmif->timings[0], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG));
- writel(pmif->timings[2], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG));
- }
- (void)readl(PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG));
-}
-
-/*
- * Force an update of controller timing values for a given drive
- */
-static void
-pmac_ide_do_update_timings(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-
- if (pmif->kind == controller_sh_ata6 ||
- pmif->kind == controller_un_ata6 ||
- pmif->kind == controller_k2_ata6)
- pmac_ide_kauai_apply_timings(drive);
- else
- pmac_ide_apply_timings(drive);
-}
-
-static void pmac_dev_select(ide_drive_t *drive)
-{
- pmac_ide_apply_timings(drive);
-
- writeb(drive->select | ATA_DEVICE_OBS,
- (void __iomem *)drive->hwif->io_ports.device_addr);
-}
-
-static void pmac_kauai_dev_select(ide_drive_t *drive)
-{
- pmac_ide_kauai_apply_timings(drive);
-
- writeb(drive->select | ATA_DEVICE_OBS,
- (void __iomem *)drive->hwif->io_ports.device_addr);
-}
-
-static void pmac_exec_command(ide_hwif_t *hwif, u8 cmd)
-{
- writeb(cmd, (void __iomem *)hwif->io_ports.command_addr);
- (void)readl((void __iomem *)(hwif->io_ports.data_addr
- + IDE_TIMING_CONFIG));
-}
-
-static void pmac_write_devctl(ide_hwif_t *hwif, u8 ctl)
-{
- writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
- (void)readl((void __iomem *)(hwif->io_ports.data_addr
- + IDE_TIMING_CONFIG));
-}
-
-/*
- * Old tuning functions (called on hdparm -p), sets up drive PIO timings
- */
-static void pmac_ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
- const u8 pio = drive->pio_mode - XFER_PIO_0;
- struct ide_timing *tim = ide_timing_find_mode(XFER_PIO_0 + pio);
- u32 *timings, t;
- unsigned accessTicks, recTicks;
- unsigned accessTime, recTime;
- unsigned int cycle_time;
-
- /* which drive is it ? */
- timings = &pmif->timings[drive->dn & 1];
- t = *timings;
-
- cycle_time = ide_pio_cycle_time(drive, pio);
-
- switch (pmif->kind) {
- case controller_sh_ata6: {
- /* 133Mhz cell */
- u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time);
- t = (t & ~TR_133_PIOREG_PIO_MASK) | tr;
- break;
- }
- case controller_un_ata6:
- case controller_k2_ata6: {
- /* 100Mhz cell */
- u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time);
- t = (t & ~TR_100_PIOREG_PIO_MASK) | tr;
- break;
- }
- case controller_kl_ata4:
- /* 66Mhz cell */
- recTime = cycle_time - tim->active - tim->setup;
- recTime = max(recTime, 150U);
- accessTime = tim->active;
- accessTime = max(accessTime, 150U);
- accessTicks = SYSCLK_TICKS_66(accessTime);
- accessTicks = min(accessTicks, 0x1fU);
- recTicks = SYSCLK_TICKS_66(recTime);
- recTicks = min(recTicks, 0x1fU);
- t = (t & ~TR_66_PIO_MASK) |
- (accessTicks << TR_66_PIO_ACCESS_SHIFT) |
- (recTicks << TR_66_PIO_RECOVERY_SHIFT);
- break;
- default: {
- /* 33Mhz cell */
- int ebit = 0;
- recTime = cycle_time - tim->active - tim->setup;
- recTime = max(recTime, 150U);
- accessTime = tim->active;
- accessTime = max(accessTime, 150U);
- accessTicks = SYSCLK_TICKS(accessTime);
- accessTicks = min(accessTicks, 0x1fU);
- accessTicks = max(accessTicks, 4U);
- recTicks = SYSCLK_TICKS(recTime);
- recTicks = min(recTicks, 0x1fU);
- recTicks = max(recTicks, 5U) - 4;
- if (recTicks > 9) {
- recTicks--; /* guess, but it's only for PIO0, so... */
- ebit = 1;
- }
- t = (t & ~TR_33_PIO_MASK) |
- (accessTicks << TR_33_PIO_ACCESS_SHIFT) |
- (recTicks << TR_33_PIO_RECOVERY_SHIFT);
- if (ebit)
- t |= TR_33_PIO_E;
- break;
- }
- }
-
-#ifdef IDE_PMAC_DEBUG
- printk(KERN_ERR "%s: Set PIO timing for mode %d, reg: 0x%08x\n",
- drive->name, pio, *timings);
-#endif
-
- *timings = t;
- pmac_ide_do_update_timings(drive);
-}
-
-/*
- * Calculate KeyLargo ATA/66 UDMA timings
- */
-static int
-set_timings_udma_ata4(u32 *timings, u8 speed)
-{
- unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks;
-
- if (speed > XFER_UDMA_4)
- return 1;
-
- rdyToPauseTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].rdy2pause);
- wrDataSetupTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].wrDataSetup);
- addrTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].addrSetup);
-
- *timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) |
- (wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) |
- (rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) |
- (addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) |
- TR_66_UDMA_EN;
-#ifdef IDE_PMAC_DEBUG
- printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n",
- speed & 0xf, *timings);
-#endif
-
- return 0;
-}
-
-/*
- * Calculate Kauai ATA/100 UDMA timings
- */
-static int
-set_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, u8 speed)
-{
- struct ide_timing *t = ide_timing_find_mode(speed);
- u32 tr;
-
- if (speed > XFER_UDMA_5 || t == NULL)
- return 1;
- tr = kauai_lookup_timing(kauai_udma_timings, (int)t->udma);
- *ultra_timings = ((*ultra_timings) & ~TR_100_UDMAREG_UDMA_MASK) | tr;
- *ultra_timings = (*ultra_timings) | TR_100_UDMAREG_UDMA_EN;
-
- return 0;
-}
-
-/*
- * Calculate Shasta ATA/133 UDMA timings
- */
-static int
-set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed)
-{
- struct ide_timing *t = ide_timing_find_mode(speed);
- u32 tr;
-
- if (speed > XFER_UDMA_6 || t == NULL)
- return 1;
- tr = kauai_lookup_timing(shasta_udma133_timings, (int)t->udma);
- *ultra_timings = ((*ultra_timings) & ~TR_133_UDMAREG_UDMA_MASK) | tr;
- *ultra_timings = (*ultra_timings) | TR_133_UDMAREG_UDMA_EN;
-
- return 0;
-}
-
-/*
- * Calculate MDMA timings for all cells
- */
-static void
-set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
- u8 speed)
-{
- u16 *id = drive->id;
- int cycleTime, accessTime = 0, recTime = 0;
- unsigned accessTicks, recTicks;
- struct mdma_timings_t* tm = NULL;
- int i;
-
- /* Get default cycle time for mode */
- switch(speed & 0xf) {
- case 0: cycleTime = 480; break;
- case 1: cycleTime = 150; break;
- case 2: cycleTime = 120; break;
- default:
- BUG();
- break;
- }
-
- /* Check if drive provides explicit DMA cycle time */
- if ((id[ATA_ID_FIELD_VALID] & 2) && id[ATA_ID_EIDE_DMA_TIME])
- cycleTime = max_t(int, id[ATA_ID_EIDE_DMA_TIME], cycleTime);
-
- /* OHare limits according to some old Apple sources */
- if ((intf_type == controller_ohare) && (cycleTime < 150))
- cycleTime = 150;
- /* Get the proper timing array for this controller */
- switch(intf_type) {
- case controller_sh_ata6:
- case controller_un_ata6:
- case controller_k2_ata6:
- break;
- case controller_kl_ata4:
- tm = mdma_timings_66;
- break;
- case controller_kl_ata3:
- tm = mdma_timings_33k;
- break;
- default:
- tm = mdma_timings_33;
- break;
- }
- if (tm != NULL) {
- /* Lookup matching access & recovery times */
- i = -1;
- for (;;) {
- if (tm[i+1].cycleTime < cycleTime)
- break;
- i++;
- }
- cycleTime = tm[i].cycleTime;
- accessTime = tm[i].accessTime;
- recTime = tm[i].recoveryTime;
-
-#ifdef IDE_PMAC_DEBUG
- printk(KERN_ERR "%s: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n",
- drive->name, cycleTime, accessTime, recTime);
-#endif
- }
- switch(intf_type) {
- case controller_sh_ata6: {
- /* 133Mhz cell */
- u32 tr = kauai_lookup_timing(shasta_mdma_timings, cycleTime);
- *timings = ((*timings) & ~TR_133_PIOREG_MDMA_MASK) | tr;
- *timings2 = (*timings2) & ~TR_133_UDMAREG_UDMA_EN;
- }
- break;
- case controller_un_ata6:
- case controller_k2_ata6: {
- /* 100Mhz cell */
- u32 tr = kauai_lookup_timing(kauai_mdma_timings, cycleTime);
- *timings = ((*timings) & ~TR_100_PIOREG_MDMA_MASK) | tr;
- *timings2 = (*timings2) & ~TR_100_UDMAREG_UDMA_EN;
- }
- break;
- case controller_kl_ata4:
- /* 66Mhz cell */
- accessTicks = SYSCLK_TICKS_66(accessTime);
- accessTicks = min(accessTicks, 0x1fU);
- accessTicks = max(accessTicks, 0x1U);
- recTicks = SYSCLK_TICKS_66(recTime);
- recTicks = min(recTicks, 0x1fU);
- recTicks = max(recTicks, 0x3U);
- /* Clear out mdma bits and disable udma */
- *timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) |
- (accessTicks << TR_66_MDMA_ACCESS_SHIFT) |
- (recTicks << TR_66_MDMA_RECOVERY_SHIFT);
- break;
- case controller_kl_ata3:
- /* 33Mhz cell on KeyLargo */
- accessTicks = SYSCLK_TICKS(accessTime);
- accessTicks = max(accessTicks, 1U);
- accessTicks = min(accessTicks, 0x1fU);
- accessTime = accessTicks * IDE_SYSCLK_NS;
- recTicks = SYSCLK_TICKS(recTime);
- recTicks = max(recTicks, 1U);
- recTicks = min(recTicks, 0x1fU);
- *timings = ((*timings) & ~TR_33_MDMA_MASK) |
- (accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
- (recTicks << TR_33_MDMA_RECOVERY_SHIFT);
- break;
- default: {
- /* 33Mhz cell on others */
- int halfTick = 0;
- int origAccessTime = accessTime;
- int origRecTime = recTime;
-
- accessTicks = SYSCLK_TICKS(accessTime);
- accessTicks = max(accessTicks, 1U);
- accessTicks = min(accessTicks, 0x1fU);
- accessTime = accessTicks * IDE_SYSCLK_NS;
- recTicks = SYSCLK_TICKS(recTime);
- recTicks = max(recTicks, 2U) - 1;
- recTicks = min(recTicks, 0x1fU);
- recTime = (recTicks + 1) * IDE_SYSCLK_NS;
- if ((accessTicks > 1) &&
- ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
- ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) {
- halfTick = 1;
- accessTicks--;
- }
- *timings = ((*timings) & ~TR_33_MDMA_MASK) |
- (accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
- (recTicks << TR_33_MDMA_RECOVERY_SHIFT);
- if (halfTick)
- *timings |= TR_33_MDMA_HALFTICK;
- }
- }
-#ifdef IDE_PMAC_DEBUG
- printk(KERN_ERR "%s: Set MDMA timing for mode %d, reg: 0x%08x\n",
- drive->name, speed & 0xf, *timings);
-#endif
-}
-
-static void pmac_ide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
- int ret = 0;
- u32 *timings, *timings2, tl[2];
- u8 unit = drive->dn & 1;
- const u8 speed = drive->dma_mode;
-
- timings = &pmif->timings[unit];
- timings2 = &pmif->timings[unit+2];
-
- /* Copy timings to local image */
- tl[0] = *timings;
- tl[1] = *timings2;
-
- if (speed >= XFER_UDMA_0) {
- if (pmif->kind == controller_kl_ata4)
- ret = set_timings_udma_ata4(&tl[0], speed);
- else if (pmif->kind == controller_un_ata6
- || pmif->kind == controller_k2_ata6)
- ret = set_timings_udma_ata6(&tl[0], &tl[1], speed);
- else if (pmif->kind == controller_sh_ata6)
- ret = set_timings_udma_shasta(&tl[0], &tl[1], speed);
- else
- ret = -1;
- } else
- set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed);
-
- if (ret)
- return;
-
- /* Apply timings to controller */
- *timings = tl[0];
- *timings2 = tl[1];
-
- pmac_ide_do_update_timings(drive);
-}
-
-/*
- * Blast some well known "safe" values to the timing registers at init or
- * wakeup from sleep time, before we do real calculation
- */
-static void
-sanitize_timings(pmac_ide_hwif_t *pmif)
-{
- unsigned int value, value2 = 0;
-
- switch(pmif->kind) {
- case controller_sh_ata6:
- value = 0x0a820c97;
- value2 = 0x00033031;
- break;
- case controller_un_ata6:
- case controller_k2_ata6:
- value = 0x08618a92;
- value2 = 0x00002921;
- break;
- case controller_kl_ata4:
- value = 0x0008438c;
- break;
- case controller_kl_ata3:
- value = 0x00084526;
- break;
- case controller_heathrow:
- case controller_ohare:
- default:
- value = 0x00074526;
- break;
- }
- pmif->timings[0] = pmif->timings[1] = value;
- pmif->timings[2] = pmif->timings[3] = value2;
-}
-
-static int on_media_bay(pmac_ide_hwif_t *pmif)
-{
- return pmif->mdev && pmif->mdev->media_bay != NULL;
-}
-
-/* Suspend call back, should be called after the child devices
- * have actually been suspended
- */
-static int pmac_ide_do_suspend(pmac_ide_hwif_t *pmif)
-{
- /* We clear the timings */
- pmif->timings[0] = 0;
- pmif->timings[1] = 0;
-
- disable_irq(pmif->irq);
-
- /* The media bay will handle itself just fine */
- if (on_media_bay(pmif))
- return 0;
-
- /* Kauai has bus control FCRs directly here */
- if (pmif->kauai_fcr) {
- u32 fcr = readl(pmif->kauai_fcr);
- fcr &= ~(KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE);
- writel(fcr, pmif->kauai_fcr);
- }
-
- /* Disable the bus on older machines and the cell on kauai */
- ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id,
- 0);
-
- return 0;
-}
-
-/* Resume call back, should be called before the child devices
- * are resumed
- */
-static int pmac_ide_do_resume(pmac_ide_hwif_t *pmif)
-{
- /* Hard reset & re-enable controller (do we really need to reset ? -BenH) */
- if (!on_media_bay(pmif)) {
- ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 1);
- ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 1);
- msleep(10);
- ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 0);
-
- /* Kauai has it different */
- if (pmif->kauai_fcr) {
- u32 fcr = readl(pmif->kauai_fcr);
- fcr |= KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE;
- writel(fcr, pmif->kauai_fcr);
- }
-
- msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY));
- }
-
- /* Sanitize drive timings */
- sanitize_timings(pmif);
-
- enable_irq(pmif->irq);
-
- return 0;
-}
-
-static u8 pmac_ide_cable_detect(ide_hwif_t *hwif)
-{
- pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
- struct device_node *np = pmif->node;
- const char *cable = of_get_property(np, "cable-type", NULL);
- struct device_node *root = of_find_node_by_path("/");
- const char *model = of_get_property(root, "model", NULL);
-
- of_node_put(root);
- /* Get cable type from device-tree. */
- if (cable && !strncmp(cable, "80-", 3)) {
- /* Some drives fail to detect 80c cable in PowerBook */
- /* These machine use proprietary short IDE cable anyway */
- if (!strncmp(model, "PowerBook", 9))
- return ATA_CBL_PATA40_SHORT;
- else
- return ATA_CBL_PATA80;
- }
-
- /*
- * G5's seem to have incorrect cable type in device-tree.
- * Let's assume they have a 80 conductor cable, this seem
- * to be always the case unless the user mucked around.
- */
- if (of_device_is_compatible(np, "K2-UATA") ||
- of_device_is_compatible(np, "shasta-ata"))
- return ATA_CBL_PATA80;
-
- return ATA_CBL_PATA40;
-}
-
-static void pmac_ide_init_dev(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
-
- if (on_media_bay(pmif)) {
- if (check_media_bay(pmif->mdev->media_bay) == MB_CD) {
- drive->dev_flags &= ~IDE_DFLAG_NOPROBE;
- return;
- }
- drive->dev_flags |= IDE_DFLAG_NOPROBE;
- }
-}
-
-static const struct ide_tp_ops pmac_tp_ops = {
- .exec_command = pmac_exec_command,
- .read_status = ide_read_status,
- .read_altstatus = ide_read_altstatus,
- .write_devctl = pmac_write_devctl,
-
- .dev_select = pmac_dev_select,
- .tf_load = ide_tf_load,
- .tf_read = ide_tf_read,
-
- .input_data = ide_input_data,
- .output_data = ide_output_data,
-};
-
-static const struct ide_tp_ops pmac_ata6_tp_ops = {
- .exec_command = pmac_exec_command,
- .read_status = ide_read_status,
- .read_altstatus = ide_read_altstatus,
- .write_devctl = pmac_write_devctl,
-
- .dev_select = pmac_kauai_dev_select,
- .tf_load = ide_tf_load,
- .tf_read = ide_tf_read,
-
- .input_data = ide_input_data,
- .output_data = ide_output_data,
-};
-
-static const struct ide_port_ops pmac_ide_ata4_port_ops = {
- .init_dev = pmac_ide_init_dev,
- .set_pio_mode = pmac_ide_set_pio_mode,
- .set_dma_mode = pmac_ide_set_dma_mode,
- .cable_detect = pmac_ide_cable_detect,
-};
-
-static const struct ide_port_ops pmac_ide_port_ops = {
- .init_dev = pmac_ide_init_dev,
- .set_pio_mode = pmac_ide_set_pio_mode,
- .set_dma_mode = pmac_ide_set_dma_mode,
-};
-
-static const struct ide_dma_ops pmac_dma_ops;
-
-static const struct ide_port_info pmac_port_info = {
- .name = DRV_NAME,
- .init_dma = pmac_ide_init_dma,
- .chipset = ide_pmac,
- .tp_ops = &pmac_tp_ops,
- .port_ops = &pmac_ide_port_ops,
- .dma_ops = &pmac_dma_ops,
- .host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA |
- IDE_HFLAG_POST_SET_MODE |
- IDE_HFLAG_MMIO |
- IDE_HFLAG_UNMASK_IRQS,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
-};
-
-/*
- * Setup, register & probe an IDE channel driven by this driver, this is
- * called by one of the 2 probe functions (macio or PCI).
- */
-static int pmac_ide_setup_device(pmac_ide_hwif_t *pmif, struct ide_hw *hw)
-{
- struct device_node *np = pmif->node;
- const int *bidp;
- struct ide_host *host;
- struct ide_hw *hws[] = { hw };
- struct ide_port_info d = pmac_port_info;
- int rc;
-
- pmif->broken_dma = pmif->broken_dma_warn = 0;
- if (of_device_is_compatible(np, "shasta-ata")) {
- pmif->kind = controller_sh_ata6;
- d.tp_ops = &pmac_ata6_tp_ops;
- d.port_ops = &pmac_ide_ata4_port_ops;
- d.udma_mask = ATA_UDMA6;
- } else if (of_device_is_compatible(np, "kauai-ata")) {
- pmif->kind = controller_un_ata6;
- d.tp_ops = &pmac_ata6_tp_ops;
- d.port_ops = &pmac_ide_ata4_port_ops;
- d.udma_mask = ATA_UDMA5;
- } else if (of_device_is_compatible(np, "K2-UATA")) {
- pmif->kind = controller_k2_ata6;
- d.tp_ops = &pmac_ata6_tp_ops;
- d.port_ops = &pmac_ide_ata4_port_ops;
- d.udma_mask = ATA_UDMA5;
- } else if (of_device_is_compatible(np, "keylargo-ata")) {
- if (of_node_name_eq(np, "ata-4")) {
- pmif->kind = controller_kl_ata4;
- d.port_ops = &pmac_ide_ata4_port_ops;
- d.udma_mask = ATA_UDMA4;
- } else
- pmif->kind = controller_kl_ata3;
- } else if (of_device_is_compatible(np, "heathrow-ata")) {
- pmif->kind = controller_heathrow;
- } else {
- pmif->kind = controller_ohare;
- pmif->broken_dma = 1;
- }
-
- bidp = of_get_property(np, "AAPL,bus-id", NULL);
- pmif->aapl_bus_id = bidp ? *bidp : 0;
-
- /* On Kauai-type controllers, we make sure the FCR is correct */
- if (pmif->kauai_fcr)
- writel(KAUAI_FCR_UATA_MAGIC |
- KAUAI_FCR_UATA_RESET_N |
- KAUAI_FCR_UATA_ENABLE, pmif->kauai_fcr);
-
- /* Make sure we have sane timings */
- sanitize_timings(pmif);
-
- /* If we are on a media bay, wait for it to settle and lock it */
- if (pmif->mdev)
- lock_media_bay(pmif->mdev->media_bay);
-
- host = ide_host_alloc(&d, hws, 1);
- if (host == NULL) {
- rc = -ENOMEM;
- goto bail;
- }
- pmif->hwif = host->ports[0];
-
- if (on_media_bay(pmif)) {
- /* Fixup bus ID for media bay */
- if (!bidp)
- pmif->aapl_bus_id = 1;
- } else if (pmif->kind == controller_ohare) {
- /* The code below is having trouble on some ohare machines
- * (timing related ?). Until I can put my hand on one of these
- * units, I keep the old way
- */
- ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
- } else {
- /* This is necessary to enable IDE when net-booting */
- ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
- ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
- msleep(10);
- ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
- msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY));
- }
-
- printk(KERN_INFO DRV_NAME ": Found Apple %s controller (%s), "
- "bus ID %d%s, irq %d\n", model_name[pmif->kind],
- pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id,
- on_media_bay(pmif) ? " (mediabay)" : "", hw->irq);
-
- rc = ide_host_register(host, &d, hws);
- if (rc)
- pmif->hwif = NULL;
-
- if (pmif->mdev)
- unlock_media_bay(pmif->mdev->media_bay);
-
- bail:
- if (rc && host)
- ide_host_free(host);
- return rc;
-}
-
-static void pmac_ide_init_ports(struct ide_hw *hw, unsigned long base)
-{
- int i;
-
- for (i = 0; i < 8; ++i)
- hw->io_ports_array[i] = base + i * 0x10;
-
- hw->io_ports.ctl_addr = base + 0x160;
-}
-
-/*
- * Attach to a macio probed interface
- */
-static int pmac_ide_macio_attach(struct macio_dev *mdev,
- const struct of_device_id *match)
-{
- void __iomem *base;
- unsigned long regbase;
- pmac_ide_hwif_t *pmif;
- int irq, rc;
- struct ide_hw hw;
-
- pmif = kzalloc(sizeof(*pmif), GFP_KERNEL);
- if (pmif == NULL)
- return -ENOMEM;
-
- if (macio_resource_count(mdev) == 0) {
- printk(KERN_WARNING "ide-pmac: no address for %pOF\n",
- mdev->ofdev.dev.of_node);
- rc = -ENXIO;
- goto out_free_pmif;
- }
-
- /* Request memory resource for IO ports */
- if (macio_request_resource(mdev, 0, "ide-pmac (ports)")) {
- printk(KERN_ERR "ide-pmac: can't request MMIO resource for "
- "%pOF!\n", mdev->ofdev.dev.of_node);
- rc = -EBUSY;
- goto out_free_pmif;
- }
-
- /* XXX This is bogus. Should be fixed in the registry by checking
- * the kind of host interrupt controller, a bit like gatwick
- * fixes in irq.c. That works well enough for the single case
- * where that happens though...
- */
- if (macio_irq_count(mdev) == 0) {
- printk(KERN_WARNING "ide-pmac: no intrs for device %pOF, using "
- "13\n", mdev->ofdev.dev.of_node);
- irq = irq_create_mapping(NULL, 13);
- } else
- irq = macio_irq(mdev, 0);
-
- base = ioremap(macio_resource_start(mdev, 0), 0x400);
- regbase = (unsigned long) base;
-
- pmif->mdev = mdev;
- pmif->node = mdev->ofdev.dev.of_node;
- pmif->regbase = regbase;
- pmif->irq = irq;
- pmif->kauai_fcr = NULL;
-
- if (macio_resource_count(mdev) >= 2) {
- if (macio_request_resource(mdev, 1, "ide-pmac (dma)"))
- printk(KERN_WARNING "ide-pmac: can't request DMA "
- "resource for %pOF!\n",
- mdev->ofdev.dev.of_node);
- else
- pmif->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x1000);
- } else
- pmif->dma_regs = NULL;
-
- dev_set_drvdata(&mdev->ofdev.dev, pmif);
-
- memset(&hw, 0, sizeof(hw));
- pmac_ide_init_ports(&hw, pmif->regbase);
- hw.irq = irq;
- hw.dev = &mdev->bus->pdev->dev;
- hw.parent = &mdev->ofdev.dev;
-
- rc = pmac_ide_setup_device(pmif, &hw);
- if (rc != 0) {
- /* The inteface is released to the common IDE layer */
- dev_set_drvdata(&mdev->ofdev.dev, NULL);
- iounmap(base);
- if (pmif->dma_regs) {
- iounmap(pmif->dma_regs);
- macio_release_resource(mdev, 1);
- }
- macio_release_resource(mdev, 0);
- kfree(pmif);
- }
-
- return rc;
-
-out_free_pmif:
- kfree(pmif);
- return rc;
-}
-
-static int
-pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t mesg)
-{
- pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev);
- int rc = 0;
-
- if (mesg.event != mdev->ofdev.dev.power.power_state.event
- && (mesg.event & PM_EVENT_SLEEP)) {
- rc = pmac_ide_do_suspend(pmif);
- if (rc == 0)
- mdev->ofdev.dev.power.power_state = mesg;
- }
-
- return rc;
-}
-
-static int
-pmac_ide_macio_resume(struct macio_dev *mdev)
-{
- pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev);
- int rc = 0;
-
- if (mdev->ofdev.dev.power.power_state.event != PM_EVENT_ON) {
- rc = pmac_ide_do_resume(pmif);
- if (rc == 0)
- mdev->ofdev.dev.power.power_state = PMSG_ON;
- }
-
- return rc;
-}
-
-/*
- * Attach to a PCI probed interface
- */
-static int pmac_ide_pci_attach(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- struct device_node *np;
- pmac_ide_hwif_t *pmif;
- void __iomem *base;
- unsigned long rbase, rlen;
- int rc;
- struct ide_hw hw;
-
- np = pci_device_to_OF_node(pdev);
- if (np == NULL) {
- printk(KERN_ERR "ide-pmac: cannot find MacIO node for Kauai ATA interface\n");
- return -ENODEV;
- }
-
- pmif = kzalloc(sizeof(*pmif), GFP_KERNEL);
- if (pmif == NULL)
- return -ENOMEM;
-
- if (pci_enable_device(pdev)) {
- printk(KERN_WARNING "ide-pmac: Can't enable PCI device for "
- "%pOF\n", np);
- rc = -ENXIO;
- goto out_free_pmif;
- }
- pci_set_master(pdev);
-
- if (pci_request_regions(pdev, "Kauai ATA")) {
- printk(KERN_ERR "ide-pmac: Cannot obtain PCI resources for "
- "%pOF\n", np);
- rc = -ENXIO;
- goto out_free_pmif;
- }
-
- pmif->mdev = NULL;
- pmif->node = np;
-
- rbase = pci_resource_start(pdev, 0);
- rlen = pci_resource_len(pdev, 0);
-
- base = ioremap(rbase, rlen);
- pmif->regbase = (unsigned long) base + 0x2000;
- pmif->dma_regs = base + 0x1000;
- pmif->kauai_fcr = base;
- pmif->irq = pdev->irq;
-
- pci_set_drvdata(pdev, pmif);
-
- memset(&hw, 0, sizeof(hw));
- pmac_ide_init_ports(&hw, pmif->regbase);
- hw.irq = pdev->irq;
- hw.dev = &pdev->dev;
-
- rc = pmac_ide_setup_device(pmif, &hw);
- if (rc != 0) {
- /* The inteface is released to the common IDE layer */
- iounmap(base);
- pci_release_regions(pdev);
- kfree(pmif);
- }
-
- return rc;
-
-out_free_pmif:
- kfree(pmif);
- return rc;
-}
-
-static int
-pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
-{
- pmac_ide_hwif_t *pmif = pci_get_drvdata(pdev);
- int rc = 0;
-
- if (mesg.event != pdev->dev.power.power_state.event
- && (mesg.event & PM_EVENT_SLEEP)) {
- rc = pmac_ide_do_suspend(pmif);
- if (rc == 0)
- pdev->dev.power.power_state = mesg;
- }
-
- return rc;
-}
-
-static int
-pmac_ide_pci_resume(struct pci_dev *pdev)
-{
- pmac_ide_hwif_t *pmif = pci_get_drvdata(pdev);
- int rc = 0;
-
- if (pdev->dev.power.power_state.event != PM_EVENT_ON) {
- rc = pmac_ide_do_resume(pmif);
- if (rc == 0)
- pdev->dev.power.power_state = PMSG_ON;
- }
-
- return rc;
-}
-
-#ifdef CONFIG_PMAC_MEDIABAY
-static void pmac_ide_macio_mb_event(struct macio_dev* mdev, int mb_state)
-{
- pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev);
-
- switch(mb_state) {
- case MB_CD:
- if (!pmif->hwif->present)
- ide_port_scan(pmif->hwif);
- break;
- default:
- if (pmif->hwif->present)
- ide_port_unregister_devices(pmif->hwif);
- }
-}
-#endif /* CONFIG_PMAC_MEDIABAY */
-
-
-static struct of_device_id pmac_ide_macio_match[] =
-{
- {
- .name = "IDE",
- },
- {
- .name = "ATA",
- },
- {
- .type = "ide",
- },
- {
- .type = "ata",
- },
- {},
-};
-
-static struct macio_driver pmac_ide_macio_driver =
-{
- .driver = {
- .name = "ide-pmac",
- .owner = THIS_MODULE,
- .of_match_table = pmac_ide_macio_match,
- },
- .probe = pmac_ide_macio_attach,
- .suspend = pmac_ide_macio_suspend,
- .resume = pmac_ide_macio_resume,
-#ifdef CONFIG_PMAC_MEDIABAY
- .mediabay_event = pmac_ide_macio_mb_event,
-#endif
-};
-
-static const struct pci_device_id pmac_ide_pci_match[] = {
- { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA), 0 },
- { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100), 0 },
- { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100), 0 },
- { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_SH_ATA), 0 },
- { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA), 0 },
- {},
-};
-
-static struct pci_driver pmac_ide_pci_driver = {
- .name = "ide-pmac",
- .id_table = pmac_ide_pci_match,
- .probe = pmac_ide_pci_attach,
- .suspend = pmac_ide_pci_suspend,
- .resume = pmac_ide_pci_resume,
-};
-MODULE_DEVICE_TABLE(pci, pmac_ide_pci_match);
-
-int __init pmac_ide_probe(void)
-{
- int error;
-
- if (!machine_is(powermac))
- return -ENODEV;
-
-#ifdef CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST
- error = pci_register_driver(&pmac_ide_pci_driver);
- if (error)
- goto out;
- error = macio_register_driver(&pmac_ide_macio_driver);
- if (error) {
- pci_unregister_driver(&pmac_ide_pci_driver);
- goto out;
- }
-#else
- error = macio_register_driver(&pmac_ide_macio_driver);
- if (error)
- goto out;
- error = pci_register_driver(&pmac_ide_pci_driver);
- if (error) {
- macio_unregister_driver(&pmac_ide_macio_driver);
- goto out;
- }
-#endif
-out:
- return error;
-}
-
-/*
- * pmac_ide_build_dmatable builds the DBDMA command list
- * for a transfer and sets the DBDMA channel to point to it.
- */
-static int pmac_ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
- pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
- struct dbdma_cmd *table;
- volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
- struct scatterlist *sg;
- int wr = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
- int i = cmd->sg_nents, count = 0;
-
- /* DMA table is already aligned */
- table = (struct dbdma_cmd *) pmif->dma_table_cpu;
-
- /* Make sure DMA controller is stopped (necessary ?) */
- writel((RUN|PAUSE|FLUSH|WAKE|DEAD) << 16, &dma->control);
- while (readl(&dma->status) & RUN)
- udelay(1);
-
- /* Build DBDMA commands list */
- sg = hwif->sg_table;
- while (i && sg_dma_len(sg)) {
- u32 cur_addr;
- u32 cur_len;
-
- cur_addr = sg_dma_address(sg);
- cur_len = sg_dma_len(sg);
-
- if (pmif->broken_dma && cur_addr & (L1_CACHE_BYTES - 1)) {
- if (pmif->broken_dma_warn == 0) {
- printk(KERN_WARNING "%s: DMA on non aligned address, "
- "switching to PIO on Ohare chipset\n", drive->name);
- pmif->broken_dma_warn = 1;
- }
- return 0;
- }
- while (cur_len) {
- unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
-
- if (count++ >= MAX_DCMDS) {
- printk(KERN_WARNING "%s: DMA table too small\n",
- drive->name);
- return 0;
- }
- table->command = cpu_to_le16(wr? OUTPUT_MORE: INPUT_MORE);
- table->req_count = cpu_to_le16(tc);
- table->phy_addr = cpu_to_le32(cur_addr);
- table->cmd_dep = 0;
- table->xfer_status = 0;
- table->res_count = 0;
- cur_addr += tc;
- cur_len -= tc;
- ++table;
- }
- sg = sg_next(sg);
- i--;
- }
-
- /* convert the last command to an input/output last command */
- if (count) {
- table[-1].command = cpu_to_le16(wr? OUTPUT_LAST: INPUT_LAST);
- /* add the stop command to the end of the list */
- memset(table, 0, sizeof(struct dbdma_cmd));
- table->command = cpu_to_le16(DBDMA_STOP);
- mb();
- writel(hwif->dmatable_dma, &dma->cmdptr);
- return 1;
- }
-
- printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
-
- return 0; /* revert to PIO for this request */
-}
-
-/*
- * Prepare a DMA transfer. We build the DMA table, adjust the timings for
- * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion
- */
-static int pmac_ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
- pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
- u8 unit = drive->dn & 1, ata4 = (pmif->kind == controller_kl_ata4);
- u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
-
- if (pmac_ide_build_dmatable(drive, cmd) == 0)
- return 1;
-
- /* Apple adds 60ns to wrDataSetup on reads */
- if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
- writel(pmif->timings[unit] + (write ? 0 : 0x00800000UL),
- PMAC_IDE_REG(IDE_TIMING_CONFIG));
- (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG));
- }
-
- return 0;
-}
-
-/*
- * Kick the DMA controller into life after the DMA command has been issued
- * to the drive.
- */
-static void
-pmac_ide_dma_start(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
- volatile struct dbdma_regs __iomem *dma;
-
- dma = pmif->dma_regs;
-
- writel((RUN << 16) | RUN, &dma->control);
- /* Make sure it gets to the controller right now */
- (void)readl(&dma->control);
-}
-
-/*
- * After a DMA transfer, make sure the controller is stopped
- */
-static int
-pmac_ide_dma_end (ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
- volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
- u32 dstat;
-
- dstat = readl(&dma->status);
- writel(((RUN|WAKE|DEAD) << 16), &dma->control);
-
- /* verify good dma status. we don't check for ACTIVE beeing 0. We should...
- * in theory, but with ATAPI decices doing buffer underruns, that would
- * cause us to disable DMA, which isn't what we want
- */
- return (dstat & (RUN|DEAD)) != RUN;
-}
-
-/*
- * Check out that the interrupt we got was for us. We can't always know this
- * for sure with those Apple interfaces (well, we could on the recent ones but
- * that's not implemented yet), on the other hand, we don't have shared interrupts
- * so it's not really a problem
- */
-static int
-pmac_ide_dma_test_irq (ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
- volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
- unsigned long status, timeout;
-
- /* We have to things to deal with here:
- *
- * - The dbdma won't stop if the command was started
- * but completed with an error without transferring all
- * datas. This happens when bad blocks are met during
- * a multi-block transfer.
- *
- * - The dbdma fifo hasn't yet finished flushing to
- * to system memory when the disk interrupt occurs.
- *
- */
-
- /* If ACTIVE is cleared, the STOP command have passed and
- * transfer is complete.
- */
- status = readl(&dma->status);
- if (!(status & ACTIVE))
- return 1;
-
- /* If dbdma didn't execute the STOP command yet, the
- * active bit is still set. We consider that we aren't
- * sharing interrupts (which is hopefully the case with
- * those controllers) and so we just try to flush the
- * channel for pending data in the fifo
- */
- udelay(1);
- writel((FLUSH << 16) | FLUSH, &dma->control);
- timeout = 0;
- for (;;) {
- udelay(1);
- status = readl(&dma->status);
- if ((status & FLUSH) == 0)
- break;
- if (++timeout > 100) {
- printk(KERN_WARNING "ide%d, ide_dma_test_irq timeout flushing channel\n",
- hwif->index);
- break;
- }
- }
- return 1;
-}
-
-static void pmac_ide_dma_host_set(ide_drive_t *drive, int on)
-{
-}
-
-static void
-pmac_ide_dma_lost_irq (ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
- volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
- unsigned long status = readl(&dma->status);
-
- printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status);
-}
-
-static const struct ide_dma_ops pmac_dma_ops = {
- .dma_host_set = pmac_ide_dma_host_set,
- .dma_setup = pmac_ide_dma_setup,
- .dma_start = pmac_ide_dma_start,
- .dma_end = pmac_ide_dma_end,
- .dma_test_irq = pmac_ide_dma_test_irq,
- .dma_lost_irq = pmac_ide_dma_lost_irq,
-};
-
-/*
- * Allocate the data structures needed for using DMA with an interface
- * and fill the proper list of functions pointers
- */
-static int pmac_ide_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
- pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent);
- struct pci_dev *dev = to_pci_dev(hwif->dev);
-
- /* We won't need pci_dev if we switch to generic consistent
- * DMA routines ...
- */
- if (dev == NULL || pmif->dma_regs == 0)
- return -ENODEV;
- /*
- * Allocate space for the DBDMA commands.
- * The +2 is +1 for the stop command and +1 to allow for
- * aligning the start address to a multiple of 16 bytes.
- */
- pmif->dma_table_cpu = dma_alloc_coherent(&dev->dev,
- (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
- &hwif->dmatable_dma, GFP_KERNEL);
- if (pmif->dma_table_cpu == NULL) {
- printk(KERN_ERR "%s: unable to allocate DMA command list\n",
- hwif->name);
- return -ENOMEM;
- }
-
- hwif->sg_max_nents = MAX_DCMDS;
-
- return 0;
-}
-
-module_init(pmac_ide_probe);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c
deleted file mode 100644
index ecd0a69245f6..000000000000
--- a/drivers/ide/q40ide.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Q40 I/O port IDE Driver
- *
- * (c) Richard Zidlicky
- *
- * 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.
- *
- *
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/module.h>
-
-#include <asm/ide.h>
-
- /*
- * Bases of the IDE interfaces
- */
-
-#define Q40IDE_NUM_HWIFS 2
-
-#define PCIDE_BASE1 0x1f0
-#define PCIDE_BASE2 0x170
-#define PCIDE_BASE3 0x1e8
-#define PCIDE_BASE4 0x168
-#define PCIDE_BASE5 0x1e0
-#define PCIDE_BASE6 0x160
-
-static const unsigned long pcide_bases[Q40IDE_NUM_HWIFS] = {
- PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4 , PCIDE_BASE5,
- PCIDE_BASE6 */
-};
-
-static int q40ide_default_irq(unsigned long base)
-{
- switch (base) {
- case 0x1f0: return 14;
- case 0x170: return 15;
- case 0x1e8: return 11;
- default:
- return 0;
- }
-}
-
-
-/*
- * Addresses are pretranslated for Q40 ISA access.
- */
-static void q40_ide_setup_ports(struct ide_hw *hw, unsigned long base, int irq)
-{
- memset(hw, 0, sizeof(*hw));
- /* BIG FAT WARNING:
- assumption: only DATA port is ever used in 16 bit mode */
- hw->io_ports.data_addr = Q40_ISA_IO_W(base);
- hw->io_ports.error_addr = Q40_ISA_IO_B(base + 1);
- hw->io_ports.nsect_addr = Q40_ISA_IO_B(base + 2);
- hw->io_ports.lbal_addr = Q40_ISA_IO_B(base + 3);
- hw->io_ports.lbam_addr = Q40_ISA_IO_B(base + 4);
- hw->io_ports.lbah_addr = Q40_ISA_IO_B(base + 5);
- hw->io_ports.device_addr = Q40_ISA_IO_B(base + 6);
- hw->io_ports.status_addr = Q40_ISA_IO_B(base + 7);
- hw->io_ports.ctl_addr = Q40_ISA_IO_B(base + 0x206);
-
- hw->irq = irq;
-}
-
-static void q40ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
- void *buf, unsigned int len)
-{
- unsigned long data_addr = drive->hwif->io_ports.data_addr;
-
- if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
- __ide_mm_insw(data_addr, buf, (len + 1) / 2);
- return;
- }
-
- raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
-}
-
-static void q40ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
- void *buf, unsigned int len)
-{
- unsigned long data_addr = drive->hwif->io_ports.data_addr;
-
- if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
- __ide_mm_outsw(data_addr, buf, (len + 1) / 2);
- return;
- }
-
- raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
-}
-
-/* Q40 has a byte-swapped IDE interface */
-static const struct ide_tp_ops q40ide_tp_ops = {
- .exec_command = ide_exec_command,
- .read_status = ide_read_status,
- .read_altstatus = ide_read_altstatus,
- .write_devctl = ide_write_devctl,
-
- .dev_select = ide_dev_select,
- .tf_load = ide_tf_load,
- .tf_read = ide_tf_read,
-
- .input_data = q40ide_input_data,
- .output_data = q40ide_output_data,
-};
-
-static const struct ide_port_info q40ide_port_info = {
- .tp_ops = &q40ide_tp_ops,
- .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
- .irq_flags = IRQF_SHARED,
- .chipset = ide_generic,
-};
-
-/*
- * the static array is needed to have the name reported in /proc/ioports,
- * hwif->name unfortunately isn't available yet
- */
-static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
- "ide0", "ide1"
-};
-
-/*
- * Probe for Q40 IDE interfaces
- */
-
-static int __init q40ide_init(void)
-{
- int i;
- struct ide_hw hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL };
-
- if (!MACH_IS_Q40)
- return -ENODEV;
-
- printk(KERN_INFO "ide: Q40 IDE controller\n");
-
- for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
- const char *name = q40_ide_names[i];
-
- if (!request_region(pcide_bases[i], 8, name)) {
- printk("could not reserve ports %lx-%lx for %s\n",
- pcide_bases[i],pcide_bases[i]+8,name);
- continue;
- }
- if (!request_region(pcide_bases[i]+0x206, 1, name)) {
- printk("could not reserve port %lx for %s\n",
- pcide_bases[i]+0x206,name);
- release_region(pcide_bases[i], 8);
- continue;
- }
- q40_ide_setup_ports(&hw[i], pcide_bases[i],
- q40ide_default_irq(pcide_bases[i]));
-
- hws[i] = &hw[i];
- }
-
- return ide_host_add(&q40ide_port_info, hws, Q40IDE_NUM_HWIFS, NULL);
-}
-
-module_init(q40ide_init);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c
deleted file mode 100644
index ab79b6289464..000000000000
--- a/drivers/ide/qd65xx.c
+++ /dev/null
@@ -1,446 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1996-2001 Linus Torvalds & author (see below)
- */
-
-/*
- * Version 0.03 Cleaned auto-tune, added probe
- * Version 0.04 Added second channel tuning
- * Version 0.05 Enhanced tuning ; added qd6500 support
- * Version 0.06 Added dos driver's list
- * Version 0.07 Second channel bug fix
- *
- * QDI QD6500/QD6580 EIDE controller fast support
- *
- * To activate controller support, use "ide0=qd65xx"
- */
-
-/*
- * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
- * Samuel Thibault <samuel.thibault@ens-lyon.org>
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <asm/io.h>
-
-#define DRV_NAME "qd65xx"
-
-#include "qd65xx.h"
-
-/*
- * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580)
- * or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580)
- * -- qd6500 is a single IDE interface
- * -- qd6580 is a dual IDE interface
- *
- * More research on qd6580 being done by willmore@cig.mot.com (David)
- * More Information given by Petr Soucek (petr@ryston.cz)
- * http://www.ryston.cz/petr/vlb
- */
-
-/*
- * base: Timer1
- *
- *
- * base+0x01: Config (R/O)
- *
- * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500)
- * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30
- * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
- * bit 3: qd6500: 1 = disabled, 0 = enabled
- * qd6580: 1
- * upper nibble:
- * qd6500: 1100
- * qd6580: either 1010 or 0101
- *
- *
- * base+0x02: Timer2 (qd6580 only)
- *
- *
- * base+0x03: Control (qd6580 only)
- *
- * bits 0-3 must always be set 1
- * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
- * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
- * 0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
- * channel 1 for hdc & hdd
- * bit 1 : 1 = only disks on primary port
- * 0 = disks & ATAPI devices on primary port
- * bit 2-4 : always 0
- * bit 5 : status, but of what ?
- * bit 6 : always set 1 by dos driver
- * bit 7 : set 1 for non-ATAPI devices on primary port
- * (maybe read-ahead and post-write buffer ?)
- */
-
-static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
-
-/*
- * qd65xx_select:
- *
- * This routine is invoked to prepare for access to a given drive.
- */
-
-static void qd65xx_dev_select(ide_drive_t *drive)
-{
- u8 index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) |
- (QD_TIMREG(drive) & 0x02);
-
- if (timings[index] != QD_TIMING(drive))
- outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
-
- outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
-}
-
-/*
- * qd6500_compute_timing
- *
- * computes the timing value where
- * lower nibble represents active time, in count of VLB clocks
- * upper nibble represents recovery time, in count of VLB clocks
- */
-
-static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
-{
- int clk = ide_vlb_clk ? ide_vlb_clk : 50;
- u8 act_cyc, rec_cyc;
-
- if (clk <= 33) {
- act_cyc = 9 - IDE_IN(active_time * clk / 1000 + 1, 2, 9);
- rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 0, 15);
- } else {
- act_cyc = 8 - IDE_IN(active_time * clk / 1000 + 1, 1, 8);
- rec_cyc = 18 - IDE_IN(recovery_time * clk / 1000 + 1, 3, 18);
- }
-
- return (rec_cyc << 4) | 0x08 | act_cyc;
-}
-
-/*
- * qd6580_compute_timing
- *
- * idem for qd6580
- */
-
-static u8 qd6580_compute_timing (int active_time, int recovery_time)
-{
- int clk = ide_vlb_clk ? ide_vlb_clk : 50;
- u8 act_cyc, rec_cyc;
-
- act_cyc = 17 - IDE_IN(active_time * clk / 1000 + 1, 2, 17);
- rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 2, 15);
-
- return (rec_cyc << 4) | act_cyc;
-}
-
-/*
- * qd_find_disk_type
- *
- * tries to find timing from dos driver's table
- */
-
-static int qd_find_disk_type (ide_drive_t *drive,
- int *active_time, int *recovery_time)
-{
- struct qd65xx_timing_s *p;
- char *m = (char *)&drive->id[ATA_ID_PROD];
- char model[ATA_ID_PROD_LEN];
-
- if (*m == 0)
- return 0;
-
- strncpy(model, m, ATA_ID_PROD_LEN);
- ide_fixstring(model, ATA_ID_PROD_LEN, 1); /* byte-swap */
-
- for (p = qd65xx_timing ; p->offset != -1 ; p++) {
- if (!strncmp(p->model, model+p->offset, 4)) {
- printk(KERN_DEBUG "%s: listed !\n", drive->name);
- *active_time = p->active;
- *recovery_time = p->recovery;
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * qd_set_timing:
- *
- * records the timing
- */
-
-static void qd_set_timing (ide_drive_t *drive, u8 timing)
-{
- unsigned long data = (unsigned long)ide_get_drivedata(drive);
-
- data &= 0xff00;
- data |= timing;
- ide_set_drivedata(drive, (void *)data);
-
- printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
-}
-
-static void qd6500_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- u16 *id = drive->id;
- int active_time = 175;
- int recovery_time = 415; /* worst case values from the dos driver */
-
- /* FIXME: use drive->pio_mode value */
- if (!qd_find_disk_type(drive, &active_time, &recovery_time) &&
- (id[ATA_ID_OLD_PIO_MODES] & 0xff) && (id[ATA_ID_FIELD_VALID] & 2) &&
- id[ATA_ID_EIDE_PIO] >= 240) {
- printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
- id[ATA_ID_OLD_PIO_MODES] & 0xff);
- active_time = 110;
- recovery_time = drive->id[ATA_ID_EIDE_PIO] - 120;
- }
-
- qd_set_timing(drive, qd6500_compute_timing(drive->hwif,
- active_time, recovery_time));
-}
-
-static void qd6580_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- const u8 pio = drive->pio_mode - XFER_PIO_0;
- struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
- unsigned int cycle_time;
- int active_time = 175;
- int recovery_time = 415; /* worst case values from the dos driver */
- u8 base = (hwif->config_data & 0xff00) >> 8;
-
- if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
- cycle_time = ide_pio_cycle_time(drive, pio);
-
- switch (pio) {
- case 0: break;
- case 3:
- if (cycle_time >= 110) {
- active_time = 86;
- recovery_time = cycle_time - 102;
- } else
- printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
- break;
- case 4:
- if (cycle_time >= 69) {
- active_time = 70;
- recovery_time = cycle_time - 61;
- } else
- printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
- break;
- default:
- if (cycle_time >= 180) {
- active_time = 110;
- recovery_time = cycle_time - 120;
- } else {
- active_time = t->active;
- recovery_time = cycle_time - active_time;
- }
- }
- printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
- }
-
- if (!hwif->channel && drive->media != ide_disk) {
- outb(0x5f, QD_CONTROL_PORT);
- printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO "
- "and post-write buffer on %s.\n",
- drive->name, hwif->name);
- }
-
- qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time));
-}
-
-/*
- * qd_testreg
- *
- * tests if the given port is a register
- */
-
-static int __init qd_testreg(int port)
-{
- unsigned long flags;
- u8 savereg, readreg;
-
- local_irq_save(flags);
- savereg = inb_p(port);
- outb_p(QD_TESTVAL, port); /* safe value */
- readreg = inb_p(port);
- outb(savereg, port);
- local_irq_restore(flags);
-
- if (savereg == QD_TESTVAL) {
- printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
- printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
- printk(KERN_ERR "Assuming qd65xx is not present.\n");
- return 1;
- }
-
- return (readreg != QD_TESTVAL);
-}
-
-static void __init qd6500_init_dev(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 base = (hwif->config_data & 0xff00) >> 8;
- u8 config = QD_CONFIG(hwif);
-
- ide_set_drivedata(drive, (void *)QD6500_DEF_DATA);
-}
-
-static void __init qd6580_init_dev(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- unsigned long t1, t2;
- u8 base = (hwif->config_data & 0xff00) >> 8;
- u8 config = QD_CONFIG(hwif);
-
- if (hwif->host_flags & IDE_HFLAG_SINGLE) {
- t1 = QD6580_DEF_DATA;
- t2 = QD6580_DEF_DATA2;
- } else
- t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA;
-
- ide_set_drivedata(drive, (void *)((drive->dn & 1) ? t2 : t1));
-}
-
-static const struct ide_tp_ops qd65xx_tp_ops = {
- .exec_command = ide_exec_command,
- .read_status = ide_read_status,
- .read_altstatus = ide_read_altstatus,
- .write_devctl = ide_write_devctl,
-
- .dev_select = qd65xx_dev_select,
- .tf_load = ide_tf_load,
- .tf_read = ide_tf_read,
-
- .input_data = ide_input_data,
- .output_data = ide_output_data,
-};
-
-static const struct ide_port_ops qd6500_port_ops = {
- .init_dev = qd6500_init_dev,
- .set_pio_mode = qd6500_set_pio_mode,
-};
-
-static const struct ide_port_ops qd6580_port_ops = {
- .init_dev = qd6580_init_dev,
- .set_pio_mode = qd6580_set_pio_mode,
-};
-
-static const struct ide_port_info qd65xx_port_info __initconst = {
- .name = DRV_NAME,
- .tp_ops = &qd65xx_tp_ops,
- .chipset = ide_qd65xx,
- .host_flags = IDE_HFLAG_IO_32BIT |
- IDE_HFLAG_NO_DMA,
- .pio_mask = ATA_PIO4,
-};
-
-/*
- * qd_probe:
- *
- * looks at the specified baseport, and if qd found, registers & initialises it
- * return 1 if another qd may be probed
- */
-
-static int __init qd_probe(int base)
-{
- int rc;
- u8 config, unit, control;
- struct ide_port_info d = qd65xx_port_info;
-
- config = inb(QD_CONFIG_PORT);
-
- if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) )
- return -ENODEV;
-
- unit = ! (config & QD_CONFIG_IDE_BASEPORT);
-
- if (unit)
- d.host_flags |= IDE_HFLAG_QD_2ND_PORT;
-
- switch (config & 0xf0) {
- case QD_CONFIG_QD6500:
- if (qd_testreg(base))
- return -ENODEV; /* bad register */
-
- if (config & QD_CONFIG_DISABLED) {
- printk(KERN_WARNING "qd6500 is disabled !\n");
- return -ENODEV;
- }
-
- printk(KERN_NOTICE "qd6500 at %#x\n", base);
- printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
- config, QD_ID3);
-
- d.port_ops = &qd6500_port_ops;
- d.host_flags |= IDE_HFLAG_SINGLE;
- break;
- case QD_CONFIG_QD6580_A:
- case QD_CONFIG_QD6580_B:
- if (qd_testreg(base) || qd_testreg(base + 0x02))
- return -ENODEV; /* bad registers */
-
- control = inb(QD_CONTROL_PORT);
-
- printk(KERN_NOTICE "qd6580 at %#x\n", base);
- printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
- config, control, QD_ID3);
-
- outb(QD_DEF_CONTR, QD_CONTROL_PORT);
-
- d.port_ops = &qd6580_port_ops;
- if (control & QD_CONTR_SEC_DISABLED)
- d.host_flags |= IDE_HFLAG_SINGLE;
-
- printk(KERN_INFO "qd6580: %s IDE board\n",
- (control & QD_CONTR_SEC_DISABLED) ? "single" : "dual");
- break;
- default:
- return -ENODEV;
- }
-
- rc = ide_legacy_device_add(&d, (base << 8) | config);
-
- if (d.host_flags & IDE_HFLAG_SINGLE)
- return (rc == 0) ? 1 : rc;
-
- return rc;
-}
-
-static bool probe_qd65xx;
-
-module_param_named(probe, probe_qd65xx, bool, 0);
-MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
-
-static int __init qd65xx_init(void)
-{
- int rc1, rc2 = -ENODEV;
-
- if (probe_qd65xx == 0)
- return -ENODEV;
-
- rc1 = qd_probe(0x30);
- if (rc1)
- rc2 = qd_probe(0xb0);
-
- if (rc1 < 0 && rc2 < 0)
- return -ENODEV;
-
- return 0;
-}
-
-module_init(qd65xx_init);
-
-MODULE_AUTHOR("Samuel Thibault");
-MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/qd65xx.h b/drivers/ide/qd65xx.h
deleted file mode 100644
index 01a43ab45e0e..000000000000
--- a/drivers/ide/qd65xx.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2000 Linus Torvalds & authors
- */
-
-/*
- * Authors: Petr Soucek <petr@ryston.cz>
- * Samuel Thibault <samuel.thibault@ens-lyon.org>
- */
-
-/* truncates a in [b,c] */
-#define IDE_IN(a,b,c) ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) )
-
-#define IDE_IMPLY(a,b) ((!(a)) || (b))
-
-#define QD_TIM1_PORT (base)
-#define QD_CONFIG_PORT (base+0x01)
-#define QD_TIM2_PORT (base+0x02)
-#define QD_CONTROL_PORT (base+0x03)
-
-#define QD_CONFIG_IDE_BASEPORT 0x01
-#define QD_CONFIG_BASEPORT 0x02
-#define QD_CONFIG_ID3 0x04
-#define QD_CONFIG_DISABLED 0x08
-#define QD_CONFIG_QD6500 0xc0
-#define QD_CONFIG_QD6580_A 0xa0
-#define QD_CONFIG_QD6580_B 0x50
-
-#define QD_CONTR_SEC_DISABLED 0x01
-
-#define QD_ID3 ((config & QD_CONFIG_ID3)!=0)
-
-#define QD_CONFIG(hwif) ((hwif)->config_data & 0x00ff)
-
-static inline u8 QD_TIMING(ide_drive_t *drive)
-{
- return (unsigned long)ide_get_drivedata(drive) & 0x00ff;
-}
-
-static inline u8 QD_TIMREG(ide_drive_t *drive)
-{
- return ((unsigned long)ide_get_drivedata(drive) & 0xff00) >> 8;
-}
-
-#define QD6500_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
-#define QD6580_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
-#define QD6580_DEF_DATA2 ((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
-#define QD_DEF_CONTR (0x40 | ((control & 0x02) ? 0x9f : 0x1f))
-
-#define QD_TESTVAL 0x19 /* safe value */
-
-/* Drive specific timing taken from DOS driver v3.7 */
-
-static struct qd65xx_timing_s {
- s8 offset; /* ofset from the beginning of Model Number" */
- char model[4]; /* 4 chars from Model number, no conversion */
- s16 active; /* active time */
- s16 recovery; /* recovery time */
-} qd65xx_timing [] = {
- { 30, "2040", 110, 225 }, /* Conner CP30204 */
- { 30, "2045", 135, 225 }, /* Conner CP30254 */
- { 30, "1040", 155, 325 }, /* Conner CP30104 */
- { 30, "1047", 135, 265 }, /* Conner CP30174 */
- { 30, "5344", 135, 225 }, /* Conner CP3544 */
- { 30, "01 4", 175, 405 }, /* Conner CP-3104 */
- { 27, "C030", 175, 375 }, /* Conner CP3000 */
- { 8, "PL42", 110, 295 }, /* Quantum LP240 */
- { 8, "PL21", 110, 315 }, /* Quantum LP120 */
- { 8, "PL25", 175, 385 }, /* Quantum LP52 */
- { 4, "PA24", 110, 285 }, /* WD Piranha SP4200 */
- { 6, "2200", 110, 260 }, /* WD Caviar AC2200 */
- { 6, "3204", 110, 235 }, /* WD Caviar AC2340 */
- { 6, "1202", 110, 265 }, /* WD Caviar AC2120 */
- { 0, "DS3-", 135, 315 }, /* Teac SD340 */
- { 8, "KM32", 175, 355 }, /* Toshiba MK234 */
- { 2, "53A1", 175, 355 }, /* Seagate ST351A */
- { 2, "4108", 175, 295 }, /* Seagate ST1480A */
- { 2, "1344", 175, 335 }, /* Seagate ST3144A */
- { 6, "7 12", 110, 225 }, /* Maxtor 7213A */
- { 30, "02F4", 145, 295 }, /* Conner 3204F */
- { 2, "1302", 175, 335 }, /* Seagate ST3120A */
- { 2, "2334", 145, 265 }, /* Seagate ST3243A */
- { 2, "2338", 145, 275 }, /* Seagate ST3283A */
- { 2, "3309", 145, 275 }, /* Seagate ST3390A */
- { 2, "5305", 145, 275 }, /* Seagate ST3550A */
- { 2, "4100", 175, 295 }, /* Seagate ST1400A */
- { 2, "4110", 175, 295 }, /* Seagate ST1401A */
- { 2, "6300", 135, 265 }, /* Seagate ST3600A */
- { 2, "5300", 135, 265 }, /* Seagate ST3500A */
- { 6, "7 31", 135, 225 }, /* Maxtor 7131 AT */
- { 6, "7 43", 115, 265 }, /* Maxtor 7345 AT */
- { 6, "7 42", 110, 255 }, /* Maxtor 7245 AT */
- { 6, "3 04", 135, 265 }, /* Maxtor 340 AT */
- { 6, "61 0", 135, 285 }, /* WD AC160 */
- { 6, "1107", 135, 235 }, /* WD AC1170 */
- { 6, "2101", 110, 220 }, /* WD AC1210 */
- { 6, "4202", 135, 245 }, /* WD AC2420 */
- { 6, "41 0", 175, 355 }, /* WD Caviar 140 */
- { 6, "82 0", 175, 355 }, /* WD Caviar 280 */
- { 8, "PL01", 175, 375 }, /* Quantum LP105 */
- { 8, "PL25", 110, 295 }, /* Quantum LP525 */
- { 10, "4S 2", 175, 385 }, /* Quantum ELS42 */
- { 10, "8S 5", 175, 385 }, /* Quantum ELS85 */
- { 10, "1S72", 175, 385 }, /* Quantum ELS127 */
- { 10, "1S07", 175, 385 }, /* Quantum ELS170 */
- { 8, "ZE42", 135, 295 }, /* Quantum EZ240 */
- { 8, "ZE21", 175, 385 }, /* Quantum EZ127 */
- { 8, "ZE58", 175, 385 }, /* Quantum EZ85 */
- { 8, "ZE24", 175, 385 }, /* Quantum EZ42 */
- { 27, "C036", 155, 325 }, /* Conner CP30064 */
- { 27, "C038", 155, 325 }, /* Conner CP30084 */
- { 6, "2205", 110, 255 }, /* WDC AC2250 */
- { 2, " CHA", 140, 415 }, /* WDC AH series; WDC AH260, WDC */
- { 2, " CLA", 140, 415 }, /* WDC AL series: WDC AL2120, 2170, */
- { 4, "UC41", 140, 415 }, /* WDC CU140 */
- { 6, "1207", 130, 275 }, /* WDC AC2170 */
- { 6, "2107", 130, 275 }, /* WDC AC1270 */
- { 6, "5204", 130, 275 }, /* WDC AC2540 */
- { 30, "3004", 110, 235 }, /* Conner CP30340 */
- { 30, "0345", 135, 255 }, /* Conner CP30544 */
- { 12, "12A3", 175, 320 }, /* MAXTOR LXT-213A */
- { 12, "43A0", 145, 240 }, /* MAXTOR LXT-340A */
- { 6, "7 21", 180, 290 }, /* Maxtor 7120 AT */
- { 6, "7 71", 135, 240 }, /* Maxtor 7170 AT */
- { 12, "45\0000", 110, 205 }, /* MAXTOR MXT-540 */
- { 8, "PL11", 180, 290 }, /* QUANTUM LP110A */
- { 8, "OG21", 150, 275 }, /* QUANTUM GO120 */
- { 12, "42A5", 175, 320 }, /* MAXTOR LXT-245A */
- { 2, "2309", 175, 295 }, /* ST3290A */
- { 2, "3358", 180, 310 }, /* ST3385A */
- { 2, "6355", 180, 310 }, /* ST3655A */
- { 2, "1900", 175, 270 }, /* ST9100A */
- { 2, "1954", 175, 270 }, /* ST9145A */
- { 2, "1909", 175, 270 }, /* ST9190AG */
- { 2, "2953", 175, 270 }, /* ST9235A */
- { 2, "1359", 175, 270 }, /* ST3195A */
- { 24, "3R11", 175, 290 }, /* ALPS ELECTRIC Co.,LTD, DR311C */
- { 0, "2M26", 175, 215 }, /* M262XT-0Ah */
- { 4, "2253", 175, 300 }, /* HP C2235A */
- { 4, "-32A", 145, 245 }, /* H3133-A2 */
- { 30, "0326", 150, 270 }, /* Samsung Electronics 120MB */
- { 30, "3044", 110, 195 }, /* Conner CFA340A */
- { 30, "43A0", 110, 195 }, /* Conner CFA340A */
- { -1, " ", 175, 415 } /* unknown disk name */
-};
diff --git a/drivers/ide/rapide.c b/drivers/ide/rapide.c
deleted file mode 100644
index 0ab8b86b7ed7..000000000000
--- a/drivers/ide/rapide.c
+++ /dev/null
@@ -1,106 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 1996-2002 Russell King.
- */
-
-#include <linux/module.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/ecard.h>
-
-static const struct ide_port_info rapide_port_info = {
- .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
- .chipset = ide_generic,
-};
-
-static void rapide_setup_ports(struct ide_hw *hw, void __iomem *base,
- void __iomem *ctrl, unsigned int sz, int irq)
-{
- unsigned long port = (unsigned long)base;
- int i;
-
- for (i = 0; i <= 7; i++) {
- hw->io_ports_array[i] = port;
- port += sz;
- }
- hw->io_ports.ctl_addr = (unsigned long)ctrl;
- hw->irq = irq;
-}
-
-static int rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
- void __iomem *base;
- struct ide_host *host;
- int ret;
- struct ide_hw hw, *hws[] = { &hw };
-
- ret = ecard_request_resources(ec);
- if (ret)
- goto out;
-
- base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
- if (!base) {
- ret = -ENOMEM;
- goto release;
- }
-
- memset(&hw, 0, sizeof(hw));
- rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq);
- hw.dev = &ec->dev;
-
- ret = ide_host_add(&rapide_port_info, hws, 1, &host);
- if (ret)
- goto release;
-
- ecard_set_drvdata(ec, host);
- goto out;
-
- release:
- ecard_release_resources(ec);
- out:
- return ret;
-}
-
-static void rapide_remove(struct expansion_card *ec)
-{
- struct ide_host *host = ecard_get_drvdata(ec);
-
- ecard_set_drvdata(ec, NULL);
-
- ide_host_remove(host);
-
- ecard_release_resources(ec);
-}
-
-static struct ecard_id rapide_ids[] = {
- { MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
- { 0xffff, 0xffff }
-};
-
-static struct ecard_driver rapide_driver = {
- .probe = rapide_probe,
- .remove = rapide_remove,
- .id_table = rapide_ids,
- .drv = {
- .name = "rapide",
- },
-};
-
-static int __init rapide_init(void)
-{
- return ecard_register_driver(&rapide_driver);
-}
-
-static void __exit rapide_exit(void)
-{
- ecard_remove_driver(&rapide_driver);
-}
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Yellowstone RAPIDE driver");
-
-module_init(rapide_init);
-module_exit(rapide_exit);
diff --git a/drivers/ide/rz1000.c b/drivers/ide/rz1000.c
deleted file mode 100644
index fce2b7de5a19..000000000000
--- a/drivers/ide/rz1000.c
+++ /dev/null
@@ -1,100 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1995-1998 Linus Torvalds & author (see below)
- */
-
-/*
- * Principal Author: mlord@pobox.com (Mark Lord)
- *
- * See linux/MAINTAINERS for address of current maintainer.
- *
- * This file provides support for disabling the buggy read-ahead
- * mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
- *
- * Dunno if this fixes both ports, or only the primary port (?).
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "rz1000"
-
-static int rz1000_disable_readahead(struct pci_dev *dev)
-{
- u16 reg;
-
- if (!pci_read_config_word (dev, 0x40, &reg) &&
- !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
- printk(KERN_INFO "%s: disabled chipset read-ahead "
- "(buggy RZ1000/RZ1001)\n", pci_name(dev));
- return 0;
- } else {
- printk(KERN_INFO "%s: serialized, disabled unmasking "
- "(buggy RZ1000/RZ1001)\n", pci_name(dev));
- return 1;
- }
-}
-
-static const struct ide_port_info rz1000_chipset = {
- .name = DRV_NAME,
- .host_flags = IDE_HFLAG_NO_DMA,
-};
-
-static int rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct ide_port_info d = rz1000_chipset;
- int rc;
-
- rc = pci_enable_device(dev);
- if (rc)
- return rc;
-
- if (rz1000_disable_readahead(dev)) {
- d.host_flags |= IDE_HFLAG_SERIALIZE;
- d.host_flags |= IDE_HFLAG_NO_UNMASK_IRQS;
- }
-
- return ide_pci_init_one(dev, &d, NULL);
-}
-
-static void rz1000_remove(struct pci_dev *dev)
-{
- ide_pci_remove(dev);
- pci_disable_device(dev);
-}
-
-static const struct pci_device_id rz1000_pci_tbl[] = {
- { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), 0 },
- { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), 0 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl);
-
-static struct pci_driver rz1000_pci_driver = {
- .name = "RZ1000_IDE",
- .id_table = rz1000_pci_tbl,
- .probe = rz1000_init_one,
- .remove = rz1000_remove,
-};
-
-static int __init rz1000_ide_init(void)
-{
- return ide_pci_register_driver(&rz1000_pci_driver);
-}
-
-static void __exit rz1000_ide_exit(void)
-{
- pci_unregister_driver(&rz1000_pci_driver);
-}
-
-module_init(rz1000_ide_init);
-module_exit(rz1000_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for RZ1000 IDE");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/ide/sc1200.c b/drivers/ide/sc1200.c
deleted file mode 100644
index a5b701818405..000000000000
--- a/drivers/ide/sc1200.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Copyright (C) 2000-2002 Mark Lord <mlord@pobox.com>
- * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- * Development of this chipset driver was funded
- * by the nice folks at National Semiconductor.
- *
- * Documentation:
- * Available from National Semiconductor
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <linux/pm.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "sc1200"
-
-#define SC1200_REV_A 0x00
-#define SC1200_REV_B1 0x01
-#define SC1200_REV_B3 0x02
-#define SC1200_REV_C1 0x03
-#define SC1200_REV_D1 0x04
-
-#define PCI_CLK_33 0x00
-#define PCI_CLK_48 0x01
-#define PCI_CLK_66 0x02
-#define PCI_CLK_33A 0x03
-
-static unsigned short sc1200_get_pci_clock (void)
-{
- unsigned char chip_id, silicon_revision;
- unsigned int pci_clock;
- /*
- * Check the silicon revision, as not all versions of the chip
- * have the register with the fast PCI bus timings.
- */
- chip_id = inb (0x903c);
- silicon_revision = inb (0x903d);
-
- // Read the fast pci clock frequency
- if (chip_id == 0x04 && silicon_revision < SC1200_REV_B1) {
- pci_clock = PCI_CLK_33;
- } else {
- // check clock generator configuration (cfcc)
- // the clock is in bits 8 and 9 of this word
-
- pci_clock = inw (0x901e);
- pci_clock >>= 8;
- pci_clock &= 0x03;
- if (pci_clock == PCI_CLK_33A)
- pci_clock = PCI_CLK_33;
- }
- return pci_clock;
-}
-
-/*
- * Here are the standard PIO mode 0-4 timings for each "format".
- * Format-0 uses fast data reg timings, with slower command reg timings.
- * Format-1 uses fast timings for all registers, but won't work with all drives.
- */
-static const unsigned int sc1200_pio_timings[4][5] =
- {{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, // format0 33Mhz
- {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}, // format1, 33Mhz
- {0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021}, // format1, 48Mhz
- {0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131}}; // format1, 66Mhz
-
-/*
- * After chip reset, the PIO timings are set to 0x00009172, which is not valid.
- */
-//#define SC1200_BAD_PIO(timings) (((timings)&~0x80000000)==0x00009172)
-
-static void sc1200_tunepio(ide_drive_t *drive, u8 pio)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *pdev = to_pci_dev(hwif->dev);
- unsigned int basereg = hwif->channel ? 0x50 : 0x40, format = 0;
-
- pci_read_config_dword(pdev, basereg + 4, &format);
- format = (format >> 31) & 1;
- if (format)
- format += sc1200_get_pci_clock();
- pci_write_config_dword(pdev, basereg + ((drive->dn & 1) << 3),
- sc1200_pio_timings[format][pio]);
-}
-
-/*
- * The SC1200 specifies that two drives sharing a cable cannot mix
- * UDMA/MDMA. It has to be one or the other, for the pair, though
- * different timings can still be chosen for each drive. We could
- * set the appropriate timing bits on the fly, but that might be
- * a bit confusing. So, for now we statically handle this requirement
- * by looking at our mate drive to see what it is capable of, before
- * choosing a mode for our own drive.
- */
-static u8 sc1200_udma_filter(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- ide_drive_t *mate = ide_get_pair_dev(drive);
- u16 *mateid;
- u8 mask = hwif->ultra_mask;
-
- if (mate == NULL)
- goto out;
- mateid = mate->id;
-
- if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) {
- if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
- (mateid[ATA_ID_UDMA_MODES] & 7))
- goto out;
- if (mateid[ATA_ID_MWDMA_MODES] & 7)
- mask = 0;
- }
-out:
- return mask;
-}
-
-static void sc1200_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned int reg, timings;
- unsigned short pci_clock;
- unsigned int basereg = hwif->channel ? 0x50 : 0x40;
- const u8 mode = drive->dma_mode;
-
- static const u32 udma_timing[3][3] = {
- { 0x00921250, 0x00911140, 0x00911030 },
- { 0x00932470, 0x00922260, 0x00922140 },
- { 0x009436a1, 0x00933481, 0x00923261 },
- };
-
- static const u32 mwdma_timing[3][3] = {
- { 0x00077771, 0x00012121, 0x00002020 },
- { 0x000bbbb2, 0x00024241, 0x00013131 },
- { 0x000ffff3, 0x00035352, 0x00015151 },
- };
-
- pci_clock = sc1200_get_pci_clock();
-
- /*
- * Note that each DMA mode has several timings associated with it.
- * The correct timing depends on the fast PCI clock freq.
- */
-
- if (mode >= XFER_UDMA_0)
- timings = udma_timing[pci_clock][mode - XFER_UDMA_0];
- else
- timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0];
-
- if ((drive->dn & 1) == 0) {
- pci_read_config_dword(dev, basereg + 4, &reg);
- timings |= reg & 0x80000000; /* preserve PIO format bit */
- pci_write_config_dword(dev, basereg + 4, timings);
- } else
- pci_write_config_dword(dev, basereg + 12, timings);
-}
-
-/* Replacement for the standard ide_dma_end action in
- * dma_proc.
- *
- * returns 1 on error, 0 otherwise
- */
-static int sc1200_dma_end(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- unsigned long dma_base = hwif->dma_base;
- u8 dma_stat;
-
- dma_stat = inb(dma_base+2); /* get DMA status */
-
- if (!(dma_stat & 4))
- printk(" ide_dma_end dma_stat=%0x err=%x newerr=%x\n",
- dma_stat, ((dma_stat&7)!=4), ((dma_stat&2)==2));
-
- outb(dma_stat|0x1b, dma_base+2); /* clear the INTR & ERROR bits */
- outb(inb(dma_base)&~1, dma_base); /* !! DO THIS HERE !! stop DMA */
-
- return (dma_stat & 7) != 4; /* verify good DMA status */
-}
-
-/*
- * sc1200_set_pio_mode() handles setting of PIO modes
- * for both the chipset and drive.
- *
- * All existing BIOSs for this chipset guarantee that all drives
- * will have valid default PIO timings set up before we get here.
- */
-
-static void sc1200_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- int mode = -1;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
-
- /*
- * bad abuse of ->set_pio_mode interface
- */
- switch (pio) {
- case 200: mode = XFER_UDMA_0; break;
- case 201: mode = XFER_UDMA_1; break;
- case 202: mode = XFER_UDMA_2; break;
- case 100: mode = XFER_MW_DMA_0; break;
- case 101: mode = XFER_MW_DMA_1; break;
- case 102: mode = XFER_MW_DMA_2; break;
- }
- if (mode != -1) {
- printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
- ide_dma_off_quietly(drive);
- if (ide_set_dma_mode(drive, mode) == 0 &&
- (drive->dev_flags & IDE_DFLAG_USING_DMA))
- hwif->dma_ops->dma_host_set(drive, 1);
- return;
- }
-
- sc1200_tunepio(drive, pio);
-}
-
-#ifdef CONFIG_PM
-struct sc1200_saved_state {
- u32 regs[8];
-};
-
-static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
-{
- printk("SC1200: suspend(%u)\n", state.event);
-
- /*
- * we only save state when going from full power to less
- */
- if (state.event == PM_EVENT_ON) {
- struct ide_host *host = pci_get_drvdata(dev);
- struct sc1200_saved_state *ss = host->host_priv;
- unsigned int r;
-
- /*
- * save timing registers
- * (this may be unnecessary if BIOS also does it)
- */
- for (r = 0; r < 8; r++)
- pci_read_config_dword(dev, 0x40 + r * 4, &ss->regs[r]);
- }
-
- pci_disable_device(dev);
- pci_set_power_state(dev, pci_choose_state(dev, state));
- return 0;
-}
-
-static int sc1200_resume (struct pci_dev *dev)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- struct sc1200_saved_state *ss = host->host_priv;
- unsigned int r;
- int i;
-
- i = pci_enable_device(dev);
- if (i)
- return i;
-
- /*
- * restore timing registers
- * (this may be unnecessary if BIOS also does it)
- */
- for (r = 0; r < 8; r++)
- pci_write_config_dword(dev, 0x40 + r * 4, ss->regs[r]);
-
- return 0;
-}
-#endif
-
-static const struct ide_port_ops sc1200_port_ops = {
- .set_pio_mode = sc1200_set_pio_mode,
- .set_dma_mode = sc1200_set_dma_mode,
- .udma_filter = sc1200_udma_filter,
-};
-
-static const struct ide_dma_ops sc1200_dma_ops = {
- .dma_host_set = ide_dma_host_set,
- .dma_setup = ide_dma_setup,
- .dma_start = ide_dma_start,
- .dma_end = sc1200_dma_end,
- .dma_test_irq = ide_dma_test_irq,
- .dma_lost_irq = ide_dma_lost_irq,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_sff_read_status = ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info sc1200_chipset = {
- .name = DRV_NAME,
- .port_ops = &sc1200_port_ops,
- .dma_ops = &sc1200_dma_ops,
- .host_flags = IDE_HFLAG_SERIALIZE |
- IDE_HFLAG_POST_SET_MODE |
- IDE_HFLAG_ABUSE_DMA_MODES,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA2,
-};
-
-static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct sc1200_saved_state *ss = NULL;
- int rc;
-
-#ifdef CONFIG_PM
- ss = kmalloc(sizeof(*ss), GFP_KERNEL);
- if (ss == NULL)
- return -ENOMEM;
-#endif
- rc = ide_pci_init_one(dev, &sc1200_chipset, ss);
- if (rc)
- kfree(ss);
-
- return rc;
-}
-
-static const struct pci_device_id sc1200_pci_tbl[] = {
- { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_IDE), 0},
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl);
-
-static struct pci_driver sc1200_pci_driver = {
- .name = "SC1200_IDE",
- .id_table = sc1200_pci_tbl,
- .probe = sc1200_init_one,
- .remove = ide_pci_remove,
-#ifdef CONFIG_PM
- .suspend = sc1200_suspend,
- .resume = sc1200_resume,
-#endif
-};
-
-static int __init sc1200_ide_init(void)
-{
- return ide_pci_register_driver(&sc1200_pci_driver);
-}
-
-static void __exit sc1200_ide_exit(void)
-{
- pci_unregister_driver(&sc1200_pci_driver);
-}
-
-module_init(sc1200_ide_init);
-module_exit(sc1200_ide_exit);
-
-MODULE_AUTHOR("Mark Lord");
-MODULE_DESCRIPTION("PCI driver module for NS SC1200 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
deleted file mode 100644
index 458e72e034b0..000000000000
--- a/drivers/ide/serverworks.c
+++ /dev/null
@@ -1,456 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1998-2000 Michel Aubry
- * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
- * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz
- * Portions copyright (c) 2001 Sun Microsystems
- *
- *
- * RCC/ServerWorks IDE driver for Linux
- *
- * OSB4: `Open South Bridge' IDE Interface (fn 1)
- * supports UDMA mode 2 (33 MB/s)
- *
- * CSB5: `Champion South Bridge' IDE Interface (fn 1)
- * all revisions support UDMA mode 4 (66 MB/s)
- * revision A2.0 and up support UDMA mode 5 (100 MB/s)
- *
- * *** The CSB5 does not provide ANY register ***
- * *** to detect 80-conductor cable presence. ***
- *
- * CSB6: `Champion South Bridge' IDE Interface (optional: third channel)
- *
- * HT1000: AKA BCM5785 - Hypertransport Southbridge for Opteron systems. IDE
- * controller same as the CSB6. Single channel ATA100 only.
- *
- * Documentation:
- * Available under NDA only. Errata info very hard to get.
- *
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "serverworks"
-
-#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
-#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
-
-/* Seagate Barracuda ATA IV Family drives in UDMA mode 5
- * can overrun their FIFOs when used with the CSB5 */
-static const char *svwks_bad_ata100[] = {
- "ST320011A",
- "ST340016A",
- "ST360021A",
- "ST380021A",
- NULL
-};
-
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
- char *m = (char *)&drive->id[ATA_ID_PROD];
-
- while (*list)
- if (!strcmp(*list++, m))
- return 1;
- return 0;
-}
-
-static u8 svwks_udma_filter(ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
-
- if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) {
- return 0x1f;
- } else if (dev->revision < SVWKS_CSB5_REVISION_NEW) {
- return 0x07;
- } else {
- u8 btr = 0, mode, mask;
-
- pci_read_config_byte(dev, 0x5A, &btr);
- mode = btr & 0x3;
-
- /* If someone decides to do UDMA133 on CSB5 the same
- issue will bite so be inclusive */
- if (mode > 2 && check_in_drive_lists(drive, svwks_bad_ata100))
- mode = 2;
-
- switch(mode) {
- case 3: mask = 0x3f; break;
- case 2: mask = 0x1f; break;
- case 1: mask = 0x07; break;
- default: mask = 0x00; break;
- }
-
- return mask;
- }
-}
-
-static u8 svwks_csb_check (struct pci_dev *dev)
-{
- switch (dev->device) {
- case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
- case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
- case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
- case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE:
- return 1;
- default:
- break;
- }
- return 0;
-}
-
-static void svwks_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
- static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
-
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- const u8 pio = drive->pio_mode - XFER_PIO_0;
-
- if (drive->dn >= ARRAY_SIZE(drive_pci))
- return;
-
- pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]);
-
- if (svwks_csb_check(dev)) {
- u16 csb_pio = 0;
-
- pci_read_config_word(dev, 0x4a, &csb_pio);
-
- csb_pio &= ~(0x0f << (4 * drive->dn));
- csb_pio |= (pio << (4 * drive->dn));
-
- pci_write_config_word(dev, 0x4a, csb_pio);
- }
-}
-
-static void svwks_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- static const u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
- static const u8 dma_modes[] = { 0x77, 0x21, 0x20 };
- static const u8 drive_pci2[] = { 0x45, 0x44, 0x47, 0x46 };
-
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- const u8 speed = drive->dma_mode;
- u8 unit = drive->dn & 1;
-
- u8 ultra_enable = 0, ultra_timing = 0, dma_timing = 0;
-
- if (drive->dn >= ARRAY_SIZE(drive_pci2))
- return;
-
- pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
- pci_read_config_byte(dev, 0x54, &ultra_enable);
-
- ultra_timing &= ~(0x0F << (4*unit));
- ultra_enable &= ~(0x01 << drive->dn);
-
- if (speed >= XFER_UDMA_0) {
- dma_timing |= dma_modes[2];
- ultra_timing |= (udma_modes[speed - XFER_UDMA_0] << (4 * unit));
- ultra_enable |= (0x01 << drive->dn);
- } else if (speed >= XFER_MW_DMA_0)
- dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
-
- pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
- pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
- pci_write_config_byte(dev, 0x54, ultra_enable);
-}
-
-static int init_chipset_svwks(struct pci_dev *dev)
-{
- unsigned int reg;
- u8 btr;
-
- /* force Master Latency Timer value to 64 PCICLKs */
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
-
- /* OSB4 : South Bridge and IDE */
- if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
- struct pci_dev *isa_dev =
- pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
- PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
- if (isa_dev) {
- pci_read_config_dword(isa_dev, 0x64, &reg);
- reg &= ~0x00002000; /* disable 600ns interrupt mask */
- if(!(reg & 0x00004000))
- printk(KERN_DEBUG DRV_NAME " %s: UDMA not BIOS "
- "enabled.\n", pci_name(dev));
- reg |= 0x00004000; /* enable UDMA/33 support */
- pci_write_config_dword(isa_dev, 0x64, reg);
- pci_dev_put(isa_dev);
- }
- }
-
- /* setup CSB5/CSB6 : South Bridge and IDE option RAID */
- else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
- (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
- (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
-
- /* Third Channel Test */
- if (!(PCI_FUNC(dev->devfn) & 1)) {
- struct pci_dev * findev = NULL;
- u32 reg4c = 0;
- findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
- PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
- if (findev) {
- pci_read_config_dword(findev, 0x4C, &reg4c);
- reg4c &= ~0x000007FF;
- reg4c |= 0x00000040;
- reg4c |= 0x00000020;
- pci_write_config_dword(findev, 0x4C, reg4c);
- pci_dev_put(findev);
- }
- outb_p(0x06, 0x0c00);
- dev->irq = inb_p(0x0c01);
- } else {
- struct pci_dev * findev = NULL;
- u8 reg41 = 0;
-
- findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
- PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL);
- if (findev) {
- pci_read_config_byte(findev, 0x41, &reg41);
- reg41 &= ~0x40;
- pci_write_config_byte(findev, 0x41, reg41);
- pci_dev_put(findev);
- }
- /*
- * This is a device pin issue on CSB6.
- * Since there will be a future raid mode,
- * early versions of the chipset require the
- * interrupt pin to be set, and it is a compatibility
- * mode issue.
- */
- if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)
- dev->irq = 0;
- }
-// pci_read_config_dword(dev, 0x40, &pioreg)
-// pci_write_config_dword(dev, 0x40, 0x99999999);
-// pci_read_config_dword(dev, 0x44, &dmareg);
-// pci_write_config_dword(dev, 0x44, 0xFFFFFFFF);
- /* setup the UDMA Control register
- *
- * 1. clear bit 6 to enable DMA
- * 2. enable DMA modes with bits 0-1
- * 00 : legacy
- * 01 : udma2
- * 10 : udma2/udma4
- * 11 : udma2/udma4/udma5
- */
- pci_read_config_byte(dev, 0x5A, &btr);
- btr &= ~0x40;
- if (!(PCI_FUNC(dev->devfn) & 1))
- btr |= 0x2;
- else
- btr |= (dev->revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
- pci_write_config_byte(dev, 0x5A, btr);
- }
- /* Setup HT1000 SouthBridge Controller - Single Channel Only */
- else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) {
- pci_read_config_byte(dev, 0x5A, &btr);
- btr &= ~0x40;
- btr |= 0x3;
- pci_write_config_byte(dev, 0x5A, btr);
- }
-
- return 0;
-}
-
-static u8 ata66_svwks_svwks(ide_hwif_t *hwif)
-{
- return ATA_CBL_PATA80;
-}
-
-/* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits
- * of the subsystem device ID indicate presence of an 80-pin cable.
- * Bit 15 clear = secondary IDE channel does not have 80-pin cable.
- * Bit 15 set = secondary IDE channel has 80-pin cable.
- * Bit 14 clear = primary IDE channel does not have 80-pin cable.
- * Bit 14 set = primary IDE channel has 80-pin cable.
- */
-static u8 ata66_svwks_dell(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
-
- if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
- dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
- (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE ||
- dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE))
- return ((1 << (hwif->channel + 14)) &
- dev->subsystem_device) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
- return ATA_CBL_PATA40;
-}
-
-/* Sun Cobalt Alpine hardware avoids the 80-pin cable
- * detect issue by attaching the drives directly to the board.
- * This check follows the Dell precedent (how scary is that?!)
- *
- * WARNING: this only works on Alpine hardware!
- */
-static u8 ata66_svwks_cobalt(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
-
- if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
- dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
- dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
- return ((1 << (hwif->channel + 14)) &
- dev->subsystem_device) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
- return ATA_CBL_PATA40;
-}
-
-static u8 svwks_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
-
- /* Server Works */
- if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
- return ata66_svwks_svwks (hwif);
-
- /* Dell PowerEdge */
- if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
- return ata66_svwks_dell (hwif);
-
- /* Cobalt Alpine */
- if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
- return ata66_svwks_cobalt (hwif);
-
- /* Per Specified Design by OEM, and ASIC Architect */
- if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
- (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
- return ATA_CBL_PATA80;
-
- return ATA_CBL_PATA40;
-}
-
-static const struct ide_port_ops osb4_port_ops = {
- .set_pio_mode = svwks_set_pio_mode,
- .set_dma_mode = svwks_set_dma_mode,
-};
-
-static const struct ide_port_ops svwks_port_ops = {
- .set_pio_mode = svwks_set_pio_mode,
- .set_dma_mode = svwks_set_dma_mode,
- .udma_filter = svwks_udma_filter,
- .cable_detect = svwks_cable_detect,
-};
-
-static const struct ide_port_info serverworks_chipsets[] = {
- { /* 0: OSB4 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_svwks,
- .port_ops = &osb4_port_ops,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = 0x00, /* UDMA is problematic on OSB4 */
- },
- { /* 1: CSB5 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_svwks,
- .port_ops = &svwks_port_ops,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA5,
- },
- { /* 2: CSB6 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_svwks,
- .port_ops = &svwks_port_ops,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA5,
- },
- { /* 3: CSB6-2 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_svwks,
- .port_ops = &svwks_port_ops,
- .host_flags = IDE_HFLAG_SINGLE,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA5,
- },
- { /* 4: HT1000 */
- .name = DRV_NAME,
- .init_chipset = init_chipset_svwks,
- .port_ops = &svwks_port_ops,
- .host_flags = IDE_HFLAG_SINGLE,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA5,
- }
-};
-
-/**
- * svwks_init_one - called when a OSB/CSB is found
- * @dev: the svwks device
- * @id: the matching pci id
- *
- * Called when the PCI registration layer (or the IDE initialization)
- * finds a device matching our IDE device tables.
- */
-
-static int svwks_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct ide_port_info d;
- u8 idx = id->driver_data;
-
- d = serverworks_chipsets[idx];
-
- if (idx == 1)
- d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
- else if (idx == 2 || idx == 3) {
- if ((PCI_FUNC(dev->devfn) & 1) == 0) {
- if (pci_resource_start(dev, 0) != 0x01f1)
- d.host_flags |= IDE_HFLAG_NON_BOOTABLE;
- d.host_flags |= IDE_HFLAG_SINGLE;
- } else
- d.host_flags &= ~IDE_HFLAG_SINGLE;
- }
-
- return ide_pci_init_one(dev, &d, NULL);
-}
-
-static const struct pci_device_id svwks_pci_tbl[] = {
- { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0 },
- { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 1 },
- { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2 },
- { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 3 },
- { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 4 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, svwks_pci_tbl);
-
-static struct pci_driver svwks_pci_driver = {
- .name = "Serverworks_IDE",
- .id_table = svwks_pci_tbl,
- .probe = svwks_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init svwks_ide_init(void)
-{
- return ide_pci_register_driver(&svwks_pci_driver);
-}
-
-static void __exit svwks_ide_exit(void)
-{
- pci_unregister_driver(&svwks_pci_driver);
-}
-
-module_init(svwks_ide_init);
-module_exit(svwks_ide_exit);
-
-MODULE_AUTHOR("Michael Aubry. Andrzej Krzysztofowicz, Andre Hedrick, Bartlomiej Zolnierkiewicz");
-MODULE_DESCRIPTION("PCI driver module for Serverworks OSB4/CSB5/CSB6 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
deleted file mode 100644
index fdc8e813170c..000000000000
--- a/drivers/ide/setup-pci.c
+++ /dev/null
@@ -1,682 +0,0 @@
-/*
- * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 1995-1998 Mark Lord
- * Copyright (C) 2007-2009 Bartlomiej Zolnierkiewicz
- *
- * May be copied or modified under the terms of the GNU General Public License
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ide.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/io.h>
-
-/**
- * ide_setup_pci_baseregs - place a PCI IDE controller native
- * @dev: PCI device of interface to switch native
- * @name: Name of interface
- *
- * We attempt to place the PCI interface into PCI native mode. If
- * we succeed the BARs are ok and the controller is in PCI mode.
- * Returns 0 on success or an errno code.
- *
- * FIXME: if we program the interface and then fail to set the BARS
- * we don't switch it back to legacy mode. Do we actually care ??
- */
-
-static int ide_setup_pci_baseregs(struct pci_dev *dev, const char *name)
-{
- u8 progif = 0;
-
- /*
- * Place both IDE interfaces into PCI "native" mode:
- */
- if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
- (progif & 5) != 5) {
- if ((progif & 0xa) != 0xa) {
- printk(KERN_INFO "%s %s: device not capable of full "
- "native PCI mode\n", name, pci_name(dev));
- return -EOPNOTSUPP;
- }
- printk(KERN_INFO "%s %s: placing both ports into native PCI "
- "mode\n", name, pci_name(dev));
- (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
- if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
- (progif & 5) != 5) {
- printk(KERN_ERR "%s %s: rewrite of PROGIF failed, "
- "wanted 0x%04x, got 0x%04x\n",
- name, pci_name(dev), progif | 5, progif);
- return -EOPNOTSUPP;
- }
- }
- return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
-static int ide_pci_clear_simplex(unsigned long dma_base, const char *name)
-{
- u8 dma_stat = inb(dma_base + 2);
-
- outb(dma_stat & 0x60, dma_base + 2);
- dma_stat = inb(dma_base + 2);
-
- return (dma_stat & 0x80) ? 1 : 0;
-}
-
-/**
- * ide_pci_dma_base - setup BMIBA
- * @hwif: IDE interface
- * @d: IDE port info
- *
- * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space.
- */
-
-unsigned long ide_pci_dma_base(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long dma_base = 0;
-
- if (hwif->host_flags & IDE_HFLAG_MMIO)
- return hwif->dma_base;
-
- if (hwif->mate && hwif->mate->dma_base) {
- dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
- } else {
- u8 baridx = (d->host_flags & IDE_HFLAG_CS5520) ? 2 : 4;
-
- dma_base = pci_resource_start(dev, baridx);
-
- if (dma_base == 0) {
- printk(KERN_ERR "%s %s: DMA base is invalid\n",
- d->name, pci_name(dev));
- return 0;
- }
- }
-
- if (hwif->channel)
- dma_base += 8;
-
- return dma_base;
-}
-EXPORT_SYMBOL_GPL(ide_pci_dma_base);
-
-int ide_pci_check_simplex(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 dma_stat;
-
- if (d->host_flags & (IDE_HFLAG_MMIO | IDE_HFLAG_CS5520))
- goto out;
-
- if (d->host_flags & IDE_HFLAG_CLEAR_SIMPLEX) {
- if (ide_pci_clear_simplex(hwif->dma_base, d->name))
- printk(KERN_INFO "%s %s: simplex device: DMA forced\n",
- d->name, pci_name(dev));
- goto out;
- }
-
- /*
- * If the device claims "simplex" DMA, this means that only one of
- * the two interfaces can be trusted with DMA at any point in time
- * (so we should enable DMA only on one of the two interfaces).
- *
- * FIXME: At this point we haven't probed the drives so we can't make
- * the appropriate decision. Really we should defer this problem until
- * we tune the drive then try to grab DMA ownership if we want to be
- * the DMA end. This has to be become dynamic to handle hot-plug.
- */
- dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
- if ((dma_stat & 0x80) && hwif->mate && hwif->mate->dma_base) {
- printk(KERN_INFO "%s %s: simplex device: DMA disabled\n",
- d->name, pci_name(dev));
- return -1;
- }
-out:
- return 0;
-}
-EXPORT_SYMBOL_GPL(ide_pci_check_simplex);
-
-/*
- * Set up BM-DMA capability (PnP BIOS should have done this)
- */
-int ide_pci_set_master(struct pci_dev *dev, const char *name)
-{
- u16 pcicmd;
-
- pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
-
- if ((pcicmd & PCI_COMMAND_MASTER) == 0) {
- pci_set_master(dev);
-
- if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) ||
- (pcicmd & PCI_COMMAND_MASTER) == 0) {
- printk(KERN_ERR "%s %s: error updating PCICMD\n",
- name, pci_name(dev));
- return -EIO;
- }
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ide_pci_set_master);
-#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
-
-void ide_setup_pci_noise(struct pci_dev *dev, const struct ide_port_info *d)
-{
- printk(KERN_INFO "%s %s: IDE controller (0x%04x:0x%04x rev 0x%02x)\n",
- d->name, pci_name(dev),
- dev->vendor, dev->device, dev->revision);
-}
-EXPORT_SYMBOL_GPL(ide_setup_pci_noise);
-
-
-/**
- * ide_pci_enable - do PCI enables
- * @dev: PCI device
- * @bars: PCI BARs mask
- * @d: IDE port info
- *
- * Enable the IDE PCI device. We attempt to enable the device in full
- * but if that fails then we only need IO space. The PCI code should
- * have setup the proper resources for us already for controllers in
- * legacy mode.
- *
- * Returns zero on success or an error code
- */
-
-static int ide_pci_enable(struct pci_dev *dev, int bars,
- const struct ide_port_info *d)
-{
- int ret;
-
- if (pci_enable_device(dev)) {
- ret = pci_enable_device_io(dev);
- if (ret < 0) {
- printk(KERN_WARNING "%s %s: couldn't enable device\n",
- d->name, pci_name(dev));
- goto out;
- }
- printk(KERN_WARNING "%s %s: BIOS configuration fixed\n",
- d->name, pci_name(dev));
- }
-
- /*
- * assume all devices can do 32-bit DMA for now, we can add
- * a DMA mask field to the struct ide_port_info if we need it
- * (or let lower level driver set the DMA mask)
- */
- ret = dma_set_mask(&dev->dev, DMA_BIT_MASK(32));
- if (ret < 0) {
- printk(KERN_ERR "%s %s: can't set DMA mask\n",
- d->name, pci_name(dev));
- goto out;
- }
-
- ret = pci_request_selected_regions(dev, bars, d->name);
- if (ret < 0)
- printk(KERN_ERR "%s %s: can't reserve resources\n",
- d->name, pci_name(dev));
-out:
- return ret;
-}
-
-/**
- * ide_pci_configure - configure an unconfigured device
- * @dev: PCI device
- * @d: IDE port info
- *
- * Enable and configure the PCI device we have been passed.
- * Returns zero on success or an error code.
- */
-
-static int ide_pci_configure(struct pci_dev *dev, const struct ide_port_info *d)
-{
- u16 pcicmd = 0;
- /*
- * PnP BIOS was *supposed* to have setup this device, but we
- * can do it ourselves, so long as the BIOS has assigned an IRQ
- * (or possibly the device is using a "legacy header" for IRQs).
- * Maybe the user deliberately *disabled* the device,
- * but we'll eventually ignore it again if no drives respond.
- */
- if (ide_setup_pci_baseregs(dev, d->name) ||
- pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_IO)) {
- printk(KERN_INFO "%s %s: device disabled (BIOS)\n",
- d->name, pci_name(dev));
- return -ENODEV;
- }
- if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
- printk(KERN_ERR "%s %s: error accessing PCI regs\n",
- d->name, pci_name(dev));
- return -EIO;
- }
- if (!(pcicmd & PCI_COMMAND_IO)) {
- printk(KERN_ERR "%s %s: unable to enable IDE controller\n",
- d->name, pci_name(dev));
- return -ENXIO;
- }
- return 0;
-}
-
-/**
- * ide_pci_check_iomem - check a register is I/O
- * @dev: PCI device
- * @d: IDE port info
- * @bar: BAR number
- *
- * Checks if a BAR is configured and points to MMIO space. If so,
- * return an error code. Otherwise return 0
- */
-
-static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *d,
- int bar)
-{
- ulong flags = pci_resource_flags(dev, bar);
-
- /* Unconfigured ? */
- if (!flags || pci_resource_len(dev, bar) == 0)
- return 0;
-
- /* I/O space */
- if (flags & IORESOURCE_IO)
- return 0;
-
- /* Bad */
- return -EINVAL;
-}
-
-/**
- * ide_hw_configure - configure a struct ide_hw instance
- * @dev: PCI device holding interface
- * @d: IDE port info
- * @port: port number
- * @hw: struct ide_hw instance corresponding to this port
- *
- * Perform the initial set up for the hardware interface structure. This
- * is done per interface port rather than per PCI device. There may be
- * more than one port per device.
- *
- * Returns zero on success or an error code.
- */
-
-static int ide_hw_configure(struct pci_dev *dev, const struct ide_port_info *d,
- unsigned int port, struct ide_hw *hw)
-{
- unsigned long ctl = 0, base = 0;
-
- if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
- if (ide_pci_check_iomem(dev, d, 2 * port) ||
- ide_pci_check_iomem(dev, d, 2 * port + 1)) {
- printk(KERN_ERR "%s %s: I/O baseregs (BIOS) are "
- "reported as MEM for port %d!\n",
- d->name, pci_name(dev), port);
- return -EINVAL;
- }
-
- ctl = pci_resource_start(dev, 2*port+1);
- base = pci_resource_start(dev, 2*port);
- } else {
- /* Use default values */
- ctl = port ? 0x374 : 0x3f4;
- base = port ? 0x170 : 0x1f0;
- }
-
- if (!base || !ctl) {
- printk(KERN_ERR "%s %s: bad PCI BARs for port %d, skipping\n",
- d->name, pci_name(dev), port);
- return -EINVAL;
- }
-
- memset(hw, 0, sizeof(*hw));
- hw->dev = &dev->dev;
- ide_std_init_ports(hw, base, ctl | 2);
-
- return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
-/**
- * ide_hwif_setup_dma - configure DMA interface
- * @hwif: IDE interface
- * @d: IDE port info
- *
- * Set up the DMA base for the interface. Enable the master bits as
- * necessary and attempt to bring the device DMA into a ready to use
- * state
- */
-
-int ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
-
- if ((d->host_flags & IDE_HFLAG_NO_AUTODMA) == 0 ||
- ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
- (dev->class & 0x80))) {
- unsigned long base = ide_pci_dma_base(hwif, d);
-
- if (base == 0)
- return -1;
-
- hwif->dma_base = base;
-
- if (hwif->dma_ops == NULL)
- hwif->dma_ops = &sff_dma_ops;
-
- if (ide_pci_check_simplex(hwif, d) < 0)
- return -1;
-
- if (ide_pci_set_master(dev, d->name) < 0)
- return -1;
-
- if (hwif->host_flags & IDE_HFLAG_MMIO)
- printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name);
- else
- printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n",
- hwif->name, base, base + 7);
-
- hwif->extra_base = base + (hwif->channel ? 8 : 16);
-
- if (ide_allocate_dma_engine(hwif))
- return -1;
- }
-
- return 0;
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
-
-/**
- * ide_setup_pci_controller - set up IDE PCI
- * @dev: PCI device
- * @bars: PCI BARs mask
- * @d: IDE port info
- * @noisy: verbose flag
- *
- * Set up the PCI and controller side of the IDE interface. This brings
- * up the PCI side of the device, checks that the device is enabled
- * and enables it if need be
- */
-
-static int ide_setup_pci_controller(struct pci_dev *dev, int bars,
- const struct ide_port_info *d, int noisy)
-{
- int ret;
- u16 pcicmd;
-
- if (noisy)
- ide_setup_pci_noise(dev, d);
-
- ret = ide_pci_enable(dev, bars, d);
- if (ret < 0)
- goto out;
-
- ret = pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
- if (ret < 0) {
- printk(KERN_ERR "%s %s: error accessing PCI regs\n",
- d->name, pci_name(dev));
- goto out_free_bars;
- }
- if (!(pcicmd & PCI_COMMAND_IO)) { /* is device disabled? */
- ret = ide_pci_configure(dev, d);
- if (ret < 0)
- goto out_free_bars;
- printk(KERN_INFO "%s %s: device enabled (Linux)\n",
- d->name, pci_name(dev));
- }
-
- goto out;
-
-out_free_bars:
- pci_release_selected_regions(dev, bars);
-out:
- return ret;
-}
-
-/**
- * ide_pci_setup_ports - configure ports/devices on PCI IDE
- * @dev: PCI device
- * @d: IDE port info
- * @hw: struct ide_hw instances corresponding to this PCI IDE device
- * @hws: struct ide_hw pointers table to update
- *
- * Scan the interfaces attached to this device and do any
- * necessary per port setup. Attach the devices and ask the
- * generic DMA layer to do its work for us.
- *
- * Normally called automaticall from do_ide_pci_setup_device,
- * but is also used directly as a helper function by some controllers
- * where the chipset setup is not the default PCI IDE one.
- */
-
-void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d,
- struct ide_hw *hw, struct ide_hw **hws)
-{
- int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port;
- u8 tmp;
-
- /*
- * Set up the IDE ports
- */
-
- for (port = 0; port < channels; ++port) {
- const struct ide_pci_enablebit *e = &d->enablebits[port];
-
- if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
- (tmp & e->mask) != e->val)) {
- printk(KERN_INFO "%s %s: IDE port disabled\n",
- d->name, pci_name(dev));
- continue; /* port not enabled */
- }
-
- if (ide_hw_configure(dev, d, port, hw + port))
- continue;
-
- *(hws + port) = hw + port;
- }
-}
-EXPORT_SYMBOL_GPL(ide_pci_setup_ports);
-
-/*
- * ide_setup_pci_device() looks at the primary/secondary interfaces
- * on a PCI IDE device and, if they are enabled, prepares the IDE driver
- * for use with them. This generic code works for most PCI chipsets.
- *
- * One thing that is not standardized is the location of the
- * primary/secondary interface "enable/disable" bits. For chipsets that
- * we "know" about, this information is in the struct ide_port_info;
- * for all other chipsets, we just assume both interfaces are enabled.
- */
-static int do_ide_setup_pci_device(struct pci_dev *dev,
- const struct ide_port_info *d,
- u8 noisy)
-{
- int pciirq, ret;
-
- /*
- * Can we trust the reported IRQ?
- */
- pciirq = dev->irq;
-
- /*
- * This allows offboard ide-pci cards the enable a BIOS,
- * verify interrupt settings of split-mirror pci-config
- * space, place chipset into init-mode, and/or preserve
- * an interrupt if the card is not native ide support.
- */
- ret = d->init_chipset ? d->init_chipset(dev) : 0;
- if (ret < 0)
- goto out;
-
- if (ide_pci_is_in_compatibility_mode(dev)) {
- if (noisy)
- printk(KERN_INFO "%s %s: not 100%% native mode: will "
- "probe irqs later\n", d->name, pci_name(dev));
- pciirq = 0;
- } else if (!pciirq && noisy) {
- printk(KERN_WARNING "%s %s: bad irq (%d): will probe later\n",
- d->name, pci_name(dev), pciirq);
- } else if (noisy) {
- printk(KERN_INFO "%s %s: 100%% native mode on irq %d\n",
- d->name, pci_name(dev), pciirq);
- }
-
- ret = pciirq;
-out:
- return ret;
-}
-
-int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2,
- const struct ide_port_info *d, void *priv)
-{
- struct pci_dev *pdev[] = { dev1, dev2 };
- struct ide_host *host;
- int ret, i, n_ports = dev2 ? 4 : 2, bars;
- struct ide_hw hw[4], *hws[] = { NULL, NULL, NULL, NULL };
-
- if (d->host_flags & IDE_HFLAG_SINGLE)
- bars = (1 << 2) - 1;
- else
- bars = (1 << 4) - 1;
-
- if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) {
- if (d->host_flags & IDE_HFLAG_CS5520)
- bars |= (1 << 2);
- else
- bars |= (1 << 4);
- }
-
- for (i = 0; i < n_ports / 2; i++) {
- ret = ide_setup_pci_controller(pdev[i], bars, d, !i);
- if (ret < 0) {
- if (i == 1)
- pci_release_selected_regions(pdev[0], bars);
- goto out;
- }
-
- ide_pci_setup_ports(pdev[i], d, &hw[i*2], &hws[i*2]);
- }
-
- host = ide_host_alloc(d, hws, n_ports);
- if (host == NULL) {
- ret = -ENOMEM;
- goto out_free_bars;
- }
-
- host->dev[0] = &dev1->dev;
- if (dev2)
- host->dev[1] = &dev2->dev;
-
- host->host_priv = priv;
- host->irq_flags = IRQF_SHARED;
-
- pci_set_drvdata(pdev[0], host);
- if (dev2)
- pci_set_drvdata(pdev[1], host);
-
- for (i = 0; i < n_ports / 2; i++) {
- ret = do_ide_setup_pci_device(pdev[i], d, !i);
-
- /*
- * FIXME: Mom, mom, they stole me the helper function to undo
- * do_ide_setup_pci_device() on the first device!
- */
- if (ret < 0)
- goto out_free_bars;
-
- /* fixup IRQ */
- if (ide_pci_is_in_compatibility_mode(pdev[i])) {
- hw[i*2].irq = pci_get_legacy_ide_irq(pdev[i], 0);
- hw[i*2 + 1].irq = pci_get_legacy_ide_irq(pdev[i], 1);
- } else
- hw[i*2 + 1].irq = hw[i*2].irq = ret;
- }
-
- ret = ide_host_register(host, d, hws);
- if (ret)
- ide_host_free(host);
- else
- goto out;
-
-out_free_bars:
- i = n_ports / 2;
- while (i--)
- pci_release_selected_regions(pdev[i], bars);
-out:
- return ret;
-}
-EXPORT_SYMBOL_GPL(ide_pci_init_two);
-
-int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d,
- void *priv)
-{
- return ide_pci_init_two(dev, NULL, d, priv);
-}
-EXPORT_SYMBOL_GPL(ide_pci_init_one);
-
-void ide_pci_remove(struct pci_dev *dev)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
- int bars;
-
- if (host->host_flags & IDE_HFLAG_SINGLE)
- bars = (1 << 2) - 1;
- else
- bars = (1 << 4) - 1;
-
- if ((host->host_flags & IDE_HFLAG_NO_DMA) == 0) {
- if (host->host_flags & IDE_HFLAG_CS5520)
- bars |= (1 << 2);
- else
- bars |= (1 << 4);
- }
-
- ide_host_remove(host);
-
- if (dev2)
- pci_release_selected_regions(dev2, bars);
- pci_release_selected_regions(dev, bars);
-
- if (dev2)
- pci_disable_device(dev2);
- pci_disable_device(dev);
-}
-EXPORT_SYMBOL_GPL(ide_pci_remove);
-
-#ifdef CONFIG_PM
-int ide_pci_suspend(struct pci_dev *dev, pm_message_t state)
-{
- pci_save_state(dev);
- pci_disable_device(dev);
- pci_set_power_state(dev, pci_choose_state(dev, state));
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ide_pci_suspend);
-
-int ide_pci_resume(struct pci_dev *dev)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- int rc;
-
- pci_set_power_state(dev, PCI_D0);
-
- rc = pci_enable_device(dev);
- if (rc)
- return rc;
-
- pci_restore_state(dev);
- pci_set_master(dev);
-
- if (host->init_chipset)
- host->init_chipset(dev);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ide_pci_resume);
-#endif
diff --git a/drivers/ide/siimage.c b/drivers/ide/siimage.c
deleted file mode 100644
index c4b20f350b84..000000000000
--- a/drivers/ide/siimage.c
+++ /dev/null
@@ -1,843 +0,0 @@
-/*
- * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2003 Red Hat
- * Copyright (C) 2007-2008 MontaVista Software, Inc.
- * Copyright (C) 2007-2008 Bartlomiej Zolnierkiewicz
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- * Documentation for CMD680:
- * http://gkernel.sourceforge.net/specs/sii/sii-0680a-v1.31.pdf.bz2
- *
- * Documentation for SiI 3112:
- * http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2
- *
- * Errata and other documentation only available under NDA.
- *
- *
- * FAQ Items:
- * If you are using Marvell SATA-IDE adapters with Maxtor drives
- * ensure the system is set up for ATA100/UDMA5, not UDMA6.
- *
- * If you are using WD drives with SATA bridges you must set the
- * drive to "Single". "Master" will hang.
- *
- * If you have strange problems with nVidia chipset systems please
- * see the SI support documentation and update your system BIOS
- * if necessary
- *
- * The Dell DRAC4 has some interesting features including effectively hot
- * unplugging/replugging the virtual CD interface when the DRAC is reset.
- * This often causes drivers/ide/siimage to panic but is ok with the rather
- * smarter code in libata.
- *
- * TODO:
- * - VDMA support
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/io.h>
-
-#define DRV_NAME "siimage"
-
-/**
- * pdev_is_sata - check if device is SATA
- * @pdev: PCI device to check
- *
- * Returns true if this is a SATA controller
- */
-
-static int pdev_is_sata(struct pci_dev *pdev)
-{
-#ifdef CONFIG_BLK_DEV_IDE_SATA
- switch (pdev->device) {
- case PCI_DEVICE_ID_SII_3112:
- case PCI_DEVICE_ID_SII_1210SA:
- return 1;
- case PCI_DEVICE_ID_SII_680:
- return 0;
- }
- BUG();
-#endif
- return 0;
-}
-
-/**
- * is_sata - check if hwif is SATA
- * @hwif: interface to check
- *
- * Returns true if this is a SATA controller
- */
-
-static inline int is_sata(ide_hwif_t *hwif)
-{
- return pdev_is_sata(to_pci_dev(hwif->dev));
-}
-
-/**
- * siimage_selreg - return register base
- * @hwif: interface
- * @r: config offset
- *
- * Turn a config register offset into the right address in either
- * PCI space or MMIO space to access the control register in question
- * Thankfully this is a configuration operation, so isn't performance
- * critical.
- */
-
-static unsigned long siimage_selreg(ide_hwif_t *hwif, int r)
-{
- unsigned long base = (unsigned long)hwif->hwif_data;
-
- base += 0xA0 + r;
- if (hwif->host_flags & IDE_HFLAG_MMIO)
- base += hwif->channel << 6;
- else
- base += hwif->channel << 4;
- return base;
-}
-
-/**
- * siimage_seldev - return register base
- * @hwif: interface
- * @r: config offset
- *
- * Turn a config register offset into the right address in either
- * PCI space or MMIO space to access the control register in question
- * including accounting for the unit shift.
- */
-
-static inline unsigned long siimage_seldev(ide_drive_t *drive, int r)
-{
- ide_hwif_t *hwif = drive->hwif;
- unsigned long base = (unsigned long)hwif->hwif_data;
- u8 unit = drive->dn & 1;
-
- base += 0xA0 + r;
- if (hwif->host_flags & IDE_HFLAG_MMIO)
- base += hwif->channel << 6;
- else
- base += hwif->channel << 4;
- base |= unit << unit;
- return base;
-}
-
-static u8 sil_ioread8(struct pci_dev *dev, unsigned long addr)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- u8 tmp = 0;
-
- if (host->host_priv)
- tmp = readb((void __iomem *)addr);
- else
- pci_read_config_byte(dev, addr, &tmp);
-
- return tmp;
-}
-
-static u16 sil_ioread16(struct pci_dev *dev, unsigned long addr)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- u16 tmp = 0;
-
- if (host->host_priv)
- tmp = readw((void __iomem *)addr);
- else
- pci_read_config_word(dev, addr, &tmp);
-
- return tmp;
-}
-
-static void sil_iowrite8(struct pci_dev *dev, u8 val, unsigned long addr)
-{
- struct ide_host *host = pci_get_drvdata(dev);
-
- if (host->host_priv)
- writeb(val, (void __iomem *)addr);
- else
- pci_write_config_byte(dev, addr, val);
-}
-
-static void sil_iowrite16(struct pci_dev *dev, u16 val, unsigned long addr)
-{
- struct ide_host *host = pci_get_drvdata(dev);
-
- if (host->host_priv)
- writew(val, (void __iomem *)addr);
- else
- pci_write_config_word(dev, addr, val);
-}
-
-static void sil_iowrite32(struct pci_dev *dev, u32 val, unsigned long addr)
-{
- struct ide_host *host = pci_get_drvdata(dev);
-
- if (host->host_priv)
- writel(val, (void __iomem *)addr);
- else
- pci_write_config_dword(dev, addr, val);
-}
-
-/**
- * sil_udma_filter - compute UDMA mask
- * @drive: IDE device
- *
- * Compute the available UDMA speeds for the device on the interface.
- *
- * For the CMD680 this depends on the clocking mode (scsc), for the
- * SI3112 SATA controller life is a bit simpler.
- */
-
-static u8 sil_pata_udma_filter(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long base = (unsigned long)hwif->hwif_data;
- u8 scsc, mask = 0;
-
- base += (hwif->host_flags & IDE_HFLAG_MMIO) ? 0x4A : 0x8A;
-
- scsc = sil_ioread8(dev, base);
-
- switch (scsc & 0x30) {
- case 0x10: /* 133 */
- mask = ATA_UDMA6;
- break;
- case 0x20: /* 2xPCI */
- mask = ATA_UDMA6;
- break;
- case 0x00: /* 100 */
- mask = ATA_UDMA5;
- break;
- default: /* Disabled ? */
- BUG();
- }
-
- return mask;
-}
-
-static u8 sil_sata_udma_filter(ide_drive_t *drive)
-{
- char *m = (char *)&drive->id[ATA_ID_PROD];
-
- return strstr(m, "Maxtor") ? ATA_UDMA5 : ATA_UDMA6;
-}
-
-/**
- * sil_set_pio_mode - set host controller for PIO mode
- * @hwif: port
- * @drive: drive
- *
- * Load the timing settings for this device mode into the
- * controller.
- */
-
-static void sil_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- static const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 };
- static const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
-
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- ide_drive_t *pair = ide_get_pair_dev(drive);
- u32 speedt = 0;
- u16 speedp = 0;
- unsigned long addr = siimage_seldev(drive, 0x04);
- unsigned long tfaddr = siimage_selreg(hwif, 0x02);
- unsigned long base = (unsigned long)hwif->hwif_data;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
- u8 tf_pio = pio;
- u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
- u8 addr_mask = hwif->channel ? (mmio ? 0xF4 : 0x84)
- : (mmio ? 0xB4 : 0x80);
- u8 mode = 0;
- u8 unit = drive->dn & 1;
-
- /* trim *taskfile* PIO to the slowest of the master/slave */
- if (pair) {
- u8 pair_pio = pair->pio_mode - XFER_PIO_0;
-
- if (pair_pio < tf_pio)
- tf_pio = pair_pio;
- }
-
- /* cheat for now and use the docs */
- speedp = data_speed[pio];
- speedt = tf_speed[tf_pio];
-
- sil_iowrite16(dev, speedp, addr);
- sil_iowrite16(dev, speedt, tfaddr);
-
- /* now set up IORDY */
- speedp = sil_ioread16(dev, tfaddr - 2);
- speedp &= ~0x200;
-
- mode = sil_ioread8(dev, base + addr_mask);
- mode &= ~(unit ? 0x30 : 0x03);
-
- if (ide_pio_need_iordy(drive, pio)) {
- speedp |= 0x200;
- mode |= unit ? 0x10 : 0x01;
- }
-
- sil_iowrite16(dev, speedp, tfaddr - 2);
- sil_iowrite8(dev, mode, base + addr_mask);
-}
-
-/**
- * sil_set_dma_mode - set host controller for DMA mode
- * @hwif: port
- * @drive: drive
- *
- * Tune the SiI chipset for the desired DMA mode.
- */
-
-static void sil_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- static const u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
- static const u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
- static const u16 dma[] = { 0x2208, 0x10C2, 0x10C1 };
-
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long base = (unsigned long)hwif->hwif_data;
- u16 ultra = 0, multi = 0;
- u8 mode = 0, unit = drive->dn & 1;
- u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
- u8 scsc = 0, addr_mask = hwif->channel ? (mmio ? 0xF4 : 0x84)
- : (mmio ? 0xB4 : 0x80);
- unsigned long ma = siimage_seldev(drive, 0x08);
- unsigned long ua = siimage_seldev(drive, 0x0C);
- const u8 speed = drive->dma_mode;
-
- scsc = sil_ioread8 (dev, base + (mmio ? 0x4A : 0x8A));
- mode = sil_ioread8 (dev, base + addr_mask);
- multi = sil_ioread16(dev, ma);
- ultra = sil_ioread16(dev, ua);
-
- mode &= ~(unit ? 0x30 : 0x03);
- ultra &= ~0x3F;
- scsc = ((scsc & 0x30) == 0x00) ? 0 : 1;
-
- scsc = is_sata(hwif) ? 1 : scsc;
-
- if (speed >= XFER_UDMA_0) {
- multi = dma[2];
- ultra |= scsc ? ultra6[speed - XFER_UDMA_0] :
- ultra5[speed - XFER_UDMA_0];
- mode |= unit ? 0x30 : 0x03;
- } else {
- multi = dma[speed - XFER_MW_DMA_0];
- mode |= unit ? 0x20 : 0x02;
- }
-
- sil_iowrite8 (dev, mode, base + addr_mask);
- sil_iowrite16(dev, multi, ma);
- sil_iowrite16(dev, ultra, ua);
-}
-
-static int sil_test_irq(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long addr = siimage_selreg(hwif, 1);
- u8 val = sil_ioread8(dev, addr);
-
- /* Return 1 if INTRQ asserted */
- return (val & 8) ? 1 : 0;
-}
-
-/**
- * siimage_mmio_dma_test_irq - check we caused an IRQ
- * @drive: drive we are testing
- *
- * Check if we caused an IDE DMA interrupt. We may also have caused
- * SATA status interrupts, if so we clean them up and continue.
- */
-
-static int siimage_mmio_dma_test_irq(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- void __iomem *sata_error_addr
- = (void __iomem *)hwif->sata_scr[SATA_ERROR_OFFSET];
-
- if (sata_error_addr) {
- unsigned long base = (unsigned long)hwif->hwif_data;
- u32 ext_stat = readl((void __iomem *)(base + 0x10));
- u8 watchdog = 0;
-
- if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {
- u32 sata_error = readl(sata_error_addr);
-
- writel(sata_error, sata_error_addr);
- watchdog = (sata_error & 0x00680000) ? 1 : 0;
- printk(KERN_WARNING "%s: sata_error = 0x%08x, "
- "watchdog = %d, %s\n",
- drive->name, sata_error, watchdog, __func__);
- } else
- watchdog = (ext_stat & 0x8000) ? 1 : 0;
-
- ext_stat >>= 16;
- if (!(ext_stat & 0x0404) && !watchdog)
- return 0;
- }
-
- /* return 1 if INTR asserted */
- if (readb((void __iomem *)(hwif->dma_base + ATA_DMA_STATUS)) & 4)
- return 1;
-
- return 0;
-}
-
-static int siimage_dma_test_irq(ide_drive_t *drive)
-{
- if (drive->hwif->host_flags & IDE_HFLAG_MMIO)
- return siimage_mmio_dma_test_irq(drive);
- else
- return ide_dma_test_irq(drive);
-}
-
-/**
- * sil_sata_reset_poll - wait for SATA reset
- * @drive: drive we are resetting
- *
- * Poll the SATA phy and see whether it has come back from the dead
- * yet.
- */
-
-static blk_status_t sil_sata_reset_poll(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- void __iomem *sata_status_addr
- = (void __iomem *)hwif->sata_scr[SATA_STATUS_OFFSET];
-
- if (sata_status_addr) {
- /* SATA Status is available only when in MMIO mode */
- u32 sata_stat = readl(sata_status_addr);
-
- if ((sata_stat & 0x03) != 0x03) {
- printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n",
- hwif->name, sata_stat);
- return BLK_STS_IOERR;
- }
- }
-
- return BLK_STS_OK;
-}
-
-/**
- * sil_sata_pre_reset - reset hook
- * @drive: IDE device being reset
- *
- * For the SATA devices we need to handle recalibration/geometry
- * differently
- */
-
-static void sil_sata_pre_reset(ide_drive_t *drive)
-{
- if (drive->media == ide_disk) {
- drive->special_flags &=
- ~(IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE);
- }
-}
-
-/**
- * init_chipset_siimage - set up an SI device
- * @dev: PCI device
- *
- * Perform the initial PCI set up for this device. Attempt to switch
- * to 133 MHz clocking if the system isn't already set up to do it.
- */
-
-static int init_chipset_siimage(struct pci_dev *dev)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- void __iomem *ioaddr = host->host_priv;
- unsigned long base, scsc_addr;
- u8 rev = dev->revision, tmp;
-
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, rev ? 1 : 255);
-
- if (ioaddr)
- pci_set_master(dev);
-
- base = (unsigned long)ioaddr;
-
- if (ioaddr && pdev_is_sata(dev)) {
- u32 tmp32, irq_mask;
-
- /* make sure IDE0/1 interrupts are not masked */
- irq_mask = (1 << 22) | (1 << 23);
- tmp32 = readl(ioaddr + 0x48);
- if (tmp32 & irq_mask) {
- tmp32 &= ~irq_mask;
- writel(tmp32, ioaddr + 0x48);
- readl(ioaddr + 0x48); /* flush */
- }
- writel(0, ioaddr + 0x148);
- writel(0, ioaddr + 0x1C8);
- }
-
- sil_iowrite8(dev, 0, base ? (base + 0xB4) : 0x80);
- sil_iowrite8(dev, 0, base ? (base + 0xF4) : 0x84);
-
- scsc_addr = base ? (base + 0x4A) : 0x8A;
- tmp = sil_ioread8(dev, scsc_addr);
-
- switch (tmp & 0x30) {
- case 0x00:
- /* On 100 MHz clocking, try and switch to 133 MHz */
- sil_iowrite8(dev, tmp | 0x10, scsc_addr);
- break;
- case 0x30:
- /* Clocking is disabled, attempt to force 133MHz clocking. */
- sil_iowrite8(dev, tmp & ~0x20, scsc_addr);
- case 0x10:
- /* On 133Mhz clocking. */
- break;
- case 0x20:
- /* On PCIx2 clocking. */
- break;
- }
-
- tmp = sil_ioread8(dev, scsc_addr);
-
- sil_iowrite8 (dev, 0x72, base + 0xA1);
- sil_iowrite16(dev, 0x328A, base + 0xA2);
- sil_iowrite32(dev, 0x62DD62DD, base + 0xA4);
- sil_iowrite32(dev, 0x43924392, base + 0xA8);
- sil_iowrite32(dev, 0x40094009, base + 0xAC);
- sil_iowrite8 (dev, 0x72, base ? (base + 0xE1) : 0xB1);
- sil_iowrite16(dev, 0x328A, base ? (base + 0xE2) : 0xB2);
- sil_iowrite32(dev, 0x62DD62DD, base ? (base + 0xE4) : 0xB4);
- sil_iowrite32(dev, 0x43924392, base ? (base + 0xE8) : 0xB8);
- sil_iowrite32(dev, 0x40094009, base ? (base + 0xEC) : 0xBC);
-
- if (base && pdev_is_sata(dev)) {
- writel(0xFFFF0000, ioaddr + 0x108);
- writel(0xFFFF0000, ioaddr + 0x188);
- writel(0x00680000, ioaddr + 0x148);
- writel(0x00680000, ioaddr + 0x1C8);
- }
-
- /* report the clocking mode of the controller */
- if (!pdev_is_sata(dev)) {
- static const char *clk_str[] =
- { "== 100", "== 133", "== 2X PCI", "DISABLED!" };
-
- tmp >>= 4;
- printk(KERN_INFO DRV_NAME " %s: BASE CLOCK %s\n",
- pci_name(dev), clk_str[tmp & 3]);
- }
-
- return 0;
-}
-
-/**
- * init_mmio_iops_siimage - set up the iops for MMIO
- * @hwif: interface to set up
- *
- * The basic setup here is fairly simple, we can use standard MMIO
- * operations. However we do have to set the taskfile register offsets
- * by hand as there isn't a standard defined layout for them this time.
- *
- * The hardware supports buffered taskfiles and also some rather nice
- * extended PRD tables. For better SI3112 support use the libata driver
- */
-
-static void init_mmio_iops_siimage(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct ide_host *host = pci_get_drvdata(dev);
- void *addr = host->host_priv;
- u8 ch = hwif->channel;
- struct ide_io_ports *io_ports = &hwif->io_ports;
- unsigned long base;
-
- /*
- * Fill in the basic hwif bits
- */
- hwif->host_flags |= IDE_HFLAG_MMIO;
-
- hwif->hwif_data = addr;
-
- /*
- * Now set up the hw. We have to do this ourselves as the
- * MMIO layout isn't the same as the standard port based I/O.
- */
- memset(io_ports, 0, sizeof(*io_ports));
-
- base = (unsigned long)addr;
- if (ch)
- base += 0xC0;
- else
- base += 0x80;
-
- /*
- * The buffered task file doesn't have status/control, so we
- * can't currently use it sanely since we want to use LBA48 mode.
- */
- io_ports->data_addr = base;
- io_ports->error_addr = base + 1;
- io_ports->nsect_addr = base + 2;
- io_ports->lbal_addr = base + 3;
- io_ports->lbam_addr = base + 4;
- io_ports->lbah_addr = base + 5;
- io_ports->device_addr = base + 6;
- io_ports->status_addr = base + 7;
- io_ports->ctl_addr = base + 10;
-
- if (pdev_is_sata(dev)) {
- base = (unsigned long)addr;
- if (ch)
- base += 0x80;
- hwif->sata_scr[SATA_STATUS_OFFSET] = base + 0x104;
- hwif->sata_scr[SATA_ERROR_OFFSET] = base + 0x108;
- hwif->sata_scr[SATA_CONTROL_OFFSET] = base + 0x100;
- }
-
- hwif->irq = dev->irq;
-
- hwif->dma_base = (unsigned long)addr + (ch ? 0x08 : 0x00);
-}
-
-static int is_dev_seagate_sata(ide_drive_t *drive)
-{
- const char *s = (const char *)&drive->id[ATA_ID_PROD];
- unsigned len = strnlen(s, ATA_ID_PROD_LEN);
-
- if ((len > 4) && (!memcmp(s, "ST", 2)))
- if ((!memcmp(s + len - 2, "AS", 2)) ||
- (!memcmp(s + len - 3, "ASL", 3))) {
- printk(KERN_INFO "%s: applying pessimistic Seagate "
- "errata fix\n", drive->name);
- return 1;
- }
-
- return 0;
-}
-
-/**
- * sil_quirkproc - post probe fixups
- * @drive: drive
- *
- * Called after drive probe we use this to decide whether the
- * Seagate fixup must be applied. This used to be in init_iops but
- * that can occur before we know what drives are present.
- */
-
-static void sil_quirkproc(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
-
- /* Try and rise the rqsize */
- if (!is_sata(hwif) || !is_dev_seagate_sata(drive))
- hwif->rqsize = 128;
-}
-
-/**
- * init_iops_siimage - set up iops
- * @hwif: interface to set up
- *
- * Do the basic setup for the SIIMAGE hardware interface
- * and then do the MMIO setup if we can. This is the first
- * look in we get for setting up the hwif so that we
- * can get the iops right before using them.
- */
-
-static void init_iops_siimage(ide_hwif_t *hwif)
-{
- struct ide_host *host = dev_get_drvdata(hwif->dev);
-
- hwif->hwif_data = NULL;
-
- /* Pessimal until we finish probing */
- hwif->rqsize = 15;
-
- if (host->host_priv)
- init_mmio_iops_siimage(hwif);
-}
-
-/**
- * sil_cable_detect - cable detection
- * @hwif: interface to check
- *
- * Check for the presence of an ATA66 capable cable on the interface.
- */
-
-static u8 sil_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long addr = siimage_selreg(hwif, 0);
- u8 ata66 = sil_ioread8(dev, addr);
-
- return (ata66 & 0x01) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
-}
-
-static const struct ide_port_ops sil_pata_port_ops = {
- .set_pio_mode = sil_set_pio_mode,
- .set_dma_mode = sil_set_dma_mode,
- .quirkproc = sil_quirkproc,
- .test_irq = sil_test_irq,
- .udma_filter = sil_pata_udma_filter,
- .cable_detect = sil_cable_detect,
-};
-
-static const struct ide_port_ops sil_sata_port_ops = {
- .set_pio_mode = sil_set_pio_mode,
- .set_dma_mode = sil_set_dma_mode,
- .reset_poll = sil_sata_reset_poll,
- .pre_reset = sil_sata_pre_reset,
- .quirkproc = sil_quirkproc,
- .test_irq = sil_test_irq,
- .udma_filter = sil_sata_udma_filter,
- .cable_detect = sil_cable_detect,
-};
-
-static const struct ide_dma_ops sil_dma_ops = {
- .dma_host_set = ide_dma_host_set,
- .dma_setup = ide_dma_setup,
- .dma_start = ide_dma_start,
- .dma_end = ide_dma_end,
- .dma_test_irq = siimage_dma_test_irq,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_lost_irq = ide_dma_lost_irq,
- .dma_sff_read_status = ide_dma_sff_read_status,
-};
-
-#define DECLARE_SII_DEV(p_ops) \
- { \
- .name = DRV_NAME, \
- .init_chipset = init_chipset_siimage, \
- .init_iops = init_iops_siimage, \
- .port_ops = p_ops, \
- .dma_ops = &sil_dma_ops, \
- .pio_mask = ATA_PIO4, \
- .mwdma_mask = ATA_MWDMA2, \
- .udma_mask = ATA_UDMA6, \
- }
-
-static const struct ide_port_info siimage_chipsets[] = {
- /* 0: SiI680 */ DECLARE_SII_DEV(&sil_pata_port_ops),
- /* 1: SiI3112 */ DECLARE_SII_DEV(&sil_sata_port_ops)
-};
-
-/**
- * siimage_init_one - PCI layer discovery entry
- * @dev: PCI device
- * @id: ident table entry
- *
- * Called by the PCI code when it finds an SiI680 or SiI3112 controller.
- * We then use the IDE PCI generic helper to do most of the work.
- */
-
-static int siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- void __iomem *ioaddr = NULL;
- resource_size_t bar5 = pci_resource_start(dev, 5);
- unsigned long barsize = pci_resource_len(dev, 5);
- int rc;
- struct ide_port_info d;
- u8 idx = id->driver_data;
- u8 BA5_EN;
-
- d = siimage_chipsets[idx];
-
- if (idx) {
- static int first = 1;
-
- if (first) {
- printk(KERN_INFO DRV_NAME ": For full SATA support you "
- "should use the libata sata_sil module.\n");
- first = 0;
- }
-
- d.host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
- }
-
- rc = pci_enable_device(dev);
- if (rc)
- return rc;
-
- pci_read_config_byte(dev, 0x8A, &BA5_EN);
- if ((BA5_EN & 0x01) || bar5) {
- /*
- * Drop back to PIO if we can't map the MMIO. Some systems
- * seem to get terminally confused in the PCI spaces.
- */
- if (!request_mem_region(bar5, barsize, d.name)) {
- printk(KERN_WARNING DRV_NAME " %s: MMIO ports not "
- "available\n", pci_name(dev));
- } else {
- ioaddr = pci_ioremap_bar(dev, 5);
- if (ioaddr == NULL)
- release_mem_region(bar5, barsize);
- }
- }
-
- rc = ide_pci_init_one(dev, &d, ioaddr);
- if (rc) {
- if (ioaddr) {
- iounmap(ioaddr);
- release_mem_region(bar5, barsize);
- }
- pci_disable_device(dev);
- }
-
- return rc;
-}
-
-static void siimage_remove(struct pci_dev *dev)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- void __iomem *ioaddr = host->host_priv;
-
- ide_pci_remove(dev);
-
- if (ioaddr) {
- resource_size_t bar5 = pci_resource_start(dev, 5);
- unsigned long barsize = pci_resource_len(dev, 5);
-
- iounmap(ioaddr);
- release_mem_region(bar5, barsize);
- }
-
- pci_disable_device(dev);
-}
-
-static const struct pci_device_id siimage_pci_tbl[] = {
- { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), 0 },
-#ifdef CONFIG_BLK_DEV_IDE_SATA
- { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_3112), 1 },
- { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_1210SA), 1 },
-#endif
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, siimage_pci_tbl);
-
-static struct pci_driver siimage_pci_driver = {
- .name = "SiI_IDE",
- .id_table = siimage_pci_tbl,
- .probe = siimage_init_one,
- .remove = siimage_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init siimage_ide_init(void)
-{
- return ide_pci_register_driver(&siimage_pci_driver);
-}
-
-static void __exit siimage_ide_exit(void)
-{
- pci_unregister_driver(&siimage_pci_driver);
-}
-
-module_init(siimage_ide_init);
-module_exit(siimage_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick, Alan Cox");
-MODULE_DESCRIPTION("PCI driver module for SiI IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
deleted file mode 100644
index 1a700bef6c56..000000000000
--- a/drivers/ide/sis5513.c
+++ /dev/null
@@ -1,637 +0,0 @@
-/*
- * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
- * Copyright (C) 2003 Vojtech Pavlik <vojtech@suse.cz>
- * Copyright (C) 2007-2009 Bartlomiej Zolnierkiewicz
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- *
- * Thanks :
- *
- * SiS Taiwan : for direct support and hardware.
- * Daniela Engert : for initial ATA100 advices and numerous others.
- * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt :
- * for checking code correctness, providing patches.
- *
- *
- * Original tests and design on the SiS620 chipset.
- * ATA100 tests and design on the SiS735 chipset.
- * ATA16/33 support from specs
- * ATA133 support for SiS961/962 by L.C. Chang <lcchang@sis.com.tw>
- * ATA133 961/962/963 fixes by Vojtech Pavlik <vojtech@suse.cz>
- *
- * Documentation:
- * SiS chipset documentation available under NDA to companies only
- * (not to individuals).
- */
-
-/*
- * The original SiS5513 comes from a SiS5511/55112/5513 chipset. The original
- * SiS5513 was also used in the SiS5596/5513 chipset. Thus if we see a SiS5511
- * or SiS5596, we can assume we see the first MWDMA-16 capable SiS5513 chip.
- *
- * Later SiS chipsets integrated the 5513 functionality into the NorthBridge,
- * starting with SiS5571 and up to SiS745. The PCI ID didn't change, though. We
- * can figure out that we have a more modern and more capable 5513 by looking
- * for the respective NorthBridge IDs.
- *
- * Even later (96x family) SiS chipsets use the MuTIOL link and place the 5513
- * into the SouthBrige. Here we cannot rely on looking up the NorthBridge PCI
- * ID, while the now ATA-133 capable 5513 still has the same PCI ID.
- * Fortunately the 5513 can be 'unmasked' by fiddling with some config space
- * bits, changing its device id to the true one - 5517 for 961 and 5518 for
- * 962/963.
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#define DRV_NAME "sis5513"
-
-/* registers layout and init values are chipset family dependent */
-#undef ATA_16
-#define ATA_16 0x01
-#define ATA_33 0x02
-#define ATA_66 0x03
-#define ATA_100a 0x04 /* SiS730/SiS550 is ATA100 with ATA66 layout */
-#define ATA_100 0x05
-#define ATA_133a 0x06 /* SiS961b with 133 support */
-#define ATA_133 0x07 /* SiS962/963 */
-
-static u8 chipset_family;
-
-/*
- * Devices supported
- */
-static const struct {
- const char *name;
- u16 host_id;
- u8 chipset_family;
- u8 flags;
-} SiSHostChipInfo[] = {
- { "SiS968", PCI_DEVICE_ID_SI_968, ATA_133 },
- { "SiS966", PCI_DEVICE_ID_SI_966, ATA_133 },
- { "SiS965", PCI_DEVICE_ID_SI_965, ATA_133 },
- { "SiS745", PCI_DEVICE_ID_SI_745, ATA_100 },
- { "SiS735", PCI_DEVICE_ID_SI_735, ATA_100 },
- { "SiS733", PCI_DEVICE_ID_SI_733, ATA_100 },
- { "SiS635", PCI_DEVICE_ID_SI_635, ATA_100 },
- { "SiS633", PCI_DEVICE_ID_SI_633, ATA_100 },
-
- { "SiS730", PCI_DEVICE_ID_SI_730, ATA_100a },
- { "SiS550", PCI_DEVICE_ID_SI_550, ATA_100a },
-
- { "SiS640", PCI_DEVICE_ID_SI_640, ATA_66 },
- { "SiS630", PCI_DEVICE_ID_SI_630, ATA_66 },
- { "SiS620", PCI_DEVICE_ID_SI_620, ATA_66 },
- { "SiS540", PCI_DEVICE_ID_SI_540, ATA_66 },
- { "SiS530", PCI_DEVICE_ID_SI_530, ATA_66 },
-
- { "SiS5600", PCI_DEVICE_ID_SI_5600, ATA_33 },
- { "SiS5598", PCI_DEVICE_ID_SI_5598, ATA_33 },
- { "SiS5597", PCI_DEVICE_ID_SI_5597, ATA_33 },
- { "SiS5591/2", PCI_DEVICE_ID_SI_5591, ATA_33 },
- { "SiS5582", PCI_DEVICE_ID_SI_5582, ATA_33 },
- { "SiS5581", PCI_DEVICE_ID_SI_5581, ATA_33 },
-
- { "SiS5596", PCI_DEVICE_ID_SI_5596, ATA_16 },
- { "SiS5571", PCI_DEVICE_ID_SI_5571, ATA_16 },
- { "SiS5517", PCI_DEVICE_ID_SI_5517, ATA_16 },
- { "SiS551x", PCI_DEVICE_ID_SI_5511, ATA_16 },
-};
-
-/* Cycle time bits and values vary across chip dma capabilities
- These three arrays hold the register layout and the values to set.
- Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
-
-/* {0, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */
-static u8 cycle_time_offset[] = { 0, 0, 5, 4, 4, 0, 0 };
-static u8 cycle_time_range[] = { 0, 0, 2, 3, 3, 4, 4 };
-static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
- { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */
- { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */
- { 3, 2, 1, 0, 0, 0, 0 }, /* ATA_33 */
- { 7, 5, 3, 2, 1, 0, 0 }, /* ATA_66 */
- { 7, 5, 3, 2, 1, 0, 0 }, /* ATA_100a (730 specific),
- different cycle_time range and offset */
- { 11, 7, 5, 4, 2, 1, 0 }, /* ATA_100 */
- { 15, 10, 7, 5, 3, 2, 1 }, /* ATA_133a (earliest 691 southbridges) */
- { 15, 10, 7, 5, 3, 2, 1 }, /* ATA_133 */
-};
-/* CRC Valid Setup Time vary across IDE clock setting 33/66/100/133
- See SiS962 data sheet for more detail */
-static u8 cvs_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
- { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */
- { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */
- { 2, 1, 1, 0, 0, 0, 0 },
- { 4, 3, 2, 1, 0, 0, 0 },
- { 4, 3, 2, 1, 0, 0, 0 },
- { 6, 4, 3, 1, 1, 1, 0 },
- { 9, 6, 4, 2, 2, 2, 2 },
- { 9, 6, 4, 2, 2, 2, 2 },
-};
-/* Initialize time, Active time, Recovery time vary across
- IDE clock settings. These 3 arrays hold the register value
- for PIO0/1/2/3/4 and DMA0/1/2 mode in order */
-static u8 ini_time_value[][8] = {
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 2, 1, 0, 0, 0, 1, 0, 0 },
- { 4, 3, 1, 1, 1, 3, 1, 1 },
- { 4, 3, 1, 1, 1, 3, 1, 1 },
- { 6, 4, 2, 2, 2, 4, 2, 2 },
- { 9, 6, 3, 3, 3, 6, 3, 3 },
- { 9, 6, 3, 3, 3, 6, 3, 3 },
-};
-static u8 act_time_value[][8] = {
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 9, 9, 9, 2, 2, 7, 2, 2 },
- { 19, 19, 19, 5, 4, 14, 5, 4 },
- { 19, 19, 19, 5, 4, 14, 5, 4 },
- { 28, 28, 28, 7, 6, 21, 7, 6 },
- { 38, 38, 38, 10, 9, 28, 10, 9 },
- { 38, 38, 38, 10, 9, 28, 10, 9 },
-};
-static u8 rco_time_value[][8] = {
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 9, 2, 0, 2, 0, 7, 1, 1 },
- { 19, 5, 1, 5, 2, 16, 3, 2 },
- { 19, 5, 1, 5, 2, 16, 3, 2 },
- { 30, 9, 3, 9, 4, 25, 6, 4 },
- { 40, 12, 4, 12, 5, 34, 12, 5 },
- { 40, 12, 4, 12, 5, 34, 12, 5 },
-};
-
-/*
- * Printing configuration
- */
-/* Used for chipset type printing at boot time */
-static char *chipset_capability[] = {
- "ATA", "ATA 16",
- "ATA 33", "ATA 66",
- "ATA 100 (1st gen)", "ATA 100 (2nd gen)",
- "ATA 133 (1st gen)", "ATA 133 (2nd gen)"
-};
-
-/*
- * Configuration functions
- */
-
-static u8 sis_ata133_get_base(ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- u32 reg54 = 0;
-
- pci_read_config_dword(dev, 0x54, &reg54);
-
- return ((reg54 & 0x40000000) ? 0x70 : 0x40) + drive->dn * 4;
-}
-
-static void sis_ata16_program_timings(ide_drive_t *drive, const u8 mode)
-{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- u16 t1 = 0;
- u8 drive_pci = 0x40 + drive->dn * 2;
-
- const u16 pio_timings[] = { 0x000, 0x607, 0x404, 0x303, 0x301 };
- const u16 mwdma_timings[] = { 0x008, 0x302, 0x301 };
-
- pci_read_config_word(dev, drive_pci, &t1);
-
- /* clear active/recovery timings */
- t1 &= ~0x070f;
- if (mode >= XFER_MW_DMA_0) {
- if (chipset_family > ATA_16)
- t1 &= ~0x8000; /* disable UDMA */
- t1 |= mwdma_timings[mode - XFER_MW_DMA_0];
- } else
- t1 |= pio_timings[mode - XFER_PIO_0];
-
- pci_write_config_word(dev, drive_pci, t1);
-}
-
-static void sis_ata100_program_timings(ide_drive_t *drive, const u8 mode)
-{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- u8 t1, drive_pci = 0x40 + drive->dn * 2;
-
- /* timing bits: 7:4 active 3:0 recovery */
- const u8 pio_timings[] = { 0x00, 0x67, 0x44, 0x33, 0x31 };
- const u8 mwdma_timings[] = { 0x08, 0x32, 0x31 };
-
- if (mode >= XFER_MW_DMA_0) {
- u8 t2 = 0;
-
- pci_read_config_byte(dev, drive_pci, &t2);
- t2 &= ~0x80; /* disable UDMA */
- pci_write_config_byte(dev, drive_pci, t2);
-
- t1 = mwdma_timings[mode - XFER_MW_DMA_0];
- } else
- t1 = pio_timings[mode - XFER_PIO_0];
-
- pci_write_config_byte(dev, drive_pci + 1, t1);
-}
-
-static void sis_ata133_program_timings(ide_drive_t *drive, const u8 mode)
-{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- u32 t1 = 0;
- u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
-
- pci_read_config_dword(dev, drive_pci, &t1);
-
- t1 &= 0xc0c00fff;
- clk = (t1 & 0x08) ? ATA_133 : ATA_100;
- if (mode >= XFER_MW_DMA_0) {
- t1 &= ~0x04; /* disable UDMA */
- idx = mode - XFER_MW_DMA_0 + 5;
- } else
- idx = mode - XFER_PIO_0;
- t1 |= ini_time_value[clk][idx] << 12;
- t1 |= act_time_value[clk][idx] << 16;
- t1 |= rco_time_value[clk][idx] << 24;
-
- pci_write_config_dword(dev, drive_pci, t1);
-}
-
-static void sis_program_timings(ide_drive_t *drive, const u8 mode)
-{
- if (chipset_family < ATA_100) /* ATA_16/33/66/100a */
- sis_ata16_program_timings(drive, mode);
- else if (chipset_family < ATA_133) /* ATA_100/133a */
- sis_ata100_program_timings(drive, mode);
- else /* ATA_133 */
- sis_ata133_program_timings(drive, mode);
-}
-
-static void config_drive_art_rwp(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 reg4bh = 0;
- u8 rw_prefetch = 0;
-
- pci_read_config_byte(dev, 0x4b, &reg4bh);
-
- rw_prefetch = reg4bh & ~(0x11 << drive->dn);
-
- if (drive->media == ide_disk)
- rw_prefetch |= 0x11 << drive->dn;
-
- if (reg4bh != rw_prefetch)
- pci_write_config_byte(dev, 0x4b, rw_prefetch);
-}
-
-static void sis_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- config_drive_art_rwp(drive);
- sis_program_timings(drive, drive->pio_mode);
-}
-
-static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode)
-{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- u32 regdw = 0;
- u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
-
- pci_read_config_dword(dev, drive_pci, &regdw);
-
- regdw |= 0x04;
- regdw &= 0xfffff00f;
- /* check if ATA133 enable */
- clk = (regdw & 0x08) ? ATA_133 : ATA_100;
- idx = mode - XFER_UDMA_0;
- regdw |= cycle_time_value[clk][idx] << 4;
- regdw |= cvs_time_value[clk][idx] << 8;
-
- pci_write_config_dword(dev, drive_pci, regdw);
-}
-
-static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode)
-{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family;
-
- pci_read_config_byte(dev, drive_pci + 1, &reg);
-
- /* force the UDMA bit on if we want to use UDMA */
- reg |= 0x80;
- /* clean reg cycle time bits */
- reg &= ~((0xff >> (8 - cycle_time_range[i])) << cycle_time_offset[i]);
- /* set reg cycle time bits */
- reg |= cycle_time_value[i][mode - XFER_UDMA_0] << cycle_time_offset[i];
-
- pci_write_config_byte(dev, drive_pci + 1, reg);
-}
-
-static void sis_program_udma_timings(ide_drive_t *drive, const u8 mode)
-{
- if (chipset_family >= ATA_133) /* ATA_133 */
- sis_ata133_program_udma_timings(drive, mode);
- else /* ATA_33/66/100a/100/133a */
- sis_ata33_program_udma_timings(drive, mode);
-}
-
-static void sis_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- const u8 speed = drive->dma_mode;
-
- if (speed >= XFER_UDMA_0)
- sis_program_udma_timings(drive, speed);
- else
- sis_program_timings(drive, speed);
-}
-
-static u8 sis_ata133_udma_filter(ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- u32 regdw = 0;
- u8 drive_pci = sis_ata133_get_base(drive);
-
- pci_read_config_dword(dev, drive_pci, &regdw);
-
- /* if ATA133 disable, we should not set speed above UDMA5 */
- return (regdw & 0x08) ? ATA_UDMA6 : ATA_UDMA5;
-}
-
-static int sis_find_family(struct pci_dev *dev)
-{
- struct pci_dev *host;
- int i = 0;
-
- chipset_family = 0;
-
- for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !chipset_family; i++) {
-
- host = pci_get_device(PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL);
-
- if (!host)
- continue;
-
- chipset_family = SiSHostChipInfo[i].chipset_family;
-
- /* Special case for SiS630 : 630S/ET is ATA_100a */
- if (SiSHostChipInfo[i].host_id == PCI_DEVICE_ID_SI_630) {
- if (host->revision >= 0x30)
- chipset_family = ATA_100a;
- }
- pci_dev_put(host);
-
- printk(KERN_INFO DRV_NAME " %s: %s %s controller\n",
- pci_name(dev), SiSHostChipInfo[i].name,
- chipset_capability[chipset_family]);
- }
-
- if (!chipset_family) { /* Belongs to pci-quirks */
-
- u32 idemisc;
- u16 trueid;
-
- /* Disable ID masking and register remapping */
- pci_read_config_dword(dev, 0x54, &idemisc);
- pci_write_config_dword(dev, 0x54, (idemisc & 0x7fffffff));
- pci_read_config_word(dev, PCI_DEVICE_ID, &trueid);
- pci_write_config_dword(dev, 0x54, idemisc);
-
- if (trueid == 0x5518) {
- printk(KERN_INFO DRV_NAME " %s: SiS 962/963 MuTIOL IDE UDMA133 controller\n",
- pci_name(dev));
- chipset_family = ATA_133;
-
- /* Check for 5513 compatibility mapping
- * We must use this, else the port enabled code will fail,
- * as it expects the enablebits at 0x4a.
- */
- if ((idemisc & 0x40000000) == 0) {
- pci_write_config_dword(dev, 0x54, idemisc | 0x40000000);
- printk(KERN_INFO DRV_NAME " %s: Switching to 5513 register mapping\n",
- pci_name(dev));
- }
- }
- }
-
- if (!chipset_family) { /* Belongs to pci-quirks */
-
- struct pci_dev *lpc_bridge;
- u16 trueid;
- u8 prefctl;
- u8 idecfg;
-
- pci_read_config_byte(dev, 0x4a, &idecfg);
- pci_write_config_byte(dev, 0x4a, idecfg | 0x10);
- pci_read_config_word(dev, PCI_DEVICE_ID, &trueid);
- pci_write_config_byte(dev, 0x4a, idecfg);
-
- if (trueid == 0x5517) { /* SiS 961/961B */
-
- lpc_bridge = pci_get_slot(dev->bus, 0x10); /* Bus 0, Dev 2, Fn 0 */
- pci_read_config_byte(dev, 0x49, &prefctl);
- pci_dev_put(lpc_bridge);
-
- if (lpc_bridge->revision == 0x10 && (prefctl & 0x80)) {
- printk(KERN_INFO DRV_NAME " %s: SiS 961B MuTIOL IDE UDMA133 controller\n",
- pci_name(dev));
- chipset_family = ATA_133a;
- } else {
- printk(KERN_INFO DRV_NAME " %s: SiS 961 MuTIOL IDE UDMA100 controller\n",
- pci_name(dev));
- chipset_family = ATA_100;
- }
- }
- }
-
- return chipset_family;
-}
-
-static int init_chipset_sis5513(struct pci_dev *dev)
-{
- /* Make general config ops here
- 1/ tell IDE channels to operate in Compatibility mode only
- 2/ tell old chips to allow per drive IDE timings */
-
- u8 reg;
- u16 regw;
-
- switch (chipset_family) {
- case ATA_133:
- /* SiS962 operation mode */
- pci_read_config_word(dev, 0x50, &regw);
- if (regw & 0x08)
- pci_write_config_word(dev, 0x50, regw&0xfff7);
- pci_read_config_word(dev, 0x52, &regw);
- if (regw & 0x08)
- pci_write_config_word(dev, 0x52, regw&0xfff7);
- break;
- case ATA_133a:
- case ATA_100:
- /* Fixup latency */
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
- /* Set compatibility bit */
- pci_read_config_byte(dev, 0x49, &reg);
- if (!(reg & 0x01))
- pci_write_config_byte(dev, 0x49, reg|0x01);
- break;
- case ATA_100a:
- case ATA_66:
- /* Fixup latency */
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10);
-
- /* On ATA_66 chips the bit was elsewhere */
- pci_read_config_byte(dev, 0x52, &reg);
- if (!(reg & 0x04))
- pci_write_config_byte(dev, 0x52, reg|0x04);
- break;
- case ATA_33:
- /* On ATA_33 we didn't have a single bit to set */
- pci_read_config_byte(dev, 0x09, &reg);
- if ((reg & 0x0f) != 0x00)
- pci_write_config_byte(dev, 0x09, reg&0xf0);
- fallthrough;
- case ATA_16:
- /* force per drive recovery and active timings
- needed on ATA_33 and below chips */
- pci_read_config_byte(dev, 0x52, &reg);
- if (!(reg & 0x08))
- pci_write_config_byte(dev, 0x52, reg|0x08);
- break;
- }
-
- return 0;
-}
-
-struct sis_laptop {
- u16 device;
- u16 subvendor;
- u16 subdevice;
-};
-
-static const struct sis_laptop sis_laptop[] = {
- /* devid, subvendor, subdev */
- { 0x5513, 0x1043, 0x1107 }, /* ASUS A6K */
- { 0x5513, 0x1734, 0x105f }, /* FSC Amilo A1630 */
- { 0x5513, 0x1071, 0x8640 }, /* EasyNote K5305 */
- /* end marker */
- { 0, }
-};
-
-static u8 sis_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *pdev = to_pci_dev(hwif->dev);
- const struct sis_laptop *lap = &sis_laptop[0];
- u8 ata66 = 0;
-
- while (lap->device) {
- if (lap->device == pdev->device &&
- lap->subvendor == pdev->subsystem_vendor &&
- lap->subdevice == pdev->subsystem_device)
- return ATA_CBL_PATA40_SHORT;
- lap++;
- }
-
- if (chipset_family >= ATA_133) {
- u16 regw = 0;
- u16 reg_addr = hwif->channel ? 0x52: 0x50;
- pci_read_config_word(pdev, reg_addr, &regw);
- ata66 = (regw & 0x8000) ? 0 : 1;
- } else if (chipset_family >= ATA_66) {
- u8 reg48h = 0;
- u8 mask = hwif->channel ? 0x20 : 0x10;
- pci_read_config_byte(pdev, 0x48, &reg48h);
- ata66 = (reg48h & mask) ? 0 : 1;
- }
-
- return ata66 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
-}
-
-static const struct ide_port_ops sis_port_ops = {
- .set_pio_mode = sis_set_pio_mode,
- .set_dma_mode = sis_set_dma_mode,
- .cable_detect = sis_cable_detect,
-};
-
-static const struct ide_port_ops sis_ata133_port_ops = {
- .set_pio_mode = sis_set_pio_mode,
- .set_dma_mode = sis_set_dma_mode,
- .udma_filter = sis_ata133_udma_filter,
- .cable_detect = sis_cable_detect,
-};
-
-static const struct ide_port_info sis5513_chipset = {
- .name = DRV_NAME,
- .init_chipset = init_chipset_sis5513,
- .enablebits = { {0x4a, 0x02, 0x02}, {0x4a, 0x04, 0x04} },
- .host_flags = IDE_HFLAG_NO_AUTODMA,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
-};
-
-static int sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct ide_port_info d = sis5513_chipset;
- u8 udma_rates[] = { 0x00, 0x00, 0x07, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f };
- int rc;
-
- rc = pci_enable_device(dev);
- if (rc)
- return rc;
-
- if (sis_find_family(dev) == 0)
- return -ENOTSUPP;
-
- if (chipset_family >= ATA_133)
- d.port_ops = &sis_ata133_port_ops;
- else
- d.port_ops = &sis_port_ops;
-
- d.udma_mask = udma_rates[chipset_family];
-
- return ide_pci_init_one(dev, &d, NULL);
-}
-
-static void sis5513_remove(struct pci_dev *dev)
-{
- ide_pci_remove(dev);
- pci_disable_device(dev);
-}
-
-static const struct pci_device_id sis5513_pci_tbl[] = {
- { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_5513), 0 },
- { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_5518), 0 },
- { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_1180), 0 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, sis5513_pci_tbl);
-
-static struct pci_driver sis5513_pci_driver = {
- .name = "SIS_IDE",
- .id_table = sis5513_pci_tbl,
- .probe = sis5513_init_one,
- .remove = sis5513_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init sis5513_ide_init(void)
-{
- return ide_pci_register_driver(&sis5513_pci_driver);
-}
-
-static void __exit sis5513_ide_exit(void)
-{
- pci_unregister_driver(&sis5513_pci_driver);
-}
-
-module_init(sis5513_ide_init);
-module_exit(sis5513_ide_exit);
-
-MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick, Vojtech Pavlik");
-MODULE_DESCRIPTION("PCI driver module for SIS IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
deleted file mode 100644
index 5c24c420c438..000000000000
--- a/drivers/ide/sl82c105.c
+++ /dev/null
@@ -1,367 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * SL82C105/Winbond 553 IDE driver
- *
- * Maintainer unknown.
- *
- * Drive tuning added from Rebel.com's kernel sources
- * -- Russell King (15/11/98) linux@arm.linux.org.uk
- *
- * Merge in Russell's HW workarounds, fix various problems
- * with the timing registers setup.
- * -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org
- *
- * Copyright (C) 2006-2007,2009 MontaVista Software, Inc. <source@mvista.com>
- * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "sl82c105"
-
-/*
- * SL82C105 PCI config register 0x40 bits.
- */
-#define CTRL_IDE_IRQB (1 << 30)
-#define CTRL_IDE_IRQA (1 << 28)
-#define CTRL_LEGIRQ (1 << 11)
-#define CTRL_P1F16 (1 << 5)
-#define CTRL_P1EN (1 << 4)
-#define CTRL_P0F16 (1 << 1)
-#define CTRL_P0EN (1 << 0)
-
-/*
- * Convert a PIO mode and cycle time to the required on/off times
- * for the interface. This has protection against runaway timings.
- */
-static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
-{
- struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
- unsigned int cmd_on, cmd_off;
- u8 iordy = 0;
-
- cmd_on = (t->active + 29) / 30;
- cmd_off = (ide_pio_cycle_time(drive, pio) - 30 * cmd_on + 29) / 30;
-
- if (cmd_on == 0)
- cmd_on = 1;
-
- if (cmd_off == 0)
- cmd_off = 1;
-
- if (ide_pio_need_iordy(drive, pio))
- iordy = 0x40;
-
- return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy;
-}
-
-/*
- * Configure the chipset for PIO mode.
- */
-static void sl82c105_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long timings = (unsigned long)ide_get_drivedata(drive);
- int reg = 0x44 + drive->dn * 4;
- u16 drv_ctrl;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
-
- drv_ctrl = get_pio_timings(drive, pio);
-
- /*
- * Store the PIO timings so that we can restore them
- * in case DMA will be turned off...
- */
- timings &= 0xffff0000;
- timings |= drv_ctrl;
- ide_set_drivedata(drive, (void *)timings);
-
- pci_write_config_word(dev, reg, drv_ctrl);
- pci_read_config_word (dev, reg, &drv_ctrl);
-
- printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
- ide_xfer_verbose(pio + XFER_PIO_0),
- ide_pio_cycle_time(drive, pio), drv_ctrl);
-}
-
-/*
- * Configure the chipset for DMA mode.
- */
-static void sl82c105_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200};
- unsigned long timings = (unsigned long)ide_get_drivedata(drive);
- u16 drv_ctrl;
- const u8 speed = drive->dma_mode;
-
- drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0];
-
- /*
- * Store the DMA timings so that we can actually program
- * them when DMA will be turned on...
- */
- timings &= 0x0000ffff;
- timings |= (unsigned long)drv_ctrl << 16;
- ide_set_drivedata(drive, (void *)timings);
-}
-
-static int sl82c105_test_irq(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
-
- pci_read_config_dword(dev, 0x40, &val);
-
- return (val & mask) ? 1 : 0;
-}
-
-/*
- * The SL82C105 holds off all IDE interrupts while in DMA mode until
- * all DMA activity is completed. Sometimes this causes problems (eg,
- * when the drive wants to report an error condition).
- *
- * 0x7e is a "chip testing" register. Bit 2 resets the DMA controller
- * state machine. We need to kick this to work around various bugs.
- */
-static inline void sl82c105_reset_host(struct pci_dev *dev)
-{
- u16 val;
-
- pci_read_config_word(dev, 0x7e, &val);
- pci_write_config_word(dev, 0x7e, val | (1 << 2));
- pci_write_config_word(dev, 0x7e, val & ~(1 << 2));
-}
-
-/*
- * If we get an IRQ timeout, it might be that the DMA state machine
- * got confused. Fix from Todd Inglett. Details from Winbond.
- *
- * This function is called when the IDE timer expires, the drive
- * indicates that it is READY, and we were waiting for DMA to complete.
- */
-static void sl82c105_dma_lost_irq(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
- u8 dma_cmd;
-
- printk(KERN_WARNING "sl82c105: lost IRQ, resetting host\n");
-
- /*
- * Check the raw interrupt from the drive.
- */
- pci_read_config_dword(dev, 0x40, &val);
- if (val & mask)
- printk(KERN_INFO "sl82c105: drive was requesting IRQ, "
- "but host lost it\n");
-
- /*
- * Was DMA enabled? If so, disable it - we're resetting the
- * host. The IDE layer will be handling the drive for us.
- */
- dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
- if (dma_cmd & 1) {
- outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
- printk(KERN_INFO "sl82c105: DMA was enabled\n");
- }
-
- sl82c105_reset_host(dev);
-}
-
-/*
- * ATAPI devices can cause the SL82C105 DMA state machine to go gaga.
- * Winbond recommend that the DMA state machine is reset prior to
- * setting the bus master DMA enable bit.
- *
- * The generic IDE core will have disabled the BMEN bit before this
- * function is called.
- */
-static void sl82c105_dma_start(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- int reg = 0x44 + drive->dn * 4;
-
- pci_write_config_word(dev, reg,
- (unsigned long)ide_get_drivedata(drive) >> 16);
-
- sl82c105_reset_host(dev);
- ide_dma_start(drive);
-}
-
-static void sl82c105_dma_clear(ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
-
- sl82c105_reset_host(dev);
-}
-
-static int sl82c105_dma_end(ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- int reg = 0x44 + drive->dn * 4;
- int ret = ide_dma_end(drive);
-
- pci_write_config_word(dev, reg,
- (unsigned long)ide_get_drivedata(drive));
-
- return ret;
-}
-
-/*
- * ATA reset will clear the 16 bits mode in the control
- * register, we need to reprogram it
- */
-static void sl82c105_resetproc(ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
- u32 val;
-
- pci_read_config_dword(dev, 0x40, &val);
- val |= (CTRL_P1F16 | CTRL_P0F16);
- pci_write_config_dword(dev, 0x40, val);
-}
-
-/*
- * Return the revision of the Winbond bridge
- * which this function is part of.
- */
-static u8 sl82c105_bridge_revision(struct pci_dev *dev)
-{
- struct pci_dev *bridge;
-
- /*
- * The bridge should be part of the same device, but function 0.
- */
- bridge = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus),
- dev->bus->number,
- PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
- if (!bridge)
- return -1;
-
- /*
- * Make sure it is a Winbond 553 and is an ISA bridge.
- */
- if (bridge->vendor != PCI_VENDOR_ID_WINBOND ||
- bridge->device != PCI_DEVICE_ID_WINBOND_83C553 ||
- bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA) {
- pci_dev_put(bridge);
- return -1;
- }
- /*
- * We need to find function 0's revision, not function 1
- */
- pci_dev_put(bridge);
-
- return bridge->revision;
-}
-
-/*
- * Enable the PCI device
- *
- * --BenH: It's arch fixup code that should enable channels that
- * have not been enabled by firmware. I decided we can still enable
- * channel 0 here at least, but channel 1 has to be enabled by
- * firmware or arch code. We still set both to 16 bits mode.
- */
-static int init_chipset_sl82c105(struct pci_dev *dev)
-{
- u32 val;
-
- pci_read_config_dword(dev, 0x40, &val);
- val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
- pci_write_config_dword(dev, 0x40, val);
-
- return 0;
-}
-
-static const struct ide_port_ops sl82c105_port_ops = {
- .set_pio_mode = sl82c105_set_pio_mode,
- .set_dma_mode = sl82c105_set_dma_mode,
- .resetproc = sl82c105_resetproc,
- .test_irq = sl82c105_test_irq,
-};
-
-static const struct ide_dma_ops sl82c105_dma_ops = {
- .dma_host_set = ide_dma_host_set,
- .dma_setup = ide_dma_setup,
- .dma_start = sl82c105_dma_start,
- .dma_end = sl82c105_dma_end,
- .dma_test_irq = ide_dma_test_irq,
- .dma_lost_irq = sl82c105_dma_lost_irq,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_clear = sl82c105_dma_clear,
- .dma_sff_read_status = ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info sl82c105_chipset = {
- .name = DRV_NAME,
- .init_chipset = init_chipset_sl82c105,
- .enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
- .port_ops = &sl82c105_port_ops,
- .dma_ops = &sl82c105_dma_ops,
- .host_flags = IDE_HFLAG_IO_32BIT |
- IDE_HFLAG_UNMASK_IRQS |
- IDE_HFLAG_SERIALIZE_DMA |
- IDE_HFLAG_NO_AUTODMA,
- .pio_mask = ATA_PIO5,
- .mwdma_mask = ATA_MWDMA2,
-};
-
-static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct ide_port_info d = sl82c105_chipset;
- u8 rev = sl82c105_bridge_revision(dev);
-
- if (rev <= 5) {
- /*
- * Never ever EVER under any circumstances enable
- * DMA when the bridge is this old.
- */
- printk(KERN_INFO DRV_NAME ": Winbond W83C553 bridge "
- "revision %d, BM-DMA disabled\n", rev);
- d.dma_ops = NULL;
- d.mwdma_mask = 0;
- d.host_flags &= ~IDE_HFLAG_SERIALIZE_DMA;
- }
-
- return ide_pci_init_one(dev, &d, NULL);
-}
-
-static const struct pci_device_id sl82c105_pci_tbl[] = {
- { PCI_VDEVICE(WINBOND, PCI_DEVICE_ID_WINBOND_82C105), 0 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl);
-
-static struct pci_driver sl82c105_pci_driver = {
- .name = "W82C105_IDE",
- .id_table = sl82c105_pci_tbl,
- .probe = sl82c105_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init sl82c105_ide_init(void)
-{
- return ide_pci_register_driver(&sl82c105_pci_driver);
-}
-
-static void __exit sl82c105_ide_exit(void)
-{
- pci_unregister_driver(&sl82c105_pci_driver);
-}
-
-module_init(sl82c105_ide_init);
-module_exit(sl82c105_ide_exit);
-
-MODULE_DESCRIPTION("PCI driver module for W82C105 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c
deleted file mode 100644
index f521d5ebf916..000000000000
--- a/drivers/ide/slc90e66.c
+++ /dev/null
@@ -1,182 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
- *
- * This is a look-alike variation of the ICH0 PIIX4 Ultra-66,
- * but this keeps the ISA-Bridge and slots alive.
- *
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "slc90e66"
-
-static DEFINE_SPINLOCK(slc90e66_lock);
-
-static void slc90e66_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- int is_slave = drive->dn & 1;
- int master_port = hwif->channel ? 0x42 : 0x40;
- int slave_port = 0x44;
- unsigned long flags;
- u16 master_data;
- u8 slave_data;
- int control = 0;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
-
- /* ISP RTC */
- static const u8 timings[][2] = {
- { 0, 0 },
- { 0, 0 },
- { 1, 0 },
- { 2, 1 },
- { 2, 3 }, };
-
- spin_lock_irqsave(&slc90e66_lock, flags);
- pci_read_config_word(dev, master_port, &master_data);
-
- if (pio > 1)
- control |= 1; /* Programmable timing on */
- if (drive->media == ide_disk)
- control |= 4; /* Prefetch, post write */
- if (ide_pio_need_iordy(drive, pio))
- control |= 2; /* IORDY */
- if (is_slave) {
- master_data |= 0x4000;
- master_data &= ~0x0070;
- if (pio > 1) {
- /* Set PPE, IE and TIME */
- master_data |= control << 4;
- }
- pci_read_config_byte(dev, slave_port, &slave_data);
- slave_data &= hwif->channel ? 0x0f : 0xf0;
- slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) <<
- (hwif->channel ? 4 : 0);
- } else {
- master_data &= ~0x3307;
- if (pio > 1) {
- /* enable PPE, IE and TIME */
- master_data |= control;
- }
- master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
- }
- pci_write_config_word(dev, master_port, master_data);
- if (is_slave)
- pci_write_config_byte(dev, slave_port, slave_data);
- spin_unlock_irqrestore(&slc90e66_lock, flags);
-}
-
-static void slc90e66_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 maslave = hwif->channel ? 0x42 : 0x40;
- int sitre = 0, a_speed = 7 << (drive->dn * 4);
- int u_speed = 0, u_flag = 1 << drive->dn;
- u16 reg4042, reg44, reg48, reg4a;
- const u8 speed = drive->dma_mode;
-
- pci_read_config_word(dev, maslave, &reg4042);
- sitre = (reg4042 & 0x4000) ? 1 : 0;
- pci_read_config_word(dev, 0x44, &reg44);
- pci_read_config_word(dev, 0x48, &reg48);
- pci_read_config_word(dev, 0x4a, &reg4a);
-
- if (speed >= XFER_UDMA_0) {
- u_speed = (speed - XFER_UDMA_0) << (drive->dn * 4);
-
- if (!(reg48 & u_flag))
- pci_write_config_word(dev, 0x48, reg48|u_flag);
- if ((reg4a & a_speed) != u_speed) {
- pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
- pci_read_config_word(dev, 0x4a, &reg4a);
- pci_write_config_word(dev, 0x4a, reg4a|u_speed);
- }
- } else {
- const u8 mwdma_to_pio[] = { 0, 3, 4 };
-
- if (reg48 & u_flag)
- pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
- if (reg4a & a_speed)
- pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-
- if (speed >= XFER_MW_DMA_0)
- drive->pio_mode =
- mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0;
- else
- drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */
-
- slc90e66_set_pio_mode(hwif, drive);
- }
-}
-
-static u8 slc90e66_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u8 reg47 = 0, mask = hwif->channel ? 0x01 : 0x02;
-
- pci_read_config_byte(dev, 0x47, &reg47);
-
- /* bit[0(1)]: 0:80, 1:40 */
- return (reg47 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-}
-
-static const struct ide_port_ops slc90e66_port_ops = {
- .set_pio_mode = slc90e66_set_pio_mode,
- .set_dma_mode = slc90e66_set_dma_mode,
- .cable_detect = slc90e66_cable_detect,
-};
-
-static const struct ide_port_info slc90e66_chipset = {
- .name = DRV_NAME,
- .enablebits = { {0x41, 0x80, 0x80}, {0x43, 0x80, 0x80} },
- .port_ops = &slc90e66_port_ops,
- .pio_mask = ATA_PIO4,
- .swdma_mask = ATA_SWDMA2_ONLY,
- .mwdma_mask = ATA_MWDMA12_ONLY,
- .udma_mask = ATA_UDMA4,
-};
-
-static int slc90e66_init_one(struct pci_dev *dev,
- const struct pci_device_id *id)
-{
- return ide_pci_init_one(dev, &slc90e66_chipset, NULL);
-}
-
-static const struct pci_device_id slc90e66_pci_tbl[] = {
- { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1), 0 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl);
-
-static struct pci_driver slc90e66_pci_driver = {
- .name = "SLC90e66_IDE",
- .id_table = slc90e66_pci_tbl,
- .probe = slc90e66_init_one,
- .remove = ide_pci_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init slc90e66_ide_init(void)
-{
- return ide_pci_register_driver(&slc90e66_pci_driver);
-}
-
-static void __exit slc90e66_ide_exit(void)
-{
- pci_unregister_driver(&slc90e66_pci_driver);
-}
-
-module_init(slc90e66_ide_init);
-module_exit(slc90e66_ide_exit);
-
-MODULE_AUTHOR("Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for SLC90E66 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/tc86c001.c b/drivers/ide/tc86c001.c
deleted file mode 100644
index 17e6132b99bf..000000000000
--- a/drivers/ide/tc86c001.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2002 Toshiba Corporation
- * Copyright (C) 2005-2006 MontaVista Software, Inc. <source@mvista.com>
- *
- * 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/types.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/module.h>
-
-#define DRV_NAME "tc86c001"
-
-static void tc86c001_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00);
- u16 mode, scr = inw(scr_port);
- const u8 speed = drive->dma_mode;
-
- switch (speed) {
- case XFER_UDMA_4: mode = 0x00c0; break;
- case XFER_UDMA_3: mode = 0x00b0; break;
- case XFER_UDMA_2: mode = 0x00a0; break;
- case XFER_UDMA_1: mode = 0x0090; break;
- case XFER_UDMA_0: mode = 0x0080; break;
- case XFER_MW_DMA_2: mode = 0x0070; break;
- case XFER_MW_DMA_1: mode = 0x0060; break;
- case XFER_MW_DMA_0: mode = 0x0050; break;
- case XFER_PIO_4: mode = 0x0400; break;
- case XFER_PIO_3: mode = 0x0300; break;
- case XFER_PIO_2: mode = 0x0200; break;
- case XFER_PIO_1: mode = 0x0100; break;
- case XFER_PIO_0:
- default: mode = 0x0000; break;
- }
-
- scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f;
- scr |= mode;
- outw(scr, scr_port);
-}
-
-static void tc86c001_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- drive->dma_mode = drive->pio_mode;
- tc86c001_set_mode(hwif, drive);
-}
-
-/*
- * HACKITY HACK
- *
- * This is a workaround for the limitation 5 of the TC86C001 IDE controller:
- * if a DMA transfer terminates prematurely, the controller leaves the device's
- * interrupt request (INTRQ) pending and does not generate a PCI interrupt (or
- * set the interrupt bit in the DMA status register), thus no PCI interrupt
- * will occur until a DMA transfer has been successfully completed.
- *
- * We work around this by initiating dummy, zero-length DMA transfer on
- * a DMA timeout expiration. I found no better way to do this with the current
- * IDE core than to temporarily replace a higher level driver's timer expiry
- * handler with our own backing up to that handler in case our recovery fails.
- */
-static int tc86c001_timer_expiry(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- ide_expiry_t *expiry = ide_get_hwifdata(hwif);
- u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
-
- /* Restore a higher level driver's expiry handler first. */
- hwif->expiry = expiry;
-
- if ((dma_stat & 5) == 1) { /* DMA active and no interrupt */
- unsigned long sc_base = hwif->config_data;
- unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
- u8 dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
-
- printk(KERN_WARNING "%s: DMA interrupt possibly stuck, "
- "attempting recovery...\n", drive->name);
-
- /* Stop DMA */
- outb(dma_cmd & ~0x01, hwif->dma_base + ATA_DMA_CMD);
-
- /* Setup the dummy DMA transfer */
- outw(0, sc_base + 0x0a); /* Sector Count */
- outw(0, twcr_port); /* Transfer Word Count 1 or 2 */
-
- /* Start the dummy DMA transfer */
-
- /* clear R_OR_WCTR for write */
- outb(0x00, hwif->dma_base + ATA_DMA_CMD);
- /* set START_STOPBM */
- outb(0x01, hwif->dma_base + ATA_DMA_CMD);
-
- /*
- * If an interrupt was pending, it should come thru shortly.
- * If not, a higher level driver's expiry handler should
- * eventually cause some kind of recovery from the DMA stall.
- */
- return WAIT_MIN_SLEEP;
- }
-
- /* Chain to the restored expiry handler if DMA wasn't active. */
- if (likely(expiry != NULL))
- return expiry(drive);
-
- /* If there was no handler, "emulate" that for ide_timer_expiry()... */
- return -1;
-}
-
-static void tc86c001_dma_start(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- unsigned long sc_base = hwif->config_data;
- unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
- unsigned long nsectors = blk_rq_sectors(hwif->rq);
-
- /*
- * We have to manually load the sector count and size into
- * the appropriate system control registers for DMA to work
- * with LBA48 and ATAPI devices...
- */
- outw(nsectors, sc_base + 0x0a); /* Sector Count */
- outw(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */
-
- /* Install our timeout expiry hook, saving the current handler... */
- ide_set_hwifdata(hwif, hwif->expiry);
- hwif->expiry = &tc86c001_timer_expiry;
-
- ide_dma_start(drive);
-}
-
-static u8 tc86c001_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long sc_base = pci_resource_start(dev, 5);
- u16 scr1 = inw(sc_base + 0x00);
-
- /*
- * System Control 1 Register bit 13 (PDIAGN):
- * 0=80-pin cable, 1=40-pin cable
- */
- return (scr1 & 0x2000) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-}
-
-static void init_hwif_tc86c001(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long sc_base = pci_resource_start(dev, 5);
- u16 scr1 = inw(sc_base + 0x00);
-
- /* System Control 1 Register bit 15 (Soft Reset) set */
- outw(scr1 | 0x8000, sc_base + 0x00);
-
- /* System Control 1 Register bit 14 (FIFO Reset) set */
- outw(scr1 | 0x4000, sc_base + 0x00);
-
- /* System Control 1 Register: reset clear */
- outw(scr1 & ~0xc000, sc_base + 0x00);
-
- /* Store the system control register base for convenience... */
- hwif->config_data = sc_base;
-
- if (!hwif->dma_base)
- return;
-
- /*
- * Sector Count Control Register bits 0 and 1 set:
- * software sets Sector Count Register for master and slave device
- */
- outw(0x0003, sc_base + 0x0c);
-
- /* Sector Count Register limit */
- hwif->rqsize = 0xffff;
-}
-
-static const struct ide_port_ops tc86c001_port_ops = {
- .set_pio_mode = tc86c001_set_pio_mode,
- .set_dma_mode = tc86c001_set_mode,
- .cable_detect = tc86c001_cable_detect,
-};
-
-static const struct ide_dma_ops tc86c001_dma_ops = {
- .dma_host_set = ide_dma_host_set,
- .dma_setup = ide_dma_setup,
- .dma_start = tc86c001_dma_start,
- .dma_end = ide_dma_end,
- .dma_test_irq = ide_dma_test_irq,
- .dma_lost_irq = ide_dma_lost_irq,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_sff_read_status = ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info tc86c001_chipset = {
- .name = DRV_NAME,
- .init_hwif = init_hwif_tc86c001,
- .port_ops = &tc86c001_port_ops,
- .dma_ops = &tc86c001_dma_ops,
- .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA4,
-};
-
-static int tc86c001_init_one(struct pci_dev *dev,
- const struct pci_device_id *id)
-{
- int rc;
-
- rc = pci_enable_device(dev);
- if (rc)
- goto out;
-
- rc = pci_request_region(dev, 5, DRV_NAME);
- if (rc) {
- printk(KERN_ERR DRV_NAME ": system control regs already in use");
- goto out_disable;
- }
-
- rc = ide_pci_init_one(dev, &tc86c001_chipset, NULL);
- if (rc)
- goto out_release;
-
- goto out;
-
-out_release:
- pci_release_region(dev, 5);
-out_disable:
- pci_disable_device(dev);
-out:
- return rc;
-}
-
-static void tc86c001_remove(struct pci_dev *dev)
-{
- ide_pci_remove(dev);
- pci_release_region(dev, 5);
- pci_disable_device(dev);
-}
-
-static const struct pci_device_id tc86c001_pci_tbl[] = {
- { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE), 0 },
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl);
-
-static struct pci_driver tc86c001_pci_driver = {
- .name = "TC86C001",
- .id_table = tc86c001_pci_tbl,
- .probe = tc86c001_init_one,
- .remove = tc86c001_remove,
-};
-
-static int __init tc86c001_ide_init(void)
-{
- return ide_pci_register_driver(&tc86c001_pci_driver);
-}
-
-static void __exit tc86c001_ide_exit(void)
-{
- pci_unregister_driver(&tc86c001_pci_driver);
-}
-
-module_init(tc86c001_ide_init);
-module_exit(tc86c001_ide_exit);
-
-MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
-MODULE_DESCRIPTION("PCI driver module for TC86C001 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/triflex.c b/drivers/ide/triflex.c
deleted file mode 100644
index 16ddd0956832..000000000000
--- a/drivers/ide/triflex.c
+++ /dev/null
@@ -1,143 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * IDE Chipset driver for the Compaq TriFlex IDE controller.
- *
- * Known to work with the Compaq Workstation 5x00 series.
- *
- * Copyright (C) 2002 Hewlett-Packard Development Group, L.P.
- * Author: Torben Mathiasen <torben.mathiasen@hp.com>
- *
- * Loosely based on the piix & svwks drivers.
- *
- * Documentation:
- * Not publicly available.
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#define DRV_NAME "triflex"
-
-static void triflex_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- u32 triflex_timings = 0;
- u16 timing = 0;
- u8 channel_offset = hwif->channel ? 0x74 : 0x70, unit = drive->dn & 1;
-
- pci_read_config_dword(dev, channel_offset, &triflex_timings);
-
- switch (drive->dma_mode) {
- case XFER_MW_DMA_2:
- timing = 0x0103;
- break;
- case XFER_MW_DMA_1:
- timing = 0x0203;
- break;
- case XFER_MW_DMA_0:
- timing = 0x0808;
- break;
- case XFER_SW_DMA_2:
- case XFER_SW_DMA_1:
- case XFER_SW_DMA_0:
- timing = 0x0f0f;
- break;
- case XFER_PIO_4:
- timing = 0x0202;
- break;
- case XFER_PIO_3:
- timing = 0x0204;
- break;
- case XFER_PIO_2:
- timing = 0x0404;
- break;
- case XFER_PIO_1:
- timing = 0x0508;
- break;
- case XFER_PIO_0:
- timing = 0x0808;
- break;
- }
-
- triflex_timings &= ~(0xFFFF << (16 * unit));
- triflex_timings |= (timing << (16 * unit));
-
- pci_write_config_dword(dev, channel_offset, triflex_timings);
-}
-
-static void triflex_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- drive->dma_mode = drive->pio_mode;
- triflex_set_mode(hwif, drive);
-}
-
-static const struct ide_port_ops triflex_port_ops = {
- .set_pio_mode = triflex_set_pio_mode,
- .set_dma_mode = triflex_set_mode,
-};
-
-static const struct ide_port_info triflex_device = {
- .name = DRV_NAME,
- .enablebits = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}},
- .port_ops = &triflex_port_ops,
- .pio_mask = ATA_PIO4,
- .swdma_mask = ATA_SWDMA2,
- .mwdma_mask = ATA_MWDMA2,
-};
-
-static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- return ide_pci_init_one(dev, &triflex_device, NULL);
-}
-
-static const struct pci_device_id triflex_pci_tbl[] = {
- { PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), 0 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, triflex_pci_tbl);
-
-#ifdef CONFIG_PM
-static int triflex_ide_pci_suspend(struct pci_dev *dev, pm_message_t state)
-{
- /*
- * We must not disable or powerdown the device.
- * APM bios refuses to suspend if IDE is not accessible.
- */
- pci_save_state(dev);
- return 0;
-}
-#else
-#define triflex_ide_pci_suspend NULL
-#endif
-
-static struct pci_driver triflex_pci_driver = {
- .name = "TRIFLEX_IDE",
- .id_table = triflex_pci_tbl,
- .probe = triflex_init_one,
- .remove = ide_pci_remove,
- .suspend = triflex_ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init triflex_ide_init(void)
-{
- return ide_pci_register_driver(&triflex_pci_driver);
-}
-
-static void __exit triflex_ide_exit(void)
-{
- pci_unregister_driver(&triflex_pci_driver);
-}
-
-module_init(triflex_ide_init);
-module_exit(triflex_ide_exit);
-
-MODULE_AUTHOR("Torben Mathiasen");
-MODULE_DESCRIPTION("PCI driver module for Compaq Triflex IDE");
-MODULE_LICENSE("GPL");
-
-
diff --git a/drivers/ide/trm290.c b/drivers/ide/trm290.c
deleted file mode 100644
index d550b379b0f1..000000000000
--- a/drivers/ide/trm290.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright (c) 1997-1998 Mark Lord
- * Copyright (c) 2007 MontaVista Software, Inc. <source@mvista.com>
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- * June 22, 2004 - get rid of check_region
- * - Jesper Juhl
- *
- */
-
-/*
- * This module provides support for the bus-master IDE DMA function
- * of the Tekram TRM290 chip, used on a variety of PCI IDE add-on boards,
- * including a "Precision Instruments" board. The TRM290 pre-dates
- * the sff-8038 standard (ide-dma.c) by a few months, and differs
- * significantly enough to warrant separate routines for some functions,
- * while re-using others from ide-dma.c.
- *
- * EXPERIMENTAL! It works for me (a sample of one).
- *
- * Works reliably for me in DMA mode (READs only),
- * DMA WRITEs are disabled by default (see #define below);
- *
- * DMA is not enabled automatically for this chipset,
- * but can be turned on manually (with "hdparm -d1") at run time.
- *
- * I need volunteers with "spare" drives for further testing
- * and development, and maybe to help figure out the peculiarities.
- * Even knowing the registers (below), some things behave strangely.
- */
-
-#define TRM290_NO_DMA_WRITES /* DMA writes seem unreliable sometimes */
-
-/*
- * TRM-290 PCI-IDE2 Bus Master Chip
- * ================================
- * The configuration registers are addressed in normal I/O port space
- * and are used as follows:
- *
- * trm290_base depends on jumper settings, and is probed for by ide-dma.c
- *
- * trm290_base+2 when WRITTEN: chiptest register (byte, write-only)
- * bit7 must always be written as "1"
- * bits6-2 undefined
- * bit1 1=legacy_compatible_mode, 0=native_pci_mode
- * bit0 1=test_mode, 0=normal(default)
- *
- * trm290_base+2 when READ: status register (byte, read-only)
- * bits7-2 undefined
- * bit1 channel0 busmaster interrupt status 0=none, 1=asserted
- * bit0 channel0 interrupt status 0=none, 1=asserted
- *
- * trm290_base+3 Interrupt mask register
- * bits7-5 undefined
- * bit4 legacy_header: 1=present, 0=absent
- * bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only)
- * bit2 channel1 interrupt status 0=none, 1=asserted (read only)
- * bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default)
- * bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default)
- *
- * trm290_base+1 "CPR" Config Pointer Register (byte)
- * bit7 1=autoincrement CPR bits 2-0 after each access of CDR
- * bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state
- * bit5 0=enabled master burst access (default), 1=disable (write only)
- * bit4 PCI DEVSEL# timing select: 1=medium(default), 0=fast
- * bit3 0=primary IDE channel, 1=secondary IDE channel
- * bits2-0 register index for accesses through CDR port
- *
- * trm290_base+0 "CDR" Config Data Register (word)
- * two sets of seven config registers,
- * selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6),
- * each index defined below:
- *
- * Index-0 Base address register for command block (word)
- * defaults: 0x1f0 for primary, 0x170 for secondary
- *
- * Index-1 general config register (byte)
- * bit7 1=DMA enable, 0=DMA disable
- * bit6 1=activate IDE_RESET, 0=no action (default)
- * bit5 1=enable IORDY, 0=disable IORDY (default)
- * bit4 0=16-bit data port(default), 1=8-bit (XT) data port
- * bit3 interrupt polarity: 1=active_low, 0=active_high(default)
- * bit2 power-saving-mode(?): 1=enable, 0=disable(default) (write only)
- * bit1 bus_master_mode(?): 1=enable, 0=disable(default)
- * bit0 enable_io_ports: 1=enable(default), 0=disable
- *
- * Index-2 read-ahead counter preload bits 0-7 (byte, write only)
- * bits7-0 bits7-0 of readahead count
- *
- * Index-3 read-ahead config register (byte, write only)
- * bit7 1=enable_readahead, 0=disable_readahead(default)
- * bit6 1=clear_FIFO, 0=no_action
- * bit5 undefined
- * bit4 mode4 timing control: 1=enable, 0=disable(default)
- * bit3 undefined
- * bit2 undefined
- * bits1-0 bits9-8 of read-ahead count
- *
- * Index-4 base address register for control block (word)
- * defaults: 0x3f6 for primary, 0x376 for secondary
- *
- * Index-5 data port timings (shared by both drives) (byte)
- * standard PCI "clk" (clock) counts, default value = 0xf5
- *
- * bits7-6 setup time: 00=1clk, 01=2clk, 10=3clk, 11=4clk
- * bits5-3 hold time: 000=1clk, 001=2clk, 010=3clk,
- * 011=4clk, 100=5clk, 101=6clk,
- * 110=8clk, 111=12clk
- * bits2-0 active time: 000=2clk, 001=3clk, 010=4clk,
- * 011=5clk, 100=6clk, 101=8clk,
- * 110=12clk, 111=16clk
- *
- * Index-6 command/control port timings (shared by both drives) (byte)
- * same layout as Index-5, default value = 0xde
- *
- * Suggested CDR programming for PIO mode0 (600ns):
- * 0x01f0,0x21,0xff,0x80,0x03f6,0xf5,0xde ; primary
- * 0x0170,0x21,0xff,0x80,0x0376,0xf5,0xde ; secondary
- *
- * Suggested CDR programming for PIO mode3 (180ns):
- * 0x01f0,0x21,0xff,0x80,0x03f6,0x09,0xde ; primary
- * 0x0170,0x21,0xff,0x80,0x0376,0x09,0xde ; secondary
- *
- * Suggested CDR programming for PIO mode4 (120ns):
- * 0x01f0,0x21,0xff,0x80,0x03f6,0x00,0xde ; primary
- * 0x0170,0x21,0xff,0x80,0x0376,0x00,0xde ; secondary
- *
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "trm290"
-
-static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
-{
- ide_hwif_t *hwif = drive->hwif;
- u16 reg = 0;
- unsigned long flags;
-
- /* select PIO or DMA */
- reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
-
- local_irq_save(flags);
-
- if (reg != hwif->select_data) {
- hwif->select_data = reg;
- /* set PIO/DMA */
- outb(0x51 | (hwif->channel << 3), hwif->config_data + 1);
- outw(reg & 0xff, hwif->config_data);
- }
-
- /* enable IRQ if not probing */
- if (drive->dev_flags & IDE_DFLAG_PRESENT) {
- reg = inw(hwif->config_data + 3);
- reg &= 0x13;
- reg &= ~(1 << hwif->channel);
- outw(reg, hwif->config_data + 3);
- }
-
- local_irq_restore(flags);
-}
-
-static void trm290_dev_select(ide_drive_t *drive)
-{
- trm290_prepare_drive(drive, !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
-
- outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
-}
-
-static int trm290_dma_check(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- if (cmd->tf_flags & IDE_TFLAG_WRITE) {
-#ifdef TRM290_NO_DMA_WRITES
- /* always use PIO for writes */
- return 1;
-#endif
- }
- return 0;
-}
-
-static int trm290_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
- unsigned int count, rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 2;
-
- count = ide_build_dmatable(drive, cmd);
- if (count == 0)
- /* try PIO instead of DMA */
- return 1;
-
- outl(hwif->dmatable_dma | rw, hwif->dma_base);
- /* start DMA */
- outw(count * 2 - 1, hwif->dma_base + 2);
-
- return 0;
-}
-
-static void trm290_dma_start(ide_drive_t *drive)
-{
- trm290_prepare_drive(drive, 1);
-}
-
-static int trm290_dma_end(ide_drive_t *drive)
-{
- u16 status = inw(drive->hwif->dma_base + 2);
-
- trm290_prepare_drive(drive, 0);
-
- return status != 0x00ff;
-}
-
-static int trm290_dma_test_irq(ide_drive_t *drive)
-{
- u16 status = inw(drive->hwif->dma_base + 2);
-
- return status == 0x00ff;
-}
-
-static void trm290_dma_host_set(ide_drive_t *drive, int on)
-{
-}
-
-static void init_hwif_trm290(ide_hwif_t *hwif)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned int cfg_base = pci_resource_start(dev, 4);
- unsigned long flags;
- u8 reg = 0;
-
- if ((dev->class & 5) && cfg_base)
- printk(KERN_INFO DRV_NAME " %s: chip", pci_name(dev));
- else {
- cfg_base = 0x3df0;
- printk(KERN_INFO DRV_NAME " %s: using default", pci_name(dev));
- }
- printk(KERN_CONT " config base at 0x%04x\n", cfg_base);
- hwif->config_data = cfg_base;
- hwif->dma_base = (cfg_base + 4) ^ (hwif->channel ? 0x80 : 0);
-
- printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n",
- hwif->name, hwif->dma_base, hwif->dma_base + 3);
-
- if (ide_allocate_dma_engine(hwif))
- return;
-
- local_irq_save(flags);
- /* put config reg into first byte of hwif->select_data */
- outb(0x51 | (hwif->channel << 3), hwif->config_data + 1);
- /* select PIO as default */
- hwif->select_data = 0x21;
- outb(hwif->select_data, hwif->config_data);
- /* get IRQ info */
- reg = inb(hwif->config_data + 3);
- /* mask IRQs for both ports */
- reg = (reg & 0x10) | 0x03;
- outb(reg, hwif->config_data + 3);
- local_irq_restore(flags);
-
- if (reg & 0x10)
- /* legacy mode */
- hwif->irq = hwif->channel ? 15 : 14;
-
-#if 1
- {
- /*
- * My trm290-based card doesn't seem to work with all possible values
- * for the control basereg, so this kludge ensures that we use only
- * values that are known to work. Ugh. -ml
- */
- u16 new, old, compat = hwif->channel ? 0x374 : 0x3f4;
- static u16 next_offset = 0;
- u8 old_mask;
-
- outb(0x54 | (hwif->channel << 3), hwif->config_data + 1);
- old = inw(hwif->config_data);
- old &= ~1;
- old_mask = inb(old + 2);
- if (old != compat && old_mask == 0xff) {
- /* leave lower 10 bits untouched */
- compat += (next_offset += 0x400);
- hwif->io_ports.ctl_addr = compat + 2;
- outw(compat | 1, hwif->config_data);
- new = inw(hwif->config_data);
- printk(KERN_INFO "%s: control basereg workaround: "
- "old=0x%04x, new=0x%04x\n",
- hwif->name, old, new & ~1);
- }
- }
-#endif
-}
-
-static const struct ide_tp_ops trm290_tp_ops = {
- .exec_command = ide_exec_command,
- .read_status = ide_read_status,
- .read_altstatus = ide_read_altstatus,
- .write_devctl = ide_write_devctl,
-
- .dev_select = trm290_dev_select,
- .tf_load = ide_tf_load,
- .tf_read = ide_tf_read,
-
- .input_data = ide_input_data,
- .output_data = ide_output_data,
-};
-
-static const struct ide_dma_ops trm290_dma_ops = {
- .dma_host_set = trm290_dma_host_set,
- .dma_setup = trm290_dma_setup,
- .dma_start = trm290_dma_start,
- .dma_end = trm290_dma_end,
- .dma_test_irq = trm290_dma_test_irq,
- .dma_lost_irq = ide_dma_lost_irq,
- .dma_check = trm290_dma_check,
-};
-
-static const struct ide_port_info trm290_chipset = {
- .name = DRV_NAME,
- .init_hwif = init_hwif_trm290,
- .tp_ops = &trm290_tp_ops,
- .dma_ops = &trm290_dma_ops,
- .host_flags = IDE_HFLAG_TRM290 |
- IDE_HFLAG_NO_ATAPI_DMA |
-#if 0 /* play it safe for now */
- IDE_HFLAG_TRUST_BIOS_FOR_DMA |
-#endif
- IDE_HFLAG_NO_AUTODMA |
- IDE_HFLAG_NO_LBA48,
-};
-
-static int trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- return ide_pci_init_one(dev, &trm290_chipset, NULL);
-}
-
-static const struct pci_device_id trm290_pci_tbl[] = {
- { PCI_VDEVICE(TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290), 0 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, trm290_pci_tbl);
-
-static struct pci_driver trm290_pci_driver = {
- .name = "TRM290_IDE",
- .id_table = trm290_pci_tbl,
- .probe = trm290_init_one,
- .remove = ide_pci_remove,
-};
-
-static int __init trm290_ide_init(void)
-{
- return ide_pci_register_driver(&trm290_pci_driver);
-}
-
-static void __exit trm290_ide_exit(void)
-{
- pci_unregister_driver(&trm290_pci_driver);
-}
-
-module_init(trm290_ide_init);
-module_exit(trm290_ide_exit);
-
-MODULE_AUTHOR("Mark Lord");
-MODULE_DESCRIPTION("PCI driver module for Tekram TRM290 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/tx4938ide.c b/drivers/ide/tx4938ide.c
deleted file mode 100644
index 962eb92501b5..000000000000
--- a/drivers/ide/tx4938ide.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * TX4938 internal IDE driver
- * Based on tx4939ide.c.
- *
- * 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.
- *
- * (C) Copyright TOSHIBA CORPORATION 2005-2007
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <asm/ide.h>
-#include <asm/txx9/tx4938.h>
-
-static void tx4938ide_tune_ebusc(unsigned int ebus_ch,
- unsigned int gbus_clock,
- u8 pio)
-{
- struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
- u64 cr = __raw_readq(&tx4938_ebuscptr->cr[ebus_ch]);
- unsigned int sp = (cr >> 4) & 3;
- unsigned int clock = gbus_clock / (4 - sp);
- unsigned int cycle = 1000000000 / clock;
- unsigned int shwt;
- int wt;
-
- /* Minimum DIOx- active time */
- wt = DIV_ROUND_UP(t->act8b, cycle) - 2;
- /* IORDY setup time: 35ns */
- wt = max_t(int, wt, DIV_ROUND_UP(35, cycle));
- /* actual wait-cycle is max(wt & ~1, 1) */
- if (wt > 2 && (wt & 1))
- wt++;
- wt &= ~1;
- /* Address-valid to DIOR/DIOW setup */
- shwt = DIV_ROUND_UP(t->setup, cycle);
-
- /* -DIOx recovery time (SHWT * 4) and cycle time requirement */
- while ((shwt * 4 + wt + (wt ? 2 : 3)) * cycle < t->cycle)
- shwt++;
- if (shwt > 7) {
- pr_warn("tx4938ide: SHWT violation (%d)\n", shwt);
- shwt = 7;
- }
- pr_debug("tx4938ide: ebus %d, bus cycle %dns, WT %d, SHWT %d\n",
- ebus_ch, cycle, wt, shwt);
-
- __raw_writeq((cr & ~0x3f007ull) | (wt << 12) | shwt,
- &tx4938_ebuscptr->cr[ebus_ch]);
-}
-
-static void tx4938ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- struct tx4938ide_platform_info *pdata = dev_get_platdata(hwif->dev);
- u8 safe = drive->pio_mode - XFER_PIO_0;
- ide_drive_t *pair;
-
- pair = ide_get_pair_dev(drive);
- if (pair)
- safe = min_t(u8, safe, pair->pio_mode - XFER_PIO_0);
- tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, safe);
-}
-
-#ifdef __BIG_ENDIAN
-
-/* custom iops (independent from SWAP_IO_SPACE) */
-static void tx4938ide_input_data_swap(ide_drive_t *drive, struct ide_cmd *cmd,
- void *buf, unsigned int len)
-{
- unsigned long port = drive->hwif->io_ports.data_addr;
- unsigned short *ptr = buf;
- unsigned int count = (len + 1) / 2;
-
- while (count--)
- *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port));
- __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
-}
-
-static void tx4938ide_output_data_swap(ide_drive_t *drive, struct ide_cmd *cmd,
- void *buf, unsigned int len)
-{
- unsigned long port = drive->hwif->io_ports.data_addr;
- unsigned short *ptr = buf;
- unsigned int count = (len + 1) / 2;
-
- while (count--) {
- __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port);
- ptr++;
- }
- __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
-}
-
-static const struct ide_tp_ops tx4938ide_tp_ops = {
- .exec_command = ide_exec_command,
- .read_status = ide_read_status,
- .read_altstatus = ide_read_altstatus,
- .write_devctl = ide_write_devctl,
-
- .dev_select = ide_dev_select,
- .tf_load = ide_tf_load,
- .tf_read = ide_tf_read,
-
- .input_data = tx4938ide_input_data_swap,
- .output_data = tx4938ide_output_data_swap,
-};
-
-#endif /* __BIG_ENDIAN */
-
-static const struct ide_port_ops tx4938ide_port_ops = {
- .set_pio_mode = tx4938ide_set_pio_mode,
-};
-
-static const struct ide_port_info tx4938ide_port_info __initconst = {
- .port_ops = &tx4938ide_port_ops,
-#ifdef __BIG_ENDIAN
- .tp_ops = &tx4938ide_tp_ops,
-#endif
- .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
- .pio_mask = ATA_PIO5,
- .chipset = ide_generic,
-};
-
-static int __init tx4938ide_probe(struct platform_device *pdev)
-{
- struct ide_hw hw, *hws[] = { &hw };
- struct ide_host *host;
- struct resource *res;
- struct tx4938ide_platform_info *pdata = dev_get_platdata(&pdev->dev);
- int irq, ret, i;
- unsigned long mapbase, mapctl;
- struct ide_port_info d = tx4938ide_port_info;
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return -ENODEV;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
-
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), "tx4938ide"))
- return -EBUSY;
- mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start,
- 8 << pdata->ioport_shift);
- mapctl = (unsigned long)devm_ioremap(&pdev->dev,
- res->start + 0x10000 +
- (6 << pdata->ioport_shift),
- 1 << pdata->ioport_shift);
- if (!mapbase || !mapctl)
- return -EBUSY;
-
- memset(&hw, 0, sizeof(hw));
- if (pdata->ioport_shift) {
- unsigned long port = mapbase;
- unsigned long ctl = mapctl;
-
- hw.io_ports_array[0] = port;
-#ifdef __BIG_ENDIAN
- port++;
- ctl++;
-#endif
- for (i = 1; i <= 7; i++)
- hw.io_ports_array[i] =
- port + (i << pdata->ioport_shift);
- hw.io_ports.ctl_addr = ctl;
- } else
- ide_std_init_ports(&hw, mapbase, mapctl);
- hw.irq = irq;
- hw.dev = &pdev->dev;
-
- pr_info("TX4938 IDE interface (base %#lx, ctl %#lx, irq %d)\n",
- mapbase, mapctl, hw.irq);
- if (pdata->gbus_clock)
- tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, 0);
- else
- d.port_ops = NULL;
- ret = ide_host_add(&d, hws, 1, &host);
- if (!ret)
- platform_set_drvdata(pdev, host);
- return ret;
-}
-
-static int __exit tx4938ide_remove(struct platform_device *pdev)
-{
- struct ide_host *host = platform_get_drvdata(pdev);
-
- ide_host_remove(host);
- return 0;
-}
-
-static struct platform_driver tx4938ide_driver = {
- .driver = {
- .name = "tx4938ide",
- },
- .remove = __exit_p(tx4938ide_remove),
-};
-
-module_platform_driver_probe(tx4938ide_driver, tx4938ide_probe);
-
-MODULE_DESCRIPTION("TX4938 internal IDE driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:tx4938ide");
diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c
deleted file mode 100644
index b1bbf807bb3d..000000000000
--- a/drivers/ide/tx4939ide.c
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
- * TX4939 internal IDE driver
- * Based on RBTX49xx patch from CELF patch archive.
- *
- * 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.
- *
- * (C) Copyright TOSHIBA CORPORATION 2005-2007
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/scatterlist.h>
-
-#include <asm/ide.h>
-
-#define MODNAME "tx4939ide"
-
-/* ATA Shadow Registers (8-bit except for Data which is 16-bit) */
-#define TX4939IDE_Data 0x000
-#define TX4939IDE_Error_Feature 0x001
-#define TX4939IDE_Sec 0x002
-#define TX4939IDE_LBA0 0x003
-#define TX4939IDE_LBA1 0x004
-#define TX4939IDE_LBA2 0x005
-#define TX4939IDE_DevHead 0x006
-#define TX4939IDE_Stat_Cmd 0x007
-#define TX4939IDE_AltStat_DevCtl 0x402
-/* H/W DMA Registers */
-#define TX4939IDE_DMA_Cmd 0x800 /* 8-bit */
-#define TX4939IDE_DMA_Stat 0x802 /* 8-bit */
-#define TX4939IDE_PRD_Ptr 0x804 /* 32-bit */
-/* ATA100 CORE Registers (16-bit) */
-#define TX4939IDE_Sys_Ctl 0xc00
-#define TX4939IDE_Xfer_Cnt_1 0xc08
-#define TX4939IDE_Xfer_Cnt_2 0xc0a
-#define TX4939IDE_Sec_Cnt 0xc10
-#define TX4939IDE_Start_Lo_Addr 0xc18
-#define TX4939IDE_Start_Up_Addr 0xc20
-#define TX4939IDE_Add_Ctl 0xc28
-#define TX4939IDE_Lo_Burst_Cnt 0xc30
-#define TX4939IDE_Up_Burst_Cnt 0xc38
-#define TX4939IDE_PIO_Addr 0xc88
-#define TX4939IDE_H_Rst_Tim 0xc90
-#define TX4939IDE_Int_Ctl 0xc98
-#define TX4939IDE_Pkt_Cmd 0xcb8
-#define TX4939IDE_Bxfer_Cnt_Hi 0xcc0
-#define TX4939IDE_Bxfer_Cnt_Lo 0xcc8
-#define TX4939IDE_Dev_TErr 0xcd0
-#define TX4939IDE_Pkt_Xfer_Ctl 0xcd8
-#define TX4939IDE_Start_TAddr 0xce0
-
-/* bits for Int_Ctl */
-#define TX4939IDE_INT_ADDRERR 0x80
-#define TX4939IDE_INT_REACHMUL 0x40
-#define TX4939IDE_INT_DEVTIMING 0x20
-#define TX4939IDE_INT_UDMATERM 0x10
-#define TX4939IDE_INT_TIMER 0x08
-#define TX4939IDE_INT_BUSERR 0x04
-#define TX4939IDE_INT_XFEREND 0x02
-#define TX4939IDE_INT_HOST 0x01
-
-#define TX4939IDE_IGNORE_INTS \
- (TX4939IDE_INT_ADDRERR | TX4939IDE_INT_REACHMUL | \
- TX4939IDE_INT_DEVTIMING | TX4939IDE_INT_UDMATERM | \
- TX4939IDE_INT_TIMER | TX4939IDE_INT_XFEREND)
-
-#ifdef __BIG_ENDIAN
-#define tx4939ide_swizzlel(a) ((a) ^ 4)
-#define tx4939ide_swizzlew(a) ((a) ^ 6)
-#define tx4939ide_swizzleb(a) ((a) ^ 7)
-#else
-#define tx4939ide_swizzlel(a) (a)
-#define tx4939ide_swizzlew(a) (a)
-#define tx4939ide_swizzleb(a) (a)
-#endif
-
-static u16 tx4939ide_readw(void __iomem *base, u32 reg)
-{
- return __raw_readw(base + tx4939ide_swizzlew(reg));
-}
-static u8 tx4939ide_readb(void __iomem *base, u32 reg)
-{
- return __raw_readb(base + tx4939ide_swizzleb(reg));
-}
-static void tx4939ide_writel(u32 val, void __iomem *base, u32 reg)
-{
- __raw_writel(val, base + tx4939ide_swizzlel(reg));
-}
-static void tx4939ide_writew(u16 val, void __iomem *base, u32 reg)
-{
- __raw_writew(val, base + tx4939ide_swizzlew(reg));
-}
-static void tx4939ide_writeb(u8 val, void __iomem *base, u32 reg)
-{
- __raw_writeb(val, base + tx4939ide_swizzleb(reg));
-}
-
-#define TX4939IDE_BASE(hwif) ((void __iomem *)(hwif)->extra_base)
-
-static void tx4939ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- int is_slave = drive->dn;
- u32 mask, val;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
- u8 safe = pio;
- ide_drive_t *pair;
-
- pair = ide_get_pair_dev(drive);
- if (pair)
- safe = min_t(u8, safe, pair->pio_mode - XFER_PIO_0);
- /*
- * Update Command Transfer Mode for master/slave and Data
- * Transfer Mode for this drive.
- */
- mask = is_slave ? 0x07f00000 : 0x000007f0;
- val = ((safe << 8) | (pio << 4)) << (is_slave ? 16 : 0);
- hwif->select_data = (hwif->select_data & ~mask) | val;
- /* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */
-}
-
-static void tx4939ide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- u32 mask, val;
- const u8 mode = drive->dma_mode;
-
- /* Update Data Transfer Mode for this drive. */
- if (mode >= XFER_UDMA_0)
- val = mode - XFER_UDMA_0 + 8;
- else
- val = mode - XFER_MW_DMA_0 + 5;
- if (drive->dn) {
- mask = 0x00f00000;
- val <<= 20;
- } else {
- mask = 0x000000f0;
- val <<= 4;
- }
- hwif->select_data = (hwif->select_data & ~mask) | val;
- /* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */
-}
-
-static u16 tx4939ide_check_error_ints(ide_hwif_t *hwif)
-{
- void __iomem *base = TX4939IDE_BASE(hwif);
- u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl);
-
- if (ctl & TX4939IDE_INT_BUSERR) {
- /* reset FIFO */
- u16 sysctl = tx4939ide_readw(base, TX4939IDE_Sys_Ctl);
-
- tx4939ide_writew(sysctl | 0x4000, base, TX4939IDE_Sys_Ctl);
- /* wait 12GBUSCLK (typ. 60ns @ GBUS200MHz, max 270ns) */
- ndelay(270);
- tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl);
- }
- if (ctl & (TX4939IDE_INT_ADDRERR |
- TX4939IDE_INT_DEVTIMING | TX4939IDE_INT_BUSERR))
- pr_err("%s: Error interrupt %#x (%s%s%s )\n",
- hwif->name, ctl,
- ctl & TX4939IDE_INT_ADDRERR ? " Address-Error" : "",
- ctl & TX4939IDE_INT_DEVTIMING ? " DEV-Timing" : "",
- ctl & TX4939IDE_INT_BUSERR ? " Bus-Error" : "");
- return ctl;
-}
-
-static void tx4939ide_clear_irq(ide_drive_t *drive)
-{
- ide_hwif_t *hwif;
- void __iomem *base;
- u16 ctl;
-
- /*
- * tx4939ide_dma_test_irq() and tx4939ide_dma_end() do all job
- * for DMA case.
- */
- if (drive->waiting_for_dma)
- return;
- hwif = drive->hwif;
- base = TX4939IDE_BASE(hwif);
- ctl = tx4939ide_check_error_ints(hwif);
- tx4939ide_writew(ctl, base, TX4939IDE_Int_Ctl);
-}
-
-static u8 tx4939ide_cable_detect(ide_hwif_t *hwif)
-{
- void __iomem *base = TX4939IDE_BASE(hwif);
-
- return tx4939ide_readw(base, TX4939IDE_Sys_Ctl) & 0x2000 ?
- ATA_CBL_PATA40 : ATA_CBL_PATA80;
-}
-
-#ifdef __BIG_ENDIAN
-static void tx4939ide_dma_host_set(ide_drive_t *drive, int on)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 unit = drive->dn;
- void __iomem *base = TX4939IDE_BASE(hwif);
- u8 dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat);
-
- if (on)
- dma_stat |= (1 << (5 + unit));
- else
- dma_stat &= ~(1 << (5 + unit));
-
- tx4939ide_writeb(dma_stat, base, TX4939IDE_DMA_Stat);
-}
-#else
-#define tx4939ide_dma_host_set ide_dma_host_set
-#endif
-
-static u8 tx4939ide_clear_dma_status(void __iomem *base)
-{
- u8 dma_stat;
-
- /* read DMA status for INTR & ERROR flags */
- dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat);
- /* clear INTR & ERROR flags */
- tx4939ide_writeb(dma_stat | ATA_DMA_INTR | ATA_DMA_ERR, base,
- TX4939IDE_DMA_Stat);
- /* recover intmask cleared by writing to bit2 of DMA_Stat */
- tx4939ide_writew(TX4939IDE_IGNORE_INTS << 8, base, TX4939IDE_Int_Ctl);
- return dma_stat;
-}
-
-#ifdef __BIG_ENDIAN
-/* custom ide_build_dmatable to handle swapped layout */
-static int tx4939ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
- u32 *table = (u32 *)hwif->dmatable_cpu;
- unsigned int count = 0;
- int i;
- struct scatterlist *sg;
-
- for_each_sg(hwif->sg_table, sg, cmd->sg_nents, i) {
- u32 cur_addr, cur_len, bcount;
-
- cur_addr = sg_dma_address(sg);
- cur_len = sg_dma_len(sg);
-
- /*
- * Fill in the DMA table, without crossing any 64kB boundaries.
- */
-
- while (cur_len) {
- if (count++ >= PRD_ENTRIES)
- goto use_pio_instead;
-
- bcount = 0x10000 - (cur_addr & 0xffff);
- if (bcount > cur_len)
- bcount = cur_len;
- /*
- * This workaround for zero count seems required.
- * (standard ide_build_dmatable does it too)
- */
- if (bcount == 0x10000)
- bcount = 0x8000;
- *table++ = bcount & 0xffff;
- *table++ = cur_addr;
- cur_addr += bcount;
- cur_len -= bcount;
- }
- }
-
- if (count) {
- *(table - 2) |= 0x80000000;
- return count;
- }
-
-use_pio_instead:
- printk(KERN_ERR "%s: %s\n", drive->name,
- count ? "DMA table too small" : "empty DMA table?");
-
- return 0; /* revert to PIO for this request */
-}
-#else
-#define tx4939ide_build_dmatable ide_build_dmatable
-#endif
-
-static int tx4939ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
- void __iomem *base = TX4939IDE_BASE(hwif);
- u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR;
-
- /* fall back to PIO! */
- if (tx4939ide_build_dmatable(drive, cmd) == 0)
- return 1;
-
- /* PRD table */
- tx4939ide_writel(hwif->dmatable_dma, base, TX4939IDE_PRD_Ptr);
-
- /* specify r/w */
- tx4939ide_writeb(rw, base, TX4939IDE_DMA_Cmd);
-
- /* clear INTR & ERROR flags */
- tx4939ide_clear_dma_status(base);
-
- tx4939ide_writew(SECTOR_SIZE / 2, base, drive->dn ?
- TX4939IDE_Xfer_Cnt_2 : TX4939IDE_Xfer_Cnt_1);
-
- tx4939ide_writew(blk_rq_sectors(cmd->rq), base, TX4939IDE_Sec_Cnt);
-
- return 0;
-}
-
-static int tx4939ide_dma_end(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- u8 dma_stat, dma_cmd;
- void __iomem *base = TX4939IDE_BASE(hwif);
- u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl);
-
- /* get DMA command mode */
- dma_cmd = tx4939ide_readb(base, TX4939IDE_DMA_Cmd);
- /* stop DMA */
- tx4939ide_writeb(dma_cmd & ~ATA_DMA_START, base, TX4939IDE_DMA_Cmd);
-
- /* read and clear the INTR & ERROR bits */
- dma_stat = tx4939ide_clear_dma_status(base);
-
-#define CHECK_DMA_MASK (ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR)
-
- /* verify good DMA status */
- if ((dma_stat & CHECK_DMA_MASK) == 0 &&
- (ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) ==
- (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST))
- /* INT_IDE lost... bug? */
- return 0;
- return ((dma_stat & CHECK_DMA_MASK) !=
- ATA_DMA_INTR) ? 0x10 | dma_stat : 0;
-}
-
-/* returns 1 if DMA IRQ issued, 0 otherwise */
-static int tx4939ide_dma_test_irq(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- void __iomem *base = TX4939IDE_BASE(hwif);
- u16 ctl, ide_int;
- u8 dma_stat, stat;
- int found = 0;
-
- ctl = tx4939ide_check_error_ints(hwif);
- ide_int = ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST);
- switch (ide_int) {
- case TX4939IDE_INT_HOST:
- /* On error, XFEREND might not be asserted. */
- stat = tx4939ide_readb(base, TX4939IDE_AltStat_DevCtl);
- if ((stat & (ATA_BUSY | ATA_DRQ | ATA_ERR)) == ATA_ERR)
- found = 1;
- else
- /* Wait for XFEREND (Mask HOST and unmask XFEREND) */
- ctl &= ~TX4939IDE_INT_XFEREND << 8;
- ctl |= ide_int << 8;
- break;
- case TX4939IDE_INT_HOST | TX4939IDE_INT_XFEREND:
- dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat);
- if (!(dma_stat & ATA_DMA_INTR))
- pr_warn("%s: weird interrupt status. "
- "DMA_Stat %#02x int_ctl %#04x\n",
- hwif->name, dma_stat, ctl);
- found = 1;
- break;
- }
- /*
- * Do not clear XFEREND, HOST now. They will be cleared by
- * clearing bit2 of DMA_Stat.
- */
- ctl &= ~ide_int;
- tx4939ide_writew(ctl, base, TX4939IDE_Int_Ctl);
- return found;
-}
-
-#ifdef __BIG_ENDIAN
-static u8 tx4939ide_dma_sff_read_status(ide_hwif_t *hwif)
-{
- void __iomem *base = TX4939IDE_BASE(hwif);
-
- return tx4939ide_readb(base, TX4939IDE_DMA_Stat);
-}
-#else
-#define tx4939ide_dma_sff_read_status ide_dma_sff_read_status
-#endif
-
-static void tx4939ide_init_hwif(ide_hwif_t *hwif)
-{
- void __iomem *base = TX4939IDE_BASE(hwif);
-
- /* Soft Reset */
- tx4939ide_writew(0x8000, base, TX4939IDE_Sys_Ctl);
- /* at least 20 GBUSCLK (typ. 100ns @ GBUS200MHz, max 450ns) */
- ndelay(450);
- tx4939ide_writew(0x0000, base, TX4939IDE_Sys_Ctl);
- /* mask some interrupts and clear all interrupts */
- tx4939ide_writew((TX4939IDE_IGNORE_INTS << 8) | 0xff, base,
- TX4939IDE_Int_Ctl);
-
- tx4939ide_writew(0x0008, base, TX4939IDE_Lo_Burst_Cnt);
- tx4939ide_writew(0, base, TX4939IDE_Up_Burst_Cnt);
-}
-
-static int tx4939ide_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
- hwif->dma_base =
- hwif->extra_base + tx4939ide_swizzleb(TX4939IDE_DMA_Cmd);
- /*
- * Note that we cannot use ATA_DMA_TABLE_OFS, ATA_DMA_STATUS
- * for big endian.
- */
- return ide_allocate_dma_engine(hwif);
-}
-
-static void tx4939ide_tf_load_fixup(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- void __iomem *base = TX4939IDE_BASE(hwif);
- u16 sysctl = hwif->select_data >> (drive->dn ? 16 : 0);
-
- /*
- * Fix ATA100 CORE System Control Register. (The write to the
- * Device/Head register may write wrong data to the System
- * Control Register)
- * While Sys_Ctl is written here, dev_select() is not needed.
- */
- tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl);
-}
-
-static void tx4939ide_tf_load(ide_drive_t *drive, struct ide_taskfile *tf,
- u8 valid)
-{
- ide_tf_load(drive, tf, valid);
-
- if (valid & IDE_VALID_DEVICE)
- tx4939ide_tf_load_fixup(drive);
-}
-
-#ifdef __BIG_ENDIAN
-
-/* custom iops (independent from SWAP_IO_SPACE) */
-static void tx4939ide_input_data_swap(ide_drive_t *drive, struct ide_cmd *cmd,
- void *buf, unsigned int len)
-{
- unsigned long port = drive->hwif->io_ports.data_addr;
- unsigned short *ptr = buf;
- unsigned int count = (len + 1) / 2;
-
- while (count--)
- *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port));
- __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
-}
-
-static void tx4939ide_output_data_swap(ide_drive_t *drive, struct ide_cmd *cmd,
- void *buf, unsigned int len)
-{
- unsigned long port = drive->hwif->io_ports.data_addr;
- unsigned short *ptr = buf;
- unsigned int count = (len + 1) / 2;
-
- while (count--) {
- __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port);
- ptr++;
- }
- __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
-}
-
-static const struct ide_tp_ops tx4939ide_tp_ops = {
- .exec_command = ide_exec_command,
- .read_status = ide_read_status,
- .read_altstatus = ide_read_altstatus,
- .write_devctl = ide_write_devctl,
-
- .dev_select = ide_dev_select,
- .tf_load = tx4939ide_tf_load,
- .tf_read = ide_tf_read,
-
- .input_data = tx4939ide_input_data_swap,
- .output_data = tx4939ide_output_data_swap,
-};
-
-#else /* __LITTLE_ENDIAN */
-
-static const struct ide_tp_ops tx4939ide_tp_ops = {
- .exec_command = ide_exec_command,
- .read_status = ide_read_status,
- .read_altstatus = ide_read_altstatus,
- .write_devctl = ide_write_devctl,
-
- .dev_select = ide_dev_select,
- .tf_load = tx4939ide_tf_load,
- .tf_read = ide_tf_read,
-
- .input_data = ide_input_data,
- .output_data = ide_output_data,
-};
-
-#endif /* __LITTLE_ENDIAN */
-
-static const struct ide_port_ops tx4939ide_port_ops = {
- .set_pio_mode = tx4939ide_set_pio_mode,
- .set_dma_mode = tx4939ide_set_dma_mode,
- .clear_irq = tx4939ide_clear_irq,
- .cable_detect = tx4939ide_cable_detect,
-};
-
-static const struct ide_dma_ops tx4939ide_dma_ops = {
- .dma_host_set = tx4939ide_dma_host_set,
- .dma_setup = tx4939ide_dma_setup,
- .dma_start = ide_dma_start,
- .dma_end = tx4939ide_dma_end,
- .dma_test_irq = tx4939ide_dma_test_irq,
- .dma_lost_irq = ide_dma_lost_irq,
- .dma_timer_expiry = ide_dma_sff_timer_expiry,
- .dma_sff_read_status = tx4939ide_dma_sff_read_status,
-};
-
-static const struct ide_port_info tx4939ide_port_info __initconst = {
- .init_hwif = tx4939ide_init_hwif,
- .init_dma = tx4939ide_init_dma,
- .port_ops = &tx4939ide_port_ops,
- .dma_ops = &tx4939ide_dma_ops,
- .tp_ops = &tx4939ide_tp_ops,
- .host_flags = IDE_HFLAG_MMIO,
- .pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
- .udma_mask = ATA_UDMA5,
- .chipset = ide_generic,
-};
-
-static int __init tx4939ide_probe(struct platform_device *pdev)
-{
- struct ide_hw hw, *hws[] = { &hw };
- struct ide_host *host;
- struct resource *res;
- int irq, ret;
- unsigned long mapbase;
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return -ENODEV;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
-
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), MODNAME))
- return -EBUSY;
- mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!mapbase)
- return -EBUSY;
- memset(&hw, 0, sizeof(hw));
- hw.io_ports.data_addr =
- mapbase + tx4939ide_swizzlew(TX4939IDE_Data);
- hw.io_ports.error_addr =
- mapbase + tx4939ide_swizzleb(TX4939IDE_Error_Feature);
- hw.io_ports.nsect_addr =
- mapbase + tx4939ide_swizzleb(TX4939IDE_Sec);
- hw.io_ports.lbal_addr =
- mapbase + tx4939ide_swizzleb(TX4939IDE_LBA0);
- hw.io_ports.lbam_addr =
- mapbase + tx4939ide_swizzleb(TX4939IDE_LBA1);
- hw.io_ports.lbah_addr =
- mapbase + tx4939ide_swizzleb(TX4939IDE_LBA2);
- hw.io_ports.device_addr =
- mapbase + tx4939ide_swizzleb(TX4939IDE_DevHead);
- hw.io_ports.command_addr =
- mapbase + tx4939ide_swizzleb(TX4939IDE_Stat_Cmd);
- hw.io_ports.ctl_addr =
- mapbase + tx4939ide_swizzleb(TX4939IDE_AltStat_DevCtl);
- hw.irq = irq;
- hw.dev = &pdev->dev;
-
- pr_info("TX4939 IDE interface (base %#lx, irq %d)\n", mapbase, irq);
- host = ide_host_alloc(&tx4939ide_port_info, hws, 1);
- if (!host)
- return -ENOMEM;
- /* use extra_base for base address of the all registers */
- host->ports[0]->extra_base = mapbase;
- ret = ide_host_register(host, &tx4939ide_port_info, hws);
- if (ret) {
- ide_host_free(host);
- return ret;
- }
- platform_set_drvdata(pdev, host);
- return 0;
-}
-
-static int __exit tx4939ide_remove(struct platform_device *pdev)
-{
- struct ide_host *host = platform_get_drvdata(pdev);
-
- ide_host_remove(host);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int tx4939ide_resume(struct platform_device *dev)
-{
- struct ide_host *host = platform_get_drvdata(dev);
- ide_hwif_t *hwif = host->ports[0];
-
- tx4939ide_init_hwif(hwif);
- return 0;
-}
-#else
-#define tx4939ide_resume NULL
-#endif
-
-static struct platform_driver tx4939ide_driver = {
- .driver = {
- .name = MODNAME,
- },
- .remove = __exit_p(tx4939ide_remove),
- .resume = tx4939ide_resume,
-};
-
-module_platform_driver_probe(tx4939ide_driver, tx4939ide_probe);
-
-MODULE_DESCRIPTION("TX4939 internal IDE driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:tx4939ide");
diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c
deleted file mode 100644
index cf996f788292..000000000000
--- a/drivers/ide/umc8672.c
+++ /dev/null
@@ -1,184 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 1995-1996 Linus Torvalds & author (see below)
- */
-
-/*
- * Principal Author/Maintainer: PODIEN@hml2.atlas.de (Wolfram Podien)
- *
- * This file provides support for the advanced features
- * of the UMC 8672 IDE interface.
- *
- * Version 0.01 Initial version, hacked out of ide.c,
- * and #include'd rather than compiled separately.
- * This will get cleaned up in a subsequent release.
- *
- * Version 0.02 now configs/compiles separate from ide.c -ml
- * Version 0.03 enhanced auto-tune, fix display bug
- * Version 0.05 replace sti() with restore_flags() -ml
- * add detection of possible race condition -ml
- */
-
-/*
- * VLB Controller Support from
- * Wolfram Podien
- * Rohoefe 3
- * D28832 Achim
- * Germany
- *
- * To enable UMC8672 support there must a lilo line like
- * append="ide0=umc8672"...
- * To set the speed according to the abilities of the hardware there must be a
- * line like
- * #define UMC_DRIVE0 11
- * in the beginning of the driver, which sets the speed of drive 0 to 11 (there
- * are some lines present). 0 - 11 are allowed speed values. These values are
- * the results from the DOS speed test program supplied from UMC. 11 is the
- * highest speed (about PIO mode 3)
- */
-#define REALLY_SLOW_IO /* some systems can safely undef this */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#define DRV_NAME "umc8672"
-
-/*
- * Default speeds. These can be changed with "auto-tune" and/or hdparm.
- */
-#define UMC_DRIVE0 1 /* DOS measured drive speeds */
-#define UMC_DRIVE1 1 /* 0 to 11 allowed */
-#define UMC_DRIVE2 1 /* 11 = Fastest Speed */
-#define UMC_DRIVE3 1 /* In case of crash reduce speed */
-
-static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
-static const u8 pio_to_umc [5] = {0, 3, 7, 10, 11}; /* rough guesses */
-
-/* 0 1 2 3 4 5 6 7 8 9 10 11 */
-static const u8 speedtab [3][12] = {
- {0x0f, 0x0b, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1},
- {0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1},
- {0xff, 0xcb, 0xc0, 0x58, 0x36, 0x33, 0x23, 0x22, 0x21, 0x11, 0x10, 0x0}
-};
-
-static void out_umc(char port, char wert)
-{
- outb_p(port, 0x108);
- outb_p(wert, 0x109);
-}
-
-static inline u8 in_umc(char port)
-{
- outb_p(port, 0x108);
- return inb_p(0x109);
-}
-
-static void umc_set_speeds(u8 speeds[])
-{
- int i, tmp;
-
- outb_p(0x5A, 0x108); /* enable umc */
-
- out_umc(0xd7, (speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
- out_umc(0xd6, (speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
- tmp = 0;
- for (i = 3; i >= 0; i--)
- tmp = (tmp << 2) | speedtab[1][speeds[i]];
- out_umc(0xdc, tmp);
- for (i = 0; i < 4; i++) {
- out_umc(0xd0 + i, speedtab[2][speeds[i]]);
- out_umc(0xd8 + i, speedtab[2][speeds[i]]);
- }
- outb_p(0xa5, 0x108); /* disable umc */
-
- printk("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
- speeds[0], speeds[1], speeds[2], speeds[3]);
-}
-
-static void umc_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- ide_hwif_t *mate = hwif->mate;
- unsigned long flags;
- const u8 pio = drive->pio_mode - XFER_PIO_0;
-
- printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
- drive->name, pio, pio_to_umc[pio]);
- if (mate)
- spin_lock_irqsave(&mate->lock, flags);
- if (mate && mate->handler) {
- printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n");
- } else {
- current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
- umc_set_speeds(current_speeds);
- }
- if (mate)
- spin_unlock_irqrestore(&mate->lock, flags);
-}
-
-static const struct ide_port_ops umc8672_port_ops = {
- .set_pio_mode = umc_set_pio_mode,
-};
-
-static const struct ide_port_info umc8672_port_info __initconst = {
- .name = DRV_NAME,
- .chipset = ide_umc8672,
- .port_ops = &umc8672_port_ops,
- .host_flags = IDE_HFLAG_NO_DMA,
- .pio_mask = ATA_PIO4,
-};
-
-static int __init umc8672_probe(void)
-{
- unsigned long flags;
-
- if (!request_region(0x108, 2, "umc8672")) {
- printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n");
- return 1;
- }
- local_irq_save(flags);
- outb_p(0x5A, 0x108); /* enable umc */
- if (in_umc (0xd5) != 0xa0) {
- local_irq_restore(flags);
- printk(KERN_ERR "umc8672: not found\n");
- release_region(0x108, 2);
- return 1;
- }
- outb_p(0xa5, 0x108); /* disable umc */
-
- umc_set_speeds(current_speeds);
- local_irq_restore(flags);
-
- return ide_legacy_device_add(&umc8672_port_info, 0);
-}
-
-static bool probe_umc8672;
-
-module_param_named(probe, probe_umc8672, bool, 0);
-MODULE_PARM_DESC(probe, "probe for UMC8672 chipset");
-
-static int __init umc8672_init(void)
-{
- if (probe_umc8672 == 0)
- goto out;
-
- if (umc8672_probe() == 0)
- return 0;
-out:
- return -ENODEV;
-}
-
-module_init(umc8672_init);
-
-MODULE_AUTHOR("Wolfram Podien");
-MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
deleted file mode 100644
index 63a3aca506fc..000000000000
--- a/drivers/ide/via82cxxx.c
+++ /dev/null
@@ -1,532 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * VIA IDE driver for Linux. Supported southbridges:
- *
- * vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
- * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
- * vt8235, vt8237, vt8237a
- *
- * Copyright (c) 2000-2002 Vojtech Pavlik
- * Copyright (c) 2007-2010 Bartlomiej Zolnierkiewicz
- *
- * Based on the work of:
- * Michel Aubry
- * Jeff Garzik
- * Andre Hedrick
- *
- * Documentation:
- * Obsolete device documentation publicly available from via.com.tw
- * Current device documentation available under NDA only
- */
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <linux/dmi.h>
-
-#ifdef CONFIG_PPC_CHRP
-#include <asm/processor.h>
-#endif
-
-#define DRV_NAME "via82cxxx"
-
-#define VIA_IDE_ENABLE 0x40
-#define VIA_IDE_CONFIG 0x41
-#define VIA_FIFO_CONFIG 0x43
-#define VIA_MISC_1 0x44
-#define VIA_MISC_2 0x45
-#define VIA_MISC_3 0x46
-#define VIA_DRIVE_TIMING 0x48
-#define VIA_8BIT_TIMING 0x4e
-#define VIA_ADDRESS_SETUP 0x4c
-#define VIA_UDMA_TIMING 0x50
-
-#define VIA_BAD_PREQ 0x01 /* Crashes if PREQ# till DDACK# set */
-#define VIA_BAD_CLK66 0x02 /* 66 MHz clock doesn't work correctly */
-#define VIA_SET_FIFO 0x04 /* Needs to have FIFO split set */
-#define VIA_NO_UNMASK 0x08 /* Doesn't work with IRQ unmasking on */
-#define VIA_BAD_ID 0x10 /* Has wrong vendor ID (0x1107) */
-#define VIA_BAD_AST 0x20 /* Don't touch Address Setup Timing */
-#define VIA_SATA_PATA 0x80 /* SATA/PATA combined configuration */
-
-enum {
- VIA_IDFLAG_SINGLE = (1 << 1), /* single channel controller */
-};
-
-/*
- * VIA SouthBridge chips.
- */
-
-static struct via_isa_bridge {
- char *name;
- u16 id;
- u8 rev_min;
- u8 rev_max;
- u8 udma_mask;
- u8 flags;
-} via_isa_bridges[] = {
- { "vx855", PCI_DEVICE_ID_VIA_VX855, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
- { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
- { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
- { "vt8261", PCI_DEVICE_ID_VIA_8261, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
- { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
- { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
- { "vt6415", PCI_DEVICE_ID_VIA_6415, 0x00, 0xff, ATA_UDMA6, VIA_BAD_AST },
- { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
- { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
- { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
- { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
- { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
- { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, ATA_UDMA5, },
- { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, ATA_UDMA5, },
- { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, ATA_UDMA5, },
- { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, ATA_UDMA5, },
- { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, ATA_UDMA4, },
- { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 },
- { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, ATA_UDMA4, },
- { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 },
- { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, ATA_UDMA2, VIA_SET_FIFO },
- { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, ATA_UDMA2, VIA_SET_FIFO | VIA_BAD_PREQ },
- { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, ATA_UDMA2, VIA_SET_FIFO },
- { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, ATA_UDMA2, VIA_SET_FIFO },
- { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, 0x00, VIA_SET_FIFO },
- { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, 0x00, VIA_SET_FIFO | VIA_NO_UNMASK },
- { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, 0x00, VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
- { "vtxxxx", PCI_DEVICE_ID_VIA_ANON, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
- { NULL }
-};
-
-static unsigned int via_clock;
-static char *via_dma[] = { "16", "25", "33", "44", "66", "100", "133" };
-
-struct via82cxxx_dev
-{
- struct via_isa_bridge *via_config;
- unsigned int via_80w;
-};
-
-/**
- * via_set_speed - write timing registers
- * @dev: PCI device
- * @dn: device
- * @timing: IDE timing data to use
- *
- * via_set_speed writes timing values to the chipset registers
- */
-
-static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct ide_host *host = pci_get_drvdata(dev);
- struct via82cxxx_dev *vdev = host->host_priv;
- u8 t;
-
- if (~vdev->via_config->flags & VIA_BAD_AST) {
- pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
- t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
- pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t);
- }
-
- pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)),
- ((clamp_val(timing->act8b, 1, 16) - 1) << 4) | (clamp_val(timing->rec8b, 1, 16) - 1));
-
- pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn),
- ((clamp_val(timing->active, 1, 16) - 1) << 4) | (clamp_val(timing->recover, 1, 16) - 1));
-
- switch (vdev->via_config->udma_mask) {
- case ATA_UDMA2: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 5) - 2)) : 0x03; break;
- case ATA_UDMA4: t = timing->udma ? (0xe8 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x0f; break;
- case ATA_UDMA5: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x07; break;
- case ATA_UDMA6: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x07; break;
- }
-
- /* Set UDMA unless device is not UDMA capable */
- if (vdev->via_config->udma_mask) {
- u8 udma_etc;
-
- pci_read_config_byte(dev, VIA_UDMA_TIMING + 3 - dn, &udma_etc);
-
- /* clear transfer mode bit */
- udma_etc &= ~0x20;
-
- if (timing->udma) {
- /* preserve 80-wire cable detection bit */
- udma_etc &= 0x10;
- udma_etc |= t;
- }
-
- pci_write_config_byte(dev, VIA_UDMA_TIMING + 3 - dn, udma_etc);
- }
-}
-
-/**
- * via_set_drive - configure transfer mode
- * @hwif: port
- * @drive: Drive to set up
- *
- * via_set_drive() computes timing values configures the chipset to
- * a desired transfer mode. It also can be called by upper layers.
- */
-
-static void via_set_drive(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- ide_drive_t *peer = ide_get_pair_dev(drive);
- struct ide_host *host = dev_get_drvdata(hwif->dev);
- struct via82cxxx_dev *vdev = host->host_priv;
- struct ide_timing t, p;
- unsigned int T, UT;
- const u8 speed = drive->dma_mode;
-
- T = 1000000000 / via_clock;
-
- switch (vdev->via_config->udma_mask) {
- case ATA_UDMA2: UT = T; break;
- case ATA_UDMA4: UT = T/2; break;
- case ATA_UDMA5: UT = T/3; break;
- case ATA_UDMA6: UT = T/4; break;
- default: UT = T;
- }
-
- ide_timing_compute(drive, speed, &t, T, UT);
-
- if (peer) {
- ide_timing_compute(peer, peer->pio_mode, &p, T, UT);
- ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
- }
-
- via_set_speed(hwif, drive->dn, &t);
-}
-
-/**
- * via_set_pio_mode - set host controller for PIO mode
- * @hwif: port
- * @drive: drive
- *
- * A callback from the upper layers for PIO-only tuning.
- */
-
-static void via_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
- drive->dma_mode = drive->pio_mode;
- via_set_drive(hwif, drive);
-}
-
-static struct via_isa_bridge *via_config_find(struct pci_dev **isa)
-{
- struct via_isa_bridge *via_config;
-
- for (via_config = via_isa_bridges;
- via_config->id != PCI_DEVICE_ID_VIA_ANON; via_config++)
- if ((*isa = pci_get_device(PCI_VENDOR_ID_VIA +
- !!(via_config->flags & VIA_BAD_ID),
- via_config->id, NULL))) {
-
- if ((*isa)->revision >= via_config->rev_min &&
- (*isa)->revision <= via_config->rev_max)
- break;
- pci_dev_put(*isa);
- }
-
- return via_config;
-}
-
-/*
- * Check and handle 80-wire cable presence
- */
-static void via_cable_detect(struct via82cxxx_dev *vdev, u32 u)
-{
- int i;
-
- switch (vdev->via_config->udma_mask) {
- case ATA_UDMA4:
- for (i = 24; i >= 0; i -= 8)
- if (((u >> (i & 16)) & 8) &&
- ((u >> i) & 0x20) &&
- (((u >> i) & 7) < 2)) {
- /*
- * 2x PCI clock and
- * UDMA w/ < 3T/cycle
- */
- vdev->via_80w |= (1 << (1 - (i >> 4)));
- }
- break;
-
- case ATA_UDMA5:
- for (i = 24; i >= 0; i -= 8)
- if (((u >> i) & 0x10) ||
- (((u >> i) & 0x20) &&
- (((u >> i) & 7) < 4))) {
- /* BIOS 80-wire bit or
- * UDMA w/ < 60ns/cycle
- */
- vdev->via_80w |= (1 << (1 - (i >> 4)));
- }
- break;
-
- case ATA_UDMA6:
- for (i = 24; i >= 0; i -= 8)
- if (((u >> i) & 0x10) ||
- (((u >> i) & 0x20) &&
- (((u >> i) & 7) < 6))) {
- /* BIOS 80-wire bit or
- * UDMA w/ < 60ns/cycle
- */
- vdev->via_80w |= (1 << (1 - (i >> 4)));
- }
- break;
- }
-}
-
-/**
- * init_chipset_via82cxxx - initialization handler
- * @dev: PCI device
- *
- * The initialization callback. Here we determine the IDE chip type
- * and initialize its drive independent registers.
- */
-
-static int init_chipset_via82cxxx(struct pci_dev *dev)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- struct via82cxxx_dev *vdev = host->host_priv;
- struct via_isa_bridge *via_config = vdev->via_config;
- u8 t, v;
- u32 u;
-
- /*
- * Detect cable and configure Clk66
- */
- pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-
- via_cable_detect(vdev, u);
-
- if (via_config->udma_mask == ATA_UDMA4) {
- /* Enable Clk66 */
- pci_write_config_dword(dev, VIA_UDMA_TIMING, u|0x80008);
- } else if (via_config->flags & VIA_BAD_CLK66) {
- /* Would cause trouble on 596a and 686 */
- pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008);
- }
-
- /*
- * Check whether interfaces are enabled.
- */
-
- pci_read_config_byte(dev, VIA_IDE_ENABLE, &v);
-
- /*
- * Set up FIFO sizes and thresholds.
- */
-
- pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t);
-
- /* Disable PREQ# till DDACK# */
- if (via_config->flags & VIA_BAD_PREQ) {
- /* Would crash on 586b rev 41 */
- t &= 0x7f;
- }
-
- /* Fix FIFO split between channels */
- if (via_config->flags & VIA_SET_FIFO) {
- t &= (t & 0x9f);
- switch (v & 3) {
- case 2: t |= 0x00; break; /* 16 on primary */
- case 1: t |= 0x60; break; /* 16 on secondary */
- case 3: t |= 0x20; break; /* 8 pri 8 sec */
- }
- }
-
- pci_write_config_byte(dev, VIA_FIFO_CONFIG, t);
-
- return 0;
-}
-
-/*
- * Cable special cases
- */
-
-static const struct dmi_system_id cable_dmi_table[] = {
- {
- .ident = "Acer Ferrari 3400",
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "Acer,Inc."),
- DMI_MATCH(DMI_BOARD_NAME, "Ferrari 3400"),
- },
- },
- { }
-};
-
-static int via_cable_override(struct pci_dev *pdev)
-{
- /* Systems by DMI */
- if (dmi_check_system(cable_dmi_table))
- return 1;
-
- /* Arima W730-K8/Targa Visionary 811/... */
- if (pdev->subsystem_vendor == 0x161F &&
- pdev->subsystem_device == 0x2032)
- return 1;
-
- return 0;
-}
-
-static u8 via82cxxx_cable_detect(ide_hwif_t *hwif)
-{
- struct pci_dev *pdev = to_pci_dev(hwif->dev);
- struct ide_host *host = pci_get_drvdata(pdev);
- struct via82cxxx_dev *vdev = host->host_priv;
-
- if (via_cable_override(pdev))
- return ATA_CBL_PATA40_SHORT;
-
- if ((vdev->via_config->flags & VIA_SATA_PATA) && hwif->channel == 0)
- return ATA_CBL_SATA;
-
- if ((vdev->via_80w >> hwif->channel) & 1)
- return ATA_CBL_PATA80;
- else
- return ATA_CBL_PATA40;
-}
-
-static const struct ide_port_ops via_port_ops = {
- .set_pio_mode = via_set_pio_mode,
- .set_dma_mode = via_set_drive,
- .cable_detect = via82cxxx_cable_detect,
-};
-
-static const struct ide_port_info via82cxxx_chipset = {
- .name = DRV_NAME,
- .init_chipset = init_chipset_via82cxxx,
- .enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
- .port_ops = &via_port_ops,
- .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST |
- IDE_HFLAG_POST_SET_MODE |
- IDE_HFLAG_IO_32BIT,
- .pio_mask = ATA_PIO5,
- .swdma_mask = ATA_SWDMA2,
- .mwdma_mask = ATA_MWDMA2,
-};
-
-static int via_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct pci_dev *isa = NULL;
- struct via_isa_bridge *via_config;
- struct via82cxxx_dev *vdev;
- int rc;
- u8 idx = id->driver_data;
- struct ide_port_info d;
-
- d = via82cxxx_chipset;
-
- /*
- * Find the ISA bridge and check we know what it is.
- */
- via_config = via_config_find(&isa);
-
- /*
- * Print the boot message.
- */
- printk(KERN_INFO DRV_NAME " %s: VIA %s (rev %02x) IDE %sDMA%s\n",
- pci_name(dev), via_config->name, isa->revision,
- via_config->udma_mask ? "U" : "MW",
- via_dma[via_config->udma_mask ?
- (fls(via_config->udma_mask) - 1) : 0]);
-
- pci_dev_put(isa);
-
- /*
- * Determine system bus clock.
- */
- via_clock = (ide_pci_clk ? ide_pci_clk : 33) * 1000;
-
- switch (via_clock) {
- case 33000: via_clock = 33333; break;
- case 37000: via_clock = 37500; break;
- case 41000: via_clock = 41666; break;
- }
-
- if (via_clock < 20000 || via_clock > 50000) {
- printk(KERN_WARNING DRV_NAME ": User given PCI clock speed "
- "impossible (%d), using 33 MHz instead.\n", via_clock);
- via_clock = 33333;
- }
-
- if (idx == 1)
- d.enablebits[1].reg = d.enablebits[0].reg = 0;
- else
- d.host_flags |= IDE_HFLAG_NO_AUTODMA;
-
- if (idx == VIA_IDFLAG_SINGLE)
- d.host_flags |= IDE_HFLAG_SINGLE;
-
- if ((via_config->flags & VIA_NO_UNMASK) == 0)
- d.host_flags |= IDE_HFLAG_UNMASK_IRQS;
-
- d.udma_mask = via_config->udma_mask;
-
- vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
- if (!vdev) {
- printk(KERN_ERR DRV_NAME " %s: out of memory :(\n",
- pci_name(dev));
- return -ENOMEM;
- }
-
- vdev->via_config = via_config;
-
- rc = ide_pci_init_one(dev, &d, vdev);
- if (rc)
- kfree(vdev);
-
- return rc;
-}
-
-static void via_remove(struct pci_dev *dev)
-{
- struct ide_host *host = pci_get_drvdata(dev);
- struct via82cxxx_dev *vdev = host->host_priv;
-
- ide_pci_remove(dev);
- kfree(vdev);
-}
-
-static const struct pci_device_id via_pci_tbl[] = {
- { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), 0 },
- { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), 0 },
- { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_CX700_IDE), 0 },
- { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_VX855_IDE), VIA_IDFLAG_SINGLE },
- { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410), 1 },
- { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6415), 1 },
- { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), 1 },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, via_pci_tbl);
-
-static struct pci_driver via_pci_driver = {
- .name = "VIA_IDE",
- .id_table = via_pci_tbl,
- .probe = via_init_one,
- .remove = via_remove,
- .suspend = ide_pci_suspend,
- .resume = ide_pci_resume,
-};
-
-static int __init via_ide_init(void)
-{
- return ide_pci_register_driver(&via_pci_driver);
-}
-
-static void __exit via_ide_exit(void)
-{
- pci_unregister_driver(&via_pci_driver);
-}
-
-module_init(via_ide_init);
-module_exit(via_ide_exit);
-
-MODULE_AUTHOR("Vojtech Pavlik, Bartlomiej Zolnierkiewicz, Michel Aubry, Jeff Garzik, Andre Hedrick");
-MODULE_DESCRIPTION("PCI driver module for VIA IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index ec1b9d306ba6..e6c543b5ee1d 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -1484,6 +1484,36 @@ static void __init sklh_idle_state_table_update(void)
skl_cstates[6].flags |= CPUIDLE_FLAG_UNUSABLE; /* C9-SKL */
}
+/**
+ * skx_idle_state_table_update - Adjust the Sky Lake/Cascade Lake
+ * idle states table.
+ */
+static void __init skx_idle_state_table_update(void)
+{
+ unsigned long long msr;
+
+ rdmsrl(MSR_PKG_CST_CONFIG_CONTROL, msr);
+
+ /*
+ * 000b: C0/C1 (no package C-state support)
+ * 001b: C2
+ * 010b: C6 (non-retention)
+ * 011b: C6 (retention)
+ * 111b: No Package C state limits.
+ */
+ if ((msr & 0x7) < 2) {
+ /*
+ * Uses the CC6 + PC0 latency and 3 times of
+ * latency for target_residency if the PC6
+ * is disabled in BIOS. This is consistent
+ * with how intel_idle driver uses _CST
+ * to set the target_residency.
+ */
+ skx_cstates[2].exit_latency = 92;
+ skx_cstates[2].target_residency = 276;
+ }
+}
+
static bool __init intel_idle_verify_cstate(unsigned int mwait_hint)
{
unsigned int mwait_cstate = MWAIT_HINT2CSTATE(mwait_hint) + 1;
@@ -1515,6 +1545,9 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv)
case INTEL_FAM6_SKYLAKE:
sklh_idle_state_table_update();
break;
+ case INTEL_FAM6_SKYLAKE_X:
+ skx_idle_state_table_update();
+ break;
}
for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) {
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 8b1723635cce..0e56ace61103 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -89,13 +89,13 @@ config ADXL372_I2C
module will be called adxl372_i2c.
config BMA180
- tristate "Bosch BMA023/BMA1x0/BMA25x 3-Axis Accelerometer Driver"
+ tristate "Bosch BMA023/BMA1x0/BMA250 3-Axis Accelerometer Driver"
depends on I2C && INPUT_BMA150=n
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say Y here if you want to build a driver for the Bosch BMA023, BMA150
- BMA180, SMB380, or BMA25x triaxial acceleration sensor.
+ BMA180, BMA250 or SMB380 triaxial acceleration sensor.
To compile this driver as a module, choose M here: the
module will be called bma180.
@@ -143,9 +143,12 @@ config BMC150_ACCEL
select BMC150_ACCEL_SPI if SPI
help
Say yes here to build support for the following Bosch accelerometers:
- BMC150, BMI055, BMA250E, BMA222E, BMA255, BMA280.
+ BMA222, BMA222E, BMA250E, BMA253, BMA254, BMA255, BMA280, BMC150, BMI055.
+
+ Note that some of these are combo modules:
+ - BMC150: accelerometer and magnetometer
+ - BMI055: accelerometer and gyroscope
- This is a combo module with both accelerometer and magnetometer.
This driver is only implementing accelerometer part, which has
its own address and register map.
@@ -226,6 +229,33 @@ config DMARD10
Choosing M will build the driver as a module. If so, the module
will be called dmard10.
+config FXLS8962AF
+ tristate
+
+config FXLS8962AF_I2C
+ tristate "NXP FXLS8962AF/FXLS8964AF Accelerometer I2C Driver"
+ depends on I2C
+ select FXLS8962AF
+ select REGMAP_I2C
+ help
+ Say yes here to build support for the NXP 3-axis automotive
+ accelerometer FXLS8962AF/FXLS8964AF with I2C support.
+
+ To compile this driver as a module, choose M here: the module
+ will be called fxls8962af_i2c.
+
+config FXLS8962AF_SPI
+ tristate "NXP FXLS8962AF/FXLS8964AF Accelerometer SPI Driver"
+ depends on SPI
+ select FXLS8962AF
+ select REGMAP_SPI
+ help
+ Say yes here to build support for the NXP 3-axis automotive
+ accelerometer FXLS8962AF/FXLS8964AF with SPI support.
+
+ To compile this driver as a module, choose M here: the module
+ will be called fxls8962af_spi.
+
config HID_SENSOR_ACCEL_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
@@ -449,6 +479,19 @@ config SCA3000
To compile this driver as a module, say M here: the module will be
called sca3000.
+config SCA3300
+ tristate "Murata SCA3300 3-Axis Accelerometer Driver"
+ depends on SPI
+ select CRC8
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Murata SCA3300 3-Axis
+ accelerometer.
+
+ To compile this driver as a module, choose M here: the module will be
+ called sca3300.
+
config STK8312
tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
depends on I2C
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 32cd1342a31a..89280e823bcd 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -27,6 +27,9 @@ obj-$(CONFIG_DA311) += da311.o
obj-$(CONFIG_DMARD06) += dmard06.o
obj-$(CONFIG_DMARD09) += dmard09.o
obj-$(CONFIG_DMARD10) += dmard10.o
+obj-$(CONFIG_FXLS8962AF) += fxls8962af-core.o
+obj-$(CONFIG_FXLS8962AF_I2C) += fxls8962af-i2c.o
+obj-$(CONFIG_FXLS8962AF_SPI) += fxls8962af-spi.o
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
obj-$(CONFIG_KXSD9) += kxsd9.o
@@ -50,6 +53,7 @@ obj-$(CONFIG_MXC4005) += mxc4005.o
obj-$(CONFIG_MXC6255) += mxc6255.o
obj-$(CONFIG_SCA3000) += sca3000.o
+obj-$(CONFIG_SCA3300) += sca3300.o
obj-$(CONFIG_STK8312) += stk8312.o
obj-$(CONFIG_STK8BA50) += stk8ba50.o
diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c
index fe225990de24..7a434e2884d4 100644
--- a/drivers/iio/accel/adis16201.c
+++ b/drivers/iio/accel/adis16201.c
@@ -8,10 +8,7 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/imu/adis.h>
diff --git a/drivers/iio/accel/adis16209.c b/drivers/iio/accel/adis16209.c
index 6c2d4a967de7..ac08e866d612 100644
--- a/drivers/iio/accel/adis16209.c
+++ b/drivers/iio/accel/adis16209.c
@@ -7,11 +7,8 @@
#include <linux/device.h>
#include <linux/kernel.h>
-#include <linux/list.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/imu/adis.h>
diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c
index 9c9a896a872a..fc9592407717 100644
--- a/drivers/iio/accel/adxl372.c
+++ b/drivers/iio/accel/adxl372.c
@@ -1223,14 +1223,14 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
st->dready_trig = devm_iio_trigger_alloc(dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (st->dready_trig == NULL)
return -ENOMEM;
st->peak_datardy_trig = devm_iio_trigger_alloc(dev,
"%s-dev%d-peak",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!st->peak_datardy_trig)
return -ENOMEM;
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
index b8a7469cdae4..2edfcb4819b7 100644
--- a/drivers/iio/accel/bma180.c
+++ b/drivers/iio/accel/bma180.c
@@ -10,7 +10,6 @@
* BMA023/BMA150/SMB380: 7-bit I2C slave address 0x38
* BMA180: 7-bit I2C slave address 0x40 or 0x41
* BMA250: 7-bit I2C slave address 0x18 or 0x19
- * BMA254: 7-bit I2C slave address 0x18 or 0x19
*/
#include <linux/module.h>
@@ -38,7 +37,6 @@ enum chip_ids {
BMA150,
BMA180,
BMA250,
- BMA254,
};
struct bma180_data;
@@ -55,11 +53,10 @@ struct bma180_part_info {
u8 int_reset_reg, int_reset_mask;
u8 sleep_reg, sleep_mask;
- u8 bw_reg, bw_mask;
+ u8 bw_reg, bw_mask, bw_offset;
u8 scale_reg, scale_mask;
u8 power_reg, power_mask, lowpower_val;
u8 int_enable_reg, int_enable_mask;
- u8 int_map_reg, int_enable_dataready_int1_mask;
u8 softreset_reg, softreset_val;
int (*chip_config)(struct bma180_data *data);
@@ -112,7 +109,6 @@ struct bma180_part_info {
#define BMA023_ID_REG_VAL 0x02
#define BMA180_ID_REG_VAL 0x03
#define BMA250_ID_REG_VAL 0x03
-#define BMA254_ID_REG_VAL 0xfa /* 250 decimal */
/* Chip power modes */
#define BMA180_LOW_POWER 0x03
@@ -127,29 +123,13 @@ struct bma180_part_info {
#define BMA250_RANGE_MASK GENMASK(3, 0) /* Range of accel values */
#define BMA250_BW_MASK GENMASK(4, 0) /* Accel bandwidth */
+#define BMA250_BW_OFFSET 8
#define BMA250_SUSPEND_MASK BIT(7) /* chip will sleep */
#define BMA250_LOWPOWER_MASK BIT(6)
#define BMA250_DATA_INTEN_MASK BIT(4)
#define BMA250_INT1_DATA_MASK BIT(0)
#define BMA250_INT_RESET_MASK BIT(7) /* Reset pending interrupts */
-#define BMA254_RANGE_REG 0x0f
-#define BMA254_BW_REG 0x10
-#define BMA254_POWER_REG 0x11
-#define BMA254_RESET_REG 0x14
-#define BMA254_INT_ENABLE_REG 0x17
-#define BMA254_INT_MAP_REG 0x1a
-#define BMA254_INT_RESET_REG 0x21
-
-#define BMA254_RANGE_MASK GENMASK(3, 0) /* Range of accel values */
-#define BMA254_BW_MASK GENMASK(4, 0) /* Accel bandwidth */
-#define BMA254_SUSPEND_MASK BIT(7) /* chip will sleep */
-#define BMA254_LOWPOWER_MASK BIT(6)
-#define BMA254_DATA_INTEN_MASK BIT(4)
-#define BMA254_INT2_DATA_MASK BIT(7)
-#define BMA254_INT1_DATA_MASK BIT(0)
-#define BMA254_INT_RESET_MASK BIT(7) /* Reset pending interrupts */
-
struct bma180_data {
struct regulator *vdd_supply;
struct regulator *vddio_supply;
@@ -162,7 +142,11 @@ struct bma180_data {
int scale;
int bw;
bool pmode;
- u8 buff[16]; /* 3x 16-bit + 8-bit + padding + timestamp */
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ s16 chan[4];
+ s64 timestamp __aligned(8);
+ } scan;
};
enum bma180_chan {
@@ -178,8 +162,8 @@ static int bma023_scale_table[] = { 2452, 4903, 9709, };
static int bma180_bw_table[] = { 10, 20, 40, 75, 150, 300 }; /* Hz */
static int bma180_scale_table[] = { 1275, 1863, 2452, 3727, 4903, 9709, 19417 };
-static int bma25x_bw_table[] = { 8, 16, 31, 63, 125, 250 }; /* Hz */
-static int bma25x_scale_table[] = { 0, 0, 0, 38344, 0, 76590, 0, 0, 153180, 0,
+static int bma250_bw_table[] = { 8, 16, 31, 63, 125, 250, 500, 1000 }; /* Hz */
+static int bma250_scale_table[] = { 0, 0, 0, 38344, 0, 76590, 0, 0, 153180, 0,
0, 0, 306458 };
static int bma180_get_data_reg(struct bma180_data *data, enum bma180_chan chan)
@@ -283,7 +267,8 @@ static int bma180_set_bw(struct bma180_data *data, int val)
for (i = 0; i < data->part_info->num_bw; ++i) {
if (data->part_info->bw_table[i] == val) {
ret = bma180_set_bits(data, data->part_info->bw_reg,
- data->part_info->bw_mask, i);
+ data->part_info->bw_mask,
+ i + data->part_info->bw_offset);
if (ret) {
dev_err(&data->client->dev,
"failed to set bandwidth\n");
@@ -425,7 +410,7 @@ err:
return ret;
}
-static int bma25x_chip_config(struct bma180_data *data)
+static int bma250_chip_config(struct bma180_data *data)
{
int ret = bma180_chip_init(data);
@@ -444,8 +429,7 @@ static int bma25x_chip_config(struct bma180_data *data)
* This enables dataready interrupt on the INT1 pin
* FIXME: support using the INT2 pin
*/
- ret = bma180_set_bits(data, data->part_info->int_map_reg,
- data->part_info->int_enable_dataready_int1_mask, 1);
+ ret = bma180_set_bits(data, BMA250_INT_MAP_REG, BMA250_INT1_DATA_MASK, 1);
if (ret)
goto err;
@@ -482,7 +466,7 @@ err:
dev_err(&data->client->dev, "failed to disable the chip\n");
}
-static void bma25x_chip_disable(struct bma180_data *data)
+static void bma250_chip_disable(struct bma180_data *data)
{
if (bma180_set_new_data_intr_state(data, false))
goto err;
@@ -768,14 +752,6 @@ static const struct iio_chan_spec bma250_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(4),
};
-static const struct iio_chan_spec bma254_channels[] = {
- BMA180_ACC_CHANNEL(X, 12),
- BMA180_ACC_CHANNEL(Y, 12),
- BMA180_ACC_CHANNEL(Z, 12),
- BMA180_TEMP_CHANNEL,
- IIO_CHAN_SOFT_TIMESTAMP(4),
-};
-
static const struct bma180_part_info bma180_part_info[] = {
[BMA023] = {
.chip_id = BMA023_ID_REG_VAL,
@@ -865,10 +841,10 @@ static const struct bma180_part_info bma180_part_info[] = {
.chip_id = BMA250_ID_REG_VAL,
.channels = bma250_channels,
.num_channels = ARRAY_SIZE(bma250_channels),
- .scale_table = bma25x_scale_table,
- .num_scales = ARRAY_SIZE(bma25x_scale_table),
- .bw_table = bma25x_bw_table,
- .num_bw = ARRAY_SIZE(bma25x_bw_table),
+ .scale_table = bma250_scale_table,
+ .num_scales = ARRAY_SIZE(bma250_scale_table),
+ .bw_table = bma250_bw_table,
+ .num_bw = ARRAY_SIZE(bma250_bw_table),
.temp_offset = 48, /* 0 LSB @ 24 degree C */
.int_reset_reg = BMA250_INT_RESET_REG,
.int_reset_mask = BMA250_INT_RESET_MASK,
@@ -876,6 +852,7 @@ static const struct bma180_part_info bma180_part_info[] = {
.sleep_mask = BMA250_SUSPEND_MASK,
.bw_reg = BMA250_BW_REG,
.bw_mask = BMA250_BW_MASK,
+ .bw_offset = BMA250_BW_OFFSET,
.scale_reg = BMA250_RANGE_REG,
.scale_mask = BMA250_RANGE_MASK,
.power_reg = BMA250_POWER_REG,
@@ -883,41 +860,10 @@ static const struct bma180_part_info bma180_part_info[] = {
.lowpower_val = 1,
.int_enable_reg = BMA250_INT_ENABLE_REG,
.int_enable_mask = BMA250_DATA_INTEN_MASK,
- .int_map_reg = BMA250_INT_MAP_REG,
- .int_enable_dataready_int1_mask = BMA250_INT1_DATA_MASK,
.softreset_reg = BMA250_RESET_REG,
.softreset_val = BMA180_RESET_VAL,
- .chip_config = bma25x_chip_config,
- .chip_disable = bma25x_chip_disable,
- },
- [BMA254] = {
- .chip_id = BMA254_ID_REG_VAL,
- .channels = bma254_channels,
- .num_channels = ARRAY_SIZE(bma254_channels),
- .scale_table = bma25x_scale_table,
- .num_scales = ARRAY_SIZE(bma25x_scale_table),
- .bw_table = bma25x_bw_table,
- .num_bw = ARRAY_SIZE(bma25x_bw_table),
- .temp_offset = 46, /* 0 LSB @ 23 degree C */
- .int_reset_reg = BMA254_INT_RESET_REG,
- .int_reset_mask = BMA254_INT_RESET_MASK,
- .sleep_reg = BMA254_POWER_REG,
- .sleep_mask = BMA254_SUSPEND_MASK,
- .bw_reg = BMA254_BW_REG,
- .bw_mask = BMA254_BW_MASK,
- .scale_reg = BMA254_RANGE_REG,
- .scale_mask = BMA254_RANGE_MASK,
- .power_reg = BMA254_POWER_REG,
- .power_mask = BMA254_LOWPOWER_MASK,
- .lowpower_val = 1,
- .int_enable_reg = BMA254_INT_ENABLE_REG,
- .int_enable_mask = BMA254_DATA_INTEN_MASK,
- .int_map_reg = BMA254_INT_MAP_REG,
- .int_enable_dataready_int1_mask = BMA254_INT1_DATA_MASK,
- .softreset_reg = BMA254_RESET_REG,
- .softreset_val = BMA180_RESET_VAL,
- .chip_config = bma25x_chip_config,
- .chip_disable = bma25x_chip_disable,
+ .chip_config = bma250_chip_config,
+ .chip_disable = bma250_chip_disable,
},
};
@@ -938,12 +884,12 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p)
mutex_unlock(&data->mutex);
goto err;
}
- ((s16 *)data->buff)[i++] = ret;
+ data->scan.chan[i++] = ret;
}
mutex_unlock(&data->mutex);
- iio_push_to_buffers_with_timestamp(indio_dev, data->buff, time_ns);
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns);
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -997,8 +943,7 @@ static int bma180_probe(struct i2c_client *client,
chip = id->driver_data;
data->part_info = &bma180_part_info[chip];
- ret = iio_read_mount_matrix(dev, "mount-matrix",
- &data->orientation);
+ ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
@@ -1045,7 +990,7 @@ static int bma180_probe(struct i2c_client *client,
if (client->irq > 0) {
data->trig = iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->trig) {
ret = -ENOMEM;
goto err_chip_disable;
@@ -1158,7 +1103,6 @@ static const struct i2c_device_id bma180_ids[] = {
{ "bma150", BMA150 },
{ "bma180", BMA180 },
{ "bma250", BMA250 },
- { "bma254", BMA254 },
{ "smb380", BMA150 },
{ }
};
@@ -1183,10 +1127,6 @@ static const struct of_device_id bma180_of_match[] = {
.data = (void *)BMA250
},
{
- .compatible = "bosch,bma254",
- .data = (void *)BMA254
- },
- {
.compatible = "bosch,smb380",
.data = (void *)BMA150
},
@@ -1209,5 +1149,5 @@ module_i2c_driver(bma180_driver);
MODULE_AUTHOR("Kravchenko Oleksandr <x0199363@ti.com>");
MODULE_AUTHOR("Texas Instruments, Inc.");
-MODULE_DESCRIPTION("Bosch BMA023/BMA1x0/BMA25x triaxial acceleration sensor");
+MODULE_DESCRIPTION("Bosch BMA023/BMA1x0/BMA250 triaxial acceleration sensor");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c
index 36fc9876dbca..0622c7936499 100644
--- a/drivers/iio/accel/bma220_spi.c
+++ b/drivers/iio/accel/bma220_spi.c
@@ -63,7 +63,11 @@ static const int bma220_scale_table[][2] = {
struct bma220_data {
struct spi_device *spi_device;
struct mutex lock;
- s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 8x8 timestamp */
+ struct {
+ s8 chans[3];
+ /* Ensure timestamp is naturally aligned. */
+ s64 timestamp __aligned(8);
+ } scan;
u8 tx_buf[2] ____cacheline_aligned;
};
@@ -94,12 +98,12 @@ static irqreturn_t bma220_trigger_handler(int irq, void *p)
mutex_lock(&data->lock);
data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK;
- ret = spi_write_then_read(spi, data->tx_buf, 1, data->buffer,
+ ret = spi_write_then_read(spi, data->tx_buf, 1, &data->scan.chans,
ARRAY_SIZE(bma220_channels) - 1);
if (ret < 0)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
pf->timestamp);
err:
mutex_unlock(&data->lock);
diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c
index 7eeba80e32cb..21520e022a21 100644
--- a/drivers/iio/accel/bma400_core.c
+++ b/drivers/iio/accel/bma400_core.c
@@ -811,7 +811,7 @@ int bma400_probe(struct device *dev, struct regmap *regmap, const char *name)
if (ret)
return ret;
- ret = iio_read_mount_matrix(dev, "mount-matrix", &data->orientation);
+ ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 04d85ce34e9f..5ce384ebe6c7 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -1,14 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
- * - BMC150
- * - BMI055
- * - BMA255
- * - BMA250E
- * - BMA222
- * - BMA222E
- * - BMA280
- *
+ * 3-axis accelerometer driver supporting many Bosch-Sensortec chips
* Copyright (c) 2014, Intel Corporation.
*/
@@ -157,59 +149,6 @@ struct bmc150_accel_chip_info {
const struct bmc150_scale_info scale_table[4];
};
-struct bmc150_accel_interrupt {
- const struct bmc150_accel_interrupt_info *info;
- atomic_t users;
-};
-
-struct bmc150_accel_trigger {
- struct bmc150_accel_data *data;
- struct iio_trigger *indio_trig;
- int (*setup)(struct bmc150_accel_trigger *t, bool state);
- int intr;
- bool enabled;
-};
-
-enum bmc150_accel_interrupt_id {
- BMC150_ACCEL_INT_DATA_READY,
- BMC150_ACCEL_INT_ANY_MOTION,
- BMC150_ACCEL_INT_WATERMARK,
- BMC150_ACCEL_INTERRUPTS,
-};
-
-enum bmc150_accel_trigger_id {
- BMC150_ACCEL_TRIGGER_DATA_READY,
- BMC150_ACCEL_TRIGGER_ANY_MOTION,
- BMC150_ACCEL_TRIGGERS,
-};
-
-struct bmc150_accel_data {
- struct regmap *regmap;
- struct regulator_bulk_data regulators[2];
- struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
- struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
- struct mutex mutex;
- u8 fifo_mode, watermark;
- s16 buffer[8];
- /*
- * Ensure there is sufficient space and correct alignment for
- * the timestamp if enabled
- */
- struct {
- __le16 channels[3];
- s64 ts __aligned(8);
- } scan;
- u8 bw_bits;
- u32 slope_dur;
- u32 slope_thres;
- u32 range;
- int ev_enable_state;
- int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
- const struct bmc150_accel_chip_info *chip_info;
- struct i2c_client *second_device;
- struct iio_mount_matrix orientation;
-};
-
static const struct {
int val;
int val2;
@@ -389,7 +328,7 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
int ret;
if (on) {
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
} else {
pm_runtime_mark_last_busy(dev);
ret = pm_runtime_put_autosuspend(dev);
@@ -398,9 +337,6 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
if (ret < 0) {
dev_err(dev,
"Failed: %s for %d\n", __func__, on);
- if (on)
- pm_runtime_put_noidle(dev);
-
return ret;
}
@@ -439,8 +375,8 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
* Onda V80 plus
* Predia Basic Tablet
*/
-static bool bmc150_apply_acpi_orientation(struct device *dev,
- struct iio_mount_matrix *orientation)
+static bool bmc150_apply_bosc0200_acpi_orientation(struct device *dev,
+ struct iio_mount_matrix *orientation)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct iio_dev *indio_dev = dev_get_drvdata(dev);
@@ -450,9 +386,6 @@ static bool bmc150_apply_acpi_orientation(struct device *dev,
acpi_status status;
int i, j, val[3];
- if (!adev || !acpi_dev_hid_uid_match(adev, "BOSC0200", NULL))
- return false;
-
if (strcmp(dev_name(dev), "i2c-BOSC0200:base") == 0) {
alt_name = "ROMK";
label = "accel-base";
@@ -508,6 +441,33 @@ unknown_format:
kfree(buffer.pointer);
return false;
}
+
+static bool bmc150_apply_dual250e_acpi_orientation(struct device *dev,
+ struct iio_mount_matrix *orientation)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+
+ if (strcmp(dev_name(dev), "i2c-DUAL250E:base") == 0)
+ indio_dev->label = "accel-base";
+ else
+ indio_dev->label = "accel-display";
+
+ return false; /* DUAL250E fwnodes have no mount matrix info */
+}
+
+static bool bmc150_apply_acpi_orientation(struct device *dev,
+ struct iio_mount_matrix *orientation)
+{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+
+ if (adev && acpi_dev_hid_uid_match(adev, "BOSC0200", NULL))
+ return bmc150_apply_bosc0200_acpi_orientation(dev, orientation);
+
+ if (adev && acpi_dev_hid_uid_match(adev, "DUAL250E", NULL))
+ return bmc150_apply_dual250e_acpi_orientation(dev, orientation);
+
+ return false;
+}
#else
static bool bmc150_apply_acpi_orientation(struct device *dev,
struct iio_mount_matrix *orientation)
@@ -1128,80 +1088,63 @@ static const struct iio_chan_spec bmc150_accel_channels[] =
static const struct iio_chan_spec bma280_accel_channels[] =
BMC150_ACCEL_CHANNELS(14);
+/*
+ * The range for the Bosch sensors is typically +-2g/4g/8g/16g, distributed
+ * over the amount of bits (see above). The scale table can be calculated using
+ * (range / 2^bits) * g = (range / 2^bits) * 9.80665 m/s^2
+ * e.g. for +-2g and 12 bits: (4 / 2^12) * 9.80665 m/s^2 = 0.0095768... m/s^2
+ * Multiply 10^6 and round to get the values listed below.
+ */
static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
- [bmc150] = {
- .name = "BMC150A",
- .chip_id = 0xFA,
- .channels = bmc150_accel_channels,
- .num_channels = ARRAY_SIZE(bmc150_accel_channels),
- .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G},
- {19122, BMC150_ACCEL_DEF_RANGE_4G},
- {38344, BMC150_ACCEL_DEF_RANGE_8G},
- {76590, BMC150_ACCEL_DEF_RANGE_16G} },
- },
- [bmi055] = {
- .name = "BMI055A",
- .chip_id = 0xFA,
- .channels = bmc150_accel_channels,
- .num_channels = ARRAY_SIZE(bmc150_accel_channels),
- .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G},
- {19122, BMC150_ACCEL_DEF_RANGE_4G},
- {38344, BMC150_ACCEL_DEF_RANGE_8G},
- {76590, BMC150_ACCEL_DEF_RANGE_16G} },
- },
- [bma255] = {
- .name = "BMA0255",
- .chip_id = 0xFA,
- .channels = bmc150_accel_channels,
- .num_channels = ARRAY_SIZE(bmc150_accel_channels),
- .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G},
- {19122, BMC150_ACCEL_DEF_RANGE_4G},
- {38344, BMC150_ACCEL_DEF_RANGE_8G},
- {76590, BMC150_ACCEL_DEF_RANGE_16G} },
- },
- [bma250e] = {
- .name = "BMA250E",
- .chip_id = 0xF9,
- .channels = bma250e_accel_channels,
- .num_channels = ARRAY_SIZE(bma250e_accel_channels),
- .scale_table = { {38344, BMC150_ACCEL_DEF_RANGE_2G},
- {76590, BMC150_ACCEL_DEF_RANGE_4G},
- {153277, BMC150_ACCEL_DEF_RANGE_8G},
- {306457, BMC150_ACCEL_DEF_RANGE_16G} },
- },
- [bma222] = {
+ {
.name = "BMA222",
.chip_id = 0x03,
.channels = bma222e_accel_channels,
.num_channels = ARRAY_SIZE(bma222e_accel_channels),
- /*
- * The datasheet page 17 says:
- * 15.6, 31.3, 62.5 and 125 mg per LSB.
- */
- .scale_table = { {156000, BMC150_ACCEL_DEF_RANGE_2G},
- {313000, BMC150_ACCEL_DEF_RANGE_4G},
- {625000, BMC150_ACCEL_DEF_RANGE_8G},
- {1250000, BMC150_ACCEL_DEF_RANGE_16G} },
+ .scale_table = { {153229, BMC150_ACCEL_DEF_RANGE_2G},
+ {306458, BMC150_ACCEL_DEF_RANGE_4G},
+ {612916, BMC150_ACCEL_DEF_RANGE_8G},
+ {1225831, BMC150_ACCEL_DEF_RANGE_16G} },
},
- [bma222e] = {
+ {
.name = "BMA222E",
.chip_id = 0xF8,
.channels = bma222e_accel_channels,
.num_channels = ARRAY_SIZE(bma222e_accel_channels),
- .scale_table = { {153277, BMC150_ACCEL_DEF_RANGE_2G},
- {306457, BMC150_ACCEL_DEF_RANGE_4G},
- {612915, BMC150_ACCEL_DEF_RANGE_8G},
+ .scale_table = { {153229, BMC150_ACCEL_DEF_RANGE_2G},
+ {306458, BMC150_ACCEL_DEF_RANGE_4G},
+ {612916, BMC150_ACCEL_DEF_RANGE_8G},
{1225831, BMC150_ACCEL_DEF_RANGE_16G} },
},
- [bma280] = {
- .name = "BMA0280",
+ {
+ .name = "BMA250E",
+ .chip_id = 0xF9,
+ .channels = bma250e_accel_channels,
+ .num_channels = ARRAY_SIZE(bma250e_accel_channels),
+ .scale_table = { {38307, BMC150_ACCEL_DEF_RANGE_2G},
+ {76614, BMC150_ACCEL_DEF_RANGE_4G},
+ {153229, BMC150_ACCEL_DEF_RANGE_8G},
+ {306458, BMC150_ACCEL_DEF_RANGE_16G} },
+ },
+ {
+ .name = "BMA253/BMA254/BMA255/BMC150/BMI055",
+ .chip_id = 0xFA,
+ .channels = bmc150_accel_channels,
+ .num_channels = ARRAY_SIZE(bmc150_accel_channels),
+ .scale_table = { {9577, BMC150_ACCEL_DEF_RANGE_2G},
+ {19154, BMC150_ACCEL_DEF_RANGE_4G},
+ {38307, BMC150_ACCEL_DEF_RANGE_8G},
+ {76614, BMC150_ACCEL_DEF_RANGE_16G} },
+ },
+ {
+ .name = "BMA280",
.chip_id = 0xFB,
.channels = bma280_accel_channels,
.num_channels = ARRAY_SIZE(bma280_accel_channels),
- .scale_table = { {2392, BMC150_ACCEL_DEF_RANGE_2G},
- {4785, BMC150_ACCEL_DEF_RANGE_4G},
- {9581, BMC150_ACCEL_DEF_RANGE_8G},
- {19152, BMC150_ACCEL_DEF_RANGE_16G} },
+ .scale_table = { {2394, BMC150_ACCEL_DEF_RANGE_2G},
+ {4788, BMC150_ACCEL_DEF_RANGE_4G},
+ {9577, BMC150_ACCEL_DEF_RANGE_8G},
+ {19154, BMC150_ACCEL_DEF_RANGE_16G} },
},
};
@@ -1470,9 +1413,9 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
struct bmc150_accel_trigger *t = &data->triggers[i];
t->indio_trig = devm_iio_trigger_alloc(dev,
- bmc150_accel_triggers[i].name,
+ bmc150_accel_triggers[i].name,
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!t->indio_trig) {
ret = -ENOMEM;
break;
@@ -1688,8 +1631,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
data->regmap = regmap;
if (!bmc150_apply_acpi_orientation(dev, &data->orientation)) {
- ret = iio_read_mount_matrix(dev, "mount-matrix",
- &data->orientation);
+ ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
}
@@ -1807,26 +1749,6 @@ err_disable_regulators:
}
EXPORT_SYMBOL_GPL(bmc150_accel_core_probe);
-struct i2c_client *bmc150_get_second_device(struct i2c_client *client)
-{
- struct bmc150_accel_data *data = i2c_get_clientdata(client);
-
- if (!data)
- return NULL;
-
- return data->second_device;
-}
-EXPORT_SYMBOL_GPL(bmc150_get_second_device);
-
-void bmc150_set_second_device(struct i2c_client *client)
-{
- struct bmc150_accel_data *data = i2c_get_clientdata(client);
-
- if (data)
- data->second_device = client;
-}
-EXPORT_SYMBOL_GPL(bmc150_set_second_device);
-
int bmc150_accel_core_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
@@ -1836,7 +1758,6 @@ int bmc150_accel_core_remove(struct device *dev)
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
- pm_runtime_put_noidle(dev);
bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
@@ -1876,6 +1797,9 @@ static int bmc150_accel_resume(struct device *dev)
bmc150_accel_fifo_set_mode(data);
mutex_unlock(&data->mutex);
+ if (data->resume_callback)
+ data->resume_callback(dev);
+
return 0;
}
#endif
diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c
index 69f709319484..999495f0669d 100644
--- a/drivers/iio/accel/bmc150-accel-i2c.c
+++ b/drivers/iio/accel/bmc150-accel-i2c.c
@@ -1,14 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * 3-axis accelerometer driver supporting following I2C Bosch-Sensortec chips:
- * - BMC150
- * - BMI055
- * - BMA255
- * - BMA250E
- * - BMA222
- * - BMA222E
- * - BMA280
- *
+ * 3-axis accelerometer driver supporting many I2C Bosch-Sensortec chips
* Copyright (c) 2014, Intel Corporation.
*/
@@ -21,6 +13,164 @@
#include "bmc150-accel.h"
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id bmc150_acpi_dual_accel_ids[] = {
+ {"BOSC0200"},
+ {"DUAL250E"},
+ { }
+};
+
+/*
+ * The DUAL250E ACPI device for 360° hinges type 2-in-1s with 1 accelerometer
+ * in the display and 1 in the hinge has an ACPI-method (DSM) to tell the
+ * ACPI code about the angle between the 2 halves. This will make the ACPI
+ * code enable/disable the keyboard and touchpad. We need to call this to avoid
+ * the keyboard being disabled when the 2-in-1 is turned-on or resumed while
+ * fully folded into tablet mode (which gets detected with a HALL-sensor).
+ * If we don't call this then the keyboard won't work even when the 2-in-1 is
+ * changed to be used in laptop mode after the power-on / resume.
+ *
+ * This DSM takes 2 angles, selected by setting aux0 to 0 or 1, these presumably
+ * define the angle between the gravity vector measured by the accelerometer in
+ * the display (aux0=0) resp. the base (aux0=1) and some reference vector.
+ * The 2 angles get subtracted from each other so the reference vector does
+ * not matter and we can simply leave the second angle at 0.
+ */
+
+#define BMC150_DSM_GUID "7681541e-8827-4239-8d9d-36be7fe12542"
+#define DUAL250E_SET_ANGLE_FN_INDEX 3
+
+struct dual250e_set_angle_args {
+ u32 aux0;
+ u32 ang0;
+ u32 rawx;
+ u32 rawy;
+ u32 rawz;
+} __packed;
+
+static bool bmc150_acpi_set_angle_dsm(struct i2c_client *client, u32 aux0, u32 ang0)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&client->dev);
+ struct dual250e_set_angle_args args = {
+ .aux0 = aux0,
+ .ang0 = ang0,
+ };
+ union acpi_object args_obj, *obj;
+ guid_t guid;
+
+ if (!acpi_dev_hid_uid_match(adev, "DUAL250E", NULL))
+ return false;
+
+ guid_parse(BMC150_DSM_GUID, &guid);
+
+ if (!acpi_check_dsm(adev->handle, &guid, 0, BIT(DUAL250E_SET_ANGLE_FN_INDEX)))
+ return false;
+
+ /*
+ * Note this triggers the following warning:
+ * "ACPI Warning: \_SB.PCI0.I2C2.ACC1._DSM: Argument #4 type mismatch -
+ * Found [Buffer], ACPI requires [Package]"
+ * This is unavoidable since the _DSM implementation expects a "naked"
+ * buffer, so wrapping it in a package will _not_ work.
+ */
+ args_obj.type = ACPI_TYPE_BUFFER;
+ args_obj.buffer.length = sizeof(args);
+ args_obj.buffer.pointer = (u8 *)&args;
+
+ obj = acpi_evaluate_dsm(adev->handle, &guid, 0, DUAL250E_SET_ANGLE_FN_INDEX, &args_obj);
+ if (!obj) {
+ dev_err(&client->dev, "Failed to call DSM to enable keyboard and touchpad\n");
+ return false;
+ }
+
+ ACPI_FREE(obj);
+ return true;
+}
+
+static bool bmc150_acpi_enable_keyboard(struct i2c_client *client)
+{
+ /*
+ * The EC must see a change for it to re-enable the kbd, so first
+ * set the angle to 270° (tent/stand mode) and then change it to
+ * 90° (laptop mode).
+ */
+ if (!bmc150_acpi_set_angle_dsm(client, 0, 270))
+ return false;
+
+ /* The EC needs some time to notice the angle being changed */
+ msleep(100);
+
+ return bmc150_acpi_set_angle_dsm(client, 0, 90);
+}
+
+static void bmc150_acpi_resume_work(struct work_struct *work)
+{
+ struct bmc150_accel_data *data =
+ container_of(work, struct bmc150_accel_data, resume_work.work);
+
+ bmc150_acpi_enable_keyboard(data->second_device);
+}
+
+static void bmc150_acpi_resume_handler(struct device *dev)
+{
+ struct bmc150_accel_data *data = iio_priv(dev_get_drvdata(dev));
+
+ /*
+ * Delay the bmc150_acpi_enable_keyboard() call till after the system
+ * resume has completed, otherwise it will not work.
+ */
+ schedule_delayed_work(&data->resume_work, msecs_to_jiffies(1000));
+}
+
+/*
+ * Some acpi_devices describe 2 accelerometers in a single ACPI device,
+ * try instantiating a second i2c_client for an I2cSerialBusV2 ACPI resource
+ * with index 1.
+ */
+static void bmc150_acpi_dual_accel_probe(struct i2c_client *client)
+{
+ struct bmc150_accel_data *data = iio_priv(i2c_get_clientdata(client));
+ struct acpi_device *adev = ACPI_COMPANION(&client->dev);
+ char dev_name[16];
+ struct i2c_board_info board_info = {
+ .type = "bmc150_accel",
+ .dev_name = dev_name,
+ .fwnode = client->dev.fwnode,
+ };
+
+ if (acpi_match_device_ids(adev, bmc150_acpi_dual_accel_ids))
+ return;
+
+ /*
+ * The 2nd accel sits in the base of 2-in-1s. The suffix is static, as
+ * there should never be more then 1 ACPI node with 2 accelerometers.
+ */
+ snprintf(dev_name, sizeof(dev_name), "%s:base", acpi_device_hid(adev));
+
+ board_info.irq = acpi_dev_gpio_irq_get(adev, 1);
+
+ data->second_device = i2c_acpi_new_device(&client->dev, 1, &board_info);
+
+ if (!IS_ERR(data->second_device) && bmc150_acpi_enable_keyboard(data->second_device)) {
+ INIT_DELAYED_WORK(&data->resume_work, bmc150_acpi_resume_work);
+ data->resume_callback = bmc150_acpi_resume_handler;
+ }
+}
+
+static void bmc150_acpi_dual_accel_remove(struct i2c_client *client)
+{
+ struct bmc150_accel_data *data = iio_priv(i2c_get_clientdata(client));
+
+ if (data->resume_callback)
+ cancel_delayed_work_sync(&data->resume_work);
+
+ i2c_unregister_device(data->second_device);
+}
+#else
+static void bmc150_acpi_dual_accel_probe(struct i2c_client *client) {}
+static void bmc150_acpi_dual_accel_remove(struct i2c_client *client) {}
+#endif
+
static int bmc150_accel_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -30,7 +180,6 @@ static int bmc150_accel_probe(struct i2c_client *client,
i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_I2C_BLOCK);
- struct acpi_device __maybe_unused *adev;
int ret;
regmap = devm_regmap_init_i2c(client, &bmc150_regmap_conf);
@@ -47,80 +196,62 @@ static int bmc150_accel_probe(struct i2c_client *client,
return ret;
/*
- * Some BOSC0200 acpi_devices describe 2 accelerometers in a single ACPI
- * device, try instantiating a second i2c_client for an I2cSerialBusV2
- * ACPI resource with index 1. The !id check avoids recursion when
- * bmc150_accel_probe() gets called for the second client.
+ * The !id check avoids recursion when probe() gets called
+ * for the second client.
*/
-#ifdef CONFIG_ACPI
- adev = ACPI_COMPANION(&client->dev);
- if (!id && adev && strcmp(acpi_device_hid(adev), "BOSC0200") == 0) {
- struct i2c_board_info board_info = {
- .type = "bmc150_accel",
- /*
- * The 2nd accel sits in the base of 2-in-1s. Note this
- * name is static, as there should never be more then 1
- * BOSC0200 ACPI node with 2 accelerometers in it.
- */
- .dev_name = "BOSC0200:base",
- .fwnode = client->dev.fwnode,
- .irq = -ENOENT,
- };
- struct i2c_client *second_dev;
-
- second_dev = i2c_acpi_new_device(&client->dev, 1, &board_info);
- if (!IS_ERR(second_dev))
- bmc150_set_second_device(second_dev);
- }
-#endif
+ if (!id && has_acpi_companion(&client->dev))
+ bmc150_acpi_dual_accel_probe(client);
return 0;
}
static int bmc150_accel_remove(struct i2c_client *client)
{
- struct i2c_client *second_dev = bmc150_get_second_device(client);
-
- i2c_unregister_device(second_dev);
+ bmc150_acpi_dual_accel_remove(client);
return bmc150_accel_core_remove(&client->dev);
}
static const struct acpi_device_id bmc150_accel_acpi_match[] = {
- {"BSBA0150", bmc150},
- {"BMC150A", bmc150},
- {"BMI055A", bmi055},
- {"BMA0255", bma255},
- {"BMA250E", bma250e},
- {"BMA222", bma222},
- {"BMA222E", bma222e},
- {"BMA0280", bma280},
+ {"BMA0255"},
+ {"BMA0280"},
+ {"BMA222"},
+ {"BMA222E"},
+ {"BMA250E"},
+ {"BMC150A"},
+ {"BMI055A"},
{"BOSC0200"},
+ {"BSBA0150"},
+ {"DUAL250E"},
{ },
};
MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
static const struct i2c_device_id bmc150_accel_id[] = {
- {"bmc150_accel", bmc150},
- {"bmi055_accel", bmi055},
- {"bma255", bma255},
- {"bma250e", bma250e},
- {"bma222", bma222},
- {"bma222e", bma222e},
- {"bma280", bma280},
+ {"bma222"},
+ {"bma222e"},
+ {"bma250e"},
+ {"bma253"},
+ {"bma254"},
+ {"bma255"},
+ {"bma280"},
+ {"bmc150_accel"},
+ {"bmi055_accel"},
{}
};
MODULE_DEVICE_TABLE(i2c, bmc150_accel_id);
static const struct of_device_id bmc150_accel_of_match[] = {
- { .compatible = "bosch,bmc150_accel" },
- { .compatible = "bosch,bmi055_accel" },
- { .compatible = "bosch,bma255" },
- { .compatible = "bosch,bma250e" },
{ .compatible = "bosch,bma222" },
{ .compatible = "bosch,bma222e" },
+ { .compatible = "bosch,bma250e" },
+ { .compatible = "bosch,bma253" },
+ { .compatible = "bosch,bma254" },
+ { .compatible = "bosch,bma255" },
{ .compatible = "bosch,bma280" },
+ { .compatible = "bosch,bmc150_accel" },
+ { .compatible = "bosch,bmi055_accel" },
{ },
};
MODULE_DEVICE_TABLE(of, bmc150_accel_of_match);
diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c
index 74a8aee4f612..54b8c9c8068b 100644
--- a/drivers/iio/accel/bmc150-accel-spi.c
+++ b/drivers/iio/accel/bmc150-accel-spi.c
@@ -34,26 +34,27 @@ static int bmc150_accel_remove(struct spi_device *spi)
}
static const struct acpi_device_id bmc150_accel_acpi_match[] = {
- {"BSBA0150", bmc150},
- {"BMC150A", bmc150},
- {"BMI055A", bmi055},
- {"BMA0255", bma255},
- {"BMA250E", bma250e},
- {"BMA222", bma222},
- {"BMA222E", bma222e},
- {"BMA0280", bma280},
+ {"BMA0255"},
+ {"BMA0280"},
+ {"BMA222"},
+ {"BMA222E"},
+ {"BMA250E"},
+ {"BMC150A"},
+ {"BMI055A"},
+ {"BSBA0150"},
{ },
};
MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
static const struct spi_device_id bmc150_accel_id[] = {
- {"bmc150_accel", bmc150},
- {"bmi055_accel", bmi055},
- {"bma255", bma255},
- {"bma250e", bma250e},
- {"bma222", bma222},
- {"bma222e", bma222e},
- {"bma280", bma280},
+ {"bma222"},
+ {"bma222e"},
+ {"bma250e"},
+ {"bma253"},
+ {"bma255"},
+ {"bma280"},
+ {"bmc150_accel"},
+ {"bmi055_accel"},
{}
};
MODULE_DEVICE_TABLE(spi, bmc150_accel_id);
diff --git a/drivers/iio/accel/bmc150-accel.h b/drivers/iio/accel/bmc150-accel.h
index 6024f15b9700..47121f070fe9 100644
--- a/drivers/iio/accel/bmc150-accel.h
+++ b/drivers/iio/accel/bmc150-accel.h
@@ -2,23 +2,75 @@
#ifndef _BMC150_ACCEL_H_
#define _BMC150_ACCEL_H_
+#include <linux/atomic.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+
struct regmap;
+struct i2c_client;
+struct bmc150_accel_chip_info;
+struct bmc150_accel_interrupt_info;
+
+struct bmc150_accel_interrupt {
+ const struct bmc150_accel_interrupt_info *info;
+ atomic_t users;
+};
+
+struct bmc150_accel_trigger {
+ struct bmc150_accel_data *data;
+ struct iio_trigger *indio_trig;
+ int (*setup)(struct bmc150_accel_trigger *t, bool state);
+ int intr;
+ bool enabled;
+};
+
+enum bmc150_accel_interrupt_id {
+ BMC150_ACCEL_INT_DATA_READY,
+ BMC150_ACCEL_INT_ANY_MOTION,
+ BMC150_ACCEL_INT_WATERMARK,
+ BMC150_ACCEL_INTERRUPTS,
+};
+
+enum bmc150_accel_trigger_id {
+ BMC150_ACCEL_TRIGGER_DATA_READY,
+ BMC150_ACCEL_TRIGGER_ANY_MOTION,
+ BMC150_ACCEL_TRIGGERS,
+};
-enum {
- bmc150,
- bmi055,
- bma255,
- bma250e,
- bma222,
- bma222e,
- bma280,
+struct bmc150_accel_data {
+ struct regmap *regmap;
+ struct regulator_bulk_data regulators[2];
+ struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
+ struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
+ struct mutex mutex;
+ u8 fifo_mode, watermark;
+ s16 buffer[8];
+ /*
+ * Ensure there is sufficient space and correct alignment for
+ * the timestamp if enabled
+ */
+ struct {
+ __le16 channels[3];
+ s64 ts __aligned(8);
+ } scan;
+ u8 bw_bits;
+ u32 slope_dur;
+ u32 slope_thres;
+ u32 range;
+ int ev_enable_state;
+ int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
+ const struct bmc150_accel_chip_info *chip_info;
+ struct i2c_client *second_device;
+ void (*resume_callback)(struct device *dev);
+ struct delayed_work resume_work;
+ struct iio_mount_matrix orientation;
};
int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name, bool block_supported);
int bmc150_accel_core_remove(struct device *dev);
-struct i2c_client *bmc150_get_second_device(struct i2c_client *second_device);
-void bmc150_set_second_device(struct i2c_client *second_device);
extern const struct dev_pm_ops bmc150_accel_pm_ops;
extern const struct regmap_config bmc150_regmap_conf;
diff --git a/drivers/iio/accel/bmi088-accel-core.c b/drivers/iio/accel/bmi088-accel-core.c
index 12d00658e46f..a06dae5c971d 100644
--- a/drivers/iio/accel/bmi088-accel-core.c
+++ b/drivers/iio/accel/bmi088-accel-core.c
@@ -285,11 +285,17 @@ static int bmi088_accel_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_TEMP:
- pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
ret = bmi088_accel_get_temp(data, val);
goto out_read_raw_pm_put;
case IIO_ACCEL:
- pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
goto out_read_raw_pm_put;
@@ -319,7 +325,10 @@ static int bmi088_accel_read_raw(struct iio_dev *indio_dev,
*val = BMI088_ACCEL_TEMP_UNIT;
return IIO_VAL_INT;
case IIO_ACCEL:
- pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
ret = regmap_read(data->regmap,
BMI088_ACCEL_REG_ACC_RANGE, val);
if (ret)
@@ -334,7 +343,10 @@ static int bmi088_accel_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_SAMP_FREQ:
- pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
ret = bmi088_accel_get_sample_freq(data, val, val2);
goto out_read_raw_pm_put;
default:
@@ -376,7 +388,10 @@ static int bmi088_accel_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
- pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
ret = bmi088_accel_set_sample_freq(data, val);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
@@ -496,7 +511,6 @@ int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap,
if (ret)
return ret;
- indio_dev->dev.parent = dev;
indio_dev->channels = data->chip_info->channels;
indio_dev->num_channels = data->chip_info->num_channels;
indio_dev->name = name ? name : data->chip_info->name;
@@ -531,7 +545,6 @@ int bmi088_accel_core_remove(struct device *dev)
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
- pm_runtime_put_noidle(dev);
bmi088_accel_power_down(data);
return 0;
diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c
new file mode 100644
index 000000000000..078d87865fde
--- /dev/null
+++ b/drivers/iio/accel/fxls8962af-core.c
@@ -0,0 +1,968 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NXP FXLS8962AF/FXLS8964AF Accelerometer Core Driver
+ *
+ * Copyright 2021 Connected Cars A/S
+ *
+ * Datasheet:
+ * https://www.nxp.com/docs/en/data-sheet/FXLS8962AF.pdf
+ * https://www.nxp.com/docs/en/data-sheet/FXLS8964AF.pdf
+ *
+ * Errata:
+ * https://www.nxp.com/docs/en/errata/ES_FXLS8962AF.pdf
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/sysfs.h>
+
+#include "fxls8962af.h"
+
+#define FXLS8962AF_INT_STATUS 0x00
+#define FXLS8962AF_INT_STATUS_SRC_BOOT BIT(0)
+#define FXLS8962AF_INT_STATUS_SRC_BUF BIT(5)
+#define FXLS8962AF_INT_STATUS_SRC_DRDY BIT(7)
+#define FXLS8962AF_TEMP_OUT 0x01
+#define FXLS8962AF_VECM_LSB 0x02
+#define FXLS8962AF_OUT_X_LSB 0x04
+#define FXLS8962AF_OUT_Y_LSB 0x06
+#define FXLS8962AF_OUT_Z_LSB 0x08
+#define FXLS8962AF_BUF_STATUS 0x0b
+#define FXLS8962AF_BUF_STATUS_BUF_CNT GENMASK(5, 0)
+#define FXLS8962AF_BUF_STATUS_BUF_OVF BIT(6)
+#define FXLS8962AF_BUF_STATUS_BUF_WMRK BIT(7)
+#define FXLS8962AF_BUF_X_LSB 0x0c
+#define FXLS8962AF_BUF_Y_LSB 0x0e
+#define FXLS8962AF_BUF_Z_LSB 0x10
+
+#define FXLS8962AF_PROD_REV 0x12
+#define FXLS8962AF_WHO_AM_I 0x13
+
+#define FXLS8962AF_SYS_MODE 0x14
+#define FXLS8962AF_SENS_CONFIG1 0x15
+#define FXLS8962AF_SENS_CONFIG1_ACTIVE BIT(0)
+#define FXLS8962AF_SENS_CONFIG1_RST BIT(7)
+#define FXLS8962AF_SC1_FSR_MASK GENMASK(2, 1)
+#define FXLS8962AF_SC1_FSR_PREP(x) FIELD_PREP(FXLS8962AF_SC1_FSR_MASK, (x))
+#define FXLS8962AF_SC1_FSR_GET(x) FIELD_GET(FXLS8962AF_SC1_FSR_MASK, (x))
+
+#define FXLS8962AF_SENS_CONFIG2 0x16
+#define FXLS8962AF_SENS_CONFIG3 0x17
+#define FXLS8962AF_SC3_WAKE_ODR_MASK GENMASK(7, 4)
+#define FXLS8962AF_SC3_WAKE_ODR_PREP(x) FIELD_PREP(FXLS8962AF_SC3_WAKE_ODR_MASK, (x))
+#define FXLS8962AF_SC3_WAKE_ODR_GET(x) FIELD_GET(FXLS8962AF_SC3_WAKE_ODR_MASK, (x))
+#define FXLS8962AF_SENS_CONFIG4 0x18
+#define FXLS8962AF_SC4_INT_PP_OD_MASK BIT(1)
+#define FXLS8962AF_SC4_INT_PP_OD_PREP(x) FIELD_PREP(FXLS8962AF_SC4_INT_PP_OD_MASK, (x))
+#define FXLS8962AF_SC4_INT_POL_MASK BIT(0)
+#define FXLS8962AF_SC4_INT_POL_PREP(x) FIELD_PREP(FXLS8962AF_SC4_INT_POL_MASK, (x))
+#define FXLS8962AF_SENS_CONFIG5 0x19
+
+#define FXLS8962AF_WAKE_IDLE_LSB 0x1b
+#define FXLS8962AF_SLEEP_IDLE_LSB 0x1c
+#define FXLS8962AF_ASLP_COUNT_LSB 0x1e
+
+#define FXLS8962AF_INT_EN 0x20
+#define FXLS8962AF_INT_EN_BUF_EN BIT(6)
+#define FXLS8962AF_INT_PIN_SEL 0x21
+#define FXLS8962AF_INT_PIN_SEL_MASK GENMASK(7, 0)
+#define FXLS8962AF_INT_PIN_SEL_INT1 0x00
+#define FXLS8962AF_INT_PIN_SEL_INT2 GENMASK(7, 0)
+
+#define FXLS8962AF_OFF_X 0x22
+#define FXLS8962AF_OFF_Y 0x23
+#define FXLS8962AF_OFF_Z 0x24
+
+#define FXLS8962AF_BUF_CONFIG1 0x26
+#define FXLS8962AF_BC1_BUF_MODE_MASK GENMASK(6, 5)
+#define FXLS8962AF_BC1_BUF_MODE_PREP(x) FIELD_PREP(FXLS8962AF_BC1_BUF_MODE_MASK, (x))
+#define FXLS8962AF_BUF_CONFIG2 0x27
+#define FXLS8962AF_BUF_CONFIG2_BUF_WMRK GENMASK(5, 0)
+
+#define FXLS8962AF_ORIENT_STATUS 0x28
+#define FXLS8962AF_ORIENT_CONFIG 0x29
+#define FXLS8962AF_ORIENT_DBCOUNT 0x2a
+#define FXLS8962AF_ORIENT_BF_ZCOMP 0x2b
+#define FXLS8962AF_ORIENT_THS_REG 0x2c
+
+#define FXLS8962AF_SDCD_INT_SRC1 0x2d
+#define FXLS8962AF_SDCD_INT_SRC2 0x2e
+#define FXLS8962AF_SDCD_CONFIG1 0x2f
+#define FXLS8962AF_SDCD_CONFIG2 0x30
+#define FXLS8962AF_SDCD_OT_DBCNT 0x31
+#define FXLS8962AF_SDCD_WT_DBCNT 0x32
+#define FXLS8962AF_SDCD_LTHS_LSB 0x33
+#define FXLS8962AF_SDCD_UTHS_LSB 0x35
+
+#define FXLS8962AF_SELF_TEST_CONFIG1 0x37
+#define FXLS8962AF_SELF_TEST_CONFIG2 0x38
+
+#define FXLS8962AF_MAX_REG 0x38
+
+#define FXLS8962AF_DEVICE_ID 0x62
+#define FXLS8964AF_DEVICE_ID 0x84
+
+/* Raw temp channel offset */
+#define FXLS8962AF_TEMP_CENTER_VAL 25
+
+#define FXLS8962AF_AUTO_SUSPEND_DELAY_MS 2000
+
+#define FXLS8962AF_FIFO_LENGTH 32
+#define FXLS8962AF_SCALE_TABLE_LEN 4
+#define FXLS8962AF_SAMP_FREQ_TABLE_LEN 13
+
+static const int fxls8962af_scale_table[FXLS8962AF_SCALE_TABLE_LEN][2] = {
+ {0, IIO_G_TO_M_S_2(980000)},
+ {0, IIO_G_TO_M_S_2(1950000)},
+ {0, IIO_G_TO_M_S_2(3910000)},
+ {0, IIO_G_TO_M_S_2(7810000)},
+};
+
+static const int fxls8962af_samp_freq_table[FXLS8962AF_SAMP_FREQ_TABLE_LEN][2] = {
+ {3200, 0}, {1600, 0}, {800, 0}, {400, 0}, {200, 0}, {100, 0},
+ {50, 0}, {25, 0}, {12, 500000}, {6, 250000}, {3, 125000},
+ {1, 563000}, {0, 781000},
+};
+
+struct fxls8962af_chip_info {
+ const char *name;
+ const struct iio_chan_spec *channels;
+ int num_channels;
+ u8 chip_id;
+};
+
+struct fxls8962af_data {
+ struct regmap *regmap;
+ const struct fxls8962af_chip_info *chip_info;
+ struct regulator *vdd_reg;
+ struct {
+ __le16 channels[3];
+ s64 ts __aligned(8);
+ } scan;
+ int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
+ struct iio_mount_matrix orientation;
+ u8 watermark;
+};
+
+const struct regmap_config fxls8962af_regmap_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = FXLS8962AF_MAX_REG,
+};
+EXPORT_SYMBOL_GPL(fxls8962af_regmap_conf);
+
+enum {
+ fxls8962af_idx_x,
+ fxls8962af_idx_y,
+ fxls8962af_idx_z,
+ fxls8962af_idx_ts,
+};
+
+enum fxls8962af_int_pin {
+ FXLS8962AF_PIN_INT1,
+ FXLS8962AF_PIN_INT2,
+};
+
+static int fxls8962af_power_on(struct fxls8962af_data *data)
+{
+ struct device *dev = regmap_get_device(data->regmap);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ dev_err(dev, "failed to power on\n");
+
+ return ret;
+}
+
+static int fxls8962af_power_off(struct fxls8962af_data *data)
+{
+ struct device *dev = regmap_get_device(data->regmap);
+ int ret;
+
+ pm_runtime_mark_last_busy(dev);
+ ret = pm_runtime_put_autosuspend(dev);
+ if (ret)
+ dev_err(dev, "failed to power off\n");
+
+ return ret;
+}
+
+static int fxls8962af_standby(struct fxls8962af_data *data)
+{
+ return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
+ FXLS8962AF_SENS_CONFIG1_ACTIVE, 0);
+}
+
+static int fxls8962af_active(struct fxls8962af_data *data)
+{
+ return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
+ FXLS8962AF_SENS_CONFIG1_ACTIVE, 1);
+}
+
+static int fxls8962af_is_active(struct fxls8962af_data *data)
+{
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG1, &reg);
+ if (ret)
+ return ret;
+
+ return reg & FXLS8962AF_SENS_CONFIG1_ACTIVE;
+}
+
+static int fxls8962af_get_out(struct fxls8962af_data *data,
+ struct iio_chan_spec const *chan, int *val)
+{
+ struct device *dev = regmap_get_device(data->regmap);
+ __le16 raw_val;
+ int is_active;
+ int ret;
+
+ is_active = fxls8962af_is_active(data);
+ if (!is_active) {
+ ret = fxls8962af_power_on(data);
+ if (ret)
+ return ret;
+ }
+
+ ret = regmap_bulk_read(data->regmap, chan->address,
+ &raw_val, (chan->scan_type.storagebits / 8));
+
+ if (!is_active)
+ fxls8962af_power_off(data);
+
+ if (ret) {
+ dev_err(dev, "failed to get out reg 0x%lx\n", chan->address);
+ return ret;
+ }
+
+ *val = sign_extend32(le16_to_cpu(raw_val),
+ chan->scan_type.realbits - 1);
+
+ return IIO_VAL_INT;
+}
+
+static int fxls8962af_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ *type = IIO_VAL_INT_PLUS_NANO;
+ *vals = (int *)fxls8962af_scale_table;
+ *length = ARRAY_SIZE(fxls8962af_scale_table) * 2;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *vals = (int *)fxls8962af_samp_freq_table;
+ *length = ARRAY_SIZE(fxls8962af_samp_freq_table) * 2;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int fxls8962af_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return IIO_VAL_INT_PLUS_NANO;
+ }
+}
+
+static int fxls8962af_update_config(struct fxls8962af_data *data, u8 reg,
+ u8 mask, u8 val)
+{
+ int ret;
+ int is_active;
+
+ is_active = fxls8962af_is_active(data);
+ if (is_active) {
+ ret = fxls8962af_standby(data);
+ if (ret)
+ return ret;
+ }
+
+ ret = regmap_update_bits(data->regmap, reg, mask, val);
+ if (ret)
+ return ret;
+
+ if (is_active) {
+ ret = fxls8962af_active(data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fxls8962af_set_full_scale(struct fxls8962af_data *data, u32 scale)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fxls8962af_scale_table); i++)
+ if (scale == fxls8962af_scale_table[i][1])
+ break;
+
+ if (i == ARRAY_SIZE(fxls8962af_scale_table))
+ return -EINVAL;
+
+ return fxls8962af_update_config(data, FXLS8962AF_SENS_CONFIG1,
+ FXLS8962AF_SC1_FSR_MASK,
+ FXLS8962AF_SC1_FSR_PREP(i));
+}
+
+static unsigned int fxls8962af_read_full_scale(struct fxls8962af_data *data,
+ int *val)
+{
+ int ret;
+ unsigned int reg;
+ u8 range_idx;
+
+ ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG1, &reg);
+ if (ret)
+ return ret;
+
+ range_idx = FXLS8962AF_SC1_FSR_GET(reg);
+
+ *val = fxls8962af_scale_table[range_idx][1];
+
+ return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int fxls8962af_set_samp_freq(struct fxls8962af_data *data, u32 val,
+ u32 val2)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fxls8962af_samp_freq_table); i++)
+ if (val == fxls8962af_samp_freq_table[i][0] &&
+ val2 == fxls8962af_samp_freq_table[i][1])
+ break;
+
+ if (i == ARRAY_SIZE(fxls8962af_samp_freq_table))
+ return -EINVAL;
+
+ return fxls8962af_update_config(data, FXLS8962AF_SENS_CONFIG3,
+ FXLS8962AF_SC3_WAKE_ODR_MASK,
+ FXLS8962AF_SC3_WAKE_ODR_PREP(i));
+}
+
+static unsigned int fxls8962af_read_samp_freq(struct fxls8962af_data *data,
+ int *val, int *val2)
+{
+ int ret;
+ unsigned int reg;
+ u8 range_idx;
+
+ ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG3, &reg);
+ if (ret)
+ return ret;
+
+ range_idx = FXLS8962AF_SC3_WAKE_ODR_GET(reg);
+
+ *val = fxls8962af_samp_freq_table[range_idx][0];
+ *val2 = fxls8962af_samp_freq_table[range_idx][1];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int fxls8962af_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_TEMP:
+ case IIO_ACCEL:
+ return fxls8962af_get_out(data, chan, val);
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_OFFSET:
+ if (chan->type != IIO_TEMP)
+ return -EINVAL;
+
+ *val = FXLS8962AF_TEMP_CENTER_VAL;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ return fxls8962af_read_full_scale(data, val2);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return fxls8962af_read_samp_freq(data, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int fxls8962af_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (val != 0)
+ return -EINVAL;
+
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = fxls8962af_set_full_scale(data, val2);
+
+ iio_device_release_direct_mode(indio_dev);
+ return ret;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = fxls8962af_set_samp_freq(data, val, val2);
+
+ iio_device_release_direct_mode(indio_dev);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int fxls8962af_set_watermark(struct iio_dev *indio_dev, unsigned val)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+
+ if (val > FXLS8962AF_FIFO_LENGTH)
+ val = FXLS8962AF_FIFO_LENGTH;
+
+ data->watermark = val;
+
+ return 0;
+}
+
+#define FXLS8962AF_CHANNEL(axis, reg, idx) { \
+ .type = IIO_ACCEL, \
+ .address = reg, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = idx, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ .shift = 4, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define FXLS8962AF_TEMP_CHANNEL { \
+ .type = IIO_TEMP, \
+ .address = FXLS8962AF_TEMP_OUT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_OFFSET),\
+ .scan_index = -1, \
+ .scan_type = { \
+ .realbits = 8, \
+ .storagebits = 8, \
+ }, \
+}
+
+static const struct iio_chan_spec fxls8962af_channels[] = {
+ FXLS8962AF_CHANNEL(X, FXLS8962AF_OUT_X_LSB, fxls8962af_idx_x),
+ FXLS8962AF_CHANNEL(Y, FXLS8962AF_OUT_Y_LSB, fxls8962af_idx_y),
+ FXLS8962AF_CHANNEL(Z, FXLS8962AF_OUT_Z_LSB, fxls8962af_idx_z),
+ IIO_CHAN_SOFT_TIMESTAMP(fxls8962af_idx_ts),
+ FXLS8962AF_TEMP_CHANNEL,
+};
+
+static const struct fxls8962af_chip_info fxls_chip_info_table[] = {
+ [fxls8962af] = {
+ .chip_id = FXLS8962AF_DEVICE_ID,
+ .name = "fxls8962af",
+ .channels = fxls8962af_channels,
+ .num_channels = ARRAY_SIZE(fxls8962af_channels),
+ },
+ [fxls8964af] = {
+ .chip_id = FXLS8964AF_DEVICE_ID,
+ .name = "fxls8964af",
+ .channels = fxls8962af_channels,
+ .num_channels = ARRAY_SIZE(fxls8962af_channels),
+ },
+};
+
+static const struct iio_info fxls8962af_info = {
+ .read_raw = &fxls8962af_read_raw,
+ .write_raw = &fxls8962af_write_raw,
+ .write_raw_get_fmt = fxls8962af_write_raw_get_fmt,
+ .read_avail = fxls8962af_read_avail,
+ .hwfifo_set_watermark = fxls8962af_set_watermark,
+};
+
+static int fxls8962af_reset(struct fxls8962af_data *data)
+{
+ struct device *dev = regmap_get_device(data->regmap);
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
+ FXLS8962AF_SENS_CONFIG1_RST,
+ FXLS8962AF_SENS_CONFIG1_RST);
+ if (ret)
+ return ret;
+
+ /* TBOOT1, TBOOT2, specifies we have to wait between 1 - 17.7ms */
+ ret = regmap_read_poll_timeout(data->regmap, FXLS8962AF_INT_STATUS, reg,
+ (reg & FXLS8962AF_INT_STATUS_SRC_BOOT),
+ 1000, 18000);
+ if (ret == -ETIMEDOUT)
+ dev_err(dev, "reset timeout, int_status = 0x%x\n", reg);
+
+ return ret;
+}
+
+static int __fxls8962af_fifo_set_mode(struct fxls8962af_data *data, bool onoff)
+{
+ int ret;
+
+ /* Enable watermark at max fifo size */
+ ret = regmap_update_bits(data->regmap, FXLS8962AF_BUF_CONFIG2,
+ FXLS8962AF_BUF_CONFIG2_BUF_WMRK,
+ data->watermark);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(data->regmap, FXLS8962AF_BUF_CONFIG1,
+ FXLS8962AF_BC1_BUF_MODE_MASK,
+ FXLS8962AF_BC1_BUF_MODE_PREP(onoff));
+}
+
+static int fxls8962af_buffer_preenable(struct iio_dev *indio_dev)
+{
+ return fxls8962af_power_on(iio_priv(indio_dev));
+}
+
+static int fxls8962af_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ int ret;
+
+ fxls8962af_standby(data);
+
+ /* Enable buffer interrupt */
+ ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN,
+ FXLS8962AF_INT_EN_BUF_EN,
+ FXLS8962AF_INT_EN_BUF_EN);
+ if (ret)
+ return ret;
+
+ ret = __fxls8962af_fifo_set_mode(data, true);
+
+ fxls8962af_active(data);
+
+ return ret;
+}
+
+static int fxls8962af_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ int ret;
+
+ fxls8962af_standby(data);
+
+ /* Disable buffer interrupt */
+ ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN,
+ FXLS8962AF_INT_EN_BUF_EN, 0);
+ if (ret)
+ return ret;
+
+ ret = __fxls8962af_fifo_set_mode(data, false);
+
+ fxls8962af_active(data);
+
+ return ret;
+}
+
+static int fxls8962af_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+
+ return fxls8962af_power_off(data);
+}
+
+static const struct iio_buffer_setup_ops fxls8962af_buffer_ops = {
+ .preenable = fxls8962af_buffer_preenable,
+ .postenable = fxls8962af_buffer_postenable,
+ .predisable = fxls8962af_buffer_predisable,
+ .postdisable = fxls8962af_buffer_postdisable,
+};
+
+static int fxls8962af_i2c_raw_read_errata3(struct fxls8962af_data *data,
+ u16 *buffer, int samples,
+ int sample_length)
+{
+ int i, ret;
+
+ for (i = 0; i < samples; i++) {
+ ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB,
+ &buffer[i * 3], sample_length);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int fxls8962af_fifo_transfer(struct fxls8962af_data *data,
+ u16 *buffer, int samples)
+{
+ struct device *dev = regmap_get_device(data->regmap);
+ int sample_length = 3 * sizeof(*buffer);
+ int total_length = samples * sample_length;
+ int ret;
+
+ if (i2c_verify_client(dev))
+ /*
+ * Due to errata bug:
+ * E3: FIFO burst read operation error using I2C interface
+ * We have to avoid burst reads on I2C..
+ */
+ ret = fxls8962af_i2c_raw_read_errata3(data, buffer, samples,
+ sample_length);
+ else
+ ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB, buffer,
+ total_length);
+
+ if (ret)
+ dev_err(dev, "Error transferring data from fifo: %d\n", ret);
+
+ return ret;
+}
+
+static int fxls8962af_fifo_flush(struct iio_dev *indio_dev)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ struct device *dev = regmap_get_device(data->regmap);
+ u16 buffer[FXLS8962AF_FIFO_LENGTH * 3];
+ uint64_t sample_period;
+ unsigned int reg;
+ int64_t tstamp;
+ int ret, i;
+ u8 count;
+
+ ret = regmap_read(data->regmap, FXLS8962AF_BUF_STATUS, &reg);
+ if (ret)
+ return ret;
+
+ if (reg & FXLS8962AF_BUF_STATUS_BUF_OVF) {
+ dev_err(dev, "Buffer overflow");
+ return -EOVERFLOW;
+ }
+
+ count = reg & FXLS8962AF_BUF_STATUS_BUF_CNT;
+ if (!count)
+ return 0;
+
+ data->old_timestamp = data->timestamp;
+ data->timestamp = iio_get_time_ns(indio_dev);
+
+ /*
+ * Approximate timestamps for each of the sample based on the sampling,
+ * frequency, timestamp for last sample and number of samples.
+ */
+ sample_period = (data->timestamp - data->old_timestamp);
+ do_div(sample_period, count);
+ tstamp = data->timestamp - (count - 1) * sample_period;
+
+ ret = fxls8962af_fifo_transfer(data, buffer, count);
+ if (ret)
+ return ret;
+
+ /* Demux hw FIFO into kfifo. */
+ for (i = 0; i < count; i++) {
+ int j, bit;
+
+ j = 0;
+ for_each_set_bit(bit, indio_dev->active_scan_mask,
+ indio_dev->masklength) {
+ memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit],
+ sizeof(data->scan.channels[0]));
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
+ tstamp);
+
+ tstamp += sample_period;
+ }
+
+ return count;
+}
+
+static irqreturn_t fxls8962af_interrupt(int irq, void *p)
+{
+ struct iio_dev *indio_dev = p;
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(data->regmap, FXLS8962AF_INT_STATUS, &reg);
+ if (ret)
+ return IRQ_NONE;
+
+ if (reg & FXLS8962AF_INT_STATUS_SRC_BUF) {
+ ret = fxls8962af_fifo_flush(indio_dev);
+ if (ret)
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static void fxls8962af_regulator_disable(void *data_ptr)
+{
+ struct fxls8962af_data *data = data_ptr;
+
+ regulator_disable(data->vdd_reg);
+}
+
+static void fxls8962af_pm_disable(void *dev_ptr)
+{
+ struct device *dev = dev_ptr;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
+
+ fxls8962af_standby(iio_priv(indio_dev));
+}
+
+static void fxls8962af_get_irq(struct device_node *of_node,
+ enum fxls8962af_int_pin *pin)
+{
+ int irq;
+
+ irq = of_irq_get_byname(of_node, "INT2");
+ if (irq > 0) {
+ *pin = FXLS8962AF_PIN_INT2;
+ return;
+ }
+
+ *pin = FXLS8962AF_PIN_INT1;
+}
+
+static int fxls8962af_irq_setup(struct iio_dev *indio_dev, int irq)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ struct device *dev = regmap_get_device(data->regmap);
+ unsigned long irq_type;
+ bool irq_active_high;
+ enum fxls8962af_int_pin int_pin;
+ u8 int_pin_sel;
+ int ret;
+
+ fxls8962af_get_irq(dev->of_node, &int_pin);
+ switch (int_pin) {
+ case FXLS8962AF_PIN_INT1:
+ int_pin_sel = FXLS8962AF_INT_PIN_SEL_INT1;
+ break;
+ case FXLS8962AF_PIN_INT2:
+ int_pin_sel = FXLS8962AF_INT_PIN_SEL_INT2;
+ break;
+ default:
+ dev_err(dev, "unsupported int pin selected\n");
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_PIN_SEL,
+ FXLS8962AF_INT_PIN_SEL_MASK, int_pin_sel);
+ if (ret)
+ return ret;
+
+ irq_type = irqd_get_trigger_type(irq_get_irq_data(irq));
+
+ switch (irq_type) {
+ case IRQF_TRIGGER_HIGH:
+ case IRQF_TRIGGER_RISING:
+ irq_active_high = true;
+ break;
+ case IRQF_TRIGGER_LOW:
+ case IRQF_TRIGGER_FALLING:
+ irq_active_high = false;
+ break;
+ default:
+ dev_info(dev, "mode %lx unsupported\n", irq_type);
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG4,
+ FXLS8962AF_SC4_INT_POL_MASK,
+ FXLS8962AF_SC4_INT_POL_PREP(irq_active_high));
+ if (ret)
+ return ret;
+
+ if (device_property_read_bool(dev, "drive-open-drain")) {
+ ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG4,
+ FXLS8962AF_SC4_INT_PP_OD_MASK,
+ FXLS8962AF_SC4_INT_PP_OD_PREP(1));
+ if (ret)
+ return ret;
+
+ irq_type |= IRQF_SHARED;
+ }
+
+ return devm_request_threaded_irq(dev,
+ irq,
+ NULL, fxls8962af_interrupt,
+ irq_type | IRQF_ONESHOT,
+ indio_dev->name, indio_dev);
+}
+
+int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq)
+{
+ struct fxls8962af_data *data;
+ struct iio_dev *indio_dev;
+ unsigned int reg;
+ int ret, i;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ dev_set_drvdata(dev, indio_dev);
+ data->regmap = regmap;
+
+ ret = iio_read_mount_matrix(dev, &data->orientation);
+ if (ret)
+ return ret;
+
+ data->vdd_reg = devm_regulator_get(dev, "vdd");
+ if (IS_ERR(data->vdd_reg))
+ return dev_err_probe(dev, PTR_ERR(data->vdd_reg),
+ "Failed to get vdd regulator\n");
+
+ ret = regulator_enable(data->vdd_reg);
+ if (ret) {
+ dev_err(dev, "Failed to enable vdd regulator: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(dev, fxls8962af_regulator_disable, data);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(data->regmap, FXLS8962AF_WHO_AM_I, &reg);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(fxls_chip_info_table); i++) {
+ if (fxls_chip_info_table[i].chip_id == reg) {
+ data->chip_info = &fxls_chip_info_table[i];
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(fxls_chip_info_table)) {
+ dev_err(dev, "failed to match device in table\n");
+ return -ENXIO;
+ }
+
+ indio_dev->channels = data->chip_info->channels;
+ indio_dev->num_channels = data->chip_info->num_channels;
+ indio_dev->name = data->chip_info->name;
+ indio_dev->info = &fxls8962af_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = fxls8962af_reset(data);
+ if (ret)
+ return ret;
+
+ if (irq) {
+ ret = fxls8962af_irq_setup(indio_dev, irq);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
+ INDIO_BUFFER_SOFTWARE,
+ &fxls8962af_buffer_ops);
+ if (ret)
+ return ret;
+ }
+
+ ret = pm_runtime_set_active(dev);
+ if (ret)
+ return ret;
+
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, FXLS8962AF_AUTO_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
+
+ ret = devm_add_action_or_reset(dev, fxls8962af_pm_disable, dev);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+EXPORT_SYMBOL_GPL(fxls8962af_core_probe);
+
+static int __maybe_unused fxls8962af_runtime_suspend(struct device *dev)
+{
+ struct fxls8962af_data *data = iio_priv(dev_get_drvdata(dev));
+ int ret;
+
+ ret = fxls8962af_standby(data);
+ if (ret) {
+ dev_err(dev, "powering off device failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __maybe_unused fxls8962af_runtime_resume(struct device *dev)
+{
+ struct fxls8962af_data *data = iio_priv(dev_get_drvdata(dev));
+
+ return fxls8962af_active(data);
+}
+
+const struct dev_pm_ops fxls8962af_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(fxls8962af_runtime_suspend,
+ fxls8962af_runtime_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(fxls8962af_pm_ops);
+
+MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.com>");
+MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/fxls8962af-i2c.c b/drivers/iio/accel/fxls8962af-i2c.c
new file mode 100644
index 000000000000..cfb004b20455
--- /dev/null
+++ b/drivers/iio/accel/fxls8962af-i2c.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NXP FXLS8962AF/FXLS8964AF Accelerometer I2C Driver
+ *
+ * Copyright 2021 Connected Cars A/S
+ */
+
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "fxls8962af.h"
+
+static int fxls8962af_probe(struct i2c_client *client)
+{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &fxls8962af_regmap_conf);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "Failed to initialize i2c regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ return fxls8962af_core_probe(&client->dev, regmap, client->irq);
+}
+
+static const struct i2c_device_id fxls8962af_id[] = {
+ { "fxls8962af", fxls8962af },
+ { "fxls8964af", fxls8964af },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, fxls8962af_id);
+
+static const struct of_device_id fxls8962af_of_match[] = {
+ { .compatible = "nxp,fxls8962af" },
+ { .compatible = "nxp,fxls8964af" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fxls8962af_of_match);
+
+static struct i2c_driver fxls8962af_driver = {
+ .driver = {
+ .name = "fxls8962af_i2c",
+ .of_match_table = fxls8962af_of_match,
+ .pm = &fxls8962af_pm_ops,
+ },
+ .probe_new = fxls8962af_probe,
+ .id_table = fxls8962af_id,
+};
+module_i2c_driver(fxls8962af_driver);
+
+MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.com>");
+MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer i2c driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/fxls8962af-spi.c b/drivers/iio/accel/fxls8962af-spi.c
new file mode 100644
index 000000000000..57108d3d480b
--- /dev/null
+++ b/drivers/iio/accel/fxls8962af-spi.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NXP FXLS8962AF/FXLS8964AF Accelerometer SPI Driver
+ *
+ * Copyright 2021 Connected Cars A/S
+ */
+
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include "fxls8962af.h"
+
+static int fxls8962af_probe(struct spi_device *spi)
+{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &fxls8962af_regmap_conf);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "Failed to initialize spi regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ return fxls8962af_core_probe(&spi->dev, regmap, spi->irq);
+}
+
+static const struct of_device_id fxls8962af_spi_of_match[] = {
+ { .compatible = "nxp,fxls8962af" },
+ { .compatible = "nxp,fxls8964af" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fxls8962af_spi_of_match);
+
+static const struct spi_device_id fxls8962af_spi_id_table[] = {
+ { "fxls8962af", fxls8962af },
+ { "fxls8964af", fxls8964af },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, fxls8962af_spi_id_table);
+
+static struct spi_driver fxls8962af_driver = {
+ .driver = {
+ .name = "fxls8962af_spi",
+ .pm = &fxls8962af_pm_ops,
+ .of_match_table = fxls8962af_spi_of_match,
+ },
+ .probe = fxls8962af_probe,
+ .id_table = fxls8962af_spi_id_table,
+};
+module_spi_driver(fxls8962af_driver);
+
+MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.com>");
+MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer spi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/fxls8962af.h b/drivers/iio/accel/fxls8962af.h
new file mode 100644
index 000000000000..b67572c3ef06
--- /dev/null
+++ b/drivers/iio/accel/fxls8962af.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2021 Connected Cars A/S
+ */
+#ifndef _FXLS8962AF_H_
+#define _FXLS8962AF_H_
+
+struct regmap;
+struct device;
+
+enum {
+ fxls8962af,
+ fxls8964af,
+};
+
+int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq);
+int fxls8962af_core_remove(struct device *dev);
+
+extern const struct dev_pm_ops fxls8962af_pm_ops;
+extern const struct regmap_config fxls8962af_regmap_conf;
+
+#endif /* _FXLS8962AF_H_ */
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index 2f9465cb382f..55cdca818b3b 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -6,13 +6,10 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
+#include <linux/mod_devicetable.h>
#include <linux/slab.h>
-#include <linux/delay.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
@@ -28,8 +25,11 @@ struct accel_3d_state {
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX];
- /* Reserve for 3 channels + padding + timestamp */
- u32 accel_val[ACCEL_3D_CHANNEL_MAX + 3];
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ u32 accel_val[3];
+ s64 timestamp __aligned(8);
+ } scan;
int scale_pre_decml;
int scale_post_decml;
int scale_precision;
@@ -245,8 +245,8 @@ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev,
accel_state->timestamp = iio_get_time_ns(indio_dev);
hid_sensor_push_data(indio_dev,
- accel_state->accel_val,
- sizeof(accel_state->accel_val),
+ &accel_state->scan,
+ sizeof(accel_state->scan),
accel_state->timestamp);
accel_state->timestamp = 0;
@@ -271,7 +271,7 @@ static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
case HID_USAGE_SENSOR_ACCEL_Y_AXIS:
case HID_USAGE_SENSOR_ACCEL_Z_AXIS:
offset = usage_id - HID_USAGE_SENSOR_ACCEL_X_AXIS;
- accel_state->accel_val[CHANNEL_SCAN_INDEX_X + offset] =
+ accel_state->scan.accel_val[CHANNEL_SCAN_INDEX_X + offset] =
*(u32 *)raw_data;
ret = 0;
break;
@@ -462,3 +462,4 @@ module_platform_driver(hid_accel_3d_platform_driver);
MODULE_DESCRIPTION("HID Sensor Accel 3D");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HID);
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index ff724bc17a45..a51fdd3c9b5b 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -51,13 +51,15 @@
#define KXTF9_REG_TILT_POS_CUR 0x10
#define KXTF9_REG_TILT_POS_PREV 0x11
#define KXTF9_REG_INT_SRC1 0x15
-#define KXCJK1013_REG_INT_SRC1 0x16 /* compatible, but called INT_SRC2 in KXTF9 ds */
+#define KXTF9_REG_INT_SRC2 0x16
+#define KXCJK1013_REG_INT_SRC1 0x16
#define KXCJK1013_REG_INT_SRC2 0x17
#define KXCJK1013_REG_STATUS_REG 0x18
#define KXCJK1013_REG_INT_REL 0x1A
#define KXCJK1013_REG_CTRL1 0x1B
#define KXTF9_REG_CTRL2 0x1C
-#define KXCJK1013_REG_CTRL2 0x1D /* mostly compatible, CTRL_REG3 in KTXF9 ds */
+#define KXTF9_REG_CTRL3 0x1D
+#define KXCJK1013_REG_CTRL2 0x1D
#define KXCJK1013_REG_INT_CTRL1 0x1E
#define KXCJK1013_REG_INT_CTRL2 0x1F
#define KXTF9_REG_INT_CTRL3 0x20
@@ -77,6 +79,45 @@
#define KXTF9_REG_HYST_SET 0x5F
#define KXCJK1013_REG_WAKE_THRES 0x6A
+/* Everything up to 0x11 is equal to KXCJK1013/KXTF9 above */
+#define KX023_REG_INS1 0x12
+#define KX023_REG_INS2 0x13
+#define KX023_REG_INS3 0x14
+#define KX023_REG_STAT 0x15
+#define KX023_REG_INT_REL 0x17
+#define KX023_REG_CNTL1 0x18
+#define KX023_REG_CNTL2 0x19
+#define KX023_REG_CNTL3 0x1A
+#define KX023_REG_ODCNTL 0x1B
+#define KX023_REG_INC1 0x1C
+#define KX023_REG_INC2 0x1D
+#define KX023_REG_INC3 0x1E
+#define KX023_REG_INC4 0x1F
+#define KX023_REG_INC5 0x20
+#define KX023_REG_INC6 0x21
+#define KX023_REG_TILT_TIMER 0x22
+#define KX023_REG_WUFC 0x23
+#define KX023_REG_TDTRC 0x24
+#define KX023_REG_TDTC 0x25
+#define KX023_REG_TTH 0x26
+#define KX023_REG_TTL 0x27
+#define KX023_REG_FTD 0x28
+#define KX023_REG_STD 0x29
+#define KX023_REG_TLT 0x2A
+#define KX023_REG_TWS 0x2B
+#define KX023_REG_ATH 0x30
+#define KX023_REG_TILT_ANGLE_LL 0x32
+#define KX023_REG_TILT_ANGLE_HL 0x33
+#define KX023_REG_HYST_SET 0x34
+#define KX023_REG_LP_CNTL 0x35
+#define KX023_REG_BUF_CNTL1 0x3A
+#define KX023_REG_BUF_CNTL2 0x3B
+#define KX023_REG_BUF_STATUS_1 0x3C
+#define KX023_REG_BUF_STATUS_2 0x3D
+#define KX023_REG_BUF_CLEAR 0x3E
+#define KX023_REG_BUF_READ 0x3F
+#define KX023_REG_SELF_TEST 0x60
+
#define KXCJK1013_REG_CTRL1_BIT_PC1 BIT(7)
#define KXCJK1013_REG_CTRL1_BIT_RES BIT(6)
#define KXCJK1013_REG_CTRL1_BIT_DRDY BIT(5)
@@ -117,6 +158,14 @@
#define KXCJK1013_REG_INT_SRC2_BIT_XP BIT(4)
#define KXCJK1013_REG_INT_SRC2_BIT_XN BIT(5)
+/* KX023 interrupt routing to INT1. INT2 can be configured with INC6 */
+#define KX023_REG_INC4_BFI1 BIT(6)
+#define KX023_REG_INC4_WMI1 BIT(5)
+#define KX023_REG_INC4_DRDY1 BIT(4)
+#define KX023_REG_INC4_TDTI1 BIT(2)
+#define KX023_REG_INC4_WUFI1 BIT(1)
+#define KX023_REG_INC4_TPI1 BIT(0)
+
#define KXCJK1013_DEFAULT_WAKE_THRES 1
enum kx_chipset {
@@ -124,6 +173,7 @@ enum kx_chipset {
KXCJ91008,
KXTJ21009,
KXTF9,
+ KX0231025,
KX_MAX_CHIPS /* this must be last */
};
@@ -133,6 +183,63 @@ enum kx_acpi_type {
ACPI_KIOX010A,
};
+struct kx_chipset_regs {
+ u8 int_src1;
+ u8 int_src2;
+ u8 int_rel;
+ u8 ctrl1;
+ u8 wuf_ctrl;
+ u8 int_ctrl1;
+ u8 data_ctrl;
+ u8 wake_timer;
+ u8 wake_thres;
+};
+
+static const struct kx_chipset_regs kxcjk1013_regs = {
+ .int_src1 = KXCJK1013_REG_INT_SRC1,
+ .int_src2 = KXCJK1013_REG_INT_SRC2,
+ .int_rel = KXCJK1013_REG_INT_REL,
+ .ctrl1 = KXCJK1013_REG_CTRL1,
+ .wuf_ctrl = KXCJK1013_REG_CTRL2,
+ .int_ctrl1 = KXCJK1013_REG_INT_CTRL1,
+ .data_ctrl = KXCJK1013_REG_DATA_CTRL,
+ .wake_timer = KXCJK1013_REG_WAKE_TIMER,
+ .wake_thres = KXCJK1013_REG_WAKE_THRES,
+};
+
+static const struct kx_chipset_regs kxtf9_regs = {
+ /* .int_src1 was moved to INT_SRC2 on KXTF9 */
+ .int_src1 = KXTF9_REG_INT_SRC2,
+ /* .int_src2 is not available */
+ .int_rel = KXCJK1013_REG_INT_REL,
+ .ctrl1 = KXCJK1013_REG_CTRL1,
+ .wuf_ctrl = KXTF9_REG_CTRL3,
+ .int_ctrl1 = KXCJK1013_REG_INT_CTRL1,
+ .data_ctrl = KXCJK1013_REG_DATA_CTRL,
+ .wake_timer = KXCJK1013_REG_WAKE_TIMER,
+ .wake_thres = KXTF9_REG_WAKE_THRESH,
+};
+
+/* The registers have totally different names but the bits are compatible */
+static const struct kx_chipset_regs kx0231025_regs = {
+ .int_src1 = KX023_REG_INS2,
+ .int_src2 = KX023_REG_INS3,
+ .int_rel = KX023_REG_INT_REL,
+ .ctrl1 = KX023_REG_CNTL1,
+ .wuf_ctrl = KX023_REG_CNTL3,
+ .int_ctrl1 = KX023_REG_INC1,
+ .data_ctrl = KX023_REG_ODCNTL,
+ .wake_timer = KX023_REG_WUFC,
+ .wake_thres = KX023_REG_ATH,
+};
+
+enum kxcjk1013_axis {
+ AXIS_X,
+ AXIS_Y,
+ AXIS_Z,
+ AXIS_MAX
+};
+
struct kxcjk1013_data {
struct regulator_bulk_data regulators[2];
struct i2c_client *client;
@@ -140,7 +247,11 @@ struct kxcjk1013_data {
struct iio_trigger *motion_trig;
struct iio_mount_matrix orientation;
struct mutex mutex;
- s16 buffer[8];
+ /* Ensure timestamp naturally aligned */
+ struct {
+ s16 chans[AXIS_MAX];
+ s64 timestamp __aligned(8);
+ } scan;
u8 odr_bits;
u8 range;
int wake_thres;
@@ -152,13 +263,7 @@ struct kxcjk1013_data {
int64_t timestamp;
enum kx_chipset chipset;
enum kx_acpi_type acpi_type;
-};
-
-enum kxcjk1013_axis {
- AXIS_X,
- AXIS_Y,
- AXIS_Z,
- AXIS_MAX,
+ const struct kx_chipset_regs *regs;
};
enum kxcjk1013_mode {
@@ -268,6 +373,22 @@ static const struct {
{0x05, 5100},
{0x06, 2700},
},
+ /* KX023-1025 */
+ {
+ /* First 4 are not in datasheet, taken from KXCTJ2-1009 */
+ {0x08, 1240000},
+ {0x09, 621000},
+ {0x0A, 309000},
+ {0x0B, 151000},
+ {0, 81000},
+ {0x01, 40000},
+ {0x02, 22000},
+ {0x03, 12000},
+ {0x04, 7000},
+ {0x05, 4400},
+ {0x06, 3000},
+ {0x07, 3000},
+ },
};
static const struct {
@@ -309,7 +430,7 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
{
int ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -320,8 +441,7 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
else
ret |= KXCJK1013_REG_CTRL1_BIT_PC1;
- ret = i2c_smbus_write_byte_data(data->client,
- KXCJK1013_REG_CTRL1, ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
return ret;
@@ -335,7 +455,7 @@ static int kxcjk1013_get_mode(struct kxcjk1013_data *data,
{
int ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -353,7 +473,7 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index)
{
int ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -364,9 +484,7 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index)
ret |= (KXCJK1013_scale_table[range_index].gsel_0 << 3);
ret |= (KXCJK1013_scale_table[range_index].gsel_1 << 4);
- ret = i2c_smbus_write_byte_data(data->client,
- KXCJK1013_REG_CTRL1,
- ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
return ret;
@@ -400,7 +518,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
if (ret < 0)
return ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -409,8 +527,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
/* Set 12 bit mode */
ret |= KXCJK1013_REG_CTRL1_BIT_RES;
- ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL1,
- ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl\n");
return ret;
@@ -421,7 +538,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
if (ret < 0)
return ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_DATA_CTRL);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->data_ctrl);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_data_ctrl\n");
return ret;
@@ -430,7 +547,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
data->odr_bits = ret;
/* Set up INT polarity */
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
return ret;
@@ -441,13 +558,23 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
else
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEA;
- ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
- ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
return ret;
}
+ /* On KX023, route all used interrupts to INT1 for now */
+ if (data->chipset == KX0231025 && data->client->irq > 0) {
+ ret = i2c_smbus_write_byte_data(data->client, KX023_REG_INC4,
+ KX023_REG_INC4_DRDY1 |
+ KX023_REG_INC4_WUFI1);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error writing reg_inc4\n");
+ return ret;
+ }
+ }
+
ret = kxcjk1013_set_mode(data, OPERATION);
if (ret < 0)
return ret;
@@ -478,7 +605,7 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
int ret;
if (on)
- ret = pm_runtime_get_sync(&data->client->dev);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
else {
pm_runtime_mark_last_busy(&data->client->dev);
ret = pm_runtime_put_autosuspend(&data->client->dev);
@@ -486,8 +613,6 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
if (ret < 0) {
dev_err(&data->client->dev,
"Failed: %s for %d\n", __func__, on);
- if (on)
- pm_runtime_put_noidle(&data->client->dev);
return ret;
}
#endif
@@ -497,10 +622,9 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
{
- int waketh_reg, ret;
+ int ret;
- ret = i2c_smbus_write_byte_data(data->client,
- KXCJK1013_REG_WAKE_TIMER,
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->wake_timer,
data->wake_dur);
if (ret < 0) {
dev_err(&data->client->dev,
@@ -508,9 +632,7 @@ static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
return ret;
}
- waketh_reg = data->chipset == KXTF9 ?
- KXTF9_REG_WAKE_THRESH : KXCJK1013_REG_WAKE_THRES;
- ret = i2c_smbus_write_byte_data(data->client, waketh_reg,
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->wake_thres,
data->wake_thres);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_wake_thres\n");
@@ -539,7 +661,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
if (ret < 0)
return ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
return ret;
@@ -550,14 +672,13 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
else
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN;
- ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
- ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
return ret;
}
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -568,8 +689,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
else
ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE;
- ret = i2c_smbus_write_byte_data(data->client,
- KXCJK1013_REG_CTRL1, ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
return ret;
@@ -599,7 +719,7 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
if (ret < 0)
return ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
return ret;
@@ -610,14 +730,13 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
else
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN;
- ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
- ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
return ret;
}
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
return ret;
@@ -628,8 +747,7 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
else
ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY;
- ret = i2c_smbus_write_byte_data(data->client,
- KXCJK1013_REG_CTRL1, ret);
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
return ret;
@@ -701,7 +819,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
if (ret < 0)
return ret;
- ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_DATA_CTRL,
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->data_ctrl,
odr_setting->odr_bits);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing data_ctrl\n");
@@ -710,7 +828,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
data->odr_bits = odr_setting->odr_bits;
- ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL2,
+ ret = i2c_smbus_write_byte_data(data->client, data->regs->wuf_ctrl,
odr_setting->wuf_bits);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl2\n");
@@ -1094,12 +1212,12 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
ret = i2c_smbus_read_i2c_block_data_or_emulated(data->client,
KXCJK1013_REG_XOUT_L,
AXIS_MAX * 2,
- (u8 *)data->buffer);
+ (u8 *)data->scan.chans);
mutex_unlock(&data->mutex);
if (ret < 0)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
data->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -1113,7 +1231,7 @@ static void kxcjk1013_trig_reen(struct iio_trigger *trig)
struct kxcjk1013_data *data = iio_priv(indio_dev);
int ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->int_rel);
if (ret < 0)
dev_err(&data->client->dev, "Error reading reg_int_rel\n");
}
@@ -1166,8 +1284,7 @@ static void kxcjk1013_report_motion_event(struct iio_dev *indio_dev)
{
struct kxcjk1013_data *data = iio_priv(indio_dev);
- int ret = i2c_smbus_read_byte_data(data->client,
- KXCJK1013_REG_INT_SRC2);
+ int ret = i2c_smbus_read_byte_data(data->client, data->regs->int_src2);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_src2\n");
return;
@@ -1234,7 +1351,7 @@ static irqreturn_t kxcjk1013_event_handler(int irq, void *private)
struct kxcjk1013_data *data = iio_priv(indio_dev);
int ret;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_SRC1);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->int_src1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_src1\n");
goto ack_intr;
@@ -1257,7 +1374,7 @@ ack_intr:
if (data->dready_trigger_on)
return IRQ_HANDLED;
- ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL);
+ ret = i2c_smbus_read_byte_data(data->client, data->regs->int_rel);
if (ret < 0)
dev_err(&data->client->dev, "Error reading reg_int_rel\n");
@@ -1338,8 +1455,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
} else {
data->active_high_intr = true; /* default polarity */
- ret = iio_read_mount_matrix(&client->dev, "mount-matrix",
- &data->orientation);
+ ret = iio_read_mount_matrix(&client->dev, &data->orientation);
if (ret)
return ret;
}
@@ -1378,6 +1494,22 @@ static int kxcjk1013_probe(struct i2c_client *client,
} else
return -ENODEV;
+ switch (data->chipset) {
+ case KXCJK1013:
+ case KXCJ91008:
+ case KXTJ21009:
+ data->regs = &kxcjk1013_regs;
+ break;
+ case KXTF9:
+ data->regs = &kxtf9_regs;
+ break;
+ case KX0231025:
+ data->regs = &kx0231025_regs;
+ break;
+ default:
+ return -EINVAL;
+ }
+
ret = kxcjk1013_chip_init(data);
if (ret < 0)
return ret;
@@ -1404,7 +1536,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->dready_trig) {
ret = -ENOMEM;
goto err_poweroff;
@@ -1413,7 +1545,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
data->motion_trig = devm_iio_trigger_alloc(&client->dev,
"%s-any-motion-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->motion_trig) {
ret = -ENOMEM;
goto err_poweroff;
@@ -1485,7 +1617,6 @@ static int kxcjk1013_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
if (data->dready_trig) {
iio_triggered_buffer_cleanup(indio_dev);
@@ -1593,6 +1724,7 @@ static const struct i2c_device_id kxcjk1013_id[] = {
{"kxcj91008", KXCJ91008},
{"kxtj21009", KXTJ21009},
{"kxtf9", KXTF9},
+ {"kx023-1025", KX0231025},
{"SMO8500", KXCJ91008},
{}
};
@@ -1604,6 +1736,7 @@ static const struct of_device_id kxcjk1013_of_match[] = {
{ .compatible = "kionix,kxcj91008", },
{ .compatible = "kionix,kxtj21009", },
{ .compatible = "kionix,kxtf9", },
+ { .compatible = "kionix,kx023-1025", },
{ }
};
MODULE_DEVICE_TABLE(of, kxcjk1013_of_match);
diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
index 0e18b92e2099..bf7ed9e7d00f 100644
--- a/drivers/iio/accel/kxsd9.c
+++ b/drivers/iio/accel/kxsd9.c
@@ -420,7 +420,7 @@ int kxsd9_common_probe(struct device *dev,
indio_dev->available_scan_masks = kxsd9_scan_masks;
/* Read the mounting matrix, if present */
- ret = iio_read_mount_matrix(dev, "mount-matrix", &st->orientation);
+ ret = iio_read_mount_matrix(dev, &st->orientation);
if (ret)
return ret;
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 4d307dfb9169..715b8138fb71 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -221,7 +221,7 @@ static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on)
int ret;
if (on) {
- ret = pm_runtime_get_sync(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
} else {
pm_runtime_mark_last_busy(&client->dev);
ret = pm_runtime_put_autosuspend(&client->dev);
@@ -230,8 +230,6 @@ static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on)
if (ret < 0) {
dev_err(&client->dev,
"failed to change power state to %d\n", on);
- if (on)
- pm_runtime_put_noidle(&client->dev);
return ret;
}
@@ -1461,7 +1459,7 @@ static int mma8452_trigger_setup(struct iio_dev *indio_dev)
trig = devm_iio_trigger_alloc(&data->client->dev, "%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!trig)
return -ENOMEM;
@@ -1711,7 +1709,6 @@ static int mma8452_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
iio_triggered_buffer_cleanup(indio_dev);
mma8452_trigger_cleanup(indio_dev);
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
index 08a2303cc9df..4c359fb05480 100644
--- a/drivers/iio/accel/mma9551.c
+++ b/drivers/iio/accel/mma9551.c
@@ -515,7 +515,6 @@ static int mma9551_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
mutex_lock(&data->mutex);
mma9551_set_device_state(data->client, false);
diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c
index 666e7a04a7d7..fbf2e2c45678 100644
--- a/drivers/iio/accel/mma9551_core.c
+++ b/drivers/iio/accel/mma9551_core.c
@@ -664,7 +664,7 @@ int mma9551_set_power_state(struct i2c_client *client, bool on)
int ret;
if (on)
- ret = pm_runtime_get_sync(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
else {
pm_runtime_mark_last_busy(&client->dev);
ret = pm_runtime_put_autosuspend(&client->dev);
@@ -673,8 +673,6 @@ int mma9551_set_power_state(struct i2c_client *client, bool on)
if (ret < 0) {
dev_err(&client->dev,
"failed to change power state to %d\n", on);
- if (on)
- pm_runtime_put_noidle(&client->dev);
return ret;
}
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
index c15908faa381..ba3ecb3b57dc 100644
--- a/drivers/iio/accel/mma9553.c
+++ b/drivers/iio/accel/mma9553.c
@@ -1154,7 +1154,6 @@ static int mma9553_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
mutex_lock(&data->mutex);
mma9551_set_device_state(data->client, false);
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c
index fb3cbaa62bd8..b3afbf064915 100644
--- a/drivers/iio/accel/mxc4005.c
+++ b/drivers/iio/accel/mxc4005.c
@@ -56,7 +56,11 @@ struct mxc4005_data {
struct mutex mutex;
struct regmap *regmap;
struct iio_trigger *dready_trig;
- __be16 buffer[8];
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ __be16 chans[3];
+ s64 timestamp __aligned(8);
+ } scan;
bool trigger_enabled;
};
@@ -135,7 +139,7 @@ static int mxc4005_read_xyz(struct mxc4005_data *data)
int ret;
ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER,
- data->buffer, sizeof(data->buffer));
+ data->scan.chans, sizeof(data->scan.chans));
if (ret < 0) {
dev_err(data->dev, "failed to read axes\n");
return ret;
@@ -301,7 +305,7 @@ static irqreturn_t mxc4005_trigger_handler(int irq, void *private)
if (ret < 0)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
pf->timestamp);
err:
@@ -433,7 +437,7 @@ static int mxc4005_probe(struct i2c_client *client,
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->dready_trig)
return -ENOMEM;
diff --git a/drivers/iio/accel/sca3300.c b/drivers/iio/accel/sca3300.c
new file mode 100644
index 000000000000..f7ef8ecfd34a
--- /dev/null
+++ b/drivers/iio/accel/sca3300.c
@@ -0,0 +1,472 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Murata SCA3300 3-axis industrial accelerometer
+ *
+ * Copyright (c) 2021 Vaisala Oyj. All rights reserved.
+ */
+
+#include <linux/bitops.h>
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include <asm/unaligned.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define SCA3300_ALIAS "sca3300"
+
+#define SCA3300_CRC8_POLYNOMIAL 0x1d
+
+/* Device mode register */
+#define SCA3300_REG_MODE 0xd
+#define SCA3300_MODE_SW_RESET 0x20
+
+/* Last register in map */
+#define SCA3300_REG_SELBANK 0x1f
+
+/* Device status and mask */
+#define SCA3300_REG_STATUS 0x6
+#define SCA3300_STATUS_MASK GENMASK(8, 0)
+
+/* Device ID */
+#define SCA3300_REG_WHOAMI 0x10
+#define SCA3300_WHOAMI_ID 0x51
+
+/* Device return status and mask */
+#define SCA3300_VALUE_RS_ERROR 0x3
+#define SCA3300_MASK_RS_STATUS GENMASK(1, 0)
+
+enum sca3300_scan_indexes {
+ SCA3300_ACC_X = 0,
+ SCA3300_ACC_Y,
+ SCA3300_ACC_Z,
+ SCA3300_TEMP,
+ SCA3300_TIMESTAMP,
+};
+
+#define SCA3300_ACCEL_CHANNEL(index, reg, axis) { \
+ .type = IIO_ACCEL, \
+ .address = reg, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ }, \
+}
+
+static const struct iio_chan_spec sca3300_channels[] = {
+ SCA3300_ACCEL_CHANNEL(SCA3300_ACC_X, 0x1, X),
+ SCA3300_ACCEL_CHANNEL(SCA3300_ACC_Y, 0x2, Y),
+ SCA3300_ACCEL_CHANNEL(SCA3300_ACC_Z, 0x3, Z),
+ {
+ .type = IIO_TEMP,
+ .address = 0x5,
+ .scan_index = SCA3300_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_CPU,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+static const int sca3300_lp_freq[] = {70, 70, 70, 10};
+static const int sca3300_accel_scale[][2] = {{0, 370}, {0, 741}, {0, 185}, {0, 185}};
+
+static const unsigned long sca3300_scan_masks[] = {
+ BIT(SCA3300_ACC_X) | BIT(SCA3300_ACC_Y) | BIT(SCA3300_ACC_Z) |
+ BIT(SCA3300_TEMP),
+ 0
+};
+
+/**
+ * struct sca3300_data - device data
+ * @spi: SPI device structure
+ * @lock: Data buffer lock
+ * @scan: Triggered buffer. Four channel 16-bit data + 64-bit timestamp
+ * @txbuf: Transmit buffer
+ * @rxbuf: Receive buffer
+ */
+struct sca3300_data {
+ struct spi_device *spi;
+ struct mutex lock;
+ struct {
+ s16 channels[4];
+ s64 ts __aligned(sizeof(s64));
+ } scan;
+ u8 txbuf[4] ____cacheline_aligned;
+ u8 rxbuf[4];
+};
+
+DECLARE_CRC8_TABLE(sca3300_crc_table);
+
+static int sca3300_transfer(struct sca3300_data *sca_data, int *val)
+{
+ /* Consecutive requests min. 10 us delay (Datasheet section 5.1.2) */
+ struct spi_delay delay = { .value = 10, .unit = SPI_DELAY_UNIT_USECS };
+ int32_t ret;
+ int rs;
+ u8 crc;
+ struct spi_transfer xfers[2] = {
+ {
+ .tx_buf = sca_data->txbuf,
+ .len = ARRAY_SIZE(sca_data->txbuf),
+ .delay = delay,
+ .cs_change = 1,
+ },
+ {
+ .rx_buf = sca_data->rxbuf,
+ .len = ARRAY_SIZE(sca_data->rxbuf),
+ .delay = delay,
+ }
+ };
+
+ /* inverted crc value as described in device data sheet */
+ crc = ~crc8(sca3300_crc_table, &sca_data->txbuf[0], 3, CRC8_INIT_VALUE);
+ sca_data->txbuf[3] = crc;
+
+ ret = spi_sync_transfer(sca_data->spi, xfers, ARRAY_SIZE(xfers));
+ if (ret) {
+ dev_err(&sca_data->spi->dev,
+ "transfer error, error: %d\n", ret);
+ return -EIO;
+ }
+
+ crc = ~crc8(sca3300_crc_table, &sca_data->rxbuf[0], 3, CRC8_INIT_VALUE);
+ if (sca_data->rxbuf[3] != crc) {
+ dev_err(&sca_data->spi->dev, "CRC checksum mismatch");
+ return -EIO;
+ }
+
+ /* get return status */
+ rs = sca_data->rxbuf[0] & SCA3300_MASK_RS_STATUS;
+ if (rs == SCA3300_VALUE_RS_ERROR)
+ ret = -EINVAL;
+
+ *val = sign_extend32(get_unaligned_be16(&sca_data->rxbuf[1]), 15);
+
+ return ret;
+}
+
+static int sca3300_error_handler(struct sca3300_data *sca_data)
+{
+ int ret;
+ int val;
+
+ mutex_lock(&sca_data->lock);
+ sca_data->txbuf[0] = SCA3300_REG_STATUS << 2;
+ ret = sca3300_transfer(sca_data, &val);
+ mutex_unlock(&sca_data->lock);
+ /*
+ * Return status error is cleared after reading status register once,
+ * expect EINVAL here.
+ */
+ if (ret != -EINVAL) {
+ dev_err(&sca_data->spi->dev,
+ "error reading device status: %d\n", ret);
+ return ret;
+ }
+
+ dev_err(&sca_data->spi->dev, "device status: 0x%lx\n",
+ val & SCA3300_STATUS_MASK);
+
+ return 0;
+}
+
+static int sca3300_read_reg(struct sca3300_data *sca_data, u8 reg, int *val)
+{
+ int ret;
+
+ mutex_lock(&sca_data->lock);
+ sca_data->txbuf[0] = reg << 2;
+ ret = sca3300_transfer(sca_data, val);
+ mutex_unlock(&sca_data->lock);
+ if (ret != -EINVAL)
+ return ret;
+
+ return sca3300_error_handler(sca_data);
+}
+
+static int sca3300_write_reg(struct sca3300_data *sca_data, u8 reg, int val)
+{
+ int reg_val = 0;
+ int ret;
+
+ mutex_lock(&sca_data->lock);
+ /* BIT(7) for write operation */
+ sca_data->txbuf[0] = BIT(7) | (reg << 2);
+ put_unaligned_be16(val, &sca_data->txbuf[1]);
+ ret = sca3300_transfer(sca_data, &reg_val);
+ mutex_unlock(&sca_data->lock);
+ if (ret != -EINVAL)
+ return ret;
+
+ return sca3300_error_handler(sca_data);
+}
+
+static int sca3300_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct sca3300_data *data = iio_priv(indio_dev);
+ int reg_val;
+ int ret;
+ int i;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (val)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(sca3300_accel_scale); i++) {
+ if (val2 == sca3300_accel_scale[i][1])
+ return sca3300_write_reg(data, SCA3300_REG_MODE, i);
+ }
+ return -EINVAL;
+
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ ret = sca3300_read_reg(data, SCA3300_REG_MODE, &reg_val);
+ if (ret)
+ return ret;
+ /* freq. change is possible only for mode 3 and 4 */
+ if (reg_val == 2 && val == sca3300_lp_freq[3])
+ return sca3300_write_reg(data, SCA3300_REG_MODE, 3);
+ if (reg_val == 3 && val == sca3300_lp_freq[2])
+ return sca3300_write_reg(data, SCA3300_REG_MODE, 2);
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sca3300_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct sca3300_data *data = iio_priv(indio_dev);
+ int ret;
+ int reg_val;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = sca3300_read_reg(data, chan->address, val);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ ret = sca3300_read_reg(data, SCA3300_REG_MODE, &reg_val);
+ if (ret)
+ return ret;
+ *val = 0;
+ *val2 = sca3300_accel_scale[reg_val][1];
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ ret = sca3300_read_reg(data, SCA3300_REG_MODE, &reg_val);
+ if (ret)
+ return ret;
+ *val = sca3300_lp_freq[reg_val];
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static irqreturn_t sca3300_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct sca3300_data *data = iio_priv(indio_dev);
+ int bit, ret, val, i = 0;
+
+ for_each_set_bit(bit, indio_dev->active_scan_mask,
+ indio_dev->masklength) {
+ ret = sca3300_read_reg(data, sca3300_channels[bit].address,
+ &val);
+ if (ret) {
+ dev_err_ratelimited(&data->spi->dev,
+ "failed to read register, error: %d\n", ret);
+ /* handled, but bailing out due to errors */
+ goto out;
+ }
+ data->scan.channels[i++] = val;
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
+ iio_get_time_ns(indio_dev));
+out:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * sca3300_init - Device init sequence. See datasheet rev 2 section
+ * 4.2 Start-Up Sequence for details.
+ */
+static int sca3300_init(struct sca3300_data *sca_data,
+ struct iio_dev *indio_dev)
+{
+ int value = 0;
+ int ret;
+
+ ret = sca3300_write_reg(sca_data, SCA3300_REG_MODE,
+ SCA3300_MODE_SW_RESET);
+ if (ret)
+ return ret;
+
+ /*
+ * Wait 1ms after SW-reset command.
+ * Wait 15ms for settling of signal paths.
+ */
+ usleep_range(16e3, 50e3);
+
+ ret = sca3300_read_reg(sca_data, SCA3300_REG_WHOAMI, &value);
+ if (ret)
+ return ret;
+
+ if (value != SCA3300_WHOAMI_ID) {
+ dev_err(&sca_data->spi->dev,
+ "device id not expected value, %d != %u\n",
+ value, SCA3300_WHOAMI_ID);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int sca3300_debugfs_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg, unsigned int writeval,
+ unsigned int *readval)
+{
+ struct sca3300_data *data = iio_priv(indio_dev);
+ int value;
+ int ret;
+
+ if (reg > SCA3300_REG_SELBANK)
+ return -EINVAL;
+
+ if (!readval)
+ return sca3300_write_reg(data, reg, writeval);
+
+ ret = sca3300_read_reg(data, reg, &value);
+ if (ret)
+ return ret;
+
+ *readval = value;
+
+ return 0;
+}
+
+static int sca3300_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (const int *)sca3300_accel_scale;
+ *length = ARRAY_SIZE(sca3300_accel_scale) * 2 - 2;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ *vals = &sca3300_lp_freq[2];
+ *length = 2;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info sca3300_info = {
+ .read_raw = sca3300_read_raw,
+ .write_raw = sca3300_write_raw,
+ .debugfs_reg_access = &sca3300_debugfs_reg_access,
+ .read_avail = sca3300_read_avail,
+};
+
+static int sca3300_probe(struct spi_device *spi)
+{
+ struct sca3300_data *sca_data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*sca_data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ sca_data = iio_priv(indio_dev);
+ mutex_init(&sca_data->lock);
+ sca_data->spi = spi;
+
+ crc8_populate_msb(sca3300_crc_table, SCA3300_CRC8_POLYNOMIAL);
+
+ indio_dev->info = &sca3300_info;
+ indio_dev->name = SCA3300_ALIAS;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = sca3300_channels;
+ indio_dev->num_channels = ARRAY_SIZE(sca3300_channels);
+ indio_dev->available_scan_masks = sca3300_scan_masks;
+
+ ret = sca3300_init(sca_data, indio_dev);
+ if (ret) {
+ dev_err(&spi->dev, "failed to init device, error: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
+ iio_pollfunc_store_time,
+ sca3300_trigger_handler, NULL);
+ if (ret) {
+ dev_err(&spi->dev,
+ "iio triggered buffer setup failed, error: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_iio_device_register(&spi->dev, indio_dev);
+ if (ret) {
+ dev_err(&spi->dev, "iio device register failed, error: %d\n",
+ ret);
+ }
+
+ return ret;
+}
+
+static const struct of_device_id sca3300_dt_ids[] = {
+ { .compatible = "murata,sca3300"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, sca3300_dt_ids);
+
+static struct spi_driver sca3300_driver = {
+ .driver = {
+ .name = SCA3300_ALIAS,
+ .of_match_table = sca3300_dt_ids,
+ },
+ .probe = sca3300_probe,
+};
+module_spi_driver(sca3300_driver);
+
+MODULE_AUTHOR("Tomas Melin <tomas.melin@vaisala.com>");
+MODULE_DESCRIPTION("Murata SCA3300 SPI Accelerometer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h
index 5d356288e001..f5b0b8bbaff7 100644
--- a/drivers/iio/accel/st_accel.h
+++ b/drivers/iio/accel/st_accel.h
@@ -62,18 +62,6 @@ enum st_accel_type {
#define LIS2DE12_ACCEL_DEV_NAME "lis2de12"
#define LIS2HH12_ACCEL_DEV_NAME "lis2hh12"
-/**
-* struct st_sensors_platform_data - default accel platform data
-* @drdy_int_pin: default accel DRDY is available on INT1 pin.
-*/
-static __maybe_unused const struct st_sensors_platform_data default_accel_pdata = {
- .drdy_int_pin = 1,
-};
-
-const struct st_sensor_settings *st_accel_get_settings(const char *name);
-int st_accel_common_probe(struct iio_dev *indio_dev);
-void st_accel_common_remove(struct iio_dev *indio_dev);
-
#ifdef CONFIG_IIO_BUFFER
int st_accel_allocate_ring(struct iio_dev *indio_dev);
void st_accel_deallocate_ring(struct iio_dev *indio_dev);
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index 43c50167d220..28fceac9f2f6 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -41,51 +41,74 @@
#define ST_ACCEL_FS_AVL_200G 200
#define ST_ACCEL_FS_AVL_400G 400
+static const struct iio_mount_matrix *
+st_accel_get_mount_matrix(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct st_sensor_data *adata = iio_priv(indio_dev);
+
+ return &adata->mount_matrix;
+}
+
+static const struct iio_chan_spec_ext_info st_accel_mount_matrix_ext_info[] = {
+ IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_accel_get_mount_matrix),
+ { }
+};
+
static const struct iio_chan_spec st_accel_8bit_channels[] = {
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 8, 8,
- ST_ACCEL_DEFAULT_OUT_X_L_ADDR+1),
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_ACCEL_DEFAULT_OUT_X_L_ADDR+1,
+ st_accel_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 8, 8,
- ST_ACCEL_DEFAULT_OUT_Y_L_ADDR+1),
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_ACCEL_DEFAULT_OUT_Y_L_ADDR+1,
+ st_accel_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 8, 8,
- ST_ACCEL_DEFAULT_OUT_Z_L_ADDR+1),
+ ST_ACCEL_DEFAULT_OUT_Z_L_ADDR+1,
+ st_accel_mount_matrix_ext_info),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct iio_chan_spec st_accel_12bit_channels[] = {
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 12, 16,
- ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_ACCEL_DEFAULT_OUT_X_L_ADDR,
+ st_accel_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 12, 16,
- ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_ACCEL_DEFAULT_OUT_Y_L_ADDR,
+ st_accel_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 12, 16,
- ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
+ ST_ACCEL_DEFAULT_OUT_Z_L_ADDR,
+ st_accel_mount_matrix_ext_info),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct iio_chan_spec st_accel_16bit_channels[] = {
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16,
- ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_ACCEL_DEFAULT_OUT_X_L_ADDR,
+ st_accel_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16,
- ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
- ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
+ ST_ACCEL_DEFAULT_OUT_Y_L_ADDR,
+ st_accel_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16,
- ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
+ ST_ACCEL_DEFAULT_OUT_Z_L_ADDR,
+ st_accel_mount_matrix_ext_info),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
@@ -980,7 +1003,99 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.multi_read_bit = true,
.bootime = 2,
},
+ {
+ .wai = 0x49,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
+ .sensors_supported = {
+ [0] = LSM9DS0_IMU_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_accel_16bit_channels,
+ .odr = {
+ .addr = 0x20,
+ .mask = GENMASK(7, 4),
+ .odr_avl = {
+ { 3, 0x01, },
+ { 6, 0x02, },
+ { 12, 0x03, },
+ { 25, 0x04, },
+ { 50, 0x05, },
+ { 100, 0x06, },
+ { 200, 0x07, },
+ { 400, 0x08, },
+ { 800, 0x09, },
+ { 1600, 0x0a, },
+ },
+ },
+ .pw = {
+ .addr = 0x20,
+ .mask = GENMASK(7, 4),
+ .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+ },
+ .enable_axis = {
+ .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
+ .mask = ST_SENSORS_DEFAULT_AXIS_MASK,
+ },
+ .fs = {
+ .addr = 0x21,
+ .mask = GENMASK(5, 3),
+ .fs_avl = {
+ [0] = {
+ .num = ST_ACCEL_FS_AVL_2G,
+ .value = 0x00,
+ .gain = IIO_G_TO_M_S_2(61),
+ },
+ [1] = {
+ .num = ST_ACCEL_FS_AVL_4G,
+ .value = 0x01,
+ .gain = IIO_G_TO_M_S_2(122),
+ },
+ [2] = {
+ .num = ST_ACCEL_FS_AVL_6G,
+ .value = 0x02,
+ .gain = IIO_G_TO_M_S_2(183),
+ },
+ [3] = {
+ .num = ST_ACCEL_FS_AVL_8G,
+ .value = 0x03,
+ .gain = IIO_G_TO_M_S_2(244),
+ },
+ [4] = {
+ .num = ST_ACCEL_FS_AVL_16G,
+ .value = 0x04,
+ .gain = IIO_G_TO_M_S_2(732),
+ },
+ },
+ },
+ .bdu = {
+ .addr = 0x20,
+ .mask = BIT(3),
+ },
+ .drdy_irq = {
+ .int1 = {
+ .addr = 0x22,
+ .mask = BIT(2),
+ },
+ .int2 = {
+ .addr = 0x23,
+ .mask = BIT(3),
+ },
+ .stat_drdy = {
+ .addr = ST_SENSORS_DEFAULT_STAT_ADDR,
+ .mask = GENMASK(2, 0),
+ },
+ },
+ .sim = {
+ .addr = 0x21,
+ .value = BIT(0),
+ },
+ .multi_read_bit = true,
+ .bootime = 2,
+ },
+};
+/* Default accel DRDY is available on INT1 pin */
+static const struct st_sensors_platform_data default_accel_pdata = {
+ .drdy_int_pin = 1,
};
static int st_accel_read_raw(struct iio_dev *indio_dev,
@@ -1070,25 +1185,10 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
#endif
#ifdef CONFIG_ACPI
-static const struct iio_mount_matrix *
-get_mount_matrix(const struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan)
-{
- struct st_sensor_data *adata = iio_priv(indio_dev);
-
- return adata->mount_matrix;
-}
-
-static const struct iio_chan_spec_ext_info mount_matrix_ext_info[] = {
- IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, get_mount_matrix),
- { },
-};
-
/* Read ST-specific _ONT orientation data from ACPI and generate an
* appropriate mount matrix.
*/
-static int apply_acpi_orientation(struct iio_dev *indio_dev,
- struct iio_chan_spec *channels)
+static int apply_acpi_orientation(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
@@ -1177,14 +1277,6 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev,
}
/* Convert our integer matrix to a string-based iio_mount_matrix */
- adata->mount_matrix = devm_kmalloc(&indio_dev->dev,
- sizeof(*adata->mount_matrix),
- GFP_KERNEL);
- if (!adata->mount_matrix) {
- ret = -ENOMEM;
- goto out;
- }
-
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
int matrix_val = final_ont[i][j];
@@ -1203,26 +1295,25 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev,
default:
goto out;
}
- adata->mount_matrix->rotation[i * 3 + j] = str_value;
+ adata->mount_matrix.rotation[i * 3 + j] = str_value;
}
}
- /* Expose the mount matrix via ext_info */
- for (i = 0; i < indio_dev->num_channels; i++)
- channels[i].ext_info = mount_matrix_ext_info;
-
ret = 0;
dev_info(&indio_dev->dev, "computed mount matrix from ACPI\n");
out:
kfree(buffer.pointer);
+ if (ret)
+ dev_dbg(&indio_dev->dev,
+ "failed to apply ACPI orientation data: %d\n", ret);
+
return ret;
}
#else /* !CONFIG_ACPI */
-static int apply_acpi_orientation(struct iio_dev *indio_dev,
- struct iio_chan_spec *channels)
+static int apply_acpi_orientation(struct iio_dev *indio_dev)
{
- return 0;
+ return -EINVAL;
}
#endif
@@ -1248,38 +1339,30 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
struct st_sensors_platform_data *pdata = dev_get_platdata(adata->dev);
- struct iio_chan_spec *channels;
- size_t channels_size;
int err;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &accel_info;
- err = st_sensors_power_enable(indio_dev);
- if (err)
- return err;
-
err = st_sensors_verify_id(indio_dev);
if (err < 0)
- goto st_accel_power_off;
+ return err;
adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS;
+ indio_dev->channels = adata->sensor_settings->ch;
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
- channels_size = indio_dev->num_channels * sizeof(struct iio_chan_spec);
- channels = devm_kmemdup(&indio_dev->dev,
- adata->sensor_settings->ch,
- channels_size, GFP_KERNEL);
- if (!channels) {
- err = -ENOMEM;
- goto st_accel_power_off;
+ /*
+ * First try specific ACPI methods to retrieve orientation then try the
+ * generic function.
+ */
+ err = apply_acpi_orientation(indio_dev);
+ if (err) {
+ err = iio_read_mount_matrix(adata->dev, &adata->mount_matrix);
+ if (err)
+ return err;
}
- if (apply_acpi_orientation(indio_dev, channels))
- dev_warn(&indio_dev->dev,
- "failed to apply ACPI orientation data: %d\n", err);
-
- indio_dev->channels = channels;
adata->current_fullscale = &adata->sensor_settings->fs.fs_avl[0];
adata->odr = adata->sensor_settings->odr.odr_avl[0].hz;
@@ -1288,11 +1371,11 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
err = st_sensors_init_sensor(indio_dev, pdata);
if (err < 0)
- goto st_accel_power_off;
+ return err;
err = st_accel_allocate_ring(indio_dev);
if (err < 0)
- goto st_accel_power_off;
+ return err;
if (adata->irq > 0) {
err = st_sensors_allocate_trigger(indio_dev,
@@ -1315,9 +1398,6 @@ st_accel_device_register_error:
st_sensors_deallocate_trigger(indio_dev);
st_accel_probe_trigger_error:
st_accel_deallocate_ring(indio_dev);
-st_accel_power_off:
- st_sensors_power_disable(indio_dev);
-
return err;
}
EXPORT_SYMBOL(st_accel_common_probe);
@@ -1326,8 +1406,6 @@ void st_accel_common_remove(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
- st_sensors_power_disable(indio_dev);
-
iio_device_unregister(indio_dev);
if (adata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index 360e16f2cadb..95e305b88d5e 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -174,16 +174,29 @@ static int st_accel_i2c_probe(struct i2c_client *client)
if (ret < 0)
return ret;
+ ret = st_sensors_power_enable(indio_dev);
+ if (ret)
+ return ret;
+
ret = st_accel_common_probe(indio_dev);
if (ret < 0)
- return ret;
+ goto st_accel_power_off;
return 0;
+
+st_accel_power_off:
+ st_sensors_power_disable(indio_dev);
+
+ return ret;
}
static int st_accel_i2c_remove(struct i2c_client *client)
{
- st_accel_common_remove(i2c_get_clientdata(client));
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+ st_sensors_power_disable(indio_dev);
+
+ st_accel_common_remove(indio_dev);
return 0;
}
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
index 568ff1bae0ee..83d3308ce5cc 100644
--- a/drivers/iio/accel/st_accel_spi.c
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -123,16 +123,29 @@ static int st_accel_spi_probe(struct spi_device *spi)
if (err < 0)
return err;
+ err = st_sensors_power_enable(indio_dev);
+ if (err)
+ return err;
+
err = st_accel_common_probe(indio_dev);
if (err < 0)
- return err;
+ goto st_accel_power_off;
return 0;
+
+st_accel_power_off:
+ st_sensors_power_disable(indio_dev);
+
+ return err;
}
static int st_accel_spi_remove(struct spi_device *spi)
{
- st_accel_common_remove(spi_get_drvdata(spi));
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+ st_sensors_power_disable(indio_dev);
+
+ st_accel_common_remove(indio_dev);
return 0;
}
diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c
index 157d8faefb9e..43c621d0f11e 100644
--- a/drivers/iio/accel/stk8312.c
+++ b/drivers/iio/accel/stk8312.c
@@ -7,7 +7,6 @@
* IIO driver for STK8312; 7-bit I2C address: 0x3D.
*/
-#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
@@ -103,7 +102,11 @@ struct stk8312_data {
u8 mode;
struct iio_trigger *dready_trig;
bool dready_trigger_on;
- s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 64-bit timestamp */
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ s8 chans[3];
+ s64 timestamp __aligned(8);
+ } scan;
};
static IIO_CONST_ATTR(in_accel_scale_available, STK8312_SCALE_AVAIL);
@@ -438,7 +441,7 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p)
ret = i2c_smbus_read_i2c_block_data(data->client,
STK8312_REG_XOUT,
STK8312_ALL_CHANNEL_SIZE,
- data->buffer);
+ data->scan.chans);
if (ret < STK8312_ALL_CHANNEL_SIZE) {
dev_err(&data->client->dev, "register read failed\n");
mutex_unlock(&data->lock);
@@ -452,12 +455,12 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p)
mutex_unlock(&data->lock);
goto err;
}
- data->buffer[i++] = ret;
+ data->scan.chans[i++] = ret;
}
}
mutex_unlock(&data->lock);
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
pf->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -552,7 +555,7 @@ static int stk8312_probe(struct i2c_client *client,
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->dready_trig) {
ret = -ENOMEM;
goto err_power_off;
@@ -635,23 +638,17 @@ static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, stk8312_resume);
#endif
static const struct i2c_device_id stk8312_i2c_id[] = {
- {"STK8312", 0},
+ /* Deprecated in favour of lowercase form */
+ { "STK8312", 0 },
+ { "stk8312", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id);
-static const struct acpi_device_id stk8312_acpi_id[] = {
- {"STK8312", 0},
- {}
-};
-
-MODULE_DEVICE_TABLE(acpi, stk8312_acpi_id);
-
static struct i2c_driver stk8312_driver = {
.driver = {
.name = STK8312_DRIVER_NAME,
.pm = STK8312_PM_OPS,
- .acpi_match_table = ACPI_PTR(stk8312_acpi_id),
},
.probe = stk8312_probe,
.remove = stk8312_remove,
diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c
index 7cf9cb7e8666..e137a34b5c9a 100644
--- a/drivers/iio/accel/stk8ba50.c
+++ b/drivers/iio/accel/stk8ba50.c
@@ -91,12 +91,11 @@ struct stk8ba50_data {
u8 sample_rate_idx;
struct iio_trigger *dready_trig;
bool dready_trigger_on;
- /*
- * 3 x 16-bit channels (10-bit data, 6-bit padding) +
- * 1 x 16 padding +
- * 4 x 16 64-bit timestamp
- */
- s16 buffer[8];
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ s16 chans[3];
+ s64 timetamp __aligned(8);
+ } scan;
};
#define STK8BA50_ACCEL_CHANNEL(index, reg, axis) { \
@@ -324,7 +323,7 @@ static irqreturn_t stk8ba50_trigger_handler(int irq, void *p)
ret = i2c_smbus_read_i2c_block_data(data->client,
STK8BA50_REG_XOUT,
STK8BA50_ALL_CHANNEL_SIZE,
- (u8 *)data->buffer);
+ (u8 *)data->scan.chans);
if (ret < STK8BA50_ALL_CHANNEL_SIZE) {
dev_err(&data->client->dev, "register read failed\n");
goto err;
@@ -337,10 +336,10 @@ static irqreturn_t stk8ba50_trigger_handler(int irq, void *p)
if (ret < 0)
goto err;
- data->buffer[i++] = ret;
+ data->scan.chans[i++] = ret;
}
}
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
pf->timestamp);
err:
mutex_unlock(&data->lock);
@@ -448,7 +447,7 @@ static int stk8ba50_probe(struct i2c_client *client,
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->dready_trig) {
ret = -ENOMEM;
goto err_power_off;
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index c7946c439612..db0c8fb60515 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -1190,6 +1190,18 @@ config TI_TLC4541
This driver can also be built as a module. If so, the module will be
called ti-tlc4541.
+config TI_TSC2046
+ tristate "Texas Instruments TSC2046 ADC driver"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for ADC functionality of Texas
+ Instruments TSC2046 touch screen controller.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-tsc2046.
+
config TWL4030_MADC
tristate "TWL4030 MADC (Monitoring A/D Converter)"
depends on TWL4030_CORE
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index a226657d19c0..f70d877c555a 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
+obj-$(CONFIG_TI_TSC2046) += ti-tsc2046.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
index a27db78ea13e..e45c600fccc0 100644
--- a/drivers/iio/adc/ad7124.c
+++ b/drivers/iio/adc/ad7124.c
@@ -862,6 +862,11 @@ static void ad7124_reg_disable(void *r)
regulator_disable(r);
}
+static void ad7124_clk_disable(void *c)
+{
+ clk_disable_unprepare(c);
+}
+
static int ad7124_probe(struct spi_device *spi)
{
const struct ad7124_chip_info *info;
@@ -883,8 +888,6 @@ static int ad7124_probe(struct spi_device *spi)
ad_sd_init(&st->sd, indio_dev, spi, &ad7124_sigma_delta_info);
- spi_set_drvdata(spi, indio_dev);
-
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &ad7124_info;
@@ -922,48 +925,28 @@ static int ad7124_probe(struct spi_device *spi)
if (ret < 0)
return ret;
+ ret = devm_add_action_or_reset(&spi->dev, ad7124_clk_disable, st->mclk);
+ if (ret)
+ return ret;
+
ret = ad7124_soft_reset(st);
if (ret < 0)
- goto error_clk_disable_unprepare;
+ return ret;
ret = ad7124_check_chip_id(st);
if (ret)
- goto error_clk_disable_unprepare;
+ return ret;
ret = ad7124_setup(st);
if (ret < 0)
- goto error_clk_disable_unprepare;
+ return ret;
- ret = ad_sd_setup_buffer_and_trigger(indio_dev);
+ ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
if (ret < 0)
- goto error_clk_disable_unprepare;
-
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(&spi->dev, "Failed to register iio device\n");
- goto error_remove_trigger;
- }
-
- return 0;
-
-error_remove_trigger:
- ad_sd_cleanup_buffer_and_trigger(indio_dev);
-error_clk_disable_unprepare:
- clk_disable_unprepare(st->mclk);
-
- return ret;
-}
-
-static int ad7124_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ad7124_state *st = iio_priv(indio_dev);
+ return ret;
- iio_device_unregister(indio_dev);
- ad_sd_cleanup_buffer_and_trigger(indio_dev);
- clk_disable_unprepare(st->mclk);
+ return devm_iio_device_register(&spi->dev, indio_dev);
- return 0;
}
static const struct of_device_id ad7124_of_match[] = {
@@ -981,7 +964,6 @@ static struct spi_driver ad71124_driver = {
.of_match_table = ad7124_of_match,
},
.probe = ad7124_probe,
- .remove = ad7124_remove,
};
module_spi_driver(ad71124_driver);
diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c
index 1141cc13a124..ee8ed9481025 100644
--- a/drivers/iio/adc/ad7192.c
+++ b/drivers/iio/adc/ad7192.c
@@ -326,7 +326,7 @@ static int ad7192_of_clock_select(struct ad7192_state *st)
clock_sel = AD7192_CLK_INT;
/* use internal clock */
- if (PTR_ERR(st->mclk) == -ENOENT) {
+ if (st->mclk) {
if (of_property_read_bool(np, "adi,int-clock-output-enable"))
clock_sel = AD7192_CLK_INT_CO;
} else {
@@ -908,6 +908,16 @@ static int ad7192_channels_config(struct iio_dev *indio_dev)
return 0;
}
+static void ad7192_reg_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
+static void ad7192_clk_disable(void *clk)
+{
+ clk_disable_unprepare(clk);
+}
+
static int ad7192_probe(struct spi_device *spi)
{
struct ad7192_state *st;
@@ -937,33 +947,38 @@ static int ad7192_probe(struct spi_device *spi)
return ret;
}
+ ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->avdd);
+ if (ret)
+ return ret;
+
st->dvdd = devm_regulator_get(&spi->dev, "dvdd");
- if (IS_ERR(st->dvdd)) {
- ret = PTR_ERR(st->dvdd);
- goto error_disable_avdd;
- }
+ if (IS_ERR(st->dvdd))
+ return PTR_ERR(st->dvdd);
ret = regulator_enable(st->dvdd);
if (ret) {
dev_err(&spi->dev, "Failed to enable specified DVdd supply\n");
- goto error_disable_avdd;
+ return ret;
}
+ ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->dvdd);
+ if (ret)
+ return ret;
+
ret = regulator_get_voltage(st->avdd);
if (ret < 0) {
dev_err(&spi->dev, "Device tree error, reference voltage undefined\n");
- goto error_disable_avdd;
+ return ret;
}
st->int_vref_mv = ret / 1000;
- spi_set_drvdata(spi, indio_dev);
st->chip_info = of_device_get_match_data(&spi->dev);
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = ad7192_channels_config(indio_dev);
if (ret < 0)
- goto error_disable_dvdd;
+ return ret;
if (st->chip_info->chip_id == CHIPID_AD7195)
indio_dev->info = &ad7195_info;
@@ -972,17 +987,15 @@ static int ad7192_probe(struct spi_device *spi)
ad_sd_init(&st->sd, indio_dev, spi, &ad7192_sigma_delta_info);
- ret = ad_sd_setup_buffer_and_trigger(indio_dev);
+ ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
if (ret)
- goto error_disable_dvdd;
+ return ret;
st->fclk = AD7192_INT_FREQ_MHZ;
- st->mclk = devm_clk_get(&st->sd.spi->dev, "mclk");
- if (IS_ERR(st->mclk) && PTR_ERR(st->mclk) != -ENOENT) {
- ret = PTR_ERR(st->mclk);
- goto error_remove_trigger;
- }
+ st->mclk = devm_clk_get_optional(&spi->dev, "mclk");
+ if (IS_ERR(st->mclk))
+ return PTR_ERR(st->mclk);
st->clock_sel = ad7192_of_clock_select(st);
@@ -990,55 +1003,26 @@ static int ad7192_probe(struct spi_device *spi)
st->clock_sel == AD7192_CLK_EXT_MCLK2) {
ret = clk_prepare_enable(st->mclk);
if (ret < 0)
- goto error_remove_trigger;
+ return ret;
+
+ ret = devm_add_action_or_reset(&spi->dev, ad7192_clk_disable,
+ st->mclk);
+ if (ret)
+ return ret;
st->fclk = clk_get_rate(st->mclk);
if (!ad7192_valid_external_frequency(st->fclk)) {
- ret = -EINVAL;
dev_err(&spi->dev,
"External clock frequency out of bounds\n");
- goto error_disable_clk;
+ return -EINVAL;
}
}
ret = ad7192_setup(st, spi->dev.of_node);
if (ret)
- goto error_disable_clk;
-
- ret = iio_device_register(indio_dev);
- if (ret < 0)
- goto error_disable_clk;
- return 0;
-
-error_disable_clk:
- if (st->clock_sel == AD7192_CLK_EXT_MCLK1_2 ||
- st->clock_sel == AD7192_CLK_EXT_MCLK2)
- clk_disable_unprepare(st->mclk);
-error_remove_trigger:
- ad_sd_cleanup_buffer_and_trigger(indio_dev);
-error_disable_dvdd:
- regulator_disable(st->dvdd);
-error_disable_avdd:
- regulator_disable(st->avdd);
-
- return ret;
-}
-
-static int ad7192_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ad7192_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- if (st->clock_sel == AD7192_CLK_EXT_MCLK1_2 ||
- st->clock_sel == AD7192_CLK_EXT_MCLK2)
- clk_disable_unprepare(st->mclk);
- ad_sd_cleanup_buffer_and_trigger(indio_dev);
-
- regulator_disable(st->dvdd);
- regulator_disable(st->avdd);
+ return ret;
- return 0;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct of_device_id ad7192_of_match[] = {
@@ -1056,7 +1040,6 @@ static struct spi_driver ad7192_driver = {
.of_match_table = ad7192_of_match,
},
.probe = ad7192_probe,
- .remove = ad7192_remove,
};
module_spi_driver(ad7192_driver);
diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c
index d2163cb62f4f..3f4e73f7d35a 100644
--- a/drivers/iio/adc/ad7298.c
+++ b/drivers/iio/adc/ad7298.c
@@ -13,6 +13,7 @@
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/delay.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
@@ -346,6 +347,12 @@ static int ad7298_probe(struct spi_device *spi)
return devm_iio_device_register(&spi->dev, indio_dev);
}
+static const struct acpi_device_id ad7298_acpi_ids[] = {
+ { "INT3494", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, ad7298_acpi_ids);
+
static const struct spi_device_id ad7298_id[] = {
{"ad7298", 0},
{}
@@ -355,6 +362,7 @@ MODULE_DEVICE_TABLE(spi, ad7298_id);
static struct spi_driver ad7298_driver = {
.driver = {
.name = "ad7298",
+ .acpi_match_table = ad7298_acpi_ids,
},
.probe = ad7298_probe,
.id_table = ad7298_id,
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index 9e9ff07cf972..a1e8b32671cf 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -32,12 +32,14 @@ struct ad7476_chip_info {
/* channels used when convst gpio is defined */
struct iio_chan_spec convst_channel[2];
void (*reset)(struct ad7476_state *);
+ bool has_vref;
+ bool has_vdrive;
};
struct ad7476_state {
struct spi_device *spi;
const struct ad7476_chip_info *chip_info;
- struct regulator *reg;
+ struct regulator *ref_reg;
struct gpio_desc *convst_gpio;
struct spi_transfer xfer;
struct spi_message msg;
@@ -52,13 +54,17 @@ struct ad7476_state {
};
enum ad7476_supported_device_ids {
+ ID_AD7091,
ID_AD7091R,
+ ID_AD7273,
+ ID_AD7274,
ID_AD7276,
ID_AD7277,
ID_AD7278,
ID_AD7466,
ID_AD7467,
ID_AD7468,
+ ID_AD7475,
ID_AD7495,
ID_AD7940,
ID_ADC081S,
@@ -145,8 +151,8 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
GENMASK(st->chip_info->channel[0].scan_type.realbits - 1, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- if (!st->chip_info->int_vref_uv) {
- scale_uv = regulator_get_voltage(st->reg);
+ if (st->ref_reg) {
+ scale_uv = regulator_get_voltage(st->ref_reg);
if (scale_uv < 0)
return scale_uv;
} else {
@@ -187,13 +193,32 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
BIT(IIO_CHAN_INFO_RAW))
static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
+ [ID_AD7091] = {
+ .channel[0] = AD7091R_CHAN(12),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ .convst_channel[0] = AD7091R_CONVST_CHAN(12),
+ .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ .reset = ad7091_reset,
+ },
[ID_AD7091R] = {
.channel[0] = AD7091R_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
.convst_channel[0] = AD7091R_CONVST_CHAN(12),
.convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ .int_vref_uv = 2500000,
+ .has_vref = true,
.reset = ad7091_reset,
},
+ [ID_AD7273] = {
+ .channel[0] = AD7940_CHAN(10),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ .has_vref = true,
+ },
+ [ID_AD7274] = {
+ .channel[0] = AD7940_CHAN(12),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ .has_vref = true,
+ },
[ID_AD7276] = {
.channel[0] = AD7940_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
@@ -218,10 +243,17 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
.channel[0] = AD7476_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
+ [ID_AD7475] = {
+ .channel[0] = AD7476_CHAN(12),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ .has_vref = true,
+ .has_vdrive = true,
+ },
[ID_AD7495] = {
.channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
.int_vref_uv = 2500000,
+ .has_vdrive = true,
},
[ID_AD7940] = {
.channel[0] = AD7940_CHAN(14),
@@ -254,6 +286,7 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
[ID_LTC2314_14] = {
.channel[0] = AD7940_CHAN(14),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ .has_vref = true,
},
};
@@ -263,15 +296,16 @@ static const struct iio_info ad7476_info = {
static void ad7476_reg_disable(void *data)
{
- struct ad7476_state *st = data;
+ struct regulator *reg = data;
- regulator_disable(st->reg);
+ regulator_disable(reg);
}
static int ad7476_probe(struct spi_device *spi)
{
struct ad7476_state *st;
struct iio_dev *indio_dev;
+ struct regulator *reg;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@@ -282,27 +316,79 @@ static int ad7476_probe(struct spi_device *spi)
st->chip_info =
&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
- st->reg = devm_regulator_get(&spi->dev, "vcc");
- if (IS_ERR(st->reg))
- return PTR_ERR(st->reg);
+ reg = devm_regulator_get(&spi->dev, "vcc");
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
- ret = regulator_enable(st->reg);
+ ret = regulator_enable(reg);
if (ret)
return ret;
- ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable,
- st);
+ ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable, reg);
if (ret)
return ret;
+ /* Either vcc or vref (below) as appropriate */
+ if (!st->chip_info->int_vref_uv)
+ st->ref_reg = reg;
+
+ if (st->chip_info->has_vref) {
+
+ /* If a device has an internal reference vref is optional */
+ if (st->chip_info->int_vref_uv) {
+ reg = devm_regulator_get_optional(&spi->dev, "vref");
+ if (IS_ERR(reg) && (PTR_ERR(reg) != -ENODEV))
+ return PTR_ERR(reg);
+ } else {
+ reg = devm_regulator_get(&spi->dev, "vref");
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+ }
+
+ if (!IS_ERR(reg)) {
+ ret = regulator_enable(reg);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(&spi->dev,
+ ad7476_reg_disable,
+ reg);
+ if (ret)
+ return ret;
+ st->ref_reg = reg;
+ } else {
+ /*
+ * Can only get here if device supports both internal
+ * and external reference, but the regulator connected
+ * to the external reference is not connected.
+ * Set the reference regulator pointer to NULL to
+ * indicate this.
+ */
+ st->ref_reg = NULL;
+ }
+ }
+
+ if (st->chip_info->has_vdrive) {
+ reg = devm_regulator_get(&spi->dev, "vdrive");
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ ret = regulator_enable(reg);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable,
+ reg);
+ if (ret)
+ return ret;
+ }
+
st->convst_gpio = devm_gpiod_get_optional(&spi->dev,
"adi,conversion-start",
GPIOD_OUT_LOW);
if (IS_ERR(st->convst_gpio))
return PTR_ERR(st->convst_gpio);
- spi_set_drvdata(spi, indio_dev);
-
st->spi = spi;
indio_dev->name = spi_get_device_id(spi)->name;
@@ -333,17 +419,17 @@ static int ad7476_probe(struct spi_device *spi)
}
static const struct spi_device_id ad7476_id[] = {
- {"ad7091", ID_AD7091R},
+ {"ad7091", ID_AD7091},
{"ad7091r", ID_AD7091R},
- {"ad7273", ID_AD7277},
- {"ad7274", ID_AD7276},
+ {"ad7273", ID_AD7273},
+ {"ad7274", ID_AD7274},
{"ad7276", ID_AD7276},
{"ad7277", ID_AD7277},
{"ad7278", ID_AD7278},
{"ad7466", ID_AD7466},
{"ad7467", ID_AD7467},
{"ad7468", ID_AD7468},
- {"ad7475", ID_AD7466},
+ {"ad7475", ID_AD7475},
{"ad7476", ID_AD7466},
{"ad7476a", ID_AD7466},
{"ad7477", ID_AD7467},
diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index 0af0bb4d5a7f..0a60ecc69d38 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -663,7 +663,8 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
}
st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
- indio_dev->name, indio_dev->id);
+ indio_dev->name,
+ iio_device_id(indio_dev));
if (!st->trig)
return -ENOMEM;
diff --git a/drivers/iio/adc/ad7766.c b/drivers/iio/adc/ad7766.c
index 1e41759f3ee5..51ee9482e0df 100644
--- a/drivers/iio/adc/ad7766.c
+++ b/drivers/iio/adc/ad7766.c
@@ -248,7 +248,8 @@ static int ad7766_probe(struct spi_device *spi)
if (spi->irq > 0) {
ad7766->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
- indio_dev->name, indio_dev->id);
+ indio_dev->name,
+ iio_device_id(indio_dev));
if (!ad7766->trig)
return -ENOMEM;
@@ -272,8 +273,6 @@ static int ad7766_probe(struct spi_device *spi)
return ret;
}
- spi_set_drvdata(spi, indio_dev);
-
ad7766->spi = spi;
/* First byte always 0 */
@@ -289,10 +288,7 @@ static int ad7766_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = devm_iio_device_register(&spi->dev, indio_dev);
- if (ret)
- return ret;
- return 0;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad7766_id[] = {
diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index 60f21fed6dcb..2c5c8a3672b2 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -614,7 +614,6 @@ static int ad7768_probe(struct spi_device *spi)
st->mclk_freq = clk_get_rate(st->mclk);
- spi_set_drvdata(spi, indio_dev);
mutex_init(&st->lock);
indio_dev->channels = ad7768_channels;
@@ -630,7 +629,8 @@ static int ad7768_probe(struct spi_device *spi)
}
st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
- indio_dev->name, indio_dev->id);
+ indio_dev->name,
+ iio_device_id(indio_dev));
if (!st->trig)
return -ENOMEM;
diff --git a/drivers/iio/adc/ad7780.c b/drivers/iio/adc/ad7780.c
index 42e7e8e595d1..42bb952f4738 100644
--- a/drivers/iio/adc/ad7780.c
+++ b/drivers/iio/adc/ad7780.c
@@ -300,6 +300,11 @@ static int ad7780_init_gpios(struct device *dev, struct ad7780_state *st)
return 0;
}
+static void ad7780_reg_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int ad7780_probe(struct spi_device *spi)
{
struct ad7780_state *st;
@@ -318,8 +323,6 @@ static int ad7780_probe(struct spi_device *spi)
st->chip_info =
&ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data];
- spi_set_drvdata(spi, indio_dev);
-
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = &st->chip_info->channel;
@@ -340,35 +343,15 @@ static int ad7780_probe(struct spi_device *spi)
return ret;
}
- ret = ad_sd_setup_buffer_and_trigger(indio_dev);
+ ret = devm_add_action_or_reset(&spi->dev, ad7780_reg_disable, st->reg);
if (ret)
- goto error_disable_reg;
+ return ret;
- ret = iio_device_register(indio_dev);
+ ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
if (ret)
- goto error_cleanup_buffer_and_trigger;
-
- return 0;
-
-error_cleanup_buffer_and_trigger:
- ad_sd_cleanup_buffer_and_trigger(indio_dev);
-error_disable_reg:
- regulator_disable(st->reg);
-
- return ret;
-}
-
-static int ad7780_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ad7780_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- ad_sd_cleanup_buffer_and_trigger(indio_dev);
-
- regulator_disable(st->reg);
+ return ret;
- return 0;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad7780_id[] = {
@@ -385,7 +368,6 @@ static struct spi_driver ad7780_driver = {
.name = "ad7780",
},
.probe = ad7780_probe,
- .remove = ad7780_remove,
.id_table = ad7780_id,
};
module_spi_driver(ad7780_driver);
diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c
index d57ad966e17c..cb579aa89f39 100644
--- a/drivers/iio/adc/ad7791.c
+++ b/drivers/iio/adc/ad7791.c
@@ -394,6 +394,11 @@ static int ad7791_setup(struct ad7791_state *st,
st->mode);
}
+static void ad7791_reg_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int ad7791_probe(struct spi_device *spi)
{
struct ad7791_platform_data *pdata = spi->dev.platform_data;
@@ -420,11 +425,13 @@ static int ad7791_probe(struct spi_device *spi)
if (ret)
return ret;
+ ret = devm_add_action_or_reset(&spi->dev, ad7791_reg_disable, st->reg);
+ if (ret)
+ return ret;
+
st->info = &ad7791_chip_infos[spi_get_device_id(spi)->driver_data];
ad_sd_init(&st->sd, indio_dev, spi, &ad7791_sigma_delta_info);
- spi_set_drvdata(spi, indio_dev);
-
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->info->channels;
@@ -434,39 +441,15 @@ static int ad7791_probe(struct spi_device *spi)
else
indio_dev->info = &ad7791_no_filter_info;
- ret = ad_sd_setup_buffer_and_trigger(indio_dev);
+ ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
if (ret)
- goto error_disable_reg;
+ return ret;
ret = ad7791_setup(st, pdata);
if (ret)
- goto error_remove_trigger;
-
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_remove_trigger;
-
- return 0;
-
-error_remove_trigger:
- ad_sd_cleanup_buffer_and_trigger(indio_dev);
-error_disable_reg:
- regulator_disable(st->reg);
-
- return ret;
-}
-
-static int ad7791_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ad7791_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- ad_sd_cleanup_buffer_and_trigger(indio_dev);
-
- regulator_disable(st->reg);
+ return ret;
- return 0;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad7791_spi_ids[] = {
@@ -484,7 +467,6 @@ static struct spi_driver ad7791_driver = {
.name = "ad7791",
},
.probe = ad7791_probe,
- .remove = ad7791_remove,
.id_table = ad7791_spi_ids,
};
module_spi_driver(ad7791_driver);
diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c
index 440ef4c7be07..ef3e2d3ecb0c 100644
--- a/drivers/iio/adc/ad7793.c
+++ b/drivers/iio/adc/ad7793.c
@@ -769,6 +769,11 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
},
};
+static void ad7793_reg_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int ad7793_probe(struct spi_device *spi)
{
const struct ad7793_platform_data *pdata = spi->dev.platform_data;
@@ -803,11 +808,13 @@ static int ad7793_probe(struct spi_device *spi)
if (ret)
return ret;
+ ret = devm_add_action_or_reset(&spi->dev, ad7793_reg_disable, st->reg);
+ if (ret)
+ return ret;
+
vref_mv = regulator_get_voltage(st->reg);
- if (vref_mv < 0) {
- ret = vref_mv;
- goto error_disable_reg;
- }
+ if (vref_mv < 0)
+ return vref_mv;
vref_mv /= 1000;
} else {
@@ -817,50 +824,21 @@ static int ad7793_probe(struct spi_device *spi)
st->chip_info =
&ad7793_chip_info_tbl[spi_get_device_id(spi)->driver_data];
- spi_set_drvdata(spi, indio_dev);
-
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->info = st->chip_info->iio_info;
- ret = ad_sd_setup_buffer_and_trigger(indio_dev);
+ ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
if (ret)
- goto error_disable_reg;
+ return ret;
ret = ad7793_setup(indio_dev, pdata, vref_mv);
if (ret)
- goto error_remove_trigger;
-
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_remove_trigger;
-
- return 0;
-
-error_remove_trigger:
- ad_sd_cleanup_buffer_and_trigger(indio_dev);
-error_disable_reg:
- if (pdata->refsel != AD7793_REFSEL_INTERNAL)
- regulator_disable(st->reg);
-
- return ret;
-}
-
-static int ad7793_remove(struct spi_device *spi)
-{
- const struct ad7793_platform_data *pdata = spi->dev.platform_data;
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ad7793_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- ad_sd_cleanup_buffer_and_trigger(indio_dev);
-
- if (pdata->refsel != AD7793_REFSEL_INTERNAL)
- regulator_disable(st->reg);
+ return ret;
- return 0;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad7793_id[] = {
@@ -882,7 +860,6 @@ static struct spi_driver ad7793_driver = {
.name = "ad7793",
},
.probe = ad7793_probe,
- .remove = ad7793_remove,
.id_table = ad7793_id,
};
module_spi_driver(ad7793_driver);
diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c
index 9b3cbe1ddc6f..f64999714a4d 100644
--- a/drivers/iio/adc/ad7887.c
+++ b/drivers/iio/adc/ad7887.c
@@ -268,7 +268,6 @@ static int ad7887_probe(struct spi_device *spi)
st->chip_info =
&ad7887_chip_info_tbl[spi_get_device_id(spi)->driver_data];
- spi_set_drvdata(spi, indio_dev);
st->spi = spi;
indio_dev->name = spi_get_device_id(spi)->name;
diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c
index 19a45dd43796..dbfc8517cb8a 100644
--- a/drivers/iio/adc/ad9467.c
+++ b/drivers/iio/adc/ad9467.c
@@ -434,8 +434,6 @@ static int ad9467_probe(struct spi_device *spi)
mdelay(10);
}
- spi_set_drvdata(spi, st);
-
conv->chip_info = &info->axi_adc_info;
id = ad9467_spi_read(spi, AN877_ADC_REG_CHIP_ID);
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index e777ec718973..1d652d9b2f5c 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -470,91 +470,65 @@ EXPORT_SYMBOL_GPL(ad_sd_validate_trigger);
static const struct iio_trigger_ops ad_sd_trigger_ops = {
};
-static int ad_sd_probe_trigger(struct iio_dev *indio_dev)
+static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_dev)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
int ret;
- sigma_delta->trig = iio_trigger_alloc(&sigma_delta->spi->dev,
- "%s-dev%d", indio_dev->name,
- indio_dev->id);
- if (sigma_delta->trig == NULL) {
- ret = -ENOMEM;
- goto error_ret;
+ if (dev != &sigma_delta->spi->dev) {
+ dev_err(dev, "Trigger parent should be '%s', got '%s'\n",
+ dev_name(dev), dev_name(&sigma_delta->spi->dev));
+ return -EFAULT;
}
+
+ sigma_delta->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
+ iio_device_id(indio_dev));
+ if (sigma_delta->trig == NULL)
+ return -ENOMEM;
+
sigma_delta->trig->ops = &ad_sd_trigger_ops;
init_completion(&sigma_delta->completion);
sigma_delta->irq_dis = true;
- ret = request_irq(sigma_delta->spi->irq,
- ad_sd_data_rdy_trig_poll,
- sigma_delta->info->irq_flags | IRQF_NO_AUTOEN,
- indio_dev->name,
- sigma_delta);
+ ret = devm_request_irq(dev, sigma_delta->spi->irq,
+ ad_sd_data_rdy_trig_poll,
+ sigma_delta->info->irq_flags | IRQF_NO_AUTOEN,
+ indio_dev->name,
+ sigma_delta);
if (ret)
- goto error_free_trig;
+ return ret;
iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta);
- ret = iio_trigger_register(sigma_delta->trig);
+ ret = devm_iio_trigger_register(dev, sigma_delta->trig);
if (ret)
- goto error_free_irq;
+ return ret;
/* select default trigger */
indio_dev->trig = iio_trigger_get(sigma_delta->trig);
return 0;
-
-error_free_irq:
- free_irq(sigma_delta->spi->irq, sigma_delta);
-error_free_trig:
- iio_trigger_free(sigma_delta->trig);
-error_ret:
- return ret;
-}
-
-static void ad_sd_remove_trigger(struct iio_dev *indio_dev)
-{
- struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
-
- iio_trigger_unregister(sigma_delta->trig);
- free_irq(sigma_delta->spi->irq, sigma_delta);
- iio_trigger_free(sigma_delta->trig);
}
/**
- * ad_sd_setup_buffer_and_trigger() -
+ * devm_ad_sd_setup_buffer_and_trigger() - Device-managed buffer & trigger setup
+ * @dev: Device object to which to bind the life-time of the resources attached
* @indio_dev: The IIO device
*/
-int ad_sd_setup_buffer_and_trigger(struct iio_dev *indio_dev)
+int devm_ad_sd_setup_buffer_and_trigger(struct device *dev, struct iio_dev *indio_dev)
{
int ret;
- ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
- &ad_sd_trigger_handler, &ad_sd_buffer_setup_ops);
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ &iio_pollfunc_store_time,
+ &ad_sd_trigger_handler,
+ &ad_sd_buffer_setup_ops);
if (ret)
return ret;
- ret = ad_sd_probe_trigger(indio_dev);
- if (ret) {
- iio_triggered_buffer_cleanup(indio_dev);
- return ret;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ad_sd_setup_buffer_and_trigger);
-
-/**
- * ad_sd_cleanup_buffer_and_trigger() -
- * @indio_dev: The IIO device
- */
-void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev)
-{
- ad_sd_remove_trigger(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
+ return devm_ad_sd_probe_trigger(dev, indio_dev);
}
-EXPORT_SYMBOL_GPL(ad_sd_cleanup_buffer_and_trigger);
+EXPORT_SYMBOL_GPL(devm_ad_sd_setup_buffer_and_trigger);
/**
* ad_sd_init() - Initializes a ad_sigma_delta struct
diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c
index d5f6ffc5b5bc..a73e3c2d212f 100644
--- a/drivers/iio/adc/adi-axi-adc.c
+++ b/drivers/iio/adc/adi-axi-adc.c
@@ -202,29 +202,25 @@ static void adi_axi_adc_conv_unregister(struct adi_axi_adc_conv *conv)
kfree(cl);
}
-static void devm_adi_axi_adc_conv_release(struct device *dev, void *res)
+static void devm_adi_axi_adc_conv_release(void *conv)
{
- adi_axi_adc_conv_unregister(*(struct adi_axi_adc_conv **)res);
+ adi_axi_adc_conv_unregister(conv);
}
struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev,
size_t sizeof_priv)
{
- struct adi_axi_adc_conv **ptr, *conv;
-
- ptr = devres_alloc(devm_adi_axi_adc_conv_release, sizeof(*ptr),
- GFP_KERNEL);
- if (!ptr)
- return ERR_PTR(-ENOMEM);
+ struct adi_axi_adc_conv *conv;
+ int ret;
conv = adi_axi_adc_conv_register(dev, sizeof_priv);
- if (IS_ERR(conv)) {
- devres_free(ptr);
- return ERR_CAST(conv);
- }
+ if (IS_ERR(conv))
+ return conv;
- *ptr = conv;
- devres_add(dev, ptr);
+ ret = devm_add_action_or_reset(dev, devm_adi_axi_adc_conv_release,
+ conv);
+ if (ret)
+ return ERR_PTR(ret);
return conv;
}
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index a7826f097b95..ea5ca163d879 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -403,7 +403,8 @@ struct at91_adc_state {
struct at91_adc_dma dma_st;
struct at91_adc_touch touch_st;
struct iio_dev *indio_dev;
- u16 buffer[AT91_BUFFER_MAX_HWORDS];
+ /* Ensure naturally aligned timestamp */
+ u16 buffer[AT91_BUFFER_MAX_HWORDS] __aligned(8);
/*
* lock to prevent concurrent 'single conversion' requests through
* sysfs.
@@ -997,7 +998,7 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *indio,
int ret;
trig = devm_iio_trigger_alloc(&indio->dev, "%s-dev%d-%s", indio->name,
- indio->id, trigger_name);
+ iio_device_id(indio), trigger_name);
if (!trig)
return NULL;
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 0b5f0c91d0d7..5a7d3a3a5fa8 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -547,7 +547,7 @@ static int at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
char *name = kasprintf(GFP_KERNEL,
"%s-dev%d-%s",
idev->name,
- idev->id,
+ iio_device_id(idev),
triggers[i].name);
if (!name)
return -ENOMEM;
@@ -626,7 +626,7 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev,
int ret;
trig = iio_trigger_alloc(idev->dev.parent, "%s-dev%d-%s", idev->name,
- idev->id, trigger->name);
+ iio_device_id(idev), trigger->name);
if (trig == NULL)
return NULL;
diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c
index 0d53ef18e045..16407664182c 100644
--- a/drivers/iio/adc/dln2-adc.c
+++ b/drivers/iio/adc/dln2-adc.c
@@ -649,7 +649,8 @@ static int dln2_adc_probe(struct platform_device *pdev)
indio_dev->setup_ops = &dln2_adc_buffer_setup_ops;
dln2->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
- indio_dev->name, indio_dev->id);
+ indio_dev->name,
+ iio_device_id(indio_dev));
if (!dln2->trig) {
dev_err(dev, "failed to allocate trigger\n");
return -ENOMEM;
diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
index c08ab3c6dfaf..a10a4e8d94fd 100644
--- a/drivers/iio/adc/ep93xx_adc.c
+++ b/drivers/iio/adc/ep93xx_adc.c
@@ -165,10 +165,8 @@ static int ep93xx_adc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(priv->base)) {
- dev_err(&pdev->dev, "Cannot map memory resource\n");
+ if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- }
iiodev->name = dev_name(&pdev->dev);
iiodev->modes = INDIO_DIRECT_MODE;
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 8c98d8c9ab1f..3b3868aa2533 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -794,7 +794,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
struct s3c2410_ts_mach_info *pdata = dev_get_platdata(&pdev->dev);
struct iio_dev *indio_dev = NULL;
bool has_ts = false;
- int ret = -ENODEV;
+ int ret;
int irq;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc));
diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c
index 074c30970465..8b353e26668e 100644
--- a/drivers/iio/adc/hi8435.c
+++ b/drivers/iio/adc/hi8435.c
@@ -483,7 +483,6 @@ static int hi8435_probe(struct spi_device *spi)
gpiod_set_value_cansleep(reset_gpio, 1);
}
- spi_set_drvdata(spi, idev);
mutex_init(&priv->lock);
idev->name = spi_get_device_id(spi)->name;
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index 6a173531d355..f7ee856a6b8b 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -86,9 +86,9 @@ struct hx711_data {
struct mutex lock;
/*
* triggered buffer
- * 2x32-bit channel + 64-bit timestamp
+ * 2x32-bit channel + 64-bit naturally aligned timestamp
*/
- u32 buffer[4];
+ u32 buffer[4] __aligned(8);
/*
* delay after a rising edge on SCK until the data is ready DOUT
* this is dependent on the hx711 where the datasheet tells a
diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c
index 2ae54258b221..a4b2ff9e0dd5 100644
--- a/drivers/iio/adc/ina2xx-adc.c
+++ b/drivers/iio/adc/ina2xx-adc.c
@@ -843,7 +843,8 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev)
chip->allow_async_readout);
task = kthread_create(ina2xx_capture_thread, (void *)indio_dev,
- "%s:%d-%uus", indio_dev->name, indio_dev->id,
+ "%s:%d-%uus", indio_dev->name,
+ iio_device_id(indio_dev),
sampling_us);
if (IS_ERR(task))
return PTR_ERR(task);
diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c
index e3c8ec107722..655ab02d03d8 100644
--- a/drivers/iio/adc/max1027.c
+++ b/drivers/iio/adc/max1027.c
@@ -430,8 +430,6 @@ static int max1027_probe(struct spi_device *spi)
return -ENOMEM;
}
- spi_set_drvdata(spi, indio_dev);
-
st = iio_priv(indio_dev);
st->spi = spi;
st->info = &max1027_chip_info_tbl[spi_get_device_id(spi)->driver_data];
diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c
index 6cf21758ca66..eb1ce6a0315c 100644
--- a/drivers/iio/adc/max11100.c
+++ b/drivers/iio/adc/max11100.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
+#include <asm/unaligned.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
@@ -63,7 +64,7 @@ static int max11100_read_single(struct iio_dev *indio_dev, int *val)
return -EINVAL;
}
- *val = (state->buffer[1] << 8) | state->buffer[2];
+ *val = get_unaligned_be16(&state->buffer[1]);
return 0;
}
@@ -101,6 +102,11 @@ static const struct iio_info max11100_info = {
.read_raw = max11100_read_raw,
};
+static void max11100_regulator_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int max11100_probe(struct spi_device *spi)
{
int ret;
@@ -111,8 +117,6 @@ static int max11100_probe(struct spi_device *spi)
if (!indio_dev)
return -ENOMEM;
- spi_set_drvdata(spi, indio_dev);
-
state = iio_priv(indio_dev);
state->spi = spi;
@@ -130,27 +134,12 @@ static int max11100_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = iio_device_register(indio_dev);
+ ret = devm_add_action_or_reset(&spi->dev, max11100_regulator_disable,
+ state->vref_reg);
if (ret)
- goto disable_regulator;
-
- return 0;
-
-disable_regulator:
- regulator_disable(state->vref_reg);
-
- return ret;
-}
-
-static int max11100_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct max11100_state *state = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- regulator_disable(state->vref_reg);
+ return ret;
- return 0;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct of_device_id max11100_ids[] = {
@@ -165,7 +154,6 @@ static struct spi_driver max11100_driver = {
.of_match_table = max11100_ids,
},
.probe = max11100_probe,
- .remove = max11100_remove,
};
module_spi_driver(max11100_driver);
diff --git a/drivers/iio/adc/max1118.c b/drivers/iio/adc/max1118.c
index 6efb0b43d938..8cec9d949083 100644
--- a/drivers/iio/adc/max1118.c
+++ b/drivers/iio/adc/max1118.c
@@ -66,9 +66,8 @@ static const struct iio_chan_spec max1118_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(2),
};
-static int max1118_read(struct spi_device *spi, int channel)
+static int max1118_read(struct iio_dev *indio_dev, int channel)
{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct max1118 *adc = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
/*
@@ -103,9 +102,9 @@ static int max1118_read(struct spi_device *spi, int channel)
int ret;
if (channel == 0)
- ret = spi_sync_transfer(spi, xfers + 1, 2);
+ ret = spi_sync_transfer(adc->spi, xfers + 1, 2);
else
- ret = spi_sync_transfer(spi, xfers, 3);
+ ret = spi_sync_transfer(adc->spi, xfers, 3);
if (ret)
return ret;
@@ -113,11 +112,10 @@ static int max1118_read(struct spi_device *spi, int channel)
return adc->data;
}
-static int max1118_get_vref_mV(struct spi_device *spi)
+static int max1118_get_vref_mV(struct iio_dev *indio_dev)
{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct max1118 *adc = iio_priv(indio_dev);
- const struct spi_device_id *id = spi_get_device_id(spi);
+ const struct spi_device_id *id = spi_get_device_id(adc->spi);
int vref_uV;
switch (id->driver_data) {
@@ -144,14 +142,14 @@ static int max1118_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&adc->lock);
- *val = max1118_read(adc->spi, chan->channel);
+ *val = max1118_read(indio_dev, chan->channel);
mutex_unlock(&adc->lock);
if (*val < 0)
return *val;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- *val = max1118_get_vref_mV(adc->spi);
+ *val = max1118_get_vref_mV(indio_dev);
if (*val < 0)
return *val;
*val2 = 8;
@@ -180,7 +178,7 @@ static irqreturn_t max1118_trigger_handler(int irq, void *p)
indio_dev->masklength) {
const struct iio_chan_spec *scan_chan =
&indio_dev->channels[scan_index];
- int ret = max1118_read(adc->spi, scan_chan->channel);
+ int ret = max1118_read(indio_dev, scan_chan->channel);
if (ret < 0) {
dev_warn(&adc->spi->dev,
@@ -201,6 +199,11 @@ out:
return IRQ_HANDLED;
}
+static void max1118_reg_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int max1118_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
@@ -225,9 +228,13 @@ static int max1118_probe(struct spi_device *spi)
ret = regulator_enable(adc->reg);
if (ret)
return ret;
- }
- spi_set_drvdata(spi, indio_dev);
+ ret = devm_add_action_or_reset(&spi->dev, max1118_reg_disable,
+ adc->reg);
+ if (ret)
+ return ret;
+
+ }
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &max1118_info;
@@ -241,40 +248,14 @@ static int max1118_probe(struct spi_device *spi)
* a conversion has been completed, the MAX1117/MAX1118/MAX1119 will go
* into AutoShutdown mode until the next conversion is initiated.
*/
- max1118_read(spi, 0);
-
- ret = iio_triggered_buffer_setup(indio_dev, NULL,
- max1118_trigger_handler, NULL);
- if (ret)
- goto err_reg_disable;
+ max1118_read(indio_dev, 0);
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
+ max1118_trigger_handler, NULL);
if (ret)
- goto err_buffer_cleanup;
-
- return 0;
-
-err_buffer_cleanup:
- iio_triggered_buffer_cleanup(indio_dev);
-err_reg_disable:
- if (id->driver_data == max1118)
- regulator_disable(adc->reg);
-
- return ret;
-}
-
-static int max1118_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct max1118 *adc = iio_priv(indio_dev);
- const struct spi_device_id *id = spi_get_device_id(spi);
-
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
- if (id->driver_data == max1118)
- return regulator_disable(adc->reg);
+ return ret;
- return 0;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id max1118_id[] = {
@@ -299,7 +280,6 @@ static struct spi_driver max1118_spi_driver = {
.of_match_table = max1118_dt_ids,
},
.probe = max1118_probe,
- .remove = max1118_remove,
.id_table = max1118_id,
};
module_spi_driver(max1118_spi_driver);
diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c
index 0cbbb3c56d08..b60f8448f21a 100644
--- a/drivers/iio/adc/max1241.c
+++ b/drivers/iio/adc/max1241.c
@@ -147,8 +147,6 @@ static int max1241_probe(struct spi_device *spi)
adc->spi = spi;
mutex_init(&adc->lock);
- spi_set_drvdata(spi, indio_dev);
-
adc->vdd = devm_regulator_get(dev, "vdd");
if (IS_ERR(adc->vdd)) {
dev_err(dev, "failed to get vdd regulator\n");
diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c
index 331a9a728217..aca084f1e78a 100644
--- a/drivers/iio/adc/mp2629_adc.c
+++ b/drivers/iio/adc/mp2629_adc.c
@@ -144,7 +144,6 @@ static int mp2629_adc_probe(struct platform_device *pdev)
}
indio_dev->name = "mp2629-adc";
- indio_dev->dev.parent = dev;
indio_dev->channels = mp2629_channels;
indio_dev->num_channels = ARRAY_SIZE(mp2629_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c
index 6b39a139ce28..07c0e6768391 100644
--- a/drivers/iio/adc/mt6360-adc.c
+++ b/drivers/iio/adc/mt6360-adc.c
@@ -337,7 +337,6 @@ static int mt6360_adc_probe(struct platform_device *pdev)
}
indio_dev->name = dev_name(&pdev->dev);
- indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &mt6360_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = mt6360_adc_channels;
diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c
index 30e29f44ebd2..bca79a93cbe4 100644
--- a/drivers/iio/adc/mxs-lradc-adc.c
+++ b/drivers/iio/adc/mxs-lradc-adc.c
@@ -115,7 +115,8 @@ struct mxs_lradc_adc {
struct device *dev;
void __iomem *base;
- u32 buffer[10];
+ /* Maximum of 8 channels + 8 byte ts */
+ u32 buffer[10] __aligned(8);
struct iio_trigger *trig;
struct completion completion;
spinlock_t lock;
@@ -455,7 +456,7 @@ static int mxs_lradc_adc_trigger_init(struct iio_dev *iio)
struct mxs_lradc_adc *adc = iio_priv(iio);
trig = devm_iio_trigger_alloc(&iio->dev, "%s-dev%i", iio->name,
- iio->id);
+ iio_device_id(iio));
if (!trig)
return -ENOMEM;
diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c
index 9f38cf3c7dc2..a48895046408 100644
--- a/drivers/iio/adc/rcar-gyroadc.c
+++ b/drivers/iio/adc/rcar-gyroadc.c
@@ -162,18 +162,13 @@ static const struct iio_chan_spec rcar_gyroadc_iio_channels_3[] = {
static int rcar_gyroadc_set_power(struct rcar_gyroadc *priv, bool on)
{
struct device *dev = priv->dev;
- int ret;
if (on) {
- ret = pm_runtime_get_sync(dev);
- if (ret < 0)
- pm_runtime_put_noidle(dev);
+ return pm_runtime_resume_and_get(dev);
} else {
pm_runtime_mark_last_busy(dev);
- ret = pm_runtime_put_autosuspend(dev);
+ return pm_runtime_put_autosuspend(dev);
}
-
- return ret;
}
static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev,
@@ -535,7 +530,10 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(dev);
pm_runtime_enable(dev);
- pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ goto err_power_up;
+
rcar_gyroadc_hw_init(priv);
rcar_gyroadc_hw_start(priv);
@@ -552,6 +550,7 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
err_iio_device_register:
rcar_gyroadc_hw_stop(priv);
pm_runtime_put_sync(dev);
+err_power_up:
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
clk_disable_unprepare(priv->clk);
diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c
index 301cf66de695..00098caf6d9e 100644
--- a/drivers/iio/adc/sc27xx_adc.c
+++ b/drivers/iio/adc/sc27xx_adc.c
@@ -549,6 +549,7 @@ static const struct of_device_id sc27xx_adc_of_match[] = {
{ .compatible = "sprd,sc2731-adc", },
{ }
};
+MODULE_DEVICE_TABLE(of, sc27xx_adc_of_match);
static struct platform_driver sc27xx_adc_driver = {
.probe = sc27xx_adc_probe,
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index b25386b19373..5088de835bb1 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -449,7 +449,7 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = {
.smp_bits = stm32h7_smp_bits,
};
-/**
+/*
* STM32 ADC registers access routines
* @adc: stm32 adc instance
* @reg: reg offset in adc instance
@@ -851,7 +851,7 @@ static int stm32h7_adc_restore_selfcalib(struct iio_dev *indio_dev)
return 0;
}
-/**
+/*
* Fixed timeout value for ADC calibration.
* worst cases:
* - low clock frequency
@@ -1158,11 +1158,9 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
adc->bufi = 0;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
return ret;
- }
/* Apply sampling time settings */
stm32_adc_writel(adc, regs->smpr[0], adc->smpr_val[0]);
@@ -1364,11 +1362,9 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev,
struct device *dev = indio_dev->dev.parent;
int ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
return ret;
- }
adc->num_conv = bitmap_weight(scan_mask, indio_dev->masklength);
@@ -1413,11 +1409,9 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev,
struct device *dev = indio_dev->dev.parent;
int ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
return ret;
- }
if (!readval)
stm32_adc_writel(adc, reg, writeval);
@@ -1537,11 +1531,9 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
struct device *dev = indio_dev->dev.parent;
int ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
return ret;
- }
ret = stm32_adc_set_trig(indio_dev, indio_dev->trig);
if (ret) {
diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c
index bb925a11c8ae..a627af9a825e 100644
--- a/drivers/iio/adc/stm32-dfsdm-core.c
+++ b/drivers/iio/adc/stm32-dfsdm-core.c
@@ -135,11 +135,9 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm)
int ret;
if (atomic_inc_return(&priv->n_active_ch) == 1) {
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
goto error_ret;
- }
/* select clock source, e.g. 0 for "dfsdm" or 1 for "audio" */
clk_src = priv->aclk ? 1 : 0;
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index b64718daa201..16fc608db36a 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -146,6 +146,11 @@ out:
return IRQ_HANDLED;
}
+static void adc081c_reg_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int adc081c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -175,6 +180,11 @@ static int adc081c_probe(struct i2c_client *client,
if (err < 0)
return err;
+ err = devm_add_action_or_reset(&client->dev, adc081c_reg_disable,
+ adc->ref);
+ if (err)
+ return err;
+
iio->name = dev_name(&client->dev);
iio->modes = INDIO_DIRECT_MODE;
iio->info = &adc081c_info;
@@ -182,38 +192,14 @@ static int adc081c_probe(struct i2c_client *client,
iio->channels = model->channels;
iio->num_channels = ADC081C_NUM_CHANNELS;
- err = iio_triggered_buffer_setup(iio, NULL, adc081c_trigger_handler, NULL);
+ err = devm_iio_triggered_buffer_setup(&client->dev, iio, NULL,
+ adc081c_trigger_handler, NULL);
if (err < 0) {
dev_err(&client->dev, "iio triggered buffer setup failed\n");
- goto err_regulator_disable;
+ return err;
}
- err = iio_device_register(iio);
- if (err < 0)
- goto err_buffer_cleanup;
-
- i2c_set_clientdata(client, iio);
-
- return 0;
-
-err_buffer_cleanup:
- iio_triggered_buffer_cleanup(iio);
-err_regulator_disable:
- regulator_disable(adc->ref);
-
- return err;
-}
-
-static int adc081c_remove(struct i2c_client *client)
-{
- struct iio_dev *iio = i2c_get_clientdata(client);
- struct adc081c *adc = iio_priv(iio);
-
- iio_device_unregister(iio);
- iio_triggered_buffer_cleanup(iio);
- regulator_disable(adc->ref);
-
- return 0;
+ return devm_iio_device_register(&client->dev, iio);
}
static const struct i2c_device_id adc081c_id[] = {
@@ -238,7 +224,6 @@ static struct i2c_driver adc081c_driver = {
.of_match_table = adc081c_of_match,
},
.probe = adc081c_probe,
- .remove = adc081c_remove,
.id_table = adc081c_id,
};
module_i2c_driver(adc081c_driver);
diff --git a/drivers/iio/adc/ti-adc0832.c b/drivers/iio/adc/ti-adc0832.c
index 0261b3cfc92b..fb5e72600b96 100644
--- a/drivers/iio/adc/ti-adc0832.c
+++ b/drivers/iio/adc/ti-adc0832.c
@@ -236,6 +236,11 @@ out:
return IRQ_HANDLED;
}
+static void adc0832_reg_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int adc0832_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
@@ -287,36 +292,17 @@ static int adc0832_probe(struct spi_device *spi)
if (ret)
return ret;
- spi_set_drvdata(spi, indio_dev);
-
- ret = iio_triggered_buffer_setup(indio_dev, NULL,
- adc0832_trigger_handler, NULL);
+ ret = devm_add_action_or_reset(&spi->dev, adc0832_reg_disable,
+ adc->reg);
if (ret)
- goto err_reg_disable;
+ return ret;
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
+ adc0832_trigger_handler, NULL);
if (ret)
- goto err_buffer_cleanup;
-
- return 0;
-err_buffer_cleanup:
- iio_triggered_buffer_cleanup(indio_dev);
-err_reg_disable:
- regulator_disable(adc->reg);
-
- return ret;
-}
-
-static int adc0832_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct adc0832 *adc = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
- regulator_disable(adc->reg);
+ return ret;
- return 0;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct of_device_id adc0832_dt_ids[] = {
@@ -343,7 +329,6 @@ static struct spi_driver adc0832_driver = {
.of_match_table = adc0832_dt_ids,
},
.probe = adc0832_probe,
- .remove = adc0832_remove,
.id_table = adc0832_id,
};
module_spi_driver(adc0832_driver);
diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c
index 33aea961d850..ce3f5a3814f9 100644
--- a/drivers/iio/adc/ti-adc084s021.c
+++ b/drivers/iio/adc/ti-adc084s021.c
@@ -210,9 +210,6 @@ static int adc084s021_probe(struct spi_device *spi)
adc = iio_priv(indio_dev);
adc->spi = spi;
- /* Connect the SPI device and the iio dev */
- spi_set_drvdata(spi, indio_dev);
-
/* Initiate the Industrial I/O device */
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c
index 183b2245e89b..db902aef2abe 100644
--- a/drivers/iio/adc/ti-adc108s102.c
+++ b/drivers/iio/adc/ti-adc108s102.c
@@ -215,6 +215,11 @@ static const struct iio_info adc108s102_info = {
.update_scan_mode = &adc108s102_update_scan_mode,
};
+static void adc108s102_reg_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int adc108s102_probe(struct spi_device *spi)
{
struct adc108s102_state *st;
@@ -239,6 +244,10 @@ static int adc108s102_probe(struct spi_device *spi)
dev_err(&spi->dev, "Cannot enable vref regulator\n");
return ret;
}
+ ret = devm_add_action_or_reset(&spi->dev, adc108s102_reg_disable,
+ st->reg);
+ if (ret)
+ return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0) {
@@ -249,7 +258,6 @@ static int adc108s102_probe(struct spi_device *spi)
st->va_millivolt = ret / 1000;
}
- spi_set_drvdata(spi, indio_dev);
st->spi = spi;
indio_dev->name = spi->modalias;
@@ -266,40 +274,18 @@ static int adc108s102_probe(struct spi_device *spi)
spi_message_init_with_transfers(&st->scan_single_msg,
&st->scan_single_xfer, 1);
- ret = iio_triggered_buffer_setup(indio_dev, NULL,
- &adc108s102_trigger_handler, NULL);
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
+ &adc108s102_trigger_handler,
+ NULL);
if (ret)
- goto error_disable_reg;
+ return ret;
- ret = iio_device_register(indio_dev);
- if (ret) {
+ ret = devm_iio_device_register(&spi->dev, indio_dev);
+ if (ret)
dev_err(&spi->dev, "Failed to register IIO device\n");
- goto error_cleanup_triggered_buffer;
- }
- return 0;
-
-error_cleanup_triggered_buffer:
- iio_triggered_buffer_cleanup(indio_dev);
-
-error_disable_reg:
- regulator_disable(st->reg);
-
return ret;
}
-static int adc108s102_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct adc108s102_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
-
- regulator_disable(st->reg);
-
- return 0;
-}
-
static const struct of_device_id adc108s102_of_match[] = {
{ .compatible = "ti,adc108s102" },
{ }
@@ -327,7 +313,6 @@ static struct spi_driver adc108s102_driver = {
.acpi_match_table = ACPI_PTR(adc108s102_acpi_ids),
},
.probe = adc108s102_probe,
- .remove = adc108s102_remove,
.id_table = adc108s102_id,
};
module_spi_driver(adc108s102_driver);
diff --git a/drivers/iio/adc/ti-adc161s626.c b/drivers/iio/adc/ti-adc161s626.c
index 607791ffe7f0..75ca7f1c8726 100644
--- a/drivers/iio/adc/ti-adc161s626.c
+++ b/drivers/iio/adc/ti-adc161s626.c
@@ -169,6 +169,11 @@ static const struct iio_info ti_adc_info = {
.read_raw = ti_adc_read_raw,
};
+static void ti_adc_reg_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int ti_adc_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
@@ -182,7 +187,6 @@ static int ti_adc_probe(struct spi_device *spi)
indio_dev->info = &ti_adc_info;
indio_dev->name = TI_ADC_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
- spi_set_drvdata(spi, indio_dev);
data = iio_priv(indio_dev);
data->spi = spi;
@@ -203,42 +207,24 @@ static int ti_adc_probe(struct spi_device *spi)
}
data->ref = devm_regulator_get(&spi->dev, "vdda");
- if (!IS_ERR(data->ref)) {
- ret = regulator_enable(data->ref);
- if (ret < 0)
- return ret;
- }
+ if (IS_ERR(data->ref))
+ return PTR_ERR(data->ref);
- ret = iio_triggered_buffer_setup(indio_dev, NULL,
- ti_adc_trigger_handler, NULL);
- if (ret)
- goto error_regulator_disable;
+ ret = regulator_enable(data->ref);
+ if (ret < 0)
+ return ret;
- ret = iio_device_register(indio_dev);
+ ret = devm_add_action_or_reset(&spi->dev, ti_adc_reg_disable,
+ data->ref);
if (ret)
- goto error_unreg_buffer;
-
- return 0;
+ return ret;
-error_unreg_buffer:
- iio_triggered_buffer_cleanup(indio_dev);
-
-error_regulator_disable:
- regulator_disable(data->ref);
-
- return ret;
-}
-
-static int ti_adc_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ti_adc_data *data = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
- regulator_disable(data->ref);
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
+ ti_adc_trigger_handler, NULL);
+ if (ret)
+ return ret;
- return 0;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct of_device_id ti_adc_dt_ids[] = {
@@ -261,7 +247,6 @@ static struct spi_driver ti_adc_driver = {
.of_match_table = ti_adc_dt_ids,
},
.probe = ti_adc_probe,
- .remove = ti_adc_remove,
.id_table = ti_adc_id,
};
module_spi_driver(ti_adc_driver);
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 9fef39bcf997..b0352e91ac16 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -323,9 +323,7 @@ static int ads1015_set_power_state(struct ads1015_data *data, bool on)
struct device *dev = regmap_get_device(data->regmap);
if (on) {
- ret = pm_runtime_get_sync(dev);
- if (ret < 0)
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
} else {
pm_runtime_mark_last_busy(dev);
ret = pm_runtime_put_autosuspend(dev);
@@ -395,10 +393,14 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ads1015_data *data = iio_priv(indio_dev);
- s16 buf[8]; /* 1x s16 ADC val + 3x s16 padding + 4x s16 timestamp */
+ /* Ensure natural alignment of timestamp */
+ struct {
+ s16 chan;
+ s64 timestamp __aligned(8);
+ } scan;
int chan, ret, res;
- memset(buf, 0, sizeof(buf));
+ memset(&scan, 0, sizeof(scan));
mutex_lock(&data->lock);
chan = find_first_bit(indio_dev->active_scan_mask,
@@ -409,10 +411,10 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p)
goto err;
}
- buf[0] = res;
+ scan.chan = res;
mutex_unlock(&data->lock);
- iio_push_to_buffers_with_timestamp(indio_dev, buf,
+ iio_push_to_buffers_with_timestamp(indio_dev, &scan,
iio_get_time_ns(indio_dev));
err:
@@ -1066,7 +1068,6 @@ static int ads1015_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
/* power down single shot mode */
return ads1015_set_conv_mode(data, ADS1015_SINGLESHOT);
diff --git a/drivers/iio/adc/ti-ads124s08.c b/drivers/iio/adc/ti-ads124s08.c
index b4a128b19188..17d0da5877a9 100644
--- a/drivers/iio/adc/ti-ads124s08.c
+++ b/drivers/iio/adc/ti-ads124s08.c
@@ -327,8 +327,6 @@ static int ads124s_probe(struct spi_device *spi)
ads124s_priv->chip_info = &ads124s_chip_info_tbl[spi_id->driver_data];
- spi_set_drvdata(spi, indio_dev);
-
ads124s_priv->spi = spi;
indio_dev->name = spi_id->name;
diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c
index 764dab087b41..0c2025a22575 100644
--- a/drivers/iio/adc/ti-ads131e08.c
+++ b/drivers/iio/adc/ti-ads131e08.c
@@ -830,7 +830,6 @@ static int ads131e08_probe(struct spi_device *spi)
return ret;
indio_dev->name = st->info->name;
- indio_dev->dev.parent = &spi->dev;
indio_dev->info = &ads131e08_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -850,7 +849,7 @@ static int ads131e08_probe(struct spi_device *spi)
}
st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
- indio_dev->name, indio_dev->id);
+ indio_dev->name, iio_device_id(indio_dev));
if (!st->trig) {
dev_err(&spi->dev, "failed to allocate IIO trigger\n");
return -ENOMEM;
diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c
index 16bcb37eebb7..79c803537dc4 100644
--- a/drivers/iio/adc/ti-ads8688.c
+++ b/drivers/iio/adc/ti-ads8688.c
@@ -383,7 +383,8 @@ static irqreturn_t ads8688_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- u16 buffer[ADS8688_MAX_CHANNELS + sizeof(s64)/sizeof(u16)];
+ /* Ensure naturally aligned timestamp */
+ u16 buffer[ADS8688_MAX_CHANNELS + sizeof(s64)/sizeof(u16)] __aligned(8);
int i, j = 0;
for (i = 0; i < indio_dev->masklength; i++) {
diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c
new file mode 100644
index 000000000000..170950d5dd49
--- /dev/null
+++ b/drivers/iio/adc/ti-tsc2046.c
@@ -0,0 +1,712 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments TSC2046 SPI ADC driver
+ *
+ * Copyright (c) 2021 Oleksij Rempel <kernel@pengutronix.de>, Pengutronix
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include <asm/unaligned.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger.h>
+
+/*
+ * The PENIRQ of TSC2046 controller is implemented as level shifter attached to
+ * the X+ line. If voltage of the X+ line reaches a specific level the IRQ will
+ * be activated or deactivated.
+ * To make this kind of IRQ reusable as trigger following additions were
+ * implemented:
+ * - rate limiting:
+ * For typical touchscreen use case, we need to trigger about each 10ms.
+ * - hrtimer:
+ * Continue triggering at least once after the IRQ was deactivated. Then
+ * deactivate this trigger to stop sampling in order to reduce power
+ * consumption.
+ */
+
+#define TI_TSC2046_NAME "tsc2046"
+
+/* This driver doesn't aim at the peak continuous sample rate */
+#define TI_TSC2046_MAX_SAMPLE_RATE 125000
+#define TI_TSC2046_SAMPLE_BITS \
+ BITS_PER_TYPE(struct tsc2046_adc_atom)
+#define TI_TSC2046_MAX_CLK_FREQ \
+ (TI_TSC2046_MAX_SAMPLE_RATE * TI_TSC2046_SAMPLE_BITS)
+
+#define TI_TSC2046_SAMPLE_INTERVAL_US 10000
+
+#define TI_TSC2046_START BIT(7)
+#define TI_TSC2046_ADDR GENMASK(6, 4)
+#define TI_TSC2046_ADDR_TEMP1 7
+#define TI_TSC2046_ADDR_AUX 6
+#define TI_TSC2046_ADDR_X 5
+#define TI_TSC2046_ADDR_Z2 4
+#define TI_TSC2046_ADDR_Z1 3
+#define TI_TSC2046_ADDR_VBAT 2
+#define TI_TSC2046_ADDR_Y 1
+#define TI_TSC2046_ADDR_TEMP0 0
+
+/*
+ * The mode bit sets the resolution of the ADC. With this bit low, the next
+ * conversion has 12-bit resolution, whereas with this bit high, the next
+ * conversion has 8-bit resolution. This driver is optimized for 12-bit mode.
+ * So, for this driver, this bit should stay zero.
+ */
+#define TI_TSC2046_8BIT_MODE BIT(3)
+
+/*
+ * SER/DFR - The SER/DFR bit controls the reference mode, either single-ended
+ * (high) or differential (low).
+ */
+#define TI_TSC2046_SER BIT(2)
+
+/*
+ * If VREF_ON and ADC_ON are both zero, then the chip operates in
+ * auto-wake/suspend mode. In most case this bits should stay zero.
+ */
+#define TI_TSC2046_PD1_VREF_ON BIT(1)
+#define TI_TSC2046_PD0_ADC_ON BIT(0)
+
+/*
+ * All supported devices can do 8 or 12bit resolution. This driver
+ * supports only 12bit mode, here we have a 16bit data transfer, where
+ * the MSB and the 3 LSB are 0.
+ */
+#define TI_TSC2046_DATA_12BIT GENMASK(14, 3)
+
+#define TI_TSC2046_MAX_CHAN 8
+
+/* Represents a HW sample */
+struct tsc2046_adc_atom {
+ /*
+ * Command transmitted to the controller. This field is empty on the RX
+ * buffer.
+ */
+ u8 cmd;
+ /*
+ * Data received from the controller. This field is empty for the TX
+ * buffer
+ */
+ __be16 data;
+} __packed;
+
+/* Layout of atomic buffers within big buffer */
+struct tsc2046_adc_group_layout {
+ /* Group offset within the SPI RX buffer */
+ unsigned int offset;
+ /*
+ * Amount of tsc2046_adc_atom structs within the same command gathered
+ * within same group.
+ */
+ unsigned int count;
+ /*
+ * Settling samples (tsc2046_adc_atom structs) which should be skipped
+ * before good samples will start.
+ */
+ unsigned int skip;
+};
+
+struct tsc2046_adc_dcfg {
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+};
+
+struct tsc2046_adc_ch_cfg {
+ unsigned int settling_time_us;
+ unsigned int oversampling_ratio;
+};
+
+struct tsc2046_adc_priv {
+ struct spi_device *spi;
+ const struct tsc2046_adc_dcfg *dcfg;
+
+ struct iio_trigger *trig;
+ struct hrtimer trig_timer;
+ spinlock_t trig_lock;
+ unsigned int trig_more_count;
+
+ struct spi_transfer xfer;
+ struct spi_message msg;
+
+ struct {
+ /* Scan data for each channel */
+ u16 data[TI_TSC2046_MAX_CHAN];
+ /* Timestamp */
+ s64 ts __aligned(8);
+ } scan_buf;
+
+ /*
+ * Lock to protect the layout and the SPI transfer buffer.
+ * tsc2046_adc_group_layout can be changed within update_scan_mode(),
+ * in this case the l[] and tx/rx buffer will be out of sync to each
+ * other.
+ */
+ struct mutex slock;
+ struct tsc2046_adc_group_layout l[TI_TSC2046_MAX_CHAN];
+ struct tsc2046_adc_atom *rx;
+ struct tsc2046_adc_atom *tx;
+
+ struct tsc2046_adc_atom *rx_one;
+ struct tsc2046_adc_atom *tx_one;
+
+ unsigned int count;
+ unsigned int groups;
+ u32 effective_speed_hz;
+ u32 scan_interval_us;
+ u32 time_per_scan_us;
+ u32 time_per_bit_ns;
+
+ struct tsc2046_adc_ch_cfg ch_cfg[TI_TSC2046_MAX_CHAN];
+};
+
+#define TI_TSC2046_V_CHAN(index, bits, name) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = index, \
+ .datasheet_name = "#name", \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = bits, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ }, \
+}
+
+#define DECLARE_TI_TSC2046_8_CHANNELS(name, bits) \
+const struct iio_chan_spec name ## _channels[] = { \
+ TI_TSC2046_V_CHAN(0, bits, TEMP0), \
+ TI_TSC2046_V_CHAN(1, bits, Y), \
+ TI_TSC2046_V_CHAN(2, bits, VBAT), \
+ TI_TSC2046_V_CHAN(3, bits, Z1), \
+ TI_TSC2046_V_CHAN(4, bits, Z2), \
+ TI_TSC2046_V_CHAN(5, bits, X), \
+ TI_TSC2046_V_CHAN(6, bits, AUX), \
+ TI_TSC2046_V_CHAN(7, bits, TEMP1), \
+ IIO_CHAN_SOFT_TIMESTAMP(8), \
+}
+
+static DECLARE_TI_TSC2046_8_CHANNELS(tsc2046_adc, 12);
+
+static const struct tsc2046_adc_dcfg tsc2046_adc_dcfg_tsc2046e = {
+ .channels = tsc2046_adc_channels,
+ .num_channels = ARRAY_SIZE(tsc2046_adc_channels),
+};
+
+/*
+ * Convert time to a number of samples which can be transferred within this
+ * time.
+ */
+static unsigned int tsc2046_adc_time_to_count(struct tsc2046_adc_priv *priv,
+ unsigned long time)
+{
+ unsigned int bit_count, sample_count;
+
+ bit_count = DIV_ROUND_UP(time * NSEC_PER_USEC, priv->time_per_bit_ns);
+ sample_count = DIV_ROUND_UP(bit_count, TI_TSC2046_SAMPLE_BITS);
+
+ dev_dbg(&priv->spi->dev, "Effective speed %u, time per bit: %u, count bits: %u, count samples: %u\n",
+ priv->effective_speed_hz, priv->time_per_bit_ns,
+ bit_count, sample_count);
+
+ return sample_count;
+}
+
+static u8 tsc2046_adc_get_cmd(struct tsc2046_adc_priv *priv, int ch_idx,
+ bool keep_power)
+{
+ u32 pd;
+
+ /*
+ * if PD bits are 0, controller will automatically disable ADC, VREF and
+ * enable IRQ.
+ */
+ if (keep_power)
+ pd = TI_TSC2046_PD0_ADC_ON;
+ else
+ pd = 0;
+
+ return TI_TSC2046_START | FIELD_PREP(TI_TSC2046_ADDR, ch_idx) | pd;
+}
+
+static u16 tsc2046_adc_get_value(struct tsc2046_adc_atom *buf)
+{
+ return FIELD_GET(TI_TSC2046_DATA_12BIT, get_unaligned_be16(&buf->data));
+}
+
+static int tsc2046_adc_read_one(struct tsc2046_adc_priv *priv, int ch_idx,
+ u32 *effective_speed_hz)
+{
+ struct spi_transfer xfer;
+ struct spi_message msg;
+ int ret;
+
+ memset(&xfer, 0, sizeof(xfer));
+ priv->tx_one->cmd = tsc2046_adc_get_cmd(priv, ch_idx, false);
+ priv->tx_one->data = 0;
+ xfer.tx_buf = priv->tx_one;
+ xfer.rx_buf = priv->rx_one;
+ xfer.len = sizeof(*priv->tx_one);
+ spi_message_init_with_transfers(&msg, &xfer, 1);
+
+ /*
+ * We aren't using spi_write_then_read() because we need to be able
+ * to get hold of the effective_speed_hz from the xfer
+ */
+ ret = spi_sync(priv->spi, &msg);
+ if (ret) {
+ dev_err_ratelimited(&priv->spi->dev, "SPI transfer failed %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
+ if (effective_speed_hz)
+ *effective_speed_hz = xfer.effective_speed_hz;
+
+ return tsc2046_adc_get_value(priv->rx_one);
+}
+
+static size_t tsc2046_adc_group_set_layout(struct tsc2046_adc_priv *priv,
+ unsigned int group,
+ unsigned int ch_idx)
+{
+ struct tsc2046_adc_ch_cfg *ch = &priv->ch_cfg[ch_idx];
+ struct tsc2046_adc_group_layout *cur;
+ unsigned int max_count, count_skip;
+ unsigned int offset = 0;
+
+ if (group)
+ offset = priv->l[group - 1].offset + priv->l[group - 1].count;
+
+ count_skip = tsc2046_adc_time_to_count(priv, ch->settling_time_us);
+ max_count = count_skip + ch->oversampling_ratio;
+
+ cur = &priv->l[group];
+ cur->offset = offset;
+ cur->count = max_count;
+ cur->skip = count_skip;
+
+ return sizeof(*priv->tx) * max_count;
+}
+
+static void tsc2046_adc_group_set_cmd(struct tsc2046_adc_priv *priv,
+ unsigned int group, int ch_idx)
+{
+ struct tsc2046_adc_group_layout *l = &priv->l[group];
+ unsigned int i;
+ u8 cmd;
+
+ /*
+ * Do not enable automatic power down on working samples. Otherwise the
+ * plates will never be completely charged.
+ */
+ cmd = tsc2046_adc_get_cmd(priv, ch_idx, true);
+
+ for (i = 0; i < l->count - 1; i++)
+ priv->tx[l->offset + i].cmd = cmd;
+
+ /* automatically power down on last sample */
+ priv->tx[l->offset + i].cmd = tsc2046_adc_get_cmd(priv, ch_idx, false);
+}
+
+static u16 tsc2046_adc_get_val(struct tsc2046_adc_priv *priv, int group)
+{
+ struct tsc2046_adc_group_layout *l;
+ unsigned int val, val_normalized = 0;
+ int valid_count, i;
+
+ l = &priv->l[group];
+ valid_count = l->count - l->skip;
+
+ for (i = 0; i < valid_count; i++) {
+ val = tsc2046_adc_get_value(&priv->rx[l->offset + l->skip + i]);
+ val_normalized += val;
+ }
+
+ return DIV_ROUND_UP(val_normalized, valid_count);
+}
+
+static int tsc2046_adc_scan(struct iio_dev *indio_dev)
+{
+ struct tsc2046_adc_priv *priv = iio_priv(indio_dev);
+ struct device *dev = &priv->spi->dev;
+ int group;
+ int ret;
+
+ ret = spi_sync(priv->spi, &priv->msg);
+ if (ret < 0) {
+ dev_err_ratelimited(dev, "SPI transfer failed: %pe\n", ERR_PTR(ret));
+ return ret;
+ }
+
+ for (group = 0; group < priv->groups; group++)
+ priv->scan_buf.data[group] = tsc2046_adc_get_val(priv, group);
+
+ ret = iio_push_to_buffers_with_timestamp(indio_dev, &priv->scan_buf,
+ iio_get_time_ns(indio_dev));
+ /* If the consumer is kfifo, we may get a EBUSY here - ignore it. */
+ if (ret < 0 && ret != -EBUSY) {
+ dev_err_ratelimited(dev, "Failed to push scan buffer %pe\n",
+ ERR_PTR(ret));
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static irqreturn_t tsc2046_adc_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct tsc2046_adc_priv *priv = iio_priv(indio_dev);
+
+ mutex_lock(&priv->slock);
+ tsc2046_adc_scan(indio_dev);
+ mutex_unlock(&priv->slock);
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int tsc2046_adc_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *active_scan_mask)
+{
+ struct tsc2046_adc_priv *priv = iio_priv(indio_dev);
+ unsigned int ch_idx, group = 0;
+ size_t size;
+
+ mutex_lock(&priv->slock);
+
+ size = 0;
+ for_each_set_bit(ch_idx, active_scan_mask, indio_dev->num_channels) {
+ size += tsc2046_adc_group_set_layout(priv, group, ch_idx);
+ tsc2046_adc_group_set_cmd(priv, group, ch_idx);
+ group++;
+ }
+
+ priv->groups = group;
+ priv->xfer.len = size;
+ priv->time_per_scan_us = size * 8 * priv->time_per_bit_ns / NSEC_PER_USEC;
+
+ if (priv->scan_interval_us > priv->time_per_scan_us)
+ dev_warn(&priv->spi->dev, "The scan interval (%d) is less then calculated scan time (%d)\n",
+ priv->scan_interval_us, priv->time_per_scan_us);
+
+ mutex_unlock(&priv->slock);
+
+ return 0;
+}
+
+static const struct iio_info tsc2046_adc_info = {
+ .update_scan_mode = tsc2046_adc_update_scan_mode,
+};
+
+static enum hrtimer_restart tsc2046_adc_trig_more(struct hrtimer *hrtimer)
+{
+ struct tsc2046_adc_priv *priv = container_of(hrtimer,
+ struct tsc2046_adc_priv,
+ trig_timer);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->trig_lock, flags);
+
+ disable_irq_nosync(priv->spi->irq);
+
+ priv->trig_more_count++;
+ iio_trigger_poll(priv->trig);
+
+ spin_unlock_irqrestore(&priv->trig_lock, flags);
+
+ return HRTIMER_NORESTART;
+}
+
+static irqreturn_t tsc2046_adc_irq(int irq, void *dev_id)
+{
+ struct iio_dev *indio_dev = dev_id;
+ struct tsc2046_adc_priv *priv = iio_priv(indio_dev);
+
+ spin_lock(&priv->trig_lock);
+
+ hrtimer_try_to_cancel(&priv->trig_timer);
+
+ priv->trig_more_count = 0;
+ disable_irq_nosync(priv->spi->irq);
+ iio_trigger_poll(priv->trig);
+
+ spin_unlock(&priv->trig_lock);
+
+ return IRQ_HANDLED;
+}
+
+static void tsc2046_adc_reenable_trigger(struct iio_trigger *trig)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct tsc2046_adc_priv *priv = iio_priv(indio_dev);
+ unsigned long flags;
+ int delta;
+
+ /*
+ * We can sample it as fast as we can, but usually we do not need so
+ * many samples. Reduce the sample rate for default (touchscreen) use
+ * case.
+ * Currently we do not need a highly precise sample rate. It is enough
+ * to have calculated numbers.
+ */
+ delta = priv->scan_interval_us - priv->time_per_scan_us;
+ if (delta > 0)
+ fsleep(delta);
+
+ spin_lock_irqsave(&priv->trig_lock, flags);
+
+ /*
+ * We need to trigger at least one extra sample to detect state
+ * difference on ADC side.
+ */
+ if (!priv->trig_more_count) {
+ int timeout_ms = DIV_ROUND_UP(priv->scan_interval_us,
+ USEC_PER_MSEC);
+
+ hrtimer_start(&priv->trig_timer, ms_to_ktime(timeout_ms),
+ HRTIMER_MODE_REL_SOFT);
+ }
+
+ enable_irq(priv->spi->irq);
+
+ spin_unlock_irqrestore(&priv->trig_lock, flags);
+}
+
+static int tsc2046_adc_set_trigger_state(struct iio_trigger *trig, bool enable)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct tsc2046_adc_priv *priv = iio_priv(indio_dev);
+
+ if (enable) {
+ enable_irq(priv->spi->irq);
+ } else {
+ disable_irq(priv->spi->irq);
+ hrtimer_try_to_cancel(&priv->trig_timer);
+ }
+
+ return 0;
+}
+
+static const struct iio_trigger_ops tsc2046_adc_trigger_ops = {
+ .set_trigger_state = tsc2046_adc_set_trigger_state,
+ .reenable = tsc2046_adc_reenable_trigger,
+};
+
+static int tsc2046_adc_setup_spi_msg(struct tsc2046_adc_priv *priv)
+{
+ unsigned int ch_idx;
+ size_t size;
+ int ret;
+
+ priv->tx_one = devm_kzalloc(&priv->spi->dev, sizeof(*priv->tx_one),
+ GFP_KERNEL);
+ if (!priv->tx_one)
+ return -ENOMEM;
+
+ priv->rx_one = devm_kzalloc(&priv->spi->dev, sizeof(*priv->rx_one),
+ GFP_KERNEL);
+ if (!priv->rx_one)
+ return -ENOMEM;
+
+ /*
+ * Make dummy read to set initial power state and get real SPI clock
+ * freq. It seems to be not important which channel is used for this
+ * case.
+ */
+ ret = tsc2046_adc_read_one(priv, TI_TSC2046_ADDR_TEMP0,
+ &priv->effective_speed_hz);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * In case SPI controller do not report effective_speed_hz, use
+ * configure value and hope it will match.
+ */
+ if (!priv->effective_speed_hz)
+ priv->effective_speed_hz = priv->spi->max_speed_hz;
+
+
+ priv->scan_interval_us = TI_TSC2046_SAMPLE_INTERVAL_US;
+ priv->time_per_bit_ns = DIV_ROUND_UP(NSEC_PER_SEC,
+ priv->effective_speed_hz);
+
+ /*
+ * Calculate and allocate maximal size buffer if all channels are
+ * enabled.
+ */
+ size = 0;
+ for (ch_idx = 0; ch_idx < priv->dcfg->num_channels; ch_idx++)
+ size += tsc2046_adc_group_set_layout(priv, ch_idx, ch_idx);
+
+ priv->tx = devm_kzalloc(&priv->spi->dev, size, GFP_KERNEL);
+ if (!priv->tx)
+ return -ENOMEM;
+
+ priv->rx = devm_kzalloc(&priv->spi->dev, size, GFP_KERNEL);
+ if (!priv->rx)
+ return -ENOMEM;
+
+ priv->xfer.tx_buf = priv->tx;
+ priv->xfer.rx_buf = priv->rx;
+ priv->xfer.len = size;
+ spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1);
+
+ return 0;
+}
+
+static void tsc2046_adc_parse_fwnode(struct tsc2046_adc_priv *priv)
+{
+ struct fwnode_handle *child;
+ struct device *dev = &priv->spi->dev;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(priv->ch_cfg); i++) {
+ priv->ch_cfg[i].settling_time_us = 1;
+ priv->ch_cfg[i].oversampling_ratio = 1;
+ }
+
+ device_for_each_child_node(dev, child) {
+ u32 stl, overs, reg;
+ int ret;
+
+ ret = fwnode_property_read_u32(child, "reg", &reg);
+ if (ret) {
+ dev_err(dev, "invalid reg on %pfw, err: %pe\n", child,
+ ERR_PTR(ret));
+ continue;
+ }
+
+ if (reg >= ARRAY_SIZE(priv->ch_cfg)) {
+ dev_err(dev, "%pfw: Unsupported reg value: %i, max supported is: %zu.\n",
+ child, reg, ARRAY_SIZE(priv->ch_cfg));
+ continue;
+ }
+
+ ret = fwnode_property_read_u32(child, "settling-time-us", &stl);
+ if (!ret)
+ priv->ch_cfg[reg].settling_time_us = stl;
+
+ ret = fwnode_property_read_u32(child, "oversampling-ratio",
+ &overs);
+ if (!ret)
+ priv->ch_cfg[reg].oversampling_ratio = overs;
+ }
+}
+
+static int tsc2046_adc_probe(struct spi_device *spi)
+{
+ const struct tsc2046_adc_dcfg *dcfg;
+ struct device *dev = &spi->dev;
+ struct tsc2046_adc_priv *priv;
+ struct iio_dev *indio_dev;
+ struct iio_trigger *trig;
+ int ret;
+
+ if (spi->max_speed_hz > TI_TSC2046_MAX_CLK_FREQ) {
+ dev_err(dev, "SPI max_speed_hz is too high: %d Hz. Max supported freq is %zu Hz\n",
+ spi->max_speed_hz, TI_TSC2046_MAX_CLK_FREQ);
+ return -EINVAL;
+ }
+
+ dcfg = device_get_match_data(dev);
+ if (!dcfg)
+ return -EINVAL;
+
+ spi->bits_per_word = 8;
+ spi->mode &= ~SPI_MODE_X_MASK;
+ spi->mode |= SPI_MODE_0;
+ ret = spi_setup(spi);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Error in SPI setup\n");
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ priv = iio_priv(indio_dev);
+ priv->dcfg = dcfg;
+
+ priv->spi = spi;
+
+ indio_dev->name = TI_TSC2046_NAME;
+ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_TRIGGERED;
+ indio_dev->channels = dcfg->channels;
+ indio_dev->num_channels = dcfg->num_channels;
+ indio_dev->info = &tsc2046_adc_info;
+
+ tsc2046_adc_parse_fwnode(priv);
+
+ ret = tsc2046_adc_setup_spi_msg(priv);
+ if (ret)
+ return ret;
+
+ mutex_init(&priv->slock);
+
+ ret = devm_request_irq(dev, spi->irq, &tsc2046_adc_irq,
+ IRQF_NO_AUTOEN, indio_dev->name, indio_dev);
+ if (ret)
+ return ret;
+
+ trig = devm_iio_trigger_alloc(dev, "touchscreen-%s", indio_dev->name);
+ if (!trig)
+ return -ENOMEM;
+
+ priv->trig = trig;
+ iio_trigger_set_drvdata(trig, indio_dev);
+ trig->ops = &tsc2046_adc_trigger_ops;
+
+ spin_lock_init(&priv->trig_lock);
+ hrtimer_init(&priv->trig_timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL_SOFT);
+ priv->trig_timer.function = tsc2046_adc_trig_more;
+
+ ret = devm_iio_trigger_register(dev, trig);
+ if (ret) {
+ dev_err(dev, "failed to register trigger\n");
+ return ret;
+ }
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ &tsc2046_adc_trigger_handler, NULL);
+ if (ret) {
+ dev_err(dev, "Failed to setup triggered buffer\n");
+ return ret;
+ }
+
+ /* set default trigger */
+ indio_dev->trig = iio_trigger_get(priv->trig);
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id ads7950_of_table[] = {
+ { .compatible = "ti,tsc2046e-adc", .data = &tsc2046_adc_dcfg_tsc2046e },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ads7950_of_table);
+
+static struct spi_driver tsc2046_adc_driver = {
+ .driver = {
+ .name = "tsc2046",
+ .of_match_table = ads7950_of_table,
+ },
+ .probe = tsc2046_adc_probe,
+};
+module_spi_driver(tsc2046_adc_driver);
+
+MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>");
+MODULE_DESCRIPTION("TI TSC2046 ADC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index 1d794cf3e3f1..fd57fc43e8e5 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -167,7 +167,11 @@ struct vf610_adc {
u32 sample_freq_avail[5];
struct completion completion;
- u16 buffer[8];
+ /* Ensure the timestamp is naturally aligned */
+ struct {
+ u16 chan;
+ s64 timestamp __aligned(8);
+ } scan;
};
static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
@@ -579,9 +583,9 @@ static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
if (coco & VF610_ADC_HS_COCO0) {
info->value = vf610_adc_read_data(info);
if (iio_buffer_enabled(indio_dev)) {
- info->buffer[0] = info->value;
+ info->scan.chan = info->value;
iio_push_to_buffers_with_timestamp(indio_dev,
- info->buffer,
+ &info->scan,
iio_get_time_ns(indio_dev));
iio_trigger_notify_done(indio_dev->trig);
} else
diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c
index 6914c1900ed0..198d2916266d 100644
--- a/drivers/iio/adc/xilinx-xadc-core.c
+++ b/drivers/iio/adc/xilinx-xadc-core.c
@@ -743,7 +743,7 @@ static struct iio_trigger *xadc_alloc_trigger(struct iio_dev *indio_dev,
int ret;
trig = devm_iio_trigger_alloc(dev, "%s%d-%s", indio_dev->name,
- indio_dev->id, name);
+ iio_device_id(indio_dev), name);
if (trig == NULL)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c
index e42ea2b1707d..774eb3044edd 100644
--- a/drivers/iio/afe/iio-rescale.c
+++ b/drivers/iio/afe/iio-rescale.c
@@ -29,6 +29,7 @@ struct rescale {
struct iio_channel *source;
struct iio_chan_spec chan;
struct iio_chan_spec_ext_info *ext_info;
+ bool chan_processed;
s32 numerator;
s32 denominator;
};
@@ -43,10 +44,27 @@ static int rescale_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- return iio_read_channel_raw(rescale->source, val);
+ if (rescale->chan_processed)
+ /*
+ * When only processed channels are supported, we
+ * read the processed data and scale it by 1/1
+ * augmented with whatever the rescaler has calculated.
+ */
+ return iio_read_channel_processed(rescale->source, val);
+ else
+ return iio_read_channel_raw(rescale->source, val);
case IIO_CHAN_INFO_SCALE:
- ret = iio_read_channel_scale(rescale->source, val, val2);
+ if (rescale->chan_processed) {
+ /*
+ * Processed channels are scaled 1-to-1
+ */
+ *val = 1;
+ *val2 = 1;
+ ret = IIO_VAL_FRACTIONAL;
+ } else {
+ ret = iio_read_channel_scale(rescale->source, val, val2);
+ }
switch (ret) {
case IIO_VAL_FRACTIONAL:
*val *= rescale->numerator;
@@ -130,16 +148,27 @@ static int rescale_configure_channel(struct device *dev,
chan->ext_info = rescale->ext_info;
chan->type = rescale->cfg->type;
- if (!iio_channel_has_info(schan, IIO_CHAN_INFO_RAW) ||
- !iio_channel_has_info(schan, IIO_CHAN_INFO_SCALE)) {
- dev_err(dev, "source channel does not support raw/scale\n");
+ if (iio_channel_has_info(schan, IIO_CHAN_INFO_RAW) ||
+ iio_channel_has_info(schan, IIO_CHAN_INFO_SCALE)) {
+ dev_info(dev, "using raw+scale source channel\n");
+ } else if (iio_channel_has_info(schan, IIO_CHAN_INFO_PROCESSED)) {
+ dev_info(dev, "using processed channel\n");
+ rescale->chan_processed = true;
+ } else {
+ dev_err(dev, "source channel is not supported\n");
return -EINVAL;
}
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE);
- if (iio_channel_has_available(schan, IIO_CHAN_INFO_RAW))
+ /*
+ * Using .read_avail() is fringe to begin with and makes no sense
+ * whatsoever for processed channels, so we make sure that this cannot
+ * be called on a processed channel.
+ */
+ if (iio_channel_has_available(schan, IIO_CHAN_INFO_RAW) &&
+ !rescale->chan_processed)
chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW);
return 0;
diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
index d76179878ff9..1ac94c4e9792 100644
--- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c
+++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
@@ -228,9 +228,9 @@ static void iio_dmaengine_buffer_free(struct iio_buffer *buffer)
iio_buffer_put(buffer);
}
-static void __devm_iio_dmaengine_buffer_free(struct device *dev, void *res)
+static void __devm_iio_dmaengine_buffer_free(void *buffer)
{
- iio_dmaengine_buffer_free(*(struct iio_buffer **)res);
+ iio_dmaengine_buffer_free(buffer);
}
/**
@@ -247,21 +247,17 @@ static void __devm_iio_dmaengine_buffer_free(struct device *dev, void *res)
static struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev,
const char *channel)
{
- struct iio_buffer **bufferp, *buffer;
-
- bufferp = devres_alloc(__devm_iio_dmaengine_buffer_free,
- sizeof(*bufferp), GFP_KERNEL);
- if (!bufferp)
- return ERR_PTR(-ENOMEM);
+ struct iio_buffer *buffer;
+ int ret;
buffer = iio_dmaengine_buffer_alloc(dev, channel);
- if (IS_ERR(buffer)) {
- devres_free(bufferp);
+ if (IS_ERR(buffer))
return buffer;
- }
- *bufferp = buffer;
- devres_add(dev, bufferp);
+ ret = devm_add_action_or_reset(dev, __devm_iio_dmaengine_buffer_free,
+ buffer);
+ if (ret)
+ return ERR_PTR(ret);
return buffer;
}
diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c
index f2d27788f666..87d9aabd20c7 100644
--- a/drivers/iio/buffer/industrialio-hw-consumer.c
+++ b/drivers/iio/buffer/industrialio-hw-consumer.c
@@ -137,9 +137,9 @@ void iio_hw_consumer_free(struct iio_hw_consumer *hwc)
}
EXPORT_SYMBOL_GPL(iio_hw_consumer_free);
-static void devm_iio_hw_consumer_release(struct device *dev, void *res)
+static void devm_iio_hw_consumer_release(void *iio_hwc)
{
- iio_hw_consumer_free(*(struct iio_hw_consumer **)res);
+ iio_hw_consumer_free(iio_hwc);
}
/**
@@ -153,20 +153,17 @@ static void devm_iio_hw_consumer_release(struct device *dev, void *res)
*/
struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev)
{
- struct iio_hw_consumer **ptr, *iio_hwc;
-
- ptr = devres_alloc(devm_iio_hw_consumer_release, sizeof(*ptr),
- GFP_KERNEL);
- if (!ptr)
- return NULL;
+ struct iio_hw_consumer *iio_hwc;
+ int ret;
iio_hwc = iio_hw_consumer_alloc(dev);
- if (IS_ERR(iio_hwc)) {
- devres_free(ptr);
- } else {
- *ptr = iio_hwc;
- devres_add(dev, ptr);
- }
+ if (IS_ERR(iio_hwc))
+ return iio_hwc;
+
+ ret = devm_add_action_or_reset(dev, devm_iio_hw_consumer_release,
+ iio_hwc);
+ if (ret)
+ return ERR_PTR(ret);
return iio_hwc;
}
diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c
index b2b1b7d27af4..f77c4538141e 100644
--- a/drivers/iio/buffer/industrialio-triggered-buffer.c
+++ b/drivers/iio/buffer/industrialio-triggered-buffer.c
@@ -56,7 +56,7 @@ int iio_triggered_buffer_setup_ext(struct iio_dev *indio_dev,
indio_dev,
"%s_consumer%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
goto error_kfifo_free;
@@ -96,9 +96,9 @@ void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev)
}
EXPORT_SYMBOL(iio_triggered_buffer_cleanup);
-static void devm_iio_triggered_buffer_clean(struct device *dev, void *res)
+static void devm_iio_triggered_buffer_clean(void *indio_dev)
{
- iio_triggered_buffer_cleanup(*(struct iio_dev **)res);
+ iio_triggered_buffer_cleanup(indio_dev);
}
int devm_iio_triggered_buffer_setup_ext(struct device *dev,
@@ -108,24 +108,15 @@ int devm_iio_triggered_buffer_setup_ext(struct device *dev,
const struct iio_buffer_setup_ops *ops,
const struct attribute **buffer_attrs)
{
- struct iio_dev **ptr;
int ret;
- ptr = devres_alloc(devm_iio_triggered_buffer_clean, sizeof(*ptr),
- GFP_KERNEL);
- if (!ptr)
- return -ENOMEM;
-
- *ptr = indio_dev;
-
ret = iio_triggered_buffer_setup_ext(indio_dev, h, thread, ops,
buffer_attrs);
- if (!ret)
- devres_add(dev, ptr);
- else
- devres_free(ptr);
+ if (ret)
+ return ret;
- return ret;
+ return devm_add_action_or_reset(dev, devm_iio_triggered_buffer_clean,
+ indio_dev);
}
EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_setup_ext);
diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig
index 10bb431bc3ce..a4920646e9be 100644
--- a/drivers/iio/chemical/Kconfig
+++ b/drivers/iio/chemical/Kconfig
@@ -132,17 +132,32 @@ config SENSIRION_SGP30
module will be called sgp30.
config SPS30
- tristate "SPS30 particulate matter sensor"
- depends on I2C
- select CRC8
+ tristate
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
+
+config SPS30_I2C
+ tristate "SPS30 particulate matter sensor I2C driver"
+ depends on I2C
+ select SPS30
+ select CRC8
help
- Say Y here to build support for the Sensirion SPS30 particulate
- matter sensor.
+ Say Y here to build support for the Sensirion SPS30 I2C interface
+ driver.
+
+ To compile this driver as a module, choose M here: the module will
+ be called sps30_i2c.
+
+config SPS30_SERIAL
+ tristate "SPS30 particulate matter sensor serial driver"
+ depends on SERIAL_DEV_BUS
+ select SPS30
+ help
+ Say Y here to build support for the Sensirion SPS30 serial interface
+ driver.
To compile this driver as a module, choose M here: the module will
- be called sps30.
+ be called sps30_serial.
config VZ89X
tristate "SGX Sensortech MiCS VZ89X VOC sensor"
diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile
index fef63dd5bf92..4898690cc155 100644
--- a/drivers/iio/chemical/Makefile
+++ b/drivers/iio/chemical/Makefile
@@ -17,4 +17,6 @@ obj-$(CONFIG_SCD30_I2C) += scd30_i2c.o
obj-$(CONFIG_SCD30_SERIAL) += scd30_serial.o
obj-$(CONFIG_SENSIRION_SGP30) += sgp30.o
obj-$(CONFIG_SPS30) += sps30.o
+obj-$(CONFIG_SPS30_I2C) += sps30_i2c.o
+obj-$(CONFIG_SPS30_SERIAL) += sps30_serial.o
obj-$(CONFIG_VZ89X) += vz89x.o
diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c
index 56ba6c82b501..9cb99585b6ff 100644
--- a/drivers/iio/chemical/atlas-sensor.c
+++ b/drivers/iio/chemical/atlas-sensor.c
@@ -91,8 +91,8 @@ struct atlas_data {
struct regmap *regmap;
struct irq_work work;
unsigned int interrupt_enabled;
-
- __be32 buffer[6]; /* 96-bit data + 32-bit pad + 64-bit timestamp */
+ /* 96-bit data + 32-bit pad + 64-bit timestamp */
+ __be32 buffer[6] __aligned(8);
};
static const struct regmap_config atlas_regmap_config = {
@@ -410,11 +410,9 @@ static int atlas_buffer_postenable(struct iio_dev *indio_dev)
struct atlas_data *data = iio_priv(indio_dev);
int ret;
- ret = pm_runtime_get_sync(&data->client->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&data->client->dev);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
+ if (ret)
return ret;
- }
return atlas_set_interrupt(data, true);
}
@@ -487,11 +485,9 @@ static int atlas_read_measurement(struct atlas_data *data, int reg, __be32 *val)
int suspended = pm_runtime_suspended(dev);
int ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
return ret;
- }
if (suspended)
msleep(data->chip->delay);
@@ -640,7 +636,7 @@ static int atlas_probe(struct i2c_client *client,
indio_dev->modes = INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE;
trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d",
- indio_dev->name, indio_dev->id);
+ indio_dev->name, iio_device_id(indio_dev));
if (!trig)
return -ENOMEM;
@@ -741,7 +737,6 @@ static int atlas_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
return atlas_set_powermode(data, 0);
}
diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c
index 29c0dfa4702b..74cf89c82c0a 100644
--- a/drivers/iio/chemical/bme680_i2c.c
+++ b/drivers/iio/chemical/bme680_i2c.c
@@ -11,7 +11,6 @@
* Note: SDO pin cannot be left floating otherwise I2C address
* will be undefined.
*/
-#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -42,12 +41,6 @@ static const struct i2c_device_id bme680_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, bme680_i2c_id);
-static const struct acpi_device_id bme680_acpi_match[] = {
- {"BME0680", 0},
- {},
-};
-MODULE_DEVICE_TABLE(acpi, bme680_acpi_match);
-
static const struct of_device_id bme680_of_i2c_match[] = {
{ .compatible = "bosch,bme680", },
{},
@@ -57,7 +50,6 @@ MODULE_DEVICE_TABLE(of, bme680_of_i2c_match);
static struct i2c_driver bme680_i2c_driver = {
.driver = {
.name = "bme680_i2c",
- .acpi_match_table = ACPI_PTR(bme680_acpi_match),
.of_match_table = bme680_of_i2c_match,
},
.probe = bme680_i2c_probe,
diff --git a/drivers/iio/chemical/bme680_spi.c b/drivers/iio/chemical/bme680_spi.c
index 6f56ad48cc40..cc579a7ac5ce 100644
--- a/drivers/iio/chemical/bme680_spi.c
+++ b/drivers/iio/chemical/bme680_spi.c
@@ -4,7 +4,6 @@
*
* Copyright (C) 2018 Himanshu Jha <himanshujha199640@gmail.com>
*/
-#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
@@ -145,12 +144,6 @@ static const struct spi_device_id bme680_spi_id[] = {
};
MODULE_DEVICE_TABLE(spi, bme680_spi_id);
-static const struct acpi_device_id bme680_acpi_match[] = {
- {"BME0680", 0},
- {},
-};
-MODULE_DEVICE_TABLE(acpi, bme680_acpi_match);
-
static const struct of_device_id bme680_of_spi_match[] = {
{ .compatible = "bosch,bme680", },
{},
@@ -160,7 +153,6 @@ MODULE_DEVICE_TABLE(of, bme680_of_spi_match);
static struct spi_driver bme680_spi_driver = {
.driver = {
.name = "bme680_spi",
- .acpi_match_table = ACPI_PTR(bme680_acpi_match),
.of_match_table = bme680_of_spi_match,
},
.probe = bme680_spi_probe,
diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c
index 886e96496dbf..847194fa1e46 100644
--- a/drivers/iio/chemical/ccs811.c
+++ b/drivers/iio/chemical/ccs811.c
@@ -491,7 +491,7 @@ static int ccs811_probe(struct i2c_client *client,
data->drdy_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->drdy_trig) {
ret = -ENOMEM;
goto err_poweroff;
diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c
index d89f117dd0ef..9fe6bbe9ee04 100644
--- a/drivers/iio/chemical/scd30_core.c
+++ b/drivers/iio/chemical/scd30_core.c
@@ -640,7 +640,8 @@ static int scd30_setup_trigger(struct iio_dev *indio_dev)
struct iio_trigger *trig;
int ret;
- trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, indio_dev->id);
+ trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
+ iio_device_id(indio_dev));
if (!trig) {
dev_err(dev, "failed to allocate trigger\n");
return -ENOMEM;
diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c
index 1029c457be15..2343d444604d 100644
--- a/drivers/iio/chemical/sgp30.c
+++ b/drivers/iio/chemical/sgp30.c
@@ -425,7 +425,7 @@ static int sgp_check_compat(struct sgp_data *data,
product = SGP_VERS_PRODUCT(data);
if (product != product_id) {
- dev_err(dev, "sensor reports a different product: 0x%04hx\n",
+ dev_err(dev, "sensor reports a different product: 0x%04x\n",
product);
return -ENODEV;
}
diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c
index 2ea9a5c4d846..d51314505115 100644
--- a/drivers/iio/chemical/sps30.c
+++ b/drivers/iio/chemical/sps30.c
@@ -3,11 +3,8 @@
* Sensirion SPS30 particulate matter sensor driver
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
- *
- * I2C slave address: 0x69
*/
-#include <asm/unaligned.h>
#include <linux/crc8.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -19,27 +16,14 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#define SPS30_CRC8_POLYNOMIAL 0x31
-/* max number of bytes needed to store PM measurements or serial string */
-#define SPS30_MAX_READ_SIZE 48
+#include "sps30.h"
+
/* sensor measures reliably up to 3000 ug / m3 */
#define SPS30_MAX_PM 3000
/* minimum and maximum self cleaning periods in seconds */
#define SPS30_AUTO_CLEANING_PERIOD_MIN 0
#define SPS30_AUTO_CLEANING_PERIOD_MAX 604800
-/* SPS30 commands */
-#define SPS30_START_MEAS 0x0010
-#define SPS30_STOP_MEAS 0x0104
-#define SPS30_RESET 0xd304
-#define SPS30_READ_DATA_READY_FLAG 0x0202
-#define SPS30_READ_DATA 0x0300
-#define SPS30_READ_SERIAL 0xd033
-#define SPS30_START_FAN_CLEANING 0x5607
-#define SPS30_AUTO_CLEANING_PERIOD 0x8004
-/* not a sensor command per se, used only to distinguish write from read */
-#define SPS30_READ_AUTO_CLEANING_PERIOD 0x8005
-
enum {
PM1,
PM2P5,
@@ -52,114 +36,9 @@ enum {
MEASURING,
};
-struct sps30_state {
- struct i2c_client *client;
- /*
- * Guards against concurrent access to sensor registers.
- * Must be held whenever sequence of commands is to be executed.
- */
- struct mutex lock;
- int state;
-};
-
-DECLARE_CRC8_TABLE(sps30_crc8_table);
-
-static int sps30_write_then_read(struct sps30_state *state, u8 *txbuf,
- int txsize, u8 *rxbuf, int rxsize)
-{
- int ret;
-
- /*
- * Sensor does not support repeated start so instead of
- * sending two i2c messages in a row we just send one by one.
- */
- ret = i2c_master_send(state->client, txbuf, txsize);
- if (ret != txsize)
- return ret < 0 ? ret : -EIO;
-
- if (!rxbuf)
- return 0;
-
- ret = i2c_master_recv(state->client, rxbuf, rxsize);
- if (ret != rxsize)
- return ret < 0 ? ret : -EIO;
-
- return 0;
-}
-
-static int sps30_do_cmd(struct sps30_state *state, u16 cmd, u8 *data, int size)
-{
- /*
- * Internally sensor stores measurements in a following manner:
- *
- * PM1: upper two bytes, crc8, lower two bytes, crc8
- * PM2P5: upper two bytes, crc8, lower two bytes, crc8
- * PM4: upper two bytes, crc8, lower two bytes, crc8
- * PM10: upper two bytes, crc8, lower two bytes, crc8
- *
- * What follows next are number concentration measurements and
- * typical particle size measurement which we omit.
- */
- u8 buf[SPS30_MAX_READ_SIZE] = { cmd >> 8, cmd };
- int i, ret = 0;
-
- switch (cmd) {
- case SPS30_START_MEAS:
- buf[2] = 0x03;
- buf[3] = 0x00;
- buf[4] = crc8(sps30_crc8_table, &buf[2], 2, CRC8_INIT_VALUE);
- ret = sps30_write_then_read(state, buf, 5, NULL, 0);
- break;
- case SPS30_STOP_MEAS:
- case SPS30_RESET:
- case SPS30_START_FAN_CLEANING:
- ret = sps30_write_then_read(state, buf, 2, NULL, 0);
- break;
- case SPS30_READ_AUTO_CLEANING_PERIOD:
- buf[0] = SPS30_AUTO_CLEANING_PERIOD >> 8;
- buf[1] = (u8)(SPS30_AUTO_CLEANING_PERIOD & 0xff);
- fallthrough;
- case SPS30_READ_DATA_READY_FLAG:
- case SPS30_READ_DATA:
- case SPS30_READ_SERIAL:
- /* every two data bytes are checksummed */
- size += size / 2;
- ret = sps30_write_then_read(state, buf, 2, buf, size);
- break;
- case SPS30_AUTO_CLEANING_PERIOD:
- buf[2] = data[0];
- buf[3] = data[1];
- buf[4] = crc8(sps30_crc8_table, &buf[2], 2, CRC8_INIT_VALUE);
- buf[5] = data[2];
- buf[6] = data[3];
- buf[7] = crc8(sps30_crc8_table, &buf[5], 2, CRC8_INIT_VALUE);
- ret = sps30_write_then_read(state, buf, 8, NULL, 0);
- break;
- }
-
- if (ret)
- return ret;
-
- /* validate received data and strip off crc bytes */
- for (i = 0; i < size; i += 3) {
- u8 crc = crc8(sps30_crc8_table, &buf[i], 2, CRC8_INIT_VALUE);
-
- if (crc != buf[i + 2]) {
- dev_err(&state->client->dev,
- "data integrity check failed\n");
- return -EIO;
- }
-
- *data++ = buf[i];
- *data++ = buf[i + 1];
- }
-
- return 0;
-}
-
-static s32 sps30_float_to_int_clamped(const u8 *fp)
+static s32 sps30_float_to_int_clamped(__be32 *fp)
{
- int val = get_unaligned_be32(fp);
+ int val = be32_to_cpup(fp);
int mantissa = val & GENMASK(22, 0);
/* this is fine since passed float is always non-negative */
int exp = val >> 23;
@@ -188,38 +67,35 @@ static s32 sps30_float_to_int_clamped(const u8 *fp)
static int sps30_do_meas(struct sps30_state *state, s32 *data, int size)
{
- int i, ret, tries = 5;
- u8 tmp[16];
+ int i, ret;
if (state->state == RESET) {
- ret = sps30_do_cmd(state, SPS30_START_MEAS, NULL, 0);
+ ret = state->ops->start_meas(state);
if (ret)
return ret;
state->state = MEASURING;
}
- while (tries--) {
- ret = sps30_do_cmd(state, SPS30_READ_DATA_READY_FLAG, tmp, 2);
- if (ret)
- return -EIO;
+ ret = state->ops->read_meas(state, (__be32 *)data, size);
+ if (ret)
+ return ret;
- /* new measurements ready to be read */
- if (tmp[1] == 1)
- break;
+ for (i = 0; i < size; i++)
+ data[i] = sps30_float_to_int_clamped((__be32 *)&data[i]);
- msleep_interruptible(300);
- }
+ return 0;
+}
- if (tries == -1)
- return -ETIMEDOUT;
+static int sps30_do_reset(struct sps30_state *state)
+{
+ int ret;
- ret = sps30_do_cmd(state, SPS30_READ_DATA, tmp, sizeof(int) * size);
+ ret = state->ops->reset(state);
if (ret)
return ret;
- for (i = 0; i < size; i++)
- data[i] = sps30_float_to_int_clamped(&tmp[4 * i]);
+ state->state = RESET;
return 0;
}
@@ -310,24 +186,6 @@ static int sps30_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
-static int sps30_do_cmd_reset(struct sps30_state *state)
-{
- int ret;
-
- ret = sps30_do_cmd(state, SPS30_RESET, NULL, 0);
- msleep(300);
- /*
- * Power-on-reset causes sensor to produce some glitch on i2c bus and
- * some controllers end up in error state. Recover simply by placing
- * some data on the bus, for example STOP_MEAS command, which
- * is NOP in this case.
- */
- sps30_do_cmd(state, SPS30_STOP_MEAS, NULL, 0);
- state->state = RESET;
-
- return ret;
-}
-
static ssize_t start_cleaning_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
@@ -340,7 +198,7 @@ static ssize_t start_cleaning_store(struct device *dev,
return -EINVAL;
mutex_lock(&state->lock);
- ret = sps30_do_cmd(state, SPS30_START_FAN_CLEANING, NULL, 0);
+ ret = state->ops->clean_fan(state);
mutex_unlock(&state->lock);
if (ret)
return ret;
@@ -349,31 +207,29 @@ static ssize_t start_cleaning_store(struct device *dev,
}
static ssize_t cleaning_period_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sps30_state *state = iio_priv(indio_dev);
- u8 tmp[4];
+ __be32 val;
int ret;
mutex_lock(&state->lock);
- ret = sps30_do_cmd(state, SPS30_READ_AUTO_CLEANING_PERIOD, tmp, 4);
+ ret = state->ops->read_cleaning_period(state, &val);
mutex_unlock(&state->lock);
if (ret)
return ret;
- return sprintf(buf, "%d\n", get_unaligned_be32(tmp));
+ return sprintf(buf, "%d\n", be32_to_cpu(val));
}
-static ssize_t cleaning_period_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static ssize_t cleaning_period_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sps30_state *state = iio_priv(indio_dev);
int val, ret;
- u8 tmp[4];
if (kstrtoint(buf, 0, &val))
return -EINVAL;
@@ -382,10 +238,8 @@ static ssize_t cleaning_period_store(struct device *dev,
(val > SPS30_AUTO_CLEANING_PERIOD_MAX))
return -EINVAL;
- put_unaligned_be32(val, tmp);
-
mutex_lock(&state->lock);
- ret = sps30_do_cmd(state, SPS30_AUTO_CLEANING_PERIOD, tmp, 0);
+ ret = state->ops->write_cleaning_period(state, cpu_to_be32(val));
if (ret) {
mutex_unlock(&state->lock);
return ret;
@@ -397,7 +251,7 @@ static ssize_t cleaning_period_store(struct device *dev,
* sensor requires reset in order to return up to date self cleaning
* period
*/
- ret = sps30_do_cmd_reset(state);
+ ret = sps30_do_reset(state);
if (ret)
dev_warn(dev,
"period changed but reads will return the old value\n");
@@ -411,9 +265,9 @@ static ssize_t cleaning_period_available_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return snprintf(buf, PAGE_SIZE, "[%d %d %d]\n",
- SPS30_AUTO_CLEANING_PERIOD_MIN, 1,
- SPS30_AUTO_CLEANING_PERIOD_MAX);
+ return sysfs_emit(buf, "[%d %d %d]\n",
+ SPS30_AUTO_CLEANING_PERIOD_MIN, 1,
+ SPS30_AUTO_CLEANING_PERIOD_MAX);
}
static IIO_DEVICE_ATTR_WO(start_cleaning, 0);
@@ -460,90 +314,65 @@ static const struct iio_chan_spec sps30_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(4),
};
-static void sps30_stop_meas(void *data)
+static void sps30_devm_stop_meas(void *data)
{
struct sps30_state *state = data;
- sps30_do_cmd(state, SPS30_STOP_MEAS, NULL, 0);
+ if (state->state == MEASURING)
+ state->ops->stop_meas(state);
}
static const unsigned long sps30_scan_masks[] = { 0x0f, 0x00 };
-static int sps30_probe(struct i2c_client *client)
+int sps30_probe(struct device *dev, const char *name, void *priv, const struct sps30_ops *ops)
{
struct iio_dev *indio_dev;
struct sps30_state *state;
- u8 buf[32];
int ret;
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
- return -EOPNOTSUPP;
-
- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*state));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*state));
if (!indio_dev)
return -ENOMEM;
+ dev_set_drvdata(dev, indio_dev);
+
state = iio_priv(indio_dev);
- i2c_set_clientdata(client, indio_dev);
- state->client = client;
- state->state = RESET;
+ state->dev = dev;
+ state->priv = priv;
+ state->ops = ops;
+ mutex_init(&state->lock);
+
indio_dev->info = &sps30_info;
- indio_dev->name = client->name;
+ indio_dev->name = name;
indio_dev->channels = sps30_channels;
indio_dev->num_channels = ARRAY_SIZE(sps30_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->available_scan_masks = sps30_scan_masks;
- mutex_init(&state->lock);
- crc8_populate_msb(sps30_crc8_table, SPS30_CRC8_POLYNOMIAL);
-
- ret = sps30_do_cmd_reset(state);
+ ret = sps30_do_reset(state);
if (ret) {
- dev_err(&client->dev, "failed to reset device\n");
+ dev_err(dev, "failed to reset device\n");
return ret;
}
- ret = sps30_do_cmd(state, SPS30_READ_SERIAL, buf, sizeof(buf));
+ ret = state->ops->show_info(state);
if (ret) {
- dev_err(&client->dev, "failed to read serial number\n");
+ dev_err(dev, "failed to read device info\n");
return ret;
}
- /* returned serial number is already NUL terminated */
- dev_info(&client->dev, "serial number: %s\n", buf);
- ret = devm_add_action_or_reset(&client->dev, sps30_stop_meas, state);
+ ret = devm_add_action_or_reset(dev, sps30_devm_stop_meas, state);
if (ret)
return ret;
- ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
sps30_trigger_handler, NULL);
if (ret)
return ret;
- return devm_iio_device_register(&client->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
-
-static const struct i2c_device_id sps30_id[] = {
- { "sps30" },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, sps30_id);
-
-static const struct of_device_id sps30_of_match[] = {
- { .compatible = "sensirion,sps30" },
- { }
-};
-MODULE_DEVICE_TABLE(of, sps30_of_match);
-
-static struct i2c_driver sps30_driver = {
- .driver = {
- .name = "sps30",
- .of_match_table = sps30_of_match,
- },
- .id_table = sps30_id,
- .probe_new = sps30_probe,
-};
-module_i2c_driver(sps30_driver);
+EXPORT_SYMBOL_GPL(sps30_probe);
MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor driver");
diff --git a/drivers/iio/chemical/sps30.h b/drivers/iio/chemical/sps30.h
new file mode 100644
index 000000000000..a58ee43cf45d
--- /dev/null
+++ b/drivers/iio/chemical/sps30.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SPS30_H
+#define _SPS30_H
+
+#include <linux/types.h>
+
+struct sps30_state;
+struct sps30_ops {
+ int (*start_meas)(struct sps30_state *state);
+ int (*stop_meas)(struct sps30_state *state);
+ int (*read_meas)(struct sps30_state *state, __be32 *meas, size_t num);
+ int (*reset)(struct sps30_state *state);
+ int (*clean_fan)(struct sps30_state *state);
+ int (*read_cleaning_period)(struct sps30_state *state, __be32 *period);
+ int (*write_cleaning_period)(struct sps30_state *state, __be32 period);
+ int (*show_info)(struct sps30_state *state);
+};
+
+struct sps30_state {
+ /* serialize access to the device */
+ struct mutex lock;
+ struct device *dev;
+ int state;
+ /*
+ * priv pointer is solely for serdev driver private data. We keep it
+ * here because driver_data inside dev has been already used for iio and
+ * struct serdev_device doesn't have one.
+ */
+ void *priv;
+ const struct sps30_ops *ops;
+};
+
+int sps30_probe(struct device *dev, const char *name, void *priv, const struct sps30_ops *ops);
+
+#endif
diff --git a/drivers/iio/chemical/sps30_i2c.c b/drivers/iio/chemical/sps30_i2c.c
new file mode 100644
index 000000000000..d33560ed7184
--- /dev/null
+++ b/drivers/iio/chemical/sps30_i2c.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sensirion SPS30 particulate matter sensor i2c driver
+ *
+ * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com>
+ *
+ * I2C slave address: 0x69
+ */
+#include <asm/unaligned.h>
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include "sps30.h"
+
+#define SPS30_I2C_CRC8_POLYNOMIAL 0x31
+/* max number of bytes needed to store PM measurements or serial string */
+#define SPS30_I2C_MAX_BUF_SIZE 48
+
+DECLARE_CRC8_TABLE(sps30_i2c_crc8_table);
+
+#define SPS30_I2C_START_MEAS 0x0010
+#define SPS30_I2C_STOP_MEAS 0x0104
+#define SPS30_I2C_READ_MEAS 0x0300
+#define SPS30_I2C_MEAS_READY 0x0202
+#define SPS30_I2C_RESET 0xd304
+#define SPS30_I2C_CLEAN_FAN 0x5607
+#define SPS30_I2C_PERIOD 0x8004
+#define SPS30_I2C_READ_SERIAL 0xd033
+#define SPS30_I2C_READ_VERSION 0xd100
+
+static int sps30_i2c_xfer(struct sps30_state *state, unsigned char *txbuf, size_t txsize,
+ unsigned char *rxbuf, size_t rxsize)
+{
+ struct i2c_client *client = to_i2c_client(state->dev);
+ int ret;
+
+ /*
+ * Sensor does not support repeated start so instead of
+ * sending two i2c messages in a row we just send one by one.
+ */
+ ret = i2c_master_send(client, txbuf, txsize);
+ if (ret < 0)
+ return ret;
+ if (ret != txsize)
+ return -EIO;
+
+ if (!rxsize)
+ return 0;
+
+ ret = i2c_master_recv(client, rxbuf, rxsize);
+ if (ret < 0)
+ return ret;
+ if (ret != rxsize)
+ return -EIO;
+
+ return 0;
+}
+
+static int sps30_i2c_command(struct sps30_state *state, u16 cmd, void *arg, size_t arg_size,
+ void *rsp, size_t rsp_size)
+{
+ /*
+ * Internally sensor stores measurements in a following manner:
+ *
+ * PM1: upper two bytes, crc8, lower two bytes, crc8
+ * PM2P5: upper two bytes, crc8, lower two bytes, crc8
+ * PM4: upper two bytes, crc8, lower two bytes, crc8
+ * PM10: upper two bytes, crc8, lower two bytes, crc8
+ *
+ * What follows next are number concentration measurements and
+ * typical particle size measurement which we omit.
+ */
+ unsigned char buf[SPS30_I2C_MAX_BUF_SIZE];
+ unsigned char *tmp;
+ unsigned char crc;
+ size_t i;
+ int ret;
+
+ put_unaligned_be16(cmd, buf);
+ i = 2;
+
+ if (rsp) {
+ /* each two bytes are followed by a crc8 */
+ rsp_size += rsp_size / 2;
+ } else {
+ tmp = arg;
+
+ while (arg_size) {
+ buf[i] = *tmp++;
+ buf[i + 1] = *tmp++;
+ buf[i + 2] = crc8(sps30_i2c_crc8_table, buf + i, 2, CRC8_INIT_VALUE);
+ arg_size -= 2;
+ i += 3;
+ }
+ }
+
+ ret = sps30_i2c_xfer(state, buf, i, buf, rsp_size);
+ if (ret)
+ return ret;
+
+ /* validate received data and strip off crc bytes */
+ tmp = rsp;
+ for (i = 0; i < rsp_size; i += 3) {
+ crc = crc8(sps30_i2c_crc8_table, buf + i, 2, CRC8_INIT_VALUE);
+ if (crc != buf[i + 2]) {
+ dev_err(state->dev, "data integrity check failed\n");
+ return -EIO;
+ }
+
+ *tmp++ = buf[i];
+ *tmp++ = buf[i + 1];
+ }
+
+ return 0;
+}
+
+static int sps30_i2c_start_meas(struct sps30_state *state)
+{
+ /* request BE IEEE754 formatted data */
+ unsigned char buf[] = { 0x03, 0x00 };
+
+ return sps30_i2c_command(state, SPS30_I2C_START_MEAS, buf, sizeof(buf), NULL, 0);
+}
+
+static int sps30_i2c_stop_meas(struct sps30_state *state)
+{
+ return sps30_i2c_command(state, SPS30_I2C_STOP_MEAS, NULL, 0, NULL, 0);
+}
+
+static int sps30_i2c_reset(struct sps30_state *state)
+{
+ int ret;
+
+ ret = sps30_i2c_command(state, SPS30_I2C_RESET, NULL, 0, NULL, 0);
+ msleep(500);
+ /*
+ * Power-on-reset causes sensor to produce some glitch on i2c bus and
+ * some controllers end up in error state. Recover simply by placing
+ * some data on the bus, for example STOP_MEAS command, which
+ * is NOP in this case.
+ */
+ sps30_i2c_stop_meas(state);
+
+ return ret;
+}
+
+static bool sps30_i2c_meas_ready(struct sps30_state *state)
+{
+ unsigned char buf[2];
+ int ret;
+
+ ret = sps30_i2c_command(state, SPS30_I2C_MEAS_READY, NULL, 0, buf, sizeof(buf));
+ if (ret)
+ return false;
+
+ return buf[1];
+}
+
+static int sps30_i2c_read_meas(struct sps30_state *state, __be32 *meas, size_t num)
+{
+ /* measurements are ready within a second */
+ if (msleep_interruptible(1000))
+ return -EINTR;
+
+ if (!sps30_i2c_meas_ready(state))
+ return -ETIMEDOUT;
+
+ return sps30_i2c_command(state, SPS30_I2C_READ_MEAS, NULL, 0, meas, sizeof(num) * num);
+}
+
+static int sps30_i2c_clean_fan(struct sps30_state *state)
+{
+ return sps30_i2c_command(state, SPS30_I2C_CLEAN_FAN, NULL, 0, NULL, 0);
+}
+
+static int sps30_i2c_read_cleaning_period(struct sps30_state *state, __be32 *period)
+{
+ return sps30_i2c_command(state, SPS30_I2C_PERIOD, NULL, 0, period, sizeof(*period));
+}
+
+static int sps30_i2c_write_cleaning_period(struct sps30_state *state, __be32 period)
+{
+ return sps30_i2c_command(state, SPS30_I2C_PERIOD, &period, sizeof(period), NULL, 0);
+}
+
+static int sps30_i2c_show_info(struct sps30_state *state)
+{
+ /* extra nul just in case */
+ unsigned char buf[32 + 1] = { 0x00 };
+ int ret;
+
+ ret = sps30_i2c_command(state, SPS30_I2C_READ_SERIAL, NULL, 0, buf, sizeof(buf) - 1);
+ if (ret)
+ return ret;
+
+ dev_info(state->dev, "serial number: %s\n", buf);
+
+ ret = sps30_i2c_command(state, SPS30_I2C_READ_VERSION, NULL, 0, buf, 2);
+ if (ret)
+ return ret;
+
+ dev_info(state->dev, "fw version: %u.%u\n", buf[0], buf[1]);
+
+ return 0;
+}
+
+static const struct sps30_ops sps30_i2c_ops = {
+ .start_meas = sps30_i2c_start_meas,
+ .stop_meas = sps30_i2c_stop_meas,
+ .read_meas = sps30_i2c_read_meas,
+ .reset = sps30_i2c_reset,
+ .clean_fan = sps30_i2c_clean_fan,
+ .read_cleaning_period = sps30_i2c_read_cleaning_period,
+ .write_cleaning_period = sps30_i2c_write_cleaning_period,
+ .show_info = sps30_i2c_show_info,
+};
+
+static int sps30_i2c_probe(struct i2c_client *client)
+{
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -EOPNOTSUPP;
+
+ crc8_populate_msb(sps30_i2c_crc8_table, SPS30_I2C_CRC8_POLYNOMIAL);
+
+ return sps30_probe(&client->dev, client->name, NULL, &sps30_i2c_ops);
+}
+
+static const struct i2c_device_id sps30_i2c_id[] = {
+ { "sps30" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, sps30_i2c_id);
+
+static const struct of_device_id sps30_i2c_of_match[] = {
+ { .compatible = "sensirion,sps30" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sps30_i2c_of_match);
+
+static struct i2c_driver sps30_i2c_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = sps30_i2c_of_match,
+ },
+ .id_table = sps30_i2c_id,
+ .probe_new = sps30_i2c_probe,
+};
+module_i2c_driver(sps30_i2c_driver);
+
+MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
+MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor i2c driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/chemical/sps30_serial.c b/drivers/iio/chemical/sps30_serial.c
new file mode 100644
index 000000000000..3f311d50087c
--- /dev/null
+++ b/drivers/iio/chemical/sps30_serial.c
@@ -0,0 +1,431 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sensirion SPS30 particulate matter sensor serial driver
+ *
+ * Copyright (c) 2021 Tomasz Duszynski <tomasz.duszynski@octakon.com>
+ */
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/iio/iio.h>
+#include <linux/minmax.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/serdev.h>
+#include <linux/types.h>
+
+#include "sps30.h"
+
+#define SPS30_SERIAL_DEV_NAME "sps30"
+
+#define SPS30_SERIAL_SOF_EOF 0x7e
+#define SPS30_SERIAL_TIMEOUT msecs_to_jiffies(20)
+#define SPS30_SERIAL_MAX_BUF_SIZE 263
+#define SPS30_SERIAL_ESCAPE_CHAR 0x7d
+
+#define SPS30_SERIAL_FRAME_MIN_SIZE 7
+#define SPS30_SERIAL_FRAME_ADR_OFFSET 1
+#define SPS30_SERIAL_FRAME_CMD_OFFSET 2
+#define SPS30_SERIAL_FRAME_MOSI_LEN_OFFSET 3
+#define SPS30_SERIAL_FRAME_MISO_STATE_OFFSET 3
+#define SPS30_SERIAL_FRAME_MISO_LEN_OFFSET 4
+#define SPS30_SERIAL_FRAME_MISO_DATA_OFFSET 5
+
+#define SPS30_SERIAL_START_MEAS 0x00
+#define SPS30_SERIAL_STOP_MEAS 0x01
+#define SPS30_SERIAL_READ_MEAS 0x03
+#define SPS30_SERIAL_RESET 0xd3
+#define SPS30_SERIAL_CLEAN_FAN 0x56
+#define SPS30_SERIAL_PERIOD 0x80
+#define SPS30_SERIAL_DEV_INFO 0xd0
+#define SPS30_SERIAL_READ_VERSION 0xd1
+
+struct sps30_serial_priv {
+ struct completion new_frame;
+ unsigned char buf[SPS30_SERIAL_MAX_BUF_SIZE];
+ size_t num;
+ bool escaped;
+ bool done;
+};
+
+static int sps30_serial_xfer(struct sps30_state *state, const unsigned char *buf, size_t size)
+{
+ struct serdev_device *serdev = to_serdev_device(state->dev);
+ struct sps30_serial_priv *priv = state->priv;
+ int ret;
+
+ priv->num = 0;
+ priv->escaped = false;
+ priv->done = false;
+
+ ret = serdev_device_write(serdev, buf, size, SPS30_SERIAL_TIMEOUT);
+ if (ret < 0)
+ return ret;
+ if (ret != size)
+ return -EIO;
+
+ ret = wait_for_completion_interruptible_timeout(&priv->new_frame, SPS30_SERIAL_TIMEOUT);
+ if (ret < 0)
+ return ret;
+ if (!ret)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static const struct {
+ unsigned char byte;
+ unsigned char byte2;
+} sps30_serial_bytes[] = {
+ { 0x11, 0x31 },
+ { 0x13, 0x33 },
+ { 0x7e, 0x5e },
+ { 0x7d, 0x5d },
+};
+
+static int sps30_serial_put_byte(unsigned char *buf, unsigned char byte)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sps30_serial_bytes); i++) {
+ if (sps30_serial_bytes[i].byte != byte)
+ continue;
+
+ buf[0] = SPS30_SERIAL_ESCAPE_CHAR;
+ buf[1] = sps30_serial_bytes[i].byte2;
+
+ return 2;
+ }
+
+ buf[0] = byte;
+
+ return 1;
+}
+
+static char sps30_serial_get_byte(bool escaped, unsigned char byte2)
+{
+ int i;
+
+ if (!escaped)
+ return byte2;
+
+ for (i = 0; i < ARRAY_SIZE(sps30_serial_bytes); i++) {
+ if (sps30_serial_bytes[i].byte2 != byte2)
+ continue;
+
+ return sps30_serial_bytes[i].byte;
+ }
+
+ return 0;
+}
+
+static unsigned char sps30_serial_calc_chksum(const unsigned char *buf, size_t num)
+{
+ unsigned int chksum = 0;
+ size_t i;
+
+ for (i = 0; i < num; i++)
+ chksum += buf[i];
+
+ return ~chksum;
+}
+
+static int sps30_serial_prep_frame(unsigned char *buf, unsigned char cmd,
+ const unsigned char *arg, size_t arg_size)
+{
+ unsigned char chksum;
+ int num = 0;
+ size_t i;
+
+ buf[num++] = SPS30_SERIAL_SOF_EOF;
+ buf[num++] = 0;
+ num += sps30_serial_put_byte(buf + num, cmd);
+ num += sps30_serial_put_byte(buf + num, arg_size);
+
+ for (i = 0; i < arg_size; i++)
+ num += sps30_serial_put_byte(buf + num, arg[i]);
+
+ /* SOF isn't checksummed */
+ chksum = sps30_serial_calc_chksum(buf + 1, num - 1);
+ num += sps30_serial_put_byte(buf + num, chksum);
+ buf[num++] = SPS30_SERIAL_SOF_EOF;
+
+ return num;
+}
+
+static bool sps30_serial_frame_valid(struct sps30_state *state, const unsigned char *buf)
+{
+ struct sps30_serial_priv *priv = state->priv;
+ unsigned char chksum;
+
+ if ((priv->num < SPS30_SERIAL_FRAME_MIN_SIZE) ||
+ (priv->num != SPS30_SERIAL_FRAME_MIN_SIZE +
+ priv->buf[SPS30_SERIAL_FRAME_MISO_LEN_OFFSET])) {
+ dev_err(state->dev, "frame has invalid number of bytes\n");
+ return false;
+ }
+
+ if ((priv->buf[SPS30_SERIAL_FRAME_ADR_OFFSET] != buf[SPS30_SERIAL_FRAME_ADR_OFFSET]) ||
+ (priv->buf[SPS30_SERIAL_FRAME_CMD_OFFSET] != buf[SPS30_SERIAL_FRAME_CMD_OFFSET])) {
+ dev_err(state->dev, "frame has wrong ADR and CMD bytes\n");
+ return false;
+ }
+
+ if (priv->buf[SPS30_SERIAL_FRAME_MISO_STATE_OFFSET]) {
+ dev_err(state->dev, "frame with non-zero state received (0x%02x)\n",
+ priv->buf[SPS30_SERIAL_FRAME_MISO_STATE_OFFSET]);
+ return false;
+ }
+
+ /* SOF, checksum and EOF are not checksummed */
+ chksum = sps30_serial_calc_chksum(priv->buf + 1, priv->num - 3);
+ if (priv->buf[priv->num - 2] != chksum) {
+ dev_err(state->dev, "frame integrity check failed\n");
+ return false;
+ }
+
+ return true;
+}
+
+static int sps30_serial_command(struct sps30_state *state, unsigned char cmd,
+ const void *arg, size_t arg_size, void *rsp, size_t rsp_size)
+{
+ struct sps30_serial_priv *priv = state->priv;
+ unsigned char buf[SPS30_SERIAL_MAX_BUF_SIZE];
+ int ret, size;
+
+ size = sps30_serial_prep_frame(buf, cmd, arg, arg_size);
+ ret = sps30_serial_xfer(state, buf, size);
+ if (ret)
+ return ret;
+
+ if (!sps30_serial_frame_valid(state, buf))
+ return -EIO;
+
+ if (rsp) {
+ rsp_size = min_t(size_t, priv->buf[SPS30_SERIAL_FRAME_MISO_LEN_OFFSET], rsp_size);
+ memcpy(rsp, &priv->buf[SPS30_SERIAL_FRAME_MISO_DATA_OFFSET], rsp_size);
+ }
+
+ return rsp_size;
+}
+
+static int sps30_serial_receive_buf(struct serdev_device *serdev,
+ const unsigned char *buf, size_t size)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev);
+ struct sps30_serial_priv *priv;
+ struct sps30_state *state;
+ unsigned char byte;
+ size_t i;
+
+ if (!indio_dev)
+ return 0;
+
+ state = iio_priv(indio_dev);
+ priv = state->priv;
+
+ /* just in case device put some unexpected data on the bus */
+ if (priv->done)
+ return size;
+
+ /* wait for the start of frame */
+ if (!priv->num && size && buf[0] != SPS30_SERIAL_SOF_EOF)
+ return 1;
+
+ if (priv->num + size >= ARRAY_SIZE(priv->buf))
+ size = ARRAY_SIZE(priv->buf) - priv->num;
+
+ for (i = 0; i < size; i++) {
+ byte = buf[i];
+ /* remove stuffed bytes on-the-fly */
+ if (byte == SPS30_SERIAL_ESCAPE_CHAR) {
+ priv->escaped = true;
+ continue;
+ }
+
+ byte = sps30_serial_get_byte(priv->escaped, byte);
+ if (priv->escaped && !byte)
+ dev_warn(state->dev, "unrecognized escaped char (0x%02x)\n", byte);
+
+ priv->buf[priv->num++] = byte;
+
+ /* EOF received */
+ if (!priv->escaped && byte == SPS30_SERIAL_SOF_EOF) {
+ if (priv->num < SPS30_SERIAL_FRAME_MIN_SIZE)
+ continue;
+
+ priv->done = true;
+ complete(&priv->new_frame);
+ i++;
+ break;
+ }
+
+ priv->escaped = false;
+ }
+
+ return i;
+}
+
+static const struct serdev_device_ops sps30_serial_device_ops = {
+ .receive_buf = sps30_serial_receive_buf,
+ .write_wakeup = serdev_device_write_wakeup,
+};
+
+static int sps30_serial_start_meas(struct sps30_state *state)
+{
+ /* request BE IEEE754 formatted data */
+ unsigned char buf[] = { 0x01, 0x03 };
+
+ return sps30_serial_command(state, SPS30_SERIAL_START_MEAS, buf, sizeof(buf), NULL, 0);
+}
+
+static int sps30_serial_stop_meas(struct sps30_state *state)
+{
+ return sps30_serial_command(state, SPS30_SERIAL_STOP_MEAS, NULL, 0, NULL, 0);
+}
+
+static int sps30_serial_reset(struct sps30_state *state)
+{
+ int ret;
+
+ ret = sps30_serial_command(state, SPS30_SERIAL_RESET, NULL, 0, NULL, 0);
+ msleep(500);
+
+ return ret;
+}
+
+static int sps30_serial_read_meas(struct sps30_state *state, __be32 *meas, size_t num)
+{
+ int ret;
+
+ /* measurements are ready within a second */
+ if (msleep_interruptible(1000))
+ return -EINTR;
+
+ ret = sps30_serial_command(state, SPS30_SERIAL_READ_MEAS, NULL, 0, meas, num * sizeof(num));
+ if (ret < 0)
+ return ret;
+ /* if measurements aren't ready sensor returns empty frame */
+ if (ret == SPS30_SERIAL_FRAME_MIN_SIZE)
+ return -ETIMEDOUT;
+ if (ret != num * sizeof(*meas))
+ return -EIO;
+
+ return 0;
+}
+
+static int sps30_serial_clean_fan(struct sps30_state *state)
+{
+ return sps30_serial_command(state, SPS30_SERIAL_CLEAN_FAN, NULL, 0, NULL, 0);
+}
+
+static int sps30_serial_read_cleaning_period(struct sps30_state *state, __be32 *period)
+{
+ unsigned char buf[] = { 0x00 };
+ int ret;
+
+ ret = sps30_serial_command(state, SPS30_SERIAL_PERIOD, buf, sizeof(buf),
+ period, sizeof(*period));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(*period))
+ return -EIO;
+
+ return 0;
+}
+
+static int sps30_serial_write_cleaning_period(struct sps30_state *state, __be32 period)
+{
+ unsigned char buf[5] = { 0x00 };
+
+ memcpy(buf + 1, &period, sizeof(period));
+
+ return sps30_serial_command(state, SPS30_SERIAL_PERIOD, buf, sizeof(buf), NULL, 0);
+}
+
+static int sps30_serial_show_info(struct sps30_state *state)
+{
+ /*
+ * tell device do return serial number and add extra nul byte just in case
+ * serial number isn't a valid string
+ */
+ unsigned char buf[32 + 1] = { 0x03 };
+ struct device *dev = state->dev;
+ int ret;
+
+ ret = sps30_serial_command(state, SPS30_SERIAL_DEV_INFO, buf, 1, buf, sizeof(buf) - 1);
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(buf) - 1)
+ return -EIO;
+
+ dev_info(dev, "serial number: %s\n", buf);
+
+ ret = sps30_serial_command(state, SPS30_SERIAL_READ_VERSION, NULL, 0, buf, sizeof(buf) - 1);
+ if (ret < 0)
+ return ret;
+ if (ret < 2)
+ return -EIO;
+
+ dev_info(dev, "fw version: %u.%u\n", buf[0], buf[1]);
+
+ return 0;
+}
+
+static const struct sps30_ops sps30_serial_ops = {
+ .start_meas = sps30_serial_start_meas,
+ .stop_meas = sps30_serial_stop_meas,
+ .read_meas = sps30_serial_read_meas,
+ .reset = sps30_serial_reset,
+ .clean_fan = sps30_serial_clean_fan,
+ .read_cleaning_period = sps30_serial_read_cleaning_period,
+ .write_cleaning_period = sps30_serial_write_cleaning_period,
+ .show_info = sps30_serial_show_info,
+};
+
+static int sps30_serial_probe(struct serdev_device *serdev)
+{
+ struct device *dev = &serdev->dev;
+ struct sps30_serial_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ init_completion(&priv->new_frame);
+ serdev_device_set_client_ops(serdev, &sps30_serial_device_ops);
+
+ ret = devm_serdev_device_open(dev, serdev);
+ if (ret)
+ return ret;
+
+ serdev_device_set_baudrate(serdev, 115200);
+ serdev_device_set_flow_control(serdev, false);
+
+ ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
+ if (ret)
+ return ret;
+
+ return sps30_probe(dev, SPS30_SERIAL_DEV_NAME, priv, &sps30_serial_ops);
+}
+
+static const struct of_device_id sps30_serial_of_match[] = {
+ { .compatible = "sensirion,sps30" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sps30_serial_of_match);
+
+static struct serdev_device_driver sps30_serial_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = sps30_serial_of_match,
+ },
+ .probe = sps30_serial_probe,
+};
+module_serdev_device_driver(sps30_serial_driver);
+
+MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");
+MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor serial driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
index cb52b4fd6bf7..043f199e7bc6 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
@@ -3,18 +3,12 @@
* HID Sensors Driver
* Copyright (c) 2012, Intel Corporation.
*/
-#include <linux/device.h>
-#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
#include <linux/kernel.h>
-#include <linux/slab.h>
#include <linux/time.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
#define HZ_PER_MHZ 1000000L
@@ -176,7 +170,7 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st)
return value;
}
-EXPORT_SYMBOL(hid_sensor_read_poll_value);
+EXPORT_SYMBOL_NS(hid_sensor_read_poll_value, IIO_HID_ATTRIBUTES);
int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
int *val1, int *val2)
@@ -203,7 +197,7 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
return IIO_VAL_INT_PLUS_MICRO;
}
-EXPORT_SYMBOL(hid_sensor_read_samp_freq_value);
+EXPORT_SYMBOL_NS(hid_sensor_read_samp_freq_value, IIO_HID);
int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
int val1, int val2)
@@ -238,7 +232,7 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
return 0;
}
-EXPORT_SYMBOL(hid_sensor_write_samp_freq_value);
+EXPORT_SYMBOL_NS(hid_sensor_write_samp_freq_value, IIO_HID);
int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st,
int *val1, int *val2)
@@ -261,7 +255,7 @@ int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st,
return IIO_VAL_INT_PLUS_MICRO;
}
-EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value);
+EXPORT_SYMBOL_NS(hid_sensor_read_raw_hyst_value, IIO_HID);
int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1,
int *val2)
@@ -283,7 +277,7 @@ int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1,
return IIO_VAL_INT_PLUS_MICRO;
}
-EXPORT_SYMBOL(hid_sensor_read_raw_hyst_rel_value);
+EXPORT_SYMBOL_NS(hid_sensor_read_raw_hyst_rel_value, IIO_HID);
int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
@@ -315,7 +309,7 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
return 0;
}
-EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value);
+EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_value, IIO_HID);
int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st,
int val1, int val2)
@@ -346,7 +340,7 @@ int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st,
return 0;
}
-EXPORT_SYMBOL(hid_sensor_write_raw_hyst_rel_value);
+EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_rel_value, IIO_HID);
/*
* This fuction applies the unit exponent to the scale.
@@ -430,14 +424,14 @@ int hid_sensor_format_scale(u32 usage_id,
return IIO_VAL_INT_PLUS_NANO;
}
-EXPORT_SYMBOL(hid_sensor_format_scale);
+EXPORT_SYMBOL_NS(hid_sensor_format_scale, IIO_HID);
int64_t hid_sensor_convert_timestamp(struct hid_sensor_common *st,
int64_t raw_value)
{
return st->timestamp_ns_scale * raw_value;
}
-EXPORT_SYMBOL(hid_sensor_convert_timestamp);
+EXPORT_SYMBOL_NS(hid_sensor_convert_timestamp, IIO_HID);
static
int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev,
@@ -484,7 +478,7 @@ int hid_sensor_get_report_latency(struct hid_sensor_common *st)
return value;
}
-EXPORT_SYMBOL(hid_sensor_get_report_latency);
+EXPORT_SYMBOL_NS(hid_sensor_get_report_latency, IIO_HID_ATTRIBUTES);
int hid_sensor_set_report_latency(struct hid_sensor_common *st, int latency_ms)
{
@@ -492,13 +486,13 @@ int hid_sensor_set_report_latency(struct hid_sensor_common *st, int latency_ms)
st->report_latency.index,
sizeof(latency_ms), &latency_ms);
}
-EXPORT_SYMBOL(hid_sensor_set_report_latency);
+EXPORT_SYMBOL_NS(hid_sensor_set_report_latency, IIO_HID_ATTRIBUTES);
bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st)
{
return st->report_latency.index > 0 && st->report_latency.report_id > 0;
}
-EXPORT_SYMBOL(hid_sensor_batch_mode_supported);
+EXPORT_SYMBOL_NS(hid_sensor_batch_mode_supported, IIO_HID_ATTRIBUTES);
int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
@@ -590,7 +584,7 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
return 0;
}
-EXPORT_SYMBOL(hid_sensor_parse_common_attributes);
+EXPORT_SYMBOL_NS(hid_sensor_parse_common_attributes, IIO_HID);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
MODULE_DESCRIPTION("HID Sensor common attribute processing");
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 95ddccb44f1c..a4ec11a3b68a 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -6,16 +6,13 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/hid-sensor-hub.h>
+#include <linux/workqueue.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
-#include <linux/iio/buffer.h>
#include <linux/iio/sysfs.h>
#include "hid-sensor-trigger.h"
@@ -150,7 +147,7 @@ static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
return 0;
}
-EXPORT_SYMBOL(hid_sensor_power_state);
+EXPORT_SYMBOL_NS(hid_sensor_power_state, IIO_HID);
int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
{
@@ -163,18 +160,15 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
if (state) {
atomic_inc(&st->user_requested_state);
- ret = pm_runtime_get_sync(&st->pdev->dev);
+ ret = pm_runtime_resume_and_get(&st->pdev->dev);
} else {
atomic_dec(&st->user_requested_state);
pm_runtime_mark_last_busy(&st->pdev->dev);
pm_runtime_use_autosuspend(&st->pdev->dev);
ret = pm_runtime_put_autosuspend(&st->pdev->dev);
}
- if (ret < 0) {
- if (state)
- pm_runtime_put_noidle(&st->pdev->dev);
+ if (ret < 0)
return ret;
- }
return 0;
#else
@@ -222,14 +216,13 @@ void hid_sensor_remove_trigger(struct iio_dev *indio_dev,
pm_runtime_disable(&attrb->pdev->dev);
pm_runtime_set_suspended(&attrb->pdev->dev);
- pm_runtime_put_noidle(&attrb->pdev->dev);
cancel_work_sync(&attrb->work);
iio_trigger_unregister(attrb->trigger);
iio_trigger_free(attrb->trigger);
iio_triggered_buffer_cleanup(indio_dev);
}
-EXPORT_SYMBOL(hid_sensor_remove_trigger);
+EXPORT_SYMBOL_NS(hid_sensor_remove_trigger, IIO_HID);
static const struct iio_trigger_ops hid_sensor_trigger_ops = {
.set_trigger_state = &hid_sensor_data_rdy_trigger_set_state,
@@ -256,7 +249,7 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
}
trig = iio_trigger_alloc(indio_dev->dev.parent,
- "%s-dev%d", name, indio_dev->id);
+ "%s-dev%d", name, iio_device_id(indio_dev));
if (trig == NULL) {
dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
ret = -ENOMEM;
@@ -295,7 +288,7 @@ error_triggered_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
-EXPORT_SYMBOL(hid_sensor_setup_trigger);
+EXPORT_SYMBOL_NS(hid_sensor_setup_trigger, IIO_HID);
static int __maybe_unused hid_sensor_suspend(struct device *dev)
{
@@ -325,8 +318,9 @@ const struct dev_pm_ops hid_sensor_pm_ops = {
SET_RUNTIME_PM_OPS(hid_sensor_suspend,
hid_sensor_runtime_resume, NULL)
};
-EXPORT_SYMBOL(hid_sensor_pm_ops);
+EXPORT_SYMBOL_NS(hid_sensor_pm_ops, IIO_HID);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
MODULE_DESCRIPTION("HID Sensor trigger processing");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HID_ATTRIBUTES);
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
index bb45cc89e551..f94fca4f1edf 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
@@ -9,6 +9,9 @@
#include <linux/pm.h>
#include <linux/pm_runtime.h>
+struct hid_sensor_common;
+struct iio_dev;
+
extern const struct dev_pm_ops hid_sensor_pm_ops;
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
diff --git a/drivers/iio/common/scmi_sensors/Makefile b/drivers/iio/common/scmi_sensors/Makefile
index f13140a2575a..645e0fce1a73 100644
--- a/drivers/iio/common/scmi_sensors/Makefile
+++ b/drivers/iio/common/scmi_sensors/Makefile
@@ -1,4 +1,4 @@
-# SPDX - License - Identifier : GPL - 2.0 - only
+# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the IIO over SCMI
#
diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c
index 141e8aa6911e..7cf2bf282cef 100644
--- a/drivers/iio/common/scmi_sensors/scmi_iio.c
+++ b/drivers/iio/common/scmi_sensors/scmi_iio.c
@@ -525,7 +525,6 @@ scmi_alloc_iiodev(struct scmi_device *sdev,
return ERR_PTR(-ENOMEM);
iiodev->modes = INDIO_DIRECT_MODE;
- iiodev->dev.parent = dev;
sensor = iio_priv(iiodev);
sensor->sensor_ops = ops;
sensor->ph = ph;
diff --git a/drivers/iio/dac/ad5766.c b/drivers/iio/dac/ad5766.c
index 79837a4b3a41..3104ec32dfac 100644
--- a/drivers/iio/dac/ad5766.c
+++ b/drivers/iio/dac/ad5766.c
@@ -597,8 +597,6 @@ static int ad5766_probe(struct spi_device *spi)
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->info = &ad5766_info;
- indio_dev->dev.parent = &spi->dev;
- indio_dev->dev.of_node = spi->dev.of_node;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c
index a5b0a52bf86e..dd2e306824e7 100644
--- a/drivers/iio/dac/stm32-dac.c
+++ b/drivers/iio/dac/stm32-dac.c
@@ -69,9 +69,8 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch,
}
if (enable) {
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0) {
- pm_runtime_put_noidle(dev);
mutex_unlock(&dac->lock);
return ret;
}
diff --git a/drivers/iio/dummy/Kconfig b/drivers/iio/dummy/Kconfig
index 5c5c2f8c55f3..1f46cb9e51b7 100644
--- a/drivers/iio/dummy/Kconfig
+++ b/drivers/iio/dummy/Kconfig
@@ -34,6 +34,7 @@ config IIO_SIMPLE_DUMMY_BUFFER
select IIO_BUFFER
select IIO_TRIGGER
select IIO_KFIFO_BUF
+ select IIO_TRIGGERED_BUFFER
help
Add buffered data capture to the simple dummy driver.
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c
index 1462a6a5bc6d..3d9eba716b69 100644
--- a/drivers/iio/frequency/adf4350.c
+++ b/drivers/iio/frequency/adf4350.c
@@ -563,8 +563,10 @@ static int adf4350_probe(struct spi_device *spi)
st->lock_detect_gpiod = devm_gpiod_get_optional(&spi->dev, NULL,
GPIOD_IN);
- if (IS_ERR(st->lock_detect_gpiod))
- return PTR_ERR(st->lock_detect_gpiod);
+ if (IS_ERR(st->lock_detect_gpiod)) {
+ ret = PTR_ERR(st->lock_detect_gpiod);
+ goto error_disable_reg;
+ }
if (pdata->power_up_frequency) {
ret = adf4350_set_freq(st, pdata->power_up_frequency);
diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c
index a11ae9db0d11..36879f01e28c 100644
--- a/drivers/iio/gyro/adis16136.c
+++ b/drivers/iio/gyro/adis16136.c
@@ -6,19 +6,14 @@
* Author: Lars-Peter Clausen <lars@metafoo.de>
*/
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#include <linux/debugfs.h>
@@ -223,13 +218,12 @@ static ssize_t adis16136_read_frequency(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16136 *adis16136 = iio_priv(indio_dev);
- struct mutex *slock = &adis16136->adis.state_lock;
unsigned int freq;
int ret;
- mutex_lock(slock);
+ adis_dev_lock(&adis16136->adis);
ret = __adis16136_get_freq(adis16136, &freq);
- mutex_unlock(slock);
+ adis_dev_unlock(&adis16136->adis);
if (ret)
return ret;
@@ -254,11 +248,10 @@ static const unsigned adis16136_3db_divisors[] = {
static int adis16136_set_filter(struct iio_dev *indio_dev, int val)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
- struct mutex *slock = &adis16136->adis.state_lock;
unsigned int freq;
int i, ret;
- mutex_lock(slock);
+ adis_dev_lock(&adis16136->adis);
ret = __adis16136_get_freq(adis16136, &freq);
if (ret)
goto out_unlock;
@@ -270,7 +263,7 @@ static int adis16136_set_filter(struct iio_dev *indio_dev, int val)
ret = __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
out_unlock:
- mutex_unlock(slock);
+ adis_dev_unlock(&adis16136->adis);
return ret;
}
@@ -278,12 +271,11 @@ out_unlock:
static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
- struct mutex *slock = &adis16136->adis.state_lock;
unsigned int freq;
uint16_t val16;
int ret;
- mutex_lock(slock);
+ adis_dev_lock(&adis16136->adis);
ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT,
&val16);
@@ -297,7 +289,7 @@ static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
*val = freq / adis16136_3db_divisors[val16 & 0x07];
err_unlock:
- mutex_unlock(slock);
+ adis_dev_unlock(&adis16136->adis);
return ret ? ret : IIO_VAL_INT;
}
diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c
index e7c9a3e31c45..66b6b7bd5e1b 100644
--- a/drivers/iio/gyro/adis16260.c
+++ b/drivers/iio/gyro/adis16260.c
@@ -5,17 +5,12 @@
* Copyright 2010 Analog Devices Inc.
*/
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#define ADIS16260_STARTUP_DELAY 220 /* ms */
@@ -293,7 +288,7 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
addr = adis16260_addresses[chan->scan_index][1];
return adis_write_reg_16(adis, addr, val);
case IIO_CHAN_INFO_SAMP_FREQ:
- mutex_lock(&adis->state_lock);
+ adis_dev_lock(adis);
if (spi_get_device_id(adis->spi)->driver_data)
t = 256 / val;
else
@@ -310,7 +305,7 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
adis->spi->max_speed_hz = ADIS16260_SPI_FAST;
ret = __adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);
- mutex_unlock(&adis->state_lock);
+ adis_dev_unlock(adis);
return ret;
}
return -EINVAL;
diff --git a/drivers/iio/gyro/adxrs290.c b/drivers/iio/gyro/adxrs290.c
index cec5e1f17c22..3e0734ddafe3 100644
--- a/drivers/iio/gyro/adxrs290.c
+++ b/drivers/iio/gyro/adxrs290.c
@@ -589,7 +589,7 @@ static int adxrs290_probe_trigger(struct iio_dev *indio_dev)
st->dready_trig = devm_iio_trigger_alloc(&st->spi->dev, "%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!st->dready_trig)
return -ENOMEM;
diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c
index b11ebd9bb7a4..17b939a367ad 100644
--- a/drivers/iio/gyro/bmg160_core.c
+++ b/drivers/iio/gyro/bmg160_core.c
@@ -98,7 +98,11 @@ struct bmg160_data {
struct iio_trigger *motion_trig;
struct iio_mount_matrix orientation;
struct mutex mutex;
- s16 buffer[8];
+ /* Ensure naturally aligned timestamp */
+ struct {
+ s16 chans[3];
+ s64 timestamp __aligned(8);
+ } scan;
u32 dps_range;
int ev_enable_state;
int slope_thres;
@@ -882,12 +886,12 @@ static irqreturn_t bmg160_trigger_handler(int irq, void *p)
mutex_lock(&data->mutex);
ret = regmap_bulk_read(data->regmap, BMG160_REG_XOUT_L,
- data->buffer, AXIS_MAX * 2);
+ data->scan.chans, AXIS_MAX * 2);
mutex_unlock(&data->mutex);
if (ret < 0)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
pf->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -1102,8 +1106,7 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
if (ret)
return ret;
- ret = iio_read_mount_matrix(dev, "mount-matrix",
- &data->orientation);
+ ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
@@ -1137,14 +1140,14 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
data->dready_trig = devm_iio_trigger_alloc(dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->dready_trig)
return -ENOMEM;
data->motion_trig = devm_iio_trigger_alloc(dev,
"%s-any-motion-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->motion_trig)
return -ENOMEM;
diff --git a/drivers/iio/gyro/fxas21002c_core.c b/drivers/iio/gyro/fxas21002c_core.c
index 645461c70454..410e5e9f2672 100644
--- a/drivers/iio/gyro/fxas21002c_core.c
+++ b/drivers/iio/gyro/fxas21002c_core.c
@@ -366,14 +366,7 @@ out_unlock:
static int fxas21002c_pm_get(struct fxas21002c_data *data)
{
- struct device *dev = regmap_get_device(data->regmap);
- int ret;
-
- ret = pm_runtime_get_sync(dev);
- if (ret < 0)
- pm_runtime_put_noidle(dev);
-
- return ret;
+ return pm_runtime_resume_and_get(regmap_get_device(data->regmap));
}
static int fxas21002c_pm_put(struct fxas21002c_data *data)
@@ -854,7 +847,7 @@ static int fxas21002c_trigger_probe(struct fxas21002c_data *data)
data->dready_trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->dready_trig)
return -ENOMEM;
@@ -1004,7 +997,6 @@ int fxas21002c_core_probe(struct device *dev, struct regmap *regmap, int irq,
pm_disable:
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
- pm_runtime_put_noidle(dev);
return ret;
}
@@ -1018,7 +1010,6 @@ void fxas21002c_core_remove(struct device *dev)
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
- pm_runtime_put_noidle(dev);
}
EXPORT_SYMBOL_GPL(fxas21002c_core_remove);
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index dad26ee4fd1f..bc63c2a34c5e 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -6,13 +6,10 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
+#include <linux/mod_devicetable.h>
#include <linux/slab.h>
-#include <linux/delay.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
@@ -400,3 +397,4 @@ module_platform_driver(hid_gyro_3d_platform_driver);
MODULE_DESCRIPTION("HID Sensor Gyroscope 3D");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HID);
diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c
index af0aaa146f0c..04dd6a7969ea 100644
--- a/drivers/iio/gyro/itg3200_buffer.c
+++ b/drivers/iio/gyro/itg3200_buffer.c
@@ -114,7 +114,7 @@ int itg3200_probe_trigger(struct iio_dev *indio_dev)
struct itg3200 *st = iio_priv(indio_dev);
st->trig = iio_trigger_alloc(&st->i2c->dev, "%s-dev%d", indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!st->trig)
return -ENOMEM;
diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c
index e9804664db73..a7f1bbb5f289 100644
--- a/drivers/iio/gyro/itg3200_core.c
+++ b/drivers/iio/gyro/itg3200_core.c
@@ -308,8 +308,7 @@ static int itg3200_probe(struct i2c_client *client,
st = iio_priv(indio_dev);
- ret = iio_read_mount_matrix(&client->dev, "mount-matrix",
- &st->orientation);
+ ret = iio_read_mount_matrix(&client->dev, &st->orientation);
if (ret)
return ret;
diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c
index f17a93519535..3225de1f023b 100644
--- a/drivers/iio/gyro/mpu3050-core.c
+++ b/drivers/iio/gyro/mpu3050-core.c
@@ -1058,7 +1058,7 @@ static int mpu3050_trigger_probe(struct iio_dev *indio_dev, int irq)
mpu3050->trig = devm_iio_trigger_alloc(&indio_dev->dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!mpu3050->trig)
return -ENOMEM;
@@ -1164,7 +1164,7 @@ int mpu3050_common_probe(struct device *dev,
mpu3050->divisor = 99;
/* Read the mounting matrix, if present */
- ret = iio_read_mount_matrix(dev, "mount-matrix", &mpu3050->orientation);
+ ret = iio_read_mount_matrix(dev, &mpu3050->orientation);
if (ret)
return ret;
diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h
index fd9171cc3aba..6537f5cb8320 100644
--- a/drivers/iio/gyro/st_gyro.h
+++ b/drivers/iio/gyro/st_gyro.h
@@ -24,18 +24,6 @@
#define LSM330_GYRO_DEV_NAME "lsm330_gyro"
#define LSM9DS0_GYRO_DEV_NAME "lsm9ds0_gyro"
-/**
- * struct st_sensors_platform_data - gyro platform data
- * @drdy_int_pin: DRDY on gyros is available only on INT2 pin.
- */
-static __maybe_unused const struct st_sensors_platform_data gyro_pdata = {
- .drdy_int_pin = 2,
-};
-
-const struct st_sensor_settings *st_gyro_get_settings(const char *name);
-int st_gyro_common_probe(struct iio_dev *indio_dev);
-void st_gyro_common_remove(struct iio_dev *indio_dev);
-
#ifdef CONFIG_IIO_BUFFER
int st_gyro_allocate_ring(struct iio_dev *indio_dev);
void st_gyro_deallocate_ring(struct iio_dev *indio_dev);
diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c
index c8aa051995d3..b86ee4d940d9 100644
--- a/drivers/iio/gyro/st_gyro_core.c
+++ b/drivers/iio/gyro/st_gyro_core.c
@@ -37,19 +37,36 @@
#define ST_GYRO_FS_AVL_500DPS 500
#define ST_GYRO_FS_AVL_2000DPS 2000
+static const struct iio_mount_matrix *
+st_gyro_get_mount_matrix(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct st_sensor_data *gdata = iio_priv(indio_dev);
+
+ return &gdata->mount_matrix;
+}
+
+static const struct iio_chan_spec_ext_info st_gyro_mount_matrix_ext_info[] = {
+ IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_gyro_get_mount_matrix),
+ { }
+};
+
static const struct iio_chan_spec st_gyro_16bit_channels[] = {
- ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL,
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ANGL_VEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16,
- ST_GYRO_DEFAULT_OUT_X_L_ADDR),
- ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL,
+ ST_GYRO_DEFAULT_OUT_X_L_ADDR,
+ st_gyro_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ANGL_VEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16,
- ST_GYRO_DEFAULT_OUT_Y_L_ADDR),
- ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL,
+ ST_GYRO_DEFAULT_OUT_Y_L_ADDR,
+ st_gyro_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_ANGL_VEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16,
- ST_GYRO_DEFAULT_OUT_Z_L_ADDR),
+ ST_GYRO_DEFAULT_OUT_Z_L_ADDR,
+ st_gyro_mount_matrix_ext_info),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
@@ -357,6 +374,11 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
},
};
+/* DRDY on gyros is available only on INT2 pin */
+static const struct st_sensors_platform_data gyro_pdata = {
+ .drdy_int_pin = 2,
+};
+
static int st_gyro_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *ch, int *val,
int *val2, long mask)
@@ -466,18 +488,18 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &gyro_info;
- err = st_sensors_power_enable(indio_dev);
- if (err)
- return err;
-
err = st_sensors_verify_id(indio_dev);
if (err < 0)
- goto st_gyro_power_off;
+ return err;
gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS;
indio_dev->channels = gdata->sensor_settings->ch;
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
+ err = iio_read_mount_matrix(gdata->dev, &gdata->mount_matrix);
+ if (err)
+ return err;
+
gdata->current_fullscale = &gdata->sensor_settings->fs.fs_avl[0];
gdata->odr = gdata->sensor_settings->odr.odr_avl[0].hz;
@@ -485,11 +507,11 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
err = st_sensors_init_sensor(indio_dev, pdata);
if (err < 0)
- goto st_gyro_power_off;
+ return err;
err = st_gyro_allocate_ring(indio_dev);
if (err < 0)
- goto st_gyro_power_off;
+ return err;
if (gdata->irq > 0) {
err = st_sensors_allocate_trigger(indio_dev,
@@ -512,9 +534,6 @@ st_gyro_device_register_error:
st_sensors_deallocate_trigger(indio_dev);
st_gyro_probe_trigger_error:
st_gyro_deallocate_ring(indio_dev);
-st_gyro_power_off:
- st_sensors_power_disable(indio_dev);
-
return err;
}
EXPORT_SYMBOL(st_gyro_common_probe);
@@ -523,8 +542,6 @@ void st_gyro_common_remove(struct iio_dev *indio_dev)
{
struct st_sensor_data *gdata = iio_priv(indio_dev);
- st_sensors_power_disable(indio_dev);
-
iio_device_unregister(indio_dev);
if (gdata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c
index 8190966e6ff0..a25cc0379e16 100644
--- a/drivers/iio/gyro/st_gyro_i2c.c
+++ b/drivers/iio/gyro/st_gyro_i2c.c
@@ -86,16 +86,29 @@ static int st_gyro_i2c_probe(struct i2c_client *client,
if (err < 0)
return err;
+ err = st_sensors_power_enable(indio_dev);
+ if (err)
+ return err;
+
err = st_gyro_common_probe(indio_dev);
if (err < 0)
- return err;
+ goto st_gyro_power_off;
return 0;
+
+st_gyro_power_off:
+ st_sensors_power_disable(indio_dev);
+
+ return err;
}
static int st_gyro_i2c_remove(struct i2c_client *client)
{
- st_gyro_common_remove(i2c_get_clientdata(client));
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+ st_sensors_power_disable(indio_dev);
+
+ st_gyro_common_remove(indio_dev);
return 0;
}
diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c
index efb862763ca3..18d6a2aeda45 100644
--- a/drivers/iio/gyro/st_gyro_spi.c
+++ b/drivers/iio/gyro/st_gyro_spi.c
@@ -90,16 +90,29 @@ static int st_gyro_spi_probe(struct spi_device *spi)
if (err < 0)
return err;
+ err = st_sensors_power_enable(indio_dev);
+ if (err)
+ return err;
+
err = st_gyro_common_probe(indio_dev);
if (err < 0)
- return err;
+ goto st_gyro_power_off;
return 0;
+
+st_gyro_power_off:
+ st_sensors_power_disable(indio_dev);
+
+ return err;
}
static int st_gyro_spi_remove(struct spi_device *spi)
{
- st_gyro_common_remove(spi_get_drvdata(spi));
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+ st_sensors_power_disable(indio_dev);
+
+ st_gyro_common_remove(indio_dev);
return 0;
}
diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c
index 1fa8d51d5080..d4921385aaf7 100644
--- a/drivers/iio/health/afe4403.c
+++ b/drivers/iio/health/afe4403.c
@@ -521,7 +521,7 @@ static int afe4403_probe(struct spi_device *spi)
afe->trig = devm_iio_trigger_alloc(afe->dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!afe->trig) {
dev_err(afe->dev, "Unable to allocate IIO trigger\n");
ret = -ENOMEM;
diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c
index e1476bf79fe2..d8a27dfe074a 100644
--- a/drivers/iio/health/afe4404.c
+++ b/drivers/iio/health/afe4404.c
@@ -528,7 +528,7 @@ static int afe4404_probe(struct i2c_client *client,
afe->trig = devm_iio_trigger_alloc(afe->dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!afe->trig) {
dev_err(afe->dev, "Unable to allocate IIO trigger\n");
ret = -ENOMEM;
diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c
index 23bc9c784ef4..4a39f1019347 100644
--- a/drivers/iio/humidity/am2315.c
+++ b/drivers/iio/humidity/am2315.c
@@ -7,7 +7,6 @@
* 7-bit I2C address: 0x5C.
*/
-#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
@@ -33,7 +32,11 @@
struct am2315_data {
struct i2c_client *client;
struct mutex lock;
- s16 buffer[8]; /* 2x16-bit channels + 2x16 padding + 4x16 timestamp */
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ s16 chans[2];
+ s64 timestamp __aligned(8);
+ } scan;
};
struct am2315_sensor_data {
@@ -167,20 +170,20 @@ static irqreturn_t am2315_trigger_handler(int irq, void *p)
mutex_lock(&data->lock);
if (*(indio_dev->active_scan_mask) == AM2315_ALL_CHANNEL_MASK) {
- data->buffer[0] = sensor_data.hum_data;
- data->buffer[1] = sensor_data.temp_data;
+ data->scan.chans[0] = sensor_data.hum_data;
+ data->scan.chans[1] = sensor_data.temp_data;
} else {
i = 0;
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->masklength) {
- data->buffer[i] = (bit ? sensor_data.temp_data :
- sensor_data.hum_data);
+ data->scan.chans[i] = (bit ? sensor_data.temp_data :
+ sensor_data.hum_data);
i++;
}
}
mutex_unlock(&data->lock);
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
pf->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -256,17 +259,9 @@ static const struct i2c_device_id am2315_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, am2315_i2c_id);
-static const struct acpi_device_id am2315_acpi_id[] = {
- {"AOS2315", 0},
- {}
-};
-
-MODULE_DEVICE_TABLE(acpi, am2315_acpi_id);
-
static struct i2c_driver am2315_driver = {
.driver = {
.name = "am2315",
- .acpi_match_table = ACPI_PTR(am2315_acpi_id),
},
.probe = am2315_probe,
.id_table = am2315_i2c_id,
diff --git a/drivers/iio/humidity/hdc2010.c b/drivers/iio/humidity/hdc2010.c
index 83f5b9f60780..1381df46187c 100644
--- a/drivers/iio/humidity/hdc2010.c
+++ b/drivers/iio/humidity/hdc2010.c
@@ -272,7 +272,6 @@ static int hdc2010_probe(struct i2c_client *client,
data->client = client;
mutex_init(&data->lock);
- indio_dev->dev.parent = &client->dev;
/*
* As DEVICE ID register does not differentiate between
* HDC2010 and HDC2080, we have the name hardcoded
diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c
index 74383abc0d44..fa0fe404a70a 100644
--- a/drivers/iio/humidity/hid-sensor-humidity.c
+++ b/drivers/iio/humidity/hid-sensor-humidity.c
@@ -8,6 +8,7 @@
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include "hid-sensor-trigger.h"
@@ -295,3 +296,4 @@ module_platform_driver(hid_humidity_platform_driver);
MODULE_DESCRIPTION("HID Environmental humidity sensor");
MODULE_AUTHOR("Song Hongyan <hongyan.song@intel.com>");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_HID);
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index f02883b08480..001ca2c3ff95 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -94,6 +94,7 @@ config KMX61
source "drivers/iio/imu/inv_icm42600/Kconfig"
source "drivers/iio/imu/inv_mpu6050/Kconfig"
source "drivers/iio/imu/st_lsm6dsx/Kconfig"
+source "drivers/iio/imu/st_lsm9ds0/Kconfig"
endmenu
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 13e9ff442b11..c82748096c77 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -26,3 +26,4 @@ obj-y += inv_mpu6050/
obj-$(CONFIG_KMX61) += kmx61.o
obj-y += st_lsm6dsx/
+obj-y += st_lsm9ds0/
diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
index 319b64b2fd88..a5b421f42287 100644
--- a/drivers/iio/imu/adis.c
+++ b/drivers/iio/imu/adis.c
@@ -12,14 +12,10 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
#include <linux/module.h>
#include <asm/unaligned.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#define ADIS_MSC_CTRL_DATA_RDY_EN BIT(2)
diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c
index 768aa493a1a6..b12917a7cb60 100644
--- a/drivers/iio/imu/adis16400.c
+++ b/drivers/iio/imu/adis16400.c
@@ -10,22 +10,15 @@
* Copyright (c) 2011 Analog Devices Inc.
*/
-#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/list.h>
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/bitops.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/imu/adis.h>
@@ -641,28 +634,13 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16400_state *st = iio_priv(indio_dev);
struct adis *adis = &st->adis;
- u32 old_speed_hz = st->adis.spi->max_speed_hz;
void *buffer;
int ret;
- if (!adis->buffer)
- return -ENOMEM;
-
- if (!(st->variant->flags & ADIS16400_NO_BURST) &&
- st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) {
- st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST;
- spi_setup(st->adis.spi);
- }
-
ret = spi_sync(adis->spi, &adis->msg);
if (ret)
dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret);
- if (!(st->variant->flags & ADIS16400_NO_BURST)) {
- st->adis.spi->max_speed_hz = old_speed_hz;
- spi_setup(st->adis.spi);
- }
-
if (st->variant->flags & ADIS16400_BURST_DIAG_STAT)
buffer = adis->buffer + sizeof(u16);
else
@@ -968,7 +946,8 @@ static const char * const adis16400_status_error_msgs[] = {
BIT(ADIS16400_DIAG_STAT_POWER_LOW), \
.timeouts = (_timeouts), \
.burst_reg_cmd = ADIS16400_GLOB_CMD, \
- .burst_len = (_burst_len) \
+ .burst_len = (_burst_len), \
+ .burst_max_speed_hz = ADIS16400_SPI_BURST \
}
static const struct adis_timeout adis16300_timeouts = {
@@ -1178,8 +1157,6 @@ static int adis16400_probe(struct spi_device *spi)
return -ENOMEM;
st = iio_priv(indio_dev);
- /* this is only used for removal purposes */
- spi_set_drvdata(spi, indio_dev);
/* setup the industrialio driver allocated elements */
st->variant = &adis16400_chips[spi_get_device_id(spi)->driver_data];
diff --git a/drivers/iio/imu/adis16460.c b/drivers/iio/imu/adis16460.c
index 73bf45e859b8..a6f9fba3e03f 100644
--- a/drivers/iio/imu/adis16460.c
+++ b/drivers/iio/imu/adis16460.c
@@ -5,7 +5,6 @@
* Copyright 2019 Analog Devices Inc.
*/
-#include <linux/delay.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
@@ -388,8 +387,6 @@ static int adis16460_probe(struct spi_device *spi)
if (indio_dev == NULL)
return -ENOMEM;
- spi_set_drvdata(spi, indio_dev);
-
st = iio_priv(indio_dev);
st->chip_info = &adis16460_chip_info;
diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c
index 1de62fc79e0f..eb48102f9424 100644
--- a/drivers/iio/imu/adis16475.c
+++ b/drivers/iio/imu/adis16475.c
@@ -14,7 +14,6 @@
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/imu/adis.h>
-#include <linux/iio/sysfs.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/irq.h>
#include <linux/lcm.h>
@@ -645,7 +644,8 @@ static int adis16475_enable_irq(struct adis *adis, bool enable)
.timeouts = (_timeouts), \
.burst_reg_cmd = ADIS16475_REG_GLOB_CMD, \
.burst_len = ADIS16475_BURST_MAX_DATA, \
- .burst_max_len = ADIS16475_BURST32_MAX_DATA \
+ .burst_max_len = ADIS16475_BURST32_MAX_DATA, \
+ .burst_max_speed_hz = ADIS16475_BURST_MAX_SPEED \
}
static const struct adis16475_sync adis16475_sync_mode[] = {
@@ -1062,15 +1062,11 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p)
bool valid;
/* offset until the first element after gyro and accel */
const u8 offset = st->burst32 ? 13 : 7;
- const u32 cached_spi_speed_hz = adis->spi->max_speed_hz;
-
- adis->spi->max_speed_hz = ADIS16475_BURST_MAX_SPEED;
ret = spi_sync(adis->spi, &adis->msg);
if (ret)
- return ret;
+ goto check_burst32;
- adis->spi->max_speed_hz = cached_spi_speed_hz;
buffer = adis->buffer;
crc = be16_to_cpu(buffer[offset + 2]);
@@ -1332,7 +1328,6 @@ static int adis16475_probe(struct spi_device *spi)
return -ENOMEM;
st = iio_priv(indio_dev);
- spi_set_drvdata(spi, indio_dev);
st->info = device_get_match_data(&spi->dev);
if (!st->info)
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index f81b86690b76..a869a6e52a16 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -9,21 +9,19 @@
#include <linux/bitfield.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
-#include <linux/delay.h>
#include <linux/math.h>
-#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/lcm.h>
+#include <linux/swab.h>
+#include <linux/crc32.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
+#include <linux/iio/trigger_consumer.h>
#include <linux/debugfs.h>
@@ -103,6 +101,12 @@
* Available only for ADIS1649x devices
*/
#define ADIS16495_REG_SYNC_SCALE ADIS16480_REG(0x03, 0x10)
+#define ADIS16495_REG_BURST_CMD ADIS16480_REG(0x00, 0x7C)
+#define ADIS16495_BURST_ID 0xA5A5
+/* total number of segments in burst */
+#define ADIS16495_BURST_MAX_DATA 20
+/* spi max speed in burst mode */
+#define ADIS16495_BURST_MAX_SPEED 6000000
#define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20)
@@ -163,6 +167,8 @@ struct adis16480 {
struct clk *ext_clk;
enum adis16480_clock_mode clk_mode;
unsigned int clk_freq;
+ /* Alignment needed for the timestamp */
+ __be16 data[ADIS16495_BURST_MAX_DATA] __aligned(8);
};
static const char * const adis16480_int_pin_names[4] = {
@@ -863,7 +869,7 @@ static const char * const adis16480_status_error_msgs[] = {
static int adis16480_enable_irq(struct adis *adis, bool enable);
-#define ADIS16480_DATA(_prod_id, _timeouts) \
+#define ADIS16480_DATA(_prod_id, _timeouts, _burst_len) \
{ \
.diag_stat_reg = ADIS16480_REG_DIAG_STS, \
.glob_cmd_reg = ADIS16480_REG_GLOB_CMD, \
@@ -887,6 +893,9 @@ static int adis16480_enable_irq(struct adis *adis, bool enable);
BIT(ADIS16480_DIAG_STAT_BARO_FAIL), \
.enable_irq = adis16480_enable_irq, \
.timeouts = (_timeouts), \
+ .burst_reg_cmd = ADIS16495_REG_BURST_CMD, \
+ .burst_len = (_burst_len), \
+ .burst_max_speed_hz = ADIS16495_BURST_MAX_SPEED \
}
static const struct adis_timeout adis16485_timeouts = {
@@ -931,7 +940,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.int_clk = 2460000,
.max_dec_rate = 2048,
.filter_freqs = adis16480_def_filter_freqs,
- .adis_data = ADIS16480_DATA(16375, &adis16485_timeouts),
+ .adis_data = ADIS16480_DATA(16375, &adis16485_timeouts, 0),
},
[ADIS16480] = {
.channels = adis16480_channels,
@@ -944,7 +953,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.int_clk = 2460000,
.max_dec_rate = 2048,
.filter_freqs = adis16480_def_filter_freqs,
- .adis_data = ADIS16480_DATA(16480, &adis16480_timeouts),
+ .adis_data = ADIS16480_DATA(16480, &adis16480_timeouts, 0),
},
[ADIS16485] = {
.channels = adis16485_channels,
@@ -957,7 +966,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.int_clk = 2460000,
.max_dec_rate = 2048,
.filter_freqs = adis16480_def_filter_freqs,
- .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts),
+ .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0),
},
[ADIS16488] = {
.channels = adis16480_channels,
@@ -970,7 +979,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.int_clk = 2460000,
.max_dec_rate = 2048,
.filter_freqs = adis16480_def_filter_freqs,
- .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts),
+ .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0),
},
[ADIS16490] = {
.channels = adis16485_channels,
@@ -984,7 +993,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
- .adis_data = ADIS16480_DATA(16490, &adis16495_timeouts),
+ .adis_data = ADIS16480_DATA(16490, &adis16495_timeouts, 0),
},
[ADIS16495_1] = {
.channels = adis16485_channels,
@@ -998,7 +1007,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
- .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts),
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2),
},
[ADIS16495_2] = {
.channels = adis16485_channels,
@@ -1012,7 +1023,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
- .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts),
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2),
},
[ADIS16495_3] = {
.channels = adis16485_channels,
@@ -1026,7 +1039,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
- .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts),
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2),
},
[ADIS16497_1] = {
.channels = adis16485_channels,
@@ -1040,7 +1055,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
- .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts),
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2),
},
[ADIS16497_2] = {
.channels = adis16485_channels,
@@ -1054,7 +1071,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
- .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts),
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2),
},
[ADIS16497_3] = {
.channels = adis16485_channels,
@@ -1068,10 +1087,118 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
- .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts),
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2),
},
};
+static bool adis16480_validate_crc(const u16 *buf, const u8 n_elem, const u32 crc)
+{
+ u32 crc_calc;
+ u16 crc_buf[15];
+ int j;
+
+ for (j = 0; j < n_elem; j++)
+ crc_buf[j] = swab16(buf[j]);
+
+ crc_calc = crc32(~0, crc_buf, n_elem * 2);
+ crc_calc ^= ~0;
+
+ return (crc == crc_calc);
+}
+
+static irqreturn_t adis16480_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct adis16480 *st = iio_priv(indio_dev);
+ struct adis *adis = &st->adis;
+ int ret, bit, offset, i = 0;
+ __be16 *buffer;
+ u32 crc;
+ bool valid;
+
+ adis_dev_lock(adis);
+ if (adis->current_page != 0) {
+ adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
+ adis->tx[1] = 0;
+ ret = spi_write(adis->spi, adis->tx, 2);
+ if (ret) {
+ dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret);
+ adis_dev_unlock(adis);
+ goto irq_done;
+ }
+
+ adis->current_page = 0;
+ }
+
+ ret = spi_sync(adis->spi, &adis->msg);
+ if (ret) {
+ dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret);
+ adis_dev_unlock(adis);
+ goto irq_done;
+ }
+
+ adis_dev_unlock(adis);
+
+ /*
+ * After making the burst request, the response can have one or two
+ * 16-bit responses containing the BURST_ID depending on the sclk. If
+ * clk > 3.6MHz, then we will have two BURST_ID in a row. If clk < 3MHZ,
+ * we have only one. To manage that variation, we use the transition from the
+ * BURST_ID to the SYS_E_FLAG register, which will not be equal to 0xA5A5. If
+ * we not find this variation in the first 4 segments, then the data should
+ * not be valid.
+ */
+ buffer = adis->buffer;
+ for (offset = 0; offset < 4; offset++) {
+ u16 curr = be16_to_cpu(buffer[offset]);
+ u16 next = be16_to_cpu(buffer[offset + 1]);
+
+ if (curr == ADIS16495_BURST_ID && next != ADIS16495_BURST_ID) {
+ offset++;
+ break;
+ }
+ }
+
+ if (offset == 4) {
+ dev_err(&adis->spi->dev, "Invalid burst data\n");
+ goto irq_done;
+ }
+
+ crc = be16_to_cpu(buffer[offset + 16]) << 16 | be16_to_cpu(buffer[offset + 15]);
+ valid = adis16480_validate_crc((u16 *)&buffer[offset], 15, crc);
+ if (!valid) {
+ dev_err(&adis->spi->dev, "Invalid crc\n");
+ goto irq_done;
+ }
+
+ for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
+ /*
+ * When burst mode is used, temperature is the first data
+ * channel in the sequence, but the temperature scan index
+ * is 10.
+ */
+ switch (bit) {
+ case ADIS16480_SCAN_TEMP:
+ st->data[i++] = buffer[offset + 1];
+ break;
+ case ADIS16480_SCAN_GYRO_X ... ADIS16480_SCAN_ACCEL_Z:
+ /* The lower register data is sequenced first */
+ st->data[i++] = buffer[2 * bit + offset + 3];
+ st->data[i++] = buffer[2 * bit + offset + 2];
+ break;
+ }
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, st->data, pf->timestamp);
+irq_done:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
static const struct iio_info adis16480_info = {
.read_raw = &adis16480_read_raw,
.write_raw = &adis16480_write_raw,
@@ -1279,8 +1406,6 @@ static int adis16480_probe(struct spi_device *spi)
if (indio_dev == NULL)
return -ENOMEM;
- spi_set_drvdata(spi, indio_dev);
-
st = iio_priv(indio_dev);
st->chip_info = &adis16480_chip_info[id->driver_data];
@@ -1341,7 +1466,8 @@ static int adis16480_probe(struct spi_device *spi)
st->clk_freq = st->chip_info->int_clk;
}
- ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL);
+ ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev,
+ adis16480_trigger_handler);
if (ret)
return ret;
diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c
index ac354321f63a..351c303c8a8c 100644
--- a/drivers/iio/imu/adis_buffer.c
+++ b/drivers/iio/imu/adis_buffer.c
@@ -51,9 +51,13 @@ static int adis_update_scan_mode_burst(struct iio_dev *indio_dev,
adis->xfer[0].tx_buf = tx;
adis->xfer[0].bits_per_word = 8;
adis->xfer[0].len = 2;
+ if (adis->data->burst_max_speed_hz)
+ adis->xfer[0].speed_hz = adis->data->burst_max_speed_hz;
adis->xfer[1].rx_buf = adis->buffer;
adis->xfer[1].bits_per_word = 8;
adis->xfer[1].len = burst_length;
+ if (adis->data->burst_max_speed_hz)
+ adis->xfer[1].speed_hz = adis->data->burst_max_speed_hz;
spi_message_init(&adis->msg);
spi_message_add_tail(&adis->xfer[0], &adis->msg);
@@ -129,31 +133,34 @@ static irqreturn_t adis_trigger_handler(int irq, void *p)
struct adis *adis = iio_device_get_drvdata(indio_dev);
int ret;
- if (!adis->buffer)
- return -ENOMEM;
-
if (adis->data->has_paging) {
mutex_lock(&adis->state_lock);
if (adis->current_page != 0) {
adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
adis->tx[1] = 0;
- spi_write(adis->spi, adis->tx, 2);
+ ret = spi_write(adis->spi, adis->tx, 2);
+ if (ret) {
+ dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret);
+ mutex_unlock(&adis->state_lock);
+ goto irq_done;
+ }
+
+ adis->current_page = 0;
}
}
ret = spi_sync(adis->spi, &adis->msg);
- if (ret)
- dev_err(&adis->spi->dev, "Failed to read data: %d", ret);
-
-
- if (adis->data->has_paging) {
- adis->current_page = 0;
+ if (adis->data->has_paging)
mutex_unlock(&adis->state_lock);
+ if (ret) {
+ dev_err(&adis->spi->dev, "Failed to read data: %d", ret);
+ goto irq_done;
}
iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer,
pf->timestamp);
+irq_done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c
index fa5540fabacc..48eedc29b28a 100644
--- a/drivers/iio/imu/adis_trigger.c
+++ b/drivers/iio/imu/adis_trigger.c
@@ -62,7 +62,8 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
int ret;
adis->trig = devm_iio_trigger_alloc(&adis->spi->dev, "%s-dev%d",
- indio_dev->name, indio_dev->id);
+ indio_dev->name,
+ iio_device_id(indio_dev));
if (!adis->trig)
return -ENOMEM;
diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c
index 290b5ef83f77..824b5124a5f5 100644
--- a/drivers/iio/imu/bmi160/bmi160_core.c
+++ b/drivers/iio/imu/bmi160/bmi160_core.c
@@ -785,7 +785,8 @@ int bmi160_probe_trigger(struct iio_dev *indio_dev, int irq, u32 irq_type)
int ret;
data->trig = devm_iio_trigger_alloc(&indio_dev->dev, "%s-dev%d",
- indio_dev->name, indio_dev->id);
+ indio_dev->name,
+ iio_device_id(indio_dev));
if (data->trig == NULL)
return -ENOMEM;
@@ -851,8 +852,7 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap,
return ret;
}
- ret = iio_read_mount_matrix(dev, "mount-matrix",
- &data->orientation);
+ ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
index 8bd77185ccb7..86858da9cc38 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
@@ -592,7 +592,7 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
st->chip = chip;
st->map = regmap;
- ret = iio_read_mount_matrix(dev, "mount-matrix", &st->orientation);
+ ret = iio_read_mount_matrix(dev, &st->orientation);
if (ret) {
dev_err(dev, "failed to retrieve mounting matrix %d\n", ret);
return ret;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index 6244a07048df..8a7a920e6200 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -570,11 +570,9 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,
freq_hz = INV_MPU6050_DIVIDER_TO_FIFO_RATE(st->chip_config.divider);
period_us = 1000000 / freq_hz;
- result = pm_runtime_get_sync(pdev);
- if (result < 0) {
- pm_runtime_put_noidle(pdev);
+ result = pm_runtime_resume_and_get(pdev);
+ if (result)
return result;
- }
switch (chan->type) {
case IIO_ANGL_VEL:
@@ -812,11 +810,9 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
return result;
mutex_lock(&st->lock);
- result = pm_runtime_get_sync(pdev);
- if (result < 0) {
- pm_runtime_put_noidle(pdev);
+ result = pm_runtime_resume_and_get(pdev);
+ if (result)
goto error_write_raw_unlock;
- }
switch (mask) {
case IIO_CHAN_INFO_SCALE:
@@ -930,11 +926,9 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
result = 0;
goto fifo_rate_fail_unlock;
}
- result = pm_runtime_get_sync(pdev);
- if (result < 0) {
- pm_runtime_put_noidle(pdev);
+ result = pm_runtime_resume_and_get(pdev);
+ if (result)
goto fifo_rate_fail_unlock;
- }
result = regmap_write(st->map, st->reg->sample_rate_div, d);
if (result)
@@ -1314,8 +1308,7 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
for (i = 0; i < INV_NUM_PARTS; ++i) {
if (regval == hw_info[i].whoami) {
dev_warn(regmap_get_device(st->map),
- "whoami mismatch got %#02x (%s)"
- "expected %#02hhx (%s)\n",
+ "whoami mismatch got 0x%02x (%s) expected 0x%02x (%s)\n",
regval, hw_info[i].name,
st->hw->whoami, st->hw->name);
break;
@@ -1323,7 +1316,7 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
}
if (i >= INV_NUM_PARTS) {
dev_err(regmap_get_device(st->map),
- "invalid whoami %#02x expected %#02hhx (%s)\n",
+ "invalid whoami 0x%02x expected 0x%02x (%s)\n",
regval, st->hw->whoami, st->hw->name);
return -ENODEV;
}
@@ -1422,7 +1415,6 @@ static void inv_mpu_pm_disable(void *data)
{
struct device *dev = data;
- pm_runtime_put_sync_suspend(dev);
pm_runtime_disable(dev);
}
@@ -1455,8 +1447,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
pdata = dev_get_platdata(dev);
if (!pdata) {
- result = iio_read_mount_matrix(dev, "mount-matrix",
- &st->orientation);
+ result = iio_read_mount_matrix(dev, &st->orientation);
if (result) {
dev_err(dev, "Failed to retrieve mounting matrix %d\n",
result);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
index de8ed1446d60..2d0e8cdd4848 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
@@ -173,11 +173,9 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
if (enable) {
scan = inv_scan_query(indio_dev);
- result = pm_runtime_get_sync(pdev);
- if (result < 0) {
- pm_runtime_put_noidle(pdev);
+ result = pm_runtime_resume_and_get(pdev);
+ if (result)
return result;
- }
/*
* In case autosuspend didn't trigger, turn off first not
* required sensors.
@@ -238,7 +236,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type)
st->trig = devm_iio_trigger_alloc(&indio_dev->dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!st->trig)
return -ENOMEM;
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index fc5a60fcfec0..1dabfd615dab 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -750,7 +750,7 @@ static int kmx61_set_power_state(struct kmx61_data *data, bool on, u8 device)
}
if (on) {
- ret = pm_runtime_get_sync(&data->client->dev);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
} else {
pm_runtime_mark_last_busy(&data->client->dev);
ret = pm_runtime_put_autosuspend(&data->client->dev);
@@ -759,8 +759,6 @@ static int kmx61_set_power_state(struct kmx61_data *data, bool on, u8 device)
dev_err(&data->client->dev,
"Failed: kmx61_set_power_state for %d, ret %d\n",
on, ret);
- if (on)
- pm_runtime_put_noidle(&data->client->dev);
return ret;
}
@@ -1264,7 +1262,7 @@ static struct iio_trigger *kmx61_trigger_setup(struct kmx61_data *data,
"%s-%s-dev%d",
indio_dev->name,
tag,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!trig)
return ERR_PTR(-ENOMEM);
@@ -1426,7 +1424,6 @@ static int kmx61_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
if (client->irq > 0) {
iio_triggered_buffer_cleanup(data->acc_indio_dev);
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index 7cedaab096a7..db45f1fc0b81 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -15,19 +15,19 @@
*
* Supported sensors:
* - LSM6DS3:
- * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
+ * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 8KB
*
* - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C:
- * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
+ * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 4KB
*
* - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX/LSM6DST/LSM6DSOP:
- * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416,
+ * - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416,
* 833
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
@@ -2256,7 +2256,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
return err;
}
- err = iio_read_mount_matrix(hw->dev, "mount-matrix", &hw->orientation);
+ err = iio_read_mount_matrix(hw->dev, &hw->orientation);
if (err)
return err;
diff --git a/drivers/iio/imu/st_lsm9ds0/Kconfig b/drivers/iio/imu/st_lsm9ds0/Kconfig
new file mode 100644
index 000000000000..53b7017014f8
--- /dev/null
+++ b/drivers/iio/imu/st_lsm9ds0/Kconfig
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config IIO_ST_LSM9DS0
+ tristate "STMicroelectronics LSM9DS0 IMU driver"
+ depends on (I2C || SPI_MASTER) && SYSFS
+ depends on !SENSORS_LIS3_I2C
+ depends on !SENSORS_LIS3_SPI
+ select IIO_ST_LSM9DS0_I2C if I2C
+ select IIO_ST_LSM9DS0_SPI if SPI_MASTER
+ select IIO_ST_ACCEL_3AXIS
+ select IIO_ST_MAGN_3AXIS
+
+ help
+ Say yes here to build support for STMicroelectronics LSM9DS0 IMU
+ sensor. Supported devices: accelerometer/magnetometer of lsm9ds0.
+
+ To compile this driver as a module, choose M here: the module
+ will be called st_lsm9ds0.
+
+config IIO_ST_LSM9DS0_I2C
+ tristate
+ depends on IIO_ST_LSM9DS0
+ select REGMAP_I2C
+
+config IIO_ST_LSM9DS0_SPI
+ tristate
+ depends on IIO_ST_LSM9DS0
+ select REGMAP_SPI
diff --git a/drivers/iio/imu/st_lsm9ds0/Makefile b/drivers/iio/imu/st_lsm9ds0/Makefile
new file mode 100644
index 000000000000..488af523f648
--- /dev/null
+++ b/drivers/iio/imu/st_lsm9ds0/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_IIO_ST_LSM9DS0) += st_lsm9ds0.o
+st_lsm9ds0-y := st_lsm9ds0_core.o
+obj-$(CONFIG_IIO_ST_LSM9DS0_I2C) += st_lsm9ds0_i2c.o
+obj-$(CONFIG_IIO_ST_LSM9DS0_SPI) += st_lsm9ds0_spi.o
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h
new file mode 100644
index 000000000000..146393afd9a7
--- /dev/null
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+// STMicroelectronics LSM9DS0 IMU driver
+
+#ifndef ST_LSM9DS0_H
+#define ST_LSM9DS0_H
+
+struct iio_dev;
+struct regulator;
+
+struct st_lsm9ds0 {
+ struct device *dev;
+ const char *name;
+ int irq;
+ struct iio_dev *accel;
+ struct iio_dev *magn;
+ struct regulator *vdd;
+ struct regulator *vdd_io;
+};
+
+int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap);
+int st_lsm9ds0_remove(struct st_lsm9ds0 *lsm9ds0);
+
+#endif /* ST_LSM9DS0_H */
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c
new file mode 100644
index 000000000000..8204f7303fd7
--- /dev/null
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * STMicroelectronics LSM9DS0 IMU driver
+ *
+ * Copyright (C) 2021, Intel Corporation
+ *
+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/common/st_sensors.h>
+#include <linux/iio/iio.h>
+
+#include "st_lsm9ds0.h"
+
+static int st_lsm9ds0_power_enable(struct device *dev, struct st_lsm9ds0 *lsm9ds0)
+{
+ int ret;
+
+ /* Regulators not mandatory, but if requested we should enable them. */
+ lsm9ds0->vdd = devm_regulator_get(dev, "vdd");
+ if (IS_ERR(lsm9ds0->vdd)) {
+ dev_err(dev, "unable to get Vdd supply\n");
+ return PTR_ERR(lsm9ds0->vdd);
+ }
+ ret = regulator_enable(lsm9ds0->vdd);
+ if (ret) {
+ dev_warn(dev, "Failed to enable specified Vdd supply\n");
+ return ret;
+ }
+
+ lsm9ds0->vdd_io = devm_regulator_get(dev, "vddio");
+ if (IS_ERR(lsm9ds0->vdd_io)) {
+ dev_err(dev, "unable to get Vdd_IO supply\n");
+ regulator_disable(lsm9ds0->vdd);
+ return PTR_ERR(lsm9ds0->vdd_io);
+ }
+ ret = regulator_enable(lsm9ds0->vdd_io);
+ if (ret) {
+ dev_warn(dev, "Failed to enable specified Vdd_IO supply\n");
+ regulator_disable(lsm9ds0->vdd);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void st_lsm9ds0_power_disable(void *data)
+{
+ struct st_lsm9ds0 *lsm9ds0 = data;
+
+ regulator_disable(lsm9ds0->vdd_io);
+ regulator_disable(lsm9ds0->vdd);
+}
+
+static int devm_st_lsm9ds0_power_enable(struct st_lsm9ds0 *lsm9ds0)
+{
+ struct device *dev = lsm9ds0->dev;
+ int ret;
+
+ ret = st_lsm9ds0_power_enable(dev, lsm9ds0);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(dev, st_lsm9ds0_power_disable, lsm9ds0);
+}
+
+static int st_lsm9ds0_probe_accel(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap)
+{
+ const struct st_sensor_settings *settings;
+ struct device *dev = lsm9ds0->dev;
+ struct st_sensor_data *data;
+
+ settings = st_accel_get_settings(lsm9ds0->name);
+ if (!settings) {
+ dev_err(dev, "device name %s not recognized.\n", lsm9ds0->name);
+ return -ENODEV;
+ }
+
+ lsm9ds0->accel = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!lsm9ds0->accel)
+ return -ENOMEM;
+
+ lsm9ds0->accel->name = lsm9ds0->name;
+
+ data = iio_priv(lsm9ds0->accel);
+ data->sensor_settings = (struct st_sensor_settings *)settings;
+ data->dev = dev;
+ data->irq = lsm9ds0->irq;
+ data->regmap = regmap;
+ data->vdd = lsm9ds0->vdd;
+ data->vdd_io = lsm9ds0->vdd_io;
+
+ return st_accel_common_probe(lsm9ds0->accel);
+}
+
+static int st_lsm9ds0_probe_magn(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap)
+{
+ const struct st_sensor_settings *settings;
+ struct device *dev = lsm9ds0->dev;
+ struct st_sensor_data *data;
+
+ settings = st_magn_get_settings(lsm9ds0->name);
+ if (!settings) {
+ dev_err(dev, "device name %s not recognized.\n", lsm9ds0->name);
+ return -ENODEV;
+ }
+
+ lsm9ds0->magn = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!lsm9ds0->magn)
+ return -ENOMEM;
+
+ lsm9ds0->magn->name = lsm9ds0->name;
+
+ data = iio_priv(lsm9ds0->magn);
+ data->sensor_settings = (struct st_sensor_settings *)settings;
+ data->dev = dev;
+ data->irq = lsm9ds0->irq;
+ data->regmap = regmap;
+ data->vdd = lsm9ds0->vdd;
+ data->vdd_io = lsm9ds0->vdd_io;
+
+ return st_magn_common_probe(lsm9ds0->magn);
+}
+
+int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap)
+{
+ int ret;
+
+ ret = devm_st_lsm9ds0_power_enable(lsm9ds0);
+ if (ret)
+ return ret;
+
+ /* Setup accelerometer device */
+ ret = st_lsm9ds0_probe_accel(lsm9ds0, regmap);
+ if (ret)
+ return ret;
+
+ /* Setup magnetometer device */
+ ret = st_lsm9ds0_probe_magn(lsm9ds0, regmap);
+ if (ret)
+ st_accel_common_remove(lsm9ds0->accel);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(st_lsm9ds0_probe);
+
+int st_lsm9ds0_remove(struct st_lsm9ds0 *lsm9ds0)
+{
+ st_magn_common_remove(lsm9ds0->magn);
+ st_accel_common_remove(lsm9ds0->accel);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(st_lsm9ds0_remove);
+
+MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
+MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU core driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
new file mode 100644
index 000000000000..50a36ab53bc3
--- /dev/null
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * STMicroelectronics LSM9DS0 IMU driver
+ *
+ * Copyright (C) 2021, Intel Corporation
+ *
+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/iio/common/st_sensors_i2c.h>
+
+#include "st_lsm9ds0.h"
+
+static const struct of_device_id st_lsm9ds0_of_match[] = {
+ {
+ .compatible = "st,lsm9ds0-imu",
+ .data = LSM9DS0_IMU_DEV_NAME,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match);
+
+static const struct i2c_device_id st_lsm9ds0_id_table[] = {
+ { LSM9DS0_IMU_DEV_NAME },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, st_lsm9ds0_id_table);
+
+static const struct regmap_config st_lsm9ds0_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .read_flag_mask = 0x80,
+};
+
+static int st_lsm9ds0_i2c_probe(struct i2c_client *client)
+{
+ const struct regmap_config *config = &st_lsm9ds0_regmap_config;
+ struct device *dev = &client->dev;
+ struct st_lsm9ds0 *lsm9ds0;
+ struct regmap *regmap;
+
+ st_sensors_dev_name_probe(dev, client->name, sizeof(client->name));
+
+ lsm9ds0 = devm_kzalloc(dev, sizeof(*lsm9ds0), GFP_KERNEL);
+ if (!lsm9ds0)
+ return -ENOMEM;
+
+ lsm9ds0->dev = dev;
+ lsm9ds0->name = client->name;
+ lsm9ds0->irq = client->irq;
+
+ regmap = devm_regmap_init_i2c(client, config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ i2c_set_clientdata(client, lsm9ds0);
+
+ return st_lsm9ds0_probe(lsm9ds0, regmap);
+}
+
+static int st_lsm9ds0_i2c_remove(struct i2c_client *client)
+{
+ return st_lsm9ds0_remove(i2c_get_clientdata(client));
+}
+
+static struct i2c_driver st_lsm9ds0_driver = {
+ .driver = {
+ .name = "st-lsm9ds0-i2c",
+ .of_match_table = st_lsm9ds0_of_match,
+ },
+ .probe_new = st_lsm9ds0_i2c_probe,
+ .remove = st_lsm9ds0_i2c_remove,
+ .id_table = st_lsm9ds0_id_table,
+};
+module_i2c_driver(st_lsm9ds0_driver);
+
+MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
+MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU I2C driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
new file mode 100644
index 000000000000..272c88990dd0
--- /dev/null
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * STMicroelectronics LSM9DS0 IMU driver
+ *
+ * Copyright (C) 2021, Intel Corporation
+ *
+ * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/common/st_sensors_spi.h>
+
+#include "st_lsm9ds0.h"
+
+static const struct of_device_id st_lsm9ds0_of_match[] = {
+ {
+ .compatible = "st,lsm9ds0-imu",
+ .data = LSM9DS0_IMU_DEV_NAME,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match);
+
+static const struct spi_device_id st_lsm9ds0_id_table[] = {
+ { LSM9DS0_IMU_DEV_NAME },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, st_lsm9ds0_id_table);
+
+static const struct regmap_config st_lsm9ds0_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .read_flag_mask = 0xc0,
+};
+
+static int st_lsm9ds0_spi_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct st_lsm9ds0 *lsm9ds0;
+ struct regmap *regmap;
+
+ st_sensors_dev_name_probe(dev, spi->modalias, sizeof(spi->modalias));
+
+ lsm9ds0 = devm_kzalloc(dev, sizeof(*lsm9ds0), GFP_KERNEL);
+ if (!lsm9ds0)
+ return -ENOMEM;
+
+ lsm9ds0->dev = dev;
+ lsm9ds0->name = spi->modalias;
+ lsm9ds0->irq = spi->irq;
+
+ regmap = devm_regmap_init_spi(spi, &st_lsm9ds0_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ spi_set_drvdata(spi, lsm9ds0);
+
+ return st_lsm9ds0_probe(lsm9ds0, regmap);
+}
+
+static int st_lsm9ds0_spi_remove(struct spi_device *spi)
+{
+ return st_lsm9ds0_remove(spi_get_drvdata(spi));
+}
+
+static struct spi_driver st_lsm9ds0_driver = {
+ .driver = {
+ .name = "st-lsm9ds0-spi",
+ .of_match_table = st_lsm9ds0_of_match,
+ },
+ .probe = st_lsm9ds0_spi_probe,
+ .remove = st_lsm9ds0_spi_remove,
+ .id_table = st_lsm9ds0_id_table,
+};
+module_spi_driver(st_lsm9ds0_driver);
+
+MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
+MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 9a8e16c7e9af..fdd623407b96 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -601,8 +601,10 @@ static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev,
static unsigned int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+
return iio_storage_bytes_for_si(indio_dev,
- indio_dev->scan_index_timestamp);
+ iio_dev_opaque->scan_index_timestamp);
}
static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
@@ -924,7 +926,6 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
if (ret)
goto error_clear_mux_table;
out_loc += length;
- in_loc += length;
}
buffer->demux_bounce = kzalloc(out_loc, GFP_KERNEL);
if (buffer->demux_bounce == NULL) {
@@ -1148,12 +1149,13 @@ int iio_update_buffers(struct iio_dev *indio_dev,
struct iio_buffer *insert_buffer,
struct iio_buffer *remove_buffer)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
int ret;
if (insert_buffer == remove_buffer)
return 0;
- mutex_lock(&indio_dev->info_exist_lock);
+ mutex_lock(&iio_dev_opaque->info_exist_lock);
mutex_lock(&indio_dev->mlock);
if (insert_buffer && iio_buffer_is_active(insert_buffer))
@@ -1176,7 +1178,7 @@ int iio_update_buffers(struct iio_dev *indio_dev,
out_unlock:
mutex_unlock(&indio_dev->mlock);
- mutex_unlock(&indio_dev->info_exist_lock);
+ mutex_unlock(&iio_dev_opaque->info_exist_lock);
return ret;
}
@@ -1469,6 +1471,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
struct iio_dev *indio_dev,
int index)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
struct iio_dev_attr *p;
struct attribute **attr;
int ret, i, attrn, scan_el_attrcount, buffer_attrcount;
@@ -1495,7 +1498,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
goto error_cleanup_dynamic;
scan_el_attrcount += ret;
if (channels[i].type == IIO_TIMESTAMP)
- indio_dev->scan_index_timestamp =
+ iio_dev_opaque->scan_index_timestamp =
channels[i].scan_index;
}
if (indio_dev->masklength && buffer->scan_mask == NULL) {
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 59efb36db2c7..6d2175eb7af2 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -169,6 +169,20 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_THERMOCOUPLE_TYPE] = "thermocouple_type",
[IIO_CHAN_INFO_CALIBAMBIENT] = "calibambient",
};
+/**
+ * iio_device_id() - query the unique ID for the device
+ * @indio_dev: Device structure whose ID is being queried
+ *
+ * The IIO device ID is a unique index used for example for the naming
+ * of the character device /dev/iio\:device[ID]
+ */
+int iio_device_id(struct iio_dev *indio_dev)
+{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+
+ return iio_dev_opaque->id;
+}
+EXPORT_SYMBOL_GPL(iio_device_id);
/**
* iio_sysfs_match_string_with_gaps - matches given string in an array with gaps
@@ -257,7 +271,7 @@ int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
- indio_dev->clock_id = clock_id;
+ iio_dev_opaque->clock_id = clock_id;
mutex_unlock(&indio_dev->mlock);
return 0;
@@ -265,6 +279,18 @@ int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
EXPORT_SYMBOL(iio_device_set_clock);
/**
+ * iio_device_get_clock() - Retrieve current timestamping clock for the device
+ * @indio_dev: IIO device structure containing the device
+ */
+clockid_t iio_device_get_clock(const struct iio_dev *indio_dev)
+{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+
+ return iio_dev_opaque->clock_id;
+}
+EXPORT_SYMBOL(iio_device_get_clock);
+
+/**
* iio_get_time_ns() - utility function to get a time stamp for events etc
* @indio_dev: device
*/
@@ -591,7 +617,6 @@ EXPORT_SYMBOL_GPL(iio_show_mount_matrix);
* iio_read_mount_matrix() - retrieve iio device mounting matrix from
* device "mount-matrix" property
* @dev: device the mounting matrix property is assigned to
- * @propname: device specific mounting matrix property name
* @matrix: where to store retrieved matrix
*
* If device is assigned no mounting matrix property, a default 3x3 identity
@@ -599,14 +624,12 @@ EXPORT_SYMBOL_GPL(iio_show_mount_matrix);
*
* Return: 0 if success, or a negative error code on failure.
*/
-int iio_read_mount_matrix(struct device *dev, const char *propname,
- struct iio_mount_matrix *matrix)
+int iio_read_mount_matrix(struct device *dev, struct iio_mount_matrix *matrix)
{
size_t len = ARRAY_SIZE(iio_mount_idmatrix.rotation);
int err;
- err = device_property_read_string_array(dev, propname,
- matrix->rotation, len);
+ err = device_property_read_string_array(dev, "mount-matrix", matrix->rotation, len);
if (err == len)
return 0;
@@ -1588,7 +1611,7 @@ static void iio_dev_release(struct device *device)
iio_device_detach_buffers(indio_dev);
- ida_simple_remove(&iio_ida, indio_dev->id);
+ ida_simple_remove(&iio_ida, iio_dev_opaque->id);
kfree(iio_dev_opaque);
}
@@ -1628,17 +1651,17 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
device_initialize(&indio_dev->dev);
iio_device_set_drvdata(indio_dev, (void *)indio_dev);
mutex_init(&indio_dev->mlock);
- mutex_init(&indio_dev->info_exist_lock);
+ mutex_init(&iio_dev_opaque->info_exist_lock);
INIT_LIST_HEAD(&iio_dev_opaque->channel_attr_list);
- indio_dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
- if (indio_dev->id < 0) {
+ iio_dev_opaque->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
+ if (iio_dev_opaque->id < 0) {
/* cannot use a dev_err as the name isn't available */
pr_err("failed to get device id\n");
kfree(iio_dev_opaque);
return NULL;
}
- dev_set_name(&indio_dev->dev, "iio:device%d", indio_dev->id);
+ dev_set_name(&indio_dev->dev, "iio:device%d", iio_dev_opaque->id);
INIT_LIST_HEAD(&iio_dev_opaque->buffer_list);
INIT_LIST_HEAD(&iio_dev_opaque->ioctl_handlers);
@@ -1657,9 +1680,9 @@ void iio_device_free(struct iio_dev *dev)
}
EXPORT_SYMBOL(iio_device_free);
-static void devm_iio_device_release(struct device *dev, void *res)
+static void devm_iio_device_release(void *iio_dev)
{
- iio_device_free(*(struct iio_dev **)res);
+ iio_device_free(iio_dev);
}
/**
@@ -1675,20 +1698,17 @@ static void devm_iio_device_release(struct device *dev, void *res)
*/
struct iio_dev *devm_iio_device_alloc(struct device *parent, int sizeof_priv)
{
- struct iio_dev **ptr, *iio_dev;
+ struct iio_dev *iio_dev;
+ int ret;
- ptr = devres_alloc(devm_iio_device_release, sizeof(*ptr),
- GFP_KERNEL);
- if (!ptr)
+ iio_dev = iio_device_alloc(parent, sizeof_priv);
+ if (!iio_dev)
return NULL;
- iio_dev = iio_device_alloc(parent, sizeof_priv);
- if (iio_dev) {
- *ptr = iio_dev;
- devres_add(parent, ptr);
- } else {
- devres_free(ptr);
- }
+ ret = devm_add_action_or_reset(parent, devm_iio_device_release,
+ iio_dev);
+ if (ret)
+ return NULL;
return iio_dev;
}
@@ -1704,11 +1724,12 @@ EXPORT_SYMBOL_GPL(devm_iio_device_alloc);
**/
static int iio_chrdev_open(struct inode *inode, struct file *filp)
{
- struct iio_dev *indio_dev = container_of(inode->i_cdev,
- struct iio_dev, chrdev);
+ struct iio_dev_opaque *iio_dev_opaque =
+ container_of(inode->i_cdev, struct iio_dev_opaque, chrdev);
+ struct iio_dev *indio_dev = &iio_dev_opaque->indio_dev;
struct iio_dev_buffer_pair *ib;
- if (test_and_set_bit(IIO_BUSY_BIT_POS, &indio_dev->flags))
+ if (test_and_set_bit(IIO_BUSY_BIT_POS, &iio_dev_opaque->flags))
return -EBUSY;
iio_device_get(indio_dev);
@@ -1716,7 +1737,7 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp)
ib = kmalloc(sizeof(*ib), GFP_KERNEL);
if (!ib) {
iio_device_put(indio_dev);
- clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags);
+ clear_bit(IIO_BUSY_BIT_POS, &iio_dev_opaque->flags);
return -ENOMEM;
}
@@ -1738,10 +1759,11 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp)
static int iio_chrdev_release(struct inode *inode, struct file *filp)
{
struct iio_dev_buffer_pair *ib = filp->private_data;
- struct iio_dev *indio_dev = container_of(inode->i_cdev,
- struct iio_dev, chrdev);
+ struct iio_dev_opaque *iio_dev_opaque =
+ container_of(inode->i_cdev, struct iio_dev_opaque, chrdev);
+ struct iio_dev *indio_dev = &iio_dev_opaque->indio_dev;
kfree(ib);
- clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags);
+ clear_bit(IIO_BUSY_BIT_POS, &iio_dev_opaque->flags);
iio_device_put(indio_dev);
return 0;
@@ -1768,7 +1790,7 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
struct iio_ioctl_handler *h;
int ret = -ENODEV;
- mutex_lock(&indio_dev->info_exist_lock);
+ mutex_lock(&iio_dev_opaque->info_exist_lock);
/**
* The NULL check here is required to prevent crashing when a device
@@ -1788,7 +1810,7 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
ret = -ENODEV;
out_unlock:
- mutex_unlock(&indio_dev->info_exist_lock);
+ mutex_unlock(&iio_dev_opaque->info_exist_lock);
return ret;
}
@@ -1847,7 +1869,7 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
if (!indio_dev->info)
return -EINVAL;
- indio_dev->driver_module = this_mod;
+ iio_dev_opaque->driver_module = this_mod;
/* If the calling driver did not initialize of_node, do it here */
if (!indio_dev->dev.of_node && indio_dev->dev.parent)
indio_dev->dev.of_node = indio_dev->dev.parent->of_node;
@@ -1889,19 +1911,19 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
indio_dev->setup_ops = &noop_ring_setup_ops;
if (iio_dev_opaque->attached_buffers_cnt)
- cdev_init(&indio_dev->chrdev, &iio_buffer_fileops);
+ cdev_init(&iio_dev_opaque->chrdev, &iio_buffer_fileops);
else if (iio_dev_opaque->event_interface)
- cdev_init(&indio_dev->chrdev, &iio_event_fileops);
+ cdev_init(&iio_dev_opaque->chrdev, &iio_event_fileops);
if (iio_dev_opaque->attached_buffers_cnt || iio_dev_opaque->event_interface) {
- indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
- indio_dev->chrdev.owner = this_mod;
+ indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), iio_dev_opaque->id);
+ iio_dev_opaque->chrdev.owner = this_mod;
}
/* assign device groups now; they should be all registered now */
indio_dev->dev.groups = iio_dev_opaque->groups;
- ret = cdev_device_add(&indio_dev->chrdev, &indio_dev->dev);
+ ret = cdev_device_add(&iio_dev_opaque->chrdev, &indio_dev->dev);
if (ret < 0)
goto error_unreg_eventset;
@@ -1925,9 +1947,11 @@ EXPORT_SYMBOL(__iio_device_register);
**/
void iio_device_unregister(struct iio_dev *indio_dev)
{
- cdev_device_del(&indio_dev->chrdev, &indio_dev->dev);
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
- mutex_lock(&indio_dev->info_exist_lock);
+ cdev_device_del(&iio_dev_opaque->chrdev, &indio_dev->dev);
+
+ mutex_lock(&iio_dev_opaque->info_exist_lock);
iio_device_unregister_debugfs(indio_dev);
@@ -1938,35 +1962,27 @@ void iio_device_unregister(struct iio_dev *indio_dev)
iio_device_wakeup_eventset(indio_dev);
iio_buffer_wakeup_poll(indio_dev);
- mutex_unlock(&indio_dev->info_exist_lock);
+ mutex_unlock(&iio_dev_opaque->info_exist_lock);
iio_buffers_free_sysfs_and_mask(indio_dev);
}
EXPORT_SYMBOL(iio_device_unregister);
-static void devm_iio_device_unreg(struct device *dev, void *res)
+static void devm_iio_device_unreg(void *indio_dev)
{
- iio_device_unregister(*(struct iio_dev **)res);
+ iio_device_unregister(indio_dev);
}
int __devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev,
struct module *this_mod)
{
- struct iio_dev **ptr;
int ret;
- ptr = devres_alloc(devm_iio_device_unreg, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return -ENOMEM;
-
- *ptr = indio_dev;
ret = __iio_device_register(indio_dev, this_mod);
- if (!ret)
- devres_add(dev, ptr);
- else
- devres_free(ptr);
+ if (ret)
+ return ret;
- return ret;
+ return devm_add_action_or_reset(dev, devm_iio_device_unreg, indio_dev);
}
EXPORT_SYMBOL_GPL(__devm_iio_device_register);
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index b2c94abbb487..b23caa2f2aa1 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/iio/iio.h>
+#include <linux/iio/iio-opaque.h>
#include <linux/iio/trigger.h>
#include "iio_core.h"
#include "iio_core_trigger.h"
@@ -116,14 +117,17 @@ EXPORT_SYMBOL(iio_trigger_unregister);
int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *trig)
{
+ struct iio_dev_opaque *iio_dev_opaque;
+
if (!indio_dev || !trig)
return -EINVAL;
+ iio_dev_opaque = to_iio_dev_opaque(indio_dev);
mutex_lock(&indio_dev->mlock);
- WARN_ON(indio_dev->trig_readonly);
+ WARN_ON(iio_dev_opaque->trig_readonly);
indio_dev->trig = iio_trigger_get(trig);
- indio_dev->trig_readonly = true;
+ iio_dev_opaque->trig_readonly = true;
mutex_unlock(&indio_dev->mlock);
return 0;
@@ -240,12 +244,13 @@ static void iio_trigger_put_irq(struct iio_trigger *trig, int irq)
int iio_trigger_attach_poll_func(struct iio_trigger *trig,
struct iio_poll_func *pf)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(pf->indio_dev);
bool notinuse =
bitmap_empty(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
int ret = 0;
/* Prevent the module from being removed whilst attached to a trigger */
- __module_get(pf->indio_dev->driver_module);
+ __module_get(iio_dev_opaque->driver_module);
/* Get irq number */
pf->irq = iio_trigger_get_irq(trig);
@@ -284,13 +289,14 @@ out_free_irq:
out_put_irq:
iio_trigger_put_irq(trig, pf->irq);
out_put_module:
- module_put(pf->indio_dev->driver_module);
+ module_put(iio_dev_opaque->driver_module);
return ret;
}
int iio_trigger_detach_poll_func(struct iio_trigger *trig,
struct iio_poll_func *pf)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(pf->indio_dev);
bool no_other_users =
bitmap_weight(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER) == 1;
int ret = 0;
@@ -304,7 +310,7 @@ int iio_trigger_detach_poll_func(struct iio_trigger *trig,
trig->attached_own_device = false;
iio_trigger_put_irq(trig, pf->irq);
free_irq(pf->irq, pf);
- module_put(pf->indio_dev->driver_module);
+ module_put(iio_dev_opaque->driver_module);
return ret;
}
@@ -399,6 +405,7 @@ static ssize_t iio_trigger_write_current(struct device *dev,
size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
struct iio_trigger *oldtrig = indio_dev->trig;
struct iio_trigger *trig;
int ret;
@@ -408,7 +415,7 @@ static ssize_t iio_trigger_write_current(struct device *dev,
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
- if (indio_dev->trig_readonly) {
+ if (iio_dev_opaque->trig_readonly) {
mutex_unlock(&indio_dev->mlock);
return -EPERM;
}
@@ -634,9 +641,9 @@ struct iio_trigger *devm_iio_trigger_alloc(struct device *parent, const char *fm
}
EXPORT_SYMBOL_GPL(devm_iio_trigger_alloc);
-static void devm_iio_trigger_unreg(struct device *dev, void *res)
+static void devm_iio_trigger_unreg(void *trigger_info)
{
- iio_trigger_unregister(*(struct iio_trigger **)res);
+ iio_trigger_unregister(trigger_info);
}
/**
@@ -657,21 +664,13 @@ int __devm_iio_trigger_register(struct device *dev,
struct iio_trigger *trig_info,
struct module *this_mod)
{
- struct iio_trigger **ptr;
int ret;
- ptr = devres_alloc(devm_iio_trigger_unreg, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return -ENOMEM;
-
- *ptr = trig_info;
ret = __iio_trigger_register(trig_info, this_mod);
- if (!ret)
- devres_add(dev, ptr);
- else
- devres_free(ptr);
+ if (ret)
+ return ret;
- return ret;
+ return devm_add_action_or_reset(dev, devm_iio_trigger_unreg, trig_info);
}
EXPORT_SYMBOL_GPL(__devm_iio_trigger_register);
diff --git a/drivers/iio/industrialio-triggered-event.c b/drivers/iio/industrialio-triggered-event.c
index 53da9ab17a62..4bedc65c9fe3 100644
--- a/drivers/iio/industrialio-triggered-event.c
+++ b/drivers/iio/industrialio-triggered-event.c
@@ -37,7 +37,7 @@ int iio_triggered_event_setup(struct iio_dev *indio_dev,
indio_dev,
"%s_consumer%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (indio_dev->pollfunc_event == NULL)
return -ENOMEM;
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 9c22697b7e83..391a3380a1d1 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -10,6 +10,7 @@
#include <linux/of.h>
#include <linux/iio/iio.h>
+#include <linux/iio/iio-opaque.h>
#include "iio_core.h"
#include <linux/iio/machine.h>
#include <linux/iio/driver.h>
@@ -359,30 +360,24 @@ void iio_channel_release(struct iio_channel *channel)
}
EXPORT_SYMBOL_GPL(iio_channel_release);
-static void devm_iio_channel_free(struct device *dev, void *res)
+static void devm_iio_channel_free(void *iio_channel)
{
- struct iio_channel *channel = *(struct iio_channel **)res;
-
- iio_channel_release(channel);
+ iio_channel_release(iio_channel);
}
struct iio_channel *devm_iio_channel_get(struct device *dev,
const char *channel_name)
{
- struct iio_channel **ptr, *channel;
-
- ptr = devres_alloc(devm_iio_channel_free, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return ERR_PTR(-ENOMEM);
+ struct iio_channel *channel;
+ int ret;
channel = iio_channel_get(dev, channel_name);
- if (IS_ERR(channel)) {
- devres_free(ptr);
+ if (IS_ERR(channel))
return channel;
- }
- *ptr = channel;
- devres_add(dev, ptr);
+ ret = devm_add_action_or_reset(dev, devm_iio_channel_free, channel);
+ if (ret)
+ return ERR_PTR(ret);
return channel;
}
@@ -392,20 +387,16 @@ struct iio_channel *devm_of_iio_channel_get_by_name(struct device *dev,
struct device_node *np,
const char *channel_name)
{
- struct iio_channel **ptr, *channel;
-
- ptr = devres_alloc(devm_iio_channel_free, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return ERR_PTR(-ENOMEM);
+ struct iio_channel *channel;
+ int ret;
channel = of_iio_channel_get_by_name(np, channel_name);
- if (IS_ERR(channel)) {
- devres_free(ptr);
+ if (IS_ERR(channel))
return channel;
- }
- *ptr = channel;
- devres_add(dev, ptr);
+ ret = devm_add_action_or_reset(dev, devm_iio_channel_free, channel);
+ if (ret)
+ return ERR_PTR(ret);
return channel;
}
@@ -496,29 +487,24 @@ void iio_channel_release_all(struct iio_channel *channels)
}
EXPORT_SYMBOL_GPL(iio_channel_release_all);
-static void devm_iio_channel_free_all(struct device *dev, void *res)
+static void devm_iio_channel_free_all(void *iio_channels)
{
- struct iio_channel *channels = *(struct iio_channel **)res;
-
- iio_channel_release_all(channels);
+ iio_channel_release_all(iio_channels);
}
struct iio_channel *devm_iio_channel_get_all(struct device *dev)
{
- struct iio_channel **ptr, *channels;
-
- ptr = devres_alloc(devm_iio_channel_free_all, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return ERR_PTR(-ENOMEM);
+ struct iio_channel *channels;
+ int ret;
channels = iio_channel_get_all(dev);
- if (IS_ERR(channels)) {
- devres_free(ptr);
+ if (IS_ERR(channels))
return channels;
- }
- *ptr = channels;
- devres_add(dev, ptr);
+ ret = devm_add_action_or_reset(dev, devm_iio_channel_free_all,
+ channels);
+ if (ret)
+ return ERR_PTR(ret);
return channels;
}
@@ -553,9 +539,10 @@ static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
int iio_read_channel_raw(struct iio_channel *chan, int *val)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev);
int ret;
- mutex_lock(&chan->indio_dev->info_exist_lock);
+ mutex_lock(&iio_dev_opaque->info_exist_lock);
if (chan->indio_dev->info == NULL) {
ret = -ENODEV;
goto err_unlock;
@@ -563,7 +550,7 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val)
ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
err_unlock:
- mutex_unlock(&chan->indio_dev->info_exist_lock);
+ mutex_unlock(&iio_dev_opaque->info_exist_lock);
return ret;
}
@@ -571,9 +558,10 @@ EXPORT_SYMBOL_GPL(iio_read_channel_raw);
int iio_read_channel_average_raw(struct iio_channel *chan, int *val)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev);
int ret;
- mutex_lock(&chan->indio_dev->info_exist_lock);
+ mutex_lock(&iio_dev_opaque->info_exist_lock);
if (chan->indio_dev->info == NULL) {
ret = -ENODEV;
goto err_unlock;
@@ -581,7 +569,7 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val)
ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_AVERAGE_RAW);
err_unlock:
- mutex_unlock(&chan->indio_dev->info_exist_lock);
+ mutex_unlock(&iio_dev_opaque->info_exist_lock);
return ret;
}
@@ -646,9 +634,10 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
int *processed, unsigned int scale)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev);
int ret;
- mutex_lock(&chan->indio_dev->info_exist_lock);
+ mutex_lock(&iio_dev_opaque->info_exist_lock);
if (chan->indio_dev->info == NULL) {
ret = -ENODEV;
goto err_unlock;
@@ -657,7 +646,7 @@ int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
ret = iio_convert_raw_to_processed_unlocked(chan, raw, processed,
scale);
err_unlock:
- mutex_unlock(&chan->indio_dev->info_exist_lock);
+ mutex_unlock(&iio_dev_opaque->info_exist_lock);
return ret;
}
@@ -666,9 +655,10 @@ EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed);
int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2,
enum iio_chan_info_enum attribute)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev);
int ret;
- mutex_lock(&chan->indio_dev->info_exist_lock);
+ mutex_lock(&iio_dev_opaque->info_exist_lock);
if (chan->indio_dev->info == NULL) {
ret = -ENODEV;
goto err_unlock;
@@ -676,7 +666,7 @@ int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2,
ret = iio_channel_read(chan, val, val2, attribute);
err_unlock:
- mutex_unlock(&chan->indio_dev->info_exist_lock);
+ mutex_unlock(&iio_dev_opaque->info_exist_lock);
return ret;
}
@@ -691,9 +681,10 @@ EXPORT_SYMBOL_GPL(iio_read_channel_offset);
int iio_read_channel_processed_scale(struct iio_channel *chan, int *val,
unsigned int scale)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev);
int ret;
- mutex_lock(&chan->indio_dev->info_exist_lock);
+ mutex_lock(&iio_dev_opaque->info_exist_lock);
if (chan->indio_dev->info == NULL) {
ret = -ENODEV;
goto err_unlock;
@@ -714,7 +705,7 @@ int iio_read_channel_processed_scale(struct iio_channel *chan, int *val,
}
err_unlock:
- mutex_unlock(&chan->indio_dev->info_exist_lock);
+ mutex_unlock(&iio_dev_opaque->info_exist_lock);
return ret;
}
@@ -748,9 +739,10 @@ int iio_read_avail_channel_attribute(struct iio_channel *chan,
const int **vals, int *type, int *length,
enum iio_chan_info_enum attribute)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev);
int ret;
- mutex_lock(&chan->indio_dev->info_exist_lock);
+ mutex_lock(&iio_dev_opaque->info_exist_lock);
if (!chan->indio_dev->info) {
ret = -ENODEV;
goto err_unlock;
@@ -758,7 +750,7 @@ int iio_read_avail_channel_attribute(struct iio_channel *chan,
ret = iio_channel_read_avail(chan, vals, type, length, attribute);
err_unlock:
- mutex_unlock(&chan->indio_dev->info_exist_lock);
+ mutex_unlock(&iio_dev_opaque->info_exist_lock);
return ret;
}
@@ -830,10 +822,11 @@ static int iio_channel_read_max(struct iio_channel *chan,
int iio_read_max_channel_raw(struct iio_channel *chan, int *val)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev);
int ret;
int type;
- mutex_lock(&chan->indio_dev->info_exist_lock);
+ mutex_lock(&iio_dev_opaque->info_exist_lock);
if (!chan->indio_dev->info) {
ret = -ENODEV;
goto err_unlock;
@@ -841,7 +834,7 @@ int iio_read_max_channel_raw(struct iio_channel *chan, int *val)
ret = iio_channel_read_max(chan, val, NULL, &type, IIO_CHAN_INFO_RAW);
err_unlock:
- mutex_unlock(&chan->indio_dev->info_exist_lock);
+ mutex_unlock(&iio_dev_opaque->info_exist_lock);
return ret;
}
@@ -849,10 +842,11 @@ EXPORT_SYMBOL_GPL(iio_read_max_channel_raw);
int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev);
int ret = 0;
/* Need to verify underlying driver has not gone away */
- mutex_lock(&chan->indio_dev->info_exist_lock);
+ mutex_lock(&iio_dev_opaque->info_exist_lock);
if (chan->indio_dev->info == NULL) {
ret = -ENODEV;
goto err_unlock;
@@ -860,7 +854,7 @@ int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type)
*type = chan->channel->type;
err_unlock:
- mutex_unlock(&chan->indio_dev->info_exist_lock);
+ mutex_unlock(&iio_dev_opaque->info_exist_lock);
return ret;
}
@@ -876,9 +870,10 @@ static int iio_channel_write(struct iio_channel *chan, int val, int val2,
int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2,
enum iio_chan_info_enum attribute)
{
+ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev);
int ret;
- mutex_lock(&chan->indio_dev->info_exist_lock);
+ mutex_lock(&iio_dev_opaque->info_exist_lock);
if (chan->indio_dev->info == NULL) {
ret = -ENODEV;
goto err_unlock;
@@ -886,7 +881,7 @@ int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2,
ret = iio_channel_write(chan, val, val2, attribute);
err_unlock:
- mutex_unlock(&chan->indio_dev->info_exist_lock);
+ mutex_unlock(&iio_dev_opaque->info_exist_lock);
return ret;
}
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 917f9becf9c7..a62c7b4b8678 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -499,6 +499,17 @@ config TSL2583
Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices.
Access ALS data via iio, sysfs.
+config TSL2591
+ tristate "TAOS TSL2591 ambient light sensor"
+ depends on I2C
+ help
+ Select Y here for support of the AMS/TAOS TSL2591 ambient light sensor,
+ featuring channels for combined visible + IR intensity and lux illuminance.
+ Access data via iio and sysfs. Supports iio_events.
+
+ To compile this driver as a module, select M: the
+ module will be called tsl2591.
+
config TSL2772
tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors"
depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index ea376deaca54..d10912faf964 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_ST_UVIS25_SPI) += st_uvis25_spi.o
obj-$(CONFIG_TCS3414) += tcs3414.o
obj-$(CONFIG_TCS3472) += tcs3472.o
obj-$(CONFIG_TSL2583) += tsl2583.o
+obj-$(CONFIG_TSL2591) += tsl2591.o
obj-$(CONFIG_TSL2772) += tsl2772.o
obj-$(CONFIG_TSL4531) += tsl4531.o
obj-$(CONFIG_US5182D) += us5182d.o
diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c
index 0a6ab5761eec..e1ff6f524f4b 100644
--- a/drivers/iio/light/acpi-als.c
+++ b/drivers/iio/light/acpi-als.c
@@ -204,7 +204,8 @@ static int acpi_als_add(struct acpi_device *device)
indio_dev->channels = acpi_als_channels;
indio_dev->num_channels = ARRAY_SIZE(acpi_als_channels);
- als->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, indio_dev->id);
+ als->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
+ iio_device_id(indio_dev));
if (!als->trig)
return -ENOMEM;
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index 85c8a05b73cb..2ff252c75c03 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -6,13 +6,10 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
+#include <linux/mod_devicetable.h>
#include <linux/slab.h>
-#include <linux/delay.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
@@ -392,3 +389,4 @@ module_platform_driver(hid_als_platform_driver);
MODULE_DESCRIPTION("HID Sensor ALS");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HID);
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
index 17d167c3d595..1621530f5f61 100644
--- a/drivers/iio/light/hid-sensor-prox.c
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -6,13 +6,10 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
+#include <linux/mod_devicetable.h>
#include <linux/slab.h>
-#include <linux/delay.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
@@ -350,3 +347,4 @@ module_platform_driver(hid_prox_platform_driver);
MODULE_DESCRIPTION("HID Sensor Proximity");
MODULE_AUTHOR("Archana Patni <archana.patni@intel.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HID);
diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c
index 2f8b494f3e08..9de3262aa688 100644
--- a/drivers/iio/light/isl29028.c
+++ b/drivers/iio/light/isl29028.c
@@ -339,9 +339,7 @@ static int isl29028_set_pm_runtime_busy(struct isl29028_chip *chip, bool on)
int ret;
if (on) {
- ret = pm_runtime_get_sync(dev);
- if (ret < 0)
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
} else {
pm_runtime_mark_last_busy(dev);
ret = pm_runtime_put_autosuspend(dev);
@@ -647,7 +645,6 @@ static int isl29028_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
return isl29028_clear_configure_reg(chip);
}
diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c
index b93b85dbc3a6..ba53b50d711a 100644
--- a/drivers/iio/light/isl29125.c
+++ b/drivers/iio/light/isl29125.c
@@ -51,7 +51,11 @@
struct isl29125_data {
struct i2c_client *client;
u8 conf1;
- u16 buffer[8]; /* 3x 16-bit, padding, 8 bytes timestamp */
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ u16 chans[3];
+ s64 timestamp __aligned(8);
+ } scan;
};
#define ISL29125_CHANNEL(_color, _si) { \
@@ -184,10 +188,10 @@ static irqreturn_t isl29125_trigger_handler(int irq, void *p)
if (ret < 0)
goto done;
- data->buffer[j++] = ret;
+ data->scan.chans[j++] = ret;
}
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
iio_get_time_ns(indio_dev));
done:
diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c
index b4323d2db0b1..1830221da48d 100644
--- a/drivers/iio/light/ltr501.c
+++ b/drivers/iio/light/ltr501.c
@@ -32,9 +32,12 @@
#define LTR501_PART_ID 0x86
#define LTR501_MANUFAC_ID 0x87
#define LTR501_ALS_DATA1 0x88 /* 16-bit, little endian */
+#define LTR501_ALS_DATA1_UPPER 0x89 /* upper 8 bits of LTR501_ALS_DATA1 */
#define LTR501_ALS_DATA0 0x8a /* 16-bit, little endian */
+#define LTR501_ALS_DATA0_UPPER 0x8b /* upper 8 bits of LTR501_ALS_DATA0 */
#define LTR501_ALS_PS_STATUS 0x8c
#define LTR501_PS_DATA 0x8d /* 16-bit, little endian */
+#define LTR501_PS_DATA_UPPER 0x8e /* upper 8 bits of LTR501_PS_DATA */
#define LTR501_INTR 0x8f /* output mode, polarity, mode */
#define LTR501_PS_THRESH_UP 0x90 /* 11 bit, ps upper threshold */
#define LTR501_PS_THRESH_LOW 0x92 /* 11 bit, ps lower threshold */
@@ -149,7 +152,7 @@ struct ltr501_chip_info {
struct ltr501_data {
struct i2c_client *client;
struct mutex lock_als, lock_ps;
- struct ltr501_chip_info *chip_info;
+ const struct ltr501_chip_info *chip_info;
u8 als_contr, ps_contr;
int als_period, ps_period; /* period in micro seconds */
struct regmap *regmap;
@@ -406,18 +409,19 @@ static int ltr501_read_als(const struct ltr501_data *data, __le16 buf[2])
static int ltr501_read_ps(const struct ltr501_data *data)
{
- int ret, status;
+ __le16 status;
+ int ret;
ret = ltr501_drdy(data, LTR501_STATUS_PS_RDY);
if (ret < 0)
return ret;
ret = regmap_bulk_read(data->regmap, LTR501_PS_DATA,
- &status, 2);
+ &status, sizeof(status));
if (ret < 0)
return ret;
- return status;
+ return le16_to_cpu(status);
}
static int ltr501_read_intr_prst(const struct ltr501_data *data,
@@ -735,7 +739,7 @@ static int ltr501_write_raw(struct iio_dev *indio_dev,
{
struct ltr501_data *data = iio_priv(indio_dev);
int i, ret, freq_val, freq_val2;
- struct ltr501_chip_info *info = data->chip_info;
+ const struct ltr501_chip_info *info = data->chip_info;
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
@@ -1082,7 +1086,7 @@ static ssize_t ltr501_show_proximity_scale_avail(struct device *dev,
char *buf)
{
struct ltr501_data *data = iio_priv(dev_to_iio_dev(dev));
- struct ltr501_chip_info *info = data->chip_info;
+ const struct ltr501_chip_info *info = data->chip_info;
ssize_t len = 0;
int i;
@@ -1104,7 +1108,7 @@ static ssize_t ltr501_show_intensity_scale_avail(struct device *dev,
char *buf)
{
struct ltr501_data *data = iio_priv(dev_to_iio_dev(dev));
- struct ltr501_chip_info *info = data->chip_info;
+ const struct ltr501_chip_info *info = data->chip_info;
ssize_t len = 0;
int i;
@@ -1184,7 +1188,7 @@ static const struct iio_info ltr301_info = {
.write_event_config = &ltr501_write_event_config,
};
-static struct ltr501_chip_info ltr501_chip_info_tbl[] = {
+static const struct ltr501_chip_info ltr501_chip_info_tbl[] = {
[ltr501] = {
.partid = 0x08,
.als_gain = ltr501_als_gain_tbl,
@@ -1205,7 +1209,7 @@ static struct ltr501_chip_info ltr501_chip_info_tbl[] = {
.als_gain_tbl_size = ARRAY_SIZE(ltr559_als_gain_tbl),
.ps_gain = ltr559_ps_gain_tbl,
.ps_gain_tbl_size = ARRAY_SIZE(ltr559_ps_gain_tbl),
- .als_mode_active = BIT(1),
+ .als_mode_active = BIT(0),
.als_gain_mask = BIT(2) | BIT(3) | BIT(4),
.als_gain_shift = 2,
.info = &ltr501_info,
@@ -1354,9 +1358,12 @@ static bool ltr501_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case LTR501_ALS_DATA1:
+ case LTR501_ALS_DATA1_UPPER:
case LTR501_ALS_DATA0:
+ case LTR501_ALS_DATA0_UPPER:
case LTR501_ALS_PS_STATUS:
case LTR501_PS_DATA:
+ case LTR501_PS_DATA_UPPER:
return true;
default:
return false;
diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c
index bfade6577a38..a52b2c788540 100644
--- a/drivers/iio/light/pa12203001.c
+++ b/drivers/iio/light/pa12203001.c
@@ -186,9 +186,7 @@ static int pa12203001_set_power_state(struct pa12203001_data *data, bool on,
}
if (on) {
- ret = pm_runtime_get_sync(&data->client->dev);
- if (ret < 0)
- pm_runtime_put_noidle(&data->client->dev);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
} else {
pm_runtime_mark_last_busy(&data->client->dev);
diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c
index 033578f444e4..c2dd8a3d4217 100644
--- a/drivers/iio/light/rpr0521.c
+++ b/drivers/iio/light/rpr0521.c
@@ -360,7 +360,7 @@ static int rpr0521_set_power_state(struct rpr0521_data *data, bool on,
* both stay enabled until _suspend().
*/
if (on) {
- ret = pm_runtime_get_sync(&data->client->dev);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
} else {
pm_runtime_mark_last_busy(&data->client->dev);
ret = pm_runtime_put_autosuspend(&data->client->dev);
@@ -369,9 +369,6 @@ static int rpr0521_set_power_state(struct rpr0521_data *data, bool on,
dev_err(&data->client->dev,
"Failed: rpr0521_set_power_state for %d, ret %d\n",
on, ret);
- if (on)
- pm_runtime_put_noidle(&data->client->dev);
-
return ret;
}
@@ -985,7 +982,7 @@ static int rpr0521_probe(struct i2c_client *client,
/* Trigger0 producer setup */
data->drdy_trigger0 = devm_iio_trigger_alloc(
indio_dev->dev.parent,
- "%s-dev%d", indio_dev->name, indio_dev->id);
+ "%s-dev%d", indio_dev->name, iio_device_id(indio_dev));
if (!data->drdy_trigger0) {
ret = -ENOMEM;
goto err_pm_disable;
@@ -1038,7 +1035,6 @@ static int rpr0521_probe(struct i2c_client *client,
err_pm_disable:
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
err_poweroff:
rpr0521_poweroff(data);
@@ -1053,7 +1049,6 @@ static int rpr0521_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
rpr0521_poweroff(iio_priv(indio_dev));
diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c
index c280b4195003..f8c9b2cc322e 100644
--- a/drivers/iio/light/si1133.c
+++ b/drivers/iio/light/si1133.c
@@ -352,22 +352,22 @@ static int si1133_parse_response_err(struct device *dev, u32 resp, u8 cmd)
switch (resp) {
case SI1133_ERR_OUTPUT_BUFFER_OVERFLOW:
- dev_warn(dev, "Output buffer overflow: %#02hhx\n", cmd);
+ dev_warn(dev, "Output buffer overflow: 0x%02x\n", cmd);
return -EOVERFLOW;
case SI1133_ERR_SATURATION_ADC_OR_OVERFLOW_ACCUMULATION:
- dev_warn(dev, "Saturation of the ADC or overflow of accumulation: %#02hhx\n",
+ dev_warn(dev, "Saturation of the ADC or overflow of accumulation: 0x%02x\n",
cmd);
return -EOVERFLOW;
case SI1133_ERR_INVALID_LOCATION_CMD:
dev_warn(dev,
- "Parameter access to an invalid location: %#02hhx\n",
+ "Parameter access to an invalid location: 0x%02x\n",
cmd);
return -EINVAL;
case SI1133_ERR_INVALID_CMD:
- dev_warn(dev, "Invalid command %#02hhx\n", cmd);
+ dev_warn(dev, "Invalid command 0x%02x\n", cmd);
return -EINVAL;
default:
- dev_warn(dev, "Unknown error %#02hhx\n", cmd);
+ dev_warn(dev, "Unknown error 0x%02x\n", cmd);
return -EINVAL;
}
}
@@ -400,7 +400,7 @@ static int si1133_command(struct si1133_data *data, u8 cmd)
err = regmap_write(data->regmap, SI1133_REG_COMMAND, cmd);
if (err) {
- dev_warn(dev, "Failed to write command %#02hhx, ret=%d\n", cmd,
+ dev_warn(dev, "Failed to write command 0x%02x, ret=%d\n", cmd,
err);
goto out;
}
@@ -425,7 +425,7 @@ static int si1133_command(struct si1133_data *data, u8 cmd)
SI1133_CMD_TIMEOUT_MS * 1000);
if (err) {
dev_warn(dev,
- "Failed to read command %#02hhx, ret=%d\n",
+ "Failed to read command 0x%02x, ret=%d\n",
cmd, err);
goto out;
}
@@ -978,11 +978,11 @@ static int si1133_validate_ids(struct iio_dev *iio_dev)
return err;
dev_info(&iio_dev->dev,
- "Device ID part %#02hhx rev %#02hhx mfr %#02hhx\n",
+ "Device ID part 0x%02x rev 0x%02x mfr 0x%02x\n",
part_id, rev_id, mfr_id);
if (part_id != SI1133_PART_ID) {
dev_err(&iio_dev->dev,
- "Part ID mismatch got %#02hhx, expected %#02x\n",
+ "Part ID mismatch got 0x%02x, expected 0x%02x\n",
part_id, SI1133_PART_ID);
return -ENODEV;
}
diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c
index 9b5c99823943..e2abad48b9f4 100644
--- a/drivers/iio/light/si1145.c
+++ b/drivers/iio/light/si1145.c
@@ -271,7 +271,7 @@ static int si1145_command(struct si1145_data *data, u8 cmd)
if ((ret & ~SI1145_RSP_COUNTER_MASK) == 0) {
if (ret == data->rsp_seq) {
if (time_after(jiffies, stop_jiffies)) {
- dev_warn(dev, "timeout on command %#02hhx\n",
+ dev_warn(dev, "timeout on command 0x%02x\n",
cmd);
ret = -ETIMEDOUT;
break;
@@ -291,12 +291,12 @@ static int si1145_command(struct si1145_data *data, u8 cmd)
ret = -EIO;
} else {
if (ret == SI1145_RSP_INVALID_SETTING) {
- dev_warn(dev, "INVALID_SETTING error on command %#02hhx\n",
+ dev_warn(dev, "INVALID_SETTING error on command 0x%02x\n",
cmd);
ret = -EINVAL;
} else {
/* All overflows are treated identically */
- dev_dbg(dev, "overflow, ret=%d, cmd=%#02hhx\n",
+ dev_dbg(dev, "overflow, ret=%d, cmd=0x%02x\n",
ret, cmd);
ret = -EOVERFLOW;
}
@@ -1243,7 +1243,7 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev)
int ret;
trig = devm_iio_trigger_alloc(&client->dev,
- "%s-dev%d", indio_dev->name, indio_dev->id);
+ "%s-dev%d", indio_dev->name, iio_device_id(indio_dev));
if (!trig)
return -ENOMEM;
@@ -1299,10 +1299,10 @@ static int si1145_probe(struct i2c_client *client,
SI1145_REG_SEQ_ID);
if (ret < 0)
return ret;
- dev_info(&client->dev, "device ID part %#02hhx rev %#02hhx seq %#02hhx\n",
+ dev_info(&client->dev, "device ID part 0x%02x rev 0x%02x seq 0x%02x\n",
part_id, rev_id, seq_id);
if (part_id != data->part_info->part) {
- dev_err(&client->dev, "part ID mismatch got %#02hhx, expected %#02x\n",
+ dev_err(&client->dev, "part ID mismatch got 0x%02x, expected 0x%02x\n",
part_id, data->part_info->part);
return -ENODEV;
}
diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c
index 6fe5d46f80d4..0593abd600ec 100644
--- a/drivers/iio/light/tcs3414.c
+++ b/drivers/iio/light/tcs3414.c
@@ -53,7 +53,11 @@ struct tcs3414_data {
u8 control;
u8 gain;
u8 timing;
- u16 buffer[8]; /* 4x 16-bit + 8 bytes timestamp */
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ u16 chans[4];
+ s64 timestamp __aligned(8);
+ } scan;
};
#define TCS3414_CHANNEL(_color, _si, _addr) { \
@@ -209,10 +213,10 @@ static irqreturn_t tcs3414_trigger_handler(int irq, void *p)
if (ret < 0)
goto done;
- data->buffer[j++] = ret;
+ data->scan.chans[j++] = ret;
}
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
iio_get_time_ns(indio_dev));
done:
diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c
index a0dc447aeb68..371c6a39a165 100644
--- a/drivers/iio/light/tcs3472.c
+++ b/drivers/iio/light/tcs3472.c
@@ -64,7 +64,11 @@ struct tcs3472_data {
u8 control;
u8 atime;
u8 apers;
- u16 buffer[8]; /* 4 16-bit channels + 64-bit timestamp */
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ u16 chans[4];
+ s64 timestamp __aligned(8);
+ } scan;
};
static const struct iio_event_spec tcs3472_events[] = {
@@ -386,10 +390,10 @@ static irqreturn_t tcs3472_trigger_handler(int irq, void *p)
if (ret < 0)
goto done;
- data->buffer[j++] = ret;
+ data->scan.chans[j++] = ret;
}
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
iio_get_time_ns(indio_dev));
done:
@@ -531,7 +535,8 @@ static int tcs3472_probe(struct i2c_client *client,
return 0;
free_irq:
- free_irq(client->irq, indio_dev);
+ if (client->irq)
+ free_irq(client->irq, indio_dev);
buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
@@ -559,7 +564,8 @@ static int tcs3472_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
- free_irq(client->irq, indio_dev);
+ if (client->irq)
+ free_irq(client->irq, indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
tcs3472_powerdown(iio_priv(indio_dev));
diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c
index c9d8f07a6fcd..7e101d5f72ee 100644
--- a/drivers/iio/light/tsl2583.c
+++ b/drivers/iio/light/tsl2583.c
@@ -644,9 +644,7 @@ static int tsl2583_set_pm_runtime_busy(struct tsl2583_chip *chip, bool on)
int ret;
if (on) {
- ret = pm_runtime_get_sync(&chip->client->dev);
- if (ret < 0)
- pm_runtime_put_noidle(&chip->client->dev);
+ ret = pm_runtime_resume_and_get(&chip->client->dev);
} else {
pm_runtime_mark_last_busy(&chip->client->dev);
ret = pm_runtime_put_autosuspend(&chip->client->dev);
@@ -729,8 +727,10 @@ static int tsl2583_read_raw(struct iio_dev *indio_dev,
read_done:
mutex_unlock(&chip->als_mutex);
- if (ret < 0)
+ if (ret < 0) {
+ tsl2583_set_pm_runtime_busy(chip, false);
return ret;
+ }
/*
* Preserve the ret variable if the call to
@@ -791,8 +791,10 @@ static int tsl2583_write_raw(struct iio_dev *indio_dev,
mutex_unlock(&chip->als_mutex);
- if (ret < 0)
+ if (ret < 0) {
+ tsl2583_set_pm_runtime_busy(chip, false);
return ret;
+ }
ret = tsl2583_set_pm_runtime_busy(chip, false);
if (ret < 0)
@@ -880,7 +882,6 @@ static int tsl2583_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
return tsl2583_set_power_state(chip, TSL2583_CNTL_PWR_OFF);
}
diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c
new file mode 100644
index 000000000000..39e68d0c9d6a
--- /dev/null
+++ b/drivers/iio/light/tsl2591.c
@@ -0,0 +1,1225 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2021 Joe Sandom <joe.g.sandom@gmail.com>
+ *
+ * Datasheet: https://ams.com/tsl25911#tab/documents
+ *
+ * Device driver for the TAOS TSL2591. This is a very-high sensitivity
+ * light-to-digital converter that transforms light intensity into a digital
+ * signal.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/sysfs.h>
+
+#include <asm/unaligned.h>
+
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/* ADC integration time, field value to time in ms */
+#define TSL2591_FVAL_TO_MSEC(x) (((x) + 1) * 100)
+/* ADC integration time, field value to time in seconds */
+#define TSL2591_FVAL_TO_SEC(x) ((x) + 1)
+/* ADC integration time, time in seconds to field value */
+#define TSL2591_SEC_TO_FVAL(x) ((x) - 1)
+
+/* TSL2591 register set */
+#define TSL2591_ENABLE 0x00
+#define TSL2591_CONTROL 0x01
+#define TSL2591_AILTL 0x04
+#define TSL2591_AILTH 0x05
+#define TSL2591_AIHTL 0x06
+#define TSL2591_AIHTH 0x07
+#define TSL2591_NP_AILTL 0x08
+#define TSL2591_NP_AILTH 0x09
+#define TSL2591_NP_AIHTL 0x0A
+#define TSL2591_NP_AIHTH 0x0B
+#define TSL2591_PERSIST 0x0C
+#define TSL2591_PACKAGE_ID 0x11
+#define TSL2591_DEVICE_ID 0x12
+#define TSL2591_STATUS 0x13
+#define TSL2591_C0_DATAL 0x14
+#define TSL2591_C0_DATAH 0x15
+#define TSL2591_C1_DATAL 0x16
+#define TSL2591_C1_DATAH 0x17
+
+/* TSL2591 command register definitions */
+#define TSL2591_CMD_NOP 0xA0
+#define TSL2591_CMD_SF_INTSET 0xE4
+#define TSL2591_CMD_SF_CALS_I 0xE5
+#define TSL2591_CMD_SF_CALS_NPI 0xE7
+#define TSL2591_CMD_SF_CNP_ALSI 0xEA
+
+/* TSL2591 enable register definitions */
+#define TSL2591_PWR_ON 0x01
+#define TSL2591_PWR_OFF 0x00
+#define TSL2591_ENABLE_ALS 0x02
+#define TSL2591_ENABLE_ALS_INT 0x10
+#define TSL2591_ENABLE_SLEEP_INT 0x40
+#define TSL2591_ENABLE_NP_INT 0x80
+
+/* TSL2591 control register definitions */
+#define TSL2591_CTRL_ALS_INTEGRATION_100MS 0x00
+#define TSL2591_CTRL_ALS_INTEGRATION_200MS 0x01
+#define TSL2591_CTRL_ALS_INTEGRATION_300MS 0x02
+#define TSL2591_CTRL_ALS_INTEGRATION_400MS 0x03
+#define TSL2591_CTRL_ALS_INTEGRATION_500MS 0x04
+#define TSL2591_CTRL_ALS_INTEGRATION_600MS 0x05
+#define TSL2591_CTRL_ALS_LOW_GAIN 0x00
+#define TSL2591_CTRL_ALS_MED_GAIN 0x10
+#define TSL2591_CTRL_ALS_HIGH_GAIN 0x20
+#define TSL2591_CTRL_ALS_MAX_GAIN 0x30
+#define TSL2591_CTRL_SYS_RESET 0x80
+
+/* TSL2591 persist register definitions */
+#define TSL2591_PRST_ALS_INT_CYCLE_0 0x00
+#define TSL2591_PRST_ALS_INT_CYCLE_ANY 0x01
+#define TSL2591_PRST_ALS_INT_CYCLE_2 0x02
+#define TSL2591_PRST_ALS_INT_CYCLE_3 0x03
+#define TSL2591_PRST_ALS_INT_CYCLE_5 0x04
+#define TSL2591_PRST_ALS_INT_CYCLE_10 0x05
+#define TSL2591_PRST_ALS_INT_CYCLE_15 0x06
+#define TSL2591_PRST_ALS_INT_CYCLE_20 0x07
+#define TSL2591_PRST_ALS_INT_CYCLE_25 0x08
+#define TSL2591_PRST_ALS_INT_CYCLE_30 0x09
+#define TSL2591_PRST_ALS_INT_CYCLE_35 0x0A
+#define TSL2591_PRST_ALS_INT_CYCLE_40 0x0B
+#define TSL2591_PRST_ALS_INT_CYCLE_45 0x0C
+#define TSL2591_PRST_ALS_INT_CYCLE_50 0x0D
+#define TSL2591_PRST_ALS_INT_CYCLE_55 0x0E
+#define TSL2591_PRST_ALS_INT_CYCLE_60 0x0F
+#define TSL2591_PRST_ALS_INT_CYCLE_MAX (BIT(4) - 1)
+
+/* TSL2591 PID register mask */
+#define TSL2591_PACKAGE_ID_MASK GENMASK(5, 4)
+
+/* TSL2591 ID register mask */
+#define TSL2591_DEVICE_ID_MASK GENMASK(7, 0)
+
+/* TSL2591 status register masks */
+#define TSL2591_STS_ALS_VALID_MASK BIT(0)
+#define TSL2591_STS_ALS_INT_MASK BIT(4)
+#define TSL2591_STS_NPERS_INT_MASK BIT(5)
+#define TSL2591_STS_VAL_HIGH_MASK BIT(0)
+
+/* TSL2591 constant values */
+#define TSL2591_PACKAGE_ID_VAL 0x00
+#define TSL2591_DEVICE_ID_VAL 0x50
+
+/* Power off suspend delay time MS */
+#define TSL2591_POWER_OFF_DELAY_MS 2000
+
+/* TSL2591 default values */
+#define TSL2591_DEFAULT_ALS_INT_TIME TSL2591_CTRL_ALS_INTEGRATION_300MS
+#define TSL2591_DEFAULT_ALS_GAIN TSL2591_CTRL_ALS_MED_GAIN
+#define TSL2591_DEFAULT_ALS_PERSIST TSL2591_PRST_ALS_INT_CYCLE_ANY
+#define TSL2591_DEFAULT_ALS_LOWER_THRESH 100
+#define TSL2591_DEFAULT_ALS_UPPER_THRESH 1500
+
+/* TSL2591 number of data registers */
+#define TSL2591_NUM_DATA_REGISTERS 4
+
+/* TSL2591 number of valid status reads on ADC complete */
+#define TSL2591_ALS_STS_VALID_COUNT 10
+
+/* TSL2591 delay period between polls when checking for ALS valid flag */
+#define TSL2591_DELAY_PERIOD_US 10000
+
+/* TSL2591 maximum values */
+#define TSL2591_MAX_ALS_INT_TIME_MS 600
+#define TSL2591_ALS_MAX_VALUE (BIT(16) - 1)
+
+/*
+ * LUX calculations;
+ * AGAIN values from Adafruit's TSL2591 Arduino library
+ * https://github.com/adafruit/Adafruit_TSL2591_Library
+ */
+#define TSL2591_CTRL_ALS_LOW_GAIN_MULTIPLIER 1
+#define TSL2591_CTRL_ALS_MED_GAIN_MULTIPLIER 25
+#define TSL2591_CTRL_ALS_HIGH_GAIN_MULTIPLIER 428
+#define TSL2591_CTRL_ALS_MAX_GAIN_MULTIPLIER 9876
+#define TSL2591_LUX_COEFFICIENT 408
+
+struct tsl2591_als_settings {
+ u16 als_lower_thresh;
+ u16 als_upper_thresh;
+ u8 als_int_time;
+ u8 als_persist;
+ u8 als_gain;
+};
+
+struct tsl2591_chip {
+ struct tsl2591_als_settings als_settings;
+ struct i2c_client *client;
+ /*
+ * Keep als_settings in sync with hardware state
+ * and ensure multiple readers are serialized.
+ */
+ struct mutex als_mutex;
+ bool events_enabled;
+};
+
+/*
+ * Period table is ALS persist cycle x integration time setting
+ * Integration times: 100ms, 200ms, 300ms, 400ms, 500ms, 600ms
+ * ALS cycles: 1, 2, 3, 5, 10, 20, 25, 30, 35, 40, 45, 50, 55, 60
+ */
+static const char * const tsl2591_als_period_list[] = {
+ "0.1 0.2 0.3 0.5 1.0 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0",
+ "0.2 0.4 0.6 1.0 2.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0",
+ "0.3 0.6 0.9 1.5 3.0 6.0 7.5 9.0 10.5 12.0 13.5 15.0 16.5 18.0",
+ "0.4 0.8 1.2 2.0 4.0 8.0 10.0 12.0 14.0 16.0 18.0 20.0 22.0 24.0",
+ "0.5 1.0 1.5 2.5 5.0 10.0 12.5 15.0 17.5 20.0 22.5 25.0 27.5 30.0",
+ "0.6 1.2 1.8 3.0 6.0 12.0 15.0 18.0 21.0 24.0 27.0 30.0 33.0 36.0",
+};
+
+static const int tsl2591_int_time_available[] = {
+ 1, 2, 3, 4, 5, 6,
+};
+
+static const int tsl2591_calibscale_available[] = {
+ 1, 25, 428, 9876,
+};
+
+static int tsl2591_set_als_lower_threshold(struct tsl2591_chip *chip,
+ u16 als_lower_threshold);
+static int tsl2591_set_als_upper_threshold(struct tsl2591_chip *chip,
+ u16 als_upper_threshold);
+
+static int tsl2591_gain_to_multiplier(const u8 als_gain)
+{
+ switch (als_gain) {
+ case TSL2591_CTRL_ALS_LOW_GAIN:
+ return TSL2591_CTRL_ALS_LOW_GAIN_MULTIPLIER;
+ case TSL2591_CTRL_ALS_MED_GAIN:
+ return TSL2591_CTRL_ALS_MED_GAIN_MULTIPLIER;
+ case TSL2591_CTRL_ALS_HIGH_GAIN:
+ return TSL2591_CTRL_ALS_HIGH_GAIN_MULTIPLIER;
+ case TSL2591_CTRL_ALS_MAX_GAIN:
+ return TSL2591_CTRL_ALS_MAX_GAIN_MULTIPLIER;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tsl2591_multiplier_to_gain(const u32 multiplier)
+{
+ switch (multiplier) {
+ case TSL2591_CTRL_ALS_LOW_GAIN_MULTIPLIER:
+ return TSL2591_CTRL_ALS_LOW_GAIN;
+ case TSL2591_CTRL_ALS_MED_GAIN_MULTIPLIER:
+ return TSL2591_CTRL_ALS_MED_GAIN;
+ case TSL2591_CTRL_ALS_HIGH_GAIN_MULTIPLIER:
+ return TSL2591_CTRL_ALS_HIGH_GAIN;
+ case TSL2591_CTRL_ALS_MAX_GAIN_MULTIPLIER:
+ return TSL2591_CTRL_ALS_MAX_GAIN;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tsl2591_persist_cycle_to_lit(const u8 als_persist)
+{
+ switch (als_persist) {
+ case TSL2591_PRST_ALS_INT_CYCLE_ANY:
+ return 1;
+ case TSL2591_PRST_ALS_INT_CYCLE_2:
+ return 2;
+ case TSL2591_PRST_ALS_INT_CYCLE_3:
+ return 3;
+ case TSL2591_PRST_ALS_INT_CYCLE_5:
+ return 5;
+ case TSL2591_PRST_ALS_INT_CYCLE_10:
+ return 10;
+ case TSL2591_PRST_ALS_INT_CYCLE_15:
+ return 15;
+ case TSL2591_PRST_ALS_INT_CYCLE_20:
+ return 20;
+ case TSL2591_PRST_ALS_INT_CYCLE_25:
+ return 25;
+ case TSL2591_PRST_ALS_INT_CYCLE_30:
+ return 30;
+ case TSL2591_PRST_ALS_INT_CYCLE_35:
+ return 35;
+ case TSL2591_PRST_ALS_INT_CYCLE_40:
+ return 40;
+ case TSL2591_PRST_ALS_INT_CYCLE_45:
+ return 45;
+ case TSL2591_PRST_ALS_INT_CYCLE_50:
+ return 50;
+ case TSL2591_PRST_ALS_INT_CYCLE_55:
+ return 55;
+ case TSL2591_PRST_ALS_INT_CYCLE_60:
+ return 60;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tsl2591_persist_lit_to_cycle(const u8 als_persist)
+{
+ switch (als_persist) {
+ case 1:
+ return TSL2591_PRST_ALS_INT_CYCLE_ANY;
+ case 2:
+ return TSL2591_PRST_ALS_INT_CYCLE_2;
+ case 3:
+ return TSL2591_PRST_ALS_INT_CYCLE_3;
+ case 5:
+ return TSL2591_PRST_ALS_INT_CYCLE_5;
+ case 10:
+ return TSL2591_PRST_ALS_INT_CYCLE_10;
+ case 15:
+ return TSL2591_PRST_ALS_INT_CYCLE_15;
+ case 20:
+ return TSL2591_PRST_ALS_INT_CYCLE_20;
+ case 25:
+ return TSL2591_PRST_ALS_INT_CYCLE_25;
+ case 30:
+ return TSL2591_PRST_ALS_INT_CYCLE_30;
+ case 35:
+ return TSL2591_PRST_ALS_INT_CYCLE_35;
+ case 40:
+ return TSL2591_PRST_ALS_INT_CYCLE_40;
+ case 45:
+ return TSL2591_PRST_ALS_INT_CYCLE_45;
+ case 50:
+ return TSL2591_PRST_ALS_INT_CYCLE_50;
+ case 55:
+ return TSL2591_PRST_ALS_INT_CYCLE_55;
+ case 60:
+ return TSL2591_PRST_ALS_INT_CYCLE_60;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tsl2591_compatible_int_time(struct tsl2591_chip *chip,
+ const u32 als_integration_time)
+{
+ switch (als_integration_time) {
+ case TSL2591_CTRL_ALS_INTEGRATION_100MS:
+ case TSL2591_CTRL_ALS_INTEGRATION_200MS:
+ case TSL2591_CTRL_ALS_INTEGRATION_300MS:
+ case TSL2591_CTRL_ALS_INTEGRATION_400MS:
+ case TSL2591_CTRL_ALS_INTEGRATION_500MS:
+ case TSL2591_CTRL_ALS_INTEGRATION_600MS:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tsl2591_als_time_to_fval(const u32 als_integration_time)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tsl2591_int_time_available); i++) {
+ if (als_integration_time == tsl2591_int_time_available[i])
+ return TSL2591_SEC_TO_FVAL(als_integration_time);
+ }
+
+ return -EINVAL;
+}
+
+static int tsl2591_compatible_gain(struct tsl2591_chip *chip, const u8 als_gain)
+{
+ switch (als_gain) {
+ case TSL2591_CTRL_ALS_LOW_GAIN:
+ case TSL2591_CTRL_ALS_MED_GAIN:
+ case TSL2591_CTRL_ALS_HIGH_GAIN:
+ case TSL2591_CTRL_ALS_MAX_GAIN:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tsl2591_compatible_als_persist_cycle(struct tsl2591_chip *chip,
+ const u32 als_persist)
+{
+ switch (als_persist) {
+ case TSL2591_PRST_ALS_INT_CYCLE_ANY:
+ case TSL2591_PRST_ALS_INT_CYCLE_2:
+ case TSL2591_PRST_ALS_INT_CYCLE_3:
+ case TSL2591_PRST_ALS_INT_CYCLE_5:
+ case TSL2591_PRST_ALS_INT_CYCLE_10:
+ case TSL2591_PRST_ALS_INT_CYCLE_15:
+ case TSL2591_PRST_ALS_INT_CYCLE_20:
+ case TSL2591_PRST_ALS_INT_CYCLE_25:
+ case TSL2591_PRST_ALS_INT_CYCLE_30:
+ case TSL2591_PRST_ALS_INT_CYCLE_35:
+ case TSL2591_PRST_ALS_INT_CYCLE_40:
+ case TSL2591_PRST_ALS_INT_CYCLE_45:
+ case TSL2591_PRST_ALS_INT_CYCLE_50:
+ case TSL2591_PRST_ALS_INT_CYCLE_55:
+ case TSL2591_PRST_ALS_INT_CYCLE_60:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tsl2591_check_als_valid(struct i2c_client *client)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, TSL2591_CMD_NOP | TSL2591_STATUS);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to read register\n");
+ return -EINVAL;
+ }
+
+ return FIELD_GET(TSL2591_STS_ALS_VALID_MASK, ret);
+}
+
+static int tsl2591_wait_adc_complete(struct tsl2591_chip *chip)
+{
+ struct tsl2591_als_settings settings = chip->als_settings;
+ struct i2c_client *client = chip->client;
+ int delay;
+ int val;
+ int ret;
+
+ delay = TSL2591_FVAL_TO_MSEC(settings.als_int_time);
+ if (!delay)
+ return -EINVAL;
+
+ /*
+ * Sleep for ALS integration time to allow enough time or an ADC read
+ * cycle to complete. Check status after delay for ALS valid.
+ */
+ msleep(delay);
+
+ /* Check for status ALS valid flag for up to 100ms */
+ ret = readx_poll_timeout(tsl2591_check_als_valid, client,
+ val, val == TSL2591_STS_VAL_HIGH_MASK,
+ TSL2591_DELAY_PERIOD_US,
+ TSL2591_DELAY_PERIOD_US * TSL2591_ALS_STS_VALID_COUNT);
+ if (ret)
+ dev_err(&client->dev, "Timed out waiting for valid ALS data\n");
+
+ return ret;
+}
+
+/*
+ * tsl2591_read_channel_data - Reads raw channel data and calculates lux
+ *
+ * Formula for lux calculation;
+ * Derived from Adafruit's TSL2591 library
+ * Link: https://github.com/adafruit/Adafruit_TSL2591_Library
+ * Counts Per Lux (CPL) = (ATIME_ms * AGAIN) / LUX DF
+ * lux = ((C0DATA - C1DATA) * (1 - (C1DATA / C0DATA))) / CPL
+ *
+ * Scale values to get more representative value of lux i.e.
+ * lux = ((C0DATA - C1DATA) * (1000 - ((C1DATA * 1000) / C0DATA))) / CPL
+ *
+ * Channel 0 = IR + Visible
+ * Channel 1 = IR only
+ */
+static int tsl2591_read_channel_data(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2)
+{
+ struct tsl2591_chip *chip = iio_priv(indio_dev);
+ struct tsl2591_als_settings *settings = &chip->als_settings;
+ struct i2c_client *client = chip->client;
+ u8 als_data[TSL2591_NUM_DATA_REGISTERS];
+ int counts_per_lux, int_time_fval, gain_multi, lux;
+ u16 als_ch0, als_ch1;
+ int ret;
+
+ ret = tsl2591_wait_adc_complete(chip);
+ if (ret < 0) {
+ dev_err(&client->dev, "No data available. Err: %d\n", ret);
+ return ret;
+ }
+
+ ret = i2c_smbus_read_i2c_block_data(client,
+ TSL2591_CMD_NOP | TSL2591_C0_DATAL,
+ sizeof(als_data), als_data);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to read data bytes");
+ return ret;
+ }
+
+ als_ch0 = get_unaligned_le16(&als_data[0]);
+ als_ch1 = get_unaligned_le16(&als_data[2]);
+
+ switch (chan->type) {
+ case IIO_INTENSITY:
+ if (chan->channel2 == IIO_MOD_LIGHT_BOTH)
+ *val = als_ch0;
+ else if (chan->channel2 == IIO_MOD_LIGHT_IR)
+ *val = als_ch1;
+ else
+ return -EINVAL;
+ break;
+ case IIO_LIGHT:
+ gain_multi = tsl2591_gain_to_multiplier(settings->als_gain);
+ if (gain_multi < 0) {
+ dev_err(&client->dev, "Invalid multiplier");
+ return gain_multi;
+ }
+
+ int_time_fval = TSL2591_FVAL_TO_MSEC(settings->als_int_time);
+ /* Calculate counts per lux value */
+ counts_per_lux = (int_time_fval * gain_multi) / TSL2591_LUX_COEFFICIENT;
+
+ dev_dbg(&client->dev, "Counts Per Lux: %d\n", counts_per_lux);
+
+ /* Calculate lux value */
+ lux = ((als_ch0 - als_ch1) *
+ (1000 - ((als_ch1 * 1000) / als_ch0))) / counts_per_lux;
+
+ dev_dbg(&client->dev, "Raw lux calculation: %d\n", lux);
+
+ /* Divide by 1000 to get real lux value before scaling */
+ *val = lux / 1000;
+
+ /* Get the decimal part of lux reading */
+ *val2 = (lux - (*val * 1000)) * 1000;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tsl2591_set_als_gain_int_time(struct tsl2591_chip *chip)
+{
+ struct tsl2591_als_settings als_settings = chip->als_settings;
+ struct i2c_client *client = chip->client;
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client,
+ TSL2591_CMD_NOP | TSL2591_CONTROL,
+ als_settings.als_int_time | als_settings.als_gain);
+ if (ret)
+ dev_err(&client->dev, "Failed to set als gain & int time\n");
+
+ return ret;
+}
+
+static int tsl2591_set_als_lower_threshold(struct tsl2591_chip *chip,
+ u16 als_lower_threshold)
+{
+ struct tsl2591_als_settings als_settings = chip->als_settings;
+ struct i2c_client *client = chip->client;
+ u16 als_upper_threshold;
+ u8 als_lower_l;
+ u8 als_lower_h;
+ int ret;
+
+ chip->als_settings.als_lower_thresh = als_lower_threshold;
+
+ /*
+ * Lower threshold should not be greater or equal to upper.
+ * If this is the case, then assert upper threshold to new lower
+ * threshold + 1 to avoid ordering issues when setting thresholds.
+ */
+ if (als_lower_threshold >= als_settings.als_upper_thresh) {
+ als_upper_threshold = als_lower_threshold + 1;
+ tsl2591_set_als_upper_threshold(chip, als_upper_threshold);
+ }
+
+ als_lower_l = als_lower_threshold;
+ als_lower_h = als_lower_threshold >> 8;
+
+ ret = i2c_smbus_write_byte_data(client,
+ TSL2591_CMD_NOP | TSL2591_AILTL,
+ als_lower_l);
+ if (ret) {
+ dev_err(&client->dev, "Failed to set als lower threshold\n");
+ return ret;
+ }
+
+ ret = i2c_smbus_write_byte_data(client,
+ TSL2591_CMD_NOP | TSL2591_AILTH,
+ als_lower_h);
+ if (ret) {
+ dev_err(&client->dev, "Failed to set als lower threshold\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tsl2591_set_als_upper_threshold(struct tsl2591_chip *chip,
+ u16 als_upper_threshold)
+{
+ struct tsl2591_als_settings als_settings = chip->als_settings;
+ struct i2c_client *client = chip->client;
+ u16 als_lower_threshold;
+ u8 als_upper_l;
+ u8 als_upper_h;
+ int ret;
+
+ if (als_upper_threshold > TSL2591_ALS_MAX_VALUE)
+ return -EINVAL;
+
+ chip->als_settings.als_upper_thresh = als_upper_threshold;
+
+ /*
+ * Upper threshold should not be less than lower. If this
+ * is the case, then assert lower threshold to new upper
+ * threshold - 1 to avoid ordering issues when setting thresholds.
+ */
+ if (als_upper_threshold < als_settings.als_lower_thresh) {
+ als_lower_threshold = als_upper_threshold - 1;
+ tsl2591_set_als_lower_threshold(chip, als_lower_threshold);
+ }
+
+ als_upper_l = als_upper_threshold;
+ als_upper_h = als_upper_threshold >> 8;
+
+ ret = i2c_smbus_write_byte_data(client,
+ TSL2591_CMD_NOP | TSL2591_AIHTL,
+ als_upper_l);
+ if (ret) {
+ dev_err(&client->dev, "Failed to set als upper threshold\n");
+ return ret;
+ }
+
+ ret = i2c_smbus_write_byte_data(client,
+ TSL2591_CMD_NOP | TSL2591_AIHTH,
+ als_upper_h);
+ if (ret) {
+ dev_err(&client->dev, "Failed to set als upper threshold\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tsl2591_set_als_persist_cycle(struct tsl2591_chip *chip,
+ u8 als_persist)
+{
+ struct i2c_client *client = chip->client;
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client,
+ TSL2591_CMD_NOP | TSL2591_PERSIST,
+ als_persist);
+ if (ret)
+ dev_err(&client->dev, "Failed to set als persist cycle\n");
+
+ chip->als_settings.als_persist = als_persist;
+
+ return ret;
+}
+
+static int tsl2591_set_power_state(struct tsl2591_chip *chip, u8 state)
+{
+ struct i2c_client *client = chip->client;
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client,
+ TSL2591_CMD_NOP | TSL2591_ENABLE,
+ state);
+ if (ret)
+ dev_err(&client->dev,
+ "Failed to set the power state to %#04x\n", state);
+
+ return ret;
+}
+
+static ssize_t tsl2591_in_illuminance_period_available_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct tsl2591_chip *chip = iio_priv(indio_dev);
+
+ return sysfs_emit(buf, "%s\n",
+ tsl2591_als_period_list[chip->als_settings.als_int_time]);
+}
+
+static IIO_DEVICE_ATTR_RO(tsl2591_in_illuminance_period_available, 0);
+
+static struct attribute *tsl2591_event_attrs_ctrl[] = {
+ &iio_dev_attr_tsl2591_in_illuminance_period_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group tsl2591_event_attribute_group = {
+ .attrs = tsl2591_event_attrs_ctrl,
+};
+
+static const struct iio_event_spec tsl2591_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ }, {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ }, {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_PERIOD) |
+ BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+static const struct iio_chan_spec tsl2591_channels[] = {
+ {
+ .type = IIO_INTENSITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_IR,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE)
+ },
+ {
+ .type = IIO_INTENSITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_BOTH,
+ .event_spec = tsl2591_events,
+ .num_event_specs = ARRAY_SIZE(tsl2591_events),
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE)
+ },
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE)
+ },
+};
+
+static int tsl2591_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct tsl2591_chip *chip = iio_priv(indio_dev);
+ struct i2c_client *client = chip->client;
+ int ret;
+
+ pm_runtime_get_sync(&client->dev);
+
+ mutex_lock(&chip->als_mutex);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (chan->type != IIO_INTENSITY) {
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+
+ ret = tsl2591_read_channel_data(indio_dev, chan, val, val2);
+ if (ret < 0)
+ goto err_unlock;
+
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_PROCESSED:
+ if (chan->type != IIO_LIGHT) {
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+
+ ret = tsl2591_read_channel_data(indio_dev, chan, val, val2);
+ if (ret < 0)
+ break;
+
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ case IIO_CHAN_INFO_INT_TIME:
+ if (chan->type != IIO_INTENSITY) {
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+
+ *val = TSL2591_FVAL_TO_SEC(chip->als_settings.als_int_time);
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_CALIBSCALE:
+ if (chan->type != IIO_INTENSITY) {
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+
+ *val = tsl2591_gain_to_multiplier(chip->als_settings.als_gain);
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+err_unlock:
+ mutex_unlock(&chip->als_mutex);
+
+ pm_runtime_mark_last_busy(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
+
+ return ret;
+}
+
+static int tsl2591_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct tsl2591_chip *chip = iio_priv(indio_dev);
+ int int_time;
+ int gain;
+ int ret;
+
+ mutex_lock(&chip->als_mutex);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_INT_TIME:
+ int_time = tsl2591_als_time_to_fval(val);
+ if (int_time < 0) {
+ ret = int_time;
+ goto err_unlock;
+ }
+ ret = tsl2591_compatible_int_time(chip, int_time);
+ if (ret < 0)
+ goto err_unlock;
+
+ chip->als_settings.als_int_time = int_time;
+ break;
+ case IIO_CHAN_INFO_CALIBSCALE:
+ gain = tsl2591_multiplier_to_gain(val);
+ if (gain < 0) {
+ ret = gain;
+ goto err_unlock;
+ }
+ ret = tsl2591_compatible_gain(chip, gain);
+ if (ret < 0)
+ goto err_unlock;
+
+ chip->als_settings.als_gain = gain;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+
+ ret = tsl2591_set_als_gain_int_time(chip);
+
+err_unlock:
+ mutex_unlock(&chip->als_mutex);
+ return ret;
+}
+
+static int tsl2591_read_available(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_INT_TIME:
+ *length = ARRAY_SIZE(tsl2591_int_time_available);
+ *vals = tsl2591_int_time_available;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_LIST;
+
+ case IIO_CHAN_INFO_CALIBSCALE:
+ *length = ARRAY_SIZE(tsl2591_calibscale_available);
+ *vals = tsl2591_calibscale_available;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tsl2591_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info, int *val,
+ int *val2)
+{
+ struct tsl2591_chip *chip = iio_priv(indio_dev);
+ struct i2c_client *client = chip->client;
+ int als_persist, int_time, period;
+ int ret;
+
+ mutex_lock(&chip->als_mutex);
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ *val = chip->als_settings.als_upper_thresh;
+ break;
+ case IIO_EV_DIR_FALLING:
+ *val = chip->als_settings.als_lower_thresh;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_EV_INFO_PERIOD:
+ ret = i2c_smbus_read_byte_data(client,
+ TSL2591_CMD_NOP | TSL2591_PERSIST);
+ if (ret <= 0 || ret > TSL2591_PRST_ALS_INT_CYCLE_MAX)
+ goto err_unlock;
+
+ als_persist = tsl2591_persist_cycle_to_lit(ret);
+ int_time = TSL2591_FVAL_TO_MSEC(chip->als_settings.als_int_time);
+ period = als_persist * (int_time * MSEC_PER_SEC);
+
+ *val = period / USEC_PER_SEC;
+ *val2 = period % USEC_PER_SEC;
+
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+err_unlock:
+ mutex_unlock(&chip->als_mutex);
+ return ret;
+}
+
+static int tsl2591_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info, int val,
+ int val2)
+{
+ struct tsl2591_chip *chip = iio_priv(indio_dev);
+ int period, int_time, als_persist;
+ int ret;
+
+ if (val < 0 || val2 < 0)
+ return -EINVAL;
+
+ mutex_lock(&chip->als_mutex);
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ if (val > TSL2591_ALS_MAX_VALUE) {
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ ret = tsl2591_set_als_upper_threshold(chip, val);
+ if (ret < 0)
+ goto err_unlock;
+ break;
+ case IIO_EV_DIR_FALLING:
+ ret = tsl2591_set_als_lower_threshold(chip, val);
+ if (ret < 0)
+ goto err_unlock;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+ break;
+ case IIO_EV_INFO_PERIOD:
+ int_time = TSL2591_FVAL_TO_MSEC(chip->als_settings.als_int_time);
+
+ period = ((val * MSEC_PER_SEC) +
+ (val2 / MSEC_PER_SEC)) / int_time;
+
+ als_persist = tsl2591_persist_lit_to_cycle(period);
+ if (als_persist < 0) {
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+
+ ret = tsl2591_compatible_als_persist_cycle(chip, als_persist);
+ if (ret < 0)
+ goto err_unlock;
+
+ ret = tsl2591_set_als_persist_cycle(chip, als_persist);
+ if (ret < 0)
+ goto err_unlock;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+err_unlock:
+ mutex_unlock(&chip->als_mutex);
+ return ret;
+}
+
+static int tsl2591_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct tsl2591_chip *chip = iio_priv(indio_dev);
+
+ return chip->events_enabled;
+}
+
+static int tsl2591_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ int state)
+{
+ struct tsl2591_chip *chip = iio_priv(indio_dev);
+ struct i2c_client *client = chip->client;
+
+ if (state && !chip->events_enabled) {
+ chip->events_enabled = true;
+ pm_runtime_get_sync(&client->dev);
+ } else if (!state && chip->events_enabled) {
+ chip->events_enabled = false;
+ pm_runtime_mark_last_busy(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
+ }
+
+ return 0;
+}
+
+static const struct iio_info tsl2591_info = {
+ .event_attrs = &tsl2591_event_attribute_group,
+ .read_raw = tsl2591_read_raw,
+ .write_raw = tsl2591_write_raw,
+ .read_avail = tsl2591_read_available,
+ .read_event_value = tsl2591_read_event_value,
+ .write_event_value = tsl2591_write_event_value,
+ .read_event_config = tsl2591_read_event_config,
+ .write_event_config = tsl2591_write_event_config,
+};
+
+static const struct iio_info tsl2591_info_no_irq = {
+ .read_raw = tsl2591_read_raw,
+ .write_raw = tsl2591_write_raw,
+ .read_avail = tsl2591_read_available,
+};
+
+static int __maybe_unused tsl2591_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct tsl2591_chip *chip = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&chip->als_mutex);
+ ret = tsl2591_set_power_state(chip, TSL2591_PWR_OFF);
+ mutex_unlock(&chip->als_mutex);
+
+ return ret;
+}
+
+static int __maybe_unused tsl2591_resume(struct device *dev)
+{
+ int power_state = TSL2591_PWR_ON | TSL2591_ENABLE_ALS;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct tsl2591_chip *chip = iio_priv(indio_dev);
+ int ret;
+
+ if (chip->events_enabled)
+ power_state |= TSL2591_ENABLE_ALS_INT;
+
+ mutex_lock(&chip->als_mutex);
+ ret = tsl2591_set_power_state(chip, power_state);
+ mutex_unlock(&chip->als_mutex);
+
+ return ret;
+}
+
+static const struct dev_pm_ops tsl2591_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(tsl2591_suspend, tsl2591_resume, NULL)
+};
+
+static irqreturn_t tsl2591_event_handler(int irq, void *private)
+{
+ struct iio_dev *dev_info = private;
+ struct tsl2591_chip *chip = iio_priv(dev_info);
+ struct i2c_client *client = chip->client;
+
+ if (!chip->events_enabled)
+ return IRQ_NONE;
+
+ iio_push_event(dev_info,
+ IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER),
+ iio_get_time_ns(dev_info));
+
+ /* Clear ALS irq */
+ i2c_smbus_write_byte(client, TSL2591_CMD_SF_CALS_NPI);
+
+ return IRQ_HANDLED;
+}
+
+static int tsl2591_load_defaults(struct tsl2591_chip *chip)
+{
+ int ret;
+
+ chip->als_settings.als_int_time = TSL2591_DEFAULT_ALS_INT_TIME;
+ chip->als_settings.als_gain = TSL2591_DEFAULT_ALS_GAIN;
+ chip->als_settings.als_lower_thresh = TSL2591_DEFAULT_ALS_LOWER_THRESH;
+ chip->als_settings.als_upper_thresh = TSL2591_DEFAULT_ALS_UPPER_THRESH;
+
+ ret = tsl2591_set_als_gain_int_time(chip);
+ if (ret < 0)
+ return ret;
+
+ ret = tsl2591_set_als_persist_cycle(chip, TSL2591_DEFAULT_ALS_PERSIST);
+ if (ret < 0)
+ return ret;
+
+ ret = tsl2591_set_als_lower_threshold(chip, TSL2591_DEFAULT_ALS_LOWER_THRESH);
+ if (ret < 0)
+ return ret;
+
+ ret = tsl2591_set_als_upper_threshold(chip, TSL2591_DEFAULT_ALS_UPPER_THRESH);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static void tsl2591_chip_off(void *data)
+{
+ struct iio_dev *indio_dev = data;
+ struct tsl2591_chip *chip = iio_priv(indio_dev);
+ struct i2c_client *client = chip->client;
+
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+ pm_runtime_put_noidle(&client->dev);
+
+ tsl2591_set_power_state(chip, TSL2591_PWR_OFF);
+}
+
+static int tsl2591_probe(struct i2c_client *client)
+{
+ struct tsl2591_chip *chip;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev,
+ "I2C smbus byte data functionality is not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ chip = iio_priv(indio_dev);
+ chip->client = client;
+ i2c_set_clientdata(client, indio_dev);
+
+ if (client->irq) {
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, tsl2591_event_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "tsl2591_irq", indio_dev);
+ if (ret) {
+ dev_err_probe(&client->dev, ret, "IRQ request error\n");
+ return -EINVAL;
+ }
+ indio_dev->info = &tsl2591_info;
+ } else {
+ indio_dev->info = &tsl2591_info_no_irq;
+ }
+
+ mutex_init(&chip->als_mutex);
+
+ ret = i2c_smbus_read_byte_data(client,
+ TSL2591_CMD_NOP | TSL2591_DEVICE_ID);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "Failed to read the device ID register\n");
+ return ret;
+ }
+ ret = FIELD_GET(TSL2591_DEVICE_ID_MASK, ret);
+ if (ret != TSL2591_DEVICE_ID_VAL) {
+ dev_err(&client->dev, "Device ID: %#04x unknown\n", ret);
+ return -EINVAL;
+ }
+
+ indio_dev->channels = tsl2591_channels;
+ indio_dev->num_channels = ARRAY_SIZE(tsl2591_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->name = chip->client->name;
+ chip->events_enabled = false;
+
+ pm_runtime_enable(&client->dev);
+ pm_runtime_set_autosuspend_delay(&client->dev,
+ TSL2591_POWER_OFF_DELAY_MS);
+ pm_runtime_use_autosuspend(&client->dev);
+
+ /*
+ * Add chip off to automatically managed path and disable runtime
+ * power management. This ensures that the chip power management
+ * is handled correctly on driver remove. tsl2591_chip_off() must be
+ * added to the managed path after pm runtime is enabled and before
+ * any error exit paths are met to ensure we're not left in a state
+ * of pm runtime not being disabled properly.
+ */
+ ret = devm_add_action_or_reset(&client->dev, tsl2591_chip_off,
+ indio_dev);
+ if (ret < 0)
+ return -EINVAL;
+
+ ret = tsl2591_load_defaults(chip);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to load sensor defaults\n");
+ return -EINVAL;
+ }
+
+ ret = i2c_smbus_write_byte(client, TSL2591_CMD_SF_CALS_NPI);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to clear als irq\n");
+ return -EINVAL;
+ }
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct of_device_id tsl2591_of_match[] = {
+ { .compatible = "amstaos,tsl2591"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, tsl2591_of_match);
+
+static struct i2c_driver tsl2591_driver = {
+ .driver = {
+ .name = "tsl2591",
+ .pm = &tsl2591_pm_ops,
+ .of_match_table = tsl2591_of_match,
+ },
+ .probe_new = tsl2591_probe
+};
+module_i2c_driver(tsl2591_driver);
+
+MODULE_AUTHOR("Joe Sandom <joe.g.sandom@gmail.com>");
+MODULE_DESCRIPTION("TAOS tsl2591 ambient light sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c
index 393f27b75c75..96e4a66ddf28 100644
--- a/drivers/iio/light/us5182d.c
+++ b/drivers/iio/light/us5182d.c
@@ -367,9 +367,7 @@ static int us5182d_set_power_state(struct us5182d_data *data, bool on)
return 0;
if (on) {
- ret = pm_runtime_get_sync(&data->client->dev);
- if (ret < 0)
- pm_runtime_put_noidle(&data->client->dev);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
} else {
pm_runtime_mark_last_busy(&data->client->dev);
ret = pm_runtime_put_autosuspend(&data->client->dev);
diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index 2f7916f95689..e02e92bc2928 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -413,9 +413,7 @@ static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on)
int ret;
if (on) {
- ret = pm_runtime_get_sync(dev);
- if (ret < 0)
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
} else {
pm_runtime_mark_last_busy(dev);
ret = pm_runtime_put_autosuspend(dev);
@@ -910,7 +908,7 @@ static irqreturn_t vcnl4010_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct vcnl4000_data *data = iio_priv(indio_dev);
const unsigned long *active_scan_mask = indio_dev->active_scan_mask;
- u16 buffer[8] = {0}; /* 1x16-bit + ts */
+ u16 buffer[8] __aligned(8) = {0}; /* 1x16-bit + naturally aligned ts */
bool data_read = false;
unsigned long isr;
int val = 0;
@@ -998,7 +996,8 @@ static int vcnl4010_probe_trigger(struct iio_dev *indio_dev)
struct iio_trigger *trigger;
trigger = devm_iio_trigger_alloc(&client->dev, "%s-dev%d",
- indio_dev->name, indio_dev->id);
+ indio_dev->name,
+ iio_device_id(indio_dev));
if (!trigger)
return -ENOMEM;
diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c
index ae87740d9cef..0db306ee910e 100644
--- a/drivers/iio/light/vcnl4035.c
+++ b/drivers/iio/light/vcnl4035.c
@@ -102,7 +102,8 @@ static irqreturn_t vcnl4035_trigger_consumer_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct vcnl4035_data *data = iio_priv(indio_dev);
- u8 buffer[ALIGN(sizeof(u16), sizeof(s64)) + sizeof(s64)];
+ /* Ensure naturally aligned timestamp */
+ u8 buffer[ALIGN(sizeof(u16), sizeof(s64)) + sizeof(s64)] __aligned(8);
int ret;
ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, (int *)buffer);
@@ -144,9 +145,7 @@ static int vcnl4035_set_pm_runtime_state(struct vcnl4035_data *data, bool on)
struct device *dev = &data->client->dev;
if (on) {
- ret = pm_runtime_get_sync(dev);
- if (ret < 0)
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
} else {
pm_runtime_mark_last_busy(dev);
ret = pm_runtime_put_autosuspend(dev);
@@ -507,7 +506,7 @@ static int vcnl4035_probe_trigger(struct iio_dev *indio_dev)
data->drdy_trigger0 = devm_iio_trigger_alloc(
indio_dev->dev.parent,
- "%s-dev%d", indio_dev->name, indio_dev->id);
+ "%s-dev%d", indio_dev->name, iio_device_id(indio_dev));
if (!data->drdy_trigger0)
return -ENOMEM;
diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c
index de85c9b30be1..3c937c55a10d 100644
--- a/drivers/iio/light/veml6030.c
+++ b/drivers/iio/light/veml6030.c
@@ -128,7 +128,7 @@ static ssize_t in_illuminance_period_available_show(struct device *dev,
return -EINVAL;
}
- return snprintf(buf, PAGE_SIZE, "%s\n", period_values[x]);
+ return sysfs_emit(buf, "%s\n", period_values[x]);
}
static IIO_DEVICE_ATTR_RO(in_illuminance_period_available, 0);
diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c
index 24b2f7b1fe44..e54feacfb980 100644
--- a/drivers/iio/magnetometer/ak8974.c
+++ b/drivers/iio/magnetometer/ak8974.c
@@ -833,8 +833,7 @@ static int ak8974_probe(struct i2c_client *i2c,
ak8974->i2c = i2c;
mutex_init(&ak8974->lock);
- ret = iio_read_mount_matrix(&i2c->dev, "mount-matrix",
- &ak8974->orientation);
+ ret = iio_read_mount_matrix(&i2c->dev, &ak8974->orientation);
if (ret)
return ret;
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index d988b6ac3659..42b8a2680e3a 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -890,7 +890,7 @@ static int ak8975_probe(struct i2c_client *client,
data->reset_gpiod = reset_gpiod;
data->eoc_irq = 0;
- err = iio_read_mount_matrix(&client->dev, "mount-matrix", &data->orientation);
+ err = iio_read_mount_matrix(&client->dev, &data->orientation);
if (err)
return err;
diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c
index 00f9766bad5c..f96f53175349 100644
--- a/drivers/iio/magnetometer/bmc150_magn.c
+++ b/drivers/iio/magnetometer/bmc150_magn.c
@@ -138,8 +138,11 @@ struct bmc150_magn_data {
struct regmap *regmap;
struct regulator_bulk_data regulators[2];
struct iio_mount_matrix orientation;
- /* 4 x 32 bits for x, y z, 4 bytes align, 64 bits timestamp */
- s32 buffer[6];
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ s32 chans[3];
+ s64 timestamp __aligned(8);
+ } scan;
struct iio_trigger *dready_trig;
bool dready_trigger_on;
int max_odr;
@@ -262,7 +265,7 @@ static int bmc150_magn_set_power_state(struct bmc150_magn_data *data, bool on)
int ret;
if (on) {
- ret = pm_runtime_get_sync(data->dev);
+ ret = pm_runtime_resume_and_get(data->dev);
} else {
pm_runtime_mark_last_busy(data->dev);
ret = pm_runtime_put_autosuspend(data->dev);
@@ -271,9 +274,6 @@ static int bmc150_magn_set_power_state(struct bmc150_magn_data *data, bool on)
if (ret < 0) {
dev_err(data->dev,
"failed to change power state to %d\n", on);
- if (on)
- pm_runtime_put_noidle(data->dev);
-
return ret;
}
#endif
@@ -675,11 +675,11 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
int ret;
mutex_lock(&data->mutex);
- ret = bmc150_magn_read_xyz(data, data->buffer);
+ ret = bmc150_magn_read_xyz(data, data->scan.chans);
if (ret < 0)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
pf->timestamp);
err:
@@ -890,8 +890,7 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap,
if (ret)
return dev_err_probe(dev, ret, "failed to get regulators\n");
- ret = iio_read_mount_matrix(dev, "mount-matrix",
- &data->orientation);
+ ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
@@ -915,7 +914,7 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap,
data->dready_trig = devm_iio_trigger_alloc(dev,
"%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->dready_trig) {
ret = -ENOMEM;
dev_err(dev, "iio trigger alloc failed\n");
@@ -963,12 +962,14 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap,
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(dev, "unable to register iio device\n");
- goto err_buffer_cleanup;
+ goto err_disable_runtime_pm;
}
dev_dbg(dev, "Registered device %s\n", name);
return 0;
+err_disable_runtime_pm:
+ pm_runtime_disable(dev);
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
err_free_irq:
@@ -992,7 +993,6 @@ int bmc150_magn_remove(struct device *dev)
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
- pm_runtime_put_noidle(dev);
iio_triggered_buffer_cleanup(indio_dev);
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index b78691523dd4..e85a3a8eea90 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -6,13 +6,9 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
+#include <linux/mod_devicetable.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
@@ -587,3 +583,4 @@ module_platform_driver(hid_magn_3d_platform_driver);
MODULE_DESCRIPTION("HID Sensor Magnetometer 3D");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HID);
diff --git a/drivers/iio/magnetometer/hmc5843.h b/drivers/iio/magnetometer/hmc5843.h
index 3f6c0b662941..242f742f2643 100644
--- a/drivers/iio/magnetometer/hmc5843.h
+++ b/drivers/iio/magnetometer/hmc5843.h
@@ -33,7 +33,8 @@ enum hmc5843_ids {
* @lock: update and read regmap data
* @regmap: hardware access register maps
* @variant: describe chip variants
- * @buffer: 3x 16-bit channels + padding + 64-bit timestamp
+ * @scan: buffer to pack data for passing to
+ * iio_push_to_buffers_with_timestamp()
*/
struct hmc5843_data {
struct device *dev;
@@ -41,7 +42,10 @@ struct hmc5843_data {
struct regmap *regmap;
const struct hmc5843_chip_info *variant;
struct iio_mount_matrix orientation;
- __be16 buffer[8];
+ struct {
+ __be16 chans[3];
+ s64 timestamp __aligned(8);
+ } scan;
};
int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
diff --git a/drivers/iio/magnetometer/hmc5843_core.c b/drivers/iio/magnetometer/hmc5843_core.c
index 780faea61d82..cf62057480cf 100644
--- a/drivers/iio/magnetometer/hmc5843_core.c
+++ b/drivers/iio/magnetometer/hmc5843_core.c
@@ -446,13 +446,13 @@ static irqreturn_t hmc5843_trigger_handler(int irq, void *p)
}
ret = regmap_bulk_read(data->regmap, HMC5843_DATA_OUT_MSB_REGS,
- data->buffer, 3 * sizeof(__be16));
+ data->scan.chans, sizeof(data->scan.chans));
mutex_unlock(&data->lock);
if (ret < 0)
goto done;
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
iio_get_time_ns(indio_dev));
done:
@@ -637,8 +637,7 @@ int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
data->variant = &hmc5843_chip_info_tbl[id];
mutex_init(&data->lock);
- ret = iio_read_mount_matrix(dev, "mount-matrix",
- &data->orientation);
+ ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c
index dd811da9cb6d..13914273c999 100644
--- a/drivers/iio/magnetometer/rm3100-core.c
+++ b/drivers/iio/magnetometer/rm3100-core.c
@@ -78,7 +78,8 @@ struct rm3100_data {
bool use_interrupt;
int conversion_time;
int scale;
- u8 buffer[RM3100_SCAN_BYTES];
+ /* Ensure naturally aligned timestamp */
+ u8 buffer[RM3100_SCAN_BYTES] __aligned(8);
struct iio_trigger *drdy_trig;
/*
@@ -575,7 +576,7 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq)
data->drdy_trig = devm_iio_trigger_alloc(dev, "%s-drdy%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->drdy_trig)
return -ENOMEM;
diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h
index 7ba6a6ba5c58..fb6c906c4c0c 100644
--- a/drivers/iio/magnetometer/st_magn.h
+++ b/drivers/iio/magnetometer/st_magn.h
@@ -23,10 +23,6 @@
#define LSM9DS1_MAGN_DEV_NAME "lsm9ds1_magn"
#define IIS2MDC_MAGN_DEV_NAME "iis2mdc"
-const struct st_sensor_settings *st_magn_get_settings(const char *name);
-int st_magn_common_probe(struct iio_dev *indio_dev);
-void st_magn_common_remove(struct iio_dev *indio_dev);
-
#ifdef CONFIG_IIO_BUFFER
int st_magn_allocate_ring(struct iio_dev *indio_dev);
void st_magn_deallocate_ring(struct iio_dev *indio_dev);
diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c
index 71faebd07feb..0048c3cd36ee 100644
--- a/drivers/iio/magnetometer/st_magn_core.c
+++ b/drivers/iio/magnetometer/st_magn_core.c
@@ -33,6 +33,7 @@
/* FULLSCALE */
#define ST_MAGN_FS_AVL_1300MG 1300
#define ST_MAGN_FS_AVL_1900MG 1900
+#define ST_MAGN_FS_AVL_2000MG 2000
#define ST_MAGN_FS_AVL_2500MG 2500
#define ST_MAGN_FS_AVL_4000MG 4000
#define ST_MAGN_FS_AVL_4700MG 4700
@@ -53,51 +54,95 @@
#define ST_MAGN_3_OUT_Y_L_ADDR 0x6a
#define ST_MAGN_3_OUT_Z_L_ADDR 0x6c
+/* Special L addresses for sensor 4 */
+#define ST_MAGN_4_OUT_X_L_ADDR 0x08
+#define ST_MAGN_4_OUT_Y_L_ADDR 0x0a
+#define ST_MAGN_4_OUT_Z_L_ADDR 0x0c
+
+static const struct iio_mount_matrix *
+st_magn_get_mount_matrix(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct st_sensor_data *mdata = iio_priv(indio_dev);
+
+ return &mdata->mount_matrix;
+}
+
+static const struct iio_chan_spec_ext_info st_magn_mount_matrix_ext_info[] = {
+ IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_magn_get_mount_matrix),
+ { }
+};
+
static const struct iio_chan_spec st_magn_16bit_channels[] = {
- ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_BE, 16, 16,
- ST_MAGN_DEFAULT_OUT_X_H_ADDR),
- ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
+ ST_MAGN_DEFAULT_OUT_X_H_ADDR,
+ st_magn_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_BE, 16, 16,
- ST_MAGN_DEFAULT_OUT_Y_H_ADDR),
- ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
+ ST_MAGN_DEFAULT_OUT_Y_H_ADDR,
+ st_magn_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_BE, 16, 16,
- ST_MAGN_DEFAULT_OUT_Z_H_ADDR),
+ ST_MAGN_DEFAULT_OUT_Z_H_ADDR,
+ st_magn_mount_matrix_ext_info),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct iio_chan_spec st_magn_2_16bit_channels[] = {
- ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16,
- ST_MAGN_2_OUT_X_L_ADDR),
- ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
+ ST_MAGN_2_OUT_X_L_ADDR,
+ st_magn_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16,
- ST_MAGN_2_OUT_Y_L_ADDR),
- ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
+ ST_MAGN_2_OUT_Y_L_ADDR,
+ st_magn_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16,
- ST_MAGN_2_OUT_Z_L_ADDR),
+ ST_MAGN_2_OUT_Z_L_ADDR,
+ st_magn_mount_matrix_ext_info),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct iio_chan_spec st_magn_3_16bit_channels[] = {
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN,
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16,
+ ST_MAGN_3_OUT_X_L_ADDR,
+ st_magn_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN,
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16,
+ ST_MAGN_3_OUT_Y_L_ADDR,
+ st_magn_mount_matrix_ext_info),
+ ST_SENSORS_LSM_CHANNELS_EXT(IIO_MAGN,
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16,
+ ST_MAGN_3_OUT_Z_L_ADDR,
+ st_magn_mount_matrix_ext_info),
+ IIO_CHAN_SOFT_TIMESTAMP(3)
+};
+
+static const struct iio_chan_spec st_magn_4_16bit_channels[] = {
ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16,
- ST_MAGN_3_OUT_X_L_ADDR),
+ ST_MAGN_4_OUT_X_L_ADDR),
ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16,
- ST_MAGN_3_OUT_Y_L_ADDR),
+ ST_MAGN_4_OUT_Y_L_ADDR),
ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16,
- ST_MAGN_3_OUT_Z_L_ADDR),
+ ST_MAGN_4_OUT_Z_L_ADDR),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
@@ -381,6 +426,87 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
.multi_read_bit = false,
.bootime = 2,
},
+ {
+ .wai = 0x49,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
+ .sensors_supported = {
+ [0] = LSM9DS0_IMU_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_magn_4_16bit_channels,
+ .odr = {
+ .addr = 0x24,
+ .mask = GENMASK(4, 2),
+ .odr_avl = {
+ { 3, 0x00, },
+ { 6, 0x01, },
+ { 12, 0x02, },
+ { 25, 0x03, },
+ { 50, 0x04, },
+ { 100, 0x05, },
+ },
+ },
+ .pw = {
+ .addr = 0x26,
+ .mask = GENMASK(1, 0),
+ .value_on = 0x00,
+ .value_off = 0x03,
+ },
+ .fs = {
+ .addr = 0x25,
+ .mask = GENMASK(6, 5),
+ .fs_avl = {
+ [0] = {
+ .num = ST_MAGN_FS_AVL_2000MG,
+ .value = 0x00,
+ .gain = 73,
+ },
+ [1] = {
+ .num = ST_MAGN_FS_AVL_4000MG,
+ .value = 0x01,
+ .gain = 146,
+ },
+ [2] = {
+ .num = ST_MAGN_FS_AVL_8000MG,
+ .value = 0x02,
+ .gain = 292,
+ },
+ [3] = {
+ .num = ST_MAGN_FS_AVL_12000MG,
+ .value = 0x03,
+ .gain = 438,
+ },
+ },
+ },
+ .bdu = {
+ .addr = 0x20,
+ .mask = BIT(3),
+ },
+ .drdy_irq = {
+ .int1 = {
+ .addr = 0x22,
+ .mask = BIT(1),
+ },
+ .int2 = {
+ .addr = 0x23,
+ .mask = BIT(2),
+ },
+ .stat_drdy = {
+ .addr = 0x07,
+ .mask = GENMASK(2, 0),
+ },
+ },
+ .sim = {
+ .addr = 0x21,
+ .value = BIT(0),
+ },
+ .multi_read_bit = true,
+ .bootime = 2,
+ },
+};
+
+/* Default magn DRDY is available on INT2 pin */
+static const struct st_sensors_platform_data default_magn_pdata = {
+ .drdy_int_pin = 2,
};
static int st_magn_read_raw(struct iio_dev *indio_dev,
@@ -490,33 +616,37 @@ EXPORT_SYMBOL(st_magn_get_settings);
int st_magn_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *mdata = iio_priv(indio_dev);
+ struct st_sensors_platform_data *pdata = dev_get_platdata(mdata->dev);
int err;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &magn_info;
- err = st_sensors_power_enable(indio_dev);
- if (err)
- return err;
-
err = st_sensors_verify_id(indio_dev);
if (err < 0)
- goto st_magn_power_off;
+ return err;
mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS;
indio_dev->channels = mdata->sensor_settings->ch;
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
+ err = iio_read_mount_matrix(mdata->dev, &mdata->mount_matrix);
+ if (err)
+ return err;
+
mdata->current_fullscale = &mdata->sensor_settings->fs.fs_avl[0];
mdata->odr = mdata->sensor_settings->odr.odr_avl[0].hz;
- err = st_sensors_init_sensor(indio_dev, NULL);
+ if (!pdata)
+ pdata = (struct st_sensors_platform_data *)&default_magn_pdata;
+
+ err = st_sensors_init_sensor(indio_dev, pdata);
if (err < 0)
- goto st_magn_power_off;
+ return err;
err = st_magn_allocate_ring(indio_dev);
if (err < 0)
- goto st_magn_power_off;
+ return err;
if (mdata->irq > 0) {
err = st_sensors_allocate_trigger(indio_dev,
@@ -539,9 +669,6 @@ st_magn_device_register_error:
st_sensors_deallocate_trigger(indio_dev);
st_magn_probe_trigger_error:
st_magn_deallocate_ring(indio_dev);
-st_magn_power_off:
- st_sensors_power_disable(indio_dev);
-
return err;
}
EXPORT_SYMBOL(st_magn_common_probe);
@@ -550,8 +677,6 @@ void st_magn_common_remove(struct iio_dev *indio_dev)
{
struct st_sensor_data *mdata = iio_priv(indio_dev);
- st_sensors_power_disable(indio_dev);
-
iio_device_unregister(indio_dev);
if (mdata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c
index 36f4e7b53b24..3e23c117de8e 100644
--- a/drivers/iio/magnetometer/st_magn_i2c.c
+++ b/drivers/iio/magnetometer/st_magn_i2c.c
@@ -82,16 +82,28 @@ static int st_magn_i2c_probe(struct i2c_client *client,
if (err < 0)
return err;
+ err = st_sensors_power_enable(indio_dev);
+ if (err)
+ return err;
+
err = st_magn_common_probe(indio_dev);
if (err < 0)
- return err;
+ goto st_magn_power_off;
return 0;
+
+st_magn_power_off:
+ st_sensors_power_disable(indio_dev);
+
+ return err;
}
static int st_magn_i2c_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+ st_sensors_power_disable(indio_dev);
+
st_magn_common_remove(indio_dev);
return 0;
diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c
index 0e2323dfc687..03c0a737aba6 100644
--- a/drivers/iio/magnetometer/st_magn_spi.c
+++ b/drivers/iio/magnetometer/st_magn_spi.c
@@ -76,16 +76,28 @@ static int st_magn_spi_probe(struct spi_device *spi)
if (err < 0)
return err;
+ err = st_sensors_power_enable(indio_dev);
+ if (err)
+ return err;
+
err = st_magn_common_probe(indio_dev);
if (err < 0)
- return err;
+ goto st_magn_power_off;
return 0;
+
+st_magn_power_off:
+ st_sensors_power_disable(indio_dev);
+
+ return err;
}
static int st_magn_spi_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+ st_sensors_power_disable(indio_dev);
+
st_magn_common_remove(indio_dev);
return 0;
diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c
index 2f2f8cb3c26c..9ff7b0e56cf6 100644
--- a/drivers/iio/magnetometer/yamaha-yas530.c
+++ b/drivers/iio/magnetometer/yamaha-yas530.c
@@ -831,7 +831,7 @@ static int yas5xx_probe(struct i2c_client *i2c,
yas5xx->dev = dev;
mutex_init(&yas5xx->lock);
- ret = iio_read_mount_matrix(dev, "mount-matrix", &yas5xx->orientation);
+ ret = iio_read_mount_matrix(dev, &yas5xx->orientation);
if (ret)
return ret;
diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c
index 7af48d336285..c0079e2c8807 100644
--- a/drivers/iio/orientation/hid-sensor-incl-3d.c
+++ b/drivers/iio/orientation/hid-sensor-incl-3d.c
@@ -7,13 +7,10 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
+#include <linux/mod_devicetable.h>
#include <linux/slab.h>
-#include <linux/delay.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
@@ -425,3 +422,4 @@ module_platform_driver(hid_incl_3d_platform_driver);
MODULE_DESCRIPTION("HID Sensor Inclinometer 3D");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HID);
diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c
index cf7f57a47681..a033699910e8 100644
--- a/drivers/iio/orientation/hid-sensor-rotation.c
+++ b/drivers/iio/orientation/hid-sensor-rotation.c
@@ -7,9 +7,7 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -373,3 +371,4 @@ module_platform_driver(hid_dev_rot_platform_driver);
MODULE_DESCRIPTION("HID Sensor Device Rotation");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HID);
diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
index fd77e7ee87f3..07c30d217255 100644
--- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c
+++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
@@ -7,6 +7,8 @@
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
@@ -303,7 +305,6 @@ static int hid_hinge_probe(struct platform_device *pdev)
return ret;
}
- indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &hinge_info;
indio_dev->name = "hinge";
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -377,3 +378,4 @@ module_platform_driver(hid_hinge_platform_driver);
MODULE_DESCRIPTION("HID Sensor INTEL Hinge");
MODULE_AUTHOR("Ye Xiang <xiang.ye@intel.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HID);
diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c
index 8a9c576616ee..ed30bdaa10ec 100644
--- a/drivers/iio/potentiostat/lmp91000.c
+++ b/drivers/iio/potentiostat/lmp91000.c
@@ -71,8 +71,8 @@ struct lmp91000_data {
struct completion completion;
u8 chan_select;
-
- u32 buffer[4]; /* 64-bit data + 64-bit timestamp */
+ /* 64-bit data + 64-bit naturally aligned timestamp */
+ u32 buffer[4] __aligned(8);
};
static const struct iio_chan_spec lmp91000_channels[] = {
@@ -323,7 +323,8 @@ static int lmp91000_probe(struct i2c_client *client,
}
data->trig = devm_iio_trigger_alloc(dev, "%s-mux%d",
- indio_dev->name, indio_dev->id);
+ indio_dev->name,
+ iio_device_id(indio_dev));
if (!data->trig) {
dev_err(dev, "cannot allocate iio trigger.\n");
return -ENOMEM;
diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c
index c416d261e3e3..10c52b8df2ba 100644
--- a/drivers/iio/pressure/hid-sensor-press.c
+++ b/drivers/iio/pressure/hid-sensor-press.c
@@ -6,13 +6,10 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
+#include <linux/mod_devicetable.h>
#include <linux/slab.h>
-#include <linux/delay.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
@@ -357,3 +354,4 @@ module_platform_driver(hid_press_platform_driver);
MODULE_DESCRIPTION("HID Sensor Pressure");
MODULE_AUTHOR("Archana Patni <archana.patni@intel.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HID);
diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c
index 48759fc4bf18..af4621eaa6b5 100644
--- a/drivers/iio/pressure/icp10100.c
+++ b/drivers/iio/pressure/icp10100.c
@@ -250,7 +250,9 @@ static int icp10100_get_measures(struct icp10100_state *st,
__be16 measures[3];
int ret;
- pm_runtime_get_sync(&st->client->dev);
+ ret = pm_runtime_resume_and_get(&st->client->dev);
+ if (ret < 0)
+ return ret;
mutex_lock(&st->lock);
cmd = &icp10100_cmd_measure[st->mode];
@@ -525,7 +527,6 @@ static void icp10100_pm_disable(void *data)
{
struct device *dev = data;
- pm_runtime_put_sync_suspend(dev);
pm_runtime_disable(dev);
}
diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h
index 5c746ff6087e..9417b3bd7513 100644
--- a/drivers/iio/pressure/st_pressure.h
+++ b/drivers/iio/pressure/st_pressure.h
@@ -41,10 +41,6 @@ static __maybe_unused const struct st_sensors_platform_data default_press_pdata
.drdy_int_pin = 1,
};
-const struct st_sensor_settings *st_press_get_settings(const char *name);
-int st_press_common_probe(struct iio_dev *indio_dev);
-void st_press_common_remove(struct iio_dev *indio_dev);
-
#ifdef CONFIG_IIO_BUFFER
int st_press_allocate_ring(struct iio_dev *indio_dev);
void st_press_deallocate_ring(struct iio_dev *indio_dev);
diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c
index 789a2928504a..7912b5a68395 100644
--- a/drivers/iio/pressure/st_pressure_core.c
+++ b/drivers/iio/pressure/st_pressure_core.c
@@ -689,13 +689,9 @@ int st_press_common_probe(struct iio_dev *indio_dev)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &press_info;
- err = st_sensors_power_enable(indio_dev);
- if (err)
- return err;
-
err = st_sensors_verify_id(indio_dev);
if (err < 0)
- goto st_press_power_off;
+ return err;
/*
* Skip timestamping channel while declaring available channels to
@@ -718,11 +714,11 @@ int st_press_common_probe(struct iio_dev *indio_dev)
err = st_sensors_init_sensor(indio_dev, pdata);
if (err < 0)
- goto st_press_power_off;
+ return err;
err = st_press_allocate_ring(indio_dev);
if (err < 0)
- goto st_press_power_off;
+ return err;
if (press_data->irq > 0) {
err = st_sensors_allocate_trigger(indio_dev,
@@ -745,9 +741,6 @@ st_press_device_register_error:
st_sensors_deallocate_trigger(indio_dev);
st_press_probe_trigger_error:
st_press_deallocate_ring(indio_dev);
-st_press_power_off:
- st_sensors_power_disable(indio_dev);
-
return err;
}
EXPORT_SYMBOL(st_press_common_probe);
@@ -756,8 +749,6 @@ void st_press_common_remove(struct iio_dev *indio_dev)
{
struct st_sensor_data *press_data = iio_priv(indio_dev);
- st_sensors_power_disable(indio_dev);
-
iio_device_unregister(indio_dev);
if (press_data->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
index 09c6903f99b8..f0a5af314ceb 100644
--- a/drivers/iio/pressure/st_pressure_i2c.c
+++ b/drivers/iio/pressure/st_pressure_i2c.c
@@ -98,16 +98,29 @@ static int st_press_i2c_probe(struct i2c_client *client,
if (ret < 0)
return ret;
+ ret = st_sensors_power_enable(indio_dev);
+ if (ret)
+ return ret;
+
ret = st_press_common_probe(indio_dev);
if (ret < 0)
- return ret;
+ goto st_press_power_off;
return 0;
+
+st_press_power_off:
+ st_sensors_power_disable(indio_dev);
+
+ return ret;
}
static int st_press_i2c_remove(struct i2c_client *client)
{
- st_press_common_remove(i2c_get_clientdata(client));
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+ st_sensors_power_disable(indio_dev);
+
+ st_press_common_remove(indio_dev);
return 0;
}
diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c
index b5ee3ec2764f..b48cf7d01cd7 100644
--- a/drivers/iio/pressure/st_pressure_spi.c
+++ b/drivers/iio/pressure/st_pressure_spi.c
@@ -82,16 +82,29 @@ static int st_press_spi_probe(struct spi_device *spi)
if (err < 0)
return err;
+ err = st_sensors_power_enable(indio_dev);
+ if (err)
+ return err;
+
err = st_press_common_probe(indio_dev);
if (err < 0)
- return err;
+ goto st_press_power_off;
return 0;
+
+st_press_power_off:
+ st_sensors_power_disable(indio_dev);
+
+ return err;
}
static int st_press_spi_remove(struct spi_device *spi)
{
- st_press_common_remove(spi_get_drvdata(spi));
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+ st_sensors_power_disable(indio_dev);
+
+ st_press_common_remove(indio_dev);
return 0;
}
diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c
index a93411216aee..89295c90f801 100644
--- a/drivers/iio/pressure/zpa2326.c
+++ b/drivers/iio/pressure/zpa2326.c
@@ -1408,7 +1408,8 @@ static int zpa2326_init_managed_trigger(struct device *parent,
return 0;
trigger = devm_iio_trigger_alloc(parent, "%s-dev%d",
- indio_dev->name, indio_dev->id);
+ indio_dev->name,
+ iio_device_id(indio_dev));
if (!trigger)
return -ENOMEM;
diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c
index edc4a35ae66d..3797a8f54276 100644
--- a/drivers/iio/proximity/as3935.c
+++ b/drivers/iio/proximity/as3935.c
@@ -59,7 +59,11 @@ struct as3935_state {
unsigned long noise_tripped;
u32 tune_cap;
u32 nflwdth_reg;
- u8 buffer[16]; /* 8-bit data + 56-bit padding + 64-bit timestamp */
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ u8 chan;
+ s64 timestamp __aligned(8);
+ } scan;
u8 buf[2] ____cacheline_aligned;
};
@@ -225,8 +229,8 @@ static irqreturn_t as3935_trigger_handler(int irq, void *private)
if (ret)
goto err_read;
- st->buffer[0] = val & AS3935_DATA_MASK;
- iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer,
+ st->scan.chan = val & AS3935_DATA_MASK;
+ iio_push_to_buffers_with_timestamp(indio_dev, &st->scan,
iio_get_time_ns(indio_dev));
err_read:
iio_trigger_notify_done(indio_dev->trig);
@@ -404,7 +408,8 @@ static int as3935_probe(struct spi_device *spi)
indio_dev->info = &as3935_info;
trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
- indio_dev->name, indio_dev->id);
+ indio_dev->name,
+ iio_device_id(indio_dev));
if (!trig)
return -ENOMEM;
diff --git a/drivers/iio/proximity/isl29501.c b/drivers/iio/proximity/isl29501.c
index 90e76451c972..5b6ea783795d 100644
--- a/drivers/iio/proximity/isl29501.c
+++ b/drivers/iio/proximity/isl29501.c
@@ -938,7 +938,7 @@ static irqreturn_t isl29501_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct isl29501_private *isl29501 = iio_priv(indio_dev);
const unsigned long *active_mask = indio_dev->active_scan_mask;
- u32 buffer[4] = {}; /* 1x16-bit + ts */
+ u32 buffer[4] __aligned(8) = {}; /* 1x16-bit + naturally aligned ts */
if (test_bit(ISL29501_DISTANCE_SCAN_INDEX, active_mask))
isl29501_register_read(isl29501, REG_DISTANCE, buffer);
diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
index cc206bfa09c7..27026c060ab9 100644
--- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
+++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
@@ -44,7 +44,11 @@ struct lidar_data {
int (*xfer)(struct lidar_data *data, u8 reg, u8 *val, int len);
int i2c_enabled;
- u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ u16 chan;
+ s64 timestamp __aligned(8);
+ } scan;
};
static const struct iio_chan_spec lidar_channels[] = {
@@ -154,7 +158,9 @@ static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
int tries = 10;
int ret;
- pm_runtime_get_sync(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
+ return ret;
/* start sample */
ret = lidar_write_control(data, LIDAR_REG_CONTROL_ACQUIRE);
@@ -230,9 +236,9 @@ static irqreturn_t lidar_trigger_handler(int irq, void *private)
struct lidar_data *data = iio_priv(indio_dev);
int ret;
- ret = lidar_get_measurement(data, data->buffer);
+ ret = lidar_get_measurement(data, &data->scan.chan);
if (!ret) {
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
iio_get_time_ns(indio_dev));
} else if (ret != -EINVAL) {
dev_err(&data->client->dev, "cannot read LIDAR measurement");
diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c
index 420c37c72de4..fe88b2bb60bc 100644
--- a/drivers/iio/proximity/srf04.c
+++ b/drivers/iio/proximity/srf04.c
@@ -100,9 +100,11 @@ static int srf04_read(struct srf04_data *data)
u64 dt_ns;
u32 time_ns, distance_mm;
- if (data->gpiod_power)
- pm_runtime_get_sync(data->dev);
-
+ if (data->gpiod_power) {
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return ret;
+ }
/*
* just one read-echo-cycle can take place at a time
* ==> lock against concurrent reading calls
diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c
index 70beac5c9c1d..9b0886760f76 100644
--- a/drivers/iio/proximity/srf08.c
+++ b/drivers/iio/proximity/srf08.c
@@ -63,11 +63,11 @@ struct srf08_data {
int range_mm;
struct mutex lock;
- /*
- * triggered buffer
- * 1x16-bit channel + 3x16 padding + 4x16 timestamp
- */
- s16 buffer[8];
+ /* Ensure timestamp is naturally aligned */
+ struct {
+ s16 chan;
+ s64 timestamp __aligned(8);
+ } scan;
/* Sensor-Type */
enum srf08_sensor_type sensor_type;
@@ -190,9 +190,9 @@ static irqreturn_t srf08_trigger_handler(int irq, void *p)
mutex_lock(&data->lock);
- data->buffer[0] = sensor_data;
+ data->scan.chan = sensor_data;
iio_push_to_buffers_with_timestamp(indio_dev,
- data->buffer, pf->timestamp);
+ &data->scan, pf->timestamp);
mutex_unlock(&data->lock);
err:
diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c
index 327ebb7ddbb9..175f3b7c61d7 100644
--- a/drivers/iio/proximity/sx9310.c
+++ b/drivers/iio/proximity/sx9310.c
@@ -1473,7 +1473,7 @@ static int sx9310_probe(struct i2c_client *client)
data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
indio_dev->name,
- indio_dev->id);
+ iio_device_id(indio_dev));
if (!data->trig)
return -ENOMEM;
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
index a87f4a8e4327..3e4ddb2e8c2b 100644
--- a/drivers/iio/proximity/sx9500.c
+++ b/drivers/iio/proximity/sx9500.c
@@ -946,7 +946,7 @@ static int sx9500_probe(struct i2c_client *client,
return ret;
data->trig = devm_iio_trigger_alloc(&client->dev,
- "%s-dev%d", indio_dev->name, indio_dev->id);
+ "%s-dev%d", indio_dev->name, iio_device_id(indio_dev));
if (!data->trig)
return -ENOMEM;
diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
index 4df60082c1fa..f20ae3c963cb 100644
--- a/drivers/iio/temperature/Kconfig
+++ b/drivers/iio/temperature/Kconfig
@@ -96,6 +96,16 @@ config TMP007
This driver can also be built as a module. If so, the module will
be called tmp007.
+config TMP117
+ tristate "TMP117 Digital temperature sensor with integrated NV memory"
+ depends on I2C
+ help
+ If you say yes here you get support for the Texas Instruments
+ TMP117 Digital temperature sensor with integrated NV memory.
+
+ This driver can also be built as a module. If so, the module will
+ be called tmp117.
+
config TSYS01
tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection"
depends on I2C
diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
index 90c113115422..e3392c4b29b4 100644
--- a/drivers/iio/temperature/Makefile
+++ b/drivers/iio/temperature/Makefile
@@ -12,5 +12,6 @@ obj-$(CONFIG_MLX90614) += mlx90614.o
obj-$(CONFIG_MLX90632) += mlx90632.o
obj-$(CONFIG_TMP006) += tmp006.o
obj-$(CONFIG_TMP007) += tmp007.o
+obj-$(CONFIG_TMP117) += tmp117.o
obj-$(CONFIG_TSYS01) += tsys01.o
obj-$(CONFIG_TSYS02D) += tsys02d.o
diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c
index dc534ed784c3..d40f235af1d4 100644
--- a/drivers/iio/temperature/hid-sensor-temperature.c
+++ b/drivers/iio/temperature/hid-sensor-temperature.c
@@ -8,6 +8,7 @@
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
@@ -291,3 +292,4 @@ module_platform_driver(hid_temperature_platform_driver);
MODULE_DESCRIPTION("HID Environmental temperature sensor");
MODULE_AUTHOR("Song Hongyan <hongyan.song@intel.com>");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_HID);
diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c
index ef0fec94d269..afcb10ea7c44 100644
--- a/drivers/iio/temperature/mlx90614.c
+++ b/drivers/iio/temperature/mlx90614.c
@@ -176,11 +176,14 @@ static inline s32 mlx90614_iir_search(const struct i2c_client *client,
static int mlx90614_power_get(struct mlx90614_data *data, bool startup)
{
unsigned long now;
+ int ret;
if (!data->wakeup_gpio)
return 0;
- pm_runtime_get_sync(&data->client->dev);
+ ret = pm_runtime_resume_and_get(&data->client->dev);
+ if (ret < 0)
+ return ret;
if (startup) {
now = jiffies;
@@ -267,7 +270,10 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
*val = MLX90614_CONST_SCALE;
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */
- mlx90614_power_get(data, false);
+ ret = mlx90614_power_get(data, false);
+ if (ret < 0)
+ return ret;
+
mutex_lock(&data->lock);
ret = i2c_smbus_read_word_data(data->client,
MLX90614_EMISSIVITY);
@@ -287,7 +293,10 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR setting with
FIR = 1024 */
- mlx90614_power_get(data, false);
+ ret = mlx90614_power_get(data, false);
+ if (ret < 0)
+ return ret;
+
mutex_lock(&data->lock);
ret = i2c_smbus_read_word_data(data->client, MLX90614_CONFIG);
mutex_unlock(&data->lock);
@@ -319,7 +328,10 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev,
val = val * MLX90614_CONST_RAW_EMISSIVITY_MAX +
val2 / MLX90614_CONST_EMISSIVITY_RESOLUTION;
- mlx90614_power_get(data, false);
+ ret = mlx90614_power_get(data, false);
+ if (ret < 0)
+ return ret;
+
mutex_lock(&data->lock);
ret = mlx90614_write_word(data->client, MLX90614_EMISSIVITY,
val);
@@ -331,7 +343,10 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev,
if (val < 0 || val2 < 0)
return -EINVAL;
- mlx90614_power_get(data, false);
+ ret = mlx90614_power_get(data, false);
+ if (ret < 0)
+ return ret;
+
mutex_lock(&data->lock);
ret = mlx90614_iir_search(data->client,
val * 100 + val2 / 10000);
diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c
new file mode 100644
index 000000000000..f9b8f2b570f6
--- /dev/null
+++ b/drivers/iio/temperature/tmp117.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Digital temperature sensor with integrated Non-volatile memory
+ * Copyright (c) 2021 Puranjay Mohan <puranjay12@gmail.com>
+ *
+ * Driver for the Texas Instruments TMP117 Temperature Sensor
+ * (7-bit I2C slave address (0x48 - 0x4B), changeable via ADD pins)
+ *
+ * Note: This driver assumes that the sensor has been calibrated beforehand.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/limits.h>
+
+#include <linux/iio/iio.h>
+
+#define TMP117_REG_TEMP 0x0
+#define TMP117_REG_CFGR 0x1
+#define TMP117_REG_HIGH_LIM 0x2
+#define TMP117_REG_LOW_LIM 0x3
+#define TMP117_REG_EEPROM_UL 0x4
+#define TMP117_REG_EEPROM1 0x5
+#define TMP117_REG_EEPROM2 0x6
+#define TMP117_REG_TEMP_OFFSET 0x7
+#define TMP117_REG_EEPROM3 0x8
+#define TMP117_REG_DEVICE_ID 0xF
+
+#define TMP117_RESOLUTION_10UC 78125
+#define TMP117_DEVICE_ID 0x0117
+#define MICRODEGREE_PER_10MILLIDEGREE 10000
+
+struct tmp117_data {
+ struct i2c_client *client;
+ s16 calibbias;
+};
+
+static int tmp117_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ struct tmp117_data *data = iio_priv(indio_dev);
+ s32 ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = i2c_smbus_read_word_swapped(data->client,
+ TMP117_REG_TEMP);
+ if (ret < 0)
+ return ret;
+ *val = sign_extend32(ret, 15);
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_CALIBBIAS:
+ ret = i2c_smbus_read_word_swapped(data->client,
+ TMP117_REG_TEMP_OFFSET);
+ if (ret < 0)
+ return ret;
+ *val = sign_extend32(ret, 15);
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ /*
+ * Conversion from 10s of uC to mC
+ * as IIO reports temperature in mC
+ */
+ *val = TMP117_RESOLUTION_10UC / MICRODEGREE_PER_10MILLIDEGREE;
+ *val2 = (TMP117_RESOLUTION_10UC %
+ MICRODEGREE_PER_10MILLIDEGREE) * 100;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tmp117_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int val,
+ int val2, long mask)
+{
+ struct tmp117_data *data = iio_priv(indio_dev);
+ s16 off;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_CALIBBIAS:
+ off = clamp_t(int, val, S16_MIN, S16_MAX);
+ if (off == data->calibbias)
+ return 0;
+ data->calibbias = off;
+ return i2c_smbus_write_word_swapped(data->client,
+ TMP117_REG_TEMP_OFFSET, off);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec tmp117_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_SCALE),
+ },
+};
+
+static const struct iio_info tmp117_info = {
+ .read_raw = tmp117_read_raw,
+ .write_raw = tmp117_write_raw,
+};
+
+static int tmp117_identify(struct i2c_client *client)
+{
+ int dev_id;
+
+ dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID);
+ if (dev_id < 0)
+ return dev_id;
+ if (dev_id != TMP117_DEVICE_ID) {
+ dev_err(&client->dev, "TMP117 not found\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int tmp117_probe(struct i2c_client *client)
+{
+ struct tmp117_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return -EOPNOTSUPP;
+
+ ret = tmp117_identify(client);
+ if (ret < 0)
+ return ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->client = client;
+ data->calibbias = 0;
+
+ indio_dev->name = "tmp117";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &tmp117_info;
+
+ indio_dev->channels = tmp117_channels;
+ indio_dev->num_channels = ARRAY_SIZE(tmp117_channels);
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct of_device_id tmp117_of_match[] = {
+ { .compatible = "ti,tmp117", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tmp117_of_match);
+
+static const struct i2c_device_id tmp117_id[] = {
+ { "tmp117", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tmp117_id);
+
+static struct i2c_driver tmp117_driver = {
+ .driver = {
+ .name = "tmp117",
+ .of_match_table = tmp117_of_match,
+ },
+ .probe_new = tmp117_probe,
+ .id_table = tmp117_id,
+};
+module_i2c_driver(tmp117_driver);
+
+MODULE_AUTHOR("Puranjay Mohan <puranjay12@gmail.com>");
+MODULE_DESCRIPTION("TI TMP117 Temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/test/iio-test-format.c b/drivers/iio/test/iio-test-format.c
index 55a0cfe9181d..f1e951eddb43 100644
--- a/drivers/iio/test/iio-test-format.c
+++ b/drivers/iio/test/iio-test-format.c
@@ -8,7 +8,7 @@
#include <linux/iio/iio.h>
#define IIO_TEST_FORMAT_EXPECT_EQ(_test, _buf, _ret, _val) do { \
- KUNIT_EXPECT_EQ(_test, (int)strlen(_buf), _ret); \
+ KUNIT_EXPECT_EQ(_test, strlen(_buf), _ret); \
KUNIT_EXPECT_STREQ(_test, (_buf), (_val)); \
} while (0)
diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
index 3aa9e8bba005..33083877cd19 100644
--- a/drivers/iio/trigger/stm32-timer-trigger.c
+++ b/drivers/iio/trigger/stm32-timer-trigger.c
@@ -296,7 +296,7 @@ static ssize_t stm32_tt_show_master_mode(struct device *dev,
else
cr2 = (cr2 & TIM_CR2_MMS) >> TIM_CR2_MMS_SHIFT;
- return snprintf(buf, PAGE_SIZE, "%s\n", master_mode_table[cr2]);
+ return sysfs_emit(buf, "%s\n", master_mode_table[cr2]);
}
static ssize_t stm32_tt_store_master_mode(struct device *dev,
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index 04a78d9f8fe3..33d3ce9c888e 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -82,7 +82,7 @@ source "drivers/infiniband/hw/mthca/Kconfig"
source "drivers/infiniband/hw/qib/Kconfig"
source "drivers/infiniband/hw/cxgb4/Kconfig"
source "drivers/infiniband/hw/efa/Kconfig"
-source "drivers/infiniband/hw/i40iw/Kconfig"
+source "drivers/infiniband/hw/irdma/Kconfig"
source "drivers/infiniband/hw/mlx4/Kconfig"
source "drivers/infiniband/hw/mlx5/Kconfig"
source "drivers/infiniband/hw/ocrdma/Kconfig"
diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
index 3b0991fedd81..c9e9fc81447e 100644
--- a/drivers/infiniband/core/cache.c
+++ b/drivers/infiniband/core/cache.c
@@ -240,7 +240,7 @@ static void free_gid_entry_locked(struct ib_gid_table_entry *entry)
u32 port_num = entry->attr.port_num;
struct ib_gid_table *table = rdma_gid_table(device, port_num);
- dev_dbg(&device->dev, "%s port=%u index=%d gid %pI6\n", __func__,
+ dev_dbg(&device->dev, "%s port=%u index=%u gid %pI6\n", __func__,
port_num, entry->attr.index, entry->attr.gid.raw);
write_lock_irq(&table->rwlock);
@@ -323,7 +323,7 @@ static void store_gid_entry(struct ib_gid_table *table,
{
entry->state = GID_TABLE_ENTRY_VALID;
- dev_dbg(&entry->attr.device->dev, "%s port=%d index=%d gid %pI6\n",
+ dev_dbg(&entry->attr.device->dev, "%s port=%u index=%u gid %pI6\n",
__func__, entry->attr.port_num, entry->attr.index,
entry->attr.gid.raw);
@@ -354,7 +354,7 @@ static int add_roce_gid(struct ib_gid_table_entry *entry)
int ret;
if (!attr->ndev) {
- dev_err(&attr->device->dev, "%s NULL netdev port=%d index=%d\n",
+ dev_err(&attr->device->dev, "%s NULL netdev port=%u index=%u\n",
__func__, attr->port_num, attr->index);
return -EINVAL;
}
@@ -362,7 +362,7 @@ static int add_roce_gid(struct ib_gid_table_entry *entry)
ret = attr->device->ops.add_gid(attr, &entry->context);
if (ret) {
dev_err(&attr->device->dev,
- "%s GID add failed port=%d index=%d\n",
+ "%s GID add failed port=%u index=%u\n",
__func__, attr->port_num, attr->index);
return ret;
}
@@ -805,7 +805,7 @@ static void release_gid_table(struct ib_device *device,
continue;
if (kref_read(&table->data_vec[i]->kref) > 1) {
dev_err(&device->dev,
- "GID entry ref leak for index %d ref=%d\n", i,
+ "GID entry ref leak for index %d ref=%u\n", i,
kref_read(&table->data_vec[i]->kref));
leak = true;
}
@@ -1069,19 +1069,14 @@ int ib_get_cached_pkey(struct ib_device *device,
}
EXPORT_SYMBOL(ib_get_cached_pkey);
-int ib_get_cached_subnet_prefix(struct ib_device *device, u32 port_num,
+void ib_get_cached_subnet_prefix(struct ib_device *device, u32 port_num,
u64 *sn_pfx)
{
unsigned long flags;
- if (!rdma_is_port_valid(device, port_num))
- return -EINVAL;
-
read_lock_irqsave(&device->cache_lock, flags);
*sn_pfx = device->port_data[port_num].cache.subnet_prefix;
read_unlock_irqrestore(&device->cache_lock, flags);
-
- return 0;
}
EXPORT_SYMBOL(ib_get_cached_subnet_prefix);
@@ -1465,10 +1460,12 @@ err:
}
static int
-ib_cache_update(struct ib_device *device, u32 port, bool enforce_security)
+ib_cache_update(struct ib_device *device, u32 port, bool update_gids,
+ bool update_pkeys, bool enforce_security)
{
struct ib_port_attr *tprops = NULL;
- struct ib_pkey_cache *pkey_cache = NULL, *old_pkey_cache;
+ struct ib_pkey_cache *pkey_cache = NULL;
+ struct ib_pkey_cache *old_pkey_cache = NULL;
int i;
int ret;
@@ -1485,14 +1482,16 @@ ib_cache_update(struct ib_device *device, u32 port, bool enforce_security)
goto err;
}
- if (!rdma_protocol_roce(device, port)) {
+ if (!rdma_protocol_roce(device, port) && update_gids) {
ret = config_non_roce_gid_cache(device, port,
tprops->gid_tbl_len);
if (ret)
goto err;
}
- if (tprops->pkey_tbl_len) {
+ update_pkeys &= !!tprops->pkey_tbl_len;
+
+ if (update_pkeys) {
pkey_cache = kmalloc(struct_size(pkey_cache, table,
tprops->pkey_tbl_len),
GFP_KERNEL);
@@ -1517,9 +1516,10 @@ ib_cache_update(struct ib_device *device, u32 port, bool enforce_security)
write_lock_irq(&device->cache_lock);
- old_pkey_cache = device->port_data[port].cache.pkey;
-
- device->port_data[port].cache.pkey = pkey_cache;
+ if (update_pkeys) {
+ old_pkey_cache = device->port_data[port].cache.pkey;
+ device->port_data[port].cache.pkey = pkey_cache;
+ }
device->port_data[port].cache.lmc = tprops->lmc;
device->port_data[port].cache.port_state = tprops->state;
@@ -1551,6 +1551,8 @@ static void ib_cache_event_task(struct work_struct *_work)
* the cache.
*/
ret = ib_cache_update(work->event.device, work->event.element.port_num,
+ work->event.event == IB_EVENT_GID_CHANGE,
+ work->event.event == IB_EVENT_PKEY_CHANGE,
work->enforce_security);
/* GID event is notified already for individual GID entries by
@@ -1624,7 +1626,7 @@ int ib_cache_setup_one(struct ib_device *device)
return err;
rdma_for_each_port (device, p) {
- err = ib_cache_update(device, p, true);
+ err = ib_cache_update(device, p, true, true, true);
if (err)
return err;
}
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 0ead0d223154..c903b74f46a4 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -25,6 +25,7 @@
#include <rdma/ib_cache.h>
#include <rdma/ib_cm.h>
+#include <rdma/ib_sysfs.h>
#include "cm_msgs.h"
#include "core_priv.h"
#include "cm_trace.h"
@@ -121,8 +122,6 @@ static struct ib_cm {
__be32 random_id_operand;
struct list_head timewait_list;
struct workqueue_struct *wq;
- /* Sync on cm change port state */
- spinlock_t state_lock;
} cm;
/* Counter indexes ordered by attribute ID */
@@ -150,66 +149,23 @@ enum {
CM_COUNTER_GROUPS
};
-static char const counter_group_names[CM_COUNTER_GROUPS]
- [sizeof("cm_rx_duplicates")] = {
- "cm_tx_msgs", "cm_tx_retries",
- "cm_rx_msgs", "cm_rx_duplicates"
-};
-
-struct cm_counter_group {
- struct kobject obj;
- atomic_long_t counter[CM_ATTR_COUNT];
-};
-
struct cm_counter_attribute {
- struct attribute attr;
- int index;
-};
-
-#define CM_COUNTER_ATTR(_name, _index) \
-struct cm_counter_attribute cm_##_name##_counter_attr = { \
- .attr = { .name = __stringify(_name), .mode = 0444 }, \
- .index = _index \
-}
-
-static CM_COUNTER_ATTR(req, CM_REQ_COUNTER);
-static CM_COUNTER_ATTR(mra, CM_MRA_COUNTER);
-static CM_COUNTER_ATTR(rej, CM_REJ_COUNTER);
-static CM_COUNTER_ATTR(rep, CM_REP_COUNTER);
-static CM_COUNTER_ATTR(rtu, CM_RTU_COUNTER);
-static CM_COUNTER_ATTR(dreq, CM_DREQ_COUNTER);
-static CM_COUNTER_ATTR(drep, CM_DREP_COUNTER);
-static CM_COUNTER_ATTR(sidr_req, CM_SIDR_REQ_COUNTER);
-static CM_COUNTER_ATTR(sidr_rep, CM_SIDR_REP_COUNTER);
-static CM_COUNTER_ATTR(lap, CM_LAP_COUNTER);
-static CM_COUNTER_ATTR(apr, CM_APR_COUNTER);
-
-static struct attribute *cm_counter_default_attrs[] = {
- &cm_req_counter_attr.attr,
- &cm_mra_counter_attr.attr,
- &cm_rej_counter_attr.attr,
- &cm_rep_counter_attr.attr,
- &cm_rtu_counter_attr.attr,
- &cm_dreq_counter_attr.attr,
- &cm_drep_counter_attr.attr,
- &cm_sidr_req_counter_attr.attr,
- &cm_sidr_rep_counter_attr.attr,
- &cm_lap_counter_attr.attr,
- &cm_apr_counter_attr.attr,
- NULL
+ struct ib_port_attribute attr;
+ unsigned short group;
+ unsigned short index;
};
struct cm_port {
struct cm_device *cm_dev;
struct ib_mad_agent *mad_agent;
u32 port_num;
- struct list_head cm_priv_prim_list;
- struct list_head cm_priv_altr_list;
- struct cm_counter_group counter_group[CM_COUNTER_GROUPS];
+ atomic_long_t counters[CM_COUNTER_GROUPS][CM_ATTR_COUNT];
};
struct cm_device {
+ struct kref kref;
struct list_head list;
+ spinlock_t mad_agent_lock;
struct ib_device *ib_device;
u8 ack_delay;
int going_down;
@@ -218,7 +174,6 @@ struct cm_device {
struct cm_av {
struct cm_port *port;
- union ib_gid dgid;
struct rdma_ah_attr ah_attr;
u16 pkey_index;
u8 timeout;
@@ -251,6 +206,7 @@ struct cm_id_private {
struct rb_node service_node;
struct rb_node sidr_id_node;
+ u32 sidr_slid;
spinlock_t lock; /* Do not acquire inside cm.lock */
struct completion comp;
refcount_t refcount;
@@ -285,18 +241,28 @@ struct cm_id_private {
u8 service_timeout;
u8 target_ack_delay;
- struct list_head prim_list;
- struct list_head altr_list;
- /* Indicates that the send port mad is registered and av is set */
- int prim_send_port_not_ready;
- int altr_send_port_not_ready;
-
struct list_head work_list;
atomic_t work_count;
struct rdma_ucm_ece ece;
};
+static void cm_dev_release(struct kref *kref)
+{
+ struct cm_device *cm_dev = container_of(kref, struct cm_device, kref);
+ u32 i;
+
+ rdma_for_each_port(cm_dev->ib_device, i)
+ kfree(cm_dev->port[i - 1]);
+
+ kfree(cm_dev);
+}
+
+static void cm_device_put(struct cm_device *cm_dev)
+{
+ kref_put(&cm_dev->kref, cm_dev_release);
+}
+
static void cm_work_handler(struct work_struct *work);
static inline void cm_deref_id(struct cm_id_private *cm_id_priv)
@@ -305,52 +271,37 @@ static inline void cm_deref_id(struct cm_id_private *cm_id_priv)
complete(&cm_id_priv->comp);
}
-static int cm_alloc_msg(struct cm_id_private *cm_id_priv,
- struct ib_mad_send_buf **msg)
+static struct ib_mad_send_buf *cm_alloc_msg(struct cm_id_private *cm_id_priv)
{
struct ib_mad_agent *mad_agent;
struct ib_mad_send_buf *m;
struct ib_ah *ah;
- struct cm_av *av;
- unsigned long flags, flags2;
- int ret = 0;
- /* don't let the port to be released till the agent is down */
- spin_lock_irqsave(&cm.state_lock, flags2);
- spin_lock_irqsave(&cm.lock, flags);
- if (!cm_id_priv->prim_send_port_not_ready)
- av = &cm_id_priv->av;
- else if (!cm_id_priv->altr_send_port_not_ready &&
- (cm_id_priv->alt_av.port))
- av = &cm_id_priv->alt_av;
- else {
- pr_info("%s: not valid CM id\n", __func__);
- ret = -ENODEV;
- spin_unlock_irqrestore(&cm.lock, flags);
- goto out;
- }
- spin_unlock_irqrestore(&cm.lock, flags);
- /* Make sure the port haven't released the mad yet */
+ lockdep_assert_held(&cm_id_priv->lock);
+
+ if (!cm_id_priv->av.port)
+ return ERR_PTR(-EINVAL);
+
+ spin_lock(&cm_id_priv->av.port->cm_dev->mad_agent_lock);
mad_agent = cm_id_priv->av.port->mad_agent;
if (!mad_agent) {
- pr_info("%s: not a valid MAD agent\n", __func__);
- ret = -ENODEV;
+ m = ERR_PTR(-EINVAL);
goto out;
}
- ah = rdma_create_ah(mad_agent->qp->pd, &av->ah_attr, 0);
+
+ ah = rdma_create_ah(mad_agent->qp->pd, &cm_id_priv->av.ah_attr, 0);
if (IS_ERR(ah)) {
- ret = PTR_ERR(ah);
+ m = ERR_CAST(ah);
goto out;
}
m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn,
- av->pkey_index,
+ cm_id_priv->av.pkey_index,
0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
GFP_ATOMIC,
IB_MGMT_BASE_VERSION);
if (IS_ERR(m)) {
rdma_destroy_ah(ah, 0);
- ret = PTR_ERR(m);
goto out;
}
@@ -360,11 +311,49 @@ static int cm_alloc_msg(struct cm_id_private *cm_id_priv,
refcount_inc(&cm_id_priv->refcount);
m->context[0] = cm_id_priv;
- *msg = m;
out:
- spin_unlock_irqrestore(&cm.state_lock, flags2);
- return ret;
+ spin_unlock(&cm_id_priv->av.port->cm_dev->mad_agent_lock);
+ return m;
+}
+
+static void cm_free_msg(struct ib_mad_send_buf *msg)
+{
+ struct cm_id_private *cm_id_priv = msg->context[0];
+
+ if (msg->ah)
+ rdma_destroy_ah(msg->ah, 0);
+ cm_deref_id(cm_id_priv);
+ ib_free_send_mad(msg);
+}
+
+static struct ib_mad_send_buf *
+cm_alloc_priv_msg(struct cm_id_private *cm_id_priv)
+{
+ struct ib_mad_send_buf *msg;
+
+ lockdep_assert_held(&cm_id_priv->lock);
+
+ msg = cm_alloc_msg(cm_id_priv);
+ if (IS_ERR(msg))
+ return msg;
+ cm_id_priv->msg = msg;
+ return msg;
+}
+
+static void cm_free_priv_msg(struct ib_mad_send_buf *msg)
+{
+ struct cm_id_private *cm_id_priv = msg->context[0];
+
+ lockdep_assert_held(&cm_id_priv->lock);
+
+ if (!WARN_ON(cm_id_priv->msg != msg))
+ cm_id_priv->msg = NULL;
+
+ if (msg->ah)
+ rdma_destroy_ah(msg->ah, 0);
+ cm_deref_id(cm_id_priv);
+ ib_free_send_mad(msg);
}
static struct ib_mad_send_buf *cm_alloc_response_msg_no_ah(struct cm_port *port,
@@ -391,15 +380,6 @@ static int cm_create_response_msg_ah(struct cm_port *port,
return 0;
}
-static void cm_free_msg(struct ib_mad_send_buf *msg)
-{
- if (msg->ah)
- rdma_destroy_ah(msg->ah, 0);
- if (msg->context[0])
- cm_deref_id(msg->context[0]);
- ib_free_send_mad(msg);
-}
-
static int cm_alloc_response_msg(struct cm_port *port,
struct ib_mad_recv_wc *mad_recv_wc,
struct ib_mad_send_buf **msg)
@@ -413,7 +393,7 @@ static int cm_alloc_response_msg(struct cm_port *port,
ret = cm_create_response_msg_ah(port, mad_recv_wc, m);
if (ret) {
- cm_free_msg(m);
+ ib_free_send_mad(m);
return ret;
}
@@ -421,6 +401,13 @@ static int cm_alloc_response_msg(struct cm_port *port,
return 0;
}
+static void cm_free_response_msg(struct ib_mad_send_buf *msg)
+{
+ if (msg->ah)
+ rdma_destroy_ah(msg->ah, 0);
+ ib_free_send_mad(msg);
+}
+
static void *cm_copy_private_data(const void *private_data, u8 private_data_len)
{
void *data;
@@ -445,57 +432,38 @@ static void cm_set_private_data(struct cm_id_private *cm_id_priv,
cm_id_priv->private_data_len = private_data_len;
}
-static int cm_init_av_for_lap(struct cm_port *port, struct ib_wc *wc,
- struct ib_grh *grh, struct cm_av *av)
+static void cm_set_av_port(struct cm_av *av, struct cm_port *port)
{
- struct rdma_ah_attr new_ah_attr;
- int ret;
+ struct cm_port *old_port = av->port;
- av->port = port;
- av->pkey_index = wc->pkey_index;
+ if (old_port == port)
+ return;
- /*
- * av->ah_attr might be initialized based on past wc during incoming
- * connect request or while sending out connect request. So initialize
- * a new ah_attr on stack. If initialization fails, old ah_attr is
- * used for sending any responses. If initialization is successful,
- * than new ah_attr is used by overwriting old one.
- */
- ret = ib_init_ah_attr_from_wc(port->cm_dev->ib_device,
- port->port_num, wc,
- grh, &new_ah_attr);
- if (ret)
- return ret;
+ av->port = port;
+ if (old_port)
+ cm_device_put(old_port->cm_dev);
+ if (port)
+ kref_get(&port->cm_dev->kref);
+}
- rdma_move_ah_attr(&av->ah_attr, &new_ah_attr);
- return 0;
+static void cm_init_av_for_lap(struct cm_port *port, struct ib_wc *wc,
+ struct rdma_ah_attr *ah_attr, struct cm_av *av)
+{
+ cm_set_av_port(av, port);
+ av->pkey_index = wc->pkey_index;
+ rdma_move_ah_attr(&av->ah_attr, ah_attr);
}
static int cm_init_av_for_response(struct cm_port *port, struct ib_wc *wc,
struct ib_grh *grh, struct cm_av *av)
{
- av->port = port;
+ cm_set_av_port(av, port);
av->pkey_index = wc->pkey_index;
return ib_init_ah_attr_from_wc(port->cm_dev->ib_device,
port->port_num, wc,
grh, &av->ah_attr);
}
-static void add_cm_id_to_port_list(struct cm_id_private *cm_id_priv,
- struct cm_av *av, struct cm_port *port)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cm.lock, flags);
- if (&cm_id_priv->av == av)
- list_add_tail(&cm_id_priv->prim_list, &port->cm_priv_prim_list);
- else if (&cm_id_priv->alt_av == av)
- list_add_tail(&cm_id_priv->altr_list, &port->cm_priv_altr_list);
- else
- WARN_ON(true);
- spin_unlock_irqrestore(&cm.lock, flags);
-}
-
static struct cm_port *
get_cm_port_from_path(struct sa_path_rec *path, const struct ib_gid_attr *attr)
{
@@ -539,8 +507,7 @@ get_cm_port_from_path(struct sa_path_rec *path, const struct ib_gid_attr *attr)
static int cm_init_av_by_path(struct sa_path_rec *path,
const struct ib_gid_attr *sgid_attr,
- struct cm_av *av,
- struct cm_id_private *cm_id_priv)
+ struct cm_av *av)
{
struct rdma_ah_attr new_ah_attr;
struct cm_device *cm_dev;
@@ -557,7 +524,7 @@ static int cm_init_av_by_path(struct sa_path_rec *path,
if (ret)
return ret;
- av->port = port;
+ cm_set_av_port(av, port);
/*
* av->ah_attr might be initialized based on wc or during
@@ -574,11 +541,26 @@ static int cm_init_av_by_path(struct sa_path_rec *path,
return ret;
av->timeout = path->packet_life_time + 1;
- add_cm_id_to_port_list(cm_id_priv, av, port);
rdma_move_ah_attr(&av->ah_attr, &new_ah_attr);
return 0;
}
+/* Move av created by cm_init_av_by_path(), so av.dgid is not moved */
+static void cm_move_av_from_path(struct cm_av *dest, struct cm_av *src)
+{
+ cm_set_av_port(dest, src->port);
+ cm_set_av_port(src, NULL);
+ dest->pkey_index = src->pkey_index;
+ rdma_move_ah_attr(&dest->ah_attr, &src->ah_attr);
+ dest->timeout = src->timeout;
+}
+
+static void cm_destroy_av(struct cm_av *av)
+{
+ rdma_destroy_ah_attr(&av->ah_attr);
+ cm_set_av_port(av, NULL);
+}
+
static u32 cm_local_id(__be32 local_id)
{
return (__force u32) (local_id ^ cm.random_id_operand);
@@ -803,7 +785,6 @@ cm_insert_remote_sidr(struct cm_id_private *cm_id_priv)
struct rb_node **link = &cm.remote_sidr_table.rb_node;
struct rb_node *parent = NULL;
struct cm_id_private *cur_cm_id_priv;
- union ib_gid *port_gid = &cm_id_priv->av.dgid;
__be32 remote_id = cm_id_priv->id.remote_id;
while (*link) {
@@ -815,12 +796,9 @@ cm_insert_remote_sidr(struct cm_id_private *cm_id_priv)
else if (be32_gt(remote_id, cur_cm_id_priv->id.remote_id))
link = &(*link)->rb_right;
else {
- int cmp;
- cmp = memcmp(port_gid, &cur_cm_id_priv->av.dgid,
- sizeof *port_gid);
- if (cmp < 0)
+ if (cur_cm_id_priv->sidr_slid < cm_id_priv->sidr_slid)
link = &(*link)->rb_left;
- else if (cmp > 0)
+ else if (cur_cm_id_priv->sidr_slid > cm_id_priv->sidr_slid)
link = &(*link)->rb_right;
else
return cur_cm_id_priv;
@@ -854,8 +832,6 @@ static struct cm_id_private *cm_alloc_id_priv(struct ib_device *device,
spin_lock_init(&cm_id_priv->lock);
init_completion(&cm_id_priv->comp);
INIT_LIST_HEAD(&cm_id_priv->work_list);
- INIT_LIST_HEAD(&cm_id_priv->prim_list);
- INIT_LIST_HEAD(&cm_id_priv->altr_list);
atomic_set(&cm_id_priv->work_count, -1);
refcount_set(&cm_id_priv->refcount, 1);
@@ -1082,7 +1058,7 @@ retest:
break;
case IB_CM_SIDR_REQ_SENT:
cm_id->state = IB_CM_IDLE;
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
break;
case IB_CM_SIDR_REQ_RCVD:
cm_send_sidr_rep_locked(cm_id_priv,
@@ -1093,7 +1069,7 @@ retest:
break;
case IB_CM_REQ_SENT:
case IB_CM_MRA_REQ_RCVD:
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
cm_send_rej_locked(cm_id_priv, IB_CM_REJ_TIMEOUT,
&cm_id_priv->id.device->node_guid,
sizeof(cm_id_priv->id.device->node_guid),
@@ -1111,7 +1087,7 @@ retest:
break;
case IB_CM_REP_SENT:
case IB_CM_MRA_REP_RCVD:
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
cm_send_rej_locked(cm_id_priv, IB_CM_REJ_CONSUMER_DEFINED, NULL,
0, NULL, 0);
goto retest;
@@ -1129,7 +1105,7 @@ retest:
cm_send_dreq_locked(cm_id_priv, NULL, 0);
goto retest;
case IB_CM_DREQ_SENT:
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
cm_enter_timewait(cm_id_priv);
goto retest;
case IB_CM_DREQ_RCVD:
@@ -1156,12 +1132,7 @@ retest:
kfree(cm_id_priv->timewait_info);
cm_id_priv->timewait_info = NULL;
}
- if (!list_empty(&cm_id_priv->altr_list) &&
- (!cm_id_priv->altr_send_port_not_ready))
- list_del(&cm_id_priv->altr_list);
- if (!list_empty(&cm_id_priv->prim_list) &&
- (!cm_id_priv->prim_send_port_not_ready))
- list_del(&cm_id_priv->prim_list);
+
WARN_ON(cm_id_priv->listen_sharecount);
WARN_ON(!RB_EMPTY_NODE(&cm_id_priv->service_node));
if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node))
@@ -1175,8 +1146,8 @@ retest:
while ((work = cm_dequeue_work(cm_id_priv)) != NULL)
cm_free_work(work);
- rdma_destroy_ah_attr(&cm_id_priv->av.ah_attr);
- rdma_destroy_ah_attr(&cm_id_priv->alt_av.ah_attr);
+ cm_destroy_av(&cm_id_priv->av);
+ cm_destroy_av(&cm_id_priv->alt_av);
kfree(cm_id_priv->private_data);
kfree_rcu(cm_id_priv, rcu);
}
@@ -1308,10 +1279,18 @@ EXPORT_SYMBOL(ib_cm_insert_listen);
static __be64 cm_form_tid(struct cm_id_private *cm_id_priv)
{
- u64 hi_tid, low_tid;
+ u64 hi_tid = 0, low_tid;
- hi_tid = ((u64) cm_id_priv->av.port->mad_agent->hi_tid) << 32;
- low_tid = (u64)cm_id_priv->id.local_id;
+ lockdep_assert_held(&cm_id_priv->lock);
+
+ low_tid = (u64)cm_id_priv->id.local_id;
+ if (!cm_id_priv->av.port)
+ return cpu_to_be64(low_tid);
+
+ spin_lock(&cm_id_priv->av.port->cm_dev->mad_agent_lock);
+ if (cm_id_priv->av.port->mad_agent)
+ hi_tid = ((u64)cm_id_priv->av.port->mad_agent->hi_tid) << 32;
+ spin_unlock(&cm_id_priv->av.port->cm_dev->mad_agent_lock);
return cpu_to_be64(hi_tid | low_tid);
}
@@ -1500,7 +1479,9 @@ static int cm_validate_req_param(struct ib_cm_req_param *param)
int ib_send_cm_req(struct ib_cm_id *cm_id,
struct ib_cm_req_param *param)
{
+ struct cm_av av = {}, alt_av = {};
struct cm_id_private *cm_id_priv;
+ struct ib_mad_send_buf *msg;
struct cm_req_msg *req_msg;
unsigned long flags;
int ret;
@@ -1514,8 +1495,7 @@ int ib_send_cm_req(struct ib_cm_id *cm_id,
spin_lock_irqsave(&cm_id_priv->lock, flags);
if (cm_id->state != IB_CM_IDLE || WARN_ON(cm_id_priv->timewait_info)) {
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
@@ -1524,19 +1504,20 @@ int ib_send_cm_req(struct ib_cm_id *cm_id,
if (IS_ERR(cm_id_priv->timewait_info)) {
ret = PTR_ERR(cm_id_priv->timewait_info);
cm_id_priv->timewait_info = NULL;
- goto out;
+ return ret;
}
ret = cm_init_av_by_path(param->primary_path,
- param->ppath_sgid_attr, &cm_id_priv->av,
- cm_id_priv);
+ param->ppath_sgid_attr, &av);
if (ret)
- goto out;
+ return ret;
if (param->alternate_path) {
ret = cm_init_av_by_path(param->alternate_path, NULL,
- &cm_id_priv->alt_av, cm_id_priv);
- if (ret)
- goto out;
+ &alt_av);
+ if (ret) {
+ cm_destroy_av(&av);
+ return ret;
+ }
}
cm_id->service_id = param->service_id;
cm_id->service_mask = ~cpu_to_be64(0);
@@ -1552,33 +1533,40 @@ int ib_send_cm_req(struct ib_cm_id *cm_id,
cm_id_priv->pkey = param->primary_path->pkey;
cm_id_priv->qp_type = param->qp_type;
- ret = cm_alloc_msg(cm_id_priv, &cm_id_priv->msg);
- if (ret)
- goto out;
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+
+ cm_move_av_from_path(&cm_id_priv->av, &av);
+ if (param->alternate_path)
+ cm_move_av_from_path(&cm_id_priv->alt_av, &alt_av);
+
+ msg = cm_alloc_priv_msg(cm_id_priv);
+ if (IS_ERR(msg)) {
+ ret = PTR_ERR(msg);
+ goto out_unlock;
+ }
- req_msg = (struct cm_req_msg *) cm_id_priv->msg->mad;
+ req_msg = (struct cm_req_msg *)msg->mad;
cm_format_req(req_msg, cm_id_priv, param);
cm_id_priv->tid = req_msg->hdr.tid;
- cm_id_priv->msg->timeout_ms = cm_id_priv->timeout_ms;
- cm_id_priv->msg->context[1] = (void *) (unsigned long) IB_CM_REQ_SENT;
+ msg->timeout_ms = cm_id_priv->timeout_ms;
+ msg->context[1] = (void *)(unsigned long)IB_CM_REQ_SENT;
cm_id_priv->local_qpn = cpu_to_be32(IBA_GET(CM_REQ_LOCAL_QPN, req_msg));
cm_id_priv->rq_psn = cpu_to_be32(IBA_GET(CM_REQ_STARTING_PSN, req_msg));
trace_icm_send_req(&cm_id_priv->id);
- spin_lock_irqsave(&cm_id_priv->lock, flags);
- ret = ib_post_send_mad(cm_id_priv->msg, NULL);
- if (ret) {
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
- goto error2;
- }
+ ret = ib_post_send_mad(msg, NULL);
+ if (ret)
+ goto out_free;
BUG_ON(cm_id->state != IB_CM_IDLE);
cm_id->state = IB_CM_REQ_SENT;
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
return 0;
-
-error2: cm_free_msg(cm_id_priv->msg);
-out: return ret;
+out_free:
+ cm_free_priv_msg(msg);
+out_unlock:
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ return ret;
}
EXPORT_SYMBOL(ib_send_cm_req);
@@ -1618,7 +1606,7 @@ static int cm_issue_rej(struct cm_port *port,
IBA_GET(CM_REJ_REMOTE_COMM_ID, rcv_msg));
ret = ib_post_send_mad(msg, NULL);
if (ret)
- cm_free_msg(msg);
+ cm_free_response_msg(msg);
return ret;
}
@@ -1757,7 +1745,7 @@ static u16 cm_get_bth_pkey(struct cm_work *work)
ret = ib_get_cached_pkey(ib_dev, port_num, pkey_index, &pkey);
if (ret) {
- dev_warn_ratelimited(&ib_dev->dev, "ib_cm: Couldn't retrieve pkey for incoming request (port %d, pkey index %d). %d\n",
+ dev_warn_ratelimited(&ib_dev->dev, "ib_cm: Couldn't retrieve pkey for incoming request (port %u, pkey index %u). %d\n",
port_num, pkey_index, ret);
return 0;
}
@@ -1934,8 +1922,8 @@ static void cm_dup_req_handler(struct cm_work *work,
struct ib_mad_send_buf *msg = NULL;
int ret;
- atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
- counter[CM_REQ_COUNTER]);
+ atomic_long_inc(
+ &work->port->counters[CM_RECV_DUPLICATES][CM_REQ_COUNTER]);
/* Quick state check to discard duplicate REQs. */
spin_lock_irq(&cm_id_priv->lock);
@@ -1974,7 +1962,7 @@ static void cm_dup_req_handler(struct cm_work *work,
return;
unlock: spin_unlock_irq(&cm_id_priv->lock);
-free: cm_free_msg(msg);
+free: cm_free_response_msg(msg);
}
static struct cm_id_private *cm_match_req(struct cm_work *work,
@@ -2163,8 +2151,10 @@ static int cm_req_handler(struct cm_work *work)
sa_path_set_dmac(&work->path[0],
cm_id_priv->av.ah_attr.roce.dmac);
work->path[0].hop_limit = grh->hop_limit;
- ret = cm_init_av_by_path(&work->path[0], gid_attr, &cm_id_priv->av,
- cm_id_priv);
+
+ /* This destroy call is needed to pair with cm_init_av_for_response */
+ cm_destroy_av(&cm_id_priv->av);
+ ret = cm_init_av_by_path(&work->path[0], gid_attr, &cm_id_priv->av);
if (ret) {
int err;
@@ -2183,7 +2173,7 @@ static int cm_req_handler(struct cm_work *work)
}
if (cm_req_has_alt_path(req_msg)) {
ret = cm_init_av_by_path(&work->path[1], NULL,
- &cm_id_priv->alt_av, cm_id_priv);
+ &cm_id_priv->alt_av);
if (ret) {
ib_send_cm_rej(&cm_id_priv->id,
IB_CM_REJ_INVALID_ALT_GID,
@@ -2283,9 +2273,11 @@ int ib_send_cm_rep(struct ib_cm_id *cm_id,
goto out;
}
- ret = cm_alloc_msg(cm_id_priv, &msg);
- if (ret)
+ msg = cm_alloc_priv_msg(cm_id_priv);
+ if (IS_ERR(msg)) {
+ ret = PTR_ERR(msg);
goto out;
+ }
rep_msg = (struct cm_rep_msg *) msg->mad;
cm_format_rep(rep_msg, cm_id_priv, param);
@@ -2294,14 +2286,10 @@ int ib_send_cm_rep(struct ib_cm_id *cm_id,
trace_icm_send_rep(cm_id);
ret = ib_post_send_mad(msg, NULL);
- if (ret) {
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
- cm_free_msg(msg);
- return ret;
- }
+ if (ret)
+ goto out_free;
cm_id->state = IB_CM_REP_SENT;
- cm_id_priv->msg = msg;
cm_id_priv->initiator_depth = param->initiator_depth;
cm_id_priv->responder_resources = param->responder_resources;
cm_id_priv->rq_psn = cpu_to_be32(IBA_GET(CM_REP_STARTING_PSN, rep_msg));
@@ -2309,8 +2297,13 @@ int ib_send_cm_rep(struct ib_cm_id *cm_id,
"IBTA declares QPN to be 24 bits, but it is 0x%X\n",
param->qp_num);
cm_id_priv->local_qpn = cpu_to_be32(param->qp_num & 0xFFFFFF);
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ return 0;
-out: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+out_free:
+ cm_free_priv_msg(msg);
+out:
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
return ret;
}
EXPORT_SYMBOL(ib_send_cm_rep);
@@ -2357,9 +2350,11 @@ int ib_send_cm_rtu(struct ib_cm_id *cm_id,
goto error;
}
- ret = cm_alloc_msg(cm_id_priv, &msg);
- if (ret)
+ msg = cm_alloc_msg(cm_id_priv);
+ if (IS_ERR(msg)) {
+ ret = PTR_ERR(msg);
goto error;
+ }
cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv,
private_data, private_data_len);
@@ -2426,8 +2421,8 @@ static void cm_dup_rep_handler(struct cm_work *work)
if (!cm_id_priv)
return;
- atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
- counter[CM_REP_COUNTER]);
+ atomic_long_inc(
+ &work->port->counters[CM_RECV_DUPLICATES][CM_REP_COUNTER]);
ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg);
if (ret)
goto deref;
@@ -2453,7 +2448,7 @@ static void cm_dup_rep_handler(struct cm_work *work)
goto deref;
unlock: spin_unlock_irq(&cm_id_priv->lock);
-free: cm_free_msg(msg);
+free: cm_free_response_msg(msg);
deref: cm_deref_id(cm_id_priv);
}
@@ -2553,7 +2548,7 @@ static int cm_rep_handler(struct cm_work *work)
cm_ack_timeout(cm_id_priv->target_ack_delay,
cm_id_priv->alt_av.timeout - 1);
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
cm_queue_work_unlock(cm_id_priv, work);
return 0;
@@ -2577,7 +2572,7 @@ static int cm_establish_handler(struct cm_work *work)
goto out;
}
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
cm_queue_work_unlock(cm_id_priv, work);
return 0;
out:
@@ -2604,13 +2599,13 @@ static int cm_rtu_handler(struct cm_work *work)
if (cm_id_priv->id.state != IB_CM_REP_SENT &&
cm_id_priv->id.state != IB_CM_MRA_REP_RCVD) {
spin_unlock_irq(&cm_id_priv->lock);
- atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
- counter[CM_RTU_COUNTER]);
+ atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
+ [CM_RTU_COUNTER]);
goto out;
}
cm_id_priv->id.state = IB_CM_ESTABLISHED;
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
cm_queue_work_unlock(cm_id_priv, work);
return 0;
out:
@@ -2655,12 +2650,12 @@ static int cm_send_dreq_locked(struct cm_id_private *cm_id_priv,
if (cm_id_priv->id.lap_state == IB_CM_LAP_SENT ||
cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD)
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
- ret = cm_alloc_msg(cm_id_priv, &msg);
- if (ret) {
+ msg = cm_alloc_priv_msg(cm_id_priv);
+ if (IS_ERR(msg)) {
cm_enter_timewait(cm_id_priv);
- return ret;
+ return PTR_ERR(msg);
}
cm_format_dreq((struct cm_dreq_msg *) msg->mad, cm_id_priv,
@@ -2672,12 +2667,11 @@ static int cm_send_dreq_locked(struct cm_id_private *cm_id_priv,
ret = ib_post_send_mad(msg, NULL);
if (ret) {
cm_enter_timewait(cm_id_priv);
- cm_free_msg(msg);
+ cm_free_priv_msg(msg);
return ret;
}
cm_id_priv->id.state = IB_CM_DREQ_SENT;
- cm_id_priv->msg = msg;
return 0;
}
@@ -2732,9 +2726,9 @@ static int cm_send_drep_locked(struct cm_id_private *cm_id_priv,
cm_set_private_data(cm_id_priv, private_data, private_data_len);
cm_enter_timewait(cm_id_priv);
- ret = cm_alloc_msg(cm_id_priv, &msg);
- if (ret)
- return ret;
+ msg = cm_alloc_msg(cm_id_priv);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv,
private_data, private_data_len);
@@ -2794,7 +2788,7 @@ static int cm_issue_drep(struct cm_port *port,
IBA_GET(CM_DREQ_REMOTE_COMM_ID, dreq_msg));
ret = ib_post_send_mad(msg, NULL);
if (ret)
- cm_free_msg(msg);
+ cm_free_response_msg(msg);
return ret;
}
@@ -2810,8 +2804,8 @@ static int cm_dreq_handler(struct cm_work *work)
cpu_to_be32(IBA_GET(CM_DREQ_REMOTE_COMM_ID, dreq_msg)),
cpu_to_be32(IBA_GET(CM_DREQ_LOCAL_COMM_ID, dreq_msg)));
if (!cm_id_priv) {
- atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
- counter[CM_DREQ_COUNTER]);
+ atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
+ [CM_DREQ_COUNTER]);
cm_issue_drep(work->port, work->mad_recv_wc);
trace_icm_no_priv_err(
IBA_GET(CM_DREQ_LOCAL_COMM_ID, dreq_msg),
@@ -2830,18 +2824,18 @@ static int cm_dreq_handler(struct cm_work *work)
switch (cm_id_priv->id.state) {
case IB_CM_REP_SENT:
case IB_CM_DREQ_SENT:
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
break;
case IB_CM_ESTABLISHED:
if (cm_id_priv->id.lap_state == IB_CM_LAP_SENT ||
cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD)
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
break;
case IB_CM_MRA_REP_RCVD:
break;
case IB_CM_TIMEWAIT:
- atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
- counter[CM_DREQ_COUNTER]);
+ atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
+ [CM_DREQ_COUNTER]);
msg = cm_alloc_response_msg_no_ah(work->port, work->mad_recv_wc);
if (IS_ERR(msg))
goto unlock;
@@ -2853,11 +2847,11 @@ static int cm_dreq_handler(struct cm_work *work)
if (cm_create_response_msg_ah(work->port, work->mad_recv_wc, msg) ||
ib_post_send_mad(msg, NULL))
- cm_free_msg(msg);
+ cm_free_response_msg(msg);
goto deref;
case IB_CM_DREQ_RCVD:
- atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
- counter[CM_DREQ_COUNTER]);
+ atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
+ [CM_DREQ_COUNTER]);
goto unlock;
default:
trace_icm_dreq_unknown_err(&cm_id_priv->id);
@@ -2896,7 +2890,7 @@ static int cm_drep_handler(struct cm_work *work)
}
cm_enter_timewait(cm_id_priv);
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
cm_queue_work_unlock(cm_id_priv, work);
return 0;
out:
@@ -2927,9 +2921,9 @@ static int cm_send_rej_locked(struct cm_id_private *cm_id_priv,
case IB_CM_REP_RCVD:
case IB_CM_MRA_REP_SENT:
cm_reset_to_idle(cm_id_priv);
- ret = cm_alloc_msg(cm_id_priv, &msg);
- if (ret)
- return ret;
+ msg = cm_alloc_msg(cm_id_priv);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
cm_format_rej((struct cm_rej_msg *)msg->mad, cm_id_priv, reason,
ari, ari_length, private_data, private_data_len,
state);
@@ -2937,9 +2931,9 @@ static int cm_send_rej_locked(struct cm_id_private *cm_id_priv,
case IB_CM_REP_SENT:
case IB_CM_MRA_REP_RCVD:
cm_enter_timewait(cm_id_priv);
- ret = cm_alloc_msg(cm_id_priv, &msg);
- if (ret)
- return ret;
+ msg = cm_alloc_msg(cm_id_priv);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
cm_format_rej((struct cm_rej_msg *)msg->mad, cm_id_priv, reason,
ari, ari_length, private_data, private_data_len,
state);
@@ -3032,7 +3026,7 @@ static int cm_rej_handler(struct cm_work *work)
case IB_CM_MRA_REQ_RCVD:
case IB_CM_REP_SENT:
case IB_CM_MRA_REP_RCVD:
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
fallthrough;
case IB_CM_REQ_RCVD:
case IB_CM_MRA_REQ_SENT:
@@ -3042,7 +3036,7 @@ static int cm_rej_handler(struct cm_work *work)
cm_reset_to_idle(cm_id_priv);
break;
case IB_CM_DREQ_SENT:
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
fallthrough;
case IB_CM_REP_RCVD:
case IB_CM_MRA_REP_SENT:
@@ -3052,8 +3046,7 @@ static int cm_rej_handler(struct cm_work *work)
if (cm_id_priv->id.lap_state == IB_CM_LAP_UNINIT ||
cm_id_priv->id.lap_state == IB_CM_LAP_SENT) {
if (cm_id_priv->id.lap_state == IB_CM_LAP_SENT)
- ib_cancel_mad(cm_id_priv->av.port->mad_agent,
- cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
cm_enter_timewait(cm_id_priv);
break;
}
@@ -3117,13 +3110,15 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id,
default:
trace_icm_send_mra_unknown_err(&cm_id_priv->id);
ret = -EINVAL;
- goto error1;
+ goto error_unlock;
}
if (!(service_timeout & IB_CM_MRA_FLAG_DELAY)) {
- ret = cm_alloc_msg(cm_id_priv, &msg);
- if (ret)
- goto error1;
+ msg = cm_alloc_msg(cm_id_priv);
+ if (IS_ERR(msg)) {
+ ret = PTR_ERR(msg);
+ goto error_unlock;
+ }
cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
msg_response, service_timeout,
@@ -3131,7 +3126,7 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id,
trace_icm_send_mra(cm_id);
ret = ib_post_send_mad(msg, NULL);
if (ret)
- goto error2;
+ goto error_free_msg;
}
cm_id->state = cm_state;
@@ -3141,13 +3136,11 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id,
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
return 0;
-error1: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
- kfree(data);
- return ret;
-
-error2: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
- kfree(data);
+error_free_msg:
cm_free_msg(msg);
+error_unlock:
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ kfree(data);
return ret;
}
EXPORT_SYMBOL(ib_send_cm_mra);
@@ -3192,16 +3185,14 @@ static int cm_mra_handler(struct cm_work *work)
case IB_CM_REQ_SENT:
if (IBA_GET(CM_MRA_MESSAGE_MRAED, mra_msg) !=
CM_MSG_RESPONSE_REQ ||
- ib_modify_mad(cm_id_priv->av.port->mad_agent,
- cm_id_priv->msg, timeout))
+ ib_modify_mad(cm_id_priv->msg, timeout))
goto out;
cm_id_priv->id.state = IB_CM_MRA_REQ_RCVD;
break;
case IB_CM_REP_SENT:
if (IBA_GET(CM_MRA_MESSAGE_MRAED, mra_msg) !=
CM_MSG_RESPONSE_REP ||
- ib_modify_mad(cm_id_priv->av.port->mad_agent,
- cm_id_priv->msg, timeout))
+ ib_modify_mad(cm_id_priv->msg, timeout))
goto out;
cm_id_priv->id.state = IB_CM_MRA_REP_RCVD;
break;
@@ -3209,20 +3200,19 @@ static int cm_mra_handler(struct cm_work *work)
if (IBA_GET(CM_MRA_MESSAGE_MRAED, mra_msg) !=
CM_MSG_RESPONSE_OTHER ||
cm_id_priv->id.lap_state != IB_CM_LAP_SENT ||
- ib_modify_mad(cm_id_priv->av.port->mad_agent,
- cm_id_priv->msg, timeout)) {
+ ib_modify_mad(cm_id_priv->msg, timeout)) {
if (cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD)
- atomic_long_inc(&work->port->
- counter_group[CM_RECV_DUPLICATES].
- counter[CM_MRA_COUNTER]);
+ atomic_long_inc(
+ &work->port->counters[CM_RECV_DUPLICATES]
+ [CM_MRA_COUNTER]);
goto out;
}
cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD;
break;
case IB_CM_MRA_REQ_RCVD:
case IB_CM_MRA_REP_RCVD:
- atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
- counter[CM_MRA_COUNTER]);
+ atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
+ [CM_MRA_COUNTER]);
fallthrough;
default:
trace_icm_mra_unknown_err(&cm_id_priv->id);
@@ -3291,6 +3281,8 @@ static int cm_lap_handler(struct cm_work *work)
struct cm_lap_msg *lap_msg;
struct ib_cm_lap_event_param *param;
struct ib_mad_send_buf *msg = NULL;
+ struct rdma_ah_attr ah_attr;
+ struct cm_av alt_av = {};
int ret;
/* Currently Alternate path messages are not supported for
@@ -3319,7 +3311,25 @@ static int cm_lap_handler(struct cm_work *work)
work->cm_event.private_data =
IBA_GET_MEM_PTR(CM_LAP_PRIVATE_DATA, lap_msg);
+ ret = ib_init_ah_attr_from_wc(work->port->cm_dev->ib_device,
+ work->port->port_num,
+ work->mad_recv_wc->wc,
+ work->mad_recv_wc->recv_buf.grh,
+ &ah_attr);
+ if (ret)
+ goto deref;
+
+ ret = cm_init_av_by_path(param->alternate_path, NULL, &alt_av);
+ if (ret) {
+ rdma_destroy_ah_attr(&ah_attr);
+ return -EINVAL;
+ }
+
spin_lock_irq(&cm_id_priv->lock);
+ cm_init_av_for_lap(work->port, work->mad_recv_wc->wc,
+ &ah_attr, &cm_id_priv->av);
+ cm_move_av_from_path(&cm_id_priv->alt_av, &alt_av);
+
if (cm_id_priv->id.state != IB_CM_ESTABLISHED)
goto unlock;
@@ -3328,8 +3338,8 @@ static int cm_lap_handler(struct cm_work *work)
case IB_CM_LAP_IDLE:
break;
case IB_CM_MRA_LAP_SENT:
- atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
- counter[CM_LAP_COUNTER]);
+ atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
+ [CM_LAP_COUNTER]);
msg = cm_alloc_response_msg_no_ah(work->port, work->mad_recv_wc);
if (IS_ERR(msg))
goto unlock;
@@ -3343,27 +3353,16 @@ static int cm_lap_handler(struct cm_work *work)
if (cm_create_response_msg_ah(work->port, work->mad_recv_wc, msg) ||
ib_post_send_mad(msg, NULL))
- cm_free_msg(msg);
+ cm_free_response_msg(msg);
goto deref;
case IB_CM_LAP_RCVD:
- atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
- counter[CM_LAP_COUNTER]);
+ atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
+ [CM_LAP_COUNTER]);
goto unlock;
default:
goto unlock;
}
- ret = cm_init_av_for_lap(work->port, work->mad_recv_wc->wc,
- work->mad_recv_wc->recv_buf.grh,
- &cm_id_priv->av);
- if (ret)
- goto unlock;
-
- ret = cm_init_av_by_path(param->alternate_path, NULL,
- &cm_id_priv->alt_av, cm_id_priv);
- if (ret)
- goto unlock;
-
cm_id_priv->id.lap_state = IB_CM_LAP_RCVD;
cm_id_priv->tid = lap_msg->hdr.tid;
cm_queue_work_unlock(cm_id_priv, work);
@@ -3410,8 +3409,7 @@ static int cm_apr_handler(struct cm_work *work)
goto out;
}
cm_id_priv->id.lap_state = IB_CM_LAP_IDLE;
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
- cm_id_priv->msg = NULL;
+ ib_cancel_mad(cm_id_priv->msg);
cm_queue_work_unlock(cm_id_priv, work);
return 0;
out:
@@ -3471,6 +3469,7 @@ int ib_send_cm_sidr_req(struct ib_cm_id *cm_id,
{
struct cm_id_private *cm_id_priv;
struct ib_mad_send_buf *msg;
+ struct cm_av av = {};
unsigned long flags;
int ret;
@@ -3479,42 +3478,43 @@ int ib_send_cm_sidr_req(struct ib_cm_id *cm_id,
return -EINVAL;
cm_id_priv = container_of(cm_id, struct cm_id_private, id);
- ret = cm_init_av_by_path(param->path, param->sgid_attr,
- &cm_id_priv->av,
- cm_id_priv);
+ ret = cm_init_av_by_path(param->path, param->sgid_attr, &av);
if (ret)
- goto out;
+ return ret;
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ cm_move_av_from_path(&cm_id_priv->av, &av);
cm_id->service_id = param->service_id;
cm_id->service_mask = ~cpu_to_be64(0);
cm_id_priv->timeout_ms = param->timeout_ms;
cm_id_priv->max_cm_retries = param->max_cm_retries;
- ret = cm_alloc_msg(cm_id_priv, &msg);
- if (ret)
- goto out;
-
- cm_format_sidr_req((struct cm_sidr_req_msg *) msg->mad, cm_id_priv,
- param);
- msg->timeout_ms = cm_id_priv->timeout_ms;
- msg->context[1] = (void *) (unsigned long) IB_CM_SIDR_REQ_SENT;
-
- spin_lock_irqsave(&cm_id_priv->lock, flags);
- if (cm_id->state == IB_CM_IDLE) {
- trace_icm_send_sidr_req(&cm_id_priv->id);
- ret = ib_post_send_mad(msg, NULL);
- } else {
+ if (cm_id->state != IB_CM_IDLE) {
ret = -EINVAL;
+ goto out_unlock;
}
- if (ret) {
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
- cm_free_msg(msg);
- goto out;
+ msg = cm_alloc_priv_msg(cm_id_priv);
+ if (IS_ERR(msg)) {
+ ret = PTR_ERR(msg);
+ goto out_unlock;
}
+
+ cm_format_sidr_req((struct cm_sidr_req_msg *)msg->mad, cm_id_priv,
+ param);
+ msg->timeout_ms = cm_id_priv->timeout_ms;
+ msg->context[1] = (void *)(unsigned long)IB_CM_SIDR_REQ_SENT;
+
+ trace_icm_send_sidr_req(&cm_id_priv->id);
+ ret = ib_post_send_mad(msg, NULL);
+ if (ret)
+ goto out_free;
cm_id->state = IB_CM_SIDR_REQ_SENT;
- cm_id_priv->msg = msg;
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-out:
+ return 0;
+out_free:
+ cm_free_priv_msg(msg);
+out_unlock:
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
return ret;
}
EXPORT_SYMBOL(ib_send_cm_sidr_req);
@@ -3564,8 +3564,7 @@ static int cm_sidr_req_handler(struct cm_work *work)
cm_id_priv->tid = sidr_req_msg->hdr.tid;
wc = work->mad_recv_wc->wc;
- cm_id_priv->av.dgid.global.subnet_prefix = cpu_to_be64(wc->slid);
- cm_id_priv->av.dgid.global.interface_id = 0;
+ cm_id_priv->sidr_slid = wc->slid;
ret = cm_init_av_for_response(work->port, work->mad_recv_wc->wc,
work->mad_recv_wc->recv_buf.grh,
&cm_id_priv->av);
@@ -3576,8 +3575,8 @@ static int cm_sidr_req_handler(struct cm_work *work)
listen_cm_id_priv = cm_insert_remote_sidr(cm_id_priv);
if (listen_cm_id_priv) {
spin_unlock_irq(&cm.lock);
- atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
- counter[CM_SIDR_REQ_COUNTER]);
+ atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES]
+ [CM_SIDR_REQ_COUNTER]);
goto out; /* Duplicate message. */
}
cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD;
@@ -3661,9 +3660,9 @@ static int cm_send_sidr_rep_locked(struct cm_id_private *cm_id_priv,
if (cm_id_priv->id.state != IB_CM_SIDR_REQ_RCVD)
return -EINVAL;
- ret = cm_alloc_msg(cm_id_priv, &msg);
- if (ret)
- return ret;
+ msg = cm_alloc_msg(cm_id_priv);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
cm_format_sidr_rep((struct cm_sidr_rep_msg *) msg->mad, cm_id_priv,
param);
@@ -3737,7 +3736,7 @@ static int cm_sidr_rep_handler(struct cm_work *work)
goto out;
}
cm_id_priv->id.state = IB_CM_IDLE;
- ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
+ ib_cancel_mad(cm_id_priv->msg);
spin_unlock_irq(&cm_id_priv->lock);
cm_format_sidr_rep_event(work, cm_id_priv);
@@ -3748,22 +3747,26 @@ out:
return -EINVAL;
}
-static void cm_process_send_error(struct ib_mad_send_buf *msg,
+static void cm_process_send_error(struct cm_id_private *cm_id_priv,
+ struct ib_mad_send_buf *msg,
+ enum ib_cm_state state,
enum ib_wc_status wc_status)
{
- struct cm_id_private *cm_id_priv;
- struct ib_cm_event cm_event;
- enum ib_cm_state state;
+ struct ib_cm_event cm_event = {};
int ret;
- memset(&cm_event, 0, sizeof cm_event);
- cm_id_priv = msg->context[0];
-
/* Discard old sends or ones without a response. */
spin_lock_irq(&cm_id_priv->lock);
- state = (enum ib_cm_state) (unsigned long) msg->context[1];
- if (msg != cm_id_priv->msg || state != cm_id_priv->id.state)
- goto discard;
+ if (msg != cm_id_priv->msg) {
+ spin_unlock_irq(&cm_id_priv->lock);
+ cm_free_msg(msg);
+ return;
+ }
+ cm_free_priv_msg(msg);
+
+ if (state != cm_id_priv->id.state || wc_status == IB_WC_SUCCESS ||
+ wc_status == IB_WC_WR_FLUSH_ERR)
+ goto out_unlock;
trace_icm_mad_send_err(state, wc_status);
switch (state) {
@@ -3786,26 +3789,27 @@ static void cm_process_send_error(struct ib_mad_send_buf *msg,
cm_event.event = IB_CM_SIDR_REQ_ERROR;
break;
default:
- goto discard;
+ goto out_unlock;
}
spin_unlock_irq(&cm_id_priv->lock);
cm_event.param.send_status = wc_status;
/* No other events can occur on the cm_id at this point. */
ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, &cm_event);
- cm_free_msg(msg);
if (ret)
ib_destroy_cm_id(&cm_id_priv->id);
return;
-discard:
+out_unlock:
spin_unlock_irq(&cm_id_priv->lock);
- cm_free_msg(msg);
}
static void cm_send_handler(struct ib_mad_agent *mad_agent,
struct ib_mad_send_wc *mad_send_wc)
{
struct ib_mad_send_buf *msg = mad_send_wc->send_buf;
+ struct cm_id_private *cm_id_priv = msg->context[0];
+ enum ib_cm_state state =
+ (enum ib_cm_state)(unsigned long)msg->context[1];
struct cm_port *port;
u16 attr_index;
@@ -3818,28 +3822,19 @@ static void cm_send_handler(struct ib_mad_agent *mad_agent,
* set to a cm_id), and is not a REJ, then it is a send that was
* manually retried.
*/
- if (!msg->context[0] && (attr_index != CM_REJ_COUNTER))
+ if (!cm_id_priv && (attr_index != CM_REJ_COUNTER))
msg->retries = 1;
- atomic_long_add(1 + msg->retries,
- &port->counter_group[CM_XMIT].counter[attr_index]);
+ atomic_long_add(1 + msg->retries, &port->counters[CM_XMIT][attr_index]);
if (msg->retries)
atomic_long_add(msg->retries,
- &port->counter_group[CM_XMIT_RETRIES].
- counter[attr_index]);
+ &port->counters[CM_XMIT_RETRIES][attr_index]);
- switch (mad_send_wc->status) {
- case IB_WC_SUCCESS:
- case IB_WC_WR_FLUSH_ERR:
- cm_free_msg(msg);
- break;
- default:
- if (msg->context[0] && msg->context[1])
- cm_process_send_error(msg, mad_send_wc->status);
- else
- cm_free_msg(msg);
- break;
- }
+ if (cm_id_priv)
+ cm_process_send_error(cm_id_priv, msg, state,
+ mad_send_wc->status);
+ else
+ cm_free_response_msg(msg);
}
static void cm_work_handler(struct work_struct *_work)
@@ -3963,9 +3958,7 @@ out:
static int cm_migrate(struct ib_cm_id *cm_id)
{
struct cm_id_private *cm_id_priv;
- struct cm_av tmp_av;
unsigned long flags;
- int tmp_send_port_not_ready;
int ret = 0;
cm_id_priv = container_of(cm_id, struct cm_id_private, id);
@@ -3974,14 +3967,7 @@ static int cm_migrate(struct ib_cm_id *cm_id)
(cm_id->lap_state == IB_CM_LAP_UNINIT ||
cm_id->lap_state == IB_CM_LAP_IDLE)) {
cm_id->lap_state = IB_CM_LAP_IDLE;
- /* Swap address vector */
- tmp_av = cm_id_priv->av;
cm_id_priv->av = cm_id_priv->alt_av;
- cm_id_priv->alt_av = tmp_av;
- /* Swap port send ready state */
- tmp_send_port_not_ready = cm_id_priv->prim_send_port_not_ready;
- cm_id_priv->prim_send_port_not_ready = cm_id_priv->altr_send_port_not_ready;
- cm_id_priv->altr_send_port_not_ready = tmp_send_port_not_ready;
} else
ret = -EINVAL;
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
@@ -4063,8 +4049,7 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
}
attr_id = be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id);
- atomic_long_inc(&port->counter_group[CM_RECV].
- counter[attr_id - CM_ATTR_ID_OFFSET]);
+ atomic_long_inc(&port->counters[CM_RECV][attr_id - CM_ATTR_ID_OFFSET]);
work = kmalloc(struct_size(work, path, paths), GFP_KERNEL);
if (!work) {
@@ -4116,7 +4101,8 @@ static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv,
qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ |
IB_ACCESS_REMOTE_ATOMIC;
qp_attr->pkey_index = cm_id_priv->av.pkey_index;
- qp_attr->port_num = cm_id_priv->av.port->port_num;
+ if (cm_id_priv->av.port)
+ qp_attr->port_num = cm_id_priv->av.port->port_num;
ret = 0;
break;
default:
@@ -4158,7 +4144,8 @@ static int cm_init_qp_rtr_attr(struct cm_id_private *cm_id_priv,
cm_id_priv->responder_resources;
qp_attr->min_rnr_timer = 0;
}
- if (rdma_ah_get_dlid(&cm_id_priv->alt_av.ah_attr)) {
+ if (rdma_ah_get_dlid(&cm_id_priv->alt_av.ah_attr) &&
+ cm_id_priv->alt_av.port) {
*qp_attr_mask |= IB_QP_ALT_PATH;
qp_attr->alt_port_num = cm_id_priv->alt_av.port->port_num;
qp_attr->alt_pkey_index = cm_id_priv->alt_av.pkey_index;
@@ -4219,7 +4206,9 @@ static int cm_init_qp_rts_attr(struct cm_id_private *cm_id_priv,
}
} else {
*qp_attr_mask = IB_QP_ALT_PATH | IB_QP_PATH_MIG_STATE;
- qp_attr->alt_port_num = cm_id_priv->alt_av.port->port_num;
+ if (cm_id_priv->alt_av.port)
+ qp_attr->alt_port_num =
+ cm_id_priv->alt_av.port->port_num;
qp_attr->alt_pkey_index = cm_id_priv->alt_av.pkey_index;
qp_attr->alt_timeout = cm_id_priv->alt_av.timeout;
qp_attr->alt_ah_attr = cm_id_priv->alt_av.ah_attr;
@@ -4262,59 +4251,74 @@ int ib_cm_init_qp_attr(struct ib_cm_id *cm_id,
}
EXPORT_SYMBOL(ib_cm_init_qp_attr);
-static ssize_t cm_show_counter(struct kobject *obj, struct attribute *attr,
- char *buf)
+static ssize_t cm_show_counter(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
{
- struct cm_counter_group *group;
- struct cm_counter_attribute *cm_attr;
+ struct cm_counter_attribute *cm_attr =
+ container_of(attr, struct cm_counter_attribute, attr);
+ struct cm_device *cm_dev = ib_get_client_data(ibdev, &cm_client);
- group = container_of(obj, struct cm_counter_group, obj);
- cm_attr = container_of(attr, struct cm_counter_attribute, attr);
+ if (WARN_ON(!cm_dev))
+ return -EINVAL;
- return sysfs_emit(buf, "%ld\n",
- atomic_long_read(&group->counter[cm_attr->index]));
+ return sysfs_emit(
+ buf, "%ld\n",
+ atomic_long_read(
+ &cm_dev->port[port_num - 1]
+ ->counters[cm_attr->group][cm_attr->index]));
}
-static const struct sysfs_ops cm_counter_ops = {
- .show = cm_show_counter
-};
-
-static struct kobj_type cm_counter_obj_type = {
- .sysfs_ops = &cm_counter_ops,
- .default_attrs = cm_counter_default_attrs
-};
-
-static int cm_create_port_fs(struct cm_port *port)
-{
- int i, ret;
-
- for (i = 0; i < CM_COUNTER_GROUPS; i++) {
- ret = ib_port_register_module_stat(port->cm_dev->ib_device,
- port->port_num,
- &port->counter_group[i].obj,
- &cm_counter_obj_type,
- counter_group_names[i]);
- if (ret)
- goto error;
+#define CM_COUNTER_ATTR(_name, _group, _index) \
+ { \
+ .attr = __ATTR(_name, 0444, cm_show_counter, NULL), \
+ .group = _group, .index = _index \
}
- return 0;
-
-error:
- while (i--)
- ib_port_unregister_module_stat(&port->counter_group[i].obj);
- return ret;
-
-}
-
-static void cm_remove_port_fs(struct cm_port *port)
-{
- int i;
-
- for (i = 0; i < CM_COUNTER_GROUPS; i++)
- ib_port_unregister_module_stat(&port->counter_group[i].obj);
+#define CM_COUNTER_GROUP(_group, _name) \
+ static struct cm_counter_attribute cm_counter_attr_##_group[] = { \
+ CM_COUNTER_ATTR(req, _group, CM_REQ_COUNTER), \
+ CM_COUNTER_ATTR(mra, _group, CM_MRA_COUNTER), \
+ CM_COUNTER_ATTR(rej, _group, CM_REJ_COUNTER), \
+ CM_COUNTER_ATTR(rep, _group, CM_REP_COUNTER), \
+ CM_COUNTER_ATTR(rtu, _group, CM_RTU_COUNTER), \
+ CM_COUNTER_ATTR(dreq, _group, CM_DREQ_COUNTER), \
+ CM_COUNTER_ATTR(drep, _group, CM_DREP_COUNTER), \
+ CM_COUNTER_ATTR(sidr_req, _group, CM_SIDR_REQ_COUNTER), \
+ CM_COUNTER_ATTR(sidr_rep, _group, CM_SIDR_REP_COUNTER), \
+ CM_COUNTER_ATTR(lap, _group, CM_LAP_COUNTER), \
+ CM_COUNTER_ATTR(apr, _group, CM_APR_COUNTER), \
+ }; \
+ static struct attribute *cm_counter_attrs_##_group[] = { \
+ &cm_counter_attr_##_group[0].attr.attr, \
+ &cm_counter_attr_##_group[1].attr.attr, \
+ &cm_counter_attr_##_group[2].attr.attr, \
+ &cm_counter_attr_##_group[3].attr.attr, \
+ &cm_counter_attr_##_group[4].attr.attr, \
+ &cm_counter_attr_##_group[5].attr.attr, \
+ &cm_counter_attr_##_group[6].attr.attr, \
+ &cm_counter_attr_##_group[7].attr.attr, \
+ &cm_counter_attr_##_group[8].attr.attr, \
+ &cm_counter_attr_##_group[9].attr.attr, \
+ &cm_counter_attr_##_group[10].attr.attr, \
+ NULL, \
+ }; \
+ static const struct attribute_group cm_counter_group_##_group = { \
+ .name = _name, \
+ .attrs = cm_counter_attrs_##_group, \
+ };
-}
+CM_COUNTER_GROUP(CM_XMIT, "cm_tx_msgs")
+CM_COUNTER_GROUP(CM_XMIT_RETRIES, "cm_tx_retries")
+CM_COUNTER_GROUP(CM_RECV, "cm_rx_msgs")
+CM_COUNTER_GROUP(CM_RECV_DUPLICATES, "cm_rx_duplicates")
+
+static const struct attribute_group *cm_counter_groups[] = {
+ &cm_counter_group_CM_XMIT,
+ &cm_counter_group_CM_XMIT_RETRIES,
+ &cm_counter_group_CM_RECV,
+ &cm_counter_group_CM_RECV_DUPLICATES,
+ NULL,
+};
static int cm_add_one(struct ib_device *ib_device)
{
@@ -4337,10 +4341,14 @@ static int cm_add_one(struct ib_device *ib_device)
if (!cm_dev)
return -ENOMEM;
+ kref_init(&cm_dev->kref);
+ spin_lock_init(&cm_dev->mad_agent_lock);
cm_dev->ib_device = ib_device;
cm_dev->ack_delay = ib_device->attrs.local_ca_ack_delay;
cm_dev->going_down = 0;
+ ib_set_client_data(ib_device, &cm_client, cm_dev);
+
set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
rdma_for_each_port (ib_device, i) {
if (!rdma_cap_ib_cm(ib_device, i))
@@ -4356,10 +4364,8 @@ static int cm_add_one(struct ib_device *ib_device)
port->cm_dev = cm_dev;
port->port_num = i;
- INIT_LIST_HEAD(&port->cm_priv_prim_list);
- INIT_LIST_HEAD(&port->cm_priv_altr_list);
-
- ret = cm_create_port_fs(port);
+ ret = ib_port_register_client_groups(ib_device, i,
+ cm_counter_groups);
if (ret)
goto error1;
@@ -4388,8 +4394,6 @@ static int cm_add_one(struct ib_device *ib_device)
goto free;
}
- ib_set_client_data(ib_device, &cm_client, cm_dev);
-
write_lock_irqsave(&cm.device_lock, flags);
list_add_tail(&cm_dev->list, &cm.device_list);
write_unlock_irqrestore(&cm.device_lock, flags);
@@ -4398,11 +4402,10 @@ static int cm_add_one(struct ib_device *ib_device)
error3:
ib_unregister_mad_agent(port->mad_agent);
error2:
- cm_remove_port_fs(port);
+ ib_port_unregister_client_groups(ib_device, i, cm_counter_groups);
error1:
port_modify.set_port_cap_mask = 0;
port_modify.clr_port_cap_mask = IB_PORT_CM_SUP;
- kfree(port);
while (--i) {
if (!rdma_cap_ib_cm(ib_device, i))
continue;
@@ -4410,11 +4413,11 @@ error1:
port = cm_dev->port[i-1];
ib_modify_port(ib_device, port->port_num, 0, &port_modify);
ib_unregister_mad_agent(port->mad_agent);
- cm_remove_port_fs(port);
- kfree(port);
+ ib_port_unregister_client_groups(ib_device, i,
+ cm_counter_groups);
}
free:
- kfree(cm_dev);
+ cm_device_put(cm_dev);
return ret;
}
@@ -4422,8 +4425,6 @@ static void cm_remove_one(struct ib_device *ib_device, void *client_data)
{
struct cm_device *cm_dev = client_data;
struct cm_port *port;
- struct cm_id_private *cm_id_priv;
- struct ib_mad_agent *cur_mad_agent;
struct ib_port_modify port_modify = {
.clr_port_cap_mask = IB_PORT_CM_SUP
};
@@ -4439,34 +4440,33 @@ static void cm_remove_one(struct ib_device *ib_device, void *client_data)
spin_unlock_irq(&cm.lock);
rdma_for_each_port (ib_device, i) {
+ struct ib_mad_agent *mad_agent;
+
if (!rdma_cap_ib_cm(ib_device, i))
continue;
port = cm_dev->port[i-1];
+ mad_agent = port->mad_agent;
ib_modify_port(ib_device, port->port_num, 0, &port_modify);
- /* Mark all the cm_id's as not valid */
- spin_lock_irq(&cm.lock);
- list_for_each_entry(cm_id_priv, &port->cm_priv_altr_list, altr_list)
- cm_id_priv->altr_send_port_not_ready = 1;
- list_for_each_entry(cm_id_priv, &port->cm_priv_prim_list, prim_list)
- cm_id_priv->prim_send_port_not_ready = 1;
- spin_unlock_irq(&cm.lock);
/*
* We flush the queue here after the going_down set, this
* verify that no new works will be queued in the recv handler,
* after that we can call the unregister_mad_agent
*/
flush_workqueue(cm.wq);
- spin_lock_irq(&cm.state_lock);
- cur_mad_agent = port->mad_agent;
+ /*
+ * The above ensures no call paths from the work are running,
+ * the remaining paths all take the mad_agent_lock.
+ */
+ spin_lock(&cm_dev->mad_agent_lock);
port->mad_agent = NULL;
- spin_unlock_irq(&cm.state_lock);
- ib_unregister_mad_agent(cur_mad_agent);
- cm_remove_port_fs(port);
- kfree(port);
+ spin_unlock(&cm_dev->mad_agent_lock);
+ ib_unregister_mad_agent(mad_agent);
+ ib_port_unregister_client_groups(ib_device, i,
+ cm_counter_groups);
}
- kfree(cm_dev);
+ cm_device_put(cm_dev);
}
static int __init ib_cm_init(void)
@@ -4476,7 +4476,6 @@ static int __init ib_cm_init(void)
INIT_LIST_HEAD(&cm.device_list);
rwlock_init(&cm.device_lock);
spin_lock_init(&cm.lock);
- spin_lock_init(&cm.state_lock);
cm.listen_service_table = RB_ROOT;
cm.listen_service_id = be64_to_cpu(IB_CM_ASSIGN_SERVICE_ID);
cm.remote_id_table = RB_ROOT;
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index ab148a696c0c..515a7e95a421 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -926,25 +926,12 @@ static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
return ret;
}
-static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
-{
- struct ib_qp_attr qp_attr;
- int qp_attr_mask, ret;
-
- qp_attr.qp_state = IB_QPS_INIT;
- ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
- if (ret)
- return ret;
-
- return ib_modify_qp(qp, &qp_attr, qp_attr_mask);
-}
-
int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
struct ib_qp_init_attr *qp_init_attr)
{
struct rdma_id_private *id_priv;
struct ib_qp *qp;
- int ret;
+ int ret = 0;
id_priv = container_of(id, struct rdma_id_private, id);
if (id->device != pd->device) {
@@ -961,8 +948,6 @@ int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
if (id->qp_type == IB_QPT_UD)
ret = cma_init_ud_qp(id_priv, qp);
- else
- ret = cma_init_conn_qp(id_priv, qp);
if (ret)
goto out_destroy;
@@ -1852,6 +1837,7 @@ static void _destroy_id(struct rdma_id_private *id_priv,
{
cma_cancel_operation(id_priv, state);
+ rdma_restrack_del(&id_priv->res);
if (id_priv->cma_dev) {
if (rdma_cap_ib_cm(id_priv->id.device, 1)) {
if (id_priv->cm_id.ib)
@@ -1861,7 +1847,6 @@ static void _destroy_id(struct rdma_id_private *id_priv,
iw_destroy_cm_id(id_priv->cm_id.iw);
}
cma_leave_mc_groups(id_priv);
- rdma_restrack_del(&id_priv->res);
cma_release_dev(id_priv);
}
@@ -2472,8 +2457,10 @@ static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog)
if (IS_ERR(id))
return PTR_ERR(id);
+ mutex_lock(&id_priv->qp_mutex);
id->tos = id_priv->tos;
id->tos_set = id_priv->tos_set;
+ mutex_unlock(&id_priv->qp_mutex);
id->afonly = id_priv->afonly;
id_priv->cm_id.iw = id;
@@ -2534,8 +2521,10 @@ static int cma_listen_on_dev(struct rdma_id_private *id_priv,
cma_id_get(id_priv);
dev_id_priv->internal_id = 1;
dev_id_priv->afonly = id_priv->afonly;
+ mutex_lock(&id_priv->qp_mutex);
dev_id_priv->tos_set = id_priv->tos_set;
dev_id_priv->tos = id_priv->tos;
+ mutex_unlock(&id_priv->qp_mutex);
ret = rdma_listen(&dev_id_priv->id, id_priv->backlog);
if (ret)
@@ -2582,8 +2571,10 @@ void rdma_set_service_type(struct rdma_cm_id *id, int tos)
struct rdma_id_private *id_priv;
id_priv = container_of(id, struct rdma_id_private, id);
+ mutex_lock(&id_priv->qp_mutex);
id_priv->tos = (u8) tos;
id_priv->tos_set = true;
+ mutex_unlock(&id_priv->qp_mutex);
}
EXPORT_SYMBOL(rdma_set_service_type);
@@ -2610,8 +2601,10 @@ int rdma_set_ack_timeout(struct rdma_cm_id *id, u8 timeout)
return -EINVAL;
id_priv = container_of(id, struct rdma_id_private, id);
+ mutex_lock(&id_priv->qp_mutex);
id_priv->timeout = timeout;
id_priv->timeout_set = true;
+ mutex_unlock(&id_priv->qp_mutex);
return 0;
}
@@ -2647,8 +2640,10 @@ int rdma_set_min_rnr_timer(struct rdma_cm_id *id, u8 min_rnr_timer)
return -EINVAL;
id_priv = container_of(id, struct rdma_id_private, id);
+ mutex_lock(&id_priv->qp_mutex);
id_priv->min_rnr_timer = min_rnr_timer;
id_priv->min_rnr_timer_set = true;
+ mutex_unlock(&id_priv->qp_mutex);
return 0;
}
@@ -2819,7 +2814,8 @@ static int cma_resolve_ib_route(struct rdma_id_private *id_priv,
cma_init_resolve_route_work(work, id_priv);
- route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL);
+ if (!route->path_rec)
+ route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL);
if (!route->path_rec) {
ret = -ENOMEM;
goto err1;
@@ -3034,8 +3030,11 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
u8 default_roce_tos = id_priv->cma_dev->default_roce_tos[id_priv->id.port_num -
rdma_start_port(id_priv->cma_dev->device)];
- u8 tos = id_priv->tos_set ? id_priv->tos : default_roce_tos;
+ u8 tos;
+ mutex_lock(&id_priv->qp_mutex);
+ tos = id_priv->tos_set ? id_priv->tos : default_roce_tos;
+ mutex_unlock(&id_priv->qp_mutex);
work = kzalloc(sizeof *work, GFP_KERNEL);
if (!work)
@@ -3082,8 +3081,12 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
* PacketLifeTime = local ACK timeout/2
* as a reasonable approximation for RoCE networks.
*/
- route->path_rec->packet_life_time = id_priv->timeout_set ?
- id_priv->timeout - 1 : CMA_IBOE_PACKET_LIFETIME;
+ mutex_lock(&id_priv->qp_mutex);
+ if (id_priv->timeout_set && id_priv->timeout)
+ route->path_rec->packet_life_time = id_priv->timeout - 1;
+ else
+ route->path_rec->packet_life_time = CMA_IBOE_PACKET_LIFETIME;
+ mutex_unlock(&id_priv->qp_mutex);
if (!route->path_rec->mtu) {
ret = -EINVAL;
@@ -4107,8 +4110,11 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
if (IS_ERR(cm_id))
return PTR_ERR(cm_id);
+ mutex_lock(&id_priv->qp_mutex);
cm_id->tos = id_priv->tos;
cm_id->tos_set = id_priv->tos_set;
+ mutex_unlock(&id_priv->qp_mutex);
+
id_priv->cm_id.iw = cm_id;
memcpy(&cm_id->local_addr, cma_src_addr(id_priv),
diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h
index 29809dd30041..647cca4e0240 100644
--- a/drivers/infiniband/core/core_priv.h
+++ b/drivers/infiniband/core/core_priv.h
@@ -78,8 +78,6 @@ static inline struct rdma_dev_net *rdma_net_to_dev_net(struct net *net)
return net_generic(net, rdma_dev_net_id);
}
-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);
@@ -214,7 +212,7 @@ int ib_nl_handle_ip_res_resp(struct sk_buff *skb,
struct nlmsghdr *nlh,
struct netlink_ext_ack *extack);
-int ib_get_cached_subnet_prefix(struct ib_device *device,
+void ib_get_cached_subnet_prefix(struct ib_device *device,
u32 port_num,
u64 *sn_pfx);
@@ -378,13 +376,16 @@ struct net_device *rdma_read_gid_attr_ndev_rcu(const struct ib_gid_attr *attr);
void ib_free_port_attrs(struct ib_core_device *coredev);
int ib_setup_port_attrs(struct ib_core_device *coredev);
+struct rdma_hw_stats *ib_get_hw_stats_port(struct ib_device *ibdev, u32 port_num);
+void ib_device_release_hw_stats(struct hw_stats_device_data *data);
+int ib_setup_device_attrs(struct ib_device *ibdev);
int rdma_compatdev_set(u8 enable);
-int ib_port_register_module_stat(struct ib_device *device, u32 port_num,
- struct kobject *kobj, struct kobj_type *ktype,
- const char *name);
-void ib_port_unregister_module_stat(struct kobject *kobj);
+int ib_port_register_client_groups(struct ib_device *ibdev, u32 port_num,
+ const struct attribute_group **groups);
+void ib_port_unregister_client_groups(struct ib_device *ibdev, u32 port_num,
+ const struct attribute_group **groups);
int ib_device_set_netns_put(struct sk_buff *skb,
struct ib_device *dev, u32 ns_fd);
diff --git a/drivers/infiniband/core/counters.c b/drivers/infiniband/core/counters.c
index 15493357cfef..df9e6c5e4ddf 100644
--- a/drivers/infiniband/core/counters.c
+++ b/drivers/infiniband/core/counters.c
@@ -605,10 +605,10 @@ void rdma_counter_init(struct ib_device *dev)
port_counter->mode.mode = RDMA_COUNTER_MODE_NONE;
mutex_init(&port_counter->lock);
- if (!dev->ops.alloc_hw_stats)
+ if (!dev->ops.alloc_hw_port_stats)
continue;
- port_counter->hstats = dev->ops.alloc_hw_stats(dev, port);
+ port_counter->hstats = dev->ops.alloc_hw_port_stats(dev, port);
if (!port_counter->hstats)
goto fail;
}
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index c660cef66ac6..fa20b1824fb8 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -491,6 +491,8 @@ static void ib_device_release(struct device *device)
free_netdevs(dev);
WARN_ON(refcount_read(&dev->refcount));
+ if (dev->hw_stats_data)
+ ib_device_release_hw_stats(dev->hw_stats_data);
if (dev->port_data) {
ib_cache_release_one(dev);
ib_security_release_port_pkey_list(dev);
@@ -584,7 +586,6 @@ struct ib_device *_ib_alloc_device(size_t size)
return NULL;
}
- device->groups[0] = &ib_dev_attr_group;
rdma_init_coredev(&device->coredev, device, &init_net);
INIT_LIST_HEAD(&device->event_handler_list);
@@ -886,15 +887,8 @@ static void ib_policy_change_task(struct work_struct *work)
rdma_for_each_port (dev, i) {
u64 sp;
- int ret = ib_get_cached_subnet_prefix(dev,
- i,
- &sp);
-
- WARN_ONCE(ret,
- "ib_get_cached_subnet_prefix err: %d, this should never happen here\n",
- ret);
- if (!ret)
- ib_security_cache_change(dev, i, sp);
+ ib_get_cached_subnet_prefix(dev, i, &sp);
+ ib_security_cache_change(dev, i, sp);
}
}
up_read(&devices_rwsem);
@@ -1394,6 +1388,12 @@ int ib_register_device(struct ib_device *device, const char *name,
return ret;
}
+ device->groups[0] = &ib_dev_attr_group;
+ device->groups[1] = device->ops.device_group;
+ ret = ib_setup_device_attrs(device);
+ if (ret)
+ goto cache_cleanup;
+
ib_device_register_rdmacg(device);
rdma_counter_init(device);
@@ -1407,7 +1407,7 @@ int ib_register_device(struct ib_device *device, const char *name,
if (ret)
goto cg_cleanup;
- ret = ib_device_register_sysfs(device);
+ ret = ib_setup_port_attrs(&device->coredev);
if (ret) {
dev_warn(&device->dev,
"Couldn't register device with driver model\n");
@@ -1449,6 +1449,7 @@ dev_cleanup:
cg_cleanup:
dev_set_uevent_suppress(&device->dev, false);
ib_device_unregister_rdmacg(device);
+cache_cleanup:
ib_cache_cleanup_one(device);
return ret;
}
@@ -1473,7 +1474,7 @@ static void __ib_unregister_device(struct ib_device *ib_dev)
/* Expedite removing unregistered pointers from the hash table */
free_netdevs(ib_dev);
- ib_device_unregister_sysfs(ib_dev);
+ ib_free_port_attrs(&ib_dev->coredev);
device_del(&ib_dev->dev);
ib_device_unregister_rdmacg(ib_dev);
ib_cache_cleanup_one(ib_dev);
@@ -1691,13 +1692,11 @@ int ib_device_set_netns_put(struct sk_buff *skb,
}
/*
- * Currently supported only for those providers which support
- * disassociation and don't do port specific sysfs init. Once a
- * port_cleanup infrastructure is implemented, this limitation will be
- * removed.
+ * All the ib_clients, including uverbs, are reset when the namespace is
+ * changed and this cannot be blocked waiting for userspace to do
+ * something, so disassociation is mandatory.
*/
- if (!dev->ops.disassociate_ucontext || dev->ops.init_port ||
- ib_devices_shared_netns) {
+ if (!dev->ops.disassociate_ucontext || ib_devices_shared_netns) {
ret = -EOPNOTSUPP;
goto ns_err;
}
@@ -2595,7 +2594,8 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
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_hw_stats);
+ SET_DEVICE_OP(dev_ops, alloc_hw_device_stats);
+ SET_DEVICE_OP(dev_ops, alloc_hw_port_stats);
SET_DEVICE_OP(dev_ops, alloc_mr);
SET_DEVICE_OP(dev_ops, alloc_mr_integrity);
SET_DEVICE_OP(dev_ops, alloc_mw);
@@ -2637,6 +2637,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
SET_DEVICE_OP(dev_ops, destroy_rwq_ind_table);
SET_DEVICE_OP(dev_ops, destroy_srq);
SET_DEVICE_OP(dev_ops, destroy_wq);
+ SET_DEVICE_OP(dev_ops, device_group);
SET_DEVICE_OP(dev_ops, detach_mcast);
SET_DEVICE_OP(dev_ops, disassociate_ucontext);
SET_DEVICE_OP(dev_ops, drain_rq);
@@ -2660,7 +2661,6 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
SET_DEVICE_OP(dev_ops, get_vf_config);
SET_DEVICE_OP(dev_ops, get_vf_guid);
SET_DEVICE_OP(dev_ops, get_vf_stats);
- SET_DEVICE_OP(dev_ops, init_port);
SET_DEVICE_OP(dev_ops, iw_accept);
SET_DEVICE_OP(dev_ops, iw_add_ref);
SET_DEVICE_OP(dev_ops, iw_connect);
@@ -2683,6 +2683,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
SET_DEVICE_OP(dev_ops, modify_wq);
SET_DEVICE_OP(dev_ops, peek_cq);
SET_DEVICE_OP(dev_ops, poll_cq);
+ SET_DEVICE_OP(dev_ops, port_groups);
SET_DEVICE_OP(dev_ops, post_recv);
SET_DEVICE_OP(dev_ops, post_send);
SET_DEVICE_OP(dev_ops, post_srq_recv);
diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c
index da8adadf4755..42261152b489 100644
--- a/drivers/infiniband/core/iwcm.c
+++ b/drivers/infiniband/core/iwcm.c
@@ -211,8 +211,7 @@ static void free_cm_id(struct iwcm_id_private *cm_id_priv)
*/
static int iwcm_deref_id(struct iwcm_id_private *cm_id_priv)
{
- BUG_ON(atomic_read(&cm_id_priv->refcount)==0);
- if (atomic_dec_and_test(&cm_id_priv->refcount)) {
+ if (refcount_dec_and_test(&cm_id_priv->refcount)) {
BUG_ON(!list_empty(&cm_id_priv->work_list));
free_cm_id(cm_id_priv);
return 1;
@@ -225,7 +224,7 @@ static void add_ref(struct iw_cm_id *cm_id)
{
struct iwcm_id_private *cm_id_priv;
cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
- atomic_inc(&cm_id_priv->refcount);
+ refcount_inc(&cm_id_priv->refcount);
}
static void rem_ref(struct iw_cm_id *cm_id)
@@ -257,7 +256,7 @@ struct iw_cm_id *iw_create_cm_id(struct ib_device *device,
cm_id_priv->id.add_ref = add_ref;
cm_id_priv->id.rem_ref = rem_ref;
spin_lock_init(&cm_id_priv->lock);
- atomic_set(&cm_id_priv->refcount, 1);
+ refcount_set(&cm_id_priv->refcount, 1);
init_waitqueue_head(&cm_id_priv->connect_wait);
init_completion(&cm_id_priv->destroy_comp);
INIT_LIST_HEAD(&cm_id_priv->work_list);
@@ -1094,7 +1093,7 @@ static int cm_event_handler(struct iw_cm_id *cm_id,
}
}
- atomic_inc(&cm_id_priv->refcount);
+ refcount_inc(&cm_id_priv->refcount);
if (list_empty(&cm_id_priv->work_list)) {
list_add_tail(&work->list, &cm_id_priv->work_list);
queue_work(iwcm_wq, &work->work);
diff --git a/drivers/infiniband/core/iwcm.h b/drivers/infiniband/core/iwcm.h
index 82c2cd1b0a80..bf74639be128 100644
--- a/drivers/infiniband/core/iwcm.h
+++ b/drivers/infiniband/core/iwcm.h
@@ -52,7 +52,7 @@ struct iwcm_id_private {
wait_queue_head_t connect_wait;
struct list_head work_list;
spinlock_t lock;
- atomic_t refcount;
+ refcount_t refcount;
struct list_head work_free_list;
};
diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c
index 932b26f50d03..12a9816fc0e2 100644
--- a/drivers/infiniband/core/iwpm_msg.c
+++ b/drivers/infiniband/core/iwpm_msg.c
@@ -123,7 +123,7 @@ int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client)
ret = iwpm_wait_complete_req(nlmsg_request);
return ret;
pid_query_error:
- pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client);
+ pr_info("%s: %s (client = %u)\n", __func__, err_str, nl_client);
dev_kfree_skb(skb);
if (nlmsg_request)
iwpm_free_nlmsg_request(&nlmsg_request->kref);
@@ -211,7 +211,7 @@ int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
ret = iwpm_wait_complete_req(nlmsg_request);
return ret;
add_mapping_error:
- pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client);
+ pr_info("%s: %s (client = %u)\n", __func__, err_str, nl_client);
add_mapping_error_nowarn:
dev_kfree_skb(skb);
if (nlmsg_request)
@@ -304,7 +304,7 @@ int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
ret = iwpm_wait_complete_req(nlmsg_request);
return ret;
query_mapping_error:
- pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client);
+ pr_info("%s: %s (client = %u)\n", __func__, err_str, nl_client);
query_mapping_error_nowarn:
dev_kfree_skb(skb);
if (nlmsg_request)
@@ -372,7 +372,7 @@ int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client)
"remove_mapping: Local sockaddr:");
return 0;
remove_mapping_error:
- pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client);
+ pr_info("%s: %s (client = %u)\n", __func__, err_str, nl_client);
if (skb)
dev_kfree_skb_any(skb);
return ret;
@@ -431,7 +431,7 @@ int iwpm_register_pid_cb(struct sk_buff *skb, struct netlink_callback *cb)
strcmp(iwpm_ulib_name, iwpm_name) ||
iwpm_version < IWPM_UABI_VERSION_MIN) {
- pr_info("%s: Incorrect info (dev = %s name = %s version = %d)\n",
+ pr_info("%s: Incorrect info (dev = %s name = %s version = %u)\n",
__func__, dev_name, iwpm_name, iwpm_version);
nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
goto register_pid_response_exit;
@@ -439,7 +439,7 @@ int iwpm_register_pid_cb(struct sk_buff *skb, struct netlink_callback *cb)
iwpm_user_pid = cb->nlh->nlmsg_pid;
iwpm_ulib_version = iwpm_version;
if (iwpm_ulib_version < IWPM_UABI_VERSION)
- pr_warn_once("%s: Down level iwpmd/pid %u. Continuing...",
+ pr_warn_once("%s: Down level iwpmd/pid %d. Continuing...",
__func__, iwpm_user_pid);
atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n",
@@ -650,7 +650,7 @@ int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
if (!iwpm_valid_client(nl_client)) {
- pr_info("%s: Invalid port mapper client = %d\n",
+ pr_info("%s: Invalid port mapper client = %u\n",
__func__, nl_client);
return ret;
}
@@ -731,13 +731,13 @@ int iwpm_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
iwpm_version = nla_get_u16(nltb[IWPM_NLA_MAPINFO_ULIB_VER]);
if (strcmp(iwpm_ulib_name, iwpm_name) ||
iwpm_version < IWPM_UABI_VERSION_MIN) {
- pr_info("%s: Invalid port mapper name = %s version = %d\n",
+ pr_info("%s: Invalid port mapper name = %s version = %u\n",
__func__, iwpm_name, iwpm_version);
return ret;
}
nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
if (!iwpm_valid_client(nl_client)) {
- pr_info("%s: Invalid port mapper client = %d\n",
+ pr_info("%s: Invalid port mapper client = %u\n",
__func__, nl_client);
return ret;
}
@@ -746,7 +746,7 @@ int iwpm_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
iwpm_user_pid = cb->nlh->nlmsg_pid;
if (iwpm_ulib_version < IWPM_UABI_VERSION)
- pr_warn_once("%s: Down level iwpmd/pid %u. Continuing...",
+ pr_warn_once("%s: Down level iwpmd/pid %d. Continuing...",
__func__, iwpm_user_pid);
if (!iwpm_mapinfo_available())
@@ -864,7 +864,7 @@ int iwpm_hello_cb(struct sk_buff *skb, struct netlink_callback *cb)
abi_version = nla_get_u16(nltb[IWPM_NLA_HELLO_ABI_VERSION]);
nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
if (!iwpm_valid_client(nl_client)) {
- pr_info("%s: Invalid port mapper client = %d\n",
+ pr_info("%s: Invalid port mapper client = %u\n",
__func__, nl_client);
return ret;
}
diff --git a/drivers/infiniband/core/iwpm_util.c b/drivers/infiniband/core/iwpm_util.c
index f80e5550b51f..3f8c019c7260 100644
--- a/drivers/infiniband/core/iwpm_util.c
+++ b/drivers/infiniband/core/iwpm_util.c
@@ -61,7 +61,7 @@ int iwpm_init(u8 nl_client)
{
int ret = 0;
mutex_lock(&iwpm_admin_lock);
- if (atomic_read(&iwpm_admin.refcount) == 0) {
+ if (!refcount_read(&iwpm_admin.refcount)) {
iwpm_hash_bucket = kcalloc(IWPM_MAPINFO_HASH_SIZE,
sizeof(struct hlist_head),
GFP_KERNEL);
@@ -77,8 +77,12 @@ int iwpm_init(u8 nl_client)
ret = -ENOMEM;
goto init_exit;
}
+
+ refcount_set(&iwpm_admin.refcount, 1);
+ } else {
+ refcount_inc(&iwpm_admin.refcount);
}
- atomic_inc(&iwpm_admin.refcount);
+
init_exit:
mutex_unlock(&iwpm_admin_lock);
if (!ret) {
@@ -105,12 +109,12 @@ int iwpm_exit(u8 nl_client)
if (!iwpm_valid_client(nl_client))
return -EINVAL;
mutex_lock(&iwpm_admin_lock);
- if (atomic_read(&iwpm_admin.refcount) == 0) {
+ if (!refcount_read(&iwpm_admin.refcount)) {
mutex_unlock(&iwpm_admin_lock);
pr_err("%s Incorrect usage - negative refcount\n", __func__);
return -EINVAL;
}
- if (atomic_dec_and_test(&iwpm_admin.refcount)) {
+ if (refcount_dec_and_test(&iwpm_admin.refcount)) {
free_hash_bucket();
free_reminfo_bucket();
pr_debug("%s: Resources are destroyed\n", __func__);
@@ -303,7 +307,7 @@ int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr,
int ret = -EINVAL;
if (!iwpm_valid_client(nl_client)) {
- pr_info("%s: Invalid client = %d\n", __func__, nl_client);
+ pr_info("%s: Invalid client = %u\n", __func__, nl_client);
return ret;
}
spin_lock_irqsave(&iwpm_reminfo_lock, flags);
@@ -651,7 +655,7 @@ static int send_mapinfo_num(u32 mapping_num, u8 nl_client, int iwpm_pid)
err_str = "Unable to send a nlmsg";
goto mapinfo_num_error;
}
- pr_debug("%s: Sent mapping number = %d\n", __func__, mapping_num);
+ pr_debug("%s: Sent mapping number = %u\n", __func__, mapping_num);
return 0;
mapinfo_num_error:
pr_info("%s: %s\n", __func__, err_str);
diff --git a/drivers/infiniband/core/iwpm_util.h b/drivers/infiniband/core/iwpm_util.h
index eeb8e6010907..e201835de733 100644
--- a/drivers/infiniband/core/iwpm_util.h
+++ b/drivers/infiniband/core/iwpm_util.h
@@ -90,7 +90,7 @@ struct iwpm_remote_info {
};
struct iwpm_admin_data {
- atomic_t refcount;
+ refcount_t refcount;
atomic_t nlmsg_seq;
int client_list[RDMA_NL_NUM_CLIENTS];
u32 reg_list[RDMA_NL_NUM_CLIENTS];
@@ -183,7 +183,7 @@ u32 iwpm_check_registration(u8 nl_client, u32 reg);
void iwpm_set_registration(u8 nl_client, u32 reg);
/**
- * iwpm_get_registration
+ * iwpm_get_registration - Get the client registration
* @nl_client: The index of the netlink client
*
* Returns the client registration type
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 2081e4854fb0..1893aa613ad7 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -351,7 +351,7 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
/* Validate device and port */
port_priv = ib_get_mad_port(device, port_num);
if (!port_priv) {
- dev_dbg_ratelimited(&device->dev, "%s: Invalid port %d\n",
+ dev_dbg_ratelimited(&device->dev, "%s: Invalid port %u\n",
__func__, port_num);
ret = ERR_PTR(-ENODEV);
goto error1;
@@ -1626,7 +1626,7 @@ static int validate_mad(const struct ib_mad_hdr *mad_hdr,
/* Make sure MAD base version is understood */
if (mad_hdr->base_version != IB_MGMT_BASE_VERSION &&
(!opa || mad_hdr->base_version != OPA_MGMT_BASE_VERSION)) {
- pr_err("MAD received with unsupported base version %d %s\n",
+ pr_err("MAD received with unsupported base version %u %s\n",
mad_hdr->base_version, opa ? "(opa)" : "");
goto out;
}
@@ -2459,16 +2459,18 @@ find_send_wr(struct ib_mad_agent_private *mad_agent_priv,
return NULL;
}
-int ib_modify_mad(struct ib_mad_agent *mad_agent,
- struct ib_mad_send_buf *send_buf, u32 timeout_ms)
+int ib_modify_mad(struct ib_mad_send_buf *send_buf, u32 timeout_ms)
{
struct ib_mad_agent_private *mad_agent_priv;
struct ib_mad_send_wr_private *mad_send_wr;
unsigned long flags;
int active;
- mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private,
- agent);
+ if (!send_buf)
+ return -EINVAL;
+
+ mad_agent_priv = container_of(send_buf->mad_agent,
+ struct ib_mad_agent_private, agent);
spin_lock_irqsave(&mad_agent_priv->lock, flags);
mad_send_wr = find_send_wr(mad_agent_priv, send_buf);
if (!mad_send_wr || mad_send_wr->status != IB_WC_SUCCESS) {
@@ -2493,13 +2495,6 @@ int ib_modify_mad(struct ib_mad_agent *mad_agent,
}
EXPORT_SYMBOL(ib_modify_mad);
-void ib_cancel_mad(struct ib_mad_agent *mad_agent,
- struct ib_mad_send_buf *send_buf)
-{
- ib_modify_mad(mad_agent, send_buf, 0);
-}
-EXPORT_SYMBOL(ib_cancel_mad);
-
static void local_completions(struct work_struct *work)
{
struct ib_mad_agent_private *mad_agent_priv;
@@ -2872,7 +2867,7 @@ static void qp_event_handler(struct ib_event *event, void *qp_context)
/* It's worse than that! He's dead, Jim! */
dev_err(&qp_info->port_priv->device->dev,
- "Fatal error (%d) on MAD QP (%d)\n",
+ "Fatal error (%d) on MAD QP (%u)\n",
event->event, qp_info->qp->qp_num);
}
@@ -3130,9 +3125,9 @@ static void ib_mad_remove_device(struct ib_device *device, void *client_data)
if (ib_agent_port_close(device, i))
dev_err(&device->dev,
- "Couldn't close port %d for agents\n", i);
+ "Couldn't close port %u for agents\n", i);
if (ib_mad_port_close(device, i))
- dev_err(&device->dev, "Couldn't close port %d\n", i);
+ dev_err(&device->dev, "Couldn't close port %u\n", i);
}
}
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
index 4aa16b35dad0..1b7445a6f671 100644
--- a/drivers/infiniband/core/mad_priv.h
+++ b/drivers/infiniband/core/mad_priv.h
@@ -115,7 +115,6 @@ struct ib_mad_snoop_private {
struct ib_mad_qp_info *qp_info;
int snoop_index;
int mad_snoop_flags;
- atomic_t refcount;
struct completion comp;
};
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
index a5dd4b7a74bc..a236532a9026 100644
--- a/drivers/infiniband/core/multicast.c
+++ b/drivers/infiniband/core/multicast.c
@@ -61,7 +61,7 @@ struct mcast_port {
struct mcast_device *dev;
spinlock_t lock;
struct rb_root table;
- atomic_t refcount;
+ refcount_t refcount;
struct completion comp;
u32 port_num;
};
@@ -117,7 +117,7 @@ struct mcast_member {
struct mcast_group *group;
struct list_head list;
enum mcast_state state;
- atomic_t refcount;
+ refcount_t refcount;
struct completion comp;
};
@@ -178,7 +178,7 @@ static struct mcast_group *mcast_insert(struct mcast_port *port,
static void deref_port(struct mcast_port *port)
{
- if (atomic_dec_and_test(&port->refcount))
+ if (refcount_dec_and_test(&port->refcount))
complete(&port->comp);
}
@@ -199,7 +199,7 @@ static void release_group(struct mcast_group *group)
static void deref_member(struct mcast_member *member)
{
- if (atomic_dec_and_test(&member->refcount))
+ if (refcount_dec_and_test(&member->refcount))
complete(&member->comp);
}
@@ -401,7 +401,7 @@ static void process_group_error(struct mcast_group *group)
while (!list_empty(&group->active_list)) {
member = list_entry(group->active_list.next,
struct mcast_member, list);
- atomic_inc(&member->refcount);
+ refcount_inc(&member->refcount);
list_del_init(&member->list);
adjust_membership(group, member->multicast.rec.join_state, -1);
member->state = MCAST_ERROR;
@@ -445,7 +445,7 @@ retest:
struct mcast_member, list);
multicast = &member->multicast;
join_state = multicast->rec.join_state;
- atomic_inc(&member->refcount);
+ refcount_inc(&member->refcount);
if (join_state == (group->rec.join_state & join_state)) {
status = cmp_rec(&group->rec, &multicast->rec,
@@ -497,7 +497,7 @@ static void process_join_error(struct mcast_group *group, int status)
member = list_entry(group->pending_list.next,
struct mcast_member, list);
if (group->last_join == member) {
- atomic_inc(&member->refcount);
+ refcount_inc(&member->refcount);
list_del_init(&member->list);
spin_unlock_irq(&group->lock);
ret = member->multicast.callback(status, &member->multicast);
@@ -589,7 +589,7 @@ static struct mcast_group *acquire_group(struct mcast_port *port,
kfree(group);
group = cur_group;
} else
- atomic_inc(&port->refcount);
+ refcount_inc(&port->refcount);
found:
atomic_inc(&group->refcount);
spin_unlock_irqrestore(&port->lock, flags);
@@ -632,7 +632,7 @@ ib_sa_join_multicast(struct ib_sa_client *client,
member->multicast.callback = callback;
member->multicast.context = context;
init_completion(&member->comp);
- atomic_set(&member->refcount, 1);
+ refcount_set(&member->refcount, 1);
member->state = MCAST_JOINING;
member->group = acquire_group(&dev->port[port_num - dev->start_port],
@@ -840,7 +840,7 @@ static int mcast_add_one(struct ib_device *device)
spin_lock_init(&port->lock);
port->table = RB_ROOT;
init_completion(&port->comp);
- atomic_set(&port->refcount, 1);
+ refcount_set(&port->refcount, 1);
++count;
}
diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c
index 8cd31ef25eff..1b2cc9e45ade 100644
--- a/drivers/infiniband/core/netlink.c
+++ b/drivers/infiniband/core/netlink.c
@@ -98,7 +98,7 @@ get_cb_table(const struct sk_buff *skb, unsigned int type, unsigned int op)
*/
up_read(&rdma_nl_types[type].sem);
- request_module("rdma-netlink-subsys-%d", type);
+ request_module("rdma-netlink-subsys-%u", type);
down_read(&rdma_nl_types[type].sem);
cb_table = READ_ONCE(rdma_nl_types[type].cb_table);
diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c
index 34d0cc1a4147..e9b4b2cccaa0 100644
--- a/drivers/infiniband/core/nldev.c
+++ b/drivers/infiniband/core/nldev.c
@@ -2060,13 +2060,14 @@ static int stat_get_doit_default_counter(struct sk_buff *skb,
if (!device)
return -EINVAL;
- if (!device->ops.alloc_hw_stats || !device->ops.get_hw_stats) {
+ if (!device->ops.alloc_hw_port_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)) {
+ stats = ib_get_hw_stats_port(device, port);
+ if (!stats) {
ret = -EINVAL;
goto err;
}
@@ -2088,11 +2089,6 @@ static int stat_get_doit_default_counter(struct sk_buff *skb,
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);
diff --git a/drivers/infiniband/core/roce_gid_mgmt.c b/drivers/infiniband/core/roce_gid_mgmt.c
index 7b638d91a4ec..68197e576433 100644
--- a/drivers/infiniband/core/roce_gid_mgmt.c
+++ b/drivers/infiniband/core/roce_gid_mgmt.c
@@ -186,12 +186,13 @@ is_eth_port_inactive_slave_filter(struct ib_device *ib_dev, u32 port,
return res;
}
-/** is_ndev_for_default_gid_filter - Check if a given netdevice
+/**
+ * is_ndev_for_default_gid_filter - Check if a given netdevice
* can be considered for default GIDs or not.
* @ib_dev: IB device to check
* @port: Port to consider for adding default GID
* @rdma_ndev: rdma netdevice pointer
- * @cookie_ndev: Netdevice to consider to form a default GID
+ * @cookie: Netdevice to consider to form a default GID
*
* is_ndev_for_default_gid_filter() returns true if a given netdevice can be
* considered for deriving default RoCE GID, returns false otherwise.
diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c
index a588c2038479..5221cce65675 100644
--- a/drivers/infiniband/core/rw.c
+++ b/drivers/infiniband/core/rw.c
@@ -389,7 +389,7 @@ int rdma_rw_ctx_signature_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
int count = 0, ret;
if (sg_cnt > pages_per_mr || prot_sg_cnt > pages_per_mr) {
- pr_err("SG count too large: sg_cnt=%d, prot_sg_cnt=%d, pages_per_mr=%d\n",
+ pr_err("SG count too large: sg_cnt=%u, prot_sg_cnt=%u, pages_per_mr=%u\n",
sg_cnt, prot_sg_cnt, pages_per_mr);
return -EINVAL;
}
@@ -429,7 +429,7 @@ int rdma_rw_ctx_signature_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
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);
+ pr_err("failed to map PI sg (%u)\n", sg_cnt + prot_sg_cnt);
goto out_destroy_sig_mr;
}
@@ -714,7 +714,7 @@ int rdma_rw_init_mrs(struct ib_qp *qp, struct ib_qp_init_attr *attr)
IB_MR_TYPE_MEM_REG,
max_num_sg, 0);
if (ret) {
- pr_err("%s: failed to allocated %d MRs\n",
+ pr_err("%s: failed to allocated %u MRs\n",
__func__, nr_mrs);
return ret;
}
@@ -724,7 +724,7 @@ int rdma_rw_init_mrs(struct ib_qp *qp, struct ib_qp_init_attr *attr)
ret = ib_mr_pool_init(qp, &qp->sig_mrs, nr_sig_mrs,
IB_MR_TYPE_INTEGRITY, max_num_sg, max_num_sg);
if (ret) {
- pr_err("%s: failed to allocated %d SIG MRs\n",
+ pr_err("%s: failed to allocated %u SIG MRs\n",
__func__, nr_sig_mrs);
goto out_free_rdma_mrs;
}
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 8f1705c403b4..b61576f702b8 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -1172,7 +1172,6 @@ EXPORT_SYMBOL(ib_sa_unregister_client);
void ib_sa_cancel_query(int id, struct ib_sa_query *query)
{
unsigned long flags;
- struct ib_mad_agent *agent;
struct ib_mad_send_buf *mad_buf;
xa_lock_irqsave(&queries, flags);
@@ -1180,7 +1179,6 @@ void ib_sa_cancel_query(int id, struct ib_sa_query *query)
xa_unlock_irqrestore(&queries, flags);
return;
}
- agent = query->port->agent;
mad_buf = query->mad_buf;
xa_unlock_irqrestore(&queries, flags);
@@ -1190,7 +1188,7 @@ void ib_sa_cancel_query(int id, struct ib_sa_query *query)
* sent to the MAD layer and has to be cancelled from there.
*/
if (!ib_nl_cancel_request(query))
- ib_cancel_mad(agent, mad_buf);
+ ib_cancel_mad(mad_buf);
}
EXPORT_SYMBOL(ib_sa_cancel_query);
@@ -1444,8 +1442,7 @@ enum opa_pr_supported {
*/
static int opa_pr_query_possible(struct ib_sa_client *client,
struct ib_sa_device *sa_dev,
- struct ib_device *device, u32 port_num,
- struct sa_path_rec *rec)
+ struct ib_device *device, u32 port_num)
{
struct ib_port_attr port_attr;
@@ -1567,8 +1564,7 @@ int ib_sa_path_rec_get(struct ib_sa_client *client,
query->sa_query.port = port;
if (rec->rec_type == SA_PATH_REC_TYPE_OPA) {
- status = opa_pr_query_possible(client, sa_dev, device, port_num,
- rec);
+ status = opa_pr_query_possible(client, sa_dev, device, port_num);
if (status == PR_NOT_SUPPORTED) {
ret = -EINVAL;
goto err1;
diff --git a/drivers/infiniband/core/security.c b/drivers/infiniband/core/security.c
index e5a78d1a63c9..3512c2e54efc 100644
--- a/drivers/infiniband/core/security.c
+++ b/drivers/infiniband/core/security.c
@@ -72,7 +72,7 @@ static int get_pkey_and_subnet_prefix(struct ib_port_pkey *pp,
if (ret)
return ret;
- ret = ib_get_cached_subnet_prefix(dev, pp->port_num, subnet_prefix);
+ ib_get_cached_subnet_prefix(dev, pp->port_num, subnet_prefix);
return ret;
}
@@ -586,7 +586,7 @@ int ib_security_modify_qp(struct ib_qp *qp,
WARN_ONCE((qp_attr_mask & IB_QP_PORT &&
rdma_protocol_ib(real_qp->device, qp_attr->port_num) &&
!real_qp->qp_sec),
- "%s: QP security is not initialized for IB QP: %d\n",
+ "%s: QP security is not initialized for IB QP: %u\n",
__func__, real_qp->qp_num);
/* The port/pkey settings are maintained only for the real QP. Open
@@ -664,10 +664,7 @@ static int ib_security_pkey_access(struct ib_device *dev,
if (ret)
return ret;
- ret = ib_get_cached_subnet_prefix(dev, port_num, &subnet_prefix);
-
- if (ret)
- return ret;
+ ib_get_cached_subnet_prefix(dev, port_num, &subnet_prefix);
return security_ib_pkey_access(sec, subnet_prefix, pkey);
}
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 05b702de00e8..6146c3c1cbe5 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -44,110 +44,174 @@
#include <rdma/ib_pma.h>
#include <rdma/ib_cache.h>
#include <rdma/rdma_counter.h>
+#include <rdma/ib_sysfs.h>
-struct ib_port;
+struct port_table_attribute {
+ struct ib_port_attribute attr;
+ char name[8];
+ int index;
+ __be16 attr_id;
+};
struct gid_attr_group {
- struct ib_port *port;
- struct kobject kobj;
- struct attribute_group ndev;
- struct attribute_group type;
+ struct ib_port *port;
+ struct kobject kobj;
+ struct attribute_group groups[2];
+ const struct attribute_group *groups_list[3];
+ struct port_table_attribute attrs_list[];
};
+
struct ib_port {
- struct kobject kobj;
- struct ib_device *ibdev;
+ struct kobject kobj;
+ struct ib_device *ibdev;
struct gid_attr_group *gid_attr_group;
- struct attribute_group gid_group;
- struct attribute_group *pkey_group;
- const struct attribute_group *pma_table;
- struct attribute_group *hw_stats_ag;
- struct rdma_hw_stats *hw_stats;
- u32 port_num;
+ struct hw_stats_port_data *hw_stats_data;
+
+ struct attribute_group groups[3];
+ const struct attribute_group *groups_list[5];
+ u32 port_num;
+ struct port_table_attribute attrs_list[];
};
-struct port_attribute {
- struct attribute attr;
- ssize_t (*show)(struct ib_port *, struct port_attribute *, char *buf);
- ssize_t (*store)(struct ib_port *, struct port_attribute *,
+struct hw_stats_device_attribute {
+ struct device_attribute attr;
+ ssize_t (*show)(struct ib_device *ibdev, struct rdma_hw_stats *stats,
+ unsigned int index, unsigned int port_num, char *buf);
+ ssize_t (*store)(struct ib_device *ibdev, struct rdma_hw_stats *stats,
+ unsigned int index, unsigned int port_num,
const char *buf, size_t count);
};
-#define PORT_ATTR(_name, _mode, _show, _store) \
-struct port_attribute port_attr_##_name = __ATTR(_name, _mode, _show, _store)
-
-#define PORT_ATTR_RO(_name) \
-struct port_attribute port_attr_##_name = __ATTR_RO(_name)
+struct hw_stats_port_attribute {
+ struct ib_port_attribute attr;
+ ssize_t (*show)(struct ib_device *ibdev, struct rdma_hw_stats *stats,
+ unsigned int index, unsigned int port_num, char *buf);
+ ssize_t (*store)(struct ib_device *ibdev, struct rdma_hw_stats *stats,
+ unsigned int index, unsigned int port_num,
+ const char *buf, size_t count);
+};
-struct port_table_attribute {
- struct port_attribute attr;
- char name[8];
- int index;
- __be16 attr_id;
+struct hw_stats_device_data {
+ struct attribute_group group;
+ struct rdma_hw_stats *stats;
+ struct hw_stats_device_attribute attrs[];
};
-struct hw_stats_attribute {
- struct attribute attr;
- ssize_t (*show)(struct kobject *kobj,
- struct attribute *attr, char *buf);
- ssize_t (*store)(struct kobject *kobj,
- struct attribute *attr,
- const char *buf,
- size_t count);
- int index;
- u32 port_num;
+struct hw_stats_port_data {
+ struct rdma_hw_stats *stats;
+ struct hw_stats_port_attribute attrs[];
};
static ssize_t port_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
- struct port_attribute *port_attr =
- container_of(attr, struct port_attribute, attr);
+ struct ib_port_attribute *port_attr =
+ container_of(attr, struct ib_port_attribute, attr);
struct ib_port *p = container_of(kobj, struct ib_port, kobj);
if (!port_attr->show)
return -EIO;
- return port_attr->show(p, port_attr, buf);
+ return port_attr->show(p->ibdev, p->port_num, port_attr, buf);
}
static ssize_t port_attr_store(struct kobject *kobj,
struct attribute *attr,
const char *buf, size_t count)
{
- struct port_attribute *port_attr =
- container_of(attr, struct port_attribute, attr);
+ struct ib_port_attribute *port_attr =
+ container_of(attr, struct ib_port_attribute, attr);
struct ib_port *p = container_of(kobj, struct ib_port, kobj);
if (!port_attr->store)
return -EIO;
- return port_attr->store(p, port_attr, buf, count);
+ return port_attr->store(p->ibdev, p->port_num, port_attr, buf, count);
+}
+
+struct ib_device *ib_port_sysfs_get_ibdev_kobj(struct kobject *kobj,
+ u32 *port_num)
+{
+ struct ib_port *port = container_of(kobj, struct ib_port, kobj);
+
+ *port_num = port->port_num;
+ return port->ibdev;
}
+EXPORT_SYMBOL(ib_port_sysfs_get_ibdev_kobj);
static const struct sysfs_ops port_sysfs_ops = {
.show = port_attr_show,
.store = port_attr_store
};
+static ssize_t hw_stat_device_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hw_stats_device_attribute *stat_attr =
+ container_of(attr, struct hw_stats_device_attribute, attr);
+ struct ib_device *ibdev = container_of(dev, struct ib_device, dev);
+
+ return stat_attr->show(ibdev, ibdev->hw_stats_data->stats,
+ stat_attr - ibdev->hw_stats_data->attrs, 0, buf);
+}
+
+static ssize_t hw_stat_device_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hw_stats_device_attribute *stat_attr =
+ container_of(attr, struct hw_stats_device_attribute, attr);
+ struct ib_device *ibdev = container_of(dev, struct ib_device, dev);
+
+ return stat_attr->store(ibdev, ibdev->hw_stats_data->stats,
+ stat_attr - ibdev->hw_stats_data->attrs, 0, buf,
+ count);
+}
+
+static ssize_t hw_stat_port_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
+{
+ struct hw_stats_port_attribute *stat_attr =
+ container_of(attr, struct hw_stats_port_attribute, attr);
+ struct ib_port *port = ibdev->port_data[port_num].sysfs;
+
+ return stat_attr->show(ibdev, port->hw_stats_data->stats,
+ stat_attr - port->hw_stats_data->attrs,
+ port->port_num, buf);
+}
+
+static ssize_t hw_stat_port_store(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hw_stats_port_attribute *stat_attr =
+ container_of(attr, struct hw_stats_port_attribute, attr);
+ struct ib_port *port = ibdev->port_data[port_num].sysfs;
+
+ return stat_attr->store(ibdev, port->hw_stats_data->stats,
+ stat_attr - port->hw_stats_data->attrs,
+ port->port_num, buf, count);
+}
+
static ssize_t gid_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
- struct port_attribute *port_attr =
- container_of(attr, struct port_attribute, attr);
+ struct ib_port_attribute *port_attr =
+ container_of(attr, struct ib_port_attribute, attr);
struct ib_port *p = container_of(kobj, struct gid_attr_group,
kobj)->port;
if (!port_attr->show)
return -EIO;
- return port_attr->show(p, port_attr, buf);
+ return port_attr->show(p->ibdev, p->port_num, port_attr, buf);
}
static const struct sysfs_ops gid_attr_sysfs_ops = {
.show = gid_attr_show
};
-static ssize_t state_show(struct ib_port *p, struct port_attribute *unused,
- char *buf)
+static ssize_t state_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *unused, char *buf)
{
struct ib_port_attr attr;
ssize_t ret;
@@ -161,7 +225,7 @@ static ssize_t state_show(struct ib_port *p, struct port_attribute *unused,
[IB_PORT_ACTIVE_DEFER] = "ACTIVE_DEFER"
};
- ret = ib_query_port(p->ibdev, p->port_num, &attr);
+ ret = ib_query_port(ibdev, port_num, &attr);
if (ret)
return ret;
@@ -172,81 +236,80 @@ static ssize_t state_show(struct ib_port *p, struct port_attribute *unused,
"UNKNOWN");
}
-static ssize_t lid_show(struct ib_port *p, struct port_attribute *unused,
- char *buf)
+static ssize_t lid_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *unused, char *buf)
{
struct ib_port_attr attr;
ssize_t ret;
- ret = ib_query_port(p->ibdev, p->port_num, &attr);
+ ret = ib_query_port(ibdev, port_num, &attr);
if (ret)
return ret;
return sysfs_emit(buf, "0x%x\n", attr.lid);
}
-static ssize_t lid_mask_count_show(struct ib_port *p,
- struct port_attribute *unused,
- char *buf)
+static ssize_t lid_mask_count_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *unused, char *buf)
{
struct ib_port_attr attr;
ssize_t ret;
- ret = ib_query_port(p->ibdev, p->port_num, &attr);
+ ret = ib_query_port(ibdev, port_num, &attr);
if (ret)
return ret;
- return sysfs_emit(buf, "%d\n", attr.lmc);
+ return sysfs_emit(buf, "%u\n", attr.lmc);
}
-static ssize_t sm_lid_show(struct ib_port *p, struct port_attribute *unused,
- char *buf)
+static ssize_t sm_lid_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *unused, char *buf)
{
struct ib_port_attr attr;
ssize_t ret;
- ret = ib_query_port(p->ibdev, p->port_num, &attr);
+ ret = ib_query_port(ibdev, port_num, &attr);
if (ret)
return ret;
return sysfs_emit(buf, "0x%x\n", attr.sm_lid);
}
-static ssize_t sm_sl_show(struct ib_port *p, struct port_attribute *unused,
- char *buf)
+static ssize_t sm_sl_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *unused, char *buf)
{
struct ib_port_attr attr;
ssize_t ret;
- ret = ib_query_port(p->ibdev, p->port_num, &attr);
+ ret = ib_query_port(ibdev, port_num, &attr);
if (ret)
return ret;
- return sysfs_emit(buf, "%d\n", attr.sm_sl);
+ return sysfs_emit(buf, "%u\n", attr.sm_sl);
}
-static ssize_t cap_mask_show(struct ib_port *p, struct port_attribute *unused,
- char *buf)
+static ssize_t cap_mask_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *unused, char *buf)
{
struct ib_port_attr attr;
ssize_t ret;
- ret = ib_query_port(p->ibdev, p->port_num, &attr);
+ ret = ib_query_port(ibdev, port_num, &attr);
if (ret)
return ret;
return sysfs_emit(buf, "0x%08x\n", attr.port_cap_flags);
}
-static ssize_t rate_show(struct ib_port *p, struct port_attribute *unused,
- char *buf)
+static ssize_t rate_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *unused, char *buf)
{
struct ib_port_attr attr;
char *speed = "";
int rate; /* in deci-Gb/sec */
ssize_t ret;
- ret = ib_query_port(p->ibdev, p->port_num, &attr);
+ ret = ib_query_port(ibdev, port_num, &attr);
if (ret)
return ret;
@@ -313,27 +376,27 @@ static const char *phys_state_to_str(enum ib_port_phys_state phys_state)
return "<unknown>";
}
-static ssize_t phys_state_show(struct ib_port *p, struct port_attribute *unused,
- char *buf)
+static ssize_t phys_state_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *unused, char *buf)
{
struct ib_port_attr attr;
ssize_t ret;
- ret = ib_query_port(p->ibdev, p->port_num, &attr);
+ ret = ib_query_port(ibdev, port_num, &attr);
if (ret)
return ret;
- return sysfs_emit(buf, "%d: %s\n", attr.phys_state,
+ return sysfs_emit(buf, "%u: %s\n", attr.phys_state,
phys_state_to_str(attr.phys_state));
}
-static ssize_t link_layer_show(struct ib_port *p, struct port_attribute *unused,
- char *buf)
+static ssize_t link_layer_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *unused, char *buf)
{
const char *output;
- switch (rdma_port_get_link_layer(p->ibdev, p->port_num)) {
+ switch (rdma_port_get_link_layer(ibdev, port_num)) {
case IB_LINK_LAYER_INFINIBAND:
output = "InfiniBand";
break;
@@ -348,26 +411,26 @@ static ssize_t link_layer_show(struct ib_port *p, struct port_attribute *unused,
return sysfs_emit(buf, "%s\n", output);
}
-static PORT_ATTR_RO(state);
-static PORT_ATTR_RO(lid);
-static PORT_ATTR_RO(lid_mask_count);
-static PORT_ATTR_RO(sm_lid);
-static PORT_ATTR_RO(sm_sl);
-static PORT_ATTR_RO(cap_mask);
-static PORT_ATTR_RO(rate);
-static PORT_ATTR_RO(phys_state);
-static PORT_ATTR_RO(link_layer);
+static IB_PORT_ATTR_RO(state);
+static IB_PORT_ATTR_RO(lid);
+static IB_PORT_ATTR_RO(lid_mask_count);
+static IB_PORT_ATTR_RO(sm_lid);
+static IB_PORT_ATTR_RO(sm_sl);
+static IB_PORT_ATTR_RO(cap_mask);
+static IB_PORT_ATTR_RO(rate);
+static IB_PORT_ATTR_RO(phys_state);
+static IB_PORT_ATTR_RO(link_layer);
static struct attribute *port_default_attrs[] = {
- &port_attr_state.attr,
- &port_attr_lid.attr,
- &port_attr_lid_mask_count.attr,
- &port_attr_sm_lid.attr,
- &port_attr_sm_sl.attr,
- &port_attr_cap_mask.attr,
- &port_attr_rate.attr,
- &port_attr_phys_state.attr,
- &port_attr_link_layer.attr,
+ &ib_port_attr_state.attr,
+ &ib_port_attr_lid.attr,
+ &ib_port_attr_lid_mask_count.attr,
+ &ib_port_attr_sm_lid.attr,
+ &ib_port_attr_sm_sl.attr,
+ &ib_port_attr_cap_mask.attr,
+ &ib_port_attr_rate.attr,
+ &ib_port_attr_phys_state.attr,
+ &ib_port_attr_link_layer.attr,
NULL
};
@@ -391,7 +454,8 @@ static ssize_t print_gid_type(const struct ib_gid_attr *gid_attr, char *buf)
}
static ssize_t _show_port_gid_attr(
- struct ib_port *p, struct port_attribute *attr, char *buf,
+ struct ib_device *ibdev, u32 port_num, struct ib_port_attribute *attr,
+ char *buf,
ssize_t (*print)(const struct ib_gid_attr *gid_attr, char *buf))
{
struct port_table_attribute *tab_attr =
@@ -399,7 +463,7 @@ static ssize_t _show_port_gid_attr(
const struct ib_gid_attr *gid_attr;
ssize_t ret;
- gid_attr = rdma_get_gid_attr(p->ibdev, p->port_num, tab_attr->index);
+ gid_attr = rdma_get_gid_attr(ibdev, port_num, tab_attr->index);
if (IS_ERR(gid_attr))
/* -EINVAL is returned for user space compatibility reasons. */
return -EINVAL;
@@ -409,15 +473,15 @@ static ssize_t _show_port_gid_attr(
return ret;
}
-static ssize_t show_port_gid(struct ib_port *p, struct port_attribute *attr,
- char *buf)
+static ssize_t show_port_gid(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
{
struct port_table_attribute *tab_attr =
container_of(attr, struct port_table_attribute, attr);
const struct ib_gid_attr *gid_attr;
int len;
- gid_attr = rdma_get_gid_attr(p->ibdev, p->port_num, tab_attr->index);
+ gid_attr = rdma_get_gid_attr(ibdev, port_num, tab_attr->index);
if (IS_ERR(gid_attr)) {
const union ib_gid zgid = {};
@@ -438,28 +502,30 @@ static ssize_t show_port_gid(struct ib_port *p, struct port_attribute *attr,
return len;
}
-static ssize_t show_port_gid_attr_ndev(struct ib_port *p,
- struct port_attribute *attr, char *buf)
+static ssize_t show_port_gid_attr_ndev(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr,
+ char *buf)
{
- return _show_port_gid_attr(p, attr, buf, print_ndev);
+ return _show_port_gid_attr(ibdev, port_num, attr, buf, print_ndev);
}
-static ssize_t show_port_gid_attr_gid_type(struct ib_port *p,
- struct port_attribute *attr,
+static ssize_t show_port_gid_attr_gid_type(struct ib_device *ibdev,
+ u32 port_num,
+ struct ib_port_attribute *attr,
char *buf)
{
- return _show_port_gid_attr(p, attr, buf, print_gid_type);
+ return _show_port_gid_attr(ibdev, port_num, attr, buf, print_gid_type);
}
-static ssize_t show_port_pkey(struct ib_port *p, struct port_attribute *attr,
- char *buf)
+static ssize_t show_port_pkey(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
{
struct port_table_attribute *tab_attr =
container_of(attr, struct port_table_attribute, attr);
u16 pkey;
int ret;
- ret = ib_query_pkey(p->ibdev, p->port_num, tab_attr->index, &pkey);
+ ret = ib_query_pkey(ibdev, port_num, tab_attr->index, &pkey);
if (ret)
return ret;
@@ -528,8 +594,8 @@ out:
return ret;
}
-static ssize_t show_pma_counter(struct ib_port *p, struct port_attribute *attr,
- char *buf)
+static ssize_t show_pma_counter(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
{
struct port_table_attribute *tab_attr =
container_of(attr, struct port_table_attribute, attr);
@@ -539,14 +605,14 @@ static ssize_t show_pma_counter(struct ib_port *p, struct port_attribute *attr,
u8 data[8];
int len;
- ret = get_perf_mad(p->ibdev, p->port_num, tab_attr->attr_id, &data,
+ ret = get_perf_mad(ibdev, port_num, tab_attr->attr_id, &data,
40 + offset / 8, sizeof(data));
if (ret < 0)
return ret;
switch (width) {
case 4:
- len = sysfs_emit(buf, "%u\n",
+ len = sysfs_emit(buf, "%d\n",
(*data >> (4 - (offset % 8))) & 0xf);
break;
case 8:
@@ -683,54 +749,26 @@ static const struct attribute_group pma_group_noietf = {
static void ib_port_release(struct kobject *kobj)
{
- struct ib_port *p = container_of(kobj, struct ib_port, kobj);
- struct attribute *a;
+ struct ib_port *port = container_of(kobj, struct ib_port, kobj);
int i;
- if (p->gid_group.attrs) {
- for (i = 0; (a = p->gid_group.attrs[i]); ++i)
- kfree(a);
-
- kfree(p->gid_group.attrs);
- }
-
- if (p->pkey_group) {
- if (p->pkey_group->attrs) {
- for (i = 0; (a = p->pkey_group->attrs[i]); ++i)
- kfree(a);
-
- kfree(p->pkey_group->attrs);
- }
-
- kfree(p->pkey_group);
- p->pkey_group = NULL;
- }
-
- kfree(p);
+ for (i = 0; i != ARRAY_SIZE(port->groups); i++)
+ kfree(port->groups[i].attrs);
+ if (port->hw_stats_data)
+ kfree(port->hw_stats_data->stats);
+ kfree(port->hw_stats_data);
+ kfree(port);
}
static void ib_port_gid_attr_release(struct kobject *kobj)
{
- struct gid_attr_group *g = container_of(kobj, struct gid_attr_group,
- kobj);
- struct attribute *a;
+ struct gid_attr_group *gid_attr_group =
+ container_of(kobj, struct gid_attr_group, kobj);
int i;
- if (g->ndev.attrs) {
- for (i = 0; (a = g->ndev.attrs[i]); ++i)
- kfree(a);
-
- kfree(g->ndev.attrs);
- }
-
- if (g->type.attrs) {
- for (i = 0; (a = g->type.attrs[i]); ++i)
- kfree(a);
-
- kfree(g->type.attrs);
- }
-
- kfree(g);
+ for (i = 0; i != ARRAY_SIZE(gid_attr_group->groups); i++)
+ kfree(gid_attr_group->groups[i].attrs);
+ kfree(gid_attr_group);
}
static struct kobj_type port_type = {
@@ -744,49 +782,6 @@ static struct kobj_type gid_attr_type = {
.release = ib_port_gid_attr_release
};
-static struct attribute **
-alloc_group_attrs(ssize_t (*show)(struct ib_port *,
- struct port_attribute *, char *buf),
- int len)
-{
- struct attribute **tab_attr;
- struct port_table_attribute *element;
- int i;
-
- tab_attr = kcalloc(1 + len, sizeof(struct attribute *), GFP_KERNEL);
- if (!tab_attr)
- return NULL;
-
- for (i = 0; i < len; i++) {
- element = kzalloc(sizeof(struct port_table_attribute),
- GFP_KERNEL);
- if (!element)
- goto err;
-
- if (snprintf(element->name, sizeof(element->name),
- "%d", i) >= sizeof(element->name)) {
- kfree(element);
- goto err;
- }
-
- element->attr.attr.name = element->name;
- element->attr.attr.mode = S_IRUGO;
- element->attr.show = show;
- element->index = i;
- sysfs_attr_init(&element->attr.attr);
-
- tab_attr[i] = &element->attr.attr;
- }
-
- return tab_attr;
-
-err:
- while (--i >= 0)
- kfree(tab_attr[i]);
- kfree(tab_attr);
- return NULL;
-}
-
/*
* Figure out which counter table to use depending on
* the device capabilities.
@@ -835,56 +830,30 @@ static int print_hw_stat(struct ib_device *dev, int port_num,
return sysfs_emit(buf, "%llu\n", stats->value[index] + v);
}
-static ssize_t show_hw_stats(struct kobject *kobj, struct attribute *attr,
- char *buf)
+static ssize_t show_hw_stats(struct ib_device *ibdev,
+ struct rdma_hw_stats *stats, unsigned int index,
+ unsigned int port_num, char *buf)
{
- struct ib_device *dev;
- struct ib_port *port;
- struct hw_stats_attribute *hsa;
- struct rdma_hw_stats *stats;
int ret;
- hsa = container_of(attr, struct hw_stats_attribute, attr);
- if (!hsa->port_num) {
- dev = container_of((struct device *)kobj,
- struct ib_device, dev);
- stats = dev->hw_stats;
- } else {
- port = container_of(kobj, struct ib_port, kobj);
- dev = port->ibdev;
- stats = port->hw_stats;
- }
mutex_lock(&stats->lock);
- ret = update_hw_stats(dev, stats, hsa->port_num, hsa->index);
+ ret = update_hw_stats(ibdev, stats, port_num, index);
if (ret)
goto unlock;
- ret = print_hw_stat(dev, hsa->port_num, stats, hsa->index, buf);
+ ret = print_hw_stat(ibdev, port_num, stats, index, buf);
unlock:
mutex_unlock(&stats->lock);
return ret;
}
-static ssize_t show_stats_lifespan(struct kobject *kobj,
- struct attribute *attr,
+static ssize_t show_stats_lifespan(struct ib_device *ibdev,
+ struct rdma_hw_stats *stats,
+ unsigned int index, unsigned int port_num,
char *buf)
{
- struct hw_stats_attribute *hsa;
- struct rdma_hw_stats *stats;
int msecs;
- hsa = container_of(attr, struct hw_stats_attribute, attr);
- if (!hsa->port_num) {
- struct ib_device *dev = container_of((struct device *)kobj,
- struct ib_device, dev);
-
- stats = dev->hw_stats;
- } else {
- struct ib_port *p = container_of(kobj, struct ib_port, kobj);
-
- stats = p->hw_stats;
- }
-
mutex_lock(&stats->lock);
msecs = jiffies_to_msecs(stats->lifespan);
mutex_unlock(&stats->lock);
@@ -892,12 +861,11 @@ static ssize_t show_stats_lifespan(struct kobject *kobj,
return sysfs_emit(buf, "%d\n", msecs);
}
-static ssize_t set_stats_lifespan(struct kobject *kobj,
- struct attribute *attr,
- const char *buf, size_t count)
+static ssize_t set_stats_lifespan(struct ib_device *ibdev,
+ struct rdma_hw_stats *stats,
+ unsigned int index, unsigned int port_num,
+ const char *buf, size_t count)
{
- struct hw_stats_attribute *hsa;
- struct rdma_hw_stats *stats;
int msecs;
int jiffies;
int ret;
@@ -908,17 +876,6 @@ static ssize_t set_stats_lifespan(struct kobject *kobj,
if (msecs < 0 || msecs > 10000)
return -EINVAL;
jiffies = msecs_to_jiffies(msecs);
- hsa = container_of(attr, struct hw_stats_attribute, attr);
- if (!hsa->port_num) {
- struct ib_device *dev = container_of((struct device *)kobj,
- struct ib_device, dev);
-
- stats = dev->hw_stats;
- } else {
- struct ib_port *p = container_of(kobj, struct ib_port, kobj);
-
- stats = p->hw_stats;
- }
mutex_lock(&stats->lock);
stats->lifespan = jiffies;
@@ -927,65 +884,116 @@ static ssize_t set_stats_lifespan(struct kobject *kobj,
return count;
}
-static void free_hsag(struct kobject *kobj, struct attribute_group *attr_group)
+static struct hw_stats_device_data *
+alloc_hw_stats_device(struct ib_device *ibdev)
{
- struct attribute **attr;
-
- sysfs_remove_group(kobj, attr_group);
+ struct hw_stats_device_data *data;
+ struct rdma_hw_stats *stats;
- for (attr = attr_group->attrs; *attr; attr++)
- kfree(*attr);
- kfree(attr_group);
-}
+ if (!ibdev->ops.alloc_hw_device_stats)
+ return ERR_PTR(-EOPNOTSUPP);
+ stats = ibdev->ops.alloc_hw_device_stats(ibdev);
+ if (!stats)
+ return ERR_PTR(-ENOMEM);
+ if (!stats->names || stats->num_counters <= 0)
+ goto err_free_stats;
-static struct attribute *alloc_hsa(int index, u32 port_num, const char *name)
-{
- struct hw_stats_attribute *hsa;
+ /*
+ * Two extra attribue elements here, one for the lifespan entry and
+ * one to NULL terminate the list for the sysfs core code
+ */
+ data = kzalloc(struct_size(data, attrs, stats->num_counters + 1),
+ GFP_KERNEL);
+ if (!data)
+ goto err_free_stats;
+ data->group.attrs = kcalloc(stats->num_counters + 2,
+ sizeof(*data->group.attrs), GFP_KERNEL);
+ if (!data->group.attrs)
+ goto err_free_data;
- hsa = kmalloc(sizeof(*hsa), GFP_KERNEL);
- if (!hsa)
- return NULL;
+ mutex_init(&stats->lock);
+ data->group.name = "hw_counters";
+ data->stats = stats;
+ return data;
- hsa->attr.name = (char *)name;
- hsa->attr.mode = S_IRUGO;
- hsa->show = show_hw_stats;
- hsa->store = NULL;
- hsa->index = index;
- hsa->port_num = port_num;
+err_free_data:
+ kfree(data);
+err_free_stats:
+ kfree(stats);
+ return ERR_PTR(-ENOMEM);
+}
- return &hsa->attr;
+void ib_device_release_hw_stats(struct hw_stats_device_data *data)
+{
+ kfree(data->group.attrs);
+ kfree(data->stats);
+ kfree(data);
}
-static struct attribute *alloc_hsa_lifespan(char *name, u32 port_num)
+int ib_setup_device_attrs(struct ib_device *ibdev)
{
- struct hw_stats_attribute *hsa;
+ struct hw_stats_device_attribute *attr;
+ struct hw_stats_device_data *data;
+ int i, ret;
- hsa = kmalloc(sizeof(*hsa), GFP_KERNEL);
- if (!hsa)
- return NULL;
+ data = alloc_hw_stats_device(ibdev);
+ if (IS_ERR(data)) {
+ if (PTR_ERR(data) == -EOPNOTSUPP)
+ return 0;
+ return PTR_ERR(data);
+ }
+ ibdev->hw_stats_data = data;
- hsa->attr.name = name;
- hsa->attr.mode = S_IWUSR | S_IRUGO;
- hsa->show = show_stats_lifespan;
- hsa->store = set_stats_lifespan;
- hsa->index = 0;
- hsa->port_num = port_num;
+ ret = ibdev->ops.get_hw_stats(ibdev, data->stats, 0,
+ data->stats->num_counters);
+ if (ret != data->stats->num_counters) {
+ if (WARN_ON(ret >= 0))
+ return -EINVAL;
+ return ret;
+ }
+
+ data->stats->timestamp = jiffies;
+
+ for (i = 0; i < data->stats->num_counters; i++) {
+ attr = &data->attrs[i];
+ sysfs_attr_init(&attr->attr.attr);
+ attr->attr.attr.name = data->stats->names[i];
+ attr->attr.attr.mode = 0444;
+ attr->attr.show = hw_stat_device_show;
+ attr->show = show_hw_stats;
+ data->group.attrs[i] = &attr->attr.attr;
+ }
- return &hsa->attr;
+ attr = &data->attrs[i];
+ sysfs_attr_init(&attr->attr.attr);
+ attr->attr.attr.name = "lifespan";
+ attr->attr.attr.mode = 0644;
+ attr->attr.show = hw_stat_device_show;
+ attr->show = show_stats_lifespan;
+ attr->attr.store = hw_stat_device_store;
+ attr->store = set_stats_lifespan;
+ data->group.attrs[i] = &attr->attr.attr;
+ for (i = 0; i != ARRAY_SIZE(ibdev->groups); i++)
+ if (!ibdev->groups[i]) {
+ ibdev->groups[i] = &data->group;
+ return 0;
+ }
+ WARN(true, "struct ib_device->groups is too small");
+ return -EINVAL;
}
-static void setup_hw_stats(struct ib_device *device, struct ib_port *port,
- u32 port_num)
+static struct hw_stats_port_data *
+alloc_hw_stats_port(struct ib_port *port, struct attribute_group *group)
{
- struct attribute_group *hsag;
+ struct ib_device *ibdev = port->ibdev;
+ struct hw_stats_port_data *data;
struct rdma_hw_stats *stats;
- int i, ret;
-
- stats = device->ops.alloc_hw_stats(device, port_num);
+ if (!ibdev->ops.alloc_hw_port_stats)
+ return ERR_PTR(-EOPNOTSUPP);
+ stats = ibdev->ops.alloc_hw_port_stats(port->ibdev, port->port_num);
if (!stats)
- return;
-
+ return ERR_PTR(-ENOMEM);
if (!stats->names || stats->num_counters <= 0)
goto err_free_stats;
@@ -993,244 +1001,275 @@ static void setup_hw_stats(struct ib_device *device, struct ib_port *port,
* Two extra attribue elements here, one for the lifespan entry and
* one to NULL terminate the list for the sysfs core code
*/
- hsag = kzalloc(sizeof(*hsag) +
- sizeof(void *) * (stats->num_counters + 2),
+ data = kzalloc(struct_size(data, attrs, stats->num_counters + 1),
GFP_KERNEL);
- if (!hsag)
+ if (!data)
goto err_free_stats;
+ group->attrs = kcalloc(stats->num_counters + 2,
+ sizeof(*group->attrs), GFP_KERNEL);
+ if (!group->attrs)
+ goto err_free_data;
- ret = device->ops.get_hw_stats(device, stats, port_num,
- stats->num_counters);
- if (ret != stats->num_counters)
- goto err_free_hsag;
+ mutex_init(&stats->lock);
+ group->name = "hw_counters";
+ data->stats = stats;
+ return data;
- stats->timestamp = jiffies;
+err_free_data:
+ kfree(data);
+err_free_stats:
+ kfree(stats);
+ return ERR_PTR(-ENOMEM);
+}
- hsag->name = "hw_counters";
- hsag->attrs = (void *)hsag + sizeof(*hsag);
+static int setup_hw_port_stats(struct ib_port *port,
+ struct attribute_group *group)
+{
+ struct hw_stats_port_attribute *attr;
+ struct hw_stats_port_data *data;
+ int i, ret;
- for (i = 0; i < stats->num_counters; i++) {
- hsag->attrs[i] = alloc_hsa(i, port_num, stats->names[i]);
- if (!hsag->attrs[i])
- goto err;
- sysfs_attr_init(hsag->attrs[i]);
+ data = alloc_hw_stats_port(port, group);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ ret = port->ibdev->ops.get_hw_stats(port->ibdev, data->stats,
+ port->port_num,
+ data->stats->num_counters);
+ if (ret != data->stats->num_counters) {
+ if (WARN_ON(ret >= 0))
+ return -EINVAL;
+ return ret;
}
- mutex_init(&stats->lock);
- /* treat an error here as non-fatal */
- hsag->attrs[i] = alloc_hsa_lifespan("lifespan", port_num);
- if (hsag->attrs[i])
- sysfs_attr_init(hsag->attrs[i]);
-
- if (port) {
- struct kobject *kobj = &port->kobj;
- ret = sysfs_create_group(kobj, hsag);
- if (ret)
- 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);
- if (ret)
- goto err;
- device->hw_stats_ag = hsag;
- device->hw_stats = stats;
+ data->stats->timestamp = jiffies;
+
+ for (i = 0; i < data->stats->num_counters; i++) {
+ attr = &data->attrs[i];
+ sysfs_attr_init(&attr->attr.attr);
+ attr->attr.attr.name = data->stats->names[i];
+ attr->attr.attr.mode = 0444;
+ attr->attr.show = hw_stat_port_show;
+ attr->show = show_hw_stats;
+ group->attrs[i] = &attr->attr.attr;
}
- return;
+ attr = &data->attrs[i];
+ sysfs_attr_init(&attr->attr.attr);
+ attr->attr.attr.name = "lifespan";
+ attr->attr.attr.mode = 0644;
+ attr->attr.show = hw_stat_port_show;
+ attr->show = show_stats_lifespan;
+ attr->attr.store = hw_stat_port_store;
+ attr->store = set_stats_lifespan;
+ group->attrs[i] = &attr->attr.attr;
+
+ port->hw_stats_data = data;
+ return 0;
+}
-err:
- for (; i >= 0; i--)
- kfree(hsag->attrs[i]);
-err_free_hsag:
- kfree(hsag);
-err_free_stats:
- kfree(stats);
+struct rdma_hw_stats *ib_get_hw_stats_port(struct ib_device *ibdev,
+ u32 port_num)
+{
+ if (!ibdev->port_data || !rdma_is_port_valid(ibdev, port_num) ||
+ !ibdev->port_data[port_num].sysfs->hw_stats_data)
+ return NULL;
+ return ibdev->port_data[port_num].sysfs->hw_stats_data->stats;
}
-static int add_port(struct ib_core_device *coredev, int port_num)
+static int
+alloc_port_table_group(const char *name, struct attribute_group *group,
+ struct port_table_attribute *attrs, size_t num,
+ ssize_t (*show)(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *, char *buf))
{
- struct ib_device *device = rdma_device_to_ibdev(&coredev->dev);
- bool is_full_dev = &device->coredev == coredev;
- struct ib_port *p;
- struct ib_port_attr attr;
+ struct attribute **attr_list;
int i;
- int ret;
-
- ret = ib_query_port(device, port_num, &attr);
- if (ret)
- return ret;
- p = kzalloc(sizeof *p, GFP_KERNEL);
- if (!p)
+ attr_list = kcalloc(num + 1, sizeof(*attr_list), GFP_KERNEL);
+ if (!attr_list)
return -ENOMEM;
- p->ibdev = device;
- p->port_num = port_num;
-
- ret = kobject_init_and_add(&p->kobj, &port_type,
- coredev->ports_kobj,
- "%d", port_num);
- if (ret)
- goto err_put;
+ for (i = 0; i < num; i++) {
+ struct port_table_attribute *element = &attrs[i];
- p->gid_attr_group = kzalloc(sizeof(*p->gid_attr_group), GFP_KERNEL);
- if (!p->gid_attr_group) {
- ret = -ENOMEM;
- goto err_put;
- }
-
- p->gid_attr_group->port = p;
- ret = kobject_init_and_add(&p->gid_attr_group->kobj, &gid_attr_type,
- &p->kobj, "gid_attrs");
- if (ret)
- goto err_put_gid_attrs;
+ if (snprintf(element->name, sizeof(element->name), "%d", i) >=
+ sizeof(element->name))
+ goto err;
- if (device->ops.process_mad && is_full_dev) {
- p->pma_table = get_counter_table(device, port_num);
- ret = sysfs_create_group(&p->kobj, p->pma_table);
- if (ret)
- goto err_put_gid_attrs;
- }
+ sysfs_attr_init(&element->attr.attr);
+ element->attr.attr.name = element->name;
+ element->attr.attr.mode = 0444;
+ element->attr.show = show;
+ element->index = i;
- p->gid_group.name = "gids";
- p->gid_group.attrs = alloc_group_attrs(show_port_gid, attr.gid_tbl_len);
- if (!p->gid_group.attrs) {
- ret = -ENOMEM;
- goto err_remove_pma;
+ attr_list[i] = &element->attr.attr;
}
+ group->name = name;
+ group->attrs = attr_list;
+ return 0;
+err:
+ kfree(attr_list);
+ return -EINVAL;
+}
- ret = sysfs_create_group(&p->kobj, &p->gid_group);
- if (ret)
- goto err_free_gid;
+/*
+ * Create the sysfs:
+ * ibp0s9/ports/XX/gid_attrs/{ndevs,types}/YYY
+ * YYY is the gid table index in decimal
+ */
+static int setup_gid_attrs(struct ib_port *port,
+ const struct ib_port_attr *attr)
+{
+ struct gid_attr_group *gid_attr_group;
+ int ret;
- p->gid_attr_group->ndev.name = "ndevs";
- p->gid_attr_group->ndev.attrs = alloc_group_attrs(show_port_gid_attr_ndev,
- attr.gid_tbl_len);
- if (!p->gid_attr_group->ndev.attrs) {
- ret = -ENOMEM;
- goto err_remove_gid;
- }
+ gid_attr_group = kzalloc(struct_size(gid_attr_group, attrs_list,
+ attr->gid_tbl_len * 2),
+ GFP_KERNEL);
+ if (!gid_attr_group)
+ return -ENOMEM;
+ gid_attr_group->port = port;
+ kobject_init(&gid_attr_group->kobj, &gid_attr_type);
- ret = sysfs_create_group(&p->gid_attr_group->kobj,
- &p->gid_attr_group->ndev);
+ ret = alloc_port_table_group("ndevs", &gid_attr_group->groups[0],
+ gid_attr_group->attrs_list,
+ attr->gid_tbl_len,
+ show_port_gid_attr_ndev);
if (ret)
- goto err_free_gid_ndev;
+ goto err_put;
+ gid_attr_group->groups_list[0] = &gid_attr_group->groups[0];
- p->gid_attr_group->type.name = "types";
- p->gid_attr_group->type.attrs = alloc_group_attrs(show_port_gid_attr_gid_type,
- attr.gid_tbl_len);
- if (!p->gid_attr_group->type.attrs) {
- ret = -ENOMEM;
- goto err_remove_gid_ndev;
- }
+ ret = alloc_port_table_group(
+ "types", &gid_attr_group->groups[1],
+ gid_attr_group->attrs_list + attr->gid_tbl_len,
+ attr->gid_tbl_len, show_port_gid_attr_gid_type);
+ if (ret)
+ goto err_put;
+ gid_attr_group->groups_list[1] = &gid_attr_group->groups[1];
- ret = sysfs_create_group(&p->gid_attr_group->kobj,
- &p->gid_attr_group->type);
+ ret = kobject_add(&gid_attr_group->kobj, &port->kobj, "gid_attrs");
+ if (ret)
+ goto err_put;
+ ret = sysfs_create_groups(&gid_attr_group->kobj,
+ gid_attr_group->groups_list);
if (ret)
- goto err_free_gid_type;
+ goto err_del;
+ port->gid_attr_group = gid_attr_group;
+ return 0;
- if (attr.pkey_tbl_len) {
- p->pkey_group = kzalloc(sizeof(*p->pkey_group), GFP_KERNEL);
- if (!p->pkey_group) {
- ret = -ENOMEM;
- goto err_remove_gid_type;
- }
+err_del:
+ kobject_del(&gid_attr_group->kobj);
+err_put:
+ kobject_put(&gid_attr_group->kobj);
+ return ret;
+}
- p->pkey_group->name = "pkeys";
- p->pkey_group->attrs = alloc_group_attrs(show_port_pkey,
- attr.pkey_tbl_len);
- if (!p->pkey_group->attrs) {
- ret = -ENOMEM;
- goto err_free_pkey_group;
- }
+static void destroy_gid_attrs(struct ib_port *port)
+{
+ struct gid_attr_group *gid_attr_group = port->gid_attr_group;
- ret = sysfs_create_group(&p->kobj, p->pkey_group);
- if (ret)
- goto err_free_pkey;
- }
+ if (!gid_attr_group)
+ return;
+ sysfs_remove_groups(&gid_attr_group->kobj, gid_attr_group->groups_list);
+ kobject_del(&gid_attr_group->kobj);
+ kobject_put(&gid_attr_group->kobj);
+}
+
+/*
+ * Create the sysfs:
+ * ibp0s9/ports/XX/{gids,pkeys,counters}/YYY
+ */
+static struct ib_port *setup_port(struct ib_core_device *coredev, int port_num,
+ const struct ib_port_attr *attr)
+{
+ struct ib_device *device = rdma_device_to_ibdev(&coredev->dev);
+ bool is_full_dev = &device->coredev == coredev;
+ const struct attribute_group **cur_group;
+ struct ib_port *p;
+ int ret;
+ p = kzalloc(struct_size(p, attrs_list,
+ attr->gid_tbl_len + attr->pkey_tbl_len),
+ GFP_KERNEL);
+ if (!p)
+ return ERR_PTR(-ENOMEM);
+ p->ibdev = device;
+ p->port_num = port_num;
+ kobject_init(&p->kobj, &port_type);
+
+ cur_group = p->groups_list;
+ ret = alloc_port_table_group("gids", &p->groups[0], p->attrs_list,
+ attr->gid_tbl_len, show_port_gid);
+ if (ret)
+ goto err_put;
+ *cur_group++ = &p->groups[0];
- if (device->ops.init_port && is_full_dev) {
- ret = device->ops.init_port(device, port_num, &p->kobj);
+ if (attr->pkey_tbl_len) {
+ ret = alloc_port_table_group("pkeys", &p->groups[1],
+ p->attrs_list + attr->gid_tbl_len,
+ attr->pkey_tbl_len, show_port_pkey);
if (ret)
- goto err_remove_pkey;
+ goto err_put;
+ *cur_group++ = &p->groups[1];
}
/*
* If port == 0, it means hw_counters are per device and not per
- * port, so holder should be device. Therefore skip per port conunter
- * initialization.
+ * port, so holder should be device. Therefore skip per port
+ * counter initialization.
*/
- if (device->ops.alloc_hw_stats && port_num && is_full_dev)
- setup_hw_stats(device, p, port_num);
-
- list_add_tail(&p->kobj.entry, &coredev->port_list);
-
- kobject_uevent(&p->kobj, KOBJ_ADD);
- return 0;
-
-err_remove_pkey:
- if (p->pkey_group)
- sysfs_remove_group(&p->kobj, p->pkey_group);
-
-err_free_pkey:
- if (p->pkey_group) {
- for (i = 0; i < attr.pkey_tbl_len; ++i)
- kfree(p->pkey_group->attrs[i]);
-
- kfree(p->pkey_group->attrs);
- p->pkey_group->attrs = NULL;
+ if (port_num && is_full_dev) {
+ ret = setup_hw_port_stats(p, &p->groups[2]);
+ if (ret && ret != -EOPNOTSUPP)
+ goto err_put;
+ if (!ret)
+ *cur_group++ = &p->groups[2];
}
-err_free_pkey_group:
- kfree(p->pkey_group);
-
-err_remove_gid_type:
- sysfs_remove_group(&p->gid_attr_group->kobj,
- &p->gid_attr_group->type);
-
-err_free_gid_type:
- for (i = 0; i < attr.gid_tbl_len; ++i)
- kfree(p->gid_attr_group->type.attrs[i]);
-
- kfree(p->gid_attr_group->type.attrs);
- p->gid_attr_group->type.attrs = NULL;
-
-err_remove_gid_ndev:
- sysfs_remove_group(&p->gid_attr_group->kobj,
- &p->gid_attr_group->ndev);
-
-err_free_gid_ndev:
- for (i = 0; i < attr.gid_tbl_len; ++i)
- kfree(p->gid_attr_group->ndev.attrs[i]);
+ if (device->ops.process_mad && is_full_dev)
+ *cur_group++ = get_counter_table(device, port_num);
- kfree(p->gid_attr_group->ndev.attrs);
- p->gid_attr_group->ndev.attrs = NULL;
-
-err_remove_gid:
- sysfs_remove_group(&p->kobj, &p->gid_group);
-
-err_free_gid:
- for (i = 0; i < attr.gid_tbl_len; ++i)
- kfree(p->gid_group.attrs[i]);
-
- kfree(p->gid_group.attrs);
- p->gid_group.attrs = NULL;
+ ret = kobject_add(&p->kobj, coredev->ports_kobj, "%d", port_num);
+ if (ret)
+ goto err_put;
+ ret = sysfs_create_groups(&p->kobj, p->groups_list);
+ if (ret)
+ goto err_del;
+ if (is_full_dev) {
+ ret = sysfs_create_groups(&p->kobj, device->ops.port_groups);
+ if (ret)
+ goto err_groups;
+ }
-err_remove_pma:
- if (p->pma_table)
- sysfs_remove_group(&p->kobj, p->pma_table);
+ list_add_tail(&p->kobj.entry, &coredev->port_list);
+ if (device->port_data && is_full_dev)
+ device->port_data[port_num].sysfs = p;
-err_put_gid_attrs:
- kobject_put(&p->gid_attr_group->kobj);
+ return p;
+err_groups:
+ sysfs_remove_groups(&p->kobj, p->groups_list);
+err_del:
+ kobject_del(&p->kobj);
err_put:
kobject_put(&p->kobj);
- return ret;
+ return ERR_PTR(ret);
+}
+
+static void destroy_port(struct ib_core_device *coredev, struct ib_port *port)
+{
+ bool is_full_dev = &port->ibdev->coredev == coredev;
+
+ if (port->ibdev->port_data &&
+ port->ibdev->port_data[port->port_num].sysfs == port)
+ port->ibdev->port_data[port->port_num].sysfs = NULL;
+ list_del(&port->kobj.entry);
+ if (is_full_dev)
+ sysfs_remove_groups(&port->kobj, port->ibdev->ops.port_groups);
+ sysfs_remove_groups(&port->kobj, port->groups_list);
+ kobject_del(&port->kobj);
+ kobject_put(&port->kobj);
}
static const char *node_type_string(int node_type)
@@ -1259,7 +1298,7 @@ static ssize_t node_type_show(struct device *device,
{
struct ib_device *dev = rdma_device_to_ibdev(device);
- return sysfs_emit(buf, "%d: %s\n", dev->node_type,
+ return sysfs_emit(buf, "%u: %s\n", dev->node_type,
node_type_string(dev->node_type));
}
static DEVICE_ATTR_RO(node_type);
@@ -1347,31 +1386,13 @@ 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) {
struct ib_port *port = container_of(p, struct ib_port, kobj);
- list_del(&p->entry);
- 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);
- if (port->pkey_group)
- sysfs_remove_group(p, port->pkey_group);
- sysfs_remove_group(p, &port->gid_group);
- sysfs_remove_group(&port->gid_attr_group->kobj,
- &port->gid_attr_group->ndev);
- sysfs_remove_group(&port->gid_attr_group->kobj,
- &port->gid_attr_group->type);
- kobject_put(&port->gid_attr_group->kobj);
- kobject_put(p);
+ destroy_gid_attrs(port);
+ destroy_port(coredev, port);
}
kobject_put(coredev->ports_kobj);
@@ -1380,7 +1401,7 @@ void ib_free_port_attrs(struct ib_core_device *coredev)
int ib_setup_port_attrs(struct ib_core_device *coredev)
{
struct ib_device *device = rdma_device_to_ibdev(&coredev->dev);
- u32 port;
+ u32 port_num;
int ret;
coredev->ports_kobj = kobject_create_and_add("ports",
@@ -1388,12 +1409,24 @@ int ib_setup_port_attrs(struct ib_core_device *coredev)
if (!coredev->ports_kobj)
return -ENOMEM;
- rdma_for_each_port (device, port) {
- ret = add_port(coredev, port);
+ rdma_for_each_port (device, port_num) {
+ struct ib_port_attr attr;
+ struct ib_port *port;
+
+ ret = ib_query_port(device, port_num, &attr);
if (ret)
goto err_put;
- }
+ port = setup_port(coredev, port_num, &attr);
+ if (IS_ERR(port)) {
+ ret = PTR_ERR(port);
+ goto err_put;
+ }
+
+ ret = setup_gid_attrs(port, &attr);
+ if (ret)
+ goto err_put;
+ }
return 0;
err_put:
@@ -1401,70 +1434,27 @@ err_put:
return ret;
}
-int ib_device_register_sysfs(struct ib_device *device)
-{
- int ret;
-
- ret = ib_setup_port_attrs(&device->coredev);
- if (ret)
- return ret;
-
- if (device->ops.alloc_hw_stats)
- setup_hw_stats(device, NULL, 0);
-
- return 0;
-}
-
-void ib_device_unregister_sysfs(struct ib_device *device)
-{
- if (device->hw_stats_ag)
- free_hsag(&device->dev.kobj, device->hw_stats_ag);
- kfree(device->hw_stats);
-
- ib_free_port_attrs(&device->coredev);
-}
-
/**
- * ib_port_register_module_stat - add module counters under relevant port
- * of IB device.
+ * ib_port_register_client_groups - Add an ib_client's attributes to the port
*
- * @device: IB device to add counters
+ * @ibdev: IB device to add counters
* @port_num: valid port number
- * @kobj: pointer to the kobject to initialize
- * @ktype: pointer to the ktype for this kobject.
- * @name: the name of the kobject
+ * @groups: Group list of attributes
+ *
+ * Do not use. Only for legacy sysfs compatibility.
*/
-int ib_port_register_module_stat(struct ib_device *device, u32 port_num,
- struct kobject *kobj, struct kobj_type *ktype,
- const char *name)
+int ib_port_register_client_groups(struct ib_device *ibdev, u32 port_num,
+ const struct attribute_group **groups)
{
- struct kobject *p, *t;
- int ret;
-
- list_for_each_entry_safe(p, t, &device->coredev.port_list, entry) {
- struct ib_port *port = container_of(p, struct ib_port, kobj);
-
- if (port->port_num != port_num)
- continue;
-
- ret = kobject_init_and_add(kobj, ktype, &port->kobj, "%s",
- name);
- if (ret) {
- kobject_put(kobj);
- return ret;
- }
- }
-
- return 0;
+ return sysfs_create_groups(&ibdev->port_data[port_num].sysfs->kobj,
+ groups);
}
-EXPORT_SYMBOL(ib_port_register_module_stat);
+EXPORT_SYMBOL(ib_port_register_client_groups);
-/**
- * ib_port_unregister_module_stat - release module counters
- * @kobj: pointer to the kobject to release
- */
-void ib_port_unregister_module_stat(struct kobject *kobj)
+void ib_port_unregister_client_groups(struct ib_device *ibdev, u32 port_num,
+ const struct attribute_group **groups)
{
- kobject_put(kobj);
+ return sysfs_remove_groups(&ibdev->port_data[port_num].sysfs->kobj,
+ groups);
}
-EXPORT_SYMBOL(ib_port_unregister_module_stat);
+EXPORT_SYMBOL(ib_port_unregister_client_groups);
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 15d57ba4d07a..2b72c4fa9550 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -468,8 +468,8 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,
resp.id = ctx->id;
if (copy_to_user(u64_to_user_ptr(cmd.response),
&resp, sizeof(resp))) {
- ucma_destroy_private_ctx(ctx);
- return -EFAULT;
+ ret = -EFAULT;
+ goto err1;
}
mutex_lock(&file->mut);
@@ -1830,13 +1830,12 @@ static struct ib_client rdma_cma_client = {
};
MODULE_ALIAS_RDMA_CLIENT("rdma_cm");
-static ssize_t show_abi_version(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t abi_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
return sysfs_emit(buf, "%d\n", RDMA_USER_CM_ABI_VERSION);
}
-static DEVICE_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
+static DEVICE_ATTR_RO(abi_version);
static int __init ucma_init(void)
{
diff --git a/drivers/infiniband/core/ud_header.c b/drivers/infiniband/core/ud_header.c
index d65d541b9a25..64d9c492de64 100644
--- a/drivers/infiniband/core/ud_header.c
+++ b/drivers/infiniband/core/ud_header.c
@@ -479,7 +479,7 @@ int ib_ud_header_unpack(void *buf,
buf += IB_LRH_BYTES;
if (header->lrh.link_version != 0) {
- pr_warn("Invalid LRH.link_version %d\n",
+ pr_warn("Invalid LRH.link_version %u\n",
header->lrh.link_version);
return -EINVAL;
}
@@ -496,7 +496,7 @@ int ib_ud_header_unpack(void *buf,
buf += IB_GRH_BYTES;
if (header->grh.ip_version != 6) {
- pr_warn("Invalid GRH.ip_version %d\n",
+ pr_warn("Invalid GRH.ip_version %u\n",
header->grh.ip_version);
return -EINVAL;
}
@@ -508,7 +508,7 @@ int ib_ud_header_unpack(void *buf,
break;
default:
- pr_warn("Invalid LRH.link_next_header %d\n",
+ pr_warn("Invalid LRH.link_next_header %u\n",
header->lrh.link_next_header);
return -EINVAL;
}
@@ -530,7 +530,7 @@ int ib_ud_header_unpack(void *buf,
}
if (header->bth.transport_header_version != 0) {
- pr_warn("Invalid BTH.transport_header_version %d\n",
+ pr_warn("Invalid BTH.transport_header_version %u\n",
header->bth.transport_header_version);
return -EINVAL;
}
diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c
index 323f6cf00682..9462dbe66014 100644
--- a/drivers/infiniband/core/umem_odp.c
+++ b/drivers/infiniband/core/umem_odp.c
@@ -445,7 +445,7 @@ retry:
if (hmm_order + PAGE_SHIFT < page_shift) {
ret = -EINVAL;
ibdev_dbg(umem_odp->umem.ibdev,
- "%s: un-expected hmm_order %d, page_shift %d\n",
+ "%s: un-expected hmm_order %u, page_shift %u\n",
__func__, hmm_order, page_shift);
break;
}
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index 852efedda798..98cb594cd9a6 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -700,7 +700,7 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
if (ureq.qpn != 0 && ureq.qpn != 1) {
dev_notice(&file->port->dev,
- "%s: invalid QPN %d specified\n", __func__,
+ "%s: invalid QPN %u specified\n", __func__,
ureq.qpn);
ret = -EINVAL;
goto out;
@@ -800,7 +800,7 @@ static int ib_umad_reg_agent2(struct ib_umad_file *file, void __user *arg)
}
if (ureq.qpn != 0 && ureq.qpn != 1) {
- dev_notice(&file->port->dev, "%s: invalid QPN %d specified\n",
+ dev_notice(&file->port->dev, "%s: invalid QPN %u specified\n",
__func__, ureq.qpn);
ret = -EINVAL;
goto out;
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 53a10479958b..821d93c8f712 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -97,7 +97,7 @@ ib_uverbs_init_udata_buf_or_null(struct ib_udata *udata,
*/
struct ib_uverbs_device {
- atomic_t refcount;
+ refcount_t refcount;
u32 num_comp_vectors;
struct completion comp;
struct device dev;
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 64e4be1cbec7..8c8ca7bce3ca 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -3034,12 +3034,29 @@ static int ib_uverbs_ex_modify_wq(struct uverbs_attr_bundle *attrs)
if (!wq)
return -EINVAL;
- wq_attr.curr_wq_state = cmd.curr_wq_state;
- wq_attr.wq_state = cmd.wq_state;
if (cmd.attr_mask & IB_WQ_FLAGS) {
wq_attr.flags = cmd.flags;
wq_attr.flags_mask = cmd.flags_mask;
}
+
+ if (cmd.attr_mask & IB_WQ_CUR_STATE) {
+ if (cmd.curr_wq_state > IB_WQS_ERR)
+ return -EINVAL;
+
+ wq_attr.curr_wq_state = cmd.curr_wq_state;
+ } else {
+ wq_attr.curr_wq_state = wq->state;
+ }
+
+ if (cmd.attr_mask & IB_WQ_STATE) {
+ if (cmd.wq_state > IB_WQS_ERR)
+ return -EINVAL;
+
+ wq_attr.wq_state = cmd.wq_state;
+ } else {
+ wq_attr.wq_state = wq_attr.curr_wq_state;
+ }
+
ret = wq->device->ops.modify_wq(wq, &wq_attr, cmd.attr_mask,
&attrs->driver_udata);
rdma_lookup_put_uobject(&wq->uobject->uevent.uobject,
@@ -3302,7 +3319,7 @@ static int ib_uverbs_ex_create_flow(struct uverbs_attr_bundle *attrs)
ib_spec += ((union ib_flow_spec *) ib_spec)->size;
}
if (cmd.flow_attr.size || (i != flow_attr->num_of_specs)) {
- pr_warn("create flow failed, flow %d: %d bytes left from uverb cmd\n",
+ pr_warn("create flow failed, flow %d: %u bytes left from uverb cmd\n",
i, cmd.flow_attr.size);
err = -EINVAL;
goto err_free;
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index f173ecd102dc..d54434088727 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -197,7 +197,7 @@ void ib_uverbs_release_file(struct kref *ref)
module_put(ib_dev->ops.owner);
srcu_read_unlock(&file->device->disassociate_srcu, srcu_key);
- if (atomic_dec_and_test(&file->device->refcount))
+ if (refcount_dec_and_test(&file->device->refcount))
ib_uverbs_comp_dev(file->device);
if (file->default_async_file)
@@ -891,7 +891,7 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
int srcu_key;
dev = container_of(inode->i_cdev, struct ib_uverbs_device, cdev);
- if (!atomic_inc_not_zero(&dev->refcount))
+ if (!refcount_inc_not_zero(&dev->refcount))
return -ENXIO;
get_device(&dev->dev);
@@ -955,7 +955,7 @@ err_module:
err:
mutex_unlock(&dev->lists_mutex);
srcu_read_unlock(&dev->disassociate_srcu, srcu_key);
- if (atomic_dec_and_test(&dev->refcount))
+ if (refcount_dec_and_test(&dev->refcount))
ib_uverbs_comp_dev(dev);
put_device(&dev->dev);
@@ -1124,7 +1124,7 @@ static int ib_uverbs_add_one(struct ib_device *device)
uverbs_dev->dev.release = ib_uverbs_release_dev;
uverbs_dev->groups[0] = &dev_attr_group;
uverbs_dev->dev.groups = uverbs_dev->groups;
- atomic_set(&uverbs_dev->refcount, 1);
+ refcount_set(&uverbs_dev->refcount, 1);
init_completion(&uverbs_dev->comp);
uverbs_dev->xrcd_tree = RB_ROOT;
mutex_init(&uverbs_dev->xrcd_tree_mutex);
@@ -1166,7 +1166,7 @@ static int ib_uverbs_add_one(struct ib_device *device)
err_uapi:
ida_free(&uverbs_ida, devnum);
err:
- if (atomic_dec_and_test(&uverbs_dev->refcount))
+ if (refcount_dec_and_test(&uverbs_dev->refcount))
ib_uverbs_comp_dev(uverbs_dev);
wait_for_completion(&uverbs_dev->comp);
put_device(&uverbs_dev->dev);
@@ -1229,7 +1229,7 @@ static void ib_uverbs_remove_one(struct ib_device *device, void *client_data)
wait_clients = 0;
}
- if (atomic_dec_and_test(&uverbs_dev->refcount))
+ if (refcount_dec_and_test(&uverbs_dev->refcount))
ib_uverbs_comp_dev(uverbs_dev);
if (wait_clients)
wait_for_completion(&uverbs_dev->comp);
diff --git a/drivers/infiniband/core/uverbs_uapi.c b/drivers/infiniband/core/uverbs_uapi.c
index 62f5bcb712cf..2f2c7646fce1 100644
--- a/drivers/infiniband/core/uverbs_uapi.c
+++ b/drivers/infiniband/core/uverbs_uapi.c
@@ -517,7 +517,7 @@ static void uapi_key_okay(u32 key)
count++;
if (uapi_key_is_attr(key))
count++;
- WARN(count != 1, "Bad count %d key=%x", count, key);
+ WARN(count != 1, "Bad count %u key=%x", count, key);
}
static void uapi_finalize_disable(struct uverbs_api *uapi)
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 2b0798151fb7..7036967e4c0b 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -1834,7 +1834,7 @@ int ib_get_eth_speed(struct ib_device *dev, u32 port_num, u16 *speed, u8 *width)
netdev_speed = lksettings.base.speed;
} else {
netdev_speed = SPEED_1000;
- pr_warn("%s speed is unknown, defaulting to %d\n", netdev->name,
+ pr_warn("%s speed is unknown, defaulting to %u\n", netdev->name,
netdev_speed);
}
@@ -2445,27 +2445,6 @@ int ib_destroy_wq_user(struct ib_wq *wq, struct ib_udata *udata)
}
EXPORT_SYMBOL(ib_destroy_wq_user);
-/**
- * ib_modify_wq - Modifies the specified WQ.
- * @wq: The WQ to modify.
- * @wq_attr: On input, specifies the WQ attributes to modify.
- * @wq_attr_mask: A bit-mask used to specify which attributes of the WQ
- * are being modified.
- * On output, the current values of selected WQ attributes are returned.
- */
-int ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr,
- u32 wq_attr_mask)
-{
- int err;
-
- if (!wq->device->ops.modify_wq)
- return -EOPNOTSUPP;
-
- err = wq->device->ops.modify_wq(wq, wq_attr, wq_attr_mask, NULL);
- return err;
-}
-EXPORT_SYMBOL(ib_modify_wq);
-
int ib_check_mr_status(struct ib_mr *mr, u32 check_mask,
struct ib_mr_status *mr_status)
{
diff --git a/drivers/infiniband/hw/Makefile b/drivers/infiniband/hw/Makefile
index 0aeccd984889..fba0b3be903e 100644
--- a/drivers/infiniband/hw/Makefile
+++ b/drivers/infiniband/hw/Makefile
@@ -3,7 +3,7 @@ obj-$(CONFIG_INFINIBAND_MTHCA) += mthca/
obj-$(CONFIG_INFINIBAND_QIB) += qib/
obj-$(CONFIG_INFINIBAND_CXGB4) += cxgb4/
obj-$(CONFIG_INFINIBAND_EFA) += efa/
-obj-$(CONFIG_INFINIBAND_I40IW) += i40iw/
+obj-$(CONFIG_INFINIBAND_IRDMA) += irdma/
obj-$(CONFIG_MLX4_INFINIBAND) += mlx4/
obj-$(CONFIG_MLX5_INFINIBAND) += mlx5/
obj-$(CONFIG_INFINIBAND_OCRDMA) += ocrdma/
diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.c b/drivers/infiniband/hw/bnxt_re/hw_counters.c
index 3e54e1ae75b4..7ba07797845c 100644
--- a/drivers/infiniband/hw/bnxt_re/hw_counters.c
+++ b/drivers/infiniband/hw/bnxt_re/hw_counters.c
@@ -234,13 +234,10 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev,
return ARRAY_SIZE(bnxt_re_stat_name);
}
-struct rdma_hw_stats *bnxt_re_ib_alloc_hw_stats(struct ib_device *ibdev,
- u32 port_num)
+struct rdma_hw_stats *bnxt_re_ib_alloc_hw_port_stats(struct ib_device *ibdev,
+ u32 port_num)
{
BUILD_BUG_ON(ARRAY_SIZE(bnxt_re_stat_name) != BNXT_RE_NUM_COUNTERS);
- /* We support only per port stats */
- if (!port_num)
- return NULL;
return rdma_alloc_hw_stats_struct(bnxt_re_stat_name,
ARRAY_SIZE(bnxt_re_stat_name),
diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.h b/drivers/infiniband/hw/bnxt_re/hw_counters.h
index ede048607d6c..6f2d2f91d9ff 100644
--- a/drivers/infiniband/hw/bnxt_re/hw_counters.h
+++ b/drivers/infiniband/hw/bnxt_re/hw_counters.h
@@ -96,8 +96,8 @@ enum bnxt_re_hw_stats {
BNXT_RE_NUM_COUNTERS
};
-struct rdma_hw_stats *bnxt_re_ib_alloc_hw_stats(struct ib_device *ibdev,
- u32 port_num);
+struct rdma_hw_stats *bnxt_re_ib_alloc_hw_port_stats(struct ib_device *ibdev,
+ u32 port_num);
int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev,
struct rdma_hw_stats *stats,
u32 port, int index);
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 2efaa80bfbd2..283b6b81563c 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -163,6 +163,10 @@ int bnxt_re_query_device(struct ib_device *ibdev,
ib_attr->max_qp_init_rd_atom = dev_attr->max_qp_init_rd_atom;
ib_attr->atomic_cap = IB_ATOMIC_NONE;
ib_attr->masked_atomic_cap = IB_ATOMIC_NONE;
+ if (dev_attr->is_atomic) {
+ ib_attr->atomic_cap = IB_ATOMIC_GLOB;
+ ib_attr->masked_atomic_cap = IB_ATOMIC_GLOB;
+ }
ib_attr->max_ee_rd_atom = 0;
ib_attr->max_res_rd_atom = 0;
@@ -1098,10 +1102,6 @@ static int bnxt_re_init_rq_attr(struct bnxt_re_qp *qp,
struct bnxt_re_srq *srq;
srq = container_of(init_attr->srq, struct bnxt_re_srq, ib_srq);
- if (!srq) {
- ibdev_err(&rdev->ibdev, "SRQ not found");
- return -EINVAL;
- }
qplqp->srq = &srq->qplib_srq;
rq->max_wqe = 0;
} else {
@@ -1279,22 +1279,12 @@ static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd,
/* Setup CQs */
if (init_attr->send_cq) {
cq = container_of(init_attr->send_cq, struct bnxt_re_cq, ib_cq);
- if (!cq) {
- ibdev_err(&rdev->ibdev, "Send CQ not found");
- rc = -EINVAL;
- goto out;
- }
qplqp->scq = &cq->qplib_cq;
qp->scq = cq;
}
if (init_attr->recv_cq) {
cq = container_of(init_attr->recv_cq, struct bnxt_re_cq, ib_cq);
- if (!cq) {
- ibdev_err(&rdev->ibdev, "Receive CQ not found");
- rc = -EINVAL;
- goto out;
- }
qplqp->rcq = &cq->qplib_cq;
qp->rcq = cq;
}
@@ -3473,10 +3463,6 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc)
((struct bnxt_qplib_qp *)
(unsigned long)(cqe->qp_handle),
struct bnxt_re_qp, qplib_qp);
- if (!qp) {
- ibdev_err(&cq->rdev->ibdev, "POLL CQ : bad QP handle");
- continue;
- }
wc->qp = &qp->ib_qp;
wc->ex.imm_data = cqe->immdata;
wc->src_qp = cqe->src_qp;
@@ -3858,7 +3844,7 @@ int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata)
container_of(ctx, struct bnxt_re_ucontext, ib_uctx);
struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev);
struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr;
- struct bnxt_re_uctx_resp resp;
+ struct bnxt_re_uctx_resp resp = {};
u32 chip_met_rev_num = 0;
int rc;
@@ -3886,15 +3872,15 @@ int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata)
chip_met_rev_num |= ((u32)rdev->chip_ctx->chip_metal & 0xFF) <<
BNXT_RE_CHIP_ID0_CHIP_MET_SFT;
resp.chip_id0 = chip_met_rev_num;
- /* Future extension of chip info */
- resp.chip_id1 = 0;
/*Temp, Use xa_alloc instead */
resp.dev_id = rdev->en_dev->pdev->devfn;
resp.max_qp = rdev->qplib_ctx.qpc_count;
resp.pg_size = PAGE_SIZE;
resp.cqe_sz = sizeof(struct cq_base);
resp.max_cqd = dev_attr->max_cq_wqes;
- resp.rsvd = 0;
+
+ resp.comp_mask |= BNXT_RE_UCNTX_CMASK_HAVE_MODE;
+ resp.mode = rdev->chip_ctx->modes.wqe_mode;
rc = ib_copy_to_udata(udata, &resp, min(udata->outlen, sizeof(resp)));
if (rc) {
diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c
index 8bfbf0231a9e..d5674026512a 100644
--- a/drivers/infiniband/hw/bnxt_re/main.c
+++ b/drivers/infiniband/hw/bnxt_re/main.c
@@ -128,6 +128,9 @@ static int bnxt_re_setup_chip_ctx(struct bnxt_re_dev *rdev, u8 wqe_mode)
rdev->rcfw.res = &rdev->qplib_res;
bnxt_re_set_drv_mode(rdev, wqe_mode);
+ if (bnxt_qplib_determine_atomics(en_dev->pdev))
+ ibdev_info(&rdev->ibdev,
+ "platform doesn't support global atomics.");
return 0;
}
@@ -662,7 +665,7 @@ static const struct ib_device_ops bnxt_re_dev_ops = {
.uverbs_abi_ver = BNXT_RE_ABI_VERSION,
.add_gid = bnxt_re_add_gid,
- .alloc_hw_stats = bnxt_re_ib_alloc_hw_stats,
+ .alloc_hw_port_stats = bnxt_re_ib_alloc_hw_port_stats,
.alloc_mr = bnxt_re_alloc_mr,
.alloc_pd = bnxt_re_alloc_pd,
.alloc_ucontext = bnxt_re_alloc_ucontext,
@@ -680,6 +683,7 @@ static const struct ib_device_ops bnxt_re_dev_ops = {
.destroy_cq = bnxt_re_destroy_cq,
.destroy_qp = bnxt_re_destroy_qp,
.destroy_srq = bnxt_re_destroy_srq,
+ .device_group = &bnxt_re_dev_attr_group,
.get_dev_fw_str = bnxt_re_query_fw_str,
.get_dma_mr = bnxt_re_get_dma_mr,
.get_hw_stats = bnxt_re_ib_get_hw_stats,
@@ -726,7 +730,6 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev)
ibdev->dev.parent = &rdev->en_dev->pdev->dev;
ibdev->local_dma_lkey = BNXT_QPLIB_RSVD_LKEY;
- rdma_set_device_sysfs_group(ibdev, &bnxt_re_dev_attr_group);
ib_set_device_ops(ibdev, &bnxt_re_dev_ops);
ret = ib_device_set_netdev(&rdev->ibdev, rdev->netdev, 1);
if (ret)
@@ -885,12 +888,6 @@ static int bnxt_re_srqn_handler(struct bnxt_qplib_nq *nq,
struct ib_event ib_event;
int rc = 0;
- if (!srq) {
- ibdev_err(NULL, "%s: SRQ is NULL, SRQN not handled",
- ROCE_DRV_MODULE_NAME);
- rc = -EINVAL;
- goto done;
- }
ib_event.device = &srq->rdev->ibdev;
ib_event.element.srq = &srq->ib_srq;
if (event == NQ_SRQ_EVENT_EVENT_SRQ_THRESHOLD_EVENT)
@@ -903,7 +900,6 @@ static int bnxt_re_srqn_handler(struct bnxt_qplib_nq *nq,
(*srq->ib_srq.event_handler)(&ib_event,
srq->ib_srq.srq_context);
}
-done:
return rc;
}
@@ -913,11 +909,6 @@ static int bnxt_re_cqn_handler(struct bnxt_qplib_nq *nq,
struct bnxt_re_cq *cq = container_of(handle, struct bnxt_re_cq,
qplib_cq);
- if (!cq) {
- ibdev_err(NULL, "%s: CQ is NULL, CQN not handled",
- ROCE_DRV_MODULE_NAME);
- return -EINVAL;
- }
if (cq->ib_cq.comp_handler) {
/* Lock comp_handler? */
(*cq->ib_cq.comp_handler)(&cq->ib_cq, cq->ib_cq.cq_context);
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h
index f50784405e27..037501952543 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h
@@ -39,6 +39,8 @@
#ifndef __BNXT_QPLIB_FP_H__
#define __BNXT_QPLIB_FP_H__
+#include <rdma/bnxt_re-abi.h>
+
/* Few helper structures temporarily defined here
* should get rid of these when roce_hsi.h is updated
* in original code base
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c
index 3ca47004b752..17f0701b3cee 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_res.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c
@@ -959,3 +959,20 @@ fail:
bnxt_qplib_free_res(res);
return rc;
}
+
+int bnxt_qplib_determine_atomics(struct pci_dev *dev)
+{
+ int comp;
+ u16 ctl2;
+
+ comp = pci_enable_atomic_ops_to_root(dev,
+ PCI_EXP_DEVCAP2_ATOMIC_COMP32);
+ if (comp)
+ return -EOPNOTSUPP;
+ comp = pci_enable_atomic_ops_to_root(dev,
+ PCI_EXP_DEVCAP2_ATOMIC_COMP64);
+ if (comp)
+ return -EOPNOTSUPP;
+ pcie_capability_read_word(dev, PCI_EXP_DEVCTL2, &ctl2);
+ return !(ctl2 & PCI_EXP_DEVCTL2_ATOMIC_REQ);
+}
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.h b/drivers/infiniband/hw/bnxt_re/qplib_res.h
index 7a1ab38b95da..c291f495ae91 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_res.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_res.h
@@ -45,12 +45,6 @@ extern const struct bnxt_qplib_gid bnxt_qplib_gid_zero;
#define CHIP_NUM_57504 0x1751
#define CHIP_NUM_57502 0x1752
-enum bnxt_qplib_wqe_mode {
- BNXT_QPLIB_WQE_MODE_STATIC = 0x00,
- BNXT_QPLIB_WQE_MODE_VARIABLE = 0x01,
- BNXT_QPLIB_WQE_MODE_INVALID = 0x02
-};
-
struct bnxt_qplib_drv_modes {
u8 wqe_mode;
/* Other modes to follow here */
@@ -373,6 +367,7 @@ void bnxt_qplib_free_ctx(struct bnxt_qplib_res *res,
int bnxt_qplib_alloc_ctx(struct bnxt_qplib_res *res,
struct bnxt_qplib_ctx *ctx,
bool virt_fn, bool is_p5);
+int bnxt_qplib_determine_atomics(struct pci_dev *dev);
static inline void bnxt_qplib_hwq_incr_prod(struct bnxt_qplib_hwq *hwq, u32 cnt)
{
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c
index 049b3576302b..3d9259632eb3 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c
@@ -54,6 +54,17 @@ const struct bnxt_qplib_gid bnxt_qplib_gid_zero = {{ 0, 0, 0, 0, 0, 0, 0, 0,
/* Device */
+static bool bnxt_qplib_is_atomic_cap(struct bnxt_qplib_rcfw *rcfw)
+{
+ u16 pcie_ctl2 = 0;
+
+ if (!bnxt_qplib_is_chip_gen_p5(rcfw->res->cctx))
+ return false;
+
+ pcie_capability_read_word(rcfw->pdev, PCI_EXP_DEVCTL2, &pcie_ctl2);
+ return (pcie_ctl2 & PCI_EXP_DEVCTL2_ATOMIC_REQ);
+}
+
static void bnxt_qplib_query_version(struct bnxt_qplib_rcfw *rcfw,
char *fw_ver)
{
@@ -162,7 +173,7 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
attr->tqm_alloc_reqs[i * 4 + 3] = *(++tqm_alloc);
}
- attr->is_atomic = false;
+ attr->is_atomic = bnxt_qplib_is_atomic_cap(rcfw);
bail:
bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf);
return rc;
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.h b/drivers/infiniband/hw/bnxt_re/qplib_sp.h
index bc228340684f..260104783691 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_sp.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.h
@@ -42,8 +42,6 @@
#define BNXT_QPLIB_RESERVED_QP_WRS 128
-#define PCI_EXP_DEVCTL2_ATOMIC_REQ 0x0040
-
struct bnxt_qplib_dev_attr {
#define FW_VER_ARR_LEN 4
u8 fw_ver[FW_VER_ARR_LEN];
diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
index 44c2416588d4..6c8c910f4e86 100644
--- a/drivers/infiniband/hw/cxgb4/cq.c
+++ b/drivers/infiniband/hw/cxgb4/cq.c
@@ -976,8 +976,8 @@ int c4iw_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
chp = to_c4iw_cq(ib_cq);
xa_erase_irq(&chp->rhp->cqs, chp->cq.cqid);
- atomic_dec(&chp->refcnt);
- wait_event(chp->wait, !atomic_read(&chp->refcnt));
+ refcount_dec(&chp->refcnt);
+ wait_event(chp->wait, !refcount_read(&chp->refcnt));
ucontext = rdma_udata_to_drv_context(udata, struct c4iw_ucontext,
ibucontext);
@@ -1080,7 +1080,7 @@ int c4iw_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
chp->ibcq.cqe = entries - 2;
spin_lock_init(&chp->lock);
spin_lock_init(&chp->comp_handler_lock);
- atomic_set(&chp->refcnt, 1);
+ refcount_set(&chp->refcnt, 1);
init_waitqueue_head(&chp->wait);
ret = xa_insert_irq(&rhp->cqs, chp->cq.cqid, chp, GFP_KERNEL);
if (ret)
diff --git a/drivers/infiniband/hw/cxgb4/ev.c b/drivers/infiniband/hw/cxgb4/ev.c
index 4cd877bd2f56..7798d090888b 100644
--- a/drivers/infiniband/hw/cxgb4/ev.c
+++ b/drivers/infiniband/hw/cxgb4/ev.c
@@ -151,7 +151,7 @@ void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
}
c4iw_qp_add_ref(&qhp->ibqp);
- atomic_inc(&chp->refcnt);
+ refcount_inc(&chp->refcnt);
xa_unlock_irq(&dev->qps);
/* Bad incoming write */
@@ -213,7 +213,7 @@ void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
break;
}
done:
- if (atomic_dec_and_test(&chp->refcnt))
+ if (refcount_dec_and_test(&chp->refcnt))
wake_up(&chp->wait);
c4iw_qp_rem_ref(&qhp->ibqp);
out:
@@ -228,13 +228,13 @@ int c4iw_ev_handler(struct c4iw_dev *dev, u32 qid)
xa_lock_irqsave(&dev->cqs, flag);
chp = xa_load(&dev->cqs, qid);
if (chp) {
- atomic_inc(&chp->refcnt);
+ refcount_inc(&chp->refcnt);
xa_unlock_irqrestore(&dev->cqs, flag);
t4_clear_cq_armed(&chp->cq);
spin_lock_irqsave(&chp->comp_handler_lock, flag);
(*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
- if (atomic_dec_and_test(&chp->refcnt))
+ if (refcount_dec_and_test(&chp->refcnt))
wake_up(&chp->wait);
} else {
pr_debug("unknown cqid 0x%x\n", qid);
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index cdec5deb37a1..3883af3d2312 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -427,7 +427,7 @@ struct c4iw_cq {
struct t4_cq cq;
spinlock_t lock;
spinlock_t comp_handler_lock;
- atomic_t refcnt;
+ refcount_t refcnt;
wait_queue_head_t wait;
struct c4iw_wr_wait *wr_waitp;
};
diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
index 3f1893e180dd..881d515eb15a 100644
--- a/drivers/infiniband/hw/cxgb4/provider.c
+++ b/drivers/infiniband/hw/cxgb4/provider.c
@@ -377,14 +377,11 @@ static const char * const names[] = {
[IP6OUTRSTS] = "ip6OutRsts"
};
-static struct rdma_hw_stats *c4iw_alloc_stats(struct ib_device *ibdev,
- u32 port_num)
+static struct rdma_hw_stats *c4iw_alloc_device_stats(struct ib_device *ibdev)
{
BUILD_BUG_ON(ARRAY_SIZE(names) != NR_COUNTERS);
- if (port_num != 0)
- return NULL;
-
+ /* FIXME: these look like port stats */
return rdma_alloc_hw_stats_struct(names, NR_COUNTERS,
RDMA_HW_STATS_DEFAULT_LIFESPAN);
}
@@ -455,7 +452,7 @@ static const struct ib_device_ops c4iw_dev_ops = {
.driver_id = RDMA_DRIVER_CXGB4,
.uverbs_abi_ver = C4IW_UVERBS_ABI_VERSION,
- .alloc_hw_stats = c4iw_alloc_stats,
+ .alloc_hw_device_stats = c4iw_alloc_device_stats,
.alloc_mr = c4iw_alloc_mr,
.alloc_pd = c4iw_allocate_pd,
.alloc_ucontext = c4iw_alloc_ucontext,
@@ -468,6 +465,7 @@ static const struct ib_device_ops c4iw_dev_ops = {
.destroy_cq = c4iw_destroy_cq,
.destroy_qp = c4iw_destroy_qp,
.destroy_srq = c4iw_destroy_srq,
+ .device_group = &c4iw_attr_group,
.fill_res_cq_entry = c4iw_fill_res_cq_entry,
.fill_res_cm_id_entry = c4iw_fill_res_cm_id_entry,
.fill_res_mr_entry = c4iw_fill_res_mr_entry,
@@ -542,7 +540,6 @@ void c4iw_register_device(struct work_struct *work)
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);
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 d109bb3822a5..a81fa7a56edb 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -295,6 +295,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
if (user && (!wq->sq.bar2_pa || (need_rq && !wq->rq.bar2_pa))) {
pr_warn("%s: sqid %u or rqid %u not in BAR2 range\n",
pci_name(rdev->lldi.pdev), wq->sq.qid, wq->rq.qid);
+ ret = -EINVAL;
goto free_dma;
}
@@ -1963,7 +1964,6 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
t4_set_wq_in_error(&qhp->wq, 0);
set_state(qhp, C4IW_QP_STATE_ERROR);
if (!internal) {
- abort = 1;
disconnect = 1;
ep = qhp->ep;
c4iw_get_ep(&qhp->ep->com);
diff --git a/drivers/infiniband/hw/efa/efa.h b/drivers/infiniband/hw/efa/efa.h
index ea322cec27d2..2b8ca099b381 100644
--- a/drivers/infiniband/hw/efa/efa.h
+++ b/drivers/infiniband/hw/efa/efa.h
@@ -157,7 +157,8 @@ int efa_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
int qp_attr_mask, struct ib_udata *udata);
enum rdma_link_layer efa_port_link_layer(struct ib_device *ibdev,
u32 port_num);
-struct rdma_hw_stats *efa_alloc_hw_stats(struct ib_device *ibdev, u32 port_num);
+struct rdma_hw_stats *efa_alloc_hw_port_stats(struct ib_device *ibdev, u32 port_num);
+struct rdma_hw_stats *efa_alloc_hw_device_stats(struct ib_device *ibdev);
int efa_get_hw_stats(struct ib_device *ibdev, struct rdma_hw_stats *stats,
u32 port_num, int index);
diff --git a/drivers/infiniband/hw/efa/efa_main.c b/drivers/infiniband/hw/efa/efa_main.c
index 816cfd65b7ac..203e6ddcacbc 100644
--- a/drivers/infiniband/hw/efa/efa_main.c
+++ b/drivers/infiniband/hw/efa/efa_main.c
@@ -242,7 +242,8 @@ static const struct ib_device_ops efa_dev_ops = {
.driver_id = RDMA_DRIVER_EFA,
.uverbs_abi_ver = EFA_UVERBS_ABI_VERSION,
- .alloc_hw_stats = efa_alloc_hw_stats,
+ .alloc_hw_port_stats = efa_alloc_hw_port_stats,
+ .alloc_hw_device_stats = efa_alloc_hw_device_stats,
.alloc_pd = efa_alloc_pd,
.alloc_ucontext = efa_alloc_ucontext,
.create_cq = efa_create_cq,
diff --git a/drivers/infiniband/hw/efa/efa_verbs.c b/drivers/infiniband/hw/efa/efa_verbs.c
index 51572f1dc611..be6d3ff0f1be 100644
--- a/drivers/infiniband/hw/efa/efa_verbs.c
+++ b/drivers/infiniband/hw/efa/efa_verbs.c
@@ -1904,13 +1904,22 @@ int efa_destroy_ah(struct ib_ah *ibah, u32 flags)
return 0;
}
-struct rdma_hw_stats *efa_alloc_hw_stats(struct ib_device *ibdev, u32 port_num)
+struct rdma_hw_stats *efa_alloc_hw_port_stats(struct ib_device *ibdev, u32 port_num)
{
return rdma_alloc_hw_stats_struct(efa_stats_names,
ARRAY_SIZE(efa_stats_names),
RDMA_HW_STATS_DEFAULT_LIFESPAN);
}
+struct rdma_hw_stats *efa_alloc_hw_device_stats(struct ib_device *ibdev)
+{
+ /*
+ * It is probably a bug that efa reports its port stats as device
+ * stats
+ */
+ return efa_alloc_hw_port_stats(ibdev, 0);
+}
+
int efa_get_hw_stats(struct ib_device *ibdev, struct rdma_hw_stats *stats,
u32 port_num, int index)
{
diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c
index 5eeae8df415b..c97544638367 100644
--- a/drivers/infiniband/hw/hfi1/chip.c
+++ b/drivers/infiniband/hw/hfi1/chip.c
@@ -14186,7 +14186,7 @@ static void init_kdeth_qp(struct hfi1_devdata *dd)
}
/**
- * hfi1_get_qp_map
+ * hfi1_get_qp_map - get qp map
* @dd: device data
* @idx: index to read
*/
@@ -14199,7 +14199,7 @@ u8 hfi1_get_qp_map(struct hfi1_devdata *dd, u8 idx)
}
/**
- * init_qpmap_table
+ * init_qpmap_table - init qp map
* @dd: device data
* @first_ctxt: first context
* @last_ctxt: first context
diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c
index 3b7bbc7b9d10..955c3637980e 100644
--- a/drivers/infiniband/hw/hfi1/file_ops.c
+++ b/drivers/infiniband/hw/hfi1/file_ops.c
@@ -736,7 +736,7 @@ static u64 kvirt_to_phys(void *addr)
}
/**
- * complete_subctxt
+ * complete_subctxt - complete sub-context info
* @fd: valid filedata pointer
*
* Sub-context info can only be set up after the base context
@@ -841,7 +841,7 @@ static int assign_ctxt(struct hfi1_filedata *fd, unsigned long arg, u32 len)
}
/**
- * match_ctxt
+ * match_ctxt - match context
* @fd: valid filedata pointer
* @uinfo: user info to compare base context with
* @uctxt: context to compare uinfo to.
@@ -898,7 +898,7 @@ static int match_ctxt(struct hfi1_filedata *fd,
}
/**
- * find_sub_ctxt
+ * find_sub_ctxt - fund sub-context
* @fd: valid filedata pointer
* @uinfo: matching info to use to find a possible context to share.
*
diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h
index 867ae0b1aa95..31664f43c27f 100644
--- a/drivers/infiniband/hw/hfi1/hfi.h
+++ b/drivers/infiniband/hw/hfi1/hfi.h
@@ -772,10 +772,6 @@ struct hfi1_pportdata {
struct hfi1_ibport ibport_data;
struct hfi1_devdata *dd;
- struct kobject pport_cc_kobj;
- struct kobject sc2vl_kobj;
- struct kobject sl2sc_kobj;
- struct kobject vl2mtu_kobj;
/* PHY support */
struct qsfp_data qsfp_info;
@@ -1764,7 +1760,7 @@ static inline void pause_for_credit_return(struct hfi1_devdata *dd)
}
/**
- * sc_to_vlt() reverse lookup sc to vl
+ * sc_to_vlt() - reverse lookup sc to vl
* @dd - devdata
* @sc5 - 5 bit sc
*/
@@ -2188,12 +2184,11 @@ static inline bool hfi1_packet_present(struct hfi1_ctxtdata *rcd)
extern const char ib_hfi1_version[];
extern const struct attribute_group ib_hfi1_attr_group;
+extern const struct attribute_group *hfi1_attr_port_groups[];
int hfi1_device_create(struct hfi1_devdata *dd);
void hfi1_device_remove(struct hfi1_devdata *dd);
-int hfi1_create_port_files(struct ib_device *ibdev, u32 port_num,
- struct kobject *kobj);
int hfi1_verbs_register_sysfs(struct hfi1_devdata *dd);
void hfi1_verbs_unregister_sysfs(struct hfi1_devdata *dd);
/* Hook for sysfs read of QSFP */
diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c
index e3a8a420c045..0986aa065418 100644
--- a/drivers/infiniband/hw/hfi1/init.c
+++ b/drivers/infiniband/hw/hfi1/init.c
@@ -312,7 +312,7 @@ struct hfi1_ctxtdata *hfi1_rcd_get_by_index_safe(struct hfi1_devdata *dd,
}
/**
- * hfi1_rcd_get_by_index
+ * hfi1_rcd_get_by_index - get by index
* @dd: pointer to a valid devdata structure
* @ctxt: the index of an possilbe rcd
*
@@ -499,7 +499,7 @@ bail:
}
/**
- * hfi1_free_ctxt
+ * hfi1_free_ctxt - free context
* @rcd: pointer to an initialized rcd data structure
*
* This wrapper is the free function that matches hfi1_create_ctxtdata().
diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c
index ff864f6f0266..e276522104c6 100644
--- a/drivers/infiniband/hw/hfi1/pio.c
+++ b/drivers/infiniband/hw/hfi1/pio.c
@@ -993,7 +993,7 @@ static bool is_sc_halted(struct hfi1_devdata *dd, u32 hw_context)
}
/**
- * sc_wait_for_packet_egress
+ * sc_wait_for_packet_egress - wait for packet
* @sc: valid send context
* @pause: wait for credit return
*
diff --git a/drivers/infiniband/hw/hfi1/pio.h b/drivers/infiniband/hw/hfi1/pio.h
index 0102262343c0..9e5f08d2b985 100644
--- a/drivers/infiniband/hw/hfi1/pio.h
+++ b/drivers/infiniband/hw/hfi1/pio.h
@@ -279,7 +279,6 @@ int init_credit_return(struct hfi1_devdata *dd);
void free_credit_return(struct hfi1_devdata *dd);
int init_sc_pools_and_sizes(struct hfi1_devdata *dd);
int init_send_contexts(struct hfi1_devdata *dd);
-int init_credit_return(struct hfi1_devdata *dd);
int init_pervl_scs(struct hfi1_devdata *dd);
struct send_context *sc_alloc(struct hfi1_devdata *dd, int type,
uint hdrqentsize, int numa);
@@ -294,7 +293,6 @@ void sc_stop(struct send_context *sc, int bit);
struct pio_buf *sc_buffer_alloc(struct send_context *sc, u32 dw_len,
pio_release_cb cb, void *arg);
void sc_release_update(struct send_context *sc);
-void sc_return_credits(struct send_context *sc);
void sc_group_release_update(struct hfi1_devdata *dd, u32 hw_context);
void sc_add_credit_return_intr(struct send_context *sc);
void sc_del_credit_return_intr(struct send_context *sc);
diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c
index 1fcc6e9666e0..eb15c310d63d 100644
--- a/drivers/infiniband/hw/hfi1/sdma.c
+++ b/drivers/infiniband/hw/hfi1/sdma.c
@@ -3130,7 +3130,7 @@ int ext_coal_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx,
}
if (type == SDMA_MAP_PAGE) {
- kvaddr = kmap(page);
+ kvaddr = kmap_local_page(page);
kvaddr += offset;
} else if (WARN_ON(!kvaddr)) {
__sdma_txclean(dd, tx);
@@ -3140,7 +3140,7 @@ int ext_coal_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx,
memcpy(tx->coalesce_buf + tx->coalesce_idx, kvaddr, len);
tx->coalesce_idx += len;
if (type == SDMA_MAP_PAGE)
- kunmap(page);
+ kunmap_local(kvaddr);
/* If there is more data, return */
if (tx->tlen - tx->coalesce_idx)
diff --git a/drivers/infiniband/hw/hfi1/sysfs.c b/drivers/infiniband/hw/hfi1/sysfs.c
index eaf441ece25e..acfcbedebe0d 100644
--- a/drivers/infiniband/hw/hfi1/sysfs.c
+++ b/drivers/infiniband/hw/hfi1/sysfs.c
@@ -45,11 +45,21 @@
*
*/
#include <linux/ctype.h>
+#include <rdma/ib_sysfs.h>
#include "hfi.h"
#include "mad.h"
#include "trace.h"
+static struct hfi1_pportdata *hfi1_get_pportdata_kobj(struct kobject *kobj)
+{
+ u32 port_num;
+ struct ib_device *ibdev = ib_port_sysfs_get_ibdev_kobj(kobj, &port_num);
+ struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
+
+ return &dd->pport[port_num - 1];
+}
+
/*
* Start of per-port congestion control structures and support code
*/
@@ -57,13 +67,12 @@
/*
* Congestion control table size followed by table entries
*/
-static ssize_t read_cc_table_bin(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t pos, size_t count)
+static ssize_t cc_table_bin_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t pos, size_t count)
{
int ret;
- struct hfi1_pportdata *ppd =
- container_of(kobj, struct hfi1_pportdata, pport_cc_kobj);
+ struct hfi1_pportdata *ppd = hfi1_get_pportdata_kobj(kobj);
struct cc_state *cc_state;
ret = ppd->total_cct_entry * sizeof(struct ib_cc_table_entry_shadow)
@@ -89,30 +98,19 @@ static ssize_t read_cc_table_bin(struct file *filp, struct kobject *kobj,
return count;
}
-
-static void port_release(struct kobject *kobj)
-{
- /* nothing to do since memory is freed by hfi1_free_devdata() */
-}
-
-static const struct bin_attribute cc_table_bin_attr = {
- .attr = {.name = "cc_table_bin", .mode = 0444},
- .read = read_cc_table_bin,
- .size = PAGE_SIZE,
-};
+static BIN_ATTR_RO(cc_table_bin, PAGE_SIZE);
/*
* Congestion settings: port control, control map and an array of 16
* entries for the congestion entries - increase, timer, event log
* trigger threshold and the minimum injection rate delay.
*/
-static ssize_t read_cc_setting_bin(struct file *filp, struct kobject *kobj,
+static ssize_t cc_setting_bin_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t count)
{
+ struct hfi1_pportdata *ppd = hfi1_get_pportdata_kobj(kobj);
int ret;
- struct hfi1_pportdata *ppd =
- container_of(kobj, struct hfi1_pportdata, pport_cc_kobj);
struct cc_state *cc_state;
ret = sizeof(struct opa_congestion_setting_attr_shadow);
@@ -136,27 +134,30 @@ static ssize_t read_cc_setting_bin(struct file *filp, struct kobject *kobj,
return count;
}
+static BIN_ATTR_RO(cc_setting_bin, PAGE_SIZE);
-static const struct bin_attribute cc_setting_bin_attr = {
- .attr = {.name = "cc_settings_bin", .mode = 0444},
- .read = read_cc_setting_bin,
- .size = PAGE_SIZE,
-};
-
-struct hfi1_port_attr {
- struct attribute attr;
- ssize_t (*show)(struct hfi1_pportdata *, char *);
- ssize_t (*store)(struct hfi1_pportdata *, const char *, size_t);
+static struct bin_attribute *port_cc_bin_attributes[] = {
+ &bin_attr_cc_setting_bin,
+ &bin_attr_cc_table_bin,
+ NULL
};
-static ssize_t cc_prescan_show(struct hfi1_pportdata *ppd, char *buf)
+static ssize_t cc_prescan_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
{
+ struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
+ struct hfi1_pportdata *ppd = &dd->pport[port_num - 1];
+
return sysfs_emit(buf, "%s\n", ppd->cc_prescan ? "on" : "off");
}
-static ssize_t cc_prescan_store(struct hfi1_pportdata *ppd, const char *buf,
+static ssize_t cc_prescan_store(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, const char *buf,
size_t count)
{
+ struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
+ struct hfi1_pportdata *ppd = &dd->pport[port_num - 1];
+
if (!memcmp(buf, "on", 2))
ppd->cc_prescan = true;
else if (!memcmp(buf, "off", 3))
@@ -164,60 +165,41 @@ static ssize_t cc_prescan_store(struct hfi1_pportdata *ppd, const char *buf,
return count;
}
+static IB_PORT_ATTR_ADMIN_RW(cc_prescan);
-static struct hfi1_port_attr cc_prescan_attr =
- __ATTR(cc_prescan, 0600, cc_prescan_show, cc_prescan_store);
-
-static ssize_t cc_attr_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- struct hfi1_port_attr *port_attr =
- container_of(attr, struct hfi1_port_attr, attr);
- struct hfi1_pportdata *ppd =
- container_of(kobj, struct hfi1_pportdata, pport_cc_kobj);
-
- return port_attr->show(ppd, buf);
-}
-
-static ssize_t cc_attr_store(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- struct hfi1_port_attr *port_attr =
- container_of(attr, struct hfi1_port_attr, attr);
- struct hfi1_pportdata *ppd =
- container_of(kobj, struct hfi1_pportdata, pport_cc_kobj);
-
- return port_attr->store(ppd, buf, count);
-}
-
-static const struct sysfs_ops port_cc_sysfs_ops = {
- .show = cc_attr_show,
- .store = cc_attr_store
-};
-
-static struct attribute *port_cc_default_attributes[] = {
- &cc_prescan_attr.attr,
+static struct attribute *port_cc_attributes[] = {
+ &ib_port_attr_cc_prescan.attr,
NULL
};
-static struct kobj_type port_cc_ktype = {
- .release = port_release,
- .sysfs_ops = &port_cc_sysfs_ops,
- .default_attrs = port_cc_default_attributes
+static const struct attribute_group port_cc_group = {
+ .name = "CCMgtA",
+ .attrs = port_cc_attributes,
+ .bin_attrs = port_cc_bin_attributes,
};
/* Start sc2vl */
-#define HFI1_SC2VL_ATTR(N) \
- static struct hfi1_sc2vl_attr hfi1_sc2vl_attr_##N = { \
- .attr = { .name = __stringify(N), .mode = 0444 }, \
- .sc = N \
- }
-
struct hfi1_sc2vl_attr {
- struct attribute attr;
+ struct ib_port_attribute attr;
int sc;
};
+static ssize_t sc2vl_attr_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
+{
+ struct hfi1_sc2vl_attr *sattr =
+ container_of(attr, struct hfi1_sc2vl_attr, attr);
+ struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
+
+ return sysfs_emit(buf, "%u\n", *((u8 *)dd->sc2vl + sattr->sc));
+}
+
+#define HFI1_SC2VL_ATTR(N) \
+ static struct hfi1_sc2vl_attr hfi1_sc2vl_attr_##N = { \
+ .attr = __ATTR(N, 0444, sc2vl_attr_show, NULL), \
+ .sc = N, \
+ }
+
HFI1_SC2VL_ATTR(0);
HFI1_SC2VL_ATTR(1);
HFI1_SC2VL_ATTR(2);
@@ -251,78 +233,70 @@ HFI1_SC2VL_ATTR(29);
HFI1_SC2VL_ATTR(30);
HFI1_SC2VL_ATTR(31);
-static struct attribute *sc2vl_default_attributes[] = {
- &hfi1_sc2vl_attr_0.attr,
- &hfi1_sc2vl_attr_1.attr,
- &hfi1_sc2vl_attr_2.attr,
- &hfi1_sc2vl_attr_3.attr,
- &hfi1_sc2vl_attr_4.attr,
- &hfi1_sc2vl_attr_5.attr,
- &hfi1_sc2vl_attr_6.attr,
- &hfi1_sc2vl_attr_7.attr,
- &hfi1_sc2vl_attr_8.attr,
- &hfi1_sc2vl_attr_9.attr,
- &hfi1_sc2vl_attr_10.attr,
- &hfi1_sc2vl_attr_11.attr,
- &hfi1_sc2vl_attr_12.attr,
- &hfi1_sc2vl_attr_13.attr,
- &hfi1_sc2vl_attr_14.attr,
- &hfi1_sc2vl_attr_15.attr,
- &hfi1_sc2vl_attr_16.attr,
- &hfi1_sc2vl_attr_17.attr,
- &hfi1_sc2vl_attr_18.attr,
- &hfi1_sc2vl_attr_19.attr,
- &hfi1_sc2vl_attr_20.attr,
- &hfi1_sc2vl_attr_21.attr,
- &hfi1_sc2vl_attr_22.attr,
- &hfi1_sc2vl_attr_23.attr,
- &hfi1_sc2vl_attr_24.attr,
- &hfi1_sc2vl_attr_25.attr,
- &hfi1_sc2vl_attr_26.attr,
- &hfi1_sc2vl_attr_27.attr,
- &hfi1_sc2vl_attr_28.attr,
- &hfi1_sc2vl_attr_29.attr,
- &hfi1_sc2vl_attr_30.attr,
- &hfi1_sc2vl_attr_31.attr,
+static struct attribute *port_sc2vl_attributes[] = {
+ &hfi1_sc2vl_attr_0.attr.attr,
+ &hfi1_sc2vl_attr_1.attr.attr,
+ &hfi1_sc2vl_attr_2.attr.attr,
+ &hfi1_sc2vl_attr_3.attr.attr,
+ &hfi1_sc2vl_attr_4.attr.attr,
+ &hfi1_sc2vl_attr_5.attr.attr,
+ &hfi1_sc2vl_attr_6.attr.attr,
+ &hfi1_sc2vl_attr_7.attr.attr,
+ &hfi1_sc2vl_attr_8.attr.attr,
+ &hfi1_sc2vl_attr_9.attr.attr,
+ &hfi1_sc2vl_attr_10.attr.attr,
+ &hfi1_sc2vl_attr_11.attr.attr,
+ &hfi1_sc2vl_attr_12.attr.attr,
+ &hfi1_sc2vl_attr_13.attr.attr,
+ &hfi1_sc2vl_attr_14.attr.attr,
+ &hfi1_sc2vl_attr_15.attr.attr,
+ &hfi1_sc2vl_attr_16.attr.attr,
+ &hfi1_sc2vl_attr_17.attr.attr,
+ &hfi1_sc2vl_attr_18.attr.attr,
+ &hfi1_sc2vl_attr_19.attr.attr,
+ &hfi1_sc2vl_attr_20.attr.attr,
+ &hfi1_sc2vl_attr_21.attr.attr,
+ &hfi1_sc2vl_attr_22.attr.attr,
+ &hfi1_sc2vl_attr_23.attr.attr,
+ &hfi1_sc2vl_attr_24.attr.attr,
+ &hfi1_sc2vl_attr_25.attr.attr,
+ &hfi1_sc2vl_attr_26.attr.attr,
+ &hfi1_sc2vl_attr_27.attr.attr,
+ &hfi1_sc2vl_attr_28.attr.attr,
+ &hfi1_sc2vl_attr_29.attr.attr,
+ &hfi1_sc2vl_attr_30.attr.attr,
+ &hfi1_sc2vl_attr_31.attr.attr,
NULL
};
-static ssize_t sc2vl_attr_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- struct hfi1_sc2vl_attr *sattr =
- container_of(attr, struct hfi1_sc2vl_attr, attr);
- struct hfi1_pportdata *ppd =
- container_of(kobj, struct hfi1_pportdata, sc2vl_kobj);
- struct hfi1_devdata *dd = ppd->dd;
-
- return sysfs_emit(buf, "%u\n", *((u8 *)dd->sc2vl + sattr->sc));
-}
-
-static const struct sysfs_ops hfi1_sc2vl_ops = {
- .show = sc2vl_attr_show,
-};
-
-static struct kobj_type hfi1_sc2vl_ktype = {
- .release = port_release,
- .sysfs_ops = &hfi1_sc2vl_ops,
- .default_attrs = sc2vl_default_attributes
+static const struct attribute_group port_sc2vl_group = {
+ .name = "sc2vl",
+ .attrs = port_sc2vl_attributes,
};
-
/* End sc2vl */
/* Start sl2sc */
-#define HFI1_SL2SC_ATTR(N) \
- static struct hfi1_sl2sc_attr hfi1_sl2sc_attr_##N = { \
- .attr = { .name = __stringify(N), .mode = 0444 }, \
- .sl = N \
- }
-
struct hfi1_sl2sc_attr {
- struct attribute attr;
+ struct ib_port_attribute attr;
int sl;
};
+static ssize_t sl2sc_attr_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
+{
+ struct hfi1_sl2sc_attr *sattr =
+ container_of(attr, struct hfi1_sl2sc_attr, attr);
+ struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
+ struct hfi1_ibport *ibp = &dd->pport[port_num - 1].ibport_data;
+
+ return sysfs_emit(buf, "%u\n", ibp->sl_to_sc[sattr->sl]);
+}
+
+#define HFI1_SL2SC_ATTR(N) \
+ static struct hfi1_sl2sc_attr hfi1_sl2sc_attr_##N = { \
+ .attr = __ATTR(N, 0444, sl2sc_attr_show, NULL), .sl = N \
+ }
+
HFI1_SL2SC_ATTR(0);
HFI1_SL2SC_ATTR(1);
HFI1_SL2SC_ATTR(2);
@@ -356,79 +330,72 @@ HFI1_SL2SC_ATTR(29);
HFI1_SL2SC_ATTR(30);
HFI1_SL2SC_ATTR(31);
-static struct attribute *sl2sc_default_attributes[] = {
- &hfi1_sl2sc_attr_0.attr,
- &hfi1_sl2sc_attr_1.attr,
- &hfi1_sl2sc_attr_2.attr,
- &hfi1_sl2sc_attr_3.attr,
- &hfi1_sl2sc_attr_4.attr,
- &hfi1_sl2sc_attr_5.attr,
- &hfi1_sl2sc_attr_6.attr,
- &hfi1_sl2sc_attr_7.attr,
- &hfi1_sl2sc_attr_8.attr,
- &hfi1_sl2sc_attr_9.attr,
- &hfi1_sl2sc_attr_10.attr,
- &hfi1_sl2sc_attr_11.attr,
- &hfi1_sl2sc_attr_12.attr,
- &hfi1_sl2sc_attr_13.attr,
- &hfi1_sl2sc_attr_14.attr,
- &hfi1_sl2sc_attr_15.attr,
- &hfi1_sl2sc_attr_16.attr,
- &hfi1_sl2sc_attr_17.attr,
- &hfi1_sl2sc_attr_18.attr,
- &hfi1_sl2sc_attr_19.attr,
- &hfi1_sl2sc_attr_20.attr,
- &hfi1_sl2sc_attr_21.attr,
- &hfi1_sl2sc_attr_22.attr,
- &hfi1_sl2sc_attr_23.attr,
- &hfi1_sl2sc_attr_24.attr,
- &hfi1_sl2sc_attr_25.attr,
- &hfi1_sl2sc_attr_26.attr,
- &hfi1_sl2sc_attr_27.attr,
- &hfi1_sl2sc_attr_28.attr,
- &hfi1_sl2sc_attr_29.attr,
- &hfi1_sl2sc_attr_30.attr,
- &hfi1_sl2sc_attr_31.attr,
+static struct attribute *port_sl2sc_attributes[] = {
+ &hfi1_sl2sc_attr_0.attr.attr,
+ &hfi1_sl2sc_attr_1.attr.attr,
+ &hfi1_sl2sc_attr_2.attr.attr,
+ &hfi1_sl2sc_attr_3.attr.attr,
+ &hfi1_sl2sc_attr_4.attr.attr,
+ &hfi1_sl2sc_attr_5.attr.attr,
+ &hfi1_sl2sc_attr_6.attr.attr,
+ &hfi1_sl2sc_attr_7.attr.attr,
+ &hfi1_sl2sc_attr_8.attr.attr,
+ &hfi1_sl2sc_attr_9.attr.attr,
+ &hfi1_sl2sc_attr_10.attr.attr,
+ &hfi1_sl2sc_attr_11.attr.attr,
+ &hfi1_sl2sc_attr_12.attr.attr,
+ &hfi1_sl2sc_attr_13.attr.attr,
+ &hfi1_sl2sc_attr_14.attr.attr,
+ &hfi1_sl2sc_attr_15.attr.attr,
+ &hfi1_sl2sc_attr_16.attr.attr,
+ &hfi1_sl2sc_attr_17.attr.attr,
+ &hfi1_sl2sc_attr_18.attr.attr,
+ &hfi1_sl2sc_attr_19.attr.attr,
+ &hfi1_sl2sc_attr_20.attr.attr,
+ &hfi1_sl2sc_attr_21.attr.attr,
+ &hfi1_sl2sc_attr_22.attr.attr,
+ &hfi1_sl2sc_attr_23.attr.attr,
+ &hfi1_sl2sc_attr_24.attr.attr,
+ &hfi1_sl2sc_attr_25.attr.attr,
+ &hfi1_sl2sc_attr_26.attr.attr,
+ &hfi1_sl2sc_attr_27.attr.attr,
+ &hfi1_sl2sc_attr_28.attr.attr,
+ &hfi1_sl2sc_attr_29.attr.attr,
+ &hfi1_sl2sc_attr_30.attr.attr,
+ &hfi1_sl2sc_attr_31.attr.attr,
NULL
};
-static ssize_t sl2sc_attr_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- struct hfi1_sl2sc_attr *sattr =
- container_of(attr, struct hfi1_sl2sc_attr, attr);
- struct hfi1_pportdata *ppd =
- container_of(kobj, struct hfi1_pportdata, sl2sc_kobj);
- struct hfi1_ibport *ibp = &ppd->ibport_data;
-
- return sysfs_emit(buf, "%u\n", ibp->sl_to_sc[sattr->sl]);
-}
-
-static const struct sysfs_ops hfi1_sl2sc_ops = {
- .show = sl2sc_attr_show,
-};
-
-static struct kobj_type hfi1_sl2sc_ktype = {
- .release = port_release,
- .sysfs_ops = &hfi1_sl2sc_ops,
- .default_attrs = sl2sc_default_attributes
+static const struct attribute_group port_sl2sc_group = {
+ .name = "sl2sc",
+ .attrs = port_sl2sc_attributes,
};
/* End sl2sc */
/* Start vl2mtu */
-#define HFI1_VL2MTU_ATTR(N) \
- static struct hfi1_vl2mtu_attr hfi1_vl2mtu_attr_##N = { \
- .attr = { .name = __stringify(N), .mode = 0444 }, \
- .vl = N \
- }
-
struct hfi1_vl2mtu_attr {
- struct attribute attr;
+ struct ib_port_attribute attr;
int vl;
};
+static ssize_t vl2mtu_attr_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
+{
+ struct hfi1_vl2mtu_attr *vlattr =
+ container_of(attr, struct hfi1_vl2mtu_attr, attr);
+ struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
+
+ return sysfs_emit(buf, "%u\n", dd->vld[vlattr->vl].mtu);
+}
+
+#define HFI1_VL2MTU_ATTR(N) \
+ static struct hfi1_vl2mtu_attr hfi1_vl2mtu_attr_##N = { \
+ .attr = __ATTR(N, 0444, vl2mtu_attr_show, NULL), \
+ .vl = N, \
+ }
+
HFI1_VL2MTU_ATTR(0);
HFI1_VL2MTU_ATTR(1);
HFI1_VL2MTU_ATTR(2);
@@ -446,46 +413,29 @@ HFI1_VL2MTU_ATTR(13);
HFI1_VL2MTU_ATTR(14);
HFI1_VL2MTU_ATTR(15);
-static struct attribute *vl2mtu_default_attributes[] = {
- &hfi1_vl2mtu_attr_0.attr,
- &hfi1_vl2mtu_attr_1.attr,
- &hfi1_vl2mtu_attr_2.attr,
- &hfi1_vl2mtu_attr_3.attr,
- &hfi1_vl2mtu_attr_4.attr,
- &hfi1_vl2mtu_attr_5.attr,
- &hfi1_vl2mtu_attr_6.attr,
- &hfi1_vl2mtu_attr_7.attr,
- &hfi1_vl2mtu_attr_8.attr,
- &hfi1_vl2mtu_attr_9.attr,
- &hfi1_vl2mtu_attr_10.attr,
- &hfi1_vl2mtu_attr_11.attr,
- &hfi1_vl2mtu_attr_12.attr,
- &hfi1_vl2mtu_attr_13.attr,
- &hfi1_vl2mtu_attr_14.attr,
- &hfi1_vl2mtu_attr_15.attr,
+static struct attribute *port_vl2mtu_attributes[] = {
+ &hfi1_vl2mtu_attr_0.attr.attr,
+ &hfi1_vl2mtu_attr_1.attr.attr,
+ &hfi1_vl2mtu_attr_2.attr.attr,
+ &hfi1_vl2mtu_attr_3.attr.attr,
+ &hfi1_vl2mtu_attr_4.attr.attr,
+ &hfi1_vl2mtu_attr_5.attr.attr,
+ &hfi1_vl2mtu_attr_6.attr.attr,
+ &hfi1_vl2mtu_attr_7.attr.attr,
+ &hfi1_vl2mtu_attr_8.attr.attr,
+ &hfi1_vl2mtu_attr_9.attr.attr,
+ &hfi1_vl2mtu_attr_10.attr.attr,
+ &hfi1_vl2mtu_attr_11.attr.attr,
+ &hfi1_vl2mtu_attr_12.attr.attr,
+ &hfi1_vl2mtu_attr_13.attr.attr,
+ &hfi1_vl2mtu_attr_14.attr.attr,
+ &hfi1_vl2mtu_attr_15.attr.attr,
NULL
};
-static ssize_t vl2mtu_attr_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- struct hfi1_vl2mtu_attr *vlattr =
- container_of(attr, struct hfi1_vl2mtu_attr, attr);
- struct hfi1_pportdata *ppd =
- container_of(kobj, struct hfi1_pportdata, vl2mtu_kobj);
- struct hfi1_devdata *dd = ppd->dd;
-
- return sysfs_emit(buf, "%u\n", dd->vld[vlattr->vl].mtu);
-}
-
-static const struct sysfs_ops hfi1_vl2mtu_ops = {
- .show = vl2mtu_attr_show,
-};
-
-static struct kobj_type hfi1_vl2mtu_ktype = {
- .release = port_release,
- .sysfs_ops = &hfi1_vl2mtu_ops,
- .default_attrs = vl2mtu_default_attributes
+static const struct attribute_group port_vl2mtu_group = {
+ .name = "vl2mtu",
+ .attrs = port_vl2mtu_attributes,
};
/* end of per-port file structures and support code */
@@ -649,101 +599,13 @@ const struct attribute_group ib_hfi1_attr_group = {
.attrs = hfi1_attributes,
};
-int hfi1_create_port_files(struct ib_device *ibdev, u32 port_num,
- struct kobject *kobj)
-{
- struct hfi1_pportdata *ppd;
- struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
- int ret;
-
- if (!port_num || port_num > dd->num_pports) {
- dd_dev_err(dd,
- "Skipping infiniband class with invalid port %u\n",
- port_num);
- return -ENODEV;
- }
- ppd = &dd->pport[port_num - 1];
-
- ret = kobject_init_and_add(&ppd->sc2vl_kobj, &hfi1_sc2vl_ktype, kobj,
- "sc2vl");
- if (ret) {
- dd_dev_err(dd,
- "Skipping sc2vl sysfs info, (err %d) port %u\n",
- ret, port_num);
- /*
- * Based on the documentation for kobject_init_and_add(), the
- * caller should call kobject_put even if this call fails.
- */
- goto bail_sc2vl;
- }
- kobject_uevent(&ppd->sc2vl_kobj, KOBJ_ADD);
-
- ret = kobject_init_and_add(&ppd->sl2sc_kobj, &hfi1_sl2sc_ktype, kobj,
- "sl2sc");
- if (ret) {
- dd_dev_err(dd,
- "Skipping sl2sc sysfs info, (err %d) port %u\n",
- ret, port_num);
- goto bail_sl2sc;
- }
- kobject_uevent(&ppd->sl2sc_kobj, KOBJ_ADD);
-
- ret = kobject_init_and_add(&ppd->vl2mtu_kobj, &hfi1_vl2mtu_ktype, kobj,
- "vl2mtu");
- if (ret) {
- dd_dev_err(dd,
- "Skipping vl2mtu sysfs info, (err %d) port %u\n",
- ret, port_num);
- goto bail_vl2mtu;
- }
- kobject_uevent(&ppd->vl2mtu_kobj, KOBJ_ADD);
-
- ret = kobject_init_and_add(&ppd->pport_cc_kobj, &port_cc_ktype,
- kobj, "CCMgtA");
- if (ret) {
- dd_dev_err(dd,
- "Skipping Congestion Control sysfs info, (err %d) port %u\n",
- ret, port_num);
- goto bail_cc;
- }
-
- kobject_uevent(&ppd->pport_cc_kobj, KOBJ_ADD);
-
- ret = sysfs_create_bin_file(&ppd->pport_cc_kobj, &cc_setting_bin_attr);
- if (ret) {
- dd_dev_err(dd,
- "Skipping Congestion Control setting sysfs info, (err %d) port %u\n",
- ret, port_num);
- goto bail_cc;
- }
-
- ret = sysfs_create_bin_file(&ppd->pport_cc_kobj, &cc_table_bin_attr);
- if (ret) {
- dd_dev_err(dd,
- "Skipping Congestion Control table sysfs info, (err %d) port %u\n",
- ret, port_num);
- goto bail_cc_entry_bin;
- }
-
- dd_dev_info(dd,
- "Congestion Control Agent enabled for port %d\n",
- port_num);
-
- return 0;
-
-bail_cc_entry_bin:
- sysfs_remove_bin_file(&ppd->pport_cc_kobj,
- &cc_setting_bin_attr);
-bail_cc:
- kobject_put(&ppd->pport_cc_kobj);
-bail_vl2mtu:
- kobject_put(&ppd->vl2mtu_kobj);
-bail_sl2sc:
- kobject_put(&ppd->sl2sc_kobj);
-bail_sc2vl:
- kobject_put(&ppd->sc2vl_kobj);
- return ret;
-}
+const struct attribute_group *hfi1_attr_port_groups[] = {
+ &port_cc_group,
+ &port_sc2vl_group,
+ &port_sl2sc_group,
+ &port_vl2mtu_group,
+ NULL,
+};
struct sde_attribute {
struct attribute attr;
@@ -868,23 +730,9 @@ bail:
*/
void hfi1_verbs_unregister_sysfs(struct hfi1_devdata *dd)
{
- struct hfi1_pportdata *ppd;
int i;
/* Unwind operations in hfi1_verbs_register_sysfs() */
for (i = 0; i < dd->num_sdma; i++)
kobject_put(&dd->per_sdma[i].kobj);
-
- for (i = 0; i < dd->num_pports; i++) {
- ppd = &dd->pport[i];
-
- sysfs_remove_bin_file(&ppd->pport_cc_kobj,
- &cc_setting_bin_attr);
- sysfs_remove_bin_file(&ppd->pport_cc_kobj,
- &cc_table_bin_attr);
- kobject_put(&ppd->pport_cc_kobj);
- kobject_put(&ppd->vl2mtu_kobj);
- kobject_put(&ppd->sl2sc_kobj);
- kobject_put(&ppd->sc2vl_kobj);
- }
}
diff --git a/drivers/infiniband/hw/hfi1/tid_rdma.c b/drivers/infiniband/hw/hfi1/tid_rdma.c
index 0b1f9e4d038b..233ea48b72c8 100644
--- a/drivers/infiniband/hw/hfi1/tid_rdma.c
+++ b/drivers/infiniband/hw/hfi1/tid_rdma.c
@@ -1115,7 +1115,7 @@ static u32 kern_find_pages(struct tid_rdma_flow *flow,
}
flow->length = flow->req->seg_len - length;
- *last = req->isge == ss->num_sge ? false : true;
+ *last = req->isge != ss->num_sge;
return i;
}
diff --git a/drivers/infiniband/hw/hfi1/trace.c b/drivers/infiniband/hw/hfi1/trace.c
index b219ea90fd6f..715c81308b85 100644
--- a/drivers/infiniband/hw/hfi1/trace.c
+++ b/drivers/infiniband/hw/hfi1/trace.c
@@ -189,6 +189,11 @@ void hfi1_trace_parse_16b_bth(struct ib_other_headers *ohdr,
*qpn = ib_bth_get_qpn(ohdr);
}
+static u16 ib_get_len(const struct ib_header *hdr)
+{
+ return be16_to_cpu(hdr->lrh[2]);
+}
+
void hfi1_trace_parse_9b_hdr(struct ib_header *hdr, bool sc5,
u8 *lnh, u8 *lver, u8 *sl, u8 *sc,
u16 *len, u32 *dlid, u32 *slid)
diff --git a/drivers/infiniband/hw/hfi1/trace_misc.h b/drivers/infiniband/hw/hfi1/trace_misc.h
index 8db2253523ff..93338988b922 100644
--- a/drivers/infiniband/hw/hfi1/trace_misc.h
+++ b/drivers/infiniband/hw/hfi1/trace_misc.h
@@ -63,7 +63,7 @@ TRACE_EVENT(hfi1_interrupt,
__array(char, buf, 64)
__field(int, src)
),
- TP_fast_assign(DD_DEV_ASSIGN(dd)
+ TP_fast_assign(DD_DEV_ASSIGN(dd);
is_entry->is_name(__entry->buf, 64,
src - is_entry->start);
__entry->src = src;
@@ -100,7 +100,7 @@ TRACE_EVENT(hfi1_fault_opcode,
__field(u32, qpn)
__field(u8, opcode)
),
- TP_fast_assign(DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device))
+ TP_fast_assign(DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device));
__entry->qpn = qp->ibqp.qp_num;
__entry->opcode = opcode;
),
diff --git a/drivers/infiniband/hw/hfi1/trace_rc.h b/drivers/infiniband/hw/hfi1/trace_rc.h
index 1ebca37862e0..5f49e1eeb211 100644
--- a/drivers/infiniband/hw/hfi1/trace_rc.h
+++ b/drivers/infiniband/hw/hfi1/trace_rc.h
@@ -70,7 +70,7 @@ DECLARE_EVENT_CLASS(hfi1_rc_template,
__field(u32, r_psn)
),
TP_fast_assign(
- DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device))
+ DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device));
__entry->qpn = qp->ibqp.qp_num;
__entry->s_flags = qp->s_flags;
__entry->psn = psn;
@@ -130,7 +130,7 @@ DECLARE_EVENT_CLASS(/* rc_ack */
__field(u32, lpsn)
),
TP_fast_assign(/* assign */
- DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device))
+ DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device));
__entry->qpn = qp->ibqp.qp_num;
__entry->aeth = aeth;
__entry->psn = psn;
diff --git a/drivers/infiniband/hw/hfi1/trace_tid.h b/drivers/infiniband/hw/hfi1/trace_tid.h
index 985ffa9cc958..d129b8195959 100644
--- a/drivers/infiniband/hw/hfi1/trace_tid.h
+++ b/drivers/infiniband/hw/hfi1/trace_tid.h
@@ -886,7 +886,7 @@ DECLARE_EVENT_CLASS(/* sender_info */
__field(u8, s_retry)
),
TP_fast_assign(/* assign */
- DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device))
+ DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device));
__entry->qpn = qp->ibqp.qp_num;
__entry->state = qp->state;
__entry->s_cur = qp->s_cur;
@@ -1285,7 +1285,7 @@ DECLARE_EVENT_CLASS(/* rc_rcv_err */
__field(int, diff)
),
TP_fast_assign(/* assign */
- DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device))
+ DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device));
__entry->qpn = qp->ibqp.qp_num;
__entry->s_flags = qp->s_flags;
__entry->state = qp->state;
@@ -1574,7 +1574,7 @@ DECLARE_EVENT_CLASS(/* tid_ack */
__field(u32, resync_psn)
),
TP_fast_assign(/* assign */
- DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device))
+ DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device));
__entry->qpn = qp->ibqp.qp_num;
__entry->aeth = aeth;
__entry->psn = psn;
diff --git a/drivers/infiniband/hw/hfi1/trace_tx.h b/drivers/infiniband/hw/hfi1/trace_tx.h
index d44fc54858b9..f1922a7619fe 100644
--- a/drivers/infiniband/hw/hfi1/trace_tx.h
+++ b/drivers/infiniband/hw/hfi1/trace_tx.h
@@ -120,7 +120,7 @@ DECLARE_EVENT_CLASS(hfi1_qpsleepwakeup_template,
__field(unsigned long, iow_flags)
),
TP_fast_assign(
- DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device))
+ DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device));
__entry->flags = flags;
__entry->qpn = qp->ibqp.qp_num;
__entry->s_flags = qp->s_flags;
@@ -868,7 +868,7 @@ TRACE_EVENT(
__field(int, send_flags)
),
TP_fast_assign(
- DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device))
+ DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device));
__entry->wqe = wqe;
__entry->wr_id = wqe->wr.wr_id;
__entry->qpn = qp->ibqp.qp_num;
@@ -904,7 +904,7 @@ DECLARE_EVENT_CLASS(
__field(bool, flag)
),
TP_fast_assign(
- DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device))
+ DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device));
__entry->qpn = qp->ibqp.qp_num;
__entry->flag = flag;
),
@@ -952,7 +952,7 @@ DECLARE_EVENT_CLASS(/* AIP */
__field(u8, stopped)
),
TP_fast_assign(/* assign */
- DD_DEV_ASSIGN(txq->priv->dd)
+ DD_DEV_ASSIGN(txq->priv->dd);
__entry->txq = txq;
__entry->sde = txq->sde;
__entry->head = txq->tx_ring.head;
diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c
index 554294340caa..9b198c35e1a1 100644
--- a/drivers/infiniband/hw/hfi1/verbs.c
+++ b/drivers/infiniband/hw/hfi1/verbs.c
@@ -1693,54 +1693,53 @@ static int init_cntr_names(const char *names_in,
return 0;
}
-static struct rdma_hw_stats *alloc_hw_stats(struct ib_device *ibdev,
- u32 port_num)
+static int init_counters(struct ib_device *ibdev)
{
- int i, err;
+ struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
+ int i, err = 0;
mutex_lock(&cntr_names_lock);
- if (!cntr_names_initialized) {
- struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
-
- err = init_cntr_names(dd->cntrnames,
- dd->cntrnameslen,
- num_driver_cntrs,
- &num_dev_cntrs,
- &dev_cntr_names);
- if (err) {
- mutex_unlock(&cntr_names_lock);
- return NULL;
- }
-
- for (i = 0; i < num_driver_cntrs; i++)
- dev_cntr_names[num_dev_cntrs + i] =
- driver_cntr_names[i];
-
- err = init_cntr_names(dd->portcntrnames,
- dd->portcntrnameslen,
- 0,
- &num_port_cntrs,
- &port_cntr_names);
- if (err) {
- kfree(dev_cntr_names);
- dev_cntr_names = NULL;
- mutex_unlock(&cntr_names_lock);
- return NULL;
- }
- cntr_names_initialized = 1;
+ if (cntr_names_initialized)
+ goto out_unlock;
+
+ err = init_cntr_names(dd->cntrnames, dd->cntrnameslen, num_driver_cntrs,
+ &num_dev_cntrs, &dev_cntr_names);
+ if (err)
+ goto out_unlock;
+
+ for (i = 0; i < num_driver_cntrs; i++)
+ dev_cntr_names[num_dev_cntrs + i] = driver_cntr_names[i];
+
+ err = init_cntr_names(dd->portcntrnames, dd->portcntrnameslen, 0,
+ &num_port_cntrs, &port_cntr_names);
+ if (err) {
+ kfree(dev_cntr_names);
+ dev_cntr_names = NULL;
+ goto out_unlock;
}
+ cntr_names_initialized = 1;
+
+out_unlock:
mutex_unlock(&cntr_names_lock);
+ return err;
+}
- if (!port_num)
- return rdma_alloc_hw_stats_struct(
- dev_cntr_names,
- num_dev_cntrs + num_driver_cntrs,
- RDMA_HW_STATS_DEFAULT_LIFESPAN);
- else
- return rdma_alloc_hw_stats_struct(
- port_cntr_names,
- num_port_cntrs,
- RDMA_HW_STATS_DEFAULT_LIFESPAN);
+static struct rdma_hw_stats *hfi1_alloc_hw_device_stats(struct ib_device *ibdev)
+{
+ if (init_counters(ibdev))
+ return NULL;
+ return rdma_alloc_hw_stats_struct(dev_cntr_names,
+ num_dev_cntrs + num_driver_cntrs,
+ RDMA_HW_STATS_DEFAULT_LIFESPAN);
+}
+
+static struct rdma_hw_stats *hfi_alloc_hw_port_stats(struct ib_device *ibdev,
+ u32 port_num)
+{
+ if (init_counters(ibdev))
+ return NULL;
+ return rdma_alloc_hw_stats_struct(port_cntr_names, num_port_cntrs,
+ RDMA_HW_STATS_DEFAULT_LIFESPAN);
}
static u64 hfi1_sps_ints(void)
@@ -1787,12 +1786,14 @@ static const struct ib_device_ops hfi1_dev_ops = {
.owner = THIS_MODULE,
.driver_id = RDMA_DRIVER_HFI1,
- .alloc_hw_stats = alloc_hw_stats,
+ .alloc_hw_device_stats = hfi1_alloc_hw_device_stats,
+ .alloc_hw_port_stats = hfi_alloc_hw_port_stats,
.alloc_rdma_netdev = hfi1_vnic_alloc_rn,
+ .device_group = &ib_hfi1_attr_group,
.get_dev_fw_str = hfi1_get_dev_fw_str,
.get_hw_stats = get_hw_stats,
- .init_port = hfi1_create_port_files,
.modify_device = modify_device,
+ .port_groups = hfi1_attr_port_groups,
/* keep process mad in the driver */
.process_mad = hfi1_process_mad,
.rdma_netdev_get_params = hfi1_ipoib_rn_get_params,
@@ -1927,9 +1928,6 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd)
i,
ppd->pkeys);
- rdma_set_device_sysfs_group(&dd->verbs_dev.rdi.ibdev,
- &ib_hfi1_attr_group);
-
ret = rvt_register_device(&dd->verbs_dev.rdi);
if (ret)
goto err_verbs_txreq;
diff --git a/drivers/infiniband/hw/hns/hns_roce_alloc.c b/drivers/infiniband/hw/hns/hns_roce_alloc.c
index 5d389ed55376..1b02d3bc9bae 100644
--- a/drivers/infiniband/hw/hns/hns_roce_alloc.c
+++ b/drivers/infiniband/hw/hns/hns_roce_alloc.c
@@ -63,65 +63,14 @@ int hns_roce_bitmap_alloc(struct hns_roce_bitmap *bitmap, unsigned long *obj)
return ret;
}
-void hns_roce_bitmap_free(struct hns_roce_bitmap *bitmap, unsigned long obj,
- int rr)
+void hns_roce_bitmap_free(struct hns_roce_bitmap *bitmap, unsigned long obj)
{
- hns_roce_bitmap_free_range(bitmap, obj, 1, rr);
-}
-
-int hns_roce_bitmap_alloc_range(struct hns_roce_bitmap *bitmap, int cnt,
- int align, unsigned long *obj)
-{
- int ret = 0;
- int i;
-
- if (likely(cnt == 1 && align == 1))
- return hns_roce_bitmap_alloc(bitmap, obj);
-
- spin_lock(&bitmap->lock);
-
- *obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max,
- bitmap->last, cnt, align - 1);
- if (*obj >= bitmap->max) {
- bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
- & bitmap->mask;
- *obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max, 0,
- cnt, align - 1);
- }
-
- if (*obj < bitmap->max) {
- for (i = 0; i < cnt; i++)
- set_bit(*obj + i, bitmap->table);
-
- if (*obj == bitmap->last) {
- bitmap->last = (*obj + cnt);
- if (bitmap->last >= bitmap->max)
- bitmap->last = 0;
- }
- *obj |= bitmap->top;
- } else {
- ret = -EINVAL;
- }
-
- spin_unlock(&bitmap->lock);
-
- return ret;
-}
-
-void hns_roce_bitmap_free_range(struct hns_roce_bitmap *bitmap,
- unsigned long obj, int cnt,
- int rr)
-{
- int i;
-
obj &= bitmap->max + bitmap->reserved_top - 1;
spin_lock(&bitmap->lock);
- for (i = 0; i < cnt; i++)
- clear_bit(obj + i, bitmap->table);
+ clear_bit(obj, bitmap->table);
- if (!rr)
- bitmap->last = min(bitmap->last, obj);
+ bitmap->last = min(bitmap->last, obj);
bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
& bitmap->mask;
spin_unlock(&bitmap->lock);
@@ -208,10 +157,10 @@ struct hns_roce_buf *hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size,
/* Calc the trunk size and num by required size and page_shift */
if (flags & HNS_ROCE_BUF_DIRECT) {
- buf->trunk_shift = ilog2(ALIGN(size, PAGE_SIZE));
+ buf->trunk_shift = order_base_2(ALIGN(size, PAGE_SIZE));
ntrunk = 1;
} else {
- buf->trunk_shift = ilog2(ALIGN(page_size, PAGE_SIZE));
+ buf->trunk_shift = order_base_2(ALIGN(page_size, PAGE_SIZE));
ntrunk = DIV_ROUND_UP(size, 1 << buf->trunk_shift);
}
@@ -252,50 +201,41 @@ struct hns_roce_buf *hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size,
}
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 buf_cnt, struct hns_roce_buf *buf,
+ unsigned int page_shift)
{
- int i, end;
- int total;
-
- end = start + buf_cnt;
- if (end > buf->npages) {
- dev_err(hr_dev->dev,
- "failed to check kmem bufs, end %d + %d total %u!\n",
- start, buf_cnt, buf->npages);
+ unsigned int offset, max_size;
+ int total = 0;
+ int i;
+
+ if (page_shift > buf->trunk_shift) {
+ dev_err(hr_dev->dev, "failed to check kmem buf shift %u > %u\n",
+ page_shift, buf->trunk_shift);
return -EINVAL;
}
- total = 0;
- for (i = start; i < end; i++)
- bufs[total++] = hns_roce_buf_page(buf, i);
+ offset = 0;
+ max_size = buf->ntrunks << buf->trunk_shift;
+ for (i = 0; i < buf_cnt && offset < max_size; i++) {
+ bufs[total++] = hns_roce_buf_dma_addr(buf, offset);
+ offset += (1 << page_shift);
+ }
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 buf_cnt, struct ib_umem *umem,
unsigned int page_shift)
{
struct ib_block_iter biter;
int total = 0;
- int idx = 0;
- u64 addr;
-
- if (page_shift < HNS_HW_PAGE_SHIFT) {
- dev_err(hr_dev->dev, "failed to check umem page shift %u!\n",
- page_shift);
- return -EINVAL;
- }
/* convert system page cnt to hw page cnt */
rdma_umem_for_each_dma_block(umem, &biter, 1 << page_shift) {
- addr = rdma_block_iter_dma_address(&biter);
- if (idx >= start) {
- bufs[total++] = addr;
- if (total >= buf_cnt)
- goto done;
- }
- idx++;
+ bufs[total++] = rdma_block_iter_dma_address(&biter);
+ if (total >= buf_cnt)
+ goto done;
}
done:
@@ -305,13 +245,13 @@ done:
void hns_roce_cleanup_bitmap(struct hns_roce_dev *hr_dev)
{
if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_XRC)
- hns_roce_cleanup_xrcd_table(hr_dev);
+ ida_destroy(&hr_dev->xrcd_ida.ida);
if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SRQ)
hns_roce_cleanup_srq_table(hr_dev);
hns_roce_cleanup_qp_table(hr_dev);
hns_roce_cleanup_cq_table(hr_dev);
- hns_roce_cleanup_mr_table(hr_dev);
- hns_roce_cleanup_pd_table(hr_dev);
+ ida_destroy(&hr_dev->mr_table.mtpt_ida.ida);
+ ida_destroy(&hr_dev->pd_ida.ida);
hns_roce_cleanup_uar_table(hr_dev);
}
diff --git a/drivers/infiniband/hw/hns/hns_roce_common.h b/drivers/infiniband/hw/hns/hns_roce_common.h
index d5fe56c78394..b73e55de83ac 100644
--- a/drivers/infiniband/hw/hns/hns_roce_common.h
+++ b/drivers/infiniband/hw/hns/hns_roce_common.h
@@ -77,6 +77,14 @@
#define hr_reg_clear(ptr, field) _hr_reg_clear(ptr, field)
+#define _hr_reg_write_bool(ptr, field_type, field_h, field_l, val) \
+ ({ \
+ (val) ? _hr_reg_enable(ptr, field_type, field_h, field_l) : \
+ _hr_reg_clear(ptr, field_type, field_h, field_l); \
+ })
+
+#define hr_reg_write_bool(ptr, field, val) _hr_reg_write_bool(ptr, field, val)
+
#define _hr_reg_write(ptr, field_type, field_h, field_l, val) \
({ \
_hr_reg_clear(ptr, field_type, field_h, field_l); \
@@ -373,8 +381,8 @@
#define ROCEE_TX_CMQ_BASEADDR_L_REG 0x07000
#define ROCEE_TX_CMQ_BASEADDR_H_REG 0x07004
#define ROCEE_TX_CMQ_DEPTH_REG 0x07008
-#define ROCEE_TX_CMQ_HEAD_REG 0x07010
-#define ROCEE_TX_CMQ_TAIL_REG 0x07014
+#define ROCEE_TX_CMQ_PI_REG 0x07010
+#define ROCEE_TX_CMQ_CI_REG 0x07014
#define ROCEE_RX_CMQ_BASEADDR_L_REG 0x07018
#define ROCEE_RX_CMQ_BASEADDR_H_REG 0x0701c
diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c
index 800884b074f2..1e9c3c5bee68 100644
--- a/drivers/infiniband/hw/hns/hns_roce_cq.c
+++ b/drivers/infiniband/hw/hns/hns_roce_cq.c
@@ -154,7 +154,7 @@ static int alloc_cqc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)
hr_cq->cons_index = 0;
hr_cq->arm_sn = 1;
- atomic_set(&hr_cq->refcount, 1);
+ refcount_set(&hr_cq->refcount, 1);
init_completion(&hr_cq->free);
return 0;
@@ -188,7 +188,7 @@ static void free_cqc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)
synchronize_irq(hr_dev->eq_table.eq[hr_cq->vector].irq);
/* wait for all interrupt processed */
- if (atomic_dec_and_test(&hr_cq->refcount))
+ if (refcount_dec_and_test(&hr_cq->refcount))
complete(&hr_cq->free);
wait_for_completion(&hr_cq->free);
@@ -202,13 +202,13 @@ static int alloc_cq_buf(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq,
struct hns_roce_buf_attr buf_attr = {};
int ret;
- buf_attr.page_shift = hr_dev->caps.cqe_buf_pg_sz + HNS_HW_PAGE_SHIFT;
+ buf_attr.page_shift = hr_dev->caps.cqe_buf_pg_sz + PAGE_SHIFT;
buf_attr.region[0].size = hr_cq->cq_depth * hr_cq->cqe_size;
buf_attr.region[0].hopnum = hr_dev->caps.cqe_hop_num;
buf_attr.region_count = 1;
ret = hns_roce_mtr_create(hr_dev, &hr_cq->mtr, &buf_attr,
- hr_dev->caps.cqe_ba_pg_sz + HNS_HW_PAGE_SHIFT,
+ hr_dev->caps.cqe_ba_pg_sz + PAGE_SHIFT,
udata, addr);
if (ret)
ibdev_err(ibdev, "failed to alloc CQ mtr, ret = %d.\n", ret);
@@ -234,8 +234,7 @@ static int alloc_cq_db(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq,
udata->outlen >= offsetofend(typeof(*resp), cap_flags)) {
uctx = rdma_udata_to_drv_context(udata,
struct hns_roce_ucontext, ibucontext);
- err = hns_roce_db_map_user(uctx, udata, addr,
- &hr_cq->db);
+ err = hns_roce_db_map_user(uctx, addr, &hr_cq->db);
if (err)
return err;
hr_cq->flags |= HNS_ROCE_CQ_FLAG_RECORD_DB;
@@ -481,7 +480,7 @@ void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type)
return;
}
- atomic_inc(&hr_cq->refcount);
+ refcount_inc(&hr_cq->refcount);
ibcq = &hr_cq->ib_cq;
if (ibcq->event_handler) {
@@ -491,7 +490,7 @@ void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type)
ibcq->event_handler(&event, ibcq->cq_context);
}
- if (atomic_dec_and_test(&hr_cq->refcount))
+ if (refcount_dec_and_test(&hr_cq->refcount))
complete(&hr_cq->free);
}
diff --git a/drivers/infiniband/hw/hns/hns_roce_db.c b/drivers/infiniband/hw/hns/hns_roce_db.c
index 5cb7376ce978..d40ea3d87260 100644
--- a/drivers/infiniband/hw/hns/hns_roce_db.c
+++ b/drivers/infiniband/hw/hns/hns_roce_db.c
@@ -8,8 +8,7 @@
#include <rdma/ib_umem.h>
#include "hns_roce_device.h"
-int hns_roce_db_map_user(struct hns_roce_ucontext *context,
- struct ib_udata *udata, unsigned long virt,
+int hns_roce_db_map_user(struct hns_roce_ucontext *context, unsigned long virt,
struct hns_roce_db *db)
{
unsigned long page_addr = virt & PAGE_MASK;
diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
index 97800d2b9d39..991f65269fa6 100644
--- a/drivers/infiniband/hw/hns/hns_roce_device.h
+++ b/drivers/infiniband/hw/hns/hns_roce_device.h
@@ -47,8 +47,6 @@
#define HNS_ROCE_IB_MIN_SQ_STRIDE 6
-#define HNS_ROCE_BA_SIZE (32 * 4096)
-
#define BA_BYTE_LEN 8
/* Hardware specification only for v1 engine */
@@ -97,9 +95,6 @@
#define HNS_ROCE_HOP_NUM_0 0xff
-#define BITMAP_NO_RR 0
-#define BITMAP_RR 1
-
#define MR_TYPE_MR 0x00
#define MR_TYPE_FRMR 0x01
#define MR_TYPE_DMA 0x03
@@ -258,14 +253,18 @@ struct hns_roce_bitmap {
unsigned long *table;
};
+struct hns_roce_ida {
+ struct ida ida;
+ u32 min; /* Lowest ID to allocate. */
+ u32 max; /* Highest ID to allocate. */
+};
+
/* For Hardware Entry Memory */
struct hns_roce_hem_table {
/* HEM type: 0 = qpc, 1 = mtt, 2 = cqc, 3 = srq, 4 = other */
u32 type;
/* HEM array elment num */
unsigned long num_hem;
- /* HEM entry record obj total num */
- unsigned long num_obj;
/* Single obj size */
unsigned long obj_size;
unsigned long table_chunk_size;
@@ -338,7 +337,7 @@ struct hns_roce_mw {
struct hns_roce_mr {
struct ib_mr ibmr;
- u64 iova; /* MR's virtual orignal addr */
+ u64 iova; /* MR's virtual original addr */
u64 size; /* Address range of MR */
u32 key; /* Key of MR */
u32 pd; /* PD num of MR */
@@ -352,7 +351,7 @@ struct hns_roce_mr {
};
struct hns_roce_mr_table {
- struct hns_roce_bitmap mtpt_bitmap;
+ struct hns_roce_ida mtpt_ida;
struct hns_roce_hem_table mtpt_table;
};
@@ -446,7 +445,7 @@ struct hns_roce_cq {
int cqe_size;
unsigned long cqn;
u32 vector;
- atomic_t refcount;
+ refcount_t refcount;
struct completion free;
struct list_head sq_list; /* all qps on this send cq */
struct list_head rq_list; /* all qps on this recv cq */
@@ -473,7 +472,7 @@ struct hns_roce_srq {
u32 xrcdn;
void __iomem *db_reg;
- atomic_t refcount;
+ refcount_t refcount;
struct completion free;
struct hns_roce_mtr buf_mtr;
@@ -555,7 +554,6 @@ struct hns_roce_cmd_context {
struct hns_roce_cmdq {
struct dma_pool *pool;
- struct mutex hcr_mutex;
struct semaphore poll_sem;
/*
* Event mode: cmd register mutex protection,
@@ -642,7 +640,7 @@ struct hns_roce_qp {
u32 xrcdn;
- atomic_t refcount;
+ refcount_t refcount;
struct completion free;
struct hns_roce_sge sge;
@@ -745,6 +743,7 @@ struct hns_roce_caps {
u32 max_rq_sg;
u32 max_extend_sg;
u32 num_qps;
+ u32 num_pi_qps;
u32 reserved_qps;
int num_qpc_timer;
int num_cqc_timer;
@@ -854,8 +853,7 @@ struct hns_roce_caps {
u32 gmv_buf_pg_sz;
u32 gmv_hop_num;
u32 sl_num;
- u32 tsq_buf_pg_sz;
- u32 tpq_buf_pg_sz;
+ u32 llm_buf_pg_sz;
u32 chunk_sz; /* chunk size in non multihop mode */
u64 flags;
u16 default_ceq_max_cnt;
@@ -963,8 +961,8 @@ struct hns_roce_dev {
void __iomem *priv_addr;
struct hns_roce_cmdq cmd;
- struct hns_roce_bitmap pd_bitmap;
- struct hns_roce_bitmap xrcd_bitmap;
+ struct hns_roce_ida pd_ida;
+ struct hns_roce_ida xrcd_ida;
struct hns_roce_uar_table uar_table;
struct hns_roce_mr_table mr_table;
struct hns_roce_cq_table cq_table;
@@ -1052,7 +1050,7 @@ static inline void hns_roce_write64_k(__le32 val[2], void __iomem *dest)
static inline struct hns_roce_qp
*__hns_roce_qp_lookup(struct hns_roce_dev *hr_dev, u32 qpn)
{
- return xa_load(&hr_dev->qp_table_xa, qpn & (hr_dev->caps.num_qps - 1));
+ return xa_load(&hr_dev->qp_table_xa, qpn);
}
static inline void *hns_roce_buf_offset(struct hns_roce_buf *buf,
@@ -1062,14 +1060,18 @@ static inline void *hns_roce_buf_offset(struct hns_roce_buf *buf,
(offset & ((1 << buf->trunk_shift) - 1));
}
-static inline dma_addr_t hns_roce_buf_page(struct hns_roce_buf *buf, u32 idx)
+static inline dma_addr_t hns_roce_buf_dma_addr(struct hns_roce_buf *buf,
+ unsigned int offset)
{
- unsigned int offset = idx << buf->page_shift;
-
return buf->trunk_list[offset >> buf->trunk_shift].map +
(offset & ((1 << buf->trunk_shift) - 1));
}
+static inline dma_addr_t hns_roce_buf_page(struct hns_roce_buf *buf, u32 idx)
+{
+ return hns_roce_buf_dma_addr(buf, idx << buf->page_shift);
+}
+
#define hr_hw_page_align(x) ALIGN(x, 1 << HNS_HW_PAGE_SHIFT)
static inline u64 to_hr_hw_page_addr(u64 addr)
@@ -1141,33 +1143,24 @@ void hns_roce_mtr_destroy(struct hns_roce_dev *hr_dev,
int hns_roce_mtr_map(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
dma_addr_t *pages, unsigned int page_cnt);
-int hns_roce_init_pd_table(struct hns_roce_dev *hr_dev);
-int hns_roce_init_mr_table(struct hns_roce_dev *hr_dev);
+void hns_roce_init_pd_table(struct hns_roce_dev *hr_dev);
+void hns_roce_init_mr_table(struct hns_roce_dev *hr_dev);
void hns_roce_init_cq_table(struct hns_roce_dev *hr_dev);
-int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev);
+void hns_roce_init_qp_table(struct hns_roce_dev *hr_dev);
int hns_roce_init_srq_table(struct hns_roce_dev *hr_dev);
-int hns_roce_init_xrcd_table(struct hns_roce_dev *hr_dev);
+void hns_roce_init_xrcd_table(struct hns_roce_dev *hr_dev);
-void hns_roce_cleanup_pd_table(struct hns_roce_dev *hr_dev);
-void hns_roce_cleanup_mr_table(struct hns_roce_dev *hr_dev);
void hns_roce_cleanup_eq_table(struct hns_roce_dev *hr_dev);
void hns_roce_cleanup_cq_table(struct hns_roce_dev *hr_dev);
void hns_roce_cleanup_qp_table(struct hns_roce_dev *hr_dev);
void hns_roce_cleanup_srq_table(struct hns_roce_dev *hr_dev);
-void hns_roce_cleanup_xrcd_table(struct hns_roce_dev *hr_dev);
int hns_roce_bitmap_alloc(struct hns_roce_bitmap *bitmap, unsigned long *obj);
-void hns_roce_bitmap_free(struct hns_roce_bitmap *bitmap, unsigned long obj,
- int rr);
+void hns_roce_bitmap_free(struct hns_roce_bitmap *bitmap, unsigned long obj);
int hns_roce_bitmap_init(struct hns_roce_bitmap *bitmap, u32 num, u32 mask,
u32 reserved_bot, u32 resetrved_top);
void hns_roce_bitmap_cleanup(struct hns_roce_bitmap *bitmap);
void hns_roce_cleanup_bitmap(struct hns_roce_dev *hr_dev);
-int hns_roce_bitmap_alloc_range(struct hns_roce_bitmap *bitmap, int cnt,
- int align, unsigned long *obj);
-void hns_roce_bitmap_free_range(struct hns_roce_bitmap *bitmap,
- unsigned long obj, int cnt,
- int rr);
int hns_roce_create_ah(struct ib_ah *ah, struct rdma_ah_init_attr *init_attr,
struct ib_udata *udata);
@@ -1206,9 +1199,10 @@ struct hns_roce_buf *hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size,
u32 page_shift, u32 flags);
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 buf_cnt, struct hns_roce_buf *buf,
+ unsigned int page_shift);
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 buf_cnt, struct ib_umem *umem,
unsigned int page_shift);
int hns_roce_create_srq(struct ib_srq *srq,
@@ -1248,8 +1242,7 @@ int hns_roce_create_cq(struct ib_cq *ib_cq, const struct ib_cq_init_attr *attr,
struct ib_udata *udata);
int hns_roce_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata);
-int hns_roce_db_map_user(struct hns_roce_ucontext *context,
- struct ib_udata *udata, unsigned long virt,
+int hns_roce_db_map_user(struct hns_roce_ucontext *context, unsigned long virt,
struct hns_roce_db *db);
void hns_roce_db_unmap_user(struct hns_roce_ucontext *context,
struct hns_roce_db *db);
@@ -1259,6 +1252,7 @@ void hns_roce_free_db(struct hns_roce_dev *hr_dev, struct hns_roce_db *db);
void hns_roce_cq_completion(struct hns_roce_dev *hr_dev, u32 cqn);
void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type);
+void flush_cqe(struct hns_roce_dev *dev, struct hns_roce_qp *qp);
void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type);
void hns_roce_srq_event(struct hns_roce_dev *hr_dev, u32 srqn, int event_type);
u8 hns_get_gid_index(struct hns_roce_dev *hr_dev, u32 port, int gid_index);
diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.c b/drivers/infiniband/hw/hns/hns_roce_hem.c
index cfd2e1b60c7f..fa15d79eabb3 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hem.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hem.c
@@ -36,9 +36,6 @@
#include "hns_roce_hem.h"
#include "hns_roce_common.h"
-#define DMA_ADDR_T_SHIFT 12
-#define BT_BA_SHIFT 32
-
#define HEM_INDEX_BUF BIT(0)
#define HEM_INDEX_L0 BIT(1)
#define HEM_INDEX_L1 BIT(2)
@@ -227,8 +224,7 @@ int hns_roce_calc_hem_mhop(struct hns_roce_dev *hr_dev,
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)) /
- (chunk_size / table->obj_size);
+ table_idx = *obj / (chunk_size / table->obj_size);
switch (bt_num) {
case 3:
mhop->l2_idx = table_idx & (chunk_ba_num - 1);
@@ -271,7 +267,6 @@ static struct hns_roce_hem *hns_roce_alloc_hem(struct hns_roce_dev *hr_dev,
if (!hem)
return NULL;
- hem->refcount = 0;
INIT_LIST_HEAD(&hem->chunk_list);
order = get_order(hem_alloc_size);
@@ -338,81 +333,6 @@ void hns_roce_free_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem *hem)
kfree(hem);
}
-static int hns_roce_set_hem(struct hns_roce_dev *hr_dev,
- struct hns_roce_hem_table *table, unsigned long obj)
-{
- spinlock_t *lock = &hr_dev->bt_cmd_lock;
- struct device *dev = hr_dev->dev;
- struct hns_roce_hem_iter iter;
- void __iomem *bt_cmd;
- __le32 bt_cmd_val[2];
- __le32 bt_cmd_h = 0;
- unsigned long flags;
- __le32 bt_cmd_l;
- int ret = 0;
- u64 bt_ba;
- long end;
-
- /* Find the HEM(Hardware Entry Memory) entry */
- unsigned long i = (obj & (table->num_obj - 1)) /
- (table->table_chunk_size / table->obj_size);
-
- switch (table->type) {
- case HEM_TYPE_QPC:
- case HEM_TYPE_MTPT:
- case HEM_TYPE_CQC:
- case HEM_TYPE_SRQC:
- roce_set_field(bt_cmd_h, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M,
- ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, table->type);
- break;
- default:
- return ret;
- }
-
- roce_set_field(bt_cmd_h, ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_M,
- ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_S, obj);
- roce_set_bit(bt_cmd_h, ROCEE_BT_CMD_H_ROCEE_BT_CMD_S, 0);
- roce_set_bit(bt_cmd_h, ROCEE_BT_CMD_H_ROCEE_BT_CMD_HW_SYNS_S, 1);
-
- /* Currently iter only a chunk */
- for (hns_roce_hem_first(table->hem[i], &iter);
- !hns_roce_hem_last(&iter); hns_roce_hem_next(&iter)) {
- bt_ba = hns_roce_hem_addr(&iter) >> DMA_ADDR_T_SHIFT;
-
- spin_lock_irqsave(lock, flags);
-
- bt_cmd = hr_dev->reg_base + ROCEE_BT_CMD_H_REG;
-
- end = HW_SYNC_TIMEOUT_MSECS;
- while (end > 0) {
- 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 = cpu_to_le32(bt_ba);
- roce_set_field(bt_cmd_h, ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_M,
- ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_S,
- bt_ba >> BT_BA_SHIFT);
-
- bt_cmd_val[0] = bt_cmd_l;
- bt_cmd_val[1] = bt_cmd_h;
- hns_roce_write64_k(bt_cmd_val,
- hr_dev->reg_base + ROCEE_BT_CMD_L_REG);
- spin_unlock_irqrestore(lock, flags);
- }
-
- return ret;
-}
-
static int calc_hem_config(struct hns_roce_dev *hr_dev,
struct hns_roce_hem_table *table, unsigned long obj,
struct hns_roce_hem_mhop *mhop,
@@ -618,7 +538,7 @@ static int hns_roce_table_mhop_get(struct hns_roce_dev *hr_dev,
mutex_lock(&table->mutex);
if (table->hem[index.buf]) {
- ++table->hem[index.buf]->refcount;
+ refcount_inc(&table->hem[index.buf]->refcount);
goto out;
}
@@ -637,7 +557,7 @@ static int hns_roce_table_mhop_get(struct hns_roce_dev *hr_dev,
}
}
- ++table->hem[index.buf]->refcount;
+ refcount_set(&table->hem[index.buf]->refcount, 1);
goto out;
err_alloc:
@@ -657,13 +577,12 @@ int hns_roce_table_get(struct hns_roce_dev *hr_dev,
if (hns_roce_check_whether_mhop(hr_dev, table->type))
return hns_roce_table_mhop_get(hr_dev, table, obj);
- i = (obj & (table->num_obj - 1)) / (table->table_chunk_size /
- table->obj_size);
+ i = obj / (table->table_chunk_size / table->obj_size);
mutex_lock(&table->mutex);
if (table->hem[i]) {
- ++table->hem[i]->refcount;
+ refcount_inc(&table->hem[i]->refcount);
goto out;
}
@@ -678,7 +597,7 @@ int hns_roce_table_get(struct hns_roce_dev *hr_dev,
}
/* Set HEM base address(128K/page, pa) to Hardware */
- if (hns_roce_set_hem(hr_dev, table, obj)) {
+ if (hr_dev->hw->set_hem(hr_dev, table, obj, HEM_HOP_STEP_DIRECT)) {
hns_roce_free_hem(hr_dev, table->hem[i]);
table->hem[i] = NULL;
ret = -ENODEV;
@@ -686,7 +605,7 @@ int hns_roce_table_get(struct hns_roce_dev *hr_dev,
goto out;
}
- ++table->hem[i]->refcount;
+ refcount_set(&table->hem[i]->refcount, 1);
out:
mutex_unlock(&table->mutex);
return ret;
@@ -753,11 +672,11 @@ static void hns_roce_table_mhop_put(struct hns_roce_dev *hr_dev,
return;
}
- mutex_lock(&table->mutex);
- if (check_refcount && (--table->hem[index.buf]->refcount > 0)) {
- mutex_unlock(&table->mutex);
+ if (!check_refcount)
+ mutex_lock(&table->mutex);
+ else if (!refcount_dec_and_mutex_lock(&table->hem[index.buf]->refcount,
+ &table->mutex))
return;
- }
clear_mhop_hem(hr_dev, table, obj, &mhop, &index);
free_mhop_hem(hr_dev, table, &mhop, &index);
@@ -776,19 +695,17 @@ void hns_roce_table_put(struct hns_roce_dev *hr_dev,
return;
}
- i = (obj & (table->num_obj - 1)) /
- (table->table_chunk_size / table->obj_size);
+ i = obj / (table->table_chunk_size / table->obj_size);
- mutex_lock(&table->mutex);
+ if (!refcount_dec_and_mutex_lock(&table->hem[i]->refcount,
+ &table->mutex))
+ return;
- if (--table->hem[i]->refcount == 0) {
- /* Clear HEM base address */
- if (hr_dev->hw->clear_hem(hr_dev, table, obj, 0))
- dev_warn(dev, "Clear HEM base address failed.\n");
+ if (hr_dev->hw->clear_hem(hr_dev, table, obj, HEM_HOP_STEP_DIRECT))
+ dev_warn(dev, "failed to clear HEM base address.\n");
- hns_roce_free_hem(hr_dev, table->hem[i]);
- table->hem[i] = NULL;
- }
+ hns_roce_free_hem(hr_dev, table->hem[i]);
+ table->hem[i] = NULL;
mutex_unlock(&table->mutex);
}
@@ -816,8 +733,8 @@ void *hns_roce_table_find(struct hns_roce_dev *hr_dev,
if (!hns_roce_check_whether_mhop(hr_dev, table->type)) {
obj_per_chunk = table->table_chunk_size / table->obj_size;
- hem = table->hem[(obj & (table->num_obj - 1)) / obj_per_chunk];
- idx_offset = (obj & (table->num_obj - 1)) % obj_per_chunk;
+ hem = table->hem[obj / obj_per_chunk];
+ idx_offset = obj % obj_per_chunk;
dma_offset = offset = idx_offset * table->obj_size;
} else {
u32 seg_size = 64; /* 8 bytes per BA and 8 BA per segment */
@@ -834,8 +751,7 @@ void *hns_roce_table_find(struct hns_roce_dev *hr_dev,
hem_idx = i;
hem = table->hem[hem_idx];
- dma_offset = offset = (obj & (table->num_obj - 1)) * seg_size %
- mhop.bt_chunk_size;
+ dma_offset = offset = obj * seg_size % mhop.bt_chunk_size;
if (mhop.hop_num == 2)
dma_offset = offset = 0;
}
@@ -877,7 +793,7 @@ int hns_roce_init_hem_table(struct hns_roce_dev *hr_dev,
if (!hns_roce_check_whether_mhop(hr_dev, type)) {
table->table_chunk_size = hr_dev->caps.chunk_sz;
obj_per_chunk = table->table_chunk_size / obj_size;
- num_hem = (nobj + obj_per_chunk - 1) / obj_per_chunk;
+ num_hem = DIV_ROUND_UP(nobj, obj_per_chunk);
table->hem = kcalloc(num_hem, sizeof(*table->hem), GFP_KERNEL);
if (!table->hem)
@@ -899,8 +815,9 @@ int hns_roce_init_hem_table(struct hns_roce_dev *hr_dev,
hop_num = mhop.hop_num;
obj_per_chunk = buf_chunk_size / obj_size;
- num_hem = (nobj + obj_per_chunk - 1) / obj_per_chunk;
+ num_hem = DIV_ROUND_UP(nobj, obj_per_chunk);
bt_chunk_num = bt_chunk_size / BA_BYTE_LEN;
+
if (type >= HEM_TYPE_MTT)
num_bt_l0 = bt_chunk_num;
@@ -912,8 +829,7 @@ int hns_roce_init_hem_table(struct hns_roce_dev *hr_dev,
if (check_whether_bt_num_3(type, hop_num)) {
unsigned long num_bt_l1;
- num_bt_l1 = (num_hem + bt_chunk_num - 1) /
- bt_chunk_num;
+ num_bt_l1 = DIV_ROUND_UP(num_hem, bt_chunk_num);
table->bt_l1 = kcalloc(num_bt_l1,
sizeof(*table->bt_l1),
GFP_KERNEL);
@@ -945,7 +861,6 @@ int hns_roce_init_hem_table(struct hns_roce_dev *hr_dev,
table->type = type;
table->num_hem = num_hem;
- table->num_obj = nobj;
table->obj_size = obj_size;
table->lowmem = use_lowmem;
mutex_init(&table->mutex);
@@ -1053,7 +968,7 @@ void hns_roce_cleanup_hem(struct hns_roce_dev *hr_dev)
hns_roce_cleanup_hem_table(hr_dev, &hr_dev->mr_table.mtpt_table);
}
-struct roce_hem_item {
+struct hns_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;
@@ -1063,12 +978,18 @@ struct roce_hem_item {
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)
+/* All HEM items are linked in a tree structure */
+struct hns_roce_hem_head {
+ struct list_head branch[HNS_ROCE_MAX_BT_REGION];
+ struct list_head root;
+ struct list_head leaf;
+};
+
+static struct hns_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;
+ struct hns_roce_hem_item *hem;
hem = kzalloc(sizeof(*hem), GFP_KERNEL);
if (!hem)
@@ -1093,7 +1014,7 @@ static struct roce_hem_item *hem_list_alloc_item(struct hns_roce_dev *hr_dev,
}
static void hem_list_free_item(struct hns_roce_dev *hr_dev,
- struct roce_hem_item *hem, bool exist_bt)
+ struct hns_roce_hem_item *hem, bool exist_bt)
{
if (exist_bt)
dma_free_coherent(hr_dev->dev, hem->count * BA_BYTE_LEN,
@@ -1104,7 +1025,7 @@ static void hem_list_free_item(struct hns_roce_dev *hr_dev,
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;
+ struct hns_roce_hem_item *hem, *temp_hem;
list_for_each_entry_safe(hem, temp_hem, head, list) {
list_del(&hem->list);
@@ -1120,24 +1041,24 @@ static void hem_list_link_bt(struct hns_roce_dev *hr_dev, void *base_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,
+ struct hns_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,
+static inline bool hem_list_page_is_in_range(struct hns_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)
+static struct hns_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;
+ struct hns_roce_hem_item *hem, *temp_hem;
+ struct hns_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)) {
@@ -1161,7 +1082,7 @@ static bool hem_list_is_bottom_bt(int hopnum, int bt_level)
return bt_level >= (hopnum ? hopnum - 1 : hopnum);
}
-/**
+/*
* calc base address entries num
* @hopnum: num of mutihop addressing
* @bt_level: base address table level
@@ -1194,7 +1115,7 @@ static u32 hem_list_calc_ba_range(int hopnum, int bt_level, int unit)
return step;
}
-/**
+/*
* calc the root ba entries which could cover all regions
* @regions: buf region array
* @region_cnt: array size of @regions
@@ -1227,9 +1148,9 @@ static int hem_list_alloc_mid_bt(struct hns_roce_dev *hr_dev,
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 hns_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;
+ struct hns_roce_hem_item *cur, *pre;
const int hopnum = r->hopnum;
int start_aligned;
int distance;
@@ -1307,56 +1228,96 @@ err_exit:
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)
+static struct hns_roce_hem_item *
+alloc_root_hem(struct hns_roce_dev *hr_dev, int unit, int *max_ba_num,
+ const struct hns_roce_buf_region *regions, int region_cnt)
{
- struct list_head temp_list[HNS_ROCE_MAX_BT_REGION];
- struct roce_hem_item *hem, *temp_hem, *root_hem;
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;
+ struct hns_roce_hem_item *hem;
int ba_num;
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;
ba_num = hns_roce_hem_list_calc_root_ba(regions, region_cnt, unit);
if (ba_num < 1)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
if (ba_num > unit)
- return -ENOBUFS;
+ return ERR_PTR(-ENOBUFS);
- ba_num = min_t(int, ba_num, unit);
- INIT_LIST_HEAD(&temp_root);
- offset = r->offset;
+ offset = regions[0].offset;
/* indicate to last region */
r = &regions[region_cnt - 1];
- root_hem = hem_list_alloc_item(hr_dev, offset, r->offset + r->count - 1,
- ba_num, true, 0);
- if (!root_hem)
+ hem = hem_list_alloc_item(hr_dev, offset, r->offset + r->count - 1,
+ ba_num, true, 0);
+ if (!hem)
+ return ERR_PTR(-ENOMEM);
+
+ *max_ba_num = ba_num;
+
+ return hem;
+}
+
+static int alloc_fake_root_bt(struct hns_roce_dev *hr_dev, void *cpu_base,
+ u64 phy_base, const struct hns_roce_buf_region *r,
+ struct list_head *branch_head,
+ struct list_head *leaf_head)
+{
+ struct hns_roce_hem_item *hem;
+
+ hem = hem_list_alloc_item(hr_dev, r->offset, r->offset + r->count - 1,
+ r->count, false, 0);
+ if (!hem)
return -ENOMEM;
- list_add(&root_hem->list, &temp_root);
- hem_list->root_ba = root_hem->dma_addr;
+ hem_list_assign_bt(hr_dev, hem, cpu_base, phy_base);
+ list_add(&hem->list, branch_head);
+ list_add(&hem->sibling, leaf_head);
- INIT_LIST_HEAD(&temp_btm);
- for (i = 0; i < region_cnt; i++)
- INIT_LIST_HEAD(&temp_list[i]);
+ return r->count;
+}
+
+static int setup_middle_bt(struct hns_roce_dev *hr_dev, void *cpu_base,
+ int unit, const struct hns_roce_buf_region *r,
+ const struct list_head *branch_head)
+{
+ struct hns_roce_hem_item *hem, *temp_hem;
+ int total = 0;
+ int offset;
+ int step;
+
+ step = hem_list_calc_ba_range(r->hopnum, 1, unit);
+ if (step < 1)
+ return -EINVAL;
+
+ /* if exist mid bt, link L1 to L0 */
+ list_for_each_entry_safe(hem, temp_hem, branch_head, list) {
+ offset = (hem->start - r->offset) / step * BA_BYTE_LEN;
+ hem_list_link_bt(hr_dev, cpu_base + offset, hem->dma_addr);
+ total++;
+ }
+
+ return total;
+}
+
+static int
+setup_root_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem_list *hem_list,
+ int unit, int max_ba_num, struct hns_roce_hem_head *head,
+ const struct hns_roce_buf_region *regions, int region_cnt)
+{
+ const struct hns_roce_buf_region *r;
+ struct hns_roce_hem_item *root_hem;
+ void *cpu_base;
+ u64 phy_base;
+ int i, total;
+ int ret;
+
+ root_hem = list_first_entry(&head->root,
+ struct hns_roce_hem_item, list);
+ if (!root_hem)
+ return -ENOMEM;
total = 0;
- for (i = 0; i < region_cnt && total < ba_num; i++) {
+ for (i = 0; i < region_cnt && total < max_ba_num; i++) {
r = &regions[i];
if (!r->count)
continue;
@@ -1368,48 +1329,64 @@ static int hem_list_alloc_root_bt(struct hns_roce_dev *hr_dev,
/* 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 - r->offset) / step *
- BA_BYTE_LEN;
- hem_list_link_bt(hr_dev, cpu_base + offset,
- hem->dma_addr);
- total++;
- }
- }
+ if (hem_list_is_bottom_bt(r->hopnum, 0))
+ ret = alloc_fake_root_bt(hr_dev, cpu_base, phy_base, r,
+ &head->branch[i], &head->leaf);
+ else
+ ret = setup_middle_bt(hr_dev, cpu_base, unit, r,
+ &hem_list->mid_bt[i][1]);
+
+ if (ret < 0)
+ return ret;
+
+ total += ret;
}
- list_splice(&temp_btm, &hem_list->btm_bt);
- list_splice(&temp_root, &hem_list->root_bt);
+ list_splice(&head->leaf, &hem_list->btm_bt);
+ list_splice(&head->root, &hem_list->root_bt);
for (i = 0; i < region_cnt; i++)
- list_splice(&temp_list[i], &hem_list->mid_bt[i][0]);
+ list_splice(&head->branch[i], &hem_list->mid_bt[i][0]);
return 0;
+}
-err_exit:
+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 hns_roce_hem_item *root_hem;
+ struct hns_roce_hem_head head;
+ int max_ba_num;
+ int ret;
+ int i;
+
+ root_hem = hem_list_search_item(&hem_list->root_bt, regions[0].offset);
+ if (root_hem)
+ return 0;
+
+ max_ba_num = 0;
+ root_hem = alloc_root_hem(hr_dev, unit, &max_ba_num, regions,
+ region_cnt);
+ if (IS_ERR(root_hem))
+ return PTR_ERR(root_hem);
+
+ /* List head for storing all allocated HEM items */
+ INIT_LIST_HEAD(&head.root);
+ INIT_LIST_HEAD(&head.leaf);
for (i = 0; i < region_cnt; i++)
- hem_list_free_all(hr_dev, &temp_list[i], false);
+ INIT_LIST_HEAD(&head.branch[i]);
- hem_list_free_all(hr_dev, &temp_root, true);
+ hem_list->root_ba = root_hem->dma_addr;
+ list_add(&root_hem->list, &head.root);
+ ret = setup_root_hem(hr_dev, hem_list, unit, max_ba_num, &head, regions,
+ region_cnt);
+ if (ret) {
+ for (i = 0; i < region_cnt; i++)
+ hem_list_free_all(hr_dev, &head.branch[i], false);
+
+ hem_list_free_all(hr_dev, &head.root, true);
+ }
return ret;
}
@@ -1495,7 +1472,7 @@ void *hns_roce_hem_list_find_mtt(struct hns_roce_dev *hr_dev,
int offset, int *mtt_cnt, u64 *phy_addr)
{
struct list_head *head = &hem_list->btm_bt;
- struct roce_hem_item *hem, *temp_hem;
+ struct hns_roce_hem_item *hem, *temp_hem;
void *cpu_base = NULL;
u64 phy_base = 0;
int nr = 0;
diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.h b/drivers/infiniband/hw/hns/hns_roce_hem.h
index 13fdeb3274e7..2d84a6b3f05d 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hem.h
+++ b/drivers/infiniband/hw/hns/hns_roce_hem.h
@@ -34,9 +34,7 @@
#ifndef _HNS_ROCE_HEM_H
#define _HNS_ROCE_HEM_H
-#define HW_SYNC_SLEEP_TIME_INTERVAL 20
-#define HW_SYNC_TIMEOUT_MSECS (25 * HW_SYNC_SLEEP_TIME_INTERVAL)
-#define BT_CMD_SYNC_SHIFT 31
+#define HEM_HOP_STEP_DIRECT 0xff
enum {
/* MAP HEM(Hardware Entry Memory) */
@@ -74,11 +72,6 @@ enum {
(type >= HEM_TYPE_MTT && hop_num == 1) || \
(type >= HEM_TYPE_MTT && hop_num == HNS_ROCE_HOP_NUM_0))
-enum {
- HNS_ROCE_HEM_PAGE_SHIFT = 12,
- HNS_ROCE_HEM_PAGE_SIZE = 1 << HNS_ROCE_HEM_PAGE_SHIFT,
-};
-
struct hns_roce_hem_chunk {
struct list_head list;
int npages;
@@ -88,8 +81,8 @@ struct hns_roce_hem_chunk {
};
struct hns_roce_hem {
- struct list_head chunk_list;
- int refcount;
+ struct list_head chunk_list;
+ refcount_t refcount;
};
struct hns_roce_hem_iter {
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
index 620acf66b22c..a3305d196675 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c
@@ -462,6 +462,81 @@ static void hns_roce_set_db_event_mode(struct hns_roce_dev *hr_dev,
roce_write(hr_dev, ROCEE_GLB_CFG_REG, val);
}
+static int hns_roce_v1_set_hem(struct hns_roce_dev *hr_dev,
+ struct hns_roce_hem_table *table, int obj,
+ int step_idx)
+{
+ spinlock_t *lock = &hr_dev->bt_cmd_lock;
+ struct device *dev = hr_dev->dev;
+ struct hns_roce_hem_iter iter;
+ void __iomem *bt_cmd;
+ __le32 bt_cmd_val[2];
+ __le32 bt_cmd_h = 0;
+ unsigned long flags;
+ __le32 bt_cmd_l;
+ int ret = 0;
+ u64 bt_ba;
+ long end;
+
+ /* Find the HEM(Hardware Entry Memory) entry */
+ unsigned long i = obj / (table->table_chunk_size / table->obj_size);
+
+ switch (table->type) {
+ case HEM_TYPE_QPC:
+ case HEM_TYPE_MTPT:
+ case HEM_TYPE_CQC:
+ case HEM_TYPE_SRQC:
+ roce_set_field(bt_cmd_h, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, table->type);
+ break;
+ default:
+ return ret;
+ }
+
+ roce_set_field(bt_cmd_h, ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_S, obj);
+ roce_set_bit(bt_cmd_h, ROCEE_BT_CMD_H_ROCEE_BT_CMD_S, 0);
+ roce_set_bit(bt_cmd_h, ROCEE_BT_CMD_H_ROCEE_BT_CMD_HW_SYNS_S, 1);
+
+ /* Currently iter only a chunk */
+ for (hns_roce_hem_first(table->hem[i], &iter);
+ !hns_roce_hem_last(&iter); hns_roce_hem_next(&iter)) {
+ bt_ba = hns_roce_hem_addr(&iter) >> HNS_HW_PAGE_SHIFT;
+
+ spin_lock_irqsave(lock, flags);
+
+ bt_cmd = hr_dev->reg_base + ROCEE_BT_CMD_H_REG;
+
+ end = HW_SYNC_TIMEOUT_MSECS;
+ while (end > 0) {
+ 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 = cpu_to_le32(bt_ba);
+ roce_set_field(bt_cmd_h, ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_M,
+ ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_S,
+ upper_32_bits(bt_ba));
+
+ bt_cmd_val[0] = bt_cmd_l;
+ bt_cmd_val[1] = bt_cmd_h;
+ hns_roce_write64_k(bt_cmd_val,
+ hr_dev->reg_base + ROCEE_BT_CMD_L_REG);
+ spin_unlock_irqrestore(lock, flags);
+ }
+
+ return ret;
+}
+
static void hns_roce_set_db_ext_mode(struct hns_roce_dev *hr_dev, u32 sdb_mode,
u32 odb_mode)
{
@@ -1123,8 +1198,7 @@ free_mr:
dev_dbg(dev, "Free mr 0x%x use 0x%x us.\n",
mr->key, jiffies_to_usecs(jiffies) - jiffies_to_usecs(start));
- hns_roce_bitmap_free(&hr_dev->mr_table.mtpt_bitmap,
- key_to_hw_index(mr->key), 0);
+ ida_free(&hr_dev->mr_table.mtpt_ida.ida, (int)key_to_hw_index(mr->key));
hns_roce_mtr_destroy(hr_dev, &mr->pbl_mtr);
kfree(mr);
@@ -4352,6 +4426,7 @@ static const struct hns_roce_hw hns_roce_hw_v1 = {
.set_mtu = hns_roce_v1_set_mtu,
.write_mtpt = hns_roce_v1_write_mtpt,
.write_cqc = hns_roce_v1_write_cqc,
+ .set_hem = hns_roce_v1_set_hem,
.clear_hem = hns_roce_v1_clear_hem,
.modify_qp = hns_roce_v1_modify_qp,
.dereg_mr = hns_roce_v1_dereg_mr,
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h
index 84383236e47d..60fdcbae6729 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h
@@ -1085,6 +1085,11 @@ struct hns_roce_db_table {
struct hns_roce_ext_db *ext_db;
};
+#define HW_SYNC_SLEEP_TIME_INTERVAL 20
+#define HW_SYNC_TIMEOUT_MSECS (25 * HW_SYNC_SLEEP_TIME_INTERVAL)
+#define BT_CMD_SYNC_SHIFT 31
+#define HNS_ROCE_BA_SIZE (32 * 4096)
+
struct hns_roce_bt_table {
struct hns_roce_buf_list qpc_buf;
struct hns_roce_buf_list mtpt_buf;
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
index 7652dafe32ec..594d4cef31b3 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
@@ -105,16 +105,12 @@ static void set_frmr_seg(struct hns_roce_v2_rc_send_wqe *rc_sq_wqe,
u64 pbl_ba;
/* use ib_access_flags */
- roce_set_bit(fseg->byte_40, V2_RC_FRMR_WQE_BYTE_40_BIND_EN_S,
- !!(wr->access & IB_ACCESS_MW_BIND));
- roce_set_bit(fseg->byte_40, V2_RC_FRMR_WQE_BYTE_40_ATOMIC_S,
- !!(wr->access & IB_ACCESS_REMOTE_ATOMIC));
- roce_set_bit(fseg->byte_40, V2_RC_FRMR_WQE_BYTE_40_RR_S,
- !!(wr->access & IB_ACCESS_REMOTE_READ));
- roce_set_bit(fseg->byte_40, V2_RC_FRMR_WQE_BYTE_40_RW_S,
- !!(wr->access & IB_ACCESS_REMOTE_WRITE));
- roce_set_bit(fseg->byte_40, V2_RC_FRMR_WQE_BYTE_40_LW_S,
- !!(wr->access & IB_ACCESS_LOCAL_WRITE));
+ hr_reg_write_bool(fseg, FRMR_BIND_EN, wr->access & IB_ACCESS_MW_BIND);
+ hr_reg_write_bool(fseg, FRMR_ATOMIC,
+ wr->access & IB_ACCESS_REMOTE_ATOMIC);
+ hr_reg_write_bool(fseg, FRMR_RR, wr->access & IB_ACCESS_REMOTE_READ);
+ hr_reg_write_bool(fseg, FRMR_RW, wr->access & IB_ACCESS_REMOTE_WRITE);
+ hr_reg_write_bool(fseg, FRMR_LW, wr->access & IB_ACCESS_LOCAL_WRITE);
/* Data structure reuse may lead to confusion */
pbl_ba = mr->pbl_mtr.hem_cfg.root_ba;
@@ -126,11 +122,10 @@ static void set_frmr_seg(struct hns_roce_v2_rc_send_wqe *rc_sq_wqe,
rc_sq_wqe->rkey = cpu_to_le32(wr->key);
rc_sq_wqe->va = cpu_to_le64(wr->mr->iova);
- fseg->pbl_size = cpu_to_le32(mr->npages);
- roce_set_field(fseg->byte_40, V2_RC_FRMR_WQE_BYTE_40_PBL_BUF_PG_SZ_M,
- V2_RC_FRMR_WQE_BYTE_40_PBL_BUF_PG_SZ_S,
- to_hr_hw_page_shift(mr->pbl_mtr.hem_cfg.buf_pg_shift));
- roce_set_bit(fseg->byte_40, V2_RC_FRMR_WQE_BYTE_40_BLK_MODE_S, 0);
+ hr_reg_write(fseg, FRMR_PBL_SIZE, mr->npages);
+ hr_reg_write(fseg, FRMR_PBL_BUF_PG_SZ,
+ to_hr_hw_page_shift(mr->pbl_mtr.hem_cfg.buf_pg_shift));
+ hr_reg_clear(fseg, FRMR_BLK_MODE);
}
static void set_atomic_seg(const struct ib_send_wr *wr,
@@ -274,8 +269,6 @@ static int set_rc_inl(struct hns_roce_qp *qp, const struct ib_send_wr *wr,
dseg += sizeof(struct hns_roce_v2_rc_send_wqe);
- roce_set_bit(rc_sq_wqe->byte_4, V2_RC_SEND_WQE_BYTE_4_INLINE_S, 1);
-
if (msg_len <= HNS_ROCE_V2_MAX_RC_INL_INN_SZ) {
roce_set_bit(rc_sq_wqe->byte_20,
V2_RC_SEND_WQE_BYTE_20_INL_TYPE_S, 0);
@@ -320,6 +313,8 @@ static int set_rwqe_data_seg(struct ib_qp *ibqp, const struct ib_send_wr *wr,
V2_RC_SEND_WQE_BYTE_20_MSG_START_SGE_IDX_S,
(*sge_ind) & (qp->sge.sge_cnt - 1));
+ roce_set_bit(rc_sq_wqe->byte_4, V2_RC_SEND_WQE_BYTE_4_INLINE_S,
+ !!(wr->send_flags & IB_SEND_INLINE));
if (wr->send_flags & IB_SEND_INLINE)
return set_rc_inl(qp, wr, rc_sq_wqe, sge_ind);
@@ -629,32 +624,15 @@ static inline int set_rc_wqe(struct hns_roce_qp *qp,
static inline void update_sq_db(struct hns_roce_dev *hr_dev,
struct hns_roce_qp *qp)
{
- /*
- * Hip08 hardware cannot flush the WQEs in SQ if the QP state
- * gets into errored mode. Hence, as a workaround to this
- * hardware limitation, driver needs to assist in flushing. But
- * the flushing operation uses mailbox to convey the QP state to
- * the hardware and which can sleep due to the mutex protection
- * around the mailbox calls. Hence, use the deferred flush for
- * now.
- */
if (unlikely(qp->state == IB_QPS_ERR)) {
- if (!test_and_set_bit(HNS_ROCE_FLUSH_FLAG, &qp->flush_flag))
- init_flush_work(hr_dev, qp);
+ flush_cqe(hr_dev, qp);
} else {
struct hns_roce_v2_db sq_db = {};
- roce_set_field(sq_db.byte_4, V2_DB_TAG_M, V2_DB_TAG_S,
- qp->doorbell_qpn);
- roce_set_field(sq_db.byte_4, V2_DB_CMD_M, V2_DB_CMD_S,
- HNS_ROCE_V2_SQ_DB);
-
- /* indicates data on new BAR, 0 : SQ doorbell, 1 : DWQE */
- roce_set_bit(sq_db.byte_4, V2_DB_FLAG_S, 0);
- roce_set_field(sq_db.parameter, V2_DB_PRODUCER_IDX_M,
- V2_DB_PRODUCER_IDX_S, qp->sq.head);
- roce_set_field(sq_db.parameter, V2_DB_SL_M, V2_DB_SL_S,
- qp->sl);
+ hr_reg_write(&sq_db, DB_TAG, qp->doorbell_qpn);
+ hr_reg_write(&sq_db, DB_CMD, HNS_ROCE_V2_SQ_DB);
+ hr_reg_write(&sq_db, DB_PI, qp->sq.head);
+ hr_reg_write(&sq_db, DB_SL, qp->sl);
hns_roce_write64(hr_dev, (__le32 *)&sq_db, qp->sq.db_reg);
}
@@ -663,18 +641,8 @@ static inline void update_sq_db(struct hns_roce_dev *hr_dev,
static inline void update_rq_db(struct hns_roce_dev *hr_dev,
struct hns_roce_qp *qp)
{
- /*
- * Hip08 hardware cannot flush the WQEs in RQ if the QP state
- * gets into errored mode. Hence, as a workaround to this
- * hardware limitation, driver needs to assist in flushing. But
- * the flushing operation uses mailbox to convey the QP state to
- * the hardware and which can sleep due to the mutex protection
- * around the mailbox calls. Hence, use the deferred flush for
- * now.
- */
if (unlikely(qp->state == IB_QPS_ERR)) {
- if (!test_and_set_bit(HNS_ROCE_FLUSH_FLAG, &qp->flush_flag))
- init_flush_work(hr_dev, qp);
+ flush_cqe(hr_dev, qp);
} else {
if (likely(qp->en_flags & HNS_ROCE_QP_CAP_RQ_RECORD_DB)) {
*qp->rdb.db_record =
@@ -682,12 +650,9 @@ static inline void update_rq_db(struct hns_roce_dev *hr_dev,
} else {
struct hns_roce_v2_db rq_db = {};
- roce_set_field(rq_db.byte_4, V2_DB_TAG_M, V2_DB_TAG_S,
- qp->qpn);
- roce_set_field(rq_db.byte_4, V2_DB_CMD_M, V2_DB_CMD_S,
- HNS_ROCE_V2_RQ_DB);
- roce_set_field(rq_db.parameter, V2_DB_PRODUCER_IDX_M,
- V2_DB_PRODUCER_IDX_S, qp->rq.head);
+ hr_reg_write(&rq_db, DB_TAG, qp->qpn);
+ hr_reg_write(&rq_db, DB_CMD, HNS_ROCE_V2_RQ_DB);
+ hr_reg_write(&rq_db, DB_PI, qp->rq.head);
hns_roce_write64(hr_dev, (__le32 *)&rq_db,
qp->rq.db_reg);
@@ -775,10 +740,10 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp,
~(((qp->sq.head + nreq) >> ilog2(qp->sq.wqe_cnt)) & 0x1);
/* Corresponding to the QP type, wqe process separately */
- if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_UD)
- ret = set_ud_wqe(qp, wr, wqe, &sge_idx, owner_bit);
- else if (ibqp->qp_type == IB_QPT_RC)
+ if (ibqp->qp_type == IB_QPT_RC)
ret = set_rc_wqe(qp, wr, wqe, &sge_idx, owner_bit);
+ else
+ ret = set_ud_wqe(qp, wr, wqe, &sge_idx, owner_bit);
if (unlikely(ret)) {
*bad_wr = wr;
@@ -791,8 +756,7 @@ out:
qp->sq.head += nreq;
qp->next_sge = sge_idx;
- if (nreq == 1 && qp->sq.head == qp->sq.tail + 1 &&
- (qp->en_flags & HNS_ROCE_QP_CAP_DIRECT_WQE))
+ if (nreq == 1 && (qp->en_flags & HNS_ROCE_QP_CAP_DIRECT_WQE))
write_dwqe(hr_dev, qp, wqe);
else
update_sq_db(hr_dev, qp);
@@ -1005,6 +969,13 @@ static void fill_wqe_idx(struct hns_roce_srq *srq, unsigned int wqe_idx)
idx_que->head++;
}
+static void update_srq_db(struct hns_roce_v2_db *db, struct hns_roce_srq *srq)
+{
+ hr_reg_write(db, DB_TAG, srq->srqn);
+ hr_reg_write(db, DB_CMD, HNS_ROCE_V2_SRQ_DB);
+ hr_reg_write(db, DB_PI, srq->idx_que.head);
+}
+
static int hns_roce_v2_post_srq_recv(struct ib_srq *ibsrq,
const struct ib_recv_wr *wr,
const struct ib_recv_wr **bad_wr)
@@ -1042,12 +1013,7 @@ static int hns_roce_v2_post_srq_recv(struct ib_srq *ibsrq,
}
if (likely(nreq)) {
- roce_set_field(srq_db.byte_4, V2_DB_TAG_M, V2_DB_TAG_S,
- srq->srqn);
- roce_set_field(srq_db.byte_4, V2_DB_CMD_M, V2_DB_CMD_S,
- HNS_ROCE_V2_SRQ_DB);
- roce_set_field(srq_db.parameter, V2_DB_PRODUCER_IDX_M,
- V2_DB_PRODUCER_IDX_S, srq->idx_que.head);
+ update_srq_db(&srq_db, srq);
hns_roce_write64(hr_dev, (__le32 *)&srq_db, srq->db_reg);
}
@@ -1210,8 +1176,6 @@ static int hns_roce_alloc_cmq_desc(struct hns_roce_dev *hr_dev,
kfree(ring->desc);
ring->desc = NULL;
- dev_err_ratelimited(hr_dev->dev,
- "failed to map cmq desc addr.\n");
return -ENOMEM;
}
@@ -1229,44 +1193,32 @@ static void hns_roce_free_cmq_desc(struct hns_roce_dev *hr_dev,
kfree(ring->desc);
}
-static int hns_roce_init_cmq_ring(struct hns_roce_dev *hr_dev, bool ring_type)
+static int init_csq(struct hns_roce_dev *hr_dev,
+ struct hns_roce_v2_cmq_ring *csq)
{
- struct hns_roce_v2_priv *priv = hr_dev->priv;
- struct hns_roce_v2_cmq_ring *ring = (ring_type == TYPE_CSQ) ?
- &priv->cmq.csq : &priv->cmq.crq;
+ dma_addr_t dma;
+ int ret;
- ring->flag = ring_type;
- ring->head = 0;
+ csq->desc_num = CMD_CSQ_DESC_NUM;
+ spin_lock_init(&csq->lock);
+ csq->flag = TYPE_CSQ;
+ csq->head = 0;
- return hns_roce_alloc_cmq_desc(hr_dev, ring);
-}
+ ret = hns_roce_alloc_cmq_desc(hr_dev, csq);
+ if (ret)
+ return ret;
-static void hns_roce_cmq_init_regs(struct hns_roce_dev *hr_dev, bool ring_type)
-{
- struct hns_roce_v2_priv *priv = hr_dev->priv;
- struct hns_roce_v2_cmq_ring *ring = (ring_type == TYPE_CSQ) ?
- &priv->cmq.csq : &priv->cmq.crq;
- dma_addr_t dma = ring->desc_dma_addr;
-
- if (ring_type == TYPE_CSQ) {
- roce_write(hr_dev, ROCEE_TX_CMQ_BASEADDR_L_REG, (u32)dma);
- roce_write(hr_dev, ROCEE_TX_CMQ_BASEADDR_H_REG,
- upper_32_bits(dma));
- roce_write(hr_dev, ROCEE_TX_CMQ_DEPTH_REG,
- (u32)ring->desc_num >> HNS_ROCE_CMQ_DESC_NUM_S);
-
- /* Make sure to write tail first and then head */
- roce_write(hr_dev, ROCEE_TX_CMQ_TAIL_REG, 0);
- roce_write(hr_dev, ROCEE_TX_CMQ_HEAD_REG, 0);
- } else {
- roce_write(hr_dev, ROCEE_RX_CMQ_BASEADDR_L_REG, (u32)dma);
- roce_write(hr_dev, ROCEE_RX_CMQ_BASEADDR_H_REG,
- upper_32_bits(dma));
- roce_write(hr_dev, ROCEE_RX_CMQ_DEPTH_REG,
- (u32)ring->desc_num >> HNS_ROCE_CMQ_DESC_NUM_S);
- roce_write(hr_dev, ROCEE_RX_CMQ_HEAD_REG, 0);
- roce_write(hr_dev, ROCEE_RX_CMQ_TAIL_REG, 0);
- }
+ dma = csq->desc_dma_addr;
+ roce_write(hr_dev, ROCEE_TX_CMQ_BASEADDR_L_REG, lower_32_bits(dma));
+ roce_write(hr_dev, ROCEE_TX_CMQ_BASEADDR_H_REG, upper_32_bits(dma));
+ roce_write(hr_dev, ROCEE_TX_CMQ_DEPTH_REG,
+ (u32)csq->desc_num >> HNS_ROCE_CMQ_DESC_NUM_S);
+
+ /* Make sure to write CI first and then PI */
+ roce_write(hr_dev, ROCEE_TX_CMQ_CI_REG, 0);
+ roce_write(hr_dev, ROCEE_TX_CMQ_PI_REG, 0);
+
+ return 0;
}
static int hns_roce_v2_cmq_init(struct hns_roce_dev *hr_dev)
@@ -1274,43 +1226,11 @@ static int hns_roce_v2_cmq_init(struct hns_roce_dev *hr_dev)
struct hns_roce_v2_priv *priv = hr_dev->priv;
int ret;
- /* Setup the queue entries for command queue */
- priv->cmq.csq.desc_num = CMD_CSQ_DESC_NUM;
- priv->cmq.crq.desc_num = CMD_CRQ_DESC_NUM;
-
- /* Setup the lock for command queue */
- spin_lock_init(&priv->cmq.csq.lock);
- spin_lock_init(&priv->cmq.crq.lock);
-
- /* Setup Tx write back timeout */
priv->cmq.tx_timeout = HNS_ROCE_CMQ_TX_TIMEOUT;
- /* Init CSQ */
- ret = hns_roce_init_cmq_ring(hr_dev, TYPE_CSQ);
- if (ret) {
- dev_err_ratelimited(hr_dev->dev,
- "failed to init CSQ, ret = %d.\n", ret);
- return ret;
- }
-
- /* Init CRQ */
- ret = hns_roce_init_cmq_ring(hr_dev, TYPE_CRQ);
- if (ret) {
- dev_err_ratelimited(hr_dev->dev,
- "failed to init CRQ, ret = %d.\n", ret);
- goto err_crq;
- }
-
- /* Init CSQ REG */
- hns_roce_cmq_init_regs(hr_dev, TYPE_CSQ);
-
- /* Init CRQ REG */
- hns_roce_cmq_init_regs(hr_dev, TYPE_CRQ);
-
- return 0;
-
-err_crq:
- hns_roce_free_cmq_desc(hr_dev, &priv->cmq.csq);
+ ret = init_csq(hr_dev, &priv->cmq.csq);
+ if (ret)
+ dev_err(hr_dev->dev, "failed to init CSQ, ret = %d.\n", ret);
return ret;
}
@@ -1320,7 +1240,6 @@ static void hns_roce_v2_cmq_exit(struct hns_roce_dev *hr_dev)
struct hns_roce_v2_priv *priv = hr_dev->priv;
hns_roce_free_cmq_desc(hr_dev, &priv->cmq.csq);
- hns_roce_free_cmq_desc(hr_dev, &priv->cmq.crq);
}
static void hns_roce_cmq_setup_basic_desc(struct hns_roce_cmq_desc *desc,
@@ -1339,7 +1258,7 @@ static void hns_roce_cmq_setup_basic_desc(struct hns_roce_cmq_desc *desc,
static int hns_roce_cmq_csq_done(struct hns_roce_dev *hr_dev)
{
- u32 tail = roce_read(hr_dev, ROCEE_TX_CMQ_TAIL_REG);
+ u32 tail = roce_read(hr_dev, ROCEE_TX_CMQ_CI_REG);
struct hns_roce_v2_priv *priv = hr_dev->priv;
return tail == priv->cmq.csq.head;
@@ -1367,7 +1286,7 @@ static int __hns_roce_cmq_send(struct hns_roce_dev *hr_dev,
}
/* Write to hardware */
- roce_write(hr_dev, ROCEE_TX_CMQ_HEAD_REG, csq->head);
+ roce_write(hr_dev, ROCEE_TX_CMQ_PI_REG, csq->head);
/* If the command is sync, wait for the firmware to write back,
* if multi descriptors to be sent, use the first one to check
@@ -1398,7 +1317,7 @@ static int __hns_roce_cmq_send(struct hns_roce_dev *hr_dev,
}
} else {
/* FW/HW reset or incorrect number of desc */
- tail = roce_read(hr_dev, ROCEE_TX_CMQ_TAIL_REG);
+ tail = roce_read(hr_dev, ROCEE_TX_CMQ_CI_REG);
dev_warn(hr_dev->dev, "CMDQ move tail from %d to %d\n",
csq->head, tail);
csq->head = tail;
@@ -1620,6 +1539,22 @@ static void hns_roce_function_clear(struct hns_roce_dev *hr_dev)
}
}
+static int hns_roce_clear_extdb_list_info(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_cmq_desc desc;
+ int ret;
+
+ hns_roce_cmq_setup_basic_desc(&desc, HNS_ROCE_OPC_CLEAR_EXTDB_LIST_INFO,
+ false);
+ ret = hns_roce_cmq_send(hr_dev, &desc, 1);
+ if (ret)
+ ibdev_err(&hr_dev->ib_dev,
+ "failed to clear extended doorbell info, ret = %d.\n",
+ ret);
+
+ return ret;
+}
+
static int hns_roce_query_fw_ver(struct hns_roce_dev *hr_dev)
{
struct hns_roce_query_fw_info *resp;
@@ -1723,17 +1658,30 @@ static int load_func_res_caps(struct hns_roce_dev *hr_dev, bool is_vf)
return 0;
}
-static int hns_roce_query_pf_resource(struct hns_roce_dev *hr_dev)
+static int load_ext_cfg_caps(struct hns_roce_dev *hr_dev, bool is_vf)
{
- return load_func_res_caps(hr_dev, false);
-}
+ struct hns_roce_cmq_desc desc;
+ struct hns_roce_cmq_req *req = (struct hns_roce_cmq_req *)desc.data;
+ struct hns_roce_caps *caps = &hr_dev->caps;
+ u32 func_num, qp_num;
+ int ret;
-static int hns_roce_query_vf_resource(struct hns_roce_dev *hr_dev)
-{
- return load_func_res_caps(hr_dev, true);
+ hns_roce_cmq_setup_basic_desc(&desc, HNS_ROCE_OPC_EXT_CFG, true);
+ ret = hns_roce_cmq_send(hr_dev, &desc, 1);
+ if (ret)
+ return ret;
+
+ func_num = is_vf ? 1 : max_t(u32, 1, hr_dev->func_num);
+ qp_num = hr_reg_read(req, EXT_CFG_QP_PI_NUM) / func_num;
+ caps->num_pi_qps = round_down(qp_num, HNS_ROCE_QP_BANK_NUM);
+
+ qp_num = hr_reg_read(req, EXT_CFG_QP_NUM) / func_num;
+ caps->num_qps = round_down(qp_num, HNS_ROCE_QP_BANK_NUM);
+
+ return 0;
}
-static int hns_roce_query_pf_timer_resource(struct hns_roce_dev *hr_dev)
+static int load_pf_timer_res_caps(struct hns_roce_dev *hr_dev)
{
struct hns_roce_cmq_desc desc;
struct hns_roce_cmq_req *req = (struct hns_roce_cmq_req *)desc.data;
@@ -1753,6 +1701,50 @@ static int hns_roce_query_pf_timer_resource(struct hns_roce_dev *hr_dev)
return 0;
}
+static int query_func_resource_caps(struct hns_roce_dev *hr_dev, bool is_vf)
+{
+ struct device *dev = hr_dev->dev;
+ int ret;
+
+ ret = load_func_res_caps(hr_dev, is_vf);
+ if (ret) {
+ dev_err(dev, "failed to load res caps, ret = %d (%s).\n", ret,
+ is_vf ? "vf" : "pf");
+ return ret;
+ }
+
+ if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09) {
+ ret = load_ext_cfg_caps(hr_dev, is_vf);
+ if (ret)
+ dev_err(dev, "failed to load ext cfg, ret = %d (%s).\n",
+ ret, is_vf ? "vf" : "pf");
+ }
+
+ return ret;
+}
+
+static int hns_roce_query_pf_resource(struct hns_roce_dev *hr_dev)
+{
+ struct device *dev = hr_dev->dev;
+ int ret;
+
+ ret = query_func_resource_caps(hr_dev, false);
+ if (ret)
+ return ret;
+
+ ret = load_pf_timer_res_caps(hr_dev);
+ if (ret)
+ dev_err(dev, "failed to load pf timer resource, ret = %d.\n",
+ ret);
+
+ return ret;
+}
+
+static int hns_roce_query_vf_resource(struct hns_roce_dev *hr_dev)
+{
+ return query_func_resource_caps(hr_dev, true);
+}
+
static int __hns_roce_set_vf_switch_param(struct hns_roce_dev *hr_dev,
u32 vf_id)
{
@@ -1792,7 +1784,7 @@ static int hns_roce_set_vf_switch_param(struct hns_roce_dev *hr_dev)
return 0;
}
-static int __hns_roce_alloc_vf_resource(struct hns_roce_dev *hr_dev, int vf_id)
+static int config_vf_hem_resource(struct hns_roce_dev *hr_dev, int vf_id)
{
struct hns_roce_cmq_desc desc[2];
struct hns_roce_cmq_req *r_a = (struct hns_roce_cmq_req *)desc[0].data;
@@ -1837,15 +1829,48 @@ static int __hns_roce_alloc_vf_resource(struct hns_roce_dev *hr_dev, int vf_id)
return hns_roce_cmq_send(hr_dev, desc, 2);
}
+static int config_vf_ext_resource(struct hns_roce_dev *hr_dev, u32 vf_id)
+{
+ struct hns_roce_cmq_desc desc;
+ struct hns_roce_cmq_req *req = (struct hns_roce_cmq_req *)desc.data;
+ struct hns_roce_caps *caps = &hr_dev->caps;
+
+ hns_roce_cmq_setup_basic_desc(&desc, HNS_ROCE_OPC_EXT_CFG, false);
+
+ hr_reg_write(req, EXT_CFG_VF_ID, vf_id);
+
+ hr_reg_write(req, EXT_CFG_QP_PI_NUM, caps->num_pi_qps);
+ hr_reg_write(req, EXT_CFG_QP_PI_IDX, vf_id * caps->num_pi_qps);
+ hr_reg_write(req, EXT_CFG_QP_NUM, caps->num_qps);
+ hr_reg_write(req, EXT_CFG_QP_IDX, vf_id * caps->num_qps);
+
+ return hns_roce_cmq_send(hr_dev, &desc, 1);
+}
+
static int hns_roce_alloc_vf_resource(struct hns_roce_dev *hr_dev)
{
- int vf_id;
+ u32 func_num = max_t(u32, 1, hr_dev->func_num);
+ u32 vf_id;
int ret;
- for (vf_id = 0; vf_id < hr_dev->func_num; vf_id++) {
- ret = __hns_roce_alloc_vf_resource(hr_dev, vf_id);
- if (ret)
+ for (vf_id = 0; vf_id < func_num; vf_id++) {
+ ret = config_vf_hem_resource(hr_dev, vf_id);
+ if (ret) {
+ dev_err(hr_dev->dev,
+ "failed to config vf-%u hem res, ret = %d.\n",
+ vf_id, ret);
return ret;
+ }
+
+ if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09) {
+ ret = config_vf_ext_resource(hr_dev, vf_id);
+ if (ret) {
+ dev_err(hr_dev->dev,
+ "failed to config vf-%u ext res, ret = %d.\n",
+ vf_id, ret);
+ return ret;
+ }
+ }
}
return 0;
@@ -1897,9 +1922,9 @@ static int hns_roce_v2_set_bt(struct hns_roce_dev *hr_dev)
return hns_roce_cmq_send(hr_dev, &desc, 1);
}
+/* Use default caps when hns_roce_query_pf_caps() failed or init VF profile */
static void set_default_caps(struct hns_roce_dev *hr_dev)
{
- struct hns_roce_v2_priv *priv = hr_dev->priv;
struct hns_roce_caps *caps = &hr_dev->caps;
caps->num_qps = HNS_ROCE_V2_MAX_QP_NUM;
@@ -1911,19 +1936,18 @@ static void set_default_caps(struct hns_roce_dev *hr_dev)
caps->max_sq_sg = HNS_ROCE_V2_MAX_SQ_SGE_NUM;
caps->max_extend_sg = HNS_ROCE_V2_MAX_EXTEND_SGE_NUM;
caps->max_rq_sg = HNS_ROCE_V2_MAX_RQ_SGE_NUM;
+
caps->num_uars = HNS_ROCE_V2_UAR_NUM;
caps->phy_num_uars = HNS_ROCE_V2_PHY_UAR_NUM;
caps->num_aeq_vectors = HNS_ROCE_V2_AEQE_VEC_NUM;
- caps->num_comp_vectors =
- min_t(u32, caps->eqc_bt_num - 1,
- (u32)priv->handle->rinfo.num_vectors - 2);
caps->num_other_vectors = HNS_ROCE_V2_ABNORMAL_VEC_NUM;
+ caps->num_comp_vectors = 0;
+
caps->num_mtpts = HNS_ROCE_V2_MAX_MTPT_NUM;
- caps->num_mtt_segs = HNS_ROCE_V2_MAX_MTT_SEGS;
- caps->num_srqwqe_segs = HNS_ROCE_V2_MAX_SRQWQE_SEGS;
- caps->num_idx_segs = HNS_ROCE_V2_MAX_IDX_SEGS;
caps->num_pds = HNS_ROCE_V2_MAX_PD_NUM;
- caps->num_xrcds = HNS_ROCE_V2_MAX_XRCD_NUM;
+ caps->num_qpc_timer = HNS_ROCE_V2_MAX_QPC_TIMER_NUM;
+ caps->num_cqc_timer = HNS_ROCE_V2_MAX_CQC_TIMER_NUM;
+
caps->max_qp_init_rdma = HNS_ROCE_V2_MAX_QP_INIT_RDMA;
caps->max_qp_dest_rdma = HNS_ROCE_V2_MAX_QP_DEST_RDMA;
caps->max_sq_desc_sz = HNS_ROCE_V2_MAX_SQ_DESC_SZ;
@@ -1934,12 +1958,10 @@ static void set_default_caps(struct hns_roce_dev *hr_dev)
caps->cqc_entry_sz = HNS_ROCE_V2_CQC_ENTRY_SZ;
caps->srqc_entry_sz = HNS_ROCE_V2_SRQC_ENTRY_SZ;
caps->mtpt_entry_sz = HNS_ROCE_V2_MTPT_ENTRY_SZ;
- caps->mtt_entry_sz = HNS_ROCE_V2_MTT_ENTRY_SZ;
caps->idx_entry_sz = HNS_ROCE_V2_IDX_ENTRY_SZ;
caps->page_size_cap = HNS_ROCE_V2_PAGE_SIZE_SUPPORTED;
caps->reserved_lkey = 0;
caps->reserved_pds = 0;
- caps->reserved_xrcds = HNS_ROCE_V2_RSV_XRCD_NUM;
caps->reserved_mrws = 1;
caps->reserved_uars = 0;
caps->reserved_cqs = 0;
@@ -1950,15 +1972,15 @@ static void set_default_caps(struct hns_roce_dev *hr_dev)
caps->srqc_hop_num = HNS_ROCE_CONTEXT_HOP_NUM;
caps->cqc_hop_num = HNS_ROCE_CONTEXT_HOP_NUM;
caps->mpt_hop_num = HNS_ROCE_CONTEXT_HOP_NUM;
+ caps->sccc_hop_num = HNS_ROCE_SCCC_HOP_NUM;
+
caps->mtt_hop_num = HNS_ROCE_MTT_HOP_NUM;
- caps->pbl_hop_num = HNS_ROCE_PBL_HOP_NUM;
caps->wqe_sq_hop_num = HNS_ROCE_SQWQE_HOP_NUM;
caps->wqe_sge_hop_num = HNS_ROCE_EXT_SGE_HOP_NUM;
caps->wqe_rq_hop_num = HNS_ROCE_RQWQE_HOP_NUM;
caps->cqe_hop_num = HNS_ROCE_CQE_HOP_NUM;
caps->srqwqe_hop_num = HNS_ROCE_SRQWQE_HOP_NUM;
caps->idx_hop_num = HNS_ROCE_IDX_HOP_NUM;
- caps->eqe_hop_num = HNS_ROCE_EQE_HOP_NUM;
caps->chunk_sz = HNS_ROCE_V2_TABLE_CHUNK_SIZE;
caps->flags = HNS_ROCE_CAP_FLAG_REREG_MR |
@@ -1979,36 +2001,17 @@ static void set_default_caps(struct hns_roce_dev *hr_dev)
HNS_ROCE_CAP_FLAG_SRQ | HNS_ROCE_CAP_FLAG_FRMR |
HNS_ROCE_CAP_FLAG_QP_FLOW_CTRL | HNS_ROCE_CAP_FLAG_XRC;
- caps->num_qpc_timer = HNS_ROCE_V2_MAX_QPC_TIMER_NUM;
- caps->qpc_timer_entry_sz = HNS_ROCE_V2_QPC_TIMER_ENTRY_SZ;
- caps->qpc_timer_hop_num = HNS_ROCE_HOP_NUM_0;
- caps->num_cqc_timer = HNS_ROCE_V2_MAX_CQC_TIMER_NUM;
- caps->cqc_timer_entry_sz = HNS_ROCE_V2_CQC_TIMER_ENTRY_SZ;
- caps->cqc_timer_hop_num = HNS_ROCE_HOP_NUM_0;
-
- caps->sccc_hop_num = HNS_ROCE_SCCC_HOP_NUM;
+ caps->gid_table_len[0] = HNS_ROCE_V2_GID_INDEX_NUM;
if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09) {
- caps->aeqe_size = HNS_ROCE_V3_EQE_SIZE;
- caps->ceqe_size = HNS_ROCE_V3_EQE_SIZE;
- caps->cqe_sz = HNS_ROCE_V3_CQE_SIZE;
- caps->qpc_sz = HNS_ROCE_V3_QPC_SZ;
- caps->sccc_sz = HNS_ROCE_V3_SCCC_SZ;
- caps->gmv_entry_sz = HNS_ROCE_V3_GMV_ENTRY_SZ;
- caps->gmv_entry_num = caps->gmv_bt_num * (PAGE_SIZE /
- caps->gmv_entry_sz);
- caps->gmv_hop_num = HNS_ROCE_HOP_NUM_0;
- caps->gid_table_len[0] = caps->gmv_bt_num * (HNS_HW_PAGE_SIZE /
- caps->gmv_entry_sz);
- caps->max_sq_inline = HNS_ROCE_V2_MAX_SQ_INL_EXT;
+ caps->max_sq_inline = HNS_ROCE_V3_MAX_SQ_INLINE;
} else {
- caps->aeqe_size = HNS_ROCE_AEQE_SIZE;
- caps->ceqe_size = HNS_ROCE_CEQE_SIZE;
- caps->cqe_sz = HNS_ROCE_V2_CQE_SIZE;
+ caps->max_sq_inline = HNS_ROCE_V2_MAX_SQ_INLINE;
+
+ /* The following configuration are only valid for HIP08 */
caps->qpc_sz = HNS_ROCE_V2_QPC_SZ;
caps->sccc_sz = HNS_ROCE_V2_SCCC_SZ;
- caps->gid_table_len[0] = HNS_ROCE_V2_GID_INDEX_NUM;
- caps->max_sq_inline = HNS_ROCE_V2_MAX_SQ_INLINE;
+ caps->cqe_sz = HNS_ROCE_V2_CQE_SIZE;
}
}
@@ -2063,9 +2066,11 @@ static void set_hem_page_size(struct hns_roce_dev *hr_dev)
caps->eqe_buf_pg_sz = 0;
/* Link Table */
- caps->tsq_buf_pg_sz = 0;
+ caps->llm_buf_pg_sz = 0;
/* MR */
+ caps->mpt_ba_pg_sz = 0;
+ caps->mpt_buf_pg_sz = 0;
caps->pbl_ba_pg_sz = HNS_ROCE_BA_PG_SZ_SUPPORTED_16K;
caps->pbl_buf_pg_sz = 0;
calc_pg_sz(caps->num_mtpts, caps->mtpt_entry_sz, caps->mpt_hop_num,
@@ -2073,8 +2078,12 @@ static void set_hem_page_size(struct hns_roce_dev *hr_dev)
HEM_TYPE_MTPT);
/* QP */
- caps->qpc_timer_ba_pg_sz = 0;
+ caps->qpc_ba_pg_sz = 0;
+ caps->qpc_buf_pg_sz = 0;
+ caps->qpc_timer_ba_pg_sz = 0;
caps->qpc_timer_buf_pg_sz = 0;
+ caps->sccc_ba_pg_sz = 0;
+ caps->sccc_buf_pg_sz = 0;
caps->mtt_ba_pg_sz = 0;
caps->mtt_buf_pg_sz = 0;
calc_pg_sz(caps->num_qps, caps->qpc_sz, caps->qpc_hop_num,
@@ -2087,20 +2096,26 @@ static void set_hem_page_size(struct hns_roce_dev *hr_dev)
&caps->sccc_ba_pg_sz, HEM_TYPE_SCCC);
/* CQ */
+ caps->cqc_ba_pg_sz = 0;
+ caps->cqc_buf_pg_sz = 0;
+ caps->cqc_timer_ba_pg_sz = 0;
+ caps->cqc_timer_buf_pg_sz = 0;
+ caps->cqe_ba_pg_sz = HNS_ROCE_BA_PG_SZ_SUPPORTED_256K;
+ caps->cqe_buf_pg_sz = 0;
calc_pg_sz(caps->num_cqs, caps->cqc_entry_sz, caps->cqc_hop_num,
caps->cqc_bt_num, &caps->cqc_buf_pg_sz, &caps->cqc_ba_pg_sz,
HEM_TYPE_CQC);
calc_pg_sz(caps->max_cqes, caps->cqe_sz, caps->cqe_hop_num,
1, &caps->cqe_buf_pg_sz, &caps->cqe_ba_pg_sz, HEM_TYPE_CQE);
- if (caps->cqc_timer_entry_sz)
- calc_pg_sz(caps->num_cqc_timer, caps->cqc_timer_entry_sz,
- caps->cqc_timer_hop_num, caps->cqc_timer_bt_num,
- &caps->cqc_timer_buf_pg_sz,
- &caps->cqc_timer_ba_pg_sz, HEM_TYPE_CQC_TIMER);
-
/* SRQ */
if (caps->flags & HNS_ROCE_CAP_FLAG_SRQ) {
+ caps->srqc_ba_pg_sz = 0;
+ caps->srqc_buf_pg_sz = 0;
+ caps->srqwqe_ba_pg_sz = 0;
+ caps->srqwqe_buf_pg_sz = 0;
+ caps->idx_ba_pg_sz = 0;
+ caps->idx_buf_pg_sz = 0;
calc_pg_sz(caps->num_srqs, caps->srqc_entry_sz,
caps->srqc_hop_num, caps->srqc_bt_num,
&caps->srqc_buf_pg_sz, &caps->srqc_ba_pg_sz,
@@ -2118,6 +2133,71 @@ static void set_hem_page_size(struct hns_roce_dev *hr_dev)
caps->gmv_buf_pg_sz = 0;
}
+/* Apply all loaded caps before setting to hardware */
+static void apply_func_caps(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_caps *caps = &hr_dev->caps;
+ struct hns_roce_v2_priv *priv = hr_dev->priv;
+
+ /* The following configurations don't need to be got from firmware. */
+ caps->qpc_timer_entry_sz = HNS_ROCE_V2_QPC_TIMER_ENTRY_SZ;
+ caps->cqc_timer_entry_sz = HNS_ROCE_V2_CQC_TIMER_ENTRY_SZ;
+ caps->mtt_entry_sz = HNS_ROCE_V2_MTT_ENTRY_SZ;
+
+ caps->eqe_hop_num = HNS_ROCE_EQE_HOP_NUM;
+ caps->pbl_hop_num = HNS_ROCE_PBL_HOP_NUM;
+ caps->qpc_timer_hop_num = HNS_ROCE_HOP_NUM_0;
+ caps->cqc_timer_hop_num = HNS_ROCE_HOP_NUM_0;
+
+ caps->num_xrcds = HNS_ROCE_V2_MAX_XRCD_NUM;
+ caps->reserved_xrcds = HNS_ROCE_V2_RSV_XRCD_NUM;
+
+ caps->num_mtt_segs = HNS_ROCE_V2_MAX_MTT_SEGS;
+ caps->num_srqwqe_segs = HNS_ROCE_V2_MAX_SRQWQE_SEGS;
+ caps->num_idx_segs = HNS_ROCE_V2_MAX_IDX_SEGS;
+
+ if (!caps->num_comp_vectors)
+ caps->num_comp_vectors = min_t(u32, caps->eqc_bt_num - 1,
+ (u32)priv->handle->rinfo.num_vectors - 2);
+
+ if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09) {
+ caps->ceqe_size = HNS_ROCE_V3_EQE_SIZE;
+ caps->aeqe_size = HNS_ROCE_V3_EQE_SIZE;
+
+ /* The following configurations will be overwritten */
+ caps->qpc_sz = HNS_ROCE_V3_QPC_SZ;
+ caps->cqe_sz = HNS_ROCE_V3_CQE_SIZE;
+ caps->sccc_sz = HNS_ROCE_V3_SCCC_SZ;
+
+ /* The following configurations are not got from firmware */
+ caps->gmv_entry_sz = HNS_ROCE_V3_GMV_ENTRY_SZ;
+
+ caps->gmv_hop_num = HNS_ROCE_HOP_NUM_0;
+ caps->gid_table_len[0] = caps->gmv_bt_num *
+ (HNS_HW_PAGE_SIZE / caps->gmv_entry_sz);
+
+ caps->gmv_entry_num = caps->gmv_bt_num * (PAGE_SIZE /
+ caps->gmv_entry_sz);
+ } else {
+ u32 func_num = max_t(u32, 1, hr_dev->func_num);
+
+ caps->ceqe_size = HNS_ROCE_CEQE_SIZE;
+ caps->aeqe_size = HNS_ROCE_AEQE_SIZE;
+ caps->gid_table_len[0] /= func_num;
+ }
+
+ if (hr_dev->is_vf) {
+ caps->default_aeq_arm_st = 0x3;
+ caps->default_ceq_arm_st = 0x3;
+ caps->default_ceq_max_cnt = 0x1;
+ caps->default_ceq_period = 0x10;
+ caps->default_aeq_max_cnt = 0x1;
+ caps->default_aeq_period = 0x10;
+ }
+
+ set_hem_page_size(hr_dev);
+}
+
static int hns_roce_query_pf_caps(struct hns_roce_dev *hr_dev)
{
struct hns_roce_cmq_desc desc[HNS_ROCE_QUERY_PF_CAPS_CMD_NUM];
@@ -2167,7 +2247,7 @@ static int hns_roce_query_pf_caps(struct hns_roce_dev *hr_dev)
caps->max_sq_desc_sz = resp_a->max_sq_desc_sz;
caps->max_rq_desc_sz = resp_a->max_rq_desc_sz;
caps->max_srq_desc_sz = resp_a->max_srq_desc_sz;
- caps->cqe_sz = HNS_ROCE_V2_CQE_SIZE;
+ caps->cqe_sz = resp_a->cqe_sz;
caps->mtpt_entry_sz = resp_b->mtpt_entry_sz;
caps->irrl_entry_sz = resp_b->irrl_entry_sz;
@@ -2177,7 +2257,7 @@ static int hns_roce_query_pf_caps(struct hns_roce_dev *hr_dev)
caps->idx_entry_sz = resp_b->idx_entry_sz;
caps->sccc_sz = resp_b->sccc_sz;
caps->max_mtu = resp_b->max_mtu;
- caps->qpc_sz = HNS_ROCE_V2_QPC_SZ;
+ caps->qpc_sz = le16_to_cpu(resp_b->qpc_sz);
caps->min_cqes = resp_b->min_cqes;
caps->min_wqes = resp_b->min_wqes;
caps->page_size_cap = le32_to_cpu(resp_b->page_size_cap);
@@ -2202,8 +2282,6 @@ static int hns_roce_query_pf_caps(struct hns_roce_dev *hr_dev)
V2_QUERY_PF_CAPS_C_MAX_GID_M,
V2_QUERY_PF_CAPS_C_MAX_GID_S);
- caps->gid_table_len[0] /= hr_dev->func_num;
-
caps->max_cqes = 1 << roce_get_field(resp_c->cq_depth,
V2_QUERY_PF_CAPS_C_CQ_DEPTH_M,
V2_QUERY_PF_CAPS_C_CQ_DEPTH_S);
@@ -2274,18 +2352,8 @@ static int hns_roce_query_pf_caps(struct hns_roce_dev *hr_dev)
caps->default_aeq_max_cnt = le16_to_cpu(resp_e->aeq_max_cnt);
caps->default_aeq_period = le16_to_cpu(resp_e->aeq_period);
- caps->qpc_timer_entry_sz = HNS_ROCE_V2_QPC_TIMER_ENTRY_SZ;
- caps->cqc_timer_entry_sz = HNS_ROCE_V2_CQC_TIMER_ENTRY_SZ;
- caps->mtt_entry_sz = HNS_ROCE_V2_MTT_ENTRY_SZ;
- caps->num_mtt_segs = HNS_ROCE_V2_MAX_MTT_SEGS;
- caps->ceqe_size = HNS_ROCE_CEQE_SIZE;
- caps->aeqe_size = HNS_ROCE_AEQE_SIZE;
- caps->num_xrcds = HNS_ROCE_V2_MAX_XRCD_NUM;
- caps->reserved_xrcds = HNS_ROCE_V2_RSV_XRCD_NUM;
- caps->num_srqwqe_segs = HNS_ROCE_V2_MAX_SRQWQE_SEGS;
- caps->num_idx_segs = HNS_ROCE_V2_MAX_IDX_SEGS;
-
caps->qpc_hop_num = ctx_hop_num;
+ caps->sccc_hop_num = ctx_hop_num;
caps->srqc_hop_num = ctx_hop_num;
caps->cqc_hop_num = ctx_hop_num;
caps->mpt_hop_num = ctx_hop_num;
@@ -2303,23 +2371,6 @@ static int hns_roce_query_pf_caps(struct hns_roce_dev *hr_dev)
V2_QUERY_PF_CAPS_D_RQWQE_HOP_NUM_M,
V2_QUERY_PF_CAPS_D_RQWQE_HOP_NUM_S);
- if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09) {
- caps->ceqe_size = HNS_ROCE_V3_EQE_SIZE;
- caps->aeqe_size = HNS_ROCE_V3_EQE_SIZE;
- caps->cqe_sz = HNS_ROCE_V3_CQE_SIZE;
- caps->qpc_sz = HNS_ROCE_V3_QPC_SZ;
- caps->sccc_sz = HNS_ROCE_V3_SCCC_SZ;
- caps->gmv_entry_sz = HNS_ROCE_V3_GMV_ENTRY_SZ;
- caps->gmv_entry_num = caps->gmv_bt_num * (PAGE_SIZE /
- caps->gmv_entry_sz);
- caps->gmv_hop_num = HNS_ROCE_HOP_NUM_0;
- caps->gid_table_len[0] = caps->gmv_bt_num *
- (HNS_HW_PAGE_SIZE / caps->gmv_entry_sz);
- }
-
- caps->qpc_timer_hop_num = HNS_ROCE_HOP_NUM_0;
- caps->cqc_timer_hop_num = HNS_ROCE_HOP_NUM_0;
-
return 0;
}
@@ -2362,285 +2413,235 @@ static int hns_roce_config_entry_size(struct hns_roce_dev *hr_dev)
static int hns_roce_v2_vf_profile(struct hns_roce_dev *hr_dev)
{
+ struct device *dev = hr_dev->dev;
int ret;
- hr_dev->vendor_part_id = hr_dev->pci_dev->device;
- hr_dev->sys_image_guid = be64_to_cpu(hr_dev->ib_dev.node_guid);
hr_dev->func_num = 1;
+ set_default_caps(hr_dev);
+
ret = hns_roce_query_vf_resource(hr_dev);
if (ret) {
- dev_err(hr_dev->dev,
- "Query the VF resource fail, ret = %d.\n", ret);
+ dev_err(dev, "failed to query VF resource, ret = %d.\n", ret);
return ret;
}
- set_default_caps(hr_dev);
- set_hem_page_size(hr_dev);
+ apply_func_caps(hr_dev);
ret = hns_roce_v2_set_bt(hr_dev);
- if (ret) {
- dev_err(hr_dev->dev,
- "Configure the VF bt attribute fail, ret = %d.\n",
- ret);
- return ret;
- }
+ if (ret)
+ dev_err(dev, "failed to config VF BA table, ret = %d.\n", ret);
- return 0;
+ return ret;
}
-static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev)
+static int hns_roce_v2_pf_profile(struct hns_roce_dev *hr_dev)
{
- struct hns_roce_caps *caps = &hr_dev->caps;
+ struct device *dev = hr_dev->dev;
int ret;
- ret = hns_roce_cmq_query_hw_info(hr_dev);
+ ret = hns_roce_query_func_info(hr_dev);
if (ret) {
- dev_err(hr_dev->dev, "Query hardware version fail, ret = %d.\n",
- ret);
+ dev_err(dev, "failed to query func info, ret = %d.\n", ret);
return ret;
}
- ret = hns_roce_query_fw_ver(hr_dev);
+ ret = hns_roce_config_global_param(hr_dev);
if (ret) {
- dev_err(hr_dev->dev, "Query firmware version fail, ret = %d.\n",
- ret);
+ dev_err(dev, "failed to config global param, ret = %d.\n", ret);
return ret;
}
- if (hr_dev->is_vf)
- return hns_roce_v2_vf_profile(hr_dev);
-
- ret = hns_roce_query_func_info(hr_dev);
+ ret = hns_roce_set_vf_switch_param(hr_dev);
if (ret) {
- dev_err(hr_dev->dev, "Query function info fail, ret = %d.\n",
- ret);
+ dev_err(dev, "failed to set switch param, ret = %d.\n", ret);
return ret;
}
- ret = hns_roce_config_global_param(hr_dev);
- if (ret) {
- dev_err(hr_dev->dev, "Configure global param fail, ret = %d.\n",
- ret);
- return ret;
- }
+ ret = hns_roce_query_pf_caps(hr_dev);
+ if (ret)
+ set_default_caps(hr_dev);
- /* Get pf resource owned by every pf */
ret = hns_roce_query_pf_resource(hr_dev);
if (ret) {
- dev_err(hr_dev->dev, "Query pf resource fail, ret = %d.\n",
- ret);
+ dev_err(dev, "failed to query pf resource, ret = %d.\n", ret);
return ret;
}
- ret = hns_roce_query_pf_timer_resource(hr_dev);
+ apply_func_caps(hr_dev);
+
+ ret = hns_roce_alloc_vf_resource(hr_dev);
if (ret) {
- dev_err(hr_dev->dev,
- "failed to query pf timer resource, ret = %d.\n", ret);
+ dev_err(dev, "failed to alloc vf resource, ret = %d.\n", ret);
return ret;
}
- ret = hns_roce_set_vf_switch_param(hr_dev);
+ ret = hns_roce_v2_set_bt(hr_dev);
if (ret) {
- dev_err(hr_dev->dev,
- "failed to set function switch param, ret = %d.\n",
- ret);
+ dev_err(dev, "failed to config BA table, ret = %d.\n", ret);
return ret;
}
- hr_dev->vendor_part_id = hr_dev->pci_dev->device;
- hr_dev->sys_image_guid = be64_to_cpu(hr_dev->ib_dev.node_guid);
-
- caps->pbl_hop_num = HNS_ROCE_PBL_HOP_NUM;
- caps->eqe_hop_num = HNS_ROCE_EQE_HOP_NUM;
+ /* Configure the size of QPC, SCCC, etc. */
+ return hns_roce_config_entry_size(hr_dev);
+}
- ret = hns_roce_query_pf_caps(hr_dev);
- if (ret)
- set_default_caps(hr_dev);
+static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev)
+{
+ struct device *dev = hr_dev->dev;
+ int ret;
- ret = hns_roce_alloc_vf_resource(hr_dev);
+ ret = hns_roce_cmq_query_hw_info(hr_dev);
if (ret) {
- dev_err(hr_dev->dev, "Allocate vf resource fail, ret = %d.\n",
- ret);
+ dev_err(dev, "failed to query hardware info, ret = %d.\n", ret);
return ret;
}
- set_hem_page_size(hr_dev);
- ret = hns_roce_v2_set_bt(hr_dev);
+ ret = hns_roce_query_fw_ver(hr_dev);
if (ret) {
- dev_err(hr_dev->dev,
- "Configure bt attribute fail, ret = %d.\n", ret);
+ dev_err(dev, "failed to query firmware info, ret = %d.\n", ret);
return ret;
}
- /* Configure the size of QPC, SCCC, etc. */
- ret = hns_roce_config_entry_size(hr_dev);
+ hr_dev->vendor_part_id = hr_dev->pci_dev->device;
+ hr_dev->sys_image_guid = be64_to_cpu(hr_dev->ib_dev.node_guid);
- return ret;
+ if (hr_dev->is_vf)
+ return hns_roce_v2_vf_profile(hr_dev);
+ else
+ return hns_roce_v2_pf_profile(hr_dev);
}
-static int hns_roce_config_link_table(struct hns_roce_dev *hr_dev,
- enum hns_roce_link_table_type type)
+static void config_llm_table(struct hns_roce_buf *data_buf, void *cfg_buf)
{
- struct hns_roce_cmq_desc desc[2];
- struct hns_roce_cfg_llm_a *req_a =
- (struct hns_roce_cfg_llm_a *)desc[0].data;
- struct hns_roce_cfg_llm_b *req_b =
- (struct hns_roce_cfg_llm_b *)desc[1].data;
- struct hns_roce_v2_priv *priv = hr_dev->priv;
- struct hns_roce_link_table *link_tbl;
- struct hns_roce_link_table_entry *entry;
- enum hns_roce_opcode_type opcode;
- u32 page_num;
+ u32 i, next_ptr, page_num;
+ __le64 *entry = cfg_buf;
+ dma_addr_t addr;
+ u64 val;
- switch (type) {
- case TSQ_LINK_TABLE:
- link_tbl = &priv->tsq;
- opcode = HNS_ROCE_OPC_CFG_EXT_LLM;
- break;
- case TPQ_LINK_TABLE:
- link_tbl = &priv->tpq;
- opcode = HNS_ROCE_OPC_CFG_TMOUT_LLM;
- break;
- default:
- return -EINVAL;
+ page_num = data_buf->npages;
+ for (i = 0; i < page_num; i++) {
+ addr = hns_roce_buf_page(data_buf, i);
+ if (i == (page_num - 1))
+ next_ptr = 0;
+ else
+ next_ptr = i + 1;
+
+ val = HNS_ROCE_EXT_LLM_ENTRY(addr, (u64)next_ptr);
+ entry[i] = cpu_to_le64(val);
}
+}
- page_num = link_tbl->npages;
- entry = link_tbl->table.buf;
+static int set_llm_cfg_to_hw(struct hns_roce_dev *hr_dev,
+ struct hns_roce_link_table *table)
+{
+ struct hns_roce_cmq_desc desc[2];
+ struct hns_roce_cmq_req *r_a = (struct hns_roce_cmq_req *)desc[0].data;
+ struct hns_roce_cmq_req *r_b = (struct hns_roce_cmq_req *)desc[1].data;
+ struct hns_roce_buf *buf = table->buf;
+ enum hns_roce_opcode_type opcode;
+ dma_addr_t addr;
+ opcode = HNS_ROCE_OPC_CFG_EXT_LLM;
hns_roce_cmq_setup_basic_desc(&desc[0], opcode, false);
desc[0].flag |= cpu_to_le16(HNS_ROCE_CMD_FLAG_NEXT);
-
hns_roce_cmq_setup_basic_desc(&desc[1], opcode, false);
- req_a->base_addr_l = cpu_to_le32(link_tbl->table.map & 0xffffffff);
- req_a->base_addr_h = cpu_to_le32(link_tbl->table.map >> 32);
- roce_set_field(req_a->depth_pgsz_init_en, CFG_LLM_QUE_DEPTH_M,
- CFG_LLM_QUE_DEPTH_S, link_tbl->npages);
- roce_set_field(req_a->depth_pgsz_init_en, CFG_LLM_QUE_PGSZ_M,
- CFG_LLM_QUE_PGSZ_S, link_tbl->pg_sz);
- roce_set_field(req_a->depth_pgsz_init_en, CFG_LLM_INIT_EN_M,
- CFG_LLM_INIT_EN_S, 1);
- req_a->head_ba_l = cpu_to_le32(entry[0].blk_ba0);
- req_a->head_ba_h_nxtptr = cpu_to_le32(entry[0].blk_ba1_nxt_ptr);
- roce_set_field(req_a->head_ptr, CFG_LLM_HEAD_PTR_M, CFG_LLM_HEAD_PTR_S,
- 0);
-
- req_b->tail_ba_l = cpu_to_le32(entry[page_num - 1].blk_ba0);
- roce_set_field(req_b->tail_ba_h, CFG_LLM_TAIL_BA_H_M,
- CFG_LLM_TAIL_BA_H_S,
- entry[page_num - 1].blk_ba1_nxt_ptr &
- HNS_ROCE_LINK_TABLE_BA1_M);
- roce_set_field(req_b->tail_ptr, CFG_LLM_TAIL_PTR_M, CFG_LLM_TAIL_PTR_S,
- (entry[page_num - 2].blk_ba1_nxt_ptr &
- HNS_ROCE_LINK_TABLE_NXT_PTR_M) >>
- HNS_ROCE_LINK_TABLE_NXT_PTR_S);
+ hr_reg_write(r_a, CFG_LLM_A_BA_L, lower_32_bits(table->table.map));
+ hr_reg_write(r_a, CFG_LLM_A_BA_H, upper_32_bits(table->table.map));
+ hr_reg_write(r_a, CFG_LLM_A_DEPTH, buf->npages);
+ hr_reg_write(r_a, CFG_LLM_A_PGSZ, to_hr_hw_page_shift(buf->page_shift));
+ hr_reg_enable(r_a, CFG_LLM_A_INIT_EN);
+
+ addr = to_hr_hw_page_addr(hns_roce_buf_page(buf, 0));
+ hr_reg_write(r_a, CFG_LLM_A_HEAD_BA_L, lower_32_bits(addr));
+ hr_reg_write(r_a, CFG_LLM_A_HEAD_BA_H, upper_32_bits(addr));
+ hr_reg_write(r_a, CFG_LLM_A_HEAD_NXTPTR, 1);
+ hr_reg_write(r_a, CFG_LLM_A_HEAD_PTR, 0);
+
+ addr = to_hr_hw_page_addr(hns_roce_buf_page(buf, buf->npages - 1));
+ hr_reg_write(r_b, CFG_LLM_B_TAIL_BA_L, lower_32_bits(addr));
+ hr_reg_write(r_b, CFG_LLM_B_TAIL_BA_H, upper_32_bits(addr));
+ hr_reg_write(r_b, CFG_LLM_B_TAIL_PTR, buf->npages - 1);
return hns_roce_cmq_send(hr_dev, desc, 2);
}
-static int hns_roce_init_link_table(struct hns_roce_dev *hr_dev,
- enum hns_roce_link_table_type type)
+static struct hns_roce_link_table *
+alloc_link_table_buf(struct hns_roce_dev *hr_dev)
{
struct hns_roce_v2_priv *priv = hr_dev->priv;
struct hns_roce_link_table *link_tbl;
- struct hns_roce_link_table_entry *entry;
- struct device *dev = hr_dev->dev;
- u32 buf_chk_sz;
- dma_addr_t t;
- int func_num = 1;
- u32 pg_num_a;
- u32 pg_num_b;
- u32 pg_num;
- u32 size;
- int i;
-
- switch (type) {
- case TSQ_LINK_TABLE:
- link_tbl = &priv->tsq;
- buf_chk_sz = 1 << (hr_dev->caps.tsq_buf_pg_sz + PAGE_SHIFT);
- pg_num_a = hr_dev->caps.num_qps * 8 / buf_chk_sz;
- pg_num_b = hr_dev->caps.sl_num * 4 + 2;
- break;
- case TPQ_LINK_TABLE:
- link_tbl = &priv->tpq;
- buf_chk_sz = 1 << (hr_dev->caps.tpq_buf_pg_sz + PAGE_SHIFT);
- pg_num_a = hr_dev->caps.num_cqs * 4 / buf_chk_sz;
- pg_num_b = 2 * 4 * func_num + 2;
- break;
- default:
- return -EINVAL;
+ u32 pg_shift, size, min_size;
+
+ link_tbl = &priv->ext_llm;
+ pg_shift = hr_dev->caps.llm_buf_pg_sz + PAGE_SHIFT;
+ size = hr_dev->caps.num_qps * HNS_ROCE_V2_EXT_LLM_ENTRY_SZ;
+ min_size = HNS_ROCE_EXT_LLM_MIN_PAGES(hr_dev->caps.sl_num) << pg_shift;
+
+ /* Alloc data table */
+ size = max(size, min_size);
+ link_tbl->buf = hns_roce_buf_alloc(hr_dev, size, pg_shift, 0);
+ if (IS_ERR(link_tbl->buf))
+ return ERR_PTR(-ENOMEM);
+
+ /* Alloc config table */
+ size = link_tbl->buf->npages * sizeof(u64);
+ link_tbl->table.buf = dma_alloc_coherent(hr_dev->dev, size,
+ &link_tbl->table.map,
+ GFP_KERNEL);
+ if (!link_tbl->table.buf) {
+ hns_roce_buf_free(hr_dev, link_tbl->buf);
+ return ERR_PTR(-ENOMEM);
}
- pg_num = max(pg_num_a, pg_num_b);
- size = pg_num * sizeof(struct hns_roce_link_table_entry);
+ return link_tbl;
+}
- link_tbl->table.buf = dma_alloc_coherent(dev, size,
- &link_tbl->table.map,
- GFP_KERNEL);
- if (!link_tbl->table.buf)
- goto out;
+static void free_link_table_buf(struct hns_roce_dev *hr_dev,
+ struct hns_roce_link_table *tbl)
+{
+ if (tbl->buf) {
+ u32 size = tbl->buf->npages * sizeof(u64);
- link_tbl->pg_list = kcalloc(pg_num, sizeof(*link_tbl->pg_list),
- GFP_KERNEL);
- if (!link_tbl->pg_list)
- goto err_kcalloc_failed;
+ dma_free_coherent(hr_dev->dev, size, tbl->table.buf,
+ tbl->table.map);
+ }
- entry = link_tbl->table.buf;
- for (i = 0; i < pg_num; ++i) {
- link_tbl->pg_list[i].buf = dma_alloc_coherent(dev, buf_chk_sz,
- &t, GFP_KERNEL);
- if (!link_tbl->pg_list[i].buf)
- goto err_alloc_buf_failed;
+ hns_roce_buf_free(hr_dev, tbl->buf);
+}
- link_tbl->pg_list[i].map = t;
+static int hns_roce_init_link_table(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_link_table *link_tbl;
+ int ret;
- entry[i].blk_ba0 = (u32)(t >> 12);
- entry[i].blk_ba1_nxt_ptr = (u32)(t >> 44);
+ link_tbl = alloc_link_table_buf(hr_dev);
+ if (IS_ERR(link_tbl))
+ return -ENOMEM;
- if (i < (pg_num - 1))
- entry[i].blk_ba1_nxt_ptr |=
- (i + 1) << HNS_ROCE_LINK_TABLE_NXT_PTR_S;
+ if (WARN_ON(link_tbl->buf->npages > HNS_ROCE_V2_EXT_LLM_MAX_DEPTH)) {
+ ret = -EINVAL;
+ goto err_alloc;
}
- link_tbl->npages = pg_num;
- link_tbl->pg_sz = buf_chk_sz;
-
- return hns_roce_config_link_table(hr_dev, type);
-err_alloc_buf_failed:
- for (i -= 1; i >= 0; i--)
- dma_free_coherent(dev, buf_chk_sz,
- link_tbl->pg_list[i].buf,
- link_tbl->pg_list[i].map);
- kfree(link_tbl->pg_list);
+ config_llm_table(link_tbl->buf, link_tbl->table.buf);
+ ret = set_llm_cfg_to_hw(hr_dev, link_tbl);
+ if (ret)
+ goto err_alloc;
-err_kcalloc_failed:
- dma_free_coherent(dev, size, link_tbl->table.buf,
- link_tbl->table.map);
+ return 0;
-out:
- return -ENOMEM;
+err_alloc:
+ free_link_table_buf(hr_dev, link_tbl);
+ return ret;
}
-static void hns_roce_free_link_table(struct hns_roce_dev *hr_dev,
- struct hns_roce_link_table *link_tbl)
+static void hns_roce_free_link_table(struct hns_roce_dev *hr_dev)
{
- struct device *dev = hr_dev->dev;
- int size;
- int i;
-
- size = link_tbl->npages * sizeof(struct hns_roce_link_table_entry);
-
- for (i = 0; i < link_tbl->npages; ++i)
- if (link_tbl->pg_list[i].buf)
- dma_free_coherent(dev, link_tbl->pg_sz,
- link_tbl->pg_list[i].buf,
- link_tbl->pg_list[i].map);
- kfree(link_tbl->pg_list);
+ struct hns_roce_v2_priv *priv = hr_dev->priv;
- dma_free_coherent(dev, size, link_tbl->table.buf,
- link_tbl->table.map);
+ free_link_table_buf(hr_dev, &priv->ext_llm);
}
static void free_dip_list(struct hns_roce_dev *hr_dev)
@@ -2736,9 +2737,13 @@ static void put_hem_table(struct hns_roce_dev *hr_dev)
static int hns_roce_v2_init(struct hns_roce_dev *hr_dev)
{
- struct hns_roce_v2_priv *priv = hr_dev->priv;
int ret;
+ /* The hns ROCEE requires the extdb info to be cleared before using */
+ ret = hns_roce_clear_extdb_list_info(hr_dev);
+ if (ret)
+ return ret;
+
ret = get_hem_table(hr_dev);
if (ret)
return ret;
@@ -2746,40 +2751,26 @@ static int hns_roce_v2_init(struct hns_roce_dev *hr_dev)
if (hr_dev->is_vf)
return 0;
- /* TSQ includes SQ doorbell and ack doorbell */
- ret = hns_roce_init_link_table(hr_dev, TSQ_LINK_TABLE);
- if (ret) {
- dev_err(hr_dev->dev, "failed to init TSQ, ret = %d.\n", ret);
- goto err_tsq_init_failed;
- }
-
- ret = hns_roce_init_link_table(hr_dev, TPQ_LINK_TABLE);
+ ret = hns_roce_init_link_table(hr_dev);
if (ret) {
- dev_err(hr_dev->dev, "failed to init TPQ, ret = %d.\n", ret);
- goto err_tpq_init_failed;
+ dev_err(hr_dev->dev, "failed to init llm, ret = %d.\n", ret);
+ goto err_llm_init_failed;
}
return 0;
-err_tsq_init_failed:
+err_llm_init_failed:
put_hem_table(hr_dev);
-err_tpq_init_failed:
- hns_roce_free_link_table(hr_dev, &priv->tpq);
-
return ret;
}
static void hns_roce_v2_exit(struct hns_roce_dev *hr_dev)
{
- struct hns_roce_v2_priv *priv = hr_dev->priv;
-
hns_roce_function_clear(hr_dev);
- if (!hr_dev->is_vf) {
- hns_roce_free_link_table(hr_dev, &priv->tpq);
- hns_roce_free_link_table(hr_dev, &priv->tsq);
- }
+ if (!hr_dev->is_vf)
+ hns_roce_free_link_table(hr_dev);
if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP09)
free_dip_list(hr_dev);
@@ -3085,16 +3076,16 @@ static int hns_roce_v2_write_mtpt(struct hns_roce_dev *hr_dev,
hr_reg_write(mpt_entry, MPT_PD, mr->pd);
hr_reg_enable(mpt_entry, MPT_L_INV_EN);
- hr_reg_write(mpt_entry, MPT_BIND_EN,
- !!(mr->access & IB_ACCESS_MW_BIND));
- hr_reg_write(mpt_entry, MPT_ATOMIC_EN,
- !!(mr->access & IB_ACCESS_REMOTE_ATOMIC));
- hr_reg_write(mpt_entry, MPT_RR_EN,
- !!(mr->access & IB_ACCESS_REMOTE_READ));
- hr_reg_write(mpt_entry, MPT_RW_EN,
- !!(mr->access & IB_ACCESS_REMOTE_WRITE));
- hr_reg_write(mpt_entry, MPT_LW_EN,
- !!((mr->access & IB_ACCESS_LOCAL_WRITE)));
+ hr_reg_write_bool(mpt_entry, MPT_BIND_EN,
+ mr->access & IB_ACCESS_MW_BIND);
+ hr_reg_write_bool(mpt_entry, MPT_ATOMIC_EN,
+ mr->access & IB_ACCESS_REMOTE_ATOMIC);
+ hr_reg_write_bool(mpt_entry, MPT_RR_EN,
+ mr->access & IB_ACCESS_REMOTE_READ);
+ hr_reg_write_bool(mpt_entry, MPT_RW_EN,
+ mr->access & IB_ACCESS_REMOTE_WRITE);
+ hr_reg_write_bool(mpt_entry, MPT_LW_EN,
+ mr->access & IB_ACCESS_LOCAL_WRITE);
mpt_entry->len_l = cpu_to_le32(lower_32_bits(mr->size));
mpt_entry->len_h = cpu_to_le32(upper_32_bits(mr->size));
@@ -3261,8 +3252,8 @@ static void *get_sw_cqe_v2(struct hns_roce_cq *hr_cq, unsigned int n)
struct hns_roce_v2_cqe *cqe = get_cqe_v2(hr_cq, n & hr_cq->ib_cq.cqe);
/* Get cqe when Owner bit is Conversely with the MSB of cons_idx */
- return (roce_get_bit(cqe->byte_4, V2_CQE_BYTE_4_OWNER_S) ^
- !!(n & hr_cq->cq_depth)) ? cqe : NULL;
+ return (hr_reg_read(cqe, CQE_OWNER) ^ !!(n & hr_cq->cq_depth)) ? cqe :
+ NULL;
}
static inline void update_cq_db(struct hns_roce_dev *hr_dev,
@@ -3273,14 +3264,10 @@ static inline void update_cq_db(struct hns_roce_dev *hr_dev,
} else {
struct hns_roce_v2_db cq_db = {};
- roce_set_field(cq_db.byte_4, V2_DB_TAG_M, V2_DB_TAG_S,
- hr_cq->cqn);
- roce_set_field(cq_db.byte_4, V2_DB_CMD_M, V2_DB_CMD_S,
- HNS_ROCE_V2_CQ_DB);
- roce_set_field(cq_db.parameter, V2_CQ_DB_CONS_IDX_M,
- V2_CQ_DB_CONS_IDX_S, hr_cq->cons_index);
- roce_set_field(cq_db.parameter, V2_CQ_DB_CMD_SN_M,
- V2_CQ_DB_CMD_SN_S, 1);
+ hr_reg_write(&cq_db, DB_TAG, hr_cq->cqn);
+ hr_reg_write(&cq_db, DB_CMD, HNS_ROCE_V2_CQ_DB);
+ hr_reg_write(&cq_db, DB_CQ_CI, hr_cq->cons_index);
+ hr_reg_write(&cq_db, DB_CQ_CMD_SN, 1);
hns_roce_write64(hr_dev, (__le32 *)&cq_db, hr_cq->db_reg);
}
@@ -3308,25 +3295,18 @@ static void __hns_roce_v2_cq_clean(struct hns_roce_cq *hr_cq, u32 qpn,
*/
while ((int) --prod_index - (int) hr_cq->cons_index >= 0) {
cqe = get_cqe_v2(hr_cq, prod_index & hr_cq->ib_cq.cqe);
- if ((roce_get_field(cqe->byte_16, V2_CQE_BYTE_16_LCL_QPN_M,
- V2_CQE_BYTE_16_LCL_QPN_S) &
- HNS_ROCE_V2_CQE_QPN_MASK) == qpn) {
- if (srq &&
- roce_get_bit(cqe->byte_4, V2_CQE_BYTE_4_S_R_S)) {
- wqe_index = roce_get_field(cqe->byte_4,
- V2_CQE_BYTE_4_WQE_INDX_M,
- V2_CQE_BYTE_4_WQE_INDX_S);
+ if (hr_reg_read(cqe, CQE_LCL_QPN) == qpn) {
+ if (srq && hr_reg_read(cqe, CQE_S_R)) {
+ wqe_index = hr_reg_read(cqe, CQE_WQE_IDX);
hns_roce_free_srq_wqe(srq, wqe_index);
}
++nfreed;
} else if (nfreed) {
dest = get_cqe_v2(hr_cq, (prod_index + nfreed) &
hr_cq->ib_cq.cqe);
- owner_bit = roce_get_bit(dest->byte_4,
- V2_CQE_BYTE_4_OWNER_S);
+ owner_bit = hr_reg_read(dest, CQE_OWNER);
memcpy(dest, cqe, sizeof(*cqe));
- roce_set_bit(dest->byte_4, V2_CQE_BYTE_4_OWNER_S,
- owner_bit);
+ hr_reg_write(dest, CQE_OWNER, owner_bit);
}
}
@@ -3353,73 +3333,44 @@ static void hns_roce_v2_write_cqc(struct hns_roce_dev *hr_dev,
cq_context = mb_buf;
memset(cq_context, 0, sizeof(*cq_context));
- roce_set_field(cq_context->byte_4_pg_ceqn, V2_CQC_BYTE_4_CQ_ST_M,
- V2_CQC_BYTE_4_CQ_ST_S, V2_CQ_STATE_VALID);
- roce_set_field(cq_context->byte_4_pg_ceqn, V2_CQC_BYTE_4_ARM_ST_M,
- V2_CQC_BYTE_4_ARM_ST_S, REG_NXT_CEQE);
- roce_set_field(cq_context->byte_4_pg_ceqn, V2_CQC_BYTE_4_SHIFT_M,
- V2_CQC_BYTE_4_SHIFT_S, ilog2(hr_cq->cq_depth));
- roce_set_field(cq_context->byte_4_pg_ceqn, V2_CQC_BYTE_4_CEQN_M,
- V2_CQC_BYTE_4_CEQN_S, hr_cq->vector);
-
- roce_set_field(cq_context->byte_8_cqn, V2_CQC_BYTE_8_CQN_M,
- V2_CQC_BYTE_8_CQN_S, hr_cq->cqn);
+ hr_reg_write(cq_context, CQC_CQ_ST, V2_CQ_STATE_VALID);
+ hr_reg_write(cq_context, CQC_ARM_ST, REG_NXT_CEQE);
+ hr_reg_write(cq_context, CQC_SHIFT, ilog2(hr_cq->cq_depth));
+ hr_reg_write(cq_context, CQC_CEQN, hr_cq->vector);
+ hr_reg_write(cq_context, CQC_CQN, hr_cq->cqn);
- roce_set_field(cq_context->byte_8_cqn, V2_CQC_BYTE_8_CQE_SIZE_M,
- V2_CQC_BYTE_8_CQE_SIZE_S, hr_cq->cqe_size ==
- HNS_ROCE_V3_CQE_SIZE ? 1 : 0);
+ if (hr_cq->cqe_size == HNS_ROCE_V3_CQE_SIZE)
+ hr_reg_write(cq_context, CQC_CQE_SIZE, CQE_SIZE_64B);
if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_STASH)
hr_reg_enable(cq_context, CQC_STASH);
- cq_context->cqe_cur_blk_addr = cpu_to_le32(to_hr_hw_page_addr(mtts[0]));
-
- roce_set_field(cq_context->byte_16_hop_addr,
- V2_CQC_BYTE_16_CQE_CUR_BLK_ADDR_M,
- V2_CQC_BYTE_16_CQE_CUR_BLK_ADDR_S,
- upper_32_bits(to_hr_hw_page_addr(mtts[0])));
- roce_set_field(cq_context->byte_16_hop_addr,
- V2_CQC_BYTE_16_CQE_HOP_NUM_M,
- V2_CQC_BYTE_16_CQE_HOP_NUM_S, hr_dev->caps.cqe_hop_num ==
- HNS_ROCE_HOP_NUM_0 ? 0 : hr_dev->caps.cqe_hop_num);
-
- cq_context->cqe_nxt_blk_addr = cpu_to_le32(to_hr_hw_page_addr(mtts[1]));
- roce_set_field(cq_context->byte_24_pgsz_addr,
- V2_CQC_BYTE_24_CQE_NXT_BLK_ADDR_M,
- V2_CQC_BYTE_24_CQE_NXT_BLK_ADDR_S,
- upper_32_bits(to_hr_hw_page_addr(mtts[1])));
- roce_set_field(cq_context->byte_24_pgsz_addr,
- V2_CQC_BYTE_24_CQE_BA_PG_SZ_M,
- V2_CQC_BYTE_24_CQE_BA_PG_SZ_S,
- to_hr_hw_page_shift(hr_cq->mtr.hem_cfg.ba_pg_shift));
- roce_set_field(cq_context->byte_24_pgsz_addr,
- V2_CQC_BYTE_24_CQE_BUF_PG_SZ_M,
- V2_CQC_BYTE_24_CQE_BUF_PG_SZ_S,
- to_hr_hw_page_shift(hr_cq->mtr.hem_cfg.buf_pg_shift));
-
- cq_context->cqe_ba = cpu_to_le32(dma_handle >> 3);
-
- roce_set_field(cq_context->byte_40_cqe_ba, V2_CQC_BYTE_40_CQE_BA_M,
- V2_CQC_BYTE_40_CQE_BA_S, (dma_handle >> (32 + 3)));
-
- roce_set_bit(cq_context->byte_44_db_record,
- V2_CQC_BYTE_44_DB_RECORD_EN_S,
- (hr_cq->flags & HNS_ROCE_CQ_FLAG_RECORD_DB) ? 1 : 0);
-
- roce_set_field(cq_context->byte_44_db_record,
- V2_CQC_BYTE_44_DB_RECORD_ADDR_M,
- V2_CQC_BYTE_44_DB_RECORD_ADDR_S,
- ((u32)hr_cq->db.dma) >> 1);
- cq_context->db_record_addr = cpu_to_le32(hr_cq->db.dma >> 32);
-
- roce_set_field(cq_context->byte_56_cqe_period_maxcnt,
- V2_CQC_BYTE_56_CQ_MAX_CNT_M,
- V2_CQC_BYTE_56_CQ_MAX_CNT_S,
- HNS_ROCE_V2_CQ_DEFAULT_BURST_NUM);
- roce_set_field(cq_context->byte_56_cqe_period_maxcnt,
- V2_CQC_BYTE_56_CQ_PERIOD_M,
- V2_CQC_BYTE_56_CQ_PERIOD_S,
- HNS_ROCE_V2_CQ_DEFAULT_INTERVAL);
+ hr_reg_write(cq_context, CQC_CQE_CUR_BLK_ADDR_L,
+ to_hr_hw_page_addr(mtts[0]));
+ hr_reg_write(cq_context, CQC_CQE_CUR_BLK_ADDR_H,
+ upper_32_bits(to_hr_hw_page_addr(mtts[0])));
+ hr_reg_write(cq_context, CQC_CQE_HOP_NUM, hr_dev->caps.cqe_hop_num ==
+ HNS_ROCE_HOP_NUM_0 ? 0 : hr_dev->caps.cqe_hop_num);
+ hr_reg_write(cq_context, CQC_CQE_NEX_BLK_ADDR_L,
+ to_hr_hw_page_addr(mtts[1]));
+ hr_reg_write(cq_context, CQC_CQE_NEX_BLK_ADDR_H,
+ upper_32_bits(to_hr_hw_page_addr(mtts[1])));
+ hr_reg_write(cq_context, CQC_CQE_BAR_PG_SZ,
+ to_hr_hw_page_shift(hr_cq->mtr.hem_cfg.ba_pg_shift));
+ hr_reg_write(cq_context, CQC_CQE_BUF_PG_SZ,
+ to_hr_hw_page_shift(hr_cq->mtr.hem_cfg.buf_pg_shift));
+ hr_reg_write(cq_context, CQC_CQE_BA_L, dma_handle >> 3);
+ hr_reg_write(cq_context, CQC_CQE_BA_H, (dma_handle >> (32 + 3)));
+ hr_reg_write_bool(cq_context, CQC_DB_RECORD_EN,
+ hr_cq->flags & HNS_ROCE_CQ_FLAG_RECORD_DB);
+ hr_reg_write(cq_context, CQC_CQE_DB_RECORD_ADDR_L,
+ ((u32)hr_cq->db.dma) >> 1);
+ hr_reg_write(cq_context, CQC_CQE_DB_RECORD_ADDR_H,
+ hr_cq->db.dma >> 32);
+ hr_reg_write(cq_context, CQC_CQ_MAX_CNT,
+ HNS_ROCE_V2_CQ_DEFAULT_BURST_NUM);
+ hr_reg_write(cq_context, CQC_CQ_PERIOD,
+ HNS_ROCE_V2_CQ_DEFAULT_INTERVAL);
}
static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq,
@@ -3437,14 +3388,11 @@ static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq,
notify_flag = (flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
V2_CQ_DB_REQ_NOT : V2_CQ_DB_REQ_NOT_SOL;
- roce_set_field(cq_db.byte_4, V2_DB_TAG_M, V2_DB_TAG_S, hr_cq->cqn);
- roce_set_field(cq_db.byte_4, V2_DB_CMD_M, V2_DB_CMD_S,
- HNS_ROCE_V2_CQ_DB_NOTIFY);
- roce_set_field(cq_db.parameter, V2_CQ_DB_CONS_IDX_M,
- V2_CQ_DB_CONS_IDX_S, hr_cq->cons_index);
- roce_set_field(cq_db.parameter, V2_CQ_DB_CMD_SN_M,
- V2_CQ_DB_CMD_SN_S, hr_cq->arm_sn);
- roce_set_bit(cq_db.parameter, V2_CQ_DB_NOTIFY_TYPE_S, notify_flag);
+ hr_reg_write(&cq_db, DB_TAG, hr_cq->cqn);
+ hr_reg_write(&cq_db, DB_CMD, HNS_ROCE_V2_CQ_DB_NOTIFY);
+ hr_reg_write(&cq_db, DB_CQ_CI, hr_cq->cons_index);
+ hr_reg_write(&cq_db, DB_CQ_CMD_SN, hr_cq->arm_sn);
+ hr_reg_write(&cq_db, DB_CQ_NOTIFY, notify_flag);
hns_roce_write64(hr_dev, (__le32 *)&cq_db, hr_cq->db_reg);
@@ -3460,8 +3408,7 @@ static int hns_roce_handle_recv_inl_wqe(struct hns_roce_v2_cqe *cqe,
u32 sge_cnt, data_len, size;
void *wqe_buf;
- wr_num = roce_get_field(cqe->byte_4, V2_CQE_BYTE_4_WQE_INDX_M,
- V2_CQE_BYTE_4_WQE_INDX_S) & 0xffff;
+ wr_num = hr_reg_read(cqe, CQE_WQE_IDX);
wr_cnt = wr_num & (qp->rq.wqe_cnt - 1);
sge_list = qp->rq_inl_buf.wqe_list[wr_cnt].sg_list;
@@ -3560,8 +3507,7 @@ static void get_cqe_status(struct hns_roce_dev *hr_dev, struct hns_roce_qp *qp,
{ HNS_ROCE_CQE_V2_GENERAL_ERR, IB_WC_GENERAL_ERR}
};
- u32 cqe_status = roce_get_field(cqe->byte_4, V2_CQE_BYTE_4_STATUS_M,
- V2_CQE_BYTE_4_STATUS_S);
+ u32 cqe_status = hr_reg_read(cqe, CQE_STATUS);
int i;
wc->status = IB_WC_GENERAL_ERR;
@@ -3578,6 +3524,7 @@ static void get_cqe_status(struct hns_roce_dev *hr_dev, struct hns_roce_qp *qp,
ibdev_err(&hr_dev->ib_dev, "error cqe status 0x%x:\n", cqe_status);
print_hex_dump(KERN_ERR, "", DUMP_PREFIX_NONE, 16, 4, cqe,
cq->cqe_size, false);
+ wc->vendor_err = hr_reg_read(cqe, CQE_SUB_STATUS);
/*
* For hns ROCEE, GENERAL_ERR is an error type that is not defined in
@@ -3587,17 +3534,7 @@ static void get_cqe_status(struct hns_roce_dev *hr_dev, struct hns_roce_qp *qp,
if (cqe_status == HNS_ROCE_CQE_V2_GENERAL_ERR)
return;
- /*
- * Hip08 hardware cannot flush the WQEs in SQ/RQ if the QP state gets
- * into errored mode. Hence, as a workaround to this hardware
- * limitation, driver needs to assist in flushing. But the flushing
- * operation uses mailbox to convey the QP state to the hardware and
- * which can sleep due to the mutex protection around the mailbox calls.
- * Hence, use the deferred flush for now. Once wc error detected, the
- * flushing operation is needed.
- */
- if (!test_and_set_bit(HNS_ROCE_FLUSH_FLAG, &qp->flush_flag))
- init_flush_work(hr_dev, qp);
+ flush_cqe(hr_dev, qp);
}
static int get_cur_qp(struct hns_roce_cq *hr_cq, struct hns_roce_v2_cqe *cqe,
@@ -3607,9 +3544,7 @@ static int get_cur_qp(struct hns_roce_cq *hr_cq, struct hns_roce_v2_cqe *cqe,
struct hns_roce_qp *hr_qp = *cur_qp;
u32 qpn;
- qpn = roce_get_field(cqe->byte_16, V2_CQE_BYTE_16_LCL_QPN_M,
- V2_CQE_BYTE_16_LCL_QPN_S) &
- HNS_ROCE_V2_CQE_QPN_MASK;
+ qpn = hr_reg_read(cqe, CQE_LCL_QPN);
if (!hr_qp || qpn != hr_qp->qpn) {
hr_qp = __hns_roce_qp_lookup(hr_dev, qpn);
@@ -3683,8 +3618,7 @@ static void fill_send_wc(struct ib_wc *wc, struct hns_roce_v2_cqe *cqe)
wc->wc_flags = 0;
- hr_opcode = roce_get_field(cqe->byte_4, V2_CQE_BYTE_4_OPCODE_M,
- V2_CQE_BYTE_4_OPCODE_S) & 0x1f;
+ hr_opcode = hr_reg_read(cqe, CQE_OPCODE);
switch (hr_opcode) {
case HNS_ROCE_V2_WQE_OP_RDMA_READ:
wc->byte_len = le32_to_cpu(cqe->byte_cnt);
@@ -3716,12 +3650,11 @@ static void fill_send_wc(struct ib_wc *wc, struct hns_roce_v2_cqe *cqe)
static inline bool is_rq_inl_enabled(struct ib_wc *wc, u32 hr_opcode,
struct hns_roce_v2_cqe *cqe)
{
- return wc->qp->qp_type != IB_QPT_UD &&
- wc->qp->qp_type != IB_QPT_GSI &&
+ return wc->qp->qp_type != IB_QPT_UD && wc->qp->qp_type != IB_QPT_GSI &&
(hr_opcode == HNS_ROCE_V2_OPCODE_SEND ||
hr_opcode == HNS_ROCE_V2_OPCODE_SEND_WITH_IMM ||
hr_opcode == HNS_ROCE_V2_OPCODE_SEND_WITH_INV) &&
- roce_get_bit(cqe->byte_4, V2_CQE_BYTE_4_RQ_INLINE_S);
+ hr_reg_read(cqe, CQE_RQ_INLINE);
}
static int fill_recv_wc(struct ib_wc *wc, struct hns_roce_v2_cqe *cqe)
@@ -3733,8 +3666,7 @@ static int fill_recv_wc(struct ib_wc *wc, struct hns_roce_v2_cqe *cqe)
wc->byte_len = le32_to_cpu(cqe->byte_cnt);
- hr_opcode = roce_get_field(cqe->byte_4, V2_CQE_BYTE_4_OPCODE_M,
- V2_CQE_BYTE_4_OPCODE_S) & 0x1f;
+ hr_opcode = hr_reg_read(cqe, CQE_OPCODE);
switch (hr_opcode) {
case HNS_ROCE_V2_OPCODE_RDMA_WRITE_IMM:
case HNS_ROCE_V2_OPCODE_SEND_WITH_IMM:
@@ -3761,28 +3693,21 @@ static int fill_recv_wc(struct ib_wc *wc, struct hns_roce_v2_cqe *cqe)
return ret;
}
- wc->sl = roce_get_field(cqe->byte_32, V2_CQE_BYTE_32_SL_M,
- V2_CQE_BYTE_32_SL_S);
- wc->src_qp = roce_get_field(cqe->byte_32, V2_CQE_BYTE_32_RMT_QPN_M,
- V2_CQE_BYTE_32_RMT_QPN_S);
+ wc->sl = hr_reg_read(cqe, CQE_SL);
+ wc->src_qp = hr_reg_read(cqe, CQE_RMT_QPN);
wc->slid = 0;
- wc->wc_flags |= roce_get_bit(cqe->byte_32, V2_CQE_BYTE_32_GRH_S) ?
- IB_WC_GRH : 0;
- wc->port_num = roce_get_field(cqe->byte_32, V2_CQE_BYTE_32_PORTN_M,
- V2_CQE_BYTE_32_PORTN_S);
+ wc->wc_flags |= hr_reg_read(cqe, CQE_GRH) ? IB_WC_GRH : 0;
+ wc->port_num = hr_reg_read(cqe, CQE_PORTN);
wc->pkey_index = 0;
- if (roce_get_bit(cqe->byte_28, V2_CQE_BYTE_28_VID_VLD_S)) {
- wc->vlan_id = roce_get_field(cqe->byte_28, V2_CQE_BYTE_28_VID_M,
- V2_CQE_BYTE_28_VID_S);
+ if (hr_reg_read(cqe, CQE_VID_VLD)) {
+ wc->vlan_id = hr_reg_read(cqe, CQE_VID);
wc->wc_flags |= IB_WC_WITH_VLAN;
} else {
wc->vlan_id = 0xffff;
}
- wc->network_hdr_type = roce_get_field(cqe->byte_28,
- V2_CQE_BYTE_28_PORT_TYPE_M,
- V2_CQE_BYTE_28_PORT_TYPE_S);
+ wc->network_hdr_type = hr_reg_read(cqe, CQE_PORT_TYPE);
return 0;
}
@@ -3814,10 +3739,9 @@ static int hns_roce_v2_poll_one(struct hns_roce_cq *hr_cq,
wc->qp = &qp->ibqp;
wc->vendor_err = 0;
- wqe_idx = roce_get_field(cqe->byte_4, V2_CQE_BYTE_4_WQE_INDX_M,
- V2_CQE_BYTE_4_WQE_INDX_S);
+ wqe_idx = hr_reg_read(cqe, CQE_WQE_IDX);
- is_send = !roce_get_bit(cqe->byte_4, V2_CQE_BYTE_4_S_R_S);
+ is_send = !hr_reg_read(cqe, CQE_S_R);
if (is_send) {
wq = &qp->sq;
@@ -4116,38 +4040,33 @@ static void set_access_flags(struct hns_roce_qp *hr_qp,
if (!dest_rd_atomic)
access_flags &= IB_ACCESS_REMOTE_WRITE;
- roce_set_bit(context->byte_76_srqn_op_en, V2_QPC_BYTE_76_RRE_S,
- !!(access_flags & IB_ACCESS_REMOTE_READ));
- roce_set_bit(qpc_mask->byte_76_srqn_op_en, V2_QPC_BYTE_76_RRE_S, 0);
+ hr_reg_write_bool(context, QPC_RRE,
+ access_flags & IB_ACCESS_REMOTE_READ);
+ hr_reg_clear(qpc_mask, QPC_RRE);
- roce_set_bit(context->byte_76_srqn_op_en, V2_QPC_BYTE_76_RWE_S,
- !!(access_flags & IB_ACCESS_REMOTE_WRITE));
- roce_set_bit(qpc_mask->byte_76_srqn_op_en, V2_QPC_BYTE_76_RWE_S, 0);
+ hr_reg_write_bool(context, QPC_RWE,
+ access_flags & IB_ACCESS_REMOTE_WRITE);
+ hr_reg_clear(qpc_mask, QPC_RWE);
- roce_set_bit(context->byte_76_srqn_op_en, V2_QPC_BYTE_76_ATE_S,
- !!(access_flags & IB_ACCESS_REMOTE_ATOMIC));
- roce_set_bit(qpc_mask->byte_76_srqn_op_en, V2_QPC_BYTE_76_ATE_S, 0);
- roce_set_bit(context->byte_76_srqn_op_en, V2_QPC_BYTE_76_EXT_ATE_S,
- !!(access_flags & IB_ACCESS_REMOTE_ATOMIC));
- roce_set_bit(qpc_mask->byte_76_srqn_op_en, V2_QPC_BYTE_76_EXT_ATE_S, 0);
+ hr_reg_write_bool(context, QPC_ATE,
+ access_flags & IB_ACCESS_REMOTE_ATOMIC);
+ hr_reg_clear(qpc_mask, QPC_ATE);
+ hr_reg_write_bool(context, QPC_EXT_ATE,
+ access_flags & IB_ACCESS_REMOTE_ATOMIC);
+ hr_reg_clear(qpc_mask, QPC_EXT_ATE);
}
static void set_qpc_wqe_cnt(struct hns_roce_qp *hr_qp,
struct hns_roce_v2_qp_context *context,
struct hns_roce_v2_qp_context *qpc_mask)
{
- roce_set_field(context->byte_4_sqpn_tst,
- V2_QPC_BYTE_4_SGE_SHIFT_M, V2_QPC_BYTE_4_SGE_SHIFT_S,
- to_hr_hem_entries_shift(hr_qp->sge.sge_cnt,
- hr_qp->sge.sge_shift));
+ hr_reg_write(context, QPC_SGE_SHIFT,
+ to_hr_hem_entries_shift(hr_qp->sge.sge_cnt,
+ hr_qp->sge.sge_shift));
- roce_set_field(context->byte_20_smac_sgid_idx,
- V2_QPC_BYTE_20_SQ_SHIFT_M, V2_QPC_BYTE_20_SQ_SHIFT_S,
- ilog2(hr_qp->sq.wqe_cnt));
+ hr_reg_write(context, QPC_SQ_SHIFT, ilog2(hr_qp->sq.wqe_cnt));
- roce_set_field(context->byte_20_smac_sgid_idx,
- V2_QPC_BYTE_20_RQ_SHIFT_M, V2_QPC_BYTE_20_RQ_SHIFT_S,
- ilog2(hr_qp->rq.wqe_cnt));
+ hr_reg_write(context, QPC_RQ_SHIFT, ilog2(hr_qp->rq.wqe_cnt));
}
static inline int get_cqn(struct ib_cq *ib_cq)
@@ -4175,62 +4094,45 @@ static void modify_qp_reset_to_init(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.
*/
- roce_set_field(context->byte_4_sqpn_tst, V2_QPC_BYTE_4_TST_M,
- V2_QPC_BYTE_4_TST_S, to_hr_qp_type(ibqp->qp_type));
-
- roce_set_field(context->byte_4_sqpn_tst, V2_QPC_BYTE_4_SQPN_M,
- V2_QPC_BYTE_4_SQPN_S, hr_qp->qpn);
+ hr_reg_write(context, QPC_TST, to_hr_qp_type(ibqp->qp_type));
- roce_set_field(context->byte_16_buf_ba_pg_sz, V2_QPC_BYTE_16_PD_M,
- V2_QPC_BYTE_16_PD_S, get_pdn(ibqp->pd));
+ hr_reg_write(context, QPC_PD, get_pdn(ibqp->pd));
- roce_set_field(context->byte_20_smac_sgid_idx, V2_QPC_BYTE_20_RQWS_M,
- V2_QPC_BYTE_20_RQWS_S, ilog2(hr_qp->rq.max_gs));
+ hr_reg_write(context, QPC_RQWS, ilog2(hr_qp->rq.max_gs));
set_qpc_wqe_cnt(hr_qp, context, qpc_mask);
/* No VLAN need to set 0xFFF */
- roce_set_field(context->byte_24_mtu_tc, V2_QPC_BYTE_24_VLAN_ID_M,
- V2_QPC_BYTE_24_VLAN_ID_S, 0xfff);
+ hr_reg_write(context, QPC_VLAN_ID, 0xfff);
if (ibqp->qp_type == IB_QPT_XRC_TGT) {
context->qkey_xrcd = cpu_to_le32(hr_qp->xrcdn);
- roce_set_bit(context->byte_80_rnr_rx_cqn,
- V2_QPC_BYTE_80_XRC_QP_TYPE_S, 1);
+ hr_reg_enable(context, QPC_XRC_QP_TYPE);
}
if (hr_qp->en_flags & HNS_ROCE_QP_CAP_RQ_RECORD_DB)
- roce_set_bit(context->byte_68_rq_db,
- V2_QPC_BYTE_68_RQ_RECORD_EN_S, 1);
+ hr_reg_enable(context, QPC_RQ_RECORD_EN);
- roce_set_field(context->byte_68_rq_db,
- V2_QPC_BYTE_68_RQ_DB_RECORD_ADDR_M,
- V2_QPC_BYTE_68_RQ_DB_RECORD_ADDR_S,
- ((u32)hr_qp->rdb.dma) >> 1);
- context->rq_db_record_addr = cpu_to_le32(hr_qp->rdb.dma >> 32);
+ hr_reg_write(context, QPC_RQ_DB_RECORD_ADDR_L,
+ lower_32_bits(hr_qp->rdb.dma) >> 1);
+ hr_reg_write(context, QPC_RQ_DB_RECORD_ADDR_H,
+ upper_32_bits(hr_qp->rdb.dma));
if (ibqp->qp_type != IB_QPT_UD && ibqp->qp_type != IB_QPT_GSI)
- roce_set_bit(context->byte_76_srqn_op_en,
- V2_QPC_BYTE_76_RQIE_S,
- !!(hr_dev->caps.flags &
- HNS_ROCE_CAP_FLAG_RQ_INLINE));
+ hr_reg_write_bool(context, QPC_RQIE,
+ hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE);
- roce_set_field(context->byte_80_rnr_rx_cqn, V2_QPC_BYTE_80_RX_CQN_M,
- V2_QPC_BYTE_80_RX_CQN_S, get_cqn(ibqp->recv_cq));
+ hr_reg_write(context, QPC_RX_CQN, get_cqn(ibqp->recv_cq));
if (ibqp->srq) {
- roce_set_bit(context->byte_76_srqn_op_en,
- V2_QPC_BYTE_76_SRQ_EN_S, 1);
- roce_set_field(context->byte_76_srqn_op_en,
- V2_QPC_BYTE_76_SRQN_M, V2_QPC_BYTE_76_SRQN_S,
- to_hr_srq(ibqp->srq)->srqn);
+ hr_reg_enable(context, QPC_SRQ_EN);
+ hr_reg_write(context, QPC_SRQN, to_hr_srq(ibqp->srq)->srqn);
}
- roce_set_bit(context->byte_172_sq_psn, V2_QPC_BYTE_172_FRE_S, 1);
+ hr_reg_enable(context, QPC_FRE);
- roce_set_field(context->byte_252_err_txcqn, V2_QPC_BYTE_252_TX_CQN_M,
- V2_QPC_BYTE_252_TX_CQN_S, get_cqn(ibqp->send_cq));
+ hr_reg_write(context, QPC_TX_CQN, get_cqn(ibqp->send_cq));
if (hr_dev->caps.qpc_sz < HNS_ROCE_V3_QPC_SZ)
return;
@@ -4252,49 +4154,28 @@ static void modify_qp_init_to_init(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.
*/
- roce_set_field(context->byte_4_sqpn_tst, V2_QPC_BYTE_4_TST_M,
- V2_QPC_BYTE_4_TST_S, to_hr_qp_type(ibqp->qp_type));
- roce_set_field(qpc_mask->byte_4_sqpn_tst, V2_QPC_BYTE_4_TST_M,
- V2_QPC_BYTE_4_TST_S, 0);
+ hr_reg_write(context, QPC_TST, to_hr_qp_type(ibqp->qp_type));
+ hr_reg_clear(qpc_mask, QPC_TST);
- roce_set_field(context->byte_16_buf_ba_pg_sz, V2_QPC_BYTE_16_PD_M,
- V2_QPC_BYTE_16_PD_S, get_pdn(ibqp->pd));
+ hr_reg_write(context, QPC_PD, get_pdn(ibqp->pd));
+ hr_reg_clear(qpc_mask, QPC_PD);
- roce_set_field(qpc_mask->byte_16_buf_ba_pg_sz, V2_QPC_BYTE_16_PD_M,
- V2_QPC_BYTE_16_PD_S, 0);
+ hr_reg_write(context, QPC_RX_CQN, get_cqn(ibqp->recv_cq));
+ hr_reg_clear(qpc_mask, QPC_RX_CQN);
- roce_set_field(context->byte_80_rnr_rx_cqn, V2_QPC_BYTE_80_RX_CQN_M,
- V2_QPC_BYTE_80_RX_CQN_S, get_cqn(ibqp->recv_cq));
- roce_set_field(qpc_mask->byte_80_rnr_rx_cqn, V2_QPC_BYTE_80_RX_CQN_M,
- V2_QPC_BYTE_80_RX_CQN_S, 0);
-
- roce_set_field(context->byte_252_err_txcqn, V2_QPC_BYTE_252_TX_CQN_M,
- V2_QPC_BYTE_252_TX_CQN_S, get_cqn(ibqp->send_cq));
- roce_set_field(qpc_mask->byte_252_err_txcqn, V2_QPC_BYTE_252_TX_CQN_M,
- V2_QPC_BYTE_252_TX_CQN_S, 0);
+ hr_reg_write(context, QPC_TX_CQN, get_cqn(ibqp->send_cq));
+ hr_reg_clear(qpc_mask, QPC_TX_CQN);
if (ibqp->srq) {
- roce_set_bit(context->byte_76_srqn_op_en,
- V2_QPC_BYTE_76_SRQ_EN_S, 1);
- roce_set_bit(qpc_mask->byte_76_srqn_op_en,
- V2_QPC_BYTE_76_SRQ_EN_S, 0);
- roce_set_field(context->byte_76_srqn_op_en,
- V2_QPC_BYTE_76_SRQN_M, V2_QPC_BYTE_76_SRQN_S,
- to_hr_srq(ibqp->srq)->srqn);
- roce_set_field(qpc_mask->byte_76_srqn_op_en,
- V2_QPC_BYTE_76_SRQN_M, V2_QPC_BYTE_76_SRQN_S, 0);
- }
-
- roce_set_field(context->byte_4_sqpn_tst, V2_QPC_BYTE_4_SQPN_M,
- V2_QPC_BYTE_4_SQPN_S, hr_qp->qpn);
- roce_set_field(qpc_mask->byte_4_sqpn_tst, V2_QPC_BYTE_4_SQPN_M,
- V2_QPC_BYTE_4_SQPN_S, 0);
+ hr_reg_enable(context, QPC_SRQ_EN);
+ hr_reg_clear(qpc_mask, QPC_SRQ_EN);
+ hr_reg_write(context, QPC_SRQN, to_hr_srq(ibqp->srq)->srqn);
+ hr_reg_clear(qpc_mask, QPC_SRQN);
+ }
if (attr_mask & IB_QP_DEST_QPN) {
- roce_set_field(context->byte_56_dqpn_err, V2_QPC_BYTE_56_DQPN_M,
- V2_QPC_BYTE_56_DQPN_S, hr_qp->qpn);
- roce_set_field(qpc_mask->byte_56_dqpn_err,
- V2_QPC_BYTE_56_DQPN_M, V2_QPC_BYTE_56_DQPN_S, 0);
+ hr_reg_write(context, QPC_DQPN, hr_qp->qpn);
+ hr_reg_clear(qpc_mask, QPC_DQPN);
}
}
@@ -4325,74 +4206,46 @@ static int config_qp_rq_buf(struct hns_roce_dev *hr_dev,
* we should set all bits of the relevant fields in context mask to
* 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, 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,
- to_hr_hem_hopnum(hr_dev->caps.wqe_sq_hop_num,
- hr_qp->sq.wqe_cnt));
- 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,
- to_hr_hem_hopnum(hr_dev->caps.wqe_sge_hop_num,
- hr_qp->sge.sge_cnt));
- 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);
-
- 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,
- to_hr_hem_hopnum(hr_dev->caps.wqe_rq_hop_num,
- hr_qp->rq.wqe_cnt));
-
- 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);
-
- 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,
- to_hr_hw_page_shift(hr_qp->mtr.hem_cfg.ba_pg_shift));
- 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);
-
- roce_set_field(context->byte_16_buf_ba_pg_sz,
- V2_QPC_BYTE_16_WQE_SGE_BUF_PG_SZ_M,
- V2_QPC_BYTE_16_WQE_SGE_BUF_PG_SZ_S,
- to_hr_hw_page_shift(hr_qp->mtr.hem_cfg.buf_pg_shift));
- roce_set_field(qpc_mask->byte_16_buf_ba_pg_sz,
- V2_QPC_BYTE_16_WQE_SGE_BUF_PG_SZ_M,
- V2_QPC_BYTE_16_WQE_SGE_BUF_PG_SZ_S, 0);
+ hr_reg_write(context, QPC_WQE_SGE_BA_H, wqe_sge_ba >> (32 + 3));
+ hr_reg_clear(qpc_mask, QPC_WQE_SGE_BA_H);
+
+ hr_reg_write(context, QPC_SQ_HOP_NUM,
+ to_hr_hem_hopnum(hr_dev->caps.wqe_sq_hop_num,
+ hr_qp->sq.wqe_cnt));
+ hr_reg_clear(qpc_mask, QPC_SQ_HOP_NUM);
+
+ hr_reg_write(context, QPC_SGE_HOP_NUM,
+ to_hr_hem_hopnum(hr_dev->caps.wqe_sge_hop_num,
+ hr_qp->sge.sge_cnt));
+ hr_reg_clear(qpc_mask, QPC_SGE_HOP_NUM);
+
+ hr_reg_write(context, QPC_RQ_HOP_NUM,
+ to_hr_hem_hopnum(hr_dev->caps.wqe_rq_hop_num,
+ hr_qp->rq.wqe_cnt));
+
+ hr_reg_clear(qpc_mask, QPC_RQ_HOP_NUM);
+
+ hr_reg_write(context, QPC_WQE_SGE_BA_PG_SZ,
+ to_hr_hw_page_shift(hr_qp->mtr.hem_cfg.ba_pg_shift));
+ hr_reg_clear(qpc_mask, QPC_WQE_SGE_BA_PG_SZ);
+
+ hr_reg_write(context, QPC_WQE_SGE_BUF_PG_SZ,
+ to_hr_hw_page_shift(hr_qp->mtr.hem_cfg.buf_pg_shift));
+ hr_reg_clear(qpc_mask, QPC_WQE_SGE_BUF_PG_SZ);
context->rq_cur_blk_addr = cpu_to_le32(to_hr_hw_page_addr(mtts[0]));
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,
- upper_32_bits(to_hr_hw_page_addr(mtts[0])));
- 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);
+ hr_reg_write(context, QPC_RQ_CUR_BLK_ADDR_H,
+ upper_32_bits(to_hr_hw_page_addr(mtts[0])));
+ hr_reg_clear(qpc_mask, QPC_RQ_CUR_BLK_ADDR_H);
context->rq_nxt_blk_addr = cpu_to_le32(to_hr_hw_page_addr(mtts[1]));
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,
- upper_32_bits(to_hr_hw_page_addr(mtts[1])));
- 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);
+ hr_reg_write(context, QPC_RQ_NXT_BLK_ADDR_H,
+ upper_32_bits(to_hr_hw_page_addr(mtts[1])));
+ hr_reg_clear(qpc_mask, QPC_RQ_NXT_BLK_ADDR_H);
return 0;
}
@@ -4431,37 +4284,26 @@ static int config_qp_sq_buf(struct hns_roce_dev *hr_dev,
* 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 = cpu_to_le32(to_hr_hw_page_addr(sq_cur_blk));
- 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,
- upper_32_bits(to_hr_hw_page_addr(sq_cur_blk)));
- 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);
-
- context->sq_cur_sge_blk_addr =
- cpu_to_le32(to_hr_hw_page_addr(sge_cur_blk));
- 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,
- upper_32_bits(to_hr_hw_page_addr(sge_cur_blk)));
- 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 =
- cpu_to_le32(to_hr_hw_page_addr(sq_cur_blk));
- 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,
- upper_32_bits(to_hr_hw_page_addr(sq_cur_blk)));
- 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,
- V2_QPC_BYTE_232_RX_SQ_CUR_BLK_ADDR_S, 0);
+ hr_reg_write(context, QPC_SQ_CUR_BLK_ADDR_L,
+ lower_32_bits(to_hr_hw_page_addr(sq_cur_blk)));
+ hr_reg_write(context, QPC_SQ_CUR_BLK_ADDR_H,
+ upper_32_bits(to_hr_hw_page_addr(sq_cur_blk)));
+ hr_reg_clear(qpc_mask, QPC_SQ_CUR_BLK_ADDR_L);
+ hr_reg_clear(qpc_mask, QPC_SQ_CUR_BLK_ADDR_H);
+
+ hr_reg_write(context, QPC_SQ_CUR_SGE_BLK_ADDR_L,
+ lower_32_bits(to_hr_hw_page_addr(sge_cur_blk)));
+ hr_reg_write(context, QPC_SQ_CUR_SGE_BLK_ADDR_H,
+ upper_32_bits(to_hr_hw_page_addr(sge_cur_blk)));
+ hr_reg_clear(qpc_mask, QPC_SQ_CUR_SGE_BLK_ADDR_L);
+ hr_reg_clear(qpc_mask, QPC_SQ_CUR_SGE_BLK_ADDR_H);
+
+ hr_reg_write(context, QPC_RX_SQ_CUR_BLK_ADDR_L,
+ lower_32_bits(to_hr_hw_page_addr(sq_cur_blk)));
+ hr_reg_write(context, QPC_RX_SQ_CUR_BLK_ADDR_H,
+ upper_32_bits(to_hr_hw_page_addr(sq_cur_blk)));
+ hr_reg_clear(qpc_mask, QPC_RX_SQ_CUR_BLK_ADDR_L);
+ hr_reg_clear(qpc_mask, QPC_RX_SQ_CUR_BLK_ADDR_H);
return 0;
}
@@ -4485,12 +4327,13 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
struct ib_device *ibdev = &hr_dev->ib_dev;
dma_addr_t trrl_ba;
dma_addr_t irrl_ba;
- enum ib_mtu mtu;
+ enum ib_mtu ib_mtu;
u8 lp_pktn_ini;
u64 *mtts;
u8 *dmac;
u8 *smac;
u32 port;
+ int mtu;
int ret;
ret = config_qp_rq_buf(hr_dev, hr_qp, context, qpc_mask);
@@ -4521,33 +4364,23 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
return -EINVAL;
}
- roce_set_field(context->byte_132_trrl, V2_QPC_BYTE_132_TRRL_BA_M,
- V2_QPC_BYTE_132_TRRL_BA_S, trrl_ba >> 4);
- roce_set_field(qpc_mask->byte_132_trrl, V2_QPC_BYTE_132_TRRL_BA_M,
- V2_QPC_BYTE_132_TRRL_BA_S, 0);
+ hr_reg_write(context, QPC_TRRL_BA_L, trrl_ba >> 4);
+ hr_reg_clear(qpc_mask, QPC_TRRL_BA_L);
context->trrl_ba = cpu_to_le32(trrl_ba >> (16 + 4));
qpc_mask->trrl_ba = 0;
- roce_set_field(context->byte_140_raq, V2_QPC_BYTE_140_TRRL_BA_M,
- V2_QPC_BYTE_140_TRRL_BA_S,
- (u32)(trrl_ba >> (32 + 16 + 4)));
- roce_set_field(qpc_mask->byte_140_raq, V2_QPC_BYTE_140_TRRL_BA_M,
- V2_QPC_BYTE_140_TRRL_BA_S, 0);
+ hr_reg_write(context, QPC_TRRL_BA_H, trrl_ba >> (32 + 16 + 4));
+ hr_reg_clear(qpc_mask, QPC_TRRL_BA_H);
context->irrl_ba = cpu_to_le32(irrl_ba >> 6);
qpc_mask->irrl_ba = 0;
- roce_set_field(context->byte_208_irrl, V2_QPC_BYTE_208_IRRL_BA_M,
- V2_QPC_BYTE_208_IRRL_BA_S,
- irrl_ba >> (32 + 6));
- roce_set_field(qpc_mask->byte_208_irrl, V2_QPC_BYTE_208_IRRL_BA_M,
- V2_QPC_BYTE_208_IRRL_BA_S, 0);
+ hr_reg_write(context, QPC_IRRL_BA_H, irrl_ba >> (32 + 6));
+ hr_reg_clear(qpc_mask, QPC_IRRL_BA_H);
- roce_set_bit(context->byte_208_irrl, V2_QPC_BYTE_208_RMT_E2E_S, 1);
- roce_set_bit(qpc_mask->byte_208_irrl, V2_QPC_BYTE_208_RMT_E2E_S, 0);
+ hr_reg_enable(context, QPC_RMT_E2E);
+ hr_reg_clear(qpc_mask, QPC_RMT_E2E);
- roce_set_bit(context->byte_252_err_txcqn, V2_QPC_BYTE_252_SIG_TYPE_S,
- hr_qp->sq_signal_bits);
- roce_set_bit(qpc_mask->byte_252_err_txcqn, V2_QPC_BYTE_252_SIG_TYPE_S,
- 0);
+ hr_reg_write(context, QPC_SIG_TYPE, hr_qp->sq_signal_bits);
+ hr_reg_clear(qpc_mask, QPC_SIG_TYPE);
port = (attr_mask & IB_QP_PORT) ? (attr->port_num - 1) : hr_qp->port;
@@ -4556,73 +4389,56 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
/* when dmac equals smac or loop_idc is 1, it should loopback */
if (ether_addr_equal_unaligned(dmac, smac) ||
hr_dev->loop_idc == 0x1) {
- roce_set_bit(context->byte_28_at_fl, V2_QPC_BYTE_28_LBI_S, 1);
- roce_set_bit(qpc_mask->byte_28_at_fl, V2_QPC_BYTE_28_LBI_S, 0);
+ hr_reg_write(context, QPC_LBI, hr_dev->loop_idc);
+ hr_reg_clear(qpc_mask, QPC_LBI);
}
if (attr_mask & IB_QP_DEST_QPN) {
- roce_set_field(context->byte_56_dqpn_err, V2_QPC_BYTE_56_DQPN_M,
- V2_QPC_BYTE_56_DQPN_S, attr->dest_qp_num);
- roce_set_field(qpc_mask->byte_56_dqpn_err,
- V2_QPC_BYTE_56_DQPN_M, V2_QPC_BYTE_56_DQPN_S, 0);
+ hr_reg_write(context, QPC_DQPN, attr->dest_qp_num);
+ hr_reg_clear(qpc_mask, QPC_DQPN);
}
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])));
+ hr_reg_write(context, QPC_DMAC_H, *((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);
+ hr_reg_clear(qpc_mask, QPC_DMAC_H);
+
+ ib_mtu = get_mtu(ibqp, attr);
+ hr_qp->path_mtu = ib_mtu;
- mtu = get_mtu(ibqp, attr);
- hr_qp->path_mtu = mtu;
+ mtu = ib_mtu_enum_to_int(ib_mtu);
+ if (WARN_ON(mtu < 0))
+ return -EINVAL;
if (attr_mask & IB_QP_PATH_MTU) {
- roce_set_field(context->byte_24_mtu_tc, V2_QPC_BYTE_24_MTU_M,
- V2_QPC_BYTE_24_MTU_S, mtu);
- roce_set_field(qpc_mask->byte_24_mtu_tc, V2_QPC_BYTE_24_MTU_M,
- V2_QPC_BYTE_24_MTU_S, 0);
+ hr_reg_write(context, QPC_MTU, ib_mtu);
+ hr_reg_clear(qpc_mask, QPC_MTU);
}
#define MAX_LP_MSG_LEN 65536
/* MTU * (2 ^ LP_PKTN_INI) shouldn't be bigger than 64KB */
- lp_pktn_ini = ilog2(MAX_LP_MSG_LEN / ib_mtu_enum_to_int(mtu));
+ lp_pktn_ini = ilog2(MAX_LP_MSG_LEN / mtu);
- roce_set_field(context->byte_56_dqpn_err, V2_QPC_BYTE_56_LP_PKTN_INI_M,
- V2_QPC_BYTE_56_LP_PKTN_INI_S, lp_pktn_ini);
- roce_set_field(qpc_mask->byte_56_dqpn_err, V2_QPC_BYTE_56_LP_PKTN_INI_M,
- V2_QPC_BYTE_56_LP_PKTN_INI_S, 0);
+ hr_reg_write(context, QPC_LP_PKTN_INI, lp_pktn_ini);
+ hr_reg_clear(qpc_mask, QPC_LP_PKTN_INI);
/* ACK_REQ_FREQ should be larger than or equal to LP_PKTN_INI */
- roce_set_field(context->byte_172_sq_psn, V2_QPC_BYTE_172_ACK_REQ_FREQ_M,
- V2_QPC_BYTE_172_ACK_REQ_FREQ_S, lp_pktn_ini);
- roce_set_field(qpc_mask->byte_172_sq_psn,
- V2_QPC_BYTE_172_ACK_REQ_FREQ_M,
- V2_QPC_BYTE_172_ACK_REQ_FREQ_S, 0);
-
- roce_set_bit(qpc_mask->byte_108_rx_reqepsn,
- V2_QPC_BYTE_108_RX_REQ_PSN_ERR_S, 0);
- roce_set_field(qpc_mask->byte_96_rx_reqmsn, V2_QPC_BYTE_96_RX_REQ_MSN_M,
- V2_QPC_BYTE_96_RX_REQ_MSN_S, 0);
- roce_set_field(qpc_mask->byte_108_rx_reqepsn,
- V2_QPC_BYTE_108_RX_REQ_LAST_OPTYPE_M,
- V2_QPC_BYTE_108_RX_REQ_LAST_OPTYPE_S, 0);
+ hr_reg_write(context, QPC_ACK_REQ_FREQ, lp_pktn_ini);
+ hr_reg_clear(qpc_mask, QPC_ACK_REQ_FREQ);
+
+ hr_reg_clear(qpc_mask, QPC_RX_REQ_PSN_ERR);
+ hr_reg_clear(qpc_mask, QPC_RX_REQ_MSN);
+ hr_reg_clear(qpc_mask, QPC_RX_REQ_LAST_OPTYPE);
context->rq_rnr_timer = 0;
qpc_mask->rq_rnr_timer = 0;
- roce_set_field(qpc_mask->byte_132_trrl, V2_QPC_BYTE_132_TRRL_HEAD_MAX_M,
- V2_QPC_BYTE_132_TRRL_HEAD_MAX_S, 0);
- 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);
+ hr_reg_clear(qpc_mask, QPC_TRRL_HEAD_MAX);
+ hr_reg_clear(qpc_mask, QPC_TRRL_TAIL_MAX);
/* 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);
- roce_set_field(qpc_mask->byte_168_irrl_idx,
- V2_QPC_BYTE_168_LP_SGEN_INI_M,
- V2_QPC_BYTE_168_LP_SGEN_INI_S, 0);
+ hr_reg_write(context, QPC_LP_SGEN_INI, 3);
+ hr_reg_clear(qpc_mask, QPC_LP_SGEN_INI);
return 0;
}
@@ -4654,44 +4470,26 @@ static int modify_qp_rtr_to_rts(struct ib_qp *ibqp,
* of all fields in context are zero, we need not set them to 0 again.
* but we should set the relevant fields of context mask to 0.
*/
- roce_set_field(qpc_mask->byte_232_irrl_sge,
- V2_QPC_BYTE_232_IRRL_SGE_IDX_M,
- V2_QPC_BYTE_232_IRRL_SGE_IDX_S, 0);
+ hr_reg_clear(qpc_mask, QPC_IRRL_SGE_IDX);
- roce_set_field(qpc_mask->byte_240_irrl_tail,
- V2_QPC_BYTE_240_RX_ACK_MSN_M,
- V2_QPC_BYTE_240_RX_ACK_MSN_S, 0);
+ hr_reg_clear(qpc_mask, QPC_RX_ACK_MSN);
- roce_set_field(qpc_mask->byte_248_ack_psn,
- V2_QPC_BYTE_248_ACK_LAST_OPTYPE_M,
- V2_QPC_BYTE_248_ACK_LAST_OPTYPE_S, 0);
- roce_set_bit(qpc_mask->byte_248_ack_psn,
- V2_QPC_BYTE_248_IRRL_PSN_VLD_S, 0);
- roce_set_field(qpc_mask->byte_248_ack_psn,
- V2_QPC_BYTE_248_IRRL_PSN_M,
- V2_QPC_BYTE_248_IRRL_PSN_S, 0);
+ hr_reg_clear(qpc_mask, QPC_ACK_LAST_OPTYPE);
+ hr_reg_clear(qpc_mask, QPC_IRRL_PSN_VLD);
+ hr_reg_clear(qpc_mask, QPC_IRRL_PSN);
- roce_set_field(qpc_mask->byte_240_irrl_tail,
- V2_QPC_BYTE_240_IRRL_TAIL_REAL_M,
- V2_QPC_BYTE_240_IRRL_TAIL_REAL_S, 0);
+ hr_reg_clear(qpc_mask, QPC_IRRL_TAIL_REAL);
- roce_set_field(qpc_mask->byte_220_retry_psn_msn,
- V2_QPC_BYTE_220_RETRY_MSG_MSN_M,
- V2_QPC_BYTE_220_RETRY_MSG_MSN_S, 0);
+ hr_reg_clear(qpc_mask, QPC_RETRY_MSG_MSN);
- roce_set_bit(qpc_mask->byte_248_ack_psn,
- V2_QPC_BYTE_248_RNR_RETRY_FLAG_S, 0);
+ hr_reg_clear(qpc_mask, QPC_RNR_RETRY_FLAG);
- roce_set_field(qpc_mask->byte_212_lsn, V2_QPC_BYTE_212_CHECK_FLG_M,
- V2_QPC_BYTE_212_CHECK_FLG_S, 0);
+ hr_reg_clear(qpc_mask, QPC_CHECK_FLG);
- roce_set_field(context->byte_212_lsn, V2_QPC_BYTE_212_LSN_M,
- V2_QPC_BYTE_212_LSN_S, 0x100);
- roce_set_field(qpc_mask->byte_212_lsn, V2_QPC_BYTE_212_LSN_M,
- V2_QPC_BYTE_212_LSN_S, 0);
+ hr_reg_write(context, QPC_LSN, 0x100);
+ hr_reg_clear(qpc_mask, QPC_LSN);
- roce_set_field(qpc_mask->byte_196_sq_psn, V2_QPC_BYTE_196_IRRL_HEAD_M,
- V2_QPC_BYTE_196_IRRL_HEAD_S, 0);
+ hr_reg_clear(qpc_mask, QPC_V2_IRRL_HEAD);
return 0;
}
@@ -4758,6 +4556,11 @@ enum {
DIP_VALID,
};
+enum {
+ WND_LIMIT,
+ WND_UNLIMIT,
+};
+
static int check_cong_type(struct ib_qp *ibqp,
struct hns_roce_congestion_algorithm *cong_alg)
{
@@ -4769,21 +4572,25 @@ static int check_cong_type(struct ib_qp *ibqp,
cong_alg->alg_sel = CONG_DCQCN;
cong_alg->alg_sub_sel = UNSUPPORT_CONG_LEVEL;
cong_alg->dip_vld = DIP_INVALID;
+ cong_alg->wnd_mode_sel = WND_LIMIT;
break;
case CONG_TYPE_LDCP:
cong_alg->alg_sel = CONG_WINDOW;
cong_alg->alg_sub_sel = CONG_LDCP;
cong_alg->dip_vld = DIP_INVALID;
+ cong_alg->wnd_mode_sel = WND_UNLIMIT;
break;
case CONG_TYPE_HC3:
cong_alg->alg_sel = CONG_WINDOW;
cong_alg->alg_sub_sel = CONG_HC3;
cong_alg->dip_vld = DIP_INVALID;
+ cong_alg->wnd_mode_sel = WND_LIMIT;
break;
case CONG_TYPE_DIP:
cong_alg->alg_sel = CONG_DCQCN;
cong_alg->alg_sub_sel = UNSUPPORT_CONG_LEVEL;
cong_alg->dip_vld = DIP_VALID;
+ cong_alg->wnd_mode_sel = WND_LIMIT;
break;
default:
ibdev_err(&hr_dev->ib_dev,
@@ -4816,14 +4623,17 @@ static int fill_cong_field(struct ib_qp *ibqp, const struct ib_qp_attr *attr,
hr_reg_write(context, QPC_CONG_ALGO_TMPL_ID, hr_dev->cong_algo_tmpl_id +
hr_dev->caps.cong_type * HNS_ROCE_CONG_SIZE);
- hr_reg_write(qpc_mask, QPC_CONG_ALGO_TMPL_ID, 0);
+ hr_reg_clear(qpc_mask, QPC_CONG_ALGO_TMPL_ID);
hr_reg_write(&context->ext, QPCEX_CONG_ALG_SEL, cong_field.alg_sel);
- hr_reg_write(&qpc_mask->ext, QPCEX_CONG_ALG_SEL, 0);
+ hr_reg_clear(&qpc_mask->ext, QPCEX_CONG_ALG_SEL);
hr_reg_write(&context->ext, QPCEX_CONG_ALG_SUB_SEL,
cong_field.alg_sub_sel);
- hr_reg_write(&qpc_mask->ext, QPCEX_CONG_ALG_SUB_SEL, 0);
+ hr_reg_clear(&qpc_mask->ext, QPCEX_CONG_ALG_SUB_SEL);
hr_reg_write(&context->ext, QPCEX_DIP_CTX_IDX_VLD, cong_field.dip_vld);
- hr_reg_write(&qpc_mask->ext, QPCEX_DIP_CTX_IDX_VLD, 0);
+ hr_reg_clear(&qpc_mask->ext, QPCEX_DIP_CTX_IDX_VLD);
+ hr_reg_write(&context->ext, QPCEX_SQ_RQ_NOT_FORBID_EN,
+ cong_field.wnd_mode_sel);
+ hr_reg_clear(&qpc_mask->ext, QPCEX_SQ_RQ_NOT_FORBID_EN);
/* if dip is disabled, there is no need to set dip idx */
if (cong_field.dip_vld == 0)
@@ -4878,20 +4688,14 @@ static int hns_roce_v2_set_path(struct ib_qp *ibqp,
/* Only HIP08 needs to set the vlan_en bits in QPC */
if (vlan_id < VLAN_N_VID &&
hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08) {
- roce_set_bit(context->byte_76_srqn_op_en,
- V2_QPC_BYTE_76_RQ_VLAN_EN_S, 1);
- roce_set_bit(qpc_mask->byte_76_srqn_op_en,
- V2_QPC_BYTE_76_RQ_VLAN_EN_S, 0);
- roce_set_bit(context->byte_168_irrl_idx,
- V2_QPC_BYTE_168_SQ_VLAN_EN_S, 1);
- roce_set_bit(qpc_mask->byte_168_irrl_idx,
- V2_QPC_BYTE_168_SQ_VLAN_EN_S, 0);
+ hr_reg_enable(context, QPC_RQ_VLAN_EN);
+ hr_reg_clear(qpc_mask, QPC_RQ_VLAN_EN);
+ hr_reg_enable(context, QPC_SQ_VLAN_EN);
+ hr_reg_clear(qpc_mask, QPC_SQ_VLAN_EN);
}
- roce_set_field(context->byte_24_mtu_tc, V2_QPC_BYTE_24_VLAN_ID_M,
- V2_QPC_BYTE_24_VLAN_ID_S, vlan_id);
- roce_set_field(qpc_mask->byte_24_mtu_tc, V2_QPC_BYTE_24_VLAN_ID_M,
- V2_QPC_BYTE_24_VLAN_ID_S, 0);
+ hr_reg_write(context, QPC_VLAN_ID, vlan_id);
+ hr_reg_clear(qpc_mask, QPC_VLAN_ID);
if (grh->sgid_index >= hr_dev->caps.gid_table_len[hr_port]) {
ibdev_err(ibdev, "sgid_index(%u) too large. max is %d\n",
@@ -4904,39 +4708,28 @@ static int hns_roce_v2_set_path(struct ib_qp *ibqp,
return -EINVAL;
}
- roce_set_field(context->byte_52_udpspn_dmac, V2_QPC_BYTE_52_UDPSPN_M,
- V2_QPC_BYTE_52_UDPSPN_S,
- is_udp ? get_udp_sport(grh->flow_label, ibqp->qp_num,
- attr->dest_qp_num) : 0);
+ hr_reg_write(context, QPC_UDPSPN,
+ is_udp ? get_udp_sport(grh->flow_label, ibqp->qp_num,
+ attr->dest_qp_num) : 0);
- roce_set_field(qpc_mask->byte_52_udpspn_dmac, V2_QPC_BYTE_52_UDPSPN_M,
- V2_QPC_BYTE_52_UDPSPN_S, 0);
+ hr_reg_clear(qpc_mask, QPC_UDPSPN);
- roce_set_field(context->byte_20_smac_sgid_idx,
- V2_QPC_BYTE_20_SGID_IDX_M, V2_QPC_BYTE_20_SGID_IDX_S,
- grh->sgid_index);
+ hr_reg_write(context, QPC_GMV_IDX, grh->sgid_index);
- 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);
+ hr_reg_clear(qpc_mask, QPC_GMV_IDX);
- roce_set_field(context->byte_24_mtu_tc, V2_QPC_BYTE_24_HOP_LIMIT_M,
- V2_QPC_BYTE_24_HOP_LIMIT_S, grh->hop_limit);
- roce_set_field(qpc_mask->byte_24_mtu_tc, V2_QPC_BYTE_24_HOP_LIMIT_M,
- V2_QPC_BYTE_24_HOP_LIMIT_S, 0);
+ hr_reg_write(context, QPC_HOPLIMIT, grh->hop_limit);
+ hr_reg_clear(qpc_mask, QPC_HOPLIMIT);
ret = fill_cong_field(ibqp, attr, context, qpc_mask);
if (ret)
return ret;
- roce_set_field(context->byte_24_mtu_tc, V2_QPC_BYTE_24_TC_M,
- V2_QPC_BYTE_24_TC_S, get_tclass(&attr->ah_attr.grh));
- roce_set_field(qpc_mask->byte_24_mtu_tc, V2_QPC_BYTE_24_TC_M,
- V2_QPC_BYTE_24_TC_S, 0);
+ hr_reg_write(context, QPC_TC, get_tclass(&attr->ah_attr.grh));
+ hr_reg_clear(qpc_mask, QPC_TC);
- roce_set_field(context->byte_28_at_fl, V2_QPC_BYTE_28_FL_M,
- V2_QPC_BYTE_28_FL_S, grh->flow_label);
- roce_set_field(qpc_mask->byte_28_at_fl, V2_QPC_BYTE_28_FL_M,
- V2_QPC_BYTE_28_FL_S, 0);
+ hr_reg_write(context, QPC_FL, grh->flow_label);
+ hr_reg_clear(qpc_mask, QPC_FL);
memcpy(context->dgid, grh->dgid.raw, sizeof(grh->dgid.raw));
memset(qpc_mask->dgid, 0, sizeof(grh->dgid.raw));
@@ -4948,10 +4741,8 @@ static int hns_roce_v2_set_path(struct ib_qp *ibqp,
return -EINVAL;
}
- roce_set_field(context->byte_28_at_fl, V2_QPC_BYTE_28_SL_M,
- V2_QPC_BYTE_28_SL_S, hr_qp->sl);
- roce_set_field(qpc_mask->byte_28_at_fl, V2_QPC_BYTE_28_SL_M,
- V2_QPC_BYTE_28_SL_S, 0);
+ hr_reg_write(context, QPC_SL, hr_qp->sl);
+ hr_reg_clear(qpc_mask, QPC_SL);
return 0;
}
@@ -5033,12 +4824,8 @@ static int hns_roce_v2_set_opt_fields(struct ib_qp *ibqp,
if (attr_mask & IB_QP_TIMEOUT) {
if (attr->timeout < 31) {
- roce_set_field(context->byte_28_at_fl,
- V2_QPC_BYTE_28_AT_M, V2_QPC_BYTE_28_AT_S,
- attr->timeout);
- roce_set_field(qpc_mask->byte_28_at_fl,
- V2_QPC_BYTE_28_AT_M, V2_QPC_BYTE_28_AT_S,
- 0);
+ hr_reg_write(context, QPC_AT, attr->timeout);
+ hr_reg_clear(qpc_mask, QPC_AT);
} else {
ibdev_warn(&hr_dev->ib_dev,
"Local ACK timeout shall be 0 to 30.\n");
@@ -5046,128 +4833,68 @@ static int hns_roce_v2_set_opt_fields(struct ib_qp *ibqp,
}
if (attr_mask & IB_QP_RETRY_CNT) {
- roce_set_field(context->byte_212_lsn,
- V2_QPC_BYTE_212_RETRY_NUM_INIT_M,
- V2_QPC_BYTE_212_RETRY_NUM_INIT_S,
- attr->retry_cnt);
- roce_set_field(qpc_mask->byte_212_lsn,
- V2_QPC_BYTE_212_RETRY_NUM_INIT_M,
- V2_QPC_BYTE_212_RETRY_NUM_INIT_S, 0);
-
- roce_set_field(context->byte_212_lsn,
- V2_QPC_BYTE_212_RETRY_CNT_M,
- V2_QPC_BYTE_212_RETRY_CNT_S, attr->retry_cnt);
- roce_set_field(qpc_mask->byte_212_lsn,
- V2_QPC_BYTE_212_RETRY_CNT_M,
- V2_QPC_BYTE_212_RETRY_CNT_S, 0);
+ hr_reg_write(context, QPC_RETRY_NUM_INIT, attr->retry_cnt);
+ hr_reg_clear(qpc_mask, QPC_RETRY_NUM_INIT);
+
+ hr_reg_write(context, QPC_RETRY_CNT, attr->retry_cnt);
+ hr_reg_clear(qpc_mask, QPC_RETRY_CNT);
}
if (attr_mask & IB_QP_RNR_RETRY) {
- roce_set_field(context->byte_244_rnr_rxack,
- V2_QPC_BYTE_244_RNR_NUM_INIT_M,
- V2_QPC_BYTE_244_RNR_NUM_INIT_S, attr->rnr_retry);
- roce_set_field(qpc_mask->byte_244_rnr_rxack,
- V2_QPC_BYTE_244_RNR_NUM_INIT_M,
- V2_QPC_BYTE_244_RNR_NUM_INIT_S, 0);
+ hr_reg_write(context, QPC_RNR_NUM_INIT, attr->rnr_retry);
+ hr_reg_clear(qpc_mask, QPC_RNR_NUM_INIT);
- roce_set_field(context->byte_244_rnr_rxack,
- V2_QPC_BYTE_244_RNR_CNT_M,
- V2_QPC_BYTE_244_RNR_CNT_S, attr->rnr_retry);
- roce_set_field(qpc_mask->byte_244_rnr_rxack,
- V2_QPC_BYTE_244_RNR_CNT_M,
- V2_QPC_BYTE_244_RNR_CNT_S, 0);
+ hr_reg_write(context, QPC_RNR_CNT, attr->rnr_retry);
+ hr_reg_clear(qpc_mask, QPC_RNR_CNT);
}
if (attr_mask & IB_QP_SQ_PSN) {
- roce_set_field(context->byte_172_sq_psn,
- V2_QPC_BYTE_172_SQ_CUR_PSN_M,
- V2_QPC_BYTE_172_SQ_CUR_PSN_S, attr->sq_psn);
- roce_set_field(qpc_mask->byte_172_sq_psn,
- V2_QPC_BYTE_172_SQ_CUR_PSN_M,
- V2_QPC_BYTE_172_SQ_CUR_PSN_S, 0);
-
- roce_set_field(context->byte_196_sq_psn,
- V2_QPC_BYTE_196_SQ_MAX_PSN_M,
- V2_QPC_BYTE_196_SQ_MAX_PSN_S, attr->sq_psn);
- roce_set_field(qpc_mask->byte_196_sq_psn,
- V2_QPC_BYTE_196_SQ_MAX_PSN_M,
- V2_QPC_BYTE_196_SQ_MAX_PSN_S, 0);
-
- roce_set_field(context->byte_220_retry_psn_msn,
- V2_QPC_BYTE_220_RETRY_MSG_PSN_M,
- V2_QPC_BYTE_220_RETRY_MSG_PSN_S, attr->sq_psn);
- roce_set_field(qpc_mask->byte_220_retry_psn_msn,
- V2_QPC_BYTE_220_RETRY_MSG_PSN_M,
- V2_QPC_BYTE_220_RETRY_MSG_PSN_S, 0);
-
- 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 >> 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);
-
- roce_set_field(context->byte_224_retry_msg,
- V2_QPC_BYTE_224_RETRY_MSG_FPKT_PSN_M,
- V2_QPC_BYTE_224_RETRY_MSG_FPKT_PSN_S,
- attr->sq_psn);
- roce_set_field(qpc_mask->byte_224_retry_msg,
- V2_QPC_BYTE_224_RETRY_MSG_FPKT_PSN_M,
- V2_QPC_BYTE_224_RETRY_MSG_FPKT_PSN_S, 0);
-
- roce_set_field(context->byte_244_rnr_rxack,
- V2_QPC_BYTE_244_RX_ACK_EPSN_M,
- V2_QPC_BYTE_244_RX_ACK_EPSN_S, attr->sq_psn);
- roce_set_field(qpc_mask->byte_244_rnr_rxack,
- V2_QPC_BYTE_244_RX_ACK_EPSN_M,
- V2_QPC_BYTE_244_RX_ACK_EPSN_S, 0);
+ hr_reg_write(context, QPC_SQ_CUR_PSN, attr->sq_psn);
+ hr_reg_clear(qpc_mask, QPC_SQ_CUR_PSN);
+
+ hr_reg_write(context, QPC_SQ_MAX_PSN, attr->sq_psn);
+ hr_reg_clear(qpc_mask, QPC_SQ_MAX_PSN);
+
+ hr_reg_write(context, QPC_RETRY_MSG_PSN_L, attr->sq_psn);
+ hr_reg_clear(qpc_mask, QPC_RETRY_MSG_PSN_L);
+
+ hr_reg_write(context, QPC_RETRY_MSG_PSN_H,
+ attr->sq_psn >> RETRY_MSG_PSN_SHIFT);
+ hr_reg_clear(qpc_mask, QPC_RETRY_MSG_PSN_H);
+
+ hr_reg_write(context, QPC_RETRY_MSG_FPKT_PSN, attr->sq_psn);
+ hr_reg_clear(qpc_mask, QPC_RETRY_MSG_FPKT_PSN);
+
+ hr_reg_write(context, QPC_RX_ACK_EPSN, attr->sq_psn);
+ hr_reg_clear(qpc_mask, QPC_RX_ACK_EPSN);
}
if ((attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) &&
attr->max_dest_rd_atomic) {
- roce_set_field(context->byte_140_raq, V2_QPC_BYTE_140_RR_MAX_M,
- V2_QPC_BYTE_140_RR_MAX_S,
- fls(attr->max_dest_rd_atomic - 1));
- roce_set_field(qpc_mask->byte_140_raq, V2_QPC_BYTE_140_RR_MAX_M,
- V2_QPC_BYTE_140_RR_MAX_S, 0);
+ hr_reg_write(context, QPC_RR_MAX,
+ fls(attr->max_dest_rd_atomic - 1));
+ hr_reg_clear(qpc_mask, QPC_RR_MAX);
}
if ((attr_mask & IB_QP_MAX_QP_RD_ATOMIC) && attr->max_rd_atomic) {
- roce_set_field(context->byte_208_irrl, V2_QPC_BYTE_208_SR_MAX_M,
- V2_QPC_BYTE_208_SR_MAX_S,
- fls(attr->max_rd_atomic - 1));
- roce_set_field(qpc_mask->byte_208_irrl,
- V2_QPC_BYTE_208_SR_MAX_M,
- V2_QPC_BYTE_208_SR_MAX_S, 0);
+ hr_reg_write(context, QPC_SR_MAX, fls(attr->max_rd_atomic - 1));
+ hr_reg_clear(qpc_mask, QPC_SR_MAX);
}
if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC))
set_access_flags(hr_qp, context, qpc_mask, attr, attr_mask);
if (attr_mask & IB_QP_MIN_RNR_TIMER) {
- roce_set_field(context->byte_80_rnr_rx_cqn,
- V2_QPC_BYTE_80_MIN_RNR_TIME_M,
- V2_QPC_BYTE_80_MIN_RNR_TIME_S,
- attr->min_rnr_timer);
- roce_set_field(qpc_mask->byte_80_rnr_rx_cqn,
- V2_QPC_BYTE_80_MIN_RNR_TIME_M,
- V2_QPC_BYTE_80_MIN_RNR_TIME_S, 0);
+ hr_reg_write(context, QPC_MIN_RNR_TIME, attr->min_rnr_timer);
+ hr_reg_clear(qpc_mask, QPC_MIN_RNR_TIME);
}
if (attr_mask & IB_QP_RQ_PSN) {
- roce_set_field(context->byte_108_rx_reqepsn,
- V2_QPC_BYTE_108_RX_REQ_EPSN_M,
- V2_QPC_BYTE_108_RX_REQ_EPSN_S, attr->rq_psn);
- roce_set_field(qpc_mask->byte_108_rx_reqepsn,
- V2_QPC_BYTE_108_RX_REQ_EPSN_M,
- V2_QPC_BYTE_108_RX_REQ_EPSN_S, 0);
+ hr_reg_write(context, QPC_RX_REQ_EPSN, attr->rq_psn);
+ hr_reg_clear(qpc_mask, QPC_RX_REQ_EPSN);
- roce_set_field(context->byte_152_raq, V2_QPC_BYTE_152_RAQ_PSN_M,
- V2_QPC_BYTE_152_RAQ_PSN_S, attr->rq_psn - 1);
- roce_set_field(qpc_mask->byte_152_raq,
- V2_QPC_BYTE_152_RAQ_PSN_M,
- V2_QPC_BYTE_152_RAQ_PSN_S, 0);
+ hr_reg_write(context, QPC_RAQ_PSN, attr->rq_psn - 1);
+ hr_reg_clear(qpc_mask, QPC_RAQ_PSN);
}
if (attr_mask & IB_QP_QKEY) {
@@ -5220,6 +4947,32 @@ static void clear_qp(struct hns_roce_qp *hr_qp)
hr_qp->next_sge = 0;
}
+static void v2_set_flushed_fields(struct ib_qp *ibqp,
+ struct hns_roce_v2_qp_context *context,
+ struct hns_roce_v2_qp_context *qpc_mask)
+{
+ struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
+ unsigned long sq_flag = 0;
+ unsigned long rq_flag = 0;
+
+ if (ibqp->qp_type == IB_QPT_XRC_TGT)
+ return;
+
+ spin_lock_irqsave(&hr_qp->sq.lock, sq_flag);
+ hr_reg_write(context, QPC_SQ_PRODUCER_IDX, hr_qp->sq.head);
+ hr_reg_clear(qpc_mask, QPC_SQ_PRODUCER_IDX);
+ hr_qp->state = IB_QPS_ERR;
+ spin_unlock_irqrestore(&hr_qp->sq.lock, sq_flag);
+
+ if (ibqp->srq || ibqp->qp_type == IB_QPT_XRC_INI) /* no RQ */
+ return;
+
+ spin_lock_irqsave(&hr_qp->rq.lock, rq_flag);
+ hr_reg_write(context, QPC_RQ_PRODUCER_IDX, hr_qp->rq.head);
+ hr_reg_clear(qpc_mask, QPC_RQ_PRODUCER_IDX);
+ spin_unlock_irqrestore(&hr_qp->rq.lock, rq_flag);
+}
+
static int hns_roce_v2_modify_qp(struct ib_qp *ibqp,
const struct ib_qp_attr *attr,
int attr_mask, enum ib_qp_state cur_state,
@@ -5231,8 +4984,6 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp,
struct hns_roce_v2_qp_context *context = ctx;
struct hns_roce_v2_qp_context *qpc_mask = ctx + 1;
struct ib_device *ibdev = &hr_dev->ib_dev;
- unsigned long sq_flag = 0;
- unsigned long rq_flag = 0;
int ret;
if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
@@ -5253,34 +5004,8 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp,
goto out;
/* When QP state is err, SQ and RQ WQE should be flushed */
- if (new_state == IB_QPS_ERR) {
- if (ibqp->qp_type != IB_QPT_XRC_TGT) {
- spin_lock_irqsave(&hr_qp->sq.lock, sq_flag);
- hr_qp->state = IB_QPS_ERR;
- roce_set_field(context->byte_160_sq_ci_pi,
- V2_QPC_BYTE_160_SQ_PRODUCER_IDX_M,
- V2_QPC_BYTE_160_SQ_PRODUCER_IDX_S,
- hr_qp->sq.head);
- roce_set_field(qpc_mask->byte_160_sq_ci_pi,
- V2_QPC_BYTE_160_SQ_PRODUCER_IDX_M,
- V2_QPC_BYTE_160_SQ_PRODUCER_IDX_S, 0);
- spin_unlock_irqrestore(&hr_qp->sq.lock, sq_flag);
- }
-
- if (!ibqp->srq && ibqp->qp_type != IB_QPT_XRC_INI &&
- ibqp->qp_type != IB_QPT_XRC_TGT) {
- spin_lock_irqsave(&hr_qp->rq.lock, rq_flag);
- hr_qp->state = IB_QPS_ERR;
- roce_set_field(context->byte_84_rq_ci_pi,
- V2_QPC_BYTE_84_RQ_PRODUCER_IDX_M,
- V2_QPC_BYTE_84_RQ_PRODUCER_IDX_S,
- hr_qp->rq.head);
- roce_set_field(qpc_mask->byte_84_rq_ci_pi,
- V2_QPC_BYTE_84_RQ_PRODUCER_IDX_M,
- V2_QPC_BYTE_84_RQ_PRODUCER_IDX_S, 0);
- spin_unlock_irqrestore(&hr_qp->rq.lock, rq_flag);
- }
- }
+ if (new_state == IB_QPS_ERR)
+ v2_set_flushed_fields(ibqp, context, qpc_mask);
/* Configure the optional fields */
ret = hns_roce_v2_set_opt_fields(ibqp, attr, attr_mask, context,
@@ -5288,17 +5013,14 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp,
if (ret)
goto out;
- roce_set_bit(context->byte_108_rx_reqepsn, V2_QPC_BYTE_108_INV_CREDIT_S,
- ((to_hr_qp_type(hr_qp->ibqp.qp_type) == SERV_TYPE_XRC) ||
- ibqp->srq) ? 1 : 0);
- roce_set_bit(qpc_mask->byte_108_rx_reqepsn,
- V2_QPC_BYTE_108_INV_CREDIT_S, 0);
+ hr_reg_write_bool(context, QPC_INV_CREDIT,
+ to_hr_qp_type(hr_qp->ibqp.qp_type) == SERV_TYPE_XRC ||
+ ibqp->srq);
+ hr_reg_clear(qpc_mask, QPC_INV_CREDIT);
/* Every status migrate must change state */
- roce_set_field(context->byte_60_qpst_tempid, V2_QPC_BYTE_60_QP_ST_M,
- V2_QPC_BYTE_60_QP_ST_S, new_state);
- roce_set_field(qpc_mask->byte_60_qpst_tempid, V2_QPC_BYTE_60_QP_ST_M,
- V2_QPC_BYTE_60_QP_ST_S, 0);
+ hr_reg_write(context, QPC_QP_ST, new_state);
+ hr_reg_clear(qpc_mask, QPC_QP_ST);
/* SW pass context to HW */
ret = hns_roce_v2_qp_modify(hr_dev, context, qpc_mask, hr_qp);
@@ -5388,8 +5110,7 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
goto out;
}
- state = roce_get_field(context.byte_60_qpst_tempid,
- V2_QPC_BYTE_60_QP_ST_M, V2_QPC_BYTE_60_QP_ST_S);
+ state = hr_reg_read(&context, QPC_QP_ST);
tmp_qp_state = to_ib_qp_st((enum hns_roce_v2_qp_state)state);
if (tmp_qp_state == -1) {
ibdev_err(ibdev, "Illegal ib_qp_state\n");
@@ -5398,77 +5119,45 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
}
hr_qp->state = (u8)tmp_qp_state;
qp_attr->qp_state = (enum ib_qp_state)hr_qp->state;
- qp_attr->path_mtu = (enum ib_mtu)roce_get_field(context.byte_24_mtu_tc,
- V2_QPC_BYTE_24_MTU_M,
- V2_QPC_BYTE_24_MTU_S);
+ qp_attr->path_mtu = (enum ib_mtu)hr_reg_read(&context, QPC_MTU);
qp_attr->path_mig_state = IB_MIG_ARMED;
- qp_attr->ah_attr.type = RDMA_AH_ATTR_TYPE_ROCE;
+ qp_attr->ah_attr.type = RDMA_AH_ATTR_TYPE_ROCE;
if (hr_qp->ibqp.qp_type == IB_QPT_UD)
qp_attr->qkey = le32_to_cpu(context.qkey_xrcd);
- qp_attr->rq_psn = roce_get_field(context.byte_108_rx_reqepsn,
- V2_QPC_BYTE_108_RX_REQ_EPSN_M,
- V2_QPC_BYTE_108_RX_REQ_EPSN_S);
- qp_attr->sq_psn = (u32)roce_get_field(context.byte_172_sq_psn,
- V2_QPC_BYTE_172_SQ_CUR_PSN_M,
- V2_QPC_BYTE_172_SQ_CUR_PSN_S);
- qp_attr->dest_qp_num = (u8)roce_get_field(context.byte_56_dqpn_err,
- 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)) << V2_QP_RRE_S) |
- ((roce_get_bit(context.byte_76_srqn_op_en,
- V2_QPC_BYTE_76_RWE_S)) << V2_QP_RWE_S) |
- ((roce_get_bit(context.byte_76_srqn_op_en,
- V2_QPC_BYTE_76_ATE_S)) << V2_QP_ATE_S);
+ qp_attr->rq_psn = hr_reg_read(&context, QPC_RX_REQ_EPSN);
+ qp_attr->sq_psn = (u32)hr_reg_read(&context, QPC_SQ_CUR_PSN);
+ qp_attr->dest_qp_num = (u8)hr_reg_read(&context, QPC_DQPN);
+ qp_attr->qp_access_flags =
+ ((hr_reg_read(&context, QPC_RRE)) << V2_QP_RRE_S) |
+ ((hr_reg_read(&context, QPC_RWE)) << V2_QP_RWE_S) |
+ ((hr_reg_read(&context, QPC_ATE)) << V2_QP_ATE_S);
if (hr_qp->ibqp.qp_type == IB_QPT_RC ||
hr_qp->ibqp.qp_type == IB_QPT_XRC_INI ||
hr_qp->ibqp.qp_type == IB_QPT_XRC_TGT) {
struct ib_global_route *grh =
- rdma_ah_retrieve_grh(&qp_attr->ah_attr);
+ rdma_ah_retrieve_grh(&qp_attr->ah_attr);
rdma_ah_set_sl(&qp_attr->ah_attr,
- roce_get_field(context.byte_28_at_fl,
- V2_QPC_BYTE_28_SL_M,
- V2_QPC_BYTE_28_SL_S));
- grh->flow_label = roce_get_field(context.byte_28_at_fl,
- V2_QPC_BYTE_28_FL_M,
- V2_QPC_BYTE_28_FL_S);
- grh->sgid_index = roce_get_field(context.byte_20_smac_sgid_idx,
- V2_QPC_BYTE_20_SGID_IDX_M,
- V2_QPC_BYTE_20_SGID_IDX_S);
- grh->hop_limit = roce_get_field(context.byte_24_mtu_tc,
- V2_QPC_BYTE_24_HOP_LIMIT_M,
- V2_QPC_BYTE_24_HOP_LIMIT_S);
- grh->traffic_class = roce_get_field(context.byte_24_mtu_tc,
- V2_QPC_BYTE_24_TC_M,
- V2_QPC_BYTE_24_TC_S);
+ hr_reg_read(&context, QPC_SL));
+ grh->flow_label = hr_reg_read(&context, QPC_FL);
+ grh->sgid_index = hr_reg_read(&context, QPC_GMV_IDX);
+ grh->hop_limit = hr_reg_read(&context, QPC_HOPLIMIT);
+ grh->traffic_class = hr_reg_read(&context, QPC_TC);
memcpy(grh->dgid.raw, context.dgid, sizeof(grh->dgid.raw));
}
qp_attr->port_num = hr_qp->port + 1;
qp_attr->sq_draining = 0;
- qp_attr->max_rd_atomic = 1 << roce_get_field(context.byte_208_irrl,
- V2_QPC_BYTE_208_SR_MAX_M,
- V2_QPC_BYTE_208_SR_MAX_S);
- qp_attr->max_dest_rd_atomic = 1 << roce_get_field(context.byte_140_raq,
- V2_QPC_BYTE_140_RR_MAX_M,
- V2_QPC_BYTE_140_RR_MAX_S);
-
- qp_attr->min_rnr_timer = (u8)roce_get_field(context.byte_80_rnr_rx_cqn,
- V2_QPC_BYTE_80_MIN_RNR_TIME_M,
- V2_QPC_BYTE_80_MIN_RNR_TIME_S);
- qp_attr->timeout = (u8)roce_get_field(context.byte_28_at_fl,
- V2_QPC_BYTE_28_AT_M,
- V2_QPC_BYTE_28_AT_S);
- qp_attr->retry_cnt = roce_get_field(context.byte_212_lsn,
- V2_QPC_BYTE_212_RETRY_NUM_INIT_M,
- V2_QPC_BYTE_212_RETRY_NUM_INIT_S);
- qp_attr->rnr_retry = roce_get_field(context.byte_244_rnr_rxack,
- V2_QPC_BYTE_244_RNR_NUM_INIT_M,
- V2_QPC_BYTE_244_RNR_NUM_INIT_S);
+ qp_attr->max_rd_atomic = 1 << hr_reg_read(&context, QPC_SR_MAX);
+ qp_attr->max_dest_rd_atomic = 1 << hr_reg_read(&context, QPC_RR_MAX);
+
+ qp_attr->min_rnr_timer = (u8)hr_reg_read(&context, QPC_MIN_RNR_TIME);
+ qp_attr->timeout = (u8)hr_reg_read(&context, QPC_AT);
+ qp_attr->retry_cnt = hr_reg_read(&context, QPC_RETRY_NUM_INIT);
+ qp_attr->rnr_retry = hr_reg_read(&context, QPC_RNR_NUM_INIT);
done:
qp_attr->cur_qp_state = qp_attr->qp_state;
@@ -5476,14 +5165,14 @@ done:
qp_attr->cap.max_recv_sge = hr_qp->rq.max_gs - hr_qp->rq.rsv_sge;
qp_attr->cap.max_inline_data = hr_qp->max_inline_data;
- if (!ibqp->uobject) {
- qp_attr->cap.max_send_wr = hr_qp->sq.wqe_cnt;
- qp_attr->cap.max_send_sge = hr_qp->sq.max_gs;
- } else {
- qp_attr->cap.max_send_wr = 0;
- qp_attr->cap.max_send_sge = 0;
- }
+ qp_attr->cap.max_send_wr = hr_qp->sq.wqe_cnt;
+ qp_attr->cap.max_send_sge = hr_qp->sq.max_gs;
+ qp_init_attr->qp_context = ibqp->qp_context;
+ qp_init_attr->qp_type = ibqp->qp_type;
+ qp_init_attr->recv_cq = ibqp->recv_cq;
+ qp_init_attr->send_cq = ibqp->send_cq;
+ qp_init_attr->srq = ibqp->srq;
qp_init_attr->cap = qp_attr->cap;
qp_init_attr->sq_sig_type = hr_qp->sq_signal_bits;
@@ -5689,8 +5378,8 @@ static int hns_roce_v2_write_srqc(struct hns_roce_srq *srq, void *mb_buf)
}
hr_reg_write(ctx, SRQC_SRQ_ST, 1);
- hr_reg_write(ctx, SRQC_SRQ_TYPE,
- !!(srq->ibsrq.srq_type == IB_SRQT_XRC));
+ hr_reg_write_bool(ctx, SRQC_SRQ_TYPE,
+ srq->ibsrq.srq_type == IB_SRQT_XRC);
hr_reg_write(ctx, SRQC_PD, to_hr_pd(srq->ibsrq.pd)->pdn);
hr_reg_write(ctx, SRQC_SRQN, srq->srqn);
hr_reg_write(ctx, SRQC_XRCD, srq->xrcdn);
@@ -5744,12 +5433,8 @@ static int hns_roce_v2_modify_srq(struct ib_srq *ibsrq,
memset(srqc_mask, 0xff, sizeof(*srqc_mask));
- roce_set_field(srq_context->byte_8_limit_wl,
- SRQC_BYTE_8_SRQ_LIMIT_WL_M,
- SRQC_BYTE_8_SRQ_LIMIT_WL_S, srq_attr->srq_limit);
- roce_set_field(srqc_mask->byte_8_limit_wl,
- SRQC_BYTE_8_SRQ_LIMIT_WL_M,
- SRQC_BYTE_8_SRQ_LIMIT_WL_S, 0);
+ hr_reg_write(srq_context, SRQC_LIMIT_WL, srq_attr->srq_limit);
+ hr_reg_clear(srqc_mask, SRQC_LIMIT_WL);
ret = hns_roce_cmd_mbox(hr_dev, mailbox->dma, 0, srq->srqn, 0,
HNS_ROCE_CMD_MODIFY_SRQC,
@@ -5772,7 +5457,6 @@ static int hns_roce_v2_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr)
struct hns_roce_srq *srq = to_hr_srq(ibsrq);
struct hns_roce_srq_context *srq_context;
struct hns_roce_cmd_mailbox *mailbox;
- int limit_wl;
int ret;
mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
@@ -5790,11 +5474,7 @@ static int hns_roce_v2_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr)
goto out;
}
- limit_wl = roce_get_field(srq_context->byte_8_limit_wl,
- SRQC_BYTE_8_SRQ_LIMIT_WL_M,
- SRQC_BYTE_8_SRQ_LIMIT_WL_S);
-
- attr->srq_limit = limit_wl;
+ attr->srq_limit = hr_reg_read(srq_context, SRQC_LIMIT_WL);
attr->max_wr = srq->wqe_cnt;
attr->max_sge = srq->max_gs - srq->rsv_sge;
@@ -5821,18 +5501,10 @@ static int hns_roce_v2_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period)
memset(cqc_mask, 0xff, sizeof(*cqc_mask));
- roce_set_field(cq_context->byte_56_cqe_period_maxcnt,
- V2_CQC_BYTE_56_CQ_MAX_CNT_M, V2_CQC_BYTE_56_CQ_MAX_CNT_S,
- cq_count);
- roce_set_field(cqc_mask->byte_56_cqe_period_maxcnt,
- V2_CQC_BYTE_56_CQ_MAX_CNT_M, V2_CQC_BYTE_56_CQ_MAX_CNT_S,
- 0);
- roce_set_field(cq_context->byte_56_cqe_period_maxcnt,
- V2_CQC_BYTE_56_CQ_PERIOD_M, V2_CQC_BYTE_56_CQ_PERIOD_S,
- cq_period);
- roce_set_field(cqc_mask->byte_56_cqe_period_maxcnt,
- V2_CQC_BYTE_56_CQ_PERIOD_M, V2_CQC_BYTE_56_CQ_PERIOD_S,
- 0);
+ hr_reg_write(cq_context, CQC_CQ_MAX_CNT, cq_count);
+ hr_reg_clear(cqc_mask, CQC_CQ_MAX_CNT);
+ hr_reg_write(cq_context, CQC_CQ_PERIOD, cq_period);
+ hr_reg_clear(cqc_mask, CQC_CQ_PERIOD);
ret = hns_roce_cmd_mbox(hr_dev, mailbox->dma, 0, hr_cq->cqn, 1,
HNS_ROCE_CMD_MODIFY_CQC,
@@ -5933,22 +5605,20 @@ static void update_eq_db(struct hns_roce_eq *eq)
struct hns_roce_v2_db eq_db = {};
if (eq->type_flag == HNS_ROCE_AEQ) {
- roce_set_field(eq_db.byte_4, V2_EQ_DB_CMD_M, V2_EQ_DB_CMD_S,
- eq->arm_st == HNS_ROCE_V2_EQ_ALWAYS_ARMED ?
- HNS_ROCE_EQ_DB_CMD_AEQ :
- HNS_ROCE_EQ_DB_CMD_AEQ_ARMED);
+ hr_reg_write(&eq_db, EQ_DB_CMD,
+ eq->arm_st == HNS_ROCE_V2_EQ_ALWAYS_ARMED ?
+ HNS_ROCE_EQ_DB_CMD_AEQ :
+ HNS_ROCE_EQ_DB_CMD_AEQ_ARMED);
} else {
- roce_set_field(eq_db.byte_4, V2_EQ_DB_TAG_M, V2_EQ_DB_TAG_S,
- eq->eqn);
+ hr_reg_write(&eq_db, EQ_DB_TAG, eq->eqn);
- roce_set_field(eq_db.byte_4, V2_EQ_DB_CMD_M, V2_EQ_DB_CMD_S,
- eq->arm_st == HNS_ROCE_V2_EQ_ALWAYS_ARMED ?
- HNS_ROCE_EQ_DB_CMD_CEQ :
- HNS_ROCE_EQ_DB_CMD_CEQ_ARMED);
+ hr_reg_write(&eq_db, EQ_DB_CMD,
+ eq->arm_st == HNS_ROCE_V2_EQ_ALWAYS_ARMED ?
+ HNS_ROCE_EQ_DB_CMD_CEQ :
+ HNS_ROCE_EQ_DB_CMD_CEQ_ARMED);
}
- roce_set_field(eq_db.parameter, V2_EQ_DB_CONS_IDX_M,
- V2_EQ_DB_CONS_IDX_S, eq->cons_index);
+ hr_reg_write(&eq_db, EQ_DB_CI, eq->cons_index);
hns_roce_write64(hr_dev, (__le32 *)&eq_db, eq->db_reg);
}
@@ -6240,8 +5910,7 @@ static int config_eqc(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq,
hr_reg_write(eqc, EQC_EQ_CONS_INDX, HNS_ROCE_EQ_INIT_CONS_IDX);
hr_reg_write(eqc, EQC_NEX_EQE_BA_L, eqe_ba[1] >> 12);
hr_reg_write(eqc, EQC_NEX_EQE_BA_H, eqe_ba[1] >> 44);
- hr_reg_write(eqc, EQC_EQE_SIZE,
- !!(eq->eqe_size == HNS_ROCE_V3_EQE_SIZE));
+ hr_reg_write(eqc, EQC_EQE_SIZE, eq->eqe_size == HNS_ROCE_V3_EQE_SIZE);
return 0;
}
@@ -6256,14 +5925,14 @@ static int alloc_eq_buf(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq)
else
eq->hop_num = hr_dev->caps.eqe_hop_num;
- buf_attr.page_shift = hr_dev->caps.eqe_buf_pg_sz + HNS_HW_PAGE_SHIFT;
+ buf_attr.page_shift = hr_dev->caps.eqe_buf_pg_sz + PAGE_SHIFT;
buf_attr.region[0].size = eq->entries * eq->eqe_size;
buf_attr.region[0].hopnum = eq->hop_num;
buf_attr.region_count = 1;
err = hns_roce_mtr_create(hr_dev, &eq->mtr, &buf_attr,
- hr_dev->caps.eqe_ba_pg_sz +
- HNS_HW_PAGE_SHIFT, NULL, 0);
+ hr_dev->caps.eqe_ba_pg_sz + PAGE_SHIFT, NULL,
+ 0);
if (err)
dev_err(hr_dev->dev, "Failed to alloc EQE mtr, err %d\n", err);
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
index a2100a629859..b8a09d411e2e 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
@@ -59,7 +59,7 @@
#define HNS_ROCE_V2_MAX_SQ_SGE_NUM 64
#define HNS_ROCE_V2_MAX_EXTEND_SGE_NUM 0x200000
#define HNS_ROCE_V2_MAX_SQ_INLINE 0x20
-#define HNS_ROCE_V2_MAX_SQ_INL_EXT 0x400
+#define HNS_ROCE_V3_MAX_SQ_INLINE 0x400
#define HNS_ROCE_V2_MAX_RC_INL_INN_SZ 32
#define HNS_ROCE_V2_UAR_NUM 256
#define HNS_ROCE_V2_PHY_UAR_NUM 1
@@ -93,6 +93,9 @@
#define HNS_ROCE_V3_SCCC_SZ 64
#define HNS_ROCE_V3_GMV_ENTRY_SZ 32
+#define HNS_ROCE_V2_EXT_LLM_ENTRY_SZ 8
+#define HNS_ROCE_V2_EXT_LLM_MAX_DEPTH 4096
+
#define HNS_ROCE_V2_QPC_TIMER_ENTRY_SZ PAGE_SIZE
#define HNS_ROCE_V2_CQC_TIMER_ENTRY_SZ PAGE_SIZE
#define HNS_ROCE_V2_PAGE_SIZE_SUPPORTED 0xFFFFF000
@@ -162,6 +165,11 @@ enum {
REG_NXT_SE_CEQE = 0x3
};
+enum {
+ CQE_SIZE_32B = 0x0,
+ CQE_SIZE_64B = 0x1
+};
+
#define V2_CQ_DB_REQ_NOT_SOL 0
#define V2_CQ_DB_REQ_NOT 1
@@ -170,8 +178,6 @@ enum {
#define GID_LEN_V2 16
-#define HNS_ROCE_V2_CQE_QPN_MASK 0xfffff
-
enum {
HNS_ROCE_V2_WQE_OP_SEND = 0x0,
HNS_ROCE_V2_WQE_OP_SEND_WITH_INV = 0x1,
@@ -234,7 +240,6 @@ enum hns_roce_opcode_type {
HNS_ROCE_OPC_QUERY_PF_RES = 0x8400,
HNS_ROCE_OPC_ALLOC_VF_RES = 0x8401,
HNS_ROCE_OPC_CFG_EXT_LLM = 0x8403,
- HNS_ROCE_OPC_CFG_TMOUT_LLM = 0x8404,
HNS_ROCE_OPC_QUERY_PF_TIMER_RES = 0x8406,
HNS_ROCE_OPC_QUERY_FUNC_INFO = 0x8407,
HNS_ROCE_OPC_QUERY_PF_CAPS_NUM = 0x8408,
@@ -248,9 +253,11 @@ enum hns_roce_opcode_type {
HNS_ROCE_OPC_CLR_SCCC = 0x8509,
HNS_ROCE_OPC_QUERY_SCCC = 0x850a,
HNS_ROCE_OPC_RESET_SCCC = 0x850b,
+ HNS_ROCE_OPC_CLEAR_EXTDB_LIST_INFO = 0x850d,
HNS_ROCE_OPC_QUERY_VF_RES = 0x850e,
HNS_ROCE_OPC_CFG_GMV_TBL = 0x850f,
HNS_ROCE_OPC_CFG_GMV_BT = 0x8510,
+ HNS_ROCE_OPC_EXT_CFG = 0x8512,
HNS_SWITCH_PARAMETER_CFG = 0x1033,
};
@@ -304,67 +311,24 @@ struct hns_roce_v2_cq_context {
#define HNS_ROCE_V2_CQ_DEFAULT_BURST_NUM 0x0
#define HNS_ROCE_V2_CQ_DEFAULT_INTERVAL 0x0
-#define V2_CQC_BYTE_4_CQ_ST_S 0
-#define V2_CQC_BYTE_4_CQ_ST_M GENMASK(1, 0)
-
-#define V2_CQC_BYTE_4_POLL_S 2
-
-#define V2_CQC_BYTE_4_SE_S 3
-
-#define V2_CQC_BYTE_4_OVER_IGNORE_S 4
-
-#define V2_CQC_BYTE_4_COALESCE_S 5
-
#define V2_CQC_BYTE_4_ARM_ST_S 6
#define V2_CQC_BYTE_4_ARM_ST_M GENMASK(7, 6)
-#define V2_CQC_BYTE_4_SHIFT_S 8
-#define V2_CQC_BYTE_4_SHIFT_M GENMASK(12, 8)
-
-#define V2_CQC_BYTE_4_CMD_SN_S 13
-#define V2_CQC_BYTE_4_CMD_SN_M GENMASK(14, 13)
-
#define V2_CQC_BYTE_4_CEQN_S 15
#define V2_CQC_BYTE_4_CEQN_M GENMASK(23, 15)
-#define V2_CQC_BYTE_4_PAGE_OFFSET_S 24
-#define V2_CQC_BYTE_4_PAGE_OFFSET_M GENMASK(31, 24)
-
#define V2_CQC_BYTE_8_CQN_S 0
#define V2_CQC_BYTE_8_CQN_M GENMASK(23, 0)
-#define V2_CQC_BYTE_8_CQE_SIZE_S 27
-#define V2_CQC_BYTE_8_CQE_SIZE_M GENMASK(28, 27)
-
-#define V2_CQC_BYTE_16_CQE_CUR_BLK_ADDR_S 0
-#define V2_CQC_BYTE_16_CQE_CUR_BLK_ADDR_M GENMASK(19, 0)
-
#define V2_CQC_BYTE_16_CQE_HOP_NUM_S 30
#define V2_CQC_BYTE_16_CQE_HOP_NUM_M GENMASK(31, 30)
-#define V2_CQC_BYTE_24_CQE_NXT_BLK_ADDR_S 0
-#define V2_CQC_BYTE_24_CQE_NXT_BLK_ADDR_M GENMASK(19, 0)
-
-#define V2_CQC_BYTE_24_CQE_BA_PG_SZ_S 24
-#define V2_CQC_BYTE_24_CQE_BA_PG_SZ_M GENMASK(27, 24)
-
-#define V2_CQC_BYTE_24_CQE_BUF_PG_SZ_S 28
-#define V2_CQC_BYTE_24_CQE_BUF_PG_SZ_M GENMASK(31, 28)
-
#define V2_CQC_BYTE_28_CQ_PRODUCER_IDX_S 0
#define V2_CQC_BYTE_28_CQ_PRODUCER_IDX_M GENMASK(23, 0)
#define V2_CQC_BYTE_32_CQ_CONSUMER_IDX_S 0
#define V2_CQC_BYTE_32_CQ_CONSUMER_IDX_M GENMASK(23, 0)
-#define V2_CQC_BYTE_40_CQE_BA_S 0
-#define V2_CQC_BYTE_40_CQE_BA_M GENMASK(28, 0)
-
-#define V2_CQC_BYTE_44_DB_RECORD_EN_S 0
-
-#define V2_CQC_BYTE_44_DB_RECORD_ADDR_S 1
-#define V2_CQC_BYTE_44_DB_RECORD_ADDR_M GENMASK(31, 1)
-
#define V2_CQC_BYTE_52_CQE_CNT_S 0
#define V2_CQC_BYTE_52_CQE_CNT_M GENMASK(23, 0)
@@ -374,30 +338,48 @@ struct hns_roce_v2_cq_context {
#define V2_CQC_BYTE_56_CQ_PERIOD_S 16
#define V2_CQC_BYTE_56_CQ_PERIOD_M GENMASK(31, 16)
-#define V2_CQC_BYTE_64_SE_CQE_IDX_S 0
-#define V2_CQC_BYTE_64_SE_CQE_IDX_M GENMASK(23, 0)
-
#define CQC_FIELD_LOC(h, l) FIELD_LOC(struct hns_roce_v2_cq_context, h, l)
+#define CQC_CQ_ST CQC_FIELD_LOC(1, 0)
+#define CQC_POLL CQC_FIELD_LOC(2, 2)
+#define CQC_SE CQC_FIELD_LOC(3, 3)
+#define CQC_OVER_IGNORE CQC_FIELD_LOC(4, 4)
+#define CQC_ARM_ST CQC_FIELD_LOC(7, 6)
+#define CQC_SHIFT CQC_FIELD_LOC(12, 8)
+#define CQC_CMD_SN CQC_FIELD_LOC(14, 13)
+#define CQC_CEQN CQC_FIELD_LOC(23, 15)
+#define CQC_CQN CQC_FIELD_LOC(55, 32)
+#define CQC_POE_EN CQC_FIELD_LOC(56, 56)
+#define CQC_POE_NUM CQC_FIELD_LOC(58, 57)
+#define CQC_CQE_SIZE CQC_FIELD_LOC(60, 59)
+#define CQC_CQ_CNT_MODE CQC_FIELD_LOC(61, 61)
#define CQC_STASH CQC_FIELD_LOC(63, 63)
+#define CQC_CQE_CUR_BLK_ADDR_L CQC_FIELD_LOC(95, 64)
+#define CQC_CQE_CUR_BLK_ADDR_H CQC_FIELD_LOC(115, 96)
+#define CQC_POE_QID CQC_FIELD_LOC(125, 116)
+#define CQC_CQE_HOP_NUM CQC_FIELD_LOC(127, 126)
+#define CQC_CQE_NEX_BLK_ADDR_L CQC_FIELD_LOC(159, 128)
+#define CQC_CQE_NEX_BLK_ADDR_H CQC_FIELD_LOC(179, 160)
+#define CQC_CQE_BAR_PG_SZ CQC_FIELD_LOC(187, 184)
+#define CQC_CQE_BUF_PG_SZ CQC_FIELD_LOC(191, 188)
+#define CQC_CQ_PRODUCER_IDX CQC_FIELD_LOC(215, 192)
+#define CQC_CQ_CONSUMER_IDX CQC_FIELD_LOC(247, 224)
+#define CQC_CQE_BA_L CQC_FIELD_LOC(287, 256)
+#define CQC_CQE_BA_H CQC_FIELD_LOC(316, 288)
+#define CQC_POE_QID_H_0 CQC_FIELD_LOC(319, 317)
+#define CQC_DB_RECORD_EN CQC_FIELD_LOC(320, 320)
+#define CQC_CQE_DB_RECORD_ADDR_L CQC_FIELD_LOC(351, 321)
+#define CQC_CQE_DB_RECORD_ADDR_H CQC_FIELD_LOC(383, 352)
+#define CQC_CQE_CNT CQC_FIELD_LOC(407, 384)
+#define CQC_CQ_MAX_CNT CQC_FIELD_LOC(431, 416)
+#define CQC_CQ_PERIOD CQC_FIELD_LOC(447, 432)
+#define CQC_CQE_REPORT_TIMER CQC_FIELD_LOC(471, 448)
+#define CQC_WR_CQE_IDX CQC_FIELD_LOC(479, 472)
+#define CQC_SE_CQE_IDX CQC_FIELD_LOC(503, 480)
+#define CQC_POE_QID_H_1 CQC_FIELD_LOC(511, 511)
struct hns_roce_srq_context {
- __le32 byte_4_srqn_srqst;
- __le32 byte_8_limit_wl;
- __le32 byte_12_xrcd;
- __le32 byte_16_pi_ci;
- __le32 wqe_bt_ba;
- __le32 byte_24_wqe_bt_ba;
- __le32 byte_28_rqws_pd;
- __le32 idx_bt_ba;
- __le32 rsv_idx_bt_ba;
- __le32 idx_cur_blk_addr;
- __le32 byte_44_idxbufpgsz_addr;
- __le32 idx_nxt_blk_addr;
- __le32 rsv_idxnxtblkaddr;
- __le32 byte_56_xrc_cqn;
- __le32 db_record_addr_record_en;
- __le32 db_record_addr;
+ __le32 data[16];
};
#define SRQC_FIELD_LOC(h, l) FIELD_LOC(struct hns_roce_srq_context, h, l)
@@ -438,71 +420,6 @@ struct hns_roce_srq_context {
#define SRQC_DB_RECORD_ADDR_L SRQC_FIELD_LOC(479, 449)
#define SRQC_DB_RECORD_ADDR_H SRQC_FIELD_LOC(511, 480)
-#define SRQC_BYTE_4_SRQ_ST_S 0
-#define SRQC_BYTE_4_SRQ_ST_M GENMASK(1, 0)
-
-#define SRQC_BYTE_4_SRQ_WQE_HOP_NUM_S 2
-#define SRQC_BYTE_4_SRQ_WQE_HOP_NUM_M GENMASK(3, 2)
-
-#define SRQC_BYTE_4_SRQ_SHIFT_S 4
-#define SRQC_BYTE_4_SRQ_SHIFT_M GENMASK(7, 4)
-
-#define SRQC_BYTE_4_SRQN_S 8
-#define SRQC_BYTE_4_SRQN_M GENMASK(31, 8)
-
-#define SRQC_BYTE_8_SRQ_LIMIT_WL_S 0
-#define SRQC_BYTE_8_SRQ_LIMIT_WL_M GENMASK(15, 0)
-
-#define SRQC_BYTE_12_SRQ_XRCD_S 0
-#define SRQC_BYTE_12_SRQ_XRCD_M GENMASK(23, 0)
-
-#define SRQC_BYTE_16_SRQ_PRODUCER_IDX_S 0
-#define SRQC_BYTE_16_SRQ_PRODUCER_IDX_M GENMASK(15, 0)
-
-#define SRQC_BYTE_16_SRQ_CONSUMER_IDX_S 0
-#define SRQC_BYTE_16_SRQ_CONSUMER_IDX_M GENMASK(31, 16)
-
-#define SRQC_BYTE_24_SRQ_WQE_BT_BA_S 0
-#define SRQC_BYTE_24_SRQ_WQE_BT_BA_M GENMASK(28, 0)
-
-#define SRQC_BYTE_28_PD_S 0
-#define SRQC_BYTE_28_PD_M GENMASK(23, 0)
-
-#define SRQC_BYTE_28_RQWS_S 24
-#define SRQC_BYTE_28_RQWS_M GENMASK(27, 24)
-
-#define SRQC_BYTE_36_SRQ_IDX_BT_BA_S 0
-#define SRQC_BYTE_36_SRQ_IDX_BT_BA_M GENMASK(28, 0)
-
-#define SRQC_BYTE_44_SRQ_IDX_CUR_BLK_ADDR_S 0
-#define SRQC_BYTE_44_SRQ_IDX_CUR_BLK_ADDR_M GENMASK(19, 0)
-
-#define SRQC_BYTE_44_SRQ_IDX_HOP_NUM_S 22
-#define SRQC_BYTE_44_SRQ_IDX_HOP_NUM_M GENMASK(23, 22)
-
-#define SRQC_BYTE_44_SRQ_IDX_BA_PG_SZ_S 24
-#define SRQC_BYTE_44_SRQ_IDX_BA_PG_SZ_M GENMASK(27, 24)
-
-#define SRQC_BYTE_44_SRQ_IDX_BUF_PG_SZ_S 28
-#define SRQC_BYTE_44_SRQ_IDX_BUF_PG_SZ_M GENMASK(31, 28)
-
-#define SRQC_BYTE_52_SRQ_IDX_NXT_BLK_ADDR_S 0
-#define SRQC_BYTE_52_SRQ_IDX_NXT_BLK_ADDR_M GENMASK(19, 0)
-
-#define SRQC_BYTE_56_SRQ_XRC_CQN_S 0
-#define SRQC_BYTE_56_SRQ_XRC_CQN_M GENMASK(23, 0)
-
-#define SRQC_BYTE_56_SRQ_WQE_BA_PG_SZ_S 24
-#define SRQC_BYTE_56_SRQ_WQE_BA_PG_SZ_M GENMASK(27, 24)
-
-#define SRQC_BYTE_56_SRQ_WQE_BUF_PG_SZ_S 28
-#define SRQC_BYTE_56_SRQ_WQE_BUF_PG_SZ_M GENMASK(31, 28)
-
-#define SRQC_BYTE_60_SRQ_RECORD_EN_S 0
-
-#define SRQC_BYTE_60_SRQ_DB_RECORD_ADDR_S 1
-#define SRQC_BYTE_60_SRQ_DB_RECORD_ADDR_M GENMASK(31, 1)
-
enum {
V2_MPT_ST_VALID = 0x1,
V2_MPT_ST_FREE = 0x2,
@@ -590,372 +507,192 @@ struct hns_roce_v2_qp_context {
#define QPC_FIELD_LOC(h, l) FIELD_LOC(struct hns_roce_v2_qp_context, h, l)
+#define QPC_TST QPC_FIELD_LOC(2, 0)
+#define QPC_SGE_SHIFT QPC_FIELD_LOC(7, 3)
+#define QPC_CNP_TIMER QPC_FIELD_LOC(31, 8)
+#define QPC_WQE_SGE_BA_L QPC_FIELD_LOC(63, 32)
+#define QPC_WQE_SGE_BA_H QPC_FIELD_LOC(92, 64)
+#define QPC_SQ_HOP_NUM QPC_FIELD_LOC(94, 93)
+#define QPC_CIRE_EN QPC_FIELD_LOC(95, 95)
+#define QPC_WQE_SGE_BA_PG_SZ QPC_FIELD_LOC(99, 96)
+#define QPC_WQE_SGE_BUF_PG_SZ QPC_FIELD_LOC(103, 100)
+#define QPC_PD QPC_FIELD_LOC(127, 104)
+#define QPC_RQ_HOP_NUM QPC_FIELD_LOC(129, 128)
+#define QPC_SGE_HOP_NUM QPC_FIELD_LOC(131, 130)
+#define QPC_RQWS QPC_FIELD_LOC(135, 132)
+#define QPC_SQ_SHIFT QPC_FIELD_LOC(139, 136)
+#define QPC_RQ_SHIFT QPC_FIELD_LOC(143, 140)
+#define QPC_GMV_IDX QPC_FIELD_LOC(159, 144)
+#define QPC_HOPLIMIT QPC_FIELD_LOC(167, 160)
+#define QPC_TC QPC_FIELD_LOC(175, 168)
+#define QPC_VLAN_ID QPC_FIELD_LOC(187, 176)
+#define QPC_MTU QPC_FIELD_LOC(191, 188)
+#define QPC_FL QPC_FIELD_LOC(211, 192)
+#define QPC_SL QPC_FIELD_LOC(215, 212)
+#define QPC_CNP_TX_FLAG QPC_FIELD_LOC(216, 216)
+#define QPC_CE_FLAG QPC_FIELD_LOC(217, 217)
+#define QPC_LBI QPC_FIELD_LOC(218, 218)
+#define QPC_AT QPC_FIELD_LOC(223, 219)
+#define QPC_DGID QPC_FIELD_LOC(351, 224)
+#define QPC_DMAC_L QPC_FIELD_LOC(383, 352)
+#define QPC_DMAC_H QPC_FIELD_LOC(399, 384)
+#define QPC_UDPSPN QPC_FIELD_LOC(415, 400)
+#define QPC_DQPN QPC_FIELD_LOC(439, 416)
+#define QPC_SQ_TX_ERR QPC_FIELD_LOC(440, 440)
+#define QPC_SQ_RX_ERR QPC_FIELD_LOC(441, 441)
+#define QPC_RQ_TX_ERR QPC_FIELD_LOC(442, 442)
+#define QPC_RQ_RX_ERR QPC_FIELD_LOC(443, 443)
+#define QPC_LP_PKTN_INI QPC_FIELD_LOC(447, 444)
#define QPC_CONG_ALGO_TMPL_ID QPC_FIELD_LOC(455, 448)
-
-#define V2_QPC_BYTE_4_TST_S 0
-#define V2_QPC_BYTE_4_TST_M GENMASK(2, 0)
-
-#define V2_QPC_BYTE_4_SGE_SHIFT_S 3
-#define V2_QPC_BYTE_4_SGE_SHIFT_M GENMASK(7, 3)
-
-#define V2_QPC_BYTE_4_SQPN_S 8
-#define V2_QPC_BYTE_4_SQPN_M GENMASK(31, 8)
-
-#define V2_QPC_BYTE_12_WQE_SGE_BA_S 0
-#define V2_QPC_BYTE_12_WQE_SGE_BA_M GENMASK(28, 0)
-
-#define V2_QPC_BYTE_12_SQ_HOP_NUM_S 29
-#define V2_QPC_BYTE_12_SQ_HOP_NUM_M GENMASK(30, 29)
-
-#define V2_QPC_BYTE_12_RSVD_LKEY_EN_S 31
-
-#define V2_QPC_BYTE_16_WQE_SGE_BA_PG_SZ_S 0
-#define V2_QPC_BYTE_16_WQE_SGE_BA_PG_SZ_M GENMASK(3, 0)
-
-#define V2_QPC_BYTE_16_WQE_SGE_BUF_PG_SZ_S 4
-#define V2_QPC_BYTE_16_WQE_SGE_BUF_PG_SZ_M GENMASK(7, 4)
-
-#define V2_QPC_BYTE_16_PD_S 8
-#define V2_QPC_BYTE_16_PD_M GENMASK(31, 8)
-
-#define V2_QPC_BYTE_20_RQ_HOP_NUM_S 0
-#define V2_QPC_BYTE_20_RQ_HOP_NUM_M GENMASK(1, 0)
-
-#define V2_QPC_BYTE_20_SGE_HOP_NUM_S 2
-#define V2_QPC_BYTE_20_SGE_HOP_NUM_M GENMASK(3, 2)
-
-#define V2_QPC_BYTE_20_RQWS_S 4
-#define V2_QPC_BYTE_20_RQWS_M GENMASK(7, 4)
-
-#define V2_QPC_BYTE_20_SQ_SHIFT_S 8
-#define V2_QPC_BYTE_20_SQ_SHIFT_M GENMASK(11, 8)
-
-#define V2_QPC_BYTE_20_RQ_SHIFT_S 12
-#define V2_QPC_BYTE_20_RQ_SHIFT_M GENMASK(15, 12)
-
-#define V2_QPC_BYTE_20_SGID_IDX_S 16
-#define V2_QPC_BYTE_20_SGID_IDX_M GENMASK(23, 16)
-
-#define V2_QPC_BYTE_20_SMAC_IDX_S 24
-#define V2_QPC_BYTE_20_SMAC_IDX_M GENMASK(31, 24)
-
-#define V2_QPC_BYTE_24_HOP_LIMIT_S 0
-#define V2_QPC_BYTE_24_HOP_LIMIT_M GENMASK(7, 0)
-
-#define V2_QPC_BYTE_24_TC_S 8
-#define V2_QPC_BYTE_24_TC_M GENMASK(15, 8)
-
-#define V2_QPC_BYTE_24_VLAN_ID_S 16
-#define V2_QPC_BYTE_24_VLAN_ID_M GENMASK(27, 16)
-
-#define V2_QPC_BYTE_24_MTU_S 28
-#define V2_QPC_BYTE_24_MTU_M GENMASK(31, 28)
-
-#define V2_QPC_BYTE_28_FL_S 0
-#define V2_QPC_BYTE_28_FL_M GENMASK(19, 0)
-
-#define V2_QPC_BYTE_28_SL_S 20
-#define V2_QPC_BYTE_28_SL_M GENMASK(23, 20)
-
-#define V2_QPC_BYTE_28_CNP_TX_FLAG_S 24
-
-#define V2_QPC_BYTE_28_CE_FLAG_S 25
-
-#define V2_QPC_BYTE_28_LBI_S 26
-
-#define V2_QPC_BYTE_28_AT_S 27
-#define V2_QPC_BYTE_28_AT_M GENMASK(31, 27)
-
-#define V2_QPC_BYTE_52_DMAC_S 0
-#define V2_QPC_BYTE_52_DMAC_M GENMASK(15, 0)
-
-#define V2_QPC_BYTE_52_UDPSPN_S 16
-#define V2_QPC_BYTE_52_UDPSPN_M GENMASK(31, 16)
-
-#define V2_QPC_BYTE_56_DQPN_S 0
-#define V2_QPC_BYTE_56_DQPN_M GENMASK(23, 0)
-
-#define V2_QPC_BYTE_56_SQ_TX_ERR_S 24
-#define V2_QPC_BYTE_56_SQ_RX_ERR_S 25
-#define V2_QPC_BYTE_56_RQ_TX_ERR_S 26
-#define V2_QPC_BYTE_56_RQ_RX_ERR_S 27
-
-#define V2_QPC_BYTE_56_LP_PKTN_INI_S 28
-#define V2_QPC_BYTE_56_LP_PKTN_INI_M GENMASK(31, 28)
-
-#define V2_QPC_BYTE_60_SCC_TOKEN_S 8
-#define V2_QPC_BYTE_60_SCC_TOKEN_M GENMASK(26, 8)
-
-#define V2_QPC_BYTE_60_SQ_DB_DOING_S 27
-
-#define V2_QPC_BYTE_60_RQ_DB_DOING_S 28
-
-#define V2_QPC_BYTE_60_QP_ST_S 29
-#define V2_QPC_BYTE_60_QP_ST_M GENMASK(31, 29)
-
-#define V2_QPC_BYTE_68_RQ_RECORD_EN_S 0
-
-#define V2_QPC_BYTE_68_RQ_DB_RECORD_ADDR_S 1
-#define V2_QPC_BYTE_68_RQ_DB_RECORD_ADDR_M GENMASK(31, 1)
-
-#define V2_QPC_BYTE_76_SRQN_S 0
-#define V2_QPC_BYTE_76_SRQN_M GENMASK(23, 0)
-
-#define V2_QPC_BYTE_76_SRQ_EN_S 24
-
-#define V2_QPC_BYTE_76_RRE_S 25
-
-#define V2_QPC_BYTE_76_RWE_S 26
-
-#define V2_QPC_BYTE_76_ATE_S 27
-
-#define V2_QPC_BYTE_76_RQIE_S 28
-#define V2_QPC_BYTE_76_EXT_ATE_S 29
-#define V2_QPC_BYTE_76_RQ_VLAN_EN_S 30
-#define V2_QPC_BYTE_80_RX_CQN_S 0
-#define V2_QPC_BYTE_80_RX_CQN_M GENMASK(23, 0)
-
-#define V2_QPC_BYTE_80_XRC_QP_TYPE_S 24
-
-#define V2_QPC_BYTE_80_MIN_RNR_TIME_S 27
-#define V2_QPC_BYTE_80_MIN_RNR_TIME_M GENMASK(31, 27)
-
-#define V2_QPC_BYTE_84_RQ_PRODUCER_IDX_S 0
-#define V2_QPC_BYTE_84_RQ_PRODUCER_IDX_M GENMASK(15, 0)
-
-#define V2_QPC_BYTE_84_RQ_CONSUMER_IDX_S 16
-#define V2_QPC_BYTE_84_RQ_CONSUMER_IDX_M GENMASK(31, 16)
-
-#define V2_QPC_BYTE_92_RQ_CUR_BLK_ADDR_S 0
-#define V2_QPC_BYTE_92_RQ_CUR_BLK_ADDR_M GENMASK(19, 0)
-
-#define V2_QPC_BYTE_92_SRQ_INFO_S 20
-#define V2_QPC_BYTE_92_SRQ_INFO_M GENMASK(31, 20)
-
-#define V2_QPC_BYTE_96_RX_REQ_MSN_S 0
-#define V2_QPC_BYTE_96_RX_REQ_MSN_M GENMASK(23, 0)
-
-#define V2_QPC_BYTE_104_RQ_NXT_BLK_ADDR_S 0
-#define V2_QPC_BYTE_104_RQ_NXT_BLK_ADDR_M GENMASK(19, 0)
-
-#define V2_QPC_BYTE_104_RQ_CUR_WQE_SGE_NUM_S 24
-#define V2_QPC_BYTE_104_RQ_CUR_WQE_SGE_NUM_M GENMASK(31, 24)
-
-#define V2_QPC_BYTE_108_INV_CREDIT_S 0
-
-#define V2_QPC_BYTE_108_RX_REQ_PSN_ERR_S 3
-
-#define V2_QPC_BYTE_108_RX_REQ_LAST_OPTYPE_S 4
-#define V2_QPC_BYTE_108_RX_REQ_LAST_OPTYPE_M GENMASK(6, 4)
-
-#define V2_QPC_BYTE_108_RX_REQ_RNR_S 7
-
-#define V2_QPC_BYTE_108_RX_REQ_EPSN_S 8
-#define V2_QPC_BYTE_108_RX_REQ_EPSN_M GENMASK(31, 8)
-
-#define V2_QPC_BYTE_132_TRRL_HEAD_MAX_S 0
-#define V2_QPC_BYTE_132_TRRL_HEAD_MAX_M GENMASK(7, 0)
-
-#define V2_QPC_BYTE_132_TRRL_TAIL_MAX_S 8
-#define V2_QPC_BYTE_132_TRRL_TAIL_MAX_M GENMASK(15, 8)
-
-#define V2_QPC_BYTE_132_TRRL_BA_S 16
-#define V2_QPC_BYTE_132_TRRL_BA_M GENMASK(31, 16)
-
-#define V2_QPC_BYTE_140_TRRL_BA_S 0
-#define V2_QPC_BYTE_140_TRRL_BA_M GENMASK(11, 0)
-
-#define V2_QPC_BYTE_140_RR_MAX_S 12
-#define V2_QPC_BYTE_140_RR_MAX_M GENMASK(14, 12)
-
-#define V2_QPC_BYTE_140_RQ_RTY_WAIT_DO_S 15
-
-#define V2_QPC_BYTE_140_RAQ_TRRL_HEAD_S 16
-#define V2_QPC_BYTE_140_RAQ_TRRL_HEAD_M GENMASK(23, 16)
-
-#define V2_QPC_BYTE_140_RAQ_TRRL_TAIL_S 24
-#define V2_QPC_BYTE_140_RAQ_TRRL_TAIL_M GENMASK(31, 24)
-
-#define V2_QPC_BYTE_144_RAQ_RTY_INI_PSN_S 0
-#define V2_QPC_BYTE_144_RAQ_RTY_INI_PSN_M GENMASK(23, 0)
-
-#define V2_QPC_BYTE_144_RAQ_CREDIT_S 25
-#define V2_QPC_BYTE_144_RAQ_CREDIT_M GENMASK(29, 25)
-
-#define V2_QPC_BYTE_144_RESP_RTY_FLG_S 31
-
-#define V2_QPC_BYTE_148_RQ_MSN_S 0
-#define V2_QPC_BYTE_148_RQ_MSN_M GENMASK(23, 0)
-
-#define V2_QPC_BYTE_148_RAQ_SYNDROME_S 24
-#define V2_QPC_BYTE_148_RAQ_SYNDROME_M GENMASK(31, 24)
-
-#define V2_QPC_BYTE_152_RAQ_PSN_S 0
-#define V2_QPC_BYTE_152_RAQ_PSN_M GENMASK(23, 0)
-
-#define V2_QPC_BYTE_152_RAQ_TRRL_RTY_HEAD_S 24
-#define V2_QPC_BYTE_152_RAQ_TRRL_RTY_HEAD_M GENMASK(31, 24)
-
-#define V2_QPC_BYTE_156_RAQ_USE_PKTN_S 0
-#define V2_QPC_BYTE_156_RAQ_USE_PKTN_M GENMASK(23, 0)
-
-#define V2_QPC_BYTE_160_SQ_PRODUCER_IDX_S 0
-#define V2_QPC_BYTE_160_SQ_PRODUCER_IDX_M GENMASK(15, 0)
-
-#define V2_QPC_BYTE_160_SQ_CONSUMER_IDX_S 16
-#define V2_QPC_BYTE_160_SQ_CONSUMER_IDX_M GENMASK(31, 16)
-
-#define V2_QPC_BYTE_168_SQ_CUR_BLK_ADDR_S 0
-#define V2_QPC_BYTE_168_SQ_CUR_BLK_ADDR_M GENMASK(19, 0)
-
-#define V2_QPC_BYTE_168_MSG_RTY_LP_FLG_S 20
-
-#define V2_QPC_BYTE_168_SQ_INVLD_FLG_S 21
-
-#define V2_QPC_BYTE_168_LP_SGEN_INI_S 22
-#define V2_QPC_BYTE_168_LP_SGEN_INI_M GENMASK(23, 22)
-
-#define V2_QPC_BYTE_168_SQ_VLAN_EN_S 24
-#define V2_QPC_BYTE_168_POLL_DB_WAIT_DO_S 25
-#define V2_QPC_BYTE_168_SCC_TOKEN_FORBID_SQ_DEQ_S 26
-#define V2_QPC_BYTE_168_WAIT_ACK_TIMEOUT_S 27
-#define V2_QPC_BYTE_168_IRRL_IDX_LSB_S 28
-#define V2_QPC_BYTE_168_IRRL_IDX_LSB_M GENMASK(31, 28)
-
-#define V2_QPC_BYTE_172_ACK_REQ_FREQ_S 0
-#define V2_QPC_BYTE_172_ACK_REQ_FREQ_M GENMASK(5, 0)
-
-#define V2_QPC_BYTE_172_MSG_RNR_FLG_S 6
-
-#define V2_QPC_BYTE_172_FRE_S 7
-
-#define V2_QPC_BYTE_172_SQ_CUR_PSN_S 8
-#define V2_QPC_BYTE_172_SQ_CUR_PSN_M GENMASK(31, 8)
-
-#define V2_QPC_BYTE_176_MSG_USE_PKTN_S 0
-#define V2_QPC_BYTE_176_MSG_USE_PKTN_M GENMASK(23, 0)
-
-#define V2_QPC_BYTE_176_IRRL_HEAD_PRE_S 24
-#define V2_QPC_BYTE_176_IRRL_HEAD_PRE_M GENMASK(31, 24)
-
-#define V2_QPC_BYTE_184_SQ_CUR_SGE_BLK_ADDR_S 0
-#define V2_QPC_BYTE_184_SQ_CUR_SGE_BLK_ADDR_M GENMASK(19, 0)
-
-#define V2_QPC_BYTE_184_IRRL_IDX_MSB_S 20
-#define V2_QPC_BYTE_184_IRRL_IDX_MSB_M GENMASK(31, 20)
-
-#define V2_QPC_BYTE_192_CUR_SGE_IDX_S 0
-#define V2_QPC_BYTE_192_CUR_SGE_IDX_M GENMASK(23, 0)
-
-#define V2_QPC_BYTE_192_EXT_SGE_NUM_LEFT_S 24
-#define V2_QPC_BYTE_192_EXT_SGE_NUM_LEFT_M GENMASK(31, 24)
-
-#define V2_QPC_BYTE_196_IRRL_HEAD_S 0
-#define V2_QPC_BYTE_196_IRRL_HEAD_M GENMASK(7, 0)
-
-#define V2_QPC_BYTE_196_SQ_MAX_PSN_S 8
-#define V2_QPC_BYTE_196_SQ_MAX_PSN_M GENMASK(31, 8)
-
-#define V2_QPC_BYTE_200_SQ_MAX_IDX_S 0
-#define V2_QPC_BYTE_200_SQ_MAX_IDX_M GENMASK(15, 0)
-
-#define V2_QPC_BYTE_200_LCL_OPERATED_CNT_S 16
-#define V2_QPC_BYTE_200_LCL_OPERATED_CNT_M GENMASK(31, 16)
-
-#define V2_QPC_BYTE_208_IRRL_BA_S 0
-#define V2_QPC_BYTE_208_IRRL_BA_M GENMASK(25, 0)
-
-#define V2_QPC_BYTE_208_PKT_RNR_FLG_S 26
-
-#define V2_QPC_BYTE_208_PKT_RTY_FLG_S 27
-
-#define V2_QPC_BYTE_208_RMT_E2E_S 28
-
-#define V2_QPC_BYTE_208_SR_MAX_S 29
-#define V2_QPC_BYTE_208_SR_MAX_M GENMASK(31, 29)
-
-#define V2_QPC_BYTE_212_LSN_S 0
-#define V2_QPC_BYTE_212_LSN_M GENMASK(23, 0)
-
-#define V2_QPC_BYTE_212_RETRY_NUM_INIT_S 24
-#define V2_QPC_BYTE_212_RETRY_NUM_INIT_M GENMASK(26, 24)
-
-#define V2_QPC_BYTE_212_CHECK_FLG_S 27
-#define V2_QPC_BYTE_212_CHECK_FLG_M GENMASK(28, 27)
-
-#define V2_QPC_BYTE_212_RETRY_CNT_S 29
-#define V2_QPC_BYTE_212_RETRY_CNT_M GENMASK(31, 29)
-
-#define V2_QPC_BYTE_220_RETRY_MSG_MSN_S 0
-#define V2_QPC_BYTE_220_RETRY_MSG_MSN_M GENMASK(15, 0)
-
-#define V2_QPC_BYTE_220_RETRY_MSG_PSN_S 16
-#define V2_QPC_BYTE_220_RETRY_MSG_PSN_M GENMASK(31, 16)
-
-#define V2_QPC_BYTE_224_RETRY_MSG_PSN_S 0
-#define V2_QPC_BYTE_224_RETRY_MSG_PSN_M GENMASK(7, 0)
-
-#define V2_QPC_BYTE_224_RETRY_MSG_FPKT_PSN_S 8
-#define V2_QPC_BYTE_224_RETRY_MSG_FPKT_PSN_M GENMASK(31, 8)
-
-#define V2_QPC_BYTE_232_RX_SQ_CUR_BLK_ADDR_S 0
-#define V2_QPC_BYTE_232_RX_SQ_CUR_BLK_ADDR_M GENMASK(19, 0)
-
-#define V2_QPC_BYTE_232_IRRL_SGE_IDX_S 20
-#define V2_QPC_BYTE_232_IRRL_SGE_IDX_M GENMASK(28, 20)
-
-#define V2_QPC_BYTE_232_SO_LP_VLD_S 29
-#define V2_QPC_BYTE_232_FENCE_LP_VLD_S 30
-#define V2_QPC_BYTE_232_IRRL_LP_VLD_S 31
-
-#define V2_QPC_BYTE_240_IRRL_TAIL_REAL_S 0
-#define V2_QPC_BYTE_240_IRRL_TAIL_REAL_M GENMASK(7, 0)
-
-#define V2_QPC_BYTE_240_IRRL_TAIL_RD_S 8
-#define V2_QPC_BYTE_240_IRRL_TAIL_RD_M GENMASK(15, 8)
-
-#define V2_QPC_BYTE_240_RX_ACK_MSN_S 16
-#define V2_QPC_BYTE_240_RX_ACK_MSN_M GENMASK(31, 16)
-
-#define V2_QPC_BYTE_244_RX_ACK_EPSN_S 0
-#define V2_QPC_BYTE_244_RX_ACK_EPSN_M GENMASK(23, 0)
-
-#define V2_QPC_BYTE_244_RNR_NUM_INIT_S 24
-#define V2_QPC_BYTE_244_RNR_NUM_INIT_M GENMASK(26, 24)
-
-#define V2_QPC_BYTE_244_RNR_CNT_S 27
-#define V2_QPC_BYTE_244_RNR_CNT_M GENMASK(29, 27)
-
-#define V2_QPC_BYTE_244_LCL_OP_FLG_S 30
-#define V2_QPC_BYTE_244_IRRL_RD_FLG_S 31
-
-#define V2_QPC_BYTE_248_IRRL_PSN_S 0
-#define V2_QPC_BYTE_248_IRRL_PSN_M GENMASK(23, 0)
-
-#define V2_QPC_BYTE_248_ACK_PSN_ERR_S 24
-
-#define V2_QPC_BYTE_248_ACK_LAST_OPTYPE_S 25
-#define V2_QPC_BYTE_248_ACK_LAST_OPTYPE_M GENMASK(26, 25)
-
-#define V2_QPC_BYTE_248_IRRL_PSN_VLD_S 27
-
-#define V2_QPC_BYTE_248_RNR_RETRY_FLAG_S 28
-
-#define V2_QPC_BYTE_248_CQ_ERR_IND_S 31
-
-#define V2_QPC_BYTE_252_TX_CQN_S 0
-#define V2_QPC_BYTE_252_TX_CQN_M GENMASK(23, 0)
-
-#define V2_QPC_BYTE_252_SIG_TYPE_S 24
-
-#define V2_QPC_BYTE_252_ERR_TYPE_S 25
-#define V2_QPC_BYTE_252_ERR_TYPE_M GENMASK(31, 25)
-
-#define V2_QPC_BYTE_256_RQ_CQE_IDX_S 0
-#define V2_QPC_BYTE_256_RQ_CQE_IDX_M GENMASK(15, 0)
-
-#define V2_QPC_BYTE_256_SQ_FLUSH_IDX_S 16
-#define V2_QPC_BYTE_256_SQ_FLUSH_IDX_M GENMASK(31, 16)
+#define QPC_SCC_TOKEN QPC_FIELD_LOC(474, 456)
+#define QPC_SQ_DB_DOING QPC_FIELD_LOC(475, 475)
+#define QPC_RQ_DB_DOING QPC_FIELD_LOC(476, 476)
+#define QPC_QP_ST QPC_FIELD_LOC(479, 477)
+#define QPC_QKEY_XRCD QPC_FIELD_LOC(511, 480)
+#define QPC_RQ_RECORD_EN QPC_FIELD_LOC(512, 512)
+#define QPC_RQ_DB_RECORD_ADDR_L QPC_FIELD_LOC(543, 513)
+#define QPC_RQ_DB_RECORD_ADDR_H QPC_FIELD_LOC(575, 544)
+#define QPC_SRQN QPC_FIELD_LOC(599, 576)
+#define QPC_SRQ_EN QPC_FIELD_LOC(600, 600)
+#define QPC_RRE QPC_FIELD_LOC(601, 601)
+#define QPC_RWE QPC_FIELD_LOC(602, 602)
+#define QPC_ATE QPC_FIELD_LOC(603, 603)
+#define QPC_RQIE QPC_FIELD_LOC(604, 604)
+#define QPC_EXT_ATE QPC_FIELD_LOC(605, 605)
+#define QPC_RQ_VLAN_EN QPC_FIELD_LOC(606, 606)
+#define QPC_RQ_RTY_TX_ERR QPC_FIELD_LOC(607, 607)
+#define QPC_RX_CQN QPC_FIELD_LOC(631, 608)
+#define QPC_XRC_QP_TYPE QPC_FIELD_LOC(632, 632)
+#define QPC_RSV3 QPC_FIELD_LOC(634, 633)
+#define QPC_MIN_RNR_TIME QPC_FIELD_LOC(639, 635)
+#define QPC_RQ_PRODUCER_IDX QPC_FIELD_LOC(655, 640)
+#define QPC_RQ_CONSUMER_IDX QPC_FIELD_LOC(671, 656)
+#define QPC_RQ_CUR_BLK_ADDR_L QPC_FIELD_LOC(703, 672)
+#define QPC_RQ_CUR_BLK_ADDR_H QPC_FIELD_LOC(723, 704)
+#define QPC_SRQ_INFO QPC_FIELD_LOC(735, 724)
+#define QPC_RX_REQ_MSN QPC_FIELD_LOC(759, 736)
+#define QPC_REDUCE_CODE QPC_FIELD_LOC(766, 760)
+#define QPC_RX_XRC_PKT_CQE_FLG QPC_FIELD_LOC(767, 767)
+#define QPC_RQ_NXT_BLK_ADDR_L QPC_FIELD_LOC(799, 768)
+#define QPC_RQ_NXT_BLK_ADDR_H QPC_FIELD_LOC(819, 800)
+#define QPC_REDUCE_EN QPC_FIELD_LOC(820, 820)
+#define QPC_FLUSH_EN QPC_FIELD_LOC(821, 821)
+#define QPC_AW_EN QPC_FIELD_LOC(822, 822)
+#define QPC_WN_EN QPC_FIELD_LOC(823, 823)
+#define QPC_RQ_CUR_WQE_SGE_NUM QPC_FIELD_LOC(831, 824)
+#define QPC_INV_CREDIT QPC_FIELD_LOC(832, 832)
+#define QPC_LAST_WRITE_TYPE QPC_FIELD_LOC(834, 833)
+#define QPC_RX_REQ_PSN_ERR QPC_FIELD_LOC(835, 835)
+#define QPC_RX_REQ_LAST_OPTYPE QPC_FIELD_LOC(838, 836)
+#define QPC_RX_REQ_RNR QPC_FIELD_LOC(839, 839)
+#define QPC_RX_REQ_EPSN QPC_FIELD_LOC(863, 840)
+#define QPC_RQ_RNR_TIMER QPC_FIELD_LOC(895, 864)
+#define QPC_RX_MSG_LEN QPC_FIELD_LOC(927, 896)
+#define QPC_RX_RKEY_PKT_INFO QPC_FIELD_LOC(959, 928)
+#define QPC_RX_VA QPC_FIELD_LOC(1023, 960)
+#define QPC_TRRL_HEAD_MAX QPC_FIELD_LOC(1031, 1024)
+#define QPC_TRRL_TAIL_MAX QPC_FIELD_LOC(1039, 1032)
+#define QPC_TRRL_BA_L QPC_FIELD_LOC(1055, 1040)
+#define QPC_TRRL_BA_M QPC_FIELD_LOC(1087, 1056)
+#define QPC_TRRL_BA_H QPC_FIELD_LOC(1099, 1088)
+#define QPC_RR_MAX QPC_FIELD_LOC(1102, 1100)
+#define QPC_RQ_RTY_WAIT_DO QPC_FIELD_LOC(1103, 1103)
+#define QPC_RAQ_TRRL_HEAD QPC_FIELD_LOC(1111, 1104)
+#define QPC_RAQ_TRRL_TAIL QPC_FIELD_LOC(1119, 1112)
+#define QPC_RAQ_RTY_INI_PSN QPC_FIELD_LOC(1143, 1120)
+#define QPC_CIRE_SLV_RQ_EN QPC_FIELD_LOC(1144, 1144)
+#define QPC_RAQ_CREDIT QPC_FIELD_LOC(1149, 1145)
+#define QPC_RQ_DB_IN_EXT QPC_FIELD_LOC(1150, 1150)
+#define QPC_RESP_RTY_FLG QPC_FIELD_LOC(1151, 1151)
+#define QPC_RAQ_MSN QPC_FIELD_LOC(1175, 1152)
+#define QPC_RAQ_SYNDROME QPC_FIELD_LOC(1183, 1176)
+#define QPC_RAQ_PSN QPC_FIELD_LOC(1207, 1184)
+#define QPC_RAQ_TRRL_RTY_HEAD QPC_FIELD_LOC(1215, 1208)
+#define QPC_RAQ_USE_PKTN QPC_FIELD_LOC(1239, 1216)
+#define QPC_RQ_SCC_TOKEN QPC_FIELD_LOC(1245, 1240)
+#define QPC_RVD10 QPC_FIELD_LOC(1247, 1246)
+#define QPC_SQ_PRODUCER_IDX QPC_FIELD_LOC(1263, 1248)
+#define QPC_SQ_CONSUMER_IDX QPC_FIELD_LOC(1279, 1264)
+#define QPC_SQ_CUR_BLK_ADDR_L QPC_FIELD_LOC(1311, 1280)
+#define QPC_SQ_CUR_BLK_ADDR_H QPC_FIELD_LOC(1331, 1312)
+#define QPC_MSG_RTY_LP_FLG QPC_FIELD_LOC(1332, 1332)
+#define QPC_SQ_INVLD_FLG QPC_FIELD_LOC(1333, 1333)
+#define QPC_LP_SGEN_INI QPC_FIELD_LOC(1335, 1334)
+#define QPC_SQ_VLAN_EN QPC_FIELD_LOC(1336, 1336)
+#define QPC_POLL_DB_WAIT_DO QPC_FIELD_LOC(1337, 1337)
+#define QPC_SCC_TOKEN_FORBID_SQ_DEQ QPC_FIELD_LOC(1338, 1338)
+#define QPC_WAIT_ACK_TIMEOUT QPC_FIELD_LOC(1339, 1339)
+#define QPC_IRRL_IDX_LSB QPC_FIELD_LOC(1343, 1340)
+#define QPC_ACK_REQ_FREQ QPC_FIELD_LOC(1349, 1344)
+#define QPC_MSG_RNR_FLG QPC_FIELD_LOC(1350, 1350)
+#define QPC_FRE QPC_FIELD_LOC(1351, 1351)
+#define QPC_SQ_CUR_PSN QPC_FIELD_LOC(1375, 1352)
+#define QPC_MSG_USE_PKTN QPC_FIELD_LOC(1399, 1376)
+#define QPC_IRRL_HEAD_PRE QPC_FIELD_LOC(1407, 1400)
+#define QPC_SQ_CUR_SGE_BLK_ADDR_L QPC_FIELD_LOC(1439, 1408)
+#define QPC_SQ_CUR_SGE_BLK_ADDR_H QPC_FIELD_LOC(1459, 1440)
+#define QPC_IRRL_IDX_MSB QPC_FIELD_LOC(1471, 1460)
+#define QPC_CUR_SGE_OFFSET QPC_FIELD_LOC(1503, 1472)
+#define QPC_CUR_SGE_IDX QPC_FIELD_LOC(1527, 1504)
+#define QPC_EXT_SGE_NUM_LEFT QPC_FIELD_LOC(1535, 1528)
+#define QPC_OWNER_MODE QPC_FIELD_LOC(1536, 1536)
+#define QPC_CIRE_SLV_SQ_EN QPC_FIELD_LOC(1537, 1537)
+#define QPC_CIRE_DOING QPC_FIELD_LOC(1538, 1538)
+#define QPC_CIRE_RESULT QPC_FIELD_LOC(1539, 1539)
+#define QPC_OWNER_DB_WAIT_DO QPC_FIELD_LOC(1540, 1540)
+#define QPC_SQ_WQE_INVLD QPC_FIELD_LOC(1541, 1541)
+#define QPC_DCA_MODE QPC_FIELD_LOC(1542, 1542)
+#define QPC_RTY_OWNER_NOCHK QPC_FIELD_LOC(1543, 1543)
+#define QPC_V2_IRRL_HEAD QPC_FIELD_LOC(1543, 1536)
+#define QPC_SQ_MAX_PSN QPC_FIELD_LOC(1567, 1544)
+#define QPC_SQ_MAX_IDX QPC_FIELD_LOC(1583, 1568)
+#define QPC_LCL_OPERATED_CNT QPC_FIELD_LOC(1599, 1584)
+#define QPC_IRRL_BA_L QPC_FIELD_LOC(1631, 1600)
+#define QPC_IRRL_BA_H QPC_FIELD_LOC(1657, 1632)
+#define QPC_PKT_RNR_FLG QPC_FIELD_LOC(1658, 1658)
+#define QPC_PKT_RTY_FLG QPC_FIELD_LOC(1659, 1659)
+#define QPC_RMT_E2E QPC_FIELD_LOC(1660, 1660)
+#define QPC_SR_MAX QPC_FIELD_LOC(1663, 1661)
+#define QPC_LSN QPC_FIELD_LOC(1687, 1664)
+#define QPC_RETRY_NUM_INIT QPC_FIELD_LOC(1690, 1688)
+#define QPC_CHECK_FLG QPC_FIELD_LOC(1692, 1691)
+#define QPC_RETRY_CNT QPC_FIELD_LOC(1695, 1693)
+#define QPC_SQ_TIMER QPC_FIELD_LOC(1727, 1696)
+#define QPC_RETRY_MSG_MSN QPC_FIELD_LOC(1743, 1728)
+#define QPC_RETRY_MSG_PSN_L QPC_FIELD_LOC(1759, 1744)
+#define QPC_RETRY_MSG_PSN_H QPC_FIELD_LOC(1767, 1760)
+#define QPC_RETRY_MSG_FPKT_PSN QPC_FIELD_LOC(1791, 1768)
+#define QPC_RX_SQ_CUR_BLK_ADDR_L QPC_FIELD_LOC(1823, 1792)
+#define QPC_RX_SQ_CUR_BLK_ADDR_H QPC_FIELD_LOC(1843, 1824)
+#define QPC_IRRL_SGE_IDX QPC_FIELD_LOC(1851, 1844)
+#define QPC_LSAN_EN QPC_FIELD_LOC(1852, 1852)
+#define QPC_SO_LP_VLD QPC_FIELD_LOC(1853, 1853)
+#define QPC_FENCE_LP_VLD QPC_FIELD_LOC(1854, 1854)
+#define QPC_IRRL_LP_VLD QPC_FIELD_LOC(1855, 1855)
+#define QPC_IRRL_CUR_SGE_OFFSET QPC_FIELD_LOC(1887, 1856)
+#define QPC_IRRL_TAIL_REAL QPC_FIELD_LOC(1895, 1888)
+#define QPC_IRRL_TAIL_RD QPC_FIELD_LOC(1903, 1896)
+#define QPC_RX_ACK_MSN QPC_FIELD_LOC(1919, 1904)
+#define QPC_RX_ACK_EPSN QPC_FIELD_LOC(1943, 1920)
+#define QPC_RNR_NUM_INIT QPC_FIELD_LOC(1946, 1944)
+#define QPC_RNR_CNT QPC_FIELD_LOC(1949, 1947)
+#define QPC_LCL_OP_FLG QPC_FIELD_LOC(1950, 1950)
+#define QPC_IRRL_RD_FLG QPC_FIELD_LOC(1951, 1951)
+#define QPC_IRRL_PSN QPC_FIELD_LOC(1975, 1952)
+#define QPC_ACK_PSN_ERR QPC_FIELD_LOC(1976, 1976)
+#define QPC_ACK_LAST_OPTYPE QPC_FIELD_LOC(1978, 1977)
+#define QPC_IRRL_PSN_VLD QPC_FIELD_LOC(1979, 1979)
+#define QPC_RNR_RETRY_FLAG QPC_FIELD_LOC(1980, 1980)
+#define QPC_SQ_RTY_TX_ERR QPC_FIELD_LOC(1981, 1981)
+#define QPC_LAST_IND QPC_FIELD_LOC(1982, 1982)
+#define QPC_CQ_ERR_IND QPC_FIELD_LOC(1983, 1983)
+#define QPC_TX_CQN QPC_FIELD_LOC(2007, 1984)
+#define QPC_SIG_TYPE QPC_FIELD_LOC(2008, 2008)
+#define QPC_ERR_TYPE QPC_FIELD_LOC(2015, 2009)
+#define QPC_RQ_CQE_IDX QPC_FIELD_LOC(2031, 2016)
+#define QPC_SQ_FLUSH_IDX QPC_FIELD_LOC(2047, 2032)
+
+#define RETRY_MSG_PSN_SHIFT 16
#define QPCEX_FIELD_LOC(h, l) FIELD_LOC(struct hns_roce_v2_qp_context_ex, h, l)
@@ -963,6 +700,7 @@ struct hns_roce_v2_qp_context {
#define QPCEX_CONG_ALG_SUB_SEL QPCEX_FIELD_LOC(1, 1)
#define QPCEX_DIP_CTX_IDX_VLD QPCEX_FIELD_LOC(2, 2)
#define QPCEX_DIP_CTX_IDX QPCEX_FIELD_LOC(22, 3)
+#define QPCEX_SQ_RQ_NOT_FORBID_EN QPCEX_FIELD_LOC(23, 23)
#define QPCEX_STASH QPCEX_FIELD_LOC(82, 82)
#define V2_QP_RWE_S 1 /* rdma write enable */
@@ -984,56 +722,31 @@ struct hns_roce_v2_cqe {
__le32 rsv[8];
};
-#define V2_CQE_BYTE_4_OPCODE_S 0
-#define V2_CQE_BYTE_4_OPCODE_M GENMASK(4, 0)
-
-#define V2_CQE_BYTE_4_RQ_INLINE_S 5
-
-#define V2_CQE_BYTE_4_S_R_S 6
-
-#define V2_CQE_BYTE_4_OWNER_S 7
-
-#define V2_CQE_BYTE_4_STATUS_S 8
-#define V2_CQE_BYTE_4_STATUS_M GENMASK(15, 8)
-
-#define V2_CQE_BYTE_4_WQE_INDX_S 16
-#define V2_CQE_BYTE_4_WQE_INDX_M GENMASK(31, 16)
-
-#define V2_CQE_BYTE_12_XRC_SRQN_S 0
-#define V2_CQE_BYTE_12_XRC_SRQN_M GENMASK(23, 0)
-
-#define V2_CQE_BYTE_16_LCL_QPN_S 0
-#define V2_CQE_BYTE_16_LCL_QPN_M GENMASK(23, 0)
-
-#define V2_CQE_BYTE_16_SUB_STATUS_S 24
-#define V2_CQE_BYTE_16_SUB_STATUS_M GENMASK(31, 24)
-
-#define V2_CQE_BYTE_28_SMAC_4_S 0
-#define V2_CQE_BYTE_28_SMAC_4_M GENMASK(7, 0)
-
-#define V2_CQE_BYTE_28_SMAC_5_S 8
-#define V2_CQE_BYTE_28_SMAC_5_M GENMASK(15, 8)
-
-#define V2_CQE_BYTE_28_PORT_TYPE_S 16
-#define V2_CQE_BYTE_28_PORT_TYPE_M GENMASK(17, 16)
-
-#define V2_CQE_BYTE_28_VID_S 18
-#define V2_CQE_BYTE_28_VID_M GENMASK(29, 18)
-
-#define V2_CQE_BYTE_28_VID_VLD_S 30
-
-#define V2_CQE_BYTE_32_RMT_QPN_S 0
-#define V2_CQE_BYTE_32_RMT_QPN_M GENMASK(23, 0)
-
-#define V2_CQE_BYTE_32_SL_S 24
-#define V2_CQE_BYTE_32_SL_M GENMASK(26, 24)
-
-#define V2_CQE_BYTE_32_PORTN_S 27
-#define V2_CQE_BYTE_32_PORTN_M GENMASK(29, 27)
-
-#define V2_CQE_BYTE_32_GRH_S 30
-
-#define V2_CQE_BYTE_32_LPK_S 31
+#define CQE_FIELD_LOC(h, l) FIELD_LOC(struct hns_roce_v2_cqe, h, l)
+
+#define CQE_OPCODE CQE_FIELD_LOC(4, 0)
+#define CQE_RQ_INLINE CQE_FIELD_LOC(5, 5)
+#define CQE_S_R CQE_FIELD_LOC(6, 6)
+#define CQE_OWNER CQE_FIELD_LOC(7, 7)
+#define CQE_STATUS CQE_FIELD_LOC(15, 8)
+#define CQE_WQE_IDX CQE_FIELD_LOC(31, 16)
+#define CQE_RKEY_IMMTDATA CQE_FIELD_LOC(63, 32)
+#define CQE_XRC_SRQN CQE_FIELD_LOC(87, 64)
+#define CQE_RSV0 CQE_FIELD_LOC(95, 88)
+#define CQE_LCL_QPN CQE_FIELD_LOC(119, 96)
+#define CQE_SUB_STATUS CQE_FIELD_LOC(127, 120)
+#define CQE_BYTE_CNT CQE_FIELD_LOC(159, 128)
+#define CQE_SMAC CQE_FIELD_LOC(207, 160)
+#define CQE_PORT_TYPE CQE_FIELD_LOC(209, 208)
+#define CQE_VID CQE_FIELD_LOC(221, 210)
+#define CQE_VID_VLD CQE_FIELD_LOC(222, 222)
+#define CQE_RSV2 CQE_FIELD_LOC(223, 223)
+#define CQE_RMT_QPN CQE_FIELD_LOC(247, 224)
+#define CQE_SL CQE_FIELD_LOC(250, 248)
+#define CQE_PORTN CQE_FIELD_LOC(253, 251)
+#define CQE_GRH CQE_FIELD_LOC(254, 254)
+#define CQE_LPK CQE_FIELD_LOC(255, 255)
+#define CQE_RSV3 CQE_FIELD_LOC(511, 256)
struct hns_roce_v2_mpt_entry {
__le32 byte_4_pd_hop_st;
@@ -1153,28 +866,30 @@ struct hns_roce_v2_mpt_entry {
#define V2_MPT_BYTE_64_PBL_BUF_PG_SZ_S 28
#define V2_MPT_BYTE_64_PBL_BUF_PG_SZ_M GENMASK(31, 28)
-#define V2_DB_TAG_S 0
-#define V2_DB_TAG_M GENMASK(23, 0)
+struct hns_roce_v2_db {
+ __le32 data[2];
+};
-#define V2_DB_CMD_S 24
-#define V2_DB_CMD_M GENMASK(27, 24)
+#define DB_FIELD_LOC(h, l) FIELD_LOC(struct hns_roce_v2_db, h, l)
-#define V2_DB_FLAG_S 31
+#define DB_TAG DB_FIELD_LOC(23, 0)
+#define DB_CMD DB_FIELD_LOC(27, 24)
+#define DB_FLAG DB_FIELD_LOC(31, 31)
+#define DB_PI DB_FIELD_LOC(47, 32)
+#define DB_SL DB_FIELD_LOC(50, 48)
+#define DB_CQ_CI DB_FIELD_LOC(55, 32)
+#define DB_CQ_NOTIFY DB_FIELD_LOC(56, 56)
+#define DB_CQ_CMD_SN DB_FIELD_LOC(58, 57)
+#define EQ_DB_TAG DB_FIELD_LOC(7, 0)
+#define EQ_DB_CMD DB_FIELD_LOC(17, 16)
+#define EQ_DB_CI DB_FIELD_LOC(55, 32)
#define V2_DB_PRODUCER_IDX_S 0
#define V2_DB_PRODUCER_IDX_M GENMASK(15, 0)
-#define V2_DB_SL_S 16
-#define V2_DB_SL_M GENMASK(18, 16)
-
#define V2_CQ_DB_CONS_IDX_S 0
#define V2_CQ_DB_CONS_IDX_M GENMASK(23, 0)
-#define V2_CQ_DB_NOTIFY_TYPE_S 24
-
-#define V2_CQ_DB_CMD_SN_S 25
-#define V2_CQ_DB_CMD_SN_M GENMASK(26, 25)
-
struct hns_roce_v2_ud_send_wqe {
__le32 byte_4;
__le32 msg_len;
@@ -1272,16 +987,6 @@ struct hns_roce_v2_rc_send_wqe {
#define V2_RC_SEND_WQE_BYTE_4_INLINE_S 12
-#define V2_RC_FRMR_WQE_BYTE_40_BIND_EN_S 10
-
-#define V2_RC_FRMR_WQE_BYTE_40_ATOMIC_S 11
-
-#define V2_RC_FRMR_WQE_BYTE_40_RR_S 12
-
-#define V2_RC_FRMR_WQE_BYTE_40_RW_S 13
-
-#define V2_RC_FRMR_WQE_BYTE_40_LW_S 14
-
#define V2_RC_SEND_WQE_BYTE_4_FLAG_S 31
#define V2_RC_SEND_WQE_BYTE_16_XRC_SRQN_S 0
@@ -1300,10 +1005,18 @@ struct hns_roce_wqe_frmr_seg {
__le32 byte_40;
};
-#define V2_RC_FRMR_WQE_BYTE_40_PBL_BUF_PG_SZ_S 4
-#define V2_RC_FRMR_WQE_BYTE_40_PBL_BUF_PG_SZ_M GENMASK(7, 4)
+#define FRMR_WQE_FIELD_LOC(h, l) FIELD_LOC(struct hns_roce_wqe_frmr_seg, h, l)
-#define V2_RC_FRMR_WQE_BYTE_40_BLK_MODE_S 8
+#define FRMR_PBL_SIZE FRMR_WQE_FIELD_LOC(31, 0)
+#define FRMR_BLOCK_SIZE FRMR_WQE_FIELD_LOC(35, 32)
+#define FRMR_PBL_BUF_PG_SZ FRMR_WQE_FIELD_LOC(39, 36)
+#define FRMR_BLK_MODE FRMR_WQE_FIELD_LOC(40, 40)
+#define FRMR_ZBVA FRMR_WQE_FIELD_LOC(41, 41)
+#define FRMR_BIND_EN FRMR_WQE_FIELD_LOC(42, 42)
+#define FRMR_ATOMIC FRMR_WQE_FIELD_LOC(43, 43)
+#define FRMR_RR FRMR_WQE_FIELD_LOC(44, 44)
+#define FRMR_RW FRMR_WQE_FIELD_LOC(45, 45)
+#define FRMR_LW FRMR_WQE_FIELD_LOC(46, 46)
struct hns_roce_v2_wqe_data_seg {
__le32 len;
@@ -1311,11 +1024,6 @@ struct hns_roce_v2_wqe_data_seg {
__le64 addr;
};
-struct hns_roce_v2_db {
- __le32 byte_4;
- __le32 parameter;
-};
-
struct hns_roce_query_version {
__le16 rocee_vendor_id;
__le16 rocee_hw_version;
@@ -1342,39 +1050,27 @@ struct hns_roce_func_clear {
#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;
- __le32 depth_pgsz_init_en;
- __le32 head_ba_l;
- __le32 head_ba_h_nxtptr;
- __le32 head_ptr;
-};
-
-#define CFG_LLM_QUE_DEPTH_S 0
-#define CFG_LLM_QUE_DEPTH_M GENMASK(12, 0)
-
-#define CFG_LLM_QUE_PGSZ_S 16
-#define CFG_LLM_QUE_PGSZ_M GENMASK(19, 16)
-
-#define CFG_LLM_INIT_EN_S 20
-#define CFG_LLM_INIT_EN_M GENMASK(20, 20)
-
-#define CFG_LLM_HEAD_PTR_S 0
-#define CFG_LLM_HEAD_PTR_M GENMASK(11, 0)
-
-struct hns_roce_cfg_llm_b {
- __le32 tail_ba_l;
- __le32 tail_ba_h;
- __le32 tail_ptr;
- __le32 rsv[3];
-};
-
-#define CFG_LLM_TAIL_BA_H_S 0
-#define CFG_LLM_TAIL_BA_H_M GENMASK(19, 0)
-
-#define CFG_LLM_TAIL_PTR_S 0
-#define CFG_LLM_TAIL_PTR_M GENMASK(11, 0)
+/* Fields of HNS_ROCE_OPC_EXT_CFG */
+#define EXT_CFG_VF_ID CMQ_REQ_FIELD_LOC(31, 0)
+#define EXT_CFG_QP_PI_IDX CMQ_REQ_FIELD_LOC(45, 32)
+#define EXT_CFG_QP_PI_NUM CMQ_REQ_FIELD_LOC(63, 48)
+#define EXT_CFG_QP_NUM CMQ_REQ_FIELD_LOC(87, 64)
+#define EXT_CFG_QP_IDX CMQ_REQ_FIELD_LOC(119, 96)
+#define EXT_CFG_LLM_IDX CMQ_REQ_FIELD_LOC(139, 128)
+#define EXT_CFG_LLM_NUM CMQ_REQ_FIELD_LOC(156, 144)
+
+#define CFG_LLM_A_BA_L CMQ_REQ_FIELD_LOC(31, 0)
+#define CFG_LLM_A_BA_H CMQ_REQ_FIELD_LOC(63, 32)
+#define CFG_LLM_A_DEPTH CMQ_REQ_FIELD_LOC(76, 64)
+#define CFG_LLM_A_PGSZ CMQ_REQ_FIELD_LOC(83, 80)
+#define CFG_LLM_A_INIT_EN CMQ_REQ_FIELD_LOC(84, 84)
+#define CFG_LLM_A_HEAD_BA_L CMQ_REQ_FIELD_LOC(127, 96)
+#define CFG_LLM_A_HEAD_BA_H CMQ_REQ_FIELD_LOC(147, 128)
+#define CFG_LLM_A_HEAD_NXTPTR CMQ_REQ_FIELD_LOC(159, 148)
+#define CFG_LLM_A_HEAD_PTR CMQ_REQ_FIELD_LOC(171, 160)
+#define CFG_LLM_B_TAIL_BA_L CMQ_REQ_FIELD_LOC(31, 0)
+#define CFG_LLM_B_TAIL_BA_H CMQ_REQ_FIELD_LOC(63, 32)
+#define CFG_LLM_B_TAIL_PTR CMQ_REQ_FIELD_LOC(75, 64)
/* Fields of HNS_ROCE_OPC_CFG_GLOBAL_PARAM */
#define CFG_GLOBAL_PARAM_1US_CYCLES CMQ_REQ_FIELD_LOC(9, 0)
@@ -1642,6 +1338,7 @@ struct hns_roce_congestion_algorithm {
u8 alg_sel;
u8 alg_sub_sel;
u8 dip_vld;
+ u8 wnd_mode_sel;
};
#define V2_QUERY_PF_CAPS_D_CEQ_DEPTH_S 0
@@ -1731,52 +1428,21 @@ struct hns_roce_v2_cmq_ring {
struct hns_roce_v2_cmq {
struct hns_roce_v2_cmq_ring csq;
- struct hns_roce_v2_cmq_ring crq;
u16 tx_timeout;
};
-enum hns_roce_link_table_type {
- TSQ_LINK_TABLE,
- TPQ_LINK_TABLE,
-};
-
struct hns_roce_link_table {
struct hns_roce_buf_list table;
- struct hns_roce_buf_list *pg_list;
- u32 npages;
- u32 pg_sz;
+ struct hns_roce_buf *buf;
};
-struct hns_roce_link_table_entry {
- u32 blk_ba0;
- u32 blk_ba1_nxt_ptr;
-};
-#define HNS_ROCE_LINK_TABLE_BA1_S 0
-#define HNS_ROCE_LINK_TABLE_BA1_M GENMASK(19, 0)
-
-#define HNS_ROCE_LINK_TABLE_NXT_PTR_S 20
-#define HNS_ROCE_LINK_TABLE_NXT_PTR_M GENMASK(31, 20)
+#define HNS_ROCE_EXT_LLM_ENTRY(addr, id) (((id) << (64 - 12)) | ((addr) >> 12))
+#define HNS_ROCE_EXT_LLM_MIN_PAGES(que_num) ((que_num) * 4 + 2)
struct hns_roce_v2_priv {
struct hnae3_handle *handle;
struct hns_roce_v2_cmq cmq;
- struct hns_roce_link_table tsq;
- struct hns_roce_link_table tpq;
-};
-
-struct hns_roce_eq_context {
- __le32 byte_4;
- __le32 byte_8;
- __le32 byte_12;
- __le32 eqe_report_timer;
- __le32 eqe_ba0;
- __le32 eqe_ba1;
- __le32 byte_28;
- __le32 byte_32;
- __le32 byte_36;
- __le32 byte_40;
- __le32 byte_44;
- __le32 rsv[5];
+ struct hns_roce_link_table ext_llm;
};
struct hns_roce_dip {
@@ -1840,6 +1506,10 @@ struct hns_roce_dip {
#define HNS_ROCE_V2_VF_ABN_INT_CFG_M GENMASK(2, 0)
#define HNS_ROCE_V2_VF_EVENT_INT_EN_M GENMASK(0, 0)
+struct hns_roce_eq_context {
+ __le32 data[16];
+};
+
#define EQC_FIELD_LOC(h, l) FIELD_LOC(struct hns_roce_eq_context, h, l)
#define EQC_EQ_ST EQC_FIELD_LOC(1, 0)
@@ -1876,15 +1546,6 @@ struct hns_roce_dip {
#define HNS_ROCE_V2_AEQE_SUB_TYPE_S 8
#define HNS_ROCE_V2_AEQE_SUB_TYPE_M GENMASK(15, 8)
-#define V2_EQ_DB_TAG_S 0
-#define V2_EQ_DB_TAG_M GENMASK(7, 0)
-
-#define V2_EQ_DB_CMD_S 16
-#define V2_EQ_DB_CMD_M GENMASK(17, 16)
-
-#define V2_EQ_DB_CONS_IDX_S 0
-#define V2_EQ_DB_CONS_IDX_M GENMASK(23, 0)
-
#define HNS_ROCE_V2_AEQE_EVENT_QUEUE_NUM_S 0
#define HNS_ROCE_V2_AEQE_EVENT_QUEUE_NUM_M GENMASK(23, 0)
diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c
index 6c6e82b11d8b..078a97193f0e 100644
--- a/drivers/infiniband/hw/hns/hns_roce_main.c
+++ b/drivers/infiniband/hw/hns/hns_roce_main.c
@@ -748,34 +748,16 @@ static int hns_roce_setup_hca(struct hns_roce_dev *hr_dev)
goto err_uar_table_free;
}
- ret = hns_roce_init_pd_table(hr_dev);
- if (ret) {
- dev_err(dev, "Failed to init protected domain table.\n");
- goto err_uar_alloc_free;
- }
+ hns_roce_init_pd_table(hr_dev);
- if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_XRC) {
- ret = hns_roce_init_xrcd_table(hr_dev);
- if (ret) {
- dev_err(dev, "failed to init xrcd table, ret = %d.\n",
- ret);
- goto err_pd_table_free;
- }
- }
+ if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_XRC)
+ hns_roce_init_xrcd_table(hr_dev);
- ret = hns_roce_init_mr_table(hr_dev);
- if (ret) {
- dev_err(dev, "Failed to init memory region table.\n");
- goto err_xrcd_table_free;
- }
+ hns_roce_init_mr_table(hr_dev);
hns_roce_init_cq_table(hr_dev);
- ret = hns_roce_init_qp_table(hr_dev);
- if (ret) {
- dev_err(dev, "Failed to init queue pair table.\n");
- goto err_cq_table_free;
- }
+ hns_roce_init_qp_table(hr_dev);
if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SRQ) {
ret = hns_roce_init_srq_table(hr_dev);
@@ -790,19 +772,13 @@ static int hns_roce_setup_hca(struct hns_roce_dev *hr_dev)
err_qp_table_free:
hns_roce_cleanup_qp_table(hr_dev);
-
-err_cq_table_free:
hns_roce_cleanup_cq_table(hr_dev);
- hns_roce_cleanup_mr_table(hr_dev);
+ ida_destroy(&hr_dev->mr_table.mtpt_ida.ida);
-err_xrcd_table_free:
if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_XRC)
- hns_roce_cleanup_xrcd_table(hr_dev);
-
-err_pd_table_free:
- hns_roce_cleanup_pd_table(hr_dev);
+ ida_destroy(&hr_dev->xrcd_ida.ida);
-err_uar_alloc_free:
+ ida_destroy(&hr_dev->pd_ida.ida);
hns_roce_uar_free(hr_dev, &hr_dev->priv_uar);
err_uar_table_free:
diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c
index 79b3c3023fe7..006c84bb3f9f 100644
--- a/drivers/infiniband/hw/hns/hns_roce_mr.c
+++ b/drivers/infiniband/hw/hns/hns_roce_mr.c
@@ -38,9 +38,9 @@
#include "hns_roce_cmd.h"
#include "hns_roce_hem.h"
-static u32 hw_index_to_key(unsigned long ind)
+static u32 hw_index_to_key(int ind)
{
- return (u32)(ind >> 24) | (ind << 8);
+ return ((u32)ind >> 24) | ((u32)ind << 8);
}
unsigned long key_to_hw_index(u32 key)
@@ -68,22 +68,23 @@ int hns_roce_hw_destroy_mpt(struct hns_roce_dev *hr_dev,
static int alloc_mr_key(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr)
{
+ struct hns_roce_ida *mtpt_ida = &hr_dev->mr_table.mtpt_ida;
struct ib_device *ibdev = &hr_dev->ib_dev;
- unsigned long obj = 0;
int err;
+ int id;
/* Allocate a key for mr from mr_table */
- err = hns_roce_bitmap_alloc(&hr_dev->mr_table.mtpt_bitmap, &obj);
- if (err) {
- ibdev_err(ibdev,
- "failed to alloc bitmap for MR key, ret = %d.\n",
- err);
+ id = ida_alloc_range(&mtpt_ida->ida, mtpt_ida->min, mtpt_ida->max,
+ GFP_KERNEL);
+ if (id < 0) {
+ ibdev_err(ibdev, "failed to alloc id for MR key, id(%d)\n", id);
return -ENOMEM;
}
- mr->key = hw_index_to_key(obj); /* MR key */
+ mr->key = hw_index_to_key(id); /* MR key */
- err = hns_roce_table_get(hr_dev, &hr_dev->mr_table.mtpt_table, obj);
+ err = hns_roce_table_get(hr_dev, &hr_dev->mr_table.mtpt_table,
+ (unsigned long)id);
if (err) {
ibdev_err(ibdev, "failed to alloc mtpt, ret = %d.\n", err);
goto err_free_bitmap;
@@ -91,7 +92,7 @@ static int alloc_mr_key(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr)
return 0;
err_free_bitmap:
- hns_roce_bitmap_free(&hr_dev->mr_table.mtpt_bitmap, obj, BITMAP_NO_RR);
+ ida_free(&mtpt_ida->ida, id);
return err;
}
@@ -100,7 +101,7 @@ static void free_mr_key(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr)
unsigned long obj = key_to_hw_index(mr->key);
hns_roce_table_put(hr_dev, &hr_dev->mr_table.mtpt_table, obj);
- hns_roce_bitmap_free(&hr_dev->mr_table.mtpt_bitmap, obj, BITMAP_NO_RR);
+ ida_free(&hr_dev->mr_table.mtpt_ida.ida, (int)obj);
}
static int alloc_mr_pbl(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr,
@@ -122,7 +123,7 @@ static int alloc_mr_pbl(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr,
buf_attr.mtt_only = is_fast;
err = hns_roce_mtr_create(hr_dev, &mr->pbl_mtr, &buf_attr,
- hr_dev->caps.pbl_ba_pg_sz + HNS_HW_PAGE_SHIFT,
+ hr_dev->caps.pbl_ba_pg_sz + PAGE_SHIFT,
udata, start);
if (err)
ibdev_err(ibdev, "failed to alloc pbl mtr, ret = %d.\n", err);
@@ -196,23 +197,13 @@ err_page:
return ret;
}
-int hns_roce_init_mr_table(struct hns_roce_dev *hr_dev)
-{
- struct hns_roce_mr_table *mr_table = &hr_dev->mr_table;
- int ret;
-
- ret = hns_roce_bitmap_init(&mr_table->mtpt_bitmap,
- hr_dev->caps.num_mtpts,
- hr_dev->caps.num_mtpts - 1,
- hr_dev->caps.reserved_mrws, 0);
- return ret;
-}
-
-void hns_roce_cleanup_mr_table(struct hns_roce_dev *hr_dev)
+void hns_roce_init_mr_table(struct hns_roce_dev *hr_dev)
{
- struct hns_roce_mr_table *mr_table = &hr_dev->mr_table;
+ struct hns_roce_ida *mtpt_ida = &hr_dev->mr_table.mtpt_ida;
- hns_roce_bitmap_cleanup(&mr_table->mtpt_bitmap);
+ ida_init(&mtpt_ida->ida);
+ mtpt_ida->max = hr_dev->caps.num_mtpts - 1;
+ mtpt_ida->min = hr_dev->caps.reserved_mrws;
}
struct ib_mr *hns_roce_get_dma_mr(struct ib_pd *pd, int acc)
@@ -503,8 +494,8 @@ static void hns_roce_mw_free(struct hns_roce_dev *hr_dev,
key_to_hw_index(mw->rkey));
}
- hns_roce_bitmap_free(&hr_dev->mr_table.mtpt_bitmap,
- key_to_hw_index(mw->rkey), BITMAP_NO_RR);
+ ida_free(&hr_dev->mr_table.mtpt_ida.ida,
+ (int)key_to_hw_index(mw->rkey));
}
static int hns_roce_mw_enable(struct hns_roce_dev *hr_dev,
@@ -558,16 +549,21 @@ err_table:
int hns_roce_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
{
struct hns_roce_dev *hr_dev = to_hr_dev(ibmw->device);
+ struct hns_roce_ida *mtpt_ida = &hr_dev->mr_table.mtpt_ida;
+ struct ib_device *ibdev = &hr_dev->ib_dev;
struct hns_roce_mw *mw = to_hr_mw(ibmw);
- unsigned long index = 0;
int ret;
+ int id;
- /* Allocate a key for mw from bitmap */
- ret = hns_roce_bitmap_alloc(&hr_dev->mr_table.mtpt_bitmap, &index);
- if (ret)
- return ret;
+ /* Allocate a key for mw from mr_table */
+ id = ida_alloc_range(&mtpt_ida->ida, mtpt_ida->min, mtpt_ida->max,
+ GFP_KERNEL);
+ if (id < 0) {
+ ibdev_err(ibdev, "failed to alloc id for MW key, id(%d)\n", id);
+ return -ENOMEM;
+ }
- mw->rkey = hw_index_to_key(index);
+ mw->rkey = hw_index_to_key(id);
ibmw->rkey = mw->rkey;
mw->pdn = to_hr_pd(ibmw->pd)->pdn;
@@ -737,11 +733,11 @@ static int mtr_map_bufs(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
return -ENOMEM;
if (mtr->umem)
- npage = hns_roce_get_umem_bufs(hr_dev, pages, page_count, 0,
+ npage = hns_roce_get_umem_bufs(hr_dev, pages, page_count,
mtr->umem, page_shift);
else
- npage = hns_roce_get_kmem_bufs(hr_dev, pages, page_count, 0,
- mtr->kmem);
+ npage = hns_roce_get_kmem_bufs(hr_dev, pages, page_count,
+ mtr->kmem, page_shift);
if (npage != page_count) {
ibdev_err(ibdev, "failed to get mtr page %d != %d.\n", npage,
@@ -753,8 +749,8 @@ static int mtr_map_bufs(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
if (mtr->hem_cfg.is_direct && npage > 1) {
ret = mtr_check_direct_pages(pages, npage, page_shift);
if (ret) {
- ibdev_err(ibdev, "failed to check %s mtr, idx = %d.\n",
- mtr->umem ? "user" : "kernel", ret);
+ ibdev_err(ibdev, "failed to check %s page: %d / %d.\n",
+ mtr->umem ? "umtr" : "kmtr", ret, npage);
ret = -ENOBUFS;
goto err_alloc_list;
}
@@ -776,7 +772,7 @@ int hns_roce_mtr_map(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
struct ib_device *ibdev = &hr_dev->ib_dev;
struct hns_roce_buf_region *r;
unsigned int i, mapped_cnt;
- int ret;
+ int ret = 0;
/*
* Only use the first page address as root ba when hopnum is 0, this
@@ -799,7 +795,7 @@ int hns_roce_mtr_map(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
if (r->offset + r->count > page_cnt) {
ret = -EINVAL;
ibdev_err(ibdev,
- "failed to check mtr%u end %u + %u, max %u.\n",
+ "failed to check mtr%u count %u + %u > %u.\n",
i, r->offset, r->count, page_cnt);
return ret;
}
@@ -992,7 +988,7 @@ int hns_roce_mtr_create(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
&buf_page_shift,
udata ? user_addr & ~PAGE_MASK : 0);
if (buf_page_cnt < 1 || buf_page_shift < HNS_HW_PAGE_SHIFT) {
- ibdev_err(ibdev, "failed to init mtr cfg, count %d shift %d.\n",
+ ibdev_err(ibdev, "failed to init mtr cfg, count %d shift %u.\n",
buf_page_cnt, buf_page_shift);
return -EINVAL;
}
diff --git a/drivers/infiniband/hw/hns/hns_roce_pd.c b/drivers/infiniband/hw/hns/hns_roce_pd.c
index a5813bf567b2..ea5663630985 100644
--- a/drivers/infiniband/hw/hns/hns_roce_pd.c
+++ b/drivers/infiniband/hw/hns/hns_roce_pd.c
@@ -34,39 +34,31 @@
#include <linux/pci.h>
#include "hns_roce_device.h"
-static int hns_roce_pd_alloc(struct hns_roce_dev *hr_dev, unsigned long *pdn)
+void hns_roce_init_pd_table(struct hns_roce_dev *hr_dev)
{
- return hns_roce_bitmap_alloc(&hr_dev->pd_bitmap, pdn) ? -ENOMEM : 0;
-}
-
-static void hns_roce_pd_free(struct hns_roce_dev *hr_dev, unsigned long pdn)
-{
- hns_roce_bitmap_free(&hr_dev->pd_bitmap, pdn, BITMAP_NO_RR);
-}
-
-int hns_roce_init_pd_table(struct hns_roce_dev *hr_dev)
-{
- return hns_roce_bitmap_init(&hr_dev->pd_bitmap, hr_dev->caps.num_pds,
- hr_dev->caps.num_pds - 1,
- hr_dev->caps.reserved_pds, 0);
-}
+ struct hns_roce_ida *pd_ida = &hr_dev->pd_ida;
-void hns_roce_cleanup_pd_table(struct hns_roce_dev *hr_dev)
-{
- hns_roce_bitmap_cleanup(&hr_dev->pd_bitmap);
+ ida_init(&pd_ida->ida);
+ pd_ida->max = hr_dev->caps.num_pds - 1;
+ pd_ida->min = hr_dev->caps.reserved_pds;
}
int hns_roce_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
{
struct ib_device *ib_dev = ibpd->device;
+ struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev);
+ struct hns_roce_ida *pd_ida = &hr_dev->pd_ida;
struct hns_roce_pd *pd = to_hr_pd(ibpd);
- int ret;
+ int ret = 0;
+ int id;
- ret = hns_roce_pd_alloc(to_hr_dev(ib_dev), &pd->pdn);
- if (ret) {
- ibdev_err(ib_dev, "failed to alloc pd, ret = %d.\n", ret);
- return ret;
+ id = ida_alloc_range(&pd_ida->ida, pd_ida->min, pd_ida->max,
+ GFP_KERNEL);
+ if (id < 0) {
+ ibdev_err(ib_dev, "failed to alloc pd, id = %d.\n", id);
+ return -ENOMEM;
}
+ pd->pdn = (unsigned long)id;
if (udata) {
struct hns_roce_ib_alloc_pd_resp resp = {.pdn = pd->pdn};
@@ -74,7 +66,7 @@ int hns_roce_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
ret = ib_copy_to_udata(udata, &resp,
min(udata->outlen, sizeof(resp)));
if (ret) {
- hns_roce_pd_free(to_hr_dev(ib_dev), pd->pdn);
+ ida_free(&pd_ida->ida, id);
ibdev_err(ib_dev, "failed to copy to udata, ret = %d\n", ret);
}
}
@@ -84,7 +76,10 @@ int hns_roce_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
int 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);
+ struct hns_roce_dev *hr_dev = to_hr_dev(pd->device);
+
+ ida_free(&hr_dev->pd_ida.ida, (int)to_hr_pd(pd)->pdn);
+
return 0;
}
@@ -121,8 +116,7 @@ int hns_roce_uar_alloc(struct hns_roce_dev *hr_dev, struct hns_roce_uar *uar)
void hns_roce_uar_free(struct hns_roce_dev *hr_dev, struct hns_roce_uar *uar)
{
- hns_roce_bitmap_free(&hr_dev->uar_table.bitmap, uar->logic_idx,
- BITMAP_NO_RR);
+ hns_roce_bitmap_free(&hr_dev->uar_table.bitmap, uar->logic_idx);
}
int hns_roce_init_uar_table(struct hns_roce_dev *hr_dev)
@@ -140,35 +134,27 @@ void hns_roce_cleanup_uar_table(struct hns_roce_dev *hr_dev)
static int hns_roce_xrcd_alloc(struct hns_roce_dev *hr_dev, u32 *xrcdn)
{
- unsigned long obj;
- int ret;
+ struct hns_roce_ida *xrcd_ida = &hr_dev->xrcd_ida;
+ int id;
- ret = hns_roce_bitmap_alloc(&hr_dev->xrcd_bitmap, &obj);
- if (ret)
- return ret;
-
- *xrcdn = obj;
+ id = ida_alloc_range(&xrcd_ida->ida, xrcd_ida->min, xrcd_ida->max,
+ GFP_KERNEL);
+ if (id < 0) {
+ ibdev_err(&hr_dev->ib_dev, "failed to alloc xrcdn(%d).\n", id);
+ return -ENOMEM;
+ }
+ *xrcdn = (u32)id;
return 0;
}
-static void hns_roce_xrcd_free(struct hns_roce_dev *hr_dev,
- u32 xrcdn)
-{
- hns_roce_bitmap_free(&hr_dev->xrcd_bitmap, xrcdn, BITMAP_NO_RR);
-}
-
-int hns_roce_init_xrcd_table(struct hns_roce_dev *hr_dev)
+void hns_roce_init_xrcd_table(struct hns_roce_dev *hr_dev)
{
- return hns_roce_bitmap_init(&hr_dev->xrcd_bitmap,
- hr_dev->caps.num_xrcds,
- hr_dev->caps.num_xrcds - 1,
- hr_dev->caps.reserved_xrcds, 0);
-}
+ struct hns_roce_ida *xrcd_ida = &hr_dev->xrcd_ida;
-void hns_roce_cleanup_xrcd_table(struct hns_roce_dev *hr_dev)
-{
- hns_roce_bitmap_cleanup(&hr_dev->xrcd_bitmap);
+ ida_init(&xrcd_ida->ida);
+ xrcd_ida->max = hr_dev->caps.num_xrcds - 1;
+ xrcd_ida->min = hr_dev->caps.reserved_xrcds;
}
int hns_roce_alloc_xrcd(struct ib_xrcd *ib_xrcd, struct ib_udata *udata)
@@ -181,18 +167,18 @@ int hns_roce_alloc_xrcd(struct ib_xrcd *ib_xrcd, struct ib_udata *udata)
return -EINVAL;
ret = hns_roce_xrcd_alloc(hr_dev, &xrcd->xrcdn);
- if (ret) {
- dev_err(hr_dev->dev, "failed to alloc xrcdn, ret = %d.\n", ret);
+ if (ret)
return ret;
- }
return 0;
}
int hns_roce_dealloc_xrcd(struct ib_xrcd *ib_xrcd, struct ib_udata *udata)
{
- hns_roce_xrcd_free(to_hr_dev(ib_xrcd->device),
- to_hr_xrcd(ib_xrcd)->xrcdn);
+ struct hns_roce_dev *hr_dev = to_hr_dev(ib_xrcd->device);
+ u32 xrcdn = to_hr_xrcd(ib_xrcd)->xrcdn;
+
+ ida_free(&hr_dev->xrcd_ida.ida, (int)xrcdn);
return 0;
}
diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c
index 230a909ba9bc..b101b7e578f2 100644
--- a/drivers/infiniband/hw/hns/hns_roce_qp.c
+++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
@@ -65,7 +65,7 @@ static void flush_work_handle(struct work_struct *work)
* make sure we signal QP destroy leg that flush QP was completed
* so that it can safely proceed ahead now and destroy QP
*/
- if (atomic_dec_and_test(&hr_qp->refcount))
+ if (refcount_dec_and_test(&hr_qp->refcount))
complete(&hr_qp->free);
}
@@ -75,10 +75,25 @@ void init_flush_work(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
flush_work->hr_dev = hr_dev;
INIT_WORK(&flush_work->work, flush_work_handle);
- atomic_inc(&hr_qp->refcount);
+ refcount_inc(&hr_qp->refcount);
queue_work(hr_dev->irq_workq, &flush_work->work);
}
+void flush_cqe(struct hns_roce_dev *dev, struct hns_roce_qp *qp)
+{
+ /*
+ * Hip08 hardware cannot flush the WQEs in SQ/RQ if the QP state
+ * gets into errored mode. Hence, as a workaround to this
+ * hardware limitation, driver needs to assist in flushing. But
+ * the flushing operation uses mailbox to convey the QP state to
+ * the hardware and which can sleep due to the mutex protection
+ * around the mailbox calls. Hence, use the deferred flush for
+ * now.
+ */
+ if (!test_and_set_bit(HNS_ROCE_FLUSH_FLAG, &qp->flush_flag))
+ init_flush_work(dev, qp);
+}
+
void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type)
{
struct device *dev = hr_dev->dev;
@@ -87,7 +102,7 @@ void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type)
xa_lock(&hr_dev->qp_table_xa);
qp = __hns_roce_qp_lookup(hr_dev, qpn);
if (qp)
- atomic_inc(&qp->refcount);
+ refcount_inc(&qp->refcount);
xa_unlock(&hr_dev->qp_table_xa);
if (!qp) {
@@ -102,13 +117,13 @@ void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type)
event_type == HNS_ROCE_EVENT_TYPE_XRCD_VIOLATION ||
event_type == HNS_ROCE_EVENT_TYPE_INVALID_XRCETH)) {
qp->state = IB_QPS_ERR;
- if (!test_and_set_bit(HNS_ROCE_FLUSH_FLAG, &qp->flush_flag))
- init_flush_work(hr_dev, qp);
+
+ flush_cqe(hr_dev, qp);
}
qp->event(qp, (enum hns_roce_event)event_type);
- if (atomic_dec_and_test(&qp->refcount))
+ if (refcount_dec_and_test(&qp->refcount))
complete(&qp->free);
}
@@ -379,7 +394,7 @@ void hns_roce_qp_remove(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
list_del(&hr_qp->rq_node);
xa_lock_irqsave(xa, flags);
- __xa_erase(xa, hr_qp->qpn & (hr_dev->caps.num_qps - 1));
+ __xa_erase(xa, hr_qp->qpn);
xa_unlock_irqrestore(xa, flags);
}
@@ -648,9 +663,7 @@ static int set_kernel_sq_size(struct hns_roce_dev *hr_dev,
if (!cap->max_send_wr || cap->max_send_wr > hr_dev->caps.max_wqes ||
cap->max_send_sge > hr_dev->caps.max_sq_sg) {
- ibdev_err(ibdev,
- "failed to check SQ WR or SGE num, ret = %d.\n",
- -EINVAL);
+ ibdev_err(ibdev, "failed to check SQ WR or SGE num.\n");
return -EINVAL;
}
@@ -761,7 +774,7 @@ static int alloc_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
goto err_inline;
}
ret = hns_roce_mtr_create(hr_dev, &hr_qp->mtr, &buf_attr,
- HNS_HW_PAGE_SHIFT + hr_dev->caps.mtt_ba_pg_sz,
+ PAGE_SHIFT + hr_dev->caps.mtt_ba_pg_sz,
udata, addr);
if (ret) {
ibdev_err(ibdev, "failed to create WQE mtr, ret = %d.\n", ret);
@@ -826,7 +839,7 @@ static int alloc_qp_db(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
if (udata) {
if (user_qp_has_sdb(hr_dev, init_attr, udata, resp, ucmd)) {
- ret = hns_roce_db_map_user(uctx, udata, ucmd->sdb_addr,
+ ret = hns_roce_db_map_user(uctx, ucmd->sdb_addr,
&hr_qp->sdb);
if (ret) {
ibdev_err(ibdev,
@@ -839,7 +852,7 @@ static int alloc_qp_db(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
}
if (user_qp_has_rdb(hr_dev, init_attr, udata, resp)) {
- ret = hns_roce_db_map_user(uctx, udata, ucmd->db_addr,
+ ret = hns_roce_db_map_user(uctx, ucmd->db_addr,
&hr_qp->rdb);
if (ret) {
ibdev_err(ibdev,
@@ -1076,7 +1089,7 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
hr_qp->ibqp.qp_num = hr_qp->qpn;
hr_qp->event = hns_roce_ib_qp_event;
- atomic_set(&hr_qp->refcount, 1);
+ refcount_set(&hr_qp->refcount, 1);
init_completion(&hr_qp->free);
return 0;
@@ -1099,7 +1112,7 @@ err_buf:
void hns_roce_qp_destroy(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
struct ib_udata *udata)
{
- if (atomic_dec_and_test(&hr_qp->refcount))
+ if (refcount_dec_and_test(&hr_qp->refcount))
complete(&hr_qp->free);
wait_for_completion(&hr_qp->free);
@@ -1416,7 +1429,7 @@ bool hns_roce_wq_overflow(struct hns_roce_wq *hr_wq, u32 nreq,
return cur + nreq >= hr_wq->wqe_cnt;
}
-int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev)
+void hns_roce_init_qp_table(struct hns_roce_dev *hr_dev)
{
struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
unsigned int reserved_from_bot;
@@ -1439,8 +1452,6 @@ int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev)
HNS_ROCE_QP_BANK_NUM - 1;
hr_dev->qp_table.bank[i].next = hr_dev->qp_table.bank[i].min;
}
-
- return 0;
}
void hns_roce_cleanup_qp_table(struct hns_roce_dev *hr_dev)
diff --git a/drivers/infiniband/hw/hns/hns_roce_srq.c b/drivers/infiniband/hw/hns/hns_roce_srq.c
index 546d182c577a..6f2992f443fa 100644
--- a/drivers/infiniband/hw/hns/hns_roce_srq.c
+++ b/drivers/infiniband/hw/hns/hns_roce_srq.c
@@ -17,7 +17,7 @@ void hns_roce_srq_event(struct hns_roce_dev *hr_dev, u32 srqn, int event_type)
xa_lock(&srq_table->xa);
srq = xa_load(&srq_table->xa, srqn & (hr_dev->caps.num_srqs - 1));
if (srq)
- atomic_inc(&srq->refcount);
+ refcount_inc(&srq->refcount);
xa_unlock(&srq_table->xa);
if (!srq) {
@@ -27,7 +27,7 @@ void hns_roce_srq_event(struct hns_roce_dev *hr_dev, u32 srqn, int event_type)
srq->event(srq, event_type);
- if (atomic_dec_and_test(&srq->refcount))
+ if (refcount_dec_and_test(&srq->refcount))
complete(&srq->free);
}
@@ -132,7 +132,7 @@ err_xa:
err_put:
hns_roce_table_put(hr_dev, &srq_table->table, srq->srqn);
err_out:
- hns_roce_bitmap_free(&srq_table->bitmap, srq->srqn, BITMAP_NO_RR);
+ hns_roce_bitmap_free(&srq_table->bitmap, srq->srqn);
return ret;
}
@@ -149,12 +149,12 @@ static void free_srqc(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq)
xa_erase(&srq_table->xa, srq->srqn);
- if (atomic_dec_and_test(&srq->refcount))
+ if (refcount_dec_and_test(&srq->refcount))
complete(&srq->free);
wait_for_completion(&srq->free);
hns_roce_table_put(hr_dev, &srq_table->table, srq->srqn);
- hns_roce_bitmap_free(&srq_table->bitmap, srq->srqn, BITMAP_NO_RR);
+ hns_roce_bitmap_free(&srq_table->bitmap, srq->srqn);
}
static int alloc_srq_idx(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq,
@@ -167,14 +167,14 @@ static int alloc_srq_idx(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq,
srq->idx_que.entry_shift = ilog2(HNS_ROCE_IDX_QUE_ENTRY_SZ);
- buf_attr.page_shift = hr_dev->caps.idx_buf_pg_sz + HNS_HW_PAGE_SHIFT;
+ buf_attr.page_shift = hr_dev->caps.idx_buf_pg_sz + PAGE_SHIFT;
buf_attr.region[0].size = to_hr_hem_entries_size(srq->wqe_cnt,
srq->idx_que.entry_shift);
buf_attr.region[0].hopnum = hr_dev->caps.idx_hop_num;
buf_attr.region_count = 1;
ret = hns_roce_mtr_create(hr_dev, &idx_que->mtr, &buf_attr,
- hr_dev->caps.idx_ba_pg_sz + HNS_HW_PAGE_SHIFT,
+ hr_dev->caps.idx_ba_pg_sz + PAGE_SHIFT,
udata, addr);
if (ret) {
ibdev_err(ibdev,
@@ -222,15 +222,15 @@ static int alloc_srq_wqe_buf(struct hns_roce_dev *hr_dev,
HNS_ROCE_SGE_SIZE *
srq->max_gs)));
- buf_attr.page_shift = hr_dev->caps.srqwqe_buf_pg_sz + HNS_HW_PAGE_SHIFT;
+ buf_attr.page_shift = hr_dev->caps.srqwqe_buf_pg_sz + PAGE_SHIFT;
buf_attr.region[0].size = to_hr_hem_entries_size(srq->wqe_cnt,
srq->wqe_shift);
buf_attr.region[0].hopnum = hr_dev->caps.srqwqe_hop_num;
buf_attr.region_count = 1;
ret = hns_roce_mtr_create(hr_dev, &srq->buf_mtr, &buf_attr,
- hr_dev->caps.srqwqe_ba_pg_sz +
- HNS_HW_PAGE_SHIFT, udata, addr);
+ hr_dev->caps.srqwqe_ba_pg_sz + PAGE_SHIFT,
+ udata, addr);
if (ret)
ibdev_err(ibdev,
"failed to alloc SRQ buf mtr, ret = %d.\n", ret);
@@ -417,7 +417,7 @@ int hns_roce_create_srq(struct ib_srq *ib_srq,
srq->db_reg = hr_dev->reg_base + SRQ_DB_REG;
srq->event = hns_roce_ib_srq_event;
- atomic_set(&srq->refcount, 1);
+ refcount_set(&srq->refcount, 1);
init_completion(&srq->free);
return 0;
diff --git a/drivers/infiniband/hw/i40iw/Kconfig b/drivers/infiniband/hw/i40iw/Kconfig
deleted file mode 100644
index 7476f3b14c39..000000000000
--- a/drivers/infiniband/hw/i40iw/Kconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config INFINIBAND_I40IW
- tristate "Intel(R) Ethernet X722 iWARP Driver"
- depends on INET && I40E
- depends on IPV6 || !IPV6
- depends on PCI
- select GENERIC_ALLOCATOR
- help
- Intel(R) Ethernet X722 iWARP Driver
diff --git a/drivers/infiniband/hw/i40iw/Makefile b/drivers/infiniband/hw/i40iw/Makefile
deleted file mode 100644
index 34da9eba8a7c..000000000000
--- a/drivers/infiniband/hw/i40iw/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-$(CONFIG_INFINIBAND_I40IW) += i40iw.o
-
-i40iw-objs :=\
- i40iw_cm.o i40iw_ctrl.o \
- i40iw_hmc.o i40iw_hw.o i40iw_main.o \
- i40iw_pble.o i40iw_puda.o i40iw_uk.o i40iw_utils.o \
- i40iw_verbs.o i40iw_virtchnl.o i40iw_vf.o
diff --git a/drivers/infiniband/hw/i40iw/i40iw.h b/drivers/infiniband/hw/i40iw/i40iw.h
deleted file mode 100644
index be4094ac4fac..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw.h
+++ /dev/null
@@ -1,602 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_IW_H
-#define I40IW_IW_H
-#include <linux/netdevice.h>
-#include <linux/inetdevice.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 <linux/io.h>
-#include <linux/crc32c.h>
-#include <linux/net/intel/i40e_client.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 <crypto/hash.h>
-
-#include "i40iw_status.h"
-#include "i40iw_osdep.h"
-#include "i40iw_d.h"
-#include "i40iw_hmc.h"
-
-#include "i40iw_type.h"
-#include "i40iw_p.h"
-#include <rdma/i40iw-abi.h>
-#include "i40iw_pble.h"
-#include "i40iw_verbs.h"
-#include "i40iw_cm.h"
-#include "i40iw_user.h"
-#include "i40iw_puda.h"
-
-#define I40IW_FW_VER_DEFAULT 2
-#define I40IW_HW_VERSION 2
-
-#define I40IW_ARP_ADD 1
-#define I40IW_ARP_DELETE 2
-#define I40IW_ARP_RESOLVE 3
-
-#define I40IW_MACIP_ADD 1
-#define I40IW_MACIP_DELETE 2
-
-#define IW_CCQ_SIZE (I40IW_CQP_SW_SQSIZE_2048 + 1)
-#define IW_CEQ_SIZE 2048
-#define IW_AEQ_SIZE 2048
-
-#define RX_BUF_SIZE (1536 + 8)
-#define IW_REG0_SIZE (4 * 1024)
-#define IW_TX_TIMEOUT (6 * HZ)
-#define IW_FIRST_QPN 1
-#define IW_SW_CONTEXT_ALIGN 1024
-
-#define MAX_DPC_ITERATIONS 128
-
-#define I40IW_EVENT_TIMEOUT 100000
-#define I40IW_VCHNL_EVENT_TIMEOUT 100000
-
-#define I40IW_NO_VLAN 0xffff
-#define I40IW_NO_QSET 0xffff
-
-/* access to mcast filter list */
-#define IW_ADD_MCAST false
-#define IW_DEL_MCAST true
-
-#define I40IW_DRV_OPT_ENABLE_MPA_VER_0 0x00000001
-#define I40IW_DRV_OPT_DISABLE_MPA_CRC 0x00000002
-#define I40IW_DRV_OPT_DISABLE_FIRST_WRITE 0x00000004
-#define I40IW_DRV_OPT_DISABLE_INTF 0x00000008
-#define I40IW_DRV_OPT_ENABLE_MSI 0x00000010
-#define I40IW_DRV_OPT_DUAL_LOGICAL_PORT 0x00000020
-#define I40IW_DRV_OPT_NO_INLINE_DATA 0x00000080
-#define I40IW_DRV_OPT_DISABLE_INT_MOD 0x00000100
-#define I40IW_DRV_OPT_DISABLE_VIRT_WQ 0x00000200
-#define I40IW_DRV_OPT_ENABLE_PAU 0x00000400
-#define I40IW_DRV_OPT_MCAST_LOGPORT_MAP 0x00000800
-
-#define IW_HMC_OBJ_TYPE_NUM ARRAY_SIZE(iw_hmc_obj_types)
-#define IW_CFG_FPM_QP_COUNT 32768
-#define I40IW_MAX_PAGES_PER_FMR 512
-#define I40IW_MIN_PAGES_PER_FMR 1
-#define I40IW_CQP_COMPL_RQ_WQE_FLUSHED 2
-#define I40IW_CQP_COMPL_SQ_WQE_FLUSHED 3
-#define I40IW_CQP_COMPL_RQ_SQ_WQE_FLUSHED 4
-
-struct i40iw_cqp_compl_info {
- u32 op_ret_val;
- u16 maj_err_code;
- u16 min_err_code;
- bool error;
- u8 op_code;
-};
-
-#define i40iw_pr_err(fmt, args ...) pr_err("%s: "fmt, __func__, ## args)
-
-#define i40iw_pr_info(fmt, args ...) pr_info("%s: " fmt, __func__, ## args)
-
-#define i40iw_pr_warn(fmt, args ...) pr_warn("%s: " fmt, __func__, ## args)
-
-struct i40iw_cqp_request {
- struct cqp_commands_info info;
- wait_queue_head_t waitq;
- struct list_head list;
- atomic_t refcount;
- void (*callback_fcn)(struct i40iw_cqp_request*, u32);
- void *param;
- struct i40iw_cqp_compl_info compl_info;
- bool waiting;
- bool request_done;
- bool dynamic;
-};
-
-struct i40iw_cqp {
- struct i40iw_sc_cqp sc_cqp;
- spinlock_t req_lock; /*cqp request list */
- wait_queue_head_t waitq;
- struct i40iw_dma_mem sq;
- struct i40iw_dma_mem host_ctx;
- u64 *scratch_array;
- struct i40iw_cqp_request *cqp_requests;
- struct list_head cqp_avail_reqs;
- struct list_head cqp_pending_reqs;
-};
-
-struct i40iw_device;
-
-struct i40iw_ccq {
- struct i40iw_sc_cq sc_cq;
- spinlock_t lock; /* ccq control */
- wait_queue_head_t waitq;
- struct i40iw_dma_mem mem_cq;
- struct i40iw_dma_mem shadow_area;
-};
-
-struct i40iw_ceq {
- struct i40iw_sc_ceq sc_ceq;
- struct i40iw_dma_mem mem;
- u32 irq;
- u32 msix_idx;
- struct i40iw_device *iwdev;
- struct tasklet_struct dpc_tasklet;
-};
-
-struct i40iw_aeq {
- struct i40iw_sc_aeq sc_aeq;
- struct i40iw_dma_mem mem;
-};
-
-struct i40iw_arp_entry {
- u32 ip_addr[4];
- u8 mac_addr[ETH_ALEN];
-};
-
-enum init_completion_state {
- INVALID_STATE = 0,
- INITIAL_STATE,
- CQP_CREATED,
- HMC_OBJS_CREATED,
- PBLE_CHUNK_MEM,
- CCQ_CREATED,
- AEQ_CREATED,
- CEQ_CREATED,
- ILQ_CREATED,
- IEQ_CREATED,
- IP_ADDR_REGISTERED,
- RDMA_DEV_REGISTERED
-};
-
-struct i40iw_msix_vector {
- u32 idx;
- u32 irq;
- u32 cpu_affinity;
- u32 ceq_id;
- cpumask_t mask;
-};
-
-struct l2params_work {
- struct work_struct work;
- struct i40iw_device *iwdev;
- struct i40iw_l2params l2params;
-};
-
-#define I40IW_MSIX_TABLE_SIZE 65
-
-struct virtchnl_work {
- struct work_struct work;
- union {
- struct i40iw_cqp_request *cqp_request;
- struct i40iw_virtchnl_work_info work_info;
- };
-};
-
-struct i40e_qvlist_info;
-
-struct i40iw_device {
- struct i40iw_ib_device *iwibdev;
- struct net_device *netdev;
- wait_queue_head_t vchnl_waitq;
- struct i40iw_sc_dev sc_dev;
- struct i40iw_sc_vsi vsi;
- struct i40iw_handler *hdl;
- struct i40e_info *ldev;
- struct i40e_client *client;
- struct i40iw_hw hw;
- struct i40iw_cm_core cm_core;
- u8 *mem_resources;
- unsigned long *allocated_qps;
- unsigned long *allocated_cqs;
- unsigned long *allocated_mrs;
- unsigned long *allocated_pds;
- unsigned long *allocated_arps;
- struct i40iw_qp **qp_table;
- bool msix_shared;
- u32 msix_count;
- struct i40iw_msix_vector *iw_msixtbl;
- struct i40e_qvlist_info *iw_qvlist;
-
- struct i40iw_hmc_pble_rsrc *pble_rsrc;
- struct i40iw_arp_entry *arp_table;
- struct i40iw_cqp cqp;
- struct i40iw_ccq ccq;
- u32 ceqs_count;
- struct i40iw_ceq *ceqlist;
- struct i40iw_aeq aeq;
- u32 arp_table_size;
- u32 next_arp_index;
- spinlock_t resource_lock; /* hw resource access */
- spinlock_t qptable_lock;
- u32 vendor_id;
- u32 vendor_part_id;
- u32 of_device_registered;
-
- u32 device_cap_flags;
- unsigned long db_start;
- u8 resource_profile;
- u8 max_rdma_vfs;
- u8 max_enabled_vfs;
- u8 max_sge;
- u8 iw_status;
- u8 send_term_ok;
-
- /* x710 specific */
- struct mutex pbl_mutex;
- struct tasklet_struct dpc_tasklet;
- struct workqueue_struct *virtchnl_wq;
- struct virtchnl_work virtchnl_w[I40IW_MAX_PE_ENABLED_VF_COUNT];
- struct i40iw_dma_mem obj_mem;
- struct i40iw_dma_mem obj_next;
- u8 *hmc_info_mem;
- u32 sd_type;
- struct workqueue_struct *param_wq;
- atomic_t params_busy;
- enum init_completion_state init_state;
- u16 mac_ip_table_idx;
- atomic_t vchnl_msgs;
- u32 max_mr;
- u32 max_qp;
- u32 max_cq;
- u32 max_pd;
- u32 next_qp;
- u32 next_cq;
- u32 next_pd;
- u32 max_mr_size;
- u32 max_qp_wr;
- u32 max_cqe;
- u32 mr_stagmask;
- u32 mpa_version;
- bool dcb;
- bool closing;
- bool reset;
- u32 used_pds;
- u32 used_cqs;
- u32 used_mrs;
- u32 used_qps;
- wait_queue_head_t close_wq;
- atomic64_t use_count;
-};
-
-struct i40iw_ib_device {
- struct ib_device ibdev;
- struct i40iw_device *iwdev;
-};
-
-struct i40iw_handler {
- struct list_head list;
- struct i40e_client *client;
- struct i40iw_device device;
- struct i40e_info ldev;
-};
-
-/**
- * i40iw_fw_major_ver - get firmware major version
- * @dev: iwarp device
- **/
-static inline u64 i40iw_fw_major_ver(struct i40iw_sc_dev *dev)
-{
- return RS_64(dev->feature_info[I40IW_FEATURE_FW_INFO],
- I40IW_FW_VER_MAJOR);
-}
-
-/**
- * i40iw_fw_minor_ver - get firmware minor version
- * @dev: iwarp device
- **/
-static inline u64 i40iw_fw_minor_ver(struct i40iw_sc_dev *dev)
-{
- return RS_64(dev->feature_info[I40IW_FEATURE_FW_INFO],
- I40IW_FW_VER_MINOR);
-}
-
-/**
- * to_iwdev - get device
- * @ibdev: ib device
- **/
-static inline struct i40iw_device *to_iwdev(struct ib_device *ibdev)
-{
- return container_of(ibdev, struct i40iw_ib_device, ibdev)->iwdev;
-}
-
-/**
- * to_ucontext - get user context
- * @ibucontext: ib user context
- **/
-static inline struct i40iw_ucontext *to_ucontext(struct ib_ucontext *ibucontext)
-{
- return container_of(ibucontext, struct i40iw_ucontext, ibucontext);
-}
-
-/**
- * to_iwpd - get protection domain
- * @ibpd: ib pd
- **/
-static inline struct i40iw_pd *to_iwpd(struct ib_pd *ibpd)
-{
- return container_of(ibpd, struct i40iw_pd, ibpd);
-}
-
-/**
- * to_iwmr - get device memory region
- * @ibdev: ib memory region
- **/
-static inline struct i40iw_mr *to_iwmr(struct ib_mr *ibmr)
-{
- return container_of(ibmr, struct i40iw_mr, ibmr);
-}
-
-/**
- * to_iwmw - get device memory window
- * @ibmw: ib memory window
- **/
-static inline struct i40iw_mr *to_iwmw(struct ib_mw *ibmw)
-{
- return container_of(ibmw, struct i40iw_mr, ibmw);
-}
-
-/**
- * to_iwcq - get completion queue
- * @ibcq: ib cqdevice
- **/
-static inline struct i40iw_cq *to_iwcq(struct ib_cq *ibcq)
-{
- return container_of(ibcq, struct i40iw_cq, ibcq);
-}
-
-/**
- * to_iwqp - get device qp
- * @ibqp: ib qp
- **/
-static inline struct i40iw_qp *to_iwqp(struct ib_qp *ibqp)
-{
- return container_of(ibqp, struct i40iw_qp, ibqp);
-}
-
-/* i40iw.c */
-void i40iw_qp_add_ref(struct ib_qp *ibqp);
-void i40iw_qp_rem_ref(struct ib_qp *ibqp);
-struct ib_qp *i40iw_get_qp(struct ib_device *, int);
-
-void i40iw_flush_wqes(struct i40iw_device *iwdev,
- struct i40iw_qp *qp);
-
-void i40iw_manage_arp_cache(struct i40iw_device *iwdev,
- unsigned char *mac_addr,
- u32 *ip_addr,
- bool ipv4,
- u32 action);
-
-int i40iw_manage_apbvt(struct i40iw_device *iwdev,
- u16 accel_local_port,
- bool add_port);
-
-struct i40iw_cqp_request *i40iw_get_cqp_request(struct i40iw_cqp *cqp, bool wait);
-void i40iw_free_cqp_request(struct i40iw_cqp *cqp, struct i40iw_cqp_request *cqp_request);
-void i40iw_put_cqp_request(struct i40iw_cqp *cqp, struct i40iw_cqp_request *cqp_request);
-
-/**
- * i40iw_alloc_resource - allocate a resource
- * @iwdev: device pointer
- * @resource_array: resource bit array:
- * @max_resources: maximum resource number
- * @req_resources_num: Allocated resource number
- * @next: next free id
- **/
-static inline int i40iw_alloc_resource(struct i40iw_device *iwdev,
- unsigned long *resource_array,
- u32 max_resources,
- u32 *req_resource_num,
- u32 *next)
-{
- u32 resource_num;
- unsigned long flags;
-
- spin_lock_irqsave(&iwdev->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) {
- spin_unlock_irqrestore(&iwdev->resource_lock, flags);
- return -EOVERFLOW;
- }
- }
- set_bit(resource_num, resource_array);
- *next = resource_num + 1;
- if (*next == max_resources)
- *next = 0;
- *req_resource_num = resource_num;
- spin_unlock_irqrestore(&iwdev->resource_lock, flags);
-
- return 0;
-}
-
-/**
- * i40iw_is_resource_allocated - detrmine if resource is
- * allocated
- * @iwdev: device pointer
- * @resource_array: resource array for the resource_num
- * @resource_num: resource number to check
- **/
-static inline bool i40iw_is_resource_allocated(struct i40iw_device *iwdev,
- unsigned long *resource_array,
- u32 resource_num)
-{
- bool bit_is_set;
- unsigned long flags;
-
- spin_lock_irqsave(&iwdev->resource_lock, flags);
-
- bit_is_set = test_bit(resource_num, resource_array);
- spin_unlock_irqrestore(&iwdev->resource_lock, flags);
-
- return bit_is_set;
-}
-
-/**
- * i40iw_free_resource - free a resource
- * @iwdev: device pointer
- * @resource_array: resource array for the resource_num
- * @resource_num: resource number to free
- **/
-static inline void i40iw_free_resource(struct i40iw_device *iwdev,
- unsigned long *resource_array,
- u32 resource_num)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&iwdev->resource_lock, flags);
- clear_bit(resource_num, resource_array);
- spin_unlock_irqrestore(&iwdev->resource_lock, flags);
-}
-
-struct i40iw_handler *i40iw_find_netdev(struct net_device *netdev);
-
-/**
- * iw_init_resources -
- */
-u32 i40iw_initialize_hw_resources(struct i40iw_device *iwdev);
-
-int i40iw_register_rdma_device(struct i40iw_device *iwdev);
-void i40iw_port_ibevent(struct i40iw_device *iwdev);
-void i40iw_cm_disconn(struct i40iw_qp *iwqp);
-void i40iw_cm_disconn_worker(void *);
-int mini_cm_recv_pkt(struct i40iw_cm_core *, struct i40iw_device *,
- struct sk_buff *);
-
-enum i40iw_status_code i40iw_handle_cqp_op(struct i40iw_device *iwdev,
- struct i40iw_cqp_request *cqp_request);
-enum i40iw_status_code i40iw_add_mac_addr(struct i40iw_device *iwdev,
- u8 *mac_addr, u8 *mac_index);
-int i40iw_modify_qp(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *);
-void i40iw_cq_wq_destroy(struct i40iw_device *iwdev, struct i40iw_sc_cq *cq);
-
-void i40iw_cleanup_pending_cqp_op(struct i40iw_device *iwdev);
-void i40iw_rem_pdusecount(struct i40iw_pd *iwpd, struct i40iw_device *iwdev);
-void i40iw_add_pdusecount(struct i40iw_pd *iwpd);
-void i40iw_rem_devusecount(struct i40iw_device *iwdev);
-void i40iw_add_devusecount(struct i40iw_device *iwdev);
-void i40iw_hw_modify_qp(struct i40iw_device *iwdev, struct i40iw_qp *iwqp,
- struct i40iw_modify_qp_info *info, bool wait);
-
-void i40iw_qp_suspend_resume(struct i40iw_sc_dev *dev,
- struct i40iw_sc_qp *qp,
- bool suspend);
-enum i40iw_status_code i40iw_manage_qhash(struct i40iw_device *iwdev,
- struct i40iw_cm_info *cminfo,
- enum i40iw_quad_entry_type etype,
- enum i40iw_quad_hash_manage_type mtype,
- void *cmnode,
- bool wait);
-void i40iw_receive_ilq(struct i40iw_sc_vsi *vsi, struct i40iw_puda_buf *rbuf);
-void i40iw_free_sqbuf(struct i40iw_sc_vsi *vsi, void *bufp);
-void i40iw_free_qp_resources(struct i40iw_qp *iwqp);
-
-enum i40iw_status_code i40iw_obj_aligned_mem(struct i40iw_device *iwdev,
- struct i40iw_dma_mem *memptr,
- u32 size, u32 mask);
-
-void i40iw_request_reset(struct i40iw_device *iwdev);
-void i40iw_destroy_rdma_device(struct i40iw_ib_device *iwibdev);
-int i40iw_setup_cm_core(struct i40iw_device *iwdev);
-void i40iw_cleanup_cm_core(struct i40iw_cm_core *cm_core);
-void i40iw_process_ceq(struct i40iw_device *, struct i40iw_ceq *iwceq);
-void i40iw_process_aeq(struct i40iw_device *);
-void i40iw_next_iw_state(struct i40iw_qp *iwqp,
- u8 state, u8 del_hash,
- u8 term, u8 term_len);
-int i40iw_send_syn(struct i40iw_cm_node *cm_node, u32 sendack);
-int i40iw_send_reset(struct i40iw_cm_node *cm_node);
-struct i40iw_cm_node *i40iw_find_node(struct i40iw_cm_core *cm_core,
- u16 rem_port,
- u32 *rem_addr,
- u16 loc_port,
- u32 *loc_addr,
- bool add_refcnt,
- bool accelerated_list);
-
-enum i40iw_status_code i40iw_hw_flush_wqes(struct i40iw_device *iwdev,
- struct i40iw_sc_qp *qp,
- struct i40iw_qp_flush_info *info,
- bool wait);
-
-void i40iw_gen_ae(struct i40iw_device *iwdev,
- struct i40iw_sc_qp *qp,
- struct i40iw_gen_ae_info *info,
- bool wait);
-
-void i40iw_copy_ip_ntohl(u32 *dst, __be32 *src);
-struct ib_mr *i40iw_reg_phys_mr(struct ib_pd *ib_pd,
- u64 addr,
- u64 size,
- int acc,
- u64 *iova_start);
-
-int i40iw_inetaddr_event(struct notifier_block *notifier,
- unsigned long event,
- void *ptr);
-int i40iw_inet6addr_event(struct notifier_block *notifier,
- unsigned long event,
- void *ptr);
-int i40iw_net_event(struct notifier_block *notifier,
- unsigned long event,
- void *ptr);
-int i40iw_netdevice_event(struct notifier_block *notifier,
- unsigned long event,
- void *ptr);
-
-#endif
diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c
deleted file mode 100644
index 2450b7dd51f6..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_cm.c
+++ /dev/null
@@ -1,4419 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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/atomic.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 <net/arp.h>
-#include <net/ndisc.h>
-#include <net/neighbour.h>
-#include <net/route.h>
-#include <net/addrconf.h>
-#include <net/ip6_route.h>
-#include <net/ip_fib.h>
-#include <net/secure_seq.h>
-#include <net/tcp.h>
-#include <asm/checksum.h>
-
-#include "i40iw.h"
-
-static void i40iw_rem_ref_cm_node(struct i40iw_cm_node *);
-static void i40iw_cm_post_event(struct i40iw_cm_event *event);
-static void i40iw_disconnect_worker(struct work_struct *work);
-
-/**
- * i40iw_free_sqbuf - put back puda buffer if refcount = 0
- * @vsi: pointer to vsi structure
- * @bufp: puda buffer to free
- */
-void i40iw_free_sqbuf(struct i40iw_sc_vsi *vsi, void *bufp)
-{
- struct i40iw_puda_buf *buf = (struct i40iw_puda_buf *)bufp;
- struct i40iw_puda_rsrc *ilq = vsi->ilq;
-
- if (!atomic_dec_return(&buf->refcount))
- i40iw_puda_ret_bufpool(ilq, buf);
-}
-
-/**
- * i40iw_derive_hw_ird_setting - Calculate IRD
- *
- * @cm_ird: IRD of connection's node
- *
- * The ird from the connection is rounded to a supported HW
- * setting (2,8,32,64) and then encoded for ird_size field of
- * qp_ctx
- */
-static u8 i40iw_derive_hw_ird_setting(u16 cm_ird)
-{
- u8 encoded_ird_size;
-
- /* ird_size field is encoded in qp_ctx */
- switch (cm_ird ? roundup_pow_of_two(cm_ird) : 0) {
- case I40IW_HW_IRD_SETTING_64:
- encoded_ird_size = 3;
- break;
- case I40IW_HW_IRD_SETTING_32:
- case I40IW_HW_IRD_SETTING_16:
- encoded_ird_size = 2;
- break;
- case I40IW_HW_IRD_SETTING_8:
- case I40IW_HW_IRD_SETTING_4:
- encoded_ird_size = 1;
- break;
- case I40IW_HW_IRD_SETTING_2:
- default:
- encoded_ird_size = 0;
- break;
- }
- return encoded_ird_size;
-}
-
-/**
- * i40iw_record_ird_ord - Record IRD/ORD passed in
- * @cm_node: connection's node
- * @conn_ird: connection IRD
- * @conn_ord: connection ORD
- */
-static void i40iw_record_ird_ord(struct i40iw_cm_node *cm_node, u32 conn_ird,
- u32 conn_ord)
-{
- if (conn_ird > I40IW_MAX_IRD_SIZE)
- conn_ird = I40IW_MAX_IRD_SIZE;
-
- if (conn_ord > I40IW_MAX_ORD_SIZE)
- conn_ord = I40IW_MAX_ORD_SIZE;
- else if (!conn_ord && cm_node->send_rdma0_op == SEND_RDMA_READ_ZERO)
- conn_ord = 1;
-
- cm_node->ird_size = conn_ird;
- cm_node->ord_size = conn_ord;
-}
-
-/**
- * i40iw_copy_ip_ntohl - change network to host ip
- * @dst: host ip
- * @src: big endian
- */
-void i40iw_copy_ip_ntohl(u32 *dst, __be32 *src)
-{
- *dst++ = ntohl(*src++);
- *dst++ = ntohl(*src++);
- *dst++ = ntohl(*src++);
- *dst = ntohl(*src);
-}
-
-/**
- * i40iw_copy_ip_htonl - change host addr to network ip
- * @dst: host ip
- * @src: little endian
- */
-static inline void i40iw_copy_ip_htonl(__be32 *dst, u32 *src)
-{
- *dst++ = htonl(*src++);
- *dst++ = htonl(*src++);
- *dst++ = htonl(*src++);
- *dst = htonl(*src);
-}
-
-/**
- * i40iw_fill_sockaddr4 - get addr info for passive connection
- * @cm_node: connection's node
- * @event: upper layer's cm event
- */
-static inline void i40iw_fill_sockaddr4(struct i40iw_cm_node *cm_node,
- struct iw_cm_event *event)
-{
- struct sockaddr_in *laddr = (struct sockaddr_in *)&event->local_addr;
- struct sockaddr_in *raddr = (struct sockaddr_in *)&event->remote_addr;
-
- laddr->sin_family = AF_INET;
- raddr->sin_family = AF_INET;
-
- laddr->sin_port = htons(cm_node->loc_port);
- raddr->sin_port = htons(cm_node->rem_port);
-
- laddr->sin_addr.s_addr = htonl(cm_node->loc_addr[0]);
- raddr->sin_addr.s_addr = htonl(cm_node->rem_addr[0]);
-}
-
-/**
- * i40iw_fill_sockaddr6 - get ipv6 addr info for passive side
- * @cm_node: connection's node
- * @event: upper layer's cm event
- */
-static inline void i40iw_fill_sockaddr6(struct i40iw_cm_node *cm_node,
- struct iw_cm_event *event)
-{
- struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)&event->local_addr;
- struct sockaddr_in6 *raddr6 = (struct sockaddr_in6 *)&event->remote_addr;
-
- laddr6->sin6_family = AF_INET6;
- raddr6->sin6_family = AF_INET6;
-
- laddr6->sin6_port = htons(cm_node->loc_port);
- raddr6->sin6_port = htons(cm_node->rem_port);
-
- i40iw_copy_ip_htonl(laddr6->sin6_addr.in6_u.u6_addr32,
- cm_node->loc_addr);
- i40iw_copy_ip_htonl(raddr6->sin6_addr.in6_u.u6_addr32,
- cm_node->rem_addr);
-}
-
-/**
- * i40iw_get_addr_info
- * @cm_node: contains ip/tcp info
- * @cm_info: to get a copy of the cm_node ip/tcp info
-*/
-static void i40iw_get_addr_info(struct i40iw_cm_node *cm_node,
- struct i40iw_cm_info *cm_info)
-{
- cm_info->ipv4 = cm_node->ipv4;
- cm_info->vlan_id = cm_node->vlan_id;
- memcpy(cm_info->loc_addr, cm_node->loc_addr, sizeof(cm_info->loc_addr));
- memcpy(cm_info->rem_addr, cm_node->rem_addr, sizeof(cm_info->rem_addr));
- cm_info->loc_port = cm_node->loc_port;
- cm_info->rem_port = cm_node->rem_port;
- cm_info->user_pri = cm_node->user_pri;
-}
-
-/**
- * i40iw_get_cmevent_info - for cm event upcall
- * @cm_node: connection's node
- * @cm_id: upper layers cm struct for the event
- * @event: upper layer's cm event
- */
-static inline void i40iw_get_cmevent_info(struct i40iw_cm_node *cm_node,
- struct iw_cm_id *cm_id,
- struct iw_cm_event *event)
-{
- memcpy(&event->local_addr, &cm_id->m_local_addr,
- sizeof(event->local_addr));
- memcpy(&event->remote_addr, &cm_id->m_remote_addr,
- sizeof(event->remote_addr));
- if (cm_node) {
- event->private_data = (void *)cm_node->pdata_buf;
- event->private_data_len = (u8)cm_node->pdata.size;
- event->ird = cm_node->ird_size;
- event->ord = cm_node->ord_size;
- }
-}
-
-/**
- * i40iw_send_cm_event - upcall cm's event handler
- * @cm_node: connection's node
- * @cm_id: upper layer's cm info struct
- * @type: Event type to indicate
- * @status: status for the event type
- */
-static int i40iw_send_cm_event(struct i40iw_cm_node *cm_node,
- struct iw_cm_id *cm_id,
- enum iw_cm_event_type type,
- int status)
-{
- struct iw_cm_event event;
-
- memset(&event, 0, sizeof(event));
- event.event = type;
- event.status = status;
- switch (type) {
- case IW_CM_EVENT_CONNECT_REQUEST:
- if (cm_node->ipv4)
- i40iw_fill_sockaddr4(cm_node, &event);
- else
- i40iw_fill_sockaddr6(cm_node, &event);
- event.provider_data = (void *)cm_node;
- event.private_data = (void *)cm_node->pdata_buf;
- event.private_data_len = (u8)cm_node->pdata.size;
- event.ird = cm_node->ird_size;
- break;
- case IW_CM_EVENT_CONNECT_REPLY:
- i40iw_get_cmevent_info(cm_node, cm_id, &event);
- break;
- case IW_CM_EVENT_ESTABLISHED:
- event.ird = cm_node->ird_size;
- event.ord = cm_node->ord_size;
- break;
- case IW_CM_EVENT_DISCONNECT:
- break;
- case IW_CM_EVENT_CLOSE:
- break;
- default:
- i40iw_pr_err("event type received type = %d\n", type);
- return -1;
- }
- return cm_id->event_handler(cm_id, &event);
-}
-
-/**
- * i40iw_create_event - create cm event
- * @cm_node: connection's node
- * @type: Event type to generate
- */
-static struct i40iw_cm_event *i40iw_create_event(struct i40iw_cm_node *cm_node,
- enum i40iw_cm_event_type type)
-{
- struct i40iw_cm_event *event;
-
- if (!cm_node->cm_id)
- return NULL;
-
- event = kzalloc(sizeof(*event), GFP_ATOMIC);
-
- if (!event)
- return NULL;
-
- event->type = type;
- event->cm_node = cm_node;
- memcpy(event->cm_info.rem_addr, cm_node->rem_addr, sizeof(event->cm_info.rem_addr));
- memcpy(event->cm_info.loc_addr, cm_node->loc_addr, sizeof(event->cm_info.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;
-
- i40iw_debug(cm_node->dev,
- I40IW_DEBUG_CM,
- "node=%p event=%p type=%u dst=%pI4 src=%pI4\n",
- cm_node,
- event,
- type,
- event->cm_info.loc_addr,
- event->cm_info.rem_addr);
-
- i40iw_cm_post_event(event);
- return event;
-}
-
-/**
- * i40iw_free_retrans_entry - free send entry
- * @cm_node: connection's node
- */
-static void i40iw_free_retrans_entry(struct i40iw_cm_node *cm_node)
-{
- struct i40iw_device *iwdev = cm_node->iwdev;
- struct i40iw_timer_entry *send_entry;
-
- send_entry = cm_node->send_entry;
- if (send_entry) {
- cm_node->send_entry = NULL;
- i40iw_free_sqbuf(&iwdev->vsi, (void *)send_entry->sqbuf);
- kfree(send_entry);
- atomic_dec(&cm_node->ref_count);
- }
-}
-
-/**
- * i40iw_cleanup_retrans_entry - free send entry with lock
- * @cm_node: connection's node
- */
-static void i40iw_cleanup_retrans_entry(struct i40iw_cm_node *cm_node)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
- i40iw_free_retrans_entry(cm_node);
- spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-}
-
-/**
- * i40iw_form_cm_frame - get a free packet and build frame
- * @cm_node: connection's node ionfo to use in frame
- * @options: pointer to options info
- * @hdr: pointer mpa header
- * @pdata: pointer to private data
- * @flags: indicates FIN or ACK
- */
-static struct i40iw_puda_buf *i40iw_form_cm_frame(struct i40iw_cm_node *cm_node,
- struct i40iw_kmem_info *options,
- struct i40iw_kmem_info *hdr,
- struct i40iw_kmem_info *pdata,
- u8 flags)
-{
- struct i40iw_puda_buf *sqbuf;
- struct i40iw_sc_vsi *vsi = &cm_node->iwdev->vsi;
- u8 *buf;
-
- struct tcphdr *tcph;
- struct iphdr *iph;
- struct ipv6hdr *ip6h;
- struct ethhdr *ethh;
- u16 packetsize;
- u16 eth_hlen = ETH_HLEN;
- u32 opts_len = 0;
- u32 pd_len = 0;
- u32 hdr_len = 0;
- u16 vtag;
-
- sqbuf = i40iw_puda_get_bufpool(vsi->ilq);
- if (!sqbuf)
- return NULL;
- buf = sqbuf->mem.va;
-
- if (options)
- opts_len = (u32)options->size;
-
- if (hdr)
- hdr_len = hdr->size;
-
- if (pdata)
- pd_len = pdata->size;
-
- if (cm_node->vlan_id <= VLAN_VID_MASK)
- eth_hlen += 4;
-
- if (cm_node->ipv4)
- packetsize = sizeof(*iph) + sizeof(*tcph);
- else
- packetsize = sizeof(*ip6h) + sizeof(*tcph);
- packetsize += opts_len + hdr_len + pd_len;
-
- memset(buf, 0x00, eth_hlen + packetsize);
-
- sqbuf->totallen = packetsize + eth_hlen;
- sqbuf->maclen = eth_hlen;
- sqbuf->tcphlen = sizeof(*tcph) + opts_len;
- sqbuf->scratch = (void *)cm_node;
-
- ethh = (struct ethhdr *)buf;
- buf += eth_hlen;
-
- if (cm_node->ipv4) {
- sqbuf->ipv4 = true;
-
- iph = (struct iphdr *)buf;
- buf += sizeof(*iph);
- tcph = (struct tcphdr *)buf;
- buf += sizeof(*tcph);
-
- ether_addr_copy(ethh->h_dest, cm_node->rem_mac);
- ether_addr_copy(ethh->h_source, cm_node->loc_mac);
- if (cm_node->vlan_id <= VLAN_VID_MASK) {
- ((struct vlan_ethhdr *)ethh)->h_vlan_proto = htons(ETH_P_8021Q);
- vtag = (cm_node->user_pri << VLAN_PRIO_SHIFT) | cm_node->vlan_id;
- ((struct vlan_ethhdr *)ethh)->h_vlan_TCI = htons(vtag);
-
- ((struct vlan_ethhdr *)ethh)->h_vlan_encapsulated_proto = htons(ETH_P_IP);
- } else {
- ethh->h_proto = htons(ETH_P_IP);
- }
-
- iph->version = IPVERSION;
- iph->ihl = 5; /* 5 * 4Byte words, IP headr len */
- iph->tos = cm_node->tos;
- iph->tot_len = htons(packetsize);
- iph->id = htons(++cm_node->tcp_cntxt.loc_id);
-
- iph->frag_off = htons(0x4000);
- iph->ttl = 0x40;
- iph->protocol = IPPROTO_TCP;
- iph->saddr = htonl(cm_node->loc_addr[0]);
- iph->daddr = htonl(cm_node->rem_addr[0]);
- } else {
- sqbuf->ipv4 = false;
- ip6h = (struct ipv6hdr *)buf;
- buf += sizeof(*ip6h);
- tcph = (struct tcphdr *)buf;
- buf += sizeof(*tcph);
-
- ether_addr_copy(ethh->h_dest, cm_node->rem_mac);
- ether_addr_copy(ethh->h_source, cm_node->loc_mac);
- if (cm_node->vlan_id <= VLAN_VID_MASK) {
- ((struct vlan_ethhdr *)ethh)->h_vlan_proto = htons(ETH_P_8021Q);
- vtag = (cm_node->user_pri << VLAN_PRIO_SHIFT) | cm_node->vlan_id;
- ((struct vlan_ethhdr *)ethh)->h_vlan_TCI = htons(vtag);
- ((struct vlan_ethhdr *)ethh)->h_vlan_encapsulated_proto = htons(ETH_P_IPV6);
- } else {
- ethh->h_proto = htons(ETH_P_IPV6);
- }
- ip6h->version = 6;
- ip6h->priority = cm_node->tos >> 4;
- ip6h->flow_lbl[0] = cm_node->tos << 4;
- ip6h->flow_lbl[1] = 0;
- ip6h->flow_lbl[2] = 0;
- ip6h->payload_len = htons(packetsize - sizeof(*ip6h));
- ip6h->nexthdr = 6;
- ip6h->hop_limit = 128;
- i40iw_copy_ip_htonl(ip6h->saddr.in6_u.u6_addr32,
- cm_node->loc_addr);
- i40iw_copy_ip_htonl(ip6h->daddr.in6_u.u6_addr32,
- 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 += hdr_len + pd_len;
- }
-
- 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) + opts_len + 3) >> 2);
- sqbuf->tcphlen = tcph->doff << 2;
- tcph->window = htons(cm_node->tcp_cntxt.rcv_wnd);
- tcph->urg_ptr = 0;
-
- if (opts_len) {
- memcpy(buf, options->addr, opts_len);
- buf += opts_len;
- }
-
- if (hdr_len) {
- memcpy(buf, hdr->addr, hdr_len);
- buf += hdr_len;
- }
-
- if (pdata && pdata->addr)
- memcpy(buf, pdata->addr, pdata->size);
-
- atomic_set(&sqbuf->refcount, 1);
-
- return sqbuf;
-}
-
-/**
- * i40iw_send_reset - Send RST packet
- * @cm_node: connection's node
- */
-int i40iw_send_reset(struct i40iw_cm_node *cm_node)
-{
- struct i40iw_puda_buf *sqbuf;
- int flags = SET_RST | SET_ACK;
-
- sqbuf = i40iw_form_cm_frame(cm_node, NULL, NULL, NULL, flags);
- if (!sqbuf) {
- i40iw_pr_err("no sqbuf\n");
- return -1;
- }
-
- return i40iw_schedule_cm_timer(cm_node, sqbuf, I40IW_TIMER_TYPE_SEND, 0, 1);
-}
-
-/**
- * i40iw_active_open_err - send event for active side cm error
- * @cm_node: connection's node
- * @reset: Flag to send reset or not
- */
-static void i40iw_active_open_err(struct i40iw_cm_node *cm_node, bool reset)
-{
- i40iw_cleanup_retrans_entry(cm_node);
- cm_node->cm_core->stats_connect_errs++;
- if (reset) {
- i40iw_debug(cm_node->dev,
- I40IW_DEBUG_CM,
- "%s cm_node=%p state=%d\n",
- __func__,
- cm_node,
- cm_node->state);
- atomic_inc(&cm_node->ref_count);
- i40iw_send_reset(cm_node);
- }
-
- cm_node->state = I40IW_CM_STATE_CLOSED;
- i40iw_create_event(cm_node, I40IW_CM_EVENT_ABORTED);
-}
-
-/**
- * i40iw_passive_open_err - handle passive side cm error
- * @cm_node: connection's node
- * @reset: send reset or just free cm_node
- */
-static void i40iw_passive_open_err(struct i40iw_cm_node *cm_node, bool reset)
-{
- i40iw_cleanup_retrans_entry(cm_node);
- cm_node->cm_core->stats_passive_errs++;
- cm_node->state = I40IW_CM_STATE_CLOSED;
- i40iw_debug(cm_node->dev,
- I40IW_DEBUG_CM,
- "%s cm_node=%p state =%d\n",
- __func__,
- cm_node,
- cm_node->state);
- if (reset)
- i40iw_send_reset(cm_node);
- else
- i40iw_rem_ref_cm_node(cm_node);
-}
-
-/**
- * i40iw_event_connect_error - to create connect error event
- * @event: cm information for connect event
- */
-static void i40iw_event_connect_error(struct i40iw_cm_event *event)
-{
- struct i40iw_qp *iwqp;
- struct iw_cm_id *cm_id;
-
- cm_id = event->cm_node->cm_id;
- if (!cm_id)
- return;
-
- iwqp = cm_id->provider_data;
-
- if (!iwqp || !iwqp->iwdev)
- return;
-
- iwqp->cm_id = NULL;
- cm_id->provider_data = NULL;
- i40iw_send_cm_event(event->cm_node, cm_id,
- IW_CM_EVENT_CONNECT_REPLY,
- -ECONNRESET);
- cm_id->rem_ref(cm_id);
- i40iw_rem_ref_cm_node(event->cm_node);
-}
-
-/**
- * i40iw_process_options
- * @cm_node: connection's node
- * @optionsloc: point to start of options
- * @optionsize: size of all options
- * @syn_packet: flag if syn packet
- */
-static int i40iw_process_options(struct i40iw_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:
- i40iw_debug(cm_node->dev,
- I40IW_DEBUG_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;
- 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:
- i40iw_debug(cm_node->dev,
- I40IW_DEBUG_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 = I40IW_CM_DEFAULT_MSS;
- return 0;
-}
-
-/**
- * i40iw_handle_tcp_options -
- * @cm_node: connection's node
- * @tcph: pointer tcp header
- * @optionsize: size of options rcvd
- * @passive: active or passive flag
- */
-static int i40iw_handle_tcp_options(struct i40iw_cm_node *cm_node,
- struct tcphdr *tcph,
- int optionsize,
- int passive)
-{
- u8 *optionsloc = (u8 *)&tcph[1];
-
- if (optionsize) {
- if (i40iw_process_options(cm_node,
- optionsloc,
- optionsize,
- (u32)tcph->syn)) {
- i40iw_debug(cm_node->dev,
- I40IW_DEBUG_CM,
- "%s: Node %p, Sending RESET\n",
- __func__,
- cm_node);
- if (passive)
- i40iw_passive_open_err(cm_node, true);
- else
- i40iw_active_open_err(cm_node, true);
- 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;
-}
-
-/**
- * i40iw_build_mpa_v1 - build a MPA V1 frame
- * @cm_node: connection's node
- * @start_addr: MPA frame start address
- * @mpa_key: to do read0 or write0
- */
-static void i40iw_build_mpa_v1(struct i40iw_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;
- default:
- break;
- }
- mpa_frame->flags = IETF_MPA_FLAGS_CRC;
- mpa_frame->rev = cm_node->mpa_frame_rev;
- mpa_frame->priv_data_len = htons(cm_node->pdata.size);
-}
-
-/**
- * i40iw_build_mpa_v2 - build a MPA V2 frame
- * @cm_node: connection's node
- * @start_addr: buffer start address
- * @mpa_key: to do read0 or write0
- */
-static void i40iw_build_mpa_v2(struct i40iw_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, ctrl_ord;
-
- /* initialize the upper 5 bytes of the frame */
- i40iw_build_mpa_v1(cm_node, start_addr, mpa_key);
- mpa_frame->flags |= IETF_MPA_V2_FLAG;
- 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) ?
- IETF_NO_IRD_ORD : cm_node->ird_size;
- ctrl_ord = (cm_node->ord_size > IETF_NO_IRD_ORD) ?
- IETF_NO_IRD_ORD : cm_node->ord_size;
- }
-
- 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;
- }
- break;
- default:
- break;
- }
- rtr_msg->ctrl_ird = htons(ctrl_ird);
- rtr_msg->ctrl_ord = htons(ctrl_ord);
-}
-
-/**
- * i40iw_cm_build_mpa_frame - build mpa frame for mpa version 1 or version 2
- * @cm_node: connection's node
- * @mpa: mpa: data buffer
- * @mpa_key: to do read0 or write0
- */
-static int i40iw_cm_build_mpa_frame(struct i40iw_cm_node *cm_node,
- struct i40iw_kmem_info *mpa,
- u8 mpa_key)
-{
- int hdr_len = 0;
-
- switch (cm_node->mpa_frame_rev) {
- case IETF_MPA_V1:
- hdr_len = sizeof(struct ietf_mpa_v1);
- i40iw_build_mpa_v1(cm_node, mpa->addr, mpa_key);
- break;
- case IETF_MPA_V2:
- hdr_len = sizeof(struct ietf_mpa_v2);
- i40iw_build_mpa_v2(cm_node, mpa->addr, mpa_key);
- break;
- default:
- break;
- }
-
- return hdr_len;
-}
-
-/**
- * i40iw_send_mpa_request - active node send mpa request to passive node
- * @cm_node: connection's node
- */
-static int i40iw_send_mpa_request(struct i40iw_cm_node *cm_node)
-{
- struct i40iw_puda_buf *sqbuf;
-
- if (!cm_node) {
- i40iw_pr_err("cm_node == NULL\n");
- return -1;
- }
-
- cm_node->mpa_hdr.addr = &cm_node->mpa_frame;
- cm_node->mpa_hdr.size = i40iw_cm_build_mpa_frame(cm_node,
- &cm_node->mpa_hdr,
- MPA_KEY_REQUEST);
- if (!cm_node->mpa_hdr.size) {
- i40iw_pr_err("mpa size = %d\n", cm_node->mpa_hdr.size);
- return -1;
- }
-
- sqbuf = i40iw_form_cm_frame(cm_node,
- NULL,
- &cm_node->mpa_hdr,
- &cm_node->pdata,
- SET_ACK);
- if (!sqbuf) {
- i40iw_pr_err("sq_buf == NULL\n");
- return -1;
- }
- return i40iw_schedule_cm_timer(cm_node, sqbuf, I40IW_TIMER_TYPE_SEND, 1, 0);
-}
-
-/**
- * i40iw_send_mpa_reject -
- * @cm_node: connection's node
- * @pdata: reject data for connection
- * @plen: length of reject data
- */
-static int i40iw_send_mpa_reject(struct i40iw_cm_node *cm_node,
- const void *pdata,
- u8 plen)
-{
- struct i40iw_puda_buf *sqbuf;
- struct i40iw_kmem_info priv_info;
-
- cm_node->mpa_hdr.addr = &cm_node->mpa_frame;
- cm_node->mpa_hdr.size = i40iw_cm_build_mpa_frame(cm_node,
- &cm_node->mpa_hdr,
- MPA_KEY_REPLY);
-
- cm_node->mpa_frame.flags |= IETF_MPA_FLAGS_REJECT;
- priv_info.addr = (void *)pdata;
- priv_info.size = plen;
-
- sqbuf = i40iw_form_cm_frame(cm_node,
- NULL,
- &cm_node->mpa_hdr,
- &priv_info,
- SET_ACK | SET_FIN);
- if (!sqbuf) {
- i40iw_pr_err("no sqbuf\n");
- return -ENOMEM;
- }
- cm_node->state = I40IW_CM_STATE_FIN_WAIT1;
- return i40iw_schedule_cm_timer(cm_node, sqbuf, I40IW_TIMER_TYPE_SEND, 1, 0);
-}
-
-/**
- * i40iw_parse_mpa - process an IETF MPA frame
- * @cm_node: connection's node
- * @buffer: Data pointer
- * @type: to return accept or reject
- * @len: Len of mpa buffer
- */
-static int i40iw_parse_mpa(struct i40iw_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 = I40IW_MPA_REQUEST_ACCEPT;
-
- if (len < sizeof(struct ietf_mpa_v1)) {
- i40iw_pr_err("ietf buffer small (%x)\n", len);
- return -1;
- }
-
- mpa_frame = (struct ietf_mpa_v1 *)buffer;
- mpa_hdr_len = sizeof(struct ietf_mpa_v1);
- priv_data_len = ntohs(mpa_frame->priv_data_len);
-
- if (priv_data_len > IETF_MAX_PRIV_DATA_LEN) {
- i40iw_pr_err("large pri_data %d\n", priv_data_len);
- return -1;
- }
- if (mpa_frame->rev != IETF_MPA_V1 && mpa_frame->rev != IETF_MPA_V2) {
- i40iw_pr_err("unsupported mpa rev = %d\n", mpa_frame->rev);
- return -1;
- }
- if (mpa_frame->rev > cm_node->mpa_frame_rev) {
- i40iw_pr_err("rev %d\n", mpa_frame->rev);
- return -1;
- }
- cm_node->mpa_frame_rev = mpa_frame->rev;
-
- if (cm_node->state != I40IW_CM_STATE_MPAREQ_SENT) {
- if (memcmp(mpa_frame->key, IEFT_MPA_KEY_REQ, IETF_MPA_KEY_SIZE)) {
- i40iw_pr_err("Unexpected MPA Key received\n");
- return -1;
- }
- } else {
- if (memcmp(mpa_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE)) {
- i40iw_pr_err("Unexpected MPA Key received\n");
- return -1;
- }
- }
-
- if (priv_data_len + mpa_hdr_len > len) {
- i40iw_pr_err("ietf buffer len(%x + %x != %x)\n",
- priv_data_len, mpa_hdr_len, len);
- return -1;
- }
- if (len > MAX_CM_BUFFER) {
- i40iw_pr_err("ietf buffer large len = %d\n", len);
- return -1;
- }
-
- switch (mpa_frame->rev) {
- case IETF_MPA_V2:{
- u16 ird_size;
- u16 ord_size;
- u16 ctrl_ord;
- u16 ctrl_ird;
-
- mpa_v2_frame = (struct ietf_mpa_v2 *)buffer;
- mpa_hdr_len += IETF_RTR_MSG_SIZE;
- rtr_msg = &mpa_v2_frame->rtr_msg;
-
- /* parse rtr message */
- ctrl_ord = ntohs(rtr_msg->ctrl_ord);
- ctrl_ird = ntohs(rtr_msg->ctrl_ird);
- ird_size = ctrl_ird & IETF_NO_IRD_ORD;
- ord_size = ctrl_ord & IETF_NO_IRD_ORD;
-
- if (!(ctrl_ird & IETF_PEER_TO_PEER))
- return -1;
-
- if (ird_size == IETF_NO_IRD_ORD || ord_size == IETF_NO_IRD_ORD) {
- cm_node->mpav2_ird_ord = IETF_NO_IRD_ORD;
- goto negotiate_done;
- }
-
- if (cm_node->state != I40IW_CM_STATE_MPAREQ_SENT) {
- /* responder */
- if (!ord_size && (ctrl_ord & IETF_RDMA0_READ))
- cm_node->ird_size = 1;
- if (cm_node->ord_size > ird_size)
- cm_node->ord_size = ird_size;
- } else {
- /* initiator */
- if (!ird_size && (ctrl_ord & IETF_RDMA0_READ))
- return -1;
- if (cm_node->ord_size > ird_size)
- cm_node->ord_size = ird_size;
-
- if (cm_node->ird_size < ord_size)
- /* no resources available */
- return -1;
- }
-
-negotiate_done:
- if (ctrl_ord & IETF_RDMA0_READ)
- cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO;
- else if (ctrl_ord & IETF_RDMA0_WRITE)
- cm_node->send_rdma0_op = SEND_RDMA_WRITE_ZERO;
- else /* Not supported RDMA0 operation */
- return -1;
- i40iw_debug(cm_node->dev, I40IW_DEBUG_CM,
- "MPAV2: Negotiated ORD: %d, IRD: %d\n",
- cm_node->ord_size, cm_node->ird_size);
- break;
- }
- break;
- case IETF_MPA_V1:
- default:
- break;
- }
-
- memcpy(cm_node->pdata_buf, buffer + mpa_hdr_len, priv_data_len);
- cm_node->pdata.size = priv_data_len;
-
- if (mpa_frame->flags & IETF_MPA_FLAGS_REJECT)
- *type = I40IW_MPA_REQUEST_REJECT;
-
- if (mpa_frame->flags & IETF_MPA_FLAGS_MARKERS)
- cm_node->snd_mark_en = true;
-
- return 0;
-}
-
-/**
- * i40iw_schedule_cm_timer
- * @cm_node: connection's node
- * @sqbuf: buffer to send
- * @type: if it is send or close
- * @send_retrans: if rexmits to be done
- * @close_when_complete: is cm_node to be removed
- *
- * note - cm_node needs to be protected before calling this. Encase in:
- * i40iw_rem_ref_cm_node(cm_core, cm_node);
- * i40iw_schedule_cm_timer(...)
- * atomic_inc(&cm_node->ref_count);
- */
-int i40iw_schedule_cm_timer(struct i40iw_cm_node *cm_node,
- struct i40iw_puda_buf *sqbuf,
- enum i40iw_timer_type type,
- int send_retrans,
- int close_when_complete)
-{
- struct i40iw_sc_vsi *vsi = &cm_node->iwdev->vsi;
- struct i40iw_cm_core *cm_core = cm_node->cm_core;
- struct i40iw_timer_entry *new_send;
- int ret = 0;
- u32 was_timer_set;
- unsigned long flags;
-
- new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
- if (!new_send) {
- if (type != I40IW_TIMER_TYPE_CLOSE)
- i40iw_free_sqbuf(vsi, (void *)sqbuf);
- return -ENOMEM;
- }
- new_send->retrycount = I40IW_DEFAULT_RETRYS;
- new_send->retranscount = I40IW_DEFAULT_RETRANS;
- new_send->sqbuf = sqbuf;
- new_send->timetosend = jiffies;
- new_send->type = type;
- new_send->send_retrans = send_retrans;
- new_send->close_when_complete = close_when_complete;
-
- if (type == I40IW_TIMER_TYPE_CLOSE) {
- new_send->timetosend += (HZ / 10);
- if (cm_node->close_entry) {
- kfree(new_send);
- i40iw_pr_err("already close entry\n");
- return -EINVAL;
- }
- cm_node->close_entry = new_send;
- }
-
- if (type == I40IW_TIMER_TYPE_SEND) {
- spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
- cm_node->send_entry = new_send;
- atomic_inc(&cm_node->ref_count);
- spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
- new_send->timetosend = jiffies + I40IW_RETRY_TIMEOUT;
-
- atomic_inc(&sqbuf->refcount);
- i40iw_puda_send_buf(vsi->ilq, sqbuf);
- if (!send_retrans) {
- i40iw_cleanup_retrans_entry(cm_node);
- if (close_when_complete)
- i40iw_rem_ref_cm_node(cm_node);
- return ret;
- }
- }
-
- spin_lock_irqsave(&cm_core->ht_lock, flags);
- was_timer_set = timer_pending(&cm_core->tcp_timer);
-
- if (!was_timer_set) {
- cm_core->tcp_timer.expires = new_send->timetosend;
- add_timer(&cm_core->tcp_timer);
- }
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
-
- return ret;
-}
-
-/**
- * i40iw_retrans_expired - Could not rexmit the packet
- * @cm_node: connection's node
- */
-static void i40iw_retrans_expired(struct i40iw_cm_node *cm_node)
-{
- struct iw_cm_id *cm_id = cm_node->cm_id;
- enum i40iw_cm_node_state state = cm_node->state;
-
- cm_node->state = I40IW_CM_STATE_CLOSED;
- switch (state) {
- case I40IW_CM_STATE_SYN_RCVD:
- case I40IW_CM_STATE_CLOSING:
- i40iw_rem_ref_cm_node(cm_node);
- break;
- case I40IW_CM_STATE_FIN_WAIT1:
- case I40IW_CM_STATE_LAST_ACK:
- if (cm_node->cm_id)
- cm_id->rem_ref(cm_id);
- i40iw_send_reset(cm_node);
- break;
- default:
- atomic_inc(&cm_node->ref_count);
- i40iw_send_reset(cm_node);
- i40iw_create_event(cm_node, I40IW_CM_EVENT_ABORTED);
- break;
- }
-}
-
-/**
- * i40iw_handle_close_entry - for handling retry/timeouts
- * @cm_node: connection's node
- * @rem_node: flag for remove cm_node
- */
-static void i40iw_handle_close_entry(struct i40iw_cm_node *cm_node, u32 rem_node)
-{
- struct i40iw_timer_entry *close_entry = cm_node->close_entry;
- struct iw_cm_id *cm_id = cm_node->cm_id;
- struct i40iw_qp *iwqp;
- unsigned long flags;
-
- if (!close_entry)
- return;
- iwqp = (struct i40iw_qp *)close_entry->sqbuf;
- if (iwqp) {
- spin_lock_irqsave(&iwqp->lock, flags);
- if (iwqp->cm_id) {
- iwqp->hw_tcp_state = I40IW_TCP_STATE_CLOSED;
- iwqp->hw_iwarp_state = I40IW_QP_STATE_ERROR;
- iwqp->last_aeq = I40IW_AE_RESET_SENT;
- iwqp->ibqp_state = IB_QPS_ERR;
- spin_unlock_irqrestore(&iwqp->lock, flags);
- i40iw_cm_disconn(iwqp);
- } else {
- spin_unlock_irqrestore(&iwqp->lock, flags);
- }
- } else if (rem_node) {
- /* TIME_WAIT state */
- i40iw_rem_ref_cm_node(cm_node);
- }
- if (cm_id)
- cm_id->rem_ref(cm_id);
- kfree(close_entry);
- cm_node->close_entry = NULL;
-}
-
-/**
- * i40iw_build_timer_list - Add cm_nodes to timer list
- * @timer_list: ptr to timer list
- * @hte: ptr to accelerated or non-accelerated list
- */
-static void i40iw_build_timer_list(struct list_head *timer_list,
- struct list_head *hte)
-{
- struct i40iw_cm_node *cm_node;
- struct list_head *list_core_temp, *list_node;
-
- list_for_each_safe(list_node, list_core_temp, hte) {
- cm_node = container_of(list_node, struct i40iw_cm_node, list);
- if (cm_node->close_entry || cm_node->send_entry) {
- atomic_inc(&cm_node->ref_count);
- list_add(&cm_node->timer_entry, timer_list);
- }
- }
-}
-
-/**
- * i40iw_cm_timer_tick - system's timer expired callback
- * @t: Timer instance to fetch the cm_core pointer from
- */
-static void i40iw_cm_timer_tick(struct timer_list *t)
-{
- unsigned long nexttimeout = jiffies + I40IW_LONG_TIME;
- struct i40iw_cm_node *cm_node;
- struct i40iw_timer_entry *send_entry, *close_entry;
- struct list_head *list_core_temp;
- struct i40iw_sc_vsi *vsi;
- struct list_head *list_node;
- struct i40iw_cm_core *cm_core = from_timer(cm_core, t, tcp_timer);
- u32 settimer = 0;
- unsigned long timetosend;
- unsigned long flags;
-
- struct list_head timer_list;
-
- INIT_LIST_HEAD(&timer_list);
-
- spin_lock_irqsave(&cm_core->ht_lock, flags);
- i40iw_build_timer_list(&timer_list, &cm_core->non_accelerated_list);
- i40iw_build_timer_list(&timer_list, &cm_core->accelerated_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 i40iw_cm_node,
- timer_entry);
- close_entry = cm_node->close_entry;
-
- if (close_entry) {
- if (time_after(close_entry->timetosend, jiffies)) {
- if (nexttimeout > close_entry->timetosend ||
- !settimer) {
- nexttimeout = close_entry->timetosend;
- settimer = 1;
- }
- } else {
- i40iw_handle_close_entry(cm_node, 1);
- }
- }
-
- spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-
- send_entry = cm_node->send_entry;
- if (!send_entry)
- goto done;
- if (time_after(send_entry->timetosend, jiffies)) {
- if (cm_node->state != I40IW_CM_STATE_OFFLOADED) {
- if ((nexttimeout > send_entry->timetosend) ||
- !settimer) {
- nexttimeout = send_entry->timetosend;
- settimer = 1;
- }
- } else {
- i40iw_free_retrans_entry(cm_node);
- }
- goto done;
- }
-
- if ((cm_node->state == I40IW_CM_STATE_OFFLOADED) ||
- (cm_node->state == I40IW_CM_STATE_CLOSED)) {
- i40iw_free_retrans_entry(cm_node);
- goto done;
- }
-
- if (!send_entry->retranscount || !send_entry->retrycount) {
- i40iw_free_retrans_entry(cm_node);
-
- spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
- i40iw_retrans_expired(cm_node);
- cm_node->state = I40IW_CM_STATE_CLOSED;
- spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
- goto done;
- }
- spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-
- vsi = &cm_node->iwdev->vsi;
-
- if (!cm_node->ack_rcvd) {
- atomic_inc(&send_entry->sqbuf->refcount);
- i40iw_puda_send_buf(vsi->ilq, send_entry->sqbuf);
- cm_node->cm_core->stats_pkt_retrans++;
- }
- spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
- if (send_entry->send_retrans) {
- send_entry->retranscount--;
- timetosend = (I40IW_RETRY_TIMEOUT <<
- (I40IW_DEFAULT_RETRANS -
- send_entry->retranscount));
-
- send_entry->timetosend = jiffies +
- min(timetosend, I40IW_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;
- i40iw_debug(cm_node->dev,
- I40IW_DEBUG_CM,
- "cm_node=%p state=%d\n",
- cm_node,
- cm_node->state);
- i40iw_free_retrans_entry(cm_node);
- if (close_when_complete)
- i40iw_rem_ref_cm_node(cm_node);
- }
-done:
- spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
- i40iw_rem_ref_cm_node(cm_node);
- }
-
- if (settimer) {
- spin_lock_irqsave(&cm_core->ht_lock, flags);
- if (!timer_pending(&cm_core->tcp_timer)) {
- cm_core->tcp_timer.expires = nexttimeout;
- add_timer(&cm_core->tcp_timer);
- }
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
- }
-}
-
-/**
- * i40iw_send_syn - send SYN packet
- * @cm_node: connection's node
- * @sendack: flag to set ACK bit or not
- */
-int i40iw_send_syn(struct i40iw_cm_node *cm_node, u32 sendack)
-{
- struct i40iw_puda_buf *sqbuf;
- int flags = SET_SYN;
- char optionsbuffer[sizeof(struct option_mss) +
- sizeof(struct option_windowscale) +
- sizeof(struct option_base) + TCP_OPTIONS_PADDING];
- struct i40iw_kmem_info opts;
-
- int optionssize = 0;
- /* Sending MSS option */
- union all_known_options *options;
-
- opts.addr = optionsbuffer;
- if (!cm_node) {
- i40iw_pr_err("no cm_node\n");
- 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);
- options = (union all_known_options *)&optionsbuffer[optionssize];
- options->as_end = OPTION_NUMBER_END;
- optionssize += 1;
-
- if (sendack)
- flags |= SET_ACK;
-
- opts.size = optionssize;
-
- sqbuf = i40iw_form_cm_frame(cm_node, &opts, NULL, NULL, flags);
- if (!sqbuf) {
- i40iw_pr_err("no sqbuf\n");
- return -1;
- }
- return i40iw_schedule_cm_timer(cm_node, sqbuf, I40IW_TIMER_TYPE_SEND, 1, 0);
-}
-
-/**
- * i40iw_send_ack - Send ACK packet
- * @cm_node: connection's node
- */
-static void i40iw_send_ack(struct i40iw_cm_node *cm_node)
-{
- struct i40iw_puda_buf *sqbuf;
- struct i40iw_sc_vsi *vsi = &cm_node->iwdev->vsi;
-
- sqbuf = i40iw_form_cm_frame(cm_node, NULL, NULL, NULL, SET_ACK);
- if (sqbuf)
- i40iw_puda_send_buf(vsi->ilq, sqbuf);
- else
- i40iw_pr_err("no sqbuf\n");
-}
-
-/**
- * i40iw_send_fin - Send FIN pkt
- * @cm_node: connection's node
- */
-static int i40iw_send_fin(struct i40iw_cm_node *cm_node)
-{
- struct i40iw_puda_buf *sqbuf;
-
- sqbuf = i40iw_form_cm_frame(cm_node, NULL, NULL, NULL, SET_ACK | SET_FIN);
- if (!sqbuf) {
- i40iw_pr_err("no sqbuf\n");
- return -1;
- }
- return i40iw_schedule_cm_timer(cm_node, sqbuf, I40IW_TIMER_TYPE_SEND, 1, 0);
-}
-
-/**
- * i40iw_find_node - find a cm node that matches the reference cm node
- * @cm_core: cm's core
- * @rem_port: remote tcp port num
- * @rem_addr: remote ip addr
- * @loc_port: local tcp port num
- * @loc_addr: loc ip addr
- * @add_refcnt: flag to increment refcount of cm_node
- * @accelerated_list: flag for accelerated vs non-accelerated list to search
- */
-struct i40iw_cm_node *i40iw_find_node(struct i40iw_cm_core *cm_core,
- u16 rem_port,
- u32 *rem_addr,
- u16 loc_port,
- u32 *loc_addr,
- bool add_refcnt,
- bool accelerated_list)
-{
- struct list_head *hte;
- struct i40iw_cm_node *cm_node;
- unsigned long flags;
-
- hte = accelerated_list ?
- &cm_core->accelerated_list : &cm_core->non_accelerated_list;
-
- /* 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) {
- if (!memcmp(cm_node->loc_addr, loc_addr, sizeof(cm_node->loc_addr)) &&
- (cm_node->loc_port == loc_port) &&
- !memcmp(cm_node->rem_addr, rem_addr, sizeof(cm_node->rem_addr)) &&
- (cm_node->rem_port == rem_port)) {
- if (add_refcnt)
- atomic_inc(&cm_node->ref_count);
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
- return cm_node;
- }
- }
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
-
- /* no owner node */
- return NULL;
-}
-
-/**
- * i40iw_find_listener - find a cm node listening on this addr-port pair
- * @cm_core: cm's core
- * @dst_port: listener tcp port num
- * @dst_addr: listener ip addr
- * @vlan_id: vlan id for the given address
- * @listener_state: state to match with listen node's
- */
-static struct i40iw_cm_listener *i40iw_find_listener(
- struct i40iw_cm_core *cm_core,
- u32 *dst_addr,
- u16 dst_port,
- u16 vlan_id,
- enum i40iw_cm_listener_state
- listener_state)
-{
- struct i40iw_cm_listener *listen_node;
- static const u32 ip_zero[4] = { 0, 0, 0, 0 };
- u32 listen_addr[4];
- u16 listen_port;
- unsigned long flags;
-
- /* 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_nodes, list) {
- memcpy(listen_addr, listen_node->loc_addr, sizeof(listen_addr));
- listen_port = listen_node->loc_port;
- /* compare node pair, return node handle if a match */
- if ((!memcmp(listen_addr, dst_addr, sizeof(listen_addr)) ||
- !memcmp(listen_addr, ip_zero, sizeof(listen_addr))) &&
- (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);
- return NULL;
-}
-
-/**
- * i40iw_add_hte_node - add a cm node to the hash table
- * @cm_core: cm's core
- * @cm_node: connection's node
- */
-static void i40iw_add_hte_node(struct i40iw_cm_core *cm_core,
- struct i40iw_cm_node *cm_node)
-{
- unsigned long flags;
-
- if (!cm_node || !cm_core) {
- i40iw_pr_err("cm_node or cm_core == NULL\n");
- return;
- }
-
- spin_lock_irqsave(&cm_core->ht_lock, flags);
- list_add_tail(&cm_node->list, &cm_core->non_accelerated_list);
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
-}
-
-/**
- * i40iw_find_port - find port that matches reference port
- * @hte: ptr to accelerated or non-accelerated list
- * @port: port number to locate
- */
-static bool i40iw_find_port(struct list_head *hte, u16 port)
-{
- struct i40iw_cm_node *cm_node;
-
- list_for_each_entry(cm_node, hte, list) {
- if (cm_node->loc_port == port)
- return true;
- }
- return false;
-}
-
-/**
- * i40iw_port_in_use - determine if port is in use
- * @cm_core: cm's core
- * @port: port number
- */
-bool i40iw_port_in_use(struct i40iw_cm_core *cm_core, u16 port)
-{
- struct i40iw_cm_listener *listen_node;
- unsigned long flags;
-
- spin_lock_irqsave(&cm_core->ht_lock, flags);
- if (i40iw_find_port(&cm_core->accelerated_list, port) ||
- i40iw_find_port(&cm_core->non_accelerated_list, port)) {
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
- return true;
- }
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
-
- spin_lock_irqsave(&cm_core->listen_list_lock, flags);
- list_for_each_entry(listen_node, &cm_core->listen_nodes, list) {
- if (listen_node->loc_port == port) {
- spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
- return true;
- }
- }
- spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
-
- return false;
-}
-
-/**
- * i40iw_del_multiple_qhash - Remove qhash and child listens
- * @iwdev: iWarp device
- * @cm_info: CM info for parent listen node
- * @cm_parent_listen_node: The parent listen node
- */
-static enum i40iw_status_code i40iw_del_multiple_qhash(
- struct i40iw_device *iwdev,
- struct i40iw_cm_info *cm_info,
- struct i40iw_cm_listener *cm_parent_listen_node)
-{
- struct i40iw_cm_listener *child_listen_node;
- enum i40iw_status_code ret = I40IW_ERR_CONFIG;
- struct list_head *pos, *tpos;
- unsigned long flags;
-
- spin_lock_irqsave(&iwdev->cm_core.listen_list_lock, flags);
- list_for_each_safe(pos, tpos, &cm_parent_listen_node->child_listen_list) {
- child_listen_node = list_entry(pos, struct i40iw_cm_listener, child_listen_list);
- if (child_listen_node->ipv4)
- i40iw_debug(&iwdev->sc_dev,
- I40IW_DEBUG_CM,
- "removing child listen for IP=%pI4, port=%d, vlan=%d\n",
- child_listen_node->loc_addr,
- child_listen_node->loc_port,
- child_listen_node->vlan_id);
- else
- i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_CM,
- "removing child listen for IP=%pI6, port=%d, vlan=%d\n",
- child_listen_node->loc_addr,
- child_listen_node->loc_port,
- child_listen_node->vlan_id);
- list_del(pos);
- memcpy(cm_info->loc_addr, child_listen_node->loc_addr,
- sizeof(cm_info->loc_addr));
- cm_info->vlan_id = child_listen_node->vlan_id;
- if (child_listen_node->qhash_set) {
- ret = i40iw_manage_qhash(iwdev, cm_info,
- I40IW_QHASH_TYPE_TCP_SYN,
- I40IW_QHASH_MANAGE_TYPE_DELETE,
- NULL, false);
- child_listen_node->qhash_set = false;
- } else {
- ret = I40IW_SUCCESS;
- }
- i40iw_debug(&iwdev->sc_dev,
- I40IW_DEBUG_CM,
- "freed pointer = %p\n",
- child_listen_node);
- kfree(child_listen_node);
- cm_parent_listen_node->cm_core->stats_listen_nodes_destroyed++;
- }
- spin_unlock_irqrestore(&iwdev->cm_core.listen_list_lock, flags);
-
- return ret;
-}
-
-/**
- * i40iw_netdev_vlan_ipv6 - Gets the netdev and vlan
- * @addr: local IPv6 address
- * @vlan_id: vlan id for the given IPv6 address
- *
- * Returns the net_device of the IPv6 address and also sets the
- * vlan id for that address.
- */
-static struct net_device *i40iw_netdev_vlan_ipv6(u32 *addr, u16 *vlan_id)
-{
- struct net_device *ip_dev = NULL;
- struct in6_addr laddr6;
-
- if (!IS_ENABLED(CONFIG_IPV6))
- return NULL;
- i40iw_copy_ip_htonl(laddr6.in6_u.u6_addr32, addr);
- if (vlan_id)
- *vlan_id = I40IW_NO_VLAN;
- rcu_read_lock();
- for_each_netdev_rcu(&init_net, ip_dev) {
- if (ipv6_chk_addr(&init_net, &laddr6, ip_dev, 1)) {
- if (vlan_id)
- *vlan_id = rdma_vlan_dev_vlan_id(ip_dev);
- break;
- }
- }
- rcu_read_unlock();
- return ip_dev;
-}
-
-/**
- * i40iw_get_vlan_ipv4 - Returns the vlan_id for IPv4 address
- * @addr: local IPv4 address
- */
-static u16 i40iw_get_vlan_ipv4(u32 *addr)
-{
- struct net_device *netdev;
- u16 vlan_id = I40IW_NO_VLAN;
-
- netdev = ip_dev_find(&init_net, htonl(addr[0]));
- if (netdev) {
- vlan_id = rdma_vlan_dev_vlan_id(netdev);
- dev_put(netdev);
- }
- return vlan_id;
-}
-
-/**
- * i40iw_add_mqh_6 - Adds multiple qhashes for IPv6
- * @iwdev: iWarp device
- * @cm_info: CM info for parent listen node
- * @cm_parent_listen_node: The parent listen node
- *
- * Adds a qhash and a child listen node for every IPv6 address
- * on the adapter and adds the associated qhash filter
- */
-static enum i40iw_status_code i40iw_add_mqh_6(struct i40iw_device *iwdev,
- struct i40iw_cm_info *cm_info,
- struct i40iw_cm_listener *cm_parent_listen_node)
-{
- struct net_device *ip_dev;
- struct inet6_dev *idev;
- struct inet6_ifaddr *ifp, *tmp;
- enum i40iw_status_code ret = 0;
- struct i40iw_cm_listener *child_listen_node;
- unsigned long flags;
-
- rtnl_lock();
- for_each_netdev(&init_net, ip_dev) {
- if ((((rdma_vlan_dev_vlan_id(ip_dev) < I40IW_NO_VLAN) &&
- (rdma_vlan_dev_real_dev(ip_dev) == iwdev->netdev)) ||
- (ip_dev == iwdev->netdev)) && (ip_dev->flags & IFF_UP)) {
- idev = __in6_dev_get(ip_dev);
- if (!idev) {
- i40iw_pr_err("idev == NULL\n");
- break;
- }
- list_for_each_entry_safe(ifp, tmp, &idev->addr_list, if_list) {
- i40iw_debug(&iwdev->sc_dev,
- I40IW_DEBUG_CM,
- "IP=%pI6, vlan_id=%d, MAC=%pM\n",
- &ifp->addr,
- rdma_vlan_dev_vlan_id(ip_dev),
- ip_dev->dev_addr);
- child_listen_node =
- kzalloc(sizeof(*child_listen_node), GFP_ATOMIC);
- i40iw_debug(&iwdev->sc_dev,
- I40IW_DEBUG_CM,
- "Allocating child listener %p\n",
- child_listen_node);
- if (!child_listen_node) {
- ret = I40IW_ERR_NO_MEMORY;
- goto exit;
- }
- cm_info->vlan_id = rdma_vlan_dev_vlan_id(ip_dev);
- cm_parent_listen_node->vlan_id = cm_info->vlan_id;
-
- memcpy(child_listen_node, cm_parent_listen_node,
- sizeof(*child_listen_node));
-
- i40iw_copy_ip_ntohl(child_listen_node->loc_addr,
- ifp->addr.in6_u.u6_addr32);
- memcpy(cm_info->loc_addr, child_listen_node->loc_addr,
- sizeof(cm_info->loc_addr));
-
- ret = i40iw_manage_qhash(iwdev, cm_info,
- I40IW_QHASH_TYPE_TCP_SYN,
- I40IW_QHASH_MANAGE_TYPE_ADD,
- NULL, true);
- if (!ret) {
- child_listen_node->qhash_set = true;
- spin_lock_irqsave(&iwdev->cm_core.listen_list_lock, flags);
- list_add(&child_listen_node->child_listen_list,
- &cm_parent_listen_node->child_listen_list);
- spin_unlock_irqrestore(&iwdev->cm_core.listen_list_lock, flags);
- cm_parent_listen_node->cm_core->stats_listen_nodes_created++;
- } else {
- kfree(child_listen_node);
- }
- }
- }
- }
-exit:
- rtnl_unlock();
- return ret;
-}
-
-/**
- * i40iw_add_mqh_4 - Adds multiple qhashes for IPv4
- * @iwdev: iWarp device
- * @cm_info: CM info for parent listen node
- * @cm_parent_listen_node: The parent listen node
- *
- * Adds a qhash and a child listen node for every IPv4 address
- * on the adapter and adds the associated qhash filter
- */
-static enum i40iw_status_code i40iw_add_mqh_4(
- struct i40iw_device *iwdev,
- struct i40iw_cm_info *cm_info,
- struct i40iw_cm_listener *cm_parent_listen_node)
-{
- struct net_device *dev;
- struct in_device *idev;
- struct i40iw_cm_listener *child_listen_node;
- enum i40iw_status_code ret = 0;
- unsigned long flags;
-
- rtnl_lock();
- for_each_netdev(&init_net, dev) {
- 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);
-
- 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",
- &ifa->ifa_address,
- rdma_vlan_dev_vlan_id(dev),
- dev->dev_addr);
- child_listen_node = kzalloc(sizeof(*child_listen_node), GFP_KERNEL);
- cm_parent_listen_node->cm_core->stats_listen_nodes_created++;
- i40iw_debug(&iwdev->sc_dev,
- I40IW_DEBUG_CM,
- "Allocating child listener %p\n",
- child_listen_node);
- if (!child_listen_node) {
- in_dev_put(idev);
- ret = I40IW_ERR_NO_MEMORY;
- goto exit;
- }
- cm_info->vlan_id = rdma_vlan_dev_vlan_id(dev);
- cm_parent_listen_node->vlan_id = cm_info->vlan_id;
- memcpy(child_listen_node,
- cm_parent_listen_node,
- sizeof(*child_listen_node));
-
- child_listen_node->loc_addr[0] = ntohl(ifa->ifa_address);
- memcpy(cm_info->loc_addr, child_listen_node->loc_addr,
- sizeof(cm_info->loc_addr));
-
- ret = i40iw_manage_qhash(iwdev,
- cm_info,
- I40IW_QHASH_TYPE_TCP_SYN,
- I40IW_QHASH_MANAGE_TYPE_ADD,
- NULL,
- true);
- if (!ret) {
- child_listen_node->qhash_set = true;
- spin_lock_irqsave(&iwdev->cm_core.listen_list_lock, flags);
- list_add(&child_listen_node->child_listen_list,
- &cm_parent_listen_node->child_listen_list);
- spin_unlock_irqrestore(&iwdev->cm_core.listen_list_lock, flags);
- } else {
- kfree(child_listen_node);
- cm_parent_listen_node->cm_core->stats_listen_nodes_created--;
- }
- }
-
- in_dev_put(idev);
- }
- }
-exit:
- rtnl_unlock();
- return ret;
-}
-
-/**
- * i40iw_dec_refcnt_listen - delete listener and associated cm nodes
- * @cm_core: cm's core
- * @listener: passive connection's listener
- * @free_hanging_nodes: to free associated cm_nodes
- * @apbvt_del: flag to delete the apbvt
- */
-static int i40iw_dec_refcnt_listen(struct i40iw_cm_core *cm_core,
- struct i40iw_cm_listener *listener,
- int free_hanging_nodes, bool apbvt_del)
-{
- int ret = -EINVAL;
- int err = 0;
- struct list_head *list_pos;
- struct list_head *list_temp;
- struct i40iw_cm_node *cm_node;
- struct list_head reset_list;
- struct i40iw_cm_info nfo;
- struct i40iw_cm_node *loopback;
- enum i40iw_cm_node_state old_state;
- unsigned long flags;
-
- /* 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, &cm_core->non_accelerated_list) {
- cm_node = container_of(list_pos, struct i40iw_cm_node, list);
- if ((cm_node->listener == listener) &&
- !cm_node->accelerated) {
- atomic_inc(&cm_node->ref_count);
- 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 i40iw_cm_node, reset_entry);
- loopback = cm_node->loopbackpartner;
- if (cm_node->state >= I40IW_CM_STATE_FIN_WAIT1) {
- i40iw_rem_ref_cm_node(cm_node);
- } else {
- if (!loopback) {
- i40iw_cleanup_retrans_entry(cm_node);
- err = i40iw_send_reset(cm_node);
- if (err) {
- cm_node->state = I40IW_CM_STATE_CLOSED;
- i40iw_pr_err("send reset\n");
- } else {
- old_state = cm_node->state;
- cm_node->state = I40IW_CM_STATE_LISTENER_DESTROYED;
- if (old_state != I40IW_CM_STATE_MPAREQ_RCVD)
- i40iw_rem_ref_cm_node(cm_node);
- }
- } else {
- struct i40iw_cm_event event;
-
- event.cm_node = loopback;
- memcpy(event.cm_info.rem_addr,
- loopback->rem_addr, sizeof(event.cm_info.rem_addr));
- memcpy(event.cm_info.loc_addr,
- loopback->loc_addr, sizeof(event.cm_info.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;
- event.cm_info.ipv4 = loopback->ipv4;
- atomic_inc(&loopback->ref_count);
- loopback->state = I40IW_CM_STATE_CLOSED;
- i40iw_event_connect_error(&event);
- cm_node->state = I40IW_CM_STATE_LISTENER_DESTROYED;
- i40iw_rem_ref_cm_node(cm_node);
- }
- }
- }
-
- if (!atomic_dec_return(&listener->ref_count)) {
- spin_lock_irqsave(&cm_core->listen_list_lock, flags);
- list_del(&listener->list);
- spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
-
- if (listener->iwdev) {
- if (apbvt_del)
- i40iw_manage_apbvt(listener->iwdev,
- listener->loc_port,
- I40IW_MANAGE_APBVT_DEL);
-
- memcpy(nfo.loc_addr, listener->loc_addr, sizeof(nfo.loc_addr));
- nfo.loc_port = listener->loc_port;
- nfo.ipv4 = listener->ipv4;
- nfo.vlan_id = listener->vlan_id;
- nfo.user_pri = listener->user_pri;
-
- if (!list_empty(&listener->child_listen_list)) {
- i40iw_del_multiple_qhash(listener->iwdev, &nfo, listener);
- } else {
- if (listener->qhash_set)
- i40iw_manage_qhash(listener->iwdev,
- &nfo,
- I40IW_QHASH_TYPE_TCP_SYN,
- I40IW_QHASH_MANAGE_TYPE_DELETE,
- NULL,
- false);
- }
- }
-
- cm_core->stats_listen_destroyed++;
- kfree(listener);
- cm_core->stats_listen_nodes_destroyed++;
- listener = NULL;
- ret = 0;
- }
-
- if (listener) {
- if (atomic_read(&listener->pend_accepts_cnt) > 0)
- i40iw_debug(cm_core->dev,
- I40IW_DEBUG_CM,
- "%s: listener (%p) pending accepts=%u\n",
- __func__,
- listener,
- atomic_read(&listener->pend_accepts_cnt));
- }
-
- return ret;
-}
-
-/**
- * i40iw_cm_del_listen - delete a linstener
- * @cm_core: cm's core
- * @listener: passive connection's listener
- * @apbvt_del: flag to delete apbvt
- */
-static int i40iw_cm_del_listen(struct i40iw_cm_core *cm_core,
- struct i40iw_cm_listener *listener,
- bool apbvt_del)
-{
- listener->listener_state = I40IW_CM_LISTENER_PASSIVE_STATE;
- listener->cm_id = NULL; /* going to be destroyed pretty soon */
- return i40iw_dec_refcnt_listen(cm_core, listener, 1, apbvt_del);
-}
-
-/**
- * i40iw_addr_resolve_neigh - resolve neighbor address
- * @iwdev: iwarp device structure
- * @src_ip: local ip address
- * @dst_ip: remote ip address
- * @arpindex: if there is an arp entry
- */
-static int i40iw_addr_resolve_neigh(struct i40iw_device *iwdev,
- u32 src_ip,
- u32 dst_ip,
- int arpindex)
-{
- struct rtable *rt;
- struct neighbour *neigh;
- int rc = arpindex;
- __be32 dst_ipaddr = htonl(dst_ip);
- __be32 src_ipaddr = htonl(src_ip);
-
- rt = ip_route_output(&init_net, dst_ipaddr, src_ipaddr, 0, 0);
- if (IS_ERR(rt)) {
- i40iw_pr_err("ip_route_output\n");
- return rc;
- }
-
- neigh = dst_neigh_lookup(&rt->dst, &dst_ipaddr);
-
- rcu_read_lock();
- if (neigh) {
- if (neigh->nud_state & NUD_VALID) {
- if (arpindex >= 0) {
- if (ether_addr_equal(iwdev->arp_table[arpindex].mac_addr,
- neigh->ha))
- /* Mac address same as arp table */
- goto resolve_neigh_exit;
- i40iw_manage_arp_cache(iwdev,
- iwdev->arp_table[arpindex].mac_addr,
- &dst_ip,
- true,
- I40IW_ARP_DELETE);
- }
-
- i40iw_manage_arp_cache(iwdev, neigh->ha, &dst_ip, true, I40IW_ARP_ADD);
- rc = i40iw_arp_table(iwdev, &dst_ip, true, NULL, I40IW_ARP_RESOLVE);
- } else {
- neigh_event_send(neigh, NULL);
- }
- }
- resolve_neigh_exit:
-
- rcu_read_unlock();
- if (neigh)
- neigh_release(neigh);
-
- ip_rt_put(rt);
- return rc;
-}
-
-/*
- * i40iw_get_dst_ipv6
- */
-static struct dst_entry *i40iw_get_dst_ipv6(struct sockaddr_in6 *src_addr,
- struct sockaddr_in6 *dst_addr)
-{
- struct dst_entry *dst;
- struct flowi6 fl6;
-
- memset(&fl6, 0, sizeof(fl6));
- fl6.daddr = dst_addr->sin6_addr;
- fl6.saddr = src_addr->sin6_addr;
- if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL)
- fl6.flowi6_oif = dst_addr->sin6_scope_id;
-
- dst = ip6_route_output(&init_net, NULL, &fl6);
- return dst;
-}
-
-/**
- * i40iw_addr_resolve_neigh_ipv6 - resolve neighbor ipv6 address
- * @iwdev: iwarp device structure
- * @src: source ip address
- * @dest: remote ip address
- * @arpindex: if there is an arp entry
- */
-static int i40iw_addr_resolve_neigh_ipv6(struct i40iw_device *iwdev,
- u32 *src,
- u32 *dest,
- int arpindex)
-{
- struct neighbour *neigh;
- int rc = arpindex;
- struct dst_entry *dst;
- struct sockaddr_in6 dst_addr;
- struct sockaddr_in6 src_addr;
-
- memset(&dst_addr, 0, sizeof(dst_addr));
- dst_addr.sin6_family = AF_INET6;
- i40iw_copy_ip_htonl(dst_addr.sin6_addr.in6_u.u6_addr32, dest);
- memset(&src_addr, 0, sizeof(src_addr));
- src_addr.sin6_family = AF_INET6;
- i40iw_copy_ip_htonl(src_addr.sin6_addr.in6_u.u6_addr32, src);
- dst = i40iw_get_dst_ipv6(&src_addr, &dst_addr);
- if (!dst || dst->error) {
- if (dst) {
- i40iw_pr_err("ip6_route_output returned dst->error = %d\n",
- dst->error);
- dst_release(dst);
- }
- return rc;
- }
-
- neigh = dst_neigh_lookup(dst, dst_addr.sin6_addr.in6_u.u6_addr32);
-
- rcu_read_lock();
- if (neigh) {
- i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_CM, "dst_neigh_lookup MAC=%pM\n", neigh->ha);
- if (neigh->nud_state & NUD_VALID) {
- if (arpindex >= 0) {
- if (ether_addr_equal
- (iwdev->arp_table[arpindex].mac_addr,
- neigh->ha)) {
- /* Mac address same as in arp table */
- goto resolve_neigh_exit6;
- }
- i40iw_manage_arp_cache(iwdev,
- iwdev->arp_table[arpindex].mac_addr,
- dest,
- false,
- I40IW_ARP_DELETE);
- }
- i40iw_manage_arp_cache(iwdev,
- neigh->ha,
- dest,
- false,
- I40IW_ARP_ADD);
- rc = i40iw_arp_table(iwdev,
- dest,
- false,
- NULL,
- I40IW_ARP_RESOLVE);
- } else {
- neigh_event_send(neigh, NULL);
- }
- }
-
- resolve_neigh_exit6:
- rcu_read_unlock();
- if (neigh)
- neigh_release(neigh);
- dst_release(dst);
- return rc;
-}
-
-/**
- * i40iw_ipv4_is_loopback - check if loopback
- * @loc_addr: local addr to compare
- * @rem_addr: remote address
- */
-static bool i40iw_ipv4_is_loopback(u32 loc_addr, u32 rem_addr)
-{
- return ipv4_is_loopback(htonl(rem_addr)) || (loc_addr == rem_addr);
-}
-
-/**
- * i40iw_ipv6_is_loopback - check if loopback
- * @loc_addr: local addr to compare
- * @rem_addr: remote address
- */
-static bool i40iw_ipv6_is_loopback(u32 *loc_addr, u32 *rem_addr)
-{
- struct in6_addr raddr6;
-
- i40iw_copy_ip_htonl(raddr6.in6_u.u6_addr32, rem_addr);
- return !memcmp(loc_addr, rem_addr, 16) || ipv6_addr_loopback(&raddr6);
-}
-
-/**
- * i40iw_make_cm_node - create a new instance of a cm node
- * @cm_core: cm's core
- * @iwdev: iwarp device structure
- * @cm_info: quad info for connection
- * @listener: passive connection's listener
- */
-static struct i40iw_cm_node *i40iw_make_cm_node(
- struct i40iw_cm_core *cm_core,
- struct i40iw_device *iwdev,
- struct i40iw_cm_info *cm_info,
- struct i40iw_cm_listener *listener)
-{
- struct i40iw_cm_node *cm_node;
- int oldarpindex;
- int arpindex;
- struct net_device *netdev = iwdev->netdev;
-
- /* 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 */
- cm_node->ipv4 = cm_info->ipv4;
- cm_node->vlan_id = cm_info->vlan_id;
- if ((cm_node->vlan_id == I40IW_NO_VLAN) && iwdev->dcb)
- cm_node->vlan_id = 0;
- cm_node->tos = cm_info->tos;
- cm_node->user_pri = cm_info->user_pri;
- if (listener) {
- if (listener->tos != cm_info->tos)
- i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_DCB,
- "application TOS[%d] and remote client TOS[%d] mismatch\n",
- listener->tos, cm_info->tos);
- cm_node->tos = max(listener->tos, cm_info->tos);
- cm_node->user_pri = rt_tos2priority(cm_node->tos);
- i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_DCB, "listener: TOS:[%d] UP:[%d]\n",
- cm_node->tos, cm_node->user_pri);
- }
- memcpy(cm_node->loc_addr, cm_info->loc_addr, sizeof(cm_node->loc_addr));
- memcpy(cm_node->rem_addr, cm_info->rem_addr, sizeof(cm_node->rem_addr));
- cm_node->loc_port = cm_info->loc_port;
- cm_node->rem_port = cm_info->rem_port;
-
- cm_node->mpa_frame_rev = iwdev->mpa_version;
- cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO;
- cm_node->ird_size = I40IW_MAX_IRD_SIZE;
- cm_node->ord_size = I40IW_MAX_ORD_SIZE;
-
- cm_node->listener = listener;
- cm_node->cm_id = cm_info->cm_id;
- ether_addr_copy(cm_node->loc_mac, netdev->dev_addr);
- spin_lock_init(&cm_node->retrans_list_lock);
- cm_node->ack_rcvd = false;
-
- atomic_set(&cm_node->ref_count, 1);
- /* associate our parent CM core */
- cm_node->cm_core = cm_core;
- cm_node->tcp_cntxt.loc_id = I40IW_CM_DEF_LOCAL_ID;
- cm_node->tcp_cntxt.rcv_wscale = I40IW_CM_DEFAULT_RCV_WND_SCALE;
- cm_node->tcp_cntxt.rcv_wnd =
- I40IW_CM_DEFAULT_RCV_WND_SCALED >> I40IW_CM_DEFAULT_RCV_WND_SCALE;
- if (cm_node->ipv4) {
- cm_node->tcp_cntxt.loc_seq_num = secure_tcp_seq(htonl(cm_node->loc_addr[0]),
- htonl(cm_node->rem_addr[0]),
- htons(cm_node->loc_port),
- htons(cm_node->rem_port));
- cm_node->tcp_cntxt.mss = iwdev->vsi.mtu - I40IW_MTU_TO_MSS_IPV4;
- } else if (IS_ENABLED(CONFIG_IPV6)) {
- __be32 loc[4] = {
- htonl(cm_node->loc_addr[0]), htonl(cm_node->loc_addr[1]),
- htonl(cm_node->loc_addr[2]), htonl(cm_node->loc_addr[3])
- };
- __be32 rem[4] = {
- htonl(cm_node->rem_addr[0]), htonl(cm_node->rem_addr[1]),
- htonl(cm_node->rem_addr[2]), htonl(cm_node->rem_addr[3])
- };
- cm_node->tcp_cntxt.loc_seq_num = secure_tcpv6_seq(loc, rem,
- htons(cm_node->loc_port),
- htons(cm_node->rem_port));
- cm_node->tcp_cntxt.mss = iwdev->vsi.mtu - I40IW_MTU_TO_MSS_IPV6;
- }
-
- cm_node->iwdev = iwdev;
- cm_node->dev = &iwdev->sc_dev;
-
- if ((cm_node->ipv4 &&
- i40iw_ipv4_is_loopback(cm_node->loc_addr[0], cm_node->rem_addr[0])) ||
- (!cm_node->ipv4 && i40iw_ipv6_is_loopback(cm_node->loc_addr,
- cm_node->rem_addr))) {
- arpindex = i40iw_arp_table(iwdev,
- cm_node->rem_addr,
- false,
- NULL,
- I40IW_ARP_RESOLVE);
- } else {
- oldarpindex = i40iw_arp_table(iwdev,
- cm_node->rem_addr,
- false,
- NULL,
- I40IW_ARP_RESOLVE);
- if (cm_node->ipv4)
- arpindex = i40iw_addr_resolve_neigh(iwdev,
- cm_info->loc_addr[0],
- cm_info->rem_addr[0],
- oldarpindex);
- else if (IS_ENABLED(CONFIG_IPV6))
- arpindex = i40iw_addr_resolve_neigh_ipv6(iwdev,
- cm_info->loc_addr,
- cm_info->rem_addr,
- oldarpindex);
- else
- arpindex = -EINVAL;
- }
- if (arpindex < 0) {
- i40iw_pr_err("cm_node arpindex\n");
- kfree(cm_node);
- return NULL;
- }
- ether_addr_copy(cm_node->rem_mac, iwdev->arp_table[arpindex].mac_addr);
- i40iw_add_hte_node(cm_core, cm_node);
- cm_core->stats_nodes_created++;
- return cm_node;
-}
-
-/**
- * i40iw_rem_ref_cm_node - destroy an instance of a cm node
- * @cm_node: connection's node
- */
-static void i40iw_rem_ref_cm_node(struct i40iw_cm_node *cm_node)
-{
- struct i40iw_cm_core *cm_core = cm_node->cm_core;
- struct i40iw_qp *iwqp;
- struct i40iw_cm_info nfo;
- unsigned long flags;
-
- 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;
- }
- list_del(&cm_node->list);
- 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) {
- pr_err("node destroyed before established\n");
- atomic_dec(&cm_node->listener->pend_accepts_cnt);
- }
- if (cm_node->close_entry)
- i40iw_handle_close_entry(cm_node, 0);
- if (cm_node->listener) {
- i40iw_dec_refcnt_listen(cm_core, cm_node->listener, 0, true);
- } else {
- if (cm_node->apbvt_set) {
- i40iw_manage_apbvt(cm_node->iwdev,
- cm_node->loc_port,
- I40IW_MANAGE_APBVT_DEL);
- cm_node->apbvt_set = 0;
- }
- i40iw_get_addr_info(cm_node, &nfo);
- if (cm_node->qhash_set) {
- i40iw_manage_qhash(cm_node->iwdev,
- &nfo,
- I40IW_QHASH_TYPE_TCP_ESTABLISHED,
- I40IW_QHASH_MANAGE_TYPE_DELETE,
- NULL,
- false);
- cm_node->qhash_set = 0;
- }
- }
-
- iwqp = cm_node->iwqp;
- if (iwqp) {
- iwqp->cm_node = NULL;
- i40iw_qp_rem_ref(&iwqp->ibqp);
- cm_node->iwqp = NULL;
- } else if (cm_node->qhash_set) {
- i40iw_get_addr_info(cm_node, &nfo);
- i40iw_manage_qhash(cm_node->iwdev,
- &nfo,
- I40IW_QHASH_TYPE_TCP_ESTABLISHED,
- I40IW_QHASH_MANAGE_TYPE_DELETE,
- NULL,
- false);
- cm_node->qhash_set = 0;
- }
-
- cm_node->cm_core->stats_nodes_destroyed++;
- kfree(cm_node);
-}
-
-/**
- * i40iw_handle_fin_pkt - FIN packet received
- * @cm_node: connection's node
- */
-static void i40iw_handle_fin_pkt(struct i40iw_cm_node *cm_node)
-{
- u32 ret;
-
- switch (cm_node->state) {
- case I40IW_CM_STATE_SYN_RCVD:
- case I40IW_CM_STATE_SYN_SENT:
- case I40IW_CM_STATE_ESTABLISHED:
- case I40IW_CM_STATE_MPAREJ_RCVD:
- cm_node->tcp_cntxt.rcv_nxt++;
- i40iw_cleanup_retrans_entry(cm_node);
- cm_node->state = I40IW_CM_STATE_LAST_ACK;
- i40iw_send_fin(cm_node);
- break;
- case I40IW_CM_STATE_MPAREQ_SENT:
- i40iw_create_event(cm_node, I40IW_CM_EVENT_ABORTED);
- cm_node->tcp_cntxt.rcv_nxt++;
- i40iw_cleanup_retrans_entry(cm_node);
- cm_node->state = I40IW_CM_STATE_CLOSED;
- atomic_inc(&cm_node->ref_count);
- i40iw_send_reset(cm_node);
- break;
- case I40IW_CM_STATE_FIN_WAIT1:
- cm_node->tcp_cntxt.rcv_nxt++;
- i40iw_cleanup_retrans_entry(cm_node);
- cm_node->state = I40IW_CM_STATE_CLOSING;
- i40iw_send_ack(cm_node);
- /*
- * Wait for ACK as this is simultaneous close.
- * After we receive ACK, do not send anything.
- * Just rm the node.
- */
- break;
- case I40IW_CM_STATE_FIN_WAIT2:
- cm_node->tcp_cntxt.rcv_nxt++;
- i40iw_cleanup_retrans_entry(cm_node);
- cm_node->state = I40IW_CM_STATE_TIME_WAIT;
- i40iw_send_ack(cm_node);
- ret =
- i40iw_schedule_cm_timer(cm_node, NULL, I40IW_TIMER_TYPE_CLOSE, 1, 0);
- if (ret)
- i40iw_pr_err("node %p state = %d\n", cm_node, cm_node->state);
- break;
- case I40IW_CM_STATE_TIME_WAIT:
- cm_node->tcp_cntxt.rcv_nxt++;
- i40iw_cleanup_retrans_entry(cm_node);
- cm_node->state = I40IW_CM_STATE_CLOSED;
- i40iw_rem_ref_cm_node(cm_node);
- break;
- case I40IW_CM_STATE_OFFLOADED:
- default:
- i40iw_pr_err("bad state node %p state = %d\n", cm_node, cm_node->state);
- break;
- }
-}
-
-/**
- * i40iw_handle_rst_pkt - process received RST packet
- * @cm_node: connection's node
- * @rbuf: receive buffer
- */
-static void i40iw_handle_rst_pkt(struct i40iw_cm_node *cm_node,
- struct i40iw_puda_buf *rbuf)
-{
- i40iw_cleanup_retrans_entry(cm_node);
- switch (cm_node->state) {
- case I40IW_CM_STATE_SYN_SENT:
- case I40IW_CM_STATE_MPAREQ_SENT:
- 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 = I40IW_CM_STATE_SYN_SENT;
- if (i40iw_send_syn(cm_node, 0))
- i40iw_active_open_err(cm_node, false);
- break;
- case IETF_MPA_V1:
- default:
- i40iw_active_open_err(cm_node, false);
- break;
- }
- break;
- case I40IW_CM_STATE_MPAREQ_RCVD:
- atomic_inc(&cm_node->passive_state);
- break;
- case I40IW_CM_STATE_ESTABLISHED:
- case I40IW_CM_STATE_SYN_RCVD:
- case I40IW_CM_STATE_LISTENING:
- i40iw_pr_err("Bad state state = %d\n", cm_node->state);
- i40iw_passive_open_err(cm_node, false);
- break;
- case I40IW_CM_STATE_OFFLOADED:
- i40iw_active_open_err(cm_node, false);
- break;
- case I40IW_CM_STATE_CLOSED:
- break;
- case I40IW_CM_STATE_FIN_WAIT2:
- case I40IW_CM_STATE_FIN_WAIT1:
- case I40IW_CM_STATE_LAST_ACK:
- cm_node->cm_id->rem_ref(cm_node->cm_id);
- fallthrough;
- case I40IW_CM_STATE_TIME_WAIT:
- cm_node->state = I40IW_CM_STATE_CLOSED;
- i40iw_rem_ref_cm_node(cm_node);
- break;
- default:
- break;
- }
-}
-
-/**
- * i40iw_handle_rcv_mpa - Process a recv'd mpa buffer
- * @cm_node: connection's node
- * @rbuf: receive buffer
- */
-static void i40iw_handle_rcv_mpa(struct i40iw_cm_node *cm_node,
- struct i40iw_puda_buf *rbuf)
-{
- int ret;
- int datasize = rbuf->datalen;
- u8 *dataloc = rbuf->data;
-
- enum i40iw_cm_event_type type = I40IW_CM_EVENT_UNKNOWN;
- u32 res_type;
-
- ret = i40iw_parse_mpa(cm_node, dataloc, &res_type, datasize);
- if (ret) {
- if (cm_node->state == I40IW_CM_STATE_MPAREQ_SENT)
- i40iw_active_open_err(cm_node, true);
- else
- i40iw_passive_open_err(cm_node, true);
- return;
- }
-
- switch (cm_node->state) {
- case I40IW_CM_STATE_ESTABLISHED:
- if (res_type == I40IW_MPA_REQUEST_REJECT)
- i40iw_pr_err("state for reject\n");
- cm_node->state = I40IW_CM_STATE_MPAREQ_RCVD;
- type = I40IW_CM_EVENT_MPA_REQ;
- i40iw_send_ack(cm_node); /* ACK received MPA request */
- atomic_set(&cm_node->passive_state,
- I40IW_PASSIVE_STATE_INDICATED);
- break;
- case I40IW_CM_STATE_MPAREQ_SENT:
- i40iw_cleanup_retrans_entry(cm_node);
- if (res_type == I40IW_MPA_REQUEST_REJECT) {
- type = I40IW_CM_EVENT_MPA_REJECT;
- cm_node->state = I40IW_CM_STATE_MPAREJ_RCVD;
- } else {
- type = I40IW_CM_EVENT_CONNECTED;
- cm_node->state = I40IW_CM_STATE_OFFLOADED;
- }
- i40iw_send_ack(cm_node);
- break;
- default:
- pr_err("%s wrong cm_node state =%d\n", __func__, cm_node->state);
- break;
- }
- i40iw_create_event(cm_node, type);
-}
-
-/**
- * i40iw_indicate_pkt_err - Send up err event to cm
- * @cm_node: connection's node
- */
-static void i40iw_indicate_pkt_err(struct i40iw_cm_node *cm_node)
-{
- switch (cm_node->state) {
- case I40IW_CM_STATE_SYN_SENT:
- case I40IW_CM_STATE_MPAREQ_SENT:
- i40iw_active_open_err(cm_node, true);
- break;
- case I40IW_CM_STATE_ESTABLISHED:
- case I40IW_CM_STATE_SYN_RCVD:
- i40iw_passive_open_err(cm_node, true);
- break;
- case I40IW_CM_STATE_OFFLOADED:
- default:
- break;
- }
-}
-
-/**
- * i40iw_check_syn - Check for error on received syn ack
- * @cm_node: connection's node
- * @tcph: pointer tcp header
- */
-static int i40iw_check_syn(struct i40iw_cm_node *cm_node, struct tcphdr *tcph)
-{
- int err = 0;
-
- if (ntohl(tcph->ack_seq) != cm_node->tcp_cntxt.loc_seq_num) {
- err = 1;
- i40iw_active_open_err(cm_node, true);
- }
- return err;
-}
-
-/**
- * i40iw_check_seq - check seq numbers if OK
- * @cm_node: connection's node
- * @tcph: pointer tcp header
- */
-static int i40iw_check_seq(struct i40iw_cm_node *cm_node, struct tcphdr *tcph)
-{
- 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) {
- i40iw_pr_err("seq number\n");
- i40iw_indicate_pkt_err(cm_node);
- }
- return err;
-}
-
-/**
- * i40iw_handle_syn_pkt - is for Passive node
- * @cm_node: connection's node
- * @rbuf: receive buffer
- */
-static void i40iw_handle_syn_pkt(struct i40iw_cm_node *cm_node,
- struct i40iw_puda_buf *rbuf)
-{
- struct tcphdr *tcph = (struct tcphdr *)rbuf->tcph;
- int ret;
- u32 inc_sequence;
- int optionsize;
- struct i40iw_cm_info nfo;
-
- optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
- inc_sequence = ntohl(tcph->seq);
-
- switch (cm_node->state) {
- case I40IW_CM_STATE_SYN_SENT:
- case I40IW_CM_STATE_MPAREQ_SENT:
- /* Rcvd syn on active open connection */
- i40iw_active_open_err(cm_node, 1);
- break;
- case I40IW_CM_STATE_LISTENING:
- /* Passive OPEN */
- if (atomic_read(&cm_node->listener->pend_accepts_cnt) >
- cm_node->listener->backlog) {
- cm_node->cm_core->stats_backlog_drops++;
- i40iw_passive_open_err(cm_node, false);
- break;
- }
- ret = i40iw_handle_tcp_options(cm_node, tcph, optionsize, 1);
- if (ret) {
- i40iw_passive_open_err(cm_node, false);
- /* drop pkt */
- break;
- }
- cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
- cm_node->accept_pend = 1;
- atomic_inc(&cm_node->listener->pend_accepts_cnt);
-
- cm_node->state = I40IW_CM_STATE_SYN_RCVD;
- i40iw_get_addr_info(cm_node, &nfo);
- ret = i40iw_manage_qhash(cm_node->iwdev,
- &nfo,
- I40IW_QHASH_TYPE_TCP_ESTABLISHED,
- I40IW_QHASH_MANAGE_TYPE_ADD,
- (void *)cm_node,
- false);
- cm_node->qhash_set = true;
- break;
- case I40IW_CM_STATE_CLOSED:
- i40iw_cleanup_retrans_entry(cm_node);
- atomic_inc(&cm_node->ref_count);
- i40iw_send_reset(cm_node);
- break;
- case I40IW_CM_STATE_OFFLOADED:
- case I40IW_CM_STATE_ESTABLISHED:
- case I40IW_CM_STATE_FIN_WAIT1:
- case I40IW_CM_STATE_FIN_WAIT2:
- case I40IW_CM_STATE_MPAREQ_RCVD:
- case I40IW_CM_STATE_LAST_ACK:
- case I40IW_CM_STATE_CLOSING:
- case I40IW_CM_STATE_UNKNOWN:
- default:
- break;
- }
-}
-
-/**
- * i40iw_handle_synack_pkt - Process SYN+ACK packet (active side)
- * @cm_node: connection's node
- * @rbuf: receive buffer
- */
-static void i40iw_handle_synack_pkt(struct i40iw_cm_node *cm_node,
- struct i40iw_puda_buf *rbuf)
-{
- struct tcphdr *tcph = (struct tcphdr *)rbuf->tcph;
- int ret;
- u32 inc_sequence;
- int optionsize;
-
- optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
- inc_sequence = ntohl(tcph->seq);
- switch (cm_node->state) {
- case I40IW_CM_STATE_SYN_SENT:
- i40iw_cleanup_retrans_entry(cm_node);
- /* active open */
- if (i40iw_check_syn(cm_node, tcph)) {
- i40iw_pr_err("check syn fail\n");
- return;
- }
- cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
- /* setup options */
- ret = i40iw_handle_tcp_options(cm_node, tcph, optionsize, 0);
- if (ret) {
- i40iw_debug(cm_node->dev,
- I40IW_DEBUG_CM,
- "cm_node=%p tcp_options failed\n",
- cm_node);
- break;
- }
- i40iw_cleanup_retrans_entry(cm_node);
- cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
- i40iw_send_ack(cm_node); /* ACK for the syn_ack */
- ret = i40iw_send_mpa_request(cm_node);
- if (ret) {
- i40iw_debug(cm_node->dev,
- I40IW_DEBUG_CM,
- "cm_node=%p i40iw_send_mpa_request failed\n",
- cm_node);
- break;
- }
- cm_node->state = I40IW_CM_STATE_MPAREQ_SENT;
- break;
- case I40IW_CM_STATE_MPAREQ_RCVD:
- i40iw_passive_open_err(cm_node, true);
- break;
- case I40IW_CM_STATE_LISTENING:
- cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
- i40iw_cleanup_retrans_entry(cm_node);
- cm_node->state = I40IW_CM_STATE_CLOSED;
- i40iw_send_reset(cm_node);
- break;
- case I40IW_CM_STATE_CLOSED:
- cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
- i40iw_cleanup_retrans_entry(cm_node);
- atomic_inc(&cm_node->ref_count);
- i40iw_send_reset(cm_node);
- break;
- case I40IW_CM_STATE_ESTABLISHED:
- case I40IW_CM_STATE_FIN_WAIT1:
- case I40IW_CM_STATE_FIN_WAIT2:
- case I40IW_CM_STATE_LAST_ACK:
- case I40IW_CM_STATE_OFFLOADED:
- case I40IW_CM_STATE_CLOSING:
- case I40IW_CM_STATE_UNKNOWN:
- case I40IW_CM_STATE_MPAREQ_SENT:
- default:
- break;
- }
-}
-
-/**
- * i40iw_handle_ack_pkt - process packet with ACK
- * @cm_node: connection's node
- * @rbuf: receive buffer
- */
-static int i40iw_handle_ack_pkt(struct i40iw_cm_node *cm_node,
- struct i40iw_puda_buf *rbuf)
-{
- struct tcphdr *tcph = (struct tcphdr *)rbuf->tcph;
- u32 inc_sequence;
- int ret = 0;
- int optionsize;
- u32 datasize = rbuf->datalen;
-
- optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
-
- if (i40iw_check_seq(cm_node, tcph))
- return -EINVAL;
-
- inc_sequence = ntohl(tcph->seq);
- switch (cm_node->state) {
- case I40IW_CM_STATE_SYN_RCVD:
- i40iw_cleanup_retrans_entry(cm_node);
- ret = i40iw_handle_tcp_options(cm_node, tcph, optionsize, 1);
- if (ret)
- break;
- cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
- cm_node->state = I40IW_CM_STATE_ESTABLISHED;
- if (datasize) {
- cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
- i40iw_handle_rcv_mpa(cm_node, rbuf);
- }
- break;
- case I40IW_CM_STATE_ESTABLISHED:
- i40iw_cleanup_retrans_entry(cm_node);
- if (datasize) {
- cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
- i40iw_handle_rcv_mpa(cm_node, rbuf);
- }
- break;
- case I40IW_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;
- cm_node->ack_rcvd = false;
- i40iw_handle_rcv_mpa(cm_node, rbuf);
- } else {
- cm_node->ack_rcvd = true;
- }
- break;
- case I40IW_CM_STATE_LISTENING:
- i40iw_cleanup_retrans_entry(cm_node);
- cm_node->state = I40IW_CM_STATE_CLOSED;
- i40iw_send_reset(cm_node);
- break;
- case I40IW_CM_STATE_CLOSED:
- i40iw_cleanup_retrans_entry(cm_node);
- atomic_inc(&cm_node->ref_count);
- i40iw_send_reset(cm_node);
- break;
- case I40IW_CM_STATE_LAST_ACK:
- case I40IW_CM_STATE_CLOSING:
- i40iw_cleanup_retrans_entry(cm_node);
- cm_node->state = I40IW_CM_STATE_CLOSED;
- if (!cm_node->accept_pend)
- cm_node->cm_id->rem_ref(cm_node->cm_id);
- i40iw_rem_ref_cm_node(cm_node);
- break;
- case I40IW_CM_STATE_FIN_WAIT1:
- i40iw_cleanup_retrans_entry(cm_node);
- cm_node->state = I40IW_CM_STATE_FIN_WAIT2;
- break;
- case I40IW_CM_STATE_SYN_SENT:
- case I40IW_CM_STATE_FIN_WAIT2:
- case I40IW_CM_STATE_OFFLOADED:
- case I40IW_CM_STATE_MPAREQ_RCVD:
- case I40IW_CM_STATE_UNKNOWN:
- default:
- i40iw_cleanup_retrans_entry(cm_node);
- break;
- }
- return ret;
-}
-
-/**
- * i40iw_process_packet - process cm packet
- * @cm_node: connection's node
- * @rbuf: receive buffer
- */
-static void i40iw_process_packet(struct i40iw_cm_node *cm_node,
- struct i40iw_puda_buf *rbuf)
-{
- enum i40iw_tcpip_pkt_type pkt_type = I40IW_PKT_TYPE_UNKNOWN;
- struct tcphdr *tcph = (struct tcphdr *)rbuf->tcph;
- u32 fin_set = 0;
- int ret;
-
- if (tcph->rst) {
- pkt_type = I40IW_PKT_TYPE_RST;
- } else if (tcph->syn) {
- pkt_type = I40IW_PKT_TYPE_SYN;
- if (tcph->ack)
- pkt_type = I40IW_PKT_TYPE_SYNACK;
- } else if (tcph->ack) {
- pkt_type = I40IW_PKT_TYPE_ACK;
- }
- if (tcph->fin)
- fin_set = 1;
-
- switch (pkt_type) {
- case I40IW_PKT_TYPE_SYN:
- i40iw_handle_syn_pkt(cm_node, rbuf);
- break;
- case I40IW_PKT_TYPE_SYNACK:
- i40iw_handle_synack_pkt(cm_node, rbuf);
- break;
- case I40IW_PKT_TYPE_ACK:
- ret = i40iw_handle_ack_pkt(cm_node, rbuf);
- if (fin_set && !ret)
- i40iw_handle_fin_pkt(cm_node);
- break;
- case I40IW_PKT_TYPE_RST:
- i40iw_handle_rst_pkt(cm_node, rbuf);
- break;
- default:
- if (fin_set &&
- (!i40iw_check_seq(cm_node, (struct tcphdr *)rbuf->tcph)))
- i40iw_handle_fin_pkt(cm_node);
- break;
- }
-}
-
-/**
- * i40iw_make_listen_node - create a listen node with params
- * @cm_core: cm's core
- * @iwdev: iwarp device structure
- * @cm_info: quad info for connection
- */
-static struct i40iw_cm_listener *i40iw_make_listen_node(
- struct i40iw_cm_core *cm_core,
- struct i40iw_device *iwdev,
- struct i40iw_cm_info *cm_info)
-{
- struct i40iw_cm_listener *listener;
- unsigned long flags;
-
- /* cannot have multiple matching listeners */
- listener = i40iw_find_listener(cm_core, cm_info->loc_addr,
- cm_info->loc_port,
- cm_info->vlan_id,
- I40IW_CM_LISTENER_EITHER_STATE);
- if (listener &&
- (listener->listener_state == I40IW_CM_LISTENER_ACTIVE_STATE)) {
- atomic_dec(&listener->ref_count);
- i40iw_debug(cm_core->dev,
- I40IW_DEBUG_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_KERNEL);
- if (!listener)
- return NULL;
- cm_core->stats_listen_nodes_created++;
- memcpy(listener->loc_addr, cm_info->loc_addr, sizeof(listener->loc_addr));
- listener->loc_port = cm_info->loc_port;
-
- INIT_LIST_HEAD(&listener->child_listen_list);
-
- atomic_set(&listener->ref_count, 1);
- } else {
- listener->reused_node = 1;
- }
-
- listener->cm_id = cm_info->cm_id;
- listener->ipv4 = cm_info->ipv4;
- listener->vlan_id = cm_info->vlan_id;
- atomic_set(&listener->pend_accepts_cnt, 0);
- listener->cm_core = cm_core;
- listener->iwdev = iwdev;
-
- listener->backlog = cm_info->backlog;
- listener->listener_state = I40IW_CM_LISTENER_ACTIVE_STATE;
-
- if (!listener->reused_node) {
- spin_lock_irqsave(&cm_core->listen_list_lock, flags);
- list_add(&listener->list, &cm_core->listen_nodes);
- spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
- }
-
- return listener;
-}
-
-/**
- * i40iw_create_cm_node - make a connection node with params
- * @cm_core: cm's core
- * @iwdev: iwarp device structure
- * @conn_param: upper layer connection parameters
- * @cm_info: quad info for connection
- */
-static struct i40iw_cm_node *i40iw_create_cm_node(
- struct i40iw_cm_core *cm_core,
- struct i40iw_device *iwdev,
- struct iw_cm_conn_param *conn_param,
- struct i40iw_cm_info *cm_info)
-{
- struct i40iw_cm_node *cm_node;
- struct i40iw_cm_listener *loopback_remotelistener;
- struct i40iw_cm_node *loopback_remotenode;
- struct i40iw_cm_info loopback_cm_info;
-
- u16 private_data_len = conn_param->private_data_len;
- const void *private_data = conn_param->private_data;
-
- /* create a CM connection node */
- cm_node = i40iw_make_cm_node(cm_core, iwdev, cm_info, NULL);
- if (!cm_node)
- return ERR_PTR(-ENOMEM);
- /* set our node side to client (active) side */
- cm_node->tcp_cntxt.client = 1;
- cm_node->tcp_cntxt.rcv_wscale = I40IW_CM_DEFAULT_RCV_WND_SCALE;
-
- i40iw_record_ird_ord(cm_node, conn_param->ird, conn_param->ord);
-
- if (!memcmp(cm_info->loc_addr, cm_info->rem_addr, sizeof(cm_info->loc_addr))) {
- loopback_remotelistener = i40iw_find_listener(
- cm_core,
- cm_info->rem_addr,
- cm_node->rem_port,
- cm_node->vlan_id,
- I40IW_CM_LISTENER_ACTIVE_STATE);
- if (!loopback_remotelistener) {
- i40iw_rem_ref_cm_node(cm_node);
- return ERR_PTR(-ECONNREFUSED);
- } 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.cm_id = loopback_remotelistener->cm_id;
- loopback_cm_info.ipv4 = cm_info->ipv4;
- loopback_remotenode = i40iw_make_cm_node(cm_core,
- iwdev,
- &loopback_cm_info,
- loopback_remotelistener);
- if (!loopback_remotenode) {
- i40iw_rem_ref_cm_node(cm_node);
- return ERR_PTR(-ENOMEM);
- }
- cm_core->stats_loopbacks++;
- loopback_remotenode->loopbackpartner = cm_node;
- loopback_remotenode->tcp_cntxt.rcv_wscale =
- I40IW_CM_DEFAULT_RCV_WND_SCALE;
- cm_node->loopbackpartner = loopback_remotenode;
- memcpy(loopback_remotenode->pdata_buf, private_data,
- private_data_len);
- loopback_remotenode->pdata.size = private_data_len;
-
- if (loopback_remotenode->ord_size > cm_node->ird_size)
- loopback_remotenode->ord_size =
- cm_node->ird_size;
-
- cm_node->state = I40IW_CM_STATE_OFFLOADED;
- cm_node->tcp_cntxt.rcv_nxt =
- loopback_remotenode->tcp_cntxt.loc_seq_num;
- loopback_remotenode->tcp_cntxt.rcv_nxt =
- cm_node->tcp_cntxt.loc_seq_num;
- cm_node->tcp_cntxt.max_snd_wnd =
- loopback_remotenode->tcp_cntxt.rcv_wnd;
- loopback_remotenode->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.rcv_wnd;
- cm_node->tcp_cntxt.snd_wnd = loopback_remotenode->tcp_cntxt.rcv_wnd;
- loopback_remotenode->tcp_cntxt.snd_wnd = cm_node->tcp_cntxt.rcv_wnd;
- cm_node->tcp_cntxt.snd_wscale = loopback_remotenode->tcp_cntxt.rcv_wscale;
- loopback_remotenode->tcp_cntxt.snd_wscale = cm_node->tcp_cntxt.rcv_wscale;
- }
- return cm_node;
- }
-
- cm_node->pdata.size = private_data_len;
- cm_node->pdata.addr = cm_node->pdata_buf;
-
- memcpy(cm_node->pdata_buf, private_data, private_data_len);
-
- cm_node->state = I40IW_CM_STATE_SYN_SENT;
- return cm_node;
-}
-
-/**
- * i40iw_cm_reject - reject and teardown a connection
- * @cm_node: connection's node
- * @pdata: ptr to private data for reject
- * @plen: size of private data
- */
-static int i40iw_cm_reject(struct i40iw_cm_node *cm_node, const void *pdata, u8 plen)
-{
- int ret = 0;
- int err;
- int passive_state;
- struct iw_cm_id *cm_id = cm_node->cm_id;
- struct i40iw_cm_node *loopback = cm_node->loopbackpartner;
-
- if (cm_node->tcp_cntxt.client)
- return ret;
- i40iw_cleanup_retrans_entry(cm_node);
-
- if (!loopback) {
- passive_state = atomic_inc_return(&cm_node->passive_state);
- if (passive_state == I40IW_SEND_RESET_EVENT) {
- cm_node->state = I40IW_CM_STATE_CLOSED;
- i40iw_rem_ref_cm_node(cm_node);
- } else {
- if (cm_node->state == I40IW_CM_STATE_LISTENER_DESTROYED) {
- i40iw_rem_ref_cm_node(cm_node);
- } else {
- ret = i40iw_send_mpa_reject(cm_node, pdata, plen);
- if (ret) {
- cm_node->state = I40IW_CM_STATE_CLOSED;
- err = i40iw_send_reset(cm_node);
- if (err)
- i40iw_pr_err("send reset failed\n");
- } else {
- cm_id->add_ref(cm_id);
- }
- }
- }
- } else {
- cm_node->cm_id = NULL;
- if (cm_node->state == I40IW_CM_STATE_LISTENER_DESTROYED) {
- i40iw_rem_ref_cm_node(cm_node);
- i40iw_rem_ref_cm_node(loopback);
- } else {
- ret = i40iw_send_cm_event(loopback,
- loopback->cm_id,
- IW_CM_EVENT_CONNECT_REPLY,
- -ECONNREFUSED);
- i40iw_rem_ref_cm_node(cm_node);
- loopback->state = I40IW_CM_STATE_CLOSING;
-
- cm_id = loopback->cm_id;
- i40iw_rem_ref_cm_node(loopback);
- cm_id->rem_ref(cm_id);
- }
- }
-
- return ret;
-}
-
-/**
- * i40iw_cm_close - close of cm connection
- * @cm_node: connection's node
- */
-static int i40iw_cm_close(struct i40iw_cm_node *cm_node)
-{
- int ret = 0;
-
- if (!cm_node)
- return -EINVAL;
-
- switch (cm_node->state) {
- case I40IW_CM_STATE_SYN_RCVD:
- case I40IW_CM_STATE_SYN_SENT:
- case I40IW_CM_STATE_ONE_SIDE_ESTABLISHED:
- case I40IW_CM_STATE_ESTABLISHED:
- case I40IW_CM_STATE_ACCEPTING:
- case I40IW_CM_STATE_MPAREQ_SENT:
- case I40IW_CM_STATE_MPAREQ_RCVD:
- i40iw_cleanup_retrans_entry(cm_node);
- i40iw_send_reset(cm_node);
- break;
- case I40IW_CM_STATE_CLOSE_WAIT:
- cm_node->state = I40IW_CM_STATE_LAST_ACK;
- i40iw_send_fin(cm_node);
- break;
- case I40IW_CM_STATE_FIN_WAIT1:
- case I40IW_CM_STATE_FIN_WAIT2:
- case I40IW_CM_STATE_LAST_ACK:
- case I40IW_CM_STATE_TIME_WAIT:
- case I40IW_CM_STATE_CLOSING:
- ret = -1;
- break;
- case I40IW_CM_STATE_LISTENING:
- i40iw_cleanup_retrans_entry(cm_node);
- i40iw_send_reset(cm_node);
- break;
- case I40IW_CM_STATE_MPAREJ_RCVD:
- case I40IW_CM_STATE_UNKNOWN:
- case I40IW_CM_STATE_INITED:
- case I40IW_CM_STATE_CLOSED:
- case I40IW_CM_STATE_LISTENER_DESTROYED:
- i40iw_rem_ref_cm_node(cm_node);
- break;
- case I40IW_CM_STATE_OFFLOADED:
- if (cm_node->send_entry)
- i40iw_pr_err("send_entry\n");
- i40iw_rem_ref_cm_node(cm_node);
- break;
- }
- return ret;
-}
-
-/**
- * i40iw_receive_ilq - recv an ETHERNET packet, and process it
- * through CM
- * @vsi: pointer to the vsi structure
- * @rbuf: receive buffer
- */
-void i40iw_receive_ilq(struct i40iw_sc_vsi *vsi, struct i40iw_puda_buf *rbuf)
-{
- struct i40iw_cm_node *cm_node;
- struct i40iw_cm_listener *listener;
- struct iphdr *iph;
- struct ipv6hdr *ip6h;
- struct tcphdr *tcph;
- struct i40iw_cm_info cm_info;
- struct i40iw_sc_dev *dev = vsi->dev;
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
- struct i40iw_cm_core *cm_core = &iwdev->cm_core;
- struct vlan_ethhdr *ethh;
- u16 vtag;
-
- /* if vlan, then maclen = 18 else 14 */
- iph = (struct iphdr *)rbuf->iph;
- memset(&cm_info, 0, sizeof(cm_info));
-
- i40iw_debug_buf(dev,
- I40IW_DEBUG_ILQ,
- "RECEIVE ILQ BUFFER",
- rbuf->mem.va,
- rbuf->totallen);
- ethh = (struct vlan_ethhdr *)rbuf->mem.va;
-
- if (ethh->h_vlan_proto == htons(ETH_P_8021Q)) {
- vtag = ntohs(ethh->h_vlan_TCI);
- cm_info.user_pri = (vtag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
- cm_info.vlan_id = vtag & VLAN_VID_MASK;
- i40iw_debug(cm_core->dev,
- I40IW_DEBUG_CM,
- "%s vlan_id=%d\n",
- __func__,
- cm_info.vlan_id);
- } else {
- cm_info.vlan_id = I40IW_NO_VLAN;
- }
- tcph = (struct tcphdr *)rbuf->tcph;
-
- if (rbuf->ipv4) {
- cm_info.loc_addr[0] = ntohl(iph->daddr);
- cm_info.rem_addr[0] = ntohl(iph->saddr);
- cm_info.ipv4 = true;
- cm_info.tos = iph->tos;
- } else {
- ip6h = (struct ipv6hdr *)rbuf->iph;
- i40iw_copy_ip_ntohl(cm_info.loc_addr,
- ip6h->daddr.in6_u.u6_addr32);
- i40iw_copy_ip_ntohl(cm_info.rem_addr,
- ip6h->saddr.in6_u.u6_addr32);
- cm_info.ipv4 = false;
- cm_info.tos = (ip6h->priority << 4) | (ip6h->flow_lbl[0] >> 4);
- }
- cm_info.loc_port = ntohs(tcph->dest);
- cm_info.rem_port = ntohs(tcph->source);
- cm_node = i40iw_find_node(cm_core,
- cm_info.rem_port,
- cm_info.rem_addr,
- cm_info.loc_port,
- cm_info.loc_addr,
- true,
- false);
-
- if (!cm_node) {
- /* Only type of packet accepted are for */
- /* the PASSIVE open (syn only) */
- if (!tcph->syn || tcph->ack)
- return;
- listener =
- i40iw_find_listener(cm_core,
- cm_info.loc_addr,
- cm_info.loc_port,
- cm_info.vlan_id,
- I40IW_CM_LISTENER_ACTIVE_STATE);
- if (!listener) {
- cm_info.cm_id = NULL;
- i40iw_debug(cm_core->dev,
- I40IW_DEBUG_CM,
- "%s no listener found\n",
- __func__);
- return;
- }
- cm_info.cm_id = listener->cm_id;
- cm_node = i40iw_make_cm_node(cm_core, iwdev, &cm_info, listener);
- if (!cm_node) {
- i40iw_debug(cm_core->dev,
- I40IW_DEBUG_CM,
- "%s allocate node failed\n",
- __func__);
- atomic_dec(&listener->ref_count);
- return;
- }
- if (!tcph->rst && !tcph->fin) {
- cm_node->state = I40IW_CM_STATE_LISTENING;
- } else {
- i40iw_rem_ref_cm_node(cm_node);
- return;
- }
- atomic_inc(&cm_node->ref_count);
- } else if (cm_node->state == I40IW_CM_STATE_OFFLOADED) {
- i40iw_rem_ref_cm_node(cm_node);
- return;
- }
- i40iw_process_packet(cm_node, rbuf);
- i40iw_rem_ref_cm_node(cm_node);
-}
-
-/**
- * i40iw_setup_cm_core - allocate a top level instance of a cm
- * core
- * @iwdev: iwarp device structure
- */
-int i40iw_setup_cm_core(struct i40iw_device *iwdev)
-{
- struct i40iw_cm_core *cm_core = &iwdev->cm_core;
-
- cm_core->iwdev = iwdev;
- cm_core->dev = &iwdev->sc_dev;
-
- INIT_LIST_HEAD(&cm_core->accelerated_list);
- INIT_LIST_HEAD(&cm_core->non_accelerated_list);
- INIT_LIST_HEAD(&cm_core->listen_nodes);
-
- timer_setup(&cm_core->tcp_timer, i40iw_cm_timer_tick, 0);
-
- spin_lock_init(&cm_core->ht_lock);
- spin_lock_init(&cm_core->listen_list_lock);
- spin_lock_init(&cm_core->apbvt_lock);
-
- cm_core->event_wq = alloc_ordered_workqueue("iwewq",
- WQ_MEM_RECLAIM);
- if (!cm_core->event_wq)
- goto error;
-
- cm_core->disconn_wq = alloc_ordered_workqueue("iwdwq",
- WQ_MEM_RECLAIM);
- if (!cm_core->disconn_wq)
- goto error;
-
- return 0;
-error:
- i40iw_cleanup_cm_core(&iwdev->cm_core);
-
- return -ENOMEM;
-}
-
-/**
- * i40iw_cleanup_cm_core - deallocate a top level instance of a
- * cm core
- * @cm_core: cm's core
- */
-void i40iw_cleanup_cm_core(struct i40iw_cm_core *cm_core)
-{
- unsigned long flags;
-
- if (!cm_core)
- return;
-
- spin_lock_irqsave(&cm_core->ht_lock, flags);
- if (timer_pending(&cm_core->tcp_timer))
- del_timer_sync(&cm_core->tcp_timer);
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
-
- if (cm_core->event_wq)
- destroy_workqueue(cm_core->event_wq);
- if (cm_core->disconn_wq)
- destroy_workqueue(cm_core->disconn_wq);
-}
-
-/**
- * i40iw_init_tcp_ctx - setup qp context
- * @cm_node: connection's node
- * @tcp_info: offload info for tcp
- * @iwqp: associate qp for the connection
- */
-static void i40iw_init_tcp_ctx(struct i40iw_cm_node *cm_node,
- struct i40iw_tcp_offload_info *tcp_info,
- struct i40iw_qp *iwqp)
-{
- tcp_info->ipv4 = cm_node->ipv4;
- tcp_info->drop_ooo_seg = true;
- tcp_info->wscale = true;
- tcp_info->ignore_tcp_opt = true;
- tcp_info->ignore_tcp_uns_opt = true;
- tcp_info->no_nagle = false;
-
- tcp_info->ttl = I40IW_DEFAULT_TTL;
- tcp_info->rtt_var = cpu_to_le32(I40IW_DEFAULT_RTT_VAR);
- tcp_info->ss_thresh = cpu_to_le32(I40IW_DEFAULT_SS_THRESH);
- tcp_info->rexmit_thresh = I40IW_DEFAULT_REXMIT_THRESH;
-
- tcp_info->tcp_state = I40IW_TCP_STATE_ESTABLISHED;
- tcp_info->snd_wscale = cm_node->tcp_cntxt.snd_wscale;
- tcp_info->rcv_wscale = cm_node->tcp_cntxt.rcv_wscale;
-
- tcp_info->snd_nxt = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
- tcp_info->snd_wnd = cpu_to_le32(cm_node->tcp_cntxt.snd_wnd);
- tcp_info->rcv_nxt = cpu_to_le32(cm_node->tcp_cntxt.rcv_nxt);
- tcp_info->snd_max = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
-
- tcp_info->snd_una = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
- tcp_info->cwnd = cpu_to_le32(2 * cm_node->tcp_cntxt.mss);
- tcp_info->snd_wl1 = cpu_to_le32(cm_node->tcp_cntxt.rcv_nxt);
- tcp_info->snd_wl2 = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
- tcp_info->max_snd_window = cpu_to_le32(cm_node->tcp_cntxt.max_snd_wnd);
- tcp_info->rcv_wnd = cpu_to_le32(cm_node->tcp_cntxt.rcv_wnd <<
- cm_node->tcp_cntxt.rcv_wscale);
-
- tcp_info->flow_label = 0;
- tcp_info->snd_mss = cpu_to_le32(((u32)cm_node->tcp_cntxt.mss));
- if (cm_node->vlan_id <= VLAN_VID_MASK) {
- tcp_info->insert_vlan_tag = true;
- tcp_info->vlan_tag = cpu_to_le16(((u16)cm_node->user_pri << I40IW_VLAN_PRIO_SHIFT) |
- cm_node->vlan_id);
- }
- if (cm_node->ipv4) {
- tcp_info->src_port = cpu_to_le16(cm_node->loc_port);
- tcp_info->dst_port = cpu_to_le16(cm_node->rem_port);
-
- tcp_info->dest_ip_addr3 = cpu_to_le32(cm_node->rem_addr[0]);
- tcp_info->local_ipaddr3 = cpu_to_le32(cm_node->loc_addr[0]);
- tcp_info->arp_idx =
- cpu_to_le16((u16)i40iw_arp_table(
- iwqp->iwdev,
- &tcp_info->dest_ip_addr3,
- true,
- NULL,
- I40IW_ARP_RESOLVE));
- } else {
- tcp_info->src_port = cpu_to_le16(cm_node->loc_port);
- tcp_info->dst_port = cpu_to_le16(cm_node->rem_port);
- tcp_info->dest_ip_addr0 = cpu_to_le32(cm_node->rem_addr[0]);
- tcp_info->dest_ip_addr1 = cpu_to_le32(cm_node->rem_addr[1]);
- tcp_info->dest_ip_addr2 = cpu_to_le32(cm_node->rem_addr[2]);
- tcp_info->dest_ip_addr3 = cpu_to_le32(cm_node->rem_addr[3]);
- tcp_info->local_ipaddr0 = cpu_to_le32(cm_node->loc_addr[0]);
- tcp_info->local_ipaddr1 = cpu_to_le32(cm_node->loc_addr[1]);
- tcp_info->local_ipaddr2 = cpu_to_le32(cm_node->loc_addr[2]);
- tcp_info->local_ipaddr3 = cpu_to_le32(cm_node->loc_addr[3]);
- tcp_info->arp_idx =
- cpu_to_le16((u16)i40iw_arp_table(
- iwqp->iwdev,
- &tcp_info->dest_ip_addr0,
- false,
- NULL,
- I40IW_ARP_RESOLVE));
- }
-}
-
-/**
- * i40iw_cm_init_tsa_conn - setup qp for RTS
- * @iwqp: associate qp for the connection
- * @cm_node: connection's node
- */
-static void i40iw_cm_init_tsa_conn(struct i40iw_qp *iwqp,
- struct i40iw_cm_node *cm_node)
-{
- struct i40iw_tcp_offload_info tcp_info;
- struct i40iwarp_offload_info *iwarp_info;
- struct i40iw_qp_host_ctx_info *ctx_info;
- struct i40iw_device *iwdev = iwqp->iwdev;
- struct i40iw_sc_dev *dev = &iwqp->iwdev->sc_dev;
-
- memset(&tcp_info, 0x00, sizeof(struct i40iw_tcp_offload_info));
- iwarp_info = &iwqp->iwarp_info;
- ctx_info = &iwqp->ctx_info;
-
- ctx_info->tcp_info = &tcp_info;
- ctx_info->send_cq_num = iwqp->iwscq->sc_cq.cq_uk.cq_id;
- ctx_info->rcv_cq_num = iwqp->iwrcq->sc_cq.cq_uk.cq_id;
-
- iwarp_info->ord_size = cm_node->ord_size;
- iwarp_info->ird_size = i40iw_derive_hw_ird_setting(cm_node->ird_size);
-
- if (iwarp_info->ord_size == 1)
- iwarp_info->ord_size = 2;
-
- iwarp_info->rd_enable = true;
- iwarp_info->rdmap_ver = 1;
- iwarp_info->ddp_ver = 1;
-
- iwarp_info->pd_id = iwqp->iwpd->sc_pd.pd_id;
-
- ctx_info->tcp_info_valid = true;
- ctx_info->iwarp_info_valid = true;
- ctx_info->add_to_qoslist = true;
- ctx_info->user_pri = cm_node->user_pri;
-
- i40iw_init_tcp_ctx(cm_node, &tcp_info, iwqp);
- if (cm_node->snd_mark_en) {
- iwarp_info->snd_mark_en = true;
- iwarp_info->snd_mark_offset = (tcp_info.snd_nxt &
- SNDMARKER_SEQNMASK) + cm_node->lsmm_size;
- }
-
- cm_node->state = I40IW_CM_STATE_OFFLOADED;
- tcp_info.tcp_state = I40IW_TCP_STATE_ESTABLISHED;
- tcp_info.src_mac_addr_idx = iwdev->mac_ip_table_idx;
- tcp_info.tos = cm_node->tos;
-
- dev->iw_priv_qp_ops->qp_setctx(&iwqp->sc_qp, (u64 *)(iwqp->host_ctx.va), ctx_info);
-
- /* once tcp_info is set, no need to do it again */
- ctx_info->tcp_info_valid = false;
- ctx_info->iwarp_info_valid = false;
- ctx_info->add_to_qoslist = false;
-}
-
-/**
- * i40iw_cm_disconn - when a connection is being closed
- * @iwqp: associate qp for the connection
- */
-void i40iw_cm_disconn(struct i40iw_qp *iwqp)
-{
- struct disconn_work *work;
- struct i40iw_device *iwdev = iwqp->iwdev;
- struct i40iw_cm_core *cm_core = &iwdev->cm_core;
- unsigned long flags;
-
- work = kzalloc(sizeof(*work), GFP_ATOMIC);
- if (!work)
- return; /* Timer will clean up */
-
- spin_lock_irqsave(&iwdev->qptable_lock, flags);
- if (!iwdev->qp_table[iwqp->ibqp.qp_num]) {
- spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
- i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_CM,
- "%s qp_id %d is already freed\n",
- __func__, iwqp->ibqp.qp_num);
- kfree(work);
- return;
- }
- i40iw_qp_add_ref(&iwqp->ibqp);
- spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
-
- work->iwqp = iwqp;
- INIT_WORK(&work->work, i40iw_disconnect_worker);
- queue_work(cm_core->disconn_wq, &work->work);
- return;
-}
-
-/**
- * i40iw_qp_disconnect - free qp and close cm
- * @iwqp: associate qp for the connection
- */
-static void i40iw_qp_disconnect(struct i40iw_qp *iwqp)
-{
- struct i40iw_device *iwdev;
- struct i40iw_ib_device *iwibdev;
-
- iwdev = to_iwdev(iwqp->ibqp.device);
- if (!iwdev) {
- i40iw_pr_err("iwdev == NULL\n");
- return;
- }
-
- iwibdev = iwdev->iwibdev;
-
- if (iwqp->active_conn) {
- /* indicate this connection is NOT active */
- iwqp->active_conn = 0;
- } else {
- /* Need to free the Last Streaming Mode Message */
- if (iwqp->ietf_mem.va) {
- if (iwqp->lsmm_mr)
- iwibdev->ibdev.ops.dereg_mr(iwqp->lsmm_mr,
- NULL);
- i40iw_free_dma_mem(iwdev->sc_dev.hw, &iwqp->ietf_mem);
- }
- }
-
- /* close the CM node down if it is still active */
- if (iwqp->cm_node) {
- i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_CM, "%s Call close API\n", __func__);
- i40iw_cm_close(iwqp->cm_node);
- }
-}
-
-/**
- * i40iw_cm_disconn_true - called by worker thread to disconnect qp
- * @iwqp: associate qp for the connection
- */
-static void i40iw_cm_disconn_true(struct i40iw_qp *iwqp)
-{
- struct iw_cm_id *cm_id;
- struct i40iw_device *iwdev;
- struct i40iw_sc_qp *qp = &iwqp->sc_qp;
- 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;
- struct ib_event ibevent;
- unsigned long flags;
- int ret;
-
- if (!iwqp) {
- i40iw_pr_err("iwqp == NULL\n");
- return;
- }
-
- spin_lock_irqsave(&iwqp->lock, flags);
- cm_id = iwqp->cm_id;
- /* make sure we havent already closed this connection */
- if (!cm_id) {
- spin_unlock_irqrestore(&iwqp->lock, flags);
- return;
- }
-
- iwdev = to_iwdev(iwqp->ibqp.device);
-
- original_hw_tcp_state = iwqp->hw_tcp_state;
- original_ibqp_state = iwqp->ibqp_state;
- last_ae = iwqp->last_aeq;
-
- if (qp->term_flags) {
- issue_disconn = 1;
- issue_close = 1;
- iwqp->cm_id = NULL;
- /*When term timer expires after cm_timer, don't want
- *terminate-handler to issue cm_disconn which can re-free
- *a QP even after its refcnt=0.
- */
- i40iw_terminate_del_timer(qp);
- if (!iwqp->flush_issued) {
- iwqp->flush_issued = 1;
- issue_flush = 1;
- }
- } else if ((original_hw_tcp_state == I40IW_TCP_STATE_CLOSE_WAIT) ||
- ((original_ibqp_state == IB_QPS_RTS) &&
- (last_ae == I40IW_AE_LLP_CONNECTION_RESET))) {
- issue_disconn = 1;
- if (last_ae == I40IW_AE_LLP_CONNECTION_RESET)
- disconn_status = -ECONNRESET;
- }
-
- if (((original_hw_tcp_state == I40IW_TCP_STATE_CLOSED) ||
- (original_hw_tcp_state == I40IW_TCP_STATE_TIME_WAIT) ||
- (last_ae == I40IW_AE_RDMAP_ROE_BAD_LLP_CLOSE) ||
- (last_ae == I40IW_AE_LLP_CONNECTION_RESET) ||
- iwdev->reset)) {
- issue_close = 1;
- iwqp->cm_id = NULL;
- if (!iwqp->flush_issued) {
- iwqp->flush_issued = 1;
- issue_flush = 1;
- }
- }
-
- spin_unlock_irqrestore(&iwqp->lock, flags);
- if (issue_flush && !iwqp->destroyed) {
- /* Flush the queues */
- i40iw_flush_wqes(iwdev, iwqp);
-
- if (qp->term_flags && iwqp->ibqp.event_handler) {
- ibevent.device = iwqp->ibqp.device;
- ibevent.event = (qp->eventtype == TERM_EVENT_QP_FATAL) ?
- IB_EVENT_QP_FATAL : IB_EVENT_QP_ACCESS_ERR;
- ibevent.element.qp = &iwqp->ibqp;
- iwqp->ibqp.event_handler(&ibevent, iwqp->ibqp.qp_context);
- }
- }
-
- if (cm_id && cm_id->event_handler) {
- if (issue_disconn) {
- ret = i40iw_send_cm_event(NULL,
- cm_id,
- IW_CM_EVENT_DISCONNECT,
- disconn_status);
-
- if (ret)
- i40iw_debug(&iwdev->sc_dev,
- I40IW_DEBUG_CM,
- "disconnect event failed %s: - cm_id = %p\n",
- __func__, cm_id);
- }
- if (issue_close) {
- i40iw_qp_disconnect(iwqp);
- cm_id->provider_data = iwqp;
- ret = i40iw_send_cm_event(NULL, cm_id, IW_CM_EVENT_CLOSE, 0);
- if (ret)
- i40iw_debug(&iwdev->sc_dev,
- I40IW_DEBUG_CM,
- "close event failed %s: - cm_id = %p\n",
- __func__, cm_id);
- cm_id->rem_ref(cm_id);
- }
- }
-}
-
-/**
- * i40iw_disconnect_worker - worker for connection close
- * @work: points or disconn structure
- */
-static void i40iw_disconnect_worker(struct work_struct *work)
-{
- struct disconn_work *dwork = container_of(work, struct disconn_work, work);
- struct i40iw_qp *iwqp = dwork->iwqp;
-
- kfree(dwork);
- i40iw_cm_disconn_true(iwqp);
- i40iw_qp_rem_ref(&iwqp->ibqp);
-}
-
-/**
- * i40iw_accept - registered call for connection to be accepted
- * @cm_id: cm information for passive connection
- * @conn_param: accpet parameters
- */
-int i40iw_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
-{
- struct ib_qp *ibqp;
- struct i40iw_qp *iwqp;
- struct i40iw_device *iwdev;
- struct i40iw_sc_dev *dev;
- struct i40iw_cm_core *cm_core;
- struct i40iw_cm_node *cm_node;
- struct ib_qp_attr attr;
- int passive_state;
- struct ib_mr *ibmr;
- struct i40iw_pd *iwpd;
- u16 buf_len = 0;
- struct i40iw_kmem_info accept;
- enum i40iw_status_code status;
- u64 tagged_offset;
- unsigned long flags;
-
- memset(&attr, 0, sizeof(attr));
- ibqp = i40iw_get_qp(cm_id->device, conn_param->qpn);
- if (!ibqp)
- return -EINVAL;
-
- iwqp = to_iwqp(ibqp);
- iwdev = iwqp->iwdev;
- dev = &iwdev->sc_dev;
- cm_core = &iwdev->cm_core;
- cm_node = (struct i40iw_cm_node *)cm_id->provider_data;
-
- if (((struct sockaddr_in *)&cm_id->local_addr)->sin_family == AF_INET) {
- cm_node->ipv4 = true;
- cm_node->vlan_id = i40iw_get_vlan_ipv4(cm_node->loc_addr);
- } else {
- cm_node->ipv4 = false;
- i40iw_netdev_vlan_ipv6(cm_node->loc_addr, &cm_node->vlan_id);
- }
- i40iw_debug(cm_node->dev,
- I40IW_DEBUG_CM,
- "Accept vlan_id=%d\n",
- cm_node->vlan_id);
- if (cm_node->state == I40IW_CM_STATE_LISTENER_DESTROYED) {
- if (cm_node->loopbackpartner)
- i40iw_rem_ref_cm_node(cm_node->loopbackpartner);
- i40iw_rem_ref_cm_node(cm_node);
- return -EINVAL;
- }
-
- passive_state = atomic_inc_return(&cm_node->passive_state);
- if (passive_state == I40IW_SEND_RESET_EVENT) {
- i40iw_rem_ref_cm_node(cm_node);
- return -ECONNRESET;
- }
-
- cm_node->cm_core->stats_accepts++;
- iwqp->cm_node = (void *)cm_node;
- cm_node->iwqp = iwqp;
-
- buf_len = conn_param->private_data_len + I40IW_MAX_IETF_SIZE;
-
- status = i40iw_allocate_dma_mem(dev->hw, &iwqp->ietf_mem, buf_len, 1);
-
- if (status)
- return -ENOMEM;
- cm_node->pdata.size = conn_param->private_data_len;
- accept.addr = iwqp->ietf_mem.va;
- accept.size = i40iw_cm_build_mpa_frame(cm_node, &accept, MPA_KEY_REPLY);
- memcpy(accept.addr + accept.size, conn_param->private_data,
- conn_param->private_data_len);
-
- /* setup our first outgoing iWarp send WQE (the IETF frame response) */
- if ((cm_node->ipv4 &&
- !i40iw_ipv4_is_loopback(cm_node->loc_addr[0], cm_node->rem_addr[0])) ||
- (!cm_node->ipv4 &&
- !i40iw_ipv6_is_loopback(cm_node->loc_addr, cm_node->rem_addr))) {
- iwpd = iwqp->iwpd;
- tagged_offset = (uintptr_t)iwqp->ietf_mem.va;
- ibmr = i40iw_reg_phys_mr(&iwpd->ibpd,
- iwqp->ietf_mem.pa,
- buf_len,
- IB_ACCESS_LOCAL_WRITE,
- &tagged_offset);
- if (IS_ERR(ibmr)) {
- i40iw_free_dma_mem(dev->hw, &iwqp->ietf_mem);
- return -ENOMEM;
- }
-
- ibmr->pd = &iwpd->ibpd;
- ibmr->device = iwpd->ibpd.device;
- iwqp->lsmm_mr = ibmr;
- if (iwqp->page)
- iwqp->sc_qp.qp_uk.sq_base = kmap(iwqp->page);
- dev->iw_priv_qp_ops->qp_send_lsmm(&iwqp->sc_qp,
- iwqp->ietf_mem.va,
- (accept.size + conn_param->private_data_len),
- ibmr->lkey);
-
- } else {
- if (iwqp->page)
- iwqp->sc_qp.qp_uk.sq_base = kmap(iwqp->page);
- dev->iw_priv_qp_ops->qp_send_lsmm(&iwqp->sc_qp, NULL, 0, 0);
- }
-
- if (iwqp->page)
- kunmap(iwqp->page);
-
- iwqp->cm_id = cm_id;
- cm_node->cm_id = cm_id;
-
- cm_id->provider_data = (void *)iwqp;
- iwqp->active_conn = 0;
-
- cm_node->lsmm_size = accept.size + conn_param->private_data_len;
- i40iw_cm_init_tsa_conn(iwqp, cm_node);
- cm_id->add_ref(cm_id);
- i40iw_qp_add_ref(&iwqp->ibqp);
-
- attr.qp_state = IB_QPS_RTS;
- cm_node->qhash_set = false;
- i40iw_modify_qp(&iwqp->ibqp, &attr, IB_QP_STATE, NULL);
-
- cm_node->accelerated = true;
- spin_lock_irqsave(&cm_core->ht_lock, flags);
- list_move_tail(&cm_node->list, &cm_core->accelerated_list);
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
-
- status =
- i40iw_send_cm_event(cm_node, cm_id, IW_CM_EVENT_ESTABLISHED, 0);
- if (status)
- i40iw_debug(dev, I40IW_DEBUG_CM, "error sending cm event - ESTABLISHED\n");
-
- if (cm_node->loopbackpartner) {
- cm_node->loopbackpartner->pdata.size = conn_param->private_data_len;
-
- /* copy entire MPA frame to our cm_node's frame */
- memcpy(cm_node->loopbackpartner->pdata_buf,
- conn_param->private_data,
- conn_param->private_data_len);
- i40iw_create_event(cm_node->loopbackpartner, I40IW_CM_EVENT_CONNECTED);
- }
-
- if (cm_node->accept_pend) {
- atomic_dec(&cm_node->listener->pend_accepts_cnt);
- cm_node->accept_pend = 0;
- }
- return 0;
-}
-
-/**
- * i40iw_reject - registered call for connection to be rejected
- * @cm_id: cm information for passive connection
- * @pdata: private data to be sent
- * @pdata_len: private data length
- */
-int i40iw_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
-{
- struct i40iw_device *iwdev;
- struct i40iw_cm_node *cm_node;
- struct i40iw_cm_node *loopback;
-
- cm_node = (struct i40iw_cm_node *)cm_id->provider_data;
- loopback = cm_node->loopbackpartner;
- cm_node->cm_id = cm_id;
- cm_node->pdata.size = pdata_len;
-
- iwdev = to_iwdev(cm_id->device);
- if (!iwdev)
- return -EINVAL;
- cm_node->cm_core->stats_rejects++;
-
- if (pdata_len + sizeof(struct ietf_mpa_v2) > MAX_CM_BUFFER)
- return -EINVAL;
-
- if (loopback) {
- memcpy(&loopback->pdata_buf, pdata, pdata_len);
- loopback->pdata.size = pdata_len;
- }
-
- return i40iw_cm_reject(cm_node, pdata, pdata_len);
-}
-
-/**
- * i40iw_connect - registered call for connection to be established
- * @cm_id: cm information for passive connection
- * @conn_param: Information about the connection
- */
-int i40iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
-{
- struct ib_qp *ibqp;
- struct i40iw_qp *iwqp;
- struct i40iw_device *iwdev;
- struct i40iw_cm_node *cm_node;
- struct i40iw_cm_info cm_info;
- struct sockaddr_in *laddr;
- struct sockaddr_in *raddr;
- struct sockaddr_in6 *laddr6;
- struct sockaddr_in6 *raddr6;
- int ret = 0;
-
- ibqp = i40iw_get_qp(cm_id->device, conn_param->qpn);
- if (!ibqp)
- return -EINVAL;
- iwqp = to_iwqp(ibqp);
- if (!iwqp)
- return -EINVAL;
- iwdev = to_iwdev(iwqp->ibqp.device);
- if (!iwdev)
- return -EINVAL;
-
- laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
- raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
- laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
- raddr6 = (struct sockaddr_in6 *)&cm_id->m_remote_addr;
-
- if (!(laddr->sin_port) || !(raddr->sin_port))
- return -EINVAL;
-
- iwqp->active_conn = 1;
- iwqp->cm_id = NULL;
- cm_id->provider_data = iwqp;
-
- /* set up the connection params for the node */
- if (cm_id->remote_addr.ss_family == AF_INET) {
- cm_info.ipv4 = true;
- memset(cm_info.loc_addr, 0, sizeof(cm_info.loc_addr));
- memset(cm_info.rem_addr, 0, sizeof(cm_info.rem_addr));
- cm_info.loc_addr[0] = ntohl(laddr->sin_addr.s_addr);
- cm_info.rem_addr[0] = ntohl(raddr->sin_addr.s_addr);
- cm_info.loc_port = ntohs(laddr->sin_port);
- cm_info.rem_port = ntohs(raddr->sin_port);
- cm_info.vlan_id = i40iw_get_vlan_ipv4(cm_info.loc_addr);
- } else {
- cm_info.ipv4 = false;
- i40iw_copy_ip_ntohl(cm_info.loc_addr,
- laddr6->sin6_addr.in6_u.u6_addr32);
- i40iw_copy_ip_ntohl(cm_info.rem_addr,
- raddr6->sin6_addr.in6_u.u6_addr32);
- cm_info.loc_port = ntohs(laddr6->sin6_port);
- cm_info.rem_port = ntohs(raddr6->sin6_port);
- i40iw_netdev_vlan_ipv6(cm_info.loc_addr, &cm_info.vlan_id);
- }
- cm_info.cm_id = cm_id;
- cm_info.tos = cm_id->tos;
- cm_info.user_pri = rt_tos2priority(cm_id->tos);
- i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_DCB, "%s TOS:[%d] UP:[%d]\n",
- __func__, cm_id->tos, cm_info.user_pri);
- cm_id->add_ref(cm_id);
- cm_node = i40iw_create_cm_node(&iwdev->cm_core, iwdev,
- conn_param, &cm_info);
-
- if (IS_ERR(cm_node)) {
- ret = PTR_ERR(cm_node);
- cm_id->rem_ref(cm_id);
- return ret;
- }
-
- if ((cm_info.ipv4 && (laddr->sin_addr.s_addr != raddr->sin_addr.s_addr)) ||
- (!cm_info.ipv4 && memcmp(laddr6->sin6_addr.in6_u.u6_addr32,
- raddr6->sin6_addr.in6_u.u6_addr32,
- sizeof(laddr6->sin6_addr.in6_u.u6_addr32)))) {
- if (i40iw_manage_qhash(iwdev, &cm_info, I40IW_QHASH_TYPE_TCP_ESTABLISHED,
- I40IW_QHASH_MANAGE_TYPE_ADD, NULL, true)) {
- ret = -EINVAL;
- goto err;
- }
- cm_node->qhash_set = true;
- }
-
- if (i40iw_manage_apbvt(iwdev, cm_info.loc_port,
- I40IW_MANAGE_APBVT_ADD)) {
- ret = -EINVAL;
- goto err;
- }
-
- cm_node->apbvt_set = true;
- iwqp->cm_node = cm_node;
- cm_node->iwqp = iwqp;
- iwqp->cm_id = cm_id;
- i40iw_qp_add_ref(&iwqp->ibqp);
-
- if (cm_node->state != I40IW_CM_STATE_OFFLOADED) {
- cm_node->state = I40IW_CM_STATE_SYN_SENT;
- ret = i40iw_send_syn(cm_node, 0);
- if (ret)
- goto err;
- }
-
- if (cm_node->loopbackpartner) {
- cm_node->loopbackpartner->state = I40IW_CM_STATE_MPAREQ_RCVD;
- i40iw_create_event(cm_node->loopbackpartner,
- I40IW_CM_EVENT_MPA_REQ);
- }
-
- i40iw_debug(cm_node->dev,
- I40IW_DEBUG_CM,
- "Api - connect(): port=0x%04x, cm_node=%p, cm_id = %p.\n",
- cm_node->rem_port,
- cm_node,
- cm_node->cm_id);
-
- return 0;
-
-err:
- if (cm_info.ipv4)
- i40iw_debug(&iwdev->sc_dev,
- I40IW_DEBUG_CM,
- "Api - connect() FAILED: dest addr=%pI4",
- cm_info.rem_addr);
- else
- i40iw_debug(&iwdev->sc_dev,
- I40IW_DEBUG_CM,
- "Api - connect() FAILED: dest addr=%pI6",
- cm_info.rem_addr);
-
- i40iw_rem_ref_cm_node(cm_node);
- cm_id->rem_ref(cm_id);
- iwdev->cm_core.stats_connect_errs++;
- return ret;
-}
-
-/**
- * i40iw_create_listen - registered call creating listener
- * @cm_id: cm information for passive connection
- * @backlog: to max accept pending count
- */
-int i40iw_create_listen(struct iw_cm_id *cm_id, int backlog)
-{
- struct i40iw_device *iwdev;
- struct i40iw_cm_listener *cm_listen_node;
- struct i40iw_cm_info cm_info;
- enum i40iw_status_code ret;
- struct sockaddr_in *laddr;
- struct sockaddr_in6 *laddr6;
- bool wildcard = false;
-
- iwdev = to_iwdev(cm_id->device);
- if (!iwdev)
- return -EINVAL;
-
- laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
- laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
- memset(&cm_info, 0, sizeof(cm_info));
- if (laddr->sin_family == AF_INET) {
- cm_info.ipv4 = true;
- cm_info.loc_addr[0] = ntohl(laddr->sin_addr.s_addr);
- cm_info.loc_port = ntohs(laddr->sin_port);
-
- if (laddr->sin_addr.s_addr != INADDR_ANY)
- cm_info.vlan_id = i40iw_get_vlan_ipv4(cm_info.loc_addr);
- else
- wildcard = true;
-
- } else {
- cm_info.ipv4 = false;
- i40iw_copy_ip_ntohl(cm_info.loc_addr,
- laddr6->sin6_addr.in6_u.u6_addr32);
- cm_info.loc_port = ntohs(laddr6->sin6_port);
- if (ipv6_addr_type(&laddr6->sin6_addr) != IPV6_ADDR_ANY)
- i40iw_netdev_vlan_ipv6(cm_info.loc_addr,
- &cm_info.vlan_id);
- else
- wildcard = true;
- }
- cm_info.backlog = backlog;
- cm_info.cm_id = cm_id;
-
- cm_listen_node = i40iw_make_listen_node(&iwdev->cm_core, iwdev, &cm_info);
- if (!cm_listen_node) {
- i40iw_pr_err("cm_listen_node == NULL\n");
- return -ENOMEM;
- }
-
- cm_id->provider_data = cm_listen_node;
-
- cm_listen_node->tos = cm_id->tos;
- cm_listen_node->user_pri = rt_tos2priority(cm_id->tos);
- cm_info.user_pri = cm_listen_node->user_pri;
-
- if (!cm_listen_node->reused_node) {
- if (wildcard) {
- if (cm_info.ipv4)
- ret = i40iw_add_mqh_4(iwdev,
- &cm_info,
- cm_listen_node);
- else
- ret = i40iw_add_mqh_6(iwdev,
- &cm_info,
- cm_listen_node);
- if (ret)
- goto error;
-
- ret = i40iw_manage_apbvt(iwdev,
- cm_info.loc_port,
- I40IW_MANAGE_APBVT_ADD);
-
- if (ret)
- goto error;
- } else {
- ret = i40iw_manage_qhash(iwdev,
- &cm_info,
- I40IW_QHASH_TYPE_TCP_SYN,
- I40IW_QHASH_MANAGE_TYPE_ADD,
- NULL,
- true);
- if (ret)
- goto error;
- cm_listen_node->qhash_set = true;
- ret = i40iw_manage_apbvt(iwdev,
- cm_info.loc_port,
- I40IW_MANAGE_APBVT_ADD);
- if (ret)
- goto error;
- }
- }
- cm_id->add_ref(cm_id);
- cm_listen_node->cm_core->stats_listen_created++;
- return 0;
- error:
- i40iw_cm_del_listen(&iwdev->cm_core, (void *)cm_listen_node, false);
- return -EINVAL;
-}
-
-/**
- * i40iw_destroy_listen - registered call to destroy listener
- * @cm_id: cm information for passive connection
- */
-int i40iw_destroy_listen(struct iw_cm_id *cm_id)
-{
- struct i40iw_device *iwdev;
-
- iwdev = to_iwdev(cm_id->device);
- if (cm_id->provider_data)
- i40iw_cm_del_listen(&iwdev->cm_core, cm_id->provider_data, true);
- else
- i40iw_pr_err("cm_id->provider_data was NULL\n");
-
- cm_id->rem_ref(cm_id);
-
- return 0;
-}
-
-/**
- * i40iw_cm_event_connected - handle connected active node
- * @event: the info for cm_node of connection
- */
-static void i40iw_cm_event_connected(struct i40iw_cm_event *event)
-{
- struct i40iw_qp *iwqp;
- struct i40iw_device *iwdev;
- struct i40iw_cm_core *cm_core;
- struct i40iw_cm_node *cm_node;
- struct i40iw_sc_dev *dev;
- struct ib_qp_attr attr;
- struct iw_cm_id *cm_id;
- unsigned long flags;
- int status;
- bool read0;
-
- cm_node = event->cm_node;
- cm_id = cm_node->cm_id;
- iwqp = (struct i40iw_qp *)cm_id->provider_data;
- iwdev = to_iwdev(iwqp->ibqp.device);
- dev = &iwdev->sc_dev;
- cm_core = &iwdev->cm_core;
-
- if (iwqp->destroyed) {
- status = -ETIMEDOUT;
- goto error;
- }
- i40iw_cm_init_tsa_conn(iwqp, cm_node);
- read0 = (cm_node->send_rdma0_op == SEND_RDMA_READ_ZERO);
- if (iwqp->page)
- iwqp->sc_qp.qp_uk.sq_base = kmap(iwqp->page);
- dev->iw_priv_qp_ops->qp_send_rtt(&iwqp->sc_qp, read0);
- if (iwqp->page)
- kunmap(iwqp->page);
-
- memset(&attr, 0, sizeof(attr));
- attr.qp_state = IB_QPS_RTS;
- cm_node->qhash_set = false;
- i40iw_modify_qp(&iwqp->ibqp, &attr, IB_QP_STATE, NULL);
-
- cm_node->accelerated = true;
- spin_lock_irqsave(&cm_core->ht_lock, flags);
- list_move_tail(&cm_node->list, &cm_core->accelerated_list);
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
- status = i40iw_send_cm_event(cm_node, cm_id, IW_CM_EVENT_CONNECT_REPLY,
- 0);
- if (status)
- i40iw_debug(dev, I40IW_DEBUG_CM, "error sending cm event - CONNECT_REPLY\n");
-
- return;
-
-error:
- iwqp->cm_id = NULL;
- cm_id->provider_data = NULL;
- i40iw_send_cm_event(event->cm_node,
- cm_id,
- IW_CM_EVENT_CONNECT_REPLY,
- status);
- cm_id->rem_ref(cm_id);
- i40iw_rem_ref_cm_node(event->cm_node);
-}
-
-/**
- * i40iw_cm_event_reset - handle reset
- * @event: the info for cm_node of connection
- */
-static void i40iw_cm_event_reset(struct i40iw_cm_event *event)
-{
- struct i40iw_cm_node *cm_node = event->cm_node;
- struct iw_cm_id *cm_id = cm_node->cm_id;
- struct i40iw_qp *iwqp;
-
- if (!cm_id)
- return;
-
- iwqp = cm_id->provider_data;
- if (!iwqp)
- return;
-
- i40iw_debug(cm_node->dev,
- I40IW_DEBUG_CM,
- "reset event %p - cm_id = %p\n",
- event->cm_node, cm_id);
- iwqp->cm_id = NULL;
-
- i40iw_send_cm_event(cm_node, cm_node->cm_id, IW_CM_EVENT_DISCONNECT, -ECONNRESET);
- i40iw_send_cm_event(cm_node, cm_node->cm_id, IW_CM_EVENT_CLOSE, 0);
-}
-
-/**
- * i40iw_cm_event_handler - worker thread callback to send event to cm upper layer
- * @work: pointer of cm event info.
- */
-static void i40iw_cm_event_handler(struct work_struct *work)
-{
- struct i40iw_cm_event *event = container_of(work,
- struct i40iw_cm_event,
- event_work);
- struct i40iw_cm_node *cm_node;
-
- if (!event || !event->cm_node || !event->cm_node->cm_core)
- return;
-
- cm_node = event->cm_node;
-
- switch (event->type) {
- case I40IW_CM_EVENT_MPA_REQ:
- i40iw_send_cm_event(cm_node,
- cm_node->cm_id,
- IW_CM_EVENT_CONNECT_REQUEST,
- 0);
- break;
- case I40IW_CM_EVENT_RESET:
- i40iw_cm_event_reset(event);
- break;
- case I40IW_CM_EVENT_CONNECTED:
- if (!event->cm_node->cm_id ||
- (event->cm_node->state != I40IW_CM_STATE_OFFLOADED))
- break;
- i40iw_cm_event_connected(event);
- break;
- case I40IW_CM_EVENT_MPA_REJECT:
- if (!event->cm_node->cm_id ||
- (cm_node->state == I40IW_CM_STATE_OFFLOADED))
- break;
- i40iw_send_cm_event(cm_node,
- cm_node->cm_id,
- IW_CM_EVENT_CONNECT_REPLY,
- -ECONNREFUSED);
- break;
- case I40IW_CM_EVENT_ABORTED:
- if (!event->cm_node->cm_id ||
- (event->cm_node->state == I40IW_CM_STATE_OFFLOADED))
- break;
- i40iw_event_connect_error(event);
- break;
- default:
- i40iw_pr_err("event type = %d\n", event->type);
- break;
- }
-
- event->cm_info.cm_id->rem_ref(event->cm_info.cm_id);
- i40iw_rem_ref_cm_node(event->cm_node);
- kfree(event);
-}
-
-/**
- * i40iw_cm_post_event - queue event request for worker thread
- * @event: cm node's info for up event call
- */
-static void i40iw_cm_post_event(struct i40iw_cm_event *event)
-{
- atomic_inc(&event->cm_node->ref_count);
- event->cm_info.cm_id->add_ref(event->cm_info.cm_id);
- INIT_WORK(&event->event_work, i40iw_cm_event_handler);
-
- queue_work(event->cm_node->cm_core->event_wq, &event->event_work);
-}
-
-/**
- * i40iw_qhash_ctrl - enable/disable qhash for list
- * @iwdev: device pointer
- * @parent_listen_node: parent listen node
- * @nfo: cm info node
- * @ipaddr: Pointer to IPv4 or IPv6 address
- * @ipv4: flag indicating IPv4 when true
- * @ifup: flag indicating interface up when true
- *
- * Enables or disables the qhash for the node in the child
- * listen list that matches ipaddr. If no matching IP was found
- * it will allocate and add a new child listen node to the
- * parent listen node. The listen_list_lock is assumed to be
- * held when called.
- */
-static void i40iw_qhash_ctrl(struct i40iw_device *iwdev,
- struct i40iw_cm_listener *parent_listen_node,
- struct i40iw_cm_info *nfo,
- u32 *ipaddr, bool ipv4, bool ifup)
-{
- struct list_head *child_listen_list = &parent_listen_node->child_listen_list;
- struct i40iw_cm_listener *child_listen_node;
- struct list_head *pos, *tpos;
- enum i40iw_status_code ret;
- bool node_allocated = false;
- enum i40iw_quad_hash_manage_type op =
- ifup ? I40IW_QHASH_MANAGE_TYPE_ADD : I40IW_QHASH_MANAGE_TYPE_DELETE;
-
- list_for_each_safe(pos, tpos, child_listen_list) {
- child_listen_node =
- list_entry(pos,
- struct i40iw_cm_listener,
- child_listen_list);
- if (!memcmp(child_listen_node->loc_addr, ipaddr, ipv4 ? 4 : 16))
- goto set_qhash;
- }
-
- /* if not found then add a child listener if interface is going up */
- if (!ifup)
- return;
- 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->loc_addr, ipaddr, ipv4 ? 4 : 16);
-
-set_qhash:
- memcpy(nfo->loc_addr,
- child_listen_node->loc_addr,
- sizeof(nfo->loc_addr));
- nfo->vlan_id = child_listen_node->vlan_id;
- ret = i40iw_manage_qhash(iwdev, nfo,
- I40IW_QHASH_TYPE_TCP_SYN,
- op,
- NULL, false);
- if (!ret) {
- child_listen_node->qhash_set = ifup;
- if (node_allocated)
- list_add(&child_listen_node->child_listen_list,
- &parent_listen_node->child_listen_list);
- } else if (node_allocated) {
- kfree(child_listen_node);
- }
-}
-
-/**
- * i40iw_cm_teardown_connections - teardown QPs
- * @iwdev: device pointer
- * @ipaddr: Pointer to IPv4 or IPv6 address
- * @nfo: cm info node
- * @disconnect_all: flag indicating disconnect all QPs
- * teardown QPs where source or destination addr matches ip addr
- */
-void i40iw_cm_teardown_connections(struct i40iw_device *iwdev, u32 *ipaddr,
- struct i40iw_cm_info *nfo,
- bool disconnect_all)
-{
- struct i40iw_cm_core *cm_core = &iwdev->cm_core;
- struct list_head *list_core_temp;
- struct list_head *list_node;
- struct i40iw_cm_node *cm_node;
- unsigned long flags;
- struct list_head teardown_list;
- struct ib_qp_attr attr;
-
- INIT_LIST_HEAD(&teardown_list);
- spin_lock_irqsave(&cm_core->ht_lock, flags);
- list_for_each_safe(list_node, list_core_temp,
- &cm_core->accelerated_list) {
- cm_node = container_of(list_node, struct i40iw_cm_node, list);
- if (disconnect_all ||
- (nfo->vlan_id == cm_node->vlan_id &&
- (!memcmp(cm_node->loc_addr, ipaddr, nfo->ipv4 ? 4 : 16) ||
- !memcmp(cm_node->rem_addr, ipaddr, nfo->ipv4 ? 4 : 16)))) {
- atomic_inc(&cm_node->ref_count);
- list_add(&cm_node->teardown_entry, &teardown_list);
- }
- }
- list_for_each_safe(list_node, list_core_temp,
- &cm_core->non_accelerated_list) {
- cm_node = container_of(list_node, struct i40iw_cm_node, list);
- if (disconnect_all ||
- (nfo->vlan_id == cm_node->vlan_id &&
- (!memcmp(cm_node->loc_addr, ipaddr, nfo->ipv4 ? 4 : 16) ||
- !memcmp(cm_node->rem_addr, ipaddr, nfo->ipv4 ? 4 : 16)))) {
- atomic_inc(&cm_node->ref_count);
- list_add(&cm_node->teardown_entry, &teardown_list);
- }
- }
- spin_unlock_irqrestore(&cm_core->ht_lock, flags);
-
- list_for_each_safe(list_node, list_core_temp, &teardown_list) {
- cm_node = container_of(list_node, struct i40iw_cm_node,
- teardown_entry);
- attr.qp_state = IB_QPS_ERR;
- i40iw_modify_qp(&cm_node->iwqp->ibqp, &attr, IB_QP_STATE, NULL);
- if (iwdev->reset)
- i40iw_cm_disconn(cm_node->iwqp);
- i40iw_rem_ref_cm_node(cm_node);
- }
-}
-
-/**
- * i40iw_if_notify - process an ifdown on an interface
- * @iwdev: device pointer
- * @netdev: network interface device structure
- * @ipaddr: Pointer to IPv4 or IPv6 address
- * @ipv4: flag indicating IPv4 when true
- * @ifup: flag indicating interface up when true
- */
-void i40iw_if_notify(struct i40iw_device *iwdev, struct net_device *netdev,
- u32 *ipaddr, bool ipv4, bool ifup)
-{
- struct i40iw_cm_core *cm_core = &iwdev->cm_core;
- unsigned long flags;
- struct i40iw_cm_listener *listen_node;
- static const u32 ip_zero[4] = { 0, 0, 0, 0 };
- struct i40iw_cm_info nfo;
- u16 vlan_id = rdma_vlan_dev_vlan_id(netdev);
- enum i40iw_status_code ret;
- enum i40iw_quad_hash_manage_type op =
- ifup ? I40IW_QHASH_MANAGE_TYPE_ADD : I40IW_QHASH_MANAGE_TYPE_DELETE;
-
- nfo.vlan_id = vlan_id;
- nfo.ipv4 = ipv4;
-
- /* Disable or enable qhash for listeners */
- spin_lock_irqsave(&cm_core->listen_list_lock, flags);
- list_for_each_entry(listen_node, &cm_core->listen_nodes, list) {
- if (vlan_id == listen_node->vlan_id &&
- (!memcmp(listen_node->loc_addr, ipaddr, ipv4 ? 4 : 16) ||
- !memcmp(listen_node->loc_addr, ip_zero, ipv4 ? 4 : 16))) {
- memcpy(nfo.loc_addr, listen_node->loc_addr,
- sizeof(nfo.loc_addr));
- nfo.loc_port = listen_node->loc_port;
- nfo.user_pri = listen_node->user_pri;
- if (!list_empty(&listen_node->child_listen_list)) {
- i40iw_qhash_ctrl(iwdev,
- listen_node,
- &nfo,
- ipaddr, ipv4, ifup);
- } else if (memcmp(listen_node->loc_addr, ip_zero,
- ipv4 ? 4 : 16)) {
- ret = i40iw_manage_qhash(iwdev,
- &nfo,
- I40IW_QHASH_TYPE_TCP_SYN,
- op,
- NULL,
- false);
- if (!ret)
- listen_node->qhash_set = ifup;
- }
- }
- }
- spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
-
- /* teardown connected qp's on ifdown */
- if (!ifup)
- i40iw_cm_teardown_connections(iwdev, ipaddr, &nfo, false);
-}
diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.h b/drivers/infiniband/hw/i40iw/i40iw_cm.h
deleted file mode 100644
index 6e43e4d730f4..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_cm.h
+++ /dev/null
@@ -1,462 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_CM_H
-#define I40IW_CM_H
-
-#define QUEUE_EVENTS
-
-#define I40IW_MANAGE_APBVT_DEL 0
-#define I40IW_MANAGE_APBVT_ADD 1
-
-#define I40IW_MPA_REQUEST_ACCEPT 1
-#define I40IW_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
-#define SNDMARKER_SEQNMASK 0x000001FF
-
-#define I40IW_MAX_IETF_SIZE 32
-
-/* 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
-
-/* HW-supported IRD sizes*/
-#define I40IW_HW_IRD_SETTING_2 2
-#define I40IW_HW_IRD_SETTING_4 4
-#define I40IW_HW_IRD_SETTING_8 8
-#define I40IW_HW_IRD_SETTING_16 16
-#define I40IW_HW_IRD_SETTING_32 32
-#define I40IW_HW_IRD_SETTING_64 64
-
-#define MAX_PORTS 65536
-#define I40IW_VLAN_PRIO_SHIFT 13
-
-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[];
-};
-
-#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[];
-};
-
-struct i40iw_cm_node;
-enum i40iw_timer_type {
- I40IW_TIMER_TYPE_SEND,
- I40IW_TIMER_TYPE_RECV,
- I40IW_TIMER_NODE_CLEANUP,
- I40IW_TIMER_TYPE_CLOSE,
-};
-
-#define I40IW_PASSIVE_STATE_INDICATED 0
-#define I40IW_DO_NOT_SEND_RESET_EVENT 1
-#define I40IW_SEND_RESET_EVENT 2
-
-#define MAX_I40IW_IFS 4
-
-#define SET_ACK 0x1
-#define SET_SYN 0x2
-#define SET_FIN 0x4
-#define SET_RST 0x8
-
-#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 i40iw_timer_entry {
- struct list_head list;
- unsigned long timetosend; /* jiffies */
- struct i40iw_puda_buf *sqbuf;
- u32 type;
- u32 retrycount;
- u32 retranscount;
- u32 context;
- u32 send_retrans;
- int close_when_complete;
-};
-
-#define I40IW_DEFAULT_RETRYS 64
-#define I40IW_DEFAULT_RETRANS 8
-#define I40IW_DEFAULT_TTL 0x40
-#define I40IW_DEFAULT_RTT_VAR 0x6
-#define I40IW_DEFAULT_SS_THRESH 0x3FFFFFFF
-#define I40IW_DEFAULT_REXMIT_THRESH 8
-
-#define I40IW_RETRY_TIMEOUT HZ
-#define I40IW_SHORT_TIME 10
-#define I40IW_LONG_TIME (2 * HZ)
-#define I40IW_MAX_TIMEOUT ((unsigned long)(12 * HZ))
-
-#define I40IW_CM_HASHTABLE_SIZE 1024
-#define I40IW_CM_TCP_TIMER_INTERVAL 3000
-#define I40IW_CM_DEFAULT_MTU 1540
-#define I40IW_CM_DEFAULT_FRAME_CNT 10
-#define I40IW_CM_THREAD_STACK_SIZE 256
-#define I40IW_CM_DEFAULT_RCV_WND 64240
-#define I40IW_CM_DEFAULT_RCV_WND_SCALED 0x3fffc
-#define I40IW_CM_DEFAULT_RCV_WND_SCALE 2
-#define I40IW_CM_DEFAULT_FREE_PKTS 0x000A
-#define I40IW_CM_FREE_PKT_LO_WATERMARK 2
-
-#define I40IW_CM_DEFAULT_MSS 536
-
-#define I40IW_CM_DEF_SEQ 0x159bf75f
-#define I40IW_CM_DEF_LOCAL_ID 0x3b47
-
-#define I40IW_CM_DEF_SEQ2 0x18ed5740
-#define I40IW_CM_DEF_LOCAL_ID2 0xb807
-#define MAX_CM_BUFFER (I40IW_MAX_IETF_SIZE + IETF_MAX_PRIV_DATA_LEN)
-
-typedef u32 i40iw_addr_t;
-
-#define i40iw_cm_tsa_context i40iw_qp_context
-
-struct i40iw_qp;
-
-/* cm node transition states */
-enum i40iw_cm_node_state {
- I40IW_CM_STATE_UNKNOWN,
- I40IW_CM_STATE_INITED,
- I40IW_CM_STATE_LISTENING,
- I40IW_CM_STATE_SYN_RCVD,
- I40IW_CM_STATE_SYN_SENT,
- I40IW_CM_STATE_ONE_SIDE_ESTABLISHED,
- I40IW_CM_STATE_ESTABLISHED,
- I40IW_CM_STATE_ACCEPTING,
- I40IW_CM_STATE_MPAREQ_SENT,
- I40IW_CM_STATE_MPAREQ_RCVD,
- I40IW_CM_STATE_MPAREJ_RCVD,
- I40IW_CM_STATE_OFFLOADED,
- I40IW_CM_STATE_FIN_WAIT1,
- I40IW_CM_STATE_FIN_WAIT2,
- I40IW_CM_STATE_CLOSE_WAIT,
- I40IW_CM_STATE_TIME_WAIT,
- I40IW_CM_STATE_LAST_ACK,
- I40IW_CM_STATE_CLOSING,
- I40IW_CM_STATE_LISTENER_DESTROYED,
- I40IW_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 i40iw_tcpip_pkt_type {
- I40IW_PKT_TYPE_UNKNOWN,
- I40IW_PKT_TYPE_SYN,
- I40IW_PKT_TYPE_SYNACK,
- I40IW_PKT_TYPE_ACK,
- I40IW_PKT_TYPE_FIN,
- I40IW_PKT_TYPE_RST
-};
-
-/* CM context params */
-struct i40iw_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;
-};
-
-enum i40iw_cm_listener_state {
- I40IW_CM_LISTENER_PASSIVE_STATE = 1,
- I40IW_CM_LISTENER_ACTIVE_STATE = 2,
- I40IW_CM_LISTENER_EITHER_STATE = 3
-};
-
-struct i40iw_cm_listener {
- struct list_head list;
- struct i40iw_cm_core *cm_core;
- u8 loc_mac[ETH_ALEN];
- u32 loc_addr[4];
- u16 loc_port;
- struct iw_cm_id *cm_id;
- atomic_t ref_count;
- struct i40iw_device *iwdev;
- atomic_t pend_accepts_cnt;
- int backlog;
- enum i40iw_cm_listener_state listener_state;
- u32 reused_node;
- u8 user_pri;
- u8 tos;
- u16 vlan_id;
- bool qhash_set;
- bool ipv4;
- struct list_head child_listen_list;
-
-};
-
-struct i40iw_kmem_info {
- void *addr;
- u32 size;
-};
-
-/* per connection node and node state information */
-struct i40iw_cm_node {
- u32 loc_addr[4], rem_addr[4];
- u16 loc_port, rem_port;
- u16 vlan_id;
- enum i40iw_cm_node_state state;
- u8 loc_mac[ETH_ALEN];
- u8 rem_mac[ETH_ALEN];
- atomic_t ref_count;
- struct i40iw_qp *iwqp;
- struct i40iw_device *iwdev;
- struct i40iw_sc_dev *dev;
- struct i40iw_cm_tcp_context tcp_cntxt;
- struct i40iw_cm_core *cm_core;
- struct i40iw_cm_node *loopbackpartner;
- struct i40iw_timer_entry *send_entry;
- struct i40iw_timer_entry *close_entry;
- spinlock_t retrans_list_lock; /* cm transmit packet */
- enum send_rdma0 send_rdma0_op;
- u16 ird_size;
- u16 ord_size;
- u16 mpav2_ird_ord;
- struct iw_cm_id *cm_id;
- struct list_head list;
- bool accelerated;
- struct i40iw_cm_listener *listener;
- int apbvt_set;
- int accept_pend;
- struct list_head timer_entry;
- struct list_head reset_entry;
- struct list_head teardown_entry;
- atomic_t passive_state;
- bool qhash_set;
- u8 user_pri;
- u8 tos;
- bool ipv4;
- bool snd_mark_en;
- u16 lsmm_size;
- enum mpa_frame_version mpa_frame_rev;
- struct i40iw_kmem_info pdata;
- union {
- struct ietf_mpa_v1 mpa_frame;
- struct ietf_mpa_v2 mpa_v2_frame;
- };
-
- u8 pdata_buf[IETF_MAX_PRIV_DATA_LEN];
- struct i40iw_kmem_info mpa_hdr;
- bool ack_rcvd;
-};
-
-/* structure for client or CM to fill when making CM api calls. */
-/* - only need to set relevant data, based on op. */
-struct i40iw_cm_info {
- struct iw_cm_id *cm_id;
- u16 loc_port;
- u16 rem_port;
- u32 loc_addr[4];
- u32 rem_addr[4];
- u16 vlan_id;
- int backlog;
- u8 user_pri;
- u8 tos;
- bool ipv4;
-};
-
-/* CM event codes */
-enum i40iw_cm_event_type {
- I40IW_CM_EVENT_UNKNOWN,
- I40IW_CM_EVENT_ESTABLISHED,
- I40IW_CM_EVENT_MPA_REQ,
- I40IW_CM_EVENT_MPA_CONNECT,
- I40IW_CM_EVENT_MPA_ACCEPT,
- I40IW_CM_EVENT_MPA_REJECT,
- I40IW_CM_EVENT_MPA_ESTABLISHED,
- I40IW_CM_EVENT_CONNECTED,
- I40IW_CM_EVENT_RESET,
- I40IW_CM_EVENT_ABORTED
-};
-
-/* event to post to CM event handler */
-struct i40iw_cm_event {
- enum i40iw_cm_event_type type;
- struct i40iw_cm_info cm_info;
- struct work_struct event_work;
- struct i40iw_cm_node *cm_node;
-};
-
-struct i40iw_cm_core {
- struct i40iw_device *iwdev;
- struct i40iw_sc_dev *dev;
-
- struct list_head listen_nodes;
- struct list_head accelerated_list;
- struct list_head non_accelerated_list;
-
- struct timer_list tcp_timer;
-
- struct workqueue_struct *event_wq;
- struct workqueue_struct *disconn_wq;
-
- spinlock_t ht_lock; /* manage hash table */
- spinlock_t listen_list_lock; /* listen list */
- spinlock_t apbvt_lock; /*manage apbvt entries*/
-
- unsigned long ports_in_use[BITS_TO_LONGS(MAX_PORTS)];
-
- u64 stats_nodes_created;
- u64 stats_nodes_destroyed;
- u64 stats_listen_created;
- u64 stats_listen_destroyed;
- u64 stats_listen_nodes_created;
- u64 stats_listen_nodes_destroyed;
- u64 stats_loopbacks;
- u64 stats_accepts;
- u64 stats_rejects;
- u64 stats_connect_errs;
- u64 stats_passive_errs;
- u64 stats_pkt_retrans;
- u64 stats_backlog_drops;
-};
-
-int i40iw_schedule_cm_timer(struct i40iw_cm_node *cm_node,
- struct i40iw_puda_buf *sqbuf,
- enum i40iw_timer_type type,
- int send_retrans,
- int close_when_complete);
-
-int i40iw_accept(struct iw_cm_id *, struct iw_cm_conn_param *);
-int i40iw_reject(struct iw_cm_id *, const void *, u8);
-int i40iw_connect(struct iw_cm_id *, struct iw_cm_conn_param *);
-int i40iw_create_listen(struct iw_cm_id *, int);
-int i40iw_destroy_listen(struct iw_cm_id *);
-
-int i40iw_cm_start(struct i40iw_device *);
-int i40iw_cm_stop(struct i40iw_device *);
-
-int i40iw_arp_table(struct i40iw_device *iwdev,
- u32 *ip_addr,
- bool ipv4,
- u8 *mac_addr,
- u32 action);
-
-void i40iw_if_notify(struct i40iw_device *iwdev, struct net_device *netdev,
- u32 *ipaddr, bool ipv4, bool ifup);
-void i40iw_cm_teardown_connections(struct i40iw_device *iwdev, u32 *ipaddr,
- struct i40iw_cm_info *nfo,
- bool disconnect_all);
-bool i40iw_port_in_use(struct i40iw_cm_core *cm_core, u16 port);
-#endif /* I40IW_CM_H */
diff --git a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c
deleted file mode 100644
index eaea5d545eb8..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c
+++ /dev/null
@@ -1,5243 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 "i40iw_osdep.h"
-#include "i40iw_register.h"
-#include "i40iw_status.h"
-#include "i40iw_hmc.h"
-
-#include "i40iw_d.h"
-#include "i40iw_type.h"
-#include "i40iw_p.h"
-#include "i40iw_vf.h"
-#include "i40iw_virtchnl.h"
-
-/**
- * i40iw_insert_wqe_hdr - write wqe header
- * @wqe: cqp wqe for header
- * @header: header for the cqp wqe
- */
-void i40iw_insert_wqe_hdr(u64 *wqe, u64 header)
-{
- wmb(); /* make sure WQE is populated before polarity is set */
- set_64bit_val(wqe, 24, header);
-}
-
-void i40iw_check_cqp_progress(struct i40iw_cqp_timeout *cqp_timeout, struct i40iw_sc_dev *dev)
-{
- if (cqp_timeout->compl_cqp_cmds != dev->cqp_cmd_stats[OP_COMPLETED_COMMANDS]) {
- cqp_timeout->compl_cqp_cmds = dev->cqp_cmd_stats[OP_COMPLETED_COMMANDS];
- cqp_timeout->count = 0;
- } else {
- if (dev->cqp_cmd_stats[OP_REQUESTED_COMMANDS] != cqp_timeout->compl_cqp_cmds)
- cqp_timeout->count++;
- }
-}
-
-/**
- * i40iw_get_cqp_reg_info - get head and tail for cqp using registers
- * @cqp: struct for cqp hw
- * @val: cqp tail register value
- * @tail:wqtail register value
- * @error: cqp processing err
- */
-static inline void i40iw_get_cqp_reg_info(struct i40iw_sc_cqp *cqp,
- u32 *val,
- u32 *tail,
- u32 *error)
-{
- if (cqp->dev->is_pf) {
- *val = i40iw_rd32(cqp->dev->hw, I40E_PFPE_CQPTAIL);
- *tail = RS_32(*val, I40E_PFPE_CQPTAIL_WQTAIL);
- *error = RS_32(*val, I40E_PFPE_CQPTAIL_CQP_OP_ERR);
- } else {
- *val = i40iw_rd32(cqp->dev->hw, I40E_VFPE_CQPTAIL1);
- *tail = RS_32(*val, I40E_VFPE_CQPTAIL_WQTAIL);
- *error = RS_32(*val, I40E_VFPE_CQPTAIL_CQP_OP_ERR);
- }
-}
-
-/**
- * i40iw_cqp_poll_registers - poll cqp registers
- * @cqp: struct for cqp hw
- * @tail:wqtail register value
- * @count: how many times to try for completion
- */
-static enum i40iw_status_code i40iw_cqp_poll_registers(
- struct i40iw_sc_cqp *cqp,
- u32 tail,
- u32 count)
-{
- u32 i = 0;
- u32 newtail, error, val;
-
- while (i < count) {
- i++;
- i40iw_get_cqp_reg_info(cqp, &val, &newtail, &error);
- if (error) {
- error = (cqp->dev->is_pf) ?
- i40iw_rd32(cqp->dev->hw, I40E_PFPE_CQPERRCODES) :
- i40iw_rd32(cqp->dev->hw, I40E_VFPE_CQPERRCODES1);
- return I40IW_ERR_CQP_COMPL_ERROR;
- }
- if (newtail != tail) {
- /* SUCCESS */
- I40IW_RING_MOVE_TAIL(cqp->sq_ring);
- cqp->dev->cqp_cmd_stats[OP_COMPLETED_COMMANDS]++;
- return 0;
- }
- udelay(I40IW_SLEEP_COUNT);
- }
- return I40IW_ERR_TIMEOUT;
-}
-
-/**
- * i40iw_sc_parse_fpm_commit_buf - parse fpm commit buffer
- * @buf: ptr to fpm commit buffer
- * @info: ptr to i40iw_hmc_obj_info struct
- * @sd: number of SDs for HMC objects
- *
- * parses fpm commit info and copy base value
- * of hmc objects in hmc_info
- */
-static enum i40iw_status_code i40iw_sc_parse_fpm_commit_buf(
- u64 *buf,
- struct i40iw_hmc_obj_info *info,
- u32 *sd)
-{
- u64 temp;
- u64 size;
- u64 base = 0;
- u32 i, j;
- u32 k = 0;
-
- /* copy base values in obj_info */
- for (i = I40IW_HMC_IW_QP, j = 0; i <= I40IW_HMC_IW_PBLE; i++, j += 8) {
- if ((i == I40IW_HMC_IW_SRQ) ||
- (i == I40IW_HMC_IW_FSIMC) ||
- (i == I40IW_HMC_IW_FSIAV)) {
- info[i].base = 0;
- info[i].cnt = 0;
- continue;
- }
- get_64bit_val(buf, j, &temp);
- info[i].base = RS_64_1(temp, 32) * 512;
- if (info[i].base > base) {
- base = info[i].base;
- k = i;
- }
- if (i == I40IW_HMC_IW_APBVT_ENTRY) {
- info[i].cnt = 1;
- continue;
- }
- if (i == I40IW_HMC_IW_QP)
- info[i].cnt = (u32)RS_64(temp, I40IW_QUERY_FPM_MAX_QPS);
- else if (i == I40IW_HMC_IW_CQ)
- info[i].cnt = (u32)RS_64(temp, I40IW_QUERY_FPM_MAX_CQS);
- else
- info[i].cnt = (u32)(temp);
- }
- size = info[k].cnt * info[k].size + info[k].base;
- if (size & 0x1FFFFF)
- *sd = (u32)((size >> 21) + 1); /* add 1 for remainder */
- else
- *sd = (u32)(size >> 21);
-
- return 0;
-}
-
-/**
- * i40iw_sc_decode_fpm_query() - Decode a 64 bit value into max count and size
- * @buf: ptr to fpm query buffer
- * @buf_idx: index into buf
- * @obj_info: ptr to i40iw_hmc_obj_info struct
- * @rsrc_idx: resource index into info
- *
- * Decode a 64 bit value from fpm query buffer into max count and size
- */
-static u64 i40iw_sc_decode_fpm_query(u64 *buf,
- u32 buf_idx,
- struct i40iw_hmc_obj_info *obj_info,
- u32 rsrc_idx)
-{
- u64 temp;
- u32 size;
-
- get_64bit_val(buf, buf_idx, &temp);
- obj_info[rsrc_idx].max_cnt = (u32)temp;
- size = (u32)RS_64_1(temp, 32);
- obj_info[rsrc_idx].size = LS_64_1(1, size);
-
- return temp;
-}
-
-/**
- * i40iw_sc_parse_fpm_query_buf() - parses fpm query buffer
- * @buf: ptr to fpm query buffer
- * @hmc_info: ptr to i40iw_hmc_obj_info struct
- * @hmc_fpm_misc: ptr to fpm data
- *
- * parses fpm query buffer and copy max_cnt and
- * size value of hmc objects in hmc_info
- */
-static enum i40iw_status_code i40iw_sc_parse_fpm_query_buf(
- u64 *buf,
- struct i40iw_hmc_info *hmc_info,
- struct i40iw_hmc_fpm_misc *hmc_fpm_misc)
-{
- struct i40iw_hmc_obj_info *obj_info;
- u64 temp;
- u32 size;
- u16 max_pe_sds;
-
- obj_info = hmc_info->hmc_obj;
-
- get_64bit_val(buf, 0, &temp);
- hmc_info->first_sd_index = (u16)RS_64(temp, I40IW_QUERY_FPM_FIRST_PE_SD_INDEX);
- max_pe_sds = (u16)RS_64(temp, I40IW_QUERY_FPM_MAX_PE_SDS);
-
- /* Reduce SD count for VFs by 1 to account for PBLE backing page rounding */
- if (hmc_info->hmc_fn_id >= I40IW_FIRST_VF_FPM_ID)
- max_pe_sds--;
- hmc_fpm_misc->max_sds = max_pe_sds;
- hmc_info->sd_table.sd_cnt = max_pe_sds + hmc_info->first_sd_index;
-
- get_64bit_val(buf, 8, &temp);
- obj_info[I40IW_HMC_IW_QP].max_cnt = (u32)RS_64(temp, I40IW_QUERY_FPM_MAX_QPS);
- size = (u32)RS_64_1(temp, 32);
- obj_info[I40IW_HMC_IW_QP].size = LS_64_1(1, size);
-
- get_64bit_val(buf, 16, &temp);
- obj_info[I40IW_HMC_IW_CQ].max_cnt = (u32)RS_64(temp, I40IW_QUERY_FPM_MAX_CQS);
- size = (u32)RS_64_1(temp, 32);
- obj_info[I40IW_HMC_IW_CQ].size = LS_64_1(1, size);
-
- i40iw_sc_decode_fpm_query(buf, 32, obj_info, I40IW_HMC_IW_HTE);
- i40iw_sc_decode_fpm_query(buf, 40, obj_info, I40IW_HMC_IW_ARP);
-
- obj_info[I40IW_HMC_IW_APBVT_ENTRY].size = 8192;
- obj_info[I40IW_HMC_IW_APBVT_ENTRY].max_cnt = 1;
-
- i40iw_sc_decode_fpm_query(buf, 48, obj_info, I40IW_HMC_IW_MR);
- i40iw_sc_decode_fpm_query(buf, 56, obj_info, I40IW_HMC_IW_XF);
-
- get_64bit_val(buf, 64, &temp);
- obj_info[I40IW_HMC_IW_XFFL].max_cnt = (u32)temp;
- obj_info[I40IW_HMC_IW_XFFL].size = 4;
- hmc_fpm_misc->xf_block_size = RS_64(temp, I40IW_QUERY_FPM_XFBLOCKSIZE);
- if (!hmc_fpm_misc->xf_block_size)
- return I40IW_ERR_INVALID_SIZE;
-
- i40iw_sc_decode_fpm_query(buf, 72, obj_info, I40IW_HMC_IW_Q1);
-
- get_64bit_val(buf, 80, &temp);
- obj_info[I40IW_HMC_IW_Q1FL].max_cnt = (u32)temp;
- obj_info[I40IW_HMC_IW_Q1FL].size = 4;
- hmc_fpm_misc->q1_block_size = RS_64(temp, I40IW_QUERY_FPM_Q1BLOCKSIZE);
- if (!hmc_fpm_misc->q1_block_size)
- return I40IW_ERR_INVALID_SIZE;
-
- i40iw_sc_decode_fpm_query(buf, 88, obj_info, I40IW_HMC_IW_TIMER);
-
- get_64bit_val(buf, 112, &temp);
- obj_info[I40IW_HMC_IW_PBLE].max_cnt = (u32)temp;
- obj_info[I40IW_HMC_IW_PBLE].size = 8;
-
- get_64bit_val(buf, 120, &temp);
- hmc_fpm_misc->max_ceqs = (u8)RS_64(temp, I40IW_QUERY_FPM_MAX_CEQS);
- hmc_fpm_misc->ht_multiplier = RS_64(temp, I40IW_QUERY_FPM_HTMULTIPLIER);
- hmc_fpm_misc->timer_bucket = RS_64(temp, I40IW_QUERY_FPM_TIMERBUCKET);
-
- return 0;
-}
-
-/**
- * i40iw_fill_qos_list - Change all unknown qs handles to available ones
- * @qs_list: list of qs_handles to be fixed with valid qs_handles
- */
-static void i40iw_fill_qos_list(u16 *qs_list)
-{
- u16 qshandle = qs_list[0];
- int i;
-
- for (i = 0; i < I40IW_MAX_USER_PRIORITY; i++) {
- if (qs_list[i] == QS_HANDLE_UNKNOWN)
- qs_list[i] = qshandle;
- else
- qshandle = qs_list[i];
- }
-}
-
-/**
- * i40iw_qp_from_entry - Given entry, get to the qp structure
- * @entry: Points to list of qp structure
- */
-static struct i40iw_sc_qp *i40iw_qp_from_entry(struct list_head *entry)
-{
- if (!entry)
- return NULL;
-
- return (struct i40iw_sc_qp *)((char *)entry - offsetof(struct i40iw_sc_qp, list));
-}
-
-/**
- * i40iw_get_qp - get the next qp from the list given current qp
- * @head: Listhead of qp's
- * @qp: current qp
- */
-static struct i40iw_sc_qp *i40iw_get_qp(struct list_head *head, struct i40iw_sc_qp *qp)
-{
- struct list_head *entry = NULL;
- struct list_head *lastentry;
-
- if (list_empty(head))
- return NULL;
-
- if (!qp) {
- entry = head->next;
- } else {
- lastentry = &qp->list;
- entry = (lastentry != head) ? lastentry->next : NULL;
- }
-
- return i40iw_qp_from_entry(entry);
-}
-
-/**
- * i40iw_change_l2params - given the new l2 parameters, change all qp
- * @vsi: pointer to the vsi structure
- * @l2params: New paramaters from l2
- */
-void i40iw_change_l2params(struct i40iw_sc_vsi *vsi, struct i40iw_l2params *l2params)
-{
- struct i40iw_sc_dev *dev = vsi->dev;
- struct i40iw_sc_qp *qp = NULL;
- bool qs_handle_change = false;
- unsigned long flags;
- u16 qs_handle;
- int i;
-
- if (vsi->mtu != l2params->mtu) {
- vsi->mtu = l2params->mtu;
- i40iw_reinitialize_ieq(dev);
- }
-
- i40iw_fill_qos_list(l2params->qs_handle_list);
- for (i = 0; i < I40IW_MAX_USER_PRIORITY; i++) {
- qs_handle = l2params->qs_handle_list[i];
- if (vsi->qos[i].qs_handle != qs_handle)
- qs_handle_change = true;
- spin_lock_irqsave(&vsi->qos[i].lock, flags);
- qp = i40iw_get_qp(&vsi->qos[i].qplist, qp);
- while (qp) {
- if (qs_handle_change) {
- qp->qs_handle = qs_handle;
- /* issue cqp suspend command */
- i40iw_qp_suspend_resume(dev, qp, true);
- }
- qp = i40iw_get_qp(&vsi->qos[i].qplist, qp);
- }
- spin_unlock_irqrestore(&vsi->qos[i].lock, flags);
- vsi->qos[i].qs_handle = qs_handle;
- }
-}
-
-/**
- * i40iw_qp_rem_qos - remove qp from qos lists during destroy qp
- * @qp: qp to be removed from qos
- */
-void i40iw_qp_rem_qos(struct i40iw_sc_qp *qp)
-{
- struct i40iw_sc_vsi *vsi = qp->vsi;
- unsigned long flags;
-
- if (!qp->on_qoslist)
- return;
- spin_lock_irqsave(&vsi->qos[qp->user_pri].lock, flags);
- list_del(&qp->list);
- spin_unlock_irqrestore(&vsi->qos[qp->user_pri].lock, flags);
-}
-
-/**
- * i40iw_qp_add_qos - called during setctx fot qp to be added to qos
- * @qp: qp to be added to qos
- */
-void i40iw_qp_add_qos(struct i40iw_sc_qp *qp)
-{
- struct i40iw_sc_vsi *vsi = qp->vsi;
- unsigned long flags;
-
- if (qp->on_qoslist)
- return;
- spin_lock_irqsave(&vsi->qos[qp->user_pri].lock, flags);
- qp->qs_handle = vsi->qos[qp->user_pri].qs_handle;
- list_add(&qp->list, &vsi->qos[qp->user_pri].qplist);
- qp->on_qoslist = true;
- spin_unlock_irqrestore(&vsi->qos[qp->user_pri].lock, flags);
-}
-
-/**
- * i40iw_sc_pd_init - initialize sc pd struct
- * @dev: sc device struct
- * @pd: sc pd ptr
- * @pd_id: pd_id for allocated pd
- * @abi_ver: ABI version from user context, -1 if not valid
- */
-static void i40iw_sc_pd_init(struct i40iw_sc_dev *dev,
- struct i40iw_sc_pd *pd,
- u16 pd_id,
- int abi_ver)
-{
- pd->size = sizeof(*pd);
- pd->pd_id = pd_id;
- pd->abi_ver = abi_ver;
- pd->dev = dev;
-}
-
-/**
- * i40iw_get_encoded_wqe_size - given wq size, returns hardware encoded size
- * @wqsize: size of the wq (sq, rq, srq) to encoded_size
- * @cqpsq: encoded size for sq for cqp as its encoded size is 1+ other wq's
- */
-u8 i40iw_get_encoded_wqe_size(u32 wqsize, bool cqpsq)
-{
- u8 encoded_size = 0;
-
- /* cqp sq's hw coded value starts from 1 for size of 4
- * while it starts from 0 for qp' wq's.
- */
- if (cqpsq)
- encoded_size = 1;
- wqsize >>= 2;
- while (wqsize >>= 1)
- encoded_size++;
- return encoded_size;
-}
-
-/**
- * i40iw_sc_cqp_init - Initialize buffers for a control Queue Pair
- * @cqp: IWARP control queue pair pointer
- * @info: IWARP control queue pair init info pointer
- *
- * Initializes the object and context buffers for a control Queue Pair.
- */
-static enum i40iw_status_code i40iw_sc_cqp_init(struct i40iw_sc_cqp *cqp,
- struct i40iw_cqp_init_info *info)
-{
- u8 hw_sq_size;
-
- if ((info->sq_size > I40IW_CQP_SW_SQSIZE_2048) ||
- (info->sq_size < I40IW_CQP_SW_SQSIZE_4) ||
- ((info->sq_size & (info->sq_size - 1))))
- return I40IW_ERR_INVALID_SIZE;
-
- hw_sq_size = i40iw_get_encoded_wqe_size(info->sq_size, true);
- cqp->size = sizeof(*cqp);
- cqp->sq_size = info->sq_size;
- cqp->hw_sq_size = hw_sq_size;
- cqp->sq_base = info->sq;
- cqp->host_ctx = info->host_ctx;
- cqp->sq_pa = info->sq_pa;
- cqp->host_ctx_pa = info->host_ctx_pa;
- cqp->dev = info->dev;
- cqp->struct_ver = info->struct_ver;
- cqp->scratch_array = info->scratch_array;
- cqp->polarity = 0;
- cqp->en_datacenter_tcp = info->en_datacenter_tcp;
- cqp->enabled_vf_count = info->enabled_vf_count;
- cqp->hmc_profile = info->hmc_profile;
- info->dev->cqp = cqp;
-
- I40IW_RING_INIT(cqp->sq_ring, cqp->sq_size);
- cqp->dev->cqp_cmd_stats[OP_REQUESTED_COMMANDS] = 0;
- cqp->dev->cqp_cmd_stats[OP_COMPLETED_COMMANDS] = 0;
- INIT_LIST_HEAD(&cqp->dev->cqp_cmd_head); /* for the cqp commands backlog. */
-
- i40iw_wr32(cqp->dev->hw, I40E_PFPE_CQPTAIL, 0);
- i40iw_wr32(cqp->dev->hw, I40E_PFPE_CQPDB, 0);
-
- i40iw_debug(cqp->dev, I40IW_DEBUG_WQE,
- "%s: sq_size[%04d] hw_sq_size[%04d] sq_base[%p] sq_pa[%llxh] cqp[%p] polarity[x%04X]\n",
- __func__, cqp->sq_size, cqp->hw_sq_size,
- cqp->sq_base, cqp->sq_pa, cqp, cqp->polarity);
- return 0;
-}
-
-/**
- * i40iw_sc_cqp_create - create cqp during bringup
- * @cqp: struct for cqp hw
- * @maj_err: If error, major err number
- * @min_err: If error, minor err number
- */
-static enum i40iw_status_code i40iw_sc_cqp_create(struct i40iw_sc_cqp *cqp,
- u16 *maj_err,
- u16 *min_err)
-{
- u64 temp;
- u32 cnt = 0, p1, p2, val = 0, err_code;
- enum i40iw_status_code ret_code;
-
- *maj_err = 0;
- *min_err = 0;
-
- ret_code = i40iw_allocate_dma_mem(cqp->dev->hw,
- &cqp->sdbuf,
- I40IW_UPDATE_SD_BUF_SIZE * cqp->sq_size,
- I40IW_SD_BUF_ALIGNMENT);
-
- if (ret_code)
- goto exit;
-
- temp = LS_64(cqp->hw_sq_size, I40IW_CQPHC_SQSIZE) |
- LS_64(cqp->struct_ver, I40IW_CQPHC_SVER);
-
- set_64bit_val(cqp->host_ctx, 0, temp);
- set_64bit_val(cqp->host_ctx, 8, cqp->sq_pa);
- temp = LS_64(cqp->enabled_vf_count, I40IW_CQPHC_ENABLED_VFS) |
- LS_64(cqp->hmc_profile, I40IW_CQPHC_HMC_PROFILE);
- set_64bit_val(cqp->host_ctx, 16, temp);
- set_64bit_val(cqp->host_ctx, 24, (uintptr_t)cqp);
- set_64bit_val(cqp->host_ctx, 32, 0);
- set_64bit_val(cqp->host_ctx, 40, 0);
- set_64bit_val(cqp->host_ctx, 48, 0);
- set_64bit_val(cqp->host_ctx, 56, 0);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "CQP_HOST_CTX",
- cqp->host_ctx, I40IW_CQP_CTX_SIZE * 8);
-
- p1 = RS_32_1(cqp->host_ctx_pa, 32);
- p2 = (u32)cqp->host_ctx_pa;
-
- if (cqp->dev->is_pf) {
- i40iw_wr32(cqp->dev->hw, I40E_PFPE_CCQPHIGH, p1);
- i40iw_wr32(cqp->dev->hw, I40E_PFPE_CCQPLOW, p2);
- } else {
- i40iw_wr32(cqp->dev->hw, I40E_VFPE_CCQPHIGH1, p1);
- i40iw_wr32(cqp->dev->hw, I40E_VFPE_CCQPLOW1, p2);
- }
- do {
- if (cnt++ > I40IW_DONE_COUNT) {
- i40iw_free_dma_mem(cqp->dev->hw, &cqp->sdbuf);
- ret_code = I40IW_ERR_TIMEOUT;
- /*
- * read PFPE_CQPERRORCODES register to get the minor
- * and major error code
- */
- if (cqp->dev->is_pf)
- err_code = i40iw_rd32(cqp->dev->hw, I40E_PFPE_CQPERRCODES);
- else
- err_code = i40iw_rd32(cqp->dev->hw, I40E_VFPE_CQPERRCODES1);
- *min_err = RS_32(err_code, I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE);
- *maj_err = RS_32(err_code, I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE);
- goto exit;
- }
- udelay(I40IW_SLEEP_COUNT);
- if (cqp->dev->is_pf)
- val = i40iw_rd32(cqp->dev->hw, I40E_PFPE_CCQPSTATUS);
- else
- val = i40iw_rd32(cqp->dev->hw, I40E_VFPE_CCQPSTATUS1);
- } while (!val);
-
-exit:
- if (!ret_code)
- cqp->process_cqp_sds = i40iw_update_sds_noccq;
- return ret_code;
-}
-
-/**
- * i40iw_sc_cqp_post_sq - post of cqp's sq
- * @cqp: struct for cqp hw
- */
-void i40iw_sc_cqp_post_sq(struct i40iw_sc_cqp *cqp)
-{
- if (cqp->dev->is_pf)
- i40iw_wr32(cqp->dev->hw, I40E_PFPE_CQPDB, I40IW_RING_GETCURRENT_HEAD(cqp->sq_ring));
- else
- i40iw_wr32(cqp->dev->hw, I40E_VFPE_CQPDB1, I40IW_RING_GETCURRENT_HEAD(cqp->sq_ring));
-
- i40iw_debug(cqp->dev,
- I40IW_DEBUG_WQE,
- "%s: HEAD_TAIL[%04d,%04d,%04d]\n",
- __func__,
- cqp->sq_ring.head,
- cqp->sq_ring.tail,
- cqp->sq_ring.size);
-}
-
-/**
- * i40iw_sc_cqp_get_next_send_wqe_idx - get next WQE on CQP SQ and pass back the index
- * @cqp: pointer to CQP structure
- * @scratch: private data for CQP WQE
- * @wqe_idx: WQE index for next WQE on CQP SQ
- */
-static u64 *i40iw_sc_cqp_get_next_send_wqe_idx(struct i40iw_sc_cqp *cqp,
- u64 scratch, u32 *wqe_idx)
-{
- u64 *wqe = NULL;
- enum i40iw_status_code ret_code;
-
- if (I40IW_RING_FULL_ERR(cqp->sq_ring)) {
- i40iw_debug(cqp->dev,
- I40IW_DEBUG_WQE,
- "%s: ring is full head %x tail %x size %x\n",
- __func__,
- cqp->sq_ring.head,
- cqp->sq_ring.tail,
- cqp->sq_ring.size);
- return NULL;
- }
- I40IW_ATOMIC_RING_MOVE_HEAD(cqp->sq_ring, *wqe_idx, ret_code);
- cqp->dev->cqp_cmd_stats[OP_REQUESTED_COMMANDS]++;
- if (ret_code)
- return NULL;
- if (!*wqe_idx)
- cqp->polarity = !cqp->polarity;
-
- wqe = cqp->sq_base[*wqe_idx].elem;
- cqp->scratch_array[*wqe_idx] = scratch;
- I40IW_CQP_INIT_WQE(wqe);
-
- return wqe;
-}
-
-/**
- * i40iw_sc_cqp_get_next_send_wqe - get next wqe on cqp sq
- * @cqp: struct for cqp hw
- * @scratch: private data for CQP WQE
- */
-u64 *i40iw_sc_cqp_get_next_send_wqe(struct i40iw_sc_cqp *cqp, u64 scratch)
-{
- u32 wqe_idx;
-
- return i40iw_sc_cqp_get_next_send_wqe_idx(cqp, scratch, &wqe_idx);
-}
-
-/**
- * i40iw_sc_cqp_destroy - destroy cqp during close
- * @cqp: struct for cqp hw
- */
-static enum i40iw_status_code i40iw_sc_cqp_destroy(struct i40iw_sc_cqp *cqp)
-{
- u32 cnt = 0, val = 1;
- enum i40iw_status_code ret_code = 0;
- u32 cqpstat_addr;
-
- if (cqp->dev->is_pf) {
- i40iw_wr32(cqp->dev->hw, I40E_PFPE_CCQPHIGH, 0);
- i40iw_wr32(cqp->dev->hw, I40E_PFPE_CCQPLOW, 0);
- cqpstat_addr = I40E_PFPE_CCQPSTATUS;
- } else {
- i40iw_wr32(cqp->dev->hw, I40E_VFPE_CCQPHIGH1, 0);
- i40iw_wr32(cqp->dev->hw, I40E_VFPE_CCQPLOW1, 0);
- cqpstat_addr = I40E_VFPE_CCQPSTATUS1;
- }
- do {
- if (cnt++ > I40IW_DONE_COUNT) {
- ret_code = I40IW_ERR_TIMEOUT;
- break;
- }
- udelay(I40IW_SLEEP_COUNT);
- val = i40iw_rd32(cqp->dev->hw, cqpstat_addr);
- } while (val);
-
- i40iw_free_dma_mem(cqp->dev->hw, &cqp->sdbuf);
- return ret_code;
-}
-
-/**
- * i40iw_sc_ccq_arm - enable intr for control cq
- * @ccq: ccq sc struct
- */
-static void i40iw_sc_ccq_arm(struct i40iw_sc_cq *ccq)
-{
- u64 temp_val;
- u16 sw_cq_sel;
- u8 arm_next_se;
- u8 arm_seq_num;
-
- /* write to cq doorbell shadow area */
- /* arm next se should always be zero */
- get_64bit_val(ccq->cq_uk.shadow_area, 32, &temp_val);
-
- sw_cq_sel = (u16)RS_64(temp_val, I40IW_CQ_DBSA_SW_CQ_SELECT);
- arm_next_se = (u8)RS_64(temp_val, I40IW_CQ_DBSA_ARM_NEXT_SE);
-
- arm_seq_num = (u8)RS_64(temp_val, I40IW_CQ_DBSA_ARM_SEQ_NUM);
- arm_seq_num++;
-
- temp_val = LS_64(arm_seq_num, I40IW_CQ_DBSA_ARM_SEQ_NUM) |
- LS_64(sw_cq_sel, I40IW_CQ_DBSA_SW_CQ_SELECT) |
- LS_64(arm_next_se, I40IW_CQ_DBSA_ARM_NEXT_SE) |
- LS_64(1, I40IW_CQ_DBSA_ARM_NEXT);
-
- set_64bit_val(ccq->cq_uk.shadow_area, 32, temp_val);
-
- wmb(); /* make sure shadow area is updated before arming */
-
- if (ccq->dev->is_pf)
- i40iw_wr32(ccq->dev->hw, I40E_PFPE_CQARM, ccq->cq_uk.cq_id);
- else
- i40iw_wr32(ccq->dev->hw, I40E_VFPE_CQARM1, ccq->cq_uk.cq_id);
-}
-
-/**
- * i40iw_sc_ccq_get_cqe_info - get ccq's cq entry
- * @ccq: ccq sc struct
- * @info: completion q entry to return
- */
-static enum i40iw_status_code i40iw_sc_ccq_get_cqe_info(
- struct i40iw_sc_cq *ccq,
- struct i40iw_ccq_cqe_info *info)
-{
- u64 qp_ctx, temp, temp1;
- u64 *cqe;
- struct i40iw_sc_cqp *cqp;
- u32 wqe_idx;
- u8 polarity;
- enum i40iw_status_code ret_code = 0;
-
- if (ccq->cq_uk.avoid_mem_cflct)
- cqe = (u64 *)I40IW_GET_CURRENT_EXTENDED_CQ_ELEMENT(&ccq->cq_uk);
- else
- cqe = (u64 *)I40IW_GET_CURRENT_CQ_ELEMENT(&ccq->cq_uk);
-
- get_64bit_val(cqe, 24, &temp);
- polarity = (u8)RS_64(temp, I40IW_CQ_VALID);
- if (polarity != ccq->cq_uk.polarity)
- return I40IW_ERR_QUEUE_EMPTY;
-
- get_64bit_val(cqe, 8, &qp_ctx);
- cqp = (struct i40iw_sc_cqp *)(unsigned long)qp_ctx;
- info->error = (bool)RS_64(temp, I40IW_CQ_ERROR);
- info->min_err_code = (u16)RS_64(temp, I40IW_CQ_MINERR);
- if (info->error) {
- info->maj_err_code = (u16)RS_64(temp, I40IW_CQ_MAJERR);
- info->min_err_code = (u16)RS_64(temp, I40IW_CQ_MINERR);
- }
- wqe_idx = (u32)RS_64(temp, I40IW_CQ_WQEIDX);
- info->scratch = cqp->scratch_array[wqe_idx];
-
- get_64bit_val(cqe, 16, &temp1);
- info->op_ret_val = (u32)RS_64(temp1, I40IW_CCQ_OPRETVAL);
- get_64bit_val(cqp->sq_base[wqe_idx].elem, 24, &temp1);
- info->op_code = (u8)RS_64(temp1, I40IW_CQPSQ_OPCODE);
- info->cqp = cqp;
-
- /* move the head for cq */
- I40IW_RING_MOVE_HEAD(ccq->cq_uk.cq_ring, ret_code);
- if (I40IW_RING_GETCURRENT_HEAD(ccq->cq_uk.cq_ring) == 0)
- ccq->cq_uk.polarity ^= 1;
-
- /* update cq tail in cq shadow memory also */
- I40IW_RING_MOVE_TAIL(ccq->cq_uk.cq_ring);
- set_64bit_val(ccq->cq_uk.shadow_area,
- 0,
- I40IW_RING_GETCURRENT_HEAD(ccq->cq_uk.cq_ring));
- wmb(); /* write shadow area before tail */
- I40IW_RING_MOVE_TAIL(cqp->sq_ring);
- ccq->dev->cqp_cmd_stats[OP_COMPLETED_COMMANDS]++;
-
- return ret_code;
-}
-
-/**
- * i40iw_sc_poll_for_cqp_op_done - Waits for last write to complete in CQP SQ
- * @cqp: struct for cqp hw
- * @op_code: cqp opcode for completion
- * @compl_info: completion q entry to return
- */
-static enum i40iw_status_code i40iw_sc_poll_for_cqp_op_done(
- struct i40iw_sc_cqp *cqp,
- u8 op_code,
- struct i40iw_ccq_cqe_info *compl_info)
-{
- struct i40iw_ccq_cqe_info info;
- struct i40iw_sc_cq *ccq;
- enum i40iw_status_code ret_code = 0;
- u32 cnt = 0;
-
- memset(&info, 0, sizeof(info));
- ccq = cqp->dev->ccq;
- while (1) {
- if (cnt++ > I40IW_DONE_COUNT)
- return I40IW_ERR_TIMEOUT;
-
- if (i40iw_sc_ccq_get_cqe_info(ccq, &info)) {
- udelay(I40IW_SLEEP_COUNT);
- continue;
- }
-
- if (info.error) {
- ret_code = I40IW_ERR_CQP_COMPL_ERROR;
- break;
- }
- /* check if opcode is cq create */
- if (op_code != info.op_code) {
- i40iw_debug(cqp->dev, I40IW_DEBUG_WQE,
- "%s: opcode mismatch for my op code 0x%x, returned opcode %x\n",
- __func__, op_code, info.op_code);
- }
- /* success, exit out of the loop */
- if (op_code == info.op_code)
- break;
- }
-
- if (compl_info)
- memcpy(compl_info, &info, sizeof(*compl_info));
-
- return ret_code;
-}
-
-/**
- * i40iw_sc_manage_hmc_pm_func_table - manage of function table
- * @cqp: struct for cqp hw
- * @scratch: u64 saved to be used during cqp completion
- * @vf_index: vf index for cqp
- * @free_pm_fcn: function number
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_manage_hmc_pm_func_table(
- struct i40iw_sc_cqp *cqp,
- u64 scratch,
- u8 vf_index,
- bool free_pm_fcn,
- bool post_sq)
-{
- u64 *wqe;
- u64 header;
-
- if (vf_index >= I40IW_MAX_VF_PER_PF)
- return I40IW_ERR_INVALID_VF_ID;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- header = LS_64(vf_index, I40IW_CQPSQ_MHMC_VFIDX) |
- LS_64(I40IW_CQP_OP_MANAGE_HMC_PM_FUNC_TABLE, I40IW_CQPSQ_OPCODE) |
- LS_64(free_pm_fcn, I40IW_CQPSQ_MHMC_FREEPMFN) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "MANAGE_HMC_PM_FUNC_TABLE WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_set_hmc_resource_profile - cqp wqe for hmc profile
- * @cqp: struct for cqp hw
- * @scratch: u64 saved to be used during cqp completion
- * @hmc_profile_type: type of profile to set
- * @vf_num: vf number for profile
- * @post_sq: flag for cqp db to ring
- * @poll_registers: flag to poll register for cqp completion
- */
-static enum i40iw_status_code i40iw_sc_set_hmc_resource_profile(
- struct i40iw_sc_cqp *cqp,
- u64 scratch,
- u8 hmc_profile_type,
- u8 vf_num, bool post_sq,
- bool poll_registers)
-{
- u64 *wqe;
- u64 header;
- u32 val, tail, error;
- enum i40iw_status_code ret_code = 0;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- set_64bit_val(wqe, 16,
- (LS_64(hmc_profile_type, I40IW_CQPSQ_SHMCRP_HMC_PROFILE) |
- LS_64(vf_num, I40IW_CQPSQ_SHMCRP_VFNUM)));
-
- header = LS_64(I40IW_CQP_OP_SET_HMC_RESOURCE_PROFILE, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "MANAGE_HMC_PM_FUNC_TABLE WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- i40iw_get_cqp_reg_info(cqp, &val, &tail, &error);
- if (error)
- return I40IW_ERR_CQP_COMPL_ERROR;
-
- if (post_sq) {
- i40iw_sc_cqp_post_sq(cqp);
- if (poll_registers)
- ret_code = i40iw_cqp_poll_registers(cqp, tail, 1000000);
- else
- ret_code = i40iw_sc_poll_for_cqp_op_done(cqp,
- I40IW_CQP_OP_SHMC_PAGES_ALLOCATED,
- NULL);
- }
-
- return ret_code;
-}
-
-/**
- * i40iw_sc_manage_hmc_pm_func_table_done - wait for cqp wqe completion for function table
- * @cqp: struct for cqp hw
- */
-static enum i40iw_status_code i40iw_sc_manage_hmc_pm_func_table_done(struct i40iw_sc_cqp *cqp)
-{
- return i40iw_sc_poll_for_cqp_op_done(cqp, I40IW_CQP_OP_MANAGE_HMC_PM_FUNC_TABLE, NULL);
-}
-
-/**
- * i40iw_sc_commit_fpm_values_done - wait for cqp eqe completion for fpm commit
- * @cqp: struct for cqp hw
- */
-static enum i40iw_status_code i40iw_sc_commit_fpm_values_done(struct i40iw_sc_cqp *cqp)
-{
- return i40iw_sc_poll_for_cqp_op_done(cqp, I40IW_CQP_OP_COMMIT_FPM_VALUES, NULL);
-}
-
-/**
- * i40iw_sc_commit_fpm_values - cqp wqe for commit fpm values
- * @cqp: struct for cqp hw
- * @scratch: u64 saved to be used during cqp completion
- * @hmc_fn_id: hmc function id
- * @commit_fpm_mem: Memory for fpm values
- * @post_sq: flag for cqp db to ring
- * @wait_type: poll ccq or cqp registers for cqp completion
- */
-static enum i40iw_status_code i40iw_sc_commit_fpm_values(
- struct i40iw_sc_cqp *cqp,
- u64 scratch,
- u8 hmc_fn_id,
- struct i40iw_dma_mem *commit_fpm_mem,
- bool post_sq,
- u8 wait_type)
-{
- u64 *wqe;
- u64 header;
- u32 tail, val, error;
- enum i40iw_status_code ret_code = 0;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- set_64bit_val(wqe, 16, hmc_fn_id);
- set_64bit_val(wqe, 32, commit_fpm_mem->pa);
-
- header = LS_64(I40IW_CQP_OP_COMMIT_FPM_VALUES, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "COMMIT_FPM_VALUES WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- i40iw_get_cqp_reg_info(cqp, &val, &tail, &error);
- if (error)
- return I40IW_ERR_CQP_COMPL_ERROR;
-
- if (post_sq) {
- i40iw_sc_cqp_post_sq(cqp);
-
- if (wait_type == I40IW_CQP_WAIT_POLL_REGS)
- ret_code = i40iw_cqp_poll_registers(cqp, tail, I40IW_DONE_COUNT);
- else if (wait_type == I40IW_CQP_WAIT_POLL_CQ)
- ret_code = i40iw_sc_commit_fpm_values_done(cqp);
- }
-
- return ret_code;
-}
-
-/**
- * i40iw_sc_query_rdma_features_done - poll cqp for query features done
- * @cqp: struct for cqp hw
- */
-static enum i40iw_status_code
-i40iw_sc_query_rdma_features_done(struct i40iw_sc_cqp *cqp)
-{
- return i40iw_sc_poll_for_cqp_op_done(
- cqp, I40IW_CQP_OP_QUERY_RDMA_FEATURES, NULL);
-}
-
-/**
- * i40iw_sc_query_rdma_features - query rdma features
- * @cqp: struct for cqp hw
- * @feat_mem: holds PA for HW to use
- * @scratch: u64 saved to be used during cqp completion
- */
-static enum i40iw_status_code
-i40iw_sc_query_rdma_features(struct i40iw_sc_cqp *cqp,
- struct i40iw_dma_mem *feat_mem, u64 scratch)
-{
- u64 *wqe;
- u64 header;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- set_64bit_val(wqe, 32, feat_mem->pa);
-
- header = LS_64(I40IW_CQP_OP_QUERY_RDMA_FEATURES, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID) | feat_mem->size;
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "QUERY RDMA FEATURES WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- i40iw_sc_cqp_post_sq(cqp);
-
- return 0;
-}
-
-/**
- * i40iw_get_rdma_features - get RDMA features
- * @dev: sc device struct
- */
-enum i40iw_status_code i40iw_get_rdma_features(struct i40iw_sc_dev *dev)
-{
- enum i40iw_status_code ret_code;
- struct i40iw_dma_mem feat_buf;
- u64 temp;
- u16 byte_idx, feat_type, feat_cnt;
-
- ret_code = i40iw_allocate_dma_mem(dev->hw, &feat_buf,
- I40IW_FEATURE_BUF_SIZE,
- I40IW_FEATURE_BUF_ALIGNMENT);
-
- if (ret_code)
- return I40IW_ERR_NO_MEMORY;
-
- ret_code = i40iw_sc_query_rdma_features(dev->cqp, &feat_buf, 0);
- if (!ret_code)
- ret_code = i40iw_sc_query_rdma_features_done(dev->cqp);
-
- if (ret_code)
- goto exit;
-
- get_64bit_val(feat_buf.va, 0, &temp);
- feat_cnt = RS_64(temp, I40IW_FEATURE_CNT);
- if (feat_cnt < I40IW_MAX_FEATURES) {
- ret_code = I40IW_ERR_INVALID_FEAT_CNT;
- goto exit;
- } else if (feat_cnt > I40IW_MAX_FEATURES) {
- i40iw_debug(dev, I40IW_DEBUG_CQP,
- "features buf size insufficient\n");
- }
-
- for (byte_idx = 0, feat_type = 0; feat_type < I40IW_MAX_FEATURES;
- feat_type++, byte_idx += 8) {
- get_64bit_val((u64 *)feat_buf.va, byte_idx, &temp);
- dev->feature_info[feat_type] = RS_64(temp, I40IW_FEATURE_INFO);
- }
-exit:
- i40iw_free_dma_mem(dev->hw, &feat_buf);
-
- return ret_code;
-}
-
-/**
- * i40iw_sc_query_fpm_values_done - poll for cqp wqe completion for query fpm
- * @cqp: struct for cqp hw
- */
-static enum i40iw_status_code i40iw_sc_query_fpm_values_done(struct i40iw_sc_cqp *cqp)
-{
- return i40iw_sc_poll_for_cqp_op_done(cqp, I40IW_CQP_OP_QUERY_FPM_VALUES, NULL);
-}
-
-/**
- * i40iw_sc_query_fpm_values - cqp wqe query fpm values
- * @cqp: struct for cqp hw
- * @scratch: u64 saved to be used during cqp completion
- * @hmc_fn_id: hmc function id
- * @query_fpm_mem: memory for return fpm values
- * @post_sq: flag for cqp db to ring
- * @wait_type: poll ccq or cqp registers for cqp completion
- */
-static enum i40iw_status_code i40iw_sc_query_fpm_values(
- struct i40iw_sc_cqp *cqp,
- u64 scratch,
- u8 hmc_fn_id,
- struct i40iw_dma_mem *query_fpm_mem,
- bool post_sq,
- u8 wait_type)
-{
- u64 *wqe;
- u64 header;
- u32 tail, val, error;
- enum i40iw_status_code ret_code = 0;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- set_64bit_val(wqe, 16, hmc_fn_id);
- set_64bit_val(wqe, 32, query_fpm_mem->pa);
-
- header = LS_64(I40IW_CQP_OP_QUERY_FPM_VALUES, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "QUERY_FPM WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- /* read the tail from CQP_TAIL register */
- i40iw_get_cqp_reg_info(cqp, &val, &tail, &error);
-
- if (error)
- return I40IW_ERR_CQP_COMPL_ERROR;
-
- if (post_sq) {
- i40iw_sc_cqp_post_sq(cqp);
- if (wait_type == I40IW_CQP_WAIT_POLL_REGS)
- ret_code = i40iw_cqp_poll_registers(cqp, tail, I40IW_DONE_COUNT);
- else if (wait_type == I40IW_CQP_WAIT_POLL_CQ)
- ret_code = i40iw_sc_query_fpm_values_done(cqp);
- }
-
- return ret_code;
-}
-
-/**
- * i40iw_sc_add_arp_cache_entry - cqp wqe add arp cache entry
- * @cqp: struct for cqp hw
- * @info: arp entry information
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_add_arp_cache_entry(
- struct i40iw_sc_cqp *cqp,
- struct i40iw_add_arp_cache_entry_info *info,
- u64 scratch,
- bool post_sq)
-{
- u64 *wqe;
- u64 temp, header;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe, 8, info->reach_max);
-
- temp = info->mac_addr[5] |
- LS_64_1(info->mac_addr[4], 8) |
- LS_64_1(info->mac_addr[3], 16) |
- LS_64_1(info->mac_addr[2], 24) |
- LS_64_1(info->mac_addr[1], 32) |
- LS_64_1(info->mac_addr[0], 40);
-
- set_64bit_val(wqe, 16, temp);
-
- header = info->arp_index |
- LS_64(I40IW_CQP_OP_MANAGE_ARP, I40IW_CQPSQ_OPCODE) |
- LS_64((info->permanent ? 1 : 0), I40IW_CQPSQ_MAT_PERMANENT) |
- LS_64(1, I40IW_CQPSQ_MAT_ENTRYVALID) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "ARP_CACHE_ENTRY WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_del_arp_cache_entry - dele arp cache entry
- * @cqp: struct for cqp hw
- * @scratch: u64 saved to be used during cqp completion
- * @arp_index: arp index to delete arp entry
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_del_arp_cache_entry(
- struct i40iw_sc_cqp *cqp,
- u64 scratch,
- u16 arp_index,
- bool post_sq)
-{
- u64 *wqe;
- u64 header;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- header = arp_index |
- LS_64(I40IW_CQP_OP_MANAGE_ARP, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "ARP_CACHE_DEL_ENTRY WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_query_arp_cache_entry - cqp wqe to query arp and arp index
- * @cqp: struct for cqp hw
- * @scratch: u64 saved to be used during cqp completion
- * @arp_index: arp index to delete arp entry
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_query_arp_cache_entry(
- struct i40iw_sc_cqp *cqp,
- u64 scratch,
- u16 arp_index,
- bool post_sq)
-{
- u64 *wqe;
- u64 header;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- header = arp_index |
- LS_64(I40IW_CQP_OP_MANAGE_ARP, I40IW_CQPSQ_OPCODE) |
- LS_64(1, I40IW_CQPSQ_MAT_QUERY) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "QUERY_ARP_CACHE_ENTRY WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_manage_apbvt_entry - for adding and deleting apbvt entries
- * @cqp: struct for cqp hw
- * @info: info for apbvt entry to add or delete
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_manage_apbvt_entry(
- struct i40iw_sc_cqp *cqp,
- struct i40iw_apbvt_info *info,
- u64 scratch,
- bool post_sq)
-{
- u64 *wqe;
- u64 header;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- set_64bit_val(wqe, 16, info->port);
-
- header = LS_64(I40IW_CQP_OP_MANAGE_APBVT, I40IW_CQPSQ_OPCODE) |
- LS_64(info->add, I40IW_CQPSQ_MAPT_ADDPORT) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "MANAGE_APBVT WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_manage_qhash_table_entry - manage quad hash entries
- * @cqp: struct for cqp hw
- * @info: info for quad hash to manage
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- *
- * This is called before connection establishment is started. For passive connections, when
- * listener is created, it will call with entry type of I40IW_QHASH_TYPE_TCP_SYN with local
- * ip address and tcp port. When SYN is received (passive connections) or
- * sent (active connections), this routine is called with entry type of
- * I40IW_QHASH_TYPE_TCP_ESTABLISHED and quad is passed in info.
- *
- * When iwarp connection is done and its state moves to RTS, the quad hash entry in
- * the hardware will point to iwarp's qp number and requires no calls from the driver.
- */
-static enum i40iw_status_code i40iw_sc_manage_qhash_table_entry(
- struct i40iw_sc_cqp *cqp,
- struct i40iw_qhash_table_info *info,
- u64 scratch,
- bool post_sq)
-{
- u64 *wqe;
- u64 qw1 = 0;
- u64 qw2 = 0;
- u64 temp;
- struct i40iw_sc_vsi *vsi = info->vsi;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- temp = info->mac_addr[5] |
- LS_64_1(info->mac_addr[4], 8) |
- LS_64_1(info->mac_addr[3], 16) |
- LS_64_1(info->mac_addr[2], 24) |
- LS_64_1(info->mac_addr[1], 32) |
- LS_64_1(info->mac_addr[0], 40);
-
- set_64bit_val(wqe, 0, temp);
-
- qw1 = LS_64(info->qp_num, I40IW_CQPSQ_QHASH_QPN) |
- LS_64(info->dest_port, I40IW_CQPSQ_QHASH_DEST_PORT);
- if (info->ipv4_valid) {
- set_64bit_val(wqe,
- 48,
- LS_64(info->dest_ip[0], I40IW_CQPSQ_QHASH_ADDR3));
- } else {
- set_64bit_val(wqe,
- 56,
- LS_64(info->dest_ip[0], I40IW_CQPSQ_QHASH_ADDR0) |
- LS_64(info->dest_ip[1], I40IW_CQPSQ_QHASH_ADDR1));
-
- set_64bit_val(wqe,
- 48,
- LS_64(info->dest_ip[2], I40IW_CQPSQ_QHASH_ADDR2) |
- LS_64(info->dest_ip[3], I40IW_CQPSQ_QHASH_ADDR3));
- }
- qw2 = LS_64(vsi->qos[info->user_pri].qs_handle, I40IW_CQPSQ_QHASH_QS_HANDLE);
- if (info->vlan_valid)
- qw2 |= LS_64(info->vlan_id, I40IW_CQPSQ_QHASH_VLANID);
- set_64bit_val(wqe, 16, qw2);
- if (info->entry_type == I40IW_QHASH_TYPE_TCP_ESTABLISHED) {
- qw1 |= LS_64(info->src_port, I40IW_CQPSQ_QHASH_SRC_PORT);
- if (!info->ipv4_valid) {
- set_64bit_val(wqe,
- 40,
- LS_64(info->src_ip[0], I40IW_CQPSQ_QHASH_ADDR0) |
- LS_64(info->src_ip[1], I40IW_CQPSQ_QHASH_ADDR1));
- set_64bit_val(wqe,
- 32,
- LS_64(info->src_ip[2], I40IW_CQPSQ_QHASH_ADDR2) |
- LS_64(info->src_ip[3], I40IW_CQPSQ_QHASH_ADDR3));
- } else {
- set_64bit_val(wqe,
- 32,
- LS_64(info->src_ip[0], I40IW_CQPSQ_QHASH_ADDR3));
- }
- }
-
- set_64bit_val(wqe, 8, qw1);
- temp = LS_64(cqp->polarity, I40IW_CQPSQ_QHASH_WQEVALID) |
- LS_64(I40IW_CQP_OP_MANAGE_QUAD_HASH_TABLE_ENTRY, I40IW_CQPSQ_QHASH_OPCODE) |
- LS_64(info->manage, I40IW_CQPSQ_QHASH_MANAGE) |
- LS_64(info->ipv4_valid, I40IW_CQPSQ_QHASH_IPV4VALID) |
- LS_64(info->vlan_valid, I40IW_CQPSQ_QHASH_VLANVALID) |
- LS_64(info->entry_type, I40IW_CQPSQ_QHASH_ENTRYTYPE);
-
- i40iw_insert_wqe_hdr(wqe, temp);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "MANAGE_QHASH WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_alloc_local_mac_ipaddr_entry - cqp wqe for loc mac entry
- * @cqp: struct for cqp hw
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_alloc_local_mac_ipaddr_entry(
- struct i40iw_sc_cqp *cqp,
- u64 scratch,
- bool post_sq)
-{
- u64 *wqe;
- u64 header;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- header = LS_64(I40IW_CQP_OP_ALLOCATE_LOC_MAC_IP_TABLE_ENTRY, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "ALLOCATE_LOCAL_MAC_IPADDR WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_add_local_mac_ipaddr_entry - add mac enry
- * @cqp: struct for cqp hw
- * @info:mac addr info
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_add_local_mac_ipaddr_entry(
- struct i40iw_sc_cqp *cqp,
- struct i40iw_local_mac_ipaddr_entry_info *info,
- u64 scratch,
- bool post_sq)
-{
- u64 *wqe;
- u64 temp, header;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- temp = info->mac_addr[5] |
- LS_64_1(info->mac_addr[4], 8) |
- LS_64_1(info->mac_addr[3], 16) |
- LS_64_1(info->mac_addr[2], 24) |
- LS_64_1(info->mac_addr[1], 32) |
- LS_64_1(info->mac_addr[0], 40);
-
- set_64bit_val(wqe, 32, temp);
-
- header = LS_64(info->entry_idx, I40IW_CQPSQ_MLIPA_IPTABLEIDX) |
- LS_64(I40IW_CQP_OP_MANAGE_LOC_MAC_IP_TABLE, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "ADD_LOCAL_MAC_IPADDR WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_del_local_mac_ipaddr_entry - cqp wqe to dele local mac
- * @cqp: struct for cqp hw
- * @scratch: u64 saved to be used during cqp completion
- * @entry_idx: index of mac entry
- * @ignore_ref_count: to force mac adde delete
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_del_local_mac_ipaddr_entry(
- struct i40iw_sc_cqp *cqp,
- u64 scratch,
- u8 entry_idx,
- u8 ignore_ref_count,
- bool post_sq)
-{
- u64 *wqe;
- u64 header;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- header = LS_64(entry_idx, I40IW_CQPSQ_MLIPA_IPTABLEIDX) |
- LS_64(I40IW_CQP_OP_MANAGE_LOC_MAC_IP_TABLE, I40IW_CQPSQ_OPCODE) |
- LS_64(1, I40IW_CQPSQ_MLIPA_FREEENTRY) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID) |
- LS_64(ignore_ref_count, I40IW_CQPSQ_MLIPA_IGNORE_REF_CNT);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "DEL_LOCAL_MAC_IPADDR WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_cqp_nop - send a nop wqe
- * @cqp: struct for cqp hw
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_cqp_nop(struct i40iw_sc_cqp *cqp,
- u64 scratch,
- bool post_sq)
-{
- u64 *wqe;
- u64 header;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- header = LS_64(I40IW_CQP_OP_NOP, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
- i40iw_insert_wqe_hdr(wqe, header);
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "NOP WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_ceq_init - initialize ceq
- * @ceq: ceq sc structure
- * @info: ceq initialization info
- */
-static enum i40iw_status_code i40iw_sc_ceq_init(struct i40iw_sc_ceq *ceq,
- struct i40iw_ceq_init_info *info)
-{
- u32 pble_obj_cnt;
-
- if ((info->elem_cnt < I40IW_MIN_CEQ_ENTRIES) ||
- (info->elem_cnt > I40IW_MAX_CEQ_ENTRIES))
- return I40IW_ERR_INVALID_SIZE;
-
- if (info->ceq_id >= I40IW_MAX_CEQID)
- return I40IW_ERR_INVALID_CEQ_ID;
-
- pble_obj_cnt = info->dev->hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].cnt;
-
- if (info->virtual_map && (info->first_pm_pbl_idx >= pble_obj_cnt))
- return I40IW_ERR_INVALID_PBLE_INDEX;
-
- ceq->size = sizeof(*ceq);
- ceq->ceqe_base = (struct i40iw_ceqe *)info->ceqe_base;
- ceq->ceq_id = info->ceq_id;
- ceq->dev = info->dev;
- ceq->elem_cnt = info->elem_cnt;
- ceq->ceq_elem_pa = info->ceqe_pa;
- ceq->virtual_map = info->virtual_map;
-
- ceq->pbl_chunk_size = (ceq->virtual_map ? info->pbl_chunk_size : 0);
- ceq->first_pm_pbl_idx = (ceq->virtual_map ? info->first_pm_pbl_idx : 0);
- ceq->pbl_list = (ceq->virtual_map ? info->pbl_list : NULL);
-
- ceq->tph_en = info->tph_en;
- ceq->tph_val = info->tph_val;
- ceq->polarity = 1;
- I40IW_RING_INIT(ceq->ceq_ring, ceq->elem_cnt);
- ceq->dev->ceq[info->ceq_id] = ceq;
-
- return 0;
-}
-
-/**
- * i40iw_sc_ceq_create - create ceq wqe
- * @ceq: ceq sc structure
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_ceq_create(struct i40iw_sc_ceq *ceq,
- u64 scratch,
- bool post_sq)
-{
- struct i40iw_sc_cqp *cqp;
- u64 *wqe;
- u64 header;
-
- cqp = ceq->dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe, 16, ceq->elem_cnt);
- set_64bit_val(wqe, 32, (ceq->virtual_map ? 0 : ceq->ceq_elem_pa));
- set_64bit_val(wqe, 48, (ceq->virtual_map ? ceq->first_pm_pbl_idx : 0));
- set_64bit_val(wqe, 56, LS_64(ceq->tph_val, I40IW_CQPSQ_TPHVAL));
-
- header = ceq->ceq_id |
- LS_64(I40IW_CQP_OP_CREATE_CEQ, I40IW_CQPSQ_OPCODE) |
- LS_64(ceq->pbl_chunk_size, I40IW_CQPSQ_CEQ_LPBLSIZE) |
- LS_64(ceq->virtual_map, I40IW_CQPSQ_CEQ_VMAP) |
- LS_64(ceq->tph_en, I40IW_CQPSQ_TPHEN) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "CEQ_CREATE WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_cceq_create_done - poll for control ceq wqe to complete
- * @ceq: ceq sc structure
- */
-static enum i40iw_status_code i40iw_sc_cceq_create_done(struct i40iw_sc_ceq *ceq)
-{
- struct i40iw_sc_cqp *cqp;
-
- cqp = ceq->dev->cqp;
- return i40iw_sc_poll_for_cqp_op_done(cqp, I40IW_CQP_OP_CREATE_CEQ, NULL);
-}
-
-/**
- * i40iw_sc_cceq_destroy_done - poll for destroy cceq to complete
- * @ceq: ceq sc structure
- */
-static enum i40iw_status_code i40iw_sc_cceq_destroy_done(struct i40iw_sc_ceq *ceq)
-{
- struct i40iw_sc_cqp *cqp;
-
- cqp = ceq->dev->cqp;
- cqp->process_cqp_sds = i40iw_update_sds_noccq;
- return i40iw_sc_poll_for_cqp_op_done(cqp, I40IW_CQP_OP_DESTROY_CEQ, NULL);
-}
-
-/**
- * i40iw_sc_cceq_create - create cceq
- * @ceq: ceq sc structure
- * @scratch: u64 saved to be used during cqp completion
- */
-static enum i40iw_status_code i40iw_sc_cceq_create(struct i40iw_sc_ceq *ceq, u64 scratch)
-{
- enum i40iw_status_code ret_code;
-
- ret_code = i40iw_sc_ceq_create(ceq, scratch, true);
- if (!ret_code)
- ret_code = i40iw_sc_cceq_create_done(ceq);
- return ret_code;
-}
-
-/**
- * i40iw_sc_ceq_destroy - destroy ceq
- * @ceq: ceq sc structure
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_ceq_destroy(struct i40iw_sc_ceq *ceq,
- u64 scratch,
- bool post_sq)
-{
- struct i40iw_sc_cqp *cqp;
- u64 *wqe;
- u64 header;
-
- cqp = ceq->dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe, 16, ceq->elem_cnt);
- set_64bit_val(wqe, 48, ceq->first_pm_pbl_idx);
- header = ceq->ceq_id |
- LS_64(I40IW_CQP_OP_DESTROY_CEQ, I40IW_CQPSQ_OPCODE) |
- LS_64(ceq->pbl_chunk_size, I40IW_CQPSQ_CEQ_LPBLSIZE) |
- LS_64(ceq->virtual_map, I40IW_CQPSQ_CEQ_VMAP) |
- LS_64(ceq->tph_en, I40IW_CQPSQ_TPHEN) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
- i40iw_insert_wqe_hdr(wqe, header);
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "CEQ_DESTROY WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_process_ceq - process ceq
- * @dev: sc device struct
- * @ceq: ceq sc structure
- */
-static void *i40iw_sc_process_ceq(struct i40iw_sc_dev *dev, struct i40iw_sc_ceq *ceq)
-{
- u64 temp;
- u64 *ceqe;
- struct i40iw_sc_cq *cq = NULL;
- u8 polarity;
-
- ceqe = (u64 *)I40IW_GET_CURRENT_CEQ_ELEMENT(ceq);
- get_64bit_val(ceqe, 0, &temp);
- polarity = (u8)RS_64(temp, I40IW_CEQE_VALID);
- if (polarity != ceq->polarity)
- return cq;
-
- cq = (struct i40iw_sc_cq *)(unsigned long)LS_64_1(temp, 1);
-
- I40IW_RING_MOVE_TAIL(ceq->ceq_ring);
- if (I40IW_RING_GETCURRENT_TAIL(ceq->ceq_ring) == 0)
- ceq->polarity ^= 1;
-
- if (dev->is_pf)
- i40iw_wr32(dev->hw, I40E_PFPE_CQACK, cq->cq_uk.cq_id);
- else
- i40iw_wr32(dev->hw, I40E_VFPE_CQACK1, cq->cq_uk.cq_id);
-
- return cq;
-}
-
-/**
- * i40iw_sc_aeq_init - initialize aeq
- * @aeq: aeq structure ptr
- * @info: aeq initialization info
- */
-static enum i40iw_status_code i40iw_sc_aeq_init(struct i40iw_sc_aeq *aeq,
- struct i40iw_aeq_init_info *info)
-{
- u32 pble_obj_cnt;
-
- if ((info->elem_cnt < I40IW_MIN_AEQ_ENTRIES) ||
- (info->elem_cnt > I40IW_MAX_AEQ_ENTRIES))
- return I40IW_ERR_INVALID_SIZE;
- pble_obj_cnt = info->dev->hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].cnt;
-
- if (info->virtual_map && (info->first_pm_pbl_idx >= pble_obj_cnt))
- return I40IW_ERR_INVALID_PBLE_INDEX;
-
- aeq->size = sizeof(*aeq);
- aeq->polarity = 1;
- aeq->aeqe_base = (struct i40iw_sc_aeqe *)info->aeqe_base;
- aeq->dev = info->dev;
- aeq->elem_cnt = info->elem_cnt;
-
- aeq->aeq_elem_pa = info->aeq_elem_pa;
- I40IW_RING_INIT(aeq->aeq_ring, aeq->elem_cnt);
- info->dev->aeq = aeq;
-
- aeq->virtual_map = info->virtual_map;
- aeq->pbl_list = (aeq->virtual_map ? info->pbl_list : NULL);
- aeq->pbl_chunk_size = (aeq->virtual_map ? info->pbl_chunk_size : 0);
- aeq->first_pm_pbl_idx = (aeq->virtual_map ? info->first_pm_pbl_idx : 0);
- info->dev->aeq = aeq;
- return 0;
-}
-
-/**
- * i40iw_sc_aeq_create - create aeq
- * @aeq: aeq structure ptr
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_aeq_create(struct i40iw_sc_aeq *aeq,
- u64 scratch,
- bool post_sq)
-{
- u64 *wqe;
- struct i40iw_sc_cqp *cqp;
- u64 header;
-
- cqp = aeq->dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe, 16, aeq->elem_cnt);
- set_64bit_val(wqe, 32,
- (aeq->virtual_map ? 0 : aeq->aeq_elem_pa));
- set_64bit_val(wqe, 48,
- (aeq->virtual_map ? aeq->first_pm_pbl_idx : 0));
-
- header = LS_64(I40IW_CQP_OP_CREATE_AEQ, I40IW_CQPSQ_OPCODE) |
- LS_64(aeq->pbl_chunk_size, I40IW_CQPSQ_AEQ_LPBLSIZE) |
- LS_64(aeq->virtual_map, I40IW_CQPSQ_AEQ_VMAP) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "AEQ_CREATE WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_aeq_destroy - destroy aeq during close
- * @aeq: aeq structure ptr
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_aeq_destroy(struct i40iw_sc_aeq *aeq,
- u64 scratch,
- bool post_sq)
-{
- u64 *wqe;
- struct i40iw_sc_cqp *cqp;
- u64 header;
-
- cqp = aeq->dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe, 16, aeq->elem_cnt);
- set_64bit_val(wqe, 48, aeq->first_pm_pbl_idx);
- header = LS_64(I40IW_CQP_OP_DESTROY_AEQ, I40IW_CQPSQ_OPCODE) |
- LS_64(aeq->pbl_chunk_size, I40IW_CQPSQ_AEQ_LPBLSIZE) |
- LS_64(aeq->virtual_map, I40IW_CQPSQ_AEQ_VMAP) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "AEQ_DESTROY WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_get_next_aeqe - get next aeq entry
- * @aeq: aeq structure ptr
- * @info: aeqe info to be returned
- */
-static enum i40iw_status_code i40iw_sc_get_next_aeqe(struct i40iw_sc_aeq *aeq,
- struct i40iw_aeqe_info *info)
-{
- u64 temp, compl_ctx;
- u64 *aeqe;
- u16 wqe_idx;
- u8 ae_src;
- u8 polarity;
-
- aeqe = (u64 *)I40IW_GET_CURRENT_AEQ_ELEMENT(aeq);
- get_64bit_val(aeqe, 0, &compl_ctx);
- get_64bit_val(aeqe, 8, &temp);
- polarity = (u8)RS_64(temp, I40IW_AEQE_VALID);
-
- if (aeq->polarity != polarity)
- return I40IW_ERR_QUEUE_EMPTY;
-
- i40iw_debug_buf(aeq->dev, I40IW_DEBUG_WQE, "AEQ_ENTRY", aeqe, 16);
-
- ae_src = (u8)RS_64(temp, I40IW_AEQE_AESRC);
- wqe_idx = (u16)RS_64(temp, I40IW_AEQE_WQDESCIDX);
- info->qp_cq_id = (u32)RS_64(temp, I40IW_AEQE_QPCQID);
- info->ae_id = (u16)RS_64(temp, I40IW_AEQE_AECODE);
- info->tcp_state = (u8)RS_64(temp, I40IW_AEQE_TCPSTATE);
- info->iwarp_state = (u8)RS_64(temp, I40IW_AEQE_IWSTATE);
- info->q2_data_written = (u8)RS_64(temp, I40IW_AEQE_Q2DATA);
- info->aeqe_overflow = (bool)RS_64(temp, I40IW_AEQE_OVERFLOW);
-
- switch (info->ae_id) {
- case I40IW_AE_PRIV_OPERATION_DENIED:
- case I40IW_AE_UDA_XMIT_DGRAM_TOO_LONG:
- case I40IW_AE_UDA_XMIT_DGRAM_TOO_SHORT:
- case I40IW_AE_BAD_CLOSE:
- case I40IW_AE_RDMAP_ROE_BAD_LLP_CLOSE:
- case I40IW_AE_RDMA_READ_WHILE_ORD_ZERO:
- case I40IW_AE_STAG_ZERO_INVALID:
- case I40IW_AE_IB_RREQ_AND_Q1_FULL:
- case I40IW_AE_WQE_UNEXPECTED_OPCODE:
- case I40IW_AE_DDP_UBE_INVALID_DDP_VERSION:
- case I40IW_AE_DDP_UBE_INVALID_MO:
- case I40IW_AE_DDP_UBE_INVALID_QN:
- case I40IW_AE_DDP_NO_L_BIT:
- case I40IW_AE_RDMAP_ROE_INVALID_RDMAP_VERSION:
- case I40IW_AE_RDMAP_ROE_UNEXPECTED_OPCODE:
- case I40IW_AE_ROE_INVALID_RDMA_READ_REQUEST:
- case I40IW_AE_ROE_INVALID_RDMA_WRITE_OR_READ_RESP:
- case I40IW_AE_INVALID_ARP_ENTRY:
- case I40IW_AE_INVALID_TCP_OPTION_RCVD:
- case I40IW_AE_STALE_ARP_ENTRY:
- case I40IW_AE_LLP_CLOSE_COMPLETE:
- case I40IW_AE_LLP_CONNECTION_RESET:
- case I40IW_AE_LLP_FIN_RECEIVED:
- case I40IW_AE_LLP_RECEIVED_MPA_CRC_ERROR:
- case I40IW_AE_LLP_SEGMENT_TOO_SMALL:
- case I40IW_AE_LLP_SYN_RECEIVED:
- case I40IW_AE_LLP_TERMINATE_RECEIVED:
- case I40IW_AE_LLP_TOO_MANY_RETRIES:
- case I40IW_AE_LLP_DOUBT_REACHABILITY:
- case I40IW_AE_RESET_SENT:
- case I40IW_AE_TERMINATE_SENT:
- case I40IW_AE_RESET_NOT_SENT:
- case I40IW_AE_LCE_QP_CATASTROPHIC:
- case I40IW_AE_QP_SUSPEND_COMPLETE:
- info->qp = true;
- info->compl_ctx = compl_ctx;
- ae_src = I40IW_AE_SOURCE_RSVD;
- break;
- case I40IW_AE_LCE_CQ_CATASTROPHIC:
- info->cq = true;
- info->compl_ctx = LS_64_1(compl_ctx, 1);
- ae_src = I40IW_AE_SOURCE_RSVD;
- break;
- }
-
- switch (ae_src) {
- case I40IW_AE_SOURCE_RQ:
- case I40IW_AE_SOURCE_RQ_0011:
- info->qp = true;
- info->wqe_idx = wqe_idx;
- info->compl_ctx = compl_ctx;
- break;
- case I40IW_AE_SOURCE_CQ:
- case I40IW_AE_SOURCE_CQ_0110:
- case I40IW_AE_SOURCE_CQ_1010:
- case I40IW_AE_SOURCE_CQ_1110:
- info->cq = true;
- info->compl_ctx = LS_64_1(compl_ctx, 1);
- break;
- case I40IW_AE_SOURCE_SQ:
- case I40IW_AE_SOURCE_SQ_0111:
- info->qp = true;
- info->sq = true;
- info->wqe_idx = wqe_idx;
- info->compl_ctx = compl_ctx;
- break;
- case I40IW_AE_SOURCE_IN_RR_WR:
- case I40IW_AE_SOURCE_IN_RR_WR_1011:
- info->qp = true;
- info->compl_ctx = compl_ctx;
- info->in_rdrsp_wr = true;
- break;
- case I40IW_AE_SOURCE_OUT_RR:
- case I40IW_AE_SOURCE_OUT_RR_1111:
- info->qp = true;
- info->compl_ctx = compl_ctx;
- info->out_rdrsp = true;
- break;
- case I40IW_AE_SOURCE_RSVD:
- default:
- break;
- }
- I40IW_RING_MOVE_TAIL(aeq->aeq_ring);
- if (I40IW_RING_GETCURRENT_TAIL(aeq->aeq_ring) == 0)
- aeq->polarity ^= 1;
- return 0;
-}
-
-/**
- * i40iw_sc_repost_aeq_entries - repost completed aeq entries
- * @dev: sc device struct
- * @count: allocate count
- */
-static enum i40iw_status_code i40iw_sc_repost_aeq_entries(struct i40iw_sc_dev *dev,
- u32 count)
-{
-
- if (dev->is_pf)
- i40iw_wr32(dev->hw, I40E_PFPE_AEQALLOC, count);
- else
- i40iw_wr32(dev->hw, I40E_VFPE_AEQALLOC1, count);
-
- return 0;
-}
-
-/**
- * i40iw_sc_aeq_create_done - create aeq
- * @aeq: aeq structure ptr
- */
-static enum i40iw_status_code i40iw_sc_aeq_create_done(struct i40iw_sc_aeq *aeq)
-{
- struct i40iw_sc_cqp *cqp;
-
- cqp = aeq->dev->cqp;
- return i40iw_sc_poll_for_cqp_op_done(cqp, I40IW_CQP_OP_CREATE_AEQ, NULL);
-}
-
-/**
- * i40iw_sc_aeq_destroy_done - destroy of aeq during close
- * @aeq: aeq structure ptr
- */
-static enum i40iw_status_code i40iw_sc_aeq_destroy_done(struct i40iw_sc_aeq *aeq)
-{
- struct i40iw_sc_cqp *cqp;
-
- cqp = aeq->dev->cqp;
- return i40iw_sc_poll_for_cqp_op_done(cqp, I40IW_CQP_OP_DESTROY_AEQ, NULL);
-}
-
-/**
- * i40iw_sc_ccq_init - initialize control cq
- * @cq: sc's cq ctruct
- * @info: info for control cq initialization
- */
-static enum i40iw_status_code i40iw_sc_ccq_init(struct i40iw_sc_cq *cq,
- struct i40iw_ccq_init_info *info)
-{
- u32 pble_obj_cnt;
-
- if (info->num_elem < I40IW_MIN_CQ_SIZE || info->num_elem > I40IW_MAX_CQ_SIZE)
- return I40IW_ERR_INVALID_SIZE;
-
- if (info->ceq_id > I40IW_MAX_CEQID)
- return I40IW_ERR_INVALID_CEQ_ID;
-
- pble_obj_cnt = info->dev->hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].cnt;
-
- if (info->virtual_map && (info->first_pm_pbl_idx >= pble_obj_cnt))
- return I40IW_ERR_INVALID_PBLE_INDEX;
-
- cq->cq_pa = info->cq_pa;
- cq->cq_uk.cq_base = info->cq_base;
- cq->shadow_area_pa = info->shadow_area_pa;
- cq->cq_uk.shadow_area = info->shadow_area;
- cq->shadow_read_threshold = info->shadow_read_threshold;
- cq->dev = info->dev;
- cq->ceq_id = info->ceq_id;
- cq->cq_uk.cq_size = info->num_elem;
- cq->cq_type = I40IW_CQ_TYPE_CQP;
- cq->ceqe_mask = info->ceqe_mask;
- I40IW_RING_INIT(cq->cq_uk.cq_ring, info->num_elem);
-
- cq->cq_uk.cq_id = 0; /* control cq is id 0 always */
- cq->ceq_id_valid = info->ceq_id_valid;
- cq->tph_en = info->tph_en;
- cq->tph_val = info->tph_val;
- cq->cq_uk.avoid_mem_cflct = info->avoid_mem_cflct;
-
- cq->pbl_list = info->pbl_list;
- cq->virtual_map = info->virtual_map;
- cq->pbl_chunk_size = info->pbl_chunk_size;
- cq->first_pm_pbl_idx = info->first_pm_pbl_idx;
- cq->cq_uk.polarity = true;
-
- /* following are only for iw cqs so initialize them to zero */
- cq->cq_uk.cqe_alloc_reg = NULL;
- info->dev->ccq = cq;
- return 0;
-}
-
-/**
- * i40iw_sc_ccq_create_done - poll cqp for ccq create
- * @ccq: ccq sc struct
- */
-static enum i40iw_status_code i40iw_sc_ccq_create_done(struct i40iw_sc_cq *ccq)
-{
- struct i40iw_sc_cqp *cqp;
-
- cqp = ccq->dev->cqp;
- return i40iw_sc_poll_for_cqp_op_done(cqp, I40IW_CQP_OP_CREATE_CQ, NULL);
-}
-
-/**
- * i40iw_sc_ccq_create - create control cq
- * @ccq: ccq sc struct
- * @scratch: u64 saved to be used during cqp completion
- * @check_overflow: overlow flag for ccq
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_ccq_create(struct i40iw_sc_cq *ccq,
- u64 scratch,
- bool check_overflow,
- bool post_sq)
-{
- u64 *wqe;
- struct i40iw_sc_cqp *cqp;
- u64 header;
- enum i40iw_status_code ret_code;
-
- cqp = ccq->dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe, 0, ccq->cq_uk.cq_size);
- set_64bit_val(wqe, 8, RS_64_1(ccq, 1));
- set_64bit_val(wqe, 16,
- LS_64(ccq->shadow_read_threshold, I40IW_CQPSQ_CQ_SHADOW_READ_THRESHOLD));
- set_64bit_val(wqe, 32, (ccq->virtual_map ? 0 : ccq->cq_pa));
- set_64bit_val(wqe, 40, ccq->shadow_area_pa);
- set_64bit_val(wqe, 48,
- (ccq->virtual_map ? ccq->first_pm_pbl_idx : 0));
- set_64bit_val(wqe, 56,
- LS_64(ccq->tph_val, I40IW_CQPSQ_TPHVAL));
-
- header = ccq->cq_uk.cq_id |
- LS_64((ccq->ceq_id_valid ? ccq->ceq_id : 0), I40IW_CQPSQ_CQ_CEQID) |
- LS_64(I40IW_CQP_OP_CREATE_CQ, I40IW_CQPSQ_OPCODE) |
- LS_64(ccq->pbl_chunk_size, I40IW_CQPSQ_CQ_LPBLSIZE) |
- LS_64(check_overflow, I40IW_CQPSQ_CQ_CHKOVERFLOW) |
- LS_64(ccq->virtual_map, I40IW_CQPSQ_CQ_VIRTMAP) |
- LS_64(ccq->ceqe_mask, I40IW_CQPSQ_CQ_ENCEQEMASK) |
- LS_64(ccq->ceq_id_valid, I40IW_CQPSQ_CQ_CEQIDVALID) |
- LS_64(ccq->tph_en, I40IW_CQPSQ_TPHEN) |
- LS_64(ccq->cq_uk.avoid_mem_cflct, I40IW_CQPSQ_CQ_AVOIDMEMCNFLCT) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "CCQ_CREATE WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq) {
- i40iw_sc_cqp_post_sq(cqp);
- ret_code = i40iw_sc_ccq_create_done(ccq);
- if (ret_code)
- return ret_code;
- }
- cqp->process_cqp_sds = i40iw_cqp_sds_cmd;
-
- return 0;
-}
-
-/**
- * i40iw_sc_ccq_destroy - destroy ccq during close
- * @ccq: ccq sc struct
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_ccq_destroy(struct i40iw_sc_cq *ccq,
- u64 scratch,
- bool post_sq)
-{
- struct i40iw_sc_cqp *cqp;
- u64 *wqe;
- u64 header;
- enum i40iw_status_code ret_code = 0;
- u32 tail, val, error;
-
- cqp = ccq->dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe, 0, ccq->cq_uk.cq_size);
- set_64bit_val(wqe, 8, RS_64_1(ccq, 1));
- set_64bit_val(wqe, 40, ccq->shadow_area_pa);
-
- header = ccq->cq_uk.cq_id |
- LS_64((ccq->ceq_id_valid ? ccq->ceq_id : 0), I40IW_CQPSQ_CQ_CEQID) |
- LS_64(I40IW_CQP_OP_DESTROY_CQ, I40IW_CQPSQ_OPCODE) |
- LS_64(ccq->ceqe_mask, I40IW_CQPSQ_CQ_ENCEQEMASK) |
- LS_64(ccq->ceq_id_valid, I40IW_CQPSQ_CQ_CEQIDVALID) |
- LS_64(ccq->tph_en, I40IW_CQPSQ_TPHEN) |
- LS_64(ccq->cq_uk.avoid_mem_cflct, I40IW_CQPSQ_CQ_AVOIDMEMCNFLCT) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "CCQ_DESTROY WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- i40iw_get_cqp_reg_info(cqp, &val, &tail, &error);
- if (error)
- return I40IW_ERR_CQP_COMPL_ERROR;
-
- if (post_sq) {
- i40iw_sc_cqp_post_sq(cqp);
- ret_code = i40iw_cqp_poll_registers(cqp, tail, 1000);
- }
-
- cqp->process_cqp_sds = i40iw_update_sds_noccq;
-
- return ret_code;
-}
-
-/**
- * i40iw_sc_cq_init - initialize completion q
- * @cq: cq struct
- * @info: cq initialization info
- */
-static enum i40iw_status_code i40iw_sc_cq_init(struct i40iw_sc_cq *cq,
- struct i40iw_cq_init_info *info)
-{
- u32 __iomem *cqe_alloc_reg = NULL;
- enum i40iw_status_code ret_code;
- u32 pble_obj_cnt;
- u32 arm_offset;
-
- pble_obj_cnt = info->dev->hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].cnt;
-
- if (info->virtual_map && (info->first_pm_pbl_idx >= pble_obj_cnt))
- return I40IW_ERR_INVALID_PBLE_INDEX;
-
- cq->cq_pa = info->cq_base_pa;
- cq->dev = info->dev;
- cq->ceq_id = info->ceq_id;
- arm_offset = (info->dev->is_pf) ? I40E_PFPE_CQARM : I40E_VFPE_CQARM1;
- if (i40iw_get_hw_addr(cq->dev))
- cqe_alloc_reg = (u32 __iomem *)(i40iw_get_hw_addr(cq->dev) +
- arm_offset);
- info->cq_uk_init_info.cqe_alloc_reg = cqe_alloc_reg;
- ret_code = i40iw_cq_uk_init(&cq->cq_uk, &info->cq_uk_init_info);
- if (ret_code)
- return ret_code;
- cq->virtual_map = info->virtual_map;
- cq->pbl_chunk_size = info->pbl_chunk_size;
- cq->ceqe_mask = info->ceqe_mask;
- cq->cq_type = (info->type) ? info->type : I40IW_CQ_TYPE_IWARP;
-
- cq->shadow_area_pa = info->shadow_area_pa;
- cq->shadow_read_threshold = info->shadow_read_threshold;
-
- cq->ceq_id_valid = info->ceq_id_valid;
- cq->tph_en = info->tph_en;
- cq->tph_val = info->tph_val;
-
- cq->first_pm_pbl_idx = info->first_pm_pbl_idx;
-
- return 0;
-}
-
-/**
- * i40iw_sc_cq_create - create completion q
- * @cq: cq struct
- * @scratch: u64 saved to be used during cqp completion
- * @check_overflow: flag for overflow check
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_cq_create(struct i40iw_sc_cq *cq,
- u64 scratch,
- bool check_overflow,
- bool post_sq)
-{
- u64 *wqe;
- struct i40iw_sc_cqp *cqp;
- u64 header;
-
- if (cq->cq_uk.cq_id > I40IW_MAX_CQID)
- return I40IW_ERR_INVALID_CQ_ID;
-
- if (cq->ceq_id > I40IW_MAX_CEQID)
- return I40IW_ERR_INVALID_CEQ_ID;
-
- cqp = cq->dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- set_64bit_val(wqe, 0, cq->cq_uk.cq_size);
- set_64bit_val(wqe, 8, RS_64_1(cq, 1));
- set_64bit_val(wqe,
- 16,
- LS_64(cq->shadow_read_threshold, I40IW_CQPSQ_CQ_SHADOW_READ_THRESHOLD));
-
- set_64bit_val(wqe, 32, (cq->virtual_map ? 0 : cq->cq_pa));
-
- set_64bit_val(wqe, 40, cq->shadow_area_pa);
- set_64bit_val(wqe, 48, (cq->virtual_map ? cq->first_pm_pbl_idx : 0));
- set_64bit_val(wqe, 56, LS_64(cq->tph_val, I40IW_CQPSQ_TPHVAL));
-
- header = cq->cq_uk.cq_id |
- LS_64((cq->ceq_id_valid ? cq->ceq_id : 0), I40IW_CQPSQ_CQ_CEQID) |
- LS_64(I40IW_CQP_OP_CREATE_CQ, I40IW_CQPSQ_OPCODE) |
- LS_64(cq->pbl_chunk_size, I40IW_CQPSQ_CQ_LPBLSIZE) |
- LS_64(check_overflow, I40IW_CQPSQ_CQ_CHKOVERFLOW) |
- LS_64(cq->virtual_map, I40IW_CQPSQ_CQ_VIRTMAP) |
- LS_64(cq->ceqe_mask, I40IW_CQPSQ_CQ_ENCEQEMASK) |
- LS_64(cq->ceq_id_valid, I40IW_CQPSQ_CQ_CEQIDVALID) |
- LS_64(cq->tph_en, I40IW_CQPSQ_TPHEN) |
- LS_64(cq->cq_uk.avoid_mem_cflct, I40IW_CQPSQ_CQ_AVOIDMEMCNFLCT) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "CQ_CREATE WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_cq_destroy - destroy completion q
- * @cq: cq struct
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_cq_destroy(struct i40iw_sc_cq *cq,
- u64 scratch,
- bool post_sq)
-{
- struct i40iw_sc_cqp *cqp;
- u64 *wqe;
- u64 header;
-
- cqp = cq->dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe, 0, cq->cq_uk.cq_size);
- set_64bit_val(wqe, 8, RS_64_1(cq, 1));
- set_64bit_val(wqe, 40, cq->shadow_area_pa);
- set_64bit_val(wqe, 48, (cq->virtual_map ? cq->first_pm_pbl_idx : 0));
-
- header = cq->cq_uk.cq_id |
- LS_64((cq->ceq_id_valid ? cq->ceq_id : 0), I40IW_CQPSQ_CQ_CEQID) |
- LS_64(I40IW_CQP_OP_DESTROY_CQ, I40IW_CQPSQ_OPCODE) |
- LS_64(cq->pbl_chunk_size, I40IW_CQPSQ_CQ_LPBLSIZE) |
- LS_64(cq->virtual_map, I40IW_CQPSQ_CQ_VIRTMAP) |
- LS_64(cq->ceqe_mask, I40IW_CQPSQ_CQ_ENCEQEMASK) |
- LS_64(cq->ceq_id_valid, I40IW_CQPSQ_CQ_CEQIDVALID) |
- LS_64(cq->tph_en, I40IW_CQPSQ_TPHEN) |
- LS_64(cq->cq_uk.avoid_mem_cflct, I40IW_CQPSQ_CQ_AVOIDMEMCNFLCT) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "CQ_DESTROY WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_cq_modify - modify a Completion Queue
- * @cq: cq struct
- * @info: modification info struct
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag to post to sq
- */
-static enum i40iw_status_code i40iw_sc_cq_modify(struct i40iw_sc_cq *cq,
- struct i40iw_modify_cq_info *info,
- u64 scratch,
- bool post_sq)
-{
- struct i40iw_sc_cqp *cqp;
- u64 *wqe;
- u64 header;
- u32 cq_size, ceq_id, first_pm_pbl_idx;
- u8 pbl_chunk_size;
- bool virtual_map, ceq_id_valid, check_overflow;
- u32 pble_obj_cnt;
-
- if (info->ceq_valid && (info->ceq_id > I40IW_MAX_CEQID))
- return I40IW_ERR_INVALID_CEQ_ID;
-
- pble_obj_cnt = cq->dev->hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].cnt;
-
- if (info->cq_resize && info->virtual_map &&
- (info->first_pm_pbl_idx >= pble_obj_cnt))
- return I40IW_ERR_INVALID_PBLE_INDEX;
-
- cqp = cq->dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- cq->pbl_list = info->pbl_list;
- cq->cq_pa = info->cq_pa;
- cq->first_pm_pbl_idx = info->first_pm_pbl_idx;
-
- cq_size = info->cq_resize ? info->cq_size : cq->cq_uk.cq_size;
- if (info->ceq_change) {
- ceq_id_valid = true;
- ceq_id = info->ceq_id;
- } else {
- ceq_id_valid = cq->ceq_id_valid;
- ceq_id = ceq_id_valid ? cq->ceq_id : 0;
- }
- virtual_map = info->cq_resize ? info->virtual_map : cq->virtual_map;
- first_pm_pbl_idx = (info->cq_resize ?
- (info->virtual_map ? info->first_pm_pbl_idx : 0) :
- (cq->virtual_map ? cq->first_pm_pbl_idx : 0));
- pbl_chunk_size = (info->cq_resize ?
- (info->virtual_map ? info->pbl_chunk_size : 0) :
- (cq->virtual_map ? cq->pbl_chunk_size : 0));
- check_overflow = info->check_overflow_change ? info->check_overflow :
- cq->check_overflow;
- cq->cq_uk.cq_size = cq_size;
- cq->ceq_id_valid = ceq_id_valid;
- cq->ceq_id = ceq_id;
- cq->virtual_map = virtual_map;
- cq->first_pm_pbl_idx = first_pm_pbl_idx;
- cq->pbl_chunk_size = pbl_chunk_size;
- cq->check_overflow = check_overflow;
-
- set_64bit_val(wqe, 0, cq_size);
- set_64bit_val(wqe, 8, RS_64_1(cq, 1));
- set_64bit_val(wqe, 16,
- LS_64(info->shadow_read_threshold, I40IW_CQPSQ_CQ_SHADOW_READ_THRESHOLD));
- set_64bit_val(wqe, 32, (cq->virtual_map ? 0 : cq->cq_pa));
- set_64bit_val(wqe, 40, cq->shadow_area_pa);
- set_64bit_val(wqe, 48, (cq->virtual_map ? first_pm_pbl_idx : 0));
- set_64bit_val(wqe, 56, LS_64(cq->tph_val, I40IW_CQPSQ_TPHVAL));
-
- header = cq->cq_uk.cq_id |
- LS_64(ceq_id, I40IW_CQPSQ_CQ_CEQID) |
- LS_64(I40IW_CQP_OP_MODIFY_CQ, I40IW_CQPSQ_OPCODE) |
- LS_64(info->cq_resize, I40IW_CQPSQ_CQ_CQRESIZE) |
- LS_64(pbl_chunk_size, I40IW_CQPSQ_CQ_LPBLSIZE) |
- LS_64(check_overflow, I40IW_CQPSQ_CQ_CHKOVERFLOW) |
- LS_64(virtual_map, I40IW_CQPSQ_CQ_VIRTMAP) |
- LS_64(cq->ceqe_mask, I40IW_CQPSQ_CQ_ENCEQEMASK) |
- LS_64(ceq_id_valid, I40IW_CQPSQ_CQ_CEQIDVALID) |
- LS_64(cq->tph_en, I40IW_CQPSQ_TPHEN) |
- LS_64(cq->cq_uk.avoid_mem_cflct, I40IW_CQPSQ_CQ_AVOIDMEMCNFLCT) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "CQ_MODIFY WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_qp_init - initialize qp
- * @qp: sc qp
- * @info: initialization qp info
- */
-static enum i40iw_status_code i40iw_sc_qp_init(struct i40iw_sc_qp *qp,
- struct i40iw_qp_init_info *info)
-{
- u32 __iomem *wqe_alloc_reg = NULL;
- enum i40iw_status_code ret_code;
- u32 pble_obj_cnt;
- u8 wqe_size;
- u32 offset;
-
- qp->dev = info->pd->dev;
- qp->vsi = info->vsi;
- qp->sq_pa = info->sq_pa;
- qp->rq_pa = info->rq_pa;
- qp->hw_host_ctx_pa = info->host_ctx_pa;
- qp->q2_pa = info->q2_pa;
- qp->shadow_area_pa = info->shadow_area_pa;
-
- qp->q2_buf = info->q2;
- qp->pd = info->pd;
- qp->hw_host_ctx = info->host_ctx;
- offset = (qp->pd->dev->is_pf) ? I40E_PFPE_WQEALLOC : I40E_VFPE_WQEALLOC1;
- if (i40iw_get_hw_addr(qp->pd->dev))
- wqe_alloc_reg = (u32 __iomem *)(i40iw_get_hw_addr(qp->pd->dev) +
- offset);
-
- info->qp_uk_init_info.wqe_alloc_reg = wqe_alloc_reg;
- info->qp_uk_init_info.abi_ver = qp->pd->abi_ver;
- ret_code = i40iw_qp_uk_init(&qp->qp_uk, &info->qp_uk_init_info);
- if (ret_code)
- return ret_code;
- qp->virtual_map = info->virtual_map;
-
- pble_obj_cnt = info->pd->dev->hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].cnt;
-
- if ((info->virtual_map && (info->sq_pa >= pble_obj_cnt)) ||
- (info->virtual_map && (info->rq_pa >= pble_obj_cnt)))
- return I40IW_ERR_INVALID_PBLE_INDEX;
-
- qp->llp_stream_handle = (void *)(-1);
- qp->qp_type = (info->type) ? info->type : I40IW_QP_TYPE_IWARP;
-
- qp->hw_sq_size = i40iw_get_encoded_wqe_size(qp->qp_uk.sq_ring.size,
- false);
- i40iw_debug(qp->dev, I40IW_DEBUG_WQE, "%s: hw_sq_size[%04d] sq_ring.size[%04d]\n",
- __func__, qp->hw_sq_size, qp->qp_uk.sq_ring.size);
-
- switch (qp->pd->abi_ver) {
- case 4:
- ret_code = i40iw_fragcnt_to_wqesize_rq(qp->qp_uk.max_rq_frag_cnt,
- &wqe_size);
- if (ret_code)
- return ret_code;
- break;
- case 5: /* fallthrough until next ABI version */
- default:
- if (qp->qp_uk.max_rq_frag_cnt > I40IW_MAX_WQ_FRAGMENT_COUNT)
- return I40IW_ERR_INVALID_FRAG_COUNT;
- wqe_size = I40IW_MAX_WQE_SIZE_RQ;
- break;
- }
- qp->hw_rq_size = i40iw_get_encoded_wqe_size(qp->qp_uk.rq_size *
- (wqe_size / I40IW_QP_WQE_MIN_SIZE), false);
- i40iw_debug(qp->dev, I40IW_DEBUG_WQE,
- "%s: hw_rq_size[%04d] qp_uk.rq_size[%04d] wqe_size[%04d]\n",
- __func__, qp->hw_rq_size, qp->qp_uk.rq_size, wqe_size);
- qp->sq_tph_val = info->sq_tph_val;
- qp->rq_tph_val = info->rq_tph_val;
- qp->sq_tph_en = info->sq_tph_en;
- qp->rq_tph_en = info->rq_tph_en;
- qp->rcv_tph_en = info->rcv_tph_en;
- qp->xmit_tph_en = info->xmit_tph_en;
- qp->qs_handle = qp->vsi->qos[qp->user_pri].qs_handle;
-
- return 0;
-}
-
-/**
- * i40iw_sc_qp_create - create qp
- * @qp: sc qp
- * @info: qp create info
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_qp_create(
- struct i40iw_sc_qp *qp,
- struct i40iw_create_qp_info *info,
- u64 scratch,
- bool post_sq)
-{
- struct i40iw_sc_cqp *cqp;
- u64 *wqe;
- u64 header;
-
- if ((qp->qp_uk.qp_id < I40IW_MIN_IW_QP_ID) ||
- (qp->qp_uk.qp_id > I40IW_MAX_IW_QP_ID))
- return I40IW_ERR_INVALID_QP_ID;
-
- cqp = qp->pd->dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- set_64bit_val(wqe, 16, qp->hw_host_ctx_pa);
-
- set_64bit_val(wqe, 40, qp->shadow_area_pa);
-
- header = qp->qp_uk.qp_id |
- LS_64(I40IW_CQP_OP_CREATE_QP, I40IW_CQPSQ_OPCODE) |
- LS_64((info->ord_valid ? 1 : 0), I40IW_CQPSQ_QP_ORDVALID) |
- LS_64(info->tcp_ctx_valid, I40IW_CQPSQ_QP_TOECTXVALID) |
- LS_64(qp->qp_type, I40IW_CQPSQ_QP_QPTYPE) |
- LS_64(qp->virtual_map, I40IW_CQPSQ_QP_VQ) |
- LS_64(info->cq_num_valid, I40IW_CQPSQ_QP_CQNUMVALID) |
- LS_64(info->arp_cache_idx_valid, I40IW_CQPSQ_QP_ARPTABIDXVALID) |
- LS_64(info->next_iwarp_state, I40IW_CQPSQ_QP_NEXTIWSTATE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "QP_CREATE WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_qp_modify - modify qp cqp wqe
- * @qp: sc qp
- * @info: modify qp info
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_qp_modify(
- struct i40iw_sc_qp *qp,
- struct i40iw_modify_qp_info *info,
- u64 scratch,
- bool post_sq)
-{
- u64 *wqe;
- struct i40iw_sc_cqp *cqp;
- u64 header;
- u8 term_actions = 0;
- u8 term_len = 0;
-
- cqp = qp->pd->dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- if (info->next_iwarp_state == I40IW_QP_STATE_TERMINATE) {
- if (info->dont_send_fin)
- term_actions += I40IWQP_TERM_SEND_TERM_ONLY;
- if (info->dont_send_term)
- term_actions += I40IWQP_TERM_SEND_FIN_ONLY;
- if ((term_actions == I40IWQP_TERM_SEND_TERM_AND_FIN) ||
- (term_actions == I40IWQP_TERM_SEND_TERM_ONLY))
- term_len = info->termlen;
- }
-
- set_64bit_val(wqe,
- 8,
- LS_64(term_len, I40IW_CQPSQ_QP_TERMLEN));
-
- set_64bit_val(wqe, 16, qp->hw_host_ctx_pa);
- set_64bit_val(wqe, 40, qp->shadow_area_pa);
-
- header = qp->qp_uk.qp_id |
- LS_64(I40IW_CQP_OP_MODIFY_QP, I40IW_CQPSQ_OPCODE) |
- LS_64(info->ord_valid, I40IW_CQPSQ_QP_ORDVALID) |
- LS_64(info->tcp_ctx_valid, I40IW_CQPSQ_QP_TOECTXVALID) |
- LS_64(info->cached_var_valid, I40IW_CQPSQ_QP_CACHEDVARVALID) |
- LS_64(qp->virtual_map, I40IW_CQPSQ_QP_VQ) |
- LS_64(info->cq_num_valid, I40IW_CQPSQ_QP_CQNUMVALID) |
- LS_64(info->force_loopback, I40IW_CQPSQ_QP_FORCELOOPBACK) |
- LS_64(qp->qp_type, I40IW_CQPSQ_QP_QPTYPE) |
- LS_64(info->remove_hash_idx, I40IW_CQPSQ_QP_REMOVEHASHENTRY) |
- LS_64(term_actions, I40IW_CQPSQ_QP_TERMACT) |
- LS_64(info->reset_tcp_conn, I40IW_CQPSQ_QP_RESETCON) |
- LS_64(info->arp_cache_idx_valid, I40IW_CQPSQ_QP_ARPTABIDXVALID) |
- LS_64(info->next_iwarp_state, I40IW_CQPSQ_QP_NEXTIWSTATE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "QP_MODIFY WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_qp_destroy - cqp destroy qp
- * @qp: sc qp
- * @scratch: u64 saved to be used during cqp completion
- * @remove_hash_idx: flag if to remove hash idx
- * @ignore_mw_bnd: memory window bind flag
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_qp_destroy(
- struct i40iw_sc_qp *qp,
- u64 scratch,
- bool remove_hash_idx,
- bool ignore_mw_bnd,
- bool post_sq)
-{
- u64 *wqe;
- struct i40iw_sc_cqp *cqp;
- u64 header;
-
- i40iw_qp_rem_qos(qp);
- cqp = qp->pd->dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe, 16, qp->hw_host_ctx_pa);
- set_64bit_val(wqe, 40, qp->shadow_area_pa);
-
- header = qp->qp_uk.qp_id |
- LS_64(I40IW_CQP_OP_DESTROY_QP, I40IW_CQPSQ_OPCODE) |
- LS_64(qp->qp_type, I40IW_CQPSQ_QP_QPTYPE) |
- LS_64(ignore_mw_bnd, I40IW_CQPSQ_QP_IGNOREMWBOUND) |
- LS_64(remove_hash_idx, I40IW_CQPSQ_QP_REMOVEHASHENTRY) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "QP_DESTROY WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_qp_flush_wqes - flush qp's wqe
- * @qp: sc qp
- * @info: dlush information
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_qp_flush_wqes(
- struct i40iw_sc_qp *qp,
- struct i40iw_qp_flush_info *info,
- u64 scratch,
- bool post_sq)
-{
- u64 temp = 0;
- u64 *wqe;
- struct i40iw_sc_cqp *cqp;
- u64 header;
- bool flush_sq = false, flush_rq = false;
-
- if (info->rq && !qp->flush_rq)
- flush_rq = true;
-
- if (info->sq && !qp->flush_sq)
- flush_sq = true;
-
- qp->flush_sq |= flush_sq;
- qp->flush_rq |= flush_rq;
- if (!flush_sq && !flush_rq)
- return 0;
-
- cqp = qp->pd->dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- if (info->userflushcode) {
- if (flush_rq) {
- temp |= LS_64(info->rq_minor_code, I40IW_CQPSQ_FWQE_RQMNERR) |
- LS_64(info->rq_major_code, I40IW_CQPSQ_FWQE_RQMJERR);
- }
- if (flush_sq) {
- temp |= LS_64(info->sq_minor_code, I40IW_CQPSQ_FWQE_SQMNERR) |
- LS_64(info->sq_major_code, I40IW_CQPSQ_FWQE_SQMJERR);
- }
- }
- set_64bit_val(wqe, 16, temp);
-
- temp = (info->generate_ae) ?
- info->ae_code | LS_64(info->ae_source, I40IW_CQPSQ_FWQE_AESOURCE) : 0;
-
- set_64bit_val(wqe, 8, temp);
-
- header = qp->qp_uk.qp_id |
- LS_64(I40IW_CQP_OP_FLUSH_WQES, I40IW_CQPSQ_OPCODE) |
- LS_64(info->generate_ae, I40IW_CQPSQ_FWQE_GENERATE_AE) |
- LS_64(info->userflushcode, I40IW_CQPSQ_FWQE_USERFLCODE) |
- LS_64(flush_sq, I40IW_CQPSQ_FWQE_FLUSHSQ) |
- LS_64(flush_rq, I40IW_CQPSQ_FWQE_FLUSHRQ) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "QP_FLUSH WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_gen_ae - generate AE, currently uses flush WQE CQP OP
- * @qp: sc qp
- * @info: gen ae information
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_gen_ae(
- struct i40iw_sc_qp *qp,
- struct i40iw_gen_ae_info *info,
- u64 scratch,
- bool post_sq)
-{
- u64 temp;
- u64 *wqe;
- struct i40iw_sc_cqp *cqp;
- u64 header;
-
- cqp = qp->pd->dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- temp = info->ae_code |
- LS_64(info->ae_source, I40IW_CQPSQ_FWQE_AESOURCE);
-
- set_64bit_val(wqe, 8, temp);
-
- header = qp->qp_uk.qp_id |
- LS_64(I40IW_CQP_OP_GEN_AE, I40IW_CQPSQ_OPCODE) |
- LS_64(1, I40IW_CQPSQ_FWQE_GENERATE_AE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "GEN_AE WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_qp_upload_context - upload qp's context
- * @dev: sc device struct
- * @info: upload context info ptr for return
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_qp_upload_context(
- struct i40iw_sc_dev *dev,
- struct i40iw_upload_context_info *info,
- u64 scratch,
- bool post_sq)
-{
- u64 *wqe;
- struct i40iw_sc_cqp *cqp;
- u64 header;
-
- cqp = dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe, 16, info->buf_pa);
-
- header = LS_64(info->qp_id, I40IW_CQPSQ_UCTX_QPID) |
- LS_64(I40IW_CQP_OP_UPLOAD_CONTEXT, I40IW_CQPSQ_OPCODE) |
- LS_64(info->qp_type, I40IW_CQPSQ_UCTX_QPTYPE) |
- LS_64(info->raw_format, I40IW_CQPSQ_UCTX_RAWFORMAT) |
- LS_64(info->freeze_qp, I40IW_CQPSQ_UCTX_FREEZEQP) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(dev, I40IW_DEBUG_WQE, "QP_UPLOAD_CTX WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_qp_setctx - set qp's context
- * @qp: sc qp
- * @qp_ctx: context ptr
- * @info: ctx info
- */
-static enum i40iw_status_code i40iw_sc_qp_setctx(
- struct i40iw_sc_qp *qp,
- u64 *qp_ctx,
- struct i40iw_qp_host_ctx_info *info)
-{
- struct i40iwarp_offload_info *iw;
- struct i40iw_tcp_offload_info *tcp;
- struct i40iw_sc_vsi *vsi;
- struct i40iw_sc_dev *dev;
- u64 qw0, qw3, qw7 = 0;
-
- iw = info->iwarp_info;
- tcp = info->tcp_info;
- vsi = qp->vsi;
- dev = qp->dev;
- if (info->add_to_qoslist) {
- qp->user_pri = info->user_pri;
- i40iw_qp_add_qos(qp);
- i40iw_debug(qp->dev, I40IW_DEBUG_DCB, "%s qp[%d] UP[%d] qset[%d]\n",
- __func__, qp->qp_uk.qp_id, qp->user_pri, qp->qs_handle);
- }
- qw0 = LS_64(qp->qp_uk.rq_wqe_size, I40IWQPC_RQWQESIZE) |
- LS_64(info->err_rq_idx_valid, I40IWQPC_ERR_RQ_IDX_VALID) |
- LS_64(qp->rcv_tph_en, I40IWQPC_RCVTPHEN) |
- LS_64(qp->xmit_tph_en, I40IWQPC_XMITTPHEN) |
- LS_64(qp->rq_tph_en, I40IWQPC_RQTPHEN) |
- LS_64(qp->sq_tph_en, I40IWQPC_SQTPHEN);
-
- set_64bit_val(qp_ctx, 8, qp->sq_pa);
- set_64bit_val(qp_ctx, 16, qp->rq_pa);
-
- qw3 = LS_64(qp->src_mac_addr_idx, I40IWQPC_SRCMACADDRIDX) |
- LS_64(qp->hw_rq_size, I40IWQPC_RQSIZE) |
- LS_64(qp->hw_sq_size, I40IWQPC_SQSIZE);
-
- set_64bit_val(qp_ctx,
- 128,
- LS_64(info->err_rq_idx, I40IWQPC_ERR_RQ_IDX));
-
- set_64bit_val(qp_ctx,
- 136,
- LS_64(info->send_cq_num, I40IWQPC_TXCQNUM) |
- LS_64(info->rcv_cq_num, I40IWQPC_RXCQNUM));
-
- set_64bit_val(qp_ctx,
- 168,
- LS_64(info->qp_compl_ctx, I40IWQPC_QPCOMPCTX));
- set_64bit_val(qp_ctx,
- 176,
- LS_64(qp->sq_tph_val, I40IWQPC_SQTPHVAL) |
- LS_64(qp->rq_tph_val, I40IWQPC_RQTPHVAL) |
- LS_64(qp->qs_handle, I40IWQPC_QSHANDLE) |
- LS_64(vsi->exception_lan_queue, I40IWQPC_EXCEPTION_LAN_QUEUE));
-
- if (info->iwarp_info_valid) {
- qw0 |= LS_64(iw->ddp_ver, I40IWQPC_DDP_VER) |
- LS_64(iw->rdmap_ver, I40IWQPC_RDMAP_VER);
-
- qw7 |= LS_64(iw->pd_id, I40IWQPC_PDIDX);
- set_64bit_val(qp_ctx,
- 144,
- LS_64(qp->q2_pa, I40IWQPC_Q2ADDR) |
- LS_64(vsi->fcn_id, I40IWQPC_STAT_INDEX));
- set_64bit_val(qp_ctx,
- 152,
- LS_64(iw->last_byte_sent, I40IWQPC_LASTBYTESENT));
-
- set_64bit_val(qp_ctx,
- 160,
- LS_64(iw->ord_size, I40IWQPC_ORDSIZE) |
- LS_64(iw->ird_size, I40IWQPC_IRDSIZE) |
- LS_64(iw->wr_rdresp_en, I40IWQPC_WRRDRSPOK) |
- LS_64(iw->rd_enable, I40IWQPC_RDOK) |
- LS_64(iw->snd_mark_en, I40IWQPC_SNDMARKERS) |
- LS_64(iw->bind_en, I40IWQPC_BINDEN) |
- LS_64(iw->fast_reg_en, I40IWQPC_FASTREGEN) |
- LS_64(iw->priv_mode_en, I40IWQPC_PRIVEN) |
- LS_64((((vsi->stats_fcn_id_alloc) &&
- (dev->is_pf) && (vsi->fcn_id >= I40IW_FIRST_NON_PF_STAT)) ? 1 : 0),
- I40IWQPC_USESTATSINSTANCE) |
- LS_64(1, I40IWQPC_IWARPMODE) |
- LS_64(iw->rcv_mark_en, I40IWQPC_RCVMARKERS) |
- LS_64(iw->align_hdrs, I40IWQPC_ALIGNHDRS) |
- LS_64(iw->rcv_no_mpa_crc, I40IWQPC_RCVNOMPACRC) |
- LS_64(iw->rcv_mark_offset, I40IWQPC_RCVMARKOFFSET) |
- LS_64(iw->snd_mark_offset, I40IWQPC_SNDMARKOFFSET));
- }
- if (info->tcp_info_valid) {
- qw0 |= LS_64(tcp->ipv4, I40IWQPC_IPV4) |
- LS_64(tcp->no_nagle, I40IWQPC_NONAGLE) |
- LS_64(tcp->insert_vlan_tag, I40IWQPC_INSERTVLANTAG) |
- LS_64(tcp->time_stamp, I40IWQPC_TIMESTAMP) |
- LS_64(tcp->cwnd_inc_limit, I40IWQPC_LIMIT) |
- LS_64(tcp->drop_ooo_seg, I40IWQPC_DROPOOOSEG) |
- LS_64(tcp->dup_ack_thresh, I40IWQPC_DUPACK_THRESH);
-
- qw3 |= LS_64(tcp->ttl, I40IWQPC_TTL) |
- LS_64(tcp->src_mac_addr_idx, I40IWQPC_SRCMACADDRIDX) |
- LS_64(tcp->avoid_stretch_ack, I40IWQPC_AVOIDSTRETCHACK) |
- LS_64(tcp->tos, I40IWQPC_TOS) |
- LS_64(tcp->src_port, I40IWQPC_SRCPORTNUM) |
- LS_64(tcp->dst_port, I40IWQPC_DESTPORTNUM);
-
- qp->src_mac_addr_idx = tcp->src_mac_addr_idx;
- set_64bit_val(qp_ctx,
- 32,
- LS_64(tcp->dest_ip_addr2, I40IWQPC_DESTIPADDR2) |
- LS_64(tcp->dest_ip_addr3, I40IWQPC_DESTIPADDR3));
-
- set_64bit_val(qp_ctx,
- 40,
- LS_64(tcp->dest_ip_addr0, I40IWQPC_DESTIPADDR0) |
- LS_64(tcp->dest_ip_addr1, I40IWQPC_DESTIPADDR1));
-
- set_64bit_val(qp_ctx,
- 48,
- LS_64(tcp->snd_mss, I40IWQPC_SNDMSS) |
- LS_64(tcp->vlan_tag, I40IWQPC_VLANTAG) |
- LS_64(tcp->arp_idx, I40IWQPC_ARPIDX));
-
- qw7 |= LS_64(tcp->flow_label, I40IWQPC_FLOWLABEL) |
- LS_64(tcp->wscale, I40IWQPC_WSCALE) |
- LS_64(tcp->ignore_tcp_opt, I40IWQPC_IGNORE_TCP_OPT) |
- LS_64(tcp->ignore_tcp_uns_opt, I40IWQPC_IGNORE_TCP_UNS_OPT) |
- LS_64(tcp->tcp_state, I40IWQPC_TCPSTATE) |
- LS_64(tcp->rcv_wscale, I40IWQPC_RCVSCALE) |
- LS_64(tcp->snd_wscale, I40IWQPC_SNDSCALE);
-
- set_64bit_val(qp_ctx,
- 72,
- LS_64(tcp->time_stamp_recent, I40IWQPC_TIMESTAMP_RECENT) |
- LS_64(tcp->time_stamp_age, I40IWQPC_TIMESTAMP_AGE));
- set_64bit_val(qp_ctx,
- 80,
- LS_64(tcp->snd_nxt, I40IWQPC_SNDNXT) |
- LS_64(tcp->snd_wnd, I40IWQPC_SNDWND));
-
- set_64bit_val(qp_ctx,
- 88,
- LS_64(tcp->rcv_nxt, I40IWQPC_RCVNXT) |
- LS_64(tcp->rcv_wnd, I40IWQPC_RCVWND));
- set_64bit_val(qp_ctx,
- 96,
- LS_64(tcp->snd_max, I40IWQPC_SNDMAX) |
- LS_64(tcp->snd_una, I40IWQPC_SNDUNA));
- set_64bit_val(qp_ctx,
- 104,
- LS_64(tcp->srtt, I40IWQPC_SRTT) |
- LS_64(tcp->rtt_var, I40IWQPC_RTTVAR));
- set_64bit_val(qp_ctx,
- 112,
- LS_64(tcp->ss_thresh, I40IWQPC_SSTHRESH) |
- LS_64(tcp->cwnd, I40IWQPC_CWND));
- set_64bit_val(qp_ctx,
- 120,
- LS_64(tcp->snd_wl1, I40IWQPC_SNDWL1) |
- LS_64(tcp->snd_wl2, I40IWQPC_SNDWL2));
- set_64bit_val(qp_ctx,
- 128,
- LS_64(tcp->max_snd_window, I40IWQPC_MAXSNDWND) |
- LS_64(tcp->rexmit_thresh, I40IWQPC_REXMIT_THRESH));
- set_64bit_val(qp_ctx,
- 184,
- LS_64(tcp->local_ipaddr3, I40IWQPC_LOCAL_IPADDR3) |
- LS_64(tcp->local_ipaddr2, I40IWQPC_LOCAL_IPADDR2));
- set_64bit_val(qp_ctx,
- 192,
- LS_64(tcp->local_ipaddr1, I40IWQPC_LOCAL_IPADDR1) |
- LS_64(tcp->local_ipaddr0, I40IWQPC_LOCAL_IPADDR0));
- }
-
- set_64bit_val(qp_ctx, 0, qw0);
- set_64bit_val(qp_ctx, 24, qw3);
- set_64bit_val(qp_ctx, 56, qw7);
-
- i40iw_debug_buf(qp->dev, I40IW_DEBUG_WQE, "QP_HOST)CTX WQE",
- qp_ctx, I40IW_QP_CTX_SIZE);
- return 0;
-}
-
-/**
- * i40iw_sc_alloc_stag - mr stag alloc
- * @dev: sc device struct
- * @info: stag info
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_alloc_stag(
- struct i40iw_sc_dev *dev,
- struct i40iw_allocate_stag_info *info,
- u64 scratch,
- bool post_sq)
-{
- u64 *wqe;
- struct i40iw_sc_cqp *cqp;
- u64 header;
- enum i40iw_page_size page_size;
-
- page_size = (info->page_size == 0x200000) ? I40IW_PAGE_SIZE_2M : I40IW_PAGE_SIZE_4K;
- cqp = dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe,
- 8,
- LS_64(info->pd_id, I40IW_CQPSQ_STAG_PDID) |
- LS_64(info->total_len, I40IW_CQPSQ_STAG_STAGLEN));
- set_64bit_val(wqe,
- 16,
- LS_64(info->stag_idx, I40IW_CQPSQ_STAG_IDX));
- set_64bit_val(wqe,
- 40,
- LS_64(info->hmc_fcn_index, I40IW_CQPSQ_STAG_HMCFNIDX));
-
- header = LS_64(I40IW_CQP_OP_ALLOC_STAG, I40IW_CQPSQ_OPCODE) |
- LS_64(1, I40IW_CQPSQ_STAG_MR) |
- LS_64(info->access_rights, I40IW_CQPSQ_STAG_ARIGHTS) |
- LS_64(info->chunk_size, I40IW_CQPSQ_STAG_LPBLSIZE) |
- LS_64(page_size, I40IW_CQPSQ_STAG_HPAGESIZE) |
- LS_64(info->remote_access, I40IW_CQPSQ_STAG_REMACCENABLED) |
- LS_64(info->use_hmc_fcn_index, I40IW_CQPSQ_STAG_USEHMCFNIDX) |
- LS_64(info->use_pf_rid, I40IW_CQPSQ_STAG_USEPFRID) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(dev, I40IW_DEBUG_WQE, "ALLOC_STAG WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_mr_reg_non_shared - non-shared mr registration
- * @dev: sc device struct
- * @info: mr info
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_mr_reg_non_shared(
- struct i40iw_sc_dev *dev,
- struct i40iw_reg_ns_stag_info *info,
- u64 scratch,
- bool post_sq)
-{
- u64 *wqe;
- u64 temp;
- struct i40iw_sc_cqp *cqp;
- u64 header;
- u32 pble_obj_cnt;
- bool remote_access;
- u8 addr_type;
- enum i40iw_page_size page_size;
-
- page_size = (info->page_size == 0x200000) ? I40IW_PAGE_SIZE_2M : I40IW_PAGE_SIZE_4K;
- if (info->access_rights & (I40IW_ACCESS_FLAGS_REMOTEREAD_ONLY |
- I40IW_ACCESS_FLAGS_REMOTEWRITE_ONLY))
- remote_access = true;
- else
- remote_access = false;
-
- pble_obj_cnt = dev->hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].cnt;
-
- if (info->chunk_size && (info->first_pm_pbl_index >= pble_obj_cnt))
- return I40IW_ERR_INVALID_PBLE_INDEX;
-
- cqp = dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- temp = (info->addr_type == I40IW_ADDR_TYPE_VA_BASED) ? (uintptr_t)info->va : info->fbo;
- set_64bit_val(wqe, 0, temp);
-
- set_64bit_val(wqe,
- 8,
- LS_64(info->total_len, I40IW_CQPSQ_STAG_STAGLEN) |
- LS_64(info->pd_id, I40IW_CQPSQ_STAG_PDID));
-
- set_64bit_val(wqe,
- 16,
- LS_64(info->stag_key, I40IW_CQPSQ_STAG_KEY) |
- LS_64(info->stag_idx, I40IW_CQPSQ_STAG_IDX));
- if (!info->chunk_size) {
- set_64bit_val(wqe, 32, info->reg_addr_pa);
- set_64bit_val(wqe, 48, 0);
- } else {
- set_64bit_val(wqe, 32, 0);
- set_64bit_val(wqe, 48, info->first_pm_pbl_index);
- }
- set_64bit_val(wqe, 40, info->hmc_fcn_index);
- set_64bit_val(wqe, 56, 0);
-
- addr_type = (info->addr_type == I40IW_ADDR_TYPE_VA_BASED) ? 1 : 0;
- header = LS_64(I40IW_CQP_OP_REG_MR, I40IW_CQPSQ_OPCODE) |
- LS_64(1, I40IW_CQPSQ_STAG_MR) |
- LS_64(info->chunk_size, I40IW_CQPSQ_STAG_LPBLSIZE) |
- LS_64(page_size, I40IW_CQPSQ_STAG_HPAGESIZE) |
- LS_64(info->access_rights, I40IW_CQPSQ_STAG_ARIGHTS) |
- LS_64(remote_access, I40IW_CQPSQ_STAG_REMACCENABLED) |
- LS_64(addr_type, I40IW_CQPSQ_STAG_VABASEDTO) |
- LS_64(info->use_hmc_fcn_index, I40IW_CQPSQ_STAG_USEHMCFNIDX) |
- LS_64(info->use_pf_rid, I40IW_CQPSQ_STAG_USEPFRID) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(dev, I40IW_DEBUG_WQE, "MR_REG_NS WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_mr_reg_shared - registered shared memory region
- * @dev: sc device struct
- * @info: info for shared memory registeration
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_mr_reg_shared(
- struct i40iw_sc_dev *dev,
- struct i40iw_register_shared_stag *info,
- u64 scratch,
- bool post_sq)
-{
- u64 *wqe;
- struct i40iw_sc_cqp *cqp;
- u64 temp, va64, fbo, header;
- u32 va32;
- bool remote_access;
- u8 addr_type;
-
- if (info->access_rights & (I40IW_ACCESS_FLAGS_REMOTEREAD_ONLY |
- I40IW_ACCESS_FLAGS_REMOTEWRITE_ONLY))
- remote_access = true;
- else
- remote_access = false;
- cqp = dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- va64 = (uintptr_t)(info->va);
- va32 = (u32)(va64 & 0x00000000FFFFFFFF);
- fbo = (u64)(va32 & (4096 - 1));
-
- set_64bit_val(wqe,
- 0,
- (info->addr_type == I40IW_ADDR_TYPE_VA_BASED ? (uintptr_t)info->va : fbo));
-
- set_64bit_val(wqe,
- 8,
- LS_64(info->pd_id, I40IW_CQPSQ_STAG_PDID));
- temp = LS_64(info->new_stag_key, I40IW_CQPSQ_STAG_KEY) |
- LS_64(info->new_stag_idx, I40IW_CQPSQ_STAG_IDX) |
- LS_64(info->parent_stag_idx, I40IW_CQPSQ_STAG_PARENTSTAGIDX);
- set_64bit_val(wqe, 16, temp);
-
- addr_type = (info->addr_type == I40IW_ADDR_TYPE_VA_BASED) ? 1 : 0;
- header = LS_64(I40IW_CQP_OP_REG_SMR, I40IW_CQPSQ_OPCODE) |
- LS_64(1, I40IW_CQPSQ_STAG_MR) |
- LS_64(info->access_rights, I40IW_CQPSQ_STAG_ARIGHTS) |
- LS_64(remote_access, I40IW_CQPSQ_STAG_REMACCENABLED) |
- LS_64(addr_type, I40IW_CQPSQ_STAG_VABASEDTO) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(dev, I40IW_DEBUG_WQE, "MR_REG_SHARED WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_dealloc_stag - deallocate stag
- * @dev: sc device struct
- * @info: dealloc stag info
- * @scratch: u64 saved to be used during cqp completion
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_dealloc_stag(
- struct i40iw_sc_dev *dev,
- struct i40iw_dealloc_stag_info *info,
- u64 scratch,
- bool post_sq)
-{
- u64 header;
- u64 *wqe;
- struct i40iw_sc_cqp *cqp;
-
- cqp = dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe,
- 8,
- LS_64(info->pd_id, I40IW_CQPSQ_STAG_PDID));
- set_64bit_val(wqe,
- 16,
- LS_64(info->stag_idx, I40IW_CQPSQ_STAG_IDX));
-
- header = LS_64(I40IW_CQP_OP_DEALLOC_STAG, I40IW_CQPSQ_OPCODE) |
- LS_64(info->mr, I40IW_CQPSQ_STAG_MR) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(dev, I40IW_DEBUG_WQE, "DEALLOC_STAG WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_query_stag - query hardware for stag
- * @dev: sc device struct
- * @scratch: u64 saved to be used during cqp completion
- * @stag_index: stag index for query
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_query_stag(struct i40iw_sc_dev *dev,
- u64 scratch,
- u32 stag_index,
- bool post_sq)
-{
- u64 header;
- u64 *wqe;
- struct i40iw_sc_cqp *cqp;
-
- cqp = dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe,
- 16,
- LS_64(stag_index, I40IW_CQPSQ_QUERYSTAG_IDX));
-
- header = LS_64(I40IW_CQP_OP_QUERY_STAG, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(dev, I40IW_DEBUG_WQE, "QUERY_STAG WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_mw_alloc - mw allocate
- * @dev: sc device struct
- * @scratch: u64 saved to be used during cqp completion
- * @mw_stag_index:stag index
- * @pd_id: pd is for this mw
- * @post_sq: flag for cqp db to ring
- */
-static enum i40iw_status_code i40iw_sc_mw_alloc(
- struct i40iw_sc_dev *dev,
- u64 scratch,
- u32 mw_stag_index,
- u16 pd_id,
- bool post_sq)
-{
- u64 header;
- struct i40iw_sc_cqp *cqp;
- u64 *wqe;
-
- cqp = dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe, 8, LS_64(pd_id, I40IW_CQPSQ_STAG_PDID));
- set_64bit_val(wqe,
- 16,
- LS_64(mw_stag_index, I40IW_CQPSQ_STAG_IDX));
-
- header = LS_64(I40IW_CQP_OP_ALLOC_STAG, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(dev, I40IW_DEBUG_WQE, "MW_ALLOC WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_mr_fast_register - Posts RDMA fast register mr WR to iwarp qp
- * @qp: sc qp struct
- * @info: fast mr info
- * @post_sq: flag for cqp db to ring
- */
-enum i40iw_status_code i40iw_sc_mr_fast_register(
- struct i40iw_sc_qp *qp,
- struct i40iw_fast_reg_stag_info *info,
- bool post_sq)
-{
- u64 temp, header;
- u64 *wqe;
- u32 wqe_idx;
- enum i40iw_page_size page_size;
-
- page_size = (info->page_size == 0x200000) ? I40IW_PAGE_SIZE_2M : I40IW_PAGE_SIZE_4K;
- wqe = i40iw_qp_get_next_send_wqe(&qp->qp_uk, &wqe_idx, I40IW_QP_WQE_MIN_SIZE,
- 0, info->wr_id);
- if (!wqe)
- return I40IW_ERR_QP_TOOMANY_WRS_POSTED;
-
- i40iw_debug(qp->dev, I40IW_DEBUG_MR, "%s: wr_id[%llxh] wqe_idx[%04d] location[%p]\n",
- __func__, info->wr_id, wqe_idx,
- &qp->qp_uk.sq_wrtrk_array[wqe_idx].wrid);
- temp = (info->addr_type == I40IW_ADDR_TYPE_VA_BASED) ? (uintptr_t)info->va : info->fbo;
- set_64bit_val(wqe, 0, temp);
-
- temp = RS_64(info->first_pm_pbl_index >> 16, I40IWQPSQ_FIRSTPMPBLIDXHI);
- set_64bit_val(wqe,
- 8,
- LS_64(temp, I40IWQPSQ_FIRSTPMPBLIDXHI) |
- LS_64(info->reg_addr_pa >> I40IWQPSQ_PBLADDR_SHIFT, I40IWQPSQ_PBLADDR));
-
- set_64bit_val(wqe,
- 16,
- info->total_len |
- LS_64(info->first_pm_pbl_index, I40IWQPSQ_FIRSTPMPBLIDXLO));
-
- header = LS_64(info->stag_key, I40IWQPSQ_STAGKEY) |
- LS_64(info->stag_idx, I40IWQPSQ_STAGINDEX) |
- LS_64(I40IWQP_OP_FAST_REGISTER, I40IWQPSQ_OPCODE) |
- LS_64(info->chunk_size, I40IWQPSQ_LPBLSIZE) |
- LS_64(page_size, I40IWQPSQ_HPAGESIZE) |
- LS_64(info->access_rights, I40IWQPSQ_STAGRIGHTS) |
- LS_64(info->addr_type, I40IWQPSQ_VABASEDTO) |
- LS_64(info->read_fence, I40IWQPSQ_READFENCE) |
- LS_64(info->local_fence, I40IWQPSQ_LOCALFENCE) |
- LS_64(info->signaled, I40IWQPSQ_SIGCOMPL) |
- LS_64(qp->qp_uk.swqe_polarity, I40IWQPSQ_VALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(qp->dev, I40IW_DEBUG_WQE, "FAST_REG WQE",
- wqe, I40IW_QP_WQE_MIN_SIZE);
-
- if (post_sq)
- i40iw_qp_post_wr(&qp->qp_uk);
- return 0;
-}
-
-/**
- * i40iw_sc_send_lsmm - send last streaming mode message
- * @qp: sc qp struct
- * @lsmm_buf: buffer with lsmm message
- * @size: size of lsmm buffer
- * @stag: stag of lsmm buffer
- */
-static void i40iw_sc_send_lsmm(struct i40iw_sc_qp *qp,
- void *lsmm_buf,
- u32 size,
- i40iw_stag stag)
-{
- u64 *wqe;
- u64 header;
- struct i40iw_qp_uk *qp_uk;
-
- qp_uk = &qp->qp_uk;
- wqe = qp_uk->sq_base->elem;
-
- set_64bit_val(wqe, 0, (uintptr_t)lsmm_buf);
-
- set_64bit_val(wqe, 8, (size | LS_64(stag, I40IWQPSQ_FRAG_STAG)));
-
- set_64bit_val(wqe, 16, 0);
-
- header = LS_64(I40IWQP_OP_RDMA_SEND, I40IWQPSQ_OPCODE) |
- LS_64(1, I40IWQPSQ_STREAMMODE) |
- LS_64(1, I40IWQPSQ_WAITFORRCVPDU) |
- LS_64(qp->qp_uk.swqe_polarity, I40IWQPSQ_VALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(qp->dev, I40IW_DEBUG_QP, "SEND_LSMM WQE",
- wqe, I40IW_QP_WQE_MIN_SIZE);
-}
-
-/**
- * i40iw_sc_send_lsmm_nostag - for privilege qp
- * @qp: sc qp struct
- * @lsmm_buf: buffer with lsmm message
- * @size: size of lsmm buffer
- */
-static void i40iw_sc_send_lsmm_nostag(struct i40iw_sc_qp *qp,
- void *lsmm_buf,
- u32 size)
-{
- u64 *wqe;
- u64 header;
- struct i40iw_qp_uk *qp_uk;
-
- qp_uk = &qp->qp_uk;
- wqe = qp_uk->sq_base->elem;
-
- set_64bit_val(wqe, 0, (uintptr_t)lsmm_buf);
-
- set_64bit_val(wqe, 8, size);
-
- set_64bit_val(wqe, 16, 0);
-
- header = LS_64(I40IWQP_OP_RDMA_SEND, I40IWQPSQ_OPCODE) |
- LS_64(1, I40IWQPSQ_STREAMMODE) |
- LS_64(1, I40IWQPSQ_WAITFORRCVPDU) |
- LS_64(qp->qp_uk.swqe_polarity, I40IWQPSQ_VALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(qp->dev, I40IW_DEBUG_WQE, "SEND_LSMM_NOSTAG WQE",
- wqe, I40IW_QP_WQE_MIN_SIZE);
-}
-
-/**
- * i40iw_sc_send_rtt - send last read0 or write0
- * @qp: sc qp struct
- * @read: Do read0 or write0
- */
-static void i40iw_sc_send_rtt(struct i40iw_sc_qp *qp, bool read)
-{
- u64 *wqe;
- u64 header;
- struct i40iw_qp_uk *qp_uk;
-
- qp_uk = &qp->qp_uk;
- wqe = qp_uk->sq_base->elem;
-
- set_64bit_val(wqe, 0, 0);
- set_64bit_val(wqe, 8, 0);
- set_64bit_val(wqe, 16, 0);
- if (read) {
- header = LS_64(0x1234, I40IWQPSQ_REMSTAG) |
- LS_64(I40IWQP_OP_RDMA_READ, I40IWQPSQ_OPCODE) |
- LS_64(qp->qp_uk.swqe_polarity, I40IWQPSQ_VALID);
- set_64bit_val(wqe, 8, ((u64)0xabcd << 32));
- } else {
- header = LS_64(I40IWQP_OP_RDMA_WRITE, I40IWQPSQ_OPCODE) |
- LS_64(qp->qp_uk.swqe_polarity, I40IWQPSQ_VALID);
- }
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(qp->dev, I40IW_DEBUG_WQE, "RTR WQE",
- wqe, I40IW_QP_WQE_MIN_SIZE);
-}
-
-/**
- * i40iw_sc_post_wqe0 - send wqe with opcode
- * @qp: sc qp struct
- * @opcode: opcode to use for wqe0
- */
-static enum i40iw_status_code i40iw_sc_post_wqe0(struct i40iw_sc_qp *qp, u8 opcode)
-{
- u64 *wqe;
- u64 header;
- struct i40iw_qp_uk *qp_uk;
-
- qp_uk = &qp->qp_uk;
- wqe = qp_uk->sq_base->elem;
-
- if (!wqe)
- return I40IW_ERR_QP_TOOMANY_WRS_POSTED;
- switch (opcode) {
- case I40IWQP_OP_NOP:
- set_64bit_val(wqe, 0, 0);
- set_64bit_val(wqe, 8, 0);
- set_64bit_val(wqe, 16, 0);
- header = LS_64(I40IWQP_OP_NOP, I40IWQPSQ_OPCODE) |
- LS_64(qp->qp_uk.swqe_polarity, I40IWQPSQ_VALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
- break;
- case I40IWQP_OP_RDMA_SEND:
- set_64bit_val(wqe, 0, 0);
- set_64bit_val(wqe, 8, 0);
- set_64bit_val(wqe, 16, 0);
- header = LS_64(I40IWQP_OP_RDMA_SEND, I40IWQPSQ_OPCODE) |
- LS_64(qp->qp_uk.swqe_polarity, I40IWQPSQ_VALID) |
- LS_64(1, I40IWQPSQ_STREAMMODE) |
- LS_64(1, I40IWQPSQ_WAITFORRCVPDU);
-
- i40iw_insert_wqe_hdr(wqe, header);
- break;
- default:
- i40iw_debug(qp->dev, I40IW_DEBUG_QP, "%s: Invalid WQE zero opcode\n",
- __func__);
- break;
- }
- return 0;
-}
-
-/**
- * i40iw_sc_init_iw_hmc() - queries fpm values using cqp and populates hmc_info
- * @dev : ptr to i40iw_dev struct
- * @hmc_fn_id: hmc function id
- */
-enum i40iw_status_code i40iw_sc_init_iw_hmc(struct i40iw_sc_dev *dev, u8 hmc_fn_id)
-{
- struct i40iw_hmc_info *hmc_info;
- struct i40iw_dma_mem query_fpm_mem;
- struct i40iw_virt_mem virt_mem;
- struct i40iw_vfdev *vf_dev = NULL;
- u32 mem_size;
- enum i40iw_status_code ret_code = 0;
- bool poll_registers = true;
- u16 iw_vf_idx;
- u8 wait_type;
-
- if (hmc_fn_id >= I40IW_MAX_VF_FPM_ID ||
- (dev->hmc_fn_id != hmc_fn_id && hmc_fn_id < I40IW_FIRST_VF_FPM_ID))
- return I40IW_ERR_INVALID_HMCFN_ID;
-
- i40iw_debug(dev, I40IW_DEBUG_HMC, "hmc_fn_id %u, dev->hmc_fn_id %u\n", hmc_fn_id,
- dev->hmc_fn_id);
- if (hmc_fn_id == dev->hmc_fn_id) {
- hmc_info = dev->hmc_info;
- query_fpm_mem.pa = dev->fpm_query_buf_pa;
- query_fpm_mem.va = dev->fpm_query_buf;
- } else {
- vf_dev = i40iw_vfdev_from_fpm(dev, hmc_fn_id);
- if (!vf_dev)
- return I40IW_ERR_INVALID_VF_ID;
-
- hmc_info = &vf_dev->hmc_info;
- iw_vf_idx = vf_dev->iw_vf_idx;
- i40iw_debug(dev, I40IW_DEBUG_HMC, "vf_dev %p, hmc_info %p, hmc_obj %p\n", vf_dev,
- hmc_info, hmc_info->hmc_obj);
- if (!vf_dev->fpm_query_buf) {
- if (!dev->vf_fpm_query_buf[iw_vf_idx].va) {
- ret_code = i40iw_alloc_query_fpm_buf(dev,
- &dev->vf_fpm_query_buf[iw_vf_idx]);
- if (ret_code)
- return ret_code;
- }
- vf_dev->fpm_query_buf = dev->vf_fpm_query_buf[iw_vf_idx].va;
- vf_dev->fpm_query_buf_pa = dev->vf_fpm_query_buf[iw_vf_idx].pa;
- }
- query_fpm_mem.pa = vf_dev->fpm_query_buf_pa;
- query_fpm_mem.va = vf_dev->fpm_query_buf;
- /**
- * It is HARDWARE specific:
- * this call is done by PF for VF and
- * i40iw_sc_query_fpm_values needs ccq poll
- * because PF ccq is already created.
- */
- poll_registers = false;
- }
-
- hmc_info->hmc_fn_id = hmc_fn_id;
-
- if (hmc_fn_id != dev->hmc_fn_id) {
- ret_code =
- i40iw_cqp_query_fpm_values_cmd(dev, &query_fpm_mem, hmc_fn_id);
- } else {
- wait_type = poll_registers ? (u8)I40IW_CQP_WAIT_POLL_REGS :
- (u8)I40IW_CQP_WAIT_POLL_CQ;
-
- ret_code = i40iw_sc_query_fpm_values(
- dev->cqp,
- 0,
- hmc_info->hmc_fn_id,
- &query_fpm_mem,
- true,
- wait_type);
- }
- if (ret_code)
- return ret_code;
-
- /* parse the fpm_query_buf and fill hmc obj info */
- ret_code =
- i40iw_sc_parse_fpm_query_buf((u64 *)query_fpm_mem.va,
- hmc_info,
- &dev->hmc_fpm_misc);
- if (ret_code)
- return ret_code;
- i40iw_debug_buf(dev, I40IW_DEBUG_HMC, "QUERY FPM BUFFER",
- query_fpm_mem.va, I40IW_QUERY_FPM_BUF_SIZE);
-
- if (hmc_fn_id != dev->hmc_fn_id) {
- i40iw_cqp_commit_fpm_values_cmd(dev, &query_fpm_mem, hmc_fn_id);
-
- /* parse the fpm_commit_buf and fill hmc obj info */
- i40iw_sc_parse_fpm_commit_buf((u64 *)query_fpm_mem.va, hmc_info->hmc_obj, &hmc_info->sd_table.sd_cnt);
- mem_size = sizeof(struct i40iw_hmc_sd_entry) *
- (hmc_info->sd_table.sd_cnt + hmc_info->first_sd_index);
- ret_code = i40iw_allocate_virt_mem(dev->hw, &virt_mem, mem_size);
- if (ret_code)
- return ret_code;
- hmc_info->sd_table.sd_entry = virt_mem.va;
- }
-
- return ret_code;
-}
-
-/**
- * i40iw_sc_configure_iw_fpm() - commits hmc obj cnt values using cqp command and
- * populates fpm base address in hmc_info
- * @dev : ptr to i40iw_dev struct
- * @hmc_fn_id: hmc function id
- */
-static enum i40iw_status_code i40iw_sc_configure_iw_fpm(struct i40iw_sc_dev *dev,
- u8 hmc_fn_id)
-{
- struct i40iw_hmc_info *hmc_info;
- struct i40iw_hmc_obj_info *obj_info;
- u64 *buf;
- struct i40iw_dma_mem commit_fpm_mem;
- u32 i, j;
- enum i40iw_status_code ret_code = 0;
- bool poll_registers = true;
- u8 wait_type;
-
- if (hmc_fn_id >= I40IW_MAX_VF_FPM_ID ||
- (dev->hmc_fn_id != hmc_fn_id && hmc_fn_id < I40IW_FIRST_VF_FPM_ID))
- return I40IW_ERR_INVALID_HMCFN_ID;
-
- if (hmc_fn_id == dev->hmc_fn_id) {
- hmc_info = dev->hmc_info;
- } else {
- hmc_info = i40iw_vf_hmcinfo_from_fpm(dev, hmc_fn_id);
- poll_registers = false;
- }
- if (!hmc_info)
- return I40IW_ERR_BAD_PTR;
-
- obj_info = hmc_info->hmc_obj;
- buf = dev->fpm_commit_buf;
-
- /* copy cnt values in commit buf */
- for (i = I40IW_HMC_IW_QP, j = 0; i <= I40IW_HMC_IW_PBLE;
- i++, j += 8)
- set_64bit_val(buf, j, (u64)obj_info[i].cnt);
-
- set_64bit_val(buf, 40, 0); /* APBVT rsvd */
-
- commit_fpm_mem.pa = dev->fpm_commit_buf_pa;
- commit_fpm_mem.va = dev->fpm_commit_buf;
- wait_type = poll_registers ? (u8)I40IW_CQP_WAIT_POLL_REGS :
- (u8)I40IW_CQP_WAIT_POLL_CQ;
- ret_code = i40iw_sc_commit_fpm_values(
- dev->cqp,
- 0,
- hmc_info->hmc_fn_id,
- &commit_fpm_mem,
- true,
- wait_type);
-
- /* parse the fpm_commit_buf and fill hmc obj info */
- if (!ret_code)
- ret_code = i40iw_sc_parse_fpm_commit_buf(dev->fpm_commit_buf,
- hmc_info->hmc_obj,
- &hmc_info->sd_table.sd_cnt);
-
- i40iw_debug_buf(dev, I40IW_DEBUG_HMC, "COMMIT FPM BUFFER",
- commit_fpm_mem.va, I40IW_COMMIT_FPM_BUF_SIZE);
-
- return ret_code;
-}
-
-/**
- * cqp_sds_wqe_fill - fill cqp wqe doe sd
- * @cqp: struct for cqp hw
- * @info: sd info for wqe
- * @scratch: u64 saved to be used during cqp completion
- */
-static enum i40iw_status_code cqp_sds_wqe_fill(struct i40iw_sc_cqp *cqp,
- struct i40iw_update_sds_info *info,
- u64 scratch)
-{
- u64 data;
- u64 header;
- u64 *wqe;
- int mem_entries, wqe_entries;
- struct i40iw_dma_mem *sdbuf = &cqp->sdbuf;
- u64 offset;
- u32 wqe_idx;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe_idx(cqp, scratch, &wqe_idx);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- I40IW_CQP_INIT_WQE(wqe);
- wqe_entries = (info->cnt > 3) ? 3 : info->cnt;
- mem_entries = info->cnt - wqe_entries;
-
- header = LS_64(I40IW_CQP_OP_UPDATE_PE_SDS, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID) |
- LS_64(mem_entries, I40IW_CQPSQ_UPESD_ENTRY_COUNT);
-
- if (mem_entries) {
- offset = wqe_idx * I40IW_UPDATE_SD_BUF_SIZE;
- memcpy((char *)sdbuf->va + offset, &info->entry[3],
- mem_entries << 4);
- data = (u64)sdbuf->pa + offset;
- } else {
- data = 0;
- }
- data |= LS_64(info->hmc_fn_id, I40IW_CQPSQ_UPESD_HMCFNID);
-
- set_64bit_val(wqe, 16, data);
-
- switch (wqe_entries) {
- case 3:
- set_64bit_val(wqe, 48,
- (LS_64(info->entry[2].cmd, I40IW_CQPSQ_UPESD_SDCMD) |
- LS_64(1, I40IW_CQPSQ_UPESD_ENTRY_VALID)));
-
- set_64bit_val(wqe, 56, info->entry[2].data);
- fallthrough;
- case 2:
- set_64bit_val(wqe, 32,
- (LS_64(info->entry[1].cmd, I40IW_CQPSQ_UPESD_SDCMD) |
- LS_64(1, I40IW_CQPSQ_UPESD_ENTRY_VALID)));
-
- set_64bit_val(wqe, 40, info->entry[1].data);
- fallthrough;
- case 1:
- set_64bit_val(wqe, 0,
- LS_64(info->entry[0].cmd, I40IW_CQPSQ_UPESD_SDCMD));
-
- set_64bit_val(wqe, 8, info->entry[0].data);
- break;
- default:
- break;
- }
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "UPDATE_PE_SDS WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
- return 0;
-}
-
-/**
- * i40iw_update_pe_sds - cqp wqe for sd
- * @dev: ptr to i40iw_dev struct
- * @info: sd info for sd's
- * @scratch: u64 saved to be used during cqp completion
- */
-static enum i40iw_status_code i40iw_update_pe_sds(struct i40iw_sc_dev *dev,
- struct i40iw_update_sds_info *info,
- u64 scratch)
-{
- struct i40iw_sc_cqp *cqp = dev->cqp;
- enum i40iw_status_code ret_code;
-
- ret_code = cqp_sds_wqe_fill(cqp, info, scratch);
- if (!ret_code)
- i40iw_sc_cqp_post_sq(cqp);
-
- return ret_code;
-}
-
-/**
- * i40iw_update_sds_noccq - update sd before ccq created
- * @dev: sc device struct
- * @info: sd info for sd's
- */
-enum i40iw_status_code i40iw_update_sds_noccq(struct i40iw_sc_dev *dev,
- struct i40iw_update_sds_info *info)
-{
- u32 error, val, tail;
- struct i40iw_sc_cqp *cqp = dev->cqp;
- enum i40iw_status_code ret_code;
-
- ret_code = cqp_sds_wqe_fill(cqp, info, 0);
- if (ret_code)
- return ret_code;
- i40iw_get_cqp_reg_info(cqp, &val, &tail, &error);
- if (error)
- return I40IW_ERR_CQP_COMPL_ERROR;
-
- i40iw_sc_cqp_post_sq(cqp);
- ret_code = i40iw_cqp_poll_registers(cqp, tail, I40IW_DONE_COUNT);
-
- return ret_code;
-}
-
-/**
- * i40iw_sc_suspend_qp - suspend qp for param change
- * @cqp: struct for cqp hw
- * @qp: sc qp struct
- * @scratch: u64 saved to be used during cqp completion
- */
-enum i40iw_status_code i40iw_sc_suspend_qp(struct i40iw_sc_cqp *cqp,
- struct i40iw_sc_qp *qp,
- u64 scratch)
-{
- u64 header;
- u64 *wqe;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- header = LS_64(qp->qp_uk.qp_id, I40IW_CQPSQ_SUSPENDQP_QPID) |
- LS_64(I40IW_CQP_OP_SUSPEND_QP, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "SUSPEND_QP WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_resume_qp - resume qp after suspend
- * @cqp: struct for cqp hw
- * @qp: sc qp struct
- * @scratch: u64 saved to be used during cqp completion
- */
-enum i40iw_status_code i40iw_sc_resume_qp(struct i40iw_sc_cqp *cqp,
- struct i40iw_sc_qp *qp,
- u64 scratch)
-{
- u64 header;
- u64 *wqe;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe,
- 16,
- LS_64(qp->qs_handle, I40IW_CQPSQ_RESUMEQP_QSHANDLE));
-
- header = LS_64(qp->qp_uk.qp_id, I40IW_CQPSQ_RESUMEQP_QPID) |
- LS_64(I40IW_CQP_OP_RESUME_QP, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "RESUME_QP WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-/**
- * i40iw_sc_static_hmc_pages_allocated - cqp wqe to allocate hmc pages
- * @cqp: struct for cqp hw
- * @scratch: u64 saved to be used during cqp completion
- * @hmc_fn_id: hmc function id
- * @post_sq: flag for cqp db to ring
- * @poll_registers: flag to poll register for cqp completion
- */
-enum i40iw_status_code i40iw_sc_static_hmc_pages_allocated(
- struct i40iw_sc_cqp *cqp,
- u64 scratch,
- u8 hmc_fn_id,
- bool post_sq,
- bool poll_registers)
-{
- u64 header;
- u64 *wqe;
- u32 tail, val, error;
- enum i40iw_status_code ret_code = 0;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
- set_64bit_val(wqe,
- 16,
- LS_64(hmc_fn_id, I40IW_SHMC_PAGE_ALLOCATED_HMC_FN_ID));
-
- header = LS_64(I40IW_CQP_OP_SHMC_PAGES_ALLOCATED, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "SHMC_PAGES_ALLOCATED WQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
- i40iw_get_cqp_reg_info(cqp, &val, &tail, &error);
- if (error) {
- ret_code = I40IW_ERR_CQP_COMPL_ERROR;
- return ret_code;
- }
- if (post_sq) {
- i40iw_sc_cqp_post_sq(cqp);
- if (poll_registers)
- /* check for cqp sq tail update */
- ret_code = i40iw_cqp_poll_registers(cqp, tail, 1000);
- else
- ret_code = i40iw_sc_poll_for_cqp_op_done(cqp,
- I40IW_CQP_OP_SHMC_PAGES_ALLOCATED,
- NULL);
- }
-
- return ret_code;
-}
-
-/**
- * i40iw_ring_full - check if cqp ring is full
- * @cqp: struct for cqp hw
- */
-static bool i40iw_ring_full(struct i40iw_sc_cqp *cqp)
-{
- return I40IW_RING_FULL_ERR(cqp->sq_ring);
-}
-
-/**
- * i40iw_est_sd - returns approximate number of SDs for HMC
- * @dev: sc device struct
- * @hmc_info: hmc structure, size and count for HMC objects
- */
-static u64 i40iw_est_sd(struct i40iw_sc_dev *dev, struct i40iw_hmc_info *hmc_info)
-{
- int i;
- u64 size = 0;
- u64 sd;
-
- for (i = I40IW_HMC_IW_QP; i < I40IW_HMC_IW_PBLE; i++)
- size += hmc_info->hmc_obj[i].cnt * hmc_info->hmc_obj[i].size;
-
- if (dev->is_pf)
- size += hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].cnt * hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].size;
-
- if (size & 0x1FFFFF)
- sd = (size >> 21) + 1; /* add 1 for remainder */
- else
- sd = size >> 21;
-
- if (!dev->is_pf) {
- /* 2MB alignment for VF PBLE HMC */
- size = hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].cnt * hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].size;
- if (size & 0x1FFFFF)
- sd += (size >> 21) + 1; /* add 1 for remainder */
- else
- sd += size >> 21;
- }
-
- return sd;
-}
-
-/**
- * i40iw_config_fpm_values - configure HMC objects
- * @dev: sc device struct
- * @qp_count: desired qp count
- */
-enum i40iw_status_code i40iw_config_fpm_values(struct i40iw_sc_dev *dev, u32 qp_count)
-{
- struct i40iw_virt_mem virt_mem;
- u32 i, mem_size;
- u32 qpwantedoriginal, qpwanted, mrwanted, pblewanted;
- u64 sd_needed;
- u32 loop_count = 0;
-
- struct i40iw_hmc_info *hmc_info;
- struct i40iw_hmc_fpm_misc *hmc_fpm_misc;
- enum i40iw_status_code ret_code = 0;
-
- hmc_info = dev->hmc_info;
- hmc_fpm_misc = &dev->hmc_fpm_misc;
-
- ret_code = i40iw_sc_init_iw_hmc(dev, dev->hmc_fn_id);
- if (ret_code) {
- i40iw_debug(dev, I40IW_DEBUG_HMC,
- "i40iw_sc_init_iw_hmc returned error_code = %d\n",
- ret_code);
- return ret_code;
- }
-
- for (i = I40IW_HMC_IW_QP; i < I40IW_HMC_IW_MAX; i++)
- hmc_info->hmc_obj[i].cnt = hmc_info->hmc_obj[i].max_cnt;
- sd_needed = i40iw_est_sd(dev, hmc_info);
- i40iw_debug(dev, I40IW_DEBUG_HMC,
- "%s: FW initial max sd_count[%08lld] first_sd_index[%04d]\n",
- __func__, sd_needed, hmc_info->first_sd_index);
- i40iw_debug(dev, I40IW_DEBUG_HMC,
- "%s: sd count %d where max sd is %d\n",
- __func__, hmc_info->sd_table.sd_cnt,
- hmc_fpm_misc->max_sds);
-
- qpwanted = min(qp_count, hmc_info->hmc_obj[I40IW_HMC_IW_QP].max_cnt);
- qpwantedoriginal = qpwanted;
- mrwanted = hmc_info->hmc_obj[I40IW_HMC_IW_MR].max_cnt;
- pblewanted = hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].max_cnt;
-
- i40iw_debug(dev, I40IW_DEBUG_HMC,
- "req_qp=%d max_sd=%d, max_qp = %d, max_cq=%d, max_mr=%d, max_pble=%d\n",
- qp_count, hmc_fpm_misc->max_sds,
- hmc_info->hmc_obj[I40IW_HMC_IW_QP].max_cnt,
- hmc_info->hmc_obj[I40IW_HMC_IW_CQ].max_cnt,
- hmc_info->hmc_obj[I40IW_HMC_IW_MR].max_cnt,
- hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].max_cnt);
-
- do {
- ++loop_count;
- hmc_info->hmc_obj[I40IW_HMC_IW_QP].cnt = qpwanted;
- hmc_info->hmc_obj[I40IW_HMC_IW_CQ].cnt =
- min(2 * qpwanted, hmc_info->hmc_obj[I40IW_HMC_IW_CQ].cnt);
- hmc_info->hmc_obj[I40IW_HMC_IW_SRQ].cnt = 0x00; /* Reserved */
- hmc_info->hmc_obj[I40IW_HMC_IW_HTE].cnt =
- qpwanted * hmc_fpm_misc->ht_multiplier;
- hmc_info->hmc_obj[I40IW_HMC_IW_ARP].cnt =
- hmc_info->hmc_obj[I40IW_HMC_IW_ARP].max_cnt;
- hmc_info->hmc_obj[I40IW_HMC_IW_APBVT_ENTRY].cnt = 1;
- hmc_info->hmc_obj[I40IW_HMC_IW_MR].cnt = mrwanted;
-
- hmc_info->hmc_obj[I40IW_HMC_IW_XF].cnt =
- roundup_pow_of_two(I40IW_MAX_WQ_ENTRIES * qpwanted);
- hmc_info->hmc_obj[I40IW_HMC_IW_Q1].cnt =
- roundup_pow_of_two(2 * I40IW_MAX_IRD_SIZE * qpwanted);
- hmc_info->hmc_obj[I40IW_HMC_IW_XFFL].cnt =
- hmc_info->hmc_obj[I40IW_HMC_IW_XF].cnt / hmc_fpm_misc->xf_block_size;
- hmc_info->hmc_obj[I40IW_HMC_IW_Q1FL].cnt =
- hmc_info->hmc_obj[I40IW_HMC_IW_Q1].cnt / hmc_fpm_misc->q1_block_size;
- hmc_info->hmc_obj[I40IW_HMC_IW_TIMER].cnt =
- ((qpwanted) / 512 + 1) * hmc_fpm_misc->timer_bucket;
- hmc_info->hmc_obj[I40IW_HMC_IW_FSIMC].cnt = 0x00;
- hmc_info->hmc_obj[I40IW_HMC_IW_FSIAV].cnt = 0x00;
- hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].cnt = pblewanted;
-
- /* How much memory is needed for all the objects. */
- sd_needed = i40iw_est_sd(dev, hmc_info);
- if ((loop_count > 1000) ||
- ((!(loop_count % 10)) &&
- (qpwanted > qpwantedoriginal * 2 / 3))) {
- if (qpwanted > FPM_MULTIPLIER)
- qpwanted = roundup_pow_of_two(qpwanted -
- FPM_MULTIPLIER);
- qpwanted >>= 1;
- }
- if (mrwanted > FPM_MULTIPLIER * 10)
- mrwanted -= FPM_MULTIPLIER * 10;
- if (pblewanted > FPM_MULTIPLIER * 1000)
- pblewanted -= FPM_MULTIPLIER * 1000;
- } while (sd_needed > hmc_fpm_misc->max_sds && loop_count < 2000);
-
- i40iw_debug(dev, I40IW_DEBUG_HMC,
- "loop_cnt=%d, sd_needed=%lld, qpcnt = %d, cqcnt=%d, mrcnt=%d, pblecnt=%d\n",
- loop_count, sd_needed,
- hmc_info->hmc_obj[I40IW_HMC_IW_QP].cnt,
- hmc_info->hmc_obj[I40IW_HMC_IW_CQ].cnt,
- hmc_info->hmc_obj[I40IW_HMC_IW_MR].cnt,
- hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].cnt);
-
- ret_code = i40iw_sc_configure_iw_fpm(dev, dev->hmc_fn_id);
- if (ret_code) {
- i40iw_debug(dev, I40IW_DEBUG_HMC,
- "configure_iw_fpm returned error_code[x%08X]\n",
- i40iw_rd32(dev->hw, dev->is_pf ? I40E_PFPE_CQPERRCODES : I40E_VFPE_CQPERRCODES1));
- return ret_code;
- }
-
- mem_size = sizeof(struct i40iw_hmc_sd_entry) *
- (hmc_info->sd_table.sd_cnt + hmc_info->first_sd_index + 1);
- ret_code = i40iw_allocate_virt_mem(dev->hw, &virt_mem, mem_size);
- if (ret_code) {
- i40iw_debug(dev, I40IW_DEBUG_HMC,
- "%s: failed to allocate memory for sd_entry buffer\n",
- __func__);
- return ret_code;
- }
- hmc_info->sd_table.sd_entry = virt_mem.va;
-
- return ret_code;
-}
-
-/**
- * i40iw_exec_cqp_cmd - execute cqp cmd when wqe are available
- * @dev: rdma device
- * @pcmdinfo: cqp command info
- */
-static enum i40iw_status_code i40iw_exec_cqp_cmd(struct i40iw_sc_dev *dev,
- struct cqp_commands_info *pcmdinfo)
-{
- enum i40iw_status_code status;
- struct i40iw_dma_mem values_mem;
-
- dev->cqp_cmd_stats[pcmdinfo->cqp_cmd]++;
- switch (pcmdinfo->cqp_cmd) {
- case OP_DELETE_LOCAL_MAC_IPADDR_ENTRY:
- status = i40iw_sc_del_local_mac_ipaddr_entry(
- pcmdinfo->in.u.del_local_mac_ipaddr_entry.cqp,
- pcmdinfo->in.u.del_local_mac_ipaddr_entry.scratch,
- pcmdinfo->in.u.del_local_mac_ipaddr_entry.entry_idx,
- pcmdinfo->in.u.del_local_mac_ipaddr_entry.ignore_ref_count,
- pcmdinfo->post_sq);
- break;
- case OP_CEQ_DESTROY:
- status = i40iw_sc_ceq_destroy(pcmdinfo->in.u.ceq_destroy.ceq,
- pcmdinfo->in.u.ceq_destroy.scratch,
- pcmdinfo->post_sq);
- break;
- case OP_AEQ_DESTROY:
- status = i40iw_sc_aeq_destroy(pcmdinfo->in.u.aeq_destroy.aeq,
- pcmdinfo->in.u.aeq_destroy.scratch,
- pcmdinfo->post_sq);
-
- break;
- case OP_DELETE_ARP_CACHE_ENTRY:
- status = i40iw_sc_del_arp_cache_entry(
- pcmdinfo->in.u.del_arp_cache_entry.cqp,
- pcmdinfo->in.u.del_arp_cache_entry.scratch,
- pcmdinfo->in.u.del_arp_cache_entry.arp_index,
- pcmdinfo->post_sq);
- break;
- case OP_MANAGE_APBVT_ENTRY:
- status = i40iw_sc_manage_apbvt_entry(
- pcmdinfo->in.u.manage_apbvt_entry.cqp,
- &pcmdinfo->in.u.manage_apbvt_entry.info,
- pcmdinfo->in.u.manage_apbvt_entry.scratch,
- pcmdinfo->post_sq);
- break;
- case OP_CEQ_CREATE:
- status = i40iw_sc_ceq_create(pcmdinfo->in.u.ceq_create.ceq,
- pcmdinfo->in.u.ceq_create.scratch,
- pcmdinfo->post_sq);
- break;
- case OP_AEQ_CREATE:
- status = i40iw_sc_aeq_create(pcmdinfo->in.u.aeq_create.aeq,
- pcmdinfo->in.u.aeq_create.scratch,
- pcmdinfo->post_sq);
- break;
- case OP_ALLOC_LOCAL_MAC_IPADDR_ENTRY:
- status = i40iw_sc_alloc_local_mac_ipaddr_entry(
- pcmdinfo->in.u.alloc_local_mac_ipaddr_entry.cqp,
- pcmdinfo->in.u.alloc_local_mac_ipaddr_entry.scratch,
- pcmdinfo->post_sq);
- break;
- case OP_ADD_LOCAL_MAC_IPADDR_ENTRY:
- status = i40iw_sc_add_local_mac_ipaddr_entry(
- pcmdinfo->in.u.add_local_mac_ipaddr_entry.cqp,
- &pcmdinfo->in.u.add_local_mac_ipaddr_entry.info,
- pcmdinfo->in.u.add_local_mac_ipaddr_entry.scratch,
- pcmdinfo->post_sq);
- break;
- case OP_MANAGE_QHASH_TABLE_ENTRY:
- status = i40iw_sc_manage_qhash_table_entry(
- pcmdinfo->in.u.manage_qhash_table_entry.cqp,
- &pcmdinfo->in.u.manage_qhash_table_entry.info,
- pcmdinfo->in.u.manage_qhash_table_entry.scratch,
- pcmdinfo->post_sq);
-
- break;
- case OP_QP_MODIFY:
- status = i40iw_sc_qp_modify(
- pcmdinfo->in.u.qp_modify.qp,
- &pcmdinfo->in.u.qp_modify.info,
- pcmdinfo->in.u.qp_modify.scratch,
- pcmdinfo->post_sq);
-
- break;
- case OP_QP_UPLOAD_CONTEXT:
- status = i40iw_sc_qp_upload_context(
- pcmdinfo->in.u.qp_upload_context.dev,
- &pcmdinfo->in.u.qp_upload_context.info,
- pcmdinfo->in.u.qp_upload_context.scratch,
- pcmdinfo->post_sq);
-
- break;
- case OP_CQ_CREATE:
- status = i40iw_sc_cq_create(
- pcmdinfo->in.u.cq_create.cq,
- pcmdinfo->in.u.cq_create.scratch,
- pcmdinfo->in.u.cq_create.check_overflow,
- pcmdinfo->post_sq);
- break;
- case OP_CQ_DESTROY:
- status = i40iw_sc_cq_destroy(
- pcmdinfo->in.u.cq_destroy.cq,
- pcmdinfo->in.u.cq_destroy.scratch,
- pcmdinfo->post_sq);
-
- break;
- case OP_QP_CREATE:
- status = i40iw_sc_qp_create(
- pcmdinfo->in.u.qp_create.qp,
- &pcmdinfo->in.u.qp_create.info,
- pcmdinfo->in.u.qp_create.scratch,
- pcmdinfo->post_sq);
- break;
- case OP_QP_DESTROY:
- status = i40iw_sc_qp_destroy(
- pcmdinfo->in.u.qp_destroy.qp,
- pcmdinfo->in.u.qp_destroy.scratch,
- pcmdinfo->in.u.qp_destroy.remove_hash_idx,
- pcmdinfo->in.u.qp_destroy.
- ignore_mw_bnd,
- pcmdinfo->post_sq);
-
- break;
- case OP_ALLOC_STAG:
- status = i40iw_sc_alloc_stag(
- pcmdinfo->in.u.alloc_stag.dev,
- &pcmdinfo->in.u.alloc_stag.info,
- pcmdinfo->in.u.alloc_stag.scratch,
- pcmdinfo->post_sq);
- break;
- case OP_MR_REG_NON_SHARED:
- status = i40iw_sc_mr_reg_non_shared(
- pcmdinfo->in.u.mr_reg_non_shared.dev,
- &pcmdinfo->in.u.mr_reg_non_shared.info,
- pcmdinfo->in.u.mr_reg_non_shared.scratch,
- pcmdinfo->post_sq);
-
- break;
- case OP_DEALLOC_STAG:
- status = i40iw_sc_dealloc_stag(
- pcmdinfo->in.u.dealloc_stag.dev,
- &pcmdinfo->in.u.dealloc_stag.info,
- pcmdinfo->in.u.dealloc_stag.scratch,
- pcmdinfo->post_sq);
-
- break;
- case OP_MW_ALLOC:
- status = i40iw_sc_mw_alloc(
- pcmdinfo->in.u.mw_alloc.dev,
- pcmdinfo->in.u.mw_alloc.scratch,
- pcmdinfo->in.u.mw_alloc.mw_stag_index,
- pcmdinfo->in.u.mw_alloc.pd_id,
- pcmdinfo->post_sq);
-
- break;
- case OP_QP_FLUSH_WQES:
- status = i40iw_sc_qp_flush_wqes(
- pcmdinfo->in.u.qp_flush_wqes.qp,
- &pcmdinfo->in.u.qp_flush_wqes.info,
- pcmdinfo->in.u.qp_flush_wqes.
- scratch, pcmdinfo->post_sq);
- break;
- case OP_GEN_AE:
- status = i40iw_sc_gen_ae(
- pcmdinfo->in.u.gen_ae.qp,
- &pcmdinfo->in.u.gen_ae.info,
- pcmdinfo->in.u.gen_ae.scratch,
- pcmdinfo->post_sq);
- break;
- case OP_ADD_ARP_CACHE_ENTRY:
- status = i40iw_sc_add_arp_cache_entry(
- pcmdinfo->in.u.add_arp_cache_entry.cqp,
- &pcmdinfo->in.u.add_arp_cache_entry.info,
- pcmdinfo->in.u.add_arp_cache_entry.scratch,
- pcmdinfo->post_sq);
- break;
- case OP_UPDATE_PE_SDS:
- /* case I40IW_CQP_OP_UPDATE_PE_SDS */
- status = i40iw_update_pe_sds(
- pcmdinfo->in.u.update_pe_sds.dev,
- &pcmdinfo->in.u.update_pe_sds.info,
- pcmdinfo->in.u.update_pe_sds.
- scratch);
-
- break;
- case OP_MANAGE_HMC_PM_FUNC_TABLE:
- status = i40iw_sc_manage_hmc_pm_func_table(
- pcmdinfo->in.u.manage_hmc_pm.dev->cqp,
- pcmdinfo->in.u.manage_hmc_pm.scratch,
- (u8)pcmdinfo->in.u.manage_hmc_pm.info.vf_id,
- pcmdinfo->in.u.manage_hmc_pm.info.free_fcn,
- true);
- break;
- case OP_SUSPEND:
- status = i40iw_sc_suspend_qp(
- pcmdinfo->in.u.suspend_resume.cqp,
- pcmdinfo->in.u.suspend_resume.qp,
- pcmdinfo->in.u.suspend_resume.scratch);
- break;
- case OP_RESUME:
- status = i40iw_sc_resume_qp(
- pcmdinfo->in.u.suspend_resume.cqp,
- pcmdinfo->in.u.suspend_resume.qp,
- pcmdinfo->in.u.suspend_resume.scratch);
- break;
- case OP_MANAGE_VF_PBLE_BP:
- status = i40iw_manage_vf_pble_bp(
- pcmdinfo->in.u.manage_vf_pble_bp.cqp,
- &pcmdinfo->in.u.manage_vf_pble_bp.info,
- pcmdinfo->in.u.manage_vf_pble_bp.scratch, true);
- break;
- case OP_QUERY_FPM_VALUES:
- values_mem.pa = pcmdinfo->in.u.query_fpm_values.fpm_values_pa;
- values_mem.va = pcmdinfo->in.u.query_fpm_values.fpm_values_va;
- status = i40iw_sc_query_fpm_values(
- pcmdinfo->in.u.query_fpm_values.cqp,
- pcmdinfo->in.u.query_fpm_values.scratch,
- pcmdinfo->in.u.query_fpm_values.hmc_fn_id,
- &values_mem, true, I40IW_CQP_WAIT_EVENT);
- break;
- case OP_COMMIT_FPM_VALUES:
- values_mem.pa = pcmdinfo->in.u.commit_fpm_values.fpm_values_pa;
- values_mem.va = pcmdinfo->in.u.commit_fpm_values.fpm_values_va;
- status = i40iw_sc_commit_fpm_values(
- pcmdinfo->in.u.commit_fpm_values.cqp,
- pcmdinfo->in.u.commit_fpm_values.scratch,
- pcmdinfo->in.u.commit_fpm_values.hmc_fn_id,
- &values_mem,
- true,
- I40IW_CQP_WAIT_EVENT);
- break;
- case OP_QUERY_RDMA_FEATURES:
- values_mem.pa = pcmdinfo->in.u.query_rdma_features.cap_pa;
- values_mem.va = pcmdinfo->in.u.query_rdma_features.cap_va;
- status = i40iw_sc_query_rdma_features(
- pcmdinfo->in.u.query_rdma_features.cqp, &values_mem,
- pcmdinfo->in.u.query_rdma_features.scratch);
- break;
- default:
- status = I40IW_NOT_SUPPORTED;
- break;
- }
-
- return status;
-}
-
-/**
- * i40iw_process_cqp_cmd - process all cqp commands
- * @dev: sc device struct
- * @pcmdinfo: cqp command info
- */
-enum i40iw_status_code i40iw_process_cqp_cmd(struct i40iw_sc_dev *dev,
- struct cqp_commands_info *pcmdinfo)
-{
- enum i40iw_status_code status = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->cqp_lock, flags);
- if (list_empty(&dev->cqp_cmd_head) && !i40iw_ring_full(dev->cqp))
- status = i40iw_exec_cqp_cmd(dev, pcmdinfo);
- else
- list_add_tail(&pcmdinfo->cqp_cmd_entry, &dev->cqp_cmd_head);
- spin_unlock_irqrestore(&dev->cqp_lock, flags);
- return status;
-}
-
-/**
- * i40iw_process_bh - called from tasklet for cqp list
- * @dev: sc device struct
- */
-enum i40iw_status_code i40iw_process_bh(struct i40iw_sc_dev *dev)
-{
- enum i40iw_status_code status = 0;
- struct cqp_commands_info *pcmdinfo;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->cqp_lock, flags);
- while (!list_empty(&dev->cqp_cmd_head) && !i40iw_ring_full(dev->cqp)) {
- pcmdinfo = (struct cqp_commands_info *)i40iw_remove_head(&dev->cqp_cmd_head);
-
- status = i40iw_exec_cqp_cmd(dev, pcmdinfo);
- if (status)
- break;
- }
- spin_unlock_irqrestore(&dev->cqp_lock, flags);
- return status;
-}
-
-/**
- * i40iw_iwarp_opcode - determine if incoming is rdma layer
- * @info: aeq info for the packet
- * @pkt: packet for error
- */
-static u32 i40iw_iwarp_opcode(struct i40iw_aeqe_info *info, u8 *pkt)
-{
- __be16 *mpa;
- u32 opcode = 0xffffffff;
-
- if (info->q2_data_written) {
- mpa = (__be16 *)pkt;
- opcode = ntohs(mpa[1]) & 0xf;
- }
- return opcode;
-}
-
-/**
- * i40iw_locate_mpa - return pointer to mpa in the pkt
- * @pkt: packet with data
- */
-static u8 *i40iw_locate_mpa(u8 *pkt)
-{
- /* skip over ethernet header */
- pkt += I40IW_MAC_HLEN;
-
- /* Skip over IP and TCP headers */
- pkt += 4 * (pkt[0] & 0x0f);
- pkt += 4 * ((pkt[12] >> 4) & 0x0f);
- return pkt;
-}
-
-/**
- * i40iw_setup_termhdr - termhdr for terminate pkt
- * @qp: sc qp ptr for pkt
- * @hdr: term hdr
- * @opcode: flush opcode for termhdr
- * @layer_etype: error layer + error type
- * @err: error cod ein the header
- */
-static void i40iw_setup_termhdr(struct i40iw_sc_qp *qp,
- struct i40iw_terminate_hdr *hdr,
- enum i40iw_flush_opcode opcode,
- u8 layer_etype,
- u8 err)
-{
- qp->flush_code = opcode;
- hdr->layer_etype = layer_etype;
- hdr->error_code = err;
-}
-
-/**
- * i40iw_bld_terminate_hdr - build terminate message header
- * @qp: qp associated with received terminate AE
- * @info: the struct contiaing AE information
- */
-static int i40iw_bld_terminate_hdr(struct i40iw_sc_qp *qp,
- struct i40iw_aeqe_info *info)
-{
- u8 *pkt = qp->q2_buf + Q2_BAD_FRAME_OFFSET;
- u16 ddp_seg_len;
- int copy_len = 0;
- u8 is_tagged = 0;
- u32 opcode;
- struct i40iw_terminate_hdr *termhdr;
-
- termhdr = (struct i40iw_terminate_hdr *)qp->q2_buf;
- memset(termhdr, 0, Q2_BAD_FRAME_OFFSET);
-
- if (info->q2_data_written) {
- /* Use data from offending packet to fill in ddp & rdma hdrs */
- pkt = i40iw_locate_mpa(pkt);
- ddp_seg_len = ntohs(*(__be16 *)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;
- }
- }
- }
- }
- }
-
- opcode = i40iw_iwarp_opcode(info, pkt);
-
- switch (info->ae_id) {
- case I40IW_AE_AMP_UNALLOCATED_STAG:
- qp->eventtype = TERM_EVENT_QP_ACCESS_ERR;
- if (opcode == I40IW_OP_TYPE_RDMA_WRITE)
- i40iw_setup_termhdr(qp, termhdr, FLUSH_PROT_ERR,
- (LAYER_DDP << 4) | DDP_TAGGED_BUFFER, DDP_TAGGED_INV_STAG);
- else
- i40iw_setup_termhdr(qp, termhdr, FLUSH_REM_ACCESS_ERR,
- (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT, RDMAP_INV_STAG);
- break;
- case I40IW_AE_AMP_BOUNDS_VIOLATION:
- qp->eventtype = TERM_EVENT_QP_ACCESS_ERR;
- if (info->q2_data_written)
- i40iw_setup_termhdr(qp, termhdr, FLUSH_PROT_ERR,
- (LAYER_DDP << 4) | DDP_TAGGED_BUFFER, DDP_TAGGED_BOUNDS);
- else
- i40iw_setup_termhdr(qp, termhdr, FLUSH_REM_ACCESS_ERR,
- (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT, RDMAP_INV_BOUNDS);
- break;
- case I40IW_AE_AMP_BAD_PD:
- switch (opcode) {
- case I40IW_OP_TYPE_RDMA_WRITE:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_PROT_ERR,
- (LAYER_DDP << 4) | DDP_TAGGED_BUFFER, DDP_TAGGED_UNASSOC_STAG);
- break;
- case I40IW_OP_TYPE_SEND_INV:
- case I40IW_OP_TYPE_SEND_SOL_INV:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_REM_ACCESS_ERR,
- (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT, RDMAP_CANT_INV_STAG);
- break;
- default:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_REM_ACCESS_ERR,
- (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT, RDMAP_UNASSOC_STAG);
- }
- break;
- case I40IW_AE_AMP_INVALID_STAG:
- qp->eventtype = TERM_EVENT_QP_ACCESS_ERR;
- i40iw_setup_termhdr(qp, termhdr, FLUSH_REM_ACCESS_ERR,
- (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT, RDMAP_INV_STAG);
- break;
- case I40IW_AE_AMP_BAD_QP:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_LOC_QP_OP_ERR,
- (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER, DDP_UNTAGGED_INV_QN);
- break;
- case I40IW_AE_AMP_BAD_STAG_KEY:
- case I40IW_AE_AMP_BAD_STAG_INDEX:
- qp->eventtype = TERM_EVENT_QP_ACCESS_ERR;
- switch (opcode) {
- case I40IW_OP_TYPE_SEND_INV:
- case I40IW_OP_TYPE_SEND_SOL_INV:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_REM_OP_ERR,
- (LAYER_RDMA << 4) | RDMAP_REMOTE_OP, RDMAP_CANT_INV_STAG);
- break;
- default:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_REM_ACCESS_ERR,
- (LAYER_RDMA << 4) | RDMAP_REMOTE_OP, RDMAP_INV_STAG);
- }
- break;
- case I40IW_AE_AMP_RIGHTS_VIOLATION:
- case I40IW_AE_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS:
- case I40IW_AE_PRIV_OPERATION_DENIED:
- qp->eventtype = TERM_EVENT_QP_ACCESS_ERR;
- i40iw_setup_termhdr(qp, termhdr, FLUSH_REM_ACCESS_ERR,
- (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT, RDMAP_ACCESS);
- break;
- case I40IW_AE_AMP_TO_WRAP:
- qp->eventtype = TERM_EVENT_QP_ACCESS_ERR;
- i40iw_setup_termhdr(qp, termhdr, FLUSH_REM_ACCESS_ERR,
- (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT, RDMAP_TO_WRAP);
- break;
- case I40IW_AE_LLP_RECEIVED_MPA_CRC_ERROR:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_GENERAL_ERR,
- (LAYER_MPA << 4) | DDP_LLP, MPA_CRC);
- break;
- case I40IW_AE_LLP_SEGMENT_TOO_LARGE:
- case I40IW_AE_LLP_SEGMENT_TOO_SMALL:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_LOC_LEN_ERR,
- (LAYER_DDP << 4) | DDP_CATASTROPHIC, DDP_CATASTROPHIC_LOCAL);
- break;
- case I40IW_AE_LCE_QP_CATASTROPHIC:
- case I40IW_AE_DDP_NO_L_BIT:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_FATAL_ERR,
- (LAYER_DDP << 4) | DDP_CATASTROPHIC, DDP_CATASTROPHIC_LOCAL);
- break;
- case I40IW_AE_DDP_INVALID_MSN_GAP_IN_MSN:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_GENERAL_ERR,
- (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER, DDP_UNTAGGED_INV_MSN_RANGE);
- break;
- case I40IW_AE_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER:
- qp->eventtype = TERM_EVENT_QP_ACCESS_ERR;
- i40iw_setup_termhdr(qp, termhdr, FLUSH_LOC_LEN_ERR,
- (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER, DDP_UNTAGGED_INV_TOO_LONG);
- break;
- case I40IW_AE_DDP_UBE_INVALID_DDP_VERSION:
- if (is_tagged)
- i40iw_setup_termhdr(qp, termhdr, FLUSH_GENERAL_ERR,
- (LAYER_DDP << 4) | DDP_TAGGED_BUFFER, DDP_TAGGED_INV_DDP_VER);
- else
- i40iw_setup_termhdr(qp, termhdr, FLUSH_GENERAL_ERR,
- (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER, DDP_UNTAGGED_INV_DDP_VER);
- break;
- case I40IW_AE_DDP_UBE_INVALID_MO:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_GENERAL_ERR,
- (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER, DDP_UNTAGGED_INV_MO);
- break;
- case I40IW_AE_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_REM_OP_ERR,
- (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER, DDP_UNTAGGED_INV_MSN_NO_BUF);
- break;
- case I40IW_AE_DDP_UBE_INVALID_QN:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_GENERAL_ERR,
- (LAYER_DDP << 4) | DDP_UNTAGGED_BUFFER, DDP_UNTAGGED_INV_QN);
- break;
- case I40IW_AE_RDMAP_ROE_INVALID_RDMAP_VERSION:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_GENERAL_ERR,
- (LAYER_RDMA << 4) | RDMAP_REMOTE_OP, RDMAP_INV_RDMAP_VER);
- break;
- case I40IW_AE_RDMAP_ROE_UNEXPECTED_OPCODE:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_LOC_QP_OP_ERR,
- (LAYER_RDMA << 4) | RDMAP_REMOTE_OP, RDMAP_UNEXPECTED_OP);
- break;
- default:
- i40iw_setup_termhdr(qp, termhdr, FLUSH_FATAL_ERR,
- (LAYER_RDMA << 4) | RDMAP_REMOTE_OP, RDMAP_UNSPECIFIED);
- break;
- }
-
- if (copy_len)
- memcpy(termhdr + 1, pkt, copy_len);
-
- return sizeof(struct i40iw_terminate_hdr) + copy_len;
-}
-
-/**
- * i40iw_terminate_send_fin() - Send fin for terminate message
- * @qp: qp associated with received terminate AE
- */
-void i40iw_terminate_send_fin(struct i40iw_sc_qp *qp)
-{
- /* Send the fin only */
- i40iw_term_modify_qp(qp,
- I40IW_QP_STATE_TERMINATE,
- I40IWQP_TERM_SEND_FIN_ONLY,
- 0);
-}
-
-/**
- * i40iw_terminate_connection() - Bad AE and send terminate to remote QP
- * @qp: qp associated with received terminate AE
- * @info: the struct contiaing AE information
- */
-void i40iw_terminate_connection(struct i40iw_sc_qp *qp, struct i40iw_aeqe_info *info)
-{
- u8 termlen = 0;
-
- if (qp->term_flags & I40IW_TERM_SENT)
- return; /* Sanity check */
-
- /* Eventtype can change from bld_terminate_hdr */
- qp->eventtype = TERM_EVENT_QP_FATAL;
- termlen = i40iw_bld_terminate_hdr(qp, info);
- i40iw_terminate_start_timer(qp);
- qp->term_flags |= I40IW_TERM_SENT;
- i40iw_term_modify_qp(qp, I40IW_QP_STATE_TERMINATE,
- I40IWQP_TERM_SEND_TERM_ONLY, termlen);
-}
-
-/**
- * i40iw_terminate_received - handle terminate received AE
- * @qp: qp associated with received terminate AE
- * @info: the struct contiaing AE information
- */
-void i40iw_terminate_received(struct i40iw_sc_qp *qp, struct i40iw_aeqe_info *info)
-{
- u8 *pkt = qp->q2_buf + Q2_BAD_FRAME_OFFSET;
- __be32 *mpa;
- u8 ddp_ctl;
- u8 rdma_ctl;
- u16 aeq_id = 0;
- struct i40iw_terminate_hdr *termhdr;
-
- mpa = (__be32 *)i40iw_locate_mpa(pkt);
- if (info->q2_data_written) {
- /* did not validate the frame - do it now */
- ddp_ctl = (ntohl(mpa[0]) >> 8) & 0xff;
- rdma_ctl = ntohl(mpa[0]) & 0xff;
- if ((ddp_ctl & 0xc0) != 0x40)
- aeq_id = I40IW_AE_LCE_QP_CATASTROPHIC;
- else if ((ddp_ctl & 0x03) != 1)
- aeq_id = I40IW_AE_DDP_UBE_INVALID_DDP_VERSION;
- else if (ntohl(mpa[2]) != 2)
- aeq_id = I40IW_AE_DDP_UBE_INVALID_QN;
- else if (ntohl(mpa[3]) != 1)
- aeq_id = I40IW_AE_DDP_INVALID_MSN_GAP_IN_MSN;
- else if (ntohl(mpa[4]) != 0)
- aeq_id = I40IW_AE_DDP_UBE_INVALID_MO;
- else if ((rdma_ctl & 0xc0) != 0x40)
- aeq_id = I40IW_AE_RDMAP_ROE_INVALID_RDMAP_VERSION;
-
- info->ae_id = aeq_id;
- if (info->ae_id) {
- /* Bad terminate recvd - send back a terminate */
- i40iw_terminate_connection(qp, info);
- return;
- }
- }
-
- qp->term_flags |= I40IW_TERM_RCVD;
- qp->eventtype = TERM_EVENT_QP_FATAL;
- termhdr = (struct i40iw_terminate_hdr *)&mpa[5];
- if (termhdr->layer_etype == RDMAP_REMOTE_PROT ||
- termhdr->layer_etype == RDMAP_REMOTE_OP) {
- i40iw_terminate_done(qp, 0);
- } else {
- i40iw_terminate_start_timer(qp);
- i40iw_terminate_send_fin(qp);
- }
-}
-
-/**
- * i40iw_sc_vsi_init - Initialize virtual device
- * @vsi: pointer to the vsi structure
- * @info: parameters to initialize vsi
- **/
-void i40iw_sc_vsi_init(struct i40iw_sc_vsi *vsi, struct i40iw_vsi_init_info *info)
-{
- int i;
-
- vsi->dev = info->dev;
- vsi->back_vsi = info->back_vsi;
- vsi->mtu = info->params->mtu;
- vsi->exception_lan_queue = info->exception_lan_queue;
- i40iw_fill_qos_list(info->params->qs_handle_list);
-
- for (i = 0; i < I40IW_MAX_USER_PRIORITY; i++) {
- vsi->qos[i].qs_handle = info->params->qs_handle_list[i];
- i40iw_debug(vsi->dev, I40IW_DEBUG_DCB, "qset[%d]: %d\n", i,
- vsi->qos[i].qs_handle);
- spin_lock_init(&vsi->qos[i].lock);
- INIT_LIST_HEAD(&vsi->qos[i].qplist);
- }
-}
-
-/**
- * i40iw_hw_stats_init - Initiliaze HW stats table
- * @stats: pestat struct
- * @fcn_idx: PCI fn id
- * @is_pf: Is it a PF?
- *
- * Populate the HW stats table with register offset addr for each
- * stats. And start the perioidic stats timer.
- */
-void i40iw_hw_stats_init(struct i40iw_vsi_pestat *stats, u8 fcn_idx, bool is_pf)
-{
- u32 stats_reg_offset;
- u32 stats_index;
- struct i40iw_dev_hw_stats_offsets *stats_table =
- &stats->hw_stats_offsets;
- struct i40iw_dev_hw_stats *last_rd_stats = &stats->last_read_hw_stats;
-
- if (is_pf) {
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP4RXDISCARD] =
- I40E_GLPES_PFIP4RXDISCARD(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP4RXTRUNC] =
- I40E_GLPES_PFIP4RXTRUNC(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP4TXNOROUTE] =
- I40E_GLPES_PFIP4TXNOROUTE(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP6RXDISCARD] =
- I40E_GLPES_PFIP6RXDISCARD(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP6RXTRUNC] =
- I40E_GLPES_PFIP6RXTRUNC(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP6TXNOROUTE] =
- I40E_GLPES_PFIP6TXNOROUTE(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_TCPRTXSEG] =
- I40E_GLPES_PFTCPRTXSEG(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_TCPRXOPTERR] =
- I40E_GLPES_PFTCPRXOPTERR(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_TCPRXPROTOERR] =
- I40E_GLPES_PFTCPRXPROTOERR(fcn_idx);
-
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXOCTS] =
- I40E_GLPES_PFIP4RXOCTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXPKTS] =
- I40E_GLPES_PFIP4RXPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXFRAGS] =
- I40E_GLPES_PFIP4RXFRAGSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXMCPKTS] =
- I40E_GLPES_PFIP4RXMCPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXOCTS] =
- I40E_GLPES_PFIP4TXOCTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXPKTS] =
- I40E_GLPES_PFIP4TXPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXFRAGS] =
- I40E_GLPES_PFIP4TXFRAGSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXMCPKTS] =
- I40E_GLPES_PFIP4TXMCPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXOCTS] =
- I40E_GLPES_PFIP6RXOCTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXPKTS] =
- I40E_GLPES_PFIP6RXPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXFRAGS] =
- I40E_GLPES_PFIP6RXFRAGSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXMCPKTS] =
- I40E_GLPES_PFIP6RXMCPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXOCTS] =
- I40E_GLPES_PFIP6TXOCTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXPKTS] =
- I40E_GLPES_PFIP6TXPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXPKTS] =
- I40E_GLPES_PFIP6TXPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXFRAGS] =
- I40E_GLPES_PFIP6TXFRAGSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_TCPRXSEGS] =
- I40E_GLPES_PFTCPRXSEGSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_TCPTXSEG] =
- I40E_GLPES_PFTCPTXSEGLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMARXRDS] =
- I40E_GLPES_PFRDMARXRDSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMARXSNDS] =
- I40E_GLPES_PFRDMARXSNDSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMARXWRS] =
- I40E_GLPES_PFRDMARXWRSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMATXRDS] =
- I40E_GLPES_PFRDMATXRDSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMATXSNDS] =
- I40E_GLPES_PFRDMATXSNDSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMATXWRS] =
- I40E_GLPES_PFRDMATXWRSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMAVBND] =
- I40E_GLPES_PFRDMAVBNDLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMAVINV] =
- I40E_GLPES_PFRDMAVINVLO(fcn_idx);
- } else {
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP4RXDISCARD] =
- I40E_GLPES_VFIP4RXDISCARD(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP4RXTRUNC] =
- I40E_GLPES_VFIP4RXTRUNC(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP4TXNOROUTE] =
- I40E_GLPES_VFIP4TXNOROUTE(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP6RXDISCARD] =
- I40E_GLPES_VFIP6RXDISCARD(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP6RXTRUNC] =
- I40E_GLPES_VFIP6RXTRUNC(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP6TXNOROUTE] =
- I40E_GLPES_VFIP6TXNOROUTE(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_TCPRTXSEG] =
- I40E_GLPES_VFTCPRTXSEG(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_TCPRXOPTERR] =
- I40E_GLPES_VFTCPRXOPTERR(fcn_idx);
- stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_TCPRXPROTOERR] =
- I40E_GLPES_VFTCPRXPROTOERR(fcn_idx);
-
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXOCTS] =
- I40E_GLPES_VFIP4RXOCTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXPKTS] =
- I40E_GLPES_VFIP4RXPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXFRAGS] =
- I40E_GLPES_VFIP4RXFRAGSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXMCPKTS] =
- I40E_GLPES_VFIP4RXMCPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXOCTS] =
- I40E_GLPES_VFIP4TXOCTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXPKTS] =
- I40E_GLPES_VFIP4TXPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXFRAGS] =
- I40E_GLPES_VFIP4TXFRAGSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXMCPKTS] =
- I40E_GLPES_VFIP4TXMCPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXOCTS] =
- I40E_GLPES_VFIP6RXOCTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXPKTS] =
- I40E_GLPES_VFIP6RXPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXFRAGS] =
- I40E_GLPES_VFIP6RXFRAGSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXMCPKTS] =
- I40E_GLPES_VFIP6RXMCPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXOCTS] =
- I40E_GLPES_VFIP6TXOCTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXPKTS] =
- I40E_GLPES_VFIP6TXPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXPKTS] =
- I40E_GLPES_VFIP6TXPKTSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXFRAGS] =
- I40E_GLPES_VFIP6TXFRAGSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_TCPRXSEGS] =
- I40E_GLPES_VFTCPRXSEGSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_TCPTXSEG] =
- I40E_GLPES_VFTCPTXSEGLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMARXRDS] =
- I40E_GLPES_VFRDMARXRDSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMARXSNDS] =
- I40E_GLPES_VFRDMARXSNDSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMARXWRS] =
- I40E_GLPES_VFRDMARXWRSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMATXRDS] =
- I40E_GLPES_VFRDMATXRDSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMATXSNDS] =
- I40E_GLPES_VFRDMATXSNDSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMATXWRS] =
- I40E_GLPES_VFRDMATXWRSLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMAVBND] =
- I40E_GLPES_VFRDMAVBNDLO(fcn_idx);
- stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMAVINV] =
- I40E_GLPES_VFRDMAVINVLO(fcn_idx);
- }
-
- for (stats_index = 0; stats_index < I40IW_HW_STAT_INDEX_MAX_64;
- stats_index++) {
- stats_reg_offset = stats_table->stats_offset_64[stats_index];
- last_rd_stats->stats_value_64[stats_index] =
- readq(stats->hw->hw_addr + stats_reg_offset);
- }
-
- for (stats_index = 0; stats_index < I40IW_HW_STAT_INDEX_MAX_32;
- stats_index++) {
- stats_reg_offset = stats_table->stats_offset_32[stats_index];
- last_rd_stats->stats_value_32[stats_index] =
- i40iw_rd32(stats->hw, stats_reg_offset);
- }
-}
-
-/**
- * i40iw_hw_stats_read_32 - Read 32-bit HW stats counters and accommodates for roll-overs.
- * @stats: pestat struct
- * @index: index in HW stats table which contains offset reg-addr
- * @value: hw stats value
- */
-void i40iw_hw_stats_read_32(struct i40iw_vsi_pestat *stats,
- enum i40iw_hw_stats_index_32b index,
- u64 *value)
-{
- struct i40iw_dev_hw_stats_offsets *stats_table =
- &stats->hw_stats_offsets;
- struct i40iw_dev_hw_stats *last_rd_stats = &stats->last_read_hw_stats;
- struct i40iw_dev_hw_stats *hw_stats = &stats->hw_stats;
- u64 new_stats_value = 0;
- u32 stats_reg_offset = stats_table->stats_offset_32[index];
-
- new_stats_value = i40iw_rd32(stats->hw, stats_reg_offset);
- /*roll-over case */
- if (new_stats_value < last_rd_stats->stats_value_32[index])
- hw_stats->stats_value_32[index] += new_stats_value;
- else
- hw_stats->stats_value_32[index] +=
- new_stats_value - last_rd_stats->stats_value_32[index];
- last_rd_stats->stats_value_32[index] = new_stats_value;
- *value = hw_stats->stats_value_32[index];
-}
-
-/**
- * i40iw_hw_stats_read_64 - Read HW stats counters (greater than 32-bit) and accommodates for roll-overs.
- * @stats: pestat struct
- * @index: index in HW stats table which contains offset reg-addr
- * @value: hw stats value
- */
-void i40iw_hw_stats_read_64(struct i40iw_vsi_pestat *stats,
- enum i40iw_hw_stats_index_64b index,
- u64 *value)
-{
- struct i40iw_dev_hw_stats_offsets *stats_table =
- &stats->hw_stats_offsets;
- struct i40iw_dev_hw_stats *last_rd_stats = &stats->last_read_hw_stats;
- struct i40iw_dev_hw_stats *hw_stats = &stats->hw_stats;
- u64 new_stats_value = 0;
- u32 stats_reg_offset = stats_table->stats_offset_64[index];
-
- new_stats_value = readq(stats->hw->hw_addr + stats_reg_offset);
- /*roll-over case */
- if (new_stats_value < last_rd_stats->stats_value_64[index])
- hw_stats->stats_value_64[index] += new_stats_value;
- else
- hw_stats->stats_value_64[index] +=
- new_stats_value - last_rd_stats->stats_value_64[index];
- last_rd_stats->stats_value_64[index] = new_stats_value;
- *value = hw_stats->stats_value_64[index];
-}
-
-/**
- * i40iw_hw_stats_read_all - read all HW stat counters
- * @stats: pestat struct
- * @stats_values: hw stats structure
- *
- * Read all the HW stat counters and populates hw_stats structure
- * of passed-in vsi's pestat as well as copy created in stat_values.
- */
-void i40iw_hw_stats_read_all(struct i40iw_vsi_pestat *stats,
- struct i40iw_dev_hw_stats *stats_values)
-{
- u32 stats_index;
- unsigned long flags;
-
- spin_lock_irqsave(&stats->lock, flags);
-
- for (stats_index = 0; stats_index < I40IW_HW_STAT_INDEX_MAX_32;
- stats_index++)
- i40iw_hw_stats_read_32(stats, stats_index,
- &stats_values->stats_value_32[stats_index]);
- for (stats_index = 0; stats_index < I40IW_HW_STAT_INDEX_MAX_64;
- stats_index++)
- i40iw_hw_stats_read_64(stats, stats_index,
- &stats_values->stats_value_64[stats_index]);
- spin_unlock_irqrestore(&stats->lock, flags);
-}
-
-/**
- * i40iw_hw_stats_refresh_all - Update all HW stats structs
- * @stats: pestat struct
- *
- * Read all the HW stats counters to refresh values in hw_stats structure
- * of passed-in dev's pestat
- */
-void i40iw_hw_stats_refresh_all(struct i40iw_vsi_pestat *stats)
-{
- u64 stats_value;
- u32 stats_index;
- unsigned long flags;
-
- spin_lock_irqsave(&stats->lock, flags);
-
- for (stats_index = 0; stats_index < I40IW_HW_STAT_INDEX_MAX_32;
- stats_index++)
- i40iw_hw_stats_read_32(stats, stats_index, &stats_value);
- for (stats_index = 0; stats_index < I40IW_HW_STAT_INDEX_MAX_64;
- stats_index++)
- i40iw_hw_stats_read_64(stats, stats_index, &stats_value);
- spin_unlock_irqrestore(&stats->lock, flags);
-}
-
-/**
- * i40iw_get_fcn_id - Return the function id
- * @dev: pointer to the device
- */
-static u8 i40iw_get_fcn_id(struct i40iw_sc_dev *dev)
-{
- u8 fcn_id = I40IW_INVALID_FCN_ID;
- u8 i;
-
- for (i = I40IW_FIRST_NON_PF_STAT; i < I40IW_MAX_STATS_COUNT; i++)
- if (!dev->fcn_id_array[i]) {
- fcn_id = i;
- dev->fcn_id_array[i] = true;
- break;
- }
- return fcn_id;
-}
-
-/**
- * i40iw_vsi_stats_init - Initialize the vsi statistics
- * @vsi: pointer to the vsi structure
- * @info: The info structure used for initialization
- */
-enum i40iw_status_code i40iw_vsi_stats_init(struct i40iw_sc_vsi *vsi, struct i40iw_vsi_stats_info *info)
-{
- u8 fcn_id = info->fcn_id;
-
- if (info->alloc_fcn_id)
- fcn_id = i40iw_get_fcn_id(vsi->dev);
-
- if (fcn_id == I40IW_INVALID_FCN_ID)
- return I40IW_ERR_NOT_READY;
-
- vsi->pestat = info->pestat;
- vsi->pestat->hw = vsi->dev->hw;
- vsi->pestat->vsi = vsi;
-
- if (info->stats_initialize) {
- i40iw_hw_stats_init(vsi->pestat, fcn_id, true);
- spin_lock_init(&vsi->pestat->lock);
- i40iw_hw_stats_start_timer(vsi);
- }
- vsi->stats_fcn_id_alloc = info->alloc_fcn_id;
- vsi->fcn_id = fcn_id;
- return I40IW_SUCCESS;
-}
-
-/**
- * i40iw_vsi_stats_free - Free the vsi stats
- * @vsi: pointer to the vsi structure
- */
-void i40iw_vsi_stats_free(struct i40iw_sc_vsi *vsi)
-{
- u8 fcn_id = vsi->fcn_id;
-
- if (vsi->stats_fcn_id_alloc && fcn_id < I40IW_MAX_STATS_COUNT)
- vsi->dev->fcn_id_array[fcn_id] = false;
- i40iw_hw_stats_stop_timer(vsi);
-}
-
-static const struct i40iw_cqp_ops iw_cqp_ops = {
- .cqp_init = i40iw_sc_cqp_init,
- .cqp_create = i40iw_sc_cqp_create,
- .cqp_post_sq = i40iw_sc_cqp_post_sq,
- .cqp_get_next_send_wqe = i40iw_sc_cqp_get_next_send_wqe,
- .cqp_destroy = i40iw_sc_cqp_destroy,
- .poll_for_cqp_op_done = i40iw_sc_poll_for_cqp_op_done
-};
-
-static const struct i40iw_ccq_ops iw_ccq_ops = {
- .ccq_init = i40iw_sc_ccq_init,
- .ccq_create = i40iw_sc_ccq_create,
- .ccq_destroy = i40iw_sc_ccq_destroy,
- .ccq_create_done = i40iw_sc_ccq_create_done,
- .ccq_get_cqe_info = i40iw_sc_ccq_get_cqe_info,
- .ccq_arm = i40iw_sc_ccq_arm
-};
-
-static const struct i40iw_ceq_ops iw_ceq_ops = {
- .ceq_init = i40iw_sc_ceq_init,
- .ceq_create = i40iw_sc_ceq_create,
- .cceq_create_done = i40iw_sc_cceq_create_done,
- .cceq_destroy_done = i40iw_sc_cceq_destroy_done,
- .cceq_create = i40iw_sc_cceq_create,
- .ceq_destroy = i40iw_sc_ceq_destroy,
- .process_ceq = i40iw_sc_process_ceq
-};
-
-static const struct i40iw_aeq_ops iw_aeq_ops = {
- .aeq_init = i40iw_sc_aeq_init,
- .aeq_create = i40iw_sc_aeq_create,
- .aeq_destroy = i40iw_sc_aeq_destroy,
- .get_next_aeqe = i40iw_sc_get_next_aeqe,
- .repost_aeq_entries = i40iw_sc_repost_aeq_entries,
- .aeq_create_done = i40iw_sc_aeq_create_done,
- .aeq_destroy_done = i40iw_sc_aeq_destroy_done
-};
-
-/* iwarp pd ops */
-static const struct i40iw_pd_ops iw_pd_ops = {
- .pd_init = i40iw_sc_pd_init,
-};
-
-static const struct i40iw_priv_qp_ops iw_priv_qp_ops = {
- .qp_init = i40iw_sc_qp_init,
- .qp_create = i40iw_sc_qp_create,
- .qp_modify = i40iw_sc_qp_modify,
- .qp_destroy = i40iw_sc_qp_destroy,
- .qp_flush_wqes = i40iw_sc_qp_flush_wqes,
- .qp_upload_context = i40iw_sc_qp_upload_context,
- .qp_setctx = i40iw_sc_qp_setctx,
- .qp_send_lsmm = i40iw_sc_send_lsmm,
- .qp_send_lsmm_nostag = i40iw_sc_send_lsmm_nostag,
- .qp_send_rtt = i40iw_sc_send_rtt,
- .qp_post_wqe0 = i40iw_sc_post_wqe0,
- .iw_mr_fast_register = i40iw_sc_mr_fast_register
-};
-
-static const struct i40iw_priv_cq_ops iw_priv_cq_ops = {
- .cq_init = i40iw_sc_cq_init,
- .cq_create = i40iw_sc_cq_create,
- .cq_destroy = i40iw_sc_cq_destroy,
- .cq_modify = i40iw_sc_cq_modify,
-};
-
-static const struct i40iw_mr_ops iw_mr_ops = {
- .alloc_stag = i40iw_sc_alloc_stag,
- .mr_reg_non_shared = i40iw_sc_mr_reg_non_shared,
- .mr_reg_shared = i40iw_sc_mr_reg_shared,
- .dealloc_stag = i40iw_sc_dealloc_stag,
- .query_stag = i40iw_sc_query_stag,
- .mw_alloc = i40iw_sc_mw_alloc
-};
-
-static const struct i40iw_cqp_misc_ops iw_cqp_misc_ops = {
- .manage_hmc_pm_func_table = i40iw_sc_manage_hmc_pm_func_table,
- .set_hmc_resource_profile = i40iw_sc_set_hmc_resource_profile,
- .commit_fpm_values = i40iw_sc_commit_fpm_values,
- .query_fpm_values = i40iw_sc_query_fpm_values,
- .static_hmc_pages_allocated = i40iw_sc_static_hmc_pages_allocated,
- .add_arp_cache_entry = i40iw_sc_add_arp_cache_entry,
- .del_arp_cache_entry = i40iw_sc_del_arp_cache_entry,
- .query_arp_cache_entry = i40iw_sc_query_arp_cache_entry,
- .manage_apbvt_entry = i40iw_sc_manage_apbvt_entry,
- .manage_qhash_table_entry = i40iw_sc_manage_qhash_table_entry,
- .alloc_local_mac_ipaddr_table_entry = i40iw_sc_alloc_local_mac_ipaddr_entry,
- .add_local_mac_ipaddr_entry = i40iw_sc_add_local_mac_ipaddr_entry,
- .del_local_mac_ipaddr_entry = i40iw_sc_del_local_mac_ipaddr_entry,
- .cqp_nop = i40iw_sc_cqp_nop,
- .commit_fpm_values_done = i40iw_sc_commit_fpm_values_done,
- .query_fpm_values_done = i40iw_sc_query_fpm_values_done,
- .manage_hmc_pm_func_table_done = i40iw_sc_manage_hmc_pm_func_table_done,
- .update_suspend_qp = i40iw_sc_suspend_qp,
- .update_resume_qp = i40iw_sc_resume_qp
-};
-
-static const struct i40iw_hmc_ops iw_hmc_ops = {
- .init_iw_hmc = i40iw_sc_init_iw_hmc,
- .parse_fpm_query_buf = i40iw_sc_parse_fpm_query_buf,
- .configure_iw_fpm = i40iw_sc_configure_iw_fpm,
- .parse_fpm_commit_buf = i40iw_sc_parse_fpm_commit_buf,
- .create_hmc_object = i40iw_sc_create_hmc_obj,
- .del_hmc_object = i40iw_sc_del_hmc_obj
-};
-
-/**
- * i40iw_device_init - Initialize IWARP device
- * @dev: IWARP device pointer
- * @info: IWARP init info
- */
-enum i40iw_status_code i40iw_device_init(struct i40iw_sc_dev *dev,
- struct i40iw_device_init_info *info)
-{
- u32 val;
- u32 vchnl_ver = 0;
- u16 hmc_fcn = 0;
- enum i40iw_status_code ret_code = 0;
- u8 db_size;
-
- spin_lock_init(&dev->cqp_lock);
-
- i40iw_device_init_uk(&dev->dev_uk);
-
- dev->debug_mask = info->debug_mask;
-
- dev->hmc_fn_id = info->hmc_fn_id;
- dev->is_pf = info->is_pf;
-
- dev->fpm_query_buf_pa = info->fpm_query_buf_pa;
- dev->fpm_query_buf = info->fpm_query_buf;
-
- dev->fpm_commit_buf_pa = info->fpm_commit_buf_pa;
- dev->fpm_commit_buf = info->fpm_commit_buf;
-
- dev->hw = info->hw;
- dev->hw->hw_addr = info->bar0;
-
- if (dev->is_pf) {
- val = i40iw_rd32(dev->hw, I40E_GLPCI_DREVID);
- dev->hw_rev = (u8)RS_32(val, I40E_GLPCI_DREVID_DEFAULT_REVID);
-
- val = i40iw_rd32(dev->hw, I40E_GLPCI_LBARCTRL);
- db_size = (u8)RS_32(val, I40E_GLPCI_LBARCTRL_PE_DB_SIZE);
- if ((db_size != I40IW_PE_DB_SIZE_4M) &&
- (db_size != I40IW_PE_DB_SIZE_8M)) {
- i40iw_debug(dev, I40IW_DEBUG_DEV,
- "%s: PE doorbell is not enabled in CSR val 0x%x\n",
- __func__, val);
- ret_code = I40IW_ERR_PE_DOORBELL_NOT_ENABLED;
- return ret_code;
- }
- dev->db_addr = dev->hw->hw_addr + I40IW_DB_ADDR_OFFSET;
- dev->vchnl_if.vchnl_recv = i40iw_vchnl_recv_pf;
- } else {
- dev->db_addr = dev->hw->hw_addr + I40IW_VF_DB_ADDR_OFFSET;
- }
-
- dev->cqp_ops = &iw_cqp_ops;
- dev->ccq_ops = &iw_ccq_ops;
- dev->ceq_ops = &iw_ceq_ops;
- dev->aeq_ops = &iw_aeq_ops;
- dev->cqp_misc_ops = &iw_cqp_misc_ops;
- dev->iw_pd_ops = &iw_pd_ops;
- dev->iw_priv_qp_ops = &iw_priv_qp_ops;
- dev->iw_priv_cq_ops = &iw_priv_cq_ops;
- dev->mr_ops = &iw_mr_ops;
- dev->hmc_ops = &iw_hmc_ops;
- dev->vchnl_if.vchnl_send = info->vchnl_send;
- if (dev->vchnl_if.vchnl_send)
- dev->vchnl_up = true;
- else
- dev->vchnl_up = false;
- if (!dev->is_pf) {
- dev->vchnl_if.vchnl_recv = i40iw_vchnl_recv_vf;
- ret_code = i40iw_vchnl_vf_get_ver(dev, &vchnl_ver);
- if (!ret_code) {
- i40iw_debug(dev, I40IW_DEBUG_DEV,
- "%s: Get Channel version rc = 0x%0x, version is %u\n",
- __func__, ret_code, vchnl_ver);
- ret_code = i40iw_vchnl_vf_get_hmc_fcn(dev, &hmc_fcn);
- if (!ret_code) {
- i40iw_debug(dev, I40IW_DEBUG_DEV,
- "%s Get HMC function rc = 0x%0x, hmc fcn is %u\n",
- __func__, ret_code, hmc_fcn);
- dev->hmc_fn_id = (u8)hmc_fcn;
- }
- }
- }
- dev->iw_vf_cqp_ops = &iw_vf_cqp_ops;
-
- return ret_code;
-}
diff --git a/drivers/infiniband/hw/i40iw/i40iw_d.h b/drivers/infiniband/hw/i40iw/i40iw_d.h
deleted file mode 100644
index 86d5a33c57cc..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_d.h
+++ /dev/null
@@ -1,1746 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_D_H
-#define I40IW_D_H
-
-#define I40IW_FIRST_USER_QP_ID 2
-
-#define I40IW_DB_ADDR_OFFSET (4 * 1024 * 1024 - 64 * 1024)
-#define I40IW_VF_DB_ADDR_OFFSET (64 * 1024)
-
-#define I40IW_PE_DB_SIZE_4M 1
-#define I40IW_PE_DB_SIZE_8M 2
-
-#define I40IW_DDP_VER 1
-#define I40IW_RDMAP_VER 1
-
-#define I40IW_RDMA_MODE_RDMAC 0
-#define I40IW_RDMA_MODE_IETF 1
-
-#define I40IW_QP_STATE_INVALID 0
-#define I40IW_QP_STATE_IDLE 1
-#define I40IW_QP_STATE_RTS 2
-#define I40IW_QP_STATE_CLOSING 3
-#define I40IW_QP_STATE_RESERVED 4
-#define I40IW_QP_STATE_TERMINATE 5
-#define I40IW_QP_STATE_ERROR 6
-
-#define I40IW_STAG_STATE_INVALID 0
-#define I40IW_STAG_STATE_VALID 1
-
-#define I40IW_STAG_TYPE_SHARED 0
-#define I40IW_STAG_TYPE_NONSHARED 1
-
-#define I40IW_MAX_USER_PRIORITY 8
-#define I40IW_MAX_STATS_COUNT 16
-#define I40IW_FIRST_NON_PF_STAT 4
-
-
-#define I40IW_MTU_TO_MSS_IPV4 40
-#define I40IW_MTU_TO_MSS_IPV6 60
-#define I40IW_DEFAULT_MTU 1500
-
-#define LS_64_1(val, bits) ((u64)(uintptr_t)val << bits)
-#define RS_64_1(val, bits) ((u64)(uintptr_t)val >> bits)
-#define LS_32_1(val, bits) (u32)(val << bits)
-#define RS_32_1(val, bits) (u32)(val >> bits)
-#define I40E_HI_DWORD(x) ((u32)((((x) >> 16) >> 16) & 0xFFFFFFFF))
-
-#define QS_HANDLE_UNKNOWN 0xffff
-
-#define LS_64(val, field) (((u64)val << field ## _SHIFT) & (field ## _MASK))
-
-#define RS_64(val, field) ((u64)(val & field ## _MASK) >> field ## _SHIFT)
-#define LS_32(val, field) ((val << field ## _SHIFT) & (field ## _MASK))
-#define RS_32(val, field) ((val & field ## _MASK) >> field ## _SHIFT)
-
-#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 Q2_BAD_FRAME_OFFSET 72
-#define Q2_FPSN_OFFSET 64
-#define CQE_MAJOR_DRV 0x8000
-
-#define I40IW_TERM_SENT 0x01
-#define I40IW_TERM_RCVD 0x02
-#define I40IW_TERM_DONE 0x04
-#define I40IW_MAC_HLEN 14
-
-#define I40IW_INVALID_WQE_INDEX 0xffffffff
-
-#define I40IW_CQP_WAIT_POLL_REGS 1
-#define I40IW_CQP_WAIT_POLL_CQ 2
-#define I40IW_CQP_WAIT_EVENT 3
-
-#define I40IW_CQP_INIT_WQE(wqe) memset(wqe, 0, 64)
-
-#define I40IW_GET_CURRENT_CQ_ELEMENT(_cq) \
- ( \
- &((_cq)->cq_base[I40IW_RING_GETCURRENT_HEAD((_cq)->cq_ring)]) \
- )
-#define I40IW_GET_CURRENT_EXTENDED_CQ_ELEMENT(_cq) \
- ( \
- &(((struct i40iw_extended_cqe *) \
- ((_cq)->cq_base))[I40IW_RING_GETCURRENT_HEAD((_cq)->cq_ring)]) \
- )
-
-#define I40IW_GET_CURRENT_AEQ_ELEMENT(_aeq) \
- ( \
- &_aeq->aeqe_base[I40IW_RING_GETCURRENT_TAIL(_aeq->aeq_ring)] \
- )
-
-#define I40IW_GET_CURRENT_CEQ_ELEMENT(_ceq) \
- ( \
- &_ceq->ceqe_base[I40IW_RING_GETCURRENT_TAIL(_ceq->ceq_ring)] \
- )
-
-#define I40IW_AE_SOURCE_RSVD 0x0
-#define I40IW_AE_SOURCE_RQ 0x1
-#define I40IW_AE_SOURCE_RQ_0011 0x3
-
-#define I40IW_AE_SOURCE_CQ 0x2
-#define I40IW_AE_SOURCE_CQ_0110 0x6
-#define I40IW_AE_SOURCE_CQ_1010 0xA
-#define I40IW_AE_SOURCE_CQ_1110 0xE
-
-#define I40IW_AE_SOURCE_SQ 0x5
-#define I40IW_AE_SOURCE_SQ_0111 0x7
-
-#define I40IW_AE_SOURCE_IN_RR_WR 0x9
-#define I40IW_AE_SOURCE_IN_RR_WR_1011 0xB
-#define I40IW_AE_SOURCE_OUT_RR 0xD
-#define I40IW_AE_SOURCE_OUT_RR_1111 0xF
-
-#define I40IW_TCP_STATE_NON_EXISTENT 0
-#define I40IW_TCP_STATE_CLOSED 1
-#define I40IW_TCP_STATE_LISTEN 2
-#define I40IW_STATE_SYN_SEND 3
-#define I40IW_TCP_STATE_SYN_RECEIVED 4
-#define I40IW_TCP_STATE_ESTABLISHED 5
-#define I40IW_TCP_STATE_CLOSE_WAIT 6
-#define I40IW_TCP_STATE_FIN_WAIT_1 7
-#define I40IW_TCP_STATE_CLOSING 8
-#define I40IW_TCP_STATE_LAST_ACK 9
-#define I40IW_TCP_STATE_FIN_WAIT_2 10
-#define I40IW_TCP_STATE_TIME_WAIT 11
-#define I40IW_TCP_STATE_RESERVED_1 12
-#define I40IW_TCP_STATE_RESERVED_2 13
-#define I40IW_TCP_STATE_RESERVED_3 14
-#define I40IW_TCP_STATE_RESERVED_4 15
-
-/* ILQ CQP hash table fields */
-#define I40IW_CQPSQ_QHASH_VLANID_SHIFT 32
-#define I40IW_CQPSQ_QHASH_VLANID_MASK \
- ((u64)0xfff << I40IW_CQPSQ_QHASH_VLANID_SHIFT)
-
-#define I40IW_CQPSQ_QHASH_QPN_SHIFT 32
-#define I40IW_CQPSQ_QHASH_QPN_MASK \
- ((u64)0x3ffff << I40IW_CQPSQ_QHASH_QPN_SHIFT)
-
-#define I40IW_CQPSQ_QHASH_QS_HANDLE_SHIFT 0
-#define I40IW_CQPSQ_QHASH_QS_HANDLE_MASK ((u64)0x3ff << I40IW_CQPSQ_QHASH_QS_HANDLE_SHIFT)
-
-#define I40IW_CQPSQ_QHASH_SRC_PORT_SHIFT 16
-#define I40IW_CQPSQ_QHASH_SRC_PORT_MASK \
- ((u64)0xffff << I40IW_CQPSQ_QHASH_SRC_PORT_SHIFT)
-
-#define I40IW_CQPSQ_QHASH_DEST_PORT_SHIFT 0
-#define I40IW_CQPSQ_QHASH_DEST_PORT_MASK \
- ((u64)0xffff << I40IW_CQPSQ_QHASH_DEST_PORT_SHIFT)
-
-#define I40IW_CQPSQ_QHASH_ADDR0_SHIFT 32
-#define I40IW_CQPSQ_QHASH_ADDR0_MASK \
- ((u64)0xffffffff << I40IW_CQPSQ_QHASH_ADDR0_SHIFT)
-
-#define I40IW_CQPSQ_QHASH_ADDR1_SHIFT 0
-#define I40IW_CQPSQ_QHASH_ADDR1_MASK \
- ((u64)0xffffffff << I40IW_CQPSQ_QHASH_ADDR1_SHIFT)
-
-#define I40IW_CQPSQ_QHASH_ADDR2_SHIFT 32
-#define I40IW_CQPSQ_QHASH_ADDR2_MASK \
- ((u64)0xffffffff << I40IW_CQPSQ_QHASH_ADDR2_SHIFT)
-
-#define I40IW_CQPSQ_QHASH_ADDR3_SHIFT 0
-#define I40IW_CQPSQ_QHASH_ADDR3_MASK \
- ((u64)0xffffffff << I40IW_CQPSQ_QHASH_ADDR3_SHIFT)
-
-#define I40IW_CQPSQ_QHASH_WQEVALID_SHIFT 63
-#define I40IW_CQPSQ_QHASH_WQEVALID_MASK \
- ((u64)0x1 << I40IW_CQPSQ_QHASH_WQEVALID_SHIFT)
-#define I40IW_CQPSQ_QHASH_OPCODE_SHIFT 32
-#define I40IW_CQPSQ_QHASH_OPCODE_MASK \
- ((u64)0x3f << I40IW_CQPSQ_QHASH_OPCODE_SHIFT)
-
-#define I40IW_CQPSQ_QHASH_MANAGE_SHIFT 61
-#define I40IW_CQPSQ_QHASH_MANAGE_MASK \
- ((u64)0x3 << I40IW_CQPSQ_QHASH_MANAGE_SHIFT)
-
-#define I40IW_CQPSQ_QHASH_IPV4VALID_SHIFT 60
-#define I40IW_CQPSQ_QHASH_IPV4VALID_MASK \
- ((u64)0x1 << I40IW_CQPSQ_QHASH_IPV4VALID_SHIFT)
-
-#define I40IW_CQPSQ_QHASH_VLANVALID_SHIFT 59
-#define I40IW_CQPSQ_QHASH_VLANVALID_MASK \
- ((u64)0x1 << I40IW_CQPSQ_QHASH_VLANVALID_SHIFT)
-
-#define I40IW_CQPSQ_QHASH_ENTRYTYPE_SHIFT 42
-#define I40IW_CQPSQ_QHASH_ENTRYTYPE_MASK \
- ((u64)0x7 << I40IW_CQPSQ_QHASH_ENTRYTYPE_SHIFT)
-/* CQP Host Context */
-#define I40IW_CQPHC_EN_DC_TCP_SHIFT 0
-#define I40IW_CQPHC_EN_DC_TCP_MASK (1UL << I40IW_CQPHC_EN_DC_TCP_SHIFT)
-
-#define I40IW_CQPHC_SQSIZE_SHIFT 8
-#define I40IW_CQPHC_SQSIZE_MASK (0xfUL << I40IW_CQPHC_SQSIZE_SHIFT)
-
-#define I40IW_CQPHC_DISABLE_PFPDUS_SHIFT 1
-#define I40IW_CQPHC_DISABLE_PFPDUS_MASK (0x1UL << I40IW_CQPHC_DISABLE_PFPDUS_SHIFT)
-
-#define I40IW_CQPHC_ENABLED_VFS_SHIFT 32
-#define I40IW_CQPHC_ENABLED_VFS_MASK (0x3fULL << I40IW_CQPHC_ENABLED_VFS_SHIFT)
-
-#define I40IW_CQPHC_HMC_PROFILE_SHIFT 0
-#define I40IW_CQPHC_HMC_PROFILE_MASK (0x7ULL << I40IW_CQPHC_HMC_PROFILE_SHIFT)
-
-#define I40IW_CQPHC_SVER_SHIFT 24
-#define I40IW_CQPHC_SVER_MASK (0xffUL << I40IW_CQPHC_SVER_SHIFT)
-
-#define I40IW_CQPHC_SQBASE_SHIFT 9
-#define I40IW_CQPHC_SQBASE_MASK \
- (0xfffffffffffffeULL << I40IW_CQPHC_SQBASE_SHIFT)
-
-#define I40IW_CQPHC_QPCTX_SHIFT 0
-#define I40IW_CQPHC_QPCTX_MASK \
- (0xffffffffffffffffULL << I40IW_CQPHC_QPCTX_SHIFT)
-#define I40IW_CQPHC_SVER 1
-
-#define I40IW_CQP_SW_SQSIZE_4 4
-#define I40IW_CQP_SW_SQSIZE_2048 2048
-
-/* iWARP QP Doorbell shadow area */
-#define I40IW_QP_DBSA_HW_SQ_TAIL_SHIFT 0
-#define I40IW_QP_DBSA_HW_SQ_TAIL_MASK \
- (0x3fffUL << I40IW_QP_DBSA_HW_SQ_TAIL_SHIFT)
-
-/* Completion Queue Doorbell shadow area */
-#define I40IW_CQ_DBSA_CQEIDX_SHIFT 0
-#define I40IW_CQ_DBSA_CQEIDX_MASK (0xfffffUL << I40IW_CQ_DBSA_CQEIDX_SHIFT)
-
-#define I40IW_CQ_DBSA_SW_CQ_SELECT_SHIFT 0
-#define I40IW_CQ_DBSA_SW_CQ_SELECT_MASK \
- (0x3fffUL << I40IW_CQ_DBSA_SW_CQ_SELECT_SHIFT)
-
-#define I40IW_CQ_DBSA_ARM_NEXT_SHIFT 14
-#define I40IW_CQ_DBSA_ARM_NEXT_MASK (1UL << I40IW_CQ_DBSA_ARM_NEXT_SHIFT)
-
-#define I40IW_CQ_DBSA_ARM_NEXT_SE_SHIFT 15
-#define I40IW_CQ_DBSA_ARM_NEXT_SE_MASK (1UL << I40IW_CQ_DBSA_ARM_NEXT_SE_SHIFT)
-
-#define I40IW_CQ_DBSA_ARM_SEQ_NUM_SHIFT 16
-#define I40IW_CQ_DBSA_ARM_SEQ_NUM_MASK \
- (0x3UL << I40IW_CQ_DBSA_ARM_SEQ_NUM_SHIFT)
-
-/* CQP and iWARP Completion Queue */
-#define I40IW_CQ_QPCTX_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IW_CQ_QPCTX_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IW_CCQ_OPRETVAL_SHIFT 0
-#define I40IW_CCQ_OPRETVAL_MASK (0xffffffffUL << I40IW_CCQ_OPRETVAL_SHIFT)
-
-#define I40IW_CQ_MINERR_SHIFT 0
-#define I40IW_CQ_MINERR_MASK (0xffffUL << I40IW_CQ_MINERR_SHIFT)
-
-#define I40IW_CQ_MAJERR_SHIFT 16
-#define I40IW_CQ_MAJERR_MASK (0xffffUL << I40IW_CQ_MAJERR_SHIFT)
-
-#define I40IW_CQ_WQEIDX_SHIFT 32
-#define I40IW_CQ_WQEIDX_MASK (0x3fffULL << I40IW_CQ_WQEIDX_SHIFT)
-
-#define I40IW_CQ_ERROR_SHIFT 55
-#define I40IW_CQ_ERROR_MASK (1ULL << I40IW_CQ_ERROR_SHIFT)
-
-#define I40IW_CQ_SQ_SHIFT 62
-#define I40IW_CQ_SQ_MASK (1ULL << I40IW_CQ_SQ_SHIFT)
-
-#define I40IW_CQ_VALID_SHIFT 63
-#define I40IW_CQ_VALID_MASK (1ULL << I40IW_CQ_VALID_SHIFT)
-
-#define I40IWCQ_PAYLDLEN_SHIFT 0
-#define I40IWCQ_PAYLDLEN_MASK (0xffffffffUL << I40IWCQ_PAYLDLEN_SHIFT)
-
-#define I40IWCQ_TCPSEQNUM_SHIFT 32
-#define I40IWCQ_TCPSEQNUM_MASK (0xffffffffULL << I40IWCQ_TCPSEQNUM_SHIFT)
-
-#define I40IWCQ_INVSTAG_SHIFT 0
-#define I40IWCQ_INVSTAG_MASK (0xffffffffUL << I40IWCQ_INVSTAG_SHIFT)
-
-#define I40IWCQ_QPID_SHIFT 32
-#define I40IWCQ_QPID_MASK (0x3ffffULL << I40IWCQ_QPID_SHIFT)
-
-#define I40IWCQ_PSHDROP_SHIFT 51
-#define I40IWCQ_PSHDROP_MASK (1ULL << I40IWCQ_PSHDROP_SHIFT)
-
-#define I40IWCQ_SRQ_SHIFT 52
-#define I40IWCQ_SRQ_MASK (1ULL << I40IWCQ_SRQ_SHIFT)
-
-#define I40IWCQ_STAG_SHIFT 53
-#define I40IWCQ_STAG_MASK (1ULL << I40IWCQ_STAG_SHIFT)
-
-#define I40IWCQ_SOEVENT_SHIFT 54
-#define I40IWCQ_SOEVENT_MASK (1ULL << I40IWCQ_SOEVENT_SHIFT)
-
-#define I40IWCQ_OP_SHIFT 56
-#define I40IWCQ_OP_MASK (0x3fULL << I40IWCQ_OP_SHIFT)
-
-/* CEQE format */
-#define I40IW_CEQE_CQCTX_SHIFT 0
-#define I40IW_CEQE_CQCTX_MASK \
- (0x7fffffffffffffffULL << I40IW_CEQE_CQCTX_SHIFT)
-
-#define I40IW_CEQE_VALID_SHIFT 63
-#define I40IW_CEQE_VALID_MASK (1ULL << I40IW_CEQE_VALID_SHIFT)
-
-/* AEQE format */
-#define I40IW_AEQE_COMPCTX_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IW_AEQE_COMPCTX_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IW_AEQE_QPCQID_SHIFT 0
-#define I40IW_AEQE_QPCQID_MASK (0x3ffffUL << I40IW_AEQE_QPCQID_SHIFT)
-
-#define I40IW_AEQE_WQDESCIDX_SHIFT 18
-#define I40IW_AEQE_WQDESCIDX_MASK (0x3fffULL << I40IW_AEQE_WQDESCIDX_SHIFT)
-
-#define I40IW_AEQE_OVERFLOW_SHIFT 33
-#define I40IW_AEQE_OVERFLOW_MASK (1ULL << I40IW_AEQE_OVERFLOW_SHIFT)
-
-#define I40IW_AEQE_AECODE_SHIFT 34
-#define I40IW_AEQE_AECODE_MASK (0xffffULL << I40IW_AEQE_AECODE_SHIFT)
-
-#define I40IW_AEQE_AESRC_SHIFT 50
-#define I40IW_AEQE_AESRC_MASK (0xfULL << I40IW_AEQE_AESRC_SHIFT)
-
-#define I40IW_AEQE_IWSTATE_SHIFT 54
-#define I40IW_AEQE_IWSTATE_MASK (0x7ULL << I40IW_AEQE_IWSTATE_SHIFT)
-
-#define I40IW_AEQE_TCPSTATE_SHIFT 57
-#define I40IW_AEQE_TCPSTATE_MASK (0xfULL << I40IW_AEQE_TCPSTATE_SHIFT)
-
-#define I40IW_AEQE_Q2DATA_SHIFT 61
-#define I40IW_AEQE_Q2DATA_MASK (0x3ULL << I40IW_AEQE_Q2DATA_SHIFT)
-
-#define I40IW_AEQE_VALID_SHIFT 63
-#define I40IW_AEQE_VALID_MASK (1ULL << I40IW_AEQE_VALID_SHIFT)
-
-/* CQP SQ WQES */
-#define I40IW_QP_TYPE_IWARP 1
-#define I40IW_QP_TYPE_UDA 2
-#define I40IW_QP_TYPE_CQP 4
-
-#define I40IW_CQ_TYPE_IWARP 1
-#define I40IW_CQ_TYPE_ILQ 2
-#define I40IW_CQ_TYPE_IEQ 3
-#define I40IW_CQ_TYPE_CQP 4
-
-#define I40IWQP_TERM_SEND_TERM_AND_FIN 0
-#define I40IWQP_TERM_SEND_TERM_ONLY 1
-#define I40IWQP_TERM_SEND_FIN_ONLY 2
-#define I40IWQP_TERM_DONOT_SEND_TERM_OR_FIN 3
-
-#define I40IW_CQP_OP_CREATE_QP 0
-#define I40IW_CQP_OP_MODIFY_QP 0x1
-#define I40IW_CQP_OP_DESTROY_QP 0x02
-#define I40IW_CQP_OP_CREATE_CQ 0x03
-#define I40IW_CQP_OP_MODIFY_CQ 0x04
-#define I40IW_CQP_OP_DESTROY_CQ 0x05
-#define I40IW_CQP_OP_CREATE_SRQ 0x06
-#define I40IW_CQP_OP_MODIFY_SRQ 0x07
-#define I40IW_CQP_OP_DESTROY_SRQ 0x08
-#define I40IW_CQP_OP_ALLOC_STAG 0x09
-#define I40IW_CQP_OP_REG_MR 0x0a
-#define I40IW_CQP_OP_QUERY_STAG 0x0b
-#define I40IW_CQP_OP_REG_SMR 0x0c
-#define I40IW_CQP_OP_DEALLOC_STAG 0x0d
-#define I40IW_CQP_OP_MANAGE_LOC_MAC_IP_TABLE 0x0e
-#define I40IW_CQP_OP_MANAGE_ARP 0x0f
-#define I40IW_CQP_OP_MANAGE_VF_PBLE_BP 0x10
-#define I40IW_CQP_OP_QUERY_RDMA_FEATURES 0x12
-#define I40IW_CQP_OP_UPLOAD_CONTEXT 0x13
-#define I40IW_CQP_OP_ALLOCATE_LOC_MAC_IP_TABLE_ENTRY 0x14
-#define I40IW_CQP_OP_MANAGE_HMC_PM_FUNC_TABLE 0x15
-#define I40IW_CQP_OP_CREATE_CEQ 0x16
-#define I40IW_CQP_OP_DESTROY_CEQ 0x18
-#define I40IW_CQP_OP_CREATE_AEQ 0x19
-#define I40IW_CQP_OP_DESTROY_AEQ 0x1b
-#define I40IW_CQP_OP_CREATE_ADDR_VECT 0x1c
-#define I40IW_CQP_OP_MODIFY_ADDR_VECT 0x1d
-#define I40IW_CQP_OP_DESTROY_ADDR_VECT 0x1e
-#define I40IW_CQP_OP_UPDATE_PE_SDS 0x1f
-#define I40IW_CQP_OP_QUERY_FPM_VALUES 0x20
-#define I40IW_CQP_OP_COMMIT_FPM_VALUES 0x21
-#define I40IW_CQP_OP_FLUSH_WQES 0x22
-/* I40IW_CQP_OP_GEN_AE is the same value as I40IW_CQP_OP_FLUSH_WQES */
-#define I40IW_CQP_OP_GEN_AE 0x22
-#define I40IW_CQP_OP_MANAGE_APBVT 0x23
-#define I40IW_CQP_OP_NOP 0x24
-#define I40IW_CQP_OP_MANAGE_QUAD_HASH_TABLE_ENTRY 0x25
-#define I40IW_CQP_OP_CREATE_UDA_MCAST_GROUP 0x26
-#define I40IW_CQP_OP_MODIFY_UDA_MCAST_GROUP 0x27
-#define I40IW_CQP_OP_DESTROY_UDA_MCAST_GROUP 0x28
-#define I40IW_CQP_OP_SUSPEND_QP 0x29
-#define I40IW_CQP_OP_RESUME_QP 0x2a
-#define I40IW_CQP_OP_SHMC_PAGES_ALLOCATED 0x2b
-#define I40IW_CQP_OP_SET_HMC_RESOURCE_PROFILE 0x2d
-
-#define I40IW_FEATURE_BUF_SIZE (8 * I40IW_MAX_FEATURES)
-
-#define I40IW_FW_VER_MINOR_SHIFT 0
-#define I40IW_FW_VER_MINOR_MASK \
- (0xffffULL << I40IW_FW_VER_MINOR_SHIFT)
-
-#define I40IW_FW_VER_MAJOR_SHIFT 16
-#define I40IW_FW_VER_MAJOR_MASK \
- (0xffffULL << I40IW_FW_VER_MAJOR_SHIFT)
-
-#define I40IW_FEATURE_INFO_SHIFT 0
-#define I40IW_FEATURE_INFO_MASK \
- (0xffffULL << I40IW_FEATURE_INFO_SHIFT)
-
-#define I40IW_FEATURE_CNT_SHIFT 32
-#define I40IW_FEATURE_CNT_MASK \
- (0xffffULL << I40IW_FEATURE_CNT_SHIFT)
-
-#define I40IW_UDA_QPSQ_NEXT_HEADER_SHIFT 16
-#define I40IW_UDA_QPSQ_NEXT_HEADER_MASK ((u64)0xff << I40IW_UDA_QPSQ_NEXT_HEADER_SHIFT)
-
-#define I40IW_UDA_QPSQ_OPCODE_SHIFT 32
-#define I40IW_UDA_QPSQ_OPCODE_MASK ((u64)0x3f << I40IW_UDA_QPSQ_OPCODE_SHIFT)
-
-#define I40IW_UDA_QPSQ_MACLEN_SHIFT 56
-#define I40IW_UDA_QPSQ_MACLEN_MASK \
- ((u64)0x7f << I40IW_UDA_QPSQ_MACLEN_SHIFT)
-
-#define I40IW_UDA_QPSQ_IPLEN_SHIFT 48
-#define I40IW_UDA_QPSQ_IPLEN_MASK \
- ((u64)0x7f << I40IW_UDA_QPSQ_IPLEN_SHIFT)
-
-#define I40IW_UDA_QPSQ_L4T_SHIFT 30
-#define I40IW_UDA_QPSQ_L4T_MASK \
- ((u64)0x3 << I40IW_UDA_QPSQ_L4T_SHIFT)
-
-#define I40IW_UDA_QPSQ_IIPT_SHIFT 28
-#define I40IW_UDA_QPSQ_IIPT_MASK \
- ((u64)0x3 << I40IW_UDA_QPSQ_IIPT_SHIFT)
-
-#define I40IW_UDA_QPSQ_L4LEN_SHIFT 24
-#define I40IW_UDA_QPSQ_L4LEN_MASK ((u64)0xf << I40IW_UDA_QPSQ_L4LEN_SHIFT)
-
-#define I40IW_UDA_QPSQ_AVIDX_SHIFT 0
-#define I40IW_UDA_QPSQ_AVIDX_MASK ((u64)0xffff << I40IW_UDA_QPSQ_AVIDX_SHIFT)
-
-#define I40IW_UDA_QPSQ_VALID_SHIFT 63
-#define I40IW_UDA_QPSQ_VALID_MASK \
- ((u64)0x1 << I40IW_UDA_QPSQ_VALID_SHIFT)
-
-#define I40IW_UDA_QPSQ_SIGCOMPL_SHIFT 62
-#define I40IW_UDA_QPSQ_SIGCOMPL_MASK ((u64)0x1 << I40IW_UDA_QPSQ_SIGCOMPL_SHIFT)
-
-#define I40IW_UDA_PAYLOADLEN_SHIFT 0
-#define I40IW_UDA_PAYLOADLEN_MASK ((u64)0x3fff << I40IW_UDA_PAYLOADLEN_SHIFT)
-
-#define I40IW_UDA_HDRLEN_SHIFT 16
-#define I40IW_UDA_HDRLEN_MASK ((u64)0x1ff << I40IW_UDA_HDRLEN_SHIFT)
-
-#define I40IW_VLAN_TAG_VALID_SHIFT 50
-#define I40IW_VLAN_TAG_VALID_MASK ((u64)0x1 << I40IW_VLAN_TAG_VALID_SHIFT)
-
-#define I40IW_UDA_L3PROTO_SHIFT 0
-#define I40IW_UDA_L3PROTO_MASK ((u64)0x3 << I40IW_UDA_L3PROTO_SHIFT)
-
-#define I40IW_UDA_L4PROTO_SHIFT 16
-#define I40IW_UDA_L4PROTO_MASK ((u64)0x3 << I40IW_UDA_L4PROTO_SHIFT)
-
-#define I40IW_UDA_QPSQ_DOLOOPBACK_SHIFT 44
-#define I40IW_UDA_QPSQ_DOLOOPBACK_MASK \
- ((u64)0x1 << I40IW_UDA_QPSQ_DOLOOPBACK_SHIFT)
-
-/* CQP SQ WQE common fields */
-#define I40IW_CQPSQ_OPCODE_SHIFT 32
-#define I40IW_CQPSQ_OPCODE_MASK (0x3fULL << I40IW_CQPSQ_OPCODE_SHIFT)
-
-#define I40IW_CQPSQ_WQEVALID_SHIFT 63
-#define I40IW_CQPSQ_WQEVALID_MASK (1ULL << I40IW_CQPSQ_WQEVALID_SHIFT)
-
-#define I40IW_CQPSQ_TPHVAL_SHIFT 0
-#define I40IW_CQPSQ_TPHVAL_MASK (0xffUL << I40IW_CQPSQ_TPHVAL_SHIFT)
-
-#define I40IW_CQPSQ_TPHEN_SHIFT 60
-#define I40IW_CQPSQ_TPHEN_MASK (1ULL << I40IW_CQPSQ_TPHEN_SHIFT)
-
-#define I40IW_CQPSQ_PBUFADDR_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IW_CQPSQ_PBUFADDR_MASK I40IW_CQPHC_QPCTX_MASK
-
-/* Create/Modify/Destroy QP */
-
-#define I40IW_CQPSQ_QP_NEWMSS_SHIFT 32
-#define I40IW_CQPSQ_QP_NEWMSS_MASK (0x3fffULL << I40IW_CQPSQ_QP_NEWMSS_SHIFT)
-
-#define I40IW_CQPSQ_QP_TERMLEN_SHIFT 48
-#define I40IW_CQPSQ_QP_TERMLEN_MASK (0xfULL << I40IW_CQPSQ_QP_TERMLEN_SHIFT)
-
-#define I40IW_CQPSQ_QP_QPCTX_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IW_CQPSQ_QP_QPCTX_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IW_CQPSQ_QP_QPID_SHIFT 0
-#define I40IW_CQPSQ_QP_QPID_MASK (0x3FFFFUL)
-/* I40IWCQ_QPID_MASK */
-
-#define I40IW_CQPSQ_QP_OP_SHIFT 32
-#define I40IW_CQPSQ_QP_OP_MASK I40IWCQ_OP_MASK
-
-#define I40IW_CQPSQ_QP_ORDVALID_SHIFT 42
-#define I40IW_CQPSQ_QP_ORDVALID_MASK (1ULL << I40IW_CQPSQ_QP_ORDVALID_SHIFT)
-
-#define I40IW_CQPSQ_QP_TOECTXVALID_SHIFT 43
-#define I40IW_CQPSQ_QP_TOECTXVALID_MASK \
- (1ULL << I40IW_CQPSQ_QP_TOECTXVALID_SHIFT)
-
-#define I40IW_CQPSQ_QP_CACHEDVARVALID_SHIFT 44
-#define I40IW_CQPSQ_QP_CACHEDVARVALID_MASK \
- (1ULL << I40IW_CQPSQ_QP_CACHEDVARVALID_SHIFT)
-
-#define I40IW_CQPSQ_QP_VQ_SHIFT 45
-#define I40IW_CQPSQ_QP_VQ_MASK (1ULL << I40IW_CQPSQ_QP_VQ_SHIFT)
-
-#define I40IW_CQPSQ_QP_FORCELOOPBACK_SHIFT 46
-#define I40IW_CQPSQ_QP_FORCELOOPBACK_MASK \
- (1ULL << I40IW_CQPSQ_QP_FORCELOOPBACK_SHIFT)
-
-#define I40IW_CQPSQ_QP_CQNUMVALID_SHIFT 47
-#define I40IW_CQPSQ_QP_CQNUMVALID_MASK \
- (1ULL << I40IW_CQPSQ_QP_CQNUMVALID_SHIFT)
-
-#define I40IW_CQPSQ_QP_QPTYPE_SHIFT 48
-#define I40IW_CQPSQ_QP_QPTYPE_MASK (0x3ULL << I40IW_CQPSQ_QP_QPTYPE_SHIFT)
-
-#define I40IW_CQPSQ_QP_MSSCHANGE_SHIFT 52
-#define I40IW_CQPSQ_QP_MSSCHANGE_MASK (1ULL << I40IW_CQPSQ_QP_MSSCHANGE_SHIFT)
-
-#define I40IW_CQPSQ_QP_IGNOREMWBOUND_SHIFT 54
-#define I40IW_CQPSQ_QP_IGNOREMWBOUND_MASK \
- (1ULL << I40IW_CQPSQ_QP_IGNOREMWBOUND_SHIFT)
-
-#define I40IW_CQPSQ_QP_REMOVEHASHENTRY_SHIFT 55
-#define I40IW_CQPSQ_QP_REMOVEHASHENTRY_MASK \
- (1ULL << I40IW_CQPSQ_QP_REMOVEHASHENTRY_SHIFT)
-
-#define I40IW_CQPSQ_QP_TERMACT_SHIFT 56
-#define I40IW_CQPSQ_QP_TERMACT_MASK (0x3ULL << I40IW_CQPSQ_QP_TERMACT_SHIFT)
-
-#define I40IW_CQPSQ_QP_RESETCON_SHIFT 58
-#define I40IW_CQPSQ_QP_RESETCON_MASK (1ULL << I40IW_CQPSQ_QP_RESETCON_SHIFT)
-
-#define I40IW_CQPSQ_QP_ARPTABIDXVALID_SHIFT 59
-#define I40IW_CQPSQ_QP_ARPTABIDXVALID_MASK \
- (1ULL << I40IW_CQPSQ_QP_ARPTABIDXVALID_SHIFT)
-
-#define I40IW_CQPSQ_QP_NEXTIWSTATE_SHIFT 60
-#define I40IW_CQPSQ_QP_NEXTIWSTATE_MASK \
- (0x7ULL << I40IW_CQPSQ_QP_NEXTIWSTATE_SHIFT)
-
-#define I40IW_CQPSQ_QP_DBSHADOWADDR_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IW_CQPSQ_QP_DBSHADOWADDR_MASK I40IW_CQPHC_QPCTX_MASK
-
-/* Create/Modify/Destroy CQ */
-#define I40IW_CQPSQ_CQ_CQSIZE_SHIFT 0
-#define I40IW_CQPSQ_CQ_CQSIZE_MASK (0x3ffffUL << I40IW_CQPSQ_CQ_CQSIZE_SHIFT)
-
-#define I40IW_CQPSQ_CQ_CQCTX_SHIFT 0
-#define I40IW_CQPSQ_CQ_CQCTX_MASK \
- (0x7fffffffffffffffULL << I40IW_CQPSQ_CQ_CQCTX_SHIFT)
-
-#define I40IW_CQPSQ_CQ_CQCTX_SHIFT 0
-#define I40IW_CQPSQ_CQ_CQCTX_MASK \
- (0x7fffffffffffffffULL << I40IW_CQPSQ_CQ_CQCTX_SHIFT)
-
-#define I40IW_CQPSQ_CQ_SHADOW_READ_THRESHOLD_SHIFT 0
-#define I40IW_CQPSQ_CQ_SHADOW_READ_THRESHOLD_MASK \
- (0x3ffff << I40IW_CQPSQ_CQ_SHADOW_READ_THRESHOLD_SHIFT)
-
-#define I40IW_CQPSQ_CQ_CEQID_SHIFT 24
-#define I40IW_CQPSQ_CQ_CEQID_MASK (0x7fUL << I40IW_CQPSQ_CQ_CEQID_SHIFT)
-
-#define I40IW_CQPSQ_CQ_OP_SHIFT 32
-#define I40IW_CQPSQ_CQ_OP_MASK (0x3fULL << I40IW_CQPSQ_CQ_OP_SHIFT)
-
-#define I40IW_CQPSQ_CQ_CQRESIZE_SHIFT 43
-#define I40IW_CQPSQ_CQ_CQRESIZE_MASK (1ULL << I40IW_CQPSQ_CQ_CQRESIZE_SHIFT)
-
-#define I40IW_CQPSQ_CQ_LPBLSIZE_SHIFT 44
-#define I40IW_CQPSQ_CQ_LPBLSIZE_MASK (3ULL << I40IW_CQPSQ_CQ_LPBLSIZE_SHIFT)
-
-#define I40IW_CQPSQ_CQ_CHKOVERFLOW_SHIFT 46
-#define I40IW_CQPSQ_CQ_CHKOVERFLOW_MASK \
- (1ULL << I40IW_CQPSQ_CQ_CHKOVERFLOW_SHIFT)
-
-#define I40IW_CQPSQ_CQ_VIRTMAP_SHIFT 47
-#define I40IW_CQPSQ_CQ_VIRTMAP_MASK (1ULL << I40IW_CQPSQ_CQ_VIRTMAP_SHIFT)
-
-#define I40IW_CQPSQ_CQ_ENCEQEMASK_SHIFT 48
-#define I40IW_CQPSQ_CQ_ENCEQEMASK_MASK \
- (1ULL << I40IW_CQPSQ_CQ_ENCEQEMASK_SHIFT)
-
-#define I40IW_CQPSQ_CQ_CEQIDVALID_SHIFT 49
-#define I40IW_CQPSQ_CQ_CEQIDVALID_MASK \
- (1ULL << I40IW_CQPSQ_CQ_CEQIDVALID_SHIFT)
-
-#define I40IW_CQPSQ_CQ_AVOIDMEMCNFLCT_SHIFT 61
-#define I40IW_CQPSQ_CQ_AVOIDMEMCNFLCT_MASK \
- (1ULL << I40IW_CQPSQ_CQ_AVOIDMEMCNFLCT_SHIFT)
-
-/* Create/Modify/Destroy Shared Receive Queue */
-
-#define I40IW_CQPSQ_SRQ_RQSIZE_SHIFT 0
-#define I40IW_CQPSQ_SRQ_RQSIZE_MASK (0xfUL << I40IW_CQPSQ_SRQ_RQSIZE_SHIFT)
-
-#define I40IW_CQPSQ_SRQ_RQWQESIZE_SHIFT 4
-#define I40IW_CQPSQ_SRQ_RQWQESIZE_MASK \
- (0x7UL << I40IW_CQPSQ_SRQ_RQWQESIZE_SHIFT)
-
-#define I40IW_CQPSQ_SRQ_SRQLIMIT_SHIFT 32
-#define I40IW_CQPSQ_SRQ_SRQLIMIT_MASK \
- (0xfffULL << I40IW_CQPSQ_SRQ_SRQLIMIT_SHIFT)
-
-#define I40IW_CQPSQ_SRQ_SRQCTX_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IW_CQPSQ_SRQ_SRQCTX_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IW_CQPSQ_SRQ_PDID_SHIFT 16
-#define I40IW_CQPSQ_SRQ_PDID_MASK \
- (0x7fffULL << I40IW_CQPSQ_SRQ_PDID_SHIFT)
-
-#define I40IW_CQPSQ_SRQ_SRQID_SHIFT 0
-#define I40IW_CQPSQ_SRQ_SRQID_MASK (0x7fffUL << I40IW_CQPSQ_SRQ_SRQID_SHIFT)
-
-#define I40IW_CQPSQ_SRQ_LPBLSIZE_SHIFT I40IW_CQPSQ_CQ_LPBLSIZE_SHIFT
-#define I40IW_CQPSQ_SRQ_LPBLSIZE_MASK I40IW_CQPSQ_CQ_LPBLSIZE_MASK
-
-#define I40IW_CQPSQ_SRQ_VIRTMAP_SHIFT I40IW_CQPSQ_CQ_VIRTMAP_SHIFT
-#define I40IW_CQPSQ_SRQ_VIRTMAP_MASK I40IW_CQPSQ_CQ_VIRTMAP_MASK
-
-#define I40IW_CQPSQ_SRQ_TPHEN_SHIFT I40IW_CQPSQ_TPHEN_SHIFT
-#define I40IW_CQPSQ_SRQ_TPHEN_MASK I40IW_CQPSQ_TPHEN_MASK
-
-#define I40IW_CQPSQ_SRQ_ARMLIMITEVENT_SHIFT 61
-#define I40IW_CQPSQ_SRQ_ARMLIMITEVENT_MASK \
- (1ULL << I40IW_CQPSQ_SRQ_ARMLIMITEVENT_SHIFT)
-
-#define I40IW_CQPSQ_SRQ_DBSHADOWAREA_SHIFT 6
-#define I40IW_CQPSQ_SRQ_DBSHADOWAREA_MASK \
- (0x3ffffffffffffffULL << I40IW_CQPSQ_SRQ_DBSHADOWAREA_SHIFT)
-
-#define I40IW_CQPSQ_SRQ_FIRSTPMPBLIDX_SHIFT 0
-#define I40IW_CQPSQ_SRQ_FIRSTPMPBLIDX_MASK \
- (0xfffffffUL << I40IW_CQPSQ_SRQ_FIRSTPMPBLIDX_SHIFT)
-
-/* Allocate/Register/Register Shared/Deallocate Stag */
-#define I40IW_CQPSQ_STAG_VA_FBO_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IW_CQPSQ_STAG_VA_FBO_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IW_CQPSQ_STAG_STAGLEN_SHIFT 0
-#define I40IW_CQPSQ_STAG_STAGLEN_MASK \
- (0x3fffffffffffULL << I40IW_CQPSQ_STAG_STAGLEN_SHIFT)
-
-#define I40IW_CQPSQ_STAG_PDID_SHIFT 48
-#define I40IW_CQPSQ_STAG_PDID_MASK (0x7fffULL << I40IW_CQPSQ_STAG_PDID_SHIFT)
-
-#define I40IW_CQPSQ_STAG_KEY_SHIFT 0
-#define I40IW_CQPSQ_STAG_KEY_MASK (0xffUL << I40IW_CQPSQ_STAG_KEY_SHIFT)
-
-#define I40IW_CQPSQ_STAG_IDX_SHIFT 8
-#define I40IW_CQPSQ_STAG_IDX_MASK (0xffffffUL << I40IW_CQPSQ_STAG_IDX_SHIFT)
-
-#define I40IW_CQPSQ_STAG_PARENTSTAGIDX_SHIFT 32
-#define I40IW_CQPSQ_STAG_PARENTSTAGIDX_MASK \
- (0xffffffULL << I40IW_CQPSQ_STAG_PARENTSTAGIDX_SHIFT)
-
-#define I40IW_CQPSQ_STAG_MR_SHIFT 43
-#define I40IW_CQPSQ_STAG_MR_MASK (1ULL << I40IW_CQPSQ_STAG_MR_SHIFT)
-
-#define I40IW_CQPSQ_STAG_LPBLSIZE_SHIFT I40IW_CQPSQ_CQ_LPBLSIZE_SHIFT
-#define I40IW_CQPSQ_STAG_LPBLSIZE_MASK I40IW_CQPSQ_CQ_LPBLSIZE_MASK
-
-#define I40IW_CQPSQ_STAG_HPAGESIZE_SHIFT 46
-#define I40IW_CQPSQ_STAG_HPAGESIZE_MASK \
- (1ULL << I40IW_CQPSQ_STAG_HPAGESIZE_SHIFT)
-
-#define I40IW_CQPSQ_STAG_ARIGHTS_SHIFT 48
-#define I40IW_CQPSQ_STAG_ARIGHTS_MASK \
- (0x1fULL << I40IW_CQPSQ_STAG_ARIGHTS_SHIFT)
-
-#define I40IW_CQPSQ_STAG_REMACCENABLED_SHIFT 53
-#define I40IW_CQPSQ_STAG_REMACCENABLED_MASK \
- (1ULL << I40IW_CQPSQ_STAG_REMACCENABLED_SHIFT)
-
-#define I40IW_CQPSQ_STAG_VABASEDTO_SHIFT 59
-#define I40IW_CQPSQ_STAG_VABASEDTO_MASK \
- (1ULL << I40IW_CQPSQ_STAG_VABASEDTO_SHIFT)
-
-#define I40IW_CQPSQ_STAG_USEHMCFNIDX_SHIFT 60
-#define I40IW_CQPSQ_STAG_USEHMCFNIDX_MASK \
- (1ULL << I40IW_CQPSQ_STAG_USEHMCFNIDX_SHIFT)
-
-#define I40IW_CQPSQ_STAG_USEPFRID_SHIFT 61
-#define I40IW_CQPSQ_STAG_USEPFRID_MASK \
- (1ULL << I40IW_CQPSQ_STAG_USEPFRID_SHIFT)
-
-#define I40IW_CQPSQ_STAG_PBA_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IW_CQPSQ_STAG_PBA_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IW_CQPSQ_STAG_HMCFNIDX_SHIFT 0
-#define I40IW_CQPSQ_STAG_HMCFNIDX_MASK \
- (0x3fUL << I40IW_CQPSQ_STAG_HMCFNIDX_SHIFT)
-
-#define I40IW_CQPSQ_STAG_FIRSTPMPBLIDX_SHIFT 0
-#define I40IW_CQPSQ_STAG_FIRSTPMPBLIDX_MASK \
- (0xfffffffUL << I40IW_CQPSQ_STAG_FIRSTPMPBLIDX_SHIFT)
-
-/* Query stag */
-#define I40IW_CQPSQ_QUERYSTAG_IDX_SHIFT I40IW_CQPSQ_STAG_IDX_SHIFT
-#define I40IW_CQPSQ_QUERYSTAG_IDX_MASK I40IW_CQPSQ_STAG_IDX_MASK
-
-/* Allocate Local IP Address Entry */
-
-/* Manage Local IP Address Table - MLIPA */
-#define I40IW_CQPSQ_MLIPA_IPV6LO_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IW_CQPSQ_MLIPA_IPV6LO_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IW_CQPSQ_MLIPA_IPV6HI_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IW_CQPSQ_MLIPA_IPV6HI_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IW_CQPSQ_MLIPA_IPV4_SHIFT 0
-#define I40IW_CQPSQ_MLIPA_IPV4_MASK \
- (0xffffffffUL << I40IW_CQPSQ_MLIPA_IPV4_SHIFT)
-
-#define I40IW_CQPSQ_MLIPA_IPTABLEIDX_SHIFT 0
-#define I40IW_CQPSQ_MLIPA_IPTABLEIDX_MASK \
- (0x3fUL << I40IW_CQPSQ_MLIPA_IPTABLEIDX_SHIFT)
-
-#define I40IW_CQPSQ_MLIPA_IPV4VALID_SHIFT 42
-#define I40IW_CQPSQ_MLIPA_IPV4VALID_MASK \
- (1ULL << I40IW_CQPSQ_MLIPA_IPV4VALID_SHIFT)
-
-#define I40IW_CQPSQ_MLIPA_IPV6VALID_SHIFT 43
-#define I40IW_CQPSQ_MLIPA_IPV6VALID_MASK \
- (1ULL << I40IW_CQPSQ_MLIPA_IPV6VALID_SHIFT)
-
-#define I40IW_CQPSQ_MLIPA_FREEENTRY_SHIFT 62
-#define I40IW_CQPSQ_MLIPA_FREEENTRY_MASK \
- (1ULL << I40IW_CQPSQ_MLIPA_FREEENTRY_SHIFT)
-
-#define I40IW_CQPSQ_MLIPA_IGNORE_REF_CNT_SHIFT 61
-#define I40IW_CQPSQ_MLIPA_IGNORE_REF_CNT_MASK \
- (1ULL << I40IW_CQPSQ_MLIPA_IGNORE_REF_CNT_SHIFT)
-
-#define I40IW_CQPSQ_MLIPA_MAC0_SHIFT 0
-#define I40IW_CQPSQ_MLIPA_MAC0_MASK (0xffUL << I40IW_CQPSQ_MLIPA_MAC0_SHIFT)
-
-#define I40IW_CQPSQ_MLIPA_MAC1_SHIFT 8
-#define I40IW_CQPSQ_MLIPA_MAC1_MASK (0xffUL << I40IW_CQPSQ_MLIPA_MAC1_SHIFT)
-
-#define I40IW_CQPSQ_MLIPA_MAC2_SHIFT 16
-#define I40IW_CQPSQ_MLIPA_MAC2_MASK (0xffUL << I40IW_CQPSQ_MLIPA_MAC2_SHIFT)
-
-#define I40IW_CQPSQ_MLIPA_MAC3_SHIFT 24
-#define I40IW_CQPSQ_MLIPA_MAC3_MASK (0xffUL << I40IW_CQPSQ_MLIPA_MAC3_SHIFT)
-
-#define I40IW_CQPSQ_MLIPA_MAC4_SHIFT 32
-#define I40IW_CQPSQ_MLIPA_MAC4_MASK (0xffULL << I40IW_CQPSQ_MLIPA_MAC4_SHIFT)
-
-#define I40IW_CQPSQ_MLIPA_MAC5_SHIFT 40
-#define I40IW_CQPSQ_MLIPA_MAC5_MASK (0xffULL << I40IW_CQPSQ_MLIPA_MAC5_SHIFT)
-
-/* Manage ARP Table - MAT */
-#define I40IW_CQPSQ_MAT_REACHMAX_SHIFT 0
-#define I40IW_CQPSQ_MAT_REACHMAX_MASK \
- (0xffffffffUL << I40IW_CQPSQ_MAT_REACHMAX_SHIFT)
-
-#define I40IW_CQPSQ_MAT_MACADDR_SHIFT 0
-#define I40IW_CQPSQ_MAT_MACADDR_MASK \
- (0xffffffffffffULL << I40IW_CQPSQ_MAT_MACADDR_SHIFT)
-
-#define I40IW_CQPSQ_MAT_ARPENTRYIDX_SHIFT 0
-#define I40IW_CQPSQ_MAT_ARPENTRYIDX_MASK \
- (0xfffUL << I40IW_CQPSQ_MAT_ARPENTRYIDX_SHIFT)
-
-#define I40IW_CQPSQ_MAT_ENTRYVALID_SHIFT 42
-#define I40IW_CQPSQ_MAT_ENTRYVALID_MASK \
- (1ULL << I40IW_CQPSQ_MAT_ENTRYVALID_SHIFT)
-
-#define I40IW_CQPSQ_MAT_PERMANENT_SHIFT 43
-#define I40IW_CQPSQ_MAT_PERMANENT_MASK \
- (1ULL << I40IW_CQPSQ_MAT_PERMANENT_SHIFT)
-
-#define I40IW_CQPSQ_MAT_QUERY_SHIFT 44
-#define I40IW_CQPSQ_MAT_QUERY_MASK (1ULL << I40IW_CQPSQ_MAT_QUERY_SHIFT)
-
-/* Manage VF PBLE Backing Pages - MVPBP*/
-#define I40IW_CQPSQ_MVPBP_PD_ENTRY_CNT_SHIFT 0
-#define I40IW_CQPSQ_MVPBP_PD_ENTRY_CNT_MASK \
- (0x3ffULL << I40IW_CQPSQ_MVPBP_PD_ENTRY_CNT_SHIFT)
-
-#define I40IW_CQPSQ_MVPBP_FIRST_PD_INX_SHIFT 16
-#define I40IW_CQPSQ_MVPBP_FIRST_PD_INX_MASK \
- (0x1ffULL << I40IW_CQPSQ_MVPBP_FIRST_PD_INX_SHIFT)
-
-#define I40IW_CQPSQ_MVPBP_SD_INX_SHIFT 32
-#define I40IW_CQPSQ_MVPBP_SD_INX_MASK \
- (0xfffULL << I40IW_CQPSQ_MVPBP_SD_INX_SHIFT)
-
-#define I40IW_CQPSQ_MVPBP_INV_PD_ENT_SHIFT 62
-#define I40IW_CQPSQ_MVPBP_INV_PD_ENT_MASK \
- (0x1ULL << I40IW_CQPSQ_MVPBP_INV_PD_ENT_SHIFT)
-
-#define I40IW_CQPSQ_MVPBP_PD_PLPBA_SHIFT 3
-#define I40IW_CQPSQ_MVPBP_PD_PLPBA_MASK \
- (0x1fffffffffffffffULL << I40IW_CQPSQ_MVPBP_PD_PLPBA_SHIFT)
-
-#define I40IW_INVALID_PUSH_PAGE_INDEX 0xffff
-
-#define I40IW_CQPSQ_MPP_QS_HANDLE_SHIFT 0
-#define I40IW_CQPSQ_MPP_QS_HANDLE_MASK (0xffffUL << \
- I40IW_CQPSQ_MPP_QS_HANDLE_SHIFT)
-
-#define I40IW_CQPSQ_MPP_PPIDX_SHIFT 0
-#define I40IW_CQPSQ_MPP_PPIDX_MASK (0x3ffUL << I40IW_CQPSQ_MPP_PPIDX_SHIFT)
-
-#define I40IW_CQPSQ_MPP_FREE_PAGE_SHIFT 62
-#define I40IW_CQPSQ_MPP_FREE_PAGE_MASK (1ULL << I40IW_CQPSQ_MPP_FREE_PAGE_SHIFT)
-
-/* Upload Context - UCTX */
-#define I40IW_CQPSQ_UCTX_QPCTXADDR_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IW_CQPSQ_UCTX_QPCTXADDR_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IW_CQPSQ_UCTX_QPID_SHIFT 0
-#define I40IW_CQPSQ_UCTX_QPID_MASK (0x3ffffUL << I40IW_CQPSQ_UCTX_QPID_SHIFT)
-
-#define I40IW_CQPSQ_UCTX_QPTYPE_SHIFT 48
-#define I40IW_CQPSQ_UCTX_QPTYPE_MASK (0xfULL << I40IW_CQPSQ_UCTX_QPTYPE_SHIFT)
-
-#define I40IW_CQPSQ_UCTX_RAWFORMAT_SHIFT 61
-#define I40IW_CQPSQ_UCTX_RAWFORMAT_MASK \
- (1ULL << I40IW_CQPSQ_UCTX_RAWFORMAT_SHIFT)
-
-#define I40IW_CQPSQ_UCTX_FREEZEQP_SHIFT 62
-#define I40IW_CQPSQ_UCTX_FREEZEQP_MASK \
- (1ULL << I40IW_CQPSQ_UCTX_FREEZEQP_SHIFT)
-
-/* Manage HMC PM Function Table - MHMC */
-#define I40IW_CQPSQ_MHMC_VFIDX_SHIFT 0
-#define I40IW_CQPSQ_MHMC_VFIDX_MASK (0x7fUL << I40IW_CQPSQ_MHMC_VFIDX_SHIFT)
-
-#define I40IW_CQPSQ_MHMC_FREEPMFN_SHIFT 62
-#define I40IW_CQPSQ_MHMC_FREEPMFN_MASK \
- (1ULL << I40IW_CQPSQ_MHMC_FREEPMFN_SHIFT)
-
-/* Set HMC Resource Profile - SHMCRP */
-#define I40IW_CQPSQ_SHMCRP_HMC_PROFILE_SHIFT 0
-#define I40IW_CQPSQ_SHMCRP_HMC_PROFILE_MASK \
- (0x7ULL << I40IW_CQPSQ_SHMCRP_HMC_PROFILE_SHIFT)
-#define I40IW_CQPSQ_SHMCRP_VFNUM_SHIFT 32
-#define I40IW_CQPSQ_SHMCRP_VFNUM_MASK (0x3fULL << I40IW_CQPSQ_SHMCRP_VFNUM_SHIFT)
-
-/* Create/Destroy CEQ */
-#define I40IW_CQPSQ_CEQ_CEQSIZE_SHIFT 0
-#define I40IW_CQPSQ_CEQ_CEQSIZE_MASK \
- (0x1ffffUL << I40IW_CQPSQ_CEQ_CEQSIZE_SHIFT)
-
-#define I40IW_CQPSQ_CEQ_CEQID_SHIFT 0
-#define I40IW_CQPSQ_CEQ_CEQID_MASK (0x7fUL << I40IW_CQPSQ_CEQ_CEQID_SHIFT)
-
-#define I40IW_CQPSQ_CEQ_LPBLSIZE_SHIFT I40IW_CQPSQ_CQ_LPBLSIZE_SHIFT
-#define I40IW_CQPSQ_CEQ_LPBLSIZE_MASK I40IW_CQPSQ_CQ_LPBLSIZE_MASK
-
-#define I40IW_CQPSQ_CEQ_VMAP_SHIFT 47
-#define I40IW_CQPSQ_CEQ_VMAP_MASK (1ULL << I40IW_CQPSQ_CEQ_VMAP_SHIFT)
-
-#define I40IW_CQPSQ_CEQ_FIRSTPMPBLIDX_SHIFT 0
-#define I40IW_CQPSQ_CEQ_FIRSTPMPBLIDX_MASK \
- (0xfffffffUL << I40IW_CQPSQ_CEQ_FIRSTPMPBLIDX_SHIFT)
-
-/* Create/Destroy AEQ */
-#define I40IW_CQPSQ_AEQ_AEQECNT_SHIFT 0
-#define I40IW_CQPSQ_AEQ_AEQECNT_MASK \
- (0x7ffffUL << I40IW_CQPSQ_AEQ_AEQECNT_SHIFT)
-
-#define I40IW_CQPSQ_AEQ_LPBLSIZE_SHIFT I40IW_CQPSQ_CQ_LPBLSIZE_SHIFT
-#define I40IW_CQPSQ_AEQ_LPBLSIZE_MASK I40IW_CQPSQ_CQ_LPBLSIZE_MASK
-
-#define I40IW_CQPSQ_AEQ_VMAP_SHIFT 47
-#define I40IW_CQPSQ_AEQ_VMAP_MASK (1ULL << I40IW_CQPSQ_AEQ_VMAP_SHIFT)
-
-#define I40IW_CQPSQ_AEQ_FIRSTPMPBLIDX_SHIFT 0
-#define I40IW_CQPSQ_AEQ_FIRSTPMPBLIDX_MASK \
- (0xfffffffUL << I40IW_CQPSQ_AEQ_FIRSTPMPBLIDX_SHIFT)
-
-/* Commit FPM Values - CFPM */
-#define I40IW_CQPSQ_CFPM_HMCFNID_SHIFT 0
-#define I40IW_CQPSQ_CFPM_HMCFNID_MASK (0x3fUL << I40IW_CQPSQ_CFPM_HMCFNID_SHIFT)
-
-/* Flush WQEs - FWQE */
-#define I40IW_CQPSQ_FWQE_AECODE_SHIFT 0
-#define I40IW_CQPSQ_FWQE_AECODE_MASK (0xffffUL << I40IW_CQPSQ_FWQE_AECODE_SHIFT)
-
-#define I40IW_CQPSQ_FWQE_AESOURCE_SHIFT 16
-#define I40IW_CQPSQ_FWQE_AESOURCE_MASK \
- (0xfUL << I40IW_CQPSQ_FWQE_AESOURCE_SHIFT)
-
-#define I40IW_CQPSQ_FWQE_RQMNERR_SHIFT 0
-#define I40IW_CQPSQ_FWQE_RQMNERR_MASK \
- (0xffffUL << I40IW_CQPSQ_FWQE_RQMNERR_SHIFT)
-
-#define I40IW_CQPSQ_FWQE_RQMJERR_SHIFT 16
-#define I40IW_CQPSQ_FWQE_RQMJERR_MASK \
- (0xffffUL << I40IW_CQPSQ_FWQE_RQMJERR_SHIFT)
-
-#define I40IW_CQPSQ_FWQE_SQMNERR_SHIFT 32
-#define I40IW_CQPSQ_FWQE_SQMNERR_MASK \
- (0xffffULL << I40IW_CQPSQ_FWQE_SQMNERR_SHIFT)
-
-#define I40IW_CQPSQ_FWQE_SQMJERR_SHIFT 48
-#define I40IW_CQPSQ_FWQE_SQMJERR_MASK \
- (0xffffULL << I40IW_CQPSQ_FWQE_SQMJERR_SHIFT)
-
-#define I40IW_CQPSQ_FWQE_QPID_SHIFT 0
-#define I40IW_CQPSQ_FWQE_QPID_MASK (0x3ffffULL << I40IW_CQPSQ_FWQE_QPID_SHIFT)
-
-#define I40IW_CQPSQ_FWQE_GENERATE_AE_SHIFT 59
-#define I40IW_CQPSQ_FWQE_GENERATE_AE_MASK (1ULL << \
- I40IW_CQPSQ_FWQE_GENERATE_AE_SHIFT)
-
-#define I40IW_CQPSQ_FWQE_USERFLCODE_SHIFT 60
-#define I40IW_CQPSQ_FWQE_USERFLCODE_MASK \
- (1ULL << I40IW_CQPSQ_FWQE_USERFLCODE_SHIFT)
-
-#define I40IW_CQPSQ_FWQE_FLUSHSQ_SHIFT 61
-#define I40IW_CQPSQ_FWQE_FLUSHSQ_MASK (1ULL << I40IW_CQPSQ_FWQE_FLUSHSQ_SHIFT)
-
-#define I40IW_CQPSQ_FWQE_FLUSHRQ_SHIFT 62
-#define I40IW_CQPSQ_FWQE_FLUSHRQ_MASK (1ULL << I40IW_CQPSQ_FWQE_FLUSHRQ_SHIFT)
-
-/* Manage Accelerated Port Table - MAPT */
-#define I40IW_CQPSQ_MAPT_PORT_SHIFT 0
-#define I40IW_CQPSQ_MAPT_PORT_MASK (0xffffUL << I40IW_CQPSQ_MAPT_PORT_SHIFT)
-
-#define I40IW_CQPSQ_MAPT_ADDPORT_SHIFT 62
-#define I40IW_CQPSQ_MAPT_ADDPORT_MASK (1ULL << I40IW_CQPSQ_MAPT_ADDPORT_SHIFT)
-
-/* Update Protocol Engine SDs */
-#define I40IW_CQPSQ_UPESD_SDCMD_SHIFT 0
-#define I40IW_CQPSQ_UPESD_SDCMD_MASK (0xffffffffUL << I40IW_CQPSQ_UPESD_SDCMD_SHIFT)
-
-#define I40IW_CQPSQ_UPESD_SDDATALOW_SHIFT 0
-#define I40IW_CQPSQ_UPESD_SDDATALOW_MASK \
- (0xffffffffUL << I40IW_CQPSQ_UPESD_SDDATALOW_SHIFT)
-
-#define I40IW_CQPSQ_UPESD_SDDATAHI_SHIFT 32
-#define I40IW_CQPSQ_UPESD_SDDATAHI_MASK \
- (0xffffffffULL << I40IW_CQPSQ_UPESD_SDDATAHI_SHIFT)
-#define I40IW_CQPSQ_UPESD_HMCFNID_SHIFT 0
-#define I40IW_CQPSQ_UPESD_HMCFNID_MASK \
- (0x3fUL << I40IW_CQPSQ_UPESD_HMCFNID_SHIFT)
-
-#define I40IW_CQPSQ_UPESD_ENTRY_VALID_SHIFT 63
-#define I40IW_CQPSQ_UPESD_ENTRY_VALID_MASK \
- ((u64)1 << I40IW_CQPSQ_UPESD_ENTRY_VALID_SHIFT)
-
-#define I40IW_CQPSQ_UPESD_ENTRY_COUNT_SHIFT 0
-#define I40IW_CQPSQ_UPESD_ENTRY_COUNT_MASK \
- (0xfUL << I40IW_CQPSQ_UPESD_ENTRY_COUNT_SHIFT)
-
-#define I40IW_CQPSQ_UPESD_SKIP_ENTRY_SHIFT 7
-#define I40IW_CQPSQ_UPESD_SKIP_ENTRY_MASK \
- (0x1UL << I40IW_CQPSQ_UPESD_SKIP_ENTRY_SHIFT)
-
-/* Suspend QP */
-#define I40IW_CQPSQ_SUSPENDQP_QPID_SHIFT 0
-#define I40IW_CQPSQ_SUSPENDQP_QPID_MASK (0x3FFFFUL)
-/* I40IWCQ_QPID_MASK */
-
-/* Resume QP */
-#define I40IW_CQPSQ_RESUMEQP_QSHANDLE_SHIFT 0
-#define I40IW_CQPSQ_RESUMEQP_QSHANDLE_MASK \
- (0xffffffffUL << I40IW_CQPSQ_RESUMEQP_QSHANDLE_SHIFT)
-
-#define I40IW_CQPSQ_RESUMEQP_QPID_SHIFT 0
-#define I40IW_CQPSQ_RESUMEQP_QPID_MASK (0x3FFFFUL)
-/* I40IWCQ_QPID_MASK */
-
-/* IW QP Context */
-#define I40IWQPC_DDP_VER_SHIFT 0
-#define I40IWQPC_DDP_VER_MASK (3UL << I40IWQPC_DDP_VER_SHIFT)
-
-#define I40IWQPC_SNAP_SHIFT 2
-#define I40IWQPC_SNAP_MASK (1UL << I40IWQPC_SNAP_SHIFT)
-
-#define I40IWQPC_IPV4_SHIFT 3
-#define I40IWQPC_IPV4_MASK (1UL << I40IWQPC_IPV4_SHIFT)
-
-#define I40IWQPC_NONAGLE_SHIFT 4
-#define I40IWQPC_NONAGLE_MASK (1UL << I40IWQPC_NONAGLE_SHIFT)
-
-#define I40IWQPC_INSERTVLANTAG_SHIFT 5
-#define I40IWQPC_INSERTVLANTAG_MASK (1 << I40IWQPC_INSERTVLANTAG_SHIFT)
-
-#define I40IWQPC_USESRQ_SHIFT 6
-#define I40IWQPC_USESRQ_MASK (1UL << I40IWQPC_USESRQ_SHIFT)
-
-#define I40IWQPC_TIMESTAMP_SHIFT 7
-#define I40IWQPC_TIMESTAMP_MASK (1UL << I40IWQPC_TIMESTAMP_SHIFT)
-
-#define I40IWQPC_RQWQESIZE_SHIFT 8
-#define I40IWQPC_RQWQESIZE_MASK (3UL << I40IWQPC_RQWQESIZE_SHIFT)
-
-#define I40IWQPC_INSERTL2TAG2_SHIFT 11
-#define I40IWQPC_INSERTL2TAG2_MASK (1UL << I40IWQPC_INSERTL2TAG2_SHIFT)
-
-#define I40IWQPC_LIMIT_SHIFT 12
-#define I40IWQPC_LIMIT_MASK (3UL << I40IWQPC_LIMIT_SHIFT)
-
-#define I40IWQPC_DROPOOOSEG_SHIFT 15
-#define I40IWQPC_DROPOOOSEG_MASK (1UL << I40IWQPC_DROPOOOSEG_SHIFT)
-
-#define I40IWQPC_DUPACK_THRESH_SHIFT 16
-#define I40IWQPC_DUPACK_THRESH_MASK (7UL << I40IWQPC_DUPACK_THRESH_SHIFT)
-
-#define I40IWQPC_ERR_RQ_IDX_VALID_SHIFT 19
-#define I40IWQPC_ERR_RQ_IDX_VALID_MASK (1UL << I40IWQPC_ERR_RQ_IDX_VALID_SHIFT)
-
-#define I40IWQPC_DIS_VLAN_CHECKS_SHIFT 19
-#define I40IWQPC_DIS_VLAN_CHECKS_MASK (7UL << I40IWQPC_DIS_VLAN_CHECKS_SHIFT)
-
-#define I40IWQPC_RCVTPHEN_SHIFT 28
-#define I40IWQPC_RCVTPHEN_MASK (1UL << I40IWQPC_RCVTPHEN_SHIFT)
-
-#define I40IWQPC_XMITTPHEN_SHIFT 29
-#define I40IWQPC_XMITTPHEN_MASK (1ULL << I40IWQPC_XMITTPHEN_SHIFT)
-
-#define I40IWQPC_RQTPHEN_SHIFT 30
-#define I40IWQPC_RQTPHEN_MASK (1UL << I40IWQPC_RQTPHEN_SHIFT)
-
-#define I40IWQPC_SQTPHEN_SHIFT 31
-#define I40IWQPC_SQTPHEN_MASK (1ULL << I40IWQPC_SQTPHEN_SHIFT)
-
-#define I40IWQPC_PPIDX_SHIFT 32
-#define I40IWQPC_PPIDX_MASK (0x3ffULL << I40IWQPC_PPIDX_SHIFT)
-
-#define I40IWQPC_PMENA_SHIFT 47
-#define I40IWQPC_PMENA_MASK (1ULL << I40IWQPC_PMENA_SHIFT)
-
-#define I40IWQPC_RDMAP_VER_SHIFT 62
-#define I40IWQPC_RDMAP_VER_MASK (3ULL << I40IWQPC_RDMAP_VER_SHIFT)
-
-#define I40IWQPC_SQADDR_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IWQPC_SQADDR_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IWQPC_RQADDR_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IWQPC_RQADDR_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IWQPC_TTL_SHIFT 0
-#define I40IWQPC_TTL_MASK (0xffUL << I40IWQPC_TTL_SHIFT)
-
-#define I40IWQPC_RQSIZE_SHIFT 8
-#define I40IWQPC_RQSIZE_MASK (0xfUL << I40IWQPC_RQSIZE_SHIFT)
-
-#define I40IWQPC_SQSIZE_SHIFT 12
-#define I40IWQPC_SQSIZE_MASK (0xfUL << I40IWQPC_SQSIZE_SHIFT)
-
-#define I40IWQPC_SRCMACADDRIDX_SHIFT 16
-#define I40IWQPC_SRCMACADDRIDX_MASK (0x3fUL << I40IWQPC_SRCMACADDRIDX_SHIFT)
-
-#define I40IWQPC_AVOIDSTRETCHACK_SHIFT 23
-#define I40IWQPC_AVOIDSTRETCHACK_MASK (1UL << I40IWQPC_AVOIDSTRETCHACK_SHIFT)
-
-#define I40IWQPC_TOS_SHIFT 24
-#define I40IWQPC_TOS_MASK (0xffUL << I40IWQPC_TOS_SHIFT)
-
-#define I40IWQPC_SRCPORTNUM_SHIFT 32
-#define I40IWQPC_SRCPORTNUM_MASK (0xffffULL << I40IWQPC_SRCPORTNUM_SHIFT)
-
-#define I40IWQPC_DESTPORTNUM_SHIFT 48
-#define I40IWQPC_DESTPORTNUM_MASK (0xffffULL << I40IWQPC_DESTPORTNUM_SHIFT)
-
-#define I40IWQPC_DESTIPADDR0_SHIFT 32
-#define I40IWQPC_DESTIPADDR0_MASK \
- (0xffffffffULL << I40IWQPC_DESTIPADDR0_SHIFT)
-
-#define I40IWQPC_DESTIPADDR1_SHIFT 0
-#define I40IWQPC_DESTIPADDR1_MASK \
- (0xffffffffULL << I40IWQPC_DESTIPADDR1_SHIFT)
-
-#define I40IWQPC_DESTIPADDR2_SHIFT 32
-#define I40IWQPC_DESTIPADDR2_MASK \
- (0xffffffffULL << I40IWQPC_DESTIPADDR2_SHIFT)
-
-#define I40IWQPC_DESTIPADDR3_SHIFT 0
-#define I40IWQPC_DESTIPADDR3_MASK \
- (0xffffffffULL << I40IWQPC_DESTIPADDR3_SHIFT)
-
-#define I40IWQPC_SNDMSS_SHIFT 16
-#define I40IWQPC_SNDMSS_MASK (0x3fffUL << I40IWQPC_SNDMSS_SHIFT)
-
-#define I40IW_UDA_QPC_MAXFRAMESIZE_SHIFT 16
-#define I40IW_UDA_QPC_MAXFRAMESIZE_MASK (0x3fffUL << I40IW_UDA_QPC_MAXFRAMESIZE_SHIFT)
-
-#define I40IWQPC_VLANTAG_SHIFT 32
-#define I40IWQPC_VLANTAG_MASK (0xffffULL << I40IWQPC_VLANTAG_SHIFT)
-
-#define I40IWQPC_ARPIDX_SHIFT 48
-#define I40IWQPC_ARPIDX_MASK (0xffffULL << I40IWQPC_ARPIDX_SHIFT)
-
-#define I40IWQPC_FLOWLABEL_SHIFT 0
-#define I40IWQPC_FLOWLABEL_MASK (0xfffffUL << I40IWQPC_FLOWLABEL_SHIFT)
-
-#define I40IWQPC_WSCALE_SHIFT 20
-#define I40IWQPC_WSCALE_MASK (1UL << I40IWQPC_WSCALE_SHIFT)
-
-#define I40IWQPC_KEEPALIVE_SHIFT 21
-#define I40IWQPC_KEEPALIVE_MASK (1UL << I40IWQPC_KEEPALIVE_SHIFT)
-
-#define I40IWQPC_IGNORE_TCP_OPT_SHIFT 22
-#define I40IWQPC_IGNORE_TCP_OPT_MASK (1UL << I40IWQPC_IGNORE_TCP_OPT_SHIFT)
-
-#define I40IWQPC_IGNORE_TCP_UNS_OPT_SHIFT 23
-#define I40IWQPC_IGNORE_TCP_UNS_OPT_MASK \
- (1UL << I40IWQPC_IGNORE_TCP_UNS_OPT_SHIFT)
-
-#define I40IWQPC_TCPSTATE_SHIFT 28
-#define I40IWQPC_TCPSTATE_MASK (0xfUL << I40IWQPC_TCPSTATE_SHIFT)
-
-#define I40IWQPC_RCVSCALE_SHIFT 32
-#define I40IWQPC_RCVSCALE_MASK (0xfULL << I40IWQPC_RCVSCALE_SHIFT)
-
-#define I40IWQPC_SNDSCALE_SHIFT 40
-#define I40IWQPC_SNDSCALE_MASK (0xfULL << I40IWQPC_SNDSCALE_SHIFT)
-
-#define I40IWQPC_PDIDX_SHIFT 48
-#define I40IWQPC_PDIDX_MASK (0x7fffULL << I40IWQPC_PDIDX_SHIFT)
-
-#define I40IWQPC_KALIVE_TIMER_MAX_PROBES_SHIFT 16
-#define I40IWQPC_KALIVE_TIMER_MAX_PROBES_MASK \
- (0xffUL << I40IWQPC_KALIVE_TIMER_MAX_PROBES_SHIFT)
-
-#define I40IWQPC_KEEPALIVE_INTERVAL_SHIFT 24
-#define I40IWQPC_KEEPALIVE_INTERVAL_MASK \
- (0xffUL << I40IWQPC_KEEPALIVE_INTERVAL_SHIFT)
-
-#define I40IWQPC_TIMESTAMP_RECENT_SHIFT 0
-#define I40IWQPC_TIMESTAMP_RECENT_MASK \
- (0xffffffffUL << I40IWQPC_TIMESTAMP_RECENT_SHIFT)
-
-#define I40IWQPC_TIMESTAMP_AGE_SHIFT 32
-#define I40IWQPC_TIMESTAMP_AGE_MASK \
- (0xffffffffULL << I40IWQPC_TIMESTAMP_AGE_SHIFT)
-
-#define I40IWQPC_SNDNXT_SHIFT 0
-#define I40IWQPC_SNDNXT_MASK (0xffffffffUL << I40IWQPC_SNDNXT_SHIFT)
-
-#define I40IWQPC_SNDWND_SHIFT 32
-#define I40IWQPC_SNDWND_MASK (0xffffffffULL << I40IWQPC_SNDWND_SHIFT)
-
-#define I40IWQPC_RCVNXT_SHIFT 0
-#define I40IWQPC_RCVNXT_MASK (0xffffffffUL << I40IWQPC_RCVNXT_SHIFT)
-
-#define I40IWQPC_RCVWND_SHIFT 32
-#define I40IWQPC_RCVWND_MASK (0xffffffffULL << I40IWQPC_RCVWND_SHIFT)
-
-#define I40IWQPC_SNDMAX_SHIFT 0
-#define I40IWQPC_SNDMAX_MASK (0xffffffffUL << I40IWQPC_SNDMAX_SHIFT)
-
-#define I40IWQPC_SNDUNA_SHIFT 32
-#define I40IWQPC_SNDUNA_MASK (0xffffffffULL << I40IWQPC_SNDUNA_SHIFT)
-
-#define I40IWQPC_SRTT_SHIFT 0
-#define I40IWQPC_SRTT_MASK (0xffffffffUL << I40IWQPC_SRTT_SHIFT)
-
-#define I40IWQPC_RTTVAR_SHIFT 32
-#define I40IWQPC_RTTVAR_MASK (0xffffffffULL << I40IWQPC_RTTVAR_SHIFT)
-
-#define I40IWQPC_SSTHRESH_SHIFT 0
-#define I40IWQPC_SSTHRESH_MASK (0xffffffffUL << I40IWQPC_SSTHRESH_SHIFT)
-
-#define I40IWQPC_CWND_SHIFT 32
-#define I40IWQPC_CWND_MASK (0xffffffffULL << I40IWQPC_CWND_SHIFT)
-
-#define I40IWQPC_SNDWL1_SHIFT 0
-#define I40IWQPC_SNDWL1_MASK (0xffffffffUL << I40IWQPC_SNDWL1_SHIFT)
-
-#define I40IWQPC_SNDWL2_SHIFT 32
-#define I40IWQPC_SNDWL2_MASK (0xffffffffULL << I40IWQPC_SNDWL2_SHIFT)
-
-#define I40IWQPC_ERR_RQ_IDX_SHIFT 32
-#define I40IWQPC_ERR_RQ_IDX_MASK (0x3fffULL << I40IWQPC_ERR_RQ_IDX_SHIFT)
-
-#define I40IWQPC_MAXSNDWND_SHIFT 0
-#define I40IWQPC_MAXSNDWND_MASK (0xffffffffUL << I40IWQPC_MAXSNDWND_SHIFT)
-
-#define I40IWQPC_REXMIT_THRESH_SHIFT 48
-#define I40IWQPC_REXMIT_THRESH_MASK (0x3fULL << I40IWQPC_REXMIT_THRESH_SHIFT)
-
-#define I40IWQPC_TXCQNUM_SHIFT 0
-#define I40IWQPC_TXCQNUM_MASK (0x1ffffUL << I40IWQPC_TXCQNUM_SHIFT)
-
-#define I40IWQPC_RXCQNUM_SHIFT 32
-#define I40IWQPC_RXCQNUM_MASK (0x1ffffULL << I40IWQPC_RXCQNUM_SHIFT)
-
-#define I40IWQPC_STAT_INDEX_SHIFT 0
-#define I40IWQPC_STAT_INDEX_MASK (0x1fULL << I40IWQPC_STAT_INDEX_SHIFT)
-
-#define I40IWQPC_Q2ADDR_SHIFT 0
-#define I40IWQPC_Q2ADDR_MASK (0xffffffffffffff00ULL << I40IWQPC_Q2ADDR_SHIFT)
-
-#define I40IWQPC_LASTBYTESENT_SHIFT 0
-#define I40IWQPC_LASTBYTESENT_MASK (0xffUL << I40IWQPC_LASTBYTESENT_SHIFT)
-
-#define I40IWQPC_SRQID_SHIFT 32
-#define I40IWQPC_SRQID_MASK (0xffULL << I40IWQPC_SRQID_SHIFT)
-
-#define I40IWQPC_ORDSIZE_SHIFT 0
-#define I40IWQPC_ORDSIZE_MASK (0x7fUL << I40IWQPC_ORDSIZE_SHIFT)
-
-#define I40IWQPC_IRDSIZE_SHIFT 16
-#define I40IWQPC_IRDSIZE_MASK (0x3UL << I40IWQPC_IRDSIZE_SHIFT)
-
-#define I40IWQPC_WRRDRSPOK_SHIFT 20
-#define I40IWQPC_WRRDRSPOK_MASK (1UL << I40IWQPC_WRRDRSPOK_SHIFT)
-
-#define I40IWQPC_RDOK_SHIFT 21
-#define I40IWQPC_RDOK_MASK (1UL << I40IWQPC_RDOK_SHIFT)
-
-#define I40IWQPC_SNDMARKERS_SHIFT 22
-#define I40IWQPC_SNDMARKERS_MASK (1UL << I40IWQPC_SNDMARKERS_SHIFT)
-
-#define I40IWQPC_BINDEN_SHIFT 23
-#define I40IWQPC_BINDEN_MASK (1UL << I40IWQPC_BINDEN_SHIFT)
-
-#define I40IWQPC_FASTREGEN_SHIFT 24
-#define I40IWQPC_FASTREGEN_MASK (1UL << I40IWQPC_FASTREGEN_SHIFT)
-
-#define I40IWQPC_PRIVEN_SHIFT 25
-#define I40IWQPC_PRIVEN_MASK (1UL << I40IWQPC_PRIVEN_SHIFT)
-
-#define I40IWQPC_USESTATSINSTANCE_SHIFT 26
-#define I40IWQPC_USESTATSINSTANCE_MASK (1UL << I40IWQPC_USESTATSINSTANCE_SHIFT)
-
-#define I40IWQPC_IWARPMODE_SHIFT 28
-#define I40IWQPC_IWARPMODE_MASK (1UL << I40IWQPC_IWARPMODE_SHIFT)
-
-#define I40IWQPC_RCVMARKERS_SHIFT 29
-#define I40IWQPC_RCVMARKERS_MASK (1UL << I40IWQPC_RCVMARKERS_SHIFT)
-
-#define I40IWQPC_ALIGNHDRS_SHIFT 30
-#define I40IWQPC_ALIGNHDRS_MASK (1UL << I40IWQPC_ALIGNHDRS_SHIFT)
-
-#define I40IWQPC_RCVNOMPACRC_SHIFT 31
-#define I40IWQPC_RCVNOMPACRC_MASK (1UL << I40IWQPC_RCVNOMPACRC_SHIFT)
-
-#define I40IWQPC_RCVMARKOFFSET_SHIFT 33
-#define I40IWQPC_RCVMARKOFFSET_MASK (0x1ffULL << I40IWQPC_RCVMARKOFFSET_SHIFT)
-
-#define I40IWQPC_SNDMARKOFFSET_SHIFT 48
-#define I40IWQPC_SNDMARKOFFSET_MASK (0x1ffULL << I40IWQPC_SNDMARKOFFSET_SHIFT)
-
-#define I40IWQPC_QPCOMPCTX_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IWQPC_QPCOMPCTX_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IWQPC_SQTPHVAL_SHIFT 0
-#define I40IWQPC_SQTPHVAL_MASK (0xffUL << I40IWQPC_SQTPHVAL_SHIFT)
-
-#define I40IWQPC_RQTPHVAL_SHIFT 8
-#define I40IWQPC_RQTPHVAL_MASK (0xffUL << I40IWQPC_RQTPHVAL_SHIFT)
-
-#define I40IWQPC_QSHANDLE_SHIFT 16
-#define I40IWQPC_QSHANDLE_MASK (0x3ffUL << I40IWQPC_QSHANDLE_SHIFT)
-
-#define I40IWQPC_EXCEPTION_LAN_QUEUE_SHIFT 32
-#define I40IWQPC_EXCEPTION_LAN_QUEUE_MASK (0xfffULL << \
- I40IWQPC_EXCEPTION_LAN_QUEUE_SHIFT)
-
-#define I40IWQPC_LOCAL_IPADDR3_SHIFT 0
-#define I40IWQPC_LOCAL_IPADDR3_MASK \
- (0xffffffffUL << I40IWQPC_LOCAL_IPADDR3_SHIFT)
-
-#define I40IWQPC_LOCAL_IPADDR2_SHIFT 32
-#define I40IWQPC_LOCAL_IPADDR2_MASK \
- (0xffffffffULL << I40IWQPC_LOCAL_IPADDR2_SHIFT)
-
-#define I40IWQPC_LOCAL_IPADDR1_SHIFT 0
-#define I40IWQPC_LOCAL_IPADDR1_MASK \
- (0xffffffffUL << I40IWQPC_LOCAL_IPADDR1_SHIFT)
-
-#define I40IWQPC_LOCAL_IPADDR0_SHIFT 32
-#define I40IWQPC_LOCAL_IPADDR0_MASK \
- (0xffffffffULL << I40IWQPC_LOCAL_IPADDR0_SHIFT)
-
-/* wqe size considering 32 bytes per wqe*/
-#define I40IW_QP_SW_MIN_WQSIZE 4 /*in WRs*/
-#define I40IW_SQ_RSVD 2
-#define I40IW_RQ_RSVD 1
-#define I40IW_MAX_QUANTAS_PER_WR 2
-#define I40IW_QP_SW_MAX_SQ_QUANTAS 2048
-#define I40IW_QP_SW_MAX_RQ_QUANTAS 16384
-#define I40IW_MAX_QP_WRS ((I40IW_QP_SW_MAX_SQ_QUANTAS / I40IW_MAX_QUANTAS_PER_WR) - 1)
-
-#define I40IWQP_OP_RDMA_WRITE 0
-#define I40IWQP_OP_RDMA_READ 1
-#define I40IWQP_OP_RDMA_SEND 3
-#define I40IWQP_OP_RDMA_SEND_INV 4
-#define I40IWQP_OP_RDMA_SEND_SOL_EVENT 5
-#define I40IWQP_OP_RDMA_SEND_SOL_EVENT_INV 6
-#define I40IWQP_OP_BIND_MW 8
-#define I40IWQP_OP_FAST_REGISTER 9
-#define I40IWQP_OP_LOCAL_INVALIDATE 10
-#define I40IWQP_OP_RDMA_READ_LOC_INV 11
-#define I40IWQP_OP_NOP 12
-
-#define I40IW_RSVD_SHIFT 41
-#define I40IW_RSVD_MASK (0x7fffULL << I40IW_RSVD_SHIFT)
-
-/* iwarp QP SQ WQE common fields */
-#define I40IWQPSQ_OPCODE_SHIFT 32
-#define I40IWQPSQ_OPCODE_MASK (0x3fULL << I40IWQPSQ_OPCODE_SHIFT)
-
-#define I40IWQPSQ_ADDFRAGCNT_SHIFT 38
-#define I40IWQPSQ_ADDFRAGCNT_MASK (0x7ULL << I40IWQPSQ_ADDFRAGCNT_SHIFT)
-
-#define I40IWQPSQ_STREAMMODE_SHIFT 58
-#define I40IWQPSQ_STREAMMODE_MASK (1ULL << I40IWQPSQ_STREAMMODE_SHIFT)
-
-#define I40IWQPSQ_WAITFORRCVPDU_SHIFT 59
-#define I40IWQPSQ_WAITFORRCVPDU_MASK (1ULL << I40IWQPSQ_WAITFORRCVPDU_SHIFT)
-
-#define I40IWQPSQ_READFENCE_SHIFT 60
-#define I40IWQPSQ_READFENCE_MASK (1ULL << I40IWQPSQ_READFENCE_SHIFT)
-
-#define I40IWQPSQ_LOCALFENCE_SHIFT 61
-#define I40IWQPSQ_LOCALFENCE_MASK (1ULL << I40IWQPSQ_LOCALFENCE_SHIFT)
-
-#define I40IWQPSQ_SIGCOMPL_SHIFT 62
-#define I40IWQPSQ_SIGCOMPL_MASK (1ULL << I40IWQPSQ_SIGCOMPL_SHIFT)
-
-#define I40IWQPSQ_VALID_SHIFT 63
-#define I40IWQPSQ_VALID_MASK (1ULL << I40IWQPSQ_VALID_SHIFT)
-
-#define I40IWQPSQ_FRAG_TO_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IWQPSQ_FRAG_TO_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IWQPSQ_FRAG_LEN_SHIFT 0
-#define I40IWQPSQ_FRAG_LEN_MASK (0xffffffffUL << I40IWQPSQ_FRAG_LEN_SHIFT)
-
-#define I40IWQPSQ_FRAG_STAG_SHIFT 32
-#define I40IWQPSQ_FRAG_STAG_MASK (0xffffffffULL << I40IWQPSQ_FRAG_STAG_SHIFT)
-
-#define I40IWQPSQ_REMSTAGINV_SHIFT 0
-#define I40IWQPSQ_REMSTAGINV_MASK (0xffffffffUL << I40IWQPSQ_REMSTAGINV_SHIFT)
-
-#define I40IWQPSQ_INLINEDATAFLAG_SHIFT 57
-#define I40IWQPSQ_INLINEDATAFLAG_MASK (1ULL << I40IWQPSQ_INLINEDATAFLAG_SHIFT)
-
-#define I40IWQPSQ_INLINEDATALEN_SHIFT 48
-#define I40IWQPSQ_INLINEDATALEN_MASK \
- (0x7fULL << I40IWQPSQ_INLINEDATALEN_SHIFT)
-
-/* iwarp send with push mode */
-#define I40IWQPSQ_WQDESCIDX_SHIFT 0
-#define I40IWQPSQ_WQDESCIDX_MASK (0x3fffUL << I40IWQPSQ_WQDESCIDX_SHIFT)
-
-/* rdma write */
-#define I40IWQPSQ_REMSTAG_SHIFT 0
-#define I40IWQPSQ_REMSTAG_MASK (0xffffffffUL << I40IWQPSQ_REMSTAG_SHIFT)
-
-#define I40IWQPSQ_REMTO_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IWQPSQ_REMTO_MASK I40IW_CQPHC_QPCTX_MASK
-
-/* memory window */
-#define I40IWQPSQ_STAGRIGHTS_SHIFT 48
-#define I40IWQPSQ_STAGRIGHTS_MASK (0x1fULL << I40IWQPSQ_STAGRIGHTS_SHIFT)
-
-#define I40IWQPSQ_VABASEDTO_SHIFT 53
-#define I40IWQPSQ_VABASEDTO_MASK (1ULL << I40IWQPSQ_VABASEDTO_SHIFT)
-
-#define I40IWQPSQ_MWLEN_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IWQPSQ_MWLEN_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IWQPSQ_PARENTMRSTAG_SHIFT 0
-#define I40IWQPSQ_PARENTMRSTAG_MASK \
- (0xffffffffUL << I40IWQPSQ_PARENTMRSTAG_SHIFT)
-
-#define I40IWQPSQ_MWSTAG_SHIFT 32
-#define I40IWQPSQ_MWSTAG_MASK (0xffffffffULL << I40IWQPSQ_MWSTAG_SHIFT)
-
-#define I40IWQPSQ_BASEVA_TO_FBO_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IWQPSQ_BASEVA_TO_FBO_MASK I40IW_CQPHC_QPCTX_MASK
-
-/* Local Invalidate */
-#define I40IWQPSQ_LOCSTAG_SHIFT 32
-#define I40IWQPSQ_LOCSTAG_MASK (0xffffffffULL << I40IWQPSQ_LOCSTAG_SHIFT)
-
-/* Fast Register */
-#define I40IWQPSQ_STAGKEY_SHIFT 0
-#define I40IWQPSQ_STAGKEY_MASK (0xffUL << I40IWQPSQ_STAGKEY_SHIFT)
-
-#define I40IWQPSQ_STAGINDEX_SHIFT 8
-#define I40IWQPSQ_STAGINDEX_MASK (0xffffffUL << I40IWQPSQ_STAGINDEX_SHIFT)
-
-#define I40IWQPSQ_COPYHOSTPBLS_SHIFT 43
-#define I40IWQPSQ_COPYHOSTPBLS_MASK (1ULL << I40IWQPSQ_COPYHOSTPBLS_SHIFT)
-
-#define I40IWQPSQ_LPBLSIZE_SHIFT 44
-#define I40IWQPSQ_LPBLSIZE_MASK (3ULL << I40IWQPSQ_LPBLSIZE_SHIFT)
-
-#define I40IWQPSQ_HPAGESIZE_SHIFT 46
-#define I40IWQPSQ_HPAGESIZE_MASK (3ULL << I40IWQPSQ_HPAGESIZE_SHIFT)
-
-#define I40IWQPSQ_STAGLEN_SHIFT 0
-#define I40IWQPSQ_STAGLEN_MASK (0x1ffffffffffULL << I40IWQPSQ_STAGLEN_SHIFT)
-
-#define I40IWQPSQ_FIRSTPMPBLIDXLO_SHIFT 48
-#define I40IWQPSQ_FIRSTPMPBLIDXLO_MASK \
- (0xffffULL << I40IWQPSQ_FIRSTPMPBLIDXLO_SHIFT)
-
-#define I40IWQPSQ_FIRSTPMPBLIDXHI_SHIFT 0
-#define I40IWQPSQ_FIRSTPMPBLIDXHI_MASK \
- (0xfffUL << I40IWQPSQ_FIRSTPMPBLIDXHI_SHIFT)
-
-#define I40IWQPSQ_PBLADDR_SHIFT 12
-#define I40IWQPSQ_PBLADDR_MASK (0xfffffffffffffULL << I40IWQPSQ_PBLADDR_SHIFT)
-
-/* iwarp QP RQ WQE common fields */
-#define I40IWQPRQ_ADDFRAGCNT_SHIFT I40IWQPSQ_ADDFRAGCNT_SHIFT
-#define I40IWQPRQ_ADDFRAGCNT_MASK I40IWQPSQ_ADDFRAGCNT_MASK
-
-#define I40IWQPRQ_VALID_SHIFT I40IWQPSQ_VALID_SHIFT
-#define I40IWQPRQ_VALID_MASK I40IWQPSQ_VALID_MASK
-
-#define I40IWQPRQ_COMPLCTX_SHIFT I40IW_CQPHC_QPCTX_SHIFT
-#define I40IWQPRQ_COMPLCTX_MASK I40IW_CQPHC_QPCTX_MASK
-
-#define I40IWQPRQ_FRAG_LEN_SHIFT I40IWQPSQ_FRAG_LEN_SHIFT
-#define I40IWQPRQ_FRAG_LEN_MASK I40IWQPSQ_FRAG_LEN_MASK
-
-#define I40IWQPRQ_STAG_SHIFT I40IWQPSQ_FRAG_STAG_SHIFT
-#define I40IWQPRQ_STAG_MASK I40IWQPSQ_FRAG_STAG_MASK
-
-#define I40IWQPRQ_TO_SHIFT I40IWQPSQ_FRAG_TO_SHIFT
-#define I40IWQPRQ_TO_MASK I40IWQPSQ_FRAG_TO_MASK
-
-/* Query FPM CQP buf */
-#define I40IW_QUERY_FPM_MAX_QPS_SHIFT 0
-#define I40IW_QUERY_FPM_MAX_QPS_MASK \
- (0x7ffffUL << I40IW_QUERY_FPM_MAX_QPS_SHIFT)
-
-#define I40IW_QUERY_FPM_MAX_CQS_SHIFT 0
-#define I40IW_QUERY_FPM_MAX_CQS_MASK \
- (0x3ffffUL << I40IW_QUERY_FPM_MAX_CQS_SHIFT)
-
-#define I40IW_QUERY_FPM_FIRST_PE_SD_INDEX_SHIFT 0
-#define I40IW_QUERY_FPM_FIRST_PE_SD_INDEX_MASK \
- (0x3fffUL << I40IW_QUERY_FPM_FIRST_PE_SD_INDEX_SHIFT)
-
-#define I40IW_QUERY_FPM_MAX_PE_SDS_SHIFT 32
-#define I40IW_QUERY_FPM_MAX_PE_SDS_MASK \
- (0x3fffULL << I40IW_QUERY_FPM_MAX_PE_SDS_SHIFT)
-
-#define I40IW_QUERY_FPM_MAX_QPS_SHIFT 0
-#define I40IW_QUERY_FPM_MAX_QPS_MASK \
- (0x7ffffUL << I40IW_QUERY_FPM_MAX_QPS_SHIFT)
-
-#define I40IW_QUERY_FPM_MAX_CQS_SHIFT 0
-#define I40IW_QUERY_FPM_MAX_CQS_MASK \
- (0x3ffffUL << I40IW_QUERY_FPM_MAX_CQS_SHIFT)
-
-#define I40IW_QUERY_FPM_MAX_CEQS_SHIFT 0
-#define I40IW_QUERY_FPM_MAX_CEQS_MASK \
- (0xffUL << I40IW_QUERY_FPM_MAX_CEQS_SHIFT)
-
-#define I40IW_QUERY_FPM_XFBLOCKSIZE_SHIFT 32
-#define I40IW_QUERY_FPM_XFBLOCKSIZE_MASK \
- (0xffffffffULL << I40IW_QUERY_FPM_XFBLOCKSIZE_SHIFT)
-
-#define I40IW_QUERY_FPM_Q1BLOCKSIZE_SHIFT 32
-#define I40IW_QUERY_FPM_Q1BLOCKSIZE_MASK \
- (0xffffffffULL << I40IW_QUERY_FPM_Q1BLOCKSIZE_SHIFT)
-
-#define I40IW_QUERY_FPM_HTMULTIPLIER_SHIFT 16
-#define I40IW_QUERY_FPM_HTMULTIPLIER_MASK \
- (0xfUL << I40IW_QUERY_FPM_HTMULTIPLIER_SHIFT)
-
-#define I40IW_QUERY_FPM_TIMERBUCKET_SHIFT 32
-#define I40IW_QUERY_FPM_TIMERBUCKET_MASK \
- (0xffFFULL << I40IW_QUERY_FPM_TIMERBUCKET_SHIFT)
-
-/* Static HMC pages allocated buf */
-#define I40IW_SHMC_PAGE_ALLOCATED_HMC_FN_ID_SHIFT 0
-#define I40IW_SHMC_PAGE_ALLOCATED_HMC_FN_ID_MASK \
- (0x3fUL << I40IW_SHMC_PAGE_ALLOCATED_HMC_FN_ID_SHIFT)
-
-#define I40IW_HW_PAGE_SIZE 4096
-#define I40IW_DONE_COUNT 1000
-#define I40IW_SLEEP_COUNT 10
-
-enum {
- I40IW_QUEUES_ALIGNMENT_MASK = (128 - 1),
- I40IW_AEQ_ALIGNMENT_MASK = (256 - 1),
- I40IW_Q2_ALIGNMENT_MASK = (256 - 1),
- I40IW_CEQ_ALIGNMENT_MASK = (256 - 1),
- I40IW_CQ0_ALIGNMENT_MASK = (256 - 1),
- I40IW_HOST_CTX_ALIGNMENT_MASK = (4 - 1),
- I40IW_SHADOWAREA_MASK = (128 - 1),
- I40IW_FPM_QUERY_BUF_ALIGNMENT_MASK = (4 - 1),
- I40IW_FPM_COMMIT_BUF_ALIGNMENT_MASK = (4 - 1)
-};
-
-enum i40iw_alignment {
- I40IW_CQP_ALIGNMENT = 0x200,
- I40IW_AEQ_ALIGNMENT = 0x100,
- I40IW_CEQ_ALIGNMENT = 0x100,
- I40IW_CQ0_ALIGNMENT = 0x100,
- I40IW_SD_BUF_ALIGNMENT = 0x80,
- I40IW_FEATURE_BUF_ALIGNMENT = 0x8
-};
-
-#define I40IW_WQE_SIZE_64 64
-
-#define I40IW_QP_WQE_MIN_SIZE 32
-#define I40IW_QP_WQE_MAX_SIZE 128
-
-#define I40IW_UPDATE_SD_BUF_SIZE 128
-
-#define I40IW_CQE_QTYPE_RQ 0
-#define I40IW_CQE_QTYPE_SQ 1
-
-#define I40IW_RING_INIT(_ring, _size) \
- { \
- (_ring).head = 0; \
- (_ring).tail = 0; \
- (_ring).size = (_size); \
- }
-#define I40IW_RING_GETSIZE(_ring) ((_ring).size)
-#define I40IW_RING_GETCURRENT_HEAD(_ring) ((_ring).head)
-#define I40IW_RING_GETCURRENT_TAIL(_ring) ((_ring).tail)
-
-#define I40IW_RING_MOVE_HEAD(_ring, _retcode) \
- { \
- register u32 size; \
- size = (_ring).size; \
- if (!I40IW_RING_FULL_ERR(_ring)) { \
- (_ring).head = ((_ring).head + 1) % size; \
- (_retcode) = 0; \
- } else { \
- (_retcode) = I40IW_ERR_RING_FULL; \
- } \
- }
-
-#define I40IW_RING_MOVE_HEAD_BY_COUNT(_ring, _count, _retcode) \
- { \
- register u32 size; \
- size = (_ring).size; \
- if ((I40IW_RING_WORK_AVAILABLE(_ring) + (_count)) < size) { \
- (_ring).head = ((_ring).head + (_count)) % size; \
- (_retcode) = 0; \
- } else { \
- (_retcode) = I40IW_ERR_RING_FULL; \
- } \
- }
-
-#define I40IW_RING_MOVE_TAIL(_ring) \
- (_ring).tail = ((_ring).tail + 1) % (_ring).size
-
-#define I40IW_RING_MOVE_HEAD_NOCHECK(_ring) \
- (_ring).head = ((_ring).head + 1) % (_ring).size
-
-#define I40IW_RING_MOVE_TAIL_BY_COUNT(_ring, _count) \
- (_ring).tail = ((_ring).tail + (_count)) % (_ring).size
-
-#define I40IW_RING_SET_TAIL(_ring, _pos) \
- (_ring).tail = (_pos) % (_ring).size
-
-#define I40IW_RING_FULL_ERR(_ring) \
- ( \
- (I40IW_RING_WORK_AVAILABLE(_ring) == ((_ring).size - 1)) \
- )
-
-#define I40IW_ERR_RING_FULL2(_ring) \
- ( \
- (I40IW_RING_WORK_AVAILABLE(_ring) == ((_ring).size - 2)) \
- )
-
-#define I40IW_ERR_RING_FULL3(_ring) \
- ( \
- (I40IW_RING_WORK_AVAILABLE(_ring) == ((_ring).size - 3)) \
- )
-
-#define I40IW_RING_MORE_WORK(_ring) \
- ( \
- (I40IW_RING_WORK_AVAILABLE(_ring) != 0) \
- )
-
-#define I40IW_RING_WORK_AVAILABLE(_ring) \
- ( \
- (((_ring).head + (_ring).size - (_ring).tail) % (_ring).size) \
- )
-
-#define I40IW_RING_GET_WQES_AVAILABLE(_ring) \
- ( \
- ((_ring).size - I40IW_RING_WORK_AVAILABLE(_ring) - 1) \
- )
-
-#define I40IW_ATOMIC_RING_MOVE_HEAD(_ring, index, _retcode) \
- { \
- index = I40IW_RING_GETCURRENT_HEAD(_ring); \
- I40IW_RING_MOVE_HEAD(_ring, _retcode); \
- }
-
-/* Async Events codes */
-#define I40IW_AE_AMP_UNALLOCATED_STAG 0x0102
-#define I40IW_AE_AMP_INVALID_STAG 0x0103
-#define I40IW_AE_AMP_BAD_QP 0x0104
-#define I40IW_AE_AMP_BAD_PD 0x0105
-#define I40IW_AE_AMP_BAD_STAG_KEY 0x0106
-#define I40IW_AE_AMP_BAD_STAG_INDEX 0x0107
-#define I40IW_AE_AMP_BOUNDS_VIOLATION 0x0108
-#define I40IW_AE_AMP_RIGHTS_VIOLATION 0x0109
-#define I40IW_AE_AMP_TO_WRAP 0x010a
-#define I40IW_AE_AMP_FASTREG_SHARED 0x010b
-#define I40IW_AE_AMP_FASTREG_VALID_STAG 0x010c
-#define I40IW_AE_AMP_FASTREG_MW_STAG 0x010d
-#define I40IW_AE_AMP_FASTREG_INVALID_RIGHTS 0x010e
-#define I40IW_AE_AMP_FASTREG_PBL_TABLE_OVERFLOW 0x010f
-#define I40IW_AE_AMP_FASTREG_INVALID_LENGTH 0x0110
-#define I40IW_AE_AMP_INVALIDATE_SHARED 0x0111
-#define I40IW_AE_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS 0x0112
-#define I40IW_AE_AMP_INVALIDATE_MR_WITH_BOUND_WINDOWS 0x0113
-#define I40IW_AE_AMP_MWBIND_VALID_STAG 0x0114
-#define I40IW_AE_AMP_MWBIND_OF_MR_STAG 0x0115
-#define I40IW_AE_AMP_MWBIND_TO_ZERO_BASED_STAG 0x0116
-#define I40IW_AE_AMP_MWBIND_TO_MW_STAG 0x0117
-#define I40IW_AE_AMP_MWBIND_INVALID_RIGHTS 0x0118
-#define I40IW_AE_AMP_MWBIND_INVALID_BOUNDS 0x0119
-#define I40IW_AE_AMP_MWBIND_TO_INVALID_PARENT 0x011a
-#define I40IW_AE_AMP_MWBIND_BIND_DISABLED 0x011b
-#define I40IW_AE_UDA_XMIT_DGRAM_TOO_LONG 0x0132
-#define I40IW_AE_UDA_XMIT_DGRAM_TOO_SHORT 0x0134
-#define I40IW_AE_BAD_CLOSE 0x0201
-#define I40IW_AE_RDMAP_ROE_BAD_LLP_CLOSE 0x0202
-#define I40IW_AE_CQ_OPERATION_ERROR 0x0203
-#define I40IW_AE_PRIV_OPERATION_DENIED 0x011c
-#define I40IW_AE_RDMA_READ_WHILE_ORD_ZERO 0x0205
-#define I40IW_AE_STAG_ZERO_INVALID 0x0206
-#define I40IW_AE_IB_RREQ_AND_Q1_FULL 0x0207
-#define I40IW_AE_WQE_UNEXPECTED_OPCODE 0x020a
-#define I40IW_AE_WQE_INVALID_PARAMETER 0x020b
-#define I40IW_AE_WQE_LSMM_TOO_LONG 0x0220
-#define I40IW_AE_DDP_INVALID_MSN_GAP_IN_MSN 0x0301
-#define I40IW_AE_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER 0x0303
-#define I40IW_AE_DDP_UBE_INVALID_DDP_VERSION 0x0304
-#define I40IW_AE_DDP_UBE_INVALID_MO 0x0305
-#define I40IW_AE_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE 0x0306
-#define I40IW_AE_DDP_UBE_INVALID_QN 0x0307
-#define I40IW_AE_DDP_NO_L_BIT 0x0308
-#define I40IW_AE_RDMAP_ROE_INVALID_RDMAP_VERSION 0x0311
-#define I40IW_AE_RDMAP_ROE_UNEXPECTED_OPCODE 0x0312
-#define I40IW_AE_ROE_INVALID_RDMA_READ_REQUEST 0x0313
-#define I40IW_AE_ROE_INVALID_RDMA_WRITE_OR_READ_RESP 0x0314
-#define I40IW_AE_INVALID_ARP_ENTRY 0x0401
-#define I40IW_AE_INVALID_TCP_OPTION_RCVD 0x0402
-#define I40IW_AE_STALE_ARP_ENTRY 0x0403
-#define I40IW_AE_INVALID_MAC_ENTRY 0x0405
-#define I40IW_AE_LLP_CLOSE_COMPLETE 0x0501
-#define I40IW_AE_LLP_CONNECTION_RESET 0x0502
-#define I40IW_AE_LLP_FIN_RECEIVED 0x0503
-#define I40IW_AE_LLP_RECEIVED_MPA_CRC_ERROR 0x0505
-#define I40IW_AE_LLP_SEGMENT_TOO_LARGE 0x0506
-#define I40IW_AE_LLP_SEGMENT_TOO_SMALL 0x0507
-#define I40IW_AE_LLP_SYN_RECEIVED 0x0508
-#define I40IW_AE_LLP_TERMINATE_RECEIVED 0x0509
-#define I40IW_AE_LLP_TOO_MANY_RETRIES 0x050a
-#define I40IW_AE_LLP_TOO_MANY_KEEPALIVE_RETRIES 0x050b
-#define I40IW_AE_LLP_DOUBT_REACHABILITY 0x050c
-#define I40IW_AE_LLP_RX_VLAN_MISMATCH 0x050d
-#define I40IW_AE_RESOURCE_EXHAUSTION 0x0520
-#define I40IW_AE_RESET_SENT 0x0601
-#define I40IW_AE_TERMINATE_SENT 0x0602
-#define I40IW_AE_RESET_NOT_SENT 0x0603
-#define I40IW_AE_LCE_QP_CATASTROPHIC 0x0700
-#define I40IW_AE_LCE_FUNCTION_CATASTROPHIC 0x0701
-#define I40IW_AE_LCE_CQ_CATASTROPHIC 0x0702
-#define I40IW_AE_QP_SUSPEND_COMPLETE 0x0900
-
-#define OP_DELETE_LOCAL_MAC_IPADDR_ENTRY 1
-#define OP_CEQ_DESTROY 2
-#define OP_AEQ_DESTROY 3
-#define OP_DELETE_ARP_CACHE_ENTRY 4
-#define OP_MANAGE_APBVT_ENTRY 5
-#define OP_CEQ_CREATE 6
-#define OP_AEQ_CREATE 7
-#define OP_ALLOC_LOCAL_MAC_IPADDR_ENTRY 8
-#define OP_ADD_LOCAL_MAC_IPADDR_ENTRY 9
-#define OP_MANAGE_QHASH_TABLE_ENTRY 10
-#define OP_QP_MODIFY 11
-#define OP_QP_UPLOAD_CONTEXT 12
-#define OP_CQ_CREATE 13
-#define OP_CQ_DESTROY 14
-#define OP_QP_CREATE 15
-#define OP_QP_DESTROY 16
-#define OP_ALLOC_STAG 17
-#define OP_MR_REG_NON_SHARED 18
-#define OP_DEALLOC_STAG 19
-#define OP_MW_ALLOC 20
-#define OP_QP_FLUSH_WQES 21
-#define OP_ADD_ARP_CACHE_ENTRY 22
-#define OP_UPDATE_PE_SDS 23
-#define OP_MANAGE_HMC_PM_FUNC_TABLE 24
-#define OP_SUSPEND 25
-#define OP_RESUME 26
-#define OP_MANAGE_VF_PBLE_BP 27
-#define OP_QUERY_FPM_VALUES 28
-#define OP_COMMIT_FPM_VALUES 29
-#define OP_REQUESTED_COMMANDS 30
-#define OP_COMPLETED_COMMANDS 31
-#define OP_GEN_AE 32
-#define OP_QUERY_RDMA_FEATURES 33
-#define OP_SIZE_CQP_STAT_ARRAY 34
-
-#endif
diff --git a/drivers/infiniband/hw/i40iw/i40iw_hmc.c b/drivers/infiniband/hw/i40iw/i40iw_hmc.c
deleted file mode 100644
index b44bfc1d239b..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_hmc.c
+++ /dev/null
@@ -1,821 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 "i40iw_osdep.h"
-#include "i40iw_register.h"
-#include "i40iw_status.h"
-#include "i40iw_hmc.h"
-#include "i40iw_d.h"
-#include "i40iw_type.h"
-#include "i40iw_p.h"
-#include "i40iw_vf.h"
-#include "i40iw_virtchnl.h"
-
-/**
- * i40iw_find_sd_index_limit - finds segment descriptor index limit
- * @hmc_info: pointer to the HMC configuration information structure
- * @type: type of HMC resources we're searching
- * @idx: starting index for the object
- * @cnt: number of objects we're trying to create
- * @sd_idx: pointer to return index of the segment descriptor in question
- * @sd_limit: pointer to return the maximum number of segment descriptors
- *
- * This function calculates the segment descriptor index and index limit
- * for the resource defined by i40iw_hmc_rsrc_type.
- */
-
-static inline void i40iw_find_sd_index_limit(struct i40iw_hmc_info *hmc_info,
- u32 type,
- u32 idx,
- u32 cnt,
- u32 *sd_idx,
- u32 *sd_limit)
-{
- u64 fpm_addr, fpm_limit;
-
- fpm_addr = hmc_info->hmc_obj[(type)].base +
- hmc_info->hmc_obj[type].size * idx;
- fpm_limit = fpm_addr + hmc_info->hmc_obj[type].size * cnt;
- *sd_idx = (u32)(fpm_addr / I40IW_HMC_DIRECT_BP_SIZE);
- *sd_limit = (u32)((fpm_limit - 1) / I40IW_HMC_DIRECT_BP_SIZE);
- *sd_limit += 1;
-}
-
-/**
- * i40iw_find_pd_index_limit - finds page descriptor index limit
- * @hmc_info: pointer to the HMC configuration information struct
- * @type: HMC resource type we're examining
- * @idx: starting index for the object
- * @cnt: number of objects we're trying to create
- * @pd_idx: pointer to return page descriptor index
- * @pd_limit: pointer to return page descriptor index limit
- *
- * Calculates the page descriptor index and index limit for the resource
- * defined by i40iw_hmc_rsrc_type.
- */
-
-static inline void i40iw_find_pd_index_limit(struct i40iw_hmc_info *hmc_info,
- u32 type,
- u32 idx,
- u32 cnt,
- u32 *pd_idx,
- u32 *pd_limit)
-{
- u64 fpm_adr, fpm_limit;
-
- fpm_adr = hmc_info->hmc_obj[type].base +
- hmc_info->hmc_obj[type].size * idx;
- fpm_limit = fpm_adr + (hmc_info)->hmc_obj[(type)].size * (cnt);
- *(pd_idx) = (u32)(fpm_adr / I40IW_HMC_PAGED_BP_SIZE);
- *(pd_limit) = (u32)((fpm_limit - 1) / I40IW_HMC_PAGED_BP_SIZE);
- *(pd_limit) += 1;
-}
-
-/**
- * i40iw_set_sd_entry - setup entry for sd programming
- * @pa: physical addr
- * @idx: sd index
- * @type: paged or direct sd
- * @entry: sd entry ptr
- */
-static inline void i40iw_set_sd_entry(u64 pa,
- u32 idx,
- enum i40iw_sd_entry_type type,
- struct update_sd_entry *entry)
-{
- entry->data = pa | (I40IW_HMC_MAX_BP_COUNT << I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) |
- (((type == I40IW_SD_TYPE_PAGED) ? 0 : 1) <<
- I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) |
- (1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT);
- entry->cmd = (idx | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT) | (1 << 15));
-}
-
-/**
- * i40iw_clr_sd_entry - setup entry for sd clear
- * @idx: sd index
- * @type: paged or direct sd
- * @entry: sd entry ptr
- */
-static inline void i40iw_clr_sd_entry(u32 idx, enum i40iw_sd_entry_type type,
- struct update_sd_entry *entry)
-{
- entry->data = (I40IW_HMC_MAX_BP_COUNT <<
- I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) |
- (((type == I40IW_SD_TYPE_PAGED) ? 0 : 1) <<
- I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT);
- entry->cmd = (idx | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT) | (1 << 15));
-}
-
-/**
- * i40iw_hmc_sd_one - setup 1 sd entry for cqp
- * @dev: pointer to the device structure
- * @hmc_fn_id: hmc's function id
- * @pa: physical addr
- * @sd_idx: sd index
- * @type: paged or direct sd
- * @setsd: flag to set or clear sd
- */
-enum i40iw_status_code i40iw_hmc_sd_one(struct i40iw_sc_dev *dev,
- u8 hmc_fn_id,
- u64 pa, u32 sd_idx,
- enum i40iw_sd_entry_type type,
- bool setsd)
-{
- struct i40iw_update_sds_info sdinfo;
-
- sdinfo.cnt = 1;
- sdinfo.hmc_fn_id = hmc_fn_id;
- if (setsd)
- i40iw_set_sd_entry(pa, sd_idx, type, sdinfo.entry);
- else
- i40iw_clr_sd_entry(sd_idx, type, sdinfo.entry);
-
- return dev->cqp->process_cqp_sds(dev, &sdinfo);
-}
-
-/**
- * i40iw_hmc_sd_grp - setup group od sd entries for cqp
- * @dev: pointer to the device structure
- * @hmc_info: pointer to the HMC configuration information struct
- * @sd_index: sd index
- * @sd_cnt: number of sd entries
- * @setsd: flag to set or clear sd
- */
-static enum i40iw_status_code i40iw_hmc_sd_grp(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_info *hmc_info,
- u32 sd_index,
- u32 sd_cnt,
- bool setsd)
-{
- struct i40iw_hmc_sd_entry *sd_entry;
- struct i40iw_update_sds_info sdinfo;
- u64 pa;
- u32 i;
- enum i40iw_status_code ret_code = 0;
-
- memset(&sdinfo, 0, sizeof(sdinfo));
- sdinfo.hmc_fn_id = hmc_info->hmc_fn_id;
- for (i = sd_index; i < sd_index + sd_cnt; i++) {
- sd_entry = &hmc_info->sd_table.sd_entry[i];
- if (!sd_entry ||
- (!sd_entry->valid && setsd) ||
- (sd_entry->valid && !setsd))
- continue;
- if (setsd) {
- pa = (sd_entry->entry_type == I40IW_SD_TYPE_PAGED) ?
- sd_entry->u.pd_table.pd_page_addr.pa :
- sd_entry->u.bp.addr.pa;
- i40iw_set_sd_entry(pa, i, sd_entry->entry_type,
- &sdinfo.entry[sdinfo.cnt]);
- } else {
- i40iw_clr_sd_entry(i, sd_entry->entry_type,
- &sdinfo.entry[sdinfo.cnt]);
- }
- sdinfo.cnt++;
- if (sdinfo.cnt == I40IW_MAX_SD_ENTRIES) {
- ret_code = dev->cqp->process_cqp_sds(dev, &sdinfo);
- if (ret_code) {
- i40iw_debug(dev, I40IW_DEBUG_HMC,
- "i40iw_hmc_sd_grp: sd_programming failed err=%d\n",
- ret_code);
- return ret_code;
- }
- sdinfo.cnt = 0;
- }
- }
- if (sdinfo.cnt)
- ret_code = dev->cqp->process_cqp_sds(dev, &sdinfo);
-
- return ret_code;
-}
-
-/**
- * i40iw_vfdev_from_fpm - return vf dev ptr for hmc function id
- * @dev: pointer to the device structure
- * @hmc_fn_id: hmc's function id
- */
-struct i40iw_vfdev *i40iw_vfdev_from_fpm(struct i40iw_sc_dev *dev, u8 hmc_fn_id)
-{
- struct i40iw_vfdev *vf_dev = NULL;
- u16 idx;
-
- for (idx = 0; idx < I40IW_MAX_PE_ENABLED_VF_COUNT; idx++) {
- if (dev->vf_dev[idx] &&
- ((u8)dev->vf_dev[idx]->pmf_index == hmc_fn_id)) {
- vf_dev = dev->vf_dev[idx];
- break;
- }
- }
- return vf_dev;
-}
-
-/**
- * i40iw_vf_hmcinfo_from_fpm - get ptr to hmc for func_id
- * @dev: pointer to the device structure
- * @hmc_fn_id: hmc's function id
- */
-struct i40iw_hmc_info *i40iw_vf_hmcinfo_from_fpm(struct i40iw_sc_dev *dev,
- u8 hmc_fn_id)
-{
- struct i40iw_hmc_info *hmc_info = NULL;
- u16 idx;
-
- for (idx = 0; idx < I40IW_MAX_PE_ENABLED_VF_COUNT; idx++) {
- if (dev->vf_dev[idx] &&
- ((u8)dev->vf_dev[idx]->pmf_index == hmc_fn_id)) {
- hmc_info = &dev->vf_dev[idx]->hmc_info;
- break;
- }
- }
- return hmc_info;
-}
-
-/**
- * i40iw_hmc_finish_add_sd_reg - program sd entries for objects
- * @dev: pointer to the device structure
- * @info: create obj info
- */
-static enum i40iw_status_code i40iw_hmc_finish_add_sd_reg(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_create_obj_info *info)
-{
- if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt)
- return I40IW_ERR_INVALID_HMC_OBJ_INDEX;
-
- if ((info->start_idx + info->count) >
- info->hmc_info->hmc_obj[info->rsrc_type].cnt)
- return I40IW_ERR_INVALID_HMC_OBJ_COUNT;
-
- if (!info->add_sd_cnt)
- return 0;
-
- return i40iw_hmc_sd_grp(dev, info->hmc_info,
- info->hmc_info->sd_indexes[0],
- info->add_sd_cnt, true);
-}
-
-/**
- * i40iw_sc_create_hmc_obj - allocate backing store for hmc objects
- * @dev: pointer to the device structure
- * @info: pointer to i40iw_hmc_iw_create_obj_info struct
- *
- * This will allocate memory for PDs and backing pages and populate
- * the sd and pd entries.
- */
-enum i40iw_status_code i40iw_sc_create_hmc_obj(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_create_obj_info *info)
-{
- struct i40iw_hmc_sd_entry *sd_entry;
- u32 sd_idx, sd_lmt;
- u32 pd_idx = 0, pd_lmt = 0;
- u32 pd_idx1 = 0, pd_lmt1 = 0;
- u32 i, j;
- bool pd_error = false;
- enum i40iw_status_code ret_code = 0;
-
- if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt)
- return I40IW_ERR_INVALID_HMC_OBJ_INDEX;
-
- if ((info->start_idx + info->count) >
- info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
- i40iw_debug(dev, I40IW_DEBUG_HMC,
- "%s: error type %u, start = %u, req cnt %u, cnt = %u\n",
- __func__, info->rsrc_type, info->start_idx, info->count,
- info->hmc_info->hmc_obj[info->rsrc_type].cnt);
- return I40IW_ERR_INVALID_HMC_OBJ_COUNT;
- }
-
- if (!dev->is_pf)
- return i40iw_vchnl_vf_add_hmc_objs(dev, info->rsrc_type, 0, info->count);
-
- i40iw_find_sd_index_limit(info->hmc_info, info->rsrc_type,
- info->start_idx, info->count,
- &sd_idx, &sd_lmt);
- if (sd_idx >= info->hmc_info->sd_table.sd_cnt ||
- sd_lmt > info->hmc_info->sd_table.sd_cnt) {
- return I40IW_ERR_INVALID_SD_INDEX;
- }
- i40iw_find_pd_index_limit(info->hmc_info, info->rsrc_type,
- info->start_idx, info->count, &pd_idx, &pd_lmt);
-
- for (j = sd_idx; j < sd_lmt; j++) {
- ret_code = i40iw_add_sd_table_entry(dev->hw, info->hmc_info,
- j,
- info->entry_type,
- I40IW_HMC_DIRECT_BP_SIZE);
- if (ret_code)
- goto exit_sd_error;
- sd_entry = &info->hmc_info->sd_table.sd_entry[j];
-
- if ((sd_entry->entry_type == I40IW_SD_TYPE_PAGED) &&
- ((dev->hmc_info == info->hmc_info) &&
- (info->rsrc_type != I40IW_HMC_IW_PBLE))) {
- pd_idx1 = max(pd_idx, (j * I40IW_HMC_MAX_BP_COUNT));
- pd_lmt1 = min(pd_lmt,
- (j + 1) * I40IW_HMC_MAX_BP_COUNT);
- for (i = pd_idx1; i < pd_lmt1; i++) {
- /* update the pd table entry */
- ret_code = i40iw_add_pd_table_entry(dev->hw, info->hmc_info,
- i, NULL);
- if (ret_code) {
- pd_error = true;
- break;
- }
- }
- if (pd_error) {
- while (i && (i > pd_idx1)) {
- i40iw_remove_pd_bp(dev->hw, info->hmc_info, (i - 1),
- info->is_pf);
- i--;
- }
- }
- }
- if (sd_entry->valid)
- continue;
-
- info->hmc_info->sd_indexes[info->add_sd_cnt] = (u16)j;
- info->add_sd_cnt++;
- sd_entry->valid = true;
- }
- return i40iw_hmc_finish_add_sd_reg(dev, info);
-
-exit_sd_error:
- while (j && (j > sd_idx)) {
- sd_entry = &info->hmc_info->sd_table.sd_entry[j - 1];
- switch (sd_entry->entry_type) {
- case I40IW_SD_TYPE_PAGED:
- pd_idx1 = max(pd_idx,
- (j - 1) * I40IW_HMC_MAX_BP_COUNT);
- pd_lmt1 = min(pd_lmt, (j * I40IW_HMC_MAX_BP_COUNT));
- for (i = pd_idx1; i < pd_lmt1; i++)
- i40iw_prep_remove_pd_page(info->hmc_info, i);
- break;
- case I40IW_SD_TYPE_DIRECT:
- i40iw_prep_remove_pd_page(info->hmc_info, (j - 1));
- break;
- default:
- ret_code = I40IW_ERR_INVALID_SD_TYPE;
- break;
- }
- j--;
- }
-
- return ret_code;
-}
-
-/**
- * i40iw_finish_del_sd_reg - delete sd entries for objects
- * @dev: pointer to the device structure
- * @info: dele obj info
- * @reset: true if called before reset
- */
-static enum i40iw_status_code i40iw_finish_del_sd_reg(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_del_obj_info *info,
- bool reset)
-{
- struct i40iw_hmc_sd_entry *sd_entry;
- enum i40iw_status_code ret_code = 0;
- u32 i, sd_idx;
- struct i40iw_dma_mem *mem;
-
- if (dev->is_pf && !reset)
- ret_code = i40iw_hmc_sd_grp(dev, info->hmc_info,
- info->hmc_info->sd_indexes[0],
- info->del_sd_cnt, false);
-
- if (ret_code)
- i40iw_debug(dev, I40IW_DEBUG_HMC, "%s: error cqp sd sd_grp\n", __func__);
-
- for (i = 0; i < info->del_sd_cnt; i++) {
- sd_idx = info->hmc_info->sd_indexes[i];
- sd_entry = &info->hmc_info->sd_table.sd_entry[sd_idx];
- if (!sd_entry)
- continue;
- mem = (sd_entry->entry_type == I40IW_SD_TYPE_PAGED) ?
- &sd_entry->u.pd_table.pd_page_addr :
- &sd_entry->u.bp.addr;
-
- if (!mem || !mem->va)
- i40iw_debug(dev, I40IW_DEBUG_HMC, "%s: error cqp sd mem\n", __func__);
- else
- i40iw_free_dma_mem(dev->hw, mem);
- }
- return ret_code;
-}
-
-/**
- * i40iw_sc_del_hmc_obj - remove pe hmc objects
- * @dev: pointer to the device structure
- * @info: pointer to i40iw_hmc_del_obj_info struct
- * @reset: true if called before reset
- *
- * This will de-populate the SDs and PDs. It frees
- * the memory for PDS and backing storage. After this function is returned,
- * caller should deallocate memory allocated previously for
- * book-keeping information about PDs and backing storage.
- */
-enum i40iw_status_code i40iw_sc_del_hmc_obj(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_del_obj_info *info,
- bool reset)
-{
- struct i40iw_hmc_pd_table *pd_table;
- u32 sd_idx, sd_lmt;
- u32 pd_idx, pd_lmt, rel_pd_idx;
- u32 i, j;
- enum i40iw_status_code ret_code = 0;
-
- if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
- i40iw_debug(dev, I40IW_DEBUG_HMC,
- "%s: error start_idx[%04d] >= [type %04d].cnt[%04d]\n",
- __func__, info->start_idx, info->rsrc_type,
- info->hmc_info->hmc_obj[info->rsrc_type].cnt);
- return I40IW_ERR_INVALID_HMC_OBJ_INDEX;
- }
-
- if ((info->start_idx + info->count) >
- info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
- i40iw_debug(dev, I40IW_DEBUG_HMC,
- "%s: error start_idx[%04d] + count %04d >= [type %04d].cnt[%04d]\n",
- __func__, info->start_idx, info->count,
- info->rsrc_type,
- info->hmc_info->hmc_obj[info->rsrc_type].cnt);
- return I40IW_ERR_INVALID_HMC_OBJ_COUNT;
- }
- if (!dev->is_pf) {
- ret_code = i40iw_vchnl_vf_del_hmc_obj(dev, info->rsrc_type, 0,
- info->count);
- if (info->rsrc_type != I40IW_HMC_IW_PBLE)
- return ret_code;
- }
-
- i40iw_find_pd_index_limit(info->hmc_info, info->rsrc_type,
- info->start_idx, info->count, &pd_idx, &pd_lmt);
-
- for (j = pd_idx; j < pd_lmt; j++) {
- sd_idx = j / I40IW_HMC_PD_CNT_IN_SD;
-
- if (info->hmc_info->sd_table.sd_entry[sd_idx].entry_type !=
- I40IW_SD_TYPE_PAGED)
- continue;
-
- rel_pd_idx = j % I40IW_HMC_PD_CNT_IN_SD;
- pd_table = &info->hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
- if (pd_table->pd_entry[rel_pd_idx].valid) {
- ret_code = i40iw_remove_pd_bp(dev->hw, info->hmc_info, j,
- info->is_pf);
- if (ret_code) {
- i40iw_debug(dev, I40IW_DEBUG_HMC, "%s: error\n", __func__);
- return ret_code;
- }
- }
- }
-
- i40iw_find_sd_index_limit(info->hmc_info, info->rsrc_type,
- info->start_idx, info->count, &sd_idx, &sd_lmt);
- if (sd_idx >= info->hmc_info->sd_table.sd_cnt ||
- sd_lmt > info->hmc_info->sd_table.sd_cnt) {
- i40iw_debug(dev, I40IW_DEBUG_HMC, "%s: error invalid sd_idx\n", __func__);
- return I40IW_ERR_INVALID_SD_INDEX;
- }
-
- for (i = sd_idx; i < sd_lmt; i++) {
- if (!info->hmc_info->sd_table.sd_entry[i].valid)
- continue;
- switch (info->hmc_info->sd_table.sd_entry[i].entry_type) {
- case I40IW_SD_TYPE_DIRECT:
- ret_code = i40iw_prep_remove_sd_bp(info->hmc_info, i);
- if (!ret_code) {
- info->hmc_info->sd_indexes[info->del_sd_cnt] = (u16)i;
- info->del_sd_cnt++;
- }
- break;
- case I40IW_SD_TYPE_PAGED:
- ret_code = i40iw_prep_remove_pd_page(info->hmc_info, i);
- if (!ret_code) {
- info->hmc_info->sd_indexes[info->del_sd_cnt] = (u16)i;
- info->del_sd_cnt++;
- }
- break;
- default:
- break;
- }
- }
- return i40iw_finish_del_sd_reg(dev, info, reset);
-}
-
-/**
- * i40iw_add_sd_table_entry - Adds a segment descriptor to the table
- * @hw: pointer to our hw struct
- * @hmc_info: pointer to the HMC configuration information struct
- * @sd_index: segment descriptor index to manipulate
- * @type: what type of segment descriptor we're manipulating
- * @direct_mode_sz: size to alloc in direct mode
- */
-enum i40iw_status_code i40iw_add_sd_table_entry(struct i40iw_hw *hw,
- struct i40iw_hmc_info *hmc_info,
- u32 sd_index,
- enum i40iw_sd_entry_type type,
- u64 direct_mode_sz)
-{
- enum i40iw_status_code ret_code = 0;
- struct i40iw_hmc_sd_entry *sd_entry;
- bool dma_mem_alloc_done = false;
- struct i40iw_dma_mem mem;
- u64 alloc_len;
-
- sd_entry = &hmc_info->sd_table.sd_entry[sd_index];
- if (!sd_entry->valid) {
- if (type == I40IW_SD_TYPE_PAGED)
- alloc_len = I40IW_HMC_PAGED_BP_SIZE;
- else
- alloc_len = direct_mode_sz;
-
- /* allocate a 4K pd page or 2M backing page */
- ret_code = i40iw_allocate_dma_mem(hw, &mem, alloc_len,
- I40IW_HMC_PD_BP_BUF_ALIGNMENT);
- if (ret_code)
- goto exit;
- dma_mem_alloc_done = true;
- if (type == I40IW_SD_TYPE_PAGED) {
- ret_code = i40iw_allocate_virt_mem(hw,
- &sd_entry->u.pd_table.pd_entry_virt_mem,
- sizeof(struct i40iw_hmc_pd_entry) * 512);
- if (ret_code)
- goto exit;
- sd_entry->u.pd_table.pd_entry = (struct i40iw_hmc_pd_entry *)
- sd_entry->u.pd_table.pd_entry_virt_mem.va;
-
- memcpy(&sd_entry->u.pd_table.pd_page_addr, &mem, sizeof(struct i40iw_dma_mem));
- } else {
- memcpy(&sd_entry->u.bp.addr, &mem, sizeof(struct i40iw_dma_mem));
- sd_entry->u.bp.sd_pd_index = sd_index;
- }
-
- hmc_info->sd_table.sd_entry[sd_index].entry_type = type;
-
- I40IW_INC_SD_REFCNT(&hmc_info->sd_table);
- }
- if (sd_entry->entry_type == I40IW_SD_TYPE_DIRECT)
- I40IW_INC_BP_REFCNT(&sd_entry->u.bp);
-exit:
- if (ret_code)
- if (dma_mem_alloc_done)
- i40iw_free_dma_mem(hw, &mem);
-
- return ret_code;
-}
-
-/**
- * i40iw_add_pd_table_entry - Adds page descriptor to the specified table
- * @hw: pointer to our HW structure
- * @hmc_info: pointer to the HMC configuration information structure
- * @pd_index: which page descriptor index to manipulate
- * @rsrc_pg: if not NULL, use preallocated page instead of allocating new one.
- *
- * This function:
- * 1. Initializes the pd entry
- * 2. Adds pd_entry in the pd_table
- * 3. Mark the entry valid in i40iw_hmc_pd_entry structure
- * 4. Initializes the pd_entry's ref count to 1
- * assumptions:
- * 1. The memory for pd should be pinned down, physically contiguous and
- * aligned on 4K boundary and zeroed memory.
- * 2. It should be 4K in size.
- */
-enum i40iw_status_code i40iw_add_pd_table_entry(struct i40iw_hw *hw,
- struct i40iw_hmc_info *hmc_info,
- u32 pd_index,
- struct i40iw_dma_mem *rsrc_pg)
-{
- enum i40iw_status_code ret_code = 0;
- struct i40iw_hmc_pd_table *pd_table;
- struct i40iw_hmc_pd_entry *pd_entry;
- struct i40iw_dma_mem mem;
- struct i40iw_dma_mem *page = &mem;
- u32 sd_idx, rel_pd_idx;
- u64 *pd_addr;
- u64 page_desc;
-
- if (pd_index / I40IW_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt)
- return I40IW_ERR_INVALID_PAGE_DESC_INDEX;
-
- sd_idx = (pd_index / I40IW_HMC_PD_CNT_IN_SD);
- if (hmc_info->sd_table.sd_entry[sd_idx].entry_type != I40IW_SD_TYPE_PAGED)
- return 0;
-
- rel_pd_idx = (pd_index % I40IW_HMC_PD_CNT_IN_SD);
- pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
- pd_entry = &pd_table->pd_entry[rel_pd_idx];
- if (!pd_entry->valid) {
- if (rsrc_pg) {
- pd_entry->rsrc_pg = true;
- page = rsrc_pg;
- } else {
- ret_code = i40iw_allocate_dma_mem(hw, page,
- I40IW_HMC_PAGED_BP_SIZE,
- I40IW_HMC_PD_BP_BUF_ALIGNMENT);
- if (ret_code)
- return ret_code;
- pd_entry->rsrc_pg = false;
- }
-
- memcpy(&pd_entry->bp.addr, page, sizeof(struct i40iw_dma_mem));
- pd_entry->bp.sd_pd_index = pd_index;
- pd_entry->bp.entry_type = I40IW_SD_TYPE_PAGED;
- page_desc = page->pa | 0x1;
-
- pd_addr = (u64 *)pd_table->pd_page_addr.va;
- pd_addr += rel_pd_idx;
-
- memcpy(pd_addr, &page_desc, sizeof(*pd_addr));
-
- pd_entry->sd_index = sd_idx;
- pd_entry->valid = true;
- I40IW_INC_PD_REFCNT(pd_table);
- if (hmc_info->hmc_fn_id < I40IW_FIRST_VF_FPM_ID)
- I40IW_INVALIDATE_PF_HMC_PD(hw, sd_idx, rel_pd_idx);
- else if (hw->hmc.hmc_fn_id != hmc_info->hmc_fn_id)
- I40IW_INVALIDATE_VF_HMC_PD(hw, sd_idx, rel_pd_idx,
- hmc_info->hmc_fn_id);
- }
- I40IW_INC_BP_REFCNT(&pd_entry->bp);
-
- return 0;
-}
-
-/**
- * i40iw_remove_pd_bp - remove a backing page from a page descriptor
- * @hw: pointer to our HW structure
- * @hmc_info: pointer to the HMC configuration information structure
- * @idx: the page index
- * @is_pf: distinguishes a VF from a PF
- *
- * This function:
- * 1. Marks the entry in pd table (for paged address mode) or in sd table
- * (for direct address mode) invalid.
- * 2. Write to register PMPDINV to invalidate the backing page in FV cache
- * 3. Decrement the ref count for the pd _entry
- * assumptions:
- * 1. Caller can deallocate the memory used by backing storage after this
- * function returns.
- */
-enum i40iw_status_code i40iw_remove_pd_bp(struct i40iw_hw *hw,
- struct i40iw_hmc_info *hmc_info,
- u32 idx,
- bool is_pf)
-{
- struct i40iw_hmc_pd_entry *pd_entry;
- struct i40iw_hmc_pd_table *pd_table;
- struct i40iw_hmc_sd_entry *sd_entry;
- u32 sd_idx, rel_pd_idx;
- struct i40iw_dma_mem *mem;
- u64 *pd_addr;
-
- sd_idx = idx / I40IW_HMC_PD_CNT_IN_SD;
- rel_pd_idx = idx % I40IW_HMC_PD_CNT_IN_SD;
- if (sd_idx >= hmc_info->sd_table.sd_cnt)
- return I40IW_ERR_INVALID_PAGE_DESC_INDEX;
-
- sd_entry = &hmc_info->sd_table.sd_entry[sd_idx];
- if (sd_entry->entry_type != I40IW_SD_TYPE_PAGED)
- return I40IW_ERR_INVALID_SD_TYPE;
-
- pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
- pd_entry = &pd_table->pd_entry[rel_pd_idx];
- I40IW_DEC_BP_REFCNT(&pd_entry->bp);
- if (pd_entry->bp.ref_cnt)
- return 0;
-
- pd_entry->valid = false;
- I40IW_DEC_PD_REFCNT(pd_table);
- pd_addr = (u64 *)pd_table->pd_page_addr.va;
- pd_addr += rel_pd_idx;
- memset(pd_addr, 0, sizeof(u64));
- if (is_pf)
- I40IW_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx);
- else
- I40IW_INVALIDATE_VF_HMC_PD(hw, sd_idx, idx,
- hmc_info->hmc_fn_id);
-
- if (!pd_entry->rsrc_pg) {
- mem = &pd_entry->bp.addr;
- if (!mem || !mem->va)
- return I40IW_ERR_PARAM;
- i40iw_free_dma_mem(hw, mem);
- }
- if (!pd_table->ref_cnt)
- i40iw_free_virt_mem(hw, &pd_table->pd_entry_virt_mem);
-
- return 0;
-}
-
-/**
- * i40iw_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry
- * @hmc_info: pointer to the HMC configuration information structure
- * @idx: the page index
- */
-enum i40iw_status_code i40iw_prep_remove_sd_bp(struct i40iw_hmc_info *hmc_info, u32 idx)
-{
- struct i40iw_hmc_sd_entry *sd_entry;
-
- sd_entry = &hmc_info->sd_table.sd_entry[idx];
- I40IW_DEC_BP_REFCNT(&sd_entry->u.bp);
- if (sd_entry->u.bp.ref_cnt)
- return I40IW_ERR_NOT_READY;
-
- I40IW_DEC_SD_REFCNT(&hmc_info->sd_table);
- sd_entry->valid = false;
-
- return 0;
-}
-
-/**
- * i40iw_prep_remove_pd_page - Prepares to remove a PD page from sd entry.
- * @hmc_info: pointer to the HMC configuration information structure
- * @idx: segment descriptor index to find the relevant page descriptor
- */
-enum i40iw_status_code i40iw_prep_remove_pd_page(struct i40iw_hmc_info *hmc_info,
- u32 idx)
-{
- struct i40iw_hmc_sd_entry *sd_entry;
-
- sd_entry = &hmc_info->sd_table.sd_entry[idx];
-
- if (sd_entry->u.pd_table.ref_cnt)
- return I40IW_ERR_NOT_READY;
-
- sd_entry->valid = false;
- I40IW_DEC_SD_REFCNT(&hmc_info->sd_table);
-
- return 0;
-}
-
-/**
- * i40iw_pf_init_vfhmc -
- * @vf_cnt_array: array of cnt values of iwarp hmc objects
- * @vf_hmc_fn_id: hmc function id ofr vf driver
- * @dev: pointer to i40iw_dev struct
- *
- * Called by pf driver to initialize hmc_info for vf driver instance.
- */
-enum i40iw_status_code i40iw_pf_init_vfhmc(struct i40iw_sc_dev *dev,
- u8 vf_hmc_fn_id,
- u32 *vf_cnt_array)
-{
- struct i40iw_hmc_info *hmc_info;
- enum i40iw_status_code ret_code = 0;
- u32 i;
-
- if ((vf_hmc_fn_id < I40IW_FIRST_VF_FPM_ID) ||
- (vf_hmc_fn_id >= I40IW_FIRST_VF_FPM_ID +
- I40IW_MAX_PE_ENABLED_VF_COUNT)) {
- i40iw_debug(dev, I40IW_DEBUG_HMC, "%s: invalid vf_hmc_fn_id 0x%x\n",
- __func__, vf_hmc_fn_id);
- return I40IW_ERR_INVALID_HMCFN_ID;
- }
-
- ret_code = i40iw_sc_init_iw_hmc(dev, vf_hmc_fn_id);
- if (ret_code)
- return ret_code;
-
- hmc_info = i40iw_vf_hmcinfo_from_fpm(dev, vf_hmc_fn_id);
-
- for (i = I40IW_HMC_IW_QP; i < I40IW_HMC_IW_MAX; i++)
- if (vf_cnt_array)
- hmc_info->hmc_obj[i].cnt =
- vf_cnt_array[i - I40IW_HMC_IW_QP];
- else
- hmc_info->hmc_obj[i].cnt = hmc_info->hmc_obj[i].max_cnt;
-
- return 0;
-}
diff --git a/drivers/infiniband/hw/i40iw/i40iw_hmc.h b/drivers/infiniband/hw/i40iw/i40iw_hmc.h
deleted file mode 100644
index 4c3fdd875621..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_hmc.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_HMC_H
-#define I40IW_HMC_H
-
-#include "i40iw_d.h"
-
-struct i40iw_hw;
-enum i40iw_status_code;
-
-#define I40IW_HMC_MAX_BP_COUNT 512
-#define I40IW_MAX_SD_ENTRIES 11
-#define I40IW_HW_DBG_HMC_INVALID_BP_MARK 0xCA
-
-#define I40IW_HMC_INFO_SIGNATURE 0x484D5347
-#define I40IW_HMC_PD_CNT_IN_SD 512
-#define I40IW_HMC_DIRECT_BP_SIZE 0x200000
-#define I40IW_HMC_MAX_SD_COUNT 4096
-#define I40IW_HMC_PAGED_BP_SIZE 4096
-#define I40IW_HMC_PD_BP_BUF_ALIGNMENT 4096
-#define I40IW_FIRST_VF_FPM_ID 16
-#define FPM_MULTIPLIER 1024
-
-#define I40IW_INC_SD_REFCNT(sd_table) ((sd_table)->ref_cnt++)
-#define I40IW_INC_PD_REFCNT(pd_table) ((pd_table)->ref_cnt++)
-#define I40IW_INC_BP_REFCNT(bp) ((bp)->ref_cnt++)
-
-#define I40IW_DEC_SD_REFCNT(sd_table) ((sd_table)->ref_cnt--)
-#define I40IW_DEC_PD_REFCNT(pd_table) ((pd_table)->ref_cnt--)
-#define I40IW_DEC_BP_REFCNT(bp) ((bp)->ref_cnt--)
-
-/**
- * I40IW_INVALIDATE_PF_HMC_PD - Invalidates the pd cache in the hardware
- * @hw: pointer to our hw struct
- * @sd_idx: segment descriptor index
- * @pd_idx: page descriptor index
- */
-#define I40IW_INVALIDATE_PF_HMC_PD(hw, sd_idx, pd_idx) \
- i40iw_wr32((hw), I40E_PFHMC_PDINV, \
- (((sd_idx) << I40E_PFHMC_PDINV_PMSDIDX_SHIFT) | \
- (0x1 << I40E_PFHMC_PDINV_PMSDPARTSEL_SHIFT) | \
- ((pd_idx) << I40E_PFHMC_PDINV_PMPDIDX_SHIFT)))
-
-/**
- * I40IW_INVALIDATE_VF_HMC_PD - Invalidates the pd cache in the hardware
- * @hw: pointer to our hw struct
- * @sd_idx: segment descriptor index
- * @pd_idx: page descriptor index
- * @hmc_fn_id: VF's function id
- */
-#define I40IW_INVALIDATE_VF_HMC_PD(hw, sd_idx, pd_idx, hmc_fn_id) \
- i40iw_wr32(hw, I40E_GLHMC_VFPDINV(hmc_fn_id - I40IW_FIRST_VF_FPM_ID), \
- ((sd_idx << I40E_PFHMC_PDINV_PMSDIDX_SHIFT) | \
- (pd_idx << I40E_PFHMC_PDINV_PMPDIDX_SHIFT)))
-
-struct i40iw_hmc_obj_info {
- u64 base;
- u32 max_cnt;
- u32 cnt;
- u64 size;
-};
-
-enum i40iw_sd_entry_type {
- I40IW_SD_TYPE_INVALID = 0,
- I40IW_SD_TYPE_PAGED = 1,
- I40IW_SD_TYPE_DIRECT = 2
-};
-
-struct i40iw_hmc_bp {
- enum i40iw_sd_entry_type entry_type;
- struct i40iw_dma_mem addr;
- u32 sd_pd_index;
- u32 ref_cnt;
-};
-
-struct i40iw_hmc_pd_entry {
- struct i40iw_hmc_bp bp;
- u32 sd_index;
- bool rsrc_pg;
- bool valid;
-};
-
-struct i40iw_hmc_pd_table {
- struct i40iw_dma_mem pd_page_addr;
- struct i40iw_hmc_pd_entry *pd_entry;
- struct i40iw_virt_mem pd_entry_virt_mem;
- u32 ref_cnt;
- u32 sd_index;
-};
-
-struct i40iw_hmc_sd_entry {
- enum i40iw_sd_entry_type entry_type;
- bool valid;
-
- union {
- struct i40iw_hmc_pd_table pd_table;
- struct i40iw_hmc_bp bp;
- } u;
-};
-
-struct i40iw_hmc_sd_table {
- struct i40iw_virt_mem addr;
- u32 sd_cnt;
- u32 ref_cnt;
- struct i40iw_hmc_sd_entry *sd_entry;
-};
-
-struct i40iw_hmc_info {
- u32 signature;
- u8 hmc_fn_id;
- u16 first_sd_index;
-
- struct i40iw_hmc_obj_info *hmc_obj;
- struct i40iw_virt_mem hmc_obj_virt_mem;
- struct i40iw_hmc_sd_table sd_table;
- u16 sd_indexes[I40IW_HMC_MAX_SD_COUNT];
-};
-
-struct update_sd_entry {
- u64 cmd;
- u64 data;
-};
-
-struct i40iw_update_sds_info {
- u32 cnt;
- u8 hmc_fn_id;
- struct update_sd_entry entry[I40IW_MAX_SD_ENTRIES];
-};
-
-struct i40iw_ccq_cqe_info;
-struct i40iw_hmc_fcn_info {
- void (*callback_fcn)(struct i40iw_sc_dev *, void *,
- struct i40iw_ccq_cqe_info *);
- void *cqp_callback_param;
- u32 vf_id;
- u16 iw_vf_idx;
- bool free_fcn;
-};
-
-enum i40iw_hmc_rsrc_type {
- I40IW_HMC_IW_QP = 0,
- I40IW_HMC_IW_CQ = 1,
- I40IW_HMC_IW_SRQ = 2,
- I40IW_HMC_IW_HTE = 3,
- I40IW_HMC_IW_ARP = 4,
- I40IW_HMC_IW_APBVT_ENTRY = 5,
- I40IW_HMC_IW_MR = 6,
- I40IW_HMC_IW_XF = 7,
- I40IW_HMC_IW_XFFL = 8,
- I40IW_HMC_IW_Q1 = 9,
- I40IW_HMC_IW_Q1FL = 10,
- I40IW_HMC_IW_TIMER = 11,
- I40IW_HMC_IW_FSIMC = 12,
- I40IW_HMC_IW_FSIAV = 13,
- I40IW_HMC_IW_PBLE = 14,
- I40IW_HMC_IW_MAX = 15,
-};
-
-struct i40iw_hmc_create_obj_info {
- struct i40iw_hmc_info *hmc_info;
- struct i40iw_virt_mem add_sd_virt_mem;
- u32 rsrc_type;
- u32 start_idx;
- u32 count;
- u32 add_sd_cnt;
- enum i40iw_sd_entry_type entry_type;
- bool is_pf;
-};
-
-struct i40iw_hmc_del_obj_info {
- struct i40iw_hmc_info *hmc_info;
- struct i40iw_virt_mem del_sd_virt_mem;
- u32 rsrc_type;
- u32 start_idx;
- u32 count;
- u32 del_sd_cnt;
- bool is_pf;
-};
-
-enum i40iw_status_code i40iw_copy_dma_mem(struct i40iw_hw *hw, void *dest_buf,
- struct i40iw_dma_mem *src_mem, u64 src_offset, u64 size);
-enum i40iw_status_code i40iw_sc_create_hmc_obj(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_create_obj_info *info);
-enum i40iw_status_code i40iw_sc_del_hmc_obj(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_del_obj_info *info,
- bool reset);
-enum i40iw_status_code i40iw_hmc_sd_one(struct i40iw_sc_dev *dev, u8 hmc_fn_id,
- u64 pa, u32 sd_idx, enum i40iw_sd_entry_type type,
- bool setsd);
-enum i40iw_status_code i40iw_update_sds_noccq(struct i40iw_sc_dev *dev,
- struct i40iw_update_sds_info *info);
-struct i40iw_vfdev *i40iw_vfdev_from_fpm(struct i40iw_sc_dev *dev, u8 hmc_fn_id);
-struct i40iw_hmc_info *i40iw_vf_hmcinfo_from_fpm(struct i40iw_sc_dev *dev,
- u8 hmc_fn_id);
-enum i40iw_status_code i40iw_add_sd_table_entry(struct i40iw_hw *hw,
- struct i40iw_hmc_info *hmc_info, u32 sd_index,
- enum i40iw_sd_entry_type type, u64 direct_mode_sz);
-enum i40iw_status_code i40iw_add_pd_table_entry(struct i40iw_hw *hw,
- struct i40iw_hmc_info *hmc_info, u32 pd_index,
- struct i40iw_dma_mem *rsrc_pg);
-enum i40iw_status_code i40iw_remove_pd_bp(struct i40iw_hw *hw,
- struct i40iw_hmc_info *hmc_info, u32 idx, bool is_pf);
-enum i40iw_status_code i40iw_prep_remove_sd_bp(struct i40iw_hmc_info *hmc_info, u32 idx);
-enum i40iw_status_code i40iw_prep_remove_pd_page(struct i40iw_hmc_info *hmc_info, u32 idx);
-
-#define ENTER_SHARED_FUNCTION()
-#define EXIT_SHARED_FUNCTION()
-
-#endif /* I40IW_HMC_H */
diff --git a/drivers/infiniband/hw/i40iw/i40iw_hw.c b/drivers/infiniband/hw/i40iw/i40iw_hw.c
deleted file mode 100644
index d167ac10c751..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_hw.c
+++ /dev/null
@@ -1,851 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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_vlan.h>
-
-#include "i40iw.h"
-
-/**
- * i40iw_initialize_hw_resources - initialize hw resource during open
- * @iwdev: iwarp device
- */
-u32 i40iw_initialize_hw_resources(struct i40iw_device *iwdev)
-{
- unsigned long num_pds;
- u32 resources_size;
- u32 max_mr;
- u32 max_qp;
- u32 max_cq;
- u32 arp_table_size;
- u32 mrdrvbits;
- void *resource_ptr;
-
- max_qp = iwdev->sc_dev.hmc_info->hmc_obj[I40IW_HMC_IW_QP].cnt;
- max_cq = iwdev->sc_dev.hmc_info->hmc_obj[I40IW_HMC_IW_CQ].cnt;
- max_mr = iwdev->sc_dev.hmc_info->hmc_obj[I40IW_HMC_IW_MR].cnt;
- arp_table_size = iwdev->sc_dev.hmc_info->hmc_obj[I40IW_HMC_IW_ARP].cnt;
- iwdev->max_cqe = 0xFFFFF;
- num_pds = I40IW_MAX_PDS;
- resources_size = sizeof(struct i40iw_arp_entry) * arp_table_size;
- resources_size += sizeof(unsigned long) * BITS_TO_LONGS(max_qp);
- resources_size += sizeof(unsigned long) * BITS_TO_LONGS(max_mr);
- resources_size += sizeof(unsigned long) * BITS_TO_LONGS(max_cq);
- resources_size += sizeof(unsigned long) * BITS_TO_LONGS(num_pds);
- resources_size += sizeof(unsigned long) * BITS_TO_LONGS(arp_table_size);
- resources_size += sizeof(struct i40iw_qp **) * max_qp;
- iwdev->mem_resources = kzalloc(resources_size, GFP_KERNEL);
-
- if (!iwdev->mem_resources)
- return -ENOMEM;
-
- iwdev->max_qp = max_qp;
- iwdev->max_mr = max_mr;
- iwdev->max_cq = max_cq;
- iwdev->max_pd = num_pds;
- iwdev->arp_table_size = arp_table_size;
- iwdev->arp_table = (struct i40iw_arp_entry *)iwdev->mem_resources;
- resource_ptr = iwdev->mem_resources + (sizeof(struct i40iw_arp_entry) * arp_table_size);
-
- iwdev->device_cap_flags = IB_DEVICE_LOCAL_DMA_LKEY |
- IB_DEVICE_MEM_WINDOW | IB_DEVICE_MEM_MGT_EXTENSIONS;
-
- iwdev->allocated_qps = resource_ptr;
- iwdev->allocated_cqs = &iwdev->allocated_qps[BITS_TO_LONGS(max_qp)];
- iwdev->allocated_mrs = &iwdev->allocated_cqs[BITS_TO_LONGS(max_cq)];
- iwdev->allocated_pds = &iwdev->allocated_mrs[BITS_TO_LONGS(max_mr)];
- iwdev->allocated_arps = &iwdev->allocated_pds[BITS_TO_LONGS(num_pds)];
- iwdev->qp_table = (struct i40iw_qp **)(&iwdev->allocated_arps[BITS_TO_LONGS(arp_table_size)]);
- set_bit(0, iwdev->allocated_mrs);
- set_bit(0, iwdev->allocated_qps);
- set_bit(0, iwdev->allocated_cqs);
- set_bit(0, iwdev->allocated_pds);
- set_bit(0, iwdev->allocated_arps);
-
- /* Following for ILQ/IEQ */
- set_bit(1, iwdev->allocated_qps);
- set_bit(1, iwdev->allocated_cqs);
- set_bit(1, iwdev->allocated_pds);
- set_bit(2, iwdev->allocated_cqs);
- set_bit(2, iwdev->allocated_pds);
-
- spin_lock_init(&iwdev->resource_lock);
- spin_lock_init(&iwdev->qptable_lock);
- /* stag index mask has a minimum of 14 bits */
- mrdrvbits = 24 - max(get_count_order(iwdev->max_mr), 14);
- iwdev->mr_stagmask = ~(((1 << mrdrvbits) - 1) << (32 - mrdrvbits));
- return 0;
-}
-
-/**
- * i40iw_cqp_ce_handler - handle cqp completions
- * @iwdev: iwarp device
- * @arm: flag to arm after completions
- * @cq: cq for cqp completions
- */
-static void i40iw_cqp_ce_handler(struct i40iw_device *iwdev, struct i40iw_sc_cq *cq, bool arm)
-{
- struct i40iw_cqp_request *cqp_request;
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- u32 cqe_count = 0;
- struct i40iw_ccq_cqe_info info;
- int ret;
-
- do {
- memset(&info, 0, sizeof(info));
- ret = dev->ccq_ops->ccq_get_cqe_info(cq, &info);
- if (ret)
- break;
- cqp_request = (struct i40iw_cqp_request *)(unsigned long)info.scratch;
- if (info.error)
- i40iw_pr_err("opcode = 0x%x maj_err_code = 0x%x min_err_code = 0x%x\n",
- info.op_code, info.maj_err_code, info.min_err_code);
- if (cqp_request) {
- cqp_request->compl_info.maj_err_code = info.maj_err_code;
- cqp_request->compl_info.min_err_code = info.min_err_code;
- cqp_request->compl_info.op_ret_val = info.op_ret_val;
- cqp_request->compl_info.error = info.error;
-
- if (cqp_request->waiting) {
- cqp_request->request_done = true;
- wake_up(&cqp_request->waitq);
- i40iw_put_cqp_request(&iwdev->cqp, cqp_request);
- } else {
- if (cqp_request->callback_fcn)
- cqp_request->callback_fcn(cqp_request, 1);
- i40iw_put_cqp_request(&iwdev->cqp, cqp_request);
- }
- }
-
- cqe_count++;
- } while (1);
-
- if (arm && cqe_count) {
- i40iw_process_bh(dev);
- dev->ccq_ops->ccq_arm(cq);
- }
-}
-
-/**
- * i40iw_iwarp_ce_handler - handle iwarp completions
- * @iwdev: iwarp device
- * @iwcq: iwarp cq receiving event
- */
-static void i40iw_iwarp_ce_handler(struct i40iw_device *iwdev,
- struct i40iw_sc_cq *iwcq)
-{
- struct i40iw_cq *i40iwcq = iwcq->back_cq;
-
- if (i40iwcq->ibcq.comp_handler)
- i40iwcq->ibcq.comp_handler(&i40iwcq->ibcq,
- i40iwcq->ibcq.cq_context);
-}
-
-/**
- * i40iw_puda_ce_handler - handle puda completion events
- * @iwdev: iwarp device
- * @cq: puda completion q for event
- */
-static void i40iw_puda_ce_handler(struct i40iw_device *iwdev,
- struct i40iw_sc_cq *cq)
-{
- struct i40iw_sc_dev *dev = (struct i40iw_sc_dev *)&iwdev->sc_dev;
- enum i40iw_status_code status;
- u32 compl_error;
-
- do {
- status = i40iw_puda_poll_completion(dev, cq, &compl_error);
- if (status == I40IW_ERR_QUEUE_EMPTY)
- break;
- if (status) {
- i40iw_pr_err("puda status = %d\n", status);
- break;
- }
- if (compl_error) {
- i40iw_pr_err("puda compl_err =0x%x\n", compl_error);
- break;
- }
- } while (1);
-
- dev->ccq_ops->ccq_arm(cq);
-}
-
-/**
- * i40iw_process_ceq - handle ceq for completions
- * @iwdev: iwarp device
- * @ceq: ceq having cq for completion
- */
-void i40iw_process_ceq(struct i40iw_device *iwdev, struct i40iw_ceq *ceq)
-{
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_sc_ceq *sc_ceq;
- struct i40iw_sc_cq *cq;
- bool arm = true;
-
- sc_ceq = &ceq->sc_ceq;
- do {
- cq = dev->ceq_ops->process_ceq(dev, sc_ceq);
- if (!cq)
- break;
-
- if (cq->cq_type == I40IW_CQ_TYPE_CQP)
- i40iw_cqp_ce_handler(iwdev, cq, arm);
- else if (cq->cq_type == I40IW_CQ_TYPE_IWARP)
- i40iw_iwarp_ce_handler(iwdev, cq);
- else if ((cq->cq_type == I40IW_CQ_TYPE_ILQ) ||
- (cq->cq_type == I40IW_CQ_TYPE_IEQ))
- i40iw_puda_ce_handler(iwdev, cq);
- } while (1);
-}
-
-/**
- * i40iw_next_iw_state - modify qp state
- * @iwqp: iwarp qp to modify
- * @state: next state for qp
- * @del_hash: del hash
- * @term: term message
- * @termlen: length of term message
- */
-void i40iw_next_iw_state(struct i40iw_qp *iwqp,
- u8 state,
- u8 del_hash,
- u8 term,
- u8 termlen)
-{
- struct i40iw_modify_qp_info info;
-
- memset(&info, 0, sizeof(info));
- info.next_iwarp_state = state;
- info.remove_hash_idx = del_hash;
- info.cq_num_valid = true;
- info.arp_cache_idx_valid = true;
- info.dont_send_term = true;
- info.dont_send_fin = true;
- info.termlen = termlen;
-
- if (term & I40IWQP_TERM_SEND_TERM_ONLY)
- info.dont_send_term = false;
- if (term & I40IWQP_TERM_SEND_FIN_ONLY)
- info.dont_send_fin = false;
- if (iwqp->sc_qp.term_flags && (state == I40IW_QP_STATE_ERROR))
- info.reset_tcp_conn = true;
- iwqp->hw_iwarp_state = state;
- i40iw_hw_modify_qp(iwqp->iwdev, iwqp, &info, 0);
-}
-
-/**
- * i40iw_process_aeq - handle aeq events
- * @iwdev: iwarp device
- */
-void i40iw_process_aeq(struct i40iw_device *iwdev)
-{
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_aeq *aeq = &iwdev->aeq;
- struct i40iw_sc_aeq *sc_aeq = &aeq->sc_aeq;
- struct i40iw_aeqe_info aeinfo;
- struct i40iw_aeqe_info *info = &aeinfo;
- int ret;
- struct i40iw_qp *iwqp = NULL;
- struct i40iw_sc_cq *cq = NULL;
- struct i40iw_cq *iwcq = NULL;
- struct i40iw_sc_qp *qp = NULL;
- struct i40iw_qp_host_ctx_info *ctx_info = NULL;
- unsigned long flags;
-
- u32 aeqcnt = 0;
-
- if (!sc_aeq->size)
- return;
-
- do {
- memset(info, 0, sizeof(*info));
- ret = dev->aeq_ops->get_next_aeqe(sc_aeq, info);
- if (ret)
- break;
-
- aeqcnt++;
- i40iw_debug(dev, I40IW_DEBUG_AEQ,
- "%s ae_id = 0x%x bool qp=%d qp_id = %d\n",
- __func__, info->ae_id, info->qp, info->qp_cq_id);
- if (info->qp) {
- spin_lock_irqsave(&iwdev->qptable_lock, flags);
- iwqp = iwdev->qp_table[info->qp_cq_id];
- if (!iwqp) {
- spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
- i40iw_debug(dev, I40IW_DEBUG_AEQ,
- "%s qp_id %d is already freed\n",
- __func__, info->qp_cq_id);
- continue;
- }
- i40iw_qp_add_ref(&iwqp->ibqp);
- spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
- qp = &iwqp->sc_qp;
- spin_lock_irqsave(&iwqp->lock, flags);
- iwqp->hw_tcp_state = info->tcp_state;
- iwqp->hw_iwarp_state = info->iwarp_state;
- iwqp->last_aeq = info->ae_id;
- spin_unlock_irqrestore(&iwqp->lock, flags);
- ctx_info = &iwqp->ctx_info;
- ctx_info->err_rq_idx_valid = true;
- } else {
- if (info->ae_id != I40IW_AE_CQ_OPERATION_ERROR)
- continue;
- }
-
- switch (info->ae_id) {
- case I40IW_AE_LLP_FIN_RECEIVED:
- if (qp->term_flags)
- break;
- if (atomic_inc_return(&iwqp->close_timer_started) == 1) {
- iwqp->hw_tcp_state = I40IW_TCP_STATE_CLOSE_WAIT;
- if ((iwqp->hw_tcp_state == I40IW_TCP_STATE_CLOSE_WAIT) &&
- (iwqp->ibqp_state == IB_QPS_RTS)) {
- i40iw_next_iw_state(iwqp,
- I40IW_QP_STATE_CLOSING, 0, 0, 0);
- i40iw_cm_disconn(iwqp);
- }
- iwqp->cm_id->add_ref(iwqp->cm_id);
- i40iw_schedule_cm_timer(iwqp->cm_node,
- (struct i40iw_puda_buf *)iwqp,
- I40IW_TIMER_TYPE_CLOSE, 1, 0);
- }
- break;
- case I40IW_AE_LLP_CLOSE_COMPLETE:
- if (qp->term_flags)
- i40iw_terminate_done(qp, 0);
- else
- i40iw_cm_disconn(iwqp);
- break;
- case I40IW_AE_BAD_CLOSE:
- case I40IW_AE_RESET_SENT:
- i40iw_next_iw_state(iwqp, I40IW_QP_STATE_ERROR, 1, 0, 0);
- i40iw_cm_disconn(iwqp);
- break;
- case I40IW_AE_LLP_CONNECTION_RESET:
- if (atomic_read(&iwqp->close_timer_started))
- break;
- i40iw_cm_disconn(iwqp);
- break;
- case I40IW_AE_QP_SUSPEND_COMPLETE:
- i40iw_qp_suspend_resume(dev, &iwqp->sc_qp, false);
- break;
- case I40IW_AE_TERMINATE_SENT:
- i40iw_terminate_send_fin(qp);
- break;
- case I40IW_AE_LLP_TERMINATE_RECEIVED:
- i40iw_terminate_received(qp, info);
- break;
- case I40IW_AE_CQ_OPERATION_ERROR:
- i40iw_pr_err("Processing an iWARP related AE for CQ misc = 0x%04X\n",
- info->ae_id);
- cq = (struct i40iw_sc_cq *)(unsigned long)info->compl_ctx;
- iwcq = (struct i40iw_cq *)cq->back_cq;
-
- if (iwcq->ibcq.event_handler) {
- struct ib_event ibevent;
-
- ibevent.device = iwcq->ibcq.device;
- ibevent.event = IB_EVENT_CQ_ERR;
- ibevent.element.cq = &iwcq->ibcq;
- iwcq->ibcq.event_handler(&ibevent, iwcq->ibcq.cq_context);
- }
- break;
- case I40IW_AE_LLP_DOUBT_REACHABILITY:
- break;
- case I40IW_AE_PRIV_OPERATION_DENIED:
- case I40IW_AE_STAG_ZERO_INVALID:
- case I40IW_AE_IB_RREQ_AND_Q1_FULL:
- case I40IW_AE_DDP_UBE_INVALID_DDP_VERSION:
- case I40IW_AE_DDP_UBE_INVALID_MO:
- case I40IW_AE_DDP_UBE_INVALID_QN:
- case I40IW_AE_DDP_NO_L_BIT:
- case I40IW_AE_RDMAP_ROE_INVALID_RDMAP_VERSION:
- case I40IW_AE_RDMAP_ROE_UNEXPECTED_OPCODE:
- case I40IW_AE_ROE_INVALID_RDMA_READ_REQUEST:
- case I40IW_AE_ROE_INVALID_RDMA_WRITE_OR_READ_RESP:
- case I40IW_AE_INVALID_ARP_ENTRY:
- case I40IW_AE_INVALID_TCP_OPTION_RCVD:
- case I40IW_AE_STALE_ARP_ENTRY:
- case I40IW_AE_LLP_RECEIVED_MPA_CRC_ERROR:
- case I40IW_AE_LLP_SEGMENT_TOO_SMALL:
- case I40IW_AE_LLP_SYN_RECEIVED:
- case I40IW_AE_LLP_TOO_MANY_RETRIES:
- case I40IW_AE_LCE_QP_CATASTROPHIC:
- case I40IW_AE_LCE_FUNCTION_CATASTROPHIC:
- case I40IW_AE_LCE_CQ_CATASTROPHIC:
- case I40IW_AE_UDA_XMIT_DGRAM_TOO_LONG:
- case I40IW_AE_UDA_XMIT_DGRAM_TOO_SHORT:
- ctx_info->err_rq_idx_valid = false;
- fallthrough;
- default:
- if (!info->sq && ctx_info->err_rq_idx_valid) {
- ctx_info->err_rq_idx = info->wqe_idx;
- ctx_info->tcp_info_valid = false;
- ctx_info->iwarp_info_valid = false;
- ret = dev->iw_priv_qp_ops->qp_setctx(&iwqp->sc_qp,
- iwqp->host_ctx.va,
- ctx_info);
- }
- i40iw_terminate_connection(qp, info);
- break;
- }
- if (info->qp)
- i40iw_qp_rem_ref(&iwqp->ibqp);
- } while (1);
-
- if (aeqcnt)
- dev->aeq_ops->repost_aeq_entries(dev, aeqcnt);
-}
-
-/**
- * i40iw_cqp_manage_abvpt_cmd - send cqp command manage abpvt
- * @iwdev: iwarp device
- * @accel_local_port: port for apbvt
- * @add_port: add or delete port
- */
-static enum i40iw_status_code
-i40iw_cqp_manage_abvpt_cmd(struct i40iw_device *iwdev,
- u16 accel_local_port,
- bool add_port)
-{
- struct i40iw_apbvt_info *info;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- enum i40iw_status_code status;
-
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, add_port);
- if (!cqp_request)
- return I40IW_ERR_NO_MEMORY;
-
- cqp_info = &cqp_request->info;
- info = &cqp_info->in.u.manage_apbvt_entry.info;
-
- memset(info, 0, sizeof(*info));
- info->add = add_port;
- info->port = cpu_to_le16(accel_local_port);
-
- cqp_info->cqp_cmd = OP_MANAGE_APBVT_ENTRY;
- cqp_info->post_sq = 1;
- cqp_info->in.u.manage_apbvt_entry.cqp = &iwdev->cqp.sc_cqp;
- cqp_info->in.u.manage_apbvt_entry.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP-OP Manage APBVT entry fail");
-
- return status;
-}
-
-/**
- * i40iw_manage_apbvt - add or delete tcp port
- * @iwdev: iwarp device
- * @accel_local_port: port for apbvt
- * @add_port: add or delete port
- */
-enum i40iw_status_code i40iw_manage_apbvt(struct i40iw_device *iwdev,
- u16 accel_local_port,
- bool add_port)
-{
- struct i40iw_cm_core *cm_core = &iwdev->cm_core;
- enum i40iw_status_code status;
- unsigned long flags;
- bool in_use;
-
- /* apbvt_lock is held across CQP delete APBVT OP (non-waiting) to
- * protect against race where add APBVT CQP can race ahead of the delete
- * APBVT for same port.
- */
- if (add_port) {
- spin_lock_irqsave(&cm_core->apbvt_lock, flags);
- in_use = __test_and_set_bit(accel_local_port,
- cm_core->ports_in_use);
- spin_unlock_irqrestore(&cm_core->apbvt_lock, flags);
- if (in_use)
- return 0;
- return i40iw_cqp_manage_abvpt_cmd(iwdev, accel_local_port,
- true);
- } else {
- spin_lock_irqsave(&cm_core->apbvt_lock, flags);
- in_use = i40iw_port_in_use(cm_core, accel_local_port);
- if (in_use) {
- spin_unlock_irqrestore(&cm_core->apbvt_lock, flags);
- return 0;
- }
- __clear_bit(accel_local_port, cm_core->ports_in_use);
- status = i40iw_cqp_manage_abvpt_cmd(iwdev, accel_local_port,
- false);
- spin_unlock_irqrestore(&cm_core->apbvt_lock, flags);
- return status;
- }
-}
-
-/**
- * i40iw_manage_arp_cache - manage hw arp cache
- * @iwdev: iwarp device
- * @mac_addr: mac address ptr
- * @ip_addr: ip addr for arp cache
- * @ipv4: flag indicating IPv4 when true
- * @action: add, delete or modify
- */
-void i40iw_manage_arp_cache(struct i40iw_device *iwdev,
- unsigned char *mac_addr,
- u32 *ip_addr,
- bool ipv4,
- u32 action)
-{
- struct i40iw_add_arp_cache_entry_info *info;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- int arp_index;
-
- arp_index = i40iw_arp_table(iwdev, ip_addr, ipv4, mac_addr, action);
- if (arp_index < 0)
- return;
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, false);
- if (!cqp_request)
- return;
-
- cqp_info = &cqp_request->info;
- if (action == I40IW_ARP_ADD) {
- cqp_info->cqp_cmd = OP_ADD_ARP_CACHE_ENTRY;
- info = &cqp_info->in.u.add_arp_cache_entry.info;
- memset(info, 0, sizeof(*info));
- info->arp_index = cpu_to_le16((u16)arp_index);
- info->permanent = true;
- ether_addr_copy(info->mac_addr, mac_addr);
- cqp_info->in.u.add_arp_cache_entry.scratch = (uintptr_t)cqp_request;
- cqp_info->in.u.add_arp_cache_entry.cqp = &iwdev->cqp.sc_cqp;
- } else {
- cqp_info->cqp_cmd = OP_DELETE_ARP_CACHE_ENTRY;
- cqp_info->in.u.del_arp_cache_entry.scratch = (uintptr_t)cqp_request;
- cqp_info->in.u.del_arp_cache_entry.cqp = &iwdev->cqp.sc_cqp;
- cqp_info->in.u.del_arp_cache_entry.arp_index = arp_index;
- }
-
- cqp_info->in.u.add_arp_cache_entry.cqp = &iwdev->cqp.sc_cqp;
- cqp_info->in.u.add_arp_cache_entry.scratch = (uintptr_t)cqp_request;
- cqp_info->post_sq = 1;
- if (i40iw_handle_cqp_op(iwdev, cqp_request))
- i40iw_pr_err("CQP-OP Add/Del Arp Cache entry fail");
-}
-
-/**
- * i40iw_send_syn_cqp_callback - do syn/ack after qhash
- * @cqp_request: qhash cqp completion
- * @send_ack: flag send ack
- */
-static void i40iw_send_syn_cqp_callback(struct i40iw_cqp_request *cqp_request, u32 send_ack)
-{
- i40iw_send_syn(cqp_request->param, send_ack);
-}
-
-/**
- * i40iw_manage_qhash - add or modify qhash
- * @iwdev: iwarp device
- * @cminfo: cm info for qhash
- * @etype: type (syn or quad)
- * @mtype: type of qhash
- * @cmnode: cmnode associated with connection
- * @wait: wait for completion
- */
-enum i40iw_status_code i40iw_manage_qhash(struct i40iw_device *iwdev,
- struct i40iw_cm_info *cminfo,
- enum i40iw_quad_entry_type etype,
- enum i40iw_quad_hash_manage_type mtype,
- void *cmnode,
- bool wait)
-{
- struct i40iw_qhash_table_info *info;
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_sc_vsi *vsi = &iwdev->vsi;
- enum i40iw_status_code status;
- struct i40iw_cqp *iwcqp = &iwdev->cqp;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
-
- cqp_request = i40iw_get_cqp_request(iwcqp, wait);
- if (!cqp_request)
- return I40IW_ERR_NO_MEMORY;
- cqp_info = &cqp_request->info;
- info = &cqp_info->in.u.manage_qhash_table_entry.info;
- memset(info, 0, sizeof(*info));
-
- info->vsi = &iwdev->vsi;
- info->manage = mtype;
- info->entry_type = etype;
- if (cminfo->vlan_id != 0xFFFF) {
- info->vlan_valid = true;
- info->vlan_id = cpu_to_le16(cminfo->vlan_id);
- } else {
- info->vlan_valid = false;
- }
-
- info->ipv4_valid = cminfo->ipv4;
- info->user_pri = cminfo->user_pri;
- ether_addr_copy(info->mac_addr, iwdev->netdev->dev_addr);
- info->qp_num = cpu_to_le32(vsi->ilq->qp_id);
- info->dest_port = cpu_to_le16(cminfo->loc_port);
- info->dest_ip[0] = cpu_to_le32(cminfo->loc_addr[0]);
- info->dest_ip[1] = cpu_to_le32(cminfo->loc_addr[1]);
- info->dest_ip[2] = cpu_to_le32(cminfo->loc_addr[2]);
- info->dest_ip[3] = cpu_to_le32(cminfo->loc_addr[3]);
- if (etype == I40IW_QHASH_TYPE_TCP_ESTABLISHED) {
- info->src_port = cpu_to_le16(cminfo->rem_port);
- info->src_ip[0] = cpu_to_le32(cminfo->rem_addr[0]);
- info->src_ip[1] = cpu_to_le32(cminfo->rem_addr[1]);
- info->src_ip[2] = cpu_to_le32(cminfo->rem_addr[2]);
- info->src_ip[3] = cpu_to_le32(cminfo->rem_addr[3]);
- }
- if (cmnode) {
- cqp_request->callback_fcn = i40iw_send_syn_cqp_callback;
- cqp_request->param = (void *)cmnode;
- }
-
- if (info->ipv4_valid)
- i40iw_debug(dev, I40IW_DEBUG_CM,
- "%s:%s IP=%pI4, port=%d, mac=%pM, vlan_id=%d\n",
- __func__, (!mtype) ? "DELETE" : "ADD",
- info->dest_ip,
- info->dest_port, info->mac_addr, cminfo->vlan_id);
- else
- i40iw_debug(dev, I40IW_DEBUG_CM,
- "%s:%s IP=%pI6, port=%d, mac=%pM, vlan_id=%d\n",
- __func__, (!mtype) ? "DELETE" : "ADD",
- info->dest_ip,
- info->dest_port, info->mac_addr, cminfo->vlan_id);
- cqp_info->in.u.manage_qhash_table_entry.cqp = &iwdev->cqp.sc_cqp;
- cqp_info->in.u.manage_qhash_table_entry.scratch = (uintptr_t)cqp_request;
- cqp_info->cqp_cmd = OP_MANAGE_QHASH_TABLE_ENTRY;
- cqp_info->post_sq = 1;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP-OP Manage Qhash Entry fail");
- return status;
-}
-
-/**
- * i40iw_hw_flush_wqes - flush qp's wqe
- * @iwdev: iwarp device
- * @qp: hardware control qp
- * @info: info for flush
- * @wait: flag wait for completion
- */
-enum i40iw_status_code i40iw_hw_flush_wqes(struct i40iw_device *iwdev,
- struct i40iw_sc_qp *qp,
- struct i40iw_qp_flush_info *info,
- bool wait)
-{
- enum i40iw_status_code status;
- struct i40iw_qp_flush_info *hw_info;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- struct i40iw_qp *iwqp = (struct i40iw_qp *)qp->back_qp;
-
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, wait);
- if (!cqp_request)
- return I40IW_ERR_NO_MEMORY;
-
- cqp_info = &cqp_request->info;
- hw_info = &cqp_request->info.in.u.qp_flush_wqes.info;
- memcpy(hw_info, info, sizeof(*hw_info));
-
- cqp_info->cqp_cmd = OP_QP_FLUSH_WQES;
- cqp_info->post_sq = 1;
- cqp_info->in.u.qp_flush_wqes.qp = qp;
- cqp_info->in.u.qp_flush_wqes.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status) {
- i40iw_pr_err("CQP-OP Flush WQE's fail");
- complete(&iwqp->sq_drained);
- complete(&iwqp->rq_drained);
- return status;
- }
- if (!cqp_request->compl_info.maj_err_code) {
- switch (cqp_request->compl_info.min_err_code) {
- case I40IW_CQP_COMPL_RQ_WQE_FLUSHED:
- complete(&iwqp->sq_drained);
- break;
- case I40IW_CQP_COMPL_SQ_WQE_FLUSHED:
- complete(&iwqp->rq_drained);
- break;
- case I40IW_CQP_COMPL_RQ_SQ_WQE_FLUSHED:
- break;
- default:
- complete(&iwqp->sq_drained);
- complete(&iwqp->rq_drained);
- break;
- }
- }
-
- return 0;
-}
-
-/**
- * i40iw_gen_ae - generate AE
- * @iwdev: iwarp device
- * @qp: qp associated with AE
- * @info: info for ae
- * @wait: wait for completion
- */
-void i40iw_gen_ae(struct i40iw_device *iwdev,
- struct i40iw_sc_qp *qp,
- struct i40iw_gen_ae_info *info,
- bool wait)
-{
- struct i40iw_gen_ae_info *ae_info;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
-
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, wait);
- if (!cqp_request)
- return;
-
- cqp_info = &cqp_request->info;
- ae_info = &cqp_request->info.in.u.gen_ae.info;
- memcpy(ae_info, info, sizeof(*ae_info));
-
- cqp_info->cqp_cmd = OP_GEN_AE;
- cqp_info->post_sq = 1;
- cqp_info->in.u.gen_ae.qp = qp;
- cqp_info->in.u.gen_ae.scratch = (uintptr_t)cqp_request;
- if (i40iw_handle_cqp_op(iwdev, cqp_request))
- i40iw_pr_err("CQP OP failed attempting to generate ae_code=0x%x\n",
- info->ae_code);
-}
-
-/**
- * i40iw_hw_manage_vf_pble_bp - manage vf pbles
- * @iwdev: iwarp device
- * @info: info for managing pble
- * @wait: flag wait for completion
- */
-enum i40iw_status_code i40iw_hw_manage_vf_pble_bp(struct i40iw_device *iwdev,
- struct i40iw_manage_vf_pble_info *info,
- bool wait)
-{
- enum i40iw_status_code status;
- struct i40iw_manage_vf_pble_info *hw_info;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
-
- if ((iwdev->init_state < CCQ_CREATED) && wait)
- wait = false;
-
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, wait);
- if (!cqp_request)
- return I40IW_ERR_NO_MEMORY;
-
- cqp_info = &cqp_request->info;
- hw_info = &cqp_request->info.in.u.manage_vf_pble_bp.info;
- memcpy(hw_info, info, sizeof(*hw_info));
-
- cqp_info->cqp_cmd = OP_MANAGE_VF_PBLE_BP;
- cqp_info->post_sq = 1;
- cqp_info->in.u.manage_vf_pble_bp.cqp = &iwdev->cqp.sc_cqp;
- cqp_info->in.u.manage_vf_pble_bp.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP-OP Manage VF pble_bp fail");
- return status;
-}
-
-/**
- * i40iw_get_ib_wc - return change flush code to IB's
- * @opcode: iwarp flush code
- */
-static enum ib_wc_status i40iw_get_ib_wc(enum i40iw_flush_opcode opcode)
-{
- switch (opcode) {
- case FLUSH_PROT_ERR:
- return IB_WC_LOC_PROT_ERR;
- case FLUSH_REM_ACCESS_ERR:
- return IB_WC_REM_ACCESS_ERR;
- case FLUSH_LOC_QP_OP_ERR:
- return IB_WC_LOC_QP_OP_ERR;
- case FLUSH_REM_OP_ERR:
- return IB_WC_REM_OP_ERR;
- case FLUSH_LOC_LEN_ERR:
- return IB_WC_LOC_LEN_ERR;
- case FLUSH_GENERAL_ERR:
- return IB_WC_GENERAL_ERR;
- case FLUSH_FATAL_ERR:
- default:
- return IB_WC_FATAL_ERR;
- }
-}
-
-/**
- * i40iw_set_flush_info - set flush info
- * @pinfo: set flush info
- * @min: minor err
- * @maj: major err
- * @opcode: flush error code
- */
-static void i40iw_set_flush_info(struct i40iw_qp_flush_info *pinfo,
- u16 *min,
- u16 *maj,
- enum i40iw_flush_opcode opcode)
-{
- *min = (u16)i40iw_get_ib_wc(opcode);
- *maj = CQE_MAJOR_DRV;
- pinfo->userflushcode = true;
-}
-
-/**
- * i40iw_flush_wqes - flush wqe for qp
- * @iwdev: iwarp device
- * @iwqp: qp to flush wqes
- */
-void i40iw_flush_wqes(struct i40iw_device *iwdev, struct i40iw_qp *iwqp)
-{
- struct i40iw_qp_flush_info info;
- struct i40iw_qp_flush_info *pinfo = &info;
-
- struct i40iw_sc_qp *qp = &iwqp->sc_qp;
-
- memset(pinfo, 0, sizeof(*pinfo));
- info.sq = true;
- info.rq = true;
- if (qp->term_flags) {
- i40iw_set_flush_info(pinfo, &pinfo->sq_minor_code,
- &pinfo->sq_major_code, qp->flush_code);
- i40iw_set_flush_info(pinfo, &pinfo->rq_minor_code,
- &pinfo->rq_major_code, qp->flush_code);
- }
- (void)i40iw_hw_flush_wqes(iwdev, &iwqp->sc_qp, &info, true);
-}
diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c
deleted file mode 100644
index b496f30ce066..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_main.c
+++ /dev/null
@@ -1,2065 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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_vlan.h>
-#include <net/addrconf.h>
-
-#include "i40iw.h"
-#include "i40iw_register.h"
-#include <net/netevent.h>
-#define CLIENT_IW_INTERFACE_VERSION_MAJOR 0
-#define CLIENT_IW_INTERFACE_VERSION_MINOR 01
-#define CLIENT_IW_INTERFACE_VERSION_BUILD 00
-
-#define DRV_VERSION_MAJOR 0
-#define DRV_VERSION_MINOR 5
-#define DRV_VERSION_BUILD 123
-#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
- __stringify(DRV_VERSION_MINOR) "." __stringify(DRV_VERSION_BUILD)
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "debug flags: 0=disabled (default), 0x7fffffff=all");
-
-static int resource_profile;
-module_param(resource_profile, int, 0644);
-MODULE_PARM_DESC(resource_profile,
- "Resource Profile: 0=no VF RDMA support (default), 1=Weighted VF, 2=Even Distribution");
-
-static int max_rdma_vfs = 32;
-module_param(max_rdma_vfs, int, 0644);
-MODULE_PARM_DESC(max_rdma_vfs, "Maximum VF count: 0-32 32=default");
-static int mpa_version = 2;
-module_param(mpa_version, int, 0644);
-MODULE_PARM_DESC(mpa_version, "MPA version to be used in MPA Req/Resp 1 or 2");
-
-MODULE_AUTHOR("Intel Corporation, <e1000-rdma@lists.sourceforge.net>");
-MODULE_DESCRIPTION("Intel(R) Ethernet Connection X722 iWARP RDMA Driver");
-MODULE_LICENSE("Dual BSD/GPL");
-
-static struct i40e_client i40iw_client;
-static char i40iw_client_name[I40E_CLIENT_STR_LENGTH] = "i40iw";
-
-static LIST_HEAD(i40iw_handlers);
-static DEFINE_SPINLOCK(i40iw_handler_lock);
-
-static enum i40iw_status_code i40iw_virtchnl_send(struct i40iw_sc_dev *dev,
- u32 vf_id, u8 *msg, u16 len);
-
-static struct notifier_block i40iw_inetaddr_notifier = {
- .notifier_call = i40iw_inetaddr_event
-};
-
-static struct notifier_block i40iw_inetaddr6_notifier = {
- .notifier_call = i40iw_inet6addr_event
-};
-
-static struct notifier_block i40iw_net_notifier = {
- .notifier_call = i40iw_net_event
-};
-
-static struct notifier_block i40iw_netdevice_notifier = {
- .notifier_call = i40iw_netdevice_event
-};
-
-/**
- * i40iw_find_i40e_handler - find a handler given a client info
- * @ldev: pointer to a client info
- */
-static struct i40iw_handler *i40iw_find_i40e_handler(struct i40e_info *ldev)
-{
- struct i40iw_handler *hdl;
- unsigned long flags;
-
- spin_lock_irqsave(&i40iw_handler_lock, flags);
- list_for_each_entry(hdl, &i40iw_handlers, list) {
- if (hdl->ldev.netdev == ldev->netdev) {
- spin_unlock_irqrestore(&i40iw_handler_lock, flags);
- return hdl;
- }
- }
- spin_unlock_irqrestore(&i40iw_handler_lock, flags);
- return NULL;
-}
-
-/**
- * i40iw_find_netdev - find a handler given a netdev
- * @netdev: pointer to net_device
- */
-struct i40iw_handler *i40iw_find_netdev(struct net_device *netdev)
-{
- struct i40iw_handler *hdl;
- unsigned long flags;
-
- spin_lock_irqsave(&i40iw_handler_lock, flags);
- list_for_each_entry(hdl, &i40iw_handlers, list) {
- if (hdl->ldev.netdev == netdev) {
- spin_unlock_irqrestore(&i40iw_handler_lock, flags);
- return hdl;
- }
- }
- spin_unlock_irqrestore(&i40iw_handler_lock, flags);
- return NULL;
-}
-
-/**
- * i40iw_add_handler - add a handler to the list
- * @hdl: handler to be added to the handler list
- */
-static void i40iw_add_handler(struct i40iw_handler *hdl)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&i40iw_handler_lock, flags);
- list_add(&hdl->list, &i40iw_handlers);
- spin_unlock_irqrestore(&i40iw_handler_lock, flags);
-}
-
-/**
- * i40iw_del_handler - delete a handler from the list
- * @hdl: handler to be deleted from the handler list
- */
-static int i40iw_del_handler(struct i40iw_handler *hdl)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&i40iw_handler_lock, flags);
- list_del(&hdl->list);
- spin_unlock_irqrestore(&i40iw_handler_lock, flags);
- return 0;
-}
-
-/**
- * i40iw_enable_intr - set up device interrupts
- * @dev: hardware control device structure
- * @msix_id: id of the interrupt to be enabled
- */
-static void i40iw_enable_intr(struct i40iw_sc_dev *dev, u32 msix_id)
-{
- u32 val;
-
- val = I40E_PFINT_DYN_CTLN_INTENA_MASK |
- I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
- (3 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
- if (dev->is_pf)
- i40iw_wr32(dev->hw, I40E_PFINT_DYN_CTLN(msix_id - 1), val);
- else
- i40iw_wr32(dev->hw, I40E_VFINT_DYN_CTLN1(msix_id - 1), val);
-}
-
-/**
- * i40iw_dpc - tasklet for aeq and ceq 0
- * @t: Timer context to fetch pointer to iwarp device
- */
-static void i40iw_dpc(struct tasklet_struct *t)
-{
- struct i40iw_device *iwdev = from_tasklet(iwdev, t, dpc_tasklet);
-
- if (iwdev->msix_shared)
- i40iw_process_ceq(iwdev, iwdev->ceqlist);
- i40iw_process_aeq(iwdev);
- i40iw_enable_intr(&iwdev->sc_dev, iwdev->iw_msixtbl[0].idx);
-}
-
-/**
- * i40iw_ceq_dpc - dpc handler for CEQ
- * @t: Timer context to fetch pointer to CEQ data
- */
-static void i40iw_ceq_dpc(struct tasklet_struct *t)
-{
- struct i40iw_ceq *iwceq = from_tasklet(iwceq, t, dpc_tasklet);
- struct i40iw_device *iwdev = iwceq->iwdev;
-
- i40iw_process_ceq(iwdev, iwceq);
- i40iw_enable_intr(&iwdev->sc_dev, iwceq->msix_idx);
-}
-
-/**
- * i40iw_irq_handler - interrupt handler for aeq and ceq0
- * @irq: Interrupt request number
- * @data: iwarp device
- */
-static irqreturn_t i40iw_irq_handler(int irq, void *data)
-{
- struct i40iw_device *iwdev = (struct i40iw_device *)data;
-
- tasklet_schedule(&iwdev->dpc_tasklet);
- return IRQ_HANDLED;
-}
-
-/**
- * i40iw_destroy_cqp - destroy control qp
- * @iwdev: iwarp device
- * @free_hwcqp: 1 if CQP should be destroyed
- *
- * Issue destroy cqp request and
- * free the resources associated with the cqp
- */
-static void i40iw_destroy_cqp(struct i40iw_device *iwdev, bool free_hwcqp)
-{
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_cqp *cqp = &iwdev->cqp;
-
- if (free_hwcqp)
- dev->cqp_ops->cqp_destroy(dev->cqp);
-
- i40iw_cleanup_pending_cqp_op(iwdev);
-
- i40iw_free_dma_mem(dev->hw, &cqp->sq);
- kfree(cqp->scratch_array);
- iwdev->cqp.scratch_array = NULL;
-
- kfree(cqp->cqp_requests);
- cqp->cqp_requests = NULL;
-}
-
-/**
- * i40iw_disable_irq - disable device interrupts
- * @dev: hardware control device structure
- * @msix_vec: msix vector to disable irq
- * @dev_id: parameter to pass to free_irq (used during irq setup)
- *
- * The function is called when destroying aeq/ceq
- */
-static void i40iw_disable_irq(struct i40iw_sc_dev *dev,
- struct i40iw_msix_vector *msix_vec,
- void *dev_id)
-{
- if (dev->is_pf)
- i40iw_wr32(dev->hw, I40E_PFINT_DYN_CTLN(msix_vec->idx - 1), 0);
- else
- i40iw_wr32(dev->hw, I40E_VFINT_DYN_CTLN1(msix_vec->idx - 1), 0);
- irq_set_affinity_hint(msix_vec->irq, NULL);
- free_irq(msix_vec->irq, dev_id);
-}
-
-/**
- * i40iw_destroy_aeq - destroy aeq
- * @iwdev: iwarp device
- *
- * Issue a destroy aeq request and
- * free the resources associated with the aeq
- * The function is called during driver unload
- */
-static void i40iw_destroy_aeq(struct i40iw_device *iwdev)
-{
- enum i40iw_status_code status = I40IW_ERR_NOT_READY;
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_aeq *aeq = &iwdev->aeq;
-
- if (!iwdev->msix_shared)
- i40iw_disable_irq(dev, iwdev->iw_msixtbl, (void *)iwdev);
- if (iwdev->reset)
- goto exit;
-
- if (!dev->aeq_ops->aeq_destroy(&aeq->sc_aeq, 0, 1))
- status = dev->aeq_ops->aeq_destroy_done(&aeq->sc_aeq);
- if (status)
- i40iw_pr_err("destroy aeq failed %d\n", status);
-
-exit:
- i40iw_free_dma_mem(dev->hw, &aeq->mem);
-}
-
-/**
- * i40iw_destroy_ceq - destroy ceq
- * @iwdev: iwarp device
- * @iwceq: ceq to be destroyed
- *
- * Issue a destroy ceq request and
- * free the resources associated with the ceq
- */
-static void i40iw_destroy_ceq(struct i40iw_device *iwdev,
- struct i40iw_ceq *iwceq)
-{
- enum i40iw_status_code status;
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
-
- if (iwdev->reset)
- goto exit;
-
- status = dev->ceq_ops->ceq_destroy(&iwceq->sc_ceq, 0, 1);
- if (status) {
- i40iw_pr_err("ceq destroy command failed %d\n", status);
- goto exit;
- }
-
- status = dev->ceq_ops->cceq_destroy_done(&iwceq->sc_ceq);
- if (status)
- i40iw_pr_err("ceq destroy completion failed %d\n", status);
-exit:
- i40iw_free_dma_mem(dev->hw, &iwceq->mem);
-}
-
-/**
- * i40iw_dele_ceqs - destroy all ceq's
- * @iwdev: iwarp device
- *
- * Go through all of the device ceq's and for each ceq
- * disable the ceq interrupt and destroy the ceq
- */
-static void i40iw_dele_ceqs(struct i40iw_device *iwdev)
-{
- u32 i = 0;
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_ceq *iwceq = iwdev->ceqlist;
- struct i40iw_msix_vector *msix_vec = iwdev->iw_msixtbl;
-
- if (iwdev->msix_shared) {
- i40iw_disable_irq(dev, msix_vec, (void *)iwdev);
- i40iw_destroy_ceq(iwdev, iwceq);
- iwceq++;
- i++;
- }
-
- for (msix_vec++; i < iwdev->ceqs_count; i++, msix_vec++, iwceq++) {
- i40iw_disable_irq(dev, msix_vec, (void *)iwceq);
- i40iw_destroy_ceq(iwdev, iwceq);
- }
-
- iwdev->sc_dev.ceq_valid = false;
-}
-
-/**
- * i40iw_destroy_ccq - destroy control cq
- * @iwdev: iwarp device
- *
- * Issue destroy ccq request and
- * free the resources associated with the ccq
- */
-static void i40iw_destroy_ccq(struct i40iw_device *iwdev)
-{
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_ccq *ccq = &iwdev->ccq;
- enum i40iw_status_code status = 0;
-
- if (!iwdev->reset)
- status = dev->ccq_ops->ccq_destroy(dev->ccq, 0, true);
- if (status)
- i40iw_pr_err("ccq destroy failed %d\n", status);
- i40iw_free_dma_mem(dev->hw, &ccq->mem_cq);
-}
-
-/* types of hmc objects */
-static enum i40iw_hmc_rsrc_type iw_hmc_obj_types[] = {
- I40IW_HMC_IW_QP,
- I40IW_HMC_IW_CQ,
- I40IW_HMC_IW_HTE,
- I40IW_HMC_IW_ARP,
- I40IW_HMC_IW_APBVT_ENTRY,
- I40IW_HMC_IW_MR,
- I40IW_HMC_IW_XF,
- I40IW_HMC_IW_XFFL,
- I40IW_HMC_IW_Q1,
- I40IW_HMC_IW_Q1FL,
- I40IW_HMC_IW_TIMER,
-};
-
-/**
- * i40iw_close_hmc_objects_type - delete hmc objects of a given type
- * @dev: iwarp device
- * @obj_type: the hmc object type to be deleted
- * @hmc_info: pointer to the HMC configuration information
- * @is_pf: true if the function is PF otherwise false
- * @reset: true if called before reset
- */
-static void i40iw_close_hmc_objects_type(struct i40iw_sc_dev *dev,
- enum i40iw_hmc_rsrc_type obj_type,
- struct i40iw_hmc_info *hmc_info,
- bool is_pf,
- bool reset)
-{
- struct i40iw_hmc_del_obj_info info;
-
- memset(&info, 0, sizeof(info));
- info.hmc_info = hmc_info;
- info.rsrc_type = obj_type;
- info.count = hmc_info->hmc_obj[obj_type].cnt;
- info.is_pf = is_pf;
- if (dev->hmc_ops->del_hmc_object(dev, &info, reset))
- i40iw_pr_err("del obj of type %d failed\n", obj_type);
-}
-
-/**
- * i40iw_del_hmc_objects - remove all device hmc objects
- * @dev: iwarp device
- * @hmc_info: hmc_info to free
- * @is_pf: true if hmc_info belongs to PF, not vf nor allocated
- * by PF on behalf of VF
- * @reset: true if called before reset
- */
-static void i40iw_del_hmc_objects(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_info *hmc_info,
- bool is_pf,
- bool reset)
-{
- unsigned int i;
-
- for (i = 0; i < IW_HMC_OBJ_TYPE_NUM; i++)
- i40iw_close_hmc_objects_type(dev, iw_hmc_obj_types[i], hmc_info, is_pf, reset);
-}
-
-/**
- * i40iw_ceq_handler - interrupt handler for ceq
- * @irq: interrupt request number
- * @data: ceq pointer
- */
-static irqreturn_t i40iw_ceq_handler(int irq, void *data)
-{
- struct i40iw_ceq *iwceq = (struct i40iw_ceq *)data;
-
- if (iwceq->irq != irq)
- i40iw_pr_err("expected irq = %d received irq = %d\n", iwceq->irq, irq);
- tasklet_schedule(&iwceq->dpc_tasklet);
- return IRQ_HANDLED;
-}
-
-/**
- * i40iw_create_hmc_obj_type - create hmc object of a given type
- * @dev: hardware control device structure
- * @info: information for the hmc object to create
- */
-static enum i40iw_status_code i40iw_create_hmc_obj_type(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_create_obj_info *info)
-{
- return dev->hmc_ops->create_hmc_object(dev, info);
-}
-
-/**
- * i40iw_create_hmc_objs - create all hmc objects for the device
- * @iwdev: iwarp device
- * @is_pf: true if the function is PF otherwise false
- *
- * Create the device hmc objects and allocate hmc pages
- * Return 0 if successful, otherwise clean up and return error
- */
-static enum i40iw_status_code i40iw_create_hmc_objs(struct i40iw_device *iwdev,
- bool is_pf)
-{
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_hmc_create_obj_info info;
- enum i40iw_status_code status;
- int i;
-
- memset(&info, 0, sizeof(info));
- info.hmc_info = dev->hmc_info;
- info.is_pf = is_pf;
- info.entry_type = iwdev->sd_type;
- for (i = 0; i < IW_HMC_OBJ_TYPE_NUM; i++) {
- info.rsrc_type = iw_hmc_obj_types[i];
- info.count = dev->hmc_info->hmc_obj[info.rsrc_type].cnt;
- info.add_sd_cnt = 0;
- status = i40iw_create_hmc_obj_type(dev, &info);
- if (status) {
- i40iw_pr_err("create obj type %d status = %d\n",
- iw_hmc_obj_types[i], status);
- break;
- }
- }
- if (!status)
- return (dev->cqp_misc_ops->static_hmc_pages_allocated(dev->cqp, 0,
- dev->hmc_fn_id,
- true, true));
-
- while (i) {
- i--;
- /* destroy the hmc objects of a given type */
- i40iw_close_hmc_objects_type(dev,
- iw_hmc_obj_types[i],
- dev->hmc_info,
- is_pf,
- false);
- }
- return status;
-}
-
-/**
- * i40iw_obj_aligned_mem - get aligned memory from device allocated memory
- * @iwdev: iwarp device
- * @memptr: points to the memory addresses
- * @size: size of memory needed
- * @mask: mask for the aligned memory
- *
- * Get aligned memory of the requested size and
- * update the memptr to point to the new aligned memory
- * Return 0 if successful, otherwise return no memory error
- */
-enum i40iw_status_code i40iw_obj_aligned_mem(struct i40iw_device *iwdev,
- struct i40iw_dma_mem *memptr,
- u32 size,
- u32 mask)
-{
- unsigned long va, newva;
- unsigned long extra;
-
- va = (unsigned long)iwdev->obj_next.va;
- newva = va;
- if (mask)
- newva = ALIGN(va, (mask + 1));
- extra = newva - va;
- memptr->va = (u8 *)va + extra;
- memptr->pa = iwdev->obj_next.pa + extra;
- memptr->size = size;
- if ((memptr->va + size) > (iwdev->obj_mem.va + iwdev->obj_mem.size))
- return I40IW_ERR_NO_MEMORY;
-
- iwdev->obj_next.va = memptr->va + size;
- iwdev->obj_next.pa = memptr->pa + size;
- return 0;
-}
-
-/**
- * i40iw_create_cqp - create control qp
- * @iwdev: iwarp device
- *
- * Return 0, if the cqp and all the resources associated with it
- * are successfully created, otherwise return error
- */
-static enum i40iw_status_code i40iw_create_cqp(struct i40iw_device *iwdev)
-{
- enum i40iw_status_code status;
- u32 sqsize = I40IW_CQP_SW_SQSIZE_2048;
- struct i40iw_dma_mem mem;
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_cqp_init_info cqp_init_info;
- struct i40iw_cqp *cqp = &iwdev->cqp;
- u16 maj_err, min_err;
- int i;
-
- cqp->cqp_requests = kcalloc(sqsize, sizeof(*cqp->cqp_requests), GFP_KERNEL);
- if (!cqp->cqp_requests)
- return I40IW_ERR_NO_MEMORY;
- cqp->scratch_array = kcalloc(sqsize, sizeof(*cqp->scratch_array), GFP_KERNEL);
- if (!cqp->scratch_array) {
- kfree(cqp->cqp_requests);
- return I40IW_ERR_NO_MEMORY;
- }
- dev->cqp = &cqp->sc_cqp;
- dev->cqp->dev = dev;
- memset(&cqp_init_info, 0, sizeof(cqp_init_info));
- status = i40iw_allocate_dma_mem(dev->hw, &cqp->sq,
- (sizeof(struct i40iw_cqp_sq_wqe) * sqsize),
- I40IW_CQP_ALIGNMENT);
- if (status)
- goto exit;
- status = i40iw_obj_aligned_mem(iwdev, &mem, sizeof(struct i40iw_cqp_ctx),
- I40IW_HOST_CTX_ALIGNMENT_MASK);
- if (status)
- goto exit;
- dev->cqp->host_ctx_pa = mem.pa;
- dev->cqp->host_ctx = mem.va;
- /* populate the cqp init info */
- cqp_init_info.dev = dev;
- cqp_init_info.sq_size = sqsize;
- cqp_init_info.sq = cqp->sq.va;
- cqp_init_info.sq_pa = cqp->sq.pa;
- cqp_init_info.host_ctx_pa = mem.pa;
- cqp_init_info.host_ctx = mem.va;
- cqp_init_info.hmc_profile = iwdev->resource_profile;
- cqp_init_info.enabled_vf_count = iwdev->max_rdma_vfs;
- cqp_init_info.scratch_array = cqp->scratch_array;
- status = dev->cqp_ops->cqp_init(dev->cqp, &cqp_init_info);
- if (status) {
- i40iw_pr_err("cqp init status %d\n", status);
- goto exit;
- }
- status = dev->cqp_ops->cqp_create(dev->cqp, &maj_err, &min_err);
- if (status) {
- i40iw_pr_err("cqp create status %d maj_err %d min_err %d\n",
- status, maj_err, min_err);
- goto exit;
- }
- spin_lock_init(&cqp->req_lock);
- INIT_LIST_HEAD(&cqp->cqp_avail_reqs);
- INIT_LIST_HEAD(&cqp->cqp_pending_reqs);
- /* init the waitq of the cqp_requests and add them to the list */
- for (i = 0; i < sqsize; i++) {
- init_waitqueue_head(&cqp->cqp_requests[i].waitq);
- list_add_tail(&cqp->cqp_requests[i].list, &cqp->cqp_avail_reqs);
- }
- return 0;
-exit:
- /* clean up the created resources */
- i40iw_destroy_cqp(iwdev, false);
- return status;
-}
-
-/**
- * i40iw_create_ccq - create control cq
- * @iwdev: iwarp device
- *
- * Return 0, if the ccq and the resources associated with it
- * are successfully created, otherwise return error
- */
-static enum i40iw_status_code i40iw_create_ccq(struct i40iw_device *iwdev)
-{
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_dma_mem mem;
- enum i40iw_status_code status;
- struct i40iw_ccq_init_info info;
- struct i40iw_ccq *ccq = &iwdev->ccq;
-
- memset(&info, 0, sizeof(info));
- dev->ccq = &ccq->sc_cq;
- dev->ccq->dev = dev;
- info.dev = dev;
- ccq->shadow_area.size = sizeof(struct i40iw_cq_shadow_area);
- ccq->mem_cq.size = sizeof(struct i40iw_cqe) * IW_CCQ_SIZE;
- status = i40iw_allocate_dma_mem(dev->hw, &ccq->mem_cq,
- ccq->mem_cq.size, I40IW_CQ0_ALIGNMENT);
- if (status)
- goto exit;
- status = i40iw_obj_aligned_mem(iwdev, &mem, ccq->shadow_area.size,
- I40IW_SHADOWAREA_MASK);
- if (status)
- goto exit;
- ccq->sc_cq.back_cq = (void *)ccq;
- /* populate the ccq init info */
- info.cq_base = ccq->mem_cq.va;
- info.cq_pa = ccq->mem_cq.pa;
- info.num_elem = IW_CCQ_SIZE;
- info.shadow_area = mem.va;
- info.shadow_area_pa = mem.pa;
- info.ceqe_mask = false;
- info.ceq_id_valid = true;
- info.shadow_read_threshold = 16;
- status = dev->ccq_ops->ccq_init(dev->ccq, &info);
- if (!status)
- status = dev->ccq_ops->ccq_create(dev->ccq, 0, true, true);
-exit:
- if (status)
- i40iw_free_dma_mem(dev->hw, &ccq->mem_cq);
- return status;
-}
-
-/**
- * i40iw_configure_ceq_vector - set up the msix interrupt vector for ceq
- * @iwdev: iwarp device
- * @msix_vec: interrupt vector information
- * @iwceq: ceq associated with the vector
- * @ceq_id: the id number of the iwceq
- *
- * Allocate interrupt resources and enable irq handling
- * Return 0 if successful, otherwise return error
- */
-static enum i40iw_status_code i40iw_configure_ceq_vector(struct i40iw_device *iwdev,
- struct i40iw_ceq *iwceq,
- u32 ceq_id,
- struct i40iw_msix_vector *msix_vec)
-{
- enum i40iw_status_code status;
-
- if (iwdev->msix_shared && !ceq_id) {
- tasklet_setup(&iwdev->dpc_tasklet, i40iw_dpc);
- status = request_irq(msix_vec->irq, i40iw_irq_handler, 0, "AEQCEQ", iwdev);
- } else {
- tasklet_setup(&iwceq->dpc_tasklet, i40iw_ceq_dpc);
- status = request_irq(msix_vec->irq, i40iw_ceq_handler, 0, "CEQ", iwceq);
- }
-
- cpumask_clear(&msix_vec->mask);
- cpumask_set_cpu(msix_vec->cpu_affinity, &msix_vec->mask);
- irq_set_affinity_hint(msix_vec->irq, &msix_vec->mask);
-
- if (status) {
- i40iw_pr_err("ceq irq config fail\n");
- return I40IW_ERR_CONFIG;
- }
- msix_vec->ceq_id = ceq_id;
-
- return 0;
-}
-
-/**
- * i40iw_create_ceq - create completion event queue
- * @iwdev: iwarp device
- * @iwceq: pointer to the ceq resources to be created
- * @ceq_id: the id number of the iwceq
- *
- * Return 0, if the ceq and the resources associated with it
- * are successfully created, otherwise return error
- */
-static enum i40iw_status_code i40iw_create_ceq(struct i40iw_device *iwdev,
- struct i40iw_ceq *iwceq,
- u32 ceq_id)
-{
- enum i40iw_status_code status;
- struct i40iw_ceq_init_info info;
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- u64 scratch;
-
- memset(&info, 0, sizeof(info));
- info.ceq_id = ceq_id;
- iwceq->iwdev = iwdev;
- iwceq->mem.size = sizeof(struct i40iw_ceqe) *
- iwdev->sc_dev.hmc_info->hmc_obj[I40IW_HMC_IW_CQ].cnt;
- status = i40iw_allocate_dma_mem(dev->hw, &iwceq->mem, iwceq->mem.size,
- I40IW_CEQ_ALIGNMENT);
- if (status)
- goto exit;
- info.ceq_id = ceq_id;
- info.ceqe_base = iwceq->mem.va;
- info.ceqe_pa = iwceq->mem.pa;
-
- info.elem_cnt = iwdev->sc_dev.hmc_info->hmc_obj[I40IW_HMC_IW_CQ].cnt;
- iwceq->sc_ceq.ceq_id = ceq_id;
- info.dev = dev;
- scratch = (uintptr_t)&iwdev->cqp.sc_cqp;
- status = dev->ceq_ops->ceq_init(&iwceq->sc_ceq, &info);
- if (!status)
- status = dev->ceq_ops->cceq_create(&iwceq->sc_ceq, scratch);
-
-exit:
- if (status)
- i40iw_free_dma_mem(dev->hw, &iwceq->mem);
- return status;
-}
-
-void i40iw_request_reset(struct i40iw_device *iwdev)
-{
- struct i40e_info *ldev = iwdev->ldev;
-
- ldev->ops->request_reset(ldev, iwdev->client, 1);
-}
-
-/**
- * i40iw_setup_ceqs - manage the device ceq's and their interrupt resources
- * @iwdev: iwarp device
- * @ldev: i40e lan device
- *
- * Allocate a list for all device completion event queues
- * Create the ceq's and configure their msix interrupt vectors
- * Return 0, if at least one ceq is successfully set up, otherwise return error
- */
-static enum i40iw_status_code i40iw_setup_ceqs(struct i40iw_device *iwdev,
- struct i40e_info *ldev)
-{
- u32 i;
- u32 ceq_id;
- struct i40iw_ceq *iwceq;
- struct i40iw_msix_vector *msix_vec;
- enum i40iw_status_code status = 0;
- u32 num_ceqs;
-
- if (ldev && ldev->ops && ldev->ops->setup_qvlist) {
- status = ldev->ops->setup_qvlist(ldev, &i40iw_client,
- iwdev->iw_qvlist);
- if (status)
- goto exit;
- } else {
- status = I40IW_ERR_BAD_PTR;
- goto exit;
- }
-
- num_ceqs = min(iwdev->msix_count, iwdev->sc_dev.hmc_fpm_misc.max_ceqs);
- iwdev->ceqlist = kcalloc(num_ceqs, sizeof(*iwdev->ceqlist), GFP_KERNEL);
- if (!iwdev->ceqlist) {
- status = I40IW_ERR_NO_MEMORY;
- goto exit;
- }
- i = (iwdev->msix_shared) ? 0 : 1;
- for (ceq_id = 0; i < num_ceqs; i++, ceq_id++) {
- iwceq = &iwdev->ceqlist[ceq_id];
- status = i40iw_create_ceq(iwdev, iwceq, ceq_id);
- if (status) {
- i40iw_pr_err("create ceq status = %d\n", status);
- break;
- }
-
- msix_vec = &iwdev->iw_msixtbl[i];
- iwceq->irq = msix_vec->irq;
- iwceq->msix_idx = msix_vec->idx;
- status = i40iw_configure_ceq_vector(iwdev, iwceq, ceq_id, msix_vec);
- if (status) {
- i40iw_destroy_ceq(iwdev, iwceq);
- break;
- }
- i40iw_enable_intr(&iwdev->sc_dev, msix_vec->idx);
- iwdev->ceqs_count++;
- }
-exit:
- if (status && !iwdev->ceqs_count) {
- kfree(iwdev->ceqlist);
- iwdev->ceqlist = NULL;
- return status;
- } else {
- iwdev->sc_dev.ceq_valid = true;
- return 0;
- }
-
-}
-
-/**
- * i40iw_configure_aeq_vector - set up the msix vector for aeq
- * @iwdev: iwarp device
- *
- * Allocate interrupt resources and enable irq handling
- * Return 0 if successful, otherwise return error
- */
-static enum i40iw_status_code i40iw_configure_aeq_vector(struct i40iw_device *iwdev)
-{
- struct i40iw_msix_vector *msix_vec = iwdev->iw_msixtbl;
- u32 ret = 0;
-
- if (!iwdev->msix_shared) {
- tasklet_setup(&iwdev->dpc_tasklet, i40iw_dpc);
- ret = request_irq(msix_vec->irq, i40iw_irq_handler, 0, "i40iw", iwdev);
- }
- if (ret) {
- i40iw_pr_err("aeq irq config fail\n");
- return I40IW_ERR_CONFIG;
- }
-
- return 0;
-}
-
-/**
- * i40iw_create_aeq - create async event queue
- * @iwdev: iwarp device
- *
- * Return 0, if the aeq and the resources associated with it
- * are successfully created, otherwise return error
- */
-static enum i40iw_status_code i40iw_create_aeq(struct i40iw_device *iwdev)
-{
- enum i40iw_status_code status;
- struct i40iw_aeq_init_info info;
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_aeq *aeq = &iwdev->aeq;
- u64 scratch = 0;
- u32 aeq_size;
-
- aeq_size = 2 * iwdev->sc_dev.hmc_info->hmc_obj[I40IW_HMC_IW_QP].cnt +
- iwdev->sc_dev.hmc_info->hmc_obj[I40IW_HMC_IW_CQ].cnt;
- memset(&info, 0, sizeof(info));
- aeq->mem.size = sizeof(struct i40iw_sc_aeqe) * aeq_size;
- status = i40iw_allocate_dma_mem(dev->hw, &aeq->mem, aeq->mem.size,
- I40IW_AEQ_ALIGNMENT);
- if (status)
- goto exit;
-
- info.aeqe_base = aeq->mem.va;
- info.aeq_elem_pa = aeq->mem.pa;
- info.elem_cnt = aeq_size;
- info.dev = dev;
- status = dev->aeq_ops->aeq_init(&aeq->sc_aeq, &info);
- if (status)
- goto exit;
- status = dev->aeq_ops->aeq_create(&aeq->sc_aeq, scratch, 1);
- if (!status)
- status = dev->aeq_ops->aeq_create_done(&aeq->sc_aeq);
-exit:
- if (status)
- i40iw_free_dma_mem(dev->hw, &aeq->mem);
- return status;
-}
-
-/**
- * i40iw_setup_aeq - set up the device aeq
- * @iwdev: iwarp device
- *
- * Create the aeq and configure its msix interrupt vector
- * Return 0 if successful, otherwise return error
- */
-static enum i40iw_status_code i40iw_setup_aeq(struct i40iw_device *iwdev)
-{
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- enum i40iw_status_code status;
-
- status = i40iw_create_aeq(iwdev);
- if (status)
- return status;
-
- status = i40iw_configure_aeq_vector(iwdev);
- if (status) {
- i40iw_destroy_aeq(iwdev);
- return status;
- }
-
- if (!iwdev->msix_shared)
- i40iw_enable_intr(dev, iwdev->iw_msixtbl[0].idx);
- return 0;
-}
-
-/**
- * i40iw_initialize_ilq - create iwarp local queue for cm
- * @iwdev: iwarp device
- *
- * Return 0 if successful, otherwise return error
- */
-static enum i40iw_status_code i40iw_initialize_ilq(struct i40iw_device *iwdev)
-{
- struct i40iw_puda_rsrc_info info;
- enum i40iw_status_code status;
-
- memset(&info, 0, sizeof(info));
- info.type = I40IW_PUDA_RSRC_TYPE_ILQ;
- info.cq_id = 1;
- info.qp_id = 0;
- info.count = 1;
- info.pd_id = 1;
- info.sq_size = 8192;
- info.rq_size = 8192;
- info.buf_size = 1024;
- info.tx_buf_cnt = 16384;
- info.receive = i40iw_receive_ilq;
- info.xmit_complete = i40iw_free_sqbuf;
- status = i40iw_puda_create_rsrc(&iwdev->vsi, &info);
- if (status)
- i40iw_pr_err("ilq create fail\n");
- return status;
-}
-
-/**
- * i40iw_initialize_ieq - create iwarp exception queue
- * @iwdev: iwarp device
- *
- * Return 0 if successful, otherwise return error
- */
-static enum i40iw_status_code i40iw_initialize_ieq(struct i40iw_device *iwdev)
-{
- struct i40iw_puda_rsrc_info info;
- enum i40iw_status_code status;
-
- memset(&info, 0, sizeof(info));
- info.type = I40IW_PUDA_RSRC_TYPE_IEQ;
- info.cq_id = 2;
- info.qp_id = iwdev->vsi.exception_lan_queue;
- info.count = 1;
- info.pd_id = 2;
- info.sq_size = 8192;
- info.rq_size = 8192;
- info.buf_size = iwdev->vsi.mtu + VLAN_ETH_HLEN;
- info.tx_buf_cnt = 4096;
- status = i40iw_puda_create_rsrc(&iwdev->vsi, &info);
- if (status)
- i40iw_pr_err("ieq create fail\n");
- return status;
-}
-
-/**
- * i40iw_reinitialize_ieq - destroy and re-create ieq
- * @dev: iwarp device
- */
-void i40iw_reinitialize_ieq(struct i40iw_sc_dev *dev)
-{
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
-
- i40iw_puda_dele_resources(&iwdev->vsi, I40IW_PUDA_RSRC_TYPE_IEQ, false);
- if (i40iw_initialize_ieq(iwdev)) {
- iwdev->reset = true;
- i40iw_request_reset(iwdev);
- }
-}
-
-/**
- * i40iw_hmc_setup - create hmc objects for the device
- * @iwdev: iwarp device
- *
- * Set up the device private memory space for the number and size of
- * the hmc objects and create the objects
- * Return 0 if successful, otherwise return error
- */
-static enum i40iw_status_code i40iw_hmc_setup(struct i40iw_device *iwdev)
-{
- enum i40iw_status_code status;
-
- iwdev->sd_type = I40IW_SD_TYPE_DIRECT;
- status = i40iw_config_fpm_values(&iwdev->sc_dev, IW_CFG_FPM_QP_COUNT);
- if (status)
- goto exit;
- status = i40iw_create_hmc_objs(iwdev, true);
- if (status)
- goto exit;
- iwdev->init_state = HMC_OBJS_CREATED;
-exit:
- return status;
-}
-
-/**
- * i40iw_del_init_mem - deallocate memory resources
- * @iwdev: iwarp device
- */
-static void i40iw_del_init_mem(struct i40iw_device *iwdev)
-{
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
-
- i40iw_free_dma_mem(&iwdev->hw, &iwdev->obj_mem);
- kfree(dev->hmc_info->sd_table.sd_entry);
- dev->hmc_info->sd_table.sd_entry = NULL;
- kfree(iwdev->mem_resources);
- iwdev->mem_resources = NULL;
- kfree(iwdev->ceqlist);
- iwdev->ceqlist = NULL;
- kfree(iwdev->iw_msixtbl);
- iwdev->iw_msixtbl = NULL;
- kfree(iwdev->hmc_info_mem);
- iwdev->hmc_info_mem = NULL;
-}
-
-/**
- * i40iw_del_macip_entry - remove a mac ip address entry from the hw table
- * @iwdev: iwarp device
- * @idx: the index of the mac ip address to delete
- */
-static void i40iw_del_macip_entry(struct i40iw_device *iwdev, u8 idx)
-{
- struct i40iw_cqp *iwcqp = &iwdev->cqp;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- enum i40iw_status_code status = 0;
-
- cqp_request = i40iw_get_cqp_request(iwcqp, true);
- if (!cqp_request) {
- i40iw_pr_err("cqp_request memory failed\n");
- return;
- }
- cqp_info = &cqp_request->info;
- cqp_info->cqp_cmd = OP_DELETE_LOCAL_MAC_IPADDR_ENTRY;
- cqp_info->post_sq = 1;
- cqp_info->in.u.del_local_mac_ipaddr_entry.cqp = &iwcqp->sc_cqp;
- cqp_info->in.u.del_local_mac_ipaddr_entry.scratch = (uintptr_t)cqp_request;
- cqp_info->in.u.del_local_mac_ipaddr_entry.entry_idx = idx;
- cqp_info->in.u.del_local_mac_ipaddr_entry.ignore_ref_count = 0;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP-OP Del MAC Ip entry fail");
-}
-
-/**
- * i40iw_add_mac_ipaddr_entry - add a mac ip address entry to the hw table
- * @iwdev: iwarp device
- * @mac_addr: pointer to mac address
- * @idx: the index of the mac ip address to add
- */
-static enum i40iw_status_code i40iw_add_mac_ipaddr_entry(struct i40iw_device *iwdev,
- u8 *mac_addr,
- u8 idx)
-{
- struct i40iw_local_mac_ipaddr_entry_info *info;
- struct i40iw_cqp *iwcqp = &iwdev->cqp;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- enum i40iw_status_code status = 0;
-
- cqp_request = i40iw_get_cqp_request(iwcqp, true);
- if (!cqp_request) {
- i40iw_pr_err("cqp_request memory failed\n");
- return I40IW_ERR_NO_MEMORY;
- }
-
- cqp_info = &cqp_request->info;
-
- cqp_info->post_sq = 1;
- info = &cqp_info->in.u.add_local_mac_ipaddr_entry.info;
- ether_addr_copy(info->mac_addr, mac_addr);
- info->entry_idx = idx;
- cqp_info->in.u.add_local_mac_ipaddr_entry.scratch = (uintptr_t)cqp_request;
- cqp_info->cqp_cmd = OP_ADD_LOCAL_MAC_IPADDR_ENTRY;
- cqp_info->in.u.add_local_mac_ipaddr_entry.cqp = &iwcqp->sc_cqp;
- cqp_info->in.u.add_local_mac_ipaddr_entry.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP-OP Add MAC Ip entry fail");
- return status;
-}
-
-/**
- * i40iw_alloc_local_mac_ipaddr_entry - allocate a mac ip address entry
- * @iwdev: iwarp device
- * @mac_ip_tbl_idx: the index of the new mac ip address
- *
- * Allocate a mac ip address entry and update the mac_ip_tbl_idx
- * to hold the index of the newly created mac ip address
- * Return 0 if successful, otherwise return error
- */
-static enum i40iw_status_code i40iw_alloc_local_mac_ipaddr_entry(struct i40iw_device *iwdev,
- u16 *mac_ip_tbl_idx)
-{
- struct i40iw_cqp *iwcqp = &iwdev->cqp;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- enum i40iw_status_code status = 0;
-
- cqp_request = i40iw_get_cqp_request(iwcqp, true);
- if (!cqp_request) {
- i40iw_pr_err("cqp_request memory failed\n");
- return I40IW_ERR_NO_MEMORY;
- }
-
- /* increment refcount, because we need the cqp request ret value */
- atomic_inc(&cqp_request->refcount);
-
- cqp_info = &cqp_request->info;
- cqp_info->cqp_cmd = OP_ALLOC_LOCAL_MAC_IPADDR_ENTRY;
- cqp_info->post_sq = 1;
- cqp_info->in.u.alloc_local_mac_ipaddr_entry.cqp = &iwcqp->sc_cqp;
- cqp_info->in.u.alloc_local_mac_ipaddr_entry.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (!status)
- *mac_ip_tbl_idx = cqp_request->compl_info.op_ret_val;
- else
- i40iw_pr_err("CQP-OP Alloc MAC Ip entry fail");
- /* decrement refcount and free the cqp request, if no longer used */
- i40iw_put_cqp_request(iwcqp, cqp_request);
- return status;
-}
-
-/**
- * i40iw_alloc_set_mac_ipaddr - set up a mac ip address table entry
- * @iwdev: iwarp device
- * @macaddr: pointer to mac address
- *
- * Allocate a mac ip address entry and add it to the hw table
- * Return 0 if successful, otherwise return error
- */
-static enum i40iw_status_code i40iw_alloc_set_mac_ipaddr(struct i40iw_device *iwdev,
- u8 *macaddr)
-{
- enum i40iw_status_code status;
-
- status = i40iw_alloc_local_mac_ipaddr_entry(iwdev, &iwdev->mac_ip_table_idx);
- if (!status) {
- status = i40iw_add_mac_ipaddr_entry(iwdev, macaddr,
- (u8)iwdev->mac_ip_table_idx);
- if (status)
- i40iw_del_macip_entry(iwdev, (u8)iwdev->mac_ip_table_idx);
- }
- return status;
-}
-
-/**
- * i40iw_add_ipv6_addr - add ipv6 address to the hw arp table
- * @iwdev: iwarp device
- */
-static void i40iw_add_ipv6_addr(struct i40iw_device *iwdev)
-{
- struct net_device *ip_dev;
- struct inet6_dev *idev;
- struct inet6_ifaddr *ifp, *tmp;
- u32 local_ipaddr6[4];
-
- rcu_read_lock();
- for_each_netdev_rcu(&init_net, ip_dev) {
- if ((((rdma_vlan_dev_vlan_id(ip_dev) < 0xFFFF) &&
- (rdma_vlan_dev_real_dev(ip_dev) == iwdev->netdev)) ||
- (ip_dev == iwdev->netdev)) && (ip_dev->flags & IFF_UP)) {
- idev = __in6_dev_get(ip_dev);
- if (!idev) {
- i40iw_pr_err("ipv6 inet device not found\n");
- break;
- }
- list_for_each_entry_safe(ifp, tmp, &idev->addr_list, if_list) {
- i40iw_pr_info("IP=%pI6, vlan_id=%d, MAC=%pM\n", &ifp->addr,
- rdma_vlan_dev_vlan_id(ip_dev), ip_dev->dev_addr);
- i40iw_copy_ip_ntohl(local_ipaddr6,
- ifp->addr.in6_u.u6_addr32);
- i40iw_manage_arp_cache(iwdev,
- ip_dev->dev_addr,
- local_ipaddr6,
- false,
- I40IW_ARP_ADD);
- }
- }
- }
- rcu_read_unlock();
-}
-
-/**
- * i40iw_add_ipv4_addr - add ipv4 address to the hw arp table
- * @iwdev: iwarp device
- */
-static void i40iw_add_ipv4_addr(struct i40iw_device *iwdev)
-{
- struct net_device *dev;
- struct in_device *idev;
- u32 ip_addr;
-
- rcu_read_lock();
- for_each_netdev_rcu(&init_net, dev) {
- if ((((rdma_vlan_dev_vlan_id(dev) < 0xFFFF) &&
- (rdma_vlan_dev_real_dev(dev) == iwdev->netdev)) ||
- (dev == iwdev->netdev)) && (READ_ONCE(dev->flags) & IFF_UP)) {
- const struct in_ifaddr *ifa;
-
- idev = __in_dev_get_rcu(dev);
- if (!idev)
- continue;
- in_dev_for_each_ifa_rcu(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);
-
- ip_addr = ntohl(ifa->ifa_address);
- i40iw_manage_arp_cache(iwdev,
- dev->dev_addr,
- &ip_addr,
- true,
- I40IW_ARP_ADD);
- }
- }
- }
- rcu_read_unlock();
-}
-
-/**
- * i40iw_add_mac_ip - add mac and ip addresses
- * @iwdev: iwarp device
- *
- * Create and add a mac ip address entry to the hw table and
- * ipv4/ipv6 addresses to the arp cache
- * Return 0 if successful, otherwise return error
- */
-static enum i40iw_status_code i40iw_add_mac_ip(struct i40iw_device *iwdev)
-{
- struct net_device *netdev = iwdev->netdev;
- enum i40iw_status_code status;
-
- status = i40iw_alloc_set_mac_ipaddr(iwdev, (u8 *)netdev->dev_addr);
- if (status)
- return status;
- i40iw_add_ipv4_addr(iwdev);
- i40iw_add_ipv6_addr(iwdev);
- return 0;
-}
-
-/**
- * i40iw_wait_pe_ready - Check if firmware is ready
- * @hw: provides access to registers
- */
-static void i40iw_wait_pe_ready(struct i40iw_hw *hw)
-{
- u32 statusfw;
- u32 statuscpu0;
- u32 statuscpu1;
- u32 statuscpu2;
- u32 retrycount = 0;
-
- do {
- statusfw = i40iw_rd32(hw, I40E_GLPE_FWLDSTATUS);
- i40iw_pr_info("[%04d] fm load status[x%04X]\n", __LINE__, statusfw);
- statuscpu0 = i40iw_rd32(hw, I40E_GLPE_CPUSTATUS0);
- i40iw_pr_info("[%04d] CSR_CQP status[x%04X]\n", __LINE__, statuscpu0);
- statuscpu1 = i40iw_rd32(hw, I40E_GLPE_CPUSTATUS1);
- i40iw_pr_info("[%04d] I40E_GLPE_CPUSTATUS1 status[x%04X]\n",
- __LINE__, statuscpu1);
- statuscpu2 = i40iw_rd32(hw, I40E_GLPE_CPUSTATUS2);
- i40iw_pr_info("[%04d] I40E_GLPE_CPUSTATUS2 status[x%04X]\n",
- __LINE__, statuscpu2);
- if ((statuscpu0 == 0x80) && (statuscpu1 == 0x80) && (statuscpu2 == 0x80))
- break; /* SUCCESS */
- msleep(1000);
- retrycount++;
- } while (retrycount < 14);
- i40iw_wr32(hw, 0xb4040, 0x4C104C5);
-}
-
-/**
- * i40iw_initialize_dev - initialize device
- * @iwdev: iwarp device
- * @ldev: lan device information
- *
- * Allocate memory for the hmc objects and initialize iwdev
- * Return 0 if successful, otherwise clean up the resources
- * and return error
- */
-static enum i40iw_status_code i40iw_initialize_dev(struct i40iw_device *iwdev,
- struct i40e_info *ldev)
-{
- enum i40iw_status_code status;
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_device_init_info info;
- struct i40iw_vsi_init_info vsi_info;
- struct i40iw_dma_mem mem;
- struct i40iw_l2params l2params;
- u32 size;
- struct i40iw_vsi_stats_info stats_info;
- u16 last_qset = I40IW_NO_QSET;
- u16 qset;
- u32 i;
-
- memset(&l2params, 0, sizeof(l2params));
- memset(&info, 0, sizeof(info));
- size = sizeof(struct i40iw_hmc_pble_rsrc) + sizeof(struct i40iw_hmc_info) +
- (sizeof(struct i40iw_hmc_obj_info) * I40IW_HMC_IW_MAX);
- iwdev->hmc_info_mem = kzalloc(size, GFP_KERNEL);
- if (!iwdev->hmc_info_mem)
- return I40IW_ERR_NO_MEMORY;
-
- iwdev->pble_rsrc = (struct i40iw_hmc_pble_rsrc *)iwdev->hmc_info_mem;
- dev->hmc_info = &iwdev->hw.hmc;
- dev->hmc_info->hmc_obj = (struct i40iw_hmc_obj_info *)(iwdev->pble_rsrc + 1);
- status = i40iw_obj_aligned_mem(iwdev, &mem, I40IW_QUERY_FPM_BUF_SIZE,
- I40IW_FPM_QUERY_BUF_ALIGNMENT_MASK);
- if (status)
- goto error;
- info.fpm_query_buf_pa = mem.pa;
- info.fpm_query_buf = mem.va;
- status = i40iw_obj_aligned_mem(iwdev, &mem, I40IW_COMMIT_FPM_BUF_SIZE,
- I40IW_FPM_COMMIT_BUF_ALIGNMENT_MASK);
- if (status)
- goto error;
- info.fpm_commit_buf_pa = mem.pa;
- info.fpm_commit_buf = mem.va;
- info.hmc_fn_id = ldev->fid;
- info.is_pf = (ldev->ftype) ? false : true;
- info.bar0 = ldev->hw_addr;
- info.hw = &iwdev->hw;
- info.debug_mask = debug;
- l2params.mtu =
- (ldev->params.mtu) ? ldev->params.mtu : I40IW_DEFAULT_MTU;
- for (i = 0; i < I40E_CLIENT_MAX_USER_PRIORITY; i++) {
- qset = ldev->params.qos.prio_qos[i].qs_handle;
- l2params.qs_handle_list[i] = qset;
- if (last_qset == I40IW_NO_QSET)
- last_qset = qset;
- else if ((qset != last_qset) && (qset != I40IW_NO_QSET))
- iwdev->dcb = true;
- }
- i40iw_pr_info("DCB is set/clear = %d\n", iwdev->dcb);
- info.vchnl_send = i40iw_virtchnl_send;
- status = i40iw_device_init(&iwdev->sc_dev, &info);
-
- if (status)
- goto error;
- memset(&vsi_info, 0, sizeof(vsi_info));
- vsi_info.dev = &iwdev->sc_dev;
- vsi_info.back_vsi = (void *)iwdev;
- vsi_info.params = &l2params;
- vsi_info.exception_lan_queue = 1;
- i40iw_sc_vsi_init(&iwdev->vsi, &vsi_info);
-
- if (dev->is_pf) {
- memset(&stats_info, 0, sizeof(stats_info));
- stats_info.fcn_id = ldev->fid;
- stats_info.pestat = kzalloc(sizeof(*stats_info.pestat), GFP_KERNEL);
- if (!stats_info.pestat) {
- status = I40IW_ERR_NO_MEMORY;
- goto error;
- }
- stats_info.stats_initialize = true;
- if (stats_info.pestat)
- i40iw_vsi_stats_init(&iwdev->vsi, &stats_info);
- }
- return status;
-error:
- kfree(iwdev->hmc_info_mem);
- iwdev->hmc_info_mem = NULL;
- return status;
-}
-
-/**
- * i40iw_register_notifiers - register tcp ip notifiers
- */
-static void i40iw_register_notifiers(void)
-{
- register_inetaddr_notifier(&i40iw_inetaddr_notifier);
- register_inet6addr_notifier(&i40iw_inetaddr6_notifier);
- register_netevent_notifier(&i40iw_net_notifier);
- register_netdevice_notifier(&i40iw_netdevice_notifier);
-}
-
-/**
- * i40iw_unregister_notifiers - unregister tcp ip notifiers
- */
-
-static void i40iw_unregister_notifiers(void)
-{
- unregister_netevent_notifier(&i40iw_net_notifier);
- unregister_inetaddr_notifier(&i40iw_inetaddr_notifier);
- unregister_inet6addr_notifier(&i40iw_inetaddr6_notifier);
- unregister_netdevice_notifier(&i40iw_netdevice_notifier);
-}
-
-/**
- * i40iw_save_msix_info - copy msix vector information to iwarp device
- * @iwdev: iwarp device
- * @ldev: lan device information
- *
- * Allocate iwdev msix table and copy the ldev msix info to the table
- * Return 0 if successful, otherwise return error
- */
-static enum i40iw_status_code i40iw_save_msix_info(struct i40iw_device *iwdev,
- struct i40e_info *ldev)
-{
- struct i40e_qvlist_info *iw_qvlist;
- struct i40e_qv_info *iw_qvinfo;
- u32 ceq_idx;
- u32 i;
- u32 size;
-
- if (!ldev->msix_count) {
- i40iw_pr_err("No MSI-X vectors\n");
- return I40IW_ERR_CONFIG;
- }
-
- iwdev->msix_count = ldev->msix_count;
-
- size = sizeof(struct i40iw_msix_vector) * iwdev->msix_count;
- size += sizeof(struct i40e_qvlist_info);
- size += sizeof(struct i40e_qv_info) * iwdev->msix_count - 1;
- iwdev->iw_msixtbl = kzalloc(size, GFP_KERNEL);
-
- if (!iwdev->iw_msixtbl)
- return I40IW_ERR_NO_MEMORY;
- iwdev->iw_qvlist = (struct i40e_qvlist_info *)(&iwdev->iw_msixtbl[iwdev->msix_count]);
- iw_qvlist = iwdev->iw_qvlist;
- iw_qvinfo = iw_qvlist->qv_info;
- iw_qvlist->num_vectors = iwdev->msix_count;
- if (iwdev->msix_count <= num_online_cpus())
- iwdev->msix_shared = true;
- for (i = 0, ceq_idx = 0; i < iwdev->msix_count; i++, iw_qvinfo++) {
- iwdev->iw_msixtbl[i].idx = ldev->msix_entries[i].entry;
- iwdev->iw_msixtbl[i].irq = ldev->msix_entries[i].vector;
- iwdev->iw_msixtbl[i].cpu_affinity = ceq_idx;
- if (i == 0) {
- iw_qvinfo->aeq_idx = 0;
- if (iwdev->msix_shared)
- iw_qvinfo->ceq_idx = ceq_idx++;
- else
- iw_qvinfo->ceq_idx = I40E_QUEUE_INVALID_IDX;
- } else {
- iw_qvinfo->aeq_idx = I40E_QUEUE_INVALID_IDX;
- iw_qvinfo->ceq_idx = ceq_idx++;
- }
- iw_qvinfo->itr_idx = 3;
- iw_qvinfo->v_idx = iwdev->iw_msixtbl[i].idx;
- }
- return 0;
-}
-
-/**
- * i40iw_deinit_device - clean up the device resources
- * @iwdev: iwarp device
- *
- * Destroy the ib device interface, remove the mac ip entry and ipv4/ipv6 addresses,
- * destroy the device queues and free the pble and the hmc objects
- */
-static void i40iw_deinit_device(struct i40iw_device *iwdev)
-{
- struct i40e_info *ldev = iwdev->ldev;
-
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
-
- i40iw_pr_info("state = %d\n", iwdev->init_state);
- if (iwdev->param_wq)
- destroy_workqueue(iwdev->param_wq);
-
- switch (iwdev->init_state) {
- case RDMA_DEV_REGISTERED:
- iwdev->iw_status = 0;
- i40iw_port_ibevent(iwdev);
- i40iw_destroy_rdma_device(iwdev->iwibdev);
- fallthrough;
- case IP_ADDR_REGISTERED:
- if (!iwdev->reset)
- i40iw_del_macip_entry(iwdev, (u8)iwdev->mac_ip_table_idx);
- fallthrough;
- case PBLE_CHUNK_MEM:
- i40iw_destroy_pble_pool(dev, iwdev->pble_rsrc);
- fallthrough;
- case CEQ_CREATED:
- i40iw_dele_ceqs(iwdev);
- fallthrough;
- case AEQ_CREATED:
- i40iw_destroy_aeq(iwdev);
- fallthrough;
- case IEQ_CREATED:
- i40iw_puda_dele_resources(&iwdev->vsi, I40IW_PUDA_RSRC_TYPE_IEQ, iwdev->reset);
- fallthrough;
- case ILQ_CREATED:
- i40iw_puda_dele_resources(&iwdev->vsi, I40IW_PUDA_RSRC_TYPE_ILQ, iwdev->reset);
- fallthrough;
- case CCQ_CREATED:
- i40iw_destroy_ccq(iwdev);
- fallthrough;
- case HMC_OBJS_CREATED:
- i40iw_del_hmc_objects(dev, dev->hmc_info, true, iwdev->reset);
- fallthrough;
- case CQP_CREATED:
- i40iw_destroy_cqp(iwdev, true);
- fallthrough;
- case INITIAL_STATE:
- i40iw_cleanup_cm_core(&iwdev->cm_core);
- if (iwdev->vsi.pestat) {
- i40iw_vsi_stats_free(&iwdev->vsi);
- kfree(iwdev->vsi.pestat);
- }
- i40iw_del_init_mem(iwdev);
- break;
- case INVALID_STATE:
- default:
- i40iw_pr_err("bad init_state = %d\n", iwdev->init_state);
- break;
- }
-
- i40iw_del_handler(i40iw_find_i40e_handler(ldev));
- kfree(iwdev->hdl);
-}
-
-/**
- * i40iw_setup_init_state - set up the initial device struct
- * @hdl: handler for iwarp device - one per instance
- * @ldev: lan device information
- * @client: iwarp client information, provided during registration
- *
- * Initialize the iwarp device and its hdl information
- * using the ldev and client information
- * Return 0 if successful, otherwise return error
- */
-static enum i40iw_status_code i40iw_setup_init_state(struct i40iw_handler *hdl,
- struct i40e_info *ldev,
- struct i40e_client *client)
-{
- struct i40iw_device *iwdev = &hdl->device;
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- enum i40iw_status_code status;
-
- memcpy(&hdl->ldev, ldev, sizeof(*ldev));
-
- iwdev->mpa_version = mpa_version;
- iwdev->resource_profile = (resource_profile < I40IW_HMC_PROFILE_EQUAL) ?
- (u8)resource_profile + I40IW_HMC_PROFILE_DEFAULT :
- I40IW_HMC_PROFILE_DEFAULT;
- iwdev->max_rdma_vfs =
- (iwdev->resource_profile != I40IW_HMC_PROFILE_DEFAULT) ? max_rdma_vfs : 0;
- iwdev->max_enabled_vfs = iwdev->max_rdma_vfs;
- iwdev->netdev = ldev->netdev;
- hdl->client = client;
- if (!ldev->ftype)
- iwdev->db_start = pci_resource_start(ldev->pcidev, 0) + I40IW_DB_ADDR_OFFSET;
- else
- iwdev->db_start = pci_resource_start(ldev->pcidev, 0) + I40IW_VF_DB_ADDR_OFFSET;
-
- status = i40iw_save_msix_info(iwdev, ldev);
- if (status)
- return status;
- iwdev->hw.pcidev = ldev->pcidev;
- iwdev->hw.hw_addr = ldev->hw_addr;
- status = i40iw_allocate_dma_mem(&iwdev->hw,
- &iwdev->obj_mem, 8192, 4096);
- if (status)
- goto exit;
- iwdev->obj_next = iwdev->obj_mem;
-
- init_waitqueue_head(&iwdev->vchnl_waitq);
- init_waitqueue_head(&dev->vf_reqs);
- init_waitqueue_head(&iwdev->close_wq);
-
- status = i40iw_initialize_dev(iwdev, ldev);
-exit:
- if (status) {
- kfree(iwdev->iw_msixtbl);
- i40iw_free_dma_mem(dev->hw, &iwdev->obj_mem);
- iwdev->iw_msixtbl = NULL;
- }
- return status;
-}
-
-/**
- * i40iw_get_used_rsrc - determine resources used internally
- * @iwdev: iwarp device
- *
- * Called after internal allocations
- */
-static void i40iw_get_used_rsrc(struct i40iw_device *iwdev)
-{
- iwdev->used_pds = find_next_zero_bit(iwdev->allocated_pds, iwdev->max_pd, 0);
- iwdev->used_qps = find_next_zero_bit(iwdev->allocated_qps, iwdev->max_qp, 0);
- iwdev->used_cqs = find_next_zero_bit(iwdev->allocated_cqs, iwdev->max_cq, 0);
- iwdev->used_mrs = find_next_zero_bit(iwdev->allocated_mrs, iwdev->max_mr, 0);
-}
-
-/**
- * i40iw_open - client interface operation open for iwarp/uda device
- * @ldev: lan device information
- * @client: iwarp client information, provided during registration
- *
- * Called by the lan driver during the processing of client register
- * Create device resources, set up queues, pble and hmc objects and
- * register the device with the ib verbs interface
- * Return 0 if successful, otherwise return error
- */
-static int i40iw_open(struct i40e_info *ldev, struct i40e_client *client)
-{
- struct i40iw_device *iwdev;
- struct i40iw_sc_dev *dev;
- enum i40iw_status_code status;
- struct i40iw_handler *hdl;
-
- hdl = i40iw_find_netdev(ldev->netdev);
- if (hdl)
- return 0;
-
- hdl = kzalloc(sizeof(*hdl), GFP_KERNEL);
- if (!hdl)
- return -ENOMEM;
- iwdev = &hdl->device;
- iwdev->hdl = hdl;
- dev = &iwdev->sc_dev;
- if (i40iw_setup_cm_core(iwdev)) {
- kfree(iwdev->hdl);
- return -ENOMEM;
- }
-
- dev->back_dev = (void *)iwdev;
- iwdev->ldev = &hdl->ldev;
- iwdev->client = client;
- mutex_init(&iwdev->pbl_mutex);
- i40iw_add_handler(hdl);
-
- do {
- status = i40iw_setup_init_state(hdl, ldev, client);
- if (status)
- break;
- iwdev->init_state = INITIAL_STATE;
- if (dev->is_pf)
- i40iw_wait_pe_ready(dev->hw);
- status = i40iw_create_cqp(iwdev);
- if (status)
- break;
- iwdev->init_state = CQP_CREATED;
- status = i40iw_hmc_setup(iwdev);
- if (status)
- break;
- status = i40iw_create_ccq(iwdev);
- if (status)
- break;
- iwdev->init_state = CCQ_CREATED;
- status = i40iw_initialize_ilq(iwdev);
- if (status)
- break;
- iwdev->init_state = ILQ_CREATED;
- status = i40iw_initialize_ieq(iwdev);
- if (status)
- break;
- iwdev->init_state = IEQ_CREATED;
- status = i40iw_setup_aeq(iwdev);
- if (status)
- break;
- iwdev->init_state = AEQ_CREATED;
- status = i40iw_setup_ceqs(iwdev, ldev);
- if (status)
- break;
-
- status = i40iw_get_rdma_features(dev);
- if (status)
- dev->feature_info[I40IW_FEATURE_FW_INFO] =
- I40IW_FW_VER_DEFAULT;
-
- iwdev->init_state = CEQ_CREATED;
- status = i40iw_initialize_hw_resources(iwdev);
- if (status)
- break;
- i40iw_get_used_rsrc(iwdev);
- dev->ccq_ops->ccq_arm(dev->ccq);
- status = i40iw_hmc_init_pble(&iwdev->sc_dev, iwdev->pble_rsrc);
- if (status)
- break;
- iwdev->init_state = PBLE_CHUNK_MEM;
- iwdev->virtchnl_wq = alloc_ordered_workqueue("iwvch", WQ_MEM_RECLAIM);
- status = i40iw_add_mac_ip(iwdev);
- if (status)
- break;
- iwdev->init_state = IP_ADDR_REGISTERED;
- if (i40iw_register_rdma_device(iwdev)) {
- i40iw_pr_err("register rdma device fail\n");
- break;
- };
-
- iwdev->init_state = RDMA_DEV_REGISTERED;
- iwdev->iw_status = 1;
- i40iw_port_ibevent(iwdev);
- iwdev->param_wq = alloc_ordered_workqueue("l2params", WQ_MEM_RECLAIM);
- if(iwdev->param_wq == NULL)
- break;
- i40iw_pr_info("i40iw_open completed\n");
- return 0;
- } while (0);
-
- i40iw_pr_err("status = %d last completion = %d\n", status, iwdev->init_state);
- i40iw_deinit_device(iwdev);
- return -ERESTART;
-}
-
-/**
- * i40iw_l2params_worker - worker for l2 params change
- * @work: work pointer for l2 params
- */
-static void i40iw_l2params_worker(struct work_struct *work)
-{
- struct l2params_work *dwork =
- container_of(work, struct l2params_work, work);
- struct i40iw_device *iwdev = dwork->iwdev;
-
- i40iw_change_l2params(&iwdev->vsi, &dwork->l2params);
- atomic_dec(&iwdev->params_busy);
- kfree(work);
-}
-
-/**
- * i40iw_l2param_change - handle qs handles for qos and mss change
- * @ldev: lan device information
- * @client: client for paramater change
- * @params: new parameters from L2
- */
-static void i40iw_l2param_change(struct i40e_info *ldev, struct i40e_client *client,
- struct i40e_params *params)
-{
- struct i40iw_handler *hdl;
- struct i40iw_l2params *l2params;
- struct l2params_work *work;
- struct i40iw_device *iwdev;
- int i;
-
- hdl = i40iw_find_i40e_handler(ldev);
- if (!hdl)
- return;
-
- iwdev = &hdl->device;
-
- if (atomic_read(&iwdev->params_busy))
- return;
-
-
- work = kzalloc(sizeof(*work), GFP_KERNEL);
- if (!work)
- return;
-
- atomic_inc(&iwdev->params_busy);
-
- work->iwdev = iwdev;
- l2params = &work->l2params;
- for (i = 0; i < I40E_CLIENT_MAX_USER_PRIORITY; i++)
- l2params->qs_handle_list[i] = params->qos.prio_qos[i].qs_handle;
-
- l2params->mtu = (params->mtu) ? params->mtu : iwdev->vsi.mtu;
-
- INIT_WORK(&work->work, i40iw_l2params_worker);
- queue_work(iwdev->param_wq, &work->work);
-}
-
-/**
- * i40iw_close - client interface operation close for iwarp/uda device
- * @ldev: lan device information
- * @reset: true if called before reset
- * @client: client to close
- *
- * Called by the lan driver during the processing of client unregister
- * Destroy and clean up the driver resources
- */
-static void i40iw_close(struct i40e_info *ldev, struct i40e_client *client, bool reset)
-{
- struct i40iw_device *iwdev;
- struct i40iw_handler *hdl;
-
- hdl = i40iw_find_i40e_handler(ldev);
- if (!hdl)
- return;
-
- iwdev = &hdl->device;
- iwdev->closing = true;
-
- if (reset)
- iwdev->reset = true;
-
- i40iw_cm_teardown_connections(iwdev, NULL, NULL, true);
- destroy_workqueue(iwdev->virtchnl_wq);
- i40iw_deinit_device(iwdev);
-}
-
-/**
- * i40iw_vf_reset - process VF reset
- * @ldev: lan device information
- * @client: client interface instance
- * @vf_id: virtual function id
- *
- * Called when a VF is reset by the PF
- * Destroy and clean up the VF resources
- */
-static void i40iw_vf_reset(struct i40e_info *ldev, struct i40e_client *client, u32 vf_id)
-{
- struct i40iw_handler *hdl;
- struct i40iw_sc_dev *dev;
- struct i40iw_hmc_fcn_info hmc_fcn_info;
- struct i40iw_virt_mem vf_dev_mem;
- struct i40iw_vfdev *tmp_vfdev;
- unsigned int i;
- unsigned long flags;
- struct i40iw_device *iwdev;
-
- hdl = i40iw_find_i40e_handler(ldev);
- if (!hdl)
- return;
-
- dev = &hdl->device.sc_dev;
- iwdev = (struct i40iw_device *)dev->back_dev;
-
- for (i = 0; i < I40IW_MAX_PE_ENABLED_VF_COUNT; i++) {
- if (!dev->vf_dev[i] || (dev->vf_dev[i]->vf_id != vf_id))
- continue;
- /* free all resources allocated on behalf of vf */
- tmp_vfdev = dev->vf_dev[i];
- spin_lock_irqsave(&iwdev->vsi.pestat->lock, flags);
- dev->vf_dev[i] = NULL;
- spin_unlock_irqrestore(&iwdev->vsi.pestat->lock, flags);
- i40iw_del_hmc_objects(dev, &tmp_vfdev->hmc_info, false, false);
- /* remove vf hmc function */
- memset(&hmc_fcn_info, 0, sizeof(hmc_fcn_info));
- hmc_fcn_info.vf_id = vf_id;
- hmc_fcn_info.iw_vf_idx = tmp_vfdev->iw_vf_idx;
- hmc_fcn_info.free_fcn = true;
- i40iw_cqp_manage_hmc_fcn_cmd(dev, &hmc_fcn_info);
- /* free vf_dev */
- vf_dev_mem.va = tmp_vfdev;
- vf_dev_mem.size = sizeof(struct i40iw_vfdev) +
- sizeof(struct i40iw_hmc_obj_info) * I40IW_HMC_IW_MAX;
- i40iw_free_virt_mem(dev->hw, &vf_dev_mem);
- break;
- }
-}
-
-/**
- * i40iw_vf_enable - enable a number of VFs
- * @ldev: lan device information
- * @client: client interface instance
- * @num_vfs: number of VFs for the PF
- *
- * Called when the number of VFs changes
- */
-static void i40iw_vf_enable(struct i40e_info *ldev,
- struct i40e_client *client,
- u32 num_vfs)
-{
- struct i40iw_handler *hdl;
-
- hdl = i40iw_find_i40e_handler(ldev);
- if (!hdl)
- return;
-
- if (num_vfs > I40IW_MAX_PE_ENABLED_VF_COUNT)
- hdl->device.max_enabled_vfs = I40IW_MAX_PE_ENABLED_VF_COUNT;
- else
- hdl->device.max_enabled_vfs = num_vfs;
-}
-
-/**
- * i40iw_vf_capable - check if VF capable
- * @ldev: lan device information
- * @client: client interface instance
- * @vf_id: virtual function id
- *
- * Return 1 if a VF slot is available or if VF is already RDMA enabled
- * Return 0 otherwise
- */
-static int i40iw_vf_capable(struct i40e_info *ldev,
- struct i40e_client *client,
- u32 vf_id)
-{
- struct i40iw_handler *hdl;
- struct i40iw_sc_dev *dev;
- unsigned int i;
-
- hdl = i40iw_find_i40e_handler(ldev);
- if (!hdl)
- return 0;
-
- dev = &hdl->device.sc_dev;
-
- for (i = 0; i < hdl->device.max_enabled_vfs; i++) {
- if (!dev->vf_dev[i] || (dev->vf_dev[i]->vf_id == vf_id))
- return 1;
- }
-
- return 0;
-}
-
-/**
- * i40iw_virtchnl_receive - receive a message through the virtual channel
- * @ldev: lan device information
- * @client: client interface instance
- * @vf_id: virtual function id associated with the message
- * @msg: message buffer pointer
- * @len: length of the message
- *
- * Invoke virtual channel receive operation for the given msg
- * Return 0 if successful, otherwise return error
- */
-static int i40iw_virtchnl_receive(struct i40e_info *ldev,
- struct i40e_client *client,
- u32 vf_id,
- u8 *msg,
- u16 len)
-{
- struct i40iw_handler *hdl;
- struct i40iw_sc_dev *dev;
- struct i40iw_device *iwdev;
- int ret_code = I40IW_NOT_SUPPORTED;
-
- if (!len || !msg)
- return I40IW_ERR_PARAM;
-
- hdl = i40iw_find_i40e_handler(ldev);
- if (!hdl)
- return I40IW_ERR_PARAM;
-
- dev = &hdl->device.sc_dev;
- iwdev = dev->back_dev;
-
- if (dev->vchnl_if.vchnl_recv) {
- ret_code = dev->vchnl_if.vchnl_recv(dev, vf_id, msg, len);
- if (!dev->is_pf) {
- atomic_dec(&iwdev->vchnl_msgs);
- wake_up(&iwdev->vchnl_waitq);
- }
- }
- return ret_code;
-}
-
-/**
- * i40iw_vf_clear_to_send - wait to send virtual channel message
- * @dev: iwarp device *
- * Wait for until virtual channel is clear
- * before sending the next message
- *
- * Returns false if error
- * Returns true if clear to send
- */
-bool i40iw_vf_clear_to_send(struct i40iw_sc_dev *dev)
-{
- struct i40iw_device *iwdev;
- wait_queue_entry_t wait;
-
- iwdev = dev->back_dev;
-
- if (!wq_has_sleeper(&dev->vf_reqs) &&
- (atomic_read(&iwdev->vchnl_msgs) == 0))
- return true; /* virtual channel is clear */
-
- init_wait(&wait);
- add_wait_queue_exclusive(&dev->vf_reqs, &wait);
-
- if (!wait_event_timeout(dev->vf_reqs,
- (atomic_read(&iwdev->vchnl_msgs) == 0),
- I40IW_VCHNL_EVENT_TIMEOUT))
- dev->vchnl_up = false;
-
- remove_wait_queue(&dev->vf_reqs, &wait);
-
- return dev->vchnl_up;
-}
-
-/**
- * i40iw_virtchnl_send - send a message through the virtual channel
- * @dev: iwarp device
- * @vf_id: virtual function id associated with the message
- * @msg: virtual channel message buffer pointer
- * @len: length of the message
- *
- * Invoke virtual channel send operation for the given msg
- * Return 0 if successful, otherwise return error
- */
-static enum i40iw_status_code i40iw_virtchnl_send(struct i40iw_sc_dev *dev,
- u32 vf_id,
- u8 *msg,
- u16 len)
-{
- struct i40iw_device *iwdev;
- struct i40e_info *ldev;
-
- if (!dev || !dev->back_dev)
- return I40IW_ERR_BAD_PTR;
-
- iwdev = dev->back_dev;
- ldev = iwdev->ldev;
-
- if (ldev && ldev->ops && ldev->ops->virtchnl_send)
- return ldev->ops->virtchnl_send(ldev, &i40iw_client, vf_id, msg, len);
- return I40IW_ERR_BAD_PTR;
-}
-
-/* client interface functions */
-static const struct i40e_client_ops i40e_ops = {
- .open = i40iw_open,
- .close = i40iw_close,
- .l2_param_change = i40iw_l2param_change,
- .virtchnl_receive = i40iw_virtchnl_receive,
- .vf_reset = i40iw_vf_reset,
- .vf_enable = i40iw_vf_enable,
- .vf_capable = i40iw_vf_capable
-};
-
-/**
- * i40iw_init_module - driver initialization function
- *
- * First function to call when the driver is loaded
- * Register the driver as i40e client and port mapper client
- */
-static int __init i40iw_init_module(void)
-{
- int ret;
-
- memset(&i40iw_client, 0, sizeof(i40iw_client));
- i40iw_client.version.major = CLIENT_IW_INTERFACE_VERSION_MAJOR;
- i40iw_client.version.minor = CLIENT_IW_INTERFACE_VERSION_MINOR;
- i40iw_client.version.build = CLIENT_IW_INTERFACE_VERSION_BUILD;
- i40iw_client.ops = &i40e_ops;
- memcpy(i40iw_client.name, i40iw_client_name, I40E_CLIENT_STR_LENGTH);
- i40iw_client.type = I40E_CLIENT_IWARP;
- ret = i40e_register_client(&i40iw_client);
- i40iw_register_notifiers();
-
- return ret;
-}
-
-/**
- * i40iw_exit_module - driver exit clean up function
- *
- * The function is called just before the driver is unloaded
- * Unregister the driver as i40e client and port mapper client
- */
-static void __exit i40iw_exit_module(void)
-{
- i40iw_unregister_notifiers();
- i40e_unregister_client(&i40iw_client);
-}
-
-module_init(i40iw_init_module);
-module_exit(i40iw_exit_module);
diff --git a/drivers/infiniband/hw/i40iw/i40iw_osdep.h b/drivers/infiniband/hw/i40iw/i40iw_osdep.h
deleted file mode 100644
index d938ccb195b1..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_osdep.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_OSDEP_H
-#define I40IW_OSDEP_H
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/bitops.h>
-#include <net/tcp.h>
-#include <crypto/hash.h>
-/* get readq/writeq support for 32 bit kernels, use the low-first version */
-#include <linux/io-64-nonatomic-lo-hi.h>
-
-#define STATS_TIMER_DELAY 1000
-
-static inline void set_64bit_val(u64 *wqe_words, u32 byte_index, u64 value)
-{
- wqe_words[byte_index >> 3] = value;
-}
-
-/**
- * get_64bit_val - read 64 bit value from wqe
- * @wqe_words: wqe addr
- * @byte_index: index to read from
- * @value: read value
- **/
-static inline void get_64bit_val(u64 *wqe_words, u32 byte_index, u64 *value)
-{
- *value = wqe_words[byte_index >> 3];
-}
-
-struct i40iw_dma_mem {
- void *va;
- dma_addr_t pa;
- u32 size;
-} __packed;
-
-struct i40iw_virt_mem {
- void *va;
- u32 size;
-} __packed;
-
-#define i40iw_debug(h, m, s, ...) \
-do { \
- if (((m) & (h)->debug_mask)) \
- pr_info("i40iw " s, ##__VA_ARGS__); \
-} while (0)
-
-#define i40iw_flush(a) readl((a)->hw_addr + I40E_GLGEN_STAT)
-
-#define I40E_GLHMC_VFSDCMD(_i) (0x000C8000 + ((_i) * 4)) \
- /* _i=0...31 */
-#define I40E_GLHMC_VFSDCMD_MAX_INDEX 31
-#define I40E_GLHMC_VFSDCMD_PMSDIDX_SHIFT 0
-#define I40E_GLHMC_VFSDCMD_PMSDIDX_MASK (0xFFF \
- << I40E_GLHMC_VFSDCMD_PMSDIDX_SHIFT)
-#define I40E_GLHMC_VFSDCMD_PF_SHIFT 16
-#define I40E_GLHMC_VFSDCMD_PF_MASK (0xF << I40E_GLHMC_VFSDCMD_PF_SHIFT)
-#define I40E_GLHMC_VFSDCMD_VF_SHIFT 20
-#define I40E_GLHMC_VFSDCMD_VF_MASK (0x1FF << I40E_GLHMC_VFSDCMD_VF_SHIFT)
-#define I40E_GLHMC_VFSDCMD_PMF_TYPE_SHIFT 29
-#define I40E_GLHMC_VFSDCMD_PMF_TYPE_MASK (0x3 \
- << I40E_GLHMC_VFSDCMD_PMF_TYPE_SHIFT)
-#define I40E_GLHMC_VFSDCMD_PMSDWR_SHIFT 31
-#define I40E_GLHMC_VFSDCMD_PMSDWR_MASK (0x1 << I40E_GLHMC_VFSDCMD_PMSDWR_SHIFT)
-
-#define I40E_GLHMC_VFSDDATAHIGH(_i) (0x000C8200 + ((_i) * 4)) \
- /* _i=0...31 */
-#define I40E_GLHMC_VFSDDATAHIGH_MAX_INDEX 31
-#define I40E_GLHMC_VFSDDATAHIGH_PMSDDATAHIGH_SHIFT 0
-#define I40E_GLHMC_VFSDDATAHIGH_PMSDDATAHIGH_MASK (0xFFFFFFFF \
- << I40E_GLHMC_VFSDDATAHIGH_PMSDDATAHIGH_SHIFT)
-
-#define I40E_GLHMC_VFSDDATALOW(_i) (0x000C8100 + ((_i) * 4)) \
- /* _i=0...31 */
-#define I40E_GLHMC_VFSDDATALOW_MAX_INDEX 31
-#define I40E_GLHMC_VFSDDATALOW_PMSDVALID_SHIFT 0
-#define I40E_GLHMC_VFSDDATALOW_PMSDVALID_MASK (0x1 \
- << I40E_GLHMC_VFSDDATALOW_PMSDVALID_SHIFT)
-#define I40E_GLHMC_VFSDDATALOW_PMSDTYPE_SHIFT 1
-#define I40E_GLHMC_VFSDDATALOW_PMSDTYPE_MASK (0x1 \
- << I40E_GLHMC_VFSDDATALOW_PMSDTYPE_SHIFT)
-#define I40E_GLHMC_VFSDDATALOW_PMSDBPCOUNT_SHIFT 2
-#define I40E_GLHMC_VFSDDATALOW_PMSDBPCOUNT_MASK (0x3FF \
- << I40E_GLHMC_VFSDDATALOW_PMSDBPCOUNT_SHIFT)
-#define I40E_GLHMC_VFSDDATALOW_PMSDDATALOW_SHIFT 12
-#define I40E_GLHMC_VFSDDATALOW_PMSDDATALOW_MASK (0xFFFFF \
- << I40E_GLHMC_VFSDDATALOW_PMSDDATALOW_SHIFT)
-
-#define I40E_GLPE_FWLDSTATUS 0x0000D200
-#define I40E_GLPE_FWLDSTATUS_LOAD_REQUESTED_SHIFT 0
-#define I40E_GLPE_FWLDSTATUS_LOAD_REQUESTED_MASK (0x1 \
- << I40E_GLPE_FWLDSTATUS_LOAD_REQUESTED_SHIFT)
-#define I40E_GLPE_FWLDSTATUS_DONE_SHIFT 1
-#define I40E_GLPE_FWLDSTATUS_DONE_MASK (0x1 << I40E_GLPE_FWLDSTATUS_DONE_SHIFT)
-#define I40E_GLPE_FWLDSTATUS_CQP_FAIL_SHIFT 2
-#define I40E_GLPE_FWLDSTATUS_CQP_FAIL_MASK (0x1 \
- << I40E_GLPE_FWLDSTATUS_CQP_FAIL_SHIFT)
-#define I40E_GLPE_FWLDSTATUS_TEP_FAIL_SHIFT 3
-#define I40E_GLPE_FWLDSTATUS_TEP_FAIL_MASK (0x1 \
- << I40E_GLPE_FWLDSTATUS_TEP_FAIL_SHIFT)
-#define I40E_GLPE_FWLDSTATUS_OOP_FAIL_SHIFT 4
-#define I40E_GLPE_FWLDSTATUS_OOP_FAIL_MASK (0x1 \
- << I40E_GLPE_FWLDSTATUS_OOP_FAIL_SHIFT)
-
-struct i40iw_sc_dev;
-struct i40iw_sc_qp;
-struct i40iw_puda_buf;
-struct i40iw_puda_completion_info;
-struct i40iw_update_sds_info;
-struct i40iw_hmc_fcn_info;
-struct i40iw_virtchnl_work_info;
-struct i40iw_manage_vf_pble_info;
-struct i40iw_device;
-struct i40iw_hmc_info;
-struct i40iw_hw;
-
-u8 __iomem *i40iw_get_hw_addr(void *dev);
-void i40iw_ieq_mpa_crc_ae(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp);
-enum i40iw_status_code i40iw_vf_wait_vchnl_resp(struct i40iw_sc_dev *dev);
-bool i40iw_vf_clear_to_send(struct i40iw_sc_dev *dev);
-enum i40iw_status_code i40iw_ieq_check_mpacrc(struct shash_desc *desc, void *addr,
- u32 length, u32 value);
-struct i40iw_sc_qp *i40iw_ieq_get_qp(struct i40iw_sc_dev *dev, struct i40iw_puda_buf *buf);
-void i40iw_ieq_update_tcpip_info(struct i40iw_puda_buf *buf, u16 length, u32 seqnum);
-void i40iw_free_hash_desc(struct shash_desc *);
-enum i40iw_status_code i40iw_init_hash_desc(struct shash_desc **);
-enum i40iw_status_code i40iw_puda_get_tcpip_info(struct i40iw_puda_completion_info *info,
- struct i40iw_puda_buf *buf);
-enum i40iw_status_code i40iw_cqp_sds_cmd(struct i40iw_sc_dev *dev,
- struct i40iw_update_sds_info *info);
-enum i40iw_status_code i40iw_cqp_manage_hmc_fcn_cmd(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_fcn_info *hmcfcninfo);
-enum i40iw_status_code i40iw_cqp_query_fpm_values_cmd(struct i40iw_sc_dev *dev,
- struct i40iw_dma_mem *values_mem,
- u8 hmc_fn_id);
-enum i40iw_status_code i40iw_cqp_commit_fpm_values_cmd(struct i40iw_sc_dev *dev,
- struct i40iw_dma_mem *values_mem,
- u8 hmc_fn_id);
-enum i40iw_status_code i40iw_alloc_query_fpm_buf(struct i40iw_sc_dev *dev,
- struct i40iw_dma_mem *mem);
-enum i40iw_status_code i40iw_cqp_manage_vf_pble_bp(struct i40iw_sc_dev *dev,
- struct i40iw_manage_vf_pble_info *info);
-void i40iw_cqp_spawn_worker(struct i40iw_sc_dev *dev,
- struct i40iw_virtchnl_work_info *work_info, u32 iw_vf_idx);
-void *i40iw_remove_head(struct list_head *list);
-void i40iw_qp_suspend_resume(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp, bool suspend);
-
-void i40iw_term_modify_qp(struct i40iw_sc_qp *qp, u8 next_state, u8 term, u8 term_len);
-void i40iw_terminate_done(struct i40iw_sc_qp *qp, int timeout_occurred);
-void i40iw_terminate_start_timer(struct i40iw_sc_qp *qp);
-void i40iw_terminate_del_timer(struct i40iw_sc_qp *qp);
-
-enum i40iw_status_code i40iw_hw_manage_vf_pble_bp(struct i40iw_device *iwdev,
- struct i40iw_manage_vf_pble_info *info,
- bool wait);
-struct i40iw_sc_vsi;
-void i40iw_hw_stats_start_timer(struct i40iw_sc_vsi *vsi);
-void i40iw_hw_stats_stop_timer(struct i40iw_sc_vsi *vsi);
-#define i40iw_mmiowb() do { } while (0)
-void i40iw_wr32(struct i40iw_hw *hw, u32 reg, u32 value);
-u32 i40iw_rd32(struct i40iw_hw *hw, u32 reg);
-#endif /* _I40IW_OSDEP_H_ */
diff --git a/drivers/infiniband/hw/i40iw/i40iw_p.h b/drivers/infiniband/hw/i40iw/i40iw_p.h
deleted file mode 100644
index 4c429567bbb4..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_p.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_P_H
-#define I40IW_P_H
-
-#define PAUSE_TIMER_VALUE 0xFFFF
-#define REFRESH_THRESHOLD 0x7FFF
-#define HIGH_THRESHOLD 0x800
-#define LOW_THRESHOLD 0x200
-#define ALL_TC2PFC 0xFF
-#define CQP_COMPL_WAIT_TIME 0x3E8
-#define CQP_TIMEOUT_THRESHOLD 5
-
-void i40iw_debug_buf(struct i40iw_sc_dev *dev, enum i40iw_debug_flag mask,
- char *desc, u64 *buf, u32 size);
-/* init operations */
-enum i40iw_status_code i40iw_device_init(struct i40iw_sc_dev *dev,
- struct i40iw_device_init_info *info);
-
-void i40iw_sc_cqp_post_sq(struct i40iw_sc_cqp *cqp);
-
-u64 *i40iw_sc_cqp_get_next_send_wqe(struct i40iw_sc_cqp *cqp, u64 scratch);
-
-void i40iw_check_cqp_progress(struct i40iw_cqp_timeout *cqp_timeout, struct i40iw_sc_dev *dev);
-
-enum i40iw_status_code i40iw_sc_mr_fast_register(struct i40iw_sc_qp *qp,
- struct i40iw_fast_reg_stag_info *info,
- bool post_sq);
-
-void i40iw_insert_wqe_hdr(u64 *wqe, u64 header);
-
-/* HMC/FPM functions */
-enum i40iw_status_code i40iw_sc_init_iw_hmc(struct i40iw_sc_dev *dev,
- u8 hmc_fn_id);
-
-enum i40iw_status_code i40iw_pf_init_vfhmc(struct i40iw_sc_dev *dev, u8 vf_hmc_fn_id,
- u32 *vf_cnt_array);
-
-/* stats functions */
-void i40iw_hw_stats_refresh_all(struct i40iw_vsi_pestat *stats);
-void i40iw_hw_stats_read_all(struct i40iw_vsi_pestat *stats, struct i40iw_dev_hw_stats *stats_values);
-void i40iw_hw_stats_read_32(struct i40iw_vsi_pestat *stats,
- enum i40iw_hw_stats_index_32b index,
- u64 *value);
-void i40iw_hw_stats_read_64(struct i40iw_vsi_pestat *stats,
- enum i40iw_hw_stats_index_64b index,
- u64 *value);
-void i40iw_hw_stats_init(struct i40iw_vsi_pestat *stats, u8 index, bool is_pf);
-
-/* vsi misc functions */
-enum i40iw_status_code i40iw_vsi_stats_init(struct i40iw_sc_vsi *vsi, struct i40iw_vsi_stats_info *info);
-void i40iw_vsi_stats_free(struct i40iw_sc_vsi *vsi);
-void i40iw_sc_vsi_init(struct i40iw_sc_vsi *vsi, struct i40iw_vsi_init_info *info);
-
-void i40iw_change_l2params(struct i40iw_sc_vsi *vsi, struct i40iw_l2params *l2params);
-void i40iw_qp_add_qos(struct i40iw_sc_qp *qp);
-void i40iw_qp_rem_qos(struct i40iw_sc_qp *qp);
-void i40iw_terminate_send_fin(struct i40iw_sc_qp *qp);
-
-void i40iw_terminate_connection(struct i40iw_sc_qp *qp, struct i40iw_aeqe_info *info);
-
-void i40iw_terminate_received(struct i40iw_sc_qp *qp, struct i40iw_aeqe_info *info);
-
-enum i40iw_status_code i40iw_sc_suspend_qp(struct i40iw_sc_cqp *cqp,
- struct i40iw_sc_qp *qp, u64 scratch);
-
-enum i40iw_status_code i40iw_sc_resume_qp(struct i40iw_sc_cqp *cqp,
- struct i40iw_sc_qp *qp, u64 scratch);
-
-enum i40iw_status_code i40iw_sc_static_hmc_pages_allocated(struct i40iw_sc_cqp *cqp,
- u64 scratch, u8 hmc_fn_id,
- bool post_sq,
- bool poll_registers);
-
-enum i40iw_status_code i40iw_config_fpm_values(struct i40iw_sc_dev *dev, u32 qp_count);
-enum i40iw_status_code i40iw_get_rdma_features(struct i40iw_sc_dev *dev);
-
-void free_sd_mem(struct i40iw_sc_dev *dev);
-
-enum i40iw_status_code i40iw_process_cqp_cmd(struct i40iw_sc_dev *dev,
- struct cqp_commands_info *pcmdinfo);
-
-enum i40iw_status_code i40iw_process_bh(struct i40iw_sc_dev *dev);
-
-/* prototype for functions used for dynamic memory allocation */
-enum i40iw_status_code i40iw_allocate_dma_mem(struct i40iw_hw *hw,
- struct i40iw_dma_mem *mem, u64 size,
- u32 alignment);
-void i40iw_free_dma_mem(struct i40iw_hw *hw, struct i40iw_dma_mem *mem);
-enum i40iw_status_code i40iw_allocate_virt_mem(struct i40iw_hw *hw,
- struct i40iw_virt_mem *mem, u32 size);
-enum i40iw_status_code i40iw_free_virt_mem(struct i40iw_hw *hw,
- struct i40iw_virt_mem *mem);
-u8 i40iw_get_encoded_wqe_size(u32 wqsize, bool cqpsq);
-void i40iw_reinitialize_ieq(struct i40iw_sc_dev *dev);
-
-#endif
diff --git a/drivers/infiniband/hw/i40iw/i40iw_pble.c b/drivers/infiniband/hw/i40iw/i40iw_pble.c
deleted file mode 100644
index 146a4148219b..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_pble.c
+++ /dev/null
@@ -1,611 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 "i40iw_status.h"
-#include "i40iw_osdep.h"
-#include "i40iw_register.h"
-#include "i40iw_hmc.h"
-
-#include "i40iw_d.h"
-#include "i40iw_type.h"
-#include "i40iw_p.h"
-
-#include <linux/pci.h>
-#include <linux/genalloc.h>
-#include <linux/vmalloc.h>
-#include "i40iw_pble.h"
-#include "i40iw.h"
-
-struct i40iw_device;
-static enum i40iw_status_code add_pble_pool(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_pble_rsrc *pble_rsrc);
-static void i40iw_free_vmalloc_mem(struct i40iw_hw *hw, struct i40iw_chunk *chunk);
-
-/**
- * i40iw_destroy_pble_pool - destroy pool during module unload
- * @dev: i40iw_sc_dev struct
- * @pble_rsrc: pble resources
- */
-void i40iw_destroy_pble_pool(struct i40iw_sc_dev *dev, struct i40iw_hmc_pble_rsrc *pble_rsrc)
-{
- struct list_head *clist;
- struct list_head *tlist;
- struct i40iw_chunk *chunk;
- struct i40iw_pble_pool *pinfo = &pble_rsrc->pinfo;
-
- if (pinfo->pool) {
- list_for_each_safe(clist, tlist, &pinfo->clist) {
- chunk = list_entry(clist, struct i40iw_chunk, list);
- if (chunk->type == I40IW_VMALLOC)
- i40iw_free_vmalloc_mem(dev->hw, chunk);
- kfree(chunk);
- }
- gen_pool_destroy(pinfo->pool);
- }
-}
-
-/**
- * i40iw_hmc_init_pble - Initialize pble resources during module load
- * @dev: i40iw_sc_dev struct
- * @pble_rsrc: pble resources
- */
-enum i40iw_status_code i40iw_hmc_init_pble(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_pble_rsrc *pble_rsrc)
-{
- struct i40iw_hmc_info *hmc_info;
- u32 fpm_idx = 0;
-
- hmc_info = dev->hmc_info;
- pble_rsrc->fpm_base_addr = hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].base;
- /* Now start the pble' on 4k boundary */
- if (pble_rsrc->fpm_base_addr & 0xfff)
- fpm_idx = (PAGE_SIZE - (pble_rsrc->fpm_base_addr & 0xfff)) >> 3;
-
- pble_rsrc->unallocated_pble =
- hmc_info->hmc_obj[I40IW_HMC_IW_PBLE].cnt - fpm_idx;
- pble_rsrc->next_fpm_addr = pble_rsrc->fpm_base_addr + (fpm_idx << 3);
-
- pble_rsrc->pinfo.pool_shift = POOL_SHIFT;
- pble_rsrc->pinfo.pool = gen_pool_create(pble_rsrc->pinfo.pool_shift, -1);
- INIT_LIST_HEAD(&pble_rsrc->pinfo.clist);
- if (!pble_rsrc->pinfo.pool)
- goto error;
-
- if (add_pble_pool(dev, pble_rsrc))
- goto error;
-
- return 0;
-
- error:i40iw_destroy_pble_pool(dev, pble_rsrc);
- return I40IW_ERR_NO_MEMORY;
-}
-
-/**
- * get_sd_pd_idx - Returns sd index, pd index and rel_pd_idx from fpm address
- * @pble_rsrc: structure containing fpm address
- * @idx: where to return indexes
- */
-static inline void get_sd_pd_idx(struct i40iw_hmc_pble_rsrc *pble_rsrc,
- struct sd_pd_idx *idx)
-{
- idx->sd_idx = (u32)(pble_rsrc->next_fpm_addr) / I40IW_HMC_DIRECT_BP_SIZE;
- idx->pd_idx = (u32)(pble_rsrc->next_fpm_addr) / I40IW_HMC_PAGED_BP_SIZE;
- idx->rel_pd_idx = (idx->pd_idx % I40IW_HMC_PD_CNT_IN_SD);
-}
-
-/**
- * add_sd_direct - add sd direct for pble
- * @dev: hardware control device structure
- * @pble_rsrc: pble resource ptr
- * @info: page info for sd
- */
-static enum i40iw_status_code add_sd_direct(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_pble_rsrc *pble_rsrc,
- struct i40iw_add_page_info *info)
-{
- enum i40iw_status_code ret_code = 0;
- struct sd_pd_idx *idx = &info->idx;
- struct i40iw_chunk *chunk = info->chunk;
- struct i40iw_hmc_info *hmc_info = info->hmc_info;
- struct i40iw_hmc_sd_entry *sd_entry = info->sd_entry;
- u32 offset = 0;
-
- if (!sd_entry->valid) {
- if (dev->is_pf) {
- ret_code = i40iw_add_sd_table_entry(dev->hw, hmc_info,
- info->idx.sd_idx,
- I40IW_SD_TYPE_DIRECT,
- I40IW_HMC_DIRECT_BP_SIZE);
- if (ret_code)
- return ret_code;
- chunk->type = I40IW_DMA_COHERENT;
- }
- }
- offset = idx->rel_pd_idx << I40IW_HMC_PAGED_BP_SHIFT;
- chunk->size = info->pages << I40IW_HMC_PAGED_BP_SHIFT;
- chunk->vaddr = ((u8 *)sd_entry->u.bp.addr.va + offset);
- chunk->fpm_addr = pble_rsrc->next_fpm_addr;
- i40iw_debug(dev, I40IW_DEBUG_PBLE, "chunk_size[%d] = 0x%x vaddr=%p fpm_addr = %llx\n",
- chunk->size, chunk->size, chunk->vaddr, chunk->fpm_addr);
- return 0;
-}
-
-/**
- * i40iw_free_vmalloc_mem - free vmalloc during close
- * @hw: hw struct
- * @chunk: chunk information for vmalloc
- */
-static void i40iw_free_vmalloc_mem(struct i40iw_hw *hw, struct i40iw_chunk *chunk)
-{
- struct pci_dev *pcidev = hw->pcidev;
- int i;
-
- if (!chunk->pg_cnt)
- goto done;
- for (i = 0; i < chunk->pg_cnt; i++)
- dma_unmap_page(&pcidev->dev, chunk->dmaaddrs[i], PAGE_SIZE, DMA_BIDIRECTIONAL);
-
- done:
- kfree(chunk->dmaaddrs);
- chunk->dmaaddrs = NULL;
- vfree(chunk->vaddr);
- chunk->vaddr = NULL;
- chunk->type = 0;
-}
-
-/**
- * i40iw_get_vmalloc_mem - get 2M page for sd
- * @hw: hardware address
- * @chunk: chunk to adf
- * @pg_cnt: #of 4 K pages
- */
-static enum i40iw_status_code i40iw_get_vmalloc_mem(struct i40iw_hw *hw,
- struct i40iw_chunk *chunk,
- int pg_cnt)
-{
- struct pci_dev *pcidev = hw->pcidev;
- struct page *page;
- u8 *addr;
- u32 size;
- int i;
-
- chunk->dmaaddrs = kzalloc(pg_cnt << 3, GFP_KERNEL);
- if (!chunk->dmaaddrs)
- return I40IW_ERR_NO_MEMORY;
- size = PAGE_SIZE * pg_cnt;
- chunk->vaddr = vmalloc(size);
- if (!chunk->vaddr) {
- kfree(chunk->dmaaddrs);
- chunk->dmaaddrs = NULL;
- return I40IW_ERR_NO_MEMORY;
- }
- chunk->size = size;
- addr = (u8 *)chunk->vaddr;
- for (i = 0; i < pg_cnt; i++) {
- page = vmalloc_to_page((void *)addr);
- if (!page)
- break;
- chunk->dmaaddrs[i] = dma_map_page(&pcidev->dev, page, 0,
- PAGE_SIZE, DMA_BIDIRECTIONAL);
- if (dma_mapping_error(&pcidev->dev, chunk->dmaaddrs[i]))
- break;
- addr += PAGE_SIZE;
- }
-
- chunk->pg_cnt = i;
- chunk->type = I40IW_VMALLOC;
- if (i == pg_cnt)
- return 0;
-
- i40iw_free_vmalloc_mem(hw, chunk);
- return I40IW_ERR_NO_MEMORY;
-}
-
-/**
- * fpm_to_idx - given fpm address, get pble index
- * @pble_rsrc: pble resource management
- * @addr: fpm address for index
- */
-static inline u32 fpm_to_idx(struct i40iw_hmc_pble_rsrc *pble_rsrc, u64 addr)
-{
- return (addr - (pble_rsrc->fpm_base_addr)) >> 3;
-}
-
-/**
- * add_bp_pages - add backing pages for sd
- * @dev: hardware control device structure
- * @pble_rsrc: pble resource management
- * @info: page info for sd
- */
-static enum i40iw_status_code add_bp_pages(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_pble_rsrc *pble_rsrc,
- struct i40iw_add_page_info *info)
-{
- u8 *addr;
- struct i40iw_dma_mem mem;
- struct i40iw_hmc_pd_entry *pd_entry;
- struct i40iw_hmc_sd_entry *sd_entry = info->sd_entry;
- struct i40iw_hmc_info *hmc_info = info->hmc_info;
- struct i40iw_chunk *chunk = info->chunk;
- struct i40iw_manage_vf_pble_info vf_pble_info;
- enum i40iw_status_code status = 0;
- u32 rel_pd_idx = info->idx.rel_pd_idx;
- u32 pd_idx = info->idx.pd_idx;
- u32 i;
-
- status = i40iw_get_vmalloc_mem(dev->hw, chunk, info->pages);
- if (status)
- return I40IW_ERR_NO_MEMORY;
- status = i40iw_add_sd_table_entry(dev->hw, hmc_info,
- info->idx.sd_idx, I40IW_SD_TYPE_PAGED,
- I40IW_HMC_DIRECT_BP_SIZE);
- if (status)
- goto error;
- if (!dev->is_pf) {
- status = i40iw_vchnl_vf_add_hmc_objs(dev, I40IW_HMC_IW_PBLE,
- fpm_to_idx(pble_rsrc,
- pble_rsrc->next_fpm_addr),
- (info->pages << PBLE_512_SHIFT));
- if (status) {
- i40iw_pr_err("allocate PBLEs in the PF. Error %i\n", status);
- goto error;
- }
- }
- addr = chunk->vaddr;
- for (i = 0; i < info->pages; i++) {
- mem.pa = chunk->dmaaddrs[i];
- mem.size = PAGE_SIZE;
- mem.va = (void *)(addr);
- pd_entry = &sd_entry->u.pd_table.pd_entry[rel_pd_idx++];
- if (!pd_entry->valid) {
- status = i40iw_add_pd_table_entry(dev->hw, hmc_info, pd_idx++, &mem);
- if (status)
- goto error;
- addr += PAGE_SIZE;
- } else {
- i40iw_pr_err("pd entry is valid expecting to be invalid\n");
- }
- }
- if (!dev->is_pf) {
- vf_pble_info.first_pd_index = info->idx.rel_pd_idx;
- vf_pble_info.inv_pd_ent = false;
- vf_pble_info.pd_entry_cnt = PBLE_PER_PAGE;
- vf_pble_info.pd_pl_pba = sd_entry->u.pd_table.pd_page_addr.pa;
- vf_pble_info.sd_index = info->idx.sd_idx;
- status = i40iw_hw_manage_vf_pble_bp(dev->back_dev,
- &vf_pble_info, true);
- if (status) {
- i40iw_pr_err("CQP manage VF PBLE BP failed. %i\n", status);
- goto error;
- }
- }
- chunk->fpm_addr = pble_rsrc->next_fpm_addr;
- return 0;
-error:
- i40iw_free_vmalloc_mem(dev->hw, chunk);
- return status;
-}
-
-/**
- * add_pble_pool - add a sd entry for pble resoure
- * @dev: hardware control device structure
- * @pble_rsrc: pble resource management
- */
-static enum i40iw_status_code add_pble_pool(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_pble_rsrc *pble_rsrc)
-{
- struct i40iw_hmc_sd_entry *sd_entry;
- struct i40iw_hmc_info *hmc_info;
- struct i40iw_chunk *chunk;
- struct i40iw_add_page_info info;
- struct sd_pd_idx *idx = &info.idx;
- enum i40iw_status_code ret_code = 0;
- enum i40iw_sd_entry_type sd_entry_type;
- u64 sd_reg_val = 0;
- u32 pages;
-
- if (pble_rsrc->unallocated_pble < PBLE_PER_PAGE)
- return I40IW_ERR_NO_MEMORY;
- if (pble_rsrc->next_fpm_addr & 0xfff) {
- i40iw_pr_err("next fpm_addr %llx\n", pble_rsrc->next_fpm_addr);
- return I40IW_ERR_INVALID_PAGE_DESC_INDEX;
- }
- chunk = kzalloc(sizeof(*chunk), GFP_KERNEL);
- if (!chunk)
- return I40IW_ERR_NO_MEMORY;
- hmc_info = dev->hmc_info;
- chunk->fpm_addr = pble_rsrc->next_fpm_addr;
- get_sd_pd_idx(pble_rsrc, idx);
- sd_entry = &hmc_info->sd_table.sd_entry[idx->sd_idx];
- pages = (idx->rel_pd_idx) ? (I40IW_HMC_PD_CNT_IN_SD -
- idx->rel_pd_idx) : I40IW_HMC_PD_CNT_IN_SD;
- pages = min(pages, pble_rsrc->unallocated_pble >> PBLE_512_SHIFT);
- info.chunk = chunk;
- info.hmc_info = hmc_info;
- info.pages = pages;
- info.sd_entry = sd_entry;
- if (!sd_entry->valid) {
- sd_entry_type = (!idx->rel_pd_idx &&
- (pages == I40IW_HMC_PD_CNT_IN_SD) &&
- dev->is_pf) ? I40IW_SD_TYPE_DIRECT : I40IW_SD_TYPE_PAGED;
- } else {
- sd_entry_type = sd_entry->entry_type;
- }
- i40iw_debug(dev, I40IW_DEBUG_PBLE,
- "pages = %d, unallocated_pble[%u] current_fpm_addr = %llx\n",
- pages, pble_rsrc->unallocated_pble, pble_rsrc->next_fpm_addr);
- i40iw_debug(dev, I40IW_DEBUG_PBLE, "sd_entry_type = %d sd_entry valid = %d\n",
- sd_entry_type, sd_entry->valid);
-
- if (sd_entry_type == I40IW_SD_TYPE_DIRECT)
- ret_code = add_sd_direct(dev, pble_rsrc, &info);
- if (ret_code)
- sd_entry_type = I40IW_SD_TYPE_PAGED;
- else
- pble_rsrc->stats_direct_sds++;
-
- if (sd_entry_type == I40IW_SD_TYPE_PAGED) {
- ret_code = add_bp_pages(dev, pble_rsrc, &info);
- if (ret_code)
- goto error;
- else
- pble_rsrc->stats_paged_sds++;
- }
-
- if (gen_pool_add_virt(pble_rsrc->pinfo.pool, (unsigned long)chunk->vaddr,
- (phys_addr_t)chunk->fpm_addr, chunk->size, -1)) {
- i40iw_pr_err("could not allocate memory by gen_pool_addr_virt()\n");
- ret_code = I40IW_ERR_NO_MEMORY;
- goto error;
- }
- pble_rsrc->next_fpm_addr += chunk->size;
- i40iw_debug(dev, I40IW_DEBUG_PBLE, "next_fpm_addr = %llx chunk_size[%u] = 0x%x\n",
- pble_rsrc->next_fpm_addr, chunk->size, chunk->size);
- pble_rsrc->unallocated_pble -= (chunk->size >> 3);
- sd_reg_val = (sd_entry_type == I40IW_SD_TYPE_PAGED) ?
- sd_entry->u.pd_table.pd_page_addr.pa : sd_entry->u.bp.addr.pa;
- if (dev->is_pf && !sd_entry->valid) {
- ret_code = i40iw_hmc_sd_one(dev, hmc_info->hmc_fn_id,
- sd_reg_val, idx->sd_idx,
- sd_entry->entry_type, true);
- if (ret_code) {
- i40iw_pr_err("cqp cmd failed for sd (pbles)\n");
- goto error;
- }
- }
-
- sd_entry->valid = true;
- list_add(&chunk->list, &pble_rsrc->pinfo.clist);
- return 0;
- error:
- kfree(chunk);
- return ret_code;
-}
-
-/**
- * free_lvl2 - fee level 2 pble
- * @pble_rsrc: pble resource management
- * @palloc: level 2 pble allocation
- */
-static void free_lvl2(struct i40iw_hmc_pble_rsrc *pble_rsrc,
- struct i40iw_pble_alloc *palloc)
-{
- u32 i;
- struct gen_pool *pool;
- struct i40iw_pble_level2 *lvl2 = &palloc->level2;
- struct i40iw_pble_info *root = &lvl2->root;
- struct i40iw_pble_info *leaf = lvl2->leaf;
-
- pool = pble_rsrc->pinfo.pool;
-
- for (i = 0; i < lvl2->leaf_cnt; i++, leaf++) {
- if (leaf->addr)
- gen_pool_free(pool, leaf->addr, (leaf->cnt << 3));
- else
- break;
- }
-
- if (root->addr)
- gen_pool_free(pool, root->addr, (root->cnt << 3));
-
- kfree(lvl2->leaf);
- lvl2->leaf = NULL;
-}
-
-/**
- * get_lvl2_pble - get level 2 pble resource
- * @pble_rsrc: pble resource management
- * @palloc: level 2 pble allocation
- * @pool: pool pointer
- */
-static enum i40iw_status_code get_lvl2_pble(struct i40iw_hmc_pble_rsrc *pble_rsrc,
- struct i40iw_pble_alloc *palloc,
- struct gen_pool *pool)
-{
- u32 lf4k, lflast, total, i;
- u32 pblcnt = PBLE_PER_PAGE;
- u64 *addr;
- struct i40iw_pble_level2 *lvl2 = &palloc->level2;
- struct i40iw_pble_info *root = &lvl2->root;
- struct i40iw_pble_info *leaf;
-
- /* number of full 512 (4K) leafs) */
- lf4k = palloc->total_cnt >> 9;
- lflast = palloc->total_cnt % PBLE_PER_PAGE;
- total = (lflast == 0) ? lf4k : lf4k + 1;
- lvl2->leaf_cnt = total;
-
- leaf = kzalloc((sizeof(*leaf) * total), GFP_ATOMIC);
- if (!leaf)
- return I40IW_ERR_NO_MEMORY;
- lvl2->leaf = leaf;
- /* allocate pbles for the root */
- root->addr = gen_pool_alloc(pool, (total << 3));
- if (!root->addr) {
- kfree(lvl2->leaf);
- lvl2->leaf = NULL;
- return I40IW_ERR_NO_MEMORY;
- }
- root->idx = fpm_to_idx(pble_rsrc,
- (u64)gen_pool_virt_to_phys(pool, root->addr));
- root->cnt = total;
- addr = (u64 *)root->addr;
- for (i = 0; i < total; i++, leaf++) {
- pblcnt = (lflast && ((i + 1) == total)) ? lflast : PBLE_PER_PAGE;
- leaf->addr = gen_pool_alloc(pool, (pblcnt << 3));
- if (!leaf->addr)
- goto error;
- leaf->idx = fpm_to_idx(pble_rsrc, (u64)gen_pool_virt_to_phys(pool, leaf->addr));
-
- leaf->cnt = pblcnt;
- *addr = (u64)leaf->idx;
- addr++;
- }
- palloc->level = I40IW_LEVEL_2;
- pble_rsrc->stats_lvl2++;
- return 0;
- error:
- free_lvl2(pble_rsrc, palloc);
- return I40IW_ERR_NO_MEMORY;
-}
-
-/**
- * get_lvl1_pble - get level 1 pble resource
- * @dev: hardware control device structure
- * @pble_rsrc: pble resource management
- * @palloc: level 1 pble allocation
- */
-static enum i40iw_status_code get_lvl1_pble(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_pble_rsrc *pble_rsrc,
- struct i40iw_pble_alloc *palloc)
-{
- u64 *addr;
- struct gen_pool *pool;
- struct i40iw_pble_info *lvl1 = &palloc->level1;
-
- pool = pble_rsrc->pinfo.pool;
- addr = (u64 *)gen_pool_alloc(pool, (palloc->total_cnt << 3));
-
- if (!addr)
- return I40IW_ERR_NO_MEMORY;
-
- palloc->level = I40IW_LEVEL_1;
- lvl1->addr = (unsigned long)addr;
- lvl1->idx = fpm_to_idx(pble_rsrc, (u64)gen_pool_virt_to_phys(pool,
- (unsigned long)addr));
- lvl1->cnt = palloc->total_cnt;
- pble_rsrc->stats_lvl1++;
- return 0;
-}
-
-/**
- * get_lvl1_lvl2_pble - calls get_lvl1 and get_lvl2 pble routine
- * @dev: i40iw_sc_dev struct
- * @pble_rsrc: pble resources
- * @palloc: contains all inforamtion regarding pble (idx + pble addr)
- * @pool: pointer to general purpose special memory pool descriptor
- */
-static inline enum i40iw_status_code get_lvl1_lvl2_pble(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_pble_rsrc *pble_rsrc,
- struct i40iw_pble_alloc *palloc,
- struct gen_pool *pool)
-{
- enum i40iw_status_code status = 0;
-
- status = get_lvl1_pble(dev, pble_rsrc, palloc);
- if (status && (palloc->total_cnt > PBLE_PER_PAGE))
- status = get_lvl2_pble(pble_rsrc, palloc, pool);
- return status;
-}
-
-/**
- * i40iw_get_pble - allocate pbles from the pool
- * @dev: i40iw_sc_dev struct
- * @pble_rsrc: pble resources
- * @palloc: contains all inforamtion regarding pble (idx + pble addr)
- * @pble_cnt: #of pbles requested
- */
-enum i40iw_status_code i40iw_get_pble(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_pble_rsrc *pble_rsrc,
- struct i40iw_pble_alloc *palloc,
- u32 pble_cnt)
-{
- struct gen_pool *pool;
- enum i40iw_status_code status = 0;
- u32 max_sds = 0;
- int i;
-
- pool = pble_rsrc->pinfo.pool;
- palloc->total_cnt = pble_cnt;
- palloc->level = I40IW_LEVEL_0;
- /*check first to see if we can get pble's without acquiring additional sd's */
- status = get_lvl1_lvl2_pble(dev, pble_rsrc, palloc, pool);
- if (!status)
- goto exit;
- max_sds = (palloc->total_cnt >> 18) + 1;
- for (i = 0; i < max_sds; i++) {
- status = add_pble_pool(dev, pble_rsrc);
- if (status)
- break;
- status = get_lvl1_lvl2_pble(dev, pble_rsrc, palloc, pool);
- if (!status)
- break;
- }
-exit:
- if (!status)
- pble_rsrc->stats_alloc_ok++;
- else
- pble_rsrc->stats_alloc_fail++;
-
- return status;
-}
-
-/**
- * i40iw_free_pble - put pbles back into pool
- * @pble_rsrc: pble resources
- * @palloc: contains all inforamtion regarding pble resource being freed
- */
-void i40iw_free_pble(struct i40iw_hmc_pble_rsrc *pble_rsrc,
- struct i40iw_pble_alloc *palloc)
-{
- struct gen_pool *pool;
-
- pool = pble_rsrc->pinfo.pool;
- if (palloc->level == I40IW_LEVEL_2)
- free_lvl2(pble_rsrc, palloc);
- else
- gen_pool_free(pool, palloc->level1.addr,
- (palloc->level1.cnt << 3));
- pble_rsrc->stats_alloc_freed++;
-}
diff --git a/drivers/infiniband/hw/i40iw/i40iw_pble.h b/drivers/infiniband/hw/i40iw/i40iw_pble.h
deleted file mode 100644
index 7b1851d21cc0..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_pble.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_PBLE_H
-#define I40IW_PBLE_H
-
-#define POOL_SHIFT 6
-#define PBLE_PER_PAGE 512
-#define I40IW_HMC_PAGED_BP_SHIFT 12
-#define PBLE_512_SHIFT 9
-
-enum i40iw_pble_level {
- I40IW_LEVEL_0 = 0,
- I40IW_LEVEL_1 = 1,
- I40IW_LEVEL_2 = 2
-};
-
-enum i40iw_alloc_type {
- I40IW_NO_ALLOC = 0,
- I40IW_DMA_COHERENT = 1,
- I40IW_VMALLOC = 2
-};
-
-struct i40iw_pble_info {
- unsigned long addr;
- u32 idx;
- u32 cnt;
-};
-
-struct i40iw_pble_level2 {
- struct i40iw_pble_info root;
- struct i40iw_pble_info *leaf;
- u32 leaf_cnt;
-};
-
-struct i40iw_pble_alloc {
- u32 total_cnt;
- enum i40iw_pble_level level;
- union {
- struct i40iw_pble_info level1;
- struct i40iw_pble_level2 level2;
- };
-};
-
-struct sd_pd_idx {
- u32 sd_idx;
- u32 pd_idx;
- u32 rel_pd_idx;
-};
-
-struct i40iw_add_page_info {
- struct i40iw_chunk *chunk;
- struct i40iw_hmc_sd_entry *sd_entry;
- struct i40iw_hmc_info *hmc_info;
- struct sd_pd_idx idx;
- u32 pages;
-};
-
-struct i40iw_chunk {
- struct list_head list;
- u32 size;
- void *vaddr;
- u64 fpm_addr;
- u32 pg_cnt;
- dma_addr_t *dmaaddrs;
- enum i40iw_alloc_type type;
-};
-
-struct i40iw_pble_pool {
- struct gen_pool *pool;
- struct list_head clist;
- u32 total_pble_alloc;
- u32 free_pble_cnt;
- u32 pool_shift;
-};
-
-struct i40iw_hmc_pble_rsrc {
- u32 unallocated_pble;
- u64 fpm_base_addr;
- u64 next_fpm_addr;
- struct i40iw_pble_pool pinfo;
-
- u32 stats_direct_sds;
- u32 stats_paged_sds;
- u64 stats_alloc_ok;
- u64 stats_alloc_fail;
- u64 stats_alloc_freed;
- u64 stats_lvl1;
- u64 stats_lvl2;
-};
-
-void i40iw_destroy_pble_pool(struct i40iw_sc_dev *dev, struct i40iw_hmc_pble_rsrc *pble_rsrc);
-enum i40iw_status_code i40iw_hmc_init_pble(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_pble_rsrc *pble_rsrc);
-void i40iw_free_pble(struct i40iw_hmc_pble_rsrc *pble_rsrc, struct i40iw_pble_alloc *palloc);
-enum i40iw_status_code i40iw_get_pble(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_pble_rsrc *pble_rsrc,
- struct i40iw_pble_alloc *palloc,
- u32 pble_cnt);
-#endif
diff --git a/drivers/infiniband/hw/i40iw/i40iw_puda.c b/drivers/infiniband/hw/i40iw/i40iw_puda.c
deleted file mode 100644
index 88fb68e866ba..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_puda.c
+++ /dev/null
@@ -1,1496 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 "i40iw_osdep.h"
-#include "i40iw_register.h"
-#include "i40iw_status.h"
-#include "i40iw_hmc.h"
-
-#include "i40iw_d.h"
-#include "i40iw_type.h"
-#include "i40iw_p.h"
-#include "i40iw_puda.h"
-
-static void i40iw_ieq_receive(struct i40iw_sc_vsi *vsi,
- struct i40iw_puda_buf *buf);
-static void i40iw_ieq_tx_compl(struct i40iw_sc_vsi *vsi, void *sqwrid);
-static void i40iw_ilq_putback_rcvbuf(struct i40iw_sc_qp *qp, u32 wqe_idx);
-static enum i40iw_status_code i40iw_puda_replenish_rq(struct i40iw_puda_rsrc
- *rsrc, bool initial);
-/**
- * i40iw_puda_get_listbuf - get buffer from puda list
- * @list: list to use for buffers (ILQ or IEQ)
- */
-static struct i40iw_puda_buf *i40iw_puda_get_listbuf(struct list_head *list)
-{
- struct i40iw_puda_buf *buf = NULL;
-
- if (!list_empty(list)) {
- buf = (struct i40iw_puda_buf *)list->next;
- list_del((struct list_head *)&buf->list);
- }
- return buf;
-}
-
-/**
- * i40iw_puda_get_bufpool - return buffer from resource
- * @rsrc: resource to use for buffer
- */
-struct i40iw_puda_buf *i40iw_puda_get_bufpool(struct i40iw_puda_rsrc *rsrc)
-{
- struct i40iw_puda_buf *buf = NULL;
- struct list_head *list = &rsrc->bufpool;
- unsigned long flags;
-
- spin_lock_irqsave(&rsrc->bufpool_lock, flags);
- buf = i40iw_puda_get_listbuf(list);
- if (buf)
- rsrc->avail_buf_count--;
- else
- rsrc->stats_buf_alloc_fail++;
- spin_unlock_irqrestore(&rsrc->bufpool_lock, flags);
- return buf;
-}
-
-/**
- * i40iw_puda_ret_bufpool - return buffer to rsrc list
- * @rsrc: resource to use for buffer
- * @buf: buffe to return to resouce
- */
-void i40iw_puda_ret_bufpool(struct i40iw_puda_rsrc *rsrc,
- struct i40iw_puda_buf *buf)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&rsrc->bufpool_lock, flags);
- list_add(&buf->list, &rsrc->bufpool);
- spin_unlock_irqrestore(&rsrc->bufpool_lock, flags);
- rsrc->avail_buf_count++;
-}
-
-/**
- * i40iw_puda_post_recvbuf - set wqe for rcv buffer
- * @rsrc: resource ptr
- * @wqe_idx: wqe index to use
- * @buf: puda buffer for rcv q
- * @initial: flag if during init time
- */
-static void i40iw_puda_post_recvbuf(struct i40iw_puda_rsrc *rsrc, u32 wqe_idx,
- struct i40iw_puda_buf *buf, bool initial)
-{
- u64 *wqe;
- struct i40iw_sc_qp *qp = &rsrc->qp;
- u64 offset24 = 0;
-
- qp->qp_uk.rq_wrid_array[wqe_idx] = (uintptr_t)buf;
- wqe = qp->qp_uk.rq_base[wqe_idx].elem;
- i40iw_debug(rsrc->dev, I40IW_DEBUG_PUDA,
- "%s: wqe_idx= %d buf = %p wqe = %p\n", __func__,
- wqe_idx, buf, wqe);
- if (!initial)
- get_64bit_val(wqe, 24, &offset24);
-
- offset24 = (offset24) ? 0 : LS_64(1, I40IWQPSQ_VALID);
-
- set_64bit_val(wqe, 0, buf->mem.pa);
- set_64bit_val(wqe, 8,
- LS_64(buf->mem.size, I40IWQPSQ_FRAG_LEN));
- i40iw_insert_wqe_hdr(wqe, offset24);
-}
-
-/**
- * i40iw_puda_replenish_rq - post rcv buffers
- * @rsrc: resource to use for buffer
- * @initial: flag if during init time
- */
-static enum i40iw_status_code i40iw_puda_replenish_rq(struct i40iw_puda_rsrc *rsrc,
- bool initial)
-{
- u32 i;
- u32 invalid_cnt = rsrc->rxq_invalid_cnt;
- struct i40iw_puda_buf *buf = NULL;
-
- for (i = 0; i < invalid_cnt; i++) {
- buf = i40iw_puda_get_bufpool(rsrc);
- if (!buf)
- return I40IW_ERR_list_empty;
- i40iw_puda_post_recvbuf(rsrc, rsrc->rx_wqe_idx, buf,
- initial);
- rsrc->rx_wqe_idx =
- ((rsrc->rx_wqe_idx + 1) % rsrc->rq_size);
- rsrc->rxq_invalid_cnt--;
- }
- return 0;
-}
-
-/**
- * i40iw_puda_alloc_buf - allocate mem for buffer
- * @dev: iwarp device
- * @length: length of buffer
- */
-static struct i40iw_puda_buf *i40iw_puda_alloc_buf(struct i40iw_sc_dev *dev,
- u32 length)
-{
- struct i40iw_puda_buf *buf = NULL;
- struct i40iw_virt_mem buf_mem;
- enum i40iw_status_code ret;
-
- ret = i40iw_allocate_virt_mem(dev->hw, &buf_mem,
- sizeof(struct i40iw_puda_buf));
- if (ret) {
- i40iw_debug(dev, I40IW_DEBUG_PUDA,
- "%s: error mem for buf\n", __func__);
- return NULL;
- }
- buf = (struct i40iw_puda_buf *)buf_mem.va;
- ret = i40iw_allocate_dma_mem(dev->hw, &buf->mem, length, 1);
- if (ret) {
- i40iw_debug(dev, I40IW_DEBUG_PUDA,
- "%s: error dma mem for buf\n", __func__);
- i40iw_free_virt_mem(dev->hw, &buf_mem);
- return NULL;
- }
- buf->buf_mem.va = buf_mem.va;
- buf->buf_mem.size = buf_mem.size;
- return buf;
-}
-
-/**
- * i40iw_puda_dele_buf - delete buffer back to system
- * @dev: iwarp device
- * @buf: buffer to free
- */
-static void i40iw_puda_dele_buf(struct i40iw_sc_dev *dev,
- struct i40iw_puda_buf *buf)
-{
- i40iw_free_dma_mem(dev->hw, &buf->mem);
- i40iw_free_virt_mem(dev->hw, &buf->buf_mem);
-}
-
-/**
- * i40iw_puda_get_next_send_wqe - return next wqe for processing
- * @qp: puda qp for wqe
- * @wqe_idx: wqe index for caller
- */
-static u64 *i40iw_puda_get_next_send_wqe(struct i40iw_qp_uk *qp, u32 *wqe_idx)
-{
- u64 *wqe = NULL;
- enum i40iw_status_code ret_code = 0;
-
- *wqe_idx = I40IW_RING_GETCURRENT_HEAD(qp->sq_ring);
- if (!*wqe_idx)
- qp->swqe_polarity = !qp->swqe_polarity;
- I40IW_RING_MOVE_HEAD(qp->sq_ring, ret_code);
- if (ret_code)
- return wqe;
- wqe = qp->sq_base[*wqe_idx].elem;
-
- return wqe;
-}
-
-/**
- * i40iw_puda_poll_info - poll cq for completion
- * @cq: cq for poll
- * @info: info return for successful completion
- */
-static enum i40iw_status_code i40iw_puda_poll_info(struct i40iw_sc_cq *cq,
- struct i40iw_puda_completion_info *info)
-{
- u64 qword0, qword2, qword3;
- u64 *cqe;
- u64 comp_ctx;
- bool valid_bit;
- u32 major_err, minor_err;
- bool error;
-
- cqe = (u64 *)I40IW_GET_CURRENT_CQ_ELEMENT(&cq->cq_uk);
- get_64bit_val(cqe, 24, &qword3);
- valid_bit = (bool)RS_64(qword3, I40IW_CQ_VALID);
-
- if (valid_bit != cq->cq_uk.polarity)
- return I40IW_ERR_QUEUE_EMPTY;
-
- i40iw_debug_buf(cq->dev, I40IW_DEBUG_PUDA, "PUDA CQE", cqe, 32);
- error = (bool)RS_64(qword3, I40IW_CQ_ERROR);
- if (error) {
- i40iw_debug(cq->dev, I40IW_DEBUG_PUDA, "%s receive error\n", __func__);
- major_err = (u32)(RS_64(qword3, I40IW_CQ_MAJERR));
- minor_err = (u32)(RS_64(qword3, I40IW_CQ_MINERR));
- info->compl_error = major_err << 16 | minor_err;
- return I40IW_ERR_CQ_COMPL_ERROR;
- }
-
- get_64bit_val(cqe, 0, &qword0);
- get_64bit_val(cqe, 16, &qword2);
-
- info->q_type = (u8)RS_64(qword3, I40IW_CQ_SQ);
- info->qp_id = (u32)RS_64(qword2, I40IWCQ_QPID);
-
- get_64bit_val(cqe, 8, &comp_ctx);
- info->qp = (struct i40iw_qp_uk *)(unsigned long)comp_ctx;
- info->wqe_idx = (u32)RS_64(qword3, I40IW_CQ_WQEIDX);
-
- if (info->q_type == I40IW_CQE_QTYPE_RQ) {
- info->vlan_valid = (bool)RS_64(qword3, I40IW_VLAN_TAG_VALID);
- info->l4proto = (u8)RS_64(qword2, I40IW_UDA_L4PROTO);
- info->l3proto = (u8)RS_64(qword2, I40IW_UDA_L3PROTO);
- info->payload_len = (u16)RS_64(qword0, I40IW_UDA_PAYLOADLEN);
- }
-
- return 0;
-}
-
-/**
- * i40iw_puda_poll_completion - processes completion for cq
- * @dev: iwarp device
- * @cq: cq getting interrupt
- * @compl_err: return any completion err
- */
-enum i40iw_status_code i40iw_puda_poll_completion(struct i40iw_sc_dev *dev,
- struct i40iw_sc_cq *cq, u32 *compl_err)
-{
- struct i40iw_qp_uk *qp;
- struct i40iw_cq_uk *cq_uk = &cq->cq_uk;
- struct i40iw_puda_completion_info info;
- enum i40iw_status_code ret = 0;
- struct i40iw_puda_buf *buf;
- struct i40iw_puda_rsrc *rsrc;
- void *sqwrid;
- u8 cq_type = cq->cq_type;
- unsigned long flags;
-
- if ((cq_type == I40IW_CQ_TYPE_ILQ) || (cq_type == I40IW_CQ_TYPE_IEQ)) {
- rsrc = (cq_type == I40IW_CQ_TYPE_ILQ) ? cq->vsi->ilq : cq->vsi->ieq;
- } else {
- i40iw_debug(dev, I40IW_DEBUG_PUDA, "%s qp_type error\n", __func__);
- return I40IW_ERR_BAD_PTR;
- }
- memset(&info, 0, sizeof(info));
- ret = i40iw_puda_poll_info(cq, &info);
- *compl_err = info.compl_error;
- if (ret == I40IW_ERR_QUEUE_EMPTY)
- return ret;
- if (ret)
- goto done;
-
- qp = info.qp;
- if (!qp || !rsrc) {
- ret = I40IW_ERR_BAD_PTR;
- goto done;
- }
-
- if (qp->qp_id != rsrc->qp_id) {
- ret = I40IW_ERR_BAD_PTR;
- goto done;
- }
-
- if (info.q_type == I40IW_CQE_QTYPE_RQ) {
- buf = (struct i40iw_puda_buf *)(uintptr_t)qp->rq_wrid_array[info.wqe_idx];
- /* Get all the tcpip information in the buf header */
- ret = i40iw_puda_get_tcpip_info(&info, buf);
- if (ret) {
- rsrc->stats_rcvd_pkt_err++;
- if (cq_type == I40IW_CQ_TYPE_ILQ) {
- i40iw_ilq_putback_rcvbuf(&rsrc->qp,
- info.wqe_idx);
- } else {
- i40iw_puda_ret_bufpool(rsrc, buf);
- i40iw_puda_replenish_rq(rsrc, false);
- }
- goto done;
- }
-
- rsrc->stats_pkt_rcvd++;
- rsrc->compl_rxwqe_idx = info.wqe_idx;
- i40iw_debug(dev, I40IW_DEBUG_PUDA, "%s RQ completion\n", __func__);
- rsrc->receive(rsrc->vsi, buf);
- if (cq_type == I40IW_CQ_TYPE_ILQ)
- i40iw_ilq_putback_rcvbuf(&rsrc->qp, info.wqe_idx);
- else
- i40iw_puda_replenish_rq(rsrc, false);
-
- } else {
- i40iw_debug(dev, I40IW_DEBUG_PUDA, "%s SQ completion\n", __func__);
- sqwrid = (void *)(uintptr_t)qp->sq_wrtrk_array[info.wqe_idx].wrid;
- I40IW_RING_SET_TAIL(qp->sq_ring, info.wqe_idx);
- rsrc->xmit_complete(rsrc->vsi, sqwrid);
- spin_lock_irqsave(&rsrc->bufpool_lock, flags);
- rsrc->tx_wqe_avail_cnt++;
- spin_unlock_irqrestore(&rsrc->bufpool_lock, flags);
- if (!list_empty(&rsrc->txpend))
- i40iw_puda_send_buf(rsrc, NULL);
- }
-
-done:
- I40IW_RING_MOVE_HEAD(cq_uk->cq_ring, ret);
- if (I40IW_RING_GETCURRENT_HEAD(cq_uk->cq_ring) == 0)
- cq_uk->polarity = !cq_uk->polarity;
- /* update cq tail in cq shadow memory also */
- I40IW_RING_MOVE_TAIL(cq_uk->cq_ring);
- set_64bit_val(cq_uk->shadow_area, 0,
- I40IW_RING_GETCURRENT_HEAD(cq_uk->cq_ring));
- return 0;
-}
-
-/**
- * i40iw_puda_send - complete send wqe for transmit
- * @qp: puda qp for send
- * @info: buffer information for transmit
- */
-enum i40iw_status_code i40iw_puda_send(struct i40iw_sc_qp *qp,
- struct i40iw_puda_send_info *info)
-{
- u64 *wqe;
- u32 iplen, l4len;
- u64 header[2];
- u32 wqe_idx;
- u8 iipt;
-
- /* number of 32 bits DWORDS in header */
- l4len = info->tcplen >> 2;
- if (info->ipv4) {
- iipt = 3;
- iplen = 5;
- } else {
- iipt = 1;
- iplen = 10;
- }
-
- wqe = i40iw_puda_get_next_send_wqe(&qp->qp_uk, &wqe_idx);
- if (!wqe)
- return I40IW_ERR_QP_TOOMANY_WRS_POSTED;
- qp->qp_uk.sq_wrtrk_array[wqe_idx].wrid = (uintptr_t)info->scratch;
- /* Third line of WQE descriptor */
- /* maclen is in words */
- header[0] = LS_64((info->maclen >> 1), I40IW_UDA_QPSQ_MACLEN) |
- LS_64(iplen, I40IW_UDA_QPSQ_IPLEN) | LS_64(1, I40IW_UDA_QPSQ_L4T) |
- LS_64(iipt, I40IW_UDA_QPSQ_IIPT) |
- LS_64(l4len, I40IW_UDA_QPSQ_L4LEN);
- /* Forth line of WQE descriptor */
- header[1] = LS_64(I40IW_OP_TYPE_SEND, I40IW_UDA_QPSQ_OPCODE) |
- LS_64(1, I40IW_UDA_QPSQ_SIGCOMPL) |
- LS_64(info->doloopback, I40IW_UDA_QPSQ_DOLOOPBACK) |
- LS_64(qp->qp_uk.swqe_polarity, I40IW_UDA_QPSQ_VALID);
-
- set_64bit_val(wqe, 0, info->paddr);
- set_64bit_val(wqe, 8, LS_64(info->len, I40IWQPSQ_FRAG_LEN));
- set_64bit_val(wqe, 16, header[0]);
-
- i40iw_insert_wqe_hdr(wqe, header[1]);
-
- i40iw_debug_buf(qp->dev, I40IW_DEBUG_PUDA, "PUDA SEND WQE", wqe, 32);
- i40iw_qp_post_wr(&qp->qp_uk);
- return 0;
-}
-
-/**
- * i40iw_puda_send_buf - transmit puda buffer
- * @rsrc: resource to use for buffer
- * @buf: puda buffer to transmit
- */
-void i40iw_puda_send_buf(struct i40iw_puda_rsrc *rsrc, struct i40iw_puda_buf *buf)
-{
- struct i40iw_puda_send_info info;
- enum i40iw_status_code ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&rsrc->bufpool_lock, flags);
- /* if no wqe available or not from a completion and we have
- * pending buffers, we must queue new buffer
- */
- if (!rsrc->tx_wqe_avail_cnt || (buf && !list_empty(&rsrc->txpend))) {
- list_add_tail(&buf->list, &rsrc->txpend);
- spin_unlock_irqrestore(&rsrc->bufpool_lock, flags);
- rsrc->stats_sent_pkt_q++;
- if (rsrc->type == I40IW_PUDA_RSRC_TYPE_ILQ)
- i40iw_debug(rsrc->dev, I40IW_DEBUG_PUDA,
- "%s: adding to txpend\n", __func__);
- return;
- }
- rsrc->tx_wqe_avail_cnt--;
- /* if we are coming from a completion and have pending buffers
- * then Get one from pending list
- */
- if (!buf) {
- buf = i40iw_puda_get_listbuf(&rsrc->txpend);
- if (!buf)
- goto done;
- }
-
- info.scratch = (void *)buf;
- info.paddr = buf->mem.pa;
- info.len = buf->totallen;
- info.tcplen = buf->tcphlen;
- info.maclen = buf->maclen;
- info.ipv4 = buf->ipv4;
- info.doloopback = (rsrc->type == I40IW_PUDA_RSRC_TYPE_IEQ);
-
- ret = i40iw_puda_send(&rsrc->qp, &info);
- if (ret) {
- rsrc->tx_wqe_avail_cnt++;
- rsrc->stats_sent_pkt_q++;
- list_add(&buf->list, &rsrc->txpend);
- if (rsrc->type == I40IW_PUDA_RSRC_TYPE_ILQ)
- i40iw_debug(rsrc->dev, I40IW_DEBUG_PUDA,
- "%s: adding to puda_send\n", __func__);
- } else {
- rsrc->stats_pkt_sent++;
- }
-done:
- spin_unlock_irqrestore(&rsrc->bufpool_lock, flags);
-}
-
-/**
- * i40iw_puda_qp_setctx - during init, set qp's context
- * @rsrc: qp's resource
- */
-static void i40iw_puda_qp_setctx(struct i40iw_puda_rsrc *rsrc)
-{
- struct i40iw_sc_qp *qp = &rsrc->qp;
- u64 *qp_ctx = qp->hw_host_ctx;
-
- set_64bit_val(qp_ctx, 8, qp->sq_pa);
- set_64bit_val(qp_ctx, 16, qp->rq_pa);
-
- set_64bit_val(qp_ctx, 24,
- LS_64(qp->hw_rq_size, I40IWQPC_RQSIZE) |
- LS_64(qp->hw_sq_size, I40IWQPC_SQSIZE));
-
- set_64bit_val(qp_ctx, 48, LS_64(rsrc->buf_size, I40IW_UDA_QPC_MAXFRAMESIZE));
- set_64bit_val(qp_ctx, 56, 0);
- set_64bit_val(qp_ctx, 64, 1);
-
- set_64bit_val(qp_ctx, 136,
- LS_64(rsrc->cq_id, I40IWQPC_TXCQNUM) |
- LS_64(rsrc->cq_id, I40IWQPC_RXCQNUM));
-
- set_64bit_val(qp_ctx, 160, LS_64(1, I40IWQPC_PRIVEN));
-
- set_64bit_val(qp_ctx, 168,
- LS_64((uintptr_t)qp, I40IWQPC_QPCOMPCTX));
-
- set_64bit_val(qp_ctx, 176,
- LS_64(qp->sq_tph_val, I40IWQPC_SQTPHVAL) |
- LS_64(qp->rq_tph_val, I40IWQPC_RQTPHVAL) |
- LS_64(qp->qs_handle, I40IWQPC_QSHANDLE));
-
- i40iw_debug_buf(rsrc->dev, I40IW_DEBUG_PUDA, "PUDA QP CONTEXT",
- qp_ctx, I40IW_QP_CTX_SIZE);
-}
-
-/**
- * i40iw_puda_qp_wqe - setup wqe for qp create
- * @dev: iwarp device
- * @qp: resource for qp
- */
-static enum i40iw_status_code i40iw_puda_qp_wqe(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp)
-{
- struct i40iw_sc_cqp *cqp;
- u64 *wqe;
- u64 header;
- struct i40iw_ccq_cqe_info compl_info;
- enum i40iw_status_code status = 0;
-
- cqp = dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, 0);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- set_64bit_val(wqe, 16, qp->hw_host_ctx_pa);
- set_64bit_val(wqe, 40, qp->shadow_area_pa);
- header = qp->qp_uk.qp_id |
- LS_64(I40IW_CQP_OP_CREATE_QP, I40IW_CQPSQ_OPCODE) |
- LS_64(I40IW_QP_TYPE_UDA, I40IW_CQPSQ_QP_QPTYPE) |
- LS_64(1, I40IW_CQPSQ_QP_CQNUMVALID) |
- LS_64(2, I40IW_CQPSQ_QP_NEXTIWSTATE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
-
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_PUDA, "PUDA CQE", wqe, 32);
- i40iw_sc_cqp_post_sq(cqp);
- status = dev->cqp_ops->poll_for_cqp_op_done(dev->cqp,
- I40IW_CQP_OP_CREATE_QP,
- &compl_info);
- return status;
-}
-
-/**
- * i40iw_puda_qp_create - create qp for resource
- * @rsrc: resource to use for buffer
- */
-static enum i40iw_status_code i40iw_puda_qp_create(struct i40iw_puda_rsrc *rsrc)
-{
- struct i40iw_sc_qp *qp = &rsrc->qp;
- struct i40iw_qp_uk *ukqp = &qp->qp_uk;
- enum i40iw_status_code ret = 0;
- u32 sq_size, rq_size, t_size;
- struct i40iw_dma_mem *mem;
-
- sq_size = rsrc->sq_size * I40IW_QP_WQE_MIN_SIZE;
- rq_size = rsrc->rq_size * I40IW_QP_WQE_MIN_SIZE;
- t_size = (sq_size + rq_size + (I40IW_SHADOW_AREA_SIZE << 3) +
- I40IW_QP_CTX_SIZE);
- /* Get page aligned memory */
- ret =
- i40iw_allocate_dma_mem(rsrc->dev->hw, &rsrc->qpmem, t_size,
- I40IW_HW_PAGE_SIZE);
- if (ret) {
- i40iw_debug(rsrc->dev, I40IW_DEBUG_PUDA, "%s: error dma mem\n", __func__);
- return ret;
- }
-
- mem = &rsrc->qpmem;
- memset(mem->va, 0, t_size);
- qp->hw_sq_size = i40iw_get_encoded_wqe_size(rsrc->sq_size, false);
- qp->hw_rq_size = i40iw_get_encoded_wqe_size(rsrc->rq_size, false);
- qp->pd = &rsrc->sc_pd;
- qp->qp_type = I40IW_QP_TYPE_UDA;
- qp->dev = rsrc->dev;
- qp->back_qp = (void *)rsrc;
- qp->sq_pa = mem->pa;
- qp->rq_pa = qp->sq_pa + sq_size;
- qp->vsi = rsrc->vsi;
- ukqp->sq_base = mem->va;
- ukqp->rq_base = &ukqp->sq_base[rsrc->sq_size];
- ukqp->shadow_area = ukqp->rq_base[rsrc->rq_size].elem;
- qp->shadow_area_pa = qp->rq_pa + rq_size;
- qp->hw_host_ctx = ukqp->shadow_area + I40IW_SHADOW_AREA_SIZE;
- qp->hw_host_ctx_pa =
- qp->shadow_area_pa + (I40IW_SHADOW_AREA_SIZE << 3);
- ukqp->qp_id = rsrc->qp_id;
- ukqp->sq_wrtrk_array = rsrc->sq_wrtrk_array;
- ukqp->rq_wrid_array = rsrc->rq_wrid_array;
-
- ukqp->qp_id = rsrc->qp_id;
- ukqp->sq_size = rsrc->sq_size;
- ukqp->rq_size = rsrc->rq_size;
-
- I40IW_RING_INIT(ukqp->sq_ring, ukqp->sq_size);
- I40IW_RING_INIT(ukqp->initial_ring, ukqp->sq_size);
- I40IW_RING_INIT(ukqp->rq_ring, ukqp->rq_size);
-
- if (qp->pd->dev->is_pf)
- ukqp->wqe_alloc_reg = (u32 __iomem *)(i40iw_get_hw_addr(qp->pd->dev) +
- I40E_PFPE_WQEALLOC);
- else
- ukqp->wqe_alloc_reg = (u32 __iomem *)(i40iw_get_hw_addr(qp->pd->dev) +
- I40E_VFPE_WQEALLOC1);
-
- qp->user_pri = 0;
- i40iw_qp_add_qos(qp);
- i40iw_puda_qp_setctx(rsrc);
- if (rsrc->dev->ceq_valid)
- ret = i40iw_cqp_qp_create_cmd(rsrc->dev, qp);
- else
- ret = i40iw_puda_qp_wqe(rsrc->dev, qp);
- if (ret) {
- i40iw_qp_rem_qos(qp);
- i40iw_free_dma_mem(rsrc->dev->hw, &rsrc->qpmem);
- }
- return ret;
-}
-
-/**
- * i40iw_puda_cq_wqe - setup wqe for cq create
- * @dev: iwarp device
- * @cq: cq to setup
- */
-static enum i40iw_status_code i40iw_puda_cq_wqe(struct i40iw_sc_dev *dev, struct i40iw_sc_cq *cq)
-{
- u64 *wqe;
- struct i40iw_sc_cqp *cqp;
- u64 header;
- struct i40iw_ccq_cqe_info compl_info;
- enum i40iw_status_code status = 0;
-
- cqp = dev->cqp;
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, 0);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- set_64bit_val(wqe, 0, cq->cq_uk.cq_size);
- set_64bit_val(wqe, 8, RS_64_1(cq, 1));
- set_64bit_val(wqe, 16,
- LS_64(cq->shadow_read_threshold,
- I40IW_CQPSQ_CQ_SHADOW_READ_THRESHOLD));
- set_64bit_val(wqe, 32, cq->cq_pa);
-
- set_64bit_val(wqe, 40, cq->shadow_area_pa);
-
- header = cq->cq_uk.cq_id |
- LS_64(I40IW_CQP_OP_CREATE_CQ, I40IW_CQPSQ_OPCODE) |
- LS_64(1, I40IW_CQPSQ_CQ_CHKOVERFLOW) |
- LS_64(1, I40IW_CQPSQ_CQ_ENCEQEMASK) |
- LS_64(1, I40IW_CQPSQ_CQ_CEQIDVALID) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
- i40iw_insert_wqe_hdr(wqe, header);
-
- i40iw_debug_buf(dev, I40IW_DEBUG_PUDA, "PUDA CQE",
- wqe, I40IW_CQP_WQE_SIZE * 8);
-
- i40iw_sc_cqp_post_sq(dev->cqp);
- status = dev->cqp_ops->poll_for_cqp_op_done(dev->cqp,
- I40IW_CQP_OP_CREATE_CQ,
- &compl_info);
- return status;
-}
-
-/**
- * i40iw_puda_cq_create - create cq for resource
- * @rsrc: resource for which cq to create
- */
-static enum i40iw_status_code i40iw_puda_cq_create(struct i40iw_puda_rsrc *rsrc)
-{
- struct i40iw_sc_dev *dev = rsrc->dev;
- struct i40iw_sc_cq *cq = &rsrc->cq;
- enum i40iw_status_code ret = 0;
- u32 tsize, cqsize;
- struct i40iw_dma_mem *mem;
- struct i40iw_cq_init_info info;
- struct i40iw_cq_uk_init_info *init_info = &info.cq_uk_init_info;
-
- cq->vsi = rsrc->vsi;
- cqsize = rsrc->cq_size * (sizeof(struct i40iw_cqe));
- tsize = cqsize + sizeof(struct i40iw_cq_shadow_area);
- ret = i40iw_allocate_dma_mem(dev->hw, &rsrc->cqmem, tsize,
- I40IW_CQ0_ALIGNMENT);
- if (ret)
- return ret;
-
- mem = &rsrc->cqmem;
- memset(&info, 0, sizeof(info));
- info.dev = dev;
- info.type = (rsrc->type == I40IW_PUDA_RSRC_TYPE_ILQ) ?
- I40IW_CQ_TYPE_ILQ : I40IW_CQ_TYPE_IEQ;
- info.shadow_read_threshold = rsrc->cq_size >> 2;
- info.ceq_id_valid = true;
- info.cq_base_pa = mem->pa;
- info.shadow_area_pa = mem->pa + cqsize;
- init_info->cq_base = mem->va;
- init_info->shadow_area = (u64 *)((u8 *)mem->va + cqsize);
- init_info->cq_size = rsrc->cq_size;
- init_info->cq_id = rsrc->cq_id;
- info.ceqe_mask = true;
- info.ceq_id_valid = true;
- ret = dev->iw_priv_cq_ops->cq_init(cq, &info);
- if (ret)
- goto error;
- if (rsrc->dev->ceq_valid)
- ret = i40iw_cqp_cq_create_cmd(dev, cq);
- else
- ret = i40iw_puda_cq_wqe(dev, cq);
-error:
- if (ret)
- i40iw_free_dma_mem(dev->hw, &rsrc->cqmem);
- return ret;
-}
-
-/**
- * i40iw_puda_free_qp - free qp for resource
- * @rsrc: resource for which qp to free
- */
-static void i40iw_puda_free_qp(struct i40iw_puda_rsrc *rsrc)
-{
- enum i40iw_status_code ret;
- struct i40iw_ccq_cqe_info compl_info;
- struct i40iw_sc_dev *dev = rsrc->dev;
-
- if (rsrc->dev->ceq_valid) {
- i40iw_cqp_qp_destroy_cmd(dev, &rsrc->qp);
- return;
- }
-
- ret = dev->iw_priv_qp_ops->qp_destroy(&rsrc->qp,
- 0, false, true, true);
- if (ret)
- i40iw_debug(dev, I40IW_DEBUG_PUDA,
- "%s error puda qp destroy wqe\n",
- __func__);
-
- if (!ret) {
- ret = dev->cqp_ops->poll_for_cqp_op_done(dev->cqp,
- I40IW_CQP_OP_DESTROY_QP,
- &compl_info);
- if (ret)
- i40iw_debug(dev, I40IW_DEBUG_PUDA,
- "%s error puda qp destroy failed\n",
- __func__);
- }
-}
-
-/**
- * i40iw_puda_free_cq - free cq for resource
- * @rsrc: resource for which cq to free
- */
-static void i40iw_puda_free_cq(struct i40iw_puda_rsrc *rsrc)
-{
- enum i40iw_status_code ret;
- struct i40iw_ccq_cqe_info compl_info;
- struct i40iw_sc_dev *dev = rsrc->dev;
-
- if (rsrc->dev->ceq_valid) {
- i40iw_cqp_cq_destroy_cmd(dev, &rsrc->cq);
- return;
- }
- ret = dev->iw_priv_cq_ops->cq_destroy(&rsrc->cq, 0, true);
-
- if (ret)
- i40iw_debug(dev, I40IW_DEBUG_PUDA,
- "%s error ieq cq destroy\n",
- __func__);
-
- if (!ret) {
- ret = dev->cqp_ops->poll_for_cqp_op_done(dev->cqp,
- I40IW_CQP_OP_DESTROY_CQ,
- &compl_info);
- if (ret)
- i40iw_debug(dev, I40IW_DEBUG_PUDA,
- "%s error ieq qp destroy done\n",
- __func__);
- }
-}
-
-/**
- * i40iw_puda_dele_resources - delete all resources during close
- * @vsi: pointer to vsi structure
- * @type: type of resource to dele
- * @reset: true if reset chip
- */
-void i40iw_puda_dele_resources(struct i40iw_sc_vsi *vsi,
- enum puda_resource_type type,
- bool reset)
-{
- struct i40iw_sc_dev *dev = vsi->dev;
- struct i40iw_puda_rsrc *rsrc;
- struct i40iw_puda_buf *buf = NULL;
- struct i40iw_puda_buf *nextbuf = NULL;
- struct i40iw_virt_mem *vmem;
-
- switch (type) {
- case I40IW_PUDA_RSRC_TYPE_ILQ:
- rsrc = vsi->ilq;
- vmem = &vsi->ilq_mem;
- break;
- case I40IW_PUDA_RSRC_TYPE_IEQ:
- rsrc = vsi->ieq;
- vmem = &vsi->ieq_mem;
- break;
- default:
- i40iw_debug(dev, I40IW_DEBUG_PUDA, "%s: error resource type = 0x%x\n",
- __func__, type);
- return;
- }
-
- switch (rsrc->completion) {
- case PUDA_HASH_CRC_COMPLETE:
- i40iw_free_hash_desc(rsrc->hash_desc);
- fallthrough;
- case PUDA_QP_CREATED:
- if (!reset)
- i40iw_puda_free_qp(rsrc);
-
- i40iw_free_dma_mem(dev->hw, &rsrc->qpmem);
- fallthrough;
- case PUDA_CQ_CREATED:
- if (!reset)
- i40iw_puda_free_cq(rsrc);
-
- i40iw_free_dma_mem(dev->hw, &rsrc->cqmem);
- break;
- default:
- i40iw_debug(rsrc->dev, I40IW_DEBUG_PUDA, "%s error no resources\n", __func__);
- break;
- }
- /* Free all allocated puda buffers for both tx and rx */
- buf = rsrc->alloclist;
- while (buf) {
- nextbuf = buf->next;
- i40iw_puda_dele_buf(dev, buf);
- buf = nextbuf;
- rsrc->alloc_buf_count--;
- }
- i40iw_free_virt_mem(dev->hw, vmem);
-}
-
-/**
- * i40iw_puda_allocbufs - allocate buffers for resource
- * @rsrc: resource for buffer allocation
- * @count: number of buffers to create
- */
-static enum i40iw_status_code i40iw_puda_allocbufs(struct i40iw_puda_rsrc *rsrc,
- u32 count)
-{
- u32 i;
- struct i40iw_puda_buf *buf;
- struct i40iw_puda_buf *nextbuf;
-
- for (i = 0; i < count; i++) {
- buf = i40iw_puda_alloc_buf(rsrc->dev, rsrc->buf_size);
- if (!buf) {
- rsrc->stats_buf_alloc_fail++;
- return I40IW_ERR_NO_MEMORY;
- }
- i40iw_puda_ret_bufpool(rsrc, buf);
- rsrc->alloc_buf_count++;
- if (!rsrc->alloclist) {
- rsrc->alloclist = buf;
- } else {
- nextbuf = rsrc->alloclist;
- rsrc->alloclist = buf;
- buf->next = nextbuf;
- }
- }
- rsrc->avail_buf_count = rsrc->alloc_buf_count;
- return 0;
-}
-
-/**
- * i40iw_puda_create_rsrc - create resouce (ilq or ieq)
- * @vsi: pointer to vsi structure
- * @info: resource information
- */
-enum i40iw_status_code i40iw_puda_create_rsrc(struct i40iw_sc_vsi *vsi,
- struct i40iw_puda_rsrc_info *info)
-{
- struct i40iw_sc_dev *dev = vsi->dev;
- enum i40iw_status_code ret = 0;
- struct i40iw_puda_rsrc *rsrc;
- u32 pudasize;
- u32 sqwridsize, rqwridsize;
- struct i40iw_virt_mem *vmem;
-
- info->count = 1;
- pudasize = sizeof(struct i40iw_puda_rsrc);
- sqwridsize = info->sq_size * sizeof(struct i40iw_sq_uk_wr_trk_info);
- rqwridsize = info->rq_size * 8;
- switch (info->type) {
- case I40IW_PUDA_RSRC_TYPE_ILQ:
- vmem = &vsi->ilq_mem;
- break;
- case I40IW_PUDA_RSRC_TYPE_IEQ:
- vmem = &vsi->ieq_mem;
- break;
- default:
- return I40IW_NOT_SUPPORTED;
- }
- ret =
- i40iw_allocate_virt_mem(dev->hw, vmem,
- pudasize + sqwridsize + rqwridsize);
- if (ret)
- return ret;
- rsrc = (struct i40iw_puda_rsrc *)vmem->va;
- spin_lock_init(&rsrc->bufpool_lock);
- if (info->type == I40IW_PUDA_RSRC_TYPE_ILQ) {
- vsi->ilq = (struct i40iw_puda_rsrc *)vmem->va;
- vsi->ilq_count = info->count;
- rsrc->receive = info->receive;
- rsrc->xmit_complete = info->xmit_complete;
- } else {
- vmem = &vsi->ieq_mem;
- vsi->ieq_count = info->count;
- vsi->ieq = (struct i40iw_puda_rsrc *)vmem->va;
- rsrc->receive = i40iw_ieq_receive;
- rsrc->xmit_complete = i40iw_ieq_tx_compl;
- }
-
- rsrc->type = info->type;
- rsrc->sq_wrtrk_array = (struct i40iw_sq_uk_wr_trk_info *)((u8 *)vmem->va + pudasize);
- rsrc->rq_wrid_array = (u64 *)((u8 *)vmem->va + pudasize + sqwridsize);
- /* Initialize all ieq lists */
- INIT_LIST_HEAD(&rsrc->bufpool);
- INIT_LIST_HEAD(&rsrc->txpend);
-
- rsrc->tx_wqe_avail_cnt = info->sq_size - 1;
- dev->iw_pd_ops->pd_init(dev, &rsrc->sc_pd, info->pd_id, -1);
- rsrc->qp_id = info->qp_id;
- rsrc->cq_id = info->cq_id;
- rsrc->sq_size = info->sq_size;
- rsrc->rq_size = info->rq_size;
- rsrc->cq_size = info->rq_size + info->sq_size;
- rsrc->buf_size = info->buf_size;
- rsrc->dev = dev;
- rsrc->vsi = vsi;
-
- ret = i40iw_puda_cq_create(rsrc);
- if (!ret) {
- rsrc->completion = PUDA_CQ_CREATED;
- ret = i40iw_puda_qp_create(rsrc);
- }
- if (ret) {
- i40iw_debug(dev, I40IW_DEBUG_PUDA, "[%s] error qp_create\n",
- __func__);
- goto error;
- }
- rsrc->completion = PUDA_QP_CREATED;
-
- ret = i40iw_puda_allocbufs(rsrc, info->tx_buf_cnt + info->rq_size);
- if (ret) {
- i40iw_debug(dev, I40IW_DEBUG_PUDA, "[%s] error alloc_buf\n",
- __func__);
- goto error;
- }
-
- rsrc->rxq_invalid_cnt = info->rq_size;
- ret = i40iw_puda_replenish_rq(rsrc, true);
- if (ret)
- goto error;
-
- if (info->type == I40IW_PUDA_RSRC_TYPE_IEQ) {
- if (!i40iw_init_hash_desc(&rsrc->hash_desc)) {
- rsrc->check_crc = true;
- rsrc->completion = PUDA_HASH_CRC_COMPLETE;
- ret = 0;
- }
- }
-
- dev->ccq_ops->ccq_arm(&rsrc->cq);
- return ret;
- error:
- i40iw_puda_dele_resources(vsi, info->type, false);
-
- return ret;
-}
-
-/**
- * i40iw_ilq_putback_rcvbuf - ilq buffer to put back on rq
- * @qp: ilq's qp resource
- * @wqe_idx: wqe index of completed rcvbuf
- */
-static void i40iw_ilq_putback_rcvbuf(struct i40iw_sc_qp *qp, u32 wqe_idx)
-{
- u64 *wqe;
- u64 offset24;
-
- wqe = qp->qp_uk.rq_base[wqe_idx].elem;
- get_64bit_val(wqe, 24, &offset24);
- offset24 = (offset24) ? 0 : LS_64(1, I40IWQPSQ_VALID);
- set_64bit_val(wqe, 24, offset24);
-}
-
-/**
- * i40iw_ieq_get_fpdu_length - given length return fpdu length
- * @length: length if fpdu
- */
-static u16 i40iw_ieq_get_fpdu_length(u16 length)
-{
- u16 fpdu_len;
-
- fpdu_len = length + I40IW_IEQ_MPA_FRAMING;
- fpdu_len = (fpdu_len + 3) & 0xfffffffc;
- return fpdu_len;
-}
-
-/**
- * i40iw_ieq_copy_to_txbuf - copydata from rcv buf to tx buf
- * @buf: rcv buffer with partial
- * @txbuf: tx buffer for sendign back
- * @buf_offset: rcv buffer offset to copy from
- * @txbuf_offset: at offset in tx buf to copy
- * @length: length of data to copy
- */
-static void i40iw_ieq_copy_to_txbuf(struct i40iw_puda_buf *buf,
- struct i40iw_puda_buf *txbuf,
- u16 buf_offset, u32 txbuf_offset,
- u32 length)
-{
- void *mem1 = (u8 *)buf->mem.va + buf_offset;
- void *mem2 = (u8 *)txbuf->mem.va + txbuf_offset;
-
- memcpy(mem2, mem1, length);
-}
-
-/**
- * i40iw_ieq_setup_tx_buf - setup tx buffer for partial handling
- * @buf: reeive buffer with partial
- * @txbuf: buffer to prepare
- */
-static void i40iw_ieq_setup_tx_buf(struct i40iw_puda_buf *buf,
- struct i40iw_puda_buf *txbuf)
-{
- txbuf->maclen = buf->maclen;
- txbuf->tcphlen = buf->tcphlen;
- txbuf->ipv4 = buf->ipv4;
- txbuf->hdrlen = buf->hdrlen;
- i40iw_ieq_copy_to_txbuf(buf, txbuf, 0, 0, buf->hdrlen);
-}
-
-/**
- * i40iw_ieq_check_first_buf - check if rcv buffer's seq is in range
- * @buf: receive exception buffer
- * @fps: first partial sequence number
- */
-static void i40iw_ieq_check_first_buf(struct i40iw_puda_buf *buf, u32 fps)
-{
- u32 offset;
-
- if (buf->seqnum < fps) {
- offset = fps - buf->seqnum;
- if (offset > buf->datalen)
- return;
- buf->data += offset;
- buf->datalen -= (u16)offset;
- buf->seqnum = fps;
- }
-}
-
-/**
- * i40iw_ieq_compl_pfpdu - write txbuf with full fpdu
- * @ieq: ieq resource
- * @rxlist: ieq's received buffer list
- * @pbufl: temporary list for buffers for fpddu
- * @txbuf: tx buffer for fpdu
- * @fpdu_len: total length of fpdu
- */
-static void i40iw_ieq_compl_pfpdu(struct i40iw_puda_rsrc *ieq,
- struct list_head *rxlist,
- struct list_head *pbufl,
- struct i40iw_puda_buf *txbuf,
- u16 fpdu_len)
-{
- struct i40iw_puda_buf *buf;
- u32 nextseqnum;
- u16 txoffset, bufoffset;
-
- buf = i40iw_puda_get_listbuf(pbufl);
- if (!buf)
- return;
- nextseqnum = buf->seqnum + fpdu_len;
- txbuf->totallen = buf->hdrlen + fpdu_len;
- txbuf->data = (u8 *)txbuf->mem.va + buf->hdrlen;
- i40iw_ieq_setup_tx_buf(buf, txbuf);
-
- txoffset = buf->hdrlen;
- bufoffset = (u16)(buf->data - (u8 *)buf->mem.va);
-
- do {
- if (buf->datalen >= fpdu_len) {
- /* copied full fpdu */
- i40iw_ieq_copy_to_txbuf(buf, txbuf, bufoffset, txoffset, fpdu_len);
- buf->datalen -= fpdu_len;
- buf->data += fpdu_len;
- buf->seqnum = nextseqnum;
- break;
- }
- /* copy partial fpdu */
- i40iw_ieq_copy_to_txbuf(buf, txbuf, bufoffset, txoffset, buf->datalen);
- txoffset += buf->datalen;
- fpdu_len -= buf->datalen;
- i40iw_puda_ret_bufpool(ieq, buf);
- buf = i40iw_puda_get_listbuf(pbufl);
- if (!buf)
- return;
- bufoffset = (u16)(buf->data - (u8 *)buf->mem.va);
- } while (1);
-
- /* last buffer on the list*/
- if (buf->datalen)
- list_add(&buf->list, rxlist);
- else
- i40iw_puda_ret_bufpool(ieq, buf);
-}
-
-/**
- * i40iw_ieq_create_pbufl - create buffer list for single fpdu
- * @pfpdu: partial management per user qp
- * @rxlist: resource list for receive ieq buffes
- * @pbufl: temp. list for buffers for fpddu
- * @buf: first receive buffer
- * @fpdu_len: total length of fpdu
- */
-static enum i40iw_status_code i40iw_ieq_create_pbufl(
- struct i40iw_pfpdu *pfpdu,
- struct list_head *rxlist,
- struct list_head *pbufl,
- struct i40iw_puda_buf *buf,
- u16 fpdu_len)
-{
- enum i40iw_status_code status = 0;
- struct i40iw_puda_buf *nextbuf;
- u32 nextseqnum;
- u16 plen = fpdu_len - buf->datalen;
- bool done = false;
-
- nextseqnum = buf->seqnum + buf->datalen;
- do {
- nextbuf = i40iw_puda_get_listbuf(rxlist);
- if (!nextbuf) {
- status = I40IW_ERR_list_empty;
- break;
- }
- list_add_tail(&nextbuf->list, pbufl);
- if (nextbuf->seqnum != nextseqnum) {
- pfpdu->bad_seq_num++;
- status = I40IW_ERR_SEQ_NUM;
- break;
- }
- if (nextbuf->datalen >= plen) {
- done = true;
- } else {
- plen -= nextbuf->datalen;
- nextseqnum = nextbuf->seqnum + nextbuf->datalen;
- }
-
- } while (!done);
-
- return status;
-}
-
-/**
- * i40iw_ieq_handle_partial - process partial fpdu buffer
- * @ieq: ieq resource
- * @pfpdu: partial management per user qp
- * @buf: receive buffer
- * @fpdu_len: fpdu len in the buffer
- */
-static enum i40iw_status_code i40iw_ieq_handle_partial(struct i40iw_puda_rsrc *ieq,
- struct i40iw_pfpdu *pfpdu,
- struct i40iw_puda_buf *buf,
- u16 fpdu_len)
-{
- enum i40iw_status_code status = 0;
- u8 *crcptr;
- u32 mpacrc;
- u32 seqnum = buf->seqnum;
- struct list_head pbufl; /* partial buffer list */
- struct i40iw_puda_buf *txbuf = NULL;
- struct list_head *rxlist = &pfpdu->rxlist;
-
- INIT_LIST_HEAD(&pbufl);
- list_add(&buf->list, &pbufl);
-
- status = i40iw_ieq_create_pbufl(pfpdu, rxlist, &pbufl, buf, fpdu_len);
- if (status)
- goto error;
-
- txbuf = i40iw_puda_get_bufpool(ieq);
- if (!txbuf) {
- pfpdu->no_tx_bufs++;
- status = I40IW_ERR_NO_TXBUFS;
- goto error;
- }
-
- i40iw_ieq_compl_pfpdu(ieq, rxlist, &pbufl, txbuf, fpdu_len);
- i40iw_ieq_update_tcpip_info(txbuf, fpdu_len, seqnum);
- crcptr = txbuf->data + fpdu_len - 4;
- mpacrc = *(u32 *)crcptr;
- if (ieq->check_crc) {
- status = i40iw_ieq_check_mpacrc(ieq->hash_desc, txbuf->data,
- (fpdu_len - 4), mpacrc);
- if (status) {
- i40iw_debug(ieq->dev, I40IW_DEBUG_IEQ,
- "%s: error bad crc\n", __func__);
- goto error;
- }
- }
-
- i40iw_debug_buf(ieq->dev, I40IW_DEBUG_IEQ, "IEQ TX BUFFER",
- txbuf->mem.va, txbuf->totallen);
- i40iw_puda_send_buf(ieq, txbuf);
- pfpdu->rcv_nxt = seqnum + fpdu_len;
- return status;
- error:
- while (!list_empty(&pbufl)) {
- buf = (struct i40iw_puda_buf *)(pbufl.prev);
- list_del(&buf->list);
- list_add(&buf->list, rxlist);
- }
- if (txbuf)
- i40iw_puda_ret_bufpool(ieq, txbuf);
- return status;
-}
-
-/**
- * i40iw_ieq_process_buf - process buffer rcvd for ieq
- * @ieq: ieq resource
- * @pfpdu: partial management per user qp
- * @buf: receive buffer
- */
-static enum i40iw_status_code i40iw_ieq_process_buf(struct i40iw_puda_rsrc *ieq,
- struct i40iw_pfpdu *pfpdu,
- struct i40iw_puda_buf *buf)
-{
- u16 fpdu_len = 0;
- u16 datalen = buf->datalen;
- u8 *datap = buf->data;
- u8 *crcptr;
- u16 ioffset = 0;
- u32 mpacrc;
- u32 seqnum = buf->seqnum;
- u16 length = 0;
- u16 full = 0;
- bool partial = false;
- struct i40iw_puda_buf *txbuf;
- struct list_head *rxlist = &pfpdu->rxlist;
- enum i40iw_status_code ret = 0;
- enum i40iw_status_code status = 0;
-
- ioffset = (u16)(buf->data - (u8 *)buf->mem.va);
- while (datalen) {
- fpdu_len = i40iw_ieq_get_fpdu_length(ntohs(*(__be16 *)datap));
- if (fpdu_len > pfpdu->max_fpdu_data) {
- i40iw_debug(ieq->dev, I40IW_DEBUG_IEQ,
- "%s: error bad fpdu_len\n", __func__);
- status = I40IW_ERR_MPA_CRC;
- list_add(&buf->list, rxlist);
- return status;
- }
-
- if (datalen < fpdu_len) {
- partial = true;
- break;
- }
- crcptr = datap + fpdu_len - 4;
- mpacrc = *(u32 *)crcptr;
- if (ieq->check_crc)
- ret = i40iw_ieq_check_mpacrc(ieq->hash_desc,
- datap, fpdu_len - 4, mpacrc);
- if (ret) {
- status = I40IW_ERR_MPA_CRC;
- list_add(&buf->list, rxlist);
- return status;
- }
- full++;
- pfpdu->fpdu_processed++;
- datap += fpdu_len;
- length += fpdu_len;
- datalen -= fpdu_len;
- }
- if (full) {
- /* copy full pdu's in the txbuf and send them out */
- txbuf = i40iw_puda_get_bufpool(ieq);
- if (!txbuf) {
- pfpdu->no_tx_bufs++;
- status = I40IW_ERR_NO_TXBUFS;
- list_add(&buf->list, rxlist);
- return status;
- }
- /* modify txbuf's buffer header */
- i40iw_ieq_setup_tx_buf(buf, txbuf);
- /* copy full fpdu's to new buffer */
- i40iw_ieq_copy_to_txbuf(buf, txbuf, ioffset, buf->hdrlen,
- length);
- txbuf->totallen = buf->hdrlen + length;
-
- i40iw_ieq_update_tcpip_info(txbuf, length, buf->seqnum);
- i40iw_puda_send_buf(ieq, txbuf);
-
- if (!datalen) {
- pfpdu->rcv_nxt = buf->seqnum + length;
- i40iw_puda_ret_bufpool(ieq, buf);
- return status;
- }
- buf->data = datap;
- buf->seqnum = seqnum + length;
- buf->datalen = datalen;
- pfpdu->rcv_nxt = buf->seqnum;
- }
- if (partial)
- status = i40iw_ieq_handle_partial(ieq, pfpdu, buf, fpdu_len);
-
- return status;
-}
-
-/**
- * i40iw_ieq_process_fpdus - process fpdu's buffers on its list
- * @qp: qp for which partial fpdus
- * @ieq: ieq resource
- */
-static void i40iw_ieq_process_fpdus(struct i40iw_sc_qp *qp,
- struct i40iw_puda_rsrc *ieq)
-{
- struct i40iw_pfpdu *pfpdu = &qp->pfpdu;
- struct list_head *rxlist = &pfpdu->rxlist;
- struct i40iw_puda_buf *buf;
- enum i40iw_status_code status;
-
- do {
- if (list_empty(rxlist))
- break;
- buf = i40iw_puda_get_listbuf(rxlist);
- if (!buf) {
- i40iw_debug(ieq->dev, I40IW_DEBUG_IEQ,
- "%s: error no buf\n", __func__);
- break;
- }
- if (buf->seqnum != pfpdu->rcv_nxt) {
- /* This could be out of order or missing packet */
- pfpdu->out_of_order++;
- list_add(&buf->list, rxlist);
- break;
- }
- /* keep processing buffers from the head of the list */
- status = i40iw_ieq_process_buf(ieq, pfpdu, buf);
- if (status == I40IW_ERR_MPA_CRC) {
- pfpdu->mpa_crc_err = true;
- while (!list_empty(rxlist)) {
- buf = i40iw_puda_get_listbuf(rxlist);
- i40iw_puda_ret_bufpool(ieq, buf);
- pfpdu->crc_err++;
- }
- /* create CQP for AE */
- i40iw_ieq_mpa_crc_ae(ieq->dev, qp);
- }
- } while (!status);
-}
-
-/**
- * i40iw_ieq_handle_exception - handle qp's exception
- * @ieq: ieq resource
- * @qp: qp receiving excpetion
- * @buf: receive buffer
- */
-static void i40iw_ieq_handle_exception(struct i40iw_puda_rsrc *ieq,
- struct i40iw_sc_qp *qp,
- struct i40iw_puda_buf *buf)
-{
- struct i40iw_puda_buf *tmpbuf = NULL;
- struct i40iw_pfpdu *pfpdu = &qp->pfpdu;
- u32 *hw_host_ctx = (u32 *)qp->hw_host_ctx;
- u32 rcv_wnd = hw_host_ctx[23];
- /* first partial seq # in q2 */
- u32 fps = *(u32 *)(qp->q2_buf + Q2_FPSN_OFFSET);
- struct list_head *rxlist = &pfpdu->rxlist;
- struct list_head *plist;
-
- pfpdu->total_ieq_bufs++;
-
- if (pfpdu->mpa_crc_err) {
- pfpdu->crc_err++;
- goto error;
- }
- if (pfpdu->mode && (fps != pfpdu->fps)) {
- /* clean up qp as it is new partial sequence */
- i40iw_ieq_cleanup_qp(ieq, qp);
- i40iw_debug(ieq->dev, I40IW_DEBUG_IEQ,
- "%s: restarting new partial\n", __func__);
- pfpdu->mode = false;
- }
-
- if (!pfpdu->mode) {
- i40iw_debug_buf(ieq->dev, I40IW_DEBUG_IEQ, "Q2 BUFFER", (u64 *)qp->q2_buf, 128);
- /* First_Partial_Sequence_Number check */
- pfpdu->rcv_nxt = fps;
- pfpdu->fps = fps;
- pfpdu->mode = true;
- pfpdu->max_fpdu_data = (buf->ipv4) ? (ieq->vsi->mtu - I40IW_MTU_TO_MSS_IPV4) :
- (ieq->vsi->mtu - I40IW_MTU_TO_MSS_IPV6);
- pfpdu->pmode_count++;
- INIT_LIST_HEAD(rxlist);
- i40iw_ieq_check_first_buf(buf, fps);
- }
-
- if (!(rcv_wnd >= (buf->seqnum - pfpdu->rcv_nxt))) {
- pfpdu->bad_seq_num++;
- goto error;
- }
-
- if (!list_empty(rxlist)) {
- tmpbuf = (struct i40iw_puda_buf *)rxlist->next;
- while ((struct list_head *)tmpbuf != rxlist) {
- if ((int)(buf->seqnum - tmpbuf->seqnum) < 0)
- break;
- plist = &tmpbuf->list;
- tmpbuf = (struct i40iw_puda_buf *)plist->next;
- }
- /* Insert buf before tmpbuf */
- list_add_tail(&buf->list, &tmpbuf->list);
- } else {
- list_add_tail(&buf->list, rxlist);
- }
- i40iw_ieq_process_fpdus(qp, ieq);
- return;
- error:
- i40iw_puda_ret_bufpool(ieq, buf);
-}
-
-/**
- * i40iw_ieq_receive - received exception buffer
- * @vsi: pointer to vsi structure
- * @buf: exception buffer received
- */
-static void i40iw_ieq_receive(struct i40iw_sc_vsi *vsi,
- struct i40iw_puda_buf *buf)
-{
- struct i40iw_puda_rsrc *ieq = vsi->ieq;
- struct i40iw_sc_qp *qp = NULL;
- u32 wqe_idx = ieq->compl_rxwqe_idx;
-
- qp = i40iw_ieq_get_qp(vsi->dev, buf);
- if (!qp) {
- ieq->stats_bad_qp_id++;
- i40iw_puda_ret_bufpool(ieq, buf);
- } else {
- i40iw_ieq_handle_exception(ieq, qp, buf);
- }
- /*
- * ieq->rx_wqe_idx is used by i40iw_puda_replenish_rq()
- * on which wqe_idx to start replenish rq
- */
- if (!ieq->rxq_invalid_cnt)
- ieq->rx_wqe_idx = wqe_idx;
- ieq->rxq_invalid_cnt++;
-}
-
-/**
- * i40iw_ieq_tx_compl - put back after sending completed exception buffer
- * @vsi: pointer to the vsi structure
- * @sqwrid: pointer to puda buffer
- */
-static void i40iw_ieq_tx_compl(struct i40iw_sc_vsi *vsi, void *sqwrid)
-{
- struct i40iw_puda_rsrc *ieq = vsi->ieq;
- struct i40iw_puda_buf *buf = (struct i40iw_puda_buf *)sqwrid;
-
- i40iw_puda_ret_bufpool(ieq, buf);
-}
-
-/**
- * i40iw_ieq_cleanup_qp - qp is being destroyed
- * @ieq: ieq resource
- * @qp: all pending fpdu buffers
- */
-void i40iw_ieq_cleanup_qp(struct i40iw_puda_rsrc *ieq, struct i40iw_sc_qp *qp)
-{
- struct i40iw_puda_buf *buf;
- struct i40iw_pfpdu *pfpdu = &qp->pfpdu;
- struct list_head *rxlist = &pfpdu->rxlist;
-
- if (!pfpdu->mode)
- return;
- while (!list_empty(rxlist)) {
- buf = i40iw_puda_get_listbuf(rxlist);
- i40iw_puda_ret_bufpool(ieq, buf);
- }
-}
diff --git a/drivers/infiniband/hw/i40iw/i40iw_puda.h b/drivers/infiniband/hw/i40iw/i40iw_puda.h
deleted file mode 100644
index 53a7d58c84b5..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_puda.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_PUDA_H
-#define I40IW_PUDA_H
-
-#define I40IW_IEQ_MPA_FRAMING 6
-
-struct i40iw_sc_dev;
-struct i40iw_sc_qp;
-struct i40iw_sc_cq;
-
-enum puda_resource_type {
- I40IW_PUDA_RSRC_TYPE_ILQ = 1,
- I40IW_PUDA_RSRC_TYPE_IEQ
-};
-
-enum puda_rsrc_complete {
- PUDA_CQ_CREATED = 1,
- PUDA_QP_CREATED,
- PUDA_TX_COMPLETE,
- PUDA_RX_COMPLETE,
- PUDA_HASH_CRC_COMPLETE
-};
-
-struct i40iw_puda_completion_info {
- struct i40iw_qp_uk *qp;
- u8 q_type;
- u8 vlan_valid;
- u8 l3proto;
- u8 l4proto;
- u16 payload_len;
- u32 compl_error; /* No_err=0, else major and minor err code */
- u32 qp_id;
- u32 wqe_idx;
-};
-
-struct i40iw_puda_send_info {
- u64 paddr; /* Physical address */
- u32 len;
- u8 tcplen;
- u8 maclen;
- bool ipv4;
- bool doloopback;
- void *scratch;
-};
-
-struct i40iw_puda_buf {
- struct list_head list; /* MUST be first entry */
- struct i40iw_dma_mem mem; /* DMA memory for the buffer */
- struct i40iw_puda_buf *next; /* for alloclist in rsrc struct */
- struct i40iw_virt_mem buf_mem; /* Buffer memory for this buffer */
- void *scratch;
- u8 *iph;
- u8 *tcph;
- u8 *data;
- u16 datalen;
- u16 vlan_id;
- u8 tcphlen; /* tcp length in bytes */
- u8 maclen; /* mac length in bytes */
- u32 totallen; /* machlen+iphlen+tcphlen+datalen */
- atomic_t refcount;
- u8 hdrlen;
- bool ipv4;
- u32 seqnum;
-};
-
-struct i40iw_puda_rsrc_info {
- enum puda_resource_type type; /* ILQ or IEQ */
- u32 count;
- u16 pd_id;
- u32 cq_id;
- u32 qp_id;
- u32 sq_size;
- u32 rq_size;
- u16 buf_size;
- u16 mss;
- u32 tx_buf_cnt; /* total bufs allocated will be rq_size + tx_buf_cnt */
- void (*receive)(struct i40iw_sc_vsi *, struct i40iw_puda_buf *);
- void (*xmit_complete)(struct i40iw_sc_vsi *, void *);
-};
-
-struct i40iw_puda_rsrc {
- struct i40iw_sc_cq cq;
- struct i40iw_sc_qp qp;
- struct i40iw_sc_pd sc_pd;
- struct i40iw_sc_dev *dev;
- struct i40iw_sc_vsi *vsi;
- struct i40iw_dma_mem cqmem;
- struct i40iw_dma_mem qpmem;
- struct i40iw_virt_mem ilq_mem;
- enum puda_rsrc_complete completion;
- enum puda_resource_type type;
- u16 buf_size; /*buffer must be max datalen + tcpip hdr + mac */
- u16 mss;
- u32 cq_id;
- u32 qp_id;
- u32 sq_size;
- u32 rq_size;
- u32 cq_size;
- struct i40iw_sq_uk_wr_trk_info *sq_wrtrk_array;
- u64 *rq_wrid_array;
- u32 compl_rxwqe_idx;
- u32 rx_wqe_idx;
- u32 rxq_invalid_cnt;
- u32 tx_wqe_avail_cnt;
- bool check_crc;
- struct shash_desc *hash_desc;
- struct list_head txpend;
- struct list_head bufpool; /* free buffers pool list for recv and xmit */
- u32 alloc_buf_count;
- u32 avail_buf_count; /* snapshot of currently available buffers */
- spinlock_t bufpool_lock;
- struct i40iw_puda_buf *alloclist;
- void (*receive)(struct i40iw_sc_vsi *, struct i40iw_puda_buf *);
- void (*xmit_complete)(struct i40iw_sc_vsi *, void *);
- /* puda stats */
- u64 stats_buf_alloc_fail;
- u64 stats_pkt_rcvd;
- u64 stats_pkt_sent;
- u64 stats_rcvd_pkt_err;
- u64 stats_sent_pkt_q;
- u64 stats_bad_qp_id;
-};
-
-struct i40iw_puda_buf *i40iw_puda_get_bufpool(struct i40iw_puda_rsrc *rsrc);
-void i40iw_puda_ret_bufpool(struct i40iw_puda_rsrc *rsrc,
- struct i40iw_puda_buf *buf);
-void i40iw_puda_send_buf(struct i40iw_puda_rsrc *rsrc,
- struct i40iw_puda_buf *buf);
-enum i40iw_status_code i40iw_puda_send(struct i40iw_sc_qp *qp,
- struct i40iw_puda_send_info *info);
-enum i40iw_status_code i40iw_puda_create_rsrc(struct i40iw_sc_vsi *vsi,
- struct i40iw_puda_rsrc_info *info);
-void i40iw_puda_dele_resources(struct i40iw_sc_vsi *vsi,
- enum puda_resource_type type,
- bool reset);
-enum i40iw_status_code i40iw_puda_poll_completion(struct i40iw_sc_dev *dev,
- struct i40iw_sc_cq *cq, u32 *compl_err);
-
-struct i40iw_sc_qp *i40iw_ieq_get_qp(struct i40iw_sc_dev *dev,
- struct i40iw_puda_buf *buf);
-enum i40iw_status_code i40iw_puda_get_tcpip_info(struct i40iw_puda_completion_info *info,
- struct i40iw_puda_buf *buf);
-enum i40iw_status_code i40iw_ieq_check_mpacrc(struct shash_desc *desc,
- void *addr, u32 length, u32 value);
-enum i40iw_status_code i40iw_init_hash_desc(struct shash_desc **desc);
-void i40iw_ieq_mpa_crc_ae(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp);
-void i40iw_free_hash_desc(struct shash_desc *desc);
-void i40iw_ieq_update_tcpip_info(struct i40iw_puda_buf *buf, u16 length,
- u32 seqnum);
-enum i40iw_status_code i40iw_cqp_qp_create_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp);
-enum i40iw_status_code i40iw_cqp_cq_create_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_cq *cq);
-void i40iw_cqp_qp_destroy_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp);
-void i40iw_cqp_cq_destroy_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_cq *cq);
-void i40iw_ieq_cleanup_qp(struct i40iw_puda_rsrc *ieq, struct i40iw_sc_qp *qp);
-#endif
diff --git a/drivers/infiniband/hw/i40iw/i40iw_register.h b/drivers/infiniband/hw/i40iw/i40iw_register.h
deleted file mode 100644
index 57768184e251..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_register.h
+++ /dev/null
@@ -1,1030 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_REGISTER_H
-#define I40IW_REGISTER_H
-
-#define I40E_GLGEN_STAT 0x000B612C /* Reset: POR */
-
-#define I40E_PFHMC_PDINV 0x000C0300 /* Reset: PFR */
-#define I40E_PFHMC_PDINV_PMSDIDX_SHIFT 0
-#define I40E_PFHMC_PDINV_PMSDIDX_MASK (0xFFF << I40E_PFHMC_PDINV_PMSDIDX_SHIFT)
-#define I40E_PFHMC_PDINV_PMPDIDX_SHIFT 16
-#define I40E_PFHMC_PDINV_PMPDIDX_MASK (0x1FF << I40E_PFHMC_PDINV_PMPDIDX_SHIFT)
-#define I40E_PFHMC_SDCMD_PMSDWR_SHIFT 31
-#define I40E_PFHMC_SDCMD_PMSDWR_MASK (0x1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT)
-#define I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT 0
-#define I40E_PFHMC_SDDATALOW_PMSDVALID_MASK (0x1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT)
-#define I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT 1
-#define I40E_PFHMC_SDDATALOW_PMSDTYPE_MASK (0x1 << I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT)
-#define I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT 2
-#define I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_MASK (0x3FF << I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT)
-
-#define I40E_PFINT_DYN_CTLN(_INTPF) (0x00034800 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: PFR */
-#define I40E_PFINT_DYN_CTLN_INTENA_SHIFT 0
-#define I40E_PFINT_DYN_CTLN_INTENA_MASK (0x1 << I40E_PFINT_DYN_CTLN_INTENA_SHIFT)
-#define I40E_PFINT_DYN_CTLN_CLEARPBA_SHIFT 1
-#define I40E_PFINT_DYN_CTLN_CLEARPBA_MASK (0x1 << I40E_PFINT_DYN_CTLN_CLEARPBA_SHIFT)
-#define I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT 3
-#define I40E_PFINT_DYN_CTLN_ITR_INDX_MASK (0x3 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT)
-
-#define I40E_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...15 */ /* Reset: VFR */
-#define I40E_GLHMC_VFPDINV(_i) (0x000C8300 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */
-
-#define I40E_PFHMC_PDINV_PMSDPARTSEL_SHIFT 15
-#define I40E_PFHMC_PDINV_PMSDPARTSEL_MASK (0x1 << I40E_PFHMC_PDINV_PMSDPARTSEL_SHIFT)
-#define I40E_GLPCI_LBARCTRL 0x000BE484 /* Reset: POR */
-#define I40E_GLPCI_LBARCTRL_PE_DB_SIZE_SHIFT 4
-#define I40E_GLPCI_LBARCTRL_PE_DB_SIZE_MASK (0x3 << I40E_GLPCI_LBARCTRL_PE_DB_SIZE_SHIFT)
-#define I40E_GLPCI_DREVID 0x0009C480 /* Reset: PCIR */
-#define I40E_GLPCI_DREVID_DEFAULT_REVID_SHIFT 0
-#define I40E_GLPCI_DREVID_DEFAULT_REVID_MASK 0xFF
-
-#define I40E_PFPE_AEQALLOC 0x00131180 /* Reset: PFR */
-#define I40E_PFPE_AEQALLOC_AECOUNT_SHIFT 0
-#define I40E_PFPE_AEQALLOC_AECOUNT_MASK (0xFFFFFFFF << I40E_PFPE_AEQALLOC_AECOUNT_SHIFT)
-#define I40E_PFPE_CCQPHIGH 0x00008200 /* Reset: PFR */
-#define I40E_PFPE_CCQPHIGH_PECCQPHIGH_SHIFT 0
-#define I40E_PFPE_CCQPHIGH_PECCQPHIGH_MASK (0xFFFFFFFF << I40E_PFPE_CCQPHIGH_PECCQPHIGH_SHIFT)
-#define I40E_PFPE_CCQPLOW 0x00008180 /* Reset: PFR */
-#define I40E_PFPE_CCQPLOW_PECCQPLOW_SHIFT 0
-#define I40E_PFPE_CCQPLOW_PECCQPLOW_MASK (0xFFFFFFFF << I40E_PFPE_CCQPLOW_PECCQPLOW_SHIFT)
-#define I40E_PFPE_CCQPSTATUS 0x00008100 /* Reset: PFR */
-#define I40E_PFPE_CCQPSTATUS_CCQP_DONE_SHIFT 0
-#define I40E_PFPE_CCQPSTATUS_CCQP_DONE_MASK (0x1 << I40E_PFPE_CCQPSTATUS_CCQP_DONE_SHIFT)
-#define I40E_PFPE_CCQPSTATUS_HMC_PROFILE_SHIFT 4
-#define I40E_PFPE_CCQPSTATUS_HMC_PROFILE_MASK (0x7 << I40E_PFPE_CCQPSTATUS_HMC_PROFILE_SHIFT)
-#define I40E_PFPE_CCQPSTATUS_RDMA_EN_VFS_SHIFT 16
-#define I40E_PFPE_CCQPSTATUS_RDMA_EN_VFS_MASK (0x3F << I40E_PFPE_CCQPSTATUS_RDMA_EN_VFS_SHIFT)
-#define I40E_PFPE_CCQPSTATUS_CCQP_ERR_SHIFT 31
-#define I40E_PFPE_CCQPSTATUS_CCQP_ERR_MASK (0x1 << I40E_PFPE_CCQPSTATUS_CCQP_ERR_SHIFT)
-#define I40E_PFPE_CQACK 0x00131100 /* Reset: PFR */
-#define I40E_PFPE_CQACK_PECQID_SHIFT 0
-#define I40E_PFPE_CQACK_PECQID_MASK (0x1FFFF << I40E_PFPE_CQACK_PECQID_SHIFT)
-#define I40E_PFPE_CQARM 0x00131080 /* Reset: PFR */
-#define I40E_PFPE_CQARM_PECQID_SHIFT 0
-#define I40E_PFPE_CQARM_PECQID_MASK (0x1FFFF << I40E_PFPE_CQARM_PECQID_SHIFT)
-#define I40E_PFPE_CQPDB 0x00008000 /* Reset: PFR */
-#define I40E_PFPE_CQPDB_WQHEAD_SHIFT 0
-#define I40E_PFPE_CQPDB_WQHEAD_MASK (0x7FF << I40E_PFPE_CQPDB_WQHEAD_SHIFT)
-#define I40E_PFPE_CQPERRCODES 0x00008880 /* Reset: PFR */
-#define I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT 0
-#define I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_MASK (0xFFFF << I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT)
-#define I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT 16
-#define I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_MASK (0xFFFF << I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT)
-#define I40E_PFPE_CQPTAIL 0x00008080 /* Reset: PFR */
-#define I40E_PFPE_CQPTAIL_WQTAIL_SHIFT 0
-#define I40E_PFPE_CQPTAIL_WQTAIL_MASK (0x7FF << I40E_PFPE_CQPTAIL_WQTAIL_SHIFT)
-#define I40E_PFPE_CQPTAIL_CQP_OP_ERR_SHIFT 31
-#define I40E_PFPE_CQPTAIL_CQP_OP_ERR_MASK (0x1 << I40E_PFPE_CQPTAIL_CQP_OP_ERR_SHIFT)
-#define I40E_PFPE_FLMQ1ALLOCERR 0x00008980 /* Reset: PFR */
-#define I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_SHIFT 0
-#define I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_SHIFT)
-#define I40E_PFPE_FLMXMITALLOCERR 0x00008900 /* Reset: PFR */
-#define I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_SHIFT 0
-#define I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_SHIFT)
-#define I40E_PFPE_IPCONFIG0 0x00008280 /* Reset: PFR */
-#define I40E_PFPE_IPCONFIG0_PEIPID_SHIFT 0
-#define I40E_PFPE_IPCONFIG0_PEIPID_MASK (0xFFFF << I40E_PFPE_IPCONFIG0_PEIPID_SHIFT)
-#define I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT 16
-#define I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_MASK (0x1 << I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT)
-#define I40E_PFPE_MRTEIDXMASK 0x00008600 /* Reset: PFR */
-#define I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT 0
-#define I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_MASK (0x1F << I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT)
-#define I40E_PFPE_RCVUNEXPECTEDERROR 0x00008680 /* Reset: PFR */
-#define I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT 0
-#define I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_MASK (0xFFFFFF << I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT)
-#define I40E_PFPE_TCPNOWTIMER 0x00008580 /* Reset: PFR */
-#define I40E_PFPE_TCPNOWTIMER_TCP_NOW_SHIFT 0
-#define I40E_PFPE_TCPNOWTIMER_TCP_NOW_MASK (0xFFFFFFFF << I40E_PFPE_TCPNOWTIMER_TCP_NOW_SHIFT)
-
-#define I40E_PFPE_WQEALLOC 0x00138C00 /* Reset: PFR */
-#define I40E_PFPE_WQEALLOC_PEQPID_SHIFT 0
-#define I40E_PFPE_WQEALLOC_PEQPID_MASK (0x3FFFF << I40E_PFPE_WQEALLOC_PEQPID_SHIFT)
-#define I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT 20
-#define I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_MASK (0xFFF << I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT)
-
-#define I40E_VFPE_AEQALLOC(_VF) (0x00130C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */
-#define I40E_VFPE_AEQALLOC_MAX_INDEX 127
-#define I40E_VFPE_AEQALLOC_AECOUNT_SHIFT 0
-#define I40E_VFPE_AEQALLOC_AECOUNT_MASK (0xFFFFFFFF << I40E_VFPE_AEQALLOC_AECOUNT_SHIFT)
-#define I40E_VFPE_CCQPHIGH(_VF) (0x00001000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */
-#define I40E_VFPE_CCQPHIGH_MAX_INDEX 127
-#define I40E_VFPE_CCQPHIGH_PECCQPHIGH_SHIFT 0
-#define I40E_VFPE_CCQPHIGH_PECCQPHIGH_MASK (0xFFFFFFFF << I40E_VFPE_CCQPHIGH_PECCQPHIGH_SHIFT)
-#define I40E_VFPE_CCQPLOW(_VF) (0x00000C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */
-#define I40E_VFPE_CCQPLOW_MAX_INDEX 127
-#define I40E_VFPE_CCQPLOW_PECCQPLOW_SHIFT 0
-#define I40E_VFPE_CCQPLOW_PECCQPLOW_MASK (0xFFFFFFFF << I40E_VFPE_CCQPLOW_PECCQPLOW_SHIFT)
-#define I40E_VFPE_CCQPSTATUS(_VF) (0x00000800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */
-#define I40E_VFPE_CCQPSTATUS_MAX_INDEX 127
-#define I40E_VFPE_CCQPSTATUS_CCQP_DONE_SHIFT 0
-#define I40E_VFPE_CCQPSTATUS_CCQP_DONE_MASK (0x1 << I40E_VFPE_CCQPSTATUS_CCQP_DONE_SHIFT)
-#define I40E_VFPE_CCQPSTATUS_HMC_PROFILE_SHIFT 4
-#define I40E_VFPE_CCQPSTATUS_HMC_PROFILE_MASK (0x7 << I40E_VFPE_CCQPSTATUS_HMC_PROFILE_SHIFT)
-#define I40E_VFPE_CCQPSTATUS_RDMA_EN_VFS_SHIFT 16
-#define I40E_VFPE_CCQPSTATUS_RDMA_EN_VFS_MASK (0x3F << I40E_VFPE_CCQPSTATUS_RDMA_EN_VFS_SHIFT)
-#define I40E_VFPE_CCQPSTATUS_CCQP_ERR_SHIFT 31
-#define I40E_VFPE_CCQPSTATUS_CCQP_ERR_MASK (0x1 << I40E_VFPE_CCQPSTATUS_CCQP_ERR_SHIFT)
-#define I40E_VFPE_CQACK(_VF) (0x00130800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */
-#define I40E_VFPE_CQACK_MAX_INDEX 127
-#define I40E_VFPE_CQACK_PECQID_SHIFT 0
-#define I40E_VFPE_CQACK_PECQID_MASK (0x1FFFF << I40E_VFPE_CQACK_PECQID_SHIFT)
-#define I40E_VFPE_CQARM(_VF) (0x00130400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */
-#define I40E_VFPE_CQARM_MAX_INDEX 127
-#define I40E_VFPE_CQARM_PECQID_SHIFT 0
-#define I40E_VFPE_CQARM_PECQID_MASK (0x1FFFF << I40E_VFPE_CQARM_PECQID_SHIFT)
-#define I40E_VFPE_CQPDB(_VF) (0x00000000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */
-#define I40E_VFPE_CQPDB_MAX_INDEX 127
-#define I40E_VFPE_CQPDB_WQHEAD_SHIFT 0
-#define I40E_VFPE_CQPDB_WQHEAD_MASK (0x7FF << I40E_VFPE_CQPDB_WQHEAD_SHIFT)
-#define I40E_VFPE_CQPERRCODES(_VF) (0x00001800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */
-#define I40E_VFPE_CQPERRCODES_MAX_INDEX 127
-#define I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT 0
-#define I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT)
-#define I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT 16
-#define I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT)
-#define I40E_VFPE_CQPTAIL(_VF) (0x00000400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */
-#define I40E_VFPE_CQPTAIL_MAX_INDEX 127
-#define I40E_VFPE_CQPTAIL_WQTAIL_SHIFT 0
-#define I40E_VFPE_CQPTAIL_WQTAIL_MASK (0x7FF << I40E_VFPE_CQPTAIL_WQTAIL_SHIFT)
-#define I40E_VFPE_CQPTAIL_CQP_OP_ERR_SHIFT 31
-#define I40E_VFPE_CQPTAIL_CQP_OP_ERR_MASK (0x1 << I40E_VFPE_CQPTAIL_CQP_OP_ERR_SHIFT)
-#define I40E_VFPE_IPCONFIG0(_VF) (0x00001400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */
-#define I40E_VFPE_IPCONFIG0_MAX_INDEX 127
-#define I40E_VFPE_IPCONFIG0_PEIPID_SHIFT 0
-#define I40E_VFPE_IPCONFIG0_PEIPID_MASK (0xFFFF << I40E_VFPE_IPCONFIG0_PEIPID_SHIFT)
-#define I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT 16
-#define I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_MASK (0x1 << I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT)
-#define I40E_VFPE_MRTEIDXMASK(_VF) (0x00003000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */
-#define I40E_VFPE_MRTEIDXMASK_MAX_INDEX 127
-#define I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT 0
-#define I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_MASK (0x1F << I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT)
-#define I40E_VFPE_RCVUNEXPECTEDERROR(_VF) (0x00003400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */
-#define I40E_VFPE_RCVUNEXPECTEDERROR_MAX_INDEX 127
-#define I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT 0
-#define I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_MASK (0xFFFFFF << I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT)
-#define I40E_VFPE_TCPNOWTIMER(_VF) (0x00002C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */
-#define I40E_VFPE_TCPNOWTIMER_MAX_INDEX 127
-#define I40E_VFPE_TCPNOWTIMER_TCP_NOW_SHIFT 0
-#define I40E_VFPE_TCPNOWTIMER_TCP_NOW_MASK (0xFFFFFFFF << I40E_VFPE_TCPNOWTIMER_TCP_NOW_SHIFT)
-#define I40E_VFPE_WQEALLOC(_VF) (0x00138000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */
-#define I40E_VFPE_WQEALLOC_MAX_INDEX 127
-#define I40E_VFPE_WQEALLOC_PEQPID_SHIFT 0
-#define I40E_VFPE_WQEALLOC_PEQPID_MASK (0x3FFFF << I40E_VFPE_WQEALLOC_PEQPID_SHIFT)
-#define I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT 20
-#define I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_MASK (0xFFF << I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT)
-
-#define I40E_GLPE_CPUSTATUS0 0x0000D040 /* Reset: PE_CORER */
-#define I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_SHIFT 0
-#define I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_MASK (0xFFFFFFFF << I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_SHIFT)
-#define I40E_GLPE_CPUSTATUS1 0x0000D044 /* Reset: PE_CORER */
-#define I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_SHIFT 0
-#define I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_MASK (0xFFFFFFFF << I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_SHIFT)
-#define I40E_GLPE_CPUSTATUS2 0x0000D048 /* Reset: PE_CORER */
-#define I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_SHIFT 0
-#define I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_MASK (0xFFFFFFFF << I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_SHIFT)
-#define I40E_GLPE_CPUTRIG0 0x0000D060 /* Reset: PE_CORER */
-#define I40E_GLPE_CPUTRIG0_PECPUTRIG0_SHIFT 0
-#define I40E_GLPE_CPUTRIG0_PECPUTRIG0_MASK (0xFFFF << I40E_GLPE_CPUTRIG0_PECPUTRIG0_SHIFT)
-#define I40E_GLPE_CPUTRIG0_TEPREQUEST0_SHIFT 17
-#define I40E_GLPE_CPUTRIG0_TEPREQUEST0_MASK (0x1 << I40E_GLPE_CPUTRIG0_TEPREQUEST0_SHIFT)
-#define I40E_GLPE_CPUTRIG0_OOPREQUEST0_SHIFT 18
-#define I40E_GLPE_CPUTRIG0_OOPREQUEST0_MASK (0x1 << I40E_GLPE_CPUTRIG0_OOPREQUEST0_SHIFT)
-#define I40E_GLPE_DUAL40_RUPM 0x0000DA04 /* Reset: PE_CORER */
-#define I40E_GLPE_DUAL40_RUPM_DUAL_40G_MODE_SHIFT 0
-#define I40E_GLPE_DUAL40_RUPM_DUAL_40G_MODE_MASK (0x1 << I40E_GLPE_DUAL40_RUPM_DUAL_40G_MODE_SHIFT)
-#define I40E_GLPE_PFAEQEDROPCNT(_i) (0x00131440 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */
-#define I40E_GLPE_PFAEQEDROPCNT_MAX_INDEX 15
-#define I40E_GLPE_PFAEQEDROPCNT_AEQEDROPCNT_SHIFT 0
-#define I40E_GLPE_PFAEQEDROPCNT_AEQEDROPCNT_MASK (0xFFFF << I40E_GLPE_PFAEQEDROPCNT_AEQEDROPCNT_SHIFT)
-#define I40E_GLPE_PFCEQEDROPCNT(_i) (0x001313C0 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */
-#define I40E_GLPE_PFCEQEDROPCNT_MAX_INDEX 15
-#define I40E_GLPE_PFCEQEDROPCNT_CEQEDROPCNT_SHIFT 0
-#define I40E_GLPE_PFCEQEDROPCNT_CEQEDROPCNT_MASK (0xFFFF << I40E_GLPE_PFCEQEDROPCNT_CEQEDROPCNT_SHIFT)
-#define I40E_GLPE_PFCQEDROPCNT(_i) (0x00131340 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */
-#define I40E_GLPE_PFCQEDROPCNT_MAX_INDEX 15
-#define I40E_GLPE_PFCQEDROPCNT_CQEDROPCNT_SHIFT 0
-#define I40E_GLPE_PFCQEDROPCNT_CQEDROPCNT_MASK (0xFFFF << I40E_GLPE_PFCQEDROPCNT_CQEDROPCNT_SHIFT)
-#define I40E_GLPE_RUPM_CQPPOOL 0x0000DACC /* Reset: PE_CORER */
-#define I40E_GLPE_RUPM_CQPPOOL_CQPSPADS_SHIFT 0
-#define I40E_GLPE_RUPM_CQPPOOL_CQPSPADS_MASK (0xFF << I40E_GLPE_RUPM_CQPPOOL_CQPSPADS_SHIFT)
-#define I40E_GLPE_RUPM_FLRPOOL 0x0000DAC4 /* Reset: PE_CORER */
-#define I40E_GLPE_RUPM_FLRPOOL_FLRSPADS_SHIFT 0
-#define I40E_GLPE_RUPM_FLRPOOL_FLRSPADS_MASK (0xFF << I40E_GLPE_RUPM_FLRPOOL_FLRSPADS_SHIFT)
-#define I40E_GLPE_RUPM_GCTL 0x0000DA00 /* Reset: PE_CORER */
-#define I40E_GLPE_RUPM_GCTL_ALLOFFTH_SHIFT 0
-#define I40E_GLPE_RUPM_GCTL_ALLOFFTH_MASK (0xFF << I40E_GLPE_RUPM_GCTL_ALLOFFTH_SHIFT)
-#define I40E_GLPE_RUPM_GCTL_RUPM_P0_DIS_SHIFT 26
-#define I40E_GLPE_RUPM_GCTL_RUPM_P0_DIS_MASK (0x1 << I40E_GLPE_RUPM_GCTL_RUPM_P0_DIS_SHIFT)
-#define I40E_GLPE_RUPM_GCTL_RUPM_P1_DIS_SHIFT 27
-#define I40E_GLPE_RUPM_GCTL_RUPM_P1_DIS_MASK (0x1 << I40E_GLPE_RUPM_GCTL_RUPM_P1_DIS_SHIFT)
-#define I40E_GLPE_RUPM_GCTL_RUPM_P2_DIS_SHIFT 28
-#define I40E_GLPE_RUPM_GCTL_RUPM_P2_DIS_MASK (0x1 << I40E_GLPE_RUPM_GCTL_RUPM_P2_DIS_SHIFT)
-#define I40E_GLPE_RUPM_GCTL_RUPM_P3_DIS_SHIFT 29
-#define I40E_GLPE_RUPM_GCTL_RUPM_P3_DIS_MASK (0x1 << I40E_GLPE_RUPM_GCTL_RUPM_P3_DIS_SHIFT)
-#define I40E_GLPE_RUPM_GCTL_RUPM_DIS_SHIFT 30
-#define I40E_GLPE_RUPM_GCTL_RUPM_DIS_MASK (0x1 << I40E_GLPE_RUPM_GCTL_RUPM_DIS_SHIFT)
-#define I40E_GLPE_RUPM_GCTL_SWLB_MODE_SHIFT 31
-#define I40E_GLPE_RUPM_GCTL_SWLB_MODE_MASK (0x1 << I40E_GLPE_RUPM_GCTL_SWLB_MODE_SHIFT)
-#define I40E_GLPE_RUPM_PTXPOOL 0x0000DAC8 /* Reset: PE_CORER */
-#define I40E_GLPE_RUPM_PTXPOOL_PTXSPADS_SHIFT 0
-#define I40E_GLPE_RUPM_PTXPOOL_PTXSPADS_MASK (0xFF << I40E_GLPE_RUPM_PTXPOOL_PTXSPADS_SHIFT)
-#define I40E_GLPE_RUPM_PUSHPOOL 0x0000DAC0 /* Reset: PE_CORER */
-#define I40E_GLPE_RUPM_PUSHPOOL_PUSHSPADS_SHIFT 0
-#define I40E_GLPE_RUPM_PUSHPOOL_PUSHSPADS_MASK (0xFF << I40E_GLPE_RUPM_PUSHPOOL_PUSHSPADS_SHIFT)
-#define I40E_GLPE_RUPM_TXHOST_EN 0x0000DA08 /* Reset: PE_CORER */
-#define I40E_GLPE_RUPM_TXHOST_EN_TXHOST_EN_SHIFT 0
-#define I40E_GLPE_RUPM_TXHOST_EN_TXHOST_EN_MASK (0x1 << I40E_GLPE_RUPM_TXHOST_EN_TXHOST_EN_SHIFT)
-#define I40E_GLPE_VFAEQEDROPCNT(_i) (0x00132540 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */
-#define I40E_GLPE_VFAEQEDROPCNT_MAX_INDEX 31
-#define I40E_GLPE_VFAEQEDROPCNT_AEQEDROPCNT_SHIFT 0
-#define I40E_GLPE_VFAEQEDROPCNT_AEQEDROPCNT_MASK (0xFFFF << I40E_GLPE_VFAEQEDROPCNT_AEQEDROPCNT_SHIFT)
-#define I40E_GLPE_VFCEQEDROPCNT(_i) (0x00132440 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */
-#define I40E_GLPE_VFCEQEDROPCNT_MAX_INDEX 31
-#define I40E_GLPE_VFCEQEDROPCNT_CEQEDROPCNT_SHIFT 0
-#define I40E_GLPE_VFCEQEDROPCNT_CEQEDROPCNT_MASK (0xFFFF << I40E_GLPE_VFCEQEDROPCNT_CEQEDROPCNT_SHIFT)
-#define I40E_GLPE_VFCQEDROPCNT(_i) (0x00132340 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */
-#define I40E_GLPE_VFCQEDROPCNT_MAX_INDEX 31
-#define I40E_GLPE_VFCQEDROPCNT_CQEDROPCNT_SHIFT 0
-#define I40E_GLPE_VFCQEDROPCNT_CQEDROPCNT_MASK (0xFFFF << I40E_GLPE_VFCQEDROPCNT_CQEDROPCNT_SHIFT)
-#define I40E_GLPE_VFFLMOBJCTRL(_i) (0x0000D400 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPE_VFFLMOBJCTRL_MAX_INDEX 31
-#define I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT 0
-#define I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_MASK (0x7 << I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT)
-#define I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT 8
-#define I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_MASK (0x7 << I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT)
-#define I40E_GLPE_VFFLMQ1ALLOCERR(_i) (0x0000C700 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPE_VFFLMQ1ALLOCERR_MAX_INDEX 31
-#define I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_SHIFT 0
-#define I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_SHIFT)
-#define I40E_GLPE_VFFLMXMITALLOCERR(_i) (0x0000C600 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPE_VFFLMXMITALLOCERR_MAX_INDEX 31
-#define I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_SHIFT 0
-#define I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_SHIFT)
-#define I40E_GLPE_VFUDACTRL(_i) (0x0000C000 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPE_VFUDACTRL_MAX_INDEX 31
-#define I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_SHIFT 0
-#define I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_SHIFT)
-#define I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_SHIFT 1
-#define I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_SHIFT)
-#define I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_SHIFT 2
-#define I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_SHIFT)
-#define I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_SHIFT 3
-#define I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_SHIFT)
-#define I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_SHIFT 4
-#define I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_MASK (0x1 << I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_SHIFT)
-#define I40E_GLPE_VFUDAUCFBQPN(_i) (0x0000C100 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPE_VFUDAUCFBQPN_MAX_INDEX 31
-#define I40E_GLPE_VFUDAUCFBQPN_QPN_SHIFT 0
-#define I40E_GLPE_VFUDAUCFBQPN_QPN_MASK (0x3FFFF << I40E_GLPE_VFUDAUCFBQPN_QPN_SHIFT)
-#define I40E_GLPE_VFUDAUCFBQPN_VALID_SHIFT 31
-#define I40E_GLPE_VFUDAUCFBQPN_VALID_MASK (0x1 << I40E_GLPE_VFUDAUCFBQPN_VALID_SHIFT)
-
-#define I40E_GLPES_PFIP4RXDISCARD(_i) (0x00010600 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4RXDISCARD_MAX_INDEX 15
-#define I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_SHIFT 0
-#define I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_SHIFT)
-#define I40E_GLPES_PFIP4RXFRAGSHI(_i) (0x00010804 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4RXFRAGSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT 0
-#define I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT)
-#define I40E_GLPES_PFIP4RXFRAGSLO(_i) (0x00010800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4RXFRAGSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT 0
-#define I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT)
-#define I40E_GLPES_PFIP4RXMCOCTSHI(_i) (0x00010A04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4RXMCOCTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT 0
-#define I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT)
-#define I40E_GLPES_PFIP4RXMCOCTSLO(_i) (0x00010A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4RXMCOCTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT 0
-#define I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT)
-#define I40E_GLPES_PFIP4RXMCPKTSHI(_i) (0x00010C04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4RXMCPKTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT 0
-#define I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT)
-#define I40E_GLPES_PFIP4RXMCPKTSLO(_i) (0x00010C00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4RXMCPKTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT 0
-#define I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT)
-#define I40E_GLPES_PFIP4RXOCTSHI(_i) (0x00010204 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4RXOCTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT 0
-#define I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT)
-#define I40E_GLPES_PFIP4RXOCTSLO(_i) (0x00010200 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4RXOCTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT 0
-#define I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT)
-#define I40E_GLPES_PFIP4RXPKTSHI(_i) (0x00010404 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4RXPKTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT 0
-#define I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT)
-#define I40E_GLPES_PFIP4RXPKTSLO(_i) (0x00010400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4RXPKTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT 0
-#define I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT)
-#define I40E_GLPES_PFIP4RXTRUNC(_i) (0x00010700 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4RXTRUNC_MAX_INDEX 15
-#define I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_SHIFT 0
-#define I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_SHIFT)
-#define I40E_GLPES_PFIP4TXFRAGSHI(_i) (0x00011E04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4TXFRAGSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT 0
-#define I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT)
-#define I40E_GLPES_PFIP4TXFRAGSLO(_i) (0x00011E00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4TXFRAGSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT 0
-#define I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT)
-#define I40E_GLPES_PFIP4TXMCOCTSHI(_i) (0x00012004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4TXMCOCTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT 0
-#define I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT)
-#define I40E_GLPES_PFIP4TXMCOCTSLO(_i) (0x00012000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4TXMCOCTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT 0
-#define I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT)
-#define I40E_GLPES_PFIP4TXMCPKTSHI(_i) (0x00012204 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4TXMCPKTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT 0
-#define I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT)
-#define I40E_GLPES_PFIP4TXMCPKTSLO(_i) (0x00012200 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4TXMCPKTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT 0
-#define I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT)
-#define I40E_GLPES_PFIP4TXNOROUTE(_i) (0x00012E00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4TXNOROUTE_MAX_INDEX 15
-#define I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT 0
-#define I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT)
-#define I40E_GLPES_PFIP4TXOCTSHI(_i) (0x00011A04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4TXOCTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT 0
-#define I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT)
-#define I40E_GLPES_PFIP4TXOCTSLO(_i) (0x00011A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4TXOCTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT 0
-#define I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT)
-#define I40E_GLPES_PFIP4TXPKTSHI(_i) (0x00011C04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4TXPKTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT 0
-#define I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT)
-#define I40E_GLPES_PFIP4TXPKTSLO(_i) (0x00011C00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP4TXPKTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT 0
-#define I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT)
-#define I40E_GLPES_PFIP6RXDISCARD(_i) (0x00011200 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6RXDISCARD_MAX_INDEX 15
-#define I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_SHIFT 0
-#define I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_SHIFT)
-#define I40E_GLPES_PFIP6RXFRAGSHI(_i) (0x00011404 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6RXFRAGSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT 0
-#define I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT)
-#define I40E_GLPES_PFIP6RXFRAGSLO(_i) (0x00011400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6RXFRAGSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT 0
-#define I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT)
-#define I40E_GLPES_PFIP6RXMCOCTSHI(_i) (0x00011604 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6RXMCOCTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT 0
-#define I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT)
-#define I40E_GLPES_PFIP6RXMCOCTSLO(_i) (0x00011600 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6RXMCOCTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT 0
-#define I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT)
-#define I40E_GLPES_PFIP6RXMCPKTSHI(_i) (0x00011804 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6RXMCPKTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT 0
-#define I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT)
-#define I40E_GLPES_PFIP6RXMCPKTSLO(_i) (0x00011800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6RXMCPKTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT 0
-#define I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT)
-#define I40E_GLPES_PFIP6RXOCTSHI(_i) (0x00010E04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6RXOCTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT 0
-#define I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT)
-#define I40E_GLPES_PFIP6RXOCTSLO(_i) (0x00010E00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6RXOCTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT 0
-#define I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT)
-#define I40E_GLPES_PFIP6RXPKTSHI(_i) (0x00011004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6RXPKTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT 0
-#define I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT)
-#define I40E_GLPES_PFIP6RXPKTSLO(_i) (0x00011000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6RXPKTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT 0
-#define I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT)
-#define I40E_GLPES_PFIP6RXTRUNC(_i) (0x00011300 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6RXTRUNC_MAX_INDEX 15
-#define I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_SHIFT 0
-#define I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_SHIFT)
-#define I40E_GLPES_PFIP6TXFRAGSHI(_i) (0x00012804 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6TXFRAGSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT 0
-#define I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT)
-#define I40E_GLPES_PFIP6TXFRAGSLO(_i) (0x00012800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6TXFRAGSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT 0
-#define I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT)
-#define I40E_GLPES_PFIP6TXMCOCTSHI(_i) (0x00012A04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6TXMCOCTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT 0
-#define I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT)
-#define I40E_GLPES_PFIP6TXMCOCTSLO(_i) (0x00012A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6TXMCOCTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT 0
-#define I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT)
-#define I40E_GLPES_PFIP6TXMCPKTSHI(_i) (0x00012C04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6TXMCPKTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT 0
-#define I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT)
-#define I40E_GLPES_PFIP6TXMCPKTSLO(_i) (0x00012C00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6TXMCPKTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT 0
-#define I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT)
-#define I40E_GLPES_PFIP6TXNOROUTE(_i) (0x00012F00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6TXNOROUTE_MAX_INDEX 15
-#define I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT 0
-#define I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT)
-#define I40E_GLPES_PFIP6TXOCTSHI(_i) (0x00012404 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6TXOCTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT 0
-#define I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT)
-#define I40E_GLPES_PFIP6TXOCTSLO(_i) (0x00012400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6TXOCTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT 0
-#define I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT)
-#define I40E_GLPES_PFIP6TXPKTSHI(_i) (0x00012604 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6TXPKTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT 0
-#define I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT)
-#define I40E_GLPES_PFIP6TXPKTSLO(_i) (0x00012600 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFIP6TXPKTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT 0
-#define I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT)
-#define I40E_GLPES_PFRDMARXRDSHI(_i) (0x00013E04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMARXRDSHI_MAX_INDEX 15
-#define I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_SHIFT 0
-#define I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_SHIFT)
-#define I40E_GLPES_PFRDMARXRDSLO(_i) (0x00013E00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMARXRDSLO_MAX_INDEX 15
-#define I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_SHIFT 0
-#define I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_SHIFT)
-#define I40E_GLPES_PFRDMARXSNDSHI(_i) (0x00014004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMARXSNDSHI_MAX_INDEX 15
-#define I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT 0
-#define I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT)
-#define I40E_GLPES_PFRDMARXSNDSLO(_i) (0x00014000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMARXSNDSLO_MAX_INDEX 15
-#define I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT 0
-#define I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT)
-#define I40E_GLPES_PFRDMARXWRSHI(_i) (0x00013C04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMARXWRSHI_MAX_INDEX 15
-#define I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_SHIFT 0
-#define I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_SHIFT)
-#define I40E_GLPES_PFRDMARXWRSLO(_i) (0x00013C00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMARXWRSLO_MAX_INDEX 15
-#define I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_SHIFT 0
-#define I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_SHIFT)
-#define I40E_GLPES_PFRDMATXRDSHI(_i) (0x00014404 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMATXRDSHI_MAX_INDEX 15
-#define I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_SHIFT 0
-#define I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_SHIFT)
-#define I40E_GLPES_PFRDMATXRDSLO(_i) (0x00014400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMATXRDSLO_MAX_INDEX 15
-#define I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_SHIFT 0
-#define I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_SHIFT)
-#define I40E_GLPES_PFRDMATXSNDSHI(_i) (0x00014604 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMATXSNDSHI_MAX_INDEX 15
-#define I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT 0
-#define I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT)
-#define I40E_GLPES_PFRDMATXSNDSLO(_i) (0x00014600 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMATXSNDSLO_MAX_INDEX 15
-#define I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT 0
-#define I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT)
-#define I40E_GLPES_PFRDMATXWRSHI(_i) (0x00014204 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMATXWRSHI_MAX_INDEX 15
-#define I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_SHIFT 0
-#define I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_SHIFT)
-#define I40E_GLPES_PFRDMATXWRSLO(_i) (0x00014200 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMATXWRSLO_MAX_INDEX 15
-#define I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_SHIFT 0
-#define I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_SHIFT)
-#define I40E_GLPES_PFRDMAVBNDHI(_i) (0x00014804 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMAVBNDHI_MAX_INDEX 15
-#define I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_SHIFT 0
-#define I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_SHIFT)
-#define I40E_GLPES_PFRDMAVBNDLO(_i) (0x00014800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMAVBNDLO_MAX_INDEX 15
-#define I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_SHIFT 0
-#define I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_SHIFT)
-#define I40E_GLPES_PFRDMAVINVHI(_i) (0x00014A04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMAVINVHI_MAX_INDEX 15
-#define I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_SHIFT 0
-#define I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_SHIFT)
-#define I40E_GLPES_PFRDMAVINVLO(_i) (0x00014A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRDMAVINVLO_MAX_INDEX 15
-#define I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_SHIFT 0
-#define I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_SHIFT)
-#define I40E_GLPES_PFRXVLANERR(_i) (0x00010000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFRXVLANERR_MAX_INDEX 15
-#define I40E_GLPES_PFRXVLANERR_RXVLANERR_SHIFT 0
-#define I40E_GLPES_PFRXVLANERR_RXVLANERR_MASK (0xFFFFFF << I40E_GLPES_PFRXVLANERR_RXVLANERR_SHIFT)
-#define I40E_GLPES_PFTCPRTXSEG(_i) (0x00013600 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFTCPRTXSEG_MAX_INDEX 15
-#define I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_SHIFT 0
-#define I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_MASK (0xFFFFFFFF << I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_SHIFT)
-#define I40E_GLPES_PFTCPRXOPTERR(_i) (0x00013200 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFTCPRXOPTERR_MAX_INDEX 15
-#define I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_SHIFT 0
-#define I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_MASK (0xFFFFFF << I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_SHIFT)
-#define I40E_GLPES_PFTCPRXPROTOERR(_i) (0x00013300 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFTCPRXPROTOERR_MAX_INDEX 15
-#define I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT 0
-#define I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_MASK (0xFFFFFF << I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT)
-#define I40E_GLPES_PFTCPRXSEGSHI(_i) (0x00013004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFTCPRXSEGSHI_MAX_INDEX 15
-#define I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT 0
-#define I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_MASK (0xFFFF << I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT)
-#define I40E_GLPES_PFTCPRXSEGSLO(_i) (0x00013000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFTCPRXSEGSLO_MAX_INDEX 15
-#define I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT 0
-#define I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT)
-#define I40E_GLPES_PFTCPTXSEGHI(_i) (0x00013404 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFTCPTXSEGHI_MAX_INDEX 15
-#define I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_SHIFT 0
-#define I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_MASK (0xFFFF << I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_SHIFT)
-#define I40E_GLPES_PFTCPTXSEGLO(_i) (0x00013400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFTCPTXSEGLO_MAX_INDEX 15
-#define I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_SHIFT 0
-#define I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_MASK (0xFFFFFFFF << I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_SHIFT)
-#define I40E_GLPES_PFUDPRXPKTSHI(_i) (0x00013804 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFUDPRXPKTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT 0
-#define I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT)
-#define I40E_GLPES_PFUDPRXPKTSLO(_i) (0x00013800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFUDPRXPKTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT 0
-#define I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT)
-#define I40E_GLPES_PFUDPTXPKTSHI(_i) (0x00013A04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFUDPTXPKTSHI_MAX_INDEX 15
-#define I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT 0
-#define I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT)
-#define I40E_GLPES_PFUDPTXPKTSLO(_i) (0x00013A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
-#define I40E_GLPES_PFUDPTXPKTSLO_MAX_INDEX 15
-#define I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT 0
-#define I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT)
-#define I40E_GLPES_RDMARXMULTFPDUSHI 0x0001E014 /* Reset: PE_CORER */
-#define I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_SHIFT 0
-#define I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_MASK (0xFFFFFF << I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_SHIFT)
-#define I40E_GLPES_RDMARXMULTFPDUSLO 0x0001E010 /* Reset: PE_CORER */
-#define I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_SHIFT 0
-#define I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_SHIFT)
-#define I40E_GLPES_RDMARXOOODDPHI 0x0001E01C /* Reset: PE_CORER */
-#define I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_SHIFT 0
-#define I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_MASK (0xFFFFFF << I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_SHIFT)
-#define I40E_GLPES_RDMARXOOODDPLO 0x0001E018 /* Reset: PE_CORER */
-#define I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_SHIFT 0
-#define I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_SHIFT)
-#define I40E_GLPES_RDMARXOOONOMARK 0x0001E004 /* Reset: PE_CORER */
-#define I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_SHIFT 0
-#define I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_SHIFT)
-#define I40E_GLPES_RDMARXUNALIGN 0x0001E000 /* Reset: PE_CORER */
-#define I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_SHIFT 0
-#define I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_SHIFT)
-#define I40E_GLPES_TCPRXFOURHOLEHI 0x0001E044 /* Reset: PE_CORER */
-#define I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_SHIFT 0
-#define I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_SHIFT)
-#define I40E_GLPES_TCPRXFOURHOLELO 0x0001E040 /* Reset: PE_CORER */
-#define I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_SHIFT 0
-#define I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_SHIFT)
-#define I40E_GLPES_TCPRXONEHOLEHI 0x0001E02C /* Reset: PE_CORER */
-#define I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_SHIFT 0
-#define I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_SHIFT)
-#define I40E_GLPES_TCPRXONEHOLELO 0x0001E028 /* Reset: PE_CORER */
-#define I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_SHIFT 0
-#define I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_SHIFT)
-#define I40E_GLPES_TCPRXPUREACKHI 0x0001E024 /* Reset: PE_CORER */
-#define I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_SHIFT 0
-#define I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_SHIFT)
-#define I40E_GLPES_TCPRXPUREACKSLO 0x0001E020 /* Reset: PE_CORER */
-#define I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_SHIFT 0
-#define I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_SHIFT)
-#define I40E_GLPES_TCPRXTHREEHOLEHI 0x0001E03C /* Reset: PE_CORER */
-#define I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_SHIFT 0
-#define I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_SHIFT)
-#define I40E_GLPES_TCPRXTHREEHOLELO 0x0001E038 /* Reset: PE_CORER */
-#define I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_SHIFT 0
-#define I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_SHIFT)
-#define I40E_GLPES_TCPRXTWOHOLEHI 0x0001E034 /* Reset: PE_CORER */
-#define I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_SHIFT 0
-#define I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_SHIFT)
-#define I40E_GLPES_TCPRXTWOHOLELO 0x0001E030 /* Reset: PE_CORER */
-#define I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_SHIFT 0
-#define I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_SHIFT)
-#define I40E_GLPES_TCPTXRETRANSFASTHI 0x0001E04C /* Reset: PE_CORER */
-#define I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_SHIFT 0
-#define I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_MASK (0xFFFFFF << I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_SHIFT)
-#define I40E_GLPES_TCPTXRETRANSFASTLO 0x0001E048 /* Reset: PE_CORER */
-#define I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_SHIFT 0
-#define I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_SHIFT)
-#define I40E_GLPES_TCPTXTOUTSFASTHI 0x0001E054 /* Reset: PE_CORER */
-#define I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_SHIFT 0
-#define I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_MASK (0xFFFFFF << I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_SHIFT)
-#define I40E_GLPES_TCPTXTOUTSFASTLO 0x0001E050 /* Reset: PE_CORER */
-#define I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_SHIFT 0
-#define I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_SHIFT)
-#define I40E_GLPES_TCPTXTOUTSHI 0x0001E05C /* Reset: PE_CORER */
-#define I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_SHIFT 0
-#define I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_MASK (0xFFFFFF << I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_SHIFT)
-#define I40E_GLPES_TCPTXTOUTSLO 0x0001E058 /* Reset: PE_CORER */
-#define I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_SHIFT 0
-#define I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_SHIFT)
-#define I40E_GLPES_VFIP4RXDISCARD(_i) (0x00018600 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4RXDISCARD_MAX_INDEX 31
-#define I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_SHIFT 0
-#define I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_SHIFT)
-#define I40E_GLPES_VFIP4RXFRAGSHI(_i) (0x00018804 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4RXFRAGSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT 0
-#define I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT)
-#define I40E_GLPES_VFIP4RXFRAGSLO(_i) (0x00018800 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4RXFRAGSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT 0
-#define I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT)
-#define I40E_GLPES_VFIP4RXMCOCTSHI(_i) (0x00018A04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4RXMCOCTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT 0
-#define I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT)
-#define I40E_GLPES_VFIP4RXMCOCTSLO(_i) (0x00018A00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4RXMCOCTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT 0
-#define I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT)
-#define I40E_GLPES_VFIP4RXMCPKTSHI(_i) (0x00018C04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4RXMCPKTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT 0
-#define I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT)
-#define I40E_GLPES_VFIP4RXMCPKTSLO(_i) (0x00018C00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4RXMCPKTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT 0
-#define I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT)
-#define I40E_GLPES_VFIP4RXOCTSHI(_i) (0x00018204 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4RXOCTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT 0
-#define I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT)
-#define I40E_GLPES_VFIP4RXOCTSLO(_i) (0x00018200 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4RXOCTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT 0
-#define I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT)
-#define I40E_GLPES_VFIP4RXPKTSHI(_i) (0x00018404 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4RXPKTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT 0
-#define I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT)
-#define I40E_GLPES_VFIP4RXPKTSLO(_i) (0x00018400 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4RXPKTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT 0
-#define I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT)
-#define I40E_GLPES_VFIP4RXTRUNC(_i) (0x00018700 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4RXTRUNC_MAX_INDEX 31
-#define I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_SHIFT 0
-#define I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_SHIFT)
-#define I40E_GLPES_VFIP4TXFRAGSHI(_i) (0x00019E04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4TXFRAGSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT 0
-#define I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT)
-#define I40E_GLPES_VFIP4TXFRAGSLO(_i) (0x00019E00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4TXFRAGSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT 0
-#define I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT)
-#define I40E_GLPES_VFIP4TXMCOCTSHI(_i) (0x0001A004 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4TXMCOCTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT 0
-#define I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT)
-#define I40E_GLPES_VFIP4TXMCOCTSLO(_i) (0x0001A000 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4TXMCOCTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT 0
-#define I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT)
-#define I40E_GLPES_VFIP4TXMCPKTSHI(_i) (0x0001A204 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4TXMCPKTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT 0
-#define I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT)
-#define I40E_GLPES_VFIP4TXMCPKTSLO(_i) (0x0001A200 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4TXMCPKTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT 0
-#define I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT)
-#define I40E_GLPES_VFIP4TXNOROUTE(_i) (0x0001AE00 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4TXNOROUTE_MAX_INDEX 31
-#define I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT 0
-#define I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT)
-#define I40E_GLPES_VFIP4TXOCTSHI(_i) (0x00019A04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4TXOCTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT 0
-#define I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT)
-#define I40E_GLPES_VFIP4TXOCTSLO(_i) (0x00019A00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4TXOCTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT 0
-#define I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT)
-#define I40E_GLPES_VFIP4TXPKTSHI(_i) (0x00019C04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4TXPKTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT 0
-#define I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT)
-#define I40E_GLPES_VFIP4TXPKTSLO(_i) (0x00019C00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP4TXPKTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT 0
-#define I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT)
-#define I40E_GLPES_VFIP6RXDISCARD(_i) (0x00019200 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6RXDISCARD_MAX_INDEX 31
-#define I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_SHIFT 0
-#define I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_SHIFT)
-#define I40E_GLPES_VFIP6RXFRAGSHI(_i) (0x00019404 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6RXFRAGSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT 0
-#define I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT)
-#define I40E_GLPES_VFIP6RXFRAGSLO(_i) (0x00019400 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6RXFRAGSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT 0
-#define I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT)
-#define I40E_GLPES_VFIP6RXMCOCTSHI(_i) (0x00019604 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6RXMCOCTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT 0
-#define I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT)
-#define I40E_GLPES_VFIP6RXMCOCTSLO(_i) (0x00019600 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6RXMCOCTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT 0
-#define I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT)
-#define I40E_GLPES_VFIP6RXMCPKTSHI(_i) (0x00019804 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6RXMCPKTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT 0
-#define I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT)
-#define I40E_GLPES_VFIP6RXMCPKTSLO(_i) (0x00019800 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6RXMCPKTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT 0
-#define I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT)
-#define I40E_GLPES_VFIP6RXOCTSHI(_i) (0x00018E04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6RXOCTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT 0
-#define I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT)
-#define I40E_GLPES_VFIP6RXOCTSLO(_i) (0x00018E00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6RXOCTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT 0
-#define I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT)
-#define I40E_GLPES_VFIP6RXPKTSHI(_i) (0x00019004 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6RXPKTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT 0
-#define I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT)
-#define I40E_GLPES_VFIP6RXPKTSLO(_i) (0x00019000 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6RXPKTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT 0
-#define I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT)
-#define I40E_GLPES_VFIP6RXTRUNC(_i) (0x00019300 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6RXTRUNC_MAX_INDEX 31
-#define I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_SHIFT 0
-#define I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_SHIFT)
-#define I40E_GLPES_VFIP6TXFRAGSHI(_i) (0x0001A804 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6TXFRAGSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT 0
-#define I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT)
-#define I40E_GLPES_VFIP6TXFRAGSLO(_i) (0x0001A800 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6TXFRAGSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT 0
-#define I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT)
-#define I40E_GLPES_VFIP6TXMCOCTSHI(_i) (0x0001AA04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6TXMCOCTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT 0
-#define I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT)
-#define I40E_GLPES_VFIP6TXMCOCTSLO(_i) (0x0001AA00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6TXMCOCTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT 0
-#define I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT)
-#define I40E_GLPES_VFIP6TXMCPKTSHI(_i) (0x0001AC04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6TXMCPKTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT 0
-#define I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT)
-#define I40E_GLPES_VFIP6TXMCPKTSLO(_i) (0x0001AC00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6TXMCPKTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT 0
-#define I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT)
-#define I40E_GLPES_VFIP6TXNOROUTE(_i) (0x0001AF00 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6TXNOROUTE_MAX_INDEX 31
-#define I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT 0
-#define I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT)
-#define I40E_GLPES_VFIP6TXOCTSHI(_i) (0x0001A404 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6TXOCTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT 0
-#define I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT)
-#define I40E_GLPES_VFIP6TXOCTSLO(_i) (0x0001A400 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6TXOCTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT 0
-#define I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT)
-#define I40E_GLPES_VFIP6TXPKTSHI(_i) (0x0001A604 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6TXPKTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT 0
-#define I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT)
-#define I40E_GLPES_VFIP6TXPKTSLO(_i) (0x0001A600 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFIP6TXPKTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT 0
-#define I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT)
-#define I40E_GLPES_VFRDMARXRDSHI(_i) (0x0001BE04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMARXRDSHI_MAX_INDEX 31
-#define I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_SHIFT 0
-#define I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_SHIFT)
-#define I40E_GLPES_VFRDMARXRDSLO(_i) (0x0001BE00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMARXRDSLO_MAX_INDEX 31
-#define I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_SHIFT 0
-#define I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_SHIFT)
-#define I40E_GLPES_VFRDMARXSNDSHI(_i) (0x0001C004 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMARXSNDSHI_MAX_INDEX 31
-#define I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT 0
-#define I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT)
-#define I40E_GLPES_VFRDMARXSNDSLO(_i) (0x0001C000 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMARXSNDSLO_MAX_INDEX 31
-#define I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT 0
-#define I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT)
-#define I40E_GLPES_VFRDMARXWRSHI(_i) (0x0001BC04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMARXWRSHI_MAX_INDEX 31
-#define I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_SHIFT 0
-#define I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_SHIFT)
-#define I40E_GLPES_VFRDMARXWRSLO(_i) (0x0001BC00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMARXWRSLO_MAX_INDEX 31
-#define I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_SHIFT 0
-#define I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_SHIFT)
-#define I40E_GLPES_VFRDMATXRDSHI(_i) (0x0001C404 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMATXRDSHI_MAX_INDEX 31
-#define I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_SHIFT 0
-#define I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_SHIFT)
-#define I40E_GLPES_VFRDMATXRDSLO(_i) (0x0001C400 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMATXRDSLO_MAX_INDEX 31
-#define I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_SHIFT 0
-#define I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_SHIFT)
-#define I40E_GLPES_VFRDMATXSNDSHI(_i) (0x0001C604 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMATXSNDSHI_MAX_INDEX 31
-#define I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT 0
-#define I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT)
-#define I40E_GLPES_VFRDMATXSNDSLO(_i) (0x0001C600 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMATXSNDSLO_MAX_INDEX 31
-#define I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT 0
-#define I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT)
-#define I40E_GLPES_VFRDMATXWRSHI(_i) (0x0001C204 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMATXWRSHI_MAX_INDEX 31
-#define I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_SHIFT 0
-#define I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_SHIFT)
-#define I40E_GLPES_VFRDMATXWRSLO(_i) (0x0001C200 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMATXWRSLO_MAX_INDEX 31
-#define I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_SHIFT 0
-#define I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_SHIFT)
-#define I40E_GLPES_VFRDMAVBNDHI(_i) (0x0001C804 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMAVBNDHI_MAX_INDEX 31
-#define I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_SHIFT 0
-#define I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_SHIFT)
-#define I40E_GLPES_VFRDMAVBNDLO(_i) (0x0001C800 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMAVBNDLO_MAX_INDEX 31
-#define I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_SHIFT 0
-#define I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_SHIFT)
-#define I40E_GLPES_VFRDMAVINVHI(_i) (0x0001CA04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMAVINVHI_MAX_INDEX 31
-#define I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_SHIFT 0
-#define I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_SHIFT)
-#define I40E_GLPES_VFRDMAVINVLO(_i) (0x0001CA00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRDMAVINVLO_MAX_INDEX 31
-#define I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_SHIFT 0
-#define I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_SHIFT)
-#define I40E_GLPES_VFRXVLANERR(_i) (0x00018000 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFRXVLANERR_MAX_INDEX 31
-#define I40E_GLPES_VFRXVLANERR_RXVLANERR_SHIFT 0
-#define I40E_GLPES_VFRXVLANERR_RXVLANERR_MASK (0xFFFFFF << I40E_GLPES_VFRXVLANERR_RXVLANERR_SHIFT)
-#define I40E_GLPES_VFTCPRTXSEG(_i) (0x0001B600 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFTCPRTXSEG_MAX_INDEX 31
-#define I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_SHIFT 0
-#define I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_MASK (0xFFFFFFFF << I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_SHIFT)
-#define I40E_GLPES_VFTCPRXOPTERR(_i) (0x0001B200 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFTCPRXOPTERR_MAX_INDEX 31
-#define I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_SHIFT 0
-#define I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_MASK (0xFFFFFF << I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_SHIFT)
-#define I40E_GLPES_VFTCPRXPROTOERR(_i) (0x0001B300 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFTCPRXPROTOERR_MAX_INDEX 31
-#define I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT 0
-#define I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_MASK (0xFFFFFF << I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT)
-#define I40E_GLPES_VFTCPRXSEGSHI(_i) (0x0001B004 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFTCPRXSEGSHI_MAX_INDEX 31
-#define I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT 0
-#define I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_MASK (0xFFFF << I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT)
-#define I40E_GLPES_VFTCPRXSEGSLO(_i) (0x0001B000 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFTCPRXSEGSLO_MAX_INDEX 31
-#define I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT 0
-#define I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT)
-#define I40E_GLPES_VFTCPTXSEGHI(_i) (0x0001B404 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFTCPTXSEGHI_MAX_INDEX 31
-#define I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_SHIFT 0
-#define I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_MASK (0xFFFF << I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_SHIFT)
-#define I40E_GLPES_VFTCPTXSEGLO(_i) (0x0001B400 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFTCPTXSEGLO_MAX_INDEX 31
-#define I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_SHIFT 0
-#define I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_MASK (0xFFFFFFFF << I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_SHIFT)
-#define I40E_GLPES_VFUDPRXPKTSHI(_i) (0x0001B804 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFUDPRXPKTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT 0
-#define I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT)
-#define I40E_GLPES_VFUDPRXPKTSLO(_i) (0x0001B800 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFUDPRXPKTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT 0
-#define I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT)
-#define I40E_GLPES_VFUDPTXPKTSHI(_i) (0x0001BA04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFUDPTXPKTSHI_MAX_INDEX 31
-#define I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT 0
-#define I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT)
-#define I40E_GLPES_VFUDPTXPKTSLO(_i) (0x0001BA00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */
-#define I40E_GLPES_VFUDPTXPKTSLO_MAX_INDEX 31
-#define I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT 0
-#define I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT)
-
-#define I40E_VFPE_AEQALLOC1 0x0000A400 /* Reset: VFR */
-#define I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT 0
-#define I40E_VFPE_AEQALLOC1_AECOUNT_MASK (0xFFFFFFFF << I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT)
-#define I40E_VFPE_CCQPHIGH1 0x00009800 /* Reset: VFR */
-#define I40E_VFPE_CCQPHIGH1_PECCQPHIGH_SHIFT 0
-#define I40E_VFPE_CCQPHIGH1_PECCQPHIGH_MASK (0xFFFFFFFF << I40E_VFPE_CCQPHIGH1_PECCQPHIGH_SHIFT)
-#define I40E_VFPE_CCQPLOW1 0x0000AC00 /* Reset: VFR */
-#define I40E_VFPE_CCQPLOW1_PECCQPLOW_SHIFT 0
-#define I40E_VFPE_CCQPLOW1_PECCQPLOW_MASK (0xFFFFFFFF << I40E_VFPE_CCQPLOW1_PECCQPLOW_SHIFT)
-#define I40E_VFPE_CCQPSTATUS1 0x0000B800 /* Reset: VFR */
-#define I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT 0
-#define I40E_VFPE_CCQPSTATUS1_CCQP_DONE_MASK (0x1 << I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT)
-#define I40E_VFPE_CCQPSTATUS1_HMC_PROFILE_SHIFT 4
-#define I40E_VFPE_CCQPSTATUS1_HMC_PROFILE_MASK (0x7 << I40E_VFPE_CCQPSTATUS1_HMC_PROFILE_SHIFT)
-#define I40E_VFPE_CCQPSTATUS1_RDMA_EN_VFS_SHIFT 16
-#define I40E_VFPE_CCQPSTATUS1_RDMA_EN_VFS_MASK (0x3F << I40E_VFPE_CCQPSTATUS1_RDMA_EN_VFS_SHIFT)
-#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT 31
-#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_MASK (0x1 << I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT)
-#define I40E_VFPE_CQACK1 0x0000B000 /* Reset: VFR */
-#define I40E_VFPE_CQACK1_PECQID_SHIFT 0
-#define I40E_VFPE_CQACK1_PECQID_MASK (0x1FFFF << I40E_VFPE_CQACK1_PECQID_SHIFT)
-#define I40E_VFPE_CQARM1 0x0000B400 /* Reset: VFR */
-#define I40E_VFPE_CQARM1_PECQID_SHIFT 0
-#define I40E_VFPE_CQARM1_PECQID_MASK (0x1FFFF << I40E_VFPE_CQARM1_PECQID_SHIFT)
-#define I40E_VFPE_CQPDB1 0x0000BC00 /* Reset: VFR */
-#define I40E_VFPE_CQPDB1_WQHEAD_SHIFT 0
-#define I40E_VFPE_CQPDB1_WQHEAD_MASK (0x7FF << I40E_VFPE_CQPDB1_WQHEAD_SHIFT)
-#define I40E_VFPE_CQPERRCODES1 0x00009C00 /* Reset: VFR */
-#define I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_SHIFT 0
-#define I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_SHIFT)
-#define I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_SHIFT 16
-#define I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_SHIFT)
-#define I40E_VFPE_CQPTAIL1 0x0000A000 /* Reset: VFR */
-#define I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT 0
-#define I40E_VFPE_CQPTAIL1_WQTAIL_MASK (0x7FF << I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT)
-#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT 31
-#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_MASK (0x1 << I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT)
-#define I40E_VFPE_IPCONFIG01 0x00008C00 /* Reset: VFR */
-#define I40E_VFPE_IPCONFIG01_PEIPID_SHIFT 0
-#define I40E_VFPE_IPCONFIG01_PEIPID_MASK (0xFFFF << I40E_VFPE_IPCONFIG01_PEIPID_SHIFT)
-#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT 16
-#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_MASK (0x1 << I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT)
-#define I40E_VFPE_MRTEIDXMASK1 0x00009000 /* Reset: VFR */
-#define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT 0
-#define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_MASK (0x1F << I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT)
-#define I40E_VFPE_RCVUNEXPECTEDERROR1 0x00009400 /* Reset: VFR */
-#define I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_SHIFT 0
-#define I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_MASK (0xFFFFFF << I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_SHIFT)
-#define I40E_VFPE_TCPNOWTIMER1 0x0000A800 /* Reset: VFR */
-#define I40E_VFPE_TCPNOWTIMER1_TCP_NOW_SHIFT 0
-#define I40E_VFPE_TCPNOWTIMER1_TCP_NOW_MASK (0xFFFFFFFF << I40E_VFPE_TCPNOWTIMER1_TCP_NOW_SHIFT)
-#define I40E_VFPE_WQEALLOC1 0x0000C000 /* Reset: VFR */
-#define I40E_VFPE_WQEALLOC1_PEQPID_SHIFT 0
-#define I40E_VFPE_WQEALLOC1_PEQPID_MASK (0x3FFFF << I40E_VFPE_WQEALLOC1_PEQPID_SHIFT)
-#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT 20
-#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_MASK (0xFFF << I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT)
-#endif /* I40IW_REGISTER_H */
diff --git a/drivers/infiniband/hw/i40iw/i40iw_status.h b/drivers/infiniband/hw/i40iw/i40iw_status.h
deleted file mode 100644
index 36a19c4e5bba..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_status.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_STATUS_H
-#define I40IW_STATUS_H
-
-/* Error Codes */
-enum i40iw_status_code {
- I40IW_SUCCESS = 0,
- I40IW_ERR_NVM = -1,
- I40IW_ERR_NVM_CHECKSUM = -2,
- I40IW_ERR_CONFIG = -4,
- I40IW_ERR_PARAM = -5,
- I40IW_ERR_DEVICE_NOT_SUPPORTED = -6,
- I40IW_ERR_RESET_FAILED = -7,
- I40IW_ERR_SWFW_SYNC = -8,
- I40IW_ERR_NO_MEMORY = -9,
- I40IW_ERR_BAD_PTR = -10,
- I40IW_ERR_INVALID_PD_ID = -11,
- I40IW_ERR_INVALID_QP_ID = -12,
- I40IW_ERR_INVALID_CQ_ID = -13,
- I40IW_ERR_INVALID_CEQ_ID = -14,
- I40IW_ERR_INVALID_AEQ_ID = -15,
- I40IW_ERR_INVALID_SIZE = -16,
- I40IW_ERR_INVALID_ARP_INDEX = -17,
- I40IW_ERR_INVALID_FPM_FUNC_ID = -18,
- I40IW_ERR_QP_INVALID_MSG_SIZE = -19,
- I40IW_ERR_QP_TOOMANY_WRS_POSTED = -20,
- I40IW_ERR_INVALID_FRAG_COUNT = -21,
- I40IW_ERR_QUEUE_EMPTY = -22,
- I40IW_ERR_INVALID_ALIGNMENT = -23,
- I40IW_ERR_FLUSHED_QUEUE = -24,
- I40IW_ERR_INVALID_INLINE_DATA_SIZE = -26,
- I40IW_ERR_TIMEOUT = -27,
- I40IW_ERR_OPCODE_MISMATCH = -28,
- I40IW_ERR_CQP_COMPL_ERROR = -29,
- I40IW_ERR_INVALID_VF_ID = -30,
- I40IW_ERR_INVALID_HMCFN_ID = -31,
- I40IW_ERR_BACKING_PAGE_ERROR = -32,
- I40IW_ERR_NO_PBLCHUNKS_AVAILABLE = -33,
- I40IW_ERR_INVALID_PBLE_INDEX = -34,
- I40IW_ERR_INVALID_SD_INDEX = -35,
- I40IW_ERR_INVALID_PAGE_DESC_INDEX = -36,
- I40IW_ERR_INVALID_SD_TYPE = -37,
- I40IW_ERR_MEMCPY_FAILED = -38,
- I40IW_ERR_INVALID_HMC_OBJ_INDEX = -39,
- I40IW_ERR_INVALID_HMC_OBJ_COUNT = -40,
- I40IW_ERR_INVALID_SRQ_ARM_LIMIT = -41,
- I40IW_ERR_SRQ_ENABLED = -42,
- I40IW_ERR_BUF_TOO_SHORT = -43,
- I40IW_ERR_BAD_IWARP_CQE = -44,
- I40IW_ERR_NVM_BLANK_MODE = -45,
- I40IW_ERR_NOT_IMPLEMENTED = -46,
- I40IW_ERR_PE_DOORBELL_NOT_ENABLED = -47,
- I40IW_ERR_NOT_READY = -48,
- I40IW_NOT_SUPPORTED = -49,
- I40IW_ERR_FIRMWARE_API_VERSION = -50,
- I40IW_ERR_RING_FULL = -51,
- I40IW_ERR_MPA_CRC = -61,
- I40IW_ERR_NO_TXBUFS = -62,
- I40IW_ERR_SEQ_NUM = -63,
- I40IW_ERR_list_empty = -64,
- I40IW_ERR_INVALID_MAC_ADDR = -65,
- I40IW_ERR_BAD_STAG = -66,
- I40IW_ERR_CQ_COMPL_ERROR = -67,
- I40IW_ERR_QUEUE_DESTROYED = -68,
- I40IW_ERR_INVALID_FEAT_CNT = -69
-
-};
-#endif
diff --git a/drivers/infiniband/hw/i40iw/i40iw_type.h b/drivers/infiniband/hw/i40iw/i40iw_type.h
deleted file mode 100644
index 394e182686cf..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_type.h
+++ /dev/null
@@ -1,1358 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_TYPE_H
-#define I40IW_TYPE_H
-#include "i40iw_user.h"
-#include "i40iw_hmc.h"
-#include "i40iw_vf.h"
-#include "i40iw_virtchnl.h"
-
-struct i40iw_cqp_sq_wqe {
- u64 buf[I40IW_CQP_WQE_SIZE];
-};
-
-struct i40iw_sc_aeqe {
- u64 buf[I40IW_AEQE_SIZE];
-};
-
-struct i40iw_ceqe {
- u64 buf[I40IW_CEQE_SIZE];
-};
-
-struct i40iw_cqp_ctx {
- u64 buf[I40IW_CQP_CTX_SIZE];
-};
-
-struct i40iw_cq_shadow_area {
- u64 buf[I40IW_SHADOW_AREA_SIZE];
-};
-
-struct i40iw_sc_dev;
-struct i40iw_hmc_info;
-struct i40iw_vsi_pestat;
-
-struct i40iw_cqp_ops;
-struct i40iw_ccq_ops;
-struct i40iw_ceq_ops;
-struct i40iw_aeq_ops;
-struct i40iw_mr_ops;
-struct i40iw_cqp_misc_ops;
-struct i40iw_pd_ops;
-struct i40iw_priv_qp_ops;
-struct i40iw_priv_cq_ops;
-struct i40iw_hmc_ops;
-struct pci_dev;
-
-enum i40iw_page_size {
- I40IW_PAGE_SIZE_4K,
- I40IW_PAGE_SIZE_2M
-};
-
-enum i40iw_resource_indicator_type {
- I40IW_RSRC_INDICATOR_TYPE_ADAPTER = 0,
- I40IW_RSRC_INDICATOR_TYPE_CQ,
- I40IW_RSRC_INDICATOR_TYPE_QP,
- I40IW_RSRC_INDICATOR_TYPE_SRQ
-};
-
-enum i40iw_hdrct_flags {
- DDP_LEN_FLAG = 0x80,
- DDP_HDR_FLAG = 0x40,
- RDMA_HDR_FLAG = 0x20
-};
-
-enum i40iw_term_layers {
- LAYER_RDMA = 0,
- LAYER_DDP = 1,
- LAYER_MPA = 2
-};
-
-enum i40iw_term_error_types {
- RDMAP_REMOTE_PROT = 1,
- RDMAP_REMOTE_OP = 2,
- DDP_CATASTROPHIC = 0,
- DDP_TAGGED_BUFFER = 1,
- DDP_UNTAGGED_BUFFER = 2,
- DDP_LLP = 3
-};
-
-enum i40iw_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 i40iw_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 i40iw_term_mpa_errors {
- MPA_CLOSED = 0x01,
- MPA_CRC = 0x02,
- MPA_MARKER = 0x03,
- MPA_REQ_RSP = 0x04,
-};
-
-enum i40iw_flush_opcode {
- FLUSH_INVALID = 0,
- FLUSH_PROT_ERR,
- FLUSH_REM_ACCESS_ERR,
- FLUSH_LOC_QP_OP_ERR,
- FLUSH_REM_OP_ERR,
- FLUSH_LOC_LEN_ERR,
- FLUSH_GENERAL_ERR,
- FLUSH_FATAL_ERR
-};
-
-enum i40iw_term_eventtypes {
- TERM_EVENT_QP_FATAL,
- TERM_EVENT_QP_ACCESS_ERR
-};
-
-struct i40iw_terminate_hdr {
- u8 layer_etype;
- u8 error_code;
- u8 hdrct;
- u8 rsvd;
-};
-
-enum i40iw_debug_flag {
- I40IW_DEBUG_NONE = 0x00000000,
- I40IW_DEBUG_ERR = 0x00000001,
- I40IW_DEBUG_INIT = 0x00000002,
- I40IW_DEBUG_DEV = 0x00000004,
- I40IW_DEBUG_CM = 0x00000008,
- I40IW_DEBUG_VERBS = 0x00000010,
- I40IW_DEBUG_PUDA = 0x00000020,
- I40IW_DEBUG_ILQ = 0x00000040,
- I40IW_DEBUG_IEQ = 0x00000080,
- I40IW_DEBUG_QP = 0x00000100,
- I40IW_DEBUG_CQ = 0x00000200,
- I40IW_DEBUG_MR = 0x00000400,
- I40IW_DEBUG_PBLE = 0x00000800,
- I40IW_DEBUG_WQE = 0x00001000,
- I40IW_DEBUG_AEQ = 0x00002000,
- I40IW_DEBUG_CQP = 0x00004000,
- I40IW_DEBUG_HMC = 0x00008000,
- I40IW_DEBUG_USER = 0x00010000,
- I40IW_DEBUG_VIRT = 0x00020000,
- I40IW_DEBUG_DCB = 0x00040000,
- I40IW_DEBUG_CQE = 0x00800000,
- I40IW_DEBUG_ALL = 0xFFFFFFFF
-};
-
-enum i40iw_hw_stats_index_32b {
- I40IW_HW_STAT_INDEX_IP4RXDISCARD = 0,
- I40IW_HW_STAT_INDEX_IP4RXTRUNC,
- I40IW_HW_STAT_INDEX_IP4TXNOROUTE,
- I40IW_HW_STAT_INDEX_IP6RXDISCARD,
- I40IW_HW_STAT_INDEX_IP6RXTRUNC,
- I40IW_HW_STAT_INDEX_IP6TXNOROUTE,
- I40IW_HW_STAT_INDEX_TCPRTXSEG,
- I40IW_HW_STAT_INDEX_TCPRXOPTERR,
- I40IW_HW_STAT_INDEX_TCPRXPROTOERR,
- I40IW_HW_STAT_INDEX_MAX_32
-};
-
-enum i40iw_hw_stats_index_64b {
- I40IW_HW_STAT_INDEX_IP4RXOCTS = 0,
- I40IW_HW_STAT_INDEX_IP4RXPKTS,
- I40IW_HW_STAT_INDEX_IP4RXFRAGS,
- I40IW_HW_STAT_INDEX_IP4RXMCPKTS,
- I40IW_HW_STAT_INDEX_IP4TXOCTS,
- I40IW_HW_STAT_INDEX_IP4TXPKTS,
- I40IW_HW_STAT_INDEX_IP4TXFRAGS,
- I40IW_HW_STAT_INDEX_IP4TXMCPKTS,
- I40IW_HW_STAT_INDEX_IP6RXOCTS,
- I40IW_HW_STAT_INDEX_IP6RXPKTS,
- I40IW_HW_STAT_INDEX_IP6RXFRAGS,
- I40IW_HW_STAT_INDEX_IP6RXMCPKTS,
- I40IW_HW_STAT_INDEX_IP6TXOCTS,
- I40IW_HW_STAT_INDEX_IP6TXPKTS,
- I40IW_HW_STAT_INDEX_IP6TXFRAGS,
- I40IW_HW_STAT_INDEX_IP6TXMCPKTS,
- I40IW_HW_STAT_INDEX_TCPRXSEGS,
- I40IW_HW_STAT_INDEX_TCPTXSEG,
- I40IW_HW_STAT_INDEX_RDMARXRDS,
- I40IW_HW_STAT_INDEX_RDMARXSNDS,
- I40IW_HW_STAT_INDEX_RDMARXWRS,
- I40IW_HW_STAT_INDEX_RDMATXRDS,
- I40IW_HW_STAT_INDEX_RDMATXSNDS,
- I40IW_HW_STAT_INDEX_RDMATXWRS,
- I40IW_HW_STAT_INDEX_RDMAVBND,
- I40IW_HW_STAT_INDEX_RDMAVINV,
- I40IW_HW_STAT_INDEX_MAX_64
-};
-
-enum i40iw_feature_type {
- I40IW_FEATURE_FW_INFO = 0,
- I40IW_MAX_FEATURES
-};
-
-struct i40iw_dev_hw_stats_offsets {
- u32 stats_offset_32[I40IW_HW_STAT_INDEX_MAX_32];
- u32 stats_offset_64[I40IW_HW_STAT_INDEX_MAX_64];
-};
-
-struct i40iw_dev_hw_stats {
- u64 stats_value_32[I40IW_HW_STAT_INDEX_MAX_32];
- u64 stats_value_64[I40IW_HW_STAT_INDEX_MAX_64];
-};
-
-struct i40iw_vsi_pestat {
- struct i40iw_hw *hw;
- struct i40iw_dev_hw_stats hw_stats;
- struct i40iw_dev_hw_stats last_read_hw_stats;
- struct i40iw_dev_hw_stats_offsets hw_stats_offsets;
- struct timer_list stats_timer;
- struct i40iw_sc_vsi *vsi;
- spinlock_t lock; /* rdma stats lock */
-};
-
-struct i40iw_hw {
- u8 __iomem *hw_addr;
- struct pci_dev *pcidev;
- struct i40iw_hmc_info hmc;
-};
-
-struct i40iw_pfpdu {
- struct list_head rxlist;
- u32 rcv_nxt;
- u32 fps;
- u32 max_fpdu_data;
- bool mode;
- bool mpa_crc_err;
- u64 total_ieq_bufs;
- u64 fpdu_processed;
- u64 bad_seq_num;
- u64 crc_err;
- u64 no_tx_bufs;
- u64 tx_err;
- u64 out_of_order;
- u64 pmode_count;
-};
-
-struct i40iw_sc_pd {
- u32 size;
- struct i40iw_sc_dev *dev;
- u16 pd_id;
- int abi_ver;
-};
-
-struct i40iw_cqp_quanta {
- u64 elem[I40IW_CQP_WQE_SIZE];
-};
-
-struct i40iw_sc_cqp {
- u32 size;
- u64 sq_pa;
- u64 host_ctx_pa;
- void *back_cqp;
- struct i40iw_sc_dev *dev;
- enum i40iw_status_code (*process_cqp_sds)(struct i40iw_sc_dev *,
- struct i40iw_update_sds_info *);
- struct i40iw_dma_mem sdbuf;
- struct i40iw_ring sq_ring;
- struct i40iw_cqp_quanta *sq_base;
- u64 *host_ctx;
- u64 *scratch_array;
- u32 cqp_id;
- u32 sq_size;
- u32 hw_sq_size;
- u8 struct_ver;
- u8 polarity;
- bool en_datacenter_tcp;
- u8 hmc_profile;
- u8 enabled_vf_count;
- u8 timeout_count;
-};
-
-struct i40iw_sc_aeq {
- u32 size;
- u64 aeq_elem_pa;
- struct i40iw_sc_dev *dev;
- struct i40iw_sc_aeqe *aeqe_base;
- void *pbl_list;
- u32 elem_cnt;
- struct i40iw_ring aeq_ring;
- bool virtual_map;
- u8 pbl_chunk_size;
- u32 first_pm_pbl_idx;
- u8 polarity;
-};
-
-struct i40iw_sc_ceq {
- u32 size;
- u64 ceq_elem_pa;
- struct i40iw_sc_dev *dev;
- struct i40iw_ceqe *ceqe_base;
- void *pbl_list;
- u32 ceq_id;
- u32 elem_cnt;
- struct i40iw_ring ceq_ring;
- bool virtual_map;
- u8 pbl_chunk_size;
- bool tph_en;
- u8 tph_val;
- u32 first_pm_pbl_idx;
- u8 polarity;
-};
-
-struct i40iw_sc_cq {
- struct i40iw_cq_uk cq_uk;
- u64 cq_pa;
- u64 shadow_area_pa;
- struct i40iw_sc_dev *dev;
- struct i40iw_sc_vsi *vsi;
- void *pbl_list;
- void *back_cq;
- u32 ceq_id;
- u32 shadow_read_threshold;
- bool ceqe_mask;
- bool virtual_map;
- u8 pbl_chunk_size;
- u8 cq_type;
- bool ceq_id_valid;
- bool tph_en;
- u8 tph_val;
- u32 first_pm_pbl_idx;
- bool check_overflow;
-};
-
-struct i40iw_sc_qp {
- struct i40iw_qp_uk qp_uk;
- u64 sq_pa;
- u64 rq_pa;
- u64 hw_host_ctx_pa;
- u64 shadow_area_pa;
- u64 q2_pa;
- struct i40iw_sc_dev *dev;
- struct i40iw_sc_vsi *vsi;
- struct i40iw_sc_pd *pd;
- u64 *hw_host_ctx;
- void *llp_stream_handle;
- void *back_qp;
- struct i40iw_pfpdu pfpdu;
- u8 *q2_buf;
- u64 qp_compl_ctx;
- u16 qs_handle;
- u8 sq_tph_val;
- u8 rq_tph_val;
- u8 qp_state;
- u8 qp_type;
- u8 hw_sq_size;
- u8 hw_rq_size;
- u8 src_mac_addr_idx;
- bool sq_tph_en;
- bool rq_tph_en;
- bool rcv_tph_en;
- bool xmit_tph_en;
- bool virtual_map;
- bool flush_sq;
- bool flush_rq;
- u8 user_pri;
- struct list_head list;
- bool on_qoslist;
- bool sq_flush;
- enum i40iw_flush_opcode flush_code;
- enum i40iw_term_eventtypes eventtype;
- u8 term_flags;
-};
-
-struct i40iw_hmc_fpm_misc {
- u32 max_ceqs;
- u32 max_sds;
- u32 xf_block_size;
- u32 q1_block_size;
- u32 ht_multiplier;
- u32 timer_bucket;
-};
-
-struct i40iw_vchnl_if {
- enum i40iw_status_code (*vchnl_recv)(struct i40iw_sc_dev *, u32, u8 *, u16);
- enum i40iw_status_code (*vchnl_send)(struct i40iw_sc_dev *dev, u32, u8 *, u16);
-};
-
-#define I40IW_VCHNL_MAX_VF_MSG_SIZE 512
-
-struct i40iw_vchnl_vf_msg_buffer {
- struct i40iw_virtchnl_op_buf vchnl_msg;
- char parm_buffer[I40IW_VCHNL_MAX_VF_MSG_SIZE - 1];
-};
-
-struct i40iw_qos {
- struct list_head qplist;
- spinlock_t lock; /* qos list */
- u16 qs_handle;
-};
-
-struct i40iw_vfdev {
- struct i40iw_sc_dev *pf_dev;
- u8 *hmc_info_mem;
- struct i40iw_vsi_pestat pestat;
- struct i40iw_hmc_pble_info *pble_info;
- struct i40iw_hmc_info hmc_info;
- struct i40iw_vchnl_vf_msg_buffer vf_msg_buffer;
- u64 fpm_query_buf_pa;
- u64 *fpm_query_buf;
- u32 vf_id;
- u32 msg_count;
- bool pf_hmc_initialized;
- u16 pmf_index;
- u16 iw_vf_idx; /* VF Device table index */
- bool stats_initialized;
-};
-
-#define I40IW_INVALID_FCN_ID 0xff
-struct i40iw_sc_vsi {
- struct i40iw_sc_dev *dev;
- void *back_vsi; /* Owned by OS */
- u32 ilq_count;
- struct i40iw_virt_mem ilq_mem;
- struct i40iw_puda_rsrc *ilq;
- u32 ieq_count;
- struct i40iw_virt_mem ieq_mem;
- struct i40iw_puda_rsrc *ieq;
- u16 exception_lan_queue;
- u16 mtu;
- u8 fcn_id;
- bool stats_fcn_id_alloc;
- struct i40iw_qos qos[I40IW_MAX_USER_PRIORITY];
- struct i40iw_vsi_pestat *pestat;
-};
-
-struct i40iw_sc_dev {
- struct list_head cqp_cmd_head; /* head of the CQP command list */
- spinlock_t cqp_lock; /* cqp list sync */
- struct i40iw_dev_uk dev_uk;
- bool fcn_id_array[I40IW_MAX_STATS_COUNT];
- struct i40iw_dma_mem vf_fpm_query_buf[I40IW_MAX_PE_ENABLED_VF_COUNT];
- u64 fpm_query_buf_pa;
- u64 fpm_commit_buf_pa;
- u64 *fpm_query_buf;
- u64 *fpm_commit_buf;
- void *back_dev;
- struct i40iw_hw *hw;
- u8 __iomem *db_addr;
- struct i40iw_hmc_info *hmc_info;
- struct i40iw_hmc_pble_info *pble_info;
- struct i40iw_vfdev *vf_dev[I40IW_MAX_PE_ENABLED_VF_COUNT];
- struct i40iw_sc_cqp *cqp;
- struct i40iw_sc_aeq *aeq;
- struct i40iw_sc_ceq *ceq[I40IW_CEQ_MAX_COUNT];
- struct i40iw_sc_cq *ccq;
- const struct i40iw_cqp_ops *cqp_ops;
- const struct i40iw_ccq_ops *ccq_ops;
- const struct i40iw_ceq_ops *ceq_ops;
- const struct i40iw_aeq_ops *aeq_ops;
- const struct i40iw_pd_ops *iw_pd_ops;
- const struct i40iw_priv_qp_ops *iw_priv_qp_ops;
- const struct i40iw_priv_cq_ops *iw_priv_cq_ops;
- const struct i40iw_mr_ops *mr_ops;
- const struct i40iw_cqp_misc_ops *cqp_misc_ops;
- const struct i40iw_hmc_ops *hmc_ops;
- struct i40iw_vchnl_if vchnl_if;
- const struct i40iw_vf_cqp_ops *iw_vf_cqp_ops;
-
- struct i40iw_hmc_fpm_misc hmc_fpm_misc;
- u64 feature_info[I40IW_MAX_FEATURES];
- u32 debug_mask;
- u8 hmc_fn_id;
- bool is_pf;
- bool vchnl_up;
- bool ceq_valid;
- u8 vf_id;
- wait_queue_head_t vf_reqs;
- u64 cqp_cmd_stats[OP_SIZE_CQP_STAT_ARRAY];
- struct i40iw_vchnl_vf_msg_buffer vchnl_vf_msg_buf;
- u8 hw_rev;
-};
-
-struct i40iw_modify_cq_info {
- u64 cq_pa;
- struct i40iw_cqe *cq_base;
- void *pbl_list;
- u32 ceq_id;
- u32 cq_size;
- u32 shadow_read_threshold;
- bool virtual_map;
- u8 pbl_chunk_size;
- bool check_overflow;
- bool cq_resize;
- bool ceq_change;
- bool check_overflow_change;
- u32 first_pm_pbl_idx;
- bool ceq_valid;
-};
-
-struct i40iw_create_qp_info {
- u8 next_iwarp_state;
- bool ord_valid;
- bool tcp_ctx_valid;
- bool cq_num_valid;
- bool arp_cache_idx_valid;
-};
-
-struct i40iw_modify_qp_info {
- u64 rx_win0;
- u64 rx_win1;
- u8 next_iwarp_state;
- u8 termlen;
- bool ord_valid;
- bool tcp_ctx_valid;
- bool cq_num_valid;
- bool arp_cache_idx_valid;
- bool reset_tcp_conn;
- bool remove_hash_idx;
- bool dont_send_term;
- bool dont_send_fin;
- bool cached_var_valid;
- bool force_loopback;
-};
-
-struct i40iw_ccq_cqe_info {
- struct i40iw_sc_cqp *cqp;
- u64 scratch;
- u32 op_ret_val;
- u16 maj_err_code;
- u16 min_err_code;
- u8 op_code;
- bool error;
-};
-
-struct i40iw_l2params {
- u16 qs_handle_list[I40IW_MAX_USER_PRIORITY];
- u16 mtu;
-};
-
-struct i40iw_vsi_init_info {
- struct i40iw_sc_dev *dev;
- void *back_vsi;
- struct i40iw_l2params *params;
- u16 exception_lan_queue;
-};
-
-struct i40iw_vsi_stats_info {
- struct i40iw_vsi_pestat *pestat;
- u8 fcn_id;
- bool alloc_fcn_id;
- bool stats_initialize;
-};
-
-struct i40iw_device_init_info {
- u64 fpm_query_buf_pa;
- u64 fpm_commit_buf_pa;
- u64 *fpm_query_buf;
- u64 *fpm_commit_buf;
- struct i40iw_hw *hw;
- void __iomem *bar0;
- enum i40iw_status_code (*vchnl_send)(struct i40iw_sc_dev *, u32, u8 *, u16);
- u8 hmc_fn_id;
- bool is_pf;
- u32 debug_mask;
-};
-
-enum i40iw_cqp_hmc_profile {
- I40IW_HMC_PROFILE_DEFAULT = 1,
- I40IW_HMC_PROFILE_FAVOR_VF = 2,
- I40IW_HMC_PROFILE_EQUAL = 3,
-};
-
-struct i40iw_cqp_init_info {
- u64 cqp_compl_ctx;
- u64 host_ctx_pa;
- u64 sq_pa;
- struct i40iw_sc_dev *dev;
- struct i40iw_cqp_quanta *sq;
- u64 *host_ctx;
- u64 *scratch_array;
- u32 sq_size;
- u8 struct_ver;
- bool en_datacenter_tcp;
- u8 hmc_profile;
- u8 enabled_vf_count;
-};
-
-struct i40iw_ceq_init_info {
- u64 ceqe_pa;
- struct i40iw_sc_dev *dev;
- u64 *ceqe_base;
- void *pbl_list;
- u32 elem_cnt;
- u32 ceq_id;
- bool virtual_map;
- u8 pbl_chunk_size;
- bool tph_en;
- u8 tph_val;
- u32 first_pm_pbl_idx;
-};
-
-struct i40iw_aeq_init_info {
- u64 aeq_elem_pa;
- struct i40iw_sc_dev *dev;
- u32 *aeqe_base;
- void *pbl_list;
- u32 elem_cnt;
- bool virtual_map;
- u8 pbl_chunk_size;
- u32 first_pm_pbl_idx;
-};
-
-struct i40iw_ccq_init_info {
- u64 cq_pa;
- u64 shadow_area_pa;
- struct i40iw_sc_dev *dev;
- struct i40iw_cqe *cq_base;
- u64 *shadow_area;
- void *pbl_list;
- u32 num_elem;
- u32 ceq_id;
- u32 shadow_read_threshold;
- bool ceqe_mask;
- bool ceq_id_valid;
- bool tph_en;
- u8 tph_val;
- bool avoid_mem_cflct;
- bool virtual_map;
- u8 pbl_chunk_size;
- u32 first_pm_pbl_idx;
-};
-
-struct i40iwarp_offload_info {
- u16 rcv_mark_offset;
- u16 snd_mark_offset;
- u16 pd_id;
- u8 ddp_ver;
- u8 rdmap_ver;
- u8 ord_size;
- u8 ird_size;
- bool wr_rdresp_en;
- bool rd_enable;
- bool snd_mark_en;
- bool rcv_mark_en;
- bool bind_en;
- bool fast_reg_en;
- bool priv_mode_en;
- bool lsmm_present;
- u8 iwarp_mode;
- bool align_hdrs;
- bool rcv_no_mpa_crc;
-
- u8 last_byte_sent;
-};
-
-struct i40iw_tcp_offload_info {
- bool ipv4;
- bool no_nagle;
- bool insert_vlan_tag;
- bool time_stamp;
- u8 cwnd_inc_limit;
- bool drop_ooo_seg;
- u8 dup_ack_thresh;
- u8 ttl;
- u8 src_mac_addr_idx;
- bool avoid_stretch_ack;
- u8 tos;
- u16 src_port;
- u16 dst_port;
- u32 dest_ip_addr0;
- u32 dest_ip_addr1;
- u32 dest_ip_addr2;
- u32 dest_ip_addr3;
- u32 snd_mss;
- u16 vlan_tag;
- u16 arp_idx;
- u32 flow_label;
- bool wscale;
- u8 tcp_state;
- u8 snd_wscale;
- u8 rcv_wscale;
- u32 time_stamp_recent;
- u32 time_stamp_age;
- u32 snd_nxt;
- u32 snd_wnd;
- u32 rcv_nxt;
- u32 rcv_wnd;
- u32 snd_max;
- u32 snd_una;
- u32 srtt;
- u32 rtt_var;
- u32 ss_thresh;
- u32 cwnd;
- u32 snd_wl1;
- u32 snd_wl2;
- u32 max_snd_window;
- u8 rexmit_thresh;
- u32 local_ipaddr0;
- u32 local_ipaddr1;
- u32 local_ipaddr2;
- u32 local_ipaddr3;
- bool ignore_tcp_opt;
- bool ignore_tcp_uns_opt;
-};
-
-struct i40iw_qp_host_ctx_info {
- u64 qp_compl_ctx;
- struct i40iw_tcp_offload_info *tcp_info;
- struct i40iwarp_offload_info *iwarp_info;
- u32 send_cq_num;
- u32 rcv_cq_num;
- bool tcp_info_valid;
- bool iwarp_info_valid;
- bool err_rq_idx_valid;
- u16 err_rq_idx;
- bool add_to_qoslist;
- u8 user_pri;
-};
-
-struct i40iw_aeqe_info {
- u64 compl_ctx;
- u32 qp_cq_id;
- u16 ae_id;
- u16 wqe_idx;
- u8 tcp_state;
- u8 iwarp_state;
- bool qp;
- bool cq;
- bool sq;
- bool in_rdrsp_wr;
- bool out_rdrsp;
- u8 q2_data_written;
- bool aeqe_overflow;
-};
-
-struct i40iw_allocate_stag_info {
- u64 total_len;
- u32 chunk_size;
- u32 stag_idx;
- u32 page_size;
- u16 pd_id;
- u16 access_rights;
- bool remote_access;
- bool use_hmc_fcn_index;
- u8 hmc_fcn_index;
- bool use_pf_rid;
-};
-
-struct i40iw_reg_ns_stag_info {
- u64 reg_addr_pa;
- u64 fbo;
- void *va;
- u64 total_len;
- u32 page_size;
- u32 chunk_size;
- u32 first_pm_pbl_index;
- enum i40iw_addressing_type addr_type;
- i40iw_stag_index stag_idx;
- u16 access_rights;
- u16 pd_id;
- i40iw_stag_key stag_key;
- bool use_hmc_fcn_index;
- u8 hmc_fcn_index;
- bool use_pf_rid;
-};
-
-struct i40iw_fast_reg_stag_info {
- u64 wr_id;
- u64 reg_addr_pa;
- u64 fbo;
- void *va;
- u64 total_len;
- u32 page_size;
- u32 chunk_size;
- u32 first_pm_pbl_index;
- enum i40iw_addressing_type addr_type;
- i40iw_stag_index stag_idx;
- u16 access_rights;
- u16 pd_id;
- i40iw_stag_key stag_key;
- bool local_fence;
- bool read_fence;
- bool signaled;
- bool use_hmc_fcn_index;
- u8 hmc_fcn_index;
- bool use_pf_rid;
- bool defer_flag;
-};
-
-struct i40iw_dealloc_stag_info {
- u32 stag_idx;
- u16 pd_id;
- bool mr;
- bool dealloc_pbl;
-};
-
-struct i40iw_register_shared_stag {
- void *va;
- enum i40iw_addressing_type addr_type;
- i40iw_stag_index new_stag_idx;
- i40iw_stag_index parent_stag_idx;
- u32 access_rights;
- u16 pd_id;
- i40iw_stag_key new_stag_key;
-};
-
-struct i40iw_qp_init_info {
- struct i40iw_qp_uk_init_info qp_uk_init_info;
- struct i40iw_sc_pd *pd;
- struct i40iw_sc_vsi *vsi;
- u64 *host_ctx;
- u8 *q2;
- u64 sq_pa;
- u64 rq_pa;
- u64 host_ctx_pa;
- u64 q2_pa;
- u64 shadow_area_pa;
- int abi_ver;
- u8 sq_tph_val;
- u8 rq_tph_val;
- u8 type;
- bool sq_tph_en;
- bool rq_tph_en;
- bool rcv_tph_en;
- bool xmit_tph_en;
- bool virtual_map;
-};
-
-struct i40iw_cq_init_info {
- struct i40iw_sc_dev *dev;
- u64 cq_base_pa;
- u64 shadow_area_pa;
- u32 ceq_id;
- u32 shadow_read_threshold;
- bool virtual_map;
- bool ceqe_mask;
- u8 pbl_chunk_size;
- u32 first_pm_pbl_idx;
- bool ceq_id_valid;
- bool tph_en;
- u8 tph_val;
- u8 type;
- struct i40iw_cq_uk_init_info cq_uk_init_info;
-};
-
-struct i40iw_upload_context_info {
- u64 buf_pa;
- bool freeze_qp;
- bool raw_format;
- u32 qp_id;
- u8 qp_type;
-};
-
-struct i40iw_add_arp_cache_entry_info {
- u8 mac_addr[6];
- u32 reach_max;
- u16 arp_index;
- bool permanent;
-};
-
-struct i40iw_apbvt_info {
- u16 port;
- bool add;
-};
-
-enum i40iw_quad_entry_type {
- I40IW_QHASH_TYPE_TCP_ESTABLISHED = 1,
- I40IW_QHASH_TYPE_TCP_SYN,
-};
-
-enum i40iw_quad_hash_manage_type {
- I40IW_QHASH_MANAGE_TYPE_DELETE = 0,
- I40IW_QHASH_MANAGE_TYPE_ADD,
- I40IW_QHASH_MANAGE_TYPE_MODIFY
-};
-
-struct i40iw_qhash_table_info {
- struct i40iw_sc_vsi *vsi;
- enum i40iw_quad_hash_manage_type manage;
- enum i40iw_quad_entry_type entry_type;
- bool vlan_valid;
- bool ipv4_valid;
- u8 mac_addr[6];
- u16 vlan_id;
- u8 user_pri;
- u32 qp_num;
- u32 dest_ip[4];
- u32 src_ip[4];
- u16 dest_port;
- u16 src_port;
-};
-
-struct i40iw_local_mac_ipaddr_entry_info {
- u8 mac_addr[6];
- u8 entry_idx;
-};
-
-struct i40iw_qp_flush_info {
- u16 sq_minor_code;
- u16 sq_major_code;
- u16 rq_minor_code;
- u16 rq_major_code;
- u16 ae_code;
- u8 ae_source;
- bool sq;
- bool rq;
- bool userflushcode;
- bool generate_ae;
-};
-
-struct i40iw_cqp_commit_fpm_values {
- u64 qp_base;
- u64 cq_base;
- u32 hte_base;
- u32 arp_base;
- u32 apbvt_inuse_base;
- u32 mr_base;
- u32 xf_base;
- u32 xffl_base;
- u32 q1_base;
- u32 q1fl_base;
- u32 fsimc_base;
- u32 fsiav_base;
- u32 pbl_base;
-
- u32 qp_cnt;
- u32 cq_cnt;
- u32 hte_cnt;
- u32 arp_cnt;
- u32 mr_cnt;
- u32 xf_cnt;
- u32 xffl_cnt;
- u32 q1_cnt;
- u32 q1fl_cnt;
- u32 fsimc_cnt;
- u32 fsiav_cnt;
- u32 pbl_cnt;
-};
-
-struct i40iw_cqp_query_fpm_values {
- u16 first_pe_sd_index;
- u32 qp_objsize;
- u32 cq_objsize;
- u32 hte_objsize;
- u32 arp_objsize;
- u32 mr_objsize;
- u32 xf_objsize;
- u32 q1_objsize;
- u32 fsimc_objsize;
- u32 fsiav_objsize;
-
- u32 qp_max;
- u32 cq_max;
- u32 hte_max;
- u32 arp_max;
- u32 mr_max;
- u32 xf_max;
- u32 xffl_max;
- u32 q1_max;
- u32 q1fl_max;
- u32 fsimc_max;
- u32 fsiav_max;
- u32 pbl_max;
-};
-
-struct i40iw_gen_ae_info {
- u16 ae_code;
- u8 ae_source;
-};
-
-struct i40iw_cqp_ops {
- enum i40iw_status_code (*cqp_init)(struct i40iw_sc_cqp *,
- struct i40iw_cqp_init_info *);
- enum i40iw_status_code (*cqp_create)(struct i40iw_sc_cqp *, u16 *, u16 *);
- void (*cqp_post_sq)(struct i40iw_sc_cqp *);
- u64 *(*cqp_get_next_send_wqe)(struct i40iw_sc_cqp *, u64 scratch);
- enum i40iw_status_code (*cqp_destroy)(struct i40iw_sc_cqp *);
- enum i40iw_status_code (*poll_for_cqp_op_done)(struct i40iw_sc_cqp *, u8,
- struct i40iw_ccq_cqe_info *);
-};
-
-struct i40iw_ccq_ops {
- enum i40iw_status_code (*ccq_init)(struct i40iw_sc_cq *,
- struct i40iw_ccq_init_info *);
- enum i40iw_status_code (*ccq_create)(struct i40iw_sc_cq *, u64, bool, bool);
- enum i40iw_status_code (*ccq_destroy)(struct i40iw_sc_cq *, u64, bool);
- enum i40iw_status_code (*ccq_create_done)(struct i40iw_sc_cq *);
- enum i40iw_status_code (*ccq_get_cqe_info)(struct i40iw_sc_cq *,
- struct i40iw_ccq_cqe_info *);
- void (*ccq_arm)(struct i40iw_sc_cq *);
-};
-
-struct i40iw_ceq_ops {
- enum i40iw_status_code (*ceq_init)(struct i40iw_sc_ceq *,
- struct i40iw_ceq_init_info *);
- enum i40iw_status_code (*ceq_create)(struct i40iw_sc_ceq *, u64, bool);
- enum i40iw_status_code (*cceq_create_done)(struct i40iw_sc_ceq *);
- enum i40iw_status_code (*cceq_destroy_done)(struct i40iw_sc_ceq *);
- enum i40iw_status_code (*cceq_create)(struct i40iw_sc_ceq *, u64);
- enum i40iw_status_code (*ceq_destroy)(struct i40iw_sc_ceq *, u64, bool);
- void *(*process_ceq)(struct i40iw_sc_dev *, struct i40iw_sc_ceq *);
-};
-
-struct i40iw_aeq_ops {
- enum i40iw_status_code (*aeq_init)(struct i40iw_sc_aeq *,
- struct i40iw_aeq_init_info *);
- enum i40iw_status_code (*aeq_create)(struct i40iw_sc_aeq *, u64, bool);
- enum i40iw_status_code (*aeq_destroy)(struct i40iw_sc_aeq *, u64, bool);
- enum i40iw_status_code (*get_next_aeqe)(struct i40iw_sc_aeq *,
- struct i40iw_aeqe_info *);
- enum i40iw_status_code (*repost_aeq_entries)(struct i40iw_sc_dev *, u32);
- enum i40iw_status_code (*aeq_create_done)(struct i40iw_sc_aeq *);
- enum i40iw_status_code (*aeq_destroy_done)(struct i40iw_sc_aeq *);
-};
-
-struct i40iw_pd_ops {
- void (*pd_init)(struct i40iw_sc_dev *, struct i40iw_sc_pd *, u16, int);
-};
-
-struct i40iw_priv_qp_ops {
- enum i40iw_status_code (*qp_init)(struct i40iw_sc_qp *, struct i40iw_qp_init_info *);
- enum i40iw_status_code (*qp_create)(struct i40iw_sc_qp *,
- struct i40iw_create_qp_info *, u64, bool);
- enum i40iw_status_code (*qp_modify)(struct i40iw_sc_qp *,
- struct i40iw_modify_qp_info *, u64, bool);
- enum i40iw_status_code (*qp_destroy)(struct i40iw_sc_qp *, u64, bool, bool, bool);
- enum i40iw_status_code (*qp_flush_wqes)(struct i40iw_sc_qp *,
- struct i40iw_qp_flush_info *, u64, bool);
- enum i40iw_status_code (*qp_upload_context)(struct i40iw_sc_dev *,
- struct i40iw_upload_context_info *,
- u64, bool);
- enum i40iw_status_code (*qp_setctx)(struct i40iw_sc_qp *, u64 *,
- struct i40iw_qp_host_ctx_info *);
-
- void (*qp_send_lsmm)(struct i40iw_sc_qp *, void *, u32, i40iw_stag);
- void (*qp_send_lsmm_nostag)(struct i40iw_sc_qp *, void *, u32);
- void (*qp_send_rtt)(struct i40iw_sc_qp *, bool);
- enum i40iw_status_code (*qp_post_wqe0)(struct i40iw_sc_qp *, u8);
- enum i40iw_status_code (*iw_mr_fast_register)(struct i40iw_sc_qp *,
- struct i40iw_fast_reg_stag_info *,
- bool);
-};
-
-struct i40iw_priv_cq_ops {
- enum i40iw_status_code (*cq_init)(struct i40iw_sc_cq *, struct i40iw_cq_init_info *);
- enum i40iw_status_code (*cq_create)(struct i40iw_sc_cq *, u64, bool, bool);
- enum i40iw_status_code (*cq_destroy)(struct i40iw_sc_cq *, u64, bool);
- enum i40iw_status_code (*cq_modify)(struct i40iw_sc_cq *,
- struct i40iw_modify_cq_info *, u64, bool);
-};
-
-struct i40iw_mr_ops {
- enum i40iw_status_code (*alloc_stag)(struct i40iw_sc_dev *,
- struct i40iw_allocate_stag_info *, u64, bool);
- enum i40iw_status_code (*mr_reg_non_shared)(struct i40iw_sc_dev *,
- struct i40iw_reg_ns_stag_info *,
- u64, bool);
- enum i40iw_status_code (*mr_reg_shared)(struct i40iw_sc_dev *,
- struct i40iw_register_shared_stag *,
- u64, bool);
- enum i40iw_status_code (*dealloc_stag)(struct i40iw_sc_dev *,
- struct i40iw_dealloc_stag_info *,
- u64, bool);
- enum i40iw_status_code (*query_stag)(struct i40iw_sc_dev *, u64, u32, bool);
- enum i40iw_status_code (*mw_alloc)(struct i40iw_sc_dev *, u64, u32, u16, bool);
-};
-
-struct i40iw_cqp_misc_ops {
- enum i40iw_status_code (*manage_hmc_pm_func_table)(struct i40iw_sc_cqp *,
- u64, u8, bool, bool);
- enum i40iw_status_code (*set_hmc_resource_profile)(struct i40iw_sc_cqp *,
- u64, u8, u8, bool, bool);
- enum i40iw_status_code (*commit_fpm_values)(struct i40iw_sc_cqp *, u64, u8,
- struct i40iw_dma_mem *, bool, u8);
- enum i40iw_status_code (*query_fpm_values)(struct i40iw_sc_cqp *, u64, u8,
- struct i40iw_dma_mem *, bool, u8);
- enum i40iw_status_code (*static_hmc_pages_allocated)(struct i40iw_sc_cqp *,
- u64, u8, bool, bool);
- enum i40iw_status_code (*add_arp_cache_entry)(struct i40iw_sc_cqp *,
- struct i40iw_add_arp_cache_entry_info *,
- u64, bool);
- enum i40iw_status_code (*del_arp_cache_entry)(struct i40iw_sc_cqp *, u64, u16, bool);
- enum i40iw_status_code (*query_arp_cache_entry)(struct i40iw_sc_cqp *, u64, u16, bool);
- enum i40iw_status_code (*manage_apbvt_entry)(struct i40iw_sc_cqp *,
- struct i40iw_apbvt_info *, u64, bool);
- enum i40iw_status_code (*manage_qhash_table_entry)(struct i40iw_sc_cqp *,
- struct i40iw_qhash_table_info *, u64, bool);
- enum i40iw_status_code (*alloc_local_mac_ipaddr_table_entry)(struct i40iw_sc_cqp *, u64, bool);
- enum i40iw_status_code (*add_local_mac_ipaddr_entry)(struct i40iw_sc_cqp *,
- struct i40iw_local_mac_ipaddr_entry_info *,
- u64, bool);
- enum i40iw_status_code (*del_local_mac_ipaddr_entry)(struct i40iw_sc_cqp *, u64, u8, u8, bool);
- enum i40iw_status_code (*cqp_nop)(struct i40iw_sc_cqp *, u64, bool);
- enum i40iw_status_code (*commit_fpm_values_done)(struct i40iw_sc_cqp
- *);
- enum i40iw_status_code (*query_fpm_values_done)(struct i40iw_sc_cqp *);
- enum i40iw_status_code (*manage_hmc_pm_func_table_done)(struct i40iw_sc_cqp *);
- enum i40iw_status_code (*update_suspend_qp)(struct i40iw_sc_cqp *, struct i40iw_sc_qp *, u64);
- enum i40iw_status_code (*update_resume_qp)(struct i40iw_sc_cqp *, struct i40iw_sc_qp *, u64);
-};
-
-struct i40iw_hmc_ops {
- enum i40iw_status_code (*init_iw_hmc)(struct i40iw_sc_dev *, u8);
- enum i40iw_status_code (*parse_fpm_query_buf)(u64 *, struct i40iw_hmc_info *,
- struct i40iw_hmc_fpm_misc *);
- enum i40iw_status_code (*configure_iw_fpm)(struct i40iw_sc_dev *, u8);
- enum i40iw_status_code (*parse_fpm_commit_buf)(u64 *, struct i40iw_hmc_obj_info *, u32 *sd);
- enum i40iw_status_code (*create_hmc_object)(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_create_obj_info *);
- enum i40iw_status_code (*del_hmc_object)(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_del_obj_info *,
- bool reset);
- enum i40iw_status_code (*pf_init_vfhmc)(struct i40iw_sc_dev *, u8, u32 *);
- enum i40iw_status_code (*vf_configure_vffpm)(struct i40iw_sc_dev *, u32 *);
-};
-
-struct cqp_info {
- union {
- struct {
- struct i40iw_sc_qp *qp;
- struct i40iw_create_qp_info info;
- u64 scratch;
- } qp_create;
-
- struct {
- struct i40iw_sc_qp *qp;
- struct i40iw_modify_qp_info info;
- u64 scratch;
- } qp_modify;
-
- struct {
- struct i40iw_sc_qp *qp;
- u64 scratch;
- bool remove_hash_idx;
- bool ignore_mw_bnd;
- } qp_destroy;
-
- struct {
- struct i40iw_sc_cq *cq;
- u64 scratch;
- bool check_overflow;
- } cq_create;
-
- struct {
- struct i40iw_sc_cq *cq;
- u64 scratch;
- } cq_destroy;
-
- struct {
- struct i40iw_sc_dev *dev;
- struct i40iw_allocate_stag_info info;
- u64 scratch;
- } alloc_stag;
-
- struct {
- struct i40iw_sc_dev *dev;
- u64 scratch;
- u32 mw_stag_index;
- u16 pd_id;
- } mw_alloc;
-
- struct {
- struct i40iw_sc_dev *dev;
- struct i40iw_reg_ns_stag_info info;
- u64 scratch;
- } mr_reg_non_shared;
-
- struct {
- struct i40iw_sc_dev *dev;
- struct i40iw_dealloc_stag_info info;
- u64 scratch;
- } dealloc_stag;
-
- struct {
- struct i40iw_sc_cqp *cqp;
- struct i40iw_local_mac_ipaddr_entry_info info;
- u64 scratch;
- } add_local_mac_ipaddr_entry;
-
- struct {
- struct i40iw_sc_cqp *cqp;
- struct i40iw_add_arp_cache_entry_info info;
- u64 scratch;
- } add_arp_cache_entry;
-
- struct {
- struct i40iw_sc_cqp *cqp;
- u64 scratch;
- u8 entry_idx;
- u8 ignore_ref_count;
- } del_local_mac_ipaddr_entry;
-
- struct {
- struct i40iw_sc_cqp *cqp;
- u64 scratch;
- u16 arp_index;
- } del_arp_cache_entry;
-
- struct {
- struct i40iw_sc_cqp *cqp;
- struct i40iw_manage_vf_pble_info info;
- u64 scratch;
- } manage_vf_pble_bp;
-
- struct {
- struct i40iw_sc_dev *dev;
- struct i40iw_upload_context_info info;
- u64 scratch;
- } qp_upload_context;
-
- struct {
- struct i40iw_sc_cqp *cqp;
- u64 scratch;
- } alloc_local_mac_ipaddr_entry;
-
- struct {
- struct i40iw_sc_dev *dev;
- struct i40iw_hmc_fcn_info info;
- u64 scratch;
- } manage_hmc_pm;
-
- struct {
- struct i40iw_sc_ceq *ceq;
- u64 scratch;
- } ceq_create;
-
- struct {
- struct i40iw_sc_ceq *ceq;
- u64 scratch;
- } ceq_destroy;
-
- struct {
- struct i40iw_sc_aeq *aeq;
- u64 scratch;
- } aeq_create;
-
- struct {
- struct i40iw_sc_aeq *aeq;
- u64 scratch;
- } aeq_destroy;
-
- struct {
- struct i40iw_sc_qp *qp;
- struct i40iw_qp_flush_info info;
- u64 scratch;
- } qp_flush_wqes;
-
- struct {
- struct i40iw_sc_qp *qp;
- struct i40iw_gen_ae_info info;
- u64 scratch;
- } gen_ae;
-
- struct {
- struct i40iw_sc_cqp *cqp;
- void *fpm_values_va;
- u64 fpm_values_pa;
- u8 hmc_fn_id;
- u64 scratch;
- } query_fpm_values;
-
- struct {
- struct i40iw_sc_cqp *cqp;
- void *fpm_values_va;
- u64 fpm_values_pa;
- u8 hmc_fn_id;
- u64 scratch;
- } commit_fpm_values;
-
- struct {
- struct i40iw_sc_cqp *cqp;
- struct i40iw_apbvt_info info;
- u64 scratch;
- } manage_apbvt_entry;
-
- struct {
- struct i40iw_sc_cqp *cqp;
- struct i40iw_qhash_table_info info;
- u64 scratch;
- } manage_qhash_table_entry;
-
- struct {
- struct i40iw_sc_dev *dev;
- struct i40iw_update_sds_info info;
- u64 scratch;
- } update_pe_sds;
-
- struct {
- struct i40iw_sc_cqp *cqp;
- struct i40iw_sc_qp *qp;
- u64 scratch;
- } suspend_resume;
- struct {
- struct i40iw_sc_cqp *cqp;
- void *cap_va;
- u64 cap_pa;
- u64 scratch;
- } query_rdma_features;
- } u;
-};
-
-struct cqp_commands_info {
- struct list_head cqp_cmd_entry;
- u8 cqp_cmd;
- u8 post_sq;
- struct cqp_info in;
-};
-
-struct i40iw_virtchnl_work_info {
- void (*callback_fcn)(void *vf_dev);
- void *worker_vf_dev;
-};
-
-struct i40iw_cqp_timeout {
- u64 compl_cqp_cmds;
- u8 count;
-};
-
-#endif
diff --git a/drivers/infiniband/hw/i40iw/i40iw_uk.c b/drivers/infiniband/hw/i40iw/i40iw_uk.c
deleted file mode 100644
index f521be16bf31..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_uk.c
+++ /dev/null
@@ -1,1200 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 "i40iw_osdep.h"
-#include "i40iw_status.h"
-#include "i40iw_d.h"
-#include "i40iw_user.h"
-#include "i40iw_register.h"
-
-static u32 nop_signature = 0x55550000;
-
-/**
- * i40iw_nop_1 - insert a nop wqe and move head. no post work
- * @qp: hw qp ptr
- */
-static enum i40iw_status_code i40iw_nop_1(struct i40iw_qp_uk *qp)
-{
- u64 header, *wqe;
- u64 *wqe_0 = NULL;
- u32 wqe_idx, peek_head;
- bool signaled = false;
-
- if (!qp->sq_ring.head)
- return I40IW_ERR_PARAM;
-
- wqe_idx = I40IW_RING_GETCURRENT_HEAD(qp->sq_ring);
- wqe = qp->sq_base[wqe_idx].elem;
-
- qp->sq_wrtrk_array[wqe_idx].wqe_size = I40IW_QP_WQE_MIN_SIZE;
-
- peek_head = (qp->sq_ring.head + 1) % qp->sq_ring.size;
- wqe_0 = qp->sq_base[peek_head].elem;
- if (peek_head)
- wqe_0[3] = LS_64(!qp->swqe_polarity, I40IWQPSQ_VALID);
- else
- wqe_0[3] = LS_64(qp->swqe_polarity, I40IWQPSQ_VALID);
-
- set_64bit_val(wqe, 0, 0);
- set_64bit_val(wqe, 8, 0);
- set_64bit_val(wqe, 16, 0);
-
- header = LS_64(I40IWQP_OP_NOP, I40IWQPSQ_OPCODE) |
- LS_64(signaled, I40IWQPSQ_SIGCOMPL) |
- LS_64(qp->swqe_polarity, I40IWQPSQ_VALID) | nop_signature++;
-
- wmb(); /* Memory barrier to ensure data is written before valid bit is set */
-
- set_64bit_val(wqe, 24, header);
- return 0;
-}
-
-/**
- * i40iw_qp_post_wr - post wr to hrdware
- * @qp: hw qp ptr
- */
-void i40iw_qp_post_wr(struct i40iw_qp_uk *qp)
-{
- u64 temp;
- u32 hw_sq_tail;
- u32 sw_sq_head;
-
- mb(); /* valid bit is written and loads completed before reading shadow */
-
- /* read the doorbell shadow area */
- get_64bit_val(qp->shadow_area, 0, &temp);
-
- hw_sq_tail = (u32)RS_64(temp, I40IW_QP_DBSA_HW_SQ_TAIL);
- sw_sq_head = I40IW_RING_GETCURRENT_HEAD(qp->sq_ring);
- if (sw_sq_head != hw_sq_tail) {
- if (sw_sq_head > qp->initial_ring.head) {
- if ((hw_sq_tail >= qp->initial_ring.head) &&
- (hw_sq_tail < sw_sq_head)) {
- writel(qp->qp_id, qp->wqe_alloc_reg);
- }
- } else if (sw_sq_head != qp->initial_ring.head) {
- if ((hw_sq_tail >= qp->initial_ring.head) ||
- (hw_sq_tail < sw_sq_head)) {
- writel(qp->qp_id, qp->wqe_alloc_reg);
- }
- }
- }
-
- qp->initial_ring.head = qp->sq_ring.head;
-}
-
-/**
- * i40iw_qp_get_next_send_wqe - return next wqe ptr
- * @qp: hw qp ptr
- * @wqe_idx: return wqe index
- * @wqe_size: size of sq wqe
- * @total_size: work request length
- * @wr_id: work request id
- */
-u64 *i40iw_qp_get_next_send_wqe(struct i40iw_qp_uk *qp,
- u32 *wqe_idx,
- u8 wqe_size,
- u32 total_size,
- u64 wr_id
- )
-{
- u64 *wqe = NULL;
- u64 wqe_ptr;
- u32 peek_head = 0;
- u16 offset;
- enum i40iw_status_code ret_code = 0;
- u8 nop_wqe_cnt = 0, i;
- u64 *wqe_0 = NULL;
-
- *wqe_idx = I40IW_RING_GETCURRENT_HEAD(qp->sq_ring);
-
- if (!*wqe_idx)
- qp->swqe_polarity = !qp->swqe_polarity;
- wqe_ptr = (uintptr_t)qp->sq_base[*wqe_idx].elem;
- offset = (u16)(wqe_ptr) & 0x7F;
- if ((offset + wqe_size) > I40IW_QP_WQE_MAX_SIZE) {
- nop_wqe_cnt = (u8)(I40IW_QP_WQE_MAX_SIZE - offset) / I40IW_QP_WQE_MIN_SIZE;
- for (i = 0; i < nop_wqe_cnt; i++) {
- i40iw_nop_1(qp);
- I40IW_RING_MOVE_HEAD(qp->sq_ring, ret_code);
- if (ret_code)
- return NULL;
- }
-
- *wqe_idx = I40IW_RING_GETCURRENT_HEAD(qp->sq_ring);
- if (!*wqe_idx)
- qp->swqe_polarity = !qp->swqe_polarity;
- }
-
- if (((*wqe_idx & 3) == 1) && (wqe_size == I40IW_WQE_SIZE_64)) {
- i40iw_nop_1(qp);
- I40IW_RING_MOVE_HEAD(qp->sq_ring, ret_code);
- if (ret_code)
- return NULL;
- *wqe_idx = I40IW_RING_GETCURRENT_HEAD(qp->sq_ring);
- if (!*wqe_idx)
- qp->swqe_polarity = !qp->swqe_polarity;
- }
- I40IW_RING_MOVE_HEAD_BY_COUNT(qp->sq_ring,
- wqe_size / I40IW_QP_WQE_MIN_SIZE, ret_code);
- if (ret_code)
- return NULL;
-
- wqe = qp->sq_base[*wqe_idx].elem;
-
- peek_head = I40IW_RING_GETCURRENT_HEAD(qp->sq_ring);
- wqe_0 = qp->sq_base[peek_head].elem;
-
- if (((peek_head & 3) == 1) || ((peek_head & 3) == 3)) {
- if (RS_64(wqe_0[3], I40IWQPSQ_VALID) != !qp->swqe_polarity)
- wqe_0[3] = LS_64(!qp->swqe_polarity, I40IWQPSQ_VALID);
- }
-
- qp->sq_wrtrk_array[*wqe_idx].wrid = wr_id;
- qp->sq_wrtrk_array[*wqe_idx].wr_len = total_size;
- qp->sq_wrtrk_array[*wqe_idx].wqe_size = wqe_size;
- return wqe;
-}
-
-/**
- * i40iw_set_fragment - set fragment in wqe
- * @wqe: wqe for setting fragment
- * @offset: offset value
- * @sge: sge length and stag
- */
-static void i40iw_set_fragment(u64 *wqe, u32 offset, struct i40iw_sge *sge)
-{
- if (sge) {
- set_64bit_val(wqe, offset, LS_64(sge->tag_off, I40IWQPSQ_FRAG_TO));
- set_64bit_val(wqe, (offset + 8),
- (LS_64(sge->len, I40IWQPSQ_FRAG_LEN) |
- LS_64(sge->stag, I40IWQPSQ_FRAG_STAG)));
- }
-}
-
-/**
- * i40iw_qp_get_next_recv_wqe - get next qp's rcv wqe
- * @qp: hw qp ptr
- * @wqe_idx: return wqe index
- */
-u64 *i40iw_qp_get_next_recv_wqe(struct i40iw_qp_uk *qp, u32 *wqe_idx)
-{
- u64 *wqe = NULL;
- enum i40iw_status_code ret_code;
-
- if (I40IW_RING_FULL_ERR(qp->rq_ring))
- return NULL;
-
- I40IW_ATOMIC_RING_MOVE_HEAD(qp->rq_ring, *wqe_idx, ret_code);
- if (ret_code)
- return NULL;
- if (!*wqe_idx)
- qp->rwqe_polarity = !qp->rwqe_polarity;
- /* rq_wqe_size_multiplier is no of qwords in one rq wqe */
- wqe = qp->rq_base[*wqe_idx * (qp->rq_wqe_size_multiplier >> 2)].elem;
-
- return wqe;
-}
-
-/**
- * i40iw_rdma_write - rdma write operation
- * @qp: hw qp ptr
- * @info: post sq information
- * @post_sq: flag to post sq
- */
-static enum i40iw_status_code i40iw_rdma_write(struct i40iw_qp_uk *qp,
- struct i40iw_post_sq_info *info,
- bool post_sq)
-{
- u64 header;
- u64 *wqe;
- struct i40iw_rdma_write *op_info;
- u32 i, wqe_idx;
- u32 total_size = 0, byte_off;
- enum i40iw_status_code ret_code;
- bool read_fence = false;
- u8 wqe_size;
-
- op_info = &info->op.rdma_write;
- if (op_info->num_lo_sges > qp->max_sq_frag_cnt)
- return I40IW_ERR_INVALID_FRAG_COUNT;
-
- for (i = 0; i < op_info->num_lo_sges; i++)
- total_size += op_info->lo_sg_list[i].len;
-
- if (total_size > I40IW_MAX_OUTBOUND_MESSAGE_SIZE)
- return I40IW_ERR_QP_INVALID_MSG_SIZE;
-
- read_fence |= info->read_fence;
-
- ret_code = i40iw_fragcnt_to_wqesize_sq(op_info->num_lo_sges, &wqe_size);
- if (ret_code)
- return ret_code;
-
- wqe = i40iw_qp_get_next_send_wqe(qp, &wqe_idx, wqe_size, total_size, info->wr_id);
- if (!wqe)
- return I40IW_ERR_QP_TOOMANY_WRS_POSTED;
- set_64bit_val(wqe, 16,
- LS_64(op_info->rem_addr.tag_off, I40IWQPSQ_FRAG_TO));
- if (!op_info->rem_addr.stag)
- return I40IW_ERR_BAD_STAG;
-
- header = LS_64(op_info->rem_addr.stag, I40IWQPSQ_REMSTAG) |
- LS_64(I40IWQP_OP_RDMA_WRITE, I40IWQPSQ_OPCODE) |
- LS_64((op_info->num_lo_sges > 1 ? (op_info->num_lo_sges - 1) : 0), I40IWQPSQ_ADDFRAGCNT) |
- LS_64(read_fence, I40IWQPSQ_READFENCE) |
- LS_64(info->local_fence, I40IWQPSQ_LOCALFENCE) |
- LS_64(info->signaled, I40IWQPSQ_SIGCOMPL) |
- LS_64(qp->swqe_polarity, I40IWQPSQ_VALID);
-
- i40iw_set_fragment(wqe, 0, op_info->lo_sg_list);
-
- for (i = 1, byte_off = 32; i < op_info->num_lo_sges; i++) {
- i40iw_set_fragment(wqe, byte_off, &op_info->lo_sg_list[i]);
- byte_off += 16;
- }
-
- wmb(); /* make sure WQE is populated before valid bit is set */
-
- set_64bit_val(wqe, 24, header);
-
- if (post_sq)
- i40iw_qp_post_wr(qp);
-
- return 0;
-}
-
-/**
- * i40iw_rdma_read - rdma read command
- * @qp: hw qp ptr
- * @info: post sq information
- * @inv_stag: flag for inv_stag
- * @post_sq: flag to post sq
- */
-static enum i40iw_status_code i40iw_rdma_read(struct i40iw_qp_uk *qp,
- struct i40iw_post_sq_info *info,
- bool inv_stag,
- bool post_sq)
-{
- u64 *wqe;
- struct i40iw_rdma_read *op_info;
- u64 header;
- u32 wqe_idx;
- enum i40iw_status_code ret_code;
- u8 wqe_size;
- bool local_fence = false;
-
- op_info = &info->op.rdma_read;
- ret_code = i40iw_fragcnt_to_wqesize_sq(1, &wqe_size);
- if (ret_code)
- return ret_code;
- wqe = i40iw_qp_get_next_send_wqe(qp, &wqe_idx, wqe_size, op_info->lo_addr.len, info->wr_id);
- if (!wqe)
- return I40IW_ERR_QP_TOOMANY_WRS_POSTED;
- local_fence |= info->local_fence;
-
- set_64bit_val(wqe, 16, LS_64(op_info->rem_addr.tag_off, I40IWQPSQ_FRAG_TO));
- header = LS_64(op_info->rem_addr.stag, I40IWQPSQ_REMSTAG) |
- LS_64((inv_stag ? I40IWQP_OP_RDMA_READ_LOC_INV : I40IWQP_OP_RDMA_READ), I40IWQPSQ_OPCODE) |
- LS_64(info->read_fence, I40IWQPSQ_READFENCE) |
- LS_64(local_fence, I40IWQPSQ_LOCALFENCE) |
- LS_64(info->signaled, I40IWQPSQ_SIGCOMPL) |
- LS_64(qp->swqe_polarity, I40IWQPSQ_VALID);
-
- i40iw_set_fragment(wqe, 0, &op_info->lo_addr);
-
- wmb(); /* make sure WQE is populated before valid bit is set */
-
- set_64bit_val(wqe, 24, header);
- if (post_sq)
- i40iw_qp_post_wr(qp);
-
- return 0;
-}
-
-/**
- * i40iw_send - rdma send command
- * @qp: hw qp ptr
- * @info: post sq information
- * @stag_to_inv: stag_to_inv value
- * @post_sq: flag to post sq
- */
-static enum i40iw_status_code i40iw_send(struct i40iw_qp_uk *qp,
- struct i40iw_post_sq_info *info,
- u32 stag_to_inv,
- bool post_sq)
-{
- u64 *wqe;
- struct i40iw_post_send *op_info;
- u64 header;
- u32 i, wqe_idx, total_size = 0, byte_off;
- enum i40iw_status_code ret_code;
- bool read_fence = false;
- u8 wqe_size;
-
- op_info = &info->op.send;
- if (qp->max_sq_frag_cnt < op_info->num_sges)
- return I40IW_ERR_INVALID_FRAG_COUNT;
-
- for (i = 0; i < op_info->num_sges; i++)
- total_size += op_info->sg_list[i].len;
- ret_code = i40iw_fragcnt_to_wqesize_sq(op_info->num_sges, &wqe_size);
- if (ret_code)
- return ret_code;
-
- wqe = i40iw_qp_get_next_send_wqe(qp, &wqe_idx, wqe_size, total_size, info->wr_id);
- if (!wqe)
- return I40IW_ERR_QP_TOOMANY_WRS_POSTED;
-
- read_fence |= info->read_fence;
- set_64bit_val(wqe, 16, 0);
- header = LS_64(stag_to_inv, I40IWQPSQ_REMSTAG) |
- LS_64(info->op_type, I40IWQPSQ_OPCODE) |
- LS_64((op_info->num_sges > 1 ? (op_info->num_sges - 1) : 0),
- I40IWQPSQ_ADDFRAGCNT) |
- LS_64(read_fence, I40IWQPSQ_READFENCE) |
- LS_64(info->local_fence, I40IWQPSQ_LOCALFENCE) |
- LS_64(info->signaled, I40IWQPSQ_SIGCOMPL) |
- LS_64(qp->swqe_polarity, I40IWQPSQ_VALID);
-
- i40iw_set_fragment(wqe, 0, op_info->sg_list);
-
- for (i = 1, byte_off = 32; i < op_info->num_sges; i++) {
- i40iw_set_fragment(wqe, byte_off, &op_info->sg_list[i]);
- byte_off += 16;
- }
-
- wmb(); /* make sure WQE is populated before valid bit is set */
-
- set_64bit_val(wqe, 24, header);
- if (post_sq)
- i40iw_qp_post_wr(qp);
-
- return 0;
-}
-
-/**
- * i40iw_inline_rdma_write - inline rdma write operation
- * @qp: hw qp ptr
- * @info: post sq information
- * @post_sq: flag to post sq
- */
-static enum i40iw_status_code i40iw_inline_rdma_write(struct i40iw_qp_uk *qp,
- struct i40iw_post_sq_info *info,
- bool post_sq)
-{
- u64 *wqe;
- u8 *dest, *src;
- struct i40iw_inline_rdma_write *op_info;
- u64 header = 0;
- u32 wqe_idx;
- enum i40iw_status_code ret_code;
- bool read_fence = false;
- u8 wqe_size;
-
- op_info = &info->op.inline_rdma_write;
- if (op_info->len > I40IW_MAX_INLINE_DATA_SIZE)
- return I40IW_ERR_INVALID_INLINE_DATA_SIZE;
-
- ret_code = i40iw_inline_data_size_to_wqesize(op_info->len, &wqe_size);
- if (ret_code)
- return ret_code;
-
- wqe = i40iw_qp_get_next_send_wqe(qp, &wqe_idx, wqe_size, op_info->len, info->wr_id);
- if (!wqe)
- return I40IW_ERR_QP_TOOMANY_WRS_POSTED;
-
- read_fence |= info->read_fence;
- set_64bit_val(wqe, 16,
- LS_64(op_info->rem_addr.tag_off, I40IWQPSQ_FRAG_TO));
-
- header = LS_64(op_info->rem_addr.stag, I40IWQPSQ_REMSTAG) |
- LS_64(I40IWQP_OP_RDMA_WRITE, I40IWQPSQ_OPCODE) |
- LS_64(op_info->len, I40IWQPSQ_INLINEDATALEN) |
- LS_64(1, I40IWQPSQ_INLINEDATAFLAG) |
- LS_64(read_fence, I40IWQPSQ_READFENCE) |
- LS_64(info->local_fence, I40IWQPSQ_LOCALFENCE) |
- LS_64(info->signaled, I40IWQPSQ_SIGCOMPL) |
- LS_64(qp->swqe_polarity, I40IWQPSQ_VALID);
-
- dest = (u8 *)wqe;
- src = (u8 *)(op_info->data);
-
- if (op_info->len <= 16) {
- memcpy(dest, src, op_info->len);
- } else {
- memcpy(dest, src, 16);
- src += 16;
- dest = (u8 *)wqe + 32;
- memcpy(dest, src, op_info->len - 16);
- }
-
- wmb(); /* make sure WQE is populated before valid bit is set */
-
- set_64bit_val(wqe, 24, header);
-
- if (post_sq)
- i40iw_qp_post_wr(qp);
-
- return 0;
-}
-
-/**
- * i40iw_inline_send - inline send operation
- * @qp: hw qp ptr
- * @info: post sq information
- * @stag_to_inv: remote stag
- * @post_sq: flag to post sq
- */
-static enum i40iw_status_code i40iw_inline_send(struct i40iw_qp_uk *qp,
- struct i40iw_post_sq_info *info,
- u32 stag_to_inv,
- bool post_sq)
-{
- u64 *wqe;
- u8 *dest, *src;
- struct i40iw_post_inline_send *op_info;
- u64 header;
- u32 wqe_idx;
- enum i40iw_status_code ret_code;
- bool read_fence = false;
- u8 wqe_size;
-
- op_info = &info->op.inline_send;
- if (op_info->len > I40IW_MAX_INLINE_DATA_SIZE)
- return I40IW_ERR_INVALID_INLINE_DATA_SIZE;
-
- ret_code = i40iw_inline_data_size_to_wqesize(op_info->len, &wqe_size);
- if (ret_code)
- return ret_code;
-
- wqe = i40iw_qp_get_next_send_wqe(qp, &wqe_idx, wqe_size, op_info->len, info->wr_id);
- if (!wqe)
- return I40IW_ERR_QP_TOOMANY_WRS_POSTED;
-
- read_fence |= info->read_fence;
- header = LS_64(stag_to_inv, I40IWQPSQ_REMSTAG) |
- LS_64(info->op_type, I40IWQPSQ_OPCODE) |
- LS_64(op_info->len, I40IWQPSQ_INLINEDATALEN) |
- LS_64(1, I40IWQPSQ_INLINEDATAFLAG) |
- LS_64(read_fence, I40IWQPSQ_READFENCE) |
- LS_64(info->local_fence, I40IWQPSQ_LOCALFENCE) |
- LS_64(info->signaled, I40IWQPSQ_SIGCOMPL) |
- LS_64(qp->swqe_polarity, I40IWQPSQ_VALID);
-
- dest = (u8 *)wqe;
- src = (u8 *)(op_info->data);
-
- if (op_info->len <= 16) {
- memcpy(dest, src, op_info->len);
- } else {
- memcpy(dest, src, 16);
- src += 16;
- dest = (u8 *)wqe + 32;
- memcpy(dest, src, op_info->len - 16);
- }
-
- wmb(); /* make sure WQE is populated before valid bit is set */
-
- set_64bit_val(wqe, 24, header);
-
- if (post_sq)
- i40iw_qp_post_wr(qp);
-
- return 0;
-}
-
-/**
- * i40iw_stag_local_invalidate - stag invalidate operation
- * @qp: hw qp ptr
- * @info: post sq information
- * @post_sq: flag to post sq
- */
-static enum i40iw_status_code i40iw_stag_local_invalidate(struct i40iw_qp_uk *qp,
- struct i40iw_post_sq_info *info,
- bool post_sq)
-{
- u64 *wqe;
- struct i40iw_inv_local_stag *op_info;
- u64 header;
- u32 wqe_idx;
- bool local_fence = false;
-
- op_info = &info->op.inv_local_stag;
- local_fence = info->local_fence;
-
- wqe = i40iw_qp_get_next_send_wqe(qp, &wqe_idx, I40IW_QP_WQE_MIN_SIZE, 0, info->wr_id);
- if (!wqe)
- return I40IW_ERR_QP_TOOMANY_WRS_POSTED;
- set_64bit_val(wqe, 0, 0);
- set_64bit_val(wqe, 8,
- LS_64(op_info->target_stag, I40IWQPSQ_LOCSTAG));
- set_64bit_val(wqe, 16, 0);
- header = LS_64(I40IW_OP_TYPE_INV_STAG, I40IWQPSQ_OPCODE) |
- LS_64(info->read_fence, I40IWQPSQ_READFENCE) |
- LS_64(local_fence, I40IWQPSQ_LOCALFENCE) |
- LS_64(info->signaled, I40IWQPSQ_SIGCOMPL) |
- LS_64(qp->swqe_polarity, I40IWQPSQ_VALID);
-
- wmb(); /* make sure WQE is populated before valid bit is set */
-
- set_64bit_val(wqe, 24, header);
-
- if (post_sq)
- i40iw_qp_post_wr(qp);
-
- return 0;
-}
-
-/**
- * i40iw_mw_bind - Memory Window bind operation
- * @qp: hw qp ptr
- * @info: post sq information
- * @post_sq: flag to post sq
- */
-static enum i40iw_status_code i40iw_mw_bind(struct i40iw_qp_uk *qp,
- struct i40iw_post_sq_info *info,
- bool post_sq)
-{
- u64 *wqe;
- struct i40iw_bind_window *op_info;
- u64 header;
- u32 wqe_idx;
- bool local_fence = false;
-
- op_info = &info->op.bind_window;
-
- local_fence |= info->local_fence;
- wqe = i40iw_qp_get_next_send_wqe(qp, &wqe_idx, I40IW_QP_WQE_MIN_SIZE, 0, info->wr_id);
- if (!wqe)
- return I40IW_ERR_QP_TOOMANY_WRS_POSTED;
- set_64bit_val(wqe, 0, (uintptr_t)op_info->va);
- set_64bit_val(wqe, 8,
- LS_64(op_info->mr_stag, I40IWQPSQ_PARENTMRSTAG) |
- LS_64(op_info->mw_stag, I40IWQPSQ_MWSTAG));
- set_64bit_val(wqe, 16, op_info->bind_length);
- header = LS_64(I40IW_OP_TYPE_BIND_MW, I40IWQPSQ_OPCODE) |
- LS_64(((op_info->enable_reads << 2) |
- (op_info->enable_writes << 3)),
- I40IWQPSQ_STAGRIGHTS) |
- LS_64((op_info->addressing_type == I40IW_ADDR_TYPE_VA_BASED ? 1 : 0),
- I40IWQPSQ_VABASEDTO) |
- LS_64(info->read_fence, I40IWQPSQ_READFENCE) |
- LS_64(local_fence, I40IWQPSQ_LOCALFENCE) |
- LS_64(info->signaled, I40IWQPSQ_SIGCOMPL) |
- LS_64(qp->swqe_polarity, I40IWQPSQ_VALID);
-
- wmb(); /* make sure WQE is populated before valid bit is set */
-
- set_64bit_val(wqe, 24, header);
-
- if (post_sq)
- i40iw_qp_post_wr(qp);
-
- return 0;
-}
-
-/**
- * i40iw_post_receive - post receive wqe
- * @qp: hw qp ptr
- * @info: post rq information
- */
-static enum i40iw_status_code i40iw_post_receive(struct i40iw_qp_uk *qp,
- struct i40iw_post_rq_info *info)
-{
- u64 *wqe;
- u64 header;
- u32 total_size = 0, wqe_idx, i, byte_off;
-
- if (qp->max_rq_frag_cnt < info->num_sges)
- return I40IW_ERR_INVALID_FRAG_COUNT;
- for (i = 0; i < info->num_sges; i++)
- total_size += info->sg_list[i].len;
- wqe = i40iw_qp_get_next_recv_wqe(qp, &wqe_idx);
- if (!wqe)
- return I40IW_ERR_QP_TOOMANY_WRS_POSTED;
-
- qp->rq_wrid_array[wqe_idx] = info->wr_id;
- set_64bit_val(wqe, 16, 0);
-
- header = LS_64((info->num_sges > 1 ? (info->num_sges - 1) : 0),
- I40IWQPSQ_ADDFRAGCNT) |
- LS_64(qp->rwqe_polarity, I40IWQPSQ_VALID);
-
- i40iw_set_fragment(wqe, 0, info->sg_list);
-
- for (i = 1, byte_off = 32; i < info->num_sges; i++) {
- i40iw_set_fragment(wqe, byte_off, &info->sg_list[i]);
- byte_off += 16;
- }
-
- wmb(); /* make sure WQE is populated before valid bit is set */
-
- set_64bit_val(wqe, 24, header);
-
- return 0;
-}
-
-/**
- * i40iw_cq_request_notification - cq notification request (door bell)
- * @cq: hw cq
- * @cq_notify: notification type
- */
-static void i40iw_cq_request_notification(struct i40iw_cq_uk *cq,
- enum i40iw_completion_notify cq_notify)
-{
- u64 temp_val;
- u16 sw_cq_sel;
- u8 arm_next_se = 0;
- u8 arm_next = 0;
- u8 arm_seq_num;
-
- get_64bit_val(cq->shadow_area, 32, &temp_val);
- arm_seq_num = (u8)RS_64(temp_val, I40IW_CQ_DBSA_ARM_SEQ_NUM);
- arm_seq_num++;
-
- sw_cq_sel = (u16)RS_64(temp_val, I40IW_CQ_DBSA_SW_CQ_SELECT);
- arm_next_se = (u8)RS_64(temp_val, I40IW_CQ_DBSA_ARM_NEXT_SE);
- arm_next_se |= 1;
- if (cq_notify == IW_CQ_COMPL_EVENT)
- arm_next = 1;
- temp_val = LS_64(arm_seq_num, I40IW_CQ_DBSA_ARM_SEQ_NUM) |
- LS_64(sw_cq_sel, I40IW_CQ_DBSA_SW_CQ_SELECT) |
- LS_64(arm_next_se, I40IW_CQ_DBSA_ARM_NEXT_SE) |
- LS_64(arm_next, I40IW_CQ_DBSA_ARM_NEXT);
-
- set_64bit_val(cq->shadow_area, 32, temp_val);
-
- wmb(); /* make sure WQE is populated before valid bit is set */
-
- writel(cq->cq_id, cq->cqe_alloc_reg);
-}
-
-/**
- * i40iw_cq_post_entries - update tail in shadow memory
- * @cq: hw cq
- * @count: # of entries processed
- */
-static enum i40iw_status_code i40iw_cq_post_entries(struct i40iw_cq_uk *cq,
- u8 count)
-{
- I40IW_RING_MOVE_TAIL_BY_COUNT(cq->cq_ring, count);
- set_64bit_val(cq->shadow_area, 0,
- I40IW_RING_GETCURRENT_HEAD(cq->cq_ring));
- return 0;
-}
-
-/**
- * i40iw_cq_poll_completion - get cq completion info
- * @cq: hw cq
- * @info: cq poll information returned
- */
-static enum i40iw_status_code i40iw_cq_poll_completion(struct i40iw_cq_uk *cq,
- struct i40iw_cq_poll_info *info)
-{
- u64 comp_ctx, qword0, qword2, qword3, wqe_qword;
- u64 *cqe, *sw_wqe;
- struct i40iw_qp_uk *qp;
- struct i40iw_ring *pring = NULL;
- u32 wqe_idx, q_type, array_idx = 0;
- enum i40iw_status_code ret_code = 0;
- bool move_cq_head = true;
- u8 polarity;
- u8 addl_wqes = 0;
-
- if (cq->avoid_mem_cflct)
- cqe = (u64 *)I40IW_GET_CURRENT_EXTENDED_CQ_ELEMENT(cq);
- else
- cqe = (u64 *)I40IW_GET_CURRENT_CQ_ELEMENT(cq);
-
- get_64bit_val(cqe, 24, &qword3);
- polarity = (u8)RS_64(qword3, I40IW_CQ_VALID);
-
- if (polarity != cq->polarity)
- return I40IW_ERR_QUEUE_EMPTY;
-
- q_type = (u8)RS_64(qword3, I40IW_CQ_SQ);
- info->error = (bool)RS_64(qword3, I40IW_CQ_ERROR);
- if (info->error) {
- info->comp_status = I40IW_COMPL_STATUS_FLUSHED;
- info->major_err = (bool)RS_64(qword3, I40IW_CQ_MAJERR);
- info->minor_err = (bool)RS_64(qword3, I40IW_CQ_MINERR);
- } else {
- info->comp_status = I40IW_COMPL_STATUS_SUCCESS;
- }
-
- get_64bit_val(cqe, 0, &qword0);
- get_64bit_val(cqe, 16, &qword2);
-
- info->tcp_seq_num = (u32)RS_64(qword0, I40IWCQ_TCPSEQNUM);
-
- info->qp_id = (u32)RS_64(qword2, I40IWCQ_QPID);
-
- get_64bit_val(cqe, 8, &comp_ctx);
-
- info->solicited_event = (bool)RS_64(qword3, I40IWCQ_SOEVENT);
- info->is_srq = (bool)RS_64(qword3, I40IWCQ_SRQ);
-
- qp = (struct i40iw_qp_uk *)(unsigned long)comp_ctx;
- if (!qp) {
- ret_code = I40IW_ERR_QUEUE_DESTROYED;
- goto exit;
- }
- wqe_idx = (u32)RS_64(qword3, I40IW_CQ_WQEIDX);
- info->qp_handle = (i40iw_qp_handle)(unsigned long)qp;
-
- if (q_type == I40IW_CQE_QTYPE_RQ) {
- array_idx = (wqe_idx * 4) / qp->rq_wqe_size_multiplier;
- if (info->comp_status == I40IW_COMPL_STATUS_FLUSHED) {
- info->wr_id = qp->rq_wrid_array[qp->rq_ring.tail];
- array_idx = qp->rq_ring.tail;
- } else {
- info->wr_id = qp->rq_wrid_array[array_idx];
- }
-
- info->op_type = I40IW_OP_TYPE_REC;
- if (qword3 & I40IWCQ_STAG_MASK) {
- info->stag_invalid_set = true;
- info->inv_stag = (u32)RS_64(qword2, I40IWCQ_INVSTAG);
- } else {
- info->stag_invalid_set = false;
- }
- info->bytes_xfered = (u32)RS_64(qword0, I40IWCQ_PAYLDLEN);
- I40IW_RING_SET_TAIL(qp->rq_ring, array_idx + 1);
- pring = &qp->rq_ring;
- } else {
- if (qp->first_sq_wq) {
- qp->first_sq_wq = false;
- if (!wqe_idx && (qp->sq_ring.head == qp->sq_ring.tail)) {
- I40IW_RING_MOVE_HEAD_NOCHECK(cq->cq_ring);
- I40IW_RING_MOVE_TAIL(cq->cq_ring);
- set_64bit_val(cq->shadow_area, 0,
- I40IW_RING_GETCURRENT_HEAD(cq->cq_ring));
- memset(info, 0, sizeof(struct i40iw_cq_poll_info));
- return i40iw_cq_poll_completion(cq, info);
- }
- }
-
- if (info->comp_status != I40IW_COMPL_STATUS_FLUSHED) {
- info->wr_id = qp->sq_wrtrk_array[wqe_idx].wrid;
- info->bytes_xfered = qp->sq_wrtrk_array[wqe_idx].wr_len;
-
- info->op_type = (u8)RS_64(qword3, I40IWCQ_OP);
- sw_wqe = qp->sq_base[wqe_idx].elem;
- get_64bit_val(sw_wqe, 24, &wqe_qword);
-
- addl_wqes = qp->sq_wrtrk_array[wqe_idx].wqe_size / I40IW_QP_WQE_MIN_SIZE;
- I40IW_RING_SET_TAIL(qp->sq_ring, (wqe_idx + addl_wqes));
- } else {
- do {
- u8 op_type;
- u32 tail;
-
- tail = qp->sq_ring.tail;
- sw_wqe = qp->sq_base[tail].elem;
- get_64bit_val(sw_wqe, 24, &wqe_qword);
- op_type = (u8)RS_64(wqe_qword, I40IWQPSQ_OPCODE);
- info->op_type = op_type;
- addl_wqes = qp->sq_wrtrk_array[tail].wqe_size / I40IW_QP_WQE_MIN_SIZE;
- I40IW_RING_SET_TAIL(qp->sq_ring, (tail + addl_wqes));
- if (op_type != I40IWQP_OP_NOP) {
- info->wr_id = qp->sq_wrtrk_array[tail].wrid;
- info->bytes_xfered = qp->sq_wrtrk_array[tail].wr_len;
- break;
- }
- } while (1);
- }
- pring = &qp->sq_ring;
- }
-
- ret_code = 0;
-
-exit:
- if (!ret_code &&
- (info->comp_status == I40IW_COMPL_STATUS_FLUSHED))
- if (pring && (I40IW_RING_MORE_WORK(*pring)))
- move_cq_head = false;
-
- if (move_cq_head) {
- I40IW_RING_MOVE_HEAD_NOCHECK(cq->cq_ring);
-
- if (I40IW_RING_GETCURRENT_HEAD(cq->cq_ring) == 0)
- cq->polarity ^= 1;
-
- I40IW_RING_MOVE_TAIL(cq->cq_ring);
- set_64bit_val(cq->shadow_area, 0,
- I40IW_RING_GETCURRENT_HEAD(cq->cq_ring));
- } else {
- if (info->is_srq)
- return ret_code;
- qword3 &= ~I40IW_CQ_WQEIDX_MASK;
- qword3 |= LS_64(pring->tail, I40IW_CQ_WQEIDX);
- set_64bit_val(cqe, 24, qword3);
- }
-
- return ret_code;
-}
-
-/**
- * i40iw_get_wqe_shift - get shift count for maximum wqe size
- * @sge: Maximum Scatter Gather Elements wqe
- * @inline_data: Maximum inline data size
- * @shift: Returns the shift needed based on sge
- *
- * Shift can be used to left shift the wqe size based on number of SGEs and inlind data size.
- * For 1 SGE or inline data <= 16, shift = 0 (wqe size of 32 bytes).
- * For 2 or 3 SGEs or inline data <= 48, shift = 1 (wqe size of 64 bytes).
- * Shift of 2 otherwise (wqe size of 128 bytes).
- */
-void i40iw_get_wqe_shift(u32 sge, u32 inline_data, u8 *shift)
-{
- *shift = 0;
- if (sge > 1 || inline_data > 16)
- *shift = (sge < 4 && inline_data <= 48) ? 1 : 2;
-}
-
-/*
- * i40iw_get_sqdepth - get SQ depth (quantas)
- * @sq_size: SQ size
- * @shift: shift which determines size of WQE
- * @sqdepth: depth of SQ
- *
- */
-enum i40iw_status_code i40iw_get_sqdepth(u32 sq_size, u8 shift, u32 *sqdepth)
-{
- *sqdepth = roundup_pow_of_two((sq_size << shift) + I40IW_SQ_RSVD);
-
- if (*sqdepth < (I40IW_QP_SW_MIN_WQSIZE << shift))
- *sqdepth = I40IW_QP_SW_MIN_WQSIZE << shift;
- else if (*sqdepth > I40IW_QP_SW_MAX_SQ_QUANTAS)
- return I40IW_ERR_INVALID_SIZE;
-
- return 0;
-}
-
-/*
- * i40iw_get_rq_depth - get RQ depth (quantas)
- * @rq_size: RQ size
- * @shift: shift which determines size of WQE
- * @rqdepth: depth of RQ
- *
- */
-enum i40iw_status_code i40iw_get_rqdepth(u32 rq_size, u8 shift, u32 *rqdepth)
-{
- *rqdepth = roundup_pow_of_two((rq_size << shift) + I40IW_RQ_RSVD);
-
- if (*rqdepth < (I40IW_QP_SW_MIN_WQSIZE << shift))
- *rqdepth = I40IW_QP_SW_MIN_WQSIZE << shift;
- else if (*rqdepth > I40IW_QP_SW_MAX_RQ_QUANTAS)
- return I40IW_ERR_INVALID_SIZE;
-
- return 0;
-}
-
-static const struct i40iw_qp_uk_ops iw_qp_uk_ops = {
- .iw_qp_post_wr = i40iw_qp_post_wr,
- .iw_rdma_write = i40iw_rdma_write,
- .iw_rdma_read = i40iw_rdma_read,
- .iw_send = i40iw_send,
- .iw_inline_rdma_write = i40iw_inline_rdma_write,
- .iw_inline_send = i40iw_inline_send,
- .iw_stag_local_invalidate = i40iw_stag_local_invalidate,
- .iw_mw_bind = i40iw_mw_bind,
- .iw_post_receive = i40iw_post_receive,
- .iw_post_nop = i40iw_nop
-};
-
-static const struct i40iw_cq_ops iw_cq_ops = {
- .iw_cq_request_notification = i40iw_cq_request_notification,
- .iw_cq_poll_completion = i40iw_cq_poll_completion,
- .iw_cq_post_entries = i40iw_cq_post_entries,
- .iw_cq_clean = i40iw_clean_cq
-};
-
-static const struct i40iw_device_uk_ops iw_device_uk_ops = {
- .iwarp_cq_uk_init = i40iw_cq_uk_init,
- .iwarp_qp_uk_init = i40iw_qp_uk_init,
-};
-
-/**
- * i40iw_qp_uk_init - initialize shared qp
- * @qp: hw qp (user and kernel)
- * @info: qp initialization info
- *
- * initializes the vars used in both user and kernel mode.
- * size of the wqe depends on numbers of max. fragements
- * allowed. Then size of wqe * the number of wqes should be the
- * amount of memory allocated for sq and rq. If srq is used,
- * then rq_base will point to one rq wqe only (not the whole
- * array of wqes)
- */
-enum i40iw_status_code i40iw_qp_uk_init(struct i40iw_qp_uk *qp,
- struct i40iw_qp_uk_init_info *info)
-{
- enum i40iw_status_code ret_code = 0;
- u32 sq_ring_size;
- u8 sqshift, rqshift;
-
- if (info->max_sq_frag_cnt > I40IW_MAX_WQ_FRAGMENT_COUNT)
- return I40IW_ERR_INVALID_FRAG_COUNT;
-
- if (info->max_rq_frag_cnt > I40IW_MAX_WQ_FRAGMENT_COUNT)
- return I40IW_ERR_INVALID_FRAG_COUNT;
- i40iw_get_wqe_shift(info->max_sq_frag_cnt, info->max_inline_data, &sqshift);
-
- qp->sq_base = info->sq;
- qp->rq_base = info->rq;
- qp->shadow_area = info->shadow_area;
- qp->sq_wrtrk_array = info->sq_wrtrk_array;
- qp->rq_wrid_array = info->rq_wrid_array;
-
- qp->wqe_alloc_reg = info->wqe_alloc_reg;
- qp->qp_id = info->qp_id;
- qp->sq_size = info->sq_size;
- qp->max_sq_frag_cnt = info->max_sq_frag_cnt;
- sq_ring_size = qp->sq_size << sqshift;
-
- I40IW_RING_INIT(qp->sq_ring, sq_ring_size);
- I40IW_RING_INIT(qp->initial_ring, sq_ring_size);
- I40IW_RING_MOVE_HEAD(qp->sq_ring, ret_code);
- I40IW_RING_MOVE_TAIL(qp->sq_ring);
- I40IW_RING_MOVE_HEAD(qp->initial_ring, ret_code);
- qp->swqe_polarity = 1;
- qp->first_sq_wq = true;
- qp->swqe_polarity_deferred = 1;
- qp->rwqe_polarity = 0;
-
- if (!qp->use_srq) {
- qp->rq_size = info->rq_size;
- qp->max_rq_frag_cnt = info->max_rq_frag_cnt;
- I40IW_RING_INIT(qp->rq_ring, qp->rq_size);
- switch (info->abi_ver) {
- case 4:
- i40iw_get_wqe_shift(info->max_rq_frag_cnt, 0, &rqshift);
- break;
- case 5: /* fallthrough until next ABI version */
- default:
- rqshift = I40IW_MAX_RQ_WQE_SHIFT;
- break;
- }
- qp->rq_wqe_size = rqshift;
- qp->rq_wqe_size_multiplier = 4 << rqshift;
- }
- qp->ops = iw_qp_uk_ops;
-
- return ret_code;
-}
-
-/**
- * i40iw_cq_uk_init - initialize shared cq (user and kernel)
- * @cq: hw cq
- * @info: hw cq initialization info
- */
-enum i40iw_status_code i40iw_cq_uk_init(struct i40iw_cq_uk *cq,
- struct i40iw_cq_uk_init_info *info)
-{
- if ((info->cq_size < I40IW_MIN_CQ_SIZE) ||
- (info->cq_size > I40IW_MAX_CQ_SIZE))
- return I40IW_ERR_INVALID_SIZE;
- cq->cq_base = (struct i40iw_cqe *)info->cq_base;
- cq->cq_id = info->cq_id;
- cq->cq_size = info->cq_size;
- cq->cqe_alloc_reg = info->cqe_alloc_reg;
- cq->shadow_area = info->shadow_area;
- cq->avoid_mem_cflct = info->avoid_mem_cflct;
-
- I40IW_RING_INIT(cq->cq_ring, cq->cq_size);
- cq->polarity = 1;
- cq->ops = iw_cq_ops;
-
- return 0;
-}
-
-/**
- * i40iw_device_init_uk - setup routines for iwarp shared device
- * @dev: iwarp shared (user and kernel)
- */
-void i40iw_device_init_uk(struct i40iw_dev_uk *dev)
-{
- dev->ops_uk = iw_device_uk_ops;
-}
-
-/**
- * i40iw_clean_cq - clean cq entries
- * @queue: completion context
- * @cq: cq to clean
- */
-void i40iw_clean_cq(void *queue, struct i40iw_cq_uk *cq)
-{
- u64 *cqe;
- u64 qword3, comp_ctx;
- u32 cq_head;
- u8 polarity, temp;
-
- cq_head = cq->cq_ring.head;
- temp = cq->polarity;
- do {
- if (cq->avoid_mem_cflct)
- cqe = (u64 *)&(((struct i40iw_extended_cqe *)cq->cq_base)[cq_head]);
- else
- cqe = (u64 *)&cq->cq_base[cq_head];
- get_64bit_val(cqe, 24, &qword3);
- polarity = (u8)RS_64(qword3, I40IW_CQ_VALID);
-
- if (polarity != temp)
- break;
-
- get_64bit_val(cqe, 8, &comp_ctx);
- if ((void *)(unsigned long)comp_ctx == queue)
- set_64bit_val(cqe, 8, 0);
-
- cq_head = (cq_head + 1) % cq->cq_ring.size;
- if (!cq_head)
- temp ^= 1;
- } while (true);
-}
-
-/**
- * i40iw_nop - send a nop
- * @qp: hw qp ptr
- * @wr_id: work request id
- * @signaled: flag if signaled for completion
- * @post_sq: flag to post sq
- */
-enum i40iw_status_code i40iw_nop(struct i40iw_qp_uk *qp,
- u64 wr_id,
- bool signaled,
- bool post_sq)
-{
- u64 header, *wqe;
- u32 wqe_idx;
-
- wqe = i40iw_qp_get_next_send_wqe(qp, &wqe_idx, I40IW_QP_WQE_MIN_SIZE, 0, wr_id);
- if (!wqe)
- return I40IW_ERR_QP_TOOMANY_WRS_POSTED;
- set_64bit_val(wqe, 0, 0);
- set_64bit_val(wqe, 8, 0);
- set_64bit_val(wqe, 16, 0);
-
- header = LS_64(I40IWQP_OP_NOP, I40IWQPSQ_OPCODE) |
- LS_64(signaled, I40IWQPSQ_SIGCOMPL) |
- LS_64(qp->swqe_polarity, I40IWQPSQ_VALID);
-
- wmb(); /* make sure WQE is populated before valid bit is set */
-
- set_64bit_val(wqe, 24, header);
- if (post_sq)
- i40iw_qp_post_wr(qp);
-
- return 0;
-}
-
-/**
- * i40iw_fragcnt_to_wqesize_sq - calculate wqe size based on fragment count for SQ
- * @frag_cnt: number of fragments
- * @wqe_size: size of sq wqe returned
- */
-enum i40iw_status_code i40iw_fragcnt_to_wqesize_sq(u32 frag_cnt, u8 *wqe_size)
-{
- switch (frag_cnt) {
- case 0:
- case 1:
- *wqe_size = I40IW_QP_WQE_MIN_SIZE;
- break;
- case 2:
- case 3:
- *wqe_size = 64;
- break;
- case 4:
- case 5:
- *wqe_size = 96;
- break;
- case 6:
- case 7:
- *wqe_size = 128;
- break;
- default:
- return I40IW_ERR_INVALID_FRAG_COUNT;
- }
-
- return 0;
-}
-
-/**
- * i40iw_fragcnt_to_wqesize_rq - calculate wqe size based on fragment count for RQ
- * @frag_cnt: number of fragments
- * @wqe_size: size of rq wqe returned
- */
-enum i40iw_status_code i40iw_fragcnt_to_wqesize_rq(u32 frag_cnt, u8 *wqe_size)
-{
- switch (frag_cnt) {
- case 0:
- case 1:
- *wqe_size = 32;
- break;
- case 2:
- case 3:
- *wqe_size = 64;
- break;
- case 4:
- case 5:
- case 6:
- case 7:
- *wqe_size = 128;
- break;
- default:
- return I40IW_ERR_INVALID_FRAG_COUNT;
- }
-
- return 0;
-}
-
-/**
- * i40iw_inline_data_size_to_wqesize - based on inline data, wqe size
- * @data_size: data size for inline
- * @wqe_size: size of sq wqe returned
- */
-enum i40iw_status_code i40iw_inline_data_size_to_wqesize(u32 data_size,
- u8 *wqe_size)
-{
- if (data_size > I40IW_MAX_INLINE_DATA_SIZE)
- return I40IW_ERR_INVALID_INLINE_DATA_SIZE;
-
- if (data_size <= 16)
- *wqe_size = I40IW_QP_WQE_MIN_SIZE;
- else
- *wqe_size = 64;
-
- return 0;
-}
diff --git a/drivers/infiniband/hw/i40iw/i40iw_user.h b/drivers/infiniband/hw/i40iw/i40iw_user.h
deleted file mode 100644
index 93fc3081dd65..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_user.h
+++ /dev/null
@@ -1,422 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_USER_H
-#define I40IW_USER_H
-
-enum i40iw_device_capabilities_const {
- I40IW_WQE_SIZE = 4,
- I40IW_CQP_WQE_SIZE = 8,
- I40IW_CQE_SIZE = 4,
- I40IW_EXTENDED_CQE_SIZE = 8,
- I40IW_AEQE_SIZE = 2,
- I40IW_CEQE_SIZE = 1,
- I40IW_CQP_CTX_SIZE = 8,
- I40IW_SHADOW_AREA_SIZE = 8,
- I40IW_CEQ_MAX_COUNT = 256,
- I40IW_QUERY_FPM_BUF_SIZE = 128,
- I40IW_COMMIT_FPM_BUF_SIZE = 128,
- I40IW_MIN_IW_QP_ID = 1,
- I40IW_MAX_IW_QP_ID = 262143,
- I40IW_MIN_CEQID = 0,
- I40IW_MAX_CEQID = 256,
- I40IW_MIN_CQID = 0,
- I40IW_MAX_CQID = 131071,
- I40IW_MIN_AEQ_ENTRIES = 1,
- I40IW_MAX_AEQ_ENTRIES = 524287,
- I40IW_MIN_CEQ_ENTRIES = 1,
- I40IW_MAX_CEQ_ENTRIES = 131071,
- I40IW_MIN_CQ_SIZE = 1,
- I40IW_MAX_CQ_SIZE = 1048575,
- I40IW_DB_ID_ZERO = 0,
- I40IW_MAX_WQ_FRAGMENT_COUNT = 3,
- I40IW_MAX_SGE_RD = 1,
- I40IW_MAX_OUTBOUND_MESSAGE_SIZE = 2147483647,
- I40IW_MAX_INBOUND_MESSAGE_SIZE = 2147483647,
- I40IW_MAX_PE_ENABLED_VF_COUNT = 32,
- I40IW_MAX_VF_FPM_ID = 47,
- I40IW_MAX_VF_PER_PF = 127,
- I40IW_MAX_SQ_PAYLOAD_SIZE = 2145386496,
- I40IW_MAX_INLINE_DATA_SIZE = 48,
- I40IW_MAX_IRD_SIZE = 64,
- I40IW_MAX_ORD_SIZE = 127,
- I40IW_MAX_WQ_ENTRIES = 2048,
- I40IW_Q2_BUFFER_SIZE = (248 + 100),
- I40IW_MAX_WQE_SIZE_RQ = 128,
- I40IW_QP_CTX_SIZE = 248,
- I40IW_MAX_PDS = 32768
-};
-
-#define i40iw_handle void *
-#define i40iw_adapter_handle i40iw_handle
-#define i40iw_qp_handle i40iw_handle
-#define i40iw_cq_handle i40iw_handle
-#define i40iw_srq_handle i40iw_handle
-#define i40iw_pd_id i40iw_handle
-#define i40iw_stag_handle i40iw_handle
-#define i40iw_stag_index u32
-#define i40iw_stag u32
-#define i40iw_stag_key u8
-
-#define i40iw_tagged_offset u64
-#define i40iw_access_privileges u32
-#define i40iw_physical_fragment u64
-#define i40iw_address_list u64 *
-
-#define I40IW_MAX_MR_SIZE 0x10000000000L
-#define I40IW_MAX_RQ_WQE_SHIFT 2
-
-struct i40iw_qp_uk;
-struct i40iw_cq_uk;
-struct i40iw_srq_uk;
-struct i40iw_qp_uk_init_info;
-struct i40iw_cq_uk_init_info;
-struct i40iw_srq_uk_init_info;
-
-struct i40iw_sge {
- i40iw_tagged_offset tag_off;
- u32 len;
- i40iw_stag stag;
-};
-
-#define i40iw_sgl struct i40iw_sge *
-
-struct i40iw_ring {
- u32 head;
- u32 tail;
- u32 size;
-};
-
-struct i40iw_cqe {
- u64 buf[I40IW_CQE_SIZE];
-};
-
-struct i40iw_extended_cqe {
- u64 buf[I40IW_EXTENDED_CQE_SIZE];
-};
-
-struct i40iw_wqe {
- u64 buf[I40IW_WQE_SIZE];
-};
-
-struct i40iw_qp_uk_ops;
-
-enum i40iw_addressing_type {
- I40IW_ADDR_TYPE_ZERO_BASED = 0,
- I40IW_ADDR_TYPE_VA_BASED = 1,
-};
-
-#define I40IW_ACCESS_FLAGS_LOCALREAD 0x01
-#define I40IW_ACCESS_FLAGS_LOCALWRITE 0x02
-#define I40IW_ACCESS_FLAGS_REMOTEREAD_ONLY 0x04
-#define I40IW_ACCESS_FLAGS_REMOTEREAD 0x05
-#define I40IW_ACCESS_FLAGS_REMOTEWRITE_ONLY 0x08
-#define I40IW_ACCESS_FLAGS_REMOTEWRITE 0x0a
-#define I40IW_ACCESS_FLAGS_BIND_WINDOW 0x10
-#define I40IW_ACCESS_FLAGS_ALL 0x1F
-
-#define I40IW_OP_TYPE_RDMA_WRITE 0
-#define I40IW_OP_TYPE_RDMA_READ 1
-#define I40IW_OP_TYPE_SEND 3
-#define I40IW_OP_TYPE_SEND_INV 4
-#define I40IW_OP_TYPE_SEND_SOL 5
-#define I40IW_OP_TYPE_SEND_SOL_INV 6
-#define I40IW_OP_TYPE_REC 7
-#define I40IW_OP_TYPE_BIND_MW 8
-#define I40IW_OP_TYPE_FAST_REG_NSMR 9
-#define I40IW_OP_TYPE_INV_STAG 10
-#define I40IW_OP_TYPE_RDMA_READ_INV_STAG 11
-#define I40IW_OP_TYPE_NOP 12
-
-enum i40iw_completion_status {
- I40IW_COMPL_STATUS_SUCCESS = 0,
- I40IW_COMPL_STATUS_FLUSHED,
- I40IW_COMPL_STATUS_INVALID_WQE,
- I40IW_COMPL_STATUS_QP_CATASTROPHIC,
- I40IW_COMPL_STATUS_REMOTE_TERMINATION,
- I40IW_COMPL_STATUS_INVALID_STAG,
- I40IW_COMPL_STATUS_BASE_BOUND_VIOLATION,
- I40IW_COMPL_STATUS_ACCESS_VIOLATION,
- I40IW_COMPL_STATUS_INVALID_PD_ID,
- I40IW_COMPL_STATUS_WRAP_ERROR,
- I40IW_COMPL_STATUS_STAG_INVALID_PDID,
- I40IW_COMPL_STATUS_RDMA_READ_ZERO_ORD,
- I40IW_COMPL_STATUS_QP_NOT_PRIVLEDGED,
- I40IW_COMPL_STATUS_STAG_NOT_INVALID,
- I40IW_COMPL_STATUS_INVALID_PHYS_BUFFER_SIZE,
- I40IW_COMPL_STATUS_INVALID_PHYS_BUFFER_ENTRY,
- I40IW_COMPL_STATUS_INVALID_FBO,
- I40IW_COMPL_STATUS_INVALID_LENGTH,
- I40IW_COMPL_STATUS_INVALID_ACCESS,
- I40IW_COMPL_STATUS_PHYS_BUFFER_LIST_TOO_LONG,
- I40IW_COMPL_STATUS_INVALID_VIRT_ADDRESS,
- I40IW_COMPL_STATUS_INVALID_REGION,
- I40IW_COMPL_STATUS_INVALID_WINDOW,
- I40IW_COMPL_STATUS_INVALID_TOTAL_LENGTH
-};
-
-enum i40iw_completion_notify {
- IW_CQ_COMPL_EVENT = 0,
- IW_CQ_COMPL_SOLICITED = 1
-};
-
-struct i40iw_post_send {
- i40iw_sgl sg_list;
- u32 num_sges;
-};
-
-struct i40iw_post_inline_send {
- void *data;
- u32 len;
-};
-
-struct i40iw_rdma_write {
- i40iw_sgl lo_sg_list;
- u32 num_lo_sges;
- struct i40iw_sge rem_addr;
-};
-
-struct i40iw_inline_rdma_write {
- void *data;
- u32 len;
- struct i40iw_sge rem_addr;
-};
-
-struct i40iw_rdma_read {
- struct i40iw_sge lo_addr;
- struct i40iw_sge rem_addr;
-};
-
-struct i40iw_bind_window {
- i40iw_stag mr_stag;
- u64 bind_length;
- void *va;
- enum i40iw_addressing_type addressing_type;
- bool enable_reads;
- bool enable_writes;
- i40iw_stag mw_stag;
-};
-
-struct i40iw_inv_local_stag {
- i40iw_stag target_stag;
-};
-
-struct i40iw_post_sq_info {
- u64 wr_id;
- u8 op_type;
- bool signaled;
- bool read_fence;
- bool local_fence;
- bool inline_data;
- bool defer_flag;
- union {
- struct i40iw_post_send send;
- struct i40iw_rdma_write rdma_write;
- struct i40iw_rdma_read rdma_read;
- struct i40iw_rdma_read rdma_read_inv;
- struct i40iw_bind_window bind_window;
- struct i40iw_inv_local_stag inv_local_stag;
- struct i40iw_inline_rdma_write inline_rdma_write;
- struct i40iw_post_inline_send inline_send;
- } op;
-};
-
-struct i40iw_post_rq_info {
- u64 wr_id;
- i40iw_sgl sg_list;
- u32 num_sges;
-};
-
-struct i40iw_cq_poll_info {
- u64 wr_id;
- i40iw_qp_handle qp_handle;
- u32 bytes_xfered;
- u32 tcp_seq_num;
- u32 qp_id;
- i40iw_stag inv_stag;
- enum i40iw_completion_status comp_status;
- u16 major_err;
- u16 minor_err;
- u8 op_type;
- bool stag_invalid_set;
- bool error;
- bool is_srq;
- bool solicited_event;
-};
-
-struct i40iw_qp_uk_ops {
- void (*iw_qp_post_wr)(struct i40iw_qp_uk *);
- enum i40iw_status_code (*iw_rdma_write)(struct i40iw_qp_uk *,
- struct i40iw_post_sq_info *, bool);
- enum i40iw_status_code (*iw_rdma_read)(struct i40iw_qp_uk *,
- struct i40iw_post_sq_info *, bool, bool);
- enum i40iw_status_code (*iw_send)(struct i40iw_qp_uk *,
- struct i40iw_post_sq_info *, u32, bool);
- enum i40iw_status_code (*iw_inline_rdma_write)(struct i40iw_qp_uk *,
- struct i40iw_post_sq_info *, bool);
- enum i40iw_status_code (*iw_inline_send)(struct i40iw_qp_uk *,
- struct i40iw_post_sq_info *, u32, bool);
- enum i40iw_status_code (*iw_stag_local_invalidate)(struct i40iw_qp_uk *,
- struct i40iw_post_sq_info *, bool);
- enum i40iw_status_code (*iw_mw_bind)(struct i40iw_qp_uk *,
- struct i40iw_post_sq_info *, bool);
- enum i40iw_status_code (*iw_post_receive)(struct i40iw_qp_uk *,
- struct i40iw_post_rq_info *);
- enum i40iw_status_code (*iw_post_nop)(struct i40iw_qp_uk *, u64, bool, bool);
-};
-
-struct i40iw_cq_ops {
- void (*iw_cq_request_notification)(struct i40iw_cq_uk *,
- enum i40iw_completion_notify);
- enum i40iw_status_code (*iw_cq_poll_completion)(struct i40iw_cq_uk *,
- struct i40iw_cq_poll_info *);
- enum i40iw_status_code (*iw_cq_post_entries)(struct i40iw_cq_uk *, u8 count);
- void (*iw_cq_clean)(void *, struct i40iw_cq_uk *);
-};
-
-struct i40iw_dev_uk;
-
-struct i40iw_device_uk_ops {
- enum i40iw_status_code (*iwarp_cq_uk_init)(struct i40iw_cq_uk *,
- struct i40iw_cq_uk_init_info *);
- enum i40iw_status_code (*iwarp_qp_uk_init)(struct i40iw_qp_uk *,
- struct i40iw_qp_uk_init_info *);
-};
-
-struct i40iw_dev_uk {
- struct i40iw_device_uk_ops ops_uk;
-};
-
-struct i40iw_sq_uk_wr_trk_info {
- u64 wrid;
- u32 wr_len;
- u8 wqe_size;
- u8 reserved[3];
-};
-
-struct i40iw_qp_quanta {
- u64 elem[I40IW_WQE_SIZE];
-};
-
-struct i40iw_qp_uk {
- struct i40iw_qp_quanta *sq_base;
- struct i40iw_qp_quanta *rq_base;
- u32 __iomem *wqe_alloc_reg;
- struct i40iw_sq_uk_wr_trk_info *sq_wrtrk_array;
- u64 *rq_wrid_array;
- u64 *shadow_area;
- struct i40iw_ring sq_ring;
- struct i40iw_ring rq_ring;
- struct i40iw_ring initial_ring;
- u32 qp_id;
- u32 sq_size;
- u32 rq_size;
- u32 max_sq_frag_cnt;
- u32 max_rq_frag_cnt;
- struct i40iw_qp_uk_ops ops;
- bool use_srq;
- u8 swqe_polarity;
- u8 swqe_polarity_deferred;
- u8 rwqe_polarity;
- u8 rq_wqe_size;
- u8 rq_wqe_size_multiplier;
- bool first_sq_wq;
- bool deferred_flag;
-};
-
-struct i40iw_cq_uk {
- struct i40iw_cqe *cq_base;
- u32 __iomem *cqe_alloc_reg;
- u64 *shadow_area;
- u32 cq_id;
- u32 cq_size;
- struct i40iw_ring cq_ring;
- u8 polarity;
- bool avoid_mem_cflct;
-
- struct i40iw_cq_ops ops;
-};
-
-struct i40iw_qp_uk_init_info {
- struct i40iw_qp_quanta *sq;
- struct i40iw_qp_quanta *rq;
- u32 __iomem *wqe_alloc_reg;
- u64 *shadow_area;
- struct i40iw_sq_uk_wr_trk_info *sq_wrtrk_array;
- u64 *rq_wrid_array;
- u32 qp_id;
- u32 sq_size;
- u32 rq_size;
- u32 max_sq_frag_cnt;
- u32 max_rq_frag_cnt;
- u32 max_inline_data;
- int abi_ver;
-};
-
-struct i40iw_cq_uk_init_info {
- u32 __iomem *cqe_alloc_reg;
- struct i40iw_cqe *cq_base;
- u64 *shadow_area;
- u32 cq_size;
- u32 cq_id;
- bool avoid_mem_cflct;
-};
-
-void i40iw_device_init_uk(struct i40iw_dev_uk *dev);
-
-void i40iw_qp_post_wr(struct i40iw_qp_uk *qp);
-u64 *i40iw_qp_get_next_send_wqe(struct i40iw_qp_uk *qp, u32 *wqe_idx,
- u8 wqe_size,
- u32 total_size,
- u64 wr_id
- );
-u64 *i40iw_qp_get_next_recv_wqe(struct i40iw_qp_uk *qp, u32 *wqe_idx);
-u64 *i40iw_qp_get_next_srq_wqe(struct i40iw_srq_uk *srq, u32 *wqe_idx);
-
-enum i40iw_status_code i40iw_cq_uk_init(struct i40iw_cq_uk *cq,
- struct i40iw_cq_uk_init_info *info);
-enum i40iw_status_code i40iw_qp_uk_init(struct i40iw_qp_uk *qp,
- struct i40iw_qp_uk_init_info *info);
-
-void i40iw_clean_cq(void *queue, struct i40iw_cq_uk *cq);
-enum i40iw_status_code i40iw_nop(struct i40iw_qp_uk *qp, u64 wr_id,
- bool signaled, bool post_sq);
-enum i40iw_status_code i40iw_fragcnt_to_wqesize_sq(u32 frag_cnt, u8 *wqe_size);
-enum i40iw_status_code i40iw_fragcnt_to_wqesize_rq(u32 frag_cnt, u8 *wqe_size);
-enum i40iw_status_code i40iw_inline_data_size_to_wqesize(u32 data_size,
- u8 *wqe_size);
-void i40iw_get_wqe_shift(u32 sge, u32 inline_data, u8 *shift);
-enum i40iw_status_code i40iw_get_sqdepth(u32 sq_size, u8 shift, u32 *sqdepth);
-enum i40iw_status_code i40iw_get_rqdepth(u32 rq_size, u8 shift, u32 *rqdepth);
-#endif
diff --git a/drivers/infiniband/hw/i40iw/i40iw_utils.c b/drivers/infiniband/hw/i40iw/i40iw_utils.c
deleted file mode 100644
index 9ff825f7860b..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_utils.c
+++ /dev/null
@@ -1,1518 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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/ip.h>
-#include <linux/tcp.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-#include <net/netevent.h>
-#include <net/neighbour.h>
-#include "i40iw.h"
-
-/**
- * i40iw_arp_table - manage arp table
- * @iwdev: iwarp device
- * @ip_addr: ip address for device
- * @ipv4: flag indicating IPv4 when true
- * @mac_addr: mac address ptr
- * @action: modify, delete or add
- */
-int i40iw_arp_table(struct i40iw_device *iwdev,
- u32 *ip_addr,
- bool ipv4,
- u8 *mac_addr,
- u32 action)
-{
- int arp_index;
- int err;
- u32 ip[4];
-
- if (ipv4) {
- memset(ip, 0, sizeof(ip));
- ip[0] = *ip_addr;
- } else {
- memcpy(ip, ip_addr, sizeof(ip));
- }
-
- for (arp_index = 0; (u32)arp_index < iwdev->arp_table_size; arp_index++)
- if (memcmp(iwdev->arp_table[arp_index].ip_addr, ip, sizeof(ip)) == 0)
- break;
- switch (action) {
- case I40IW_ARP_ADD:
- if (arp_index != iwdev->arp_table_size)
- return -1;
-
- arp_index = 0;
- err = i40iw_alloc_resource(iwdev, iwdev->allocated_arps,
- iwdev->arp_table_size,
- (u32 *)&arp_index,
- &iwdev->next_arp_index);
-
- if (err)
- return err;
-
- memcpy(iwdev->arp_table[arp_index].ip_addr, ip, sizeof(ip));
- ether_addr_copy(iwdev->arp_table[arp_index].mac_addr, mac_addr);
- break;
- case I40IW_ARP_RESOLVE:
- if (arp_index == iwdev->arp_table_size)
- return -1;
- break;
- case I40IW_ARP_DELETE:
- if (arp_index == iwdev->arp_table_size)
- return -1;
- memset(iwdev->arp_table[arp_index].ip_addr, 0,
- sizeof(iwdev->arp_table[arp_index].ip_addr));
- eth_zero_addr(iwdev->arp_table[arp_index].mac_addr);
- i40iw_free_resource(iwdev, iwdev->allocated_arps, arp_index);
- break;
- default:
- return -1;
- }
- return arp_index;
-}
-
-/**
- * i40iw_wr32 - write 32 bits to hw register
- * @hw: hardware information including registers
- * @reg: register offset
- * @value: vvalue to write to register
- */
-inline void i40iw_wr32(struct i40iw_hw *hw, u32 reg, u32 value)
-{
- writel(value, hw->hw_addr + reg);
-}
-
-/**
- * i40iw_rd32 - read a 32 bit hw register
- * @hw: hardware information including registers
- * @reg: register offset
- *
- * Return value of register content
- */
-inline u32 i40iw_rd32(struct i40iw_hw *hw, u32 reg)
-{
- return readl(hw->hw_addr + reg);
-}
-
-/**
- * i40iw_inetaddr_event - system notifier for ipv4 addr events
- * @notifier: not used
- * @event: event for notifier
- * @ptr: if address
- */
-int i40iw_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 net_device *netdev;
- struct net_device *upper_dev;
- struct i40iw_device *iwdev;
- struct i40iw_handler *hdl;
- u32 local_ipaddr;
- u32 action = I40IW_ARP_ADD;
-
- hdl = i40iw_find_netdev(event_netdev);
- if (!hdl)
- return NOTIFY_DONE;
-
- iwdev = &hdl->device;
- if (iwdev->init_state < IP_ADDR_REGISTERED || iwdev->closing)
- return NOTIFY_DONE;
-
- netdev = iwdev->ldev->netdev;
- upper_dev = netdev_master_upper_dev_get(netdev);
- if (netdev != event_netdev)
- return NOTIFY_DONE;
-
- if (upper_dev) {
- struct in_device *in;
-
- rcu_read_lock();
- in = __in_dev_get_rcu(upper_dev);
-
- 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 {
- local_ipaddr = ntohl(ifa->ifa_address);
- }
- switch (event) {
- case NETDEV_DOWN:
- action = I40IW_ARP_DELETE;
- fallthrough;
- case NETDEV_UP:
- case NETDEV_CHANGEADDR:
-
- /* Just skip if no need to handle ARP cache */
- if (!local_ipaddr)
- break;
-
- i40iw_manage_arp_cache(iwdev,
- netdev->dev_addr,
- &local_ipaddr,
- true,
- action);
- i40iw_if_notify(iwdev, netdev, &local_ipaddr, true,
- (action == I40IW_ARP_ADD) ? true : false);
- break;
- default:
- break;
- }
- return NOTIFY_DONE;
-}
-
-/**
- * i40iw_inet6addr_event - system notifier for ipv6 addr events
- * @notifier: not used
- * @event: event for notifier
- * @ptr: if address
- */
-int i40iw_inet6addr_event(struct notifier_block *notifier,
- unsigned long event,
- void *ptr)
-{
- struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
- struct net_device *event_netdev = ifa->idev->dev;
- struct net_device *netdev;
- struct i40iw_device *iwdev;
- struct i40iw_handler *hdl;
- u32 local_ipaddr6[4];
- u32 action = I40IW_ARP_ADD;
-
- hdl = i40iw_find_netdev(event_netdev);
- if (!hdl)
- return NOTIFY_DONE;
-
- iwdev = &hdl->device;
- if (iwdev->init_state < IP_ADDR_REGISTERED || iwdev->closing)
- return NOTIFY_DONE;
-
- netdev = iwdev->ldev->netdev;
- if (netdev != event_netdev)
- return NOTIFY_DONE;
-
- i40iw_copy_ip_ntohl(local_ipaddr6, ifa->addr.in6_u.u6_addr32);
- switch (event) {
- case NETDEV_DOWN:
- action = I40IW_ARP_DELETE;
- fallthrough;
- case NETDEV_UP:
- case NETDEV_CHANGEADDR:
- i40iw_manage_arp_cache(iwdev,
- netdev->dev_addr,
- local_ipaddr6,
- false,
- action);
- i40iw_if_notify(iwdev, netdev, local_ipaddr6, false,
- (action == I40IW_ARP_ADD) ? true : false);
- break;
- default:
- break;
- }
- return NOTIFY_DONE;
-}
-
-/**
- * i40iw_net_event - system notifier for netevents
- * @notifier: not used
- * @event: event for notifier
- * @ptr: neighbor
- */
-int i40iw_net_event(struct notifier_block *notifier, unsigned long event, void *ptr)
-{
- struct neighbour *neigh = ptr;
- struct i40iw_device *iwdev;
- struct i40iw_handler *iwhdl;
- __be32 *p;
- u32 local_ipaddr[4];
-
- switch (event) {
- case NETEVENT_NEIGH_UPDATE:
- iwhdl = i40iw_find_netdev((struct net_device *)neigh->dev);
- if (!iwhdl)
- return NOTIFY_DONE;
- iwdev = &iwhdl->device;
- if (iwdev->init_state < IP_ADDR_REGISTERED || iwdev->closing)
- return NOTIFY_DONE;
- p = (__be32 *)neigh->primary_key;
- i40iw_copy_ip_ntohl(local_ipaddr, p);
- if (neigh->nud_state & NUD_VALID) {
- i40iw_manage_arp_cache(iwdev,
- neigh->ha,
- local_ipaddr,
- false,
- I40IW_ARP_ADD);
-
- } else {
- i40iw_manage_arp_cache(iwdev,
- neigh->ha,
- local_ipaddr,
- false,
- I40IW_ARP_DELETE);
- }
- break;
- default:
- break;
- }
- return NOTIFY_DONE;
-}
-
-/**
- * i40iw_netdevice_event - system notifier for netdev events
- * @notifier: not used
- * @event: event for notifier
- * @ptr: netdev
- */
-int i40iw_netdevice_event(struct notifier_block *notifier,
- unsigned long event,
- void *ptr)
-{
- struct net_device *event_netdev;
- struct net_device *netdev;
- struct i40iw_device *iwdev;
- struct i40iw_handler *hdl;
-
- event_netdev = netdev_notifier_info_to_dev(ptr);
-
- hdl = i40iw_find_netdev(event_netdev);
- if (!hdl)
- return NOTIFY_DONE;
-
- iwdev = &hdl->device;
- if (iwdev->init_state < RDMA_DEV_REGISTERED || iwdev->closing)
- return NOTIFY_DONE;
-
- netdev = iwdev->ldev->netdev;
- if (netdev != event_netdev)
- return NOTIFY_DONE;
-
- iwdev->iw_status = 1;
-
- switch (event) {
- case NETDEV_DOWN:
- iwdev->iw_status = 0;
- fallthrough;
- case NETDEV_UP:
- i40iw_port_ibevent(iwdev);
- break;
- default:
- break;
- }
- return NOTIFY_DONE;
-}
-
-/**
- * i40iw_get_cqp_request - get cqp struct
- * @cqp: device cqp ptr
- * @wait: cqp to be used in wait mode
- */
-struct i40iw_cqp_request *i40iw_get_cqp_request(struct i40iw_cqp *cqp, bool wait)
-{
- struct i40iw_cqp_request *cqp_request = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&cqp->req_lock, flags);
- if (!list_empty(&cqp->cqp_avail_reqs)) {
- cqp_request = list_entry(cqp->cqp_avail_reqs.next,
- struct i40iw_cqp_request, list);
- list_del_init(&cqp_request->list);
- }
- spin_unlock_irqrestore(&cqp->req_lock, flags);
- if (!cqp_request) {
- cqp_request = kzalloc(sizeof(*cqp_request), GFP_ATOMIC);
- if (cqp_request) {
- cqp_request->dynamic = true;
- INIT_LIST_HEAD(&cqp_request->list);
- init_waitqueue_head(&cqp_request->waitq);
- }
- }
- if (!cqp_request) {
- i40iw_pr_err("CQP Request Fail: No Memory");
- return NULL;
- }
-
- if (wait) {
- atomic_set(&cqp_request->refcount, 2);
- cqp_request->waiting = true;
- } else {
- atomic_set(&cqp_request->refcount, 1);
- }
- return cqp_request;
-}
-
-/**
- * i40iw_free_cqp_request - free cqp request
- * @cqp: cqp ptr
- * @cqp_request: to be put back in cqp list
- */
-void i40iw_free_cqp_request(struct i40iw_cqp *cqp, struct i40iw_cqp_request *cqp_request)
-{
- struct i40iw_device *iwdev = container_of(cqp, struct i40iw_device, cqp);
- unsigned long flags;
-
- if (cqp_request->dynamic) {
- kfree(cqp_request);
- } else {
- cqp_request->request_done = false;
- cqp_request->callback_fcn = NULL;
- cqp_request->waiting = false;
-
- spin_lock_irqsave(&cqp->req_lock, flags);
- list_add_tail(&cqp_request->list, &cqp->cqp_avail_reqs);
- spin_unlock_irqrestore(&cqp->req_lock, flags);
- }
- wake_up(&iwdev->close_wq);
-}
-
-/**
- * i40iw_put_cqp_request - dec ref count and free if 0
- * @cqp: cqp ptr
- * @cqp_request: to be put back in cqp list
- */
-void i40iw_put_cqp_request(struct i40iw_cqp *cqp,
- struct i40iw_cqp_request *cqp_request)
-{
- if (atomic_dec_and_test(&cqp_request->refcount))
- i40iw_free_cqp_request(cqp, cqp_request);
-}
-
-/**
- * i40iw_free_pending_cqp_request -free pending cqp request objs
- * @cqp: cqp ptr
- * @cqp_request: to be put back in cqp list
- */
-static void i40iw_free_pending_cqp_request(struct i40iw_cqp *cqp,
- struct i40iw_cqp_request *cqp_request)
-{
- struct i40iw_device *iwdev = container_of(cqp, struct i40iw_device, cqp);
-
- if (cqp_request->waiting) {
- cqp_request->compl_info.error = true;
- cqp_request->request_done = true;
- wake_up(&cqp_request->waitq);
- }
- i40iw_put_cqp_request(cqp, cqp_request);
- wait_event_timeout(iwdev->close_wq,
- !atomic_read(&cqp_request->refcount),
- 1000);
-}
-
-/**
- * i40iw_cleanup_pending_cqp_op - clean-up cqp with no completions
- * @iwdev: iwarp device
- */
-void i40iw_cleanup_pending_cqp_op(struct i40iw_device *iwdev)
-{
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_cqp *cqp = &iwdev->cqp;
- struct i40iw_cqp_request *cqp_request = NULL;
- struct cqp_commands_info *pcmdinfo = NULL;
- u32 i, pending_work, wqe_idx;
-
- pending_work = I40IW_RING_WORK_AVAILABLE(cqp->sc_cqp.sq_ring);
- wqe_idx = I40IW_RING_GETCURRENT_TAIL(cqp->sc_cqp.sq_ring);
- for (i = 0; i < pending_work; i++) {
- cqp_request = (struct i40iw_cqp_request *)(unsigned long)cqp->scratch_array[wqe_idx];
- if (cqp_request)
- i40iw_free_pending_cqp_request(cqp, cqp_request);
- wqe_idx = (wqe_idx + 1) % I40IW_RING_GETSIZE(cqp->sc_cqp.sq_ring);
- }
-
- while (!list_empty(&dev->cqp_cmd_head)) {
- pcmdinfo = (struct cqp_commands_info *)i40iw_remove_head(&dev->cqp_cmd_head);
- cqp_request = container_of(pcmdinfo, struct i40iw_cqp_request, info);
- if (cqp_request)
- i40iw_free_pending_cqp_request(cqp, cqp_request);
- }
-}
-
-/**
- * i40iw_wait_event - wait for completion
- * @iwdev: iwarp device
- * @cqp_request: cqp request to wait
- */
-static int i40iw_wait_event(struct i40iw_device *iwdev,
- struct i40iw_cqp_request *cqp_request)
-{
- struct cqp_commands_info *info = &cqp_request->info;
- struct i40iw_cqp *iwcqp = &iwdev->cqp;
- struct i40iw_cqp_timeout cqp_timeout;
- bool cqp_error = false;
- int err_code = 0;
- memset(&cqp_timeout, 0, sizeof(cqp_timeout));
- cqp_timeout.compl_cqp_cmds = iwdev->sc_dev.cqp_cmd_stats[OP_COMPLETED_COMMANDS];
- do {
- if (wait_event_timeout(cqp_request->waitq,
- cqp_request->request_done, CQP_COMPL_WAIT_TIME))
- break;
-
- i40iw_check_cqp_progress(&cqp_timeout, &iwdev->sc_dev);
-
- if (cqp_timeout.count < CQP_TIMEOUT_THRESHOLD)
- continue;
-
- i40iw_pr_err("error cqp command 0x%x timed out", info->cqp_cmd);
- err_code = -ETIME;
- if (!iwdev->reset) {
- iwdev->reset = true;
- i40iw_request_reset(iwdev);
- }
- goto done;
- } while (1);
- cqp_error = cqp_request->compl_info.error;
- if (cqp_error) {
- i40iw_pr_err("error cqp command 0x%x completion maj = 0x%x min=0x%x\n",
- info->cqp_cmd, cqp_request->compl_info.maj_err_code,
- cqp_request->compl_info.min_err_code);
- err_code = -EPROTO;
- goto done;
- }
-done:
- i40iw_put_cqp_request(iwcqp, cqp_request);
- return err_code;
-}
-
-/**
- * i40iw_handle_cqp_op - process cqp command
- * @iwdev: iwarp device
- * @cqp_request: cqp request to process
- */
-enum i40iw_status_code i40iw_handle_cqp_op(struct i40iw_device *iwdev,
- struct i40iw_cqp_request
- *cqp_request)
-{
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- enum i40iw_status_code status;
- struct cqp_commands_info *info = &cqp_request->info;
- int err_code = 0;
-
- if (iwdev->reset) {
- i40iw_free_cqp_request(&iwdev->cqp, cqp_request);
- return I40IW_ERR_CQP_COMPL_ERROR;
- }
-
- status = i40iw_process_cqp_cmd(dev, info);
- if (status) {
- i40iw_pr_err("error cqp command 0x%x failed\n", info->cqp_cmd);
- i40iw_free_cqp_request(&iwdev->cqp, cqp_request);
- return status;
- }
- if (cqp_request->waiting)
- err_code = i40iw_wait_event(iwdev, cqp_request);
- if (err_code)
- status = I40IW_ERR_CQP_COMPL_ERROR;
- return status;
-}
-
-/**
- * i40iw_add_devusecount - add dev refcount
- * @iwdev: dev for refcount
- */
-void i40iw_add_devusecount(struct i40iw_device *iwdev)
-{
- atomic64_inc(&iwdev->use_count);
-}
-
-/**
- * i40iw_rem_devusecount - decrement refcount for dev
- * @iwdev: device
- */
-void i40iw_rem_devusecount(struct i40iw_device *iwdev)
-{
- if (!atomic64_dec_and_test(&iwdev->use_count))
- return;
- wake_up(&iwdev->close_wq);
-}
-
-/**
- * i40iw_add_pdusecount - add pd refcount
- * @iwpd: pd for refcount
- */
-void i40iw_add_pdusecount(struct i40iw_pd *iwpd)
-{
- atomic_inc(&iwpd->usecount);
-}
-
-/**
- * i40iw_rem_pdusecount - decrement refcount for pd and free if 0
- * @iwpd: pd for refcount
- * @iwdev: iwarp device
- */
-void i40iw_rem_pdusecount(struct i40iw_pd *iwpd, struct i40iw_device *iwdev)
-{
- if (!atomic_dec_and_test(&iwpd->usecount))
- return;
- i40iw_free_resource(iwdev, iwdev->allocated_pds, iwpd->sc_pd.pd_id);
-}
-
-/**
- * i40iw_qp_add_ref - add refcount for qp
- * @ibqp: iqarp qp
- */
-void i40iw_qp_add_ref(struct ib_qp *ibqp)
-{
- struct i40iw_qp *iwqp = (struct i40iw_qp *)ibqp;
-
- refcount_inc(&iwqp->refcount);
-}
-
-/**
- * i40iw_qp_rem_ref - rem refcount for qp and free if 0
- * @ibqp: iqarp qp
- */
-void i40iw_qp_rem_ref(struct ib_qp *ibqp)
-{
- struct i40iw_qp *iwqp;
- struct i40iw_device *iwdev;
- u32 qp_num;
- unsigned long flags;
-
- iwqp = to_iwqp(ibqp);
- iwdev = iwqp->iwdev;
- spin_lock_irqsave(&iwdev->qptable_lock, flags);
- if (!refcount_dec_and_test(&iwqp->refcount)) {
- spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
- return;
- }
-
- qp_num = iwqp->ibqp.qp_num;
- iwdev->qp_table[qp_num] = NULL;
- spin_unlock_irqrestore(&iwdev->qptable_lock, flags);
- complete(&iwqp->free_qp);
-
-}
-
-/**
- * i40iw_get_qp - get qp address
- * @device: iwarp device
- * @qpn: qp number
- */
-struct ib_qp *i40iw_get_qp(struct ib_device *device, int qpn)
-{
- struct i40iw_device *iwdev = to_iwdev(device);
-
- if ((qpn < IW_FIRST_QPN) || (qpn >= iwdev->max_qp))
- return NULL;
-
- return &iwdev->qp_table[qpn]->ibqp;
-}
-
-/**
- * i40iw_debug_buf - print debug msg and buffer is mask set
- * @dev: hardware control device structure
- * @mask: mask to compare if to print debug buffer
- * @desc: identifying string
- * @buf: points buffer addr
- * @size: saize of buffer to print
- */
-void i40iw_debug_buf(struct i40iw_sc_dev *dev,
- enum i40iw_debug_flag mask,
- char *desc,
- u64 *buf,
- u32 size)
-{
- u32 i;
-
- if (!(dev->debug_mask & mask))
- return;
- i40iw_debug(dev, mask, "%s\n", desc);
- i40iw_debug(dev, mask, "starting address virt=%p phy=%llxh\n", buf,
- (unsigned long long)virt_to_phys(buf));
-
- for (i = 0; i < size; i += 8)
- i40iw_debug(dev, mask, "index %03d val: %016llx\n", i, buf[i / 8]);
-}
-
-/**
- * i40iw_get_hw_addr - return hw addr
- * @par: points to shared dev
- */
-u8 __iomem *i40iw_get_hw_addr(void *par)
-{
- struct i40iw_sc_dev *dev = (struct i40iw_sc_dev *)par;
-
- return dev->hw->hw_addr;
-}
-
-/**
- * i40iw_remove_head - return head entry and remove from list
- * @list: list for entry
- */
-void *i40iw_remove_head(struct list_head *list)
-{
- struct list_head *entry;
-
- if (list_empty(list))
- return NULL;
-
- entry = (void *)list->next;
- list_del(entry);
- return (void *)entry;
-}
-
-/**
- * i40iw_allocate_dma_mem - Memory alloc helper fn
- * @hw: pointer to the HW structure
- * @mem: ptr to mem struct to fill out
- * @size: size of memory requested
- * @alignment: what to align the allocation to
- */
-enum i40iw_status_code i40iw_allocate_dma_mem(struct i40iw_hw *hw,
- struct i40iw_dma_mem *mem,
- u64 size,
- u32 alignment)
-{
- struct pci_dev *pcidev = hw->pcidev;
-
- if (!mem)
- return I40IW_ERR_PARAM;
- mem->size = ALIGN(size, alignment);
- mem->va = dma_alloc_coherent(&pcidev->dev, mem->size,
- (dma_addr_t *)&mem->pa, GFP_KERNEL);
- if (!mem->va)
- return I40IW_ERR_NO_MEMORY;
- return 0;
-}
-
-/**
- * i40iw_free_dma_mem - Memory free helper fn
- * @hw: pointer to the HW structure
- * @mem: ptr to mem struct to free
- */
-void i40iw_free_dma_mem(struct i40iw_hw *hw, struct i40iw_dma_mem *mem)
-{
- struct pci_dev *pcidev = hw->pcidev;
-
- if (!mem || !mem->va)
- return;
-
- dma_free_coherent(&pcidev->dev, mem->size,
- mem->va, (dma_addr_t)mem->pa);
- mem->va = NULL;
-}
-
-/**
- * i40iw_allocate_virt_mem - virtual memory alloc helper fn
- * @hw: pointer to the HW structure
- * @mem: ptr to mem struct to fill out
- * @size: size of memory requested
- */
-enum i40iw_status_code i40iw_allocate_virt_mem(struct i40iw_hw *hw,
- struct i40iw_virt_mem *mem,
- u32 size)
-{
- if (!mem)
- return I40IW_ERR_PARAM;
-
- mem->size = size;
- mem->va = kzalloc(size, GFP_KERNEL);
-
- if (mem->va)
- return 0;
- else
- return I40IW_ERR_NO_MEMORY;
-}
-
-/**
- * i40iw_free_virt_mem - virtual memory free helper fn
- * @hw: pointer to the HW structure
- * @mem: ptr to mem struct to free
- */
-enum i40iw_status_code i40iw_free_virt_mem(struct i40iw_hw *hw,
- struct i40iw_virt_mem *mem)
-{
- if (!mem)
- return I40IW_ERR_PARAM;
- /*
- * mem->va points to the parent of mem, so both mem and mem->va
- * can not be touched once mem->va is freed
- */
- kfree(mem->va);
- return 0;
-}
-
-/**
- * i40iw_cqp_sds_cmd - create cqp command for sd
- * @dev: hardware control device structure
- * @sdinfo: information for sd cqp
- *
- */
-enum i40iw_status_code i40iw_cqp_sds_cmd(struct i40iw_sc_dev *dev,
- struct i40iw_update_sds_info *sdinfo)
-{
- enum i40iw_status_code status;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
-
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, true);
- if (!cqp_request)
- return I40IW_ERR_NO_MEMORY;
- cqp_info = &cqp_request->info;
- memcpy(&cqp_info->in.u.update_pe_sds.info, sdinfo,
- sizeof(cqp_info->in.u.update_pe_sds.info));
- cqp_info->cqp_cmd = OP_UPDATE_PE_SDS;
- cqp_info->post_sq = 1;
- cqp_info->in.u.update_pe_sds.dev = dev;
- cqp_info->in.u.update_pe_sds.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP-OP Update SD's fail");
- return status;
-}
-
-/**
- * i40iw_qp_suspend_resume - cqp command for suspend/resume
- * @dev: hardware control device structure
- * @qp: hardware control qp
- * @suspend: flag if suspend or resume
- */
-void i40iw_qp_suspend_resume(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp, bool suspend)
-{
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
- struct i40iw_cqp_request *cqp_request;
- struct i40iw_sc_cqp *cqp = dev->cqp;
- struct cqp_commands_info *cqp_info;
- enum i40iw_status_code status;
-
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, false);
- if (!cqp_request)
- return;
-
- cqp_info = &cqp_request->info;
- cqp_info->cqp_cmd = (suspend) ? OP_SUSPEND : OP_RESUME;
- cqp_info->in.u.suspend_resume.cqp = cqp;
- cqp_info->in.u.suspend_resume.qp = qp;
- cqp_info->in.u.suspend_resume.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP-OP QP Suspend/Resume fail");
-}
-
-/**
- * i40iw_term_modify_qp - modify qp for term message
- * @qp: hardware control qp
- * @next_state: qp's next state
- * @term: terminate code
- * @term_len: length
- */
-void i40iw_term_modify_qp(struct i40iw_sc_qp *qp, u8 next_state, u8 term, u8 term_len)
-{
- struct i40iw_qp *iwqp;
-
- iwqp = (struct i40iw_qp *)qp->back_qp;
- i40iw_next_iw_state(iwqp, next_state, 0, term, term_len);
-};
-
-/**
- * i40iw_terminate_done - after terminate is completed
- * @qp: hardware control qp
- * @timeout_occurred: indicates if terminate timer expired
- */
-void i40iw_terminate_done(struct i40iw_sc_qp *qp, int timeout_occurred)
-{
- struct i40iw_qp *iwqp;
- u32 next_iwarp_state = I40IW_QP_STATE_ERROR;
- u8 hte = 0;
- bool first_time;
- unsigned long flags;
-
- iwqp = (struct i40iw_qp *)qp->back_qp;
- spin_lock_irqsave(&iwqp->lock, flags);
- if (iwqp->hte_added) {
- iwqp->hte_added = 0;
- hte = 1;
- }
- first_time = !(qp->term_flags & I40IW_TERM_DONE);
- qp->term_flags |= I40IW_TERM_DONE;
- spin_unlock_irqrestore(&iwqp->lock, flags);
- if (first_time) {
- if (!timeout_occurred)
- i40iw_terminate_del_timer(qp);
- else
- next_iwarp_state = I40IW_QP_STATE_CLOSING;
-
- i40iw_next_iw_state(iwqp, next_iwarp_state, hte, 0, 0);
- i40iw_cm_disconn(iwqp);
- }
-}
-
-/**
- * i40iw_terminate_timeout - timeout happened
- * @t: points to iwarp qp
- */
-static void i40iw_terminate_timeout(struct timer_list *t)
-{
- struct i40iw_qp *iwqp = from_timer(iwqp, t, terminate_timer);
- struct i40iw_sc_qp *qp = (struct i40iw_sc_qp *)&iwqp->sc_qp;
-
- i40iw_terminate_done(qp, 1);
- i40iw_qp_rem_ref(&iwqp->ibqp);
-}
-
-/**
- * i40iw_terminate_start_timer - start terminate timeout
- * @qp: hardware control qp
- */
-void i40iw_terminate_start_timer(struct i40iw_sc_qp *qp)
-{
- struct i40iw_qp *iwqp;
-
- iwqp = (struct i40iw_qp *)qp->back_qp;
- i40iw_qp_add_ref(&iwqp->ibqp);
- timer_setup(&iwqp->terminate_timer, i40iw_terminate_timeout, 0);
- iwqp->terminate_timer.expires = jiffies + HZ;
- add_timer(&iwqp->terminate_timer);
-}
-
-/**
- * i40iw_terminate_del_timer - delete terminate timeout
- * @qp: hardware control qp
- */
-void i40iw_terminate_del_timer(struct i40iw_sc_qp *qp)
-{
- struct i40iw_qp *iwqp;
-
- iwqp = (struct i40iw_qp *)qp->back_qp;
- if (del_timer(&iwqp->terminate_timer))
- i40iw_qp_rem_ref(&iwqp->ibqp);
-}
-
-/**
- * i40iw_cqp_generic_worker - generic worker for cqp
- * @work: work pointer
- */
-static void i40iw_cqp_generic_worker(struct work_struct *work)
-{
- struct i40iw_virtchnl_work_info *work_info =
- &((struct virtchnl_work *)work)->work_info;
-
- if (work_info->worker_vf_dev)
- work_info->callback_fcn(work_info->worker_vf_dev);
-}
-
-/**
- * i40iw_cqp_spawn_worker - spawn worket thread
- * @dev: device struct pointer
- * @work_info: work request info
- * @iw_vf_idx: virtual function index
- */
-void i40iw_cqp_spawn_worker(struct i40iw_sc_dev *dev,
- struct i40iw_virtchnl_work_info *work_info,
- u32 iw_vf_idx)
-{
- struct virtchnl_work *work;
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
-
- work = &iwdev->virtchnl_w[iw_vf_idx];
- memcpy(&work->work_info, work_info, sizeof(*work_info));
- INIT_WORK(&work->work, i40iw_cqp_generic_worker);
- queue_work(iwdev->virtchnl_wq, &work->work);
-}
-
-/**
- * i40iw_cqp_manage_hmc_fcn_worker -
- * @work: work pointer for hmc info
- */
-static void i40iw_cqp_manage_hmc_fcn_worker(struct work_struct *work)
-{
- struct i40iw_cqp_request *cqp_request =
- ((struct virtchnl_work *)work)->cqp_request;
- struct i40iw_ccq_cqe_info ccq_cqe_info;
- struct i40iw_hmc_fcn_info *hmcfcninfo =
- &cqp_request->info.in.u.manage_hmc_pm.info;
- struct i40iw_device *iwdev =
- (struct i40iw_device *)cqp_request->info.in.u.manage_hmc_pm.dev->back_dev;
-
- ccq_cqe_info.cqp = NULL;
- ccq_cqe_info.maj_err_code = cqp_request->compl_info.maj_err_code;
- ccq_cqe_info.min_err_code = cqp_request->compl_info.min_err_code;
- ccq_cqe_info.op_code = cqp_request->compl_info.op_code;
- ccq_cqe_info.op_ret_val = cqp_request->compl_info.op_ret_val;
- ccq_cqe_info.scratch = 0;
- ccq_cqe_info.error = cqp_request->compl_info.error;
- hmcfcninfo->callback_fcn(cqp_request->info.in.u.manage_hmc_pm.dev,
- hmcfcninfo->cqp_callback_param, &ccq_cqe_info);
- i40iw_put_cqp_request(&iwdev->cqp, cqp_request);
-}
-
-/**
- * i40iw_cqp_manage_hmc_fcn_callback - called function after cqp completion
- * @cqp_request: cqp request info struct for hmc fun
- * @unused: unused param of callback
- */
-static void i40iw_cqp_manage_hmc_fcn_callback(struct i40iw_cqp_request *cqp_request,
- u32 unused)
-{
- struct virtchnl_work *work;
- struct i40iw_hmc_fcn_info *hmcfcninfo =
- &cqp_request->info.in.u.manage_hmc_pm.info;
- struct i40iw_device *iwdev =
- (struct i40iw_device *)cqp_request->info.in.u.manage_hmc_pm.dev->
- back_dev;
-
- if (hmcfcninfo && hmcfcninfo->callback_fcn) {
- i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_HMC, "%s1\n", __func__);
- atomic_inc(&cqp_request->refcount);
- work = &iwdev->virtchnl_w[hmcfcninfo->iw_vf_idx];
- work->cqp_request = cqp_request;
- INIT_WORK(&work->work, i40iw_cqp_manage_hmc_fcn_worker);
- queue_work(iwdev->virtchnl_wq, &work->work);
- i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_HMC, "%s2\n", __func__);
- } else {
- i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_HMC, "%s: Something wrong\n", __func__);
- }
-}
-
-/**
- * i40iw_cqp_manage_hmc_fcn_cmd - issue cqp command to manage hmc
- * @dev: hardware control device structure
- * @hmcfcninfo: info for hmc
- */
-enum i40iw_status_code i40iw_cqp_manage_hmc_fcn_cmd(struct i40iw_sc_dev *dev,
- struct i40iw_hmc_fcn_info *hmcfcninfo)
-{
- enum i40iw_status_code status;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
-
- i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_HMC, "%s\n", __func__);
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, false);
- if (!cqp_request)
- return I40IW_ERR_NO_MEMORY;
- cqp_info = &cqp_request->info;
- cqp_request->callback_fcn = i40iw_cqp_manage_hmc_fcn_callback;
- cqp_request->param = hmcfcninfo;
- memcpy(&cqp_info->in.u.manage_hmc_pm.info, hmcfcninfo,
- sizeof(*hmcfcninfo));
- cqp_info->in.u.manage_hmc_pm.dev = dev;
- cqp_info->cqp_cmd = OP_MANAGE_HMC_PM_FUNC_TABLE;
- cqp_info->post_sq = 1;
- cqp_info->in.u.manage_hmc_pm.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP-OP Manage HMC fail");
- return status;
-}
-
-/**
- * i40iw_cqp_query_fpm_values_cmd - send cqp command for fpm
- * @dev: function device struct
- * @values_mem: buffer for fpm
- * @hmc_fn_id: function id for fpm
- */
-enum i40iw_status_code i40iw_cqp_query_fpm_values_cmd(struct i40iw_sc_dev *dev,
- struct i40iw_dma_mem *values_mem,
- u8 hmc_fn_id)
-{
- enum i40iw_status_code status;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
-
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, true);
- if (!cqp_request)
- return I40IW_ERR_NO_MEMORY;
- cqp_info = &cqp_request->info;
- cqp_request->param = NULL;
- cqp_info->in.u.query_fpm_values.cqp = dev->cqp;
- cqp_info->in.u.query_fpm_values.fpm_values_pa = values_mem->pa;
- cqp_info->in.u.query_fpm_values.fpm_values_va = values_mem->va;
- cqp_info->in.u.query_fpm_values.hmc_fn_id = hmc_fn_id;
- cqp_info->cqp_cmd = OP_QUERY_FPM_VALUES;
- cqp_info->post_sq = 1;
- cqp_info->in.u.query_fpm_values.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP-OP Query FPM fail");
- return status;
-}
-
-/**
- * i40iw_cqp_commit_fpm_values_cmd - commit fpm values in hw
- * @dev: hardware control device structure
- * @values_mem: buffer with fpm values
- * @hmc_fn_id: function id for fpm
- */
-enum i40iw_status_code i40iw_cqp_commit_fpm_values_cmd(struct i40iw_sc_dev *dev,
- struct i40iw_dma_mem *values_mem,
- u8 hmc_fn_id)
-{
- enum i40iw_status_code status;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
-
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, true);
- if (!cqp_request)
- return I40IW_ERR_NO_MEMORY;
- cqp_info = &cqp_request->info;
- cqp_request->param = NULL;
- cqp_info->in.u.commit_fpm_values.cqp = dev->cqp;
- cqp_info->in.u.commit_fpm_values.fpm_values_pa = values_mem->pa;
- cqp_info->in.u.commit_fpm_values.fpm_values_va = values_mem->va;
- cqp_info->in.u.commit_fpm_values.hmc_fn_id = hmc_fn_id;
- cqp_info->cqp_cmd = OP_COMMIT_FPM_VALUES;
- cqp_info->post_sq = 1;
- cqp_info->in.u.commit_fpm_values.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP-OP Commit FPM fail");
- return status;
-}
-
-/**
- * i40iw_vf_wait_vchnl_resp - wait for channel msg
- * @dev: function's device struct
- */
-enum i40iw_status_code i40iw_vf_wait_vchnl_resp(struct i40iw_sc_dev *dev)
-{
- struct i40iw_device *iwdev = dev->back_dev;
- int timeout_ret;
-
- i40iw_debug(dev, I40IW_DEBUG_VIRT, "%s[%u] dev %p, iwdev %p\n",
- __func__, __LINE__, dev, iwdev);
-
- atomic_set(&iwdev->vchnl_msgs, 2);
- timeout_ret = wait_event_timeout(iwdev->vchnl_waitq,
- (atomic_read(&iwdev->vchnl_msgs) == 1),
- I40IW_VCHNL_EVENT_TIMEOUT);
- atomic_dec(&iwdev->vchnl_msgs);
- if (!timeout_ret) {
- i40iw_pr_err("virt channel completion timeout = 0x%x\n", timeout_ret);
- atomic_set(&iwdev->vchnl_msgs, 0);
- dev->vchnl_up = false;
- return I40IW_ERR_TIMEOUT;
- }
- wake_up(&dev->vf_reqs);
- return 0;
-}
-
-/**
- * i40iw_cqp_cq_create_cmd - create a cq for the cqp
- * @dev: device pointer
- * @cq: pointer to created cq
- */
-enum i40iw_status_code i40iw_cqp_cq_create_cmd(struct i40iw_sc_dev *dev,
- struct i40iw_sc_cq *cq)
-{
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
- struct i40iw_cqp *iwcqp = &iwdev->cqp;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- enum i40iw_status_code status;
-
- cqp_request = i40iw_get_cqp_request(iwcqp, true);
- if (!cqp_request)
- return I40IW_ERR_NO_MEMORY;
-
- cqp_info = &cqp_request->info;
- cqp_info->cqp_cmd = OP_CQ_CREATE;
- cqp_info->post_sq = 1;
- cqp_info->in.u.cq_create.cq = cq;
- cqp_info->in.u.cq_create.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP-OP Create QP fail");
-
- return status;
-}
-
-/**
- * i40iw_cqp_qp_create_cmd - create a qp for the cqp
- * @dev: device pointer
- * @qp: pointer to created qp
- */
-enum i40iw_status_code i40iw_cqp_qp_create_cmd(struct i40iw_sc_dev *dev,
- struct i40iw_sc_qp *qp)
-{
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
- struct i40iw_cqp *iwcqp = &iwdev->cqp;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- struct i40iw_create_qp_info *qp_info;
- enum i40iw_status_code status;
-
- cqp_request = i40iw_get_cqp_request(iwcqp, true);
- if (!cqp_request)
- return I40IW_ERR_NO_MEMORY;
-
- cqp_info = &cqp_request->info;
- qp_info = &cqp_request->info.in.u.qp_create.info;
-
- memset(qp_info, 0, sizeof(*qp_info));
-
- qp_info->cq_num_valid = true;
- qp_info->next_iwarp_state = I40IW_QP_STATE_RTS;
-
- cqp_info->cqp_cmd = OP_QP_CREATE;
- cqp_info->post_sq = 1;
- cqp_info->in.u.qp_create.qp = qp;
- cqp_info->in.u.qp_create.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP-OP QP create fail");
- return status;
-}
-
-/**
- * i40iw_cqp_cq_destroy_cmd - destroy the cqp cq
- * @dev: device pointer
- * @cq: pointer to cq
- */
-void i40iw_cqp_cq_destroy_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_cq *cq)
-{
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
-
- i40iw_cq_wq_destroy(iwdev, cq);
-}
-
-/**
- * i40iw_cqp_qp_destroy_cmd - destroy the cqp
- * @dev: device pointer
- * @qp: pointer to qp
- */
-void i40iw_cqp_qp_destroy_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp)
-{
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
- struct i40iw_cqp *iwcqp = &iwdev->cqp;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- enum i40iw_status_code status;
-
- cqp_request = i40iw_get_cqp_request(iwcqp, true);
- if (!cqp_request)
- return;
-
- cqp_info = &cqp_request->info;
- memset(cqp_info, 0, sizeof(*cqp_info));
-
- cqp_info->cqp_cmd = OP_QP_DESTROY;
- cqp_info->post_sq = 1;
- cqp_info->in.u.qp_destroy.qp = qp;
- cqp_info->in.u.qp_destroy.scratch = (uintptr_t)cqp_request;
- cqp_info->in.u.qp_destroy.remove_hash_idx = true;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP QP_DESTROY fail");
-}
-
-
-/**
- * i40iw_ieq_mpa_crc_ae - generate AE for crc error
- * @dev: hardware control device structure
- * @qp: hardware control qp
- */
-void i40iw_ieq_mpa_crc_ae(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp)
-{
- struct i40iw_gen_ae_info info;
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
-
- i40iw_debug(dev, I40IW_DEBUG_AEQ, "%s entered\n", __func__);
- info.ae_code = I40IW_AE_LLP_RECEIVED_MPA_CRC_ERROR;
- info.ae_source = I40IW_AE_SOURCE_RQ;
- i40iw_gen_ae(iwdev, qp, &info, false);
-}
-
-/**
- * i40iw_init_hash_desc - initialize hash for crc calculation
- * @desc: cryption type
- */
-enum i40iw_status_code i40iw_init_hash_desc(struct shash_desc **desc)
-{
- struct crypto_shash *tfm;
- struct shash_desc *tdesc;
-
- tfm = crypto_alloc_shash("crc32c", 0, 0);
- if (IS_ERR(tfm))
- return I40IW_ERR_MPA_CRC;
-
- tdesc = kzalloc(sizeof(*tdesc) + crypto_shash_descsize(tfm),
- GFP_KERNEL);
- if (!tdesc) {
- crypto_free_shash(tfm);
- return I40IW_ERR_MPA_CRC;
- }
- tdesc->tfm = tfm;
- *desc = tdesc;
-
- return 0;
-}
-
-/**
- * i40iw_free_hash_desc - free hash desc
- * @desc: to be freed
- */
-void i40iw_free_hash_desc(struct shash_desc *desc)
-{
- if (desc) {
- crypto_free_shash(desc->tfm);
- kfree(desc);
- }
-}
-
-/**
- * i40iw_alloc_query_fpm_buf - allocate buffer for fpm
- * @dev: hardware control device structure
- * @mem: buffer ptr for fpm to be allocated
- * @return: memory allocation status
- */
-enum i40iw_status_code i40iw_alloc_query_fpm_buf(struct i40iw_sc_dev *dev,
- struct i40iw_dma_mem *mem)
-{
- enum i40iw_status_code status;
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
-
- status = i40iw_obj_aligned_mem(iwdev, mem, I40IW_QUERY_FPM_BUF_SIZE,
- I40IW_FPM_QUERY_BUF_ALIGNMENT_MASK);
- return status;
-}
-
-/**
- * i40iw_ieq_check_mpacrc - check if mpa crc is OK
- * @desc: desc for hash
- * @addr: address of buffer for crc
- * @length: length of buffer
- * @value: value to be compared
- */
-enum i40iw_status_code i40iw_ieq_check_mpacrc(struct shash_desc *desc,
- void *addr,
- u32 length,
- u32 value)
-{
- u32 crc = 0;
- int ret;
- enum i40iw_status_code ret_code = 0;
-
- crypto_shash_init(desc);
- ret = crypto_shash_update(desc, addr, length);
- if (!ret)
- crypto_shash_final(desc, (u8 *)&crc);
- if (crc != value) {
- i40iw_pr_err("mpa crc check fail\n");
- ret_code = I40IW_ERR_MPA_CRC;
- }
- return ret_code;
-}
-
-/**
- * i40iw_ieq_get_qp - get qp based on quad in puda buffer
- * @dev: hardware control device structure
- * @buf: receive puda buffer on exception q
- */
-struct i40iw_sc_qp *i40iw_ieq_get_qp(struct i40iw_sc_dev *dev,
- struct i40iw_puda_buf *buf)
-{
- struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev;
- struct i40iw_qp *iwqp;
- struct i40iw_cm_node *cm_node;
- u32 loc_addr[4], rem_addr[4];
- u16 loc_port, rem_port;
- struct ipv6hdr *ip6h;
- struct iphdr *iph = (struct iphdr *)buf->iph;
- struct tcphdr *tcph = (struct tcphdr *)buf->tcph;
-
- if (iph->version == 4) {
- memset(loc_addr, 0, sizeof(loc_addr));
- loc_addr[0] = ntohl(iph->daddr);
- memset(rem_addr, 0, sizeof(rem_addr));
- rem_addr[0] = ntohl(iph->saddr);
- } else {
- ip6h = (struct ipv6hdr *)buf->iph;
- i40iw_copy_ip_ntohl(loc_addr, ip6h->daddr.in6_u.u6_addr32);
- i40iw_copy_ip_ntohl(rem_addr, ip6h->saddr.in6_u.u6_addr32);
- }
- loc_port = ntohs(tcph->dest);
- rem_port = ntohs(tcph->source);
-
- cm_node = i40iw_find_node(&iwdev->cm_core, rem_port, rem_addr, loc_port,
- loc_addr, false, true);
- if (!cm_node)
- return NULL;
- iwqp = cm_node->iwqp;
- return &iwqp->sc_qp;
-}
-
-/**
- * i40iw_ieq_update_tcpip_info - update tcpip in the buffer
- * @buf: puda to update
- * @length: length of buffer
- * @seqnum: seq number for tcp
- */
-void i40iw_ieq_update_tcpip_info(struct i40iw_puda_buf *buf, u16 length, u32 seqnum)
-{
- struct tcphdr *tcph;
- struct iphdr *iph;
- u16 iphlen;
- u16 packetsize;
- u8 *addr = (u8 *)buf->mem.va;
-
- iphlen = (buf->ipv4) ? 20 : 40;
- iph = (struct iphdr *)(addr + buf->maclen);
- tcph = (struct tcphdr *)(addr + buf->maclen + iphlen);
- packetsize = length + buf->tcphlen + iphlen;
-
- iph->tot_len = htons(packetsize);
- tcph->seq = htonl(seqnum);
-}
-
-/**
- * i40iw_puda_get_tcpip_info - get tcpip info from puda buffer
- * @info: to get information
- * @buf: puda buffer
- */
-enum i40iw_status_code i40iw_puda_get_tcpip_info(struct i40iw_puda_completion_info *info,
- struct i40iw_puda_buf *buf)
-{
- struct iphdr *iph;
- struct ipv6hdr *ip6h;
- struct tcphdr *tcph;
- u16 iphlen;
- u16 pkt_len;
- u8 *mem = (u8 *)buf->mem.va;
- struct ethhdr *ethh = (struct ethhdr *)buf->mem.va;
-
- if (ethh->h_proto == htons(0x8100)) {
- info->vlan_valid = true;
- buf->vlan_id = ntohs(((struct vlan_ethhdr *)ethh)->h_vlan_TCI) & VLAN_VID_MASK;
- }
- buf->maclen = (info->vlan_valid) ? 18 : 14;
- iphlen = (info->l3proto) ? 40 : 20;
- buf->ipv4 = (info->l3proto) ? false : true;
- buf->iph = mem + buf->maclen;
- iph = (struct iphdr *)buf->iph;
-
- buf->tcph = buf->iph + iphlen;
- tcph = (struct tcphdr *)buf->tcph;
-
- if (buf->ipv4) {
- pkt_len = ntohs(iph->tot_len);
- } else {
- ip6h = (struct ipv6hdr *)buf->iph;
- pkt_len = ntohs(ip6h->payload_len) + iphlen;
- }
-
- buf->totallen = pkt_len + buf->maclen;
-
- if (info->payload_len < buf->totallen) {
- i40iw_pr_err("payload_len = 0x%x totallen expected0x%x\n",
- info->payload_len, buf->totallen);
- return I40IW_ERR_INVALID_SIZE;
- }
-
- buf->tcphlen = (tcph->doff) << 2;
- buf->datalen = pkt_len - iphlen - buf->tcphlen;
- buf->data = (buf->datalen) ? buf->tcph + buf->tcphlen : NULL;
- buf->hdrlen = buf->maclen + iphlen + buf->tcphlen;
- buf->seqnum = ntohl(tcph->seq);
- return 0;
-}
-
-/**
- * i40iw_hw_stats_timeout - Stats timer-handler which updates all HW stats
- * @t: Timer context containing pointer to the vsi structure
- */
-static void i40iw_hw_stats_timeout(struct timer_list *t)
-{
- struct i40iw_vsi_pestat *pf_devstat = from_timer(pf_devstat, t,
- stats_timer);
- struct i40iw_sc_vsi *sc_vsi = pf_devstat->vsi;
- struct i40iw_sc_dev *pf_dev = sc_vsi->dev;
- struct i40iw_vsi_pestat *vf_devstat = NULL;
- u16 iw_vf_idx;
- unsigned long flags;
-
- /*PF*/
- i40iw_hw_stats_read_all(pf_devstat, &pf_devstat->hw_stats);
-
- for (iw_vf_idx = 0; iw_vf_idx < I40IW_MAX_PE_ENABLED_VF_COUNT; iw_vf_idx++) {
- spin_lock_irqsave(&pf_devstat->lock, flags);
- if (pf_dev->vf_dev[iw_vf_idx]) {
- if (pf_dev->vf_dev[iw_vf_idx]->stats_initialized) {
- vf_devstat = &pf_dev->vf_dev[iw_vf_idx]->pestat;
- i40iw_hw_stats_read_all(vf_devstat, &vf_devstat->hw_stats);
- }
- }
- spin_unlock_irqrestore(&pf_devstat->lock, flags);
- }
-
- mod_timer(&pf_devstat->stats_timer,
- jiffies + msecs_to_jiffies(STATS_TIMER_DELAY));
-}
-
-/**
- * i40iw_hw_stats_start_timer - Start periodic stats timer
- * @vsi: pointer to the vsi structure
- */
-void i40iw_hw_stats_start_timer(struct i40iw_sc_vsi *vsi)
-{
- struct i40iw_vsi_pestat *devstat = vsi->pestat;
-
- timer_setup(&devstat->stats_timer, i40iw_hw_stats_timeout, 0);
- mod_timer(&devstat->stats_timer,
- jiffies + msecs_to_jiffies(STATS_TIMER_DELAY));
-}
-
-/**
- * i40iw_hw_stats_stop_timer - Delete periodic stats timer
- * @vsi: pointer to the vsi structure
- */
-void i40iw_hw_stats_stop_timer(struct i40iw_sc_vsi *vsi)
-{
- struct i40iw_vsi_pestat *devstat = vsi->pestat;
-
- del_timer_sync(&devstat->stats_timer);
-}
diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c
deleted file mode 100644
index b876d722fcc8..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c
+++ /dev/null
@@ -1,2652 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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/time.h>
-#include <linux/hugetlb.h>
-#include <linux/irq.h>
-#include <asm/byteorder.h>
-#include <net/ip.h>
-#include <rdma/ib_verbs.h>
-#include <rdma/iw_cm.h>
-#include <rdma/ib_user_verbs.h>
-#include <rdma/ib_umem.h>
-#include <rdma/uverbs_ioctl.h>
-#include "i40iw.h"
-
-/**
- * i40iw_query_device - get device attributes
- * @ibdev: device pointer from stack
- * @props: returning device attributes
- * @udata: user data
- */
-static int i40iw_query_device(struct ib_device *ibdev,
- struct ib_device_attr *props,
- struct ib_udata *udata)
-{
- struct i40iw_device *iwdev = to_iwdev(ibdev);
-
- if (udata->inlen || udata->outlen)
- return -EINVAL;
- memset(props, 0, sizeof(*props));
- ether_addr_copy((u8 *)&props->sys_image_guid, iwdev->netdev->dev_addr);
- props->fw_ver = i40iw_fw_major_ver(&iwdev->sc_dev) << 32 |
- i40iw_fw_minor_ver(&iwdev->sc_dev);
- props->device_cap_flags = iwdev->device_cap_flags;
- props->vendor_id = iwdev->ldev->pcidev->vendor;
- props->vendor_part_id = iwdev->ldev->pcidev->device;
- props->hw_ver = (u32)iwdev->sc_dev.hw_rev;
- props->max_mr_size = I40IW_MAX_OUTBOUND_MESSAGE_SIZE;
- props->max_qp = iwdev->max_qp - iwdev->used_qps;
- props->max_qp_wr = I40IW_MAX_QP_WRS;
- props->max_send_sge = I40IW_MAX_WQ_FRAGMENT_COUNT;
- props->max_recv_sge = I40IW_MAX_WQ_FRAGMENT_COUNT;
- props->max_cq = iwdev->max_cq - iwdev->used_cqs;
- props->max_cqe = iwdev->max_cqe;
- props->max_mr = iwdev->max_mr - iwdev->used_mrs;
- props->max_pd = iwdev->max_pd - iwdev->used_pds;
- props->max_sge_rd = I40IW_MAX_SGE_RD;
- props->max_qp_rd_atom = I40IW_MAX_IRD_SIZE;
- props->max_qp_init_rd_atom = props->max_qp_rd_atom;
- props->atomic_cap = IB_ATOMIC_NONE;
- props->max_fast_reg_page_list_len = I40IW_MAX_PAGES_PER_FMR;
- return 0;
-}
-
-/**
- * i40iw_query_port - get port attrubutes
- * @ibdev: device pointer from stack
- * @port: port number for query
- * @props: returning device attributes
- */
-static int i40iw_query_port(struct ib_device *ibdev,
- u32 port,
- struct ib_port_attr *props)
-{
- props->lid = 1;
- 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->active_width = IB_WIDTH_4X;
- props->active_speed = 1;
- props->max_msg_sz = I40IW_MAX_OUTBOUND_MESSAGE_SIZE;
- return 0;
-}
-
-/**
- * i40iw_alloc_ucontext - Allocate the user context data structure
- * @uctx: Uverbs context pointer from stack
- * @udata: user data
- *
- * This keeps track of all objects associated with a particular
- * user-mode client.
- */
-static int i40iw_alloc_ucontext(struct ib_ucontext *uctx,
- struct ib_udata *udata)
-{
- struct ib_device *ibdev = uctx->device;
- struct i40iw_device *iwdev = to_iwdev(ibdev);
- struct i40iw_alloc_ucontext_req req;
- struct i40iw_alloc_ucontext_resp uresp = {};
- struct i40iw_ucontext *ucontext = to_ucontext(uctx);
-
- if (ib_copy_from_udata(&req, udata, sizeof(req)))
- return -EINVAL;
-
- if (req.userspace_ver < 4 || req.userspace_ver > I40IW_ABI_VER) {
- i40iw_pr_err("Unsupported provider library version %u.\n", req.userspace_ver);
- return -EINVAL;
- }
-
- uresp.max_qps = iwdev->max_qp;
- uresp.max_pds = iwdev->max_pd;
- uresp.wq_size = iwdev->max_qp_wr * 2;
- uresp.kernel_ver = req.userspace_ver;
-
- ucontext->iwdev = iwdev;
- ucontext->abi_ver = req.userspace_ver;
-
- if (ib_copy_to_udata(udata, &uresp, sizeof(uresp)))
- return -EFAULT;
-
- INIT_LIST_HEAD(&ucontext->cq_reg_mem_list);
- spin_lock_init(&ucontext->cq_reg_mem_list_lock);
- INIT_LIST_HEAD(&ucontext->qp_reg_mem_list);
- spin_lock_init(&ucontext->qp_reg_mem_list_lock);
-
- return 0;
-}
-
-/**
- * i40iw_dealloc_ucontext - deallocate the user context data structure
- * @context: user context created during alloc
- */
-static void i40iw_dealloc_ucontext(struct ib_ucontext *context)
-{
- return;
-}
-
-/**
- * i40iw_mmap - user memory map
- * @context: context created during alloc
- * @vma: kernel info for user memory map
- */
-static int i40iw_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
-{
- struct i40iw_ucontext *ucontext = to_ucontext(context);
- u64 dbaddr;
-
- if (vma->vm_pgoff || vma->vm_end - vma->vm_start != PAGE_SIZE)
- return -EINVAL;
-
- dbaddr = I40IW_DB_ADDR_OFFSET + pci_resource_start(ucontext->iwdev->ldev->pcidev, 0);
-
- return rdma_user_mmap_io(context, vma, dbaddr >> PAGE_SHIFT, PAGE_SIZE,
- pgprot_noncached(vma->vm_page_prot), NULL);
-}
-
-/**
- * i40iw_alloc_pd - allocate protection domain
- * @pd: PD pointer
- * @udata: user data
- */
-static int i40iw_alloc_pd(struct ib_pd *pd, struct ib_udata *udata)
-{
- struct i40iw_pd *iwpd = to_iwpd(pd);
- struct i40iw_device *iwdev = to_iwdev(pd->device);
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_alloc_pd_resp uresp;
- struct i40iw_sc_pd *sc_pd;
- u32 pd_id = 0;
- int err;
-
- if (iwdev->closing)
- return -ENODEV;
-
- err = i40iw_alloc_resource(iwdev, iwdev->allocated_pds,
- iwdev->max_pd, &pd_id, &iwdev->next_pd);
- if (err) {
- i40iw_pr_err("alloc resource failed\n");
- return err;
- }
-
- sc_pd = &iwpd->sc_pd;
-
- if (udata) {
- struct i40iw_ucontext *ucontext = rdma_udata_to_drv_context(
- udata, struct i40iw_ucontext, ibucontext);
- dev->iw_pd_ops->pd_init(dev, sc_pd, pd_id, ucontext->abi_ver);
- memset(&uresp, 0, sizeof(uresp));
- uresp.pd_id = pd_id;
- if (ib_copy_to_udata(udata, &uresp, sizeof(uresp))) {
- err = -EFAULT;
- goto error;
- }
- } else {
- dev->iw_pd_ops->pd_init(dev, sc_pd, pd_id, -1);
- }
-
- i40iw_add_pdusecount(iwpd);
- return 0;
-
-error:
- i40iw_free_resource(iwdev, iwdev->allocated_pds, pd_id);
- return err;
-}
-
-/**
- * i40iw_dealloc_pd - deallocate pd
- * @ibpd: ptr of pd to be deallocated
- * @udata: user data or null for kernel object
- */
-static int i40iw_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
-{
- struct i40iw_pd *iwpd = to_iwpd(ibpd);
- struct i40iw_device *iwdev = to_iwdev(ibpd->device);
-
- i40iw_rem_pdusecount(iwpd, iwdev);
- return 0;
-}
-
-/**
- * i40iw_get_pbl - Retrieve pbl from a list given a virtual
- * address
- * @va: user virtual address
- * @pbl_list: pbl list to search in (QP's or CQ's)
- */
-static struct i40iw_pbl *i40iw_get_pbl(unsigned long va,
- struct list_head *pbl_list)
-{
- struct i40iw_pbl *iwpbl;
-
- list_for_each_entry(iwpbl, pbl_list, list) {
- if (iwpbl->user_base == va) {
- iwpbl->on_list = false;
- list_del(&iwpbl->list);
- return iwpbl;
- }
- }
- return NULL;
-}
-
-/**
- * i40iw_free_qp_resources - free up memory resources for qp
- * @iwqp: qp ptr (user or kernel)
- */
-void i40iw_free_qp_resources(struct i40iw_qp *iwqp)
-{
- struct i40iw_pbl *iwpbl = &iwqp->iwpbl;
- struct i40iw_device *iwdev = iwqp->iwdev;
- u32 qp_num = iwqp->ibqp.qp_num;
-
- i40iw_ieq_cleanup_qp(iwdev->vsi.ieq, &iwqp->sc_qp);
- if (qp_num)
- i40iw_free_resource(iwdev, iwdev->allocated_qps, qp_num);
- if (iwpbl->pbl_allocated)
- i40iw_free_pble(iwdev->pble_rsrc, &iwpbl->pble_alloc);
- i40iw_free_dma_mem(iwdev->sc_dev.hw, &iwqp->q2_ctx_mem);
- i40iw_free_dma_mem(iwdev->sc_dev.hw, &iwqp->kqp.dma_mem);
- kfree(iwqp->kqp.wrid_mem);
- iwqp->kqp.wrid_mem = NULL;
- kfree(iwqp);
-}
-
-/**
- * i40iw_clean_cqes - clean cq entries for qp
- * @iwqp: qp ptr (user or kernel)
- * @iwcq: cq ptr
- */
-static void i40iw_clean_cqes(struct i40iw_qp *iwqp, struct i40iw_cq *iwcq)
-{
- struct i40iw_cq_uk *ukcq = &iwcq->sc_cq.cq_uk;
-
- ukcq->ops.iw_cq_clean(&iwqp->sc_qp.qp_uk, ukcq);
-}
-
-/**
- * i40iw_destroy_qp - destroy qp
- * @ibqp: qp's ib pointer also to get to device's qp address
- * @udata: user data
- */
-static int i40iw_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
-{
- struct i40iw_qp *iwqp = to_iwqp(ibqp);
- struct ib_qp_attr attr;
- struct i40iw_device *iwdev = iwqp->iwdev;
-
- memset(&attr, 0, sizeof(attr));
-
- iwqp->destroyed = 1;
-
- if (iwqp->ibqp_state >= IB_QPS_INIT && iwqp->ibqp_state < IB_QPS_RTS)
- i40iw_next_iw_state(iwqp, I40IW_QP_STATE_ERROR, 0, 0, 0);
-
- if (!iwqp->user_mode) {
- if (iwqp->iwscq) {
- i40iw_clean_cqes(iwqp, iwqp->iwscq);
- if (iwqp->iwrcq != iwqp->iwscq)
- i40iw_clean_cqes(iwqp, iwqp->iwrcq);
- }
- }
-
- attr.qp_state = IB_QPS_ERR;
- i40iw_modify_qp(&iwqp->ibqp, &attr, IB_QP_STATE, NULL);
- i40iw_qp_rem_ref(&iwqp->ibqp);
- wait_for_completion(&iwqp->free_qp);
- i40iw_cqp_qp_destroy_cmd(&iwdev->sc_dev, &iwqp->sc_qp);
- i40iw_rem_pdusecount(iwqp->iwpd, iwdev);
- i40iw_free_qp_resources(iwqp);
- i40iw_rem_devusecount(iwdev);
-
- return 0;
-}
-
-/**
- * i40iw_setup_virt_qp - setup for allocation of virtual qp
- * @iwdev: iwarp device
- * @iwqp: qp ptr
- * @init_info: initialize info to return
- */
-static int i40iw_setup_virt_qp(struct i40iw_device *iwdev,
- struct i40iw_qp *iwqp,
- struct i40iw_qp_init_info *init_info)
-{
- struct i40iw_pbl *iwpbl = &iwqp->iwpbl;
- struct i40iw_qp_mr *qpmr = &iwpbl->qp_mr;
-
- iwqp->page = qpmr->sq_page;
- init_info->shadow_area_pa = cpu_to_le64(qpmr->shadow);
- if (iwpbl->pbl_allocated) {
- init_info->virtual_map = true;
- init_info->sq_pa = qpmr->sq_pbl.idx;
- init_info->rq_pa = qpmr->rq_pbl.idx;
- } else {
- init_info->sq_pa = qpmr->sq_pbl.addr;
- init_info->rq_pa = qpmr->rq_pbl.addr;
- }
- return 0;
-}
-
-/**
- * i40iw_setup_kmode_qp - setup initialization for kernel mode qp
- * @iwdev: iwarp device
- * @iwqp: qp ptr (user or kernel)
- * @info: initialize info to return
- */
-static int i40iw_setup_kmode_qp(struct i40iw_device *iwdev,
- struct i40iw_qp *iwqp,
- struct i40iw_qp_init_info *info)
-{
- struct i40iw_dma_mem *mem = &iwqp->kqp.dma_mem;
- u32 sqdepth, rqdepth;
- u8 sqshift;
- u32 size;
- enum i40iw_status_code status;
- struct i40iw_qp_uk_init_info *ukinfo = &info->qp_uk_init_info;
-
- i40iw_get_wqe_shift(ukinfo->max_sq_frag_cnt, ukinfo->max_inline_data, &sqshift);
- status = i40iw_get_sqdepth(ukinfo->sq_size, sqshift, &sqdepth);
- if (status)
- return -ENOMEM;
-
- status = i40iw_get_rqdepth(ukinfo->rq_size, I40IW_MAX_RQ_WQE_SHIFT, &rqdepth);
- if (status)
- return -ENOMEM;
-
- size = sqdepth * sizeof(struct i40iw_sq_uk_wr_trk_info) + (rqdepth << 3);
- iwqp->kqp.wrid_mem = kzalloc(size, GFP_KERNEL);
-
- ukinfo->sq_wrtrk_array = (struct i40iw_sq_uk_wr_trk_info *)iwqp->kqp.wrid_mem;
- if (!ukinfo->sq_wrtrk_array)
- return -ENOMEM;
-
- ukinfo->rq_wrid_array = (u64 *)&ukinfo->sq_wrtrk_array[sqdepth];
-
- size = (sqdepth + rqdepth) * I40IW_QP_WQE_MIN_SIZE;
- size += (I40IW_SHADOW_AREA_SIZE << 3);
-
- status = i40iw_allocate_dma_mem(iwdev->sc_dev.hw, mem, size, 256);
- if (status) {
- kfree(ukinfo->sq_wrtrk_array);
- ukinfo->sq_wrtrk_array = NULL;
- return -ENOMEM;
- }
-
- ukinfo->sq = mem->va;
- info->sq_pa = mem->pa;
-
- ukinfo->rq = &ukinfo->sq[sqdepth];
- info->rq_pa = info->sq_pa + (sqdepth * I40IW_QP_WQE_MIN_SIZE);
-
- ukinfo->shadow_area = ukinfo->rq[rqdepth].elem;
- info->shadow_area_pa = info->rq_pa + (rqdepth * I40IW_QP_WQE_MIN_SIZE);
-
- ukinfo->sq_size = sqdepth >> sqshift;
- ukinfo->rq_size = rqdepth >> I40IW_MAX_RQ_WQE_SHIFT;
- ukinfo->qp_id = iwqp->ibqp.qp_num;
- return 0;
-}
-
-/**
- * i40iw_create_qp - create qp
- * @ibpd: ptr of pd
- * @init_attr: attributes for qp
- * @udata: user data for create qp
- */
-static struct ib_qp *i40iw_create_qp(struct ib_pd *ibpd,
- struct ib_qp_init_attr *init_attr,
- struct ib_udata *udata)
-{
- struct i40iw_pd *iwpd = to_iwpd(ibpd);
- struct i40iw_device *iwdev = to_iwdev(ibpd->device);
- struct i40iw_cqp *iwcqp = &iwdev->cqp;
- struct i40iw_qp *iwqp;
- struct i40iw_ucontext *ucontext = rdma_udata_to_drv_context(
- udata, struct i40iw_ucontext, ibucontext);
- struct i40iw_create_qp_req req;
- struct i40iw_create_qp_resp uresp;
- u32 qp_num = 0;
- enum i40iw_status_code ret;
- int err_code;
- int sq_size;
- int rq_size;
- struct i40iw_sc_qp *qp;
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_qp_init_info init_info;
- struct i40iw_create_qp_info *qp_info;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
-
- struct i40iw_qp_host_ctx_info *ctx_info;
- struct i40iwarp_offload_info *iwarp_info;
- unsigned long flags;
-
- if (iwdev->closing)
- return ERR_PTR(-ENODEV);
-
- if (init_attr->create_flags)
- return ERR_PTR(-EOPNOTSUPP);
- if (init_attr->cap.max_inline_data > I40IW_MAX_INLINE_DATA_SIZE)
- init_attr->cap.max_inline_data = I40IW_MAX_INLINE_DATA_SIZE;
-
- if (init_attr->cap.max_send_sge > I40IW_MAX_WQ_FRAGMENT_COUNT)
- init_attr->cap.max_send_sge = I40IW_MAX_WQ_FRAGMENT_COUNT;
-
- if (init_attr->cap.max_recv_sge > I40IW_MAX_WQ_FRAGMENT_COUNT)
- init_attr->cap.max_recv_sge = I40IW_MAX_WQ_FRAGMENT_COUNT;
-
- memset(&init_info, 0, sizeof(init_info));
-
- sq_size = init_attr->cap.max_send_wr;
- rq_size = init_attr->cap.max_recv_wr;
-
- init_info.vsi = &iwdev->vsi;
- init_info.qp_uk_init_info.sq_size = sq_size;
- init_info.qp_uk_init_info.rq_size = rq_size;
- init_info.qp_uk_init_info.max_sq_frag_cnt = init_attr->cap.max_send_sge;
- init_info.qp_uk_init_info.max_rq_frag_cnt = init_attr->cap.max_recv_sge;
- init_info.qp_uk_init_info.max_inline_data = init_attr->cap.max_inline_data;
-
- iwqp = kzalloc(sizeof(*iwqp), GFP_KERNEL);
- if (!iwqp)
- return ERR_PTR(-ENOMEM);
-
- qp = &iwqp->sc_qp;
- qp->back_qp = (void *)iwqp;
- iwqp->iwdev = iwdev;
- iwqp->ctx_info.iwarp_info = &iwqp->iwarp_info;
-
- if (i40iw_allocate_dma_mem(dev->hw,
- &iwqp->q2_ctx_mem,
- I40IW_Q2_BUFFER_SIZE + I40IW_QP_CTX_SIZE,
- 256)) {
- i40iw_pr_err("dma_mem failed\n");
- err_code = -ENOMEM;
- goto error;
- }
-
- init_info.q2 = iwqp->q2_ctx_mem.va;
- init_info.q2_pa = iwqp->q2_ctx_mem.pa;
-
- init_info.host_ctx = (void *)init_info.q2 + I40IW_Q2_BUFFER_SIZE;
- init_info.host_ctx_pa = init_info.q2_pa + I40IW_Q2_BUFFER_SIZE;
-
- err_code = i40iw_alloc_resource(iwdev, iwdev->allocated_qps, iwdev->max_qp,
- &qp_num, &iwdev->next_qp);
- if (err_code) {
- i40iw_pr_err("qp resource\n");
- goto error;
- }
-
- iwqp->iwpd = iwpd;
- iwqp->ibqp.qp_num = qp_num;
- qp = &iwqp->sc_qp;
- iwqp->iwscq = to_iwcq(init_attr->send_cq);
- iwqp->iwrcq = to_iwcq(init_attr->recv_cq);
-
- iwqp->host_ctx.va = init_info.host_ctx;
- iwqp->host_ctx.pa = init_info.host_ctx_pa;
- iwqp->host_ctx.size = I40IW_QP_CTX_SIZE;
-
- init_info.pd = &iwpd->sc_pd;
- init_info.qp_uk_init_info.qp_id = iwqp->ibqp.qp_num;
- iwqp->ctx_info.qp_compl_ctx = (uintptr_t)qp;
-
- if (init_attr->qp_type != IB_QPT_RC) {
- err_code = -EOPNOTSUPP;
- goto error;
- }
- if (udata) {
- err_code = ib_copy_from_udata(&req, udata, sizeof(req));
- if (err_code) {
- i40iw_pr_err("ib_copy_from_data\n");
- goto error;
- }
- iwqp->ctx_info.qp_compl_ctx = req.user_compl_ctx;
- iwqp->user_mode = 1;
-
- if (req.user_wqe_buffers) {
- struct i40iw_pbl *iwpbl;
-
- spin_lock_irqsave(
- &ucontext->qp_reg_mem_list_lock, flags);
- iwpbl = i40iw_get_pbl(
- (unsigned long)req.user_wqe_buffers,
- &ucontext->qp_reg_mem_list);
- spin_unlock_irqrestore(
- &ucontext->qp_reg_mem_list_lock, flags);
-
- if (!iwpbl) {
- err_code = -ENODATA;
- i40iw_pr_err("no pbl info\n");
- goto error;
- }
- memcpy(&iwqp->iwpbl, iwpbl, sizeof(iwqp->iwpbl));
- }
- err_code = i40iw_setup_virt_qp(iwdev, iwqp, &init_info);
- } else {
- err_code = i40iw_setup_kmode_qp(iwdev, iwqp, &init_info);
- }
-
- if (err_code) {
- i40iw_pr_err("setup qp failed\n");
- goto error;
- }
-
- init_info.type = I40IW_QP_TYPE_IWARP;
- ret = dev->iw_priv_qp_ops->qp_init(qp, &init_info);
- if (ret) {
- err_code = -EPROTO;
- i40iw_pr_err("qp_init fail\n");
- goto error;
- }
- ctx_info = &iwqp->ctx_info;
- iwarp_info = &iwqp->iwarp_info;
- iwarp_info->rd_enable = true;
- iwarp_info->wr_rdresp_en = true;
- if (!iwqp->user_mode) {
- iwarp_info->fast_reg_en = true;
- iwarp_info->priv_mode_en = true;
- }
- iwarp_info->ddp_ver = 1;
- iwarp_info->rdmap_ver = 1;
-
- ctx_info->iwarp_info_valid = true;
- ctx_info->send_cq_num = iwqp->iwscq->sc_cq.cq_uk.cq_id;
- ctx_info->rcv_cq_num = iwqp->iwrcq->sc_cq.cq_uk.cq_id;
- ret = dev->iw_priv_qp_ops->qp_setctx(&iwqp->sc_qp,
- (u64 *)iwqp->host_ctx.va,
- ctx_info);
- ctx_info->iwarp_info_valid = false;
- cqp_request = i40iw_get_cqp_request(iwcqp, true);
- if (!cqp_request) {
- err_code = -ENOMEM;
- goto error;
- }
- cqp_info = &cqp_request->info;
- qp_info = &cqp_request->info.in.u.qp_create.info;
-
- memset(qp_info, 0, sizeof(*qp_info));
-
- qp_info->cq_num_valid = true;
- qp_info->next_iwarp_state = I40IW_QP_STATE_IDLE;
-
- cqp_info->cqp_cmd = OP_QP_CREATE;
- cqp_info->post_sq = 1;
- cqp_info->in.u.qp_create.qp = qp;
- cqp_info->in.u.qp_create.scratch = (uintptr_t)cqp_request;
- ret = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (ret) {
- i40iw_pr_err("CQP-OP QP create fail");
- err_code = -EACCES;
- goto error;
- }
-
- refcount_set(&iwqp->refcount, 1);
- spin_lock_init(&iwqp->lock);
- iwqp->sig_all = (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) ? 1 : 0;
- iwdev->qp_table[qp_num] = iwqp;
- i40iw_add_pdusecount(iwqp->iwpd);
- i40iw_add_devusecount(iwdev);
- if (udata) {
- memset(&uresp, 0, sizeof(uresp));
- uresp.actual_sq_size = sq_size;
- uresp.actual_rq_size = rq_size;
- uresp.qp_id = qp_num;
- uresp.push_idx = I40IW_INVALID_PUSH_PAGE_INDEX;
- err_code = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
- if (err_code) {
- i40iw_pr_err("copy_to_udata failed\n");
- i40iw_destroy_qp(&iwqp->ibqp, udata);
- /* let the completion of the qp destroy free the qp */
- return ERR_PTR(err_code);
- }
- }
- init_completion(&iwqp->sq_drained);
- init_completion(&iwqp->rq_drained);
- init_completion(&iwqp->free_qp);
-
- return &iwqp->ibqp;
-error:
- i40iw_free_qp_resources(iwqp);
- return ERR_PTR(err_code);
-}
-
-/**
- * i40iw_query_qp - query qp attributes
- * @ibqp: qp pointer
- * @attr: attributes pointer
- * @attr_mask: Not used
- * @init_attr: qp attributes to return
- */
-static int i40iw_query_qp(struct ib_qp *ibqp,
- struct ib_qp_attr *attr,
- int attr_mask,
- struct ib_qp_init_attr *init_attr)
-{
- 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;
- attr->cap.max_inline_data = I40IW_MAX_INLINE_DATA_SIZE;
- attr->cap.max_send_sge = I40IW_MAX_WQ_FRAGMENT_COUNT;
- attr->cap.max_recv_sge = I40IW_MAX_WQ_FRAGMENT_COUNT;
- attr->port_num = 1;
- init_attr->event_handler = iwqp->ibqp.event_handler;
- init_attr->qp_context = iwqp->ibqp.qp_context;
- init_attr->send_cq = iwqp->ibqp.send_cq;
- init_attr->recv_cq = iwqp->ibqp.recv_cq;
- init_attr->srq = iwqp->ibqp.srq;
- init_attr->cap = attr->cap;
- init_attr->port_num = 1;
- return 0;
-}
-
-/**
- * i40iw_hw_modify_qp - setup cqp for modify qp
- * @iwdev: iwarp device
- * @iwqp: qp ptr (user or kernel)
- * @info: info for modify qp
- * @wait: flag to wait or not for modify qp completion
- */
-void i40iw_hw_modify_qp(struct i40iw_device *iwdev, struct i40iw_qp *iwqp,
- struct i40iw_modify_qp_info *info, bool wait)
-{
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- struct i40iw_modify_qp_info *m_info;
- struct i40iw_gen_ae_info ae_info;
-
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, wait);
- if (!cqp_request)
- return;
-
- cqp_info = &cqp_request->info;
- m_info = &cqp_info->in.u.qp_modify.info;
- memcpy(m_info, info, sizeof(*m_info));
- cqp_info->cqp_cmd = OP_QP_MODIFY;
- cqp_info->post_sq = 1;
- cqp_info->in.u.qp_modify.qp = &iwqp->sc_qp;
- cqp_info->in.u.qp_modify.scratch = (uintptr_t)cqp_request;
- if (!i40iw_handle_cqp_op(iwdev, cqp_request))
- return;
-
- switch (m_info->next_iwarp_state) {
- case I40IW_QP_STATE_RTS:
- if (iwqp->iwarp_state == I40IW_QP_STATE_IDLE)
- i40iw_send_reset(iwqp->cm_node);
- fallthrough;
- case I40IW_QP_STATE_IDLE:
- case I40IW_QP_STATE_TERMINATE:
- case I40IW_QP_STATE_CLOSING:
- ae_info.ae_code = I40IW_AE_BAD_CLOSE;
- ae_info.ae_source = 0;
- i40iw_gen_ae(iwdev, &iwqp->sc_qp, &ae_info, false);
- break;
- case I40IW_QP_STATE_ERROR:
- default:
- break;
- }
-}
-
-/**
- * i40iw_modify_qp - modify qp request
- * @ibqp: qp's pointer for modify
- * @attr: access attributes
- * @attr_mask: state mask
- * @udata: user data
- */
-int i40iw_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
- int attr_mask, struct ib_udata *udata)
-{
- struct i40iw_qp *iwqp = to_iwqp(ibqp);
- struct i40iw_device *iwdev = iwqp->iwdev;
- struct i40iw_qp_host_ctx_info *ctx_info;
- struct i40iwarp_offload_info *iwarp_info;
- struct i40iw_modify_qp_info info;
- u8 issue_modify_qp = 0;
- u8 dont_wait = 0;
- u32 err;
- unsigned long flags;
-
- if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
- return -EOPNOTSUPP;
-
- memset(&info, 0, sizeof(info));
- ctx_info = &iwqp->ctx_info;
- iwarp_info = &iwqp->iwarp_info;
-
- spin_lock_irqsave(&iwqp->lock, flags);
-
- if (attr_mask & IB_QP_STATE) {
- if (iwdev->closing && attr->qp_state != IB_QPS_ERR) {
- err = -EINVAL;
- goto exit;
- }
-
- switch (attr->qp_state) {
- case IB_QPS_INIT:
- case IB_QPS_RTR:
- if (iwqp->iwarp_state > (u32)I40IW_QP_STATE_IDLE) {
- err = -EINVAL;
- goto exit;
- }
- if (iwqp->iwarp_state == I40IW_QP_STATE_INVALID) {
- info.next_iwarp_state = I40IW_QP_STATE_IDLE;
- issue_modify_qp = 1;
- }
- break;
- case IB_QPS_RTS:
- if ((iwqp->iwarp_state > (u32)I40IW_QP_STATE_RTS) ||
- (!iwqp->cm_id)) {
- err = -EINVAL;
- goto exit;
- }
-
- issue_modify_qp = 1;
- iwqp->hw_tcp_state = I40IW_TCP_STATE_ESTABLISHED;
- iwqp->hte_added = 1;
- info.next_iwarp_state = I40IW_QP_STATE_RTS;
- info.tcp_ctx_valid = true;
- info.ord_valid = true;
- info.arp_cache_idx_valid = true;
- info.cq_num_valid = true;
- break;
- case IB_QPS_SQD:
- if (iwqp->hw_iwarp_state > (u32)I40IW_QP_STATE_RTS) {
- err = 0;
- goto exit;
- }
- if ((iwqp->iwarp_state == (u32)I40IW_QP_STATE_CLOSING) ||
- (iwqp->iwarp_state < (u32)I40IW_QP_STATE_RTS)) {
- err = 0;
- goto exit;
- }
- if (iwqp->iwarp_state > (u32)I40IW_QP_STATE_CLOSING) {
- err = -EINVAL;
- goto exit;
- }
- info.next_iwarp_state = I40IW_QP_STATE_CLOSING;
- issue_modify_qp = 1;
- break;
- case IB_QPS_SQE:
- if (iwqp->iwarp_state >= (u32)I40IW_QP_STATE_TERMINATE) {
- err = -EINVAL;
- goto exit;
- }
- info.next_iwarp_state = I40IW_QP_STATE_TERMINATE;
- issue_modify_qp = 1;
- break;
- case IB_QPS_ERR:
- case IB_QPS_RESET:
- if (iwqp->iwarp_state == (u32)I40IW_QP_STATE_ERROR) {
- err = -EINVAL;
- goto exit;
- }
- if (iwqp->sc_qp.term_flags)
- i40iw_terminate_del_timer(&iwqp->sc_qp);
- info.next_iwarp_state = I40IW_QP_STATE_ERROR;
- if ((iwqp->hw_tcp_state > I40IW_TCP_STATE_CLOSED) &&
- iwdev->iw_status &&
- (iwqp->hw_tcp_state != I40IW_TCP_STATE_TIME_WAIT))
- info.reset_tcp_conn = true;
- else
- dont_wait = 1;
- issue_modify_qp = 1;
- info.next_iwarp_state = I40IW_QP_STATE_ERROR;
- break;
- default:
- err = -EINVAL;
- goto exit;
- }
-
- iwqp->ibqp_state = attr->qp_state;
-
- }
- if (attr_mask & IB_QP_ACCESS_FLAGS) {
- ctx_info->iwarp_info_valid = true;
- if (attr->qp_access_flags & IB_ACCESS_LOCAL_WRITE)
- iwarp_info->wr_rdresp_en = true;
- if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE)
- iwarp_info->wr_rdresp_en = true;
- if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ)
- iwarp_info->rd_enable = true;
- if (attr->qp_access_flags & IB_ACCESS_MW_BIND)
- iwarp_info->bind_en = true;
-
- if (iwqp->user_mode) {
- iwarp_info->rd_enable = true;
- iwarp_info->wr_rdresp_en = true;
- iwarp_info->priv_mode_en = false;
- }
- }
-
- if (ctx_info->iwarp_info_valid) {
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- int ret;
-
- ctx_info->send_cq_num = iwqp->iwscq->sc_cq.cq_uk.cq_id;
- ctx_info->rcv_cq_num = iwqp->iwrcq->sc_cq.cq_uk.cq_id;
- ret = dev->iw_priv_qp_ops->qp_setctx(&iwqp->sc_qp,
- (u64 *)iwqp->host_ctx.va,
- ctx_info);
- if (ret) {
- i40iw_pr_err("setting QP context\n");
- err = -EINVAL;
- goto exit;
- }
- }
-
- spin_unlock_irqrestore(&iwqp->lock, flags);
-
- if (issue_modify_qp) {
- i40iw_hw_modify_qp(iwdev, iwqp, &info, true);
-
- spin_lock_irqsave(&iwqp->lock, flags);
- iwqp->iwarp_state = info.next_iwarp_state;
- spin_unlock_irqrestore(&iwqp->lock, flags);
- }
-
- if (issue_modify_qp && (iwqp->ibqp_state > IB_QPS_RTS)) {
- if (dont_wait) {
- if (iwqp->cm_id && iwqp->hw_tcp_state) {
- spin_lock_irqsave(&iwqp->lock, flags);
- iwqp->hw_tcp_state = I40IW_TCP_STATE_CLOSED;
- iwqp->last_aeq = I40IW_AE_RESET_SENT;
- spin_unlock_irqrestore(&iwqp->lock, flags);
- i40iw_cm_disconn(iwqp);
- }
- } else {
- spin_lock_irqsave(&iwqp->lock, flags);
- if (iwqp->cm_id) {
- if (atomic_inc_return(&iwqp->close_timer_started) == 1) {
- iwqp->cm_id->add_ref(iwqp->cm_id);
- i40iw_schedule_cm_timer(iwqp->cm_node,
- (struct i40iw_puda_buf *)iwqp,
- I40IW_TIMER_TYPE_CLOSE, 1, 0);
- }
- }
- spin_unlock_irqrestore(&iwqp->lock, flags);
- }
- }
- return 0;
-exit:
- spin_unlock_irqrestore(&iwqp->lock, flags);
- return err;
-}
-
-/**
- * cq_free_resources - free up recources for cq
- * @iwdev: iwarp device
- * @iwcq: cq ptr
- */
-static void cq_free_resources(struct i40iw_device *iwdev, struct i40iw_cq *iwcq)
-{
- struct i40iw_sc_cq *cq = &iwcq->sc_cq;
-
- if (!iwcq->user_mode)
- i40iw_free_dma_mem(iwdev->sc_dev.hw, &iwcq->kmem);
- i40iw_free_resource(iwdev, iwdev->allocated_cqs, cq->cq_uk.cq_id);
-}
-
-/**
- * i40iw_cq_wq_destroy - send cq destroy cqp
- * @iwdev: iwarp device
- * @cq: hardware control cq
- */
-void i40iw_cq_wq_destroy(struct i40iw_device *iwdev, struct i40iw_sc_cq *cq)
-{
- enum i40iw_status_code status;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
-
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, true);
- if (!cqp_request)
- return;
-
- cqp_info = &cqp_request->info;
-
- cqp_info->cqp_cmd = OP_CQ_DESTROY;
- cqp_info->post_sq = 1;
- cqp_info->in.u.cq_destroy.cq = cq;
- cqp_info->in.u.cq_destroy.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP-OP Destroy QP fail");
-}
-
-/**
- * i40iw_destroy_cq - destroy 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)
-{
- struct i40iw_cq *iwcq;
- struct i40iw_device *iwdev;
- struct i40iw_sc_cq *cq;
-
- 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);
- i40iw_rem_devusecount(iwdev);
- return 0;
-}
-
-/**
- * i40iw_create_cq - create cq
- * @ibcq: CQ allocated
- * @attr: attributes for cq
- * @udata: user data
- */
-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 = 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 = {};
- enum i40iw_status_code status;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- struct i40iw_cq_uk_init_info *ukinfo = &info.cq_uk_init_info;
- unsigned long flags;
- int err_code;
- int entries = attr->cqe;
-
- if (attr->flags)
- return -EOPNOTSUPP;
-
- if (iwdev->closing)
- return -ENODEV;
-
- if (entries > iwdev->max_cqe)
- return -EINVAL;
-
- err_code = i40iw_alloc_resource(iwdev, iwdev->allocated_cqs,
- iwdev->max_cq, &cq_num,
- &iwdev->next_cq);
- if (err_code)
- return err_code;
-
- cq = &iwcq->sc_cq;
- cq->back_cq = (void *)iwcq;
- spin_lock_init(&iwcq->lock);
-
- info.dev = dev;
- ukinfo->cq_size = max(entries, 4);
- ukinfo->cq_id = cq_num;
- iwcq->ibcq.cqe = info.cq_uk_init_info.cq_size;
- info.ceqe_mask = 0;
- if (attr->comp_vector < iwdev->ceqs_count)
- info.ceq_id = attr->comp_vector;
- info.ceq_id_valid = true;
- info.ceqe_mask = 1;
- info.type = I40IW_CQ_TYPE_IWARP;
- if (udata) {
- struct i40iw_ucontext *ucontext = rdma_udata_to_drv_context(
- udata, struct i40iw_ucontext, ibucontext);
- struct i40iw_create_cq_req req;
- struct i40iw_cq_mr *cqmr;
-
- memset(&req, 0, sizeof(req));
- iwcq->user_mode = true;
- if (ib_copy_from_udata(&req, udata, sizeof(struct i40iw_create_cq_req))) {
- err_code = -EFAULT;
- goto cq_free_resources;
- }
-
- spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
- iwpbl = i40iw_get_pbl((unsigned long)req.user_cq_buffer,
- &ucontext->cq_reg_mem_list);
- spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
- if (!iwpbl) {
- err_code = -EPROTO;
- goto cq_free_resources;
- }
-
- iwcq->iwpbl = iwpbl;
- iwcq->cq_mem_size = 0;
- cqmr = &iwpbl->cq_mr;
- info.shadow_area_pa = cpu_to_le64(cqmr->shadow);
- if (iwpbl->pbl_allocated) {
- info.virtual_map = true;
- info.pbl_chunk_size = 1;
- info.first_pm_pbl_idx = cqmr->cq_pbl.idx;
- } else {
- info.cq_base_pa = cqmr->cq_pbl.addr;
- }
- } else {
- /* Kmode allocations */
- int rsize;
- int shadow;
-
- rsize = info.cq_uk_init_info.cq_size * sizeof(struct i40iw_cqe);
- rsize = round_up(rsize, 256);
- shadow = I40IW_SHADOW_AREA_SIZE << 3;
- status = i40iw_allocate_dma_mem(dev->hw, &iwcq->kmem,
- rsize + shadow, 256);
- if (status) {
- err_code = -ENOMEM;
- goto cq_free_resources;
- }
- ukinfo->cq_base = iwcq->kmem.va;
- info.cq_base_pa = iwcq->kmem.pa;
- info.shadow_area_pa = info.cq_base_pa + rsize;
- ukinfo->shadow_area = iwcq->kmem.va + rsize;
- }
-
- if (dev->iw_priv_cq_ops->cq_init(cq, &info)) {
- i40iw_pr_err("init cq fail\n");
- err_code = -EPROTO;
- goto cq_free_resources;
- }
-
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, true);
- if (!cqp_request) {
- err_code = -ENOMEM;
- goto cq_free_resources;
- }
-
- cqp_info = &cqp_request->info;
- cqp_info->cqp_cmd = OP_CQ_CREATE;
- cqp_info->post_sq = 1;
- cqp_info->in.u.cq_create.cq = cq;
- cqp_info->in.u.cq_create.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status) {
- i40iw_pr_err("CQP-OP Create QP fail");
- err_code = -EPROTO;
- goto cq_free_resources;
- }
-
- if (udata) {
- struct i40iw_create_cq_resp resp;
-
- memset(&resp, 0, sizeof(resp));
- resp.cq_id = info.cq_uk_init_info.cq_id;
- resp.cq_size = info.cq_uk_init_info.cq_size;
- if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
- i40iw_pr_err("copy to user data\n");
- err_code = -EPROTO;
- goto cq_destroy;
- }
- }
-
- i40iw_add_devusecount(iwdev);
- return 0;
-
-cq_destroy:
- i40iw_cq_wq_destroy(iwdev, cq);
-cq_free_resources:
- cq_free_resources(iwdev, iwcq);
- return err_code;
-}
-
-/**
- * i40iw_get_user_access - get hw access from IB access
- * @acc: IB access to return hw access
- */
-static inline u16 i40iw_get_user_access(int acc)
-{
- u16 access = 0;
-
- access |= (acc & IB_ACCESS_LOCAL_WRITE) ? I40IW_ACCESS_FLAGS_LOCALWRITE : 0;
- access |= (acc & IB_ACCESS_REMOTE_WRITE) ? I40IW_ACCESS_FLAGS_REMOTEWRITE : 0;
- access |= (acc & IB_ACCESS_REMOTE_READ) ? I40IW_ACCESS_FLAGS_REMOTEREAD : 0;
- access |= (acc & IB_ACCESS_MW_BIND) ? I40IW_ACCESS_FLAGS_BIND_WINDOW : 0;
- return access;
-}
-
-/**
- * i40iw_free_stag - free stag resource
- * @iwdev: iwarp device
- * @stag: stag to free
- */
-static void i40iw_free_stag(struct i40iw_device *iwdev, u32 stag)
-{
- u32 stag_idx;
-
- stag_idx = (stag & iwdev->mr_stagmask) >> I40IW_CQPSQ_STAG_IDX_SHIFT;
- i40iw_free_resource(iwdev, iwdev->allocated_mrs, stag_idx);
- i40iw_rem_devusecount(iwdev);
-}
-
-/**
- * i40iw_create_stag - create random stag
- * @iwdev: iwarp device
- */
-static u32 i40iw_create_stag(struct i40iw_device *iwdev)
-{
- u32 stag = 0;
- u32 stag_index = 0;
- u32 next_stag_index;
- u32 driver_key;
- u32 random;
- u8 consumer_key;
- int ret;
-
- get_random_bytes(&random, sizeof(random));
- consumer_key = (u8)random;
-
- driver_key = random & ~iwdev->mr_stagmask;
- next_stag_index = (random & iwdev->mr_stagmask) >> 8;
- next_stag_index %= iwdev->max_mr;
-
- ret = i40iw_alloc_resource(iwdev,
- iwdev->allocated_mrs, iwdev->max_mr,
- &stag_index, &next_stag_index);
- if (!ret) {
- stag = stag_index << I40IW_CQPSQ_STAG_IDX_SHIFT;
- stag |= driver_key;
- stag += (u32)consumer_key;
- i40iw_add_devusecount(iwdev);
- }
- return stag;
-}
-
-/**
- * i40iw_next_pbl_addr - Get next pbl address
- * @pbl: pointer to a pble
- * @pinfo: info pointer
- * @idx: index
- */
-static inline u64 *i40iw_next_pbl_addr(u64 *pbl,
- struct i40iw_pble_info **pinfo,
- u32 *idx)
-{
- *idx += 1;
- if ((!(*pinfo)) || (*idx != (*pinfo)->cnt))
- return ++pbl;
- *idx = 0;
- (*pinfo)++;
- return (u64 *)(*pinfo)->addr;
-}
-
-/**
- * i40iw_copy_user_pgaddrs - copy user page address to pble's os locally
- * @iwmr: iwmr for IB's user page addresses
- * @pbl: ple pointer to save 1 level or 0 level pble
- * @level: indicated level 0, 1 or 2
- */
-static void i40iw_copy_user_pgaddrs(struct i40iw_mr *iwmr,
- u64 *pbl,
- enum i40iw_pble_level level)
-{
- struct ib_umem *region = iwmr->region;
- struct i40iw_pbl *iwpbl = &iwmr->iwpbl;
- struct i40iw_pble_alloc *palloc = &iwpbl->pble_alloc;
- struct i40iw_pble_info *pinfo;
- struct ib_block_iter biter;
- u32 idx = 0;
-
- pinfo = (level == I40IW_LEVEL_1) ? NULL : palloc->level2.leaf;
-
- if (iwmr->type == IW_MEMREG_TYPE_QP)
- iwpbl->qp_mr.sq_page = sg_page(region->sg_head.sgl);
-
- rdma_umem_for_each_dma_block(region, &biter, iwmr->page_size) {
- *pbl = rdma_block_iter_dma_address(&biter);
- pbl = i40iw_next_pbl_addr(pbl, &pinfo, &idx);
- }
-}
-
-/**
- * i40iw_check_mem_contiguous - check if pbls stored in arr are contiguous
- * @arr: lvl1 pbl array
- * @npages: page count
- * @pg_size: page size
- *
- */
-static bool i40iw_check_mem_contiguous(u64 *arr, u32 npages, u32 pg_size)
-{
- u32 pg_idx;
-
- for (pg_idx = 0; pg_idx < npages; pg_idx++) {
- if ((*arr + (pg_size * pg_idx)) != arr[pg_idx])
- return false;
- }
- return true;
-}
-
-/**
- * i40iw_check_mr_contiguous - check if MR is physically contiguous
- * @palloc: pbl allocation struct
- * @pg_size: page size
- */
-static bool i40iw_check_mr_contiguous(struct i40iw_pble_alloc *palloc, u32 pg_size)
-{
- struct i40iw_pble_level2 *lvl2 = &palloc->level2;
- struct i40iw_pble_info *leaf = lvl2->leaf;
- u64 *arr = NULL;
- u64 *start_addr = NULL;
- int i;
- bool ret;
-
- if (palloc->level == I40IW_LEVEL_1) {
- arr = (u64 *)palloc->level1.addr;
- ret = i40iw_check_mem_contiguous(arr, palloc->total_cnt, pg_size);
- return ret;
- }
-
- start_addr = (u64 *)leaf->addr;
-
- for (i = 0; i < lvl2->leaf_cnt; i++, leaf++) {
- arr = (u64 *)leaf->addr;
- if ((*start_addr + (i * pg_size * PBLE_PER_PAGE)) != *arr)
- return false;
- ret = i40iw_check_mem_contiguous(arr, leaf->cnt, pg_size);
- if (!ret)
- return false;
- }
-
- return true;
-}
-
-/**
- * i40iw_setup_pbles - copy user pg address to pble's
- * @iwdev: iwarp device
- * @iwmr: mr pointer for this memory registration
- * @use_pbles: flag if to use pble's
- */
-static int i40iw_setup_pbles(struct i40iw_device *iwdev,
- struct i40iw_mr *iwmr,
- bool use_pbles)
-{
- struct i40iw_pbl *iwpbl = &iwmr->iwpbl;
- struct i40iw_pble_alloc *palloc = &iwpbl->pble_alloc;
- struct i40iw_pble_info *pinfo;
- u64 *pbl;
- enum i40iw_status_code status;
- enum i40iw_pble_level level = I40IW_LEVEL_1;
-
- if (use_pbles) {
- mutex_lock(&iwdev->pbl_mutex);
- status = i40iw_get_pble(&iwdev->sc_dev, iwdev->pble_rsrc, palloc, iwmr->page_cnt);
- mutex_unlock(&iwdev->pbl_mutex);
- if (status)
- return -ENOMEM;
-
- iwpbl->pbl_allocated = true;
- level = palloc->level;
- pinfo = (level == I40IW_LEVEL_1) ? &palloc->level1 : palloc->level2.leaf;
- pbl = (u64 *)pinfo->addr;
- } else {
- pbl = iwmr->pgaddrmem;
- }
-
- i40iw_copy_user_pgaddrs(iwmr, pbl, level);
-
- if (use_pbles)
- iwmr->pgaddrmem[0] = *pbl;
-
- return 0;
-}
-
-/**
- * i40iw_handle_q_mem - handle memory for qp and cq
- * @iwdev: iwarp device
- * @req: information for q memory management
- * @iwpbl: pble struct
- * @use_pbles: flag to use pble
- */
-static int i40iw_handle_q_mem(struct i40iw_device *iwdev,
- struct i40iw_mem_reg_req *req,
- struct i40iw_pbl *iwpbl,
- bool use_pbles)
-{
- struct i40iw_pble_alloc *palloc = &iwpbl->pble_alloc;
- struct i40iw_mr *iwmr = iwpbl->iwmr;
- struct i40iw_qp_mr *qpmr = &iwpbl->qp_mr;
- struct i40iw_cq_mr *cqmr = &iwpbl->cq_mr;
- struct i40iw_hmc_pble *hmc_p;
- u64 *arr = iwmr->pgaddrmem;
- u32 pg_size;
- int err;
- int total;
- bool ret = true;
-
- total = req->sq_pages + req->rq_pages + req->cq_pages;
- pg_size = iwmr->page_size;
-
- err = i40iw_setup_pbles(iwdev, iwmr, use_pbles);
- if (err)
- return err;
-
- if (use_pbles && (palloc->level != I40IW_LEVEL_1)) {
- i40iw_free_pble(iwdev->pble_rsrc, palloc);
- iwpbl->pbl_allocated = false;
- return -ENOMEM;
- }
-
- if (use_pbles)
- arr = (u64 *)palloc->level1.addr;
-
- if (iwmr->type == IW_MEMREG_TYPE_QP) {
- hmc_p = &qpmr->sq_pbl;
- qpmr->shadow = (dma_addr_t)arr[total];
-
- if (use_pbles) {
- ret = i40iw_check_mem_contiguous(arr, req->sq_pages, pg_size);
- if (ret)
- ret = i40iw_check_mem_contiguous(&arr[req->sq_pages], req->rq_pages, pg_size);
- }
-
- if (!ret) {
- hmc_p->idx = palloc->level1.idx;
- hmc_p = &qpmr->rq_pbl;
- hmc_p->idx = palloc->level1.idx + req->sq_pages;
- } else {
- hmc_p->addr = arr[0];
- hmc_p = &qpmr->rq_pbl;
- hmc_p->addr = arr[req->sq_pages];
- }
- } else { /* CQ */
- hmc_p = &cqmr->cq_pbl;
- cqmr->shadow = (dma_addr_t)arr[total];
-
- if (use_pbles)
- ret = i40iw_check_mem_contiguous(arr, req->cq_pages, pg_size);
-
- if (!ret)
- hmc_p->idx = palloc->level1.idx;
- else
- hmc_p->addr = arr[0];
- }
-
- if (use_pbles && ret) {
- i40iw_free_pble(iwdev->pble_rsrc, palloc);
- iwpbl->pbl_allocated = false;
- }
-
- return err;
-}
-
-/**
- * i40iw_hw_alloc_stag - cqp command to allocate stag
- * @iwdev: iwarp device
- * @iwmr: iwarp mr pointer
- */
-static int i40iw_hw_alloc_stag(struct i40iw_device *iwdev, struct i40iw_mr *iwmr)
-{
- struct i40iw_allocate_stag_info *info;
- struct i40iw_pd *iwpd = to_iwpd(iwmr->ibmr.pd);
- enum i40iw_status_code status;
- int err = 0;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
-
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, true);
- if (!cqp_request)
- return -ENOMEM;
-
- cqp_info = &cqp_request->info;
- info = &cqp_info->in.u.alloc_stag.info;
- memset(info, 0, sizeof(*info));
- info->page_size = PAGE_SIZE;
- info->stag_idx = iwmr->stag >> I40IW_CQPSQ_STAG_IDX_SHIFT;
- info->pd_id = iwpd->sc_pd.pd_id;
- info->total_len = iwmr->length;
- info->remote_access = true;
- cqp_info->cqp_cmd = OP_ALLOC_STAG;
- cqp_info->post_sq = 1;
- cqp_info->in.u.alloc_stag.dev = &iwdev->sc_dev;
- cqp_info->in.u.alloc_stag.scratch = (uintptr_t)cqp_request;
-
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status) {
- err = -ENOMEM;
- i40iw_pr_err("CQP-OP MR Reg fail");
- }
- return err;
-}
-
-/**
- * i40iw_alloc_mr - register stag for fast memory registration
- * @pd: ibpd pointer
- * @mr_type: memory for stag registrion
- * @max_num_sg: man number of pages
- */
-static struct ib_mr *i40iw_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
- u32 max_num_sg)
-{
- struct i40iw_pd *iwpd = to_iwpd(pd);
- struct i40iw_device *iwdev = to_iwdev(pd->device);
- struct i40iw_pble_alloc *palloc;
- struct i40iw_pbl *iwpbl;
- struct i40iw_mr *iwmr;
- enum i40iw_status_code status;
- u32 stag;
- int err_code = -ENOMEM;
-
- iwmr = kzalloc(sizeof(*iwmr), GFP_KERNEL);
- if (!iwmr)
- return ERR_PTR(-ENOMEM);
-
- stag = i40iw_create_stag(iwdev);
- if (!stag) {
- err_code = -EOVERFLOW;
- goto err;
- }
- stag &= ~I40IW_CQPSQ_STAG_KEY_MASK;
- iwmr->stag = stag;
- iwmr->ibmr.rkey = stag;
- iwmr->ibmr.lkey = stag;
- iwmr->ibmr.pd = pd;
- iwmr->ibmr.device = pd->device;
- iwpbl = &iwmr->iwpbl;
- iwpbl->iwmr = iwmr;
- iwmr->type = IW_MEMREG_TYPE_MEM;
- palloc = &iwpbl->pble_alloc;
- iwmr->page_cnt = max_num_sg;
- mutex_lock(&iwdev->pbl_mutex);
- status = i40iw_get_pble(&iwdev->sc_dev, iwdev->pble_rsrc, palloc, iwmr->page_cnt);
- mutex_unlock(&iwdev->pbl_mutex);
- if (status)
- goto err1;
-
- if (palloc->level != I40IW_LEVEL_1)
- goto err2;
- err_code = i40iw_hw_alloc_stag(iwdev, iwmr);
- if (err_code)
- goto err2;
- iwpbl->pbl_allocated = true;
- i40iw_add_pdusecount(iwpd);
- return &iwmr->ibmr;
-err2:
- i40iw_free_pble(iwdev->pble_rsrc, palloc);
-err1:
- i40iw_free_stag(iwdev, stag);
-err:
- kfree(iwmr);
- return ERR_PTR(err_code);
-}
-
-/**
- * i40iw_set_page - populate pbl list for fmr
- * @ibmr: ib mem to access iwarp mr pointer
- * @addr: page dma address fro pbl list
- */
-static int i40iw_set_page(struct ib_mr *ibmr, u64 addr)
-{
- struct i40iw_mr *iwmr = to_iwmr(ibmr);
- struct i40iw_pbl *iwpbl = &iwmr->iwpbl;
- struct i40iw_pble_alloc *palloc = &iwpbl->pble_alloc;
- u64 *pbl;
-
- if (unlikely(iwmr->npages == iwmr->page_cnt))
- return -ENOMEM;
-
- pbl = (u64 *)palloc->level1.addr;
- pbl[iwmr->npages++] = cpu_to_le64(addr);
- return 0;
-}
-
-/**
- * i40iw_map_mr_sg - map of sg list for fmr
- * @ibmr: ib mem to access iwarp mr pointer
- * @sg: scatter gather list for fmr
- * @sg_nents: number of sg pages
- * @sg_offset: scatter gather offset
- */
-static int i40iw_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
- int sg_nents, unsigned int *sg_offset)
-{
- struct i40iw_mr *iwmr = to_iwmr(ibmr);
-
- iwmr->npages = 0;
- return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, i40iw_set_page);
-}
-
-/**
- * i40iw_drain_sq - drain the send queue
- * @ibqp: ib qp pointer
- */
-static void i40iw_drain_sq(struct ib_qp *ibqp)
-{
- struct i40iw_qp *iwqp = to_iwqp(ibqp);
- struct i40iw_sc_qp *qp = &iwqp->sc_qp;
-
- if (I40IW_RING_MORE_WORK(qp->qp_uk.sq_ring))
- wait_for_completion(&iwqp->sq_drained);
-}
-
-/**
- * i40iw_drain_rq - drain the receive queue
- * @ibqp: ib qp pointer
- */
-static void i40iw_drain_rq(struct ib_qp *ibqp)
-{
- struct i40iw_qp *iwqp = to_iwqp(ibqp);
- struct i40iw_sc_qp *qp = &iwqp->sc_qp;
-
- if (I40IW_RING_MORE_WORK(qp->qp_uk.rq_ring))
- wait_for_completion(&iwqp->rq_drained);
-}
-
-/**
- * i40iw_hwreg_mr - send cqp command for memory registration
- * @iwdev: iwarp device
- * @iwmr: iwarp mr pointer
- * @access: access for MR
- */
-static int i40iw_hwreg_mr(struct i40iw_device *iwdev,
- struct i40iw_mr *iwmr,
- u16 access)
-{
- struct i40iw_pbl *iwpbl = &iwmr->iwpbl;
- struct i40iw_reg_ns_stag_info *stag_info;
- struct i40iw_pd *iwpd = to_iwpd(iwmr->ibmr.pd);
- struct i40iw_pble_alloc *palloc = &iwpbl->pble_alloc;
- enum i40iw_status_code status;
- int err = 0;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
-
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, true);
- if (!cqp_request)
- return -ENOMEM;
-
- cqp_info = &cqp_request->info;
- stag_info = &cqp_info->in.u.mr_reg_non_shared.info;
- memset(stag_info, 0, sizeof(*stag_info));
- stag_info->va = (void *)(unsigned long)iwpbl->user_base;
- stag_info->stag_idx = iwmr->stag >> I40IW_CQPSQ_STAG_IDX_SHIFT;
- stag_info->stag_key = (u8)iwmr->stag;
- stag_info->total_len = iwmr->length;
- stag_info->access_rights = access;
- stag_info->pd_id = iwpd->sc_pd.pd_id;
- stag_info->addr_type = I40IW_ADDR_TYPE_VA_BASED;
- stag_info->page_size = iwmr->page_size;
-
- if (iwpbl->pbl_allocated) {
- if (palloc->level == I40IW_LEVEL_1) {
- stag_info->first_pm_pbl_index = palloc->level1.idx;
- stag_info->chunk_size = 1;
- } else {
- stag_info->first_pm_pbl_index = palloc->level2.root.idx;
- stag_info->chunk_size = 3;
- }
- } else {
- stag_info->reg_addr_pa = iwmr->pgaddrmem[0];
- }
-
- cqp_info->cqp_cmd = OP_MR_REG_NON_SHARED;
- cqp_info->post_sq = 1;
- cqp_info->in.u.mr_reg_non_shared.dev = &iwdev->sc_dev;
- cqp_info->in.u.mr_reg_non_shared.scratch = (uintptr_t)cqp_request;
-
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status) {
- err = -ENOMEM;
- i40iw_pr_err("CQP-OP MR Reg fail");
- }
- return err;
-}
-
-/**
- * i40iw_reg_user_mr - Register a user memory region
- * @pd: ptr of pd
- * @start: virtual start address
- * @length: length of mr
- * @virt: virtual address
- * @acc: access of mr
- * @udata: user data
- */
-static struct ib_mr *i40iw_reg_user_mr(struct ib_pd *pd,
- u64 start,
- u64 length,
- u64 virt,
- int acc,
- struct ib_udata *udata)
-{
- struct i40iw_pd *iwpd = to_iwpd(pd);
- struct i40iw_device *iwdev = to_iwdev(pd->device);
- struct i40iw_ucontext *ucontext = rdma_udata_to_drv_context(
- udata, struct i40iw_ucontext, ibucontext);
- struct i40iw_pble_alloc *palloc;
- struct i40iw_pbl *iwpbl;
- struct i40iw_mr *iwmr;
- struct ib_umem *region;
- struct i40iw_mem_reg_req req;
- u32 stag = 0;
- u16 access;
- bool use_pbles = false;
- unsigned long flags;
- int err = -ENOSYS;
- int ret;
-
- if (!udata)
- return ERR_PTR(-EOPNOTSUPP);
-
- if (iwdev->closing)
- return ERR_PTR(-ENODEV);
-
- if (length > I40IW_MAX_MR_SIZE)
- return ERR_PTR(-EINVAL);
- region = ib_umem_get(pd->device, start, length, acc);
- if (IS_ERR(region))
- return (struct ib_mr *)region;
-
- if (ib_copy_from_udata(&req, udata, sizeof(req))) {
- ib_umem_release(region);
- return ERR_PTR(-EFAULT);
- }
-
- iwmr = kzalloc(sizeof(*iwmr), GFP_KERNEL);
- if (!iwmr) {
- ib_umem_release(region);
- return ERR_PTR(-ENOMEM);
- }
-
- iwpbl = &iwmr->iwpbl;
- iwpbl->iwmr = iwmr;
- iwmr->region = region;
- iwmr->ibmr.pd = pd;
- iwmr->ibmr.device = pd->device;
-
- iwmr->page_size = PAGE_SIZE;
- if (req.reg_type == IW_MEMREG_TYPE_MEM)
- iwmr->page_size = ib_umem_find_best_pgsz(region, SZ_4K | SZ_2M,
- virt);
- iwmr->length = region->length;
-
- iwpbl->user_base = virt;
- palloc = &iwpbl->pble_alloc;
-
- iwmr->type = req.reg_type;
- iwmr->page_cnt = ib_umem_num_dma_blocks(region, iwmr->page_size);
-
- switch (req.reg_type) {
- case IW_MEMREG_TYPE_QP:
- use_pbles = ((req.sq_pages + req.rq_pages) > 2);
- err = i40iw_handle_q_mem(iwdev, &req, iwpbl, use_pbles);
- if (err)
- goto error;
- spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
- list_add_tail(&iwpbl->list, &ucontext->qp_reg_mem_list);
- iwpbl->on_list = true;
- spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
- break;
- case IW_MEMREG_TYPE_CQ:
- use_pbles = (req.cq_pages > 1);
- err = i40iw_handle_q_mem(iwdev, &req, iwpbl, use_pbles);
- if (err)
- goto error;
-
- spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
- list_add_tail(&iwpbl->list, &ucontext->cq_reg_mem_list);
- iwpbl->on_list = true;
- spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
- break;
- case IW_MEMREG_TYPE_MEM:
- use_pbles = (iwmr->page_cnt != 1);
- access = I40IW_ACCESS_FLAGS_LOCALREAD;
-
- err = i40iw_setup_pbles(iwdev, iwmr, use_pbles);
- if (err)
- goto error;
-
- if (use_pbles) {
- ret = i40iw_check_mr_contiguous(palloc, iwmr->page_size);
- if (ret) {
- i40iw_free_pble(iwdev->pble_rsrc, palloc);
- iwpbl->pbl_allocated = false;
- }
- }
-
- access |= i40iw_get_user_access(acc);
- stag = i40iw_create_stag(iwdev);
- if (!stag) {
- err = -ENOMEM;
- goto error;
- }
-
- iwmr->stag = stag;
- iwmr->ibmr.rkey = stag;
- iwmr->ibmr.lkey = stag;
-
- err = i40iw_hwreg_mr(iwdev, iwmr, access);
- if (err) {
- i40iw_free_stag(iwdev, stag);
- goto error;
- }
-
- break;
- default:
- goto error;
- }
-
- iwmr->type = req.reg_type;
- if (req.reg_type == IW_MEMREG_TYPE_MEM)
- i40iw_add_pdusecount(iwpd);
- return &iwmr->ibmr;
-
-error:
- if (palloc->level != I40IW_LEVEL_0 && iwpbl->pbl_allocated)
- i40iw_free_pble(iwdev->pble_rsrc, palloc);
- ib_umem_release(region);
- kfree(iwmr);
- return ERR_PTR(err);
-}
-
-/**
- * i40iw_reg_phys_mr - register kernel physical memory
- * @pd: ibpd pointer
- * @addr: physical address of memory to register
- * @size: size of memory to register
- * @acc: Access rights
- * @iova_start: start of virtual address for physical buffers
- */
-struct ib_mr *i40iw_reg_phys_mr(struct ib_pd *pd,
- u64 addr,
- u64 size,
- int acc,
- u64 *iova_start)
-{
- struct i40iw_pd *iwpd = to_iwpd(pd);
- struct i40iw_device *iwdev = to_iwdev(pd->device);
- struct i40iw_pbl *iwpbl;
- struct i40iw_mr *iwmr;
- enum i40iw_status_code status;
- u32 stag;
- u16 access = I40IW_ACCESS_FLAGS_LOCALREAD;
- int ret;
-
- iwmr = kzalloc(sizeof(*iwmr), GFP_KERNEL);
- if (!iwmr)
- return ERR_PTR(-ENOMEM);
- iwmr->ibmr.pd = pd;
- iwmr->ibmr.device = pd->device;
- iwpbl = &iwmr->iwpbl;
- iwpbl->iwmr = iwmr;
- iwmr->type = IW_MEMREG_TYPE_MEM;
- iwpbl->user_base = *iova_start;
- stag = i40iw_create_stag(iwdev);
- if (!stag) {
- ret = -EOVERFLOW;
- goto err;
- }
- access |= i40iw_get_user_access(acc);
- iwmr->stag = stag;
- iwmr->ibmr.rkey = stag;
- iwmr->ibmr.lkey = stag;
- iwmr->page_cnt = 1;
- iwmr->pgaddrmem[0] = addr;
- iwmr->length = size;
- status = i40iw_hwreg_mr(iwdev, iwmr, access);
- if (status) {
- i40iw_free_stag(iwdev, stag);
- ret = -ENOMEM;
- goto err;
- }
-
- i40iw_add_pdusecount(iwpd);
- return &iwmr->ibmr;
- err:
- kfree(iwmr);
- return ERR_PTR(ret);
-}
-
-/**
- * i40iw_get_dma_mr - register physical mem
- * @pd: ptr of pd
- * @acc: access for memory
- */
-static struct ib_mr *i40iw_get_dma_mr(struct ib_pd *pd, int acc)
-{
- u64 kva = 0;
-
- return i40iw_reg_phys_mr(pd, 0, 0, acc, &kva);
-}
-
-/**
- * i40iw_del_memlist - Deleting pbl list entries for CQ/QP
- * @iwmr: iwmr for IB's user page addresses
- * @ucontext: ptr to user context
- */
-static void i40iw_del_memlist(struct i40iw_mr *iwmr,
- struct i40iw_ucontext *ucontext)
-{
- struct i40iw_pbl *iwpbl = &iwmr->iwpbl;
- unsigned long flags;
-
- switch (iwmr->type) {
- case IW_MEMREG_TYPE_CQ:
- spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
- if (iwpbl->on_list) {
- iwpbl->on_list = false;
- list_del(&iwpbl->list);
- }
- spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
- break;
- case IW_MEMREG_TYPE_QP:
- spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
- if (iwpbl->on_list) {
- iwpbl->on_list = false;
- list_del(&iwpbl->list);
- }
- spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
- break;
- default:
- break;
- }
-}
-
-/**
- * i40iw_dereg_mr - deregister mr
- * @ib_mr: mr ptr for dereg
- * @udata: user data
- */
-static int i40iw_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
-{
- struct ib_pd *ibpd = ib_mr->pd;
- struct i40iw_pd *iwpd = to_iwpd(ibpd);
- struct i40iw_mr *iwmr = to_iwmr(ib_mr);
- struct i40iw_device *iwdev = to_iwdev(ib_mr->device);
- enum i40iw_status_code status;
- struct i40iw_dealloc_stag_info *info;
- struct i40iw_pbl *iwpbl = &iwmr->iwpbl;
- struct i40iw_pble_alloc *palloc = &iwpbl->pble_alloc;
- struct i40iw_cqp_request *cqp_request;
- struct cqp_commands_info *cqp_info;
- u32 stag_idx;
-
- ib_umem_release(iwmr->region);
-
- if (iwmr->type != IW_MEMREG_TYPE_MEM) {
- /* region is released. only test for userness. */
- if (iwmr->region) {
- struct i40iw_ucontext *ucontext =
- rdma_udata_to_drv_context(
- udata,
- struct i40iw_ucontext,
- ibucontext);
-
- i40iw_del_memlist(iwmr, ucontext);
- }
- if (iwpbl->pbl_allocated && iwmr->type != IW_MEMREG_TYPE_QP)
- i40iw_free_pble(iwdev->pble_rsrc, palloc);
- kfree(iwmr);
- return 0;
- }
-
- cqp_request = i40iw_get_cqp_request(&iwdev->cqp, true);
- if (!cqp_request)
- return -ENOMEM;
-
- cqp_info = &cqp_request->info;
- info = &cqp_info->in.u.dealloc_stag.info;
- memset(info, 0, sizeof(*info));
-
- info->pd_id = cpu_to_le32(iwpd->sc_pd.pd_id & 0x00007fff);
- info->stag_idx = RS_64_1(ib_mr->rkey, I40IW_CQPSQ_STAG_IDX_SHIFT);
- stag_idx = info->stag_idx;
- info->mr = true;
- if (iwpbl->pbl_allocated)
- info->dealloc_pbl = true;
-
- cqp_info->cqp_cmd = OP_DEALLOC_STAG;
- cqp_info->post_sq = 1;
- cqp_info->in.u.dealloc_stag.dev = &iwdev->sc_dev;
- cqp_info->in.u.dealloc_stag.scratch = (uintptr_t)cqp_request;
- status = i40iw_handle_cqp_op(iwdev, cqp_request);
- if (status)
- i40iw_pr_err("CQP-OP dealloc failed for stag_idx = 0x%x\n", stag_idx);
- i40iw_rem_pdusecount(iwpd, iwdev);
- i40iw_free_stag(iwdev, iwmr->stag);
- if (iwpbl->pbl_allocated)
- i40iw_free_pble(iwdev->pble_rsrc, palloc);
- kfree(iwmr);
- return 0;
-}
-
-/*
- * hw_rev_show
- */
-static ssize_t hw_rev_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct i40iw_ib_device *iwibdev =
- rdma_device_to_drv_device(dev, struct i40iw_ib_device, ibdev);
- u32 hw_rev = iwibdev->iwdev->sc_dev.hw_rev;
-
- return sysfs_emit(buf, "%x\n", hw_rev);
-}
-static DEVICE_ATTR_RO(hw_rev);
-
-/*
- * hca_type_show
- */
-static ssize_t hca_type_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sysfs_emit(buf, "I40IW\n");
-}
-static DEVICE_ATTR_RO(hca_type);
-
-/*
- * board_id_show
- */
-static ssize_t board_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sysfs_emit(buf, "%.*s\n", 32, "I40IW Board ID");
-}
-static DEVICE_ATTR_RO(board_id);
-
-static struct attribute *i40iw_dev_attributes[] = {
- &dev_attr_hw_rev.attr,
- &dev_attr_hca_type.attr,
- &dev_attr_board_id.attr,
- NULL
-};
-
-static const struct attribute_group i40iw_attr_group = {
- .attrs = i40iw_dev_attributes,
-};
-
-/**
- * i40iw_copy_sg_list - copy sg list for qp
- * @sg_list: copied into sg_list
- * @sgl: copy from sgl
- * @num_sges: count of sg entries
- */
-static void i40iw_copy_sg_list(struct i40iw_sge *sg_list, struct ib_sge *sgl, int num_sges)
-{
- unsigned int i;
-
- for (i = 0; (i < num_sges) && (i < I40IW_MAX_WQ_FRAGMENT_COUNT); i++) {
- sg_list[i].tag_off = sgl[i].addr;
- sg_list[i].len = sgl[i].length;
- sg_list[i].stag = sgl[i].lkey;
- }
-}
-
-/**
- * i40iw_post_send - kernel application wr
- * @ibqp: qp ptr for wr
- * @ib_wr: work request ptr
- * @bad_wr: return of bad wr if err
- */
-static int i40iw_post_send(struct ib_qp *ibqp,
- const struct ib_send_wr *ib_wr,
- const struct ib_send_wr **bad_wr)
-{
- struct i40iw_qp *iwqp;
- struct i40iw_qp_uk *ukqp;
- struct i40iw_post_sq_info info;
- enum i40iw_status_code ret;
- int err = 0;
- unsigned long flags;
- bool inv_stag;
-
- iwqp = (struct i40iw_qp *)ibqp;
- ukqp = &iwqp->sc_qp.qp_uk;
-
- spin_lock_irqsave(&iwqp->lock, flags);
-
- if (iwqp->flush_issued) {
- err = -EINVAL;
- goto out;
- }
-
- while (ib_wr) {
- inv_stag = false;
- memset(&info, 0, sizeof(info));
- info.wr_id = (u64)(ib_wr->wr_id);
- if ((ib_wr->send_flags & IB_SEND_SIGNALED) || iwqp->sig_all)
- info.signaled = true;
- if (ib_wr->send_flags & IB_SEND_FENCE)
- info.read_fence = true;
-
- switch (ib_wr->opcode) {
- case IB_WR_SEND:
- case IB_WR_SEND_WITH_INV:
- if (ib_wr->opcode == IB_WR_SEND) {
- if (ib_wr->send_flags & IB_SEND_SOLICITED)
- info.op_type = I40IW_OP_TYPE_SEND_SOL;
- else
- info.op_type = I40IW_OP_TYPE_SEND;
- } else {
- if (ib_wr->send_flags & IB_SEND_SOLICITED)
- info.op_type = I40IW_OP_TYPE_SEND_SOL_INV;
- else
- info.op_type = I40IW_OP_TYPE_SEND_INV;
- }
-
- if (ib_wr->send_flags & IB_SEND_INLINE) {
- info.op.inline_send.data = (void *)(unsigned long)ib_wr->sg_list[0].addr;
- info.op.inline_send.len = ib_wr->sg_list[0].length;
- ret = ukqp->ops.iw_inline_send(ukqp, &info, ib_wr->ex.invalidate_rkey, false);
- } else {
- info.op.send.num_sges = ib_wr->num_sge;
- info.op.send.sg_list = (struct i40iw_sge *)ib_wr->sg_list;
- ret = ukqp->ops.iw_send(ukqp, &info, ib_wr->ex.invalidate_rkey, false);
- }
-
- if (ret) {
- if (ret == I40IW_ERR_QP_TOOMANY_WRS_POSTED)
- err = -ENOMEM;
- else
- err = -EINVAL;
- }
- break;
- case IB_WR_RDMA_WRITE:
- info.op_type = I40IW_OP_TYPE_RDMA_WRITE;
-
- if (ib_wr->send_flags & IB_SEND_INLINE) {
- info.op.inline_rdma_write.data = (void *)(unsigned long)ib_wr->sg_list[0].addr;
- info.op.inline_rdma_write.len = ib_wr->sg_list[0].length;
- info.op.inline_rdma_write.rem_addr.tag_off = rdma_wr(ib_wr)->remote_addr;
- info.op.inline_rdma_write.rem_addr.stag = rdma_wr(ib_wr)->rkey;
- ret = ukqp->ops.iw_inline_rdma_write(ukqp, &info, false);
- } else {
- info.op.rdma_write.lo_sg_list = (void *)ib_wr->sg_list;
- info.op.rdma_write.num_lo_sges = ib_wr->num_sge;
- info.op.rdma_write.rem_addr.tag_off = rdma_wr(ib_wr)->remote_addr;
- info.op.rdma_write.rem_addr.stag = rdma_wr(ib_wr)->rkey;
- ret = ukqp->ops.iw_rdma_write(ukqp, &info, false);
- }
-
- if (ret) {
- if (ret == I40IW_ERR_QP_TOOMANY_WRS_POSTED)
- err = -ENOMEM;
- else
- err = -EINVAL;
- }
- break;
- case IB_WR_RDMA_READ_WITH_INV:
- inv_stag = true;
- fallthrough;
- case IB_WR_RDMA_READ:
- if (ib_wr->num_sge > I40IW_MAX_SGE_RD) {
- err = -EINVAL;
- break;
- }
- info.op_type = I40IW_OP_TYPE_RDMA_READ;
- info.op.rdma_read.rem_addr.tag_off = rdma_wr(ib_wr)->remote_addr;
- info.op.rdma_read.rem_addr.stag = rdma_wr(ib_wr)->rkey;
- info.op.rdma_read.lo_addr.tag_off = ib_wr->sg_list->addr;
- info.op.rdma_read.lo_addr.stag = ib_wr->sg_list->lkey;
- info.op.rdma_read.lo_addr.len = ib_wr->sg_list->length;
- ret = ukqp->ops.iw_rdma_read(ukqp, &info, inv_stag, false);
- if (ret) {
- if (ret == I40IW_ERR_QP_TOOMANY_WRS_POSTED)
- err = -ENOMEM;
- else
- err = -EINVAL;
- }
- break;
- case IB_WR_LOCAL_INV:
- info.op_type = I40IW_OP_TYPE_INV_STAG;
- info.op.inv_local_stag.target_stag = ib_wr->ex.invalidate_rkey;
- ret = ukqp->ops.iw_stag_local_invalidate(ukqp, &info, true);
- if (ret)
- err = -ENOMEM;
- break;
- case IB_WR_REG_MR:
- {
- struct i40iw_mr *iwmr = to_iwmr(reg_wr(ib_wr)->mr);
- int flags = reg_wr(ib_wr)->access;
- struct i40iw_pble_alloc *palloc = &iwmr->iwpbl.pble_alloc;
- struct i40iw_sc_dev *dev = &iwqp->iwdev->sc_dev;
- struct i40iw_fast_reg_stag_info info;
-
- memset(&info, 0, sizeof(info));
- info.access_rights = I40IW_ACCESS_FLAGS_LOCALREAD;
- info.access_rights |= i40iw_get_user_access(flags);
- info.stag_key = reg_wr(ib_wr)->key & 0xff;
- info.stag_idx = reg_wr(ib_wr)->key >> 8;
- info.page_size = reg_wr(ib_wr)->mr->page_size;
- info.wr_id = ib_wr->wr_id;
-
- info.addr_type = I40IW_ADDR_TYPE_VA_BASED;
- info.va = (void *)(uintptr_t)iwmr->ibmr.iova;
- info.total_len = iwmr->ibmr.length;
- info.reg_addr_pa = *(u64 *)palloc->level1.addr;
- info.first_pm_pbl_index = palloc->level1.idx;
- info.local_fence = ib_wr->send_flags & IB_SEND_FENCE;
- info.signaled = ib_wr->send_flags & IB_SEND_SIGNALED;
-
- if (iwmr->npages > I40IW_MIN_PAGES_PER_FMR)
- info.chunk_size = 1;
-
- ret = dev->iw_priv_qp_ops->iw_mr_fast_register(&iwqp->sc_qp, &info, true);
- if (ret)
- err = -ENOMEM;
- break;
- }
- default:
- err = -EINVAL;
- i40iw_pr_err(" upost_send bad opcode = 0x%x\n",
- ib_wr->opcode);
- break;
- }
-
- if (err)
- break;
- ib_wr = ib_wr->next;
- }
-
-out:
- if (err)
- *bad_wr = ib_wr;
- else
- ukqp->ops.iw_qp_post_wr(ukqp);
- spin_unlock_irqrestore(&iwqp->lock, flags);
-
- return err;
-}
-
-/**
- * i40iw_post_recv - post receive wr for kernel application
- * @ibqp: ib qp pointer
- * @ib_wr: work request for receive
- * @bad_wr: bad wr caused an error
- */
-static int i40iw_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *ib_wr,
- const struct ib_recv_wr **bad_wr)
-{
- struct i40iw_qp *iwqp;
- struct i40iw_qp_uk *ukqp;
- struct i40iw_post_rq_info post_recv;
- struct i40iw_sge sg_list[I40IW_MAX_WQ_FRAGMENT_COUNT];
- enum i40iw_status_code ret = 0;
- unsigned long flags;
- int err = 0;
-
- iwqp = (struct i40iw_qp *)ibqp;
- ukqp = &iwqp->sc_qp.qp_uk;
-
- memset(&post_recv, 0, sizeof(post_recv));
- spin_lock_irqsave(&iwqp->lock, flags);
-
- if (iwqp->flush_issued) {
- err = -EINVAL;
- goto out;
- }
-
- while (ib_wr) {
- post_recv.num_sges = ib_wr->num_sge;
- post_recv.wr_id = ib_wr->wr_id;
- i40iw_copy_sg_list(sg_list, ib_wr->sg_list, ib_wr->num_sge);
- post_recv.sg_list = sg_list;
- ret = ukqp->ops.iw_post_receive(ukqp, &post_recv);
- if (ret) {
- i40iw_pr_err(" post_recv err %d\n", ret);
- if (ret == I40IW_ERR_QP_TOOMANY_WRS_POSTED)
- err = -ENOMEM;
- else
- err = -EINVAL;
- *bad_wr = ib_wr;
- goto out;
- }
- ib_wr = ib_wr->next;
- }
- out:
- spin_unlock_irqrestore(&iwqp->lock, flags);
- return err;
-}
-
-/**
- * i40iw_poll_cq - poll cq for completion (kernel apps)
- * @ibcq: cq to poll
- * @num_entries: number of entries to poll
- * @entry: wr of entry completed
- */
-static int i40iw_poll_cq(struct ib_cq *ibcq,
- int num_entries,
- struct ib_wc *entry)
-{
- struct i40iw_cq *iwcq;
- int cqe_count = 0;
- struct i40iw_cq_poll_info cq_poll_info;
- enum i40iw_status_code ret;
- struct i40iw_cq_uk *ukcq;
- struct i40iw_sc_qp *qp;
- struct i40iw_qp *iwqp;
- unsigned long flags;
-
- iwcq = (struct i40iw_cq *)ibcq;
- ukcq = &iwcq->sc_cq.cq_uk;
-
- spin_lock_irqsave(&iwcq->lock, flags);
- while (cqe_count < num_entries) {
- ret = ukcq->ops.iw_cq_poll_completion(ukcq, &cq_poll_info);
- if (ret == I40IW_ERR_QUEUE_EMPTY) {
- break;
- } else if (ret == I40IW_ERR_QUEUE_DESTROYED) {
- continue;
- } else if (ret) {
- if (!cqe_count)
- cqe_count = -1;
- break;
- }
- entry->wc_flags = 0;
- entry->wr_id = cq_poll_info.wr_id;
- if (cq_poll_info.error) {
- entry->status = IB_WC_WR_FLUSH_ERR;
- entry->vendor_err = cq_poll_info.major_err << 16 | cq_poll_info.minor_err;
- } else {
- entry->status = IB_WC_SUCCESS;
- }
-
- switch (cq_poll_info.op_type) {
- case I40IW_OP_TYPE_RDMA_WRITE:
- entry->opcode = IB_WC_RDMA_WRITE;
- break;
- case I40IW_OP_TYPE_RDMA_READ_INV_STAG:
- case I40IW_OP_TYPE_RDMA_READ:
- entry->opcode = IB_WC_RDMA_READ;
- break;
- case I40IW_OP_TYPE_SEND_SOL:
- case I40IW_OP_TYPE_SEND_SOL_INV:
- case I40IW_OP_TYPE_SEND_INV:
- case I40IW_OP_TYPE_SEND:
- entry->opcode = IB_WC_SEND;
- break;
- case I40IW_OP_TYPE_REC:
- entry->opcode = IB_WC_RECV;
- break;
- default:
- entry->opcode = IB_WC_RECV;
- break;
- }
-
- entry->ex.imm_data = 0;
- qp = (struct i40iw_sc_qp *)cq_poll_info.qp_handle;
- entry->qp = (struct ib_qp *)qp->back_qp;
- entry->src_qp = cq_poll_info.qp_id;
- iwqp = (struct i40iw_qp *)qp->back_qp;
- if (iwqp->iwarp_state > I40IW_QP_STATE_RTS) {
- if (!I40IW_RING_MORE_WORK(qp->qp_uk.sq_ring))
- complete(&iwqp->sq_drained);
- if (!I40IW_RING_MORE_WORK(qp->qp_uk.rq_ring))
- complete(&iwqp->rq_drained);
- }
- entry->byte_len = cq_poll_info.bytes_xfered;
- entry++;
- cqe_count++;
- }
- spin_unlock_irqrestore(&iwcq->lock, flags);
- return cqe_count;
-}
-
-/**
- * i40iw_req_notify_cq - arm cq kernel application
- * @ibcq: cq to arm
- * @notify_flags: notofication flags
- */
-static int i40iw_req_notify_cq(struct ib_cq *ibcq,
- enum ib_cq_notify_flags notify_flags)
-{
- struct i40iw_cq *iwcq;
- struct i40iw_cq_uk *ukcq;
- unsigned long flags;
- enum i40iw_completion_notify cq_notify = IW_CQ_COMPL_EVENT;
-
- iwcq = (struct i40iw_cq *)ibcq;
- ukcq = &iwcq->sc_cq.cq_uk;
- if (notify_flags == IB_CQ_SOLICITED)
- cq_notify = IW_CQ_COMPL_SOLICITED;
- spin_lock_irqsave(&iwcq->lock, flags);
- ukcq->ops.iw_cq_request_notification(ukcq, cq_notify);
- spin_unlock_irqrestore(&iwcq->lock, flags);
- return 0;
-}
-
-/**
- * i40iw_port_immutable - return port's immutable data
- * @ibdev: ib dev struct
- * @port_num: port number
- * @immutable: immutable data for the port return
- */
-static int i40iw_port_immutable(struct ib_device *ibdev, u32 port_num,
- struct ib_port_immutable *immutable)
-{
- struct ib_port_attr attr;
- int err;
-
- immutable->core_cap_flags = RDMA_CORE_PORT_IWARP;
-
- err = ib_query_port(ibdev, port_num, &attr);
-
- if (err)
- return err;
-
- immutable->gid_tbl_len = attr.gid_tbl_len;
-
- return 0;
-}
-
-static const char * const i40iw_hw_stat_names[] = {
- // 32bit names
- [I40IW_HW_STAT_INDEX_IP4RXDISCARD] = "ip4InDiscards",
- [I40IW_HW_STAT_INDEX_IP4RXTRUNC] = "ip4InTruncatedPkts",
- [I40IW_HW_STAT_INDEX_IP4TXNOROUTE] = "ip4OutNoRoutes",
- [I40IW_HW_STAT_INDEX_IP6RXDISCARD] = "ip6InDiscards",
- [I40IW_HW_STAT_INDEX_IP6RXTRUNC] = "ip6InTruncatedPkts",
- [I40IW_HW_STAT_INDEX_IP6TXNOROUTE] = "ip6OutNoRoutes",
- [I40IW_HW_STAT_INDEX_TCPRTXSEG] = "tcpRetransSegs",
- [I40IW_HW_STAT_INDEX_TCPRXOPTERR] = "tcpInOptErrors",
- [I40IW_HW_STAT_INDEX_TCPRXPROTOERR] = "tcpInProtoErrors",
- // 64bit names
- [I40IW_HW_STAT_INDEX_IP4RXOCTS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip4InOctets",
- [I40IW_HW_STAT_INDEX_IP4RXPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip4InPkts",
- [I40IW_HW_STAT_INDEX_IP4RXFRAGS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip4InReasmRqd",
- [I40IW_HW_STAT_INDEX_IP4RXMCPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip4InMcastPkts",
- [I40IW_HW_STAT_INDEX_IP4TXOCTS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip4OutOctets",
- [I40IW_HW_STAT_INDEX_IP4TXPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip4OutPkts",
- [I40IW_HW_STAT_INDEX_IP4TXFRAGS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip4OutSegRqd",
- [I40IW_HW_STAT_INDEX_IP4TXMCPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip4OutMcastPkts",
- [I40IW_HW_STAT_INDEX_IP6RXOCTS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip6InOctets",
- [I40IW_HW_STAT_INDEX_IP6RXPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip6InPkts",
- [I40IW_HW_STAT_INDEX_IP6RXFRAGS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip6InReasmRqd",
- [I40IW_HW_STAT_INDEX_IP6RXMCPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip6InMcastPkts",
- [I40IW_HW_STAT_INDEX_IP6TXOCTS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip6OutOctets",
- [I40IW_HW_STAT_INDEX_IP6TXPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip6OutPkts",
- [I40IW_HW_STAT_INDEX_IP6TXFRAGS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip6OutSegRqd",
- [I40IW_HW_STAT_INDEX_IP6TXMCPKTS + I40IW_HW_STAT_INDEX_MAX_32] =
- "ip6OutMcastPkts",
- [I40IW_HW_STAT_INDEX_TCPRXSEGS + I40IW_HW_STAT_INDEX_MAX_32] =
- "tcpInSegs",
- [I40IW_HW_STAT_INDEX_TCPTXSEG + I40IW_HW_STAT_INDEX_MAX_32] =
- "tcpOutSegs",
- [I40IW_HW_STAT_INDEX_RDMARXRDS + I40IW_HW_STAT_INDEX_MAX_32] =
- "iwInRdmaReads",
- [I40IW_HW_STAT_INDEX_RDMARXSNDS + I40IW_HW_STAT_INDEX_MAX_32] =
- "iwInRdmaSends",
- [I40IW_HW_STAT_INDEX_RDMARXWRS + I40IW_HW_STAT_INDEX_MAX_32] =
- "iwInRdmaWrites",
- [I40IW_HW_STAT_INDEX_RDMATXRDS + I40IW_HW_STAT_INDEX_MAX_32] =
- "iwOutRdmaReads",
- [I40IW_HW_STAT_INDEX_RDMATXSNDS + I40IW_HW_STAT_INDEX_MAX_32] =
- "iwOutRdmaSends",
- [I40IW_HW_STAT_INDEX_RDMATXWRS + I40IW_HW_STAT_INDEX_MAX_32] =
- "iwOutRdmaWrites",
- [I40IW_HW_STAT_INDEX_RDMAVBND + I40IW_HW_STAT_INDEX_MAX_32] =
- "iwRdmaBnd",
- [I40IW_HW_STAT_INDEX_RDMAVINV + I40IW_HW_STAT_INDEX_MAX_32] =
- "iwRdmaInv"
-};
-
-static void i40iw_get_dev_fw_str(struct ib_device *dev, char *str)
-{
- struct i40iw_device *iwdev = to_iwdev(dev);
-
- snprintf(str, IB_FW_VERSION_NAME_MAX, "%llu.%llu",
- i40iw_fw_major_ver(&iwdev->sc_dev),
- i40iw_fw_minor_ver(&iwdev->sc_dev));
-}
-
-/**
- * i40iw_alloc_hw_stats - Allocate a hw stats structure
- * @ibdev: device pointer from stack
- * @port_num: port number
- */
-static struct rdma_hw_stats *i40iw_alloc_hw_stats(struct ib_device *ibdev,
- u32 port_num)
-{
- struct i40iw_device *iwdev = to_iwdev(ibdev);
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- int num_counters = I40IW_HW_STAT_INDEX_MAX_32 +
- I40IW_HW_STAT_INDEX_MAX_64;
- unsigned long lifespan = RDMA_HW_STATS_DEFAULT_LIFESPAN;
-
- BUILD_BUG_ON(ARRAY_SIZE(i40iw_hw_stat_names) !=
- (I40IW_HW_STAT_INDEX_MAX_32 +
- I40IW_HW_STAT_INDEX_MAX_64));
-
- /*
- * PFs get the default update lifespan, but VFs only update once
- * per second
- */
- if (!dev->is_pf)
- lifespan = 1000;
- return rdma_alloc_hw_stats_struct(i40iw_hw_stat_names, num_counters,
- lifespan);
-}
-
-/**
- * i40iw_get_hw_stats - Populates the rdma_hw_stats structure
- * @ibdev: device pointer from stack
- * @stats: stats pointer from stack
- * @port_num: port number
- * @index: which hw counter the stack is requesting we update
- */
-static int i40iw_get_hw_stats(struct ib_device *ibdev,
- struct rdma_hw_stats *stats,
- u32 port_num, int index)
-{
- struct i40iw_device *iwdev = to_iwdev(ibdev);
- struct i40iw_sc_dev *dev = &iwdev->sc_dev;
- struct i40iw_vsi_pestat *devstat = iwdev->vsi.pestat;
- struct i40iw_dev_hw_stats *hw_stats = &devstat->hw_stats;
-
- if (dev->is_pf) {
- i40iw_hw_stats_read_all(devstat, &devstat->hw_stats);
- } else {
- if (i40iw_vchnl_vf_get_pe_stats(dev, &devstat->hw_stats))
- return -ENOSYS;
- }
-
- memcpy(&stats->value[0], hw_stats, sizeof(*hw_stats));
-
- return stats->num_counters;
-}
-
-/**
- * i40iw_query_gid - Query port GID
- * @ibdev: device pointer from stack
- * @port: port number
- * @index: Entry index
- * @gid: Global ID
- */
-static int i40iw_query_gid(struct ib_device *ibdev,
- u32 port,
- int index,
- union ib_gid *gid)
-{
- struct i40iw_device *iwdev = to_iwdev(ibdev);
-
- memset(gid->raw, 0, sizeof(gid->raw));
- ether_addr_copy(gid->raw, iwdev->netdev->dev_addr);
- return 0;
-}
-
-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,
- .alloc_ucontext = i40iw_alloc_ucontext,
- .create_cq = i40iw_create_cq,
- .create_qp = i40iw_create_qp,
- .dealloc_pd = i40iw_dealloc_pd,
- .dealloc_ucontext = i40iw_dealloc_ucontext,
- .dereg_mr = i40iw_dereg_mr,
- .destroy_cq = i40iw_destroy_cq,
- .destroy_qp = i40iw_destroy_qp,
- .drain_rq = i40iw_drain_rq,
- .drain_sq = i40iw_drain_sq,
- .get_dev_fw_str = i40iw_get_dev_fw_str,
- .get_dma_mr = i40iw_get_dma_mr,
- .get_hw_stats = i40iw_get_hw_stats,
- .get_port_immutable = i40iw_port_immutable,
- .iw_accept = i40iw_accept,
- .iw_add_ref = i40iw_qp_add_ref,
- .iw_connect = i40iw_connect,
- .iw_create_listen = i40iw_create_listen,
- .iw_destroy_listen = i40iw_destroy_listen,
- .iw_get_qp = i40iw_get_qp,
- .iw_reject = i40iw_reject,
- .iw_rem_ref = i40iw_qp_rem_ref,
- .map_mr_sg = i40iw_map_mr_sg,
- .mmap = i40iw_mmap,
- .modify_qp = i40iw_modify_qp,
- .poll_cq = i40iw_poll_cq,
- .post_recv = i40iw_post_recv,
- .post_send = i40iw_post_send,
- .query_device = i40iw_query_device,
- .query_gid = i40iw_query_gid,
- .query_port = i40iw_query_port,
- .query_qp = i40iw_query_qp,
- .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),
-};
-
-/**
- * i40iw_init_rdma_device - initialization of iwarp device
- * @iwdev: iwarp device
- */
-static struct i40iw_ib_device *i40iw_init_rdma_device(struct i40iw_device *iwdev)
-{
- struct i40iw_ib_device *iwibdev;
- struct net_device *netdev = iwdev->netdev;
- struct pci_dev *pcidev = iwdev->hw.pcidev;
-
- iwibdev = ib_alloc_device(i40iw_ib_device, ibdev);
- if (!iwibdev) {
- i40iw_pr_err("iwdev == NULL\n");
- return NULL;
- }
- iwdev->iwibdev = iwibdev;
- iwibdev->iwdev = iwdev;
-
- iwibdev->ibdev.node_type = RDMA_NODE_RNIC;
- ether_addr_copy((u8 *)&iwibdev->ibdev.node_guid, netdev->dev_addr);
-
- iwibdev->ibdev.phys_port_cnt = 1;
- iwibdev->ibdev.num_comp_vectors = iwdev->ceqs_count;
- iwibdev->ibdev.dev.parent = &pcidev->dev;
- memcpy(iwibdev->ibdev.iw_ifname, netdev->name,
- sizeof(iwibdev->ibdev.iw_ifname));
- ib_set_device_ops(&iwibdev->ibdev, &i40iw_dev_ops);
-
- return iwibdev;
-}
-
-/**
- * i40iw_port_ibevent - indicate port event
- * @iwdev: iwarp device
- */
-void i40iw_port_ibevent(struct i40iw_device *iwdev)
-{
- struct i40iw_ib_device *iwibdev = iwdev->iwibdev;
- struct ib_event event;
-
- event.device = &iwibdev->ibdev;
- event.element.port_num = 1;
- event.event = iwdev->iw_status ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR;
- ib_dispatch_event(&event);
-}
-
-/**
- * i40iw_destroy_rdma_device - destroy rdma device and free resources
- * @iwibdev: IB device ptr
- */
-void i40iw_destroy_rdma_device(struct i40iw_ib_device *iwibdev)
-{
- ib_unregister_device(&iwibdev->ibdev);
- wait_event_timeout(iwibdev->iwdev->close_wq,
- !atomic64_read(&iwibdev->iwdev->use_count),
- I40IW_EVENT_TIMEOUT);
- ib_dealloc_device(&iwibdev->ibdev);
-}
-
-/**
- * i40iw_register_rdma_device - register iwarp device to IB
- * @iwdev: iwarp device
- */
-int i40iw_register_rdma_device(struct i40iw_device *iwdev)
-{
- int ret;
- struct i40iw_ib_device *iwibdev;
-
- iwdev->iwibdev = i40iw_init_rdma_device(iwdev);
- if (!iwdev->iwibdev)
- return -ENOMEM;
- iwibdev = iwdev->iwibdev;
- rdma_set_device_sysfs_group(&iwibdev->ibdev, &i40iw_attr_group);
- ret = ib_device_set_netdev(&iwibdev->ibdev, iwdev->netdev, 1);
- if (ret)
- goto error;
-
- dma_set_max_seg_size(&iwdev->hw.pcidev->dev, UINT_MAX);
- ret = ib_register_device(&iwibdev->ibdev, "i40iw%d", &iwdev->hw.pcidev->dev);
- if (ret)
- goto error;
-
- return 0;
-error:
- ib_dealloc_device(&iwdev->iwibdev->ibdev);
- return ret;
-}
diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.h b/drivers/infiniband/hw/i40iw/i40iw_verbs.h
deleted file mode 100644
index bab71f3e5637..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_verbs.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_VERBS_H
-#define I40IW_VERBS_H
-
-struct i40iw_ucontext {
- struct ib_ucontext ibucontext;
- struct i40iw_device *iwdev;
- struct list_head cq_reg_mem_list;
- spinlock_t cq_reg_mem_list_lock; /* memory list for cq's */
- struct list_head qp_reg_mem_list;
- spinlock_t qp_reg_mem_list_lock; /* memory list for qp's */
- int abi_ver;
-};
-
-struct i40iw_pd {
- struct ib_pd ibpd;
- struct i40iw_sc_pd sc_pd;
- atomic_t usecount;
-};
-
-struct i40iw_hmc_pble {
- union {
- u32 idx;
- dma_addr_t addr;
- };
-};
-
-struct i40iw_cq_mr {
- struct i40iw_hmc_pble cq_pbl;
- dma_addr_t shadow;
-};
-
-struct i40iw_qp_mr {
- struct i40iw_hmc_pble sq_pbl;
- struct i40iw_hmc_pble rq_pbl;
- dma_addr_t shadow;
- struct page *sq_page;
-};
-
-struct i40iw_pbl {
- struct list_head list;
- union {
- struct i40iw_qp_mr qp_mr;
- struct i40iw_cq_mr cq_mr;
- };
-
- bool pbl_allocated;
- bool on_list;
- u64 user_base;
- struct i40iw_pble_alloc pble_alloc;
- struct i40iw_mr *iwmr;
-};
-
-#define MAX_SAVE_PAGE_ADDRS 4
-struct i40iw_mr {
- union {
- struct ib_mr ibmr;
- struct ib_mw ibmw;
- };
- struct ib_umem *region;
- u16 type;
- u32 page_cnt;
- u64 page_size;
- u32 npages;
- u32 stag;
- u64 length;
- u64 pgaddrmem[MAX_SAVE_PAGE_ADDRS];
- struct i40iw_pbl iwpbl;
-};
-
-struct i40iw_cq {
- struct ib_cq ibcq;
- struct i40iw_sc_cq sc_cq;
- u16 cq_head;
- u16 cq_size;
- u16 cq_number;
- bool user_mode;
- u32 polled_completions;
- u32 cq_mem_size;
- struct i40iw_dma_mem kmem;
- spinlock_t lock; /* for poll cq */
- struct i40iw_pbl *iwpbl;
-};
-
-struct disconn_work {
- struct work_struct work;
- struct i40iw_qp *iwqp;
-};
-
-struct iw_cm_id;
-struct ietf_mpa_frame;
-struct i40iw_ud_file;
-
-struct i40iw_qp_kmode {
- struct i40iw_dma_mem dma_mem;
- u64 *wrid_mem;
-};
-
-struct i40iw_qp {
- struct ib_qp ibqp;
- struct i40iw_sc_qp sc_qp;
- struct i40iw_device *iwdev;
- struct i40iw_cq *iwscq;
- struct i40iw_cq *iwrcq;
- struct i40iw_pd *iwpd;
- struct i40iw_qp_host_ctx_info ctx_info;
- struct i40iwarp_offload_info iwarp_info;
- void *allocated_buffer;
- refcount_t refcount;
- struct iw_cm_id *cm_id;
- void *cm_node;
- struct ib_mr *lsmm_mr;
- struct work_struct work;
- enum ib_qp_state ibqp_state;
- u32 iwarp_state;
- u32 qp_mem_size;
- u32 last_aeq;
- atomic_t close_timer_started;
- spinlock_t lock; /* for post work requests */
- struct i40iw_qp_context *iwqp_context;
- void *pbl_vbase;
- dma_addr_t pbl_pbase;
- struct page *page;
- u8 active_conn:1;
- u8 user_mode:1;
- u8 hte_added:1;
- u8 flush_issued:1;
- u8 destroyed:1;
- u8 sig_all:1;
- u8 pau_mode:1;
- u8 rsvd:1;
- u16 term_sq_flush_code;
- u16 term_rq_flush_code;
- u8 hw_iwarp_state;
- u8 hw_tcp_state;
- struct i40iw_qp_kmode kqp;
- struct i40iw_dma_mem host_ctx;
- struct timer_list terminate_timer;
- struct i40iw_pbl iwpbl;
- struct i40iw_dma_mem q2_ctx_mem;
- struct i40iw_dma_mem ietf_mem;
- struct completion sq_drained;
- struct completion rq_drained;
- struct completion free_qp;
-};
-#endif
diff --git a/drivers/infiniband/hw/i40iw/i40iw_vf.c b/drivers/infiniband/hw/i40iw/i40iw_vf.c
deleted file mode 100644
index e33d4810965c..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_vf.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 "i40iw_osdep.h"
-#include "i40iw_register.h"
-#include "i40iw_status.h"
-#include "i40iw_hmc.h"
-#include "i40iw_d.h"
-#include "i40iw_type.h"
-#include "i40iw_p.h"
-#include "i40iw_vf.h"
-
-/**
- * i40iw_manage_vf_pble_bp - manage vf pble
- * @cqp: cqp for cqp' sq wqe
- * @info: pble info
- * @scratch: pointer for completion
- * @post_sq: to post and ring
- */
-enum i40iw_status_code i40iw_manage_vf_pble_bp(struct i40iw_sc_cqp *cqp,
- struct i40iw_manage_vf_pble_info *info,
- u64 scratch,
- bool post_sq)
-{
- u64 *wqe;
- u64 temp, header, pd_pl_pba = 0;
-
- wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch);
- if (!wqe)
- return I40IW_ERR_RING_FULL;
-
- temp = LS_64(info->pd_entry_cnt, I40IW_CQPSQ_MVPBP_PD_ENTRY_CNT) |
- LS_64(info->first_pd_index, I40IW_CQPSQ_MVPBP_FIRST_PD_INX) |
- LS_64(info->sd_index, I40IW_CQPSQ_MVPBP_SD_INX);
- set_64bit_val(wqe, 16, temp);
-
- header = LS_64((info->inv_pd_ent ? 1 : 0), I40IW_CQPSQ_MVPBP_INV_PD_ENT) |
- LS_64(I40IW_CQP_OP_MANAGE_VF_PBLE_BP, I40IW_CQPSQ_OPCODE) |
- LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID);
- set_64bit_val(wqe, 24, header);
-
- pd_pl_pba = LS_64(info->pd_pl_pba >> 3, I40IW_CQPSQ_MVPBP_PD_PLPBA);
- set_64bit_val(wqe, 32, pd_pl_pba);
-
- i40iw_debug_buf(cqp->dev, I40IW_DEBUG_WQE, "MANAGE VF_PBLE_BP WQE", wqe, I40IW_CQP_WQE_SIZE * 8);
-
- if (post_sq)
- i40iw_sc_cqp_post_sq(cqp);
- return 0;
-}
-
-const struct i40iw_vf_cqp_ops iw_vf_cqp_ops = {
- i40iw_manage_vf_pble_bp
-};
diff --git a/drivers/infiniband/hw/i40iw/i40iw_vf.h b/drivers/infiniband/hw/i40iw/i40iw_vf.h
deleted file mode 100644
index 4359559ece9c..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_vf.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_VF_H
-#define I40IW_VF_H
-
-struct i40iw_sc_cqp;
-
-struct i40iw_manage_vf_pble_info {
- u32 sd_index;
- u16 first_pd_index;
- u16 pd_entry_cnt;
- u8 inv_pd_ent;
- u64 pd_pl_pba;
-};
-
-struct i40iw_vf_cqp_ops {
- enum i40iw_status_code (*manage_vf_pble_bp)(struct i40iw_sc_cqp *,
- struct i40iw_manage_vf_pble_info *,
- u64,
- bool);
-};
-
-enum i40iw_status_code i40iw_manage_vf_pble_bp(struct i40iw_sc_cqp *cqp,
- struct i40iw_manage_vf_pble_info *info,
- u64 scratch,
- bool post_sq);
-
-extern const struct i40iw_vf_cqp_ops iw_vf_cqp_ops;
-
-#endif
diff --git a/drivers/infiniband/hw/i40iw/i40iw_virtchnl.c b/drivers/infiniband/hw/i40iw/i40iw_virtchnl.c
deleted file mode 100644
index e34a1522132c..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_virtchnl.c
+++ /dev/null
@@ -1,759 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 "i40iw_osdep.h"
-#include "i40iw_register.h"
-#include "i40iw_status.h"
-#include "i40iw_hmc.h"
-#include "i40iw_d.h"
-#include "i40iw_type.h"
-#include "i40iw_p.h"
-#include "i40iw_virtchnl.h"
-
-/**
- * vchnl_vf_send_get_ver_req - Request Channel version
- * @dev: IWARP device pointer
- * @vchnl_req: Virtual channel message request pointer
- */
-static enum i40iw_status_code vchnl_vf_send_get_ver_req(struct i40iw_sc_dev *dev,
- struct i40iw_virtchnl_req *vchnl_req)
-{
- enum i40iw_status_code ret_code = I40IW_ERR_NOT_READY;
- struct i40iw_virtchnl_op_buf *vchnl_msg = vchnl_req->vchnl_msg;
-
- if (!dev->vchnl_up)
- return ret_code;
-
- memset(vchnl_msg, 0, sizeof(*vchnl_msg));
- vchnl_msg->iw_chnl_op_ctx = (uintptr_t)vchnl_req;
- vchnl_msg->iw_chnl_buf_len = sizeof(*vchnl_msg);
- vchnl_msg->iw_op_code = I40IW_VCHNL_OP_GET_VER;
- vchnl_msg->iw_op_ver = I40IW_VCHNL_OP_GET_VER_V0;
- ret_code = dev->vchnl_if.vchnl_send(dev, 0, (u8 *)vchnl_msg, vchnl_msg->iw_chnl_buf_len);
- if (ret_code)
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s: virt channel send failed 0x%x\n", __func__, ret_code);
- return ret_code;
-}
-
-/**
- * vchnl_vf_send_get_hmc_fcn_req - Request HMC Function from VF
- * @dev: IWARP device pointer
- * @vchnl_req: Virtual channel message request pointer
- */
-static enum i40iw_status_code vchnl_vf_send_get_hmc_fcn_req(struct i40iw_sc_dev *dev,
- struct i40iw_virtchnl_req *vchnl_req)
-{
- enum i40iw_status_code ret_code = I40IW_ERR_NOT_READY;
- struct i40iw_virtchnl_op_buf *vchnl_msg = vchnl_req->vchnl_msg;
-
- if (!dev->vchnl_up)
- return ret_code;
-
- memset(vchnl_msg, 0, sizeof(*vchnl_msg));
- vchnl_msg->iw_chnl_op_ctx = (uintptr_t)vchnl_req;
- vchnl_msg->iw_chnl_buf_len = sizeof(*vchnl_msg);
- vchnl_msg->iw_op_code = I40IW_VCHNL_OP_GET_HMC_FCN;
- vchnl_msg->iw_op_ver = I40IW_VCHNL_OP_GET_HMC_FCN_V0;
- ret_code = dev->vchnl_if.vchnl_send(dev, 0, (u8 *)vchnl_msg, vchnl_msg->iw_chnl_buf_len);
- if (ret_code)
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s: virt channel send failed 0x%x\n", __func__, ret_code);
- return ret_code;
-}
-
-/**
- * vchnl_vf_send_get_pe_stats_req - Request PE stats from VF
- * @dev: IWARP device pointer
- * @vchnl_req: Virtual channel message request pointer
- */
-static enum i40iw_status_code vchnl_vf_send_get_pe_stats_req(struct i40iw_sc_dev *dev,
- struct i40iw_virtchnl_req *vchnl_req)
-{
- enum i40iw_status_code ret_code = I40IW_ERR_NOT_READY;
- struct i40iw_virtchnl_op_buf *vchnl_msg = vchnl_req->vchnl_msg;
-
- if (!dev->vchnl_up)
- return ret_code;
-
- memset(vchnl_msg, 0, sizeof(*vchnl_msg));
- vchnl_msg->iw_chnl_op_ctx = (uintptr_t)vchnl_req;
- vchnl_msg->iw_chnl_buf_len = sizeof(*vchnl_msg) + sizeof(struct i40iw_dev_hw_stats) - 1;
- vchnl_msg->iw_op_code = I40IW_VCHNL_OP_GET_STATS;
- vchnl_msg->iw_op_ver = I40IW_VCHNL_OP_GET_STATS_V0;
- ret_code = dev->vchnl_if.vchnl_send(dev, 0, (u8 *)vchnl_msg, vchnl_msg->iw_chnl_buf_len);
- if (ret_code)
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s: virt channel send failed 0x%x\n", __func__, ret_code);
- return ret_code;
-}
-
-/*
- * vchnl_vf_send_add_hmc_objs_req - Add HMC objects
- * @dev: IWARP device pointer
- * @vchnl_req: Virtual channel message request pointer
- */
-static enum i40iw_status_code vchnl_vf_send_add_hmc_objs_req(struct i40iw_sc_dev *dev,
- struct i40iw_virtchnl_req *vchnl_req,
- enum i40iw_hmc_rsrc_type rsrc_type,
- u32 start_index,
- u32 rsrc_count)
-{
- enum i40iw_status_code ret_code = I40IW_ERR_NOT_READY;
- struct i40iw_virtchnl_op_buf *vchnl_msg = vchnl_req->vchnl_msg;
- struct i40iw_virtchnl_hmc_obj_range *add_hmc_obj;
-
- if (!dev->vchnl_up)
- return ret_code;
-
- add_hmc_obj = (struct i40iw_virtchnl_hmc_obj_range *)vchnl_msg->iw_chnl_buf;
- memset(vchnl_msg, 0, sizeof(*vchnl_msg));
- memset(add_hmc_obj, 0, sizeof(*add_hmc_obj));
- vchnl_msg->iw_chnl_op_ctx = (uintptr_t)vchnl_req;
- vchnl_msg->iw_chnl_buf_len = sizeof(*vchnl_msg) + sizeof(struct i40iw_virtchnl_hmc_obj_range) - 1;
- vchnl_msg->iw_op_code = I40IW_VCHNL_OP_ADD_HMC_OBJ_RANGE;
- vchnl_msg->iw_op_ver = I40IW_VCHNL_OP_ADD_HMC_OBJ_RANGE_V0;
- add_hmc_obj->obj_type = (u16)rsrc_type;
- add_hmc_obj->start_index = start_index;
- add_hmc_obj->obj_count = rsrc_count;
- ret_code = dev->vchnl_if.vchnl_send(dev, 0, (u8 *)vchnl_msg, vchnl_msg->iw_chnl_buf_len);
- if (ret_code)
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s: virt channel send failed 0x%x\n", __func__, ret_code);
- return ret_code;
-}
-
-/**
- * vchnl_vf_send_del_hmc_objs_req - del HMC objects
- * @dev: IWARP device pointer
- * @vchnl_req: Virtual channel message request pointer
- * @rsrc_type: resource type to delete
- * @start_index: starting index for resource
- * @rsrc_count: number of resource type to delete
- */
-static enum i40iw_status_code vchnl_vf_send_del_hmc_objs_req(struct i40iw_sc_dev *dev,
- struct i40iw_virtchnl_req *vchnl_req,
- enum i40iw_hmc_rsrc_type rsrc_type,
- u32 start_index,
- u32 rsrc_count)
-{
- enum i40iw_status_code ret_code = I40IW_ERR_NOT_READY;
- struct i40iw_virtchnl_op_buf *vchnl_msg = vchnl_req->vchnl_msg;
- struct i40iw_virtchnl_hmc_obj_range *add_hmc_obj;
-
- if (!dev->vchnl_up)
- return ret_code;
-
- add_hmc_obj = (struct i40iw_virtchnl_hmc_obj_range *)vchnl_msg->iw_chnl_buf;
- memset(vchnl_msg, 0, sizeof(*vchnl_msg));
- memset(add_hmc_obj, 0, sizeof(*add_hmc_obj));
- vchnl_msg->iw_chnl_op_ctx = (uintptr_t)vchnl_req;
- vchnl_msg->iw_chnl_buf_len = sizeof(*vchnl_msg) + sizeof(struct i40iw_virtchnl_hmc_obj_range) - 1;
- vchnl_msg->iw_op_code = I40IW_VCHNL_OP_DEL_HMC_OBJ_RANGE;
- vchnl_msg->iw_op_ver = I40IW_VCHNL_OP_DEL_HMC_OBJ_RANGE_V0;
- add_hmc_obj->obj_type = (u16)rsrc_type;
- add_hmc_obj->start_index = start_index;
- add_hmc_obj->obj_count = rsrc_count;
- ret_code = dev->vchnl_if.vchnl_send(dev, 0, (u8 *)vchnl_msg, vchnl_msg->iw_chnl_buf_len);
- if (ret_code)
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s: virt channel send failed 0x%x\n", __func__, ret_code);
- return ret_code;
-}
-
-/**
- * vchnl_pf_send_get_ver_resp - Send channel version to VF
- * @dev: IWARP device pointer
- * @vf_id: Virtual function ID associated with the message
- * @vchnl_msg: Virtual channel message buffer pointer
- */
-static void vchnl_pf_send_get_ver_resp(struct i40iw_sc_dev *dev,
- u32 vf_id,
- struct i40iw_virtchnl_op_buf *vchnl_msg)
-{
- enum i40iw_status_code ret_code;
- u8 resp_buffer[sizeof(struct i40iw_virtchnl_resp_buf) + sizeof(u32) - 1];
- struct i40iw_virtchnl_resp_buf *vchnl_msg_resp = (struct i40iw_virtchnl_resp_buf *)resp_buffer;
-
- memset(resp_buffer, 0, sizeof(*resp_buffer));
- vchnl_msg_resp->iw_chnl_op_ctx = vchnl_msg->iw_chnl_op_ctx;
- vchnl_msg_resp->iw_chnl_buf_len = sizeof(resp_buffer);
- vchnl_msg_resp->iw_op_ret_code = I40IW_SUCCESS;
- *((u32 *)vchnl_msg_resp->iw_chnl_buf) = I40IW_VCHNL_CHNL_VER_V0;
- ret_code = dev->vchnl_if.vchnl_send(dev, vf_id, resp_buffer, sizeof(resp_buffer));
- if (ret_code)
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s: virt channel send failed 0x%x\n", __func__, ret_code);
-}
-
-/**
- * vchnl_pf_send_get_hmc_fcn_resp - Send HMC Function to VF
- * @dev: IWARP device pointer
- * @vf_id: Virtual function ID associated with the message
- * @vchnl_msg: Virtual channel message buffer pointer
- * @hmc_fcn: HMC function index pointer
- */
-static void vchnl_pf_send_get_hmc_fcn_resp(struct i40iw_sc_dev *dev,
- u32 vf_id,
- struct i40iw_virtchnl_op_buf *vchnl_msg,
- u16 hmc_fcn)
-{
- enum i40iw_status_code ret_code;
- u8 resp_buffer[sizeof(struct i40iw_virtchnl_resp_buf) + sizeof(u16) - 1];
- struct i40iw_virtchnl_resp_buf *vchnl_msg_resp = (struct i40iw_virtchnl_resp_buf *)resp_buffer;
-
- memset(resp_buffer, 0, sizeof(*resp_buffer));
- vchnl_msg_resp->iw_chnl_op_ctx = vchnl_msg->iw_chnl_op_ctx;
- vchnl_msg_resp->iw_chnl_buf_len = sizeof(resp_buffer);
- vchnl_msg_resp->iw_op_ret_code = I40IW_SUCCESS;
- *((u16 *)vchnl_msg_resp->iw_chnl_buf) = hmc_fcn;
- ret_code = dev->vchnl_if.vchnl_send(dev, vf_id, resp_buffer, sizeof(resp_buffer));
- if (ret_code)
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s: virt channel send failed 0x%x\n", __func__, ret_code);
-}
-
-/**
- * vchnl_pf_send_get_pe_stats_resp - Send PE Stats to VF
- * @dev: IWARP device pointer
- * @vf_id: Virtual function ID associated with the message
- * @vchnl_msg: Virtual channel message buffer pointer
- * @hw_stats: HW Stats struct
- */
-
-static void vchnl_pf_send_get_pe_stats_resp(struct i40iw_sc_dev *dev,
- u32 vf_id,
- struct i40iw_virtchnl_op_buf *vchnl_msg,
- struct i40iw_dev_hw_stats *hw_stats)
-{
- enum i40iw_status_code ret_code;
- u8 resp_buffer[sizeof(struct i40iw_virtchnl_resp_buf) + sizeof(struct i40iw_dev_hw_stats) - 1];
- struct i40iw_virtchnl_resp_buf *vchnl_msg_resp = (struct i40iw_virtchnl_resp_buf *)resp_buffer;
-
- memset(resp_buffer, 0, sizeof(*resp_buffer));
- vchnl_msg_resp->iw_chnl_op_ctx = vchnl_msg->iw_chnl_op_ctx;
- vchnl_msg_resp->iw_chnl_buf_len = sizeof(resp_buffer);
- vchnl_msg_resp->iw_op_ret_code = I40IW_SUCCESS;
- *((struct i40iw_dev_hw_stats *)vchnl_msg_resp->iw_chnl_buf) = *hw_stats;
- ret_code = dev->vchnl_if.vchnl_send(dev, vf_id, resp_buffer, sizeof(resp_buffer));
- if (ret_code)
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s: virt channel send failed 0x%x\n", __func__, ret_code);
-}
-
-/**
- * vchnl_pf_send_error_resp - Send an error response to VF
- * @dev: IWARP device pointer
- * @vf_id: Virtual function ID associated with the message
- * @vchnl_msg: Virtual channel message buffer pointer
- * @op_ret_code: I40IW_ERR_* status code
- */
-static void vchnl_pf_send_error_resp(struct i40iw_sc_dev *dev, u32 vf_id,
- struct i40iw_virtchnl_op_buf *vchnl_msg,
- u16 op_ret_code)
-{
- enum i40iw_status_code ret_code;
- u8 resp_buffer[sizeof(struct i40iw_virtchnl_resp_buf)];
- struct i40iw_virtchnl_resp_buf *vchnl_msg_resp = (struct i40iw_virtchnl_resp_buf *)resp_buffer;
-
- memset(resp_buffer, 0, sizeof(resp_buffer));
- vchnl_msg_resp->iw_chnl_op_ctx = vchnl_msg->iw_chnl_op_ctx;
- vchnl_msg_resp->iw_chnl_buf_len = sizeof(resp_buffer);
- vchnl_msg_resp->iw_op_ret_code = (u16)op_ret_code;
- ret_code = dev->vchnl_if.vchnl_send(dev, vf_id, resp_buffer, sizeof(resp_buffer));
- if (ret_code)
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s: virt channel send failed 0x%x\n", __func__, ret_code);
-}
-
-/**
- * pf_cqp_get_hmc_fcn_callback - Callback for Get HMC Fcn
- * @dev: IWARP device pointer
- * @callback_param: unused CQP callback parameter
- * @cqe_info: CQE information pointer
- */
-static void pf_cqp_get_hmc_fcn_callback(struct i40iw_sc_dev *dev, void *callback_param,
- struct i40iw_ccq_cqe_info *cqe_info)
-{
- struct i40iw_vfdev *vf_dev = callback_param;
- struct i40iw_virt_mem vf_dev_mem;
-
- if (cqe_info->error) {
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "CQP Completion Error on Get HMC Function. Maj = 0x%04x, Minor = 0x%04x\n",
- cqe_info->maj_err_code, cqe_info->min_err_code);
- dev->vf_dev[vf_dev->iw_vf_idx] = NULL;
- vchnl_pf_send_error_resp(dev, vf_dev->vf_id, &vf_dev->vf_msg_buffer.vchnl_msg,
- (u16)I40IW_ERR_CQP_COMPL_ERROR);
- vf_dev_mem.va = vf_dev;
- vf_dev_mem.size = sizeof(*vf_dev);
- i40iw_free_virt_mem(dev->hw, &vf_dev_mem);
- } else {
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "CQP Completion Operation Return information = 0x%08x\n",
- cqe_info->op_ret_val);
- vf_dev->pmf_index = (u16)cqe_info->op_ret_val;
- vf_dev->msg_count--;
- vchnl_pf_send_get_hmc_fcn_resp(dev,
- vf_dev->vf_id,
- &vf_dev->vf_msg_buffer.vchnl_msg,
- vf_dev->pmf_index);
- }
-}
-
-/**
- * pf_add_hmc_obj_callback - Callback for Add HMC Object
- * @work_vf_dev: pointer to the VF Device
- */
-static void pf_add_hmc_obj_callback(void *work_vf_dev)
-{
- struct i40iw_vfdev *vf_dev = (struct i40iw_vfdev *)work_vf_dev;
- struct i40iw_hmc_info *hmc_info = &vf_dev->hmc_info;
- struct i40iw_virtchnl_op_buf *vchnl_msg = &vf_dev->vf_msg_buffer.vchnl_msg;
- struct i40iw_hmc_create_obj_info info;
- struct i40iw_virtchnl_hmc_obj_range *add_hmc_obj;
- enum i40iw_status_code ret_code;
-
- if (!vf_dev->pf_hmc_initialized) {
- ret_code = i40iw_pf_init_vfhmc(vf_dev->pf_dev, (u8)vf_dev->pmf_index, NULL);
- if (ret_code)
- goto add_out;
- vf_dev->pf_hmc_initialized = true;
- }
-
- add_hmc_obj = (struct i40iw_virtchnl_hmc_obj_range *)vchnl_msg->iw_chnl_buf;
-
- memset(&info, 0, sizeof(info));
- info.hmc_info = hmc_info;
- info.is_pf = false;
- info.rsrc_type = (u32)add_hmc_obj->obj_type;
- info.entry_type = (info.rsrc_type == I40IW_HMC_IW_PBLE) ? I40IW_SD_TYPE_PAGED : I40IW_SD_TYPE_DIRECT;
- info.start_idx = add_hmc_obj->start_index;
- info.count = add_hmc_obj->obj_count;
- i40iw_debug(vf_dev->pf_dev, I40IW_DEBUG_VIRT,
- "I40IW_VCHNL_OP_ADD_HMC_OBJ_RANGE. Add %u type %u objects\n",
- info.count, info.rsrc_type);
- ret_code = i40iw_sc_create_hmc_obj(vf_dev->pf_dev, &info);
- if (!ret_code)
- vf_dev->hmc_info.hmc_obj[add_hmc_obj->obj_type].cnt = add_hmc_obj->obj_count;
-add_out:
- vf_dev->msg_count--;
- vchnl_pf_send_error_resp(vf_dev->pf_dev, vf_dev->vf_id, vchnl_msg, (u16)ret_code);
-}
-
-/**
- * pf_del_hmc_obj_callback - Callback for delete HMC Object
- * @work_vf_dev: pointer to the VF Device
- */
-static void pf_del_hmc_obj_callback(void *work_vf_dev)
-{
- struct i40iw_vfdev *vf_dev = (struct i40iw_vfdev *)work_vf_dev;
- struct i40iw_hmc_info *hmc_info = &vf_dev->hmc_info;
- struct i40iw_virtchnl_op_buf *vchnl_msg = &vf_dev->vf_msg_buffer.vchnl_msg;
- struct i40iw_hmc_del_obj_info info;
- struct i40iw_virtchnl_hmc_obj_range *del_hmc_obj;
- enum i40iw_status_code ret_code = I40IW_SUCCESS;
-
- if (!vf_dev->pf_hmc_initialized)
- goto del_out;
-
- del_hmc_obj = (struct i40iw_virtchnl_hmc_obj_range *)vchnl_msg->iw_chnl_buf;
-
- memset(&info, 0, sizeof(info));
- info.hmc_info = hmc_info;
- info.is_pf = false;
- info.rsrc_type = (u32)del_hmc_obj->obj_type;
- info.start_idx = del_hmc_obj->start_index;
- info.count = del_hmc_obj->obj_count;
- i40iw_debug(vf_dev->pf_dev, I40IW_DEBUG_VIRT,
- "I40IW_VCHNL_OP_DEL_HMC_OBJ_RANGE. Delete %u type %u objects\n",
- info.count, info.rsrc_type);
- ret_code = i40iw_sc_del_hmc_obj(vf_dev->pf_dev, &info, false);
-del_out:
- vf_dev->msg_count--;
- vchnl_pf_send_error_resp(vf_dev->pf_dev, vf_dev->vf_id, vchnl_msg, (u16)ret_code);
-}
-
-/**
- * i40iw_vf_init_pestat - Initialize stats for VF
- * @dev: pointer to the VF Device
- * @stats: Statistics structure pointer
- * @index: Stats index
- */
-static void i40iw_vf_init_pestat(struct i40iw_sc_dev *dev, struct i40iw_vsi_pestat *stats, u16 index)
-{
- stats->hw = dev->hw;
- i40iw_hw_stats_init(stats, (u8)index, false);
- spin_lock_init(&stats->lock);
-}
-
-/**
- * i40iw_vchnl_recv_pf - Receive PF virtual channel messages
- * @dev: IWARP device pointer
- * @vf_id: Virtual function ID associated with the message
- * @msg: Virtual channel message buffer pointer
- * @len: Length of the virtual channels message
- */
-enum i40iw_status_code i40iw_vchnl_recv_pf(struct i40iw_sc_dev *dev,
- u32 vf_id,
- u8 *msg,
- u16 len)
-{
- struct i40iw_virtchnl_op_buf *vchnl_msg = (struct i40iw_virtchnl_op_buf *)msg;
- struct i40iw_vfdev *vf_dev = NULL;
- struct i40iw_hmc_fcn_info hmc_fcn_info;
- u16 iw_vf_idx;
- u16 first_avail_iw_vf = I40IW_MAX_PE_ENABLED_VF_COUNT;
- struct i40iw_virt_mem vf_dev_mem;
- struct i40iw_virtchnl_work_info work_info;
- struct i40iw_vsi_pestat *stats;
- enum i40iw_status_code ret_code;
-
- if (!dev || !msg || !len)
- return I40IW_ERR_PARAM;
-
- if (!dev->vchnl_up)
- return I40IW_ERR_NOT_READY;
- if (vchnl_msg->iw_op_code == I40IW_VCHNL_OP_GET_VER) {
- vchnl_pf_send_get_ver_resp(dev, vf_id, vchnl_msg);
- return I40IW_SUCCESS;
- }
- for (iw_vf_idx = 0; iw_vf_idx < I40IW_MAX_PE_ENABLED_VF_COUNT; iw_vf_idx++) {
- if (!dev->vf_dev[iw_vf_idx]) {
- if (first_avail_iw_vf == I40IW_MAX_PE_ENABLED_VF_COUNT)
- first_avail_iw_vf = iw_vf_idx;
- continue;
- }
- if (dev->vf_dev[iw_vf_idx]->vf_id == vf_id) {
- vf_dev = dev->vf_dev[iw_vf_idx];
- break;
- }
- }
- if (vf_dev) {
- if (!vf_dev->msg_count) {
- vf_dev->msg_count++;
- } else {
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "VF%u already has a channel message in progress.\n",
- vf_id);
- return I40IW_SUCCESS;
- }
- }
- switch (vchnl_msg->iw_op_code) {
- case I40IW_VCHNL_OP_GET_HMC_FCN:
- if (!vf_dev &&
- (first_avail_iw_vf != I40IW_MAX_PE_ENABLED_VF_COUNT)) {
- ret_code = i40iw_allocate_virt_mem(dev->hw, &vf_dev_mem, sizeof(struct i40iw_vfdev) +
- (sizeof(struct i40iw_hmc_obj_info) * I40IW_HMC_IW_MAX));
- if (!ret_code) {
- vf_dev = vf_dev_mem.va;
- vf_dev->stats_initialized = false;
- vf_dev->pf_dev = dev;
- vf_dev->msg_count = 1;
- vf_dev->vf_id = vf_id;
- vf_dev->iw_vf_idx = first_avail_iw_vf;
- vf_dev->pf_hmc_initialized = false;
- vf_dev->hmc_info.hmc_obj = (struct i40iw_hmc_obj_info *)(&vf_dev[1]);
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "vf_dev %p, hmc_info %p, hmc_obj %p\n",
- vf_dev, &vf_dev->hmc_info, vf_dev->hmc_info.hmc_obj);
- dev->vf_dev[first_avail_iw_vf] = vf_dev;
- iw_vf_idx = first_avail_iw_vf;
- } else {
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "VF%u Unable to allocate a VF device structure.\n",
- vf_id);
- vchnl_pf_send_error_resp(dev, vf_id, vchnl_msg, (u16)I40IW_ERR_NO_MEMORY);
- return I40IW_SUCCESS;
- }
- memcpy(&vf_dev->vf_msg_buffer.vchnl_msg, vchnl_msg, len);
- hmc_fcn_info.callback_fcn = pf_cqp_get_hmc_fcn_callback;
- hmc_fcn_info.vf_id = vf_id;
- hmc_fcn_info.iw_vf_idx = vf_dev->iw_vf_idx;
- hmc_fcn_info.cqp_callback_param = vf_dev;
- hmc_fcn_info.free_fcn = false;
- ret_code = i40iw_cqp_manage_hmc_fcn_cmd(dev, &hmc_fcn_info);
- if (ret_code)
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "VF%u error CQP HMC Function operation.\n",
- vf_id);
- i40iw_vf_init_pestat(dev, &vf_dev->pestat, vf_dev->pmf_index);
- vf_dev->stats_initialized = true;
- } else {
- if (vf_dev) {
- vf_dev->msg_count--;
- vchnl_pf_send_get_hmc_fcn_resp(dev, vf_id, vchnl_msg, vf_dev->pmf_index);
- } else {
- vchnl_pf_send_error_resp(dev, vf_id, vchnl_msg,
- (u16)I40IW_ERR_NO_MEMORY);
- }
- }
- break;
- case I40IW_VCHNL_OP_ADD_HMC_OBJ_RANGE:
- if (!vf_dev)
- return I40IW_ERR_BAD_PTR;
- work_info.worker_vf_dev = vf_dev;
- work_info.callback_fcn = pf_add_hmc_obj_callback;
- memcpy(&vf_dev->vf_msg_buffer.vchnl_msg, vchnl_msg, len);
- i40iw_cqp_spawn_worker(dev, &work_info, vf_dev->iw_vf_idx);
- break;
- case I40IW_VCHNL_OP_DEL_HMC_OBJ_RANGE:
- if (!vf_dev)
- return I40IW_ERR_BAD_PTR;
- work_info.worker_vf_dev = vf_dev;
- work_info.callback_fcn = pf_del_hmc_obj_callback;
- memcpy(&vf_dev->vf_msg_buffer.vchnl_msg, vchnl_msg, len);
- i40iw_cqp_spawn_worker(dev, &work_info, vf_dev->iw_vf_idx);
- break;
- case I40IW_VCHNL_OP_GET_STATS:
- if (!vf_dev)
- return I40IW_ERR_BAD_PTR;
- stats = &vf_dev->pestat;
- i40iw_hw_stats_read_all(stats, &stats->hw_stats);
- vf_dev->msg_count--;
- vchnl_pf_send_get_pe_stats_resp(dev, vf_id, vchnl_msg, &stats->hw_stats);
- break;
- default:
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "40iw_vchnl_recv_pf: Invalid OpCode 0x%x\n",
- vchnl_msg->iw_op_code);
- vchnl_pf_send_error_resp(dev, vf_id,
- vchnl_msg, (u16)I40IW_ERR_NOT_IMPLEMENTED);
- }
- return I40IW_SUCCESS;
-}
-
-/**
- * i40iw_vchnl_recv_vf - Receive VF virtual channel messages
- * @dev: IWARP device pointer
- * @vf_id: Virtual function ID associated with the message
- * @msg: Virtual channel message buffer pointer
- * @len: Length of the virtual channels message
- */
-enum i40iw_status_code i40iw_vchnl_recv_vf(struct i40iw_sc_dev *dev,
- u32 vf_id,
- u8 *msg,
- u16 len)
-{
- struct i40iw_virtchnl_resp_buf *vchnl_msg_resp = (struct i40iw_virtchnl_resp_buf *)msg;
- struct i40iw_virtchnl_req *vchnl_req;
-
- vchnl_req = (struct i40iw_virtchnl_req *)(uintptr_t)vchnl_msg_resp->iw_chnl_op_ctx;
- vchnl_req->ret_code = (enum i40iw_status_code)vchnl_msg_resp->iw_op_ret_code;
- if (len == (sizeof(*vchnl_msg_resp) + vchnl_req->parm_len - 1)) {
- if (vchnl_req->parm_len && vchnl_req->parm)
- memcpy(vchnl_req->parm, vchnl_msg_resp->iw_chnl_buf, vchnl_req->parm_len);
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s: Got response, data size %u\n", __func__,
- vchnl_req->parm_len);
- } else {
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s: error length on response, Got %u, expected %u\n", __func__,
- len, (u32)(sizeof(*vchnl_msg_resp) + vchnl_req->parm_len - 1));
- }
-
- return I40IW_SUCCESS;
-}
-
-/**
- * i40iw_vchnl_vf_get_ver - Request Channel version
- * @dev: IWARP device pointer
- * @vchnl_ver: Virtual channel message version pointer
- */
-enum i40iw_status_code i40iw_vchnl_vf_get_ver(struct i40iw_sc_dev *dev,
- u32 *vchnl_ver)
-{
- struct i40iw_virtchnl_req vchnl_req;
- enum i40iw_status_code ret_code;
-
- if (!i40iw_vf_clear_to_send(dev))
- return I40IW_ERR_TIMEOUT;
- memset(&vchnl_req, 0, sizeof(vchnl_req));
- vchnl_req.dev = dev;
- vchnl_req.parm = vchnl_ver;
- vchnl_req.parm_len = sizeof(*vchnl_ver);
- vchnl_req.vchnl_msg = &dev->vchnl_vf_msg_buf.vchnl_msg;
-
- ret_code = vchnl_vf_send_get_ver_req(dev, &vchnl_req);
- if (ret_code) {
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s Send message failed 0x%0x\n", __func__, ret_code);
- return ret_code;
- }
- ret_code = i40iw_vf_wait_vchnl_resp(dev);
- if (ret_code)
- return ret_code;
- else
- return vchnl_req.ret_code;
-}
-
-/**
- * i40iw_vchnl_vf_get_hmc_fcn - Request HMC Function
- * @dev: IWARP device pointer
- * @hmc_fcn: HMC function index pointer
- */
-enum i40iw_status_code i40iw_vchnl_vf_get_hmc_fcn(struct i40iw_sc_dev *dev,
- u16 *hmc_fcn)
-{
- struct i40iw_virtchnl_req vchnl_req;
- enum i40iw_status_code ret_code;
-
- if (!i40iw_vf_clear_to_send(dev))
- return I40IW_ERR_TIMEOUT;
- memset(&vchnl_req, 0, sizeof(vchnl_req));
- vchnl_req.dev = dev;
- vchnl_req.parm = hmc_fcn;
- vchnl_req.parm_len = sizeof(*hmc_fcn);
- vchnl_req.vchnl_msg = &dev->vchnl_vf_msg_buf.vchnl_msg;
-
- ret_code = vchnl_vf_send_get_hmc_fcn_req(dev, &vchnl_req);
- if (ret_code) {
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s Send message failed 0x%0x\n", __func__, ret_code);
- return ret_code;
- }
- ret_code = i40iw_vf_wait_vchnl_resp(dev);
- if (ret_code)
- return ret_code;
- else
- return vchnl_req.ret_code;
-}
-
-/**
- * i40iw_vchnl_vf_add_hmc_objs - Add HMC Object
- * @dev: IWARP device pointer
- * @rsrc_type: HMC Resource type
- * @start_index: Starting index of the objects to be added
- * @rsrc_count: Number of resources to be added
- */
-enum i40iw_status_code i40iw_vchnl_vf_add_hmc_objs(struct i40iw_sc_dev *dev,
- enum i40iw_hmc_rsrc_type rsrc_type,
- u32 start_index,
- u32 rsrc_count)
-{
- struct i40iw_virtchnl_req vchnl_req;
- enum i40iw_status_code ret_code;
-
- if (!i40iw_vf_clear_to_send(dev))
- return I40IW_ERR_TIMEOUT;
- memset(&vchnl_req, 0, sizeof(vchnl_req));
- vchnl_req.dev = dev;
- vchnl_req.vchnl_msg = &dev->vchnl_vf_msg_buf.vchnl_msg;
-
- ret_code = vchnl_vf_send_add_hmc_objs_req(dev,
- &vchnl_req,
- rsrc_type,
- start_index,
- rsrc_count);
- if (ret_code) {
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s Send message failed 0x%0x\n", __func__, ret_code);
- return ret_code;
- }
- ret_code = i40iw_vf_wait_vchnl_resp(dev);
- if (ret_code)
- return ret_code;
- else
- return vchnl_req.ret_code;
-}
-
-/**
- * i40iw_vchnl_vf_del_hmc_obj - del HMC obj
- * @dev: IWARP device pointer
- * @rsrc_type: HMC Resource type
- * @start_index: Starting index of the object to delete
- * @rsrc_count: Number of resources to be delete
- */
-enum i40iw_status_code i40iw_vchnl_vf_del_hmc_obj(struct i40iw_sc_dev *dev,
- enum i40iw_hmc_rsrc_type rsrc_type,
- u32 start_index,
- u32 rsrc_count)
-{
- struct i40iw_virtchnl_req vchnl_req;
- enum i40iw_status_code ret_code;
-
- if (!i40iw_vf_clear_to_send(dev))
- return I40IW_ERR_TIMEOUT;
- memset(&vchnl_req, 0, sizeof(vchnl_req));
- vchnl_req.dev = dev;
- vchnl_req.vchnl_msg = &dev->vchnl_vf_msg_buf.vchnl_msg;
-
- ret_code = vchnl_vf_send_del_hmc_objs_req(dev,
- &vchnl_req,
- rsrc_type,
- start_index,
- rsrc_count);
- if (ret_code) {
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s Send message failed 0x%0x\n", __func__, ret_code);
- return ret_code;
- }
- ret_code = i40iw_vf_wait_vchnl_resp(dev);
- if (ret_code)
- return ret_code;
- else
- return vchnl_req.ret_code;
-}
-
-/**
- * i40iw_vchnl_vf_get_pe_stats - Get PE stats
- * @dev: IWARP device pointer
- * @hw_stats: HW stats struct
- */
-enum i40iw_status_code i40iw_vchnl_vf_get_pe_stats(struct i40iw_sc_dev *dev,
- struct i40iw_dev_hw_stats *hw_stats)
-{
- struct i40iw_virtchnl_req vchnl_req;
- enum i40iw_status_code ret_code;
-
- if (!i40iw_vf_clear_to_send(dev))
- return I40IW_ERR_TIMEOUT;
- memset(&vchnl_req, 0, sizeof(vchnl_req));
- vchnl_req.dev = dev;
- vchnl_req.parm = hw_stats;
- vchnl_req.parm_len = sizeof(*hw_stats);
- vchnl_req.vchnl_msg = &dev->vchnl_vf_msg_buf.vchnl_msg;
-
- ret_code = vchnl_vf_send_get_pe_stats_req(dev, &vchnl_req);
- if (ret_code) {
- i40iw_debug(dev, I40IW_DEBUG_VIRT,
- "%s Send message failed 0x%0x\n", __func__, ret_code);
- return ret_code;
- }
- ret_code = i40iw_vf_wait_vchnl_resp(dev);
- if (ret_code)
- return ret_code;
- else
- return vchnl_req.ret_code;
-}
diff --git a/drivers/infiniband/hw/i40iw/i40iw_virtchnl.h b/drivers/infiniband/hw/i40iw/i40iw_virtchnl.h
deleted file mode 100644
index 24886ef08293..000000000000
--- a/drivers/infiniband/hw/i40iw/i40iw_virtchnl.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*******************************************************************************
-*
-* Copyright (c) 2015-2016 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
-* OpenFabrics.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 I40IW_VIRTCHNL_H
-#define I40IW_VIRTCHNL_H
-
-#include "i40iw_hmc.h"
-
-#pragma pack(push, 1)
-
-struct i40iw_virtchnl_op_buf {
- u16 iw_op_code;
- u16 iw_op_ver;
- u16 iw_chnl_buf_len;
- u16 rsvd;
- u64 iw_chnl_op_ctx;
- /* Member alignment MUST be maintained above this location */
- u8 iw_chnl_buf[1];
-};
-
-struct i40iw_virtchnl_resp_buf {
- u64 iw_chnl_op_ctx;
- u16 iw_chnl_buf_len;
- s16 iw_op_ret_code;
- /* Member alignment MUST be maintained above this location */
- u16 rsvd[2];
- u8 iw_chnl_buf[1];
-};
-
-enum i40iw_virtchnl_ops {
- I40IW_VCHNL_OP_GET_VER = 0,
- I40IW_VCHNL_OP_GET_HMC_FCN,
- I40IW_VCHNL_OP_ADD_HMC_OBJ_RANGE,
- I40IW_VCHNL_OP_DEL_HMC_OBJ_RANGE,
- I40IW_VCHNL_OP_GET_STATS
-};
-
-#define I40IW_VCHNL_OP_GET_VER_V0 0
-#define I40IW_VCHNL_OP_GET_HMC_FCN_V0 0
-#define I40IW_VCHNL_OP_ADD_HMC_OBJ_RANGE_V0 0
-#define I40IW_VCHNL_OP_DEL_HMC_OBJ_RANGE_V0 0
-#define I40IW_VCHNL_OP_GET_STATS_V0 0
-#define I40IW_VCHNL_CHNL_VER_V0 0
-
-struct i40iw_dev_hw_stats;
-
-struct i40iw_virtchnl_hmc_obj_range {
- u16 obj_type;
- u16 rsvd;
- u32 start_index;
- u32 obj_count;
-};
-
-enum i40iw_status_code i40iw_vchnl_recv_pf(struct i40iw_sc_dev *dev,
- u32 vf_id,
- u8 *msg,
- u16 len);
-
-enum i40iw_status_code i40iw_vchnl_recv_vf(struct i40iw_sc_dev *dev,
- u32 vf_id,
- u8 *msg,
- u16 len);
-
-struct i40iw_virtchnl_req {
- struct i40iw_sc_dev *dev;
- struct i40iw_virtchnl_op_buf *vchnl_msg;
- void *parm;
- u32 vf_id;
- u16 parm_len;
- s16 ret_code;
-};
-
-#pragma pack(pop)
-
-enum i40iw_status_code i40iw_vchnl_vf_get_ver(struct i40iw_sc_dev *dev,
- u32 *vchnl_ver);
-
-enum i40iw_status_code i40iw_vchnl_vf_get_hmc_fcn(struct i40iw_sc_dev *dev,
- u16 *hmc_fcn);
-
-enum i40iw_status_code i40iw_vchnl_vf_add_hmc_objs(struct i40iw_sc_dev *dev,
- enum i40iw_hmc_rsrc_type rsrc_type,
- u32 start_index,
- u32 rsrc_count);
-
-enum i40iw_status_code i40iw_vchnl_vf_del_hmc_obj(struct i40iw_sc_dev *dev,
- enum i40iw_hmc_rsrc_type rsrc_type,
- u32 start_index,
- u32 rsrc_count);
-
-enum i40iw_status_code i40iw_vchnl_vf_get_pe_stats(struct i40iw_sc_dev *dev,
- struct i40iw_dev_hw_stats *hw_stats);
-#endif
diff --git a/drivers/infiniband/hw/irdma/Kconfig b/drivers/infiniband/hw/irdma/Kconfig
new file mode 100644
index 000000000000..dab88286d549
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config INFINIBAND_IRDMA
+ tristate "Intel(R) Ethernet Protocol Driver for RDMA"
+ depends on INET
+ depends on IPV6 || !IPV6
+ depends on PCI
+ depends on ICE && I40E
+ select GENERIC_ALLOCATOR
+ select CONFIG_AUXILIARY_BUS
+ help
+ This is an Intel(R) Ethernet Protocol Driver for RDMA driver
+ that support E810 (iWARP/RoCE) and X722 (iWARP) network devices.
diff --git a/drivers/infiniband/hw/irdma/Makefile b/drivers/infiniband/hw/irdma/Makefile
new file mode 100644
index 000000000000..48c3854235a0
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/Makefile
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+# Copyright (c) 2019, Intel Corporation.
+
+#
+# Makefile for the Intel(R) Ethernet Connection RDMA Linux Driver
+#
+
+obj-$(CONFIG_INFINIBAND_IRDMA) += irdma.o
+
+irdma-objs := cm.o \
+ ctrl.o \
+ hmc.o \
+ hw.o \
+ i40iw_hw.o \
+ i40iw_if.o \
+ icrdma_hw.o \
+ main.o \
+ pble.o \
+ puda.o \
+ trace.o \
+ uda.o \
+ uk.o \
+ utils.o \
+ verbs.o \
+ ws.o \
+
+CFLAGS_trace.o = -I$(src)
diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c
new file mode 100644
index 000000000000..6b62299abfbb
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/cm.c
@@ -0,0 +1,4421 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#include "main.h"
+#include "trace.h"
+
+static void irdma_cm_post_event(struct irdma_cm_event *event);
+static void irdma_disconnect_worker(struct work_struct *work);
+
+/**
+ * irdma_free_sqbuf - put back puda buffer if refcount is 0
+ * @vsi: The VSI structure of the device
+ * @bufp: puda buffer to free
+ */
+void irdma_free_sqbuf(struct irdma_sc_vsi *vsi, void *bufp)
+{
+ struct irdma_puda_buf *buf = bufp;
+ struct irdma_puda_rsrc *ilq = vsi->ilq;
+
+ if (refcount_dec_and_test(&buf->refcount))
+ irdma_puda_ret_bufpool(ilq, buf);
+}
+
+/**
+ * irdma_record_ird_ord - Record IRD/ORD passed in
+ * @cm_node: connection's node
+ * @conn_ird: connection IRD
+ * @conn_ord: connection ORD
+ */
+static void irdma_record_ird_ord(struct irdma_cm_node *cm_node, u32 conn_ird,
+ u32 conn_ord)
+{
+ if (conn_ird > cm_node->dev->hw_attrs.max_hw_ird)
+ conn_ird = cm_node->dev->hw_attrs.max_hw_ird;
+
+ if (conn_ord > cm_node->dev->hw_attrs.max_hw_ord)
+ conn_ord = cm_node->dev->hw_attrs.max_hw_ord;
+ else if (!conn_ord && cm_node->send_rdma0_op == SEND_RDMA_READ_ZERO)
+ conn_ord = 1;
+ cm_node->ird_size = conn_ird;
+ cm_node->ord_size = conn_ord;
+}
+
+/**
+ * irdma_copy_ip_ntohl - copy IP address from network to host
+ * @dst: IP address in host order
+ * @src: IP address in network order (big endian)
+ */
+void irdma_copy_ip_ntohl(u32 *dst, __be32 *src)
+{
+ *dst++ = ntohl(*src++);
+ *dst++ = ntohl(*src++);
+ *dst++ = ntohl(*src++);
+ *dst = ntohl(*src);
+}
+
+/**
+ * irdma_copy_ip_htonl - copy IP address from host to network order
+ * @dst: IP address in network order (big endian)
+ * @src: IP address in host order
+ */
+void irdma_copy_ip_htonl(__be32 *dst, u32 *src)
+{
+ *dst++ = htonl(*src++);
+ *dst++ = htonl(*src++);
+ *dst++ = htonl(*src++);
+ *dst = htonl(*src);
+}
+
+/**
+ * irdma_get_addr_info
+ * @cm_node: contains ip/tcp info
+ * @cm_info: to get a copy of the cm_node ip/tcp info
+ */
+static void irdma_get_addr_info(struct irdma_cm_node *cm_node,
+ struct irdma_cm_info *cm_info)
+{
+ memset(cm_info, 0, sizeof(*cm_info));
+ cm_info->ipv4 = cm_node->ipv4;
+ cm_info->vlan_id = cm_node->vlan_id;
+ memcpy(cm_info->loc_addr, cm_node->loc_addr, sizeof(cm_info->loc_addr));
+ memcpy(cm_info->rem_addr, cm_node->rem_addr, sizeof(cm_info->rem_addr));
+ cm_info->loc_port = cm_node->loc_port;
+ cm_info->rem_port = cm_node->rem_port;
+}
+
+/**
+ * irdma_fill_sockaddr4 - fill in addr info for IPv4 connection
+ * @cm_node: connection's node
+ * @event: upper layer's cm event
+ */
+static inline void irdma_fill_sockaddr4(struct irdma_cm_node *cm_node,
+ struct iw_cm_event *event)
+{
+ struct sockaddr_in *laddr = (struct sockaddr_in *)&event->local_addr;
+ struct sockaddr_in *raddr = (struct sockaddr_in *)&event->remote_addr;
+
+ laddr->sin_family = AF_INET;
+ raddr->sin_family = AF_INET;
+
+ laddr->sin_port = htons(cm_node->loc_port);
+ raddr->sin_port = htons(cm_node->rem_port);
+
+ laddr->sin_addr.s_addr = htonl(cm_node->loc_addr[0]);
+ raddr->sin_addr.s_addr = htonl(cm_node->rem_addr[0]);
+}
+
+/**
+ * irdma_fill_sockaddr6 - fill in addr info for IPv6 connection
+ * @cm_node: connection's node
+ * @event: upper layer's cm event
+ */
+static inline void irdma_fill_sockaddr6(struct irdma_cm_node *cm_node,
+ struct iw_cm_event *event)
+{
+ struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)&event->local_addr;
+ struct sockaddr_in6 *raddr6 = (struct sockaddr_in6 *)&event->remote_addr;
+
+ laddr6->sin6_family = AF_INET6;
+ raddr6->sin6_family = AF_INET6;
+
+ laddr6->sin6_port = htons(cm_node->loc_port);
+ raddr6->sin6_port = htons(cm_node->rem_port);
+
+ irdma_copy_ip_htonl(laddr6->sin6_addr.in6_u.u6_addr32,
+ cm_node->loc_addr);
+ irdma_copy_ip_htonl(raddr6->sin6_addr.in6_u.u6_addr32,
+ cm_node->rem_addr);
+}
+
+/**
+ * irdma_get_cmevent_info - for cm event upcall
+ * @cm_node: connection's node
+ * @cm_id: upper layers cm struct for the event
+ * @event: upper layer's cm event
+ */
+static inline void irdma_get_cmevent_info(struct irdma_cm_node *cm_node,
+ struct iw_cm_id *cm_id,
+ struct iw_cm_event *event)
+{
+ memcpy(&event->local_addr, &cm_id->m_local_addr,
+ sizeof(event->local_addr));
+ memcpy(&event->remote_addr, &cm_id->m_remote_addr,
+ sizeof(event->remote_addr));
+ if (cm_node) {
+ event->private_data = cm_node->pdata_buf;
+ event->private_data_len = (u8)cm_node->pdata.size;
+ event->ird = cm_node->ird_size;
+ event->ord = cm_node->ord_size;
+ }
+}
+
+/**
+ * irdma_send_cm_event - upcall cm's event handler
+ * @cm_node: connection's node
+ * @cm_id: upper layer's cm info struct
+ * @type: Event type to indicate
+ * @status: status for the event type
+ */
+static int irdma_send_cm_event(struct irdma_cm_node *cm_node,
+ struct iw_cm_id *cm_id,
+ enum iw_cm_event_type type, int status)
+{
+ struct iw_cm_event event = {};
+
+ event.event = type;
+ event.status = status;
+ trace_irdma_send_cm_event(cm_node, cm_id, type, status,
+ __builtin_return_address(0));
+
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: cm_node %p cm_id=%p state=%d accel=%d event_type=%d status=%d\n",
+ cm_node, cm_id, cm_node->accelerated, cm_node->state, type,
+ status);
+
+ switch (type) {
+ case IW_CM_EVENT_CONNECT_REQUEST:
+ if (cm_node->ipv4)
+ irdma_fill_sockaddr4(cm_node, &event);
+ else
+ irdma_fill_sockaddr6(cm_node, &event);
+ event.provider_data = cm_node;
+ event.private_data = cm_node->pdata_buf;
+ event.private_data_len = (u8)cm_node->pdata.size;
+ event.ird = cm_node->ird_size;
+ break;
+ case IW_CM_EVENT_CONNECT_REPLY:
+ irdma_get_cmevent_info(cm_node, cm_id, &event);
+ break;
+ case IW_CM_EVENT_ESTABLISHED:
+ event.ird = cm_node->ird_size;
+ event.ord = cm_node->ord_size;
+ break;
+ case IW_CM_EVENT_DISCONNECT:
+ case IW_CM_EVENT_CLOSE:
+ /* Wait if we are in RTS but havent issued the iwcm event upcall */
+ if (!cm_node->accelerated)
+ wait_for_completion(&cm_node->establish_comp);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return cm_id->event_handler(cm_id, &event);
+}
+
+/**
+ * irdma_timer_list_prep - add connection nodes to a list to perform timer tasks
+ * @cm_core: cm's core
+ * @timer_list: a timer list to which cm_node will be selected
+ */
+static void irdma_timer_list_prep(struct irdma_cm_core *cm_core,
+ struct list_head *timer_list)
+{
+ struct irdma_cm_node *cm_node;
+ int bkt;
+
+ hash_for_each_rcu(cm_core->cm_hash_tbl, bkt, cm_node, list) {
+ if ((cm_node->close_entry || cm_node->send_entry) &&
+ refcount_inc_not_zero(&cm_node->refcnt))
+ list_add(&cm_node->timer_entry, timer_list);
+ }
+}
+
+/**
+ * irdma_create_event - create cm event
+ * @cm_node: connection's node
+ * @type: Event type to generate
+ */
+static struct irdma_cm_event *irdma_create_event(struct irdma_cm_node *cm_node,
+ enum irdma_cm_event_type type)
+{
+ struct irdma_cm_event *event;
+
+ if (!cm_node->cm_id)
+ return NULL;
+
+ event = kzalloc(sizeof(*event), GFP_ATOMIC);
+
+ if (!event)
+ return NULL;
+
+ event->type = type;
+ event->cm_node = cm_node;
+ memcpy(event->cm_info.rem_addr, cm_node->rem_addr,
+ sizeof(event->cm_info.rem_addr));
+ memcpy(event->cm_info.loc_addr, cm_node->loc_addr,
+ sizeof(event->cm_info.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;
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: node=%p event=%p type=%u dst=%pI4 src=%pI4\n", cm_node,
+ event, type, event->cm_info.loc_addr,
+ event->cm_info.rem_addr);
+ trace_irdma_create_event(cm_node, type, __builtin_return_address(0));
+ irdma_cm_post_event(event);
+
+ return event;
+}
+
+/**
+ * irdma_free_retrans_entry - free send entry
+ * @cm_node: connection's node
+ */
+static void irdma_free_retrans_entry(struct irdma_cm_node *cm_node)
+{
+ struct irdma_device *iwdev = cm_node->iwdev;
+ struct irdma_timer_entry *send_entry;
+
+ send_entry = cm_node->send_entry;
+ if (!send_entry)
+ return;
+
+ cm_node->send_entry = NULL;
+ irdma_free_sqbuf(&iwdev->vsi, send_entry->sqbuf);
+ kfree(send_entry);
+ refcount_dec(&cm_node->refcnt);
+}
+
+/**
+ * irdma_cleanup_retrans_entry - free send entry with lock
+ * @cm_node: connection's node
+ */
+static void irdma_cleanup_retrans_entry(struct irdma_cm_node *cm_node)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ irdma_free_retrans_entry(cm_node);
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+}
+
+/**
+ * irdma_form_ah_cm_frame - get a free packet and build frame with address handle
+ * @cm_node: connection's node ionfo to use in frame
+ * @options: pointer to options info
+ * @hdr: pointer mpa header
+ * @pdata: pointer to private data
+ * @flags: indicates FIN or ACK
+ */
+static struct irdma_puda_buf *irdma_form_ah_cm_frame(struct irdma_cm_node *cm_node,
+ struct irdma_kmem_info *options,
+ struct irdma_kmem_info *hdr,
+ struct irdma_mpa_priv_info *pdata,
+ u8 flags)
+{
+ struct irdma_puda_buf *sqbuf;
+ struct irdma_sc_vsi *vsi = &cm_node->iwdev->vsi;
+ u8 *buf;
+ struct tcphdr *tcph;
+ u16 pktsize;
+ u32 opts_len = 0;
+ u32 pd_len = 0;
+ u32 hdr_len = 0;
+
+ if (!cm_node->ah || !cm_node->ah->ah_info.ah_valid) {
+ ibdev_dbg(&cm_node->iwdev->ibdev, "CM: AH invalid\n");
+ return NULL;
+ }
+
+ sqbuf = irdma_puda_get_bufpool(vsi->ilq);
+ if (!sqbuf) {
+ ibdev_dbg(&cm_node->iwdev->ibdev, "CM: SQ buf NULL\n");
+ return NULL;
+ }
+
+ sqbuf->ah_id = cm_node->ah->ah_info.ah_idx;
+ buf = sqbuf->mem.va;
+ if (options)
+ opts_len = (u32)options->size;
+
+ if (hdr)
+ hdr_len = hdr->size;
+
+ if (pdata)
+ pd_len = pdata->size;
+
+ pktsize = sizeof(*tcph) + opts_len + hdr_len + pd_len;
+
+ memset(buf, 0, pktsize);
+
+ sqbuf->totallen = pktsize;
+ sqbuf->tcphlen = sizeof(*tcph) + opts_len;
+ sqbuf->scratch = cm_node;
+
+ tcph = (struct tcphdr *)buf;
+ buf += sizeof(*tcph);
+
+ 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 += hdr_len + pd_len;
+ }
+
+ 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) + opts_len + 3) >> 2);
+ sqbuf->tcphlen = tcph->doff << 2;
+ tcph->window = htons(cm_node->tcp_cntxt.rcv_wnd);
+ tcph->urg_ptr = 0;
+
+ if (opts_len) {
+ memcpy(buf, options->addr, opts_len);
+ buf += opts_len;
+ }
+
+ if (hdr_len) {
+ memcpy(buf, hdr->addr, hdr_len);
+ buf += hdr_len;
+ }
+
+ if (pdata && pdata->addr)
+ memcpy(buf, pdata->addr, pdata->size);
+
+ refcount_set(&sqbuf->refcount, 1);
+
+ print_hex_dump_debug("ILQ: TRANSMIT ILQ BUFFER", DUMP_PREFIX_OFFSET,
+ 16, 8, sqbuf->mem.va, sqbuf->totallen, false);
+
+ return sqbuf;
+}
+
+/**
+ * irdma_form_uda_cm_frame - get a free packet and build frame full tcpip packet
+ * @cm_node: connection's node ionfo to use in frame
+ * @options: pointer to options info
+ * @hdr: pointer mpa header
+ * @pdata: pointer to private data
+ * @flags: indicates FIN or ACK
+ */
+static struct irdma_puda_buf *irdma_form_uda_cm_frame(struct irdma_cm_node *cm_node,
+ struct irdma_kmem_info *options,
+ struct irdma_kmem_info *hdr,
+ struct irdma_mpa_priv_info *pdata,
+ u8 flags)
+{
+ struct irdma_puda_buf *sqbuf;
+ struct irdma_sc_vsi *vsi = &cm_node->iwdev->vsi;
+ u8 *buf;
+
+ struct tcphdr *tcph;
+ struct iphdr *iph;
+ struct ipv6hdr *ip6h;
+ struct ethhdr *ethh;
+ u16 pktsize;
+ u16 eth_hlen = ETH_HLEN;
+ u32 opts_len = 0;
+ u32 pd_len = 0;
+ u32 hdr_len = 0;
+
+ u16 vtag;
+
+ sqbuf = irdma_puda_get_bufpool(vsi->ilq);
+ if (!sqbuf)
+ return NULL;
+
+ buf = sqbuf->mem.va;
+
+ if (options)
+ opts_len = (u32)options->size;
+
+ if (hdr)
+ hdr_len = hdr->size;
+
+ if (pdata)
+ pd_len = pdata->size;
+
+ if (cm_node->vlan_id < VLAN_N_VID)
+ eth_hlen += 4;
+
+ if (cm_node->ipv4)
+ pktsize = sizeof(*iph) + sizeof(*tcph);
+ else
+ pktsize = sizeof(*ip6h) + sizeof(*tcph);
+ pktsize += opts_len + hdr_len + pd_len;
+
+ memset(buf, 0, eth_hlen + pktsize);
+
+ sqbuf->totallen = pktsize + eth_hlen;
+ sqbuf->maclen = eth_hlen;
+ sqbuf->tcphlen = sizeof(*tcph) + opts_len;
+ sqbuf->scratch = cm_node;
+
+ ethh = (struct ethhdr *)buf;
+ buf += eth_hlen;
+
+ if (cm_node->do_lpb)
+ sqbuf->do_lpb = true;
+
+ if (cm_node->ipv4) {
+ sqbuf->ipv4 = true;
+
+ iph = (struct iphdr *)buf;
+ buf += sizeof(*iph);
+ tcph = (struct tcphdr *)buf;
+ buf += sizeof(*tcph);
+
+ ether_addr_copy(ethh->h_dest, cm_node->rem_mac);
+ ether_addr_copy(ethh->h_source, cm_node->loc_mac);
+ if (cm_node->vlan_id < VLAN_N_VID) {
+ ((struct vlan_ethhdr *)ethh)->h_vlan_proto =
+ htons(ETH_P_8021Q);
+ vtag = (cm_node->user_pri << VLAN_PRIO_SHIFT) |
+ cm_node->vlan_id;
+ ((struct vlan_ethhdr *)ethh)->h_vlan_TCI = htons(vtag);
+
+ ((struct vlan_ethhdr *)ethh)->h_vlan_encapsulated_proto =
+ htons(ETH_P_IP);
+ } else {
+ ethh->h_proto = htons(ETH_P_IP);
+ }
+
+ iph->version = IPVERSION;
+ iph->ihl = 5; /* 5 * 4Byte words, IP headr len */
+ iph->tos = cm_node->tos;
+ iph->tot_len = htons(pktsize);
+ iph->id = htons(++cm_node->tcp_cntxt.loc_id);
+
+ iph->frag_off = htons(0x4000);
+ iph->ttl = 0x40;
+ iph->protocol = IPPROTO_TCP;
+ iph->saddr = htonl(cm_node->loc_addr[0]);
+ iph->daddr = htonl(cm_node->rem_addr[0]);
+ } else {
+ sqbuf->ipv4 = false;
+ ip6h = (struct ipv6hdr *)buf;
+ buf += sizeof(*ip6h);
+ tcph = (struct tcphdr *)buf;
+ buf += sizeof(*tcph);
+
+ ether_addr_copy(ethh->h_dest, cm_node->rem_mac);
+ ether_addr_copy(ethh->h_source, cm_node->loc_mac);
+ if (cm_node->vlan_id < VLAN_N_VID) {
+ ((struct vlan_ethhdr *)ethh)->h_vlan_proto =
+ htons(ETH_P_8021Q);
+ vtag = (cm_node->user_pri << VLAN_PRIO_SHIFT) |
+ cm_node->vlan_id;
+ ((struct vlan_ethhdr *)ethh)->h_vlan_TCI = htons(vtag);
+ ((struct vlan_ethhdr *)ethh)->h_vlan_encapsulated_proto =
+ htons(ETH_P_IPV6);
+ } else {
+ ethh->h_proto = htons(ETH_P_IPV6);
+ }
+ ip6h->version = 6;
+ ip6h->priority = cm_node->tos >> 4;
+ ip6h->flow_lbl[0] = cm_node->tos << 4;
+ ip6h->flow_lbl[1] = 0;
+ ip6h->flow_lbl[2] = 0;
+ ip6h->payload_len = htons(pktsize - sizeof(*ip6h));
+ ip6h->nexthdr = 6;
+ ip6h->hop_limit = 128;
+ irdma_copy_ip_htonl(ip6h->saddr.in6_u.u6_addr32,
+ cm_node->loc_addr);
+ irdma_copy_ip_htonl(ip6h->daddr.in6_u.u6_addr32,
+ 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 += hdr_len + pd_len;
+ }
+
+ 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) + opts_len + 3) >> 2);
+ sqbuf->tcphlen = tcph->doff << 2;
+ tcph->window = htons(cm_node->tcp_cntxt.rcv_wnd);
+ tcph->urg_ptr = 0;
+
+ if (opts_len) {
+ memcpy(buf, options->addr, opts_len);
+ buf += opts_len;
+ }
+
+ if (hdr_len) {
+ memcpy(buf, hdr->addr, hdr_len);
+ buf += hdr_len;
+ }
+
+ if (pdata && pdata->addr)
+ memcpy(buf, pdata->addr, pdata->size);
+
+ refcount_set(&sqbuf->refcount, 1);
+
+ print_hex_dump_debug("ILQ: TRANSMIT ILQ BUFFER", DUMP_PREFIX_OFFSET,
+ 16, 8, sqbuf->mem.va, sqbuf->totallen, false);
+ return sqbuf;
+}
+
+/**
+ * irdma_send_reset - Send RST packet
+ * @cm_node: connection's node
+ */
+int irdma_send_reset(struct irdma_cm_node *cm_node)
+{
+ struct irdma_puda_buf *sqbuf;
+ int flags = SET_RST | SET_ACK;
+
+ trace_irdma_send_reset(cm_node, 0, __builtin_return_address(0));
+ sqbuf = cm_node->cm_core->form_cm_frame(cm_node, NULL, NULL, NULL,
+ flags);
+ if (!sqbuf)
+ return -ENOMEM;
+
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: caller: %pS cm_node %p cm_id=%p accel=%d state=%d rem_port=0x%04x, loc_port=0x%04x rem_addr=%pI4 loc_addr=%pI4\n",
+ __builtin_return_address(0), cm_node, cm_node->cm_id,
+ cm_node->accelerated, cm_node->state, cm_node->rem_port,
+ cm_node->loc_port, cm_node->rem_addr, cm_node->loc_addr);
+
+ return irdma_schedule_cm_timer(cm_node, sqbuf, IRDMA_TIMER_TYPE_SEND, 0,
+ 1);
+}
+
+/**
+ * irdma_active_open_err - send event for active side cm error
+ * @cm_node: connection's node
+ * @reset: Flag to send reset or not
+ */
+static void irdma_active_open_err(struct irdma_cm_node *cm_node, bool reset)
+{
+ trace_irdma_active_open_err(cm_node, reset,
+ __builtin_return_address(0));
+ irdma_cleanup_retrans_entry(cm_node);
+ cm_node->cm_core->stats_connect_errs++;
+ if (reset) {
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: cm_node=%p state=%d\n", cm_node,
+ cm_node->state);
+ refcount_inc(&cm_node->refcnt);
+ irdma_send_reset(cm_node);
+ }
+
+ cm_node->state = IRDMA_CM_STATE_CLOSED;
+ irdma_create_event(cm_node, IRDMA_CM_EVENT_ABORTED);
+}
+
+/**
+ * irdma_passive_open_err - handle passive side cm error
+ * @cm_node: connection's node
+ * @reset: send reset or just free cm_node
+ */
+static void irdma_passive_open_err(struct irdma_cm_node *cm_node, bool reset)
+{
+ irdma_cleanup_retrans_entry(cm_node);
+ cm_node->cm_core->stats_passive_errs++;
+ cm_node->state = IRDMA_CM_STATE_CLOSED;
+ ibdev_dbg(&cm_node->iwdev->ibdev, "CM: cm_node=%p state =%d\n",
+ cm_node, cm_node->state);
+ trace_irdma_passive_open_err(cm_node, reset,
+ __builtin_return_address(0));
+ if (reset)
+ irdma_send_reset(cm_node);
+ else
+ irdma_rem_ref_cm_node(cm_node);
+}
+
+/**
+ * irdma_event_connect_error - to create connect error event
+ * @event: cm information for connect event
+ */
+static void irdma_event_connect_error(struct irdma_cm_event *event)
+{
+ struct irdma_qp *iwqp;
+ struct iw_cm_id *cm_id;
+
+ cm_id = event->cm_node->cm_id;
+ if (!cm_id)
+ return;
+
+ iwqp = cm_id->provider_data;
+
+ if (!iwqp || !iwqp->iwdev)
+ return;
+
+ iwqp->cm_id = NULL;
+ cm_id->provider_data = NULL;
+ irdma_send_cm_event(event->cm_node, cm_id, IW_CM_EVENT_CONNECT_REPLY,
+ -ECONNRESET);
+ irdma_rem_ref_cm_node(event->cm_node);
+}
+
+/**
+ * irdma_process_options - process options from TCP header
+ * @cm_node: connection's node
+ * @optionsloc: point to start of options
+ * @optionsize: size of all options
+ * @syn_pkt: flag if syn packet
+ */
+static int irdma_process_options(struct irdma_cm_node *cm_node, u8 *optionsloc,
+ u32 optionsize, u32 syn_pkt)
+{
+ 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->base.optionnum) {
+ case OPTION_NUM_EOL:
+ offset = optionsize;
+ break;
+ case OPTION_NUM_NONE:
+ offset += 1;
+ continue;
+ case OPTION_NUM_MSS:
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: MSS Length: %d Offset: %d Size: %d\n",
+ all_options->mss.len, offset, optionsize);
+ got_mss_option = 1;
+ if (all_options->mss.len != 4)
+ return -EINVAL;
+ tmp = ntohs(all_options->mss.mss);
+ if ((cm_node->ipv4 &&
+ (tmp + IRDMA_MTU_TO_MSS_IPV4) < IRDMA_MIN_MTU_IPV4) ||
+ (!cm_node->ipv4 &&
+ (tmp + IRDMA_MTU_TO_MSS_IPV6) < IRDMA_MIN_MTU_IPV6))
+ return -EINVAL;
+ if (tmp < cm_node->tcp_cntxt.mss)
+ cm_node->tcp_cntxt.mss = tmp;
+ break;
+ case OPTION_NUM_WINDOW_SCALE:
+ cm_node->tcp_cntxt.snd_wscale =
+ all_options->windowscale.shiftcount;
+ break;
+ default:
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: Unsupported TCP Option: %x\n",
+ all_options->base.optionnum);
+ break;
+ }
+ offset += all_options->base.len;
+ }
+ if (!got_mss_option && syn_pkt)
+ cm_node->tcp_cntxt.mss = IRDMA_CM_DEFAULT_MSS;
+
+ return 0;
+}
+
+/**
+ * irdma_handle_tcp_options - setup TCP context info after parsing TCP options
+ * @cm_node: connection's node
+ * @tcph: pointer tcp header
+ * @optionsize: size of options rcvd
+ * @passive: active or passive flag
+ */
+static int irdma_handle_tcp_options(struct irdma_cm_node *cm_node,
+ struct tcphdr *tcph, int optionsize,
+ int passive)
+{
+ u8 *optionsloc = (u8 *)&tcph[1];
+ int ret;
+
+ if (optionsize) {
+ ret = irdma_process_options(cm_node, optionsloc, optionsize,
+ (u32)tcph->syn);
+ if (ret) {
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: Node %p, Sending Reset\n", cm_node);
+ if (passive)
+ irdma_passive_open_err(cm_node, true);
+ else
+ irdma_active_open_err(cm_node, true);
+ return ret;
+ }
+ }
+
+ 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;
+}
+
+/**
+ * irdma_build_mpa_v1 - build a MPA V1 frame
+ * @cm_node: connection's node
+ * @start_addr: address where to build frame
+ * @mpa_key: to do read0 or write0
+ */
+static void irdma_build_mpa_v1(struct irdma_cm_node *cm_node, void *start_addr,
+ u8 mpa_key)
+{
+ struct ietf_mpa_v1 *mpa_frame = 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;
+ default:
+ break;
+ }
+ mpa_frame->flags = IETF_MPA_FLAGS_CRC;
+ mpa_frame->rev = cm_node->mpa_frame_rev;
+ mpa_frame->priv_data_len = htons(cm_node->pdata.size);
+}
+
+/**
+ * irdma_build_mpa_v2 - build a MPA V2 frame
+ * @cm_node: connection's node
+ * @start_addr: buffer start address
+ * @mpa_key: to do read0 or write0
+ */
+static void irdma_build_mpa_v2(struct irdma_cm_node *cm_node, void *start_addr,
+ u8 mpa_key)
+{
+ struct ietf_mpa_v2 *mpa_frame = start_addr;
+ struct ietf_rtr_msg *rtr_msg = &mpa_frame->rtr_msg;
+ u16 ctrl_ird, ctrl_ord;
+
+ /* initialize the upper 5 bytes of the frame */
+ irdma_build_mpa_v1(cm_node, start_addr, mpa_key);
+ mpa_frame->flags |= IETF_MPA_V2_FLAG;
+ if (cm_node->iwdev->iw_ooo) {
+ mpa_frame->flags |= IETF_MPA_FLAGS_MARKERS;
+ cm_node->rcv_mark_en = true;
+ }
+ mpa_frame->priv_data_len = cpu_to_be16(be16_to_cpu(mpa_frame->priv_data_len) +
+ 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) ?
+ IETF_NO_IRD_ORD :
+ cm_node->ird_size;
+ ctrl_ord = (cm_node->ord_size > IETF_NO_IRD_ORD) ?
+ IETF_NO_IRD_ORD :
+ cm_node->ord_size;
+ }
+ 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;
+ }
+ break;
+ default:
+ break;
+ }
+ rtr_msg->ctrl_ird = htons(ctrl_ird);
+ rtr_msg->ctrl_ord = htons(ctrl_ord);
+}
+
+/**
+ * irdma_cm_build_mpa_frame - build mpa frame for mpa version 1 or version 2
+ * @cm_node: connection's node
+ * @mpa: mpa: data buffer
+ * @mpa_key: to do read0 or write0
+ */
+static int irdma_cm_build_mpa_frame(struct irdma_cm_node *cm_node,
+ struct irdma_kmem_info *mpa, u8 mpa_key)
+{
+ int hdr_len = 0;
+
+ switch (cm_node->mpa_frame_rev) {
+ case IETF_MPA_V1:
+ hdr_len = sizeof(struct ietf_mpa_v1);
+ irdma_build_mpa_v1(cm_node, mpa->addr, mpa_key);
+ break;
+ case IETF_MPA_V2:
+ hdr_len = sizeof(struct ietf_mpa_v2);
+ irdma_build_mpa_v2(cm_node, mpa->addr, mpa_key);
+ break;
+ default:
+ break;
+ }
+
+ return hdr_len;
+}
+
+/**
+ * irdma_send_mpa_request - active node send mpa request to passive node
+ * @cm_node: connection's node
+ */
+static int irdma_send_mpa_request(struct irdma_cm_node *cm_node)
+{
+ struct irdma_puda_buf *sqbuf;
+
+ cm_node->mpa_hdr.addr = &cm_node->mpa_v2_frame;
+ cm_node->mpa_hdr.size = irdma_cm_build_mpa_frame(cm_node,
+ &cm_node->mpa_hdr,
+ MPA_KEY_REQUEST);
+ if (!cm_node->mpa_hdr.size) {
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: mpa size = %d\n", cm_node->mpa_hdr.size);
+ return -EINVAL;
+ }
+
+ sqbuf = cm_node->cm_core->form_cm_frame(cm_node, NULL,
+ &cm_node->mpa_hdr,
+ &cm_node->pdata, SET_ACK);
+ if (!sqbuf)
+ return -ENOMEM;
+
+ return irdma_schedule_cm_timer(cm_node, sqbuf, IRDMA_TIMER_TYPE_SEND, 1,
+ 0);
+}
+
+/**
+ * irdma_send_mpa_reject -
+ * @cm_node: connection's node
+ * @pdata: reject data for connection
+ * @plen: length of reject data
+ */
+static int irdma_send_mpa_reject(struct irdma_cm_node *cm_node,
+ const void *pdata, u8 plen)
+{
+ struct irdma_puda_buf *sqbuf;
+ struct irdma_mpa_priv_info priv_info;
+
+ cm_node->mpa_hdr.addr = &cm_node->mpa_v2_frame;
+ cm_node->mpa_hdr.size = irdma_cm_build_mpa_frame(cm_node,
+ &cm_node->mpa_hdr,
+ MPA_KEY_REPLY);
+
+ cm_node->mpa_frame.flags |= IETF_MPA_FLAGS_REJECT;
+ priv_info.addr = pdata;
+ priv_info.size = plen;
+
+ sqbuf = cm_node->cm_core->form_cm_frame(cm_node, NULL,
+ &cm_node->mpa_hdr, &priv_info,
+ SET_ACK | SET_FIN);
+ if (!sqbuf)
+ return -ENOMEM;
+
+ cm_node->state = IRDMA_CM_STATE_FIN_WAIT1;
+
+ return irdma_schedule_cm_timer(cm_node, sqbuf, IRDMA_TIMER_TYPE_SEND, 1,
+ 0);
+}
+
+/**
+ * irdma_negotiate_mpa_v2_ird_ord - negotiate MPAv2 IRD/ORD
+ * @cm_node: connection's node
+ * @buf: Data pointer
+ */
+static int irdma_negotiate_mpa_v2_ird_ord(struct irdma_cm_node *cm_node,
+ u8 *buf)
+{
+ struct ietf_mpa_v2 *mpa_v2_frame;
+ struct ietf_rtr_msg *rtr_msg;
+ u16 ird_size;
+ u16 ord_size;
+ u16 ctrl_ord;
+ u16 ctrl_ird;
+
+ mpa_v2_frame = (struct ietf_mpa_v2 *)buf;
+ rtr_msg = &mpa_v2_frame->rtr_msg;
+
+ /* parse rtr message */
+ ctrl_ord = ntohs(rtr_msg->ctrl_ord);
+ ctrl_ird = ntohs(rtr_msg->ctrl_ird);
+ ird_size = ctrl_ird & IETF_NO_IRD_ORD;
+ ord_size = ctrl_ord & IETF_NO_IRD_ORD;
+
+ if (!(ctrl_ird & IETF_PEER_TO_PEER))
+ return -EOPNOTSUPP;
+
+ if (ird_size == IETF_NO_IRD_ORD || ord_size == IETF_NO_IRD_ORD) {
+ cm_node->mpav2_ird_ord = IETF_NO_IRD_ORD;
+ goto negotiate_done;
+ }
+
+ if (cm_node->state != IRDMA_CM_STATE_MPAREQ_SENT) {
+ /* responder */
+ if (!ord_size && (ctrl_ord & IETF_RDMA0_READ))
+ cm_node->ird_size = 1;
+ if (cm_node->ord_size > ird_size)
+ cm_node->ord_size = ird_size;
+ } else {
+ /* initiator */
+ if (!ird_size && (ctrl_ord & IETF_RDMA0_READ))
+ /* Remote peer doesn't support RDMA0_READ */
+ return -EOPNOTSUPP;
+
+ if (cm_node->ord_size > ird_size)
+ cm_node->ord_size = ird_size;
+
+ if (cm_node->ird_size < ord_size)
+ /* no resources available */
+ return -EINVAL;
+ }
+
+negotiate_done:
+ if (ctrl_ord & IETF_RDMA0_READ)
+ cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO;
+ else if (ctrl_ord & IETF_RDMA0_WRITE)
+ cm_node->send_rdma0_op = SEND_RDMA_WRITE_ZERO;
+ else
+ /* Not supported RDMA0 operation */
+ return -EOPNOTSUPP;
+
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: MPAV2 Negotiated ORD: %d, IRD: %d\n",
+ cm_node->ord_size, cm_node->ird_size);
+ trace_irdma_negotiate_mpa_v2(cm_node);
+ return 0;
+}
+
+/**
+ * irdma_parse_mpa - process an IETF MPA frame
+ * @cm_node: connection's node
+ * @buf: Data pointer
+ * @type: to return accept or reject
+ * @len: Len of mpa buffer
+ */
+static int irdma_parse_mpa(struct irdma_cm_node *cm_node, u8 *buf, u32 *type,
+ u32 len)
+{
+ struct ietf_mpa_v1 *mpa_frame;
+ int mpa_hdr_len, priv_data_len, ret;
+
+ *type = IRDMA_MPA_REQUEST_ACCEPT;
+
+ if (len < sizeof(struct ietf_mpa_v1)) {
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: ietf buffer small (%x)\n", len);
+ return -EINVAL;
+ }
+
+ mpa_frame = (struct ietf_mpa_v1 *)buf;
+ mpa_hdr_len = sizeof(struct ietf_mpa_v1);
+ priv_data_len = ntohs(mpa_frame->priv_data_len);
+
+ if (priv_data_len > IETF_MAX_PRIV_DATA_LEN) {
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: private_data too big %d\n", priv_data_len);
+ return -EOVERFLOW;
+ }
+
+ if (mpa_frame->rev != IETF_MPA_V1 && mpa_frame->rev != IETF_MPA_V2) {
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: unsupported mpa rev = %d\n", mpa_frame->rev);
+ return -EINVAL;
+ }
+
+ if (mpa_frame->rev > cm_node->mpa_frame_rev) {
+ ibdev_dbg(&cm_node->iwdev->ibdev, "CM: rev %d\n",
+ mpa_frame->rev);
+ return -EINVAL;
+ }
+
+ cm_node->mpa_frame_rev = mpa_frame->rev;
+ if (cm_node->state != IRDMA_CM_STATE_MPAREQ_SENT) {
+ if (memcmp(mpa_frame->key, IEFT_MPA_KEY_REQ,
+ IETF_MPA_KEY_SIZE)) {
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: Unexpected MPA Key received\n");
+ return -EINVAL;
+ }
+ } else {
+ if (memcmp(mpa_frame->key, IEFT_MPA_KEY_REP,
+ IETF_MPA_KEY_SIZE)) {
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: Unexpected MPA Key received\n");
+ return -EINVAL;
+ }
+ }
+
+ if (priv_data_len + mpa_hdr_len > len) {
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: ietf buffer len(%x + %x != %x)\n",
+ priv_data_len, mpa_hdr_len, len);
+ return -EOVERFLOW;
+ }
+
+ if (len > IRDMA_MAX_CM_BUF) {
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: ietf buffer large len = %d\n", len);
+ return -EOVERFLOW;
+ }
+
+ switch (mpa_frame->rev) {
+ case IETF_MPA_V2:
+ mpa_hdr_len += IETF_RTR_MSG_SIZE;
+ ret = irdma_negotiate_mpa_v2_ird_ord(cm_node, buf);
+ if (ret)
+ return ret;
+ break;
+ case IETF_MPA_V1:
+ default:
+ break;
+ }
+
+ memcpy(cm_node->pdata_buf, buf + mpa_hdr_len, priv_data_len);
+ cm_node->pdata.size = priv_data_len;
+
+ if (mpa_frame->flags & IETF_MPA_FLAGS_REJECT)
+ *type = IRDMA_MPA_REQUEST_REJECT;
+
+ if (mpa_frame->flags & IETF_MPA_FLAGS_MARKERS)
+ cm_node->snd_mark_en = true;
+
+ return 0;
+}
+
+/**
+ * irdma_schedule_cm_timer
+ * @cm_node: connection's node
+ * @sqbuf: buffer to send
+ * @type: if it is send or close
+ * @send_retrans: if rexmits to be done
+ * @close_when_complete: is cm_node to be removed
+ *
+ * note - cm_node needs to be protected before calling this. Encase in:
+ * irdma_rem_ref_cm_node(cm_core, cm_node);
+ * irdma_schedule_cm_timer(...)
+ * refcount_inc(&cm_node->refcnt);
+ */
+int irdma_schedule_cm_timer(struct irdma_cm_node *cm_node,
+ struct irdma_puda_buf *sqbuf,
+ enum irdma_timer_type type, int send_retrans,
+ int close_when_complete)
+{
+ struct irdma_sc_vsi *vsi = &cm_node->iwdev->vsi;
+ struct irdma_cm_core *cm_core = cm_node->cm_core;
+ struct irdma_timer_entry *new_send;
+ u32 was_timer_set;
+ unsigned long flags;
+
+ new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
+ if (!new_send) {
+ if (type != IRDMA_TIMER_TYPE_CLOSE)
+ irdma_free_sqbuf(vsi, sqbuf);
+ return -ENOMEM;
+ }
+
+ new_send->retrycount = IRDMA_DEFAULT_RETRYS;
+ new_send->retranscount = IRDMA_DEFAULT_RETRANS;
+ new_send->sqbuf = sqbuf;
+ new_send->timetosend = jiffies;
+ new_send->type = type;
+ new_send->send_retrans = send_retrans;
+ new_send->close_when_complete = close_when_complete;
+
+ if (type == IRDMA_TIMER_TYPE_CLOSE) {
+ new_send->timetosend += (HZ / 10);
+ if (cm_node->close_entry) {
+ kfree(new_send);
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: already close entry\n");
+ return -EINVAL;
+ }
+
+ cm_node->close_entry = new_send;
+ } else { /* type == IRDMA_TIMER_TYPE_SEND */
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ cm_node->send_entry = new_send;
+ refcount_inc(&cm_node->refcnt);
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+ new_send->timetosend = jiffies + IRDMA_RETRY_TIMEOUT;
+
+ refcount_inc(&sqbuf->refcount);
+ irdma_puda_send_buf(vsi->ilq, sqbuf);
+ if (!send_retrans) {
+ irdma_cleanup_retrans_entry(cm_node);
+ if (close_when_complete)
+ irdma_rem_ref_cm_node(cm_node);
+ return 0;
+ }
+ }
+
+ spin_lock_irqsave(&cm_core->ht_lock, flags);
+ was_timer_set = timer_pending(&cm_core->tcp_timer);
+
+ if (!was_timer_set) {
+ cm_core->tcp_timer.expires = new_send->timetosend;
+ add_timer(&cm_core->tcp_timer);
+ }
+ spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+
+ return 0;
+}
+
+/**
+ * irdma_retrans_expired - Could not rexmit the packet
+ * @cm_node: connection's node
+ */
+static void irdma_retrans_expired(struct irdma_cm_node *cm_node)
+{
+ enum irdma_cm_node_state state = cm_node->state;
+
+ cm_node->state = IRDMA_CM_STATE_CLOSED;
+ switch (state) {
+ case IRDMA_CM_STATE_SYN_RCVD:
+ case IRDMA_CM_STATE_CLOSING:
+ irdma_rem_ref_cm_node(cm_node);
+ break;
+ case IRDMA_CM_STATE_FIN_WAIT1:
+ case IRDMA_CM_STATE_LAST_ACK:
+ irdma_send_reset(cm_node);
+ break;
+ default:
+ refcount_inc(&cm_node->refcnt);
+ irdma_send_reset(cm_node);
+ irdma_create_event(cm_node, IRDMA_CM_EVENT_ABORTED);
+ break;
+ }
+}
+
+/**
+ * irdma_handle_close_entry - for handling retry/timeouts
+ * @cm_node: connection's node
+ * @rem_node: flag for remove cm_node
+ */
+static void irdma_handle_close_entry(struct irdma_cm_node *cm_node,
+ u32 rem_node)
+{
+ struct irdma_timer_entry *close_entry = cm_node->close_entry;
+ struct irdma_qp *iwqp;
+ unsigned long flags;
+
+ if (!close_entry)
+ return;
+ iwqp = (struct irdma_qp *)close_entry->sqbuf;
+ if (iwqp) {
+ spin_lock_irqsave(&iwqp->lock, flags);
+ if (iwqp->cm_id) {
+ iwqp->hw_tcp_state = IRDMA_TCP_STATE_CLOSED;
+ iwqp->hw_iwarp_state = IRDMA_QP_STATE_ERROR;
+ iwqp->last_aeq = IRDMA_AE_RESET_SENT;
+ iwqp->ibqp_state = IB_QPS_ERR;
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ irdma_cm_disconn(iwqp);
+ } else {
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ }
+ } else if (rem_node) {
+ /* TIME_WAIT state */
+ irdma_rem_ref_cm_node(cm_node);
+ }
+
+ kfree(close_entry);
+ cm_node->close_entry = NULL;
+}
+
+/**
+ * irdma_cm_timer_tick - system's timer expired callback
+ * @t: Pointer to timer_list
+ */
+static void irdma_cm_timer_tick(struct timer_list *t)
+{
+ unsigned long nexttimeout = jiffies + IRDMA_LONG_TIME;
+ struct irdma_cm_node *cm_node;
+ struct irdma_timer_entry *send_entry, *close_entry;
+ struct list_head *list_core_temp;
+ struct list_head *list_node;
+ struct irdma_cm_core *cm_core = from_timer(cm_core, t, tcp_timer);
+ struct irdma_sc_vsi *vsi;
+ u32 settimer = 0;
+ unsigned long timetosend;
+ unsigned long flags;
+ struct list_head timer_list;
+
+ INIT_LIST_HEAD(&timer_list);
+
+ rcu_read_lock();
+ irdma_timer_list_prep(cm_core, &timer_list);
+ rcu_read_unlock();
+
+ list_for_each_safe (list_node, list_core_temp, &timer_list) {
+ cm_node = container_of(list_node, struct irdma_cm_node,
+ timer_entry);
+ close_entry = cm_node->close_entry;
+
+ if (close_entry) {
+ if (time_after(close_entry->timetosend, jiffies)) {
+ if (nexttimeout > close_entry->timetosend ||
+ !settimer) {
+ nexttimeout = close_entry->timetosend;
+ settimer = 1;
+ }
+ } else {
+ irdma_handle_close_entry(cm_node, 1);
+ }
+ }
+
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+
+ send_entry = cm_node->send_entry;
+ if (!send_entry)
+ goto done;
+ if (time_after(send_entry->timetosend, jiffies)) {
+ if (cm_node->state != IRDMA_CM_STATE_OFFLOADED) {
+ if (nexttimeout > send_entry->timetosend ||
+ !settimer) {
+ nexttimeout = send_entry->timetosend;
+ settimer = 1;
+ }
+ } else {
+ irdma_free_retrans_entry(cm_node);
+ }
+ goto done;
+ }
+
+ if (cm_node->state == IRDMA_CM_STATE_OFFLOADED ||
+ cm_node->state == IRDMA_CM_STATE_CLOSED) {
+ irdma_free_retrans_entry(cm_node);
+ goto done;
+ }
+
+ if (!send_entry->retranscount || !send_entry->retrycount) {
+ irdma_free_retrans_entry(cm_node);
+
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock,
+ flags);
+ irdma_retrans_expired(cm_node);
+ cm_node->state = IRDMA_CM_STATE_CLOSED;
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ goto done;
+ }
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+
+ vsi = &cm_node->iwdev->vsi;
+ if (!cm_node->ack_rcvd) {
+ refcount_inc(&send_entry->sqbuf->refcount);
+ irdma_puda_send_buf(vsi->ilq, send_entry->sqbuf);
+ cm_node->cm_core->stats_pkt_retrans++;
+ }
+
+ spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+ if (send_entry->send_retrans) {
+ send_entry->retranscount--;
+ timetosend = (IRDMA_RETRY_TIMEOUT <<
+ (IRDMA_DEFAULT_RETRANS -
+ send_entry->retranscount));
+
+ send_entry->timetosend = jiffies +
+ min(timetosend, IRDMA_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;
+ irdma_free_retrans_entry(cm_node);
+ if (close_when_complete)
+ irdma_rem_ref_cm_node(cm_node);
+ }
+done:
+ spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+ irdma_rem_ref_cm_node(cm_node);
+ }
+
+ if (settimer) {
+ spin_lock_irqsave(&cm_core->ht_lock, flags);
+ if (!timer_pending(&cm_core->tcp_timer)) {
+ cm_core->tcp_timer.expires = nexttimeout;
+ add_timer(&cm_core->tcp_timer);
+ }
+ spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+ }
+}
+
+/**
+ * irdma_send_syn - send SYN packet
+ * @cm_node: connection's node
+ * @sendack: flag to set ACK bit or not
+ */
+int irdma_send_syn(struct irdma_cm_node *cm_node, u32 sendack)
+{
+ struct irdma_puda_buf *sqbuf;
+ int flags = SET_SYN;
+ char optionsbuf[sizeof(struct option_mss) +
+ sizeof(struct option_windowscale) +
+ sizeof(struct option_base) + TCP_OPTIONS_PADDING];
+ struct irdma_kmem_info opts;
+ int optionssize = 0;
+ /* Sending MSS option */
+ union all_known_options *options;
+
+ opts.addr = optionsbuf;
+ if (!cm_node)
+ return -EINVAL;
+
+ options = (union all_known_options *)&optionsbuf[optionssize];
+ options->mss.optionnum = OPTION_NUM_MSS;
+ options->mss.len = sizeof(struct option_mss);
+ options->mss.mss = htons(cm_node->tcp_cntxt.mss);
+ optionssize += sizeof(struct option_mss);
+
+ options = (union all_known_options *)&optionsbuf[optionssize];
+ options->windowscale.optionnum = OPTION_NUM_WINDOW_SCALE;
+ options->windowscale.len = sizeof(struct option_windowscale);
+ options->windowscale.shiftcount = cm_node->tcp_cntxt.rcv_wscale;
+ optionssize += sizeof(struct option_windowscale);
+ options = (union all_known_options *)&optionsbuf[optionssize];
+ options->eol = OPTION_NUM_EOL;
+ optionssize += 1;
+
+ if (sendack)
+ flags |= SET_ACK;
+
+ opts.size = optionssize;
+
+ sqbuf = cm_node->cm_core->form_cm_frame(cm_node, &opts, NULL, NULL,
+ flags);
+ if (!sqbuf)
+ return -ENOMEM;
+
+ return irdma_schedule_cm_timer(cm_node, sqbuf, IRDMA_TIMER_TYPE_SEND, 1,
+ 0);
+}
+
+/**
+ * irdma_send_ack - Send ACK packet
+ * @cm_node: connection's node
+ */
+void irdma_send_ack(struct irdma_cm_node *cm_node)
+{
+ struct irdma_puda_buf *sqbuf;
+ struct irdma_sc_vsi *vsi = &cm_node->iwdev->vsi;
+
+ sqbuf = cm_node->cm_core->form_cm_frame(cm_node, NULL, NULL, NULL,
+ SET_ACK);
+ if (sqbuf)
+ irdma_puda_send_buf(vsi->ilq, sqbuf);
+}
+
+/**
+ * irdma_send_fin - Send FIN pkt
+ * @cm_node: connection's node
+ */
+static int irdma_send_fin(struct irdma_cm_node *cm_node)
+{
+ struct irdma_puda_buf *sqbuf;
+
+ sqbuf = cm_node->cm_core->form_cm_frame(cm_node, NULL, NULL, NULL,
+ SET_ACK | SET_FIN);
+ if (!sqbuf)
+ return -ENOMEM;
+
+ return irdma_schedule_cm_timer(cm_node, sqbuf, IRDMA_TIMER_TYPE_SEND, 1,
+ 0);
+}
+
+/**
+ * irdma_find_listener - find a cm node listening on this addr-port pair
+ * @cm_core: cm's core
+ * @dst_addr: listener ip addr
+ * @dst_port: listener tcp port num
+ * @vlan_id: virtual LAN ID
+ * @listener_state: state to match with listen node's
+ */
+static struct irdma_cm_listener *
+irdma_find_listener(struct irdma_cm_core *cm_core, u32 *dst_addr, u16 dst_port,
+ u16 vlan_id, enum irdma_cm_listener_state listener_state)
+{
+ struct irdma_cm_listener *listen_node;
+ static const u32 ip_zero[4] = { 0, 0, 0, 0 };
+ u32 listen_addr[4];
+ u16 listen_port;
+ unsigned long flags;
+
+ /* 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) {
+ memcpy(listen_addr, listen_node->loc_addr, sizeof(listen_addr));
+ listen_port = listen_node->loc_port;
+ /* compare node pair, return node handle if a match */
+ if ((!memcmp(listen_addr, dst_addr, sizeof(listen_addr)) ||
+ !memcmp(listen_addr, ip_zero, sizeof(listen_addr))) &&
+ listen_port == dst_port &&
+ vlan_id == listen_node->vlan_id &&
+ (listener_state & listen_node->listener_state)) {
+ refcount_inc(&listen_node->refcnt);
+ spin_unlock_irqrestore(&cm_core->listen_list_lock,
+ flags);
+ trace_irdma_find_listener(listen_node);
+ return listen_node;
+ }
+ }
+ spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+
+ return NULL;
+}
+
+/**
+ * irdma_del_multiple_qhash - Remove qhash and child listens
+ * @iwdev: iWarp device
+ * @cm_info: CM info for parent listen node
+ * @cm_parent_listen_node: The parent listen node
+ */
+static enum irdma_status_code
+irdma_del_multiple_qhash(struct irdma_device *iwdev,
+ struct irdma_cm_info *cm_info,
+ struct irdma_cm_listener *cm_parent_listen_node)
+{
+ struct irdma_cm_listener *child_listen_node;
+ enum irdma_status_code ret = IRDMA_ERR_CFG;
+ struct list_head *pos, *tpos;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iwdev->cm_core.listen_list_lock, flags);
+ list_for_each_safe (pos, tpos,
+ &cm_parent_listen_node->child_listen_list) {
+ child_listen_node = list_entry(pos, struct irdma_cm_listener,
+ child_listen_list);
+ if (child_listen_node->ipv4)
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: removing child listen for IP=%pI4, port=%d, vlan=%d\n",
+ child_listen_node->loc_addr,
+ child_listen_node->loc_port,
+ child_listen_node->vlan_id);
+ else
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: removing child listen for IP=%pI6, port=%d, vlan=%d\n",
+ child_listen_node->loc_addr,
+ child_listen_node->loc_port,
+ child_listen_node->vlan_id);
+ trace_irdma_del_multiple_qhash(child_listen_node);
+ list_del(pos);
+ memcpy(cm_info->loc_addr, child_listen_node->loc_addr,
+ sizeof(cm_info->loc_addr));
+ cm_info->vlan_id = child_listen_node->vlan_id;
+ if (child_listen_node->qhash_set) {
+ ret = irdma_manage_qhash(iwdev, cm_info,
+ IRDMA_QHASH_TYPE_TCP_SYN,
+ IRDMA_QHASH_MANAGE_TYPE_DELETE,
+ NULL, false);
+ child_listen_node->qhash_set = false;
+ } else {
+ ret = 0;
+ }
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: Child listen node freed = %p\n",
+ child_listen_node);
+ kfree(child_listen_node);
+ cm_parent_listen_node->cm_core->stats_listen_nodes_destroyed++;
+ }
+ spin_unlock_irqrestore(&iwdev->cm_core.listen_list_lock, flags);
+
+ return ret;
+}
+
+/**
+ * irdma_netdev_vlan_ipv6 - Gets the netdev and mac
+ * @addr: local IPv6 address
+ * @vlan_id: vlan id for the given IPv6 address
+ * @mac: mac address for the given IPv6 address
+ *
+ * Returns the net_device of the IPv6 address and also sets the
+ * vlan id and mac for that address.
+ */
+struct net_device *irdma_netdev_vlan_ipv6(u32 *addr, u16 *vlan_id, u8 *mac)
+{
+ struct net_device *ip_dev = NULL;
+ struct in6_addr laddr6;
+
+ if (!IS_ENABLED(CONFIG_IPV6))
+ return NULL;
+
+ irdma_copy_ip_htonl(laddr6.in6_u.u6_addr32, addr);
+ if (vlan_id)
+ *vlan_id = 0xFFFF; /* Match rdma_vlan_dev_vlan_id() */
+ if (mac)
+ eth_zero_addr(mac);
+
+ rcu_read_lock();
+ for_each_netdev_rcu (&init_net, ip_dev) {
+ if (ipv6_chk_addr(&init_net, &laddr6, ip_dev, 1)) {
+ if (vlan_id)
+ *vlan_id = rdma_vlan_dev_vlan_id(ip_dev);
+ if (ip_dev->dev_addr && mac)
+ ether_addr_copy(mac, ip_dev->dev_addr);
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ return ip_dev;
+}
+
+/**
+ * irdma_get_vlan_ipv4 - Returns the vlan_id for IPv4 address
+ * @addr: local IPv4 address
+ */
+u16 irdma_get_vlan_ipv4(u32 *addr)
+{
+ struct net_device *netdev;
+ u16 vlan_id = 0xFFFF;
+
+ netdev = ip_dev_find(&init_net, htonl(addr[0]));
+ if (netdev) {
+ vlan_id = rdma_vlan_dev_vlan_id(netdev);
+ dev_put(netdev);
+ }
+
+ return vlan_id;
+}
+
+/**
+ * irdma_add_mqh_6 - Adds multiple qhashes for IPv6
+ * @iwdev: iWarp device
+ * @cm_info: CM info for parent listen node
+ * @cm_parent_listen_node: The parent listen node
+ *
+ * Adds a qhash and a child listen node for every IPv6 address
+ * on the adapter and adds the associated qhash filter
+ */
+static enum irdma_status_code
+irdma_add_mqh_6(struct irdma_device *iwdev, struct irdma_cm_info *cm_info,
+ struct irdma_cm_listener *cm_parent_listen_node)
+{
+ struct net_device *ip_dev;
+ struct inet6_dev *idev;
+ struct inet6_ifaddr *ifp, *tmp;
+ enum irdma_status_code ret = 0;
+ struct irdma_cm_listener *child_listen_node;
+ unsigned long flags;
+
+ rtnl_lock();
+ for_each_netdev(&init_net, ip_dev) {
+ if (!(ip_dev->flags & IFF_UP))
+ continue;
+
+ if (((rdma_vlan_dev_vlan_id(ip_dev) >= VLAN_N_VID) ||
+ (rdma_vlan_dev_real_dev(ip_dev) != iwdev->netdev)) &&
+ ip_dev != iwdev->netdev)
+ continue;
+
+ idev = __in6_dev_get(ip_dev);
+ if (!idev) {
+ ibdev_dbg(&iwdev->ibdev, "CM: idev == NULL\n");
+ break;
+ }
+ list_for_each_entry_safe (ifp, tmp, &idev->addr_list, if_list) {
+ ibdev_dbg(&iwdev->ibdev, "CM: IP=%pI6, vlan_id=%d, MAC=%pM\n",
+ &ifp->addr, rdma_vlan_dev_vlan_id(ip_dev),
+ ip_dev->dev_addr);
+ child_listen_node = kzalloc(sizeof(*child_listen_node), GFP_KERNEL);
+ ibdev_dbg(&iwdev->ibdev, "CM: Allocating child listener %p\n",
+ child_listen_node);
+ if (!child_listen_node) {
+ ibdev_dbg(&iwdev->ibdev, "CM: listener memory allocation\n");
+ ret = IRDMA_ERR_NO_MEMORY;
+ goto exit;
+ }
+
+ cm_info->vlan_id = rdma_vlan_dev_vlan_id(ip_dev);
+ cm_parent_listen_node->vlan_id = cm_info->vlan_id;
+ memcpy(child_listen_node, cm_parent_listen_node,
+ sizeof(*child_listen_node));
+ irdma_copy_ip_ntohl(child_listen_node->loc_addr,
+ ifp->addr.in6_u.u6_addr32);
+ memcpy(cm_info->loc_addr, child_listen_node->loc_addr,
+ sizeof(cm_info->loc_addr));
+ ret = irdma_manage_qhash(iwdev, cm_info,
+ IRDMA_QHASH_TYPE_TCP_SYN,
+ IRDMA_QHASH_MANAGE_TYPE_ADD,
+ NULL, true);
+ if (ret) {
+ kfree(child_listen_node);
+ continue;
+ }
+
+ trace_irdma_add_mqh_6(iwdev, child_listen_node,
+ ip_dev->dev_addr);
+
+ child_listen_node->qhash_set = true;
+ spin_lock_irqsave(&iwdev->cm_core.listen_list_lock, flags);
+ list_add(&child_listen_node->child_listen_list,
+ &cm_parent_listen_node->child_listen_list);
+ spin_unlock_irqrestore(&iwdev->cm_core.listen_list_lock, flags);
+ cm_parent_listen_node->cm_core->stats_listen_nodes_created++;
+ }
+ }
+exit:
+ rtnl_unlock();
+
+ return ret;
+}
+
+/**
+ * irdma_add_mqh_4 - Adds multiple qhashes for IPv4
+ * @iwdev: iWarp device
+ * @cm_info: CM info for parent listen node
+ * @cm_parent_listen_node: The parent listen node
+ *
+ * Adds a qhash and a child listen node for every IPv4 address
+ * on the adapter and adds the associated qhash filter
+ */
+static enum irdma_status_code
+irdma_add_mqh_4(struct irdma_device *iwdev, struct irdma_cm_info *cm_info,
+ struct irdma_cm_listener *cm_parent_listen_node)
+{
+ struct net_device *ip_dev;
+ struct in_device *idev;
+ struct irdma_cm_listener *child_listen_node;
+ enum irdma_status_code ret = 0;
+ unsigned long flags;
+ const struct in_ifaddr *ifa;
+
+ rtnl_lock();
+ for_each_netdev(&init_net, ip_dev) {
+ if (!(ip_dev->flags & IFF_UP))
+ continue;
+
+ if (((rdma_vlan_dev_vlan_id(ip_dev) >= VLAN_N_VID) ||
+ (rdma_vlan_dev_real_dev(ip_dev) != iwdev->netdev)) &&
+ ip_dev != iwdev->netdev)
+ continue;
+
+ idev = in_dev_get(ip_dev);
+ in_dev_for_each_ifa_rtnl(ifa, idev) {
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: Allocating child CM Listener forIP=%pI4, vlan_id=%d, MAC=%pM\n",
+ &ifa->ifa_address, rdma_vlan_dev_vlan_id(ip_dev),
+ ip_dev->dev_addr);
+ child_listen_node = kzalloc(sizeof(*child_listen_node), GFP_KERNEL);
+ cm_parent_listen_node->cm_core->stats_listen_nodes_created++;
+ ibdev_dbg(&iwdev->ibdev, "CM: Allocating child listener %p\n",
+ child_listen_node);
+ if (!child_listen_node) {
+ ibdev_dbg(&iwdev->ibdev, "CM: listener memory allocation\n");
+ in_dev_put(idev);
+ ret = IRDMA_ERR_NO_MEMORY;
+ goto exit;
+ }
+
+ cm_info->vlan_id = rdma_vlan_dev_vlan_id(ip_dev);
+ cm_parent_listen_node->vlan_id = cm_info->vlan_id;
+ memcpy(child_listen_node, cm_parent_listen_node,
+ sizeof(*child_listen_node));
+ child_listen_node->loc_addr[0] =
+ ntohl(ifa->ifa_address);
+ memcpy(cm_info->loc_addr, child_listen_node->loc_addr,
+ sizeof(cm_info->loc_addr));
+ ret = irdma_manage_qhash(iwdev, cm_info,
+ IRDMA_QHASH_TYPE_TCP_SYN,
+ IRDMA_QHASH_MANAGE_TYPE_ADD,
+ NULL, true);
+ if (ret) {
+ kfree(child_listen_node);
+ cm_parent_listen_node->cm_core
+ ->stats_listen_nodes_created--;
+ continue;
+ }
+
+ trace_irdma_add_mqh_4(iwdev, child_listen_node,
+ ip_dev->dev_addr);
+
+ child_listen_node->qhash_set = true;
+ spin_lock_irqsave(&iwdev->cm_core.listen_list_lock,
+ flags);
+ list_add(&child_listen_node->child_listen_list,
+ &cm_parent_listen_node->child_listen_list);
+ spin_unlock_irqrestore(&iwdev->cm_core.listen_list_lock, flags);
+ }
+ in_dev_put(idev);
+ }
+exit:
+ rtnl_unlock();
+
+ return ret;
+}
+
+/**
+ * irdma_add_mqh - Adds multiple qhashes
+ * @iwdev: iWarp device
+ * @cm_info: CM info for parent listen node
+ * @cm_listen_node: The parent listen node
+ */
+static enum irdma_status_code
+irdma_add_mqh(struct irdma_device *iwdev, struct irdma_cm_info *cm_info,
+ struct irdma_cm_listener *cm_listen_node)
+{
+ if (cm_info->ipv4)
+ return irdma_add_mqh_4(iwdev, cm_info, cm_listen_node);
+ else
+ return irdma_add_mqh_6(iwdev, cm_info, cm_listen_node);
+}
+
+/**
+ * irdma_reset_list_prep - add connection nodes slated for reset to list
+ * @cm_core: cm's core
+ * @listener: pointer to listener node
+ * @reset_list: a list to which cm_node will be selected
+ */
+static void irdma_reset_list_prep(struct irdma_cm_core *cm_core,
+ struct irdma_cm_listener *listener,
+ struct list_head *reset_list)
+{
+ struct irdma_cm_node *cm_node;
+ int bkt;
+
+ hash_for_each_rcu(cm_core->cm_hash_tbl, bkt, cm_node, list) {
+ if (cm_node->listener == listener &&
+ !cm_node->accelerated &&
+ refcount_inc_not_zero(&cm_node->refcnt))
+ list_add(&cm_node->reset_entry, reset_list);
+ }
+}
+
+/**
+ * irdma_dec_refcnt_listen - delete listener and associated cm nodes
+ * @cm_core: cm's core
+ * @listener: pointer to listener node
+ * @free_hanging_nodes: to free associated cm_nodes
+ * @apbvt_del: flag to delete the apbvt
+ */
+static int irdma_dec_refcnt_listen(struct irdma_cm_core *cm_core,
+ struct irdma_cm_listener *listener,
+ int free_hanging_nodes, bool apbvt_del)
+{
+ int err;
+ struct list_head *list_pos;
+ struct list_head *list_temp;
+ struct irdma_cm_node *cm_node;
+ struct list_head reset_list;
+ struct irdma_cm_info nfo;
+ enum irdma_cm_node_state old_state;
+ unsigned long flags;
+
+ trace_irdma_dec_refcnt_listen(listener, __builtin_return_address(0));
+ /* free non-accelerated child nodes for this listener */
+ INIT_LIST_HEAD(&reset_list);
+ if (free_hanging_nodes) {
+ rcu_read_lock();
+ irdma_reset_list_prep(cm_core, listener, &reset_list);
+ rcu_read_unlock();
+ }
+
+ list_for_each_safe (list_pos, list_temp, &reset_list) {
+ cm_node = container_of(list_pos, struct irdma_cm_node,
+ reset_entry);
+ if (cm_node->state >= IRDMA_CM_STATE_FIN_WAIT1) {
+ irdma_rem_ref_cm_node(cm_node);
+ continue;
+ }
+
+ irdma_cleanup_retrans_entry(cm_node);
+ err = irdma_send_reset(cm_node);
+ if (err) {
+ cm_node->state = IRDMA_CM_STATE_CLOSED;
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: send reset failed\n");
+ } else {
+ old_state = cm_node->state;
+ cm_node->state = IRDMA_CM_STATE_LISTENER_DESTROYED;
+ if (old_state != IRDMA_CM_STATE_MPAREQ_RCVD)
+ irdma_rem_ref_cm_node(cm_node);
+ }
+ }
+
+ if (refcount_dec_and_test(&listener->refcnt)) {
+ spin_lock_irqsave(&cm_core->listen_list_lock, flags);
+ list_del(&listener->list);
+ spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+
+ if (apbvt_del)
+ irdma_del_apbvt(listener->iwdev,
+ listener->apbvt_entry);
+ memcpy(nfo.loc_addr, listener->loc_addr, sizeof(nfo.loc_addr));
+ nfo.loc_port = listener->loc_port;
+ nfo.ipv4 = listener->ipv4;
+ nfo.vlan_id = listener->vlan_id;
+ nfo.user_pri = listener->user_pri;
+ nfo.qh_qpid = listener->iwdev->vsi.ilq->qp_id;
+
+ if (!list_empty(&listener->child_listen_list)) {
+ irdma_del_multiple_qhash(listener->iwdev, &nfo,
+ listener);
+ } else {
+ if (listener->qhash_set)
+ irdma_manage_qhash(listener->iwdev,
+ &nfo,
+ IRDMA_QHASH_TYPE_TCP_SYN,
+ IRDMA_QHASH_MANAGE_TYPE_DELETE,
+ NULL, false);
+ }
+
+ cm_core->stats_listen_destroyed++;
+ cm_core->stats_listen_nodes_destroyed++;
+ ibdev_dbg(&listener->iwdev->ibdev,
+ "CM: loc_port=0x%04x loc_addr=%pI4 cm_listen_node=%p cm_id=%p qhash_set=%d vlan_id=%d apbvt_del=%d\n",
+ listener->loc_port, listener->loc_addr, listener,
+ listener->cm_id, listener->qhash_set,
+ listener->vlan_id, apbvt_del);
+ kfree(listener);
+ listener = NULL;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * irdma_cm_del_listen - delete a listener
+ * @cm_core: cm's core
+ * @listener: passive connection's listener
+ * @apbvt_del: flag to delete apbvt
+ */
+static int irdma_cm_del_listen(struct irdma_cm_core *cm_core,
+ struct irdma_cm_listener *listener,
+ bool apbvt_del)
+{
+ listener->listener_state = IRDMA_CM_LISTENER_PASSIVE_STATE;
+ listener->cm_id = NULL;
+
+ return irdma_dec_refcnt_listen(cm_core, listener, 1, apbvt_del);
+}
+
+/**
+ * irdma_addr_resolve_neigh - resolve neighbor address
+ * @iwdev: iwarp device structure
+ * @src_ip: local ip address
+ * @dst_ip: remote ip address
+ * @arpindex: if there is an arp entry
+ */
+static int irdma_addr_resolve_neigh(struct irdma_device *iwdev, u32 src_ip,
+ u32 dst_ip, int arpindex)
+{
+ struct rtable *rt;
+ struct neighbour *neigh;
+ int rc = arpindex;
+ __be32 dst_ipaddr = htonl(dst_ip);
+ __be32 src_ipaddr = htonl(src_ip);
+
+ rt = ip_route_output(&init_net, dst_ipaddr, src_ipaddr, 0, 0);
+ if (IS_ERR(rt)) {
+ ibdev_dbg(&iwdev->ibdev, "CM: ip_route_output fail\n");
+ return -EINVAL;
+ }
+
+ neigh = dst_neigh_lookup(&rt->dst, &dst_ipaddr);
+ if (!neigh)
+ goto exit;
+
+ if (neigh->nud_state & NUD_VALID)
+ rc = irdma_add_arp(iwdev->rf, &dst_ip, true, neigh->ha);
+ else
+ neigh_event_send(neigh, NULL);
+ if (neigh)
+ neigh_release(neigh);
+exit:
+ ip_rt_put(rt);
+
+ return rc;
+}
+
+/**
+ * irdma_get_dst_ipv6 - get destination cache entry via ipv6 lookup
+ * @src_addr: local ipv6 sock address
+ * @dst_addr: destination ipv6 sock address
+ */
+static struct dst_entry *irdma_get_dst_ipv6(struct sockaddr_in6 *src_addr,
+ struct sockaddr_in6 *dst_addr)
+{
+ struct dst_entry *dst = NULL;
+
+ if ((IS_ENABLED(CONFIG_IPV6))) {
+ struct flowi6 fl6 = {};
+
+ fl6.daddr = dst_addr->sin6_addr;
+ fl6.saddr = src_addr->sin6_addr;
+ if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL)
+ fl6.flowi6_oif = dst_addr->sin6_scope_id;
+
+ dst = ip6_route_output(&init_net, NULL, &fl6);
+ }
+
+ return dst;
+}
+
+/**
+ * irdma_addr_resolve_neigh_ipv6 - resolve neighbor ipv6 address
+ * @iwdev: iwarp device structure
+ * @src: local ip address
+ * @dest: remote ip address
+ * @arpindex: if there is an arp entry
+ */
+static int irdma_addr_resolve_neigh_ipv6(struct irdma_device *iwdev, u32 *src,
+ u32 *dest, int arpindex)
+{
+ struct neighbour *neigh;
+ int rc = arpindex;
+ struct dst_entry *dst;
+ struct sockaddr_in6 dst_addr = {};
+ struct sockaddr_in6 src_addr = {};
+
+ dst_addr.sin6_family = AF_INET6;
+ irdma_copy_ip_htonl(dst_addr.sin6_addr.in6_u.u6_addr32, dest);
+ src_addr.sin6_family = AF_INET6;
+ irdma_copy_ip_htonl(src_addr.sin6_addr.in6_u.u6_addr32, src);
+ dst = irdma_get_dst_ipv6(&src_addr, &dst_addr);
+ if (!dst || dst->error) {
+ if (dst) {
+ dst_release(dst);
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: ip6_route_output returned dst->error = %d\n",
+ dst->error);
+ }
+ return -EINVAL;
+ }
+
+ neigh = dst_neigh_lookup(dst, dst_addr.sin6_addr.in6_u.u6_addr32);
+ if (!neigh)
+ goto exit;
+
+ ibdev_dbg(&iwdev->ibdev, "CM: dst_neigh_lookup MAC=%pM\n",
+ neigh->ha);
+
+ trace_irdma_addr_resolve(iwdev, neigh->ha);
+
+ if (neigh->nud_state & NUD_VALID)
+ rc = irdma_add_arp(iwdev->rf, dest, false, neigh->ha);
+ else
+ neigh_event_send(neigh, NULL);
+ if (neigh)
+ neigh_release(neigh);
+exit:
+ dst_release(dst);
+
+ return rc;
+}
+
+/**
+ * irdma_find_node - find a cm node that matches the reference cm node
+ * @cm_core: cm's core
+ * @rem_port: remote tcp port num
+ * @rem_addr: remote ip addr
+ * @loc_port: local tcp port num
+ * @loc_addr: local ip addr
+ * @vlan_id: local VLAN ID
+ */
+struct irdma_cm_node *irdma_find_node(struct irdma_cm_core *cm_core,
+ u16 rem_port, u32 *rem_addr, u16 loc_port,
+ u32 *loc_addr, u16 vlan_id)
+{
+ struct irdma_cm_node *cm_node;
+ u32 key = (rem_port << 16) | loc_port;
+
+ rcu_read_lock();
+ hash_for_each_possible_rcu(cm_core->cm_hash_tbl, cm_node, list, key) {
+ if (cm_node->vlan_id == vlan_id &&
+ cm_node->loc_port == loc_port && cm_node->rem_port == rem_port &&
+ !memcmp(cm_node->loc_addr, loc_addr, sizeof(cm_node->loc_addr)) &&
+ !memcmp(cm_node->rem_addr, rem_addr, sizeof(cm_node->rem_addr))) {
+ if (!refcount_inc_not_zero(&cm_node->refcnt))
+ goto exit;
+ rcu_read_unlock();
+ trace_irdma_find_node(cm_node, 0, NULL);
+ return cm_node;
+ }
+ }
+
+exit:
+ rcu_read_unlock();
+
+ /* no owner node */
+ return NULL;
+}
+
+/**
+ * irdma_add_hte_node - add a cm node to the hash table
+ * @cm_core: cm's core
+ * @cm_node: connection's node
+ */
+static void irdma_add_hte_node(struct irdma_cm_core *cm_core,
+ struct irdma_cm_node *cm_node)
+{
+ unsigned long flags;
+ u32 key = (cm_node->rem_port << 16) | cm_node->loc_port;
+
+ spin_lock_irqsave(&cm_core->ht_lock, flags);
+ hash_add_rcu(cm_core->cm_hash_tbl, &cm_node->list, key);
+ spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+}
+
+/**
+ * irdma_ipv4_is_lpb - check if loopback
+ * @loc_addr: local addr to compare
+ * @rem_addr: remote address
+ */
+bool irdma_ipv4_is_lpb(u32 loc_addr, u32 rem_addr)
+{
+ return ipv4_is_loopback(htonl(rem_addr)) || (loc_addr == rem_addr);
+}
+
+/**
+ * irdma_ipv6_is_lpb - check if loopback
+ * @loc_addr: local addr to compare
+ * @rem_addr: remote address
+ */
+bool irdma_ipv6_is_lpb(u32 *loc_addr, u32 *rem_addr)
+{
+ struct in6_addr raddr6;
+
+ irdma_copy_ip_htonl(raddr6.in6_u.u6_addr32, rem_addr);
+
+ return !memcmp(loc_addr, rem_addr, 16) || ipv6_addr_loopback(&raddr6);
+}
+
+/**
+ * irdma_cm_create_ah - create a cm address handle
+ * @cm_node: The connection manager node to create AH for
+ * @wait: Provides option to wait for ah creation or not
+ */
+static int irdma_cm_create_ah(struct irdma_cm_node *cm_node, bool wait)
+{
+ struct irdma_ah_info ah_info = {};
+ struct irdma_device *iwdev = cm_node->iwdev;
+
+ ether_addr_copy(ah_info.mac_addr, iwdev->netdev->dev_addr);
+
+ ah_info.hop_ttl = 0x40;
+ ah_info.tc_tos = cm_node->tos;
+ ah_info.vsi = &iwdev->vsi;
+
+ if (cm_node->ipv4) {
+ ah_info.ipv4_valid = true;
+ ah_info.dest_ip_addr[0] = cm_node->rem_addr[0];
+ ah_info.src_ip_addr[0] = cm_node->loc_addr[0];
+ ah_info.do_lpbk = irdma_ipv4_is_lpb(ah_info.src_ip_addr[0],
+ ah_info.dest_ip_addr[0]);
+ } else {
+ memcpy(ah_info.dest_ip_addr, cm_node->rem_addr,
+ sizeof(ah_info.dest_ip_addr));
+ memcpy(ah_info.src_ip_addr, cm_node->loc_addr,
+ sizeof(ah_info.src_ip_addr));
+ ah_info.do_lpbk = irdma_ipv6_is_lpb(ah_info.src_ip_addr,
+ ah_info.dest_ip_addr);
+ }
+
+ ah_info.vlan_tag = cm_node->vlan_id;
+ if (cm_node->vlan_id < VLAN_N_VID) {
+ ah_info.insert_vlan_tag = 1;
+ ah_info.vlan_tag |= cm_node->user_pri << VLAN_PRIO_SHIFT;
+ }
+
+ ah_info.dst_arpindex =
+ irdma_arp_table(iwdev->rf, ah_info.dest_ip_addr,
+ ah_info.ipv4_valid, NULL, IRDMA_ARP_RESOLVE);
+
+ if (irdma_puda_create_ah(&iwdev->rf->sc_dev, &ah_info, wait,
+ IRDMA_PUDA_RSRC_TYPE_ILQ, cm_node,
+ &cm_node->ah))
+ return -ENOMEM;
+
+ trace_irdma_create_ah(cm_node);
+ return 0;
+}
+
+/**
+ * irdma_cm_free_ah - free a cm address handle
+ * @cm_node: The connection manager node to create AH for
+ */
+static void irdma_cm_free_ah(struct irdma_cm_node *cm_node)
+{
+ struct irdma_device *iwdev = cm_node->iwdev;
+
+ trace_irdma_cm_free_ah(cm_node);
+ irdma_puda_free_ah(&iwdev->rf->sc_dev, cm_node->ah);
+ cm_node->ah = NULL;
+}
+
+/**
+ * irdma_make_cm_node - create a new instance of a cm node
+ * @cm_core: cm's core
+ * @iwdev: iwarp device structure
+ * @cm_info: quad info for connection
+ * @listener: passive connection's listener
+ */
+static struct irdma_cm_node *
+irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev,
+ struct irdma_cm_info *cm_info,
+ struct irdma_cm_listener *listener)
+{
+ struct irdma_cm_node *cm_node;
+ int oldarpindex;
+ int arpindex;
+ struct net_device *netdev = iwdev->netdev;
+
+ /* 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 */
+ cm_node->ipv4 = cm_info->ipv4;
+ cm_node->vlan_id = cm_info->vlan_id;
+ if (cm_node->vlan_id >= VLAN_N_VID && iwdev->dcb)
+ cm_node->vlan_id = 0;
+ cm_node->tos = cm_info->tos;
+ cm_node->user_pri = cm_info->user_pri;
+ if (listener) {
+ if (listener->tos != cm_info->tos)
+ ibdev_warn(&iwdev->ibdev,
+ "application TOS[%d] and remote client TOS[%d] mismatch\n",
+ listener->tos, cm_info->tos);
+ cm_node->tos = max(listener->tos, cm_info->tos);
+ cm_node->user_pri = rt_tos2priority(cm_node->tos);
+ ibdev_dbg(&iwdev->ibdev,
+ "DCB: listener: TOS:[%d] UP:[%d]\n", cm_node->tos,
+ cm_node->user_pri);
+ trace_irdma_listener_tos(iwdev, cm_node->tos,
+ cm_node->user_pri);
+ }
+ memcpy(cm_node->loc_addr, cm_info->loc_addr, sizeof(cm_node->loc_addr));
+ memcpy(cm_node->rem_addr, cm_info->rem_addr, sizeof(cm_node->rem_addr));
+ cm_node->loc_port = cm_info->loc_port;
+ cm_node->rem_port = cm_info->rem_port;
+
+ cm_node->mpa_frame_rev = IRDMA_CM_DEFAULT_MPA_VER;
+ cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO;
+ cm_node->iwdev = iwdev;
+ cm_node->dev = &iwdev->rf->sc_dev;
+
+ cm_node->ird_size = cm_node->dev->hw_attrs.max_hw_ird;
+ cm_node->ord_size = cm_node->dev->hw_attrs.max_hw_ord;
+
+ cm_node->listener = listener;
+ cm_node->cm_id = cm_info->cm_id;
+ ether_addr_copy(cm_node->loc_mac, netdev->dev_addr);
+ spin_lock_init(&cm_node->retrans_list_lock);
+ cm_node->ack_rcvd = false;
+
+ init_completion(&cm_node->establish_comp);
+ refcount_set(&cm_node->refcnt, 1);
+ /* associate our parent CM core */
+ cm_node->cm_core = cm_core;
+ cm_node->tcp_cntxt.loc_id = IRDMA_CM_DEFAULT_LOCAL_ID;
+ cm_node->tcp_cntxt.rcv_wscale = iwdev->rcv_wscale;
+ cm_node->tcp_cntxt.rcv_wnd = iwdev->rcv_wnd >> cm_node->tcp_cntxt.rcv_wscale;
+ if (cm_node->ipv4) {
+ cm_node->tcp_cntxt.loc_seq_num = secure_tcp_seq(htonl(cm_node->loc_addr[0]),
+ htonl(cm_node->rem_addr[0]),
+ htons(cm_node->loc_port),
+ htons(cm_node->rem_port));
+ cm_node->tcp_cntxt.mss = iwdev->vsi.mtu - IRDMA_MTU_TO_MSS_IPV4;
+ } else if (IS_ENABLED(CONFIG_IPV6)) {
+ __be32 loc[4] = {
+ htonl(cm_node->loc_addr[0]), htonl(cm_node->loc_addr[1]),
+ htonl(cm_node->loc_addr[2]), htonl(cm_node->loc_addr[3])
+ };
+ __be32 rem[4] = {
+ htonl(cm_node->rem_addr[0]), htonl(cm_node->rem_addr[1]),
+ htonl(cm_node->rem_addr[2]), htonl(cm_node->rem_addr[3])
+ };
+ cm_node->tcp_cntxt.loc_seq_num = secure_tcpv6_seq(loc, rem,
+ htons(cm_node->loc_port),
+ htons(cm_node->rem_port));
+ cm_node->tcp_cntxt.mss = iwdev->vsi.mtu - IRDMA_MTU_TO_MSS_IPV6;
+ }
+
+ if ((cm_node->ipv4 &&
+ irdma_ipv4_is_lpb(cm_node->loc_addr[0], cm_node->rem_addr[0])) ||
+ (!cm_node->ipv4 &&
+ irdma_ipv6_is_lpb(cm_node->loc_addr, cm_node->rem_addr))) {
+ cm_node->do_lpb = true;
+ arpindex = irdma_arp_table(iwdev->rf, cm_node->rem_addr,
+ cm_node->ipv4, NULL,
+ IRDMA_ARP_RESOLVE);
+ } else {
+ oldarpindex = irdma_arp_table(iwdev->rf, cm_node->rem_addr,
+ cm_node->ipv4, NULL,
+ IRDMA_ARP_RESOLVE);
+ if (cm_node->ipv4)
+ arpindex = irdma_addr_resolve_neigh(iwdev,
+ cm_info->loc_addr[0],
+ cm_info->rem_addr[0],
+ oldarpindex);
+ else if (IS_ENABLED(CONFIG_IPV6))
+ arpindex = irdma_addr_resolve_neigh_ipv6(iwdev,
+ cm_info->loc_addr,
+ cm_info->rem_addr,
+ oldarpindex);
+ else
+ arpindex = -EINVAL;
+ }
+
+ if (arpindex < 0)
+ goto err;
+
+ ether_addr_copy(cm_node->rem_mac,
+ iwdev->rf->arp_table[arpindex].mac_addr);
+ irdma_add_hte_node(cm_core, cm_node);
+ cm_core->stats_nodes_created++;
+ return cm_node;
+
+err:
+ kfree(cm_node);
+
+ return NULL;
+}
+
+static void irdma_cm_node_free_cb(struct rcu_head *rcu_head)
+{
+ struct irdma_cm_node *cm_node =
+ container_of(rcu_head, struct irdma_cm_node, rcu_head);
+ struct irdma_cm_core *cm_core = cm_node->cm_core;
+ struct irdma_qp *iwqp;
+ struct irdma_cm_info nfo;
+
+ /* if the node is destroyed before connection was accelerated */
+ if (!cm_node->accelerated && cm_node->accept_pend) {
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: node destroyed before established\n");
+ atomic_dec(&cm_node->listener->pend_accepts_cnt);
+ }
+ if (cm_node->close_entry)
+ irdma_handle_close_entry(cm_node, 0);
+ if (cm_node->listener) {
+ irdma_dec_refcnt_listen(cm_core, cm_node->listener, 0, true);
+ } else {
+ if (cm_node->apbvt_set) {
+ irdma_del_apbvt(cm_node->iwdev, cm_node->apbvt_entry);
+ cm_node->apbvt_set = 0;
+ }
+ irdma_get_addr_info(cm_node, &nfo);
+ if (cm_node->qhash_set) {
+ nfo.qh_qpid = cm_node->iwdev->vsi.ilq->qp_id;
+ irdma_manage_qhash(cm_node->iwdev, &nfo,
+ IRDMA_QHASH_TYPE_TCP_ESTABLISHED,
+ IRDMA_QHASH_MANAGE_TYPE_DELETE, NULL,
+ false);
+ cm_node->qhash_set = 0;
+ }
+ }
+
+ iwqp = cm_node->iwqp;
+ if (iwqp) {
+ cm_node->cm_id->rem_ref(cm_node->cm_id);
+ cm_node->cm_id = NULL;
+ iwqp->cm_id = NULL;
+ irdma_qp_rem_ref(&iwqp->ibqp);
+ cm_node->iwqp = NULL;
+ } else if (cm_node->qhash_set) {
+ irdma_get_addr_info(cm_node, &nfo);
+ nfo.qh_qpid = cm_node->iwdev->vsi.ilq->qp_id;
+ irdma_manage_qhash(cm_node->iwdev, &nfo,
+ IRDMA_QHASH_TYPE_TCP_ESTABLISHED,
+ IRDMA_QHASH_MANAGE_TYPE_DELETE, NULL, false);
+ cm_node->qhash_set = 0;
+ }
+
+ cm_core->cm_free_ah(cm_node);
+ kfree(cm_node);
+}
+
+/**
+ * irdma_rem_ref_cm_node - destroy an instance of a cm node
+ * @cm_node: connection's node
+ */
+void irdma_rem_ref_cm_node(struct irdma_cm_node *cm_node)
+{
+ struct irdma_cm_core *cm_core = cm_node->cm_core;
+ unsigned long flags;
+
+ trace_irdma_rem_ref_cm_node(cm_node, 0, __builtin_return_address(0));
+ spin_lock_irqsave(&cm_core->ht_lock, flags);
+
+ if (!refcount_dec_and_test(&cm_node->refcnt)) {
+ spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+ return;
+ }
+ if (cm_node->iwqp) {
+ cm_node->iwqp->cm_node = NULL;
+ cm_node->iwqp->cm_id = NULL;
+ }
+ hash_del_rcu(&cm_node->list);
+ cm_node->cm_core->stats_nodes_destroyed++;
+
+ spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+
+ /* wait for all list walkers to exit their grace period */
+ call_rcu(&cm_node->rcu_head, irdma_cm_node_free_cb);
+}
+
+/**
+ * irdma_handle_fin_pkt - FIN packet received
+ * @cm_node: connection's node
+ */
+static void irdma_handle_fin_pkt(struct irdma_cm_node *cm_node)
+{
+ switch (cm_node->state) {
+ case IRDMA_CM_STATE_SYN_RCVD:
+ case IRDMA_CM_STATE_SYN_SENT:
+ case IRDMA_CM_STATE_ESTABLISHED:
+ case IRDMA_CM_STATE_MPAREJ_RCVD:
+ cm_node->tcp_cntxt.rcv_nxt++;
+ irdma_cleanup_retrans_entry(cm_node);
+ cm_node->state = IRDMA_CM_STATE_LAST_ACK;
+ irdma_send_fin(cm_node);
+ break;
+ case IRDMA_CM_STATE_MPAREQ_SENT:
+ irdma_create_event(cm_node, IRDMA_CM_EVENT_ABORTED);
+ cm_node->tcp_cntxt.rcv_nxt++;
+ irdma_cleanup_retrans_entry(cm_node);
+ cm_node->state = IRDMA_CM_STATE_CLOSED;
+ refcount_inc(&cm_node->refcnt);
+ irdma_send_reset(cm_node);
+ break;
+ case IRDMA_CM_STATE_FIN_WAIT1:
+ cm_node->tcp_cntxt.rcv_nxt++;
+ irdma_cleanup_retrans_entry(cm_node);
+ cm_node->state = IRDMA_CM_STATE_CLOSING;
+ irdma_send_ack(cm_node);
+ /*
+ * Wait for ACK as this is simultaneous close.
+ * After we receive ACK, do not send anything.
+ * Just rm the node.
+ */
+ break;
+ case IRDMA_CM_STATE_FIN_WAIT2:
+ cm_node->tcp_cntxt.rcv_nxt++;
+ irdma_cleanup_retrans_entry(cm_node);
+ cm_node->state = IRDMA_CM_STATE_TIME_WAIT;
+ irdma_send_ack(cm_node);
+ irdma_schedule_cm_timer(cm_node, NULL, IRDMA_TIMER_TYPE_CLOSE,
+ 1, 0);
+ break;
+ case IRDMA_CM_STATE_TIME_WAIT:
+ cm_node->tcp_cntxt.rcv_nxt++;
+ irdma_cleanup_retrans_entry(cm_node);
+ cm_node->state = IRDMA_CM_STATE_CLOSED;
+ irdma_rem_ref_cm_node(cm_node);
+ break;
+ case IRDMA_CM_STATE_OFFLOADED:
+ default:
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: bad state node state = %d\n", cm_node->state);
+ break;
+ }
+}
+
+/**
+ * irdma_handle_rst_pkt - process received RST packet
+ * @cm_node: connection's node
+ * @rbuf: receive buffer
+ */
+static void irdma_handle_rst_pkt(struct irdma_cm_node *cm_node,
+ struct irdma_puda_buf *rbuf)
+{
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: caller: %pS cm_node=%p state=%d rem_port=0x%04x loc_port=0x%04x rem_addr=%pI4 loc_addr=%pI4\n",
+ __builtin_return_address(0), cm_node, cm_node->state,
+ cm_node->rem_port, cm_node->loc_port, cm_node->rem_addr,
+ cm_node->loc_addr);
+
+ irdma_cleanup_retrans_entry(cm_node);
+ switch (cm_node->state) {
+ case IRDMA_CM_STATE_SYN_SENT:
+ case IRDMA_CM_STATE_MPAREQ_SENT:
+ switch (cm_node->mpa_frame_rev) {
+ case IETF_MPA_V2:
+ /* Drop down to MPA_V1*/
+ cm_node->mpa_frame_rev = IETF_MPA_V1;
+ /* send a syn and goto syn sent state */
+ cm_node->state = IRDMA_CM_STATE_SYN_SENT;
+ if (irdma_send_syn(cm_node, 0))
+ irdma_active_open_err(cm_node, false);
+ break;
+ case IETF_MPA_V1:
+ default:
+ irdma_active_open_err(cm_node, false);
+ break;
+ }
+ break;
+ case IRDMA_CM_STATE_MPAREQ_RCVD:
+ atomic_inc(&cm_node->passive_state);
+ break;
+ case IRDMA_CM_STATE_ESTABLISHED:
+ case IRDMA_CM_STATE_SYN_RCVD:
+ case IRDMA_CM_STATE_LISTENING:
+ irdma_passive_open_err(cm_node, false);
+ break;
+ case IRDMA_CM_STATE_OFFLOADED:
+ irdma_active_open_err(cm_node, false);
+ break;
+ case IRDMA_CM_STATE_CLOSED:
+ break;
+ case IRDMA_CM_STATE_FIN_WAIT2:
+ case IRDMA_CM_STATE_FIN_WAIT1:
+ case IRDMA_CM_STATE_LAST_ACK:
+ case IRDMA_CM_STATE_TIME_WAIT:
+ cm_node->state = IRDMA_CM_STATE_CLOSED;
+ irdma_rem_ref_cm_node(cm_node);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * irdma_handle_rcv_mpa - Process a recv'd mpa buffer
+ * @cm_node: connection's node
+ * @rbuf: receive buffer
+ */
+static void irdma_handle_rcv_mpa(struct irdma_cm_node *cm_node,
+ struct irdma_puda_buf *rbuf)
+{
+ int err;
+ int datasize = rbuf->datalen;
+ u8 *dataloc = rbuf->data;
+
+ enum irdma_cm_event_type type = IRDMA_CM_EVENT_UNKNOWN;
+ u32 res_type;
+
+ err = irdma_parse_mpa(cm_node, dataloc, &res_type, datasize);
+ if (err) {
+ if (cm_node->state == IRDMA_CM_STATE_MPAREQ_SENT)
+ irdma_active_open_err(cm_node, true);
+ else
+ irdma_passive_open_err(cm_node, true);
+ return;
+ }
+
+ switch (cm_node->state) {
+ case IRDMA_CM_STATE_ESTABLISHED:
+ if (res_type == IRDMA_MPA_REQUEST_REJECT)
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: state for reject\n");
+ cm_node->state = IRDMA_CM_STATE_MPAREQ_RCVD;
+ type = IRDMA_CM_EVENT_MPA_REQ;
+ irdma_send_ack(cm_node); /* ACK received MPA request */
+ atomic_set(&cm_node->passive_state,
+ IRDMA_PASSIVE_STATE_INDICATED);
+ break;
+ case IRDMA_CM_STATE_MPAREQ_SENT:
+ irdma_cleanup_retrans_entry(cm_node);
+ if (res_type == IRDMA_MPA_REQUEST_REJECT) {
+ type = IRDMA_CM_EVENT_MPA_REJECT;
+ cm_node->state = IRDMA_CM_STATE_MPAREJ_RCVD;
+ } else {
+ type = IRDMA_CM_EVENT_CONNECTED;
+ cm_node->state = IRDMA_CM_STATE_OFFLOADED;
+ }
+ irdma_send_ack(cm_node);
+ break;
+ default:
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: wrong cm_node state =%d\n", cm_node->state);
+ break;
+ }
+ irdma_create_event(cm_node, type);
+}
+
+/**
+ * irdma_check_syn - Check for error on received syn ack
+ * @cm_node: connection's node
+ * @tcph: pointer tcp header
+ */
+static int irdma_check_syn(struct irdma_cm_node *cm_node, struct tcphdr *tcph)
+{
+ if (ntohl(tcph->ack_seq) != cm_node->tcp_cntxt.loc_seq_num) {
+ irdma_active_open_err(cm_node, true);
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_check_seq - check seq numbers if OK
+ * @cm_node: connection's node
+ * @tcph: pointer tcp header
+ */
+static int irdma_check_seq(struct irdma_cm_node *cm_node, struct tcphdr *tcph)
+{
+ 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;
+ int err = 0;
+
+ seq = ntohl(tcph->seq);
+ ack_seq = ntohl(tcph->ack_seq);
+ rcv_wnd = cm_node->tcp_cntxt.rcv_wnd;
+ if (ack_seq != loc_seq_num ||
+ !between(seq, rcv_nxt, (rcv_nxt + rcv_wnd)))
+ err = -1;
+ if (err)
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: seq number err\n");
+
+ return err;
+}
+
+void irdma_add_conn_est_qh(struct irdma_cm_node *cm_node)
+{
+ struct irdma_cm_info nfo;
+
+ irdma_get_addr_info(cm_node, &nfo);
+ nfo.qh_qpid = cm_node->iwdev->vsi.ilq->qp_id;
+ irdma_manage_qhash(cm_node->iwdev, &nfo,
+ IRDMA_QHASH_TYPE_TCP_ESTABLISHED,
+ IRDMA_QHASH_MANAGE_TYPE_ADD,
+ cm_node, false);
+ cm_node->qhash_set = true;
+}
+
+/**
+ * irdma_handle_syn_pkt - is for Passive node
+ * @cm_node: connection's node
+ * @rbuf: receive buffer
+ */
+static void irdma_handle_syn_pkt(struct irdma_cm_node *cm_node,
+ struct irdma_puda_buf *rbuf)
+{
+ struct tcphdr *tcph = (struct tcphdr *)rbuf->tcph;
+ int err;
+ u32 inc_sequence;
+ int optionsize;
+
+ optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
+ inc_sequence = ntohl(tcph->seq);
+
+ switch (cm_node->state) {
+ case IRDMA_CM_STATE_SYN_SENT:
+ case IRDMA_CM_STATE_MPAREQ_SENT:
+ /* Rcvd syn on active open connection */
+ irdma_active_open_err(cm_node, 1);
+ break;
+ case IRDMA_CM_STATE_LISTENING:
+ /* Passive OPEN */
+ if (atomic_read(&cm_node->listener->pend_accepts_cnt) >
+ cm_node->listener->backlog) {
+ cm_node->cm_core->stats_backlog_drops++;
+ irdma_passive_open_err(cm_node, false);
+ break;
+ }
+ err = irdma_handle_tcp_options(cm_node, tcph, optionsize, 1);
+ if (err) {
+ irdma_passive_open_err(cm_node, false);
+ /* drop pkt */
+ break;
+ }
+ err = cm_node->cm_core->cm_create_ah(cm_node, false);
+ if (err) {
+ irdma_passive_open_err(cm_node, false);
+ /* drop pkt */
+ break;
+ }
+ cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
+ cm_node->accept_pend = 1;
+ atomic_inc(&cm_node->listener->pend_accepts_cnt);
+
+ cm_node->state = IRDMA_CM_STATE_SYN_RCVD;
+ break;
+ case IRDMA_CM_STATE_CLOSED:
+ irdma_cleanup_retrans_entry(cm_node);
+ refcount_inc(&cm_node->refcnt);
+ irdma_send_reset(cm_node);
+ break;
+ case IRDMA_CM_STATE_OFFLOADED:
+ case IRDMA_CM_STATE_ESTABLISHED:
+ case IRDMA_CM_STATE_FIN_WAIT1:
+ case IRDMA_CM_STATE_FIN_WAIT2:
+ case IRDMA_CM_STATE_MPAREQ_RCVD:
+ case IRDMA_CM_STATE_LAST_ACK:
+ case IRDMA_CM_STATE_CLOSING:
+ case IRDMA_CM_STATE_UNKNOWN:
+ default:
+ break;
+ }
+}
+
+/**
+ * irdma_handle_synack_pkt - Process SYN+ACK packet (active side)
+ * @cm_node: connection's node
+ * @rbuf: receive buffer
+ */
+static void irdma_handle_synack_pkt(struct irdma_cm_node *cm_node,
+ struct irdma_puda_buf *rbuf)
+{
+ struct tcphdr *tcph = (struct tcphdr *)rbuf->tcph;
+ int err;
+ u32 inc_sequence;
+ int optionsize;
+
+ optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
+ inc_sequence = ntohl(tcph->seq);
+ switch (cm_node->state) {
+ case IRDMA_CM_STATE_SYN_SENT:
+ irdma_cleanup_retrans_entry(cm_node);
+ /* active open */
+ if (irdma_check_syn(cm_node, tcph)) {
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: check syn fail\n");
+ return;
+ }
+ cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
+ /* setup options */
+ err = irdma_handle_tcp_options(cm_node, tcph, optionsize, 0);
+ if (err) {
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: cm_node=%p tcp_options failed\n",
+ cm_node);
+ break;
+ }
+ irdma_cleanup_retrans_entry(cm_node);
+ cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
+ irdma_send_ack(cm_node); /* ACK for the syn_ack */
+ err = irdma_send_mpa_request(cm_node);
+ if (err) {
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: cm_node=%p irdma_send_mpa_request failed\n",
+ cm_node);
+ break;
+ }
+ cm_node->state = IRDMA_CM_STATE_MPAREQ_SENT;
+ break;
+ case IRDMA_CM_STATE_MPAREQ_RCVD:
+ irdma_passive_open_err(cm_node, true);
+ break;
+ case IRDMA_CM_STATE_LISTENING:
+ cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+ irdma_cleanup_retrans_entry(cm_node);
+ cm_node->state = IRDMA_CM_STATE_CLOSED;
+ irdma_send_reset(cm_node);
+ break;
+ case IRDMA_CM_STATE_CLOSED:
+ cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+ irdma_cleanup_retrans_entry(cm_node);
+ refcount_inc(&cm_node->refcnt);
+ irdma_send_reset(cm_node);
+ break;
+ case IRDMA_CM_STATE_ESTABLISHED:
+ case IRDMA_CM_STATE_FIN_WAIT1:
+ case IRDMA_CM_STATE_FIN_WAIT2:
+ case IRDMA_CM_STATE_LAST_ACK:
+ case IRDMA_CM_STATE_OFFLOADED:
+ case IRDMA_CM_STATE_CLOSING:
+ case IRDMA_CM_STATE_UNKNOWN:
+ case IRDMA_CM_STATE_MPAREQ_SENT:
+ default:
+ break;
+ }
+}
+
+/**
+ * irdma_handle_ack_pkt - process packet with ACK
+ * @cm_node: connection's node
+ * @rbuf: receive buffer
+ */
+static int irdma_handle_ack_pkt(struct irdma_cm_node *cm_node,
+ struct irdma_puda_buf *rbuf)
+{
+ struct tcphdr *tcph = (struct tcphdr *)rbuf->tcph;
+ u32 inc_sequence;
+ int ret;
+ int optionsize;
+ u32 datasize = rbuf->datalen;
+
+ optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
+
+ if (irdma_check_seq(cm_node, tcph))
+ return -EINVAL;
+
+ inc_sequence = ntohl(tcph->seq);
+ switch (cm_node->state) {
+ case IRDMA_CM_STATE_SYN_RCVD:
+ irdma_cleanup_retrans_entry(cm_node);
+ ret = irdma_handle_tcp_options(cm_node, tcph, optionsize, 1);
+ if (ret)
+ return ret;
+ cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
+ cm_node->state = IRDMA_CM_STATE_ESTABLISHED;
+ if (datasize) {
+ cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
+ irdma_handle_rcv_mpa(cm_node, rbuf);
+ }
+ break;
+ case IRDMA_CM_STATE_ESTABLISHED:
+ irdma_cleanup_retrans_entry(cm_node);
+ if (datasize) {
+ cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
+ irdma_handle_rcv_mpa(cm_node, rbuf);
+ }
+ break;
+ case IRDMA_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;
+ cm_node->ack_rcvd = false;
+ irdma_handle_rcv_mpa(cm_node, rbuf);
+ } else {
+ cm_node->ack_rcvd = true;
+ }
+ break;
+ case IRDMA_CM_STATE_LISTENING:
+ irdma_cleanup_retrans_entry(cm_node);
+ cm_node->state = IRDMA_CM_STATE_CLOSED;
+ irdma_send_reset(cm_node);
+ break;
+ case IRDMA_CM_STATE_CLOSED:
+ irdma_cleanup_retrans_entry(cm_node);
+ refcount_inc(&cm_node->refcnt);
+ irdma_send_reset(cm_node);
+ break;
+ case IRDMA_CM_STATE_LAST_ACK:
+ case IRDMA_CM_STATE_CLOSING:
+ irdma_cleanup_retrans_entry(cm_node);
+ cm_node->state = IRDMA_CM_STATE_CLOSED;
+ irdma_rem_ref_cm_node(cm_node);
+ break;
+ case IRDMA_CM_STATE_FIN_WAIT1:
+ irdma_cleanup_retrans_entry(cm_node);
+ cm_node->state = IRDMA_CM_STATE_FIN_WAIT2;
+ break;
+ case IRDMA_CM_STATE_SYN_SENT:
+ case IRDMA_CM_STATE_FIN_WAIT2:
+ case IRDMA_CM_STATE_OFFLOADED:
+ case IRDMA_CM_STATE_MPAREQ_RCVD:
+ case IRDMA_CM_STATE_UNKNOWN:
+ default:
+ irdma_cleanup_retrans_entry(cm_node);
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_process_pkt - process cm packet
+ * @cm_node: connection's node
+ * @rbuf: receive buffer
+ */
+static void irdma_process_pkt(struct irdma_cm_node *cm_node,
+ struct irdma_puda_buf *rbuf)
+{
+ enum irdma_tcpip_pkt_type pkt_type = IRDMA_PKT_TYPE_UNKNOWN;
+ struct tcphdr *tcph = (struct tcphdr *)rbuf->tcph;
+ u32 fin_set = 0;
+ int err;
+
+ if (tcph->rst) {
+ pkt_type = IRDMA_PKT_TYPE_RST;
+ } else if (tcph->syn) {
+ pkt_type = IRDMA_PKT_TYPE_SYN;
+ if (tcph->ack)
+ pkt_type = IRDMA_PKT_TYPE_SYNACK;
+ } else if (tcph->ack) {
+ pkt_type = IRDMA_PKT_TYPE_ACK;
+ }
+ if (tcph->fin)
+ fin_set = 1;
+
+ switch (pkt_type) {
+ case IRDMA_PKT_TYPE_SYN:
+ irdma_handle_syn_pkt(cm_node, rbuf);
+ break;
+ case IRDMA_PKT_TYPE_SYNACK:
+ irdma_handle_synack_pkt(cm_node, rbuf);
+ break;
+ case IRDMA_PKT_TYPE_ACK:
+ err = irdma_handle_ack_pkt(cm_node, rbuf);
+ if (fin_set && !err)
+ irdma_handle_fin_pkt(cm_node);
+ break;
+ case IRDMA_PKT_TYPE_RST:
+ irdma_handle_rst_pkt(cm_node, rbuf);
+ break;
+ default:
+ if (fin_set &&
+ (!irdma_check_seq(cm_node, (struct tcphdr *)rbuf->tcph)))
+ irdma_handle_fin_pkt(cm_node);
+ break;
+ }
+}
+
+/**
+ * irdma_make_listen_node - create a listen node with params
+ * @cm_core: cm's core
+ * @iwdev: iwarp device structure
+ * @cm_info: quad info for connection
+ */
+static struct irdma_cm_listener *
+irdma_make_listen_node(struct irdma_cm_core *cm_core,
+ struct irdma_device *iwdev,
+ struct irdma_cm_info *cm_info)
+{
+ struct irdma_cm_listener *listener;
+ unsigned long flags;
+
+ /* cannot have multiple matching listeners */
+ listener = irdma_find_listener(cm_core, cm_info->loc_addr,
+ cm_info->loc_port, cm_info->vlan_id,
+ IRDMA_CM_LISTENER_EITHER_STATE);
+ if (listener &&
+ listener->listener_state == IRDMA_CM_LISTENER_ACTIVE_STATE) {
+ refcount_dec(&listener->refcnt);
+ return NULL;
+ }
+
+ if (!listener) {
+ /* create a CM listen node
+ * 1/2 node to compare incoming traffic to
+ */
+ listener = kzalloc(sizeof(*listener), GFP_KERNEL);
+ if (!listener)
+ return NULL;
+ cm_core->stats_listen_nodes_created++;
+ memcpy(listener->loc_addr, cm_info->loc_addr,
+ sizeof(listener->loc_addr));
+ listener->loc_port = cm_info->loc_port;
+
+ INIT_LIST_HEAD(&listener->child_listen_list);
+
+ refcount_set(&listener->refcnt, 1);
+ } else {
+ listener->reused_node = 1;
+ }
+
+ listener->cm_id = cm_info->cm_id;
+ listener->ipv4 = cm_info->ipv4;
+ listener->vlan_id = cm_info->vlan_id;
+ atomic_set(&listener->pend_accepts_cnt, 0);
+ listener->cm_core = cm_core;
+ listener->iwdev = iwdev;
+
+ listener->backlog = cm_info->backlog;
+ listener->listener_state = IRDMA_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);
+ spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+ }
+
+ return listener;
+}
+
+/**
+ * irdma_create_cm_node - make a connection node with params
+ * @cm_core: cm's core
+ * @iwdev: iwarp device structure
+ * @conn_param: connection parameters
+ * @cm_info: quad info for connection
+ * @caller_cm_node: pointer to cm_node structure to return
+ */
+static int irdma_create_cm_node(struct irdma_cm_core *cm_core,
+ struct irdma_device *iwdev,
+ struct iw_cm_conn_param *conn_param,
+ struct irdma_cm_info *cm_info,
+ struct irdma_cm_node **caller_cm_node)
+{
+ struct irdma_cm_node *cm_node;
+ u16 private_data_len = conn_param->private_data_len;
+ const void *private_data = conn_param->private_data;
+
+ /* create a CM connection node */
+ cm_node = irdma_make_cm_node(cm_core, iwdev, cm_info, NULL);
+ if (!cm_node)
+ return -ENOMEM;
+
+ /* set our node side to client (active) side */
+ cm_node->tcp_cntxt.client = 1;
+ cm_node->tcp_cntxt.rcv_wscale = IRDMA_CM_DEFAULT_RCV_WND_SCALE;
+
+ irdma_record_ird_ord(cm_node, conn_param->ird, conn_param->ord);
+
+ cm_node->pdata.size = private_data_len;
+ cm_node->pdata.addr = cm_node->pdata_buf;
+
+ memcpy(cm_node->pdata_buf, private_data, private_data_len);
+ *caller_cm_node = cm_node;
+
+ return 0;
+}
+
+/**
+ * irdma_cm_reject - reject and teardown a connection
+ * @cm_node: connection's node
+ * @pdata: ptr to private data for reject
+ * @plen: size of private data
+ */
+static int irdma_cm_reject(struct irdma_cm_node *cm_node, const void *pdata,
+ u8 plen)
+{
+ int ret;
+ int passive_state;
+
+ if (cm_node->tcp_cntxt.client)
+ return 0;
+
+ irdma_cleanup_retrans_entry(cm_node);
+
+ passive_state = atomic_add_return(1, &cm_node->passive_state);
+ if (passive_state == IRDMA_SEND_RESET_EVENT) {
+ cm_node->state = IRDMA_CM_STATE_CLOSED;
+ irdma_rem_ref_cm_node(cm_node);
+ return 0;
+ }
+
+ if (cm_node->state == IRDMA_CM_STATE_LISTENER_DESTROYED) {
+ irdma_rem_ref_cm_node(cm_node);
+ return 0;
+ }
+
+ ret = irdma_send_mpa_reject(cm_node, pdata, plen);
+ if (!ret)
+ return 0;
+
+ cm_node->state = IRDMA_CM_STATE_CLOSED;
+ if (irdma_send_reset(cm_node))
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: send reset failed\n");
+
+ return ret;
+}
+
+/**
+ * irdma_cm_close - close of cm connection
+ * @cm_node: connection's node
+ */
+static int irdma_cm_close(struct irdma_cm_node *cm_node)
+{
+ switch (cm_node->state) {
+ case IRDMA_CM_STATE_SYN_RCVD:
+ case IRDMA_CM_STATE_SYN_SENT:
+ case IRDMA_CM_STATE_ONE_SIDE_ESTABLISHED:
+ case IRDMA_CM_STATE_ESTABLISHED:
+ case IRDMA_CM_STATE_ACCEPTING:
+ case IRDMA_CM_STATE_MPAREQ_SENT:
+ case IRDMA_CM_STATE_MPAREQ_RCVD:
+ irdma_cleanup_retrans_entry(cm_node);
+ irdma_send_reset(cm_node);
+ break;
+ case IRDMA_CM_STATE_CLOSE_WAIT:
+ cm_node->state = IRDMA_CM_STATE_LAST_ACK;
+ irdma_send_fin(cm_node);
+ break;
+ case IRDMA_CM_STATE_FIN_WAIT1:
+ case IRDMA_CM_STATE_FIN_WAIT2:
+ case IRDMA_CM_STATE_LAST_ACK:
+ case IRDMA_CM_STATE_TIME_WAIT:
+ case IRDMA_CM_STATE_CLOSING:
+ return -EINVAL;
+ case IRDMA_CM_STATE_LISTENING:
+ irdma_cleanup_retrans_entry(cm_node);
+ irdma_send_reset(cm_node);
+ break;
+ case IRDMA_CM_STATE_MPAREJ_RCVD:
+ case IRDMA_CM_STATE_UNKNOWN:
+ case IRDMA_CM_STATE_INITED:
+ case IRDMA_CM_STATE_CLOSED:
+ case IRDMA_CM_STATE_LISTENER_DESTROYED:
+ irdma_rem_ref_cm_node(cm_node);
+ break;
+ case IRDMA_CM_STATE_OFFLOADED:
+ if (cm_node->send_entry)
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: CM send_entry in OFFLOADED state\n");
+ irdma_rem_ref_cm_node(cm_node);
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_receive_ilq - recv an ETHERNET packet, and process it
+ * through CM
+ * @vsi: VSI structure of dev
+ * @rbuf: receive buffer
+ */
+void irdma_receive_ilq(struct irdma_sc_vsi *vsi, struct irdma_puda_buf *rbuf)
+{
+ struct irdma_cm_node *cm_node;
+ struct irdma_cm_listener *listener;
+ struct iphdr *iph;
+ struct ipv6hdr *ip6h;
+ struct tcphdr *tcph;
+ struct irdma_cm_info cm_info = {};
+ struct irdma_device *iwdev = vsi->back_vsi;
+ struct irdma_cm_core *cm_core = &iwdev->cm_core;
+ struct vlan_ethhdr *ethh;
+ u16 vtag;
+
+ /* if vlan, then maclen = 18 else 14 */
+ iph = (struct iphdr *)rbuf->iph;
+ print_hex_dump_debug("ILQ: RECEIVE ILQ BUFFER", DUMP_PREFIX_OFFSET,
+ 16, 8, rbuf->mem.va, rbuf->totallen, false);
+ if (iwdev->rf->sc_dev.hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
+ if (rbuf->vlan_valid) {
+ vtag = rbuf->vlan_id;
+ cm_info.user_pri = (vtag & VLAN_PRIO_MASK) >>
+ VLAN_PRIO_SHIFT;
+ cm_info.vlan_id = vtag & VLAN_VID_MASK;
+ } else {
+ cm_info.vlan_id = 0xFFFF;
+ }
+ } else {
+ ethh = rbuf->mem.va;
+
+ if (ethh->h_vlan_proto == htons(ETH_P_8021Q)) {
+ vtag = ntohs(ethh->h_vlan_TCI);
+ cm_info.user_pri = (vtag & VLAN_PRIO_MASK) >>
+ VLAN_PRIO_SHIFT;
+ cm_info.vlan_id = vtag & VLAN_VID_MASK;
+ ibdev_dbg(&cm_core->iwdev->ibdev,
+ "CM: vlan_id=%d\n", cm_info.vlan_id);
+ } else {
+ cm_info.vlan_id = 0xFFFF;
+ }
+ }
+ tcph = (struct tcphdr *)rbuf->tcph;
+
+ if (rbuf->ipv4) {
+ cm_info.loc_addr[0] = ntohl(iph->daddr);
+ cm_info.rem_addr[0] = ntohl(iph->saddr);
+ cm_info.ipv4 = true;
+ cm_info.tos = iph->tos;
+ } else {
+ ip6h = (struct ipv6hdr *)rbuf->iph;
+ irdma_copy_ip_ntohl(cm_info.loc_addr,
+ ip6h->daddr.in6_u.u6_addr32);
+ irdma_copy_ip_ntohl(cm_info.rem_addr,
+ ip6h->saddr.in6_u.u6_addr32);
+ cm_info.ipv4 = false;
+ cm_info.tos = (ip6h->priority << 4) | (ip6h->flow_lbl[0] >> 4);
+ }
+ cm_info.loc_port = ntohs(tcph->dest);
+ cm_info.rem_port = ntohs(tcph->source);
+ cm_node = irdma_find_node(cm_core, cm_info.rem_port, cm_info.rem_addr,
+ cm_info.loc_port, cm_info.loc_addr, cm_info.vlan_id);
+
+ if (!cm_node) {
+ /* Only type of packet accepted are for the
+ * PASSIVE open (syn only)
+ */
+ if (!tcph->syn || tcph->ack)
+ return;
+
+ listener = irdma_find_listener(cm_core,
+ cm_info.loc_addr,
+ cm_info.loc_port,
+ cm_info.vlan_id,
+ IRDMA_CM_LISTENER_ACTIVE_STATE);
+ if (!listener) {
+ cm_info.cm_id = NULL;
+ ibdev_dbg(&cm_core->iwdev->ibdev,
+ "CM: no listener found\n");
+ return;
+ }
+
+ cm_info.cm_id = listener->cm_id;
+ cm_node = irdma_make_cm_node(cm_core, iwdev, &cm_info,
+ listener);
+ if (!cm_node) {
+ ibdev_dbg(&cm_core->iwdev->ibdev,
+ "CM: allocate node failed\n");
+ refcount_dec(&listener->refcnt);
+ return;
+ }
+
+ if (!tcph->rst && !tcph->fin) {
+ cm_node->state = IRDMA_CM_STATE_LISTENING;
+ } else {
+ irdma_rem_ref_cm_node(cm_node);
+ return;
+ }
+
+ refcount_inc(&cm_node->refcnt);
+ } else if (cm_node->state == IRDMA_CM_STATE_OFFLOADED) {
+ irdma_rem_ref_cm_node(cm_node);
+ return;
+ }
+
+ irdma_process_pkt(cm_node, rbuf);
+ irdma_rem_ref_cm_node(cm_node);
+}
+
+static int irdma_add_qh(struct irdma_cm_node *cm_node, bool active)
+{
+ if (!active)
+ irdma_add_conn_est_qh(cm_node);
+ return 0;
+}
+
+static void irdma_cm_free_ah_nop(struct irdma_cm_node *cm_node)
+{
+}
+
+/**
+ * irdma_setup_cm_core - setup top level instance of a cm core
+ * @iwdev: iwarp device structure
+ * @rdma_ver: HW version
+ */
+enum irdma_status_code irdma_setup_cm_core(struct irdma_device *iwdev,
+ u8 rdma_ver)
+{
+ struct irdma_cm_core *cm_core = &iwdev->cm_core;
+
+ cm_core->iwdev = iwdev;
+ cm_core->dev = &iwdev->rf->sc_dev;
+
+ /* Handles CM event work items send to Iwarp core */
+ cm_core->event_wq = alloc_ordered_workqueue("iwarp-event-wq", 0);
+ if (!cm_core->event_wq)
+ return IRDMA_ERR_NO_MEMORY;
+
+ INIT_LIST_HEAD(&cm_core->listen_list);
+
+ timer_setup(&cm_core->tcp_timer, irdma_cm_timer_tick, 0);
+
+ spin_lock_init(&cm_core->ht_lock);
+ spin_lock_init(&cm_core->listen_list_lock);
+ spin_lock_init(&cm_core->apbvt_lock);
+ switch (rdma_ver) {
+ case IRDMA_GEN_1:
+ cm_core->form_cm_frame = irdma_form_uda_cm_frame;
+ cm_core->cm_create_ah = irdma_add_qh;
+ cm_core->cm_free_ah = irdma_cm_free_ah_nop;
+ break;
+ case IRDMA_GEN_2:
+ default:
+ cm_core->form_cm_frame = irdma_form_ah_cm_frame;
+ cm_core->cm_create_ah = irdma_cm_create_ah;
+ cm_core->cm_free_ah = irdma_cm_free_ah;
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_cleanup_cm_core - deallocate a top level instance of a
+ * cm core
+ * @cm_core: cm's core
+ */
+void irdma_cleanup_cm_core(struct irdma_cm_core *cm_core)
+{
+ unsigned long flags;
+
+ if (!cm_core)
+ return;
+
+ spin_lock_irqsave(&cm_core->ht_lock, flags);
+ if (timer_pending(&cm_core->tcp_timer))
+ del_timer_sync(&cm_core->tcp_timer);
+ spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+
+ destroy_workqueue(cm_core->event_wq);
+ cm_core->dev->ws_reset(&cm_core->iwdev->vsi);
+}
+
+/**
+ * irdma_init_tcp_ctx - setup qp context
+ * @cm_node: connection's node
+ * @tcp_info: offload info for tcp
+ * @iwqp: associate qp for the connection
+ */
+static void irdma_init_tcp_ctx(struct irdma_cm_node *cm_node,
+ struct irdma_tcp_offload_info *tcp_info,
+ struct irdma_qp *iwqp)
+{
+ tcp_info->ipv4 = cm_node->ipv4;
+ tcp_info->drop_ooo_seg = !iwqp->iwdev->iw_ooo;
+ tcp_info->wscale = true;
+ tcp_info->ignore_tcp_opt = true;
+ tcp_info->ignore_tcp_uns_opt = true;
+ tcp_info->no_nagle = false;
+
+ tcp_info->ttl = IRDMA_DEFAULT_TTL;
+ tcp_info->rtt_var = IRDMA_DEFAULT_RTT_VAR;
+ tcp_info->ss_thresh = IRDMA_DEFAULT_SS_THRESH;
+ tcp_info->rexmit_thresh = IRDMA_DEFAULT_REXMIT_THRESH;
+
+ tcp_info->tcp_state = IRDMA_TCP_STATE_ESTABLISHED;
+ tcp_info->snd_wscale = cm_node->tcp_cntxt.snd_wscale;
+ tcp_info->rcv_wscale = cm_node->tcp_cntxt.rcv_wscale;
+
+ tcp_info->snd_nxt = cm_node->tcp_cntxt.loc_seq_num;
+ tcp_info->snd_wnd = cm_node->tcp_cntxt.snd_wnd;
+ tcp_info->rcv_nxt = cm_node->tcp_cntxt.rcv_nxt;
+ tcp_info->snd_max = cm_node->tcp_cntxt.loc_seq_num;
+
+ tcp_info->snd_una = cm_node->tcp_cntxt.loc_seq_num;
+ tcp_info->cwnd = 2 * cm_node->tcp_cntxt.mss;
+ tcp_info->snd_wl1 = cm_node->tcp_cntxt.rcv_nxt;
+ tcp_info->snd_wl2 = cm_node->tcp_cntxt.loc_seq_num;
+ tcp_info->max_snd_window = cm_node->tcp_cntxt.max_snd_wnd;
+ tcp_info->rcv_wnd = cm_node->tcp_cntxt.rcv_wnd
+ << cm_node->tcp_cntxt.rcv_wscale;
+
+ tcp_info->flow_label = 0;
+ tcp_info->snd_mss = (u32)cm_node->tcp_cntxt.mss;
+ tcp_info->tos = cm_node->tos;
+ if (cm_node->vlan_id < VLAN_N_VID) {
+ tcp_info->insert_vlan_tag = true;
+ tcp_info->vlan_tag = cm_node->vlan_id;
+ tcp_info->vlan_tag |= cm_node->user_pri << VLAN_PRIO_SHIFT;
+ }
+ if (cm_node->ipv4) {
+ tcp_info->src_port = cm_node->loc_port;
+ tcp_info->dst_port = cm_node->rem_port;
+
+ tcp_info->dest_ip_addr[3] = cm_node->rem_addr[0];
+ tcp_info->local_ipaddr[3] = cm_node->loc_addr[0];
+ tcp_info->arp_idx = (u16)irdma_arp_table(iwqp->iwdev->rf,
+ &tcp_info->dest_ip_addr[3],
+ true, NULL,
+ IRDMA_ARP_RESOLVE);
+ } else {
+ tcp_info->src_port = cm_node->loc_port;
+ tcp_info->dst_port = cm_node->rem_port;
+ memcpy(tcp_info->dest_ip_addr, cm_node->rem_addr,
+ sizeof(tcp_info->dest_ip_addr));
+ memcpy(tcp_info->local_ipaddr, cm_node->loc_addr,
+ sizeof(tcp_info->local_ipaddr));
+
+ tcp_info->arp_idx = (u16)irdma_arp_table(iwqp->iwdev->rf,
+ &tcp_info->dest_ip_addr[0],
+ false, NULL,
+ IRDMA_ARP_RESOLVE);
+ }
+}
+
+/**
+ * irdma_cm_init_tsa_conn - setup qp for RTS
+ * @iwqp: associate qp for the connection
+ * @cm_node: connection's node
+ */
+static void irdma_cm_init_tsa_conn(struct irdma_qp *iwqp,
+ struct irdma_cm_node *cm_node)
+{
+ struct irdma_iwarp_offload_info *iwarp_info;
+ struct irdma_qp_host_ctx_info *ctx_info;
+
+ iwarp_info = &iwqp->iwarp_info;
+ ctx_info = &iwqp->ctx_info;
+
+ ctx_info->tcp_info = &iwqp->tcp_info;
+ ctx_info->send_cq_num = iwqp->iwscq->sc_cq.cq_uk.cq_id;
+ ctx_info->rcv_cq_num = iwqp->iwrcq->sc_cq.cq_uk.cq_id;
+
+ iwarp_info->ord_size = cm_node->ord_size;
+ iwarp_info->ird_size = cm_node->ird_size;
+ iwarp_info->rd_en = true;
+ iwarp_info->rdmap_ver = 1;
+ iwarp_info->ddp_ver = 1;
+ iwarp_info->pd_id = iwqp->iwpd->sc_pd.pd_id;
+
+ ctx_info->tcp_info_valid = true;
+ ctx_info->iwarp_info_valid = true;
+ ctx_info->user_pri = cm_node->user_pri;
+
+ irdma_init_tcp_ctx(cm_node, &iwqp->tcp_info, iwqp);
+ if (cm_node->snd_mark_en) {
+ iwarp_info->snd_mark_en = true;
+ iwarp_info->snd_mark_offset = (iwqp->tcp_info.snd_nxt & SNDMARKER_SEQNMASK) +
+ cm_node->lsmm_size;
+ }
+
+ cm_node->state = IRDMA_CM_STATE_OFFLOADED;
+ iwqp->tcp_info.tcp_state = IRDMA_TCP_STATE_ESTABLISHED;
+ iwqp->tcp_info.src_mac_addr_idx = iwqp->iwdev->mac_ip_table_idx;
+
+ if (cm_node->rcv_mark_en) {
+ iwarp_info->rcv_mark_en = true;
+ iwarp_info->align_hdrs = true;
+ }
+
+ irdma_sc_qp_setctx(&iwqp->sc_qp, iwqp->host_ctx.va, ctx_info);
+
+ /* once tcp_info is set, no need to do it again */
+ ctx_info->tcp_info_valid = false;
+ ctx_info->iwarp_info_valid = false;
+}
+
+/**
+ * irdma_cm_disconn - when a connection is being closed
+ * @iwqp: associated qp for the connection
+ */
+void irdma_cm_disconn(struct irdma_qp *iwqp)
+{
+ struct irdma_device *iwdev = iwqp->iwdev;
+ struct disconn_work *work;
+ unsigned long flags;
+
+ work = kzalloc(sizeof(*work), GFP_ATOMIC);
+ if (!work)
+ return;
+
+ spin_lock_irqsave(&iwdev->rf->qptable_lock, flags);
+ if (!iwdev->rf->qp_table[iwqp->ibqp.qp_num]) {
+ spin_unlock_irqrestore(&iwdev->rf->qptable_lock, flags);
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: qp_id %d is already freed\n",
+ iwqp->ibqp.qp_num);
+ kfree(work);
+ return;
+ }
+ irdma_qp_add_ref(&iwqp->ibqp);
+ spin_unlock_irqrestore(&iwdev->rf->qptable_lock, flags);
+
+ work->iwqp = iwqp;
+ INIT_WORK(&work->work, irdma_disconnect_worker);
+ queue_work(iwdev->cleanup_wq, &work->work);
+}
+
+/**
+ * irdma_qp_disconnect - free qp and close cm
+ * @iwqp: associate qp for the connection
+ */
+static void irdma_qp_disconnect(struct irdma_qp *iwqp)
+{
+ struct irdma_device *iwdev = iwqp->iwdev;
+
+ iwqp->active_conn = 0;
+ /* close the CM node down if it is still active */
+ ibdev_dbg(&iwdev->ibdev, "CM: Call close API\n");
+ irdma_cm_close(iwqp->cm_node);
+}
+
+/**
+ * irdma_cm_disconn_true - called by worker thread to disconnect qp
+ * @iwqp: associate qp for the connection
+ */
+static void irdma_cm_disconn_true(struct irdma_qp *iwqp)
+{
+ struct iw_cm_id *cm_id;
+ struct irdma_device *iwdev;
+ struct irdma_sc_qp *qp = &iwqp->sc_qp;
+ 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;
+ unsigned long flags;
+ int err;
+
+ iwdev = iwqp->iwdev;
+ spin_lock_irqsave(&iwqp->lock, flags);
+ if (rdma_protocol_roce(&iwdev->ibdev, 1)) {
+ struct ib_qp_attr attr;
+
+ if (iwqp->flush_issued || iwqp->sc_qp.qp_uk.destroy_pending) {
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ return;
+ }
+
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+
+ attr.qp_state = IB_QPS_ERR;
+ irdma_modify_qp_roce(&iwqp->ibqp, &attr, IB_QP_STATE, NULL);
+ irdma_ib_qp_event(iwqp, qp->event_type);
+ return;
+ }
+
+ cm_id = iwqp->cm_id;
+ /* make sure we havent already closed this connection */
+ if (!cm_id) {
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ return;
+ }
+
+ original_hw_tcp_state = iwqp->hw_tcp_state;
+ original_ibqp_state = iwqp->ibqp_state;
+ last_ae = iwqp->last_aeq;
+
+ if (qp->term_flags) {
+ issue_disconn = 1;
+ issue_close = 1;
+ iwqp->cm_id = NULL;
+ irdma_terminate_del_timer(qp);
+ if (!iwqp->flush_issued) {
+ iwqp->flush_issued = 1;
+ issue_flush = 1;
+ }
+ } else if ((original_hw_tcp_state == IRDMA_TCP_STATE_CLOSE_WAIT) ||
+ ((original_ibqp_state == IB_QPS_RTS) &&
+ (last_ae == IRDMA_AE_LLP_CONNECTION_RESET))) {
+ issue_disconn = 1;
+ if (last_ae == IRDMA_AE_LLP_CONNECTION_RESET)
+ disconn_status = -ECONNRESET;
+ }
+
+ if ((original_hw_tcp_state == IRDMA_TCP_STATE_CLOSED ||
+ original_hw_tcp_state == IRDMA_TCP_STATE_TIME_WAIT ||
+ last_ae == IRDMA_AE_RDMAP_ROE_BAD_LLP_CLOSE ||
+ last_ae == IRDMA_AE_BAD_CLOSE ||
+ last_ae == IRDMA_AE_LLP_CONNECTION_RESET || iwdev->reset)) {
+ issue_close = 1;
+ iwqp->cm_id = NULL;
+ qp->term_flags = 0;
+ if (!iwqp->flush_issued) {
+ iwqp->flush_issued = 1;
+ issue_flush = 1;
+ }
+ }
+
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ if (issue_flush && !iwqp->sc_qp.qp_uk.destroy_pending) {
+ irdma_flush_wqes(iwqp, IRDMA_FLUSH_SQ | IRDMA_FLUSH_RQ |
+ IRDMA_FLUSH_WAIT);
+
+ if (qp->term_flags)
+ irdma_ib_qp_event(iwqp, qp->event_type);
+ }
+
+ if (!cm_id || !cm_id->event_handler)
+ return;
+
+ spin_lock_irqsave(&iwdev->cm_core.ht_lock, flags);
+ if (!iwqp->cm_node) {
+ spin_unlock_irqrestore(&iwdev->cm_core.ht_lock, flags);
+ return;
+ }
+ refcount_inc(&iwqp->cm_node->refcnt);
+
+ spin_unlock_irqrestore(&iwdev->cm_core.ht_lock, flags);
+
+ if (issue_disconn) {
+ err = irdma_send_cm_event(iwqp->cm_node, cm_id,
+ IW_CM_EVENT_DISCONNECT,
+ disconn_status);
+ if (err)
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: disconnect event failed: - cm_id = %p\n",
+ cm_id);
+ }
+ if (issue_close) {
+ cm_id->provider_data = iwqp;
+ err = irdma_send_cm_event(iwqp->cm_node, cm_id,
+ IW_CM_EVENT_CLOSE, 0);
+ if (err)
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: close event failed: - cm_id = %p\n",
+ cm_id);
+ irdma_qp_disconnect(iwqp);
+ }
+ irdma_rem_ref_cm_node(iwqp->cm_node);
+}
+
+/**
+ * irdma_disconnect_worker - worker for connection close
+ * @work: points or disconn structure
+ */
+static void irdma_disconnect_worker(struct work_struct *work)
+{
+ struct disconn_work *dwork = container_of(work, struct disconn_work, work);
+ struct irdma_qp *iwqp = dwork->iwqp;
+
+ kfree(dwork);
+ irdma_cm_disconn_true(iwqp);
+ irdma_qp_rem_ref(&iwqp->ibqp);
+}
+
+/**
+ * irdma_free_lsmm_rsrc - free lsmm memory and deregister
+ * @iwqp: associate qp for the connection
+ */
+void irdma_free_lsmm_rsrc(struct irdma_qp *iwqp)
+{
+ struct irdma_device *iwdev;
+
+ iwdev = iwqp->iwdev;
+
+ if (iwqp->ietf_mem.va) {
+ if (iwqp->lsmm_mr)
+ iwdev->ibdev.ops.dereg_mr(iwqp->lsmm_mr, NULL);
+ dma_free_coherent(iwdev->rf->sc_dev.hw->device,
+ iwqp->ietf_mem.size, iwqp->ietf_mem.va,
+ iwqp->ietf_mem.pa);
+ iwqp->ietf_mem.va = NULL;
+ iwqp->ietf_mem.va = NULL;
+ }
+}
+
+/**
+ * irdma_accept - registered call for connection to be accepted
+ * @cm_id: cm information for passive connection
+ * @conn_param: accpet parameters
+ */
+int irdma_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+{
+ struct ib_qp *ibqp;
+ struct irdma_qp *iwqp;
+ struct irdma_device *iwdev;
+ struct irdma_sc_dev *dev;
+ struct irdma_cm_node *cm_node;
+ struct ib_qp_attr attr = {};
+ int passive_state;
+ struct ib_mr *ibmr;
+ struct irdma_pd *iwpd;
+ u16 buf_len = 0;
+ struct irdma_kmem_info accept;
+ u64 tagged_offset;
+ int wait_ret;
+ int ret = 0;
+
+ ibqp = irdma_get_qp(cm_id->device, conn_param->qpn);
+ if (!ibqp)
+ return -EINVAL;
+
+ iwqp = to_iwqp(ibqp);
+ iwdev = iwqp->iwdev;
+ dev = &iwdev->rf->sc_dev;
+ cm_node = cm_id->provider_data;
+
+ if (((struct sockaddr_in *)&cm_id->local_addr)->sin_family == AF_INET) {
+ cm_node->ipv4 = true;
+ cm_node->vlan_id = irdma_get_vlan_ipv4(cm_node->loc_addr);
+ } else {
+ cm_node->ipv4 = false;
+ irdma_netdev_vlan_ipv6(cm_node->loc_addr, &cm_node->vlan_id,
+ NULL);
+ }
+ ibdev_dbg(&iwdev->ibdev, "CM: Accept vlan_id=%d\n",
+ cm_node->vlan_id);
+
+ trace_irdma_accept(cm_node, 0, NULL);
+
+ if (cm_node->state == IRDMA_CM_STATE_LISTENER_DESTROYED) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ passive_state = atomic_add_return(1, &cm_node->passive_state);
+ if (passive_state == IRDMA_SEND_RESET_EVENT) {
+ ret = -ECONNRESET;
+ goto error;
+ }
+
+ buf_len = conn_param->private_data_len + IRDMA_MAX_IETF_SIZE;
+ iwqp->ietf_mem.size = ALIGN(buf_len, 1);
+ iwqp->ietf_mem.va = dma_alloc_coherent(dev->hw->device,
+ iwqp->ietf_mem.size,
+ &iwqp->ietf_mem.pa, GFP_KERNEL);
+ if (!iwqp->ietf_mem.va) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ cm_node->pdata.size = conn_param->private_data_len;
+ accept.addr = iwqp->ietf_mem.va;
+ accept.size = irdma_cm_build_mpa_frame(cm_node, &accept, MPA_KEY_REPLY);
+ memcpy((u8 *)accept.addr + accept.size, conn_param->private_data,
+ conn_param->private_data_len);
+
+ if (cm_node->dev->ws_add(iwqp->sc_qp.vsi, cm_node->user_pri)) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ iwqp->sc_qp.user_pri = cm_node->user_pri;
+ irdma_qp_add_qos(&iwqp->sc_qp);
+ /* setup our first outgoing iWarp send WQE (the IETF frame response) */
+ iwpd = iwqp->iwpd;
+ tagged_offset = (uintptr_t)iwqp->ietf_mem.va;
+ ibmr = irdma_reg_phys_mr(&iwpd->ibpd, iwqp->ietf_mem.pa, buf_len,
+ IB_ACCESS_LOCAL_WRITE, &tagged_offset);
+ if (IS_ERR(ibmr)) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ibmr->pd = &iwpd->ibpd;
+ ibmr->device = iwpd->ibpd.device;
+ iwqp->lsmm_mr = ibmr;
+ if (iwqp->page)
+ iwqp->sc_qp.qp_uk.sq_base = kmap_local_page(iwqp->page);
+
+ cm_node->lsmm_size = accept.size + conn_param->private_data_len;
+ irdma_sc_send_lsmm(&iwqp->sc_qp, iwqp->ietf_mem.va, cm_node->lsmm_size,
+ ibmr->lkey);
+
+ if (iwqp->page)
+ kunmap_local(iwqp->sc_qp.qp_uk.sq_base);
+
+ iwqp->cm_id = cm_id;
+ cm_node->cm_id = cm_id;
+
+ cm_id->provider_data = iwqp;
+ iwqp->active_conn = 0;
+ iwqp->cm_node = cm_node;
+ cm_node->iwqp = iwqp;
+ irdma_cm_init_tsa_conn(iwqp, cm_node);
+ irdma_qp_add_ref(&iwqp->ibqp);
+ cm_id->add_ref(cm_id);
+
+ attr.qp_state = IB_QPS_RTS;
+ cm_node->qhash_set = false;
+ cm_node->cm_core->cm_free_ah(cm_node);
+
+ irdma_modify_qp(&iwqp->ibqp, &attr, IB_QP_STATE, NULL);
+ if (dev->hw_attrs.uk_attrs.feature_flags & IRDMA_FEATURE_RTS_AE) {
+ wait_ret = wait_event_interruptible_timeout(iwqp->waitq,
+ iwqp->rts_ae_rcvd,
+ IRDMA_MAX_TIMEOUT);
+ if (!wait_ret) {
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: Slow Connection: cm_node=%p, loc_port=%d, rem_port=%d, cm_id=%p\n",
+ cm_node, cm_node->loc_port,
+ cm_node->rem_port, cm_node->cm_id);
+ ret = -ECONNRESET;
+ goto error;
+ }
+ }
+
+ irdma_send_cm_event(cm_node, cm_id, IW_CM_EVENT_ESTABLISHED, 0);
+ cm_node->accelerated = true;
+ complete(&cm_node->establish_comp);
+
+ if (cm_node->accept_pend) {
+ atomic_dec(&cm_node->listener->pend_accepts_cnt);
+ cm_node->accept_pend = 0;
+ }
+
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: rem_port=0x%04x, loc_port=0x%04x rem_addr=%pI4 loc_addr=%pI4 cm_node=%p cm_id=%p qp_id = %d\n\n",
+ cm_node->rem_port, cm_node->loc_port, cm_node->rem_addr,
+ cm_node->loc_addr, cm_node, cm_id, ibqp->qp_num);
+ cm_node->cm_core->stats_accepts++;
+
+ return 0;
+error:
+ irdma_free_lsmm_rsrc(iwqp);
+ irdma_rem_ref_cm_node(cm_node);
+
+ return ret;
+}
+
+/**
+ * irdma_reject - registered call for connection to be rejected
+ * @cm_id: cm information for passive connection
+ * @pdata: private data to be sent
+ * @pdata_len: private data length
+ */
+int irdma_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
+{
+ struct irdma_device *iwdev;
+ struct irdma_cm_node *cm_node;
+
+ cm_node = cm_id->provider_data;
+ cm_node->pdata.size = pdata_len;
+
+ trace_irdma_reject(cm_node, 0, NULL);
+
+ iwdev = to_iwdev(cm_id->device);
+ if (!iwdev)
+ return -EINVAL;
+
+ cm_node->cm_core->stats_rejects++;
+
+ if (pdata_len + sizeof(struct ietf_mpa_v2) > IRDMA_MAX_CM_BUF)
+ return -EINVAL;
+
+ return irdma_cm_reject(cm_node, pdata, pdata_len);
+}
+
+/**
+ * irdma_connect - registered call for connection to be established
+ * @cm_id: cm information for passive connection
+ * @conn_param: Information about the connection
+ */
+int irdma_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+{
+ struct ib_qp *ibqp;
+ struct irdma_qp *iwqp;
+ struct irdma_device *iwdev;
+ struct irdma_cm_node *cm_node;
+ struct irdma_cm_info cm_info;
+ struct sockaddr_in *laddr;
+ struct sockaddr_in *raddr;
+ struct sockaddr_in6 *laddr6;
+ struct sockaddr_in6 *raddr6;
+ int ret = 0;
+
+ ibqp = irdma_get_qp(cm_id->device, conn_param->qpn);
+ if (!ibqp)
+ return -EINVAL;
+ iwqp = to_iwqp(ibqp);
+ if (!iwqp)
+ return -EINVAL;
+ iwdev = iwqp->iwdev;
+ if (!iwdev)
+ return -EINVAL;
+
+ laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
+ raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
+ laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
+ raddr6 = (struct sockaddr_in6 *)&cm_id->m_remote_addr;
+
+ if (!(laddr->sin_port) || !(raddr->sin_port))
+ return -EINVAL;
+
+ iwqp->active_conn = 1;
+ iwqp->cm_id = NULL;
+ cm_id->provider_data = iwqp;
+
+ /* set up the connection params for the node */
+ if (cm_id->remote_addr.ss_family == AF_INET) {
+ if (iwdev->vsi.mtu < IRDMA_MIN_MTU_IPV4)
+ return -EINVAL;
+
+ cm_info.ipv4 = true;
+ memset(cm_info.loc_addr, 0, sizeof(cm_info.loc_addr));
+ memset(cm_info.rem_addr, 0, sizeof(cm_info.rem_addr));
+ cm_info.loc_addr[0] = ntohl(laddr->sin_addr.s_addr);
+ cm_info.rem_addr[0] = ntohl(raddr->sin_addr.s_addr);
+ cm_info.loc_port = ntohs(laddr->sin_port);
+ cm_info.rem_port = ntohs(raddr->sin_port);
+ cm_info.vlan_id = irdma_get_vlan_ipv4(cm_info.loc_addr);
+ } else {
+ if (iwdev->vsi.mtu < IRDMA_MIN_MTU_IPV6)
+ return -EINVAL;
+
+ cm_info.ipv4 = false;
+ irdma_copy_ip_ntohl(cm_info.loc_addr,
+ laddr6->sin6_addr.in6_u.u6_addr32);
+ irdma_copy_ip_ntohl(cm_info.rem_addr,
+ raddr6->sin6_addr.in6_u.u6_addr32);
+ cm_info.loc_port = ntohs(laddr6->sin6_port);
+ cm_info.rem_port = ntohs(raddr6->sin6_port);
+ irdma_netdev_vlan_ipv6(cm_info.loc_addr, &cm_info.vlan_id,
+ NULL);
+ }
+ cm_info.cm_id = cm_id;
+ cm_info.qh_qpid = iwdev->vsi.ilq->qp_id;
+ cm_info.tos = cm_id->tos;
+ cm_info.user_pri = rt_tos2priority(cm_id->tos);
+
+ if (iwqp->sc_qp.dev->ws_add(iwqp->sc_qp.vsi, cm_info.user_pri))
+ return -ENOMEM;
+ iwqp->sc_qp.user_pri = cm_info.user_pri;
+ irdma_qp_add_qos(&iwqp->sc_qp);
+ ibdev_dbg(&iwdev->ibdev, "DCB: TOS:[%d] UP:[%d]\n", cm_id->tos,
+ cm_info.user_pri);
+
+ trace_irdma_dcb_tos(iwdev, cm_id->tos, cm_info.user_pri);
+
+ ret = irdma_create_cm_node(&iwdev->cm_core, iwdev, conn_param, &cm_info,
+ &cm_node);
+ if (ret)
+ return ret;
+ ret = cm_node->cm_core->cm_create_ah(cm_node, true);
+ if (ret)
+ goto err;
+ if (irdma_manage_qhash(iwdev, &cm_info,
+ IRDMA_QHASH_TYPE_TCP_ESTABLISHED,
+ IRDMA_QHASH_MANAGE_TYPE_ADD, NULL, true)) {
+ ret = -EINVAL;
+ goto err;
+ }
+ cm_node->qhash_set = true;
+
+ cm_node->apbvt_entry = irdma_add_apbvt(iwdev, cm_info.loc_port);
+ if (!cm_node->apbvt_entry) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ cm_node->apbvt_set = true;
+ iwqp->cm_node = cm_node;
+ cm_node->iwqp = iwqp;
+ iwqp->cm_id = cm_id;
+ irdma_qp_add_ref(&iwqp->ibqp);
+ cm_id->add_ref(cm_id);
+
+ if (cm_node->state != IRDMA_CM_STATE_OFFLOADED) {
+ cm_node->state = IRDMA_CM_STATE_SYN_SENT;
+ ret = irdma_send_syn(cm_node, 0);
+ if (ret)
+ goto err;
+ }
+
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: rem_port=0x%04x, loc_port=0x%04x rem_addr=%pI4 loc_addr=%pI4 cm_node=%p cm_id=%p qp_id = %d\n\n",
+ cm_node->rem_port, cm_node->loc_port, cm_node->rem_addr,
+ cm_node->loc_addr, cm_node, cm_id, ibqp->qp_num);
+
+ trace_irdma_connect(cm_node, 0, NULL);
+
+ return 0;
+
+err:
+ if (cm_info.ipv4)
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: connect() FAILED: dest addr=%pI4",
+ cm_info.rem_addr);
+ else
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: connect() FAILED: dest addr=%pI6",
+ cm_info.rem_addr);
+ irdma_rem_ref_cm_node(cm_node);
+ iwdev->cm_core.stats_connect_errs++;
+
+ return ret;
+}
+
+/**
+ * irdma_create_listen - registered call creating listener
+ * @cm_id: cm information for passive connection
+ * @backlog: to max accept pending count
+ */
+int irdma_create_listen(struct iw_cm_id *cm_id, int backlog)
+{
+ struct irdma_device *iwdev;
+ struct irdma_cm_listener *cm_listen_node;
+ struct irdma_cm_info cm_info = {};
+ enum irdma_status_code err;
+ struct sockaddr_in *laddr;
+ struct sockaddr_in6 *laddr6;
+ bool wildcard = false;
+
+ iwdev = to_iwdev(cm_id->device);
+ if (!iwdev)
+ return -EINVAL;
+
+ laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
+ laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
+ cm_info.qh_qpid = iwdev->vsi.ilq->qp_id;
+
+ if (laddr->sin_family == AF_INET) {
+ if (iwdev->vsi.mtu < IRDMA_MIN_MTU_IPV4)
+ return -EINVAL;
+
+ cm_info.ipv4 = true;
+ cm_info.loc_addr[0] = ntohl(laddr->sin_addr.s_addr);
+ cm_info.loc_port = ntohs(laddr->sin_port);
+
+ if (laddr->sin_addr.s_addr != htonl(INADDR_ANY)) {
+ cm_info.vlan_id = irdma_get_vlan_ipv4(cm_info.loc_addr);
+ } else {
+ cm_info.vlan_id = 0xFFFF;
+ wildcard = true;
+ }
+ } else {
+ if (iwdev->vsi.mtu < IRDMA_MIN_MTU_IPV6)
+ return -EINVAL;
+
+ cm_info.ipv4 = false;
+ irdma_copy_ip_ntohl(cm_info.loc_addr,
+ laddr6->sin6_addr.in6_u.u6_addr32);
+ cm_info.loc_port = ntohs(laddr6->sin6_port);
+ if (ipv6_addr_type(&laddr6->sin6_addr) != IPV6_ADDR_ANY) {
+ irdma_netdev_vlan_ipv6(cm_info.loc_addr,
+ &cm_info.vlan_id, NULL);
+ } else {
+ cm_info.vlan_id = 0xFFFF;
+ wildcard = true;
+ }
+ }
+
+ if (cm_info.vlan_id >= VLAN_N_VID && iwdev->dcb)
+ cm_info.vlan_id = 0;
+ cm_info.backlog = backlog;
+ cm_info.cm_id = cm_id;
+
+ trace_irdma_create_listen(iwdev, &cm_info);
+
+ cm_listen_node = irdma_make_listen_node(&iwdev->cm_core, iwdev,
+ &cm_info);
+ if (!cm_listen_node) {
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: cm_listen_node == NULL\n");
+ return -ENOMEM;
+ }
+
+ cm_id->provider_data = cm_listen_node;
+
+ cm_listen_node->tos = cm_id->tos;
+ cm_listen_node->user_pri = rt_tos2priority(cm_id->tos);
+ cm_info.user_pri = cm_listen_node->user_pri;
+ if (!cm_listen_node->reused_node) {
+ if (wildcard) {
+ err = irdma_add_mqh(iwdev, &cm_info, cm_listen_node);
+ if (err)
+ goto error;
+ } else {
+ err = irdma_manage_qhash(iwdev, &cm_info,
+ IRDMA_QHASH_TYPE_TCP_SYN,
+ IRDMA_QHASH_MANAGE_TYPE_ADD,
+ NULL, true);
+ if (err)
+ goto error;
+
+ cm_listen_node->qhash_set = true;
+ }
+
+ cm_listen_node->apbvt_entry = irdma_add_apbvt(iwdev,
+ cm_info.loc_port);
+ if (!cm_listen_node->apbvt_entry)
+ goto error;
+ }
+ cm_id->add_ref(cm_id);
+ cm_listen_node->cm_core->stats_listen_created++;
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: loc_port=0x%04x loc_addr=%pI4 cm_listen_node=%p cm_id=%p qhash_set=%d vlan_id=%d\n",
+ cm_listen_node->loc_port, cm_listen_node->loc_addr,
+ cm_listen_node, cm_listen_node->cm_id,
+ cm_listen_node->qhash_set, cm_listen_node->vlan_id);
+
+ return 0;
+
+error:
+
+ irdma_cm_del_listen(&iwdev->cm_core, cm_listen_node, false);
+
+ return -EINVAL;
+}
+
+/**
+ * irdma_destroy_listen - registered call to destroy listener
+ * @cm_id: cm information for passive connection
+ */
+int irdma_destroy_listen(struct iw_cm_id *cm_id)
+{
+ struct irdma_device *iwdev;
+
+ iwdev = to_iwdev(cm_id->device);
+ if (cm_id->provider_data)
+ irdma_cm_del_listen(&iwdev->cm_core, cm_id->provider_data,
+ true);
+ else
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: cm_id->provider_data was NULL\n");
+
+ cm_id->rem_ref(cm_id);
+
+ return 0;
+}
+
+/**
+ * irdma_teardown_list_prep - add conn nodes slated for tear down to list
+ * @cm_core: cm's core
+ * @teardown_list: a list to which cm_node will be selected
+ * @ipaddr: pointer to ip address
+ * @nfo: pointer to cm_info structure instance
+ * @disconnect_all: flag indicating disconnect all QPs
+ */
+static void irdma_teardown_list_prep(struct irdma_cm_core *cm_core,
+ struct list_head *teardown_list,
+ u32 *ipaddr,
+ struct irdma_cm_info *nfo,
+ bool disconnect_all)
+{
+ struct irdma_cm_node *cm_node;
+ int bkt;
+
+ hash_for_each_rcu(cm_core->cm_hash_tbl, bkt, cm_node, list) {
+ if ((disconnect_all ||
+ (nfo->vlan_id == cm_node->vlan_id &&
+ !memcmp(cm_node->loc_addr, ipaddr, nfo->ipv4 ? 4 : 16))) &&
+ refcount_inc_not_zero(&cm_node->refcnt))
+ list_add(&cm_node->teardown_entry, teardown_list);
+ }
+}
+
+/**
+ * irdma_cm_event_connected - handle connected active node
+ * @event: the info for cm_node of connection
+ */
+static void irdma_cm_event_connected(struct irdma_cm_event *event)
+{
+ struct irdma_qp *iwqp;
+ struct irdma_device *iwdev;
+ struct irdma_cm_node *cm_node;
+ struct irdma_sc_dev *dev;
+ struct ib_qp_attr attr = {};
+ struct iw_cm_id *cm_id;
+ int status;
+ bool read0;
+ int wait_ret = 0;
+
+ cm_node = event->cm_node;
+ cm_id = cm_node->cm_id;
+ iwqp = cm_id->provider_data;
+ iwdev = iwqp->iwdev;
+ dev = &iwdev->rf->sc_dev;
+ if (iwqp->sc_qp.qp_uk.destroy_pending) {
+ status = -ETIMEDOUT;
+ goto error;
+ }
+
+ irdma_cm_init_tsa_conn(iwqp, cm_node);
+ read0 = (cm_node->send_rdma0_op == SEND_RDMA_READ_ZERO);
+ if (iwqp->page)
+ iwqp->sc_qp.qp_uk.sq_base = kmap_local_page(iwqp->page);
+ irdma_sc_send_rtt(&iwqp->sc_qp, read0);
+ if (iwqp->page)
+ kunmap_local(iwqp->sc_qp.qp_uk.sq_base);
+
+ attr.qp_state = IB_QPS_RTS;
+ cm_node->qhash_set = false;
+ irdma_modify_qp(&iwqp->ibqp, &attr, IB_QP_STATE, NULL);
+ if (dev->hw_attrs.uk_attrs.feature_flags & IRDMA_FEATURE_RTS_AE) {
+ wait_ret = wait_event_interruptible_timeout(iwqp->waitq,
+ iwqp->rts_ae_rcvd,
+ IRDMA_MAX_TIMEOUT);
+ if (!wait_ret)
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: Slow Connection: cm_node=%p, loc_port=%d, rem_port=%d, cm_id=%p\n",
+ cm_node, cm_node->loc_port,
+ cm_node->rem_port, cm_node->cm_id);
+ }
+
+ irdma_send_cm_event(cm_node, cm_id, IW_CM_EVENT_CONNECT_REPLY, 0);
+ cm_node->accelerated = true;
+ complete(&cm_node->establish_comp);
+ cm_node->cm_core->cm_free_ah(cm_node);
+ return;
+
+error:
+ iwqp->cm_id = NULL;
+ cm_id->provider_data = NULL;
+ irdma_send_cm_event(event->cm_node, cm_id, IW_CM_EVENT_CONNECT_REPLY,
+ status);
+ irdma_rem_ref_cm_node(event->cm_node);
+}
+
+/**
+ * irdma_cm_event_reset - handle reset
+ * @event: the info for cm_node of connection
+ */
+static void irdma_cm_event_reset(struct irdma_cm_event *event)
+{
+ struct irdma_cm_node *cm_node = event->cm_node;
+ struct iw_cm_id *cm_id = cm_node->cm_id;
+ struct irdma_qp *iwqp;
+
+ if (!cm_id)
+ return;
+
+ iwqp = cm_id->provider_data;
+ if (!iwqp)
+ return;
+
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: reset event %p - cm_id = %p\n", event->cm_node, cm_id);
+ iwqp->cm_id = NULL;
+
+ irdma_send_cm_event(cm_node, cm_node->cm_id, IW_CM_EVENT_DISCONNECT,
+ -ECONNRESET);
+ irdma_send_cm_event(cm_node, cm_node->cm_id, IW_CM_EVENT_CLOSE, 0);
+}
+
+/**
+ * irdma_cm_event_handler - send event to cm upper layer
+ * @work: pointer of cm event info.
+ */
+static void irdma_cm_event_handler(struct work_struct *work)
+{
+ struct irdma_cm_event *event = container_of(work, struct irdma_cm_event, event_work);
+ struct irdma_cm_node *cm_node;
+
+ if (!event || !event->cm_node || !event->cm_node->cm_core)
+ return;
+
+ cm_node = event->cm_node;
+ trace_irdma_cm_event_handler(cm_node, event->type, NULL);
+
+ switch (event->type) {
+ case IRDMA_CM_EVENT_MPA_REQ:
+ irdma_send_cm_event(cm_node, cm_node->cm_id,
+ IW_CM_EVENT_CONNECT_REQUEST, 0);
+ break;
+ case IRDMA_CM_EVENT_RESET:
+ irdma_cm_event_reset(event);
+ break;
+ case IRDMA_CM_EVENT_CONNECTED:
+ if (!event->cm_node->cm_id ||
+ event->cm_node->state != IRDMA_CM_STATE_OFFLOADED)
+ break;
+ irdma_cm_event_connected(event);
+ break;
+ case IRDMA_CM_EVENT_MPA_REJECT:
+ if (!event->cm_node->cm_id ||
+ cm_node->state == IRDMA_CM_STATE_OFFLOADED)
+ break;
+ irdma_send_cm_event(cm_node, cm_node->cm_id,
+ IW_CM_EVENT_CONNECT_REPLY, -ECONNREFUSED);
+ break;
+ case IRDMA_CM_EVENT_ABORTED:
+ if (!event->cm_node->cm_id ||
+ event->cm_node->state == IRDMA_CM_STATE_OFFLOADED)
+ break;
+ irdma_event_connect_error(event);
+ break;
+ default:
+ ibdev_dbg(&cm_node->iwdev->ibdev,
+ "CM: bad event type = %d\n", event->type);
+ break;
+ }
+
+ irdma_rem_ref_cm_node(event->cm_node);
+ kfree(event);
+}
+
+/**
+ * irdma_cm_post_event - queue event request for worker thread
+ * @event: cm node's info for up event call
+ */
+static void irdma_cm_post_event(struct irdma_cm_event *event)
+{
+ refcount_inc(&event->cm_node->refcnt);
+ INIT_WORK(&event->event_work, irdma_cm_event_handler);
+ queue_work(event->cm_node->cm_core->event_wq, &event->event_work);
+}
+
+/**
+ * irdma_cm_teardown_connections - teardown QPs
+ * @iwdev: device pointer
+ * @ipaddr: Pointer to IPv4 or IPv6 address
+ * @nfo: Connection info
+ * @disconnect_all: flag indicating disconnect all QPs
+ *
+ * teardown QPs where source or destination addr matches ip addr
+ */
+void irdma_cm_teardown_connections(struct irdma_device *iwdev, u32 *ipaddr,
+ struct irdma_cm_info *nfo,
+ bool disconnect_all)
+{
+ struct irdma_cm_core *cm_core = &iwdev->cm_core;
+ struct list_head *list_core_temp;
+ struct list_head *list_node;
+ struct irdma_cm_node *cm_node;
+ struct list_head teardown_list;
+ struct ib_qp_attr attr;
+ struct irdma_sc_vsi *vsi = &iwdev->vsi;
+ struct irdma_sc_qp *sc_qp;
+ struct irdma_qp *qp;
+ int i;
+
+ INIT_LIST_HEAD(&teardown_list);
+
+ rcu_read_lock();
+ irdma_teardown_list_prep(cm_core, &teardown_list, ipaddr, nfo, disconnect_all);
+ rcu_read_unlock();
+
+ list_for_each_safe (list_node, list_core_temp, &teardown_list) {
+ cm_node = container_of(list_node, struct irdma_cm_node,
+ teardown_entry);
+ attr.qp_state = IB_QPS_ERR;
+ irdma_modify_qp(&cm_node->iwqp->ibqp, &attr, IB_QP_STATE, NULL);
+ if (iwdev->reset)
+ irdma_cm_disconn(cm_node->iwqp);
+ irdma_rem_ref_cm_node(cm_node);
+ }
+ if (!iwdev->roce_mode)
+ return;
+
+ INIT_LIST_HEAD(&teardown_list);
+ for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
+ mutex_lock(&vsi->qos[i].qos_mutex);
+ list_for_each_safe (list_node, list_core_temp,
+ &vsi->qos[i].qplist) {
+ u32 qp_ip[4];
+
+ sc_qp = container_of(list_node, struct irdma_sc_qp,
+ list);
+ if (sc_qp->qp_uk.qp_type != IRDMA_QP_TYPE_ROCE_RC)
+ continue;
+
+ qp = sc_qp->qp_uk.back_qp;
+ if (!disconnect_all) {
+ if (nfo->ipv4)
+ qp_ip[0] = qp->udp_info.local_ipaddr[3];
+ else
+ memcpy(qp_ip,
+ &qp->udp_info.local_ipaddr[0],
+ sizeof(qp_ip));
+ }
+
+ if (disconnect_all ||
+ (nfo->vlan_id == (qp->udp_info.vlan_tag & VLAN_VID_MASK) &&
+ !memcmp(qp_ip, ipaddr, nfo->ipv4 ? 4 : 16))) {
+ spin_lock(&iwdev->rf->qptable_lock);
+ if (iwdev->rf->qp_table[sc_qp->qp_uk.qp_id]) {
+ irdma_qp_add_ref(&qp->ibqp);
+ list_add(&qp->teardown_entry,
+ &teardown_list);
+ }
+ spin_unlock(&iwdev->rf->qptable_lock);
+ }
+ }
+ mutex_unlock(&vsi->qos[i].qos_mutex);
+ }
+
+ list_for_each_safe (list_node, list_core_temp, &teardown_list) {
+ qp = container_of(list_node, struct irdma_qp, teardown_entry);
+ attr.qp_state = IB_QPS_ERR;
+ irdma_modify_qp_roce(&qp->ibqp, &attr, IB_QP_STATE, NULL);
+ irdma_qp_rem_ref(&qp->ibqp);
+ }
+}
+
+/**
+ * irdma_qhash_ctrl - enable/disable qhash for list
+ * @iwdev: device pointer
+ * @parent_listen_node: parent listen node
+ * @nfo: cm info node
+ * @ipaddr: Pointer to IPv4 or IPv6 address
+ * @ipv4: flag indicating IPv4 when true
+ * @ifup: flag indicating interface up when true
+ *
+ * Enables or disables the qhash for the node in the child
+ * listen list that matches ipaddr. If no matching IP was found
+ * it will allocate and add a new child listen node to the
+ * parent listen node. The listen_list_lock is assumed to be
+ * held when called.
+ */
+static void irdma_qhash_ctrl(struct irdma_device *iwdev,
+ struct irdma_cm_listener *parent_listen_node,
+ struct irdma_cm_info *nfo, u32 *ipaddr, bool ipv4,
+ bool ifup)
+{
+ struct list_head *child_listen_list = &parent_listen_node->child_listen_list;
+ struct irdma_cm_listener *child_listen_node;
+ struct list_head *pos, *tpos;
+ enum irdma_status_code err;
+ bool node_allocated = false;
+ enum irdma_quad_hash_manage_type op = ifup ?
+ IRDMA_QHASH_MANAGE_TYPE_ADD :
+ IRDMA_QHASH_MANAGE_TYPE_DELETE;
+
+ list_for_each_safe (pos, tpos, child_listen_list) {
+ child_listen_node = list_entry(pos, struct irdma_cm_listener,
+ child_listen_list);
+ if (!memcmp(child_listen_node->loc_addr, ipaddr, ipv4 ? 4 : 16))
+ goto set_qhash;
+ }
+
+ /* if not found then add a child listener if interface is going up */
+ if (!ifup)
+ return;
+ 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->loc_addr, ipaddr, ipv4 ? 4 : 16);
+
+set_qhash:
+ memcpy(nfo->loc_addr, child_listen_node->loc_addr,
+ sizeof(nfo->loc_addr));
+ nfo->vlan_id = child_listen_node->vlan_id;
+ err = irdma_manage_qhash(iwdev, nfo, IRDMA_QHASH_TYPE_TCP_SYN, op, NULL,
+ false);
+ if (!err) {
+ child_listen_node->qhash_set = ifup;
+ if (node_allocated)
+ list_add(&child_listen_node->child_listen_list,
+ &parent_listen_node->child_listen_list);
+ } else if (node_allocated) {
+ kfree(child_listen_node);
+ }
+}
+
+/**
+ * irdma_if_notify - process an ifdown on an interface
+ * @iwdev: device pointer
+ * @netdev: network device structure
+ * @ipaddr: Pointer to IPv4 or IPv6 address
+ * @ipv4: flag indicating IPv4 when true
+ * @ifup: flag indicating interface up when true
+ */
+void irdma_if_notify(struct irdma_device *iwdev, struct net_device *netdev,
+ u32 *ipaddr, bool ipv4, bool ifup)
+{
+ struct irdma_cm_core *cm_core = &iwdev->cm_core;
+ unsigned long flags;
+ struct irdma_cm_listener *listen_node;
+ static const u32 ip_zero[4] = { 0, 0, 0, 0 };
+ struct irdma_cm_info nfo = {};
+ u16 vlan_id = rdma_vlan_dev_vlan_id(netdev);
+ enum irdma_quad_hash_manage_type op = ifup ?
+ IRDMA_QHASH_MANAGE_TYPE_ADD :
+ IRDMA_QHASH_MANAGE_TYPE_DELETE;
+
+ nfo.vlan_id = vlan_id;
+ nfo.ipv4 = ipv4;
+ nfo.qh_qpid = 1;
+
+ /* Disable or enable qhash for listeners */
+ spin_lock_irqsave(&cm_core->listen_list_lock, flags);
+ list_for_each_entry (listen_node, &cm_core->listen_list, list) {
+ if (vlan_id != listen_node->vlan_id ||
+ (memcmp(listen_node->loc_addr, ipaddr, ipv4 ? 4 : 16) &&
+ memcmp(listen_node->loc_addr, ip_zero, ipv4 ? 4 : 16)))
+ continue;
+
+ memcpy(nfo.loc_addr, listen_node->loc_addr,
+ sizeof(nfo.loc_addr));
+ nfo.loc_port = listen_node->loc_port;
+ nfo.user_pri = listen_node->user_pri;
+ if (!list_empty(&listen_node->child_listen_list)) {
+ irdma_qhash_ctrl(iwdev, listen_node, &nfo, ipaddr, ipv4,
+ ifup);
+ } else if (memcmp(listen_node->loc_addr, ip_zero,
+ ipv4 ? 4 : 16)) {
+ if (!irdma_manage_qhash(iwdev, &nfo,
+ IRDMA_QHASH_TYPE_TCP_SYN, op,
+ NULL, false))
+ listen_node->qhash_set = ifup;
+ }
+ }
+ spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+
+ /* disconnect any connected qp's on ifdown */
+ if (!ifup)
+ irdma_cm_teardown_connections(iwdev, ipaddr, &nfo, false);
+}
diff --git a/drivers/infiniband/hw/irdma/cm.h b/drivers/infiniband/hw/irdma/cm.h
new file mode 100644
index 000000000000..d03cd29333ea
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/cm.h
@@ -0,0 +1,417 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#ifndef IRDMA_CM_H
+#define IRDMA_CM_H
+
+#define IRDMA_MPA_REQUEST_ACCEPT 1
+#define IRDMA_MPA_REQUEST_REJECT 2
+
+/* IETF MPA -- defines */
+#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_VER 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
+#define SNDMARKER_SEQNMASK 0x000001ff
+#define IRDMA_MAX_IETF_SIZE 32
+
+/* 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 MAX_PORTS 65536
+
+#define IRDMA_PASSIVE_STATE_INDICATED 0
+#define IRDMA_DO_NOT_SEND_RESET_EVENT 1
+#define IRDMA_SEND_RESET_EVENT 2
+
+#define MAX_IRDMA_IFS 4
+
+#define SET_ACK 1
+#define SET_SYN 2
+#define SET_FIN 4
+#define SET_RST 8
+
+#define TCP_OPTIONS_PADDING 3
+
+#define IRDMA_DEFAULT_RETRYS 64
+#define IRDMA_DEFAULT_RETRANS 8
+#define IRDMA_DEFAULT_TTL 0x40
+#define IRDMA_DEFAULT_RTT_VAR 6
+#define IRDMA_DEFAULT_SS_THRESH 0x3fffffff
+#define IRDMA_DEFAULT_REXMIT_THRESH 8
+
+#define IRDMA_RETRY_TIMEOUT HZ
+#define IRDMA_SHORT_TIME 10
+#define IRDMA_LONG_TIME (2 * HZ)
+#define IRDMA_MAX_TIMEOUT ((unsigned long)(12 * HZ))
+
+#define IRDMA_CM_HASHTABLE_SIZE 1024
+#define IRDMA_CM_TCP_TIMER_INTERVAL 3000
+#define IRDMA_CM_DEFAULT_MTU 1540
+#define IRDMA_CM_DEFAULT_FRAME_CNT 10
+#define IRDMA_CM_THREAD_STACK_SIZE 256
+#define IRDMA_CM_DEFAULT_RCV_WND 64240
+#define IRDMA_CM_DEFAULT_RCV_WND_SCALED 0x3FFFC
+#define IRDMA_CM_DEFAULT_RCV_WND_SCALE 2
+#define IRDMA_CM_DEFAULT_FREE_PKTS 10
+#define IRDMA_CM_FREE_PKT_LO_WATERMARK 2
+#define IRDMA_CM_DEFAULT_MSS 536
+#define IRDMA_CM_DEFAULT_MPA_VER 2
+#define IRDMA_CM_DEFAULT_SEQ 0x159bf75f
+#define IRDMA_CM_DEFAULT_LOCAL_ID 0x3b47
+#define IRDMA_CM_DEFAULT_SEQ2 0x18ed5740
+#define IRDMA_CM_DEFAULT_LOCAL_ID2 0xb807
+#define IRDMA_MAX_CM_BUF (IRDMA_MAX_IETF_SIZE + IETF_MAX_PRIV_DATA_LEN)
+
+enum ietf_mpa_flags {
+ IETF_MPA_FLAGS_REJECT = 0x20,
+ IETF_MPA_FLAGS_CRC = 0x40,
+ IETF_MPA_FLAGS_MARKERS = 0x80,
+};
+
+enum irdma_timer_type {
+ IRDMA_TIMER_TYPE_SEND,
+ IRDMA_TIMER_TYPE_CLOSE,
+};
+
+enum option_nums {
+ OPTION_NUM_EOL,
+ OPTION_NUM_NONE,
+ OPTION_NUM_MSS,
+ OPTION_NUM_WINDOW_SCALE,
+ OPTION_NUM_SACK_PERM,
+ OPTION_NUM_SACK,
+ OPTION_NUM_WRITE0 = 0xbc,
+};
+
+/* cm node transition states */
+enum irdma_cm_node_state {
+ IRDMA_CM_STATE_UNKNOWN,
+ IRDMA_CM_STATE_INITED,
+ IRDMA_CM_STATE_LISTENING,
+ IRDMA_CM_STATE_SYN_RCVD,
+ IRDMA_CM_STATE_SYN_SENT,
+ IRDMA_CM_STATE_ONE_SIDE_ESTABLISHED,
+ IRDMA_CM_STATE_ESTABLISHED,
+ IRDMA_CM_STATE_ACCEPTING,
+ IRDMA_CM_STATE_MPAREQ_SENT,
+ IRDMA_CM_STATE_MPAREQ_RCVD,
+ IRDMA_CM_STATE_MPAREJ_RCVD,
+ IRDMA_CM_STATE_OFFLOADED,
+ IRDMA_CM_STATE_FIN_WAIT1,
+ IRDMA_CM_STATE_FIN_WAIT2,
+ IRDMA_CM_STATE_CLOSE_WAIT,
+ IRDMA_CM_STATE_TIME_WAIT,
+ IRDMA_CM_STATE_LAST_ACK,
+ IRDMA_CM_STATE_CLOSING,
+ IRDMA_CM_STATE_LISTENER_DESTROYED,
+ IRDMA_CM_STATE_CLOSED,
+};
+
+enum mpa_frame_ver {
+ 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 irdma_tcpip_pkt_type {
+ IRDMA_PKT_TYPE_UNKNOWN,
+ IRDMA_PKT_TYPE_SYN,
+ IRDMA_PKT_TYPE_SYNACK,
+ IRDMA_PKT_TYPE_ACK,
+ IRDMA_PKT_TYPE_FIN,
+ IRDMA_PKT_TYPE_RST,
+};
+
+enum irdma_cm_listener_state {
+ IRDMA_CM_LISTENER_PASSIVE_STATE = 1,
+ IRDMA_CM_LISTENER_ACTIVE_STATE = 2,
+ IRDMA_CM_LISTENER_EITHER_STATE = 3,
+};
+
+/* CM event codes */
+enum irdma_cm_event_type {
+ IRDMA_CM_EVENT_UNKNOWN,
+ IRDMA_CM_EVENT_ESTABLISHED,
+ IRDMA_CM_EVENT_MPA_REQ,
+ IRDMA_CM_EVENT_MPA_CONNECT,
+ IRDMA_CM_EVENT_MPA_ACCEPT,
+ IRDMA_CM_EVENT_MPA_REJECT,
+ IRDMA_CM_EVENT_MPA_ESTABLISHED,
+ IRDMA_CM_EVENT_CONNECTED,
+ IRDMA_CM_EVENT_RESET,
+ IRDMA_CM_EVENT_ABORTED,
+};
+
+struct irdma_bth { /* Base Trasnport Header */
+ u8 opcode;
+ u8 flags;
+ __be16 pkey;
+ __be32 qpn;
+ __be32 apsn;
+};
+
+struct ietf_mpa_v1 {
+ u8 key[IETF_MPA_KEY_SIZE];
+ u8 flags;
+ u8 rev;
+ __be16 priv_data_len;
+ u8 priv_data[];
+};
+
+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[];
+};
+
+struct option_base {
+ u8 optionnum;
+ u8 len;
+};
+
+struct option_mss {
+ u8 optionnum;
+ u8 len;
+ __be16 mss;
+};
+
+struct option_windowscale {
+ u8 optionnum;
+ u8 len;
+ u8 shiftcount;
+};
+
+union all_known_options {
+ char eol;
+ struct option_base base;
+ struct option_mss mss;
+ struct option_windowscale windowscale;
+};
+
+struct irdma_timer_entry {
+ struct list_head list;
+ unsigned long timetosend; /* jiffies */
+ struct irdma_puda_buf *sqbuf;
+ u32 type;
+ u32 retrycount;
+ u32 retranscount;
+ u32 context;
+ u32 send_retrans;
+ int close_when_complete;
+};
+
+/* CM context params */
+struct irdma_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 irdma_apbvt_entry {
+ struct hlist_node hlist;
+ u32 use_cnt;
+ u16 port;
+};
+
+struct irdma_cm_listener {
+ struct list_head list;
+ struct iw_cm_id *cm_id;
+ struct irdma_cm_core *cm_core;
+ struct irdma_device *iwdev;
+ struct list_head child_listen_list;
+ struct irdma_apbvt_entry *apbvt_entry;
+ enum irdma_cm_listener_state listener_state;
+ refcount_t refcnt;
+ atomic_t pend_accepts_cnt;
+ u32 loc_addr[4];
+ u32 reused_node;
+ int backlog;
+ u16 loc_port;
+ u16 vlan_id;
+ u8 loc_mac[ETH_ALEN];
+ u8 user_pri;
+ u8 tos;
+ bool qhash_set:1;
+ bool ipv4:1;
+};
+
+struct irdma_kmem_info {
+ void *addr;
+ u32 size;
+};
+
+struct irdma_mpa_priv_info {
+ const void *addr;
+ u32 size;
+};
+
+struct irdma_cm_node {
+ struct irdma_qp *iwqp;
+ struct irdma_device *iwdev;
+ struct irdma_sc_dev *dev;
+ struct irdma_cm_tcp_context tcp_cntxt;
+ struct irdma_cm_core *cm_core;
+ struct irdma_timer_entry *send_entry;
+ struct irdma_timer_entry *close_entry;
+ struct irdma_cm_listener *listener;
+ struct list_head timer_entry;
+ struct list_head reset_entry;
+ struct list_head teardown_entry;
+ struct irdma_apbvt_entry *apbvt_entry;
+ struct rcu_head rcu_head;
+ struct irdma_mpa_priv_info pdata;
+ struct irdma_sc_ah *ah;
+ union {
+ struct ietf_mpa_v1 mpa_frame;
+ struct ietf_mpa_v2 mpa_v2_frame;
+ };
+ struct irdma_kmem_info mpa_hdr;
+ struct iw_cm_id *cm_id;
+ struct hlist_node list;
+ struct completion establish_comp;
+ spinlock_t retrans_list_lock; /* protect CM node rexmit updates*/
+ atomic_t passive_state;
+ refcount_t refcnt;
+ enum irdma_cm_node_state state;
+ enum send_rdma0 send_rdma0_op;
+ enum mpa_frame_ver mpa_frame_rev;
+ u32 loc_addr[4], rem_addr[4];
+ u16 loc_port, rem_port;
+ int apbvt_set;
+ int accept_pend;
+ u16 vlan_id;
+ u16 ird_size;
+ u16 ord_size;
+ u16 mpav2_ird_ord;
+ u16 lsmm_size;
+ u8 pdata_buf[IETF_MAX_PRIV_DATA_LEN];
+ u8 loc_mac[ETH_ALEN];
+ u8 rem_mac[ETH_ALEN];
+ u8 user_pri;
+ u8 tos;
+ bool ack_rcvd:1;
+ bool qhash_set:1;
+ bool ipv4:1;
+ bool snd_mark_en:1;
+ bool rcv_mark_en:1;
+ bool do_lpb:1;
+ bool accelerated:1;
+};
+
+/* Used by internal CM APIs to pass CM information*/
+struct irdma_cm_info {
+ struct iw_cm_id *cm_id;
+ u16 loc_port;
+ u16 rem_port;
+ u32 loc_addr[4];
+ u32 rem_addr[4];
+ u32 qh_qpid;
+ u16 vlan_id;
+ int backlog;
+ u8 user_pri;
+ u8 tos;
+ bool ipv4;
+};
+
+struct irdma_cm_event {
+ enum irdma_cm_event_type type;
+ struct irdma_cm_info cm_info;
+ struct work_struct event_work;
+ struct irdma_cm_node *cm_node;
+};
+
+struct irdma_cm_core {
+ struct irdma_device *iwdev;
+ struct irdma_sc_dev *dev;
+ struct list_head listen_list;
+ DECLARE_HASHTABLE(cm_hash_tbl, 8);
+ DECLARE_HASHTABLE(apbvt_hash_tbl, 8);
+ struct timer_list tcp_timer;
+ struct workqueue_struct *event_wq;
+ spinlock_t ht_lock; /* protect CM node (active side) list */
+ spinlock_t listen_list_lock; /* protect listener list */
+ spinlock_t apbvt_lock; /*serialize apbvt add/del entries*/
+ u64 stats_nodes_created;
+ u64 stats_nodes_destroyed;
+ u64 stats_listen_created;
+ u64 stats_listen_destroyed;
+ u64 stats_listen_nodes_created;
+ u64 stats_listen_nodes_destroyed;
+ u64 stats_lpbs;
+ u64 stats_accepts;
+ u64 stats_rejects;
+ u64 stats_connect_errs;
+ u64 stats_passive_errs;
+ u64 stats_pkt_retrans;
+ u64 stats_backlog_drops;
+ struct irdma_puda_buf *(*form_cm_frame)(struct irdma_cm_node *cm_node,
+ struct irdma_kmem_info *options,
+ struct irdma_kmem_info *hdr,
+ struct irdma_mpa_priv_info *pdata,
+ u8 flags);
+ int (*cm_create_ah)(struct irdma_cm_node *cm_node, bool wait);
+ void (*cm_free_ah)(struct irdma_cm_node *cm_node);
+};
+
+int irdma_schedule_cm_timer(struct irdma_cm_node *cm_node,
+ struct irdma_puda_buf *sqbuf,
+ enum irdma_timer_type type, int send_retrans,
+ int close_when_complete);
+int irdma_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param);
+int irdma_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len);
+int irdma_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param);
+int irdma_create_listen(struct iw_cm_id *cm_id, int backlog);
+int irdma_destroy_listen(struct iw_cm_id *cm_id);
+int irdma_add_arp(struct irdma_pci_f *rf, u32 *ip, bool ipv4, u8 *mac);
+void irdma_cm_teardown_connections(struct irdma_device *iwdev, u32 *ipaddr,
+ struct irdma_cm_info *nfo,
+ bool disconnect_all);
+int irdma_cm_start(struct irdma_device *dev);
+int irdma_cm_stop(struct irdma_device *dev);
+bool irdma_ipv4_is_lpb(u32 loc_addr, u32 rem_addr);
+bool irdma_ipv6_is_lpb(u32 *loc_addr, u32 *rem_addr);
+int irdma_arp_table(struct irdma_pci_f *rf, u32 *ip_addr, bool ipv4,
+ u8 *mac_addr, u32 action);
+void irdma_if_notify(struct irdma_device *iwdev, struct net_device *netdev,
+ u32 *ipaddr, bool ipv4, bool ifup);
+bool irdma_port_in_use(struct irdma_cm_core *cm_core, u16 port);
+void irdma_send_ack(struct irdma_cm_node *cm_node);
+void irdma_lpb_nop(struct irdma_sc_qp *qp);
+void irdma_rem_ref_cm_node(struct irdma_cm_node *cm_node);
+void irdma_add_conn_est_qh(struct irdma_cm_node *cm_node);
+#endif /* IRDMA_CM_H */
diff --git a/drivers/infiniband/hw/irdma/ctrl.c b/drivers/infiniband/hw/irdma/ctrl.c
new file mode 100644
index 000000000000..b1023a7d0bd1
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/ctrl.c
@@ -0,0 +1,5657 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#include "osdep.h"
+#include "status.h"
+#include "hmc.h"
+#include "defs.h"
+#include "type.h"
+#include "ws.h"
+#include "protos.h"
+
+/**
+ * irdma_get_qp_from_list - get next qp from a list
+ * @head: Listhead of qp's
+ * @qp: current qp
+ */
+struct irdma_sc_qp *irdma_get_qp_from_list(struct list_head *head,
+ struct irdma_sc_qp *qp)
+{
+ struct list_head *lastentry;
+ struct list_head *entry = NULL;
+
+ if (list_empty(head))
+ return NULL;
+
+ if (!qp) {
+ entry = head->next;
+ } else {
+ lastentry = &qp->list;
+ entry = lastentry->next;
+ if (entry == head)
+ return NULL;
+ }
+
+ return container_of(entry, struct irdma_sc_qp, list);
+}
+
+/**
+ * irdma_sc_suspend_resume_qps - suspend/resume all qp's on VSI
+ * @vsi: the VSI struct pointer
+ * @op: Set to IRDMA_OP_RESUME or IRDMA_OP_SUSPEND
+ */
+void irdma_sc_suspend_resume_qps(struct irdma_sc_vsi *vsi, u8 op)
+{
+ struct irdma_sc_qp *qp = NULL;
+ u8 i;
+
+ for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
+ mutex_lock(&vsi->qos[i].qos_mutex);
+ qp = irdma_get_qp_from_list(&vsi->qos[i].qplist, qp);
+ while (qp) {
+ if (op == IRDMA_OP_RESUME) {
+ if (!qp->dev->ws_add(vsi, i)) {
+ qp->qs_handle =
+ vsi->qos[qp->user_pri].qs_handle;
+ irdma_cqp_qp_suspend_resume(qp, op);
+ } else {
+ irdma_cqp_qp_suspend_resume(qp, op);
+ irdma_modify_qp_to_err(qp);
+ }
+ } else if (op == IRDMA_OP_SUSPEND) {
+ /* issue cqp suspend command */
+ if (!irdma_cqp_qp_suspend_resume(qp, op))
+ atomic_inc(&vsi->qp_suspend_reqs);
+ }
+ qp = irdma_get_qp_from_list(&vsi->qos[i].qplist, qp);
+ }
+ mutex_unlock(&vsi->qos[i].qos_mutex);
+ }
+}
+
+/**
+ * irdma_change_l2params - given the new l2 parameters, change all qp
+ * @vsi: RDMA VSI pointer
+ * @l2params: New parameters from l2
+ */
+void irdma_change_l2params(struct irdma_sc_vsi *vsi,
+ struct irdma_l2params *l2params)
+{
+ if (l2params->mtu_changed) {
+ vsi->mtu = l2params->mtu;
+ if (vsi->ieq)
+ irdma_reinitialize_ieq(vsi);
+ }
+
+ if (!l2params->tc_changed)
+ return;
+
+ vsi->tc_change_pending = false;
+ irdma_sc_suspend_resume_qps(vsi, IRDMA_OP_RESUME);
+}
+
+/**
+ * irdma_qp_rem_qos - remove qp from qos lists during destroy qp
+ * @qp: qp to be removed from qos
+ */
+void irdma_qp_rem_qos(struct irdma_sc_qp *qp)
+{
+ struct irdma_sc_vsi *vsi = qp->vsi;
+
+ ibdev_dbg(to_ibdev(qp->dev),
+ "DCB: DCB: Remove qp[%d] UP[%d] qset[%d] on_qoslist[%d]\n",
+ qp->qp_uk.qp_id, qp->user_pri, qp->qs_handle,
+ qp->on_qoslist);
+ mutex_lock(&vsi->qos[qp->user_pri].qos_mutex);
+ if (qp->on_qoslist) {
+ qp->on_qoslist = false;
+ list_del(&qp->list);
+ }
+ mutex_unlock(&vsi->qos[qp->user_pri].qos_mutex);
+}
+
+/**
+ * irdma_qp_add_qos - called during setctx for qp to be added to qos
+ * @qp: qp to be added to qos
+ */
+void irdma_qp_add_qos(struct irdma_sc_qp *qp)
+{
+ struct irdma_sc_vsi *vsi = qp->vsi;
+
+ ibdev_dbg(to_ibdev(qp->dev),
+ "DCB: DCB: Add qp[%d] UP[%d] qset[%d] on_qoslist[%d]\n",
+ qp->qp_uk.qp_id, qp->user_pri, qp->qs_handle,
+ qp->on_qoslist);
+ mutex_lock(&vsi->qos[qp->user_pri].qos_mutex);
+ if (!qp->on_qoslist) {
+ list_add(&qp->list, &vsi->qos[qp->user_pri].qplist);
+ qp->on_qoslist = true;
+ qp->qs_handle = vsi->qos[qp->user_pri].qs_handle;
+ }
+ mutex_unlock(&vsi->qos[qp->user_pri].qos_mutex);
+}
+
+/**
+ * irdma_sc_pd_init - initialize sc pd struct
+ * @dev: sc device struct
+ * @pd: sc pd ptr
+ * @pd_id: pd_id for allocated pd
+ * @abi_ver: User/Kernel ABI version
+ */
+void irdma_sc_pd_init(struct irdma_sc_dev *dev, struct irdma_sc_pd *pd, u32 pd_id,
+ int abi_ver)
+{
+ pd->pd_id = pd_id;
+ pd->abi_ver = abi_ver;
+ pd->dev = dev;
+}
+
+/**
+ * irdma_sc_add_arp_cache_entry - cqp wqe add arp cache entry
+ * @cqp: struct for cqp hw
+ * @info: arp entry information
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code
+irdma_sc_add_arp_cache_entry(struct irdma_sc_cqp *cqp,
+ struct irdma_add_arp_cache_entry_info *info,
+ u64 scratch, bool post_sq)
+{
+ __le64 *wqe;
+ u64 hdr;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+ set_64bit_val(wqe, 8, info->reach_max);
+ set_64bit_val(wqe, 16, ether_addr_to_u64(info->mac_addr));
+
+ hdr = info->arp_index |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_MANAGE_ARP) |
+ FIELD_PREP(IRDMA_CQPSQ_MAT_PERMANENT, (info->permanent ? 1 : 0)) |
+ FIELD_PREP(IRDMA_CQPSQ_MAT_ENTRYVALID, 1) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: ARP_CACHE_ENTRY WQE", DUMP_PREFIX_OFFSET,
+ 16, 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_del_arp_cache_entry - dele arp cache entry
+ * @cqp: struct for cqp hw
+ * @scratch: u64 saved to be used during cqp completion
+ * @arp_index: arp index to delete arp entry
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code
+irdma_sc_del_arp_cache_entry(struct irdma_sc_cqp *cqp, u64 scratch,
+ u16 arp_index, bool post_sq)
+{
+ __le64 *wqe;
+ u64 hdr;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ hdr = arp_index |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_MANAGE_ARP) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: ARP_CACHE_DEL_ENTRY WQE",
+ DUMP_PREFIX_OFFSET, 16, 8, wqe,
+ IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_manage_apbvt_entry - for adding and deleting apbvt entries
+ * @cqp: struct for cqp hw
+ * @info: info for apbvt entry to add or delete
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code
+irdma_sc_manage_apbvt_entry(struct irdma_sc_cqp *cqp,
+ struct irdma_apbvt_info *info, u64 scratch,
+ bool post_sq)
+{
+ __le64 *wqe;
+ u64 hdr;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 16, info->port);
+
+ hdr = FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_MANAGE_APBVT) |
+ FIELD_PREP(IRDMA_CQPSQ_MAPT_ADDPORT, info->add) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: MANAGE_APBVT WQE", DUMP_PREFIX_OFFSET, 16,
+ 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_manage_qhash_table_entry - manage quad hash entries
+ * @cqp: struct for cqp hw
+ * @info: info for quad hash to manage
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ *
+ * This is called before connection establishment is started.
+ * For passive connections, when listener is created, it will
+ * call with entry type of IRDMA_QHASH_TYPE_TCP_SYN with local
+ * ip address and tcp port. When SYN is received (passive
+ * connections) or sent (active connections), this routine is
+ * called with entry type of IRDMA_QHASH_TYPE_TCP_ESTABLISHED
+ * and quad is passed in info.
+ *
+ * When iwarp connection is done and its state moves to RTS, the
+ * quad hash entry in the hardware will point to iwarp's qp
+ * number and requires no calls from the driver.
+ */
+static enum irdma_status_code
+irdma_sc_manage_qhash_table_entry(struct irdma_sc_cqp *cqp,
+ struct irdma_qhash_table_info *info,
+ u64 scratch, bool post_sq)
+{
+ __le64 *wqe;
+ u64 qw1 = 0;
+ u64 qw2 = 0;
+ u64 temp;
+ struct irdma_sc_vsi *vsi = info->vsi;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 0, ether_addr_to_u64(info->mac_addr));
+
+ qw1 = FIELD_PREP(IRDMA_CQPSQ_QHASH_QPN, info->qp_num) |
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_DEST_PORT, info->dest_port);
+ if (info->ipv4_valid) {
+ set_64bit_val(wqe, 48,
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_ADDR3, info->dest_ip[0]));
+ } else {
+ set_64bit_val(wqe, 56,
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_ADDR0, info->dest_ip[0]) |
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_ADDR1, info->dest_ip[1]));
+
+ set_64bit_val(wqe, 48,
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_ADDR2, info->dest_ip[2]) |
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_ADDR3, info->dest_ip[3]));
+ }
+ qw2 = FIELD_PREP(IRDMA_CQPSQ_QHASH_QS_HANDLE,
+ vsi->qos[info->user_pri].qs_handle);
+ if (info->vlan_valid)
+ qw2 |= FIELD_PREP(IRDMA_CQPSQ_QHASH_VLANID, info->vlan_id);
+ set_64bit_val(wqe, 16, qw2);
+ if (info->entry_type == IRDMA_QHASH_TYPE_TCP_ESTABLISHED) {
+ qw1 |= FIELD_PREP(IRDMA_CQPSQ_QHASH_SRC_PORT, info->src_port);
+ if (!info->ipv4_valid) {
+ set_64bit_val(wqe, 40,
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_ADDR0, info->src_ip[0]) |
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_ADDR1, info->src_ip[1]));
+ set_64bit_val(wqe, 32,
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_ADDR2, info->src_ip[2]) |
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_ADDR3, info->src_ip[3]));
+ } else {
+ set_64bit_val(wqe, 32,
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_ADDR3, info->src_ip[0]));
+ }
+ }
+
+ set_64bit_val(wqe, 8, qw1);
+ temp = FIELD_PREP(IRDMA_CQPSQ_QHASH_WQEVALID, cqp->polarity) |
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_OPCODE,
+ IRDMA_CQP_OP_MANAGE_QUAD_HASH_TABLE_ENTRY) |
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_MANAGE, info->manage) |
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_IPV4VALID, info->ipv4_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_VLANVALID, info->vlan_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_QHASH_ENTRYTYPE, info->entry_type);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, temp);
+
+ print_hex_dump_debug("WQE: MANAGE_QHASH WQE", DUMP_PREFIX_OFFSET, 16,
+ 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_qp_init - initialize qp
+ * @qp: sc qp
+ * @info: initialization qp info
+ */
+enum irdma_status_code irdma_sc_qp_init(struct irdma_sc_qp *qp,
+ struct irdma_qp_init_info *info)
+{
+ enum irdma_status_code ret_code;
+ u32 pble_obj_cnt;
+ u16 wqe_size;
+
+ if (info->qp_uk_init_info.max_sq_frag_cnt >
+ info->pd->dev->hw_attrs.uk_attrs.max_hw_wq_frags ||
+ info->qp_uk_init_info.max_rq_frag_cnt >
+ info->pd->dev->hw_attrs.uk_attrs.max_hw_wq_frags)
+ return IRDMA_ERR_INVALID_FRAG_COUNT;
+
+ qp->dev = info->pd->dev;
+ qp->vsi = info->vsi;
+ qp->ieq_qp = info->vsi->exception_lan_q;
+ qp->sq_pa = info->sq_pa;
+ qp->rq_pa = info->rq_pa;
+ qp->hw_host_ctx_pa = info->host_ctx_pa;
+ qp->q2_pa = info->q2_pa;
+ qp->shadow_area_pa = info->shadow_area_pa;
+ qp->q2_buf = info->q2;
+ qp->pd = info->pd;
+ qp->hw_host_ctx = info->host_ctx;
+ info->qp_uk_init_info.wqe_alloc_db = qp->pd->dev->wqe_alloc_db;
+ ret_code = irdma_uk_qp_init(&qp->qp_uk, &info->qp_uk_init_info);
+ if (ret_code)
+ return ret_code;
+
+ qp->virtual_map = info->virtual_map;
+ pble_obj_cnt = info->pd->dev->hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt;
+
+ if ((info->virtual_map && info->sq_pa >= pble_obj_cnt) ||
+ (info->virtual_map && info->rq_pa >= pble_obj_cnt))
+ return IRDMA_ERR_INVALID_PBLE_INDEX;
+
+ qp->llp_stream_handle = (void *)(-1);
+ qp->hw_sq_size = irdma_get_encoded_wqe_size(qp->qp_uk.sq_ring.size,
+ IRDMA_QUEUE_TYPE_SQ_RQ);
+ ibdev_dbg(to_ibdev(qp->dev),
+ "WQE: hw_sq_size[%04d] sq_ring.size[%04d]\n",
+ qp->hw_sq_size, qp->qp_uk.sq_ring.size);
+ if (qp->qp_uk.uk_attrs->hw_rev == IRDMA_GEN_1 && qp->pd->abi_ver > 4)
+ wqe_size = IRDMA_WQE_SIZE_128;
+ else
+ ret_code = irdma_fragcnt_to_wqesize_rq(qp->qp_uk.max_rq_frag_cnt,
+ &wqe_size);
+ if (ret_code)
+ return ret_code;
+
+ qp->hw_rq_size = irdma_get_encoded_wqe_size(qp->qp_uk.rq_size *
+ (wqe_size / IRDMA_QP_WQE_MIN_SIZE), IRDMA_QUEUE_TYPE_SQ_RQ);
+ ibdev_dbg(to_ibdev(qp->dev),
+ "WQE: hw_rq_size[%04d] qp_uk.rq_size[%04d] wqe_size[%04d]\n",
+ qp->hw_rq_size, qp->qp_uk.rq_size, wqe_size);
+ qp->sq_tph_val = info->sq_tph_val;
+ qp->rq_tph_val = info->rq_tph_val;
+ qp->sq_tph_en = info->sq_tph_en;
+ qp->rq_tph_en = info->rq_tph_en;
+ qp->rcv_tph_en = info->rcv_tph_en;
+ qp->xmit_tph_en = info->xmit_tph_en;
+ qp->qp_uk.first_sq_wq = info->qp_uk_init_info.first_sq_wq;
+ qp->qs_handle = qp->vsi->qos[qp->user_pri].qs_handle;
+
+ return 0;
+}
+
+/**
+ * irdma_sc_qp_create - create qp
+ * @qp: sc qp
+ * @info: qp create info
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+enum irdma_status_code irdma_sc_qp_create(struct irdma_sc_qp *qp, struct irdma_create_qp_info *info,
+ u64 scratch, bool post_sq)
+{
+ struct irdma_sc_cqp *cqp;
+ __le64 *wqe;
+ u64 hdr;
+
+ cqp = qp->dev->cqp;
+ if (qp->qp_uk.qp_id < cqp->dev->hw_attrs.min_hw_qp_id ||
+ qp->qp_uk.qp_id > (cqp->dev->hmc_info->hmc_obj[IRDMA_HMC_IW_QP].max_cnt - 1))
+ return IRDMA_ERR_INVALID_QP_ID;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 16, qp->hw_host_ctx_pa);
+ set_64bit_val(wqe, 40, qp->shadow_area_pa);
+
+ hdr = qp->qp_uk.qp_id |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_CREATE_QP) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_ORDVALID, (info->ord_valid ? 1 : 0)) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_TOECTXVALID, info->tcp_ctx_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_MACVALID, info->mac_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_QPTYPE, qp->qp_uk.qp_type) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_VQ, qp->virtual_map) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_FORCELOOPBACK, info->force_lpb) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_CQNUMVALID, info->cq_num_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_ARPTABIDXVALID,
+ info->arp_cache_idx_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_NEXTIWSTATE, info->next_iwarp_state) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: QP_CREATE WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_qp_modify - modify qp cqp wqe
+ * @qp: sc qp
+ * @info: modify qp info
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+enum irdma_status_code irdma_sc_qp_modify(struct irdma_sc_qp *qp,
+ struct irdma_modify_qp_info *info,
+ u64 scratch, bool post_sq)
+{
+ __le64 *wqe;
+ struct irdma_sc_cqp *cqp;
+ u64 hdr;
+ u8 term_actions = 0;
+ u8 term_len = 0;
+
+ cqp = qp->dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ if (info->next_iwarp_state == IRDMA_QP_STATE_TERMINATE) {
+ if (info->dont_send_fin)
+ term_actions += IRDMAQP_TERM_SEND_TERM_ONLY;
+ if (info->dont_send_term)
+ term_actions += IRDMAQP_TERM_SEND_FIN_ONLY;
+ if (term_actions == IRDMAQP_TERM_SEND_TERM_AND_FIN ||
+ term_actions == IRDMAQP_TERM_SEND_TERM_ONLY)
+ term_len = info->termlen;
+ }
+
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMA_CQPSQ_QP_NEWMSS, info->new_mss) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_TERMLEN, term_len));
+ set_64bit_val(wqe, 16, qp->hw_host_ctx_pa);
+ set_64bit_val(wqe, 40, qp->shadow_area_pa);
+
+ hdr = qp->qp_uk.qp_id |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_MODIFY_QP) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_ORDVALID, info->ord_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_TOECTXVALID, info->tcp_ctx_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_CACHEDVARVALID,
+ info->cached_var_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_VQ, qp->virtual_map) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_FORCELOOPBACK, info->force_lpb) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_CQNUMVALID, info->cq_num_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_MACVALID, info->mac_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_QPTYPE, qp->qp_uk.qp_type) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_MSSCHANGE, info->mss_change) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_REMOVEHASHENTRY,
+ info->remove_hash_idx) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_TERMACT, term_actions) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_RESETCON, info->reset_tcp_conn) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_ARPTABIDXVALID,
+ info->arp_cache_idx_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_NEXTIWSTATE, info->next_iwarp_state) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: QP_MODIFY WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_qp_destroy - cqp destroy qp
+ * @qp: sc qp
+ * @scratch: u64 saved to be used during cqp completion
+ * @remove_hash_idx: flag if to remove hash idx
+ * @ignore_mw_bnd: memory window bind flag
+ * @post_sq: flag for cqp db to ring
+ */
+enum irdma_status_code irdma_sc_qp_destroy(struct irdma_sc_qp *qp, u64 scratch,
+ bool remove_hash_idx, bool ignore_mw_bnd,
+ bool post_sq)
+{
+ __le64 *wqe;
+ struct irdma_sc_cqp *cqp;
+ u64 hdr;
+
+ cqp = qp->dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 16, qp->hw_host_ctx_pa);
+ set_64bit_val(wqe, 40, qp->shadow_area_pa);
+
+ hdr = qp->qp_uk.qp_id |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_DESTROY_QP) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_QPTYPE, qp->qp_uk.qp_type) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_IGNOREMWBOUND, ignore_mw_bnd) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_REMOVEHASHENTRY, remove_hash_idx) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: QP_DESTROY WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_get_encoded_ird_size -
+ * @ird_size: IRD size
+ * The ird from the connection is rounded to a supported HW setting and then encoded
+ * for ird_size field of qp_ctx. Consumers are expected to provide valid ird size based
+ * on hardware attributes. IRD size defaults to a value of 4 in case of invalid input
+ */
+static u8 irdma_sc_get_encoded_ird_size(u16 ird_size)
+{
+ switch (ird_size ?
+ roundup_pow_of_two(2 * ird_size) : 4) {
+ case 256:
+ return IRDMA_IRD_HW_SIZE_256;
+ case 128:
+ return IRDMA_IRD_HW_SIZE_128;
+ case 64:
+ case 32:
+ return IRDMA_IRD_HW_SIZE_64;
+ case 16:
+ case 8:
+ return IRDMA_IRD_HW_SIZE_16;
+ case 4:
+ default:
+ break;
+ }
+
+ return IRDMA_IRD_HW_SIZE_4;
+}
+
+/**
+ * irdma_sc_qp_setctx_roce - set qp's context
+ * @qp: sc qp
+ * @qp_ctx: context ptr
+ * @info: ctx info
+ */
+void irdma_sc_qp_setctx_roce(struct irdma_sc_qp *qp, __le64 *qp_ctx,
+ struct irdma_qp_host_ctx_info *info)
+{
+ struct irdma_roce_offload_info *roce_info;
+ struct irdma_udp_offload_info *udp;
+ u8 push_mode_en;
+ u32 push_idx;
+
+ roce_info = info->roce_info;
+ udp = info->udp_info;
+ qp->user_pri = info->user_pri;
+ if (qp->push_idx == IRDMA_INVALID_PUSH_PAGE_INDEX) {
+ push_mode_en = 0;
+ push_idx = 0;
+ } else {
+ push_mode_en = 1;
+ push_idx = qp->push_idx;
+ }
+ set_64bit_val(qp_ctx, 0,
+ FIELD_PREP(IRDMAQPC_RQWQESIZE, qp->qp_uk.rq_wqe_size) |
+ FIELD_PREP(IRDMAQPC_RCVTPHEN, qp->rcv_tph_en) |
+ FIELD_PREP(IRDMAQPC_XMITTPHEN, qp->xmit_tph_en) |
+ FIELD_PREP(IRDMAQPC_RQTPHEN, qp->rq_tph_en) |
+ FIELD_PREP(IRDMAQPC_SQTPHEN, qp->sq_tph_en) |
+ FIELD_PREP(IRDMAQPC_PPIDX, push_idx) |
+ FIELD_PREP(IRDMAQPC_PMENA, push_mode_en) |
+ FIELD_PREP(IRDMAQPC_PDIDXHI, roce_info->pd_id >> 16) |
+ FIELD_PREP(IRDMAQPC_DC_TCP_EN, roce_info->dctcp_en) |
+ FIELD_PREP(IRDMAQPC_ERR_RQ_IDX_VALID, roce_info->err_rq_idx_valid) |
+ FIELD_PREP(IRDMAQPC_ISQP1, roce_info->is_qp1) |
+ FIELD_PREP(IRDMAQPC_ROCE_TVER, roce_info->roce_tver) |
+ FIELD_PREP(IRDMAQPC_IPV4, udp->ipv4) |
+ FIELD_PREP(IRDMAQPC_INSERTVLANTAG, udp->insert_vlan_tag));
+ set_64bit_val(qp_ctx, 8, qp->sq_pa);
+ set_64bit_val(qp_ctx, 16, qp->rq_pa);
+ if ((roce_info->dcqcn_en || roce_info->dctcp_en) &&
+ !(udp->tos & 0x03))
+ udp->tos |= ECN_CODE_PT_VAL;
+ set_64bit_val(qp_ctx, 24,
+ FIELD_PREP(IRDMAQPC_RQSIZE, qp->hw_rq_size) |
+ FIELD_PREP(IRDMAQPC_SQSIZE, qp->hw_sq_size) |
+ FIELD_PREP(IRDMAQPC_TTL, udp->ttl) | FIELD_PREP(IRDMAQPC_TOS, udp->tos) |
+ FIELD_PREP(IRDMAQPC_SRCPORTNUM, udp->src_port) |
+ FIELD_PREP(IRDMAQPC_DESTPORTNUM, udp->dst_port));
+ set_64bit_val(qp_ctx, 32,
+ FIELD_PREP(IRDMAQPC_DESTIPADDR2, udp->dest_ip_addr[2]) |
+ FIELD_PREP(IRDMAQPC_DESTIPADDR3, udp->dest_ip_addr[3]));
+ set_64bit_val(qp_ctx, 40,
+ FIELD_PREP(IRDMAQPC_DESTIPADDR0, udp->dest_ip_addr[0]) |
+ FIELD_PREP(IRDMAQPC_DESTIPADDR1, udp->dest_ip_addr[1]));
+ set_64bit_val(qp_ctx, 48,
+ FIELD_PREP(IRDMAQPC_SNDMSS, udp->snd_mss) |
+ FIELD_PREP(IRDMAQPC_VLANTAG, udp->vlan_tag) |
+ FIELD_PREP(IRDMAQPC_ARPIDX, udp->arp_idx));
+ set_64bit_val(qp_ctx, 56,
+ FIELD_PREP(IRDMAQPC_PKEY, roce_info->p_key) |
+ FIELD_PREP(IRDMAQPC_PDIDX, roce_info->pd_id) |
+ FIELD_PREP(IRDMAQPC_ACKCREDITS, roce_info->ack_credits) |
+ FIELD_PREP(IRDMAQPC_FLOWLABEL, udp->flow_label));
+ set_64bit_val(qp_ctx, 64,
+ FIELD_PREP(IRDMAQPC_QKEY, roce_info->qkey) |
+ FIELD_PREP(IRDMAQPC_DESTQP, roce_info->dest_qp));
+ set_64bit_val(qp_ctx, 80,
+ FIELD_PREP(IRDMAQPC_PSNNXT, udp->psn_nxt) |
+ FIELD_PREP(IRDMAQPC_LSN, udp->lsn));
+ set_64bit_val(qp_ctx, 88,
+ FIELD_PREP(IRDMAQPC_EPSN, udp->epsn));
+ set_64bit_val(qp_ctx, 96,
+ FIELD_PREP(IRDMAQPC_PSNMAX, udp->psn_max) |
+ FIELD_PREP(IRDMAQPC_PSNUNA, udp->psn_una));
+ set_64bit_val(qp_ctx, 112,
+ FIELD_PREP(IRDMAQPC_CWNDROCE, udp->cwnd));
+ set_64bit_val(qp_ctx, 128,
+ FIELD_PREP(IRDMAQPC_ERR_RQ_IDX, roce_info->err_rq_idx) |
+ FIELD_PREP(IRDMAQPC_RNRNAK_THRESH, udp->rnr_nak_thresh) |
+ FIELD_PREP(IRDMAQPC_REXMIT_THRESH, udp->rexmit_thresh) |
+ FIELD_PREP(IRDMAQPC_RTOMIN, roce_info->rtomin));
+ set_64bit_val(qp_ctx, 136,
+ FIELD_PREP(IRDMAQPC_TXCQNUM, info->send_cq_num) |
+ FIELD_PREP(IRDMAQPC_RXCQNUM, info->rcv_cq_num));
+ set_64bit_val(qp_ctx, 144,
+ FIELD_PREP(IRDMAQPC_STAT_INDEX, info->stats_idx));
+ set_64bit_val(qp_ctx, 152, ether_addr_to_u64(roce_info->mac_addr) << 16);
+ set_64bit_val(qp_ctx, 160,
+ FIELD_PREP(IRDMAQPC_ORDSIZE, roce_info->ord_size) |
+ FIELD_PREP(IRDMAQPC_IRDSIZE, irdma_sc_get_encoded_ird_size(roce_info->ird_size)) |
+ FIELD_PREP(IRDMAQPC_WRRDRSPOK, roce_info->wr_rdresp_en) |
+ FIELD_PREP(IRDMAQPC_RDOK, roce_info->rd_en) |
+ FIELD_PREP(IRDMAQPC_USESTATSINSTANCE, info->stats_idx_valid) |
+ FIELD_PREP(IRDMAQPC_BINDEN, roce_info->bind_en) |
+ FIELD_PREP(IRDMAQPC_FASTREGEN, roce_info->fast_reg_en) |
+ FIELD_PREP(IRDMAQPC_DCQCNENABLE, roce_info->dcqcn_en) |
+ FIELD_PREP(IRDMAQPC_RCVNOICRC, roce_info->rcv_no_icrc) |
+ FIELD_PREP(IRDMAQPC_FW_CC_ENABLE, roce_info->fw_cc_enable) |
+ FIELD_PREP(IRDMAQPC_UDPRIVCQENABLE, roce_info->udprivcq_en) |
+ FIELD_PREP(IRDMAQPC_PRIVEN, roce_info->priv_mode_en) |
+ FIELD_PREP(IRDMAQPC_TIMELYENABLE, roce_info->timely_en));
+ set_64bit_val(qp_ctx, 168,
+ FIELD_PREP(IRDMAQPC_QPCOMPCTX, info->qp_compl_ctx));
+ set_64bit_val(qp_ctx, 176,
+ FIELD_PREP(IRDMAQPC_SQTPHVAL, qp->sq_tph_val) |
+ FIELD_PREP(IRDMAQPC_RQTPHVAL, qp->rq_tph_val) |
+ FIELD_PREP(IRDMAQPC_QSHANDLE, qp->qs_handle));
+ set_64bit_val(qp_ctx, 184,
+ FIELD_PREP(IRDMAQPC_LOCAL_IPADDR3, udp->local_ipaddr[3]) |
+ FIELD_PREP(IRDMAQPC_LOCAL_IPADDR2, udp->local_ipaddr[2]));
+ set_64bit_val(qp_ctx, 192,
+ FIELD_PREP(IRDMAQPC_LOCAL_IPADDR1, udp->local_ipaddr[1]) |
+ FIELD_PREP(IRDMAQPC_LOCAL_IPADDR0, udp->local_ipaddr[0]));
+ set_64bit_val(qp_ctx, 200,
+ FIELD_PREP(IRDMAQPC_THIGH, roce_info->t_high) |
+ FIELD_PREP(IRDMAQPC_TLOW, roce_info->t_low));
+ set_64bit_val(qp_ctx, 208,
+ FIELD_PREP(IRDMAQPC_REMENDPOINTIDX, info->rem_endpoint_idx));
+
+ print_hex_dump_debug("WQE: QP_HOST CTX WQE", DUMP_PREFIX_OFFSET, 16,
+ 8, qp_ctx, IRDMA_QP_CTX_SIZE, false);
+}
+
+/* irdma_sc_alloc_local_mac_entry - allocate a mac entry
+ * @cqp: struct for cqp hw
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code
+irdma_sc_alloc_local_mac_entry(struct irdma_sc_cqp *cqp, u64 scratch,
+ bool post_sq)
+{
+ __le64 *wqe;
+ u64 hdr;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ hdr = FIELD_PREP(IRDMA_CQPSQ_OPCODE,
+ IRDMA_CQP_OP_ALLOCATE_LOC_MAC_TABLE_ENTRY) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: ALLOCATE_LOCAL_MAC WQE",
+ DUMP_PREFIX_OFFSET, 16, 8, wqe,
+ IRDMA_CQP_WQE_SIZE * 8, false);
+
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+ return 0;
+}
+
+/**
+ * irdma_sc_add_local_mac_entry - add mac enry
+ * @cqp: struct for cqp hw
+ * @info:mac addr info
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code
+irdma_sc_add_local_mac_entry(struct irdma_sc_cqp *cqp,
+ struct irdma_local_mac_entry_info *info,
+ u64 scratch, bool post_sq)
+{
+ __le64 *wqe;
+ u64 header;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 32, ether_addr_to_u64(info->mac_addr));
+
+ header = FIELD_PREP(IRDMA_CQPSQ_MLM_TABLEIDX, info->entry_idx) |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE,
+ IRDMA_CQP_OP_MANAGE_LOC_MAC_TABLE) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, header);
+
+ print_hex_dump_debug("WQE: ADD_LOCAL_MAC WQE", DUMP_PREFIX_OFFSET, 16,
+ 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+ return 0;
+}
+
+/**
+ * irdma_sc_del_local_mac_entry - cqp wqe to dele local mac
+ * @cqp: struct for cqp hw
+ * @scratch: u64 saved to be used during cqp completion
+ * @entry_idx: index of mac entry
+ * @ignore_ref_count: to force mac adde delete
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code
+irdma_sc_del_local_mac_entry(struct irdma_sc_cqp *cqp, u64 scratch,
+ u16 entry_idx, u8 ignore_ref_count, bool post_sq)
+{
+ __le64 *wqe;
+ u64 header;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+ header = FIELD_PREP(IRDMA_CQPSQ_MLM_TABLEIDX, entry_idx) |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE,
+ IRDMA_CQP_OP_MANAGE_LOC_MAC_TABLE) |
+ FIELD_PREP(IRDMA_CQPSQ_MLM_FREEENTRY, 1) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity) |
+ FIELD_PREP(IRDMA_CQPSQ_MLM_IGNORE_REF_CNT, ignore_ref_count);
+
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, header);
+
+ print_hex_dump_debug("WQE: DEL_LOCAL_MAC_IPADDR WQE",
+ DUMP_PREFIX_OFFSET, 16, 8, wqe,
+ IRDMA_CQP_WQE_SIZE * 8, false);
+
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+ return 0;
+}
+
+/**
+ * irdma_sc_qp_setctx - set qp's context
+ * @qp: sc qp
+ * @qp_ctx: context ptr
+ * @info: ctx info
+ */
+void irdma_sc_qp_setctx(struct irdma_sc_qp *qp, __le64 *qp_ctx,
+ struct irdma_qp_host_ctx_info *info)
+{
+ struct irdma_iwarp_offload_info *iw;
+ struct irdma_tcp_offload_info *tcp;
+ struct irdma_sc_dev *dev;
+ u8 push_mode_en;
+ u32 push_idx;
+ u64 qw0, qw3, qw7 = 0, qw16 = 0;
+ u64 mac = 0;
+
+ iw = info->iwarp_info;
+ tcp = info->tcp_info;
+ dev = qp->dev;
+ if (iw->rcv_mark_en) {
+ qp->pfpdu.marker_len = 4;
+ qp->pfpdu.rcv_start_seq = tcp->rcv_nxt;
+ }
+ qp->user_pri = info->user_pri;
+ if (qp->push_idx == IRDMA_INVALID_PUSH_PAGE_INDEX) {
+ push_mode_en = 0;
+ push_idx = 0;
+ } else {
+ push_mode_en = 1;
+ push_idx = qp->push_idx;
+ }
+ qw0 = FIELD_PREP(IRDMAQPC_RQWQESIZE, qp->qp_uk.rq_wqe_size) |
+ FIELD_PREP(IRDMAQPC_RCVTPHEN, qp->rcv_tph_en) |
+ FIELD_PREP(IRDMAQPC_XMITTPHEN, qp->xmit_tph_en) |
+ FIELD_PREP(IRDMAQPC_RQTPHEN, qp->rq_tph_en) |
+ FIELD_PREP(IRDMAQPC_SQTPHEN, qp->sq_tph_en) |
+ FIELD_PREP(IRDMAQPC_PPIDX, push_idx) |
+ FIELD_PREP(IRDMAQPC_PMENA, push_mode_en);
+
+ set_64bit_val(qp_ctx, 8, qp->sq_pa);
+ set_64bit_val(qp_ctx, 16, qp->rq_pa);
+
+ qw3 = FIELD_PREP(IRDMAQPC_RQSIZE, qp->hw_rq_size) |
+ FIELD_PREP(IRDMAQPC_SQSIZE, qp->hw_sq_size);
+ if (dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1)
+ qw3 |= FIELD_PREP(IRDMAQPC_GEN1_SRCMACADDRIDX,
+ qp->src_mac_addr_idx);
+ set_64bit_val(qp_ctx, 136,
+ FIELD_PREP(IRDMAQPC_TXCQNUM, info->send_cq_num) |
+ FIELD_PREP(IRDMAQPC_RXCQNUM, info->rcv_cq_num));
+ set_64bit_val(qp_ctx, 168,
+ FIELD_PREP(IRDMAQPC_QPCOMPCTX, info->qp_compl_ctx));
+ set_64bit_val(qp_ctx, 176,
+ FIELD_PREP(IRDMAQPC_SQTPHVAL, qp->sq_tph_val) |
+ FIELD_PREP(IRDMAQPC_RQTPHVAL, qp->rq_tph_val) |
+ FIELD_PREP(IRDMAQPC_QSHANDLE, qp->qs_handle) |
+ FIELD_PREP(IRDMAQPC_EXCEPTION_LAN_QUEUE, qp->ieq_qp));
+ if (info->iwarp_info_valid) {
+ qw0 |= FIELD_PREP(IRDMAQPC_DDP_VER, iw->ddp_ver) |
+ FIELD_PREP(IRDMAQPC_RDMAP_VER, iw->rdmap_ver) |
+ FIELD_PREP(IRDMAQPC_DC_TCP_EN, iw->dctcp_en) |
+ FIELD_PREP(IRDMAQPC_ECN_EN, iw->ecn_en) |
+ FIELD_PREP(IRDMAQPC_IBRDENABLE, iw->ib_rd_en) |
+ FIELD_PREP(IRDMAQPC_PDIDXHI, iw->pd_id >> 16) |
+ FIELD_PREP(IRDMAQPC_ERR_RQ_IDX_VALID,
+ iw->err_rq_idx_valid);
+ qw7 |= FIELD_PREP(IRDMAQPC_PDIDX, iw->pd_id);
+ qw16 |= FIELD_PREP(IRDMAQPC_ERR_RQ_IDX, iw->err_rq_idx) |
+ FIELD_PREP(IRDMAQPC_RTOMIN, iw->rtomin);
+ set_64bit_val(qp_ctx, 144,
+ FIELD_PREP(IRDMAQPC_Q2ADDR, qp->q2_pa >> 8) |
+ FIELD_PREP(IRDMAQPC_STAT_INDEX, info->stats_idx));
+
+ if (dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2)
+ mac = ether_addr_to_u64(iw->mac_addr);
+
+ set_64bit_val(qp_ctx, 152,
+ mac << 16 | FIELD_PREP(IRDMAQPC_LASTBYTESENT, iw->last_byte_sent));
+ set_64bit_val(qp_ctx, 160,
+ FIELD_PREP(IRDMAQPC_ORDSIZE, iw->ord_size) |
+ FIELD_PREP(IRDMAQPC_IRDSIZE, irdma_sc_get_encoded_ird_size(iw->ird_size)) |
+ FIELD_PREP(IRDMAQPC_WRRDRSPOK, iw->wr_rdresp_en) |
+ FIELD_PREP(IRDMAQPC_RDOK, iw->rd_en) |
+ FIELD_PREP(IRDMAQPC_SNDMARKERS, iw->snd_mark_en) |
+ FIELD_PREP(IRDMAQPC_BINDEN, iw->bind_en) |
+ FIELD_PREP(IRDMAQPC_FASTREGEN, iw->fast_reg_en) |
+ FIELD_PREP(IRDMAQPC_PRIVEN, iw->priv_mode_en) |
+ FIELD_PREP(IRDMAQPC_USESTATSINSTANCE, info->stats_idx_valid) |
+ FIELD_PREP(IRDMAQPC_IWARPMODE, 1) |
+ FIELD_PREP(IRDMAQPC_RCVMARKERS, iw->rcv_mark_en) |
+ FIELD_PREP(IRDMAQPC_ALIGNHDRS, iw->align_hdrs) |
+ FIELD_PREP(IRDMAQPC_RCVNOMPACRC, iw->rcv_no_mpa_crc) |
+ FIELD_PREP(IRDMAQPC_RCVMARKOFFSET, iw->rcv_mark_offset || !tcp ? iw->rcv_mark_offset : tcp->rcv_nxt) |
+ FIELD_PREP(IRDMAQPC_SNDMARKOFFSET, iw->snd_mark_offset || !tcp ? iw->snd_mark_offset : tcp->snd_nxt) |
+ FIELD_PREP(IRDMAQPC_TIMELYENABLE, iw->timely_en));
+ }
+ if (info->tcp_info_valid) {
+ qw0 |= FIELD_PREP(IRDMAQPC_IPV4, tcp->ipv4) |
+ FIELD_PREP(IRDMAQPC_NONAGLE, tcp->no_nagle) |
+ FIELD_PREP(IRDMAQPC_INSERTVLANTAG,
+ tcp->insert_vlan_tag) |
+ FIELD_PREP(IRDMAQPC_TIMESTAMP, tcp->time_stamp) |
+ FIELD_PREP(IRDMAQPC_LIMIT, tcp->cwnd_inc_limit) |
+ FIELD_PREP(IRDMAQPC_DROPOOOSEG, tcp->drop_ooo_seg) |
+ FIELD_PREP(IRDMAQPC_DUPACK_THRESH, tcp->dup_ack_thresh);
+
+ if ((iw->ecn_en || iw->dctcp_en) && !(tcp->tos & 0x03))
+ tcp->tos |= ECN_CODE_PT_VAL;
+
+ qw3 |= FIELD_PREP(IRDMAQPC_TTL, tcp->ttl) |
+ FIELD_PREP(IRDMAQPC_AVOIDSTRETCHACK, tcp->avoid_stretch_ack) |
+ FIELD_PREP(IRDMAQPC_TOS, tcp->tos) |
+ FIELD_PREP(IRDMAQPC_SRCPORTNUM, tcp->src_port) |
+ FIELD_PREP(IRDMAQPC_DESTPORTNUM, tcp->dst_port);
+ if (dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1) {
+ qw3 |= FIELD_PREP(IRDMAQPC_GEN1_SRCMACADDRIDX, tcp->src_mac_addr_idx);
+
+ qp->src_mac_addr_idx = tcp->src_mac_addr_idx;
+ }
+ set_64bit_val(qp_ctx, 32,
+ FIELD_PREP(IRDMAQPC_DESTIPADDR2, tcp->dest_ip_addr[2]) |
+ FIELD_PREP(IRDMAQPC_DESTIPADDR3, tcp->dest_ip_addr[3]));
+ set_64bit_val(qp_ctx, 40,
+ FIELD_PREP(IRDMAQPC_DESTIPADDR0, tcp->dest_ip_addr[0]) |
+ FIELD_PREP(IRDMAQPC_DESTIPADDR1, tcp->dest_ip_addr[1]));
+ set_64bit_val(qp_ctx, 48,
+ FIELD_PREP(IRDMAQPC_SNDMSS, tcp->snd_mss) |
+ FIELD_PREP(IRDMAQPC_SYN_RST_HANDLING, tcp->syn_rst_handling) |
+ FIELD_PREP(IRDMAQPC_VLANTAG, tcp->vlan_tag) |
+ FIELD_PREP(IRDMAQPC_ARPIDX, tcp->arp_idx));
+ qw7 |= FIELD_PREP(IRDMAQPC_FLOWLABEL, tcp->flow_label) |
+ FIELD_PREP(IRDMAQPC_WSCALE, tcp->wscale) |
+ FIELD_PREP(IRDMAQPC_IGNORE_TCP_OPT,
+ tcp->ignore_tcp_opt) |
+ FIELD_PREP(IRDMAQPC_IGNORE_TCP_UNS_OPT,
+ tcp->ignore_tcp_uns_opt) |
+ FIELD_PREP(IRDMAQPC_TCPSTATE, tcp->tcp_state) |
+ FIELD_PREP(IRDMAQPC_RCVSCALE, tcp->rcv_wscale) |
+ FIELD_PREP(IRDMAQPC_SNDSCALE, tcp->snd_wscale);
+ set_64bit_val(qp_ctx, 72,
+ FIELD_PREP(IRDMAQPC_TIMESTAMP_RECENT, tcp->time_stamp_recent) |
+ FIELD_PREP(IRDMAQPC_TIMESTAMP_AGE, tcp->time_stamp_age));
+ set_64bit_val(qp_ctx, 80,
+ FIELD_PREP(IRDMAQPC_SNDNXT, tcp->snd_nxt) |
+ FIELD_PREP(IRDMAQPC_SNDWND, tcp->snd_wnd));
+ set_64bit_val(qp_ctx, 88,
+ FIELD_PREP(IRDMAQPC_RCVNXT, tcp->rcv_nxt) |
+ FIELD_PREP(IRDMAQPC_RCVWND, tcp->rcv_wnd));
+ set_64bit_val(qp_ctx, 96,
+ FIELD_PREP(IRDMAQPC_SNDMAX, tcp->snd_max) |
+ FIELD_PREP(IRDMAQPC_SNDUNA, tcp->snd_una));
+ set_64bit_val(qp_ctx, 104,
+ FIELD_PREP(IRDMAQPC_SRTT, tcp->srtt) |
+ FIELD_PREP(IRDMAQPC_RTTVAR, tcp->rtt_var));
+ set_64bit_val(qp_ctx, 112,
+ FIELD_PREP(IRDMAQPC_SSTHRESH, tcp->ss_thresh) |
+ FIELD_PREP(IRDMAQPC_CWND, tcp->cwnd));
+ set_64bit_val(qp_ctx, 120,
+ FIELD_PREP(IRDMAQPC_SNDWL1, tcp->snd_wl1) |
+ FIELD_PREP(IRDMAQPC_SNDWL2, tcp->snd_wl2));
+ qw16 |= FIELD_PREP(IRDMAQPC_MAXSNDWND, tcp->max_snd_window) |
+ FIELD_PREP(IRDMAQPC_REXMIT_THRESH, tcp->rexmit_thresh);
+ set_64bit_val(qp_ctx, 184,
+ FIELD_PREP(IRDMAQPC_LOCAL_IPADDR3, tcp->local_ipaddr[3]) |
+ FIELD_PREP(IRDMAQPC_LOCAL_IPADDR2, tcp->local_ipaddr[2]));
+ set_64bit_val(qp_ctx, 192,
+ FIELD_PREP(IRDMAQPC_LOCAL_IPADDR1, tcp->local_ipaddr[1]) |
+ FIELD_PREP(IRDMAQPC_LOCAL_IPADDR0, tcp->local_ipaddr[0]));
+ set_64bit_val(qp_ctx, 200,
+ FIELD_PREP(IRDMAQPC_THIGH, iw->t_high) |
+ FIELD_PREP(IRDMAQPC_TLOW, iw->t_low));
+ set_64bit_val(qp_ctx, 208,
+ FIELD_PREP(IRDMAQPC_REMENDPOINTIDX, info->rem_endpoint_idx));
+ }
+
+ set_64bit_val(qp_ctx, 0, qw0);
+ set_64bit_val(qp_ctx, 24, qw3);
+ set_64bit_val(qp_ctx, 56, qw7);
+ set_64bit_val(qp_ctx, 128, qw16);
+
+ print_hex_dump_debug("WQE: QP_HOST CTX", DUMP_PREFIX_OFFSET, 16, 8,
+ qp_ctx, IRDMA_QP_CTX_SIZE, false);
+}
+
+/**
+ * irdma_sc_alloc_stag - mr stag alloc
+ * @dev: sc device struct
+ * @info: stag info
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code
+irdma_sc_alloc_stag(struct irdma_sc_dev *dev,
+ struct irdma_allocate_stag_info *info, u64 scratch,
+ bool post_sq)
+{
+ __le64 *wqe;
+ struct irdma_sc_cqp *cqp;
+ u64 hdr;
+ enum irdma_page_size page_size;
+
+ if (info->page_size == 0x40000000)
+ page_size = IRDMA_PAGE_SIZE_1G;
+ else if (info->page_size == 0x200000)
+ page_size = IRDMA_PAGE_SIZE_2M;
+ else
+ page_size = IRDMA_PAGE_SIZE_4K;
+
+ cqp = dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 8,
+ FLD_LS_64(dev, info->pd_id, IRDMA_CQPSQ_STAG_PDID) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_STAGLEN, info->total_len));
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMA_CQPSQ_STAG_IDX, info->stag_idx));
+ set_64bit_val(wqe, 40,
+ FIELD_PREP(IRDMA_CQPSQ_STAG_HMCFNIDX, info->hmc_fcn_index));
+
+ if (info->chunk_size)
+ set_64bit_val(wqe, 48,
+ FIELD_PREP(IRDMA_CQPSQ_STAG_FIRSTPMPBLIDX, info->first_pm_pbl_idx));
+
+ hdr = FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_ALLOC_STAG) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_MR, 1) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_ARIGHTS, info->access_rights) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_LPBLSIZE, info->chunk_size) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_HPAGESIZE, page_size) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_REMACCENABLED, info->remote_access) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_USEHMCFNIDX, info->use_hmc_fcn_index) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_USEPFRID, info->use_pf_rid) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: ALLOC_STAG WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_mr_reg_non_shared - non-shared mr registration
+ * @dev: sc device struct
+ * @info: mr info
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code
+irdma_sc_mr_reg_non_shared(struct irdma_sc_dev *dev,
+ struct irdma_reg_ns_stag_info *info, u64 scratch,
+ bool post_sq)
+{
+ __le64 *wqe;
+ u64 fbo;
+ struct irdma_sc_cqp *cqp;
+ u64 hdr;
+ u32 pble_obj_cnt;
+ bool remote_access;
+ u8 addr_type;
+ enum irdma_page_size page_size;
+
+ if (info->page_size == 0x40000000)
+ page_size = IRDMA_PAGE_SIZE_1G;
+ else if (info->page_size == 0x200000)
+ page_size = IRDMA_PAGE_SIZE_2M;
+ else if (info->page_size == 0x1000)
+ page_size = IRDMA_PAGE_SIZE_4K;
+ else
+ return IRDMA_ERR_PARAM;
+
+ if (info->access_rights & (IRDMA_ACCESS_FLAGS_REMOTEREAD_ONLY |
+ IRDMA_ACCESS_FLAGS_REMOTEWRITE_ONLY))
+ remote_access = true;
+ else
+ remote_access = false;
+
+ pble_obj_cnt = dev->hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt;
+ if (info->chunk_size && info->first_pm_pbl_index >= pble_obj_cnt)
+ return IRDMA_ERR_INVALID_PBLE_INDEX;
+
+ cqp = dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+ fbo = info->va & (info->page_size - 1);
+
+ set_64bit_val(wqe, 0,
+ (info->addr_type == IRDMA_ADDR_TYPE_VA_BASED ?
+ info->va : fbo));
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMA_CQPSQ_STAG_STAGLEN, info->total_len) |
+ FLD_LS_64(dev, info->pd_id, IRDMA_CQPSQ_STAG_PDID));
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMA_CQPSQ_STAG_KEY, info->stag_key) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_IDX, info->stag_idx));
+ if (!info->chunk_size) {
+ set_64bit_val(wqe, 32, info->reg_addr_pa);
+ set_64bit_val(wqe, 48, 0);
+ } else {
+ set_64bit_val(wqe, 32, 0);
+ set_64bit_val(wqe, 48,
+ FIELD_PREP(IRDMA_CQPSQ_STAG_FIRSTPMPBLIDX, info->first_pm_pbl_index));
+ }
+ set_64bit_val(wqe, 40, info->hmc_fcn_index);
+ set_64bit_val(wqe, 56, 0);
+
+ addr_type = (info->addr_type == IRDMA_ADDR_TYPE_VA_BASED) ? 1 : 0;
+ hdr = FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_REG_MR) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_MR, 1) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_LPBLSIZE, info->chunk_size) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_HPAGESIZE, page_size) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_ARIGHTS, info->access_rights) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_REMACCENABLED, remote_access) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_VABASEDTO, addr_type) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_USEHMCFNIDX, info->use_hmc_fcn_index) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_USEPFRID, info->use_pf_rid) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: MR_REG_NS WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_dealloc_stag - deallocate stag
+ * @dev: sc device struct
+ * @info: dealloc stag info
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code
+irdma_sc_dealloc_stag(struct irdma_sc_dev *dev,
+ struct irdma_dealloc_stag_info *info, u64 scratch,
+ bool post_sq)
+{
+ u64 hdr;
+ __le64 *wqe;
+ struct irdma_sc_cqp *cqp;
+
+ cqp = dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 8,
+ FLD_LS_64(dev, info->pd_id, IRDMA_CQPSQ_STAG_PDID));
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMA_CQPSQ_STAG_IDX, info->stag_idx));
+
+ hdr = FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_DEALLOC_STAG) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_MR, info->mr) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: DEALLOC_STAG WQE", DUMP_PREFIX_OFFSET, 16,
+ 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_mw_alloc - mw allocate
+ * @dev: sc device struct
+ * @info: memory window allocation information
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code
+irdma_sc_mw_alloc(struct irdma_sc_dev *dev, struct irdma_mw_alloc_info *info,
+ u64 scratch, bool post_sq)
+{
+ u64 hdr;
+ struct irdma_sc_cqp *cqp;
+ __le64 *wqe;
+
+ cqp = dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 8,
+ FLD_LS_64(dev, info->pd_id, IRDMA_CQPSQ_STAG_PDID));
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMA_CQPSQ_STAG_IDX, info->mw_stag_index));
+
+ hdr = FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_ALLOC_STAG) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_MWTYPE, info->mw_wide) |
+ FIELD_PREP(IRDMA_CQPSQ_STAG_MW1_BIND_DONT_VLDT_KEY,
+ info->mw1_bind_dont_vldt_key) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: MW_ALLOC WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_mr_fast_register - Posts RDMA fast register mr WR to iwarp qp
+ * @qp: sc qp struct
+ * @info: fast mr info
+ * @post_sq: flag for cqp db to ring
+ */
+enum irdma_status_code
+irdma_sc_mr_fast_register(struct irdma_sc_qp *qp,
+ struct irdma_fast_reg_stag_info *info, bool post_sq)
+{
+ u64 temp, hdr;
+ __le64 *wqe;
+ u32 wqe_idx;
+ enum irdma_page_size page_size;
+ struct irdma_post_sq_info sq_info = {};
+
+ if (info->page_size == 0x40000000)
+ page_size = IRDMA_PAGE_SIZE_1G;
+ else if (info->page_size == 0x200000)
+ page_size = IRDMA_PAGE_SIZE_2M;
+ else
+ page_size = IRDMA_PAGE_SIZE_4K;
+
+ sq_info.wr_id = info->wr_id;
+ sq_info.signaled = info->signaled;
+ sq_info.push_wqe = info->push_wqe;
+
+ wqe = irdma_qp_get_next_send_wqe(&qp->qp_uk, &wqe_idx,
+ IRDMA_QP_WQE_MIN_QUANTA, 0, &sq_info);
+ if (!wqe)
+ return IRDMA_ERR_QP_TOOMANY_WRS_POSTED;
+
+ irdma_clr_wqes(&qp->qp_uk, wqe_idx);
+
+ ibdev_dbg(to_ibdev(qp->dev),
+ "MR: wr_id[%llxh] wqe_idx[%04d] location[%p]\n",
+ info->wr_id, wqe_idx,
+ &qp->qp_uk.sq_wrtrk_array[wqe_idx].wrid);
+
+ temp = (info->addr_type == IRDMA_ADDR_TYPE_VA_BASED) ?
+ (uintptr_t)info->va : info->fbo;
+ set_64bit_val(wqe, 0, temp);
+
+ temp = FIELD_GET(IRDMAQPSQ_FIRSTPMPBLIDXHI,
+ info->first_pm_pbl_index >> 16);
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMAQPSQ_FIRSTPMPBLIDXHI, temp) |
+ FIELD_PREP(IRDMAQPSQ_PBLADDR >> IRDMA_HW_PAGE_SHIFT, info->reg_addr_pa));
+ set_64bit_val(wqe, 16,
+ info->total_len |
+ FIELD_PREP(IRDMAQPSQ_FIRSTPMPBLIDXLO, info->first_pm_pbl_index));
+
+ hdr = FIELD_PREP(IRDMAQPSQ_STAGKEY, info->stag_key) |
+ FIELD_PREP(IRDMAQPSQ_STAGINDEX, info->stag_idx) |
+ FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMAQP_OP_FAST_REGISTER) |
+ FIELD_PREP(IRDMAQPSQ_LPBLSIZE, info->chunk_size) |
+ FIELD_PREP(IRDMAQPSQ_HPAGESIZE, page_size) |
+ FIELD_PREP(IRDMAQPSQ_STAGRIGHTS, info->access_rights) |
+ FIELD_PREP(IRDMAQPSQ_VABASEDTO, info->addr_type) |
+ FIELD_PREP(IRDMAQPSQ_PUSHWQE, (sq_info.push_wqe ? 1 : 0)) |
+ FIELD_PREP(IRDMAQPSQ_READFENCE, info->read_fence) |
+ FIELD_PREP(IRDMAQPSQ_LOCALFENCE, info->local_fence) |
+ FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->qp_uk.swqe_polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: FAST_REG WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_QP_WQE_MIN_SIZE, false);
+ if (sq_info.push_wqe) {
+ irdma_qp_push_wqe(&qp->qp_uk, wqe, IRDMA_QP_WQE_MIN_QUANTA,
+ wqe_idx, post_sq);
+ } else {
+ if (post_sq)
+ irdma_uk_qp_post_wr(&qp->qp_uk);
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_sc_gen_rts_ae - request AE generated after RTS
+ * @qp: sc qp struct
+ */
+static void irdma_sc_gen_rts_ae(struct irdma_sc_qp *qp)
+{
+ __le64 *wqe;
+ u64 hdr;
+ struct irdma_qp_uk *qp_uk;
+
+ qp_uk = &qp->qp_uk;
+
+ wqe = qp_uk->sq_base[1].elem;
+
+ hdr = FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMAQP_OP_NOP) |
+ FIELD_PREP(IRDMAQPSQ_LOCALFENCE, 1) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->qp_uk.swqe_polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+ print_hex_dump_debug("QP: NOP W/LOCAL FENCE WQE", DUMP_PREFIX_OFFSET,
+ 16, 8, wqe, IRDMA_QP_WQE_MIN_SIZE, false);
+
+ wqe = qp_uk->sq_base[2].elem;
+ hdr = FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMAQP_OP_GEN_RTS_AE) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->qp_uk.swqe_polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+ print_hex_dump_debug("QP: CONN EST WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_QP_WQE_MIN_SIZE, false);
+}
+
+/**
+ * irdma_sc_send_lsmm - send last streaming mode message
+ * @qp: sc qp struct
+ * @lsmm_buf: buffer with lsmm message
+ * @size: size of lsmm buffer
+ * @stag: stag of lsmm buffer
+ */
+void irdma_sc_send_lsmm(struct irdma_sc_qp *qp, void *lsmm_buf, u32 size,
+ irdma_stag stag)
+{
+ __le64 *wqe;
+ u64 hdr;
+ struct irdma_qp_uk *qp_uk;
+
+ qp_uk = &qp->qp_uk;
+ wqe = qp_uk->sq_base->elem;
+
+ set_64bit_val(wqe, 0, (uintptr_t)lsmm_buf);
+ if (qp->qp_uk.uk_attrs->hw_rev == IRDMA_GEN_1) {
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMAQPSQ_GEN1_FRAG_LEN, size) |
+ FIELD_PREP(IRDMAQPSQ_GEN1_FRAG_STAG, stag));
+ } else {
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMAQPSQ_FRAG_LEN, size) |
+ FIELD_PREP(IRDMAQPSQ_FRAG_STAG, stag) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->qp_uk.swqe_polarity));
+ }
+ set_64bit_val(wqe, 16, 0);
+
+ hdr = FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMAQP_OP_RDMA_SEND) |
+ FIELD_PREP(IRDMAQPSQ_STREAMMODE, 1) |
+ FIELD_PREP(IRDMAQPSQ_WAITFORRCVPDU, 1) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->qp_uk.swqe_polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: SEND_LSMM WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_QP_WQE_MIN_SIZE, false);
+
+ if (qp->dev->hw_attrs.uk_attrs.feature_flags & IRDMA_FEATURE_RTS_AE)
+ irdma_sc_gen_rts_ae(qp);
+}
+
+/**
+ * irdma_sc_send_lsmm_nostag - for privilege qp
+ * @qp: sc qp struct
+ * @lsmm_buf: buffer with lsmm message
+ * @size: size of lsmm buffer
+ */
+void irdma_sc_send_lsmm_nostag(struct irdma_sc_qp *qp, void *lsmm_buf, u32 size)
+{
+ __le64 *wqe;
+ u64 hdr;
+ struct irdma_qp_uk *qp_uk;
+
+ qp_uk = &qp->qp_uk;
+ wqe = qp_uk->sq_base->elem;
+
+ set_64bit_val(wqe, 0, (uintptr_t)lsmm_buf);
+
+ if (qp->qp_uk.uk_attrs->hw_rev == IRDMA_GEN_1)
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMAQPSQ_GEN1_FRAG_LEN, size));
+ else
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMAQPSQ_FRAG_LEN, size) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->qp_uk.swqe_polarity));
+ set_64bit_val(wqe, 16, 0);
+
+ hdr = FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMAQP_OP_RDMA_SEND) |
+ FIELD_PREP(IRDMAQPSQ_STREAMMODE, 1) |
+ FIELD_PREP(IRDMAQPSQ_WAITFORRCVPDU, 1) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->qp_uk.swqe_polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: SEND_LSMM_NOSTAG WQE", DUMP_PREFIX_OFFSET,
+ 16, 8, wqe, IRDMA_QP_WQE_MIN_SIZE, false);
+}
+
+/**
+ * irdma_sc_send_rtt - send last read0 or write0
+ * @qp: sc qp struct
+ * @read: Do read0 or write0
+ */
+void irdma_sc_send_rtt(struct irdma_sc_qp *qp, bool read)
+{
+ __le64 *wqe;
+ u64 hdr;
+ struct irdma_qp_uk *qp_uk;
+
+ qp_uk = &qp->qp_uk;
+ wqe = qp_uk->sq_base->elem;
+
+ set_64bit_val(wqe, 0, 0);
+ set_64bit_val(wqe, 16, 0);
+ if (read) {
+ if (qp->qp_uk.uk_attrs->hw_rev == IRDMA_GEN_1) {
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMAQPSQ_GEN1_FRAG_STAG, 0xabcd));
+ } else {
+ set_64bit_val(wqe, 8,
+ (u64)0xabcd | FIELD_PREP(IRDMAQPSQ_VALID, qp->qp_uk.swqe_polarity));
+ }
+ hdr = FIELD_PREP(IRDMAQPSQ_REMSTAG, 0x1234) |
+ FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMAQP_OP_RDMA_READ) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->qp_uk.swqe_polarity);
+
+ } else {
+ if (qp->qp_uk.uk_attrs->hw_rev == IRDMA_GEN_1) {
+ set_64bit_val(wqe, 8, 0);
+ } else {
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->qp_uk.swqe_polarity));
+ }
+ hdr = FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMAQP_OP_RDMA_WRITE) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->qp_uk.swqe_polarity);
+ }
+
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: RTR WQE", DUMP_PREFIX_OFFSET, 16, 8, wqe,
+ IRDMA_QP_WQE_MIN_SIZE, false);
+
+ if (qp->dev->hw_attrs.uk_attrs.feature_flags & IRDMA_FEATURE_RTS_AE)
+ irdma_sc_gen_rts_ae(qp);
+}
+
+/**
+ * irdma_iwarp_opcode - determine if incoming is rdma layer
+ * @info: aeq info for the packet
+ * @pkt: packet for error
+ */
+static u32 irdma_iwarp_opcode(struct irdma_aeqe_info *info, u8 *pkt)
+{
+ __be16 *mpa;
+ u32 opcode = 0xffffffff;
+
+ if (info->q2_data_written) {
+ mpa = (__be16 *)pkt;
+ opcode = ntohs(mpa[1]) & 0xf;
+ }
+
+ return opcode;
+}
+
+/**
+ * irdma_locate_mpa - return pointer to mpa in the pkt
+ * @pkt: packet with data
+ */
+static u8 *irdma_locate_mpa(u8 *pkt)
+{
+ /* skip over ethernet header */
+ pkt += IRDMA_MAC_HLEN;
+
+ /* Skip over IP and TCP headers */
+ pkt += 4 * (pkt[0] & 0x0f);
+ pkt += 4 * ((pkt[12] >> 4) & 0x0f);
+
+ return pkt;
+}
+
+/**
+ * irdma_bld_termhdr_ctrl - setup terminate hdr control fields
+ * @qp: sc qp ptr for pkt
+ * @hdr: term hdr
+ * @opcode: flush opcode for termhdr
+ * @layer_etype: error layer + error type
+ * @err: error cod ein the header
+ */
+static void irdma_bld_termhdr_ctrl(struct irdma_sc_qp *qp,
+ struct irdma_terminate_hdr *hdr,
+ enum irdma_flush_opcode opcode,
+ u8 layer_etype, u8 err)
+{
+ qp->flush_code = opcode;
+ hdr->layer_etype = layer_etype;
+ hdr->error_code = err;
+}
+
+/**
+ * irdma_bld_termhdr_ddp_rdma - setup ddp and rdma hdrs in terminate hdr
+ * @pkt: ptr to mpa in offending pkt
+ * @hdr: term hdr
+ * @copy_len: offending pkt length to be copied to term hdr
+ * @is_tagged: DDP tagged or untagged
+ */
+static void irdma_bld_termhdr_ddp_rdma(u8 *pkt, struct irdma_terminate_hdr *hdr,
+ int *copy_len, u8 *is_tagged)
+{
+ u16 ddp_seg_len;
+
+ ddp_seg_len = ntohs(*(__be16 *)pkt);
+ if (ddp_seg_len) {
+ *copy_len = 2;
+ hdr->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;
+ hdr->hdrct |= DDP_HDR_FLAG;
+ }
+ } else {
+ if (ddp_seg_len >= TERM_DDP_LEN_UNTAGGED) {
+ *copy_len += TERM_DDP_LEN_UNTAGGED;
+ hdr->hdrct |= DDP_HDR_FLAG;
+ }
+ if (ddp_seg_len >= (TERM_DDP_LEN_UNTAGGED + TERM_RDMA_LEN) &&
+ ((pkt[3] & RDMA_OPCODE_M) == RDMA_READ_REQ_OPCODE)) {
+ *copy_len += TERM_RDMA_LEN;
+ hdr->hdrct |= RDMA_HDR_FLAG;
+ }
+ }
+ }
+}
+
+/**
+ * irdma_bld_terminate_hdr - build terminate message header
+ * @qp: qp associated with received terminate AE
+ * @info: the struct contiaing AE information
+ */
+static int irdma_bld_terminate_hdr(struct irdma_sc_qp *qp,
+ struct irdma_aeqe_info *info)
+{
+ u8 *pkt = qp->q2_buf + Q2_BAD_FRAME_OFFSET;
+ int copy_len = 0;
+ u8 is_tagged = 0;
+ u32 opcode;
+ struct irdma_terminate_hdr *termhdr;
+
+ termhdr = (struct irdma_terminate_hdr *)qp->q2_buf;
+ memset(termhdr, 0, Q2_BAD_FRAME_OFFSET);
+
+ if (info->q2_data_written) {
+ pkt = irdma_locate_mpa(pkt);
+ irdma_bld_termhdr_ddp_rdma(pkt, termhdr, &copy_len, &is_tagged);
+ }
+
+ opcode = irdma_iwarp_opcode(info, pkt);
+ qp->event_type = IRDMA_QP_EVENT_CATASTROPHIC;
+ qp->sq_flush_code = info->sq;
+ qp->rq_flush_code = info->rq;
+
+ switch (info->ae_id) {
+ case IRDMA_AE_AMP_UNALLOCATED_STAG:
+ qp->event_type = IRDMA_QP_EVENT_ACCESS_ERR;
+ if (opcode == IRDMA_OP_TYPE_RDMA_WRITE)
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_PROT_ERR,
+ (LAYER_DDP << 4) | DDP_TAGGED_BUF,
+ DDP_TAGGED_INV_STAG);
+ else
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_REM_ACCESS_ERR,
+ (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT,
+ RDMAP_INV_STAG);
+ break;
+ case IRDMA_AE_AMP_BOUNDS_VIOLATION:
+ qp->event_type = IRDMA_QP_EVENT_ACCESS_ERR;
+ if (info->q2_data_written)
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_PROT_ERR,
+ (LAYER_DDP << 4) | DDP_TAGGED_BUF,
+ DDP_TAGGED_BOUNDS);
+ else
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_REM_ACCESS_ERR,
+ (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT,
+ RDMAP_INV_BOUNDS);
+ break;
+ case IRDMA_AE_AMP_BAD_PD:
+ switch (opcode) {
+ case IRDMA_OP_TYPE_RDMA_WRITE:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_PROT_ERR,
+ (LAYER_DDP << 4) | DDP_TAGGED_BUF,
+ DDP_TAGGED_UNASSOC_STAG);
+ break;
+ case IRDMA_OP_TYPE_SEND_INV:
+ case IRDMA_OP_TYPE_SEND_SOL_INV:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_REM_ACCESS_ERR,
+ (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT,
+ RDMAP_CANT_INV_STAG);
+ break;
+ default:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_REM_ACCESS_ERR,
+ (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT,
+ RDMAP_UNASSOC_STAG);
+ }
+ break;
+ case IRDMA_AE_AMP_INVALID_STAG:
+ qp->event_type = IRDMA_QP_EVENT_ACCESS_ERR;
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_REM_ACCESS_ERR,
+ (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT,
+ RDMAP_INV_STAG);
+ break;
+ case IRDMA_AE_AMP_BAD_QP:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_LOC_QP_OP_ERR,
+ (LAYER_DDP << 4) | DDP_UNTAGGED_BUF,
+ DDP_UNTAGGED_INV_QN);
+ break;
+ case IRDMA_AE_AMP_BAD_STAG_KEY:
+ case IRDMA_AE_AMP_BAD_STAG_INDEX:
+ qp->event_type = IRDMA_QP_EVENT_ACCESS_ERR;
+ switch (opcode) {
+ case IRDMA_OP_TYPE_SEND_INV:
+ case IRDMA_OP_TYPE_SEND_SOL_INV:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_REM_OP_ERR,
+ (LAYER_RDMA << 4) | RDMAP_REMOTE_OP,
+ RDMAP_CANT_INV_STAG);
+ break;
+ default:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_REM_ACCESS_ERR,
+ (LAYER_RDMA << 4) | RDMAP_REMOTE_OP,
+ RDMAP_INV_STAG);
+ }
+ break;
+ case IRDMA_AE_AMP_RIGHTS_VIOLATION:
+ case IRDMA_AE_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS:
+ case IRDMA_AE_PRIV_OPERATION_DENIED:
+ qp->event_type = IRDMA_QP_EVENT_ACCESS_ERR;
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_REM_ACCESS_ERR,
+ (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT,
+ RDMAP_ACCESS);
+ break;
+ case IRDMA_AE_AMP_TO_WRAP:
+ qp->event_type = IRDMA_QP_EVENT_ACCESS_ERR;
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_REM_ACCESS_ERR,
+ (LAYER_RDMA << 4) | RDMAP_REMOTE_PROT,
+ RDMAP_TO_WRAP);
+ break;
+ case IRDMA_AE_LLP_RECEIVED_MPA_CRC_ERROR:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_GENERAL_ERR,
+ (LAYER_MPA << 4) | DDP_LLP, MPA_CRC);
+ break;
+ case IRDMA_AE_LLP_SEGMENT_TOO_SMALL:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_LOC_LEN_ERR,
+ (LAYER_DDP << 4) | DDP_CATASTROPHIC,
+ DDP_CATASTROPHIC_LOCAL);
+ break;
+ case IRDMA_AE_LCE_QP_CATASTROPHIC:
+ case IRDMA_AE_DDP_NO_L_BIT:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_FATAL_ERR,
+ (LAYER_DDP << 4) | DDP_CATASTROPHIC,
+ DDP_CATASTROPHIC_LOCAL);
+ break;
+ case IRDMA_AE_DDP_INVALID_MSN_GAP_IN_MSN:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_GENERAL_ERR,
+ (LAYER_DDP << 4) | DDP_UNTAGGED_BUF,
+ DDP_UNTAGGED_INV_MSN_RANGE);
+ break;
+ case IRDMA_AE_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER:
+ qp->event_type = IRDMA_QP_EVENT_ACCESS_ERR;
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_LOC_LEN_ERR,
+ (LAYER_DDP << 4) | DDP_UNTAGGED_BUF,
+ DDP_UNTAGGED_INV_TOO_LONG);
+ break;
+ case IRDMA_AE_DDP_UBE_INVALID_DDP_VERSION:
+ if (is_tagged)
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_GENERAL_ERR,
+ (LAYER_DDP << 4) | DDP_TAGGED_BUF,
+ DDP_TAGGED_INV_DDP_VER);
+ else
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_GENERAL_ERR,
+ (LAYER_DDP << 4) | DDP_UNTAGGED_BUF,
+ DDP_UNTAGGED_INV_DDP_VER);
+ break;
+ case IRDMA_AE_DDP_UBE_INVALID_MO:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_GENERAL_ERR,
+ (LAYER_DDP << 4) | DDP_UNTAGGED_BUF,
+ DDP_UNTAGGED_INV_MO);
+ break;
+ case IRDMA_AE_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_REM_OP_ERR,
+ (LAYER_DDP << 4) | DDP_UNTAGGED_BUF,
+ DDP_UNTAGGED_INV_MSN_NO_BUF);
+ break;
+ case IRDMA_AE_DDP_UBE_INVALID_QN:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_GENERAL_ERR,
+ (LAYER_DDP << 4) | DDP_UNTAGGED_BUF,
+ DDP_UNTAGGED_INV_QN);
+ break;
+ case IRDMA_AE_RDMAP_ROE_INVALID_RDMAP_VERSION:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_GENERAL_ERR,
+ (LAYER_RDMA << 4) | RDMAP_REMOTE_OP,
+ RDMAP_INV_RDMAP_VER);
+ break;
+ default:
+ irdma_bld_termhdr_ctrl(qp, termhdr, FLUSH_FATAL_ERR,
+ (LAYER_RDMA << 4) | RDMAP_REMOTE_OP,
+ RDMAP_UNSPECIFIED);
+ break;
+ }
+
+ if (copy_len)
+ memcpy(termhdr + 1, pkt, copy_len);
+
+ return sizeof(struct irdma_terminate_hdr) + copy_len;
+}
+
+/**
+ * irdma_terminate_send_fin() - Send fin for terminate message
+ * @qp: qp associated with received terminate AE
+ */
+void irdma_terminate_send_fin(struct irdma_sc_qp *qp)
+{
+ irdma_term_modify_qp(qp, IRDMA_QP_STATE_TERMINATE,
+ IRDMAQP_TERM_SEND_FIN_ONLY, 0);
+}
+
+/**
+ * irdma_terminate_connection() - Bad AE and send terminate to remote QP
+ * @qp: qp associated with received terminate AE
+ * @info: the struct contiaing AE information
+ */
+void irdma_terminate_connection(struct irdma_sc_qp *qp,
+ struct irdma_aeqe_info *info)
+{
+ u8 termlen = 0;
+
+ if (qp->term_flags & IRDMA_TERM_SENT)
+ return;
+
+ termlen = irdma_bld_terminate_hdr(qp, info);
+ irdma_terminate_start_timer(qp);
+ qp->term_flags |= IRDMA_TERM_SENT;
+ irdma_term_modify_qp(qp, IRDMA_QP_STATE_TERMINATE,
+ IRDMAQP_TERM_SEND_TERM_ONLY, termlen);
+}
+
+/**
+ * irdma_terminate_received - handle terminate received AE
+ * @qp: qp associated with received terminate AE
+ * @info: the struct contiaing AE information
+ */
+void irdma_terminate_received(struct irdma_sc_qp *qp,
+ struct irdma_aeqe_info *info)
+{
+ u8 *pkt = qp->q2_buf + Q2_BAD_FRAME_OFFSET;
+ __be32 *mpa;
+ u8 ddp_ctl;
+ u8 rdma_ctl;
+ u16 aeq_id = 0;
+ struct irdma_terminate_hdr *termhdr;
+
+ mpa = (__be32 *)irdma_locate_mpa(pkt);
+ if (info->q2_data_written) {
+ /* did not validate the frame - do it now */
+ ddp_ctl = (ntohl(mpa[0]) >> 8) & 0xff;
+ rdma_ctl = ntohl(mpa[0]) & 0xff;
+ if ((ddp_ctl & 0xc0) != 0x40)
+ aeq_id = IRDMA_AE_LCE_QP_CATASTROPHIC;
+ else if ((ddp_ctl & 0x03) != 1)
+ aeq_id = IRDMA_AE_DDP_UBE_INVALID_DDP_VERSION;
+ else if (ntohl(mpa[2]) != 2)
+ aeq_id = IRDMA_AE_DDP_UBE_INVALID_QN;
+ else if (ntohl(mpa[3]) != 1)
+ aeq_id = IRDMA_AE_DDP_INVALID_MSN_GAP_IN_MSN;
+ else if (ntohl(mpa[4]) != 0)
+ aeq_id = IRDMA_AE_DDP_UBE_INVALID_MO;
+ else if ((rdma_ctl & 0xc0) != 0x40)
+ aeq_id = IRDMA_AE_RDMAP_ROE_INVALID_RDMAP_VERSION;
+
+ info->ae_id = aeq_id;
+ if (info->ae_id) {
+ /* Bad terminate recvd - send back a terminate */
+ irdma_terminate_connection(qp, info);
+ return;
+ }
+ }
+
+ qp->term_flags |= IRDMA_TERM_RCVD;
+ qp->event_type = IRDMA_QP_EVENT_CATASTROPHIC;
+ termhdr = (struct irdma_terminate_hdr *)&mpa[5];
+ if (termhdr->layer_etype == RDMAP_REMOTE_PROT ||
+ termhdr->layer_etype == RDMAP_REMOTE_OP) {
+ irdma_terminate_done(qp, 0);
+ } else {
+ irdma_terminate_start_timer(qp);
+ irdma_terminate_send_fin(qp);
+ }
+}
+
+static enum irdma_status_code irdma_null_ws_add(struct irdma_sc_vsi *vsi,
+ u8 user_pri)
+{
+ return 0;
+}
+
+static void irdma_null_ws_remove(struct irdma_sc_vsi *vsi, u8 user_pri)
+{
+ /* do nothing */
+}
+
+static void irdma_null_ws_reset(struct irdma_sc_vsi *vsi)
+{
+ /* do nothing */
+}
+
+/**
+ * irdma_sc_vsi_init - Init the vsi structure
+ * @vsi: pointer to vsi structure to initialize
+ * @info: the info used to initialize the vsi struct
+ */
+void irdma_sc_vsi_init(struct irdma_sc_vsi *vsi,
+ struct irdma_vsi_init_info *info)
+{
+ struct irdma_l2params *l2p;
+ int i;
+
+ vsi->dev = info->dev;
+ vsi->back_vsi = info->back_vsi;
+ vsi->register_qset = info->register_qset;
+ vsi->unregister_qset = info->unregister_qset;
+ vsi->mtu = info->params->mtu;
+ vsi->exception_lan_q = info->exception_lan_q;
+ vsi->vsi_idx = info->pf_data_vsi_num;
+ if (vsi->dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1)
+ vsi->fcn_id = info->dev->hmc_fn_id;
+
+ l2p = info->params;
+ vsi->qos_rel_bw = l2p->vsi_rel_bw;
+ vsi->qos_prio_type = l2p->vsi_prio_type;
+ for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
+ if (vsi->dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1)
+ vsi->qos[i].qs_handle = l2p->qs_handle_list[i];
+ vsi->qos[i].traffic_class = info->params->up2tc[i];
+ vsi->qos[i].rel_bw =
+ l2p->tc_info[vsi->qos[i].traffic_class].rel_bw;
+ vsi->qos[i].prio_type =
+ l2p->tc_info[vsi->qos[i].traffic_class].prio_type;
+ vsi->qos[i].valid = false;
+ mutex_init(&vsi->qos[i].qos_mutex);
+ INIT_LIST_HEAD(&vsi->qos[i].qplist);
+ }
+ if (vsi->register_qset) {
+ vsi->dev->ws_add = irdma_ws_add;
+ vsi->dev->ws_remove = irdma_ws_remove;
+ vsi->dev->ws_reset = irdma_ws_reset;
+ } else {
+ vsi->dev->ws_add = irdma_null_ws_add;
+ vsi->dev->ws_remove = irdma_null_ws_remove;
+ vsi->dev->ws_reset = irdma_null_ws_reset;
+ }
+}
+
+/**
+ * irdma_get_fcn_id - Return the function id
+ * @vsi: pointer to the vsi
+ */
+static u8 irdma_get_fcn_id(struct irdma_sc_vsi *vsi)
+{
+ struct irdma_stats_inst_info stats_info = {};
+ struct irdma_sc_dev *dev = vsi->dev;
+ u8 fcn_id = IRDMA_INVALID_FCN_ID;
+ u8 start_idx, max_stats, i;
+
+ if (dev->hw_attrs.uk_attrs.hw_rev != IRDMA_GEN_1) {
+ if (!irdma_cqp_stats_inst_cmd(vsi, IRDMA_OP_STATS_ALLOCATE,
+ &stats_info))
+ return stats_info.stats_idx;
+ }
+
+ start_idx = 1;
+ max_stats = 16;
+ for (i = start_idx; i < max_stats; i++)
+ if (!dev->fcn_id_array[i]) {
+ fcn_id = i;
+ dev->fcn_id_array[i] = true;
+ break;
+ }
+
+ return fcn_id;
+}
+
+/**
+ * irdma_vsi_stats_init - Initialize the vsi statistics
+ * @vsi: pointer to the vsi structure
+ * @info: The info structure used for initialization
+ */
+enum irdma_status_code irdma_vsi_stats_init(struct irdma_sc_vsi *vsi,
+ struct irdma_vsi_stats_info *info)
+{
+ u8 fcn_id = info->fcn_id;
+ struct irdma_dma_mem *stats_buff_mem;
+
+ vsi->pestat = info->pestat;
+ vsi->pestat->hw = vsi->dev->hw;
+ vsi->pestat->vsi = vsi;
+ stats_buff_mem = &vsi->pestat->gather_info.stats_buff_mem;
+ stats_buff_mem->size = ALIGN(IRDMA_GATHER_STATS_BUF_SIZE * 2, 1);
+ stats_buff_mem->va = dma_alloc_coherent(vsi->pestat->hw->device,
+ stats_buff_mem->size,
+ &stats_buff_mem->pa,
+ GFP_KERNEL);
+ if (!stats_buff_mem->va)
+ return IRDMA_ERR_NO_MEMORY;
+
+ vsi->pestat->gather_info.gather_stats_va = stats_buff_mem->va;
+ vsi->pestat->gather_info.last_gather_stats_va =
+ (void *)((uintptr_t)stats_buff_mem->va +
+ IRDMA_GATHER_STATS_BUF_SIZE);
+
+ irdma_hw_stats_start_timer(vsi);
+ if (info->alloc_fcn_id)
+ fcn_id = irdma_get_fcn_id(vsi);
+ if (fcn_id == IRDMA_INVALID_FCN_ID)
+ goto stats_error;
+
+ vsi->stats_fcn_id_alloc = info->alloc_fcn_id;
+ vsi->fcn_id = fcn_id;
+ if (info->alloc_fcn_id) {
+ vsi->pestat->gather_info.use_stats_inst = true;
+ vsi->pestat->gather_info.stats_inst_index = fcn_id;
+ }
+
+ return 0;
+
+stats_error:
+ dma_free_coherent(vsi->pestat->hw->device, stats_buff_mem->size,
+ stats_buff_mem->va, stats_buff_mem->pa);
+ stats_buff_mem->va = NULL;
+
+ return IRDMA_ERR_CQP_COMPL_ERROR;
+}
+
+/**
+ * irdma_vsi_stats_free - Free the vsi stats
+ * @vsi: pointer to the vsi structure
+ */
+void irdma_vsi_stats_free(struct irdma_sc_vsi *vsi)
+{
+ struct irdma_stats_inst_info stats_info = {};
+ u8 fcn_id = vsi->fcn_id;
+ struct irdma_sc_dev *dev = vsi->dev;
+
+ if (dev->hw_attrs.uk_attrs.hw_rev != IRDMA_GEN_1) {
+ if (vsi->stats_fcn_id_alloc) {
+ stats_info.stats_idx = vsi->fcn_id;
+ irdma_cqp_stats_inst_cmd(vsi, IRDMA_OP_STATS_FREE,
+ &stats_info);
+ }
+ } else {
+ if (vsi->stats_fcn_id_alloc &&
+ fcn_id < vsi->dev->hw_attrs.max_stat_inst)
+ vsi->dev->fcn_id_array[fcn_id] = false;
+ }
+
+ if (!vsi->pestat)
+ return;
+ irdma_hw_stats_stop_timer(vsi);
+ dma_free_coherent(vsi->pestat->hw->device,
+ vsi->pestat->gather_info.stats_buff_mem.size,
+ vsi->pestat->gather_info.stats_buff_mem.va,
+ vsi->pestat->gather_info.stats_buff_mem.pa);
+ vsi->pestat->gather_info.stats_buff_mem.va = NULL;
+}
+
+/**
+ * irdma_get_encoded_wqe_size - given wq size, returns hardware encoded size
+ * @wqsize: size of the wq (sq, rq) to encoded_size
+ * @queue_type: queue type selected for the calculation algorithm
+ */
+u8 irdma_get_encoded_wqe_size(u32 wqsize, enum irdma_queue_type queue_type)
+{
+ u8 encoded_size = 0;
+
+ /* cqp sq's hw coded value starts from 1 for size of 4
+ * while it starts from 0 for qp' wq's.
+ */
+ if (queue_type == IRDMA_QUEUE_TYPE_CQP)
+ encoded_size = 1;
+ wqsize >>= 2;
+ while (wqsize >>= 1)
+ encoded_size++;
+
+ return encoded_size;
+}
+
+/**
+ * irdma_sc_gather_stats - collect the statistics
+ * @cqp: struct for cqp hw
+ * @info: gather stats info structure
+ * @scratch: u64 saved to be used during cqp completion
+ */
+static enum irdma_status_code
+irdma_sc_gather_stats(struct irdma_sc_cqp *cqp,
+ struct irdma_stats_gather_info *info, u64 scratch)
+{
+ __le64 *wqe;
+ u64 temp;
+
+ if (info->stats_buff_mem.size < IRDMA_GATHER_STATS_BUF_SIZE)
+ return IRDMA_ERR_BUF_TOO_SHORT;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 40,
+ FIELD_PREP(IRDMA_CQPSQ_STATS_HMC_FCN_INDEX, info->hmc_fcn_index));
+ set_64bit_val(wqe, 32, info->stats_buff_mem.pa);
+
+ temp = FIELD_PREP(IRDMA_CQPSQ_STATS_WQEVALID, cqp->polarity) |
+ FIELD_PREP(IRDMA_CQPSQ_STATS_USE_INST, info->use_stats_inst) |
+ FIELD_PREP(IRDMA_CQPSQ_STATS_INST_INDEX,
+ info->stats_inst_index) |
+ FIELD_PREP(IRDMA_CQPSQ_STATS_USE_HMC_FCN_INDEX,
+ info->use_hmc_fcn_index) |
+ FIELD_PREP(IRDMA_CQPSQ_STATS_OP, IRDMA_CQP_OP_GATHER_STATS);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, temp);
+
+ print_hex_dump_debug("STATS: GATHER_STATS WQE", DUMP_PREFIX_OFFSET,
+ 16, 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+
+ irdma_sc_cqp_post_sq(cqp);
+ ibdev_dbg(to_ibdev(cqp->dev),
+ "STATS: CQP SQ head 0x%x tail 0x%x size 0x%x\n",
+ cqp->sq_ring.head, cqp->sq_ring.tail, cqp->sq_ring.size);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_manage_stats_inst - allocate or free stats instance
+ * @cqp: struct for cqp hw
+ * @info: stats info structure
+ * @alloc: alloc vs. delete flag
+ * @scratch: u64 saved to be used during cqp completion
+ */
+static enum irdma_status_code
+irdma_sc_manage_stats_inst(struct irdma_sc_cqp *cqp,
+ struct irdma_stats_inst_info *info, bool alloc,
+ u64 scratch)
+{
+ __le64 *wqe;
+ u64 temp;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 40,
+ FIELD_PREP(IRDMA_CQPSQ_STATS_HMC_FCN_INDEX, info->hmc_fn_id));
+ temp = FIELD_PREP(IRDMA_CQPSQ_STATS_WQEVALID, cqp->polarity) |
+ FIELD_PREP(IRDMA_CQPSQ_STATS_ALLOC_INST, alloc) |
+ FIELD_PREP(IRDMA_CQPSQ_STATS_USE_HMC_FCN_INDEX,
+ info->use_hmc_fcn_index) |
+ FIELD_PREP(IRDMA_CQPSQ_STATS_INST_INDEX, info->stats_idx) |
+ FIELD_PREP(IRDMA_CQPSQ_STATS_OP, IRDMA_CQP_OP_MANAGE_STATS);
+
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, temp);
+
+ print_hex_dump_debug("WQE: MANAGE_STATS WQE", DUMP_PREFIX_OFFSET, 16,
+ 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+
+ irdma_sc_cqp_post_sq(cqp);
+ return 0;
+}
+
+/**
+ * irdma_sc_set_up_map - set the up map table
+ * @cqp: struct for cqp hw
+ * @info: User priority map info
+ * @scratch: u64 saved to be used during cqp completion
+ */
+static enum irdma_status_code irdma_sc_set_up_map(struct irdma_sc_cqp *cqp,
+ struct irdma_up_info *info,
+ u64 scratch)
+{
+ __le64 *wqe;
+ u64 temp = 0;
+ int i;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++)
+ temp |= (u64)info->map[i] << (i * 8);
+
+ set_64bit_val(wqe, 0, temp);
+ set_64bit_val(wqe, 40,
+ FIELD_PREP(IRDMA_CQPSQ_UP_CNPOVERRIDE, info->cnp_up_override) |
+ FIELD_PREP(IRDMA_CQPSQ_UP_HMCFCNIDX, info->hmc_fcn_idx));
+
+ temp = FIELD_PREP(IRDMA_CQPSQ_UP_WQEVALID, cqp->polarity) |
+ FIELD_PREP(IRDMA_CQPSQ_UP_USEVLAN, info->use_vlan) |
+ FIELD_PREP(IRDMA_CQPSQ_UP_USEOVERRIDE,
+ info->use_cnp_up_override) |
+ FIELD_PREP(IRDMA_CQPSQ_UP_OP, IRDMA_CQP_OP_UP_MAP);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, temp);
+
+ print_hex_dump_debug("WQE: UPMAP WQE", DUMP_PREFIX_OFFSET, 16, 8, wqe,
+ IRDMA_CQP_WQE_SIZE * 8, false);
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_manage_ws_node - create/modify/destroy WS node
+ * @cqp: struct for cqp hw
+ * @info: node info structure
+ * @node_op: 0 for add 1 for modify, 2 for delete
+ * @scratch: u64 saved to be used during cqp completion
+ */
+static enum irdma_status_code
+irdma_sc_manage_ws_node(struct irdma_sc_cqp *cqp,
+ struct irdma_ws_node_info *info,
+ enum irdma_ws_node_op node_op, u64 scratch)
+{
+ __le64 *wqe;
+ u64 temp = 0;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 32,
+ FIELD_PREP(IRDMA_CQPSQ_WS_VSI, info->vsi) |
+ FIELD_PREP(IRDMA_CQPSQ_WS_WEIGHT, info->weight));
+
+ temp = FIELD_PREP(IRDMA_CQPSQ_WS_WQEVALID, cqp->polarity) |
+ FIELD_PREP(IRDMA_CQPSQ_WS_NODEOP, node_op) |
+ FIELD_PREP(IRDMA_CQPSQ_WS_ENABLENODE, info->enable) |
+ FIELD_PREP(IRDMA_CQPSQ_WS_NODETYPE, info->type_leaf) |
+ FIELD_PREP(IRDMA_CQPSQ_WS_PRIOTYPE, info->prio_type) |
+ FIELD_PREP(IRDMA_CQPSQ_WS_TC, info->tc) |
+ FIELD_PREP(IRDMA_CQPSQ_WS_OP, IRDMA_CQP_OP_WORK_SCHED_NODE) |
+ FIELD_PREP(IRDMA_CQPSQ_WS_PARENTID, info->parent_id) |
+ FIELD_PREP(IRDMA_CQPSQ_WS_NODEID, info->id);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, temp);
+
+ print_hex_dump_debug("WQE: MANAGE_WS WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_qp_flush_wqes - flush qp's wqe
+ * @qp: sc qp
+ * @info: dlush information
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+enum irdma_status_code irdma_sc_qp_flush_wqes(struct irdma_sc_qp *qp,
+ struct irdma_qp_flush_info *info,
+ u64 scratch, bool post_sq)
+{
+ u64 temp = 0;
+ __le64 *wqe;
+ struct irdma_sc_cqp *cqp;
+ u64 hdr;
+ bool flush_sq = false, flush_rq = false;
+
+ if (info->rq && !qp->flush_rq)
+ flush_rq = true;
+ if (info->sq && !qp->flush_sq)
+ flush_sq = true;
+ qp->flush_sq |= flush_sq;
+ qp->flush_rq |= flush_rq;
+
+ if (!flush_sq && !flush_rq) {
+ ibdev_dbg(to_ibdev(qp->dev),
+ "CQP: Additional flush request ignored for qp %x\n",
+ qp->qp_uk.qp_id);
+ return IRDMA_ERR_FLUSHED_Q;
+ }
+
+ cqp = qp->pd->dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ if (info->userflushcode) {
+ if (flush_rq)
+ temp |= FIELD_PREP(IRDMA_CQPSQ_FWQE_RQMNERR,
+ info->rq_minor_code) |
+ FIELD_PREP(IRDMA_CQPSQ_FWQE_RQMJERR,
+ info->rq_major_code);
+ if (flush_sq)
+ temp |= FIELD_PREP(IRDMA_CQPSQ_FWQE_SQMNERR,
+ info->sq_minor_code) |
+ FIELD_PREP(IRDMA_CQPSQ_FWQE_SQMJERR,
+ info->sq_major_code);
+ }
+ set_64bit_val(wqe, 16, temp);
+
+ temp = (info->generate_ae) ?
+ info->ae_code | FIELD_PREP(IRDMA_CQPSQ_FWQE_AESOURCE,
+ info->ae_src) : 0;
+ set_64bit_val(wqe, 8, temp);
+
+ hdr = qp->qp_uk.qp_id |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_FLUSH_WQES) |
+ FIELD_PREP(IRDMA_CQPSQ_FWQE_GENERATE_AE, info->generate_ae) |
+ FIELD_PREP(IRDMA_CQPSQ_FWQE_USERFLCODE, info->userflushcode) |
+ FIELD_PREP(IRDMA_CQPSQ_FWQE_FLUSHSQ, flush_sq) |
+ FIELD_PREP(IRDMA_CQPSQ_FWQE_FLUSHRQ, flush_rq) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: QP_FLUSH WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_gen_ae - generate AE, uses flush WQE CQP OP
+ * @qp: sc qp
+ * @info: gen ae information
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code irdma_sc_gen_ae(struct irdma_sc_qp *qp,
+ struct irdma_gen_ae_info *info,
+ u64 scratch, bool post_sq)
+{
+ u64 temp;
+ __le64 *wqe;
+ struct irdma_sc_cqp *cqp;
+ u64 hdr;
+
+ cqp = qp->pd->dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ temp = info->ae_code | FIELD_PREP(IRDMA_CQPSQ_FWQE_AESOURCE,
+ info->ae_src);
+ set_64bit_val(wqe, 8, temp);
+
+ hdr = qp->qp_uk.qp_id | FIELD_PREP(IRDMA_CQPSQ_OPCODE,
+ IRDMA_CQP_OP_GEN_AE) |
+ FIELD_PREP(IRDMA_CQPSQ_FWQE_GENERATE_AE, 1) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: GEN_AE WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/*** irdma_sc_qp_upload_context - upload qp's context
+ * @dev: sc device struct
+ * @info: upload context info ptr for return
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code
+irdma_sc_qp_upload_context(struct irdma_sc_dev *dev,
+ struct irdma_upload_context_info *info, u64 scratch,
+ bool post_sq)
+{
+ __le64 *wqe;
+ struct irdma_sc_cqp *cqp;
+ u64 hdr;
+
+ cqp = dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 16, info->buf_pa);
+
+ hdr = FIELD_PREP(IRDMA_CQPSQ_UCTX_QPID, info->qp_id) |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_UPLOAD_CONTEXT) |
+ FIELD_PREP(IRDMA_CQPSQ_UCTX_QPTYPE, info->qp_type) |
+ FIELD_PREP(IRDMA_CQPSQ_UCTX_RAWFORMAT, info->raw_format) |
+ FIELD_PREP(IRDMA_CQPSQ_UCTX_FREEZEQP, info->freeze_qp) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: QP_UPLOAD_CTX WQE", DUMP_PREFIX_OFFSET, 16,
+ 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_manage_push_page - Handle push page
+ * @cqp: struct for cqp hw
+ * @info: push page info
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code
+irdma_sc_manage_push_page(struct irdma_sc_cqp *cqp,
+ struct irdma_cqp_manage_push_page_info *info,
+ u64 scratch, bool post_sq)
+{
+ __le64 *wqe;
+ u64 hdr;
+
+ if (info->free_page &&
+ info->push_idx >= cqp->dev->hw_attrs.max_hw_device_pages)
+ return IRDMA_ERR_INVALID_PUSH_PAGE_INDEX;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 16, info->qs_handle);
+ hdr = FIELD_PREP(IRDMA_CQPSQ_MPP_PPIDX, info->push_idx) |
+ FIELD_PREP(IRDMA_CQPSQ_MPP_PPTYPE, info->push_page_type) |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_MANAGE_PUSH_PAGES) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity) |
+ FIELD_PREP(IRDMA_CQPSQ_MPP_FREE_PAGE, info->free_page);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: MANAGE_PUSH_PAGES WQE", DUMP_PREFIX_OFFSET,
+ 16, 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_suspend_qp - suspend qp for param change
+ * @cqp: struct for cqp hw
+ * @qp: sc qp struct
+ * @scratch: u64 saved to be used during cqp completion
+ */
+static enum irdma_status_code irdma_sc_suspend_qp(struct irdma_sc_cqp *cqp,
+ struct irdma_sc_qp *qp,
+ u64 scratch)
+{
+ u64 hdr;
+ __le64 *wqe;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ hdr = FIELD_PREP(IRDMA_CQPSQ_SUSPENDQP_QPID, qp->qp_uk.qp_id) |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_SUSPEND_QP) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: SUSPEND_QP WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_resume_qp - resume qp after suspend
+ * @cqp: struct for cqp hw
+ * @qp: sc qp struct
+ * @scratch: u64 saved to be used during cqp completion
+ */
+static enum irdma_status_code irdma_sc_resume_qp(struct irdma_sc_cqp *cqp,
+ struct irdma_sc_qp *qp,
+ u64 scratch)
+{
+ u64 hdr;
+ __le64 *wqe;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMA_CQPSQ_RESUMEQP_QSHANDLE, qp->qs_handle));
+
+ hdr = FIELD_PREP(IRDMA_CQPSQ_RESUMEQP_QPID, qp->qp_uk.qp_id) |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_RESUME_QP) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: RESUME_QP WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_cq_ack - acknowledge completion q
+ * @cq: cq struct
+ */
+static inline void irdma_sc_cq_ack(struct irdma_sc_cq *cq)
+{
+ writel(cq->cq_uk.cq_id, cq->cq_uk.cq_ack_db);
+}
+
+/**
+ * irdma_sc_cq_init - initialize completion q
+ * @cq: cq struct
+ * @info: cq initialization info
+ */
+enum irdma_status_code irdma_sc_cq_init(struct irdma_sc_cq *cq,
+ struct irdma_cq_init_info *info)
+{
+ enum irdma_status_code ret_code;
+ u32 pble_obj_cnt;
+
+ pble_obj_cnt = info->dev->hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt;
+ if (info->virtual_map && info->first_pm_pbl_idx >= pble_obj_cnt)
+ return IRDMA_ERR_INVALID_PBLE_INDEX;
+
+ cq->cq_pa = info->cq_base_pa;
+ cq->dev = info->dev;
+ cq->ceq_id = info->ceq_id;
+ info->cq_uk_init_info.cqe_alloc_db = cq->dev->cq_arm_db;
+ info->cq_uk_init_info.cq_ack_db = cq->dev->cq_ack_db;
+ ret_code = irdma_uk_cq_init(&cq->cq_uk, &info->cq_uk_init_info);
+ if (ret_code)
+ return ret_code;
+
+ cq->virtual_map = info->virtual_map;
+ cq->pbl_chunk_size = info->pbl_chunk_size;
+ cq->ceqe_mask = info->ceqe_mask;
+ cq->cq_type = (info->type) ? info->type : IRDMA_CQ_TYPE_IWARP;
+ cq->shadow_area_pa = info->shadow_area_pa;
+ cq->shadow_read_threshold = info->shadow_read_threshold;
+ cq->ceq_id_valid = info->ceq_id_valid;
+ cq->tph_en = info->tph_en;
+ cq->tph_val = info->tph_val;
+ cq->first_pm_pbl_idx = info->first_pm_pbl_idx;
+ cq->vsi = info->vsi;
+
+ return 0;
+}
+
+/**
+ * irdma_sc_cq_create - create completion q
+ * @cq: cq struct
+ * @scratch: u64 saved to be used during cqp completion
+ * @check_overflow: flag for overflow check
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code irdma_sc_cq_create(struct irdma_sc_cq *cq,
+ u64 scratch,
+ bool check_overflow,
+ bool post_sq)
+{
+ __le64 *wqe;
+ struct irdma_sc_cqp *cqp;
+ u64 hdr;
+ struct irdma_sc_ceq *ceq;
+ enum irdma_status_code ret_code = 0;
+
+ cqp = cq->dev->cqp;
+ if (cq->cq_uk.cq_id > (cqp->dev->hmc_info->hmc_obj[IRDMA_HMC_IW_CQ].max_cnt - 1))
+ return IRDMA_ERR_INVALID_CQ_ID;
+
+ if (cq->ceq_id > (cq->dev->hmc_fpm_misc.max_ceqs - 1))
+ return IRDMA_ERR_INVALID_CEQ_ID;
+
+ ceq = cq->dev->ceq[cq->ceq_id];
+ if (ceq && ceq->reg_cq)
+ ret_code = irdma_sc_add_cq_ctx(ceq, cq);
+
+ if (ret_code)
+ return ret_code;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe) {
+ if (ceq && ceq->reg_cq)
+ irdma_sc_remove_cq_ctx(ceq, cq);
+ return IRDMA_ERR_RING_FULL;
+ }
+
+ set_64bit_val(wqe, 0, cq->cq_uk.cq_size);
+ set_64bit_val(wqe, 8, (uintptr_t)cq >> 1);
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMA_CQPSQ_CQ_SHADOW_READ_THRESHOLD, cq->shadow_read_threshold));
+ set_64bit_val(wqe, 32, (cq->virtual_map ? 0 : cq->cq_pa));
+ set_64bit_val(wqe, 40, cq->shadow_area_pa);
+ set_64bit_val(wqe, 48,
+ FIELD_PREP(IRDMA_CQPSQ_CQ_FIRSTPMPBLIDX, (cq->virtual_map ? cq->first_pm_pbl_idx : 0)));
+ set_64bit_val(wqe, 56,
+ FIELD_PREP(IRDMA_CQPSQ_TPHVAL, cq->tph_val) |
+ FIELD_PREP(IRDMA_CQPSQ_VSIIDX, cq->vsi->vsi_idx));
+
+ hdr = FLD_LS_64(cq->dev, cq->cq_uk.cq_id, IRDMA_CQPSQ_CQ_CQID) |
+ FLD_LS_64(cq->dev, (cq->ceq_id_valid ? cq->ceq_id : 0),
+ IRDMA_CQPSQ_CQ_CEQID) |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_CREATE_CQ) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_LPBLSIZE, cq->pbl_chunk_size) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_CHKOVERFLOW, check_overflow) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_VIRTMAP, cq->virtual_map) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_ENCEQEMASK, cq->ceqe_mask) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_CEQIDVALID, cq->ceq_id_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_TPHEN, cq->tph_en) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_AVOIDMEMCNFLCT,
+ cq->cq_uk.avoid_mem_cflct) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: CQ_CREATE WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_cq_destroy - destroy completion q
+ * @cq: cq struct
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+enum irdma_status_code irdma_sc_cq_destroy(struct irdma_sc_cq *cq, u64 scratch,
+ bool post_sq)
+{
+ struct irdma_sc_cqp *cqp;
+ __le64 *wqe;
+ u64 hdr;
+ struct irdma_sc_ceq *ceq;
+
+ cqp = cq->dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ ceq = cq->dev->ceq[cq->ceq_id];
+ if (ceq && ceq->reg_cq)
+ irdma_sc_remove_cq_ctx(ceq, cq);
+
+ set_64bit_val(wqe, 0, cq->cq_uk.cq_size);
+ set_64bit_val(wqe, 8, (uintptr_t)cq >> 1);
+ set_64bit_val(wqe, 40, cq->shadow_area_pa);
+ set_64bit_val(wqe, 48,
+ (cq->virtual_map ? cq->first_pm_pbl_idx : 0));
+
+ hdr = cq->cq_uk.cq_id |
+ FLD_LS_64(cq->dev, (cq->ceq_id_valid ? cq->ceq_id : 0),
+ IRDMA_CQPSQ_CQ_CEQID) |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_DESTROY_CQ) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_LPBLSIZE, cq->pbl_chunk_size) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_VIRTMAP, cq->virtual_map) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_ENCEQEMASK, cq->ceqe_mask) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_CEQIDVALID, cq->ceq_id_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_TPHEN, cq->tph_en) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_AVOIDMEMCNFLCT, cq->cq_uk.avoid_mem_cflct) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: CQ_DESTROY WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_cq_resize - set resized cq buffer info
+ * @cq: resized cq
+ * @info: resized cq buffer info
+ */
+void irdma_sc_cq_resize(struct irdma_sc_cq *cq, struct irdma_modify_cq_info *info)
+{
+ cq->virtual_map = info->virtual_map;
+ cq->cq_pa = info->cq_pa;
+ cq->first_pm_pbl_idx = info->first_pm_pbl_idx;
+ cq->pbl_chunk_size = info->pbl_chunk_size;
+ irdma_uk_cq_resize(&cq->cq_uk, info->cq_base, info->cq_size);
+}
+
+/**
+ * irdma_sc_cq_modify - modify a Completion Queue
+ * @cq: cq struct
+ * @info: modification info struct
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag to post to sq
+ */
+static enum irdma_status_code
+irdma_sc_cq_modify(struct irdma_sc_cq *cq, struct irdma_modify_cq_info *info,
+ u64 scratch, bool post_sq)
+{
+ struct irdma_sc_cqp *cqp;
+ __le64 *wqe;
+ u64 hdr;
+ u32 pble_obj_cnt;
+
+ pble_obj_cnt = cq->dev->hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt;
+ if (info->cq_resize && info->virtual_map &&
+ info->first_pm_pbl_idx >= pble_obj_cnt)
+ return IRDMA_ERR_INVALID_PBLE_INDEX;
+
+ cqp = cq->dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 0, info->cq_size);
+ set_64bit_val(wqe, 8, (uintptr_t)cq >> 1);
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMA_CQPSQ_CQ_SHADOW_READ_THRESHOLD, info->shadow_read_threshold));
+ set_64bit_val(wqe, 32, info->cq_pa);
+ set_64bit_val(wqe, 40, cq->shadow_area_pa);
+ set_64bit_val(wqe, 48, info->first_pm_pbl_idx);
+ set_64bit_val(wqe, 56,
+ FIELD_PREP(IRDMA_CQPSQ_TPHVAL, cq->tph_val) |
+ FIELD_PREP(IRDMA_CQPSQ_VSIIDX, cq->vsi->vsi_idx));
+
+ hdr = cq->cq_uk.cq_id |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_MODIFY_CQ) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_CQRESIZE, info->cq_resize) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_LPBLSIZE, info->pbl_chunk_size) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_CHKOVERFLOW, info->check_overflow) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_VIRTMAP, info->virtual_map) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_ENCEQEMASK, cq->ceqe_mask) |
+ FIELD_PREP(IRDMA_CQPSQ_TPHEN, cq->tph_en) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_AVOIDMEMCNFLCT,
+ cq->cq_uk.avoid_mem_cflct) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: CQ_MODIFY WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_check_cqp_progress - check cqp processing progress
+ * @timeout: timeout info struct
+ * @dev: sc device struct
+ */
+void irdma_check_cqp_progress(struct irdma_cqp_timeout *timeout, struct irdma_sc_dev *dev)
+{
+ if (timeout->compl_cqp_cmds != dev->cqp_cmd_stats[IRDMA_OP_CMPL_CMDS]) {
+ timeout->compl_cqp_cmds = dev->cqp_cmd_stats[IRDMA_OP_CMPL_CMDS];
+ timeout->count = 0;
+ } else {
+ if (dev->cqp_cmd_stats[IRDMA_OP_REQ_CMDS] !=
+ timeout->compl_cqp_cmds)
+ timeout->count++;
+ }
+}
+
+/**
+ * irdma_get_cqp_reg_info - get head and tail for cqp using registers
+ * @cqp: struct for cqp hw
+ * @val: cqp tail register value
+ * @tail: wqtail register value
+ * @error: cqp processing err
+ */
+static inline void irdma_get_cqp_reg_info(struct irdma_sc_cqp *cqp, u32 *val,
+ u32 *tail, u32 *error)
+{
+ *val = readl(cqp->dev->hw_regs[IRDMA_CQPTAIL]);
+ *tail = FIELD_GET(IRDMA_CQPTAIL_WQTAIL, *val);
+ *error = FIELD_GET(IRDMA_CQPTAIL_CQP_OP_ERR, *val);
+}
+
+/**
+ * irdma_cqp_poll_registers - poll cqp registers
+ * @cqp: struct for cqp hw
+ * @tail: wqtail register value
+ * @count: how many times to try for completion
+ */
+static enum irdma_status_code irdma_cqp_poll_registers(struct irdma_sc_cqp *cqp,
+ u32 tail, u32 count)
+{
+ u32 i = 0;
+ u32 newtail, error, val;
+
+ while (i++ < count) {
+ irdma_get_cqp_reg_info(cqp, &val, &newtail, &error);
+ if (error) {
+ error = readl(cqp->dev->hw_regs[IRDMA_CQPERRCODES]);
+ ibdev_dbg(to_ibdev(cqp->dev),
+ "CQP: CQPERRCODES error_code[x%08X]\n",
+ error);
+ return IRDMA_ERR_CQP_COMPL_ERROR;
+ }
+ if (newtail != tail) {
+ /* SUCCESS */
+ IRDMA_RING_MOVE_TAIL(cqp->sq_ring);
+ cqp->dev->cqp_cmd_stats[IRDMA_OP_CMPL_CMDS]++;
+ return 0;
+ }
+ udelay(cqp->dev->hw_attrs.max_sleep_count);
+ }
+
+ return IRDMA_ERR_TIMEOUT;
+}
+
+/**
+ * irdma_sc_decode_fpm_commit - decode a 64 bit value into count and base
+ * @dev: sc device struct
+ * @buf: pointer to commit buffer
+ * @buf_idx: buffer index
+ * @obj_info: object info pointer
+ * @rsrc_idx: indexs of memory resource
+ */
+static u64 irdma_sc_decode_fpm_commit(struct irdma_sc_dev *dev, __le64 *buf,
+ u32 buf_idx, struct irdma_hmc_obj_info *obj_info,
+ u32 rsrc_idx)
+{
+ u64 temp;
+
+ get_64bit_val(buf, buf_idx, &temp);
+
+ switch (rsrc_idx) {
+ case IRDMA_HMC_IW_QP:
+ obj_info[rsrc_idx].cnt = (u32)FIELD_GET(IRDMA_COMMIT_FPM_QPCNT, temp);
+ break;
+ case IRDMA_HMC_IW_CQ:
+ obj_info[rsrc_idx].cnt = (u32)FLD_RS_64(dev, temp, IRDMA_COMMIT_FPM_CQCNT);
+ break;
+ case IRDMA_HMC_IW_APBVT_ENTRY:
+ obj_info[rsrc_idx].cnt = 1;
+ break;
+ default:
+ obj_info[rsrc_idx].cnt = (u32)temp;
+ break;
+ }
+
+ obj_info[rsrc_idx].base = (temp >> IRDMA_COMMIT_FPM_BASE_S) * 512;
+
+ return temp;
+}
+
+/**
+ * irdma_sc_parse_fpm_commit_buf - parse fpm commit buffer
+ * @dev: pointer to dev struct
+ * @buf: ptr to fpm commit buffer
+ * @info: ptr to irdma_hmc_obj_info struct
+ * @sd: number of SDs for HMC objects
+ *
+ * parses fpm commit info and copy base value
+ * of hmc objects in hmc_info
+ */
+static enum irdma_status_code
+irdma_sc_parse_fpm_commit_buf(struct irdma_sc_dev *dev, __le64 *buf,
+ struct irdma_hmc_obj_info *info, u32 *sd)
+{
+ u64 size;
+ u32 i;
+ u64 max_base = 0;
+ u32 last_hmc_obj = 0;
+
+ irdma_sc_decode_fpm_commit(dev, buf, 0, info,
+ IRDMA_HMC_IW_QP);
+ irdma_sc_decode_fpm_commit(dev, buf, 8, info,
+ IRDMA_HMC_IW_CQ);
+ /* skiping RSRVD */
+ irdma_sc_decode_fpm_commit(dev, buf, 24, info,
+ IRDMA_HMC_IW_HTE);
+ irdma_sc_decode_fpm_commit(dev, buf, 32, info,
+ IRDMA_HMC_IW_ARP);
+ irdma_sc_decode_fpm_commit(dev, buf, 40, info,
+ IRDMA_HMC_IW_APBVT_ENTRY);
+ irdma_sc_decode_fpm_commit(dev, buf, 48, info,
+ IRDMA_HMC_IW_MR);
+ irdma_sc_decode_fpm_commit(dev, buf, 56, info,
+ IRDMA_HMC_IW_XF);
+ irdma_sc_decode_fpm_commit(dev, buf, 64, info,
+ IRDMA_HMC_IW_XFFL);
+ irdma_sc_decode_fpm_commit(dev, buf, 72, info,
+ IRDMA_HMC_IW_Q1);
+ irdma_sc_decode_fpm_commit(dev, buf, 80, info,
+ IRDMA_HMC_IW_Q1FL);
+ irdma_sc_decode_fpm_commit(dev, buf, 88, info,
+ IRDMA_HMC_IW_TIMER);
+ irdma_sc_decode_fpm_commit(dev, buf, 112, info,
+ IRDMA_HMC_IW_PBLE);
+ /* skipping RSVD. */
+ if (dev->hw_attrs.uk_attrs.hw_rev != IRDMA_GEN_1) {
+ irdma_sc_decode_fpm_commit(dev, buf, 96, info,
+ IRDMA_HMC_IW_FSIMC);
+ irdma_sc_decode_fpm_commit(dev, buf, 104, info,
+ IRDMA_HMC_IW_FSIAV);
+ irdma_sc_decode_fpm_commit(dev, buf, 128, info,
+ IRDMA_HMC_IW_RRF);
+ irdma_sc_decode_fpm_commit(dev, buf, 136, info,
+ IRDMA_HMC_IW_RRFFL);
+ irdma_sc_decode_fpm_commit(dev, buf, 144, info,
+ IRDMA_HMC_IW_HDR);
+ irdma_sc_decode_fpm_commit(dev, buf, 152, info,
+ IRDMA_HMC_IW_MD);
+ irdma_sc_decode_fpm_commit(dev, buf, 160, info,
+ IRDMA_HMC_IW_OOISC);
+ irdma_sc_decode_fpm_commit(dev, buf, 168, info,
+ IRDMA_HMC_IW_OOISCFFL);
+ }
+
+ /* searching for the last object in HMC to find the size of the HMC area. */
+ for (i = IRDMA_HMC_IW_QP; i < IRDMA_HMC_IW_MAX; i++) {
+ if (info[i].base > max_base) {
+ max_base = info[i].base;
+ last_hmc_obj = i;
+ }
+ }
+
+ size = info[last_hmc_obj].cnt * info[last_hmc_obj].size +
+ info[last_hmc_obj].base;
+
+ if (size & 0x1FFFFF)
+ *sd = (u32)((size >> 21) + 1); /* add 1 for remainder */
+ else
+ *sd = (u32)(size >> 21);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_decode_fpm_query() - Decode a 64 bit value into max count and size
+ * @buf: ptr to fpm query buffer
+ * @buf_idx: index into buf
+ * @obj_info: ptr to irdma_hmc_obj_info struct
+ * @rsrc_idx: resource index into info
+ *
+ * Decode a 64 bit value from fpm query buffer into max count and size
+ */
+static u64 irdma_sc_decode_fpm_query(__le64 *buf, u32 buf_idx,
+ struct irdma_hmc_obj_info *obj_info,
+ u32 rsrc_idx)
+{
+ u64 temp;
+ u32 size;
+
+ get_64bit_val(buf, buf_idx, &temp);
+ obj_info[rsrc_idx].max_cnt = (u32)temp;
+ size = (u32)(temp >> 32);
+ obj_info[rsrc_idx].size = BIT_ULL(size);
+
+ return temp;
+}
+
+/**
+ * irdma_sc_parse_fpm_query_buf() - parses fpm query buffer
+ * @dev: ptr to shared code device
+ * @buf: ptr to fpm query buffer
+ * @hmc_info: ptr to irdma_hmc_obj_info struct
+ * @hmc_fpm_misc: ptr to fpm data
+ *
+ * parses fpm query buffer and copy max_cnt and
+ * size value of hmc objects in hmc_info
+ */
+static enum irdma_status_code
+irdma_sc_parse_fpm_query_buf(struct irdma_sc_dev *dev, __le64 *buf,
+ struct irdma_hmc_info *hmc_info,
+ struct irdma_hmc_fpm_misc *hmc_fpm_misc)
+{
+ struct irdma_hmc_obj_info *obj_info;
+ u64 temp;
+ u32 size;
+ u16 max_pe_sds;
+
+ obj_info = hmc_info->hmc_obj;
+
+ get_64bit_val(buf, 0, &temp);
+ hmc_info->first_sd_index = (u16)FIELD_GET(IRDMA_QUERY_FPM_FIRST_PE_SD_INDEX, temp);
+ max_pe_sds = (u16)FIELD_GET(IRDMA_QUERY_FPM_MAX_PE_SDS, temp);
+
+ hmc_fpm_misc->max_sds = max_pe_sds;
+ hmc_info->sd_table.sd_cnt = max_pe_sds + hmc_info->first_sd_index;
+ get_64bit_val(buf, 8, &temp);
+ obj_info[IRDMA_HMC_IW_QP].max_cnt = (u32)FIELD_GET(IRDMA_QUERY_FPM_MAX_QPS, temp);
+ size = (u32)(temp >> 32);
+ obj_info[IRDMA_HMC_IW_QP].size = BIT_ULL(size);
+
+ get_64bit_val(buf, 16, &temp);
+ obj_info[IRDMA_HMC_IW_CQ].max_cnt = (u32)FIELD_GET(IRDMA_QUERY_FPM_MAX_CQS, temp);
+ size = (u32)(temp >> 32);
+ obj_info[IRDMA_HMC_IW_CQ].size = BIT_ULL(size);
+
+ irdma_sc_decode_fpm_query(buf, 32, obj_info, IRDMA_HMC_IW_HTE);
+ irdma_sc_decode_fpm_query(buf, 40, obj_info, IRDMA_HMC_IW_ARP);
+
+ obj_info[IRDMA_HMC_IW_APBVT_ENTRY].size = 8192;
+ obj_info[IRDMA_HMC_IW_APBVT_ENTRY].max_cnt = 1;
+
+ irdma_sc_decode_fpm_query(buf, 48, obj_info, IRDMA_HMC_IW_MR);
+ irdma_sc_decode_fpm_query(buf, 56, obj_info, IRDMA_HMC_IW_XF);
+
+ get_64bit_val(buf, 64, &temp);
+ obj_info[IRDMA_HMC_IW_XFFL].max_cnt = (u32)temp;
+ obj_info[IRDMA_HMC_IW_XFFL].size = 4;
+ hmc_fpm_misc->xf_block_size = FIELD_GET(IRDMA_QUERY_FPM_XFBLOCKSIZE, temp);
+ if (!hmc_fpm_misc->xf_block_size)
+ return IRDMA_ERR_INVALID_SIZE;
+
+ irdma_sc_decode_fpm_query(buf, 72, obj_info, IRDMA_HMC_IW_Q1);
+ get_64bit_val(buf, 80, &temp);
+ obj_info[IRDMA_HMC_IW_Q1FL].max_cnt = (u32)temp;
+ obj_info[IRDMA_HMC_IW_Q1FL].size = 4;
+
+ hmc_fpm_misc->q1_block_size = FIELD_GET(IRDMA_QUERY_FPM_Q1BLOCKSIZE, temp);
+ if (!hmc_fpm_misc->q1_block_size)
+ return IRDMA_ERR_INVALID_SIZE;
+
+ irdma_sc_decode_fpm_query(buf, 88, obj_info, IRDMA_HMC_IW_TIMER);
+
+ get_64bit_val(buf, 112, &temp);
+ obj_info[IRDMA_HMC_IW_PBLE].max_cnt = (u32)temp;
+ obj_info[IRDMA_HMC_IW_PBLE].size = 8;
+
+ get_64bit_val(buf, 120, &temp);
+ hmc_fpm_misc->max_ceqs = FIELD_GET(IRDMA_QUERY_FPM_MAX_CEQS, temp);
+ hmc_fpm_misc->ht_multiplier = FIELD_GET(IRDMA_QUERY_FPM_HTMULTIPLIER, temp);
+ hmc_fpm_misc->timer_bucket = FIELD_GET(IRDMA_QUERY_FPM_TIMERBUCKET, temp);
+ if (dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1)
+ return 0;
+ irdma_sc_decode_fpm_query(buf, 96, obj_info, IRDMA_HMC_IW_FSIMC);
+ irdma_sc_decode_fpm_query(buf, 104, obj_info, IRDMA_HMC_IW_FSIAV);
+ irdma_sc_decode_fpm_query(buf, 128, obj_info, IRDMA_HMC_IW_RRF);
+
+ get_64bit_val(buf, 136, &temp);
+ obj_info[IRDMA_HMC_IW_RRFFL].max_cnt = (u32)temp;
+ obj_info[IRDMA_HMC_IW_RRFFL].size = 4;
+ hmc_fpm_misc->rrf_block_size = FIELD_GET(IRDMA_QUERY_FPM_RRFBLOCKSIZE, temp);
+ if (!hmc_fpm_misc->rrf_block_size &&
+ obj_info[IRDMA_HMC_IW_RRFFL].max_cnt)
+ return IRDMA_ERR_INVALID_SIZE;
+
+ irdma_sc_decode_fpm_query(buf, 144, obj_info, IRDMA_HMC_IW_HDR);
+ irdma_sc_decode_fpm_query(buf, 152, obj_info, IRDMA_HMC_IW_MD);
+ irdma_sc_decode_fpm_query(buf, 160, obj_info, IRDMA_HMC_IW_OOISC);
+
+ get_64bit_val(buf, 168, &temp);
+ obj_info[IRDMA_HMC_IW_OOISCFFL].max_cnt = (u32)temp;
+ obj_info[IRDMA_HMC_IW_OOISCFFL].size = 4;
+ hmc_fpm_misc->ooiscf_block_size = FIELD_GET(IRDMA_QUERY_FPM_OOISCFBLOCKSIZE, temp);
+ if (!hmc_fpm_misc->ooiscf_block_size &&
+ obj_info[IRDMA_HMC_IW_OOISCFFL].max_cnt)
+ return IRDMA_ERR_INVALID_SIZE;
+
+ return 0;
+}
+
+/**
+ * irdma_sc_find_reg_cq - find cq ctx index
+ * @ceq: ceq sc structure
+ * @cq: cq sc structure
+ */
+static u32 irdma_sc_find_reg_cq(struct irdma_sc_ceq *ceq,
+ struct irdma_sc_cq *cq)
+{
+ u32 i;
+
+ for (i = 0; i < ceq->reg_cq_size; i++) {
+ if (cq == ceq->reg_cq[i])
+ return i;
+ }
+
+ return IRDMA_INVALID_CQ_IDX;
+}
+
+/**
+ * irdma_sc_add_cq_ctx - add cq ctx tracking for ceq
+ * @ceq: ceq sc structure
+ * @cq: cq sc structure
+ */
+enum irdma_status_code irdma_sc_add_cq_ctx(struct irdma_sc_ceq *ceq,
+ struct irdma_sc_cq *cq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ceq->req_cq_lock, flags);
+
+ if (ceq->reg_cq_size == ceq->elem_cnt) {
+ spin_unlock_irqrestore(&ceq->req_cq_lock, flags);
+ return IRDMA_ERR_REG_CQ_FULL;
+ }
+
+ ceq->reg_cq[ceq->reg_cq_size++] = cq;
+
+ spin_unlock_irqrestore(&ceq->req_cq_lock, flags);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_remove_cq_ctx - remove cq ctx tracking for ceq
+ * @ceq: ceq sc structure
+ * @cq: cq sc structure
+ */
+void irdma_sc_remove_cq_ctx(struct irdma_sc_ceq *ceq, struct irdma_sc_cq *cq)
+{
+ unsigned long flags;
+ u32 cq_ctx_idx;
+
+ spin_lock_irqsave(&ceq->req_cq_lock, flags);
+ cq_ctx_idx = irdma_sc_find_reg_cq(ceq, cq);
+ if (cq_ctx_idx == IRDMA_INVALID_CQ_IDX)
+ goto exit;
+
+ ceq->reg_cq_size--;
+ if (cq_ctx_idx != ceq->reg_cq_size)
+ ceq->reg_cq[cq_ctx_idx] = ceq->reg_cq[ceq->reg_cq_size];
+ ceq->reg_cq[ceq->reg_cq_size] = NULL;
+
+exit:
+ spin_unlock_irqrestore(&ceq->req_cq_lock, flags);
+}
+
+/**
+ * irdma_sc_cqp_init - Initialize buffers for a control Queue Pair
+ * @cqp: IWARP control queue pair pointer
+ * @info: IWARP control queue pair init info pointer
+ *
+ * Initializes the object and context buffers for a control Queue Pair.
+ */
+enum irdma_status_code irdma_sc_cqp_init(struct irdma_sc_cqp *cqp,
+ struct irdma_cqp_init_info *info)
+{
+ u8 hw_sq_size;
+
+ if (info->sq_size > IRDMA_CQP_SW_SQSIZE_2048 ||
+ info->sq_size < IRDMA_CQP_SW_SQSIZE_4 ||
+ ((info->sq_size & (info->sq_size - 1))))
+ return IRDMA_ERR_INVALID_SIZE;
+
+ hw_sq_size = irdma_get_encoded_wqe_size(info->sq_size,
+ IRDMA_QUEUE_TYPE_CQP);
+ cqp->size = sizeof(*cqp);
+ cqp->sq_size = info->sq_size;
+ cqp->hw_sq_size = hw_sq_size;
+ cqp->sq_base = info->sq;
+ cqp->host_ctx = info->host_ctx;
+ cqp->sq_pa = info->sq_pa;
+ cqp->host_ctx_pa = info->host_ctx_pa;
+ cqp->dev = info->dev;
+ cqp->struct_ver = info->struct_ver;
+ cqp->hw_maj_ver = info->hw_maj_ver;
+ cqp->hw_min_ver = info->hw_min_ver;
+ cqp->scratch_array = info->scratch_array;
+ cqp->polarity = 0;
+ cqp->en_datacenter_tcp = info->en_datacenter_tcp;
+ cqp->ena_vf_count = info->ena_vf_count;
+ cqp->hmc_profile = info->hmc_profile;
+ cqp->ceqs_per_vf = info->ceqs_per_vf;
+ cqp->disable_packed = info->disable_packed;
+ cqp->rocev2_rto_policy = info->rocev2_rto_policy;
+ cqp->protocol_used = info->protocol_used;
+ memcpy(&cqp->dcqcn_params, &info->dcqcn_params, sizeof(cqp->dcqcn_params));
+ info->dev->cqp = cqp;
+
+ IRDMA_RING_INIT(cqp->sq_ring, cqp->sq_size);
+ cqp->dev->cqp_cmd_stats[IRDMA_OP_REQ_CMDS] = 0;
+ cqp->dev->cqp_cmd_stats[IRDMA_OP_CMPL_CMDS] = 0;
+ /* for the cqp commands backlog. */
+ INIT_LIST_HEAD(&cqp->dev->cqp_cmd_head);
+
+ writel(0, cqp->dev->hw_regs[IRDMA_CQPTAIL]);
+ writel(0, cqp->dev->hw_regs[IRDMA_CQPDB]);
+ writel(0, cqp->dev->hw_regs[IRDMA_CCQPSTATUS]);
+
+ ibdev_dbg(to_ibdev(cqp->dev),
+ "WQE: sq_size[%04d] hw_sq_size[%04d] sq_base[%p] sq_pa[%pK] cqp[%p] polarity[x%04x]\n",
+ cqp->sq_size, cqp->hw_sq_size, cqp->sq_base,
+ (u64 *)(uintptr_t)cqp->sq_pa, cqp, cqp->polarity);
+ return 0;
+}
+
+/**
+ * irdma_sc_cqp_create - create cqp during bringup
+ * @cqp: struct for cqp hw
+ * @maj_err: If error, major err number
+ * @min_err: If error, minor err number
+ */
+enum irdma_status_code irdma_sc_cqp_create(struct irdma_sc_cqp *cqp, u16 *maj_err,
+ u16 *min_err)
+{
+ u64 temp;
+ u8 hw_rev;
+ u32 cnt = 0, p1, p2, val = 0, err_code;
+ enum irdma_status_code ret_code;
+
+ hw_rev = cqp->dev->hw_attrs.uk_attrs.hw_rev;
+ cqp->sdbuf.size = ALIGN(IRDMA_UPDATE_SD_BUFF_SIZE * cqp->sq_size,
+ IRDMA_SD_BUF_ALIGNMENT);
+ cqp->sdbuf.va = dma_alloc_coherent(cqp->dev->hw->device,
+ cqp->sdbuf.size, &cqp->sdbuf.pa,
+ GFP_KERNEL);
+ if (!cqp->sdbuf.va)
+ return IRDMA_ERR_NO_MEMORY;
+
+ spin_lock_init(&cqp->dev->cqp_lock);
+
+ temp = FIELD_PREP(IRDMA_CQPHC_SQSIZE, cqp->hw_sq_size) |
+ FIELD_PREP(IRDMA_CQPHC_SVER, cqp->struct_ver) |
+ FIELD_PREP(IRDMA_CQPHC_DISABLE_PFPDUS, cqp->disable_packed) |
+ FIELD_PREP(IRDMA_CQPHC_CEQPERVF, cqp->ceqs_per_vf);
+ if (hw_rev >= IRDMA_GEN_2) {
+ temp |= FIELD_PREP(IRDMA_CQPHC_ROCEV2_RTO_POLICY,
+ cqp->rocev2_rto_policy) |
+ FIELD_PREP(IRDMA_CQPHC_PROTOCOL_USED,
+ cqp->protocol_used);
+ }
+
+ set_64bit_val(cqp->host_ctx, 0, temp);
+ set_64bit_val(cqp->host_ctx, 8, cqp->sq_pa);
+
+ temp = FIELD_PREP(IRDMA_CQPHC_ENABLED_VFS, cqp->ena_vf_count) |
+ FIELD_PREP(IRDMA_CQPHC_HMC_PROFILE, cqp->hmc_profile);
+ set_64bit_val(cqp->host_ctx, 16, temp);
+ set_64bit_val(cqp->host_ctx, 24, (uintptr_t)cqp);
+ temp = FIELD_PREP(IRDMA_CQPHC_HW_MAJVER, cqp->hw_maj_ver) |
+ FIELD_PREP(IRDMA_CQPHC_HW_MINVER, cqp->hw_min_ver);
+ if (hw_rev >= IRDMA_GEN_2) {
+ temp |= FIELD_PREP(IRDMA_CQPHC_MIN_RATE, cqp->dcqcn_params.min_rate) |
+ FIELD_PREP(IRDMA_CQPHC_MIN_DEC_FACTOR, cqp->dcqcn_params.min_dec_factor);
+ }
+ set_64bit_val(cqp->host_ctx, 32, temp);
+ set_64bit_val(cqp->host_ctx, 40, 0);
+ temp = 0;
+ if (hw_rev >= IRDMA_GEN_2) {
+ temp |= FIELD_PREP(IRDMA_CQPHC_DCQCN_T, cqp->dcqcn_params.dcqcn_t) |
+ FIELD_PREP(IRDMA_CQPHC_RAI_FACTOR, cqp->dcqcn_params.rai_factor) |
+ FIELD_PREP(IRDMA_CQPHC_HAI_FACTOR, cqp->dcqcn_params.hai_factor);
+ }
+ set_64bit_val(cqp->host_ctx, 48, temp);
+ temp = 0;
+ if (hw_rev >= IRDMA_GEN_2) {
+ temp |= FIELD_PREP(IRDMA_CQPHC_DCQCN_B, cqp->dcqcn_params.dcqcn_b) |
+ FIELD_PREP(IRDMA_CQPHC_DCQCN_F, cqp->dcqcn_params.dcqcn_f) |
+ FIELD_PREP(IRDMA_CQPHC_CC_CFG_VALID, cqp->dcqcn_params.cc_cfg_valid) |
+ FIELD_PREP(IRDMA_CQPHC_RREDUCE_MPERIOD, cqp->dcqcn_params.rreduce_mperiod);
+ }
+ set_64bit_val(cqp->host_ctx, 56, temp);
+ print_hex_dump_debug("WQE: CQP_HOST_CTX WQE", DUMP_PREFIX_OFFSET, 16,
+ 8, cqp->host_ctx, IRDMA_CQP_CTX_SIZE * 8, false);
+ p1 = cqp->host_ctx_pa >> 32;
+ p2 = (u32)cqp->host_ctx_pa;
+
+ writel(p1, cqp->dev->hw_regs[IRDMA_CCQPHIGH]);
+ writel(p2, cqp->dev->hw_regs[IRDMA_CCQPLOW]);
+
+ do {
+ if (cnt++ > cqp->dev->hw_attrs.max_done_count) {
+ ret_code = IRDMA_ERR_TIMEOUT;
+ goto err;
+ }
+ udelay(cqp->dev->hw_attrs.max_sleep_count);
+ val = readl(cqp->dev->hw_regs[IRDMA_CCQPSTATUS]);
+ } while (!val);
+
+ if (FLD_RS_32(cqp->dev, val, IRDMA_CCQPSTATUS_CCQP_ERR)) {
+ ret_code = IRDMA_ERR_DEVICE_NOT_SUPPORTED;
+ goto err;
+ }
+
+ cqp->process_cqp_sds = irdma_update_sds_noccq;
+ return 0;
+
+err:
+ dma_free_coherent(cqp->dev->hw->device, cqp->sdbuf.size,
+ cqp->sdbuf.va, cqp->sdbuf.pa);
+ cqp->sdbuf.va = NULL;
+ err_code = readl(cqp->dev->hw_regs[IRDMA_CQPERRCODES]);
+ *min_err = FIELD_GET(IRDMA_CQPERRCODES_CQP_MINOR_CODE, err_code);
+ *maj_err = FIELD_GET(IRDMA_CQPERRCODES_CQP_MAJOR_CODE, err_code);
+ return ret_code;
+}
+
+/**
+ * irdma_sc_cqp_post_sq - post of cqp's sq
+ * @cqp: struct for cqp hw
+ */
+void irdma_sc_cqp_post_sq(struct irdma_sc_cqp *cqp)
+{
+ writel(IRDMA_RING_CURRENT_HEAD(cqp->sq_ring), cqp->dev->cqp_db);
+
+ ibdev_dbg(to_ibdev(cqp->dev),
+ "WQE: CQP SQ head 0x%x tail 0x%x size 0x%x\n",
+ cqp->sq_ring.head, cqp->sq_ring.tail, cqp->sq_ring.size);
+}
+
+/**
+ * irdma_sc_cqp_get_next_send_wqe_idx - get next wqe on cqp sq
+ * and pass back index
+ * @cqp: CQP HW structure
+ * @scratch: private data for CQP WQE
+ * @wqe_idx: WQE index of CQP SQ
+ */
+__le64 *irdma_sc_cqp_get_next_send_wqe_idx(struct irdma_sc_cqp *cqp, u64 scratch,
+ u32 *wqe_idx)
+{
+ __le64 *wqe = NULL;
+ enum irdma_status_code ret_code;
+
+ if (IRDMA_RING_FULL_ERR(cqp->sq_ring)) {
+ ibdev_dbg(to_ibdev(cqp->dev),
+ "WQE: CQP SQ is full, head 0x%x tail 0x%x size 0x%x\n",
+ cqp->sq_ring.head, cqp->sq_ring.tail,
+ cqp->sq_ring.size);
+ return NULL;
+ }
+ IRDMA_ATOMIC_RING_MOVE_HEAD(cqp->sq_ring, *wqe_idx, ret_code);
+ if (ret_code)
+ return NULL;
+
+ cqp->dev->cqp_cmd_stats[IRDMA_OP_REQ_CMDS]++;
+ if (!*wqe_idx)
+ cqp->polarity = !cqp->polarity;
+ wqe = cqp->sq_base[*wqe_idx].elem;
+ cqp->scratch_array[*wqe_idx] = scratch;
+ IRDMA_CQP_INIT_WQE(wqe);
+
+ return wqe;
+}
+
+/**
+ * irdma_sc_cqp_destroy - destroy cqp during close
+ * @cqp: struct for cqp hw
+ */
+enum irdma_status_code irdma_sc_cqp_destroy(struct irdma_sc_cqp *cqp)
+{
+ u32 cnt = 0, val;
+ enum irdma_status_code ret_code = 0;
+
+ writel(0, cqp->dev->hw_regs[IRDMA_CCQPHIGH]);
+ writel(0, cqp->dev->hw_regs[IRDMA_CCQPLOW]);
+ do {
+ if (cnt++ > cqp->dev->hw_attrs.max_done_count) {
+ ret_code = IRDMA_ERR_TIMEOUT;
+ break;
+ }
+ udelay(cqp->dev->hw_attrs.max_sleep_count);
+ val = readl(cqp->dev->hw_regs[IRDMA_CCQPSTATUS]);
+ } while (FLD_RS_32(cqp->dev, val, IRDMA_CCQPSTATUS_CCQP_DONE));
+
+ dma_free_coherent(cqp->dev->hw->device, cqp->sdbuf.size,
+ cqp->sdbuf.va, cqp->sdbuf.pa);
+ cqp->sdbuf.va = NULL;
+ return ret_code;
+}
+
+/**
+ * irdma_sc_ccq_arm - enable intr for control cq
+ * @ccq: ccq sc struct
+ */
+void irdma_sc_ccq_arm(struct irdma_sc_cq *ccq)
+{
+ u64 temp_val;
+ u16 sw_cq_sel;
+ u8 arm_next_se;
+ u8 arm_seq_num;
+
+ get_64bit_val(ccq->cq_uk.shadow_area, 32, &temp_val);
+ sw_cq_sel = (u16)FIELD_GET(IRDMA_CQ_DBSA_SW_CQ_SELECT, temp_val);
+ arm_next_se = (u8)FIELD_GET(IRDMA_CQ_DBSA_ARM_NEXT_SE, temp_val);
+ arm_seq_num = (u8)FIELD_GET(IRDMA_CQ_DBSA_ARM_SEQ_NUM, temp_val);
+ arm_seq_num++;
+ temp_val = FIELD_PREP(IRDMA_CQ_DBSA_ARM_SEQ_NUM, arm_seq_num) |
+ FIELD_PREP(IRDMA_CQ_DBSA_SW_CQ_SELECT, sw_cq_sel) |
+ FIELD_PREP(IRDMA_CQ_DBSA_ARM_NEXT_SE, arm_next_se) |
+ FIELD_PREP(IRDMA_CQ_DBSA_ARM_NEXT, 1);
+ set_64bit_val(ccq->cq_uk.shadow_area, 32, temp_val);
+
+ dma_wmb(); /* make sure shadow area is updated before arming */
+
+ writel(ccq->cq_uk.cq_id, ccq->dev->cq_arm_db);
+}
+
+/**
+ * irdma_sc_ccq_get_cqe_info - get ccq's cq entry
+ * @ccq: ccq sc struct
+ * @info: completion q entry to return
+ */
+enum irdma_status_code irdma_sc_ccq_get_cqe_info(struct irdma_sc_cq *ccq,
+ struct irdma_ccq_cqe_info *info)
+{
+ u64 qp_ctx, temp, temp1;
+ __le64 *cqe;
+ struct irdma_sc_cqp *cqp;
+ u32 wqe_idx;
+ u32 error;
+ u8 polarity;
+ enum irdma_status_code ret_code = 0;
+
+ if (ccq->cq_uk.avoid_mem_cflct)
+ cqe = IRDMA_GET_CURRENT_EXTENDED_CQ_ELEM(&ccq->cq_uk);
+ else
+ cqe = IRDMA_GET_CURRENT_CQ_ELEM(&ccq->cq_uk);
+
+ get_64bit_val(cqe, 24, &temp);
+ polarity = (u8)FIELD_GET(IRDMA_CQ_VALID, temp);
+ if (polarity != ccq->cq_uk.polarity)
+ return IRDMA_ERR_Q_EMPTY;
+
+ get_64bit_val(cqe, 8, &qp_ctx);
+ cqp = (struct irdma_sc_cqp *)(unsigned long)qp_ctx;
+ info->error = (bool)FIELD_GET(IRDMA_CQ_ERROR, temp);
+ info->maj_err_code = IRDMA_CQPSQ_MAJ_NO_ERROR;
+ info->min_err_code = (u16)FIELD_GET(IRDMA_CQ_MINERR, temp);
+ if (info->error) {
+ info->maj_err_code = (u16)FIELD_GET(IRDMA_CQ_MAJERR, temp);
+ error = readl(cqp->dev->hw_regs[IRDMA_CQPERRCODES]);
+ ibdev_dbg(to_ibdev(cqp->dev),
+ "CQP: CQPERRCODES error_code[x%08X]\n", error);
+ }
+
+ wqe_idx = (u32)FIELD_GET(IRDMA_CQ_WQEIDX, temp);
+ info->scratch = cqp->scratch_array[wqe_idx];
+
+ get_64bit_val(cqe, 16, &temp1);
+ info->op_ret_val = (u32)FIELD_GET(IRDMA_CCQ_OPRETVAL, temp1);
+ get_64bit_val(cqp->sq_base[wqe_idx].elem, 24, &temp1);
+ info->op_code = (u8)FIELD_GET(IRDMA_CQPSQ_OPCODE, temp1);
+ info->cqp = cqp;
+
+ /* move the head for cq */
+ IRDMA_RING_MOVE_HEAD(ccq->cq_uk.cq_ring, ret_code);
+ if (!IRDMA_RING_CURRENT_HEAD(ccq->cq_uk.cq_ring))
+ ccq->cq_uk.polarity ^= 1;
+
+ /* update cq tail in cq shadow memory also */
+ IRDMA_RING_MOVE_TAIL(ccq->cq_uk.cq_ring);
+ set_64bit_val(ccq->cq_uk.shadow_area, 0,
+ IRDMA_RING_CURRENT_HEAD(ccq->cq_uk.cq_ring));
+
+ dma_wmb(); /* make sure shadow area is updated before moving tail */
+
+ IRDMA_RING_MOVE_TAIL(cqp->sq_ring);
+ ccq->dev->cqp_cmd_stats[IRDMA_OP_CMPL_CMDS]++;
+
+ return ret_code;
+}
+
+/**
+ * irdma_sc_poll_for_cqp_op_done - Waits for last write to complete in CQP SQ
+ * @cqp: struct for cqp hw
+ * @op_code: cqp opcode for completion
+ * @compl_info: completion q entry to return
+ */
+enum irdma_status_code irdma_sc_poll_for_cqp_op_done(struct irdma_sc_cqp *cqp, u8 op_code,
+ struct irdma_ccq_cqe_info *compl_info)
+{
+ struct irdma_ccq_cqe_info info = {};
+ struct irdma_sc_cq *ccq;
+ enum irdma_status_code ret_code = 0;
+ u32 cnt = 0;
+
+ ccq = cqp->dev->ccq;
+ while (1) {
+ if (cnt++ > 100 * cqp->dev->hw_attrs.max_done_count)
+ return IRDMA_ERR_TIMEOUT;
+
+ if (irdma_sc_ccq_get_cqe_info(ccq, &info)) {
+ udelay(cqp->dev->hw_attrs.max_sleep_count);
+ continue;
+ }
+ if (info.error && info.op_code != IRDMA_CQP_OP_QUERY_STAG) {
+ ret_code = IRDMA_ERR_CQP_COMPL_ERROR;
+ break;
+ }
+ /* make sure op code matches*/
+ if (op_code == info.op_code)
+ break;
+ ibdev_dbg(to_ibdev(cqp->dev),
+ "WQE: opcode mismatch for my op code 0x%x, returned opcode %x\n",
+ op_code, info.op_code);
+ }
+
+ if (compl_info)
+ memcpy(compl_info, &info, sizeof(*compl_info));
+
+ return ret_code;
+}
+
+/**
+ * irdma_sc_manage_hmc_pm_func_table - manage of function table
+ * @cqp: struct for cqp hw
+ * @scratch: u64 saved to be used during cqp completion
+ * @info: info for the manage function table operation
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code
+irdma_sc_manage_hmc_pm_func_table(struct irdma_sc_cqp *cqp,
+ struct irdma_hmc_fcn_info *info,
+ u64 scratch, bool post_sq)
+{
+ __le64 *wqe;
+ u64 hdr;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 0, 0);
+ set_64bit_val(wqe, 8, 0);
+ set_64bit_val(wqe, 16, 0);
+ set_64bit_val(wqe, 32, 0);
+ set_64bit_val(wqe, 40, 0);
+ set_64bit_val(wqe, 48, 0);
+ set_64bit_val(wqe, 56, 0);
+
+ hdr = FIELD_PREP(IRDMA_CQPSQ_MHMC_VFIDX, info->vf_id) |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE,
+ IRDMA_CQP_OP_MANAGE_HMC_PM_FUNC_TABLE) |
+ FIELD_PREP(IRDMA_CQPSQ_MHMC_FREEPMFN, info->free_fcn) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: MANAGE_HMC_PM_FUNC_TABLE WQE",
+ DUMP_PREFIX_OFFSET, 16, 8, wqe,
+ IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_commit_fpm_val_done - wait for cqp eqe completion
+ * for fpm commit
+ * @cqp: struct for cqp hw
+ */
+static enum irdma_status_code
+irdma_sc_commit_fpm_val_done(struct irdma_sc_cqp *cqp)
+{
+ return irdma_sc_poll_for_cqp_op_done(cqp, IRDMA_CQP_OP_COMMIT_FPM_VAL,
+ NULL);
+}
+
+/**
+ * irdma_sc_commit_fpm_val - cqp wqe for commit fpm values
+ * @cqp: struct for cqp hw
+ * @scratch: u64 saved to be used during cqp completion
+ * @hmc_fn_id: hmc function id
+ * @commit_fpm_mem: Memory for fpm values
+ * @post_sq: flag for cqp db to ring
+ * @wait_type: poll ccq or cqp registers for cqp completion
+ */
+static enum irdma_status_code
+irdma_sc_commit_fpm_val(struct irdma_sc_cqp *cqp, u64 scratch, u8 hmc_fn_id,
+ struct irdma_dma_mem *commit_fpm_mem, bool post_sq,
+ u8 wait_type)
+{
+ __le64 *wqe;
+ u64 hdr;
+ u32 tail, val, error;
+ enum irdma_status_code ret_code = 0;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 16, hmc_fn_id);
+ set_64bit_val(wqe, 32, commit_fpm_mem->pa);
+
+ hdr = FIELD_PREP(IRDMA_CQPSQ_BUFSIZE, IRDMA_COMMIT_FPM_BUF_SIZE) |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_COMMIT_FPM_VAL) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: COMMIT_FPM_VAL WQE", DUMP_PREFIX_OFFSET,
+ 16, 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ irdma_get_cqp_reg_info(cqp, &val, &tail, &error);
+
+ if (post_sq) {
+ irdma_sc_cqp_post_sq(cqp);
+ if (wait_type == IRDMA_CQP_WAIT_POLL_REGS)
+ ret_code = irdma_cqp_poll_registers(cqp, tail,
+ cqp->dev->hw_attrs.max_done_count);
+ else if (wait_type == IRDMA_CQP_WAIT_POLL_CQ)
+ ret_code = irdma_sc_commit_fpm_val_done(cqp);
+ }
+
+ return ret_code;
+}
+
+/**
+ * irdma_sc_query_fpm_val_done - poll for cqp wqe completion for
+ * query fpm
+ * @cqp: struct for cqp hw
+ */
+static enum irdma_status_code
+irdma_sc_query_fpm_val_done(struct irdma_sc_cqp *cqp)
+{
+ return irdma_sc_poll_for_cqp_op_done(cqp, IRDMA_CQP_OP_QUERY_FPM_VAL,
+ NULL);
+}
+
+/**
+ * irdma_sc_query_fpm_val - cqp wqe query fpm values
+ * @cqp: struct for cqp hw
+ * @scratch: u64 saved to be used during cqp completion
+ * @hmc_fn_id: hmc function id
+ * @query_fpm_mem: memory for return fpm values
+ * @post_sq: flag for cqp db to ring
+ * @wait_type: poll ccq or cqp registers for cqp completion
+ */
+static enum irdma_status_code
+irdma_sc_query_fpm_val(struct irdma_sc_cqp *cqp, u64 scratch, u8 hmc_fn_id,
+ struct irdma_dma_mem *query_fpm_mem, bool post_sq,
+ u8 wait_type)
+{
+ __le64 *wqe;
+ u64 hdr;
+ u32 tail, val, error;
+ enum irdma_status_code ret_code = 0;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 16, hmc_fn_id);
+ set_64bit_val(wqe, 32, query_fpm_mem->pa);
+
+ hdr = FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_QUERY_FPM_VAL) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: QUERY_FPM WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ irdma_get_cqp_reg_info(cqp, &val, &tail, &error);
+
+ if (post_sq) {
+ irdma_sc_cqp_post_sq(cqp);
+ if (wait_type == IRDMA_CQP_WAIT_POLL_REGS)
+ ret_code = irdma_cqp_poll_registers(cqp, tail,
+ cqp->dev->hw_attrs.max_done_count);
+ else if (wait_type == IRDMA_CQP_WAIT_POLL_CQ)
+ ret_code = irdma_sc_query_fpm_val_done(cqp);
+ }
+
+ return ret_code;
+}
+
+/**
+ * irdma_sc_ceq_init - initialize ceq
+ * @ceq: ceq sc structure
+ * @info: ceq initialization info
+ */
+enum irdma_status_code irdma_sc_ceq_init(struct irdma_sc_ceq *ceq,
+ struct irdma_ceq_init_info *info)
+{
+ u32 pble_obj_cnt;
+
+ if (info->elem_cnt < info->dev->hw_attrs.min_hw_ceq_size ||
+ info->elem_cnt > info->dev->hw_attrs.max_hw_ceq_size)
+ return IRDMA_ERR_INVALID_SIZE;
+
+ if (info->ceq_id > (info->dev->hmc_fpm_misc.max_ceqs - 1))
+ return IRDMA_ERR_INVALID_CEQ_ID;
+ pble_obj_cnt = info->dev->hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt;
+
+ if (info->virtual_map && info->first_pm_pbl_idx >= pble_obj_cnt)
+ return IRDMA_ERR_INVALID_PBLE_INDEX;
+
+ ceq->size = sizeof(*ceq);
+ ceq->ceqe_base = (struct irdma_ceqe *)info->ceqe_base;
+ ceq->ceq_id = info->ceq_id;
+ ceq->dev = info->dev;
+ ceq->elem_cnt = info->elem_cnt;
+ ceq->ceq_elem_pa = info->ceqe_pa;
+ ceq->virtual_map = info->virtual_map;
+ ceq->itr_no_expire = info->itr_no_expire;
+ ceq->reg_cq = info->reg_cq;
+ ceq->reg_cq_size = 0;
+ spin_lock_init(&ceq->req_cq_lock);
+ ceq->pbl_chunk_size = (ceq->virtual_map ? info->pbl_chunk_size : 0);
+ ceq->first_pm_pbl_idx = (ceq->virtual_map ? info->first_pm_pbl_idx : 0);
+ ceq->pbl_list = (ceq->virtual_map ? info->pbl_list : NULL);
+ ceq->tph_en = info->tph_en;
+ ceq->tph_val = info->tph_val;
+ ceq->vsi = info->vsi;
+ ceq->polarity = 1;
+ IRDMA_RING_INIT(ceq->ceq_ring, ceq->elem_cnt);
+ ceq->dev->ceq[info->ceq_id] = ceq;
+
+ return 0;
+}
+
+/**
+ * irdma_sc_ceq_create - create ceq wqe
+ * @ceq: ceq sc structure
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+
+static enum irdma_status_code irdma_sc_ceq_create(struct irdma_sc_ceq *ceq, u64 scratch,
+ bool post_sq)
+{
+ struct irdma_sc_cqp *cqp;
+ __le64 *wqe;
+ u64 hdr;
+
+ cqp = ceq->dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+ set_64bit_val(wqe, 16, ceq->elem_cnt);
+ set_64bit_val(wqe, 32,
+ (ceq->virtual_map ? 0 : ceq->ceq_elem_pa));
+ set_64bit_val(wqe, 48,
+ (ceq->virtual_map ? ceq->first_pm_pbl_idx : 0));
+ set_64bit_val(wqe, 56,
+ FIELD_PREP(IRDMA_CQPSQ_TPHVAL, ceq->tph_val) |
+ FIELD_PREP(IRDMA_CQPSQ_VSIIDX, ceq->vsi->vsi_idx));
+ hdr = FIELD_PREP(IRDMA_CQPSQ_CEQ_CEQID, ceq->ceq_id) |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_CREATE_CEQ) |
+ FIELD_PREP(IRDMA_CQPSQ_CEQ_LPBLSIZE, ceq->pbl_chunk_size) |
+ FIELD_PREP(IRDMA_CQPSQ_CEQ_VMAP, ceq->virtual_map) |
+ FIELD_PREP(IRDMA_CQPSQ_CEQ_ITRNOEXPIRE, ceq->itr_no_expire) |
+ FIELD_PREP(IRDMA_CQPSQ_TPHEN, ceq->tph_en) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: CEQ_CREATE WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_cceq_create_done - poll for control ceq wqe to complete
+ * @ceq: ceq sc structure
+ */
+static enum irdma_status_code
+irdma_sc_cceq_create_done(struct irdma_sc_ceq *ceq)
+{
+ struct irdma_sc_cqp *cqp;
+
+ cqp = ceq->dev->cqp;
+ return irdma_sc_poll_for_cqp_op_done(cqp, IRDMA_CQP_OP_CREATE_CEQ,
+ NULL);
+}
+
+/**
+ * irdma_sc_cceq_destroy_done - poll for destroy cceq to complete
+ * @ceq: ceq sc structure
+ */
+enum irdma_status_code irdma_sc_cceq_destroy_done(struct irdma_sc_ceq *ceq)
+{
+ struct irdma_sc_cqp *cqp;
+
+ if (ceq->reg_cq)
+ irdma_sc_remove_cq_ctx(ceq, ceq->dev->ccq);
+
+ cqp = ceq->dev->cqp;
+ cqp->process_cqp_sds = irdma_update_sds_noccq;
+
+ return irdma_sc_poll_for_cqp_op_done(cqp, IRDMA_CQP_OP_DESTROY_CEQ,
+ NULL);
+}
+
+/**
+ * irdma_sc_cceq_create - create cceq
+ * @ceq: ceq sc structure
+ * @scratch: u64 saved to be used during cqp completion
+ */
+enum irdma_status_code irdma_sc_cceq_create(struct irdma_sc_ceq *ceq, u64 scratch)
+{
+ enum irdma_status_code ret_code;
+ struct irdma_sc_dev *dev = ceq->dev;
+
+ dev->ccq->vsi = ceq->vsi;
+ if (ceq->reg_cq) {
+ ret_code = irdma_sc_add_cq_ctx(ceq, ceq->dev->ccq);
+ if (ret_code)
+ return ret_code;
+ }
+
+ ret_code = irdma_sc_ceq_create(ceq, scratch, true);
+ if (!ret_code)
+ return irdma_sc_cceq_create_done(ceq);
+
+ return ret_code;
+}
+
+/**
+ * irdma_sc_ceq_destroy - destroy ceq
+ * @ceq: ceq sc structure
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+enum irdma_status_code irdma_sc_ceq_destroy(struct irdma_sc_ceq *ceq, u64 scratch,
+ bool post_sq)
+{
+ struct irdma_sc_cqp *cqp;
+ __le64 *wqe;
+ u64 hdr;
+
+ cqp = ceq->dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 16, ceq->elem_cnt);
+ set_64bit_val(wqe, 48, ceq->first_pm_pbl_idx);
+ hdr = ceq->ceq_id |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_DESTROY_CEQ) |
+ FIELD_PREP(IRDMA_CQPSQ_CEQ_LPBLSIZE, ceq->pbl_chunk_size) |
+ FIELD_PREP(IRDMA_CQPSQ_CEQ_VMAP, ceq->virtual_map) |
+ FIELD_PREP(IRDMA_CQPSQ_TPHEN, ceq->tph_en) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: CEQ_DESTROY WQE", DUMP_PREFIX_OFFSET, 16,
+ 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_process_ceq - process ceq
+ * @dev: sc device struct
+ * @ceq: ceq sc structure
+ *
+ * It is expected caller serializes this function with cleanup_ceqes()
+ * because these functions manipulate the same ceq
+ */
+void *irdma_sc_process_ceq(struct irdma_sc_dev *dev, struct irdma_sc_ceq *ceq)
+{
+ u64 temp;
+ __le64 *ceqe;
+ struct irdma_sc_cq *cq = NULL;
+ struct irdma_sc_cq *temp_cq;
+ u8 polarity;
+ u32 cq_idx;
+ unsigned long flags;
+
+ do {
+ cq_idx = 0;
+ ceqe = IRDMA_GET_CURRENT_CEQ_ELEM(ceq);
+ get_64bit_val(ceqe, 0, &temp);
+ polarity = (u8)FIELD_GET(IRDMA_CEQE_VALID, temp);
+ if (polarity != ceq->polarity)
+ return NULL;
+
+ temp_cq = (struct irdma_sc_cq *)(unsigned long)(temp << 1);
+ if (!temp_cq) {
+ cq_idx = IRDMA_INVALID_CQ_IDX;
+ IRDMA_RING_MOVE_TAIL(ceq->ceq_ring);
+
+ if (!IRDMA_RING_CURRENT_TAIL(ceq->ceq_ring))
+ ceq->polarity ^= 1;
+ continue;
+ }
+
+ cq = temp_cq;
+ if (ceq->reg_cq) {
+ spin_lock_irqsave(&ceq->req_cq_lock, flags);
+ cq_idx = irdma_sc_find_reg_cq(ceq, cq);
+ spin_unlock_irqrestore(&ceq->req_cq_lock, flags);
+ }
+
+ IRDMA_RING_MOVE_TAIL(ceq->ceq_ring);
+ if (!IRDMA_RING_CURRENT_TAIL(ceq->ceq_ring))
+ ceq->polarity ^= 1;
+ } while (cq_idx == IRDMA_INVALID_CQ_IDX);
+
+ if (cq)
+ irdma_sc_cq_ack(cq);
+ return cq;
+}
+
+/**
+ * irdma_sc_cleanup_ceqes - clear the valid ceqes ctx matching the cq
+ * @cq: cq for which the ceqes need to be cleaned up
+ * @ceq: ceq ptr
+ *
+ * The function is called after the cq is destroyed to cleanup
+ * its pending ceqe entries. It is expected caller serializes this
+ * function with process_ceq() in interrupt context.
+ */
+void irdma_sc_cleanup_ceqes(struct irdma_sc_cq *cq, struct irdma_sc_ceq *ceq)
+{
+ struct irdma_sc_cq *next_cq;
+ u8 ceq_polarity = ceq->polarity;
+ __le64 *ceqe;
+ u8 polarity;
+ u64 temp;
+ int next;
+ u32 i;
+
+ next = IRDMA_RING_GET_NEXT_TAIL(ceq->ceq_ring, 0);
+
+ for (i = 1; i <= IRDMA_RING_SIZE(*ceq); i++) {
+ ceqe = IRDMA_GET_CEQ_ELEM_AT_POS(ceq, next);
+
+ get_64bit_val(ceqe, 0, &temp);
+ polarity = (u8)FIELD_GET(IRDMA_CEQE_VALID, temp);
+ if (polarity != ceq_polarity)
+ return;
+
+ next_cq = (struct irdma_sc_cq *)(unsigned long)(temp << 1);
+ if (cq == next_cq)
+ set_64bit_val(ceqe, 0, temp & IRDMA_CEQE_VALID);
+
+ next = IRDMA_RING_GET_NEXT_TAIL(ceq->ceq_ring, i);
+ if (!next)
+ ceq_polarity ^= 1;
+ }
+}
+
+/**
+ * irdma_sc_aeq_init - initialize aeq
+ * @aeq: aeq structure ptr
+ * @info: aeq initialization info
+ */
+enum irdma_status_code irdma_sc_aeq_init(struct irdma_sc_aeq *aeq,
+ struct irdma_aeq_init_info *info)
+{
+ u32 pble_obj_cnt;
+
+ if (info->elem_cnt < info->dev->hw_attrs.min_hw_aeq_size ||
+ info->elem_cnt > info->dev->hw_attrs.max_hw_aeq_size)
+ return IRDMA_ERR_INVALID_SIZE;
+
+ pble_obj_cnt = info->dev->hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt;
+
+ if (info->virtual_map && info->first_pm_pbl_idx >= pble_obj_cnt)
+ return IRDMA_ERR_INVALID_PBLE_INDEX;
+
+ aeq->size = sizeof(*aeq);
+ aeq->polarity = 1;
+ aeq->aeqe_base = (struct irdma_sc_aeqe *)info->aeqe_base;
+ aeq->dev = info->dev;
+ aeq->elem_cnt = info->elem_cnt;
+ aeq->aeq_elem_pa = info->aeq_elem_pa;
+ IRDMA_RING_INIT(aeq->aeq_ring, aeq->elem_cnt);
+ aeq->virtual_map = info->virtual_map;
+ aeq->pbl_list = (aeq->virtual_map ? info->pbl_list : NULL);
+ aeq->pbl_chunk_size = (aeq->virtual_map ? info->pbl_chunk_size : 0);
+ aeq->first_pm_pbl_idx = (aeq->virtual_map ? info->first_pm_pbl_idx : 0);
+ aeq->msix_idx = info->msix_idx;
+ info->dev->aeq = aeq;
+
+ return 0;
+}
+
+/**
+ * irdma_sc_aeq_create - create aeq
+ * @aeq: aeq structure ptr
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code irdma_sc_aeq_create(struct irdma_sc_aeq *aeq,
+ u64 scratch, bool post_sq)
+{
+ __le64 *wqe;
+ struct irdma_sc_cqp *cqp;
+ u64 hdr;
+
+ cqp = aeq->dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+ set_64bit_val(wqe, 16, aeq->elem_cnt);
+ set_64bit_val(wqe, 32,
+ (aeq->virtual_map ? 0 : aeq->aeq_elem_pa));
+ set_64bit_val(wqe, 48,
+ (aeq->virtual_map ? aeq->first_pm_pbl_idx : 0));
+
+ hdr = FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_CREATE_AEQ) |
+ FIELD_PREP(IRDMA_CQPSQ_AEQ_LPBLSIZE, aeq->pbl_chunk_size) |
+ FIELD_PREP(IRDMA_CQPSQ_AEQ_VMAP, aeq->virtual_map) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: AEQ_CREATE WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_aeq_destroy - destroy aeq during close
+ * @aeq: aeq structure ptr
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+static enum irdma_status_code irdma_sc_aeq_destroy(struct irdma_sc_aeq *aeq,
+ u64 scratch, bool post_sq)
+{
+ __le64 *wqe;
+ struct irdma_sc_cqp *cqp;
+ struct irdma_sc_dev *dev;
+ u64 hdr;
+
+ dev = aeq->dev;
+ writel(0, dev->hw_regs[IRDMA_PFINT_AEQCTL]);
+
+ cqp = dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+ set_64bit_val(wqe, 16, aeq->elem_cnt);
+ set_64bit_val(wqe, 48, aeq->first_pm_pbl_idx);
+ hdr = FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_DESTROY_AEQ) |
+ FIELD_PREP(IRDMA_CQPSQ_AEQ_LPBLSIZE, aeq->pbl_chunk_size) |
+ FIELD_PREP(IRDMA_CQPSQ_AEQ_VMAP, aeq->virtual_map) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: AEQ_DESTROY WQE", DUMP_PREFIX_OFFSET, 16,
+ 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ if (post_sq)
+ irdma_sc_cqp_post_sq(cqp);
+ return 0;
+}
+
+/**
+ * irdma_sc_get_next_aeqe - get next aeq entry
+ * @aeq: aeq structure ptr
+ * @info: aeqe info to be returned
+ */
+enum irdma_status_code irdma_sc_get_next_aeqe(struct irdma_sc_aeq *aeq,
+ struct irdma_aeqe_info *info)
+{
+ u64 temp, compl_ctx;
+ __le64 *aeqe;
+ u16 wqe_idx;
+ u8 ae_src;
+ u8 polarity;
+
+ aeqe = IRDMA_GET_CURRENT_AEQ_ELEM(aeq);
+ get_64bit_val(aeqe, 0, &compl_ctx);
+ get_64bit_val(aeqe, 8, &temp);
+ polarity = (u8)FIELD_GET(IRDMA_AEQE_VALID, temp);
+
+ if (aeq->polarity != polarity)
+ return IRDMA_ERR_Q_EMPTY;
+
+ print_hex_dump_debug("WQE: AEQ_ENTRY WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ aeqe, 16, false);
+
+ ae_src = (u8)FIELD_GET(IRDMA_AEQE_AESRC, temp);
+ wqe_idx = (u16)FIELD_GET(IRDMA_AEQE_WQDESCIDX, temp);
+ info->qp_cq_id = (u32)FIELD_GET(IRDMA_AEQE_QPCQID_LOW, temp) |
+ ((u32)FIELD_GET(IRDMA_AEQE_QPCQID_HI, temp) << 18);
+ info->ae_id = (u16)FIELD_GET(IRDMA_AEQE_AECODE, temp);
+ info->tcp_state = (u8)FIELD_GET(IRDMA_AEQE_TCPSTATE, temp);
+ info->iwarp_state = (u8)FIELD_GET(IRDMA_AEQE_IWSTATE, temp);
+ info->q2_data_written = (u8)FIELD_GET(IRDMA_AEQE_Q2DATA, temp);
+ info->aeqe_overflow = (bool)FIELD_GET(IRDMA_AEQE_OVERFLOW, temp);
+
+ info->ae_src = ae_src;
+ switch (info->ae_id) {
+ case IRDMA_AE_PRIV_OPERATION_DENIED:
+ case IRDMA_AE_AMP_INVALIDATE_TYPE1_MW:
+ case IRDMA_AE_AMP_MWBIND_ZERO_BASED_TYPE1_MW:
+ case IRDMA_AE_AMP_FASTREG_INVALID_PBL_HPS_CFG:
+ case IRDMA_AE_AMP_FASTREG_PBLE_MISMATCH:
+ case IRDMA_AE_UDA_XMIT_DGRAM_TOO_LONG:
+ case IRDMA_AE_UDA_XMIT_BAD_PD:
+ case IRDMA_AE_UDA_XMIT_DGRAM_TOO_SHORT:
+ case IRDMA_AE_BAD_CLOSE:
+ case IRDMA_AE_RDMA_READ_WHILE_ORD_ZERO:
+ case IRDMA_AE_STAG_ZERO_INVALID:
+ case IRDMA_AE_IB_RREQ_AND_Q1_FULL:
+ case IRDMA_AE_IB_INVALID_REQUEST:
+ case IRDMA_AE_WQE_UNEXPECTED_OPCODE:
+ case IRDMA_AE_IB_REMOTE_ACCESS_ERROR:
+ case IRDMA_AE_IB_REMOTE_OP_ERROR:
+ case IRDMA_AE_DDP_UBE_INVALID_DDP_VERSION:
+ case IRDMA_AE_DDP_UBE_INVALID_MO:
+ case IRDMA_AE_DDP_UBE_INVALID_QN:
+ case IRDMA_AE_DDP_NO_L_BIT:
+ case IRDMA_AE_RDMAP_ROE_INVALID_RDMAP_VERSION:
+ case IRDMA_AE_RDMAP_ROE_UNEXPECTED_OPCODE:
+ case IRDMA_AE_ROE_INVALID_RDMA_READ_REQUEST:
+ case IRDMA_AE_ROE_INVALID_RDMA_WRITE_OR_READ_RESP:
+ case IRDMA_AE_ROCE_RSP_LENGTH_ERROR:
+ case IRDMA_AE_INVALID_ARP_ENTRY:
+ case IRDMA_AE_INVALID_TCP_OPTION_RCVD:
+ case IRDMA_AE_STALE_ARP_ENTRY:
+ case IRDMA_AE_INVALID_AH_ENTRY:
+ case IRDMA_AE_LLP_RECEIVED_MPA_CRC_ERROR:
+ case IRDMA_AE_LLP_SEGMENT_TOO_SMALL:
+ case IRDMA_AE_LLP_TOO_MANY_RETRIES:
+ case IRDMA_AE_LLP_DOUBT_REACHABILITY:
+ case IRDMA_AE_LLP_CONNECTION_ESTABLISHED:
+ case IRDMA_AE_RESET_SENT:
+ case IRDMA_AE_TERMINATE_SENT:
+ case IRDMA_AE_RESET_NOT_SENT:
+ case IRDMA_AE_LCE_QP_CATASTROPHIC:
+ case IRDMA_AE_QP_SUSPEND_COMPLETE:
+ case IRDMA_AE_UDA_L4LEN_INVALID:
+ info->qp = true;
+ info->compl_ctx = compl_ctx;
+ break;
+ case IRDMA_AE_LCE_CQ_CATASTROPHIC:
+ info->cq = true;
+ info->compl_ctx = compl_ctx << 1;
+ ae_src = IRDMA_AE_SOURCE_RSVD;
+ break;
+ case IRDMA_AE_ROCE_EMPTY_MCG:
+ case IRDMA_AE_ROCE_BAD_MC_IP_ADDR:
+ case IRDMA_AE_ROCE_BAD_MC_QPID:
+ case IRDMA_AE_MCG_QP_PROTOCOL_MISMATCH:
+ fallthrough;
+ case IRDMA_AE_LLP_CONNECTION_RESET:
+ case IRDMA_AE_LLP_SYN_RECEIVED:
+ case IRDMA_AE_LLP_FIN_RECEIVED:
+ case IRDMA_AE_LLP_CLOSE_COMPLETE:
+ case IRDMA_AE_LLP_TERMINATE_RECEIVED:
+ case IRDMA_AE_RDMAP_ROE_BAD_LLP_CLOSE:
+ ae_src = IRDMA_AE_SOURCE_RSVD;
+ info->qp = true;
+ info->compl_ctx = compl_ctx;
+ break;
+ default:
+ break;
+ }
+
+ switch (ae_src) {
+ case IRDMA_AE_SOURCE_RQ:
+ case IRDMA_AE_SOURCE_RQ_0011:
+ info->qp = true;
+ info->rq = true;
+ info->wqe_idx = wqe_idx;
+ info->compl_ctx = compl_ctx;
+ break;
+ case IRDMA_AE_SOURCE_CQ:
+ case IRDMA_AE_SOURCE_CQ_0110:
+ case IRDMA_AE_SOURCE_CQ_1010:
+ case IRDMA_AE_SOURCE_CQ_1110:
+ info->cq = true;
+ info->compl_ctx = compl_ctx << 1;
+ break;
+ case IRDMA_AE_SOURCE_SQ:
+ case IRDMA_AE_SOURCE_SQ_0111:
+ info->qp = true;
+ info->sq = true;
+ info->wqe_idx = wqe_idx;
+ info->compl_ctx = compl_ctx;
+ break;
+ case IRDMA_AE_SOURCE_IN_RR_WR:
+ case IRDMA_AE_SOURCE_IN_RR_WR_1011:
+ info->qp = true;
+ info->compl_ctx = compl_ctx;
+ info->in_rdrsp_wr = true;
+ break;
+ case IRDMA_AE_SOURCE_OUT_RR:
+ case IRDMA_AE_SOURCE_OUT_RR_1111:
+ info->qp = true;
+ info->compl_ctx = compl_ctx;
+ info->out_rdrsp = true;
+ break;
+ case IRDMA_AE_SOURCE_RSVD:
+ default:
+ break;
+ }
+
+ IRDMA_RING_MOVE_TAIL(aeq->aeq_ring);
+ if (!IRDMA_RING_CURRENT_TAIL(aeq->aeq_ring))
+ aeq->polarity ^= 1;
+
+ return 0;
+}
+
+/**
+ * irdma_sc_repost_aeq_entries - repost completed aeq entries
+ * @dev: sc device struct
+ * @count: allocate count
+ */
+enum irdma_status_code irdma_sc_repost_aeq_entries(struct irdma_sc_dev *dev, u32 count)
+{
+ writel(count, dev->hw_regs[IRDMA_AEQALLOC]);
+
+ return 0;
+}
+
+/**
+ * irdma_sc_ccq_init - initialize control cq
+ * @cq: sc's cq ctruct
+ * @info: info for control cq initialization
+ */
+enum irdma_status_code irdma_sc_ccq_init(struct irdma_sc_cq *cq,
+ struct irdma_ccq_init_info *info)
+{
+ u32 pble_obj_cnt;
+
+ if (info->num_elem < info->dev->hw_attrs.uk_attrs.min_hw_cq_size ||
+ info->num_elem > info->dev->hw_attrs.uk_attrs.max_hw_cq_size)
+ return IRDMA_ERR_INVALID_SIZE;
+
+ if (info->ceq_id > (info->dev->hmc_fpm_misc.max_ceqs - 1))
+ return IRDMA_ERR_INVALID_CEQ_ID;
+
+ pble_obj_cnt = info->dev->hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt;
+
+ if (info->virtual_map && info->first_pm_pbl_idx >= pble_obj_cnt)
+ return IRDMA_ERR_INVALID_PBLE_INDEX;
+
+ cq->cq_pa = info->cq_pa;
+ cq->cq_uk.cq_base = info->cq_base;
+ cq->shadow_area_pa = info->shadow_area_pa;
+ cq->cq_uk.shadow_area = info->shadow_area;
+ cq->shadow_read_threshold = info->shadow_read_threshold;
+ cq->dev = info->dev;
+ cq->ceq_id = info->ceq_id;
+ cq->cq_uk.cq_size = info->num_elem;
+ cq->cq_type = IRDMA_CQ_TYPE_CQP;
+ cq->ceqe_mask = info->ceqe_mask;
+ IRDMA_RING_INIT(cq->cq_uk.cq_ring, info->num_elem);
+ cq->cq_uk.cq_id = 0; /* control cq is id 0 always */
+ cq->ceq_id_valid = info->ceq_id_valid;
+ cq->tph_en = info->tph_en;
+ cq->tph_val = info->tph_val;
+ cq->cq_uk.avoid_mem_cflct = info->avoid_mem_cflct;
+ cq->pbl_list = info->pbl_list;
+ cq->virtual_map = info->virtual_map;
+ cq->pbl_chunk_size = info->pbl_chunk_size;
+ cq->first_pm_pbl_idx = info->first_pm_pbl_idx;
+ cq->cq_uk.polarity = true;
+ cq->vsi = info->vsi;
+ cq->cq_uk.cq_ack_db = cq->dev->cq_ack_db;
+
+ /* Only applicable to CQs other than CCQ so initialize to zero */
+ cq->cq_uk.cqe_alloc_db = NULL;
+
+ info->dev->ccq = cq;
+ return 0;
+}
+
+/**
+ * irdma_sc_ccq_create_done - poll cqp for ccq create
+ * @ccq: ccq sc struct
+ */
+static inline enum irdma_status_code irdma_sc_ccq_create_done(struct irdma_sc_cq *ccq)
+{
+ struct irdma_sc_cqp *cqp;
+
+ cqp = ccq->dev->cqp;
+
+ return irdma_sc_poll_for_cqp_op_done(cqp, IRDMA_CQP_OP_CREATE_CQ, NULL);
+}
+
+/**
+ * irdma_sc_ccq_create - create control cq
+ * @ccq: ccq sc struct
+ * @scratch: u64 saved to be used during cqp completion
+ * @check_overflow: overlow flag for ccq
+ * @post_sq: flag for cqp db to ring
+ */
+enum irdma_status_code irdma_sc_ccq_create(struct irdma_sc_cq *ccq, u64 scratch,
+ bool check_overflow, bool post_sq)
+{
+ enum irdma_status_code ret_code;
+
+ ret_code = irdma_sc_cq_create(ccq, scratch, check_overflow, post_sq);
+ if (ret_code)
+ return ret_code;
+
+ if (post_sq) {
+ ret_code = irdma_sc_ccq_create_done(ccq);
+ if (ret_code)
+ return ret_code;
+ }
+ ccq->dev->cqp->process_cqp_sds = irdma_cqp_sds_cmd;
+
+ return 0;
+}
+
+/**
+ * irdma_sc_ccq_destroy - destroy ccq during close
+ * @ccq: ccq sc struct
+ * @scratch: u64 saved to be used during cqp completion
+ * @post_sq: flag for cqp db to ring
+ */
+enum irdma_status_code irdma_sc_ccq_destroy(struct irdma_sc_cq *ccq, u64 scratch,
+ bool post_sq)
+{
+ struct irdma_sc_cqp *cqp;
+ __le64 *wqe;
+ u64 hdr;
+ enum irdma_status_code ret_code = 0;
+ u32 tail, val, error;
+
+ cqp = ccq->dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 0, ccq->cq_uk.cq_size);
+ set_64bit_val(wqe, 8, (uintptr_t)ccq >> 1);
+ set_64bit_val(wqe, 40, ccq->shadow_area_pa);
+
+ hdr = ccq->cq_uk.cq_id |
+ FLD_LS_64(ccq->dev, (ccq->ceq_id_valid ? ccq->ceq_id : 0),
+ IRDMA_CQPSQ_CQ_CEQID) |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_DESTROY_CQ) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_ENCEQEMASK, ccq->ceqe_mask) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_CEQIDVALID, ccq->ceq_id_valid) |
+ FIELD_PREP(IRDMA_CQPSQ_TPHEN, ccq->tph_en) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_AVOIDMEMCNFLCT, ccq->cq_uk.avoid_mem_cflct) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: CCQ_DESTROY WQE", DUMP_PREFIX_OFFSET, 16,
+ 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ irdma_get_cqp_reg_info(cqp, &val, &tail, &error);
+
+ if (post_sq) {
+ irdma_sc_cqp_post_sq(cqp);
+ ret_code = irdma_cqp_poll_registers(cqp, tail,
+ cqp->dev->hw_attrs.max_done_count);
+ }
+
+ cqp->process_cqp_sds = irdma_update_sds_noccq;
+
+ return ret_code;
+}
+
+/**
+ * irdma_sc_init_iw_hmc() - queries fpm values using cqp and populates hmc_info
+ * @dev : ptr to irdma_dev struct
+ * @hmc_fn_id: hmc function id
+ */
+enum irdma_status_code irdma_sc_init_iw_hmc(struct irdma_sc_dev *dev,
+ u8 hmc_fn_id)
+{
+ struct irdma_hmc_info *hmc_info;
+ struct irdma_hmc_fpm_misc *hmc_fpm_misc;
+ struct irdma_dma_mem query_fpm_mem;
+ enum irdma_status_code ret_code = 0;
+ u8 wait_type;
+
+ hmc_info = dev->hmc_info;
+ hmc_fpm_misc = &dev->hmc_fpm_misc;
+ query_fpm_mem.pa = dev->fpm_query_buf_pa;
+ query_fpm_mem.va = dev->fpm_query_buf;
+ hmc_info->hmc_fn_id = hmc_fn_id;
+ wait_type = (u8)IRDMA_CQP_WAIT_POLL_REGS;
+
+ ret_code = irdma_sc_query_fpm_val(dev->cqp, 0, hmc_info->hmc_fn_id,
+ &query_fpm_mem, true, wait_type);
+ if (ret_code)
+ return ret_code;
+
+ /* parse the fpm_query_buf and fill hmc obj info */
+ ret_code = irdma_sc_parse_fpm_query_buf(dev, query_fpm_mem.va, hmc_info,
+ hmc_fpm_misc);
+
+ print_hex_dump_debug("HMC: QUERY FPM BUFFER", DUMP_PREFIX_OFFSET, 16,
+ 8, query_fpm_mem.va, IRDMA_QUERY_FPM_BUF_SIZE,
+ false);
+ return ret_code;
+}
+
+/**
+ * irdma_sc_cfg_iw_fpm() - commits hmc obj cnt values using cqp
+ * command and populates fpm base address in hmc_info
+ * @dev : ptr to irdma_dev struct
+ * @hmc_fn_id: hmc function id
+ */
+static enum irdma_status_code irdma_sc_cfg_iw_fpm(struct irdma_sc_dev *dev,
+ u8 hmc_fn_id)
+{
+ struct irdma_hmc_info *hmc_info;
+ struct irdma_hmc_obj_info *obj_info;
+ __le64 *buf;
+ struct irdma_dma_mem commit_fpm_mem;
+ enum irdma_status_code ret_code = 0;
+ u8 wait_type;
+
+ hmc_info = dev->hmc_info;
+ obj_info = hmc_info->hmc_obj;
+ buf = dev->fpm_commit_buf;
+
+ set_64bit_val(buf, 0, (u64)obj_info[IRDMA_HMC_IW_QP].cnt);
+ set_64bit_val(buf, 8, (u64)obj_info[IRDMA_HMC_IW_CQ].cnt);
+ set_64bit_val(buf, 16, (u64)0); /* RSRVD */
+ set_64bit_val(buf, 24, (u64)obj_info[IRDMA_HMC_IW_HTE].cnt);
+ set_64bit_val(buf, 32, (u64)obj_info[IRDMA_HMC_IW_ARP].cnt);
+ set_64bit_val(buf, 40, (u64)0); /* RSVD */
+ set_64bit_val(buf, 48, (u64)obj_info[IRDMA_HMC_IW_MR].cnt);
+ set_64bit_val(buf, 56, (u64)obj_info[IRDMA_HMC_IW_XF].cnt);
+ set_64bit_val(buf, 64, (u64)obj_info[IRDMA_HMC_IW_XFFL].cnt);
+ set_64bit_val(buf, 72, (u64)obj_info[IRDMA_HMC_IW_Q1].cnt);
+ set_64bit_val(buf, 80, (u64)obj_info[IRDMA_HMC_IW_Q1FL].cnt);
+ set_64bit_val(buf, 88,
+ (u64)obj_info[IRDMA_HMC_IW_TIMER].cnt);
+ set_64bit_val(buf, 96,
+ (u64)obj_info[IRDMA_HMC_IW_FSIMC].cnt);
+ set_64bit_val(buf, 104,
+ (u64)obj_info[IRDMA_HMC_IW_FSIAV].cnt);
+ set_64bit_val(buf, 112,
+ (u64)obj_info[IRDMA_HMC_IW_PBLE].cnt);
+ set_64bit_val(buf, 120, (u64)0); /* RSVD */
+ set_64bit_val(buf, 128, (u64)obj_info[IRDMA_HMC_IW_RRF].cnt);
+ set_64bit_val(buf, 136,
+ (u64)obj_info[IRDMA_HMC_IW_RRFFL].cnt);
+ set_64bit_val(buf, 144, (u64)obj_info[IRDMA_HMC_IW_HDR].cnt);
+ set_64bit_val(buf, 152, (u64)obj_info[IRDMA_HMC_IW_MD].cnt);
+ set_64bit_val(buf, 160,
+ (u64)obj_info[IRDMA_HMC_IW_OOISC].cnt);
+ set_64bit_val(buf, 168,
+ (u64)obj_info[IRDMA_HMC_IW_OOISCFFL].cnt);
+
+ commit_fpm_mem.pa = dev->fpm_commit_buf_pa;
+ commit_fpm_mem.va = dev->fpm_commit_buf;
+
+ wait_type = (u8)IRDMA_CQP_WAIT_POLL_REGS;
+ print_hex_dump_debug("HMC: COMMIT FPM BUFFER", DUMP_PREFIX_OFFSET, 16,
+ 8, commit_fpm_mem.va, IRDMA_COMMIT_FPM_BUF_SIZE,
+ false);
+ ret_code = irdma_sc_commit_fpm_val(dev->cqp, 0, hmc_info->hmc_fn_id,
+ &commit_fpm_mem, true, wait_type);
+ if (!ret_code)
+ ret_code = irdma_sc_parse_fpm_commit_buf(dev, dev->fpm_commit_buf,
+ hmc_info->hmc_obj,
+ &hmc_info->sd_table.sd_cnt);
+ print_hex_dump_debug("HMC: COMMIT FPM BUFFER", DUMP_PREFIX_OFFSET, 16,
+ 8, commit_fpm_mem.va, IRDMA_COMMIT_FPM_BUF_SIZE,
+ false);
+
+ return ret_code;
+}
+
+/**
+ * cqp_sds_wqe_fill - fill cqp wqe doe sd
+ * @cqp: struct for cqp hw
+ * @info: sd info for wqe
+ * @scratch: u64 saved to be used during cqp completion
+ */
+static enum irdma_status_code
+cqp_sds_wqe_fill(struct irdma_sc_cqp *cqp, struct irdma_update_sds_info *info,
+ u64 scratch)
+{
+ u64 data;
+ u64 hdr;
+ __le64 *wqe;
+ int mem_entries, wqe_entries;
+ struct irdma_dma_mem *sdbuf = &cqp->sdbuf;
+ u64 offset = 0;
+ u32 wqe_idx;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe_idx(cqp, scratch, &wqe_idx);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ wqe_entries = (info->cnt > 3) ? 3 : info->cnt;
+ mem_entries = info->cnt - wqe_entries;
+
+ if (mem_entries) {
+ offset = wqe_idx * IRDMA_UPDATE_SD_BUFF_SIZE;
+ memcpy(((char *)sdbuf->va + offset), &info->entry[3], mem_entries << 4);
+
+ data = (u64)sdbuf->pa + offset;
+ } else {
+ data = 0;
+ }
+ data |= FIELD_PREP(IRDMA_CQPSQ_UPESD_HMCFNID, info->hmc_fn_id);
+ set_64bit_val(wqe, 16, data);
+
+ switch (wqe_entries) {
+ case 3:
+ set_64bit_val(wqe, 48,
+ (FIELD_PREP(IRDMA_CQPSQ_UPESD_SDCMD, info->entry[2].cmd) |
+ FIELD_PREP(IRDMA_CQPSQ_UPESD_ENTRY_VALID, 1)));
+
+ set_64bit_val(wqe, 56, info->entry[2].data);
+ fallthrough;
+ case 2:
+ set_64bit_val(wqe, 32,
+ (FIELD_PREP(IRDMA_CQPSQ_UPESD_SDCMD, info->entry[1].cmd) |
+ FIELD_PREP(IRDMA_CQPSQ_UPESD_ENTRY_VALID, 1)));
+
+ set_64bit_val(wqe, 40, info->entry[1].data);
+ fallthrough;
+ case 1:
+ set_64bit_val(wqe, 0,
+ FIELD_PREP(IRDMA_CQPSQ_UPESD_SDCMD, info->entry[0].cmd));
+
+ set_64bit_val(wqe, 8, info->entry[0].data);
+ break;
+ default:
+ break;
+ }
+
+ hdr = FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_UPDATE_PE_SDS) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity) |
+ FIELD_PREP(IRDMA_CQPSQ_UPESD_ENTRY_COUNT, mem_entries);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ if (mem_entries)
+ print_hex_dump_debug("WQE: UPDATE_PE_SDS WQE Buffer",
+ DUMP_PREFIX_OFFSET, 16, 8,
+ (char *)sdbuf->va + offset,
+ mem_entries << 4, false);
+
+ print_hex_dump_debug("WQE: UPDATE_PE_SDS WQE", DUMP_PREFIX_OFFSET, 16,
+ 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+
+ return 0;
+}
+
+/**
+ * irdma_update_pe_sds - cqp wqe for sd
+ * @dev: ptr to irdma_dev struct
+ * @info: sd info for sd's
+ * @scratch: u64 saved to be used during cqp completion
+ */
+static enum irdma_status_code
+irdma_update_pe_sds(struct irdma_sc_dev *dev,
+ struct irdma_update_sds_info *info, u64 scratch)
+{
+ struct irdma_sc_cqp *cqp = dev->cqp;
+ enum irdma_status_code ret_code;
+
+ ret_code = cqp_sds_wqe_fill(cqp, info, scratch);
+ if (!ret_code)
+ irdma_sc_cqp_post_sq(cqp);
+
+ return ret_code;
+}
+
+/**
+ * irdma_update_sds_noccq - update sd before ccq created
+ * @dev: sc device struct
+ * @info: sd info for sd's
+ */
+enum irdma_status_code
+irdma_update_sds_noccq(struct irdma_sc_dev *dev,
+ struct irdma_update_sds_info *info)
+{
+ u32 error, val, tail;
+ struct irdma_sc_cqp *cqp = dev->cqp;
+ enum irdma_status_code ret_code;
+
+ ret_code = cqp_sds_wqe_fill(cqp, info, 0);
+ if (ret_code)
+ return ret_code;
+
+ irdma_get_cqp_reg_info(cqp, &val, &tail, &error);
+
+ irdma_sc_cqp_post_sq(cqp);
+ return irdma_cqp_poll_registers(cqp, tail,
+ cqp->dev->hw_attrs.max_done_count);
+}
+
+/**
+ * irdma_sc_static_hmc_pages_allocated - cqp wqe to allocate hmc pages
+ * @cqp: struct for cqp hw
+ * @scratch: u64 saved to be used during cqp completion
+ * @hmc_fn_id: hmc function id
+ * @post_sq: flag for cqp db to ring
+ * @poll_registers: flag to poll register for cqp completion
+ */
+enum irdma_status_code
+irdma_sc_static_hmc_pages_allocated(struct irdma_sc_cqp *cqp, u64 scratch,
+ u8 hmc_fn_id, bool post_sq,
+ bool poll_registers)
+{
+ u64 hdr;
+ __le64 *wqe;
+ u32 tail, val, error;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMA_SHMC_PAGE_ALLOCATED_HMC_FN_ID, hmc_fn_id));
+
+ hdr = FIELD_PREP(IRDMA_CQPSQ_OPCODE,
+ IRDMA_CQP_OP_SHMC_PAGES_ALLOCATED) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("WQE: SHMC_PAGES_ALLOCATED WQE",
+ DUMP_PREFIX_OFFSET, 16, 8, wqe,
+ IRDMA_CQP_WQE_SIZE * 8, false);
+ irdma_get_cqp_reg_info(cqp, &val, &tail, &error);
+
+ if (post_sq) {
+ irdma_sc_cqp_post_sq(cqp);
+ if (poll_registers)
+ /* check for cqp sq tail update */
+ return irdma_cqp_poll_registers(cqp, tail,
+ cqp->dev->hw_attrs.max_done_count);
+ else
+ return irdma_sc_poll_for_cqp_op_done(cqp,
+ IRDMA_CQP_OP_SHMC_PAGES_ALLOCATED,
+ NULL);
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_cqp_ring_full - check if cqp ring is full
+ * @cqp: struct for cqp hw
+ */
+static bool irdma_cqp_ring_full(struct irdma_sc_cqp *cqp)
+{
+ return IRDMA_RING_FULL_ERR(cqp->sq_ring);
+}
+
+/**
+ * irdma_est_sd - returns approximate number of SDs for HMC
+ * @dev: sc device struct
+ * @hmc_info: hmc structure, size and count for HMC objects
+ */
+static u32 irdma_est_sd(struct irdma_sc_dev *dev,
+ struct irdma_hmc_info *hmc_info)
+{
+ int i;
+ u64 size = 0;
+ u64 sd;
+
+ for (i = IRDMA_HMC_IW_QP; i < IRDMA_HMC_IW_MAX; i++)
+ if (i != IRDMA_HMC_IW_PBLE)
+ size += round_up(hmc_info->hmc_obj[i].cnt *
+ hmc_info->hmc_obj[i].size, 512);
+ size += round_up(hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt *
+ hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].size, 512);
+ if (size & 0x1FFFFF)
+ sd = (size >> 21) + 1; /* add 1 for remainder */
+ else
+ sd = size >> 21;
+ if (sd > 0xFFFFFFFF) {
+ ibdev_dbg(to_ibdev(dev), "HMC: sd overflow[%lld]\n", sd);
+ sd = 0xFFFFFFFF - 1;
+ }
+
+ return (u32)sd;
+}
+
+/**
+ * irdma_sc_query_rdma_features_done - poll cqp for query features done
+ * @cqp: struct for cqp hw
+ */
+static enum irdma_status_code
+irdma_sc_query_rdma_features_done(struct irdma_sc_cqp *cqp)
+{
+ return irdma_sc_poll_for_cqp_op_done(cqp,
+ IRDMA_CQP_OP_QUERY_RDMA_FEATURES,
+ NULL);
+}
+
+/**
+ * irdma_sc_query_rdma_features - query RDMA features and FW ver
+ * @cqp: struct for cqp hw
+ * @buf: buffer to hold query info
+ * @scratch: u64 saved to be used during cqp completion
+ */
+static enum irdma_status_code
+irdma_sc_query_rdma_features(struct irdma_sc_cqp *cqp,
+ struct irdma_dma_mem *buf, u64 scratch)
+{
+ __le64 *wqe;
+ u64 temp;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ temp = buf->pa;
+ set_64bit_val(wqe, 32, temp);
+
+ temp = FIELD_PREP(IRDMA_CQPSQ_QUERY_RDMA_FEATURES_WQEVALID,
+ cqp->polarity) |
+ FIELD_PREP(IRDMA_CQPSQ_QUERY_RDMA_FEATURES_BUF_LEN, buf->size) |
+ FIELD_PREP(IRDMA_CQPSQ_UP_OP, IRDMA_CQP_OP_QUERY_RDMA_FEATURES);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, temp);
+
+ print_hex_dump_debug("WQE: QUERY RDMA FEATURES", DUMP_PREFIX_OFFSET,
+ 16, 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_get_rdma_features - get RDMA features
+ * @dev: sc device struct
+ */
+enum irdma_status_code irdma_get_rdma_features(struct irdma_sc_dev *dev)
+{
+ enum irdma_status_code ret_code;
+ struct irdma_dma_mem feat_buf;
+ u64 temp;
+ u16 byte_idx, feat_type, feat_cnt, feat_idx;
+
+ feat_buf.size = ALIGN(IRDMA_FEATURE_BUF_SIZE,
+ IRDMA_FEATURE_BUF_ALIGNMENT);
+ feat_buf.va = dma_alloc_coherent(dev->hw->device, feat_buf.size,
+ &feat_buf.pa, GFP_KERNEL);
+ if (!feat_buf.va)
+ return IRDMA_ERR_NO_MEMORY;
+
+ ret_code = irdma_sc_query_rdma_features(dev->cqp, &feat_buf, 0);
+ if (!ret_code)
+ ret_code = irdma_sc_query_rdma_features_done(dev->cqp);
+ if (ret_code)
+ goto exit;
+
+ get_64bit_val(feat_buf.va, 0, &temp);
+ feat_cnt = (u16)FIELD_GET(IRDMA_FEATURE_CNT, temp);
+ if (feat_cnt < 2) {
+ ret_code = IRDMA_ERR_INVALID_FEAT_CNT;
+ goto exit;
+ } else if (feat_cnt > IRDMA_MAX_FEATURES) {
+ ibdev_dbg(to_ibdev(dev),
+ "DEV: feature buf size insufficient, retrying with larger buffer\n");
+ dma_free_coherent(dev->hw->device, feat_buf.size, feat_buf.va,
+ feat_buf.pa);
+ feat_buf.va = NULL;
+ feat_buf.size = ALIGN(8 * feat_cnt,
+ IRDMA_FEATURE_BUF_ALIGNMENT);
+ feat_buf.va = dma_alloc_coherent(dev->hw->device,
+ feat_buf.size, &feat_buf.pa,
+ GFP_KERNEL);
+ if (!feat_buf.va)
+ return IRDMA_ERR_NO_MEMORY;
+
+ ret_code = irdma_sc_query_rdma_features(dev->cqp, &feat_buf, 0);
+ if (!ret_code)
+ ret_code = irdma_sc_query_rdma_features_done(dev->cqp);
+ if (ret_code)
+ goto exit;
+
+ get_64bit_val(feat_buf.va, 0, &temp);
+ feat_cnt = (u16)FIELD_GET(IRDMA_FEATURE_CNT, temp);
+ if (feat_cnt < 2) {
+ ret_code = IRDMA_ERR_INVALID_FEAT_CNT;
+ goto exit;
+ }
+ }
+
+ print_hex_dump_debug("WQE: QUERY RDMA FEATURES", DUMP_PREFIX_OFFSET,
+ 16, 8, feat_buf.va, feat_cnt * 8, false);
+
+ for (byte_idx = 0, feat_idx = 0; feat_idx < min(feat_cnt, (u16)IRDMA_MAX_FEATURES);
+ feat_idx++, byte_idx += 8) {
+ get_64bit_val(feat_buf.va, byte_idx, &temp);
+ feat_type = FIELD_GET(IRDMA_FEATURE_TYPE, temp);
+ if (feat_type >= IRDMA_MAX_FEATURES) {
+ ibdev_dbg(to_ibdev(dev),
+ "DEV: found unrecognized feature type %d\n",
+ feat_type);
+ continue;
+ }
+ dev->feature_info[feat_type] = temp;
+ }
+exit:
+ dma_free_coherent(dev->hw->device, feat_buf.size, feat_buf.va,
+ feat_buf.pa);
+ feat_buf.va = NULL;
+ return ret_code;
+}
+
+static u32 irdma_q1_cnt(struct irdma_sc_dev *dev,
+ struct irdma_hmc_info *hmc_info, u32 qpwanted)
+{
+ u32 q1_cnt;
+
+ if (dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1) {
+ q1_cnt = roundup_pow_of_two(dev->hw_attrs.max_hw_ird * 2 * qpwanted);
+ } else {
+ if (dev->cqp->protocol_used != IRDMA_IWARP_PROTOCOL_ONLY)
+ q1_cnt = roundup_pow_of_two(dev->hw_attrs.max_hw_ird * 2 * qpwanted + 512);
+ else
+ q1_cnt = dev->hw_attrs.max_hw_ird * 2 * qpwanted;
+ }
+
+ return q1_cnt;
+}
+
+static void cfg_fpm_value_gen_1(struct irdma_sc_dev *dev,
+ struct irdma_hmc_info *hmc_info, u32 qpwanted)
+{
+ hmc_info->hmc_obj[IRDMA_HMC_IW_XF].cnt = roundup_pow_of_two(qpwanted * dev->hw_attrs.max_hw_wqes);
+}
+
+static void cfg_fpm_value_gen_2(struct irdma_sc_dev *dev,
+ struct irdma_hmc_info *hmc_info, u32 qpwanted)
+{
+ struct irdma_hmc_fpm_misc *hmc_fpm_misc = &dev->hmc_fpm_misc;
+
+ hmc_info->hmc_obj[IRDMA_HMC_IW_XF].cnt =
+ 4 * hmc_fpm_misc->xf_block_size * qpwanted;
+
+ hmc_info->hmc_obj[IRDMA_HMC_IW_HDR].cnt = qpwanted;
+
+ if (hmc_info->hmc_obj[IRDMA_HMC_IW_RRF].max_cnt)
+ hmc_info->hmc_obj[IRDMA_HMC_IW_RRF].cnt = 32 * qpwanted;
+ if (hmc_info->hmc_obj[IRDMA_HMC_IW_RRFFL].max_cnt)
+ hmc_info->hmc_obj[IRDMA_HMC_IW_RRFFL].cnt =
+ hmc_info->hmc_obj[IRDMA_HMC_IW_RRF].cnt /
+ hmc_fpm_misc->rrf_block_size;
+ if (hmc_info->hmc_obj[IRDMA_HMC_IW_OOISC].max_cnt)
+ hmc_info->hmc_obj[IRDMA_HMC_IW_OOISC].cnt = 32 * qpwanted;
+ if (hmc_info->hmc_obj[IRDMA_HMC_IW_OOISCFFL].max_cnt)
+ hmc_info->hmc_obj[IRDMA_HMC_IW_OOISCFFL].cnt =
+ hmc_info->hmc_obj[IRDMA_HMC_IW_OOISC].cnt /
+ hmc_fpm_misc->ooiscf_block_size;
+}
+
+/**
+ * irdma_cfg_fpm_val - configure HMC objects
+ * @dev: sc device struct
+ * @qp_count: desired qp count
+ */
+enum irdma_status_code irdma_cfg_fpm_val(struct irdma_sc_dev *dev, u32 qp_count)
+{
+ struct irdma_virt_mem virt_mem;
+ u32 i, mem_size;
+ u32 qpwanted, mrwanted, pblewanted;
+ u32 powerof2, hte;
+ u32 sd_needed;
+ u32 sd_diff;
+ u32 loop_count = 0;
+ struct irdma_hmc_info *hmc_info;
+ struct irdma_hmc_fpm_misc *hmc_fpm_misc;
+ enum irdma_status_code ret_code = 0;
+
+ hmc_info = dev->hmc_info;
+ hmc_fpm_misc = &dev->hmc_fpm_misc;
+
+ ret_code = irdma_sc_init_iw_hmc(dev, dev->hmc_fn_id);
+ if (ret_code) {
+ ibdev_dbg(to_ibdev(dev),
+ "HMC: irdma_sc_init_iw_hmc returned error_code = %d\n",
+ ret_code);
+ return ret_code;
+ }
+
+ for (i = IRDMA_HMC_IW_QP; i < IRDMA_HMC_IW_MAX; i++)
+ hmc_info->hmc_obj[i].cnt = hmc_info->hmc_obj[i].max_cnt;
+ sd_needed = irdma_est_sd(dev, hmc_info);
+ ibdev_dbg(to_ibdev(dev),
+ "HMC: FW max resources sd_needed[%08d] first_sd_index[%04d]\n",
+ sd_needed, hmc_info->first_sd_index);
+ ibdev_dbg(to_ibdev(dev), "HMC: sd count %d where max sd is %d\n",
+ hmc_info->sd_table.sd_cnt, hmc_fpm_misc->max_sds);
+
+ qpwanted = min(qp_count, hmc_info->hmc_obj[IRDMA_HMC_IW_QP].max_cnt);
+
+ powerof2 = 1;
+ while (powerof2 <= qpwanted)
+ powerof2 *= 2;
+ powerof2 /= 2;
+ qpwanted = powerof2;
+
+ mrwanted = hmc_info->hmc_obj[IRDMA_HMC_IW_MR].max_cnt;
+ pblewanted = hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].max_cnt;
+
+ ibdev_dbg(to_ibdev(dev),
+ "HMC: req_qp=%d max_sd=%d, max_qp = %d, max_cq=%d, max_mr=%d, max_pble=%d, mc=%d, av=%d\n",
+ qp_count, hmc_fpm_misc->max_sds,
+ hmc_info->hmc_obj[IRDMA_HMC_IW_QP].max_cnt,
+ hmc_info->hmc_obj[IRDMA_HMC_IW_CQ].max_cnt,
+ hmc_info->hmc_obj[IRDMA_HMC_IW_MR].max_cnt,
+ hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].max_cnt,
+ hmc_info->hmc_obj[IRDMA_HMC_IW_FSIMC].max_cnt,
+ hmc_info->hmc_obj[IRDMA_HMC_IW_FSIAV].max_cnt);
+ hmc_info->hmc_obj[IRDMA_HMC_IW_FSIMC].cnt =
+ hmc_info->hmc_obj[IRDMA_HMC_IW_FSIMC].max_cnt;
+ hmc_info->hmc_obj[IRDMA_HMC_IW_FSIAV].cnt =
+ hmc_info->hmc_obj[IRDMA_HMC_IW_FSIAV].max_cnt;
+ hmc_info->hmc_obj[IRDMA_HMC_IW_ARP].cnt =
+ hmc_info->hmc_obj[IRDMA_HMC_IW_ARP].max_cnt;
+
+ hmc_info->hmc_obj[IRDMA_HMC_IW_APBVT_ENTRY].cnt = 1;
+
+ while (irdma_q1_cnt(dev, hmc_info, qpwanted) > hmc_info->hmc_obj[IRDMA_HMC_IW_Q1].max_cnt)
+ qpwanted /= 2;
+
+ do {
+ ++loop_count;
+ hmc_info->hmc_obj[IRDMA_HMC_IW_QP].cnt = qpwanted;
+ hmc_info->hmc_obj[IRDMA_HMC_IW_CQ].cnt =
+ min(2 * qpwanted, hmc_info->hmc_obj[IRDMA_HMC_IW_CQ].cnt);
+ hmc_info->hmc_obj[IRDMA_HMC_IW_RESERVED].cnt = 0; /* Reserved */
+ hmc_info->hmc_obj[IRDMA_HMC_IW_MR].cnt = mrwanted;
+
+ hte = round_up(qpwanted + hmc_info->hmc_obj[IRDMA_HMC_IW_FSIMC].cnt, 512);
+ powerof2 = 1;
+ while (powerof2 < hte)
+ powerof2 *= 2;
+ hmc_info->hmc_obj[IRDMA_HMC_IW_HTE].cnt =
+ powerof2 * hmc_fpm_misc->ht_multiplier;
+ if (dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1)
+ cfg_fpm_value_gen_1(dev, hmc_info, qpwanted);
+ else
+ cfg_fpm_value_gen_2(dev, hmc_info, qpwanted);
+
+ hmc_info->hmc_obj[IRDMA_HMC_IW_Q1].cnt = irdma_q1_cnt(dev, hmc_info, qpwanted);
+ hmc_info->hmc_obj[IRDMA_HMC_IW_XFFL].cnt =
+ hmc_info->hmc_obj[IRDMA_HMC_IW_XF].cnt / hmc_fpm_misc->xf_block_size;
+ hmc_info->hmc_obj[IRDMA_HMC_IW_Q1FL].cnt =
+ hmc_info->hmc_obj[IRDMA_HMC_IW_Q1].cnt / hmc_fpm_misc->q1_block_size;
+ hmc_info->hmc_obj[IRDMA_HMC_IW_TIMER].cnt =
+ (round_up(qpwanted, 512) / 512 + 1) * hmc_fpm_misc->timer_bucket;
+
+ hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt = pblewanted;
+ sd_needed = irdma_est_sd(dev, hmc_info);
+ ibdev_dbg(to_ibdev(dev),
+ "HMC: sd_needed = %d, hmc_fpm_misc->max_sds=%d, mrwanted=%d, pblewanted=%d qpwanted=%d\n",
+ sd_needed, hmc_fpm_misc->max_sds, mrwanted,
+ pblewanted, qpwanted);
+
+ /* Do not reduce resources further. All objects fit with max SDs */
+ if (sd_needed <= hmc_fpm_misc->max_sds)
+ break;
+
+ sd_diff = sd_needed - hmc_fpm_misc->max_sds;
+ if (sd_diff > 128) {
+ if (qpwanted > 128 && sd_diff > 144)
+ qpwanted /= 2;
+ mrwanted /= 2;
+ pblewanted /= 2;
+ continue;
+ }
+ if (dev->cqp->hmc_profile != IRDMA_HMC_PROFILE_FAVOR_VF &&
+ pblewanted > (512 * FPM_MULTIPLIER * sd_diff)) {
+ pblewanted -= 256 * FPM_MULTIPLIER * sd_diff;
+ continue;
+ } else if (pblewanted > (100 * FPM_MULTIPLIER)) {
+ pblewanted -= 10 * FPM_MULTIPLIER;
+ } else if (pblewanted > FPM_MULTIPLIER) {
+ pblewanted -= FPM_MULTIPLIER;
+ } else if (qpwanted <= 128) {
+ if (hmc_info->hmc_obj[IRDMA_HMC_IW_FSIMC].cnt > 256)
+ hmc_info->hmc_obj[IRDMA_HMC_IW_FSIMC].cnt /= 2;
+ if (hmc_info->hmc_obj[IRDMA_HMC_IW_FSIAV].cnt > 256)
+ hmc_info->hmc_obj[IRDMA_HMC_IW_FSIAV].cnt /= 2;
+ }
+ if (mrwanted > FPM_MULTIPLIER)
+ mrwanted -= FPM_MULTIPLIER;
+ if (!(loop_count % 10) && qpwanted > 128) {
+ qpwanted /= 2;
+ if (hmc_info->hmc_obj[IRDMA_HMC_IW_FSIAV].cnt > 256)
+ hmc_info->hmc_obj[IRDMA_HMC_IW_FSIAV].cnt /= 2;
+ }
+ } while (loop_count < 2000);
+
+ if (sd_needed > hmc_fpm_misc->max_sds) {
+ ibdev_dbg(to_ibdev(dev),
+ "HMC: cfg_fpm failed loop_cnt=%d, sd_needed=%d, max sd count %d\n",
+ loop_count, sd_needed, hmc_info->sd_table.sd_cnt);
+ return IRDMA_ERR_CFG;
+ }
+
+ if (loop_count > 1 && sd_needed < hmc_fpm_misc->max_sds) {
+ pblewanted += (hmc_fpm_misc->max_sds - sd_needed) * 256 *
+ FPM_MULTIPLIER;
+ hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt = pblewanted;
+ sd_needed = irdma_est_sd(dev, hmc_info);
+ }
+
+ ibdev_dbg(to_ibdev(dev),
+ "HMC: loop_cnt=%d, sd_needed=%d, qpcnt = %d, cqcnt=%d, mrcnt=%d, pblecnt=%d, mc=%d, ah=%d, max sd count %d, first sd index %d\n",
+ loop_count, sd_needed,
+ hmc_info->hmc_obj[IRDMA_HMC_IW_QP].cnt,
+ hmc_info->hmc_obj[IRDMA_HMC_IW_CQ].cnt,
+ hmc_info->hmc_obj[IRDMA_HMC_IW_MR].cnt,
+ hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt,
+ hmc_info->hmc_obj[IRDMA_HMC_IW_FSIMC].cnt,
+ hmc_info->hmc_obj[IRDMA_HMC_IW_FSIAV].cnt,
+ hmc_info->sd_table.sd_cnt, hmc_info->first_sd_index);
+
+ ret_code = irdma_sc_cfg_iw_fpm(dev, dev->hmc_fn_id);
+ if (ret_code) {
+ ibdev_dbg(to_ibdev(dev),
+ "HMC: cfg_iw_fpm returned error_code[x%08X]\n",
+ readl(dev->hw_regs[IRDMA_CQPERRCODES]));
+ return ret_code;
+ }
+
+ mem_size = sizeof(struct irdma_hmc_sd_entry) *
+ (hmc_info->sd_table.sd_cnt + hmc_info->first_sd_index + 1);
+ virt_mem.size = mem_size;
+ virt_mem.va = kzalloc(virt_mem.size, GFP_KERNEL);
+ if (!virt_mem.va) {
+ ibdev_dbg(to_ibdev(dev),
+ "HMC: failed to allocate memory for sd_entry buffer\n");
+ return IRDMA_ERR_NO_MEMORY;
+ }
+ hmc_info->sd_table.sd_entry = virt_mem.va;
+
+ return ret_code;
+}
+
+/**
+ * irdma_exec_cqp_cmd - execute cqp cmd when wqe are available
+ * @dev: rdma device
+ * @pcmdinfo: cqp command info
+ */
+static enum irdma_status_code irdma_exec_cqp_cmd(struct irdma_sc_dev *dev,
+ struct cqp_cmds_info *pcmdinfo)
+{
+ enum irdma_status_code status;
+ struct irdma_dma_mem val_mem;
+ bool alloc = false;
+
+ dev->cqp_cmd_stats[pcmdinfo->cqp_cmd]++;
+ switch (pcmdinfo->cqp_cmd) {
+ case IRDMA_OP_CEQ_DESTROY:
+ status = irdma_sc_ceq_destroy(pcmdinfo->in.u.ceq_destroy.ceq,
+ pcmdinfo->in.u.ceq_destroy.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_AEQ_DESTROY:
+ status = irdma_sc_aeq_destroy(pcmdinfo->in.u.aeq_destroy.aeq,
+ pcmdinfo->in.u.aeq_destroy.scratch,
+ pcmdinfo->post_sq);
+
+ break;
+ case IRDMA_OP_CEQ_CREATE:
+ status = irdma_sc_ceq_create(pcmdinfo->in.u.ceq_create.ceq,
+ pcmdinfo->in.u.ceq_create.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_AEQ_CREATE:
+ status = irdma_sc_aeq_create(pcmdinfo->in.u.aeq_create.aeq,
+ pcmdinfo->in.u.aeq_create.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_QP_UPLOAD_CONTEXT:
+ status = irdma_sc_qp_upload_context(pcmdinfo->in.u.qp_upload_context.dev,
+ &pcmdinfo->in.u.qp_upload_context.info,
+ pcmdinfo->in.u.qp_upload_context.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_CQ_CREATE:
+ status = irdma_sc_cq_create(pcmdinfo->in.u.cq_create.cq,
+ pcmdinfo->in.u.cq_create.scratch,
+ pcmdinfo->in.u.cq_create.check_overflow,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_CQ_MODIFY:
+ status = irdma_sc_cq_modify(pcmdinfo->in.u.cq_modify.cq,
+ &pcmdinfo->in.u.cq_modify.info,
+ pcmdinfo->in.u.cq_modify.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_CQ_DESTROY:
+ status = irdma_sc_cq_destroy(pcmdinfo->in.u.cq_destroy.cq,
+ pcmdinfo->in.u.cq_destroy.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_QP_FLUSH_WQES:
+ status = irdma_sc_qp_flush_wqes(pcmdinfo->in.u.qp_flush_wqes.qp,
+ &pcmdinfo->in.u.qp_flush_wqes.info,
+ pcmdinfo->in.u.qp_flush_wqes.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_GEN_AE:
+ status = irdma_sc_gen_ae(pcmdinfo->in.u.gen_ae.qp,
+ &pcmdinfo->in.u.gen_ae.info,
+ pcmdinfo->in.u.gen_ae.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_MANAGE_PUSH_PAGE:
+ status = irdma_sc_manage_push_page(pcmdinfo->in.u.manage_push_page.cqp,
+ &pcmdinfo->in.u.manage_push_page.info,
+ pcmdinfo->in.u.manage_push_page.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_UPDATE_PE_SDS:
+ status = irdma_update_pe_sds(pcmdinfo->in.u.update_pe_sds.dev,
+ &pcmdinfo->in.u.update_pe_sds.info,
+ pcmdinfo->in.u.update_pe_sds.scratch);
+ break;
+ case IRDMA_OP_MANAGE_HMC_PM_FUNC_TABLE:
+ /* switch to calling through the call table */
+ status =
+ irdma_sc_manage_hmc_pm_func_table(pcmdinfo->in.u.manage_hmc_pm.dev->cqp,
+ &pcmdinfo->in.u.manage_hmc_pm.info,
+ pcmdinfo->in.u.manage_hmc_pm.scratch,
+ true);
+ break;
+ case IRDMA_OP_SUSPEND:
+ status = irdma_sc_suspend_qp(pcmdinfo->in.u.suspend_resume.cqp,
+ pcmdinfo->in.u.suspend_resume.qp,
+ pcmdinfo->in.u.suspend_resume.scratch);
+ break;
+ case IRDMA_OP_RESUME:
+ status = irdma_sc_resume_qp(pcmdinfo->in.u.suspend_resume.cqp,
+ pcmdinfo->in.u.suspend_resume.qp,
+ pcmdinfo->in.u.suspend_resume.scratch);
+ break;
+ case IRDMA_OP_QUERY_FPM_VAL:
+ val_mem.pa = pcmdinfo->in.u.query_fpm_val.fpm_val_pa;
+ val_mem.va = pcmdinfo->in.u.query_fpm_val.fpm_val_va;
+ status = irdma_sc_query_fpm_val(pcmdinfo->in.u.query_fpm_val.cqp,
+ pcmdinfo->in.u.query_fpm_val.scratch,
+ pcmdinfo->in.u.query_fpm_val.hmc_fn_id,
+ &val_mem, true, IRDMA_CQP_WAIT_EVENT);
+ break;
+ case IRDMA_OP_COMMIT_FPM_VAL:
+ val_mem.pa = pcmdinfo->in.u.commit_fpm_val.fpm_val_pa;
+ val_mem.va = pcmdinfo->in.u.commit_fpm_val.fpm_val_va;
+ status = irdma_sc_commit_fpm_val(pcmdinfo->in.u.commit_fpm_val.cqp,
+ pcmdinfo->in.u.commit_fpm_val.scratch,
+ pcmdinfo->in.u.commit_fpm_val.hmc_fn_id,
+ &val_mem,
+ true,
+ IRDMA_CQP_WAIT_EVENT);
+ break;
+ case IRDMA_OP_STATS_ALLOCATE:
+ alloc = true;
+ fallthrough;
+ case IRDMA_OP_STATS_FREE:
+ status = irdma_sc_manage_stats_inst(pcmdinfo->in.u.stats_manage.cqp,
+ &pcmdinfo->in.u.stats_manage.info,
+ alloc,
+ pcmdinfo->in.u.stats_manage.scratch);
+ break;
+ case IRDMA_OP_STATS_GATHER:
+ status = irdma_sc_gather_stats(pcmdinfo->in.u.stats_gather.cqp,
+ &pcmdinfo->in.u.stats_gather.info,
+ pcmdinfo->in.u.stats_gather.scratch);
+ break;
+ case IRDMA_OP_WS_MODIFY_NODE:
+ status = irdma_sc_manage_ws_node(pcmdinfo->in.u.ws_node.cqp,
+ &pcmdinfo->in.u.ws_node.info,
+ IRDMA_MODIFY_NODE,
+ pcmdinfo->in.u.ws_node.scratch);
+ break;
+ case IRDMA_OP_WS_DELETE_NODE:
+ status = irdma_sc_manage_ws_node(pcmdinfo->in.u.ws_node.cqp,
+ &pcmdinfo->in.u.ws_node.info,
+ IRDMA_DEL_NODE,
+ pcmdinfo->in.u.ws_node.scratch);
+ break;
+ case IRDMA_OP_WS_ADD_NODE:
+ status = irdma_sc_manage_ws_node(pcmdinfo->in.u.ws_node.cqp,
+ &pcmdinfo->in.u.ws_node.info,
+ IRDMA_ADD_NODE,
+ pcmdinfo->in.u.ws_node.scratch);
+ break;
+ case IRDMA_OP_SET_UP_MAP:
+ status = irdma_sc_set_up_map(pcmdinfo->in.u.up_map.cqp,
+ &pcmdinfo->in.u.up_map.info,
+ pcmdinfo->in.u.up_map.scratch);
+ break;
+ case IRDMA_OP_QUERY_RDMA_FEATURES:
+ status = irdma_sc_query_rdma_features(pcmdinfo->in.u.query_rdma.cqp,
+ &pcmdinfo->in.u.query_rdma.query_buff_mem,
+ pcmdinfo->in.u.query_rdma.scratch);
+ break;
+ case IRDMA_OP_DELETE_ARP_CACHE_ENTRY:
+ status = irdma_sc_del_arp_cache_entry(pcmdinfo->in.u.del_arp_cache_entry.cqp,
+ pcmdinfo->in.u.del_arp_cache_entry.scratch,
+ pcmdinfo->in.u.del_arp_cache_entry.arp_index,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_MANAGE_APBVT_ENTRY:
+ status = irdma_sc_manage_apbvt_entry(pcmdinfo->in.u.manage_apbvt_entry.cqp,
+ &pcmdinfo->in.u.manage_apbvt_entry.info,
+ pcmdinfo->in.u.manage_apbvt_entry.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_MANAGE_QHASH_TABLE_ENTRY:
+ status = irdma_sc_manage_qhash_table_entry(pcmdinfo->in.u.manage_qhash_table_entry.cqp,
+ &pcmdinfo->in.u.manage_qhash_table_entry.info,
+ pcmdinfo->in.u.manage_qhash_table_entry.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_QP_MODIFY:
+ status = irdma_sc_qp_modify(pcmdinfo->in.u.qp_modify.qp,
+ &pcmdinfo->in.u.qp_modify.info,
+ pcmdinfo->in.u.qp_modify.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_QP_CREATE:
+ status = irdma_sc_qp_create(pcmdinfo->in.u.qp_create.qp,
+ &pcmdinfo->in.u.qp_create.info,
+ pcmdinfo->in.u.qp_create.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_QP_DESTROY:
+ status = irdma_sc_qp_destroy(pcmdinfo->in.u.qp_destroy.qp,
+ pcmdinfo->in.u.qp_destroy.scratch,
+ pcmdinfo->in.u.qp_destroy.remove_hash_idx,
+ pcmdinfo->in.u.qp_destroy.ignore_mw_bnd,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_ALLOC_STAG:
+ status = irdma_sc_alloc_stag(pcmdinfo->in.u.alloc_stag.dev,
+ &pcmdinfo->in.u.alloc_stag.info,
+ pcmdinfo->in.u.alloc_stag.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_MR_REG_NON_SHARED:
+ status = irdma_sc_mr_reg_non_shared(pcmdinfo->in.u.mr_reg_non_shared.dev,
+ &pcmdinfo->in.u.mr_reg_non_shared.info,
+ pcmdinfo->in.u.mr_reg_non_shared.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_DEALLOC_STAG:
+ status = irdma_sc_dealloc_stag(pcmdinfo->in.u.dealloc_stag.dev,
+ &pcmdinfo->in.u.dealloc_stag.info,
+ pcmdinfo->in.u.dealloc_stag.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_MW_ALLOC:
+ status = irdma_sc_mw_alloc(pcmdinfo->in.u.mw_alloc.dev,
+ &pcmdinfo->in.u.mw_alloc.info,
+ pcmdinfo->in.u.mw_alloc.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_ADD_ARP_CACHE_ENTRY:
+ status = irdma_sc_add_arp_cache_entry(pcmdinfo->in.u.add_arp_cache_entry.cqp,
+ &pcmdinfo->in.u.add_arp_cache_entry.info,
+ pcmdinfo->in.u.add_arp_cache_entry.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_ALLOC_LOCAL_MAC_ENTRY:
+ status = irdma_sc_alloc_local_mac_entry(pcmdinfo->in.u.alloc_local_mac_entry.cqp,
+ pcmdinfo->in.u.alloc_local_mac_entry.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_ADD_LOCAL_MAC_ENTRY:
+ status = irdma_sc_add_local_mac_entry(pcmdinfo->in.u.add_local_mac_entry.cqp,
+ &pcmdinfo->in.u.add_local_mac_entry.info,
+ pcmdinfo->in.u.add_local_mac_entry.scratch,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_DELETE_LOCAL_MAC_ENTRY:
+ status = irdma_sc_del_local_mac_entry(pcmdinfo->in.u.del_local_mac_entry.cqp,
+ pcmdinfo->in.u.del_local_mac_entry.scratch,
+ pcmdinfo->in.u.del_local_mac_entry.entry_idx,
+ pcmdinfo->in.u.del_local_mac_entry.ignore_ref_count,
+ pcmdinfo->post_sq);
+ break;
+ case IRDMA_OP_AH_CREATE:
+ status = irdma_sc_create_ah(pcmdinfo->in.u.ah_create.cqp,
+ &pcmdinfo->in.u.ah_create.info,
+ pcmdinfo->in.u.ah_create.scratch);
+ break;
+ case IRDMA_OP_AH_DESTROY:
+ status = irdma_sc_destroy_ah(pcmdinfo->in.u.ah_destroy.cqp,
+ &pcmdinfo->in.u.ah_destroy.info,
+ pcmdinfo->in.u.ah_destroy.scratch);
+ break;
+ case IRDMA_OP_MC_CREATE:
+ status = irdma_sc_create_mcast_grp(pcmdinfo->in.u.mc_create.cqp,
+ &pcmdinfo->in.u.mc_create.info,
+ pcmdinfo->in.u.mc_create.scratch);
+ break;
+ case IRDMA_OP_MC_DESTROY:
+ status = irdma_sc_destroy_mcast_grp(pcmdinfo->in.u.mc_destroy.cqp,
+ &pcmdinfo->in.u.mc_destroy.info,
+ pcmdinfo->in.u.mc_destroy.scratch);
+ break;
+ case IRDMA_OP_MC_MODIFY:
+ status = irdma_sc_modify_mcast_grp(pcmdinfo->in.u.mc_modify.cqp,
+ &pcmdinfo->in.u.mc_modify.info,
+ pcmdinfo->in.u.mc_modify.scratch);
+ break;
+ default:
+ status = IRDMA_NOT_SUPPORTED;
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * irdma_process_cqp_cmd - process all cqp commands
+ * @dev: sc device struct
+ * @pcmdinfo: cqp command info
+ */
+enum irdma_status_code irdma_process_cqp_cmd(struct irdma_sc_dev *dev,
+ struct cqp_cmds_info *pcmdinfo)
+{
+ enum irdma_status_code status = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->cqp_lock, flags);
+ if (list_empty(&dev->cqp_cmd_head) && !irdma_cqp_ring_full(dev->cqp))
+ status = irdma_exec_cqp_cmd(dev, pcmdinfo);
+ else
+ list_add_tail(&pcmdinfo->cqp_cmd_entry, &dev->cqp_cmd_head);
+ spin_unlock_irqrestore(&dev->cqp_lock, flags);
+ return status;
+}
+
+/**
+ * irdma_process_bh - called from tasklet for cqp list
+ * @dev: sc device struct
+ */
+enum irdma_status_code irdma_process_bh(struct irdma_sc_dev *dev)
+{
+ enum irdma_status_code status = 0;
+ struct cqp_cmds_info *pcmdinfo;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->cqp_lock, flags);
+ while (!list_empty(&dev->cqp_cmd_head) &&
+ !irdma_cqp_ring_full(dev->cqp)) {
+ pcmdinfo = (struct cqp_cmds_info *)irdma_remove_cqp_head(dev);
+ status = irdma_exec_cqp_cmd(dev, pcmdinfo);
+ if (status)
+ break;
+ }
+ spin_unlock_irqrestore(&dev->cqp_lock, flags);
+ return status;
+}
+
+/**
+ * irdma_cfg_aeq- Configure AEQ interrupt
+ * @dev: pointer to the device structure
+ * @idx: vector index
+ * @enable: True to enable, False disables
+ */
+void irdma_cfg_aeq(struct irdma_sc_dev *dev, u32 idx, bool enable)
+{
+ u32 reg_val;
+
+ reg_val = FIELD_PREP(IRDMA_PFINT_AEQCTL_CAUSE_ENA, enable) |
+ FIELD_PREP(IRDMA_PFINT_AEQCTL_MSIX_INDX, idx) |
+ FIELD_PREP(IRDMA_PFINT_AEQCTL_ITR_INDX, 3);
+ writel(reg_val, dev->hw_regs[IRDMA_PFINT_AEQCTL]);
+}
+
+/**
+ * sc_vsi_update_stats - Update statistics
+ * @vsi: sc_vsi instance to update
+ */
+void sc_vsi_update_stats(struct irdma_sc_vsi *vsi)
+{
+ struct irdma_gather_stats *gather_stats;
+ struct irdma_gather_stats *last_gather_stats;
+
+ gather_stats = vsi->pestat->gather_info.gather_stats_va;
+ last_gather_stats = vsi->pestat->gather_info.last_gather_stats_va;
+ irdma_update_stats(&vsi->pestat->hw_stats, gather_stats,
+ last_gather_stats);
+}
+
+/**
+ * irdma_wait_pe_ready - Check if firmware is ready
+ * @dev: provides access to registers
+ */
+static int irdma_wait_pe_ready(struct irdma_sc_dev *dev)
+{
+ u32 statuscpu0;
+ u32 statuscpu1;
+ u32 statuscpu2;
+ u32 retrycount = 0;
+
+ do {
+ statuscpu0 = readl(dev->hw_regs[IRDMA_GLPE_CPUSTATUS0]);
+ statuscpu1 = readl(dev->hw_regs[IRDMA_GLPE_CPUSTATUS1]);
+ statuscpu2 = readl(dev->hw_regs[IRDMA_GLPE_CPUSTATUS2]);
+ if (statuscpu0 == 0x80 && statuscpu1 == 0x80 &&
+ statuscpu2 == 0x80)
+ return 0;
+ mdelay(1000);
+ } while (retrycount++ < dev->hw_attrs.max_pe_ready_count);
+ return -1;
+}
+
+static inline void irdma_sc_init_hw(struct irdma_sc_dev *dev)
+{
+ switch (dev->hw_attrs.uk_attrs.hw_rev) {
+ case IRDMA_GEN_1:
+ i40iw_init_hw(dev);
+ break;
+ case IRDMA_GEN_2:
+ icrdma_init_hw(dev);
+ break;
+ }
+}
+
+/**
+ * irdma_sc_dev_init - Initialize control part of device
+ * @ver: version
+ * @dev: Device pointer
+ * @info: Device init info
+ */
+enum irdma_status_code irdma_sc_dev_init(enum irdma_vers ver,
+ struct irdma_sc_dev *dev,
+ struct irdma_device_init_info *info)
+{
+ u32 val;
+ enum irdma_status_code ret_code = 0;
+ u8 db_size;
+
+ INIT_LIST_HEAD(&dev->cqp_cmd_head); /* for CQP command backlog */
+ mutex_init(&dev->ws_mutex);
+ dev->hmc_fn_id = info->hmc_fn_id;
+ dev->fpm_query_buf_pa = info->fpm_query_buf_pa;
+ dev->fpm_query_buf = info->fpm_query_buf;
+ dev->fpm_commit_buf_pa = info->fpm_commit_buf_pa;
+ dev->fpm_commit_buf = info->fpm_commit_buf;
+ dev->hw = info->hw;
+ dev->hw->hw_addr = info->bar0;
+ /* Setup the hardware limits, hmc may limit further */
+ dev->hw_attrs.min_hw_qp_id = IRDMA_MIN_IW_QP_ID;
+ dev->hw_attrs.min_hw_aeq_size = IRDMA_MIN_AEQ_ENTRIES;
+ dev->hw_attrs.max_hw_aeq_size = IRDMA_MAX_AEQ_ENTRIES;
+ dev->hw_attrs.min_hw_ceq_size = IRDMA_MIN_CEQ_ENTRIES;
+ dev->hw_attrs.max_hw_ceq_size = IRDMA_MAX_CEQ_ENTRIES;
+ dev->hw_attrs.uk_attrs.min_hw_cq_size = IRDMA_MIN_CQ_SIZE;
+ dev->hw_attrs.uk_attrs.max_hw_cq_size = IRDMA_MAX_CQ_SIZE;
+ dev->hw_attrs.uk_attrs.max_hw_wq_frags = IRDMA_MAX_WQ_FRAGMENT_COUNT;
+ dev->hw_attrs.uk_attrs.max_hw_read_sges = IRDMA_MAX_SGE_RD;
+ dev->hw_attrs.max_hw_outbound_msg_size = IRDMA_MAX_OUTBOUND_MSG_SIZE;
+ dev->hw_attrs.max_mr_size = IRDMA_MAX_MR_SIZE;
+ dev->hw_attrs.max_hw_inbound_msg_size = IRDMA_MAX_INBOUND_MSG_SIZE;
+ dev->hw_attrs.max_hw_device_pages = IRDMA_MAX_PUSH_PAGE_COUNT;
+ dev->hw_attrs.uk_attrs.max_hw_inline = IRDMA_MAX_INLINE_DATA_SIZE;
+ dev->hw_attrs.max_hw_wqes = IRDMA_MAX_WQ_ENTRIES;
+ dev->hw_attrs.max_qp_wr = IRDMA_MAX_QP_WRS(IRDMA_MAX_QUANTA_PER_WR);
+
+ dev->hw_attrs.uk_attrs.max_hw_rq_quanta = IRDMA_QP_SW_MAX_RQ_QUANTA;
+ dev->hw_attrs.uk_attrs.max_hw_wq_quanta = IRDMA_QP_SW_MAX_WQ_QUANTA;
+ dev->hw_attrs.max_hw_pds = IRDMA_MAX_PDS;
+ dev->hw_attrs.max_hw_ena_vf_count = IRDMA_MAX_PE_ENA_VF_COUNT;
+
+ dev->hw_attrs.max_pe_ready_count = 14;
+ dev->hw_attrs.max_done_count = IRDMA_DONE_COUNT;
+ dev->hw_attrs.max_sleep_count = IRDMA_SLEEP_COUNT;
+ dev->hw_attrs.max_cqp_compl_wait_time_ms = CQP_COMPL_WAIT_TIME_MS;
+
+ dev->hw_attrs.uk_attrs.hw_rev = ver;
+ irdma_sc_init_hw(dev);
+
+ if (irdma_wait_pe_ready(dev))
+ return IRDMA_ERR_TIMEOUT;
+
+ val = readl(dev->hw_regs[IRDMA_GLPCI_LBARCTRL]);
+ db_size = (u8)FIELD_GET(IRDMA_GLPCI_LBARCTRL_PE_DB_SIZE, val);
+ if (db_size != IRDMA_PE_DB_SIZE_4M && db_size != IRDMA_PE_DB_SIZE_8M) {
+ ibdev_dbg(to_ibdev(dev),
+ "DEV: RDMA PE doorbell is not enabled in CSR val 0x%x db_size=%d\n",
+ val, db_size);
+ return IRDMA_ERR_PE_DOORBELL_NOT_ENA;
+ }
+ dev->db_addr = dev->hw->hw_addr + (uintptr_t)dev->hw_regs[IRDMA_DB_ADDR_OFFSET];
+
+ return ret_code;
+}
+
+/**
+ * irdma_update_stats - Update statistics
+ * @hw_stats: hw_stats instance to update
+ * @gather_stats: updated stat counters
+ * @last_gather_stats: last stat counters
+ */
+void irdma_update_stats(struct irdma_dev_hw_stats *hw_stats,
+ struct irdma_gather_stats *gather_stats,
+ struct irdma_gather_stats *last_gather_stats)
+{
+ u64 *stats_val = hw_stats->stats_val_32;
+
+ stats_val[IRDMA_HW_STAT_INDEX_RXVLANERR] +=
+ IRDMA_STATS_DELTA(gather_stats->rxvlanerr,
+ last_gather_stats->rxvlanerr,
+ IRDMA_MAX_STATS_32);
+ stats_val[IRDMA_HW_STAT_INDEX_IP4RXDISCARD] +=
+ IRDMA_STATS_DELTA(gather_stats->ip4rxdiscard,
+ last_gather_stats->ip4rxdiscard,
+ IRDMA_MAX_STATS_32);
+ stats_val[IRDMA_HW_STAT_INDEX_IP4RXTRUNC] +=
+ IRDMA_STATS_DELTA(gather_stats->ip4rxtrunc,
+ last_gather_stats->ip4rxtrunc,
+ IRDMA_MAX_STATS_32);
+ stats_val[IRDMA_HW_STAT_INDEX_IP4TXNOROUTE] +=
+ IRDMA_STATS_DELTA(gather_stats->ip4txnoroute,
+ last_gather_stats->ip4txnoroute,
+ IRDMA_MAX_STATS_32);
+ stats_val[IRDMA_HW_STAT_INDEX_IP6RXDISCARD] +=
+ IRDMA_STATS_DELTA(gather_stats->ip6rxdiscard,
+ last_gather_stats->ip6rxdiscard,
+ IRDMA_MAX_STATS_32);
+ stats_val[IRDMA_HW_STAT_INDEX_IP6RXTRUNC] +=
+ IRDMA_STATS_DELTA(gather_stats->ip6rxtrunc,
+ last_gather_stats->ip6rxtrunc,
+ IRDMA_MAX_STATS_32);
+ stats_val[IRDMA_HW_STAT_INDEX_IP6TXNOROUTE] +=
+ IRDMA_STATS_DELTA(gather_stats->ip6txnoroute,
+ last_gather_stats->ip6txnoroute,
+ IRDMA_MAX_STATS_32);
+ stats_val[IRDMA_HW_STAT_INDEX_TCPRTXSEG] +=
+ IRDMA_STATS_DELTA(gather_stats->tcprtxseg,
+ last_gather_stats->tcprtxseg,
+ IRDMA_MAX_STATS_32);
+ stats_val[IRDMA_HW_STAT_INDEX_TCPRXOPTERR] +=
+ IRDMA_STATS_DELTA(gather_stats->tcprxopterr,
+ last_gather_stats->tcprxopterr,
+ IRDMA_MAX_STATS_32);
+ stats_val[IRDMA_HW_STAT_INDEX_TCPRXPROTOERR] +=
+ IRDMA_STATS_DELTA(gather_stats->tcprxprotoerr,
+ last_gather_stats->tcprxprotoerr,
+ IRDMA_MAX_STATS_32);
+ stats_val[IRDMA_HW_STAT_INDEX_RXRPCNPHANDLED] +=
+ IRDMA_STATS_DELTA(gather_stats->rxrpcnphandled,
+ last_gather_stats->rxrpcnphandled,
+ IRDMA_MAX_STATS_32);
+ stats_val[IRDMA_HW_STAT_INDEX_RXRPCNPIGNORED] +=
+ IRDMA_STATS_DELTA(gather_stats->rxrpcnpignored,
+ last_gather_stats->rxrpcnpignored,
+ IRDMA_MAX_STATS_32);
+ stats_val[IRDMA_HW_STAT_INDEX_TXNPCNPSENT] +=
+ IRDMA_STATS_DELTA(gather_stats->txnpcnpsent,
+ last_gather_stats->txnpcnpsent,
+ IRDMA_MAX_STATS_32);
+ stats_val = hw_stats->stats_val_64;
+ stats_val[IRDMA_HW_STAT_INDEX_IP4RXOCTS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip4rxocts,
+ last_gather_stats->ip4rxocts,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP4RXPKTS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip4rxpkts,
+ last_gather_stats->ip4rxpkts,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP4RXFRAGS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip4txfrag,
+ last_gather_stats->ip4txfrag,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP4RXMCPKTS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip4rxmcpkts,
+ last_gather_stats->ip4rxmcpkts,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP4TXOCTS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip4txocts,
+ last_gather_stats->ip4txocts,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP4TXPKTS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip4txpkts,
+ last_gather_stats->ip4txpkts,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP4TXFRAGS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip4txfrag,
+ last_gather_stats->ip4txfrag,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP4TXMCPKTS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip4txmcpkts,
+ last_gather_stats->ip4txmcpkts,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP6RXOCTS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip6rxocts,
+ last_gather_stats->ip6rxocts,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP6RXPKTS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip6rxpkts,
+ last_gather_stats->ip6rxpkts,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP6RXFRAGS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip6txfrags,
+ last_gather_stats->ip6txfrags,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP6RXMCPKTS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip6rxmcpkts,
+ last_gather_stats->ip6rxmcpkts,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP6TXOCTS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip6txocts,
+ last_gather_stats->ip6txocts,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP6TXPKTS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip6txpkts,
+ last_gather_stats->ip6txpkts,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP6TXFRAGS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip6txfrags,
+ last_gather_stats->ip6txfrags,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_IP6TXMCPKTS] +=
+ IRDMA_STATS_DELTA(gather_stats->ip6txmcpkts,
+ last_gather_stats->ip6txmcpkts,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_TCPRXSEGS] +=
+ IRDMA_STATS_DELTA(gather_stats->tcprxsegs,
+ last_gather_stats->tcprxsegs,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_TCPTXSEG] +=
+ IRDMA_STATS_DELTA(gather_stats->tcptxsegs,
+ last_gather_stats->tcptxsegs,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_RDMARXRDS] +=
+ IRDMA_STATS_DELTA(gather_stats->rdmarxrds,
+ last_gather_stats->rdmarxrds,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_RDMARXSNDS] +=
+ IRDMA_STATS_DELTA(gather_stats->rdmarxsnds,
+ last_gather_stats->rdmarxsnds,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_RDMARXWRS] +=
+ IRDMA_STATS_DELTA(gather_stats->rdmarxwrs,
+ last_gather_stats->rdmarxwrs,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_RDMATXRDS] +=
+ IRDMA_STATS_DELTA(gather_stats->rdmatxrds,
+ last_gather_stats->rdmatxrds,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_RDMATXSNDS] +=
+ IRDMA_STATS_DELTA(gather_stats->rdmatxsnds,
+ last_gather_stats->rdmatxsnds,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_RDMATXWRS] +=
+ IRDMA_STATS_DELTA(gather_stats->rdmatxwrs,
+ last_gather_stats->rdmatxwrs,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_RDMAVBND] +=
+ IRDMA_STATS_DELTA(gather_stats->rdmavbn,
+ last_gather_stats->rdmavbn,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_RDMAVINV] +=
+ IRDMA_STATS_DELTA(gather_stats->rdmavinv,
+ last_gather_stats->rdmavinv,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_UDPRXPKTS] +=
+ IRDMA_STATS_DELTA(gather_stats->udprxpkts,
+ last_gather_stats->udprxpkts,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_UDPTXPKTS] +=
+ IRDMA_STATS_DELTA(gather_stats->udptxpkts,
+ last_gather_stats->udptxpkts,
+ IRDMA_MAX_STATS_48);
+ stats_val[IRDMA_HW_STAT_INDEX_RXNPECNMARKEDPKTS] +=
+ IRDMA_STATS_DELTA(gather_stats->rxnpecnmrkpkts,
+ last_gather_stats->rxnpecnmrkpkts,
+ IRDMA_MAX_STATS_48);
+ memcpy(last_gather_stats, gather_stats, sizeof(*last_gather_stats));
+}
diff --git a/drivers/infiniband/hw/irdma/defs.h b/drivers/infiniband/hw/irdma/defs.h
new file mode 100644
index 000000000000..cc3d9a365b35
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/defs.h
@@ -0,0 +1,1155 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#ifndef IRDMA_DEFS_H
+#define IRDMA_DEFS_H
+
+#define IRDMA_FIRST_USER_QP_ID 3
+
+#define ECN_CODE_PT_VAL 2
+
+#define IRDMA_PUSH_OFFSET (8 * 1024 * 1024)
+#define IRDMA_PF_FIRST_PUSH_PAGE_INDEX 16
+#define IRDMA_PF_BAR_RSVD (60 * 1024)
+
+#define IRDMA_PE_DB_SIZE_4M 1
+#define IRDMA_PE_DB_SIZE_8M 2
+
+#define IRDMA_IRD_HW_SIZE_4 0
+#define IRDMA_IRD_HW_SIZE_16 1
+#define IRDMA_IRD_HW_SIZE_64 2
+#define IRDMA_IRD_HW_SIZE_128 3
+#define IRDMA_IRD_HW_SIZE_256 4
+
+enum irdma_protocol_used {
+ IRDMA_ANY_PROTOCOL = 0,
+ IRDMA_IWARP_PROTOCOL_ONLY = 1,
+ IRDMA_ROCE_PROTOCOL_ONLY = 2,
+};
+
+#define IRDMA_QP_STATE_INVALID 0
+#define IRDMA_QP_STATE_IDLE 1
+#define IRDMA_QP_STATE_RTS 2
+#define IRDMA_QP_STATE_CLOSING 3
+#define IRDMA_QP_STATE_SQD 3
+#define IRDMA_QP_STATE_RTR 4
+#define IRDMA_QP_STATE_TERMINATE 5
+#define IRDMA_QP_STATE_ERROR 6
+
+#define IRDMA_MAX_TRAFFIC_CLASS 8
+#define IRDMA_MAX_USER_PRIORITY 8
+#define IRDMA_MAX_APPS 8
+#define IRDMA_MAX_STATS_COUNT 128
+#define IRDMA_FIRST_NON_PF_STAT 4
+
+#define IRDMA_MIN_MTU_IPV4 576
+#define IRDMA_MIN_MTU_IPV6 1280
+#define IRDMA_MTU_TO_MSS_IPV4 40
+#define IRDMA_MTU_TO_MSS_IPV6 60
+#define IRDMA_DEFAULT_MTU 1500
+
+#define Q2_FPSN_OFFSET 64
+#define TERM_DDP_LEN_TAGGED 14
+#define TERM_DDP_LEN_UNTAGGED 18
+#define TERM_RDMA_LEN 28
+#define RDMA_OPCODE_M 0x0f
+#define RDMA_READ_REQ_OPCODE 1
+#define Q2_BAD_FRAME_OFFSET 72
+#define CQE_MAJOR_DRV 0x8000
+
+#define IRDMA_TERM_SENT 1
+#define IRDMA_TERM_RCVD 2
+#define IRDMA_TERM_DONE 4
+#define IRDMA_MAC_HLEN 14
+
+#define IRDMA_CQP_WAIT_POLL_REGS 1
+#define IRDMA_CQP_WAIT_POLL_CQ 2
+#define IRDMA_CQP_WAIT_EVENT 3
+
+#define IRDMA_AE_SOURCE_RSVD 0x0
+#define IRDMA_AE_SOURCE_RQ 0x1
+#define IRDMA_AE_SOURCE_RQ_0011 0x3
+
+#define IRDMA_AE_SOURCE_CQ 0x2
+#define IRDMA_AE_SOURCE_CQ_0110 0x6
+#define IRDMA_AE_SOURCE_CQ_1010 0xa
+#define IRDMA_AE_SOURCE_CQ_1110 0xe
+
+#define IRDMA_AE_SOURCE_SQ 0x5
+#define IRDMA_AE_SOURCE_SQ_0111 0x7
+
+#define IRDMA_AE_SOURCE_IN_RR_WR 0x9
+#define IRDMA_AE_SOURCE_IN_RR_WR_1011 0xb
+#define IRDMA_AE_SOURCE_OUT_RR 0xd
+#define IRDMA_AE_SOURCE_OUT_RR_1111 0xf
+
+#define IRDMA_TCP_STATE_NON_EXISTENT 0
+#define IRDMA_TCP_STATE_CLOSED 1
+#define IRDMA_TCP_STATE_LISTEN 2
+#define IRDMA_STATE_SYN_SEND 3
+#define IRDMA_TCP_STATE_SYN_RECEIVED 4
+#define IRDMA_TCP_STATE_ESTABLISHED 5
+#define IRDMA_TCP_STATE_CLOSE_WAIT 6
+#define IRDMA_TCP_STATE_FIN_WAIT_1 7
+#define IRDMA_TCP_STATE_CLOSING 8
+#define IRDMA_TCP_STATE_LAST_ACK 9
+#define IRDMA_TCP_STATE_FIN_WAIT_2 10
+#define IRDMA_TCP_STATE_TIME_WAIT 11
+#define IRDMA_TCP_STATE_RESERVED_1 12
+#define IRDMA_TCP_STATE_RESERVED_2 13
+#define IRDMA_TCP_STATE_RESERVED_3 14
+#define IRDMA_TCP_STATE_RESERVED_4 15
+
+#define IRDMA_CQP_SW_SQSIZE_4 4
+#define IRDMA_CQP_SW_SQSIZE_2048 2048
+
+#define IRDMA_CQ_TYPE_IWARP 1
+#define IRDMA_CQ_TYPE_ILQ 2
+#define IRDMA_CQ_TYPE_IEQ 3
+#define IRDMA_CQ_TYPE_CQP 4
+
+#define IRDMA_DONE_COUNT 1000
+#define IRDMA_SLEEP_COUNT 10
+
+#define IRDMA_UPDATE_SD_BUFF_SIZE 128
+#define IRDMA_FEATURE_BUF_SIZE (8 * IRDMA_MAX_FEATURES)
+
+#define IRDMA_MAX_QUANTA_PER_WR 8
+
+#define IRDMA_QP_SW_MAX_WQ_QUANTA 32768
+#define IRDMA_QP_SW_MAX_SQ_QUANTA 32768
+#define IRDMA_QP_SW_MAX_RQ_QUANTA 32768
+#define IRDMA_MAX_QP_WRS(max_quanta_per_wr) \
+ ((IRDMA_QP_SW_MAX_WQ_QUANTA - IRDMA_SQ_RSVD) / (max_quanta_per_wr))
+
+#define IRDMAQP_TERM_SEND_TERM_AND_FIN 0
+#define IRDMAQP_TERM_SEND_TERM_ONLY 1
+#define IRDMAQP_TERM_SEND_FIN_ONLY 2
+#define IRDMAQP_TERM_DONOT_SEND_TERM_OR_FIN 3
+
+#define IRDMA_QP_TYPE_IWARP 1
+#define IRDMA_QP_TYPE_UDA 2
+#define IRDMA_QP_TYPE_ROCE_RC 3
+#define IRDMA_QP_TYPE_ROCE_UD 4
+
+#define IRDMA_HW_PAGE_SIZE 4096
+#define IRDMA_HW_PAGE_SHIFT 12
+#define IRDMA_CQE_QTYPE_RQ 0
+#define IRDMA_CQE_QTYPE_SQ 1
+
+#define IRDMA_QP_SW_MIN_WQSIZE 8u /* in WRs*/
+#define IRDMA_QP_WQE_MIN_SIZE 32
+#define IRDMA_QP_WQE_MAX_SIZE 256
+#define IRDMA_QP_WQE_MIN_QUANTA 1
+#define IRDMA_MAX_RQ_WQE_SHIFT_GEN1 2
+#define IRDMA_MAX_RQ_WQE_SHIFT_GEN2 3
+
+#define IRDMA_SQ_RSVD 258
+#define IRDMA_RQ_RSVD 1
+
+#define IRDMA_FEATURE_RTS_AE 1ULL
+#define IRDMA_FEATURE_CQ_RESIZE 2ULL
+#define IRDMAQP_OP_RDMA_WRITE 0x00
+#define IRDMAQP_OP_RDMA_READ 0x01
+#define IRDMAQP_OP_RDMA_SEND 0x03
+#define IRDMAQP_OP_RDMA_SEND_INV 0x04
+#define IRDMAQP_OP_RDMA_SEND_SOL_EVENT 0x05
+#define IRDMAQP_OP_RDMA_SEND_SOL_EVENT_INV 0x06
+#define IRDMAQP_OP_BIND_MW 0x08
+#define IRDMAQP_OP_FAST_REGISTER 0x09
+#define IRDMAQP_OP_LOCAL_INVALIDATE 0x0a
+#define IRDMAQP_OP_RDMA_READ_LOC_INV 0x0b
+#define IRDMAQP_OP_NOP 0x0c
+#define IRDMAQP_OP_RDMA_WRITE_SOL 0x0d
+#define IRDMAQP_OP_GEN_RTS_AE 0x30
+
+enum irdma_cqp_op_type {
+ IRDMA_OP_CEQ_DESTROY = 1,
+ IRDMA_OP_AEQ_DESTROY = 2,
+ IRDMA_OP_DELETE_ARP_CACHE_ENTRY = 3,
+ IRDMA_OP_MANAGE_APBVT_ENTRY = 4,
+ IRDMA_OP_CEQ_CREATE = 5,
+ IRDMA_OP_AEQ_CREATE = 6,
+ IRDMA_OP_MANAGE_QHASH_TABLE_ENTRY = 7,
+ IRDMA_OP_QP_MODIFY = 8,
+ IRDMA_OP_QP_UPLOAD_CONTEXT = 9,
+ IRDMA_OP_CQ_CREATE = 10,
+ IRDMA_OP_CQ_DESTROY = 11,
+ IRDMA_OP_QP_CREATE = 12,
+ IRDMA_OP_QP_DESTROY = 13,
+ IRDMA_OP_ALLOC_STAG = 14,
+ IRDMA_OP_MR_REG_NON_SHARED = 15,
+ IRDMA_OP_DEALLOC_STAG = 16,
+ IRDMA_OP_MW_ALLOC = 17,
+ IRDMA_OP_QP_FLUSH_WQES = 18,
+ IRDMA_OP_ADD_ARP_CACHE_ENTRY = 19,
+ IRDMA_OP_MANAGE_PUSH_PAGE = 20,
+ IRDMA_OP_UPDATE_PE_SDS = 21,
+ IRDMA_OP_MANAGE_HMC_PM_FUNC_TABLE = 22,
+ IRDMA_OP_SUSPEND = 23,
+ IRDMA_OP_RESUME = 24,
+ IRDMA_OP_MANAGE_VF_PBLE_BP = 25,
+ IRDMA_OP_QUERY_FPM_VAL = 26,
+ IRDMA_OP_COMMIT_FPM_VAL = 27,
+ IRDMA_OP_REQ_CMDS = 28,
+ IRDMA_OP_CMPL_CMDS = 29,
+ IRDMA_OP_AH_CREATE = 30,
+ IRDMA_OP_AH_MODIFY = 31,
+ IRDMA_OP_AH_DESTROY = 32,
+ IRDMA_OP_MC_CREATE = 33,
+ IRDMA_OP_MC_DESTROY = 34,
+ IRDMA_OP_MC_MODIFY = 35,
+ IRDMA_OP_STATS_ALLOCATE = 36,
+ IRDMA_OP_STATS_FREE = 37,
+ IRDMA_OP_STATS_GATHER = 38,
+ IRDMA_OP_WS_ADD_NODE = 39,
+ IRDMA_OP_WS_MODIFY_NODE = 40,
+ IRDMA_OP_WS_DELETE_NODE = 41,
+ IRDMA_OP_WS_FAILOVER_START = 42,
+ IRDMA_OP_WS_FAILOVER_COMPLETE = 43,
+ IRDMA_OP_SET_UP_MAP = 44,
+ IRDMA_OP_GEN_AE = 45,
+ IRDMA_OP_QUERY_RDMA_FEATURES = 46,
+ IRDMA_OP_ALLOC_LOCAL_MAC_ENTRY = 47,
+ IRDMA_OP_ADD_LOCAL_MAC_ENTRY = 48,
+ IRDMA_OP_DELETE_LOCAL_MAC_ENTRY = 49,
+ IRDMA_OP_CQ_MODIFY = 50,
+
+ /* Must be last entry*/
+ IRDMA_MAX_CQP_OPS = 51,
+};
+
+/* CQP SQ WQES */
+#define IRDMA_CQP_OP_CREATE_QP 0
+#define IRDMA_CQP_OP_MODIFY_QP 0x1
+#define IRDMA_CQP_OP_DESTROY_QP 0x02
+#define IRDMA_CQP_OP_CREATE_CQ 0x03
+#define IRDMA_CQP_OP_MODIFY_CQ 0x04
+#define IRDMA_CQP_OP_DESTROY_CQ 0x05
+#define IRDMA_CQP_OP_ALLOC_STAG 0x09
+#define IRDMA_CQP_OP_REG_MR 0x0a
+#define IRDMA_CQP_OP_QUERY_STAG 0x0b
+#define IRDMA_CQP_OP_REG_SMR 0x0c
+#define IRDMA_CQP_OP_DEALLOC_STAG 0x0d
+#define IRDMA_CQP_OP_MANAGE_LOC_MAC_TABLE 0x0e
+#define IRDMA_CQP_OP_MANAGE_ARP 0x0f
+#define IRDMA_CQP_OP_MANAGE_VF_PBLE_BP 0x10
+#define IRDMA_CQP_OP_MANAGE_PUSH_PAGES 0x11
+#define IRDMA_CQP_OP_QUERY_RDMA_FEATURES 0x12
+#define IRDMA_CQP_OP_UPLOAD_CONTEXT 0x13
+#define IRDMA_CQP_OP_ALLOCATE_LOC_MAC_TABLE_ENTRY 0x14
+#define IRDMA_CQP_OP_UPLOAD_CONTEXT 0x13
+#define IRDMA_CQP_OP_MANAGE_HMC_PM_FUNC_TABLE 0x15
+#define IRDMA_CQP_OP_CREATE_CEQ 0x16
+#define IRDMA_CQP_OP_DESTROY_CEQ 0x18
+#define IRDMA_CQP_OP_CREATE_AEQ 0x19
+#define IRDMA_CQP_OP_DESTROY_AEQ 0x1b
+#define IRDMA_CQP_OP_CREATE_ADDR_HANDLE 0x1c
+#define IRDMA_CQP_OP_MODIFY_ADDR_HANDLE 0x1d
+#define IRDMA_CQP_OP_DESTROY_ADDR_HANDLE 0x1e
+#define IRDMA_CQP_OP_UPDATE_PE_SDS 0x1f
+#define IRDMA_CQP_OP_QUERY_FPM_VAL 0x20
+#define IRDMA_CQP_OP_COMMIT_FPM_VAL 0x21
+#define IRDMA_CQP_OP_FLUSH_WQES 0x22
+/* IRDMA_CQP_OP_GEN_AE is the same value as IRDMA_CQP_OP_FLUSH_WQES */
+#define IRDMA_CQP_OP_GEN_AE 0x22
+#define IRDMA_CQP_OP_MANAGE_APBVT 0x23
+#define IRDMA_CQP_OP_NOP 0x24
+#define IRDMA_CQP_OP_MANAGE_QUAD_HASH_TABLE_ENTRY 0x25
+#define IRDMA_CQP_OP_CREATE_MCAST_GRP 0x26
+#define IRDMA_CQP_OP_MODIFY_MCAST_GRP 0x27
+#define IRDMA_CQP_OP_DESTROY_MCAST_GRP 0x28
+#define IRDMA_CQP_OP_SUSPEND_QP 0x29
+#define IRDMA_CQP_OP_RESUME_QP 0x2a
+#define IRDMA_CQP_OP_SHMC_PAGES_ALLOCATED 0x2b
+#define IRDMA_CQP_OP_WORK_SCHED_NODE 0x2c
+#define IRDMA_CQP_OP_MANAGE_STATS 0x2d
+#define IRDMA_CQP_OP_GATHER_STATS 0x2e
+#define IRDMA_CQP_OP_UP_MAP 0x2f
+
+/* Async Events codes */
+#define IRDMA_AE_AMP_UNALLOCATED_STAG 0x0102
+#define IRDMA_AE_AMP_INVALID_STAG 0x0103
+#define IRDMA_AE_AMP_BAD_QP 0x0104
+#define IRDMA_AE_AMP_BAD_PD 0x0105
+#define IRDMA_AE_AMP_BAD_STAG_KEY 0x0106
+#define IRDMA_AE_AMP_BAD_STAG_INDEX 0x0107
+#define IRDMA_AE_AMP_BOUNDS_VIOLATION 0x0108
+#define IRDMA_AE_AMP_RIGHTS_VIOLATION 0x0109
+#define IRDMA_AE_AMP_TO_WRAP 0x010a
+#define IRDMA_AE_AMP_FASTREG_VALID_STAG 0x010c
+#define IRDMA_AE_AMP_FASTREG_MW_STAG 0x010d
+#define IRDMA_AE_AMP_FASTREG_INVALID_RIGHTS 0x010e
+#define IRDMA_AE_AMP_FASTREG_INVALID_LENGTH 0x0110
+#define IRDMA_AE_AMP_INVALIDATE_SHARED 0x0111
+#define IRDMA_AE_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS 0x0112
+#define IRDMA_AE_AMP_INVALIDATE_MR_WITH_BOUND_WINDOWS 0x0113
+#define IRDMA_AE_AMP_MWBIND_VALID_STAG 0x0114
+#define IRDMA_AE_AMP_MWBIND_OF_MR_STAG 0x0115
+#define IRDMA_AE_AMP_MWBIND_TO_ZERO_BASED_STAG 0x0116
+#define IRDMA_AE_AMP_MWBIND_TO_MW_STAG 0x0117
+#define IRDMA_AE_AMP_MWBIND_INVALID_RIGHTS 0x0118
+#define IRDMA_AE_AMP_MWBIND_INVALID_BOUNDS 0x0119
+#define IRDMA_AE_AMP_MWBIND_TO_INVALID_PARENT 0x011a
+#define IRDMA_AE_AMP_MWBIND_BIND_DISABLED 0x011b
+#define IRDMA_AE_PRIV_OPERATION_DENIED 0x011c
+#define IRDMA_AE_AMP_INVALIDATE_TYPE1_MW 0x011d
+#define IRDMA_AE_AMP_MWBIND_ZERO_BASED_TYPE1_MW 0x011e
+#define IRDMA_AE_AMP_FASTREG_INVALID_PBL_HPS_CFG 0x011f
+#define IRDMA_AE_AMP_MWBIND_WRONG_TYPE 0x0120
+#define IRDMA_AE_AMP_FASTREG_PBLE_MISMATCH 0x0121
+#define IRDMA_AE_UDA_XMIT_DGRAM_TOO_LONG 0x0132
+#define IRDMA_AE_UDA_XMIT_BAD_PD 0x0133
+#define IRDMA_AE_UDA_XMIT_DGRAM_TOO_SHORT 0x0134
+#define IRDMA_AE_UDA_L4LEN_INVALID 0x0135
+#define IRDMA_AE_BAD_CLOSE 0x0201
+#define IRDMA_AE_RDMAP_ROE_BAD_LLP_CLOSE 0x0202
+#define IRDMA_AE_CQ_OPERATION_ERROR 0x0203
+#define IRDMA_AE_RDMA_READ_WHILE_ORD_ZERO 0x0205
+#define IRDMA_AE_STAG_ZERO_INVALID 0x0206
+#define IRDMA_AE_IB_RREQ_AND_Q1_FULL 0x0207
+#define IRDMA_AE_IB_INVALID_REQUEST 0x0208
+#define IRDMA_AE_WQE_UNEXPECTED_OPCODE 0x020a
+#define IRDMA_AE_WQE_INVALID_PARAMETER 0x020b
+#define IRDMA_AE_WQE_INVALID_FRAG_DATA 0x020c
+#define IRDMA_AE_IB_REMOTE_ACCESS_ERROR 0x020d
+#define IRDMA_AE_IB_REMOTE_OP_ERROR 0x020e
+#define IRDMA_AE_WQE_LSMM_TOO_LONG 0x0220
+#define IRDMA_AE_DDP_INVALID_MSN_GAP_IN_MSN 0x0301
+#define IRDMA_AE_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER 0x0303
+#define IRDMA_AE_DDP_UBE_INVALID_DDP_VERSION 0x0304
+#define IRDMA_AE_DDP_UBE_INVALID_MO 0x0305
+#define IRDMA_AE_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE 0x0306
+#define IRDMA_AE_DDP_UBE_INVALID_QN 0x0307
+#define IRDMA_AE_DDP_NO_L_BIT 0x0308
+#define IRDMA_AE_RDMAP_ROE_INVALID_RDMAP_VERSION 0x0311
+#define IRDMA_AE_RDMAP_ROE_UNEXPECTED_OPCODE 0x0312
+#define IRDMA_AE_ROE_INVALID_RDMA_READ_REQUEST 0x0313
+#define IRDMA_AE_ROE_INVALID_RDMA_WRITE_OR_READ_RESP 0x0314
+#define IRDMA_AE_ROCE_RSP_LENGTH_ERROR 0x0316
+#define IRDMA_AE_ROCE_EMPTY_MCG 0x0380
+#define IRDMA_AE_ROCE_BAD_MC_IP_ADDR 0x0381
+#define IRDMA_AE_ROCE_BAD_MC_QPID 0x0382
+#define IRDMA_AE_MCG_QP_PROTOCOL_MISMATCH 0x0383
+#define IRDMA_AE_INVALID_ARP_ENTRY 0x0401
+#define IRDMA_AE_INVALID_TCP_OPTION_RCVD 0x0402
+#define IRDMA_AE_STALE_ARP_ENTRY 0x0403
+#define IRDMA_AE_INVALID_AH_ENTRY 0x0406
+#define IRDMA_AE_LLP_CLOSE_COMPLETE 0x0501
+#define IRDMA_AE_LLP_CONNECTION_RESET 0x0502
+#define IRDMA_AE_LLP_FIN_RECEIVED 0x0503
+#define IRDMA_AE_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH 0x0504
+#define IRDMA_AE_LLP_RECEIVED_MPA_CRC_ERROR 0x0505
+#define IRDMA_AE_LLP_SEGMENT_TOO_SMALL 0x0507
+#define IRDMA_AE_LLP_SYN_RECEIVED 0x0508
+#define IRDMA_AE_LLP_TERMINATE_RECEIVED 0x0509
+#define IRDMA_AE_LLP_TOO_MANY_RETRIES 0x050a
+#define IRDMA_AE_LLP_TOO_MANY_KEEPALIVE_RETRIES 0x050b
+#define IRDMA_AE_LLP_DOUBT_REACHABILITY 0x050c
+#define IRDMA_AE_LLP_CONNECTION_ESTABLISHED 0x050e
+#define IRDMA_AE_RESOURCE_EXHAUSTION 0x0520
+#define IRDMA_AE_RESET_SENT 0x0601
+#define IRDMA_AE_TERMINATE_SENT 0x0602
+#define IRDMA_AE_RESET_NOT_SENT 0x0603
+#define IRDMA_AE_LCE_QP_CATASTROPHIC 0x0700
+#define IRDMA_AE_LCE_FUNCTION_CATASTROPHIC 0x0701
+#define IRDMA_AE_LCE_CQ_CATASTROPHIC 0x0702
+#define IRDMA_AE_QP_SUSPEND_COMPLETE 0x0900
+
+#define FLD_LS_64(dev, val, field) \
+ (((u64)(val) << (dev)->hw_shifts[field ## _S]) & (dev)->hw_masks[field ## _M])
+#define FLD_RS_64(dev, val, field) \
+ ((u64)((val) & (dev)->hw_masks[field ## _M]) >> (dev)->hw_shifts[field ## _S])
+#define FLD_LS_32(dev, val, field) \
+ (((val) << (dev)->hw_shifts[field ## _S]) & (dev)->hw_masks[field ## _M])
+#define FLD_RS_32(dev, val, field) \
+ ((u64)((val) & (dev)->hw_masks[field ## _M]) >> (dev)->hw_shifts[field ## _S])
+
+#define IRDMA_STATS_DELTA(a, b, c) ((a) >= (b) ? (a) - (b) : (a) + (c) - (b))
+#define IRDMA_MAX_STATS_32 0xFFFFFFFFULL
+#define IRDMA_MAX_STATS_48 0xFFFFFFFFFFFFULL
+
+#define IRDMA_MAX_CQ_READ_THRESH 0x3FFFF
+#define IRDMA_CQPSQ_QHASH_VLANID GENMASK_ULL(43, 32)
+#define IRDMA_CQPSQ_QHASH_QPN GENMASK_ULL(49, 32)
+#define IRDMA_CQPSQ_QHASH_QS_HANDLE GENMASK_ULL(9, 0)
+#define IRDMA_CQPSQ_QHASH_SRC_PORT GENMASK_ULL(31, 16)
+#define IRDMA_CQPSQ_QHASH_DEST_PORT GENMASK_ULL(15, 0)
+#define IRDMA_CQPSQ_QHASH_ADDR0 GENMASK_ULL(63, 32)
+#define IRDMA_CQPSQ_QHASH_ADDR1 GENMASK_ULL(31, 0)
+#define IRDMA_CQPSQ_QHASH_ADDR2 GENMASK_ULL(63, 32)
+#define IRDMA_CQPSQ_QHASH_ADDR3 GENMASK_ULL(31, 0)
+#define IRDMA_CQPSQ_QHASH_WQEVALID BIT_ULL(63)
+#define IRDMA_CQPSQ_QHASH_OPCODE GENMASK_ULL(37, 32)
+#define IRDMA_CQPSQ_QHASH_MANAGE GENMASK_ULL(62, 61)
+#define IRDMA_CQPSQ_QHASH_IPV4VALID BIT_ULL(60)
+#define IRDMA_CQPSQ_QHASH_VLANVALID BIT_ULL(59)
+#define IRDMA_CQPSQ_QHASH_ENTRYTYPE GENMASK_ULL(44, 42)
+#define IRDMA_CQPSQ_STATS_WQEVALID BIT_ULL(63)
+#define IRDMA_CQPSQ_STATS_ALLOC_INST BIT_ULL(62)
+#define IRDMA_CQPSQ_STATS_USE_HMC_FCN_INDEX BIT_ULL(60)
+#define IRDMA_CQPSQ_STATS_USE_INST BIT_ULL(61)
+#define IRDMA_CQPSQ_STATS_OP GENMASK_ULL(37, 32)
+#define IRDMA_CQPSQ_STATS_INST_INDEX GENMASK_ULL(6, 0)
+#define IRDMA_CQPSQ_STATS_HMC_FCN_INDEX GENMASK_ULL(5, 0)
+#define IRDMA_CQPSQ_WS_WQEVALID BIT_ULL(63)
+#define IRDMA_CQPSQ_WS_NODEOP GENMASK_ULL(53, 52)
+
+#define IRDMA_CQPSQ_WS_ENABLENODE BIT_ULL(62)
+#define IRDMA_CQPSQ_WS_NODETYPE BIT_ULL(61)
+#define IRDMA_CQPSQ_WS_PRIOTYPE GENMASK_ULL(60, 59)
+#define IRDMA_CQPSQ_WS_TC GENMASK_ULL(58, 56)
+#define IRDMA_CQPSQ_WS_VMVFTYPE GENMASK_ULL(55, 54)
+#define IRDMA_CQPSQ_WS_VMVFNUM GENMASK_ULL(51, 42)
+#define IRDMA_CQPSQ_WS_OP GENMASK_ULL(37, 32)
+#define IRDMA_CQPSQ_WS_PARENTID GENMASK_ULL(25, 16)
+#define IRDMA_CQPSQ_WS_NODEID GENMASK_ULL(9, 0)
+#define IRDMA_CQPSQ_WS_VSI GENMASK_ULL(57, 48)
+#define IRDMA_CQPSQ_WS_WEIGHT GENMASK_ULL(38, 32)
+
+#define IRDMA_CQPSQ_UP_WQEVALID BIT_ULL(63)
+#define IRDMA_CQPSQ_UP_USEVLAN BIT_ULL(62)
+#define IRDMA_CQPSQ_UP_USEOVERRIDE BIT_ULL(61)
+#define IRDMA_CQPSQ_UP_OP GENMASK_ULL(37, 32)
+#define IRDMA_CQPSQ_UP_HMCFCNIDX GENMASK_ULL(5, 0)
+#define IRDMA_CQPSQ_UP_CNPOVERRIDE GENMASK_ULL(37, 32)
+#define IRDMA_CQPSQ_QUERY_RDMA_FEATURES_WQEVALID BIT_ULL(63)
+#define IRDMA_CQPSQ_QUERY_RDMA_FEATURES_BUF_LEN GENMASK_ULL(31, 0)
+#define IRDMA_CQPSQ_QUERY_RDMA_FEATURES_OP GENMASK_ULL(37, 32)
+#define IRDMA_CQPSQ_QUERY_RDMA_FEATURES_HW_MODEL_USED GENMASK_ULL(47, 32)
+#define IRDMA_CQPSQ_QUERY_RDMA_FEATURES_HW_MAJOR_VERSION GENMASK_ULL(23, 16)
+#define IRDMA_CQPSQ_QUERY_RDMA_FEATURES_HW_MINOR_VERSION GENMASK_ULL(7, 0)
+#define IRDMA_CQPHC_SQSIZE GENMASK_ULL(11, 8)
+#define IRDMA_CQPHC_DISABLE_PFPDUS BIT_ULL(1)
+#define IRDMA_CQPHC_ROCEV2_RTO_POLICY BIT_ULL(2)
+#define IRDMA_CQPHC_PROTOCOL_USED GENMASK_ULL(4, 3)
+#define IRDMA_CQPHC_MIN_RATE GENMASK_ULL(51, 48)
+#define IRDMA_CQPHC_MIN_DEC_FACTOR GENMASK_ULL(59, 56)
+#define IRDMA_CQPHC_DCQCN_T GENMASK_ULL(15, 0)
+#define IRDMA_CQPHC_HAI_FACTOR GENMASK_ULL(47, 32)
+#define IRDMA_CQPHC_RAI_FACTOR GENMASK_ULL(63, 48)
+#define IRDMA_CQPHC_DCQCN_B GENMASK_ULL(24, 0)
+#define IRDMA_CQPHC_DCQCN_F GENMASK_ULL(27, 25)
+#define IRDMA_CQPHC_CC_CFG_VALID BIT_ULL(31)
+#define IRDMA_CQPHC_RREDUCE_MPERIOD GENMASK_ULL(63, 32)
+#define IRDMA_CQPHC_HW_MINVER GENMASK_ULL(15, 0)
+
+#define IRDMA_CQPHC_HW_MAJVER_GEN_1 0
+#define IRDMA_CQPHC_HW_MAJVER_GEN_2 1
+#define IRDMA_CQPHC_HW_MAJVER_GEN_3 2
+#define IRDMA_CQPHC_HW_MAJVER GENMASK_ULL(31, 16)
+#define IRDMA_CQPHC_CEQPERVF GENMASK_ULL(39, 32)
+
+#define IRDMA_CQPHC_ENABLED_VFS GENMASK_ULL(37, 32)
+
+#define IRDMA_CQPHC_HMC_PROFILE GENMASK_ULL(2, 0)
+#define IRDMA_CQPHC_SVER GENMASK_ULL(31, 24)
+#define IRDMA_CQPHC_SQBASE GENMASK_ULL(63, 9)
+
+#define IRDMA_CQPHC_QPCTX GENMASK_ULL(63, 0)
+#define IRDMA_QP_DBSA_HW_SQ_TAIL GENMASK_ULL(14, 0)
+#define IRDMA_CQ_DBSA_CQEIDX GENMASK_ULL(19, 0)
+#define IRDMA_CQ_DBSA_SW_CQ_SELECT GENMASK_ULL(13, 0)
+#define IRDMA_CQ_DBSA_ARM_NEXT BIT_ULL(14)
+#define IRDMA_CQ_DBSA_ARM_NEXT_SE BIT_ULL(15)
+#define IRDMA_CQ_DBSA_ARM_SEQ_NUM GENMASK_ULL(17, 16)
+
+/* CQP and iWARP Completion Queue */
+#define IRDMA_CQ_QPCTX IRDMA_CQPHC_QPCTX
+
+#define IRDMA_CCQ_OPRETVAL GENMASK_ULL(31, 0)
+
+#define IRDMA_CQ_MINERR GENMASK_ULL(15, 0)
+#define IRDMA_CQ_MAJERR GENMASK_ULL(31, 16)
+#define IRDMA_CQ_WQEIDX GENMASK_ULL(46, 32)
+#define IRDMA_CQ_EXTCQE BIT_ULL(50)
+#define IRDMA_OOO_CMPL BIT_ULL(54)
+#define IRDMA_CQ_ERROR BIT_ULL(55)
+#define IRDMA_CQ_SQ BIT_ULL(62)
+
+#define IRDMA_CQ_VALID BIT_ULL(63)
+#define IRDMA_CQ_IMMVALID BIT_ULL(62)
+#define IRDMA_CQ_UDSMACVALID BIT_ULL(61)
+#define IRDMA_CQ_UDVLANVALID BIT_ULL(60)
+#define IRDMA_CQ_UDSMAC GENMASK_ULL(47, 0)
+#define IRDMA_CQ_UDVLAN GENMASK_ULL(63, 48)
+
+#define IRDMA_CQ_IMMDATA_S 0
+#define IRDMA_CQ_IMMDATA_M (0xffffffffffffffffULL << IRDMA_CQ_IMMVALID_S)
+#define IRDMA_CQ_IMMDATALOW32 GENMASK_ULL(31, 0)
+#define IRDMA_CQ_IMMDATAUP32 GENMASK_ULL(63, 32)
+#define IRDMACQ_PAYLDLEN GENMASK_ULL(31, 0)
+#define IRDMACQ_TCPSEQNUMRTT GENMASK_ULL(63, 32)
+#define IRDMACQ_INVSTAG GENMASK_ULL(31, 0)
+#define IRDMACQ_QPID GENMASK_ULL(55, 32)
+
+#define IRDMACQ_UDSRCQPN GENMASK_ULL(31, 0)
+#define IRDMACQ_PSHDROP BIT_ULL(51)
+#define IRDMACQ_STAG BIT_ULL(53)
+#define IRDMACQ_IPV4 BIT_ULL(53)
+#define IRDMACQ_SOEVENT BIT_ULL(54)
+#define IRDMACQ_OP GENMASK_ULL(61, 56)
+
+#define IRDMA_CEQE_CQCTX GENMASK_ULL(62, 0)
+#define IRDMA_CEQE_VALID BIT_ULL(63)
+
+/* AEQE format */
+#define IRDMA_AEQE_COMPCTX IRDMA_CQPHC_QPCTX
+#define IRDMA_AEQE_QPCQID_LOW GENMASK_ULL(17, 0)
+#define IRDMA_AEQE_QPCQID_HI BIT_ULL(46)
+#define IRDMA_AEQE_WQDESCIDX GENMASK_ULL(32, 18)
+#define IRDMA_AEQE_OVERFLOW BIT_ULL(33)
+#define IRDMA_AEQE_AECODE GENMASK_ULL(45, 34)
+#define IRDMA_AEQE_AESRC GENMASK_ULL(53, 50)
+#define IRDMA_AEQE_IWSTATE GENMASK_ULL(56, 54)
+#define IRDMA_AEQE_TCPSTATE GENMASK_ULL(60, 57)
+#define IRDMA_AEQE_Q2DATA GENMASK_ULL(62, 61)
+#define IRDMA_AEQE_VALID BIT_ULL(63)
+
+#define IRDMA_UDA_QPSQ_NEXT_HDR GENMASK_ULL(23, 16)
+#define IRDMA_UDA_QPSQ_OPCODE GENMASK_ULL(37, 32)
+#define IRDMA_UDA_QPSQ_L4LEN GENMASK_ULL(45, 42)
+#define IRDMA_GEN1_UDA_QPSQ_L4LEN GENMASK_ULL(27, 24)
+#define IRDMA_UDA_QPSQ_AHIDX GENMASK_ULL(16, 0)
+#define IRDMA_UDA_QPSQ_VALID BIT_ULL(63)
+#define IRDMA_UDA_QPSQ_SIGCOMPL BIT_ULL(62)
+#define IRDMA_UDA_QPSQ_MACLEN GENMASK_ULL(62, 56)
+#define IRDMA_UDA_QPSQ_IPLEN GENMASK_ULL(54, 48)
+#define IRDMA_UDA_QPSQ_L4T GENMASK_ULL(31, 30)
+#define IRDMA_UDA_QPSQ_IIPT GENMASK_ULL(29, 28)
+#define IRDMA_UDA_PAYLOADLEN GENMASK_ULL(13, 0)
+#define IRDMA_UDA_HDRLEN GENMASK_ULL(24, 16)
+#define IRDMA_VLAN_TAG_VALID BIT_ULL(50)
+#define IRDMA_UDA_L3PROTO GENMASK_ULL(1, 0)
+#define IRDMA_UDA_L4PROTO GENMASK_ULL(17, 16)
+#define IRDMA_UDA_QPSQ_DOLOOPBACK BIT_ULL(44)
+#define IRDMA_CQPSQ_BUFSIZE GENMASK_ULL(31, 0)
+#define IRDMA_CQPSQ_OPCODE GENMASK_ULL(37, 32)
+#define IRDMA_CQPSQ_WQEVALID BIT_ULL(63)
+#define IRDMA_CQPSQ_TPHVAL GENMASK_ULL(7, 0)
+
+#define IRDMA_CQPSQ_VSIIDX GENMASK_ULL(17, 8)
+#define IRDMA_CQPSQ_TPHEN BIT_ULL(60)
+
+#define IRDMA_CQPSQ_PBUFADDR IRDMA_CQPHC_QPCTX
+
+/* Create/Modify/Destroy QP */
+
+#define IRDMA_CQPSQ_QP_NEWMSS GENMASK_ULL(45, 32)
+#define IRDMA_CQPSQ_QP_TERMLEN GENMASK_ULL(51, 48)
+
+#define IRDMA_CQPSQ_QP_QPCTX IRDMA_CQPHC_QPCTX
+
+#define IRDMA_CQPSQ_QP_QPID_S 0
+#define IRDMA_CQPSQ_QP_QPID_M (0xFFFFFFUL)
+
+#define IRDMA_CQPSQ_QP_OP_S 32
+#define IRDMA_CQPSQ_QP_OP_M IRDMACQ_OP_M
+#define IRDMA_CQPSQ_QP_ORDVALID BIT_ULL(42)
+#define IRDMA_CQPSQ_QP_TOECTXVALID BIT_ULL(43)
+#define IRDMA_CQPSQ_QP_CACHEDVARVALID BIT_ULL(44)
+#define IRDMA_CQPSQ_QP_VQ BIT_ULL(45)
+#define IRDMA_CQPSQ_QP_FORCELOOPBACK BIT_ULL(46)
+#define IRDMA_CQPSQ_QP_CQNUMVALID BIT_ULL(47)
+#define IRDMA_CQPSQ_QP_QPTYPE GENMASK_ULL(50, 48)
+#define IRDMA_CQPSQ_QP_MACVALID BIT_ULL(51)
+#define IRDMA_CQPSQ_QP_MSSCHANGE BIT_ULL(52)
+
+#define IRDMA_CQPSQ_QP_IGNOREMWBOUND BIT_ULL(54)
+#define IRDMA_CQPSQ_QP_REMOVEHASHENTRY BIT_ULL(55)
+#define IRDMA_CQPSQ_QP_TERMACT GENMASK_ULL(57, 56)
+#define IRDMA_CQPSQ_QP_RESETCON BIT_ULL(58)
+#define IRDMA_CQPSQ_QP_ARPTABIDXVALID BIT_ULL(59)
+#define IRDMA_CQPSQ_QP_NEXTIWSTATE GENMASK_ULL(62, 60)
+
+#define IRDMA_CQPSQ_QP_DBSHADOWADDR IRDMA_CQPHC_QPCTX
+
+#define IRDMA_CQPSQ_CQ_CQSIZE GENMASK_ULL(20, 0)
+#define IRDMA_CQPSQ_CQ_CQCTX GENMASK_ULL(62, 0)
+#define IRDMA_CQPSQ_CQ_SHADOW_READ_THRESHOLD GENMASK(17, 0)
+
+#define IRDMA_CQPSQ_CQ_OP GENMASK_ULL(37, 32)
+#define IRDMA_CQPSQ_CQ_CQRESIZE BIT_ULL(43)
+#define IRDMA_CQPSQ_CQ_LPBLSIZE GENMASK_ULL(45, 44)
+#define IRDMA_CQPSQ_CQ_CHKOVERFLOW BIT_ULL(46)
+#define IRDMA_CQPSQ_CQ_VIRTMAP BIT_ULL(47)
+#define IRDMA_CQPSQ_CQ_ENCEQEMASK BIT_ULL(48)
+#define IRDMA_CQPSQ_CQ_CEQIDVALID BIT_ULL(49)
+#define IRDMA_CQPSQ_CQ_AVOIDMEMCNFLCT BIT_ULL(61)
+#define IRDMA_CQPSQ_CQ_FIRSTPMPBLIDX GENMASK_ULL(27, 0)
+
+/* Allocate/Register/Register Shared/Deallocate Stag */
+#define IRDMA_CQPSQ_STAG_VA_FBO IRDMA_CQPHC_QPCTX
+#define IRDMA_CQPSQ_STAG_STAGLEN GENMASK_ULL(45, 0)
+#define IRDMA_CQPSQ_STAG_KEY GENMASK_ULL(7, 0)
+#define IRDMA_CQPSQ_STAG_IDX GENMASK_ULL(31, 8)
+#define IRDMA_CQPSQ_STAG_IDX_S 8
+#define IRDMA_CQPSQ_STAG_PARENTSTAGIDX GENMASK_ULL(55, 32)
+#define IRDMA_CQPSQ_STAG_MR BIT_ULL(43)
+#define IRDMA_CQPSQ_STAG_MWTYPE BIT_ULL(42)
+#define IRDMA_CQPSQ_STAG_MW1_BIND_DONT_VLDT_KEY BIT_ULL(58)
+
+#define IRDMA_CQPSQ_STAG_LPBLSIZE IRDMA_CQPSQ_CQ_LPBLSIZE
+#define IRDMA_CQPSQ_STAG_HPAGESIZE GENMASK_ULL(47, 46)
+#define IRDMA_CQPSQ_STAG_ARIGHTS GENMASK_ULL(52, 48)
+#define IRDMA_CQPSQ_STAG_REMACCENABLED BIT_ULL(53)
+#define IRDMA_CQPSQ_STAG_VABASEDTO BIT_ULL(59)
+#define IRDMA_CQPSQ_STAG_USEHMCFNIDX BIT_ULL(60)
+#define IRDMA_CQPSQ_STAG_USEPFRID BIT_ULL(61)
+
+#define IRDMA_CQPSQ_STAG_PBA IRDMA_CQPHC_QPCTX
+#define IRDMA_CQPSQ_STAG_HMCFNIDX GENMASK_ULL(5, 0)
+
+#define IRDMA_CQPSQ_STAG_FIRSTPMPBLIDX GENMASK_ULL(27, 0)
+#define IRDMA_CQPSQ_QUERYSTAG_IDX IRDMA_CQPSQ_STAG_IDX
+#define IRDMA_CQPSQ_MLM_TABLEIDX GENMASK_ULL(5, 0)
+#define IRDMA_CQPSQ_MLM_FREEENTRY BIT_ULL(62)
+#define IRDMA_CQPSQ_MLM_IGNORE_REF_CNT BIT_ULL(61)
+#define IRDMA_CQPSQ_MLM_MAC0 GENMASK_ULL(7, 0)
+#define IRDMA_CQPSQ_MLM_MAC1 GENMASK_ULL(15, 8)
+#define IRDMA_CQPSQ_MLM_MAC2 GENMASK_ULL(23, 16)
+#define IRDMA_CQPSQ_MLM_MAC3 GENMASK_ULL(31, 24)
+#define IRDMA_CQPSQ_MLM_MAC4 GENMASK_ULL(39, 32)
+#define IRDMA_CQPSQ_MLM_MAC5 GENMASK_ULL(47, 40)
+#define IRDMA_CQPSQ_MAT_REACHMAX GENMASK_ULL(31, 0)
+#define IRDMA_CQPSQ_MAT_MACADDR GENMASK_ULL(47, 0)
+#define IRDMA_CQPSQ_MAT_ARPENTRYIDX GENMASK_ULL(11, 0)
+#define IRDMA_CQPSQ_MAT_ENTRYVALID BIT_ULL(42)
+#define IRDMA_CQPSQ_MAT_PERMANENT BIT_ULL(43)
+#define IRDMA_CQPSQ_MAT_QUERY BIT_ULL(44)
+#define IRDMA_CQPSQ_MVPBP_PD_ENTRY_CNT GENMASK_ULL(9, 0)
+#define IRDMA_CQPSQ_MVPBP_FIRST_PD_INX GENMASK_ULL(24, 16)
+#define IRDMA_CQPSQ_MVPBP_SD_INX GENMASK_ULL(43, 32)
+#define IRDMA_CQPSQ_MVPBP_INV_PD_ENT BIT_ULL(62)
+#define IRDMA_CQPSQ_MVPBP_PD_PLPBA GENMASK_ULL(63, 3)
+
+/* Manage Push Page - MPP */
+#define IRDMA_INVALID_PUSH_PAGE_INDEX_GEN_1 0xffff
+#define IRDMA_INVALID_PUSH_PAGE_INDEX 0xffffffff
+
+#define IRDMA_CQPSQ_MPP_QS_HANDLE GENMASK_ULL(9, 0)
+#define IRDMA_CQPSQ_MPP_PPIDX GENMASK_ULL(9, 0)
+#define IRDMA_CQPSQ_MPP_PPTYPE GENMASK_ULL(61, 60)
+
+#define IRDMA_CQPSQ_MPP_FREE_PAGE BIT_ULL(62)
+
+/* Upload Context - UCTX */
+#define IRDMA_CQPSQ_UCTX_QPCTXADDR IRDMA_CQPHC_QPCTX
+#define IRDMA_CQPSQ_UCTX_QPID GENMASK_ULL(23, 0)
+#define IRDMA_CQPSQ_UCTX_QPTYPE GENMASK_ULL(51, 48)
+
+#define IRDMA_CQPSQ_UCTX_RAWFORMAT BIT_ULL(61)
+#define IRDMA_CQPSQ_UCTX_FREEZEQP BIT_ULL(62)
+
+#define IRDMA_CQPSQ_MHMC_VFIDX GENMASK_ULL(15, 0)
+#define IRDMA_CQPSQ_MHMC_FREEPMFN BIT_ULL(62)
+
+#define IRDMA_CQPSQ_SHMCRP_HMC_PROFILE GENMASK_ULL(2, 0)
+#define IRDMA_CQPSQ_SHMCRP_VFNUM GENMASK_ULL(37, 32)
+#define IRDMA_CQPSQ_CEQ_CEQSIZE GENMASK_ULL(21, 0)
+#define IRDMA_CQPSQ_CEQ_CEQID GENMASK_ULL(9, 0)
+
+#define IRDMA_CQPSQ_CEQ_LPBLSIZE IRDMA_CQPSQ_CQ_LPBLSIZE
+#define IRDMA_CQPSQ_CEQ_VMAP BIT_ULL(47)
+#define IRDMA_CQPSQ_CEQ_ITRNOEXPIRE BIT_ULL(46)
+#define IRDMA_CQPSQ_CEQ_FIRSTPMPBLIDX GENMASK_ULL(27, 0)
+#define IRDMA_CQPSQ_AEQ_AEQECNT GENMASK_ULL(18, 0)
+#define IRDMA_CQPSQ_AEQ_LPBLSIZE IRDMA_CQPSQ_CQ_LPBLSIZE
+#define IRDMA_CQPSQ_AEQ_VMAP BIT_ULL(47)
+#define IRDMA_CQPSQ_AEQ_FIRSTPMPBLIDX GENMASK_ULL(27, 0)
+
+#define IRDMA_COMMIT_FPM_QPCNT GENMASK_ULL(18, 0)
+
+#define IRDMA_COMMIT_FPM_BASE_S 32
+#define IRDMA_CQPSQ_CFPM_HMCFNID GENMASK_ULL(5, 0)
+#define IRDMA_CQPSQ_FWQE_AECODE GENMASK_ULL(15, 0)
+#define IRDMA_CQPSQ_FWQE_AESOURCE GENMASK_ULL(19, 16)
+#define IRDMA_CQPSQ_FWQE_RQMNERR GENMASK_ULL(15, 0)
+#define IRDMA_CQPSQ_FWQE_RQMJERR GENMASK_ULL(31, 16)
+#define IRDMA_CQPSQ_FWQE_SQMNERR GENMASK_ULL(47, 32)
+#define IRDMA_CQPSQ_FWQE_SQMJERR GENMASK_ULL(63, 48)
+#define IRDMA_CQPSQ_FWQE_QPID GENMASK_ULL(23, 0)
+#define IRDMA_CQPSQ_FWQE_GENERATE_AE BIT_ULL(59)
+#define IRDMA_CQPSQ_FWQE_USERFLCODE BIT_ULL(60)
+#define IRDMA_CQPSQ_FWQE_FLUSHSQ BIT_ULL(61)
+#define IRDMA_CQPSQ_FWQE_FLUSHRQ BIT_ULL(62)
+#define IRDMA_CQPSQ_MAPT_PORT GENMASK_ULL(15, 0)
+#define IRDMA_CQPSQ_MAPT_ADDPORT BIT_ULL(62)
+#define IRDMA_CQPSQ_UPESD_SDCMD GENMASK_ULL(31, 0)
+#define IRDMA_CQPSQ_UPESD_SDDATALOW GENMASK_ULL(31, 0)
+#define IRDMA_CQPSQ_UPESD_SDDATAHI GENMASK_ULL(63, 32)
+#define IRDMA_CQPSQ_UPESD_HMCFNID GENMASK_ULL(5, 0)
+#define IRDMA_CQPSQ_UPESD_ENTRY_VALID BIT_ULL(63)
+
+#define IRDMA_CQPSQ_UPESD_BM_PF 0
+#define IRDMA_CQPSQ_UPESD_BM_CP_LM 1
+#define IRDMA_CQPSQ_UPESD_BM_AXF 2
+#define IRDMA_CQPSQ_UPESD_BM_LM 4
+#define IRDMA_CQPSQ_UPESD_BM GENMASK_ULL(34, 32)
+#define IRDMA_CQPSQ_UPESD_ENTRY_COUNT GENMASK_ULL(3, 0)
+#define IRDMA_CQPSQ_UPESD_SKIP_ENTRY BIT_ULL(7)
+#define IRDMA_CQPSQ_SUSPENDQP_QPID GENMASK_ULL(23, 0)
+#define IRDMA_CQPSQ_RESUMEQP_QSHANDLE GENMASK_ULL(31, 0)
+#define IRDMA_CQPSQ_RESUMEQP_QPID GENMASK(23, 0)
+
+#define IRDMA_CQPSQ_MIN_STAG_INVALID 0x0001
+#define IRDMA_CQPSQ_MIN_SUSPEND_PND 0x0005
+
+#define IRDMA_CQPSQ_MAJ_NO_ERROR 0x0000
+#define IRDMA_CQPSQ_MAJ_OBJCACHE_ERROR 0xF000
+#define IRDMA_CQPSQ_MAJ_CNTXTCACHE_ERROR 0xF001
+#define IRDMA_CQPSQ_MAJ_ERROR 0xFFFF
+#define IRDMAQPC_DDP_VER GENMASK_ULL(1, 0)
+#define IRDMAQPC_IBRDENABLE BIT_ULL(2)
+#define IRDMAQPC_IPV4 BIT_ULL(3)
+#define IRDMAQPC_NONAGLE BIT_ULL(4)
+#define IRDMAQPC_INSERTVLANTAG BIT_ULL(5)
+#define IRDMAQPC_ISQP1 BIT_ULL(6)
+#define IRDMAQPC_TIMESTAMP BIT_ULL(7)
+#define IRDMAQPC_RQWQESIZE GENMASK_ULL(9, 8)
+#define IRDMAQPC_INSERTL2TAG2 BIT_ULL(11)
+#define IRDMAQPC_LIMIT GENMASK_ULL(13, 12)
+
+#define IRDMAQPC_ECN_EN BIT_ULL(14)
+#define IRDMAQPC_DROPOOOSEG BIT_ULL(15)
+#define IRDMAQPC_DUPACK_THRESH GENMASK_ULL(18, 16)
+#define IRDMAQPC_ERR_RQ_IDX_VALID BIT_ULL(19)
+#define IRDMAQPC_DIS_VLAN_CHECKS GENMASK_ULL(21, 19)
+#define IRDMAQPC_DC_TCP_EN BIT_ULL(25)
+#define IRDMAQPC_RCVTPHEN BIT_ULL(28)
+#define IRDMAQPC_XMITTPHEN BIT_ULL(29)
+#define IRDMAQPC_RQTPHEN BIT_ULL(30)
+#define IRDMAQPC_SQTPHEN BIT_ULL(31)
+#define IRDMAQPC_PPIDX GENMASK_ULL(41, 32)
+#define IRDMAQPC_PMENA BIT_ULL(47)
+#define IRDMAQPC_RDMAP_VER GENMASK_ULL(63, 62)
+#define IRDMAQPC_ROCE_TVER GENMASK_ULL(63, 60)
+
+#define IRDMAQPC_SQADDR IRDMA_CQPHC_QPCTX
+#define IRDMAQPC_RQADDR IRDMA_CQPHC_QPCTX
+#define IRDMAQPC_TTL GENMASK_ULL(7, 0)
+#define IRDMAQPC_RQSIZE GENMASK_ULL(11, 8)
+#define IRDMAQPC_SQSIZE GENMASK_ULL(15, 12)
+#define IRDMAQPC_GEN1_SRCMACADDRIDX GENMASK(21, 16)
+#define IRDMAQPC_AVOIDSTRETCHACK BIT_ULL(23)
+#define IRDMAQPC_TOS GENMASK_ULL(31, 24)
+#define IRDMAQPC_SRCPORTNUM GENMASK_ULL(47, 32)
+#define IRDMAQPC_DESTPORTNUM GENMASK_ULL(63, 48)
+#define IRDMAQPC_DESTIPADDR0 GENMASK_ULL(63, 32)
+#define IRDMAQPC_DESTIPADDR1 GENMASK_ULL(31, 0)
+#define IRDMAQPC_DESTIPADDR2 GENMASK_ULL(63, 32)
+#define IRDMAQPC_DESTIPADDR3 GENMASK_ULL(31, 0)
+#define IRDMAQPC_SNDMSS GENMASK_ULL(29, 16)
+#define IRDMAQPC_SYN_RST_HANDLING GENMASK_ULL(31, 30)
+#define IRDMAQPC_VLANTAG GENMASK_ULL(47, 32)
+#define IRDMAQPC_ARPIDX GENMASK_ULL(63, 48)
+#define IRDMAQPC_FLOWLABEL GENMASK_ULL(19, 0)
+#define IRDMAQPC_WSCALE BIT_ULL(20)
+#define IRDMAQPC_KEEPALIVE BIT_ULL(21)
+#define IRDMAQPC_IGNORE_TCP_OPT BIT_ULL(22)
+#define IRDMAQPC_IGNORE_TCP_UNS_OPT BIT_ULL(23)
+#define IRDMAQPC_TCPSTATE GENMASK_ULL(31, 28)
+#define IRDMAQPC_RCVSCALE GENMASK_ULL(35, 32)
+#define IRDMAQPC_SNDSCALE GENMASK_ULL(43, 40)
+#define IRDMAQPC_PDIDX GENMASK_ULL(63, 48)
+#define IRDMAQPC_PDIDXHI GENMASK_ULL(21, 20)
+#define IRDMAQPC_PKEY GENMASK_ULL(47, 32)
+#define IRDMAQPC_ACKCREDITS GENMASK_ULL(24, 20)
+#define IRDMAQPC_QKEY GENMASK_ULL(63, 32)
+#define IRDMAQPC_DESTQP GENMASK_ULL(23, 0)
+#define IRDMAQPC_KALIVE_TIMER_MAX_PROBES GENMASK_ULL(23, 16)
+#define IRDMAQPC_KEEPALIVE_INTERVAL GENMASK_ULL(31, 24)
+#define IRDMAQPC_TIMESTAMP_RECENT GENMASK_ULL(31, 0)
+#define IRDMAQPC_TIMESTAMP_AGE GENMASK_ULL(63, 32)
+#define IRDMAQPC_SNDNXT GENMASK_ULL(31, 0)
+#define IRDMAQPC_ISN GENMASK_ULL(55, 32)
+#define IRDMAQPC_PSNNXT GENMASK_ULL(23, 0)
+#define IRDMAQPC_LSN GENMASK_ULL(55, 32)
+#define IRDMAQPC_SNDWND GENMASK_ULL(63, 32)
+#define IRDMAQPC_RCVNXT GENMASK_ULL(31, 0)
+#define IRDMAQPC_EPSN GENMASK_ULL(23, 0)
+#define IRDMAQPC_RCVWND GENMASK_ULL(63, 32)
+#define IRDMAQPC_SNDMAX GENMASK_ULL(31, 0)
+#define IRDMAQPC_SNDUNA GENMASK_ULL(63, 32)
+#define IRDMAQPC_PSNMAX GENMASK_ULL(23, 0)
+#define IRDMAQPC_PSNUNA GENMASK_ULL(55, 32)
+#define IRDMAQPC_SRTT GENMASK_ULL(31, 0)
+#define IRDMAQPC_RTTVAR GENMASK_ULL(63, 32)
+#define IRDMAQPC_SSTHRESH GENMASK_ULL(31, 0)
+#define IRDMAQPC_CWND GENMASK_ULL(63, 32)
+#define IRDMAQPC_CWNDROCE GENMASK_ULL(55, 32)
+#define IRDMAQPC_SNDWL1 GENMASK_ULL(31, 0)
+#define IRDMAQPC_SNDWL2 GENMASK_ULL(63, 32)
+#define IRDMAQPC_ERR_RQ_IDX GENMASK_ULL(45, 32)
+#define IRDMAQPC_RTOMIN GENMASK_ULL(63, 57)
+#define IRDMAQPC_MAXSNDWND GENMASK_ULL(31, 0)
+#define IRDMAQPC_REXMIT_THRESH GENMASK_ULL(53, 48)
+#define IRDMAQPC_RNRNAK_THRESH GENMASK_ULL(56, 54)
+#define IRDMAQPC_TXCQNUM GENMASK_ULL(18, 0)
+#define IRDMAQPC_RXCQNUM GENMASK_ULL(50, 32)
+#define IRDMAQPC_STAT_INDEX GENMASK_ULL(6, 0)
+#define IRDMAQPC_Q2ADDR GENMASK_ULL(63, 8)
+#define IRDMAQPC_LASTBYTESENT GENMASK_ULL(7, 0)
+#define IRDMAQPC_MACADDRESS GENMASK_ULL(63, 16)
+#define IRDMAQPC_ORDSIZE GENMASK_ULL(7, 0)
+
+#define IRDMAQPC_IRDSIZE GENMASK_ULL(18, 16)
+
+#define IRDMAQPC_UDPRIVCQENABLE BIT_ULL(19)
+#define IRDMAQPC_WRRDRSPOK BIT_ULL(20)
+#define IRDMAQPC_RDOK BIT_ULL(21)
+#define IRDMAQPC_SNDMARKERS BIT_ULL(22)
+#define IRDMAQPC_DCQCNENABLE BIT_ULL(22)
+#define IRDMAQPC_FW_CC_ENABLE BIT_ULL(28)
+#define IRDMAQPC_RCVNOICRC BIT_ULL(31)
+#define IRDMAQPC_BINDEN BIT_ULL(23)
+#define IRDMAQPC_FASTREGEN BIT_ULL(24)
+#define IRDMAQPC_PRIVEN BIT_ULL(25)
+#define IRDMAQPC_TIMELYENABLE BIT_ULL(27)
+#define IRDMAQPC_THIGH GENMASK_ULL(63, 52)
+#define IRDMAQPC_TLOW GENMASK_ULL(39, 32)
+#define IRDMAQPC_REMENDPOINTIDX GENMASK_ULL(16, 0)
+#define IRDMAQPC_USESTATSINSTANCE BIT_ULL(26)
+#define IRDMAQPC_IWARPMODE BIT_ULL(28)
+#define IRDMAQPC_RCVMARKERS BIT_ULL(29)
+#define IRDMAQPC_ALIGNHDRS BIT_ULL(30)
+#define IRDMAQPC_RCVNOMPACRC BIT_ULL(31)
+#define IRDMAQPC_RCVMARKOFFSET GENMASK_ULL(40, 32)
+#define IRDMAQPC_SNDMARKOFFSET GENMASK_ULL(56, 48)
+
+#define IRDMAQPC_QPCOMPCTX IRDMA_CQPHC_QPCTX
+#define IRDMAQPC_SQTPHVAL GENMASK_ULL(7, 0)
+#define IRDMAQPC_RQTPHVAL GENMASK_ULL(15, 8)
+#define IRDMAQPC_QSHANDLE GENMASK_ULL(25, 16)
+#define IRDMAQPC_EXCEPTION_LAN_QUEUE GENMASK_ULL(43, 32)
+#define IRDMAQPC_LOCAL_IPADDR3 GENMASK_ULL(31, 0)
+#define IRDMAQPC_LOCAL_IPADDR2 GENMASK_ULL(63, 32)
+#define IRDMAQPC_LOCAL_IPADDR1 GENMASK_ULL(31, 0)
+#define IRDMAQPC_LOCAL_IPADDR0 GENMASK_ULL(63, 32)
+#define IRDMA_FW_VER_MINOR GENMASK_ULL(15, 0)
+#define IRDMA_FW_VER_MAJOR GENMASK_ULL(31, 16)
+#define IRDMA_FEATURE_INFO GENMASK_ULL(47, 0)
+#define IRDMA_FEATURE_CNT GENMASK_ULL(47, 32)
+#define IRDMA_FEATURE_TYPE GENMASK_ULL(63, 48)
+
+#define IRDMAQPSQ_OPCODE GENMASK_ULL(37, 32)
+#define IRDMAQPSQ_COPY_HOST_PBL BIT_ULL(43)
+#define IRDMAQPSQ_ADDFRAGCNT GENMASK_ULL(41, 38)
+#define IRDMAQPSQ_PUSHWQE BIT_ULL(56)
+#define IRDMAQPSQ_STREAMMODE BIT_ULL(58)
+#define IRDMAQPSQ_WAITFORRCVPDU BIT_ULL(59)
+#define IRDMAQPSQ_READFENCE BIT_ULL(60)
+#define IRDMAQPSQ_LOCALFENCE BIT_ULL(61)
+#define IRDMAQPSQ_UDPHEADER BIT_ULL(61)
+#define IRDMAQPSQ_L4LEN GENMASK_ULL(45, 42)
+#define IRDMAQPSQ_SIGCOMPL BIT_ULL(62)
+#define IRDMAQPSQ_VALID BIT_ULL(63)
+
+#define IRDMAQPSQ_FRAG_TO IRDMA_CQPHC_QPCTX
+#define IRDMAQPSQ_FRAG_VALID BIT_ULL(63)
+#define IRDMAQPSQ_FRAG_LEN GENMASK_ULL(62, 32)
+#define IRDMAQPSQ_FRAG_STAG GENMASK_ULL(31, 0)
+#define IRDMAQPSQ_GEN1_FRAG_LEN GENMASK_ULL(31, 0)
+#define IRDMAQPSQ_GEN1_FRAG_STAG GENMASK_ULL(63, 32)
+#define IRDMAQPSQ_REMSTAGINV GENMASK_ULL(31, 0)
+#define IRDMAQPSQ_DESTQKEY GENMASK_ULL(31, 0)
+#define IRDMAQPSQ_DESTQPN GENMASK_ULL(55, 32)
+#define IRDMAQPSQ_AHID GENMASK_ULL(16, 0)
+#define IRDMAQPSQ_INLINEDATAFLAG BIT_ULL(57)
+
+#define IRDMA_INLINE_VALID_S 7
+#define IRDMAQPSQ_INLINEDATALEN GENMASK_ULL(55, 48)
+#define IRDMAQPSQ_IMMDATAFLAG BIT_ULL(47)
+#define IRDMAQPSQ_REPORTRTT BIT_ULL(46)
+
+#define IRDMAQPSQ_IMMDATA GENMASK_ULL(63, 0)
+#define IRDMAQPSQ_REMSTAG GENMASK_ULL(31, 0)
+
+#define IRDMAQPSQ_REMTO IRDMA_CQPHC_QPCTX
+
+#define IRDMAQPSQ_STAGRIGHTS GENMASK_ULL(52, 48)
+#define IRDMAQPSQ_VABASEDTO BIT_ULL(53)
+#define IRDMAQPSQ_MEMWINDOWTYPE BIT_ULL(54)
+
+#define IRDMAQPSQ_MWLEN IRDMA_CQPHC_QPCTX
+#define IRDMAQPSQ_PARENTMRSTAG GENMASK_ULL(63, 32)
+#define IRDMAQPSQ_MWSTAG GENMASK_ULL(31, 0)
+
+#define IRDMAQPSQ_BASEVA_TO_FBO IRDMA_CQPHC_QPCTX
+
+#define IRDMAQPSQ_LOCSTAG GENMASK_ULL(31, 0)
+
+#define IRDMAQPSQ_STAGKEY GENMASK_ULL(7, 0)
+#define IRDMAQPSQ_STAGINDEX GENMASK_ULL(31, 8)
+#define IRDMAQPSQ_COPYHOSTPBLS BIT_ULL(43)
+#define IRDMAQPSQ_LPBLSIZE GENMASK_ULL(45, 44)
+#define IRDMAQPSQ_HPAGESIZE GENMASK_ULL(47, 46)
+#define IRDMAQPSQ_STAGLEN GENMASK_ULL(40, 0)
+#define IRDMAQPSQ_FIRSTPMPBLIDXLO GENMASK_ULL(63, 48)
+#define IRDMAQPSQ_FIRSTPMPBLIDXHI GENMASK_ULL(11, 0)
+#define IRDMAQPSQ_PBLADDR GENMASK_ULL(63, 12)
+
+/* iwarp QP RQ WQE common fields */
+#define IRDMAQPRQ_ADDFRAGCNT IRDMAQPSQ_ADDFRAGCNT
+#define IRDMAQPRQ_VALID IRDMAQPSQ_VALID
+#define IRDMAQPRQ_COMPLCTX IRDMA_CQPHC_QPCTX
+#define IRDMAQPRQ_FRAG_LEN IRDMAQPSQ_FRAG_LEN
+#define IRDMAQPRQ_STAG IRDMAQPSQ_FRAG_STAG
+#define IRDMAQPRQ_TO IRDMAQPSQ_FRAG_TO
+
+#define IRDMAPFINT_OICR_HMC_ERR_M BIT(26)
+#define IRDMAPFINT_OICR_PE_PUSH_M BIT(27)
+#define IRDMAPFINT_OICR_PE_CRITERR_M BIT(28)
+
+#define IRDMA_QUERY_FPM_MAX_QPS GENMASK_ULL(18, 0)
+#define IRDMA_QUERY_FPM_MAX_CQS GENMASK_ULL(19, 0)
+#define IRDMA_QUERY_FPM_FIRST_PE_SD_INDEX GENMASK_ULL(13, 0)
+#define IRDMA_QUERY_FPM_MAX_PE_SDS GENMASK_ULL(45, 32)
+#define IRDMA_QUERY_FPM_MAX_CEQS GENMASK_ULL(9, 0)
+#define IRDMA_QUERY_FPM_XFBLOCKSIZE GENMASK_ULL(63, 32)
+#define IRDMA_QUERY_FPM_Q1BLOCKSIZE GENMASK_ULL(63, 32)
+#define IRDMA_QUERY_FPM_HTMULTIPLIER GENMASK_ULL(19, 16)
+#define IRDMA_QUERY_FPM_TIMERBUCKET GENMASK_ULL(47, 32)
+#define IRDMA_QUERY_FPM_RRFBLOCKSIZE GENMASK_ULL(63, 32)
+#define IRDMA_QUERY_FPM_RRFFLBLOCKSIZE GENMASK_ULL(63, 32)
+#define IRDMA_QUERY_FPM_OOISCFBLOCKSIZE GENMASK_ULL(63, 32)
+#define IRDMA_SHMC_PAGE_ALLOCATED_HMC_FN_ID GENMASK_ULL(5, 0)
+
+#define IRDMA_GET_CURRENT_AEQ_ELEM(_aeq) \
+ ( \
+ (_aeq)->aeqe_base[IRDMA_RING_CURRENT_TAIL((_aeq)->aeq_ring)].buf \
+ )
+
+#define IRDMA_GET_CURRENT_CEQ_ELEM(_ceq) \
+ ( \
+ (_ceq)->ceqe_base[IRDMA_RING_CURRENT_TAIL((_ceq)->ceq_ring)].buf \
+ )
+
+#define IRDMA_GET_CEQ_ELEM_AT_POS(_ceq, _pos) \
+ ( \
+ (_ceq)->ceqe_base[_pos].buf \
+ )
+
+#define IRDMA_RING_GET_NEXT_TAIL(_ring, _idx) \
+ ( \
+ ((_ring).tail + (_idx)) % (_ring).size \
+ )
+
+#define IRDMA_CQP_INIT_WQE(wqe) memset(wqe, 0, 64)
+
+#define IRDMA_GET_CURRENT_CQ_ELEM(_cq) \
+ ( \
+ (_cq)->cq_base[IRDMA_RING_CURRENT_HEAD((_cq)->cq_ring)].buf \
+ )
+#define IRDMA_GET_CURRENT_EXTENDED_CQ_ELEM(_cq) \
+ ( \
+ ((struct irdma_extended_cqe *) \
+ ((_cq)->cq_base))[IRDMA_RING_CURRENT_HEAD((_cq)->cq_ring)].buf \
+ )
+
+#define IRDMA_RING_INIT(_ring, _size) \
+ { \
+ (_ring).head = 0; \
+ (_ring).tail = 0; \
+ (_ring).size = (_size); \
+ }
+#define IRDMA_RING_SIZE(_ring) ((_ring).size)
+#define IRDMA_RING_CURRENT_HEAD(_ring) ((_ring).head)
+#define IRDMA_RING_CURRENT_TAIL(_ring) ((_ring).tail)
+
+#define IRDMA_RING_MOVE_HEAD(_ring, _retcode) \
+ { \
+ register u32 size; \
+ size = (_ring).size; \
+ if (!IRDMA_RING_FULL_ERR(_ring)) { \
+ (_ring).head = ((_ring).head + 1) % size; \
+ (_retcode) = 0; \
+ } else { \
+ (_retcode) = IRDMA_ERR_RING_FULL; \
+ } \
+ }
+#define IRDMA_RING_MOVE_HEAD_BY_COUNT(_ring, _count, _retcode) \
+ { \
+ register u32 size; \
+ size = (_ring).size; \
+ if ((IRDMA_RING_USED_QUANTA(_ring) + (_count)) < size) { \
+ (_ring).head = ((_ring).head + (_count)) % size; \
+ (_retcode) = 0; \
+ } else { \
+ (_retcode) = IRDMA_ERR_RING_FULL; \
+ } \
+ }
+#define IRDMA_SQ_RING_MOVE_HEAD(_ring, _retcode) \
+ { \
+ register u32 size; \
+ size = (_ring).size; \
+ if (!IRDMA_SQ_RING_FULL_ERR(_ring)) { \
+ (_ring).head = ((_ring).head + 1) % size; \
+ (_retcode) = 0; \
+ } else { \
+ (_retcode) = IRDMA_ERR_RING_FULL; \
+ } \
+ }
+#define IRDMA_SQ_RING_MOVE_HEAD_BY_COUNT(_ring, _count, _retcode) \
+ { \
+ register u32 size; \
+ size = (_ring).size; \
+ if ((IRDMA_RING_USED_QUANTA(_ring) + (_count)) < (size - 256)) { \
+ (_ring).head = ((_ring).head + (_count)) % size; \
+ (_retcode) = 0; \
+ } else { \
+ (_retcode) = IRDMA_ERR_RING_FULL; \
+ } \
+ }
+#define IRDMA_RING_MOVE_HEAD_BY_COUNT_NOCHECK(_ring, _count) \
+ (_ring).head = ((_ring).head + (_count)) % (_ring).size
+
+#define IRDMA_RING_MOVE_TAIL(_ring) \
+ (_ring).tail = ((_ring).tail + 1) % (_ring).size
+
+#define IRDMA_RING_MOVE_HEAD_NOCHECK(_ring) \
+ (_ring).head = ((_ring).head + 1) % (_ring).size
+
+#define IRDMA_RING_MOVE_TAIL_BY_COUNT(_ring, _count) \
+ (_ring).tail = ((_ring).tail + (_count)) % (_ring).size
+
+#define IRDMA_RING_SET_TAIL(_ring, _pos) \
+ (_ring).tail = (_pos) % (_ring).size
+
+#define IRDMA_RING_FULL_ERR(_ring) \
+ ( \
+ (IRDMA_RING_USED_QUANTA(_ring) == ((_ring).size - 1)) \
+ )
+
+#define IRDMA_ERR_RING_FULL2(_ring) \
+ ( \
+ (IRDMA_RING_USED_QUANTA(_ring) == ((_ring).size - 2)) \
+ )
+
+#define IRDMA_ERR_RING_FULL3(_ring) \
+ ( \
+ (IRDMA_RING_USED_QUANTA(_ring) == ((_ring).size - 3)) \
+ )
+
+#define IRDMA_SQ_RING_FULL_ERR(_ring) \
+ ( \
+ (IRDMA_RING_USED_QUANTA(_ring) == ((_ring).size - 257)) \
+ )
+
+#define IRDMA_ERR_SQ_RING_FULL2(_ring) \
+ ( \
+ (IRDMA_RING_USED_QUANTA(_ring) == ((_ring).size - 258)) \
+ )
+#define IRDMA_ERR_SQ_RING_FULL3(_ring) \
+ ( \
+ (IRDMA_RING_USED_QUANTA(_ring) == ((_ring).size - 259)) \
+ )
+#define IRDMA_RING_MORE_WORK(_ring) \
+ ( \
+ (IRDMA_RING_USED_QUANTA(_ring) != 0) \
+ )
+
+#define IRDMA_RING_USED_QUANTA(_ring) \
+ ( \
+ (((_ring).head + (_ring).size - (_ring).tail) % (_ring).size) \
+ )
+
+#define IRDMA_RING_FREE_QUANTA(_ring) \
+ ( \
+ ((_ring).size - IRDMA_RING_USED_QUANTA(_ring) - 1) \
+ )
+
+#define IRDMA_SQ_RING_FREE_QUANTA(_ring) \
+ ( \
+ ((_ring).size - IRDMA_RING_USED_QUANTA(_ring) - 257) \
+ )
+
+#define IRDMA_ATOMIC_RING_MOVE_HEAD(_ring, index, _retcode) \
+ { \
+ index = IRDMA_RING_CURRENT_HEAD(_ring); \
+ IRDMA_RING_MOVE_HEAD(_ring, _retcode); \
+ }
+
+enum irdma_qp_wqe_size {
+ IRDMA_WQE_SIZE_32 = 32,
+ IRDMA_WQE_SIZE_64 = 64,
+ IRDMA_WQE_SIZE_96 = 96,
+ IRDMA_WQE_SIZE_128 = 128,
+ IRDMA_WQE_SIZE_256 = 256,
+};
+
+enum irdma_ws_node_op {
+ IRDMA_ADD_NODE = 0,
+ IRDMA_MODIFY_NODE,
+ IRDMA_DEL_NODE,
+};
+
+enum { IRDMA_Q_ALIGNMENT_M = (128 - 1),
+ IRDMA_AEQ_ALIGNMENT_M = (256 - 1),
+ IRDMA_Q2_ALIGNMENT_M = (256 - 1),
+ IRDMA_CEQ_ALIGNMENT_M = (256 - 1),
+ IRDMA_CQ0_ALIGNMENT_M = (256 - 1),
+ IRDMA_HOST_CTX_ALIGNMENT_M = (4 - 1),
+ IRDMA_SHADOWAREA_M = (128 - 1),
+ IRDMA_FPM_QUERY_BUF_ALIGNMENT_M = (4 - 1),
+ IRDMA_FPM_COMMIT_BUF_ALIGNMENT_M = (4 - 1),
+};
+
+enum irdma_alignment {
+ IRDMA_CQP_ALIGNMENT = 0x200,
+ IRDMA_AEQ_ALIGNMENT = 0x100,
+ IRDMA_CEQ_ALIGNMENT = 0x100,
+ IRDMA_CQ0_ALIGNMENT = 0x100,
+ IRDMA_SD_BUF_ALIGNMENT = 0x80,
+ IRDMA_FEATURE_BUF_ALIGNMENT = 0x8,
+};
+
+enum icrdma_protocol_used {
+ ICRDMA_ANY_PROTOCOL = 0,
+ ICRDMA_IWARP_PROTOCOL_ONLY = 1,
+ ICRDMA_ROCE_PROTOCOL_ONLY = 2,
+};
+
+/**
+ * set_64bit_val - set 64 bit value to hw wqe
+ * @wqe_words: wqe addr to write
+ * @byte_index: index in wqe
+ * @val: value to write
+ **/
+static inline void set_64bit_val(__le64 *wqe_words, u32 byte_index, u64 val)
+{
+ wqe_words[byte_index >> 3] = cpu_to_le64(val);
+}
+
+/**
+ * set_32bit_val - set 32 bit value to hw wqe
+ * @wqe_words: wqe addr to write
+ * @byte_index: index in wqe
+ * @val: value to write
+ **/
+static inline void set_32bit_val(__le32 *wqe_words, u32 byte_index, u32 val)
+{
+ wqe_words[byte_index >> 2] = cpu_to_le32(val);
+}
+
+/**
+ * get_64bit_val - read 64 bit value from wqe
+ * @wqe_words: wqe addr
+ * @byte_index: index to read from
+ * @val: read value
+ **/
+static inline void get_64bit_val(__le64 *wqe_words, u32 byte_index, u64 *val)
+{
+ *val = le64_to_cpu(wqe_words[byte_index >> 3]);
+}
+
+/**
+ * get_32bit_val - read 32 bit value from wqe
+ * @wqe_words: wqe addr
+ * @byte_index: index to reaad from
+ * @val: return 32 bit value
+ **/
+static inline void get_32bit_val(__le32 *wqe_words, u32 byte_index, u32 *val)
+{
+ *val = le32_to_cpu(wqe_words[byte_index >> 2]);
+}
+#endif /* IRDMA_DEFS_H */
diff --git a/drivers/infiniband/hw/irdma/hmc.c b/drivers/infiniband/hw/irdma/hmc.c
new file mode 100644
index 000000000000..ecffcb93c05a
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/hmc.c
@@ -0,0 +1,710 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#include "osdep.h"
+#include "status.h"
+#include "hmc.h"
+#include "defs.h"
+#include "type.h"
+#include "protos.h"
+
+/**
+ * irdma_find_sd_index_limit - finds segment descriptor index limit
+ * @hmc_info: pointer to the HMC configuration information structure
+ * @type: type of HMC resources we're searching
+ * @idx: starting index for the object
+ * @cnt: number of objects we're trying to create
+ * @sd_idx: pointer to return index of the segment descriptor in question
+ * @sd_limit: pointer to return the maximum number of segment descriptors
+ *
+ * This function calculates the segment descriptor index and index limit
+ * for the resource defined by irdma_hmc_rsrc_type.
+ */
+
+static void irdma_find_sd_index_limit(struct irdma_hmc_info *hmc_info, u32 type,
+ u32 idx, u32 cnt, u32 *sd_idx,
+ u32 *sd_limit)
+{
+ u64 fpm_addr, fpm_limit;
+
+ fpm_addr = hmc_info->hmc_obj[(type)].base +
+ hmc_info->hmc_obj[type].size * idx;
+ fpm_limit = fpm_addr + hmc_info->hmc_obj[type].size * cnt;
+ *sd_idx = (u32)(fpm_addr / IRDMA_HMC_DIRECT_BP_SIZE);
+ *sd_limit = (u32)((fpm_limit - 1) / IRDMA_HMC_DIRECT_BP_SIZE);
+ *sd_limit += 1;
+}
+
+/**
+ * irdma_find_pd_index_limit - finds page descriptor index limit
+ * @hmc_info: pointer to the HMC configuration information struct
+ * @type: HMC resource type we're examining
+ * @idx: starting index for the object
+ * @cnt: number of objects we're trying to create
+ * @pd_idx: pointer to return page descriptor index
+ * @pd_limit: pointer to return page descriptor index limit
+ *
+ * Calculates the page descriptor index and index limit for the resource
+ * defined by irdma_hmc_rsrc_type.
+ */
+
+static void irdma_find_pd_index_limit(struct irdma_hmc_info *hmc_info, u32 type,
+ u32 idx, u32 cnt, u32 *pd_idx,
+ u32 *pd_limit)
+{
+ u64 fpm_adr, fpm_limit;
+
+ fpm_adr = hmc_info->hmc_obj[type].base +
+ hmc_info->hmc_obj[type].size * idx;
+ fpm_limit = fpm_adr + (hmc_info)->hmc_obj[(type)].size * (cnt);
+ *pd_idx = (u32)(fpm_adr / IRDMA_HMC_PAGED_BP_SIZE);
+ *pd_limit = (u32)((fpm_limit - 1) / IRDMA_HMC_PAGED_BP_SIZE);
+ *pd_limit += 1;
+}
+
+/**
+ * irdma_set_sd_entry - setup entry for sd programming
+ * @pa: physical addr
+ * @idx: sd index
+ * @type: paged or direct sd
+ * @entry: sd entry ptr
+ */
+static void irdma_set_sd_entry(u64 pa, u32 idx, enum irdma_sd_entry_type type,
+ struct irdma_update_sd_entry *entry)
+{
+ entry->data = pa |
+ FIELD_PREP(IRDMA_PFHMC_SDDATALOW_PMSDBPCOUNT, IRDMA_HMC_MAX_BP_COUNT) |
+ FIELD_PREP(IRDMA_PFHMC_SDDATALOW_PMSDTYPE,
+ type == IRDMA_SD_TYPE_PAGED ? 0 : 1) |
+ FIELD_PREP(IRDMA_PFHMC_SDDATALOW_PMSDVALID, 1);
+
+ entry->cmd = idx | FIELD_PREP(IRDMA_PFHMC_SDCMD_PMSDWR, 1) | BIT(15);
+}
+
+/**
+ * irdma_clr_sd_entry - setup entry for sd clear
+ * @idx: sd index
+ * @type: paged or direct sd
+ * @entry: sd entry ptr
+ */
+static void irdma_clr_sd_entry(u32 idx, enum irdma_sd_entry_type type,
+ struct irdma_update_sd_entry *entry)
+{
+ entry->data = FIELD_PREP(IRDMA_PFHMC_SDDATALOW_PMSDBPCOUNT, IRDMA_HMC_MAX_BP_COUNT) |
+ FIELD_PREP(IRDMA_PFHMC_SDDATALOW_PMSDTYPE,
+ type == IRDMA_SD_TYPE_PAGED ? 0 : 1);
+
+ entry->cmd = idx | FIELD_PREP(IRDMA_PFHMC_SDCMD_PMSDWR, 1) | BIT(15);
+}
+
+/**
+ * irdma_invalidate_pf_hmc_pd - Invalidates the pd cache in the hardware for PF
+ * @dev: pointer to our device struct
+ * @sd_idx: segment descriptor index
+ * @pd_idx: page descriptor index
+ */
+static inline void irdma_invalidate_pf_hmc_pd(struct irdma_sc_dev *dev, u32 sd_idx,
+ u32 pd_idx)
+{
+ u32 val = FIELD_PREP(IRDMA_PFHMC_PDINV_PMSDIDX, sd_idx) |
+ FIELD_PREP(IRDMA_PFHMC_PDINV_PMSDPARTSEL, 1) |
+ FIELD_PREP(IRDMA_PFHMC_PDINV_PMPDIDX, pd_idx);
+
+ writel(val, dev->hw_regs[IRDMA_PFHMC_PDINV]);
+}
+
+/**
+ * irdma_hmc_sd_one - setup 1 sd entry for cqp
+ * @dev: pointer to the device structure
+ * @hmc_fn_id: hmc's function id
+ * @pa: physical addr
+ * @sd_idx: sd index
+ * @type: paged or direct sd
+ * @setsd: flag to set or clear sd
+ */
+enum irdma_status_code irdma_hmc_sd_one(struct irdma_sc_dev *dev, u8 hmc_fn_id,
+ u64 pa, u32 sd_idx,
+ enum irdma_sd_entry_type type,
+ bool setsd)
+{
+ struct irdma_update_sds_info sdinfo;
+
+ sdinfo.cnt = 1;
+ sdinfo.hmc_fn_id = hmc_fn_id;
+ if (setsd)
+ irdma_set_sd_entry(pa, sd_idx, type, sdinfo.entry);
+ else
+ irdma_clr_sd_entry(sd_idx, type, sdinfo.entry);
+ return dev->cqp->process_cqp_sds(dev, &sdinfo);
+}
+
+/**
+ * irdma_hmc_sd_grp - setup group of sd entries for cqp
+ * @dev: pointer to the device structure
+ * @hmc_info: pointer to the HMC configuration information struct
+ * @sd_index: sd index
+ * @sd_cnt: number of sd entries
+ * @setsd: flag to set or clear sd
+ */
+static enum irdma_status_code irdma_hmc_sd_grp(struct irdma_sc_dev *dev,
+ struct irdma_hmc_info *hmc_info,
+ u32 sd_index, u32 sd_cnt,
+ bool setsd)
+{
+ struct irdma_hmc_sd_entry *sd_entry;
+ struct irdma_update_sds_info sdinfo = {};
+ u64 pa;
+ u32 i;
+ enum irdma_status_code ret_code = 0;
+
+ sdinfo.hmc_fn_id = hmc_info->hmc_fn_id;
+ for (i = sd_index; i < sd_index + sd_cnt; i++) {
+ sd_entry = &hmc_info->sd_table.sd_entry[i];
+ if (!sd_entry || (!sd_entry->valid && setsd) ||
+ (sd_entry->valid && !setsd))
+ continue;
+ if (setsd) {
+ pa = (sd_entry->entry_type == IRDMA_SD_TYPE_PAGED) ?
+ sd_entry->u.pd_table.pd_page_addr.pa :
+ sd_entry->u.bp.addr.pa;
+ irdma_set_sd_entry(pa, i, sd_entry->entry_type,
+ &sdinfo.entry[sdinfo.cnt]);
+ } else {
+ irdma_clr_sd_entry(i, sd_entry->entry_type,
+ &sdinfo.entry[sdinfo.cnt]);
+ }
+ sdinfo.cnt++;
+ if (sdinfo.cnt == IRDMA_MAX_SD_ENTRIES) {
+ ret_code = dev->cqp->process_cqp_sds(dev, &sdinfo);
+ if (ret_code) {
+ ibdev_dbg(to_ibdev(dev),
+ "HMC: sd_programming failed err=%d\n",
+ ret_code);
+ return ret_code;
+ }
+
+ sdinfo.cnt = 0;
+ }
+ }
+ if (sdinfo.cnt)
+ ret_code = dev->cqp->process_cqp_sds(dev, &sdinfo);
+
+ return ret_code;
+}
+
+/**
+ * irdma_hmc_finish_add_sd_reg - program sd entries for objects
+ * @dev: pointer to the device structure
+ * @info: create obj info
+ */
+static enum irdma_status_code
+irdma_hmc_finish_add_sd_reg(struct irdma_sc_dev *dev,
+ struct irdma_hmc_create_obj_info *info)
+{
+ if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt)
+ return IRDMA_ERR_INVALID_HMC_OBJ_INDEX;
+
+ if ((info->start_idx + info->count) >
+ info->hmc_info->hmc_obj[info->rsrc_type].cnt)
+ return IRDMA_ERR_INVALID_HMC_OBJ_COUNT;
+
+ if (!info->add_sd_cnt)
+ return 0;
+ return irdma_hmc_sd_grp(dev, info->hmc_info,
+ info->hmc_info->sd_indexes[0], info->add_sd_cnt,
+ true);
+}
+
+/**
+ * irdma_sc_create_hmc_obj - allocate backing store for hmc objects
+ * @dev: pointer to the device structure
+ * @info: pointer to irdma_hmc_create_obj_info struct
+ *
+ * This will allocate memory for PDs and backing pages and populate
+ * the sd and pd entries.
+ */
+enum irdma_status_code
+irdma_sc_create_hmc_obj(struct irdma_sc_dev *dev,
+ struct irdma_hmc_create_obj_info *info)
+{
+ struct irdma_hmc_sd_entry *sd_entry;
+ u32 sd_idx, sd_lmt;
+ u32 pd_idx = 0, pd_lmt = 0;
+ u32 pd_idx1 = 0, pd_lmt1 = 0;
+ u32 i, j;
+ bool pd_error = false;
+ enum irdma_status_code ret_code = 0;
+
+ if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt)
+ return IRDMA_ERR_INVALID_HMC_OBJ_INDEX;
+
+ if ((info->start_idx + info->count) >
+ info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
+ ibdev_dbg(to_ibdev(dev),
+ "HMC: error type %u, start = %u, req cnt %u, cnt = %u\n",
+ info->rsrc_type, info->start_idx, info->count,
+ info->hmc_info->hmc_obj[info->rsrc_type].cnt);
+ return IRDMA_ERR_INVALID_HMC_OBJ_COUNT;
+ }
+
+ irdma_find_sd_index_limit(info->hmc_info, info->rsrc_type,
+ info->start_idx, info->count, &sd_idx,
+ &sd_lmt);
+ if (sd_idx >= info->hmc_info->sd_table.sd_cnt ||
+ sd_lmt > info->hmc_info->sd_table.sd_cnt) {
+ return IRDMA_ERR_INVALID_SD_INDEX;
+ }
+
+ irdma_find_pd_index_limit(info->hmc_info, info->rsrc_type,
+ info->start_idx, info->count, &pd_idx,
+ &pd_lmt);
+
+ for (j = sd_idx; j < sd_lmt; j++) {
+ ret_code = irdma_add_sd_table_entry(dev->hw, info->hmc_info, j,
+ info->entry_type,
+ IRDMA_HMC_DIRECT_BP_SIZE);
+ if (ret_code)
+ goto exit_sd_error;
+
+ sd_entry = &info->hmc_info->sd_table.sd_entry[j];
+ if (sd_entry->entry_type == IRDMA_SD_TYPE_PAGED &&
+ (dev->hmc_info == info->hmc_info &&
+ info->rsrc_type != IRDMA_HMC_IW_PBLE)) {
+ pd_idx1 = max(pd_idx, (j * IRDMA_HMC_MAX_BP_COUNT));
+ pd_lmt1 = min(pd_lmt, (j + 1) * IRDMA_HMC_MAX_BP_COUNT);
+ for (i = pd_idx1; i < pd_lmt1; i++) {
+ /* update the pd table entry */
+ ret_code = irdma_add_pd_table_entry(dev,
+ info->hmc_info,
+ i, NULL);
+ if (ret_code) {
+ pd_error = true;
+ break;
+ }
+ }
+ if (pd_error) {
+ while (i && (i > pd_idx1)) {
+ irdma_remove_pd_bp(dev, info->hmc_info,
+ i - 1);
+ i--;
+ }
+ }
+ }
+ if (sd_entry->valid)
+ continue;
+
+ info->hmc_info->sd_indexes[info->add_sd_cnt] = (u16)j;
+ info->add_sd_cnt++;
+ sd_entry->valid = true;
+ }
+ return irdma_hmc_finish_add_sd_reg(dev, info);
+
+exit_sd_error:
+ while (j && (j > sd_idx)) {
+ sd_entry = &info->hmc_info->sd_table.sd_entry[j - 1];
+ switch (sd_entry->entry_type) {
+ case IRDMA_SD_TYPE_PAGED:
+ pd_idx1 = max(pd_idx, (j - 1) * IRDMA_HMC_MAX_BP_COUNT);
+ pd_lmt1 = min(pd_lmt, (j * IRDMA_HMC_MAX_BP_COUNT));
+ for (i = pd_idx1; i < pd_lmt1; i++)
+ irdma_prep_remove_pd_page(info->hmc_info, i);
+ break;
+ case IRDMA_SD_TYPE_DIRECT:
+ irdma_prep_remove_pd_page(info->hmc_info, (j - 1));
+ break;
+ default:
+ ret_code = IRDMA_ERR_INVALID_SD_TYPE;
+ break;
+ }
+ j--;
+ }
+
+ return ret_code;
+}
+
+/**
+ * irdma_finish_del_sd_reg - delete sd entries for objects
+ * @dev: pointer to the device structure
+ * @info: dele obj info
+ * @reset: true if called before reset
+ */
+static enum irdma_status_code
+irdma_finish_del_sd_reg(struct irdma_sc_dev *dev,
+ struct irdma_hmc_del_obj_info *info, bool reset)
+{
+ struct irdma_hmc_sd_entry *sd_entry;
+ enum irdma_status_code ret_code = 0;
+ u32 i, sd_idx;
+ struct irdma_dma_mem *mem;
+
+ if (!reset)
+ ret_code = irdma_hmc_sd_grp(dev, info->hmc_info,
+ info->hmc_info->sd_indexes[0],
+ info->del_sd_cnt, false);
+
+ if (ret_code)
+ ibdev_dbg(to_ibdev(dev), "HMC: error cqp sd sd_grp\n");
+ for (i = 0; i < info->del_sd_cnt; i++) {
+ sd_idx = info->hmc_info->sd_indexes[i];
+ sd_entry = &info->hmc_info->sd_table.sd_entry[sd_idx];
+ mem = (sd_entry->entry_type == IRDMA_SD_TYPE_PAGED) ?
+ &sd_entry->u.pd_table.pd_page_addr :
+ &sd_entry->u.bp.addr;
+
+ if (!mem || !mem->va) {
+ ibdev_dbg(to_ibdev(dev), "HMC: error cqp sd mem\n");
+ } else {
+ dma_free_coherent(dev->hw->device, mem->size, mem->va,
+ mem->pa);
+ mem->va = NULL;
+ }
+ }
+
+ return ret_code;
+}
+
+/**
+ * irdma_sc_del_hmc_obj - remove pe hmc objects
+ * @dev: pointer to the device structure
+ * @info: pointer to irdma_hmc_del_obj_info struct
+ * @reset: true if called before reset
+ *
+ * This will de-populate the SDs and PDs. It frees
+ * the memory for PDS and backing storage. After this function is returned,
+ * caller should deallocate memory allocated previously for
+ * book-keeping information about PDs and backing storage.
+ */
+enum irdma_status_code irdma_sc_del_hmc_obj(struct irdma_sc_dev *dev,
+ struct irdma_hmc_del_obj_info *info,
+ bool reset)
+{
+ struct irdma_hmc_pd_table *pd_table;
+ u32 sd_idx, sd_lmt;
+ u32 pd_idx, pd_lmt, rel_pd_idx;
+ u32 i, j;
+ enum irdma_status_code ret_code = 0;
+
+ if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
+ ibdev_dbg(to_ibdev(dev),
+ "HMC: error start_idx[%04d] >= [type %04d].cnt[%04d]\n",
+ info->start_idx, info->rsrc_type,
+ info->hmc_info->hmc_obj[info->rsrc_type].cnt);
+ return IRDMA_ERR_INVALID_HMC_OBJ_INDEX;
+ }
+
+ if ((info->start_idx + info->count) >
+ info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
+ ibdev_dbg(to_ibdev(dev),
+ "HMC: error start_idx[%04d] + count %04d >= [type %04d].cnt[%04d]\n",
+ info->start_idx, info->count, info->rsrc_type,
+ info->hmc_info->hmc_obj[info->rsrc_type].cnt);
+ return IRDMA_ERR_INVALID_HMC_OBJ_COUNT;
+ }
+
+ irdma_find_pd_index_limit(info->hmc_info, info->rsrc_type,
+ info->start_idx, info->count, &pd_idx,
+ &pd_lmt);
+
+ for (j = pd_idx; j < pd_lmt; j++) {
+ sd_idx = j / IRDMA_HMC_PD_CNT_IN_SD;
+
+ if (!info->hmc_info->sd_table.sd_entry[sd_idx].valid)
+ continue;
+
+ if (info->hmc_info->sd_table.sd_entry[sd_idx].entry_type !=
+ IRDMA_SD_TYPE_PAGED)
+ continue;
+
+ rel_pd_idx = j % IRDMA_HMC_PD_CNT_IN_SD;
+ pd_table = &info->hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
+ if (pd_table->pd_entry &&
+ pd_table->pd_entry[rel_pd_idx].valid) {
+ ret_code = irdma_remove_pd_bp(dev, info->hmc_info, j);
+ if (ret_code) {
+ ibdev_dbg(to_ibdev(dev),
+ "HMC: remove_pd_bp error\n");
+ return ret_code;
+ }
+ }
+ }
+
+ irdma_find_sd_index_limit(info->hmc_info, info->rsrc_type,
+ info->start_idx, info->count, &sd_idx,
+ &sd_lmt);
+ if (sd_idx >= info->hmc_info->sd_table.sd_cnt ||
+ sd_lmt > info->hmc_info->sd_table.sd_cnt) {
+ ibdev_dbg(to_ibdev(dev), "HMC: invalid sd_idx\n");
+ return IRDMA_ERR_INVALID_SD_INDEX;
+ }
+
+ for (i = sd_idx; i < sd_lmt; i++) {
+ pd_table = &info->hmc_info->sd_table.sd_entry[i].u.pd_table;
+ if (!info->hmc_info->sd_table.sd_entry[i].valid)
+ continue;
+ switch (info->hmc_info->sd_table.sd_entry[i].entry_type) {
+ case IRDMA_SD_TYPE_DIRECT:
+ ret_code = irdma_prep_remove_sd_bp(info->hmc_info, i);
+ if (!ret_code) {
+ info->hmc_info->sd_indexes[info->del_sd_cnt] =
+ (u16)i;
+ info->del_sd_cnt++;
+ }
+ break;
+ case IRDMA_SD_TYPE_PAGED:
+ ret_code = irdma_prep_remove_pd_page(info->hmc_info, i);
+ if (ret_code)
+ break;
+ if (dev->hmc_info != info->hmc_info &&
+ info->rsrc_type == IRDMA_HMC_IW_PBLE &&
+ pd_table->pd_entry) {
+ kfree(pd_table->pd_entry_virt_mem.va);
+ pd_table->pd_entry = NULL;
+ }
+ info->hmc_info->sd_indexes[info->del_sd_cnt] = (u16)i;
+ info->del_sd_cnt++;
+ break;
+ default:
+ break;
+ }
+ }
+ return irdma_finish_del_sd_reg(dev, info, reset);
+}
+
+/**
+ * irdma_add_sd_table_entry - Adds a segment descriptor to the table
+ * @hw: pointer to our hw struct
+ * @hmc_info: pointer to the HMC configuration information struct
+ * @sd_index: segment descriptor index to manipulate
+ * @type: what type of segment descriptor we're manipulating
+ * @direct_mode_sz: size to alloc in direct mode
+ */
+enum irdma_status_code irdma_add_sd_table_entry(struct irdma_hw *hw,
+ struct irdma_hmc_info *hmc_info,
+ u32 sd_index,
+ enum irdma_sd_entry_type type,
+ u64 direct_mode_sz)
+{
+ struct irdma_hmc_sd_entry *sd_entry;
+ struct irdma_dma_mem dma_mem;
+ u64 alloc_len;
+
+ sd_entry = &hmc_info->sd_table.sd_entry[sd_index];
+ if (!sd_entry->valid) {
+ if (type == IRDMA_SD_TYPE_PAGED)
+ alloc_len = IRDMA_HMC_PAGED_BP_SIZE;
+ else
+ alloc_len = direct_mode_sz;
+
+ /* allocate a 4K pd page or 2M backing page */
+ dma_mem.size = ALIGN(alloc_len, IRDMA_HMC_PD_BP_BUF_ALIGNMENT);
+ dma_mem.va = dma_alloc_coherent(hw->device, dma_mem.size,
+ &dma_mem.pa, GFP_KERNEL);
+ if (!dma_mem.va)
+ return IRDMA_ERR_NO_MEMORY;
+ if (type == IRDMA_SD_TYPE_PAGED) {
+ struct irdma_virt_mem *vmem =
+ &sd_entry->u.pd_table.pd_entry_virt_mem;
+
+ vmem->size = sizeof(struct irdma_hmc_pd_entry) * 512;
+ vmem->va = kzalloc(vmem->size, GFP_KERNEL);
+ if (!vmem->va) {
+ dma_free_coherent(hw->device, dma_mem.size,
+ dma_mem.va, dma_mem.pa);
+ dma_mem.va = NULL;
+ return IRDMA_ERR_NO_MEMORY;
+ }
+ sd_entry->u.pd_table.pd_entry = vmem->va;
+
+ memcpy(&sd_entry->u.pd_table.pd_page_addr, &dma_mem,
+ sizeof(sd_entry->u.pd_table.pd_page_addr));
+ } else {
+ memcpy(&sd_entry->u.bp.addr, &dma_mem,
+ sizeof(sd_entry->u.bp.addr));
+
+ sd_entry->u.bp.sd_pd_index = sd_index;
+ }
+
+ hmc_info->sd_table.sd_entry[sd_index].entry_type = type;
+ hmc_info->sd_table.use_cnt++;
+ }
+ if (sd_entry->entry_type == IRDMA_SD_TYPE_DIRECT)
+ sd_entry->u.bp.use_cnt++;
+
+ return 0;
+}
+
+/**
+ * irdma_add_pd_table_entry - Adds page descriptor to the specified table
+ * @dev: pointer to our device structure
+ * @hmc_info: pointer to the HMC configuration information structure
+ * @pd_index: which page descriptor index to manipulate
+ * @rsrc_pg: if not NULL, use preallocated page instead of allocating new one.
+ *
+ * This function:
+ * 1. Initializes the pd entry
+ * 2. Adds pd_entry in the pd_table
+ * 3. Mark the entry valid in irdma_hmc_pd_entry structure
+ * 4. Initializes the pd_entry's ref count to 1
+ * assumptions:
+ * 1. The memory for pd should be pinned down, physically contiguous and
+ * aligned on 4K boundary and zeroed memory.
+ * 2. It should be 4K in size.
+ */
+enum irdma_status_code irdma_add_pd_table_entry(struct irdma_sc_dev *dev,
+ struct irdma_hmc_info *hmc_info,
+ u32 pd_index,
+ struct irdma_dma_mem *rsrc_pg)
+{
+ struct irdma_hmc_pd_table *pd_table;
+ struct irdma_hmc_pd_entry *pd_entry;
+ struct irdma_dma_mem mem;
+ struct irdma_dma_mem *page = &mem;
+ u32 sd_idx, rel_pd_idx;
+ u64 *pd_addr;
+ u64 page_desc;
+
+ if (pd_index / IRDMA_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt)
+ return IRDMA_ERR_INVALID_PAGE_DESC_INDEX;
+
+ sd_idx = (pd_index / IRDMA_HMC_PD_CNT_IN_SD);
+ if (hmc_info->sd_table.sd_entry[sd_idx].entry_type !=
+ IRDMA_SD_TYPE_PAGED)
+ return 0;
+
+ rel_pd_idx = (pd_index % IRDMA_HMC_PD_CNT_IN_SD);
+ pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
+ pd_entry = &pd_table->pd_entry[rel_pd_idx];
+ if (!pd_entry->valid) {
+ if (rsrc_pg) {
+ pd_entry->rsrc_pg = true;
+ page = rsrc_pg;
+ } else {
+ page->size = ALIGN(IRDMA_HMC_PAGED_BP_SIZE,
+ IRDMA_HMC_PD_BP_BUF_ALIGNMENT);
+ page->va = dma_alloc_coherent(dev->hw->device,
+ page->size, &page->pa,
+ GFP_KERNEL);
+ if (!page->va)
+ return IRDMA_ERR_NO_MEMORY;
+
+ pd_entry->rsrc_pg = false;
+ }
+
+ memcpy(&pd_entry->bp.addr, page, sizeof(pd_entry->bp.addr));
+ pd_entry->bp.sd_pd_index = pd_index;
+ pd_entry->bp.entry_type = IRDMA_SD_TYPE_PAGED;
+ page_desc = page->pa | 0x1;
+ pd_addr = pd_table->pd_page_addr.va;
+ pd_addr += rel_pd_idx;
+ memcpy(pd_addr, &page_desc, sizeof(*pd_addr));
+ pd_entry->sd_index = sd_idx;
+ pd_entry->valid = true;
+ pd_table->use_cnt++;
+ irdma_invalidate_pf_hmc_pd(dev, sd_idx, rel_pd_idx);
+ }
+ pd_entry->bp.use_cnt++;
+
+ return 0;
+}
+
+/**
+ * irdma_remove_pd_bp - remove a backing page from a page descriptor
+ * @dev: pointer to our HW structure
+ * @hmc_info: pointer to the HMC configuration information structure
+ * @idx: the page index
+ *
+ * This function:
+ * 1. Marks the entry in pd table (for paged address mode) or in sd table
+ * (for direct address mode) invalid.
+ * 2. Write to register PMPDINV to invalidate the backing page in FV cache
+ * 3. Decrement the ref count for the pd _entry
+ * assumptions:
+ * 1. Caller can deallocate the memory used by backing storage after this
+ * function returns.
+ */
+enum irdma_status_code irdma_remove_pd_bp(struct irdma_sc_dev *dev,
+ struct irdma_hmc_info *hmc_info,
+ u32 idx)
+{
+ struct irdma_hmc_pd_entry *pd_entry;
+ struct irdma_hmc_pd_table *pd_table;
+ struct irdma_hmc_sd_entry *sd_entry;
+ u32 sd_idx, rel_pd_idx;
+ struct irdma_dma_mem *mem;
+ u64 *pd_addr;
+
+ sd_idx = idx / IRDMA_HMC_PD_CNT_IN_SD;
+ rel_pd_idx = idx % IRDMA_HMC_PD_CNT_IN_SD;
+ if (sd_idx >= hmc_info->sd_table.sd_cnt)
+ return IRDMA_ERR_INVALID_PAGE_DESC_INDEX;
+
+ sd_entry = &hmc_info->sd_table.sd_entry[sd_idx];
+ if (sd_entry->entry_type != IRDMA_SD_TYPE_PAGED)
+ return IRDMA_ERR_INVALID_SD_TYPE;
+
+ pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
+ pd_entry = &pd_table->pd_entry[rel_pd_idx];
+ if (--pd_entry->bp.use_cnt)
+ return 0;
+
+ pd_entry->valid = false;
+ pd_table->use_cnt--;
+ pd_addr = pd_table->pd_page_addr.va;
+ pd_addr += rel_pd_idx;
+ memset(pd_addr, 0, sizeof(u64));
+ irdma_invalidate_pf_hmc_pd(dev, sd_idx, idx);
+
+ if (!pd_entry->rsrc_pg) {
+ mem = &pd_entry->bp.addr;
+ if (!mem || !mem->va)
+ return IRDMA_ERR_PARAM;
+
+ dma_free_coherent(dev->hw->device, mem->size, mem->va,
+ mem->pa);
+ mem->va = NULL;
+ }
+ if (!pd_table->use_cnt)
+ kfree(pd_table->pd_entry_virt_mem.va);
+
+ return 0;
+}
+
+/**
+ * irdma_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry
+ * @hmc_info: pointer to the HMC configuration information structure
+ * @idx: the page index
+ */
+enum irdma_status_code irdma_prep_remove_sd_bp(struct irdma_hmc_info *hmc_info,
+ u32 idx)
+{
+ struct irdma_hmc_sd_entry *sd_entry;
+
+ sd_entry = &hmc_info->sd_table.sd_entry[idx];
+ if (--sd_entry->u.bp.use_cnt)
+ return IRDMA_ERR_NOT_READY;
+
+ hmc_info->sd_table.use_cnt--;
+ sd_entry->valid = false;
+
+ return 0;
+}
+
+/**
+ * irdma_prep_remove_pd_page - Prepares to remove a PD page from sd entry.
+ * @hmc_info: pointer to the HMC configuration information structure
+ * @idx: segment descriptor index to find the relevant page descriptor
+ */
+enum irdma_status_code
+irdma_prep_remove_pd_page(struct irdma_hmc_info *hmc_info, u32 idx)
+{
+ struct irdma_hmc_sd_entry *sd_entry;
+
+ sd_entry = &hmc_info->sd_table.sd_entry[idx];
+
+ if (sd_entry->u.pd_table.use_cnt)
+ return IRDMA_ERR_NOT_READY;
+
+ sd_entry->valid = false;
+ hmc_info->sd_table.use_cnt--;
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/irdma/hmc.h b/drivers/infiniband/hw/irdma/hmc.h
new file mode 100644
index 000000000000..e2139c788b1b
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/hmc.h
@@ -0,0 +1,180 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2015 - 2020 Intel Corporation */
+#ifndef IRDMA_HMC_H
+#define IRDMA_HMC_H
+
+#include "defs.h"
+
+#define IRDMA_HMC_MAX_BP_COUNT 512
+#define IRDMA_MAX_SD_ENTRIES 11
+#define IRDMA_HW_DBG_HMC_INVALID_BP_MARK 0xca
+#define IRDMA_HMC_INFO_SIGNATURE 0x484d5347
+#define IRDMA_HMC_PD_CNT_IN_SD 512
+#define IRDMA_HMC_DIRECT_BP_SIZE 0x200000
+#define IRDMA_HMC_MAX_SD_COUNT 8192
+#define IRDMA_HMC_PAGED_BP_SIZE 4096
+#define IRDMA_HMC_PD_BP_BUF_ALIGNMENT 4096
+#define IRDMA_FIRST_VF_FPM_ID 8
+#define FPM_MULTIPLIER 1024
+
+enum irdma_hmc_rsrc_type {
+ IRDMA_HMC_IW_QP = 0,
+ IRDMA_HMC_IW_CQ = 1,
+ IRDMA_HMC_IW_RESERVED = 2,
+ IRDMA_HMC_IW_HTE = 3,
+ IRDMA_HMC_IW_ARP = 4,
+ IRDMA_HMC_IW_APBVT_ENTRY = 5,
+ IRDMA_HMC_IW_MR = 6,
+ IRDMA_HMC_IW_XF = 7,
+ IRDMA_HMC_IW_XFFL = 8,
+ IRDMA_HMC_IW_Q1 = 9,
+ IRDMA_HMC_IW_Q1FL = 10,
+ IRDMA_HMC_IW_TIMER = 11,
+ IRDMA_HMC_IW_FSIMC = 12,
+ IRDMA_HMC_IW_FSIAV = 13,
+ IRDMA_HMC_IW_PBLE = 14,
+ IRDMA_HMC_IW_RRF = 15,
+ IRDMA_HMC_IW_RRFFL = 16,
+ IRDMA_HMC_IW_HDR = 17,
+ IRDMA_HMC_IW_MD = 18,
+ IRDMA_HMC_IW_OOISC = 19,
+ IRDMA_HMC_IW_OOISCFFL = 20,
+ IRDMA_HMC_IW_MAX, /* Must be last entry */
+};
+
+enum irdma_sd_entry_type {
+ IRDMA_SD_TYPE_INVALID = 0,
+ IRDMA_SD_TYPE_PAGED = 1,
+ IRDMA_SD_TYPE_DIRECT = 2,
+};
+
+struct irdma_hmc_obj_info {
+ u64 base;
+ u32 max_cnt;
+ u32 cnt;
+ u64 size;
+};
+
+struct irdma_hmc_bp {
+ enum irdma_sd_entry_type entry_type;
+ struct irdma_dma_mem addr;
+ u32 sd_pd_index;
+ u32 use_cnt;
+};
+
+struct irdma_hmc_pd_entry {
+ struct irdma_hmc_bp bp;
+ u32 sd_index;
+ bool rsrc_pg:1;
+ bool valid:1;
+};
+
+struct irdma_hmc_pd_table {
+ struct irdma_dma_mem pd_page_addr;
+ struct irdma_hmc_pd_entry *pd_entry;
+ struct irdma_virt_mem pd_entry_virt_mem;
+ u32 use_cnt;
+ u32 sd_index;
+};
+
+struct irdma_hmc_sd_entry {
+ enum irdma_sd_entry_type entry_type;
+ bool valid;
+ union {
+ struct irdma_hmc_pd_table pd_table;
+ struct irdma_hmc_bp bp;
+ } u;
+};
+
+struct irdma_hmc_sd_table {
+ struct irdma_virt_mem addr;
+ u32 sd_cnt;
+ u32 use_cnt;
+ struct irdma_hmc_sd_entry *sd_entry;
+};
+
+struct irdma_hmc_info {
+ u32 signature;
+ u8 hmc_fn_id;
+ u16 first_sd_index;
+ struct irdma_hmc_obj_info *hmc_obj;
+ struct irdma_virt_mem hmc_obj_virt_mem;
+ struct irdma_hmc_sd_table sd_table;
+ u16 sd_indexes[IRDMA_HMC_MAX_SD_COUNT];
+};
+
+struct irdma_update_sd_entry {
+ u64 cmd;
+ u64 data;
+};
+
+struct irdma_update_sds_info {
+ u32 cnt;
+ u8 hmc_fn_id;
+ struct irdma_update_sd_entry entry[IRDMA_MAX_SD_ENTRIES];
+};
+
+struct irdma_ccq_cqe_info;
+struct irdma_hmc_fcn_info {
+ u32 vf_id;
+ u8 free_fcn;
+};
+
+struct irdma_hmc_create_obj_info {
+ struct irdma_hmc_info *hmc_info;
+ struct irdma_virt_mem add_sd_virt_mem;
+ u32 rsrc_type;
+ u32 start_idx;
+ u32 count;
+ u32 add_sd_cnt;
+ enum irdma_sd_entry_type entry_type;
+ bool privileged;
+};
+
+struct irdma_hmc_del_obj_info {
+ struct irdma_hmc_info *hmc_info;
+ struct irdma_virt_mem del_sd_virt_mem;
+ u32 rsrc_type;
+ u32 start_idx;
+ u32 count;
+ u32 del_sd_cnt;
+ bool privileged;
+};
+
+enum irdma_status_code irdma_copy_dma_mem(struct irdma_hw *hw, void *dest_buf,
+ struct irdma_dma_mem *src_mem,
+ u64 src_offset, u64 size);
+enum irdma_status_code
+irdma_sc_create_hmc_obj(struct irdma_sc_dev *dev,
+ struct irdma_hmc_create_obj_info *info);
+enum irdma_status_code irdma_sc_del_hmc_obj(struct irdma_sc_dev *dev,
+ struct irdma_hmc_del_obj_info *info,
+ bool reset);
+enum irdma_status_code irdma_hmc_sd_one(struct irdma_sc_dev *dev, u8 hmc_fn_id,
+ u64 pa, u32 sd_idx,
+ enum irdma_sd_entry_type type,
+ bool setsd);
+enum irdma_status_code
+irdma_update_sds_noccq(struct irdma_sc_dev *dev,
+ struct irdma_update_sds_info *info);
+struct irdma_vfdev *irdma_vfdev_from_fpm(struct irdma_sc_dev *dev,
+ u8 hmc_fn_id);
+struct irdma_hmc_info *irdma_vf_hmcinfo_from_fpm(struct irdma_sc_dev *dev,
+ u8 hmc_fn_id);
+enum irdma_status_code irdma_add_sd_table_entry(struct irdma_hw *hw,
+ struct irdma_hmc_info *hmc_info,
+ u32 sd_index,
+ enum irdma_sd_entry_type type,
+ u64 direct_mode_sz);
+enum irdma_status_code irdma_add_pd_table_entry(struct irdma_sc_dev *dev,
+ struct irdma_hmc_info *hmc_info,
+ u32 pd_index,
+ struct irdma_dma_mem *rsrc_pg);
+enum irdma_status_code irdma_remove_pd_bp(struct irdma_sc_dev *dev,
+ struct irdma_hmc_info *hmc_info,
+ u32 idx);
+enum irdma_status_code irdma_prep_remove_sd_bp(struct irdma_hmc_info *hmc_info,
+ u32 idx);
+enum irdma_status_code
+irdma_prep_remove_pd_page(struct irdma_hmc_info *hmc_info, u32 idx);
+#endif /* IRDMA_HMC_H */
diff --git a/drivers/infiniband/hw/irdma/hw.c b/drivers/infiniband/hw/irdma/hw.c
new file mode 100644
index 000000000000..7afb8a6a0526
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/hw.c
@@ -0,0 +1,2725 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#include "main.h"
+
+static struct irdma_rsrc_limits rsrc_limits_table[] = {
+ [0] = {
+ .qplimit = SZ_128,
+ },
+ [1] = {
+ .qplimit = SZ_1K,
+ },
+ [2] = {
+ .qplimit = SZ_2K,
+ },
+ [3] = {
+ .qplimit = SZ_4K,
+ },
+ [4] = {
+ .qplimit = SZ_16K,
+ },
+ [5] = {
+ .qplimit = SZ_64K,
+ },
+ [6] = {
+ .qplimit = SZ_128K,
+ },
+ [7] = {
+ .qplimit = SZ_256K,
+ },
+};
+
+/* types of hmc objects */
+static enum irdma_hmc_rsrc_type iw_hmc_obj_types[] = {
+ IRDMA_HMC_IW_QP,
+ IRDMA_HMC_IW_CQ,
+ IRDMA_HMC_IW_HTE,
+ IRDMA_HMC_IW_ARP,
+ IRDMA_HMC_IW_APBVT_ENTRY,
+ IRDMA_HMC_IW_MR,
+ IRDMA_HMC_IW_XF,
+ IRDMA_HMC_IW_XFFL,
+ IRDMA_HMC_IW_Q1,
+ IRDMA_HMC_IW_Q1FL,
+ IRDMA_HMC_IW_TIMER,
+ IRDMA_HMC_IW_FSIMC,
+ IRDMA_HMC_IW_FSIAV,
+ IRDMA_HMC_IW_RRF,
+ IRDMA_HMC_IW_RRFFL,
+ IRDMA_HMC_IW_HDR,
+ IRDMA_HMC_IW_MD,
+ IRDMA_HMC_IW_OOISC,
+ IRDMA_HMC_IW_OOISCFFL,
+};
+
+/**
+ * irdma_iwarp_ce_handler - handle iwarp completions
+ * @iwcq: iwarp cq receiving event
+ */
+static void irdma_iwarp_ce_handler(struct irdma_sc_cq *iwcq)
+{
+ struct irdma_cq *cq = iwcq->back_cq;
+
+ if (cq->ibcq.comp_handler)
+ cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
+}
+
+/**
+ * irdma_puda_ce_handler - handle puda completion events
+ * @rf: RDMA PCI function
+ * @cq: puda completion q for event
+ */
+static void irdma_puda_ce_handler(struct irdma_pci_f *rf,
+ struct irdma_sc_cq *cq)
+{
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ enum irdma_status_code status;
+ u32 compl_error;
+
+ do {
+ status = irdma_puda_poll_cmpl(dev, cq, &compl_error);
+ if (status == IRDMA_ERR_Q_EMPTY)
+ break;
+ if (status) {
+ ibdev_dbg(to_ibdev(dev), "ERR: puda status = %d\n", status);
+ break;
+ }
+ if (compl_error) {
+ ibdev_dbg(to_ibdev(dev), "ERR: puda compl_err =0x%x\n",
+ compl_error);
+ break;
+ }
+ } while (1);
+
+ irdma_sc_ccq_arm(cq);
+}
+
+/**
+ * irdma_process_ceq - handle ceq for completions
+ * @rf: RDMA PCI function
+ * @ceq: ceq having cq for completion
+ */
+static void irdma_process_ceq(struct irdma_pci_f *rf, struct irdma_ceq *ceq)
+{
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ struct irdma_sc_ceq *sc_ceq;
+ struct irdma_sc_cq *cq;
+ unsigned long flags;
+
+ sc_ceq = &ceq->sc_ceq;
+ do {
+ spin_lock_irqsave(&ceq->ce_lock, flags);
+ cq = irdma_sc_process_ceq(dev, sc_ceq);
+ if (!cq) {
+ spin_unlock_irqrestore(&ceq->ce_lock, flags);
+ break;
+ }
+
+ if (cq->cq_type == IRDMA_CQ_TYPE_IWARP)
+ irdma_iwarp_ce_handler(cq);
+
+ spin_unlock_irqrestore(&ceq->ce_lock, flags);
+
+ if (cq->cq_type == IRDMA_CQ_TYPE_CQP)
+ queue_work(rf->cqp_cmpl_wq, &rf->cqp_cmpl_work);
+ else if (cq->cq_type == IRDMA_CQ_TYPE_ILQ ||
+ cq->cq_type == IRDMA_CQ_TYPE_IEQ)
+ irdma_puda_ce_handler(rf, cq);
+ } while (1);
+}
+
+static void irdma_set_flush_fields(struct irdma_sc_qp *qp,
+ struct irdma_aeqe_info *info)
+{
+ qp->sq_flush_code = info->sq;
+ qp->rq_flush_code = info->rq;
+ qp->event_type = IRDMA_QP_EVENT_CATASTROPHIC;
+
+ switch (info->ae_id) {
+ case IRDMA_AE_AMP_UNALLOCATED_STAG:
+ case IRDMA_AE_AMP_BOUNDS_VIOLATION:
+ case IRDMA_AE_AMP_INVALID_STAG:
+ qp->event_type = IRDMA_QP_EVENT_ACCESS_ERR;
+ fallthrough;
+ case IRDMA_AE_AMP_BAD_PD:
+ case IRDMA_AE_UDA_XMIT_BAD_PD:
+ qp->flush_code = FLUSH_PROT_ERR;
+ break;
+ case IRDMA_AE_AMP_BAD_QP:
+ qp->flush_code = FLUSH_LOC_QP_OP_ERR;
+ break;
+ case IRDMA_AE_AMP_BAD_STAG_KEY:
+ case IRDMA_AE_AMP_BAD_STAG_INDEX:
+ case IRDMA_AE_AMP_TO_WRAP:
+ case IRDMA_AE_AMP_RIGHTS_VIOLATION:
+ case IRDMA_AE_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS:
+ case IRDMA_AE_PRIV_OPERATION_DENIED:
+ case IRDMA_AE_IB_INVALID_REQUEST:
+ case IRDMA_AE_IB_REMOTE_ACCESS_ERROR:
+ case IRDMA_AE_IB_REMOTE_OP_ERROR:
+ qp->flush_code = FLUSH_REM_ACCESS_ERR;
+ qp->event_type = IRDMA_QP_EVENT_ACCESS_ERR;
+ break;
+ case IRDMA_AE_LLP_SEGMENT_TOO_SMALL:
+ case IRDMA_AE_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER:
+ case IRDMA_AE_UDA_XMIT_DGRAM_TOO_LONG:
+ case IRDMA_AE_UDA_XMIT_DGRAM_TOO_SHORT:
+ case IRDMA_AE_UDA_L4LEN_INVALID:
+ case IRDMA_AE_ROCE_RSP_LENGTH_ERROR:
+ qp->flush_code = FLUSH_LOC_LEN_ERR;
+ break;
+ case IRDMA_AE_LCE_QP_CATASTROPHIC:
+ qp->flush_code = FLUSH_FATAL_ERR;
+ break;
+ case IRDMA_AE_DDP_UBE_INVALID_MO:
+ case IRDMA_AE_IB_RREQ_AND_Q1_FULL:
+ case IRDMA_AE_LLP_RECEIVED_MPA_CRC_ERROR:
+ qp->flush_code = FLUSH_GENERAL_ERR;
+ break;
+ default:
+ qp->flush_code = FLUSH_FATAL_ERR;
+ break;
+ }
+}
+
+/**
+ * irdma_process_aeq - handle aeq events
+ * @rf: RDMA PCI function
+ */
+static void irdma_process_aeq(struct irdma_pci_f *rf)
+{
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ struct irdma_aeq *aeq = &rf->aeq;
+ struct irdma_sc_aeq *sc_aeq = &aeq->sc_aeq;
+ struct irdma_aeqe_info aeinfo;
+ struct irdma_aeqe_info *info = &aeinfo;
+ int ret;
+ struct irdma_qp *iwqp = NULL;
+ struct irdma_sc_cq *cq = NULL;
+ struct irdma_cq *iwcq = NULL;
+ struct irdma_sc_qp *qp = NULL;
+ struct irdma_qp_host_ctx_info *ctx_info = NULL;
+ struct irdma_device *iwdev = rf->iwdev;
+ unsigned long flags;
+
+ u32 aeqcnt = 0;
+
+ if (!sc_aeq->size)
+ return;
+
+ do {
+ memset(info, 0, sizeof(*info));
+ ret = irdma_sc_get_next_aeqe(sc_aeq, info);
+ if (ret)
+ break;
+
+ aeqcnt++;
+ ibdev_dbg(&iwdev->ibdev,
+ "AEQ: ae_id = 0x%x bool qp=%d qp_id = %d tcp_state=%d iwarp_state=%d ae_src=%d\n",
+ info->ae_id, info->qp, info->qp_cq_id, info->tcp_state,
+ info->iwarp_state, info->ae_src);
+
+ if (info->qp) {
+ spin_lock_irqsave(&rf->qptable_lock, flags);
+ iwqp = rf->qp_table[info->qp_cq_id];
+ if (!iwqp) {
+ spin_unlock_irqrestore(&rf->qptable_lock,
+ flags);
+ if (info->ae_id == IRDMA_AE_QP_SUSPEND_COMPLETE) {
+ atomic_dec(&iwdev->vsi.qp_suspend_reqs);
+ wake_up(&iwdev->suspend_wq);
+ continue;
+ }
+ ibdev_dbg(&iwdev->ibdev, "AEQ: qp_id %d is already freed\n",
+ info->qp_cq_id);
+ continue;
+ }
+ irdma_qp_add_ref(&iwqp->ibqp);
+ spin_unlock_irqrestore(&rf->qptable_lock, flags);
+ qp = &iwqp->sc_qp;
+ spin_lock_irqsave(&iwqp->lock, flags);
+ iwqp->hw_tcp_state = info->tcp_state;
+ iwqp->hw_iwarp_state = info->iwarp_state;
+ if (info->ae_id != IRDMA_AE_QP_SUSPEND_COMPLETE)
+ iwqp->last_aeq = info->ae_id;
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ ctx_info = &iwqp->ctx_info;
+ if (rdma_protocol_roce(&iwqp->iwdev->ibdev, 1))
+ ctx_info->roce_info->err_rq_idx_valid = true;
+ else
+ ctx_info->iwarp_info->err_rq_idx_valid = true;
+ } else {
+ if (info->ae_id != IRDMA_AE_CQ_OPERATION_ERROR)
+ continue;
+ }
+
+ switch (info->ae_id) {
+ struct irdma_cm_node *cm_node;
+ case IRDMA_AE_LLP_CONNECTION_ESTABLISHED:
+ cm_node = iwqp->cm_node;
+ if (cm_node->accept_pend) {
+ atomic_dec(&cm_node->listener->pend_accepts_cnt);
+ cm_node->accept_pend = 0;
+ }
+ iwqp->rts_ae_rcvd = 1;
+ wake_up_interruptible(&iwqp->waitq);
+ break;
+ case IRDMA_AE_LLP_FIN_RECEIVED:
+ case IRDMA_AE_RDMAP_ROE_BAD_LLP_CLOSE:
+ if (qp->term_flags)
+ break;
+ if (atomic_inc_return(&iwqp->close_timer_started) == 1) {
+ iwqp->hw_tcp_state = IRDMA_TCP_STATE_CLOSE_WAIT;
+ if (iwqp->hw_tcp_state == IRDMA_TCP_STATE_CLOSE_WAIT &&
+ iwqp->ibqp_state == IB_QPS_RTS) {
+ irdma_next_iw_state(iwqp,
+ IRDMA_QP_STATE_CLOSING,
+ 0, 0, 0);
+ irdma_cm_disconn(iwqp);
+ }
+ irdma_schedule_cm_timer(iwqp->cm_node,
+ (struct irdma_puda_buf *)iwqp,
+ IRDMA_TIMER_TYPE_CLOSE,
+ 1, 0);
+ }
+ break;
+ case IRDMA_AE_LLP_CLOSE_COMPLETE:
+ if (qp->term_flags)
+ irdma_terminate_done(qp, 0);
+ else
+ irdma_cm_disconn(iwqp);
+ break;
+ case IRDMA_AE_BAD_CLOSE:
+ case IRDMA_AE_RESET_SENT:
+ irdma_next_iw_state(iwqp, IRDMA_QP_STATE_ERROR, 1, 0,
+ 0);
+ irdma_cm_disconn(iwqp);
+ break;
+ case IRDMA_AE_LLP_CONNECTION_RESET:
+ if (atomic_read(&iwqp->close_timer_started))
+ break;
+ irdma_cm_disconn(iwqp);
+ break;
+ case IRDMA_AE_QP_SUSPEND_COMPLETE:
+ if (iwqp->iwdev->vsi.tc_change_pending) {
+ atomic_dec(&iwqp->sc_qp.vsi->qp_suspend_reqs);
+ wake_up(&iwqp->iwdev->suspend_wq);
+ }
+ break;
+ case IRDMA_AE_TERMINATE_SENT:
+ irdma_terminate_send_fin(qp);
+ break;
+ case IRDMA_AE_LLP_TERMINATE_RECEIVED:
+ irdma_terminate_received(qp, info);
+ break;
+ case IRDMA_AE_CQ_OPERATION_ERROR:
+ ibdev_err(&iwdev->ibdev,
+ "Processing an iWARP related AE for CQ misc = 0x%04X\n",
+ info->ae_id);
+ cq = (struct irdma_sc_cq *)(unsigned long)
+ info->compl_ctx;
+
+ iwcq = cq->back_cq;
+
+ if (iwcq->ibcq.event_handler) {
+ struct ib_event ibevent;
+
+ ibevent.device = iwcq->ibcq.device;
+ ibevent.event = IB_EVENT_CQ_ERR;
+ ibevent.element.cq = &iwcq->ibcq;
+ iwcq->ibcq.event_handler(&ibevent,
+ iwcq->ibcq.cq_context);
+ }
+ break;
+ case IRDMA_AE_RESET_NOT_SENT:
+ case IRDMA_AE_LLP_DOUBT_REACHABILITY:
+ case IRDMA_AE_RESOURCE_EXHAUSTION:
+ break;
+ case IRDMA_AE_PRIV_OPERATION_DENIED:
+ case IRDMA_AE_STAG_ZERO_INVALID:
+ case IRDMA_AE_IB_RREQ_AND_Q1_FULL:
+ case IRDMA_AE_DDP_UBE_INVALID_DDP_VERSION:
+ case IRDMA_AE_DDP_UBE_INVALID_MO:
+ case IRDMA_AE_DDP_UBE_INVALID_QN:
+ case IRDMA_AE_DDP_NO_L_BIT:
+ case IRDMA_AE_RDMAP_ROE_INVALID_RDMAP_VERSION:
+ case IRDMA_AE_RDMAP_ROE_UNEXPECTED_OPCODE:
+ case IRDMA_AE_ROE_INVALID_RDMA_READ_REQUEST:
+ case IRDMA_AE_ROE_INVALID_RDMA_WRITE_OR_READ_RESP:
+ case IRDMA_AE_INVALID_ARP_ENTRY:
+ case IRDMA_AE_INVALID_TCP_OPTION_RCVD:
+ case IRDMA_AE_STALE_ARP_ENTRY:
+ case IRDMA_AE_LLP_RECEIVED_MPA_CRC_ERROR:
+ case IRDMA_AE_LLP_SEGMENT_TOO_SMALL:
+ case IRDMA_AE_LLP_SYN_RECEIVED:
+ case IRDMA_AE_LLP_TOO_MANY_RETRIES:
+ case IRDMA_AE_LCE_QP_CATASTROPHIC:
+ case IRDMA_AE_LCE_FUNCTION_CATASTROPHIC:
+ case IRDMA_AE_LCE_CQ_CATASTROPHIC:
+ case IRDMA_AE_UDA_XMIT_DGRAM_TOO_LONG:
+ if (rdma_protocol_roce(&iwdev->ibdev, 1))
+ ctx_info->roce_info->err_rq_idx_valid = false;
+ else
+ ctx_info->iwarp_info->err_rq_idx_valid = false;
+ fallthrough;
+ default:
+ ibdev_err(&iwdev->ibdev, "abnormal ae_id = 0x%x bool qp=%d qp_id = %d\n",
+ info->ae_id, info->qp, info->qp_cq_id);
+ if (rdma_protocol_roce(&iwdev->ibdev, 1)) {
+ if (!info->sq && ctx_info->roce_info->err_rq_idx_valid) {
+ ctx_info->roce_info->err_rq_idx = info->wqe_idx;
+ irdma_sc_qp_setctx_roce(&iwqp->sc_qp, iwqp->host_ctx.va,
+ ctx_info);
+ }
+ irdma_set_flush_fields(qp, info);
+ irdma_cm_disconn(iwqp);
+ break;
+ }
+ if (!info->sq && ctx_info->iwarp_info->err_rq_idx_valid) {
+ ctx_info->iwarp_info->err_rq_idx = info->wqe_idx;
+ ctx_info->tcp_info_valid = false;
+ ctx_info->iwarp_info_valid = true;
+ irdma_sc_qp_setctx(&iwqp->sc_qp, iwqp->host_ctx.va,
+ ctx_info);
+ }
+ if (iwqp->hw_iwarp_state != IRDMA_QP_STATE_RTS &&
+ iwqp->hw_iwarp_state != IRDMA_QP_STATE_TERMINATE) {
+ irdma_next_iw_state(iwqp, IRDMA_QP_STATE_ERROR, 1, 0, 0);
+ irdma_cm_disconn(iwqp);
+ } else {
+ irdma_terminate_connection(qp, info);
+ }
+ break;
+ }
+ if (info->qp)
+ irdma_qp_rem_ref(&iwqp->ibqp);
+ } while (1);
+
+ if (aeqcnt)
+ irdma_sc_repost_aeq_entries(dev, aeqcnt);
+}
+
+/**
+ * irdma_ena_intr - set up device interrupts
+ * @dev: hardware control device structure
+ * @msix_id: id of the interrupt to be enabled
+ */
+static void irdma_ena_intr(struct irdma_sc_dev *dev, u32 msix_id)
+{
+ dev->irq_ops->irdma_en_irq(dev, msix_id);
+}
+
+/**
+ * irdma_dpc - tasklet for aeq and ceq 0
+ * @t: tasklet_struct ptr
+ */
+static void irdma_dpc(struct tasklet_struct *t)
+{
+ struct irdma_pci_f *rf = from_tasklet(rf, t, dpc_tasklet);
+
+ if (rf->msix_shared)
+ irdma_process_ceq(rf, rf->ceqlist);
+ irdma_process_aeq(rf);
+ irdma_ena_intr(&rf->sc_dev, rf->iw_msixtbl[0].idx);
+}
+
+/**
+ * irdma_ceq_dpc - dpc handler for CEQ
+ * @t: tasklet_struct ptr
+ */
+static void irdma_ceq_dpc(struct tasklet_struct *t)
+{
+ struct irdma_ceq *iwceq = from_tasklet(iwceq, t, dpc_tasklet);
+ struct irdma_pci_f *rf = iwceq->rf;
+
+ irdma_process_ceq(rf, iwceq);
+ irdma_ena_intr(&rf->sc_dev, iwceq->msix_idx);
+}
+
+/**
+ * irdma_save_msix_info - copy msix vector information to iwarp device
+ * @rf: RDMA PCI function
+ *
+ * Allocate iwdev msix table and copy the msix info to the table
+ * Return 0 if successful, otherwise return error
+ */
+static enum irdma_status_code irdma_save_msix_info(struct irdma_pci_f *rf)
+{
+ struct irdma_qvlist_info *iw_qvlist;
+ struct irdma_qv_info *iw_qvinfo;
+ struct msix_entry *pmsix;
+ u32 ceq_idx;
+ u32 i;
+ size_t size;
+
+ if (!rf->msix_count)
+ return IRDMA_ERR_NO_INTR;
+
+ size = sizeof(struct irdma_msix_vector) * rf->msix_count;
+ size += struct_size(iw_qvlist, qv_info, rf->msix_count);
+ rf->iw_msixtbl = kzalloc(size, GFP_KERNEL);
+ if (!rf->iw_msixtbl)
+ return IRDMA_ERR_NO_MEMORY;
+
+ rf->iw_qvlist = (struct irdma_qvlist_info *)
+ (&rf->iw_msixtbl[rf->msix_count]);
+ iw_qvlist = rf->iw_qvlist;
+ iw_qvinfo = iw_qvlist->qv_info;
+ iw_qvlist->num_vectors = rf->msix_count;
+ if (rf->msix_count <= num_online_cpus())
+ rf->msix_shared = true;
+
+ pmsix = rf->msix_entries;
+ for (i = 0, ceq_idx = 0; i < rf->msix_count; i++, iw_qvinfo++) {
+ rf->iw_msixtbl[i].idx = pmsix->entry;
+ rf->iw_msixtbl[i].irq = pmsix->vector;
+ rf->iw_msixtbl[i].cpu_affinity = ceq_idx;
+ if (!i) {
+ iw_qvinfo->aeq_idx = 0;
+ if (rf->msix_shared)
+ iw_qvinfo->ceq_idx = ceq_idx++;
+ else
+ iw_qvinfo->ceq_idx = IRDMA_Q_INVALID_IDX;
+ } else {
+ iw_qvinfo->aeq_idx = IRDMA_Q_INVALID_IDX;
+ iw_qvinfo->ceq_idx = ceq_idx++;
+ }
+ iw_qvinfo->itr_idx = 3;
+ iw_qvinfo->v_idx = rf->iw_msixtbl[i].idx;
+ pmsix++;
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_irq_handler - interrupt handler for aeq and ceq0
+ * @irq: Interrupt request number
+ * @data: RDMA PCI function
+ */
+static irqreturn_t irdma_irq_handler(int irq, void *data)
+{
+ struct irdma_pci_f *rf = data;
+
+ tasklet_schedule(&rf->dpc_tasklet);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * irdma_ceq_handler - interrupt handler for ceq
+ * @irq: interrupt request number
+ * @data: ceq pointer
+ */
+static irqreturn_t irdma_ceq_handler(int irq, void *data)
+{
+ struct irdma_ceq *iwceq = data;
+
+ if (iwceq->irq != irq)
+ ibdev_err(to_ibdev(&iwceq->rf->sc_dev), "expected irq = %d received irq = %d\n",
+ iwceq->irq, irq);
+ tasklet_schedule(&iwceq->dpc_tasklet);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * irdma_destroy_irq - destroy device interrupts
+ * @rf: RDMA PCI function
+ * @msix_vec: msix vector to disable irq
+ * @dev_id: parameter to pass to free_irq (used during irq setup)
+ *
+ * The function is called when destroying aeq/ceq
+ */
+static void irdma_destroy_irq(struct irdma_pci_f *rf,
+ struct irdma_msix_vector *msix_vec, void *dev_id)
+{
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+
+ dev->irq_ops->irdma_dis_irq(dev, msix_vec->idx);
+ irq_set_affinity_hint(msix_vec->irq, NULL);
+ free_irq(msix_vec->irq, dev_id);
+}
+
+/**
+ * irdma_destroy_cqp - destroy control qp
+ * @rf: RDMA PCI function
+ * @free_hwcqp: 1 if hw cqp should be freed
+ *
+ * Issue destroy cqp request and
+ * free the resources associated with the cqp
+ */
+static void irdma_destroy_cqp(struct irdma_pci_f *rf, bool free_hwcqp)
+{
+ enum irdma_status_code status = 0;
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ struct irdma_cqp *cqp = &rf->cqp;
+
+ if (rf->cqp_cmpl_wq)
+ destroy_workqueue(rf->cqp_cmpl_wq);
+ if (free_hwcqp)
+ status = irdma_sc_cqp_destroy(dev->cqp);
+ if (status)
+ ibdev_dbg(to_ibdev(dev), "ERR: Destroy CQP failed %d\n", status);
+
+ irdma_cleanup_pending_cqp_op(rf);
+ dma_free_coherent(dev->hw->device, cqp->sq.size, cqp->sq.va,
+ cqp->sq.pa);
+ cqp->sq.va = NULL;
+ kfree(cqp->scratch_array);
+ cqp->scratch_array = NULL;
+ kfree(cqp->cqp_requests);
+ cqp->cqp_requests = NULL;
+}
+
+static void irdma_destroy_virt_aeq(struct irdma_pci_f *rf)
+{
+ struct irdma_aeq *aeq = &rf->aeq;
+ u32 pg_cnt = DIV_ROUND_UP(aeq->mem.size, PAGE_SIZE);
+ dma_addr_t *pg_arr = (dma_addr_t *)aeq->palloc.level1.addr;
+
+ irdma_unmap_vm_page_list(&rf->hw, pg_arr, pg_cnt);
+ irdma_free_pble(rf->pble_rsrc, &aeq->palloc);
+ vfree(aeq->mem.va);
+}
+
+/**
+ * irdma_destroy_aeq - destroy aeq
+ * @rf: RDMA PCI function
+ *
+ * Issue a destroy aeq request and
+ * free the resources associated with the aeq
+ * The function is called during driver unload
+ */
+static void irdma_destroy_aeq(struct irdma_pci_f *rf)
+{
+ enum irdma_status_code status = IRDMA_ERR_NOT_READY;
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ struct irdma_aeq *aeq = &rf->aeq;
+
+ if (!rf->msix_shared) {
+ rf->sc_dev.irq_ops->irdma_cfg_aeq(&rf->sc_dev, rf->iw_msixtbl->idx, false);
+ irdma_destroy_irq(rf, rf->iw_msixtbl, rf);
+ }
+ if (rf->reset)
+ goto exit;
+
+ aeq->sc_aeq.size = 0;
+ status = irdma_cqp_aeq_cmd(dev, &aeq->sc_aeq, IRDMA_OP_AEQ_DESTROY);
+ if (status)
+ ibdev_dbg(to_ibdev(dev), "ERR: Destroy AEQ failed %d\n", status);
+
+exit:
+ if (aeq->virtual_map) {
+ irdma_destroy_virt_aeq(rf);
+ } else {
+ dma_free_coherent(dev->hw->device, aeq->mem.size, aeq->mem.va,
+ aeq->mem.pa);
+ aeq->mem.va = NULL;
+ }
+}
+
+/**
+ * irdma_destroy_ceq - destroy ceq
+ * @rf: RDMA PCI function
+ * @iwceq: ceq to be destroyed
+ *
+ * Issue a destroy ceq request and
+ * free the resources associated with the ceq
+ */
+static void irdma_destroy_ceq(struct irdma_pci_f *rf, struct irdma_ceq *iwceq)
+{
+ enum irdma_status_code status;
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+
+ if (rf->reset)
+ goto exit;
+
+ status = irdma_sc_ceq_destroy(&iwceq->sc_ceq, 0, 1);
+ if (status) {
+ ibdev_dbg(to_ibdev(dev), "ERR: CEQ destroy command failed %d\n", status);
+ goto exit;
+ }
+
+ status = irdma_sc_cceq_destroy_done(&iwceq->sc_ceq);
+ if (status)
+ ibdev_dbg(to_ibdev(dev), "ERR: CEQ destroy completion failed %d\n",
+ status);
+exit:
+ dma_free_coherent(dev->hw->device, iwceq->mem.size, iwceq->mem.va,
+ iwceq->mem.pa);
+ iwceq->mem.va = NULL;
+}
+
+/**
+ * irdma_del_ceq_0 - destroy ceq 0
+ * @rf: RDMA PCI function
+ *
+ * Disable the ceq 0 interrupt and destroy the ceq 0
+ */
+static void irdma_del_ceq_0(struct irdma_pci_f *rf)
+{
+ struct irdma_ceq *iwceq = rf->ceqlist;
+ struct irdma_msix_vector *msix_vec;
+
+ if (rf->msix_shared) {
+ msix_vec = &rf->iw_msixtbl[0];
+ rf->sc_dev.irq_ops->irdma_cfg_ceq(&rf->sc_dev,
+ msix_vec->ceq_id,
+ msix_vec->idx, false);
+ irdma_destroy_irq(rf, msix_vec, rf);
+ } else {
+ msix_vec = &rf->iw_msixtbl[1];
+ irdma_destroy_irq(rf, msix_vec, iwceq);
+ }
+
+ irdma_destroy_ceq(rf, iwceq);
+ rf->sc_dev.ceq_valid = false;
+ rf->ceqs_count = 0;
+}
+
+/**
+ * irdma_del_ceqs - destroy all ceq's except CEQ 0
+ * @rf: RDMA PCI function
+ *
+ * Go through all of the device ceq's, except 0, and for each
+ * ceq disable the ceq interrupt and destroy the ceq
+ */
+static void irdma_del_ceqs(struct irdma_pci_f *rf)
+{
+ struct irdma_ceq *iwceq = &rf->ceqlist[1];
+ struct irdma_msix_vector *msix_vec;
+ u32 i = 0;
+
+ if (rf->msix_shared)
+ msix_vec = &rf->iw_msixtbl[1];
+ else
+ msix_vec = &rf->iw_msixtbl[2];
+
+ for (i = 1; i < rf->ceqs_count; i++, msix_vec++, iwceq++) {
+ rf->sc_dev.irq_ops->irdma_cfg_ceq(&rf->sc_dev, msix_vec->ceq_id,
+ msix_vec->idx, false);
+ irdma_destroy_irq(rf, msix_vec, iwceq);
+ irdma_cqp_ceq_cmd(&rf->sc_dev, &iwceq->sc_ceq,
+ IRDMA_OP_CEQ_DESTROY);
+ dma_free_coherent(rf->sc_dev.hw->device, iwceq->mem.size,
+ iwceq->mem.va, iwceq->mem.pa);
+ iwceq->mem.va = NULL;
+ }
+ rf->ceqs_count = 1;
+}
+
+/**
+ * irdma_destroy_ccq - destroy control cq
+ * @rf: RDMA PCI function
+ *
+ * Issue destroy ccq request and
+ * free the resources associated with the ccq
+ */
+static void irdma_destroy_ccq(struct irdma_pci_f *rf)
+{
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ struct irdma_ccq *ccq = &rf->ccq;
+ enum irdma_status_code status = 0;
+
+ if (!rf->reset)
+ status = irdma_sc_ccq_destroy(dev->ccq, 0, true);
+ if (status)
+ ibdev_dbg(to_ibdev(dev), "ERR: CCQ destroy failed %d\n", status);
+ dma_free_coherent(dev->hw->device, ccq->mem_cq.size, ccq->mem_cq.va,
+ ccq->mem_cq.pa);
+ ccq->mem_cq.va = NULL;
+}
+
+/**
+ * irdma_close_hmc_objects_type - delete hmc objects of a given type
+ * @dev: iwarp device
+ * @obj_type: the hmc object type to be deleted
+ * @hmc_info: host memory info struct
+ * @privileged: permission to close HMC objects
+ * @reset: true if called before reset
+ */
+static void irdma_close_hmc_objects_type(struct irdma_sc_dev *dev,
+ enum irdma_hmc_rsrc_type obj_type,
+ struct irdma_hmc_info *hmc_info,
+ bool privileged, bool reset)
+{
+ struct irdma_hmc_del_obj_info info = {};
+
+ info.hmc_info = hmc_info;
+ info.rsrc_type = obj_type;
+ info.count = hmc_info->hmc_obj[obj_type].cnt;
+ info.privileged = privileged;
+ if (irdma_sc_del_hmc_obj(dev, &info, reset))
+ ibdev_dbg(to_ibdev(dev), "ERR: del HMC obj of type %d failed\n",
+ obj_type);
+}
+
+/**
+ * irdma_del_hmc_objects - remove all device hmc objects
+ * @dev: iwarp device
+ * @hmc_info: hmc_info to free
+ * @privileged: permission to delete HMC objects
+ * @reset: true if called before reset
+ * @vers: hardware version
+ */
+static void irdma_del_hmc_objects(struct irdma_sc_dev *dev,
+ struct irdma_hmc_info *hmc_info, bool privileged,
+ bool reset, enum irdma_vers vers)
+{
+ unsigned int i;
+
+ for (i = 0; i < IW_HMC_OBJ_TYPE_NUM; i++) {
+ if (dev->hmc_info->hmc_obj[iw_hmc_obj_types[i]].cnt)
+ irdma_close_hmc_objects_type(dev, iw_hmc_obj_types[i],
+ hmc_info, privileged, reset);
+ if (vers == IRDMA_GEN_1 && i == IRDMA_HMC_IW_TIMER)
+ break;
+ }
+}
+
+/**
+ * irdma_create_hmc_obj_type - create hmc object of a given type
+ * @dev: hardware control device structure
+ * @info: information for the hmc object to create
+ */
+static enum irdma_status_code
+irdma_create_hmc_obj_type(struct irdma_sc_dev *dev,
+ struct irdma_hmc_create_obj_info *info)
+{
+ return irdma_sc_create_hmc_obj(dev, info);
+}
+
+/**
+ * irdma_create_hmc_objs - create all hmc objects for the device
+ * @rf: RDMA PCI function
+ * @privileged: permission to create HMC objects
+ * @vers: HW version
+ *
+ * Create the device hmc objects and allocate hmc pages
+ * Return 0 if successful, otherwise clean up and return error
+ */
+static enum irdma_status_code
+irdma_create_hmc_objs(struct irdma_pci_f *rf, bool privileged, enum irdma_vers vers)
+{
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ struct irdma_hmc_create_obj_info info = {};
+ enum irdma_status_code status = 0;
+ int i;
+
+ info.hmc_info = dev->hmc_info;
+ info.privileged = privileged;
+ info.entry_type = rf->sd_type;
+
+ for (i = 0; i < IW_HMC_OBJ_TYPE_NUM; i++) {
+ if (dev->hmc_info->hmc_obj[iw_hmc_obj_types[i]].cnt) {
+ info.rsrc_type = iw_hmc_obj_types[i];
+ info.count = dev->hmc_info->hmc_obj[info.rsrc_type].cnt;
+ info.add_sd_cnt = 0;
+ status = irdma_create_hmc_obj_type(dev, &info);
+ if (status) {
+ ibdev_dbg(to_ibdev(dev),
+ "ERR: create obj type %d status = %d\n",
+ iw_hmc_obj_types[i], status);
+ break;
+ }
+ }
+ if (vers == IRDMA_GEN_1 && i == IRDMA_HMC_IW_TIMER)
+ break;
+ }
+
+ if (!status)
+ return irdma_sc_static_hmc_pages_allocated(dev->cqp, 0, dev->hmc_fn_id,
+ true, true);
+
+ while (i) {
+ i--;
+ /* destroy the hmc objects of a given type */
+ if (dev->hmc_info->hmc_obj[iw_hmc_obj_types[i]].cnt)
+ irdma_close_hmc_objects_type(dev, iw_hmc_obj_types[i],
+ dev->hmc_info, privileged,
+ false);
+ }
+
+ return status;
+}
+
+/**
+ * irdma_obj_aligned_mem - get aligned memory from device allocated memory
+ * @rf: RDMA PCI function
+ * @memptr: points to the memory addresses
+ * @size: size of memory needed
+ * @mask: mask for the aligned memory
+ *
+ * Get aligned memory of the requested size and
+ * update the memptr to point to the new aligned memory
+ * Return 0 if successful, otherwise return no memory error
+ */
+static enum irdma_status_code
+irdma_obj_aligned_mem(struct irdma_pci_f *rf, struct irdma_dma_mem *memptr,
+ u32 size, u32 mask)
+{
+ unsigned long va, newva;
+ unsigned long extra;
+
+ va = (unsigned long)rf->obj_next.va;
+ newva = va;
+ if (mask)
+ newva = ALIGN(va, (unsigned long)mask + 1ULL);
+ extra = newva - va;
+ memptr->va = (u8 *)va + extra;
+ memptr->pa = rf->obj_next.pa + extra;
+ memptr->size = size;
+ if (((u8 *)memptr->va + size) > ((u8 *)rf->obj_mem.va + rf->obj_mem.size))
+ return IRDMA_ERR_NO_MEMORY;
+
+ rf->obj_next.va = (u8 *)memptr->va + size;
+ rf->obj_next.pa = memptr->pa + size;
+
+ return 0;
+}
+
+/**
+ * irdma_create_cqp - create control qp
+ * @rf: RDMA PCI function
+ *
+ * Return 0, if the cqp and all the resources associated with it
+ * are successfully created, otherwise return error
+ */
+static enum irdma_status_code irdma_create_cqp(struct irdma_pci_f *rf)
+{
+ enum irdma_status_code status;
+ u32 sqsize = IRDMA_CQP_SW_SQSIZE_2048;
+ struct irdma_dma_mem mem;
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ struct irdma_cqp_init_info cqp_init_info = {};
+ struct irdma_cqp *cqp = &rf->cqp;
+ u16 maj_err, min_err;
+ int i;
+
+ cqp->cqp_requests = kcalloc(sqsize, sizeof(*cqp->cqp_requests), GFP_KERNEL);
+ if (!cqp->cqp_requests)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp->scratch_array = kcalloc(sqsize, sizeof(*cqp->scratch_array), GFP_KERNEL);
+ if (!cqp->scratch_array) {
+ kfree(cqp->cqp_requests);
+ return IRDMA_ERR_NO_MEMORY;
+ }
+
+ dev->cqp = &cqp->sc_cqp;
+ dev->cqp->dev = dev;
+ cqp->sq.size = ALIGN(sizeof(struct irdma_cqp_sq_wqe) * sqsize,
+ IRDMA_CQP_ALIGNMENT);
+ cqp->sq.va = dma_alloc_coherent(dev->hw->device, cqp->sq.size,
+ &cqp->sq.pa, GFP_KERNEL);
+ if (!cqp->sq.va) {
+ kfree(cqp->scratch_array);
+ kfree(cqp->cqp_requests);
+ return IRDMA_ERR_NO_MEMORY;
+ }
+
+ status = irdma_obj_aligned_mem(rf, &mem, sizeof(struct irdma_cqp_ctx),
+ IRDMA_HOST_CTX_ALIGNMENT_M);
+ if (status)
+ goto exit;
+
+ dev->cqp->host_ctx_pa = mem.pa;
+ dev->cqp->host_ctx = mem.va;
+ /* populate the cqp init info */
+ cqp_init_info.dev = dev;
+ cqp_init_info.sq_size = sqsize;
+ cqp_init_info.sq = cqp->sq.va;
+ cqp_init_info.sq_pa = cqp->sq.pa;
+ cqp_init_info.host_ctx_pa = mem.pa;
+ cqp_init_info.host_ctx = mem.va;
+ cqp_init_info.hmc_profile = rf->rsrc_profile;
+ cqp_init_info.scratch_array = cqp->scratch_array;
+ cqp_init_info.protocol_used = rf->protocol_used;
+
+ switch (rf->rdma_ver) {
+ case IRDMA_GEN_1:
+ cqp_init_info.hw_maj_ver = IRDMA_CQPHC_HW_MAJVER_GEN_1;
+ break;
+ case IRDMA_GEN_2:
+ cqp_init_info.hw_maj_ver = IRDMA_CQPHC_HW_MAJVER_GEN_2;
+ break;
+ }
+ status = irdma_sc_cqp_init(dev->cqp, &cqp_init_info);
+ if (status) {
+ ibdev_dbg(to_ibdev(dev), "ERR: cqp init status %d\n", status);
+ goto exit;
+ }
+
+ spin_lock_init(&cqp->req_lock);
+ spin_lock_init(&cqp->compl_lock);
+
+ status = irdma_sc_cqp_create(dev->cqp, &maj_err, &min_err);
+ if (status) {
+ ibdev_dbg(to_ibdev(dev),
+ "ERR: cqp create failed - status %d maj_err %d min_err %d\n",
+ status, maj_err, min_err);
+ goto exit;
+ }
+
+ INIT_LIST_HEAD(&cqp->cqp_avail_reqs);
+ INIT_LIST_HEAD(&cqp->cqp_pending_reqs);
+
+ /* init the waitqueue of the cqp_requests and add them to the list */
+ for (i = 0; i < sqsize; i++) {
+ init_waitqueue_head(&cqp->cqp_requests[i].waitq);
+ list_add_tail(&cqp->cqp_requests[i].list, &cqp->cqp_avail_reqs);
+ }
+ init_waitqueue_head(&cqp->remove_wq);
+ return 0;
+
+exit:
+ irdma_destroy_cqp(rf, false);
+
+ return status;
+}
+
+/**
+ * irdma_create_ccq - create control cq
+ * @rf: RDMA PCI function
+ *
+ * Return 0, if the ccq and the resources associated with it
+ * are successfully created, otherwise return error
+ */
+static enum irdma_status_code irdma_create_ccq(struct irdma_pci_f *rf)
+{
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ enum irdma_status_code status;
+ struct irdma_ccq_init_info info = {};
+ struct irdma_ccq *ccq = &rf->ccq;
+
+ dev->ccq = &ccq->sc_cq;
+ dev->ccq->dev = dev;
+ info.dev = dev;
+ ccq->shadow_area.size = sizeof(struct irdma_cq_shadow_area);
+ ccq->mem_cq.size = ALIGN(sizeof(struct irdma_cqe) * IW_CCQ_SIZE,
+ IRDMA_CQ0_ALIGNMENT);
+ ccq->mem_cq.va = dma_alloc_coherent(dev->hw->device, ccq->mem_cq.size,
+ &ccq->mem_cq.pa, GFP_KERNEL);
+ if (!ccq->mem_cq.va)
+ return IRDMA_ERR_NO_MEMORY;
+
+ status = irdma_obj_aligned_mem(rf, &ccq->shadow_area,
+ ccq->shadow_area.size,
+ IRDMA_SHADOWAREA_M);
+ if (status)
+ goto exit;
+
+ ccq->sc_cq.back_cq = ccq;
+ /* populate the ccq init info */
+ info.cq_base = ccq->mem_cq.va;
+ info.cq_pa = ccq->mem_cq.pa;
+ info.num_elem = IW_CCQ_SIZE;
+ info.shadow_area = ccq->shadow_area.va;
+ info.shadow_area_pa = ccq->shadow_area.pa;
+ info.ceqe_mask = false;
+ info.ceq_id_valid = true;
+ info.shadow_read_threshold = 16;
+ info.vsi = &rf->default_vsi;
+ status = irdma_sc_ccq_init(dev->ccq, &info);
+ if (!status)
+ status = irdma_sc_ccq_create(dev->ccq, 0, true, true);
+exit:
+ if (status) {
+ dma_free_coherent(dev->hw->device, ccq->mem_cq.size,
+ ccq->mem_cq.va, ccq->mem_cq.pa);
+ ccq->mem_cq.va = NULL;
+ }
+
+ return status;
+}
+
+/**
+ * irdma_alloc_set_mac - set up a mac address table entry
+ * @iwdev: irdma device
+ *
+ * Allocate a mac ip entry and add it to the hw table Return 0
+ * if successful, otherwise return error
+ */
+static enum irdma_status_code irdma_alloc_set_mac(struct irdma_device *iwdev)
+{
+ enum irdma_status_code status;
+
+ status = irdma_alloc_local_mac_entry(iwdev->rf,
+ &iwdev->mac_ip_table_idx);
+ if (!status) {
+ status = irdma_add_local_mac_entry(iwdev->rf,
+ (u8 *)iwdev->netdev->dev_addr,
+ (u8)iwdev->mac_ip_table_idx);
+ if (status)
+ irdma_del_local_mac_entry(iwdev->rf,
+ (u8)iwdev->mac_ip_table_idx);
+ }
+ return status;
+}
+
+/**
+ * irdma_cfg_ceq_vector - set up the msix interrupt vector for
+ * ceq
+ * @rf: RDMA PCI function
+ * @iwceq: ceq associated with the vector
+ * @ceq_id: the id number of the iwceq
+ * @msix_vec: interrupt vector information
+ *
+ * Allocate interrupt resources and enable irq handling
+ * Return 0 if successful, otherwise return error
+ */
+static enum irdma_status_code
+irdma_cfg_ceq_vector(struct irdma_pci_f *rf, struct irdma_ceq *iwceq,
+ u32 ceq_id, struct irdma_msix_vector *msix_vec)
+{
+ int status;
+
+ if (rf->msix_shared && !ceq_id) {
+ tasklet_setup(&rf->dpc_tasklet, irdma_dpc);
+ status = request_irq(msix_vec->irq, irdma_irq_handler, 0,
+ "AEQCEQ", rf);
+ } else {
+ tasklet_setup(&iwceq->dpc_tasklet, irdma_ceq_dpc);
+
+ status = request_irq(msix_vec->irq, irdma_ceq_handler, 0,
+ "CEQ", iwceq);
+ }
+ cpumask_clear(&msix_vec->mask);
+ cpumask_set_cpu(msix_vec->cpu_affinity, &msix_vec->mask);
+ irq_set_affinity_hint(msix_vec->irq, &msix_vec->mask);
+ if (status) {
+ ibdev_dbg(&rf->iwdev->ibdev, "ERR: ceq irq config fail\n");
+ return IRDMA_ERR_CFG;
+ }
+
+ msix_vec->ceq_id = ceq_id;
+ rf->sc_dev.irq_ops->irdma_cfg_ceq(&rf->sc_dev, ceq_id, msix_vec->idx, true);
+
+ return 0;
+}
+
+/**
+ * irdma_cfg_aeq_vector - set up the msix vector for aeq
+ * @rf: RDMA PCI function
+ *
+ * Allocate interrupt resources and enable irq handling
+ * Return 0 if successful, otherwise return error
+ */
+static enum irdma_status_code irdma_cfg_aeq_vector(struct irdma_pci_f *rf)
+{
+ struct irdma_msix_vector *msix_vec = rf->iw_msixtbl;
+ u32 ret = 0;
+
+ if (!rf->msix_shared) {
+ tasklet_setup(&rf->dpc_tasklet, irdma_dpc);
+ ret = request_irq(msix_vec->irq, irdma_irq_handler, 0,
+ "irdma", rf);
+ }
+ if (ret) {
+ ibdev_dbg(&rf->iwdev->ibdev, "ERR: aeq irq config fail\n");
+ return IRDMA_ERR_CFG;
+ }
+
+ rf->sc_dev.irq_ops->irdma_cfg_aeq(&rf->sc_dev, msix_vec->idx, true);
+
+ return 0;
+}
+
+/**
+ * irdma_create_ceq - create completion event queue
+ * @rf: RDMA PCI function
+ * @iwceq: pointer to the ceq resources to be created
+ * @ceq_id: the id number of the iwceq
+ * @vsi: SC vsi struct
+ *
+ * Return 0, if the ceq and the resources associated with it
+ * are successfully created, otherwise return error
+ */
+static enum irdma_status_code irdma_create_ceq(struct irdma_pci_f *rf,
+ struct irdma_ceq *iwceq,
+ u32 ceq_id,
+ struct irdma_sc_vsi *vsi)
+{
+ enum irdma_status_code status;
+ struct irdma_ceq_init_info info = {};
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ u64 scratch;
+ u32 ceq_size;
+
+ info.ceq_id = ceq_id;
+ iwceq->rf = rf;
+ ceq_size = min(rf->sc_dev.hmc_info->hmc_obj[IRDMA_HMC_IW_CQ].cnt,
+ dev->hw_attrs.max_hw_ceq_size);
+ iwceq->mem.size = ALIGN(sizeof(struct irdma_ceqe) * ceq_size,
+ IRDMA_CEQ_ALIGNMENT);
+ iwceq->mem.va = dma_alloc_coherent(dev->hw->device, iwceq->mem.size,
+ &iwceq->mem.pa, GFP_KERNEL);
+ if (!iwceq->mem.va)
+ return IRDMA_ERR_NO_MEMORY;
+
+ info.ceq_id = ceq_id;
+ info.ceqe_base = iwceq->mem.va;
+ info.ceqe_pa = iwceq->mem.pa;
+ info.elem_cnt = ceq_size;
+ iwceq->sc_ceq.ceq_id = ceq_id;
+ info.dev = dev;
+ info.vsi = vsi;
+ scratch = (uintptr_t)&rf->cqp.sc_cqp;
+ status = irdma_sc_ceq_init(&iwceq->sc_ceq, &info);
+ if (!status) {
+ if (dev->ceq_valid)
+ status = irdma_cqp_ceq_cmd(&rf->sc_dev, &iwceq->sc_ceq,
+ IRDMA_OP_CEQ_CREATE);
+ else
+ status = irdma_sc_cceq_create(&iwceq->sc_ceq, scratch);
+ }
+
+ if (status) {
+ dma_free_coherent(dev->hw->device, iwceq->mem.size,
+ iwceq->mem.va, iwceq->mem.pa);
+ iwceq->mem.va = NULL;
+ }
+
+ return status;
+}
+
+/**
+ * irdma_setup_ceq_0 - create CEQ 0 and it's interrupt resource
+ * @rf: RDMA PCI function
+ *
+ * Allocate a list for all device completion event queues
+ * Create the ceq 0 and configure it's msix interrupt vector
+ * Return 0, if successfully set up, otherwise return error
+ */
+static enum irdma_status_code irdma_setup_ceq_0(struct irdma_pci_f *rf)
+{
+ struct irdma_ceq *iwceq;
+ struct irdma_msix_vector *msix_vec;
+ u32 i;
+ enum irdma_status_code status = 0;
+ u32 num_ceqs;
+
+ num_ceqs = min(rf->msix_count, rf->sc_dev.hmc_fpm_misc.max_ceqs);
+ rf->ceqlist = kcalloc(num_ceqs, sizeof(*rf->ceqlist), GFP_KERNEL);
+ if (!rf->ceqlist) {
+ status = IRDMA_ERR_NO_MEMORY;
+ goto exit;
+ }
+
+ iwceq = &rf->ceqlist[0];
+ status = irdma_create_ceq(rf, iwceq, 0, &rf->default_vsi);
+ if (status) {
+ ibdev_dbg(&rf->iwdev->ibdev, "ERR: create ceq status = %d\n",
+ status);
+ goto exit;
+ }
+
+ spin_lock_init(&iwceq->ce_lock);
+ i = rf->msix_shared ? 0 : 1;
+ msix_vec = &rf->iw_msixtbl[i];
+ iwceq->irq = msix_vec->irq;
+ iwceq->msix_idx = msix_vec->idx;
+ status = irdma_cfg_ceq_vector(rf, iwceq, 0, msix_vec);
+ if (status) {
+ irdma_destroy_ceq(rf, iwceq);
+ goto exit;
+ }
+
+ irdma_ena_intr(&rf->sc_dev, msix_vec->idx);
+ rf->ceqs_count++;
+
+exit:
+ if (status && !rf->ceqs_count) {
+ kfree(rf->ceqlist);
+ rf->ceqlist = NULL;
+ return status;
+ }
+ rf->sc_dev.ceq_valid = true;
+
+ return 0;
+}
+
+/**
+ * irdma_setup_ceqs - manage the device ceq's and their interrupt resources
+ * @rf: RDMA PCI function
+ * @vsi: VSI structure for this CEQ
+ *
+ * Allocate a list for all device completion event queues
+ * Create the ceq's and configure their msix interrupt vectors
+ * Return 0, if ceqs are successfully set up, otherwise return error
+ */
+static enum irdma_status_code irdma_setup_ceqs(struct irdma_pci_f *rf,
+ struct irdma_sc_vsi *vsi)
+{
+ u32 i;
+ u32 ceq_id;
+ struct irdma_ceq *iwceq;
+ struct irdma_msix_vector *msix_vec;
+ enum irdma_status_code status;
+ u32 num_ceqs;
+
+ num_ceqs = min(rf->msix_count, rf->sc_dev.hmc_fpm_misc.max_ceqs);
+ i = (rf->msix_shared) ? 1 : 2;
+ for (ceq_id = 1; i < num_ceqs; i++, ceq_id++) {
+ iwceq = &rf->ceqlist[ceq_id];
+ status = irdma_create_ceq(rf, iwceq, ceq_id, vsi);
+ if (status) {
+ ibdev_dbg(&rf->iwdev->ibdev,
+ "ERR: create ceq status = %d\n", status);
+ goto del_ceqs;
+ }
+ spin_lock_init(&iwceq->ce_lock);
+ msix_vec = &rf->iw_msixtbl[i];
+ iwceq->irq = msix_vec->irq;
+ iwceq->msix_idx = msix_vec->idx;
+ status = irdma_cfg_ceq_vector(rf, iwceq, ceq_id, msix_vec);
+ if (status) {
+ irdma_destroy_ceq(rf, iwceq);
+ goto del_ceqs;
+ }
+ irdma_ena_intr(&rf->sc_dev, msix_vec->idx);
+ rf->ceqs_count++;
+ }
+
+ return 0;
+
+del_ceqs:
+ irdma_del_ceqs(rf);
+
+ return status;
+}
+
+static enum irdma_status_code irdma_create_virt_aeq(struct irdma_pci_f *rf,
+ u32 size)
+{
+ enum irdma_status_code status = IRDMA_ERR_NO_MEMORY;
+ struct irdma_aeq *aeq = &rf->aeq;
+ dma_addr_t *pg_arr;
+ u32 pg_cnt;
+
+ if (rf->rdma_ver < IRDMA_GEN_2)
+ return IRDMA_NOT_SUPPORTED;
+
+ aeq->mem.size = sizeof(struct irdma_sc_aeqe) * size;
+ aeq->mem.va = vzalloc(aeq->mem.size);
+
+ if (!aeq->mem.va)
+ return status;
+
+ pg_cnt = DIV_ROUND_UP(aeq->mem.size, PAGE_SIZE);
+ status = irdma_get_pble(rf->pble_rsrc, &aeq->palloc, pg_cnt, true);
+ if (status) {
+ vfree(aeq->mem.va);
+ return status;
+ }
+
+ pg_arr = (dma_addr_t *)aeq->palloc.level1.addr;
+ status = irdma_map_vm_page_list(&rf->hw, aeq->mem.va, pg_arr, pg_cnt);
+ if (status) {
+ irdma_free_pble(rf->pble_rsrc, &aeq->palloc);
+ vfree(aeq->mem.va);
+ return status;
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_create_aeq - create async event queue
+ * @rf: RDMA PCI function
+ *
+ * Return 0, if the aeq and the resources associated with it
+ * are successfully created, otherwise return error
+ */
+static enum irdma_status_code irdma_create_aeq(struct irdma_pci_f *rf)
+{
+ enum irdma_status_code status;
+ struct irdma_aeq_init_info info = {};
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ struct irdma_aeq *aeq = &rf->aeq;
+ struct irdma_hmc_info *hmc_info = rf->sc_dev.hmc_info;
+ u32 aeq_size;
+ u8 multiplier = (rf->protocol_used == IRDMA_IWARP_PROTOCOL_ONLY) ? 2 : 1;
+
+ aeq_size = multiplier * hmc_info->hmc_obj[IRDMA_HMC_IW_QP].cnt +
+ hmc_info->hmc_obj[IRDMA_HMC_IW_CQ].cnt;
+ aeq_size = min(aeq_size, dev->hw_attrs.max_hw_aeq_size);
+
+ aeq->mem.size = ALIGN(sizeof(struct irdma_sc_aeqe) * aeq_size,
+ IRDMA_AEQ_ALIGNMENT);
+ aeq->mem.va = dma_alloc_coherent(dev->hw->device, aeq->mem.size,
+ &aeq->mem.pa,
+ GFP_KERNEL | __GFP_NOWARN);
+ if (aeq->mem.va)
+ goto skip_virt_aeq;
+
+ /* physically mapped aeq failed. setup virtual aeq */
+ status = irdma_create_virt_aeq(rf, aeq_size);
+ if (status)
+ return status;
+
+ info.virtual_map = true;
+ aeq->virtual_map = info.virtual_map;
+ info.pbl_chunk_size = 1;
+ info.first_pm_pbl_idx = aeq->palloc.level1.idx;
+
+skip_virt_aeq:
+ info.aeqe_base = aeq->mem.va;
+ info.aeq_elem_pa = aeq->mem.pa;
+ info.elem_cnt = aeq_size;
+ info.dev = dev;
+ info.msix_idx = rf->iw_msixtbl->idx;
+ status = irdma_sc_aeq_init(&aeq->sc_aeq, &info);
+ if (status)
+ goto err;
+
+ status = irdma_cqp_aeq_cmd(dev, &aeq->sc_aeq, IRDMA_OP_AEQ_CREATE);
+ if (status)
+ goto err;
+
+ return 0;
+
+err:
+ if (aeq->virtual_map) {
+ irdma_destroy_virt_aeq(rf);
+ } else {
+ dma_free_coherent(dev->hw->device, aeq->mem.size, aeq->mem.va,
+ aeq->mem.pa);
+ aeq->mem.va = NULL;
+ }
+
+ return status;
+}
+
+/**
+ * irdma_setup_aeq - set up the device aeq
+ * @rf: RDMA PCI function
+ *
+ * Create the aeq and configure its msix interrupt vector
+ * Return 0 if successful, otherwise return error
+ */
+static enum irdma_status_code irdma_setup_aeq(struct irdma_pci_f *rf)
+{
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ enum irdma_status_code status;
+
+ status = irdma_create_aeq(rf);
+ if (status)
+ return status;
+
+ status = irdma_cfg_aeq_vector(rf);
+ if (status) {
+ irdma_destroy_aeq(rf);
+ return status;
+ }
+
+ if (!rf->msix_shared)
+ irdma_ena_intr(dev, rf->iw_msixtbl[0].idx);
+
+ return 0;
+}
+
+/**
+ * irdma_initialize_ilq - create iwarp local queue for cm
+ * @iwdev: irdma device
+ *
+ * Return 0 if successful, otherwise return error
+ */
+static enum irdma_status_code irdma_initialize_ilq(struct irdma_device *iwdev)
+{
+ struct irdma_puda_rsrc_info info = {};
+ enum irdma_status_code status;
+
+ info.type = IRDMA_PUDA_RSRC_TYPE_ILQ;
+ info.cq_id = 1;
+ info.qp_id = 1;
+ info.count = 1;
+ info.pd_id = 1;
+ info.abi_ver = IRDMA_ABI_VER;
+ info.sq_size = min(iwdev->rf->max_qp / 2, (u32)32768);
+ info.rq_size = info.sq_size;
+ info.buf_size = 1024;
+ info.tx_buf_cnt = 2 * info.sq_size;
+ info.receive = irdma_receive_ilq;
+ info.xmit_complete = irdma_free_sqbuf;
+ status = irdma_puda_create_rsrc(&iwdev->vsi, &info);
+ if (status)
+ ibdev_dbg(&iwdev->ibdev, "ERR: ilq create fail\n");
+
+ return status;
+}
+
+/**
+ * irdma_initialize_ieq - create iwarp exception queue
+ * @iwdev: irdma device
+ *
+ * Return 0 if successful, otherwise return error
+ */
+static enum irdma_status_code irdma_initialize_ieq(struct irdma_device *iwdev)
+{
+ struct irdma_puda_rsrc_info info = {};
+ enum irdma_status_code status;
+
+ info.type = IRDMA_PUDA_RSRC_TYPE_IEQ;
+ info.cq_id = 2;
+ info.qp_id = iwdev->vsi.exception_lan_q;
+ info.count = 1;
+ info.pd_id = 2;
+ info.abi_ver = IRDMA_ABI_VER;
+ info.sq_size = min(iwdev->rf->max_qp / 2, (u32)32768);
+ info.rq_size = info.sq_size;
+ info.buf_size = iwdev->vsi.mtu + IRDMA_IPV4_PAD;
+ info.tx_buf_cnt = 4096;
+ status = irdma_puda_create_rsrc(&iwdev->vsi, &info);
+ if (status)
+ ibdev_dbg(&iwdev->ibdev, "ERR: ieq create fail\n");
+
+ return status;
+}
+
+/**
+ * irdma_reinitialize_ieq - destroy and re-create ieq
+ * @vsi: VSI structure
+ */
+void irdma_reinitialize_ieq(struct irdma_sc_vsi *vsi)
+{
+ struct irdma_device *iwdev = vsi->back_vsi;
+ struct irdma_pci_f *rf = iwdev->rf;
+
+ irdma_puda_dele_rsrc(vsi, IRDMA_PUDA_RSRC_TYPE_IEQ, false);
+ if (irdma_initialize_ieq(iwdev)) {
+ iwdev->reset = true;
+ rf->gen_ops.request_reset(rf);
+ }
+}
+
+/**
+ * irdma_hmc_setup - create hmc objects for the device
+ * @rf: RDMA PCI function
+ *
+ * Set up the device private memory space for the number and size of
+ * the hmc objects and create the objects
+ * Return 0 if successful, otherwise return error
+ */
+static enum irdma_status_code irdma_hmc_setup(struct irdma_pci_f *rf)
+{
+ enum irdma_status_code status;
+ u32 qpcnt;
+
+ if (rf->rdma_ver == IRDMA_GEN_1)
+ qpcnt = rsrc_limits_table[rf->limits_sel].qplimit * 2;
+ else
+ qpcnt = rsrc_limits_table[rf->limits_sel].qplimit;
+
+ rf->sd_type = IRDMA_SD_TYPE_DIRECT;
+ status = irdma_cfg_fpm_val(&rf->sc_dev, qpcnt);
+ if (status)
+ return status;
+
+ status = irdma_create_hmc_objs(rf, true, rf->rdma_ver);
+
+ return status;
+}
+
+/**
+ * irdma_del_init_mem - deallocate memory resources
+ * @rf: RDMA PCI function
+ */
+static void irdma_del_init_mem(struct irdma_pci_f *rf)
+{
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+
+ kfree(dev->hmc_info->sd_table.sd_entry);
+ dev->hmc_info->sd_table.sd_entry = NULL;
+ kfree(rf->mem_rsrc);
+ rf->mem_rsrc = NULL;
+ dma_free_coherent(rf->hw.device, rf->obj_mem.size, rf->obj_mem.va,
+ rf->obj_mem.pa);
+ rf->obj_mem.va = NULL;
+ if (rf->rdma_ver != IRDMA_GEN_1) {
+ kfree(rf->allocated_ws_nodes);
+ rf->allocated_ws_nodes = NULL;
+ }
+ kfree(rf->ceqlist);
+ rf->ceqlist = NULL;
+ kfree(rf->iw_msixtbl);
+ rf->iw_msixtbl = NULL;
+ kfree(rf->hmc_info_mem);
+ rf->hmc_info_mem = NULL;
+}
+
+/**
+ * irdma_initialize_dev - initialize device
+ * @rf: RDMA PCI function
+ *
+ * Allocate memory for the hmc objects and initialize iwdev
+ * Return 0 if successful, otherwise clean up the resources
+ * and return error
+ */
+static enum irdma_status_code irdma_initialize_dev(struct irdma_pci_f *rf)
+{
+ enum irdma_status_code status;
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ struct irdma_device_init_info info = {};
+ struct irdma_dma_mem mem;
+ u32 size;
+
+ size = sizeof(struct irdma_hmc_pble_rsrc) +
+ sizeof(struct irdma_hmc_info) +
+ (sizeof(struct irdma_hmc_obj_info) * IRDMA_HMC_IW_MAX);
+
+ rf->hmc_info_mem = kzalloc(size, GFP_KERNEL);
+ if (!rf->hmc_info_mem)
+ return IRDMA_ERR_NO_MEMORY;
+
+ rf->pble_rsrc = (struct irdma_hmc_pble_rsrc *)rf->hmc_info_mem;
+ dev->hmc_info = &rf->hw.hmc;
+ dev->hmc_info->hmc_obj = (struct irdma_hmc_obj_info *)
+ (rf->pble_rsrc + 1);
+
+ status = irdma_obj_aligned_mem(rf, &mem, IRDMA_QUERY_FPM_BUF_SIZE,
+ IRDMA_FPM_QUERY_BUF_ALIGNMENT_M);
+ if (status)
+ goto error;
+
+ info.fpm_query_buf_pa = mem.pa;
+ info.fpm_query_buf = mem.va;
+
+ status = irdma_obj_aligned_mem(rf, &mem, IRDMA_COMMIT_FPM_BUF_SIZE,
+ IRDMA_FPM_COMMIT_BUF_ALIGNMENT_M);
+ if (status)
+ goto error;
+
+ info.fpm_commit_buf_pa = mem.pa;
+ info.fpm_commit_buf = mem.va;
+
+ info.bar0 = rf->hw.hw_addr;
+ info.hmc_fn_id = PCI_FUNC(rf->pcidev->devfn);
+ info.hw = &rf->hw;
+ status = irdma_sc_dev_init(rf->rdma_ver, &rf->sc_dev, &info);
+ if (status)
+ goto error;
+
+ return status;
+error:
+ kfree(rf->hmc_info_mem);
+ rf->hmc_info_mem = NULL;
+
+ return status;
+}
+
+/**
+ * irdma_rt_deinit_hw - clean up the irdma device resources
+ * @iwdev: irdma device
+ *
+ * remove the mac ip entry and ipv4/ipv6 addresses, destroy the
+ * device queues and free the pble and the hmc objects
+ */
+void irdma_rt_deinit_hw(struct irdma_device *iwdev)
+{
+ ibdev_dbg(&iwdev->ibdev, "INIT: state = %d\n", iwdev->init_state);
+
+ switch (iwdev->init_state) {
+ case IP_ADDR_REGISTERED:
+ if (iwdev->rf->sc_dev.hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1)
+ irdma_del_local_mac_entry(iwdev->rf,
+ (u8)iwdev->mac_ip_table_idx);
+ fallthrough;
+ case AEQ_CREATED:
+ case PBLE_CHUNK_MEM:
+ case CEQS_CREATED:
+ case IEQ_CREATED:
+ if (!iwdev->roce_mode)
+ irdma_puda_dele_rsrc(&iwdev->vsi, IRDMA_PUDA_RSRC_TYPE_IEQ,
+ iwdev->reset);
+ fallthrough;
+ case ILQ_CREATED:
+ if (!iwdev->roce_mode)
+ irdma_puda_dele_rsrc(&iwdev->vsi,
+ IRDMA_PUDA_RSRC_TYPE_ILQ,
+ iwdev->reset);
+ break;
+ default:
+ ibdev_warn(&iwdev->ibdev, "bad init_state = %d\n", iwdev->init_state);
+ break;
+ }
+
+ irdma_cleanup_cm_core(&iwdev->cm_core);
+ if (iwdev->vsi.pestat) {
+ irdma_vsi_stats_free(&iwdev->vsi);
+ kfree(iwdev->vsi.pestat);
+ }
+ if (iwdev->cleanup_wq)
+ destroy_workqueue(iwdev->cleanup_wq);
+}
+
+static enum irdma_status_code irdma_setup_init_state(struct irdma_pci_f *rf)
+{
+ enum irdma_status_code status;
+
+ status = irdma_save_msix_info(rf);
+ if (status)
+ return status;
+
+ rf->hw.device = &rf->pcidev->dev;
+ rf->obj_mem.size = ALIGN(8192, IRDMA_HW_PAGE_SIZE);
+ rf->obj_mem.va = dma_alloc_coherent(rf->hw.device, rf->obj_mem.size,
+ &rf->obj_mem.pa, GFP_KERNEL);
+ if (!rf->obj_mem.va) {
+ status = IRDMA_ERR_NO_MEMORY;
+ goto clean_msixtbl;
+ }
+
+ rf->obj_next = rf->obj_mem;
+ status = irdma_initialize_dev(rf);
+ if (status)
+ goto clean_obj_mem;
+
+ return 0;
+
+clean_obj_mem:
+ dma_free_coherent(rf->hw.device, rf->obj_mem.size, rf->obj_mem.va,
+ rf->obj_mem.pa);
+ rf->obj_mem.va = NULL;
+clean_msixtbl:
+ kfree(rf->iw_msixtbl);
+ rf->iw_msixtbl = NULL;
+ return status;
+}
+
+/**
+ * irdma_get_used_rsrc - determine resources used internally
+ * @iwdev: irdma device
+ *
+ * Called at the end of open to get all internal allocations
+ */
+static void irdma_get_used_rsrc(struct irdma_device *iwdev)
+{
+ iwdev->rf->used_pds = find_next_zero_bit(iwdev->rf->allocated_pds,
+ iwdev->rf->max_pd, 0);
+ iwdev->rf->used_qps = find_next_zero_bit(iwdev->rf->allocated_qps,
+ iwdev->rf->max_qp, 0);
+ iwdev->rf->used_cqs = find_next_zero_bit(iwdev->rf->allocated_cqs,
+ iwdev->rf->max_cq, 0);
+ iwdev->rf->used_mrs = find_next_zero_bit(iwdev->rf->allocated_mrs,
+ iwdev->rf->max_mr, 0);
+}
+
+void irdma_ctrl_deinit_hw(struct irdma_pci_f *rf)
+{
+ enum init_completion_state state = rf->init_state;
+
+ rf->init_state = INVALID_STATE;
+ if (rf->rsrc_created) {
+ irdma_destroy_aeq(rf);
+ irdma_destroy_pble_prm(rf->pble_rsrc);
+ irdma_del_ceqs(rf);
+ rf->rsrc_created = false;
+ }
+ switch (state) {
+ case CEQ0_CREATED:
+ irdma_del_ceq_0(rf);
+ fallthrough;
+ case CCQ_CREATED:
+ irdma_destroy_ccq(rf);
+ fallthrough;
+ case HW_RSRC_INITIALIZED:
+ case HMC_OBJS_CREATED:
+ irdma_del_hmc_objects(&rf->sc_dev, rf->sc_dev.hmc_info, true,
+ rf->reset, rf->rdma_ver);
+ fallthrough;
+ case CQP_CREATED:
+ irdma_destroy_cqp(rf, true);
+ fallthrough;
+ case INITIAL_STATE:
+ irdma_del_init_mem(rf);
+ break;
+ case INVALID_STATE:
+ default:
+ ibdev_warn(&rf->iwdev->ibdev, "bad init_state = %d\n", rf->init_state);
+ break;
+ }
+}
+
+/**
+ * irdma_rt_init_hw - Initializes runtime portion of HW
+ * @iwdev: irdma device
+ * @l2params: qos, tc, mtu info from netdev driver
+ *
+ * Create device queues ILQ, IEQ, CEQs and PBLEs. Setup irdma
+ * device resource objects.
+ */
+enum irdma_status_code irdma_rt_init_hw(struct irdma_device *iwdev,
+ struct irdma_l2params *l2params)
+{
+ struct irdma_pci_f *rf = iwdev->rf;
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ enum irdma_status_code status;
+ struct irdma_vsi_init_info vsi_info = {};
+ struct irdma_vsi_stats_info stats_info = {};
+
+ vsi_info.dev = dev;
+ vsi_info.back_vsi = iwdev;
+ vsi_info.params = l2params;
+ vsi_info.pf_data_vsi_num = iwdev->vsi_num;
+ vsi_info.register_qset = rf->gen_ops.register_qset;
+ vsi_info.unregister_qset = rf->gen_ops.unregister_qset;
+ vsi_info.exception_lan_q = 2;
+ irdma_sc_vsi_init(&iwdev->vsi, &vsi_info);
+
+ status = irdma_setup_cm_core(iwdev, rf->rdma_ver);
+ if (status)
+ return status;
+
+ stats_info.pestat = kzalloc(sizeof(*stats_info.pestat), GFP_KERNEL);
+ if (!stats_info.pestat) {
+ irdma_cleanup_cm_core(&iwdev->cm_core);
+ return IRDMA_ERR_NO_MEMORY;
+ }
+ stats_info.fcn_id = dev->hmc_fn_id;
+ status = irdma_vsi_stats_init(&iwdev->vsi, &stats_info);
+ if (status) {
+ irdma_cleanup_cm_core(&iwdev->cm_core);
+ kfree(stats_info.pestat);
+ return status;
+ }
+
+ do {
+ if (!iwdev->roce_mode) {
+ status = irdma_initialize_ilq(iwdev);
+ if (status)
+ break;
+ iwdev->init_state = ILQ_CREATED;
+ status = irdma_initialize_ieq(iwdev);
+ if (status)
+ break;
+ iwdev->init_state = IEQ_CREATED;
+ }
+ if (!rf->rsrc_created) {
+ status = irdma_setup_ceqs(rf, &iwdev->vsi);
+ if (status)
+ break;
+
+ iwdev->init_state = CEQS_CREATED;
+
+ status = irdma_hmc_init_pble(&rf->sc_dev,
+ rf->pble_rsrc);
+ if (status) {
+ irdma_del_ceqs(rf);
+ break;
+ }
+
+ iwdev->init_state = PBLE_CHUNK_MEM;
+
+ status = irdma_setup_aeq(rf);
+ if (status) {
+ irdma_destroy_pble_prm(rf->pble_rsrc);
+ irdma_del_ceqs(rf);
+ break;
+ }
+ iwdev->init_state = AEQ_CREATED;
+ rf->rsrc_created = true;
+ }
+
+ iwdev->device_cap_flags = IB_DEVICE_LOCAL_DMA_LKEY |
+ IB_DEVICE_MEM_WINDOW |
+ IB_DEVICE_MEM_MGT_EXTENSIONS;
+
+ if (iwdev->rf->sc_dev.hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1)
+ irdma_alloc_set_mac(iwdev);
+ irdma_add_ip(iwdev);
+ iwdev->init_state = IP_ADDR_REGISTERED;
+
+ /* handles asynch cleanup tasks - disconnect CM , free qp,
+ * free cq bufs
+ */
+ iwdev->cleanup_wq = alloc_workqueue("irdma-cleanup-wq",
+ WQ_UNBOUND, WQ_UNBOUND_MAX_ACTIVE);
+ if (!iwdev->cleanup_wq)
+ return IRDMA_ERR_NO_MEMORY;
+ irdma_get_used_rsrc(iwdev);
+ init_waitqueue_head(&iwdev->suspend_wq);
+
+ return 0;
+ } while (0);
+
+ dev_err(&rf->pcidev->dev, "HW runtime init FAIL status = %d last cmpl = %d\n",
+ status, iwdev->init_state);
+ irdma_rt_deinit_hw(iwdev);
+
+ return status;
+}
+
+/**
+ * irdma_ctrl_init_hw - Initializes control portion of HW
+ * @rf: RDMA PCI function
+ *
+ * Create admin queues, HMC obejcts and RF resource objects
+ */
+enum irdma_status_code irdma_ctrl_init_hw(struct irdma_pci_f *rf)
+{
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ enum irdma_status_code status;
+ do {
+ status = irdma_setup_init_state(rf);
+ if (status)
+ break;
+ rf->init_state = INITIAL_STATE;
+
+ status = irdma_create_cqp(rf);
+ if (status)
+ break;
+ rf->init_state = CQP_CREATED;
+
+ status = irdma_hmc_setup(rf);
+ if (status)
+ break;
+ rf->init_state = HMC_OBJS_CREATED;
+
+ status = irdma_initialize_hw_rsrc(rf);
+ if (status)
+ break;
+ rf->init_state = HW_RSRC_INITIALIZED;
+
+ status = irdma_create_ccq(rf);
+ if (status)
+ break;
+ rf->init_state = CCQ_CREATED;
+
+ dev->feature_info[IRDMA_FEATURE_FW_INFO] = IRDMA_FW_VER_DEFAULT;
+ if (rf->rdma_ver != IRDMA_GEN_1) {
+ status = irdma_get_rdma_features(dev);
+ if (status)
+ break;
+ }
+
+ status = irdma_setup_ceq_0(rf);
+ if (status)
+ break;
+ rf->init_state = CEQ0_CREATED;
+ /* Handles processing of CQP completions */
+ rf->cqp_cmpl_wq = alloc_ordered_workqueue("cqp_cmpl_wq",
+ WQ_HIGHPRI | WQ_UNBOUND);
+ if (!rf->cqp_cmpl_wq) {
+ status = IRDMA_ERR_NO_MEMORY;
+ break;
+ }
+ INIT_WORK(&rf->cqp_cmpl_work, cqp_compl_worker);
+ irdma_sc_ccq_arm(dev->ccq);
+ return 0;
+ } while (0);
+
+ dev_err(&rf->pcidev->dev, "IRDMA hardware initialization FAILED init_state=%d status=%d\n",
+ rf->init_state, status);
+ irdma_ctrl_deinit_hw(rf);
+ return status;
+}
+
+/**
+ * irdma_set_hw_rsrc - set hw memory resources.
+ * @rf: RDMA PCI function
+ */
+static u32 irdma_set_hw_rsrc(struct irdma_pci_f *rf)
+{
+ rf->allocated_qps = (void *)(rf->mem_rsrc +
+ (sizeof(struct irdma_arp_entry) * rf->arp_table_size));
+ rf->allocated_cqs = &rf->allocated_qps[BITS_TO_LONGS(rf->max_qp)];
+ rf->allocated_mrs = &rf->allocated_cqs[BITS_TO_LONGS(rf->max_cq)];
+ rf->allocated_pds = &rf->allocated_mrs[BITS_TO_LONGS(rf->max_mr)];
+ rf->allocated_ahs = &rf->allocated_pds[BITS_TO_LONGS(rf->max_pd)];
+ rf->allocated_mcgs = &rf->allocated_ahs[BITS_TO_LONGS(rf->max_ah)];
+ rf->allocated_arps = &rf->allocated_mcgs[BITS_TO_LONGS(rf->max_mcg)];
+ rf->qp_table = (struct irdma_qp **)
+ (&rf->allocated_arps[BITS_TO_LONGS(rf->arp_table_size)]);
+
+ spin_lock_init(&rf->rsrc_lock);
+ spin_lock_init(&rf->arp_lock);
+ spin_lock_init(&rf->qptable_lock);
+ spin_lock_init(&rf->qh_list_lock);
+
+ return 0;
+}
+
+/**
+ * irdma_calc_mem_rsrc_size - calculate memory resources size.
+ * @rf: RDMA PCI function
+ */
+static u32 irdma_calc_mem_rsrc_size(struct irdma_pci_f *rf)
+{
+ u32 rsrc_size;
+
+ rsrc_size = sizeof(struct irdma_arp_entry) * rf->arp_table_size;
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_qp);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_mr);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_cq);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_pd);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->arp_table_size);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_ah);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_mcg);
+ rsrc_size += sizeof(struct irdma_qp **) * rf->max_qp;
+
+ return rsrc_size;
+}
+
+/**
+ * irdma_initialize_hw_rsrc - initialize hw resource tracking array
+ * @rf: RDMA PCI function
+ */
+u32 irdma_initialize_hw_rsrc(struct irdma_pci_f *rf)
+{
+ u32 rsrc_size;
+ u32 mrdrvbits;
+ u32 ret;
+
+ if (rf->rdma_ver != IRDMA_GEN_1) {
+ rf->allocated_ws_nodes =
+ kcalloc(BITS_TO_LONGS(IRDMA_MAX_WS_NODES),
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!rf->allocated_ws_nodes)
+ return -ENOMEM;
+
+ set_bit(0, rf->allocated_ws_nodes);
+ rf->max_ws_node_id = IRDMA_MAX_WS_NODES;
+ }
+ rf->max_cqe = rf->sc_dev.hw_attrs.uk_attrs.max_hw_cq_size;
+ rf->max_qp = rf->sc_dev.hmc_info->hmc_obj[IRDMA_HMC_IW_QP].cnt;
+ rf->max_mr = rf->sc_dev.hmc_info->hmc_obj[IRDMA_HMC_IW_MR].cnt;
+ rf->max_cq = rf->sc_dev.hmc_info->hmc_obj[IRDMA_HMC_IW_CQ].cnt;
+ rf->max_pd = rf->sc_dev.hw_attrs.max_hw_pds;
+ rf->arp_table_size = rf->sc_dev.hmc_info->hmc_obj[IRDMA_HMC_IW_ARP].cnt;
+ rf->max_ah = rf->sc_dev.hmc_info->hmc_obj[IRDMA_HMC_IW_FSIAV].cnt;
+ rf->max_mcg = rf->max_qp;
+
+ rsrc_size = irdma_calc_mem_rsrc_size(rf);
+ rf->mem_rsrc = kzalloc(rsrc_size, GFP_KERNEL);
+ if (!rf->mem_rsrc) {
+ ret = -ENOMEM;
+ goto mem_rsrc_kzalloc_fail;
+ }
+
+ rf->arp_table = (struct irdma_arp_entry *)rf->mem_rsrc;
+
+ ret = irdma_set_hw_rsrc(rf);
+ if (ret)
+ goto set_hw_rsrc_fail;
+
+ set_bit(0, rf->allocated_mrs);
+ set_bit(0, rf->allocated_qps);
+ set_bit(0, rf->allocated_cqs);
+ set_bit(0, rf->allocated_pds);
+ set_bit(0, rf->allocated_arps);
+ set_bit(0, rf->allocated_ahs);
+ set_bit(0, rf->allocated_mcgs);
+ set_bit(2, rf->allocated_qps); /* qp 2 IEQ */
+ set_bit(1, rf->allocated_qps); /* qp 1 ILQ */
+ set_bit(1, rf->allocated_cqs);
+ set_bit(1, rf->allocated_pds);
+ set_bit(2, rf->allocated_cqs);
+ set_bit(2, rf->allocated_pds);
+
+ INIT_LIST_HEAD(&rf->mc_qht_list.list);
+ /* stag index mask has a minimum of 14 bits */
+ mrdrvbits = 24 - max(get_count_order(rf->max_mr), 14);
+ rf->mr_stagmask = ~(((1 << mrdrvbits) - 1) << (32 - mrdrvbits));
+
+ return 0;
+
+set_hw_rsrc_fail:
+ kfree(rf->mem_rsrc);
+ rf->mem_rsrc = NULL;
+mem_rsrc_kzalloc_fail:
+ kfree(rf->allocated_ws_nodes);
+ rf->allocated_ws_nodes = NULL;
+
+ return ret;
+}
+
+/**
+ * irdma_cqp_ce_handler - handle cqp completions
+ * @rf: RDMA PCI function
+ * @cq: cq for cqp completions
+ */
+void irdma_cqp_ce_handler(struct irdma_pci_f *rf, struct irdma_sc_cq *cq)
+{
+ struct irdma_cqp_request *cqp_request;
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ u32 cqe_count = 0;
+ struct irdma_ccq_cqe_info info;
+ unsigned long flags;
+ int ret;
+
+ do {
+ memset(&info, 0, sizeof(info));
+ spin_lock_irqsave(&rf->cqp.compl_lock, flags);
+ ret = irdma_sc_ccq_get_cqe_info(cq, &info);
+ spin_unlock_irqrestore(&rf->cqp.compl_lock, flags);
+ if (ret)
+ break;
+
+ cqp_request = (struct irdma_cqp_request *)
+ (unsigned long)info.scratch;
+ if (info.error && irdma_cqp_crit_err(dev, cqp_request->info.cqp_cmd,
+ info.maj_err_code,
+ info.min_err_code))
+ ibdev_err(&rf->iwdev->ibdev, "cqp opcode = 0x%x maj_err_code = 0x%x min_err_code = 0x%x\n",
+ info.op_code, info.maj_err_code, info.min_err_code);
+ if (cqp_request) {
+ cqp_request->compl_info.maj_err_code = info.maj_err_code;
+ cqp_request->compl_info.min_err_code = info.min_err_code;
+ cqp_request->compl_info.op_ret_val = info.op_ret_val;
+ cqp_request->compl_info.error = info.error;
+
+ if (cqp_request->waiting) {
+ cqp_request->request_done = true;
+ wake_up(&cqp_request->waitq);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+ } else {
+ if (cqp_request->callback_fcn)
+ cqp_request->callback_fcn(cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+ }
+ }
+
+ cqe_count++;
+ } while (1);
+
+ if (cqe_count) {
+ irdma_process_bh(dev);
+ irdma_sc_ccq_arm(cq);
+ }
+}
+
+/**
+ * cqp_compl_worker - Handle cqp completions
+ * @work: Pointer to work structure
+ */
+void cqp_compl_worker(struct work_struct *work)
+{
+ struct irdma_pci_f *rf = container_of(work, struct irdma_pci_f,
+ cqp_cmpl_work);
+ struct irdma_sc_cq *cq = &rf->ccq.sc_cq;
+
+ irdma_cqp_ce_handler(rf, cq);
+}
+
+/**
+ * irdma_lookup_apbvt_entry - lookup hash table for an existing apbvt entry corresponding to port
+ * @cm_core: cm's core
+ * @port: port to identify apbvt entry
+ */
+static struct irdma_apbvt_entry *irdma_lookup_apbvt_entry(struct irdma_cm_core *cm_core,
+ u16 port)
+{
+ struct irdma_apbvt_entry *entry;
+
+ hash_for_each_possible(cm_core->apbvt_hash_tbl, entry, hlist, port) {
+ if (entry->port == port) {
+ entry->use_cnt++;
+ return entry;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * irdma_next_iw_state - modify qp state
+ * @iwqp: iwarp qp to modify
+ * @state: next state for qp
+ * @del_hash: del hash
+ * @term: term message
+ * @termlen: length of term message
+ */
+void irdma_next_iw_state(struct irdma_qp *iwqp, u8 state, u8 del_hash, u8 term,
+ u8 termlen)
+{
+ struct irdma_modify_qp_info info = {};
+
+ info.next_iwarp_state = state;
+ info.remove_hash_idx = del_hash;
+ info.cq_num_valid = true;
+ info.arp_cache_idx_valid = true;
+ info.dont_send_term = true;
+ info.dont_send_fin = true;
+ info.termlen = termlen;
+
+ if (term & IRDMAQP_TERM_SEND_TERM_ONLY)
+ info.dont_send_term = false;
+ if (term & IRDMAQP_TERM_SEND_FIN_ONLY)
+ info.dont_send_fin = false;
+ if (iwqp->sc_qp.term_flags && state == IRDMA_QP_STATE_ERROR)
+ info.reset_tcp_conn = true;
+ iwqp->hw_iwarp_state = state;
+ irdma_hw_modify_qp(iwqp->iwdev, iwqp, &info, 0);
+ iwqp->iwarp_state = info.next_iwarp_state;
+}
+
+/**
+ * irdma_del_local_mac_entry - remove a mac entry from the hw
+ * table
+ * @rf: RDMA PCI function
+ * @idx: the index of the mac ip address to delete
+ */
+void irdma_del_local_mac_entry(struct irdma_pci_f *rf, u16 idx)
+{
+ struct irdma_cqp *iwcqp = &rf->cqp;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, true);
+ if (!cqp_request)
+ return;
+
+ cqp_info = &cqp_request->info;
+ cqp_info->cqp_cmd = IRDMA_OP_DELETE_LOCAL_MAC_ENTRY;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.del_local_mac_entry.cqp = &iwcqp->sc_cqp;
+ cqp_info->in.u.del_local_mac_entry.scratch = (uintptr_t)cqp_request;
+ cqp_info->in.u.del_local_mac_entry.entry_idx = idx;
+ cqp_info->in.u.del_local_mac_entry.ignore_ref_count = 0;
+
+ irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(iwcqp, cqp_request);
+}
+
+/**
+ * irdma_add_local_mac_entry - add a mac ip address entry to the
+ * hw table
+ * @rf: RDMA PCI function
+ * @mac_addr: pointer to mac address
+ * @idx: the index of the mac ip address to add
+ */
+int irdma_add_local_mac_entry(struct irdma_pci_f *rf, u8 *mac_addr, u16 idx)
+{
+ struct irdma_local_mac_entry_info *info;
+ struct irdma_cqp *iwcqp = &rf->cqp;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, true);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ cqp_info->post_sq = 1;
+ info = &cqp_info->in.u.add_local_mac_entry.info;
+ ether_addr_copy(info->mac_addr, mac_addr);
+ info->entry_idx = idx;
+ cqp_info->in.u.add_local_mac_entry.scratch = (uintptr_t)cqp_request;
+ cqp_info->cqp_cmd = IRDMA_OP_ADD_LOCAL_MAC_ENTRY;
+ cqp_info->in.u.add_local_mac_entry.cqp = &iwcqp->sc_cqp;
+ cqp_info->in.u.add_local_mac_entry.scratch = (uintptr_t)cqp_request;
+
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(iwcqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_alloc_local_mac_entry - allocate a mac entry
+ * @rf: RDMA PCI function
+ * @mac_tbl_idx: the index of the new mac address
+ *
+ * Allocate a mac address entry and update the mac_tbl_idx
+ * to hold the index of the newly created mac address
+ * Return 0 if successful, otherwise return error
+ */
+int irdma_alloc_local_mac_entry(struct irdma_pci_f *rf, u16 *mac_tbl_idx)
+{
+ struct irdma_cqp *iwcqp = &rf->cqp;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ enum irdma_status_code status = 0;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, true);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ cqp_info->cqp_cmd = IRDMA_OP_ALLOC_LOCAL_MAC_ENTRY;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.alloc_local_mac_entry.cqp = &iwcqp->sc_cqp;
+ cqp_info->in.u.alloc_local_mac_entry.scratch = (uintptr_t)cqp_request;
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ if (!status)
+ *mac_tbl_idx = (u16)cqp_request->compl_info.op_ret_val;
+
+ irdma_put_cqp_request(iwcqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_cqp_manage_apbvt_cmd - send cqp command manage apbvt
+ * @iwdev: irdma device
+ * @accel_local_port: port for apbvt
+ * @add_port: add ordelete port
+ */
+static enum irdma_status_code
+irdma_cqp_manage_apbvt_cmd(struct irdma_device *iwdev, u16 accel_local_port,
+ bool add_port)
+{
+ struct irdma_apbvt_info *info;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, add_port);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ info = &cqp_info->in.u.manage_apbvt_entry.info;
+ memset(info, 0, sizeof(*info));
+ info->add = add_port;
+ info->port = accel_local_port;
+ cqp_info->cqp_cmd = IRDMA_OP_MANAGE_APBVT_ENTRY;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.manage_apbvt_entry.cqp = &iwdev->rf->cqp.sc_cqp;
+ cqp_info->in.u.manage_apbvt_entry.scratch = (uintptr_t)cqp_request;
+ ibdev_dbg(&iwdev->ibdev, "DEV: %s: port=0x%04x\n",
+ (!add_port) ? "DELETE" : "ADD", accel_local_port);
+
+ status = irdma_handle_cqp_op(iwdev->rf, cqp_request);
+ irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_add_apbvt - add tcp port to HW apbvt table
+ * @iwdev: irdma device
+ * @port: port for apbvt
+ */
+struct irdma_apbvt_entry *irdma_add_apbvt(struct irdma_device *iwdev, u16 port)
+{
+ struct irdma_cm_core *cm_core = &iwdev->cm_core;
+ struct irdma_apbvt_entry *entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cm_core->apbvt_lock, flags);
+ entry = irdma_lookup_apbvt_entry(cm_core, port);
+ if (entry) {
+ spin_unlock_irqrestore(&cm_core->apbvt_lock, flags);
+ return entry;
+ }
+
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry) {
+ spin_unlock_irqrestore(&cm_core->apbvt_lock, flags);
+ return NULL;
+ }
+
+ entry->port = port;
+ entry->use_cnt = 1;
+ hash_add(cm_core->apbvt_hash_tbl, &entry->hlist, entry->port);
+ spin_unlock_irqrestore(&cm_core->apbvt_lock, flags);
+
+ if (irdma_cqp_manage_apbvt_cmd(iwdev, port, true)) {
+ kfree(entry);
+ return NULL;
+ }
+
+ return entry;
+}
+
+/**
+ * irdma_del_apbvt - delete tcp port from HW apbvt table
+ * @iwdev: irdma device
+ * @entry: apbvt entry object
+ */
+void irdma_del_apbvt(struct irdma_device *iwdev,
+ struct irdma_apbvt_entry *entry)
+{
+ struct irdma_cm_core *cm_core = &iwdev->cm_core;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cm_core->apbvt_lock, flags);
+ if (--entry->use_cnt) {
+ spin_unlock_irqrestore(&cm_core->apbvt_lock, flags);
+ return;
+ }
+
+ hash_del(&entry->hlist);
+ /* apbvt_lock is held across CQP delete APBVT OP (non-waiting) to
+ * protect against race where add APBVT CQP can race ahead of the delete
+ * APBVT for same port.
+ */
+ irdma_cqp_manage_apbvt_cmd(iwdev, entry->port, false);
+ kfree(entry);
+ spin_unlock_irqrestore(&cm_core->apbvt_lock, flags);
+}
+
+/**
+ * irdma_manage_arp_cache - manage hw arp cache
+ * @rf: RDMA PCI function
+ * @mac_addr: mac address ptr
+ * @ip_addr: ip addr for arp cache
+ * @ipv4: flag inicating IPv4
+ * @action: add, delete or modify
+ */
+void irdma_manage_arp_cache(struct irdma_pci_f *rf, unsigned char *mac_addr,
+ u32 *ip_addr, bool ipv4, u32 action)
+{
+ struct irdma_add_arp_cache_entry_info *info;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ int arp_index;
+
+ arp_index = irdma_arp_table(rf, ip_addr, ipv4, mac_addr, action);
+ if (arp_index == -1)
+ return;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, false);
+ if (!cqp_request)
+ return;
+
+ cqp_info = &cqp_request->info;
+ if (action == IRDMA_ARP_ADD) {
+ cqp_info->cqp_cmd = IRDMA_OP_ADD_ARP_CACHE_ENTRY;
+ info = &cqp_info->in.u.add_arp_cache_entry.info;
+ memset(info, 0, sizeof(*info));
+ info->arp_index = (u16)arp_index;
+ info->permanent = true;
+ ether_addr_copy(info->mac_addr, mac_addr);
+ cqp_info->in.u.add_arp_cache_entry.scratch =
+ (uintptr_t)cqp_request;
+ cqp_info->in.u.add_arp_cache_entry.cqp = &rf->cqp.sc_cqp;
+ } else {
+ cqp_info->cqp_cmd = IRDMA_OP_DELETE_ARP_CACHE_ENTRY;
+ cqp_info->in.u.del_arp_cache_entry.scratch =
+ (uintptr_t)cqp_request;
+ cqp_info->in.u.del_arp_cache_entry.cqp = &rf->cqp.sc_cqp;
+ cqp_info->in.u.del_arp_cache_entry.arp_index = arp_index;
+ }
+
+ cqp_info->post_sq = 1;
+ irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+}
+
+/**
+ * irdma_send_syn_cqp_callback - do syn/ack after qhash
+ * @cqp_request: qhash cqp completion
+ */
+static void irdma_send_syn_cqp_callback(struct irdma_cqp_request *cqp_request)
+{
+ struct irdma_cm_node *cm_node = cqp_request->param;
+
+ irdma_send_syn(cm_node, 1);
+ irdma_rem_ref_cm_node(cm_node);
+}
+
+/**
+ * irdma_manage_qhash - add or modify qhash
+ * @iwdev: irdma device
+ * @cminfo: cm info for qhash
+ * @etype: type (syn or quad)
+ * @mtype: type of qhash
+ * @cmnode: cmnode associated with connection
+ * @wait: wait for completion
+ */
+enum irdma_status_code
+irdma_manage_qhash(struct irdma_device *iwdev, struct irdma_cm_info *cminfo,
+ enum irdma_quad_entry_type etype,
+ enum irdma_quad_hash_manage_type mtype, void *cmnode,
+ bool wait)
+{
+ struct irdma_qhash_table_info *info;
+ enum irdma_status_code status;
+ struct irdma_cqp *iwcqp = &iwdev->rf->cqp;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_cm_node *cm_node = cmnode;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, wait);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ info = &cqp_info->in.u.manage_qhash_table_entry.info;
+ memset(info, 0, sizeof(*info));
+ info->vsi = &iwdev->vsi;
+ info->manage = mtype;
+ info->entry_type = etype;
+ if (cminfo->vlan_id < VLAN_N_VID) {
+ info->vlan_valid = true;
+ info->vlan_id = cminfo->vlan_id;
+ } else {
+ info->vlan_valid = false;
+ }
+ info->ipv4_valid = cminfo->ipv4;
+ info->user_pri = cminfo->user_pri;
+ ether_addr_copy(info->mac_addr, iwdev->netdev->dev_addr);
+ info->qp_num = cminfo->qh_qpid;
+ info->dest_port = cminfo->loc_port;
+ info->dest_ip[0] = cminfo->loc_addr[0];
+ info->dest_ip[1] = cminfo->loc_addr[1];
+ info->dest_ip[2] = cminfo->loc_addr[2];
+ info->dest_ip[3] = cminfo->loc_addr[3];
+ if (etype == IRDMA_QHASH_TYPE_TCP_ESTABLISHED ||
+ etype == IRDMA_QHASH_TYPE_UDP_UNICAST ||
+ etype == IRDMA_QHASH_TYPE_UDP_MCAST ||
+ etype == IRDMA_QHASH_TYPE_ROCE_MCAST ||
+ etype == IRDMA_QHASH_TYPE_ROCEV2_HW) {
+ info->src_port = cminfo->rem_port;
+ info->src_ip[0] = cminfo->rem_addr[0];
+ info->src_ip[1] = cminfo->rem_addr[1];
+ info->src_ip[2] = cminfo->rem_addr[2];
+ info->src_ip[3] = cminfo->rem_addr[3];
+ }
+ if (cmnode) {
+ cqp_request->callback_fcn = irdma_send_syn_cqp_callback;
+ cqp_request->param = cmnode;
+ if (!wait)
+ refcount_inc(&cm_node->refcnt);
+ }
+ if (info->ipv4_valid)
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: %s caller: %pS loc_port=0x%04x rem_port=0x%04x loc_addr=%pI4 rem_addr=%pI4 mac=%pM, vlan_id=%d cm_node=%p\n",
+ (!mtype) ? "DELETE" : "ADD",
+ __builtin_return_address(0), info->dest_port,
+ info->src_port, info->dest_ip, info->src_ip,
+ info->mac_addr, cminfo->vlan_id,
+ cmnode ? cmnode : NULL);
+ else
+ ibdev_dbg(&iwdev->ibdev,
+ "CM: %s caller: %pS loc_port=0x%04x rem_port=0x%04x loc_addr=%pI6 rem_addr=%pI6 mac=%pM, vlan_id=%d cm_node=%p\n",
+ (!mtype) ? "DELETE" : "ADD",
+ __builtin_return_address(0), info->dest_port,
+ info->src_port, info->dest_ip, info->src_ip,
+ info->mac_addr, cminfo->vlan_id,
+ cmnode ? cmnode : NULL);
+
+ cqp_info->in.u.manage_qhash_table_entry.cqp = &iwdev->rf->cqp.sc_cqp;
+ cqp_info->in.u.manage_qhash_table_entry.scratch = (uintptr_t)cqp_request;
+ cqp_info->cqp_cmd = IRDMA_OP_MANAGE_QHASH_TABLE_ENTRY;
+ cqp_info->post_sq = 1;
+ status = irdma_handle_cqp_op(iwdev->rf, cqp_request);
+ if (status && cm_node && !wait)
+ irdma_rem_ref_cm_node(cm_node);
+
+ irdma_put_cqp_request(iwcqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_hw_flush_wqes_callback - Check return code after flush
+ * @cqp_request: qhash cqp completion
+ */
+static void irdma_hw_flush_wqes_callback(struct irdma_cqp_request *cqp_request)
+{
+ struct irdma_qp_flush_info *hw_info;
+ struct irdma_sc_qp *qp;
+ struct irdma_qp *iwqp;
+ struct cqp_cmds_info *cqp_info;
+
+ cqp_info = &cqp_request->info;
+ hw_info = &cqp_info->in.u.qp_flush_wqes.info;
+ qp = cqp_info->in.u.qp_flush_wqes.qp;
+ iwqp = qp->qp_uk.back_qp;
+
+ if (cqp_request->compl_info.maj_err_code)
+ return;
+
+ if (hw_info->rq &&
+ (cqp_request->compl_info.min_err_code == IRDMA_CQP_COMPL_SQ_WQE_FLUSHED ||
+ cqp_request->compl_info.min_err_code == 0)) {
+ /* RQ WQE flush was requested but did not happen */
+ qp->qp_uk.rq_flush_complete = true;
+ }
+ if (hw_info->sq &&
+ (cqp_request->compl_info.min_err_code == IRDMA_CQP_COMPL_RQ_WQE_FLUSHED ||
+ cqp_request->compl_info.min_err_code == 0)) {
+ if (IRDMA_RING_MORE_WORK(qp->qp_uk.sq_ring)) {
+ ibdev_err(&iwqp->iwdev->ibdev, "Flush QP[%d] failed, SQ has more work",
+ qp->qp_uk.qp_id);
+ irdma_ib_qp_event(iwqp, IRDMA_QP_EVENT_CATASTROPHIC);
+ }
+ qp->qp_uk.sq_flush_complete = true;
+ }
+}
+
+/**
+ * irdma_hw_flush_wqes - flush qp's wqe
+ * @rf: RDMA PCI function
+ * @qp: hardware control qp
+ * @info: info for flush
+ * @wait: flag wait for completion
+ */
+enum irdma_status_code irdma_hw_flush_wqes(struct irdma_pci_f *rf,
+ struct irdma_sc_qp *qp,
+ struct irdma_qp_flush_info *info,
+ bool wait)
+{
+ enum irdma_status_code status;
+ struct irdma_qp_flush_info *hw_info;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_qp *iwqp = qp->qp_uk.back_qp;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, wait);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ if (!wait)
+ cqp_request->callback_fcn = irdma_hw_flush_wqes_callback;
+ hw_info = &cqp_request->info.in.u.qp_flush_wqes.info;
+ memcpy(hw_info, info, sizeof(*hw_info));
+ cqp_info->cqp_cmd = IRDMA_OP_QP_FLUSH_WQES;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.qp_flush_wqes.qp = qp;
+ cqp_info->in.u.qp_flush_wqes.scratch = (uintptr_t)cqp_request;
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ if (status) {
+ qp->qp_uk.sq_flush_complete = true;
+ qp->qp_uk.rq_flush_complete = true;
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+ return status;
+ }
+
+ if (!wait || cqp_request->compl_info.maj_err_code)
+ goto put_cqp;
+
+ if (info->rq) {
+ if (cqp_request->compl_info.min_err_code == IRDMA_CQP_COMPL_SQ_WQE_FLUSHED ||
+ cqp_request->compl_info.min_err_code == 0) {
+ /* RQ WQE flush was requested but did not happen */
+ qp->qp_uk.rq_flush_complete = true;
+ }
+ }
+ if (info->sq) {
+ if (cqp_request->compl_info.min_err_code == IRDMA_CQP_COMPL_RQ_WQE_FLUSHED ||
+ cqp_request->compl_info.min_err_code == 0) {
+ /*
+ * Handling case where WQE is posted to empty SQ when
+ * flush has not completed
+ */
+ if (IRDMA_RING_MORE_WORK(qp->qp_uk.sq_ring)) {
+ struct irdma_cqp_request *new_req;
+
+ if (!qp->qp_uk.sq_flush_complete)
+ goto put_cqp;
+ qp->qp_uk.sq_flush_complete = false;
+ qp->flush_sq = false;
+
+ info->rq = false;
+ info->sq = true;
+ new_req = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
+ if (!new_req) {
+ status = IRDMA_ERR_NO_MEMORY;
+ goto put_cqp;
+ }
+ cqp_info = &new_req->info;
+ hw_info = &new_req->info.in.u.qp_flush_wqes.info;
+ memcpy(hw_info, info, sizeof(*hw_info));
+ cqp_info->cqp_cmd = IRDMA_OP_QP_FLUSH_WQES;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.qp_flush_wqes.qp = qp;
+ cqp_info->in.u.qp_flush_wqes.scratch = (uintptr_t)new_req;
+
+ status = irdma_handle_cqp_op(rf, new_req);
+ if (new_req->compl_info.maj_err_code ||
+ new_req->compl_info.min_err_code != IRDMA_CQP_COMPL_SQ_WQE_FLUSHED ||
+ status) {
+ ibdev_err(&iwqp->iwdev->ibdev, "fatal QP event: SQ in error but not flushed, qp: %d",
+ iwqp->ibqp.qp_num);
+ qp->qp_uk.sq_flush_complete = false;
+ irdma_ib_qp_event(iwqp, IRDMA_QP_EVENT_CATASTROPHIC);
+ }
+ irdma_put_cqp_request(&rf->cqp, new_req);
+ } else {
+ /* SQ WQE flush was requested but did not happen */
+ qp->qp_uk.sq_flush_complete = true;
+ }
+ } else {
+ if (!IRDMA_RING_MORE_WORK(qp->qp_uk.sq_ring))
+ qp->qp_uk.sq_flush_complete = true;
+ }
+ }
+
+ ibdev_dbg(&rf->iwdev->ibdev,
+ "VERBS: qp_id=%d qp_type=%d qpstate=%d ibqpstate=%d last_aeq=%d hw_iw_state=%d maj_err_code=%d min_err_code=%d\n",
+ iwqp->ibqp.qp_num, rf->protocol_used, iwqp->iwarp_state,
+ iwqp->ibqp_state, iwqp->last_aeq, iwqp->hw_iwarp_state,
+ cqp_request->compl_info.maj_err_code,
+ cqp_request->compl_info.min_err_code);
+put_cqp:
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_gen_ae - generate AE
+ * @rf: RDMA PCI function
+ * @qp: qp associated with AE
+ * @info: info for ae
+ * @wait: wait for completion
+ */
+void irdma_gen_ae(struct irdma_pci_f *rf, struct irdma_sc_qp *qp,
+ struct irdma_gen_ae_info *info, bool wait)
+{
+ struct irdma_gen_ae_info *ae_info;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, wait);
+ if (!cqp_request)
+ return;
+
+ cqp_info = &cqp_request->info;
+ ae_info = &cqp_request->info.in.u.gen_ae.info;
+ memcpy(ae_info, info, sizeof(*ae_info));
+ cqp_info->cqp_cmd = IRDMA_OP_GEN_AE;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.gen_ae.qp = qp;
+ cqp_info->in.u.gen_ae.scratch = (uintptr_t)cqp_request;
+
+ irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+}
+
+void irdma_flush_wqes(struct irdma_qp *iwqp, u32 flush_mask)
+{
+ struct irdma_qp_flush_info info = {};
+ struct irdma_pci_f *rf = iwqp->iwdev->rf;
+ u8 flush_code = iwqp->sc_qp.flush_code;
+
+ if (!(flush_mask & IRDMA_FLUSH_SQ) && !(flush_mask & IRDMA_FLUSH_RQ))
+ return;
+
+ /* Set flush info fields*/
+ info.sq = flush_mask & IRDMA_FLUSH_SQ;
+ info.rq = flush_mask & IRDMA_FLUSH_RQ;
+
+ if (flush_mask & IRDMA_REFLUSH) {
+ if (info.sq)
+ iwqp->sc_qp.flush_sq = false;
+ if (info.rq)
+ iwqp->sc_qp.flush_rq = false;
+ }
+
+ /* Generate userflush errors in CQE */
+ info.sq_major_code = IRDMA_FLUSH_MAJOR_ERR;
+ info.sq_minor_code = FLUSH_GENERAL_ERR;
+ info.rq_major_code = IRDMA_FLUSH_MAJOR_ERR;
+ info.rq_minor_code = FLUSH_GENERAL_ERR;
+ info.userflushcode = true;
+ if (flush_code) {
+ if (info.sq && iwqp->sc_qp.sq_flush_code)
+ info.sq_minor_code = flush_code;
+ if (info.rq && iwqp->sc_qp.rq_flush_code)
+ info.rq_minor_code = flush_code;
+ }
+
+ /* Issue flush */
+ (void)irdma_hw_flush_wqes(rf, &iwqp->sc_qp, &info,
+ flush_mask & IRDMA_FLUSH_WAIT);
+ iwqp->flush_issued = true;
+}
diff --git a/drivers/infiniband/hw/irdma/i40iw_hw.c b/drivers/infiniband/hw/irdma/i40iw_hw.c
new file mode 100644
index 000000000000..64148ad8a604
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/i40iw_hw.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#include "osdep.h"
+#include "type.h"
+#include "i40iw_hw.h"
+#include "status.h"
+#include "protos.h"
+
+static u32 i40iw_regs[IRDMA_MAX_REGS] = {
+ I40E_PFPE_CQPTAIL,
+ I40E_PFPE_CQPDB,
+ I40E_PFPE_CCQPSTATUS,
+ I40E_PFPE_CCQPHIGH,
+ I40E_PFPE_CCQPLOW,
+ I40E_PFPE_CQARM,
+ I40E_PFPE_CQACK,
+ I40E_PFPE_AEQALLOC,
+ I40E_PFPE_CQPERRCODES,
+ I40E_PFPE_WQEALLOC,
+ I40E_PFINT_DYN_CTLN(0),
+ I40IW_DB_ADDR_OFFSET,
+
+ I40E_GLPCI_LBARCTRL,
+ I40E_GLPE_CPUSTATUS0,
+ I40E_GLPE_CPUSTATUS1,
+ I40E_GLPE_CPUSTATUS2,
+ I40E_PFINT_AEQCTL,
+ I40E_PFINT_CEQCTL(0),
+ I40E_VSIQF_CTL(0),
+ I40E_PFHMC_PDINV,
+ I40E_GLHMC_VFPDINV(0),
+ I40E_GLPE_CRITERR,
+ 0xffffffff /* PFINT_RATEN not used in FPK */
+};
+
+static u32 i40iw_stat_offsets_32[IRDMA_HW_STAT_INDEX_MAX_32] = {
+ I40E_GLPES_PFIP4RXDISCARD(0),
+ I40E_GLPES_PFIP4RXTRUNC(0),
+ I40E_GLPES_PFIP4TXNOROUTE(0),
+ I40E_GLPES_PFIP6RXDISCARD(0),
+ I40E_GLPES_PFIP6RXTRUNC(0),
+ I40E_GLPES_PFIP6TXNOROUTE(0),
+ I40E_GLPES_PFTCPRTXSEG(0),
+ I40E_GLPES_PFTCPRXOPTERR(0),
+ I40E_GLPES_PFTCPRXPROTOERR(0),
+ I40E_GLPES_PFRXVLANERR(0)
+};
+
+static u32 i40iw_stat_offsets_64[IRDMA_HW_STAT_INDEX_MAX_64] = {
+ I40E_GLPES_PFIP4RXOCTSLO(0),
+ I40E_GLPES_PFIP4RXPKTSLO(0),
+ I40E_GLPES_PFIP4RXFRAGSLO(0),
+ I40E_GLPES_PFIP4RXMCPKTSLO(0),
+ I40E_GLPES_PFIP4TXOCTSLO(0),
+ I40E_GLPES_PFIP4TXPKTSLO(0),
+ I40E_GLPES_PFIP4TXFRAGSLO(0),
+ I40E_GLPES_PFIP4TXMCPKTSLO(0),
+ I40E_GLPES_PFIP6RXOCTSLO(0),
+ I40E_GLPES_PFIP6RXPKTSLO(0),
+ I40E_GLPES_PFIP6RXFRAGSLO(0),
+ I40E_GLPES_PFIP6RXMCPKTSLO(0),
+ I40E_GLPES_PFIP6TXOCTSLO(0),
+ I40E_GLPES_PFIP6TXPKTSLO(0),
+ I40E_GLPES_PFIP6TXFRAGSLO(0),
+ I40E_GLPES_PFIP6TXMCPKTSLO(0),
+ I40E_GLPES_PFTCPRXSEGSLO(0),
+ I40E_GLPES_PFTCPTXSEGLO(0),
+ I40E_GLPES_PFRDMARXRDSLO(0),
+ I40E_GLPES_PFRDMARXSNDSLO(0),
+ I40E_GLPES_PFRDMARXWRSLO(0),
+ I40E_GLPES_PFRDMATXRDSLO(0),
+ I40E_GLPES_PFRDMATXSNDSLO(0),
+ I40E_GLPES_PFRDMATXWRSLO(0),
+ I40E_GLPES_PFRDMAVBNDLO(0),
+ I40E_GLPES_PFRDMAVINVLO(0),
+ I40E_GLPES_PFIP4RXMCOCTSLO(0),
+ I40E_GLPES_PFIP4TXMCOCTSLO(0),
+ I40E_GLPES_PFIP6RXMCOCTSLO(0),
+ I40E_GLPES_PFIP6TXMCOCTSLO(0),
+ I40E_GLPES_PFUDPRXPKTSLO(0),
+ I40E_GLPES_PFUDPTXPKTSLO(0)
+};
+
+static u64 i40iw_masks[IRDMA_MAX_MASKS] = {
+ I40E_PFPE_CCQPSTATUS_CCQP_DONE,
+ I40E_PFPE_CCQPSTATUS_CCQP_ERR,
+ I40E_CQPSQ_STAG_PDID,
+ I40E_CQPSQ_CQ_CEQID,
+ I40E_CQPSQ_CQ_CQID,
+ I40E_COMMIT_FPM_CQCNT,
+};
+
+static u64 i40iw_shifts[IRDMA_MAX_SHIFTS] = {
+ I40E_PFPE_CCQPSTATUS_CCQP_DONE_S,
+ I40E_PFPE_CCQPSTATUS_CCQP_ERR_S,
+ I40E_CQPSQ_STAG_PDID_S,
+ I40E_CQPSQ_CQ_CEQID_S,
+ I40E_CQPSQ_CQ_CQID_S,
+ I40E_COMMIT_FPM_CQCNT_S,
+};
+
+/**
+ * i40iw_config_ceq- Configure CEQ interrupt
+ * @dev: pointer to the device structure
+ * @ceq_id: Completion Event Queue ID
+ * @idx: vector index
+ * @enable: Enable CEQ interrupt when true
+ */
+static void i40iw_config_ceq(struct irdma_sc_dev *dev, u32 ceq_id, u32 idx,
+ bool enable)
+{
+ u32 reg_val;
+
+ reg_val = FIELD_PREP(I40E_PFINT_LNKLSTN_FIRSTQ_INDX, ceq_id) |
+ FIELD_PREP(I40E_PFINT_LNKLSTN_FIRSTQ_TYPE, QUEUE_TYPE_CEQ);
+ wr32(dev->hw, I40E_PFINT_LNKLSTN(idx - 1), reg_val);
+
+ reg_val = FIELD_PREP(I40E_PFINT_DYN_CTLN_ITR_INDX, 0x3) |
+ FIELD_PREP(I40E_PFINT_DYN_CTLN_INTENA, 0x1);
+ wr32(dev->hw, I40E_PFINT_DYN_CTLN(idx - 1), reg_val);
+
+ reg_val = FIELD_PREP(IRDMA_GLINT_CEQCTL_CAUSE_ENA, enable) |
+ FIELD_PREP(IRDMA_GLINT_CEQCTL_MSIX_INDX, idx) |
+ FIELD_PREP(I40E_PFINT_CEQCTL_NEXTQ_INDX, NULL_QUEUE_INDEX) |
+ FIELD_PREP(IRDMA_GLINT_CEQCTL_ITR_INDX, 0x3);
+
+ wr32(dev->hw, i40iw_regs[IRDMA_GLINT_CEQCTL] + 4 * ceq_id, reg_val);
+}
+
+/**
+ * i40iw_ena_irq - Enable interrupt
+ * @dev: pointer to the device structure
+ * @idx: vector index
+ */
+static void i40iw_ena_irq(struct irdma_sc_dev *dev, u32 idx)
+{
+ u32 val;
+
+ val = FIELD_PREP(IRDMA_GLINT_DYN_CTL_INTENA, 0x1) |
+ FIELD_PREP(IRDMA_GLINT_DYN_CTL_CLEARPBA, 0x1) |
+ FIELD_PREP(IRDMA_GLINT_DYN_CTL_ITR_INDX, 0x3);
+ wr32(dev->hw, i40iw_regs[IRDMA_GLINT_DYN_CTL] + 4 * (idx - 1), val);
+}
+
+/**
+ * i40iw_disable_irq - Disable interrupt
+ * @dev: pointer to the device structure
+ * @idx: vector index
+ */
+static void i40iw_disable_irq(struct irdma_sc_dev *dev, u32 idx)
+{
+ wr32(dev->hw, i40iw_regs[IRDMA_GLINT_DYN_CTL] + 4 * (idx - 1), 0);
+}
+
+static const struct irdma_irq_ops i40iw_irq_ops = {
+ .irdma_cfg_aeq = irdma_cfg_aeq,
+ .irdma_cfg_ceq = i40iw_config_ceq,
+ .irdma_dis_irq = i40iw_disable_irq,
+ .irdma_en_irq = i40iw_ena_irq,
+};
+
+void i40iw_init_hw(struct irdma_sc_dev *dev)
+{
+ int i;
+ u8 __iomem *hw_addr;
+
+ for (i = 0; i < IRDMA_MAX_REGS; ++i) {
+ hw_addr = dev->hw->hw_addr;
+
+ if (i == IRDMA_DB_ADDR_OFFSET)
+ hw_addr = NULL;
+
+ dev->hw_regs[i] = (u32 __iomem *)(i40iw_regs[i] + hw_addr);
+ }
+
+ for (i = 0; i < IRDMA_HW_STAT_INDEX_MAX_32; ++i)
+ dev->hw_stats_regs_32[i] = i40iw_stat_offsets_32[i];
+
+ for (i = 0; i < IRDMA_HW_STAT_INDEX_MAX_64; ++i)
+ dev->hw_stats_regs_64[i] = i40iw_stat_offsets_64[i];
+
+ dev->hw_attrs.first_hw_vf_fpm_id = I40IW_FIRST_VF_FPM_ID;
+ dev->hw_attrs.max_hw_vf_fpm_id = IRDMA_MAX_VF_FPM_ID;
+
+ for (i = 0; i < IRDMA_MAX_SHIFTS; ++i)
+ dev->hw_shifts[i] = i40iw_shifts[i];
+
+ for (i = 0; i < IRDMA_MAX_MASKS; ++i)
+ dev->hw_masks[i] = i40iw_masks[i];
+
+ dev->wqe_alloc_db = dev->hw_regs[IRDMA_WQEALLOC];
+ dev->cq_arm_db = dev->hw_regs[IRDMA_CQARM];
+ dev->aeq_alloc_db = dev->hw_regs[IRDMA_AEQALLOC];
+ dev->cqp_db = dev->hw_regs[IRDMA_CQPDB];
+ dev->cq_ack_db = dev->hw_regs[IRDMA_CQACK];
+ dev->ceq_itr_mask_db = NULL;
+ dev->aeq_itr_mask_db = NULL;
+ dev->irq_ops = &i40iw_irq_ops;
+
+ /* Setup the hardware limits, hmc may limit further */
+ dev->hw_attrs.uk_attrs.max_hw_wq_frags = I40IW_MAX_WQ_FRAGMENT_COUNT;
+ dev->hw_attrs.uk_attrs.max_hw_read_sges = I40IW_MAX_SGE_RD;
+ dev->hw_attrs.max_hw_device_pages = I40IW_MAX_PUSH_PAGE_COUNT;
+ dev->hw_attrs.uk_attrs.max_hw_inline = I40IW_MAX_INLINE_DATA_SIZE;
+ dev->hw_attrs.max_hw_ird = I40IW_MAX_IRD_SIZE;
+ dev->hw_attrs.max_hw_ord = I40IW_MAX_ORD_SIZE;
+ dev->hw_attrs.max_hw_wqes = I40IW_MAX_WQ_ENTRIES;
+ dev->hw_attrs.uk_attrs.max_hw_rq_quanta = I40IW_QP_SW_MAX_RQ_QUANTA;
+ dev->hw_attrs.uk_attrs.max_hw_wq_quanta = I40IW_QP_SW_MAX_WQ_QUANTA;
+ dev->hw_attrs.uk_attrs.max_hw_sq_chunk = I40IW_MAX_QUANTA_PER_WR;
+ dev->hw_attrs.max_hw_pds = I40IW_MAX_PDS;
+ dev->hw_attrs.max_stat_inst = I40IW_MAX_STATS_COUNT;
+ dev->hw_attrs.max_hw_outbound_msg_size = I40IW_MAX_OUTBOUND_MSG_SIZE;
+ dev->hw_attrs.max_hw_inbound_msg_size = I40IW_MAX_INBOUND_MSG_SIZE;
+ dev->hw_attrs.max_qp_wr = I40IW_MAX_QP_WRS;
+}
diff --git a/drivers/infiniband/hw/irdma/i40iw_hw.h b/drivers/infiniband/hw/irdma/i40iw_hw.h
new file mode 100644
index 000000000000..1c438b3593ea
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/i40iw_hw.h
@@ -0,0 +1,160 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#ifndef I40IW_HW_H
+#define I40IW_HW_H
+#define I40E_VFPE_CQPTAIL1 0x0000A000 /* Reset: VFR */
+#define I40E_VFPE_CQPDB1 0x0000BC00 /* Reset: VFR */
+#define I40E_VFPE_CCQPSTATUS1 0x0000B800 /* Reset: VFR */
+#define I40E_VFPE_CCQPHIGH1 0x00009800 /* Reset: VFR */
+#define I40E_VFPE_CCQPLOW1 0x0000AC00 /* Reset: VFR */
+#define I40E_VFPE_CQARM1 0x0000B400 /* Reset: VFR */
+#define I40E_VFPE_CQACK1 0x0000B000 /* Reset: VFR */
+#define I40E_VFPE_AEQALLOC1 0x0000A400 /* Reset: VFR */
+#define I40E_VFPE_CQPERRCODES1 0x00009C00 /* Reset: VFR */
+#define I40E_VFPE_WQEALLOC1 0x0000C000 /* Reset: VFR */
+#define I40E_VFINT_DYN_CTLN(_INTVF) (0x00024800 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: VFR */
+
+#define I40E_PFPE_CQPTAIL 0x00008080 /* Reset: PFR */
+
+#define I40E_PFPE_CQPDB 0x00008000 /* Reset: PFR */
+#define I40E_PFPE_CCQPSTATUS 0x00008100 /* Reset: PFR */
+#define I40E_PFPE_CCQPHIGH 0x00008200 /* Reset: PFR */
+#define I40E_PFPE_CCQPLOW 0x00008180 /* Reset: PFR */
+#define I40E_PFPE_CQARM 0x00131080 /* Reset: PFR */
+#define I40E_PFPE_CQACK 0x00131100 /* Reset: PFR */
+#define I40E_PFPE_AEQALLOC 0x00131180 /* Reset: PFR */
+#define I40E_PFPE_CQPERRCODES 0x00008880 /* Reset: PFR */
+#define I40E_PFPE_WQEALLOC 0x00138C00 /* Reset: PFR */
+#define I40E_GLPCI_LBARCTRL 0x000BE484 /* Reset: POR */
+#define I40E_GLPE_CPUSTATUS0 0x0000D040 /* Reset: PE_CORER */
+#define I40E_GLPE_CPUSTATUS1 0x0000D044 /* Reset: PE_CORER */
+#define I40E_GLPE_CPUSTATUS2 0x0000D048 /* Reset: PE_CORER */
+#define I40E_GLPE_CRITERR 0x000B4000 /* Reset: PE_CORER */
+#define I40E_PFHMC_PDINV 0x000C0300 /* Reset: PFR */
+#define I40E_GLHMC_VFPDINV(_i) (0x000C8300 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */
+#define I40E_PFINT_DYN_CTLN(_INTPF) (0x00034800 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: PFR */
+#define I40E_PFINT_AEQCTL 0x00038700 /* Reset: CORER */
+
+#define I40E_GLPES_PFIP4RXDISCARD(_i) (0x00010600 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP4RXTRUNC(_i) (0x00010700 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP4TXNOROUTE(_i) (0x00012E00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP6RXDISCARD(_i) (0x00011200 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP6RXTRUNC(_i) (0x00011300 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
+
+#define I40E_GLPES_PFRDMAVBNDLO(_i) (0x00014800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP4TXMCOCTSLO(_i) (0x00012000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP6RXMCOCTSLO(_i) (0x00011600 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP6TXMCOCTSLO(_i) (0x00012A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFUDPRXPKTSLO(_i) (0x00013800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFUDPTXPKTSLO(_i) (0x00013A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+
+#define I40E_GLPES_PFIP6TXNOROUTE(_i) (0x00012F00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFTCPRTXSEG(_i) (0x00013600 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFTCPRXOPTERR(_i) (0x00013200 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFTCPRXPROTOERR(_i) (0x00013300 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFRXVLANERR(_i) (0x00010000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP4RXOCTSLO(_i) (0x00010200 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP4RXPKTSLO(_i) (0x00010400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP4RXFRAGSLO(_i) (0x00010800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP4RXMCPKTSLO(_i) (0x00010C00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP4TXOCTSLO(_i) (0x00011A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP4TXPKTSLO(_i) (0x00011C00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP4TXFRAGSLO(_i) (0x00011E00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP4TXMCPKTSLO(_i) (0x00012200 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP6RXOCTSLO(_i) (0x00010E00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP6RXPKTSLO(_i) (0x00011000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP6RXFRAGSLO(_i) (0x00011400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP6TXOCTSLO(_i) (0x00012400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP6TXPKTSLO(_i) (0x00012600 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP6TXFRAGSLO(_i) (0x00012800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP6TXMCPKTSLO(_i) (0x00012C00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFTCPTXSEGLO(_i) (0x00013400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFRDMARXRDSLO(_i) (0x00013E00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFRDMARXSNDSLO(_i) (0x00014000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFRDMARXWRSLO(_i) (0x00013C00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFRDMATXRDSLO(_i) (0x00014400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFRDMATXSNDSLO(_i) (0x00014600 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFRDMATXWRSLO(_i) (0x00014200 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP4RXMCOCTSLO(_i) (0x00010A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFIP6RXMCPKTSLO(_i) (0x00011800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFTCPRXSEGSLO(_i) (0x00013000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+#define I40E_GLPES_PFRDMAVINVLO(_i) (0x00014A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */
+
+#define I40IW_DB_ADDR_OFFSET (4 * 1024 * 1024 - 64 * 1024)
+
+#define I40IW_VF_DB_ADDR_OFFSET (64 * 1024)
+
+#define I40E_PFINT_LNKLSTN(_INTPF) (0x00035000 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: PFR */
+#define I40E_PFINT_LNKLSTN_MAX_INDEX 511
+#define I40E_PFINT_LNKLSTN_FIRSTQ_INDX GENMASK(10, 0)
+#define I40E_PFINT_LNKLSTN_FIRSTQ_TYPE GENMASK(12, 11)
+
+#define I40E_PFINT_CEQCTL(_INTPF) (0x00036800 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: CORER */
+#define I40E_PFINT_CEQCTL_MAX_INDEX 511
+
+/* shifts/masks for FLD_[LS/RS]_64 macros used in device table */
+#define I40E_PFINT_CEQCTL_MSIX_INDX_S 0
+#define I40E_PFINT_CEQCTL_MSIX_INDX GENMASK(7, 0)
+#define I40E_PFINT_CEQCTL_ITR_INDX_S 11
+#define I40E_PFINT_CEQCTL_ITR_INDX GENMASK(12, 11)
+#define I40E_PFINT_CEQCTL_MSIX0_INDX_S 13
+#define I40E_PFINT_CEQCTL_MSIX0_INDX GENMASK(15, 13)
+#define I40E_PFINT_CEQCTL_NEXTQ_INDX_S 16
+#define I40E_PFINT_CEQCTL_NEXTQ_INDX GENMASK(26, 16)
+#define I40E_PFINT_CEQCTL_NEXTQ_TYPE_S 27
+#define I40E_PFINT_CEQCTL_NEXTQ_TYPE GENMASK(28, 27)
+#define I40E_PFINT_CEQCTL_CAUSE_ENA_S 30
+#define I40E_PFINT_CEQCTL_CAUSE_ENA BIT(30)
+#define I40E_PFINT_CEQCTL_INTEVENT_S 31
+#define I40E_PFINT_CEQCTL_INTEVENT BIT(31)
+#define I40E_CQPSQ_STAG_PDID_S 48
+#define I40E_CQPSQ_STAG_PDID GENMASK_ULL(62, 48)
+#define I40E_PFPE_CCQPSTATUS_CCQP_DONE_S 0
+#define I40E_PFPE_CCQPSTATUS_CCQP_DONE BIT_ULL(0)
+#define I40E_PFPE_CCQPSTATUS_CCQP_ERR_S 31
+#define I40E_PFPE_CCQPSTATUS_CCQP_ERR BIT_ULL(31)
+#define I40E_PFINT_DYN_CTLN_ITR_INDX_S 3
+#define I40E_PFINT_DYN_CTLN_ITR_INDX GENMASK(4, 3)
+#define I40E_PFINT_DYN_CTLN_INTENA_S 0
+#define I40E_PFINT_DYN_CTLN_INTENA BIT(0)
+#define I40E_CQPSQ_CQ_CEQID_S 24
+#define I40E_CQPSQ_CQ_CEQID GENMASK(30, 24)
+#define I40E_CQPSQ_CQ_CQID_S 0
+#define I40E_CQPSQ_CQ_CQID GENMASK_ULL(15, 0)
+#define I40E_COMMIT_FPM_CQCNT_S 0
+#define I40E_COMMIT_FPM_CQCNT GENMASK_ULL(17, 0)
+
+#define I40E_VSIQF_CTL(_VSI) (0x0020D800 + ((_VSI) * 4))
+
+enum i40iw_device_caps_const {
+ I40IW_MAX_WQ_FRAGMENT_COUNT = 3,
+ I40IW_MAX_SGE_RD = 1,
+ I40IW_MAX_PUSH_PAGE_COUNT = 0,
+ I40IW_MAX_INLINE_DATA_SIZE = 48,
+ I40IW_MAX_IRD_SIZE = 63,
+ I40IW_MAX_ORD_SIZE = 127,
+ I40IW_MAX_WQ_ENTRIES = 2048,
+ I40IW_MAX_WQE_SIZE_RQ = 128,
+ I40IW_MAX_PDS = 32768,
+ I40IW_MAX_STATS_COUNT = 16,
+ I40IW_MAX_CQ_SIZE = 1048575,
+ I40IW_MAX_OUTBOUND_MSG_SIZE = 2147483647,
+ I40IW_MAX_INBOUND_MSG_SIZE = 2147483647,
+};
+
+#define I40IW_QP_WQE_MIN_SIZE 32
+#define I40IW_QP_WQE_MAX_SIZE 128
+#define I40IW_QP_SW_MIN_WQSIZE 4
+#define I40IW_MAX_RQ_WQE_SHIFT 2
+#define I40IW_MAX_QUANTA_PER_WR 2
+
+#define I40IW_QP_SW_MAX_SQ_QUANTA 2048
+#define I40IW_QP_SW_MAX_RQ_QUANTA 16384
+#define I40IW_QP_SW_MAX_WQ_QUANTA 2048
+#define I40IW_MAX_QP_WRS ((I40IW_QP_SW_MAX_SQ_QUANTA - IRDMA_SQ_RSVD) / I40IW_MAX_QUANTA_PER_WR)
+#define I40IW_FIRST_VF_FPM_ID 16
+#define QUEUE_TYPE_CEQ 2
+#define NULL_QUEUE_INDEX 0x7FF
+
+void i40iw_init_hw(struct irdma_sc_dev *dev);
+#endif /* I40IW_HW_H */
diff --git a/drivers/infiniband/hw/irdma/i40iw_if.c b/drivers/infiniband/hw/irdma/i40iw_if.c
new file mode 100644
index 000000000000..bddf88194d09
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/i40iw_if.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#include "main.h"
+#include "i40iw_hw.h"
+#include <linux/net/intel/i40e_client.h>
+
+static struct i40e_client i40iw_client;
+
+/**
+ * i40iw_l2param_change - handle mss change
+ * @cdev_info: parent lan device information structure with data/ops
+ * @client: client for parameter change
+ * @params: new parameters from L2
+ */
+static void i40iw_l2param_change(struct i40e_info *cdev_info,
+ struct i40e_client *client,
+ struct i40e_params *params)
+{
+ struct irdma_l2params l2params = {};
+ struct irdma_device *iwdev;
+ struct ib_device *ibdev;
+
+ ibdev = ib_device_get_by_netdev(cdev_info->netdev, RDMA_DRIVER_IRDMA);
+ if (!ibdev)
+ return;
+
+ iwdev = to_iwdev(ibdev);
+
+ if (iwdev->vsi.mtu != params->mtu) {
+ l2params.mtu_changed = true;
+ l2params.mtu = params->mtu;
+ }
+ irdma_change_l2params(&iwdev->vsi, &l2params);
+ ib_device_put(ibdev);
+}
+
+/**
+ * i40iw_close - client interface operation close for iwarp/uda device
+ * @cdev_info: parent lan device information structure with data/ops
+ * @client: client to close
+ * @reset: flag to indicate close on reset
+ *
+ * Called by the lan driver during the processing of client unregister
+ * Destroy and clean up the driver resources
+ */
+static void i40iw_close(struct i40e_info *cdev_info, struct i40e_client *client,
+ bool reset)
+{
+ struct irdma_device *iwdev;
+ struct ib_device *ibdev;
+
+ ibdev = ib_device_get_by_netdev(cdev_info->netdev, RDMA_DRIVER_IRDMA);
+ if (WARN_ON(!ibdev))
+ return;
+
+ iwdev = to_iwdev(ibdev);
+ if (reset)
+ iwdev->reset = true;
+
+ iwdev->iw_status = 0;
+ irdma_port_ibevent(iwdev);
+ ib_unregister_device_and_put(ibdev);
+ pr_debug("INIT: Gen1 PF[%d] close complete\n", PCI_FUNC(cdev_info->pcidev->devfn));
+}
+
+static void i40iw_request_reset(struct irdma_pci_f *rf)
+{
+ struct i40e_info *cdev_info = rf->cdev;
+
+ cdev_info->ops->request_reset(cdev_info, &i40iw_client, 1);
+}
+
+static void i40iw_fill_device_info(struct irdma_device *iwdev, struct i40e_info *cdev_info)
+{
+ struct irdma_pci_f *rf = iwdev->rf;
+
+ rf->rdma_ver = IRDMA_GEN_1;
+ rf->gen_ops.request_reset = i40iw_request_reset;
+ rf->pcidev = cdev_info->pcidev;
+ rf->hw.hw_addr = cdev_info->hw_addr;
+ rf->cdev = cdev_info;
+ rf->msix_count = cdev_info->msix_count;
+ rf->msix_entries = cdev_info->msix_entries;
+ rf->limits_sel = 5;
+ rf->protocol_used = IRDMA_IWARP_PROTOCOL_ONLY;
+ rf->iwdev = iwdev;
+
+ iwdev->init_state = INITIAL_STATE;
+ iwdev->rcv_wnd = IRDMA_CM_DEFAULT_RCV_WND_SCALED;
+ iwdev->rcv_wscale = IRDMA_CM_DEFAULT_RCV_WND_SCALE;
+ iwdev->netdev = cdev_info->netdev;
+ iwdev->vsi_num = 0;
+}
+
+/**
+ * i40iw_open - client interface operation open for iwarp/uda device
+ * @cdev_info: parent lan device information structure with data/ops
+ * @client: iwarp client information, provided during registration
+ *
+ * Called by the lan driver during the processing of client register
+ * Create device resources, set up queues, pble and hmc objects and
+ * register the device with the ib verbs interface
+ * Return 0 if successful, otherwise return error
+ */
+static int i40iw_open(struct i40e_info *cdev_info, struct i40e_client *client)
+{
+ struct irdma_l2params l2params = {};
+ struct irdma_device *iwdev;
+ struct irdma_pci_f *rf;
+ int err = -EIO;
+ int i;
+ u16 qset;
+ u16 last_qset = IRDMA_NO_QSET;
+
+ iwdev = ib_alloc_device(irdma_device, ibdev);
+ if (!iwdev)
+ return -ENOMEM;
+
+ iwdev->rf = kzalloc(sizeof(*rf), GFP_KERNEL);
+ if (!iwdev->rf) {
+ ib_dealloc_device(&iwdev->ibdev);
+ return -ENOMEM;
+ }
+
+ i40iw_fill_device_info(iwdev, cdev_info);
+ rf = iwdev->rf;
+
+ if (irdma_ctrl_init_hw(rf)) {
+ err = -EIO;
+ goto err_ctrl_init;
+ }
+
+ l2params.mtu = (cdev_info->params.mtu) ? cdev_info->params.mtu : IRDMA_DEFAULT_MTU;
+ for (i = 0; i < I40E_CLIENT_MAX_USER_PRIORITY; i++) {
+ qset = cdev_info->params.qos.prio_qos[i].qs_handle;
+ l2params.up2tc[i] = cdev_info->params.qos.prio_qos[i].tc;
+ l2params.qs_handle_list[i] = qset;
+ if (last_qset == IRDMA_NO_QSET)
+ last_qset = qset;
+ else if ((qset != last_qset) && (qset != IRDMA_NO_QSET))
+ iwdev->dcb = true;
+ }
+
+ if (irdma_rt_init_hw(iwdev, &l2params)) {
+ err = -EIO;
+ goto err_rt_init;
+ }
+
+ err = irdma_ib_register_device(iwdev);
+ if (err)
+ goto err_ibreg;
+
+ ibdev_dbg(&iwdev->ibdev, "INIT: Gen1 PF[%d] open success\n",
+ PCI_FUNC(rf->pcidev->devfn));
+
+ return 0;
+
+err_ibreg:
+ irdma_rt_deinit_hw(iwdev);
+err_rt_init:
+ irdma_ctrl_deinit_hw(rf);
+err_ctrl_init:
+ kfree(iwdev->rf);
+ ib_dealloc_device(&iwdev->ibdev);
+
+ return err;
+}
+
+/* client interface functions */
+static const struct i40e_client_ops i40e_ops = {
+ .open = i40iw_open,
+ .close = i40iw_close,
+ .l2_param_change = i40iw_l2param_change
+};
+
+static struct i40e_client i40iw_client = {
+ .ops = &i40e_ops,
+ .type = I40E_CLIENT_IWARP,
+};
+
+static int i40iw_probe(struct auxiliary_device *aux_dev, const struct auxiliary_device_id *id)
+{
+ struct i40e_auxiliary_device *i40e_adev = container_of(aux_dev,
+ struct i40e_auxiliary_device,
+ aux_dev);
+ struct i40e_info *cdev_info = i40e_adev->ldev;
+
+ strncpy(i40iw_client.name, "irdma", I40E_CLIENT_STR_LENGTH);
+ i40e_client_device_register(cdev_info, &i40iw_client);
+
+ return 0;
+}
+
+static void i40iw_remove(struct auxiliary_device *aux_dev)
+{
+ struct i40e_auxiliary_device *i40e_adev = container_of(aux_dev,
+ struct i40e_auxiliary_device,
+ aux_dev);
+ struct i40e_info *cdev_info = i40e_adev->ldev;
+
+ return i40e_client_device_unregister(cdev_info);
+}
+
+static const struct auxiliary_device_id i40iw_auxiliary_id_table[] = {
+ {.name = "i40e.iwarp", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(auxiliary, i40iw_auxiliary_id_table);
+
+struct auxiliary_driver i40iw_auxiliary_drv = {
+ .name = "gen_1",
+ .id_table = i40iw_auxiliary_id_table,
+ .probe = i40iw_probe,
+ .remove = i40iw_remove,
+};
diff --git a/drivers/infiniband/hw/irdma/icrdma_hw.c b/drivers/infiniband/hw/irdma/icrdma_hw.c
new file mode 100644
index 000000000000..cf53b17510cd
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/icrdma_hw.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2017 - 2021 Intel Corporation */
+#include "osdep.h"
+#include "type.h"
+#include "icrdma_hw.h"
+
+static u32 icrdma_regs[IRDMA_MAX_REGS] = {
+ PFPE_CQPTAIL,
+ PFPE_CQPDB,
+ PFPE_CCQPSTATUS,
+ PFPE_CCQPHIGH,
+ PFPE_CCQPLOW,
+ PFPE_CQARM,
+ PFPE_CQACK,
+ PFPE_AEQALLOC,
+ PFPE_CQPERRCODES,
+ PFPE_WQEALLOC,
+ GLINT_DYN_CTL(0),
+ ICRDMA_DB_ADDR_OFFSET,
+
+ GLPCI_LBARCTRL,
+ GLPE_CPUSTATUS0,
+ GLPE_CPUSTATUS1,
+ GLPE_CPUSTATUS2,
+ PFINT_AEQCTL,
+ GLINT_CEQCTL(0),
+ VSIQF_PE_CTL1(0),
+ PFHMC_PDINV,
+ GLHMC_VFPDINV(0),
+ GLPE_CRITERR,
+ GLINT_RATE(0),
+};
+
+static u64 icrdma_masks[IRDMA_MAX_MASKS] = {
+ ICRDMA_CCQPSTATUS_CCQP_DONE,
+ ICRDMA_CCQPSTATUS_CCQP_ERR,
+ ICRDMA_CQPSQ_STAG_PDID,
+ ICRDMA_CQPSQ_CQ_CEQID,
+ ICRDMA_CQPSQ_CQ_CQID,
+ ICRDMA_COMMIT_FPM_CQCNT,
+};
+
+static u64 icrdma_shifts[IRDMA_MAX_SHIFTS] = {
+ ICRDMA_CCQPSTATUS_CCQP_DONE_S,
+ ICRDMA_CCQPSTATUS_CCQP_ERR_S,
+ ICRDMA_CQPSQ_STAG_PDID_S,
+ ICRDMA_CQPSQ_CQ_CEQID_S,
+ ICRDMA_CQPSQ_CQ_CQID_S,
+ ICRDMA_COMMIT_FPM_CQCNT_S,
+};
+
+/**
+ * icrdma_ena_irq - Enable interrupt
+ * @dev: pointer to the device structure
+ * @idx: vector index
+ */
+static void icrdma_ena_irq(struct irdma_sc_dev *dev, u32 idx)
+{
+ u32 val;
+ u32 interval = 0;
+
+ if (dev->ceq_itr && dev->aeq->msix_idx != idx)
+ interval = dev->ceq_itr >> 1; /* 2 usec units */
+ val = FIELD_PREP(IRDMA_GLINT_DYN_CTL_ITR_INDX, 0) |
+ FIELD_PREP(IRDMA_GLINT_DYN_CTL_INTERVAL, interval) |
+ FIELD_PREP(IRDMA_GLINT_DYN_CTL_INTENA, 1) |
+ FIELD_PREP(IRDMA_GLINT_DYN_CTL_CLEARPBA, 1);
+
+ if (dev->hw_attrs.uk_attrs.hw_rev != IRDMA_GEN_1)
+ writel(val, dev->hw_regs[IRDMA_GLINT_DYN_CTL] + idx);
+ else
+ writel(val, dev->hw_regs[IRDMA_GLINT_DYN_CTL] + (idx - 1));
+}
+
+/**
+ * icrdma_disable_irq - Disable interrupt
+ * @dev: pointer to the device structure
+ * @idx: vector index
+ */
+static void icrdma_disable_irq(struct irdma_sc_dev *dev, u32 idx)
+{
+ if (dev->hw_attrs.uk_attrs.hw_rev != IRDMA_GEN_1)
+ writel(0, dev->hw_regs[IRDMA_GLINT_DYN_CTL] + idx);
+ else
+ writel(0, dev->hw_regs[IRDMA_GLINT_DYN_CTL] + (idx - 1));
+}
+
+/**
+ * icrdma_cfg_ceq- Configure CEQ interrupt
+ * @dev: pointer to the device structure
+ * @ceq_id: Completion Event Queue ID
+ * @idx: vector index
+ * @enable: True to enable, False disables
+ */
+static void icrdma_cfg_ceq(struct irdma_sc_dev *dev, u32 ceq_id, u32 idx,
+ bool enable)
+{
+ u32 reg_val;
+
+ reg_val = FIELD_PREP(IRDMA_GLINT_CEQCTL_CAUSE_ENA, enable) |
+ FIELD_PREP(IRDMA_GLINT_CEQCTL_MSIX_INDX, idx) |
+ FIELD_PREP(IRDMA_GLINT_CEQCTL_ITR_INDX, 3);
+
+ writel(reg_val, dev->hw_regs[IRDMA_GLINT_CEQCTL] + ceq_id);
+}
+
+static const struct irdma_irq_ops icrdma_irq_ops = {
+ .irdma_cfg_aeq = irdma_cfg_aeq,
+ .irdma_cfg_ceq = icrdma_cfg_ceq,
+ .irdma_dis_irq = icrdma_disable_irq,
+ .irdma_en_irq = icrdma_ena_irq,
+};
+
+void icrdma_init_hw(struct irdma_sc_dev *dev)
+{
+ int i;
+ u8 __iomem *hw_addr;
+
+ for (i = 0; i < IRDMA_MAX_REGS; ++i) {
+ hw_addr = dev->hw->hw_addr;
+
+ if (i == IRDMA_DB_ADDR_OFFSET)
+ hw_addr = NULL;
+
+ dev->hw_regs[i] = (u32 __iomem *)(hw_addr + icrdma_regs[i]);
+ }
+ dev->hw_attrs.max_hw_vf_fpm_id = IRDMA_MAX_VF_FPM_ID;
+ dev->hw_attrs.first_hw_vf_fpm_id = IRDMA_FIRST_VF_FPM_ID;
+
+ for (i = 0; i < IRDMA_MAX_SHIFTS; ++i)
+ dev->hw_shifts[i] = icrdma_shifts[i];
+
+ for (i = 0; i < IRDMA_MAX_MASKS; ++i)
+ dev->hw_masks[i] = icrdma_masks[i];
+
+ dev->wqe_alloc_db = dev->hw_regs[IRDMA_WQEALLOC];
+ dev->cq_arm_db = dev->hw_regs[IRDMA_CQARM];
+ dev->aeq_alloc_db = dev->hw_regs[IRDMA_AEQALLOC];
+ dev->cqp_db = dev->hw_regs[IRDMA_CQPDB];
+ dev->cq_ack_db = dev->hw_regs[IRDMA_CQACK];
+ dev->irq_ops = &icrdma_irq_ops;
+ dev->hw_attrs.max_hw_ird = ICRDMA_MAX_IRD_SIZE;
+ dev->hw_attrs.max_hw_ord = ICRDMA_MAX_ORD_SIZE;
+ dev->hw_attrs.max_stat_inst = ICRDMA_MAX_STATS_COUNT;
+
+ dev->hw_attrs.uk_attrs.max_hw_sq_chunk = IRDMA_MAX_QUANTA_PER_WR;
+ dev->hw_attrs.uk_attrs.feature_flags |= IRDMA_FEATURE_RTS_AE |
+ IRDMA_FEATURE_CQ_RESIZE;
+}
diff --git a/drivers/infiniband/hw/irdma/icrdma_hw.h b/drivers/infiniband/hw/irdma/icrdma_hw.h
new file mode 100644
index 000000000000..b65c463abf0b
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/icrdma_hw.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2017 - 2021 Intel Corporation */
+#ifndef ICRDMA_HW_H
+#define ICRDMA_HW_H
+
+#include "irdma.h"
+
+#define VFPE_CQPTAIL1 0x0000a000
+#define VFPE_CQPDB1 0x0000bc00
+#define VFPE_CCQPSTATUS1 0x0000b800
+#define VFPE_CCQPHIGH1 0x00009800
+#define VFPE_CCQPLOW1 0x0000ac00
+#define VFPE_CQARM1 0x0000b400
+#define VFPE_CQARM1 0x0000b400
+#define VFPE_CQACK1 0x0000b000
+#define VFPE_AEQALLOC1 0x0000a400
+#define VFPE_CQPERRCODES1 0x00009c00
+#define VFPE_WQEALLOC1 0x0000c000
+#define VFINT_DYN_CTLN(_i) (0x00003800 + ((_i) * 4)) /* _i=0...63 */
+
+#define PFPE_CQPTAIL 0x00500880
+#define PFPE_CQPDB 0x00500800
+#define PFPE_CCQPSTATUS 0x0050a000
+#define PFPE_CCQPHIGH 0x0050a100
+#define PFPE_CCQPLOW 0x0050a080
+#define PFPE_CQARM 0x00502c00
+#define PFPE_CQACK 0x00502c80
+#define PFPE_AEQALLOC 0x00502d00
+#define GLINT_DYN_CTL(_INT) (0x00160000 + ((_INT) * 4)) /* _i=0...2047 */
+#define GLPCI_LBARCTRL 0x0009de74
+#define GLPE_CPUSTATUS0 0x0050ba5c
+#define GLPE_CPUSTATUS1 0x0050ba60
+#define GLPE_CPUSTATUS2 0x0050ba64
+#define PFINT_AEQCTL 0x0016cb00
+#define PFPE_CQPERRCODES 0x0050a200
+#define PFPE_WQEALLOC 0x00504400
+#define GLINT_CEQCTL(_INT) (0x0015c000 + ((_INT) * 4)) /* _i=0...2047 */
+#define VSIQF_PE_CTL1(_VSI) (0x00414000 + ((_VSI) * 4)) /* _i=0...767 */
+#define PFHMC_PDINV 0x00520300
+#define GLHMC_VFPDINV(_i) (0x00528300 + ((_i) * 4)) /* _i=0...31 */
+#define GLPE_CRITERR 0x00534000
+#define GLINT_RATE(_INT) (0x0015A000 + ((_INT) * 4)) /* _i=0...2047 */ /* Reset Source: CORER */
+
+#define ICRDMA_DB_ADDR_OFFSET (8 * 1024 * 1024 - 64 * 1024)
+
+#define ICRDMA_VF_DB_ADDR_OFFSET (64 * 1024)
+
+/* shifts/masks for FLD_[LS/RS]_64 macros used in device table */
+#define ICRDMA_CCQPSTATUS_CCQP_DONE_S 0
+#define ICRDMA_CCQPSTATUS_CCQP_DONE BIT_ULL(0)
+#define ICRDMA_CCQPSTATUS_CCQP_ERR_S 31
+#define ICRDMA_CCQPSTATUS_CCQP_ERR BIT_ULL(31)
+#define ICRDMA_CQPSQ_STAG_PDID_S 46
+#define ICRDMA_CQPSQ_STAG_PDID GENMASK_ULL(63, 46)
+#define ICRDMA_CQPSQ_CQ_CEQID_S 22
+#define ICRDMA_CQPSQ_CQ_CEQID GENMASK_ULL(31, 22)
+#define ICRDMA_CQPSQ_CQ_CQID_S 0
+#define ICRDMA_CQPSQ_CQ_CQID GENMASK_ULL(18, 0)
+#define ICRDMA_COMMIT_FPM_CQCNT_S 0
+#define ICRDMA_COMMIT_FPM_CQCNT GENMASK_ULL(19, 0)
+
+enum icrdma_device_caps_const {
+ ICRDMA_MAX_STATS_COUNT = 128,
+
+ ICRDMA_MAX_IRD_SIZE = 127,
+ ICRDMA_MAX_ORD_SIZE = 255,
+
+};
+
+void icrdma_init_hw(struct irdma_sc_dev *dev);
+#endif /* ICRDMA_HW_H*/
diff --git a/drivers/infiniband/hw/irdma/irdma.h b/drivers/infiniband/hw/irdma/irdma.h
new file mode 100644
index 000000000000..46c12334c735
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/irdma.h
@@ -0,0 +1,153 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2017 - 2021 Intel Corporation */
+#ifndef IRDMA_H
+#define IRDMA_H
+
+#define IRDMA_WQEALLOC_WQE_DESC_INDEX GENMASK(31, 20)
+
+#define IRDMA_CQPTAIL_WQTAIL GENMASK(10, 0)
+#define IRDMA_CQPTAIL_CQP_OP_ERR BIT(31)
+
+#define IRDMA_CQPERRCODES_CQP_MINOR_CODE GENMASK(15, 0)
+#define IRDMA_CQPERRCODES_CQP_MAJOR_CODE GENMASK(31, 16)
+#define IRDMA_GLPCI_LBARCTRL_PE_DB_SIZE GENMASK(5, 4)
+#define IRDMA_GLINT_RATE_INTERVAL GENMASK(5, 0)
+#define IRDMA_GLINT_RATE_INTRL_ENA BIT(6)
+#define IRDMA_GLINT_DYN_CTL_INTENA BIT(0)
+#define IRDMA_GLINT_DYN_CTL_CLEARPBA BIT(1)
+#define IRDMA_GLINT_DYN_CTL_ITR_INDX GENMASK(4, 3)
+#define IRDMA_GLINT_DYN_CTL_INTERVAL GENMASK(16, 5)
+#define IRDMA_GLINT_CEQCTL_ITR_INDX GENMASK(12, 11)
+#define IRDMA_GLINT_CEQCTL_CAUSE_ENA BIT(30)
+#define IRDMA_GLINT_CEQCTL_MSIX_INDX GENMASK(10, 0)
+#define IRDMA_PFINT_AEQCTL_MSIX_INDX GENMASK(10, 0)
+#define IRDMA_PFINT_AEQCTL_ITR_INDX GENMASK(12, 11)
+#define IRDMA_PFINT_AEQCTL_CAUSE_ENA BIT(30)
+#define IRDMA_PFHMC_PDINV_PMSDIDX GENMASK(11, 0)
+#define IRDMA_PFHMC_PDINV_PMSDPARTSEL BIT(15)
+#define IRDMA_PFHMC_PDINV_PMPDIDX GENMASK(24, 16)
+#define IRDMA_PFHMC_SDDATALOW_PMSDVALID BIT(0)
+#define IRDMA_PFHMC_SDDATALOW_PMSDTYPE BIT(1)
+#define IRDMA_PFHMC_SDDATALOW_PMSDBPCOUNT GENMASK(11, 2)
+#define IRDMA_PFHMC_SDDATALOW_PMSDDATALOW GENMASK(31, 12)
+#define IRDMA_PFHMC_SDCMD_PMSDWR BIT(31)
+
+#define IRDMA_INVALID_CQ_IDX 0xffffffff
+enum irdma_registers {
+ IRDMA_CQPTAIL,
+ IRDMA_CQPDB,
+ IRDMA_CCQPSTATUS,
+ IRDMA_CCQPHIGH,
+ IRDMA_CCQPLOW,
+ IRDMA_CQARM,
+ IRDMA_CQACK,
+ IRDMA_AEQALLOC,
+ IRDMA_CQPERRCODES,
+ IRDMA_WQEALLOC,
+ IRDMA_GLINT_DYN_CTL,
+ IRDMA_DB_ADDR_OFFSET,
+ IRDMA_GLPCI_LBARCTRL,
+ IRDMA_GLPE_CPUSTATUS0,
+ IRDMA_GLPE_CPUSTATUS1,
+ IRDMA_GLPE_CPUSTATUS2,
+ IRDMA_PFINT_AEQCTL,
+ IRDMA_GLINT_CEQCTL,
+ IRDMA_VSIQF_PE_CTL1,
+ IRDMA_PFHMC_PDINV,
+ IRDMA_GLHMC_VFPDINV,
+ IRDMA_GLPE_CRITERR,
+ IRDMA_GLINT_RATE,
+ IRDMA_MAX_REGS, /* Must be last entry */
+};
+
+enum irdma_shifts {
+ IRDMA_CCQPSTATUS_CCQP_DONE_S,
+ IRDMA_CCQPSTATUS_CCQP_ERR_S,
+ IRDMA_CQPSQ_STAG_PDID_S,
+ IRDMA_CQPSQ_CQ_CEQID_S,
+ IRDMA_CQPSQ_CQ_CQID_S,
+ IRDMA_COMMIT_FPM_CQCNT_S,
+ IRDMA_MAX_SHIFTS,
+};
+
+enum irdma_masks {
+ IRDMA_CCQPSTATUS_CCQP_DONE_M,
+ IRDMA_CCQPSTATUS_CCQP_ERR_M,
+ IRDMA_CQPSQ_STAG_PDID_M,
+ IRDMA_CQPSQ_CQ_CEQID_M,
+ IRDMA_CQPSQ_CQ_CQID_M,
+ IRDMA_COMMIT_FPM_CQCNT_M,
+ IRDMA_MAX_MASKS, /* Must be last entry */
+};
+
+#define IRDMA_MAX_MGS_PER_CTX 8
+
+struct irdma_mcast_grp_ctx_entry_info {
+ u32 qp_id;
+ bool valid_entry;
+ u16 dest_port;
+ u32 use_cnt;
+};
+
+struct irdma_mcast_grp_info {
+ u8 dest_mac_addr[ETH_ALEN];
+ u16 vlan_id;
+ u8 hmc_fcn_id;
+ bool ipv4_valid:1;
+ bool vlan_valid:1;
+ u16 mg_id;
+ u32 no_of_mgs;
+ u32 dest_ip_addr[4];
+ u16 qs_handle;
+ struct irdma_dma_mem dma_mem_mc;
+ struct irdma_mcast_grp_ctx_entry_info mg_ctx_info[IRDMA_MAX_MGS_PER_CTX];
+};
+
+enum irdma_vers {
+ IRDMA_GEN_RSVD,
+ IRDMA_GEN_1,
+ IRDMA_GEN_2,
+};
+
+struct irdma_uk_attrs {
+ u64 feature_flags;
+ u32 max_hw_wq_frags;
+ u32 max_hw_read_sges;
+ u32 max_hw_inline;
+ u32 max_hw_rq_quanta;
+ u32 max_hw_wq_quanta;
+ u32 min_hw_cq_size;
+ u32 max_hw_cq_size;
+ u16 max_hw_sq_chunk;
+ u8 hw_rev;
+};
+
+struct irdma_hw_attrs {
+ struct irdma_uk_attrs uk_attrs;
+ u64 max_hw_outbound_msg_size;
+ u64 max_hw_inbound_msg_size;
+ u64 max_mr_size;
+ u32 min_hw_qp_id;
+ u32 min_hw_aeq_size;
+ u32 max_hw_aeq_size;
+ u32 min_hw_ceq_size;
+ u32 max_hw_ceq_size;
+ u32 max_hw_device_pages;
+ u32 max_hw_vf_fpm_id;
+ u32 first_hw_vf_fpm_id;
+ u32 max_hw_ird;
+ u32 max_hw_ord;
+ u32 max_hw_wqes;
+ u32 max_hw_pds;
+ u32 max_hw_ena_vf_count;
+ u32 max_qp_wr;
+ u32 max_pe_ready_count;
+ u32 max_done_count;
+ u32 max_sleep_count;
+ u32 max_cqp_compl_wait_time_ms;
+ u16 max_stat_inst;
+};
+
+void i40iw_init_hw(struct irdma_sc_dev *dev);
+void icrdma_init_hw(struct irdma_sc_dev *dev);
+#endif /* IRDMA_H*/
diff --git a/drivers/infiniband/hw/irdma/main.c b/drivers/infiniband/hw/irdma/main.c
new file mode 100644
index 000000000000..ea59432351fb
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/main.c
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#include "main.h"
+#include "../../../net/ethernet/intel/ice/ice.h"
+
+MODULE_ALIAS("i40iw");
+MODULE_AUTHOR("Intel Corporation, <e1000-rdma@lists.sourceforge.net>");
+MODULE_DESCRIPTION("Intel(R) Ethernet Protocol Driver for RDMA");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static struct notifier_block irdma_inetaddr_notifier = {
+ .notifier_call = irdma_inetaddr_event
+};
+
+static struct notifier_block irdma_inetaddr6_notifier = {
+ .notifier_call = irdma_inet6addr_event
+};
+
+static struct notifier_block irdma_net_notifier = {
+ .notifier_call = irdma_net_event
+};
+
+static struct notifier_block irdma_netdevice_notifier = {
+ .notifier_call = irdma_netdevice_event
+};
+
+static void irdma_register_notifiers(void)
+{
+ register_inetaddr_notifier(&irdma_inetaddr_notifier);
+ register_inet6addr_notifier(&irdma_inetaddr6_notifier);
+ register_netevent_notifier(&irdma_net_notifier);
+ register_netdevice_notifier(&irdma_netdevice_notifier);
+}
+
+static void irdma_unregister_notifiers(void)
+{
+ unregister_netevent_notifier(&irdma_net_notifier);
+ unregister_inetaddr_notifier(&irdma_inetaddr_notifier);
+ unregister_inet6addr_notifier(&irdma_inetaddr6_notifier);
+ unregister_netdevice_notifier(&irdma_netdevice_notifier);
+}
+
+static void irdma_prep_tc_change(struct irdma_device *iwdev)
+{
+ iwdev->vsi.tc_change_pending = true;
+ irdma_sc_suspend_resume_qps(&iwdev->vsi, IRDMA_OP_SUSPEND);
+
+ /* Wait for all qp's to suspend */
+ wait_event_timeout(iwdev->suspend_wq,
+ !atomic_read(&iwdev->vsi.qp_suspend_reqs),
+ IRDMA_EVENT_TIMEOUT);
+ irdma_ws_reset(&iwdev->vsi);
+}
+
+static void irdma_log_invalid_mtu(u16 mtu, struct irdma_sc_dev *dev)
+{
+ if (mtu < IRDMA_MIN_MTU_IPV4)
+ ibdev_warn(to_ibdev(dev), "MTU setting [%d] too low for RDMA traffic. Minimum MTU is 576 for IPv4\n", mtu);
+ else if (mtu < IRDMA_MIN_MTU_IPV6)
+ ibdev_warn(to_ibdev(dev), "MTU setting [%d] too low for RDMA traffic. Minimum MTU is 1280 for IPv6\\n", mtu);
+}
+
+static void irdma_fill_qos_info(struct irdma_l2params *l2params,
+ struct iidc_qos_params *qos_info)
+{
+ int i;
+
+ l2params->num_tc = qos_info->num_tc;
+ l2params->vsi_prio_type = qos_info->vport_priority_type;
+ l2params->vsi_rel_bw = qos_info->vport_relative_bw;
+ for (i = 0; i < l2params->num_tc; i++) {
+ l2params->tc_info[i].egress_virt_up =
+ qos_info->tc_info[i].egress_virt_up;
+ l2params->tc_info[i].ingress_virt_up =
+ qos_info->tc_info[i].ingress_virt_up;
+ l2params->tc_info[i].prio_type = qos_info->tc_info[i].prio_type;
+ l2params->tc_info[i].rel_bw = qos_info->tc_info[i].rel_bw;
+ l2params->tc_info[i].tc_ctx = qos_info->tc_info[i].tc_ctx;
+ }
+ for (i = 0; i < IIDC_MAX_USER_PRIORITY; i++)
+ l2params->up2tc[i] = qos_info->up2tc[i];
+}
+
+static void irdma_iidc_event_handler(struct ice_pf *pf, struct iidc_event *event)
+{
+ struct irdma_device *iwdev = dev_get_drvdata(&pf->adev->dev);
+ struct irdma_l2params l2params = {};
+
+ if (*event->type & BIT(IIDC_EVENT_AFTER_MTU_CHANGE)) {
+ ibdev_dbg(&iwdev->ibdev, "CLNT: new MTU = %d\n", iwdev->netdev->mtu);
+ if (iwdev->vsi.mtu != iwdev->netdev->mtu) {
+ l2params.mtu = iwdev->netdev->mtu;
+ l2params.mtu_changed = true;
+ irdma_log_invalid_mtu(l2params.mtu, &iwdev->rf->sc_dev);
+ irdma_change_l2params(&iwdev->vsi, &l2params);
+ }
+ } else if (*event->type & BIT(IIDC_EVENT_BEFORE_TC_CHANGE)) {
+ if (iwdev->vsi.tc_change_pending)
+ return;
+
+ irdma_prep_tc_change(iwdev);
+ } else if (*event->type & BIT(IIDC_EVENT_AFTER_TC_CHANGE)) {
+ struct iidc_qos_params qos_info = {};
+
+ if (!iwdev->vsi.tc_change_pending)
+ return;
+
+ l2params.tc_changed = true;
+ ibdev_dbg(&iwdev->ibdev, "CLNT: TC Change\n");
+ ice_get_qos_params(pf, &qos_info);
+ iwdev->dcb = qos_info.num_tc > 1;
+ irdma_fill_qos_info(&l2params, &qos_info);
+ irdma_change_l2params(&iwdev->vsi, &l2params);
+ } else if (*event->type & BIT(IIDC_EVENT_CRIT_ERR)) {
+ ibdev_warn(&iwdev->ibdev, "ICE OICR event notification: oicr = 0x%08x\n",
+ event->reg);
+ if (event->reg & IRDMAPFINT_OICR_PE_CRITERR_M) {
+ u32 pe_criterr;
+
+ pe_criterr = readl(iwdev->rf->sc_dev.hw_regs[IRDMA_GLPE_CRITERR]);
+#define IRDMA_Q1_RESOURCE_ERR 0x0001024d
+ if (pe_criterr != IRDMA_Q1_RESOURCE_ERR) {
+ ibdev_err(&iwdev->ibdev, "critical PE Error, GLPE_CRITERR=0x%08x\n",
+ pe_criterr);
+ iwdev->rf->reset = true;
+ } else {
+ ibdev_warn(&iwdev->ibdev, "Q1 Resource Check\n");
+ }
+ }
+ if (event->reg & IRDMAPFINT_OICR_HMC_ERR_M) {
+ ibdev_err(&iwdev->ibdev, "HMC Error\n");
+ iwdev->rf->reset = true;
+ }
+ if (event->reg & IRDMAPFINT_OICR_PE_PUSH_M) {
+ ibdev_err(&iwdev->ibdev, "PE Push Error\n");
+ iwdev->rf->reset = true;
+ }
+ if (iwdev->rf->reset)
+ iwdev->rf->gen_ops.request_reset(iwdev->rf);
+ }
+}
+
+/**
+ * irdma_request_reset - Request a reset
+ * @rf: RDMA PCI function
+ */
+static void irdma_request_reset(struct irdma_pci_f *rf)
+{
+ struct ice_pf *pf = rf->cdev;
+
+ ibdev_warn(&rf->iwdev->ibdev, "Requesting a reset\n");
+ ice_rdma_request_reset(pf, IIDC_PFR);
+}
+
+/**
+ * irdma_lan_register_qset - Register qset with LAN driver
+ * @vsi: vsi structure
+ * @tc_node: Traffic class node
+ */
+static enum irdma_status_code irdma_lan_register_qset(struct irdma_sc_vsi *vsi,
+ struct irdma_ws_node *tc_node)
+{
+ struct irdma_device *iwdev = vsi->back_vsi;
+ struct ice_pf *pf = iwdev->rf->cdev;
+ struct iidc_rdma_qset_params qset = {};
+ int ret;
+
+ qset.qs_handle = tc_node->qs_handle;
+ qset.tc = tc_node->traffic_class;
+ qset.vport_id = vsi->vsi_idx;
+ ret = ice_add_rdma_qset(pf, &qset);
+ if (ret) {
+ ibdev_dbg(&iwdev->ibdev, "WS: LAN alloc_res for rdma qset failed.\n");
+ return IRDMA_ERR_REG_QSET;
+ }
+
+ tc_node->l2_sched_node_id = qset.teid;
+ vsi->qos[tc_node->user_pri].l2_sched_node_id = qset.teid;
+
+ return 0;
+}
+
+/**
+ * irdma_lan_unregister_qset - Unregister qset with LAN driver
+ * @vsi: vsi structure
+ * @tc_node: Traffic class node
+ */
+static void irdma_lan_unregister_qset(struct irdma_sc_vsi *vsi,
+ struct irdma_ws_node *tc_node)
+{
+ struct irdma_device *iwdev = vsi->back_vsi;
+ struct ice_pf *pf = iwdev->rf->cdev;
+ struct iidc_rdma_qset_params qset = {};
+
+ qset.qs_handle = tc_node->qs_handle;
+ qset.tc = tc_node->traffic_class;
+ qset.vport_id = vsi->vsi_idx;
+ qset.teid = tc_node->l2_sched_node_id;
+
+ if (ice_del_rdma_qset(pf, &qset))
+ ibdev_dbg(&iwdev->ibdev, "WS: LAN free_res for rdma qset failed.\n");
+}
+
+static void irdma_remove(struct auxiliary_device *aux_dev)
+{
+ struct iidc_auxiliary_dev *iidc_adev = container_of(aux_dev,
+ struct iidc_auxiliary_dev,
+ adev);
+ struct ice_pf *pf = iidc_adev->pf;
+ struct irdma_device *iwdev = dev_get_drvdata(&aux_dev->dev);
+
+ irdma_ib_unregister_device(iwdev);
+ ice_rdma_update_vsi_filter(pf, iwdev->vsi_num, false);
+
+ pr_debug("INIT: Gen2 PF[%d] device remove success\n", PCI_FUNC(pf->pdev->devfn));
+}
+
+static void irdma_fill_device_info(struct irdma_device *iwdev, struct ice_pf *pf)
+{
+ struct irdma_pci_f *rf = iwdev->rf;
+ struct ice_vsi *vsi = ice_get_main_vsi(pf);
+
+ rf->cdev = pf;
+ rf->gen_ops.register_qset = irdma_lan_register_qset;
+ rf->gen_ops.unregister_qset = irdma_lan_unregister_qset;
+ rf->hw.hw_addr = pf->hw.hw_addr;
+ rf->pcidev = pf->pdev;
+ rf->msix_count = pf->num_rdma_msix;
+ rf->msix_entries = &pf->msix_entries[pf->rdma_base_vector];
+ rf->default_vsi.vsi_idx = vsi->vsi_num;
+ rf->protocol_used = IRDMA_ROCE_PROTOCOL_ONLY;
+ rf->rdma_ver = IRDMA_GEN_2;
+ rf->rsrc_profile = IRDMA_HMC_PROFILE_DEFAULT;
+ rf->rst_to = IRDMA_RST_TIMEOUT_HZ;
+ rf->gen_ops.request_reset = irdma_request_reset;
+ rf->limits_sel = 7;
+ rf->iwdev = iwdev;
+
+ iwdev->netdev = vsi->netdev;
+ iwdev->vsi_num = vsi->vsi_num;
+ iwdev->init_state = INITIAL_STATE;
+ iwdev->roce_cwnd = IRDMA_ROCE_CWND_DEFAULT;
+ iwdev->roce_ackcreds = IRDMA_ROCE_ACKCREDS_DEFAULT;
+ iwdev->rcv_wnd = IRDMA_CM_DEFAULT_RCV_WND_SCALED;
+ iwdev->rcv_wscale = IRDMA_CM_DEFAULT_RCV_WND_SCALE;
+ if (rf->protocol_used == IRDMA_ROCE_PROTOCOL_ONLY)
+ iwdev->roce_mode = true;
+}
+
+static int irdma_probe(struct auxiliary_device *aux_dev, const struct auxiliary_device_id *id)
+{
+ struct iidc_auxiliary_dev *iidc_adev = container_of(aux_dev,
+ struct iidc_auxiliary_dev,
+ adev);
+ struct ice_pf *pf = iidc_adev->pf;
+ struct iidc_qos_params qos_info = {};
+ struct irdma_device *iwdev;
+ struct irdma_pci_f *rf;
+ struct irdma_l2params l2params = {};
+ int err;
+
+ iwdev = ib_alloc_device(irdma_device, ibdev);
+ if (!iwdev)
+ return -ENOMEM;
+ iwdev->rf = kzalloc(sizeof(*rf), GFP_KERNEL);
+ if (!iwdev->rf) {
+ ib_dealloc_device(&iwdev->ibdev);
+ return -ENOMEM;
+ }
+
+ irdma_fill_device_info(iwdev, pf);
+ rf = iwdev->rf;
+
+ if (irdma_ctrl_init_hw(rf)) {
+ err = -EIO;
+ goto err_ctrl_init;
+ }
+
+ l2params.mtu = iwdev->netdev->mtu;
+ ice_get_qos_params(pf, &qos_info);
+ irdma_fill_qos_info(&l2params, &qos_info);
+ if (irdma_rt_init_hw(iwdev, &l2params)) {
+ err = -EIO;
+ goto err_rt_init;
+ }
+
+ err = irdma_ib_register_device(iwdev);
+ if (err)
+ goto err_ibreg;
+
+ ice_rdma_update_vsi_filter(pf, iwdev->vsi_num, true);
+
+ ibdev_dbg(&iwdev->ibdev, "INIT: Gen2 PF[%d] device probe success\n", PCI_FUNC(rf->pcidev->devfn));
+ dev_set_drvdata(&aux_dev->dev, iwdev);
+
+ return 0;
+
+err_ibreg:
+ irdma_rt_deinit_hw(iwdev);
+err_rt_init:
+ irdma_ctrl_deinit_hw(rf);
+err_ctrl_init:
+ kfree(iwdev->rf);
+ ib_dealloc_device(&iwdev->ibdev);
+
+ return err;
+}
+
+static const struct auxiliary_device_id irdma_auxiliary_id_table[] = {
+ {.name = "ice.iwarp", },
+ {.name = "ice.roce", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(auxiliary, irdma_auxiliary_id_table);
+
+static struct iidc_auxiliary_drv irdma_auxiliary_drv = {
+ .adrv = {
+ .id_table = irdma_auxiliary_id_table,
+ .probe = irdma_probe,
+ .remove = irdma_remove,
+ },
+ .event_handler = irdma_iidc_event_handler,
+};
+
+static int __init irdma_init_module(void)
+{
+ int ret;
+
+ ret = auxiliary_driver_register(&i40iw_auxiliary_drv);
+ if (ret) {
+ pr_err("Failed i40iw(gen_1) auxiliary_driver_register() ret=%d\n",
+ ret);
+ return ret;
+ }
+
+ ret = auxiliary_driver_register(&irdma_auxiliary_drv.adrv);
+ if (ret) {
+ auxiliary_driver_unregister(&i40iw_auxiliary_drv);
+ pr_err("Failed irdma auxiliary_driver_register() ret=%d\n",
+ ret);
+ return ret;
+ }
+
+ irdma_register_notifiers();
+
+ return 0;
+}
+
+static void __exit irdma_exit_module(void)
+{
+ irdma_unregister_notifiers();
+ auxiliary_driver_unregister(&irdma_auxiliary_drv.adrv);
+ auxiliary_driver_unregister(&i40iw_auxiliary_drv);
+}
+
+module_init(irdma_init_module);
+module_exit(irdma_exit_module);
diff --git a/drivers/infiniband/hw/irdma/main.h b/drivers/infiniband/hw/irdma/main.h
new file mode 100644
index 000000000000..743d9e143a99
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/main.h
@@ -0,0 +1,555 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#ifndef IRDMA_MAIN_H
+#define IRDMA_MAIN_H
+
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/if_vlan.h>
+#include <net/addrconf.h>
+#include <net/netevent.h>
+#include <net/tcp.h>
+#include <net/ip6_route.h>
+#include <net/flow.h>
+#include <net/secure_seq.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/inetdevice.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 <linux/io.h>
+#include <linux/crc32c.h>
+#include <linux/kthread.h>
+#ifndef CONFIG_64BIT
+#include <linux/io-64-nonatomic-lo-hi.h>
+#endif
+#include <linux/auxiliary_bus.h>
+#include <linux/net/intel/iidc.h>
+#include <crypto/hash.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/ib_user_verbs.h>
+#include <rdma/ib_umem.h>
+#include <rdma/ib_cache.h>
+#include <rdma/uverbs_ioctl.h>
+#include "status.h"
+#include "osdep.h"
+#include "defs.h"
+#include "hmc.h"
+#include "type.h"
+#include "ws.h"
+#include "protos.h"
+#include "pble.h"
+#include "cm.h"
+#include <rdma/irdma-abi.h>
+#include "verbs.h"
+#include "user.h"
+#include "puda.h"
+
+extern struct auxiliary_driver i40iw_auxiliary_drv;
+
+#define IRDMA_FW_VER_DEFAULT 2
+#define IRDMA_HW_VER 2
+
+#define IRDMA_ARP_ADD 1
+#define IRDMA_ARP_DELETE 2
+#define IRDMA_ARP_RESOLVE 3
+
+#define IRDMA_MACIP_ADD 1
+#define IRDMA_MACIP_DELETE 2
+
+#define IW_CCQ_SIZE (IRDMA_CQP_SW_SQSIZE_2048 + 1)
+#define IW_CEQ_SIZE 2048
+#define IW_AEQ_SIZE 2048
+
+#define RX_BUF_SIZE (1536 + 8)
+#define IW_REG0_SIZE (4 * 1024)
+#define IW_TX_TIMEOUT (6 * HZ)
+#define IW_FIRST_QPN 1
+
+#define IW_SW_CONTEXT_ALIGN 1024
+
+#define MAX_DPC_ITERATIONS 128
+
+#define IRDMA_EVENT_TIMEOUT 50000
+#define IRDMA_VCHNL_EVENT_TIMEOUT 100000
+#define IRDMA_RST_TIMEOUT_HZ 4
+
+#define IRDMA_NO_QSET 0xffff
+
+#define IW_CFG_FPM_QP_COUNT 32768
+#define IRDMA_MAX_PAGES_PER_FMR 512
+#define IRDMA_MIN_PAGES_PER_FMR 1
+#define IRDMA_CQP_COMPL_RQ_WQE_FLUSHED 2
+#define IRDMA_CQP_COMPL_SQ_WQE_FLUSHED 3
+
+#define IRDMA_Q_TYPE_PE_AEQ 0x80
+#define IRDMA_Q_INVALID_IDX 0xffff
+#define IRDMA_REM_ENDPOINT_TRK_QPID 3
+
+#define IRDMA_DRV_OPT_ENA_MPA_VER_0 0x00000001
+#define IRDMA_DRV_OPT_DISABLE_MPA_CRC 0x00000002
+#define IRDMA_DRV_OPT_DISABLE_FIRST_WRITE 0x00000004
+#define IRDMA_DRV_OPT_DISABLE_INTF 0x00000008
+#define IRDMA_DRV_OPT_ENA_MSI 0x00000010
+#define IRDMA_DRV_OPT_DUAL_LOGICAL_PORT 0x00000020
+#define IRDMA_DRV_OPT_NO_INLINE_DATA 0x00000080
+#define IRDMA_DRV_OPT_DISABLE_INT_MOD 0x00000100
+#define IRDMA_DRV_OPT_DISABLE_VIRT_WQ 0x00000200
+#define IRDMA_DRV_OPT_ENA_PAU 0x00000400
+#define IRDMA_DRV_OPT_MCAST_LOGPORT_MAP 0x00000800
+
+#define IW_HMC_OBJ_TYPE_NUM ARRAY_SIZE(iw_hmc_obj_types)
+#define IRDMA_ROCE_CWND_DEFAULT 0x400
+#define IRDMA_ROCE_ACKCREDS_DEFAULT 0x1E
+
+#define IRDMA_FLUSH_SQ BIT(0)
+#define IRDMA_FLUSH_RQ BIT(1)
+#define IRDMA_REFLUSH BIT(2)
+#define IRDMA_FLUSH_WAIT BIT(3)
+
+enum init_completion_state {
+ INVALID_STATE = 0,
+ INITIAL_STATE,
+ CQP_CREATED,
+ HMC_OBJS_CREATED,
+ HW_RSRC_INITIALIZED,
+ CCQ_CREATED,
+ CEQ0_CREATED, /* Last state of probe */
+ ILQ_CREATED,
+ IEQ_CREATED,
+ CEQS_CREATED,
+ PBLE_CHUNK_MEM,
+ AEQ_CREATED,
+ IP_ADDR_REGISTERED, /* Last state of open */
+};
+
+struct irdma_rsrc_limits {
+ u32 qplimit;
+ u32 mrlimit;
+ u32 cqlimit;
+};
+
+struct irdma_cqp_err_info {
+ u16 maj;
+ u16 min;
+ const char *desc;
+};
+
+struct irdma_cqp_compl_info {
+ u32 op_ret_val;
+ u16 maj_err_code;
+ u16 min_err_code;
+ bool error;
+ u8 op_code;
+};
+
+struct irdma_cqp_request {
+ struct cqp_cmds_info info;
+ wait_queue_head_t waitq;
+ struct list_head list;
+ refcount_t refcnt;
+ void (*callback_fcn)(struct irdma_cqp_request *cqp_request);
+ void *param;
+ struct irdma_cqp_compl_info compl_info;
+ bool waiting:1;
+ bool request_done:1;
+ bool dynamic:1;
+};
+
+struct irdma_cqp {
+ struct irdma_sc_cqp sc_cqp;
+ spinlock_t req_lock; /* protect CQP request list */
+ spinlock_t compl_lock; /* protect CQP completion processing */
+ wait_queue_head_t waitq;
+ wait_queue_head_t remove_wq;
+ struct irdma_dma_mem sq;
+ struct irdma_dma_mem host_ctx;
+ u64 *scratch_array;
+ struct irdma_cqp_request *cqp_requests;
+ struct list_head cqp_avail_reqs;
+ struct list_head cqp_pending_reqs;
+};
+
+struct irdma_ccq {
+ struct irdma_sc_cq sc_cq;
+ struct irdma_dma_mem mem_cq;
+ struct irdma_dma_mem shadow_area;
+};
+
+struct irdma_ceq {
+ struct irdma_sc_ceq sc_ceq;
+ struct irdma_dma_mem mem;
+ u32 irq;
+ u32 msix_idx;
+ struct irdma_pci_f *rf;
+ struct tasklet_struct dpc_tasklet;
+ spinlock_t ce_lock; /* sync cq destroy with cq completion event notification */
+};
+
+struct irdma_aeq {
+ struct irdma_sc_aeq sc_aeq;
+ struct irdma_dma_mem mem;
+ struct irdma_pble_alloc palloc;
+ bool virtual_map;
+};
+
+struct irdma_arp_entry {
+ u32 ip_addr[4];
+ u8 mac_addr[ETH_ALEN];
+};
+
+struct irdma_msix_vector {
+ u32 idx;
+ u32 irq;
+ u32 cpu_affinity;
+ u32 ceq_id;
+ cpumask_t mask;
+};
+
+struct irdma_mc_table_info {
+ u32 mgn;
+ u32 dest_ip[4];
+ bool lan_fwd:1;
+ bool ipv4_valid:1;
+};
+
+struct mc_table_list {
+ struct list_head list;
+ struct irdma_mc_table_info mc_info;
+ struct irdma_mcast_grp_info mc_grp_ctx;
+};
+
+struct irdma_qv_info {
+ u32 v_idx; /* msix_vector */
+ u16 ceq_idx;
+ u16 aeq_idx;
+ u8 itr_idx;
+};
+
+struct irdma_qvlist_info {
+ u32 num_vectors;
+ struct irdma_qv_info qv_info[1];
+};
+
+struct irdma_gen_ops {
+ void (*request_reset)(struct irdma_pci_f *rf);
+ enum irdma_status_code (*register_qset)(struct irdma_sc_vsi *vsi,
+ struct irdma_ws_node *tc_node);
+ void (*unregister_qset)(struct irdma_sc_vsi *vsi,
+ struct irdma_ws_node *tc_node);
+};
+
+struct irdma_pci_f {
+ bool reset:1;
+ bool rsrc_created:1;
+ bool msix_shared:1;
+ u8 rsrc_profile;
+ u8 *hmc_info_mem;
+ u8 *mem_rsrc;
+ u8 rdma_ver;
+ u8 rst_to;
+ enum irdma_protocol_used protocol_used;
+ u32 sd_type;
+ u32 msix_count;
+ u32 max_mr;
+ u32 max_qp;
+ u32 max_cq;
+ u32 max_ah;
+ u32 next_ah;
+ u32 max_mcg;
+ u32 next_mcg;
+ u32 max_pd;
+ u32 next_qp;
+ u32 next_cq;
+ u32 next_pd;
+ u32 max_mr_size;
+ u32 max_cqe;
+ u32 mr_stagmask;
+ u32 used_pds;
+ u32 used_cqs;
+ u32 used_mrs;
+ u32 used_qps;
+ u32 arp_table_size;
+ u32 next_arp_index;
+ u32 ceqs_count;
+ u32 next_ws_node_id;
+ u32 max_ws_node_id;
+ u32 limits_sel;
+ unsigned long *allocated_ws_nodes;
+ unsigned long *allocated_qps;
+ unsigned long *allocated_cqs;
+ unsigned long *allocated_mrs;
+ unsigned long *allocated_pds;
+ unsigned long *allocated_mcgs;
+ unsigned long *allocated_ahs;
+ unsigned long *allocated_arps;
+ enum init_completion_state init_state;
+ struct irdma_sc_dev sc_dev;
+ struct pci_dev *pcidev;
+ void *cdev;
+ struct irdma_hw hw;
+ struct irdma_cqp cqp;
+ struct irdma_ccq ccq;
+ struct irdma_aeq aeq;
+ struct irdma_ceq *ceqlist;
+ struct irdma_hmc_pble_rsrc *pble_rsrc;
+ struct irdma_arp_entry *arp_table;
+ spinlock_t arp_lock; /*protect ARP table access*/
+ spinlock_t rsrc_lock; /* protect HW resource array access */
+ spinlock_t qptable_lock; /*protect QP table access*/
+ struct irdma_qp **qp_table;
+ spinlock_t qh_list_lock; /* protect mc_qht_list */
+ struct mc_table_list mc_qht_list;
+ struct irdma_msix_vector *iw_msixtbl;
+ struct irdma_qvlist_info *iw_qvlist;
+ struct tasklet_struct dpc_tasklet;
+ struct msix_entry *msix_entries;
+ struct irdma_dma_mem obj_mem;
+ struct irdma_dma_mem obj_next;
+ atomic_t vchnl_msgs;
+ wait_queue_head_t vchnl_waitq;
+ struct workqueue_struct *cqp_cmpl_wq;
+ struct work_struct cqp_cmpl_work;
+ struct irdma_sc_vsi default_vsi;
+ void *back_fcn;
+ struct irdma_gen_ops gen_ops;
+ struct irdma_device *iwdev;
+};
+
+struct irdma_device {
+ struct ib_device ibdev;
+ struct irdma_pci_f *rf;
+ struct net_device *netdev;
+ struct workqueue_struct *cleanup_wq;
+ struct irdma_sc_vsi vsi;
+ struct irdma_cm_core cm_core;
+ u32 roce_cwnd;
+ u32 roce_ackcreds;
+ u32 vendor_id;
+ u32 vendor_part_id;
+ u32 device_cap_flags;
+ u32 push_mode;
+ u32 rcv_wnd;
+ u16 mac_ip_table_idx;
+ u16 vsi_num;
+ u8 rcv_wscale;
+ u8 iw_status;
+ bool roce_mode:1;
+ bool roce_dcqcn_en:1;
+ bool dcb:1;
+ bool reset:1;
+ bool iw_ooo:1;
+ enum init_completion_state init_state;
+
+ wait_queue_head_t suspend_wq;
+};
+
+static inline struct irdma_device *to_iwdev(struct ib_device *ibdev)
+{
+ return container_of(ibdev, struct irdma_device, ibdev);
+}
+
+static inline struct irdma_ucontext *to_ucontext(struct ib_ucontext *ibucontext)
+{
+ return container_of(ibucontext, struct irdma_ucontext, ibucontext);
+}
+
+static inline struct irdma_user_mmap_entry *
+to_irdma_mmap_entry(struct rdma_user_mmap_entry *rdma_entry)
+{
+ return container_of(rdma_entry, struct irdma_user_mmap_entry,
+ rdma_entry);
+}
+
+static inline struct irdma_pd *to_iwpd(struct ib_pd *ibpd)
+{
+ return container_of(ibpd, struct irdma_pd, ibpd);
+}
+
+static inline struct irdma_ah *to_iwah(struct ib_ah *ibah)
+{
+ return container_of(ibah, struct irdma_ah, ibah);
+}
+
+static inline struct irdma_mr *to_iwmr(struct ib_mr *ibmr)
+{
+ return container_of(ibmr, struct irdma_mr, ibmr);
+}
+
+static inline struct irdma_mr *to_iwmw(struct ib_mw *ibmw)
+{
+ return container_of(ibmw, struct irdma_mr, ibmw);
+}
+
+static inline struct irdma_cq *to_iwcq(struct ib_cq *ibcq)
+{
+ return container_of(ibcq, struct irdma_cq, ibcq);
+}
+
+static inline struct irdma_qp *to_iwqp(struct ib_qp *ibqp)
+{
+ return container_of(ibqp, struct irdma_qp, ibqp);
+}
+
+static inline struct irdma_pci_f *dev_to_rf(struct irdma_sc_dev *dev)
+{
+ return container_of(dev, struct irdma_pci_f, sc_dev);
+}
+
+/**
+ * irdma_alloc_resource - allocate a resource
+ * @iwdev: device pointer
+ * @resource_array: resource bit array:
+ * @max_resources: maximum resource number
+ * @req_resources_num: Allocated resource number
+ * @next: next free id
+ **/
+static inline int irdma_alloc_rsrc(struct irdma_pci_f *rf,
+ unsigned long *rsrc_array, u32 max_rsrc,
+ u32 *req_rsrc_num, u32 *next)
+{
+ u32 rsrc_num;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rf->rsrc_lock, flags);
+ rsrc_num = find_next_zero_bit(rsrc_array, max_rsrc, *next);
+ if (rsrc_num >= max_rsrc) {
+ rsrc_num = find_first_zero_bit(rsrc_array, max_rsrc);
+ if (rsrc_num >= max_rsrc) {
+ spin_unlock_irqrestore(&rf->rsrc_lock, flags);
+ ibdev_dbg(&rf->iwdev->ibdev,
+ "ERR: resource [%d] allocation failed\n",
+ rsrc_num);
+ return -EOVERFLOW;
+ }
+ }
+ __set_bit(rsrc_num, rsrc_array);
+ *next = rsrc_num + 1;
+ if (*next == max_rsrc)
+ *next = 0;
+ *req_rsrc_num = rsrc_num;
+ spin_unlock_irqrestore(&rf->rsrc_lock, flags);
+
+ return 0;
+}
+
+/**
+ * irdma_free_resource - free a resource
+ * @iwdev: device pointer
+ * @resource_array: resource array for the resource_num
+ * @resource_num: resource number to free
+ **/
+static inline void irdma_free_rsrc(struct irdma_pci_f *rf,
+ unsigned long *rsrc_array, u32 rsrc_num)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rf->rsrc_lock, flags);
+ __clear_bit(rsrc_num, rsrc_array);
+ spin_unlock_irqrestore(&rf->rsrc_lock, flags);
+}
+
+enum irdma_status_code irdma_ctrl_init_hw(struct irdma_pci_f *rf);
+void irdma_ctrl_deinit_hw(struct irdma_pci_f *rf);
+enum irdma_status_code irdma_rt_init_hw(struct irdma_device *iwdev,
+ struct irdma_l2params *l2params);
+void irdma_rt_deinit_hw(struct irdma_device *iwdev);
+void irdma_qp_add_ref(struct ib_qp *ibqp);
+void irdma_qp_rem_ref(struct ib_qp *ibqp);
+void irdma_free_lsmm_rsrc(struct irdma_qp *iwqp);
+struct ib_qp *irdma_get_qp(struct ib_device *ibdev, int qpn);
+void irdma_flush_wqes(struct irdma_qp *iwqp, u32 flush_mask);
+void irdma_manage_arp_cache(struct irdma_pci_f *rf, unsigned char *mac_addr,
+ u32 *ip_addr, bool ipv4, u32 action);
+struct irdma_apbvt_entry *irdma_add_apbvt(struct irdma_device *iwdev, u16 port);
+void irdma_del_apbvt(struct irdma_device *iwdev,
+ struct irdma_apbvt_entry *entry);
+struct irdma_cqp_request *irdma_alloc_and_get_cqp_request(struct irdma_cqp *cqp,
+ bool wait);
+void irdma_free_cqp_request(struct irdma_cqp *cqp,
+ struct irdma_cqp_request *cqp_request);
+void irdma_put_cqp_request(struct irdma_cqp *cqp,
+ struct irdma_cqp_request *cqp_request);
+int irdma_alloc_local_mac_entry(struct irdma_pci_f *rf, u16 *mac_tbl_idx);
+int irdma_add_local_mac_entry(struct irdma_pci_f *rf, u8 *mac_addr, u16 idx);
+void irdma_del_local_mac_entry(struct irdma_pci_f *rf, u16 idx);
+
+u32 irdma_initialize_hw_rsrc(struct irdma_pci_f *rf);
+void irdma_port_ibevent(struct irdma_device *iwdev);
+void irdma_cm_disconn(struct irdma_qp *qp);
+
+bool irdma_cqp_crit_err(struct irdma_sc_dev *dev, u8 cqp_cmd,
+ u16 maj_err_code, u16 min_err_code);
+enum irdma_status_code
+irdma_handle_cqp_op(struct irdma_pci_f *rf,
+ struct irdma_cqp_request *cqp_request);
+
+int irdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
+ struct ib_udata *udata);
+int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata);
+void irdma_cq_wq_destroy(struct irdma_pci_f *rf, struct irdma_sc_cq *cq);
+
+void irdma_cleanup_pending_cqp_op(struct irdma_pci_f *rf);
+enum irdma_status_code irdma_hw_modify_qp(struct irdma_device *iwdev,
+ struct irdma_qp *iwqp,
+ struct irdma_modify_qp_info *info,
+ bool wait);
+enum irdma_status_code irdma_qp_suspend_resume(struct irdma_sc_qp *qp,
+ bool suspend);
+enum irdma_status_code
+irdma_manage_qhash(struct irdma_device *iwdev, struct irdma_cm_info *cminfo,
+ enum irdma_quad_entry_type etype,
+ enum irdma_quad_hash_manage_type mtype, void *cmnode,
+ bool wait);
+void irdma_receive_ilq(struct irdma_sc_vsi *vsi, struct irdma_puda_buf *rbuf);
+void irdma_free_sqbuf(struct irdma_sc_vsi *vsi, void *bufp);
+void irdma_free_qp_rsrc(struct irdma_qp *iwqp);
+enum irdma_status_code irdma_setup_cm_core(struct irdma_device *iwdev, u8 ver);
+void irdma_cleanup_cm_core(struct irdma_cm_core *cm_core);
+void irdma_next_iw_state(struct irdma_qp *iwqp, u8 state, u8 del_hash, u8 term,
+ u8 term_len);
+int irdma_send_syn(struct irdma_cm_node *cm_node, u32 sendack);
+int irdma_send_reset(struct irdma_cm_node *cm_node);
+struct irdma_cm_node *irdma_find_node(struct irdma_cm_core *cm_core,
+ u16 rem_port, u32 *rem_addr, u16 loc_port,
+ u32 *loc_addr, u16 vlan_id);
+enum irdma_status_code irdma_hw_flush_wqes(struct irdma_pci_f *rf,
+ struct irdma_sc_qp *qp,
+ struct irdma_qp_flush_info *info,
+ bool wait);
+void irdma_gen_ae(struct irdma_pci_f *rf, struct irdma_sc_qp *qp,
+ struct irdma_gen_ae_info *info, bool wait);
+void irdma_copy_ip_ntohl(u32 *dst, __be32 *src);
+void irdma_copy_ip_htonl(__be32 *dst, u32 *src);
+u16 irdma_get_vlan_ipv4(u32 *addr);
+struct net_device *irdma_netdev_vlan_ipv6(u32 *addr, u16 *vlan_id, u8 *mac);
+struct ib_mr *irdma_reg_phys_mr(struct ib_pd *ib_pd, u64 addr, u64 size,
+ int acc, u64 *iova_start);
+int irdma_upload_qp_context(struct irdma_qp *iwqp, bool freeze, bool raw);
+void irdma_cqp_ce_handler(struct irdma_pci_f *rf, struct irdma_sc_cq *cq);
+int irdma_ah_cqp_op(struct irdma_pci_f *rf, struct irdma_sc_ah *sc_ah, u8 cmd,
+ bool wait,
+ void (*callback_fcn)(struct irdma_cqp_request *cqp_request),
+ void *cb_param);
+void irdma_gsi_ud_qp_ah_cb(struct irdma_cqp_request *cqp_request);
+int irdma_inetaddr_event(struct notifier_block *notifier, unsigned long event,
+ void *ptr);
+int irdma_inet6addr_event(struct notifier_block *notifier, unsigned long event,
+ void *ptr);
+int irdma_net_event(struct notifier_block *notifier, unsigned long event,
+ void *ptr);
+int irdma_netdevice_event(struct notifier_block *notifier, unsigned long event,
+ void *ptr);
+void irdma_add_ip(struct irdma_device *iwdev);
+void cqp_compl_worker(struct work_struct *work);
+#endif /* IRDMA_MAIN_H */
diff --git a/drivers/infiniband/hw/irdma/osdep.h b/drivers/infiniband/hw/irdma/osdep.h
new file mode 100644
index 000000000000..b2ab52335ca6
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/osdep.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#ifndef IRDMA_OSDEP_H
+#define IRDMA_OSDEP_H
+
+#include <linux/pci.h>
+#include <linux/bitfield.h>
+#include <crypto/hash.h>
+#include <rdma/ib_verbs.h>
+
+#define STATS_TIMER_DELAY 60000
+
+struct irdma_dma_info {
+ dma_addr_t *dmaaddrs;
+};
+
+struct irdma_dma_mem {
+ void *va;
+ dma_addr_t pa;
+ u32 size;
+} __packed;
+
+struct irdma_virt_mem {
+ void *va;
+ u32 size;
+} __packed;
+
+struct irdma_sc_vsi;
+struct irdma_sc_dev;
+struct irdma_sc_qp;
+struct irdma_puda_buf;
+struct irdma_puda_cmpl_info;
+struct irdma_update_sds_info;
+struct irdma_hmc_fcn_info;
+struct irdma_manage_vf_pble_info;
+struct irdma_hw;
+struct irdma_pci_f;
+
+struct ib_device *to_ibdev(struct irdma_sc_dev *dev);
+u8 __iomem *irdma_get_hw_addr(void *dev);
+void irdma_ieq_mpa_crc_ae(struct irdma_sc_dev *dev, struct irdma_sc_qp *qp);
+enum irdma_status_code irdma_vf_wait_vchnl_resp(struct irdma_sc_dev *dev);
+bool irdma_vf_clear_to_send(struct irdma_sc_dev *dev);
+void irdma_add_dev_ref(struct irdma_sc_dev *dev);
+void irdma_put_dev_ref(struct irdma_sc_dev *dev);
+enum irdma_status_code irdma_ieq_check_mpacrc(struct shash_desc *desc,
+ void *addr, u32 len, u32 val);
+struct irdma_sc_qp *irdma_ieq_get_qp(struct irdma_sc_dev *dev,
+ struct irdma_puda_buf *buf);
+void irdma_send_ieq_ack(struct irdma_sc_qp *qp);
+void irdma_ieq_update_tcpip_info(struct irdma_puda_buf *buf, u16 len,
+ u32 seqnum);
+void irdma_free_hash_desc(struct shash_desc *hash_desc);
+enum irdma_status_code irdma_init_hash_desc(struct shash_desc **hash_desc);
+enum irdma_status_code
+irdma_puda_get_tcpip_info(struct irdma_puda_cmpl_info *info,
+ struct irdma_puda_buf *buf);
+enum irdma_status_code irdma_cqp_sds_cmd(struct irdma_sc_dev *dev,
+ struct irdma_update_sds_info *info);
+enum irdma_status_code
+irdma_cqp_manage_hmc_fcn_cmd(struct irdma_sc_dev *dev,
+ struct irdma_hmc_fcn_info *hmcfcninfo,
+ u16 *pmf_idx);
+enum irdma_status_code
+irdma_cqp_query_fpm_val_cmd(struct irdma_sc_dev *dev,
+ struct irdma_dma_mem *val_mem, u8 hmc_fn_id);
+enum irdma_status_code
+irdma_cqp_commit_fpm_val_cmd(struct irdma_sc_dev *dev,
+ struct irdma_dma_mem *val_mem, u8 hmc_fn_id);
+enum irdma_status_code irdma_alloc_query_fpm_buf(struct irdma_sc_dev *dev,
+ struct irdma_dma_mem *mem);
+void *irdma_remove_cqp_head(struct irdma_sc_dev *dev);
+void irdma_term_modify_qp(struct irdma_sc_qp *qp, u8 next_state, u8 term,
+ u8 term_len);
+void irdma_terminate_done(struct irdma_sc_qp *qp, int timeout_occurred);
+void irdma_terminate_start_timer(struct irdma_sc_qp *qp);
+void irdma_terminate_del_timer(struct irdma_sc_qp *qp);
+void irdma_hw_stats_start_timer(struct irdma_sc_vsi *vsi);
+void irdma_hw_stats_stop_timer(struct irdma_sc_vsi *vsi);
+void wr32(struct irdma_hw *hw, u32 reg, u32 val);
+u32 rd32(struct irdma_hw *hw, u32 reg);
+u64 rd64(struct irdma_hw *hw, u32 reg);
+enum irdma_status_code irdma_map_vm_page_list(struct irdma_hw *hw, void *va,
+ dma_addr_t *pg_dma, u32 pg_cnt);
+void irdma_unmap_vm_page_list(struct irdma_hw *hw, dma_addr_t *pg_dma, u32 pg_cnt);
+#endif /* IRDMA_OSDEP_H */
diff --git a/drivers/infiniband/hw/irdma/pble.c b/drivers/infiniband/hw/irdma/pble.c
new file mode 100644
index 000000000000..aeeb1c310965
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/pble.c
@@ -0,0 +1,520 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#include "osdep.h"
+#include "status.h"
+#include "hmc.h"
+#include "defs.h"
+#include "type.h"
+#include "protos.h"
+#include "pble.h"
+
+static enum irdma_status_code
+add_pble_prm(struct irdma_hmc_pble_rsrc *pble_rsrc);
+
+/**
+ * irdma_destroy_pble_prm - destroy prm during module unload
+ * @pble_rsrc: pble resources
+ */
+void irdma_destroy_pble_prm(struct irdma_hmc_pble_rsrc *pble_rsrc)
+{
+ struct irdma_chunk *chunk;
+ struct irdma_pble_prm *pinfo = &pble_rsrc->pinfo;
+
+ while (!list_empty(&pinfo->clist)) {
+ chunk = (struct irdma_chunk *) pinfo->clist.next;
+ list_del(&chunk->list);
+ if (chunk->type == PBLE_SD_PAGED)
+ irdma_pble_free_paged_mem(chunk);
+ if (chunk->bitmapbuf)
+ kfree(chunk->bitmapmem.va);
+ kfree(chunk->chunkmem.va);
+ }
+}
+
+/**
+ * irdma_hmc_init_pble - Initialize pble resources during module load
+ * @dev: irdma_sc_dev struct
+ * @pble_rsrc: pble resources
+ */
+enum irdma_status_code
+irdma_hmc_init_pble(struct irdma_sc_dev *dev,
+ struct irdma_hmc_pble_rsrc *pble_rsrc)
+{
+ struct irdma_hmc_info *hmc_info;
+ u32 fpm_idx = 0;
+ enum irdma_status_code status = 0;
+
+ hmc_info = dev->hmc_info;
+ pble_rsrc->dev = dev;
+ pble_rsrc->fpm_base_addr = hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].base;
+ /* Start pble' on 4k boundary */
+ if (pble_rsrc->fpm_base_addr & 0xfff)
+ fpm_idx = (4096 - (pble_rsrc->fpm_base_addr & 0xfff)) >> 3;
+ pble_rsrc->unallocated_pble =
+ hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt - fpm_idx;
+ pble_rsrc->next_fpm_addr = pble_rsrc->fpm_base_addr + (fpm_idx << 3);
+ pble_rsrc->pinfo.pble_shift = PBLE_SHIFT;
+
+ mutex_init(&pble_rsrc->pble_mutex_lock);
+
+ spin_lock_init(&pble_rsrc->pinfo.prm_lock);
+ INIT_LIST_HEAD(&pble_rsrc->pinfo.clist);
+ if (add_pble_prm(pble_rsrc)) {
+ irdma_destroy_pble_prm(pble_rsrc);
+ status = IRDMA_ERR_NO_MEMORY;
+ }
+
+ return status;
+}
+
+/**
+ * get_sd_pd_idx - Returns sd index, pd index and rel_pd_idx from fpm address
+ * @pble_rsrc: structure containing fpm address
+ * @idx: where to return indexes
+ */
+static void get_sd_pd_idx(struct irdma_hmc_pble_rsrc *pble_rsrc,
+ struct sd_pd_idx *idx)
+{
+ idx->sd_idx = (u32)pble_rsrc->next_fpm_addr / IRDMA_HMC_DIRECT_BP_SIZE;
+ idx->pd_idx = (u32)(pble_rsrc->next_fpm_addr / IRDMA_HMC_PAGED_BP_SIZE);
+ idx->rel_pd_idx = (idx->pd_idx % IRDMA_HMC_PD_CNT_IN_SD);
+}
+
+/**
+ * add_sd_direct - add sd direct for pble
+ * @pble_rsrc: pble resource ptr
+ * @info: page info for sd
+ */
+static enum irdma_status_code
+add_sd_direct(struct irdma_hmc_pble_rsrc *pble_rsrc,
+ struct irdma_add_page_info *info)
+{
+ struct irdma_sc_dev *dev = pble_rsrc->dev;
+ enum irdma_status_code ret_code = 0;
+ struct sd_pd_idx *idx = &info->idx;
+ struct irdma_chunk *chunk = info->chunk;
+ struct irdma_hmc_info *hmc_info = info->hmc_info;
+ struct irdma_hmc_sd_entry *sd_entry = info->sd_entry;
+ u32 offset = 0;
+
+ if (!sd_entry->valid) {
+ ret_code = irdma_add_sd_table_entry(dev->hw, hmc_info,
+ info->idx.sd_idx,
+ IRDMA_SD_TYPE_DIRECT,
+ IRDMA_HMC_DIRECT_BP_SIZE);
+ if (ret_code)
+ return ret_code;
+
+ chunk->type = PBLE_SD_CONTIGOUS;
+ }
+
+ offset = idx->rel_pd_idx << HMC_PAGED_BP_SHIFT;
+ chunk->size = info->pages << HMC_PAGED_BP_SHIFT;
+ chunk->vaddr = sd_entry->u.bp.addr.va + offset;
+ chunk->fpm_addr = pble_rsrc->next_fpm_addr;
+ ibdev_dbg(to_ibdev(dev),
+ "PBLE: chunk_size[%lld] = 0x%llx vaddr=0x%pK fpm_addr = %llx\n",
+ chunk->size, chunk->size, chunk->vaddr, chunk->fpm_addr);
+
+ return 0;
+}
+
+/**
+ * fpm_to_idx - given fpm address, get pble index
+ * @pble_rsrc: pble resource management
+ * @addr: fpm address for index
+ */
+static u32 fpm_to_idx(struct irdma_hmc_pble_rsrc *pble_rsrc, u64 addr)
+{
+ u64 idx;
+
+ idx = (addr - (pble_rsrc->fpm_base_addr)) >> 3;
+
+ return (u32)idx;
+}
+
+/**
+ * add_bp_pages - add backing pages for sd
+ * @pble_rsrc: pble resource management
+ * @info: page info for sd
+ */
+static enum irdma_status_code
+add_bp_pages(struct irdma_hmc_pble_rsrc *pble_rsrc,
+ struct irdma_add_page_info *info)
+{
+ struct irdma_sc_dev *dev = pble_rsrc->dev;
+ u8 *addr;
+ struct irdma_dma_mem mem;
+ struct irdma_hmc_pd_entry *pd_entry;
+ struct irdma_hmc_sd_entry *sd_entry = info->sd_entry;
+ struct irdma_hmc_info *hmc_info = info->hmc_info;
+ struct irdma_chunk *chunk = info->chunk;
+ enum irdma_status_code status = 0;
+ u32 rel_pd_idx = info->idx.rel_pd_idx;
+ u32 pd_idx = info->idx.pd_idx;
+ u32 i;
+
+ if (irdma_pble_get_paged_mem(chunk, info->pages))
+ return IRDMA_ERR_NO_MEMORY;
+
+ status = irdma_add_sd_table_entry(dev->hw, hmc_info, info->idx.sd_idx,
+ IRDMA_SD_TYPE_PAGED,
+ IRDMA_HMC_DIRECT_BP_SIZE);
+ if (status)
+ goto error;
+
+ addr = chunk->vaddr;
+ for (i = 0; i < info->pages; i++) {
+ mem.pa = (u64)chunk->dmainfo.dmaaddrs[i];
+ mem.size = 4096;
+ mem.va = addr;
+ pd_entry = &sd_entry->u.pd_table.pd_entry[rel_pd_idx++];
+ if (!pd_entry->valid) {
+ status = irdma_add_pd_table_entry(dev, hmc_info,
+ pd_idx++, &mem);
+ if (status)
+ goto error;
+
+ addr += 4096;
+ }
+ }
+
+ chunk->fpm_addr = pble_rsrc->next_fpm_addr;
+ return 0;
+
+error:
+ irdma_pble_free_paged_mem(chunk);
+
+ return status;
+}
+
+/**
+ * irdma_get_type - add a sd entry type for sd
+ * @dev: irdma_sc_dev struct
+ * @idx: index of sd
+ * @pages: pages in the sd
+ */
+static enum irdma_sd_entry_type irdma_get_type(struct irdma_sc_dev *dev,
+ struct sd_pd_idx *idx, u32 pages)
+{
+ enum irdma_sd_entry_type sd_entry_type;
+
+ sd_entry_type = !idx->rel_pd_idx && pages == IRDMA_HMC_PD_CNT_IN_SD ?
+ IRDMA_SD_TYPE_DIRECT : IRDMA_SD_TYPE_PAGED;
+ return sd_entry_type;
+}
+
+/**
+ * add_pble_prm - add a sd entry for pble resoure
+ * @pble_rsrc: pble resource management
+ */
+static enum irdma_status_code
+add_pble_prm(struct irdma_hmc_pble_rsrc *pble_rsrc)
+{
+ struct irdma_sc_dev *dev = pble_rsrc->dev;
+ struct irdma_hmc_sd_entry *sd_entry;
+ struct irdma_hmc_info *hmc_info;
+ struct irdma_chunk *chunk;
+ struct irdma_add_page_info info;
+ struct sd_pd_idx *idx = &info.idx;
+ enum irdma_status_code ret_code = 0;
+ enum irdma_sd_entry_type sd_entry_type;
+ u64 sd_reg_val = 0;
+ struct irdma_virt_mem chunkmem;
+ u32 pages;
+
+ if (pble_rsrc->unallocated_pble < PBLE_PER_PAGE)
+ return IRDMA_ERR_NO_MEMORY;
+
+ if (pble_rsrc->next_fpm_addr & 0xfff)
+ return IRDMA_ERR_INVALID_PAGE_DESC_INDEX;
+
+ chunkmem.size = sizeof(*chunk);
+ chunkmem.va = kzalloc(chunkmem.size, GFP_KERNEL);
+ if (!chunkmem.va)
+ return IRDMA_ERR_NO_MEMORY;
+
+ chunk = chunkmem.va;
+ chunk->chunkmem = chunkmem;
+ hmc_info = dev->hmc_info;
+ chunk->dev = dev;
+ chunk->fpm_addr = pble_rsrc->next_fpm_addr;
+ get_sd_pd_idx(pble_rsrc, idx);
+ sd_entry = &hmc_info->sd_table.sd_entry[idx->sd_idx];
+ pages = (idx->rel_pd_idx) ? (IRDMA_HMC_PD_CNT_IN_SD - idx->rel_pd_idx) :
+ IRDMA_HMC_PD_CNT_IN_SD;
+ pages = min(pages, pble_rsrc->unallocated_pble >> PBLE_512_SHIFT);
+ info.chunk = chunk;
+ info.hmc_info = hmc_info;
+ info.pages = pages;
+ info.sd_entry = sd_entry;
+ if (!sd_entry->valid)
+ sd_entry_type = irdma_get_type(dev, idx, pages);
+ else
+ sd_entry_type = sd_entry->entry_type;
+
+ ibdev_dbg(to_ibdev(dev),
+ "PBLE: pages = %d, unallocated_pble[%d] current_fpm_addr = %llx\n",
+ pages, pble_rsrc->unallocated_pble,
+ pble_rsrc->next_fpm_addr);
+ ibdev_dbg(to_ibdev(dev), "PBLE: sd_entry_type = %d\n", sd_entry_type);
+ if (sd_entry_type == IRDMA_SD_TYPE_DIRECT)
+ ret_code = add_sd_direct(pble_rsrc, &info);
+
+ if (ret_code)
+ sd_entry_type = IRDMA_SD_TYPE_PAGED;
+ else
+ pble_rsrc->stats_direct_sds++;
+
+ if (sd_entry_type == IRDMA_SD_TYPE_PAGED) {
+ ret_code = add_bp_pages(pble_rsrc, &info);
+ if (ret_code)
+ goto error;
+ else
+ pble_rsrc->stats_paged_sds++;
+ }
+
+ ret_code = irdma_prm_add_pble_mem(&pble_rsrc->pinfo, chunk);
+ if (ret_code)
+ goto error;
+
+ pble_rsrc->next_fpm_addr += chunk->size;
+ ibdev_dbg(to_ibdev(dev),
+ "PBLE: next_fpm_addr = %llx chunk_size[%llu] = 0x%llx\n",
+ pble_rsrc->next_fpm_addr, chunk->size, chunk->size);
+ pble_rsrc->unallocated_pble -= (u32)(chunk->size >> 3);
+ list_add(&chunk->list, &pble_rsrc->pinfo.clist);
+ sd_reg_val = (sd_entry_type == IRDMA_SD_TYPE_PAGED) ?
+ sd_entry->u.pd_table.pd_page_addr.pa :
+ sd_entry->u.bp.addr.pa;
+
+ if (!sd_entry->valid) {
+ ret_code = irdma_hmc_sd_one(dev, hmc_info->hmc_fn_id, sd_reg_val,
+ idx->sd_idx, sd_entry->entry_type, true);
+ if (ret_code)
+ goto error;
+ }
+
+ sd_entry->valid = true;
+ return 0;
+
+error:
+ if (chunk->bitmapbuf)
+ kfree(chunk->bitmapmem.va);
+ kfree(chunk->chunkmem.va);
+
+ return ret_code;
+}
+
+/**
+ * free_lvl2 - fee level 2 pble
+ * @pble_rsrc: pble resource management
+ * @palloc: level 2 pble allocation
+ */
+static void free_lvl2(struct irdma_hmc_pble_rsrc *pble_rsrc,
+ struct irdma_pble_alloc *palloc)
+{
+ u32 i;
+ struct irdma_pble_level2 *lvl2 = &palloc->level2;
+ struct irdma_pble_info *root = &lvl2->root;
+ struct irdma_pble_info *leaf = lvl2->leaf;
+
+ for (i = 0; i < lvl2->leaf_cnt; i++, leaf++) {
+ if (leaf->addr)
+ irdma_prm_return_pbles(&pble_rsrc->pinfo,
+ &leaf->chunkinfo);
+ else
+ break;
+ }
+
+ if (root->addr)
+ irdma_prm_return_pbles(&pble_rsrc->pinfo, &root->chunkinfo);
+
+ kfree(lvl2->leafmem.va);
+ lvl2->leaf = NULL;
+}
+
+/**
+ * get_lvl2_pble - get level 2 pble resource
+ * @pble_rsrc: pble resource management
+ * @palloc: level 2 pble allocation
+ */
+static enum irdma_status_code
+get_lvl2_pble(struct irdma_hmc_pble_rsrc *pble_rsrc,
+ struct irdma_pble_alloc *palloc)
+{
+ u32 lf4k, lflast, total, i;
+ u32 pblcnt = PBLE_PER_PAGE;
+ u64 *addr;
+ struct irdma_pble_level2 *lvl2 = &palloc->level2;
+ struct irdma_pble_info *root = &lvl2->root;
+ struct irdma_pble_info *leaf;
+ enum irdma_status_code ret_code;
+ u64 fpm_addr;
+
+ /* number of full 512 (4K) leafs) */
+ lf4k = palloc->total_cnt >> 9;
+ lflast = palloc->total_cnt % PBLE_PER_PAGE;
+ total = (lflast == 0) ? lf4k : lf4k + 1;
+ lvl2->leaf_cnt = total;
+
+ lvl2->leafmem.size = (sizeof(*leaf) * total);
+ lvl2->leafmem.va = kzalloc(lvl2->leafmem.size, GFP_KERNEL);
+ if (!lvl2->leafmem.va)
+ return IRDMA_ERR_NO_MEMORY;
+
+ lvl2->leaf = lvl2->leafmem.va;
+ leaf = lvl2->leaf;
+ ret_code = irdma_prm_get_pbles(&pble_rsrc->pinfo, &root->chunkinfo,
+ total << 3, &root->addr, &fpm_addr);
+ if (ret_code) {
+ kfree(lvl2->leafmem.va);
+ lvl2->leaf = NULL;
+ return IRDMA_ERR_NO_MEMORY;
+ }
+
+ root->idx = fpm_to_idx(pble_rsrc, fpm_addr);
+ root->cnt = total;
+ addr = root->addr;
+ for (i = 0; i < total; i++, leaf++) {
+ pblcnt = (lflast && ((i + 1) == total)) ?
+ lflast : PBLE_PER_PAGE;
+ ret_code = irdma_prm_get_pbles(&pble_rsrc->pinfo,
+ &leaf->chunkinfo, pblcnt << 3,
+ &leaf->addr, &fpm_addr);
+ if (ret_code)
+ goto error;
+
+ leaf->idx = fpm_to_idx(pble_rsrc, fpm_addr);
+
+ leaf->cnt = pblcnt;
+ *addr = (u64)leaf->idx;
+ addr++;
+ }
+
+ palloc->level = PBLE_LEVEL_2;
+ pble_rsrc->stats_lvl2++;
+ return 0;
+
+error:
+ free_lvl2(pble_rsrc, palloc);
+
+ return IRDMA_ERR_NO_MEMORY;
+}
+
+/**
+ * get_lvl1_pble - get level 1 pble resource
+ * @pble_rsrc: pble resource management
+ * @palloc: level 1 pble allocation
+ */
+static enum irdma_status_code
+get_lvl1_pble(struct irdma_hmc_pble_rsrc *pble_rsrc,
+ struct irdma_pble_alloc *palloc)
+{
+ enum irdma_status_code ret_code;
+ u64 fpm_addr;
+ struct irdma_pble_info *lvl1 = &palloc->level1;
+
+ ret_code = irdma_prm_get_pbles(&pble_rsrc->pinfo, &lvl1->chunkinfo,
+ palloc->total_cnt << 3, &lvl1->addr,
+ &fpm_addr);
+ if (ret_code)
+ return IRDMA_ERR_NO_MEMORY;
+
+ palloc->level = PBLE_LEVEL_1;
+ lvl1->idx = fpm_to_idx(pble_rsrc, fpm_addr);
+ lvl1->cnt = palloc->total_cnt;
+ pble_rsrc->stats_lvl1++;
+
+ return 0;
+}
+
+/**
+ * get_lvl1_lvl2_pble - calls get_lvl1 and get_lvl2 pble routine
+ * @pble_rsrc: pble resources
+ * @palloc: contains all inforamtion regarding pble (idx + pble addr)
+ * @level1_only: flag for a level 1 PBLE
+ */
+static enum irdma_status_code
+get_lvl1_lvl2_pble(struct irdma_hmc_pble_rsrc *pble_rsrc,
+ struct irdma_pble_alloc *palloc, bool level1_only)
+{
+ enum irdma_status_code status = 0;
+
+ status = get_lvl1_pble(pble_rsrc, palloc);
+ if (!status || level1_only || palloc->total_cnt <= PBLE_PER_PAGE)
+ return status;
+
+ status = get_lvl2_pble(pble_rsrc, palloc);
+
+ return status;
+}
+
+/**
+ * irdma_get_pble - allocate pbles from the prm
+ * @pble_rsrc: pble resources
+ * @palloc: contains all inforamtion regarding pble (idx + pble addr)
+ * @pble_cnt: #of pbles requested
+ * @level1_only: true if only pble level 1 to acquire
+ */
+enum irdma_status_code irdma_get_pble(struct irdma_hmc_pble_rsrc *pble_rsrc,
+ struct irdma_pble_alloc *palloc,
+ u32 pble_cnt, bool level1_only)
+{
+ enum irdma_status_code status = 0;
+ int max_sds = 0;
+ int i;
+
+ palloc->total_cnt = pble_cnt;
+ palloc->level = PBLE_LEVEL_0;
+
+ mutex_lock(&pble_rsrc->pble_mutex_lock);
+
+ /*check first to see if we can get pble's without acquiring
+ * additional sd's
+ */
+ status = get_lvl1_lvl2_pble(pble_rsrc, palloc, level1_only);
+ if (!status)
+ goto exit;
+
+ max_sds = (palloc->total_cnt >> 18) + 1;
+ for (i = 0; i < max_sds; i++) {
+ status = add_pble_prm(pble_rsrc);
+ if (status)
+ break;
+
+ status = get_lvl1_lvl2_pble(pble_rsrc, palloc, level1_only);
+ /* if level1_only, only go through it once */
+ if (!status || level1_only)
+ break;
+ }
+
+exit:
+ if (!status) {
+ pble_rsrc->allocdpbles += pble_cnt;
+ pble_rsrc->stats_alloc_ok++;
+ } else {
+ pble_rsrc->stats_alloc_fail++;
+ }
+ mutex_unlock(&pble_rsrc->pble_mutex_lock);
+
+ return status;
+}
+
+/**
+ * irdma_free_pble - put pbles back into prm
+ * @pble_rsrc: pble resources
+ * @palloc: contains all information regarding pble resource being freed
+ */
+void irdma_free_pble(struct irdma_hmc_pble_rsrc *pble_rsrc,
+ struct irdma_pble_alloc *palloc)
+{
+ pble_rsrc->freedpbles += palloc->total_cnt;
+
+ if (palloc->level == PBLE_LEVEL_2)
+ free_lvl2(pble_rsrc, palloc);
+ else
+ irdma_prm_return_pbles(&pble_rsrc->pinfo,
+ &palloc->level1.chunkinfo);
+ pble_rsrc->stats_alloc_freed++;
+}
diff --git a/drivers/infiniband/hw/irdma/pble.h b/drivers/infiniband/hw/irdma/pble.h
new file mode 100644
index 000000000000..e1b3b8118a2c
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/pble.h
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2015 - 2019 Intel Corporation */
+#ifndef IRDMA_PBLE_H
+#define IRDMA_PBLE_H
+
+#define PBLE_SHIFT 6
+#define PBLE_PER_PAGE 512
+#define HMC_PAGED_BP_SHIFT 12
+#define PBLE_512_SHIFT 9
+#define PBLE_INVALID_IDX 0xffffffff
+
+enum irdma_pble_level {
+ PBLE_LEVEL_0 = 0,
+ PBLE_LEVEL_1 = 1,
+ PBLE_LEVEL_2 = 2,
+};
+
+enum irdma_alloc_type {
+ PBLE_NO_ALLOC = 0,
+ PBLE_SD_CONTIGOUS = 1,
+ PBLE_SD_PAGED = 2,
+};
+
+struct irdma_chunk;
+
+struct irdma_pble_chunkinfo {
+ struct irdma_chunk *pchunk;
+ u64 bit_idx;
+ u64 bits_used;
+};
+
+struct irdma_pble_info {
+ u64 *addr;
+ u32 idx;
+ u32 cnt;
+ struct irdma_pble_chunkinfo chunkinfo;
+};
+
+struct irdma_pble_level2 {
+ struct irdma_pble_info root;
+ struct irdma_pble_info *leaf;
+ struct irdma_virt_mem leafmem;
+ u32 leaf_cnt;
+};
+
+struct irdma_pble_alloc {
+ u32 total_cnt;
+ enum irdma_pble_level level;
+ union {
+ struct irdma_pble_info level1;
+ struct irdma_pble_level2 level2;
+ };
+};
+
+struct sd_pd_idx {
+ u32 sd_idx;
+ u32 pd_idx;
+ u32 rel_pd_idx;
+};
+
+struct irdma_add_page_info {
+ struct irdma_chunk *chunk;
+ struct irdma_hmc_sd_entry *sd_entry;
+ struct irdma_hmc_info *hmc_info;
+ struct sd_pd_idx idx;
+ u32 pages;
+};
+
+struct irdma_chunk {
+ struct list_head list;
+ struct irdma_dma_info dmainfo;
+ void *bitmapbuf;
+
+ u32 sizeofbitmap;
+ u64 size;
+ void *vaddr;
+ u64 fpm_addr;
+ u32 pg_cnt;
+ enum irdma_alloc_type type;
+ struct irdma_sc_dev *dev;
+ struct irdma_virt_mem bitmapmem;
+ struct irdma_virt_mem chunkmem;
+};
+
+struct irdma_pble_prm {
+ struct list_head clist;
+ spinlock_t prm_lock; /* protect prm bitmap */
+ u64 total_pble_alloc;
+ u64 free_pble_cnt;
+ u8 pble_shift;
+};
+
+struct irdma_hmc_pble_rsrc {
+ u32 unallocated_pble;
+ struct mutex pble_mutex_lock; /* protect PBLE resource */
+ struct irdma_sc_dev *dev;
+ u64 fpm_base_addr;
+ u64 next_fpm_addr;
+ struct irdma_pble_prm pinfo;
+ u64 allocdpbles;
+ u64 freedpbles;
+ u32 stats_direct_sds;
+ u32 stats_paged_sds;
+ u64 stats_alloc_ok;
+ u64 stats_alloc_fail;
+ u64 stats_alloc_freed;
+ u64 stats_lvl1;
+ u64 stats_lvl2;
+};
+
+void irdma_destroy_pble_prm(struct irdma_hmc_pble_rsrc *pble_rsrc);
+enum irdma_status_code
+irdma_hmc_init_pble(struct irdma_sc_dev *dev,
+ struct irdma_hmc_pble_rsrc *pble_rsrc);
+void irdma_free_pble(struct irdma_hmc_pble_rsrc *pble_rsrc,
+ struct irdma_pble_alloc *palloc);
+enum irdma_status_code irdma_get_pble(struct irdma_hmc_pble_rsrc *pble_rsrc,
+ struct irdma_pble_alloc *palloc,
+ u32 pble_cnt, bool level1_only);
+enum irdma_status_code irdma_prm_add_pble_mem(struct irdma_pble_prm *pprm,
+ struct irdma_chunk *pchunk);
+enum irdma_status_code
+irdma_prm_get_pbles(struct irdma_pble_prm *pprm,
+ struct irdma_pble_chunkinfo *chunkinfo, u64 mem_size,
+ u64 **vaddr, u64 *fpm_addr);
+void irdma_prm_return_pbles(struct irdma_pble_prm *pprm,
+ struct irdma_pble_chunkinfo *chunkinfo);
+void irdma_pble_acquire_lock(struct irdma_hmc_pble_rsrc *pble_rsrc,
+ unsigned long *flags);
+void irdma_pble_release_lock(struct irdma_hmc_pble_rsrc *pble_rsrc,
+ unsigned long *flags);
+void irdma_pble_free_paged_mem(struct irdma_chunk *chunk);
+enum irdma_status_code irdma_pble_get_paged_mem(struct irdma_chunk *chunk,
+ u32 pg_cnt);
+void irdma_prm_rem_bitmapmem(struct irdma_hw *hw, struct irdma_chunk *chunk);
+#endif /* IRDMA_PBLE_H */
diff --git a/drivers/infiniband/hw/irdma/protos.h b/drivers/infiniband/hw/irdma/protos.h
new file mode 100644
index 000000000000..e3f5173706fe
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/protos.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2016 - 2021 Intel Corporation */
+#ifndef IRDMA_PROTOS_H
+#define IRDMA_PROTOS_H
+
+#define PAUSE_TIMER_VAL 0xffff
+#define REFRESH_THRESHOLD 0x7fff
+#define HIGH_THRESHOLD 0x800
+#define LOW_THRESHOLD 0x200
+#define ALL_TC2PFC 0xff
+#define CQP_COMPL_WAIT_TIME_MS 10
+#define CQP_TIMEOUT_THRESHOLD 500
+
+/* init operations */
+enum irdma_status_code irdma_sc_dev_init(enum irdma_vers ver,
+ struct irdma_sc_dev *dev,
+ struct irdma_device_init_info *info);
+void irdma_sc_rt_init(struct irdma_sc_dev *dev);
+void irdma_sc_cqp_post_sq(struct irdma_sc_cqp *cqp);
+__le64 *irdma_sc_cqp_get_next_send_wqe(struct irdma_sc_cqp *cqp, u64 scratch);
+enum irdma_status_code
+irdma_sc_mr_fast_register(struct irdma_sc_qp *qp,
+ struct irdma_fast_reg_stag_info *info, bool post_sq);
+/* HMC/FPM functions */
+enum irdma_status_code irdma_sc_init_iw_hmc(struct irdma_sc_dev *dev,
+ u8 hmc_fn_id);
+/* stats misc */
+enum irdma_status_code
+irdma_cqp_gather_stats_cmd(struct irdma_sc_dev *dev,
+ struct irdma_vsi_pestat *pestat, bool wait);
+void irdma_cqp_gather_stats_gen1(struct irdma_sc_dev *dev,
+ struct irdma_vsi_pestat *pestat);
+void irdma_hw_stats_read_all(struct irdma_vsi_pestat *stats,
+ struct irdma_dev_hw_stats *stats_values,
+ u64 *hw_stats_regs_32, u64 *hw_stats_regs_64,
+ u8 hw_rev);
+enum irdma_status_code
+irdma_cqp_ws_node_cmd(struct irdma_sc_dev *dev, u8 cmd,
+ struct irdma_ws_node_info *node_info);
+enum irdma_status_code irdma_cqp_up_map_cmd(struct irdma_sc_dev *dev, u8 cmd,
+ struct irdma_up_info *map_info);
+enum irdma_status_code irdma_cqp_ceq_cmd(struct irdma_sc_dev *dev,
+ struct irdma_sc_ceq *sc_ceq, u8 op);
+enum irdma_status_code irdma_cqp_aeq_cmd(struct irdma_sc_dev *dev,
+ struct irdma_sc_aeq *sc_aeq, u8 op);
+enum irdma_status_code
+irdma_cqp_stats_inst_cmd(struct irdma_sc_vsi *vsi, u8 cmd,
+ struct irdma_stats_inst_info *stats_info);
+u16 irdma_alloc_ws_node_id(struct irdma_sc_dev *dev);
+void irdma_free_ws_node_id(struct irdma_sc_dev *dev, u16 node_id);
+void irdma_update_stats(struct irdma_dev_hw_stats *hw_stats,
+ struct irdma_gather_stats *gather_stats,
+ struct irdma_gather_stats *last_gather_stats);
+/* vsi functions */
+enum irdma_status_code irdma_vsi_stats_init(struct irdma_sc_vsi *vsi,
+ struct irdma_vsi_stats_info *info);
+void irdma_vsi_stats_free(struct irdma_sc_vsi *vsi);
+void irdma_sc_vsi_init(struct irdma_sc_vsi *vsi,
+ struct irdma_vsi_init_info *info);
+enum irdma_status_code irdma_sc_add_cq_ctx(struct irdma_sc_ceq *ceq,
+ struct irdma_sc_cq *cq);
+void irdma_sc_remove_cq_ctx(struct irdma_sc_ceq *ceq, struct irdma_sc_cq *cq);
+/* misc L2 param change functions */
+void irdma_change_l2params(struct irdma_sc_vsi *vsi,
+ struct irdma_l2params *l2params);
+void irdma_sc_suspend_resume_qps(struct irdma_sc_vsi *vsi, u8 suspend);
+enum irdma_status_code irdma_cqp_qp_suspend_resume(struct irdma_sc_qp *qp,
+ u8 cmd);
+void irdma_qp_add_qos(struct irdma_sc_qp *qp);
+void irdma_qp_rem_qos(struct irdma_sc_qp *qp);
+struct irdma_sc_qp *irdma_get_qp_from_list(struct list_head *head,
+ struct irdma_sc_qp *qp);
+void irdma_reinitialize_ieq(struct irdma_sc_vsi *vsi);
+u16 irdma_alloc_ws_node_id(struct irdma_sc_dev *dev);
+void irdma_free_ws_node_id(struct irdma_sc_dev *dev, u16 node_id);
+/* terminate functions*/
+void irdma_terminate_send_fin(struct irdma_sc_qp *qp);
+
+void irdma_terminate_connection(struct irdma_sc_qp *qp,
+ struct irdma_aeqe_info *info);
+
+void irdma_terminate_received(struct irdma_sc_qp *qp,
+ struct irdma_aeqe_info *info);
+/* dynamic memory allocation */
+/* misc */
+u8 irdma_get_encoded_wqe_size(u32 wqsize, enum irdma_queue_type queue_type);
+void irdma_modify_qp_to_err(struct irdma_sc_qp *sc_qp);
+enum irdma_status_code
+irdma_sc_static_hmc_pages_allocated(struct irdma_sc_cqp *cqp, u64 scratch,
+ u8 hmc_fn_id, bool post_sq,
+ bool poll_registers);
+enum irdma_status_code irdma_cfg_fpm_val(struct irdma_sc_dev *dev,
+ u32 qp_count);
+enum irdma_status_code irdma_get_rdma_features(struct irdma_sc_dev *dev);
+void free_sd_mem(struct irdma_sc_dev *dev);
+enum irdma_status_code irdma_process_cqp_cmd(struct irdma_sc_dev *dev,
+ struct cqp_cmds_info *pcmdinfo);
+enum irdma_status_code irdma_process_bh(struct irdma_sc_dev *dev);
+enum irdma_status_code irdma_cqp_sds_cmd(struct irdma_sc_dev *dev,
+ struct irdma_update_sds_info *info);
+enum irdma_status_code
+irdma_cqp_query_fpm_val_cmd(struct irdma_sc_dev *dev,
+ struct irdma_dma_mem *val_mem, u8 hmc_fn_id);
+enum irdma_status_code
+irdma_cqp_commit_fpm_val_cmd(struct irdma_sc_dev *dev,
+ struct irdma_dma_mem *val_mem, u8 hmc_fn_id);
+enum irdma_status_code irdma_alloc_query_fpm_buf(struct irdma_sc_dev *dev,
+ struct irdma_dma_mem *mem);
+enum irdma_status_code
+irdma_cqp_manage_hmc_fcn_cmd(struct irdma_sc_dev *dev,
+ struct irdma_hmc_fcn_info *hmcfcninfo,
+ u16 *pmf_idx);
+void irdma_add_dev_ref(struct irdma_sc_dev *dev);
+void irdma_put_dev_ref(struct irdma_sc_dev *dev);
+void *irdma_remove_cqp_head(struct irdma_sc_dev *dev);
+#endif /* IRDMA_PROTOS_H */
diff --git a/drivers/infiniband/hw/irdma/puda.c b/drivers/infiniband/hw/irdma/puda.c
new file mode 100644
index 000000000000..58e7d875643b
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/puda.c
@@ -0,0 +1,1744 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#include "osdep.h"
+#include "status.h"
+#include "hmc.h"
+#include "defs.h"
+#include "type.h"
+#include "protos.h"
+#include "puda.h"
+#include "ws.h"
+
+static void irdma_ieq_receive(struct irdma_sc_vsi *vsi,
+ struct irdma_puda_buf *buf);
+static void irdma_ieq_tx_compl(struct irdma_sc_vsi *vsi, void *sqwrid);
+static void irdma_ilq_putback_rcvbuf(struct irdma_sc_qp *qp,
+ struct irdma_puda_buf *buf, u32 wqe_idx);
+/**
+ * irdma_puda_get_listbuf - get buffer from puda list
+ * @list: list to use for buffers (ILQ or IEQ)
+ */
+static struct irdma_puda_buf *irdma_puda_get_listbuf(struct list_head *list)
+{
+ struct irdma_puda_buf *buf = NULL;
+
+ if (!list_empty(list)) {
+ buf = (struct irdma_puda_buf *)list->next;
+ list_del((struct list_head *)&buf->list);
+ }
+
+ return buf;
+}
+
+/**
+ * irdma_puda_get_bufpool - return buffer from resource
+ * @rsrc: resource to use for buffer
+ */
+struct irdma_puda_buf *irdma_puda_get_bufpool(struct irdma_puda_rsrc *rsrc)
+{
+ struct irdma_puda_buf *buf = NULL;
+ struct list_head *list = &rsrc->bufpool;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rsrc->bufpool_lock, flags);
+ buf = irdma_puda_get_listbuf(list);
+ if (buf) {
+ rsrc->avail_buf_count--;
+ buf->vsi = rsrc->vsi;
+ } else {
+ rsrc->stats_buf_alloc_fail++;
+ }
+ spin_unlock_irqrestore(&rsrc->bufpool_lock, flags);
+
+ return buf;
+}
+
+/**
+ * irdma_puda_ret_bufpool - return buffer to rsrc list
+ * @rsrc: resource to use for buffer
+ * @buf: buffer to return to resource
+ */
+void irdma_puda_ret_bufpool(struct irdma_puda_rsrc *rsrc,
+ struct irdma_puda_buf *buf)
+{
+ unsigned long flags;
+
+ buf->do_lpb = false;
+ spin_lock_irqsave(&rsrc->bufpool_lock, flags);
+ list_add(&buf->list, &rsrc->bufpool);
+ spin_unlock_irqrestore(&rsrc->bufpool_lock, flags);
+ rsrc->avail_buf_count++;
+}
+
+/**
+ * irdma_puda_post_recvbuf - set wqe for rcv buffer
+ * @rsrc: resource ptr
+ * @wqe_idx: wqe index to use
+ * @buf: puda buffer for rcv q
+ * @initial: flag if during init time
+ */
+static void irdma_puda_post_recvbuf(struct irdma_puda_rsrc *rsrc, u32 wqe_idx,
+ struct irdma_puda_buf *buf, bool initial)
+{
+ __le64 *wqe;
+ struct irdma_sc_qp *qp = &rsrc->qp;
+ u64 offset24 = 0;
+
+ /* Synch buffer for use by device */
+ dma_sync_single_for_device(rsrc->dev->hw->device, buf->mem.pa,
+ buf->mem.size, DMA_BIDIRECTIONAL);
+ qp->qp_uk.rq_wrid_array[wqe_idx] = (uintptr_t)buf;
+ wqe = qp->qp_uk.rq_base[wqe_idx].elem;
+ if (!initial)
+ get_64bit_val(wqe, 24, &offset24);
+
+ offset24 = (offset24) ? 0 : FIELD_PREP(IRDMAQPSQ_VALID, 1);
+
+ set_64bit_val(wqe, 16, 0);
+ set_64bit_val(wqe, 0, buf->mem.pa);
+ if (qp->qp_uk.uk_attrs->hw_rev == IRDMA_GEN_1) {
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMAQPSQ_GEN1_FRAG_LEN, buf->mem.size));
+ } else {
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMAQPSQ_FRAG_LEN, buf->mem.size) |
+ offset24);
+ }
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, offset24);
+}
+
+/**
+ * irdma_puda_replenish_rq - post rcv buffers
+ * @rsrc: resource to use for buffer
+ * @initial: flag if during init time
+ */
+static enum irdma_status_code
+irdma_puda_replenish_rq(struct irdma_puda_rsrc *rsrc, bool initial)
+{
+ u32 i;
+ u32 invalid_cnt = rsrc->rxq_invalid_cnt;
+ struct irdma_puda_buf *buf = NULL;
+
+ for (i = 0; i < invalid_cnt; i++) {
+ buf = irdma_puda_get_bufpool(rsrc);
+ if (!buf)
+ return IRDMA_ERR_list_empty;
+ irdma_puda_post_recvbuf(rsrc, rsrc->rx_wqe_idx, buf, initial);
+ rsrc->rx_wqe_idx = ((rsrc->rx_wqe_idx + 1) % rsrc->rq_size);
+ rsrc->rxq_invalid_cnt--;
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_puda_alloc_buf - allocate mem for buffer
+ * @dev: iwarp device
+ * @len: length of buffer
+ */
+static struct irdma_puda_buf *irdma_puda_alloc_buf(struct irdma_sc_dev *dev,
+ u32 len)
+{
+ struct irdma_puda_buf *buf;
+ struct irdma_virt_mem buf_mem;
+
+ buf_mem.size = sizeof(struct irdma_puda_buf);
+ buf_mem.va = kzalloc(buf_mem.size, GFP_KERNEL);
+ if (!buf_mem.va)
+ return NULL;
+
+ buf = buf_mem.va;
+ buf->mem.size = len;
+ buf->mem.va = kzalloc(buf->mem.size, GFP_KERNEL);
+ if (!buf->mem.va)
+ goto free_virt;
+ buf->mem.pa = dma_map_single(dev->hw->device, buf->mem.va,
+ buf->mem.size, DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(dev->hw->device, buf->mem.pa)) {
+ kfree(buf->mem.va);
+ goto free_virt;
+ }
+
+ buf->buf_mem.va = buf_mem.va;
+ buf->buf_mem.size = buf_mem.size;
+
+ return buf;
+
+free_virt:
+ kfree(buf_mem.va);
+ return NULL;
+}
+
+/**
+ * irdma_puda_dele_buf - delete buffer back to system
+ * @dev: iwarp device
+ * @buf: buffer to free
+ */
+static void irdma_puda_dele_buf(struct irdma_sc_dev *dev,
+ struct irdma_puda_buf *buf)
+{
+ dma_unmap_single(dev->hw->device, buf->mem.pa, buf->mem.size,
+ DMA_BIDIRECTIONAL);
+ kfree(buf->mem.va);
+ kfree(buf->buf_mem.va);
+}
+
+/**
+ * irdma_puda_get_next_send_wqe - return next wqe for processing
+ * @qp: puda qp for wqe
+ * @wqe_idx: wqe index for caller
+ */
+static __le64 *irdma_puda_get_next_send_wqe(struct irdma_qp_uk *qp,
+ u32 *wqe_idx)
+{
+ __le64 *wqe = NULL;
+ enum irdma_status_code ret_code = 0;
+
+ *wqe_idx = IRDMA_RING_CURRENT_HEAD(qp->sq_ring);
+ if (!*wqe_idx)
+ qp->swqe_polarity = !qp->swqe_polarity;
+ IRDMA_RING_MOVE_HEAD(qp->sq_ring, ret_code);
+ if (ret_code)
+ return wqe;
+
+ wqe = qp->sq_base[*wqe_idx].elem;
+
+ return wqe;
+}
+
+/**
+ * irdma_puda_poll_info - poll cq for completion
+ * @cq: cq for poll
+ * @info: info return for successful completion
+ */
+static enum irdma_status_code
+irdma_puda_poll_info(struct irdma_sc_cq *cq, struct irdma_puda_cmpl_info *info)
+{
+ struct irdma_cq_uk *cq_uk = &cq->cq_uk;
+ u64 qword0, qword2, qword3, qword6;
+ __le64 *cqe;
+ __le64 *ext_cqe = NULL;
+ u64 qword7 = 0;
+ u64 comp_ctx;
+ bool valid_bit;
+ bool ext_valid = 0;
+ u32 major_err, minor_err;
+ u32 peek_head;
+ bool error;
+ u8 polarity;
+
+ cqe = IRDMA_GET_CURRENT_CQ_ELEM(&cq->cq_uk);
+ get_64bit_val(cqe, 24, &qword3);
+ valid_bit = (bool)FIELD_GET(IRDMA_CQ_VALID, qword3);
+ if (valid_bit != cq_uk->polarity)
+ return IRDMA_ERR_Q_EMPTY;
+
+ if (cq->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2)
+ ext_valid = (bool)FIELD_GET(IRDMA_CQ_EXTCQE, qword3);
+
+ if (ext_valid) {
+ peek_head = (cq_uk->cq_ring.head + 1) % cq_uk->cq_ring.size;
+ ext_cqe = cq_uk->cq_base[peek_head].buf;
+ get_64bit_val(ext_cqe, 24, &qword7);
+ polarity = (u8)FIELD_GET(IRDMA_CQ_VALID, qword7);
+ if (!peek_head)
+ polarity ^= 1;
+ if (polarity != cq_uk->polarity)
+ return IRDMA_ERR_Q_EMPTY;
+
+ IRDMA_RING_MOVE_HEAD_NOCHECK(cq_uk->cq_ring);
+ if (!IRDMA_RING_CURRENT_HEAD(cq_uk->cq_ring))
+ cq_uk->polarity = !cq_uk->polarity;
+ /* update cq tail in cq shadow memory also */
+ IRDMA_RING_MOVE_TAIL(cq_uk->cq_ring);
+ }
+
+ print_hex_dump_debug("PUDA: PUDA CQE", DUMP_PREFIX_OFFSET, 16, 8, cqe,
+ 32, false);
+ if (ext_valid)
+ print_hex_dump_debug("PUDA: PUDA EXT-CQE", DUMP_PREFIX_OFFSET,
+ 16, 8, ext_cqe, 32, false);
+
+ error = (bool)FIELD_GET(IRDMA_CQ_ERROR, qword3);
+ if (error) {
+ ibdev_dbg(to_ibdev(cq->dev), "PUDA: receive error\n");
+ major_err = (u32)(FIELD_GET(IRDMA_CQ_MAJERR, qword3));
+ minor_err = (u32)(FIELD_GET(IRDMA_CQ_MINERR, qword3));
+ info->compl_error = major_err << 16 | minor_err;
+ return IRDMA_ERR_CQ_COMPL_ERROR;
+ }
+
+ get_64bit_val(cqe, 0, &qword0);
+ get_64bit_val(cqe, 16, &qword2);
+
+ info->q_type = (u8)FIELD_GET(IRDMA_CQ_SQ, qword3);
+ info->qp_id = (u32)FIELD_GET(IRDMACQ_QPID, qword2);
+ if (cq->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2)
+ info->ipv4 = (bool)FIELD_GET(IRDMACQ_IPV4, qword3);
+
+ get_64bit_val(cqe, 8, &comp_ctx);
+ info->qp = (struct irdma_qp_uk *)(unsigned long)comp_ctx;
+ info->wqe_idx = (u32)FIELD_GET(IRDMA_CQ_WQEIDX, qword3);
+
+ if (info->q_type == IRDMA_CQE_QTYPE_RQ) {
+ if (ext_valid) {
+ info->vlan_valid = (bool)FIELD_GET(IRDMA_CQ_UDVLANVALID, qword7);
+ if (info->vlan_valid) {
+ get_64bit_val(ext_cqe, 16, &qword6);
+ info->vlan = (u16)FIELD_GET(IRDMA_CQ_UDVLAN, qword6);
+ }
+ info->smac_valid = (bool)FIELD_GET(IRDMA_CQ_UDSMACVALID, qword7);
+ if (info->smac_valid) {
+ get_64bit_val(ext_cqe, 16, &qword6);
+ info->smac[0] = (u8)((qword6 >> 40) & 0xFF);
+ info->smac[1] = (u8)((qword6 >> 32) & 0xFF);
+ info->smac[2] = (u8)((qword6 >> 24) & 0xFF);
+ info->smac[3] = (u8)((qword6 >> 16) & 0xFF);
+ info->smac[4] = (u8)((qword6 >> 8) & 0xFF);
+ info->smac[5] = (u8)(qword6 & 0xFF);
+ }
+ }
+
+ if (cq->dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1) {
+ info->vlan_valid = (bool)FIELD_GET(IRDMA_VLAN_TAG_VALID, qword3);
+ info->l4proto = (u8)FIELD_GET(IRDMA_UDA_L4PROTO, qword2);
+ info->l3proto = (u8)FIELD_GET(IRDMA_UDA_L3PROTO, qword2);
+ }
+
+ info->payload_len = (u32)FIELD_GET(IRDMACQ_PAYLDLEN, qword0);
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_puda_poll_cmpl - processes completion for cq
+ * @dev: iwarp device
+ * @cq: cq getting interrupt
+ * @compl_err: return any completion err
+ */
+enum irdma_status_code irdma_puda_poll_cmpl(struct irdma_sc_dev *dev,
+ struct irdma_sc_cq *cq,
+ u32 *compl_err)
+{
+ struct irdma_qp_uk *qp;
+ struct irdma_cq_uk *cq_uk = &cq->cq_uk;
+ struct irdma_puda_cmpl_info info = {};
+ enum irdma_status_code ret = 0;
+ struct irdma_puda_buf *buf;
+ struct irdma_puda_rsrc *rsrc;
+ u8 cq_type = cq->cq_type;
+ unsigned long flags;
+
+ if (cq_type == IRDMA_CQ_TYPE_ILQ || cq_type == IRDMA_CQ_TYPE_IEQ) {
+ rsrc = (cq_type == IRDMA_CQ_TYPE_ILQ) ? cq->vsi->ilq :
+ cq->vsi->ieq;
+ } else {
+ ibdev_dbg(to_ibdev(dev), "PUDA: qp_type error\n");
+ return IRDMA_ERR_BAD_PTR;
+ }
+
+ ret = irdma_puda_poll_info(cq, &info);
+ *compl_err = info.compl_error;
+ if (ret == IRDMA_ERR_Q_EMPTY)
+ return ret;
+ if (ret)
+ goto done;
+
+ qp = info.qp;
+ if (!qp || !rsrc) {
+ ret = IRDMA_ERR_BAD_PTR;
+ goto done;
+ }
+
+ if (qp->qp_id != rsrc->qp_id) {
+ ret = IRDMA_ERR_BAD_PTR;
+ goto done;
+ }
+
+ if (info.q_type == IRDMA_CQE_QTYPE_RQ) {
+ buf = (struct irdma_puda_buf *)(uintptr_t)
+ qp->rq_wrid_array[info.wqe_idx];
+
+ /* reusing so synch the buffer for CPU use */
+ dma_sync_single_for_cpu(dev->hw->device, buf->mem.pa,
+ buf->mem.size, DMA_BIDIRECTIONAL);
+ /* Get all the tcpip information in the buf header */
+ ret = irdma_puda_get_tcpip_info(&info, buf);
+ if (ret) {
+ rsrc->stats_rcvd_pkt_err++;
+ if (cq_type == IRDMA_CQ_TYPE_ILQ) {
+ irdma_ilq_putback_rcvbuf(&rsrc->qp, buf,
+ info.wqe_idx);
+ } else {
+ irdma_puda_ret_bufpool(rsrc, buf);
+ irdma_puda_replenish_rq(rsrc, false);
+ }
+ goto done;
+ }
+
+ rsrc->stats_pkt_rcvd++;
+ rsrc->compl_rxwqe_idx = info.wqe_idx;
+ ibdev_dbg(to_ibdev(dev), "PUDA: RQ completion\n");
+ rsrc->receive(rsrc->vsi, buf);
+ if (cq_type == IRDMA_CQ_TYPE_ILQ)
+ irdma_ilq_putback_rcvbuf(&rsrc->qp, buf, info.wqe_idx);
+ else
+ irdma_puda_replenish_rq(rsrc, false);
+
+ } else {
+ ibdev_dbg(to_ibdev(dev), "PUDA: SQ completion\n");
+ buf = (struct irdma_puda_buf *)(uintptr_t)
+ qp->sq_wrtrk_array[info.wqe_idx].wrid;
+
+ /* reusing so synch the buffer for CPU use */
+ dma_sync_single_for_cpu(dev->hw->device, buf->mem.pa,
+ buf->mem.size, DMA_BIDIRECTIONAL);
+ IRDMA_RING_SET_TAIL(qp->sq_ring, info.wqe_idx);
+ rsrc->xmit_complete(rsrc->vsi, buf);
+ spin_lock_irqsave(&rsrc->bufpool_lock, flags);
+ rsrc->tx_wqe_avail_cnt++;
+ spin_unlock_irqrestore(&rsrc->bufpool_lock, flags);
+ if (!list_empty(&rsrc->txpend))
+ irdma_puda_send_buf(rsrc, NULL);
+ }
+
+done:
+ IRDMA_RING_MOVE_HEAD_NOCHECK(cq_uk->cq_ring);
+ if (!IRDMA_RING_CURRENT_HEAD(cq_uk->cq_ring))
+ cq_uk->polarity = !cq_uk->polarity;
+ /* update cq tail in cq shadow memory also */
+ IRDMA_RING_MOVE_TAIL(cq_uk->cq_ring);
+ set_64bit_val(cq_uk->shadow_area, 0,
+ IRDMA_RING_CURRENT_HEAD(cq_uk->cq_ring));
+
+ return ret;
+}
+
+/**
+ * irdma_puda_send - complete send wqe for transmit
+ * @qp: puda qp for send
+ * @info: buffer information for transmit
+ */
+enum irdma_status_code irdma_puda_send(struct irdma_sc_qp *qp,
+ struct irdma_puda_send_info *info)
+{
+ __le64 *wqe;
+ u32 iplen, l4len;
+ u64 hdr[2];
+ u32 wqe_idx;
+ u8 iipt;
+
+ /* number of 32 bits DWORDS in header */
+ l4len = info->tcplen >> 2;
+ if (info->ipv4) {
+ iipt = 3;
+ iplen = 5;
+ } else {
+ iipt = 1;
+ iplen = 10;
+ }
+
+ wqe = irdma_puda_get_next_send_wqe(&qp->qp_uk, &wqe_idx);
+ if (!wqe)
+ return IRDMA_ERR_QP_TOOMANY_WRS_POSTED;
+
+ qp->qp_uk.sq_wrtrk_array[wqe_idx].wrid = (uintptr_t)info->scratch;
+ /* Third line of WQE descriptor */
+ /* maclen is in words */
+
+ if (qp->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
+ hdr[0] = 0; /* Dest_QPN and Dest_QKey only for UD */
+ hdr[1] = FIELD_PREP(IRDMA_UDA_QPSQ_OPCODE, IRDMA_OP_TYPE_SEND) |
+ FIELD_PREP(IRDMA_UDA_QPSQ_L4LEN, l4len) |
+ FIELD_PREP(IRDMAQPSQ_AHID, info->ah_id) |
+ FIELD_PREP(IRDMA_UDA_QPSQ_SIGCOMPL, 1) |
+ FIELD_PREP(IRDMA_UDA_QPSQ_VALID,
+ qp->qp_uk.swqe_polarity);
+
+ /* Forth line of WQE descriptor */
+
+ set_64bit_val(wqe, 0, info->paddr);
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMAQPSQ_FRAG_LEN, info->len) |
+ FIELD_PREP(IRDMA_UDA_QPSQ_VALID, qp->qp_uk.swqe_polarity));
+ } else {
+ hdr[0] = FIELD_PREP(IRDMA_UDA_QPSQ_MACLEN, info->maclen >> 1) |
+ FIELD_PREP(IRDMA_UDA_QPSQ_IPLEN, iplen) |
+ FIELD_PREP(IRDMA_UDA_QPSQ_L4T, 1) |
+ FIELD_PREP(IRDMA_UDA_QPSQ_IIPT, iipt) |
+ FIELD_PREP(IRDMA_GEN1_UDA_QPSQ_L4LEN, l4len);
+
+ hdr[1] = FIELD_PREP(IRDMA_UDA_QPSQ_OPCODE, IRDMA_OP_TYPE_SEND) |
+ FIELD_PREP(IRDMA_UDA_QPSQ_SIGCOMPL, 1) |
+ FIELD_PREP(IRDMA_UDA_QPSQ_DOLOOPBACK, info->do_lpb) |
+ FIELD_PREP(IRDMA_UDA_QPSQ_VALID, qp->qp_uk.swqe_polarity);
+
+ /* Forth line of WQE descriptor */
+
+ set_64bit_val(wqe, 0, info->paddr);
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMAQPSQ_GEN1_FRAG_LEN, info->len));
+ }
+
+ set_64bit_val(wqe, 16, hdr[0]);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr[1]);
+
+ print_hex_dump_debug("PUDA: PUDA SEND WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, 32, false);
+ irdma_uk_qp_post_wr(&qp->qp_uk);
+ return 0;
+}
+
+/**
+ * irdma_puda_send_buf - transmit puda buffer
+ * @rsrc: resource to use for buffer
+ * @buf: puda buffer to transmit
+ */
+void irdma_puda_send_buf(struct irdma_puda_rsrc *rsrc,
+ struct irdma_puda_buf *buf)
+{
+ struct irdma_puda_send_info info;
+ enum irdma_status_code ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rsrc->bufpool_lock, flags);
+ /* if no wqe available or not from a completion and we have
+ * pending buffers, we must queue new buffer
+ */
+ if (!rsrc->tx_wqe_avail_cnt || (buf && !list_empty(&rsrc->txpend))) {
+ list_add_tail(&buf->list, &rsrc->txpend);
+ spin_unlock_irqrestore(&rsrc->bufpool_lock, flags);
+ rsrc->stats_sent_pkt_q++;
+ if (rsrc->type == IRDMA_PUDA_RSRC_TYPE_ILQ)
+ ibdev_dbg(to_ibdev(rsrc->dev),
+ "PUDA: adding to txpend\n");
+ return;
+ }
+ rsrc->tx_wqe_avail_cnt--;
+ /* if we are coming from a completion and have pending buffers
+ * then Get one from pending list
+ */
+ if (!buf) {
+ buf = irdma_puda_get_listbuf(&rsrc->txpend);
+ if (!buf)
+ goto done;
+ }
+
+ info.scratch = buf;
+ info.paddr = buf->mem.pa;
+ info.len = buf->totallen;
+ info.tcplen = buf->tcphlen;
+ info.ipv4 = buf->ipv4;
+
+ if (rsrc->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
+ info.ah_id = buf->ah_id;
+ } else {
+ info.maclen = buf->maclen;
+ info.do_lpb = buf->do_lpb;
+ }
+
+ /* Synch buffer for use by device */
+ dma_sync_single_for_cpu(rsrc->dev->hw->device, buf->mem.pa,
+ buf->mem.size, DMA_BIDIRECTIONAL);
+ ret = irdma_puda_send(&rsrc->qp, &info);
+ if (ret) {
+ rsrc->tx_wqe_avail_cnt++;
+ rsrc->stats_sent_pkt_q++;
+ list_add(&buf->list, &rsrc->txpend);
+ if (rsrc->type == IRDMA_PUDA_RSRC_TYPE_ILQ)
+ ibdev_dbg(to_ibdev(rsrc->dev),
+ "PUDA: adding to puda_send\n");
+ } else {
+ rsrc->stats_pkt_sent++;
+ }
+done:
+ spin_unlock_irqrestore(&rsrc->bufpool_lock, flags);
+}
+
+/**
+ * irdma_puda_qp_setctx - during init, set qp's context
+ * @rsrc: qp's resource
+ */
+static void irdma_puda_qp_setctx(struct irdma_puda_rsrc *rsrc)
+{
+ struct irdma_sc_qp *qp = &rsrc->qp;
+ __le64 *qp_ctx = qp->hw_host_ctx;
+
+ set_64bit_val(qp_ctx, 8, qp->sq_pa);
+ set_64bit_val(qp_ctx, 16, qp->rq_pa);
+ set_64bit_val(qp_ctx, 24,
+ FIELD_PREP(IRDMAQPC_RQSIZE, qp->hw_rq_size) |
+ FIELD_PREP(IRDMAQPC_SQSIZE, qp->hw_sq_size));
+ set_64bit_val(qp_ctx, 48,
+ FIELD_PREP(IRDMAQPC_SNDMSS, rsrc->buf_size));
+ set_64bit_val(qp_ctx, 56, 0);
+ if (qp->dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1)
+ set_64bit_val(qp_ctx, 64, 1);
+ set_64bit_val(qp_ctx, 136,
+ FIELD_PREP(IRDMAQPC_TXCQNUM, rsrc->cq_id) |
+ FIELD_PREP(IRDMAQPC_RXCQNUM, rsrc->cq_id));
+ set_64bit_val(qp_ctx, 144,
+ FIELD_PREP(IRDMAQPC_STAT_INDEX, rsrc->stats_idx));
+ set_64bit_val(qp_ctx, 160,
+ FIELD_PREP(IRDMAQPC_PRIVEN, 1) |
+ FIELD_PREP(IRDMAQPC_USESTATSINSTANCE, rsrc->stats_idx_valid));
+ set_64bit_val(qp_ctx, 168,
+ FIELD_PREP(IRDMAQPC_QPCOMPCTX, (uintptr_t)qp));
+ set_64bit_val(qp_ctx, 176,
+ FIELD_PREP(IRDMAQPC_SQTPHVAL, qp->sq_tph_val) |
+ FIELD_PREP(IRDMAQPC_RQTPHVAL, qp->rq_tph_val) |
+ FIELD_PREP(IRDMAQPC_QSHANDLE, qp->qs_handle));
+
+ print_hex_dump_debug("PUDA: PUDA QP CONTEXT", DUMP_PREFIX_OFFSET, 16,
+ 8, qp_ctx, IRDMA_QP_CTX_SIZE, false);
+}
+
+/**
+ * irdma_puda_qp_wqe - setup wqe for qp create
+ * @dev: Device
+ * @qp: Resource qp
+ */
+static enum irdma_status_code irdma_puda_qp_wqe(struct irdma_sc_dev *dev,
+ struct irdma_sc_qp *qp)
+{
+ struct irdma_sc_cqp *cqp;
+ __le64 *wqe;
+ u64 hdr;
+ struct irdma_ccq_cqe_info compl_info;
+ enum irdma_status_code status = 0;
+
+ cqp = dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, 0);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 16, qp->hw_host_ctx_pa);
+ set_64bit_val(wqe, 40, qp->shadow_area_pa);
+
+ hdr = qp->qp_uk.qp_id |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_CREATE_QP) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_QPTYPE, IRDMA_QP_TYPE_UDA) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_CQNUMVALID, 1) |
+ FIELD_PREP(IRDMA_CQPSQ_QP_NEXTIWSTATE, 2) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("PUDA: PUDA QP CREATE", DUMP_PREFIX_OFFSET, 16,
+ 8, wqe, 40, false);
+ irdma_sc_cqp_post_sq(cqp);
+ status = irdma_sc_poll_for_cqp_op_done(dev->cqp, IRDMA_CQP_OP_CREATE_QP,
+ &compl_info);
+
+ return status;
+}
+
+/**
+ * irdma_puda_qp_create - create qp for resource
+ * @rsrc: resource to use for buffer
+ */
+static enum irdma_status_code irdma_puda_qp_create(struct irdma_puda_rsrc *rsrc)
+{
+ struct irdma_sc_qp *qp = &rsrc->qp;
+ struct irdma_qp_uk *ukqp = &qp->qp_uk;
+ enum irdma_status_code ret = 0;
+ u32 sq_size, rq_size;
+ struct irdma_dma_mem *mem;
+
+ sq_size = rsrc->sq_size * IRDMA_QP_WQE_MIN_SIZE;
+ rq_size = rsrc->rq_size * IRDMA_QP_WQE_MIN_SIZE;
+ rsrc->qpmem.size = ALIGN((sq_size + rq_size + (IRDMA_SHADOW_AREA_SIZE << 3) + IRDMA_QP_CTX_SIZE),
+ IRDMA_HW_PAGE_SIZE);
+ rsrc->qpmem.va = dma_alloc_coherent(rsrc->dev->hw->device,
+ rsrc->qpmem.size, &rsrc->qpmem.pa,
+ GFP_KERNEL);
+ if (!rsrc->qpmem.va)
+ return IRDMA_ERR_NO_MEMORY;
+
+ mem = &rsrc->qpmem;
+ memset(mem->va, 0, rsrc->qpmem.size);
+ qp->hw_sq_size = irdma_get_encoded_wqe_size(rsrc->sq_size, IRDMA_QUEUE_TYPE_SQ_RQ);
+ qp->hw_rq_size = irdma_get_encoded_wqe_size(rsrc->rq_size, IRDMA_QUEUE_TYPE_SQ_RQ);
+ qp->pd = &rsrc->sc_pd;
+ qp->qp_uk.qp_type = IRDMA_QP_TYPE_UDA;
+ qp->dev = rsrc->dev;
+ qp->qp_uk.back_qp = rsrc;
+ qp->sq_pa = mem->pa;
+ qp->rq_pa = qp->sq_pa + sq_size;
+ qp->vsi = rsrc->vsi;
+ ukqp->sq_base = mem->va;
+ ukqp->rq_base = &ukqp->sq_base[rsrc->sq_size];
+ ukqp->shadow_area = ukqp->rq_base[rsrc->rq_size].elem;
+ ukqp->uk_attrs = &qp->dev->hw_attrs.uk_attrs;
+ qp->shadow_area_pa = qp->rq_pa + rq_size;
+ qp->hw_host_ctx = ukqp->shadow_area + IRDMA_SHADOW_AREA_SIZE;
+ qp->hw_host_ctx_pa = qp->shadow_area_pa + (IRDMA_SHADOW_AREA_SIZE << 3);
+ qp->push_idx = IRDMA_INVALID_PUSH_PAGE_INDEX;
+ ukqp->qp_id = rsrc->qp_id;
+ ukqp->sq_wrtrk_array = rsrc->sq_wrtrk_array;
+ ukqp->rq_wrid_array = rsrc->rq_wrid_array;
+ ukqp->sq_size = rsrc->sq_size;
+ ukqp->rq_size = rsrc->rq_size;
+
+ IRDMA_RING_INIT(ukqp->sq_ring, ukqp->sq_size);
+ IRDMA_RING_INIT(ukqp->initial_ring, ukqp->sq_size);
+ IRDMA_RING_INIT(ukqp->rq_ring, ukqp->rq_size);
+ ukqp->wqe_alloc_db = qp->pd->dev->wqe_alloc_db;
+
+ ret = rsrc->dev->ws_add(qp->vsi, qp->user_pri);
+ if (ret) {
+ dma_free_coherent(rsrc->dev->hw->device, rsrc->qpmem.size,
+ rsrc->qpmem.va, rsrc->qpmem.pa);
+ rsrc->qpmem.va = NULL;
+ return ret;
+ }
+
+ irdma_qp_add_qos(qp);
+ irdma_puda_qp_setctx(rsrc);
+
+ if (rsrc->dev->ceq_valid)
+ ret = irdma_cqp_qp_create_cmd(rsrc->dev, qp);
+ else
+ ret = irdma_puda_qp_wqe(rsrc->dev, qp);
+ if (ret) {
+ irdma_qp_rem_qos(qp);
+ rsrc->dev->ws_remove(qp->vsi, qp->user_pri);
+ dma_free_coherent(rsrc->dev->hw->device, rsrc->qpmem.size,
+ rsrc->qpmem.va, rsrc->qpmem.pa);
+ rsrc->qpmem.va = NULL;
+ }
+
+ return ret;
+}
+
+/**
+ * irdma_puda_cq_wqe - setup wqe for CQ create
+ * @dev: Device
+ * @cq: resource for cq
+ */
+static enum irdma_status_code irdma_puda_cq_wqe(struct irdma_sc_dev *dev,
+ struct irdma_sc_cq *cq)
+{
+ __le64 *wqe;
+ struct irdma_sc_cqp *cqp;
+ u64 hdr;
+ struct irdma_ccq_cqe_info compl_info;
+ enum irdma_status_code status = 0;
+
+ cqp = dev->cqp;
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, 0);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 0, cq->cq_uk.cq_size);
+ set_64bit_val(wqe, 8, (uintptr_t)cq >> 1);
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMA_CQPSQ_CQ_SHADOW_READ_THRESHOLD, cq->shadow_read_threshold));
+ set_64bit_val(wqe, 32, cq->cq_pa);
+ set_64bit_val(wqe, 40, cq->shadow_area_pa);
+ set_64bit_val(wqe, 56,
+ FIELD_PREP(IRDMA_CQPSQ_TPHVAL, cq->tph_val) |
+ FIELD_PREP(IRDMA_CQPSQ_VSIIDX, cq->vsi->vsi_idx));
+
+ hdr = cq->cq_uk.cq_id |
+ FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_CREATE_CQ) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_CHKOVERFLOW, 1) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_ENCEQEMASK, 1) |
+ FIELD_PREP(IRDMA_CQPSQ_CQ_CEQIDVALID, 1) |
+ FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ print_hex_dump_debug("PUDA: PUDA CREATE CQ", DUMP_PREFIX_OFFSET, 16,
+ 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ irdma_sc_cqp_post_sq(dev->cqp);
+ status = irdma_sc_poll_for_cqp_op_done(dev->cqp, IRDMA_CQP_OP_CREATE_CQ,
+ &compl_info);
+ if (!status) {
+ struct irdma_sc_ceq *ceq = dev->ceq[0];
+
+ if (ceq && ceq->reg_cq)
+ status = irdma_sc_add_cq_ctx(ceq, cq);
+ }
+
+ return status;
+}
+
+/**
+ * irdma_puda_cq_create - create cq for resource
+ * @rsrc: resource for which cq to create
+ */
+static enum irdma_status_code irdma_puda_cq_create(struct irdma_puda_rsrc *rsrc)
+{
+ struct irdma_sc_dev *dev = rsrc->dev;
+ struct irdma_sc_cq *cq = &rsrc->cq;
+ enum irdma_status_code ret = 0;
+ u32 cqsize;
+ struct irdma_dma_mem *mem;
+ struct irdma_cq_init_info info = {};
+ struct irdma_cq_uk_init_info *init_info = &info.cq_uk_init_info;
+
+ cq->vsi = rsrc->vsi;
+ cqsize = rsrc->cq_size * (sizeof(struct irdma_cqe));
+ rsrc->cqmem.size = ALIGN(cqsize + sizeof(struct irdma_cq_shadow_area),
+ IRDMA_CQ0_ALIGNMENT);
+ rsrc->cqmem.va = dma_alloc_coherent(dev->hw->device, rsrc->cqmem.size,
+ &rsrc->cqmem.pa, GFP_KERNEL);
+ if (!rsrc->cqmem.va)
+ return IRDMA_ERR_NO_MEMORY;
+
+ mem = &rsrc->cqmem;
+ info.dev = dev;
+ info.type = (rsrc->type == IRDMA_PUDA_RSRC_TYPE_ILQ) ?
+ IRDMA_CQ_TYPE_ILQ : IRDMA_CQ_TYPE_IEQ;
+ info.shadow_read_threshold = rsrc->cq_size >> 2;
+ info.cq_base_pa = mem->pa;
+ info.shadow_area_pa = mem->pa + cqsize;
+ init_info->cq_base = mem->va;
+ init_info->shadow_area = (__le64 *)((u8 *)mem->va + cqsize);
+ init_info->cq_size = rsrc->cq_size;
+ init_info->cq_id = rsrc->cq_id;
+ info.ceqe_mask = true;
+ info.ceq_id_valid = true;
+ info.vsi = rsrc->vsi;
+
+ ret = irdma_sc_cq_init(cq, &info);
+ if (ret)
+ goto error;
+
+ if (rsrc->dev->ceq_valid)
+ ret = irdma_cqp_cq_create_cmd(dev, cq);
+ else
+ ret = irdma_puda_cq_wqe(dev, cq);
+error:
+ if (ret) {
+ dma_free_coherent(dev->hw->device, rsrc->cqmem.size,
+ rsrc->cqmem.va, rsrc->cqmem.pa);
+ rsrc->cqmem.va = NULL;
+ }
+
+ return ret;
+}
+
+/**
+ * irdma_puda_free_qp - free qp for resource
+ * @rsrc: resource for which qp to free
+ */
+static void irdma_puda_free_qp(struct irdma_puda_rsrc *rsrc)
+{
+ enum irdma_status_code ret;
+ struct irdma_ccq_cqe_info compl_info;
+ struct irdma_sc_dev *dev = rsrc->dev;
+
+ if (rsrc->dev->ceq_valid) {
+ irdma_cqp_qp_destroy_cmd(dev, &rsrc->qp);
+ rsrc->dev->ws_remove(rsrc->qp.vsi, rsrc->qp.user_pri);
+ return;
+ }
+
+ ret = irdma_sc_qp_destroy(&rsrc->qp, 0, false, true, true);
+ if (ret)
+ ibdev_dbg(to_ibdev(dev),
+ "PUDA: error puda qp destroy wqe, status = %d\n",
+ ret);
+ if (!ret) {
+ ret = irdma_sc_poll_for_cqp_op_done(dev->cqp, IRDMA_CQP_OP_DESTROY_QP,
+ &compl_info);
+ if (ret)
+ ibdev_dbg(to_ibdev(dev),
+ "PUDA: error puda qp destroy failed, status = %d\n",
+ ret);
+ }
+ rsrc->dev->ws_remove(rsrc->qp.vsi, rsrc->qp.user_pri);
+}
+
+/**
+ * irdma_puda_free_cq - free cq for resource
+ * @rsrc: resource for which cq to free
+ */
+static void irdma_puda_free_cq(struct irdma_puda_rsrc *rsrc)
+{
+ enum irdma_status_code ret;
+ struct irdma_ccq_cqe_info compl_info;
+ struct irdma_sc_dev *dev = rsrc->dev;
+
+ if (rsrc->dev->ceq_valid) {
+ irdma_cqp_cq_destroy_cmd(dev, &rsrc->cq);
+ return;
+ }
+
+ ret = irdma_sc_cq_destroy(&rsrc->cq, 0, true);
+ if (ret)
+ ibdev_dbg(to_ibdev(dev), "PUDA: error ieq cq destroy\n");
+ if (!ret) {
+ ret = irdma_sc_poll_for_cqp_op_done(dev->cqp, IRDMA_CQP_OP_DESTROY_CQ,
+ &compl_info);
+ if (ret)
+ ibdev_dbg(to_ibdev(dev),
+ "PUDA: error ieq qp destroy done\n");
+ }
+}
+
+/**
+ * irdma_puda_dele_rsrc - delete all resources during close
+ * @vsi: VSI structure of device
+ * @type: type of resource to dele
+ * @reset: true if reset chip
+ */
+void irdma_puda_dele_rsrc(struct irdma_sc_vsi *vsi, enum puda_rsrc_type type,
+ bool reset)
+{
+ struct irdma_sc_dev *dev = vsi->dev;
+ struct irdma_puda_rsrc *rsrc;
+ struct irdma_puda_buf *buf = NULL;
+ struct irdma_puda_buf *nextbuf = NULL;
+ struct irdma_virt_mem *vmem;
+ struct irdma_sc_ceq *ceq;
+
+ ceq = vsi->dev->ceq[0];
+ switch (type) {
+ case IRDMA_PUDA_RSRC_TYPE_ILQ:
+ rsrc = vsi->ilq;
+ vmem = &vsi->ilq_mem;
+ vsi->ilq = NULL;
+ if (ceq && ceq->reg_cq)
+ irdma_sc_remove_cq_ctx(ceq, &rsrc->cq);
+ break;
+ case IRDMA_PUDA_RSRC_TYPE_IEQ:
+ rsrc = vsi->ieq;
+ vmem = &vsi->ieq_mem;
+ vsi->ieq = NULL;
+ if (ceq && ceq->reg_cq)
+ irdma_sc_remove_cq_ctx(ceq, &rsrc->cq);
+ break;
+ default:
+ ibdev_dbg(to_ibdev(dev), "PUDA: error resource type = 0x%x\n",
+ type);
+ return;
+ }
+
+ switch (rsrc->cmpl) {
+ case PUDA_HASH_CRC_COMPLETE:
+ irdma_free_hash_desc(rsrc->hash_desc);
+ fallthrough;
+ case PUDA_QP_CREATED:
+ irdma_qp_rem_qos(&rsrc->qp);
+
+ if (!reset)
+ irdma_puda_free_qp(rsrc);
+
+ dma_free_coherent(dev->hw->device, rsrc->qpmem.size,
+ rsrc->qpmem.va, rsrc->qpmem.pa);
+ rsrc->qpmem.va = NULL;
+ fallthrough;
+ case PUDA_CQ_CREATED:
+ if (!reset)
+ irdma_puda_free_cq(rsrc);
+
+ dma_free_coherent(dev->hw->device, rsrc->cqmem.size,
+ rsrc->cqmem.va, rsrc->cqmem.pa);
+ rsrc->cqmem.va = NULL;
+ break;
+ default:
+ ibdev_dbg(to_ibdev(rsrc->dev), "PUDA: error no resources\n");
+ break;
+ }
+ /* Free all allocated puda buffers for both tx and rx */
+ buf = rsrc->alloclist;
+ while (buf) {
+ nextbuf = buf->next;
+ irdma_puda_dele_buf(dev, buf);
+ buf = nextbuf;
+ rsrc->alloc_buf_count--;
+ }
+
+ kfree(vmem->va);
+}
+
+/**
+ * irdma_puda_allocbufs - allocate buffers for resource
+ * @rsrc: resource for buffer allocation
+ * @count: number of buffers to create
+ */
+static enum irdma_status_code irdma_puda_allocbufs(struct irdma_puda_rsrc *rsrc,
+ u32 count)
+{
+ u32 i;
+ struct irdma_puda_buf *buf;
+ struct irdma_puda_buf *nextbuf;
+
+ for (i = 0; i < count; i++) {
+ buf = irdma_puda_alloc_buf(rsrc->dev, rsrc->buf_size);
+ if (!buf) {
+ rsrc->stats_buf_alloc_fail++;
+ return IRDMA_ERR_NO_MEMORY;
+ }
+ irdma_puda_ret_bufpool(rsrc, buf);
+ rsrc->alloc_buf_count++;
+ if (!rsrc->alloclist) {
+ rsrc->alloclist = buf;
+ } else {
+ nextbuf = rsrc->alloclist;
+ rsrc->alloclist = buf;
+ buf->next = nextbuf;
+ }
+ }
+
+ rsrc->avail_buf_count = rsrc->alloc_buf_count;
+
+ return 0;
+}
+
+/**
+ * irdma_puda_create_rsrc - create resource (ilq or ieq)
+ * @vsi: sc VSI struct
+ * @info: resource information
+ */
+enum irdma_status_code irdma_puda_create_rsrc(struct irdma_sc_vsi *vsi,
+ struct irdma_puda_rsrc_info *info)
+{
+ struct irdma_sc_dev *dev = vsi->dev;
+ enum irdma_status_code ret = 0;
+ struct irdma_puda_rsrc *rsrc;
+ u32 pudasize;
+ u32 sqwridsize, rqwridsize;
+ struct irdma_virt_mem *vmem;
+
+ info->count = 1;
+ pudasize = sizeof(struct irdma_puda_rsrc);
+ sqwridsize = info->sq_size * sizeof(struct irdma_sq_uk_wr_trk_info);
+ rqwridsize = info->rq_size * 8;
+ switch (info->type) {
+ case IRDMA_PUDA_RSRC_TYPE_ILQ:
+ vmem = &vsi->ilq_mem;
+ break;
+ case IRDMA_PUDA_RSRC_TYPE_IEQ:
+ vmem = &vsi->ieq_mem;
+ break;
+ default:
+ return IRDMA_NOT_SUPPORTED;
+ }
+ vmem->size = pudasize + sqwridsize + rqwridsize;
+ vmem->va = kzalloc(vmem->size, GFP_KERNEL);
+ if (!vmem->va)
+ return IRDMA_ERR_NO_MEMORY;
+
+ rsrc = vmem->va;
+ spin_lock_init(&rsrc->bufpool_lock);
+ switch (info->type) {
+ case IRDMA_PUDA_RSRC_TYPE_ILQ:
+ vsi->ilq = vmem->va;
+ vsi->ilq_count = info->count;
+ rsrc->receive = info->receive;
+ rsrc->xmit_complete = info->xmit_complete;
+ break;
+ case IRDMA_PUDA_RSRC_TYPE_IEQ:
+ vsi->ieq_count = info->count;
+ vsi->ieq = vmem->va;
+ rsrc->receive = irdma_ieq_receive;
+ rsrc->xmit_complete = irdma_ieq_tx_compl;
+ break;
+ default:
+ return IRDMA_NOT_SUPPORTED;
+ }
+
+ rsrc->type = info->type;
+ rsrc->sq_wrtrk_array = (struct irdma_sq_uk_wr_trk_info *)
+ ((u8 *)vmem->va + pudasize);
+ rsrc->rq_wrid_array = (u64 *)((u8 *)vmem->va + pudasize + sqwridsize);
+ /* Initialize all ieq lists */
+ INIT_LIST_HEAD(&rsrc->bufpool);
+ INIT_LIST_HEAD(&rsrc->txpend);
+
+ rsrc->tx_wqe_avail_cnt = info->sq_size - 1;
+ irdma_sc_pd_init(dev, &rsrc->sc_pd, info->pd_id, info->abi_ver);
+ rsrc->qp_id = info->qp_id;
+ rsrc->cq_id = info->cq_id;
+ rsrc->sq_size = info->sq_size;
+ rsrc->rq_size = info->rq_size;
+ rsrc->cq_size = info->rq_size + info->sq_size;
+ if (dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
+ if (rsrc->type == IRDMA_PUDA_RSRC_TYPE_ILQ)
+ rsrc->cq_size += info->rq_size;
+ }
+ rsrc->buf_size = info->buf_size;
+ rsrc->dev = dev;
+ rsrc->vsi = vsi;
+ rsrc->stats_idx = info->stats_idx;
+ rsrc->stats_idx_valid = info->stats_idx_valid;
+
+ ret = irdma_puda_cq_create(rsrc);
+ if (!ret) {
+ rsrc->cmpl = PUDA_CQ_CREATED;
+ ret = irdma_puda_qp_create(rsrc);
+ }
+ if (ret) {
+ ibdev_dbg(to_ibdev(dev),
+ "PUDA: error qp_create type=%d, status=%d\n",
+ rsrc->type, ret);
+ goto error;
+ }
+ rsrc->cmpl = PUDA_QP_CREATED;
+
+ ret = irdma_puda_allocbufs(rsrc, info->tx_buf_cnt + info->rq_size);
+ if (ret) {
+ ibdev_dbg(to_ibdev(dev), "PUDA: error alloc_buf\n");
+ goto error;
+ }
+
+ rsrc->rxq_invalid_cnt = info->rq_size;
+ ret = irdma_puda_replenish_rq(rsrc, true);
+ if (ret)
+ goto error;
+
+ if (info->type == IRDMA_PUDA_RSRC_TYPE_IEQ) {
+ if (!irdma_init_hash_desc(&rsrc->hash_desc)) {
+ rsrc->check_crc = true;
+ rsrc->cmpl = PUDA_HASH_CRC_COMPLETE;
+ ret = 0;
+ }
+ }
+
+ irdma_sc_ccq_arm(&rsrc->cq);
+ return ret;
+
+error:
+ irdma_puda_dele_rsrc(vsi, info->type, false);
+
+ return ret;
+}
+
+/**
+ * irdma_ilq_putback_rcvbuf - ilq buffer to put back on rq
+ * @qp: ilq's qp resource
+ * @buf: puda buffer for rcv q
+ * @wqe_idx: wqe index of completed rcvbuf
+ */
+static void irdma_ilq_putback_rcvbuf(struct irdma_sc_qp *qp,
+ struct irdma_puda_buf *buf, u32 wqe_idx)
+{
+ __le64 *wqe;
+ u64 offset8, offset24;
+
+ /* Synch buffer for use by device */
+ dma_sync_single_for_device(qp->dev->hw->device, buf->mem.pa,
+ buf->mem.size, DMA_BIDIRECTIONAL);
+ wqe = qp->qp_uk.rq_base[wqe_idx].elem;
+ get_64bit_val(wqe, 24, &offset24);
+ if (qp->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
+ get_64bit_val(wqe, 8, &offset8);
+ if (offset24)
+ offset8 &= ~FIELD_PREP(IRDMAQPSQ_VALID, 1);
+ else
+ offset8 |= FIELD_PREP(IRDMAQPSQ_VALID, 1);
+ set_64bit_val(wqe, 8, offset8);
+ dma_wmb(); /* make sure WQE is written before valid bit is set */
+ }
+ if (offset24)
+ offset24 = 0;
+ else
+ offset24 = FIELD_PREP(IRDMAQPSQ_VALID, 1);
+
+ set_64bit_val(wqe, 24, offset24);
+}
+
+/**
+ * irdma_ieq_get_fpdu_len - get length of fpdu with or without marker
+ * @pfpdu: pointer to fpdu
+ * @datap: pointer to data in the buffer
+ * @rcv_seq: seqnum of the data buffer
+ */
+static u16 irdma_ieq_get_fpdu_len(struct irdma_pfpdu *pfpdu, u8 *datap,
+ u32 rcv_seq)
+{
+ u32 marker_seq, end_seq, blk_start;
+ u8 marker_len = pfpdu->marker_len;
+ u16 total_len = 0;
+ u16 fpdu_len;
+
+ blk_start = (pfpdu->rcv_start_seq - rcv_seq) & (IRDMA_MRK_BLK_SZ - 1);
+ if (!blk_start) {
+ total_len = marker_len;
+ marker_seq = rcv_seq + IRDMA_MRK_BLK_SZ;
+ if (marker_len && *(u32 *)datap)
+ return 0;
+ } else {
+ marker_seq = rcv_seq + blk_start;
+ }
+
+ datap += total_len;
+ fpdu_len = ntohs(*(__be16 *)datap);
+ fpdu_len += IRDMA_IEQ_MPA_FRAMING;
+ fpdu_len = (fpdu_len + 3) & 0xfffc;
+
+ if (fpdu_len > pfpdu->max_fpdu_data)
+ return 0;
+
+ total_len += fpdu_len;
+ end_seq = rcv_seq + total_len;
+ while ((int)(marker_seq - end_seq) < 0) {
+ total_len += marker_len;
+ end_seq += marker_len;
+ marker_seq += IRDMA_MRK_BLK_SZ;
+ }
+
+ return total_len;
+}
+
+/**
+ * irdma_ieq_copy_to_txbuf - copydata from rcv buf to tx buf
+ * @buf: rcv buffer with partial
+ * @txbuf: tx buffer for sending back
+ * @buf_offset: rcv buffer offset to copy from
+ * @txbuf_offset: at offset in tx buf to copy
+ * @len: length of data to copy
+ */
+static void irdma_ieq_copy_to_txbuf(struct irdma_puda_buf *buf,
+ struct irdma_puda_buf *txbuf,
+ u16 buf_offset, u32 txbuf_offset, u32 len)
+{
+ void *mem1 = (u8 *)buf->mem.va + buf_offset;
+ void *mem2 = (u8 *)txbuf->mem.va + txbuf_offset;
+
+ memcpy(mem2, mem1, len);
+}
+
+/**
+ * irdma_ieq_setup_tx_buf - setup tx buffer for partial handling
+ * @buf: reeive buffer with partial
+ * @txbuf: buffer to prepare
+ */
+static void irdma_ieq_setup_tx_buf(struct irdma_puda_buf *buf,
+ struct irdma_puda_buf *txbuf)
+{
+ txbuf->tcphlen = buf->tcphlen;
+ txbuf->ipv4 = buf->ipv4;
+
+ if (buf->vsi->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
+ txbuf->hdrlen = txbuf->tcphlen;
+ irdma_ieq_copy_to_txbuf(buf, txbuf, IRDMA_TCP_OFFSET, 0,
+ txbuf->hdrlen);
+ } else {
+ txbuf->maclen = buf->maclen;
+ txbuf->hdrlen = buf->hdrlen;
+ irdma_ieq_copy_to_txbuf(buf, txbuf, 0, 0, buf->hdrlen);
+ }
+}
+
+/**
+ * irdma_ieq_check_first_buf - check if rcv buffer's seq is in range
+ * @buf: receive exception buffer
+ * @fps: first partial sequence number
+ */
+static void irdma_ieq_check_first_buf(struct irdma_puda_buf *buf, u32 fps)
+{
+ u32 offset;
+
+ if (buf->seqnum < fps) {
+ offset = fps - buf->seqnum;
+ if (offset > buf->datalen)
+ return;
+ buf->data += offset;
+ buf->datalen -= (u16)offset;
+ buf->seqnum = fps;
+ }
+}
+
+/**
+ * irdma_ieq_compl_pfpdu - write txbuf with full fpdu
+ * @ieq: ieq resource
+ * @rxlist: ieq's received buffer list
+ * @pbufl: temporary list for buffers for fpddu
+ * @txbuf: tx buffer for fpdu
+ * @fpdu_len: total length of fpdu
+ */
+static void irdma_ieq_compl_pfpdu(struct irdma_puda_rsrc *ieq,
+ struct list_head *rxlist,
+ struct list_head *pbufl,
+ struct irdma_puda_buf *txbuf, u16 fpdu_len)
+{
+ struct irdma_puda_buf *buf;
+ u32 nextseqnum;
+ u16 txoffset, bufoffset;
+
+ buf = irdma_puda_get_listbuf(pbufl);
+ if (!buf)
+ return;
+
+ nextseqnum = buf->seqnum + fpdu_len;
+ irdma_ieq_setup_tx_buf(buf, txbuf);
+ if (buf->vsi->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
+ txoffset = txbuf->hdrlen;
+ txbuf->totallen = txbuf->hdrlen + fpdu_len;
+ txbuf->data = (u8 *)txbuf->mem.va + txoffset;
+ } else {
+ txoffset = buf->hdrlen;
+ txbuf->totallen = buf->hdrlen + fpdu_len;
+ txbuf->data = (u8 *)txbuf->mem.va + buf->hdrlen;
+ }
+ bufoffset = (u16)(buf->data - (u8 *)buf->mem.va);
+
+ do {
+ if (buf->datalen >= fpdu_len) {
+ /* copied full fpdu */
+ irdma_ieq_copy_to_txbuf(buf, txbuf, bufoffset, txoffset,
+ fpdu_len);
+ buf->datalen -= fpdu_len;
+ buf->data += fpdu_len;
+ buf->seqnum = nextseqnum;
+ break;
+ }
+ /* copy partial fpdu */
+ irdma_ieq_copy_to_txbuf(buf, txbuf, bufoffset, txoffset,
+ buf->datalen);
+ txoffset += buf->datalen;
+ fpdu_len -= buf->datalen;
+ irdma_puda_ret_bufpool(ieq, buf);
+ buf = irdma_puda_get_listbuf(pbufl);
+ if (!buf)
+ return;
+
+ bufoffset = (u16)(buf->data - (u8 *)buf->mem.va);
+ } while (1);
+
+ /* last buffer on the list*/
+ if (buf->datalen)
+ list_add(&buf->list, rxlist);
+ else
+ irdma_puda_ret_bufpool(ieq, buf);
+}
+
+/**
+ * irdma_ieq_create_pbufl - create buffer list for single fpdu
+ * @pfpdu: pointer to fpdu
+ * @rxlist: resource list for receive ieq buffes
+ * @pbufl: temp. list for buffers for fpddu
+ * @buf: first receive buffer
+ * @fpdu_len: total length of fpdu
+ */
+static enum irdma_status_code
+irdma_ieq_create_pbufl(struct irdma_pfpdu *pfpdu, struct list_head *rxlist,
+ struct list_head *pbufl, struct irdma_puda_buf *buf,
+ u16 fpdu_len)
+{
+ enum irdma_status_code status = 0;
+ struct irdma_puda_buf *nextbuf;
+ u32 nextseqnum;
+ u16 plen = fpdu_len - buf->datalen;
+ bool done = false;
+
+ nextseqnum = buf->seqnum + buf->datalen;
+ do {
+ nextbuf = irdma_puda_get_listbuf(rxlist);
+ if (!nextbuf) {
+ status = IRDMA_ERR_list_empty;
+ break;
+ }
+ list_add_tail(&nextbuf->list, pbufl);
+ if (nextbuf->seqnum != nextseqnum) {
+ pfpdu->bad_seq_num++;
+ status = IRDMA_ERR_SEQ_NUM;
+ break;
+ }
+ if (nextbuf->datalen >= plen) {
+ done = true;
+ } else {
+ plen -= nextbuf->datalen;
+ nextseqnum = nextbuf->seqnum + nextbuf->datalen;
+ }
+
+ } while (!done);
+
+ return status;
+}
+
+/**
+ * irdma_ieq_handle_partial - process partial fpdu buffer
+ * @ieq: ieq resource
+ * @pfpdu: partial management per user qp
+ * @buf: receive buffer
+ * @fpdu_len: fpdu len in the buffer
+ */
+static enum irdma_status_code
+irdma_ieq_handle_partial(struct irdma_puda_rsrc *ieq, struct irdma_pfpdu *pfpdu,
+ struct irdma_puda_buf *buf, u16 fpdu_len)
+{
+ enum irdma_status_code status = 0;
+ u8 *crcptr;
+ u32 mpacrc;
+ u32 seqnum = buf->seqnum;
+ struct list_head pbufl; /* partial buffer list */
+ struct irdma_puda_buf *txbuf = NULL;
+ struct list_head *rxlist = &pfpdu->rxlist;
+
+ ieq->partials_handled++;
+
+ INIT_LIST_HEAD(&pbufl);
+ list_add(&buf->list, &pbufl);
+
+ status = irdma_ieq_create_pbufl(pfpdu, rxlist, &pbufl, buf, fpdu_len);
+ if (status)
+ goto error;
+
+ txbuf = irdma_puda_get_bufpool(ieq);
+ if (!txbuf) {
+ pfpdu->no_tx_bufs++;
+ status = IRDMA_ERR_NO_TXBUFS;
+ goto error;
+ }
+
+ irdma_ieq_compl_pfpdu(ieq, rxlist, &pbufl, txbuf, fpdu_len);
+ irdma_ieq_update_tcpip_info(txbuf, fpdu_len, seqnum);
+
+ crcptr = txbuf->data + fpdu_len - 4;
+ mpacrc = *(u32 *)crcptr;
+ if (ieq->check_crc) {
+ status = irdma_ieq_check_mpacrc(ieq->hash_desc, txbuf->data,
+ (fpdu_len - 4), mpacrc);
+ if (status) {
+ ibdev_dbg(to_ibdev(ieq->dev), "IEQ: error bad crc\n");
+ goto error;
+ }
+ }
+
+ print_hex_dump_debug("IEQ: IEQ TX BUFFER", DUMP_PREFIX_OFFSET, 16, 8,
+ txbuf->mem.va, txbuf->totallen, false);
+ if (ieq->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2)
+ txbuf->ah_id = pfpdu->ah->ah_info.ah_idx;
+ txbuf->do_lpb = true;
+ irdma_puda_send_buf(ieq, txbuf);
+ pfpdu->rcv_nxt = seqnum + fpdu_len;
+ return status;
+
+error:
+ while (!list_empty(&pbufl)) {
+ buf = list_last_entry(&pbufl, struct irdma_puda_buf, list);
+ list_move(&buf->list, rxlist);
+ }
+ if (txbuf)
+ irdma_puda_ret_bufpool(ieq, txbuf);
+
+ return status;
+}
+
+/**
+ * irdma_ieq_process_buf - process buffer rcvd for ieq
+ * @ieq: ieq resource
+ * @pfpdu: partial management per user qp
+ * @buf: receive buffer
+ */
+static enum irdma_status_code irdma_ieq_process_buf(struct irdma_puda_rsrc *ieq,
+ struct irdma_pfpdu *pfpdu,
+ struct irdma_puda_buf *buf)
+{
+ u16 fpdu_len = 0;
+ u16 datalen = buf->datalen;
+ u8 *datap = buf->data;
+ u8 *crcptr;
+ u16 ioffset = 0;
+ u32 mpacrc;
+ u32 seqnum = buf->seqnum;
+ u16 len = 0;
+ u16 full = 0;
+ bool partial = false;
+ struct irdma_puda_buf *txbuf;
+ struct list_head *rxlist = &pfpdu->rxlist;
+ enum irdma_status_code ret = 0;
+
+ ioffset = (u16)(buf->data - (u8 *)buf->mem.va);
+ while (datalen) {
+ fpdu_len = irdma_ieq_get_fpdu_len(pfpdu, datap, buf->seqnum);
+ if (!fpdu_len) {
+ ibdev_dbg(to_ibdev(ieq->dev),
+ "IEQ: error bad fpdu len\n");
+ list_add(&buf->list, rxlist);
+ return IRDMA_ERR_MPA_CRC;
+ }
+
+ if (datalen < fpdu_len) {
+ partial = true;
+ break;
+ }
+ crcptr = datap + fpdu_len - 4;
+ mpacrc = *(u32 *)crcptr;
+ if (ieq->check_crc)
+ ret = irdma_ieq_check_mpacrc(ieq->hash_desc, datap,
+ fpdu_len - 4, mpacrc);
+ if (ret) {
+ list_add(&buf->list, rxlist);
+ ibdev_dbg(to_ibdev(ieq->dev),
+ "ERR: IRDMA_ERR_MPA_CRC\n");
+ return IRDMA_ERR_MPA_CRC;
+ }
+ full++;
+ pfpdu->fpdu_processed++;
+ ieq->fpdu_processed++;
+ datap += fpdu_len;
+ len += fpdu_len;
+ datalen -= fpdu_len;
+ }
+ if (full) {
+ /* copy full pdu's in the txbuf and send them out */
+ txbuf = irdma_puda_get_bufpool(ieq);
+ if (!txbuf) {
+ pfpdu->no_tx_bufs++;
+ list_add(&buf->list, rxlist);
+ return IRDMA_ERR_NO_TXBUFS;
+ }
+ /* modify txbuf's buffer header */
+ irdma_ieq_setup_tx_buf(buf, txbuf);
+ /* copy full fpdu's to new buffer */
+ if (ieq->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
+ irdma_ieq_copy_to_txbuf(buf, txbuf, ioffset,
+ txbuf->hdrlen, len);
+ txbuf->totallen = txbuf->hdrlen + len;
+ txbuf->ah_id = pfpdu->ah->ah_info.ah_idx;
+ } else {
+ irdma_ieq_copy_to_txbuf(buf, txbuf, ioffset,
+ buf->hdrlen, len);
+ txbuf->totallen = buf->hdrlen + len;
+ }
+ irdma_ieq_update_tcpip_info(txbuf, len, buf->seqnum);
+ print_hex_dump_debug("IEQ: IEQ TX BUFFER", DUMP_PREFIX_OFFSET,
+ 16, 8, txbuf->mem.va, txbuf->totallen,
+ false);
+ txbuf->do_lpb = true;
+ irdma_puda_send_buf(ieq, txbuf);
+
+ if (!datalen) {
+ pfpdu->rcv_nxt = buf->seqnum + len;
+ irdma_puda_ret_bufpool(ieq, buf);
+ return 0;
+ }
+ buf->data = datap;
+ buf->seqnum = seqnum + len;
+ buf->datalen = datalen;
+ pfpdu->rcv_nxt = buf->seqnum;
+ }
+ if (partial)
+ return irdma_ieq_handle_partial(ieq, pfpdu, buf, fpdu_len);
+
+ return 0;
+}
+
+/**
+ * irdma_ieq_process_fpdus - process fpdu's buffers on its list
+ * @qp: qp for which partial fpdus
+ * @ieq: ieq resource
+ */
+void irdma_ieq_process_fpdus(struct irdma_sc_qp *qp,
+ struct irdma_puda_rsrc *ieq)
+{
+ struct irdma_pfpdu *pfpdu = &qp->pfpdu;
+ struct list_head *rxlist = &pfpdu->rxlist;
+ struct irdma_puda_buf *buf;
+ enum irdma_status_code status;
+
+ do {
+ if (list_empty(rxlist))
+ break;
+ buf = irdma_puda_get_listbuf(rxlist);
+ if (!buf) {
+ ibdev_dbg(to_ibdev(ieq->dev), "IEQ: error no buf\n");
+ break;
+ }
+ if (buf->seqnum != pfpdu->rcv_nxt) {
+ /* This could be out of order or missing packet */
+ pfpdu->out_of_order++;
+ list_add(&buf->list, rxlist);
+ break;
+ }
+ /* keep processing buffers from the head of the list */
+ status = irdma_ieq_process_buf(ieq, pfpdu, buf);
+ if (status == IRDMA_ERR_MPA_CRC) {
+ pfpdu->mpa_crc_err = true;
+ while (!list_empty(rxlist)) {
+ buf = irdma_puda_get_listbuf(rxlist);
+ irdma_puda_ret_bufpool(ieq, buf);
+ pfpdu->crc_err++;
+ ieq->crc_err++;
+ }
+ /* create CQP for AE */
+ irdma_ieq_mpa_crc_ae(ieq->dev, qp);
+ }
+ } while (!status);
+}
+
+/**
+ * irdma_ieq_create_ah - create an address handle for IEQ
+ * @qp: qp pointer
+ * @buf: buf received on IEQ used to create AH
+ */
+static enum irdma_status_code irdma_ieq_create_ah(struct irdma_sc_qp *qp,
+ struct irdma_puda_buf *buf)
+{
+ struct irdma_ah_info ah_info = {};
+
+ qp->pfpdu.ah_buf = buf;
+ irdma_puda_ieq_get_ah_info(qp, &ah_info);
+ return irdma_puda_create_ah(qp->vsi->dev, &ah_info, false,
+ IRDMA_PUDA_RSRC_TYPE_IEQ, qp,
+ &qp->pfpdu.ah);
+}
+
+/**
+ * irdma_ieq_handle_exception - handle qp's exception
+ * @ieq: ieq resource
+ * @qp: qp receiving excpetion
+ * @buf: receive buffer
+ */
+static void irdma_ieq_handle_exception(struct irdma_puda_rsrc *ieq,
+ struct irdma_sc_qp *qp,
+ struct irdma_puda_buf *buf)
+{
+ struct irdma_pfpdu *pfpdu = &qp->pfpdu;
+ u32 *hw_host_ctx = (u32 *)qp->hw_host_ctx;
+ u32 rcv_wnd = hw_host_ctx[23];
+ /* first partial seq # in q2 */
+ u32 fps = *(u32 *)(qp->q2_buf + Q2_FPSN_OFFSET);
+ struct list_head *rxlist = &pfpdu->rxlist;
+ unsigned long flags = 0;
+ u8 hw_rev = qp->dev->hw_attrs.uk_attrs.hw_rev;
+
+ print_hex_dump_debug("IEQ: IEQ RX BUFFER", DUMP_PREFIX_OFFSET, 16, 8,
+ buf->mem.va, buf->totallen, false);
+
+ spin_lock_irqsave(&pfpdu->lock, flags);
+ pfpdu->total_ieq_bufs++;
+ if (pfpdu->mpa_crc_err) {
+ pfpdu->crc_err++;
+ goto error;
+ }
+ if (pfpdu->mode && fps != pfpdu->fps) {
+ /* clean up qp as it is new partial sequence */
+ irdma_ieq_cleanup_qp(ieq, qp);
+ ibdev_dbg(to_ibdev(ieq->dev), "IEQ: restarting new partial\n");
+ pfpdu->mode = false;
+ }
+
+ if (!pfpdu->mode) {
+ print_hex_dump_debug("IEQ: Q2 BUFFER", DUMP_PREFIX_OFFSET, 16,
+ 8, (u64 *)qp->q2_buf, 128, false);
+ /* First_Partial_Sequence_Number check */
+ pfpdu->rcv_nxt = fps;
+ pfpdu->fps = fps;
+ pfpdu->mode = true;
+ pfpdu->max_fpdu_data = (buf->ipv4) ?
+ (ieq->vsi->mtu - IRDMA_MTU_TO_MSS_IPV4) :
+ (ieq->vsi->mtu - IRDMA_MTU_TO_MSS_IPV6);
+ pfpdu->pmode_count++;
+ ieq->pmode_count++;
+ INIT_LIST_HEAD(rxlist);
+ irdma_ieq_check_first_buf(buf, fps);
+ }
+
+ if (!(rcv_wnd >= (buf->seqnum - pfpdu->rcv_nxt))) {
+ pfpdu->bad_seq_num++;
+ ieq->bad_seq_num++;
+ goto error;
+ }
+
+ if (!list_empty(rxlist)) {
+ if (buf->seqnum != pfpdu->nextseqnum) {
+ irdma_send_ieq_ack(qp);
+ /* throw away out-of-order, duplicates*/
+ goto error;
+ }
+ }
+ /* Insert buf before head */
+ list_add_tail(&buf->list, rxlist);
+ pfpdu->nextseqnum = buf->seqnum + buf->datalen;
+ pfpdu->lastrcv_buf = buf;
+ if (hw_rev >= IRDMA_GEN_2 && !pfpdu->ah) {
+ irdma_ieq_create_ah(qp, buf);
+ if (!pfpdu->ah)
+ goto error;
+ goto exit;
+ }
+ if (hw_rev == IRDMA_GEN_1)
+ irdma_ieq_process_fpdus(qp, ieq);
+ else if (pfpdu->ah && pfpdu->ah->ah_info.ah_valid)
+ irdma_ieq_process_fpdus(qp, ieq);
+exit:
+ spin_unlock_irqrestore(&pfpdu->lock, flags);
+
+ return;
+
+error:
+ irdma_puda_ret_bufpool(ieq, buf);
+ spin_unlock_irqrestore(&pfpdu->lock, flags);
+}
+
+/**
+ * irdma_ieq_receive - received exception buffer
+ * @vsi: VSI of device
+ * @buf: exception buffer received
+ */
+static void irdma_ieq_receive(struct irdma_sc_vsi *vsi,
+ struct irdma_puda_buf *buf)
+{
+ struct irdma_puda_rsrc *ieq = vsi->ieq;
+ struct irdma_sc_qp *qp = NULL;
+ u32 wqe_idx = ieq->compl_rxwqe_idx;
+
+ qp = irdma_ieq_get_qp(vsi->dev, buf);
+ if (!qp) {
+ ieq->stats_bad_qp_id++;
+ irdma_puda_ret_bufpool(ieq, buf);
+ } else {
+ irdma_ieq_handle_exception(ieq, qp, buf);
+ }
+ /*
+ * ieq->rx_wqe_idx is used by irdma_puda_replenish_rq()
+ * on which wqe_idx to start replenish rq
+ */
+ if (!ieq->rxq_invalid_cnt)
+ ieq->rx_wqe_idx = wqe_idx;
+ ieq->rxq_invalid_cnt++;
+}
+
+/**
+ * irdma_ieq_tx_compl - put back after sending completed exception buffer
+ * @vsi: sc VSI struct
+ * @sqwrid: pointer to puda buffer
+ */
+static void irdma_ieq_tx_compl(struct irdma_sc_vsi *vsi, void *sqwrid)
+{
+ struct irdma_puda_rsrc *ieq = vsi->ieq;
+ struct irdma_puda_buf *buf = sqwrid;
+
+ irdma_puda_ret_bufpool(ieq, buf);
+}
+
+/**
+ * irdma_ieq_cleanup_qp - qp is being destroyed
+ * @ieq: ieq resource
+ * @qp: all pending fpdu buffers
+ */
+void irdma_ieq_cleanup_qp(struct irdma_puda_rsrc *ieq, struct irdma_sc_qp *qp)
+{
+ struct irdma_puda_buf *buf;
+ struct irdma_pfpdu *pfpdu = &qp->pfpdu;
+ struct list_head *rxlist = &pfpdu->rxlist;
+
+ if (qp->pfpdu.ah) {
+ irdma_puda_free_ah(ieq->dev, qp->pfpdu.ah);
+ qp->pfpdu.ah = NULL;
+ qp->pfpdu.ah_buf = NULL;
+ }
+
+ if (!pfpdu->mode)
+ return;
+
+ while (!list_empty(rxlist)) {
+ buf = irdma_puda_get_listbuf(rxlist);
+ irdma_puda_ret_bufpool(ieq, buf);
+ }
+}
diff --git a/drivers/infiniband/hw/irdma/puda.h b/drivers/infiniband/hw/irdma/puda.h
new file mode 100644
index 000000000000..db3a51170020
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/puda.h
@@ -0,0 +1,194 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2015 - 2020 Intel Corporation */
+#ifndef IRDMA_PUDA_H
+#define IRDMA_PUDA_H
+
+#define IRDMA_IEQ_MPA_FRAMING 6
+#define IRDMA_TCP_OFFSET 40
+#define IRDMA_IPV4_PAD 20
+#define IRDMA_MRK_BLK_SZ 512
+
+enum puda_rsrc_type {
+ IRDMA_PUDA_RSRC_TYPE_ILQ = 1,
+ IRDMA_PUDA_RSRC_TYPE_IEQ,
+ IRDMA_PUDA_RSRC_TYPE_MAX, /* Must be last entry */
+};
+
+enum puda_rsrc_complete {
+ PUDA_CQ_CREATED = 1,
+ PUDA_QP_CREATED,
+ PUDA_TX_COMPLETE,
+ PUDA_RX_COMPLETE,
+ PUDA_HASH_CRC_COMPLETE,
+};
+
+struct irdma_sc_dev;
+struct irdma_sc_qp;
+struct irdma_sc_cq;
+
+struct irdma_puda_cmpl_info {
+ struct irdma_qp_uk *qp;
+ u8 q_type;
+ u8 l3proto;
+ u8 l4proto;
+ u16 vlan;
+ u32 payload_len;
+ u32 compl_error; /* No_err=0, else major and minor err code */
+ u32 qp_id;
+ u32 wqe_idx;
+ bool ipv4:1;
+ bool smac_valid:1;
+ bool vlan_valid:1;
+ u8 smac[ETH_ALEN];
+};
+
+struct irdma_puda_send_info {
+ u64 paddr; /* Physical address */
+ u32 len;
+ u32 ah_id;
+ u8 tcplen;
+ u8 maclen;
+ bool ipv4:1;
+ bool do_lpb:1;
+ void *scratch;
+};
+
+struct irdma_puda_buf {
+ struct list_head list; /* MUST be first entry */
+ struct irdma_dma_mem mem; /* DMA memory for the buffer */
+ struct irdma_puda_buf *next; /* for alloclist in rsrc struct */
+ struct irdma_virt_mem buf_mem; /* Buffer memory for this buffer */
+ void *scratch;
+ u8 *iph;
+ u8 *tcph;
+ u8 *data;
+ u16 datalen;
+ u16 vlan_id;
+ u8 tcphlen; /* tcp length in bytes */
+ u8 maclen; /* mac length in bytes */
+ u32 totallen; /* machlen+iphlen+tcphlen+datalen */
+ refcount_t refcount;
+ u8 hdrlen;
+ bool ipv4:1;
+ bool vlan_valid:1;
+ bool do_lpb:1; /* Loopback buffer */
+ bool smac_valid:1;
+ u32 seqnum;
+ u32 ah_id;
+ u8 smac[ETH_ALEN];
+ struct irdma_sc_vsi *vsi;
+};
+
+struct irdma_puda_rsrc_info {
+ void (*receive)(struct irdma_sc_vsi *vsi, struct irdma_puda_buf *buf);
+ void (*xmit_complete)(struct irdma_sc_vsi *vsi, void *sqwrid);
+ enum puda_rsrc_type type; /* ILQ or IEQ */
+ u32 count;
+ u32 pd_id;
+ u32 cq_id;
+ u32 qp_id;
+ u32 sq_size;
+ u32 rq_size;
+ u32 tx_buf_cnt; /* total bufs allocated will be rq_size + tx_buf_cnt */
+ u16 buf_size;
+ u8 stats_idx;
+ bool stats_idx_valid:1;
+ int abi_ver;
+};
+
+struct irdma_puda_rsrc {
+ struct irdma_sc_cq cq;
+ struct irdma_sc_qp qp;
+ struct irdma_sc_pd sc_pd;
+ struct irdma_sc_dev *dev;
+ struct irdma_sc_vsi *vsi;
+ struct irdma_dma_mem cqmem;
+ struct irdma_dma_mem qpmem;
+ struct irdma_virt_mem ilq_mem;
+ enum puda_rsrc_complete cmpl;
+ enum puda_rsrc_type type;
+ u16 buf_size; /*buf must be max datalen + tcpip hdr + mac */
+ u32 cq_id;
+ u32 qp_id;
+ u32 sq_size;
+ u32 rq_size;
+ u32 cq_size;
+ struct irdma_sq_uk_wr_trk_info *sq_wrtrk_array;
+ u64 *rq_wrid_array;
+ u32 compl_rxwqe_idx;
+ u32 rx_wqe_idx;
+ u32 rxq_invalid_cnt;
+ u32 tx_wqe_avail_cnt;
+ struct shash_desc *hash_desc;
+ struct list_head txpend;
+ struct list_head bufpool; /* free buffers pool list for recv and xmit */
+ u32 alloc_buf_count;
+ u32 avail_buf_count; /* snapshot of currently available buffers */
+ spinlock_t bufpool_lock;
+ struct irdma_puda_buf *alloclist;
+ void (*receive)(struct irdma_sc_vsi *vsi, struct irdma_puda_buf *buf);
+ void (*xmit_complete)(struct irdma_sc_vsi *vsi, void *sqwrid);
+ /* puda stats */
+ u64 stats_buf_alloc_fail;
+ u64 stats_pkt_rcvd;
+ u64 stats_pkt_sent;
+ u64 stats_rcvd_pkt_err;
+ u64 stats_sent_pkt_q;
+ u64 stats_bad_qp_id;
+ /* IEQ stats */
+ u64 fpdu_processed;
+ u64 bad_seq_num;
+ u64 crc_err;
+ u64 pmode_count;
+ u64 partials_handled;
+ u8 stats_idx;
+ bool check_crc:1;
+ bool stats_idx_valid:1;
+};
+
+struct irdma_puda_buf *irdma_puda_get_bufpool(struct irdma_puda_rsrc *rsrc);
+void irdma_puda_ret_bufpool(struct irdma_puda_rsrc *rsrc,
+ struct irdma_puda_buf *buf);
+void irdma_puda_send_buf(struct irdma_puda_rsrc *rsrc,
+ struct irdma_puda_buf *buf);
+enum irdma_status_code irdma_puda_send(struct irdma_sc_qp *qp,
+ struct irdma_puda_send_info *info);
+enum irdma_status_code
+irdma_puda_create_rsrc(struct irdma_sc_vsi *vsi,
+ struct irdma_puda_rsrc_info *info);
+void irdma_puda_dele_rsrc(struct irdma_sc_vsi *vsi, enum puda_rsrc_type type,
+ bool reset);
+enum irdma_status_code irdma_puda_poll_cmpl(struct irdma_sc_dev *dev,
+ struct irdma_sc_cq *cq,
+ u32 *compl_err);
+
+struct irdma_sc_qp *irdma_ieq_get_qp(struct irdma_sc_dev *dev,
+ struct irdma_puda_buf *buf);
+enum irdma_status_code
+irdma_puda_get_tcpip_info(struct irdma_puda_cmpl_info *info,
+ struct irdma_puda_buf *buf);
+enum irdma_status_code irdma_ieq_check_mpacrc(struct shash_desc *desc,
+ void *addr, u32 len, u32 val);
+enum irdma_status_code irdma_init_hash_desc(struct shash_desc **desc);
+void irdma_ieq_mpa_crc_ae(struct irdma_sc_dev *dev, struct irdma_sc_qp *qp);
+void irdma_free_hash_desc(struct shash_desc *desc);
+void irdma_ieq_update_tcpip_info(struct irdma_puda_buf *buf, u16 len,
+ u32 seqnum);
+enum irdma_status_code irdma_cqp_qp_create_cmd(struct irdma_sc_dev *dev,
+ struct irdma_sc_qp *qp);
+enum irdma_status_code irdma_cqp_cq_create_cmd(struct irdma_sc_dev *dev,
+ struct irdma_sc_cq *cq);
+enum irdma_status_code irdma_cqp_qp_destroy_cmd(struct irdma_sc_dev *dev, struct irdma_sc_qp *qp);
+void irdma_cqp_cq_destroy_cmd(struct irdma_sc_dev *dev, struct irdma_sc_cq *cq);
+void irdma_puda_ieq_get_ah_info(struct irdma_sc_qp *qp,
+ struct irdma_ah_info *ah_info);
+enum irdma_status_code irdma_puda_create_ah(struct irdma_sc_dev *dev,
+ struct irdma_ah_info *ah_info,
+ bool wait, enum puda_rsrc_type type,
+ void *cb_param,
+ struct irdma_sc_ah **ah);
+void irdma_puda_free_ah(struct irdma_sc_dev *dev, struct irdma_sc_ah *ah);
+void irdma_ieq_process_fpdus(struct irdma_sc_qp *qp,
+ struct irdma_puda_rsrc *ieq);
+void irdma_ieq_cleanup_qp(struct irdma_puda_rsrc *ieq, struct irdma_sc_qp *qp);
+#endif /*IRDMA_PROTOS_H */
diff --git a/drivers/infiniband/hw/irdma/status.h b/drivers/infiniband/hw/irdma/status.h
new file mode 100644
index 000000000000..22ea3888253a
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/status.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2015 - 2020 Intel Corporation */
+#ifndef IRDMA_STATUS_H
+#define IRDMA_STATUS_H
+
+/* Error Codes */
+enum irdma_status_code {
+ IRDMA_SUCCESS = 0,
+ IRDMA_ERR_NVM = -1,
+ IRDMA_ERR_NVM_CHECKSUM = -2,
+ IRDMA_ERR_CFG = -4,
+ IRDMA_ERR_PARAM = -5,
+ IRDMA_ERR_DEVICE_NOT_SUPPORTED = -6,
+ IRDMA_ERR_RESET_FAILED = -7,
+ IRDMA_ERR_SWFW_SYNC = -8,
+ IRDMA_ERR_NO_MEMORY = -9,
+ IRDMA_ERR_BAD_PTR = -10,
+ IRDMA_ERR_INVALID_PD_ID = -11,
+ IRDMA_ERR_INVALID_QP_ID = -12,
+ IRDMA_ERR_INVALID_CQ_ID = -13,
+ IRDMA_ERR_INVALID_CEQ_ID = -14,
+ IRDMA_ERR_INVALID_AEQ_ID = -15,
+ IRDMA_ERR_INVALID_SIZE = -16,
+ IRDMA_ERR_INVALID_ARP_INDEX = -17,
+ IRDMA_ERR_INVALID_FPM_FUNC_ID = -18,
+ IRDMA_ERR_QP_INVALID_MSG_SIZE = -19,
+ IRDMA_ERR_QP_TOOMANY_WRS_POSTED = -20,
+ IRDMA_ERR_INVALID_FRAG_COUNT = -21,
+ IRDMA_ERR_Q_EMPTY = -22,
+ IRDMA_ERR_INVALID_ALIGNMENT = -23,
+ IRDMA_ERR_FLUSHED_Q = -24,
+ IRDMA_ERR_INVALID_PUSH_PAGE_INDEX = -25,
+ IRDMA_ERR_INVALID_INLINE_DATA_SIZE = -26,
+ IRDMA_ERR_TIMEOUT = -27,
+ IRDMA_ERR_OPCODE_MISMATCH = -28,
+ IRDMA_ERR_CQP_COMPL_ERROR = -29,
+ IRDMA_ERR_INVALID_VF_ID = -30,
+ IRDMA_ERR_INVALID_HMCFN_ID = -31,
+ IRDMA_ERR_BACKING_PAGE_ERROR = -32,
+ IRDMA_ERR_NO_PBLCHUNKS_AVAILABLE = -33,
+ IRDMA_ERR_INVALID_PBLE_INDEX = -34,
+ IRDMA_ERR_INVALID_SD_INDEX = -35,
+ IRDMA_ERR_INVALID_PAGE_DESC_INDEX = -36,
+ IRDMA_ERR_INVALID_SD_TYPE = -37,
+ IRDMA_ERR_MEMCPY_FAILED = -38,
+ IRDMA_ERR_INVALID_HMC_OBJ_INDEX = -39,
+ IRDMA_ERR_INVALID_HMC_OBJ_COUNT = -40,
+ IRDMA_ERR_BUF_TOO_SHORT = -43,
+ IRDMA_ERR_BAD_IWARP_CQE = -44,
+ IRDMA_ERR_NVM_BLANK_MODE = -45,
+ IRDMA_ERR_NOT_IMPL = -46,
+ IRDMA_ERR_PE_DOORBELL_NOT_ENA = -47,
+ IRDMA_ERR_NOT_READY = -48,
+ IRDMA_NOT_SUPPORTED = -49,
+ IRDMA_ERR_FIRMWARE_API_VER = -50,
+ IRDMA_ERR_RING_FULL = -51,
+ IRDMA_ERR_MPA_CRC = -61,
+ IRDMA_ERR_NO_TXBUFS = -62,
+ IRDMA_ERR_SEQ_NUM = -63,
+ IRDMA_ERR_list_empty = -64,
+ IRDMA_ERR_INVALID_MAC_ADDR = -65,
+ IRDMA_ERR_BAD_STAG = -66,
+ IRDMA_ERR_CQ_COMPL_ERROR = -67,
+ IRDMA_ERR_Q_DESTROYED = -68,
+ IRDMA_ERR_INVALID_FEAT_CNT = -69,
+ IRDMA_ERR_REG_CQ_FULL = -70,
+ IRDMA_ERR_VF_MSG_ERROR = -71,
+ IRDMA_ERR_NO_INTR = -72,
+ IRDMA_ERR_REG_QSET = -73,
+};
+#endif /* IRDMA_STATUS_H */
diff --git a/drivers/infiniband/hw/irdma/trace.c b/drivers/infiniband/hw/irdma/trace.c
new file mode 100644
index 000000000000..b5133f4137e0
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/trace.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2019 Intel Corporation */
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+const char *print_ip_addr(struct trace_seq *p, u32 *addr, u16 port, bool ipv4)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+
+ if (ipv4) {
+ __be32 myaddr = htonl(*addr);
+
+ trace_seq_printf(p, "%pI4:%d", &myaddr, htons(port));
+ } else {
+ trace_seq_printf(p, "%pI6:%d", addr, htons(port));
+ }
+ trace_seq_putc(p, 0);
+
+ return ret;
+}
+
+const char *parse_iw_event_type(enum iw_cm_event_type iw_type)
+{
+ switch (iw_type) {
+ case IW_CM_EVENT_CONNECT_REQUEST:
+ return "IwRequest";
+ case IW_CM_EVENT_CONNECT_REPLY:
+ return "IwReply";
+ case IW_CM_EVENT_ESTABLISHED:
+ return "IwEstablished";
+ case IW_CM_EVENT_DISCONNECT:
+ return "IwDisconnect";
+ case IW_CM_EVENT_CLOSE:
+ return "IwClose";
+ }
+
+ return "Unknown";
+}
+
+const char *parse_cm_event_type(enum irdma_cm_event_type cm_type)
+{
+ switch (cm_type) {
+ case IRDMA_CM_EVENT_ESTABLISHED:
+ return "CmEstablished";
+ case IRDMA_CM_EVENT_MPA_REQ:
+ return "CmMPA_REQ";
+ case IRDMA_CM_EVENT_MPA_CONNECT:
+ return "CmMPA_CONNECT";
+ case IRDMA_CM_EVENT_MPA_ACCEPT:
+ return "CmMPA_ACCEPT";
+ case IRDMA_CM_EVENT_MPA_REJECT:
+ return "CmMPA_REJECT";
+ case IRDMA_CM_EVENT_MPA_ESTABLISHED:
+ return "CmMPA_ESTABLISHED";
+ case IRDMA_CM_EVENT_CONNECTED:
+ return "CmConnected";
+ case IRDMA_CM_EVENT_RESET:
+ return "CmReset";
+ case IRDMA_CM_EVENT_ABORTED:
+ return "CmAborted";
+ case IRDMA_CM_EVENT_UNKNOWN:
+ return "none";
+ }
+ return "Unknown";
+}
+
+const char *parse_cm_state(enum irdma_cm_node_state state)
+{
+ switch (state) {
+ case IRDMA_CM_STATE_UNKNOWN:
+ return "UNKNOWN";
+ case IRDMA_CM_STATE_INITED:
+ return "INITED";
+ case IRDMA_CM_STATE_LISTENING:
+ return "LISTENING";
+ case IRDMA_CM_STATE_SYN_RCVD:
+ return "SYN_RCVD";
+ case IRDMA_CM_STATE_SYN_SENT:
+ return "SYN_SENT";
+ case IRDMA_CM_STATE_ONE_SIDE_ESTABLISHED:
+ return "ONE_SIDE_ESTABLISHED";
+ case IRDMA_CM_STATE_ESTABLISHED:
+ return "ESTABLISHED";
+ case IRDMA_CM_STATE_ACCEPTING:
+ return "ACCEPTING";
+ case IRDMA_CM_STATE_MPAREQ_SENT:
+ return "MPAREQ_SENT";
+ case IRDMA_CM_STATE_MPAREQ_RCVD:
+ return "MPAREQ_RCVD";
+ case IRDMA_CM_STATE_MPAREJ_RCVD:
+ return "MPAREJ_RECVD";
+ case IRDMA_CM_STATE_OFFLOADED:
+ return "OFFLOADED";
+ case IRDMA_CM_STATE_FIN_WAIT1:
+ return "FIN_WAIT1";
+ case IRDMA_CM_STATE_FIN_WAIT2:
+ return "FIN_WAIT2";
+ case IRDMA_CM_STATE_CLOSE_WAIT:
+ return "CLOSE_WAIT";
+ case IRDMA_CM_STATE_TIME_WAIT:
+ return "TIME_WAIT";
+ case IRDMA_CM_STATE_LAST_ACK:
+ return "LAST_ACK";
+ case IRDMA_CM_STATE_CLOSING:
+ return "CLOSING";
+ case IRDMA_CM_STATE_LISTENER_DESTROYED:
+ return "LISTENER_DESTROYED";
+ case IRDMA_CM_STATE_CLOSED:
+ return "CLOSED";
+ }
+ return ("Bad state");
+}
diff --git a/drivers/infiniband/hw/irdma/trace.h b/drivers/infiniband/hw/irdma/trace.h
new file mode 100644
index 000000000000..702e4efb018d
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/trace.h
@@ -0,0 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2019 Intel Corporation */
+#include "trace_cm.h"
diff --git a/drivers/infiniband/hw/irdma/trace_cm.h b/drivers/infiniband/hw/irdma/trace_cm.h
new file mode 100644
index 000000000000..bcf10ec427d6
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/trace_cm.h
@@ -0,0 +1,458 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2019 - 2021 Intel Corporation */
+#if !defined(__TRACE_CM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __TRACE_CM_H
+
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+
+#include "main.h"
+
+const char *print_ip_addr(struct trace_seq *p, u32 *addr, u16 port, bool ivp4);
+const char *parse_iw_event_type(enum iw_cm_event_type iw_type);
+const char *parse_cm_event_type(enum irdma_cm_event_type cm_type);
+const char *parse_cm_state(enum irdma_cm_node_state);
+#define __print_ip_addr(addr, port, ipv4) print_ip_addr(p, addr, port, ipv4)
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM irdma_cm
+
+TRACE_EVENT(irdma_create_listen,
+ TP_PROTO(struct irdma_device *iwdev, struct irdma_cm_info *cm_info),
+ TP_ARGS(iwdev, cm_info),
+ TP_STRUCT__entry(__field(struct irdma_device *, iwdev)
+ __dynamic_array(u32, laddr, 4)
+ __field(u16, lport)
+ __field(bool, ipv4)
+ ),
+ TP_fast_assign(__entry->iwdev = iwdev;
+ __entry->lport = cm_info->loc_port;
+ __entry->ipv4 = cm_info->ipv4;
+ memcpy(__get_dynamic_array(laddr),
+ cm_info->loc_addr, 4);
+ ),
+ TP_printk("iwdev=%p loc: %s",
+ __entry->iwdev,
+ __print_ip_addr(__get_dynamic_array(laddr),
+ __entry->lport, __entry->ipv4)
+ )
+);
+
+TRACE_EVENT(irdma_dec_refcnt_listen,
+ TP_PROTO(struct irdma_cm_listener *listener, void *caller),
+ TP_ARGS(listener, caller),
+ TP_STRUCT__entry(__field(struct irdma_device *, iwdev)
+ __field(u32, refcnt)
+ __dynamic_array(u32, laddr, 4)
+ __field(u16, lport)
+ __field(bool, ipv4)
+ __field(void *, caller)
+ ),
+ TP_fast_assign(__entry->iwdev = listener->iwdev;
+ __entry->lport = listener->loc_port;
+ __entry->ipv4 = listener->ipv4;
+ memcpy(__get_dynamic_array(laddr),
+ listener->loc_addr, 4);
+ ),
+ TP_printk("iwdev=%p caller=%pS loc: %s",
+ __entry->iwdev,
+ __entry->caller,
+ __print_ip_addr(__get_dynamic_array(laddr),
+ __entry->lport, __entry->ipv4)
+ )
+);
+
+DECLARE_EVENT_CLASS(listener_template,
+ TP_PROTO(struct irdma_cm_listener *listener),
+ TP_ARGS(listener),
+ TP_STRUCT__entry(__field(struct irdma_device *, iwdev)
+ __field(u16, lport)
+ __field(u16, vlan_id)
+ __field(bool, ipv4)
+ __field(enum irdma_cm_listener_state,
+ state)
+ __dynamic_array(u32, laddr, 4)
+ ),
+ TP_fast_assign(__entry->iwdev = listener->iwdev;
+ __entry->lport = listener->loc_port;
+ __entry->vlan_id = listener->vlan_id;
+ __entry->ipv4 = listener->ipv4;
+ __entry->state = listener->listener_state;
+ memcpy(__get_dynamic_array(laddr),
+ listener->loc_addr, 4);
+ ),
+ TP_printk("iwdev=%p vlan=%d loc: %s",
+ __entry->iwdev,
+ __entry->vlan_id,
+ __print_ip_addr(__get_dynamic_array(laddr),
+ __entry->lport, __entry->ipv4)
+ )
+);
+
+DEFINE_EVENT(listener_template, irdma_find_listener,
+ TP_PROTO(struct irdma_cm_listener *listener),
+ TP_ARGS(listener));
+
+DEFINE_EVENT(listener_template, irdma_del_multiple_qhash,
+ TP_PROTO(struct irdma_cm_listener *listener),
+ TP_ARGS(listener));
+
+TRACE_EVENT(irdma_negotiate_mpa_v2,
+ TP_PROTO(struct irdma_cm_node *cm_node),
+ TP_ARGS(cm_node),
+ TP_STRUCT__entry(__field(struct irdma_cm_node *, cm_node)
+ __field(u16, ord_size)
+ __field(u16, ird_size)
+ ),
+ TP_fast_assign(__entry->cm_node = cm_node;
+ __entry->ord_size = cm_node->ord_size;
+ __entry->ird_size = cm_node->ird_size;
+ ),
+ TP_printk("MPVA2 Negotiated cm_node=%p ORD:[%d], IRD:[%d]",
+ __entry->cm_node,
+ __entry->ord_size,
+ __entry->ird_size
+ )
+);
+
+DECLARE_EVENT_CLASS(tos_template,
+ TP_PROTO(struct irdma_device *iwdev, u8 tos, u8 user_pri),
+ TP_ARGS(iwdev, tos, user_pri),
+ TP_STRUCT__entry(__field(struct irdma_device *, iwdev)
+ __field(u8, tos)
+ __field(u8, user_pri)
+ ),
+ TP_fast_assign(__entry->iwdev = iwdev;
+ __entry->tos = tos;
+ __entry->user_pri = user_pri;
+ ),
+ TP_printk("iwdev=%p TOS:[%d] UP:[%d]",
+ __entry->iwdev,
+ __entry->tos,
+ __entry->user_pri
+ )
+);
+
+DEFINE_EVENT(tos_template, irdma_listener_tos,
+ TP_PROTO(struct irdma_device *iwdev, u8 tos, u8 user_pri),
+ TP_ARGS(iwdev, tos, user_pri));
+
+DEFINE_EVENT(tos_template, irdma_dcb_tos,
+ TP_PROTO(struct irdma_device *iwdev, u8 tos, u8 user_pri),
+ TP_ARGS(iwdev, tos, user_pri));
+
+DECLARE_EVENT_CLASS(qhash_template,
+ TP_PROTO(struct irdma_device *iwdev,
+ struct irdma_cm_listener *listener,
+ char *dev_addr),
+ TP_ARGS(iwdev, listener, dev_addr),
+ TP_STRUCT__entry(__field(struct irdma_device *, iwdev)
+ __field(u16, lport)
+ __field(u16, vlan_id)
+ __field(bool, ipv4)
+ __dynamic_array(u32, laddr, 4)
+ __dynamic_array(u32, mac, ETH_ALEN)
+ ),
+ TP_fast_assign(__entry->iwdev = iwdev;
+ __entry->lport = listener->loc_port;
+ __entry->vlan_id = listener->vlan_id;
+ __entry->ipv4 = listener->ipv4;
+ memcpy(__get_dynamic_array(laddr),
+ listener->loc_addr, 4);
+ ether_addr_copy(__get_dynamic_array(mac),
+ dev_addr);
+ ),
+ TP_printk("iwdev=%p vlan=%d MAC=%6phC loc: %s",
+ __entry->iwdev,
+ __entry->vlan_id,
+ __get_dynamic_array(mac),
+ __print_ip_addr(__get_dynamic_array(laddr),
+ __entry->lport, __entry->ipv4)
+ )
+);
+
+DEFINE_EVENT(qhash_template, irdma_add_mqh_6,
+ TP_PROTO(struct irdma_device *iwdev,
+ struct irdma_cm_listener *listener, char *dev_addr),
+ TP_ARGS(iwdev, listener, dev_addr));
+
+DEFINE_EVENT(qhash_template, irdma_add_mqh_4,
+ TP_PROTO(struct irdma_device *iwdev,
+ struct irdma_cm_listener *listener, char *dev_addr),
+ TP_ARGS(iwdev, listener, dev_addr));
+
+TRACE_EVENT(irdma_addr_resolve,
+ TP_PROTO(struct irdma_device *iwdev, char *dev_addr),
+ TP_ARGS(iwdev, dev_addr),
+ TP_STRUCT__entry(__field(struct irdma_device *, iwdev)
+ __dynamic_array(u8, mac, ETH_ALEN)
+ ),
+ TP_fast_assign(__entry->iwdev = iwdev;
+ ether_addr_copy(__get_dynamic_array(mac), dev_addr);
+ ),
+ TP_printk("iwdev=%p MAC=%6phC", __entry->iwdev,
+ __get_dynamic_array(mac)
+ )
+);
+
+TRACE_EVENT(irdma_send_cm_event,
+ TP_PROTO(struct irdma_cm_node *cm_node, struct iw_cm_id *cm_id,
+ enum iw_cm_event_type type, int status, void *caller),
+ TP_ARGS(cm_node, cm_id, type, status, caller),
+ TP_STRUCT__entry(__field(struct irdma_device *, iwdev)
+ __field(struct irdma_cm_node *, cm_node)
+ __field(struct iw_cm_id *, cm_id)
+ __field(u32, refcount)
+ __field(u16, lport)
+ __field(u16, rport)
+ __field(enum irdma_cm_node_state, state)
+ __field(bool, ipv4)
+ __field(u16, vlan_id)
+ __field(int, accel)
+ __field(enum iw_cm_event_type, type)
+ __field(int, status)
+ __field(void *, caller)
+ __dynamic_array(u32, laddr, 4)
+ __dynamic_array(u32, raddr, 4)
+ ),
+ TP_fast_assign(__entry->iwdev = cm_node->iwdev;
+ __entry->cm_node = cm_node;
+ __entry->cm_id = cm_id;
+ __entry->refcount = refcount_read(&cm_node->refcnt);
+ __entry->state = cm_node->state;
+ __entry->lport = cm_node->loc_port;
+ __entry->rport = cm_node->rem_port;
+ __entry->ipv4 = cm_node->ipv4;
+ __entry->vlan_id = cm_node->vlan_id;
+ __entry->accel = cm_node->accelerated;
+ __entry->type = type;
+ __entry->status = status;
+ __entry->caller = caller;
+ memcpy(__get_dynamic_array(laddr),
+ cm_node->loc_addr, 4);
+ memcpy(__get_dynamic_array(raddr),
+ cm_node->rem_addr, 4);
+ ),
+ TP_printk("iwdev=%p caller=%pS cm_id=%p node=%p refcnt=%d vlan_id=%d accel=%d state=%s event_type=%s status=%d loc: %s rem: %s",
+ __entry->iwdev,
+ __entry->caller,
+ __entry->cm_id,
+ __entry->cm_node,
+ __entry->refcount,
+ __entry->vlan_id,
+ __entry->accel,
+ parse_cm_state(__entry->state),
+ parse_iw_event_type(__entry->type),
+ __entry->status,
+ __print_ip_addr(__get_dynamic_array(laddr),
+ __entry->lport, __entry->ipv4),
+ __print_ip_addr(__get_dynamic_array(raddr),
+ __entry->rport, __entry->ipv4)
+ )
+);
+
+TRACE_EVENT(irdma_send_cm_event_no_node,
+ TP_PROTO(struct iw_cm_id *cm_id, enum iw_cm_event_type type,
+ int status, void *caller),
+ TP_ARGS(cm_id, type, status, caller),
+ TP_STRUCT__entry(__field(struct iw_cm_id *, cm_id)
+ __field(enum iw_cm_event_type, type)
+ __field(int, status)
+ __field(void *, caller)
+ ),
+ TP_fast_assign(__entry->cm_id = cm_id;
+ __entry->type = type;
+ __entry->status = status;
+ __entry->caller = caller;
+ ),
+ TP_printk("cm_id=%p caller=%pS event_type=%s status=%d",
+ __entry->cm_id,
+ __entry->caller,
+ parse_iw_event_type(__entry->type),
+ __entry->status
+ )
+);
+
+DECLARE_EVENT_CLASS(cm_node_template,
+ TP_PROTO(struct irdma_cm_node *cm_node,
+ enum irdma_cm_event_type type, void *caller),
+ TP_ARGS(cm_node, type, caller),
+ TP_STRUCT__entry(__field(struct irdma_device *, iwdev)
+ __field(struct irdma_cm_node *, cm_node)
+ __field(u32, refcount)
+ __field(u16, lport)
+ __field(u16, rport)
+ __field(enum irdma_cm_node_state, state)
+ __field(bool, ipv4)
+ __field(u16, vlan_id)
+ __field(int, accel)
+ __field(enum irdma_cm_event_type, type)
+ __field(void *, caller)
+ __dynamic_array(u32, laddr, 4)
+ __dynamic_array(u32, raddr, 4)
+ ),
+ TP_fast_assign(__entry->iwdev = cm_node->iwdev;
+ __entry->cm_node = cm_node;
+ __entry->refcount = refcount_read(&cm_node->refcnt);
+ __entry->state = cm_node->state;
+ __entry->lport = cm_node->loc_port;
+ __entry->rport = cm_node->rem_port;
+ __entry->ipv4 = cm_node->ipv4;
+ __entry->vlan_id = cm_node->vlan_id;
+ __entry->accel = cm_node->accelerated;
+ __entry->type = type;
+ __entry->caller = caller;
+ memcpy(__get_dynamic_array(laddr),
+ cm_node->loc_addr, 4);
+ memcpy(__get_dynamic_array(raddr),
+ cm_node->rem_addr, 4);
+ ),
+ TP_printk("iwdev=%p caller=%pS node=%p refcnt=%d vlan_id=%d accel=%d state=%s event_type=%s loc: %s rem: %s",
+ __entry->iwdev,
+ __entry->caller,
+ __entry->cm_node,
+ __entry->refcount,
+ __entry->vlan_id,
+ __entry->accel,
+ parse_cm_state(__entry->state),
+ parse_cm_event_type(__entry->type),
+ __print_ip_addr(__get_dynamic_array(laddr),
+ __entry->lport, __entry->ipv4),
+ __print_ip_addr(__get_dynamic_array(raddr),
+ __entry->rport, __entry->ipv4)
+ )
+);
+
+DEFINE_EVENT(cm_node_template, irdma_create_event,
+ TP_PROTO(struct irdma_cm_node *cm_node,
+ enum irdma_cm_event_type type, void *caller),
+ TP_ARGS(cm_node, type, caller));
+
+DEFINE_EVENT(cm_node_template, irdma_accept,
+ TP_PROTO(struct irdma_cm_node *cm_node,
+ enum irdma_cm_event_type type, void *caller),
+ TP_ARGS(cm_node, type, caller));
+
+DEFINE_EVENT(cm_node_template, irdma_connect,
+ TP_PROTO(struct irdma_cm_node *cm_node,
+ enum irdma_cm_event_type type, void *caller),
+ TP_ARGS(cm_node, type, caller));
+
+DEFINE_EVENT(cm_node_template, irdma_reject,
+ TP_PROTO(struct irdma_cm_node *cm_node,
+ enum irdma_cm_event_type type, void *caller),
+ TP_ARGS(cm_node, type, caller));
+
+DEFINE_EVENT(cm_node_template, irdma_find_node,
+ TP_PROTO(struct irdma_cm_node *cm_node,
+ enum irdma_cm_event_type type, void *caller),
+ TP_ARGS(cm_node, type, caller));
+
+DEFINE_EVENT(cm_node_template, irdma_send_reset,
+ TP_PROTO(struct irdma_cm_node *cm_node,
+ enum irdma_cm_event_type type, void *caller),
+ TP_ARGS(cm_node, type, caller));
+
+DEFINE_EVENT(cm_node_template, irdma_rem_ref_cm_node,
+ TP_PROTO(struct irdma_cm_node *cm_node,
+ enum irdma_cm_event_type type, void *caller),
+ TP_ARGS(cm_node, type, caller));
+
+DEFINE_EVENT(cm_node_template, irdma_cm_event_handler,
+ TP_PROTO(struct irdma_cm_node *cm_node,
+ enum irdma_cm_event_type type, void *caller),
+ TP_ARGS(cm_node, type, caller));
+
+TRACE_EVENT(open_err_template,
+ TP_PROTO(struct irdma_cm_node *cm_node, bool reset, void *caller),
+ TP_ARGS(cm_node, reset, caller),
+ TP_STRUCT__entry(__field(struct irdma_device *, iwdev)
+ __field(struct irdma_cm_node *, cm_node)
+ __field(enum irdma_cm_node_state, state)
+ __field(bool, reset)
+ __field(void *, caller)
+ ),
+ TP_fast_assign(__entry->iwdev = cm_node->iwdev;
+ __entry->cm_node = cm_node;
+ __entry->state = cm_node->state;
+ __entry->reset = reset;
+ __entry->caller = caller;
+ ),
+ TP_printk("iwdev=%p caller=%pS node%p reset=%d state=%s",
+ __entry->iwdev,
+ __entry->caller,
+ __entry->cm_node,
+ __entry->reset,
+ parse_cm_state(__entry->state)
+ )
+);
+
+DEFINE_EVENT(open_err_template, irdma_active_open_err,
+ TP_PROTO(struct irdma_cm_node *cm_node, bool reset, void *caller),
+ TP_ARGS(cm_node, reset, caller));
+
+DEFINE_EVENT(open_err_template, irdma_passive_open_err,
+ TP_PROTO(struct irdma_cm_node *cm_node, bool reset, void *caller),
+ TP_ARGS(cm_node, reset, caller));
+
+DECLARE_EVENT_CLASS(cm_node_ah_template,
+ TP_PROTO(struct irdma_cm_node *cm_node),
+ TP_ARGS(cm_node),
+ TP_STRUCT__entry(__field(struct irdma_device *, iwdev)
+ __field(struct irdma_cm_node *, cm_node)
+ __field(struct irdma_sc_ah *, ah)
+ __field(u32, refcount)
+ __field(u16, lport)
+ __field(u16, rport)
+ __field(enum irdma_cm_node_state, state)
+ __field(bool, ipv4)
+ __field(u16, vlan_id)
+ __field(int, accel)
+ __dynamic_array(u32, laddr, 4)
+ __dynamic_array(u32, raddr, 4)
+ ),
+ TP_fast_assign(__entry->iwdev = cm_node->iwdev;
+ __entry->cm_node = cm_node;
+ __entry->ah = cm_node->ah;
+ __entry->refcount = refcount_read(&cm_node->refcnt);
+ __entry->lport = cm_node->loc_port;
+ __entry->rport = cm_node->rem_port;
+ __entry->state = cm_node->state;
+ __entry->ipv4 = cm_node->ipv4;
+ __entry->vlan_id = cm_node->vlan_id;
+ __entry->accel = cm_node->accelerated;
+ memcpy(__get_dynamic_array(laddr),
+ cm_node->loc_addr, 4);
+ memcpy(__get_dynamic_array(raddr),
+ cm_node->rem_addr, 4);
+ ),
+ TP_printk("iwdev=%p node=%p ah=%p refcnt=%d vlan_id=%d accel=%d state=%s loc: %s rem: %s",
+ __entry->iwdev,
+ __entry->cm_node,
+ __entry->ah,
+ __entry->refcount,
+ __entry->vlan_id,
+ __entry->accel,
+ parse_cm_state(__entry->state),
+ __print_ip_addr(__get_dynamic_array(laddr),
+ __entry->lport, __entry->ipv4),
+ __print_ip_addr(__get_dynamic_array(raddr),
+ __entry->rport, __entry->ipv4)
+ )
+);
+
+DEFINE_EVENT(cm_node_ah_template, irdma_cm_free_ah,
+ TP_PROTO(struct irdma_cm_node *cm_node),
+ TP_ARGS(cm_node));
+
+DEFINE_EVENT(cm_node_ah_template, irdma_create_ah,
+ TP_PROTO(struct irdma_cm_node *cm_node),
+ TP_ARGS(cm_node));
+
+#endif /* __TRACE_CM_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_cm
+#include <trace/define_trace.h>
diff --git a/drivers/infiniband/hw/irdma/type.h b/drivers/infiniband/hw/irdma/type.h
new file mode 100644
index 000000000000..7387b83e826d
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/type.h
@@ -0,0 +1,1541 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#ifndef IRDMA_TYPE_H
+#define IRDMA_TYPE_H
+#include "status.h"
+#include "osdep.h"
+#include "irdma.h"
+#include "user.h"
+#include "hmc.h"
+#include "uda.h"
+#include "ws.h"
+#define IRDMA_DEBUG_ERR "ERR"
+#define IRDMA_DEBUG_INIT "INIT"
+#define IRDMA_DEBUG_DEV "DEV"
+#define IRDMA_DEBUG_CM "CM"
+#define IRDMA_DEBUG_VERBS "VERBS"
+#define IRDMA_DEBUG_PUDA "PUDA"
+#define IRDMA_DEBUG_ILQ "ILQ"
+#define IRDMA_DEBUG_IEQ "IEQ"
+#define IRDMA_DEBUG_QP "QP"
+#define IRDMA_DEBUG_CQ "CQ"
+#define IRDMA_DEBUG_MR "MR"
+#define IRDMA_DEBUG_PBLE "PBLE"
+#define IRDMA_DEBUG_WQE "WQE"
+#define IRDMA_DEBUG_AEQ "AEQ"
+#define IRDMA_DEBUG_CQP "CQP"
+#define IRDMA_DEBUG_HMC "HMC"
+#define IRDMA_DEBUG_USER "USER"
+#define IRDMA_DEBUG_VIRT "VIRT"
+#define IRDMA_DEBUG_DCB "DCB"
+#define IRDMA_DEBUG_CQE "CQE"
+#define IRDMA_DEBUG_CLNT "CLNT"
+#define IRDMA_DEBUG_WS "WS"
+#define IRDMA_DEBUG_STATS "STATS"
+
+enum irdma_page_size {
+ IRDMA_PAGE_SIZE_4K = 0,
+ IRDMA_PAGE_SIZE_2M,
+ IRDMA_PAGE_SIZE_1G,
+};
+
+enum irdma_hdrct_flags {
+ DDP_LEN_FLAG = 0x80,
+ DDP_HDR_FLAG = 0x40,
+ RDMA_HDR_FLAG = 0x20,
+};
+
+enum irdma_term_layers {
+ LAYER_RDMA = 0,
+ LAYER_DDP = 1,
+ LAYER_MPA = 2,
+};
+
+enum irdma_term_error_types {
+ RDMAP_REMOTE_PROT = 1,
+ RDMAP_REMOTE_OP = 2,
+ DDP_CATASTROPHIC = 0,
+ DDP_TAGGED_BUF = 1,
+ DDP_UNTAGGED_BUF = 2,
+ DDP_LLP = 3,
+};
+
+enum irdma_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 irdma_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 irdma_term_mpa_errors {
+ MPA_CLOSED = 0x01,
+ MPA_CRC = 0x02,
+ MPA_MARKER = 0x03,
+ MPA_REQ_RSP = 0x04,
+};
+
+enum irdma_qp_event_type {
+ IRDMA_QP_EVENT_CATASTROPHIC,
+ IRDMA_QP_EVENT_ACCESS_ERR,
+};
+
+enum irdma_hw_stats_index_32b {
+ IRDMA_HW_STAT_INDEX_IP4RXDISCARD = 0,
+ IRDMA_HW_STAT_INDEX_IP4RXTRUNC = 1,
+ IRDMA_HW_STAT_INDEX_IP4TXNOROUTE = 2,
+ IRDMA_HW_STAT_INDEX_IP6RXDISCARD = 3,
+ IRDMA_HW_STAT_INDEX_IP6RXTRUNC = 4,
+ IRDMA_HW_STAT_INDEX_IP6TXNOROUTE = 5,
+ IRDMA_HW_STAT_INDEX_TCPRTXSEG = 6,
+ IRDMA_HW_STAT_INDEX_TCPRXOPTERR = 7,
+ IRDMA_HW_STAT_INDEX_TCPRXPROTOERR = 8,
+ IRDMA_HW_STAT_INDEX_MAX_32_GEN_1 = 9, /* Must be same value as next entry */
+ IRDMA_HW_STAT_INDEX_RXVLANERR = 9,
+ IRDMA_HW_STAT_INDEX_RXRPCNPHANDLED = 10,
+ IRDMA_HW_STAT_INDEX_RXRPCNPIGNORED = 11,
+ IRDMA_HW_STAT_INDEX_TXNPCNPSENT = 12,
+ IRDMA_HW_STAT_INDEX_MAX_32, /* Must be last entry */
+};
+
+enum irdma_hw_stats_index_64b {
+ IRDMA_HW_STAT_INDEX_IP4RXOCTS = 0,
+ IRDMA_HW_STAT_INDEX_IP4RXPKTS = 1,
+ IRDMA_HW_STAT_INDEX_IP4RXFRAGS = 2,
+ IRDMA_HW_STAT_INDEX_IP4RXMCPKTS = 3,
+ IRDMA_HW_STAT_INDEX_IP4TXOCTS = 4,
+ IRDMA_HW_STAT_INDEX_IP4TXPKTS = 5,
+ IRDMA_HW_STAT_INDEX_IP4TXFRAGS = 6,
+ IRDMA_HW_STAT_INDEX_IP4TXMCPKTS = 7,
+ IRDMA_HW_STAT_INDEX_IP6RXOCTS = 8,
+ IRDMA_HW_STAT_INDEX_IP6RXPKTS = 9,
+ IRDMA_HW_STAT_INDEX_IP6RXFRAGS = 10,
+ IRDMA_HW_STAT_INDEX_IP6RXMCPKTS = 11,
+ IRDMA_HW_STAT_INDEX_IP6TXOCTS = 12,
+ IRDMA_HW_STAT_INDEX_IP6TXPKTS = 13,
+ IRDMA_HW_STAT_INDEX_IP6TXFRAGS = 14,
+ IRDMA_HW_STAT_INDEX_IP6TXMCPKTS = 15,
+ IRDMA_HW_STAT_INDEX_TCPRXSEGS = 16,
+ IRDMA_HW_STAT_INDEX_TCPTXSEG = 17,
+ IRDMA_HW_STAT_INDEX_RDMARXRDS = 18,
+ IRDMA_HW_STAT_INDEX_RDMARXSNDS = 19,
+ IRDMA_HW_STAT_INDEX_RDMARXWRS = 20,
+ IRDMA_HW_STAT_INDEX_RDMATXRDS = 21,
+ IRDMA_HW_STAT_INDEX_RDMATXSNDS = 22,
+ IRDMA_HW_STAT_INDEX_RDMATXWRS = 23,
+ IRDMA_HW_STAT_INDEX_RDMAVBND = 24,
+ IRDMA_HW_STAT_INDEX_RDMAVINV = 25,
+ IRDMA_HW_STAT_INDEX_MAX_64_GEN_1 = 26, /* Must be same value as next entry */
+ IRDMA_HW_STAT_INDEX_IP4RXMCOCTS = 26,
+ IRDMA_HW_STAT_INDEX_IP4TXMCOCTS = 27,
+ IRDMA_HW_STAT_INDEX_IP6RXMCOCTS = 28,
+ IRDMA_HW_STAT_INDEX_IP6TXMCOCTS = 29,
+ IRDMA_HW_STAT_INDEX_UDPRXPKTS = 30,
+ IRDMA_HW_STAT_INDEX_UDPTXPKTS = 31,
+ IRDMA_HW_STAT_INDEX_RXNPECNMARKEDPKTS = 32,
+ IRDMA_HW_STAT_INDEX_MAX_64, /* Must be last entry */
+};
+
+enum irdma_feature_type {
+ IRDMA_FEATURE_FW_INFO = 0,
+ IRDMA_HW_VERSION_INFO = 1,
+ IRDMA_QSETS_MAX = 26,
+ IRDMA_MAX_FEATURES, /* Must be last entry */
+};
+
+enum irdma_sched_prio_type {
+ IRDMA_PRIO_WEIGHTED_RR = 1,
+ IRDMA_PRIO_STRICT = 2,
+ IRDMA_PRIO_WEIGHTED_STRICT = 3,
+};
+
+enum irdma_vm_vf_type {
+ IRDMA_VF_TYPE = 0,
+ IRDMA_VM_TYPE,
+ IRDMA_PF_TYPE,
+};
+
+enum irdma_cqp_hmc_profile {
+ IRDMA_HMC_PROFILE_DEFAULT = 1,
+ IRDMA_HMC_PROFILE_FAVOR_VF = 2,
+ IRDMA_HMC_PROFILE_EQUAL = 3,
+};
+
+enum irdma_quad_entry_type {
+ IRDMA_QHASH_TYPE_TCP_ESTABLISHED = 1,
+ IRDMA_QHASH_TYPE_TCP_SYN,
+ IRDMA_QHASH_TYPE_UDP_UNICAST,
+ IRDMA_QHASH_TYPE_UDP_MCAST,
+ IRDMA_QHASH_TYPE_ROCE_MCAST,
+ IRDMA_QHASH_TYPE_ROCEV2_HW,
+};
+
+enum irdma_quad_hash_manage_type {
+ IRDMA_QHASH_MANAGE_TYPE_DELETE = 0,
+ IRDMA_QHASH_MANAGE_TYPE_ADD,
+ IRDMA_QHASH_MANAGE_TYPE_MODIFY,
+};
+
+enum irdma_syn_rst_handling {
+ IRDMA_SYN_RST_HANDLING_HW_TCP_SECURE = 0,
+ IRDMA_SYN_RST_HANDLING_HW_TCP,
+ IRDMA_SYN_RST_HANDLING_FW_TCP_SECURE,
+ IRDMA_SYN_RST_HANDLING_FW_TCP,
+};
+
+enum irdma_queue_type {
+ IRDMA_QUEUE_TYPE_SQ_RQ = 0,
+ IRDMA_QUEUE_TYPE_CQP,
+};
+
+struct irdma_sc_dev;
+struct irdma_vsi_pestat;
+
+struct irdma_dcqcn_cc_params {
+ u8 cc_cfg_valid;
+ u8 min_dec_factor;
+ u8 min_rate;
+ u8 dcqcn_f;
+ u16 rai_factor;
+ u16 hai_factor;
+ u16 dcqcn_t;
+ u32 dcqcn_b;
+ u32 rreduce_mperiod;
+};
+
+struct irdma_cqp_init_info {
+ u64 cqp_compl_ctx;
+ u64 host_ctx_pa;
+ u64 sq_pa;
+ struct irdma_sc_dev *dev;
+ struct irdma_cqp_quanta *sq;
+ struct irdma_dcqcn_cc_params dcqcn_params;
+ __le64 *host_ctx;
+ u64 *scratch_array;
+ u32 sq_size;
+ u16 hw_maj_ver;
+ u16 hw_min_ver;
+ u8 struct_ver;
+ u8 hmc_profile;
+ u8 ena_vf_count;
+ u8 ceqs_per_vf;
+ bool en_datacenter_tcp:1;
+ bool disable_packed:1;
+ bool rocev2_rto_policy:1;
+ enum irdma_protocol_used protocol_used;
+};
+
+struct irdma_terminate_hdr {
+ u8 layer_etype;
+ u8 error_code;
+ u8 hdrct;
+ u8 rsvd;
+};
+
+struct irdma_cqp_sq_wqe {
+ __le64 buf[IRDMA_CQP_WQE_SIZE];
+};
+
+struct irdma_sc_aeqe {
+ __le64 buf[IRDMA_AEQE_SIZE];
+};
+
+struct irdma_ceqe {
+ __le64 buf[IRDMA_CEQE_SIZE];
+};
+
+struct irdma_cqp_ctx {
+ __le64 buf[IRDMA_CQP_CTX_SIZE];
+};
+
+struct irdma_cq_shadow_area {
+ __le64 buf[IRDMA_SHADOW_AREA_SIZE];
+};
+
+struct irdma_dev_hw_stats_offsets {
+ u32 stats_offset_32[IRDMA_HW_STAT_INDEX_MAX_32];
+ u32 stats_offset_64[IRDMA_HW_STAT_INDEX_MAX_64];
+};
+
+struct irdma_dev_hw_stats {
+ u64 stats_val_32[IRDMA_HW_STAT_INDEX_MAX_32];
+ u64 stats_val_64[IRDMA_HW_STAT_INDEX_MAX_64];
+};
+
+struct irdma_gather_stats {
+ u32 rsvd1;
+ u32 rxvlanerr;
+ u64 ip4rxocts;
+ u64 ip4rxpkts;
+ u32 ip4rxtrunc;
+ u32 ip4rxdiscard;
+ u64 ip4rxfrags;
+ u64 ip4rxmcocts;
+ u64 ip4rxmcpkts;
+ u64 ip6rxocts;
+ u64 ip6rxpkts;
+ u32 ip6rxtrunc;
+ u32 ip6rxdiscard;
+ u64 ip6rxfrags;
+ u64 ip6rxmcocts;
+ u64 ip6rxmcpkts;
+ u64 ip4txocts;
+ u64 ip4txpkts;
+ u64 ip4txfrag;
+ u64 ip4txmcocts;
+ u64 ip4txmcpkts;
+ u64 ip6txocts;
+ u64 ip6txpkts;
+ u64 ip6txfrags;
+ u64 ip6txmcocts;
+ u64 ip6txmcpkts;
+ u32 ip6txnoroute;
+ u32 ip4txnoroute;
+ u64 tcprxsegs;
+ u32 tcprxprotoerr;
+ u32 tcprxopterr;
+ u64 tcptxsegs;
+ u32 rsvd2;
+ u32 tcprtxseg;
+ u64 udprxpkts;
+ u64 udptxpkts;
+ u64 rdmarxwrs;
+ u64 rdmarxrds;
+ u64 rdmarxsnds;
+ u64 rdmatxwrs;
+ u64 rdmatxrds;
+ u64 rdmatxsnds;
+ u64 rdmavbn;
+ u64 rdmavinv;
+ u64 rxnpecnmrkpkts;
+ u32 rxrpcnphandled;
+ u32 rxrpcnpignored;
+ u32 txnpcnpsent;
+ u32 rsvd3[88];
+};
+
+struct irdma_stats_gather_info {
+ bool use_hmc_fcn_index:1;
+ bool use_stats_inst:1;
+ u8 hmc_fcn_index;
+ u8 stats_inst_index;
+ struct irdma_dma_mem stats_buff_mem;
+ void *gather_stats_va;
+ void *last_gather_stats_va;
+};
+
+struct irdma_vsi_pestat {
+ struct irdma_hw *hw;
+ struct irdma_dev_hw_stats hw_stats;
+ struct irdma_stats_gather_info gather_info;
+ struct timer_list stats_timer;
+ struct irdma_sc_vsi *vsi;
+ struct irdma_dev_hw_stats last_hw_stats;
+ spinlock_t lock; /* rdma stats lock */
+};
+
+struct irdma_hw {
+ u8 __iomem *hw_addr;
+ u8 __iomem *priv_hw_addr;
+ struct device *device;
+ struct irdma_hmc_info hmc;
+};
+
+struct irdma_pfpdu {
+ struct list_head rxlist;
+ u32 rcv_nxt;
+ u32 fps;
+ u32 max_fpdu_data;
+ u32 nextseqnum;
+ u32 rcv_start_seq;
+ bool mode:1;
+ bool mpa_crc_err:1;
+ u8 marker_len;
+ u64 total_ieq_bufs;
+ u64 fpdu_processed;
+ u64 bad_seq_num;
+ u64 crc_err;
+ u64 no_tx_bufs;
+ u64 tx_err;
+ u64 out_of_order;
+ u64 pmode_count;
+ struct irdma_sc_ah *ah;
+ struct irdma_puda_buf *ah_buf;
+ spinlock_t lock; /* fpdu processing lock */
+ struct irdma_puda_buf *lastrcv_buf;
+};
+
+struct irdma_sc_pd {
+ struct irdma_sc_dev *dev;
+ u32 pd_id;
+ int abi_ver;
+};
+
+struct irdma_cqp_quanta {
+ __le64 elem[IRDMA_CQP_WQE_SIZE];
+};
+
+struct irdma_sc_cqp {
+ u32 size;
+ u64 sq_pa;
+ u64 host_ctx_pa;
+ void *back_cqp;
+ struct irdma_sc_dev *dev;
+ enum irdma_status_code (*process_cqp_sds)(struct irdma_sc_dev *dev,
+ struct irdma_update_sds_info *info);
+ struct irdma_dma_mem sdbuf;
+ struct irdma_ring sq_ring;
+ struct irdma_cqp_quanta *sq_base;
+ struct irdma_dcqcn_cc_params dcqcn_params;
+ __le64 *host_ctx;
+ u64 *scratch_array;
+ u32 cqp_id;
+ u32 sq_size;
+ u32 hw_sq_size;
+ u16 hw_maj_ver;
+ u16 hw_min_ver;
+ u8 struct_ver;
+ u8 polarity;
+ u8 hmc_profile;
+ u8 ena_vf_count;
+ u8 timeout_count;
+ u8 ceqs_per_vf;
+ bool en_datacenter_tcp:1;
+ bool disable_packed:1;
+ bool rocev2_rto_policy:1;
+ enum irdma_protocol_used protocol_used;
+};
+
+struct irdma_sc_aeq {
+ u32 size;
+ u64 aeq_elem_pa;
+ struct irdma_sc_dev *dev;
+ struct irdma_sc_aeqe *aeqe_base;
+ void *pbl_list;
+ u32 elem_cnt;
+ struct irdma_ring aeq_ring;
+ u8 pbl_chunk_size;
+ u32 first_pm_pbl_idx;
+ u32 msix_idx;
+ u8 polarity;
+ bool virtual_map:1;
+};
+
+struct irdma_sc_ceq {
+ u32 size;
+ u64 ceq_elem_pa;
+ struct irdma_sc_dev *dev;
+ struct irdma_ceqe *ceqe_base;
+ void *pbl_list;
+ u32 ceq_id;
+ u32 elem_cnt;
+ struct irdma_ring ceq_ring;
+ u8 pbl_chunk_size;
+ u8 tph_val;
+ u32 first_pm_pbl_idx;
+ u8 polarity;
+ struct irdma_sc_vsi *vsi;
+ struct irdma_sc_cq **reg_cq;
+ u32 reg_cq_size;
+ spinlock_t req_cq_lock; /* protect access to reg_cq array */
+ bool virtual_map:1;
+ bool tph_en:1;
+ bool itr_no_expire:1;
+};
+
+struct irdma_sc_cq {
+ struct irdma_cq_uk cq_uk;
+ u64 cq_pa;
+ u64 shadow_area_pa;
+ struct irdma_sc_dev *dev;
+ struct irdma_sc_vsi *vsi;
+ void *pbl_list;
+ void *back_cq;
+ u32 ceq_id;
+ u32 shadow_read_threshold;
+ u8 pbl_chunk_size;
+ u8 cq_type;
+ u8 tph_val;
+ u32 first_pm_pbl_idx;
+ bool ceqe_mask:1;
+ bool virtual_map:1;
+ bool check_overflow:1;
+ bool ceq_id_valid:1;
+ bool tph_en;
+};
+
+struct irdma_sc_qp {
+ struct irdma_qp_uk qp_uk;
+ u64 sq_pa;
+ u64 rq_pa;
+ u64 hw_host_ctx_pa;
+ u64 shadow_area_pa;
+ u64 q2_pa;
+ struct irdma_sc_dev *dev;
+ struct irdma_sc_vsi *vsi;
+ struct irdma_sc_pd *pd;
+ __le64 *hw_host_ctx;
+ void *llp_stream_handle;
+ struct irdma_pfpdu pfpdu;
+ u32 ieq_qp;
+ u8 *q2_buf;
+ u64 qp_compl_ctx;
+ u32 push_idx;
+ u16 qs_handle;
+ u16 push_offset;
+ u8 flush_wqes_count;
+ u8 sq_tph_val;
+ u8 rq_tph_val;
+ u8 qp_state;
+ u8 hw_sq_size;
+ u8 hw_rq_size;
+ u8 src_mac_addr_idx;
+ bool on_qoslist:1;
+ bool ieq_pass_thru:1;
+ bool sq_tph_en:1;
+ bool rq_tph_en:1;
+ bool rcv_tph_en:1;
+ bool xmit_tph_en:1;
+ bool virtual_map:1;
+ bool flush_sq:1;
+ bool flush_rq:1;
+ bool sq_flush_code:1;
+ bool rq_flush_code:1;
+ enum irdma_flush_opcode flush_code;
+ enum irdma_qp_event_type event_type;
+ u8 term_flags;
+ u8 user_pri;
+ struct list_head list;
+};
+
+struct irdma_stats_inst_info {
+ bool use_hmc_fcn_index;
+ u8 hmc_fn_id;
+ u8 stats_idx;
+};
+
+struct irdma_up_info {
+ u8 map[8];
+ u8 cnp_up_override;
+ u8 hmc_fcn_idx;
+ bool use_vlan:1;
+ bool use_cnp_up_override:1;
+};
+
+#define IRDMA_MAX_WS_NODES 0x3FF
+#define IRDMA_WS_NODE_INVALID 0xFFFF
+
+struct irdma_ws_node_info {
+ u16 id;
+ u16 vsi;
+ u16 parent_id;
+ u16 qs_handle;
+ bool type_leaf:1;
+ bool enable:1;
+ u8 prio_type;
+ u8 tc;
+ u8 weight;
+};
+
+struct irdma_hmc_fpm_misc {
+ u32 max_ceqs;
+ u32 max_sds;
+ u32 xf_block_size;
+ u32 q1_block_size;
+ u32 ht_multiplier;
+ u32 timer_bucket;
+ u32 rrf_block_size;
+ u32 ooiscf_block_size;
+};
+
+#define IRDMA_LEAF_DEFAULT_REL_BW 64
+#define IRDMA_PARENT_DEFAULT_REL_BW 1
+
+struct irdma_qos {
+ struct list_head qplist;
+ struct mutex qos_mutex; /* protect QoS attributes per QoS level */
+ u64 lan_qos_handle;
+ u32 l2_sched_node_id;
+ u16 qs_handle;
+ u8 traffic_class;
+ u8 rel_bw;
+ u8 prio_type;
+ bool valid;
+};
+
+#define IRDMA_INVALID_FCN_ID 0xff
+struct irdma_sc_vsi {
+ u16 vsi_idx;
+ struct irdma_sc_dev *dev;
+ void *back_vsi;
+ u32 ilq_count;
+ struct irdma_virt_mem ilq_mem;
+ struct irdma_puda_rsrc *ilq;
+ u32 ieq_count;
+ struct irdma_virt_mem ieq_mem;
+ struct irdma_puda_rsrc *ieq;
+ u32 exception_lan_q;
+ u16 mtu;
+ u16 vm_id;
+ u8 fcn_id;
+ enum irdma_vm_vf_type vm_vf_type;
+ bool stats_fcn_id_alloc:1;
+ bool tc_change_pending:1;
+ struct irdma_qos qos[IRDMA_MAX_USER_PRIORITY];
+ struct irdma_vsi_pestat *pestat;
+ atomic_t qp_suspend_reqs;
+ enum irdma_status_code (*register_qset)(struct irdma_sc_vsi *vsi,
+ struct irdma_ws_node *tc_node);
+ void (*unregister_qset)(struct irdma_sc_vsi *vsi,
+ struct irdma_ws_node *tc_node);
+ u8 qos_rel_bw;
+ u8 qos_prio_type;
+};
+
+struct irdma_sc_dev {
+ struct list_head cqp_cmd_head; /* head of the CQP command list */
+ spinlock_t cqp_lock; /* protect CQP list access */
+ bool fcn_id_array[IRDMA_MAX_STATS_COUNT];
+ struct irdma_dma_mem vf_fpm_query_buf[IRDMA_MAX_PE_ENA_VF_COUNT];
+ u64 fpm_query_buf_pa;
+ u64 fpm_commit_buf_pa;
+ __le64 *fpm_query_buf;
+ __le64 *fpm_commit_buf;
+ struct irdma_hw *hw;
+ u8 __iomem *db_addr;
+ u32 __iomem *wqe_alloc_db;
+ u32 __iomem *cq_arm_db;
+ u32 __iomem *aeq_alloc_db;
+ u32 __iomem *cqp_db;
+ u32 __iomem *cq_ack_db;
+ u32 __iomem *ceq_itr_mask_db;
+ u32 __iomem *aeq_itr_mask_db;
+ u32 __iomem *hw_regs[IRDMA_MAX_REGS];
+ u32 ceq_itr; /* Interrupt throttle, usecs between interrupts: 0 disabled. 2 - 8160 */
+ u64 hw_masks[IRDMA_MAX_MASKS];
+ u64 hw_shifts[IRDMA_MAX_SHIFTS];
+ u64 hw_stats_regs_32[IRDMA_HW_STAT_INDEX_MAX_32];
+ u64 hw_stats_regs_64[IRDMA_HW_STAT_INDEX_MAX_64];
+ u64 feature_info[IRDMA_MAX_FEATURES];
+ u64 cqp_cmd_stats[IRDMA_MAX_CQP_OPS];
+ struct irdma_hw_attrs hw_attrs;
+ struct irdma_hmc_info *hmc_info;
+ struct irdma_sc_cqp *cqp;
+ struct irdma_sc_aeq *aeq;
+ struct irdma_sc_ceq *ceq[IRDMA_CEQ_MAX_COUNT];
+ struct irdma_sc_cq *ccq;
+ const struct irdma_irq_ops *irq_ops;
+ struct irdma_hmc_fpm_misc hmc_fpm_misc;
+ struct irdma_ws_node *ws_tree_root;
+ struct mutex ws_mutex; /* ws tree mutex */
+ u16 num_vfs;
+ u8 hmc_fn_id;
+ u8 vf_id;
+ bool vchnl_up:1;
+ bool ceq_valid:1;
+ u8 pci_rev;
+ enum irdma_status_code (*ws_add)(struct irdma_sc_vsi *vsi, u8 user_pri);
+ void (*ws_remove)(struct irdma_sc_vsi *vsi, u8 user_pri);
+ void (*ws_reset)(struct irdma_sc_vsi *vsi);
+};
+
+struct irdma_modify_cq_info {
+ u64 cq_pa;
+ struct irdma_cqe *cq_base;
+ u32 cq_size;
+ u32 shadow_read_threshold;
+ u8 pbl_chunk_size;
+ u32 first_pm_pbl_idx;
+ bool virtual_map:1;
+ bool check_overflow;
+ bool cq_resize:1;
+};
+
+struct irdma_create_qp_info {
+ bool ord_valid:1;
+ bool tcp_ctx_valid:1;
+ bool cq_num_valid:1;
+ bool arp_cache_idx_valid:1;
+ bool mac_valid:1;
+ bool force_lpb;
+ u8 next_iwarp_state;
+};
+
+struct irdma_modify_qp_info {
+ u64 rx_win0;
+ u64 rx_win1;
+ u16 new_mss;
+ u8 next_iwarp_state;
+ u8 curr_iwarp_state;
+ u8 termlen;
+ bool ord_valid:1;
+ bool tcp_ctx_valid:1;
+ bool udp_ctx_valid:1;
+ bool cq_num_valid:1;
+ bool arp_cache_idx_valid:1;
+ bool reset_tcp_conn:1;
+ bool remove_hash_idx:1;
+ bool dont_send_term:1;
+ bool dont_send_fin:1;
+ bool cached_var_valid:1;
+ bool mss_change:1;
+ bool force_lpb:1;
+ bool mac_valid:1;
+};
+
+struct irdma_ccq_cqe_info {
+ struct irdma_sc_cqp *cqp;
+ u64 scratch;
+ u32 op_ret_val;
+ u16 maj_err_code;
+ u16 min_err_code;
+ u8 op_code;
+ bool error;
+};
+
+struct irdma_dcb_app_info {
+ u8 priority;
+ u8 selector;
+ u16 prot_id;
+};
+
+struct irdma_qos_tc_info {
+ u64 tc_ctx;
+ u8 rel_bw;
+ u8 prio_type;
+ u8 egress_virt_up;
+ u8 ingress_virt_up;
+};
+
+struct irdma_l2params {
+ struct irdma_qos_tc_info tc_info[IRDMA_MAX_USER_PRIORITY];
+ struct irdma_dcb_app_info apps[IRDMA_MAX_APPS];
+ u32 num_apps;
+ u16 qs_handle_list[IRDMA_MAX_USER_PRIORITY];
+ u16 mtu;
+ u8 up2tc[IRDMA_MAX_USER_PRIORITY];
+ u8 num_tc;
+ u8 vsi_rel_bw;
+ u8 vsi_prio_type;
+ bool mtu_changed:1;
+ bool tc_changed:1;
+};
+
+struct irdma_vsi_init_info {
+ struct irdma_sc_dev *dev;
+ void *back_vsi;
+ struct irdma_l2params *params;
+ u16 exception_lan_q;
+ u16 pf_data_vsi_num;
+ enum irdma_vm_vf_type vm_vf_type;
+ u16 vm_id;
+ enum irdma_status_code (*register_qset)(struct irdma_sc_vsi *vsi,
+ struct irdma_ws_node *tc_node);
+ void (*unregister_qset)(struct irdma_sc_vsi *vsi,
+ struct irdma_ws_node *tc_node);
+};
+
+struct irdma_vsi_stats_info {
+ struct irdma_vsi_pestat *pestat;
+ u8 fcn_id;
+ bool alloc_fcn_id;
+};
+
+struct irdma_device_init_info {
+ u64 fpm_query_buf_pa;
+ u64 fpm_commit_buf_pa;
+ __le64 *fpm_query_buf;
+ __le64 *fpm_commit_buf;
+ struct irdma_hw *hw;
+ void __iomem *bar0;
+ u8 hmc_fn_id;
+};
+
+struct irdma_ceq_init_info {
+ u64 ceqe_pa;
+ struct irdma_sc_dev *dev;
+ u64 *ceqe_base;
+ void *pbl_list;
+ u32 elem_cnt;
+ u32 ceq_id;
+ bool virtual_map:1;
+ bool tph_en:1;
+ bool itr_no_expire:1;
+ u8 pbl_chunk_size;
+ u8 tph_val;
+ u32 first_pm_pbl_idx;
+ struct irdma_sc_vsi *vsi;
+ struct irdma_sc_cq **reg_cq;
+ u32 reg_cq_idx;
+};
+
+struct irdma_aeq_init_info {
+ u64 aeq_elem_pa;
+ struct irdma_sc_dev *dev;
+ u32 *aeqe_base;
+ void *pbl_list;
+ u32 elem_cnt;
+ bool virtual_map;
+ u8 pbl_chunk_size;
+ u32 first_pm_pbl_idx;
+ u32 msix_idx;
+};
+
+struct irdma_ccq_init_info {
+ u64 cq_pa;
+ u64 shadow_area_pa;
+ struct irdma_sc_dev *dev;
+ struct irdma_cqe *cq_base;
+ __le64 *shadow_area;
+ void *pbl_list;
+ u32 num_elem;
+ u32 ceq_id;
+ u32 shadow_read_threshold;
+ bool ceqe_mask:1;
+ bool ceq_id_valid:1;
+ bool avoid_mem_cflct:1;
+ bool virtual_map:1;
+ bool tph_en:1;
+ u8 tph_val;
+ u8 pbl_chunk_size;
+ u32 first_pm_pbl_idx;
+ struct irdma_sc_vsi *vsi;
+};
+
+struct irdma_udp_offload_info {
+ bool ipv4:1;
+ bool insert_vlan_tag:1;
+ u8 ttl;
+ u8 tos;
+ u16 src_port;
+ u16 dst_port;
+ u32 dest_ip_addr[4];
+ u32 snd_mss;
+ u16 vlan_tag;
+ u16 arp_idx;
+ u32 flow_label;
+ u8 udp_state;
+ u32 psn_nxt;
+ u32 lsn;
+ u32 epsn;
+ u32 psn_max;
+ u32 psn_una;
+ u32 local_ipaddr[4];
+ u32 cwnd;
+ u8 rexmit_thresh;
+ u8 rnr_nak_thresh;
+};
+
+struct irdma_roce_offload_info {
+ u16 p_key;
+ u16 err_rq_idx;
+ u32 qkey;
+ u32 dest_qp;
+ u32 local_qp;
+ u8 roce_tver;
+ u8 ack_credits;
+ u8 err_rq_idx_valid;
+ u32 pd_id;
+ u16 ord_size;
+ u16 ird_size;
+ bool is_qp1:1;
+ bool udprivcq_en:1;
+ bool dcqcn_en:1;
+ bool rcv_no_icrc:1;
+ bool wr_rdresp_en:1;
+ bool bind_en:1;
+ bool fast_reg_en:1;
+ bool priv_mode_en:1;
+ bool rd_en:1;
+ bool timely_en:1;
+ bool dctcp_en:1;
+ bool fw_cc_enable:1;
+ bool use_stats_inst:1;
+ u16 t_high;
+ u16 t_low;
+ u8 last_byte_sent;
+ u8 mac_addr[ETH_ALEN];
+ u8 rtomin;
+};
+
+struct irdma_iwarp_offload_info {
+ u16 rcv_mark_offset;
+ u16 snd_mark_offset;
+ u8 ddp_ver;
+ u8 rdmap_ver;
+ u8 iwarp_mode;
+ u16 err_rq_idx;
+ u32 pd_id;
+ u16 ord_size;
+ u16 ird_size;
+ bool ib_rd_en:1;
+ bool align_hdrs:1;
+ bool rcv_no_mpa_crc:1;
+ bool err_rq_idx_valid:1;
+ bool snd_mark_en:1;
+ bool rcv_mark_en:1;
+ bool wr_rdresp_en:1;
+ bool bind_en:1;
+ bool fast_reg_en:1;
+ bool priv_mode_en:1;
+ bool rd_en:1;
+ bool timely_en:1;
+ bool use_stats_inst:1;
+ bool ecn_en:1;
+ bool dctcp_en:1;
+ u16 t_high;
+ u16 t_low;
+ u8 last_byte_sent;
+ u8 mac_addr[ETH_ALEN];
+ u8 rtomin;
+};
+
+struct irdma_tcp_offload_info {
+ bool ipv4:1;
+ bool no_nagle:1;
+ bool insert_vlan_tag:1;
+ bool time_stamp:1;
+ bool drop_ooo_seg:1;
+ bool avoid_stretch_ack:1;
+ bool wscale:1;
+ bool ignore_tcp_opt:1;
+ bool ignore_tcp_uns_opt:1;
+ u8 cwnd_inc_limit;
+ u8 dup_ack_thresh;
+ u8 ttl;
+ u8 src_mac_addr_idx;
+ u8 tos;
+ u16 src_port;
+ u16 dst_port;
+ u32 dest_ip_addr[4];
+ //u32 dest_ip_addr0;
+ //u32 dest_ip_addr1;
+ //u32 dest_ip_addr2;
+ //u32 dest_ip_addr3;
+ u32 snd_mss;
+ u16 syn_rst_handling;
+ u16 vlan_tag;
+ u16 arp_idx;
+ u32 flow_label;
+ u8 tcp_state;
+ u8 snd_wscale;
+ u8 rcv_wscale;
+ u32 time_stamp_recent;
+ u32 time_stamp_age;
+ u32 snd_nxt;
+ u32 snd_wnd;
+ u32 rcv_nxt;
+ u32 rcv_wnd;
+ u32 snd_max;
+ u32 snd_una;
+ u32 srtt;
+ u32 rtt_var;
+ u32 ss_thresh;
+ u32 cwnd;
+ u32 snd_wl1;
+ u32 snd_wl2;
+ u32 max_snd_window;
+ u8 rexmit_thresh;
+ u32 local_ipaddr[4];
+};
+
+struct irdma_qp_host_ctx_info {
+ u64 qp_compl_ctx;
+ union {
+ struct irdma_tcp_offload_info *tcp_info;
+ struct irdma_udp_offload_info *udp_info;
+ };
+ union {
+ struct irdma_iwarp_offload_info *iwarp_info;
+ struct irdma_roce_offload_info *roce_info;
+ };
+ u32 send_cq_num;
+ u32 rcv_cq_num;
+ u32 rem_endpoint_idx;
+ u8 stats_idx;
+ bool srq_valid:1;
+ bool tcp_info_valid:1;
+ bool iwarp_info_valid:1;
+ bool stats_idx_valid:1;
+ u8 user_pri;
+};
+
+struct irdma_aeqe_info {
+ u64 compl_ctx;
+ u32 qp_cq_id;
+ u16 ae_id;
+ u16 wqe_idx;
+ u8 tcp_state;
+ u8 iwarp_state;
+ bool qp:1;
+ bool cq:1;
+ bool sq:1;
+ bool rq:1;
+ bool in_rdrsp_wr:1;
+ bool out_rdrsp:1;
+ bool aeqe_overflow:1;
+ u8 q2_data_written;
+ u8 ae_src;
+};
+
+struct irdma_allocate_stag_info {
+ u64 total_len;
+ u64 first_pm_pbl_idx;
+ u32 chunk_size;
+ u32 stag_idx;
+ u32 page_size;
+ u32 pd_id;
+ u16 access_rights;
+ bool remote_access:1;
+ bool use_hmc_fcn_index:1;
+ bool use_pf_rid:1;
+ u8 hmc_fcn_index;
+};
+
+struct irdma_mw_alloc_info {
+ u32 mw_stag_index;
+ u32 page_size;
+ u32 pd_id;
+ bool remote_access:1;
+ bool mw_wide:1;
+ bool mw1_bind_dont_vldt_key:1;
+};
+
+struct irdma_reg_ns_stag_info {
+ u64 reg_addr_pa;
+ u64 va;
+ u64 total_len;
+ u32 page_size;
+ u32 chunk_size;
+ u32 first_pm_pbl_index;
+ enum irdma_addressing_type addr_type;
+ irdma_stag_index stag_idx;
+ u16 access_rights;
+ u32 pd_id;
+ irdma_stag_key stag_key;
+ bool use_hmc_fcn_index:1;
+ u8 hmc_fcn_index;
+ bool use_pf_rid:1;
+};
+
+struct irdma_fast_reg_stag_info {
+ u64 wr_id;
+ u64 reg_addr_pa;
+ u64 fbo;
+ void *va;
+ u64 total_len;
+ u32 page_size;
+ u32 chunk_size;
+ u32 first_pm_pbl_index;
+ enum irdma_addressing_type addr_type;
+ irdma_stag_index stag_idx;
+ u16 access_rights;
+ u32 pd_id;
+ irdma_stag_key stag_key;
+ bool local_fence:1;
+ bool read_fence:1;
+ bool signaled:1;
+ bool push_wqe:1;
+ bool use_hmc_fcn_index:1;
+ u8 hmc_fcn_index;
+ bool use_pf_rid:1;
+ bool defer_flag:1;
+};
+
+struct irdma_dealloc_stag_info {
+ u32 stag_idx;
+ u32 pd_id;
+ bool mr:1;
+ bool dealloc_pbl:1;
+};
+
+struct irdma_register_shared_stag {
+ u64 va;
+ enum irdma_addressing_type addr_type;
+ irdma_stag_index new_stag_idx;
+ irdma_stag_index parent_stag_idx;
+ u32 access_rights;
+ u32 pd_id;
+ u32 page_size;
+ irdma_stag_key new_stag_key;
+};
+
+struct irdma_qp_init_info {
+ struct irdma_qp_uk_init_info qp_uk_init_info;
+ struct irdma_sc_pd *pd;
+ struct irdma_sc_vsi *vsi;
+ __le64 *host_ctx;
+ u8 *q2;
+ u64 sq_pa;
+ u64 rq_pa;
+ u64 host_ctx_pa;
+ u64 q2_pa;
+ u64 shadow_area_pa;
+ u8 sq_tph_val;
+ u8 rq_tph_val;
+ bool sq_tph_en:1;
+ bool rq_tph_en:1;
+ bool rcv_tph_en:1;
+ bool xmit_tph_en:1;
+ bool virtual_map:1;
+};
+
+struct irdma_cq_init_info {
+ struct irdma_sc_dev *dev;
+ u64 cq_base_pa;
+ u64 shadow_area_pa;
+ u32 ceq_id;
+ u32 shadow_read_threshold;
+ u8 pbl_chunk_size;
+ u32 first_pm_pbl_idx;
+ bool virtual_map:1;
+ bool ceqe_mask:1;
+ bool ceq_id_valid:1;
+ bool tph_en:1;
+ u8 tph_val;
+ u8 type;
+ struct irdma_cq_uk_init_info cq_uk_init_info;
+ struct irdma_sc_vsi *vsi;
+};
+
+struct irdma_upload_context_info {
+ u64 buf_pa;
+ u32 qp_id;
+ u8 qp_type;
+ bool freeze_qp:1;
+ bool raw_format:1;
+};
+
+struct irdma_local_mac_entry_info {
+ u8 mac_addr[6];
+ u16 entry_idx;
+};
+
+struct irdma_add_arp_cache_entry_info {
+ u8 mac_addr[ETH_ALEN];
+ u32 reach_max;
+ u16 arp_index;
+ bool permanent;
+};
+
+struct irdma_apbvt_info {
+ u16 port;
+ bool add;
+};
+
+struct irdma_qhash_table_info {
+ struct irdma_sc_vsi *vsi;
+ enum irdma_quad_hash_manage_type manage;
+ enum irdma_quad_entry_type entry_type;
+ bool vlan_valid:1;
+ bool ipv4_valid:1;
+ u8 mac_addr[ETH_ALEN];
+ u16 vlan_id;
+ u8 user_pri;
+ u32 qp_num;
+ u32 dest_ip[4];
+ u32 src_ip[4];
+ u16 dest_port;
+ u16 src_port;
+};
+
+struct irdma_cqp_manage_push_page_info {
+ u32 push_idx;
+ u16 qs_handle;
+ u8 free_page;
+ u8 push_page_type;
+};
+
+struct irdma_qp_flush_info {
+ u16 sq_minor_code;
+ u16 sq_major_code;
+ u16 rq_minor_code;
+ u16 rq_major_code;
+ u16 ae_code;
+ u8 ae_src;
+ bool sq:1;
+ bool rq:1;
+ bool userflushcode:1;
+ bool generate_ae:1;
+};
+
+struct irdma_gen_ae_info {
+ u16 ae_code;
+ u8 ae_src;
+};
+
+struct irdma_cqp_timeout {
+ u64 compl_cqp_cmds;
+ u32 count;
+};
+
+struct irdma_irq_ops {
+ void (*irdma_cfg_aeq)(struct irdma_sc_dev *dev, u32 idx, bool enable);
+ void (*irdma_cfg_ceq)(struct irdma_sc_dev *dev, u32 ceq_id, u32 idx,
+ bool enable);
+ void (*irdma_dis_irq)(struct irdma_sc_dev *dev, u32 idx);
+ void (*irdma_en_irq)(struct irdma_sc_dev *dev, u32 idx);
+};
+
+void irdma_sc_ccq_arm(struct irdma_sc_cq *ccq);
+enum irdma_status_code irdma_sc_ccq_create(struct irdma_sc_cq *ccq, u64 scratch,
+ bool check_overflow, bool post_sq);
+enum irdma_status_code irdma_sc_ccq_destroy(struct irdma_sc_cq *ccq, u64 scratch,
+ bool post_sq);
+enum irdma_status_code irdma_sc_ccq_get_cqe_info(struct irdma_sc_cq *ccq,
+ struct irdma_ccq_cqe_info *info);
+enum irdma_status_code irdma_sc_ccq_init(struct irdma_sc_cq *ccq,
+ struct irdma_ccq_init_info *info);
+
+enum irdma_status_code irdma_sc_cceq_create(struct irdma_sc_ceq *ceq, u64 scratch);
+enum irdma_status_code irdma_sc_cceq_destroy_done(struct irdma_sc_ceq *ceq);
+
+enum irdma_status_code irdma_sc_ceq_destroy(struct irdma_sc_ceq *ceq, u64 scratch,
+ bool post_sq);
+enum irdma_status_code irdma_sc_ceq_init(struct irdma_sc_ceq *ceq,
+ struct irdma_ceq_init_info *info);
+void irdma_sc_cleanup_ceqes(struct irdma_sc_cq *cq, struct irdma_sc_ceq *ceq);
+void *irdma_sc_process_ceq(struct irdma_sc_dev *dev, struct irdma_sc_ceq *ceq);
+
+enum irdma_status_code irdma_sc_aeq_init(struct irdma_sc_aeq *aeq,
+ struct irdma_aeq_init_info *info);
+enum irdma_status_code irdma_sc_get_next_aeqe(struct irdma_sc_aeq *aeq,
+ struct irdma_aeqe_info *info);
+enum irdma_status_code irdma_sc_repost_aeq_entries(struct irdma_sc_dev *dev,
+ u32 count);
+
+void irdma_sc_pd_init(struct irdma_sc_dev *dev, struct irdma_sc_pd *pd, u32 pd_id,
+ int abi_ver);
+void irdma_cfg_aeq(struct irdma_sc_dev *dev, u32 idx, bool enable);
+void irdma_check_cqp_progress(struct irdma_cqp_timeout *cqp_timeout,
+ struct irdma_sc_dev *dev);
+enum irdma_status_code irdma_sc_cqp_create(struct irdma_sc_cqp *cqp, u16 *maj_err,
+ u16 *min_err);
+enum irdma_status_code irdma_sc_cqp_destroy(struct irdma_sc_cqp *cqp);
+enum irdma_status_code irdma_sc_cqp_init(struct irdma_sc_cqp *cqp,
+ struct irdma_cqp_init_info *info);
+void irdma_sc_cqp_post_sq(struct irdma_sc_cqp *cqp);
+enum irdma_status_code irdma_sc_poll_for_cqp_op_done(struct irdma_sc_cqp *cqp, u8 opcode,
+ struct irdma_ccq_cqe_info *cmpl_info);
+enum irdma_status_code irdma_sc_fast_register(struct irdma_sc_qp *qp,
+ struct irdma_fast_reg_stag_info *info,
+ bool post_sq);
+enum irdma_status_code irdma_sc_qp_create(struct irdma_sc_qp *qp,
+ struct irdma_create_qp_info *info,
+ u64 scratch, bool post_sq);
+enum irdma_status_code irdma_sc_qp_destroy(struct irdma_sc_qp *qp,
+ u64 scratch, bool remove_hash_idx,
+ bool ignore_mw_bnd, bool post_sq);
+enum irdma_status_code irdma_sc_qp_flush_wqes(struct irdma_sc_qp *qp,
+ struct irdma_qp_flush_info *info,
+ u64 scratch, bool post_sq);
+enum irdma_status_code irdma_sc_qp_init(struct irdma_sc_qp *qp,
+ struct irdma_qp_init_info *info);
+enum irdma_status_code irdma_sc_qp_modify(struct irdma_sc_qp *qp,
+ struct irdma_modify_qp_info *info,
+ u64 scratch, bool post_sq);
+void irdma_sc_send_lsmm(struct irdma_sc_qp *qp, void *lsmm_buf, u32 size,
+ irdma_stag stag);
+void irdma_sc_send_lsmm_nostag(struct irdma_sc_qp *qp, void *lsmm_buf, u32 size);
+void irdma_sc_send_rtt(struct irdma_sc_qp *qp, bool read);
+void irdma_sc_qp_setctx(struct irdma_sc_qp *qp, __le64 *qp_ctx,
+ struct irdma_qp_host_ctx_info *info);
+void irdma_sc_qp_setctx_roce(struct irdma_sc_qp *qp, __le64 *qp_ctx,
+ struct irdma_qp_host_ctx_info *info);
+enum irdma_status_code irdma_sc_cq_destroy(struct irdma_sc_cq *cq, u64 scratch,
+ bool post_sq);
+enum irdma_status_code irdma_sc_cq_init(struct irdma_sc_cq *cq,
+ struct irdma_cq_init_info *info);
+void irdma_sc_cq_resize(struct irdma_sc_cq *cq, struct irdma_modify_cq_info *info);
+enum irdma_status_code irdma_sc_static_hmc_pages_allocated(struct irdma_sc_cqp *cqp,
+ u64 scratch, u8 hmc_fn_id,
+ bool post_sq, bool poll_registers);
+
+void sc_vsi_update_stats(struct irdma_sc_vsi *vsi);
+struct cqp_info {
+ union {
+ struct {
+ struct irdma_sc_qp *qp;
+ struct irdma_create_qp_info info;
+ u64 scratch;
+ } qp_create;
+
+ struct {
+ struct irdma_sc_qp *qp;
+ struct irdma_modify_qp_info info;
+ u64 scratch;
+ } qp_modify;
+
+ struct {
+ struct irdma_sc_qp *qp;
+ u64 scratch;
+ bool remove_hash_idx;
+ bool ignore_mw_bnd;
+ } qp_destroy;
+
+ struct {
+ struct irdma_sc_cq *cq;
+ u64 scratch;
+ bool check_overflow;
+ } cq_create;
+
+ struct {
+ struct irdma_sc_cq *cq;
+ struct irdma_modify_cq_info info;
+ u64 scratch;
+ } cq_modify;
+
+ struct {
+ struct irdma_sc_cq *cq;
+ u64 scratch;
+ } cq_destroy;
+
+ struct {
+ struct irdma_sc_dev *dev;
+ struct irdma_allocate_stag_info info;
+ u64 scratch;
+ } alloc_stag;
+
+ struct {
+ struct irdma_sc_dev *dev;
+ struct irdma_mw_alloc_info info;
+ u64 scratch;
+ } mw_alloc;
+
+ struct {
+ struct irdma_sc_dev *dev;
+ struct irdma_reg_ns_stag_info info;
+ u64 scratch;
+ } mr_reg_non_shared;
+
+ struct {
+ struct irdma_sc_dev *dev;
+ struct irdma_dealloc_stag_info info;
+ u64 scratch;
+ } dealloc_stag;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_add_arp_cache_entry_info info;
+ u64 scratch;
+ } add_arp_cache_entry;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ u64 scratch;
+ u16 arp_index;
+ } del_arp_cache_entry;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_local_mac_entry_info info;
+ u64 scratch;
+ } add_local_mac_entry;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ u64 scratch;
+ u8 entry_idx;
+ u8 ignore_ref_count;
+ } del_local_mac_entry;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ u64 scratch;
+ } alloc_local_mac_entry;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_cqp_manage_push_page_info info;
+ u64 scratch;
+ } manage_push_page;
+
+ struct {
+ struct irdma_sc_dev *dev;
+ struct irdma_upload_context_info info;
+ u64 scratch;
+ } qp_upload_context;
+
+ struct {
+ struct irdma_sc_dev *dev;
+ struct irdma_hmc_fcn_info info;
+ u64 scratch;
+ } manage_hmc_pm;
+
+ struct {
+ struct irdma_sc_ceq *ceq;
+ u64 scratch;
+ } ceq_create;
+
+ struct {
+ struct irdma_sc_ceq *ceq;
+ u64 scratch;
+ } ceq_destroy;
+
+ struct {
+ struct irdma_sc_aeq *aeq;
+ u64 scratch;
+ } aeq_create;
+
+ struct {
+ struct irdma_sc_aeq *aeq;
+ u64 scratch;
+ } aeq_destroy;
+
+ struct {
+ struct irdma_sc_qp *qp;
+ struct irdma_qp_flush_info info;
+ u64 scratch;
+ } qp_flush_wqes;
+
+ struct {
+ struct irdma_sc_qp *qp;
+ struct irdma_gen_ae_info info;
+ u64 scratch;
+ } gen_ae;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ void *fpm_val_va;
+ u64 fpm_val_pa;
+ u8 hmc_fn_id;
+ u64 scratch;
+ } query_fpm_val;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ void *fpm_val_va;
+ u64 fpm_val_pa;
+ u8 hmc_fn_id;
+ u64 scratch;
+ } commit_fpm_val;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_apbvt_info info;
+ u64 scratch;
+ } manage_apbvt_entry;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_qhash_table_info info;
+ u64 scratch;
+ } manage_qhash_table_entry;
+
+ struct {
+ struct irdma_sc_dev *dev;
+ struct irdma_update_sds_info info;
+ u64 scratch;
+ } update_pe_sds;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_sc_qp *qp;
+ u64 scratch;
+ } suspend_resume;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_ah_info info;
+ u64 scratch;
+ } ah_create;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_ah_info info;
+ u64 scratch;
+ } ah_destroy;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_mcast_grp_info info;
+ u64 scratch;
+ } mc_create;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_mcast_grp_info info;
+ u64 scratch;
+ } mc_destroy;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_mcast_grp_info info;
+ u64 scratch;
+ } mc_modify;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_stats_inst_info info;
+ u64 scratch;
+ } stats_manage;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_stats_gather_info info;
+ u64 scratch;
+ } stats_gather;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_ws_node_info info;
+ u64 scratch;
+ } ws_node;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_up_info info;
+ u64 scratch;
+ } up_map;
+
+ struct {
+ struct irdma_sc_cqp *cqp;
+ struct irdma_dma_mem query_buff_mem;
+ u64 scratch;
+ } query_rdma;
+ } u;
+};
+
+struct cqp_cmds_info {
+ struct list_head cqp_cmd_entry;
+ u8 cqp_cmd;
+ u8 post_sq;
+ struct cqp_info in;
+};
+
+__le64 *irdma_sc_cqp_get_next_send_wqe_idx(struct irdma_sc_cqp *cqp, u64 scratch,
+ u32 *wqe_idx);
+
+/**
+ * irdma_sc_cqp_get_next_send_wqe - get next wqe on cqp sq
+ * @cqp: struct for cqp hw
+ * @scratch: private data for CQP WQE
+ */
+static inline __le64 *irdma_sc_cqp_get_next_send_wqe(struct irdma_sc_cqp *cqp, u64 scratch)
+{
+ u32 wqe_idx;
+
+ return irdma_sc_cqp_get_next_send_wqe_idx(cqp, scratch, &wqe_idx);
+}
+#endif /* IRDMA_TYPE_H */
diff --git a/drivers/infiniband/hw/irdma/uda.c b/drivers/infiniband/hw/irdma/uda.c
new file mode 100644
index 000000000000..f5b1b6150cdc
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/uda.c
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2016 - 2021 Intel Corporation */
+#include "osdep.h"
+#include "status.h"
+#include "hmc.h"
+#include "defs.h"
+#include "type.h"
+#include "protos.h"
+#include "uda.h"
+#include "uda_d.h"
+
+/**
+ * irdma_sc_access_ah() - Create, modify or delete AH
+ * @cqp: struct for cqp hw
+ * @info: ah information
+ * @op: Operation
+ * @scratch: u64 saved to be used during cqp completion
+ */
+enum irdma_status_code irdma_sc_access_ah(struct irdma_sc_cqp *cqp,
+ struct irdma_ah_info *info,
+ u32 op, u64 scratch)
+{
+ __le64 *wqe;
+ u64 qw1, qw2;
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe)
+ return IRDMA_ERR_RING_FULL;
+
+ set_64bit_val(wqe, 0, ether_addr_to_u64(info->mac_addr) << 16);
+ qw1 = FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_PDINDEXLO, info->pd_idx) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_TC, info->tc_tos) |
+ FIELD_PREP(IRDMA_UDAQPC_VLANTAG, info->vlan_tag);
+
+ qw2 = FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ARPINDEX, info->dst_arpindex) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_FLOWLABEL, info->flow_label) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_HOPLIMIT, info->hop_ttl) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_PDINDEXHI, info->pd_idx >> 16);
+
+ if (!info->ipv4_valid) {
+ set_64bit_val(wqe, 40,
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR0, info->dest_ip_addr[0]) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR1, info->dest_ip_addr[1]));
+ set_64bit_val(wqe, 32,
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR2, info->dest_ip_addr[2]) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->dest_ip_addr[3]));
+
+ set_64bit_val(wqe, 56,
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR0, info->src_ip_addr[0]) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR1, info->src_ip_addr[1]));
+ set_64bit_val(wqe, 48,
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR2, info->src_ip_addr[2]) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->src_ip_addr[3]));
+ } else {
+ set_64bit_val(wqe, 32,
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->dest_ip_addr[0]));
+
+ set_64bit_val(wqe, 48,
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->src_ip_addr[0]));
+ }
+
+ set_64bit_val(wqe, 8, qw1);
+ set_64bit_val(wqe, 16, qw2);
+
+ dma_wmb(); /* need write block before writing WQE header */
+
+ set_64bit_val(
+ wqe, 24,
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_WQEVALID, cqp->polarity) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_OPCODE, op) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_DOLOOPBACKK, info->do_lpbk) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_IPV4VALID, info->ipv4_valid) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_AVIDX, info->ah_idx) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_INSERTVLANTAG, info->insert_vlan_tag));
+
+ print_hex_dump_debug("WQE: MANAGE_AH WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_create_mg_ctx() - create a mcg context
+ * @info: multicast group context info
+ */
+static enum irdma_status_code
+irdma_create_mg_ctx(struct irdma_mcast_grp_info *info)
+{
+ struct irdma_mcast_grp_ctx_entry_info *entry_info = NULL;
+ u8 idx = 0; /* index in the array */
+ u8 ctx_idx = 0; /* index in the MG context */
+
+ memset(info->dma_mem_mc.va, 0, IRDMA_MAX_MGS_PER_CTX * sizeof(u64));
+
+ for (idx = 0; idx < IRDMA_MAX_MGS_PER_CTX; idx++) {
+ entry_info = &info->mg_ctx_info[idx];
+ if (entry_info->valid_entry) {
+ set_64bit_val((__le64 *)info->dma_mem_mc.va,
+ ctx_idx * sizeof(u64),
+ FIELD_PREP(IRDMA_UDA_MGCTX_DESTPORT, entry_info->dest_port) |
+ FIELD_PREP(IRDMA_UDA_MGCTX_VALIDENT, entry_info->valid_entry) |
+ FIELD_PREP(IRDMA_UDA_MGCTX_QPID, entry_info->qp_id));
+ ctx_idx++;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_access_mcast_grp() - Access mcast group based on op
+ * @cqp: Control QP
+ * @info: multicast group context info
+ * @op: operation to perform
+ * @scratch: u64 saved to be used during cqp completion
+ */
+enum irdma_status_code irdma_access_mcast_grp(struct irdma_sc_cqp *cqp,
+ struct irdma_mcast_grp_info *info,
+ u32 op, u64 scratch)
+{
+ __le64 *wqe;
+ enum irdma_status_code ret_code = 0;
+
+ if (info->mg_id >= IRDMA_UDA_MAX_FSI_MGS) {
+ ibdev_dbg(to_ibdev(cqp->dev), "WQE: mg_id out of range\n");
+ return IRDMA_ERR_PARAM;
+ }
+
+ wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch);
+ if (!wqe) {
+ ibdev_dbg(to_ibdev(cqp->dev), "WQE: ring full\n");
+ return IRDMA_ERR_RING_FULL;
+ }
+
+ ret_code = irdma_create_mg_ctx(info);
+ if (ret_code)
+ return ret_code;
+
+ set_64bit_val(wqe, 32, info->dma_mem_mc.pa);
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MG_VLANID, info->vlan_id) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_QS_HANDLE, info->qs_handle));
+ set_64bit_val(wqe, 0, ether_addr_to_u64(info->dest_mac_addr));
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MG_HMC_FCN_ID, info->hmc_fcn_id));
+
+ if (!info->ipv4_valid) {
+ set_64bit_val(wqe, 56,
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR0, info->dest_ip_addr[0]) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR1, info->dest_ip_addr[1]));
+ set_64bit_val(wqe, 48,
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR2, info->dest_ip_addr[2]) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->dest_ip_addr[3]));
+ } else {
+ set_64bit_val(wqe, 48,
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->dest_ip_addr[0]));
+ }
+
+ dma_wmb(); /* need write memory block before writing the WQE header. */
+
+ set_64bit_val(wqe, 24,
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MG_WQEVALID, cqp->polarity) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MG_OPCODE, op) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MG_MGIDX, info->mg_id) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MG_VLANVALID, info->vlan_valid) |
+ FIELD_PREP(IRDMA_UDA_CQPSQ_MG_IPV4VALID, info->ipv4_valid));
+
+ print_hex_dump_debug("WQE: MANAGE_MCG WQE", DUMP_PREFIX_OFFSET, 16, 8,
+ wqe, IRDMA_CQP_WQE_SIZE * 8, false);
+ print_hex_dump_debug("WQE: MCG_HOST CTX WQE", DUMP_PREFIX_OFFSET, 16,
+ 8, info->dma_mem_mc.va,
+ IRDMA_MAX_MGS_PER_CTX * 8, false);
+ irdma_sc_cqp_post_sq(cqp);
+
+ return 0;
+}
+
+/**
+ * irdma_compare_mgs - Compares two multicast group structures
+ * @entry1: Multcast group info
+ * @entry2: Multcast group info in context
+ */
+static bool irdma_compare_mgs(struct irdma_mcast_grp_ctx_entry_info *entry1,
+ struct irdma_mcast_grp_ctx_entry_info *entry2)
+{
+ if (entry1->dest_port == entry2->dest_port &&
+ entry1->qp_id == entry2->qp_id)
+ return true;
+
+ return false;
+}
+
+/**
+ * irdma_sc_add_mcast_grp - Allocates mcast group entry in ctx
+ * @ctx: Multcast group context
+ * @mg: Multcast group info
+ */
+enum irdma_status_code irdma_sc_add_mcast_grp(struct irdma_mcast_grp_info *ctx,
+ struct irdma_mcast_grp_ctx_entry_info *mg)
+{
+ u32 idx;
+ bool free_entry_found = false;
+ u32 free_entry_idx = 0;
+
+ /* find either an identical or a free entry for a multicast group */
+ for (idx = 0; idx < IRDMA_MAX_MGS_PER_CTX; idx++) {
+ if (ctx->mg_ctx_info[idx].valid_entry) {
+ if (irdma_compare_mgs(&ctx->mg_ctx_info[idx], mg)) {
+ ctx->mg_ctx_info[idx].use_cnt++;
+ return 0;
+ }
+ continue;
+ }
+ if (!free_entry_found) {
+ free_entry_found = true;
+ free_entry_idx = idx;
+ }
+ }
+
+ if (free_entry_found) {
+ ctx->mg_ctx_info[free_entry_idx] = *mg;
+ ctx->mg_ctx_info[free_entry_idx].valid_entry = true;
+ ctx->mg_ctx_info[free_entry_idx].use_cnt = 1;
+ ctx->no_of_mgs++;
+ return 0;
+ }
+
+ return IRDMA_ERR_NO_MEMORY;
+}
+
+/**
+ * irdma_sc_del_mcast_grp - Delete mcast group
+ * @ctx: Multcast group context
+ * @mg: Multcast group info
+ *
+ * Finds and removes a specific mulicast group from context, all
+ * parameters must match to remove a multicast group.
+ */
+enum irdma_status_code irdma_sc_del_mcast_grp(struct irdma_mcast_grp_info *ctx,
+ struct irdma_mcast_grp_ctx_entry_info *mg)
+{
+ u32 idx;
+
+ /* find an entry in multicast group context */
+ for (idx = 0; idx < IRDMA_MAX_MGS_PER_CTX; idx++) {
+ if (!ctx->mg_ctx_info[idx].valid_entry)
+ continue;
+
+ if (irdma_compare_mgs(mg, &ctx->mg_ctx_info[idx])) {
+ ctx->mg_ctx_info[idx].use_cnt--;
+
+ if (!ctx->mg_ctx_info[idx].use_cnt) {
+ ctx->mg_ctx_info[idx].valid_entry = false;
+ ctx->no_of_mgs--;
+ /* Remove gap if element was not the last */
+ if (idx != ctx->no_of_mgs &&
+ ctx->no_of_mgs > 0) {
+ memcpy(&ctx->mg_ctx_info[idx],
+ &ctx->mg_ctx_info[ctx->no_of_mgs - 1],
+ sizeof(ctx->mg_ctx_info[idx]));
+ ctx->mg_ctx_info[ctx->no_of_mgs - 1].valid_entry = false;
+ }
+ }
+
+ return 0;
+ }
+ }
+
+ return IRDMA_ERR_PARAM;
+}
diff --git a/drivers/infiniband/hw/irdma/uda.h b/drivers/infiniband/hw/irdma/uda.h
new file mode 100644
index 000000000000..a4ad0367dc96
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/uda.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2016 - 2021 Intel Corporation */
+#ifndef IRDMA_UDA_H
+#define IRDMA_UDA_H
+
+#define IRDMA_UDA_MAX_FSI_MGS 4096
+#define IRDMA_UDA_MAX_PFS 16
+#define IRDMA_UDA_MAX_VFS 128
+
+struct irdma_sc_cqp;
+
+struct irdma_ah_info {
+ struct irdma_sc_vsi *vsi;
+ u32 pd_idx;
+ u32 dst_arpindex;
+ u32 dest_ip_addr[4];
+ u32 src_ip_addr[4];
+ u32 flow_label;
+ u32 ah_idx;
+ u16 vlan_tag;
+ u8 insert_vlan_tag;
+ u8 tc_tos;
+ u8 hop_ttl;
+ u8 mac_addr[ETH_ALEN];
+ bool ah_valid:1;
+ bool ipv4_valid:1;
+ bool do_lpbk:1;
+};
+
+struct irdma_sc_ah {
+ struct irdma_sc_dev *dev;
+ struct irdma_ah_info ah_info;
+};
+
+enum irdma_status_code irdma_sc_add_mcast_grp(struct irdma_mcast_grp_info *ctx,
+ struct irdma_mcast_grp_ctx_entry_info *mg);
+enum irdma_status_code irdma_sc_del_mcast_grp(struct irdma_mcast_grp_info *ctx,
+ struct irdma_mcast_grp_ctx_entry_info *mg);
+enum irdma_status_code irdma_sc_access_ah(struct irdma_sc_cqp *cqp, struct irdma_ah_info *info,
+ u32 op, u64 scratch);
+enum irdma_status_code irdma_access_mcast_grp(struct irdma_sc_cqp *cqp,
+ struct irdma_mcast_grp_info *info,
+ u32 op, u64 scratch);
+
+static inline void irdma_sc_init_ah(struct irdma_sc_dev *dev, struct irdma_sc_ah *ah)
+{
+ ah->dev = dev;
+}
+
+static inline enum irdma_status_code irdma_sc_create_ah(struct irdma_sc_cqp *cqp,
+ struct irdma_ah_info *info,
+ u64 scratch)
+{
+ return irdma_sc_access_ah(cqp, info, IRDMA_CQP_OP_CREATE_ADDR_HANDLE,
+ scratch);
+}
+
+static inline enum irdma_status_code irdma_sc_destroy_ah(struct irdma_sc_cqp *cqp,
+ struct irdma_ah_info *info,
+ u64 scratch)
+{
+ return irdma_sc_access_ah(cqp, info, IRDMA_CQP_OP_DESTROY_ADDR_HANDLE,
+ scratch);
+}
+
+static inline enum irdma_status_code irdma_sc_create_mcast_grp(struct irdma_sc_cqp *cqp,
+ struct irdma_mcast_grp_info *info,
+ u64 scratch)
+{
+ return irdma_access_mcast_grp(cqp, info, IRDMA_CQP_OP_CREATE_MCAST_GRP,
+ scratch);
+}
+
+static inline enum irdma_status_code irdma_sc_modify_mcast_grp(struct irdma_sc_cqp *cqp,
+ struct irdma_mcast_grp_info *info,
+ u64 scratch)
+{
+ return irdma_access_mcast_grp(cqp, info, IRDMA_CQP_OP_MODIFY_MCAST_GRP,
+ scratch);
+}
+
+static inline enum irdma_status_code irdma_sc_destroy_mcast_grp(struct irdma_sc_cqp *cqp,
+ struct irdma_mcast_grp_info *info,
+ u64 scratch)
+{
+ return irdma_access_mcast_grp(cqp, info, IRDMA_CQP_OP_DESTROY_MCAST_GRP,
+ scratch);
+}
+#endif /* IRDMA_UDA_H */
diff --git a/drivers/infiniband/hw/irdma/uda_d.h b/drivers/infiniband/hw/irdma/uda_d.h
new file mode 100644
index 000000000000..bfc81cac2c51
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/uda_d.h
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2016 - 2021 Intel Corporation */
+#ifndef IRDMA_UDA_D_H
+#define IRDMA_UDA_D_H
+
+/* L4 packet type */
+#define IRDMA_E_UDA_SQ_L4T_UNKNOWN 0
+#define IRDMA_E_UDA_SQ_L4T_TCP 1
+#define IRDMA_E_UDA_SQ_L4T_SCTP 2
+#define IRDMA_E_UDA_SQ_L4T_UDP 3
+
+/* Inner IP header type */
+#define IRDMA_E_UDA_SQ_IIPT_UNKNOWN 0
+#define IRDMA_E_UDA_SQ_IIPT_IPV6 1
+#define IRDMA_E_UDA_SQ_IIPT_IPV4_NO_CSUM 2
+#define IRDMA_E_UDA_SQ_IIPT_IPV4_CSUM 3
+#define IRDMA_UDA_QPSQ_PUSHWQE BIT_ULL(56)
+#define IRDMA_UDA_QPSQ_INLINEDATAFLAG BIT_ULL(57)
+#define IRDMA_UDA_QPSQ_INLINEDATALEN GENMASK_ULL(55, 48)
+#define IRDMA_UDA_QPSQ_ADDFRAGCNT GENMASK_ULL(41, 38)
+#define IRDMA_UDA_QPSQ_IPFRAGFLAGS GENMASK_ULL(43, 42)
+#define IRDMA_UDA_QPSQ_NOCHECKSUM BIT_ULL(45)
+#define IRDMA_UDA_QPSQ_AHIDXVALID BIT_ULL(46)
+#define IRDMA_UDA_QPSQ_LOCAL_FENCE BIT_ULL(61)
+#define IRDMA_UDA_QPSQ_AHIDX GENMASK_ULL(16, 0)
+#define IRDMA_UDA_QPSQ_PROTOCOL GENMASK_ULL(23, 16)
+#define IRDMA_UDA_QPSQ_EXTHDRLEN GENMASK_ULL(40, 32)
+#define IRDMA_UDA_QPSQ_MULTICAST BIT_ULL(63)
+#define IRDMA_UDA_QPSQ_MACLEN GENMASK_ULL(62, 56)
+#define IRDMA_UDA_QPSQ_MACLEN_LINE 2
+#define IRDMA_UDA_QPSQ_IPLEN GENMASK_ULL(54, 48)
+#define IRDMA_UDA_QPSQ_IPLEN_LINE 2
+#define IRDMA_UDA_QPSQ_L4T GENMASK_ULL(31, 30)
+#define IRDMA_UDA_QPSQ_L4T_LINE 2
+#define IRDMA_UDA_QPSQ_IIPT GENMASK_ULL(29, 28)
+#define IRDMA_UDA_QPSQ_IIPT_LINE 2
+
+#define IRDMA_UDA_QPSQ_DO_LPB_LINE 3
+#define IRDMA_UDA_QPSQ_FWD_PROG_CONFIRM BIT_ULL(45)
+#define IRDMA_UDA_QPSQ_FWD_PROG_CONFIRM_LINE 3
+#define IRDMA_UDA_QPSQ_IMMDATA GENMASK_ULL(63, 0)
+
+/* Byte Offset 0 */
+#define IRDMA_UDAQPC_IPV4_M BIT_ULL(3)
+#define IRDMA_UDAQPC_INSERTVLANTAG BIT_ULL(5)
+#define IRDMA_UDAQPC_ISQP1 BIT_ULL(6)
+
+#define IRDMA_UDAQPC_ECNENABLE BIT_ULL(14)
+#define IRDMA_UDAQPC_PDINDEXHI GENMASK_ULL(21, 20)
+#define IRDMA_UDAQPC_DCTCPENABLE BIT_ULL(25)
+
+#define IRDMA_UDAQPC_RCVTPHEN IRDMAQPC_RCVTPHEN
+#define IRDMA_UDAQPC_XMITTPHEN IRDMAQPC_XMITTPHEN
+#define IRDMA_UDAQPC_RQTPHEN IRDMAQPC_RQTPHEN
+#define IRDMA_UDAQPC_SQTPHEN IRDMAQPC_SQTPHEN
+#define IRDMA_UDAQPC_PPIDX IRDMAQPC_PPIDX
+#define IRDMA_UDAQPC_PMENA IRDMAQPC_PMENA
+#define IRDMA_UDAQPC_INSERTTAG2 BIT_ULL(11)
+#define IRDMA_UDAQPC_INSERTTAG3 BIT_ULL(14)
+
+#define IRDMA_UDAQPC_RQSIZE IRDMAQPC_RQSIZE
+#define IRDMA_UDAQPC_SQSIZE IRDMAQPC_SQSIZE
+#define IRDMA_UDAQPC_TXCQNUM IRDMAQPC_TXCQNUM
+#define IRDMA_UDAQPC_RXCQNUM IRDMAQPC_RXCQNUM
+#define IRDMA_UDAQPC_QPCOMPCTX IRDMAQPC_QPCOMPCTX
+#define IRDMA_UDAQPC_SQTPHVAL IRDMAQPC_SQTPHVAL
+#define IRDMA_UDAQPC_RQTPHVAL IRDMAQPC_RQTPHVAL
+#define IRDMA_UDAQPC_QSHANDLE IRDMAQPC_QSHANDLE
+#define IRDMA_UDAQPC_RQHDRRINGBUFSIZE GENMASK_ULL(49, 48)
+#define IRDMA_UDAQPC_SQHDRRINGBUFSIZE GENMASK_ULL(33, 32)
+#define IRDMA_UDAQPC_PRIVILEGEENABLE BIT_ULL(25)
+#define IRDMA_UDAQPC_USE_STATISTICS_INSTANCE BIT_ULL(26)
+#define IRDMA_UDAQPC_STATISTICS_INSTANCE_INDEX GENMASK_ULL(6, 0)
+#define IRDMA_UDAQPC_PRIVHDRGENENABLE BIT_ULL(0)
+#define IRDMA_UDAQPC_RQHDRSPLITENABLE BIT_ULL(3)
+#define IRDMA_UDAQPC_RQHDRRINGBUFENABLE BIT_ULL(2)
+#define IRDMA_UDAQPC_SQHDRRINGBUFENABLE BIT_ULL(1)
+#define IRDMA_UDAQPC_IPID GENMASK_ULL(47, 32)
+#define IRDMA_UDAQPC_SNDMSS GENMASK_ULL(29, 16)
+#define IRDMA_UDAQPC_VLANTAG GENMASK_ULL(15, 0)
+
+#define IRDMA_UDA_CQPSQ_MAV_PDINDEXHI GENMASK_ULL(21, 20)
+#define IRDMA_UDA_CQPSQ_MAV_PDINDEXLO GENMASK_ULL(63, 48)
+#define IRDMA_UDA_CQPSQ_MAV_SRCMACADDRINDEX GENMASK_ULL(29, 24)
+#define IRDMA_UDA_CQPSQ_MAV_ARPINDEX GENMASK_ULL(63, 48)
+#define IRDMA_UDA_CQPSQ_MAV_TC GENMASK_ULL(39, 32)
+#define IRDMA_UDA_CQPSQ_MAV_HOPLIMIT GENMASK_ULL(39, 32)
+#define IRDMA_UDA_CQPSQ_MAV_FLOWLABEL GENMASK_ULL(19, 0)
+#define IRDMA_UDA_CQPSQ_MAV_ADDR0 GENMASK_ULL(63, 32)
+#define IRDMA_UDA_CQPSQ_MAV_ADDR1 GENMASK_ULL(31, 0)
+#define IRDMA_UDA_CQPSQ_MAV_ADDR2 GENMASK_ULL(63, 32)
+#define IRDMA_UDA_CQPSQ_MAV_ADDR3 GENMASK_ULL(31, 0)
+#define IRDMA_UDA_CQPSQ_MAV_WQEVALID BIT_ULL(63)
+#define IRDMA_UDA_CQPSQ_MAV_OPCODE GENMASK_ULL(37, 32)
+#define IRDMA_UDA_CQPSQ_MAV_DOLOOPBACKK BIT_ULL(62)
+#define IRDMA_UDA_CQPSQ_MAV_IPV4VALID BIT_ULL(59)
+#define IRDMA_UDA_CQPSQ_MAV_AVIDX GENMASK_ULL(16, 0)
+#define IRDMA_UDA_CQPSQ_MAV_INSERTVLANTAG BIT_ULL(60)
+#define IRDMA_UDA_MGCTX_VFFLAG BIT_ULL(29)
+#define IRDMA_UDA_MGCTX_DESTPORT GENMASK_ULL(47, 32)
+#define IRDMA_UDA_MGCTX_VFID GENMASK_ULL(28, 22)
+#define IRDMA_UDA_MGCTX_VALIDENT BIT_ULL(31)
+#define IRDMA_UDA_MGCTX_PFID GENMASK_ULL(21, 18)
+#define IRDMA_UDA_MGCTX_FLAGIGNOREDPORT BIT_ULL(30)
+#define IRDMA_UDA_MGCTX_QPID GENMASK_ULL(17, 0)
+#define IRDMA_UDA_CQPSQ_MG_WQEVALID BIT_ULL(63)
+#define IRDMA_UDA_CQPSQ_MG_OPCODE GENMASK_ULL(37, 32)
+#define IRDMA_UDA_CQPSQ_MG_MGIDX GENMASK_ULL(12, 0)
+#define IRDMA_UDA_CQPSQ_MG_IPV4VALID BIT_ULL(60)
+#define IRDMA_UDA_CQPSQ_MG_VLANVALID BIT_ULL(59)
+#define IRDMA_UDA_CQPSQ_MG_HMC_FCN_ID GENMASK_ULL(5, 0)
+#define IRDMA_UDA_CQPSQ_MG_VLANID GENMASK_ULL(43, 32)
+#define IRDMA_UDA_CQPSQ_QS_HANDLE GENMASK_ULL(9, 0)
+#define IRDMA_UDA_CQPSQ_QHASH_QPN GENMASK_ULL(49, 32)
+#define IRDMA_UDA_CQPSQ_QHASH_ BIT_ULL(0)
+#define IRDMA_UDA_CQPSQ_QHASH_SRC_PORT GENMASK_ULL(31, 16)
+#define IRDMA_UDA_CQPSQ_QHASH_DEST_PORT GENMASK_ULL(15, 0)
+#define IRDMA_UDA_CQPSQ_QHASH_ADDR0 GENMASK_ULL(63, 32)
+#define IRDMA_UDA_CQPSQ_QHASH_ADDR1 GENMASK_ULL(31, 0)
+#define IRDMA_UDA_CQPSQ_QHASH_ADDR2 GENMASK_ULL(63, 32)
+#define IRDMA_UDA_CQPSQ_QHASH_ADDR3 GENMASK_ULL(31, 0)
+#define IRDMA_UDA_CQPSQ_QHASH_WQEVALID BIT_ULL(63)
+#define IRDMA_UDA_CQPSQ_QHASH_OPCODE GENMASK_ULL(37, 32)
+#define IRDMA_UDA_CQPSQ_QHASH_MANAGE GENMASK_ULL(62, 61)
+#define IRDMA_UDA_CQPSQ_QHASH_IPV4VALID GENMASK_ULL(60, 60)
+#define IRDMA_UDA_CQPSQ_QHASH_LANFWD GENMASK_ULL(59, 59)
+#define IRDMA_UDA_CQPSQ_QHASH_ENTRYTYPE GENMASK_ULL(44, 42)
+#endif /* IRDMA_UDA_D_H */
diff --git a/drivers/infiniband/hw/irdma/uk.c b/drivers/infiniband/hw/irdma/uk.c
new file mode 100644
index 000000000000..a6d52c20091c
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/uk.c
@@ -0,0 +1,1684 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#include "osdep.h"
+#include "status.h"
+#include "defs.h"
+#include "user.h"
+#include "irdma.h"
+
+/**
+ * irdma_set_fragment - set fragment in wqe
+ * @wqe: wqe for setting fragment
+ * @offset: offset value
+ * @sge: sge length and stag
+ * @valid: The wqe valid
+ */
+static void irdma_set_fragment(__le64 *wqe, u32 offset, struct irdma_sge *sge,
+ u8 valid)
+{
+ if (sge) {
+ set_64bit_val(wqe, offset,
+ FIELD_PREP(IRDMAQPSQ_FRAG_TO, sge->tag_off));
+ set_64bit_val(wqe, offset + 8,
+ FIELD_PREP(IRDMAQPSQ_VALID, valid) |
+ FIELD_PREP(IRDMAQPSQ_FRAG_LEN, sge->len) |
+ FIELD_PREP(IRDMAQPSQ_FRAG_STAG, sge->stag));
+ } else {
+ set_64bit_val(wqe, offset, 0);
+ set_64bit_val(wqe, offset + 8,
+ FIELD_PREP(IRDMAQPSQ_VALID, valid));
+ }
+}
+
+/**
+ * irdma_set_fragment_gen_1 - set fragment in wqe
+ * @wqe: wqe for setting fragment
+ * @offset: offset value
+ * @sge: sge length and stag
+ * @valid: wqe valid flag
+ */
+static void irdma_set_fragment_gen_1(__le64 *wqe, u32 offset,
+ struct irdma_sge *sge, u8 valid)
+{
+ if (sge) {
+ set_64bit_val(wqe, offset,
+ FIELD_PREP(IRDMAQPSQ_FRAG_TO, sge->tag_off));
+ set_64bit_val(wqe, offset + 8,
+ FIELD_PREP(IRDMAQPSQ_GEN1_FRAG_LEN, sge->len) |
+ FIELD_PREP(IRDMAQPSQ_GEN1_FRAG_STAG, sge->stag));
+ } else {
+ set_64bit_val(wqe, offset, 0);
+ set_64bit_val(wqe, offset + 8, 0);
+ }
+}
+
+/**
+ * irdma_nop_1 - insert a NOP wqe
+ * @qp: hw qp ptr
+ */
+static enum irdma_status_code irdma_nop_1(struct irdma_qp_uk *qp)
+{
+ u64 hdr;
+ __le64 *wqe;
+ u32 wqe_idx;
+ bool signaled = false;
+
+ if (!qp->sq_ring.head)
+ return IRDMA_ERR_PARAM;
+
+ wqe_idx = IRDMA_RING_CURRENT_HEAD(qp->sq_ring);
+ wqe = qp->sq_base[wqe_idx].elem;
+
+ qp->sq_wrtrk_array[wqe_idx].quanta = IRDMA_QP_WQE_MIN_QUANTA;
+
+ set_64bit_val(wqe, 0, 0);
+ set_64bit_val(wqe, 8, 0);
+ set_64bit_val(wqe, 16, 0);
+
+ hdr = FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMAQP_OP_NOP) |
+ FIELD_PREP(IRDMAQPSQ_SIGCOMPL, signaled) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity);
+
+ /* make sure WQE is written before valid bit is set */
+ dma_wmb();
+
+ set_64bit_val(wqe, 24, hdr);
+
+ return 0;
+}
+
+/**
+ * irdma_clr_wqes - clear next 128 sq entries
+ * @qp: hw qp ptr
+ * @qp_wqe_idx: wqe_idx
+ */
+void irdma_clr_wqes(struct irdma_qp_uk *qp, u32 qp_wqe_idx)
+{
+ __le64 *wqe;
+ u32 wqe_idx;
+
+ if (!(qp_wqe_idx & 0x7F)) {
+ wqe_idx = (qp_wqe_idx + 128) % qp->sq_ring.size;
+ wqe = qp->sq_base[wqe_idx].elem;
+ if (wqe_idx)
+ memset(wqe, qp->swqe_polarity ? 0 : 0xFF, 0x1000);
+ else
+ memset(wqe, qp->swqe_polarity ? 0xFF : 0, 0x1000);
+ }
+}
+
+/**
+ * irdma_uk_qp_post_wr - ring doorbell
+ * @qp: hw qp ptr
+ */
+void irdma_uk_qp_post_wr(struct irdma_qp_uk *qp)
+{
+ u64 temp;
+ u32 hw_sq_tail;
+ u32 sw_sq_head;
+
+ /* valid bit is written and loads completed before reading shadow */
+ mb();
+
+ /* read the doorbell shadow area */
+ get_64bit_val(qp->shadow_area, 0, &temp);
+
+ hw_sq_tail = (u32)FIELD_GET(IRDMA_QP_DBSA_HW_SQ_TAIL, temp);
+ sw_sq_head = IRDMA_RING_CURRENT_HEAD(qp->sq_ring);
+ if (sw_sq_head != qp->initial_ring.head) {
+ if (qp->push_dropped) {
+ writel(qp->qp_id, qp->wqe_alloc_db);
+ qp->push_dropped = false;
+ } else if (sw_sq_head != hw_sq_tail) {
+ if (sw_sq_head > qp->initial_ring.head) {
+ if (hw_sq_tail >= qp->initial_ring.head &&
+ hw_sq_tail < sw_sq_head)
+ writel(qp->qp_id, qp->wqe_alloc_db);
+ } else {
+ if (hw_sq_tail >= qp->initial_ring.head ||
+ hw_sq_tail < sw_sq_head)
+ writel(qp->qp_id, qp->wqe_alloc_db);
+ }
+ }
+ }
+
+ qp->initial_ring.head = qp->sq_ring.head;
+}
+
+/**
+ * irdma_qp_ring_push_db - ring qp doorbell
+ * @qp: hw qp ptr
+ * @wqe_idx: wqe index
+ */
+static void irdma_qp_ring_push_db(struct irdma_qp_uk *qp, u32 wqe_idx)
+{
+ set_32bit_val(qp->push_db, 0,
+ FIELD_PREP(IRDMA_WQEALLOC_WQE_DESC_INDEX, wqe_idx >> 3) | qp->qp_id);
+ qp->initial_ring.head = qp->sq_ring.head;
+ qp->push_mode = true;
+ qp->push_dropped = false;
+}
+
+void irdma_qp_push_wqe(struct irdma_qp_uk *qp, __le64 *wqe, u16 quanta,
+ u32 wqe_idx, bool post_sq)
+{
+ __le64 *push;
+
+ if (IRDMA_RING_CURRENT_HEAD(qp->initial_ring) !=
+ IRDMA_RING_CURRENT_TAIL(qp->sq_ring) &&
+ !qp->push_mode) {
+ if (post_sq)
+ irdma_uk_qp_post_wr(qp);
+ } else {
+ push = (__le64 *)((uintptr_t)qp->push_wqe +
+ (wqe_idx & 0x7) * 0x20);
+ memcpy(push, wqe, quanta * IRDMA_QP_WQE_MIN_SIZE);
+ irdma_qp_ring_push_db(qp, wqe_idx);
+ }
+}
+
+/**
+ * irdma_qp_get_next_send_wqe - pad with NOP if needed, return where next WR should go
+ * @qp: hw qp ptr
+ * @wqe_idx: return wqe index
+ * @quanta: size of WR in quanta
+ * @total_size: size of WR in bytes
+ * @info: info on WR
+ */
+__le64 *irdma_qp_get_next_send_wqe(struct irdma_qp_uk *qp, u32 *wqe_idx,
+ u16 quanta, u32 total_size,
+ struct irdma_post_sq_info *info)
+{
+ __le64 *wqe;
+ __le64 *wqe_0 = NULL;
+ u32 nop_wqe_idx;
+ u16 avail_quanta;
+ u16 i;
+
+ avail_quanta = qp->uk_attrs->max_hw_sq_chunk -
+ (IRDMA_RING_CURRENT_HEAD(qp->sq_ring) %
+ qp->uk_attrs->max_hw_sq_chunk);
+ if (quanta <= avail_quanta) {
+ /* WR fits in current chunk */
+ if (quanta > IRDMA_SQ_RING_FREE_QUANTA(qp->sq_ring))
+ return NULL;
+ } else {
+ /* Need to pad with NOP */
+ if (quanta + avail_quanta >
+ IRDMA_SQ_RING_FREE_QUANTA(qp->sq_ring))
+ return NULL;
+
+ nop_wqe_idx = IRDMA_RING_CURRENT_HEAD(qp->sq_ring);
+ for (i = 0; i < avail_quanta; i++) {
+ irdma_nop_1(qp);
+ IRDMA_RING_MOVE_HEAD_NOCHECK(qp->sq_ring);
+ }
+ if (qp->push_db && info->push_wqe)
+ irdma_qp_push_wqe(qp, qp->sq_base[nop_wqe_idx].elem,
+ avail_quanta, nop_wqe_idx, true);
+ }
+
+ *wqe_idx = IRDMA_RING_CURRENT_HEAD(qp->sq_ring);
+ if (!*wqe_idx)
+ qp->swqe_polarity = !qp->swqe_polarity;
+
+ IRDMA_RING_MOVE_HEAD_BY_COUNT_NOCHECK(qp->sq_ring, quanta);
+
+ wqe = qp->sq_base[*wqe_idx].elem;
+ if (qp->uk_attrs->hw_rev == IRDMA_GEN_1 && quanta == 1 &&
+ (IRDMA_RING_CURRENT_HEAD(qp->sq_ring) & 1)) {
+ wqe_0 = qp->sq_base[IRDMA_RING_CURRENT_HEAD(qp->sq_ring)].elem;
+ wqe_0[3] = cpu_to_le64(FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity ? 0 : 1));
+ }
+ qp->sq_wrtrk_array[*wqe_idx].wrid = info->wr_id;
+ qp->sq_wrtrk_array[*wqe_idx].wr_len = total_size;
+ qp->sq_wrtrk_array[*wqe_idx].quanta = quanta;
+
+ return wqe;
+}
+
+/**
+ * irdma_qp_get_next_recv_wqe - get next qp's rcv wqe
+ * @qp: hw qp ptr
+ * @wqe_idx: return wqe index
+ */
+__le64 *irdma_qp_get_next_recv_wqe(struct irdma_qp_uk *qp, u32 *wqe_idx)
+{
+ __le64 *wqe;
+ enum irdma_status_code ret_code;
+
+ if (IRDMA_RING_FULL_ERR(qp->rq_ring))
+ return NULL;
+
+ IRDMA_ATOMIC_RING_MOVE_HEAD(qp->rq_ring, *wqe_idx, ret_code);
+ if (ret_code)
+ return NULL;
+
+ if (!*wqe_idx)
+ qp->rwqe_polarity = !qp->rwqe_polarity;
+ /* rq_wqe_size_multiplier is no of 32 byte quanta in one rq wqe */
+ wqe = qp->rq_base[*wqe_idx * qp->rq_wqe_size_multiplier].elem;
+
+ return wqe;
+}
+
+/**
+ * irdma_uk_rdma_write - rdma write operation
+ * @qp: hw qp ptr
+ * @info: post sq information
+ * @post_sq: flag to post sq
+ */
+enum irdma_status_code irdma_uk_rdma_write(struct irdma_qp_uk *qp,
+ struct irdma_post_sq_info *info,
+ bool post_sq)
+{
+ u64 hdr;
+ __le64 *wqe;
+ struct irdma_rdma_write *op_info;
+ u32 i, wqe_idx;
+ u32 total_size = 0, byte_off;
+ enum irdma_status_code ret_code;
+ u32 frag_cnt, addl_frag_cnt;
+ bool read_fence = false;
+ u16 quanta;
+
+ info->push_wqe = qp->push_db ? true : false;
+
+ op_info = &info->op.rdma_write;
+ if (op_info->num_lo_sges > qp->max_sq_frag_cnt)
+ return IRDMA_ERR_INVALID_FRAG_COUNT;
+
+ for (i = 0; i < op_info->num_lo_sges; i++)
+ total_size += op_info->lo_sg_list[i].len;
+
+ read_fence |= info->read_fence;
+
+ if (info->imm_data_valid)
+ frag_cnt = op_info->num_lo_sges + 1;
+ else
+ frag_cnt = op_info->num_lo_sges;
+ addl_frag_cnt = frag_cnt > 1 ? (frag_cnt - 1) : 0;
+ ret_code = irdma_fragcnt_to_quanta_sq(frag_cnt, &quanta);
+ if (ret_code)
+ return ret_code;
+
+ wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, quanta, total_size,
+ info);
+ if (!wqe)
+ return IRDMA_ERR_QP_TOOMANY_WRS_POSTED;
+
+ irdma_clr_wqes(qp, wqe_idx);
+
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMAQPSQ_FRAG_TO, op_info->rem_addr.tag_off));
+
+ if (info->imm_data_valid) {
+ set_64bit_val(wqe, 0,
+ FIELD_PREP(IRDMAQPSQ_IMMDATA, info->imm_data));
+ i = 0;
+ } else {
+ qp->wqe_ops.iw_set_fragment(wqe, 0,
+ op_info->lo_sg_list,
+ qp->swqe_polarity);
+ i = 1;
+ }
+
+ for (byte_off = 32; i < op_info->num_lo_sges; i++) {
+ qp->wqe_ops.iw_set_fragment(wqe, byte_off,
+ &op_info->lo_sg_list[i],
+ qp->swqe_polarity);
+ byte_off += 16;
+ }
+
+ /* if not an odd number set valid bit in next fragment */
+ if (qp->uk_attrs->hw_rev >= IRDMA_GEN_2 && !(frag_cnt & 0x01) &&
+ frag_cnt) {
+ qp->wqe_ops.iw_set_fragment(wqe, byte_off, NULL,
+ qp->swqe_polarity);
+ if (qp->uk_attrs->hw_rev == IRDMA_GEN_2)
+ ++addl_frag_cnt;
+ }
+
+ hdr = FIELD_PREP(IRDMAQPSQ_REMSTAG, op_info->rem_addr.stag) |
+ FIELD_PREP(IRDMAQPSQ_OPCODE, info->op_type) |
+ FIELD_PREP(IRDMAQPSQ_IMMDATAFLAG, info->imm_data_valid) |
+ FIELD_PREP(IRDMAQPSQ_REPORTRTT, info->report_rtt) |
+ FIELD_PREP(IRDMAQPSQ_ADDFRAGCNT, addl_frag_cnt) |
+ FIELD_PREP(IRDMAQPSQ_PUSHWQE, info->push_wqe) |
+ FIELD_PREP(IRDMAQPSQ_READFENCE, read_fence) |
+ FIELD_PREP(IRDMAQPSQ_LOCALFENCE, info->local_fence) |
+ FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity);
+
+ dma_wmb(); /* make sure WQE is populated before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+ if (info->push_wqe) {
+ irdma_qp_push_wqe(qp, wqe, quanta, wqe_idx, post_sq);
+ } else {
+ if (post_sq)
+ irdma_uk_qp_post_wr(qp);
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_uk_rdma_read - rdma read command
+ * @qp: hw qp ptr
+ * @info: post sq information
+ * @inv_stag: flag for inv_stag
+ * @post_sq: flag to post sq
+ */
+enum irdma_status_code irdma_uk_rdma_read(struct irdma_qp_uk *qp,
+ struct irdma_post_sq_info *info,
+ bool inv_stag, bool post_sq)
+{
+ struct irdma_rdma_read *op_info;
+ enum irdma_status_code ret_code;
+ u32 i, byte_off, total_size = 0;
+ bool local_fence = false;
+ u32 addl_frag_cnt;
+ __le64 *wqe;
+ u32 wqe_idx;
+ u16 quanta;
+ u64 hdr;
+
+ info->push_wqe = qp->push_db ? true : false;
+
+ op_info = &info->op.rdma_read;
+ if (qp->max_sq_frag_cnt < op_info->num_lo_sges)
+ return IRDMA_ERR_INVALID_FRAG_COUNT;
+
+ for (i = 0; i < op_info->num_lo_sges; i++)
+ total_size += op_info->lo_sg_list[i].len;
+
+ ret_code = irdma_fragcnt_to_quanta_sq(op_info->num_lo_sges, &quanta);
+ if (ret_code)
+ return ret_code;
+
+ wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, quanta, total_size,
+ info);
+ if (!wqe)
+ return IRDMA_ERR_QP_TOOMANY_WRS_POSTED;
+
+ irdma_clr_wqes(qp, wqe_idx);
+
+ addl_frag_cnt = op_info->num_lo_sges > 1 ?
+ (op_info->num_lo_sges - 1) : 0;
+ local_fence |= info->local_fence;
+
+ qp->wqe_ops.iw_set_fragment(wqe, 0, op_info->lo_sg_list,
+ qp->swqe_polarity);
+ for (i = 1, byte_off = 32; i < op_info->num_lo_sges; ++i) {
+ qp->wqe_ops.iw_set_fragment(wqe, byte_off,
+ &op_info->lo_sg_list[i],
+ qp->swqe_polarity);
+ byte_off += 16;
+ }
+
+ /* if not an odd number set valid bit in next fragment */
+ if (qp->uk_attrs->hw_rev >= IRDMA_GEN_2 &&
+ !(op_info->num_lo_sges & 0x01) && op_info->num_lo_sges) {
+ qp->wqe_ops.iw_set_fragment(wqe, byte_off, NULL,
+ qp->swqe_polarity);
+ if (qp->uk_attrs->hw_rev == IRDMA_GEN_2)
+ ++addl_frag_cnt;
+ }
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMAQPSQ_FRAG_TO, op_info->rem_addr.tag_off));
+ hdr = FIELD_PREP(IRDMAQPSQ_REMSTAG, op_info->rem_addr.stag) |
+ FIELD_PREP(IRDMAQPSQ_REPORTRTT, (info->report_rtt ? 1 : 0)) |
+ FIELD_PREP(IRDMAQPSQ_ADDFRAGCNT, addl_frag_cnt) |
+ FIELD_PREP(IRDMAQPSQ_OPCODE,
+ (inv_stag ? IRDMAQP_OP_RDMA_READ_LOC_INV : IRDMAQP_OP_RDMA_READ)) |
+ FIELD_PREP(IRDMAQPSQ_PUSHWQE, info->push_wqe) |
+ FIELD_PREP(IRDMAQPSQ_READFENCE, info->read_fence) |
+ FIELD_PREP(IRDMAQPSQ_LOCALFENCE, local_fence) |
+ FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity);
+
+ dma_wmb(); /* make sure WQE is populated before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+ if (info->push_wqe) {
+ irdma_qp_push_wqe(qp, wqe, quanta, wqe_idx, post_sq);
+ } else {
+ if (post_sq)
+ irdma_uk_qp_post_wr(qp);
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_uk_send - rdma send command
+ * @qp: hw qp ptr
+ * @info: post sq information
+ * @post_sq: flag to post sq
+ */
+enum irdma_status_code irdma_uk_send(struct irdma_qp_uk *qp,
+ struct irdma_post_sq_info *info,
+ bool post_sq)
+{
+ __le64 *wqe;
+ struct irdma_post_send *op_info;
+ u64 hdr;
+ u32 i, wqe_idx, total_size = 0, byte_off;
+ enum irdma_status_code ret_code;
+ u32 frag_cnt, addl_frag_cnt;
+ bool read_fence = false;
+ u16 quanta;
+
+ info->push_wqe = qp->push_db ? true : false;
+
+ op_info = &info->op.send;
+ if (qp->max_sq_frag_cnt < op_info->num_sges)
+ return IRDMA_ERR_INVALID_FRAG_COUNT;
+
+ for (i = 0; i < op_info->num_sges; i++)
+ total_size += op_info->sg_list[i].len;
+
+ if (info->imm_data_valid)
+ frag_cnt = op_info->num_sges + 1;
+ else
+ frag_cnt = op_info->num_sges;
+ ret_code = irdma_fragcnt_to_quanta_sq(frag_cnt, &quanta);
+ if (ret_code)
+ return ret_code;
+
+ wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, quanta, total_size,
+ info);
+ if (!wqe)
+ return IRDMA_ERR_QP_TOOMANY_WRS_POSTED;
+
+ irdma_clr_wqes(qp, wqe_idx);
+
+ read_fence |= info->read_fence;
+ addl_frag_cnt = frag_cnt > 1 ? (frag_cnt - 1) : 0;
+ if (info->imm_data_valid) {
+ set_64bit_val(wqe, 0,
+ FIELD_PREP(IRDMAQPSQ_IMMDATA, info->imm_data));
+ i = 0;
+ } else {
+ qp->wqe_ops.iw_set_fragment(wqe, 0, op_info->sg_list,
+ qp->swqe_polarity);
+ i = 1;
+ }
+
+ for (byte_off = 32; i < op_info->num_sges; i++) {
+ qp->wqe_ops.iw_set_fragment(wqe, byte_off, &op_info->sg_list[i],
+ qp->swqe_polarity);
+ byte_off += 16;
+ }
+
+ /* if not an odd number set valid bit in next fragment */
+ if (qp->uk_attrs->hw_rev >= IRDMA_GEN_2 && !(frag_cnt & 0x01) &&
+ frag_cnt) {
+ qp->wqe_ops.iw_set_fragment(wqe, byte_off, NULL,
+ qp->swqe_polarity);
+ if (qp->uk_attrs->hw_rev == IRDMA_GEN_2)
+ ++addl_frag_cnt;
+ }
+
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMAQPSQ_DESTQKEY, op_info->qkey) |
+ FIELD_PREP(IRDMAQPSQ_DESTQPN, op_info->dest_qp));
+ hdr = FIELD_PREP(IRDMAQPSQ_REMSTAG, info->stag_to_inv) |
+ FIELD_PREP(IRDMAQPSQ_AHID, op_info->ah_id) |
+ FIELD_PREP(IRDMAQPSQ_IMMDATAFLAG,
+ (info->imm_data_valid ? 1 : 0)) |
+ FIELD_PREP(IRDMAQPSQ_REPORTRTT, (info->report_rtt ? 1 : 0)) |
+ FIELD_PREP(IRDMAQPSQ_OPCODE, info->op_type) |
+ FIELD_PREP(IRDMAQPSQ_ADDFRAGCNT, addl_frag_cnt) |
+ FIELD_PREP(IRDMAQPSQ_PUSHWQE, info->push_wqe) |
+ FIELD_PREP(IRDMAQPSQ_READFENCE, read_fence) |
+ FIELD_PREP(IRDMAQPSQ_LOCALFENCE, info->local_fence) |
+ FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) |
+ FIELD_PREP(IRDMAQPSQ_UDPHEADER, info->udp_hdr) |
+ FIELD_PREP(IRDMAQPSQ_L4LEN, info->l4len) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity);
+
+ dma_wmb(); /* make sure WQE is populated before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+ if (info->push_wqe) {
+ irdma_qp_push_wqe(qp, wqe, quanta, wqe_idx, post_sq);
+ } else {
+ if (post_sq)
+ irdma_uk_qp_post_wr(qp);
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_set_mw_bind_wqe_gen_1 - set mw bind wqe
+ * @wqe: wqe for setting fragment
+ * @op_info: info for setting bind wqe values
+ */
+static void irdma_set_mw_bind_wqe_gen_1(__le64 *wqe,
+ struct irdma_bind_window *op_info)
+{
+ set_64bit_val(wqe, 0, (uintptr_t)op_info->va);
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMAQPSQ_PARENTMRSTAG, op_info->mw_stag) |
+ FIELD_PREP(IRDMAQPSQ_MWSTAG, op_info->mr_stag));
+ set_64bit_val(wqe, 16, op_info->bind_len);
+}
+
+/**
+ * irdma_copy_inline_data_gen_1 - Copy inline data to wqe
+ * @dest: pointer to wqe
+ * @src: pointer to inline data
+ * @len: length of inline data to copy
+ * @polarity: compatibility parameter
+ */
+static void irdma_copy_inline_data_gen_1(u8 *dest, u8 *src, u32 len,
+ u8 polarity)
+{
+ if (len <= 16) {
+ memcpy(dest, src, len);
+ } else {
+ memcpy(dest, src, 16);
+ src += 16;
+ dest = dest + 32;
+ memcpy(dest, src, len - 16);
+ }
+}
+
+/**
+ * irdma_inline_data_size_to_quanta_gen_1 - based on inline data, quanta
+ * @data_size: data size for inline
+ *
+ * Gets the quanta based on inline and immediate data.
+ */
+static inline u16 irdma_inline_data_size_to_quanta_gen_1(u32 data_size)
+{
+ return data_size <= 16 ? IRDMA_QP_WQE_MIN_QUANTA : 2;
+}
+
+/**
+ * irdma_set_mw_bind_wqe - set mw bind in wqe
+ * @wqe: wqe for setting mw bind
+ * @op_info: info for setting wqe values
+ */
+static void irdma_set_mw_bind_wqe(__le64 *wqe,
+ struct irdma_bind_window *op_info)
+{
+ set_64bit_val(wqe, 0, (uintptr_t)op_info->va);
+ set_64bit_val(wqe, 8,
+ FIELD_PREP(IRDMAQPSQ_PARENTMRSTAG, op_info->mr_stag) |
+ FIELD_PREP(IRDMAQPSQ_MWSTAG, op_info->mw_stag));
+ set_64bit_val(wqe, 16, op_info->bind_len);
+}
+
+/**
+ * irdma_copy_inline_data - Copy inline data to wqe
+ * @dest: pointer to wqe
+ * @src: pointer to inline data
+ * @len: length of inline data to copy
+ * @polarity: polarity of wqe valid bit
+ */
+static void irdma_copy_inline_data(u8 *dest, u8 *src, u32 len, u8 polarity)
+{
+ u8 inline_valid = polarity << IRDMA_INLINE_VALID_S;
+ u32 copy_size;
+
+ dest += 8;
+ if (len <= 8) {
+ memcpy(dest, src, len);
+ return;
+ }
+
+ *((u64 *)dest) = *((u64 *)src);
+ len -= 8;
+ src += 8;
+ dest += 24; /* point to additional 32 byte quanta */
+
+ while (len) {
+ copy_size = len < 31 ? len : 31;
+ memcpy(dest, src, copy_size);
+ *(dest + 31) = inline_valid;
+ len -= copy_size;
+ dest += 32;
+ src += copy_size;
+ }
+}
+
+/**
+ * irdma_inline_data_size_to_quanta - based on inline data, quanta
+ * @data_size: data size for inline
+ *
+ * Gets the quanta based on inline and immediate data.
+ */
+static u16 irdma_inline_data_size_to_quanta(u32 data_size)
+{
+ if (data_size <= 8)
+ return IRDMA_QP_WQE_MIN_QUANTA;
+ else if (data_size <= 39)
+ return 2;
+ else if (data_size <= 70)
+ return 3;
+ else if (data_size <= 101)
+ return 4;
+ else if (data_size <= 132)
+ return 5;
+ else if (data_size <= 163)
+ return 6;
+ else if (data_size <= 194)
+ return 7;
+ else
+ return 8;
+}
+
+/**
+ * irdma_uk_inline_rdma_write - inline rdma write operation
+ * @qp: hw qp ptr
+ * @info: post sq information
+ * @post_sq: flag to post sq
+ */
+enum irdma_status_code
+irdma_uk_inline_rdma_write(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info,
+ bool post_sq)
+{
+ __le64 *wqe;
+ struct irdma_inline_rdma_write *op_info;
+ u64 hdr = 0;
+ u32 wqe_idx;
+ bool read_fence = false;
+ u16 quanta;
+
+ info->push_wqe = qp->push_db ? true : false;
+ op_info = &info->op.inline_rdma_write;
+
+ if (op_info->len > qp->max_inline_data)
+ return IRDMA_ERR_INVALID_INLINE_DATA_SIZE;
+
+ quanta = qp->wqe_ops.iw_inline_data_size_to_quanta(op_info->len);
+ wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, quanta, op_info->len,
+ info);
+ if (!wqe)
+ return IRDMA_ERR_QP_TOOMANY_WRS_POSTED;
+
+ irdma_clr_wqes(qp, wqe_idx);
+
+ read_fence |= info->read_fence;
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMAQPSQ_FRAG_TO, op_info->rem_addr.tag_off));
+
+ hdr = FIELD_PREP(IRDMAQPSQ_REMSTAG, op_info->rem_addr.stag) |
+ FIELD_PREP(IRDMAQPSQ_OPCODE, info->op_type) |
+ FIELD_PREP(IRDMAQPSQ_INLINEDATALEN, op_info->len) |
+ FIELD_PREP(IRDMAQPSQ_REPORTRTT, info->report_rtt ? 1 : 0) |
+ FIELD_PREP(IRDMAQPSQ_INLINEDATAFLAG, 1) |
+ FIELD_PREP(IRDMAQPSQ_IMMDATAFLAG, info->imm_data_valid ? 1 : 0) |
+ FIELD_PREP(IRDMAQPSQ_PUSHWQE, info->push_wqe ? 1 : 0) |
+ FIELD_PREP(IRDMAQPSQ_READFENCE, read_fence) |
+ FIELD_PREP(IRDMAQPSQ_LOCALFENCE, info->local_fence) |
+ FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity);
+
+ if (info->imm_data_valid)
+ set_64bit_val(wqe, 0,
+ FIELD_PREP(IRDMAQPSQ_IMMDATA, info->imm_data));
+
+ qp->wqe_ops.iw_copy_inline_data((u8 *)wqe, op_info->data, op_info->len,
+ qp->swqe_polarity);
+ dma_wmb(); /* make sure WQE is populated before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ if (info->push_wqe) {
+ irdma_qp_push_wqe(qp, wqe, quanta, wqe_idx, post_sq);
+ } else {
+ if (post_sq)
+ irdma_uk_qp_post_wr(qp);
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_uk_inline_send - inline send operation
+ * @qp: hw qp ptr
+ * @info: post sq information
+ * @post_sq: flag to post sq
+ */
+enum irdma_status_code irdma_uk_inline_send(struct irdma_qp_uk *qp,
+ struct irdma_post_sq_info *info,
+ bool post_sq)
+{
+ __le64 *wqe;
+ struct irdma_post_inline_send *op_info;
+ u64 hdr;
+ u32 wqe_idx;
+ bool read_fence = false;
+ u16 quanta;
+
+ info->push_wqe = qp->push_db ? true : false;
+ op_info = &info->op.inline_send;
+
+ if (op_info->len > qp->max_inline_data)
+ return IRDMA_ERR_INVALID_INLINE_DATA_SIZE;
+
+ quanta = qp->wqe_ops.iw_inline_data_size_to_quanta(op_info->len);
+ wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, quanta, op_info->len,
+ info);
+ if (!wqe)
+ return IRDMA_ERR_QP_TOOMANY_WRS_POSTED;
+
+ irdma_clr_wqes(qp, wqe_idx);
+
+ set_64bit_val(wqe, 16,
+ FIELD_PREP(IRDMAQPSQ_DESTQKEY, op_info->qkey) |
+ FIELD_PREP(IRDMAQPSQ_DESTQPN, op_info->dest_qp));
+
+ read_fence |= info->read_fence;
+ hdr = FIELD_PREP(IRDMAQPSQ_REMSTAG, info->stag_to_inv) |
+ FIELD_PREP(IRDMAQPSQ_AHID, op_info->ah_id) |
+ FIELD_PREP(IRDMAQPSQ_OPCODE, info->op_type) |
+ FIELD_PREP(IRDMAQPSQ_INLINEDATALEN, op_info->len) |
+ FIELD_PREP(IRDMAQPSQ_IMMDATAFLAG,
+ (info->imm_data_valid ? 1 : 0)) |
+ FIELD_PREP(IRDMAQPSQ_REPORTRTT, (info->report_rtt ? 1 : 0)) |
+ FIELD_PREP(IRDMAQPSQ_INLINEDATAFLAG, 1) |
+ FIELD_PREP(IRDMAQPSQ_PUSHWQE, info->push_wqe) |
+ FIELD_PREP(IRDMAQPSQ_READFENCE, read_fence) |
+ FIELD_PREP(IRDMAQPSQ_LOCALFENCE, info->local_fence) |
+ FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) |
+ FIELD_PREP(IRDMAQPSQ_UDPHEADER, info->udp_hdr) |
+ FIELD_PREP(IRDMAQPSQ_L4LEN, info->l4len) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity);
+
+ if (info->imm_data_valid)
+ set_64bit_val(wqe, 0,
+ FIELD_PREP(IRDMAQPSQ_IMMDATA, info->imm_data));
+ qp->wqe_ops.iw_copy_inline_data((u8 *)wqe, op_info->data, op_info->len,
+ qp->swqe_polarity);
+
+ dma_wmb(); /* make sure WQE is populated before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ if (info->push_wqe) {
+ irdma_qp_push_wqe(qp, wqe, quanta, wqe_idx, post_sq);
+ } else {
+ if (post_sq)
+ irdma_uk_qp_post_wr(qp);
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_uk_stag_local_invalidate - stag invalidate operation
+ * @qp: hw qp ptr
+ * @info: post sq information
+ * @post_sq: flag to post sq
+ */
+enum irdma_status_code
+irdma_uk_stag_local_invalidate(struct irdma_qp_uk *qp,
+ struct irdma_post_sq_info *info, bool post_sq)
+{
+ __le64 *wqe;
+ struct irdma_inv_local_stag *op_info;
+ u64 hdr;
+ u32 wqe_idx;
+ bool local_fence = false;
+ struct irdma_sge sge = {};
+
+ info->push_wqe = qp->push_db ? true : false;
+ op_info = &info->op.inv_local_stag;
+ local_fence = info->local_fence;
+
+ wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, IRDMA_QP_WQE_MIN_QUANTA,
+ 0, info);
+ if (!wqe)
+ return IRDMA_ERR_QP_TOOMANY_WRS_POSTED;
+
+ irdma_clr_wqes(qp, wqe_idx);
+
+ sge.stag = op_info->target_stag;
+ qp->wqe_ops.iw_set_fragment(wqe, 0, &sge, 0);
+
+ set_64bit_val(wqe, 16, 0);
+
+ hdr = FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMA_OP_TYPE_INV_STAG) |
+ FIELD_PREP(IRDMAQPSQ_PUSHWQE, info->push_wqe) |
+ FIELD_PREP(IRDMAQPSQ_READFENCE, info->read_fence) |
+ FIELD_PREP(IRDMAQPSQ_LOCALFENCE, local_fence) |
+ FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity);
+
+ dma_wmb(); /* make sure WQE is populated before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ if (info->push_wqe) {
+ irdma_qp_push_wqe(qp, wqe, IRDMA_QP_WQE_MIN_QUANTA, wqe_idx,
+ post_sq);
+ } else {
+ if (post_sq)
+ irdma_uk_qp_post_wr(qp);
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_uk_mw_bind - bind Memory Window
+ * @qp: hw qp ptr
+ * @info: post sq information
+ * @post_sq: flag to post sq
+ */
+enum irdma_status_code irdma_uk_mw_bind(struct irdma_qp_uk *qp,
+ struct irdma_post_sq_info *info,
+ bool post_sq)
+{
+ __le64 *wqe;
+ struct irdma_bind_window *op_info;
+ u64 hdr;
+ u32 wqe_idx;
+ bool local_fence = false;
+
+ info->push_wqe = qp->push_db ? true : false;
+ op_info = &info->op.bind_window;
+ local_fence |= info->local_fence;
+
+ wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, IRDMA_QP_WQE_MIN_QUANTA,
+ 0, info);
+ if (!wqe)
+ return IRDMA_ERR_QP_TOOMANY_WRS_POSTED;
+
+ irdma_clr_wqes(qp, wqe_idx);
+
+ qp->wqe_ops.iw_set_mw_bind_wqe(wqe, op_info);
+
+ hdr = FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMA_OP_TYPE_BIND_MW) |
+ FIELD_PREP(IRDMAQPSQ_STAGRIGHTS,
+ ((op_info->ena_reads << 2) | (op_info->ena_writes << 3))) |
+ FIELD_PREP(IRDMAQPSQ_VABASEDTO,
+ (op_info->addressing_type == IRDMA_ADDR_TYPE_VA_BASED ? 1 : 0)) |
+ FIELD_PREP(IRDMAQPSQ_MEMWINDOWTYPE,
+ (op_info->mem_window_type_1 ? 1 : 0)) |
+ FIELD_PREP(IRDMAQPSQ_PUSHWQE, info->push_wqe) |
+ FIELD_PREP(IRDMAQPSQ_READFENCE, info->read_fence) |
+ FIELD_PREP(IRDMAQPSQ_LOCALFENCE, local_fence) |
+ FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity);
+
+ dma_wmb(); /* make sure WQE is populated before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ if (info->push_wqe) {
+ irdma_qp_push_wqe(qp, wqe, IRDMA_QP_WQE_MIN_QUANTA, wqe_idx,
+ post_sq);
+ } else {
+ if (post_sq)
+ irdma_uk_qp_post_wr(qp);
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_uk_post_receive - post receive wqe
+ * @qp: hw qp ptr
+ * @info: post rq information
+ */
+enum irdma_status_code irdma_uk_post_receive(struct irdma_qp_uk *qp,
+ struct irdma_post_rq_info *info)
+{
+ u32 total_size = 0, wqe_idx, i, byte_off;
+ u32 addl_frag_cnt;
+ __le64 *wqe;
+ u64 hdr;
+
+ if (qp->max_rq_frag_cnt < info->num_sges)
+ return IRDMA_ERR_INVALID_FRAG_COUNT;
+
+ for (i = 0; i < info->num_sges; i++)
+ total_size += info->sg_list[i].len;
+
+ wqe = irdma_qp_get_next_recv_wqe(qp, &wqe_idx);
+ if (!wqe)
+ return IRDMA_ERR_QP_TOOMANY_WRS_POSTED;
+
+ qp->rq_wrid_array[wqe_idx] = info->wr_id;
+ addl_frag_cnt = info->num_sges > 1 ? (info->num_sges - 1) : 0;
+ qp->wqe_ops.iw_set_fragment(wqe, 0, info->sg_list,
+ qp->rwqe_polarity);
+
+ for (i = 1, byte_off = 32; i < info->num_sges; i++) {
+ qp->wqe_ops.iw_set_fragment(wqe, byte_off, &info->sg_list[i],
+ qp->rwqe_polarity);
+ byte_off += 16;
+ }
+
+ /* if not an odd number set valid bit in next fragment */
+ if (qp->uk_attrs->hw_rev >= IRDMA_GEN_2 && !(info->num_sges & 0x01) &&
+ info->num_sges) {
+ qp->wqe_ops.iw_set_fragment(wqe, byte_off, NULL,
+ qp->rwqe_polarity);
+ if (qp->uk_attrs->hw_rev == IRDMA_GEN_2)
+ ++addl_frag_cnt;
+ }
+
+ set_64bit_val(wqe, 16, 0);
+ hdr = FIELD_PREP(IRDMAQPSQ_ADDFRAGCNT, addl_frag_cnt) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->rwqe_polarity);
+
+ dma_wmb(); /* make sure WQE is populated before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+
+ return 0;
+}
+
+/**
+ * irdma_uk_cq_resize - reset the cq buffer info
+ * @cq: cq to resize
+ * @cq_base: new cq buffer addr
+ * @cq_size: number of cqes
+ */
+void irdma_uk_cq_resize(struct irdma_cq_uk *cq, void *cq_base, int cq_size)
+{
+ cq->cq_base = cq_base;
+ cq->cq_size = cq_size;
+ IRDMA_RING_INIT(cq->cq_ring, cq->cq_size);
+ cq->polarity = 1;
+}
+
+/**
+ * irdma_uk_cq_set_resized_cnt - record the count of the resized buffers
+ * @cq: cq to resize
+ * @cq_cnt: the count of the resized cq buffers
+ */
+void irdma_uk_cq_set_resized_cnt(struct irdma_cq_uk *cq, u16 cq_cnt)
+{
+ u64 temp_val;
+ u16 sw_cq_sel;
+ u8 arm_next_se;
+ u8 arm_next;
+ u8 arm_seq_num;
+
+ get_64bit_val(cq->shadow_area, 32, &temp_val);
+
+ sw_cq_sel = (u16)FIELD_GET(IRDMA_CQ_DBSA_SW_CQ_SELECT, temp_val);
+ sw_cq_sel += cq_cnt;
+
+ arm_seq_num = (u8)FIELD_GET(IRDMA_CQ_DBSA_ARM_SEQ_NUM, temp_val);
+ arm_next_se = (u8)FIELD_GET(IRDMA_CQ_DBSA_ARM_NEXT_SE, temp_val);
+ arm_next = (u8)FIELD_GET(IRDMA_CQ_DBSA_ARM_NEXT, temp_val);
+
+ temp_val = FIELD_PREP(IRDMA_CQ_DBSA_ARM_SEQ_NUM, arm_seq_num) |
+ FIELD_PREP(IRDMA_CQ_DBSA_SW_CQ_SELECT, sw_cq_sel) |
+ FIELD_PREP(IRDMA_CQ_DBSA_ARM_NEXT_SE, arm_next_se) |
+ FIELD_PREP(IRDMA_CQ_DBSA_ARM_NEXT, arm_next);
+
+ set_64bit_val(cq->shadow_area, 32, temp_val);
+}
+
+/**
+ * irdma_uk_cq_request_notification - cq notification request (door bell)
+ * @cq: hw cq
+ * @cq_notify: notification type
+ */
+void irdma_uk_cq_request_notification(struct irdma_cq_uk *cq,
+ enum irdma_cmpl_notify cq_notify)
+{
+ u64 temp_val;
+ u16 sw_cq_sel;
+ u8 arm_next_se = 0;
+ u8 arm_next = 0;
+ u8 arm_seq_num;
+
+ get_64bit_val(cq->shadow_area, 32, &temp_val);
+ arm_seq_num = (u8)FIELD_GET(IRDMA_CQ_DBSA_ARM_SEQ_NUM, temp_val);
+ arm_seq_num++;
+ sw_cq_sel = (u16)FIELD_GET(IRDMA_CQ_DBSA_SW_CQ_SELECT, temp_val);
+ arm_next_se = (u8)FIELD_GET(IRDMA_CQ_DBSA_ARM_NEXT_SE, temp_val);
+ arm_next_se |= 1;
+ if (cq_notify == IRDMA_CQ_COMPL_EVENT)
+ arm_next = 1;
+ temp_val = FIELD_PREP(IRDMA_CQ_DBSA_ARM_SEQ_NUM, arm_seq_num) |
+ FIELD_PREP(IRDMA_CQ_DBSA_SW_CQ_SELECT, sw_cq_sel) |
+ FIELD_PREP(IRDMA_CQ_DBSA_ARM_NEXT_SE, arm_next_se) |
+ FIELD_PREP(IRDMA_CQ_DBSA_ARM_NEXT, arm_next);
+
+ set_64bit_val(cq->shadow_area, 32, temp_val);
+
+ dma_wmb(); /* make sure WQE is populated before valid bit is set */
+
+ writel(cq->cq_id, cq->cqe_alloc_db);
+}
+
+/**
+ * irdma_uk_cq_poll_cmpl - get cq completion info
+ * @cq: hw cq
+ * @info: cq poll information returned
+ */
+enum irdma_status_code
+irdma_uk_cq_poll_cmpl(struct irdma_cq_uk *cq, struct irdma_cq_poll_info *info)
+{
+ u64 comp_ctx, qword0, qword2, qword3;
+ __le64 *cqe;
+ struct irdma_qp_uk *qp;
+ struct irdma_ring *pring = NULL;
+ u32 wqe_idx, q_type;
+ enum irdma_status_code ret_code;
+ bool move_cq_head = true;
+ u8 polarity;
+ bool ext_valid;
+ __le64 *ext_cqe;
+
+ if (cq->avoid_mem_cflct)
+ cqe = IRDMA_GET_CURRENT_EXTENDED_CQ_ELEM(cq);
+ else
+ cqe = IRDMA_GET_CURRENT_CQ_ELEM(cq);
+
+ get_64bit_val(cqe, 24, &qword3);
+ polarity = (u8)FIELD_GET(IRDMA_CQ_VALID, qword3);
+ if (polarity != cq->polarity)
+ return IRDMA_ERR_Q_EMPTY;
+
+ /* Ensure CQE contents are read after valid bit is checked */
+ dma_rmb();
+
+ ext_valid = (bool)FIELD_GET(IRDMA_CQ_EXTCQE, qword3);
+ if (ext_valid) {
+ u64 qword6, qword7;
+ u32 peek_head;
+
+ if (cq->avoid_mem_cflct) {
+ ext_cqe = (__le64 *)((u8 *)cqe + 32);
+ get_64bit_val(ext_cqe, 24, &qword7);
+ polarity = (u8)FIELD_GET(IRDMA_CQ_VALID, qword3);
+ } else {
+ peek_head = (cq->cq_ring.head + 1) % cq->cq_ring.size;
+ ext_cqe = cq->cq_base[peek_head].buf;
+ get_64bit_val(ext_cqe, 24, &qword7);
+ polarity = (u8)FIELD_GET(IRDMA_CQ_VALID, qword3);
+ if (!peek_head)
+ polarity ^= 1;
+ }
+ if (polarity != cq->polarity)
+ return IRDMA_ERR_Q_EMPTY;
+
+ /* Ensure ext CQE contents are read after ext valid bit is checked */
+ dma_rmb();
+
+ info->imm_valid = (bool)FIELD_GET(IRDMA_CQ_IMMVALID, qword7);
+ if (info->imm_valid) {
+ u64 qword4;
+
+ get_64bit_val(ext_cqe, 0, &qword4);
+ info->imm_data = (u32)FIELD_GET(IRDMA_CQ_IMMDATALOW32, qword4);
+ }
+ info->ud_smac_valid = (bool)FIELD_GET(IRDMA_CQ_UDSMACVALID, qword7);
+ info->ud_vlan_valid = (bool)FIELD_GET(IRDMA_CQ_UDVLANVALID, qword7);
+ if (info->ud_smac_valid || info->ud_vlan_valid) {
+ get_64bit_val(ext_cqe, 16, &qword6);
+ if (info->ud_vlan_valid)
+ info->ud_vlan = (u16)FIELD_GET(IRDMA_CQ_UDVLAN, qword6);
+ if (info->ud_smac_valid) {
+ info->ud_smac[5] = qword6 & 0xFF;
+ info->ud_smac[4] = (qword6 >> 8) & 0xFF;
+ info->ud_smac[3] = (qword6 >> 16) & 0xFF;
+ info->ud_smac[2] = (qword6 >> 24) & 0xFF;
+ info->ud_smac[1] = (qword6 >> 32) & 0xFF;
+ info->ud_smac[0] = (qword6 >> 40) & 0xFF;
+ }
+ }
+ } else {
+ info->imm_valid = false;
+ info->ud_smac_valid = false;
+ info->ud_vlan_valid = false;
+ }
+
+ q_type = (u8)FIELD_GET(IRDMA_CQ_SQ, qword3);
+ info->error = (bool)FIELD_GET(IRDMA_CQ_ERROR, qword3);
+ info->push_dropped = (bool)FIELD_GET(IRDMACQ_PSHDROP, qword3);
+ info->ipv4 = (bool)FIELD_GET(IRDMACQ_IPV4, qword3);
+ if (info->error) {
+ info->major_err = FIELD_GET(IRDMA_CQ_MAJERR, qword3);
+ info->minor_err = FIELD_GET(IRDMA_CQ_MINERR, qword3);
+ if (info->major_err == IRDMA_FLUSH_MAJOR_ERR) {
+ info->comp_status = IRDMA_COMPL_STATUS_FLUSHED;
+ /* Set the min error to standard flush error code for remaining cqes */
+ if (info->minor_err != FLUSH_GENERAL_ERR) {
+ qword3 &= ~IRDMA_CQ_MINERR;
+ qword3 |= FIELD_PREP(IRDMA_CQ_MINERR, FLUSH_GENERAL_ERR);
+ set_64bit_val(cqe, 24, qword3);
+ }
+ } else {
+ info->comp_status = IRDMA_COMPL_STATUS_UNKNOWN;
+ }
+ } else {
+ info->comp_status = IRDMA_COMPL_STATUS_SUCCESS;
+ }
+
+ get_64bit_val(cqe, 0, &qword0);
+ get_64bit_val(cqe, 16, &qword2);
+
+ info->tcp_seq_num_rtt = (u32)FIELD_GET(IRDMACQ_TCPSEQNUMRTT, qword0);
+ info->qp_id = (u32)FIELD_GET(IRDMACQ_QPID, qword2);
+ info->ud_src_qpn = (u32)FIELD_GET(IRDMACQ_UDSRCQPN, qword2);
+
+ get_64bit_val(cqe, 8, &comp_ctx);
+
+ info->solicited_event = (bool)FIELD_GET(IRDMACQ_SOEVENT, qword3);
+ qp = (struct irdma_qp_uk *)(unsigned long)comp_ctx;
+ if (!qp || qp->destroy_pending) {
+ ret_code = IRDMA_ERR_Q_DESTROYED;
+ goto exit;
+ }
+ wqe_idx = (u32)FIELD_GET(IRDMA_CQ_WQEIDX, qword3);
+ info->qp_handle = (irdma_qp_handle)(unsigned long)qp;
+
+ if (q_type == IRDMA_CQE_QTYPE_RQ) {
+ u32 array_idx;
+
+ array_idx = wqe_idx / qp->rq_wqe_size_multiplier;
+
+ if (info->comp_status == IRDMA_COMPL_STATUS_FLUSHED ||
+ info->comp_status == IRDMA_COMPL_STATUS_UNKNOWN) {
+ if (!IRDMA_RING_MORE_WORK(qp->rq_ring)) {
+ ret_code = IRDMA_ERR_Q_EMPTY;
+ goto exit;
+ }
+
+ info->wr_id = qp->rq_wrid_array[qp->rq_ring.tail];
+ array_idx = qp->rq_ring.tail;
+ } else {
+ info->wr_id = qp->rq_wrid_array[array_idx];
+ }
+
+ info->bytes_xfered = (u32)FIELD_GET(IRDMACQ_PAYLDLEN, qword0);
+
+ if (info->imm_valid)
+ info->op_type = IRDMA_OP_TYPE_REC_IMM;
+ else
+ info->op_type = IRDMA_OP_TYPE_REC;
+ if (qword3 & IRDMACQ_STAG) {
+ info->stag_invalid_set = true;
+ info->inv_stag = (u32)FIELD_GET(IRDMACQ_INVSTAG, qword2);
+ } else {
+ info->stag_invalid_set = false;
+ }
+ IRDMA_RING_SET_TAIL(qp->rq_ring, array_idx + 1);
+ if (info->comp_status == IRDMA_COMPL_STATUS_FLUSHED) {
+ qp->rq_flush_seen = true;
+ if (!IRDMA_RING_MORE_WORK(qp->rq_ring))
+ qp->rq_flush_complete = true;
+ else
+ move_cq_head = false;
+ }
+ pring = &qp->rq_ring;
+ } else { /* q_type is IRDMA_CQE_QTYPE_SQ */
+ if (qp->first_sq_wq) {
+ if (wqe_idx + 1 >= qp->conn_wqes)
+ qp->first_sq_wq = false;
+
+ if (wqe_idx < qp->conn_wqes && qp->sq_ring.head == qp->sq_ring.tail) {
+ IRDMA_RING_MOVE_HEAD_NOCHECK(cq->cq_ring);
+ IRDMA_RING_MOVE_TAIL(cq->cq_ring);
+ set_64bit_val(cq->shadow_area, 0,
+ IRDMA_RING_CURRENT_HEAD(cq->cq_ring));
+ memset(info, 0,
+ sizeof(struct irdma_cq_poll_info));
+ return irdma_uk_cq_poll_cmpl(cq, info);
+ }
+ }
+ /*cease posting push mode on push drop*/
+ if (info->push_dropped) {
+ qp->push_mode = false;
+ qp->push_dropped = true;
+ }
+ if (info->comp_status != IRDMA_COMPL_STATUS_FLUSHED) {
+ info->wr_id = qp->sq_wrtrk_array[wqe_idx].wrid;
+ if (!info->comp_status)
+ info->bytes_xfered = qp->sq_wrtrk_array[wqe_idx].wr_len;
+ info->op_type = (u8)FIELD_GET(IRDMACQ_OP, qword3);
+ IRDMA_RING_SET_TAIL(qp->sq_ring,
+ wqe_idx + qp->sq_wrtrk_array[wqe_idx].quanta);
+ } else {
+ if (!IRDMA_RING_MORE_WORK(qp->sq_ring)) {
+ ret_code = IRDMA_ERR_Q_EMPTY;
+ goto exit;
+ }
+
+ do {
+ __le64 *sw_wqe;
+ u64 wqe_qword;
+ u8 op_type;
+ u32 tail;
+
+ tail = qp->sq_ring.tail;
+ sw_wqe = qp->sq_base[tail].elem;
+ get_64bit_val(sw_wqe, 24,
+ &wqe_qword);
+ op_type = (u8)FIELD_GET(IRDMAQPSQ_OPCODE, wqe_qword);
+ info->op_type = op_type;
+ IRDMA_RING_SET_TAIL(qp->sq_ring,
+ tail + qp->sq_wrtrk_array[tail].quanta);
+ if (op_type != IRDMAQP_OP_NOP) {
+ info->wr_id = qp->sq_wrtrk_array[tail].wrid;
+ info->bytes_xfered = qp->sq_wrtrk_array[tail].wr_len;
+ break;
+ }
+ } while (1);
+ qp->sq_flush_seen = true;
+ if (!IRDMA_RING_MORE_WORK(qp->sq_ring))
+ qp->sq_flush_complete = true;
+ }
+ pring = &qp->sq_ring;
+ }
+
+ ret_code = 0;
+
+exit:
+ if (!ret_code && info->comp_status == IRDMA_COMPL_STATUS_FLUSHED)
+ if (pring && IRDMA_RING_MORE_WORK(*pring))
+ move_cq_head = false;
+
+ if (move_cq_head) {
+ IRDMA_RING_MOVE_HEAD_NOCHECK(cq->cq_ring);
+ if (!IRDMA_RING_CURRENT_HEAD(cq->cq_ring))
+ cq->polarity ^= 1;
+
+ if (ext_valid && !cq->avoid_mem_cflct) {
+ IRDMA_RING_MOVE_HEAD_NOCHECK(cq->cq_ring);
+ if (!IRDMA_RING_CURRENT_HEAD(cq->cq_ring))
+ cq->polarity ^= 1;
+ }
+
+ IRDMA_RING_MOVE_TAIL(cq->cq_ring);
+ if (!cq->avoid_mem_cflct && ext_valid)
+ IRDMA_RING_MOVE_TAIL(cq->cq_ring);
+ set_64bit_val(cq->shadow_area, 0,
+ IRDMA_RING_CURRENT_HEAD(cq->cq_ring));
+ } else {
+ qword3 &= ~IRDMA_CQ_WQEIDX;
+ qword3 |= FIELD_PREP(IRDMA_CQ_WQEIDX, pring->tail);
+ set_64bit_val(cqe, 24, qword3);
+ }
+
+ return ret_code;
+}
+
+/**
+ * irdma_qp_round_up - return round up qp wq depth
+ * @wqdepth: wq depth in quanta to round up
+ */
+static int irdma_qp_round_up(u32 wqdepth)
+{
+ int scount = 1;
+
+ for (wqdepth--; scount <= 16; scount *= 2)
+ wqdepth |= wqdepth >> scount;
+
+ return ++wqdepth;
+}
+
+/**
+ * irdma_get_wqe_shift - get shift count for maximum wqe size
+ * @uk_attrs: qp HW attributes
+ * @sge: Maximum Scatter Gather Elements wqe
+ * @inline_data: Maximum inline data size
+ * @shift: Returns the shift needed based on sge
+ *
+ * Shift can be used to left shift the wqe size based on number of SGEs and inlind data size.
+ * For 1 SGE or inline data <= 8, shift = 0 (wqe size of 32
+ * bytes). For 2 or 3 SGEs or inline data <= 39, shift = 1 (wqe
+ * size of 64 bytes).
+ * For 4-7 SGE's and inline <= 101 Shift of 2 otherwise (wqe
+ * size of 256 bytes).
+ */
+void irdma_get_wqe_shift(struct irdma_uk_attrs *uk_attrs, u32 sge,
+ u32 inline_data, u8 *shift)
+{
+ *shift = 0;
+ if (uk_attrs->hw_rev >= IRDMA_GEN_2) {
+ if (sge > 1 || inline_data > 8) {
+ if (sge < 4 && inline_data <= 39)
+ *shift = 1;
+ else if (sge < 8 && inline_data <= 101)
+ *shift = 2;
+ else
+ *shift = 3;
+ }
+ } else if (sge > 1 || inline_data > 16) {
+ *shift = (sge < 4 && inline_data <= 48) ? 1 : 2;
+ }
+}
+
+/*
+ * irdma_get_sqdepth - get SQ depth (quanta)
+ * @uk_attrs: qp HW attributes
+ * @sq_size: SQ size
+ * @shift: shift which determines size of WQE
+ * @sqdepth: depth of SQ
+ *
+ */
+enum irdma_status_code irdma_get_sqdepth(struct irdma_uk_attrs *uk_attrs,
+ u32 sq_size, u8 shift, u32 *sqdepth)
+{
+ *sqdepth = irdma_qp_round_up((sq_size << shift) + IRDMA_SQ_RSVD);
+
+ if (*sqdepth < (IRDMA_QP_SW_MIN_WQSIZE << shift))
+ *sqdepth = IRDMA_QP_SW_MIN_WQSIZE << shift;
+ else if (*sqdepth > uk_attrs->max_hw_wq_quanta)
+ return IRDMA_ERR_INVALID_SIZE;
+
+ return 0;
+}
+
+/*
+ * irdma_get_rqdepth - get RQ depth (quanta)
+ * @uk_attrs: qp HW attributes
+ * @rq_size: RQ size
+ * @shift: shift which determines size of WQE
+ * @rqdepth: depth of RQ
+ */
+enum irdma_status_code irdma_get_rqdepth(struct irdma_uk_attrs *uk_attrs,
+ u32 rq_size, u8 shift, u32 *rqdepth)
+{
+ *rqdepth = irdma_qp_round_up((rq_size << shift) + IRDMA_RQ_RSVD);
+
+ if (*rqdepth < (IRDMA_QP_SW_MIN_WQSIZE << shift))
+ *rqdepth = IRDMA_QP_SW_MIN_WQSIZE << shift;
+ else if (*rqdepth > uk_attrs->max_hw_rq_quanta)
+ return IRDMA_ERR_INVALID_SIZE;
+
+ return 0;
+}
+
+static const struct irdma_wqe_uk_ops iw_wqe_uk_ops = {
+ .iw_copy_inline_data = irdma_copy_inline_data,
+ .iw_inline_data_size_to_quanta = irdma_inline_data_size_to_quanta,
+ .iw_set_fragment = irdma_set_fragment,
+ .iw_set_mw_bind_wqe = irdma_set_mw_bind_wqe,
+};
+
+static const struct irdma_wqe_uk_ops iw_wqe_uk_ops_gen_1 = {
+ .iw_copy_inline_data = irdma_copy_inline_data_gen_1,
+ .iw_inline_data_size_to_quanta = irdma_inline_data_size_to_quanta_gen_1,
+ .iw_set_fragment = irdma_set_fragment_gen_1,
+ .iw_set_mw_bind_wqe = irdma_set_mw_bind_wqe_gen_1,
+};
+
+/**
+ * irdma_setup_connection_wqes - setup WQEs necessary to complete
+ * connection.
+ * @qp: hw qp (user and kernel)
+ * @info: qp initialization info
+ */
+static void irdma_setup_connection_wqes(struct irdma_qp_uk *qp,
+ struct irdma_qp_uk_init_info *info)
+{
+ u16 move_cnt = 1;
+
+ if (!info->legacy_mode &&
+ (qp->uk_attrs->feature_flags & IRDMA_FEATURE_RTS_AE))
+ move_cnt = 3;
+
+ qp->conn_wqes = move_cnt;
+ IRDMA_RING_MOVE_HEAD_BY_COUNT_NOCHECK(qp->sq_ring, move_cnt);
+ IRDMA_RING_MOVE_TAIL_BY_COUNT(qp->sq_ring, move_cnt);
+ IRDMA_RING_MOVE_HEAD_BY_COUNT_NOCHECK(qp->initial_ring, move_cnt);
+}
+
+/**
+ * irdma_uk_qp_init - initialize shared qp
+ * @qp: hw qp (user and kernel)
+ * @info: qp initialization info
+ *
+ * initializes the vars used in both user and kernel mode.
+ * size of the wqe depends on numbers of max. fragements
+ * allowed. Then size of wqe * the number of wqes should be the
+ * amount of memory allocated for sq and rq.
+ */
+enum irdma_status_code irdma_uk_qp_init(struct irdma_qp_uk *qp,
+ struct irdma_qp_uk_init_info *info)
+{
+ enum irdma_status_code ret_code = 0;
+ u32 sq_ring_size;
+ u8 sqshift, rqshift;
+
+ qp->uk_attrs = info->uk_attrs;
+ if (info->max_sq_frag_cnt > qp->uk_attrs->max_hw_wq_frags ||
+ info->max_rq_frag_cnt > qp->uk_attrs->max_hw_wq_frags)
+ return IRDMA_ERR_INVALID_FRAG_COUNT;
+
+ irdma_get_wqe_shift(qp->uk_attrs, info->max_rq_frag_cnt, 0, &rqshift);
+ if (qp->uk_attrs->hw_rev == IRDMA_GEN_1) {
+ irdma_get_wqe_shift(qp->uk_attrs, info->max_sq_frag_cnt,
+ info->max_inline_data, &sqshift);
+ if (info->abi_ver > 4)
+ rqshift = IRDMA_MAX_RQ_WQE_SHIFT_GEN1;
+ } else {
+ irdma_get_wqe_shift(qp->uk_attrs, info->max_sq_frag_cnt + 1,
+ info->max_inline_data, &sqshift);
+ }
+ qp->qp_caps = info->qp_caps;
+ qp->sq_base = info->sq;
+ qp->rq_base = info->rq;
+ qp->qp_type = info->type ? info->type : IRDMA_QP_TYPE_IWARP;
+ qp->shadow_area = info->shadow_area;
+ qp->sq_wrtrk_array = info->sq_wrtrk_array;
+
+ qp->rq_wrid_array = info->rq_wrid_array;
+ qp->wqe_alloc_db = info->wqe_alloc_db;
+ qp->qp_id = info->qp_id;
+ qp->sq_size = info->sq_size;
+ qp->push_mode = false;
+ qp->max_sq_frag_cnt = info->max_sq_frag_cnt;
+ sq_ring_size = qp->sq_size << sqshift;
+ IRDMA_RING_INIT(qp->sq_ring, sq_ring_size);
+ IRDMA_RING_INIT(qp->initial_ring, sq_ring_size);
+ if (info->first_sq_wq) {
+ irdma_setup_connection_wqes(qp, info);
+ qp->swqe_polarity = 1;
+ qp->first_sq_wq = true;
+ } else {
+ qp->swqe_polarity = 0;
+ }
+ qp->swqe_polarity_deferred = 1;
+ qp->rwqe_polarity = 0;
+ qp->rq_size = info->rq_size;
+ qp->max_rq_frag_cnt = info->max_rq_frag_cnt;
+ qp->max_inline_data = info->max_inline_data;
+ qp->rq_wqe_size = rqshift;
+ IRDMA_RING_INIT(qp->rq_ring, qp->rq_size);
+ qp->rq_wqe_size_multiplier = 1 << rqshift;
+ if (qp->uk_attrs->hw_rev == IRDMA_GEN_1)
+ qp->wqe_ops = iw_wqe_uk_ops_gen_1;
+ else
+ qp->wqe_ops = iw_wqe_uk_ops;
+ return ret_code;
+}
+
+/**
+ * irdma_uk_cq_init - initialize shared cq (user and kernel)
+ * @cq: hw cq
+ * @info: hw cq initialization info
+ */
+enum irdma_status_code irdma_uk_cq_init(struct irdma_cq_uk *cq,
+ struct irdma_cq_uk_init_info *info)
+{
+ cq->cq_base = info->cq_base;
+ cq->cq_id = info->cq_id;
+ cq->cq_size = info->cq_size;
+ cq->cqe_alloc_db = info->cqe_alloc_db;
+ cq->cq_ack_db = info->cq_ack_db;
+ cq->shadow_area = info->shadow_area;
+ cq->avoid_mem_cflct = info->avoid_mem_cflct;
+ IRDMA_RING_INIT(cq->cq_ring, cq->cq_size);
+ cq->polarity = 1;
+
+ return 0;
+}
+
+/**
+ * irdma_uk_clean_cq - clean cq entries
+ * @q: completion context
+ * @cq: cq to clean
+ */
+void irdma_uk_clean_cq(void *q, struct irdma_cq_uk *cq)
+{
+ __le64 *cqe;
+ u64 qword3, comp_ctx;
+ u32 cq_head;
+ u8 polarity, temp;
+
+ cq_head = cq->cq_ring.head;
+ temp = cq->polarity;
+ do {
+ if (cq->avoid_mem_cflct)
+ cqe = ((struct irdma_extended_cqe *)(cq->cq_base))[cq_head].buf;
+ else
+ cqe = cq->cq_base[cq_head].buf;
+ get_64bit_val(cqe, 24, &qword3);
+ polarity = (u8)FIELD_GET(IRDMA_CQ_VALID, qword3);
+
+ if (polarity != temp)
+ break;
+
+ get_64bit_val(cqe, 8, &comp_ctx);
+ if ((void *)(unsigned long)comp_ctx == q)
+ set_64bit_val(cqe, 8, 0);
+
+ cq_head = (cq_head + 1) % cq->cq_ring.size;
+ if (!cq_head)
+ temp ^= 1;
+ } while (true);
+}
+
+/**
+ * irdma_nop - post a nop
+ * @qp: hw qp ptr
+ * @wr_id: work request id
+ * @signaled: signaled for completion
+ * @post_sq: ring doorbell
+ */
+enum irdma_status_code irdma_nop(struct irdma_qp_uk *qp, u64 wr_id,
+ bool signaled, bool post_sq)
+{
+ __le64 *wqe;
+ u64 hdr;
+ u32 wqe_idx;
+ struct irdma_post_sq_info info = {};
+
+ info.push_wqe = false;
+ info.wr_id = wr_id;
+ wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, IRDMA_QP_WQE_MIN_QUANTA,
+ 0, &info);
+ if (!wqe)
+ return IRDMA_ERR_QP_TOOMANY_WRS_POSTED;
+
+ irdma_clr_wqes(qp, wqe_idx);
+
+ set_64bit_val(wqe, 0, 0);
+ set_64bit_val(wqe, 8, 0);
+ set_64bit_val(wqe, 16, 0);
+
+ hdr = FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMAQP_OP_NOP) |
+ FIELD_PREP(IRDMAQPSQ_SIGCOMPL, signaled) |
+ FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity);
+
+ dma_wmb(); /* make sure WQE is populated before valid bit is set */
+
+ set_64bit_val(wqe, 24, hdr);
+ if (post_sq)
+ irdma_uk_qp_post_wr(qp);
+
+ return 0;
+}
+
+/**
+ * irdma_fragcnt_to_quanta_sq - calculate quanta based on fragment count for SQ
+ * @frag_cnt: number of fragments
+ * @quanta: quanta for frag_cnt
+ */
+enum irdma_status_code irdma_fragcnt_to_quanta_sq(u32 frag_cnt, u16 *quanta)
+{
+ switch (frag_cnt) {
+ case 0:
+ case 1:
+ *quanta = IRDMA_QP_WQE_MIN_QUANTA;
+ break;
+ case 2:
+ case 3:
+ *quanta = 2;
+ break;
+ case 4:
+ case 5:
+ *quanta = 3;
+ break;
+ case 6:
+ case 7:
+ *quanta = 4;
+ break;
+ case 8:
+ case 9:
+ *quanta = 5;
+ break;
+ case 10:
+ case 11:
+ *quanta = 6;
+ break;
+ case 12:
+ case 13:
+ *quanta = 7;
+ break;
+ case 14:
+ case 15: /* when immediate data is present */
+ *quanta = 8;
+ break;
+ default:
+ return IRDMA_ERR_INVALID_FRAG_COUNT;
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_fragcnt_to_wqesize_rq - calculate wqe size based on fragment count for RQ
+ * @frag_cnt: number of fragments
+ * @wqe_size: size in bytes given frag_cnt
+ */
+enum irdma_status_code irdma_fragcnt_to_wqesize_rq(u32 frag_cnt, u16 *wqe_size)
+{
+ switch (frag_cnt) {
+ case 0:
+ case 1:
+ *wqe_size = 32;
+ break;
+ case 2:
+ case 3:
+ *wqe_size = 64;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ *wqe_size = 128;
+ break;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ *wqe_size = 256;
+ break;
+ default:
+ return IRDMA_ERR_INVALID_FRAG_COUNT;
+ }
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/irdma/user.h b/drivers/infiniband/hw/irdma/user.h
new file mode 100644
index 000000000000..ff705f323233
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/user.h
@@ -0,0 +1,437 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2015 - 2020 Intel Corporation */
+#ifndef IRDMA_USER_H
+#define IRDMA_USER_H
+
+#define irdma_handle void *
+#define irdma_adapter_handle irdma_handle
+#define irdma_qp_handle irdma_handle
+#define irdma_cq_handle irdma_handle
+#define irdma_pd_id irdma_handle
+#define irdma_stag_handle irdma_handle
+#define irdma_stag_index u32
+#define irdma_stag u32
+#define irdma_stag_key u8
+#define irdma_tagged_offset u64
+#define irdma_access_privileges u32
+#define irdma_physical_fragment u64
+#define irdma_address_list u64 *
+#define irdma_sgl struct irdma_sge *
+
+#define IRDMA_MAX_MR_SIZE 0x200000000000ULL
+
+#define IRDMA_ACCESS_FLAGS_LOCALREAD 0x01
+#define IRDMA_ACCESS_FLAGS_LOCALWRITE 0x02
+#define IRDMA_ACCESS_FLAGS_REMOTEREAD_ONLY 0x04
+#define IRDMA_ACCESS_FLAGS_REMOTEREAD 0x05
+#define IRDMA_ACCESS_FLAGS_REMOTEWRITE_ONLY 0x08
+#define IRDMA_ACCESS_FLAGS_REMOTEWRITE 0x0a
+#define IRDMA_ACCESS_FLAGS_BIND_WINDOW 0x10
+#define IRDMA_ACCESS_FLAGS_ZERO_BASED 0x20
+#define IRDMA_ACCESS_FLAGS_ALL 0x3f
+
+#define IRDMA_OP_TYPE_RDMA_WRITE 0x00
+#define IRDMA_OP_TYPE_RDMA_READ 0x01
+#define IRDMA_OP_TYPE_SEND 0x03
+#define IRDMA_OP_TYPE_SEND_INV 0x04
+#define IRDMA_OP_TYPE_SEND_SOL 0x05
+#define IRDMA_OP_TYPE_SEND_SOL_INV 0x06
+#define IRDMA_OP_TYPE_RDMA_WRITE_SOL 0x0d
+#define IRDMA_OP_TYPE_BIND_MW 0x08
+#define IRDMA_OP_TYPE_FAST_REG_NSMR 0x09
+#define IRDMA_OP_TYPE_INV_STAG 0x0a
+#define IRDMA_OP_TYPE_RDMA_READ_INV_STAG 0x0b
+#define IRDMA_OP_TYPE_NOP 0x0c
+#define IRDMA_OP_TYPE_REC 0x3e
+#define IRDMA_OP_TYPE_REC_IMM 0x3f
+
+#define IRDMA_FLUSH_MAJOR_ERR 1
+
+enum irdma_device_caps_const {
+ IRDMA_WQE_SIZE = 4,
+ IRDMA_CQP_WQE_SIZE = 8,
+ IRDMA_CQE_SIZE = 4,
+ IRDMA_EXTENDED_CQE_SIZE = 8,
+ IRDMA_AEQE_SIZE = 2,
+ IRDMA_CEQE_SIZE = 1,
+ IRDMA_CQP_CTX_SIZE = 8,
+ IRDMA_SHADOW_AREA_SIZE = 8,
+ IRDMA_QUERY_FPM_BUF_SIZE = 176,
+ IRDMA_COMMIT_FPM_BUF_SIZE = 176,
+ IRDMA_GATHER_STATS_BUF_SIZE = 1024,
+ IRDMA_MIN_IW_QP_ID = 0,
+ IRDMA_MAX_IW_QP_ID = 262143,
+ IRDMA_MIN_CEQID = 0,
+ IRDMA_MAX_CEQID = 1023,
+ IRDMA_CEQ_MAX_COUNT = IRDMA_MAX_CEQID + 1,
+ IRDMA_MIN_CQID = 0,
+ IRDMA_MAX_CQID = 524287,
+ IRDMA_MIN_AEQ_ENTRIES = 1,
+ IRDMA_MAX_AEQ_ENTRIES = 524287,
+ IRDMA_MIN_CEQ_ENTRIES = 1,
+ IRDMA_MAX_CEQ_ENTRIES = 262143,
+ IRDMA_MIN_CQ_SIZE = 1,
+ IRDMA_MAX_CQ_SIZE = 1048575,
+ IRDMA_DB_ID_ZERO = 0,
+ IRDMA_MAX_WQ_FRAGMENT_COUNT = 13,
+ IRDMA_MAX_SGE_RD = 13,
+ IRDMA_MAX_OUTBOUND_MSG_SIZE = 2147483647,
+ IRDMA_MAX_INBOUND_MSG_SIZE = 2147483647,
+ IRDMA_MAX_PUSH_PAGE_COUNT = 1024,
+ IRDMA_MAX_PE_ENA_VF_COUNT = 32,
+ IRDMA_MAX_VF_FPM_ID = 47,
+ IRDMA_MAX_SQ_PAYLOAD_SIZE = 2145386496,
+ IRDMA_MAX_INLINE_DATA_SIZE = 101,
+ IRDMA_MAX_WQ_ENTRIES = 32768,
+ IRDMA_Q2_BUF_SIZE = 256,
+ IRDMA_QP_CTX_SIZE = 256,
+ IRDMA_MAX_PDS = 262144,
+};
+
+enum irdma_addressing_type {
+ IRDMA_ADDR_TYPE_ZERO_BASED = 0,
+ IRDMA_ADDR_TYPE_VA_BASED = 1,
+};
+
+enum irdma_flush_opcode {
+ FLUSH_INVALID = 0,
+ FLUSH_GENERAL_ERR,
+ FLUSH_PROT_ERR,
+ FLUSH_REM_ACCESS_ERR,
+ FLUSH_LOC_QP_OP_ERR,
+ FLUSH_REM_OP_ERR,
+ FLUSH_LOC_LEN_ERR,
+ FLUSH_FATAL_ERR,
+};
+
+enum irdma_cmpl_status {
+ IRDMA_COMPL_STATUS_SUCCESS = 0,
+ IRDMA_COMPL_STATUS_FLUSHED,
+ IRDMA_COMPL_STATUS_INVALID_WQE,
+ IRDMA_COMPL_STATUS_QP_CATASTROPHIC,
+ IRDMA_COMPL_STATUS_REMOTE_TERMINATION,
+ IRDMA_COMPL_STATUS_INVALID_STAG,
+ IRDMA_COMPL_STATUS_BASE_BOUND_VIOLATION,
+ IRDMA_COMPL_STATUS_ACCESS_VIOLATION,
+ IRDMA_COMPL_STATUS_INVALID_PD_ID,
+ IRDMA_COMPL_STATUS_WRAP_ERROR,
+ IRDMA_COMPL_STATUS_STAG_INVALID_PDID,
+ IRDMA_COMPL_STATUS_RDMA_READ_ZERO_ORD,
+ IRDMA_COMPL_STATUS_QP_NOT_PRIVLEDGED,
+ IRDMA_COMPL_STATUS_STAG_NOT_INVALID,
+ IRDMA_COMPL_STATUS_INVALID_PHYS_BUF_SIZE,
+ IRDMA_COMPL_STATUS_INVALID_PHYS_BUF_ENTRY,
+ IRDMA_COMPL_STATUS_INVALID_FBO,
+ IRDMA_COMPL_STATUS_INVALID_LEN,
+ IRDMA_COMPL_STATUS_INVALID_ACCESS,
+ IRDMA_COMPL_STATUS_PHYS_BUF_LIST_TOO_LONG,
+ IRDMA_COMPL_STATUS_INVALID_VIRT_ADDRESS,
+ IRDMA_COMPL_STATUS_INVALID_REGION,
+ IRDMA_COMPL_STATUS_INVALID_WINDOW,
+ IRDMA_COMPL_STATUS_INVALID_TOTAL_LEN,
+ IRDMA_COMPL_STATUS_UNKNOWN,
+};
+
+enum irdma_cmpl_notify {
+ IRDMA_CQ_COMPL_EVENT = 0,
+ IRDMA_CQ_COMPL_SOLICITED = 1,
+};
+
+enum irdma_qp_caps {
+ IRDMA_WRITE_WITH_IMM = 1,
+ IRDMA_SEND_WITH_IMM = 2,
+ IRDMA_ROCE = 4,
+ IRDMA_PUSH_MODE = 8,
+};
+
+struct irdma_qp_uk;
+struct irdma_cq_uk;
+struct irdma_qp_uk_init_info;
+struct irdma_cq_uk_init_info;
+
+struct irdma_sge {
+ irdma_tagged_offset tag_off;
+ u32 len;
+ irdma_stag stag;
+};
+
+struct irdma_ring {
+ u32 head;
+ u32 tail;
+ u32 size;
+};
+
+struct irdma_cqe {
+ __le64 buf[IRDMA_CQE_SIZE];
+};
+
+struct irdma_extended_cqe {
+ __le64 buf[IRDMA_EXTENDED_CQE_SIZE];
+};
+
+struct irdma_post_send {
+ irdma_sgl sg_list;
+ u32 num_sges;
+ u32 qkey;
+ u32 dest_qp;
+ u32 ah_id;
+};
+
+struct irdma_post_inline_send {
+ void *data;
+ u32 len;
+ u32 qkey;
+ u32 dest_qp;
+ u32 ah_id;
+};
+
+struct irdma_post_rq_info {
+ u64 wr_id;
+ irdma_sgl sg_list;
+ u32 num_sges;
+};
+
+struct irdma_rdma_write {
+ irdma_sgl lo_sg_list;
+ u32 num_lo_sges;
+ struct irdma_sge rem_addr;
+};
+
+struct irdma_inline_rdma_write {
+ void *data;
+ u32 len;
+ struct irdma_sge rem_addr;
+};
+
+struct irdma_rdma_read {
+ irdma_sgl lo_sg_list;
+ u32 num_lo_sges;
+ struct irdma_sge rem_addr;
+};
+
+struct irdma_bind_window {
+ irdma_stag mr_stag;
+ u64 bind_len;
+ void *va;
+ enum irdma_addressing_type addressing_type;
+ bool ena_reads:1;
+ bool ena_writes:1;
+ irdma_stag mw_stag;
+ bool mem_window_type_1:1;
+};
+
+struct irdma_inv_local_stag {
+ irdma_stag target_stag;
+};
+
+struct irdma_post_sq_info {
+ u64 wr_id;
+ u8 op_type;
+ u8 l4len;
+ bool signaled:1;
+ bool read_fence:1;
+ bool local_fence:1;
+ bool inline_data:1;
+ bool imm_data_valid:1;
+ bool push_wqe:1;
+ bool report_rtt:1;
+ bool udp_hdr:1;
+ bool defer_flag:1;
+ u32 imm_data;
+ u32 stag_to_inv;
+ union {
+ struct irdma_post_send send;
+ struct irdma_rdma_write rdma_write;
+ struct irdma_rdma_read rdma_read;
+ struct irdma_bind_window bind_window;
+ struct irdma_inv_local_stag inv_local_stag;
+ struct irdma_inline_rdma_write inline_rdma_write;
+ struct irdma_post_inline_send inline_send;
+ } op;
+};
+
+struct irdma_cq_poll_info {
+ u64 wr_id;
+ irdma_qp_handle qp_handle;
+ u32 bytes_xfered;
+ u32 tcp_seq_num_rtt;
+ u32 qp_id;
+ u32 ud_src_qpn;
+ u32 imm_data;
+ irdma_stag inv_stag; /* or L_R_Key */
+ enum irdma_cmpl_status comp_status;
+ u16 major_err;
+ u16 minor_err;
+ u16 ud_vlan;
+ u8 ud_smac[6];
+ u8 op_type;
+ bool stag_invalid_set:1; /* or L_R_Key set */
+ bool push_dropped:1;
+ bool error:1;
+ bool solicited_event:1;
+ bool ipv4:1;
+ bool ud_vlan_valid:1;
+ bool ud_smac_valid:1;
+ bool imm_valid:1;
+};
+
+enum irdma_status_code irdma_uk_inline_rdma_write(struct irdma_qp_uk *qp,
+ struct irdma_post_sq_info *info,
+ bool post_sq);
+enum irdma_status_code irdma_uk_inline_send(struct irdma_qp_uk *qp,
+ struct irdma_post_sq_info *info,
+ bool post_sq);
+enum irdma_status_code irdma_uk_mw_bind(struct irdma_qp_uk *qp,
+ struct irdma_post_sq_info *info,
+ bool post_sq);
+enum irdma_status_code irdma_uk_post_nop(struct irdma_qp_uk *qp, u64 wr_id,
+ bool signaled, bool post_sq);
+enum irdma_status_code irdma_uk_post_receive(struct irdma_qp_uk *qp,
+ struct irdma_post_rq_info *info);
+void irdma_uk_qp_post_wr(struct irdma_qp_uk *qp);
+enum irdma_status_code irdma_uk_rdma_read(struct irdma_qp_uk *qp,
+ struct irdma_post_sq_info *info,
+ bool inv_stag, bool post_sq);
+enum irdma_status_code irdma_uk_rdma_write(struct irdma_qp_uk *qp,
+ struct irdma_post_sq_info *info,
+ bool post_sq);
+enum irdma_status_code irdma_uk_send(struct irdma_qp_uk *qp,
+ struct irdma_post_sq_info *info, bool post_sq);
+enum irdma_status_code irdma_uk_stag_local_invalidate(struct irdma_qp_uk *qp,
+ struct irdma_post_sq_info *info,
+ bool post_sq);
+
+struct irdma_wqe_uk_ops {
+ void (*iw_copy_inline_data)(u8 *dest, u8 *src, u32 len, u8 polarity);
+ u16 (*iw_inline_data_size_to_quanta)(u32 data_size);
+ void (*iw_set_fragment)(__le64 *wqe, u32 offset, struct irdma_sge *sge,
+ u8 valid);
+ void (*iw_set_mw_bind_wqe)(__le64 *wqe,
+ struct irdma_bind_window *op_info);
+};
+
+enum irdma_status_code irdma_uk_cq_poll_cmpl(struct irdma_cq_uk *cq,
+ struct irdma_cq_poll_info *info);
+void irdma_uk_cq_request_notification(struct irdma_cq_uk *cq,
+ enum irdma_cmpl_notify cq_notify);
+void irdma_uk_cq_resize(struct irdma_cq_uk *cq, void *cq_base, int size);
+void irdma_uk_cq_set_resized_cnt(struct irdma_cq_uk *qp, u16 cnt);
+enum irdma_status_code irdma_uk_cq_init(struct irdma_cq_uk *cq,
+ struct irdma_cq_uk_init_info *info);
+enum irdma_status_code irdma_uk_qp_init(struct irdma_qp_uk *qp,
+ struct irdma_qp_uk_init_info *info);
+struct irdma_sq_uk_wr_trk_info {
+ u64 wrid;
+ u32 wr_len;
+ u16 quanta;
+ u8 reserved[2];
+};
+
+struct irdma_qp_quanta {
+ __le64 elem[IRDMA_WQE_SIZE];
+};
+
+struct irdma_qp_uk {
+ struct irdma_qp_quanta *sq_base;
+ struct irdma_qp_quanta *rq_base;
+ struct irdma_uk_attrs *uk_attrs;
+ u32 __iomem *wqe_alloc_db;
+ struct irdma_sq_uk_wr_trk_info *sq_wrtrk_array;
+ u64 *rq_wrid_array;
+ __le64 *shadow_area;
+ __le32 *push_db;
+ __le64 *push_wqe;
+ struct irdma_ring sq_ring;
+ struct irdma_ring rq_ring;
+ struct irdma_ring initial_ring;
+ u32 qp_id;
+ u32 qp_caps;
+ u32 sq_size;
+ u32 rq_size;
+ u32 max_sq_frag_cnt;
+ u32 max_rq_frag_cnt;
+ u32 max_inline_data;
+ struct irdma_wqe_uk_ops wqe_ops;
+ u16 conn_wqes;
+ u8 qp_type;
+ u8 swqe_polarity;
+ u8 swqe_polarity_deferred;
+ u8 rwqe_polarity;
+ u8 rq_wqe_size;
+ u8 rq_wqe_size_multiplier;
+ bool deferred_flag:1;
+ bool push_mode:1; /* whether the last post wqe was pushed */
+ bool push_dropped:1;
+ bool first_sq_wq:1;
+ bool sq_flush_complete:1; /* Indicates flush was seen and SQ was empty after the flush */
+ bool rq_flush_complete:1; /* Indicates flush was seen and RQ was empty after the flush */
+ bool destroy_pending:1; /* Indicates the QP is being destroyed */
+ void *back_qp;
+ spinlock_t *lock;
+ u8 dbg_rq_flushed;
+ u8 sq_flush_seen;
+ u8 rq_flush_seen;
+};
+
+struct irdma_cq_uk {
+ struct irdma_cqe *cq_base;
+ u32 __iomem *cqe_alloc_db;
+ u32 __iomem *cq_ack_db;
+ __le64 *shadow_area;
+ u32 cq_id;
+ u32 cq_size;
+ struct irdma_ring cq_ring;
+ u8 polarity;
+ bool avoid_mem_cflct:1;
+};
+
+struct irdma_qp_uk_init_info {
+ struct irdma_qp_quanta *sq;
+ struct irdma_qp_quanta *rq;
+ struct irdma_uk_attrs *uk_attrs;
+ u32 __iomem *wqe_alloc_db;
+ __le64 *shadow_area;
+ struct irdma_sq_uk_wr_trk_info *sq_wrtrk_array;
+ u64 *rq_wrid_array;
+ u32 qp_id;
+ u32 qp_caps;
+ u32 sq_size;
+ u32 rq_size;
+ u32 max_sq_frag_cnt;
+ u32 max_rq_frag_cnt;
+ u32 max_inline_data;
+ u8 first_sq_wq;
+ u8 type;
+ int abi_ver;
+ bool legacy_mode;
+};
+
+struct irdma_cq_uk_init_info {
+ u32 __iomem *cqe_alloc_db;
+ u32 __iomem *cq_ack_db;
+ struct irdma_cqe *cq_base;
+ __le64 *shadow_area;
+ u32 cq_size;
+ u32 cq_id;
+ bool avoid_mem_cflct;
+};
+
+__le64 *irdma_qp_get_next_send_wqe(struct irdma_qp_uk *qp, u32 *wqe_idx,
+ u16 quanta, u32 total_size,
+ struct irdma_post_sq_info *info);
+__le64 *irdma_qp_get_next_recv_wqe(struct irdma_qp_uk *qp, u32 *wqe_idx);
+void irdma_uk_clean_cq(void *q, struct irdma_cq_uk *cq);
+enum irdma_status_code irdma_nop(struct irdma_qp_uk *qp, u64 wr_id,
+ bool signaled, bool post_sq);
+enum irdma_status_code irdma_fragcnt_to_quanta_sq(u32 frag_cnt, u16 *quanta);
+enum irdma_status_code irdma_fragcnt_to_wqesize_rq(u32 frag_cnt, u16 *wqe_size);
+void irdma_get_wqe_shift(struct irdma_uk_attrs *uk_attrs, u32 sge,
+ u32 inline_data, u8 *shift);
+enum irdma_status_code irdma_get_sqdepth(struct irdma_uk_attrs *uk_attrs,
+ u32 sq_size, u8 shift, u32 *wqdepth);
+enum irdma_status_code irdma_get_rqdepth(struct irdma_uk_attrs *uk_attrs,
+ u32 rq_size, u8 shift, u32 *wqdepth);
+void irdma_qp_push_wqe(struct irdma_qp_uk *qp, __le64 *wqe, u16 quanta,
+ u32 wqe_idx, bool post_sq);
+void irdma_clr_wqes(struct irdma_qp_uk *qp, u32 qp_wqe_idx);
+#endif /* IRDMA_USER_H */
diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c
new file mode 100644
index 000000000000..5bbe44e54f9a
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/utils.c
@@ -0,0 +1,2541 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#include "main.h"
+
+/**
+ * irdma_arp_table -manage arp table
+ * @rf: RDMA PCI function
+ * @ip_addr: ip address for device
+ * @ipv4: IPv4 flag
+ * @mac_addr: mac address ptr
+ * @action: modify, delete or add
+ */
+int irdma_arp_table(struct irdma_pci_f *rf, u32 *ip_addr, bool ipv4,
+ u8 *mac_addr, u32 action)
+{
+ unsigned long flags;
+ int arp_index;
+ u32 ip[4] = {};
+
+ if (ipv4)
+ ip[0] = *ip_addr;
+ else
+ memcpy(ip, ip_addr, sizeof(ip));
+
+ spin_lock_irqsave(&rf->arp_lock, flags);
+ for (arp_index = 0; (u32)arp_index < rf->arp_table_size; arp_index++) {
+ if (!memcmp(rf->arp_table[arp_index].ip_addr, ip, sizeof(ip)))
+ break;
+ }
+
+ switch (action) {
+ case IRDMA_ARP_ADD:
+ if (arp_index != rf->arp_table_size) {
+ arp_index = -1;
+ break;
+ }
+
+ arp_index = 0;
+ if (irdma_alloc_rsrc(rf, rf->allocated_arps, rf->arp_table_size,
+ (u32 *)&arp_index, &rf->next_arp_index)) {
+ arp_index = -1;
+ break;
+ }
+
+ memcpy(rf->arp_table[arp_index].ip_addr, ip,
+ sizeof(rf->arp_table[arp_index].ip_addr));
+ ether_addr_copy(rf->arp_table[arp_index].mac_addr, mac_addr);
+ break;
+ case IRDMA_ARP_RESOLVE:
+ if (arp_index == rf->arp_table_size)
+ arp_index = -1;
+ break;
+ case IRDMA_ARP_DELETE:
+ if (arp_index == rf->arp_table_size) {
+ arp_index = -1;
+ break;
+ }
+
+ memset(rf->arp_table[arp_index].ip_addr, 0,
+ sizeof(rf->arp_table[arp_index].ip_addr));
+ eth_zero_addr(rf->arp_table[arp_index].mac_addr);
+ irdma_free_rsrc(rf, rf->allocated_arps, arp_index);
+ break;
+ default:
+ arp_index = -1;
+ break;
+ }
+
+ spin_unlock_irqrestore(&rf->arp_lock, flags);
+ return arp_index;
+}
+
+/**
+ * irdma_add_arp - add a new arp entry if needed
+ * @rf: RDMA function
+ * @ip: IP address
+ * @ipv4: IPv4 flag
+ * @mac: MAC address
+ */
+int irdma_add_arp(struct irdma_pci_f *rf, u32 *ip, bool ipv4, u8 *mac)
+{
+ int arpidx;
+
+ arpidx = irdma_arp_table(rf, &ip[0], ipv4, NULL, IRDMA_ARP_RESOLVE);
+ if (arpidx >= 0) {
+ if (ether_addr_equal(rf->arp_table[arpidx].mac_addr, mac))
+ return arpidx;
+
+ irdma_manage_arp_cache(rf, rf->arp_table[arpidx].mac_addr, ip,
+ ipv4, IRDMA_ARP_DELETE);
+ }
+
+ irdma_manage_arp_cache(rf, mac, ip, ipv4, IRDMA_ARP_ADD);
+
+ return irdma_arp_table(rf, ip, ipv4, NULL, IRDMA_ARP_RESOLVE);
+}
+
+/**
+ * wr32 - write 32 bits to hw register
+ * @hw: hardware information including registers
+ * @reg: register offset
+ * @val: value to write to register
+ */
+inline void wr32(struct irdma_hw *hw, u32 reg, u32 val)
+{
+ writel(val, hw->hw_addr + reg);
+}
+
+/**
+ * rd32 - read a 32 bit hw register
+ * @hw: hardware information including registers
+ * @reg: register offset
+ *
+ * Return value of register content
+ */
+inline u32 rd32(struct irdma_hw *hw, u32 reg)
+{
+ return readl(hw->hw_addr + reg);
+}
+
+/**
+ * rd64 - read a 64 bit hw register
+ * @hw: hardware information including registers
+ * @reg: register offset
+ *
+ * Return value of register content
+ */
+inline u64 rd64(struct irdma_hw *hw, u32 reg)
+{
+ return readq(hw->hw_addr + reg);
+}
+
+static void irdma_gid_change_event(struct ib_device *ibdev)
+{
+ struct ib_event ib_event;
+
+ ib_event.event = IB_EVENT_GID_CHANGE;
+ ib_event.device = ibdev;
+ ib_event.element.port_num = 1;
+ ib_dispatch_event(&ib_event);
+}
+
+/**
+ * irdma_inetaddr_event - system notifier for ipv4 addr events
+ * @notifier: not used
+ * @event: event for notifier
+ * @ptr: if address
+ */
+int irdma_inetaddr_event(struct notifier_block *notifier, unsigned long event,
+ void *ptr)
+{
+ struct in_ifaddr *ifa = ptr;
+ struct net_device *netdev = ifa->ifa_dev->dev;
+ struct irdma_device *iwdev;
+ struct ib_device *ibdev;
+ u32 local_ipaddr;
+
+ ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_IRDMA);
+ if (!ibdev)
+ return NOTIFY_DONE;
+
+ iwdev = to_iwdev(ibdev);
+ local_ipaddr = ntohl(ifa->ifa_address);
+ ibdev_dbg(&iwdev->ibdev,
+ "DEV: netdev %p event %lu local_ip=%pI4 MAC=%pM\n", netdev,
+ event, &local_ipaddr, netdev->dev_addr);
+ switch (event) {
+ case NETDEV_DOWN:
+ irdma_manage_arp_cache(iwdev->rf, netdev->dev_addr,
+ &local_ipaddr, true, IRDMA_ARP_DELETE);
+ irdma_if_notify(iwdev, netdev, &local_ipaddr, true, false);
+ irdma_gid_change_event(&iwdev->ibdev);
+ break;
+ case NETDEV_UP:
+ case NETDEV_CHANGEADDR:
+ irdma_add_arp(iwdev->rf, &local_ipaddr, true, netdev->dev_addr);
+ irdma_if_notify(iwdev, netdev, &local_ipaddr, true, true);
+ irdma_gid_change_event(&iwdev->ibdev);
+ break;
+ default:
+ break;
+ }
+
+ ib_device_put(ibdev);
+
+ return NOTIFY_DONE;
+}
+
+/**
+ * irdma_inet6addr_event - system notifier for ipv6 addr events
+ * @notifier: not used
+ * @event: event for notifier
+ * @ptr: if address
+ */
+int irdma_inet6addr_event(struct notifier_block *notifier, unsigned long event,
+ void *ptr)
+{
+ struct inet6_ifaddr *ifa = ptr;
+ struct net_device *netdev = ifa->idev->dev;
+ struct irdma_device *iwdev;
+ struct ib_device *ibdev;
+ u32 local_ipaddr6[4];
+
+ ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_IRDMA);
+ if (!ibdev)
+ return NOTIFY_DONE;
+
+ iwdev = to_iwdev(ibdev);
+ irdma_copy_ip_ntohl(local_ipaddr6, ifa->addr.in6_u.u6_addr32);
+ ibdev_dbg(&iwdev->ibdev,
+ "DEV: netdev %p event %lu local_ip=%pI6 MAC=%pM\n", netdev,
+ event, local_ipaddr6, netdev->dev_addr);
+ switch (event) {
+ case NETDEV_DOWN:
+ irdma_manage_arp_cache(iwdev->rf, netdev->dev_addr,
+ local_ipaddr6, false, IRDMA_ARP_DELETE);
+ irdma_if_notify(iwdev, netdev, local_ipaddr6, false, false);
+ irdma_gid_change_event(&iwdev->ibdev);
+ break;
+ case NETDEV_UP:
+ case NETDEV_CHANGEADDR:
+ irdma_add_arp(iwdev->rf, local_ipaddr6, false,
+ netdev->dev_addr);
+ irdma_if_notify(iwdev, netdev, local_ipaddr6, false, true);
+ irdma_gid_change_event(&iwdev->ibdev);
+ break;
+ default:
+ break;
+ }
+
+ ib_device_put(ibdev);
+
+ return NOTIFY_DONE;
+}
+
+/**
+ * irdma_net_event - system notifier for net events
+ * @notifier: not used
+ * @event: event for notifier
+ * @ptr: neighbor
+ */
+int irdma_net_event(struct notifier_block *notifier, unsigned long event,
+ void *ptr)
+{
+ struct neighbour *neigh = ptr;
+ struct irdma_device *iwdev;
+ struct ib_device *ibdev;
+ __be32 *p;
+ u32 local_ipaddr[4] = {};
+ bool ipv4 = true;
+
+ ibdev = ib_device_get_by_netdev((struct net_device *)neigh->dev,
+ RDMA_DRIVER_IRDMA);
+ if (!ibdev)
+ return NOTIFY_DONE;
+
+ iwdev = to_iwdev(ibdev);
+
+ switch (event) {
+ case NETEVENT_NEIGH_UPDATE:
+ p = (__be32 *)neigh->primary_key;
+ if (neigh->tbl->family == AF_INET6) {
+ ipv4 = false;
+ irdma_copy_ip_ntohl(local_ipaddr, p);
+ } else {
+ local_ipaddr[0] = ntohl(*p);
+ }
+
+ ibdev_dbg(&iwdev->ibdev,
+ "DEV: netdev %p state %d local_ip=%pI4 MAC=%pM\n",
+ iwdev->netdev, neigh->nud_state, local_ipaddr,
+ neigh->ha);
+
+ if (neigh->nud_state & NUD_VALID)
+ irdma_add_arp(iwdev->rf, local_ipaddr, ipv4, neigh->ha);
+
+ else
+ irdma_manage_arp_cache(iwdev->rf, neigh->ha,
+ local_ipaddr, ipv4,
+ IRDMA_ARP_DELETE);
+ break;
+ default:
+ break;
+ }
+
+ ib_device_put(ibdev);
+
+ return NOTIFY_DONE;
+}
+
+/**
+ * irdma_netdevice_event - system notifier for netdev events
+ * @notifier: not used
+ * @event: event for notifier
+ * @ptr: netdev
+ */
+int irdma_netdevice_event(struct notifier_block *notifier, unsigned long event,
+ void *ptr)
+{
+ struct irdma_device *iwdev;
+ struct ib_device *ibdev;
+ struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+
+ ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_IRDMA);
+ if (!ibdev)
+ return NOTIFY_DONE;
+
+ iwdev = to_iwdev(ibdev);
+ iwdev->iw_status = 1;
+ switch (event) {
+ case NETDEV_DOWN:
+ iwdev->iw_status = 0;
+ fallthrough;
+ case NETDEV_UP:
+ irdma_port_ibevent(iwdev);
+ break;
+ default:
+ break;
+ }
+ ib_device_put(ibdev);
+
+ return NOTIFY_DONE;
+}
+
+/**
+ * irdma_add_ipv6_addr - add ipv6 address to the hw arp table
+ * @iwdev: irdma device
+ */
+static void irdma_add_ipv6_addr(struct irdma_device *iwdev)
+{
+ struct net_device *ip_dev;
+ struct inet6_dev *idev;
+ struct inet6_ifaddr *ifp, *tmp;
+ u32 local_ipaddr6[4];
+
+ rcu_read_lock();
+ for_each_netdev_rcu (&init_net, ip_dev) {
+ if (((rdma_vlan_dev_vlan_id(ip_dev) < 0xFFFF &&
+ rdma_vlan_dev_real_dev(ip_dev) == iwdev->netdev) ||
+ ip_dev == iwdev->netdev) &&
+ (READ_ONCE(ip_dev->flags) & IFF_UP)) {
+ idev = __in6_dev_get(ip_dev);
+ if (!idev) {
+ ibdev_err(&iwdev->ibdev, "ipv6 inet device not found\n");
+ break;
+ }
+ list_for_each_entry_safe (ifp, tmp, &idev->addr_list,
+ if_list) {
+ ibdev_dbg(&iwdev->ibdev,
+ "INIT: IP=%pI6, vlan_id=%d, MAC=%pM\n",
+ &ifp->addr,
+ rdma_vlan_dev_vlan_id(ip_dev),
+ ip_dev->dev_addr);
+
+ irdma_copy_ip_ntohl(local_ipaddr6,
+ ifp->addr.in6_u.u6_addr32);
+ irdma_manage_arp_cache(iwdev->rf,
+ ip_dev->dev_addr,
+ local_ipaddr6, false,
+ IRDMA_ARP_ADD);
+ }
+ }
+ }
+ rcu_read_unlock();
+}
+
+/**
+ * irdma_add_ipv4_addr - add ipv4 address to the hw arp table
+ * @iwdev: irdma device
+ */
+static void irdma_add_ipv4_addr(struct irdma_device *iwdev)
+{
+ struct net_device *dev;
+ struct in_device *idev;
+ u32 ip_addr;
+
+ rcu_read_lock();
+ for_each_netdev_rcu (&init_net, dev) {
+ if (((rdma_vlan_dev_vlan_id(dev) < 0xFFFF &&
+ rdma_vlan_dev_real_dev(dev) == iwdev->netdev) ||
+ dev == iwdev->netdev) && (READ_ONCE(dev->flags) & IFF_UP)) {
+ const struct in_ifaddr *ifa;
+
+ idev = __in_dev_get_rcu(dev);
+ if (!idev)
+ continue;
+
+ in_dev_for_each_ifa_rcu(ifa, idev) {
+ ibdev_dbg(&iwdev->ibdev, "CM: IP=%pI4, vlan_id=%d, MAC=%pM\n",
+ &ifa->ifa_address, rdma_vlan_dev_vlan_id(dev),
+ dev->dev_addr);
+
+ ip_addr = ntohl(ifa->ifa_address);
+ irdma_manage_arp_cache(iwdev->rf, dev->dev_addr,
+ &ip_addr, true,
+ IRDMA_ARP_ADD);
+ }
+ }
+ }
+ rcu_read_unlock();
+}
+
+/**
+ * irdma_add_ip - add ip addresses
+ * @iwdev: irdma device
+ *
+ * Add ipv4/ipv6 addresses to the arp cache
+ */
+void irdma_add_ip(struct irdma_device *iwdev)
+{
+ irdma_add_ipv4_addr(iwdev);
+ irdma_add_ipv6_addr(iwdev);
+}
+
+/**
+ * irdma_alloc_and_get_cqp_request - get cqp struct
+ * @cqp: device cqp ptr
+ * @wait: cqp to be used in wait mode
+ */
+struct irdma_cqp_request *irdma_alloc_and_get_cqp_request(struct irdma_cqp *cqp,
+ bool wait)
+{
+ struct irdma_cqp_request *cqp_request = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cqp->req_lock, flags);
+ if (!list_empty(&cqp->cqp_avail_reqs)) {
+ cqp_request = list_first_entry(&cqp->cqp_avail_reqs,
+ struct irdma_cqp_request, list);
+ list_del_init(&cqp_request->list);
+ }
+ spin_unlock_irqrestore(&cqp->req_lock, flags);
+ if (!cqp_request) {
+ cqp_request = kzalloc(sizeof(*cqp_request), GFP_ATOMIC);
+ if (cqp_request) {
+ cqp_request->dynamic = true;
+ if (wait)
+ init_waitqueue_head(&cqp_request->waitq);
+ }
+ }
+ if (!cqp_request) {
+ ibdev_dbg(to_ibdev(cqp->sc_cqp.dev), "ERR: CQP Request Fail: No Memory");
+ return NULL;
+ }
+
+ cqp_request->waiting = wait;
+ refcount_set(&cqp_request->refcnt, 1);
+ memset(&cqp_request->compl_info, 0, sizeof(cqp_request->compl_info));
+
+ return cqp_request;
+}
+
+/**
+ * irdma_get_cqp_request - increase refcount for cqp_request
+ * @cqp_request: pointer to cqp_request instance
+ */
+static inline void irdma_get_cqp_request(struct irdma_cqp_request *cqp_request)
+{
+ refcount_inc(&cqp_request->refcnt);
+}
+
+/**
+ * irdma_free_cqp_request - free cqp request
+ * @cqp: cqp ptr
+ * @cqp_request: to be put back in cqp list
+ */
+void irdma_free_cqp_request(struct irdma_cqp *cqp,
+ struct irdma_cqp_request *cqp_request)
+{
+ unsigned long flags;
+
+ if (cqp_request->dynamic) {
+ kfree(cqp_request);
+ } else {
+ cqp_request->request_done = false;
+ cqp_request->callback_fcn = NULL;
+ cqp_request->waiting = false;
+
+ spin_lock_irqsave(&cqp->req_lock, flags);
+ list_add_tail(&cqp_request->list, &cqp->cqp_avail_reqs);
+ spin_unlock_irqrestore(&cqp->req_lock, flags);
+ }
+ wake_up(&cqp->remove_wq);
+}
+
+/**
+ * irdma_put_cqp_request - dec ref count and free if 0
+ * @cqp: cqp ptr
+ * @cqp_request: to be put back in cqp list
+ */
+void irdma_put_cqp_request(struct irdma_cqp *cqp,
+ struct irdma_cqp_request *cqp_request)
+{
+ if (refcount_dec_and_test(&cqp_request->refcnt))
+ irdma_free_cqp_request(cqp, cqp_request);
+}
+
+/**
+ * irdma_free_pending_cqp_request -free pending cqp request objs
+ * @cqp: cqp ptr
+ * @cqp_request: to be put back in cqp list
+ */
+static void
+irdma_free_pending_cqp_request(struct irdma_cqp *cqp,
+ struct irdma_cqp_request *cqp_request)
+{
+ if (cqp_request->waiting) {
+ cqp_request->compl_info.error = true;
+ cqp_request->request_done = true;
+ wake_up(&cqp_request->waitq);
+ }
+ wait_event_timeout(cqp->remove_wq,
+ refcount_read(&cqp_request->refcnt) == 1, 1000);
+ irdma_put_cqp_request(cqp, cqp_request);
+}
+
+/**
+ * irdma_cleanup_pending_cqp_op - clean-up cqp with no
+ * completions
+ * @rf: RDMA PCI function
+ */
+void irdma_cleanup_pending_cqp_op(struct irdma_pci_f *rf)
+{
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ struct irdma_cqp *cqp = &rf->cqp;
+ struct irdma_cqp_request *cqp_request = NULL;
+ struct cqp_cmds_info *pcmdinfo = NULL;
+ u32 i, pending_work, wqe_idx;
+
+ pending_work = IRDMA_RING_USED_QUANTA(cqp->sc_cqp.sq_ring);
+ wqe_idx = IRDMA_RING_CURRENT_TAIL(cqp->sc_cqp.sq_ring);
+ for (i = 0; i < pending_work; i++) {
+ cqp_request = (struct irdma_cqp_request *)(unsigned long)
+ cqp->scratch_array[wqe_idx];
+ if (cqp_request)
+ irdma_free_pending_cqp_request(cqp, cqp_request);
+ wqe_idx = (wqe_idx + 1) % IRDMA_RING_SIZE(cqp->sc_cqp.sq_ring);
+ }
+
+ while (!list_empty(&dev->cqp_cmd_head)) {
+ pcmdinfo = irdma_remove_cqp_head(dev);
+ cqp_request =
+ container_of(pcmdinfo, struct irdma_cqp_request, info);
+ if (cqp_request)
+ irdma_free_pending_cqp_request(cqp, cqp_request);
+ }
+}
+
+/**
+ * irdma_wait_event - wait for completion
+ * @rf: RDMA PCI function
+ * @cqp_request: cqp request to wait
+ */
+static enum irdma_status_code irdma_wait_event(struct irdma_pci_f *rf,
+ struct irdma_cqp_request *cqp_request)
+{
+ struct irdma_cqp_timeout cqp_timeout = {};
+ bool cqp_error = false;
+ enum irdma_status_code err_code = 0;
+
+ cqp_timeout.compl_cqp_cmds = rf->sc_dev.cqp_cmd_stats[IRDMA_OP_CMPL_CMDS];
+ do {
+ irdma_cqp_ce_handler(rf, &rf->ccq.sc_cq);
+ if (wait_event_timeout(cqp_request->waitq,
+ cqp_request->request_done,
+ msecs_to_jiffies(CQP_COMPL_WAIT_TIME_MS)))
+ break;
+
+ irdma_check_cqp_progress(&cqp_timeout, &rf->sc_dev);
+
+ if (cqp_timeout.count < CQP_TIMEOUT_THRESHOLD)
+ continue;
+
+ if (!rf->reset) {
+ rf->reset = true;
+ rf->gen_ops.request_reset(rf);
+ }
+ return IRDMA_ERR_TIMEOUT;
+ } while (1);
+
+ cqp_error = cqp_request->compl_info.error;
+ if (cqp_error) {
+ err_code = IRDMA_ERR_CQP_COMPL_ERROR;
+ if (cqp_request->compl_info.maj_err_code == 0xFFFF &&
+ cqp_request->compl_info.min_err_code == 0x8029) {
+ if (!rf->reset) {
+ rf->reset = true;
+ rf->gen_ops.request_reset(rf);
+ }
+ }
+ }
+
+ return err_code;
+}
+
+static const char *const irdma_cqp_cmd_names[IRDMA_MAX_CQP_OPS] = {
+ [IRDMA_OP_CEQ_DESTROY] = "Destroy CEQ Cmd",
+ [IRDMA_OP_AEQ_DESTROY] = "Destroy AEQ Cmd",
+ [IRDMA_OP_DELETE_ARP_CACHE_ENTRY] = "Delete ARP Cache Cmd",
+ [IRDMA_OP_MANAGE_APBVT_ENTRY] = "Manage APBV Table Entry Cmd",
+ [IRDMA_OP_CEQ_CREATE] = "CEQ Create Cmd",
+ [IRDMA_OP_AEQ_CREATE] = "AEQ Destroy Cmd",
+ [IRDMA_OP_MANAGE_QHASH_TABLE_ENTRY] = "Manage Quad Hash Table Entry Cmd",
+ [IRDMA_OP_QP_MODIFY] = "Modify QP Cmd",
+ [IRDMA_OP_QP_UPLOAD_CONTEXT] = "Upload Context Cmd",
+ [IRDMA_OP_CQ_CREATE] = "Create CQ Cmd",
+ [IRDMA_OP_CQ_DESTROY] = "Destroy CQ Cmd",
+ [IRDMA_OP_QP_CREATE] = "Create QP Cmd",
+ [IRDMA_OP_QP_DESTROY] = "Destroy QP Cmd",
+ [IRDMA_OP_ALLOC_STAG] = "Allocate STag Cmd",
+ [IRDMA_OP_MR_REG_NON_SHARED] = "Register Non-Shared MR Cmd",
+ [IRDMA_OP_DEALLOC_STAG] = "Deallocate STag Cmd",
+ [IRDMA_OP_MW_ALLOC] = "Allocate Memory Window Cmd",
+ [IRDMA_OP_QP_FLUSH_WQES] = "Flush QP Cmd",
+ [IRDMA_OP_ADD_ARP_CACHE_ENTRY] = "Add ARP Cache Cmd",
+ [IRDMA_OP_MANAGE_PUSH_PAGE] = "Manage Push Page Cmd",
+ [IRDMA_OP_UPDATE_PE_SDS] = "Update PE SDs Cmd",
+ [IRDMA_OP_MANAGE_HMC_PM_FUNC_TABLE] = "Manage HMC PM Function Table Cmd",
+ [IRDMA_OP_SUSPEND] = "Suspend QP Cmd",
+ [IRDMA_OP_RESUME] = "Resume QP Cmd",
+ [IRDMA_OP_MANAGE_VF_PBLE_BP] = "Manage VF PBLE Backing Pages Cmd",
+ [IRDMA_OP_QUERY_FPM_VAL] = "Query FPM Values Cmd",
+ [IRDMA_OP_COMMIT_FPM_VAL] = "Commit FPM Values Cmd",
+ [IRDMA_OP_AH_CREATE] = "Create Address Handle Cmd",
+ [IRDMA_OP_AH_MODIFY] = "Modify Address Handle Cmd",
+ [IRDMA_OP_AH_DESTROY] = "Destroy Address Handle Cmd",
+ [IRDMA_OP_MC_CREATE] = "Create Multicast Group Cmd",
+ [IRDMA_OP_MC_DESTROY] = "Destroy Multicast Group Cmd",
+ [IRDMA_OP_MC_MODIFY] = "Modify Multicast Group Cmd",
+ [IRDMA_OP_STATS_ALLOCATE] = "Add Statistics Instance Cmd",
+ [IRDMA_OP_STATS_FREE] = "Free Statistics Instance Cmd",
+ [IRDMA_OP_STATS_GATHER] = "Gather Statistics Cmd",
+ [IRDMA_OP_WS_ADD_NODE] = "Add Work Scheduler Node Cmd",
+ [IRDMA_OP_WS_MODIFY_NODE] = "Modify Work Scheduler Node Cmd",
+ [IRDMA_OP_WS_DELETE_NODE] = "Delete Work Scheduler Node Cmd",
+ [IRDMA_OP_SET_UP_MAP] = "Set UP-UP Mapping Cmd",
+ [IRDMA_OP_GEN_AE] = "Generate AE Cmd",
+ [IRDMA_OP_QUERY_RDMA_FEATURES] = "RDMA Get Features Cmd",
+ [IRDMA_OP_ALLOC_LOCAL_MAC_ENTRY] = "Allocate Local MAC Entry Cmd",
+ [IRDMA_OP_ADD_LOCAL_MAC_ENTRY] = "Add Local MAC Entry Cmd",
+ [IRDMA_OP_DELETE_LOCAL_MAC_ENTRY] = "Delete Local MAC Entry Cmd",
+ [IRDMA_OP_CQ_MODIFY] = "CQ Modify Cmd",
+};
+
+static const struct irdma_cqp_err_info irdma_noncrit_err_list[] = {
+ {0xffff, 0x8006, "Flush No Wqe Pending"},
+ {0xffff, 0x8007, "Modify QP Bad Close"},
+ {0xffff, 0x8009, "LLP Closed"},
+ {0xffff, 0x800a, "Reset Not Sent"}
+};
+
+/**
+ * irdma_cqp_crit_err - check if CQP error is critical
+ * @dev: pointer to dev structure
+ * @cqp_cmd: code for last CQP operation
+ * @maj_err_code: major error code
+ * @min_err_code: minot error code
+ */
+bool irdma_cqp_crit_err(struct irdma_sc_dev *dev, u8 cqp_cmd,
+ u16 maj_err_code, u16 min_err_code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(irdma_noncrit_err_list); ++i) {
+ if (maj_err_code == irdma_noncrit_err_list[i].maj &&
+ min_err_code == irdma_noncrit_err_list[i].min) {
+ ibdev_dbg(to_ibdev(dev),
+ "CQP: [%s Error][%s] maj=0x%x min=0x%x\n",
+ irdma_noncrit_err_list[i].desc,
+ irdma_cqp_cmd_names[cqp_cmd], maj_err_code,
+ min_err_code);
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * irdma_handle_cqp_op - process cqp command
+ * @rf: RDMA PCI function
+ * @cqp_request: cqp request to process
+ */
+enum irdma_status_code irdma_handle_cqp_op(struct irdma_pci_f *rf,
+ struct irdma_cqp_request *cqp_request)
+{
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ struct cqp_cmds_info *info = &cqp_request->info;
+ enum irdma_status_code status;
+ bool put_cqp_request = true;
+
+ if (rf->reset)
+ return IRDMA_ERR_NOT_READY;
+
+ irdma_get_cqp_request(cqp_request);
+ status = irdma_process_cqp_cmd(dev, info);
+ if (status)
+ goto err;
+
+ if (cqp_request->waiting) {
+ put_cqp_request = false;
+ status = irdma_wait_event(rf, cqp_request);
+ if (status)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ if (irdma_cqp_crit_err(dev, info->cqp_cmd,
+ cqp_request->compl_info.maj_err_code,
+ cqp_request->compl_info.min_err_code))
+ ibdev_err(&rf->iwdev->ibdev,
+ "[%s Error][op_code=%d] status=%d waiting=%d completion_err=%d maj=0x%x min=0x%x\n",
+ irdma_cqp_cmd_names[info->cqp_cmd], info->cqp_cmd, status, cqp_request->waiting,
+ cqp_request->compl_info.error, cqp_request->compl_info.maj_err_code,
+ cqp_request->compl_info.min_err_code);
+
+ if (put_cqp_request)
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+
+ return status;
+}
+
+void irdma_qp_add_ref(struct ib_qp *ibqp)
+{
+ struct irdma_qp *iwqp = (struct irdma_qp *)ibqp;
+
+ refcount_inc(&iwqp->refcnt);
+}
+
+void irdma_qp_rem_ref(struct ib_qp *ibqp)
+{
+ struct irdma_qp *iwqp = to_iwqp(ibqp);
+ struct irdma_device *iwdev = iwqp->iwdev;
+ u32 qp_num;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iwdev->rf->qptable_lock, flags);
+ if (!refcount_dec_and_test(&iwqp->refcnt)) {
+ spin_unlock_irqrestore(&iwdev->rf->qptable_lock, flags);
+ return;
+ }
+
+ qp_num = iwqp->ibqp.qp_num;
+ iwdev->rf->qp_table[qp_num] = NULL;
+ spin_unlock_irqrestore(&iwdev->rf->qptable_lock, flags);
+ complete(&iwqp->free_qp);
+}
+
+struct ib_device *to_ibdev(struct irdma_sc_dev *dev)
+{
+ return &(container_of(dev, struct irdma_pci_f, sc_dev))->iwdev->ibdev;
+}
+
+/**
+ * irdma_get_qp - get qp address
+ * @device: iwarp device
+ * @qpn: qp number
+ */
+struct ib_qp *irdma_get_qp(struct ib_device *device, int qpn)
+{
+ struct irdma_device *iwdev = to_iwdev(device);
+
+ if (qpn < IW_FIRST_QPN || qpn >= iwdev->rf->max_qp)
+ return NULL;
+
+ return &iwdev->rf->qp_table[qpn]->ibqp;
+}
+
+/**
+ * irdma_get_hw_addr - return hw addr
+ * @par: points to shared dev
+ */
+u8 __iomem *irdma_get_hw_addr(void *par)
+{
+ struct irdma_sc_dev *dev = par;
+
+ return dev->hw->hw_addr;
+}
+
+/**
+ * irdma_remove_cqp_head - return head entry and remove
+ * @dev: device
+ */
+void *irdma_remove_cqp_head(struct irdma_sc_dev *dev)
+{
+ struct list_head *entry;
+ struct list_head *list = &dev->cqp_cmd_head;
+
+ if (list_empty(list))
+ return NULL;
+
+ entry = list->next;
+ list_del(entry);
+
+ return entry;
+}
+
+/**
+ * irdma_cqp_sds_cmd - create cqp command for sd
+ * @dev: hardware control device structure
+ * @sdinfo: information for sd cqp
+ *
+ */
+enum irdma_status_code irdma_cqp_sds_cmd(struct irdma_sc_dev *dev,
+ struct irdma_update_sds_info *sdinfo)
+{
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ memcpy(&cqp_info->in.u.update_pe_sds.info, sdinfo,
+ sizeof(cqp_info->in.u.update_pe_sds.info));
+ cqp_info->cqp_cmd = IRDMA_OP_UPDATE_PE_SDS;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.update_pe_sds.dev = dev;
+ cqp_info->in.u.update_pe_sds.scratch = (uintptr_t)cqp_request;
+
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_cqp_qp_suspend_resume - cqp command for suspend/resume
+ * @qp: hardware control qp
+ * @op: suspend or resume
+ */
+enum irdma_status_code irdma_cqp_qp_suspend_resume(struct irdma_sc_qp *qp,
+ u8 op)
+{
+ struct irdma_sc_dev *dev = qp->dev;
+ struct irdma_cqp_request *cqp_request;
+ struct irdma_sc_cqp *cqp = dev->cqp;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, false);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ cqp_info->cqp_cmd = op;
+ cqp_info->in.u.suspend_resume.cqp = cqp;
+ cqp_info->in.u.suspend_resume.qp = qp;
+ cqp_info->in.u.suspend_resume.scratch = (uintptr_t)cqp_request;
+
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_term_modify_qp - modify qp for term message
+ * @qp: hardware control qp
+ * @next_state: qp's next state
+ * @term: terminate code
+ * @term_len: length
+ */
+void irdma_term_modify_qp(struct irdma_sc_qp *qp, u8 next_state, u8 term,
+ u8 term_len)
+{
+ struct irdma_qp *iwqp;
+
+ iwqp = qp->qp_uk.back_qp;
+ irdma_next_iw_state(iwqp, next_state, 0, term, term_len);
+};
+
+/**
+ * irdma_terminate_done - after terminate is completed
+ * @qp: hardware control qp
+ * @timeout_occurred: indicates if terminate timer expired
+ */
+void irdma_terminate_done(struct irdma_sc_qp *qp, int timeout_occurred)
+{
+ struct irdma_qp *iwqp;
+ u8 hte = 0;
+ bool first_time;
+ unsigned long flags;
+
+ iwqp = qp->qp_uk.back_qp;
+ spin_lock_irqsave(&iwqp->lock, flags);
+ if (iwqp->hte_added) {
+ iwqp->hte_added = 0;
+ hte = 1;
+ }
+ first_time = !(qp->term_flags & IRDMA_TERM_DONE);
+ qp->term_flags |= IRDMA_TERM_DONE;
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ if (first_time) {
+ if (!timeout_occurred)
+ irdma_terminate_del_timer(qp);
+
+ irdma_next_iw_state(iwqp, IRDMA_QP_STATE_ERROR, hte, 0, 0);
+ irdma_cm_disconn(iwqp);
+ }
+}
+
+static void irdma_terminate_timeout(struct timer_list *t)
+{
+ struct irdma_qp *iwqp = from_timer(iwqp, t, terminate_timer);
+ struct irdma_sc_qp *qp = &iwqp->sc_qp;
+
+ irdma_terminate_done(qp, 1);
+ irdma_qp_rem_ref(&iwqp->ibqp);
+}
+
+/**
+ * irdma_terminate_start_timer - start terminate timeout
+ * @qp: hardware control qp
+ */
+void irdma_terminate_start_timer(struct irdma_sc_qp *qp)
+{
+ struct irdma_qp *iwqp;
+
+ iwqp = qp->qp_uk.back_qp;
+ irdma_qp_add_ref(&iwqp->ibqp);
+ timer_setup(&iwqp->terminate_timer, irdma_terminate_timeout, 0);
+ iwqp->terminate_timer.expires = jiffies + HZ;
+
+ add_timer(&iwqp->terminate_timer);
+}
+
+/**
+ * irdma_terminate_del_timer - delete terminate timeout
+ * @qp: hardware control qp
+ */
+void irdma_terminate_del_timer(struct irdma_sc_qp *qp)
+{
+ struct irdma_qp *iwqp;
+ int ret;
+
+ iwqp = qp->qp_uk.back_qp;
+ ret = del_timer(&iwqp->terminate_timer);
+ if (ret)
+ irdma_qp_rem_ref(&iwqp->ibqp);
+}
+
+/**
+ * irdma_cqp_query_fpm_val_cmd - send cqp command for fpm
+ * @dev: function device struct
+ * @val_mem: buffer for fpm
+ * @hmc_fn_id: function id for fpm
+ */
+enum irdma_status_code
+irdma_cqp_query_fpm_val_cmd(struct irdma_sc_dev *dev,
+ struct irdma_dma_mem *val_mem, u8 hmc_fn_id)
+{
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ cqp_request->param = NULL;
+ cqp_info->in.u.query_fpm_val.cqp = dev->cqp;
+ cqp_info->in.u.query_fpm_val.fpm_val_pa = val_mem->pa;
+ cqp_info->in.u.query_fpm_val.fpm_val_va = val_mem->va;
+ cqp_info->in.u.query_fpm_val.hmc_fn_id = hmc_fn_id;
+ cqp_info->cqp_cmd = IRDMA_OP_QUERY_FPM_VAL;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.query_fpm_val.scratch = (uintptr_t)cqp_request;
+
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_cqp_commit_fpm_val_cmd - commit fpm values in hw
+ * @dev: hardware control device structure
+ * @val_mem: buffer with fpm values
+ * @hmc_fn_id: function id for fpm
+ */
+enum irdma_status_code
+irdma_cqp_commit_fpm_val_cmd(struct irdma_sc_dev *dev,
+ struct irdma_dma_mem *val_mem, u8 hmc_fn_id)
+{
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ cqp_request->param = NULL;
+ cqp_info->in.u.commit_fpm_val.cqp = dev->cqp;
+ cqp_info->in.u.commit_fpm_val.fpm_val_pa = val_mem->pa;
+ cqp_info->in.u.commit_fpm_val.fpm_val_va = val_mem->va;
+ cqp_info->in.u.commit_fpm_val.hmc_fn_id = hmc_fn_id;
+ cqp_info->cqp_cmd = IRDMA_OP_COMMIT_FPM_VAL;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.commit_fpm_val.scratch = (uintptr_t)cqp_request;
+
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_cqp_cq_create_cmd - create a cq for the cqp
+ * @dev: device pointer
+ * @cq: pointer to created cq
+ */
+enum irdma_status_code irdma_cqp_cq_create_cmd(struct irdma_sc_dev *dev,
+ struct irdma_sc_cq *cq)
+{
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+ struct irdma_cqp *iwcqp = &rf->cqp;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, true);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ cqp_info->cqp_cmd = IRDMA_OP_CQ_CREATE;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.cq_create.cq = cq;
+ cqp_info->in.u.cq_create.scratch = (uintptr_t)cqp_request;
+
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(iwcqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_cqp_qp_create_cmd - create a qp for the cqp
+ * @dev: device pointer
+ * @qp: pointer to created qp
+ */
+enum irdma_status_code irdma_cqp_qp_create_cmd(struct irdma_sc_dev *dev,
+ struct irdma_sc_qp *qp)
+{
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+ struct irdma_cqp *iwcqp = &rf->cqp;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_create_qp_info *qp_info;
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, true);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ qp_info = &cqp_request->info.in.u.qp_create.info;
+ memset(qp_info, 0, sizeof(*qp_info));
+ qp_info->cq_num_valid = true;
+ qp_info->next_iwarp_state = IRDMA_QP_STATE_RTS;
+ cqp_info->cqp_cmd = IRDMA_OP_QP_CREATE;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.qp_create.qp = qp;
+ cqp_info->in.u.qp_create.scratch = (uintptr_t)cqp_request;
+
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(iwcqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_dealloc_push_page - free a push page for qp
+ * @rf: RDMA PCI function
+ * @qp: hardware control qp
+ */
+static void irdma_dealloc_push_page(struct irdma_pci_f *rf,
+ struct irdma_sc_qp *qp)
+{
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ enum irdma_status_code status;
+
+ if (qp->push_idx == IRDMA_INVALID_PUSH_PAGE_INDEX)
+ return;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, false);
+ if (!cqp_request)
+ return;
+
+ cqp_info = &cqp_request->info;
+ cqp_info->cqp_cmd = IRDMA_OP_MANAGE_PUSH_PAGE;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.manage_push_page.info.push_idx = qp->push_idx;
+ cqp_info->in.u.manage_push_page.info.qs_handle = qp->qs_handle;
+ cqp_info->in.u.manage_push_page.info.free_page = 1;
+ cqp_info->in.u.manage_push_page.info.push_page_type = 0;
+ cqp_info->in.u.manage_push_page.cqp = &rf->cqp.sc_cqp;
+ cqp_info->in.u.manage_push_page.scratch = (uintptr_t)cqp_request;
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ if (!status)
+ qp->push_idx = IRDMA_INVALID_PUSH_PAGE_INDEX;
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+}
+
+/**
+ * irdma_free_qp_rsrc - free up memory resources for qp
+ * @iwqp: qp ptr (user or kernel)
+ */
+void irdma_free_qp_rsrc(struct irdma_qp *iwqp)
+{
+ struct irdma_device *iwdev = iwqp->iwdev;
+ struct irdma_pci_f *rf = iwdev->rf;
+ u32 qp_num = iwqp->ibqp.qp_num;
+
+ irdma_ieq_cleanup_qp(iwdev->vsi.ieq, &iwqp->sc_qp);
+ irdma_dealloc_push_page(rf, &iwqp->sc_qp);
+ if (iwqp->sc_qp.vsi) {
+ irdma_qp_rem_qos(&iwqp->sc_qp);
+ iwqp->sc_qp.dev->ws_remove(iwqp->sc_qp.vsi,
+ iwqp->sc_qp.user_pri);
+ }
+
+ if (qp_num > 2)
+ irdma_free_rsrc(rf, rf->allocated_qps, qp_num);
+ dma_free_coherent(rf->sc_dev.hw->device, iwqp->q2_ctx_mem.size,
+ iwqp->q2_ctx_mem.va, iwqp->q2_ctx_mem.pa);
+ iwqp->q2_ctx_mem.va = NULL;
+ dma_free_coherent(rf->sc_dev.hw->device, iwqp->kqp.dma_mem.size,
+ iwqp->kqp.dma_mem.va, iwqp->kqp.dma_mem.pa);
+ iwqp->kqp.dma_mem.va = NULL;
+ kfree(iwqp->kqp.sq_wrid_mem);
+ iwqp->kqp.sq_wrid_mem = NULL;
+ kfree(iwqp->kqp.rq_wrid_mem);
+ iwqp->kqp.rq_wrid_mem = NULL;
+ kfree(iwqp);
+}
+
+/**
+ * irdma_cq_wq_destroy - send cq destroy cqp
+ * @rf: RDMA PCI function
+ * @cq: hardware control cq
+ */
+void irdma_cq_wq_destroy(struct irdma_pci_f *rf, struct irdma_sc_cq *cq)
+{
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
+ if (!cqp_request)
+ return;
+
+ cqp_info = &cqp_request->info;
+ cqp_info->cqp_cmd = IRDMA_OP_CQ_DESTROY;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.cq_destroy.cq = cq;
+ cqp_info->in.u.cq_destroy.scratch = (uintptr_t)cqp_request;
+
+ irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+}
+
+/**
+ * irdma_hw_modify_qp_callback - handle state for modifyQPs that don't wait
+ * @cqp_request: modify QP completion
+ */
+static void irdma_hw_modify_qp_callback(struct irdma_cqp_request *cqp_request)
+{
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_qp *iwqp;
+
+ cqp_info = &cqp_request->info;
+ iwqp = cqp_info->in.u.qp_modify.qp->qp_uk.back_qp;
+ atomic_dec(&iwqp->hw_mod_qp_pend);
+ wake_up(&iwqp->mod_qp_waitq);
+}
+
+/**
+ * irdma_hw_modify_qp - setup cqp for modify qp
+ * @iwdev: RDMA device
+ * @iwqp: qp ptr (user or kernel)
+ * @info: info for modify qp
+ * @wait: flag to wait or not for modify qp completion
+ */
+enum irdma_status_code irdma_hw_modify_qp(struct irdma_device *iwdev,
+ struct irdma_qp *iwqp,
+ struct irdma_modify_qp_info *info,
+ bool wait)
+{
+ enum irdma_status_code status;
+ struct irdma_pci_f *rf = iwdev->rf;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_modify_qp_info *m_info;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, wait);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ if (!wait) {
+ cqp_request->callback_fcn = irdma_hw_modify_qp_callback;
+ atomic_inc(&iwqp->hw_mod_qp_pend);
+ }
+ cqp_info = &cqp_request->info;
+ m_info = &cqp_info->in.u.qp_modify.info;
+ memcpy(m_info, info, sizeof(*m_info));
+ cqp_info->cqp_cmd = IRDMA_OP_QP_MODIFY;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.qp_modify.qp = &iwqp->sc_qp;
+ cqp_info->in.u.qp_modify.scratch = (uintptr_t)cqp_request;
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+ if (status) {
+ if (rdma_protocol_roce(&iwdev->ibdev, 1))
+ return status;
+
+ switch (m_info->next_iwarp_state) {
+ struct irdma_gen_ae_info ae_info;
+
+ case IRDMA_QP_STATE_RTS:
+ case IRDMA_QP_STATE_IDLE:
+ case IRDMA_QP_STATE_TERMINATE:
+ case IRDMA_QP_STATE_CLOSING:
+ if (info->curr_iwarp_state == IRDMA_QP_STATE_IDLE)
+ irdma_send_reset(iwqp->cm_node);
+ else
+ iwqp->sc_qp.term_flags = IRDMA_TERM_DONE;
+ if (!wait) {
+ ae_info.ae_code = IRDMA_AE_BAD_CLOSE;
+ ae_info.ae_src = 0;
+ irdma_gen_ae(rf, &iwqp->sc_qp, &ae_info, false);
+ } else {
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp,
+ wait);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ m_info = &cqp_info->in.u.qp_modify.info;
+ memcpy(m_info, info, sizeof(*m_info));
+ cqp_info->cqp_cmd = IRDMA_OP_QP_MODIFY;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.qp_modify.qp = &iwqp->sc_qp;
+ cqp_info->in.u.qp_modify.scratch = (uintptr_t)cqp_request;
+ m_info->next_iwarp_state = IRDMA_QP_STATE_ERROR;
+ m_info->reset_tcp_conn = true;
+ irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+ }
+ break;
+ case IRDMA_QP_STATE_ERROR:
+ default:
+ break;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * irdma_cqp_cq_destroy_cmd - destroy the cqp cq
+ * @dev: device pointer
+ * @cq: pointer to cq
+ */
+void irdma_cqp_cq_destroy_cmd(struct irdma_sc_dev *dev, struct irdma_sc_cq *cq)
+{
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+
+ irdma_cq_wq_destroy(rf, cq);
+}
+
+/**
+ * irdma_cqp_qp_destroy_cmd - destroy the cqp
+ * @dev: device pointer
+ * @qp: pointer to qp
+ */
+enum irdma_status_code irdma_cqp_qp_destroy_cmd(struct irdma_sc_dev *dev, struct irdma_sc_qp *qp)
+{
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+ struct irdma_cqp *iwcqp = &rf->cqp;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, true);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ memset(cqp_info, 0, sizeof(*cqp_info));
+ cqp_info->cqp_cmd = IRDMA_OP_QP_DESTROY;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.qp_destroy.qp = qp;
+ cqp_info->in.u.qp_destroy.scratch = (uintptr_t)cqp_request;
+ cqp_info->in.u.qp_destroy.remove_hash_idx = true;
+
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_ieq_mpa_crc_ae - generate AE for crc error
+ * @dev: hardware control device structure
+ * @qp: hardware control qp
+ */
+void irdma_ieq_mpa_crc_ae(struct irdma_sc_dev *dev, struct irdma_sc_qp *qp)
+{
+ struct irdma_gen_ae_info info = {};
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+
+ ibdev_dbg(&rf->iwdev->ibdev, "AEQ: Generate MPA CRC AE\n");
+ info.ae_code = IRDMA_AE_LLP_RECEIVED_MPA_CRC_ERROR;
+ info.ae_src = IRDMA_AE_SOURCE_RQ;
+ irdma_gen_ae(rf, qp, &info, false);
+}
+
+/**
+ * irdma_init_hash_desc - initialize hash for crc calculation
+ * @desc: cryption type
+ */
+enum irdma_status_code irdma_init_hash_desc(struct shash_desc **desc)
+{
+ struct crypto_shash *tfm;
+ struct shash_desc *tdesc;
+
+ tfm = crypto_alloc_shash("crc32c", 0, 0);
+ if (IS_ERR(tfm))
+ return IRDMA_ERR_MPA_CRC;
+
+ tdesc = kzalloc(sizeof(*tdesc) + crypto_shash_descsize(tfm),
+ GFP_KERNEL);
+ if (!tdesc) {
+ crypto_free_shash(tfm);
+ return IRDMA_ERR_MPA_CRC;
+ }
+
+ tdesc->tfm = tfm;
+ *desc = tdesc;
+
+ return 0;
+}
+
+/**
+ * irdma_free_hash_desc - free hash desc
+ * @desc: to be freed
+ */
+void irdma_free_hash_desc(struct shash_desc *desc)
+{
+ if (desc) {
+ crypto_free_shash(desc->tfm);
+ kfree(desc);
+ }
+}
+
+/**
+ * irdma_ieq_check_mpacrc - check if mpa crc is OK
+ * @desc: desc for hash
+ * @addr: address of buffer for crc
+ * @len: length of buffer
+ * @val: value to be compared
+ */
+enum irdma_status_code irdma_ieq_check_mpacrc(struct shash_desc *desc,
+ void *addr, u32 len, u32 val)
+{
+ u32 crc = 0;
+ int ret;
+ enum irdma_status_code ret_code = 0;
+
+ crypto_shash_init(desc);
+ ret = crypto_shash_update(desc, addr, len);
+ if (!ret)
+ crypto_shash_final(desc, (u8 *)&crc);
+ if (crc != val)
+ ret_code = IRDMA_ERR_MPA_CRC;
+
+ return ret_code;
+}
+
+/**
+ * irdma_ieq_get_qp - get qp based on quad in puda buffer
+ * @dev: hardware control device structure
+ * @buf: receive puda buffer on exception q
+ */
+struct irdma_sc_qp *irdma_ieq_get_qp(struct irdma_sc_dev *dev,
+ struct irdma_puda_buf *buf)
+{
+ struct irdma_qp *iwqp;
+ struct irdma_cm_node *cm_node;
+ struct irdma_device *iwdev = buf->vsi->back_vsi;
+ u32 loc_addr[4] = {};
+ u32 rem_addr[4] = {};
+ u16 loc_port, rem_port;
+ struct ipv6hdr *ip6h;
+ struct iphdr *iph = (struct iphdr *)buf->iph;
+ struct tcphdr *tcph = (struct tcphdr *)buf->tcph;
+
+ if (iph->version == 4) {
+ loc_addr[0] = ntohl(iph->daddr);
+ rem_addr[0] = ntohl(iph->saddr);
+ } else {
+ ip6h = (struct ipv6hdr *)buf->iph;
+ irdma_copy_ip_ntohl(loc_addr, ip6h->daddr.in6_u.u6_addr32);
+ irdma_copy_ip_ntohl(rem_addr, ip6h->saddr.in6_u.u6_addr32);
+ }
+ loc_port = ntohs(tcph->dest);
+ rem_port = ntohs(tcph->source);
+ cm_node = irdma_find_node(&iwdev->cm_core, rem_port, rem_addr, loc_port,
+ loc_addr, buf->vlan_valid ? buf->vlan_id : 0xFFFF);
+ if (!cm_node)
+ return NULL;
+
+ iwqp = cm_node->iwqp;
+ irdma_rem_ref_cm_node(cm_node);
+
+ return &iwqp->sc_qp;
+}
+
+/**
+ * irdma_send_ieq_ack - ACKs for duplicate or OOO partials FPDUs
+ * @qp: qp ptr
+ */
+void irdma_send_ieq_ack(struct irdma_sc_qp *qp)
+{
+ struct irdma_cm_node *cm_node = ((struct irdma_qp *)qp->qp_uk.back_qp)->cm_node;
+ struct irdma_puda_buf *buf = qp->pfpdu.lastrcv_buf;
+ struct tcphdr *tcph = (struct tcphdr *)buf->tcph;
+
+ cm_node->tcp_cntxt.rcv_nxt = qp->pfpdu.nextseqnum;
+ cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+
+ irdma_send_ack(cm_node);
+}
+
+/**
+ * irdma_puda_ieq_get_ah_info - get AH info from IEQ buffer
+ * @qp: qp pointer
+ * @ah_info: AH info pointer
+ */
+void irdma_puda_ieq_get_ah_info(struct irdma_sc_qp *qp,
+ struct irdma_ah_info *ah_info)
+{
+ struct irdma_puda_buf *buf = qp->pfpdu.ah_buf;
+ struct iphdr *iph;
+ struct ipv6hdr *ip6h;
+
+ memset(ah_info, 0, sizeof(*ah_info));
+ ah_info->do_lpbk = true;
+ ah_info->vlan_tag = buf->vlan_id;
+ ah_info->insert_vlan_tag = buf->vlan_valid;
+ ah_info->ipv4_valid = buf->ipv4;
+ ah_info->vsi = qp->vsi;
+
+ if (buf->smac_valid)
+ ether_addr_copy(ah_info->mac_addr, buf->smac);
+
+ if (buf->ipv4) {
+ ah_info->ipv4_valid = true;
+ iph = (struct iphdr *)buf->iph;
+ ah_info->hop_ttl = iph->ttl;
+ ah_info->tc_tos = iph->tos;
+ ah_info->dest_ip_addr[0] = ntohl(iph->daddr);
+ ah_info->src_ip_addr[0] = ntohl(iph->saddr);
+ } else {
+ ip6h = (struct ipv6hdr *)buf->iph;
+ ah_info->hop_ttl = ip6h->hop_limit;
+ ah_info->tc_tos = ip6h->priority;
+ irdma_copy_ip_ntohl(ah_info->dest_ip_addr,
+ ip6h->daddr.in6_u.u6_addr32);
+ irdma_copy_ip_ntohl(ah_info->src_ip_addr,
+ ip6h->saddr.in6_u.u6_addr32);
+ }
+
+ ah_info->dst_arpindex = irdma_arp_table(dev_to_rf(qp->dev),
+ ah_info->dest_ip_addr,
+ ah_info->ipv4_valid,
+ NULL, IRDMA_ARP_RESOLVE);
+}
+
+/**
+ * irdma_gen1_ieq_update_tcpip_info - update tcpip in the buffer
+ * @buf: puda to update
+ * @len: length of buffer
+ * @seqnum: seq number for tcp
+ */
+static void irdma_gen1_ieq_update_tcpip_info(struct irdma_puda_buf *buf,
+ u16 len, u32 seqnum)
+{
+ struct tcphdr *tcph;
+ struct iphdr *iph;
+ u16 iphlen;
+ u16 pktsize;
+ u8 *addr = buf->mem.va;
+
+ iphlen = (buf->ipv4) ? 20 : 40;
+ iph = (struct iphdr *)(addr + buf->maclen);
+ tcph = (struct tcphdr *)(addr + buf->maclen + iphlen);
+ pktsize = len + buf->tcphlen + iphlen;
+ iph->tot_len = htons(pktsize);
+ tcph->seq = htonl(seqnum);
+}
+
+/**
+ * irdma_ieq_update_tcpip_info - update tcpip in the buffer
+ * @buf: puda to update
+ * @len: length of buffer
+ * @seqnum: seq number for tcp
+ */
+void irdma_ieq_update_tcpip_info(struct irdma_puda_buf *buf, u16 len,
+ u32 seqnum)
+{
+ struct tcphdr *tcph;
+ u8 *addr;
+
+ if (buf->vsi->dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1)
+ return irdma_gen1_ieq_update_tcpip_info(buf, len, seqnum);
+
+ addr = buf->mem.va;
+ tcph = (struct tcphdr *)addr;
+ tcph->seq = htonl(seqnum);
+}
+
+/**
+ * irdma_gen1_puda_get_tcpip_info - get tcpip info from puda
+ * buffer
+ * @info: to get information
+ * @buf: puda buffer
+ */
+static enum irdma_status_code
+irdma_gen1_puda_get_tcpip_info(struct irdma_puda_cmpl_info *info,
+ struct irdma_puda_buf *buf)
+{
+ struct iphdr *iph;
+ struct ipv6hdr *ip6h;
+ struct tcphdr *tcph;
+ u16 iphlen;
+ u16 pkt_len;
+ u8 *mem = buf->mem.va;
+ struct ethhdr *ethh = buf->mem.va;
+
+ if (ethh->h_proto == htons(0x8100)) {
+ info->vlan_valid = true;
+ buf->vlan_id = ntohs(((struct vlan_ethhdr *)ethh)->h_vlan_TCI) &
+ VLAN_VID_MASK;
+ }
+
+ buf->maclen = (info->vlan_valid) ? 18 : 14;
+ iphlen = (info->l3proto) ? 40 : 20;
+ buf->ipv4 = (info->l3proto) ? false : true;
+ buf->iph = mem + buf->maclen;
+ iph = (struct iphdr *)buf->iph;
+ buf->tcph = buf->iph + iphlen;
+ tcph = (struct tcphdr *)buf->tcph;
+
+ if (buf->ipv4) {
+ pkt_len = ntohs(iph->tot_len);
+ } else {
+ ip6h = (struct ipv6hdr *)buf->iph;
+ pkt_len = ntohs(ip6h->payload_len) + iphlen;
+ }
+
+ buf->totallen = pkt_len + buf->maclen;
+
+ if (info->payload_len < buf->totallen) {
+ ibdev_dbg(to_ibdev(buf->vsi->dev),
+ "ERR: payload_len = 0x%x totallen expected0x%x\n",
+ info->payload_len, buf->totallen);
+ return IRDMA_ERR_INVALID_SIZE;
+ }
+
+ buf->tcphlen = tcph->doff << 2;
+ buf->datalen = pkt_len - iphlen - buf->tcphlen;
+ buf->data = buf->datalen ? buf->tcph + buf->tcphlen : NULL;
+ buf->hdrlen = buf->maclen + iphlen + buf->tcphlen;
+ buf->seqnum = ntohl(tcph->seq);
+
+ return 0;
+}
+
+/**
+ * irdma_puda_get_tcpip_info - get tcpip info from puda buffer
+ * @info: to get information
+ * @buf: puda buffer
+ */
+enum irdma_status_code
+irdma_puda_get_tcpip_info(struct irdma_puda_cmpl_info *info,
+ struct irdma_puda_buf *buf)
+{
+ struct tcphdr *tcph;
+ u32 pkt_len;
+ u8 *mem;
+
+ if (buf->vsi->dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1)
+ return irdma_gen1_puda_get_tcpip_info(info, buf);
+
+ mem = buf->mem.va;
+ buf->vlan_valid = info->vlan_valid;
+ if (info->vlan_valid)
+ buf->vlan_id = info->vlan;
+
+ buf->ipv4 = info->ipv4;
+ if (buf->ipv4)
+ buf->iph = mem + IRDMA_IPV4_PAD;
+ else
+ buf->iph = mem;
+
+ buf->tcph = mem + IRDMA_TCP_OFFSET;
+ tcph = (struct tcphdr *)buf->tcph;
+ pkt_len = info->payload_len;
+ buf->totallen = pkt_len;
+ buf->tcphlen = tcph->doff << 2;
+ buf->datalen = pkt_len - IRDMA_TCP_OFFSET - buf->tcphlen;
+ buf->data = buf->datalen ? buf->tcph + buf->tcphlen : NULL;
+ buf->hdrlen = IRDMA_TCP_OFFSET + buf->tcphlen;
+ buf->seqnum = ntohl(tcph->seq);
+
+ if (info->smac_valid) {
+ ether_addr_copy(buf->smac, info->smac);
+ buf->smac_valid = true;
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_hw_stats_timeout - Stats timer-handler which updates all HW stats
+ * @t: timer_list pointer
+ */
+static void irdma_hw_stats_timeout(struct timer_list *t)
+{
+ struct irdma_vsi_pestat *pf_devstat =
+ from_timer(pf_devstat, t, stats_timer);
+ struct irdma_sc_vsi *sc_vsi = pf_devstat->vsi;
+
+ if (sc_vsi->dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1)
+ irdma_cqp_gather_stats_gen1(sc_vsi->dev, sc_vsi->pestat);
+ else
+ irdma_cqp_gather_stats_cmd(sc_vsi->dev, sc_vsi->pestat, false);
+
+ mod_timer(&pf_devstat->stats_timer,
+ jiffies + msecs_to_jiffies(STATS_TIMER_DELAY));
+}
+
+/**
+ * irdma_hw_stats_start_timer - Start periodic stats timer
+ * @vsi: vsi structure pointer
+ */
+void irdma_hw_stats_start_timer(struct irdma_sc_vsi *vsi)
+{
+ struct irdma_vsi_pestat *devstat = vsi->pestat;
+
+ timer_setup(&devstat->stats_timer, irdma_hw_stats_timeout, 0);
+ mod_timer(&devstat->stats_timer,
+ jiffies + msecs_to_jiffies(STATS_TIMER_DELAY));
+}
+
+/**
+ * irdma_hw_stats_stop_timer - Delete periodic stats timer
+ * @vsi: pointer to vsi structure
+ */
+void irdma_hw_stats_stop_timer(struct irdma_sc_vsi *vsi)
+{
+ struct irdma_vsi_pestat *devstat = vsi->pestat;
+
+ del_timer_sync(&devstat->stats_timer);
+}
+
+/**
+ * irdma_process_stats - Checking for wrap and update stats
+ * @pestat: stats structure pointer
+ */
+static inline void irdma_process_stats(struct irdma_vsi_pestat *pestat)
+{
+ sc_vsi_update_stats(pestat->vsi);
+}
+
+/**
+ * irdma_cqp_gather_stats_gen1 - Gather stats
+ * @dev: pointer to device structure
+ * @pestat: statistics structure
+ */
+void irdma_cqp_gather_stats_gen1(struct irdma_sc_dev *dev,
+ struct irdma_vsi_pestat *pestat)
+{
+ struct irdma_gather_stats *gather_stats =
+ pestat->gather_info.gather_stats_va;
+ u32 stats_inst_offset_32;
+ u32 stats_inst_offset_64;
+
+ stats_inst_offset_32 = (pestat->gather_info.use_stats_inst) ?
+ pestat->gather_info.stats_inst_index :
+ pestat->hw->hmc.hmc_fn_id;
+ stats_inst_offset_32 *= 4;
+ stats_inst_offset_64 = stats_inst_offset_32 * 2;
+
+ gather_stats->rxvlanerr =
+ rd32(dev->hw,
+ dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_RXVLANERR]
+ + stats_inst_offset_32);
+ gather_stats->ip4rxdiscard =
+ rd32(dev->hw,
+ dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_IP4RXDISCARD]
+ + stats_inst_offset_32);
+ gather_stats->ip4rxtrunc =
+ rd32(dev->hw,
+ dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_IP4RXTRUNC]
+ + stats_inst_offset_32);
+ gather_stats->ip4txnoroute =
+ rd32(dev->hw,
+ dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_IP4TXNOROUTE]
+ + stats_inst_offset_32);
+ gather_stats->ip6rxdiscard =
+ rd32(dev->hw,
+ dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_IP6RXDISCARD]
+ + stats_inst_offset_32);
+ gather_stats->ip6rxtrunc =
+ rd32(dev->hw,
+ dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_IP6RXTRUNC]
+ + stats_inst_offset_32);
+ gather_stats->ip6txnoroute =
+ rd32(dev->hw,
+ dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_IP6TXNOROUTE]
+ + stats_inst_offset_32);
+ gather_stats->tcprtxseg =
+ rd32(dev->hw,
+ dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_TCPRTXSEG]
+ + stats_inst_offset_32);
+ gather_stats->tcprxopterr =
+ rd32(dev->hw,
+ dev->hw_stats_regs_32[IRDMA_HW_STAT_INDEX_TCPRXOPTERR]
+ + stats_inst_offset_32);
+
+ gather_stats->ip4rxocts =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4RXOCTS]
+ + stats_inst_offset_64);
+ gather_stats->ip4rxpkts =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4RXPKTS]
+ + stats_inst_offset_64);
+ gather_stats->ip4txfrag =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4RXFRAGS]
+ + stats_inst_offset_64);
+ gather_stats->ip4rxmcpkts =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4RXMCPKTS]
+ + stats_inst_offset_64);
+ gather_stats->ip4txocts =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4TXOCTS]
+ + stats_inst_offset_64);
+ gather_stats->ip4txpkts =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4TXPKTS]
+ + stats_inst_offset_64);
+ gather_stats->ip4txfrag =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4TXFRAGS]
+ + stats_inst_offset_64);
+ gather_stats->ip4txmcpkts =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP4TXMCPKTS]
+ + stats_inst_offset_64);
+ gather_stats->ip6rxocts =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6RXOCTS]
+ + stats_inst_offset_64);
+ gather_stats->ip6rxpkts =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6RXPKTS]
+ + stats_inst_offset_64);
+ gather_stats->ip6txfrags =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6RXFRAGS]
+ + stats_inst_offset_64);
+ gather_stats->ip6rxmcpkts =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6RXMCPKTS]
+ + stats_inst_offset_64);
+ gather_stats->ip6txocts =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6TXOCTS]
+ + stats_inst_offset_64);
+ gather_stats->ip6txpkts =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6TXPKTS]
+ + stats_inst_offset_64);
+ gather_stats->ip6txfrags =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6TXFRAGS]
+ + stats_inst_offset_64);
+ gather_stats->ip6txmcpkts =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_IP6TXMCPKTS]
+ + stats_inst_offset_64);
+ gather_stats->tcprxsegs =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_TCPRXSEGS]
+ + stats_inst_offset_64);
+ gather_stats->tcptxsegs =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_TCPTXSEG]
+ + stats_inst_offset_64);
+ gather_stats->rdmarxrds =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMARXRDS]
+ + stats_inst_offset_64);
+ gather_stats->rdmarxsnds =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMARXSNDS]
+ + stats_inst_offset_64);
+ gather_stats->rdmarxwrs =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMARXWRS]
+ + stats_inst_offset_64);
+ gather_stats->rdmatxrds =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMATXRDS]
+ + stats_inst_offset_64);
+ gather_stats->rdmatxsnds =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMATXSNDS]
+ + stats_inst_offset_64);
+ gather_stats->rdmatxwrs =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMATXWRS]
+ + stats_inst_offset_64);
+ gather_stats->rdmavbn =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMAVBND]
+ + stats_inst_offset_64);
+ gather_stats->rdmavinv =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_RDMAVINV]
+ + stats_inst_offset_64);
+ gather_stats->udprxpkts =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_UDPRXPKTS]
+ + stats_inst_offset_64);
+ gather_stats->udptxpkts =
+ rd64(dev->hw,
+ dev->hw_stats_regs_64[IRDMA_HW_STAT_INDEX_UDPTXPKTS]
+ + stats_inst_offset_64);
+
+ irdma_process_stats(pestat);
+}
+
+/**
+ * irdma_process_cqp_stats - Checking for wrap and update stats
+ * @cqp_request: cqp_request structure pointer
+ */
+static void irdma_process_cqp_stats(struct irdma_cqp_request *cqp_request)
+{
+ struct irdma_vsi_pestat *pestat = cqp_request->param;
+
+ irdma_process_stats(pestat);
+}
+
+/**
+ * irdma_cqp_gather_stats_cmd - Gather stats
+ * @dev: pointer to device structure
+ * @pestat: pointer to stats info
+ * @wait: flag to wait or not wait for stats
+ */
+enum irdma_status_code
+irdma_cqp_gather_stats_cmd(struct irdma_sc_dev *dev,
+ struct irdma_vsi_pestat *pestat, bool wait)
+
+{
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+ struct irdma_cqp *iwcqp = &rf->cqp;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, wait);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ memset(cqp_info, 0, sizeof(*cqp_info));
+ cqp_info->cqp_cmd = IRDMA_OP_STATS_GATHER;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.stats_gather.info = pestat->gather_info;
+ cqp_info->in.u.stats_gather.scratch = (uintptr_t)cqp_request;
+ cqp_info->in.u.stats_gather.cqp = &rf->cqp.sc_cqp;
+ cqp_request->param = pestat;
+ if (!wait)
+ cqp_request->callback_fcn = irdma_process_cqp_stats;
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ if (wait)
+ irdma_process_stats(pestat);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_cqp_stats_inst_cmd - Allocate/free stats instance
+ * @vsi: pointer to vsi structure
+ * @cmd: command to allocate or free
+ * @stats_info: pointer to allocate stats info
+ */
+enum irdma_status_code
+irdma_cqp_stats_inst_cmd(struct irdma_sc_vsi *vsi, u8 cmd,
+ struct irdma_stats_inst_info *stats_info)
+{
+ struct irdma_pci_f *rf = dev_to_rf(vsi->dev);
+ struct irdma_cqp *iwcqp = &rf->cqp;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ enum irdma_status_code status;
+ bool wait = false;
+
+ if (cmd == IRDMA_OP_STATS_ALLOCATE)
+ wait = true;
+ cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, wait);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ memset(cqp_info, 0, sizeof(*cqp_info));
+ cqp_info->cqp_cmd = cmd;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.stats_manage.info = *stats_info;
+ cqp_info->in.u.stats_manage.scratch = (uintptr_t)cqp_request;
+ cqp_info->in.u.stats_manage.cqp = &rf->cqp.sc_cqp;
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ if (wait)
+ stats_info->stats_idx = cqp_request->compl_info.op_ret_val;
+ irdma_put_cqp_request(iwcqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_cqp_ceq_cmd - Create/Destroy CEQ's after CEQ 0
+ * @dev: pointer to device info
+ * @sc_ceq: pointer to ceq structure
+ * @op: Create or Destroy
+ */
+enum irdma_status_code irdma_cqp_ceq_cmd(struct irdma_sc_dev *dev,
+ struct irdma_sc_ceq *sc_ceq, u8 op)
+{
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ cqp_info->post_sq = 1;
+ cqp_info->cqp_cmd = op;
+ cqp_info->in.u.ceq_create.ceq = sc_ceq;
+ cqp_info->in.u.ceq_create.scratch = (uintptr_t)cqp_request;
+
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_cqp_aeq_cmd - Create/Destroy AEQ
+ * @dev: pointer to device info
+ * @sc_aeq: pointer to aeq structure
+ * @op: Create or Destroy
+ */
+enum irdma_status_code irdma_cqp_aeq_cmd(struct irdma_sc_dev *dev,
+ struct irdma_sc_aeq *sc_aeq, u8 op)
+{
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ cqp_info->post_sq = 1;
+ cqp_info->cqp_cmd = op;
+ cqp_info->in.u.aeq_create.aeq = sc_aeq;
+ cqp_info->in.u.aeq_create.scratch = (uintptr_t)cqp_request;
+
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_cqp_ws_node_cmd - Add/modify/delete ws node
+ * @dev: pointer to device structure
+ * @cmd: Add, modify or delete
+ * @node_info: pointer to ws node info
+ */
+enum irdma_status_code
+irdma_cqp_ws_node_cmd(struct irdma_sc_dev *dev, u8 cmd,
+ struct irdma_ws_node_info *node_info)
+{
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+ struct irdma_cqp *iwcqp = &rf->cqp;
+ struct irdma_sc_cqp *cqp = &iwcqp->sc_cqp;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ enum irdma_status_code status;
+ bool poll;
+
+ if (!rf->sc_dev.ceq_valid)
+ poll = true;
+ else
+ poll = false;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, !poll);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ memset(cqp_info, 0, sizeof(*cqp_info));
+ cqp_info->cqp_cmd = cmd;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.ws_node.info = *node_info;
+ cqp_info->in.u.ws_node.cqp = cqp;
+ cqp_info->in.u.ws_node.scratch = (uintptr_t)cqp_request;
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ if (status)
+ goto exit;
+
+ if (poll) {
+ struct irdma_ccq_cqe_info compl_info;
+
+ status = irdma_sc_poll_for_cqp_op_done(cqp, IRDMA_CQP_OP_WORK_SCHED_NODE,
+ &compl_info);
+ node_info->qs_handle = compl_info.op_ret_val;
+ ibdev_dbg(&rf->iwdev->ibdev, "DCB: opcode=%d, compl_info.retval=%d\n",
+ compl_info.op_code, compl_info.op_ret_val);
+ } else {
+ node_info->qs_handle = cqp_request->compl_info.op_ret_val;
+ }
+
+exit:
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_cqp_up_map_cmd - Set the up-up mapping
+ * @dev: pointer to device structure
+ * @cmd: map command
+ * @map_info: pointer to up map info
+ */
+enum irdma_status_code irdma_cqp_up_map_cmd(struct irdma_sc_dev *dev, u8 cmd,
+ struct irdma_up_info *map_info)
+{
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+ struct irdma_cqp *iwcqp = &rf->cqp;
+ struct irdma_sc_cqp *cqp = &iwcqp->sc_cqp;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(iwcqp, false);
+ if (!cqp_request)
+ return IRDMA_ERR_NO_MEMORY;
+
+ cqp_info = &cqp_request->info;
+ memset(cqp_info, 0, sizeof(*cqp_info));
+ cqp_info->cqp_cmd = cmd;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.up_map.info = *map_info;
+ cqp_info->in.u.up_map.cqp = cqp;
+ cqp_info->in.u.up_map.scratch = (uintptr_t)cqp_request;
+
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+
+ return status;
+}
+
+/**
+ * irdma_ah_cqp_op - perform an AH cqp operation
+ * @rf: RDMA PCI function
+ * @sc_ah: address handle
+ * @cmd: AH operation
+ * @wait: wait if true
+ * @callback_fcn: Callback function on CQP op completion
+ * @cb_param: parameter for callback function
+ *
+ * returns errno
+ */
+int irdma_ah_cqp_op(struct irdma_pci_f *rf, struct irdma_sc_ah *sc_ah, u8 cmd,
+ bool wait,
+ void (*callback_fcn)(struct irdma_cqp_request *),
+ void *cb_param)
+{
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ enum irdma_status_code status;
+
+ if (cmd != IRDMA_OP_AH_CREATE && cmd != IRDMA_OP_AH_DESTROY)
+ return -EINVAL;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, wait);
+ if (!cqp_request)
+ return -ENOMEM;
+
+ cqp_info = &cqp_request->info;
+ cqp_info->cqp_cmd = cmd;
+ cqp_info->post_sq = 1;
+ if (cmd == IRDMA_OP_AH_CREATE) {
+ cqp_info->in.u.ah_create.info = sc_ah->ah_info;
+ cqp_info->in.u.ah_create.scratch = (uintptr_t)cqp_request;
+ cqp_info->in.u.ah_create.cqp = &rf->cqp.sc_cqp;
+ } else if (cmd == IRDMA_OP_AH_DESTROY) {
+ cqp_info->in.u.ah_destroy.info = sc_ah->ah_info;
+ cqp_info->in.u.ah_destroy.scratch = (uintptr_t)cqp_request;
+ cqp_info->in.u.ah_destroy.cqp = &rf->cqp.sc_cqp;
+ }
+
+ if (!wait) {
+ cqp_request->callback_fcn = callback_fcn;
+ cqp_request->param = cb_param;
+ }
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+
+ if (status)
+ return -ENOMEM;
+
+ if (wait)
+ sc_ah->ah_info.ah_valid = (cmd == IRDMA_OP_AH_CREATE);
+
+ return 0;
+}
+
+/**
+ * irdma_ieq_ah_cb - callback after creation of AH for IEQ
+ * @cqp_request: pointer to cqp_request of create AH
+ */
+static void irdma_ieq_ah_cb(struct irdma_cqp_request *cqp_request)
+{
+ struct irdma_sc_qp *qp = cqp_request->param;
+ struct irdma_sc_ah *sc_ah = qp->pfpdu.ah;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qp->pfpdu.lock, flags);
+ if (!cqp_request->compl_info.op_ret_val) {
+ sc_ah->ah_info.ah_valid = true;
+ irdma_ieq_process_fpdus(qp, qp->vsi->ieq);
+ } else {
+ sc_ah->ah_info.ah_valid = false;
+ irdma_ieq_cleanup_qp(qp->vsi->ieq, qp);
+ }
+ spin_unlock_irqrestore(&qp->pfpdu.lock, flags);
+}
+
+/**
+ * irdma_ilq_ah_cb - callback after creation of AH for ILQ
+ * @cqp_request: pointer to cqp_request of create AH
+ */
+static void irdma_ilq_ah_cb(struct irdma_cqp_request *cqp_request)
+{
+ struct irdma_cm_node *cm_node = cqp_request->param;
+ struct irdma_sc_ah *sc_ah = cm_node->ah;
+
+ sc_ah->ah_info.ah_valid = !cqp_request->compl_info.op_ret_val;
+ irdma_add_conn_est_qh(cm_node);
+}
+
+/**
+ * irdma_puda_create_ah - create AH for ILQ/IEQ qp's
+ * @dev: device pointer
+ * @ah_info: Address handle info
+ * @wait: When true will wait for operation to complete
+ * @type: ILQ/IEQ
+ * @cb_param: Callback param when not waiting
+ * @ah_ret: Returned pointer to address handle if created
+ *
+ */
+enum irdma_status_code irdma_puda_create_ah(struct irdma_sc_dev *dev,
+ struct irdma_ah_info *ah_info,
+ bool wait, enum puda_rsrc_type type,
+ void *cb_param,
+ struct irdma_sc_ah **ah_ret)
+{
+ struct irdma_sc_ah *ah;
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+ int err;
+
+ ah = kzalloc(sizeof(*ah), GFP_ATOMIC);
+ *ah_ret = ah;
+ if (!ah)
+ return IRDMA_ERR_NO_MEMORY;
+
+ err = irdma_alloc_rsrc(rf, rf->allocated_ahs, rf->max_ah,
+ &ah_info->ah_idx, &rf->next_ah);
+ if (err)
+ goto err_free;
+
+ ah->dev = dev;
+ ah->ah_info = *ah_info;
+
+ if (type == IRDMA_PUDA_RSRC_TYPE_ILQ)
+ err = irdma_ah_cqp_op(rf, ah, IRDMA_OP_AH_CREATE, wait,
+ irdma_ilq_ah_cb, cb_param);
+ else
+ err = irdma_ah_cqp_op(rf, ah, IRDMA_OP_AH_CREATE, wait,
+ irdma_ieq_ah_cb, cb_param);
+
+ if (err)
+ goto error;
+ return 0;
+
+error:
+ irdma_free_rsrc(rf, rf->allocated_ahs, ah->ah_info.ah_idx);
+err_free:
+ kfree(ah);
+ *ah_ret = NULL;
+ return IRDMA_ERR_NO_MEMORY;
+}
+
+/**
+ * irdma_puda_free_ah - free a puda address handle
+ * @dev: device pointer
+ * @ah: The address handle to free
+ */
+void irdma_puda_free_ah(struct irdma_sc_dev *dev, struct irdma_sc_ah *ah)
+{
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+
+ if (!ah)
+ return;
+
+ if (ah->ah_info.ah_valid) {
+ irdma_ah_cqp_op(rf, ah, IRDMA_OP_AH_DESTROY, false, NULL, NULL);
+ irdma_free_rsrc(rf, rf->allocated_ahs, ah->ah_info.ah_idx);
+ }
+
+ kfree(ah);
+}
+
+/**
+ * irdma_gsi_ud_qp_ah_cb - callback after creation of AH for GSI/ID QP
+ * @cqp_request: pointer to cqp_request of create AH
+ */
+void irdma_gsi_ud_qp_ah_cb(struct irdma_cqp_request *cqp_request)
+{
+ struct irdma_sc_ah *sc_ah = cqp_request->param;
+
+ if (!cqp_request->compl_info.op_ret_val)
+ sc_ah->ah_info.ah_valid = true;
+ else
+ sc_ah->ah_info.ah_valid = false;
+}
+
+/**
+ * irdma_prm_add_pble_mem - add moemory to pble resources
+ * @pprm: pble resource manager
+ * @pchunk: chunk of memory to add
+ */
+enum irdma_status_code irdma_prm_add_pble_mem(struct irdma_pble_prm *pprm,
+ struct irdma_chunk *pchunk)
+{
+ u64 sizeofbitmap;
+
+ if (pchunk->size & 0xfff)
+ return IRDMA_ERR_PARAM;
+
+ sizeofbitmap = (u64)pchunk->size >> pprm->pble_shift;
+
+ pchunk->bitmapmem.size = sizeofbitmap >> 3;
+ pchunk->bitmapmem.va = kzalloc(pchunk->bitmapmem.size, GFP_KERNEL);
+
+ if (!pchunk->bitmapmem.va)
+ return IRDMA_ERR_NO_MEMORY;
+
+ pchunk->bitmapbuf = pchunk->bitmapmem.va;
+ bitmap_zero(pchunk->bitmapbuf, sizeofbitmap);
+
+ pchunk->sizeofbitmap = sizeofbitmap;
+ /* each pble is 8 bytes hence shift by 3 */
+ pprm->total_pble_alloc += pchunk->size >> 3;
+ pprm->free_pble_cnt += pchunk->size >> 3;
+
+ return 0;
+}
+
+/**
+ * irdma_prm_get_pbles - get pble's from prm
+ * @pprm: pble resource manager
+ * @chunkinfo: nformation about chunk where pble's were acquired
+ * @mem_size: size of pble memory needed
+ * @vaddr: returns virtual address of pble memory
+ * @fpm_addr: returns fpm address of pble memory
+ */
+enum irdma_status_code
+irdma_prm_get_pbles(struct irdma_pble_prm *pprm,
+ struct irdma_pble_chunkinfo *chunkinfo, u64 mem_size,
+ u64 **vaddr, u64 *fpm_addr)
+{
+ u64 bits_needed;
+ u64 bit_idx = PBLE_INVALID_IDX;
+ struct irdma_chunk *pchunk = NULL;
+ struct list_head *chunk_entry = pprm->clist.next;
+ u32 offset;
+ unsigned long flags;
+ *vaddr = NULL;
+ *fpm_addr = 0;
+
+ bits_needed = DIV_ROUND_UP_ULL(mem_size, BIT_ULL(pprm->pble_shift));
+
+ spin_lock_irqsave(&pprm->prm_lock, flags);
+ while (chunk_entry != &pprm->clist) {
+ pchunk = (struct irdma_chunk *)chunk_entry;
+ bit_idx = bitmap_find_next_zero_area(pchunk->bitmapbuf,
+ pchunk->sizeofbitmap, 0,
+ bits_needed, 0);
+ if (bit_idx < pchunk->sizeofbitmap)
+ break;
+
+ /* list.next used macro */
+ chunk_entry = pchunk->list.next;
+ }
+
+ if (!pchunk || bit_idx >= pchunk->sizeofbitmap) {
+ spin_unlock_irqrestore(&pprm->prm_lock, flags);
+ return IRDMA_ERR_NO_MEMORY;
+ }
+
+ bitmap_set(pchunk->bitmapbuf, bit_idx, bits_needed);
+ offset = bit_idx << pprm->pble_shift;
+ *vaddr = pchunk->vaddr + offset;
+ *fpm_addr = pchunk->fpm_addr + offset;
+
+ chunkinfo->pchunk = pchunk;
+ chunkinfo->bit_idx = bit_idx;
+ chunkinfo->bits_used = bits_needed;
+ /* 3 is sizeof pble divide */
+ pprm->free_pble_cnt -= chunkinfo->bits_used << (pprm->pble_shift - 3);
+ spin_unlock_irqrestore(&pprm->prm_lock, flags);
+
+ return 0;
+}
+
+/**
+ * irdma_prm_return_pbles - return pbles back to prm
+ * @pprm: pble resource manager
+ * @chunkinfo: chunk where pble's were acquired and to be freed
+ */
+void irdma_prm_return_pbles(struct irdma_pble_prm *pprm,
+ struct irdma_pble_chunkinfo *chunkinfo)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pprm->prm_lock, flags);
+ pprm->free_pble_cnt += chunkinfo->bits_used << (pprm->pble_shift - 3);
+ bitmap_clear(chunkinfo->pchunk->bitmapbuf, chunkinfo->bit_idx,
+ chunkinfo->bits_used);
+ spin_unlock_irqrestore(&pprm->prm_lock, flags);
+}
+
+enum irdma_status_code irdma_map_vm_page_list(struct irdma_hw *hw, void *va,
+ dma_addr_t *pg_dma, u32 pg_cnt)
+{
+ struct page *vm_page;
+ int i;
+ u8 *addr;
+
+ addr = (u8 *)(uintptr_t)va;
+ for (i = 0; i < pg_cnt; i++) {
+ vm_page = vmalloc_to_page(addr);
+ if (!vm_page)
+ goto err;
+
+ pg_dma[i] = dma_map_page(hw->device, vm_page, 0, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(hw->device, pg_dma[i]))
+ goto err;
+
+ addr += PAGE_SIZE;
+ }
+
+ return 0;
+
+err:
+ irdma_unmap_vm_page_list(hw, pg_dma, i);
+ return IRDMA_ERR_NO_MEMORY;
+}
+
+void irdma_unmap_vm_page_list(struct irdma_hw *hw, dma_addr_t *pg_dma, u32 pg_cnt)
+{
+ int i;
+
+ for (i = 0; i < pg_cnt; i++)
+ dma_unmap_page(hw->device, pg_dma[i], PAGE_SIZE, DMA_BIDIRECTIONAL);
+}
+
+/**
+ * irdma_pble_free_paged_mem - free virtual paged memory
+ * @chunk: chunk to free with paged memory
+ */
+void irdma_pble_free_paged_mem(struct irdma_chunk *chunk)
+{
+ if (!chunk->pg_cnt)
+ goto done;
+
+ irdma_unmap_vm_page_list(chunk->dev->hw, chunk->dmainfo.dmaaddrs,
+ chunk->pg_cnt);
+
+done:
+ kfree(chunk->dmainfo.dmaaddrs);
+ chunk->dmainfo.dmaaddrs = NULL;
+ vfree(chunk->vaddr);
+ chunk->vaddr = NULL;
+ chunk->type = 0;
+}
+
+/**
+ * irdma_pble_get_paged_mem -allocate paged memory for pbles
+ * @chunk: chunk to add for paged memory
+ * @pg_cnt: number of pages needed
+ */
+enum irdma_status_code irdma_pble_get_paged_mem(struct irdma_chunk *chunk,
+ u32 pg_cnt)
+{
+ u32 size;
+ void *va;
+
+ chunk->dmainfo.dmaaddrs = kzalloc(pg_cnt << 3, GFP_KERNEL);
+ if (!chunk->dmainfo.dmaaddrs)
+ return IRDMA_ERR_NO_MEMORY;
+
+ size = PAGE_SIZE * pg_cnt;
+ va = vmalloc(size);
+ if (!va)
+ goto err;
+
+ if (irdma_map_vm_page_list(chunk->dev->hw, va, chunk->dmainfo.dmaaddrs,
+ pg_cnt)) {
+ vfree(va);
+ goto err;
+ }
+ chunk->vaddr = va;
+ chunk->size = size;
+ chunk->pg_cnt = pg_cnt;
+ chunk->type = PBLE_SD_PAGED;
+
+ return 0;
+err:
+ kfree(chunk->dmainfo.dmaaddrs);
+ chunk->dmainfo.dmaaddrs = NULL;
+
+ return IRDMA_ERR_NO_MEMORY;
+}
+
+/**
+ * irdma_alloc_ws_node_id - Allocate a tx scheduler node ID
+ * @dev: device pointer
+ */
+u16 irdma_alloc_ws_node_id(struct irdma_sc_dev *dev)
+{
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+ u32 next = 1;
+ u32 node_id;
+
+ if (irdma_alloc_rsrc(rf, rf->allocated_ws_nodes, rf->max_ws_node_id,
+ &node_id, &next))
+ return IRDMA_WS_NODE_INVALID;
+
+ return (u16)node_id;
+}
+
+/**
+ * irdma_free_ws_node_id - Free a tx scheduler node ID
+ * @dev: device pointer
+ * @node_id: Work scheduler node ID
+ */
+void irdma_free_ws_node_id(struct irdma_sc_dev *dev, u16 node_id)
+{
+ struct irdma_pci_f *rf = dev_to_rf(dev);
+
+ irdma_free_rsrc(rf, rf->allocated_ws_nodes, (u32)node_id);
+}
+
+/**
+ * irdma_modify_qp_to_err - Modify a QP to error
+ * @sc_qp: qp structure
+ */
+void irdma_modify_qp_to_err(struct irdma_sc_qp *sc_qp)
+{
+ struct irdma_qp *qp = sc_qp->qp_uk.back_qp;
+ struct ib_qp_attr attr;
+
+ if (qp->iwdev->reset)
+ return;
+ attr.qp_state = IB_QPS_ERR;
+
+ if (rdma_protocol_roce(qp->ibqp.device, 1))
+ irdma_modify_qp_roce(&qp->ibqp, &attr, IB_QP_STATE, NULL);
+ else
+ irdma_modify_qp(&qp->ibqp, &attr, IB_QP_STATE, NULL);
+}
+
+void irdma_ib_qp_event(struct irdma_qp *iwqp, enum irdma_qp_event_type event)
+{
+ struct ib_event ibevent;
+
+ if (!iwqp->ibqp.event_handler)
+ return;
+
+ switch (event) {
+ case IRDMA_QP_EVENT_CATASTROPHIC:
+ ibevent.event = IB_EVENT_QP_FATAL;
+ break;
+ case IRDMA_QP_EVENT_ACCESS_ERR:
+ ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+ break;
+ }
+ ibevent.device = iwqp->ibqp.device;
+ ibevent.element.qp = &iwqp->ibqp;
+ iwqp->ibqp.event_handler(&ibevent, iwqp->ibqp.qp_context);
+}
diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c
new file mode 100644
index 000000000000..9712f6902ba8
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/verbs.c
@@ -0,0 +1,4544 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#include "main.h"
+
+/**
+ * irdma_query_device - get device attributes
+ * @ibdev: device pointer from stack
+ * @props: returning device attributes
+ * @udata: user data
+ */
+static int irdma_query_device(struct ib_device *ibdev,
+ struct ib_device_attr *props,
+ struct ib_udata *udata)
+{
+ struct irdma_device *iwdev = to_iwdev(ibdev);
+ struct irdma_pci_f *rf = iwdev->rf;
+ struct pci_dev *pcidev = iwdev->rf->pcidev;
+ struct irdma_hw_attrs *hw_attrs = &rf->sc_dev.hw_attrs;
+
+ if (udata->inlen || udata->outlen)
+ return -EINVAL;
+
+ memset(props, 0, sizeof(*props));
+ ether_addr_copy((u8 *)&props->sys_image_guid, iwdev->netdev->dev_addr);
+ props->fw_ver = (u64)irdma_fw_major_ver(&rf->sc_dev) << 32 |
+ irdma_fw_minor_ver(&rf->sc_dev);
+ props->device_cap_flags = iwdev->device_cap_flags;
+ props->vendor_id = pcidev->vendor;
+ props->vendor_part_id = pcidev->device;
+
+ props->hw_ver = rf->pcidev->revision;
+ props->page_size_cap = SZ_4K | SZ_2M | SZ_1G;
+ props->max_mr_size = hw_attrs->max_mr_size;
+ props->max_qp = rf->max_qp - rf->used_qps;
+ props->max_qp_wr = hw_attrs->max_qp_wr;
+ props->max_send_sge = hw_attrs->uk_attrs.max_hw_wq_frags;
+ props->max_recv_sge = hw_attrs->uk_attrs.max_hw_wq_frags;
+ props->max_cq = rf->max_cq - rf->used_cqs;
+ props->max_cqe = rf->max_cqe;
+ props->max_mr = rf->max_mr - rf->used_mrs;
+ props->max_mw = props->max_mr;
+ props->max_pd = rf->max_pd - rf->used_pds;
+ props->max_sge_rd = hw_attrs->uk_attrs.max_hw_read_sges;
+ props->max_qp_rd_atom = hw_attrs->max_hw_ird;
+ props->max_qp_init_rd_atom = hw_attrs->max_hw_ord;
+ if (rdma_protocol_roce(ibdev, 1))
+ props->max_pkeys = IRDMA_PKEY_TBL_SZ;
+ props->max_ah = rf->max_ah;
+ props->max_mcast_grp = rf->max_mcg;
+ props->max_mcast_qp_attach = IRDMA_MAX_MGS_PER_CTX;
+ props->max_total_mcast_qp_attach = rf->max_qp * IRDMA_MAX_MGS_PER_CTX;
+ props->max_fast_reg_page_list_len = IRDMA_MAX_PAGES_PER_FMR;
+#define HCA_CLOCK_TIMESTAMP_MASK 0x1ffff
+ if (hw_attrs->uk_attrs.hw_rev >= IRDMA_GEN_2)
+ props->timestamp_mask = HCA_CLOCK_TIMESTAMP_MASK;
+
+ return 0;
+}
+
+/**
+ * irdma_get_eth_speed_and_width - Get IB port speed and width from netdev speed
+ * @link_speed: netdev phy link speed
+ * @active_speed: IB port speed
+ * @active_width: IB port width
+ */
+static void irdma_get_eth_speed_and_width(u32 link_speed, u16 *active_speed,
+ u8 *active_width)
+{
+ if (link_speed <= SPEED_1000) {
+ *active_width = IB_WIDTH_1X;
+ *active_speed = IB_SPEED_SDR;
+ } else if (link_speed <= SPEED_10000) {
+ *active_width = IB_WIDTH_1X;
+ *active_speed = IB_SPEED_FDR10;
+ } else if (link_speed <= SPEED_20000) {
+ *active_width = IB_WIDTH_4X;
+ *active_speed = IB_SPEED_DDR;
+ } else if (link_speed <= SPEED_25000) {
+ *active_width = IB_WIDTH_1X;
+ *active_speed = IB_SPEED_EDR;
+ } else if (link_speed <= SPEED_40000) {
+ *active_width = IB_WIDTH_4X;
+ *active_speed = IB_SPEED_FDR10;
+ } else {
+ *active_width = IB_WIDTH_4X;
+ *active_speed = IB_SPEED_EDR;
+ }
+}
+
+/**
+ * irdma_query_port - get port attributes
+ * @ibdev: device pointer from stack
+ * @port: port number for query
+ * @props: returning device attributes
+ */
+static int irdma_query_port(struct ib_device *ibdev, u32 port,
+ struct ib_port_attr *props)
+{
+ struct irdma_device *iwdev = to_iwdev(ibdev);
+ struct net_device *netdev = iwdev->netdev;
+
+ /* no need to zero out pros here. done by caller */
+
+ props->max_mtu = IB_MTU_4096;
+ props->active_mtu = ib_mtu_int_to_enum(netdev->mtu);
+ props->lid = 1;
+ props->lmc = 0;
+ props->sm_lid = 0;
+ props->sm_sl = 0;
+ if (netif_carrier_ok(netdev) && netif_running(netdev)) {
+ props->state = IB_PORT_ACTIVE;
+ props->phys_state = IB_PORT_PHYS_STATE_LINK_UP;
+ } else {
+ props->state = IB_PORT_DOWN;
+ props->phys_state = IB_PORT_PHYS_STATE_DISABLED;
+ }
+ irdma_get_eth_speed_and_width(SPEED_100000, &props->active_speed,
+ &props->active_width);
+
+ if (rdma_protocol_roce(ibdev, 1)) {
+ props->gid_tbl_len = 32;
+ props->ip_gids = true;
+ props->pkey_tbl_len = IRDMA_PKEY_TBL_SZ;
+ } else {
+ props->gid_tbl_len = 1;
+ }
+ props->qkey_viol_cntr = 0;
+ props->port_cap_flags |= IB_PORT_CM_SUP | IB_PORT_REINIT_SUP;
+ props->max_msg_sz = iwdev->rf->sc_dev.hw_attrs.max_hw_outbound_msg_size;
+
+ return 0;
+}
+
+/**
+ * irdma_disassociate_ucontext - Disassociate user context
+ * @context: ib user context
+ */
+static void irdma_disassociate_ucontext(struct ib_ucontext *context)
+{
+}
+
+static int irdma_mmap_legacy(struct irdma_ucontext *ucontext,
+ struct vm_area_struct *vma)
+{
+ u64 pfn;
+
+ if (vma->vm_pgoff || vma->vm_end - vma->vm_start != PAGE_SIZE)
+ return -EINVAL;
+
+ vma->vm_private_data = ucontext;
+ pfn = ((uintptr_t)ucontext->iwdev->rf->sc_dev.hw_regs[IRDMA_DB_ADDR_OFFSET] +
+ pci_resource_start(ucontext->iwdev->rf->pcidev, 0)) >> PAGE_SHIFT;
+
+ return rdma_user_mmap_io(&ucontext->ibucontext, vma, pfn, PAGE_SIZE,
+ pgprot_noncached(vma->vm_page_prot), NULL);
+}
+
+static void irdma_mmap_free(struct rdma_user_mmap_entry *rdma_entry)
+{
+ struct irdma_user_mmap_entry *entry = to_irdma_mmap_entry(rdma_entry);
+
+ kfree(entry);
+}
+
+static struct rdma_user_mmap_entry*
+irdma_user_mmap_entry_insert(struct irdma_ucontext *ucontext, u64 bar_offset,
+ enum irdma_mmap_flag mmap_flag, u64 *mmap_offset)
+{
+ struct irdma_user_mmap_entry *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ int ret;
+
+ if (!entry)
+ return NULL;
+
+ entry->bar_offset = bar_offset;
+ entry->mmap_flag = mmap_flag;
+
+ ret = rdma_user_mmap_entry_insert(&ucontext->ibucontext,
+ &entry->rdma_entry, PAGE_SIZE);
+ if (ret) {
+ kfree(entry);
+ return NULL;
+ }
+ *mmap_offset = rdma_user_mmap_get_offset(&entry->rdma_entry);
+
+ return &entry->rdma_entry;
+}
+
+/**
+ * irdma_mmap - user memory map
+ * @context: context created during alloc
+ * @vma: kernel info for user memory map
+ */
+static int irdma_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+ struct rdma_user_mmap_entry *rdma_entry;
+ struct irdma_user_mmap_entry *entry;
+ struct irdma_ucontext *ucontext;
+ u64 pfn;
+ int ret;
+
+ ucontext = to_ucontext(context);
+
+ /* Legacy support for libi40iw with hard-coded mmap key */
+ if (ucontext->legacy_mode)
+ return irdma_mmap_legacy(ucontext, vma);
+
+ rdma_entry = rdma_user_mmap_entry_get(&ucontext->ibucontext, vma);
+ if (!rdma_entry) {
+ ibdev_dbg(&ucontext->iwdev->ibdev,
+ "VERBS: pgoff[0x%lx] does not have valid entry\n",
+ vma->vm_pgoff);
+ return -EINVAL;
+ }
+
+ entry = to_irdma_mmap_entry(rdma_entry);
+ ibdev_dbg(&ucontext->iwdev->ibdev,
+ "VERBS: bar_offset [0x%llx] mmap_flag [%d]\n",
+ entry->bar_offset, entry->mmap_flag);
+
+ pfn = (entry->bar_offset +
+ pci_resource_start(ucontext->iwdev->rf->pcidev, 0)) >> PAGE_SHIFT;
+
+ switch (entry->mmap_flag) {
+ case IRDMA_MMAP_IO_NC:
+ ret = rdma_user_mmap_io(context, vma, pfn, PAGE_SIZE,
+ pgprot_noncached(vma->vm_page_prot),
+ rdma_entry);
+ break;
+ case IRDMA_MMAP_IO_WC:
+ ret = rdma_user_mmap_io(context, vma, pfn, PAGE_SIZE,
+ pgprot_writecombine(vma->vm_page_prot),
+ rdma_entry);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (ret)
+ ibdev_dbg(&ucontext->iwdev->ibdev,
+ "VERBS: bar_offset [0x%llx] mmap_flag[%d] err[%d]\n",
+ entry->bar_offset, entry->mmap_flag, ret);
+ rdma_user_mmap_entry_put(rdma_entry);
+
+ return ret;
+}
+
+/**
+ * irdma_alloc_push_page - allocate a push page for qp
+ * @iwqp: qp pointer
+ */
+static void irdma_alloc_push_page(struct irdma_qp *iwqp)
+{
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_device *iwdev = iwqp->iwdev;
+ struct irdma_sc_qp *qp = &iwqp->sc_qp;
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, true);
+ if (!cqp_request)
+ return;
+
+ cqp_info = &cqp_request->info;
+ cqp_info->cqp_cmd = IRDMA_OP_MANAGE_PUSH_PAGE;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.manage_push_page.info.push_idx = 0;
+ cqp_info->in.u.manage_push_page.info.qs_handle =
+ qp->vsi->qos[qp->user_pri].qs_handle;
+ cqp_info->in.u.manage_push_page.info.free_page = 0;
+ cqp_info->in.u.manage_push_page.info.push_page_type = 0;
+ cqp_info->in.u.manage_push_page.cqp = &iwdev->rf->cqp.sc_cqp;
+ cqp_info->in.u.manage_push_page.scratch = (uintptr_t)cqp_request;
+
+ status = irdma_handle_cqp_op(iwdev->rf, cqp_request);
+ if (!status && cqp_request->compl_info.op_ret_val <
+ iwdev->rf->sc_dev.hw_attrs.max_hw_device_pages) {
+ qp->push_idx = cqp_request->compl_info.op_ret_val;
+ qp->push_offset = 0;
+ }
+
+ irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
+}
+
+/**
+ * irdma_alloc_ucontext - Allocate the user context data structure
+ * @uctx: uverbs context pointer
+ * @udata: user data
+ *
+ * This keeps track of all objects associated with a particular
+ * user-mode client.
+ */
+static int irdma_alloc_ucontext(struct ib_ucontext *uctx,
+ struct ib_udata *udata)
+{
+ struct ib_device *ibdev = uctx->device;
+ struct irdma_device *iwdev = to_iwdev(ibdev);
+ struct irdma_alloc_ucontext_req req;
+ struct irdma_alloc_ucontext_resp uresp = {};
+ struct irdma_ucontext *ucontext = to_ucontext(uctx);
+ struct irdma_uk_attrs *uk_attrs;
+
+ if (ib_copy_from_udata(&req, udata, min(sizeof(req), udata->inlen)))
+ return -EINVAL;
+
+ if (req.userspace_ver < 4 || req.userspace_ver > IRDMA_ABI_VER)
+ goto ver_error;
+
+ ucontext->iwdev = iwdev;
+ ucontext->abi_ver = req.userspace_ver;
+
+ uk_attrs = &iwdev->rf->sc_dev.hw_attrs.uk_attrs;
+ /* GEN_1 legacy support with libi40iw */
+ if (udata->outlen < sizeof(uresp)) {
+ if (uk_attrs->hw_rev != IRDMA_GEN_1)
+ return -EOPNOTSUPP;
+
+ ucontext->legacy_mode = true;
+ uresp.max_qps = iwdev->rf->max_qp;
+ uresp.max_pds = iwdev->rf->sc_dev.hw_attrs.max_hw_pds;
+ uresp.wq_size = iwdev->rf->sc_dev.hw_attrs.max_qp_wr * 2;
+ uresp.kernel_ver = req.userspace_ver;
+ if (ib_copy_to_udata(udata, &uresp,
+ min(sizeof(uresp), udata->outlen)))
+ return -EFAULT;
+ } else {
+ u64 bar_off = (uintptr_t)iwdev->rf->sc_dev.hw_regs[IRDMA_DB_ADDR_OFFSET];
+
+ ucontext->db_mmap_entry =
+ irdma_user_mmap_entry_insert(ucontext, bar_off,
+ IRDMA_MMAP_IO_NC,
+ &uresp.db_mmap_key);
+ if (!ucontext->db_mmap_entry)
+ return -ENOMEM;
+
+ uresp.kernel_ver = IRDMA_ABI_VER;
+ uresp.feature_flags = uk_attrs->feature_flags;
+ uresp.max_hw_wq_frags = uk_attrs->max_hw_wq_frags;
+ uresp.max_hw_read_sges = uk_attrs->max_hw_read_sges;
+ uresp.max_hw_inline = uk_attrs->max_hw_inline;
+ uresp.max_hw_rq_quanta = uk_attrs->max_hw_rq_quanta;
+ uresp.max_hw_wq_quanta = uk_attrs->max_hw_wq_quanta;
+ uresp.max_hw_sq_chunk = uk_attrs->max_hw_sq_chunk;
+ uresp.max_hw_cq_size = uk_attrs->max_hw_cq_size;
+ uresp.min_hw_cq_size = uk_attrs->min_hw_cq_size;
+ uresp.hw_rev = uk_attrs->hw_rev;
+ if (ib_copy_to_udata(udata, &uresp,
+ min(sizeof(uresp), udata->outlen))) {
+ rdma_user_mmap_entry_remove(ucontext->db_mmap_entry);
+ return -EFAULT;
+ }
+ }
+
+ INIT_LIST_HEAD(&ucontext->cq_reg_mem_list);
+ spin_lock_init(&ucontext->cq_reg_mem_list_lock);
+ INIT_LIST_HEAD(&ucontext->qp_reg_mem_list);
+ spin_lock_init(&ucontext->qp_reg_mem_list_lock);
+
+ return 0;
+
+ver_error:
+ ibdev_err(&iwdev->ibdev,
+ "Invalid userspace driver version detected. Detected version %d, should be %d\n",
+ req.userspace_ver, IRDMA_ABI_VER);
+ return -EINVAL;
+}
+
+/**
+ * irdma_dealloc_ucontext - deallocate the user context data structure
+ * @context: user context created during alloc
+ */
+static void irdma_dealloc_ucontext(struct ib_ucontext *context)
+{
+ struct irdma_ucontext *ucontext = to_ucontext(context);
+
+ rdma_user_mmap_entry_remove(ucontext->db_mmap_entry);
+}
+
+/**
+ * irdma_alloc_pd - allocate protection domain
+ * @pd: PD pointer
+ * @udata: user data
+ */
+static int irdma_alloc_pd(struct ib_pd *pd, struct ib_udata *udata)
+{
+ struct irdma_pd *iwpd = to_iwpd(pd);
+ struct irdma_device *iwdev = to_iwdev(pd->device);
+ struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
+ struct irdma_pci_f *rf = iwdev->rf;
+ struct irdma_alloc_pd_resp uresp = {};
+ struct irdma_sc_pd *sc_pd;
+ u32 pd_id = 0;
+ int err;
+
+ err = irdma_alloc_rsrc(rf, rf->allocated_pds, rf->max_pd, &pd_id,
+ &rf->next_pd);
+ if (err)
+ return err;
+
+ sc_pd = &iwpd->sc_pd;
+ if (udata) {
+ struct irdma_ucontext *ucontext =
+ rdma_udata_to_drv_context(udata, struct irdma_ucontext,
+ ibucontext);
+ irdma_sc_pd_init(dev, sc_pd, pd_id, ucontext->abi_ver);
+ uresp.pd_id = pd_id;
+ if (ib_copy_to_udata(udata, &uresp,
+ min(sizeof(uresp), udata->outlen))) {
+ err = -EFAULT;
+ goto error;
+ }
+ } else {
+ irdma_sc_pd_init(dev, sc_pd, pd_id, IRDMA_ABI_VER);
+ }
+
+ return 0;
+error:
+ irdma_free_rsrc(rf, rf->allocated_pds, pd_id);
+
+ return err;
+}
+
+/**
+ * irdma_dealloc_pd - deallocate pd
+ * @ibpd: ptr of pd to be deallocated
+ * @udata: user data
+ */
+static int irdma_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
+{
+ struct irdma_pd *iwpd = to_iwpd(ibpd);
+ struct irdma_device *iwdev = to_iwdev(ibpd->device);
+
+ irdma_free_rsrc(iwdev->rf, iwdev->rf->allocated_pds, iwpd->sc_pd.pd_id);
+
+ return 0;
+}
+
+/**
+ * irdma_get_pbl - Retrieve pbl from a list given a virtual
+ * address
+ * @va: user virtual address
+ * @pbl_list: pbl list to search in (QP's or CQ's)
+ */
+static struct irdma_pbl *irdma_get_pbl(unsigned long va,
+ struct list_head *pbl_list)
+{
+ struct irdma_pbl *iwpbl;
+
+ list_for_each_entry (iwpbl, pbl_list, list) {
+ if (iwpbl->user_base == va) {
+ list_del(&iwpbl->list);
+ iwpbl->on_list = false;
+ return iwpbl;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * irdma_clean_cqes - clean cq entries for qp
+ * @iwqp: qp ptr (user or kernel)
+ * @iwcq: cq ptr
+ */
+static void irdma_clean_cqes(struct irdma_qp *iwqp, struct irdma_cq *iwcq)
+{
+ struct irdma_cq_uk *ukcq = &iwcq->sc_cq.cq_uk;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iwcq->lock, flags);
+ irdma_uk_clean_cq(&iwqp->sc_qp.qp_uk, ukcq);
+ spin_unlock_irqrestore(&iwcq->lock, flags);
+}
+
+static void irdma_remove_push_mmap_entries(struct irdma_qp *iwqp)
+{
+ if (iwqp->push_db_mmap_entry) {
+ rdma_user_mmap_entry_remove(iwqp->push_db_mmap_entry);
+ iwqp->push_db_mmap_entry = NULL;
+ }
+ if (iwqp->push_wqe_mmap_entry) {
+ rdma_user_mmap_entry_remove(iwqp->push_wqe_mmap_entry);
+ iwqp->push_wqe_mmap_entry = NULL;
+ }
+}
+
+static int irdma_setup_push_mmap_entries(struct irdma_ucontext *ucontext,
+ struct irdma_qp *iwqp,
+ u64 *push_wqe_mmap_key,
+ u64 *push_db_mmap_key)
+{
+ struct irdma_device *iwdev = ucontext->iwdev;
+ u64 rsvd, bar_off;
+
+ rsvd = IRDMA_PF_BAR_RSVD;
+ bar_off = (uintptr_t)iwdev->rf->sc_dev.hw_regs[IRDMA_DB_ADDR_OFFSET];
+ /* skip over db page */
+ bar_off += IRDMA_HW_PAGE_SIZE;
+ /* push wqe page */
+ bar_off += rsvd + iwqp->sc_qp.push_idx * IRDMA_HW_PAGE_SIZE;
+ iwqp->push_wqe_mmap_entry = irdma_user_mmap_entry_insert(ucontext,
+ bar_off, IRDMA_MMAP_IO_WC,
+ push_wqe_mmap_key);
+ if (!iwqp->push_wqe_mmap_entry)
+ return -ENOMEM;
+
+ /* push doorbell page */
+ bar_off += IRDMA_HW_PAGE_SIZE;
+ iwqp->push_db_mmap_entry = irdma_user_mmap_entry_insert(ucontext,
+ bar_off, IRDMA_MMAP_IO_NC,
+ push_db_mmap_key);
+ if (!iwqp->push_db_mmap_entry) {
+ rdma_user_mmap_entry_remove(iwqp->push_wqe_mmap_entry);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_destroy_qp - destroy qp
+ * @ibqp: qp's ib pointer also to get to device's qp address
+ * @udata: user data
+ */
+static int irdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
+{
+ struct irdma_qp *iwqp = to_iwqp(ibqp);
+ struct irdma_device *iwdev = iwqp->iwdev;
+
+ iwqp->sc_qp.qp_uk.destroy_pending = true;
+
+ if (iwqp->iwarp_state == IRDMA_QP_STATE_RTS)
+ irdma_modify_qp_to_err(&iwqp->sc_qp);
+
+ irdma_qp_rem_ref(&iwqp->ibqp);
+ wait_for_completion(&iwqp->free_qp);
+ irdma_free_lsmm_rsrc(iwqp);
+ if (!iwdev->reset)
+ irdma_cqp_qp_destroy_cmd(&iwdev->rf->sc_dev, &iwqp->sc_qp);
+
+ if (!iwqp->user_mode) {
+ if (iwqp->iwscq) {
+ irdma_clean_cqes(iwqp, iwqp->iwscq);
+ if (iwqp->iwrcq != iwqp->iwscq)
+ irdma_clean_cqes(iwqp, iwqp->iwrcq);
+ }
+ }
+ irdma_remove_push_mmap_entries(iwqp);
+ irdma_free_qp_rsrc(iwqp);
+
+ return 0;
+}
+
+/**
+ * irdma_setup_virt_qp - setup for allocation of virtual qp
+ * @iwdev: irdma device
+ * @iwqp: qp ptr
+ * @init_info: initialize info to return
+ */
+static int irdma_setup_virt_qp(struct irdma_device *iwdev,
+ struct irdma_qp *iwqp,
+ struct irdma_qp_init_info *init_info)
+{
+ struct irdma_pbl *iwpbl = iwqp->iwpbl;
+ struct irdma_qp_mr *qpmr = &iwpbl->qp_mr;
+
+ iwqp->page = qpmr->sq_page;
+ init_info->shadow_area_pa = qpmr->shadow;
+ if (iwpbl->pbl_allocated) {
+ init_info->virtual_map = true;
+ init_info->sq_pa = qpmr->sq_pbl.idx;
+ init_info->rq_pa = qpmr->rq_pbl.idx;
+ } else {
+ init_info->sq_pa = qpmr->sq_pbl.addr;
+ init_info->rq_pa = qpmr->rq_pbl.addr;
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_setup_kmode_qp - setup initialization for kernel mode qp
+ * @iwdev: iwarp device
+ * @iwqp: qp ptr (user or kernel)
+ * @info: initialize info to return
+ * @init_attr: Initial QP create attributes
+ */
+static int irdma_setup_kmode_qp(struct irdma_device *iwdev,
+ struct irdma_qp *iwqp,
+ struct irdma_qp_init_info *info,
+ struct ib_qp_init_attr *init_attr)
+{
+ struct irdma_dma_mem *mem = &iwqp->kqp.dma_mem;
+ u32 sqdepth, rqdepth;
+ u8 sqshift, rqshift;
+ u32 size;
+ enum irdma_status_code status;
+ struct irdma_qp_uk_init_info *ukinfo = &info->qp_uk_init_info;
+ struct irdma_uk_attrs *uk_attrs = &iwdev->rf->sc_dev.hw_attrs.uk_attrs;
+
+ irdma_get_wqe_shift(uk_attrs,
+ uk_attrs->hw_rev >= IRDMA_GEN_2 ? ukinfo->max_sq_frag_cnt + 1 :
+ ukinfo->max_sq_frag_cnt,
+ ukinfo->max_inline_data, &sqshift);
+ status = irdma_get_sqdepth(uk_attrs, ukinfo->sq_size, sqshift,
+ &sqdepth);
+ if (status)
+ return -ENOMEM;
+
+ if (uk_attrs->hw_rev == IRDMA_GEN_1)
+ rqshift = IRDMA_MAX_RQ_WQE_SHIFT_GEN1;
+ else
+ irdma_get_wqe_shift(uk_attrs, ukinfo->max_rq_frag_cnt, 0,
+ &rqshift);
+
+ status = irdma_get_rqdepth(uk_attrs, ukinfo->rq_size, rqshift,
+ &rqdepth);
+ if (status)
+ return -ENOMEM;
+
+ iwqp->kqp.sq_wrid_mem =
+ kcalloc(sqdepth, sizeof(*iwqp->kqp.sq_wrid_mem), GFP_KERNEL);
+ if (!iwqp->kqp.sq_wrid_mem)
+ return -ENOMEM;
+
+ iwqp->kqp.rq_wrid_mem =
+ kcalloc(rqdepth, sizeof(*iwqp->kqp.rq_wrid_mem), GFP_KERNEL);
+ if (!iwqp->kqp.rq_wrid_mem) {
+ kfree(iwqp->kqp.sq_wrid_mem);
+ iwqp->kqp.sq_wrid_mem = NULL;
+ return -ENOMEM;
+ }
+
+ ukinfo->sq_wrtrk_array = iwqp->kqp.sq_wrid_mem;
+ ukinfo->rq_wrid_array = iwqp->kqp.rq_wrid_mem;
+
+ size = (sqdepth + rqdepth) * IRDMA_QP_WQE_MIN_SIZE;
+ size += (IRDMA_SHADOW_AREA_SIZE << 3);
+
+ mem->size = ALIGN(size, 256);
+ mem->va = dma_alloc_coherent(iwdev->rf->hw.device, mem->size,
+ &mem->pa, GFP_KERNEL);
+ if (!mem->va) {
+ kfree(iwqp->kqp.sq_wrid_mem);
+ iwqp->kqp.sq_wrid_mem = NULL;
+ kfree(iwqp->kqp.rq_wrid_mem);
+ iwqp->kqp.rq_wrid_mem = NULL;
+ return -ENOMEM;
+ }
+
+ ukinfo->sq = mem->va;
+ info->sq_pa = mem->pa;
+ ukinfo->rq = &ukinfo->sq[sqdepth];
+ info->rq_pa = info->sq_pa + (sqdepth * IRDMA_QP_WQE_MIN_SIZE);
+ ukinfo->shadow_area = ukinfo->rq[rqdepth].elem;
+ info->shadow_area_pa = info->rq_pa + (rqdepth * IRDMA_QP_WQE_MIN_SIZE);
+ ukinfo->sq_size = sqdepth >> sqshift;
+ ukinfo->rq_size = rqdepth >> rqshift;
+ ukinfo->qp_id = iwqp->ibqp.qp_num;
+
+ init_attr->cap.max_send_wr = (sqdepth - IRDMA_SQ_RSVD) >> sqshift;
+ init_attr->cap.max_recv_wr = (rqdepth - IRDMA_RQ_RSVD) >> rqshift;
+
+ return 0;
+}
+
+static int irdma_cqp_create_qp_cmd(struct irdma_qp *iwqp)
+{
+ struct irdma_pci_f *rf = iwqp->iwdev->rf;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_create_qp_info *qp_info;
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
+ if (!cqp_request)
+ return -ENOMEM;
+
+ cqp_info = &cqp_request->info;
+ qp_info = &cqp_request->info.in.u.qp_create.info;
+ memset(qp_info, 0, sizeof(*qp_info));
+ qp_info->mac_valid = true;
+ qp_info->cq_num_valid = true;
+ qp_info->next_iwarp_state = IRDMA_QP_STATE_IDLE;
+
+ cqp_info->cqp_cmd = IRDMA_OP_QP_CREATE;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.qp_create.qp = &iwqp->sc_qp;
+ cqp_info->in.u.qp_create.scratch = (uintptr_t)cqp_request;
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+
+ return status ? -ENOMEM : 0;
+}
+
+static void irdma_roce_fill_and_set_qpctx_info(struct irdma_qp *iwqp,
+ struct irdma_qp_host_ctx_info *ctx_info)
+{
+ struct irdma_device *iwdev = iwqp->iwdev;
+ struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
+ struct irdma_roce_offload_info *roce_info;
+ struct irdma_udp_offload_info *udp_info;
+
+ udp_info = &iwqp->udp_info;
+ udp_info->snd_mss = ib_mtu_enum_to_int(ib_mtu_int_to_enum(iwdev->vsi.mtu));
+ udp_info->cwnd = iwdev->roce_cwnd;
+ udp_info->rexmit_thresh = 2;
+ udp_info->rnr_nak_thresh = 2;
+ udp_info->src_port = 0xc000;
+ udp_info->dst_port = ROCE_V2_UDP_DPORT;
+ roce_info = &iwqp->roce_info;
+ ether_addr_copy(roce_info->mac_addr, iwdev->netdev->dev_addr);
+
+ roce_info->rd_en = true;
+ roce_info->wr_rdresp_en = true;
+ roce_info->bind_en = true;
+ roce_info->dcqcn_en = false;
+ roce_info->rtomin = 5;
+
+ roce_info->ack_credits = iwdev->roce_ackcreds;
+ roce_info->ird_size = dev->hw_attrs.max_hw_ird;
+ roce_info->ord_size = dev->hw_attrs.max_hw_ord;
+
+ if (!iwqp->user_mode) {
+ roce_info->priv_mode_en = true;
+ roce_info->fast_reg_en = true;
+ roce_info->udprivcq_en = true;
+ }
+ roce_info->roce_tver = 0;
+
+ ctx_info->roce_info = &iwqp->roce_info;
+ ctx_info->udp_info = &iwqp->udp_info;
+ irdma_sc_qp_setctx_roce(&iwqp->sc_qp, iwqp->host_ctx.va, ctx_info);
+}
+
+static void irdma_iw_fill_and_set_qpctx_info(struct irdma_qp *iwqp,
+ struct irdma_qp_host_ctx_info *ctx_info)
+{
+ struct irdma_device *iwdev = iwqp->iwdev;
+ struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
+ struct irdma_iwarp_offload_info *iwarp_info;
+
+ iwarp_info = &iwqp->iwarp_info;
+ ether_addr_copy(iwarp_info->mac_addr, iwdev->netdev->dev_addr);
+ iwarp_info->rd_en = true;
+ iwarp_info->wr_rdresp_en = true;
+ iwarp_info->bind_en = true;
+ iwarp_info->ecn_en = true;
+ iwarp_info->rtomin = 5;
+
+ if (dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2)
+ iwarp_info->ib_rd_en = true;
+ if (!iwqp->user_mode) {
+ iwarp_info->priv_mode_en = true;
+ iwarp_info->fast_reg_en = true;
+ }
+ iwarp_info->ddp_ver = 1;
+ iwarp_info->rdmap_ver = 1;
+
+ ctx_info->iwarp_info = &iwqp->iwarp_info;
+ ctx_info->iwarp_info_valid = true;
+ irdma_sc_qp_setctx(&iwqp->sc_qp, iwqp->host_ctx.va, ctx_info);
+ ctx_info->iwarp_info_valid = false;
+}
+
+static int irdma_validate_qp_attrs(struct ib_qp_init_attr *init_attr,
+ struct irdma_device *iwdev)
+{
+ struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
+ struct irdma_uk_attrs *uk_attrs = &dev->hw_attrs.uk_attrs;
+
+ if (init_attr->create_flags)
+ return -EOPNOTSUPP;
+
+ if (init_attr->cap.max_inline_data > uk_attrs->max_hw_inline ||
+ init_attr->cap.max_send_sge > uk_attrs->max_hw_wq_frags ||
+ init_attr->cap.max_recv_sge > uk_attrs->max_hw_wq_frags)
+ return -EINVAL;
+
+ if (rdma_protocol_roce(&iwdev->ibdev, 1)) {
+ if (init_attr->qp_type != IB_QPT_RC &&
+ init_attr->qp_type != IB_QPT_UD &&
+ init_attr->qp_type != IB_QPT_GSI)
+ return -EOPNOTSUPP;
+ } else {
+ if (init_attr->qp_type != IB_QPT_RC)
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_create_qp - create qp
+ * @ibpd: ptr of pd
+ * @init_attr: attributes for qp
+ * @udata: user data for create qp
+ */
+static struct ib_qp *irdma_create_qp(struct ib_pd *ibpd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ struct irdma_pd *iwpd = to_iwpd(ibpd);
+ struct irdma_device *iwdev = to_iwdev(ibpd->device);
+ struct irdma_pci_f *rf = iwdev->rf;
+ struct irdma_qp *iwqp;
+ struct irdma_create_qp_req req;
+ struct irdma_create_qp_resp uresp = {};
+ u32 qp_num = 0;
+ enum irdma_status_code ret;
+ int err_code;
+ int sq_size;
+ int rq_size;
+ struct irdma_sc_qp *qp;
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ struct irdma_uk_attrs *uk_attrs = &dev->hw_attrs.uk_attrs;
+ struct irdma_qp_init_info init_info = {};
+ struct irdma_qp_host_ctx_info *ctx_info;
+ unsigned long flags;
+
+ err_code = irdma_validate_qp_attrs(init_attr, iwdev);
+ if (err_code)
+ return ERR_PTR(err_code);
+
+ sq_size = init_attr->cap.max_send_wr;
+ rq_size = init_attr->cap.max_recv_wr;
+
+ init_info.vsi = &iwdev->vsi;
+ init_info.qp_uk_init_info.uk_attrs = uk_attrs;
+ init_info.qp_uk_init_info.sq_size = sq_size;
+ init_info.qp_uk_init_info.rq_size = rq_size;
+ init_info.qp_uk_init_info.max_sq_frag_cnt = init_attr->cap.max_send_sge;
+ init_info.qp_uk_init_info.max_rq_frag_cnt = init_attr->cap.max_recv_sge;
+ init_info.qp_uk_init_info.max_inline_data = init_attr->cap.max_inline_data;
+
+ iwqp = kzalloc(sizeof(*iwqp), GFP_KERNEL);
+ if (!iwqp)
+ return ERR_PTR(-ENOMEM);
+
+ qp = &iwqp->sc_qp;
+ qp->qp_uk.back_qp = iwqp;
+ qp->qp_uk.lock = &iwqp->lock;
+ qp->push_idx = IRDMA_INVALID_PUSH_PAGE_INDEX;
+
+ iwqp->iwdev = iwdev;
+ iwqp->q2_ctx_mem.size = ALIGN(IRDMA_Q2_BUF_SIZE + IRDMA_QP_CTX_SIZE,
+ 256);
+ iwqp->q2_ctx_mem.va = dma_alloc_coherent(dev->hw->device,
+ iwqp->q2_ctx_mem.size,
+ &iwqp->q2_ctx_mem.pa,
+ GFP_KERNEL);
+ if (!iwqp->q2_ctx_mem.va) {
+ err_code = -ENOMEM;
+ goto error;
+ }
+
+ init_info.q2 = iwqp->q2_ctx_mem.va;
+ init_info.q2_pa = iwqp->q2_ctx_mem.pa;
+ init_info.host_ctx = (__le64 *)(init_info.q2 + IRDMA_Q2_BUF_SIZE);
+ init_info.host_ctx_pa = init_info.q2_pa + IRDMA_Q2_BUF_SIZE;
+
+ if (init_attr->qp_type == IB_QPT_GSI)
+ qp_num = 1;
+ else
+ err_code = irdma_alloc_rsrc(rf, rf->allocated_qps, rf->max_qp,
+ &qp_num, &rf->next_qp);
+ if (err_code)
+ goto error;
+
+ iwqp->iwpd = iwpd;
+ iwqp->ibqp.qp_num = qp_num;
+ qp = &iwqp->sc_qp;
+ iwqp->iwscq = to_iwcq(init_attr->send_cq);
+ iwqp->iwrcq = to_iwcq(init_attr->recv_cq);
+ iwqp->host_ctx.va = init_info.host_ctx;
+ iwqp->host_ctx.pa = init_info.host_ctx_pa;
+ iwqp->host_ctx.size = IRDMA_QP_CTX_SIZE;
+
+ init_info.pd = &iwpd->sc_pd;
+ init_info.qp_uk_init_info.qp_id = iwqp->ibqp.qp_num;
+ if (!rdma_protocol_roce(&iwdev->ibdev, 1))
+ init_info.qp_uk_init_info.first_sq_wq = 1;
+ iwqp->ctx_info.qp_compl_ctx = (uintptr_t)qp;
+ init_waitqueue_head(&iwqp->waitq);
+ init_waitqueue_head(&iwqp->mod_qp_waitq);
+
+ if (udata) {
+ err_code = ib_copy_from_udata(&req, udata,
+ min(sizeof(req), udata->inlen));
+ if (err_code) {
+ ibdev_dbg(&iwdev->ibdev,
+ "VERBS: ib_copy_from_data fail\n");
+ goto error;
+ }
+
+ iwqp->ctx_info.qp_compl_ctx = req.user_compl_ctx;
+ iwqp->user_mode = 1;
+ if (req.user_wqe_bufs) {
+ struct irdma_ucontext *ucontext =
+ rdma_udata_to_drv_context(udata,
+ struct irdma_ucontext,
+ ibucontext);
+
+ init_info.qp_uk_init_info.legacy_mode = ucontext->legacy_mode;
+ spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
+ iwqp->iwpbl = irdma_get_pbl((unsigned long)req.user_wqe_bufs,
+ &ucontext->qp_reg_mem_list);
+ spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
+
+ if (!iwqp->iwpbl) {
+ err_code = -ENODATA;
+ ibdev_dbg(&iwdev->ibdev, "VERBS: no pbl info\n");
+ goto error;
+ }
+ }
+ init_info.qp_uk_init_info.abi_ver = iwpd->sc_pd.abi_ver;
+ err_code = irdma_setup_virt_qp(iwdev, iwqp, &init_info);
+ } else {
+ init_info.qp_uk_init_info.abi_ver = IRDMA_ABI_VER;
+ err_code = irdma_setup_kmode_qp(iwdev, iwqp, &init_info, init_attr);
+ }
+
+ if (err_code) {
+ ibdev_dbg(&iwdev->ibdev, "VERBS: setup qp failed\n");
+ goto error;
+ }
+
+ if (rdma_protocol_roce(&iwdev->ibdev, 1)) {
+ if (init_attr->qp_type == IB_QPT_RC) {
+ init_info.qp_uk_init_info.type = IRDMA_QP_TYPE_ROCE_RC;
+ init_info.qp_uk_init_info.qp_caps = IRDMA_SEND_WITH_IMM |
+ IRDMA_WRITE_WITH_IMM |
+ IRDMA_ROCE;
+ } else {
+ init_info.qp_uk_init_info.type = IRDMA_QP_TYPE_ROCE_UD;
+ init_info.qp_uk_init_info.qp_caps = IRDMA_SEND_WITH_IMM |
+ IRDMA_ROCE;
+ }
+ } else {
+ init_info.qp_uk_init_info.type = IRDMA_QP_TYPE_IWARP;
+ init_info.qp_uk_init_info.qp_caps = IRDMA_WRITE_WITH_IMM;
+ }
+
+ if (dev->hw_attrs.uk_attrs.hw_rev > IRDMA_GEN_1)
+ init_info.qp_uk_init_info.qp_caps |= IRDMA_PUSH_MODE;
+
+ ret = irdma_sc_qp_init(qp, &init_info);
+ if (ret) {
+ err_code = -EPROTO;
+ ibdev_dbg(&iwdev->ibdev, "VERBS: qp_init fail\n");
+ goto error;
+ }
+
+ ctx_info = &iwqp->ctx_info;
+ ctx_info->send_cq_num = iwqp->iwscq->sc_cq.cq_uk.cq_id;
+ ctx_info->rcv_cq_num = iwqp->iwrcq->sc_cq.cq_uk.cq_id;
+
+ if (rdma_protocol_roce(&iwdev->ibdev, 1))
+ irdma_roce_fill_and_set_qpctx_info(iwqp, ctx_info);
+ else
+ irdma_iw_fill_and_set_qpctx_info(iwqp, ctx_info);
+
+ err_code = irdma_cqp_create_qp_cmd(iwqp);
+ if (err_code)
+ goto error;
+
+ refcount_set(&iwqp->refcnt, 1);
+ spin_lock_init(&iwqp->lock);
+ spin_lock_init(&iwqp->sc_qp.pfpdu.lock);
+ iwqp->sig_all = (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) ? 1 : 0;
+ rf->qp_table[qp_num] = iwqp;
+ iwqp->max_send_wr = sq_size;
+ iwqp->max_recv_wr = rq_size;
+
+ if (rdma_protocol_roce(&iwdev->ibdev, 1)) {
+ if (dev->ws_add(&iwdev->vsi, 0)) {
+ irdma_cqp_qp_destroy_cmd(&rf->sc_dev, &iwqp->sc_qp);
+ err_code = -EINVAL;
+ goto error;
+ }
+
+ irdma_qp_add_qos(&iwqp->sc_qp);
+ }
+
+ if (udata) {
+ /* GEN_1 legacy support with libi40iw does not have expanded uresp struct */
+ if (udata->outlen < sizeof(uresp)) {
+ uresp.lsmm = 1;
+ uresp.push_idx = IRDMA_INVALID_PUSH_PAGE_INDEX_GEN_1;
+ } else {
+ if (rdma_protocol_iwarp(&iwdev->ibdev, 1))
+ uresp.lsmm = 1;
+ }
+ uresp.actual_sq_size = sq_size;
+ uresp.actual_rq_size = rq_size;
+ uresp.qp_id = qp_num;
+ uresp.qp_caps = qp->qp_uk.qp_caps;
+
+ err_code = ib_copy_to_udata(udata, &uresp,
+ min(sizeof(uresp), udata->outlen));
+ if (err_code) {
+ ibdev_dbg(&iwdev->ibdev, "VERBS: copy_to_udata failed\n");
+ irdma_destroy_qp(&iwqp->ibqp, udata);
+ return ERR_PTR(err_code);
+ }
+ }
+
+ init_completion(&iwqp->free_qp);
+ return &iwqp->ibqp;
+
+error:
+ irdma_free_qp_rsrc(iwqp);
+
+ return ERR_PTR(err_code);
+}
+
+static int irdma_get_ib_acc_flags(struct irdma_qp *iwqp)
+{
+ int acc_flags = 0;
+
+ if (rdma_protocol_roce(iwqp->ibqp.device, 1)) {
+ if (iwqp->roce_info.wr_rdresp_en) {
+ acc_flags |= IB_ACCESS_LOCAL_WRITE;
+ acc_flags |= IB_ACCESS_REMOTE_WRITE;
+ }
+ if (iwqp->roce_info.rd_en)
+ acc_flags |= IB_ACCESS_REMOTE_READ;
+ if (iwqp->roce_info.bind_en)
+ acc_flags |= IB_ACCESS_MW_BIND;
+ } else {
+ if (iwqp->iwarp_info.wr_rdresp_en) {
+ acc_flags |= IB_ACCESS_LOCAL_WRITE;
+ acc_flags |= IB_ACCESS_REMOTE_WRITE;
+ }
+ if (iwqp->iwarp_info.rd_en)
+ acc_flags |= IB_ACCESS_REMOTE_READ;
+ if (iwqp->iwarp_info.bind_en)
+ acc_flags |= IB_ACCESS_MW_BIND;
+ }
+ return acc_flags;
+}
+
+/**
+ * irdma_query_qp - query qp attributes
+ * @ibqp: qp pointer
+ * @attr: attributes pointer
+ * @attr_mask: Not used
+ * @init_attr: qp attributes to return
+ */
+static int irdma_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_qp_init_attr *init_attr)
+{
+ struct irdma_qp *iwqp = to_iwqp(ibqp);
+ struct irdma_sc_qp *qp = &iwqp->sc_qp;
+
+ memset(attr, 0, sizeof(*attr));
+ memset(init_attr, 0, sizeof(*init_attr));
+
+ attr->qp_state = iwqp->ibqp_state;
+ attr->cur_qp_state = iwqp->ibqp_state;
+ attr->cap.max_send_wr = iwqp->max_send_wr;
+ attr->cap.max_recv_wr = iwqp->max_recv_wr;
+ attr->cap.max_inline_data = qp->qp_uk.max_inline_data;
+ attr->cap.max_send_sge = qp->qp_uk.max_sq_frag_cnt;
+ attr->cap.max_recv_sge = qp->qp_uk.max_rq_frag_cnt;
+ attr->qp_access_flags = irdma_get_ib_acc_flags(iwqp);
+ attr->port_num = 1;
+ if (rdma_protocol_roce(ibqp->device, 1)) {
+ attr->path_mtu = ib_mtu_int_to_enum(iwqp->udp_info.snd_mss);
+ attr->qkey = iwqp->roce_info.qkey;
+ attr->rq_psn = iwqp->udp_info.epsn;
+ attr->sq_psn = iwqp->udp_info.psn_nxt;
+ attr->dest_qp_num = iwqp->roce_info.dest_qp;
+ attr->pkey_index = iwqp->roce_info.p_key;
+ attr->retry_cnt = iwqp->udp_info.rexmit_thresh;
+ attr->rnr_retry = iwqp->udp_info.rnr_nak_thresh;
+ attr->max_rd_atomic = iwqp->roce_info.ord_size;
+ attr->max_dest_rd_atomic = iwqp->roce_info.ird_size;
+ }
+
+ init_attr->event_handler = iwqp->ibqp.event_handler;
+ init_attr->qp_context = iwqp->ibqp.qp_context;
+ init_attr->send_cq = iwqp->ibqp.send_cq;
+ init_attr->recv_cq = iwqp->ibqp.recv_cq;
+ init_attr->cap = attr->cap;
+
+ return 0;
+}
+
+/**
+ * irdma_query_pkey - Query partition key
+ * @ibdev: device pointer from stack
+ * @port: port number
+ * @index: index of pkey
+ * @pkey: pointer to store the pkey
+ */
+static int irdma_query_pkey(struct ib_device *ibdev, u32 port, u16 index,
+ u16 *pkey)
+{
+ if (index >= IRDMA_PKEY_TBL_SZ)
+ return -EINVAL;
+
+ *pkey = IRDMA_DEFAULT_PKEY;
+ return 0;
+}
+
+/**
+ * irdma_modify_qp_roce - modify qp request
+ * @ibqp: qp's pointer for modify
+ * @attr: access attributes
+ * @attr_mask: state mask
+ * @udata: user data
+ */
+int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata)
+{
+ struct irdma_pd *iwpd = to_iwpd(ibqp->pd);
+ struct irdma_qp *iwqp = to_iwqp(ibqp);
+ struct irdma_device *iwdev = iwqp->iwdev;
+ struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
+ struct irdma_qp_host_ctx_info *ctx_info;
+ struct irdma_roce_offload_info *roce_info;
+ struct irdma_udp_offload_info *udp_info;
+ struct irdma_modify_qp_info info = {};
+ struct irdma_modify_qp_resp uresp = {};
+ struct irdma_modify_qp_req ureq = {};
+ unsigned long flags;
+ u8 issue_modify_qp = 0;
+ int ret = 0;
+
+ ctx_info = &iwqp->ctx_info;
+ roce_info = &iwqp->roce_info;
+ udp_info = &iwqp->udp_info;
+
+ if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
+ return -EOPNOTSUPP;
+
+ if (attr_mask & IB_QP_DEST_QPN)
+ roce_info->dest_qp = attr->dest_qp_num;
+
+ if (attr_mask & IB_QP_PKEY_INDEX) {
+ ret = irdma_query_pkey(ibqp->device, 0, attr->pkey_index,
+ &roce_info->p_key);
+ if (ret)
+ return ret;
+ }
+
+ if (attr_mask & IB_QP_QKEY)
+ roce_info->qkey = attr->qkey;
+
+ if (attr_mask & IB_QP_PATH_MTU)
+ udp_info->snd_mss = ib_mtu_enum_to_int(attr->path_mtu);
+
+ if (attr_mask & IB_QP_SQ_PSN) {
+ udp_info->psn_nxt = attr->sq_psn;
+ udp_info->lsn = 0xffff;
+ udp_info->psn_una = attr->sq_psn;
+ udp_info->psn_max = attr->sq_psn;
+ }
+
+ if (attr_mask & IB_QP_RQ_PSN)
+ udp_info->epsn = attr->rq_psn;
+
+ if (attr_mask & IB_QP_RNR_RETRY)
+ udp_info->rnr_nak_thresh = attr->rnr_retry;
+
+ if (attr_mask & IB_QP_RETRY_CNT)
+ udp_info->rexmit_thresh = attr->retry_cnt;
+
+ ctx_info->roce_info->pd_id = iwpd->sc_pd.pd_id;
+
+ if (attr_mask & IB_QP_AV) {
+ struct irdma_av *av = &iwqp->roce_ah.av;
+ const struct ib_gid_attr *sgid_attr;
+ u16 vlan_id = VLAN_N_VID;
+ u32 local_ip[4];
+
+ memset(&iwqp->roce_ah, 0, sizeof(iwqp->roce_ah));
+ if (attr->ah_attr.ah_flags & IB_AH_GRH) {
+ udp_info->ttl = attr->ah_attr.grh.hop_limit;
+ udp_info->flow_label = attr->ah_attr.grh.flow_label;
+ udp_info->tos = attr->ah_attr.grh.traffic_class;
+ irdma_qp_rem_qos(&iwqp->sc_qp);
+ dev->ws_remove(iwqp->sc_qp.vsi, ctx_info->user_pri);
+ ctx_info->user_pri = rt_tos2priority(udp_info->tos);
+ iwqp->sc_qp.user_pri = ctx_info->user_pri;
+ if (dev->ws_add(iwqp->sc_qp.vsi, ctx_info->user_pri))
+ return -ENOMEM;
+ irdma_qp_add_qos(&iwqp->sc_qp);
+ }
+ sgid_attr = attr->ah_attr.grh.sgid_attr;
+ ret = rdma_read_gid_l2_fields(sgid_attr, &vlan_id,
+ ctx_info->roce_info->mac_addr);
+ if (ret)
+ return ret;
+
+ if (vlan_id >= VLAN_N_VID && iwdev->dcb)
+ vlan_id = 0;
+ if (vlan_id < VLAN_N_VID) {
+ udp_info->insert_vlan_tag = true;
+ udp_info->vlan_tag = vlan_id |
+ ctx_info->user_pri << VLAN_PRIO_SHIFT;
+ } else {
+ udp_info->insert_vlan_tag = false;
+ }
+
+ av->attrs = attr->ah_attr;
+ rdma_gid2ip((struct sockaddr *)&av->sgid_addr, &sgid_attr->gid);
+ rdma_gid2ip((struct sockaddr *)&av->dgid_addr, &attr->ah_attr.grh.dgid);
+ roce_info->local_qp = ibqp->qp_num;
+ if (av->sgid_addr.saddr.sa_family == AF_INET6) {
+ __be32 *daddr =
+ av->dgid_addr.saddr_in6.sin6_addr.in6_u.u6_addr32;
+ __be32 *saddr =
+ av->sgid_addr.saddr_in6.sin6_addr.in6_u.u6_addr32;
+
+ irdma_copy_ip_ntohl(&udp_info->dest_ip_addr[0], daddr);
+ irdma_copy_ip_ntohl(&udp_info->local_ipaddr[0], saddr);
+
+ udp_info->ipv4 = false;
+ irdma_copy_ip_ntohl(local_ip, daddr);
+
+ udp_info->arp_idx = irdma_arp_table(iwdev->rf,
+ &local_ip[0],
+ false, NULL,
+ IRDMA_ARP_RESOLVE);
+ } else {
+ __be32 saddr = av->sgid_addr.saddr_in.sin_addr.s_addr;
+ __be32 daddr = av->dgid_addr.saddr_in.sin_addr.s_addr;
+
+ local_ip[0] = ntohl(daddr);
+
+ udp_info->ipv4 = true;
+ udp_info->dest_ip_addr[0] = 0;
+ udp_info->dest_ip_addr[1] = 0;
+ udp_info->dest_ip_addr[2] = 0;
+ udp_info->dest_ip_addr[3] = local_ip[0];
+
+ udp_info->local_ipaddr[0] = 0;
+ udp_info->local_ipaddr[1] = 0;
+ udp_info->local_ipaddr[2] = 0;
+ udp_info->local_ipaddr[3] = ntohl(saddr);
+ }
+ udp_info->arp_idx =
+ irdma_add_arp(iwdev->rf, local_ip, udp_info->ipv4,
+ attr->ah_attr.roce.dmac);
+ }
+
+ if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+ if (attr->max_rd_atomic > dev->hw_attrs.max_hw_ord) {
+ ibdev_err(&iwdev->ibdev,
+ "rd_atomic = %d, above max_hw_ord=%d\n",
+ attr->max_rd_atomic,
+ dev->hw_attrs.max_hw_ord);
+ return -EINVAL;
+ }
+ if (attr->max_rd_atomic)
+ roce_info->ord_size = attr->max_rd_atomic;
+ info.ord_valid = true;
+ }
+
+ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
+ if (attr->max_dest_rd_atomic > dev->hw_attrs.max_hw_ird) {
+ ibdev_err(&iwdev->ibdev,
+ "rd_atomic = %d, above max_hw_ird=%d\n",
+ attr->max_rd_atomic,
+ dev->hw_attrs.max_hw_ird);
+ return -EINVAL;
+ }
+ if (attr->max_dest_rd_atomic)
+ roce_info->ird_size = attr->max_dest_rd_atomic;
+ }
+
+ if (attr_mask & IB_QP_ACCESS_FLAGS) {
+ if (attr->qp_access_flags & IB_ACCESS_LOCAL_WRITE)
+ roce_info->wr_rdresp_en = true;
+ if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE)
+ roce_info->wr_rdresp_en = true;
+ if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ)
+ roce_info->rd_en = true;
+ }
+
+ wait_event(iwqp->mod_qp_waitq, !atomic_read(&iwqp->hw_mod_qp_pend));
+
+ ibdev_dbg(&iwdev->ibdev,
+ "VERBS: caller: %pS qp_id=%d to_ibqpstate=%d ibqpstate=%d irdma_qpstate=%d attr_mask=0x%x\n",
+ __builtin_return_address(0), ibqp->qp_num, attr->qp_state,
+ iwqp->ibqp_state, iwqp->iwarp_state, attr_mask);
+
+ spin_lock_irqsave(&iwqp->lock, flags);
+ if (attr_mask & IB_QP_STATE) {
+ if (!ib_modify_qp_is_ok(iwqp->ibqp_state, attr->qp_state,
+ iwqp->ibqp.qp_type, attr_mask)) {
+ ibdev_warn(&iwdev->ibdev, "modify_qp invalid for qp_id=%d, old_state=0x%x, new_state=0x%x\n",
+ iwqp->ibqp.qp_num, iwqp->ibqp_state,
+ attr->qp_state);
+ ret = -EINVAL;
+ goto exit;
+ }
+ info.curr_iwarp_state = iwqp->iwarp_state;
+
+ switch (attr->qp_state) {
+ case IB_QPS_INIT:
+ if (iwqp->iwarp_state > IRDMA_QP_STATE_IDLE) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (iwqp->iwarp_state == IRDMA_QP_STATE_INVALID) {
+ info.next_iwarp_state = IRDMA_QP_STATE_IDLE;
+ issue_modify_qp = 1;
+ }
+ break;
+ case IB_QPS_RTR:
+ if (iwqp->iwarp_state > IRDMA_QP_STATE_IDLE) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ info.arp_cache_idx_valid = true;
+ info.cq_num_valid = true;
+ info.next_iwarp_state = IRDMA_QP_STATE_RTR;
+ issue_modify_qp = 1;
+ break;
+ case IB_QPS_RTS:
+ if (iwqp->ibqp_state < IB_QPS_RTR ||
+ iwqp->ibqp_state == IB_QPS_ERR) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ info.arp_cache_idx_valid = true;
+ info.cq_num_valid = true;
+ info.ord_valid = true;
+ info.next_iwarp_state = IRDMA_QP_STATE_RTS;
+ issue_modify_qp = 1;
+ if (iwdev->push_mode && udata &&
+ iwqp->sc_qp.push_idx == IRDMA_INVALID_PUSH_PAGE_INDEX &&
+ dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ irdma_alloc_push_page(iwqp);
+ spin_lock_irqsave(&iwqp->lock, flags);
+ }
+ break;
+ case IB_QPS_SQD:
+ if (iwqp->iwarp_state == IRDMA_QP_STATE_SQD)
+ goto exit;
+
+ if (iwqp->iwarp_state != IRDMA_QP_STATE_RTS) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ info.next_iwarp_state = IRDMA_QP_STATE_SQD;
+ issue_modify_qp = 1;
+ break;
+ case IB_QPS_SQE:
+ case IB_QPS_ERR:
+ case IB_QPS_RESET:
+ if (iwqp->iwarp_state == IRDMA_QP_STATE_RTS) {
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ info.next_iwarp_state = IRDMA_QP_STATE_SQD;
+ irdma_hw_modify_qp(iwdev, iwqp, &info, true);
+ spin_lock_irqsave(&iwqp->lock, flags);
+ }
+
+ if (iwqp->iwarp_state == IRDMA_QP_STATE_ERROR) {
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ if (udata) {
+ if (ib_copy_from_udata(&ureq, udata,
+ min(sizeof(ureq), udata->inlen)))
+ return -EINVAL;
+
+ irdma_flush_wqes(iwqp,
+ (ureq.sq_flush ? IRDMA_FLUSH_SQ : 0) |
+ (ureq.rq_flush ? IRDMA_FLUSH_RQ : 0) |
+ IRDMA_REFLUSH);
+ }
+ return 0;
+ }
+
+ info.next_iwarp_state = IRDMA_QP_STATE_ERROR;
+ issue_modify_qp = 1;
+ break;
+ default:
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ iwqp->ibqp_state = attr->qp_state;
+ }
+
+ ctx_info->send_cq_num = iwqp->iwscq->sc_cq.cq_uk.cq_id;
+ ctx_info->rcv_cq_num = iwqp->iwrcq->sc_cq.cq_uk.cq_id;
+ irdma_sc_qp_setctx_roce(&iwqp->sc_qp, iwqp->host_ctx.va, ctx_info);
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+
+ if (attr_mask & IB_QP_STATE) {
+ if (issue_modify_qp) {
+ ctx_info->rem_endpoint_idx = udp_info->arp_idx;
+ if (irdma_hw_modify_qp(iwdev, iwqp, &info, true))
+ return -EINVAL;
+ spin_lock_irqsave(&iwqp->lock, flags);
+ if (iwqp->iwarp_state == info.curr_iwarp_state) {
+ iwqp->iwarp_state = info.next_iwarp_state;
+ iwqp->ibqp_state = attr->qp_state;
+ }
+ if (iwqp->ibqp_state > IB_QPS_RTS &&
+ !iwqp->flush_issued) {
+ iwqp->flush_issued = 1;
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ irdma_flush_wqes(iwqp, IRDMA_FLUSH_SQ |
+ IRDMA_FLUSH_RQ |
+ IRDMA_FLUSH_WAIT);
+ } else {
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ }
+ } else {
+ iwqp->ibqp_state = attr->qp_state;
+ }
+ if (udata && dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
+ struct irdma_ucontext *ucontext;
+
+ ucontext = rdma_udata_to_drv_context(udata,
+ struct irdma_ucontext, ibucontext);
+ if (iwqp->sc_qp.push_idx != IRDMA_INVALID_PUSH_PAGE_INDEX &&
+ !iwqp->push_wqe_mmap_entry &&
+ !irdma_setup_push_mmap_entries(ucontext, iwqp,
+ &uresp.push_wqe_mmap_key, &uresp.push_db_mmap_key)) {
+ uresp.push_valid = 1;
+ uresp.push_offset = iwqp->sc_qp.push_offset;
+ }
+ ret = ib_copy_to_udata(udata, &uresp, min(sizeof(uresp),
+ udata->outlen));
+ if (ret) {
+ irdma_remove_push_mmap_entries(iwqp);
+ ibdev_dbg(&iwdev->ibdev,
+ "VERBS: copy_to_udata failed\n");
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+exit:
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+
+ return ret;
+}
+
+/**
+ * irdma_modify_qp - modify qp request
+ * @ibqp: qp's pointer for modify
+ * @attr: access attributes
+ * @attr_mask: state mask
+ * @udata: user data
+ */
+int irdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
+ struct ib_udata *udata)
+{
+ struct irdma_qp *iwqp = to_iwqp(ibqp);
+ struct irdma_device *iwdev = iwqp->iwdev;
+ struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
+ struct irdma_qp_host_ctx_info *ctx_info;
+ struct irdma_tcp_offload_info *tcp_info;
+ struct irdma_iwarp_offload_info *offload_info;
+ struct irdma_modify_qp_info info = {};
+ struct irdma_modify_qp_resp uresp = {};
+ struct irdma_modify_qp_req ureq = {};
+ u8 issue_modify_qp = 0;
+ u8 dont_wait = 0;
+ int err;
+ unsigned long flags;
+
+ if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
+ return -EOPNOTSUPP;
+
+ ctx_info = &iwqp->ctx_info;
+ offload_info = &iwqp->iwarp_info;
+ tcp_info = &iwqp->tcp_info;
+ wait_event(iwqp->mod_qp_waitq, !atomic_read(&iwqp->hw_mod_qp_pend));
+ ibdev_dbg(&iwdev->ibdev,
+ "VERBS: caller: %pS qp_id=%d to_ibqpstate=%d ibqpstate=%d irdma_qpstate=%d last_aeq=%d hw_tcp_state=%d hw_iwarp_state=%d attr_mask=0x%x\n",
+ __builtin_return_address(0), ibqp->qp_num, attr->qp_state,
+ iwqp->ibqp_state, iwqp->iwarp_state, iwqp->last_aeq,
+ iwqp->hw_tcp_state, iwqp->hw_iwarp_state, attr_mask);
+
+ spin_lock_irqsave(&iwqp->lock, flags);
+ if (attr_mask & IB_QP_STATE) {
+ info.curr_iwarp_state = iwqp->iwarp_state;
+ switch (attr->qp_state) {
+ case IB_QPS_INIT:
+ case IB_QPS_RTR:
+ if (iwqp->iwarp_state > IRDMA_QP_STATE_IDLE) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ if (iwqp->iwarp_state == IRDMA_QP_STATE_INVALID) {
+ info.next_iwarp_state = IRDMA_QP_STATE_IDLE;
+ issue_modify_qp = 1;
+ }
+ if (iwdev->push_mode && udata &&
+ iwqp->sc_qp.push_idx == IRDMA_INVALID_PUSH_PAGE_INDEX &&
+ dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ irdma_alloc_push_page(iwqp);
+ spin_lock_irqsave(&iwqp->lock, flags);
+ }
+ break;
+ case IB_QPS_RTS:
+ if (iwqp->iwarp_state > IRDMA_QP_STATE_RTS ||
+ !iwqp->cm_id) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ issue_modify_qp = 1;
+ iwqp->hw_tcp_state = IRDMA_TCP_STATE_ESTABLISHED;
+ iwqp->hte_added = 1;
+ info.next_iwarp_state = IRDMA_QP_STATE_RTS;
+ info.tcp_ctx_valid = true;
+ info.ord_valid = true;
+ info.arp_cache_idx_valid = true;
+ info.cq_num_valid = true;
+ break;
+ case IB_QPS_SQD:
+ if (iwqp->hw_iwarp_state > IRDMA_QP_STATE_RTS) {
+ err = 0;
+ goto exit;
+ }
+
+ if (iwqp->iwarp_state == IRDMA_QP_STATE_CLOSING ||
+ iwqp->iwarp_state < IRDMA_QP_STATE_RTS) {
+ err = 0;
+ goto exit;
+ }
+
+ if (iwqp->iwarp_state > IRDMA_QP_STATE_CLOSING) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ info.next_iwarp_state = IRDMA_QP_STATE_CLOSING;
+ issue_modify_qp = 1;
+ break;
+ case IB_QPS_SQE:
+ if (iwqp->iwarp_state >= IRDMA_QP_STATE_TERMINATE) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ info.next_iwarp_state = IRDMA_QP_STATE_TERMINATE;
+ issue_modify_qp = 1;
+ break;
+ case IB_QPS_ERR:
+ case IB_QPS_RESET:
+ if (iwqp->iwarp_state == IRDMA_QP_STATE_ERROR) {
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ if (udata) {
+ if (ib_copy_from_udata(&ureq, udata,
+ min(sizeof(ureq), udata->inlen)))
+ return -EINVAL;
+
+ irdma_flush_wqes(iwqp,
+ (ureq.sq_flush ? IRDMA_FLUSH_SQ : 0) |
+ (ureq.rq_flush ? IRDMA_FLUSH_RQ : 0) |
+ IRDMA_REFLUSH);
+ }
+ return 0;
+ }
+
+ if (iwqp->sc_qp.term_flags) {
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ irdma_terminate_del_timer(&iwqp->sc_qp);
+ spin_lock_irqsave(&iwqp->lock, flags);
+ }
+ info.next_iwarp_state = IRDMA_QP_STATE_ERROR;
+ if (iwqp->hw_tcp_state > IRDMA_TCP_STATE_CLOSED &&
+ iwdev->iw_status &&
+ iwqp->hw_tcp_state != IRDMA_TCP_STATE_TIME_WAIT)
+ info.reset_tcp_conn = true;
+ else
+ dont_wait = 1;
+
+ issue_modify_qp = 1;
+ info.next_iwarp_state = IRDMA_QP_STATE_ERROR;
+ break;
+ default:
+ err = -EINVAL;
+ goto exit;
+ }
+
+ iwqp->ibqp_state = attr->qp_state;
+ }
+ if (attr_mask & IB_QP_ACCESS_FLAGS) {
+ ctx_info->iwarp_info_valid = true;
+ if (attr->qp_access_flags & IB_ACCESS_LOCAL_WRITE)
+ offload_info->wr_rdresp_en = true;
+ if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE)
+ offload_info->wr_rdresp_en = true;
+ if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ)
+ offload_info->rd_en = true;
+ }
+
+ if (ctx_info->iwarp_info_valid) {
+ ctx_info->send_cq_num = iwqp->iwscq->sc_cq.cq_uk.cq_id;
+ ctx_info->rcv_cq_num = iwqp->iwrcq->sc_cq.cq_uk.cq_id;
+ irdma_sc_qp_setctx(&iwqp->sc_qp, iwqp->host_ctx.va, ctx_info);
+ }
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+
+ if (attr_mask & IB_QP_STATE) {
+ if (issue_modify_qp) {
+ ctx_info->rem_endpoint_idx = tcp_info->arp_idx;
+ if (irdma_hw_modify_qp(iwdev, iwqp, &info, true))
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&iwqp->lock, flags);
+ if (iwqp->iwarp_state == info.curr_iwarp_state) {
+ iwqp->iwarp_state = info.next_iwarp_state;
+ iwqp->ibqp_state = attr->qp_state;
+ }
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ }
+
+ if (issue_modify_qp && iwqp->ibqp_state > IB_QPS_RTS) {
+ if (dont_wait) {
+ if (iwqp->cm_id && iwqp->hw_tcp_state) {
+ spin_lock_irqsave(&iwqp->lock, flags);
+ iwqp->hw_tcp_state = IRDMA_TCP_STATE_CLOSED;
+ iwqp->last_aeq = IRDMA_AE_RESET_SENT;
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ irdma_cm_disconn(iwqp);
+ }
+ } else {
+ int close_timer_started;
+
+ spin_lock_irqsave(&iwdev->cm_core.ht_lock, flags);
+
+ if (iwqp->cm_node) {
+ refcount_inc(&iwqp->cm_node->refcnt);
+ spin_unlock_irqrestore(&iwdev->cm_core.ht_lock, flags);
+ close_timer_started = atomic_inc_return(&iwqp->close_timer_started);
+ if (iwqp->cm_id && close_timer_started == 1)
+ irdma_schedule_cm_timer(iwqp->cm_node,
+ (struct irdma_puda_buf *)iwqp,
+ IRDMA_TIMER_TYPE_CLOSE, 1, 0);
+
+ irdma_rem_ref_cm_node(iwqp->cm_node);
+ } else {
+ spin_unlock_irqrestore(&iwdev->cm_core.ht_lock, flags);
+ }
+ }
+ }
+ if (attr_mask & IB_QP_STATE && udata &&
+ dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
+ struct irdma_ucontext *ucontext;
+
+ ucontext = rdma_udata_to_drv_context(udata,
+ struct irdma_ucontext, ibucontext);
+ if (iwqp->sc_qp.push_idx != IRDMA_INVALID_PUSH_PAGE_INDEX &&
+ !iwqp->push_wqe_mmap_entry &&
+ !irdma_setup_push_mmap_entries(ucontext, iwqp,
+ &uresp.push_wqe_mmap_key, &uresp.push_db_mmap_key)) {
+ uresp.push_valid = 1;
+ uresp.push_offset = iwqp->sc_qp.push_offset;
+ }
+
+ err = ib_copy_to_udata(udata, &uresp, min(sizeof(uresp),
+ udata->outlen));
+ if (err) {
+ irdma_remove_push_mmap_entries(iwqp);
+ ibdev_dbg(&iwdev->ibdev,
+ "VERBS: copy_to_udata failed\n");
+ return err;
+ }
+ }
+
+ return 0;
+exit:
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+
+ return err;
+}
+
+/**
+ * irdma_cq_free_rsrc - free up resources for cq
+ * @rf: RDMA PCI function
+ * @iwcq: cq ptr
+ */
+static void irdma_cq_free_rsrc(struct irdma_pci_f *rf, struct irdma_cq *iwcq)
+{
+ struct irdma_sc_cq *cq = &iwcq->sc_cq;
+
+ if (!iwcq->user_mode) {
+ dma_free_coherent(rf->sc_dev.hw->device, iwcq->kmem.size,
+ iwcq->kmem.va, iwcq->kmem.pa);
+ iwcq->kmem.va = NULL;
+ dma_free_coherent(rf->sc_dev.hw->device,
+ iwcq->kmem_shadow.size,
+ iwcq->kmem_shadow.va, iwcq->kmem_shadow.pa);
+ iwcq->kmem_shadow.va = NULL;
+ }
+
+ irdma_free_rsrc(rf, rf->allocated_cqs, cq->cq_uk.cq_id);
+}
+
+/**
+ * irdma_free_cqbuf - worker to free a cq buffer
+ * @work: provides access to the cq buffer to free
+ */
+static void irdma_free_cqbuf(struct work_struct *work)
+{
+ struct irdma_cq_buf *cq_buf = container_of(work, struct irdma_cq_buf, work);
+
+ dma_free_coherent(cq_buf->hw->device, cq_buf->kmem_buf.size,
+ cq_buf->kmem_buf.va, cq_buf->kmem_buf.pa);
+ cq_buf->kmem_buf.va = NULL;
+ kfree(cq_buf);
+}
+
+/**
+ * irdma_process_resize_list - remove resized cq buffers from the resize_list
+ * @iwcq: cq which owns the resize_list
+ * @iwdev: irdma device
+ * @lcqe_buf: the buffer where the last cqe is received
+ */
+static int irdma_process_resize_list(struct irdma_cq *iwcq,
+ struct irdma_device *iwdev,
+ struct irdma_cq_buf *lcqe_buf)
+{
+ struct list_head *tmp_node, *list_node;
+ struct irdma_cq_buf *cq_buf;
+ int cnt = 0;
+
+ list_for_each_safe(list_node, tmp_node, &iwcq->resize_list) {
+ cq_buf = list_entry(list_node, struct irdma_cq_buf, list);
+ if (cq_buf == lcqe_buf)
+ return cnt;
+
+ list_del(&cq_buf->list);
+ queue_work(iwdev->cleanup_wq, &cq_buf->work);
+ cnt++;
+ }
+
+ return cnt;
+}
+
+/**
+ * irdma_destroy_cq - destroy cq
+ * @ib_cq: cq pointer
+ * @udata: user data
+ */
+static int irdma_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
+{
+ struct irdma_device *iwdev = to_iwdev(ib_cq->device);
+ struct irdma_cq *iwcq = to_iwcq(ib_cq);
+ struct irdma_sc_cq *cq = &iwcq->sc_cq;
+ struct irdma_sc_dev *dev = cq->dev;
+ struct irdma_sc_ceq *ceq = dev->ceq[cq->ceq_id];
+ struct irdma_ceq *iwceq = container_of(ceq, struct irdma_ceq, sc_ceq);
+ unsigned long flags;
+
+ spin_lock_irqsave(&iwcq->lock, flags);
+ if (!list_empty(&iwcq->resize_list))
+ irdma_process_resize_list(iwcq, iwdev, NULL);
+ spin_unlock_irqrestore(&iwcq->lock, flags);
+
+ irdma_cq_wq_destroy(iwdev->rf, cq);
+ irdma_cq_free_rsrc(iwdev->rf, iwcq);
+
+ spin_lock_irqsave(&iwceq->ce_lock, flags);
+ irdma_sc_cleanup_ceqes(cq, ceq);
+ spin_unlock_irqrestore(&iwceq->ce_lock, flags);
+
+ return 0;
+}
+
+/**
+ * irdma_resize_cq - resize cq
+ * @ibcq: cq to be resized
+ * @entries: desired cq size
+ * @udata: user data
+ */
+static int irdma_resize_cq(struct ib_cq *ibcq, int entries,
+ struct ib_udata *udata)
+{
+ struct irdma_cq *iwcq = to_iwcq(ibcq);
+ struct irdma_sc_dev *dev = iwcq->sc_cq.dev;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_modify_cq_info *m_info;
+ struct irdma_modify_cq_info info = {};
+ struct irdma_dma_mem kmem_buf;
+ struct irdma_cq_mr *cqmr_buf;
+ struct irdma_pbl *iwpbl_buf;
+ struct irdma_device *iwdev;
+ struct irdma_pci_f *rf;
+ struct irdma_cq_buf *cq_buf = NULL;
+ enum irdma_status_code status = 0;
+ unsigned long flags;
+ int ret;
+
+ iwdev = to_iwdev(ibcq->device);
+ rf = iwdev->rf;
+
+ if (!(rf->sc_dev.hw_attrs.uk_attrs.feature_flags &
+ IRDMA_FEATURE_CQ_RESIZE))
+ return -EOPNOTSUPP;
+
+ if (entries > rf->max_cqe)
+ return -EINVAL;
+
+ if (!iwcq->user_mode) {
+ entries++;
+ if (rf->sc_dev.hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2)
+ entries *= 2;
+ }
+
+ info.cq_size = max(entries, 4);
+
+ if (info.cq_size == iwcq->sc_cq.cq_uk.cq_size - 1)
+ return 0;
+
+ if (udata) {
+ struct irdma_resize_cq_req req = {};
+ struct irdma_ucontext *ucontext =
+ rdma_udata_to_drv_context(udata, struct irdma_ucontext,
+ ibucontext);
+
+ /* CQ resize not supported with legacy GEN_1 libi40iw */
+ if (ucontext->legacy_mode)
+ return -EOPNOTSUPP;
+
+ if (ib_copy_from_udata(&req, udata,
+ min(sizeof(req), udata->inlen)))
+ return -EINVAL;
+
+ spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
+ iwpbl_buf = irdma_get_pbl((unsigned long)req.user_cq_buffer,
+ &ucontext->cq_reg_mem_list);
+ spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
+
+ if (!iwpbl_buf)
+ return -ENOMEM;
+
+ cqmr_buf = &iwpbl_buf->cq_mr;
+ if (iwpbl_buf->pbl_allocated) {
+ info.virtual_map = true;
+ info.pbl_chunk_size = 1;
+ info.first_pm_pbl_idx = cqmr_buf->cq_pbl.idx;
+ } else {
+ info.cq_pa = cqmr_buf->cq_pbl.addr;
+ }
+ } else {
+ /* Kmode CQ resize */
+ int rsize;
+
+ rsize = info.cq_size * sizeof(struct irdma_cqe);
+ kmem_buf.size = ALIGN(round_up(rsize, 256), 256);
+ kmem_buf.va = dma_alloc_coherent(dev->hw->device,
+ kmem_buf.size, &kmem_buf.pa,
+ GFP_KERNEL);
+ if (!kmem_buf.va)
+ return -ENOMEM;
+
+ info.cq_base = kmem_buf.va;
+ info.cq_pa = kmem_buf.pa;
+ cq_buf = kzalloc(sizeof(*cq_buf), GFP_KERNEL);
+ if (!cq_buf) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ }
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
+ if (!cqp_request) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ info.shadow_read_threshold = iwcq->sc_cq.shadow_read_threshold;
+ info.cq_resize = true;
+
+ cqp_info = &cqp_request->info;
+ m_info = &cqp_info->in.u.cq_modify.info;
+ memcpy(m_info, &info, sizeof(*m_info));
+
+ cqp_info->cqp_cmd = IRDMA_OP_CQ_MODIFY;
+ cqp_info->in.u.cq_modify.cq = &iwcq->sc_cq;
+ cqp_info->in.u.cq_modify.scratch = (uintptr_t)cqp_request;
+ cqp_info->post_sq = 1;
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+ if (status) {
+ ret = -EPROTO;
+ goto error;
+ }
+
+ spin_lock_irqsave(&iwcq->lock, flags);
+ if (cq_buf) {
+ cq_buf->kmem_buf = iwcq->kmem;
+ cq_buf->hw = dev->hw;
+ memcpy(&cq_buf->cq_uk, &iwcq->sc_cq.cq_uk, sizeof(cq_buf->cq_uk));
+ INIT_WORK(&cq_buf->work, irdma_free_cqbuf);
+ list_add_tail(&cq_buf->list, &iwcq->resize_list);
+ iwcq->kmem = kmem_buf;
+ }
+
+ irdma_sc_cq_resize(&iwcq->sc_cq, &info);
+ ibcq->cqe = info.cq_size - 1;
+ spin_unlock_irqrestore(&iwcq->lock, flags);
+
+ return 0;
+error:
+ if (!udata) {
+ dma_free_coherent(dev->hw->device, kmem_buf.size, kmem_buf.va,
+ kmem_buf.pa);
+ kmem_buf.va = NULL;
+ }
+ kfree(cq_buf);
+
+ return ret;
+}
+
+static inline int cq_validate_flags(u32 flags, u8 hw_rev)
+{
+ /* GEN1 does not support CQ create flags */
+ if (hw_rev == IRDMA_GEN_1)
+ return flags ? -EOPNOTSUPP : 0;
+
+ return flags & ~IB_UVERBS_CQ_FLAGS_TIMESTAMP_COMPLETION ? -EOPNOTSUPP : 0;
+}
+
+/**
+ * irdma_create_cq - create cq
+ * @ibcq: CQ allocated
+ * @attr: attributes for cq
+ * @udata: user data
+ */
+static int irdma_create_cq(struct ib_cq *ibcq,
+ const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
+{
+ struct ib_device *ibdev = ibcq->device;
+ struct irdma_device *iwdev = to_iwdev(ibdev);
+ struct irdma_pci_f *rf = iwdev->rf;
+ struct irdma_cq *iwcq = to_iwcq(ibcq);
+ u32 cq_num = 0;
+ struct irdma_sc_cq *cq;
+ struct irdma_sc_dev *dev = &rf->sc_dev;
+ struct irdma_cq_init_info info = {};
+ enum irdma_status_code status;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_cq_uk_init_info *ukinfo = &info.cq_uk_init_info;
+ unsigned long flags;
+ int err_code;
+ int entries = attr->cqe;
+
+ err_code = cq_validate_flags(attr->flags, dev->hw_attrs.uk_attrs.hw_rev);
+ if (err_code)
+ return err_code;
+ err_code = irdma_alloc_rsrc(rf, rf->allocated_cqs, rf->max_cq, &cq_num,
+ &rf->next_cq);
+ if (err_code)
+ return err_code;
+
+ cq = &iwcq->sc_cq;
+ cq->back_cq = iwcq;
+ spin_lock_init(&iwcq->lock);
+ INIT_LIST_HEAD(&iwcq->resize_list);
+ info.dev = dev;
+ ukinfo->cq_size = max(entries, 4);
+ ukinfo->cq_id = cq_num;
+ iwcq->ibcq.cqe = info.cq_uk_init_info.cq_size;
+ if (attr->comp_vector < rf->ceqs_count)
+ info.ceq_id = attr->comp_vector;
+ info.ceq_id_valid = true;
+ info.ceqe_mask = 1;
+ info.type = IRDMA_CQ_TYPE_IWARP;
+ info.vsi = &iwdev->vsi;
+
+ if (udata) {
+ struct irdma_ucontext *ucontext;
+ struct irdma_create_cq_req req = {};
+ struct irdma_cq_mr *cqmr;
+ struct irdma_pbl *iwpbl;
+ struct irdma_pbl *iwpbl_shadow;
+ struct irdma_cq_mr *cqmr_shadow;
+
+ iwcq->user_mode = true;
+ ucontext =
+ rdma_udata_to_drv_context(udata, struct irdma_ucontext,
+ ibucontext);
+ if (ib_copy_from_udata(&req, udata,
+ min(sizeof(req), udata->inlen))) {
+ err_code = -EFAULT;
+ goto cq_free_rsrc;
+ }
+
+ spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
+ iwpbl = irdma_get_pbl((unsigned long)req.user_cq_buf,
+ &ucontext->cq_reg_mem_list);
+ spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
+ if (!iwpbl) {
+ err_code = -EPROTO;
+ goto cq_free_rsrc;
+ }
+
+ iwcq->iwpbl = iwpbl;
+ iwcq->cq_mem_size = 0;
+ cqmr = &iwpbl->cq_mr;
+
+ if (rf->sc_dev.hw_attrs.uk_attrs.feature_flags &
+ IRDMA_FEATURE_CQ_RESIZE && !ucontext->legacy_mode) {
+ spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
+ iwpbl_shadow = irdma_get_pbl(
+ (unsigned long)req.user_shadow_area,
+ &ucontext->cq_reg_mem_list);
+ spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
+
+ if (!iwpbl_shadow) {
+ err_code = -EPROTO;
+ goto cq_free_rsrc;
+ }
+ iwcq->iwpbl_shadow = iwpbl_shadow;
+ cqmr_shadow = &iwpbl_shadow->cq_mr;
+ info.shadow_area_pa = cqmr_shadow->cq_pbl.addr;
+ cqmr->split = true;
+ } else {
+ info.shadow_area_pa = cqmr->shadow;
+ }
+ if (iwpbl->pbl_allocated) {
+ info.virtual_map = true;
+ info.pbl_chunk_size = 1;
+ info.first_pm_pbl_idx = cqmr->cq_pbl.idx;
+ } else {
+ info.cq_base_pa = cqmr->cq_pbl.addr;
+ }
+ } else {
+ /* Kmode allocations */
+ int rsize;
+
+ if (entries > rf->max_cqe) {
+ err_code = -EINVAL;
+ goto cq_free_rsrc;
+ }
+
+ entries++;
+ if (dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2)
+ entries *= 2;
+ ukinfo->cq_size = entries;
+
+ rsize = info.cq_uk_init_info.cq_size * sizeof(struct irdma_cqe);
+ iwcq->kmem.size = ALIGN(round_up(rsize, 256), 256);
+ iwcq->kmem.va = dma_alloc_coherent(dev->hw->device,
+ iwcq->kmem.size,
+ &iwcq->kmem.pa, GFP_KERNEL);
+ if (!iwcq->kmem.va) {
+ err_code = -ENOMEM;
+ goto cq_free_rsrc;
+ }
+
+ iwcq->kmem_shadow.size = ALIGN(IRDMA_SHADOW_AREA_SIZE << 3,
+ 64);
+ iwcq->kmem_shadow.va = dma_alloc_coherent(dev->hw->device,
+ iwcq->kmem_shadow.size,
+ &iwcq->kmem_shadow.pa,
+ GFP_KERNEL);
+ if (!iwcq->kmem_shadow.va) {
+ err_code = -ENOMEM;
+ goto cq_free_rsrc;
+ }
+ info.shadow_area_pa = iwcq->kmem_shadow.pa;
+ ukinfo->shadow_area = iwcq->kmem_shadow.va;
+ ukinfo->cq_base = iwcq->kmem.va;
+ info.cq_base_pa = iwcq->kmem.pa;
+ }
+
+ if (dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2)
+ info.shadow_read_threshold = min(info.cq_uk_init_info.cq_size / 2,
+ (u32)IRDMA_MAX_CQ_READ_THRESH);
+
+ if (irdma_sc_cq_init(cq, &info)) {
+ ibdev_dbg(&iwdev->ibdev, "VERBS: init cq fail\n");
+ err_code = -EPROTO;
+ goto cq_free_rsrc;
+ }
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
+ if (!cqp_request) {
+ err_code = -ENOMEM;
+ goto cq_free_rsrc;
+ }
+
+ cqp_info = &cqp_request->info;
+ cqp_info->cqp_cmd = IRDMA_OP_CQ_CREATE;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.cq_create.cq = cq;
+ cqp_info->in.u.cq_create.check_overflow = true;
+ cqp_info->in.u.cq_create.scratch = (uintptr_t)cqp_request;
+ status = irdma_handle_cqp_op(rf, cqp_request);
+ irdma_put_cqp_request(&rf->cqp, cqp_request);
+ if (status) {
+ err_code = -ENOMEM;
+ goto cq_free_rsrc;
+ }
+
+ if (udata) {
+ struct irdma_create_cq_resp resp = {};
+
+ resp.cq_id = info.cq_uk_init_info.cq_id;
+ resp.cq_size = info.cq_uk_init_info.cq_size;
+ if (ib_copy_to_udata(udata, &resp,
+ min(sizeof(resp), udata->outlen))) {
+ ibdev_dbg(&iwdev->ibdev,
+ "VERBS: copy to user data\n");
+ err_code = -EPROTO;
+ goto cq_destroy;
+ }
+ }
+ return 0;
+cq_destroy:
+ irdma_cq_wq_destroy(rf, cq);
+cq_free_rsrc:
+ irdma_cq_free_rsrc(rf, iwcq);
+
+ return err_code;
+}
+
+/**
+ * irdma_get_mr_access - get hw MR access permissions from IB access flags
+ * @access: IB access flags
+ */
+static inline u16 irdma_get_mr_access(int access)
+{
+ u16 hw_access = 0;
+
+ hw_access |= (access & IB_ACCESS_LOCAL_WRITE) ?
+ IRDMA_ACCESS_FLAGS_LOCALWRITE : 0;
+ hw_access |= (access & IB_ACCESS_REMOTE_WRITE) ?
+ IRDMA_ACCESS_FLAGS_REMOTEWRITE : 0;
+ hw_access |= (access & IB_ACCESS_REMOTE_READ) ?
+ IRDMA_ACCESS_FLAGS_REMOTEREAD : 0;
+ hw_access |= (access & IB_ACCESS_MW_BIND) ?
+ IRDMA_ACCESS_FLAGS_BIND_WINDOW : 0;
+ hw_access |= (access & IB_ZERO_BASED) ?
+ IRDMA_ACCESS_FLAGS_ZERO_BASED : 0;
+ hw_access |= IRDMA_ACCESS_FLAGS_LOCALREAD;
+
+ return hw_access;
+}
+
+/**
+ * irdma_free_stag - free stag resource
+ * @iwdev: irdma device
+ * @stag: stag to free
+ */
+static void irdma_free_stag(struct irdma_device *iwdev, u32 stag)
+{
+ u32 stag_idx;
+
+ stag_idx = (stag & iwdev->rf->mr_stagmask) >> IRDMA_CQPSQ_STAG_IDX_S;
+ irdma_free_rsrc(iwdev->rf, iwdev->rf->allocated_mrs, stag_idx);
+}
+
+/**
+ * irdma_create_stag - create random stag
+ * @iwdev: irdma device
+ */
+static u32 irdma_create_stag(struct irdma_device *iwdev)
+{
+ u32 stag = 0;
+ u32 stag_index = 0;
+ u32 next_stag_index;
+ u32 driver_key;
+ u32 random;
+ u8 consumer_key;
+ int ret;
+
+ get_random_bytes(&random, sizeof(random));
+ consumer_key = (u8)random;
+
+ driver_key = random & ~iwdev->rf->mr_stagmask;
+ next_stag_index = (random & iwdev->rf->mr_stagmask) >> 8;
+ next_stag_index %= iwdev->rf->max_mr;
+
+ ret = irdma_alloc_rsrc(iwdev->rf, iwdev->rf->allocated_mrs,
+ iwdev->rf->max_mr, &stag_index,
+ &next_stag_index);
+ if (ret)
+ return stag;
+ stag = stag_index << IRDMA_CQPSQ_STAG_IDX_S;
+ stag |= driver_key;
+ stag += (u32)consumer_key;
+
+ return stag;
+}
+
+/**
+ * irdma_next_pbl_addr - Get next pbl address
+ * @pbl: pointer to a pble
+ * @pinfo: info pointer
+ * @idx: index
+ */
+static inline u64 *irdma_next_pbl_addr(u64 *pbl, struct irdma_pble_info **pinfo,
+ u32 *idx)
+{
+ *idx += 1;
+ if (!(*pinfo) || *idx != (*pinfo)->cnt)
+ return ++pbl;
+ *idx = 0;
+ (*pinfo)++;
+
+ return (*pinfo)->addr;
+}
+
+/**
+ * irdma_copy_user_pgaddrs - copy user page address to pble's os locally
+ * @iwmr: iwmr for IB's user page addresses
+ * @pbl: ple pointer to save 1 level or 0 level pble
+ * @level: indicated level 0, 1 or 2
+ */
+static void irdma_copy_user_pgaddrs(struct irdma_mr *iwmr, u64 *pbl,
+ enum irdma_pble_level level)
+{
+ struct ib_umem *region = iwmr->region;
+ struct irdma_pbl *iwpbl = &iwmr->iwpbl;
+ struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc;
+ struct irdma_pble_info *pinfo;
+ struct ib_block_iter biter;
+ u32 idx = 0;
+ u32 pbl_cnt = 0;
+
+ pinfo = (level == PBLE_LEVEL_1) ? NULL : palloc->level2.leaf;
+
+ if (iwmr->type == IRDMA_MEMREG_TYPE_QP)
+ iwpbl->qp_mr.sq_page = sg_page(region->sg_head.sgl);
+
+ rdma_umem_for_each_dma_block(region, &biter, iwmr->page_size) {
+ *pbl = rdma_block_iter_dma_address(&biter);
+ if (++pbl_cnt == palloc->total_cnt)
+ break;
+ pbl = irdma_next_pbl_addr(pbl, &pinfo, &idx);
+ }
+}
+
+/**
+ * irdma_check_mem_contiguous - check if pbls stored in arr are contiguous
+ * @arr: lvl1 pbl array
+ * @npages: page count
+ * @pg_size: page size
+ *
+ */
+static bool irdma_check_mem_contiguous(u64 *arr, u32 npages, u32 pg_size)
+{
+ u32 pg_idx;
+
+ for (pg_idx = 0; pg_idx < npages; pg_idx++) {
+ if ((*arr + (pg_size * pg_idx)) != arr[pg_idx])
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * irdma_check_mr_contiguous - check if MR is physically contiguous
+ * @palloc: pbl allocation struct
+ * @pg_size: page size
+ */
+static bool irdma_check_mr_contiguous(struct irdma_pble_alloc *palloc,
+ u32 pg_size)
+{
+ struct irdma_pble_level2 *lvl2 = &palloc->level2;
+ struct irdma_pble_info *leaf = lvl2->leaf;
+ u64 *arr = NULL;
+ u64 *start_addr = NULL;
+ int i;
+ bool ret;
+
+ if (palloc->level == PBLE_LEVEL_1) {
+ arr = palloc->level1.addr;
+ ret = irdma_check_mem_contiguous(arr, palloc->total_cnt,
+ pg_size);
+ return ret;
+ }
+
+ start_addr = leaf->addr;
+
+ for (i = 0; i < lvl2->leaf_cnt; i++, leaf++) {
+ arr = leaf->addr;
+ if ((*start_addr + (i * pg_size * PBLE_PER_PAGE)) != *arr)
+ return false;
+ ret = irdma_check_mem_contiguous(arr, leaf->cnt, pg_size);
+ if (!ret)
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * irdma_setup_pbles - copy user pg address to pble's
+ * @rf: RDMA PCI function
+ * @iwmr: mr pointer for this memory registration
+ * @use_pbles: flag if to use pble's
+ */
+static int irdma_setup_pbles(struct irdma_pci_f *rf, struct irdma_mr *iwmr,
+ bool use_pbles)
+{
+ struct irdma_pbl *iwpbl = &iwmr->iwpbl;
+ struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc;
+ struct irdma_pble_info *pinfo;
+ u64 *pbl;
+ enum irdma_status_code status;
+ enum irdma_pble_level level = PBLE_LEVEL_1;
+
+ if (use_pbles) {
+ status = irdma_get_pble(rf->pble_rsrc, palloc, iwmr->page_cnt,
+ false);
+ if (status)
+ return -ENOMEM;
+
+ iwpbl->pbl_allocated = true;
+ level = palloc->level;
+ pinfo = (level == PBLE_LEVEL_1) ? &palloc->level1 :
+ palloc->level2.leaf;
+ pbl = pinfo->addr;
+ } else {
+ pbl = iwmr->pgaddrmem;
+ }
+
+ irdma_copy_user_pgaddrs(iwmr, pbl, level);
+
+ if (use_pbles)
+ iwmr->pgaddrmem[0] = *pbl;
+
+ return 0;
+}
+
+/**
+ * irdma_handle_q_mem - handle memory for qp and cq
+ * @iwdev: irdma device
+ * @req: information for q memory management
+ * @iwpbl: pble struct
+ * @use_pbles: flag to use pble
+ */
+static int irdma_handle_q_mem(struct irdma_device *iwdev,
+ struct irdma_mem_reg_req *req,
+ struct irdma_pbl *iwpbl, bool use_pbles)
+{
+ struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc;
+ struct irdma_mr *iwmr = iwpbl->iwmr;
+ struct irdma_qp_mr *qpmr = &iwpbl->qp_mr;
+ struct irdma_cq_mr *cqmr = &iwpbl->cq_mr;
+ struct irdma_hmc_pble *hmc_p;
+ u64 *arr = iwmr->pgaddrmem;
+ u32 pg_size, total;
+ int err = 0;
+ bool ret = true;
+
+ pg_size = iwmr->page_size;
+ err = irdma_setup_pbles(iwdev->rf, iwmr, use_pbles);
+ if (err)
+ return err;
+
+ if (use_pbles && palloc->level != PBLE_LEVEL_1) {
+ irdma_free_pble(iwdev->rf->pble_rsrc, palloc);
+ iwpbl->pbl_allocated = false;
+ return -ENOMEM;
+ }
+
+ if (use_pbles)
+ arr = palloc->level1.addr;
+
+ switch (iwmr->type) {
+ case IRDMA_MEMREG_TYPE_QP:
+ total = req->sq_pages + req->rq_pages;
+ hmc_p = &qpmr->sq_pbl;
+ qpmr->shadow = (dma_addr_t)arr[total];
+
+ if (use_pbles) {
+ ret = irdma_check_mem_contiguous(arr, req->sq_pages,
+ pg_size);
+ if (ret)
+ ret = irdma_check_mem_contiguous(&arr[req->sq_pages],
+ req->rq_pages,
+ pg_size);
+ }
+
+ if (!ret) {
+ hmc_p->idx = palloc->level1.idx;
+ hmc_p = &qpmr->rq_pbl;
+ hmc_p->idx = palloc->level1.idx + req->sq_pages;
+ } else {
+ hmc_p->addr = arr[0];
+ hmc_p = &qpmr->rq_pbl;
+ hmc_p->addr = arr[req->sq_pages];
+ }
+ break;
+ case IRDMA_MEMREG_TYPE_CQ:
+ hmc_p = &cqmr->cq_pbl;
+
+ if (!cqmr->split)
+ cqmr->shadow = (dma_addr_t)arr[req->cq_pages];
+
+ if (use_pbles)
+ ret = irdma_check_mem_contiguous(arr, req->cq_pages,
+ pg_size);
+
+ if (!ret)
+ hmc_p->idx = palloc->level1.idx;
+ else
+ hmc_p->addr = arr[0];
+ break;
+ default:
+ ibdev_dbg(&iwdev->ibdev, "VERBS: MR type error\n");
+ err = -EINVAL;
+ }
+
+ if (use_pbles && ret) {
+ irdma_free_pble(iwdev->rf->pble_rsrc, palloc);
+ iwpbl->pbl_allocated = false;
+ }
+
+ return err;
+}
+
+/**
+ * irdma_hw_alloc_mw - create the hw memory window
+ * @iwdev: irdma device
+ * @iwmr: pointer to memory window info
+ */
+static int irdma_hw_alloc_mw(struct irdma_device *iwdev, struct irdma_mr *iwmr)
+{
+ struct irdma_mw_alloc_info *info;
+ struct irdma_pd *iwpd = to_iwpd(iwmr->ibmr.pd);
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, true);
+ if (!cqp_request)
+ return -ENOMEM;
+
+ cqp_info = &cqp_request->info;
+ info = &cqp_info->in.u.mw_alloc.info;
+ memset(info, 0, sizeof(*info));
+ if (iwmr->ibmw.type == IB_MW_TYPE_1)
+ info->mw_wide = true;
+
+ info->page_size = PAGE_SIZE;
+ info->mw_stag_index = iwmr->stag >> IRDMA_CQPSQ_STAG_IDX_S;
+ info->pd_id = iwpd->sc_pd.pd_id;
+ info->remote_access = true;
+ cqp_info->cqp_cmd = IRDMA_OP_MW_ALLOC;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.mw_alloc.dev = &iwdev->rf->sc_dev;
+ cqp_info->in.u.mw_alloc.scratch = (uintptr_t)cqp_request;
+ status = irdma_handle_cqp_op(iwdev->rf, cqp_request);
+ irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
+
+ return status ? -ENOMEM : 0;
+}
+
+/**
+ * irdma_alloc_mw - Allocate memory window
+ * @ibmw: Memory Window
+ * @udata: user data pointer
+ */
+static int irdma_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
+{
+ struct irdma_device *iwdev = to_iwdev(ibmw->device);
+ struct irdma_mr *iwmr = to_iwmw(ibmw);
+ int err_code;
+ u32 stag;
+
+ stag = irdma_create_stag(iwdev);
+ if (!stag)
+ return -ENOMEM;
+
+ iwmr->stag = stag;
+ ibmw->rkey = stag;
+
+ err_code = irdma_hw_alloc_mw(iwdev, iwmr);
+ if (err_code) {
+ irdma_free_stag(iwdev, stag);
+ return err_code;
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_dealloc_mw - Dealloc memory window
+ * @ibmw: memory window structure.
+ */
+static int irdma_dealloc_mw(struct ib_mw *ibmw)
+{
+ struct ib_pd *ibpd = ibmw->pd;
+ struct irdma_pd *iwpd = to_iwpd(ibpd);
+ struct irdma_mr *iwmr = to_iwmr((struct ib_mr *)ibmw);
+ struct irdma_device *iwdev = to_iwdev(ibmw->device);
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_dealloc_stag_info *info;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, true);
+ if (!cqp_request)
+ return -ENOMEM;
+
+ cqp_info = &cqp_request->info;
+ info = &cqp_info->in.u.dealloc_stag.info;
+ memset(info, 0, sizeof(*info));
+ info->pd_id = iwpd->sc_pd.pd_id & 0x00007fff;
+ info->stag_idx = ibmw->rkey >> IRDMA_CQPSQ_STAG_IDX_S;
+ info->mr = false;
+ cqp_info->cqp_cmd = IRDMA_OP_DEALLOC_STAG;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.dealloc_stag.dev = &iwdev->rf->sc_dev;
+ cqp_info->in.u.dealloc_stag.scratch = (uintptr_t)cqp_request;
+ irdma_handle_cqp_op(iwdev->rf, cqp_request);
+ irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
+ irdma_free_stag(iwdev, iwmr->stag);
+
+ return 0;
+}
+
+/**
+ * irdma_hw_alloc_stag - cqp command to allocate stag
+ * @iwdev: irdma device
+ * @iwmr: irdma mr pointer
+ */
+static int irdma_hw_alloc_stag(struct irdma_device *iwdev,
+ struct irdma_mr *iwmr)
+{
+ struct irdma_allocate_stag_info *info;
+ struct irdma_pd *iwpd = to_iwpd(iwmr->ibmr.pd);
+ enum irdma_status_code status;
+ int err = 0;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, true);
+ if (!cqp_request)
+ return -ENOMEM;
+
+ cqp_info = &cqp_request->info;
+ info = &cqp_info->in.u.alloc_stag.info;
+ memset(info, 0, sizeof(*info));
+ info->page_size = PAGE_SIZE;
+ info->stag_idx = iwmr->stag >> IRDMA_CQPSQ_STAG_IDX_S;
+ info->pd_id = iwpd->sc_pd.pd_id;
+ info->total_len = iwmr->len;
+ info->remote_access = true;
+ cqp_info->cqp_cmd = IRDMA_OP_ALLOC_STAG;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.alloc_stag.dev = &iwdev->rf->sc_dev;
+ cqp_info->in.u.alloc_stag.scratch = (uintptr_t)cqp_request;
+ status = irdma_handle_cqp_op(iwdev->rf, cqp_request);
+ irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
+ if (status)
+ err = -ENOMEM;
+
+ return err;
+}
+
+/**
+ * irdma_alloc_mr - register stag for fast memory registration
+ * @pd: ibpd pointer
+ * @mr_type: memory for stag registrion
+ * @max_num_sg: man number of pages
+ */
+static struct ib_mr *irdma_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
+ u32 max_num_sg)
+{
+ struct irdma_device *iwdev = to_iwdev(pd->device);
+ struct irdma_pble_alloc *palloc;
+ struct irdma_pbl *iwpbl;
+ struct irdma_mr *iwmr;
+ enum irdma_status_code status;
+ u32 stag;
+ int err_code = -ENOMEM;
+
+ iwmr = kzalloc(sizeof(*iwmr), GFP_KERNEL);
+ if (!iwmr)
+ return ERR_PTR(-ENOMEM);
+
+ stag = irdma_create_stag(iwdev);
+ if (!stag) {
+ err_code = -ENOMEM;
+ goto err;
+ }
+
+ iwmr->stag = stag;
+ iwmr->ibmr.rkey = stag;
+ iwmr->ibmr.lkey = stag;
+ iwmr->ibmr.pd = pd;
+ iwmr->ibmr.device = pd->device;
+ iwpbl = &iwmr->iwpbl;
+ iwpbl->iwmr = iwmr;
+ iwmr->type = IRDMA_MEMREG_TYPE_MEM;
+ palloc = &iwpbl->pble_alloc;
+ iwmr->page_cnt = max_num_sg;
+ status = irdma_get_pble(iwdev->rf->pble_rsrc, palloc, iwmr->page_cnt,
+ true);
+ if (status)
+ goto err_get_pble;
+
+ err_code = irdma_hw_alloc_stag(iwdev, iwmr);
+ if (err_code)
+ goto err_alloc_stag;
+
+ iwpbl->pbl_allocated = true;
+
+ return &iwmr->ibmr;
+err_alloc_stag:
+ irdma_free_pble(iwdev->rf->pble_rsrc, palloc);
+err_get_pble:
+ irdma_free_stag(iwdev, stag);
+err:
+ kfree(iwmr);
+
+ return ERR_PTR(err_code);
+}
+
+/**
+ * irdma_set_page - populate pbl list for fmr
+ * @ibmr: ib mem to access iwarp mr pointer
+ * @addr: page dma address fro pbl list
+ */
+static int irdma_set_page(struct ib_mr *ibmr, u64 addr)
+{
+ struct irdma_mr *iwmr = to_iwmr(ibmr);
+ struct irdma_pbl *iwpbl = &iwmr->iwpbl;
+ struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc;
+ u64 *pbl;
+
+ if (unlikely(iwmr->npages == iwmr->page_cnt))
+ return -ENOMEM;
+
+ pbl = palloc->level1.addr;
+ pbl[iwmr->npages++] = addr;
+
+ return 0;
+}
+
+/**
+ * irdma_map_mr_sg - map of sg list for fmr
+ * @ibmr: ib mem to access iwarp mr pointer
+ * @sg: scatter gather list
+ * @sg_nents: number of sg pages
+ * @sg_offset: scatter gather list for fmr
+ */
+static int irdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
+ int sg_nents, unsigned int *sg_offset)
+{
+ struct irdma_mr *iwmr = to_iwmr(ibmr);
+
+ iwmr->npages = 0;
+
+ return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, irdma_set_page);
+}
+
+/**
+ * irdma_hwreg_mr - send cqp command for memory registration
+ * @iwdev: irdma device
+ * @iwmr: irdma mr pointer
+ * @access: access for MR
+ */
+static int irdma_hwreg_mr(struct irdma_device *iwdev, struct irdma_mr *iwmr,
+ u16 access)
+{
+ struct irdma_pbl *iwpbl = &iwmr->iwpbl;
+ struct irdma_reg_ns_stag_info *stag_info;
+ struct irdma_pd *iwpd = to_iwpd(iwmr->ibmr.pd);
+ struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc;
+ enum irdma_status_code status;
+ int err = 0;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, true);
+ if (!cqp_request)
+ return -ENOMEM;
+
+ cqp_info = &cqp_request->info;
+ stag_info = &cqp_info->in.u.mr_reg_non_shared.info;
+ memset(stag_info, 0, sizeof(*stag_info));
+ stag_info->va = iwpbl->user_base;
+ stag_info->stag_idx = iwmr->stag >> IRDMA_CQPSQ_STAG_IDX_S;
+ stag_info->stag_key = (u8)iwmr->stag;
+ stag_info->total_len = iwmr->len;
+ stag_info->access_rights = irdma_get_mr_access(access);
+ stag_info->pd_id = iwpd->sc_pd.pd_id;
+ if (stag_info->access_rights & IRDMA_ACCESS_FLAGS_ZERO_BASED)
+ stag_info->addr_type = IRDMA_ADDR_TYPE_ZERO_BASED;
+ else
+ stag_info->addr_type = IRDMA_ADDR_TYPE_VA_BASED;
+ stag_info->page_size = iwmr->page_size;
+
+ if (iwpbl->pbl_allocated) {
+ if (palloc->level == PBLE_LEVEL_1) {
+ stag_info->first_pm_pbl_index = palloc->level1.idx;
+ stag_info->chunk_size = 1;
+ } else {
+ stag_info->first_pm_pbl_index = palloc->level2.root.idx;
+ stag_info->chunk_size = 3;
+ }
+ } else {
+ stag_info->reg_addr_pa = iwmr->pgaddrmem[0];
+ }
+
+ cqp_info->cqp_cmd = IRDMA_OP_MR_REG_NON_SHARED;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.mr_reg_non_shared.dev = &iwdev->rf->sc_dev;
+ cqp_info->in.u.mr_reg_non_shared.scratch = (uintptr_t)cqp_request;
+ status = irdma_handle_cqp_op(iwdev->rf, cqp_request);
+ irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
+ if (status)
+ err = -ENOMEM;
+
+ return err;
+}
+
+/**
+ * irdma_reg_user_mr - Register a user memory region
+ * @pd: ptr of pd
+ * @start: virtual start address
+ * @len: length of mr
+ * @virt: virtual address
+ * @access: access of mr
+ * @udata: user data
+ */
+static struct ib_mr *irdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
+ u64 virt, int access,
+ struct ib_udata *udata)
+{
+ struct irdma_device *iwdev = to_iwdev(pd->device);
+ struct irdma_ucontext *ucontext;
+ struct irdma_pble_alloc *palloc;
+ struct irdma_pbl *iwpbl;
+ struct irdma_mr *iwmr;
+ struct ib_umem *region;
+ struct irdma_mem_reg_req req;
+ u32 total, stag = 0;
+ u8 shadow_pgcnt = 1;
+ bool use_pbles = false;
+ unsigned long flags;
+ int err = -EINVAL;
+ int ret;
+
+ if (len > iwdev->rf->sc_dev.hw_attrs.max_mr_size)
+ return ERR_PTR(-EINVAL);
+
+ region = ib_umem_get(pd->device, start, len, access);
+
+ if (IS_ERR(region)) {
+ ibdev_dbg(&iwdev->ibdev,
+ "VERBS: Failed to create ib_umem region\n");
+ return (struct ib_mr *)region;
+ }
+
+ if (ib_copy_from_udata(&req, udata, min(sizeof(req), udata->inlen))) {
+ ib_umem_release(region);
+ return ERR_PTR(-EFAULT);
+ }
+
+ iwmr = kzalloc(sizeof(*iwmr), GFP_KERNEL);
+ if (!iwmr) {
+ ib_umem_release(region);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ iwpbl = &iwmr->iwpbl;
+ iwpbl->iwmr = iwmr;
+ iwmr->region = region;
+ iwmr->ibmr.pd = pd;
+ iwmr->ibmr.device = pd->device;
+ iwmr->ibmr.iova = virt;
+ iwmr->page_size = PAGE_SIZE;
+
+ if (req.reg_type == IRDMA_MEMREG_TYPE_MEM) {
+ iwmr->page_size = ib_umem_find_best_pgsz(region,
+ SZ_4K | SZ_2M | SZ_1G,
+ virt);
+ if (unlikely(!iwmr->page_size)) {
+ kfree(iwmr);
+ ib_umem_release(region);
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+ }
+ iwmr->len = region->length;
+ iwpbl->user_base = virt;
+ palloc = &iwpbl->pble_alloc;
+ iwmr->type = req.reg_type;
+ iwmr->page_cnt = ib_umem_num_dma_blocks(region, iwmr->page_size);
+
+ switch (req.reg_type) {
+ case IRDMA_MEMREG_TYPE_QP:
+ total = req.sq_pages + req.rq_pages + shadow_pgcnt;
+ if (total > iwmr->page_cnt) {
+ err = -EINVAL;
+ goto error;
+ }
+ total = req.sq_pages + req.rq_pages;
+ use_pbles = (total > 2);
+ err = irdma_handle_q_mem(iwdev, &req, iwpbl, use_pbles);
+ if (err)
+ goto error;
+
+ ucontext = rdma_udata_to_drv_context(udata, struct irdma_ucontext,
+ ibucontext);
+ spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
+ list_add_tail(&iwpbl->list, &ucontext->qp_reg_mem_list);
+ iwpbl->on_list = true;
+ spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
+ break;
+ case IRDMA_MEMREG_TYPE_CQ:
+ if (iwdev->rf->sc_dev.hw_attrs.uk_attrs.feature_flags & IRDMA_FEATURE_CQ_RESIZE)
+ shadow_pgcnt = 0;
+ total = req.cq_pages + shadow_pgcnt;
+ if (total > iwmr->page_cnt) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ use_pbles = (req.cq_pages > 1);
+ err = irdma_handle_q_mem(iwdev, &req, iwpbl, use_pbles);
+ if (err)
+ goto error;
+
+ ucontext = rdma_udata_to_drv_context(udata, struct irdma_ucontext,
+ ibucontext);
+ spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
+ list_add_tail(&iwpbl->list, &ucontext->cq_reg_mem_list);
+ iwpbl->on_list = true;
+ spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
+ break;
+ case IRDMA_MEMREG_TYPE_MEM:
+ use_pbles = (iwmr->page_cnt != 1);
+
+ err = irdma_setup_pbles(iwdev->rf, iwmr, use_pbles);
+ if (err)
+ goto error;
+
+ if (use_pbles) {
+ ret = irdma_check_mr_contiguous(palloc,
+ iwmr->page_size);
+ if (ret) {
+ irdma_free_pble(iwdev->rf->pble_rsrc, palloc);
+ iwpbl->pbl_allocated = false;
+ }
+ }
+
+ stag = irdma_create_stag(iwdev);
+ if (!stag) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ iwmr->stag = stag;
+ iwmr->ibmr.rkey = stag;
+ iwmr->ibmr.lkey = stag;
+ err = irdma_hwreg_mr(iwdev, iwmr, access);
+ if (err) {
+ irdma_free_stag(iwdev, stag);
+ goto error;
+ }
+
+ break;
+ default:
+ goto error;
+ }
+
+ iwmr->type = req.reg_type;
+
+ return &iwmr->ibmr;
+
+error:
+ if (palloc->level != PBLE_LEVEL_0 && iwpbl->pbl_allocated)
+ irdma_free_pble(iwdev->rf->pble_rsrc, palloc);
+ ib_umem_release(region);
+ kfree(iwmr);
+
+ return ERR_PTR(err);
+}
+
+/**
+ * irdma_reg_phys_mr - register kernel physical memory
+ * @pd: ibpd pointer
+ * @addr: physical address of memory to register
+ * @size: size of memory to register
+ * @access: Access rights
+ * @iova_start: start of virtual address for physical buffers
+ */
+struct ib_mr *irdma_reg_phys_mr(struct ib_pd *pd, u64 addr, u64 size, int access,
+ u64 *iova_start)
+{
+ struct irdma_device *iwdev = to_iwdev(pd->device);
+ struct irdma_pbl *iwpbl;
+ struct irdma_mr *iwmr;
+ enum irdma_status_code status;
+ u32 stag;
+ int ret;
+
+ iwmr = kzalloc(sizeof(*iwmr), GFP_KERNEL);
+ if (!iwmr)
+ return ERR_PTR(-ENOMEM);
+
+ iwmr->ibmr.pd = pd;
+ iwmr->ibmr.device = pd->device;
+ iwpbl = &iwmr->iwpbl;
+ iwpbl->iwmr = iwmr;
+ iwmr->type = IRDMA_MEMREG_TYPE_MEM;
+ iwpbl->user_base = *iova_start;
+ stag = irdma_create_stag(iwdev);
+ if (!stag) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ iwmr->stag = stag;
+ iwmr->ibmr.iova = *iova_start;
+ iwmr->ibmr.rkey = stag;
+ iwmr->ibmr.lkey = stag;
+ iwmr->page_cnt = 1;
+ iwmr->pgaddrmem[0] = addr;
+ iwmr->len = size;
+ iwmr->page_size = SZ_4K;
+ status = irdma_hwreg_mr(iwdev, iwmr, access);
+ if (status) {
+ irdma_free_stag(iwdev, stag);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ return &iwmr->ibmr;
+
+err:
+ kfree(iwmr);
+
+ return ERR_PTR(ret);
+}
+
+/**
+ * irdma_get_dma_mr - register physical mem
+ * @pd: ptr of pd
+ * @acc: access for memory
+ */
+static struct ib_mr *irdma_get_dma_mr(struct ib_pd *pd, int acc)
+{
+ u64 kva = 0;
+
+ return irdma_reg_phys_mr(pd, 0, 0, acc, &kva);
+}
+
+/**
+ * irdma_del_memlist - Deleting pbl list entries for CQ/QP
+ * @iwmr: iwmr for IB's user page addresses
+ * @ucontext: ptr to user context
+ */
+static void irdma_del_memlist(struct irdma_mr *iwmr,
+ struct irdma_ucontext *ucontext)
+{
+ struct irdma_pbl *iwpbl = &iwmr->iwpbl;
+ unsigned long flags;
+
+ switch (iwmr->type) {
+ case IRDMA_MEMREG_TYPE_CQ:
+ spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
+ if (iwpbl->on_list) {
+ iwpbl->on_list = false;
+ list_del(&iwpbl->list);
+ }
+ spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
+ break;
+ case IRDMA_MEMREG_TYPE_QP:
+ spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
+ if (iwpbl->on_list) {
+ iwpbl->on_list = false;
+ list_del(&iwpbl->list);
+ }
+ spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * irdma_dereg_mr - deregister mr
+ * @ib_mr: mr ptr for dereg
+ * @udata: user data
+ */
+static int irdma_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
+{
+ struct ib_pd *ibpd = ib_mr->pd;
+ struct irdma_pd *iwpd = to_iwpd(ibpd);
+ struct irdma_mr *iwmr = to_iwmr(ib_mr);
+ struct irdma_device *iwdev = to_iwdev(ib_mr->device);
+ struct irdma_dealloc_stag_info *info;
+ struct irdma_pbl *iwpbl = &iwmr->iwpbl;
+ struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc;
+ struct irdma_cqp_request *cqp_request;
+ struct cqp_cmds_info *cqp_info;
+
+ if (iwmr->type != IRDMA_MEMREG_TYPE_MEM) {
+ if (iwmr->region) {
+ struct irdma_ucontext *ucontext;
+
+ ucontext = rdma_udata_to_drv_context(udata,
+ struct irdma_ucontext,
+ ibucontext);
+ irdma_del_memlist(iwmr, ucontext);
+ }
+ goto done;
+ }
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, true);
+ if (!cqp_request)
+ return -ENOMEM;
+
+ cqp_info = &cqp_request->info;
+ info = &cqp_info->in.u.dealloc_stag.info;
+ memset(info, 0, sizeof(*info));
+ info->pd_id = iwpd->sc_pd.pd_id & 0x00007fff;
+ info->stag_idx = ib_mr->rkey >> IRDMA_CQPSQ_STAG_IDX_S;
+ info->mr = true;
+ if (iwpbl->pbl_allocated)
+ info->dealloc_pbl = true;
+
+ cqp_info->cqp_cmd = IRDMA_OP_DEALLOC_STAG;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.dealloc_stag.dev = &iwdev->rf->sc_dev;
+ cqp_info->in.u.dealloc_stag.scratch = (uintptr_t)cqp_request;
+ irdma_handle_cqp_op(iwdev->rf, cqp_request);
+ irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
+ irdma_free_stag(iwdev, iwmr->stag);
+done:
+ if (iwpbl->pbl_allocated)
+ irdma_free_pble(iwdev->rf->pble_rsrc, palloc);
+ ib_umem_release(iwmr->region);
+ kfree(iwmr);
+
+ return 0;
+}
+
+/**
+ * irdma_copy_sg_list - copy sg list for qp
+ * @sg_list: copied into sg_list
+ * @sgl: copy from sgl
+ * @num_sges: count of sg entries
+ */
+static void irdma_copy_sg_list(struct irdma_sge *sg_list, struct ib_sge *sgl,
+ int num_sges)
+{
+ unsigned int i;
+
+ for (i = 0; (i < num_sges) && (i < IRDMA_MAX_WQ_FRAGMENT_COUNT); i++) {
+ sg_list[i].tag_off = sgl[i].addr;
+ sg_list[i].len = sgl[i].length;
+ sg_list[i].stag = sgl[i].lkey;
+ }
+}
+
+/**
+ * irdma_post_send - kernel application wr
+ * @ibqp: qp ptr for wr
+ * @ib_wr: work request ptr
+ * @bad_wr: return of bad wr if err
+ */
+static int irdma_post_send(struct ib_qp *ibqp,
+ const struct ib_send_wr *ib_wr,
+ const struct ib_send_wr **bad_wr)
+{
+ struct irdma_qp *iwqp;
+ struct irdma_qp_uk *ukqp;
+ struct irdma_sc_dev *dev;
+ struct irdma_post_sq_info info;
+ enum irdma_status_code ret;
+ int err = 0;
+ unsigned long flags;
+ bool inv_stag;
+ struct irdma_ah *ah;
+ bool reflush = false;
+
+ iwqp = to_iwqp(ibqp);
+ ukqp = &iwqp->sc_qp.qp_uk;
+ dev = &iwqp->iwdev->rf->sc_dev;
+
+ spin_lock_irqsave(&iwqp->lock, flags);
+ if (iwqp->flush_issued && ukqp->sq_flush_complete)
+ reflush = true;
+ while (ib_wr) {
+ memset(&info, 0, sizeof(info));
+ inv_stag = false;
+ info.wr_id = (ib_wr->wr_id);
+ if ((ib_wr->send_flags & IB_SEND_SIGNALED) || iwqp->sig_all)
+ info.signaled = true;
+ if (ib_wr->send_flags & IB_SEND_FENCE)
+ info.read_fence = true;
+ switch (ib_wr->opcode) {
+ case IB_WR_SEND_WITH_IMM:
+ if (ukqp->qp_caps & IRDMA_SEND_WITH_IMM) {
+ info.imm_data_valid = true;
+ info.imm_data = ntohl(ib_wr->ex.imm_data);
+ } else {
+ err = -EINVAL;
+ break;
+ }
+ fallthrough;
+ case IB_WR_SEND:
+ case IB_WR_SEND_WITH_INV:
+ if (ib_wr->opcode == IB_WR_SEND ||
+ ib_wr->opcode == IB_WR_SEND_WITH_IMM) {
+ if (ib_wr->send_flags & IB_SEND_SOLICITED)
+ info.op_type = IRDMA_OP_TYPE_SEND_SOL;
+ else
+ info.op_type = IRDMA_OP_TYPE_SEND;
+ } else {
+ if (ib_wr->send_flags & IB_SEND_SOLICITED)
+ info.op_type = IRDMA_OP_TYPE_SEND_SOL_INV;
+ else
+ info.op_type = IRDMA_OP_TYPE_SEND_INV;
+ info.stag_to_inv = ib_wr->ex.invalidate_rkey;
+ }
+
+ if (ib_wr->send_flags & IB_SEND_INLINE) {
+ info.op.inline_send.data = (void *)(unsigned long)
+ ib_wr->sg_list[0].addr;
+ info.op.inline_send.len = ib_wr->sg_list[0].length;
+ if (iwqp->ibqp.qp_type == IB_QPT_UD ||
+ iwqp->ibqp.qp_type == IB_QPT_GSI) {
+ ah = to_iwah(ud_wr(ib_wr)->ah);
+ info.op.inline_send.ah_id = ah->sc_ah.ah_info.ah_idx;
+ info.op.inline_send.qkey = ud_wr(ib_wr)->remote_qkey;
+ info.op.inline_send.dest_qp = ud_wr(ib_wr)->remote_qpn;
+ }
+ ret = irdma_uk_inline_send(ukqp, &info, false);
+ } else {
+ info.op.send.num_sges = ib_wr->num_sge;
+ info.op.send.sg_list = (struct irdma_sge *)
+ ib_wr->sg_list;
+ if (iwqp->ibqp.qp_type == IB_QPT_UD ||
+ iwqp->ibqp.qp_type == IB_QPT_GSI) {
+ ah = to_iwah(ud_wr(ib_wr)->ah);
+ info.op.send.ah_id = ah->sc_ah.ah_info.ah_idx;
+ info.op.send.qkey = ud_wr(ib_wr)->remote_qkey;
+ info.op.send.dest_qp = ud_wr(ib_wr)->remote_qpn;
+ }
+ ret = irdma_uk_send(ukqp, &info, false);
+ }
+
+ if (ret) {
+ if (ret == IRDMA_ERR_QP_TOOMANY_WRS_POSTED)
+ err = -ENOMEM;
+ else
+ err = -EINVAL;
+ }
+ break;
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ if (ukqp->qp_caps & IRDMA_WRITE_WITH_IMM) {
+ info.imm_data_valid = true;
+ info.imm_data = ntohl(ib_wr->ex.imm_data);
+ } else {
+ err = -EINVAL;
+ break;
+ }
+ fallthrough;
+ case IB_WR_RDMA_WRITE:
+ if (ib_wr->send_flags & IB_SEND_SOLICITED)
+ info.op_type = IRDMA_OP_TYPE_RDMA_WRITE_SOL;
+ else
+ info.op_type = IRDMA_OP_TYPE_RDMA_WRITE;
+
+ if (ib_wr->send_flags & IB_SEND_INLINE) {
+ info.op.inline_rdma_write.data = (void *)(uintptr_t)ib_wr->sg_list[0].addr;
+ info.op.inline_rdma_write.len = ib_wr->sg_list[0].length;
+ info.op.inline_rdma_write.rem_addr.tag_off = rdma_wr(ib_wr)->remote_addr;
+ info.op.inline_rdma_write.rem_addr.stag = rdma_wr(ib_wr)->rkey;
+ ret = irdma_uk_inline_rdma_write(ukqp, &info, false);
+ } else {
+ info.op.rdma_write.lo_sg_list = (void *)ib_wr->sg_list;
+ info.op.rdma_write.num_lo_sges = ib_wr->num_sge;
+ info.op.rdma_write.rem_addr.tag_off = rdma_wr(ib_wr)->remote_addr;
+ info.op.rdma_write.rem_addr.stag = rdma_wr(ib_wr)->rkey;
+ ret = irdma_uk_rdma_write(ukqp, &info, false);
+ }
+
+ if (ret) {
+ if (ret == IRDMA_ERR_QP_TOOMANY_WRS_POSTED)
+ err = -ENOMEM;
+ else
+ err = -EINVAL;
+ }
+ break;
+ case IB_WR_RDMA_READ_WITH_INV:
+ inv_stag = true;
+ fallthrough;
+ case IB_WR_RDMA_READ:
+ if (ib_wr->num_sge >
+ dev->hw_attrs.uk_attrs.max_hw_read_sges) {
+ err = -EINVAL;
+ break;
+ }
+ info.op_type = IRDMA_OP_TYPE_RDMA_READ;
+ info.op.rdma_read.rem_addr.tag_off = rdma_wr(ib_wr)->remote_addr;
+ info.op.rdma_read.rem_addr.stag = rdma_wr(ib_wr)->rkey;
+ info.op.rdma_read.lo_sg_list = (void *)ib_wr->sg_list;
+ info.op.rdma_read.num_lo_sges = ib_wr->num_sge;
+
+ ret = irdma_uk_rdma_read(ukqp, &info, inv_stag, false);
+ if (ret) {
+ if (ret == IRDMA_ERR_QP_TOOMANY_WRS_POSTED)
+ err = -ENOMEM;
+ else
+ err = -EINVAL;
+ }
+ break;
+ case IB_WR_LOCAL_INV:
+ info.op_type = IRDMA_OP_TYPE_INV_STAG;
+ info.op.inv_local_stag.target_stag = ib_wr->ex.invalidate_rkey;
+ ret = irdma_uk_stag_local_invalidate(ukqp, &info, true);
+ if (ret)
+ err = -ENOMEM;
+ break;
+ case IB_WR_REG_MR: {
+ struct irdma_mr *iwmr = to_iwmr(reg_wr(ib_wr)->mr);
+ struct irdma_pble_alloc *palloc = &iwmr->iwpbl.pble_alloc;
+ struct irdma_fast_reg_stag_info stag_info = {};
+
+ stag_info.signaled = info.signaled;
+ stag_info.read_fence = info.read_fence;
+ stag_info.access_rights = irdma_get_mr_access(reg_wr(ib_wr)->access);
+ stag_info.stag_key = reg_wr(ib_wr)->key & 0xff;
+ stag_info.stag_idx = reg_wr(ib_wr)->key >> 8;
+ stag_info.page_size = reg_wr(ib_wr)->mr->page_size;
+ stag_info.wr_id = ib_wr->wr_id;
+ stag_info.addr_type = IRDMA_ADDR_TYPE_VA_BASED;
+ stag_info.va = (void *)(uintptr_t)iwmr->ibmr.iova;
+ stag_info.total_len = iwmr->ibmr.length;
+ stag_info.reg_addr_pa = *palloc->level1.addr;
+ stag_info.first_pm_pbl_index = palloc->level1.idx;
+ stag_info.local_fence = ib_wr->send_flags & IB_SEND_FENCE;
+ if (iwmr->npages > IRDMA_MIN_PAGES_PER_FMR)
+ stag_info.chunk_size = 1;
+ ret = irdma_sc_mr_fast_register(&iwqp->sc_qp, &stag_info,
+ true);
+ if (ret)
+ err = -ENOMEM;
+ break;
+ }
+ default:
+ err = -EINVAL;
+ ibdev_dbg(&iwqp->iwdev->ibdev,
+ "VERBS: upost_send bad opcode = 0x%x\n",
+ ib_wr->opcode);
+ break;
+ }
+
+ if (err)
+ break;
+ ib_wr = ib_wr->next;
+ }
+
+ if (!iwqp->flush_issued && iwqp->hw_iwarp_state <= IRDMA_QP_STATE_RTS) {
+ irdma_uk_qp_post_wr(ukqp);
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ } else if (reflush) {
+ ukqp->sq_flush_complete = false;
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ irdma_flush_wqes(iwqp, IRDMA_FLUSH_SQ | IRDMA_REFLUSH);
+ } else {
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ }
+ if (err)
+ *bad_wr = ib_wr;
+
+ return err;
+}
+
+/**
+ * irdma_post_recv - post receive wr for kernel application
+ * @ibqp: ib qp pointer
+ * @ib_wr: work request for receive
+ * @bad_wr: bad wr caused an error
+ */
+static int irdma_post_recv(struct ib_qp *ibqp,
+ const struct ib_recv_wr *ib_wr,
+ const struct ib_recv_wr **bad_wr)
+{
+ struct irdma_qp *iwqp;
+ struct irdma_qp_uk *ukqp;
+ struct irdma_post_rq_info post_recv = {};
+ struct irdma_sge sg_list[IRDMA_MAX_WQ_FRAGMENT_COUNT];
+ enum irdma_status_code ret = 0;
+ unsigned long flags;
+ int err = 0;
+ bool reflush = false;
+
+ iwqp = to_iwqp(ibqp);
+ ukqp = &iwqp->sc_qp.qp_uk;
+
+ spin_lock_irqsave(&iwqp->lock, flags);
+ if (iwqp->flush_issued && ukqp->rq_flush_complete)
+ reflush = true;
+ while (ib_wr) {
+ post_recv.num_sges = ib_wr->num_sge;
+ post_recv.wr_id = ib_wr->wr_id;
+ irdma_copy_sg_list(sg_list, ib_wr->sg_list, ib_wr->num_sge);
+ post_recv.sg_list = sg_list;
+ ret = irdma_uk_post_receive(ukqp, &post_recv);
+ if (ret) {
+ ibdev_dbg(&iwqp->iwdev->ibdev,
+ "VERBS: post_recv err %d\n", ret);
+ if (ret == IRDMA_ERR_QP_TOOMANY_WRS_POSTED)
+ err = -ENOMEM;
+ else
+ err = -EINVAL;
+ goto out;
+ }
+
+ ib_wr = ib_wr->next;
+ }
+
+out:
+ if (reflush) {
+ ukqp->rq_flush_complete = false;
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ irdma_flush_wqes(iwqp, IRDMA_FLUSH_RQ | IRDMA_REFLUSH);
+ } else {
+ spin_unlock_irqrestore(&iwqp->lock, flags);
+ }
+
+ if (err)
+ *bad_wr = ib_wr;
+
+ return err;
+}
+
+/**
+ * irdma_flush_err_to_ib_wc_status - return change flush error code to IB status
+ * @opcode: iwarp flush code
+ */
+static enum ib_wc_status irdma_flush_err_to_ib_wc_status(enum irdma_flush_opcode opcode)
+{
+ switch (opcode) {
+ case FLUSH_PROT_ERR:
+ return IB_WC_LOC_PROT_ERR;
+ case FLUSH_REM_ACCESS_ERR:
+ return IB_WC_REM_ACCESS_ERR;
+ case FLUSH_LOC_QP_OP_ERR:
+ return IB_WC_LOC_QP_OP_ERR;
+ case FLUSH_REM_OP_ERR:
+ return IB_WC_REM_OP_ERR;
+ case FLUSH_LOC_LEN_ERR:
+ return IB_WC_LOC_LEN_ERR;
+ case FLUSH_GENERAL_ERR:
+ return IB_WC_WR_FLUSH_ERR;
+ case FLUSH_FATAL_ERR:
+ default:
+ return IB_WC_FATAL_ERR;
+ }
+}
+
+/**
+ * irdma_process_cqe - process cqe info
+ * @entry: processed cqe
+ * @cq_poll_info: cqe info
+ */
+static void irdma_process_cqe(struct ib_wc *entry,
+ struct irdma_cq_poll_info *cq_poll_info)
+{
+ struct irdma_qp *iwqp;
+ struct irdma_sc_qp *qp;
+
+ entry->wc_flags = 0;
+ entry->pkey_index = 0;
+ entry->wr_id = cq_poll_info->wr_id;
+
+ qp = cq_poll_info->qp_handle;
+ iwqp = qp->qp_uk.back_qp;
+ entry->qp = qp->qp_uk.back_qp;
+
+ if (cq_poll_info->error) {
+ entry->status = (cq_poll_info->comp_status == IRDMA_COMPL_STATUS_FLUSHED) ?
+ irdma_flush_err_to_ib_wc_status(cq_poll_info->minor_err) : IB_WC_GENERAL_ERR;
+
+ entry->vendor_err = cq_poll_info->major_err << 16 |
+ cq_poll_info->minor_err;
+ } else {
+ entry->status = IB_WC_SUCCESS;
+ if (cq_poll_info->imm_valid) {
+ entry->ex.imm_data = htonl(cq_poll_info->imm_data);
+ entry->wc_flags |= IB_WC_WITH_IMM;
+ }
+ if (cq_poll_info->ud_smac_valid) {
+ ether_addr_copy(entry->smac, cq_poll_info->ud_smac);
+ entry->wc_flags |= IB_WC_WITH_SMAC;
+ }
+
+ if (cq_poll_info->ud_vlan_valid) {
+ entry->vlan_id = cq_poll_info->ud_vlan & VLAN_VID_MASK;
+ entry->wc_flags |= IB_WC_WITH_VLAN;
+ entry->sl = cq_poll_info->ud_vlan >> VLAN_PRIO_SHIFT;
+ } else {
+ entry->sl = 0;
+ }
+ }
+
+ switch (cq_poll_info->op_type) {
+ case IRDMA_OP_TYPE_RDMA_WRITE:
+ case IRDMA_OP_TYPE_RDMA_WRITE_SOL:
+ entry->opcode = IB_WC_RDMA_WRITE;
+ break;
+ case IRDMA_OP_TYPE_RDMA_READ_INV_STAG:
+ case IRDMA_OP_TYPE_RDMA_READ:
+ entry->opcode = IB_WC_RDMA_READ;
+ break;
+ case IRDMA_OP_TYPE_SEND_INV:
+ case IRDMA_OP_TYPE_SEND_SOL:
+ case IRDMA_OP_TYPE_SEND_SOL_INV:
+ case IRDMA_OP_TYPE_SEND:
+ entry->opcode = IB_WC_SEND;
+ break;
+ case IRDMA_OP_TYPE_FAST_REG_NSMR:
+ entry->opcode = IB_WC_REG_MR;
+ break;
+ case IRDMA_OP_TYPE_INV_STAG:
+ entry->opcode = IB_WC_LOCAL_INV;
+ break;
+ case IRDMA_OP_TYPE_REC_IMM:
+ case IRDMA_OP_TYPE_REC:
+ entry->opcode = cq_poll_info->op_type == IRDMA_OP_TYPE_REC_IMM ?
+ IB_WC_RECV_RDMA_WITH_IMM : IB_WC_RECV;
+ if (qp->qp_uk.qp_type != IRDMA_QP_TYPE_ROCE_UD &&
+ cq_poll_info->stag_invalid_set) {
+ entry->ex.invalidate_rkey = cq_poll_info->inv_stag;
+ entry->wc_flags |= IB_WC_WITH_INVALIDATE;
+ }
+ break;
+ default:
+ ibdev_err(&iwqp->iwdev->ibdev,
+ "Invalid opcode = %d in CQE\n", cq_poll_info->op_type);
+ entry->status = IB_WC_GENERAL_ERR;
+ return;
+ }
+
+ if (qp->qp_uk.qp_type == IRDMA_QP_TYPE_ROCE_UD) {
+ entry->src_qp = cq_poll_info->ud_src_qpn;
+ entry->slid = 0;
+ entry->wc_flags |=
+ (IB_WC_GRH | IB_WC_WITH_NETWORK_HDR_TYPE);
+ entry->network_hdr_type = cq_poll_info->ipv4 ?
+ RDMA_NETWORK_IPV4 :
+ RDMA_NETWORK_IPV6;
+ } else {
+ entry->src_qp = cq_poll_info->qp_id;
+ }
+
+ entry->byte_len = cq_poll_info->bytes_xfered;
+}
+
+/**
+ * irdma_poll_one - poll one entry of the CQ
+ * @ukcq: ukcq to poll
+ * @cur_cqe: current CQE info to be filled in
+ * @entry: ibv_wc object to be filled for non-extended CQ or NULL for extended CQ
+ *
+ * Returns the internal irdma device error code or 0 on success
+ */
+static inline int irdma_poll_one(struct irdma_cq_uk *ukcq,
+ struct irdma_cq_poll_info *cur_cqe,
+ struct ib_wc *entry)
+{
+ int ret = irdma_uk_cq_poll_cmpl(ukcq, cur_cqe);
+
+ if (ret)
+ return ret;
+
+ irdma_process_cqe(entry, cur_cqe);
+
+ return 0;
+}
+
+/**
+ * __irdma_poll_cq - poll cq for completion (kernel apps)
+ * @iwcq: cq to poll
+ * @num_entries: number of entries to poll
+ * @entry: wr of a completed entry
+ */
+static int __irdma_poll_cq(struct irdma_cq *iwcq, int num_entries, struct ib_wc *entry)
+{
+ struct list_head *tmp_node, *list_node;
+ struct irdma_cq_buf *last_buf = NULL;
+ struct irdma_cq_poll_info *cur_cqe = &iwcq->cur_cqe;
+ struct irdma_cq_buf *cq_buf;
+ enum irdma_status_code ret;
+ struct irdma_device *iwdev;
+ struct irdma_cq_uk *ukcq;
+ bool cq_new_cqe = false;
+ int resized_bufs = 0;
+ int npolled = 0;
+
+ iwdev = to_iwdev(iwcq->ibcq.device);
+ ukcq = &iwcq->sc_cq.cq_uk;
+
+ /* go through the list of previously resized CQ buffers */
+ list_for_each_safe(list_node, tmp_node, &iwcq->resize_list) {
+ cq_buf = container_of(list_node, struct irdma_cq_buf, list);
+ while (npolled < num_entries) {
+ ret = irdma_poll_one(&cq_buf->cq_uk, cur_cqe, entry + npolled);
+ if (!ret) {
+ ++npolled;
+ cq_new_cqe = true;
+ continue;
+ }
+ if (ret == IRDMA_ERR_Q_EMPTY)
+ break;
+ /* QP using the CQ is destroyed. Skip reporting this CQE */
+ if (ret == IRDMA_ERR_Q_DESTROYED) {
+ cq_new_cqe = true;
+ continue;
+ }
+ goto error;
+ }
+
+ /* save the resized CQ buffer which received the last cqe */
+ if (cq_new_cqe)
+ last_buf = cq_buf;
+ cq_new_cqe = false;
+ }
+
+ /* check the current CQ for new cqes */
+ while (npolled < num_entries) {
+ ret = irdma_poll_one(ukcq, cur_cqe, entry + npolled);
+ if (!ret) {
+ ++npolled;
+ cq_new_cqe = true;
+ continue;
+ }
+
+ if (ret == IRDMA_ERR_Q_EMPTY)
+ break;
+ /* QP using the CQ is destroyed. Skip reporting this CQE */
+ if (ret == IRDMA_ERR_Q_DESTROYED) {
+ cq_new_cqe = true;
+ continue;
+ }
+ goto error;
+ }
+
+ if (cq_new_cqe)
+ /* all previous CQ resizes are complete */
+ resized_bufs = irdma_process_resize_list(iwcq, iwdev, NULL);
+ else if (last_buf)
+ /* only CQ resizes up to the last_buf are complete */
+ resized_bufs = irdma_process_resize_list(iwcq, iwdev, last_buf);
+ if (resized_bufs)
+ /* report to the HW the number of complete CQ resizes */
+ irdma_uk_cq_set_resized_cnt(ukcq, resized_bufs);
+
+ return npolled;
+error:
+ ibdev_dbg(&iwdev->ibdev, "%s: Error polling CQ, irdma_err: %d\n",
+ __func__, ret);
+
+ return -EINVAL;
+}
+
+/**
+ * irdma_poll_cq - poll cq for completion (kernel apps)
+ * @ibcq: cq to poll
+ * @num_entries: number of entries to poll
+ * @entry: wr of a completed entry
+ */
+static int irdma_poll_cq(struct ib_cq *ibcq, int num_entries,
+ struct ib_wc *entry)
+{
+ struct irdma_cq *iwcq;
+ unsigned long flags;
+ int ret;
+
+ iwcq = to_iwcq(ibcq);
+
+ spin_lock_irqsave(&iwcq->lock, flags);
+ ret = __irdma_poll_cq(iwcq, num_entries, entry);
+ spin_unlock_irqrestore(&iwcq->lock, flags);
+
+ return ret;
+}
+
+/**
+ * irdma_req_notify_cq - arm cq kernel application
+ * @ibcq: cq to arm
+ * @notify_flags: notofication flags
+ */
+static int irdma_req_notify_cq(struct ib_cq *ibcq,
+ enum ib_cq_notify_flags notify_flags)
+{
+ struct irdma_cq *iwcq;
+ struct irdma_cq_uk *ukcq;
+ unsigned long flags;
+ enum irdma_cmpl_notify cq_notify = IRDMA_CQ_COMPL_EVENT;
+
+ iwcq = to_iwcq(ibcq);
+ ukcq = &iwcq->sc_cq.cq_uk;
+ if (notify_flags == IB_CQ_SOLICITED)
+ cq_notify = IRDMA_CQ_COMPL_SOLICITED;
+
+ spin_lock_irqsave(&iwcq->lock, flags);
+ irdma_uk_cq_request_notification(ukcq, cq_notify);
+ spin_unlock_irqrestore(&iwcq->lock, flags);
+
+ return 0;
+}
+
+static int irdma_roce_port_immutable(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_immutable *immutable)
+{
+ struct ib_port_attr attr;
+ int err;
+
+ immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP;
+ err = ib_query_port(ibdev, port_num, &attr);
+ if (err)
+ return err;
+
+ immutable->max_mad_size = IB_MGMT_MAD_SIZE;
+ immutable->pkey_tbl_len = attr.pkey_tbl_len;
+ immutable->gid_tbl_len = attr.gid_tbl_len;
+
+ return 0;
+}
+
+static int irdma_iw_port_immutable(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_immutable *immutable)
+{
+ struct ib_port_attr attr;
+ int err;
+
+ immutable->core_cap_flags = RDMA_CORE_PORT_IWARP;
+ err = ib_query_port(ibdev, port_num, &attr);
+ if (err)
+ return err;
+ immutable->gid_tbl_len = attr.gid_tbl_len;
+
+ return 0;
+}
+
+static const char *const irdma_hw_stat_names[] = {
+ /* 32bit names */
+ [IRDMA_HW_STAT_INDEX_RXVLANERR] = "rxVlanErrors",
+ [IRDMA_HW_STAT_INDEX_IP4RXDISCARD] = "ip4InDiscards",
+ [IRDMA_HW_STAT_INDEX_IP4RXTRUNC] = "ip4InTruncatedPkts",
+ [IRDMA_HW_STAT_INDEX_IP4TXNOROUTE] = "ip4OutNoRoutes",
+ [IRDMA_HW_STAT_INDEX_IP6RXDISCARD] = "ip6InDiscards",
+ [IRDMA_HW_STAT_INDEX_IP6RXTRUNC] = "ip6InTruncatedPkts",
+ [IRDMA_HW_STAT_INDEX_IP6TXNOROUTE] = "ip6OutNoRoutes",
+ [IRDMA_HW_STAT_INDEX_TCPRTXSEG] = "tcpRetransSegs",
+ [IRDMA_HW_STAT_INDEX_TCPRXOPTERR] = "tcpInOptErrors",
+ [IRDMA_HW_STAT_INDEX_TCPRXPROTOERR] = "tcpInProtoErrors",
+ [IRDMA_HW_STAT_INDEX_RXRPCNPHANDLED] = "cnpHandled",
+ [IRDMA_HW_STAT_INDEX_RXRPCNPIGNORED] = "cnpIgnored",
+ [IRDMA_HW_STAT_INDEX_TXNPCNPSENT] = "cnpSent",
+
+ /* 64bit names */
+ [IRDMA_HW_STAT_INDEX_IP4RXOCTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip4InOctets",
+ [IRDMA_HW_STAT_INDEX_IP4RXPKTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip4InPkts",
+ [IRDMA_HW_STAT_INDEX_IP4RXFRAGS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip4InReasmRqd",
+ [IRDMA_HW_STAT_INDEX_IP4RXMCOCTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip4InMcastOctets",
+ [IRDMA_HW_STAT_INDEX_IP4RXMCPKTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip4InMcastPkts",
+ [IRDMA_HW_STAT_INDEX_IP4TXOCTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip4OutOctets",
+ [IRDMA_HW_STAT_INDEX_IP4TXPKTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip4OutPkts",
+ [IRDMA_HW_STAT_INDEX_IP4TXFRAGS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip4OutSegRqd",
+ [IRDMA_HW_STAT_INDEX_IP4TXMCOCTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip4OutMcastOctets",
+ [IRDMA_HW_STAT_INDEX_IP4TXMCPKTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip4OutMcastPkts",
+ [IRDMA_HW_STAT_INDEX_IP6RXOCTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip6InOctets",
+ [IRDMA_HW_STAT_INDEX_IP6RXPKTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip6InPkts",
+ [IRDMA_HW_STAT_INDEX_IP6RXFRAGS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip6InReasmRqd",
+ [IRDMA_HW_STAT_INDEX_IP6RXMCOCTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip6InMcastOctets",
+ [IRDMA_HW_STAT_INDEX_IP6RXMCPKTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip6InMcastPkts",
+ [IRDMA_HW_STAT_INDEX_IP6TXOCTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip6OutOctets",
+ [IRDMA_HW_STAT_INDEX_IP6TXPKTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip6OutPkts",
+ [IRDMA_HW_STAT_INDEX_IP6TXFRAGS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip6OutSegRqd",
+ [IRDMA_HW_STAT_INDEX_IP6TXMCOCTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip6OutMcastOctets",
+ [IRDMA_HW_STAT_INDEX_IP6TXMCPKTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "ip6OutMcastPkts",
+ [IRDMA_HW_STAT_INDEX_TCPRXSEGS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "tcpInSegs",
+ [IRDMA_HW_STAT_INDEX_TCPTXSEG + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "tcpOutSegs",
+ [IRDMA_HW_STAT_INDEX_RDMARXRDS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "iwInRdmaReads",
+ [IRDMA_HW_STAT_INDEX_RDMARXSNDS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "iwInRdmaSends",
+ [IRDMA_HW_STAT_INDEX_RDMARXWRS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "iwInRdmaWrites",
+ [IRDMA_HW_STAT_INDEX_RDMATXRDS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "iwOutRdmaReads",
+ [IRDMA_HW_STAT_INDEX_RDMATXSNDS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "iwOutRdmaSends",
+ [IRDMA_HW_STAT_INDEX_RDMATXWRS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "iwOutRdmaWrites",
+ [IRDMA_HW_STAT_INDEX_RDMAVBND + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "iwRdmaBnd",
+ [IRDMA_HW_STAT_INDEX_RDMAVINV + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "iwRdmaInv",
+ [IRDMA_HW_STAT_INDEX_UDPRXPKTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "RxUDP",
+ [IRDMA_HW_STAT_INDEX_UDPTXPKTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "TxUDP",
+ [IRDMA_HW_STAT_INDEX_RXNPECNMARKEDPKTS + IRDMA_HW_STAT_INDEX_MAX_32] =
+ "RxECNMrkd",
+};
+
+static void irdma_get_dev_fw_str(struct ib_device *dev, char *str)
+{
+ struct irdma_device *iwdev = to_iwdev(dev);
+
+ snprintf(str, IB_FW_VERSION_NAME_MAX, "%u.%u",
+ irdma_fw_major_ver(&iwdev->rf->sc_dev),
+ irdma_fw_minor_ver(&iwdev->rf->sc_dev));
+}
+
+/**
+ * irdma_alloc_hw_port_stats - Allocate a hw stats structure
+ * @ibdev: device pointer from stack
+ * @port_num: port number
+ */
+static struct rdma_hw_stats *irdma_alloc_hw_port_stats(struct ib_device *ibdev,
+ u32 port_num)
+{
+ int num_counters = IRDMA_HW_STAT_INDEX_MAX_32 +
+ IRDMA_HW_STAT_INDEX_MAX_64;
+ unsigned long lifespan = RDMA_HW_STATS_DEFAULT_LIFESPAN;
+
+ BUILD_BUG_ON(ARRAY_SIZE(irdma_hw_stat_names) !=
+ (IRDMA_HW_STAT_INDEX_MAX_32 + IRDMA_HW_STAT_INDEX_MAX_64));
+
+ return rdma_alloc_hw_stats_struct(irdma_hw_stat_names, num_counters,
+ lifespan);
+}
+
+/**
+ * irdma_get_hw_stats - Populates the rdma_hw_stats structure
+ * @ibdev: device pointer from stack
+ * @stats: stats pointer from stack
+ * @port_num: port number
+ * @index: which hw counter the stack is requesting we update
+ */
+static int irdma_get_hw_stats(struct ib_device *ibdev,
+ struct rdma_hw_stats *stats, u32 port_num,
+ int index)
+{
+ struct irdma_device *iwdev = to_iwdev(ibdev);
+ struct irdma_dev_hw_stats *hw_stats = &iwdev->vsi.pestat->hw_stats;
+
+ if (iwdev->rf->rdma_ver >= IRDMA_GEN_2)
+ irdma_cqp_gather_stats_cmd(&iwdev->rf->sc_dev, iwdev->vsi.pestat, true);
+ else
+ irdma_cqp_gather_stats_gen1(&iwdev->rf->sc_dev, iwdev->vsi.pestat);
+
+ memcpy(&stats->value[0], hw_stats, sizeof(*hw_stats));
+
+ return stats->num_counters;
+}
+
+/**
+ * irdma_query_gid - Query port GID
+ * @ibdev: device pointer from stack
+ * @port: port number
+ * @index: Entry index
+ * @gid: Global ID
+ */
+static int irdma_query_gid(struct ib_device *ibdev, u32 port, int index,
+ union ib_gid *gid)
+{
+ struct irdma_device *iwdev = to_iwdev(ibdev);
+
+ memset(gid->raw, 0, sizeof(gid->raw));
+ ether_addr_copy(gid->raw, iwdev->netdev->dev_addr);
+
+ return 0;
+}
+
+/**
+ * mcast_list_add - Add a new mcast item to list
+ * @rf: RDMA PCI function
+ * @new_elem: pointer to element to add
+ */
+static void mcast_list_add(struct irdma_pci_f *rf,
+ struct mc_table_list *new_elem)
+{
+ list_add(&new_elem->list, &rf->mc_qht_list.list);
+}
+
+/**
+ * mcast_list_del - Remove an mcast item from list
+ * @mc_qht_elem: pointer to mcast table list element
+ */
+static void mcast_list_del(struct mc_table_list *mc_qht_elem)
+{
+ if (mc_qht_elem)
+ list_del(&mc_qht_elem->list);
+}
+
+/**
+ * mcast_list_lookup_ip - Search mcast list for address
+ * @rf: RDMA PCI function
+ * @ip_mcast: pointer to mcast IP address
+ */
+static struct mc_table_list *mcast_list_lookup_ip(struct irdma_pci_f *rf,
+ u32 *ip_mcast)
+{
+ struct mc_table_list *mc_qht_el;
+ struct list_head *pos, *q;
+
+ list_for_each_safe (pos, q, &rf->mc_qht_list.list) {
+ mc_qht_el = list_entry(pos, struct mc_table_list, list);
+ if (!memcmp(mc_qht_el->mc_info.dest_ip, ip_mcast,
+ sizeof(mc_qht_el->mc_info.dest_ip)))
+ return mc_qht_el;
+ }
+
+ return NULL;
+}
+
+/**
+ * irdma_mcast_cqp_op - perform a mcast cqp operation
+ * @iwdev: irdma device
+ * @mc_grp_ctx: mcast group info
+ * @op: operation
+ *
+ * returns error status
+ */
+static int irdma_mcast_cqp_op(struct irdma_device *iwdev,
+ struct irdma_mcast_grp_info *mc_grp_ctx, u8 op)
+{
+ struct cqp_cmds_info *cqp_info;
+ struct irdma_cqp_request *cqp_request;
+ enum irdma_status_code status;
+
+ cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, true);
+ if (!cqp_request)
+ return -ENOMEM;
+
+ cqp_request->info.in.u.mc_create.info = *mc_grp_ctx;
+ cqp_info = &cqp_request->info;
+ cqp_info->cqp_cmd = op;
+ cqp_info->post_sq = 1;
+ cqp_info->in.u.mc_create.scratch = (uintptr_t)cqp_request;
+ cqp_info->in.u.mc_create.cqp = &iwdev->rf->cqp.sc_cqp;
+ status = irdma_handle_cqp_op(iwdev->rf, cqp_request);
+ irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
+ if (status)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * irdma_mcast_mac - Get the multicast MAC for an IP address
+ * @ip_addr: IPv4 or IPv6 address
+ * @mac: pointer to result MAC address
+ * @ipv4: flag indicating IPv4 or IPv6
+ *
+ */
+void irdma_mcast_mac(u32 *ip_addr, u8 *mac, bool ipv4)
+{
+ u8 *ip = (u8 *)ip_addr;
+
+ if (ipv4) {
+ unsigned char mac4[ETH_ALEN] = {0x01, 0x00, 0x5E, 0x00,
+ 0x00, 0x00};
+
+ mac4[3] = ip[2] & 0x7F;
+ mac4[4] = ip[1];
+ mac4[5] = ip[0];
+ ether_addr_copy(mac, mac4);
+ } else {
+ unsigned char mac6[ETH_ALEN] = {0x33, 0x33, 0x00, 0x00,
+ 0x00, 0x00};
+
+ mac6[2] = ip[3];
+ mac6[3] = ip[2];
+ mac6[4] = ip[1];
+ mac6[5] = ip[0];
+ ether_addr_copy(mac, mac6);
+ }
+}
+
+/**
+ * irdma_attach_mcast - attach a qp to a multicast group
+ * @ibqp: ptr to qp
+ * @ibgid: pointer to global ID
+ * @lid: local ID
+ *
+ * returns error status
+ */
+static int irdma_attach_mcast(struct ib_qp *ibqp, union ib_gid *ibgid, u16 lid)
+{
+ struct irdma_qp *iwqp = to_iwqp(ibqp);
+ struct irdma_device *iwdev = iwqp->iwdev;
+ struct irdma_pci_f *rf = iwdev->rf;
+ struct mc_table_list *mc_qht_elem;
+ struct irdma_mcast_grp_ctx_entry_info mcg_info = {};
+ unsigned long flags;
+ u32 ip_addr[4] = {};
+ u32 mgn;
+ u32 no_mgs;
+ int ret = 0;
+ bool ipv4;
+ u16 vlan_id;
+ union {
+ struct sockaddr saddr;
+ struct sockaddr_in saddr_in;
+ struct sockaddr_in6 saddr_in6;
+ } sgid_addr;
+ unsigned char dmac[ETH_ALEN];
+
+ rdma_gid2ip((struct sockaddr *)&sgid_addr, ibgid);
+
+ if (!ipv6_addr_v4mapped((struct in6_addr *)ibgid)) {
+ irdma_copy_ip_ntohl(ip_addr,
+ sgid_addr.saddr_in6.sin6_addr.in6_u.u6_addr32);
+ irdma_netdev_vlan_ipv6(ip_addr, &vlan_id, NULL);
+ ipv4 = false;
+ ibdev_dbg(&iwdev->ibdev,
+ "VERBS: qp_id=%d, IP6address=%pI6\n", ibqp->qp_num,
+ ip_addr);
+ irdma_mcast_mac(ip_addr, dmac, false);
+ } else {
+ ip_addr[0] = ntohl(sgid_addr.saddr_in.sin_addr.s_addr);
+ ipv4 = true;
+ vlan_id = irdma_get_vlan_ipv4(ip_addr);
+ irdma_mcast_mac(ip_addr, dmac, true);
+ ibdev_dbg(&iwdev->ibdev,
+ "VERBS: qp_id=%d, IP4address=%pI4, MAC=%pM\n",
+ ibqp->qp_num, ip_addr, dmac);
+ }
+
+ spin_lock_irqsave(&rf->qh_list_lock, flags);
+ mc_qht_elem = mcast_list_lookup_ip(rf, ip_addr);
+ if (!mc_qht_elem) {
+ struct irdma_dma_mem *dma_mem_mc;
+
+ spin_unlock_irqrestore(&rf->qh_list_lock, flags);
+ mc_qht_elem = kzalloc(sizeof(*mc_qht_elem), GFP_KERNEL);
+ if (!mc_qht_elem)
+ return -ENOMEM;
+
+ mc_qht_elem->mc_info.ipv4_valid = ipv4;
+ memcpy(mc_qht_elem->mc_info.dest_ip, ip_addr,
+ sizeof(mc_qht_elem->mc_info.dest_ip));
+ ret = irdma_alloc_rsrc(rf, rf->allocated_mcgs, rf->max_mcg,
+ &mgn, &rf->next_mcg);
+ if (ret) {
+ kfree(mc_qht_elem);
+ return -ENOMEM;
+ }
+
+ mc_qht_elem->mc_info.mgn = mgn;
+ dma_mem_mc = &mc_qht_elem->mc_grp_ctx.dma_mem_mc;
+ dma_mem_mc->size = ALIGN(sizeof(u64) * IRDMA_MAX_MGS_PER_CTX,
+ IRDMA_HW_PAGE_SIZE);
+ dma_mem_mc->va = dma_alloc_coherent(rf->hw.device,
+ dma_mem_mc->size,
+ &dma_mem_mc->pa,
+ GFP_KERNEL);
+ if (!dma_mem_mc->va) {
+ irdma_free_rsrc(rf, rf->allocated_mcgs, mgn);
+ kfree(mc_qht_elem);
+ return -ENOMEM;
+ }
+
+ mc_qht_elem->mc_grp_ctx.mg_id = (u16)mgn;
+ memcpy(mc_qht_elem->mc_grp_ctx.dest_ip_addr, ip_addr,
+ sizeof(mc_qht_elem->mc_grp_ctx.dest_ip_addr));
+ mc_qht_elem->mc_grp_ctx.ipv4_valid = ipv4;
+ mc_qht_elem->mc_grp_ctx.vlan_id = vlan_id;
+ if (vlan_id < VLAN_N_VID)
+ mc_qht_elem->mc_grp_ctx.vlan_valid = true;
+ mc_qht_elem->mc_grp_ctx.hmc_fcn_id = iwdev->vsi.fcn_id;
+ mc_qht_elem->mc_grp_ctx.qs_handle =
+ iwqp->sc_qp.vsi->qos[iwqp->sc_qp.user_pri].qs_handle;
+ ether_addr_copy(mc_qht_elem->mc_grp_ctx.dest_mac_addr, dmac);
+
+ spin_lock_irqsave(&rf->qh_list_lock, flags);
+ mcast_list_add(rf, mc_qht_elem);
+ } else {
+ if (mc_qht_elem->mc_grp_ctx.no_of_mgs ==
+ IRDMA_MAX_MGS_PER_CTX) {
+ spin_unlock_irqrestore(&rf->qh_list_lock, flags);
+ return -ENOMEM;
+ }
+ }
+
+ mcg_info.qp_id = iwqp->ibqp.qp_num;
+ no_mgs = mc_qht_elem->mc_grp_ctx.no_of_mgs;
+ irdma_sc_add_mcast_grp(&mc_qht_elem->mc_grp_ctx, &mcg_info);
+ spin_unlock_irqrestore(&rf->qh_list_lock, flags);
+
+ /* Only if there is a change do we need to modify or create */
+ if (!no_mgs) {
+ ret = irdma_mcast_cqp_op(iwdev, &mc_qht_elem->mc_grp_ctx,
+ IRDMA_OP_MC_CREATE);
+ } else if (no_mgs != mc_qht_elem->mc_grp_ctx.no_of_mgs) {
+ ret = irdma_mcast_cqp_op(iwdev, &mc_qht_elem->mc_grp_ctx,
+ IRDMA_OP_MC_MODIFY);
+ } else {
+ return 0;
+ }
+
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ irdma_sc_del_mcast_grp(&mc_qht_elem->mc_grp_ctx, &mcg_info);
+ if (!mc_qht_elem->mc_grp_ctx.no_of_mgs) {
+ mcast_list_del(mc_qht_elem);
+ dma_free_coherent(rf->hw.device,
+ mc_qht_elem->mc_grp_ctx.dma_mem_mc.size,
+ mc_qht_elem->mc_grp_ctx.dma_mem_mc.va,
+ mc_qht_elem->mc_grp_ctx.dma_mem_mc.pa);
+ mc_qht_elem->mc_grp_ctx.dma_mem_mc.va = NULL;
+ irdma_free_rsrc(rf, rf->allocated_mcgs,
+ mc_qht_elem->mc_grp_ctx.mg_id);
+ kfree(mc_qht_elem);
+ }
+
+ return ret;
+}
+
+/**
+ * irdma_detach_mcast - detach a qp from a multicast group
+ * @ibqp: ptr to qp
+ * @ibgid: pointer to global ID
+ * @lid: local ID
+ *
+ * returns error status
+ */
+static int irdma_detach_mcast(struct ib_qp *ibqp, union ib_gid *ibgid, u16 lid)
+{
+ struct irdma_qp *iwqp = to_iwqp(ibqp);
+ struct irdma_device *iwdev = iwqp->iwdev;
+ struct irdma_pci_f *rf = iwdev->rf;
+ u32 ip_addr[4] = {};
+ struct mc_table_list *mc_qht_elem;
+ struct irdma_mcast_grp_ctx_entry_info mcg_info = {};
+ int ret;
+ unsigned long flags;
+ union {
+ struct sockaddr saddr;
+ struct sockaddr_in saddr_in;
+ struct sockaddr_in6 saddr_in6;
+ } sgid_addr;
+
+ rdma_gid2ip((struct sockaddr *)&sgid_addr, ibgid);
+ if (!ipv6_addr_v4mapped((struct in6_addr *)ibgid))
+ irdma_copy_ip_ntohl(ip_addr,
+ sgid_addr.saddr_in6.sin6_addr.in6_u.u6_addr32);
+ else
+ ip_addr[0] = ntohl(sgid_addr.saddr_in.sin_addr.s_addr);
+
+ spin_lock_irqsave(&rf->qh_list_lock, flags);
+ mc_qht_elem = mcast_list_lookup_ip(rf, ip_addr);
+ if (!mc_qht_elem) {
+ spin_unlock_irqrestore(&rf->qh_list_lock, flags);
+ ibdev_dbg(&iwdev->ibdev,
+ "VERBS: address not found MCG\n");
+ return 0;
+ }
+
+ mcg_info.qp_id = iwqp->ibqp.qp_num;
+ irdma_sc_del_mcast_grp(&mc_qht_elem->mc_grp_ctx, &mcg_info);
+ if (!mc_qht_elem->mc_grp_ctx.no_of_mgs) {
+ mcast_list_del(mc_qht_elem);
+ spin_unlock_irqrestore(&rf->qh_list_lock, flags);
+ ret = irdma_mcast_cqp_op(iwdev, &mc_qht_elem->mc_grp_ctx,
+ IRDMA_OP_MC_DESTROY);
+ if (ret) {
+ ibdev_dbg(&iwdev->ibdev,
+ "VERBS: failed MC_DESTROY MCG\n");
+ spin_lock_irqsave(&rf->qh_list_lock, flags);
+ mcast_list_add(rf, mc_qht_elem);
+ spin_unlock_irqrestore(&rf->qh_list_lock, flags);
+ return -EAGAIN;
+ }
+
+ dma_free_coherent(rf->hw.device,
+ mc_qht_elem->mc_grp_ctx.dma_mem_mc.size,
+ mc_qht_elem->mc_grp_ctx.dma_mem_mc.va,
+ mc_qht_elem->mc_grp_ctx.dma_mem_mc.pa);
+ mc_qht_elem->mc_grp_ctx.dma_mem_mc.va = NULL;
+ irdma_free_rsrc(rf, rf->allocated_mcgs,
+ mc_qht_elem->mc_grp_ctx.mg_id);
+ kfree(mc_qht_elem);
+ } else {
+ spin_unlock_irqrestore(&rf->qh_list_lock, flags);
+ ret = irdma_mcast_cqp_op(iwdev, &mc_qht_elem->mc_grp_ctx,
+ IRDMA_OP_MC_MODIFY);
+ if (ret) {
+ ibdev_dbg(&iwdev->ibdev,
+ "VERBS: failed Modify MCG\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * irdma_create_ah - create address handle
+ * @ibah: address handle
+ * @attr: address handle attributes
+ * @udata: User data
+ *
+ * returns 0 on success, error otherwise
+ */
+static int irdma_create_ah(struct ib_ah *ibah,
+ struct rdma_ah_init_attr *attr,
+ struct ib_udata *udata)
+{
+ struct irdma_pd *pd = to_iwpd(ibah->pd);
+ struct irdma_ah *ah = container_of(ibah, struct irdma_ah, ibah);
+ struct rdma_ah_attr *ah_attr = attr->ah_attr;
+ const struct ib_gid_attr *sgid_attr;
+ struct irdma_device *iwdev = to_iwdev(ibah->pd->device);
+ struct irdma_pci_f *rf = iwdev->rf;
+ struct irdma_sc_ah *sc_ah;
+ u32 ah_id = 0;
+ struct irdma_ah_info *ah_info;
+ struct irdma_create_ah_resp uresp;
+ union {
+ struct sockaddr saddr;
+ struct sockaddr_in saddr_in;
+ struct sockaddr_in6 saddr_in6;
+ } sgid_addr, dgid_addr;
+ int err;
+ u8 dmac[ETH_ALEN];
+
+ err = irdma_alloc_rsrc(rf, rf->allocated_ahs, rf->max_ah, &ah_id,
+ &rf->next_ah);
+ if (err)
+ return err;
+
+ ah->pd = pd;
+ sc_ah = &ah->sc_ah;
+ sc_ah->ah_info.ah_idx = ah_id;
+ sc_ah->ah_info.vsi = &iwdev->vsi;
+ irdma_sc_init_ah(&rf->sc_dev, sc_ah);
+ ah->sgid_index = ah_attr->grh.sgid_index;
+ sgid_attr = ah_attr->grh.sgid_attr;
+ memcpy(&ah->dgid, &ah_attr->grh.dgid, sizeof(ah->dgid));
+ rdma_gid2ip((struct sockaddr *)&sgid_addr, &sgid_attr->gid);
+ rdma_gid2ip((struct sockaddr *)&dgid_addr, &ah_attr->grh.dgid);
+ ah->av.attrs = *ah_attr;
+ ah->av.net_type = rdma_gid_attr_network_type(sgid_attr);
+ ah->av.sgid_addr.saddr = sgid_addr.saddr;
+ ah->av.dgid_addr.saddr = dgid_addr.saddr;
+ ah_info = &sc_ah->ah_info;
+ ah_info->ah_idx = ah_id;
+ ah_info->pd_idx = pd->sc_pd.pd_id;
+ if (ah_attr->ah_flags & IB_AH_GRH) {
+ ah_info->flow_label = ah_attr->grh.flow_label;
+ ah_info->hop_ttl = ah_attr->grh.hop_limit;
+ ah_info->tc_tos = ah_attr->grh.traffic_class;
+ }
+
+ ether_addr_copy(dmac, ah_attr->roce.dmac);
+ if (rdma_gid_attr_network_type(sgid_attr) == RDMA_NETWORK_IPV4) {
+ ah_info->ipv4_valid = true;
+ ah_info->dest_ip_addr[0] =
+ ntohl(dgid_addr.saddr_in.sin_addr.s_addr);
+ ah_info->src_ip_addr[0] =
+ ntohl(sgid_addr.saddr_in.sin_addr.s_addr);
+ ah_info->do_lpbk = irdma_ipv4_is_lpb(ah_info->src_ip_addr[0],
+ ah_info->dest_ip_addr[0]);
+ if (ipv4_is_multicast(dgid_addr.saddr_in.sin_addr.s_addr)) {
+ ah_info->do_lpbk = true;
+ irdma_mcast_mac(ah_info->dest_ip_addr, dmac, true);
+ }
+ } else {
+ irdma_copy_ip_ntohl(ah_info->dest_ip_addr,
+ dgid_addr.saddr_in6.sin6_addr.in6_u.u6_addr32);
+ irdma_copy_ip_ntohl(ah_info->src_ip_addr,
+ sgid_addr.saddr_in6.sin6_addr.in6_u.u6_addr32);
+ ah_info->do_lpbk = irdma_ipv6_is_lpb(ah_info->src_ip_addr,
+ ah_info->dest_ip_addr);
+ if (rdma_is_multicast_addr(&dgid_addr.saddr_in6.sin6_addr)) {
+ ah_info->do_lpbk = true;
+ irdma_mcast_mac(ah_info->dest_ip_addr, dmac, false);
+ }
+ }
+
+ err = rdma_read_gid_l2_fields(sgid_attr, &ah_info->vlan_tag,
+ ah_info->mac_addr);
+ if (err)
+ goto error;
+
+ ah_info->dst_arpindex = irdma_add_arp(iwdev->rf, ah_info->dest_ip_addr,
+ ah_info->ipv4_valid, dmac);
+
+ if (ah_info->dst_arpindex == -1) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ if (ah_info->vlan_tag >= VLAN_N_VID && iwdev->dcb)
+ ah_info->vlan_tag = 0;
+
+ if (ah_info->vlan_tag < VLAN_N_VID) {
+ ah_info->insert_vlan_tag = true;
+ ah_info->vlan_tag |=
+ rt_tos2priority(ah_info->tc_tos) << VLAN_PRIO_SHIFT;
+ }
+
+ err = irdma_ah_cqp_op(iwdev->rf, sc_ah, IRDMA_OP_AH_CREATE,
+ attr->flags & RDMA_CREATE_AH_SLEEPABLE,
+ irdma_gsi_ud_qp_ah_cb, sc_ah);
+
+ if (err) {
+ ibdev_dbg(&iwdev->ibdev,
+ "VERBS: CQP-OP Create AH fail");
+ goto error;
+ }
+
+ if (!(attr->flags & RDMA_CREATE_AH_SLEEPABLE)) {
+ int cnt = CQP_COMPL_WAIT_TIME_MS * CQP_TIMEOUT_THRESHOLD;
+
+ do {
+ irdma_cqp_ce_handler(rf, &rf->ccq.sc_cq);
+ mdelay(1);
+ } while (!sc_ah->ah_info.ah_valid && --cnt);
+
+ if (!cnt) {
+ ibdev_dbg(&iwdev->ibdev,
+ "VERBS: CQP create AH timed out");
+ err = -ETIMEDOUT;
+ goto error;
+ }
+ }
+
+ if (udata) {
+ uresp.ah_id = ah->sc_ah.ah_info.ah_idx;
+ err = ib_copy_to_udata(udata, &uresp,
+ min(sizeof(uresp), udata->outlen));
+ }
+ return 0;
+
+error:
+ irdma_free_rsrc(iwdev->rf, iwdev->rf->allocated_ahs, ah_id);
+
+ return err;
+}
+
+/**
+ * irdma_destroy_ah - Destroy address handle
+ * @ibah: pointer to address handle
+ * @ah_flags: flags for sleepable
+ */
+static int irdma_destroy_ah(struct ib_ah *ibah, u32 ah_flags)
+{
+ struct irdma_device *iwdev = to_iwdev(ibah->device);
+ struct irdma_ah *ah = to_iwah(ibah);
+
+ irdma_ah_cqp_op(iwdev->rf, &ah->sc_ah, IRDMA_OP_AH_DESTROY,
+ false, NULL, ah);
+
+ irdma_free_rsrc(iwdev->rf, iwdev->rf->allocated_ahs,
+ ah->sc_ah.ah_info.ah_idx);
+
+ return 0;
+}
+
+/**
+ * irdma_query_ah - Query address handle
+ * @ibah: pointer to address handle
+ * @ah_attr: address handle attributes
+ */
+static int irdma_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr)
+{
+ struct irdma_ah *ah = to_iwah(ibah);
+
+ memset(ah_attr, 0, sizeof(*ah_attr));
+ if (ah->av.attrs.ah_flags & IB_AH_GRH) {
+ ah_attr->ah_flags = IB_AH_GRH;
+ ah_attr->grh.flow_label = ah->sc_ah.ah_info.flow_label;
+ ah_attr->grh.traffic_class = ah->sc_ah.ah_info.tc_tos;
+ ah_attr->grh.hop_limit = ah->sc_ah.ah_info.hop_ttl;
+ ah_attr->grh.sgid_index = ah->sgid_index;
+ ah_attr->grh.sgid_index = ah->sgid_index;
+ memcpy(&ah_attr->grh.dgid, &ah->dgid,
+ sizeof(ah_attr->grh.dgid));
+ }
+
+ return 0;
+}
+
+static enum rdma_link_layer irdma_get_link_layer(struct ib_device *ibdev,
+ u32 port_num)
+{
+ return IB_LINK_LAYER_ETHERNET;
+}
+
+static __be64 irdma_mac_to_guid(struct net_device *ndev)
+{
+ unsigned char *mac = ndev->dev_addr;
+ __be64 guid;
+ unsigned char *dst = (unsigned char *)&guid;
+
+ dst[0] = mac[0] ^ 2;
+ dst[1] = mac[1];
+ dst[2] = mac[2];
+ dst[3] = 0xff;
+ dst[4] = 0xfe;
+ dst[5] = mac[3];
+ dst[6] = mac[4];
+ dst[7] = mac[5];
+
+ return guid;
+}
+
+static const struct ib_device_ops irdma_roce_dev_ops = {
+ .attach_mcast = irdma_attach_mcast,
+ .create_ah = irdma_create_ah,
+ .create_user_ah = irdma_create_ah,
+ .destroy_ah = irdma_destroy_ah,
+ .detach_mcast = irdma_detach_mcast,
+ .get_link_layer = irdma_get_link_layer,
+ .get_port_immutable = irdma_roce_port_immutable,
+ .modify_qp = irdma_modify_qp_roce,
+ .query_ah = irdma_query_ah,
+ .query_pkey = irdma_query_pkey,
+};
+
+static const struct ib_device_ops irdma_iw_dev_ops = {
+ .modify_qp = irdma_modify_qp,
+ .get_port_immutable = irdma_iw_port_immutable,
+ .query_gid = irdma_query_gid,
+};
+
+static const struct ib_device_ops irdma_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_IRDMA,
+ .uverbs_abi_ver = IRDMA_ABI_VER,
+
+ .alloc_hw_port_stats = irdma_alloc_hw_port_stats,
+ .alloc_mr = irdma_alloc_mr,
+ .alloc_mw = irdma_alloc_mw,
+ .alloc_pd = irdma_alloc_pd,
+ .alloc_ucontext = irdma_alloc_ucontext,
+ .create_cq = irdma_create_cq,
+ .create_qp = irdma_create_qp,
+ .dealloc_driver = irdma_ib_dealloc_device,
+ .dealloc_mw = irdma_dealloc_mw,
+ .dealloc_pd = irdma_dealloc_pd,
+ .dealloc_ucontext = irdma_dealloc_ucontext,
+ .dereg_mr = irdma_dereg_mr,
+ .destroy_cq = irdma_destroy_cq,
+ .destroy_qp = irdma_destroy_qp,
+ .disassociate_ucontext = irdma_disassociate_ucontext,
+ .get_dev_fw_str = irdma_get_dev_fw_str,
+ .get_dma_mr = irdma_get_dma_mr,
+ .get_hw_stats = irdma_get_hw_stats,
+ .map_mr_sg = irdma_map_mr_sg,
+ .mmap = irdma_mmap,
+ .mmap_free = irdma_mmap_free,
+ .poll_cq = irdma_poll_cq,
+ .post_recv = irdma_post_recv,
+ .post_send = irdma_post_send,
+ .query_device = irdma_query_device,
+ .query_port = irdma_query_port,
+ .query_qp = irdma_query_qp,
+ .reg_user_mr = irdma_reg_user_mr,
+ .req_notify_cq = irdma_req_notify_cq,
+ .resize_cq = irdma_resize_cq,
+ INIT_RDMA_OBJ_SIZE(ib_pd, irdma_pd, ibpd),
+ INIT_RDMA_OBJ_SIZE(ib_ucontext, irdma_ucontext, ibucontext),
+ INIT_RDMA_OBJ_SIZE(ib_ah, irdma_ah, ibah),
+ INIT_RDMA_OBJ_SIZE(ib_cq, irdma_cq, ibcq),
+ INIT_RDMA_OBJ_SIZE(ib_mw, irdma_mr, ibmw),
+};
+
+/**
+ * irdma_init_roce_device - initialization of roce rdma device
+ * @iwdev: irdma device
+ */
+static void irdma_init_roce_device(struct irdma_device *iwdev)
+{
+ iwdev->ibdev.node_type = RDMA_NODE_IB_CA;
+ iwdev->ibdev.node_guid = irdma_mac_to_guid(iwdev->netdev);
+ ib_set_device_ops(&iwdev->ibdev, &irdma_roce_dev_ops);
+}
+
+/**
+ * irdma_init_iw_device - initialization of iwarp rdma device
+ * @iwdev: irdma device
+ */
+static int irdma_init_iw_device(struct irdma_device *iwdev)
+{
+ struct net_device *netdev = iwdev->netdev;
+
+ iwdev->ibdev.node_type = RDMA_NODE_RNIC;
+ ether_addr_copy((u8 *)&iwdev->ibdev.node_guid, netdev->dev_addr);
+ iwdev->ibdev.ops.iw_add_ref = irdma_qp_add_ref;
+ iwdev->ibdev.ops.iw_rem_ref = irdma_qp_rem_ref;
+ iwdev->ibdev.ops.iw_get_qp = irdma_get_qp;
+ iwdev->ibdev.ops.iw_connect = irdma_connect;
+ iwdev->ibdev.ops.iw_accept = irdma_accept;
+ iwdev->ibdev.ops.iw_reject = irdma_reject;
+ iwdev->ibdev.ops.iw_create_listen = irdma_create_listen;
+ iwdev->ibdev.ops.iw_destroy_listen = irdma_destroy_listen;
+ memcpy(iwdev->ibdev.iw_ifname, netdev->name,
+ sizeof(iwdev->ibdev.iw_ifname));
+ ib_set_device_ops(&iwdev->ibdev, &irdma_iw_dev_ops);
+
+ return 0;
+}
+
+/**
+ * irdma_init_rdma_device - initialization of rdma device
+ * @iwdev: irdma device
+ */
+static int irdma_init_rdma_device(struct irdma_device *iwdev)
+{
+ struct pci_dev *pcidev = iwdev->rf->pcidev;
+ int ret;
+
+ if (iwdev->roce_mode) {
+ irdma_init_roce_device(iwdev);
+ } else {
+ ret = irdma_init_iw_device(iwdev);
+ if (ret)
+ return ret;
+ }
+ iwdev->ibdev.phys_port_cnt = 1;
+ iwdev->ibdev.num_comp_vectors = iwdev->rf->ceqs_count;
+ iwdev->ibdev.dev.parent = &pcidev->dev;
+ ib_set_device_ops(&iwdev->ibdev, &irdma_dev_ops);
+
+ return 0;
+}
+
+/**
+ * irdma_port_ibevent - indicate port event
+ * @iwdev: irdma device
+ */
+void irdma_port_ibevent(struct irdma_device *iwdev)
+{
+ struct ib_event event;
+
+ event.device = &iwdev->ibdev;
+ event.element.port_num = 1;
+ event.event =
+ iwdev->iw_status ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR;
+ ib_dispatch_event(&event);
+}
+
+/**
+ * irdma_ib_unregister_device - unregister rdma device from IB
+ * core
+ * @iwdev: irdma device
+ */
+void irdma_ib_unregister_device(struct irdma_device *iwdev)
+{
+ iwdev->iw_status = 0;
+ irdma_port_ibevent(iwdev);
+ ib_unregister_device(&iwdev->ibdev);
+}
+
+/**
+ * irdma_ib_register_device - register irdma device to IB core
+ * @iwdev: irdma device
+ */
+int irdma_ib_register_device(struct irdma_device *iwdev)
+{
+ int ret;
+
+ ret = irdma_init_rdma_device(iwdev);
+ if (ret)
+ return ret;
+
+ ret = ib_device_set_netdev(&iwdev->ibdev, iwdev->netdev, 1);
+ if (ret)
+ goto error;
+ dma_set_max_seg_size(iwdev->rf->hw.device, UINT_MAX);
+ ret = ib_register_device(&iwdev->ibdev, "irdma%d", iwdev->rf->hw.device);
+ if (ret)
+ goto error;
+
+ iwdev->iw_status = 1;
+ irdma_port_ibevent(iwdev);
+
+ return 0;
+
+error:
+ if (ret)
+ ibdev_dbg(&iwdev->ibdev, "VERBS: Register RDMA device fail\n");
+
+ return ret;
+}
+
+/**
+ * irdma_ib_dealloc_device
+ * @ibdev: ib device
+ *
+ * callback from ibdev dealloc_driver to deallocate resources
+ * unber irdma device
+ */
+void irdma_ib_dealloc_device(struct ib_device *ibdev)
+{
+ struct irdma_device *iwdev = to_iwdev(ibdev);
+
+ irdma_rt_deinit_hw(iwdev);
+ irdma_ctrl_deinit_hw(iwdev->rf);
+ kfree(iwdev->rf);
+}
diff --git a/drivers/infiniband/hw/irdma/verbs.h b/drivers/infiniband/hw/irdma/verbs.h
new file mode 100644
index 000000000000..5c244cd321a3
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/verbs.h
@@ -0,0 +1,225 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2015 - 2021 Intel Corporation */
+#ifndef IRDMA_VERBS_H
+#define IRDMA_VERBS_H
+
+#define IRDMA_MAX_SAVED_PHY_PGADDR 4
+
+#define IRDMA_PKEY_TBL_SZ 1
+#define IRDMA_DEFAULT_PKEY 0xFFFF
+
+struct irdma_ucontext {
+ struct ib_ucontext ibucontext;
+ struct irdma_device *iwdev;
+ struct rdma_user_mmap_entry *db_mmap_entry;
+ struct list_head cq_reg_mem_list;
+ spinlock_t cq_reg_mem_list_lock; /* protect CQ memory list */
+ struct list_head qp_reg_mem_list;
+ spinlock_t qp_reg_mem_list_lock; /* protect QP memory list */
+ int abi_ver;
+ bool legacy_mode;
+};
+
+struct irdma_pd {
+ struct ib_pd ibpd;
+ struct irdma_sc_pd sc_pd;
+};
+
+struct irdma_av {
+ u8 macaddr[16];
+ struct rdma_ah_attr attrs;
+ union {
+ struct sockaddr saddr;
+ struct sockaddr_in saddr_in;
+ struct sockaddr_in6 saddr_in6;
+ } sgid_addr, dgid_addr;
+ u8 net_type;
+};
+
+struct irdma_ah {
+ struct ib_ah ibah;
+ struct irdma_sc_ah sc_ah;
+ struct irdma_pd *pd;
+ struct irdma_av av;
+ u8 sgid_index;
+ union ib_gid dgid;
+};
+
+struct irdma_hmc_pble {
+ union {
+ u32 idx;
+ dma_addr_t addr;
+ };
+};
+
+struct irdma_cq_mr {
+ struct irdma_hmc_pble cq_pbl;
+ dma_addr_t shadow;
+ bool split;
+};
+
+struct irdma_qp_mr {
+ struct irdma_hmc_pble sq_pbl;
+ struct irdma_hmc_pble rq_pbl;
+ dma_addr_t shadow;
+ struct page *sq_page;
+};
+
+struct irdma_cq_buf {
+ struct irdma_dma_mem kmem_buf;
+ struct irdma_cq_uk cq_uk;
+ struct irdma_hw *hw;
+ struct list_head list;
+ struct work_struct work;
+};
+
+struct irdma_pbl {
+ struct list_head list;
+ union {
+ struct irdma_qp_mr qp_mr;
+ struct irdma_cq_mr cq_mr;
+ };
+
+ bool pbl_allocated:1;
+ bool on_list:1;
+ u64 user_base;
+ struct irdma_pble_alloc pble_alloc;
+ struct irdma_mr *iwmr;
+};
+
+struct irdma_mr {
+ union {
+ struct ib_mr ibmr;
+ struct ib_mw ibmw;
+ };
+ struct ib_umem *region;
+ u16 type;
+ u32 page_cnt;
+ u64 page_size;
+ u32 npages;
+ u32 stag;
+ u64 len;
+ u64 pgaddrmem[IRDMA_MAX_SAVED_PHY_PGADDR];
+ struct irdma_pbl iwpbl;
+};
+
+struct irdma_cq {
+ struct ib_cq ibcq;
+ struct irdma_sc_cq sc_cq;
+ u16 cq_head;
+ u16 cq_size;
+ u16 cq_num;
+ bool user_mode;
+ u32 polled_cmpls;
+ u32 cq_mem_size;
+ struct irdma_dma_mem kmem;
+ struct irdma_dma_mem kmem_shadow;
+ spinlock_t lock; /* for poll cq */
+ struct irdma_pbl *iwpbl;
+ struct irdma_pbl *iwpbl_shadow;
+ struct list_head resize_list;
+ struct irdma_cq_poll_info cur_cqe;
+};
+
+struct disconn_work {
+ struct work_struct work;
+ struct irdma_qp *iwqp;
+};
+
+struct iw_cm_id;
+
+struct irdma_qp_kmode {
+ struct irdma_dma_mem dma_mem;
+ struct irdma_sq_uk_wr_trk_info *sq_wrid_mem;
+ u64 *rq_wrid_mem;
+};
+
+struct irdma_qp {
+ struct ib_qp ibqp;
+ struct irdma_sc_qp sc_qp;
+ struct irdma_device *iwdev;
+ struct irdma_cq *iwscq;
+ struct irdma_cq *iwrcq;
+ struct irdma_pd *iwpd;
+ struct rdma_user_mmap_entry *push_wqe_mmap_entry;
+ struct rdma_user_mmap_entry *push_db_mmap_entry;
+ struct irdma_qp_host_ctx_info ctx_info;
+ union {
+ struct irdma_iwarp_offload_info iwarp_info;
+ struct irdma_roce_offload_info roce_info;
+ };
+
+ union {
+ struct irdma_tcp_offload_info tcp_info;
+ struct irdma_udp_offload_info udp_info;
+ };
+
+ struct irdma_ah roce_ah;
+ struct list_head teardown_entry;
+ refcount_t refcnt;
+ struct iw_cm_id *cm_id;
+ struct irdma_cm_node *cm_node;
+ struct ib_mr *lsmm_mr;
+ atomic_t hw_mod_qp_pend;
+ enum ib_qp_state ibqp_state;
+ u32 qp_mem_size;
+ u32 last_aeq;
+ int max_send_wr;
+ int max_recv_wr;
+ atomic_t close_timer_started;
+ spinlock_t lock; /* serialize posting WRs to SQ/RQ */
+ struct irdma_qp_context *iwqp_context;
+ void *pbl_vbase;
+ dma_addr_t pbl_pbase;
+ struct page *page;
+ u8 active_conn : 1;
+ u8 user_mode : 1;
+ u8 hte_added : 1;
+ u8 flush_issued : 1;
+ u8 sig_all : 1;
+ u8 pau_mode : 1;
+ u8 rsvd : 1;
+ u8 iwarp_state;
+ u16 term_sq_flush_code;
+ u16 term_rq_flush_code;
+ u8 hw_iwarp_state;
+ u8 hw_tcp_state;
+ struct irdma_qp_kmode kqp;
+ struct irdma_dma_mem host_ctx;
+ struct timer_list terminate_timer;
+ struct irdma_pbl *iwpbl;
+ struct irdma_dma_mem q2_ctx_mem;
+ struct irdma_dma_mem ietf_mem;
+ struct completion free_qp;
+ wait_queue_head_t waitq;
+ wait_queue_head_t mod_qp_waitq;
+ u8 rts_ae_rcvd;
+};
+
+enum irdma_mmap_flag {
+ IRDMA_MMAP_IO_NC,
+ IRDMA_MMAP_IO_WC,
+};
+
+struct irdma_user_mmap_entry {
+ struct rdma_user_mmap_entry rdma_entry;
+ u64 bar_offset;
+ u8 mmap_flag;
+};
+
+static inline u16 irdma_fw_major_ver(struct irdma_sc_dev *dev)
+{
+ return (u16)FIELD_GET(IRDMA_FW_VER_MAJOR, dev->feature_info[IRDMA_FEATURE_FW_INFO]);
+}
+
+static inline u16 irdma_fw_minor_ver(struct irdma_sc_dev *dev)
+{
+ return (u16)FIELD_GET(IRDMA_FW_VER_MINOR, dev->feature_info[IRDMA_FEATURE_FW_INFO]);
+}
+
+void irdma_mcast_mac(u32 *ip_addr, u8 *mac, bool ipv4);
+int irdma_ib_register_device(struct irdma_device *iwdev);
+void irdma_ib_unregister_device(struct irdma_device *iwdev);
+void irdma_ib_dealloc_device(struct ib_device *ibdev);
+void irdma_ib_qp_event(struct irdma_qp *iwqp, enum irdma_qp_event_type event);
+#endif /* IRDMA_VERBS_H */
diff --git a/drivers/infiniband/hw/irdma/ws.c b/drivers/infiniband/hw/irdma/ws.c
new file mode 100644
index 000000000000..b68c575eb78e
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/ws.c
@@ -0,0 +1,406 @@
+// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
+/* Copyright (c) 2017 - 2021 Intel Corporation */
+#include "osdep.h"
+#include "status.h"
+#include "hmc.h"
+#include "defs.h"
+#include "type.h"
+#include "protos.h"
+
+#include "ws.h"
+
+/**
+ * irdma_alloc_node - Allocate a WS node and init
+ * @vsi: vsi pointer
+ * @user_pri: user priority
+ * @node_type: Type of node, leaf or parent
+ * @parent: parent node pointer
+ */
+static struct irdma_ws_node *irdma_alloc_node(struct irdma_sc_vsi *vsi,
+ u8 user_pri,
+ enum irdma_ws_node_type node_type,
+ struct irdma_ws_node *parent)
+{
+ struct irdma_virt_mem ws_mem;
+ struct irdma_ws_node *node;
+ u16 node_index = 0;
+
+ ws_mem.size = sizeof(struct irdma_ws_node);
+ ws_mem.va = kzalloc(ws_mem.size, GFP_KERNEL);
+ if (!ws_mem.va)
+ return NULL;
+
+ if (parent) {
+ node_index = irdma_alloc_ws_node_id(vsi->dev);
+ if (node_index == IRDMA_WS_NODE_INVALID) {
+ kfree(ws_mem.va);
+ return NULL;
+ }
+ }
+
+ node = ws_mem.va;
+ node->index = node_index;
+ node->vsi_index = vsi->vsi_idx;
+ INIT_LIST_HEAD(&node->child_list_head);
+ if (node_type == WS_NODE_TYPE_LEAF) {
+ node->type_leaf = true;
+ node->traffic_class = vsi->qos[user_pri].traffic_class;
+ node->user_pri = user_pri;
+ node->rel_bw = vsi->qos[user_pri].rel_bw;
+ if (!node->rel_bw)
+ node->rel_bw = 1;
+
+ node->lan_qs_handle = vsi->qos[user_pri].lan_qos_handle;
+ node->prio_type = IRDMA_PRIO_WEIGHTED_RR;
+ } else {
+ node->rel_bw = 1;
+ node->prio_type = IRDMA_PRIO_WEIGHTED_RR;
+ node->enable = true;
+ }
+
+ node->parent = parent;
+
+ return node;
+}
+
+/**
+ * irdma_free_node - Free a WS node
+ * @vsi: VSI stricture of device
+ * @node: Pointer to node to free
+ */
+static void irdma_free_node(struct irdma_sc_vsi *vsi,
+ struct irdma_ws_node *node)
+{
+ struct irdma_virt_mem ws_mem;
+
+ if (node->index)
+ irdma_free_ws_node_id(vsi->dev, node->index);
+
+ ws_mem.va = node;
+ ws_mem.size = sizeof(struct irdma_ws_node);
+ kfree(ws_mem.va);
+}
+
+/**
+ * irdma_ws_cqp_cmd - Post CQP work scheduler node cmd
+ * @vsi: vsi pointer
+ * @node: pointer to node
+ * @cmd: add, remove or modify
+ */
+static enum irdma_status_code
+irdma_ws_cqp_cmd(struct irdma_sc_vsi *vsi, struct irdma_ws_node *node, u8 cmd)
+{
+ struct irdma_ws_node_info node_info = {};
+
+ node_info.id = node->index;
+ node_info.vsi = node->vsi_index;
+ if (node->parent)
+ node_info.parent_id = node->parent->index;
+ else
+ node_info.parent_id = node_info.id;
+
+ node_info.weight = node->rel_bw;
+ node_info.tc = node->traffic_class;
+ node_info.prio_type = node->prio_type;
+ node_info.type_leaf = node->type_leaf;
+ node_info.enable = node->enable;
+ if (irdma_cqp_ws_node_cmd(vsi->dev, cmd, &node_info)) {
+ ibdev_dbg(to_ibdev(vsi->dev), "WS: CQP WS CMD failed\n");
+ return IRDMA_ERR_NO_MEMORY;
+ }
+
+ if (node->type_leaf && cmd == IRDMA_OP_WS_ADD_NODE) {
+ node->qs_handle = node_info.qs_handle;
+ vsi->qos[node->user_pri].qs_handle = node_info.qs_handle;
+ }
+
+ return 0;
+}
+
+/**
+ * ws_find_node - Find SC WS node based on VSI id or TC
+ * @parent: parent node of First VSI or TC node
+ * @match_val: value to match
+ * @type: match type VSI/TC
+ */
+static struct irdma_ws_node *ws_find_node(struct irdma_ws_node *parent,
+ u16 match_val,
+ enum irdma_ws_match_type type)
+{
+ struct irdma_ws_node *node;
+
+ switch (type) {
+ case WS_MATCH_TYPE_VSI:
+ list_for_each_entry(node, &parent->child_list_head, siblings) {
+ if (node->vsi_index == match_val)
+ return node;
+ }
+ break;
+ case WS_MATCH_TYPE_TC:
+ list_for_each_entry(node, &parent->child_list_head, siblings) {
+ if (node->traffic_class == match_val)
+ return node;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+/**
+ * irdma_tc_in_use - Checks to see if a leaf node is in use
+ * @vsi: vsi pointer
+ * @user_pri: user priority
+ */
+static bool irdma_tc_in_use(struct irdma_sc_vsi *vsi, u8 user_pri)
+{
+ int i;
+
+ mutex_lock(&vsi->qos[user_pri].qos_mutex);
+ if (!list_empty(&vsi->qos[user_pri].qplist)) {
+ mutex_unlock(&vsi->qos[user_pri].qos_mutex);
+ return true;
+ }
+
+ /* Check if the traffic class associated with the given user priority
+ * is in use by any other user priority. If so, nothing left to do
+ */
+ for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
+ if (vsi->qos[i].traffic_class == vsi->qos[user_pri].traffic_class &&
+ !list_empty(&vsi->qos[i].qplist)) {
+ mutex_unlock(&vsi->qos[user_pri].qos_mutex);
+ return true;
+ }
+ }
+ mutex_unlock(&vsi->qos[user_pri].qos_mutex);
+
+ return false;
+}
+
+/**
+ * irdma_remove_leaf - Remove leaf node unconditionally
+ * @vsi: vsi pointer
+ * @user_pri: user priority
+ */
+static void irdma_remove_leaf(struct irdma_sc_vsi *vsi, u8 user_pri)
+{
+ struct irdma_ws_node *ws_tree_root, *vsi_node, *tc_node;
+ int i;
+ u16 traffic_class;
+
+ traffic_class = vsi->qos[user_pri].traffic_class;
+ for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++)
+ if (vsi->qos[i].traffic_class == traffic_class)
+ vsi->qos[i].valid = false;
+
+ ws_tree_root = vsi->dev->ws_tree_root;
+ if (!ws_tree_root)
+ return;
+
+ vsi_node = ws_find_node(ws_tree_root, vsi->vsi_idx,
+ WS_MATCH_TYPE_VSI);
+ if (!vsi_node)
+ return;
+
+ tc_node = ws_find_node(vsi_node,
+ vsi->qos[user_pri].traffic_class,
+ WS_MATCH_TYPE_TC);
+ if (!tc_node)
+ return;
+
+ irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_DELETE_NODE);
+ vsi->unregister_qset(vsi, tc_node);
+ list_del(&tc_node->siblings);
+ irdma_free_node(vsi, tc_node);
+ /* Check if VSI node can be freed */
+ if (list_empty(&vsi_node->child_list_head)) {
+ irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_DELETE_NODE);
+ list_del(&vsi_node->siblings);
+ irdma_free_node(vsi, vsi_node);
+ /* Free head node there are no remaining VSI nodes */
+ if (list_empty(&ws_tree_root->child_list_head)) {
+ irdma_ws_cqp_cmd(vsi, ws_tree_root,
+ IRDMA_OP_WS_DELETE_NODE);
+ irdma_free_node(vsi, ws_tree_root);
+ vsi->dev->ws_tree_root = NULL;
+ }
+ }
+}
+
+/**
+ * irdma_ws_add - Build work scheduler tree, set RDMA qs_handle
+ * @vsi: vsi pointer
+ * @user_pri: user priority
+ */
+enum irdma_status_code irdma_ws_add(struct irdma_sc_vsi *vsi, u8 user_pri)
+{
+ struct irdma_ws_node *ws_tree_root;
+ struct irdma_ws_node *vsi_node;
+ struct irdma_ws_node *tc_node;
+ u16 traffic_class;
+ enum irdma_status_code ret = 0;
+ int i;
+
+ mutex_lock(&vsi->dev->ws_mutex);
+ if (vsi->tc_change_pending) {
+ ret = IRDMA_ERR_NOT_READY;
+ goto exit;
+ }
+
+ if (vsi->qos[user_pri].valid)
+ goto exit;
+
+ ws_tree_root = vsi->dev->ws_tree_root;
+ if (!ws_tree_root) {
+ ibdev_dbg(to_ibdev(vsi->dev), "WS: Creating root node\n");
+ ws_tree_root = irdma_alloc_node(vsi, user_pri,
+ WS_NODE_TYPE_PARENT, NULL);
+ if (!ws_tree_root) {
+ ret = IRDMA_ERR_NO_MEMORY;
+ goto exit;
+ }
+
+ ret = irdma_ws_cqp_cmd(vsi, ws_tree_root, IRDMA_OP_WS_ADD_NODE);
+ if (ret) {
+ irdma_free_node(vsi, ws_tree_root);
+ goto exit;
+ }
+
+ vsi->dev->ws_tree_root = ws_tree_root;
+ }
+
+ /* Find a second tier node that matches the VSI */
+ vsi_node = ws_find_node(ws_tree_root, vsi->vsi_idx,
+ WS_MATCH_TYPE_VSI);
+
+ /* If VSI node doesn't exist, add one */
+ if (!vsi_node) {
+ ibdev_dbg(to_ibdev(vsi->dev),
+ "WS: Node not found matching VSI %d\n",
+ vsi->vsi_idx);
+ vsi_node = irdma_alloc_node(vsi, user_pri, WS_NODE_TYPE_PARENT,
+ ws_tree_root);
+ if (!vsi_node) {
+ ret = IRDMA_ERR_NO_MEMORY;
+ goto vsi_add_err;
+ }
+
+ ret = irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_ADD_NODE);
+ if (ret) {
+ irdma_free_node(vsi, vsi_node);
+ goto vsi_add_err;
+ }
+
+ list_add(&vsi_node->siblings, &ws_tree_root->child_list_head);
+ }
+
+ ibdev_dbg(to_ibdev(vsi->dev),
+ "WS: Using node %d which represents VSI %d\n",
+ vsi_node->index, vsi->vsi_idx);
+ traffic_class = vsi->qos[user_pri].traffic_class;
+ tc_node = ws_find_node(vsi_node, traffic_class,
+ WS_MATCH_TYPE_TC);
+ if (!tc_node) {
+ /* Add leaf node */
+ ibdev_dbg(to_ibdev(vsi->dev),
+ "WS: Node not found matching VSI %d and TC %d\n",
+ vsi->vsi_idx, traffic_class);
+ tc_node = irdma_alloc_node(vsi, user_pri, WS_NODE_TYPE_LEAF,
+ vsi_node);
+ if (!tc_node) {
+ ret = IRDMA_ERR_NO_MEMORY;
+ goto leaf_add_err;
+ }
+
+ ret = irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_ADD_NODE);
+ if (ret) {
+ irdma_free_node(vsi, tc_node);
+ goto leaf_add_err;
+ }
+
+ list_add(&tc_node->siblings, &vsi_node->child_list_head);
+ /*
+ * callback to LAN to update the LAN tree with our node
+ */
+ ret = vsi->register_qset(vsi, tc_node);
+ if (ret)
+ goto reg_err;
+
+ tc_node->enable = true;
+ ret = irdma_ws_cqp_cmd(vsi, tc_node, IRDMA_OP_WS_MODIFY_NODE);
+ if (ret)
+ goto reg_err;
+ }
+ ibdev_dbg(to_ibdev(vsi->dev),
+ "WS: Using node %d which represents VSI %d TC %d\n",
+ tc_node->index, vsi->vsi_idx, traffic_class);
+ /*
+ * Iterate through other UPs and update the QS handle if they have
+ * a matching traffic class.
+ */
+ for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
+ if (vsi->qos[i].traffic_class == traffic_class) {
+ vsi->qos[i].qs_handle = tc_node->qs_handle;
+ vsi->qos[i].lan_qos_handle = tc_node->lan_qs_handle;
+ vsi->qos[i].l2_sched_node_id = tc_node->l2_sched_node_id;
+ vsi->qos[i].valid = true;
+ }
+ }
+ goto exit;
+
+leaf_add_err:
+ if (list_empty(&vsi_node->child_list_head)) {
+ if (irdma_ws_cqp_cmd(vsi, vsi_node, IRDMA_OP_WS_DELETE_NODE))
+ goto exit;
+ list_del(&vsi_node->siblings);
+ irdma_free_node(vsi, vsi_node);
+ }
+
+vsi_add_err:
+ /* Free head node there are no remaining VSI nodes */
+ if (list_empty(&ws_tree_root->child_list_head)) {
+ irdma_ws_cqp_cmd(vsi, ws_tree_root, IRDMA_OP_WS_DELETE_NODE);
+ vsi->dev->ws_tree_root = NULL;
+ irdma_free_node(vsi, ws_tree_root);
+ }
+
+exit:
+ mutex_unlock(&vsi->dev->ws_mutex);
+ return ret;
+
+reg_err:
+ mutex_unlock(&vsi->dev->ws_mutex);
+ irdma_ws_remove(vsi, user_pri);
+ return ret;
+}
+
+/**
+ * irdma_ws_remove - Free WS scheduler node, update WS tree
+ * @vsi: vsi pointer
+ * @user_pri: user priority
+ */
+void irdma_ws_remove(struct irdma_sc_vsi *vsi, u8 user_pri)
+{
+ mutex_lock(&vsi->dev->ws_mutex);
+ if (irdma_tc_in_use(vsi, user_pri))
+ goto exit;
+ irdma_remove_leaf(vsi, user_pri);
+exit:
+ mutex_unlock(&vsi->dev->ws_mutex);
+}
+
+/**
+ * irdma_ws_reset - Reset entire WS tree
+ * @vsi: vsi pointer
+ */
+void irdma_ws_reset(struct irdma_sc_vsi *vsi)
+{
+ u8 i;
+
+ mutex_lock(&vsi->dev->ws_mutex);
+ for (i = 0; i < IRDMA_MAX_USER_PRIORITY; ++i)
+ irdma_remove_leaf(vsi, i);
+ mutex_unlock(&vsi->dev->ws_mutex);
+}
diff --git a/drivers/infiniband/hw/irdma/ws.h b/drivers/infiniband/hw/irdma/ws.h
new file mode 100644
index 000000000000..f0e16f630701
--- /dev/null
+++ b/drivers/infiniband/hw/irdma/ws.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB */
+/* Copyright (c) 2015 - 2020 Intel Corporation */
+#ifndef IRDMA_WS_H
+#define IRDMA_WS_H
+
+#include "osdep.h"
+
+enum irdma_ws_node_type {
+ WS_NODE_TYPE_PARENT,
+ WS_NODE_TYPE_LEAF,
+};
+
+enum irdma_ws_match_type {
+ WS_MATCH_TYPE_VSI,
+ WS_MATCH_TYPE_TC,
+};
+
+struct irdma_ws_node {
+ struct list_head siblings;
+ struct list_head child_list_head;
+ struct irdma_ws_node *parent;
+ u64 lan_qs_handle; /* opaque handle used by LAN */
+ u32 l2_sched_node_id;
+ u16 index;
+ u16 qs_handle;
+ u16 vsi_index;
+ u8 traffic_class;
+ u8 user_pri;
+ u8 rel_bw;
+ u8 abstraction_layer; /* used for splitting a TC */
+ u8 prio_type;
+ bool type_leaf:1;
+ bool enable:1;
+};
+
+struct irdma_sc_vsi;
+enum irdma_status_code irdma_ws_add(struct irdma_sc_vsi *vsi, u8 user_pri);
+void irdma_ws_remove(struct irdma_sc_vsi *vsi, u8 user_pri);
+void irdma_ws_reset(struct irdma_sc_vsi *vsi);
+
+#endif /* IRDMA_WS_H */
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index e9b5a4d57fb1..4cd738aae53c 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -135,7 +135,7 @@ static void mlx4_ib_free_cq_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq_buf *
mlx4_buf_free(dev->dev, (cqe + 1) * buf->entry_size, &buf->buf);
}
-static int mlx4_ib_get_cq_umem(struct mlx4_ib_dev *dev, struct ib_udata *udata,
+static int mlx4_ib_get_cq_umem(struct mlx4_ib_dev *dev,
struct mlx4_ib_cq_buf *buf,
struct ib_umem **umem, u64 buf_addr, int cqe)
{
@@ -210,7 +210,7 @@ int mlx4_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
}
buf_addr = (void *)(unsigned long)ucmd.buf_addr;
- err = mlx4_ib_get_cq_umem(dev, udata, &cq->buf, &cq->umem,
+ err = mlx4_ib_get_cq_umem(dev, &cq->buf, &cq->umem,
ucmd.buf_addr, entries);
if (err)
goto err_cq;
@@ -327,8 +327,8 @@ static int mlx4_alloc_resize_umem(struct mlx4_ib_dev *dev, struct mlx4_ib_cq *cq
if (!cq->resize_buf)
return -ENOMEM;
- err = mlx4_ib_get_cq_umem(dev, udata, &cq->resize_buf->buf,
- &cq->resize_umem, ucmd.buf_addr, entries);
+ err = mlx4_ib_get_cq_umem(dev, &cq->resize_buf->buf, &cq->resize_umem,
+ ucmd.buf_addr, entries);
if (err) {
kfree(cq->resize_buf);
cq->resize_buf = NULL;
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 230a6ae0ab5a..ae4c91b612ce 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -2099,17 +2099,29 @@ static const struct diag_counter diag_device_only[] = {
DIAG_COUNTER(rq_num_udsdprd, 0x118),
};
-static struct rdma_hw_stats *mlx4_ib_alloc_hw_stats(struct ib_device *ibdev,
- u32 port_num)
+static struct rdma_hw_stats *
+mlx4_ib_alloc_hw_device_stats(struct ib_device *ibdev)
{
struct mlx4_ib_dev *dev = to_mdev(ibdev);
struct mlx4_ib_diag_counters *diag = dev->diag_counters;
- if (!diag[!!port_num].name)
+ if (!diag[0].name)
return NULL;
- return rdma_alloc_hw_stats_struct(diag[!!port_num].name,
- diag[!!port_num].num_counters,
+ return rdma_alloc_hw_stats_struct(diag[0].name, diag[0].num_counters,
+ RDMA_HW_STATS_DEFAULT_LIFESPAN);
+}
+
+static struct rdma_hw_stats *
+mlx4_ib_alloc_hw_port_stats(struct ib_device *ibdev, u32 port_num)
+{
+ struct mlx4_ib_dev *dev = to_mdev(ibdev);
+ struct mlx4_ib_diag_counters *diag = dev->diag_counters;
+
+ if (!diag[1].name)
+ return NULL;
+
+ return rdma_alloc_hw_stats_struct(diag[1].name, diag[1].num_counters,
RDMA_HW_STATS_DEFAULT_LIFESPAN);
}
@@ -2200,7 +2212,8 @@ static void mlx4_ib_fill_diag_counters(struct mlx4_ib_dev *ibdev,
}
static const struct ib_device_ops mlx4_ib_hw_stats_ops = {
- .alloc_hw_stats = mlx4_ib_alloc_hw_stats,
+ .alloc_hw_device_stats = mlx4_ib_alloc_hw_device_stats,
+ .alloc_hw_port_stats = mlx4_ib_alloc_hw_port_stats,
.get_hw_stats = mlx4_ib_get_hw_stats,
};
@@ -2528,6 +2541,7 @@ static const struct ib_device_ops mlx4_ib_dev_ops = {
.destroy_qp = mlx4_ib_destroy_qp,
.destroy_srq = mlx4_ib_destroy_srq,
.detach_mcast = mlx4_ib_mcg_detach,
+ .device_group = &mlx4_attr_group,
.disassociate_ucontext = mlx4_ib_disassociate_ucontext,
.drain_rq = mlx4_ib_drain_rq,
.drain_sq = mlx4_ib_drain_sq,
@@ -2787,7 +2801,6 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
if (mlx4_ib_alloc_diag_counters(ibdev))
goto err_steer_free_bitmap;
- rdma_set_device_sysfs_group(&ibdev->ib_dev, &mlx4_attr_group);
if (ib_register_device(&ibdev->ib_dev, "mlx4_%d",
&dev->persist->pdev->dev))
goto err_diag_counters;
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 92ddbcc00eb2..4a2ef7daaded 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -3144,7 +3144,7 @@ static int build_mlx_header(struct mlx4_ib_qp *qp, const struct ib_ud_wr *wr,
mlx->sched_prio = cpu_to_be16(pcp);
ether_addr_copy(sqp->ud_header.eth.smac_h, ah->av.eth.s_mac);
- memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6);
+ ether_addr_copy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac);
memcpy(&ctrl->srcrb_flags16[0], ah->av.eth.mac, 2);
memcpy(&ctrl->imm, ah->av.eth.mac + 2, 4);
@@ -4251,13 +4251,8 @@ int mlx4_ib_modify_wq(struct ib_wq *ibwq, struct ib_wq_attr *wq_attr,
if (wq_attr_mask & IB_WQ_FLAGS)
return -EOPNOTSUPP;
- cur_state = wq_attr_mask & IB_WQ_CUR_STATE ? wq_attr->curr_wq_state :
- ibwq->state;
- new_state = wq_attr_mask & IB_WQ_STATE ? wq_attr->wq_state : cur_state;
-
- if (cur_state < IB_WQS_RESET || cur_state > IB_WQS_ERR ||
- new_state < IB_WQS_RESET || new_state > IB_WQS_ERR)
- return -EINVAL;
+ cur_state = wq_attr->curr_wq_state;
+ new_state = wq_attr->wq_state;
if ((new_state == IB_WQS_RDY) && (cur_state == IB_WQS_ERR))
return -EINVAL;
diff --git a/drivers/infiniband/hw/mlx5/counters.c b/drivers/infiniband/hw/mlx5/counters.c
index e365341057cb..224ba36f2946 100644
--- a/drivers/infiniband/hw/mlx5/counters.c
+++ b/drivers/infiniband/hw/mlx5/counters.c
@@ -161,22 +161,29 @@ u16 mlx5_ib_get_counters_id(struct mlx5_ib_dev *dev, u32 port_num)
return cnts->set_id;
}
-static struct rdma_hw_stats *mlx5_ib_alloc_hw_stats(struct ib_device *ibdev,
- u32 port_num)
+static struct rdma_hw_stats *
+mlx5_ib_alloc_hw_device_stats(struct ib_device *ibdev)
{
struct mlx5_ib_dev *dev = to_mdev(ibdev);
- const struct mlx5_ib_counters *cnts;
- bool is_switchdev = is_mdev_switchdev_mode(dev->mdev);
+ const struct mlx5_ib_counters *cnts = &dev->port[0].cnts;
- if ((is_switchdev && port_num) || (!is_switchdev && !port_num))
- return NULL;
+ return rdma_alloc_hw_stats_struct(cnts->names,
+ cnts->num_q_counters +
+ cnts->num_cong_counters +
+ cnts->num_ext_ppcnt_counters,
+ RDMA_HW_STATS_DEFAULT_LIFESPAN);
+}
- cnts = get_counters(dev, port_num - 1);
+static struct rdma_hw_stats *
+mlx5_ib_alloc_hw_port_stats(struct ib_device *ibdev, u32 port_num)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibdev);
+ const struct mlx5_ib_counters *cnts = &dev->port[port_num - 1].cnts;
return rdma_alloc_hw_stats_struct(cnts->names,
cnts->num_q_counters +
- cnts->num_cong_counters +
- cnts->num_ext_ppcnt_counters,
+ cnts->num_cong_counters +
+ cnts->num_ext_ppcnt_counters,
RDMA_HW_STATS_DEFAULT_LIFESPAN);
}
@@ -666,7 +673,17 @@ void mlx5_ib_counters_clear_description(struct ib_counters *counters)
}
static const struct ib_device_ops hw_stats_ops = {
- .alloc_hw_stats = mlx5_ib_alloc_hw_stats,
+ .alloc_hw_port_stats = mlx5_ib_alloc_hw_port_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 const struct ib_device_ops hw_switchdev_stats_ops = {
+ .alloc_hw_device_stats = mlx5_ib_alloc_hw_device_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,
@@ -690,7 +707,10 @@ int mlx5_ib_counters_init(struct mlx5_ib_dev *dev)
if (!MLX5_CAP_GEN(dev->mdev, max_qp_cnt))
return 0;
- ib_set_device_ops(&dev->ib_dev, &hw_stats_ops);
+ if (is_mdev_switchdev_mode(dev->mdev))
+ ib_set_device_ops(&dev->ib_dev, &hw_switchdev_stats_ops);
+ else
+ ib_set_device_ops(&dev->ib_dev, &hw_stats_ops);
return mlx5_ib_alloc_counters(dev);
}
diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c
index 9ce01f729673..7abeb576b3c5 100644
--- a/drivers/infiniband/hw/mlx5/cq.c
+++ b/drivers/infiniband/hw/mlx5/cq.c
@@ -227,7 +227,7 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe,
wc->dlid_path_bits = cqe->ml_path;
g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3;
wc->wc_flags |= g ? IB_WC_GRH : 0;
- if (unlikely(is_qp1(qp->ibqp.qp_type))) {
+ if (is_qp1(qp->type)) {
u16 pkey = be32_to_cpu(cqe->pkey) & 0xffff;
ib_find_cached_pkey(&dev->ib_dev, qp->port, pkey,
@@ -725,7 +725,8 @@ static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata,
return -EFAULT;
if ((ucmd.flags & ~(MLX5_IB_CREATE_CQ_FLAGS_CQE_128B_PAD |
- MLX5_IB_CREATE_CQ_FLAGS_UAR_PAGE_INDEX)))
+ MLX5_IB_CREATE_CQ_FLAGS_UAR_PAGE_INDEX |
+ MLX5_IB_CREATE_CQ_FLAGS_REAL_TIME_TS)))
return -EINVAL;
if ((ucmd.cqe_size != 64 && ucmd.cqe_size != 128) ||
@@ -750,7 +751,7 @@ static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata,
goto err_umem;
}
- err = mlx5_ib_db_map_user(context, udata, ucmd.db_addr, &cq->db);
+ err = mlx5_ib_db_map_user(context, ucmd.db_addr, &cq->db);
if (err)
goto err_umem;
@@ -826,6 +827,9 @@ static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata,
cq->private_flags |= MLX5_IB_CQ_PR_FLAGS_CQE_128_PAD;
}
+ if (ucmd.flags & MLX5_IB_CREATE_CQ_FLAGS_REAL_TIME_TS)
+ cq->private_flags |= MLX5_IB_CQ_PR_FLAGS_REAL_TIME_TS;
+
MLX5_SET(create_cq_in, *cqb, uid, context->devx_uid);
return 0;
diff --git a/drivers/infiniband/hw/mlx5/doorbell.c b/drivers/infiniband/hw/mlx5/doorbell.c
index 7af4df7a6823..9ca2e61807ec 100644
--- a/drivers/infiniband/hw/mlx5/doorbell.c
+++ b/drivers/infiniband/hw/mlx5/doorbell.c
@@ -44,8 +44,7 @@ struct mlx5_ib_user_db_page {
struct mm_struct *mm;
};
-int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context,
- struct ib_udata *udata, unsigned long virt,
+int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt,
struct mlx5_db *db)
{
struct mlx5_ib_user_db_page *page;
diff --git a/drivers/infiniband/hw/mlx5/fs.c b/drivers/infiniband/hw/mlx5/fs.c
index 18ee2f293825..5fbc0a8454b9 100644
--- a/drivers/infiniband/hw/mlx5/fs.c
+++ b/drivers/infiniband/hw/mlx5/fs.c
@@ -2285,6 +2285,7 @@ static int mlx5_ib_flow_action_create_packet_reformat_ctx(
u8 ft_type, u8 dv_prt,
void *in, size_t len)
{
+ struct mlx5_pkt_reformat_params reformat_params;
enum mlx5_flow_namespace_type namespace;
u8 prm_prt;
int ret;
@@ -2297,9 +2298,13 @@ static int mlx5_ib_flow_action_create_packet_reformat_ctx(
if (ret)
return ret;
+ memset(&reformat_params, 0, sizeof(reformat_params));
+ reformat_params.type = prm_prt;
+ reformat_params.size = len;
+ reformat_params.data = in;
maction->flow_action_raw.pkt_reformat =
- mlx5_packet_reformat_alloc(dev->mdev, prm_prt, len,
- in, namespace);
+ mlx5_packet_reformat_alloc(dev->mdev, &reformat_params,
+ namespace);
if (IS_ERR(maction->flow_action_raw.pkt_reformat)) {
ret = PTR_ERR(maction->flow_action_raw.pkt_reformat);
return ret;
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 644d5d0ac544..094c976b1eed 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -1816,7 +1816,17 @@ static int set_ucontext_resp(struct ib_ucontext *uctx,
if (MLX5_CAP_GEN(dev->mdev, ece_support))
resp->comp_mask |= MLX5_IB_ALLOC_UCONTEXT_RESP_MASK_ECE;
+ if (rt_supported(MLX5_CAP_GEN(dev->mdev, sq_ts_format)) &&
+ rt_supported(MLX5_CAP_GEN(dev->mdev, rq_ts_format)) &&
+ rt_supported(MLX5_CAP_ROCE(dev->mdev, qp_ts_format)))
+ resp->comp_mask |=
+ MLX5_IB_ALLOC_UCONTEXT_RESP_MASK_REAL_TIME_TS;
+
resp->num_dyn_bfregs = bfregi->num_dyn_bfregs;
+
+ if (MLX5_CAP_GEN(dev->mdev, drain_sigerr))
+ resp->comp_mask |= MLX5_IB_ALLOC_UCONTEXT_RESP_MASK_SQD2RTS;
+
return 0;
}
@@ -3178,8 +3188,6 @@ static void mlx5_ib_unbind_slave_port(struct mlx5_ib_dev *ibdev,
port->mp.mpi = NULL;
- list_add_tail(&mpi->list, &mlx5_ib_unaffiliated_port_list);
-
spin_unlock(&port->mp.mpi_lock);
err = mlx5_nic_vport_unaffiliate_multiport(mpi->mdev);
@@ -3327,7 +3335,10 @@ static void mlx5_ib_cleanup_multiport_master(struct mlx5_ib_dev *dev)
} else {
mlx5_ib_dbg(dev, "unbinding port_num: %u\n",
i + 1);
- mlx5_ib_unbind_slave_port(dev, dev->port[i].mp.mpi);
+ list_add_tail(&dev->port[i].mp.mpi->list,
+ &mlx5_ib_unaffiliated_port_list);
+ mlx5_ib_unbind_slave_port(dev,
+ dev->port[i].mp.mpi);
}
}
}
@@ -3738,6 +3749,7 @@ static const struct ib_device_ops mlx5_ib_dev_ops = {
.disassociate_ucontext = mlx5_ib_disassociate_ucontext,
.drain_rq = mlx5_ib_drain_rq,
.drain_sq = mlx5_ib_drain_sq,
+ .device_group = &mlx5_attr_group,
.enable_driver = mlx5_ib_enable_driver,
.get_dev_fw_str = get_dev_fw_str,
.get_dma_mr = mlx5_ib_get_dma_mr,
@@ -4025,7 +4037,6 @@ static int mlx5_ib_stage_ib_reg_init(struct mlx5_ib_dev *dev)
{
const char *name;
- rdma_set_device_sysfs_group(&dev->ib_dev, &mlx5_attr_group);
if (!mlx5_lag_is_roce(dev->mdev))
name = "mlx5_%d";
else
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
index e9a3f34a30b8..585fb00bdce8 100644
--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -512,7 +512,6 @@ struct mlx5_ib_qp {
/*
* IB/core doesn't store low-level QP types, so
* store both MLX and IBTA types in the field below.
- * IB_QPT_DRIVER will be break to DCI/DCT subtypes.
*/
enum ib_qp_type type;
/* A flag to indicate if there's a new counter is configured
@@ -550,6 +549,7 @@ static inline const struct mlx5_umr_wr *umr_wr(const struct ib_send_wr *wr)
enum mlx5_ib_cq_pr_flags {
MLX5_IB_CQ_PR_FLAGS_CQE_128_PAD = 1 << 0,
+ MLX5_IB_CQ_PR_FLAGS_REAL_TIME_TS = 1 << 1,
};
struct mlx5_ib_cq {
@@ -1198,8 +1198,7 @@ to_mmmap(struct rdma_user_mmap_entry *rdma_entry)
struct mlx5_user_mmap_entry, rdma_entry);
}
-int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context,
- struct ib_udata *udata, unsigned long virt,
+int mlx5_ib_db_map_user(struct mlx5_ib_ucontext *context, unsigned long virt,
struct mlx5_db *db);
void mlx5_ib_db_unmap_user(struct mlx5_ib_ucontext *context, struct mlx5_db *db);
void __mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq);
@@ -1265,7 +1264,6 @@ int mlx5_ib_update_xlt(struct mlx5_ib_mr *mr, u64 idx, int npages,
int page_shift, int flags);
int mlx5_ib_update_mr_pas(struct mlx5_ib_mr *mr, unsigned int flags);
struct mlx5_ib_mr *mlx5_ib_alloc_implicit_mr(struct mlx5_ib_pd *pd,
- struct ib_udata *udata,
int access_flags);
void mlx5_ib_free_implicit_mr(struct mlx5_ib_mr *mr);
void mlx5_ib_free_odp_mr(struct mlx5_ib_mr *mr);
@@ -1614,4 +1612,10 @@ static inline bool mlx5_ib_lag_should_assign_affinity(struct mlx5_ib_dev *dev)
(MLX5_CAP_GEN(dev->mdev, num_lag_ports) > 1 &&
MLX5_CAP_GEN(dev->mdev, lag_tx_port_affinity));
}
+
+static inline bool rt_supported(int ts_cap)
+{
+ return ts_cap == MLX5_TIMESTAMP_FORMAT_CAP_REAL_TIME ||
+ ts_cap == MLX5_TIMESTAMP_FORMAT_CAP_FREE_RUNNING_AND_REAL_TIME;
+}
#endif /* MLX5_IB_H */
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index 425423dfac72..3263851ea574 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -68,6 +68,7 @@ static void set_mkc_access_pd_addr_fields(void *mkc, int acc, u64 start_addr,
struct ib_pd *pd)
{
struct mlx5_ib_dev *dev = to_mdev(pd->device);
+ bool ro_pci_enabled = pcie_relaxed_ordering_enabled(dev->mdev->pdev);
MLX5_SET(mkc, mkc, a, !!(acc & IB_ACCESS_REMOTE_ATOMIC));
MLX5_SET(mkc, mkc, rw, !!(acc & IB_ACCESS_REMOTE_WRITE));
@@ -77,10 +78,10 @@ static void set_mkc_access_pd_addr_fields(void *mkc, int acc, u64 start_addr,
if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write))
MLX5_SET(mkc, mkc, relaxed_ordering_write,
- !!(acc & IB_ACCESS_RELAXED_ORDERING));
+ (acc & IB_ACCESS_RELAXED_ORDERING) && ro_pci_enabled);
if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read))
MLX5_SET(mkc, mkc, relaxed_ordering_read,
- !!(acc & IB_ACCESS_RELAXED_ORDERING));
+ (acc & IB_ACCESS_RELAXED_ORDERING) && ro_pci_enabled);
MLX5_SET(mkc, mkc, pd, to_mpd(pd)->pdn);
MLX5_SET(mkc, mkc, qpn, 0xffffff);
@@ -811,7 +812,8 @@ struct ib_mr *mlx5_ib_get_dma_mr(struct ib_pd *pd, int acc)
MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA);
MLX5_SET(mkc, mkc, length64, 1);
- set_mkc_access_pd_addr_fields(mkc, acc, 0, pd);
+ set_mkc_access_pd_addr_fields(mkc, acc | IB_ACCESS_RELAXED_ORDERING, 0,
+ pd);
err = mlx5_ib_create_mkey(dev, &mr->mmkey, in, inlen);
if (err)
@@ -1510,7 +1512,7 @@ static struct ib_mr *create_user_odp_mr(struct ib_pd *pd, u64 start, u64 length,
if (!(dev->odp_caps.general_caps & IB_ODP_SUPPORT_IMPLICIT))
return ERR_PTR(-EINVAL);
- mr = mlx5_ib_alloc_implicit_mr(to_mpd(pd), udata, access_flags);
+ mr = mlx5_ib_alloc_implicit_mr(to_mpd(pd), access_flags);
if (IS_ERR(mr))
return ERR_CAST(mr);
return &mr->ibmr;
@@ -2010,7 +2012,7 @@ static void mlx5_set_umr_free_mkey(struct ib_pd *pd, u32 *in, int ndescs,
mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
/* This is only used from the kernel, so setting the PD is OK. */
- set_mkc_access_pd_addr_fields(mkc, 0, 0, pd);
+ set_mkc_access_pd_addr_fields(mkc, IB_ACCESS_RELAXED_ORDERING, 0, pd);
MLX5_SET(mkc, mkc, free, 1);
MLX5_SET(mkc, mkc, translations_octword_size, ndescs);
MLX5_SET(mkc, mkc, access_mode_1_0, access_mode & 0x3);
diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c
index 782b2af8f211..d0d98e584ebc 100644
--- a/drivers/infiniband/hw/mlx5/odp.c
+++ b/drivers/infiniband/hw/mlx5/odp.c
@@ -418,7 +418,7 @@ static struct mlx5_ib_mr *implicit_get_child_mr(struct mlx5_ib_mr *imr,
if (IS_ERR(odp))
return ERR_CAST(odp);
- ret = mr = mlx5_mr_cache_alloc(
+ mr = mlx5_mr_cache_alloc(
mr_to_mdev(imr), MLX5_IMR_MTT_CACHE_ENTRY, imr->access_flags);
if (IS_ERR(mr)) {
ib_umem_odp_release(odp);
@@ -478,7 +478,6 @@ out_mr:
}
struct mlx5_ib_mr *mlx5_ib_alloc_implicit_mr(struct mlx5_ib_pd *pd,
- struct ib_udata *udata,
int access_flags)
{
struct mlx5_ib_dev *dev = to_mdev(pd->ibpd.device);
@@ -1096,7 +1095,7 @@ static int mlx5_ib_mr_initiator_pfault_handler(
opcode = be32_to_cpu(ctrl->opmod_idx_opcode) &
MLX5_WQE_CTRL_OPCODE_MASK;
- if (qp->ibqp.qp_type == IB_QPT_XRC_INI)
+ if (qp->type == IB_QPT_XRC_INI)
*wqe += sizeof(struct mlx5_wqe_xrc_seg);
if (qp->type == IB_QPT_UD || qp->type == MLX5_IB_QPT_DCI) {
@@ -1559,12 +1558,16 @@ int mlx5r_odp_create_eq(struct mlx5_ib_dev *dev, struct mlx5_ib_pf_eq *eq)
}
eq->irq_nb.notifier_call = mlx5_ib_eq_pf_int;
- param = (struct mlx5_eq_param){
- .irq_index = 0,
+ param = (struct mlx5_eq_param) {
.nent = MLX5_IB_NUM_PF_EQE,
};
param.mask[0] = 1ull << MLX5_EVENT_TYPE_PAGE_FAULT;
+ if (!zalloc_cpumask_var(&param.affinity, GFP_KERNEL)) {
+ err = -ENOMEM;
+ goto err_wq;
+ }
eq->core = mlx5_eq_create_generic(dev->mdev, &param);
+ free_cpumask_var(param.affinity);
if (IS_ERR(eq->core)) {
err = PTR_ERR(eq->core);
goto err_wq;
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
index 9282eb10bfae..a77db29f8391 100644
--- a/drivers/infiniband/hw/mlx5/qp.c
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -835,7 +835,7 @@ static int create_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd,
ib_umem_num_pages(rwq->umem), page_size, rwq->rq_num_pas,
offset);
- err = mlx5_ib_db_map_user(ucontext, udata, ucmd->db_addr, &rwq->db);
+ err = mlx5_ib_db_map_user(ucontext, ucmd->db_addr, &rwq->db);
if (err) {
mlx5_ib_dbg(dev, "map failed\n");
goto err_umem;
@@ -961,7 +961,7 @@ static int _create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,
resp->bfreg_index = MLX5_IB_INVALID_BFREG;
qp->bfregn = bfregn;
- err = mlx5_ib_db_map_user(context, udata, ucmd->db_addr, &qp->db);
+ err = mlx5_ib_db_map_user(context, ucmd->db_addr, &qp->db);
if (err) {
mlx5_ib_dbg(dev, "map failed\n");
goto err_free;
@@ -1173,69 +1173,79 @@ static void destroy_flow_rule_vport_sq(struct mlx5_ib_sq *sq)
sq->flow_rule = NULL;
}
-static int get_rq_ts_format(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *send_cq)
+static bool fr_supported(int ts_cap)
{
- bool fr_supported =
- MLX5_CAP_GEN(dev->mdev, rq_ts_format) ==
- MLX5_RQ_TIMESTAMP_FORMAT_CAP_FREE_RUNNING ||
- MLX5_CAP_GEN(dev->mdev, rq_ts_format) ==
- MLX5_RQ_TIMESTAMP_FORMAT_CAP_FREE_RUNNING_AND_REAL_TIME;
+ return ts_cap == MLX5_TIMESTAMP_FORMAT_CAP_FREE_RUNNING ||
+ ts_cap == MLX5_TIMESTAMP_FORMAT_CAP_FREE_RUNNING_AND_REAL_TIME;
+}
- if (send_cq->create_flags & IB_UVERBS_CQ_FLAGS_TIMESTAMP_COMPLETION) {
- if (!fr_supported) {
- mlx5_ib_dbg(dev, "Free running TS format is not supported\n");
+static int get_ts_format(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,
+ bool fr_sup, bool rt_sup)
+{
+ if (cq->private_flags & MLX5_IB_CQ_PR_FLAGS_REAL_TIME_TS) {
+ if (!rt_sup) {
+ mlx5_ib_dbg(dev,
+ "Real time TS format is not supported\n");
return -EOPNOTSUPP;
}
- return MLX5_RQC_TIMESTAMP_FORMAT_FREE_RUNNING;
+ return MLX5_TIMESTAMP_FORMAT_REAL_TIME;
}
- return fr_supported ? MLX5_RQC_TIMESTAMP_FORMAT_FREE_RUNNING :
- MLX5_RQC_TIMESTAMP_FORMAT_DEFAULT;
+ if (cq->create_flags & IB_UVERBS_CQ_FLAGS_TIMESTAMP_COMPLETION) {
+ if (!fr_sup) {
+ mlx5_ib_dbg(dev,
+ "Free running TS format is not supported\n");
+ return -EOPNOTSUPP;
+ }
+ return MLX5_TIMESTAMP_FORMAT_FREE_RUNNING;
+ }
+ return fr_sup ? MLX5_TIMESTAMP_FORMAT_FREE_RUNNING :
+ MLX5_TIMESTAMP_FORMAT_DEFAULT;
+}
+
+static int get_rq_ts_format(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *recv_cq)
+{
+ u8 ts_cap = MLX5_CAP_GEN(dev->mdev, rq_ts_format);
+
+ return get_ts_format(dev, recv_cq, fr_supported(ts_cap),
+ rt_supported(ts_cap));
}
static int get_sq_ts_format(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *send_cq)
{
- bool fr_supported =
- MLX5_CAP_GEN(dev->mdev, sq_ts_format) ==
- MLX5_SQ_TIMESTAMP_FORMAT_CAP_FREE_RUNNING ||
- MLX5_CAP_GEN(dev->mdev, sq_ts_format) ==
- MLX5_SQ_TIMESTAMP_FORMAT_CAP_FREE_RUNNING_AND_REAL_TIME;
+ u8 ts_cap = MLX5_CAP_GEN(dev->mdev, sq_ts_format);
- if (send_cq->create_flags & IB_UVERBS_CQ_FLAGS_TIMESTAMP_COMPLETION) {
- if (!fr_supported) {
- mlx5_ib_dbg(dev, "Free running TS format is not supported\n");
- return -EOPNOTSUPP;
- }
- return MLX5_SQC_TIMESTAMP_FORMAT_FREE_RUNNING;
- }
- return fr_supported ? MLX5_SQC_TIMESTAMP_FORMAT_FREE_RUNNING :
- MLX5_SQC_TIMESTAMP_FORMAT_DEFAULT;
+ return get_ts_format(dev, send_cq, fr_supported(ts_cap),
+ rt_supported(ts_cap));
}
static int get_qp_ts_format(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *send_cq,
struct mlx5_ib_cq *recv_cq)
{
- bool fr_supported =
- MLX5_CAP_ROCE(dev->mdev, qp_ts_format) ==
- MLX5_QP_TIMESTAMP_FORMAT_CAP_FREE_RUNNING ||
- MLX5_CAP_ROCE(dev->mdev, qp_ts_format) ==
- MLX5_QP_TIMESTAMP_FORMAT_CAP_FREE_RUNNING_AND_REAL_TIME;
- int ts_format = fr_supported ? MLX5_QPC_TIMESTAMP_FORMAT_FREE_RUNNING :
- MLX5_QPC_TIMESTAMP_FORMAT_DEFAULT;
-
- if (recv_cq &&
- recv_cq->create_flags & IB_UVERBS_CQ_FLAGS_TIMESTAMP_COMPLETION)
- ts_format = MLX5_QPC_TIMESTAMP_FORMAT_FREE_RUNNING;
-
- if (send_cq &&
- send_cq->create_flags & IB_UVERBS_CQ_FLAGS_TIMESTAMP_COMPLETION)
- ts_format = MLX5_QPC_TIMESTAMP_FORMAT_FREE_RUNNING;
-
- if (ts_format == MLX5_QPC_TIMESTAMP_FORMAT_FREE_RUNNING &&
- !fr_supported) {
- mlx5_ib_dbg(dev, "Free running TS format is not supported\n");
+ u8 ts_cap = MLX5_CAP_ROCE(dev->mdev, qp_ts_format);
+ bool fr_sup = fr_supported(ts_cap);
+ bool rt_sup = rt_supported(ts_cap);
+ u8 default_ts = fr_sup ? MLX5_TIMESTAMP_FORMAT_FREE_RUNNING :
+ MLX5_TIMESTAMP_FORMAT_DEFAULT;
+ int send_ts_format =
+ send_cq ? get_ts_format(dev, send_cq, fr_sup, rt_sup) :
+ default_ts;
+ int recv_ts_format =
+ recv_cq ? get_ts_format(dev, recv_cq, fr_sup, rt_sup) :
+ default_ts;
+
+ if (send_ts_format < 0 || recv_ts_format < 0)
+ return -EOPNOTSUPP;
+
+ if (send_ts_format != MLX5_TIMESTAMP_FORMAT_DEFAULT &&
+ recv_ts_format != MLX5_TIMESTAMP_FORMAT_DEFAULT &&
+ send_ts_format != recv_ts_format) {
+ mlx5_ib_dbg(
+ dev,
+ "The send ts_format does not match the receive ts_format\n");
return -EOPNOTSUPP;
}
- return ts_format;
+
+ return send_ts_format == default_ts ? recv_ts_format : send_ts_format;
}
static int create_raw_packet_qp_sq(struct mlx5_ib_dev *dev,
@@ -3089,7 +3099,7 @@ int mlx5_ib_destroy_qp(struct ib_qp *qp, struct ib_udata *udata)
struct mlx5_ib_dev *dev = to_mdev(qp->device);
struct mlx5_ib_qp *mqp = to_mqp(qp);
- if (unlikely(qp->qp_type == IB_QPT_GSI))
+ if (mqp->type == IB_QPT_GSI)
return mlx5_ib_destroy_gsi(mqp);
if (mqp->type == MLX5_IB_QPT_DCT)
@@ -3128,7 +3138,7 @@ static int set_qpc_atomic_flags(struct mlx5_ib_qp *qp,
if (access_flags & IB_ACCESS_REMOTE_ATOMIC) {
int atomic_mode;
- atomic_mode = get_atomic_mode(dev, qp->ibqp.qp_type);
+ atomic_mode = get_atomic_mode(dev, qp->type);
if (atomic_mode < 0)
return -EOPNOTSUPP;
@@ -3300,10 +3310,10 @@ static int mlx5_set_path(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
ether_addr_copy(MLX5_ADDR_OF(ads, path, rmac_47_32),
ah->roce.dmac);
- if ((qp->ibqp.qp_type == IB_QPT_RC ||
- qp->ibqp.qp_type == IB_QPT_UC ||
- qp->ibqp.qp_type == IB_QPT_XRC_INI ||
- qp->ibqp.qp_type == IB_QPT_XRC_TGT) &&
+ if ((qp->type == IB_QPT_RC ||
+ qp->type == IB_QPT_UC ||
+ qp->type == IB_QPT_XRC_INI ||
+ qp->type == IB_QPT_XRC_TGT) &&
(grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) &&
(attr_mask & IB_QP_DEST_QPN))
mlx5_set_path_udp_sport(path, ah,
@@ -3342,7 +3352,7 @@ static int mlx5_set_path(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
MLX5_SET(ads, path, ack_timeout,
alt ? attr->alt_timeout : attr->timeout);
- if ((qp->ibqp.qp_type == IB_QPT_RAW_PACKET) && qp->sq.wqe_cnt)
+ if ((qp->type == IB_QPT_RAW_PACKET) && qp->sq.wqe_cnt)
return modify_raw_packet_eth_prio(dev->mdev,
&qp->raw_packet_qp.sq,
sl & 0xf, qp->ibqp.pd);
@@ -3453,6 +3463,17 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q
MLX5_QP_OPTPAR_RRE,
},
},
+ [MLX5_QP_STATE_SQD] = {
+ [MLX5_QP_STATE_RTS] = {
+ [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY,
+ [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_Q_KEY,
+ [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE,
+ [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RNR_TIMEOUT |
+ MLX5_QP_OPTPAR_RWE |
+ MLX5_QP_OPTPAR_RAE |
+ MLX5_QP_OPTPAR_RRE,
+ },
+ },
};
static int ib_nr_to_mlx5_nr(int ib_mask)
@@ -3848,6 +3869,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
[MLX5_QP_STATE_SQD] = {
[MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP,
[MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP,
+ [MLX5_QP_STATE_RTS] = MLX5_CMD_OP_SQD_RTS_QP,
},
[MLX5_QP_STATE_SQER] = {
[MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP,
@@ -3910,12 +3932,12 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
MLX5_CAP_GEN(dev->mdev, init2_lag_tx_port_affinity))
optpar |= MLX5_QP_OPTPAR_LAG_TX_AFF;
- if (is_sqp(ibqp->qp_type)) {
+ if (is_sqp(qp->type)) {
MLX5_SET(qpc, qpc, mtu, IB_MTU_256);
MLX5_SET(qpc, qpc, log_msg_max, 8);
- } else if ((ibqp->qp_type == IB_QPT_UD &&
+ } else if ((qp->type == IB_QPT_UD &&
!(qp->flags & IB_QP_CREATE_SOURCE_QPN)) ||
- ibqp->qp_type == MLX5_IB_QPT_REG_UMR) {
+ qp->type == MLX5_IB_QPT_REG_UMR) {
MLX5_SET(qpc, qpc, mtu, IB_MTU_4096);
MLX5_SET(qpc, qpc, log_msg_max, 12);
} else if (attr_mask & IB_QP_PATH_MTU) {
@@ -3941,7 +3963,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
/* todo implement counter_index functionality */
- if (is_sqp(ibqp->qp_type))
+ if (is_sqp(qp->type))
MLX5_SET(ads, pri_path, vhca_port_num, qp->port);
if (attr_mask & IB_QP_PORT)
@@ -3969,7 +3991,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
goto out;
}
- get_cqs(qp->ibqp.qp_type, qp->ibqp.send_cq, qp->ibqp.recv_cq,
+ get_cqs(qp->type, qp->ibqp.send_cq, qp->ibqp.recv_cq,
&send_cq, &recv_cq);
MLX5_SET(qpc, qpc, pd, pd ? pd->pdn : to_mpd(dev->devr.p0)->pdn);
@@ -4048,7 +4070,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
optpar |= ib_mask_to_mlx5_opt(attr_mask);
optpar &= opt_mask[mlx5_cur][mlx5_new][mlx5_st];
- if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET ||
+ if (qp->type == IB_QPT_RAW_PACKET ||
qp->flags & IB_QP_CREATE_SOURCE_QPN) {
struct mlx5_modify_raw_qp_param raw_qp_param = {};
@@ -4121,7 +4143,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
* entries and reinitialize the QP.
*/
if (new_state == IB_QPS_RESET &&
- !ibqp->uobject && ibqp->qp_type != IB_QPT_XRC_TGT) {
+ !ibqp->uobject && qp->type != IB_QPT_XRC_TGT) {
mlx5_ib_cq_clean(recv_cq, base->mqp.qpn,
ibqp->srq ? to_msrq(ibqp->srq) : NULL);
if (send_cq != recv_cq)
@@ -4314,13 +4336,12 @@ static int mlx5_ib_modify_dct(struct ib_qp *ibqp, struct ib_qp_attr *attr,
}
static bool mlx5_ib_modify_qp_allowed(struct mlx5_ib_dev *dev,
- struct mlx5_ib_qp *qp,
- enum ib_qp_type qp_type)
+ struct mlx5_ib_qp *qp)
{
if (dev->profile != &raw_eth_profile)
return true;
- if (qp_type == IB_QPT_RAW_PACKET || qp_type == MLX5_IB_QPT_REG_UMR)
+ if (qp->type == IB_QPT_RAW_PACKET || qp->type == MLX5_IB_QPT_REG_UMR)
return true;
/* Internal QP used for wc testing, with NOPs in wq */
@@ -4341,7 +4362,7 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
enum ib_qp_state cur_state, new_state;
int err = -EINVAL;
- if (!mlx5_ib_modify_qp_allowed(dev, qp, ibqp->qp_type))
+ if (!mlx5_ib_modify_qp_allowed(dev, qp))
return -EOPNOTSUPP;
if (attr_mask & ~(IB_QP_ATTR_STANDARD_BITS | IB_QP_RATE_LIMIT))
@@ -4370,11 +4391,10 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
}
- if (unlikely(ibqp->qp_type == IB_QPT_GSI))
+ if (qp->type == IB_QPT_GSI)
return mlx5_ib_gsi_modify_qp(ibqp, attr, attr_mask);
- qp_type = (unlikely(ibqp->qp_type == MLX5_IB_QPT_HW_GSI)) ? IB_QPT_GSI :
- qp->type;
+ qp_type = (qp->type == MLX5_IB_QPT_HW_GSI) ? IB_QPT_GSI : qp->type;
if (qp_type == MLX5_IB_QPT_DCT)
return mlx5_ib_modify_dct(ibqp, attr, attr_mask, &ucmd, udata);
@@ -4395,7 +4415,7 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
!ib_modify_qp_is_ok(cur_state, new_state, qp_type,
attr_mask)) {
mlx5_ib_dbg(dev, "invalid QP state transition from %d to %d, qp_type %d, attr_mask 0x%x\n",
- cur_state, new_state, ibqp->qp_type, attr_mask);
+ cur_state, new_state, qp->type, attr_mask);
goto out;
} else if (qp_type == MLX5_IB_QPT_DCI &&
!modify_dci_qp_is_ok(cur_state, new_state, attr_mask)) {
@@ -4668,9 +4688,8 @@ static int query_qp_attr(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
pri_path = MLX5_ADDR_OF(qpc, qpc, primary_address_path);
alt_path = MLX5_ADDR_OF(qpc, qpc, secondary_address_path);
- if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC ||
- qp->ibqp.qp_type == IB_QPT_XRC_INI ||
- qp->ibqp.qp_type == IB_QPT_XRC_TGT) {
+ if (qp->type == IB_QPT_RC || qp->type == IB_QPT_UC ||
+ qp->type == IB_QPT_XRC_INI || qp->type == IB_QPT_XRC_TGT) {
to_rdma_ah_attr(dev, &qp_attr->ah_attr, pri_path);
to_rdma_ah_attr(dev, &qp_attr->alt_ah_attr, alt_path);
qp_attr->alt_pkey_index = MLX5_GET(ads, alt_path, pkey_index);
@@ -4763,7 +4782,7 @@ int mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
if (ibqp->rwq_ind_tbl)
return -ENOSYS;
- if (unlikely(ibqp->qp_type == IB_QPT_GSI))
+ if (qp->type == IB_QPT_GSI)
return mlx5_ib_gsi_query_qp(ibqp, qp_attr, qp_attr_mask,
qp_init_attr);
@@ -4777,7 +4796,7 @@ int mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
mutex_lock(&qp->mutex);
- if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET ||
+ if (qp->type == IB_QPT_RAW_PACKET ||
qp->flags & IB_QP_CREATE_SOURCE_QPN) {
err = query_raw_packet_qp_state(dev, qp, &raw_packet_qp_state);
if (err)
@@ -4804,7 +4823,7 @@ int mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
qp_attr->cap.max_send_sge = 0;
}
- qp_init_attr->qp_type = ibqp->qp_type;
+ qp_init_attr->qp_type = qp->type;
qp_init_attr->recv_cq = ibqp->recv_cq;
qp_init_attr->send_cq = ibqp->send_cq;
qp_init_attr->srq = ibqp->srq;
@@ -5309,10 +5328,8 @@ int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr,
rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
- curr_wq_state = (wq_attr_mask & IB_WQ_CUR_STATE) ?
- wq_attr->curr_wq_state : wq->state;
- wq_state = (wq_attr_mask & IB_WQ_STATE) ?
- wq_attr->wq_state : curr_wq_state;
+ curr_wq_state = wq_attr->curr_wq_state;
+ wq_state = wq_attr->wq_state;
if (curr_wq_state == IB_WQS_ERR)
curr_wq_state = MLX5_RQC_STATE_ERR;
if (wq_state == IB_WQS_ERR)
diff --git a/drivers/infiniband/hw/mlx5/qpc.c b/drivers/infiniband/hw/mlx5/qpc.c
index c683d7000168..8844eacf2380 100644
--- a/drivers/infiniband/hw/mlx5/qpc.c
+++ b/drivers/infiniband/hw/mlx5/qpc.c
@@ -441,6 +441,12 @@ static int modify_qp_mbox_alloc(struct mlx5_core_dev *dev, u16 opcode, int qpn,
MOD_QP_IN_SET_QPC(sqerr2rts_qp, mbox->in, opcode, qpn,
opt_param_mask, qpc, uid);
break;
+ case MLX5_CMD_OP_SQD_RTS_QP:
+ if (MBOX_ALLOC(mbox, sqd2rts_qp))
+ return -ENOMEM;
+ MOD_QP_IN_SET_QPC(sqd2rts_qp, mbox->in, opcode, qpn,
+ opt_param_mask, qpc, uid);
+ break;
case MLX5_CMD_OP_INIT2INIT_QP:
if (MBOX_ALLOC(mbox, init2init_qp))
return -ENOMEM;
diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c
index fab6736e4d6a..191c4ee7db62 100644
--- a/drivers/infiniband/hw/mlx5/srq.c
+++ b/drivers/infiniband/hw/mlx5/srq.c
@@ -84,7 +84,7 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
}
in->umem = srq->umem;
- err = mlx5_ib_db_map_user(ucontext, udata, ucmd.db_addr, &srq->db);
+ err = mlx5_ib_db_map_user(ucontext, ucmd.db_addr, &srq->db);
if (err) {
mlx5_ib_dbg(dev, "map doorbell failed\n");
goto err_umem;
diff --git a/drivers/infiniband/hw/mlx5/wr.c b/drivers/infiniband/hw/mlx5/wr.c
index cf2852cba45c..8841620af82f 100644
--- a/drivers/infiniband/hw/mlx5/wr.c
+++ b/drivers/infiniband/hw/mlx5/wr.c
@@ -866,7 +866,10 @@ static int set_reg_wr(struct mlx5_ib_qp *qp,
bool atomic = wr->access & IB_ACCESS_REMOTE_ATOMIC;
u8 flags = 0;
- /* Matches access in mlx5_set_umr_free_mkey() */
+ /* Matches access in mlx5_set_umr_free_mkey().
+ * Relaxed Ordering is set implicitly in mlx5_set_umr_free_mkey() and
+ * kernel ULPs are not aware of it, so we don't set it here.
+ */
if (!mlx5_ib_can_reconfig_with_umr(dev, 0, wr->access)) {
mlx5_ib_warn(
to_mdev(qp->ibqp.device),
@@ -1278,7 +1281,7 @@ 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 mlx5_ib_qp *qp;
+ struct mlx5_ib_qp *qp = to_mqp(ibqp);
struct mlx5_wqe_xrc_seg *xrc;
struct mlx5_bf *bf;
void *cur_edge;
@@ -1299,10 +1302,9 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
return -EIO;
}
- if (unlikely(ibqp->qp_type == IB_QPT_GSI))
+ if (qp->type == IB_QPT_GSI)
return mlx5_ib_gsi_post_send(ibqp, wr, bad_wr);
- qp = to_mqp(ibqp);
bf = &qp->bf;
spin_lock_irqsave(&qp->sq.lock, flags);
@@ -1347,7 +1349,7 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
}
}
- switch (ibqp->qp_type) {
+ switch (qp->type) {
case IB_QPT_XRC_INI:
xrc = seg;
seg += sizeof(*xrc);
@@ -1476,7 +1478,7 @@ int mlx5_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
return -EIO;
}
- if (unlikely(ibqp->qp_type == IB_QPT_GSI))
+ if (qp->type == IB_QPT_GSI)
return mlx5_ib_gsi_post_recv(ibqp, wr, bad_wr);
spin_lock_irqsave(&qp->rq.lock, flags);
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 522bb606120e..adf4fcf0fee4 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -1099,6 +1099,7 @@ static const struct ib_device_ops mthca_dev_ops = {
.destroy_cq = mthca_destroy_cq,
.destroy_qp = mthca_destroy_qp,
.detach_mcast = mthca_multicast_detach,
+ .device_group = &mthca_attr_group,
.get_dev_fw_str = get_dev_fw_str,
.get_dma_mr = mthca_get_dma_mr,
.get_port_immutable = mthca_port_immutable,
@@ -1186,7 +1187,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);
ret = ib_register_device(&dev->ib_dev, "mthca%d", &dev->pdev->dev);
if (ret)
return ret;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index 4882b3156edb..f329db0c591f 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -161,6 +161,7 @@ static const struct ib_device_ops ocrdma_dev_ops = {
.destroy_ah = ocrdma_destroy_ah,
.destroy_cq = ocrdma_destroy_cq,
.destroy_qp = ocrdma_destroy_qp,
+ .device_group = &ocrdma_attr_group,
.get_dev_fw_str = get_dev_fw_str,
.get_dma_mr = ocrdma_get_dma_mr,
.get_link_layer = ocrdma_link_layer,
@@ -218,7 +219,6 @@ static int ocrdma_register_device(struct ocrdma_dev *dev)
if (ocrdma_get_asic_type(dev) == OCRDMA_ASIC_GEN_SKH_R)
ib_set_device_ops(&dev->ibdev, &ocrdma_dev_srq_ops);
- rdma_set_device_sysfs_group(&dev->ibdev, &ocrdma_attr_group);
ret = ib_device_set_netdev(&dev->ibdev, dev->nic_info.netdev, 1);
if (ret)
return ret;
diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c
index 8334a9850220..de98e0604f91 100644
--- a/drivers/infiniband/hw/qedr/main.c
+++ b/drivers/infiniband/hw/qedr/main.c
@@ -208,6 +208,7 @@ static const struct ib_device_ops qedr_dev_ops = {
.destroy_cq = qedr_destroy_cq,
.destroy_qp = qedr_destroy_qp,
.destroy_srq = qedr_destroy_srq,
+ .device_group = &qedr_attr_group,
.get_dev_fw_str = qedr_get_dev_fw_str,
.get_dma_mr = qedr_get_dma_mr,
.get_link_layer = qedr_link_layer,
@@ -256,7 +257,6 @@ static int qedr_register_device(struct qedr_dev *dev)
dev->ibdev.num_comp_vectors = dev->num_cnq;
dev->ibdev.dev.parent = &dev->pdev->dev;
- rdma_set_device_sysfs_group(&dev->ibdev, &qedr_attr_group);
ib_set_device_ops(&dev->ibdev, &qedr_dev_ops);
rc = ib_device_set_netdev(&dev->ibdev, dev->ndev, 1);
diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h
index 88497739029e..9363bccfc6e7 100644
--- a/drivers/infiniband/hw/qib/qib.h
+++ b/drivers/infiniband/hw/qib/qib.h
@@ -521,10 +521,6 @@ struct qib_pportdata {
struct qib_devdata *dd;
struct qib_chippport_specific *cpspec; /* chip-specific per-port */
- struct kobject pport_kobj;
- struct kobject pport_cc_kobj;
- struct kobject sl2vl_kobj;
- struct kobject diagc_kobj;
/* GUID for this interface, in network order */
__be64 guid;
@@ -1365,13 +1361,11 @@ static inline u32 qib_get_rcvhdrtail(const struct qib_ctxtdata *rcd)
extern const char ib_qib_version[];
extern const struct attribute_group qib_attr_group;
+extern const struct attribute_group *qib_attr_port_groups[];
int qib_device_create(struct qib_devdata *);
void qib_device_remove(struct qib_devdata *);
-int qib_create_port_files(struct ib_device *ibdev, u32 port_num,
- struct kobject *kobj);
-void qib_verbs_unregister_sysfs(struct qib_devdata *);
/* Hook for sysfs read of QSFP */
extern int qib_qsfp_dump(struct qib_pportdata *ppd, char *buf, int len);
diff --git a/drivers/infiniband/hw/qib/qib_sysfs.c b/drivers/infiniband/hw/qib/qib_sysfs.c
index 5e9e66f27064..d57e49de6650 100644
--- a/drivers/infiniband/hw/qib/qib_sysfs.c
+++ b/drivers/infiniband/hw/qib/qib_sysfs.c
@@ -32,25 +32,38 @@
* SOFTWARE.
*/
#include <linux/ctype.h>
+#include <rdma/ib_sysfs.h>
#include "qib.h"
#include "qib_mad.h"
-/* start of per-port functions */
+static struct qib_pportdata *qib_get_pportdata_kobj(struct kobject *kobj)
+{
+ u32 port_num;
+ struct ib_device *ibdev = ib_port_sysfs_get_ibdev_kobj(kobj, &port_num);
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+
+ return &dd->pport[port_num - 1];
+}
+
/*
* Get/Set heartbeat enable. OR of 1=enabled, 2=auto
*/
-static ssize_t show_hrtbt_enb(struct qib_pportdata *ppd, char *buf)
+static ssize_t hrtbt_enable_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
{
- struct qib_devdata *dd = ppd->dd;
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_pportdata *ppd = &dd->pport[port_num - 1];
return sysfs_emit(buf, "%d\n", dd->f_get_ib_cfg(ppd, QIB_IB_CFG_HRTBT));
}
-static ssize_t store_hrtbt_enb(struct qib_pportdata *ppd, const char *buf,
- size_t count)
+static ssize_t hrtbt_enable_store(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr,
+ const char *buf, size_t count)
{
- struct qib_devdata *dd = ppd->dd;
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_pportdata *ppd = &dd->pport[port_num - 1];
int ret;
u16 val;
@@ -70,11 +83,14 @@ static ssize_t store_hrtbt_enb(struct qib_pportdata *ppd, const char *buf,
ret = dd->f_set_ib_cfg(ppd, QIB_IB_CFG_HRTBT, val);
return ret < 0 ? ret : count;
}
+static IB_PORT_ATTR_RW(hrtbt_enable);
-static ssize_t store_loopback(struct qib_pportdata *ppd, const char *buf,
+static ssize_t loopback_store(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, const char *buf,
size_t count)
{
- struct qib_devdata *dd = ppd->dd;
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_pportdata *ppd = &dd->pport[port_num - 1];
int ret = count, r;
r = dd->f_set_ib_loopback(ppd, buf);
@@ -83,11 +99,14 @@ static ssize_t store_loopback(struct qib_pportdata *ppd, const char *buf,
return ret;
}
+static IB_PORT_ATTR_WO(loopback);
-static ssize_t store_led_override(struct qib_pportdata *ppd, const char *buf,
- size_t count)
+static ssize_t led_override_store(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr,
+ const char *buf, size_t count)
{
- struct qib_devdata *dd = ppd->dd;
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_pportdata *ppd = &dd->pport[port_num - 1];
int ret;
u16 val;
@@ -100,14 +119,20 @@ static ssize_t store_led_override(struct qib_pportdata *ppd, const char *buf,
qib_set_led_override(ppd, val);
return count;
}
+static IB_PORT_ATTR_WO(led_override);
-static ssize_t show_status(struct qib_pportdata *ppd, char *buf)
+static ssize_t status_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
{
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_pportdata *ppd = &dd->pport[port_num - 1];
+
if (!ppd->statusp)
return -EINVAL;
return sysfs_emit(buf, "0x%llx\n", (unsigned long long)*(ppd->statusp));
}
+static IB_PORT_ATTR_RO(status);
/*
* For userland compatibility, these offsets must remain fixed.
@@ -127,8 +152,11 @@ static const char * const qib_status_str[] = {
NULL,
};
-static ssize_t show_status_str(struct qib_pportdata *ppd, char *buf)
+static ssize_t status_str_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
{
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_pportdata *ppd = &dd->pport[port_num - 1];
int i, any;
u64 s;
ssize_t ret;
@@ -160,38 +188,22 @@ static ssize_t show_status_str(struct qib_pportdata *ppd, char *buf)
bail:
return ret;
}
+static IB_PORT_ATTR_RO(status_str);
/* end of per-port functions */
-/*
- * Start of per-port file structures and support code
- * Because we are fitting into other infrastructure, we have to supply the
- * full set of kobject/sysfs_ops structures and routines.
- */
-#define QIB_PORT_ATTR(name, mode, show, store) \
- static struct qib_port_attr qib_port_attr_##name = \
- __ATTR(name, mode, show, store)
-
-struct qib_port_attr {
- struct attribute attr;
- ssize_t (*show)(struct qib_pportdata *, char *);
- ssize_t (*store)(struct qib_pportdata *, const char *, size_t);
+static struct attribute *port_linkcontrol_attributes[] = {
+ &ib_port_attr_loopback.attr,
+ &ib_port_attr_led_override.attr,
+ &ib_port_attr_hrtbt_enable.attr,
+ &ib_port_attr_status.attr,
+ &ib_port_attr_status_str.attr,
+ NULL
};
-QIB_PORT_ATTR(loopback, S_IWUSR, NULL, store_loopback);
-QIB_PORT_ATTR(led_override, S_IWUSR, NULL, store_led_override);
-QIB_PORT_ATTR(hrtbt_enable, S_IWUSR | S_IRUGO, show_hrtbt_enb,
- store_hrtbt_enb);
-QIB_PORT_ATTR(status, S_IRUGO, show_status, NULL);
-QIB_PORT_ATTR(status_str, S_IRUGO, show_status_str, NULL);
-
-static struct attribute *port_default_attributes[] = {
- &qib_port_attr_loopback.attr,
- &qib_port_attr_led_override.attr,
- &qib_port_attr_hrtbt_enable.attr,
- &qib_port_attr_status.attr,
- &qib_port_attr_status_str.attr,
- NULL
+static const struct attribute_group port_linkcontrol_group = {
+ .name = "linkcontrol",
+ .attrs = port_linkcontrol_attributes,
};
/*
@@ -201,13 +213,12 @@ static struct attribute *port_default_attributes[] = {
/*
* Congestion control table size followed by table entries
*/
-static ssize_t read_cc_table_bin(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t pos, size_t count)
+static ssize_t cc_table_bin_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t pos, size_t count)
{
+ struct qib_pportdata *ppd = qib_get_pportdata_kobj(kobj);
int ret;
- struct qib_pportdata *ppd =
- container_of(kobj, struct qib_pportdata, pport_cc_kobj);
if (!qib_cc_table_size || !ppd->ccti_entries_shadow)
return -EINVAL;
@@ -230,34 +241,19 @@ static ssize_t read_cc_table_bin(struct file *filp, struct kobject *kobj,
return count;
}
-
-static void qib_port_release(struct kobject *kobj)
-{
- /* nothing to do since memory is freed by qib_free_devdata() */
-}
-
-static struct kobj_type qib_port_cc_ktype = {
- .release = qib_port_release,
-};
-
-static const struct bin_attribute cc_table_bin_attr = {
- .attr = {.name = "cc_table_bin", .mode = 0444},
- .read = read_cc_table_bin,
- .size = PAGE_SIZE,
-};
+static BIN_ATTR_RO(cc_table_bin, PAGE_SIZE);
/*
* Congestion settings: port control, control map and an array of 16
* entries for the congestion entries - increase, timer, event log
* trigger threshold and the minimum injection rate delay.
*/
-static ssize_t read_cc_setting_bin(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t pos, size_t count)
+static ssize_t cc_setting_bin_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t pos, size_t count)
{
+ struct qib_pportdata *ppd = qib_get_pportdata_kobj(kobj);
int ret;
- struct qib_pportdata *ppd =
- container_of(kobj, struct qib_pportdata, pport_cc_kobj);
if (!qib_cc_table_size || !ppd->congestion_entries_shadow)
return -EINVAL;
@@ -278,67 +274,54 @@ static ssize_t read_cc_setting_bin(struct file *filp, struct kobject *kobj,
return count;
}
+static BIN_ATTR_RO(cc_setting_bin, PAGE_SIZE);
-static const struct bin_attribute cc_setting_bin_attr = {
- .attr = {.name = "cc_settings_bin", .mode = 0444},
- .read = read_cc_setting_bin,
- .size = PAGE_SIZE,
+static struct bin_attribute *port_ccmgta_attributes[] = {
+ &bin_attr_cc_setting_bin,
+ &bin_attr_cc_table_bin,
+ NULL,
};
-
-static ssize_t qib_portattr_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
+static umode_t qib_ccmgta_is_bin_visible(struct kobject *kobj,
+ struct bin_attribute *attr, int n)
{
- struct qib_port_attr *pattr =
- container_of(attr, struct qib_port_attr, attr);
- struct qib_pportdata *ppd =
- container_of(kobj, struct qib_pportdata, pport_kobj);
-
- if (!pattr->show)
- return -EIO;
-
- return pattr->show(ppd, buf);
-}
+ struct qib_pportdata *ppd = qib_get_pportdata_kobj(kobj);
-static ssize_t qib_portattr_store(struct kobject *kobj,
- struct attribute *attr, const char *buf, size_t len)
-{
- struct qib_port_attr *pattr =
- container_of(attr, struct qib_port_attr, attr);
- struct qib_pportdata *ppd =
- container_of(kobj, struct qib_pportdata, pport_kobj);
-
- if (!pattr->store)
- return -EIO;
-
- return pattr->store(ppd, buf, len);
+ if (!qib_cc_table_size || !ppd->congestion_entries_shadow)
+ return 0;
+ return attr->attr.mode;
}
-
-static const struct sysfs_ops qib_port_ops = {
- .show = qib_portattr_show,
- .store = qib_portattr_store,
-};
-
-static struct kobj_type qib_port_ktype = {
- .release = qib_port_release,
- .sysfs_ops = &qib_port_ops,
- .default_attrs = port_default_attributes
+static const struct attribute_group port_ccmgta_attribute_group = {
+ .name = "CCMgtA",
+ .is_bin_visible = qib_ccmgta_is_bin_visible,
+ .bin_attrs = port_ccmgta_attributes,
};
/* Start sl2vl */
-#define QIB_SL2VL_ATTR(N) \
- static struct qib_sl2vl_attr qib_sl2vl_attr_##N = { \
- .attr = { .name = __stringify(N), .mode = 0444 }, \
- .sl = N \
- }
-
struct qib_sl2vl_attr {
- struct attribute attr;
+ struct ib_port_attribute attr;
int sl;
};
+static ssize_t sl2vl_attr_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
+{
+ struct qib_sl2vl_attr *sattr =
+ container_of(attr, struct qib_sl2vl_attr, attr);
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_ibport *qibp = &dd->pport[port_num - 1].ibport_data;
+
+ return sysfs_emit(buf, "%u\n", qibp->sl_to_vl[sattr->sl]);
+}
+
+#define QIB_SL2VL_ATTR(N) \
+ static struct qib_sl2vl_attr qib_sl2vl_attr_##N = { \
+ .attr = __ATTR(N, 0444, sl2vl_attr_show, NULL), \
+ .sl = N, \
+ }
+
QIB_SL2VL_ATTR(0);
QIB_SL2VL_ATTR(1);
QIB_SL2VL_ATTR(2);
@@ -356,72 +339,74 @@ QIB_SL2VL_ATTR(13);
QIB_SL2VL_ATTR(14);
QIB_SL2VL_ATTR(15);
-static struct attribute *sl2vl_default_attributes[] = {
- &qib_sl2vl_attr_0.attr,
- &qib_sl2vl_attr_1.attr,
- &qib_sl2vl_attr_2.attr,
- &qib_sl2vl_attr_3.attr,
- &qib_sl2vl_attr_4.attr,
- &qib_sl2vl_attr_5.attr,
- &qib_sl2vl_attr_6.attr,
- &qib_sl2vl_attr_7.attr,
- &qib_sl2vl_attr_8.attr,
- &qib_sl2vl_attr_9.attr,
- &qib_sl2vl_attr_10.attr,
- &qib_sl2vl_attr_11.attr,
- &qib_sl2vl_attr_12.attr,
- &qib_sl2vl_attr_13.attr,
- &qib_sl2vl_attr_14.attr,
- &qib_sl2vl_attr_15.attr,
+static struct attribute *port_sl2vl_attributes[] = {
+ &qib_sl2vl_attr_0.attr.attr,
+ &qib_sl2vl_attr_1.attr.attr,
+ &qib_sl2vl_attr_2.attr.attr,
+ &qib_sl2vl_attr_3.attr.attr,
+ &qib_sl2vl_attr_4.attr.attr,
+ &qib_sl2vl_attr_5.attr.attr,
+ &qib_sl2vl_attr_6.attr.attr,
+ &qib_sl2vl_attr_7.attr.attr,
+ &qib_sl2vl_attr_8.attr.attr,
+ &qib_sl2vl_attr_9.attr.attr,
+ &qib_sl2vl_attr_10.attr.attr,
+ &qib_sl2vl_attr_11.attr.attr,
+ &qib_sl2vl_attr_12.attr.attr,
+ &qib_sl2vl_attr_13.attr.attr,
+ &qib_sl2vl_attr_14.attr.attr,
+ &qib_sl2vl_attr_15.attr.attr,
NULL
};
-static ssize_t sl2vl_attr_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- struct qib_sl2vl_attr *sattr =
- container_of(attr, struct qib_sl2vl_attr, attr);
- struct qib_pportdata *ppd =
- container_of(kobj, struct qib_pportdata, sl2vl_kobj);
- struct qib_ibport *qibp = &ppd->ibport_data;
-
- return sysfs_emit(buf, "%u\n", qibp->sl_to_vl[sattr->sl]);
-}
-
-static const struct sysfs_ops qib_sl2vl_ops = {
- .show = sl2vl_attr_show,
-};
-
-static struct kobj_type qib_sl2vl_ktype = {
- .release = qib_port_release,
- .sysfs_ops = &qib_sl2vl_ops,
- .default_attrs = sl2vl_default_attributes
+static const struct attribute_group port_sl2vl_group = {
+ .name = "sl2vl",
+ .attrs = port_sl2vl_attributes,
};
/* End sl2vl */
/* Start diag_counters */
-#define QIB_DIAGC_ATTR(N) \
- static struct qib_diagc_attr qib_diagc_attr_##N = { \
- .attr = { .name = __stringify(N), .mode = 0664 }, \
- .counter = offsetof(struct qib_ibport, rvp.n_##N) \
- }
-
-#define QIB_DIAGC_ATTR_PER_CPU(N) \
- static struct qib_diagc_attr qib_diagc_attr_##N = { \
- .attr = { .name = __stringify(N), .mode = 0664 }, \
- .counter = offsetof(struct qib_ibport, rvp.z_##N) \
- }
-
struct qib_diagc_attr {
- struct attribute attr;
+ struct ib_port_attribute attr;
size_t counter;
};
-QIB_DIAGC_ATTR_PER_CPU(rc_acks);
-QIB_DIAGC_ATTR_PER_CPU(rc_qacks);
-QIB_DIAGC_ATTR_PER_CPU(rc_delayed_comp);
+static ssize_t diagc_attr_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
+{
+ struct qib_diagc_attr *dattr =
+ container_of(attr, struct qib_diagc_attr, attr);
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_ibport *qibp = &dd->pport[port_num - 1].ibport_data;
+
+ return sysfs_emit(buf, "%llu\n", *((u64 *)qibp + dattr->counter));
+}
+
+static ssize_t diagc_attr_store(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct qib_diagc_attr *dattr =
+ container_of(attr, struct qib_diagc_attr, attr);
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_ibport *qibp = &dd->pport[port_num - 1].ibport_data;
+ u64 val;
+ int ret;
+
+ ret = kstrtou64(buf, 0, &val);
+ if (ret)
+ return ret;
+ *((u64 *)qibp + dattr->counter) = val;
+ return count;
+}
+
+#define QIB_DIAGC_ATTR(N) \
+ static struct qib_diagc_attr qib_diagc_attr_##N = { \
+ .attr = __ATTR(N, 0664, diagc_attr_show, diagc_attr_store), \
+ .counter = &((struct qib_ibport *)0)->rvp.n_##N - (u64 *)0, \
+ }
QIB_DIAGC_ATTR(rc_resends);
QIB_DIAGC_ATTR(seq_naks);
@@ -437,26 +422,6 @@ QIB_DIAGC_ATTR(rc_dupreq);
QIB_DIAGC_ATTR(rc_seqnak);
QIB_DIAGC_ATTR(rc_crwaits);
-static struct attribute *diagc_default_attributes[] = {
- &qib_diagc_attr_rc_resends.attr,
- &qib_diagc_attr_rc_acks.attr,
- &qib_diagc_attr_rc_qacks.attr,
- &qib_diagc_attr_rc_delayed_comp.attr,
- &qib_diagc_attr_seq_naks.attr,
- &qib_diagc_attr_rdma_seq.attr,
- &qib_diagc_attr_rnr_naks.attr,
- &qib_diagc_attr_other_naks.attr,
- &qib_diagc_attr_rc_timeouts.attr,
- &qib_diagc_attr_loop_pkts.attr,
- &qib_diagc_attr_pkt_drops.attr,
- &qib_diagc_attr_dmawait.attr,
- &qib_diagc_attr_unaligned.attr,
- &qib_diagc_attr_rc_dupreq.attr,
- &qib_diagc_attr_rc_seqnak.attr,
- &qib_diagc_attr_rc_crwaits.attr,
- NULL
-};
-
static u64 get_all_cpu_total(u64 __percpu *cntr)
{
int cpu;
@@ -467,86 +432,127 @@ static u64 get_all_cpu_total(u64 __percpu *cntr)
return counter;
}
-#define def_write_per_cpu(cntr) \
-static void write_per_cpu_##cntr(struct qib_pportdata *ppd, u32 data) \
-{ \
- struct qib_devdata *dd = ppd->dd; \
- struct qib_ibport *qibp = &ppd->ibport_data; \
- /* A write can only zero the counter */ \
- if (data == 0) \
- qibp->rvp.z_##cntr = get_all_cpu_total(qibp->rvp.cntr); \
- else \
- qib_dev_err(dd, "Per CPU cntrs can only be zeroed"); \
+static ssize_t qib_store_per_cpu(struct qib_devdata *dd, const char *buf,
+ size_t count, u64 *zero, u64 cur)
+{
+ u32 val;
+ int ret;
+
+ ret = kstrtou32(buf, 0, &val);
+ if (ret)
+ return ret;
+ if (val != 0) {
+ qib_dev_err(dd, "Per CPU cntrs can only be zeroed");
+ return count;
+ }
+ *zero = cur;
+ return count;
}
-def_write_per_cpu(rc_acks)
-def_write_per_cpu(rc_qacks)
-def_write_per_cpu(rc_delayed_comp)
+static ssize_t rc_acks_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
+{
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_ibport *qibp = &dd->pport[port_num - 1].ibport_data;
-#define READ_PER_CPU_CNTR(cntr) (get_all_cpu_total(qibp->rvp.cntr) - \
- qibp->rvp.z_##cntr)
+ return sysfs_emit(buf, "%llu\n",
+ get_all_cpu_total(qibp->rvp.rc_acks) -
+ qibp->rvp.z_rc_acks);
+}
-static ssize_t diagc_attr_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
+static ssize_t rc_acks_store(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, const char *buf,
+ size_t count)
{
- struct qib_diagc_attr *dattr =
- container_of(attr, struct qib_diagc_attr, attr);
- struct qib_pportdata *ppd =
- container_of(kobj, struct qib_pportdata, diagc_kobj);
- struct qib_ibport *qibp = &ppd->ibport_data;
- u64 val;
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_ibport *qibp = &dd->pport[port_num - 1].ibport_data;
+
+ return qib_store_per_cpu(dd, buf, count, &qibp->rvp.z_rc_acks,
+ get_all_cpu_total(qibp->rvp.rc_acks));
+}
+static IB_PORT_ATTR_RW(rc_acks);
- if (!strncmp(dattr->attr.name, "rc_acks", 7))
- val = READ_PER_CPU_CNTR(rc_acks);
- else if (!strncmp(dattr->attr.name, "rc_qacks", 8))
- val = READ_PER_CPU_CNTR(rc_qacks);
- else if (!strncmp(dattr->attr.name, "rc_delayed_comp", 15))
- val = READ_PER_CPU_CNTR(rc_delayed_comp);
- else
- val = *(u32 *)((char *)qibp + dattr->counter);
+static ssize_t rc_qacks_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
+{
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_ibport *qibp = &dd->pport[port_num - 1].ibport_data;
- return sysfs_emit(buf, "%llu\n", val);
+ return sysfs_emit(buf, "%llu\n",
+ get_all_cpu_total(qibp->rvp.rc_qacks) -
+ qibp->rvp.z_rc_qacks);
}
-static ssize_t diagc_attr_store(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t size)
+static ssize_t rc_qacks_store(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, const char *buf,
+ size_t count)
{
- struct qib_diagc_attr *dattr =
- container_of(attr, struct qib_diagc_attr, attr);
- struct qib_pportdata *ppd =
- container_of(kobj, struct qib_pportdata, diagc_kobj);
- struct qib_ibport *qibp = &ppd->ibport_data;
- u32 val;
- int ret;
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_ibport *qibp = &dd->pport[port_num - 1].ibport_data;
- ret = kstrtou32(buf, 0, &val);
- if (ret)
- return ret;
+ return qib_store_per_cpu(dd, buf, count, &qibp->rvp.z_rc_qacks,
+ get_all_cpu_total(qibp->rvp.rc_qacks));
+}
+static IB_PORT_ATTR_RW(rc_qacks);
- if (!strncmp(dattr->attr.name, "rc_acks", 7))
- write_per_cpu_rc_acks(ppd, val);
- else if (!strncmp(dattr->attr.name, "rc_qacks", 8))
- write_per_cpu_rc_qacks(ppd, val);
- else if (!strncmp(dattr->attr.name, "rc_delayed_comp", 15))
- write_per_cpu_rc_delayed_comp(ppd, val);
- else
- *(u32 *)((char *)qibp + dattr->counter) = val;
- return size;
+static ssize_t rc_delayed_comp_show(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr, char *buf)
+{
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_ibport *qibp = &dd->pport[port_num - 1].ibport_data;
+
+ return sysfs_emit(buf, "%llu\n",
+ get_all_cpu_total(qibp->rvp.rc_delayed_comp) -
+ qibp->rvp.z_rc_delayed_comp);
}
-static const struct sysfs_ops qib_diagc_ops = {
- .show = diagc_attr_show,
- .store = diagc_attr_store,
+static ssize_t rc_delayed_comp_store(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct qib_devdata *dd = dd_from_ibdev(ibdev);
+ struct qib_ibport *qibp = &dd->pport[port_num - 1].ibport_data;
+
+ return qib_store_per_cpu(dd, buf, count, &qibp->rvp.z_rc_delayed_comp,
+ get_all_cpu_total(qibp->rvp.rc_delayed_comp));
+}
+static IB_PORT_ATTR_RW(rc_delayed_comp);
+
+static struct attribute *port_diagc_attributes[] = {
+ &qib_diagc_attr_rc_resends.attr.attr,
+ &qib_diagc_attr_seq_naks.attr.attr,
+ &qib_diagc_attr_rdma_seq.attr.attr,
+ &qib_diagc_attr_rnr_naks.attr.attr,
+ &qib_diagc_attr_other_naks.attr.attr,
+ &qib_diagc_attr_rc_timeouts.attr.attr,
+ &qib_diagc_attr_loop_pkts.attr.attr,
+ &qib_diagc_attr_pkt_drops.attr.attr,
+ &qib_diagc_attr_dmawait.attr.attr,
+ &qib_diagc_attr_unaligned.attr.attr,
+ &qib_diagc_attr_rc_dupreq.attr.attr,
+ &qib_diagc_attr_rc_seqnak.attr.attr,
+ &qib_diagc_attr_rc_crwaits.attr.attr,
+ &ib_port_attr_rc_acks.attr,
+ &ib_port_attr_rc_qacks.attr,
+ &ib_port_attr_rc_delayed_comp.attr,
+ NULL
};
-static struct kobj_type qib_diagc_ktype = {
- .release = qib_port_release,
- .sysfs_ops = &qib_diagc_ops,
- .default_attrs = diagc_default_attributes
+static const struct attribute_group port_diagc_group = {
+ .name = "linkcontrol",
+ .attrs = port_diagc_attributes,
};
/* End diag_counters */
+const struct attribute_group *qib_attr_port_groups[] = {
+ &port_linkcontrol_group,
+ &port_ccmgta_attribute_group,
+ &port_sl2vl_group,
+ &port_diagc_group,
+ NULL,
+};
+
/* end of per-port file structures and support code */
/*
@@ -727,125 +733,3 @@ static struct attribute *qib_attributes[] = {
const struct attribute_group qib_attr_group = {
.attrs = qib_attributes,
};
-
-int qib_create_port_files(struct ib_device *ibdev, u32 port_num,
- struct kobject *kobj)
-{
- struct qib_pportdata *ppd;
- struct qib_devdata *dd = dd_from_ibdev(ibdev);
- int ret;
-
- if (!port_num || port_num > dd->num_pports) {
- qib_dev_err(dd,
- "Skipping infiniband class with invalid port %u\n",
- port_num);
- ret = -ENODEV;
- goto bail;
- }
- ppd = &dd->pport[port_num - 1];
-
- ret = kobject_init_and_add(&ppd->pport_kobj, &qib_port_ktype, kobj,
- "linkcontrol");
- if (ret) {
- qib_dev_err(dd,
- "Skipping linkcontrol sysfs info, (err %d) port %u\n",
- ret, port_num);
- goto bail_link;
- }
- kobject_uevent(&ppd->pport_kobj, KOBJ_ADD);
-
- ret = kobject_init_and_add(&ppd->sl2vl_kobj, &qib_sl2vl_ktype, kobj,
- "sl2vl");
- if (ret) {
- qib_dev_err(dd,
- "Skipping sl2vl sysfs info, (err %d) port %u\n",
- ret, port_num);
- goto bail_sl;
- }
- kobject_uevent(&ppd->sl2vl_kobj, KOBJ_ADD);
-
- ret = kobject_init_and_add(&ppd->diagc_kobj, &qib_diagc_ktype, kobj,
- "diag_counters");
- if (ret) {
- qib_dev_err(dd,
- "Skipping diag_counters sysfs info, (err %d) port %u\n",
- ret, port_num);
- goto bail_diagc;
- }
- kobject_uevent(&ppd->diagc_kobj, KOBJ_ADD);
-
- if (!qib_cc_table_size || !ppd->congestion_entries_shadow)
- return 0;
-
- ret = kobject_init_and_add(&ppd->pport_cc_kobj, &qib_port_cc_ktype,
- kobj, "CCMgtA");
- if (ret) {
- qib_dev_err(dd,
- "Skipping Congestion Control sysfs info, (err %d) port %u\n",
- ret, port_num);
- goto bail_cc;
- }
-
- kobject_uevent(&ppd->pport_cc_kobj, KOBJ_ADD);
-
- ret = sysfs_create_bin_file(&ppd->pport_cc_kobj,
- &cc_setting_bin_attr);
- if (ret) {
- qib_dev_err(dd,
- "Skipping Congestion Control setting sysfs info, (err %d) port %u\n",
- ret, port_num);
- goto bail_cc;
- }
-
- ret = sysfs_create_bin_file(&ppd->pport_cc_kobj,
- &cc_table_bin_attr);
- if (ret) {
- qib_dev_err(dd,
- "Skipping Congestion Control table sysfs info, (err %d) port %u\n",
- ret, port_num);
- goto bail_cc_entry_bin;
- }
-
- qib_devinfo(dd->pcidev,
- "IB%u: Congestion Control Agent enabled for port %d\n",
- dd->unit, port_num);
-
- return 0;
-
-bail_cc_entry_bin:
- sysfs_remove_bin_file(&ppd->pport_cc_kobj, &cc_setting_bin_attr);
-bail_cc:
- kobject_put(&ppd->pport_cc_kobj);
-bail_diagc:
- kobject_put(&ppd->diagc_kobj);
-bail_sl:
- kobject_put(&ppd->sl2vl_kobj);
-bail_link:
- kobject_put(&ppd->pport_kobj);
-bail:
- return ret;
-}
-
-/*
- * Unregister and remove our files in /sys/class/infiniband.
- */
-void qib_verbs_unregister_sysfs(struct qib_devdata *dd)
-{
- struct qib_pportdata *ppd;
- int i;
-
- for (i = 0; i < dd->num_pports; i++) {
- ppd = &dd->pport[i];
- if (qib_cc_table_size &&
- ppd->congestion_entries_shadow) {
- sysfs_remove_bin_file(&ppd->pport_cc_kobj,
- &cc_setting_bin_attr);
- sysfs_remove_bin_file(&ppd->pport_cc_kobj,
- &cc_table_bin_attr);
- kobject_put(&ppd->pport_cc_kobj);
- }
- kobject_put(&ppd->diagc_kobj);
- kobject_put(&ppd->sl2vl_kobj);
- kobject_put(&ppd->pport_kobj);
- }
-}
diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c
index d17d034ecdfd..ef91bff5c23c 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.c
+++ b/drivers/infiniband/hw/qib/qib_verbs.c
@@ -1483,7 +1483,8 @@ static const struct ib_device_ops qib_dev_ops = {
.owner = THIS_MODULE,
.driver_id = RDMA_DRIVER_QIB,
- .init_port = qib_create_port_files,
+ .port_groups = qib_attr_port_groups,
+ .device_group = &qib_attr_group,
.modify_device = qib_modify_device,
.process_mad = qib_process_mad,
};
@@ -1612,7 +1613,6 @@ int qib_register_ib_device(struct qib_devdata *dd)
i,
dd->rcd[ctxt]->pkeys);
}
- 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);
@@ -1644,8 +1644,6 @@ void qib_unregister_ib_device(struct qib_devdata *dd)
{
struct qib_ibdev *dev = &dd->verbs_dev;
- qib_verbs_unregister_sysfs(dd);
-
rvt_unregister_device(&dd->verbs_dev.rdi);
if (!list_empty(&dev->piowait))
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_main.c b/drivers/infiniband/hw/usnic/usnic_ib_main.c
index ff6a40e259d5..c49f9e19d926 100644
--- a/drivers/infiniband/hw/usnic/usnic_ib_main.c
+++ b/drivers/infiniband/hw/usnic/usnic_ib_main.c
@@ -347,6 +347,7 @@ static const struct ib_device_ops usnic_dev_ops = {
.dereg_mr = usnic_ib_dereg_mr,
.destroy_cq = usnic_ib_destroy_cq,
.destroy_qp = usnic_ib_destroy_qp,
+ .device_group = &usnic_attr_group,
.get_dev_fw_str = usnic_get_dev_fw_str,
.get_link_layer = usnic_ib_port_link_layer,
.get_port_immutable = usnic_port_immutable,
@@ -400,8 +401,6 @@ static void *usnic_ib_device_add(struct pci_dev *dev)
ib_set_device_ops(&us_ibdev->ib_dev, &usnic_dev_ops);
- 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);
if (ret)
goto err_fwd_dealloc;
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
index 6bf2d2e47d07..8ed8bc24c69f 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
@@ -162,6 +162,7 @@ static const struct ib_device_ops pvrdma_dev_ops = {
.destroy_ah = pvrdma_destroy_ah,
.destroy_cq = pvrdma_destroy_cq,
.destroy_qp = pvrdma_destroy_qp,
+ .device_group = &pvrdma_attr_group,
.get_dev_fw_str = pvrdma_get_fw_ver_str,
.get_dma_mr = pvrdma_get_dma_mr,
.get_link_layer = pvrdma_port_link_layer,
@@ -240,7 +241,6 @@ static int pvrdma_register_device(struct pvrdma_dev *dev)
if (ret)
goto err_srq_free;
spin_lock_init(&dev->srq_tbl_lock);
- rdma_set_device_sysfs_group(&dev->ib_dev, &pvrdma_attr_group);
ret = ib_register_device(&dev->ib_dev, "vmw_pvrdma%d", &dev->pdev->dev);
if (ret)
diff --git a/drivers/infiniband/sw/rdmavt/mr.c b/drivers/infiniband/sw/rdmavt/mr.c
index 601d18dda1f5..34b7af6ab9c2 100644
--- a/drivers/infiniband/sw/rdmavt/mr.c
+++ b/drivers/infiniband/sw/rdmavt/mr.c
@@ -101,8 +101,8 @@ int rvt_driver_mr_init(struct rvt_dev_info *rdi)
}
/**
- *rvt_mr_exit: clean up MR
- *@rdi: rvt dev structure
+ * rvt_mr_exit - clean up MR
+ * @rdi: rvt dev structure
*
* called when drivers have unregistered or perhaps failed to register with us
*/
diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c
index 9d13db68283c..e9f3d356b361 100644
--- a/drivers/infiniband/sw/rdmavt/qp.c
+++ b/drivers/infiniband/sw/rdmavt/qp.c
@@ -984,7 +984,8 @@ static void rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp,
spin_unlock_irq(&qp->r_lock);
}
-/** rvt_free_qpn - Free a qpn from the bit map
+/**
+ * rvt_free_qpn - Free a qpn from the bit map
* @qpt: QP table
* @qpn: queue pair number to free
*/
diff --git a/drivers/infiniband/sw/rdmavt/trace_cq.h b/drivers/infiniband/sw/rdmavt/trace_cq.h
index e3c416c6f900..91bc192cee5e 100644
--- a/drivers/infiniband/sw/rdmavt/trace_cq.h
+++ b/drivers/infiniband/sw/rdmavt/trace_cq.h
@@ -85,7 +85,7 @@ DECLARE_EVENT_CLASS(rvt_cq_template,
__field(int, comp_vector_cpu)
__field(u32, flags)
),
- TP_fast_assign(RDI_DEV_ASSIGN(cq->rdi)
+ TP_fast_assign(RDI_DEV_ASSIGN(cq->rdi);
__entry->ip = cq->ip;
__entry->cqe = attr->cqe;
__entry->comp_vector = attr->comp_vector;
@@ -123,7 +123,7 @@ DECLARE_EVENT_CLASS(
__field(u32, imm)
),
TP_fast_assign(
- RDI_DEV_ASSIGN(cq->rdi)
+ RDI_DEV_ASSIGN(cq->rdi);
__entry->wr_id = wc->wr_id;
__entry->status = wc->status;
__entry->opcode = wc->opcode;
diff --git a/drivers/infiniband/sw/rdmavt/trace_mr.h b/drivers/infiniband/sw/rdmavt/trace_mr.h
index 95b8a0e3b8bd..c5b675ca4fa0 100644
--- a/drivers/infiniband/sw/rdmavt/trace_mr.h
+++ b/drivers/infiniband/sw/rdmavt/trace_mr.h
@@ -195,7 +195,7 @@ TRACE_EVENT(
__field(uint, sg_offset)
),
TP_fast_assign(
- RDI_DEV_ASSIGN(ib_to_rvt(to_imr(ibmr)->mr.pd->device))
+ 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;
diff --git a/drivers/infiniband/sw/rdmavt/trace_qp.h b/drivers/infiniband/sw/rdmavt/trace_qp.h
index c32d21cc615e..800cec8bb3c7 100644
--- a/drivers/infiniband/sw/rdmavt/trace_qp.h
+++ b/drivers/infiniband/sw/rdmavt/trace_qp.h
@@ -65,7 +65,7 @@ DECLARE_EVENT_CLASS(rvt_qphash_template,
__field(u32, bucket)
),
TP_fast_assign(
- RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device))
+ RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device));
__entry->qpn = qp->ibqp.qp_num;
__entry->bucket = bucket;
),
@@ -97,7 +97,7 @@ DECLARE_EVENT_CLASS(
__field(u32, to)
),
TP_fast_assign(
- RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device))
+ RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device));
__entry->qpn = qp->ibqp.qp_num;
__entry->hrtimer = &qp->s_rnr_timer;
__entry->s_flags = qp->s_flags;
diff --git a/drivers/infiniband/sw/rdmavt/trace_rc.h b/drivers/infiniband/sw/rdmavt/trace_rc.h
index c47357af2099..9de52e138025 100644
--- a/drivers/infiniband/sw/rdmavt/trace_rc.h
+++ b/drivers/infiniband/sw/rdmavt/trace_rc.h
@@ -71,7 +71,7 @@ DECLARE_EVENT_CLASS(rvt_rc_template,
__field(u32, r_psn)
),
TP_fast_assign(
- RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device))
+ RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device));
__entry->qpn = qp->ibqp.qp_num;
__entry->s_flags = qp->s_flags;
__entry->psn = psn;
diff --git a/drivers/infiniband/sw/rdmavt/trace_tx.h b/drivers/infiniband/sw/rdmavt/trace_tx.h
index d963ca755828..cb96be0f8f19 100644
--- a/drivers/infiniband/sw/rdmavt/trace_tx.h
+++ b/drivers/infiniband/sw/rdmavt/trace_tx.h
@@ -111,7 +111,7 @@ TRACE_EVENT(
__field(int, wr_num_sge)
),
TP_fast_assign(
- RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device))
+ RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device));
__entry->wqe = wqe;
__entry->wr_id = wqe->wr.wr_id;
__entry->qpn = qp->ibqp.qp_num;
@@ -170,7 +170,7 @@ TRACE_EVENT(
__field(int, send_flags)
),
TP_fast_assign(
- RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device))
+ RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device));
__entry->wqe = wqe;
__entry->wr_id = wqe->wr.wr_id;
__entry->qpn = qp->ibqp.qp_num;
diff --git a/drivers/infiniband/sw/rdmavt/vt.c b/drivers/infiniband/sw/rdmavt/vt.c
index 12ebe041a5da..ac17209816cd 100644
--- a/drivers/infiniband/sw/rdmavt/vt.c
+++ b/drivers/infiniband/sw/rdmavt/vt.c
@@ -144,7 +144,7 @@ static int rvt_modify_device(struct ib_device *device,
}
/**
- * rvt_query_port: Passes the query port call to the driver
+ * rvt_query_port - Passes the query port call to the driver
* @ibdev: Verbs IB dev
* @port_num: port number, 1 based from ib core
* @props: structure to hold returned properties
@@ -175,7 +175,7 @@ static int rvt_query_port(struct ib_device *ibdev, u32 port_num,
}
/**
- * rvt_modify_port
+ * rvt_modify_port - modify port
* @ibdev: Verbs IB dev
* @port_num: Port number, 1 based from ib core
* @port_modify_mask: How to change the port
@@ -418,7 +418,7 @@ static noinline int check_support(struct rvt_dev_info *rdi, int verb)
* These functions are not part of verbs specifically but are
* required for rdmavt to function.
*/
- if ((!rdi->ibdev.ops.init_port) ||
+ if ((!rdi->ibdev.ops.port_groups) ||
(!rdi->driver_f.get_pci_dev))
return -EINVAL;
break;
diff --git a/drivers/infiniband/sw/rxe/Makefile b/drivers/infiniband/sw/rxe/Makefile
index 66af72dca759..1e24673e9318 100644
--- a/drivers/infiniband/sw/rxe/Makefile
+++ b/drivers/infiniband/sw/rxe/Makefile
@@ -15,6 +15,7 @@ rdma_rxe-y := \
rxe_qp.o \
rxe_cq.o \
rxe_mr.o \
+ rxe_mw.o \
rxe_opcode.o \
rxe_mmap.o \
rxe_icrc.o \
diff --git a/drivers/infiniband/sw/rxe/rxe.c b/drivers/infiniband/sw/rxe/rxe.c
index 95f0de0c8b49..8e0f9c489cab 100644
--- a/drivers/infiniband/sw/rxe/rxe.c
+++ b/drivers/infiniband/sw/rxe/rxe.c
@@ -54,6 +54,7 @@ static void rxe_init_device_param(struct rxe_dev *rxe)
rxe->attr.max_cq = RXE_MAX_CQ;
rxe->attr.max_cqe = (1 << RXE_MAX_LOG_CQE) - 1;
rxe->attr.max_mr = RXE_MAX_MR;
+ rxe->attr.max_mw = RXE_MAX_MW;
rxe->attr.max_pd = RXE_MAX_PD;
rxe->attr.max_qp_rd_atom = RXE_MAX_QP_RD_ATOM;
rxe->attr.max_res_rd_atom = RXE_MAX_RES_RD_ATOM;
diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c
index a6712e373eed..58ad9c2644f3 100644
--- a/drivers/infiniband/sw/rxe/rxe_comp.c
+++ b/drivers/infiniband/sw/rxe/rxe_comp.c
@@ -103,6 +103,7 @@ static enum ib_wc_opcode wr_to_wc_opcode(enum ib_wr_opcode opcode)
case IB_WR_RDMA_READ_WITH_INV: return IB_WC_RDMA_READ;
case IB_WR_LOCAL_INV: return IB_WC_LOCAL_INV;
case IB_WR_REG_MR: return IB_WC_REG_MR;
+ case IB_WR_BIND_MW: return IB_WC_BIND_MW;
default:
return 0xff;
@@ -141,7 +142,10 @@ static inline enum comp_state get_wqe(struct rxe_qp *qp,
/* we come here whether or not we found a response packet to see if
* there are any posted WQEs
*/
- wqe = queue_head(qp->sq.queue);
+ if (qp->is_user)
+ wqe = queue_head(qp->sq.queue, QUEUE_TYPE_FROM_USER);
+ else
+ wqe = queue_head(qp->sq.queue, QUEUE_TYPE_KERNEL);
*wqe_p = wqe;
/* no WQE or requester has not started it yet */
@@ -345,7 +349,7 @@ static inline enum comp_state do_read(struct rxe_qp *qp,
ret = copy_data(qp->pd, IB_ACCESS_LOCAL_WRITE,
&wqe->dma, payload_addr(pkt),
- payload_size(pkt), to_mr_obj, NULL);
+ payload_size(pkt), RXE_TO_MR_OBJ, NULL);
if (ret) {
wqe->status = IB_WC_LOC_PROT_ERR;
return COMPST_ERROR;
@@ -367,7 +371,7 @@ static inline enum comp_state do_atomic(struct rxe_qp *qp,
ret = copy_data(qp->pd, IB_ACCESS_LOCAL_WRITE,
&wqe->dma, &atomic_orig,
- sizeof(u64), to_mr_obj, NULL);
+ sizeof(u64), RXE_TO_MR_OBJ, NULL);
if (ret) {
wqe->status = IB_WC_LOC_PROT_ERR;
return COMPST_ERROR;
@@ -418,16 +422,23 @@ static void do_complete(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
{
struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
struct rxe_cqe cqe;
+ bool post;
+
+ /* do we need to post a completion */
+ post = ((qp->sq_sig_type == IB_SIGNAL_ALL_WR) ||
+ (wqe->wr.send_flags & IB_SEND_SIGNALED) ||
+ wqe->status != IB_WC_SUCCESS);
- if ((qp->sq_sig_type == IB_SIGNAL_ALL_WR) ||
- (wqe->wr.send_flags & IB_SEND_SIGNALED) ||
- wqe->status != IB_WC_SUCCESS) {
+ if (post)
make_send_cqe(qp, wqe, &cqe);
- advance_consumer(qp->sq.queue);
+
+ if (qp->is_user)
+ advance_consumer(qp->sq.queue, QUEUE_TYPE_FROM_USER);
+ else
+ advance_consumer(qp->sq.queue, QUEUE_TYPE_KERNEL);
+
+ if (post)
rxe_cq_post(qp->scq, &cqe, 0);
- } else {
- advance_consumer(qp->sq.queue);
- }
if (wqe->wr.opcode == IB_WR_SEND ||
wqe->wr.opcode == IB_WR_SEND_WITH_IMM ||
@@ -515,6 +526,7 @@ static void rxe_drain_resp_pkts(struct rxe_qp *qp, bool notify)
{
struct sk_buff *skb;
struct rxe_send_wqe *wqe;
+ struct rxe_queue *q = qp->sq.queue;
while ((skb = skb_dequeue(&qp->resp_pkts))) {
rxe_drop_ref(qp);
@@ -522,12 +534,12 @@ static void rxe_drain_resp_pkts(struct rxe_qp *qp, bool notify)
ib_device_put(qp->ibqp.device);
}
- while ((wqe = queue_head(qp->sq.queue))) {
+ while ((wqe = queue_head(q, q->type))) {
if (notify) {
wqe->status = IB_WC_WR_FLUSH_ERR;
do_complete(qp, wqe);
} else {
- advance_consumer(qp->sq.queue);
+ advance_consumer(q, q->type);
}
}
}
diff --git a/drivers/infiniband/sw/rxe/rxe_cq.c b/drivers/infiniband/sw/rxe/rxe_cq.c
index b315ebf041ac..aef288f164fd 100644
--- a/drivers/infiniband/sw/rxe/rxe_cq.c
+++ b/drivers/infiniband/sw/rxe/rxe_cq.c
@@ -25,7 +25,11 @@ int rxe_cq_chk_attr(struct rxe_dev *rxe, struct rxe_cq *cq,
}
if (cq) {
- count = queue_count(cq->queue);
+ if (cq->is_user)
+ count = queue_count(cq->queue, QUEUE_TYPE_TO_USER);
+ else
+ count = queue_count(cq->queue, QUEUE_TYPE_KERNEL);
+
if (cqe < count) {
pr_warn("cqe(%d) < current # elements in queue (%d)",
cqe, count);
@@ -59,9 +63,11 @@ int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe,
struct rxe_create_cq_resp __user *uresp)
{
int err;
+ enum queue_type type;
+ type = uresp ? QUEUE_TYPE_TO_USER : QUEUE_TYPE_KERNEL;
cq->queue = rxe_queue_init(rxe, &cqe,
- sizeof(struct rxe_cqe));
+ sizeof(struct rxe_cqe), type);
if (!cq->queue) {
pr_warn("unable to create cq\n");
return -ENOMEM;
@@ -106,10 +112,17 @@ int rxe_cq_post(struct rxe_cq *cq, struct rxe_cqe *cqe, int solicited)
{
struct ib_event ev;
unsigned long flags;
+ int full;
+ void *addr;
spin_lock_irqsave(&cq->cq_lock, flags);
- if (unlikely(queue_full(cq->queue))) {
+ if (cq->is_user)
+ full = queue_full(cq->queue, QUEUE_TYPE_TO_USER);
+ else
+ full = queue_full(cq->queue, QUEUE_TYPE_KERNEL);
+
+ if (unlikely(full)) {
spin_unlock_irqrestore(&cq->cq_lock, flags);
if (cq->ibcq.event_handler) {
ev.device = cq->ibcq.device;
@@ -121,9 +134,18 @@ int rxe_cq_post(struct rxe_cq *cq, struct rxe_cqe *cqe, int solicited)
return -EBUSY;
}
- memcpy(producer_addr(cq->queue), cqe, sizeof(*cqe));
+ if (cq->is_user)
+ addr = producer_addr(cq->queue, QUEUE_TYPE_TO_USER);
+ else
+ addr = producer_addr(cq->queue, QUEUE_TYPE_KERNEL);
+
+ memcpy(addr, cqe, sizeof(*cqe));
+
+ if (cq->is_user)
+ advance_producer(cq->queue, QUEUE_TYPE_TO_USER);
+ else
+ advance_producer(cq->queue, QUEUE_TYPE_KERNEL);
- advance_producer(cq->queue);
spin_unlock_irqrestore(&cq->cq_lock, flags);
if ((cq->notify == IB_CQ_NEXT_COMP) ||
diff --git a/drivers/infiniband/sw/rxe/rxe_hw_counters.c b/drivers/infiniband/sw/rxe/rxe_hw_counters.c
index f469fd1c753d..d5ceb706d964 100644
--- a/drivers/infiniband/sw/rxe/rxe_hw_counters.c
+++ b/drivers/infiniband/sw/rxe/rxe_hw_counters.c
@@ -40,13 +40,10 @@ int rxe_ib_get_hw_stats(struct ib_device *ibdev,
return ARRAY_SIZE(rxe_counter_name);
}
-struct rdma_hw_stats *rxe_ib_alloc_hw_stats(struct ib_device *ibdev,
- u32 port_num)
+struct rdma_hw_stats *rxe_ib_alloc_hw_port_stats(struct ib_device *ibdev,
+ u32 port_num)
{
BUILD_BUG_ON(ARRAY_SIZE(rxe_counter_name) != RXE_NUM_OF_COUNTERS);
- /* We support only per port stats */
- if (!port_num)
- return NULL;
return rdma_alloc_hw_stats_struct(rxe_counter_name,
ARRAY_SIZE(rxe_counter_name),
diff --git a/drivers/infiniband/sw/rxe/rxe_hw_counters.h b/drivers/infiniband/sw/rxe/rxe_hw_counters.h
index 2f369acb46d7..71f4d4fa9dc8 100644
--- a/drivers/infiniband/sw/rxe/rxe_hw_counters.h
+++ b/drivers/infiniband/sw/rxe/rxe_hw_counters.h
@@ -29,8 +29,8 @@ enum rxe_counters {
RXE_NUM_OF_COUNTERS
};
-struct rdma_hw_stats *rxe_ib_alloc_hw_stats(struct ib_device *ibdev,
- u32 port_num);
+struct rdma_hw_stats *rxe_ib_alloc_hw_port_stats(struct ib_device *ibdev,
+ u32 port_num);
int rxe_ib_get_hw_stats(struct ib_device *ibdev,
struct rdma_hw_stats *stats,
u32 port, int index);
diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rxe/rxe_loc.h
index ef8061d2fbe0..1ddb20855dee 100644
--- a/drivers/infiniband/sw/rxe/rxe_loc.h
+++ b/drivers/infiniband/sw/rxe/rxe_loc.h
@@ -71,40 +71,32 @@ struct rxe_mmap_info *rxe_create_mmap_info(struct rxe_dev *dev, u32 size,
int rxe_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
/* rxe_mr.c */
-enum copy_direction {
- to_mr_obj,
- from_mr_obj,
-};
-
+u8 rxe_get_next_key(u32 last_key);
void rxe_mr_init_dma(struct rxe_pd *pd, int access, struct rxe_mr *mr);
-
int rxe_mr_init_user(struct rxe_pd *pd, u64 start, u64 length, u64 iova,
- int access, struct ib_udata *udata, struct rxe_mr *mr);
-
+ int access, struct rxe_mr *mr);
int rxe_mr_init_fast(struct rxe_pd *pd, int max_pages, struct rxe_mr *mr);
-
int rxe_mr_copy(struct rxe_mr *mr, u64 iova, void *addr, int length,
- enum copy_direction dir, u32 *crcp);
-
+ enum rxe_mr_copy_dir dir, u32 *crcp);
int copy_data(struct rxe_pd *pd, int access,
struct rxe_dma_info *dma, void *addr, int length,
- enum copy_direction dir, u32 *crcp);
-
+ enum rxe_mr_copy_dir dir, u32 *crcp);
void *iova_to_vaddr(struct rxe_mr *mr, u64 iova, int length);
-
-enum lookup_type {
- lookup_local,
- lookup_remote,
-};
-
struct rxe_mr *lookup_mr(struct rxe_pd *pd, int access, u32 key,
- enum lookup_type type);
-
+ enum rxe_mr_lookup_type type);
int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length);
-
+int advance_dma_data(struct rxe_dma_info *dma, unsigned int length);
+int rxe_invalidate_mr(struct rxe_qp *qp, u32 rkey);
+int rxe_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata);
void rxe_mr_cleanup(struct rxe_pool_entry *arg);
-int advance_dma_data(struct rxe_dma_info *dma, unsigned int length);
+/* rxe_mw.c */
+int rxe_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata);
+int rxe_dealloc_mw(struct ib_mw *ibmw);
+int rxe_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe);
+int rxe_invalidate_mw(struct rxe_qp *qp, u32 rkey);
+struct rxe_mw *rxe_lookup_mw(struct rxe_qp *qp, int access, u32 rkey);
+void rxe_mw_cleanup(struct rxe_pool_entry *arg);
/* rxe_net.c */
void rxe_loopback(struct sk_buff *skb);
diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c
index 9f63947bab12..6aabcb4de235 100644
--- a/drivers/infiniband/sw/rxe/rxe_mr.c
+++ b/drivers/infiniband/sw/rxe/rxe_mr.c
@@ -7,19 +7,17 @@
#include "rxe.h"
#include "rxe_loc.h"
-/*
- * lfsr (linear feedback shift register) with period 255
+/* Return a random 8 bit key value that is
+ * different than the last_key. Set last_key to -1
+ * if this is the first key for an MR or MW
*/
-static u8 rxe_get_key(void)
+u8 rxe_get_next_key(u32 last_key)
{
- static u32 key = 1;
-
- key = key << 1;
+ u8 key;
- key |= (0 != (key & 0x100)) ^ (0 != (key & 0x10))
- ^ (0 != (key & 0x80)) ^ (0 != (key & 0x40));
-
- key &= 0xff;
+ do {
+ get_random_bytes(&key, 1);
+ } while (key == last_key);
return key;
}
@@ -47,7 +45,7 @@ int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length)
static void rxe_mr_init(int access, struct rxe_mr *mr)
{
- u32 lkey = mr->pelem.index << 8 | rxe_get_key();
+ u32 lkey = mr->pelem.index << 8 | rxe_get_next_key(-1);
u32 rkey = (access & IB_ACCESS_REMOTE) ? lkey : 0;
mr->ibmr.lkey = lkey;
@@ -57,21 +55,6 @@ static void rxe_mr_init(int access, struct rxe_mr *mr)
mr->map_shift = ilog2(RXE_BUF_PER_MAP);
}
-void rxe_mr_cleanup(struct rxe_pool_entry *arg)
-{
- struct rxe_mr *mr = container_of(arg, typeof(*mr), pelem);
- int i;
-
- ib_umem_release(mr->umem);
-
- if (mr->map) {
- for (i = 0; i < mr->num_map; i++)
- kfree(mr->map[i]);
-
- kfree(mr->map);
- }
-}
-
static int rxe_mr_alloc(struct rxe_mr *mr, int num_buf)
{
int i;
@@ -121,7 +104,7 @@ void rxe_mr_init_dma(struct rxe_pd *pd, int access, struct rxe_mr *mr)
}
int rxe_mr_init_user(struct rxe_pd *pd, u64 start, u64 length, u64 iova,
- int access, struct ib_udata *udata, struct rxe_mr *mr)
+ int access, struct rxe_mr *mr)
{
struct rxe_map **map;
struct rxe_phys_buf *buf = NULL;
@@ -135,7 +118,7 @@ int rxe_mr_init_user(struct rxe_pd *pd, u64 start, u64 length, u64 iova,
if (IS_ERR(umem)) {
pr_warn("err %d from rxe_umem_get\n",
(int)PTR_ERR(umem));
- err = -EINVAL;
+ err = PTR_ERR(umem);
goto err1;
}
@@ -300,7 +283,7 @@ out:
* crc32 if crcp is not zero. caller must hold a reference to mr
*/
int rxe_mr_copy(struct rxe_mr *mr, u64 iova, void *addr, int length,
- enum copy_direction dir, u32 *crcp)
+ enum rxe_mr_copy_dir dir, u32 *crcp)
{
int err;
int bytes;
@@ -318,9 +301,9 @@ int rxe_mr_copy(struct rxe_mr *mr, u64 iova, void *addr, int length,
if (mr->type == RXE_MR_TYPE_DMA) {
u8 *src, *dest;
- src = (dir == to_mr_obj) ? addr : ((void *)(uintptr_t)iova);
+ src = (dir == RXE_TO_MR_OBJ) ? addr : ((void *)(uintptr_t)iova);
- dest = (dir == to_mr_obj) ? ((void *)(uintptr_t)iova) : addr;
+ dest = (dir == RXE_TO_MR_OBJ) ? ((void *)(uintptr_t)iova) : addr;
memcpy(dest, src, length);
@@ -348,8 +331,8 @@ int rxe_mr_copy(struct rxe_mr *mr, u64 iova, void *addr, int length,
u8 *src, *dest;
va = (u8 *)(uintptr_t)buf->addr + offset;
- src = (dir == to_mr_obj) ? addr : va;
- dest = (dir == to_mr_obj) ? va : addr;
+ src = (dir == RXE_TO_MR_OBJ) ? addr : va;
+ dest = (dir == RXE_TO_MR_OBJ) ? va : addr;
bytes = buf->size - offset;
@@ -394,7 +377,7 @@ int copy_data(
struct rxe_dma_info *dma,
void *addr,
int length,
- enum copy_direction dir,
+ enum rxe_mr_copy_dir dir,
u32 *crcp)
{
int bytes;
@@ -414,7 +397,7 @@ int copy_data(
}
if (sge->length && (offset < sge->length)) {
- mr = lookup_mr(pd, access, sge->lkey, lookup_local);
+ mr = lookup_mr(pd, access, sge->lkey, RXE_LOOKUP_LOCAL);
if (!mr) {
err = -EINVAL;
goto err1;
@@ -440,7 +423,7 @@ int copy_data(
if (sge->length) {
mr = lookup_mr(pd, access, sge->lkey,
- lookup_local);
+ RXE_LOOKUP_LOCAL);
if (!mr) {
err = -EINVAL;
goto err1;
@@ -522,7 +505,7 @@ int advance_dma_data(struct rxe_dma_info *dma, unsigned int length)
* (4) verify that mr state is valid
*/
struct rxe_mr *lookup_mr(struct rxe_pd *pd, int access, u32 key,
- enum lookup_type type)
+ enum rxe_mr_lookup_type type)
{
struct rxe_mr *mr;
struct rxe_dev *rxe = to_rdev(pd->ibpd.device);
@@ -532,8 +515,8 @@ struct rxe_mr *lookup_mr(struct rxe_pd *pd, int access, u32 key,
if (!mr)
return NULL;
- if (unlikely((type == lookup_local && mr_lkey(mr) != key) ||
- (type == lookup_remote && mr_rkey(mr) != key) ||
+ if (unlikely((type == RXE_LOOKUP_LOCAL && mr_lkey(mr) != key) ||
+ (type == RXE_LOOKUP_REMOTE && mr_rkey(mr) != key) ||
mr_pd(mr) != pd || (access && !(access & mr->access)) ||
mr->state != RXE_MR_STATE_VALID)) {
rxe_drop_ref(mr);
@@ -542,3 +525,72 @@ struct rxe_mr *lookup_mr(struct rxe_pd *pd, int access, u32 key,
return mr;
}
+
+int rxe_invalidate_mr(struct rxe_qp *qp, u32 rkey)
+{
+ struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+ struct rxe_mr *mr;
+ int ret;
+
+ mr = rxe_pool_get_index(&rxe->mr_pool, rkey >> 8);
+ if (!mr) {
+ pr_err("%s: No MR for rkey %#x\n", __func__, rkey);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (rkey != mr->ibmr.rkey) {
+ pr_err("%s: rkey (%#x) doesn't match mr->ibmr.rkey (%#x)\n",
+ __func__, rkey, mr->ibmr.rkey);
+ ret = -EINVAL;
+ goto err_drop_ref;
+ }
+
+ if (atomic_read(&mr->num_mw) > 0) {
+ pr_warn("%s: Attempt to invalidate an MR while bound to MWs\n",
+ __func__);
+ ret = -EINVAL;
+ goto err_drop_ref;
+ }
+
+ mr->state = RXE_MR_STATE_FREE;
+ ret = 0;
+
+err_drop_ref:
+ rxe_drop_ref(mr);
+err:
+ return ret;
+}
+
+int rxe_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
+{
+ struct rxe_mr *mr = to_rmr(ibmr);
+
+ if (atomic_read(&mr->num_mw) > 0) {
+ pr_warn("%s: Attempt to deregister an MR while bound to MWs\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mr->state = RXE_MR_STATE_ZOMBIE;
+ rxe_drop_ref(mr_pd(mr));
+ rxe_drop_index(mr);
+ rxe_drop_ref(mr);
+
+ return 0;
+}
+
+void rxe_mr_cleanup(struct rxe_pool_entry *arg)
+{
+ struct rxe_mr *mr = container_of(arg, typeof(*mr), pelem);
+ int i;
+
+ ib_umem_release(mr->umem);
+
+ if (mr->map) {
+ for (i = 0; i < mr->num_map; i++)
+ kfree(mr->map[i]);
+
+ kfree(mr->map);
+ }
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_mw.c b/drivers/infiniband/sw/rxe/rxe_mw.c
new file mode 100644
index 000000000000..5ba77df7598e
--- /dev/null
+++ b/drivers/infiniband/sw/rxe/rxe_mw.c
@@ -0,0 +1,343 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * Copyright (c) 2020 Hewlett Packard Enterprise, Inc. All rights reserved.
+ */
+
+#include "rxe.h"
+
+int rxe_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
+{
+ struct rxe_mw *mw = to_rmw(ibmw);
+ struct rxe_pd *pd = to_rpd(ibmw->pd);
+ struct rxe_dev *rxe = to_rdev(ibmw->device);
+ int ret;
+
+ rxe_add_ref(pd);
+
+ ret = rxe_add_to_pool(&rxe->mw_pool, mw);
+ if (ret) {
+ rxe_drop_ref(pd);
+ return ret;
+ }
+
+ rxe_add_index(mw);
+ ibmw->rkey = (mw->pelem.index << 8) | rxe_get_next_key(-1);
+ mw->state = (mw->ibmw.type == IB_MW_TYPE_2) ?
+ RXE_MW_STATE_FREE : RXE_MW_STATE_VALID;
+ spin_lock_init(&mw->lock);
+
+ return 0;
+}
+
+static void rxe_do_dealloc_mw(struct rxe_mw *mw)
+{
+ if (mw->mr) {
+ struct rxe_mr *mr = mw->mr;
+
+ mw->mr = NULL;
+ atomic_dec(&mr->num_mw);
+ rxe_drop_ref(mr);
+ }
+
+ if (mw->qp) {
+ struct rxe_qp *qp = mw->qp;
+
+ mw->qp = NULL;
+ rxe_drop_ref(qp);
+ }
+
+ mw->access = 0;
+ mw->addr = 0;
+ mw->length = 0;
+ mw->state = RXE_MW_STATE_INVALID;
+}
+
+int rxe_dealloc_mw(struct ib_mw *ibmw)
+{
+ struct rxe_mw *mw = to_rmw(ibmw);
+ struct rxe_pd *pd = to_rpd(ibmw->pd);
+ unsigned long flags;
+
+ spin_lock_irqsave(&mw->lock, flags);
+ rxe_do_dealloc_mw(mw);
+ spin_unlock_irqrestore(&mw->lock, flags);
+
+ rxe_drop_ref(mw);
+ rxe_drop_ref(pd);
+
+ return 0;
+}
+
+static int rxe_check_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
+ struct rxe_mw *mw, struct rxe_mr *mr)
+{
+ if (mw->ibmw.type == IB_MW_TYPE_1) {
+ if (unlikely(mw->state != RXE_MW_STATE_VALID)) {
+ pr_err_once(
+ "attempt to bind a type 1 MW not in the valid state\n");
+ return -EINVAL;
+ }
+
+ /* o10-36.2.2 */
+ if (unlikely((mw->access & IB_ZERO_BASED))) {
+ pr_err_once("attempt to bind a zero based type 1 MW\n");
+ return -EINVAL;
+ }
+ }
+
+ if (mw->ibmw.type == IB_MW_TYPE_2) {
+ /* o10-37.2.30 */
+ if (unlikely(mw->state != RXE_MW_STATE_FREE)) {
+ pr_err_once(
+ "attempt to bind a type 2 MW not in the free state\n");
+ return -EINVAL;
+ }
+
+ /* C10-72 */
+ if (unlikely(qp->pd != to_rpd(mw->ibmw.pd))) {
+ pr_err_once(
+ "attempt to bind type 2 MW with qp with different PD\n");
+ return -EINVAL;
+ }
+
+ /* o10-37.2.40 */
+ if (unlikely(!mr || wqe->wr.wr.mw.length == 0)) {
+ pr_err_once(
+ "attempt to invalidate type 2 MW by binding with NULL or zero length MR\n");
+ return -EINVAL;
+ }
+ }
+
+ if (unlikely((wqe->wr.wr.mw.rkey & 0xff) == (mw->ibmw.rkey & 0xff))) {
+ pr_err_once("attempt to bind MW with same key\n");
+ return -EINVAL;
+ }
+
+ /* remaining checks only apply to a nonzero MR */
+ if (!mr)
+ return 0;
+
+ if (unlikely(mr->access & IB_ZERO_BASED)) {
+ pr_err_once("attempt to bind MW to zero based MR\n");
+ return -EINVAL;
+ }
+
+ /* C10-73 */
+ if (unlikely(!(mr->access & IB_ACCESS_MW_BIND))) {
+ pr_err_once(
+ "attempt to bind an MW to an MR without bind access\n");
+ return -EINVAL;
+ }
+
+ /* C10-74 */
+ if (unlikely((mw->access &
+ (IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_ATOMIC)) &&
+ !(mr->access & IB_ACCESS_LOCAL_WRITE))) {
+ pr_err_once(
+ "attempt to bind an writeable MW to an MR without local write access\n");
+ return -EINVAL;
+ }
+
+ /* C10-75 */
+ if (mw->access & IB_ZERO_BASED) {
+ if (unlikely(wqe->wr.wr.mw.length > mr->length)) {
+ pr_err_once(
+ "attempt to bind a ZB MW outside of the MR\n");
+ return -EINVAL;
+ }
+ } else {
+ if (unlikely((wqe->wr.wr.mw.addr < mr->iova) ||
+ ((wqe->wr.wr.mw.addr + wqe->wr.wr.mw.length) >
+ (mr->iova + mr->length)))) {
+ pr_err_once(
+ "attempt to bind a VA MW outside of the MR\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void rxe_do_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
+ struct rxe_mw *mw, struct rxe_mr *mr)
+{
+ u32 rkey;
+ u32 new_rkey;
+
+ rkey = mw->ibmw.rkey;
+ new_rkey = (rkey & 0xffffff00) | (wqe->wr.wr.mw.rkey & 0x000000ff);
+
+ mw->ibmw.rkey = new_rkey;
+ mw->access = wqe->wr.wr.mw.access;
+ mw->state = RXE_MW_STATE_VALID;
+ mw->addr = wqe->wr.wr.mw.addr;
+ mw->length = wqe->wr.wr.mw.length;
+
+ if (mw->mr) {
+ rxe_drop_ref(mw->mr);
+ atomic_dec(&mw->mr->num_mw);
+ mw->mr = NULL;
+ }
+
+ if (mw->length) {
+ mw->mr = mr;
+ atomic_inc(&mr->num_mw);
+ rxe_add_ref(mr);
+ }
+
+ if (mw->ibmw.type == IB_MW_TYPE_2) {
+ rxe_add_ref(qp);
+ mw->qp = qp;
+ }
+}
+
+int rxe_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
+{
+ int ret;
+ struct rxe_mw *mw;
+ struct rxe_mr *mr;
+ struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+ unsigned long flags;
+
+ mw = rxe_pool_get_index(&rxe->mw_pool,
+ wqe->wr.wr.mw.mw_rkey >> 8);
+ if (unlikely(!mw)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (unlikely(mw->ibmw.rkey != wqe->wr.wr.mw.mw_rkey)) {
+ ret = -EINVAL;
+ goto err_drop_mw;
+ }
+
+ if (likely(wqe->wr.wr.mw.length)) {
+ mr = rxe_pool_get_index(&rxe->mr_pool,
+ wqe->wr.wr.mw.mr_lkey >> 8);
+ if (unlikely(!mr)) {
+ ret = -EINVAL;
+ goto err_drop_mw;
+ }
+
+ if (unlikely(mr->ibmr.lkey != wqe->wr.wr.mw.mr_lkey)) {
+ ret = -EINVAL;
+ goto err_drop_mr;
+ }
+ } else {
+ mr = NULL;
+ }
+
+ spin_lock_irqsave(&mw->lock, flags);
+
+ ret = rxe_check_bind_mw(qp, wqe, mw, mr);
+ if (ret)
+ goto err_unlock;
+
+ rxe_do_bind_mw(qp, wqe, mw, mr);
+err_unlock:
+ spin_unlock_irqrestore(&mw->lock, flags);
+err_drop_mr:
+ if (mr)
+ rxe_drop_ref(mr);
+err_drop_mw:
+ rxe_drop_ref(mw);
+err:
+ return ret;
+}
+
+static int rxe_check_invalidate_mw(struct rxe_qp *qp, struct rxe_mw *mw)
+{
+ if (unlikely(mw->state == RXE_MW_STATE_INVALID))
+ return -EINVAL;
+
+ /* o10-37.2.26 */
+ if (unlikely(mw->ibmw.type == IB_MW_TYPE_1))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void rxe_do_invalidate_mw(struct rxe_mw *mw)
+{
+ struct rxe_qp *qp;
+ struct rxe_mr *mr;
+
+ /* valid type 2 MW will always have a QP pointer */
+ qp = mw->qp;
+ mw->qp = NULL;
+ rxe_drop_ref(qp);
+
+ /* valid type 2 MW will always have an MR pointer */
+ mr = mw->mr;
+ mw->mr = NULL;
+ atomic_dec(&mr->num_mw);
+ rxe_drop_ref(mr);
+
+ mw->access = 0;
+ mw->addr = 0;
+ mw->length = 0;
+ mw->state = RXE_MW_STATE_FREE;
+}
+
+int rxe_invalidate_mw(struct rxe_qp *qp, u32 rkey)
+{
+ struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+ unsigned long flags;
+ struct rxe_mw *mw;
+ int ret;
+
+ mw = rxe_pool_get_index(&rxe->mw_pool, rkey >> 8);
+ if (!mw) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (rkey != mw->ibmw.rkey) {
+ ret = -EINVAL;
+ goto err_drop_ref;
+ }
+
+ spin_lock_irqsave(&mw->lock, flags);
+
+ ret = rxe_check_invalidate_mw(qp, mw);
+ if (ret)
+ goto err_unlock;
+
+ rxe_do_invalidate_mw(mw);
+err_unlock:
+ spin_unlock_irqrestore(&mw->lock, flags);
+err_drop_ref:
+ rxe_drop_ref(mw);
+err:
+ return ret;
+}
+
+struct rxe_mw *rxe_lookup_mw(struct rxe_qp *qp, int access, u32 rkey)
+{
+ struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+ struct rxe_pd *pd = to_rpd(qp->ibqp.pd);
+ struct rxe_mw *mw;
+ int index = rkey >> 8;
+
+ mw = rxe_pool_get_index(&rxe->mw_pool, index);
+ if (!mw)
+ return NULL;
+
+ if (unlikely((rxe_mw_rkey(mw) != rkey) || rxe_mw_pd(mw) != pd ||
+ (mw->ibmw.type == IB_MW_TYPE_2 && mw->qp != qp) ||
+ (mw->length == 0) ||
+ (access && !(access & mw->access)) ||
+ mw->state != RXE_MW_STATE_VALID)) {
+ rxe_drop_ref(mw);
+ return NULL;
+ }
+
+ return mw;
+}
+
+void rxe_mw_cleanup(struct rxe_pool_entry *elem)
+{
+ struct rxe_mw *mw = container_of(elem, typeof(*mw), pelem);
+
+ rxe_drop_index(mw);
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c
index 01662727dca0..dec92928a1cd 100644
--- a/drivers/infiniband/sw/rxe/rxe_net.c
+++ b/drivers/infiniband/sw/rxe/rxe_net.c
@@ -207,10 +207,8 @@ static struct socket *rxe_setup_udp_tunnel(struct net *net, __be16 port,
/* Create UDP socket */
err = udp_sock_create(net, &udp_cfg, &sock);
- if (err < 0) {
- pr_err("failed to create udp socket. err = %d\n", err);
+ if (err < 0)
return ERR_PTR(err);
- }
tnl_cfg.encap_type = 1;
tnl_cfg.encap_rcv = rxe_udp_encap_recv;
@@ -269,8 +267,6 @@ static void prepare_ipv4_hdr(struct dst_entry *dst, struct sk_buff *skb,
iph->ttl = ttl;
__ip_select_ident(dev_net(dst->dev), iph,
skb_shinfo(skb)->gso_segs ?: 1);
- iph->tot_len = htons(skb->len);
- ip_send_check(iph);
}
static void prepare_ipv6_hdr(struct dst_entry *dst, struct sk_buff *skb,
@@ -472,7 +468,7 @@ struct sk_buff *rxe_init_packet(struct rxe_dev *rxe, struct rxe_av *av,
pkt->rxe = rxe;
pkt->port_num = port_num;
- pkt->hdr = skb_put_zero(skb, paylen);
+ pkt->hdr = skb_put(skb, paylen);
pkt->mask |= RXE_GRH_MASK;
out:
@@ -619,6 +615,12 @@ static int rxe_net_ipv6_init(void)
recv_sockets.sk6 = rxe_setup_udp_tunnel(&init_net,
htons(ROCE_V2_UDP_DPORT), true);
+ if (PTR_ERR(recv_sockets.sk6) == -EAFNOSUPPORT) {
+ recv_sockets.sk6 = NULL;
+ pr_warn("IPv6 is not supported, can not create a UDPv6 socket\n");
+ return 0;
+ }
+
if (IS_ERR(recv_sockets.sk6)) {
recv_sockets.sk6 = NULL;
pr_err("Failed to create IPv6 UDP tunnel\n");
diff --git a/drivers/infiniband/sw/rxe/rxe_opcode.c b/drivers/infiniband/sw/rxe/rxe_opcode.c
index 0cb4b01fd910..3ef5a10a6efd 100644
--- a/drivers/infiniband/sw/rxe/rxe_opcode.c
+++ b/drivers/infiniband/sw/rxe/rxe_opcode.c
@@ -87,13 +87,20 @@ struct rxe_wr_opcode_info rxe_wr_opcode_info[] = {
[IB_WR_LOCAL_INV] = {
.name = "IB_WR_LOCAL_INV",
.mask = {
- [IB_QPT_RC] = WR_REG_MASK,
+ [IB_QPT_RC] = WR_LOCAL_OP_MASK,
},
},
[IB_WR_REG_MR] = {
.name = "IB_WR_REG_MR",
.mask = {
- [IB_QPT_RC] = WR_REG_MASK,
+ [IB_QPT_RC] = WR_LOCAL_OP_MASK,
+ },
+ },
+ [IB_WR_BIND_MW] = {
+ .name = "IB_WR_BIND_MW",
+ .mask = {
+ [IB_QPT_RC] = WR_LOCAL_OP_MASK,
+ [IB_QPT_UC] = WR_LOCAL_OP_MASK,
},
},
};
diff --git a/drivers/infiniband/sw/rxe/rxe_opcode.h b/drivers/infiniband/sw/rxe/rxe_opcode.h
index 1041ac9a9233..e02f039b8c44 100644
--- a/drivers/infiniband/sw/rxe/rxe_opcode.h
+++ b/drivers/infiniband/sw/rxe/rxe_opcode.h
@@ -19,8 +19,7 @@ enum rxe_wr_mask {
WR_SEND_MASK = BIT(2),
WR_READ_MASK = BIT(3),
WR_WRITE_MASK = BIT(4),
- WR_LOCAL_MASK = BIT(5),
- WR_REG_MASK = BIT(6),
+ WR_LOCAL_OP_MASK = BIT(5),
WR_READ_OR_WRITE_MASK = WR_READ_MASK | WR_WRITE_MASK,
WR_READ_WRITE_OR_SEND_MASK = WR_READ_OR_WRITE_MASK | WR_SEND_MASK,
diff --git a/drivers/infiniband/sw/rxe/rxe_param.h b/drivers/infiniband/sw/rxe/rxe_param.h
index 25ab50d9b7c2..742e6ec93686 100644
--- a/drivers/infiniband/sw/rxe/rxe_param.h
+++ b/drivers/infiniband/sw/rxe/rxe_param.h
@@ -37,7 +37,6 @@ static inline enum ib_mtu eth_mtu_int_to_enum(int mtu)
enum rxe_device_param {
RXE_MAX_MR_SIZE = -1ull,
RXE_PAGE_SIZE_CAP = 0xfffff000,
- RXE_MAX_QP = 0x10000,
RXE_MAX_QP_WR = 0x4000,
RXE_DEVICE_CAP_FLAGS = IB_DEVICE_BAD_PKEY_CNTR
| IB_DEVICE_BAD_QKEY_CNTR
@@ -49,7 +48,10 @@ enum rxe_device_param {
| IB_DEVICE_RC_RNR_NAK_GEN
| IB_DEVICE_SRQ_RESIZE
| IB_DEVICE_MEM_MGT_EXTENSIONS
- | IB_DEVICE_ALLOW_USER_UNREG,
+ | IB_DEVICE_ALLOW_USER_UNREG
+ | IB_DEVICE_MEM_WINDOW
+ | IB_DEVICE_MEM_WINDOW_TYPE_2A
+ | IB_DEVICE_MEM_WINDOW_TYPE_2B,
RXE_MAX_SGE = 32,
RXE_MAX_WQE_SIZE = sizeof(struct rxe_send_wqe) +
sizeof(struct ib_sge) * RXE_MAX_SGE,
@@ -58,7 +60,6 @@ enum rxe_device_param {
RXE_MAX_SGE_RD = 32,
RXE_MAX_CQ = 16384,
RXE_MAX_LOG_CQE = 15,
- RXE_MAX_MR = 256 * 1024,
RXE_MAX_PD = 0x7ffc,
RXE_MAX_QP_RD_ATOM = 128,
RXE_MAX_RES_RD_ATOM = 0x3f000,
@@ -67,7 +68,6 @@ enum rxe_device_param {
RXE_MAX_MCAST_QP_ATTACH = 56,
RXE_MAX_TOT_MCAST_QP_ATTACH = 0x70000,
RXE_MAX_AH = 100,
- RXE_MAX_SRQ = 960,
RXE_MAX_SRQ_WR = 0x4000,
RXE_MIN_SRQ_WR = 1,
RXE_MAX_SRQ_SGE = 27,
@@ -80,16 +80,21 @@ enum rxe_device_param {
RXE_NUM_PORT = 1,
+ RXE_MAX_QP = 0x10000,
RXE_MIN_QP_INDEX = 16,
RXE_MAX_QP_INDEX = 0x00020000,
+ RXE_MAX_SRQ = 0x00001000,
RXE_MIN_SRQ_INDEX = 0x00020001,
RXE_MAX_SRQ_INDEX = 0x00040000,
+ RXE_MAX_MR = 0x00001000,
+ RXE_MAX_MW = 0x00001000,
RXE_MIN_MR_INDEX = 0x00000001,
- RXE_MAX_MR_INDEX = 0x00040000,
- RXE_MIN_MW_INDEX = 0x00040001,
- RXE_MAX_MW_INDEX = 0x00060000,
+ RXE_MAX_MR_INDEX = 0x00010000,
+ RXE_MIN_MW_INDEX = 0x00010001,
+ RXE_MAX_MW_INDEX = 0x00020000,
+
RXE_MAX_PKT_PER_ACK = 64,
RXE_MAX_UNACKED_PSNS = 128,
diff --git a/drivers/infiniband/sw/rxe/rxe_pool.c b/drivers/infiniband/sw/rxe/rxe_pool.c
index d24901f2af3f..0b8e7c6255a2 100644
--- a/drivers/infiniband/sw/rxe/rxe_pool.c
+++ b/drivers/infiniband/sw/rxe/rxe_pool.c
@@ -65,6 +65,7 @@ struct rxe_type_info rxe_type_info[RXE_NUM_TYPES] = {
.name = "rxe-mw",
.size = sizeof(struct rxe_mw),
.elem_offset = offsetof(struct rxe_mw, pelem),
+ .cleanup = rxe_mw_cleanup,
.flags = RXE_POOL_INDEX | RXE_POOL_NO_ALLOC,
.max_index = RXE_MAX_MW_INDEX,
.min_index = RXE_MIN_MW_INDEX,
@@ -183,7 +184,7 @@ static u32 alloc_index(struct rxe_pool *pool)
return index + pool->index.min_index;
}
-static void insert_index(struct rxe_pool *pool, struct rxe_pool_entry *new)
+static int rxe_insert_index(struct rxe_pool *pool, struct rxe_pool_entry *new)
{
struct rb_node **link = &pool->index.tree.rb_node;
struct rb_node *parent = NULL;
@@ -195,7 +196,7 @@ static void insert_index(struct rxe_pool *pool, struct rxe_pool_entry *new)
if (elem->index == new->index) {
pr_warn("element already exists!\n");
- goto out;
+ return -EINVAL;
}
if (elem->index > new->index)
@@ -206,11 +207,11 @@ static void insert_index(struct rxe_pool *pool, struct rxe_pool_entry *new)
rb_link_node(&new->index_node, parent, link);
rb_insert_color(&new->index_node, &pool->index.tree);
-out:
- return;
+
+ return 0;
}
-static void insert_key(struct rxe_pool *pool, struct rxe_pool_entry *new)
+static int rxe_insert_key(struct rxe_pool *pool, struct rxe_pool_entry *new)
{
struct rb_node **link = &pool->key.tree.rb_node;
struct rb_node *parent = NULL;
@@ -226,7 +227,7 @@ static void insert_key(struct rxe_pool *pool, struct rxe_pool_entry *new)
if (cmp == 0) {
pr_warn("key already exists!\n");
- goto out;
+ return -EINVAL;
}
if (cmp > 0)
@@ -237,26 +238,32 @@ static void insert_key(struct rxe_pool *pool, struct rxe_pool_entry *new)
rb_link_node(&new->key_node, parent, link);
rb_insert_color(&new->key_node, &pool->key.tree);
-out:
- return;
+
+ return 0;
}
-void __rxe_add_key_locked(struct rxe_pool_entry *elem, void *key)
+int __rxe_add_key_locked(struct rxe_pool_entry *elem, void *key)
{
struct rxe_pool *pool = elem->pool;
+ int err;
memcpy((u8 *)elem + pool->key.key_offset, key, pool->key.key_size);
- insert_key(pool, elem);
+ err = rxe_insert_key(pool, elem);
+
+ return err;
}
-void __rxe_add_key(struct rxe_pool_entry *elem, void *key)
+int __rxe_add_key(struct rxe_pool_entry *elem, void *key)
{
struct rxe_pool *pool = elem->pool;
unsigned long flags;
+ int err;
write_lock_irqsave(&pool->pool_lock, flags);
- __rxe_add_key_locked(elem, key);
+ err = __rxe_add_key_locked(elem, key);
write_unlock_irqrestore(&pool->pool_lock, flags);
+
+ return err;
}
void __rxe_drop_key_locked(struct rxe_pool_entry *elem)
@@ -276,22 +283,28 @@ void __rxe_drop_key(struct rxe_pool_entry *elem)
write_unlock_irqrestore(&pool->pool_lock, flags);
}
-void __rxe_add_index_locked(struct rxe_pool_entry *elem)
+int __rxe_add_index_locked(struct rxe_pool_entry *elem)
{
struct rxe_pool *pool = elem->pool;
+ int err;
elem->index = alloc_index(pool);
- insert_index(pool, elem);
+ err = rxe_insert_index(pool, elem);
+
+ return err;
}
-void __rxe_add_index(struct rxe_pool_entry *elem)
+int __rxe_add_index(struct rxe_pool_entry *elem)
{
struct rxe_pool *pool = elem->pool;
unsigned long flags;
+ int err;
write_lock_irqsave(&pool->pool_lock, flags);
- __rxe_add_index_locked(elem);
+ err = __rxe_add_index_locked(elem);
write_unlock_irqrestore(&pool->pool_lock, flags);
+
+ return err;
}
void __rxe_drop_index_locked(struct rxe_pool_entry *elem)
diff --git a/drivers/infiniband/sw/rxe/rxe_pool.h b/drivers/infiniband/sw/rxe/rxe_pool.h
index 61210b300a78..1feca1bffced 100644
--- a/drivers/infiniband/sw/rxe/rxe_pool.h
+++ b/drivers/infiniband/sw/rxe/rxe_pool.h
@@ -111,11 +111,11 @@ int __rxe_add_to_pool(struct rxe_pool *pool, struct rxe_pool_entry *elem);
/* assign an index to an indexed object and insert object into
* pool's rb tree holding and not holding the pool_lock
*/
-void __rxe_add_index_locked(struct rxe_pool_entry *elem);
+int __rxe_add_index_locked(struct rxe_pool_entry *elem);
#define rxe_add_index_locked(obj) __rxe_add_index_locked(&(obj)->pelem)
-void __rxe_add_index(struct rxe_pool_entry *elem);
+int __rxe_add_index(struct rxe_pool_entry *elem);
#define rxe_add_index(obj) __rxe_add_index(&(obj)->pelem)
@@ -133,11 +133,11 @@ void __rxe_drop_index(struct rxe_pool_entry *elem);
/* assign a key to a keyed object and insert object into
* pool's rb tree holding and not holding pool_lock
*/
-void __rxe_add_key_locked(struct rxe_pool_entry *elem, void *key);
+int __rxe_add_key_locked(struct rxe_pool_entry *elem, void *key);
#define rxe_add_key_locked(obj, key) __rxe_add_key_locked(&(obj)->pelem, key)
-void __rxe_add_key(struct rxe_pool_entry *elem, void *key);
+int __rxe_add_key(struct rxe_pool_entry *elem, void *key);
#define rxe_add_key(obj, key) __rxe_add_key(&(obj)->pelem, key)
diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c
index b0f350d674fd..1ab6af7ddb25 100644
--- a/drivers/infiniband/sw/rxe/rxe_qp.c
+++ b/drivers/infiniband/sw/rxe/rxe_qp.c
@@ -136,7 +136,6 @@ static void free_rd_atomic_resources(struct rxe_qp *qp)
void free_rd_atomic_resource(struct rxe_qp *qp, struct resp_res *res)
{
if (res->type == RXE_ATOMIC_MASK) {
- rxe_drop_ref(qp);
kfree_skb(res->atomic.skb);
} else if (res->type == RXE_READ_MASK) {
if (res->read.mr)
@@ -206,6 +205,7 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp,
{
int err;
int wqe_size;
+ enum queue_type type;
err = sock_create_kern(&init_net, AF_INET, SOCK_DGRAM, 0, &qp->sk);
if (err < 0)
@@ -231,7 +231,9 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp,
qp->sq.max_inline = init->cap.max_inline_data = wqe_size;
wqe_size += sizeof(struct rxe_send_wqe);
- qp->sq.queue = rxe_queue_init(rxe, &qp->sq.max_wr, wqe_size);
+ type = uresp ? QUEUE_TYPE_FROM_USER : QUEUE_TYPE_KERNEL;
+ qp->sq.queue = rxe_queue_init(rxe, &qp->sq.max_wr,
+ wqe_size, type);
if (!qp->sq.queue)
return -ENOMEM;
@@ -246,7 +248,13 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp,
return err;
}
- qp->req.wqe_index = producer_index(qp->sq.queue);
+ if (qp->is_user)
+ qp->req.wqe_index = producer_index(qp->sq.queue,
+ QUEUE_TYPE_FROM_USER);
+ else
+ qp->req.wqe_index = producer_index(qp->sq.queue,
+ QUEUE_TYPE_KERNEL);
+
qp->req.state = QP_STATE_RESET;
qp->req.opcode = -1;
qp->comp.opcode = -1;
@@ -274,6 +282,7 @@ static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp,
{
int err;
int wqe_size;
+ enum queue_type type;
if (!qp->srq) {
qp->rq.max_wr = init->cap.max_recv_wr;
@@ -284,9 +293,9 @@ static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp,
pr_debug("qp#%d max_wr = %d, max_sge = %d, wqe_size = %d\n",
qp_num(qp), qp->rq.max_wr, qp->rq.max_sge, wqe_size);
- qp->rq.queue = rxe_queue_init(rxe,
- &qp->rq.max_wr,
- wqe_size);
+ type = uresp ? QUEUE_TYPE_FROM_USER : QUEUE_TYPE_KERNEL;
+ qp->rq.queue = rxe_queue_init(rxe, &qp->rq.max_wr,
+ wqe_size, type);
if (!qp->rq.queue)
return -ENOMEM;
@@ -304,6 +313,8 @@ static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp,
spin_lock_init(&qp->rq.producer_lock);
spin_lock_init(&qp->rq.consumer_lock);
+ qp->rq.is_user = qp->is_user;
+
skb_queue_head_init(&qp->resp_pkts);
rxe_init_task(rxe, &qp->resp.task, qp,
diff --git a/drivers/infiniband/sw/rxe/rxe_queue.c b/drivers/infiniband/sw/rxe/rxe_queue.c
index fa69241b1187..85b812586ed4 100644
--- a/drivers/infiniband/sw/rxe/rxe_queue.c
+++ b/drivers/infiniband/sw/rxe/rxe_queue.c
@@ -52,9 +52,8 @@ inline void rxe_queue_reset(struct rxe_queue *q)
memset(q->buf->data, 0, q->buf_size - sizeof(struct rxe_queue_buf));
}
-struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe,
- int *num_elem,
- unsigned int elem_size)
+struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe, int *num_elem,
+ unsigned int elem_size, enum queue_type type)
{
struct rxe_queue *q;
size_t buf_size;
@@ -69,6 +68,7 @@ struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe,
goto err1;
q->rxe = rxe;
+ q->type = type;
/* used in resize, only need to copy used part of queue */
q->elem_size = elem_size;
@@ -111,14 +111,15 @@ err1:
static int resize_finish(struct rxe_queue *q, struct rxe_queue *new_q,
unsigned int num_elem)
{
- if (!queue_empty(q) && (num_elem < queue_count(q)))
+ if (!queue_empty(q, q->type) && (num_elem < queue_count(q, q->type)))
return -EINVAL;
- while (!queue_empty(q)) {
- memcpy(producer_addr(new_q), consumer_addr(q),
- new_q->elem_size);
- advance_producer(new_q);
- advance_consumer(q);
+ while (!queue_empty(q, q->type)) {
+ memcpy(producer_addr(new_q, new_q->type),
+ consumer_addr(q, q->type),
+ new_q->elem_size);
+ advance_producer(new_q, new_q->type);
+ advance_consumer(q, q->type);
}
swap(*q, *new_q);
@@ -136,7 +137,7 @@ int rxe_queue_resize(struct rxe_queue *q, unsigned int *num_elem_p,
int err;
unsigned long flags = 0, flags1;
- new_q = rxe_queue_init(q->rxe, &num_elem, elem_size);
+ new_q = rxe_queue_init(q->rxe, &num_elem, elem_size, q->type);
if (!new_q)
return -ENOMEM;
diff --git a/drivers/infiniband/sw/rxe/rxe_queue.h b/drivers/infiniband/sw/rxe/rxe_queue.h
index 2902ca7b288c..2702b0e55fc3 100644
--- a/drivers/infiniband/sw/rxe/rxe_queue.h
+++ b/drivers/infiniband/sw/rxe/rxe_queue.h
@@ -17,8 +17,29 @@
* up to a power of 2. Since the queue is empty when the
* producer and consumer indices match the maximum capacity
* of the queue is one less than the number of element slots
+ *
+ * Notes:
+ * - Kernel space indices are always masked off to q->index_mask
+ * before storing so do not need to be checked on reads.
+ * - User space indices may be out of range and must be
+ * masked before use when read.
+ * - The kernel indices for shared queues must not be written
+ * by user space so a local copy is used and a shared copy is
+ * stored when the local copy changes.
+ * - By passing the type in the parameter list separate from q
+ * the compiler can eliminate the switch statement when the
+ * actual queue type is known when the function is called.
+ * In the performance path this is done. In less critical
+ * paths just q->type is passed.
*/
+/* type of queue */
+enum queue_type {
+ QUEUE_TYPE_KERNEL,
+ QUEUE_TYPE_TO_USER,
+ QUEUE_TYPE_FROM_USER,
+};
+
struct rxe_queue {
struct rxe_dev *rxe;
struct rxe_queue_buf *buf;
@@ -27,6 +48,13 @@ struct rxe_queue {
size_t elem_size;
unsigned int log2_elem_size;
u32 index_mask;
+ enum queue_type type;
+ /* private copy of index for shared queues between
+ * kernel space and user space. Kernel reads and writes
+ * this copy and then replicates to rxe_queue_buf
+ * for read access by user space.
+ */
+ u32 index;
};
int do_mmap_info(struct rxe_dev *rxe, struct mminfo __user *outbuf,
@@ -35,9 +63,8 @@ int do_mmap_info(struct rxe_dev *rxe, struct mminfo __user *outbuf,
void rxe_queue_reset(struct rxe_queue *q);
-struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe,
- int *num_elem,
- unsigned int elem_size);
+struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe, int *num_elem,
+ unsigned int elem_size, enum queue_type type);
int rxe_queue_resize(struct rxe_queue *q, unsigned int *num_elem_p,
unsigned int elem_size, struct ib_udata *udata,
@@ -54,120 +81,235 @@ static inline int next_index(struct rxe_queue *q, int index)
return (index + 1) & q->buf->index_mask;
}
-static inline int queue_empty(struct rxe_queue *q)
+static inline int queue_empty(struct rxe_queue *q, enum queue_type type)
{
u32 prod;
u32 cons;
- /* make sure all changes to queue complete before
- * testing queue empty
- */
- prod = smp_load_acquire(&q->buf->producer_index);
- /* same */
- cons = smp_load_acquire(&q->buf->consumer_index);
+ switch (type) {
+ case QUEUE_TYPE_FROM_USER:
+ /* protect user space index */
+ prod = smp_load_acquire(&q->buf->producer_index);
+ cons = q->index;
+ break;
+ case QUEUE_TYPE_TO_USER:
+ prod = q->index;
+ /* protect user space index */
+ cons = smp_load_acquire(&q->buf->consumer_index);
+ break;
+ case QUEUE_TYPE_KERNEL:
+ prod = q->buf->producer_index;
+ cons = q->buf->consumer_index;
+ break;
+ }
return ((prod - cons) & q->index_mask) == 0;
}
-static inline int queue_full(struct rxe_queue *q)
+static inline int queue_full(struct rxe_queue *q, enum queue_type type)
{
u32 prod;
u32 cons;
- /* make sure all changes to queue complete before
- * testing queue full
- */
- prod = smp_load_acquire(&q->buf->producer_index);
- /* same */
- cons = smp_load_acquire(&q->buf->consumer_index);
+ switch (type) {
+ case QUEUE_TYPE_FROM_USER:
+ /* protect user space index */
+ prod = smp_load_acquire(&q->buf->producer_index);
+ cons = q->index;
+ break;
+ case QUEUE_TYPE_TO_USER:
+ prod = q->index;
+ /* protect user space index */
+ cons = smp_load_acquire(&q->buf->consumer_index);
+ break;
+ case QUEUE_TYPE_KERNEL:
+ prod = q->buf->producer_index;
+ cons = q->buf->consumer_index;
+ break;
+ }
return ((prod + 1 - cons) & q->index_mask) == 0;
}
-static inline void advance_producer(struct rxe_queue *q)
+static inline unsigned int queue_count(const struct rxe_queue *q,
+ enum queue_type type)
{
u32 prod;
+ u32 cons;
- prod = (q->buf->producer_index + 1) & q->index_mask;
+ switch (type) {
+ case QUEUE_TYPE_FROM_USER:
+ /* protect user space index */
+ prod = smp_load_acquire(&q->buf->producer_index);
+ cons = q->index;
+ break;
+ case QUEUE_TYPE_TO_USER:
+ prod = q->index;
+ /* protect user space index */
+ cons = smp_load_acquire(&q->buf->consumer_index);
+ break;
+ case QUEUE_TYPE_KERNEL:
+ prod = q->buf->producer_index;
+ cons = q->buf->consumer_index;
+ break;
+ }
+
+ return (prod - cons) & q->index_mask;
+}
- /* make sure all changes to queue complete before
- * changing producer index
- */
- smp_store_release(&q->buf->producer_index, prod);
+static inline void advance_producer(struct rxe_queue *q, enum queue_type type)
+{
+ u32 prod;
+
+ switch (type) {
+ case QUEUE_TYPE_FROM_USER:
+ pr_warn_once("Normally kernel should not write user space index\n");
+ /* protect user space index */
+ prod = smp_load_acquire(&q->buf->producer_index);
+ prod = (prod + 1) & q->index_mask;
+ /* same */
+ smp_store_release(&q->buf->producer_index, prod);
+ break;
+ case QUEUE_TYPE_TO_USER:
+ prod = q->index;
+ q->index = (prod + 1) & q->index_mask;
+ q->buf->producer_index = q->index;
+ break;
+ case QUEUE_TYPE_KERNEL:
+ prod = q->buf->producer_index;
+ q->buf->producer_index = (prod + 1) & q->index_mask;
+ break;
+ }
}
-static inline void advance_consumer(struct rxe_queue *q)
+static inline void advance_consumer(struct rxe_queue *q, enum queue_type type)
{
u32 cons;
- cons = (q->buf->consumer_index + 1) & q->index_mask;
-
- /* make sure all changes to queue complete before
- * changing consumer index
- */
- smp_store_release(&q->buf->consumer_index, cons);
+ switch (type) {
+ case QUEUE_TYPE_FROM_USER:
+ cons = q->index;
+ q->index = (cons + 1) & q->index_mask;
+ q->buf->consumer_index = q->index;
+ break;
+ case QUEUE_TYPE_TO_USER:
+ pr_warn_once("Normally kernel should not write user space index\n");
+ /* protect user space index */
+ cons = smp_load_acquire(&q->buf->consumer_index);
+ cons = (cons + 1) & q->index_mask;
+ /* same */
+ smp_store_release(&q->buf->consumer_index, cons);
+ break;
+ case QUEUE_TYPE_KERNEL:
+ cons = q->buf->consumer_index;
+ q->buf->consumer_index = (cons + 1) & q->index_mask;
+ break;
+ }
}
-static inline void *producer_addr(struct rxe_queue *q)
+static inline void *producer_addr(struct rxe_queue *q, enum queue_type type)
{
- return q->buf->data + ((q->buf->producer_index & q->index_mask)
- << q->log2_elem_size);
+ u32 prod;
+
+ switch (type) {
+ case QUEUE_TYPE_FROM_USER:
+ /* protect user space index */
+ prod = smp_load_acquire(&q->buf->producer_index);
+ prod &= q->index_mask;
+ break;
+ case QUEUE_TYPE_TO_USER:
+ prod = q->index;
+ break;
+ case QUEUE_TYPE_KERNEL:
+ prod = q->buf->producer_index;
+ break;
+ }
+
+ return q->buf->data + (prod << q->log2_elem_size);
}
-static inline void *consumer_addr(struct rxe_queue *q)
+static inline void *consumer_addr(struct rxe_queue *q, enum queue_type type)
{
- return q->buf->data + ((q->buf->consumer_index & q->index_mask)
- << q->log2_elem_size);
+ u32 cons;
+
+ switch (type) {
+ case QUEUE_TYPE_FROM_USER:
+ cons = q->index;
+ break;
+ case QUEUE_TYPE_TO_USER:
+ /* protect user space index */
+ cons = smp_load_acquire(&q->buf->consumer_index);
+ cons &= q->index_mask;
+ break;
+ case QUEUE_TYPE_KERNEL:
+ cons = q->buf->consumer_index;
+ break;
+ }
+
+ return q->buf->data + (cons << q->log2_elem_size);
}
-static inline unsigned int producer_index(struct rxe_queue *q)
+static inline unsigned int producer_index(struct rxe_queue *q,
+ enum queue_type type)
{
- u32 index;
-
- /* make sure all changes to queue
- * complete before getting producer index
- */
- index = smp_load_acquire(&q->buf->producer_index);
- index &= q->index_mask;
+ u32 prod;
- return index;
+ switch (type) {
+ case QUEUE_TYPE_FROM_USER:
+ /* protect user space index */
+ prod = smp_load_acquire(&q->buf->producer_index);
+ prod &= q->index_mask;
+ break;
+ case QUEUE_TYPE_TO_USER:
+ prod = q->index;
+ break;
+ case QUEUE_TYPE_KERNEL:
+ prod = q->buf->producer_index;
+ break;
+ }
+
+ return prod;
}
-static inline unsigned int consumer_index(struct rxe_queue *q)
+static inline unsigned int consumer_index(struct rxe_queue *q,
+ enum queue_type type)
{
- u32 index;
-
- /* make sure all changes to queue
- * complete before getting consumer index
- */
- index = smp_load_acquire(&q->buf->consumer_index);
- index &= q->index_mask;
+ u32 cons;
- return index;
+ switch (type) {
+ case QUEUE_TYPE_FROM_USER:
+ cons = q->index;
+ break;
+ case QUEUE_TYPE_TO_USER:
+ /* protect user space index */
+ cons = smp_load_acquire(&q->buf->consumer_index);
+ cons &= q->index_mask;
+ break;
+ case QUEUE_TYPE_KERNEL:
+ cons = q->buf->consumer_index;
+ break;
+ }
+
+ return cons;
}
-static inline void *addr_from_index(struct rxe_queue *q, unsigned int index)
+static inline void *addr_from_index(struct rxe_queue *q,
+ unsigned int index)
{
return q->buf->data + ((index & q->index_mask)
<< q->buf->log2_elem_size);
}
static inline unsigned int index_from_addr(const struct rxe_queue *q,
- const void *addr)
+ const void *addr)
{
return (((u8 *)addr - q->buf->data) >> q->log2_elem_size)
- & q->index_mask;
-}
-
-static inline unsigned int queue_count(const struct rxe_queue *q)
-{
- return (q->buf->producer_index - q->buf->consumer_index)
- & q->index_mask;
+ & q->index_mask;
}
-static inline void *queue_head(struct rxe_queue *q)
+static inline void *queue_head(struct rxe_queue *q, enum queue_type type)
{
- return queue_empty(q) ? NULL : consumer_addr(q);
+ return queue_empty(q, type) ? NULL : consumer_addr(q, type);
}
#endif /* RXE_QUEUE_H */
diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c
index 3664cdae7e1f..c57699cc6578 100644
--- a/drivers/infiniband/sw/rxe/rxe_req.c
+++ b/drivers/infiniband/sw/rxe/rxe_req.c
@@ -45,14 +45,24 @@ static void req_retry(struct rxe_qp *qp)
unsigned int mask;
int npsn;
int first = 1;
+ struct rxe_queue *q = qp->sq.queue;
+ unsigned int cons;
+ unsigned int prod;
- qp->req.wqe_index = consumer_index(qp->sq.queue);
+ if (qp->is_user) {
+ cons = consumer_index(q, QUEUE_TYPE_FROM_USER);
+ prod = producer_index(q, QUEUE_TYPE_FROM_USER);
+ } else {
+ cons = consumer_index(q, QUEUE_TYPE_KERNEL);
+ prod = producer_index(q, QUEUE_TYPE_KERNEL);
+ }
+
+ qp->req.wqe_index = cons;
qp->req.psn = qp->comp.psn;
qp->req.opcode = -1;
- for (wqe_index = consumer_index(qp->sq.queue);
- wqe_index != producer_index(qp->sq.queue);
- wqe_index = next_index(qp->sq.queue, wqe_index)) {
+ for (wqe_index = cons; wqe_index != prod;
+ wqe_index = next_index(q, wqe_index)) {
wqe = addr_from_index(qp->sq.queue, wqe_index);
mask = wr_opcode_mask(wqe->wr.opcode, qp);
@@ -104,8 +114,22 @@ void rnr_nak_timer(struct timer_list *t)
static struct rxe_send_wqe *req_next_wqe(struct rxe_qp *qp)
{
- struct rxe_send_wqe *wqe = queue_head(qp->sq.queue);
+ struct rxe_send_wqe *wqe;
unsigned long flags;
+ struct rxe_queue *q = qp->sq.queue;
+ unsigned int index = qp->req.wqe_index;
+ unsigned int cons;
+ unsigned int prod;
+
+ if (qp->is_user) {
+ wqe = queue_head(q, QUEUE_TYPE_FROM_USER);
+ cons = consumer_index(q, QUEUE_TYPE_FROM_USER);
+ prod = producer_index(q, QUEUE_TYPE_FROM_USER);
+ } else {
+ wqe = queue_head(q, QUEUE_TYPE_KERNEL);
+ cons = consumer_index(q, QUEUE_TYPE_KERNEL);
+ prod = producer_index(q, QUEUE_TYPE_KERNEL);
+ }
if (unlikely(qp->req.state == QP_STATE_DRAIN)) {
/* check to see if we are drained;
@@ -120,8 +144,7 @@ static struct rxe_send_wqe *req_next_wqe(struct rxe_qp *qp)
break;
}
- if (wqe && ((qp->req.wqe_index !=
- consumer_index(qp->sq.queue)) ||
+ if (wqe && ((index != cons) ||
(wqe->state != wqe_state_posted))) {
/* comp not done yet */
spin_unlock_irqrestore(&qp->state_lock,
@@ -144,10 +167,10 @@ static struct rxe_send_wqe *req_next_wqe(struct rxe_qp *qp)
} while (0);
}
- if (qp->req.wqe_index == producer_index(qp->sq.queue))
+ if (index == prod)
return NULL;
- wqe = addr_from_index(qp->sq.queue, qp->req.wqe_index);
+ wqe = addr_from_index(q, index);
if (unlikely((qp->req.state == QP_STATE_DRAIN ||
qp->req.state == QP_STATE_DRAINED) &&
@@ -155,7 +178,7 @@ static struct rxe_send_wqe *req_next_wqe(struct rxe_qp *qp)
return NULL;
if (unlikely((wqe->wr.send_flags & IB_SEND_FENCE) &&
- (qp->req.wqe_index != consumer_index(qp->sq.queue)))) {
+ (index != cons))) {
qp->req.wait_fence = 1;
return NULL;
}
@@ -439,7 +462,7 @@ static struct sk_buff *init_req_packet(struct rxe_qp *qp,
return skb;
}
-static int fill_packet(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
+static int finish_packet(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
struct rxe_pkt_info *pkt, struct sk_buff *skb,
int paylen)
{
@@ -464,7 +487,7 @@ static int fill_packet(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
} else {
err = copy_data(qp->pd, 0, &wqe->dma,
payload_addr(pkt), paylen,
- from_mr_obj,
+ RXE_FROM_MR_OBJ,
&crc);
if (err)
return err;
@@ -555,6 +578,60 @@ static void update_state(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
jiffies + qp->qp_timeout_jiffies);
}
+static int rxe_do_local_ops(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
+{
+ u8 opcode = wqe->wr.opcode;
+ struct rxe_mr *mr;
+ u32 rkey;
+ int ret;
+
+ switch (opcode) {
+ case IB_WR_LOCAL_INV:
+ rkey = wqe->wr.ex.invalidate_rkey;
+ if (rkey_is_mw(rkey))
+ ret = rxe_invalidate_mw(qp, rkey);
+ else
+ ret = rxe_invalidate_mr(qp, rkey);
+
+ if (unlikely(ret)) {
+ wqe->status = IB_WC_LOC_QP_OP_ERR;
+ return ret;
+ }
+ break;
+ case IB_WR_REG_MR:
+ mr = to_rmr(wqe->wr.wr.reg.mr);
+ rxe_add_ref(mr);
+ mr->state = RXE_MR_STATE_VALID;
+ mr->access = wqe->wr.wr.reg.access;
+ mr->ibmr.lkey = wqe->wr.wr.reg.key;
+ mr->ibmr.rkey = wqe->wr.wr.reg.key;
+ mr->iova = wqe->wr.wr.reg.mr->iova;
+ rxe_drop_ref(mr);
+ break;
+ case IB_WR_BIND_MW:
+ ret = rxe_bind_mw(qp, wqe);
+ if (unlikely(ret)) {
+ wqe->status = IB_WC_MW_BIND_ERR;
+ return ret;
+ }
+ break;
+ default:
+ pr_err("Unexpected send wqe opcode %d\n", opcode);
+ wqe->status = IB_WC_LOC_QP_OP_ERR;
+ return -EINVAL;
+ }
+
+ wqe->state = wqe_state_done;
+ wqe->status = IB_WC_SUCCESS;
+ qp->req.wqe_index = next_index(qp->sq.queue, qp->req.wqe_index);
+
+ if ((wqe->wr.send_flags & IB_SEND_SIGNALED) ||
+ qp->sq_sig_type == IB_SIGNAL_ALL_WR)
+ rxe_run_task(&qp->comp.task, 1);
+
+ return 0;
+}
+
int rxe_requester(void *arg)
{
struct rxe_qp *qp = (struct rxe_qp *)arg;
@@ -568,6 +645,7 @@ int rxe_requester(void *arg)
int ret;
struct rxe_send_wqe rollback_wqe;
u32 rollback_psn;
+ struct rxe_queue *q = qp->sq.queue;
rxe_add_ref(qp);
@@ -576,7 +654,7 @@ next_wqe:
goto exit;
if (unlikely(qp->req.state == QP_STATE_RESET)) {
- qp->req.wqe_index = consumer_index(qp->sq.queue);
+ qp->req.wqe_index = consumer_index(q, q->type);
qp->req.opcode = -1;
qp->req.need_rd_atomic = 0;
qp->req.wait_psn = 0;
@@ -593,43 +671,12 @@ next_wqe:
if (unlikely(!wqe))
goto exit;
- if (wqe->mask & WR_REG_MASK) {
- if (wqe->wr.opcode == IB_WR_LOCAL_INV) {
- struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
- struct rxe_mr *rmr;
-
- rmr = rxe_pool_get_index(&rxe->mr_pool,
- wqe->wr.ex.invalidate_rkey >> 8);
- if (!rmr) {
- pr_err("No mr for key %#x\n",
- wqe->wr.ex.invalidate_rkey);
- wqe->state = wqe_state_error;
- wqe->status = IB_WC_MW_BIND_ERR;
- goto exit;
- }
- rmr->state = RXE_MR_STATE_FREE;
- rxe_drop_ref(rmr);
- wqe->state = wqe_state_done;
- wqe->status = IB_WC_SUCCESS;
- } else if (wqe->wr.opcode == IB_WR_REG_MR) {
- struct rxe_mr *rmr = to_rmr(wqe->wr.wr.reg.mr);
-
- rmr->state = RXE_MR_STATE_VALID;
- rmr->access = wqe->wr.wr.reg.access;
- rmr->ibmr.lkey = wqe->wr.wr.reg.key;
- rmr->ibmr.rkey = wqe->wr.wr.reg.key;
- rmr->iova = wqe->wr.wr.reg.mr->iova;
- wqe->state = wqe_state_done;
- wqe->status = IB_WC_SUCCESS;
- } else {
- goto exit;
- }
- if ((wqe->wr.send_flags & IB_SEND_SIGNALED) ||
- qp->sq_sig_type == IB_SIGNAL_ALL_WR)
- rxe_run_task(&qp->comp.task, 1);
- qp->req.wqe_index = next_index(qp->sq.queue,
- qp->req.wqe_index);
- goto next_wqe;
+ if (wqe->mask & WR_LOCAL_OP_MASK) {
+ ret = rxe_do_local_ops(qp, wqe);
+ if (unlikely(ret))
+ goto err;
+ else
+ goto next_wqe;
}
if (unlikely(qp_type(qp) == IB_QPT_RC &&
@@ -687,11 +734,17 @@ next_wqe:
skb = init_req_packet(qp, wqe, opcode, payload, &pkt);
if (unlikely(!skb)) {
pr_err("qp#%d Failed allocating skb\n", qp_num(qp));
+ wqe->status = IB_WC_LOC_QP_OP_ERR;
goto err;
}
- if (fill_packet(qp, wqe, &pkt, skb, payload)) {
- pr_debug("qp#%d Error during fill packet\n", qp_num(qp));
+ ret = finish_packet(qp, wqe, &pkt, skb, payload);
+ if (unlikely(ret)) {
+ pr_debug("qp#%d Error during finish packet\n", qp_num(qp));
+ if (ret == -EFAULT)
+ wqe->status = IB_WC_LOC_PROT_ERR;
+ else
+ wqe->status = IB_WC_LOC_QP_OP_ERR;
kfree_skb(skb);
goto err;
}
@@ -716,6 +769,7 @@ next_wqe:
goto exit;
}
+ wqe->status = IB_WC_LOC_QP_OP_ERR;
goto err;
}
@@ -724,7 +778,6 @@ next_wqe:
goto next_wqe;
err:
- wqe->status = IB_WC_LOC_PROT_ERR;
wqe->state = wqe_state_error;
__rxe_do_task(&qp->comp.task);
diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c
index 2b220659bddb..3743dc39b60c 100644
--- a/drivers/infiniband/sw/rxe/rxe_resp.c
+++ b/drivers/infiniband/sw/rxe/rxe_resp.c
@@ -35,6 +35,7 @@ enum resp_states {
RESPST_ERR_TOO_MANY_RDMA_ATM_REQ,
RESPST_ERR_RNR,
RESPST_ERR_RKEY_VIOLATION,
+ RESPST_ERR_INVALIDATE_RKEY,
RESPST_ERR_LENGTH,
RESPST_ERR_CQ_OVERFLOW,
RESPST_ERROR,
@@ -68,6 +69,7 @@ static char *resp_state_name[] = {
[RESPST_ERR_TOO_MANY_RDMA_ATM_REQ] = "ERR_TOO_MANY_RDMA_ATM_REQ",
[RESPST_ERR_RNR] = "ERR_RNR",
[RESPST_ERR_RKEY_VIOLATION] = "ERR_RKEY_VIOLATION",
+ [RESPST_ERR_INVALIDATE_RKEY] = "ERR_INVALIDATE_RKEY_VIOLATION",
[RESPST_ERR_LENGTH] = "ERR_LENGTH",
[RESPST_ERR_CQ_OVERFLOW] = "ERR_CQ_OVERFLOW",
[RESPST_ERROR] = "ERROR",
@@ -293,26 +295,42 @@ static enum resp_states get_srq_wqe(struct rxe_qp *qp)
struct rxe_queue *q = srq->rq.queue;
struct rxe_recv_wqe *wqe;
struct ib_event ev;
+ unsigned int count;
+ size_t size;
if (srq->error)
return RESPST_ERR_RNR;
spin_lock_bh(&srq->rq.consumer_lock);
- wqe = queue_head(q);
+ if (qp->is_user)
+ wqe = queue_head(q, QUEUE_TYPE_FROM_USER);
+ else
+ wqe = queue_head(q, QUEUE_TYPE_KERNEL);
if (!wqe) {
spin_unlock_bh(&srq->rq.consumer_lock);
return RESPST_ERR_RNR;
}
- /* note kernel and user space recv wqes have same size */
- memcpy(&qp->resp.srq_wqe, wqe, sizeof(qp->resp.srq_wqe));
+ /* don't trust user space data */
+ if (unlikely(wqe->dma.num_sge > srq->rq.max_sge)) {
+ spin_unlock_bh(&srq->rq.consumer_lock);
+ pr_warn("%s: invalid num_sge in SRQ entry\n", __func__);
+ return RESPST_ERR_MALFORMED_WQE;
+ }
+ size = sizeof(wqe) + wqe->dma.num_sge*sizeof(struct rxe_sge);
+ memcpy(&qp->resp.srq_wqe, wqe, size);
qp->resp.wqe = &qp->resp.srq_wqe.wqe;
- advance_consumer(q);
+ if (qp->is_user) {
+ advance_consumer(q, QUEUE_TYPE_FROM_USER);
+ count = queue_count(q, QUEUE_TYPE_FROM_USER);
+ } else {
+ advance_consumer(q, QUEUE_TYPE_KERNEL);
+ count = queue_count(q, QUEUE_TYPE_KERNEL);
+ }
- if (srq->limit && srq->ibsrq.event_handler &&
- (queue_count(q) < srq->limit)) {
+ if (srq->limit && srq->ibsrq.event_handler && (count < srq->limit)) {
srq->limit = 0;
goto event;
}
@@ -339,7 +357,12 @@ static enum resp_states check_resource(struct rxe_qp *qp,
qp->resp.status = IB_WC_WR_FLUSH_ERR;
return RESPST_COMPLETE;
} else if (!srq) {
- qp->resp.wqe = queue_head(qp->rq.queue);
+ if (qp->is_user)
+ qp->resp.wqe = queue_head(qp->rq.queue,
+ QUEUE_TYPE_FROM_USER);
+ else
+ qp->resp.wqe = queue_head(qp->rq.queue,
+ QUEUE_TYPE_KERNEL);
if (qp->resp.wqe) {
qp->resp.status = IB_WC_WR_FLUSH_ERR;
return RESPST_COMPLETE;
@@ -366,7 +389,12 @@ static enum resp_states check_resource(struct rxe_qp *qp,
if (srq)
return get_srq_wqe(qp);
- qp->resp.wqe = queue_head(qp->rq.queue);
+ if (qp->is_user)
+ qp->resp.wqe = queue_head(qp->rq.queue,
+ QUEUE_TYPE_FROM_USER);
+ else
+ qp->resp.wqe = queue_head(qp->rq.queue,
+ QUEUE_TYPE_KERNEL);
return (qp->resp.wqe) ? RESPST_CHK_LENGTH : RESPST_ERR_RNR;
}
@@ -392,6 +420,7 @@ static enum resp_states check_rkey(struct rxe_qp *qp,
struct rxe_pkt_info *pkt)
{
struct rxe_mr *mr = NULL;
+ struct rxe_mw *mw = NULL;
u64 va;
u32 rkey;
u32 resid;
@@ -403,6 +432,7 @@ static enum resp_states check_rkey(struct rxe_qp *qp,
if (pkt->mask & (RXE_READ_MASK | RXE_WRITE_MASK)) {
if (pkt->mask & RXE_RETH_MASK) {
qp->resp.va = reth_va(pkt);
+ qp->resp.offset = 0;
qp->resp.rkey = reth_rkey(pkt);
qp->resp.resid = reth_len(pkt);
qp->resp.length = reth_len(pkt);
@@ -411,6 +441,7 @@ static enum resp_states check_rkey(struct rxe_qp *qp,
: IB_ACCESS_REMOTE_WRITE;
} else if (pkt->mask & RXE_ATOMIC_MASK) {
qp->resp.va = atmeth_va(pkt);
+ qp->resp.offset = 0;
qp->resp.rkey = atmeth_rkey(pkt);
qp->resp.resid = sizeof(u64);
access = IB_ACCESS_REMOTE_ATOMIC;
@@ -430,18 +461,36 @@ static enum resp_states check_rkey(struct rxe_qp *qp,
resid = qp->resp.resid;
pktlen = payload_size(pkt);
- mr = lookup_mr(qp->pd, access, rkey, lookup_remote);
- if (!mr) {
- state = RESPST_ERR_RKEY_VIOLATION;
- goto err;
- }
+ if (rkey_is_mw(rkey)) {
+ mw = rxe_lookup_mw(qp, access, rkey);
+ if (!mw) {
+ pr_err("%s: no MW matches rkey %#x\n", __func__, rkey);
+ state = RESPST_ERR_RKEY_VIOLATION;
+ goto err;
+ }
- if (unlikely(mr->state == RXE_MR_STATE_FREE)) {
- state = RESPST_ERR_RKEY_VIOLATION;
- goto err;
+ mr = mw->mr;
+ if (!mr) {
+ pr_err("%s: MW doesn't have an MR\n", __func__);
+ state = RESPST_ERR_RKEY_VIOLATION;
+ goto err;
+ }
+
+ if (mw->access & IB_ZERO_BASED)
+ qp->resp.offset = mw->addr;
+
+ rxe_drop_ref(mw);
+ rxe_add_ref(mr);
+ } else {
+ mr = lookup_mr(qp->pd, access, rkey, RXE_LOOKUP_REMOTE);
+ if (!mr) {
+ pr_err("%s: no MR matches rkey %#x\n", __func__, rkey);
+ state = RESPST_ERR_RKEY_VIOLATION;
+ goto err;
+ }
}
- if (mr_check_range(mr, va, resid)) {
+ if (mr_check_range(mr, va + qp->resp.offset, resid)) {
state = RESPST_ERR_RKEY_VIOLATION;
goto err;
}
@@ -475,6 +524,9 @@ static enum resp_states check_rkey(struct rxe_qp *qp,
err:
if (mr)
rxe_drop_ref(mr);
+ if (mw)
+ rxe_drop_ref(mw);
+
return state;
}
@@ -484,7 +536,7 @@ static enum resp_states send_data_in(struct rxe_qp *qp, void *data_addr,
int err;
err = copy_data(qp->pd, IB_ACCESS_LOCAL_WRITE, &qp->resp.wqe->dma,
- data_addr, data_len, to_mr_obj, NULL);
+ data_addr, data_len, RXE_TO_MR_OBJ, NULL);
if (unlikely(err))
return (err == -ENOSPC) ? RESPST_ERR_LENGTH
: RESPST_ERR_MALFORMED_WQE;
@@ -499,8 +551,8 @@ static enum resp_states write_data_in(struct rxe_qp *qp,
int err;
int data_len = payload_size(pkt);
- err = rxe_mr_copy(qp->resp.mr, qp->resp.va, payload_addr(pkt), data_len,
- to_mr_obj, NULL);
+ err = rxe_mr_copy(qp->resp.mr, qp->resp.va + qp->resp.offset,
+ payload_addr(pkt), data_len, RXE_TO_MR_OBJ, NULL);
if (err) {
rc = RESPST_ERR_RKEY_VIOLATION;
goto out;
@@ -519,7 +571,6 @@ static DEFINE_SPINLOCK(atomic_ops_lock);
static enum resp_states process_atomic(struct rxe_qp *qp,
struct rxe_pkt_info *pkt)
{
- u64 iova = atmeth_va(pkt);
u64 *vaddr;
enum resp_states ret;
struct rxe_mr *mr = qp->resp.mr;
@@ -529,7 +580,7 @@ static enum resp_states process_atomic(struct rxe_qp *qp,
goto out;
}
- vaddr = iova_to_vaddr(mr, iova, sizeof(u64));
+ vaddr = iova_to_vaddr(mr, qp->resp.va + qp->resp.offset, sizeof(u64));
/* check vaddr is 8 bytes aligned. */
if (!vaddr || (uintptr_t)vaddr & 7) {
@@ -587,18 +638,11 @@ static struct sk_buff *prepare_ack_packet(struct rxe_qp *qp,
ack->opcode = opcode;
ack->mask = rxe_opcode[opcode].mask;
ack->paylen = paylen;
-
- /* fill in bth using the request packet headers */
- memcpy(ack->hdr, pkt->hdr, RXE_BTH_BYTES);
-
- bth_set_opcode(ack, opcode);
- bth_set_qpn(ack, qp->attr.dest_qp_num);
- bth_set_pad(ack, pad);
- bth_set_se(ack, 0);
- bth_set_psn(ack, psn);
- bth_set_ack(ack, 0);
ack->psn = psn;
+ bth_init(ack, opcode, 0, 0, pad, IB_DEFAULT_PKEY_FULL,
+ qp->attr.dest_qp_num, 0, psn);
+
if (ack->mask & RXE_AETH_MASK) {
aeth_set_syn(ack, syndrome);
aeth_set_msn(ack, qp->resp.msn);
@@ -653,8 +697,10 @@ static enum resp_states read_reply(struct rxe_qp *qp,
res->type = RXE_READ_MASK;
res->replay = 0;
- res->read.va = qp->resp.va;
- res->read.va_org = qp->resp.va;
+ res->read.va = qp->resp.va +
+ qp->resp.offset;
+ res->read.va_org = qp->resp.va +
+ qp->resp.offset;
res->first_psn = req_pkt->psn;
@@ -701,7 +747,7 @@ static enum resp_states read_reply(struct rxe_qp *qp,
return RESPST_ERR_RNR;
err = rxe_mr_copy(res->read.mr, res->read.va, payload_addr(&ack_pkt),
- payload, from_mr_obj, &icrc);
+ payload, RXE_FROM_MR_OBJ, &icrc);
if (err)
pr_err("Failed copying memory\n");
@@ -739,16 +785,12 @@ static enum resp_states read_reply(struct rxe_qp *qp,
return state;
}
-static void build_rdma_network_hdr(union rdma_network_hdr *hdr,
- struct rxe_pkt_info *pkt)
+static int invalidate_rkey(struct rxe_qp *qp, u32 rkey)
{
- struct sk_buff *skb = PKT_TO_SKB(pkt);
-
- memset(hdr, 0, sizeof(*hdr));
- if (skb->protocol == htons(ETH_P_IP))
- memcpy(&hdr->roce4grh, ip_hdr(skb), sizeof(hdr->roce4grh));
- else if (skb->protocol == htons(ETH_P_IPV6))
- memcpy(&hdr->ibgrh, ipv6_hdr(skb), sizeof(hdr->ibgrh));
+ if (rkey_is_mw(rkey))
+ return rxe_invalidate_mw(qp, rkey);
+ else
+ return rxe_invalidate_mr(qp, rkey);
}
/* Executes a new request. A retried request never reach that function (send
@@ -757,16 +799,23 @@ static void build_rdma_network_hdr(union rdma_network_hdr *hdr,
static enum resp_states execute(struct rxe_qp *qp, struct rxe_pkt_info *pkt)
{
enum resp_states err;
+ struct sk_buff *skb = PKT_TO_SKB(pkt);
+ union rdma_network_hdr hdr;
if (pkt->mask & RXE_SEND_MASK) {
if (qp_type(qp) == IB_QPT_UD ||
qp_type(qp) == IB_QPT_SMI ||
qp_type(qp) == IB_QPT_GSI) {
- union rdma_network_hdr hdr;
-
- build_rdma_network_hdr(&hdr, pkt);
-
- err = send_data_in(qp, &hdr, sizeof(hdr));
+ if (skb->protocol == htons(ETH_P_IP)) {
+ memset(&hdr.reserved, 0,
+ sizeof(hdr.reserved));
+ memcpy(&hdr.roce4grh, ip_hdr(skb),
+ sizeof(hdr.roce4grh));
+ err = send_data_in(qp, &hdr, sizeof(hdr));
+ } else {
+ err = send_data_in(qp, ipv6_hdr(skb),
+ sizeof(hdr));
+ }
if (err)
return err;
}
@@ -790,6 +839,14 @@ static enum resp_states execute(struct rxe_qp *qp, struct rxe_pkt_info *pkt)
WARN_ON_ONCE(1);
}
+ if (pkt->mask & RXE_IETH_MASK) {
+ u32 rkey = ieth_rkey(pkt);
+
+ err = invalidate_rkey(qp, rkey);
+ if (err)
+ return RESPST_ERR_INVALIDATE_RKEY;
+ }
+
/* next expected psn, read handles this separately */
qp->resp.psn = (pkt->psn + 1) & BTH_PSN_MASK;
qp->resp.ack_psn = qp->resp.psn;
@@ -822,13 +879,13 @@ static enum resp_states do_complete(struct rxe_qp *qp,
memset(&cqe, 0, sizeof(cqe));
if (qp->rcq->is_user) {
- uwc->status = qp->resp.status;
- uwc->qp_num = qp->ibqp.qp_num;
- uwc->wr_id = wqe->wr_id;
+ uwc->status = qp->resp.status;
+ uwc->qp_num = qp->ibqp.qp_num;
+ uwc->wr_id = wqe->wr_id;
} else {
- wc->status = qp->resp.status;
- wc->qp = &qp->ibqp;
- wc->wr_id = wqe->wr_id;
+ wc->status = qp->resp.status;
+ wc->qp = &qp->ibqp;
+ wc->wr_id = wqe->wr_id;
}
if (wc->status == IB_WC_SUCCESS) {
@@ -883,34 +940,25 @@ static enum resp_states do_complete(struct rxe_qp *qp,
}
if (pkt->mask & RXE_IETH_MASK) {
- struct rxe_mr *rmr;
-
wc->wc_flags |= IB_WC_WITH_INVALIDATE;
wc->ex.invalidate_rkey = ieth_rkey(pkt);
-
- rmr = rxe_pool_get_index(&rxe->mr_pool,
- wc->ex.invalidate_rkey >> 8);
- if (unlikely(!rmr)) {
- pr_err("Bad rkey %#x invalidation\n",
- wc->ex.invalidate_rkey);
- return RESPST_ERROR;
- }
- rmr->state = RXE_MR_STATE_FREE;
- rxe_drop_ref(rmr);
}
- wc->qp = &qp->ibqp;
-
if (pkt->mask & RXE_DETH_MASK)
wc->src_qp = deth_sqp(pkt);
+ wc->qp = &qp->ibqp;
wc->port_num = qp->attr.port_num;
}
}
/* have copy for srq and reference for !srq */
- if (!qp->srq)
- advance_consumer(qp->rq.queue);
+ if (!qp->srq) {
+ if (qp->is_user)
+ advance_consumer(qp->rq.queue, QUEUE_TYPE_FROM_USER);
+ else
+ advance_consumer(qp->rq.queue, QUEUE_TYPE_KERNEL);
+ }
qp->resp.wqe = NULL;
@@ -966,16 +1014,10 @@ static int send_atomic_ack(struct rxe_qp *qp, struct rxe_pkt_info *pkt,
goto out;
}
- rxe_add_ref(qp);
-
res = &qp->resp.resources[qp->resp.res_head];
free_rd_atomic_resource(qp, res);
rxe_advance_resp_resource(qp);
- memcpy(SKB_TO_PKT(skb), &ack_pkt, sizeof(ack_pkt));
- memset((unsigned char *)SKB_TO_PKT(skb) + sizeof(ack_pkt), 0,
- sizeof(skb->cb) - sizeof(ack_pkt));
-
skb_get(skb);
res->type = RXE_ATOMIC_MASK;
res->atomic.skb = skb;
@@ -1176,6 +1218,7 @@ static enum resp_states do_class_d1e_error(struct rxe_qp *qp)
static void rxe_drain_req_pkts(struct rxe_qp *qp, bool notify)
{
struct sk_buff *skb;
+ struct rxe_queue *q = qp->rq.queue;
while ((skb = skb_dequeue(&qp->req_pkts))) {
rxe_drop_ref(qp);
@@ -1186,8 +1229,8 @@ static void rxe_drain_req_pkts(struct rxe_qp *qp, bool notify)
if (notify)
return;
- while (!qp->srq && qp->rq.queue && queue_head(qp->rq.queue))
- advance_consumer(qp->rq.queue);
+ while (!qp->srq && q && queue_head(q, q->type))
+ advance_consumer(q, q->type);
}
int rxe_responder(void *arg)
@@ -1314,6 +1357,13 @@ int rxe_responder(void *arg)
}
break;
+ case RESPST_ERR_INVALIDATE_RKEY:
+ /* RC - Class J. */
+ qp->resp.goto_error = 1;
+ qp->resp.status = IB_WC_REM_INV_REQ_ERR;
+ state = RESPST_COMPLETE;
+ break;
+
case RESPST_ERR_LENGTH:
if (qp_type(qp) == IB_QPT_RC) {
/* Class C */
diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c
index 41b0d1e11baf..610c98d24b5c 100644
--- a/drivers/infiniband/sw/rxe/rxe_srq.c
+++ b/drivers/infiniband/sw/rxe/rxe_srq.c
@@ -78,6 +78,7 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq,
int err;
int srq_wqe_size;
struct rxe_queue *q;
+ enum queue_type type;
srq->ibsrq.event_handler = init->event_handler;
srq->ibsrq.srq_context = init->srq_context;
@@ -85,14 +86,16 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq,
srq->srq_num = srq->pelem.index;
srq->rq.max_wr = init->attr.max_wr;
srq->rq.max_sge = init->attr.max_sge;
+ srq->rq.is_user = srq->is_user;
srq_wqe_size = rcv_wqe_size(srq->rq.max_sge);
spin_lock_init(&srq->rq.producer_lock);
spin_lock_init(&srq->rq.consumer_lock);
+ type = uresp ? QUEUE_TYPE_FROM_USER : QUEUE_TYPE_KERNEL;
q = rxe_queue_init(rxe, &srq->rq.max_wr,
- srq_wqe_size);
+ srq_wqe_size, type);
if (!q) {
pr_warn("unable to allocate queue for srq\n");
return -ENOMEM;
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c
index aeb5e232c195..c223959ac174 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
@@ -216,8 +216,14 @@ static int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr)
u32 length;
struct rxe_recv_wqe *recv_wqe;
int num_sge = ibwr->num_sge;
+ int full;
- if (unlikely(queue_full(rq->queue))) {
+ if (rq->is_user)
+ full = queue_full(rq->queue, QUEUE_TYPE_FROM_USER);
+ else
+ full = queue_full(rq->queue, QUEUE_TYPE_KERNEL);
+
+ if (unlikely(full)) {
err = -ENOMEM;
goto err1;
}
@@ -231,7 +237,11 @@ static int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr)
for (i = 0; i < num_sge; i++)
length += ibwr->sg_list[i].length;
- recv_wqe = producer_addr(rq->queue);
+ if (rq->is_user)
+ recv_wqe = producer_addr(rq->queue, QUEUE_TYPE_FROM_USER);
+ else
+ recv_wqe = producer_addr(rq->queue, QUEUE_TYPE_KERNEL);
+
recv_wqe->wr_id = ibwr->wr_id;
recv_wqe->num_sge = num_sge;
@@ -244,7 +254,11 @@ static int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr)
recv_wqe->dma.cur_sge = 0;
recv_wqe->dma.sge_offset = 0;
- advance_producer(rq->queue);
+ if (rq->is_user)
+ advance_producer(rq->queue, QUEUE_TYPE_FROM_USER);
+ else
+ advance_producer(rq->queue, QUEUE_TYPE_KERNEL);
+
return 0;
err1:
@@ -267,6 +281,9 @@ static int rxe_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init,
if (udata->outlen < sizeof(*uresp))
return -EINVAL;
uresp = udata->outbuf;
+ srq->is_user = true;
+ } else {
+ srq->is_user = false;
}
err = rxe_srq_chk_attr(rxe, NULL, &init->attr, IB_SRQ_INIT_MASK);
@@ -408,7 +425,9 @@ static struct ib_qp *rxe_create_qp(struct ib_pd *ibpd,
err = -EINVAL;
goto err2;
}
- qp->is_user = 1;
+ qp->is_user = true;
+ } else {
+ qp->is_user = false;
}
rxe_add_index(qp);
@@ -577,7 +596,7 @@ static void init_send_wqe(struct rxe_qp *qp, const struct ib_send_wr *ibwr,
init_send_wr(qp, &wqe->wr, ibwr);
/* local operation */
- if (unlikely(mask & WR_REG_MASK)) {
+ if (unlikely(mask & WR_LOCAL_OP_MASK)) {
wqe->mask = mask;
wqe->state = wqe_state_posted;
return;
@@ -613,6 +632,7 @@ static int post_one_send(struct rxe_qp *qp, const struct ib_send_wr *ibwr,
struct rxe_sq *sq = &qp->sq;
struct rxe_send_wqe *send_wqe;
unsigned long flags;
+ int full;
err = validate_send_wr(qp, ibwr, mask, length);
if (err)
@@ -620,22 +640,31 @@ static int post_one_send(struct rxe_qp *qp, const struct ib_send_wr *ibwr,
spin_lock_irqsave(&qp->sq.sq_lock, flags);
- if (unlikely(queue_full(sq->queue))) {
- err = -ENOMEM;
- goto err1;
+ if (qp->is_user)
+ full = queue_full(sq->queue, QUEUE_TYPE_FROM_USER);
+ else
+ full = queue_full(sq->queue, QUEUE_TYPE_KERNEL);
+
+ if (unlikely(full)) {
+ spin_unlock_irqrestore(&qp->sq.sq_lock, flags);
+ return -ENOMEM;
}
- send_wqe = producer_addr(sq->queue);
+ if (qp->is_user)
+ send_wqe = producer_addr(sq->queue, QUEUE_TYPE_FROM_USER);
+ else
+ send_wqe = producer_addr(sq->queue, QUEUE_TYPE_KERNEL);
+
init_send_wqe(qp, ibwr, mask, length, send_wqe);
- advance_producer(sq->queue);
+ if (qp->is_user)
+ advance_producer(sq->queue, QUEUE_TYPE_FROM_USER);
+ else
+ advance_producer(sq->queue, QUEUE_TYPE_KERNEL);
+
spin_unlock_irqrestore(&qp->sq.sq_lock, flags);
return 0;
-
-err1:
- spin_unlock_irqrestore(&qp->sq.sq_lock, flags);
- return err;
}
static int rxe_post_send_kernel(struct rxe_qp *qp, const struct ib_send_wr *wr,
@@ -823,12 +852,18 @@ static int rxe_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
spin_lock_irqsave(&cq->cq_lock, flags);
for (i = 0; i < num_entries; i++) {
- cqe = queue_head(cq->queue);
+ if (cq->is_user)
+ cqe = queue_head(cq->queue, QUEUE_TYPE_TO_USER);
+ else
+ cqe = queue_head(cq->queue, QUEUE_TYPE_KERNEL);
if (!cqe)
break;
memcpy(wc++, &cqe->ibwc, sizeof(*wc));
- advance_consumer(cq->queue);
+ if (cq->is_user)
+ advance_consumer(cq->queue, QUEUE_TYPE_TO_USER);
+ else
+ advance_consumer(cq->queue, QUEUE_TYPE_KERNEL);
}
spin_unlock_irqrestore(&cq->cq_lock, flags);
@@ -838,7 +873,12 @@ static int rxe_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
static int rxe_peek_cq(struct ib_cq *ibcq, int wc_cnt)
{
struct rxe_cq *cq = to_rcq(ibcq);
- int count = queue_count(cq->queue);
+ int count;
+
+ if (cq->is_user)
+ count = queue_count(cq->queue, QUEUE_TYPE_TO_USER);
+ else
+ count = queue_count(cq->queue, QUEUE_TYPE_KERNEL);
return (count > wc_cnt) ? wc_cnt : count;
}
@@ -848,12 +888,18 @@ static int rxe_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
struct rxe_cq *cq = to_rcq(ibcq);
unsigned long irq_flags;
int ret = 0;
+ int empty;
spin_lock_irqsave(&cq->cq_lock, irq_flags);
if (cq->notify != IB_CQ_NEXT_COMP)
cq->notify = flags & IB_CQ_SOLICITED_MASK;
- if ((flags & IB_CQ_REPORT_MISSED_EVENTS) && !queue_empty(cq->queue))
+ if (cq->is_user)
+ empty = queue_empty(cq->queue, QUEUE_TYPE_TO_USER);
+ else
+ empty = queue_empty(cq->queue, QUEUE_TYPE_KERNEL);
+
+ if ((flags & IB_CQ_REPORT_MISSED_EVENTS) && !empty)
ret = 1;
spin_unlock_irqrestore(&cq->cq_lock, irq_flags);
@@ -899,7 +945,7 @@ static struct ib_mr *rxe_reg_user_mr(struct ib_pd *ibpd,
rxe_add_ref(pd);
- err = rxe_mr_init_user(pd, start, length, iova, access, udata, mr);
+ err = rxe_mr_init_user(pd, start, length, iova, access, mr);
if (err)
goto err3;
@@ -913,17 +959,6 @@ err2:
return ERR_PTR(err);
}
-static int rxe_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
-{
- struct rxe_mr *mr = to_rmr(ibmr);
-
- mr->state = RXE_MR_STATE_ZOMBIE;
- rxe_drop_ref(mr_pd(mr));
- rxe_drop_index(mr);
- rxe_drop_ref(mr);
- return 0;
-}
-
static struct ib_mr *rxe_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type,
u32 max_num_sg)
{
@@ -1058,8 +1093,9 @@ static const struct ib_device_ops rxe_dev_ops = {
.driver_id = RDMA_DRIVER_RXE,
.uverbs_abi_ver = RXE_UVERBS_ABI_VERSION,
- .alloc_hw_stats = rxe_ib_alloc_hw_stats,
+ .alloc_hw_port_stats = rxe_ib_alloc_hw_port_stats,
.alloc_mr = rxe_alloc_mr,
+ .alloc_mw = rxe_alloc_mw,
.alloc_pd = rxe_alloc_pd,
.alloc_ucontext = rxe_alloc_ucontext,
.attach_mcast = rxe_attach_mcast,
@@ -1069,6 +1105,7 @@ static const struct ib_device_ops rxe_dev_ops = {
.create_srq = rxe_create_srq,
.create_user_ah = rxe_create_ah,
.dealloc_driver = rxe_dealloc,
+ .dealloc_mw = rxe_dealloc_mw,
.dealloc_pd = rxe_dealloc_pd,
.dealloc_ucontext = rxe_dealloc_ucontext,
.dereg_mr = rxe_dereg_mr,
@@ -1077,6 +1114,7 @@ static const struct ib_device_ops rxe_dev_ops = {
.destroy_qp = rxe_destroy_qp,
.destroy_srq = rxe_destroy_srq,
.detach_mcast = rxe_detach_mcast,
+ .device_group = &rxe_attr_group,
.enable_driver = rxe_enable_driver,
.get_dma_mr = rxe_get_dma_mr,
.get_hw_stats = rxe_ib_get_hw_stats,
@@ -1143,7 +1181,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);
err = ib_register_device(dev, ibdev_name, NULL);
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 11eba7a3ba8f..959a3260fcab 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.h
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.h
@@ -77,6 +77,7 @@ enum wqe_state {
};
struct rxe_sq {
+ bool is_user;
int max_wr;
int max_sge;
int max_inline;
@@ -85,6 +86,7 @@ struct rxe_sq {
};
struct rxe_rq {
+ bool is_user;
int max_wr;
int max_sge;
spinlock_t producer_lock; /* guard queue producer */
@@ -98,6 +100,7 @@ struct rxe_srq {
struct rxe_pd *pd;
struct rxe_rq rq;
u32 srq_num;
+ bool is_user;
int limit;
int error;
@@ -183,6 +186,7 @@ struct rxe_resp_info {
/* RDMA read / atomic only */
u64 va;
+ u64 offset;
struct rxe_mr *mr;
u32 resid;
u32 rkey;
@@ -211,7 +215,7 @@ struct rxe_qp {
struct ib_qp_attr attr;
unsigned int valid;
unsigned int mtu;
- int is_user;
+ bool is_user;
struct rxe_pd *pd;
struct rxe_srq *srq;
@@ -273,7 +277,16 @@ enum rxe_mr_type {
RXE_MR_TYPE_NONE,
RXE_MR_TYPE_DMA,
RXE_MR_TYPE_MR,
- RXE_MR_TYPE_MW,
+};
+
+enum rxe_mr_copy_dir {
+ RXE_TO_MR_OBJ,
+ RXE_FROM_MR_OBJ,
+};
+
+enum rxe_mr_lookup_type {
+ RXE_LOOKUP_LOCAL,
+ RXE_LOOKUP_REMOTE,
};
#define RXE_BUF_PER_MAP (PAGE_SIZE / sizeof(struct rxe_phys_buf))
@@ -287,6 +300,13 @@ struct rxe_map {
struct rxe_phys_buf buf[RXE_BUF_PER_MAP];
};
+static inline int rkey_is_mw(u32 rkey)
+{
+ u32 index = rkey >> 8;
+
+ return (index >= RXE_MIN_MW_INDEX) && (index <= RXE_MAX_MW_INDEX);
+}
+
struct rxe_mr {
struct rxe_pool_entry pelem;
struct ib_mr ibmr;
@@ -312,18 +332,27 @@ struct rxe_mr {
u32 max_buf;
u32 num_map;
+ atomic_t num_mw;
+
struct rxe_map **map;
};
enum rxe_mw_state {
- RXE_MW_STATE_INVALID = RXE_MR_STATE_INVALID,
- RXE_MW_STATE_FREE = RXE_MR_STATE_FREE,
- RXE_MW_STATE_VALID = RXE_MR_STATE_VALID,
+ RXE_MW_STATE_INVALID = RXE_MR_STATE_INVALID,
+ RXE_MW_STATE_FREE = RXE_MR_STATE_FREE,
+ RXE_MW_STATE_VALID = RXE_MR_STATE_VALID,
};
struct rxe_mw {
- struct ib_mw ibmw;
- struct rxe_pool_entry pelem;
+ struct ib_mw ibmw;
+ struct rxe_pool_entry pelem;
+ spinlock_t lock;
+ enum rxe_mw_state state;
+ struct rxe_qp *qp; /* Type 2 only */
+ struct rxe_mr *mr;
+ int access;
+ u64 addr;
+ u64 length;
};
struct rxe_mc_grp {
@@ -455,6 +484,16 @@ static inline u32 mr_rkey(struct rxe_mr *mr)
return mr->ibmr.rkey;
}
+static inline struct rxe_pd *rxe_mw_pd(struct rxe_mw *mw)
+{
+ return to_rpd(mw->ibmw.pd);
+}
+
+static inline u32 rxe_mw_rkey(struct rxe_mw *mw)
+{
+ return mw->ibmw.rkey;
+}
+
int rxe_register_device(struct rxe_dev *rxe, const char *ibdev_name);
void rxe_mc_cleanup(struct rxe_pool_entry *arg);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 75cd44789661..44d8d151ff90 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -454,7 +454,7 @@ struct ipoib_neigh {
struct list_head list;
struct ipoib_neigh __rcu *hnext;
struct rcu_head rcu;
- atomic_t refcnt;
+ refcount_t refcnt;
unsigned long alive;
};
@@ -464,7 +464,7 @@ struct ipoib_neigh {
void ipoib_neigh_dtor(struct ipoib_neigh *neigh);
static inline void ipoib_neigh_put(struct ipoib_neigh *neigh)
{
- if (atomic_dec_and_test(&neigh->refcnt))
+ if (refcount_dec_and_test(&neigh->refcnt))
ipoib_neigh_dtor(neigh);
}
struct ipoib_neigh *ipoib_neigh_get(struct net_device *dev, u8 *daddr);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 9dbc85a6b702..684c2ddb16f5 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -1503,7 +1503,7 @@ static void ipoib_cm_stale_task(struct work_struct *work)
spin_unlock_irq(&priv->lock);
}
-static ssize_t show_mode(struct device *d, struct device_attribute *attr,
+static ssize_t mode_show(struct device *d, struct device_attribute *attr,
char *buf)
{
struct net_device *dev = to_net_dev(d);
@@ -1515,8 +1515,8 @@ static ssize_t show_mode(struct device *d, struct device_attribute *attr,
return sysfs_emit(buf, "datagram\n");
}
-static ssize_t set_mode(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t mode_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct net_device *dev = to_net_dev(d);
int ret;
@@ -1542,7 +1542,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr,
return (!ret || ret == -EBUSY) ? count : ret;
}
-static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, show_mode, set_mode);
+static DEVICE_ATTR_RW(mode);
int ipoib_cm_add_mode_attr(struct net_device *dev)
{
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index bbb18087fdab..abf60f4d9203 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -316,7 +316,7 @@ static bool ipoib_is_dev_match_addr_rcu(const struct sockaddr *addr,
return false;
}
-/**
+/*
* Find the master net_device on top of the given net_device.
* @dev: base IPoIB net_device
*
@@ -361,8 +361,9 @@ static int ipoib_upper_walk(struct net_device *upper,
}
/**
- * Find a net_device matching the given address, which is an upper device of
- * the given net_device.
+ * ipoib_get_net_dev_match_addr - Find a net_device matching
+ * the given address, which is an upper device of the given net_device.
+ *
* @addr: IP address to look for.
* @dev: base IPoIB net_device
*
@@ -1287,7 +1288,7 @@ struct ipoib_neigh *ipoib_neigh_get(struct net_device *dev, u8 *daddr)
neigh = rcu_dereference_bh(neigh->hnext)) {
if (memcmp(daddr, neigh->daddr, INFINIBAND_ALEN) == 0) {
/* found, take one ref on behalf of the caller */
- if (!atomic_inc_not_zero(&neigh->refcnt)) {
+ if (!refcount_inc_not_zero(&neigh->refcnt)) {
/* deleted */
neigh = NULL;
goto out_unlock;
@@ -1382,7 +1383,7 @@ static struct ipoib_neigh *ipoib_neigh_ctor(u8 *daddr,
INIT_LIST_HEAD(&neigh->list);
ipoib_cm_set(neigh, NULL);
/* one ref on behalf of the caller */
- atomic_set(&neigh->refcnt, 1);
+ refcount_set(&neigh->refcnt, 1);
return neigh;
}
@@ -1414,7 +1415,7 @@ struct ipoib_neigh *ipoib_neigh_alloc(u8 *daddr,
lockdep_is_held(&priv->lock))) {
if (memcmp(daddr, neigh->daddr, INFINIBAND_ALEN) == 0) {
/* found, take one ref on behalf of the caller */
- if (!atomic_inc_not_zero(&neigh->refcnt)) {
+ if (!refcount_inc_not_zero(&neigh->refcnt)) {
/* deleted */
neigh = NULL;
break;
@@ -1429,7 +1430,7 @@ struct ipoib_neigh *ipoib_neigh_alloc(u8 *daddr,
goto out_unlock;
/* one ref on behalf of the hash table */
- atomic_inc(&neigh->refcnt);
+ refcount_inc(&neigh->refcnt);
neigh->alive = jiffies;
/* put in hash */
rcu_assign_pointer(neigh->hnext,
@@ -2268,18 +2269,18 @@ void ipoib_intf_free(struct net_device *dev)
kfree(priv);
}
-static ssize_t show_pkey(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t pkey_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct net_device *ndev = to_net_dev(dev);
struct ipoib_dev_priv *priv = ipoib_priv(ndev);
return sysfs_emit(buf, "0x%04x\n", priv->pkey);
}
-static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
+static DEVICE_ATTR_RO(pkey);
-static ssize_t show_umcast(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t umcast_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct net_device *ndev = to_net_dev(dev);
struct ipoib_dev_priv *priv = ipoib_priv(ndev);
@@ -2300,9 +2301,8 @@ void ipoib_set_umcast(struct net_device *ndev, int umcast_val)
clear_bit(IPOIB_FLAG_UMCAST, &priv->flags);
}
-static ssize_t set_umcast(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t umcast_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
unsigned long umcast_val = simple_strtoul(buf, NULL, 0);
@@ -2310,7 +2310,7 @@ static ssize_t set_umcast(struct device *dev,
return count;
}
-static DEVICE_ATTR(umcast, S_IWUSR | S_IRUGO, show_umcast, set_umcast);
+static DEVICE_ATTR_RW(umcast);
int ipoib_add_umcast_attr(struct net_device *dev)
{
@@ -2381,9 +2381,9 @@ static int ipoib_set_mac(struct net_device *dev, void *addr)
return 0;
}
-static ssize_t create_child(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t create_child_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int pkey;
int ret;
@@ -2398,11 +2398,11 @@ static ssize_t create_child(struct device *dev,
return ret ? ret : count;
}
-static DEVICE_ATTR(create_child, S_IWUSR, NULL, create_child);
+static DEVICE_ATTR_WO(create_child);
-static ssize_t delete_child(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t delete_child_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int pkey;
int ret;
@@ -2418,7 +2418,7 @@ static ssize_t delete_child(struct device *dev,
return ret ? ret : count;
}
-static DEVICE_ATTR(delete_child, S_IWUSR, NULL, delete_child);
+static DEVICE_ATTR_WO(delete_child);
int ipoib_add_pkey_attr(struct net_device *dev)
{
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 5958840dbeed..0322dc75396f 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -40,7 +40,7 @@
#include "ipoib.h"
-static ssize_t show_parent(struct device *d, struct device_attribute *attr,
+static ssize_t parent_show(struct device *d, struct device_attribute *attr,
char *buf)
{
struct net_device *dev = to_net_dev(d);
@@ -48,7 +48,7 @@ static ssize_t show_parent(struct device *d, struct device_attribute *attr,
return sysfs_emit(buf, "%s\n", priv->parent->name);
}
-static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
+static DEVICE_ATTR_RO(parent);
static bool is_child_unique(struct ipoib_dev_priv *ppriv,
struct ipoib_dev_priv *priv)
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 8fcaa1136f2c..776e46ee95da 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -506,6 +506,7 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
iser_conn->iscsi_conn = conn;
out:
+ iscsi_put_endpoint(ep);
mutex_unlock(&iser_conn->state_mutex);
return error;
}
@@ -1002,6 +1003,7 @@ static struct iscsi_transport iscsi_iser_transport = {
/* connection management */
.create_conn = iscsi_iser_conn_create,
.bind_conn = iscsi_iser_conn_bind,
+ .unbind_conn = iscsi_conn_unbind,
.destroy_conn = iscsi_conn_teardown,
.attr_is_visible = iser_attr_is_visible,
.set_param = iscsi_iser_set_param,
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 136f6c4492e0..b44cbb8e84eb 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -761,7 +761,7 @@ void iser_conn_init(struct iser_conn *iser_conn)
ib_conn->reg_cqe.done = iser_reg_comp;
}
- /**
+/*
* starts the process of connecting to the target
* sleeps until the connection is established or rejected
*/
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index 18266f07c58d..636d590765f9 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -35,10 +35,10 @@ static const struct kernel_param_ops sg_tablesize_ops = {
.get = param_get_int,
};
-static int isert_sg_tablesize = ISCSI_ISER_DEF_SG_TABLESIZE;
+static int isert_sg_tablesize = ISCSI_ISER_MIN_SG_TABLESIZE;
module_param_cb(sg_tablesize, &sg_tablesize_ops, &isert_sg_tablesize, 0644);
MODULE_PARM_DESC(sg_tablesize,
- "Number of gather/scatter entries in a single scsi command, should >= 128 (default: 256, max: 4096)");
+ "Number of gather/scatter entries in a single scsi command, should >= 128 (default: 128, max: 4096)");
static DEFINE_MUTEX(device_list_mutex);
static LIST_HEAD(device_list);
@@ -2231,6 +2231,16 @@ isert_setup_id(struct isert_np *isert_np)
}
isert_dbg("id %p context %p\n", id, id->context);
+ /*
+ * Allow both IPv4 and IPv6 sockets to bind a single port
+ * at the same time.
+ */
+ ret = rdma_set_afonly(id, 1);
+ if (ret) {
+ isert_err("rdma_set_afonly() failed: %d\n", ret);
+ goto out_id;
+ }
+
ret = rdma_bind_addr(id, sa);
if (ret) {
isert_err("rdma_bind_addr() failed: %d\n", ret);
@@ -2387,10 +2397,10 @@ accept_wait:
spin_unlock_bh(&np->np_thread_lock);
isert_dbg("np_thread_state %d\n",
np->np_thread_state);
- /**
+ /*
* No point in stalling here when np_thread
* is in state RESET/SHUTDOWN/EXIT - bail
- **/
+ */
return -ENODEV;
}
spin_unlock_bh(&np->np_thread_lock);
diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h
index 6c5af13db4e0..ca8cfebe26ca 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.h
+++ b/drivers/infiniband/ulp/isert/ib_isert.h
@@ -65,9 +65,6 @@
*/
#define ISER_RX_SIZE (ISCSI_DEF_MAX_RECV_SEG_LEN + 1024)
-/* Default I/O size is 1MB */
-#define ISCSI_ISER_DEF_SG_TABLESIZE 256
-
/* Minimum I/O size is 512KB */
#define ISCSI_ISER_MIN_SG_TABLESIZE 128
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt-sysfs.c b/drivers/infiniband/ulp/rtrs/rtrs-clt-sysfs.c
index 7d53d18a5004..4ee592ccf979 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-clt-sysfs.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs-clt-sysfs.c
@@ -250,7 +250,6 @@ static ssize_t rtrs_clt_disconnect_store(struct kobject *kobj,
const char *buf, size_t count)
{
struct rtrs_clt_sess *sess;
- int ret;
sess = container_of(kobj, struct rtrs_clt_sess, kobj);
if (!sysfs_streq(buf, "1")) {
@@ -258,9 +257,7 @@ static ssize_t rtrs_clt_disconnect_store(struct kobject *kobj,
attr->attr.name, buf);
return -EINVAL;
}
- ret = rtrs_clt_disconnect_from_sysfs(sess);
- if (ret)
- return ret;
+ rtrs_clt_close_conns(sess, true);
return count;
}
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
index 0a794d748a7a..f2c40e50f25e 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
@@ -32,6 +32,8 @@
#define RTRS_RECONNECT_SEED 8
#define FIRST_CONN 0x01
+/* limit to 128 * 4k = 512k max IO */
+#define RTRS_MAX_SEGMENTS 128
MODULE_DESCRIPTION("RDMA Transport Client");
MODULE_LICENSE("GPL");
@@ -412,6 +414,7 @@ static void complete_rdma_req(struct rtrs_clt_io_req *req, int errno,
req->inv_errno = errno;
}
+ refcount_inc(&req->ref);
err = rtrs_inv_rkey(req);
if (unlikely(err)) {
rtrs_err(con->c.sess, "Send INV WR key=%#x: %d\n",
@@ -427,10 +430,14 @@ static void complete_rdma_req(struct rtrs_clt_io_req *req, int errno,
return;
}
+ if (!refcount_dec_and_test(&req->ref))
+ return;
}
ib_dma_unmap_sg(sess->s.dev->ib_dev, req->sglist,
req->sg_cnt, req->dir);
}
+ if (!refcount_dec_and_test(&req->ref))
+ return;
if (sess->clt->mp_policy == MP_POLICY_MIN_INFLIGHT)
atomic_dec(&sess->stats->inflight);
@@ -438,10 +445,9 @@ static void complete_rdma_req(struct rtrs_clt_io_req *req, int errno,
req->con = NULL;
if (errno) {
- rtrs_err_rl(con->c.sess,
- "IO request failed: error=%d path=%s [%s:%u]\n",
+ rtrs_err_rl(con->c.sess, "IO request failed: error=%d path=%s [%s:%u] notify=%d\n",
errno, kobject_name(&sess->kobj), sess->hca_name,
- sess->hca_port);
+ sess->hca_port, notify);
}
if (notify)
@@ -480,7 +486,7 @@ static int rtrs_post_send_rdma(struct rtrs_clt_con *con,
return rtrs_iu_post_rdma_write_imm(&con->c, req->iu, &sge, 1,
rbuf->rkey, rbuf->addr + off,
- imm, flags, wr);
+ imm, flags, wr, NULL);
}
static void process_io_rsp(struct rtrs_clt_sess *sess, u32 msg_id,
@@ -655,7 +661,6 @@ static void rtrs_clt_rdma_done(struct ib_cq *cq, struct ib_wc *wc)
rtrs_err(con->c.sess, "rtrs_post_recv_empty(): %d\n",
err);
rtrs_rdma_error_recovery(con);
- break;
}
break;
case IB_WC_RECV:
@@ -814,6 +819,9 @@ static struct rtrs_clt_sess *get_next_path_min_inflight(struct path_it *it)
int inflight;
list_for_each_entry_rcu(sess, &clt->paths_list, s.entry) {
+ if (unlikely(READ_ONCE(sess->state) != RTRS_CLT_CONNECTED))
+ continue;
+
if (unlikely(!list_empty(raw_cpu_ptr(sess->mp_skip_entry))))
continue;
@@ -913,7 +921,7 @@ static inline void path_it_deinit(struct path_it *it)
}
/**
- * rtrs_clt_init_req() Initialize an rtrs_clt_io_req holding information
+ * rtrs_clt_init_req() - Initialize an rtrs_clt_io_req holding information
* about an inflight IO.
* The user buffer holding user control message (not data) is copied into
* the corresponding buffer of rtrs_iu (req->iu->buf), which later on will
@@ -954,6 +962,7 @@ static void rtrs_clt_init_req(struct rtrs_clt_io_req *req,
req->need_inv = false;
req->need_inv_comp = false;
req->inv_errno = 0;
+ refcount_set(&req->ref, 1);
iov_iter_kvec(&iter, READ, vec, 1, usr_len);
len = _copy_from_iter(req->iu->buf, usr_len, &iter);
@@ -997,9 +1006,10 @@ rtrs_clt_get_copy_req(struct rtrs_clt_sess *alive_sess,
}
static int rtrs_post_rdma_write_sg(struct rtrs_clt_con *con,
- struct rtrs_clt_io_req *req,
- struct rtrs_rbuf *rbuf,
- u32 size, u32 imm)
+ struct rtrs_clt_io_req *req,
+ struct rtrs_rbuf *rbuf, bool fr_en,
+ u32 size, u32 imm, struct ib_send_wr *wr,
+ struct ib_send_wr *tail)
{
struct rtrs_clt_sess *sess = to_clt_sess(con->c.sess);
struct ib_sge *sge = req->sge;
@@ -1007,18 +1017,28 @@ static int rtrs_post_rdma_write_sg(struct rtrs_clt_con *con,
struct scatterlist *sg;
size_t num_sge;
int i;
-
- for_each_sg(req->sglist, sg, req->sg_cnt, i) {
- sge[i].addr = sg_dma_address(sg);
- sge[i].length = sg_dma_len(sg);
- sge[i].lkey = sess->s.dev->ib_pd->local_dma_lkey;
+ struct ib_send_wr *ptail = NULL;
+
+ if (fr_en) {
+ i = 0;
+ sge[i].addr = req->mr->iova;
+ sge[i].length = req->mr->length;
+ sge[i].lkey = req->mr->lkey;
+ i++;
+ num_sge = 2;
+ ptail = tail;
+ } else {
+ for_each_sg(req->sglist, sg, req->sg_cnt, i) {
+ sge[i].addr = sg_dma_address(sg);
+ sge[i].length = sg_dma_len(sg);
+ sge[i].lkey = sess->s.dev->ib_pd->local_dma_lkey;
+ }
+ num_sge = 1 + req->sg_cnt;
}
sge[i].addr = req->iu->dma_addr;
sge[i].length = size;
sge[i].lkey = sess->s.dev->ib_pd->local_dma_lkey;
- num_sge = 1 + req->sg_cnt;
-
/*
* From time to time we have to post signalled sends,
* or send queue will fill up and only QP reset can help.
@@ -1031,7 +1051,22 @@ static int rtrs_post_rdma_write_sg(struct rtrs_clt_con *con,
return rtrs_iu_post_rdma_write_imm(&con->c, req->iu, sge, num_sge,
rbuf->rkey, rbuf->addr, imm,
- flags, NULL);
+ flags, wr, ptail);
+}
+
+static int rtrs_map_sg_fr(struct rtrs_clt_io_req *req, size_t count)
+{
+ int nr;
+
+ /* Align the MR to a 4K page size to match the block virt boundary */
+ nr = ib_map_mr_sg(req->mr, req->sglist, count, NULL, SZ_4K);
+ if (nr < 0)
+ return nr;
+ if (unlikely(nr < req->sg_cnt))
+ return -EINVAL;
+ ib_update_fast_reg_key(req->mr, ib_inc_rkey(req->mr->rkey));
+
+ return nr;
}
static int rtrs_clt_write_req(struct rtrs_clt_io_req *req)
@@ -1044,6 +1079,10 @@ static int rtrs_clt_write_req(struct rtrs_clt_io_req *req)
struct rtrs_rbuf *rbuf;
int ret, count = 0;
u32 imm, buf_id;
+ struct ib_reg_wr rwr;
+ struct ib_send_wr inv_wr;
+ struct ib_send_wr *wr = NULL;
+ bool fr_en = false;
const size_t tsize = sizeof(*msg) + req->data_len + req->usr_len;
@@ -1072,15 +1111,43 @@ static int rtrs_clt_write_req(struct rtrs_clt_io_req *req)
req->sg_size = tsize;
rbuf = &sess->rbufs[buf_id];
+ if (count) {
+ ret = rtrs_map_sg_fr(req, count);
+ if (ret < 0) {
+ rtrs_err_rl(s,
+ "Write request failed, failed to map fast reg. data, err: %d\n",
+ ret);
+ ib_dma_unmap_sg(sess->s.dev->ib_dev, req->sglist,
+ req->sg_cnt, req->dir);
+ return ret;
+ }
+ inv_wr = (struct ib_send_wr) {
+ .opcode = IB_WR_LOCAL_INV,
+ .wr_cqe = &req->inv_cqe,
+ .send_flags = IB_SEND_SIGNALED,
+ .ex.invalidate_rkey = req->mr->rkey,
+ };
+ req->inv_cqe.done = rtrs_clt_inv_rkey_done;
+ rwr = (struct ib_reg_wr) {
+ .wr.opcode = IB_WR_REG_MR,
+ .wr.wr_cqe = &fast_reg_cqe,
+ .mr = req->mr,
+ .key = req->mr->rkey,
+ .access = (IB_ACCESS_LOCAL_WRITE),
+ };
+ wr = &rwr.wr;
+ fr_en = true;
+ refcount_inc(&req->ref);
+ }
/*
* Update stats now, after request is successfully sent it is not
* safe anymore to touch it.
*/
rtrs_clt_update_all_stats(req, WRITE);
- ret = rtrs_post_rdma_write_sg(req->con, req, rbuf,
- req->usr_len + sizeof(*msg),
- imm);
+ ret = rtrs_post_rdma_write_sg(req->con, req, rbuf, fr_en,
+ req->usr_len + sizeof(*msg),
+ imm, wr, &inv_wr);
if (unlikely(ret)) {
rtrs_err_rl(s,
"Write request failed: error=%d path=%s [%s:%u]\n",
@@ -1096,21 +1163,6 @@ static int rtrs_clt_write_req(struct rtrs_clt_io_req *req)
return ret;
}
-static int rtrs_map_sg_fr(struct rtrs_clt_io_req *req, size_t count)
-{
- int nr;
-
- /* Align the MR to a 4K page size to match the block virt boundary */
- nr = ib_map_mr_sg(req->mr, req->sglist, count, NULL, SZ_4K);
- if (nr < 0)
- return nr;
- if (unlikely(nr < req->sg_cnt))
- return -EINVAL;
- ib_update_fast_reg_key(req->mr, ib_inc_rkey(req->mr->rkey));
-
- return nr;
-}
-
static int rtrs_clt_read_req(struct rtrs_clt_io_req *req)
{
struct rtrs_clt_con *con = req->con;
@@ -1219,7 +1271,7 @@ static int rtrs_clt_read_req(struct rtrs_clt_io_req *req)
}
/**
- * rtrs_clt_failover_req() Try to find an active path for a failed request
+ * rtrs_clt_failover_req() - Try to find an active path for a failed request
* @clt: clt context
* @fail_req: a failed io request.
*/
@@ -1305,7 +1357,6 @@ static void free_sess_reqs(struct rtrs_clt_sess *sess)
static int alloc_sess_reqs(struct rtrs_clt_sess *sess)
{
struct rtrs_clt_io_req *req;
- struct rtrs_clt *clt = sess->clt;
int i, err = -ENOMEM;
sess->reqs = kcalloc(sess->queue_depth, sizeof(*sess->reqs),
@@ -1322,8 +1373,7 @@ static int alloc_sess_reqs(struct rtrs_clt_sess *sess)
if (!req->iu)
goto out;
- req->sge = kmalloc_array(clt->max_segments + 1,
- sizeof(*req->sge), GFP_KERNEL);
+ req->sge = kcalloc(2, sizeof(*req->sge), GFP_KERNEL);
if (!req->sge)
goto out;
@@ -1415,7 +1465,8 @@ static void query_fast_reg_mode(struct rtrs_clt_sess *sess)
sess->max_pages_per_mr =
min3(sess->max_pages_per_mr, (u32)max_pages_per_mr,
ib_dev->attrs.max_fast_reg_page_list_len);
- sess->max_send_sge = ib_dev->attrs.max_send_sge;
+ sess->clt->max_segments =
+ min(sess->max_pages_per_mr, sess->clt->max_segments);
}
static bool rtrs_clt_change_state_get_old(struct rtrs_clt_sess *sess,
@@ -1449,23 +1500,12 @@ static void rtrs_clt_init_hb(struct rtrs_clt_sess *sess)
rtrs_wq);
}
-static void rtrs_clt_start_hb(struct rtrs_clt_sess *sess)
-{
- rtrs_start_hb(&sess->s);
-}
-
-static void rtrs_clt_stop_hb(struct rtrs_clt_sess *sess)
-{
- rtrs_stop_hb(&sess->s);
-}
-
static void rtrs_clt_reconnect_work(struct work_struct *work);
static void rtrs_clt_close_work(struct work_struct *work);
static struct rtrs_clt_sess *alloc_sess(struct rtrs_clt *clt,
- const struct rtrs_addr *path,
- size_t con_num, u16 max_segments,
- u32 nr_poll_queues)
+ const struct rtrs_addr *path,
+ size_t con_num, u32 nr_poll_queues)
{
struct rtrs_clt_sess *sess;
int err = -ENOMEM;
@@ -1505,9 +1545,9 @@ static struct rtrs_clt_sess *alloc_sess(struct rtrs_clt *clt,
if (path->src)
memcpy(&sess->s.src_addr, path->src,
rdma_addr_size((struct sockaddr *)path->src));
- strlcpy(sess->s.sessname, clt->sessname, sizeof(sess->s.sessname));
+ strscpy(sess->s.sessname, clt->sessname, sizeof(sess->s.sessname));
sess->clt = clt;
- sess->max_pages_per_mr = max_segments;
+ sess->max_pages_per_mr = RTRS_MAX_SEGMENTS;
init_waitqueue_head(&sess->state_wq);
sess->state = RTRS_CLT_CONNECTING;
atomic_set(&sess->connected_cnt, 0);
@@ -1581,20 +1621,13 @@ static void destroy_con(struct rtrs_clt_con *con)
static int create_con_cq_qp(struct rtrs_clt_con *con)
{
struct rtrs_clt_sess *sess = to_clt_sess(con->c.sess);
- u32 max_send_wr, max_recv_wr, cq_size;
+ u32 max_send_wr, max_recv_wr, cq_num, max_send_sge, wr_limit;
int err, cq_vector;
struct rtrs_msg_rkey_rsp *rsp;
lockdep_assert_held(&con->con_mutex);
if (con->c.cid == 0) {
- /*
- * One completion for each receive and two for each send
- * (send request + registration)
- * + 2 for drain and heartbeat
- * in case qp gets into error state
- */
- max_send_wr = SERVICE_CON_QUEUE_DEPTH * 2 + 2;
- max_recv_wr = SERVICE_CON_QUEUE_DEPTH * 2 + 2;
+ max_send_sge = 1;
/* We must be the first here */
if (WARN_ON(sess->s.dev))
return -EINVAL;
@@ -1613,6 +1646,17 @@ static int create_con_cq_qp(struct rtrs_clt_con *con)
}
sess->s.dev_ref = 1;
query_fast_reg_mode(sess);
+ wr_limit = sess->s.dev->ib_dev->attrs.max_qp_wr;
+ /*
+ * Two (request + registration) completion for send
+ * Two for recv if always_invalidate is set on server
+ * or one for recv.
+ * + 2 for drain and heartbeat
+ * in case qp gets into error state.
+ */
+ max_send_wr =
+ min_t(int, wr_limit, SERVICE_CON_QUEUE_DEPTH * 2 + 2);
+ max_recv_wr = max_send_wr;
} else {
/*
* Here we assume that session members are correctly set.
@@ -1624,35 +1668,36 @@ static int create_con_cq_qp(struct rtrs_clt_con *con)
if (WARN_ON(!sess->queue_depth))
return -EINVAL;
+ wr_limit = sess->s.dev->ib_dev->attrs.max_qp_wr;
/* Shared between connections */
sess->s.dev_ref++;
- max_send_wr =
- min_t(int, sess->s.dev->ib_dev->attrs.max_qp_wr,
+ max_send_wr = min_t(int, wr_limit,
/* QD * (REQ + RSP + FR REGS or INVS) + drain */
sess->queue_depth * 3 + 1);
- max_recv_wr =
- min_t(int, sess->s.dev->ib_dev->attrs.max_qp_wr,
+ max_recv_wr = min_t(int, wr_limit,
sess->queue_depth * 3 + 1);
+ max_send_sge = 2;
}
+ cq_num = max_send_wr + max_recv_wr;
/* alloc iu to recv new rkey reply when server reports flags set */
if (sess->flags & RTRS_MSG_NEW_RKEY_F || con->c.cid == 0) {
- con->rsp_ius = rtrs_iu_alloc(max_recv_wr, sizeof(*rsp),
+ con->rsp_ius = rtrs_iu_alloc(cq_num, sizeof(*rsp),
GFP_KERNEL, sess->s.dev->ib_dev,
DMA_FROM_DEVICE,
rtrs_clt_rdma_done);
if (!con->rsp_ius)
return -ENOMEM;
- con->queue_size = max_recv_wr;
+ con->queue_num = cq_num;
}
- cq_size = max_send_wr + max_recv_wr;
+ cq_num = max_send_wr + max_recv_wr;
cq_vector = con->cpu % sess->s.dev->ib_dev->num_comp_vectors;
if (con->c.cid >= sess->s.irq_con_num)
- err = rtrs_cq_qp_create(&sess->s, &con->c, sess->max_send_sge,
- cq_vector, cq_size, max_send_wr,
+ err = rtrs_cq_qp_create(&sess->s, &con->c, max_send_sge,
+ cq_vector, cq_num, max_send_wr,
max_recv_wr, IB_POLL_DIRECT);
else
- err = rtrs_cq_qp_create(&sess->s, &con->c, sess->max_send_sge,
- cq_vector, cq_size, max_send_wr,
+ err = rtrs_cq_qp_create(&sess->s, &con->c, max_send_sge,
+ cq_vector, cq_num, max_send_wr,
max_recv_wr, IB_POLL_SOFTIRQ);
/*
* In case of error we do not bother to clean previous allocations,
@@ -1672,9 +1717,9 @@ static void destroy_con_cq_qp(struct rtrs_clt_con *con)
lockdep_assert_held(&con->con_mutex);
rtrs_cq_qp_destroy(&con->c);
if (con->rsp_ius) {
- rtrs_iu_free(con->rsp_ius, sess->s.dev->ib_dev, con->queue_size);
+ rtrs_iu_free(con->rsp_ius, sess->s.dev->ib_dev, con->queue_num);
con->rsp_ius = NULL;
- con->queue_size = 0;
+ con->queue_num = 0;
}
if (sess->s.dev_ref && !--sess->s.dev_ref) {
rtrs_ib_dev_put(sess->s.dev);
@@ -1783,12 +1828,19 @@ static int rtrs_rdma_conn_established(struct rtrs_clt_con *con,
if (con->c.cid == 0) {
queue_depth = le16_to_cpu(msg->queue_depth);
- if (queue_depth > MAX_SESS_QUEUE_DEPTH) {
- rtrs_err(clt, "Invalid RTRS message: queue=%d\n",
- queue_depth);
+ if (sess->queue_depth > 0 && queue_depth != sess->queue_depth) {
+ rtrs_err(clt, "Error: queue depth changed\n");
+
+ /*
+ * Stop any more reconnection attempts
+ */
+ sess->reconnect_attempts = -1;
+ rtrs_err(clt,
+ "Disabling auto-reconnect. Trigger a manual reconnect after issue is resolved\n");
return -ECONNRESET;
}
- if (!sess->rbufs || sess->queue_depth < queue_depth) {
+
+ if (!sess->rbufs) {
kfree(sess->rbufs);
sess->rbufs = kcalloc(queue_depth, sizeof(*sess->rbufs),
GFP_KERNEL);
@@ -1802,7 +1854,7 @@ static int rtrs_rdma_conn_established(struct rtrs_clt_con *con,
sess->chunk_size = sess->max_io_size + sess->max_hdr_size;
/*
- * Global queue depth and IO size is always a minimum.
+ * Global IO size is always a minimum.
* If while a reconnection server sends us a value a bit
* higher - client does not care and uses cached minimum.
*
@@ -1810,8 +1862,7 @@ static int rtrs_rdma_conn_established(struct rtrs_clt_con *con,
* connections in parallel, use lock.
*/
mutex_lock(&clt->paths_mutex);
- clt->queue_depth = min_not_zero(sess->queue_depth,
- clt->queue_depth);
+ clt->queue_depth = sess->queue_depth;
clt->max_io_size = min_not_zero(sess->max_io_size,
clt->max_io_size);
mutex_unlock(&clt->paths_mutex);
@@ -1869,7 +1920,7 @@ static int rtrs_rdma_conn_rejected(struct rtrs_clt_con *con,
return -ECONNRESET;
}
-static void rtrs_clt_close_conns(struct rtrs_clt_sess *sess, bool wait)
+void rtrs_clt_close_conns(struct rtrs_clt_sess *sess, bool wait)
{
if (rtrs_clt_change_state_get_old(sess, RTRS_CLT_CLOSING, NULL))
queue_work(rtrs_wq, &sess->close_work);
@@ -2098,7 +2149,7 @@ static void rtrs_clt_stop_and_destroy_conns(struct rtrs_clt_sess *sess)
*/
synchronize_rcu();
- rtrs_clt_stop_hb(sess);
+ rtrs_stop_hb(&sess->s);
/*
* The order it utterly crucial: firstly disconnect and complete all
@@ -2291,7 +2342,7 @@ static int init_conns(struct rtrs_clt_sess *sess)
if (err)
goto destroy;
- rtrs_clt_start_hb(sess);
+ rtrs_start_hb(&sess->s);
return 0;
@@ -2465,7 +2516,7 @@ static int rtrs_send_sess_info(struct rtrs_clt_sess *sess)
int err;
rx_sz = sizeof(struct rtrs_msg_info_rsp);
- rx_sz += sizeof(u64) * MAX_SESS_QUEUE_DEPTH;
+ rx_sz += sizeof(struct rtrs_sg_desc) * sess->queue_depth;
tx_iu = rtrs_iu_alloc(1, sizeof(struct rtrs_msg_info_req), GFP_KERNEL,
sess->s.dev->ib_dev, DMA_TO_DEVICE,
@@ -2617,7 +2668,6 @@ static struct rtrs_clt *alloc_clt(const char *sessname, size_t paths_num,
u16 port, size_t pdu_sz, void *priv,
void (*link_ev)(void *priv,
enum rtrs_clt_link_ev ev),
- unsigned int max_segments,
unsigned int reconnect_delay_sec,
unsigned int max_reconnect_attempts)
{
@@ -2646,13 +2696,13 @@ static struct rtrs_clt *alloc_clt(const char *sessname, size_t paths_num,
clt->paths_up = MAX_PATHS_NUM;
clt->port = port;
clt->pdu_sz = pdu_sz;
- clt->max_segments = max_segments;
+ clt->max_segments = RTRS_MAX_SEGMENTS;
clt->reconnect_delay_sec = reconnect_delay_sec;
clt->max_reconnect_attempts = max_reconnect_attempts;
clt->priv = priv;
clt->link_ev = link_ev;
clt->mp_policy = MP_POLICY_MIN_INFLIGHT;
- strlcpy(clt->sessname, sessname, sizeof(clt->sessname));
+ strscpy(clt->sessname, sessname, sizeof(clt->sessname));
init_waitqueue_head(&clt->permits_wait);
mutex_init(&clt->paths_ev_mutex);
mutex_init(&clt->paths_mutex);
@@ -2715,7 +2765,6 @@ static void free_clt(struct rtrs_clt *clt)
* @port: port to be used by the RTRS session
* @pdu_sz: Size of extra payload which can be accessed after permit allocation.
* @reconnect_delay_sec: time between reconnect tries
- * @max_segments: Max. number of segments per IO request
* @max_reconnect_attempts: Number of times to reconnect on error before giving
* up, 0 for * disabled, -1 for forever
* @nr_poll_queues: number of polling mode connection using IB_POLL_DIRECT flag
@@ -2730,7 +2779,6 @@ struct rtrs_clt *rtrs_clt_open(struct rtrs_clt_ops *ops,
const struct rtrs_addr *paths,
size_t paths_num, u16 port,
size_t pdu_sz, u8 reconnect_delay_sec,
- u16 max_segments,
s16 max_reconnect_attempts, u32 nr_poll_queues)
{
struct rtrs_clt_sess *sess, *tmp;
@@ -2739,7 +2787,7 @@ struct rtrs_clt *rtrs_clt_open(struct rtrs_clt_ops *ops,
clt = alloc_clt(sessname, paths_num, port, pdu_sz, ops->priv,
ops->link_ev,
- max_segments, reconnect_delay_sec,
+ reconnect_delay_sec,
max_reconnect_attempts);
if (IS_ERR(clt)) {
err = PTR_ERR(clt);
@@ -2749,7 +2797,7 @@ struct rtrs_clt *rtrs_clt_open(struct rtrs_clt_ops *ops,
struct rtrs_clt_sess *sess;
sess = alloc_sess(clt, &paths[i], nr_cpu_ids,
- max_segments, nr_poll_queues);
+ nr_poll_queues);
if (IS_ERR(sess)) {
err = PTR_ERR(sess);
goto close_all_sess;
@@ -2762,6 +2810,8 @@ struct rtrs_clt *rtrs_clt_open(struct rtrs_clt_ops *ops,
if (err) {
list_del_rcu(&sess->s.entry);
rtrs_clt_close_conns(sess, true);
+ free_percpu(sess->stats->pcpu_stats);
+ kfree(sess->stats);
free_sess(sess);
goto close_all_sess;
}
@@ -2770,6 +2820,8 @@ struct rtrs_clt *rtrs_clt_open(struct rtrs_clt_ops *ops,
if (err) {
list_del_rcu(&sess->s.entry);
rtrs_clt_close_conns(sess, true);
+ free_percpu(sess->stats->pcpu_stats);
+ kfree(sess->stats);
free_sess(sess);
goto close_all_sess;
}
@@ -2841,13 +2893,6 @@ int rtrs_clt_reconnect_from_sysfs(struct rtrs_clt_sess *sess)
return err;
}
-int rtrs_clt_disconnect_from_sysfs(struct rtrs_clt_sess *sess)
-{
- rtrs_clt_close_conns(sess, true);
-
- return 0;
-}
-
int rtrs_clt_remove_path_from_sysfs(struct rtrs_clt_sess *sess,
const struct attribute *sysfs_self)
{
@@ -3014,6 +3059,7 @@ int rtrs_clt_query(struct rtrs_clt *clt, struct rtrs_attrs *attr)
return -ECOMM;
attr->queue_depth = clt->queue_depth;
+ attr->max_segments = clt->max_segments;
/* Cap max_io_size to min of remote buffer size and the fr pages */
attr->max_io_size = min_t(int, clt->max_io_size,
clt->max_segments * SZ_4K);
@@ -3028,7 +3074,7 @@ int rtrs_clt_create_path_from_sysfs(struct rtrs_clt *clt,
struct rtrs_clt_sess *sess;
int err;
- sess = alloc_sess(clt, addr, nr_cpu_ids, clt->max_segments, 0);
+ sess = alloc_sess(clt, addr, nr_cpu_ids, 0);
if (IS_ERR(sess))
return PTR_ERR(sess);
@@ -3052,6 +3098,8 @@ int rtrs_clt_create_path_from_sysfs(struct rtrs_clt *clt,
close_sess:
rtrs_clt_remove_path_from_arr(sess);
rtrs_clt_close_conns(sess, true);
+ free_percpu(sess->stats->pcpu_stats);
+ kfree(sess->stats);
free_sess(sess);
return err;
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.h b/drivers/infiniband/ulp/rtrs/rtrs-clt.h
index 4c52f30e4da1..e276a2dfcf7c 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-clt.h
+++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.h
@@ -71,7 +71,7 @@ struct rtrs_clt_stats {
struct rtrs_clt_con {
struct rtrs_con c;
struct rtrs_iu *rsp_ius;
- u32 queue_size;
+ u32 queue_num;
unsigned int cpu;
struct mutex con_mutex;
atomic_t io_cnt;
@@ -116,6 +116,7 @@ struct rtrs_clt_io_req {
int inv_errno;
bool need_inv_comp;
bool need_inv;
+ refcount_t ref;
};
struct rtrs_rbuf {
@@ -141,7 +142,6 @@ struct rtrs_clt_sess {
u32 chunk_size;
size_t queue_depth;
u32 max_pages_per_mr;
- int max_send_sge;
u32 flags;
struct kobject kobj;
u8 for_new_clt;
@@ -202,7 +202,7 @@ static inline struct rtrs_permit *get_permit(struct rtrs_clt *clt, int idx)
}
int rtrs_clt_reconnect_from_sysfs(struct rtrs_clt_sess *sess);
-int rtrs_clt_disconnect_from_sysfs(struct rtrs_clt_sess *sess);
+void rtrs_clt_close_conns(struct rtrs_clt_sess *sess, bool wait);
int rtrs_clt_create_path_from_sysfs(struct rtrs_clt *clt,
struct rtrs_addr *addr);
int rtrs_clt_remove_path_from_sysfs(struct rtrs_clt_sess *sess,
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-pri.h b/drivers/infiniband/ulp/rtrs/rtrs-pri.h
index 86e65cf30cab..36f184a3b676 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-pri.h
+++ b/drivers/infiniband/ulp/rtrs/rtrs-pri.h
@@ -47,12 +47,16 @@ enum {
MAX_PATHS_NUM = 128,
/*
- * With the size of struct rtrs_permit allocated on the client, 4K
- * is the maximum number of rtrs_permits we can allocate. This number is
- * also used on the client to allocate the IU for the user connection
- * to receive the RDMA addresses from the server.
+ * Max IB immediate data size is 2^28 (MAX_IMM_PAYL_BITS)
+ * and the minimum chunk size is 4096 (2^12).
+ * So the maximum sess_queue_depth is 65536 (2^16) in theory.
+ * But mempool_create, create_qp and ib_post_send fail with
+ * "cannot allocate memory" error if sess_queue_depth is too big.
+ * Therefore the pratical max value of sess_queue_depth is
+ * somewhere between 1 and 65534 and it depends on the system.
*/
- MAX_SESS_QUEUE_DEPTH = 4096,
+ MAX_SESS_QUEUE_DEPTH = 65535,
+ MIN_CHUNK_SIZE = 8192,
RTRS_HB_INTERVAL_MS = 5000,
RTRS_HB_MISSED_MAX = 5,
@@ -91,7 +95,7 @@ struct rtrs_con {
struct ib_cq *cq;
struct rdma_cm_id *cm_id;
unsigned int cid;
- u16 cq_size;
+ int nr_cqe;
};
struct rtrs_sess {
@@ -290,10 +294,10 @@ struct rtrs_msg_rdma_hdr {
/* rtrs.c */
-struct rtrs_iu *rtrs_iu_alloc(u32 queue_size, size_t size, gfp_t t,
+struct rtrs_iu *rtrs_iu_alloc(u32 queue_num, size_t size, gfp_t t,
struct ib_device *dev, enum dma_data_direction,
void (*done)(struct ib_cq *cq, struct ib_wc *wc));
-void rtrs_iu_free(struct rtrs_iu *iu, struct ib_device *dev, u32 queue_size);
+void rtrs_iu_free(struct rtrs_iu *iu, struct ib_device *dev, u32 queue_num);
int rtrs_iu_post_recv(struct rtrs_con *con, struct rtrs_iu *iu);
int rtrs_iu_post_send(struct rtrs_con *con, struct rtrs_iu *iu, size_t size,
struct ib_send_wr *head);
@@ -301,15 +305,16 @@ int rtrs_iu_post_rdma_write_imm(struct rtrs_con *con, struct rtrs_iu *iu,
struct ib_sge *sge, unsigned int num_sge,
u32 rkey, u64 rdma_addr, u32 imm_data,
enum ib_send_flags flags,
- struct ib_send_wr *head);
+ struct ib_send_wr *head,
+ struct ib_send_wr *tail);
int rtrs_post_recv_empty(struct rtrs_con *con, struct ib_cqe *cqe);
int rtrs_post_rdma_write_imm_empty(struct rtrs_con *con, struct ib_cqe *cqe,
u32 imm_data, enum ib_send_flags flags,
struct ib_send_wr *head);
-int rtrs_cq_qp_create(struct rtrs_sess *rtrs_sess, struct rtrs_con *con,
- u32 max_send_sge, int cq_vector, int cq_size,
+int rtrs_cq_qp_create(struct rtrs_sess *sess, struct rtrs_con *con,
+ u32 max_send_sge, int cq_vector, int nr_cqe,
u32 max_send_wr, u32 max_recv_wr,
enum ib_poll_context poll_ctx);
void rtrs_cq_qp_destroy(struct rtrs_con *con);
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv-stats.c b/drivers/infiniband/ulp/rtrs/rtrs-srv-stats.c
index e102b1368d0c..12c374b5eb6e 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-srv-stats.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs-srv-stats.c
@@ -27,12 +27,10 @@ ssize_t rtrs_srv_stats_rdma_to_str(struct rtrs_srv_stats *stats,
char *page, size_t len)
{
struct rtrs_srv_stats_rdma_stats *r = &stats->rdma_stats;
- struct rtrs_srv_sess *sess = stats->sess;
- return scnprintf(page, len, "%lld %lld %lld %lld %u\n",
- (s64)atomic64_read(&r->dir[READ].cnt),
- (s64)atomic64_read(&r->dir[READ].size_total),
- (s64)atomic64_read(&r->dir[WRITE].cnt),
- (s64)atomic64_read(&r->dir[WRITE].size_total),
- atomic_read(&sess->ids_inflight));
+ return sysfs_emit(page, "%lld %lld %lld %lldn %u\n",
+ (s64)atomic64_read(&r->dir[READ].cnt),
+ (s64)atomic64_read(&r->dir[READ].size_total),
+ (s64)atomic64_read(&r->dir[WRITE].cnt),
+ (s64)atomic64_read(&r->dir[WRITE].size_total), 0);
}
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c b/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c
index a9288175fbb5..20efd44297fb 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c
@@ -208,6 +208,7 @@ rtrs_srv_destroy_once_sysfs_root_folders(struct rtrs_srv_sess *sess)
device_del(&srv->dev);
put_device(&srv->dev);
} else {
+ put_device(&srv->dev);
mutex_unlock(&srv->paths_mutex);
}
}
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c
index 0fa116cabc44..3df290086169 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c
@@ -67,59 +67,33 @@ static inline struct rtrs_srv_sess *to_srv_sess(struct rtrs_sess *s)
return container_of(s, struct rtrs_srv_sess, s);
}
-static bool __rtrs_srv_change_state(struct rtrs_srv_sess *sess,
- enum rtrs_srv_state new_state)
+static bool rtrs_srv_change_state(struct rtrs_srv_sess *sess,
+ enum rtrs_srv_state new_state)
{
enum rtrs_srv_state old_state;
bool changed = false;
- lockdep_assert_held(&sess->state_lock);
+ spin_lock_irq(&sess->state_lock);
old_state = sess->state;
switch (new_state) {
case RTRS_SRV_CONNECTED:
- switch (old_state) {
- case RTRS_SRV_CONNECTING:
+ if (old_state == RTRS_SRV_CONNECTING)
changed = true;
- fallthrough;
- default:
- break;
- }
break;
case RTRS_SRV_CLOSING:
- switch (old_state) {
- case RTRS_SRV_CONNECTING:
- case RTRS_SRV_CONNECTED:
+ if (old_state == RTRS_SRV_CONNECTING ||
+ old_state == RTRS_SRV_CONNECTED)
changed = true;
- fallthrough;
- default:
- break;
- }
break;
case RTRS_SRV_CLOSED:
- switch (old_state) {
- case RTRS_SRV_CLOSING:
+ if (old_state == RTRS_SRV_CLOSING)
changed = true;
- fallthrough;
- default:
- break;
- }
break;
default:
break;
}
if (changed)
sess->state = new_state;
-
- return changed;
-}
-
-static bool rtrs_srv_change_state(struct rtrs_srv_sess *sess,
- enum rtrs_srv_state new_state)
-{
- bool changed;
-
- spin_lock_irq(&sess->state_lock);
- changed = __rtrs_srv_change_state(sess, new_state);
spin_unlock_irq(&sess->state_lock);
return changed;
@@ -137,7 +111,6 @@ static void rtrs_srv_free_ops_ids(struct rtrs_srv_sess *sess)
struct rtrs_srv *srv = sess->srv;
int i;
- WARN_ON(atomic_read(&sess->ids_inflight));
if (sess->ops_ids) {
for (i = 0; i < srv->queue_depth; i++)
free_id(sess->ops_ids[i]);
@@ -152,11 +125,19 @@ static struct ib_cqe io_comp_cqe = {
.done = rtrs_srv_rdma_done
};
+static inline void rtrs_srv_inflight_ref_release(struct percpu_ref *ref)
+{
+ struct rtrs_srv_sess *sess = container_of(ref, struct rtrs_srv_sess, ids_inflight_ref);
+
+ percpu_ref_exit(&sess->ids_inflight_ref);
+ complete(&sess->complete_done);
+}
+
static int rtrs_srv_alloc_ops_ids(struct rtrs_srv_sess *sess)
{
struct rtrs_srv *srv = sess->srv;
struct rtrs_srv_op *id;
- int i;
+ int i, ret;
sess->ops_ids = kcalloc(srv->queue_depth, sizeof(*sess->ops_ids),
GFP_KERNEL);
@@ -170,8 +151,14 @@ static int rtrs_srv_alloc_ops_ids(struct rtrs_srv_sess *sess)
sess->ops_ids[i] = id;
}
- init_waitqueue_head(&sess->ids_waitq);
- atomic_set(&sess->ids_inflight, 0);
+
+ ret = percpu_ref_init(&sess->ids_inflight_ref,
+ rtrs_srv_inflight_ref_release, 0, GFP_KERNEL);
+ if (ret) {
+ pr_err("Percpu reference init failed\n");
+ goto err;
+ }
+ init_completion(&sess->complete_done);
return 0;
@@ -182,21 +169,14 @@ err:
static inline void rtrs_srv_get_ops_ids(struct rtrs_srv_sess *sess)
{
- atomic_inc(&sess->ids_inflight);
+ percpu_ref_get(&sess->ids_inflight_ref);
}
static inline void rtrs_srv_put_ops_ids(struct rtrs_srv_sess *sess)
{
- if (atomic_dec_and_test(&sess->ids_inflight))
- wake_up(&sess->ids_waitq);
+ percpu_ref_put(&sess->ids_inflight_ref);
}
-static void rtrs_srv_wait_ops_ids(struct rtrs_srv_sess *sess)
-{
- wait_event(sess->ids_waitq, !atomic_read(&sess->ids_inflight));
-}
-
-
static void rtrs_srv_reg_mr_done(struct ib_cq *cq, struct ib_wc *wc)
{
struct rtrs_srv_con *con = to_srv_con(wc->qp->qp_context);
@@ -773,7 +753,40 @@ static void rtrs_srv_sess_down(struct rtrs_srv_sess *sess)
mutex_unlock(&srv->paths_ev_mutex);
}
+static bool exist_sessname(struct rtrs_srv_ctx *ctx,
+ const char *sessname, const uuid_t *path_uuid)
+{
+ struct rtrs_srv *srv;
+ struct rtrs_srv_sess *sess;
+ bool found = false;
+
+ mutex_lock(&ctx->srv_mutex);
+ list_for_each_entry(srv, &ctx->srv_list, ctx_list) {
+ mutex_lock(&srv->paths_mutex);
+
+ /* when a client with same uuid and same sessname tried to add a path */
+ if (uuid_equal(&srv->paths_uuid, path_uuid)) {
+ mutex_unlock(&srv->paths_mutex);
+ continue;
+ }
+
+ list_for_each_entry(sess, &srv->paths_list, s.entry) {
+ if (strlen(sess->s.sessname) == strlen(sessname) &&
+ !strcmp(sess->s.sessname, sessname)) {
+ found = true;
+ break;
+ }
+ }
+ mutex_unlock(&srv->paths_mutex);
+ if (found)
+ break;
+ }
+ mutex_unlock(&ctx->srv_mutex);
+ return found;
+}
+
static int post_recv_sess(struct rtrs_srv_sess *sess);
+static int rtrs_rdma_do_reject(struct rdma_cm_id *cm_id, int errno);
static int process_info_req(struct rtrs_srv_con *con,
struct rtrs_msg_info_req *msg)
@@ -792,10 +805,17 @@ static int process_info_req(struct rtrs_srv_con *con,
rtrs_err(s, "post_recv_sess(), err: %d\n", err);
return err;
}
+
+ if (exist_sessname(sess->srv->ctx,
+ msg->sessname, &sess->srv->paths_uuid)) {
+ rtrs_err(s, "sessname is duplicated: %s\n", msg->sessname);
+ return -EPERM;
+ }
+ strscpy(sess->s.sessname, msg->sessname, sizeof(sess->s.sessname));
+
rwr = kcalloc(sess->mrs_num, sizeof(*rwr), GFP_KERNEL);
if (unlikely(!rwr))
return -ENOMEM;
- strlcpy(sess->s.sessname, msg->sessname, sizeof(sess->s.sessname));
tx_sz = sizeof(*rsp);
tx_sz += sizeof(rsp->desc[0]) * sess->mrs_num;
@@ -1276,7 +1296,7 @@ int rtrs_srv_get_sess_name(struct rtrs_srv *srv, char *sessname, size_t len)
list_for_each_entry(sess, &srv->paths_list, s.entry) {
if (sess->state != RTRS_SRV_CONNECTED)
continue;
- strlcpy(sessname, sess->s.sessname,
+ strscpy(sessname, sess->s.sessname,
min_t(size_t, sizeof(sess->s.sessname), len));
err = 0;
break;
@@ -1288,7 +1308,7 @@ int rtrs_srv_get_sess_name(struct rtrs_srv *srv, char *sessname, size_t len)
EXPORT_SYMBOL(rtrs_srv_get_sess_name);
/**
- * rtrs_srv_get_sess_qdepth() - Get rtrs_srv qdepth.
+ * rtrs_srv_get_queue_depth() - Get rtrs_srv qdepth.
* @srv: Session
*/
int rtrs_srv_get_queue_depth(struct rtrs_srv *srv)
@@ -1356,8 +1376,10 @@ static struct rtrs_srv *get_or_create_srv(struct rtrs_srv_ctx *ctx,
* If this request is not the first connection request from the
* client for this session then fail and return error.
*/
- if (!first_conn)
+ if (!first_conn) {
+ pr_err_ratelimited("Error: Not the first connection request for this session\n");
return ERR_PTR(-ENXIO);
+ }
/* need to allocate a new srv */
srv = kzalloc(sizeof(*srv), GFP_KERNEL);
@@ -1481,6 +1503,7 @@ static void free_sess(struct rtrs_srv_sess *sess)
kobject_del(&sess->kobj);
kobject_put(&sess->kobj);
} else {
+ kfree(sess->stats);
kfree(sess);
}
}
@@ -1503,8 +1526,15 @@ static void rtrs_srv_close_work(struct work_struct *work)
rdma_disconnect(con->c.cm_id);
ib_drain_qp(con->c.qp);
}
- /* Wait for all inflights */
- rtrs_srv_wait_ops_ids(sess);
+
+ /*
+ * Degrade ref count to the usual model with a single shared
+ * atomic_t counter
+ */
+ percpu_ref_kill(&sess->ids_inflight_ref);
+
+ /* Wait for all completion */
+ wait_for_completion(&sess->complete_done);
/* Notify upper layer if we are the last path */
rtrs_srv_sess_down(sess);
@@ -1604,7 +1634,7 @@ static int create_con(struct rtrs_srv_sess *sess,
struct rtrs_sess *s = &sess->s;
struct rtrs_srv_con *con;
- u32 cq_size, wr_queue_size;
+ u32 cq_num, max_send_wr, max_recv_wr, wr_limit;
int err, cq_vector;
con = kzalloc(sizeof(*con), GFP_KERNEL);
@@ -1619,36 +1649,42 @@ static int create_con(struct rtrs_srv_sess *sess,
con->c.sess = &sess->s;
con->c.cid = cid;
atomic_set(&con->wr_cnt, 1);
+ wr_limit = sess->s.dev->ib_dev->attrs.max_qp_wr;
if (con->c.cid == 0) {
/*
* All receive and all send (each requiring invalidate)
* + 2 for drain and heartbeat
*/
- wr_queue_size = SERVICE_CON_QUEUE_DEPTH * 3 + 2;
- cq_size = wr_queue_size;
+ max_send_wr = min_t(int, wr_limit,
+ SERVICE_CON_QUEUE_DEPTH * 2 + 2);
+ max_recv_wr = max_send_wr;
} else {
+ /* when always_invlaidate enalbed, we need linv+rinv+mr+imm */
+ if (always_invalidate)
+ max_send_wr =
+ min_t(int, wr_limit,
+ srv->queue_depth * (1 + 4) + 1);
+ else
+ max_send_wr =
+ min_t(int, wr_limit,
+ srv->queue_depth * (1 + 2) + 1);
+
+ max_recv_wr = srv->queue_depth + 1;
/*
* If we have all receive requests posted and
* all write requests posted and each read request
* requires an invalidate request + drain
* and qp gets into error state.
*/
- cq_size = srv->queue_depth * 3 + 1;
- /*
- * In theory we might have queue_depth * 32
- * outstanding requests if an unsafe global key is used
- * and we have queue_depth read requests each consisting
- * of 32 different addresses. div 3 for mlx5.
- */
- wr_queue_size = sess->s.dev->ib_dev->attrs.max_qp_wr / 3;
}
- atomic_set(&con->sq_wr_avail, wr_queue_size);
+ cq_num = max_send_wr + max_recv_wr;
+ atomic_set(&con->sq_wr_avail, max_send_wr);
cq_vector = rtrs_srv_get_next_cq_vector(sess);
/* TODO: SOFTIRQ can be faster, but be careful with softirq context */
- err = rtrs_cq_qp_create(&sess->s, &con->c, 1, cq_vector, cq_size,
- wr_queue_size, wr_queue_size,
+ err = rtrs_cq_qp_create(&sess->s, &con->c, 1, cq_vector, cq_num,
+ max_send_wr, max_recv_wr,
IB_POLL_WORKQUEUE);
if (err) {
rtrs_err(s, "rtrs_cq_qp_create(), err: %d\n", err);
@@ -1728,7 +1764,7 @@ static struct rtrs_srv_sess *__alloc_sess(struct rtrs_srv *srv,
path.src = &sess->s.src_addr;
path.dst = &sess->s.dst_addr;
rtrs_addr_to_str(&path, str, sizeof(str));
- strlcpy(sess->s.sessname, str, sizeof(sess->s.sessname));
+ strscpy(sess->s.sessname, str, sizeof(sess->s.sessname));
sess->s.con_num = con_num;
sess->s.recon_cnt = recon_cnt;
@@ -1780,38 +1816,39 @@ static int rtrs_rdma_connect(struct rdma_cm_id *cm_id,
u16 version, con_num, cid;
u16 recon_cnt;
- int err;
+ int err = -ECONNRESET;
if (len < sizeof(*msg)) {
pr_err("Invalid RTRS connection request\n");
- goto reject_w_econnreset;
+ goto reject_w_err;
}
if (le16_to_cpu(msg->magic) != RTRS_MAGIC) {
pr_err("Invalid RTRS magic\n");
- goto reject_w_econnreset;
+ goto reject_w_err;
}
version = le16_to_cpu(msg->version);
if (version >> 8 != RTRS_PROTO_VER_MAJOR) {
pr_err("Unsupported major RTRS version: %d, expected %d\n",
version >> 8, RTRS_PROTO_VER_MAJOR);
- goto reject_w_econnreset;
+ goto reject_w_err;
}
con_num = le16_to_cpu(msg->cid_num);
if (con_num > 4096) {
/* Sanity check */
pr_err("Too many connections requested: %d\n", con_num);
- goto reject_w_econnreset;
+ goto reject_w_err;
}
cid = le16_to_cpu(msg->cid);
if (cid >= con_num) {
/* Sanity check */
pr_err("Incorrect cid: %d >= %d\n", cid, con_num);
- goto reject_w_econnreset;
+ goto reject_w_err;
}
recon_cnt = le16_to_cpu(msg->recon_cnt);
srv = get_or_create_srv(ctx, &msg->paths_uuid, msg->first_conn);
if (IS_ERR(srv)) {
err = PTR_ERR(srv);
+ pr_err("get_or_create_srv(), error %d\n", err);
goto reject_w_err;
}
mutex_lock(&srv->paths_mutex);
@@ -1826,7 +1863,7 @@ static int rtrs_rdma_connect(struct rdma_cm_id *cm_id,
rtrs_err(s, "Session in wrong state: %s\n",
rtrs_srv_state_str(sess->state));
mutex_unlock(&srv->paths_mutex);
- goto reject_w_econnreset;
+ goto reject_w_err;
}
/*
* Sanity checks
@@ -1835,13 +1872,13 @@ static int rtrs_rdma_connect(struct rdma_cm_id *cm_id,
rtrs_err(s, "Incorrect request: %d, %d\n",
cid, con_num);
mutex_unlock(&srv->paths_mutex);
- goto reject_w_econnreset;
+ goto reject_w_err;
}
if (s->con[cid]) {
rtrs_err(s, "Connection already exists: %d\n",
cid);
mutex_unlock(&srv->paths_mutex);
- goto reject_w_econnreset;
+ goto reject_w_err;
}
} else {
sess = __alloc_sess(srv, cm_id, con_num, recon_cnt,
@@ -1850,11 +1887,13 @@ static int rtrs_rdma_connect(struct rdma_cm_id *cm_id,
mutex_unlock(&srv->paths_mutex);
put_srv(srv);
err = PTR_ERR(sess);
+ pr_err("RTRS server session allocation failed: %d\n", err);
goto reject_w_err;
}
}
err = create_con(sess, cm_id, cid);
if (err) {
+ rtrs_err((&sess->s), "create_con(), error %d\n", err);
(void)rtrs_rdma_do_reject(cm_id, err);
/*
* Since session has other connections we follow normal way
@@ -1865,6 +1904,7 @@ static int rtrs_rdma_connect(struct rdma_cm_id *cm_id,
}
err = rtrs_rdma_do_accept(sess, cm_id);
if (err) {
+ rtrs_err((&sess->s), "rtrs_rdma_do_accept(), error %d\n", err);
(void)rtrs_rdma_do_reject(cm_id, err);
/*
* Since current connection was successfully added to the
@@ -1882,9 +1922,6 @@ static int rtrs_rdma_connect(struct rdma_cm_id *cm_id,
reject_w_err:
return rtrs_rdma_do_reject(cm_id, err);
-reject_w_econnreset:
- return rtrs_rdma_do_reject(cm_id, -ECONNRESET);
-
close_and_return_err:
mutex_unlock(&srv->paths_mutex);
close_sess(sess);
@@ -2177,9 +2214,9 @@ static int check_module_params(void)
sess_queue_depth, 1, MAX_SESS_QUEUE_DEPTH);
return -EINVAL;
}
- if (max_chunk_size < 4096 || !is_power_of_2(max_chunk_size)) {
+ if (max_chunk_size < MIN_CHUNK_SIZE || !is_power_of_2(max_chunk_size)) {
pr_err("Invalid max_chunk_size value %d, has to be >= %d and should be power of two.\n",
- max_chunk_size, 4096);
+ max_chunk_size, MIN_CHUNK_SIZE);
return -EINVAL;
}
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.h b/drivers/infiniband/ulp/rtrs/rtrs-srv.h
index 9543ae19996c..f8da2e3f0bda 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.h
+++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.h
@@ -81,8 +81,8 @@ struct rtrs_srv_sess {
spinlock_t state_lock;
int cur_cq_vector;
struct rtrs_srv_op **ops_ids;
- atomic_t ids_inflight;
- wait_queue_head_t ids_waitq;
+ struct percpu_ref ids_inflight_ref;
+ struct completion complete_done;
struct rtrs_srv_mr *mrs;
unsigned int mrs_num;
dma_addr_t *dma_addr;
diff --git a/drivers/infiniband/ulp/rtrs/rtrs.c b/drivers/infiniband/ulp/rtrs/rtrs.c
index a7847282a2eb..61919ebd92b2 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs.c
@@ -18,7 +18,7 @@
MODULE_DESCRIPTION("RDMA Transport Core");
MODULE_LICENSE("GPL");
-struct rtrs_iu *rtrs_iu_alloc(u32 queue_size, size_t size, gfp_t gfp_mask,
+struct rtrs_iu *rtrs_iu_alloc(u32 iu_num, size_t size, gfp_t gfp_mask,
struct ib_device *dma_dev,
enum dma_data_direction dir,
void (*done)(struct ib_cq *cq, struct ib_wc *wc))
@@ -26,10 +26,10 @@ struct rtrs_iu *rtrs_iu_alloc(u32 queue_size, size_t size, gfp_t gfp_mask,
struct rtrs_iu *ius, *iu;
int i;
- ius = kcalloc(queue_size, sizeof(*ius), gfp_mask);
+ ius = kcalloc(iu_num, sizeof(*ius), gfp_mask);
if (!ius)
return NULL;
- for (i = 0; i < queue_size; i++) {
+ for (i = 0; i < iu_num; i++) {
iu = &ius[i];
iu->direction = dir;
iu->buf = kzalloc(size, gfp_mask);
@@ -50,7 +50,7 @@ err:
}
EXPORT_SYMBOL_GPL(rtrs_iu_alloc);
-void rtrs_iu_free(struct rtrs_iu *ius, struct ib_device *ibdev, u32 queue_size)
+void rtrs_iu_free(struct rtrs_iu *ius, struct ib_device *ibdev, u32 queue_num)
{
struct rtrs_iu *iu;
int i;
@@ -58,7 +58,7 @@ void rtrs_iu_free(struct rtrs_iu *ius, struct ib_device *ibdev, u32 queue_size)
if (!ius)
return;
- for (i = 0; i < queue_size; i++) {
+ for (i = 0; i < queue_num; i++) {
iu = &ius[i];
ib_dma_unmap_single(ibdev, iu->dma_addr, iu->size, iu->direction);
kfree(iu->buf);
@@ -105,18 +105,21 @@ int rtrs_post_recv_empty(struct rtrs_con *con, struct ib_cqe *cqe)
EXPORT_SYMBOL_GPL(rtrs_post_recv_empty);
static int rtrs_post_send(struct ib_qp *qp, struct ib_send_wr *head,
- struct ib_send_wr *wr)
+ struct ib_send_wr *wr, struct ib_send_wr *tail)
{
if (head) {
- struct ib_send_wr *tail = head;
+ struct ib_send_wr *next = head;
- while (tail->next)
- tail = tail->next;
- tail->next = wr;
+ while (next->next)
+ next = next->next;
+ next->next = wr;
} else {
head = wr;
}
+ if (tail)
+ wr->next = tail;
+
return ib_post_send(qp, head, NULL);
}
@@ -142,15 +145,16 @@ int rtrs_iu_post_send(struct rtrs_con *con, struct rtrs_iu *iu, size_t size,
.send_flags = IB_SEND_SIGNALED,
};
- return rtrs_post_send(con->qp, head, &wr);
+ return rtrs_post_send(con->qp, head, &wr, NULL);
}
EXPORT_SYMBOL_GPL(rtrs_iu_post_send);
int rtrs_iu_post_rdma_write_imm(struct rtrs_con *con, struct rtrs_iu *iu,
- struct ib_sge *sge, unsigned int num_sge,
- u32 rkey, u64 rdma_addr, u32 imm_data,
- enum ib_send_flags flags,
- struct ib_send_wr *head)
+ struct ib_sge *sge, unsigned int num_sge,
+ u32 rkey, u64 rdma_addr, u32 imm_data,
+ enum ib_send_flags flags,
+ struct ib_send_wr *head,
+ struct ib_send_wr *tail)
{
struct ib_rdma_wr wr;
int i;
@@ -174,7 +178,7 @@ int rtrs_iu_post_rdma_write_imm(struct rtrs_con *con, struct rtrs_iu *iu,
if (WARN_ON(sge[i].length == 0))
return -EINVAL;
- return rtrs_post_send(con->qp, head, &wr.wr);
+ return rtrs_post_send(con->qp, head, &wr.wr, tail);
}
EXPORT_SYMBOL_GPL(rtrs_iu_post_rdma_write_imm);
@@ -191,7 +195,7 @@ int rtrs_post_rdma_write_imm_empty(struct rtrs_con *con, struct ib_cqe *cqe,
.wr.ex.imm_data = cpu_to_be32(imm_data),
};
- return rtrs_post_send(con->qp, head, &wr.wr);
+ return rtrs_post_send(con->qp, head, &wr.wr, NULL);
}
EXPORT_SYMBOL_GPL(rtrs_post_rdma_write_imm_empty);
@@ -212,20 +216,20 @@ static void qp_event_handler(struct ib_event *ev, void *ctx)
}
}
-static int create_cq(struct rtrs_con *con, int cq_vector, u16 cq_size,
+static int create_cq(struct rtrs_con *con, int cq_vector, int nr_cqe,
enum ib_poll_context poll_ctx)
{
struct rdma_cm_id *cm_id = con->cm_id;
struct ib_cq *cq;
- cq = ib_cq_pool_get(cm_id->device, cq_size, cq_vector, poll_ctx);
+ cq = ib_cq_pool_get(cm_id->device, nr_cqe, cq_vector, poll_ctx);
if (IS_ERR(cq)) {
rtrs_err(con->sess, "Creating completion queue failed, errno: %ld\n",
PTR_ERR(cq));
return PTR_ERR(cq);
}
con->cq = cq;
- con->cq_size = cq_size;
+ con->nr_cqe = nr_cqe;
return 0;
}
@@ -260,20 +264,20 @@ static int create_qp(struct rtrs_con *con, struct ib_pd *pd,
}
int rtrs_cq_qp_create(struct rtrs_sess *sess, struct rtrs_con *con,
- u32 max_send_sge, int cq_vector, int cq_size,
+ u32 max_send_sge, int cq_vector, int nr_cqe,
u32 max_send_wr, u32 max_recv_wr,
enum ib_poll_context poll_ctx)
{
int err;
- err = create_cq(con, cq_vector, cq_size, poll_ctx);
+ err = create_cq(con, cq_vector, nr_cqe, poll_ctx);
if (err)
return err;
err = create_qp(con, sess->dev->ib_pd, max_send_wr, max_recv_wr,
max_send_sge);
if (err) {
- ib_cq_pool_put(con->cq, con->cq_size);
+ ib_cq_pool_put(con->cq, con->nr_cqe);
con->cq = NULL;
return err;
}
@@ -290,7 +294,7 @@ void rtrs_cq_qp_destroy(struct rtrs_con *con)
con->qp = NULL;
}
if (con->cq) {
- ib_cq_pool_put(con->cq, con->cq_size);
+ ib_cq_pool_put(con->cq, con->nr_cqe);
con->cq = NULL;
}
}
@@ -376,7 +380,6 @@ void rtrs_stop_hb(struct rtrs_sess *sess)
{
cancel_delayed_work_sync(&sess->hb_dwork);
sess->hb_missed_cnt = 0;
- sess->hb_missed_max = 0;
}
EXPORT_SYMBOL_GPL(rtrs_stop_hb);
diff --git a/drivers/infiniband/ulp/rtrs/rtrs.h b/drivers/infiniband/ulp/rtrs/rtrs.h
index dc3e1af1a85b..859c79685daf 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs.h
+++ b/drivers/infiniband/ulp/rtrs/rtrs.h
@@ -57,7 +57,6 @@ struct rtrs_clt *rtrs_clt_open(struct rtrs_clt_ops *ops,
const struct rtrs_addr *paths,
size_t path_cnt, u16 port,
size_t pdu_sz, u8 reconnect_delay_sec,
- u16 max_segments,
s16 max_reconnect_attempts, u32 nr_poll_queues);
void rtrs_clt_close(struct rtrs_clt *sess);
@@ -110,6 +109,7 @@ int rtrs_clt_rdma_cq_direct(struct rtrs_clt *clt, unsigned int index);
struct rtrs_attrs {
u32 queue_depth;
u32 max_io_size;
+ u32 max_segments;
};
int rtrs_clt_query(struct rtrs_clt *sess, struct rtrs_attrs *attr);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 31f8aa2c40ed..8d5cf5eb5778 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -965,68 +965,52 @@ static void srp_disconnect_target(struct srp_target_port *target)
}
}
-static void srp_free_req_data(struct srp_target_port *target,
- struct srp_rdma_ch *ch)
+static int srp_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
{
+ struct srp_target_port *target = host_to_target(shost);
struct srp_device *dev = target->srp_host->srp_dev;
struct ib_device *ibdev = dev->dev;
- struct srp_request *req;
- int i;
-
- if (!ch->req_ring)
- return;
+ struct srp_request *req = scsi_cmd_priv(cmd);
- for (i = 0; i < target->req_ring_size; ++i) {
- req = &ch->req_ring[i];
- if (dev->use_fast_reg)
- kfree(req->fr_list);
- if (req->indirect_dma_addr) {
- ib_dma_unmap_single(ibdev, req->indirect_dma_addr,
- target->indirect_size,
- DMA_TO_DEVICE);
- }
- kfree(req->indirect_desc);
+ kfree(req->fr_list);
+ if (req->indirect_dma_addr) {
+ ib_dma_unmap_single(ibdev, req->indirect_dma_addr,
+ target->indirect_size,
+ DMA_TO_DEVICE);
}
+ kfree(req->indirect_desc);
- kfree(ch->req_ring);
- ch->req_ring = NULL;
+ return 0;
}
-static int srp_alloc_req_data(struct srp_rdma_ch *ch)
+static int srp_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
{
- struct srp_target_port *target = ch->target;
+ struct srp_target_port *target = host_to_target(shost);
struct srp_device *srp_dev = target->srp_host->srp_dev;
struct ib_device *ibdev = srp_dev->dev;
- struct srp_request *req;
- void *mr_list;
+ struct srp_request *req = scsi_cmd_priv(cmd);
dma_addr_t dma_addr;
- int i, ret = -ENOMEM;
-
- ch->req_ring = kcalloc(target->req_ring_size, sizeof(*ch->req_ring),
- GFP_KERNEL);
- if (!ch->req_ring)
- goto out;
+ int ret = -ENOMEM;
- for (i = 0; i < target->req_ring_size; ++i) {
- req = &ch->req_ring[i];
- mr_list = kmalloc_array(target->mr_per_cmd, sizeof(void *),
+ if (srp_dev->use_fast_reg) {
+ req->fr_list = kmalloc_array(target->mr_per_cmd, sizeof(void *),
GFP_KERNEL);
- if (!mr_list)
- goto out;
- if (srp_dev->use_fast_reg)
- req->fr_list = mr_list;
- req->indirect_desc = kmalloc(target->indirect_size, GFP_KERNEL);
- if (!req->indirect_desc)
- goto out;
-
- dma_addr = ib_dma_map_single(ibdev, req->indirect_desc,
- target->indirect_size,
- DMA_TO_DEVICE);
- if (ib_dma_mapping_error(ibdev, dma_addr))
+ if (!req->fr_list)
goto out;
+ }
+ req->indirect_desc = kmalloc(target->indirect_size, GFP_KERNEL);
+ if (!req->indirect_desc)
+ goto out;
- req->indirect_dma_addr = dma_addr;
+ dma_addr = ib_dma_map_single(ibdev, req->indirect_desc,
+ target->indirect_size,
+ DMA_TO_DEVICE);
+ if (ib_dma_mapping_error(ibdev, dma_addr)) {
+ srp_exit_cmd_priv(shost, cmd);
+ goto out;
}
+
+ req->indirect_dma_addr = dma_addr;
ret = 0;
out:
@@ -1068,10 +1052,6 @@ static void srp_remove_target(struct srp_target_port *target)
}
cancel_work_sync(&target->tl_err_work);
srp_rport_put(target->rport);
- for (i = 0; i < target->ch_count; i++) {
- ch = &target->ch[i];
- srp_free_req_data(target, ch);
- }
kfree(target->ch);
target->ch = NULL;
@@ -1290,22 +1270,32 @@ static void srp_finish_req(struct srp_rdma_ch *ch, struct srp_request *req,
}
}
-static void srp_terminate_io(struct srp_rport *rport)
+struct srp_terminate_context {
+ struct srp_target_port *srp_target;
+ int scsi_result;
+};
+
+static bool srp_terminate_cmd(struct scsi_cmnd *scmnd, void *context_ptr,
+ bool reserved)
{
- struct srp_target_port *target = rport->lld_data;
- struct srp_rdma_ch *ch;
- int i, j;
+ struct srp_terminate_context *context = context_ptr;
+ struct srp_target_port *target = context->srp_target;
+ u32 tag = blk_mq_unique_tag(scmnd->request);
+ struct srp_rdma_ch *ch = &target->ch[blk_mq_unique_tag_to_hwq(tag)];
+ struct srp_request *req = scsi_cmd_priv(scmnd);
- for (i = 0; i < target->ch_count; i++) {
- ch = &target->ch[i];
+ srp_finish_req(ch, req, NULL, context->scsi_result);
- for (j = 0; j < target->req_ring_size; ++j) {
- struct srp_request *req = &ch->req_ring[j];
+ return true;
+}
- srp_finish_req(ch, req, NULL,
- DID_TRANSPORT_FAILFAST << 16);
- }
- }
+static void srp_terminate_io(struct srp_rport *rport)
+{
+ struct srp_target_port *target = rport->lld_data;
+ struct srp_terminate_context context = { .srp_target = target,
+ .scsi_result = DID_TRANSPORT_FAILFAST << 16 };
+
+ scsi_host_busy_iter(target->scsi_host, srp_terminate_cmd, &context);
}
/* Calculate maximum initiator to target information unit length. */
@@ -1361,13 +1351,12 @@ static int srp_rport_reconnect(struct srp_rport *rport)
ch = &target->ch[i];
ret += srp_new_cm_id(ch);
}
- for (i = 0; i < target->ch_count; i++) {
- ch = &target->ch[i];
- for (j = 0; j < target->req_ring_size; ++j) {
- struct srp_request *req = &ch->req_ring[j];
+ {
+ struct srp_terminate_context context = {
+ .srp_target = target, .scsi_result = DID_RESET << 16};
- srp_finish_req(ch, req, NULL, DID_RESET << 16);
- }
+ scsi_host_busy_iter(target->scsi_host, srp_terminate_cmd,
+ &context);
}
for (i = 0; i < target->ch_count; i++) {
ch = &target->ch[i];
@@ -1963,13 +1952,10 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp)
spin_unlock_irqrestore(&ch->lock, flags);
} else {
scmnd = scsi_host_find_tag(target->scsi_host, rsp->tag);
- if (scmnd && scmnd->host_scribble) {
- req = (void *)scmnd->host_scribble;
+ if (scmnd) {
+ req = scsi_cmd_priv(scmnd);
scmnd = srp_claim_req(ch, req, NULL, scmnd);
} else {
- scmnd = NULL;
- }
- if (!scmnd) {
shost_printk(KERN_ERR, target->scsi_host,
"Null scmnd for RSP w/tag %#016llx received on ch %td / QP %#x\n",
rsp->tag, ch - target->ch, ch->qp->qp_num);
@@ -2001,7 +1987,6 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp)
srp_free_req(ch, req, scmnd,
be32_to_cpu(rsp->req_lim_delta));
- scmnd->host_scribble = NULL;
scmnd->scsi_done(scmnd);
}
}
@@ -2169,13 +2154,12 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
{
struct srp_target_port *target = host_to_target(shost);
struct srp_rdma_ch *ch;
- struct srp_request *req;
+ struct srp_request *req = scsi_cmd_priv(scmnd);
struct srp_iu *iu;
struct srp_cmd *cmd;
struct ib_device *dev;
unsigned long flags;
u32 tag;
- u16 idx;
int len, ret;
scmnd->result = srp_chkready(target->rport);
@@ -2185,10 +2169,6 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
WARN_ON_ONCE(scmnd->request->tag < 0);
tag = blk_mq_unique_tag(scmnd->request);
ch = &target->ch[blk_mq_unique_tag_to_hwq(tag)];
- idx = blk_mq_unique_tag_to_tag(tag);
- WARN_ONCE(idx >= target->req_ring_size, "%s: tag %#x: idx %d >= %d\n",
- dev_name(&shost->shost_gendev), tag, idx,
- target->req_ring_size);
spin_lock_irqsave(&ch->lock, flags);
iu = __srp_get_tx_iu(ch, SRP_IU_CMD);
@@ -2197,13 +2177,10 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
if (!iu)
goto err;
- req = &ch->req_ring[idx];
dev = target->srp_host->srp_dev->dev;
ib_dma_sync_single_for_cpu(dev, iu->dma, ch->max_it_iu_len,
DMA_TO_DEVICE);
- scmnd->host_scribble = (void *) req;
-
cmd = iu->buf;
memset(cmd, 0, sizeof *cmd);
@@ -2232,7 +2209,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
* to reduce queue depth temporarily.
*/
scmnd->result = len == -ENOMEM ?
- DID_OK << 16 | QUEUE_FULL << 1 : DID_ERROR << 16;
+ DID_OK << 16 | SAM_STAT_TASK_SET_FULL : DID_ERROR << 16;
goto err_iu;
}
@@ -2891,7 +2868,7 @@ static int srp_slave_configure(struct scsi_device *sdev)
return 0;
}
-static ssize_t show_id_ext(struct device *dev, struct device_attribute *attr,
+static ssize_t id_ext_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -2899,7 +2876,9 @@ static ssize_t show_id_ext(struct device *dev, struct device_attribute *attr,
return sysfs_emit(buf, "0x%016llx\n", be64_to_cpu(target->id_ext));
}
-static ssize_t show_ioc_guid(struct device *dev, struct device_attribute *attr,
+static DEVICE_ATTR_RO(id_ext);
+
+static ssize_t ioc_guid_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -2907,7 +2886,9 @@ static ssize_t show_ioc_guid(struct device *dev, struct device_attribute *attr,
return sysfs_emit(buf, "0x%016llx\n", be64_to_cpu(target->ioc_guid));
}
-static ssize_t show_service_id(struct device *dev,
+static DEVICE_ATTR_RO(ioc_guid);
+
+static ssize_t service_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -2918,7 +2899,9 @@ static ssize_t show_service_id(struct device *dev,
be64_to_cpu(target->ib_cm.service_id));
}
-static ssize_t show_pkey(struct device *dev, struct device_attribute *attr,
+static DEVICE_ATTR_RO(service_id);
+
+static ssize_t pkey_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -2929,7 +2912,9 @@ static ssize_t show_pkey(struct device *dev, struct device_attribute *attr,
return sysfs_emit(buf, "0x%04x\n", be16_to_cpu(target->ib_cm.pkey));
}
-static ssize_t show_sgid(struct device *dev, struct device_attribute *attr,
+static DEVICE_ATTR_RO(pkey);
+
+static ssize_t sgid_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -2937,7 +2922,9 @@ static ssize_t show_sgid(struct device *dev, struct device_attribute *attr,
return sysfs_emit(buf, "%pI6\n", target->sgid.raw);
}
-static ssize_t show_dgid(struct device *dev, struct device_attribute *attr,
+static DEVICE_ATTR_RO(sgid);
+
+static ssize_t dgid_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -2949,8 +2936,10 @@ static ssize_t show_dgid(struct device *dev, struct device_attribute *attr,
return sysfs_emit(buf, "%pI6\n", ch->ib_cm.path.dgid.raw);
}
-static ssize_t show_orig_dgid(struct device *dev,
- struct device_attribute *attr, char *buf)
+static DEVICE_ATTR_RO(dgid);
+
+static ssize_t orig_dgid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -2960,8 +2949,10 @@ static ssize_t show_orig_dgid(struct device *dev,
return sysfs_emit(buf, "%pI6\n", target->ib_cm.orig_dgid.raw);
}
-static ssize_t show_req_lim(struct device *dev,
- struct device_attribute *attr, char *buf)
+static DEVICE_ATTR_RO(orig_dgid);
+
+static ssize_t req_lim_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
struct srp_rdma_ch *ch;
@@ -2975,7 +2966,9 @@ static ssize_t show_req_lim(struct device *dev,
return sysfs_emit(buf, "%d\n", req_lim);
}
-static ssize_t show_zero_req_lim(struct device *dev,
+static DEVICE_ATTR_RO(req_lim);
+
+static ssize_t zero_req_lim_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -2983,7 +2976,9 @@ static ssize_t show_zero_req_lim(struct device *dev,
return sysfs_emit(buf, "%d\n", target->zero_req_lim);
}
-static ssize_t show_local_ib_port(struct device *dev,
+static DEVICE_ATTR_RO(zero_req_lim);
+
+static ssize_t local_ib_port_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -2991,7 +2986,9 @@ static ssize_t show_local_ib_port(struct device *dev,
return sysfs_emit(buf, "%d\n", target->srp_host->port);
}
-static ssize_t show_local_ib_device(struct device *dev,
+static DEVICE_ATTR_RO(local_ib_port);
+
+static ssize_t local_ib_device_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -3000,7 +2997,9 @@ static ssize_t show_local_ib_device(struct device *dev,
dev_name(&target->srp_host->srp_dev->dev->dev));
}
-static ssize_t show_ch_count(struct device *dev, struct device_attribute *attr,
+static DEVICE_ATTR_RO(local_ib_device);
+
+static ssize_t ch_count_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -3008,7 +3007,9 @@ static ssize_t show_ch_count(struct device *dev, struct device_attribute *attr,
return sysfs_emit(buf, "%d\n", target->ch_count);
}
-static ssize_t show_comp_vector(struct device *dev,
+static DEVICE_ATTR_RO(ch_count);
+
+static ssize_t comp_vector_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -3016,7 +3017,9 @@ static ssize_t show_comp_vector(struct device *dev,
return sysfs_emit(buf, "%d\n", target->comp_vector);
}
-static ssize_t show_tl_retry_count(struct device *dev,
+static DEVICE_ATTR_RO(comp_vector);
+
+static ssize_t tl_retry_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -3024,7 +3027,9 @@ static ssize_t show_tl_retry_count(struct device *dev,
return sysfs_emit(buf, "%d\n", target->tl_retry_count);
}
-static ssize_t show_cmd_sg_entries(struct device *dev,
+static DEVICE_ATTR_RO(tl_retry_count);
+
+static ssize_t cmd_sg_entries_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -3032,7 +3037,9 @@ static ssize_t show_cmd_sg_entries(struct device *dev,
return sysfs_emit(buf, "%u\n", target->cmd_sg_cnt);
}
-static ssize_t show_allow_ext_sg(struct device *dev,
+static DEVICE_ATTR_RO(cmd_sg_entries);
+
+static ssize_t allow_ext_sg_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
@@ -3040,22 +3047,7 @@ static ssize_t show_allow_ext_sg(struct device *dev,
return sysfs_emit(buf, "%s\n", target->allow_ext_sg ? "true" : "false");
}
-static DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL);
-static DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL);
-static DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL);
-static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
-static DEVICE_ATTR(sgid, S_IRUGO, show_sgid, NULL);
-static DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL);
-static DEVICE_ATTR(orig_dgid, S_IRUGO, show_orig_dgid, NULL);
-static DEVICE_ATTR(req_lim, S_IRUGO, show_req_lim, NULL);
-static DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL);
-static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL);
-static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
-static DEVICE_ATTR(ch_count, S_IRUGO, show_ch_count, NULL);
-static DEVICE_ATTR(comp_vector, S_IRUGO, show_comp_vector, NULL);
-static DEVICE_ATTR(tl_retry_count, S_IRUGO, show_tl_retry_count, NULL);
-static DEVICE_ATTR(cmd_sg_entries, S_IRUGO, show_cmd_sg_entries, NULL);
-static DEVICE_ATTR(allow_ext_sg, S_IRUGO, show_allow_ext_sg, NULL);
+static DEVICE_ATTR_RO(allow_ext_sg);
static struct device_attribute *srp_host_attrs[] = {
&dev_attr_id_ext,
@@ -3084,6 +3076,8 @@ static struct scsi_host_template srp_template = {
.target_alloc = srp_target_alloc,
.slave_configure = srp_slave_configure,
.info = srp_target_info,
+ .init_cmd_priv = srp_init_cmd_priv,
+ .exit_cmd_priv = srp_exit_cmd_priv,
.queuecommand = srp_queuecommand,
.change_queue_depth = srp_change_queue_depth,
.eh_timed_out = srp_timed_out,
@@ -3097,6 +3091,7 @@ static struct scsi_host_template srp_template = {
.cmd_per_lun = SRP_DEFAULT_CMD_SQ_SIZE,
.shost_attrs = srp_host_attrs,
.track_queue_depth = 1,
+ .cmd_size = sizeof(struct srp_request),
};
static int srp_sdev_count(struct Scsi_Host *host)
@@ -3617,9 +3612,9 @@ out:
return ret;
}
-static ssize_t srp_create_target(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t add_target_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
{
struct srp_host *host =
container_of(dev, struct srp_host, dev);
@@ -3676,8 +3671,6 @@ static ssize_t srp_create_target(struct device *dev,
if (ret)
goto out;
- target->req_ring_size = target->queue_size - SRP_TSK_MGMT_SQ_SIZE;
-
if (!srp_conn_unique(target->srp_host, target)) {
if (target->using_rdma_cm) {
shost_printk(KERN_INFO, target->scsi_host,
@@ -3780,10 +3773,6 @@ static ssize_t srp_create_target(struct device *dev,
if (ret)
goto err_disconnect;
- ret = srp_alloc_req_data(ch);
- if (ret)
- goto err_disconnect;
-
ret = srp_connect_ch(ch, max_iu_len, multich);
if (ret) {
char dst[64];
@@ -3802,7 +3791,6 @@ static ssize_t srp_create_target(struct device *dev,
goto free_ch;
} else {
srp_free_ch_ib(target, ch);
- srp_free_req_data(target, ch);
target->ch_count = ch - target->ch;
goto connected;
}
@@ -3863,16 +3851,15 @@ free_ch:
for (i = 0; i < target->ch_count; i++) {
ch = &target->ch[i];
srp_free_ch_ib(target, ch);
- srp_free_req_data(target, ch);
}
kfree(target->ch);
goto out;
}
-static DEVICE_ATTR(add_target, S_IWUSR, NULL, srp_create_target);
+static DEVICE_ATTR_WO(add_target);
-static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr,
+static ssize_t ibdev_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct srp_host *host = container_of(dev, struct srp_host, dev);
@@ -3880,9 +3867,9 @@ static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr,
return sysfs_emit(buf, "%s\n", dev_name(&host->srp_dev->dev->dev));
}
-static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
+static DEVICE_ATTR_RO(ibdev);
-static ssize_t show_port(struct device *dev, struct device_attribute *attr,
+static ssize_t port_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct srp_host *host = container_of(dev, struct srp_host, dev);
@@ -3890,7 +3877,7 @@ static ssize_t show_port(struct device *dev, struct device_attribute *attr,
return sysfs_emit(buf, "%d\n", host->port);
}
-static DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
+static DEVICE_ATTR_RO(port);
static struct srp_host *srp_add_port(struct srp_device *device, u8 port)
{
@@ -4078,10 +4065,13 @@ static int __init srp_init_module(void)
{
int ret;
+ BUILD_BUG_ON(sizeof(struct srp_aer_req) != 36);
+ BUILD_BUG_ON(sizeof(struct srp_cmd) != 48);
BUILD_BUG_ON(sizeof(struct srp_imm_buf) != 4);
+ BUILD_BUG_ON(sizeof(struct srp_indirect_buf) != 20);
BUILD_BUG_ON(sizeof(struct srp_login_req) != 64);
BUILD_BUG_ON(sizeof(struct srp_login_req_rdma) != 56);
- BUILD_BUG_ON(sizeof(struct srp_cmd) != 48);
+ BUILD_BUG_ON(sizeof(struct srp_rsp) != 36);
if (srp_sg_tablesize) {
pr_warn("srp_sg_tablesize is deprecated, please use cmd_sg_entries\n");
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 6818cac0a3b7..abccddeea1e3 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -174,7 +174,6 @@ struct srp_rdma_ch {
struct srp_iu **tx_ring;
struct srp_iu **rx_ring;
- struct srp_request *req_ring;
int comp_vector;
u64 tsk_mgmt_tag;
@@ -220,7 +219,6 @@ struct srp_target_port {
int mr_pool_size;
int mr_per_cmd;
int queue_size;
- int req_ring_size;
int comp_vector;
int tl_retry_count;
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index ea447805d4ea..3cadf1295417 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -2858,7 +2858,6 @@ static void srpt_queue_response(struct se_cmd *cmd)
&ch->sq_wr_avail) < 0)) {
pr_warn("%s: IB send queue full (needed %d)\n",
__func__, ioctx->n_rdma);
- ret = -ENOMEM;
goto out;
}
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index ec0e861f185f..5baebf62df33 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -4,7 +4,6 @@
#
menu "Input device support"
- depends on !UML
config INPUT
tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT
diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c
index c0d0b121ae7e..e47bdf92088a 100644
--- a/drivers/input/evbug.c
+++ b/drivers/input/evbug.c
@@ -7,9 +7,6 @@
* Input driver event debug module - dumps all events into syslog
*/
-/*
- */
-
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/slab.h>
diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig
index 4761795cb49f..5a2c2fb3217d 100644
--- a/drivers/input/gameport/Kconfig
+++ b/drivers/input/gameport/Kconfig
@@ -4,6 +4,7 @@
#
config GAMEPORT
tristate "Gameport support"
+ depends on !UML
help
Gameport support is for the standard 15-pin PC gameport. If you
have a joystick, gamepad, gameport card, a soundcard with a gameport
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index da8963a9f044..947d440a3be6 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -499,7 +499,7 @@ static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
memcpy(joydev->keypam, keypam, len);
for (i = 0; i < joydev->nkey; i++)
- joydev->keymap[keypam[i] - BTN_MISC] = i;
+ joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
out:
kfree(keypam);
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 5e38899058c1..3b23078bc7b5 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -4,6 +4,7 @@
#
menuconfig INPUT_JOYSTICK
bool "Joysticks/Gamepads"
+ depends on !UML
help
If you have a joystick, 6dof controller, gamepad, steering wheel,
weapon control system or something like that you can say Y here
@@ -372,6 +373,15 @@ config JOYSTICK_PXRC
To compile this driver as a module, choose M here: the
module will be called pxrc.
+config JOYSTICK_QWIIC
+ tristate "SparkFun Qwiic Joystick"
+ depends on I2C
+ help
+ Say Y here if you want to use the SparkFun Qwiic Joystick.
+
+ To compile this driver as a module, choose M here: the
+ module will be called qwiic-joystick.
+
config JOYSTICK_FSIA6B
tristate "FlySky FS-iA6B RC Receiver"
select SERIO
diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
index 31d720c9e493..5174b8aba2dd 100644
--- a/drivers/input/joystick/Makefile
+++ b/drivers/input/joystick/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_JOYSTICK_MAPLE) += maplecontrol.o
obj-$(CONFIG_JOYSTICK_N64) += n64joy.o
obj-$(CONFIG_JOYSTICK_PSXPAD_SPI) += psxpad-spi.o
obj-$(CONFIG_JOYSTICK_PXRC) += pxrc.o
+obj-$(CONFIG_JOYSTICK_QWIIC) += qwiic-joystick.o
obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o
obj-$(CONFIG_JOYSTICK_SPACEBALL) += spaceball.o
obj-$(CONFIG_JOYSTICK_SPACEORB) += spaceorb.o
diff --git a/drivers/input/joystick/qwiic-joystick.c b/drivers/input/joystick/qwiic-joystick.c
new file mode 100644
index 000000000000..d4da31c0616c
--- /dev/null
+++ b/drivers/input/joystick/qwiic-joystick.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Oleh Kravchenko <oleg@kaa.org.ua>
+ *
+ * SparkFun Qwiic Joystick
+ * Product page:https://www.sparkfun.com/products/15168
+ * Firmware and hardware sources:https://github.com/sparkfun/Qwiic_Joystick
+ */
+
+#include <linux/bits.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#define DRV_NAME "qwiic-joystick"
+
+#define QWIIC_JSK_REG_VERS 1
+#define QWIIC_JSK_REG_DATA 3
+
+#define QWIIC_JSK_MAX_AXIS GENMASK(9, 0)
+#define QWIIC_JSK_FUZZ 2
+#define QWIIC_JSK_FLAT 2
+#define QWIIC_JSK_POLL_INTERVAL 16
+#define QWIIC_JSK_POLL_MIN 8
+#define QWIIC_JSK_POLL_MAX 32
+
+struct qwiic_jsk {
+ char phys[32];
+ struct input_dev *dev;
+ struct i2c_client *client;
+};
+
+struct qwiic_ver {
+ u8 major;
+ u8 minor;
+};
+
+struct qwiic_data {
+ __be16 x;
+ __be16 y;
+ u8 thumb;
+};
+
+static void qwiic_poll(struct input_dev *input)
+{
+ struct qwiic_jsk *priv = input_get_drvdata(input);
+ struct qwiic_data data;
+ int err;
+
+ err = i2c_smbus_read_i2c_block_data(priv->client, QWIIC_JSK_REG_DATA,
+ sizeof(data), (u8 *)&data);
+ if (err != sizeof(data))
+ return;
+
+ input_report_abs(input, ABS_X, be16_to_cpu(data.x) >> 6);
+ input_report_abs(input, ABS_Y, be16_to_cpu(data.y) >> 6);
+ input_report_key(input, BTN_THUMBL, !data.thumb);
+ input_sync(input);
+}
+
+static int qwiic_probe(struct i2c_client *client)
+{
+ struct qwiic_jsk *priv;
+ struct qwiic_ver vers;
+ int err;
+
+ err = i2c_smbus_read_i2c_block_data(client, QWIIC_JSK_REG_VERS,
+ sizeof(vers), (u8 *)&vers);
+ if (err < 0)
+ return err;
+ if (err != sizeof(vers))
+ return -EIO;
+
+ dev_dbg(&client->dev, "SparkFun Qwiic Joystick, FW: %u.%u\n",
+ vers.major, vers.minor);
+
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client = client;
+ snprintf(priv->phys, sizeof(priv->phys),
+ "i2c/%s", dev_name(&client->dev));
+ i2c_set_clientdata(client, priv);
+
+ priv->dev = devm_input_allocate_device(&client->dev);
+ if (!priv->dev)
+ return -ENOMEM;
+
+ priv->dev->id.bustype = BUS_I2C;
+ priv->dev->name = "SparkFun Qwiic Joystick";
+ priv->dev->phys = priv->phys;
+ input_set_drvdata(priv->dev, priv);
+
+ input_set_abs_params(priv->dev, ABS_X, 0, QWIIC_JSK_MAX_AXIS,
+ QWIIC_JSK_FUZZ, QWIIC_JSK_FLAT);
+ input_set_abs_params(priv->dev, ABS_Y, 0, QWIIC_JSK_MAX_AXIS,
+ QWIIC_JSK_FUZZ, QWIIC_JSK_FLAT);
+ input_set_capability(priv->dev, EV_KEY, BTN_THUMBL);
+
+ err = input_setup_polling(priv->dev, qwiic_poll);
+ if (err) {
+ dev_err(&client->dev, "failed to set up polling: %d\n", err);
+ return err;
+ }
+ input_set_poll_interval(priv->dev, QWIIC_JSK_POLL_INTERVAL);
+ input_set_min_poll_interval(priv->dev, QWIIC_JSK_POLL_MIN);
+ input_set_max_poll_interval(priv->dev, QWIIC_JSK_POLL_MAX);
+
+ err = input_register_device(priv->dev);
+ if (err) {
+ dev_err(&client->dev, "failed to register joystick: %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_qwiic_match[] = {
+ { .compatible = "sparkfun,qwiic-joystick", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_qwiic_match);
+#endif /* CONFIG_OF */
+
+static const struct i2c_device_id qwiic_id_table[] = {
+ { KBUILD_MODNAME, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, qwiic_id_table);
+
+static struct i2c_driver qwiic_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = of_match_ptr(of_qwiic_match),
+ },
+ .id_table = qwiic_id_table,
+ .probe_new = qwiic_probe,
+};
+module_i2c_driver(qwiic_driver);
+
+MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
+MODULE_DESCRIPTION("SparkFun Qwiic Joystick driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index fac91ea14f17..8e9672deb1eb 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -660,6 +660,7 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
fallthrough;
case 45: /* Ambiguous packet length */
if (j <= 40) { /* ID length less or eq 40 -> FSP */
+ fallthrough;
case 43:
sw->type = SW_ID_FSP;
break;
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index d69d7657ab12..29de8412e416 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -79,6 +79,7 @@
#define MAP_DPAD_TO_BUTTONS (1 << 0)
#define MAP_TRIGGERS_TO_BUTTONS (1 << 1)
#define MAP_STICKS_TO_NULL (1 << 2)
+#define MAP_SELECT_BUTTON (1 << 3)
#define DANCEPAD_MAP_CONFIG (MAP_DPAD_TO_BUTTONS | \
MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
@@ -130,6 +131,7 @@ static const struct xpad_device {
{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE },
{ 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE },
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
+ { 0x045e, 0x0b12, "Microsoft Xbox One X pad", MAP_SELECT_BUTTON, XTYPE_XBOXONE },
{ 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 },
{ 0x046d, 0xc21e, "Logitech Gamepad F510", 0, XTYPE_XBOX360 },
{ 0x046d, 0xc21f, "Logitech Gamepad F710", 0, XTYPE_XBOX360 },
@@ -864,6 +866,8 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
/* menu/view buttons */
input_report_key(dev, BTN_START, data[4] & 0x04);
input_report_key(dev, BTN_SELECT, data[4] & 0x08);
+ if (xpad->mapping & MAP_SELECT_BUTTON)
+ input_report_key(dev, KEY_RECORD, data[22] & 0x01);
/* buttons A,B,X,Y */
input_report_key(dev, BTN_A, data[4] & 0x10);
@@ -1674,6 +1678,8 @@ static int xpad_init_input(struct usb_xpad *xpad)
xpad->xtype == XTYPE_XBOXONE) {
for (i = 0; xpad360_btn[i] >= 0; i++)
input_set_capability(input_dev, EV_KEY, xpad360_btn[i]);
+ if (xpad->mapping & MAP_SELECT_BUTTON)
+ input_set_capability(input_dev, EV_KEY, KEY_RECORD);
} else {
for (i = 0; xpad_btn[i] >= 0; i++)
input_set_capability(input_dev, EV_KEY, xpad_btn[i]);
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 32d15809ae58..40a070a2e7f5 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -67,9 +67,6 @@ config KEYBOARD_AMIGA
To compile this driver as a module, choose M here: the
module will be called amikbd.
-config ATARI_KBD_CORE
- bool
-
config KEYBOARD_APPLESPI
tristate "Apple SPI keyboard and trackpad"
depends on ACPI && EFI
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index edc613efc158..fbdef95291e9 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -324,7 +324,7 @@ static ssize_t atkbd_show_function_row_physmap(struct atkbd *atkbd, char *buf)
static umode_t atkbd_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int i)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct serio *serio = to_serio_port(dev);
struct atkbd *atkbd = serio_get_drvdata(serio);
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index 38457d9641bd..fc02c540636e 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -644,7 +644,7 @@ static umode_t cros_ec_keyb_attr_is_visible(struct kobject *kobj,
struct attribute *attr,
int n)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
if (attr == &dev_attr_function_row_physmap.attr &&
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
index bb29a7c9a1c0..54afb38601b9 100644
--- a/drivers/input/keyboard/hil_kbd.c
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -512,6 +512,7 @@ static int hil_dev_connect(struct serio *serio, struct serio_driver *drv)
HIL_IDD_NUM_AXES_PER_SET(*idd)) {
printk(KERN_INFO PREFIX
"combo devices are not supported.\n");
+ error = -EINVAL;
goto bail1;
}
diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
index 81de8c4e37d0..6f38aa23a1ff 100644
--- a/drivers/input/misc/ims-pcu.c
+++ b/drivers/input/misc/ims-pcu.c
@@ -647,8 +647,8 @@ static int __ims_pcu_execute_command(struct ims_pcu *pcu,
#define IMS_PCU_BL_DATA_OFFSET 3
static int __ims_pcu_execute_bl_command(struct ims_pcu *pcu,
- u8 command, const void *data, size_t len,
- u8 expected_response, int response_time)
+ u8 command, const void *data, size_t len,
+ u8 expected_response, int response_time)
{
int error;
@@ -1228,7 +1228,7 @@ static struct attribute *ims_pcu_attrs[] = {
static umode_t ims_pcu_is_attr_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
umode_t mode = attr->mode;
diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c
index cf8104454e74..10e3fc0eac6e 100644
--- a/drivers/input/misc/pm8941-pwrkey.c
+++ b/drivers/input/misc/pm8941-pwrkey.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-2011, 2020-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2014, Sony Mobile Communications Inc.
*/
@@ -22,6 +22,8 @@
#define PON_RT_STS 0x10
#define PON_KPDPWR_N_SET BIT(0)
#define PON_RESIN_N_SET BIT(1)
+#define PON_GEN3_RESIN_N_SET BIT(6)
+#define PON_GEN3_KPDPWR_N_SET BIT(7)
#define PON_PS_HOLD_RST_CTL 0x5a
#define PON_PS_HOLD_RST_CTL2 0x5b
@@ -38,8 +40,12 @@
#define PON_DBC_DELAY_MASK 0x7
struct pm8941_data {
- unsigned int pull_up_bit;
- unsigned int status_bit;
+ unsigned int pull_up_bit;
+ unsigned int status_bit;
+ bool supports_ps_hold_poff_config;
+ bool supports_debounce_config;
+ const char *name;
+ const char *phys;
};
struct pm8941_pwrkey {
@@ -231,34 +237,40 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
input_set_capability(pwrkey->input, EV_KEY, pwrkey->code);
- pwrkey->input->name = "pm8941_pwrkey";
- pwrkey->input->phys = "pm8941_pwrkey/input0";
-
- req_delay = (req_delay << 6) / USEC_PER_SEC;
- req_delay = ilog2(req_delay);
-
- error = regmap_update_bits(pwrkey->regmap,
- pwrkey->baseaddr + PON_DBC_CTL,
- PON_DBC_DELAY_MASK,
- req_delay);
- if (error) {
- dev_err(&pdev->dev, "failed to set debounce: %d\n", error);
- return error;
+ pwrkey->input->name = pwrkey->data->name;
+ pwrkey->input->phys = pwrkey->data->phys;
+
+ if (pwrkey->data->supports_debounce_config) {
+ req_delay = (req_delay << 6) / USEC_PER_SEC;
+ req_delay = ilog2(req_delay);
+
+ error = regmap_update_bits(pwrkey->regmap,
+ pwrkey->baseaddr + PON_DBC_CTL,
+ PON_DBC_DELAY_MASK,
+ req_delay);
+ if (error) {
+ dev_err(&pdev->dev, "failed to set debounce: %d\n",
+ error);
+ return error;
+ }
}
- error = regmap_update_bits(pwrkey->regmap,
- pwrkey->baseaddr + PON_PULL_CTL,
- pwrkey->data->pull_up_bit,
- pull_up ? pwrkey->data->pull_up_bit : 0);
- if (error) {
- dev_err(&pdev->dev, "failed to set pull: %d\n", error);
- return error;
+ if (pwrkey->data->pull_up_bit) {
+ error = regmap_update_bits(pwrkey->regmap,
+ pwrkey->baseaddr + PON_PULL_CTL,
+ pwrkey->data->pull_up_bit,
+ pull_up ? pwrkey->data->pull_up_bit :
+ 0);
+ if (error) {
+ dev_err(&pdev->dev, "failed to set pull: %d\n", error);
+ return error;
+ }
}
error = devm_request_threaded_irq(&pdev->dev, pwrkey->irq,
NULL, pm8941_pwrkey_irq,
IRQF_ONESHOT,
- "pm8941_pwrkey", pwrkey);
+ pwrkey->data->name, pwrkey);
if (error) {
dev_err(&pdev->dev, "failed requesting IRQ: %d\n", error);
return error;
@@ -271,12 +283,14 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
return error;
}
- pwrkey->reboot_notifier.notifier_call = pm8941_reboot_notify,
- error = register_reboot_notifier(&pwrkey->reboot_notifier);
- if (error) {
- dev_err(&pdev->dev, "failed to register reboot notifier: %d\n",
- error);
- return error;
+ if (pwrkey->data->supports_ps_hold_poff_config) {
+ pwrkey->reboot_notifier.notifier_call = pm8941_reboot_notify,
+ error = register_reboot_notifier(&pwrkey->reboot_notifier);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register reboot notifier: %d\n",
+ error);
+ return error;
+ }
}
platform_set_drvdata(pdev, pwrkey);
@@ -289,7 +303,8 @@ static int pm8941_pwrkey_remove(struct platform_device *pdev)
{
struct pm8941_pwrkey *pwrkey = platform_get_drvdata(pdev);
- unregister_reboot_notifier(&pwrkey->reboot_notifier);
+ if (pwrkey->data->supports_ps_hold_poff_config)
+ unregister_reboot_notifier(&pwrkey->reboot_notifier);
return 0;
}
@@ -297,16 +312,42 @@ static int pm8941_pwrkey_remove(struct platform_device *pdev)
static const struct pm8941_data pwrkey_data = {
.pull_up_bit = PON_KPDPWR_PULL_UP,
.status_bit = PON_KPDPWR_N_SET,
+ .name = "pm8941_pwrkey",
+ .phys = "pm8941_pwrkey/input0",
+ .supports_ps_hold_poff_config = true,
+ .supports_debounce_config = true,
};
static const struct pm8941_data resin_data = {
.pull_up_bit = PON_RESIN_PULL_UP,
.status_bit = PON_RESIN_N_SET,
+ .name = "pm8941_resin",
+ .phys = "pm8941_resin/input0",
+ .supports_ps_hold_poff_config = true,
+ .supports_debounce_config = true,
+};
+
+static const struct pm8941_data pon_gen3_pwrkey_data = {
+ .status_bit = PON_GEN3_KPDPWR_N_SET,
+ .name = "pmic_pwrkey",
+ .phys = "pmic_pwrkey/input0",
+ .supports_ps_hold_poff_config = false,
+ .supports_debounce_config = false,
+};
+
+static const struct pm8941_data pon_gen3_resin_data = {
+ .status_bit = PON_GEN3_RESIN_N_SET,
+ .name = "pmic_resin",
+ .phys = "pmic_resin/input0",
+ .supports_ps_hold_poff_config = false,
+ .supports_debounce_config = false,
};
static const struct of_device_id pm8941_pwr_key_id_table[] = {
{ .compatible = "qcom,pm8941-pwrkey", .data = &pwrkey_data },
{ .compatible = "qcom,pm8941-resin", .data = &resin_data },
+ { .compatible = "qcom,pmk8350-pwrkey", .data = &pon_gen3_pwrkey_data },
+ { .compatible = "qcom,pmk8350-resin", .data = &pon_gen3_resin_data },
{ }
};
MODULE_DEVICE_TABLE(of, pm8941_pwr_key_id_table);
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index ef2fa0905208..4a86b3e31d3b 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -214,7 +214,7 @@ static bool trackpoint_is_attr_available(struct psmouse *psmouse,
static umode_t trackpoint_is_attr_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct serio *serio = to_serio_port(dev);
struct psmouse *psmouse = serio_get_drvdata(serio);
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index abae23af0791..0b9f1d0a8f8b 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -139,7 +139,7 @@ static DEFINE_SPINLOCK(i8042_lock);
/*
* Writers to AUX and KBD ports as well as users issuing i8042_command
* directly should acquire i8042_mutex (by means of calling
- * i8042_lock_chip() and i8042_unlock_ship() helpers) to ensure that
+ * i8042_lock_chip() and i8042_unlock_chip() helpers) to ensure that
* they do not disturb each other (unfortunately in many i8042
* implementations write to one of the ports will immediately abort
* command that is being processed by another port).
@@ -979,7 +979,7 @@ static int i8042_controller_selftest(void)
}
/*
- * i8042_controller init initializes the i8042 controller, and,
+ * i8042_controller_init initializes the i8042 controller, and,
* most importantly, sets it into non-xlated mode if that's
* desired.
*/
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 33e9d9bfd036..7fbbe00e3553 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -114,7 +114,8 @@ static void serport_ldisc_close(struct tty_struct *tty)
* 'interrupt' routine.
*/
-static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+static void serport_ldisc_receive(struct tty_struct *tty,
+ const unsigned char *cp, const char *fp, int count)
{
struct serport *serport = (struct serport*) tty->disc_data;
unsigned long flags;
@@ -273,6 +274,7 @@ static void serport_ldisc_write_wakeup(struct tty_struct * tty)
static struct tty_ldisc_ops serport_ldisc = {
.owner = THIS_MODULE,
+ .num = N_MOUSE,
.name = "input",
.open = serport_ldisc_open,
.close = serport_ldisc_close,
@@ -293,7 +295,7 @@ static struct tty_ldisc_ops serport_ldisc = {
static int __init serport_init(void)
{
int retval;
- retval = tty_register_ldisc(N_MOUSE, &serport_ldisc);
+ retval = tty_register_ldisc(&serport_ldisc);
if (retval)
printk(KERN_ERR "serport.c: Error registering line discipline.\n");
@@ -302,7 +304,7 @@ static int __init serport_init(void)
static void __exit serport_exit(void)
{
- tty_unregister_ldisc(N_MOUSE);
+ tty_unregister_ldisc(&serport_ldisc);
}
module_init(serport_init);
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c
index f465bae618fe..495ef156cf43 100644
--- a/drivers/input/touchscreen/cy8ctmg110_ts.c
+++ b/drivers/input/touchscreen/cy8ctmg110_ts.c
@@ -7,15 +7,14 @@
* Some cleanups by Alan Cox <alan@linux.intel.com>
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
+#include <linux/i2c.h>
#include <linux/input.h>
-#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/input/cy8ctmg110_pdata.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/byteorder.h>
#define CY8CTMG110_DRIVER_NAME "cy8ctmg110"
@@ -45,18 +44,18 @@ struct cy8ctmg110 {
struct input_dev *input;
char phys[32];
struct i2c_client *client;
- int reset_pin;
- int irq_pin;
+ struct gpio_desc *reset_gpio;
};
/*
* cy8ctmg110_power is the routine that is called when touch hardware
- * will powered off or on.
+ * is being powered off or on. When powering on this routine de-asserts
+ * the RESET line, when powering off reset line is asserted.
*/
static void cy8ctmg110_power(struct cy8ctmg110 *ts, bool poweron)
{
- if (ts->reset_pin)
- gpio_direction_output(ts->reset_pin, 1 - poweron);
+ if (ts->reset_gpio)
+ gpiod_set_value_cansleep(ts->reset_gpio, !poweron);
}
static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg,
@@ -112,7 +111,6 @@ static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc)
{
struct input_dev *input = tsc->input;
unsigned char reg_p[CY8CTMG110_REG_MAX];
- int x, y;
memset(reg_p, 0, CY8CTMG110_REG_MAX);
@@ -120,16 +118,15 @@ static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc)
if (cy8ctmg110_read_regs(tsc, reg_p, 9, CY8CTMG110_TOUCH_X1) != 0)
return -EIO;
- y = reg_p[2] << 8 | reg_p[3];
- x = reg_p[0] << 8 | reg_p[1];
-
/* Number of touch */
if (reg_p[8] == 0) {
input_report_key(input, BTN_TOUCH, 0);
} else {
input_report_key(input, BTN_TOUCH, 1);
- input_report_abs(input, ABS_X, x);
- input_report_abs(input, ABS_Y, y);
+ input_report_abs(input, ABS_X,
+ be16_to_cpup((__be16 *)(reg_p + 0)));
+ input_report_abs(input, ABS_Y,
+ be16_to_cpup((__be16 *)(reg_p + 2)));
}
input_sync(input);
@@ -163,35 +160,35 @@ static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void cy8ctmg110_shut_off(void *_ts)
+{
+ struct cy8ctmg110 *ts = _ts;
+
+ cy8ctmg110_set_sleepmode(ts, true);
+ cy8ctmg110_power(ts, false);
+}
+
static int cy8ctmg110_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- const struct cy8ctmg110_pdata *pdata = dev_get_platdata(&client->dev);
struct cy8ctmg110 *ts;
struct input_dev *input_dev;
int err;
- /* No pdata no way forward */
- if (pdata == NULL) {
- dev_err(&client->dev, "no pdata\n");
- return -ENODEV;
- }
-
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_WORD_DATA))
return -EIO;
- ts = kzalloc(sizeof(struct cy8ctmg110), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ts || !input_dev) {
- err = -ENOMEM;
- goto err_free_mem;
- }
+ ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ input_dev = devm_input_allocate_device(&client->dev);
+ if (!input_dev)
+ return -ENOMEM;
ts->client = client;
ts->input = input_dev;
- ts->reset_pin = pdata->reset_pin;
- ts->irq_pin = pdata->irq_pin;
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
@@ -199,84 +196,46 @@ static int cy8ctmg110_probe(struct i2c_client *client,
input_dev->name = CY8CTMG110_DRIVER_NAME " Touchscreen";
input_dev->phys = ts->phys;
input_dev->id.bustype = BUS_I2C;
- input_dev->dev.parent = &client->dev;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X,
CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 4, 0);
input_set_abs_params(input_dev, ABS_Y,
CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 4, 0);
- if (ts->reset_pin) {
- err = gpio_request(ts->reset_pin, NULL);
- if (err) {
- dev_err(&client->dev,
- "Unable to request GPIO pin %d.\n",
- ts->reset_pin);
- goto err_free_mem;
- }
+ /* Request and assert reset line */
+ ts->reset_gpio = devm_gpiod_get_optional(&client->dev, NULL,
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ts->reset_gpio)) {
+ err = PTR_ERR(ts->reset_gpio);
+ dev_err(&client->dev,
+ "Unable to request reset GPIO: %d\n", err);
+ return err;
}
cy8ctmg110_power(ts, true);
cy8ctmg110_set_sleepmode(ts, false);
- err = gpio_request(ts->irq_pin, "touch_irq_key");
- if (err < 0) {
- dev_err(&client->dev,
- "Failed to request GPIO %d, error %d\n",
- ts->irq_pin, err);
- goto err_shutoff_device;
- }
-
- err = gpio_direction_input(ts->irq_pin);
- if (err < 0) {
- dev_err(&client->dev,
- "Failed to configure input direction for GPIO %d, error %d\n",
- ts->irq_pin, err);
- goto err_free_irq_gpio;
- }
-
- client->irq = gpio_to_irq(ts->irq_pin);
- if (client->irq < 0) {
- err = client->irq;
- dev_err(&client->dev,
- "Unable to get irq number for GPIO %d, error %d\n",
- ts->irq_pin, err);
- goto err_free_irq_gpio;
- }
+ err = devm_add_action_or_reset(&client->dev, cy8ctmg110_shut_off, ts);
+ if (err)
+ return err;
- err = request_threaded_irq(client->irq, NULL, cy8ctmg110_irq_thread,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- "touch_reset_key", ts);
- if (err < 0) {
+ err = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, cy8ctmg110_irq_thread,
+ IRQF_ONESHOT, "touch_reset_key", ts);
+ if (err) {
dev_err(&client->dev,
"irq %d busy? error %d\n", client->irq, err);
- goto err_free_irq_gpio;
+ return err;
}
err = input_register_device(input_dev);
if (err)
- goto err_free_irq;
+ return err;
i2c_set_clientdata(client, ts);
- device_init_wakeup(&client->dev, 1);
- return 0;
-err_free_irq:
- free_irq(client->irq, ts);
-err_free_irq_gpio:
- gpio_free(ts->irq_pin);
-err_shutoff_device:
- cy8ctmg110_set_sleepmode(ts, true);
- cy8ctmg110_power(ts, false);
- if (ts->reset_pin)
- gpio_free(ts->reset_pin);
-err_free_mem:
- input_free_device(input_dev);
- kfree(ts);
- return err;
+ return 0;
}
static int __maybe_unused cy8ctmg110_suspend(struct device *dev)
@@ -284,12 +243,11 @@ static int __maybe_unused cy8ctmg110_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
- if (device_may_wakeup(&client->dev))
- enable_irq_wake(client->irq);
- else {
+ if (!device_may_wakeup(&client->dev)) {
cy8ctmg110_set_sleepmode(ts, true);
cy8ctmg110_power(ts, false);
}
+
return 0;
}
@@ -298,34 +256,16 @@ static int __maybe_unused cy8ctmg110_resume(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
- if (device_may_wakeup(&client->dev))
- disable_irq_wake(client->irq);
- else {
+ if (!device_may_wakeup(&client->dev)) {
cy8ctmg110_power(ts, true);
cy8ctmg110_set_sleepmode(ts, false);
}
+
return 0;
}
static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
-static int cy8ctmg110_remove(struct i2c_client *client)
-{
- struct cy8ctmg110 *ts = i2c_get_clientdata(client);
-
- cy8ctmg110_set_sleepmode(ts, true);
- cy8ctmg110_power(ts, false);
-
- free_irq(client->irq, ts);
- input_unregister_device(ts->input);
- gpio_free(ts->irq_pin);
- if (ts->reset_pin)
- gpio_free(ts->reset_pin);
- kfree(ts);
-
- return 0;
-}
-
static const struct i2c_device_id cy8ctmg110_idtable[] = {
{ CY8CTMG110_DRIVER_NAME, 1 },
{ }
@@ -340,7 +280,6 @@ static struct i2c_driver cy8ctmg110_driver = {
},
.id_table = cy8ctmg110_idtable,
.probe = cy8ctmg110_probe,
- .remove = cy8ctmg110_remove,
};
module_i2c_driver(cy8ctmg110_driver);
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
index 106dd4962785..1dbd849c9613 100644
--- a/drivers/input/touchscreen/cyttsp_core.c
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/property.h>
#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
#include "cyttsp_core.h"
@@ -45,8 +46,15 @@
#define CY_MAXZ 255
#define CY_DELAY_DFLT 20 /* ms */
#define CY_DELAY_MAX 500
-#define CY_ACT_DIST_DFLT 0xF8
+/* Active distance in pixels for a gesture to be reported */
+#define CY_ACT_DIST_DFLT 0xF8 /* pixels */
#define CY_ACT_DIST_MASK 0x0F
+/* Active Power state scanning/processing refresh interval */
+#define CY_ACT_INTRVL_DFLT 0x00 /* ms */
+/* Low Power state scanning/processing refresh interval */
+#define CY_LP_INTRVL_DFLT 0x0A /* ms */
+/* touch timeout for the Active power */
+#define CY_TCH_TMOUT_DFLT 0xFF /* ms */
#define CY_HNDSHK_BIT 0x80
/* device mode bits */
#define CY_OPERATE_MODE 0x00
@@ -608,6 +616,14 @@ static int cyttsp_parse_properties(struct cyttsp *ts)
return 0;
}
+static void cyttsp_disable_regulators(void *_ts)
+{
+ struct cyttsp *ts = _ts;
+
+ regulator_bulk_disable(ARRAY_SIZE(ts->regulators),
+ ts->regulators);
+}
+
struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
struct device *dev, int irq, size_t xfer_buf_size)
{
@@ -628,6 +644,32 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
ts->bus_ops = bus_ops;
ts->irq = irq;
+ /*
+ * VCPIN is the analog voltage supply
+ * VDD is the digital voltage supply
+ */
+ ts->regulators[0].supply = "vcpin";
+ ts->regulators[1].supply = "vdd";
+ error = devm_regulator_bulk_get(dev, ARRAY_SIZE(ts->regulators),
+ ts->regulators);
+ if (error) {
+ dev_err(dev, "Failed to get regulators: %d\n", error);
+ return ERR_PTR(error);
+ }
+
+ error = regulator_bulk_enable(ARRAY_SIZE(ts->regulators),
+ ts->regulators);
+ if (error) {
+ dev_err(dev, "Cannot enable regulators: %d\n", error);
+ return ERR_PTR(error);
+ }
+
+ error = devm_add_action_or_reset(dev, cyttsp_disable_regulators, ts);
+ if (error) {
+ dev_err(dev, "failed to install chip disable handler\n");
+ return ERR_PTR(error);
+ }
+
ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ts->reset_gpio)) {
error = PTR_ERR(ts->reset_gpio);
@@ -664,8 +706,7 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
}
error = devm_request_threaded_irq(dev, ts->irq, NULL, cyttsp_irq,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
- IRQF_NO_AUTOEN,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN,
"cyttsp", ts);
if (error) {
dev_err(ts->dev, "failed to request IRQ %d, err: %d\n",
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h
index 9bc4fe7e6ac5..075509e695a2 100644
--- a/drivers/input/touchscreen/cyttsp_core.h
+++ b/drivers/input/touchscreen/cyttsp_core.h
@@ -22,7 +22,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/device.h>
-#include <linux/input/cyttsp.h>
+#include <linux/regulator/consumer.h>
#define CY_NUM_RETRY 16 /* max number of retries for read ops */
@@ -122,6 +122,7 @@ struct cyttsp {
enum cyttsp_state state;
bool suspended;
+ struct regulator_bulk_data regulators[2];
struct gpio_desc *reset_gpio;
bool use_hndshk;
u8 act_dist;
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c
index 061debf64a2b..4c8473d327ab 100644
--- a/drivers/input/touchscreen/cyttsp_i2c.c
+++ b/drivers/input/touchscreen/cyttsp_i2c.c
@@ -18,6 +18,8 @@
#include <linux/i2c.h>
#include <linux/input.h>
+#define CY_I2C_NAME "cyttsp-i2c"
+
#define CY_I2C_DATA_SIZE 128
static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = {
@@ -52,10 +54,18 @@ static const struct i2c_device_id cyttsp_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
+static const struct of_device_id cyttsp_of_i2c_match[] = {
+ { .compatible = "cypress,cy8ctma340", },
+ { .compatible = "cypress,cy8ctst341", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cyttsp_of_i2c_match);
+
static struct i2c_driver cyttsp_i2c_driver = {
.driver = {
.name = CY_I2C_NAME,
.pm = &cyttsp_pm_ops,
+ .of_match_table = cyttsp_of_i2c_match,
},
.probe = cyttsp_i2c_probe,
.id_table = cyttsp_i2c_id,
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
index 54e410921d53..30c6fbf86a86 100644
--- a/drivers/input/touchscreen/cyttsp_spi.c
+++ b/drivers/input/touchscreen/cyttsp_spi.c
@@ -20,6 +20,8 @@
#include <linux/input.h>
#include <linux/spi/spi.h>
+#define CY_SPI_NAME "cyttsp-spi"
+
#define CY_SPI_WR_OP 0x00 /* r/~w */
#define CY_SPI_RD_OP 0x01
#define CY_SPI_CMD_BYTES 4
@@ -160,10 +162,18 @@ static int cyttsp_spi_probe(struct spi_device *spi)
return 0;
}
+static const struct of_device_id cyttsp_of_spi_match[] = {
+ { .compatible = "cypress,cy8ctma340", },
+ { .compatible = "cypress,cy8ctst341", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cyttsp_of_spi_match);
+
static struct spi_driver cyttsp_spi_driver = {
.driver = {
.name = CY_SPI_NAME,
.pm = &cyttsp_pm_ops,
+ .of_match_table = cyttsp_of_spi_match,
},
.probe = cyttsp_spi_probe,
};
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 2eefbc2485bc..263de3bfb6cd 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -104,6 +104,7 @@ struct edt_ft5x06_ts_data {
u16 num_x;
u16 num_y;
struct regulator *vcc;
+ struct regulator *iovcc;
struct gpio_desc *reset_gpio;
struct gpio_desc *wake_gpio;
@@ -1062,11 +1063,12 @@ static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
}
}
-static void edt_ft5x06_disable_regulator(void *arg)
+static void edt_ft5x06_disable_regulators(void *arg)
{
struct edt_ft5x06_ts_data *data = arg;
regulator_disable(data->vcc);
+ regulator_disable(data->iovcc);
}
static int edt_ft5x06_ts_probe(struct i2c_client *client,
@@ -1107,14 +1109,33 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
return error;
}
+ tsdata->iovcc = devm_regulator_get(&client->dev, "iovcc");
+ if (IS_ERR(tsdata->iovcc)) {
+ error = PTR_ERR(tsdata->iovcc);
+ if (error != -EPROBE_DEFER)
+ dev_err(&client->dev,
+ "failed to request iovcc regulator: %d\n", error);
+ return error;
+ }
+
+ error = regulator_enable(tsdata->iovcc);
+ if (error < 0) {
+ dev_err(&client->dev, "failed to enable iovcc: %d\n", error);
+ return error;
+ }
+
+ /* Delay enabling VCC for > 10us (T_ivd) after IOVCC */
+ usleep_range(10, 100);
+
error = regulator_enable(tsdata->vcc);
if (error < 0) {
dev_err(&client->dev, "failed to enable vcc: %d\n", error);
+ regulator_disable(tsdata->iovcc);
return error;
}
error = devm_add_action_or_reset(&client->dev,
- edt_ft5x06_disable_regulator,
+ edt_ft5x06_disable_regulators,
tsdata);
if (error)
return error;
@@ -1289,6 +1310,9 @@ static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev)
ret = regulator_disable(tsdata->vcc);
if (ret)
dev_warn(dev, "Failed to disable vcc\n");
+ ret = regulator_disable(tsdata->iovcc);
+ if (ret)
+ dev_warn(dev, "Failed to disable iovcc\n");
return 0;
}
@@ -1319,9 +1343,19 @@ static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev)
gpiod_set_value_cansleep(reset_gpio, 1);
usleep_range(5000, 6000);
+ ret = regulator_enable(tsdata->iovcc);
+ if (ret) {
+ dev_err(dev, "Failed to enable iovcc\n");
+ return ret;
+ }
+
+ /* Delay enabling VCC for > 10us (T_ivd) after IOVCC */
+ usleep_range(10, 100);
+
ret = regulator_enable(tsdata->vcc);
if (ret) {
dev_err(dev, "Failed to enable vcc\n");
+ regulator_disable(tsdata->iovcc);
return ret;
}
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c
index 17540bdb1eaf..68f542bb809f 100644
--- a/drivers/input/touchscreen/elants_i2c.c
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -1369,8 +1369,7 @@ static bool elants_acpi_is_hid_device(struct device *dev)
}
#endif
-static int elants_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int elants_i2c_probe(struct i2c_client *client)
{
union i2c_smbus_data dummy;
struct elants_data *ts;
@@ -1396,7 +1395,7 @@ static int elants_i2c_probe(struct i2c_client *client,
init_completion(&ts->cmd_done);
ts->client = client;
- ts->chip_id = (enum elants_chip_id)id->driver_data;
+ ts->chip_id = (enum elants_chip_id)(uintptr_t)device_get_match_data(&client->dev);
i2c_set_clientdata(client, ts);
ts->vcc33 = devm_regulator_get(&client->dev, "vcc33");
@@ -1636,15 +1635,15 @@ MODULE_DEVICE_TABLE(acpi, elants_acpi_id);
#ifdef CONFIG_OF
static const struct of_device_id elants_of_match[] = {
- { .compatible = "elan,ekth3500" },
- { .compatible = "elan,ektf3624" },
+ { .compatible = "elan,ekth3500", .data = (void *)EKTH3500 },
+ { .compatible = "elan,ektf3624", .data = (void *)EKTF3624 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, elants_of_match);
#endif
static struct i2c_driver elants_i2c_driver = {
- .probe = elants_i2c_probe,
+ .probe_new = elants_i2c_probe,
.id_table = elants_i2c_id,
.driver = {
.name = DEVICE_NAME,
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index c682b028f0a2..4f53d3c57e69 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -178,51 +178,6 @@ static const unsigned long goodix_irq_flags[] = {
IRQ_TYPE_LEVEL_HIGH,
};
-/*
- * Those tablets have their coordinates origin at the bottom right
- * of the tablet, as if rotated 180 degrees
- */
-static const struct dmi_system_id rotated_screen[] = {
-#if defined(CONFIG_DMI) && defined(CONFIG_X86)
- {
- .ident = "Teclast X89",
- .matches = {
- /* tPAD is too generic, also match on bios date */
- DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
- DMI_MATCH(DMI_BOARD_NAME, "tPAD"),
- DMI_MATCH(DMI_BIOS_DATE, "12/19/2014"),
- },
- },
- {
- .ident = "Teclast X98 Pro",
- .matches = {
- /*
- * Only match BIOS date, because the manufacturers
- * BIOS does not report the board name at all
- * (sometimes)...
- */
- DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
- DMI_MATCH(DMI_BIOS_DATE, "10/28/2015"),
- },
- },
- {
- .ident = "WinBook TW100",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
- DMI_MATCH(DMI_PRODUCT_NAME, "TW100")
- }
- },
- {
- .ident = "WinBook TW700",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
- DMI_MATCH(DMI_PRODUCT_NAME, "TW700")
- },
- },
-#endif
- {}
-};
-
static const struct dmi_system_id nine_bytes_report[] = {
#if defined(CONFIG_DMI) && defined(CONFIG_X86)
{
@@ -1123,13 +1078,6 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
ABS_MT_POSITION_Y, ts->prop.max_y);
}
- if (dmi_check_system(rotated_screen)) {
- ts->prop.invert_x = true;
- ts->prop.invert_y = true;
- dev_dbg(&ts->client->dev,
- "Applying '180 degrees rotated screen' quirk\n");
- }
-
if (dmi_check_system(nine_bytes_report)) {
ts->contact_size = 9;
diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c
index ddad4a82a5e5..e9547ee29756 100644
--- a/drivers/input/touchscreen/hideep.c
+++ b/drivers/input/touchscreen/hideep.c
@@ -361,13 +361,16 @@ static int hideep_enter_pgm(struct hideep_ts *ts)
return -EIO;
}
-static void hideep_nvm_unlock(struct hideep_ts *ts)
+static int hideep_nvm_unlock(struct hideep_ts *ts)
{
u32 unmask_code;
+ int error;
hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_SFR_RPAGE);
- hideep_pgm_r_reg(ts, 0x0000000C, &unmask_code);
+ error = hideep_pgm_r_reg(ts, 0x0000000C, &unmask_code);
hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_DEFAULT_PAGE);
+ if (error)
+ return error;
/* make it unprotected code */
unmask_code &= ~HIDEEP_PROT_MODE;
@@ -384,6 +387,8 @@ static void hideep_nvm_unlock(struct hideep_ts *ts)
NVM_W_SFR(HIDEEP_NVM_MASK_OFS, ts->nvm_mask);
SET_FLASH_HWCONTROL();
hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_DEFAULT_PAGE);
+
+ return 0;
}
static int hideep_check_status(struct hideep_ts *ts)
@@ -462,7 +467,9 @@ static int hideep_program_nvm(struct hideep_ts *ts,
u32 addr = 0;
int error;
- hideep_nvm_unlock(ts);
+ error = hideep_nvm_unlock(ts);
+ if (error)
+ return error;
while (ucode_len > 0) {
xfer_len = min_t(size_t, ucode_len, HIDEEP_NVM_PAGE_SIZE);
diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c
index e50af30183f4..744544a723b7 100644
--- a/drivers/input/touchscreen/resistive-adc-touch.c
+++ b/drivers/input/touchscreen/resistive-adc-touch.c
@@ -13,44 +13,78 @@
#include <linux/input/touchscreen.h>
#include <linux/iio/consumer.h>
#include <linux/iio/iio.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#define DRIVER_NAME "resistive-adc-touch"
#define GRTS_DEFAULT_PRESSURE_MIN 50000
+#define GRTS_DEFAULT_PRESSURE_MAX 65535
#define GRTS_MAX_POS_MASK GENMASK(11, 0)
+#define GRTS_MAX_CHANNELS 4
+
+enum grts_ch_type {
+ GRTS_CH_X,
+ GRTS_CH_Y,
+ GRTS_CH_PRESSURE,
+ GRTS_CH_Z1,
+ GRTS_CH_Z2,
+ GRTS_CH_MAX = GRTS_CH_Z2 + 1
+};
/**
* struct grts_state - generic resistive touch screen information struct
+ * @x_plate_ohms: resistance of the X plate
* @pressure_min: number representing the minimum for the pressure
* @pressure: are we getting pressure info or not
* @iio_chans: list of channels acquired
* @iio_cb: iio_callback buffer for the data
* @input: the input device structure that we register
* @prop: touchscreen properties struct
+ * @ch_map: map of channels that are defined for the touchscreen
*/
struct grts_state {
+ u32 x_plate_ohms;
u32 pressure_min;
bool pressure;
struct iio_channel *iio_chans;
struct iio_cb_buffer *iio_cb;
struct input_dev *input;
struct touchscreen_properties prop;
+ u8 ch_map[GRTS_CH_MAX];
};
static int grts_cb(const void *data, void *private)
{
const u16 *touch_info = data;
struct grts_state *st = private;
- unsigned int x, y, press = 0x0;
-
- /* channel data coming in buffer in the order below */
- x = touch_info[0];
- y = touch_info[1];
- if (st->pressure)
- press = touch_info[2];
+ unsigned int x, y, press = 0;
+
+ x = touch_info[st->ch_map[GRTS_CH_X]];
+ y = touch_info[st->ch_map[GRTS_CH_Y]];
+
+ if (st->ch_map[GRTS_CH_PRESSURE] < GRTS_MAX_CHANNELS) {
+ press = touch_info[st->ch_map[GRTS_CH_PRESSURE]];
+ } else if (st->ch_map[GRTS_CH_Z1] < GRTS_MAX_CHANNELS) {
+ unsigned int z1 = touch_info[st->ch_map[GRTS_CH_Z1]];
+ unsigned int z2 = touch_info[st->ch_map[GRTS_CH_Z2]];
+ unsigned int Rt;
+
+ Rt = z2;
+ Rt -= z1;
+ Rt *= st->x_plate_ohms;
+ Rt = DIV_ROUND_CLOSEST(Rt, 16);
+ Rt *= x;
+ Rt /= z1;
+ Rt = DIV_ROUND_CLOSEST(Rt, 256);
+ /*
+ * On increased pressure the resistance (Rt) is decreasing
+ * so, convert values to make it looks as real pressure.
+ */
+ if (Rt < GRTS_DEFAULT_PRESSURE_MAX)
+ press = GRTS_DEFAULT_PRESSURE_MAX - Rt;
+ }
if ((!x && !y) || (st->pressure && (press < st->pressure_min))) {
/* report end of touch */
@@ -94,12 +128,77 @@ static void grts_disable(void *data)
iio_channel_release_all_cb(data);
}
+static int grts_map_channel(struct grts_state *st, struct device *dev,
+ enum grts_ch_type type, const char *name,
+ bool optional)
+{
+ int idx;
+
+ idx = device_property_match_string(dev, "io-channel-names", name);
+ if (idx < 0) {
+ if (!optional)
+ return idx;
+ idx = GRTS_MAX_CHANNELS;
+ } else if (idx >= GRTS_MAX_CHANNELS) {
+ return -EOVERFLOW;
+ }
+
+ st->ch_map[type] = idx;
+ return 0;
+}
+
+static int grts_get_properties(struct grts_state *st, struct device *dev)
+{
+ int error;
+
+ error = grts_map_channel(st, dev, GRTS_CH_X, "x", false);
+ if (error)
+ return error;
+
+ error = grts_map_channel(st, dev, GRTS_CH_Y, "y", false);
+ if (error)
+ return error;
+
+ /* pressure is optional */
+ error = grts_map_channel(st, dev, GRTS_CH_PRESSURE, "pressure", true);
+ if (error)
+ return error;
+
+ if (st->ch_map[GRTS_CH_PRESSURE] < GRTS_MAX_CHANNELS) {
+ st->pressure = true;
+ return 0;
+ }
+
+ /* if no pressure is defined, try optional z1 + z2 */
+ error = grts_map_channel(st, dev, GRTS_CH_Z1, "z1", true);
+ if (error)
+ return error;
+
+ if (st->ch_map[GRTS_CH_Z1] >= GRTS_MAX_CHANNELS)
+ return 0;
+
+ /* if z1 is provided z2 is not optional */
+ error = grts_map_channel(st, dev, GRTS_CH_Z2, "z2", true);
+ if (error)
+ return error;
+
+ error = device_property_read_u32(dev,
+ "touchscreen-x-plate-ohms",
+ &st->x_plate_ohms);
+ if (error) {
+ dev_err(dev, "can't get touchscreen-x-plate-ohms property\n");
+ return error;
+ }
+
+ st->pressure = true;
+ return 0;
+}
+
static int grts_probe(struct platform_device *pdev)
{
struct grts_state *st;
struct input_dev *input;
struct device *dev = &pdev->dev;
- struct iio_channel *chan;
int error;
st = devm_kzalloc(dev, sizeof(struct grts_state), GFP_KERNEL);
@@ -115,12 +214,13 @@ static int grts_probe(struct platform_device *pdev)
return error;
}
- chan = &st->iio_chans[0];
- st->pressure = false;
- while (chan && chan->indio_dev) {
- if (!strcmp(chan->channel->datasheet_name, "pressure"))
- st->pressure = true;
- chan++;
+ if (!device_property_present(dev, "io-channel-names"))
+ return -ENODEV;
+
+ error = grts_get_properties(st, dev);
+ if (error) {
+ dev_err(dev, "Failed to parse properties\n");
+ return error;
}
if (st->pressure) {
@@ -148,7 +248,7 @@ static int grts_probe(struct platform_device *pdev)
input_set_abs_params(input, ABS_Y, 0, GRTS_MAX_POS_MASK - 1, 0, 0);
if (st->pressure)
input_set_abs_params(input, ABS_PRESSURE, st->pressure_min,
- 0xffff, 0, 0);
+ GRTS_DEFAULT_PRESSURE_MAX, 0, 0);
input_set_capability(input, EV_KEY, BTN_TOUCH);
@@ -193,7 +293,7 @@ static struct platform_driver grts_driver = {
.probe = grts_probe,
.driver = {
.name = DRIVER_NAME,
- .of_match_table = of_match_ptr(grts_of_match),
+ .of_match_table = grts_of_match,
},
};
diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c
index ce2fe30d6b8a..b8d720d52013 100644
--- a/drivers/input/touchscreen/tsc200x-core.c
+++ b/drivers/input/touchscreen/tsc200x-core.c
@@ -338,7 +338,7 @@ static struct attribute *tsc200x_attrs[] = {
static umode_t tsc200x_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct tsc200x *ts = dev_get_drvdata(dev);
umode_t mode = attr->mode;
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index c847453a03c2..43c521f50c85 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -251,7 +251,7 @@ static int e2i_init(struct usbtouch_usb *usbtouch)
int ret;
struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
- ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x01, 0x02, 0x0000, 0x0081,
NULL, 0, USB_CTRL_SET_TIMEOUT);
@@ -531,7 +531,7 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
if (ret)
return ret;
- ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
MTOUCHUSB_RESET,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
@@ -543,7 +543,7 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
msleep(150);
for (i = 0; i < 3; i++) {
- ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
MTOUCHUSB_ASYNC_REPORT,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
@@ -722,7 +722,7 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
}
/* start sending data */
- ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
TSC10_CMD_DATA1,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig
index cdb3e11462c6..0d7a2500d0b8 100644
--- a/drivers/interconnect/qcom/Kconfig
+++ b/drivers/interconnect/qcom/Kconfig
@@ -74,6 +74,15 @@ config INTERCONNECT_QCOM_SC7180
This is a driver for the Qualcomm Network-on-Chip on sc7180-based
platforms.
+config INTERCONNECT_QCOM_SC7280
+ tristate "Qualcomm SC7280 interconnect driver"
+ depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
+ select INTERCONNECT_QCOM_RPMH
+ select INTERCONNECT_QCOM_BCM_VOTER
+ help
+ This is a driver for the Qualcomm Network-on-Chip on sc7280-based
+ platforms.
+
config INTERCONNECT_QCOM_SDM660
tristate "Qualcomm SDM660 interconnect driver"
depends on INTERCONNECT_QCOM
diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile
index 46fc62447156..2880129a6fe4 100644
--- a/drivers/interconnect/qcom/Makefile
+++ b/drivers/interconnect/qcom/Makefile
@@ -8,6 +8,7 @@ icc-osm-l3-objs := osm-l3.o
qnoc-qcs404-objs := qcs404.o
icc-rpmh-obj := icc-rpmh.o
qnoc-sc7180-objs := sc7180.o
+qnoc-sc7280-objs := sc7280.o
qnoc-sdm660-objs := sdm660.o
qnoc-sdm845-objs := sdm845.o
qnoc-sdx55-objs := sdx55.o
@@ -24,6 +25,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_OSM_L3) += icc-osm-l3.o
obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o
obj-$(CONFIG_INTERCONNECT_QCOM_RPMH) += icc-rpmh.o
obj-$(CONFIG_INTERCONNECT_QCOM_SC7180) += qnoc-sc7180.o
+obj-$(CONFIG_INTERCONNECT_QCOM_SC7280) += qnoc-sc7280.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDM660) += qnoc-sdm660.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDX55) += qnoc-sdx55.o
diff --git a/drivers/interconnect/qcom/sc7280.c b/drivers/interconnect/qcom/sc7280.c
new file mode 100644
index 000000000000..8d1b55c3705c
--- /dev/null
+++ b/drivers/interconnect/qcom/sc7280.c
@@ -0,0 +1,1938 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/interconnect.h>
+#include <linux/interconnect-provider.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <dt-bindings/interconnect/qcom,sc7280.h>
+
+#include "bcm-voter.h"
+#include "icc-rpmh.h"
+#include "sc7280.h"
+
+static struct qcom_icc_node qhm_qspi = {
+ .name = "qhm_qspi",
+ .id = SC7280_MASTER_QSPI_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node qhm_qup0 = {
+ .name = "qhm_qup0",
+ .id = SC7280_MASTER_QUP_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node qhm_qup1 = {
+ .name = "qhm_qup1",
+ .id = SC7280_MASTER_QUP_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node qnm_a1noc_cfg = {
+ .name = "qnm_a1noc_cfg",
+ .id = SC7280_MASTER_A1NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_SERVICE_A1NOC },
+};
+
+static struct qcom_icc_node xm_sdc1 = {
+ .name = "xm_sdc1",
+ .id = SC7280_MASTER_SDCC_1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_sdc2 = {
+ .name = "xm_sdc2",
+ .id = SC7280_MASTER_SDCC_2,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_sdc4 = {
+ .name = "xm_sdc4",
+ .id = SC7280_MASTER_SDCC_4,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_ufs_mem = {
+ .name = "xm_ufs_mem",
+ .id = SC7280_MASTER_UFS_MEM,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_usb2 = {
+ .name = "xm_usb2",
+ .id = SC7280_MASTER_USB2,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_usb3_0 = {
+ .name = "xm_usb3_0",
+ .id = SC7280_MASTER_USB3_0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node qhm_qdss_bam = {
+ .name = "qhm_qdss_bam",
+ .id = SC7280_MASTER_QDSS_BAM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qnm_a2noc_cfg = {
+ .name = "qnm_a2noc_cfg",
+ .id = SC7280_MASTER_A2NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_SERVICE_A2NOC },
+};
+
+static struct qcom_icc_node qnm_cnoc_datapath = {
+ .name = "qnm_cnoc_datapath",
+ .id = SC7280_MASTER_CNOC_A2NOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qxm_crypto = {
+ .name = "qxm_crypto",
+ .id = SC7280_MASTER_CRYPTO,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qxm_ipa = {
+ .name = "qxm_ipa",
+ .id = SC7280_MASTER_IPA,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_pcie3_0 = {
+ .name = "xm_pcie3_0",
+ .id = SC7280_MASTER_PCIE_0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node xm_pcie3_1 = {
+ .name = "xm_pcie3_1",
+ .id = SC7280_MASTER_PCIE_1,
+ .channels = 1,
+ .buswidth = 8,
+ .links = { SC7280_SLAVE_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node xm_qdss_etr = {
+ .name = "xm_qdss_etr",
+ .id = SC7280_MASTER_QDSS_ETR,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qup0_core_master = {
+ .name = "qup0_core_master",
+ .id = SC7280_MASTER_QUP_CORE_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_QUP_CORE_0 },
+};
+
+static struct qcom_icc_node qup1_core_master = {
+ .name = "qup1_core_master",
+ .id = SC7280_MASTER_QUP_CORE_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_QUP_CORE_1 },
+};
+
+static struct qcom_icc_node qnm_cnoc3_cnoc2 = {
+ .name = "qnm_cnoc3_cnoc2",
+ .id = SC7280_MASTER_CNOC3_CNOC2,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 44,
+ .links = { SC7280_SLAVE_AHB2PHY_SOUTH, SC7280_SLAVE_AHB2PHY_NORTH,
+ SC7280_SLAVE_CAMERA_CFG, SC7280_SLAVE_CLK_CTL,
+ SC7280_SLAVE_CDSP_CFG, SC7280_SLAVE_RBCPR_CX_CFG,
+ SC7280_SLAVE_RBCPR_MX_CFG, SC7280_SLAVE_CRYPTO_0_CFG,
+ SC7280_SLAVE_CX_RDPM, SC7280_SLAVE_DCC_CFG,
+ SC7280_SLAVE_DISPLAY_CFG, SC7280_SLAVE_GFX3D_CFG,
+ SC7280_SLAVE_HWKM, SC7280_SLAVE_IMEM_CFG,
+ SC7280_SLAVE_IPA_CFG, SC7280_SLAVE_IPC_ROUTER_CFG,
+ SC7280_SLAVE_LPASS, SC7280_SLAVE_CNOC_MSS,
+ SC7280_SLAVE_MX_RDPM, SC7280_SLAVE_PCIE_0_CFG,
+ SC7280_SLAVE_PCIE_1_CFG, SC7280_SLAVE_PDM,
+ SC7280_SLAVE_PIMEM_CFG, SC7280_SLAVE_PKA_WRAPPER_CFG,
+ SC7280_SLAVE_PMU_WRAPPER_CFG, SC7280_SLAVE_QDSS_CFG,
+ SC7280_SLAVE_QSPI_0, SC7280_SLAVE_QUP_0,
+ SC7280_SLAVE_QUP_1, SC7280_SLAVE_SDCC_1,
+ SC7280_SLAVE_SDCC_2, SC7280_SLAVE_SDCC_4,
+ SC7280_SLAVE_SECURITY, SC7280_SLAVE_TCSR,
+ SC7280_SLAVE_TLMM, SC7280_SLAVE_UFS_MEM_CFG,
+ SC7280_SLAVE_USB2, SC7280_SLAVE_USB3_0,
+ SC7280_SLAVE_VENUS_CFG, SC7280_SLAVE_VSENSE_CTRL_CFG,
+ SC7280_SLAVE_A1NOC_CFG, SC7280_SLAVE_A2NOC_CFG,
+ SC7280_SLAVE_CNOC_MNOC_CFG, SC7280_SLAVE_SNOC_CFG },
+};
+
+static struct qcom_icc_node xm_qdss_dap = {
+ .name = "xm_qdss_dap",
+ .id = SC7280_MASTER_QDSS_DAP,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 45,
+ .links = { SC7280_SLAVE_AHB2PHY_SOUTH, SC7280_SLAVE_AHB2PHY_NORTH,
+ SC7280_SLAVE_CAMERA_CFG, SC7280_SLAVE_CLK_CTL,
+ SC7280_SLAVE_CDSP_CFG, SC7280_SLAVE_RBCPR_CX_CFG,
+ SC7280_SLAVE_RBCPR_MX_CFG, SC7280_SLAVE_CRYPTO_0_CFG,
+ SC7280_SLAVE_CX_RDPM, SC7280_SLAVE_DCC_CFG,
+ SC7280_SLAVE_DISPLAY_CFG, SC7280_SLAVE_GFX3D_CFG,
+ SC7280_SLAVE_HWKM, SC7280_SLAVE_IMEM_CFG,
+ SC7280_SLAVE_IPA_CFG, SC7280_SLAVE_IPC_ROUTER_CFG,
+ SC7280_SLAVE_LPASS, SC7280_SLAVE_CNOC_MSS,
+ SC7280_SLAVE_MX_RDPM, SC7280_SLAVE_PCIE_0_CFG,
+ SC7280_SLAVE_PCIE_1_CFG, SC7280_SLAVE_PDM,
+ SC7280_SLAVE_PIMEM_CFG, SC7280_SLAVE_PKA_WRAPPER_CFG,
+ SC7280_SLAVE_PMU_WRAPPER_CFG, SC7280_SLAVE_QDSS_CFG,
+ SC7280_SLAVE_QSPI_0, SC7280_SLAVE_QUP_0,
+ SC7280_SLAVE_QUP_1, SC7280_SLAVE_SDCC_1,
+ SC7280_SLAVE_SDCC_2, SC7280_SLAVE_SDCC_4,
+ SC7280_SLAVE_SECURITY, SC7280_SLAVE_TCSR,
+ SC7280_SLAVE_TLMM, SC7280_SLAVE_UFS_MEM_CFG,
+ SC7280_SLAVE_USB2, SC7280_SLAVE_USB3_0,
+ SC7280_SLAVE_VENUS_CFG, SC7280_SLAVE_VSENSE_CTRL_CFG,
+ SC7280_SLAVE_A1NOC_CFG, SC7280_SLAVE_A2NOC_CFG,
+ SC7280_SLAVE_CNOC2_CNOC3, SC7280_SLAVE_CNOC_MNOC_CFG,
+ SC7280_SLAVE_SNOC_CFG },
+};
+
+static struct qcom_icc_node qnm_cnoc2_cnoc3 = {
+ .name = "qnm_cnoc2_cnoc3",
+ .id = SC7280_MASTER_CNOC2_CNOC3,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 9,
+ .links = { SC7280_SLAVE_AOSS, SC7280_SLAVE_APPSS,
+ SC7280_SLAVE_CNOC_A2NOC, SC7280_SLAVE_DDRSS_CFG,
+ SC7280_SLAVE_BOOT_IMEM, SC7280_SLAVE_IMEM,
+ SC7280_SLAVE_PIMEM, SC7280_SLAVE_QDSS_STM,
+ SC7280_SLAVE_TCU },
+};
+
+static struct qcom_icc_node qnm_gemnoc_cnoc = {
+ .name = "qnm_gemnoc_cnoc",
+ .id = SC7280_MASTER_GEM_NOC_CNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 9,
+ .links = { SC7280_SLAVE_AOSS, SC7280_SLAVE_APPSS,
+ SC7280_SLAVE_CNOC3_CNOC2, SC7280_SLAVE_DDRSS_CFG,
+ SC7280_SLAVE_BOOT_IMEM, SC7280_SLAVE_IMEM,
+ SC7280_SLAVE_PIMEM, SC7280_SLAVE_QDSS_STM,
+ SC7280_SLAVE_TCU },
+};
+
+static struct qcom_icc_node qnm_gemnoc_pcie = {
+ .name = "qnm_gemnoc_pcie",
+ .id = SC7280_MASTER_GEM_NOC_PCIE_SNOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { SC7280_SLAVE_PCIE_0, SC7280_SLAVE_PCIE_1 },
+};
+
+static struct qcom_icc_node qnm_cnoc_dc_noc = {
+ .name = "qnm_cnoc_dc_noc",
+ .id = SC7280_MASTER_CNOC_DC_NOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 2,
+ .links = { SC7280_SLAVE_LLCC_CFG, SC7280_SLAVE_GEM_NOC_CFG },
+};
+
+static struct qcom_icc_node alm_gpu_tcu = {
+ .name = "alm_gpu_tcu",
+ .id = SC7280_MASTER_GPU_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { SC7280_SLAVE_GEM_NOC_CNOC, SC7280_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node alm_sys_tcu = {
+ .name = "alm_sys_tcu",
+ .id = SC7280_MASTER_SYS_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { SC7280_SLAVE_GEM_NOC_CNOC, SC7280_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node chm_apps = {
+ .name = "chm_apps",
+ .id = SC7280_MASTER_APPSS_PROC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 3,
+ .links = { SC7280_SLAVE_GEM_NOC_CNOC, SC7280_SLAVE_LLCC,
+ SC7280_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node qnm_cmpnoc = {
+ .name = "qnm_cmpnoc",
+ .id = SC7280_MASTER_COMPUTE_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SC7280_SLAVE_GEM_NOC_CNOC, SC7280_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_gemnoc_cfg = {
+ .name = "qnm_gemnoc_cfg",
+ .id = SC7280_MASTER_GEM_NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 5,
+ .links = { SC7280_SLAVE_MSS_PROC_MS_MPU_CFG, SC7280_SLAVE_MCDMA_MS_MPU_CFG,
+ SC7280_SLAVE_SERVICE_GEM_NOC_1, SC7280_SLAVE_SERVICE_GEM_NOC_2,
+ SC7280_SLAVE_SERVICE_GEM_NOC },
+};
+
+static struct qcom_icc_node qnm_gpu = {
+ .name = "qnm_gpu",
+ .id = SC7280_MASTER_GFX3D,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SC7280_SLAVE_GEM_NOC_CNOC, SC7280_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_mnoc_hf = {
+ .name = "qnm_mnoc_hf",
+ .id = SC7280_MASTER_MNOC_HF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_mnoc_sf = {
+ .name = "qnm_mnoc_sf",
+ .id = SC7280_MASTER_MNOC_SF_MEM_NOC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SC7280_SLAVE_GEM_NOC_CNOC, SC7280_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_pcie = {
+ .name = "qnm_pcie",
+ .id = SC7280_MASTER_ANOC_PCIE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 2,
+ .links = { SC7280_SLAVE_GEM_NOC_CNOC, SC7280_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_snoc_gc = {
+ .name = "qnm_snoc_gc",
+ .id = SC7280_MASTER_SNOC_GC_MEM_NOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_snoc_sf = {
+ .name = "qnm_snoc_sf",
+ .id = SC7280_MASTER_SNOC_SF_MEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 3,
+ .links = { SC7280_SLAVE_GEM_NOC_CNOC, SC7280_SLAVE_LLCC,
+ SC7280_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node qhm_config_noc = {
+ .name = "qhm_config_noc",
+ .id = SC7280_MASTER_CNOC_LPASS_AG_NOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 6,
+ .links = { SC7280_SLAVE_LPASS_CORE_CFG, SC7280_SLAVE_LPASS_LPI_CFG,
+ SC7280_SLAVE_LPASS_MPU_CFG, SC7280_SLAVE_LPASS_TOP_CFG,
+ SC7280_SLAVE_SERVICES_LPASS_AML_NOC, SC7280_SLAVE_SERVICE_LPASS_AG_NOC },
+};
+
+static struct qcom_icc_node llcc_mc = {
+ .name = "llcc_mc",
+ .id = SC7280_MASTER_LLCC,
+ .channels = 2,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_EBI1 },
+};
+
+static struct qcom_icc_node qnm_mnoc_cfg = {
+ .name = "qnm_mnoc_cfg",
+ .id = SC7280_MASTER_CNOC_MNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_SERVICE_MNOC },
+};
+
+static struct qcom_icc_node qnm_video0 = {
+ .name = "qnm_video0",
+ .id = SC7280_MASTER_VIDEO_P0,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_video_cpu = {
+ .name = "qnm_video_cpu",
+ .id = SC7280_MASTER_VIDEO_PROC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_camnoc_hf = {
+ .name = "qxm_camnoc_hf",
+ .id = SC7280_MASTER_CAMNOC_HF,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_camnoc_icp = {
+ .name = "qxm_camnoc_icp",
+ .id = SC7280_MASTER_CAMNOC_ICP,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_camnoc_sf = {
+ .name = "qxm_camnoc_sf",
+ .id = SC7280_MASTER_CAMNOC_SF,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_mdp0 = {
+ .name = "qxm_mdp0",
+ .id = SC7280_MASTER_MDP0,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qhm_nsp_noc_config = {
+ .name = "qhm_nsp_noc_config",
+ .id = SC7280_MASTER_CDSP_NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_SERVICE_NSP_NOC },
+};
+
+static struct qcom_icc_node qxm_nsp = {
+ .name = "qxm_nsp",
+ .id = SC7280_MASTER_CDSP_PROC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_CDSP_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_aggre1_noc = {
+ .name = "qnm_aggre1_noc",
+ .id = SC7280_MASTER_A1NOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qnm_aggre2_noc = {
+ .name = "qnm_aggre2_noc",
+ .id = SC7280_MASTER_A2NOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qnm_snoc_cfg = {
+ .name = "qnm_snoc_cfg",
+ .id = SC7280_MASTER_SNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_SERVICE_SNOC },
+};
+
+static struct qcom_icc_node qxm_pimem = {
+ .name = "qxm_pimem",
+ .id = SC7280_MASTER_PIMEM,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_SNOC_GEM_NOC_GC },
+};
+
+static struct qcom_icc_node xm_gic = {
+ .name = "xm_gic",
+ .id = SC7280_MASTER_GIC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_SLAVE_SNOC_GEM_NOC_GC },
+};
+
+static struct qcom_icc_node qns_a1noc_snoc = {
+ .name = "qns_a1noc_snoc",
+ .id = SC7280_SLAVE_A1NOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SC7280_MASTER_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node srvc_aggre1_noc = {
+ .name = "srvc_aggre1_noc",
+ .id = SC7280_SLAVE_SERVICE_A1NOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_a2noc_snoc = {
+ .name = "qns_a2noc_snoc",
+ .id = SC7280_SLAVE_A2NOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SC7280_MASTER_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qns_pcie_mem_noc = {
+ .name = "qns_pcie_mem_noc",
+ .id = SC7280_SLAVE_ANOC_PCIE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SC7280_MASTER_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node srvc_aggre2_noc = {
+ .name = "srvc_aggre2_noc",
+ .id = SC7280_SLAVE_SERVICE_A2NOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qup0_core_slave = {
+ .name = "qup0_core_slave",
+ .id = SC7280_SLAVE_QUP_CORE_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qup1_core_slave = {
+ .name = "qup1_core_slave",
+ .id = SC7280_SLAVE_QUP_CORE_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ahb2phy0 = {
+ .name = "qhs_ahb2phy0",
+ .id = SC7280_SLAVE_AHB2PHY_SOUTH,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ahb2phy1 = {
+ .name = "qhs_ahb2phy1",
+ .id = SC7280_SLAVE_AHB2PHY_NORTH,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_camera_cfg = {
+ .name = "qhs_camera_cfg",
+ .id = SC7280_SLAVE_CAMERA_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_clk_ctl = {
+ .name = "qhs_clk_ctl",
+ .id = SC7280_SLAVE_CLK_CTL,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_compute_cfg = {
+ .name = "qhs_compute_cfg",
+ .id = SC7280_SLAVE_CDSP_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_MASTER_CDSP_NOC_CFG },
+};
+
+static struct qcom_icc_node qhs_cpr_cx = {
+ .name = "qhs_cpr_cx",
+ .id = SC7280_SLAVE_RBCPR_CX_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_cpr_mx = {
+ .name = "qhs_cpr_mx",
+ .id = SC7280_SLAVE_RBCPR_MX_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_crypto0_cfg = {
+ .name = "qhs_crypto0_cfg",
+ .id = SC7280_SLAVE_CRYPTO_0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_cx_rdpm = {
+ .name = "qhs_cx_rdpm",
+ .id = SC7280_SLAVE_CX_RDPM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_dcc_cfg = {
+ .name = "qhs_dcc_cfg",
+ .id = SC7280_SLAVE_DCC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_display_cfg = {
+ .name = "qhs_display_cfg",
+ .id = SC7280_SLAVE_DISPLAY_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_gpuss_cfg = {
+ .name = "qhs_gpuss_cfg",
+ .id = SC7280_SLAVE_GFX3D_CFG,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_hwkm = {
+ .name = "qhs_hwkm",
+ .id = SC7280_SLAVE_HWKM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_imem_cfg = {
+ .name = "qhs_imem_cfg",
+ .id = SC7280_SLAVE_IMEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ipa = {
+ .name = "qhs_ipa",
+ .id = SC7280_SLAVE_IPA_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ipc_router = {
+ .name = "qhs_ipc_router",
+ .id = SC7280_SLAVE_IPC_ROUTER_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_lpass_cfg = {
+ .name = "qhs_lpass_cfg",
+ .id = SC7280_SLAVE_LPASS,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_MASTER_CNOC_LPASS_AG_NOC },
+};
+
+static struct qcom_icc_node qhs_mss_cfg = {
+ .name = "qhs_mss_cfg",
+ .id = SC7280_SLAVE_CNOC_MSS,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_mx_rdpm = {
+ .name = "qhs_mx_rdpm",
+ .id = SC7280_SLAVE_MX_RDPM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie0_cfg = {
+ .name = "qhs_pcie0_cfg",
+ .id = SC7280_SLAVE_PCIE_0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie1_cfg = {
+ .name = "qhs_pcie1_cfg",
+ .id = SC7280_SLAVE_PCIE_1_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pdm = {
+ .name = "qhs_pdm",
+ .id = SC7280_SLAVE_PDM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pimem_cfg = {
+ .name = "qhs_pimem_cfg",
+ .id = SC7280_SLAVE_PIMEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pka_wrapper_cfg = {
+ .name = "qhs_pka_wrapper_cfg",
+ .id = SC7280_SLAVE_PKA_WRAPPER_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pmu_wrapper_cfg = {
+ .name = "qhs_pmu_wrapper_cfg",
+ .id = SC7280_SLAVE_PMU_WRAPPER_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qdss_cfg = {
+ .name = "qhs_qdss_cfg",
+ .id = SC7280_SLAVE_QDSS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qspi = {
+ .name = "qhs_qspi",
+ .id = SC7280_SLAVE_QSPI_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qup0 = {
+ .name = "qhs_qup0",
+ .id = SC7280_SLAVE_QUP_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qup1 = {
+ .name = "qhs_qup1",
+ .id = SC7280_SLAVE_QUP_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_sdc1 = {
+ .name = "qhs_sdc1",
+ .id = SC7280_SLAVE_SDCC_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_sdc2 = {
+ .name = "qhs_sdc2",
+ .id = SC7280_SLAVE_SDCC_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_sdc4 = {
+ .name = "qhs_sdc4",
+ .id = SC7280_SLAVE_SDCC_4,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_security = {
+ .name = "qhs_security",
+ .id = SC7280_SLAVE_SECURITY,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_tcsr = {
+ .name = "qhs_tcsr",
+ .id = SC7280_SLAVE_TCSR,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_tlmm = {
+ .name = "qhs_tlmm",
+ .id = SC7280_SLAVE_TLMM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ufs_mem_cfg = {
+ .name = "qhs_ufs_mem_cfg",
+ .id = SC7280_SLAVE_UFS_MEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_usb2 = {
+ .name = "qhs_usb2",
+ .id = SC7280_SLAVE_USB2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_usb3_0 = {
+ .name = "qhs_usb3_0",
+ .id = SC7280_SLAVE_USB3_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_venus_cfg = {
+ .name = "qhs_venus_cfg",
+ .id = SC7280_SLAVE_VENUS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_vsense_ctrl_cfg = {
+ .name = "qhs_vsense_ctrl_cfg",
+ .id = SC7280_SLAVE_VSENSE_CTRL_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_a1_noc_cfg = {
+ .name = "qns_a1_noc_cfg",
+ .id = SC7280_SLAVE_A1NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_MASTER_A1NOC_CFG },
+};
+
+static struct qcom_icc_node qns_a2_noc_cfg = {
+ .name = "qns_a2_noc_cfg",
+ .id = SC7280_SLAVE_A2NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_MASTER_A2NOC_CFG },
+};
+
+static struct qcom_icc_node qns_cnoc2_cnoc3 = {
+ .name = "qns_cnoc2_cnoc3",
+ .id = SC7280_SLAVE_CNOC2_CNOC3,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_MASTER_CNOC2_CNOC3 },
+};
+
+static struct qcom_icc_node qns_mnoc_cfg = {
+ .name = "qns_mnoc_cfg",
+ .id = SC7280_SLAVE_CNOC_MNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_MASTER_CNOC_MNOC_CFG },
+};
+
+static struct qcom_icc_node qns_snoc_cfg = {
+ .name = "qns_snoc_cfg",
+ .id = SC7280_SLAVE_SNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_MASTER_SNOC_CFG },
+};
+
+static struct qcom_icc_node qhs_aoss = {
+ .name = "qhs_aoss",
+ .id = SC7280_SLAVE_AOSS,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_apss = {
+ .name = "qhs_apss",
+ .id = SC7280_SLAVE_APPSS,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_cnoc3_cnoc2 = {
+ .name = "qns_cnoc3_cnoc2",
+ .id = SC7280_SLAVE_CNOC3_CNOC2,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_MASTER_CNOC3_CNOC2 },
+};
+
+static struct qcom_icc_node qns_cnoc_a2noc = {
+ .name = "qns_cnoc_a2noc",
+ .id = SC7280_SLAVE_CNOC_A2NOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_MASTER_CNOC_A2NOC },
+};
+
+static struct qcom_icc_node qns_ddrss_cfg = {
+ .name = "qns_ddrss_cfg",
+ .id = SC7280_SLAVE_DDRSS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_MASTER_CNOC_DC_NOC },
+};
+
+static struct qcom_icc_node qxs_boot_imem = {
+ .name = "qxs_boot_imem",
+ .id = SC7280_SLAVE_BOOT_IMEM,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qxs_imem = {
+ .name = "qxs_imem",
+ .id = SC7280_SLAVE_IMEM,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qxs_pimem = {
+ .name = "qxs_pimem",
+ .id = SC7280_SLAVE_PIMEM,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_0 = {
+ .name = "xs_pcie_0",
+ .id = SC7280_SLAVE_PCIE_0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_1 = {
+ .name = "xs_pcie_1",
+ .id = SC7280_SLAVE_PCIE_1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_qdss_stm = {
+ .name = "xs_qdss_stm",
+ .id = SC7280_SLAVE_QDSS_STM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_sys_tcu_cfg = {
+ .name = "xs_sys_tcu_cfg",
+ .id = SC7280_SLAVE_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_llcc = {
+ .name = "qhs_llcc",
+ .id = SC7280_SLAVE_LLCC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_gemnoc = {
+ .name = "qns_gemnoc",
+ .id = SC7280_SLAVE_GEM_NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SC7280_MASTER_GEM_NOC_CFG },
+};
+
+static struct qcom_icc_node qhs_mdsp_ms_mpu_cfg = {
+ .name = "qhs_mdsp_ms_mpu_cfg",
+ .id = SC7280_SLAVE_MSS_PROC_MS_MPU_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_modem_ms_mpu_cfg = {
+ .name = "qhs_modem_ms_mpu_cfg",
+ .id = SC7280_SLAVE_MCDMA_MS_MPU_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_gem_noc_cnoc = {
+ .name = "qns_gem_noc_cnoc",
+ .id = SC7280_SLAVE_GEM_NOC_CNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SC7280_MASTER_GEM_NOC_CNOC },
+};
+
+static struct qcom_icc_node qns_llcc = {
+ .name = "qns_llcc",
+ .id = SC7280_SLAVE_LLCC,
+ .channels = 2,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SC7280_MASTER_LLCC },
+};
+
+static struct qcom_icc_node qns_pcie = {
+ .name = "qns_pcie",
+ .id = SC7280_SLAVE_MEM_NOC_PCIE_SNOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_MASTER_GEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node srvc_even_gemnoc = {
+ .name = "srvc_even_gemnoc",
+ .id = SC7280_SLAVE_SERVICE_GEM_NOC_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node srvc_odd_gemnoc = {
+ .name = "srvc_odd_gemnoc",
+ .id = SC7280_SLAVE_SERVICE_GEM_NOC_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node srvc_sys_gemnoc = {
+ .name = "srvc_sys_gemnoc",
+ .id = SC7280_SLAVE_SERVICE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_lpass_core = {
+ .name = "qhs_lpass_core",
+ .id = SC7280_SLAVE_LPASS_CORE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_lpass_lpi = {
+ .name = "qhs_lpass_lpi",
+ .id = SC7280_SLAVE_LPASS_LPI_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_lpass_mpu = {
+ .name = "qhs_lpass_mpu",
+ .id = SC7280_SLAVE_LPASS_MPU_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_lpass_top = {
+ .name = "qhs_lpass_top",
+ .id = SC7280_SLAVE_LPASS_TOP_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node srvc_niu_aml_noc = {
+ .name = "srvc_niu_aml_noc",
+ .id = SC7280_SLAVE_SERVICES_LPASS_AML_NOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node srvc_niu_lpass_agnoc = {
+ .name = "srvc_niu_lpass_agnoc",
+ .id = SC7280_SLAVE_SERVICE_LPASS_AG_NOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node ebi = {
+ .name = "ebi",
+ .id = SC7280_SLAVE_EBI1,
+ .channels = 2,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_mem_noc_hf = {
+ .name = "qns_mem_noc_hf",
+ .id = SC7280_SLAVE_MNOC_HF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SC7280_MASTER_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qns_mem_noc_sf = {
+ .name = "qns_mem_noc_sf",
+ .id = SC7280_SLAVE_MNOC_SF_MEM_NOC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SC7280_MASTER_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node srvc_mnoc = {
+ .name = "srvc_mnoc",
+ .id = SC7280_SLAVE_SERVICE_MNOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_nsp_gemnoc = {
+ .name = "qns_nsp_gemnoc",
+ .id = SC7280_SLAVE_CDSP_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SC7280_MASTER_COMPUTE_NOC },
+};
+
+static struct qcom_icc_node service_nsp_noc = {
+ .name = "service_nsp_noc",
+ .id = SC7280_SLAVE_SERVICE_NSP_NOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_gemnoc_gc = {
+ .name = "qns_gemnoc_gc",
+ .id = SC7280_SLAVE_SNOC_GEM_NOC_GC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SC7280_MASTER_SNOC_GC_MEM_NOC },
+};
+
+static struct qcom_icc_node qns_gemnoc_sf = {
+ .name = "qns_gemnoc_sf",
+ .id = SC7280_SLAVE_SNOC_GEM_NOC_SF,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SC7280_MASTER_SNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node srvc_snoc = {
+ .name = "srvc_snoc",
+ .id = SC7280_SLAVE_SERVICE_SNOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_bcm bcm_acv = {
+ .name = "ACV",
+ .num_nodes = 1,
+ .nodes = { &ebi },
+};
+
+static struct qcom_icc_bcm bcm_ce0 = {
+ .name = "CE0",
+ .num_nodes = 1,
+ .nodes = { &qxm_crypto },
+};
+
+static struct qcom_icc_bcm bcm_cn0 = {
+ .name = "CN0",
+ .keepalive = true,
+ .num_nodes = 2,
+ .nodes = { &qnm_gemnoc_cnoc, &qnm_gemnoc_pcie },
+};
+
+static struct qcom_icc_bcm bcm_cn1 = {
+ .name = "CN1",
+ .num_nodes = 47,
+ .nodes = { &qnm_cnoc3_cnoc2, &xm_qdss_dap,
+ &qhs_ahb2phy0, &qhs_ahb2phy1,
+ &qhs_camera_cfg, &qhs_clk_ctl,
+ &qhs_compute_cfg, &qhs_cpr_cx,
+ &qhs_cpr_mx, &qhs_crypto0_cfg,
+ &qhs_cx_rdpm, &qhs_dcc_cfg,
+ &qhs_display_cfg, &qhs_gpuss_cfg,
+ &qhs_hwkm, &qhs_imem_cfg,
+ &qhs_ipa, &qhs_ipc_router,
+ &qhs_mss_cfg, &qhs_mx_rdpm,
+ &qhs_pcie0_cfg, &qhs_pcie1_cfg,
+ &qhs_pimem_cfg, &qhs_pka_wrapper_cfg,
+ &qhs_pmu_wrapper_cfg, &qhs_qdss_cfg,
+ &qhs_qup0, &qhs_qup1,
+ &qhs_security, &qhs_tcsr,
+ &qhs_tlmm, &qhs_ufs_mem_cfg, &qhs_usb2,
+ &qhs_usb3_0, &qhs_venus_cfg,
+ &qhs_vsense_ctrl_cfg, &qns_a1_noc_cfg,
+ &qns_a2_noc_cfg, &qns_cnoc2_cnoc3,
+ &qns_mnoc_cfg, &qns_snoc_cfg,
+ &qnm_cnoc2_cnoc3, &qhs_aoss,
+ &qhs_apss, &qns_cnoc3_cnoc2,
+ &qns_cnoc_a2noc, &qns_ddrss_cfg },
+};
+
+static struct qcom_icc_bcm bcm_cn2 = {
+ .name = "CN2",
+ .num_nodes = 6,
+ .nodes = { &qhs_lpass_cfg, &qhs_pdm,
+ &qhs_qspi, &qhs_sdc1,
+ &qhs_sdc2, &qhs_sdc4 },
+};
+
+static struct qcom_icc_bcm bcm_co0 = {
+ .name = "CO0",
+ .num_nodes = 1,
+ .nodes = { &qns_nsp_gemnoc },
+};
+
+static struct qcom_icc_bcm bcm_co3 = {
+ .name = "CO3",
+ .num_nodes = 1,
+ .nodes = { &qxm_nsp },
+};
+
+static struct qcom_icc_bcm bcm_mc0 = {
+ .name = "MC0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &ebi },
+};
+
+static struct qcom_icc_bcm bcm_mm0 = {
+ .name = "MM0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &qns_mem_noc_hf },
+};
+
+static struct qcom_icc_bcm bcm_mm1 = {
+ .name = "MM1",
+ .num_nodes = 2,
+ .nodes = { &qxm_camnoc_hf, &qxm_mdp0 },
+};
+
+static struct qcom_icc_bcm bcm_mm4 = {
+ .name = "MM4",
+ .num_nodes = 1,
+ .nodes = { &qns_mem_noc_sf },
+};
+
+static struct qcom_icc_bcm bcm_mm5 = {
+ .name = "MM5",
+ .num_nodes = 3,
+ .nodes = { &qnm_video0, &qxm_camnoc_icp,
+ &qxm_camnoc_sf },
+};
+
+static struct qcom_icc_bcm bcm_qup0 = {
+ .name = "QUP0",
+ .vote_scale = 1,
+ .num_nodes = 1,
+ .nodes = { &qup0_core_slave },
+};
+
+static struct qcom_icc_bcm bcm_qup1 = {
+ .name = "QUP1",
+ .vote_scale = 1,
+ .num_nodes = 1,
+ .nodes = { &qup1_core_slave },
+};
+
+static struct qcom_icc_bcm bcm_sh0 = {
+ .name = "SH0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &qns_llcc },
+};
+
+static struct qcom_icc_bcm bcm_sh2 = {
+ .name = "SH2",
+ .num_nodes = 2,
+ .nodes = { &alm_gpu_tcu, &alm_sys_tcu },
+};
+
+static struct qcom_icc_bcm bcm_sh3 = {
+ .name = "SH3",
+ .num_nodes = 1,
+ .nodes = { &qnm_cmpnoc },
+};
+
+static struct qcom_icc_bcm bcm_sh4 = {
+ .name = "SH4",
+ .num_nodes = 1,
+ .nodes = { &chm_apps },
+};
+
+static struct qcom_icc_bcm bcm_sn0 = {
+ .name = "SN0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &qns_gemnoc_sf },
+};
+
+static struct qcom_icc_bcm bcm_sn2 = {
+ .name = "SN2",
+ .num_nodes = 1,
+ .nodes = { &qns_gemnoc_gc },
+};
+
+static struct qcom_icc_bcm bcm_sn3 = {
+ .name = "SN3",
+ .num_nodes = 1,
+ .nodes = { &qxs_pimem },
+};
+
+static struct qcom_icc_bcm bcm_sn4 = {
+ .name = "SN4",
+ .num_nodes = 1,
+ .nodes = { &xs_qdss_stm },
+};
+
+static struct qcom_icc_bcm bcm_sn5 = {
+ .name = "SN5",
+ .num_nodes = 1,
+ .nodes = { &xm_pcie3_0 },
+};
+
+static struct qcom_icc_bcm bcm_sn6 = {
+ .name = "SN6",
+ .num_nodes = 1,
+ .nodes = { &xm_pcie3_1 },
+};
+
+static struct qcom_icc_bcm bcm_sn7 = {
+ .name = "SN7",
+ .num_nodes = 1,
+ .nodes = { &qnm_aggre1_noc },
+};
+
+static struct qcom_icc_bcm bcm_sn8 = {
+ .name = "SN8",
+ .num_nodes = 1,
+ .nodes = { &qnm_aggre2_noc },
+};
+
+static struct qcom_icc_bcm bcm_sn14 = {
+ .name = "SN14",
+ .num_nodes = 1,
+ .nodes = { &qns_pcie_mem_noc },
+};
+
+static struct qcom_icc_bcm *aggre1_noc_bcms[] = {
+ &bcm_sn5,
+ &bcm_sn6,
+ &bcm_sn14,
+};
+
+static struct qcom_icc_node *aggre1_noc_nodes[] = {
+ [MASTER_QSPI_0] = &qhm_qspi,
+ [MASTER_QUP_0] = &qhm_qup0,
+ [MASTER_QUP_1] = &qhm_qup1,
+ [MASTER_A1NOC_CFG] = &qnm_a1noc_cfg,
+ [MASTER_PCIE_0] = &xm_pcie3_0,
+ [MASTER_PCIE_1] = &xm_pcie3_1,
+ [MASTER_SDCC_1] = &xm_sdc1,
+ [MASTER_SDCC_2] = &xm_sdc2,
+ [MASTER_SDCC_4] = &xm_sdc4,
+ [MASTER_UFS_MEM] = &xm_ufs_mem,
+ [MASTER_USB2] = &xm_usb2,
+ [MASTER_USB3_0] = &xm_usb3_0,
+ [SLAVE_A1NOC_SNOC] = &qns_a1noc_snoc,
+ [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc,
+ [SLAVE_SERVICE_A1NOC] = &srvc_aggre1_noc,
+};
+
+static struct qcom_icc_desc sc7280_aggre1_noc = {
+ .nodes = aggre1_noc_nodes,
+ .num_nodes = ARRAY_SIZE(aggre1_noc_nodes),
+ .bcms = aggre1_noc_bcms,
+ .num_bcms = ARRAY_SIZE(aggre1_noc_bcms),
+};
+
+static struct qcom_icc_bcm *aggre2_noc_bcms[] = {
+ &bcm_ce0,
+};
+
+static struct qcom_icc_node *aggre2_noc_nodes[] = {
+ [MASTER_QDSS_BAM] = &qhm_qdss_bam,
+ [MASTER_A2NOC_CFG] = &qnm_a2noc_cfg,
+ [MASTER_CNOC_A2NOC] = &qnm_cnoc_datapath,
+ [MASTER_CRYPTO] = &qxm_crypto,
+ [MASTER_IPA] = &qxm_ipa,
+ [MASTER_QDSS_ETR] = &xm_qdss_etr,
+ [SLAVE_A2NOC_SNOC] = &qns_a2noc_snoc,
+ [SLAVE_SERVICE_A2NOC] = &srvc_aggre2_noc,
+};
+
+static struct qcom_icc_desc sc7280_aggre2_noc = {
+ .nodes = aggre2_noc_nodes,
+ .num_nodes = ARRAY_SIZE(aggre2_noc_nodes),
+ .bcms = aggre2_noc_bcms,
+ .num_bcms = ARRAY_SIZE(aggre2_noc_bcms),
+};
+
+static struct qcom_icc_bcm *clk_virt_bcms[] = {
+ &bcm_qup0,
+ &bcm_qup1,
+};
+
+static struct qcom_icc_node *clk_virt_nodes[] = {
+ [MASTER_QUP_CORE_0] = &qup0_core_master,
+ [MASTER_QUP_CORE_1] = &qup1_core_master,
+ [SLAVE_QUP_CORE_0] = &qup0_core_slave,
+ [SLAVE_QUP_CORE_1] = &qup1_core_slave,
+};
+
+static struct qcom_icc_desc sc7280_clk_virt = {
+ .nodes = clk_virt_nodes,
+ .num_nodes = ARRAY_SIZE(clk_virt_nodes),
+ .bcms = clk_virt_bcms,
+ .num_bcms = ARRAY_SIZE(clk_virt_bcms),
+};
+
+static struct qcom_icc_bcm *cnoc2_bcms[] = {
+ &bcm_cn1,
+ &bcm_cn2,
+};
+
+static struct qcom_icc_node *cnoc2_nodes[] = {
+ [MASTER_CNOC3_CNOC2] = &qnm_cnoc3_cnoc2,
+ [MASTER_QDSS_DAP] = &xm_qdss_dap,
+ [SLAVE_AHB2PHY_SOUTH] = &qhs_ahb2phy0,
+ [SLAVE_AHB2PHY_NORTH] = &qhs_ahb2phy1,
+ [SLAVE_CAMERA_CFG] = &qhs_camera_cfg,
+ [SLAVE_CLK_CTL] = &qhs_clk_ctl,
+ [SLAVE_CDSP_CFG] = &qhs_compute_cfg,
+ [SLAVE_RBCPR_CX_CFG] = &qhs_cpr_cx,
+ [SLAVE_RBCPR_MX_CFG] = &qhs_cpr_mx,
+ [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg,
+ [SLAVE_CX_RDPM] = &qhs_cx_rdpm,
+ [SLAVE_DCC_CFG] = &qhs_dcc_cfg,
+ [SLAVE_DISPLAY_CFG] = &qhs_display_cfg,
+ [SLAVE_GFX3D_CFG] = &qhs_gpuss_cfg,
+ [SLAVE_HWKM] = &qhs_hwkm,
+ [SLAVE_IMEM_CFG] = &qhs_imem_cfg,
+ [SLAVE_IPA_CFG] = &qhs_ipa,
+ [SLAVE_IPC_ROUTER_CFG] = &qhs_ipc_router,
+ [SLAVE_LPASS] = &qhs_lpass_cfg,
+ [SLAVE_CNOC_MSS] = &qhs_mss_cfg,
+ [SLAVE_MX_RDPM] = &qhs_mx_rdpm,
+ [SLAVE_PCIE_0_CFG] = &qhs_pcie0_cfg,
+ [SLAVE_PCIE_1_CFG] = &qhs_pcie1_cfg,
+ [SLAVE_PDM] = &qhs_pdm,
+ [SLAVE_PIMEM_CFG] = &qhs_pimem_cfg,
+ [SLAVE_PKA_WRAPPER_CFG] = &qhs_pka_wrapper_cfg,
+ [SLAVE_PMU_WRAPPER_CFG] = &qhs_pmu_wrapper_cfg,
+ [SLAVE_QDSS_CFG] = &qhs_qdss_cfg,
+ [SLAVE_QSPI_0] = &qhs_qspi,
+ [SLAVE_QUP_0] = &qhs_qup0,
+ [SLAVE_QUP_1] = &qhs_qup1,
+ [SLAVE_SDCC_1] = &qhs_sdc1,
+ [SLAVE_SDCC_2] = &qhs_sdc2,
+ [SLAVE_SDCC_4] = &qhs_sdc4,
+ [SLAVE_SECURITY] = &qhs_security,
+ [SLAVE_TCSR] = &qhs_tcsr,
+ [SLAVE_TLMM] = &qhs_tlmm,
+ [SLAVE_UFS_MEM_CFG] = &qhs_ufs_mem_cfg,
+ [SLAVE_USB2] = &qhs_usb2,
+ [SLAVE_USB3_0] = &qhs_usb3_0,
+ [SLAVE_VENUS_CFG] = &qhs_venus_cfg,
+ [SLAVE_VSENSE_CTRL_CFG] = &qhs_vsense_ctrl_cfg,
+ [SLAVE_A1NOC_CFG] = &qns_a1_noc_cfg,
+ [SLAVE_A2NOC_CFG] = &qns_a2_noc_cfg,
+ [SLAVE_CNOC2_CNOC3] = &qns_cnoc2_cnoc3,
+ [SLAVE_CNOC_MNOC_CFG] = &qns_mnoc_cfg,
+ [SLAVE_SNOC_CFG] = &qns_snoc_cfg,
+};
+
+static struct qcom_icc_desc sc7280_cnoc2 = {
+ .nodes = cnoc2_nodes,
+ .num_nodes = ARRAY_SIZE(cnoc2_nodes),
+ .bcms = cnoc2_bcms,
+ .num_bcms = ARRAY_SIZE(cnoc2_bcms),
+};
+
+static struct qcom_icc_bcm *cnoc3_bcms[] = {
+ &bcm_cn0,
+ &bcm_cn1,
+ &bcm_sn3,
+ &bcm_sn4,
+};
+
+static struct qcom_icc_node *cnoc3_nodes[] = {
+ [MASTER_CNOC2_CNOC3] = &qnm_cnoc2_cnoc3,
+ [MASTER_GEM_NOC_CNOC] = &qnm_gemnoc_cnoc,
+ [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie,
+ [SLAVE_AOSS] = &qhs_aoss,
+ [SLAVE_APPSS] = &qhs_apss,
+ [SLAVE_CNOC3_CNOC2] = &qns_cnoc3_cnoc2,
+ [SLAVE_CNOC_A2NOC] = &qns_cnoc_a2noc,
+ [SLAVE_DDRSS_CFG] = &qns_ddrss_cfg,
+ [SLAVE_BOOT_IMEM] = &qxs_boot_imem,
+ [SLAVE_IMEM] = &qxs_imem,
+ [SLAVE_PIMEM] = &qxs_pimem,
+ [SLAVE_PCIE_0] = &xs_pcie_0,
+ [SLAVE_PCIE_1] = &xs_pcie_1,
+ [SLAVE_QDSS_STM] = &xs_qdss_stm,
+ [SLAVE_TCU] = &xs_sys_tcu_cfg,
+};
+
+static struct qcom_icc_desc sc7280_cnoc3 = {
+ .nodes = cnoc3_nodes,
+ .num_nodes = ARRAY_SIZE(cnoc3_nodes),
+ .bcms = cnoc3_bcms,
+ .num_bcms = ARRAY_SIZE(cnoc3_bcms),
+};
+
+static struct qcom_icc_bcm *dc_noc_bcms[] = {
+};
+
+static struct qcom_icc_node *dc_noc_nodes[] = {
+ [MASTER_CNOC_DC_NOC] = &qnm_cnoc_dc_noc,
+ [SLAVE_LLCC_CFG] = &qhs_llcc,
+ [SLAVE_GEM_NOC_CFG] = &qns_gemnoc,
+};
+
+static struct qcom_icc_desc sc7280_dc_noc = {
+ .nodes = dc_noc_nodes,
+ .num_nodes = ARRAY_SIZE(dc_noc_nodes),
+ .bcms = dc_noc_bcms,
+ .num_bcms = ARRAY_SIZE(dc_noc_bcms),
+};
+
+static struct qcom_icc_bcm *gem_noc_bcms[] = {
+ &bcm_sh0,
+ &bcm_sh2,
+ &bcm_sh3,
+ &bcm_sh4,
+};
+
+static struct qcom_icc_node *gem_noc_nodes[] = {
+ [MASTER_GPU_TCU] = &alm_gpu_tcu,
+ [MASTER_SYS_TCU] = &alm_sys_tcu,
+ [MASTER_APPSS_PROC] = &chm_apps,
+ [MASTER_COMPUTE_NOC] = &qnm_cmpnoc,
+ [MASTER_GEM_NOC_CFG] = &qnm_gemnoc_cfg,
+ [MASTER_GFX3D] = &qnm_gpu,
+ [MASTER_MNOC_HF_MEM_NOC] = &qnm_mnoc_hf,
+ [MASTER_MNOC_SF_MEM_NOC] = &qnm_mnoc_sf,
+ [MASTER_ANOC_PCIE_GEM_NOC] = &qnm_pcie,
+ [MASTER_SNOC_GC_MEM_NOC] = &qnm_snoc_gc,
+ [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf,
+ [SLAVE_MSS_PROC_MS_MPU_CFG] = &qhs_mdsp_ms_mpu_cfg,
+ [SLAVE_MCDMA_MS_MPU_CFG] = &qhs_modem_ms_mpu_cfg,
+ [SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc,
+ [SLAVE_LLCC] = &qns_llcc,
+ [SLAVE_MEM_NOC_PCIE_SNOC] = &qns_pcie,
+ [SLAVE_SERVICE_GEM_NOC_1] = &srvc_even_gemnoc,
+ [SLAVE_SERVICE_GEM_NOC_2] = &srvc_odd_gemnoc,
+ [SLAVE_SERVICE_GEM_NOC] = &srvc_sys_gemnoc,
+};
+
+static struct qcom_icc_desc sc7280_gem_noc = {
+ .nodes = gem_noc_nodes,
+ .num_nodes = ARRAY_SIZE(gem_noc_nodes),
+ .bcms = gem_noc_bcms,
+ .num_bcms = ARRAY_SIZE(gem_noc_bcms),
+};
+
+static struct qcom_icc_bcm *lpass_ag_noc_bcms[] = {
+};
+
+static struct qcom_icc_node *lpass_ag_noc_nodes[] = {
+ [MASTER_CNOC_LPASS_AG_NOC] = &qhm_config_noc,
+ [SLAVE_LPASS_CORE_CFG] = &qhs_lpass_core,
+ [SLAVE_LPASS_LPI_CFG] = &qhs_lpass_lpi,
+ [SLAVE_LPASS_MPU_CFG] = &qhs_lpass_mpu,
+ [SLAVE_LPASS_TOP_CFG] = &qhs_lpass_top,
+ [SLAVE_SERVICES_LPASS_AML_NOC] = &srvc_niu_aml_noc,
+ [SLAVE_SERVICE_LPASS_AG_NOC] = &srvc_niu_lpass_agnoc,
+};
+
+static struct qcom_icc_desc sc7280_lpass_ag_noc = {
+ .nodes = lpass_ag_noc_nodes,
+ .num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes),
+ .bcms = lpass_ag_noc_bcms,
+ .num_bcms = ARRAY_SIZE(lpass_ag_noc_bcms),
+};
+
+static struct qcom_icc_bcm *mc_virt_bcms[] = {
+ &bcm_acv,
+ &bcm_mc0,
+};
+
+static struct qcom_icc_node *mc_virt_nodes[] = {
+ [MASTER_LLCC] = &llcc_mc,
+ [SLAVE_EBI1] = &ebi,
+};
+
+static struct qcom_icc_desc sc7280_mc_virt = {
+ .nodes = mc_virt_nodes,
+ .num_nodes = ARRAY_SIZE(mc_virt_nodes),
+ .bcms = mc_virt_bcms,
+ .num_bcms = ARRAY_SIZE(mc_virt_bcms),
+};
+
+static struct qcom_icc_bcm *mmss_noc_bcms[] = {
+ &bcm_mm0,
+ &bcm_mm1,
+ &bcm_mm4,
+ &bcm_mm5,
+};
+
+static struct qcom_icc_node *mmss_noc_nodes[] = {
+ [MASTER_CNOC_MNOC_CFG] = &qnm_mnoc_cfg,
+ [MASTER_VIDEO_P0] = &qnm_video0,
+ [MASTER_VIDEO_PROC] = &qnm_video_cpu,
+ [MASTER_CAMNOC_HF] = &qxm_camnoc_hf,
+ [MASTER_CAMNOC_ICP] = &qxm_camnoc_icp,
+ [MASTER_CAMNOC_SF] = &qxm_camnoc_sf,
+ [MASTER_MDP0] = &qxm_mdp0,
+ [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf,
+ [SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf,
+ [SLAVE_SERVICE_MNOC] = &srvc_mnoc,
+};
+
+static struct qcom_icc_desc sc7280_mmss_noc = {
+ .nodes = mmss_noc_nodes,
+ .num_nodes = ARRAY_SIZE(mmss_noc_nodes),
+ .bcms = mmss_noc_bcms,
+ .num_bcms = ARRAY_SIZE(mmss_noc_bcms),
+};
+
+static struct qcom_icc_bcm *nsp_noc_bcms[] = {
+ &bcm_co0,
+ &bcm_co3,
+};
+
+static struct qcom_icc_node *nsp_noc_nodes[] = {
+ [MASTER_CDSP_NOC_CFG] = &qhm_nsp_noc_config,
+ [MASTER_CDSP_PROC] = &qxm_nsp,
+ [SLAVE_CDSP_MEM_NOC] = &qns_nsp_gemnoc,
+ [SLAVE_SERVICE_NSP_NOC] = &service_nsp_noc,
+};
+
+static struct qcom_icc_desc sc7280_nsp_noc = {
+ .nodes = nsp_noc_nodes,
+ .num_nodes = ARRAY_SIZE(nsp_noc_nodes),
+ .bcms = nsp_noc_bcms,
+ .num_bcms = ARRAY_SIZE(nsp_noc_bcms),
+};
+
+static struct qcom_icc_bcm *system_noc_bcms[] = {
+ &bcm_sn0,
+ &bcm_sn2,
+ &bcm_sn7,
+ &bcm_sn8,
+};
+
+static struct qcom_icc_node *system_noc_nodes[] = {
+ [MASTER_A1NOC_SNOC] = &qnm_aggre1_noc,
+ [MASTER_A2NOC_SNOC] = &qnm_aggre2_noc,
+ [MASTER_SNOC_CFG] = &qnm_snoc_cfg,
+ [MASTER_PIMEM] = &qxm_pimem,
+ [MASTER_GIC] = &xm_gic,
+ [SLAVE_SNOC_GEM_NOC_GC] = &qns_gemnoc_gc,
+ [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf,
+ [SLAVE_SERVICE_SNOC] = &srvc_snoc,
+};
+
+static struct qcom_icc_desc sc7280_system_noc = {
+ .nodes = system_noc_nodes,
+ .num_nodes = ARRAY_SIZE(system_noc_nodes),
+ .bcms = system_noc_bcms,
+ .num_bcms = ARRAY_SIZE(system_noc_bcms),
+};
+
+static int qnoc_probe(struct platform_device *pdev)
+{
+ const struct qcom_icc_desc *desc;
+ struct icc_onecell_data *data;
+ struct icc_provider *provider;
+ struct qcom_icc_node **qnodes;
+ struct qcom_icc_provider *qp;
+ struct icc_node *node;
+ size_t num_nodes, i;
+ int ret;
+
+ desc = device_get_match_data(&pdev->dev);
+ if (!desc)
+ return -EINVAL;
+
+ qnodes = desc->nodes;
+ num_nodes = desc->num_nodes;
+
+ qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
+ if (!qp)
+ return -ENOMEM;
+
+ data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ provider = &qp->provider;
+ provider->dev = &pdev->dev;
+ provider->set = qcom_icc_set;
+ provider->pre_aggregate = qcom_icc_pre_aggregate;
+ provider->aggregate = qcom_icc_aggregate;
+ provider->xlate_extended = qcom_icc_xlate_extended;
+ INIT_LIST_HEAD(&provider->nodes);
+ provider->data = data;
+
+ qp->dev = &pdev->dev;
+ qp->bcms = desc->bcms;
+ qp->num_bcms = desc->num_bcms;
+
+ qp->voter = of_bcm_voter_get(qp->dev, NULL);
+ if (IS_ERR(qp->voter))
+ return PTR_ERR(qp->voter);
+
+ ret = icc_provider_add(provider);
+ if (ret) {
+ dev_err(&pdev->dev, "error adding interconnect provider\n");
+ return ret;
+ }
+
+ for (i = 0; i < qp->num_bcms; i++)
+ qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
+
+ for (i = 0; i < num_nodes; i++) {
+ size_t j;
+
+ if (!qnodes[i])
+ continue;
+
+ node = icc_node_create(qnodes[i]->id);
+ if (IS_ERR(node)) {
+ ret = PTR_ERR(node);
+ goto err;
+ }
+
+ node->name = qnodes[i]->name;
+ node->data = qnodes[i];
+ icc_node_add(node, provider);
+
+ for (j = 0; j < qnodes[i]->num_links; j++)
+ icc_link_create(node, qnodes[i]->links[j]);
+
+ data->nodes[i] = node;
+ }
+ data->num_nodes = num_nodes;
+
+ platform_set_drvdata(pdev, qp);
+
+ return 0;
+err:
+ icc_nodes_remove(provider);
+ icc_provider_del(provider);
+ return ret;
+}
+
+static int qnoc_remove(struct platform_device *pdev)
+{
+ struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
+
+ icc_nodes_remove(&qp->provider);
+ return icc_provider_del(&qp->provider);
+}
+
+static const struct of_device_id qnoc_of_match[] = {
+ { .compatible = "qcom,sc7280-aggre1-noc",
+ .data = &sc7280_aggre1_noc},
+ { .compatible = "qcom,sc7280-aggre2-noc",
+ .data = &sc7280_aggre2_noc},
+ { .compatible = "qcom,sc7280-clk-virt",
+ .data = &sc7280_clk_virt},
+ { .compatible = "qcom,sc7280-cnoc2",
+ .data = &sc7280_cnoc2},
+ { .compatible = "qcom,sc7280-cnoc3",
+ .data = &sc7280_cnoc3},
+ { .compatible = "qcom,sc7280-dc-noc",
+ .data = &sc7280_dc_noc},
+ { .compatible = "qcom,sc7280-gem-noc",
+ .data = &sc7280_gem_noc},
+ { .compatible = "qcom,sc7280-lpass-ag-noc",
+ .data = &sc7280_lpass_ag_noc},
+ { .compatible = "qcom,sc7280-mc-virt",
+ .data = &sc7280_mc_virt},
+ { .compatible = "qcom,sc7280-mmss-noc",
+ .data = &sc7280_mmss_noc},
+ { .compatible = "qcom,sc7280-nsp-noc",
+ .data = &sc7280_nsp_noc},
+ { .compatible = "qcom,sc7280-system-noc",
+ .data = &sc7280_system_noc},
+ { }
+};
+MODULE_DEVICE_TABLE(of, qnoc_of_match);
+
+static struct platform_driver qnoc_driver = {
+ .probe = qnoc_probe,
+ .remove = qnoc_remove,
+ .driver = {
+ .name = "qnoc-sc7280",
+ .of_match_table = qnoc_of_match,
+ .sync_state = icc_sync_state,
+ },
+};
+module_platform_driver(qnoc_driver);
+
+MODULE_DESCRIPTION("SC7280 NoC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/interconnect/qcom/sc7280.h b/drivers/interconnect/qcom/sc7280.h
new file mode 100644
index 000000000000..175e400305c5
--- /dev/null
+++ b/drivers/interconnect/qcom/sc7280.h
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Qualcomm #define SC7280 interconnect IDs
+ *
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __DRIVERS_INTERCONNECT_QCOM_SC7280_H
+#define __DRIVERS_INTERCONNECT_QCOM_SC7280_H
+
+#define SC7280_MASTER_GPU_TCU 0
+#define SC7280_MASTER_SYS_TCU 1
+#define SC7280_MASTER_APPSS_PROC 2
+#define SC7280_MASTER_LLCC 3
+#define SC7280_MASTER_CNOC_LPASS_AG_NOC 4
+#define SC7280_MASTER_CDSP_NOC_CFG 5
+#define SC7280_MASTER_QDSS_BAM 6
+#define SC7280_MASTER_QSPI_0 7
+#define SC7280_MASTER_QUP_0 8
+#define SC7280_MASTER_QUP_1 9
+#define SC7280_MASTER_A1NOC_CFG 10
+#define SC7280_MASTER_A2NOC_CFG 11
+#define SC7280_MASTER_A1NOC_SNOC 12
+#define SC7280_MASTER_A2NOC_SNOC 13
+#define SC7280_MASTER_COMPUTE_NOC 14
+#define SC7280_MASTER_CNOC2_CNOC3 15
+#define SC7280_MASTER_CNOC3_CNOC2 16
+#define SC7280_MASTER_CNOC_A2NOC 17
+#define SC7280_MASTER_CNOC_DC_NOC 18
+#define SC7280_MASTER_GEM_NOC_CFG 19
+#define SC7280_MASTER_GEM_NOC_CNOC 20
+#define SC7280_MASTER_GEM_NOC_PCIE_SNOC 21
+#define SC7280_MASTER_GFX3D 22
+#define SC7280_MASTER_CNOC_MNOC_CFG 23
+#define SC7280_MASTER_MNOC_HF_MEM_NOC 24
+#define SC7280_MASTER_MNOC_SF_MEM_NOC 25
+#define SC7280_MASTER_ANOC_PCIE_GEM_NOC 26
+#define SC7280_MASTER_SNOC_CFG 27
+#define SC7280_MASTER_SNOC_GC_MEM_NOC 28
+#define SC7280_MASTER_SNOC_SF_MEM_NOC 29
+#define SC7280_MASTER_VIDEO_P0 30
+#define SC7280_MASTER_VIDEO_PROC 31
+#define SC7280_MASTER_QUP_CORE_0 32
+#define SC7280_MASTER_QUP_CORE_1 33
+#define SC7280_MASTER_CAMNOC_HF 34
+#define SC7280_MASTER_CAMNOC_ICP 35
+#define SC7280_MASTER_CAMNOC_SF 36
+#define SC7280_MASTER_CRYPTO 37
+#define SC7280_MASTER_IPA 38
+#define SC7280_MASTER_MDP0 39
+#define SC7280_MASTER_CDSP_PROC 40
+#define SC7280_MASTER_PIMEM 41
+#define SC7280_MASTER_GIC 42
+#define SC7280_MASTER_PCIE_0 43
+#define SC7280_MASTER_PCIE_1 44
+#define SC7280_MASTER_QDSS_DAP 45
+#define SC7280_MASTER_QDSS_ETR 46
+#define SC7280_MASTER_SDCC_1 47
+#define SC7280_MASTER_SDCC_2 48
+#define SC7280_MASTER_SDCC_4 49
+#define SC7280_MASTER_UFS_MEM 50
+#define SC7280_MASTER_USB2 51
+#define SC7280_MASTER_USB3_0 52
+#define SC7280_SLAVE_EBI1 53
+#define SC7280_SLAVE_AHB2PHY_SOUTH 54
+#define SC7280_SLAVE_AHB2PHY_NORTH 55
+#define SC7280_SLAVE_AOSS 56
+#define SC7280_SLAVE_APPSS 57
+#define SC7280_SLAVE_CAMERA_CFG 58
+#define SC7280_SLAVE_CLK_CTL 59
+#define SC7280_SLAVE_CDSP_CFG 60
+#define SC7280_SLAVE_RBCPR_CX_CFG 61
+#define SC7280_SLAVE_RBCPR_MX_CFG 62
+#define SC7280_SLAVE_CRYPTO_0_CFG 63
+#define SC7280_SLAVE_CX_RDPM 64
+#define SC7280_SLAVE_DCC_CFG 65
+#define SC7280_SLAVE_DISPLAY_CFG 66
+#define SC7280_SLAVE_GFX3D_CFG 67
+#define SC7280_SLAVE_HWKM 68
+#define SC7280_SLAVE_IMEM_CFG 69
+#define SC7280_SLAVE_IPA_CFG 70
+#define SC7280_SLAVE_IPC_ROUTER_CFG 71
+#define SC7280_SLAVE_LLCC_CFG 72
+#define SC7280_SLAVE_LPASS 73
+#define SC7280_SLAVE_LPASS_CORE_CFG 74
+#define SC7280_SLAVE_LPASS_LPI_CFG 75
+#define SC7280_SLAVE_LPASS_MPU_CFG 76
+#define SC7280_SLAVE_LPASS_TOP_CFG 77
+#define SC7280_SLAVE_MSS_PROC_MS_MPU_CFG 78
+#define SC7280_SLAVE_MCDMA_MS_MPU_CFG 79
+#define SC7280_SLAVE_CNOC_MSS 80
+#define SC7280_SLAVE_MX_RDPM 81
+#define SC7280_SLAVE_PCIE_0_CFG 82
+#define SC7280_SLAVE_PCIE_1_CFG 83
+#define SC7280_SLAVE_PDM 84
+#define SC7280_SLAVE_PIMEM_CFG 85
+#define SC7280_SLAVE_PKA_WRAPPER_CFG 86
+#define SC7280_SLAVE_PMU_WRAPPER_CFG 87
+#define SC7280_SLAVE_QDSS_CFG 88
+#define SC7280_SLAVE_QSPI_0 89
+#define SC7280_SLAVE_QUP_0 90
+#define SC7280_SLAVE_QUP_1 91
+#define SC7280_SLAVE_SDCC_1 92
+#define SC7280_SLAVE_SDCC_2 93
+#define SC7280_SLAVE_SDCC_4 94
+#define SC7280_SLAVE_SECURITY 95
+#define SC7280_SLAVE_TCSR 96
+#define SC7280_SLAVE_TLMM 97
+#define SC7280_SLAVE_UFS_MEM_CFG 98
+#define SC7280_SLAVE_USB2 99
+#define SC7280_SLAVE_USB3_0 100
+#define SC7280_SLAVE_VENUS_CFG 101
+#define SC7280_SLAVE_VSENSE_CTRL_CFG 102
+#define SC7280_SLAVE_A1NOC_CFG 103
+#define SC7280_SLAVE_A1NOC_SNOC 104
+#define SC7280_SLAVE_A2NOC_CFG 105
+#define SC7280_SLAVE_A2NOC_SNOC 106
+#define SC7280_SLAVE_CNOC2_CNOC3 107
+#define SC7280_SLAVE_CNOC3_CNOC2 108
+#define SC7280_SLAVE_CNOC_A2NOC 109
+#define SC7280_SLAVE_DDRSS_CFG 110
+#define SC7280_SLAVE_GEM_NOC_CNOC 111
+#define SC7280_SLAVE_GEM_NOC_CFG 112
+#define SC7280_SLAVE_SNOC_GEM_NOC_GC 113
+#define SC7280_SLAVE_SNOC_GEM_NOC_SF 114
+#define SC7280_SLAVE_LLCC 115
+#define SC7280_SLAVE_MNOC_HF_MEM_NOC 116
+#define SC7280_SLAVE_MNOC_SF_MEM_NOC 117
+#define SC7280_SLAVE_CNOC_MNOC_CFG 118
+#define SC7280_SLAVE_CDSP_MEM_NOC 119
+#define SC7280_SLAVE_MEM_NOC_PCIE_SNOC 120
+#define SC7280_SLAVE_ANOC_PCIE_GEM_NOC 121
+#define SC7280_SLAVE_SNOC_CFG 122
+#define SC7280_SLAVE_QUP_CORE_0 123
+#define SC7280_SLAVE_QUP_CORE_1 124
+#define SC7280_SLAVE_BOOT_IMEM 125
+#define SC7280_SLAVE_IMEM 126
+#define SC7280_SLAVE_PIMEM 127
+#define SC7280_SLAVE_SERVICE_NSP_NOC 128
+#define SC7280_SLAVE_SERVICE_A1NOC 129
+#define SC7280_SLAVE_SERVICE_A2NOC 130
+#define SC7280_SLAVE_SERVICE_GEM_NOC_1 131
+#define SC7280_SLAVE_SERVICE_MNOC 132
+#define SC7280_SLAVE_SERVICES_LPASS_AML_NOC 133
+#define SC7280_SLAVE_SERVICE_LPASS_AG_NOC 134
+#define SC7280_SLAVE_SERVICE_GEM_NOC_2 135
+#define SC7280_SLAVE_SERVICE_SNOC 136
+#define SC7280_SLAVE_SERVICE_GEM_NOC 137
+#define SC7280_SLAVE_PCIE_0 138
+#define SC7280_SLAVE_PCIE_1 139
+#define SC7280_SLAVE_QDSS_STM 140
+#define SC7280_SLAVE_TCU 141
+
+#endif
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 1f111b399bca..07b7c25cbed8 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -400,9 +400,11 @@ config HYPERV_IOMMU
config VIRTIO_IOMMU
tristate "Virtio IOMMU driver"
depends on VIRTIO
- depends on ARM64
+ depends on (ARM64 || X86)
select IOMMU_API
+ select IOMMU_DMA
select INTERVAL_TREE
+ select ACPI_VIOT if ACPI
help
Para-virtualised IOMMU driver with virtio.
diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index 55dd38d814d9..416815a525d6 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -11,8 +11,6 @@
#include "amd_iommu_types.h"
-extern int amd_iommu_init_dma_ops(void);
-extern int amd_iommu_init_passthrough(void);
extern irqreturn_t amd_iommu_int_thread(int irq, void *data);
extern irqreturn_t amd_iommu_int_handler(int irq, void *data);
extern void amd_iommu_apply_erratum_63(u16 devid);
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index d006724f4dc2..46280e6e1535 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -153,7 +153,8 @@ int amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_VAPIC;
static int amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE;
static bool amd_iommu_detected;
-static bool __initdata amd_iommu_disabled;
+static bool amd_iommu_disabled __initdata;
+static bool amd_iommu_force_enable __initdata;
static int amd_iommu_target_ivhd_type;
u16 amd_iommu_last_bdf; /* largest PCI device id we have
@@ -231,7 +232,6 @@ enum iommu_init_state {
IOMMU_ENABLED,
IOMMU_PCI_INIT,
IOMMU_INTERRUPTS_EN,
- IOMMU_DMA_OPS,
IOMMU_INITIALIZED,
IOMMU_NOT_FOUND,
IOMMU_INIT_ERROR,
@@ -1908,8 +1908,8 @@ static void print_iommu_info(void)
pci_info(pdev, "Found IOMMU cap 0x%x\n", iommu->cap_ptr);
if (iommu->cap & (1 << IOMMU_CAP_EFR)) {
- pci_info(pdev, "Extended features (%#llx):",
- iommu->features);
+ pr_info("Extended features (%#llx):", iommu->features);
+
for (i = 0; i < ARRAY_SIZE(feat_str); ++i) {
if (iommu_feature(iommu, (1ULL << i)))
pr_cont(" %s", feat_str[i]);
@@ -2817,7 +2817,7 @@ out:
return ret;
}
-static bool detect_ivrs(void)
+static bool __init detect_ivrs(void)
{
struct acpi_table_header *ivrs_base;
acpi_status status;
@@ -2834,6 +2834,9 @@ static bool detect_ivrs(void)
acpi_put_table(ivrs_base);
+ if (amd_iommu_force_enable)
+ goto out;
+
/* Don't use IOMMU if there is Stoney Ridge graphics */
for (i = 0; i < 32; i++) {
u32 pci_id;
@@ -2845,6 +2848,7 @@ static bool detect_ivrs(void)
}
}
+out:
/* Make sure ACS will be enabled during PCI probe */
pci_request_acs();
@@ -2895,10 +2899,6 @@ static int __init state_next(void)
init_state = ret ? IOMMU_INIT_ERROR : IOMMU_INTERRUPTS_EN;
break;
case IOMMU_INTERRUPTS_EN:
- ret = amd_iommu_init_dma_ops();
- init_state = ret ? IOMMU_INIT_ERROR : IOMMU_DMA_OPS;
- break;
- case IOMMU_DMA_OPS:
init_state = IOMMU_INITIALIZED;
break;
case IOMMU_INITIALIZED:
@@ -3100,6 +3100,8 @@ static int __init parse_amd_iommu_options(char *str)
for (; *str; ++str) {
if (strncmp(str, "fullflush", 9) == 0)
amd_iommu_unmap_flush = true;
+ if (strncmp(str, "force_enable", 12) == 0)
+ amd_iommu_force_enable = true;
if (strncmp(str, "off", 3) == 0)
amd_iommu_disabled = true;
if (strncmp(str, "force_isolation", 15) == 0)
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 3ac42bbdefc6..811a49a95d04 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -30,7 +30,6 @@
#include <linux/msi.h>
#include <linux/irqdomain.h>
#include <linux/percpu.h>
-#include <linux/iova.h>
#include <linux/io-pgtable.h>
#include <asm/irq_remapping.h>
#include <asm/io_apic.h>
@@ -1713,7 +1712,7 @@ static void amd_iommu_probe_finalize(struct device *dev)
/* Domains are initialized for this device - have a look what we ended up with */
domain = iommu_get_domain_for_dev(dev);
if (domain->type == IOMMU_DOMAIN_DMA)
- iommu_setup_dma_ops(dev, IOVA_START_PFN << PAGE_SHIFT, 0);
+ iommu_setup_dma_ops(dev, 0, U64_MAX);
else
set_dma_ops(dev, NULL);
}
@@ -1773,13 +1772,22 @@ void amd_iommu_domain_update(struct protection_domain *domain)
amd_iommu_domain_flush_complete(domain);
}
+static void __init amd_iommu_init_dma_ops(void)
+{
+ swiotlb = (iommu_default_passthrough() || sme_me_mask) ? 1 : 0;
+
+ if (amd_iommu_unmap_flush)
+ pr_info("IO/TLB flush on unmap enabled\n");
+ else
+ pr_info("Lazy IO/TLB flushing enabled\n");
+ iommu_set_dma_strict(amd_iommu_unmap_flush);
+}
+
int __init amd_iommu_init_api(void)
{
- int ret, err = 0;
+ int err;
- ret = iova_cache_get();
- if (ret)
- return ret;
+ amd_iommu_init_dma_ops();
err = bus_set_iommu(&pci_bus_type, &amd_iommu_ops);
if (err)
@@ -1796,19 +1804,6 @@ int __init amd_iommu_init_api(void)
return 0;
}
-int __init amd_iommu_init_dma_ops(void)
-{
- swiotlb = (iommu_default_passthrough() || sme_me_mask) ? 1 : 0;
-
- if (amd_iommu_unmap_flush)
- pr_info("IO/TLB flush on unmap enabled\n");
- else
- pr_info("Lazy IO/TLB flushing enabled\n");
- iommu_set_dma_strict(amd_iommu_unmap_flush);
- return 0;
-
-}
-
/*****************************************************************************
*
* The following functions belong to the exported interface of AMD IOMMU
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index bb251cab61f3..ee66d1f4cb81 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -435,9 +435,13 @@ bool arm_smmu_sva_supported(struct arm_smmu_device *smmu)
return true;
}
-static bool arm_smmu_iopf_supported(struct arm_smmu_master *master)
+bool arm_smmu_master_iopf_supported(struct arm_smmu_master *master)
{
- return false;
+ /* We're not keeping track of SIDs in fault events */
+ if (master->num_streams != 1)
+ return false;
+
+ return master->stall_enabled;
}
bool arm_smmu_master_sva_supported(struct arm_smmu_master *master)
@@ -445,8 +449,8 @@ bool arm_smmu_master_sva_supported(struct arm_smmu_master *master)
if (!(master->smmu->features & ARM_SMMU_FEAT_SVA))
return false;
- /* SSID and IOPF support are mandatory for the moment */
- return master->ssid_bits && arm_smmu_iopf_supported(master);
+ /* SSID support is mandatory for the moment */
+ return master->ssid_bits;
}
bool arm_smmu_master_sva_enabled(struct arm_smmu_master *master)
@@ -459,13 +463,55 @@ bool arm_smmu_master_sva_enabled(struct arm_smmu_master *master)
return enabled;
}
+static int arm_smmu_master_sva_enable_iopf(struct arm_smmu_master *master)
+{
+ int ret;
+ struct device *dev = master->dev;
+
+ /*
+ * Drivers for devices supporting PRI or stall should enable IOPF first.
+ * Others have device-specific fault handlers and don't need IOPF.
+ */
+ if (!arm_smmu_master_iopf_supported(master))
+ return 0;
+
+ if (!master->iopf_enabled)
+ return -EINVAL;
+
+ ret = iopf_queue_add_device(master->smmu->evtq.iopf, dev);
+ if (ret)
+ return ret;
+
+ ret = iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev);
+ if (ret) {
+ iopf_queue_remove_device(master->smmu->evtq.iopf, dev);
+ return ret;
+ }
+ return 0;
+}
+
+static void arm_smmu_master_sva_disable_iopf(struct arm_smmu_master *master)
+{
+ struct device *dev = master->dev;
+
+ if (!master->iopf_enabled)
+ return;
+
+ iommu_unregister_device_fault_handler(dev);
+ iopf_queue_remove_device(master->smmu->evtq.iopf, dev);
+}
+
int arm_smmu_master_enable_sva(struct arm_smmu_master *master)
{
+ int ret;
+
mutex_lock(&sva_lock);
- master->sva_enabled = true;
+ ret = arm_smmu_master_sva_enable_iopf(master);
+ if (!ret)
+ master->sva_enabled = true;
mutex_unlock(&sva_lock);
- return 0;
+ return ret;
}
int arm_smmu_master_disable_sva(struct arm_smmu_master *master)
@@ -476,6 +522,7 @@ int arm_smmu_master_disable_sva(struct arm_smmu_master *master)
mutex_unlock(&sva_lock);
return -EBUSY;
}
+ arm_smmu_master_sva_disable_iopf(master);
master->sva_enabled = false;
mutex_unlock(&sva_lock);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 54b2f27b81d4..235f9bdaeaf2 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -23,7 +23,6 @@
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_iommu.h>
#include <linux/of_platform.h>
#include <linux/pci.h>
#include <linux/pci-ats.h>
@@ -32,6 +31,7 @@
#include <linux/amba/bus.h>
#include "arm-smmu-v3.h"
+#include "../../iommu-sva-lib.h"
static bool disable_bypass = true;
module_param(disable_bypass, bool, 0444);
@@ -313,6 +313,11 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
}
cmd[1] |= FIELD_PREP(CMDQ_PRI_1_RESP, ent->pri.resp);
break;
+ case CMDQ_OP_RESUME:
+ cmd[0] |= FIELD_PREP(CMDQ_RESUME_0_SID, ent->resume.sid);
+ cmd[0] |= FIELD_PREP(CMDQ_RESUME_0_RESP, ent->resume.resp);
+ cmd[1] |= FIELD_PREP(CMDQ_RESUME_1_STAG, ent->resume.stag);
+ break;
case CMDQ_OP_CMD_SYNC:
if (ent->sync.msiaddr) {
cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_IRQ);
@@ -352,7 +357,7 @@ static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,
static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu)
{
- static const char *cerror_str[] = {
+ static const char * const cerror_str[] = {
[CMDQ_ERR_CERROR_NONE_IDX] = "No error",
[CMDQ_ERR_CERROR_ILL_IDX] = "Illegal command",
[CMDQ_ERR_CERROR_ABT_IDX] = "Abort on command fetch",
@@ -374,6 +379,7 @@ static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu)
switch (idx) {
case CMDQ_ERR_CERROR_ABT_IDX:
dev_err(smmu->dev, "retrying command fetch\n");
+ return;
case CMDQ_ERR_CERROR_NONE_IDX:
return;
case CMDQ_ERR_CERROR_ATC_INV_IDX:
@@ -876,6 +882,44 @@ static int arm_smmu_cmdq_batch_submit(struct arm_smmu_device *smmu,
return arm_smmu_cmdq_issue_cmdlist(smmu, cmds->cmds, cmds->num, true);
}
+static int arm_smmu_page_response(struct device *dev,
+ struct iommu_fault_event *unused,
+ struct iommu_page_response *resp)
+{
+ struct arm_smmu_cmdq_ent cmd = {0};
+ struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+ int sid = master->streams[0].id;
+
+ if (master->stall_enabled) {
+ cmd.opcode = CMDQ_OP_RESUME;
+ cmd.resume.sid = sid;
+ cmd.resume.stag = resp->grpid;
+ switch (resp->code) {
+ case IOMMU_PAGE_RESP_INVALID:
+ case IOMMU_PAGE_RESP_FAILURE:
+ cmd.resume.resp = CMDQ_RESUME_0_RESP_ABORT;
+ break;
+ case IOMMU_PAGE_RESP_SUCCESS:
+ cmd.resume.resp = CMDQ_RESUME_0_RESP_RETRY;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ return -ENODEV;
+ }
+
+ arm_smmu_cmdq_issue_cmd(master->smmu, &cmd);
+ /*
+ * Don't send a SYNC, it doesn't do anything for RESUME or PRI_RESP.
+ * RESUME consumption guarantees that the stalled transaction will be
+ * terminated... at some point in the future. PRI_RESP is fire and
+ * forget.
+ */
+
+ return 0;
+}
+
/* Context descriptor manipulation functions */
void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid)
{
@@ -986,7 +1030,6 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid,
u64 val;
bool cd_live;
__le64 *cdptr;
- struct arm_smmu_device *smmu = smmu_domain->smmu;
if (WARN_ON(ssid >= (1 << smmu_domain->s1_cfg.s1cdmax)))
return -E2BIG;
@@ -1031,8 +1074,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid,
FIELD_PREP(CTXDESC_CD_0_ASID, cd->asid) |
CTXDESC_CD_0_V;
- /* STALL_MODEL==0b10 && CD.S==0 is ILLEGAL */
- if (smmu->features & ARM_SMMU_FEAT_STALL_FORCE)
+ if (smmu_domain->stall_enabled)
val |= CTXDESC_CD_0_S;
}
@@ -1276,7 +1318,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
FIELD_PREP(STRTAB_STE_1_STRW, strw));
if (smmu->features & ARM_SMMU_FEAT_STALLS &&
- !(smmu->features & ARM_SMMU_FEAT_STALL_FORCE))
+ !master->stall_enabled)
dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD);
val |= (s1_cfg->cdcfg.cdtab_dma & STRTAB_STE_0_S1CTXPTR_MASK) |
@@ -1353,7 +1395,6 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
return 0;
}
-__maybe_unused
static struct arm_smmu_master *
arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid)
{
@@ -1377,18 +1418,118 @@ arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid)
}
/* IRQ and event handlers */
+static int arm_smmu_handle_evt(struct arm_smmu_device *smmu, u64 *evt)
+{
+ int ret;
+ u32 reason;
+ u32 perm = 0;
+ struct arm_smmu_master *master;
+ bool ssid_valid = evt[0] & EVTQ_0_SSV;
+ u32 sid = FIELD_GET(EVTQ_0_SID, evt[0]);
+ struct iommu_fault_event fault_evt = { };
+ struct iommu_fault *flt = &fault_evt.fault;
+
+ switch (FIELD_GET(EVTQ_0_ID, evt[0])) {
+ case EVT_ID_TRANSLATION_FAULT:
+ reason = IOMMU_FAULT_REASON_PTE_FETCH;
+ break;
+ case EVT_ID_ADDR_SIZE_FAULT:
+ reason = IOMMU_FAULT_REASON_OOR_ADDRESS;
+ break;
+ case EVT_ID_ACCESS_FAULT:
+ reason = IOMMU_FAULT_REASON_ACCESS;
+ break;
+ case EVT_ID_PERMISSION_FAULT:
+ reason = IOMMU_FAULT_REASON_PERMISSION;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ /* Stage-2 is always pinned at the moment */
+ if (evt[1] & EVTQ_1_S2)
+ return -EFAULT;
+
+ if (evt[1] & EVTQ_1_RnW)
+ perm |= IOMMU_FAULT_PERM_READ;
+ else
+ perm |= IOMMU_FAULT_PERM_WRITE;
+
+ if (evt[1] & EVTQ_1_InD)
+ perm |= IOMMU_FAULT_PERM_EXEC;
+
+ if (evt[1] & EVTQ_1_PnU)
+ perm |= IOMMU_FAULT_PERM_PRIV;
+
+ if (evt[1] & EVTQ_1_STALL) {
+ flt->type = IOMMU_FAULT_PAGE_REQ;
+ flt->prm = (struct iommu_fault_page_request) {
+ .flags = IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE,
+ .grpid = FIELD_GET(EVTQ_1_STAG, evt[1]),
+ .perm = perm,
+ .addr = FIELD_GET(EVTQ_2_ADDR, evt[2]),
+ };
+
+ if (ssid_valid) {
+ flt->prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
+ flt->prm.pasid = FIELD_GET(EVTQ_0_SSID, evt[0]);
+ }
+ } else {
+ flt->type = IOMMU_FAULT_DMA_UNRECOV;
+ flt->event = (struct iommu_fault_unrecoverable) {
+ .reason = reason,
+ .flags = IOMMU_FAULT_UNRECOV_ADDR_VALID,
+ .perm = perm,
+ .addr = FIELD_GET(EVTQ_2_ADDR, evt[2]),
+ };
+
+ if (ssid_valid) {
+ flt->event.flags |= IOMMU_FAULT_UNRECOV_PASID_VALID;
+ flt->event.pasid = FIELD_GET(EVTQ_0_SSID, evt[0]);
+ }
+ }
+
+ mutex_lock(&smmu->streams_mutex);
+ master = arm_smmu_find_master(smmu, sid);
+ if (!master) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ ret = iommu_report_device_fault(master->dev, &fault_evt);
+ if (ret && flt->type == IOMMU_FAULT_PAGE_REQ) {
+ /* Nobody cared, abort the access */
+ struct iommu_page_response resp = {
+ .pasid = flt->prm.pasid,
+ .grpid = flt->prm.grpid,
+ .code = IOMMU_PAGE_RESP_FAILURE,
+ };
+ arm_smmu_page_response(master->dev, &fault_evt, &resp);
+ }
+
+out_unlock:
+ mutex_unlock(&smmu->streams_mutex);
+ return ret;
+}
+
static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
{
- int i;
+ int i, ret;
struct arm_smmu_device *smmu = dev;
struct arm_smmu_queue *q = &smmu->evtq.q;
struct arm_smmu_ll_queue *llq = &q->llq;
+ static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
+ DEFAULT_RATELIMIT_BURST);
u64 evt[EVTQ_ENT_DWORDS];
do {
while (!queue_remove_raw(q, evt)) {
u8 id = FIELD_GET(EVTQ_0_ID, evt[0]);
+ ret = arm_smmu_handle_evt(smmu, evt);
+ if (!ret || !__ratelimit(&rs))
+ continue;
+
dev_info(smmu->dev, "event 0x%02x received:\n", id);
for (i = 0; i < ARRAY_SIZE(evt); ++i)
dev_info(smmu->dev, "\t0x%016llx\n",
@@ -1923,6 +2064,8 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
cfg->s1cdmax = master->ssid_bits;
+ smmu_domain->stall_enabled = master->stall_enabled;
+
ret = arm_smmu_alloc_cd_tables(smmu_domain);
if (ret)
goto out_free_asid;
@@ -2270,6 +2413,12 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
smmu_domain->s1_cfg.s1cdmax, master->ssid_bits);
ret = -EINVAL;
goto out_unlock;
+ } else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 &&
+ smmu_domain->stall_enabled != master->stall_enabled) {
+ dev_err(dev, "cannot attach to stall-%s domain\n",
+ smmu_domain->stall_enabled ? "enabled" : "disabled");
+ ret = -EINVAL;
+ goto out_unlock;
}
master->domain = smmu_domain;
@@ -2508,6 +2657,11 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
master->ssid_bits = min_t(u8, master->ssid_bits,
CTXDESC_LINEAR_CDMAX);
+ if ((smmu->features & ARM_SMMU_FEAT_STALLS &&
+ device_property_read_bool(dev, "dma-can-stall")) ||
+ smmu->features & ARM_SMMU_FEAT_STALL_FORCE)
+ master->stall_enabled = true;
+
return &smmu->iommu;
err_free_master:
@@ -2525,7 +2679,8 @@ static void arm_smmu_release_device(struct device *dev)
return;
master = dev_iommu_priv_get(dev);
- WARN_ON(arm_smmu_master_sva_enabled(master));
+ if (WARN_ON(arm_smmu_master_sva_enabled(master)))
+ iopf_queue_remove_device(master->smmu->evtq.iopf, dev);
arm_smmu_detach_dev(master);
arm_smmu_disable_pasid(master);
arm_smmu_remove_master(master);
@@ -2595,6 +2750,8 @@ static bool arm_smmu_dev_has_feature(struct device *dev,
return false;
switch (feat) {
+ case IOMMU_DEV_FEAT_IOPF:
+ return arm_smmu_master_iopf_supported(master);
case IOMMU_DEV_FEAT_SVA:
return arm_smmu_master_sva_supported(master);
default:
@@ -2611,6 +2768,8 @@ static bool arm_smmu_dev_feature_enabled(struct device *dev,
return false;
switch (feat) {
+ case IOMMU_DEV_FEAT_IOPF:
+ return master->iopf_enabled;
case IOMMU_DEV_FEAT_SVA:
return arm_smmu_master_sva_enabled(master);
default:
@@ -2621,6 +2780,8 @@ static bool arm_smmu_dev_feature_enabled(struct device *dev,
static int arm_smmu_dev_enable_feature(struct device *dev,
enum iommu_dev_features feat)
{
+ struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+
if (!arm_smmu_dev_has_feature(dev, feat))
return -ENODEV;
@@ -2628,8 +2789,11 @@ static int arm_smmu_dev_enable_feature(struct device *dev,
return -EBUSY;
switch (feat) {
+ case IOMMU_DEV_FEAT_IOPF:
+ master->iopf_enabled = true;
+ return 0;
case IOMMU_DEV_FEAT_SVA:
- return arm_smmu_master_enable_sva(dev_iommu_priv_get(dev));
+ return arm_smmu_master_enable_sva(master);
default:
return -EINVAL;
}
@@ -2638,12 +2802,19 @@ static int arm_smmu_dev_enable_feature(struct device *dev,
static int arm_smmu_dev_disable_feature(struct device *dev,
enum iommu_dev_features feat)
{
+ struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+
if (!arm_smmu_dev_feature_enabled(dev, feat))
return -EINVAL;
switch (feat) {
+ case IOMMU_DEV_FEAT_IOPF:
+ if (master->sva_enabled)
+ return -EBUSY;
+ master->iopf_enabled = false;
+ return 0;
case IOMMU_DEV_FEAT_SVA:
- return arm_smmu_master_disable_sva(dev_iommu_priv_get(dev));
+ return arm_smmu_master_disable_sva(master);
default:
return -EINVAL;
}
@@ -2673,6 +2844,7 @@ static struct iommu_ops arm_smmu_ops = {
.sva_bind = arm_smmu_sva_bind,
.sva_unbind = arm_smmu_sva_unbind,
.sva_get_pasid = arm_smmu_sva_get_pasid,
+ .page_response = arm_smmu_page_response,
.pgsize_bitmap = -1UL, /* Restricted during device attach */
.owner = THIS_MODULE,
};
@@ -2771,6 +2943,13 @@ static int arm_smmu_init_queues(struct arm_smmu_device *smmu)
if (ret)
return ret;
+ if ((smmu->features & ARM_SMMU_FEAT_SVA) &&
+ (smmu->features & ARM_SMMU_FEAT_STALLS)) {
+ smmu->evtq.iopf = iopf_queue_alloc(dev_name(smmu->dev));
+ if (!smmu->evtq.iopf)
+ return -ENOMEM;
+ }
+
/* priq */
if (!(smmu->features & ARM_SMMU_FEAT_PRI))
return 0;
@@ -2788,10 +2967,8 @@ static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu)
void *strtab = smmu->strtab_cfg.strtab;
cfg->l1_desc = devm_kzalloc(smmu->dev, size, GFP_KERNEL);
- if (!cfg->l1_desc) {
- dev_err(smmu->dev, "failed to allocate l1 stream table desc\n");
+ if (!cfg->l1_desc)
return -ENOMEM;
- }
for (i = 0; i < cfg->num_l1_ents; ++i) {
arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
@@ -3582,10 +3759,8 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
bool bypass;
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
- if (!smmu) {
- dev_err(dev, "failed to allocate arm_smmu_device\n");
+ if (!smmu)
return -ENOMEM;
- }
smmu->dev = dev;
if (dev->of_node) {
@@ -3669,10 +3844,20 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
ret = iommu_device_register(&smmu->iommu, &arm_smmu_ops, dev);
if (ret) {
dev_err(dev, "Failed to register iommu\n");
- return ret;
+ goto err_sysfs_remove;
}
- return arm_smmu_set_bus_ops(&arm_smmu_ops);
+ ret = arm_smmu_set_bus_ops(&arm_smmu_ops);
+ if (ret)
+ goto err_unregister_device;
+
+ return 0;
+
+err_unregister_device:
+ iommu_device_unregister(&smmu->iommu);
+err_sysfs_remove:
+ iommu_device_sysfs_remove(&smmu->iommu);
+ return ret;
}
static int arm_smmu_device_remove(struct platform_device *pdev)
@@ -3683,6 +3868,7 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
iommu_device_unregister(&smmu->iommu);
iommu_device_sysfs_remove(&smmu->iommu);
arm_smmu_device_disable(smmu);
+ iopf_queue_free(smmu->evtq.iopf);
return 0;
}
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 46e8c49214a8..4cb136f07914 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -184,6 +184,7 @@
#else
#define Q_MAX_SZ_SHIFT (PAGE_SHIFT + MAX_ORDER - 1)
#endif
+#define Q_MIN_SZ_SHIFT (PAGE_SHIFT)
/*
* Stream table.
@@ -354,6 +355,13 @@
#define CMDQ_PRI_1_GRPID GENMASK_ULL(8, 0)
#define CMDQ_PRI_1_RESP GENMASK_ULL(13, 12)
+#define CMDQ_RESUME_0_RESP_TERM 0UL
+#define CMDQ_RESUME_0_RESP_RETRY 1UL
+#define CMDQ_RESUME_0_RESP_ABORT 2UL
+#define CMDQ_RESUME_0_RESP GENMASK_ULL(13, 12)
+#define CMDQ_RESUME_0_SID GENMASK_ULL(63, 32)
+#define CMDQ_RESUME_1_STAG GENMASK_ULL(15, 0)
+
#define CMDQ_SYNC_0_CS GENMASK_ULL(13, 12)
#define CMDQ_SYNC_0_CS_NONE 0
#define CMDQ_SYNC_0_CS_IRQ 1
@@ -366,14 +374,33 @@
/* Event queue */
#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_MAX_SZ_SHIFT (Q_MIN_SZ_SHIFT - EVTQ_ENT_SZ_SHIFT)
#define EVTQ_0_ID GENMASK_ULL(7, 0)
+#define EVT_ID_TRANSLATION_FAULT 0x10
+#define EVT_ID_ADDR_SIZE_FAULT 0x11
+#define EVT_ID_ACCESS_FAULT 0x12
+#define EVT_ID_PERMISSION_FAULT 0x13
+
+#define EVTQ_0_SSV (1UL << 11)
+#define EVTQ_0_SSID GENMASK_ULL(31, 12)
+#define EVTQ_0_SID GENMASK_ULL(63, 32)
+#define EVTQ_1_STAG GENMASK_ULL(15, 0)
+#define EVTQ_1_STALL (1UL << 31)
+#define EVTQ_1_PnU (1UL << 33)
+#define EVTQ_1_InD (1UL << 34)
+#define EVTQ_1_RnW (1UL << 35)
+#define EVTQ_1_S2 (1UL << 39)
+#define EVTQ_1_CLASS GENMASK_ULL(41, 40)
+#define EVTQ_1_TT_READ (1UL << 44)
+#define EVTQ_2_ADDR GENMASK_ULL(63, 0)
+#define EVTQ_3_IPA GENMASK_ULL(51, 12)
+
/* PRI queue */
#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_MAX_SZ_SHIFT (Q_MIN_SZ_SHIFT - PRIQ_ENT_SZ_SHIFT)
#define PRIQ_0_SID GENMASK_ULL(31, 0)
#define PRIQ_0_SSID GENMASK_ULL(51, 32)
@@ -462,6 +489,13 @@ struct arm_smmu_cmdq_ent {
enum pri_resp resp;
} pri;
+ #define CMDQ_OP_RESUME 0x44
+ struct {
+ u32 sid;
+ u16 stag;
+ u8 resp;
+ } resume;
+
#define CMDQ_OP_CMD_SYNC 0x46
struct {
u64 msiaddr;
@@ -520,6 +554,7 @@ struct arm_smmu_cmdq_batch {
struct arm_smmu_evtq {
struct arm_smmu_queue q;
+ struct iopf_queue *iopf;
u32 max_stalls;
};
@@ -657,7 +692,9 @@ struct arm_smmu_master {
struct arm_smmu_stream *streams;
unsigned int num_streams;
bool ats_enabled;
+ bool stall_enabled;
bool sva_enabled;
+ bool iopf_enabled;
struct list_head bonds;
unsigned int ssid_bits;
};
@@ -675,6 +712,7 @@ struct arm_smmu_domain {
struct mutex init_mutex; /* Protects smmu pointer */
struct io_pgtable_ops *pgtbl_ops;
+ bool stall_enabled;
atomic_t nr_ats_masters;
enum arm_smmu_domain_stage stage;
@@ -716,6 +754,7 @@ bool arm_smmu_master_sva_supported(struct arm_smmu_master *master);
bool arm_smmu_master_sva_enabled(struct arm_smmu_master *master);
int arm_smmu_master_enable_sva(struct arm_smmu_master *master);
int arm_smmu_master_disable_sva(struct arm_smmu_master *master);
+bool arm_smmu_master_iopf_supported(struct arm_smmu_master *master);
struct iommu_sva *arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm,
void *drvdata);
void arm_smmu_sva_unbind(struct iommu_sva *handle);
@@ -747,6 +786,11 @@ static inline int arm_smmu_master_disable_sva(struct arm_smmu_master *master)
return -ENODEV;
}
+static inline bool arm_smmu_master_iopf_supported(struct arm_smmu_master *master)
+{
+ return false;
+}
+
static inline struct iommu_sva *
arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm, void *drvdata)
{
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c b/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c
index 136872e77195..9f465e146799 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c
@@ -211,7 +211,8 @@ struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu)
if (of_property_read_bool(np, "calxeda,smmu-secure-config-access"))
smmu->impl = &calxeda_impl;
- if (of_device_is_compatible(np, "nvidia,tegra194-smmu"))
+ if (of_device_is_compatible(np, "nvidia,tegra194-smmu") ||
+ of_device_is_compatible(np, "nvidia,tegra186-smmu"))
return nvidia_smmu_impl_init(smmu);
smmu = qcom_smmu_impl_init(smmu);
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c b/drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c
index 29117444e5a0..01e9b50b10a1 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-nvidia.c
@@ -7,6 +7,8 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <soc/tegra/mc.h>
+
#include "arm-smmu.h"
/*
@@ -15,18 +17,32 @@
* interleaved IOVA accesses across them and translates accesses from
* non-isochronous HW devices.
* Third one is used for translating accesses from isochronous HW devices.
+ *
+ * In addition, the SMMU driver needs to coordinate with the memory controller
+ * driver to ensure that the right SID override is programmed for any given
+ * memory client. This is necessary to allow for use-case such as seamlessly
+ * handing over the display controller configuration from the firmware to the
+ * kernel.
+ *
* This implementation supports programming of the two instances that must
- * be programmed identically.
- * The third instance usage is through standard arm-smmu driver itself and
- * is out of scope of this implementation.
+ * be programmed identically and takes care of invoking the memory controller
+ * driver for SID override programming after devices have been attached to an
+ * SMMU instance.
*/
-#define NUM_SMMU_INSTANCES 2
+#define MAX_SMMU_INSTANCES 2
struct nvidia_smmu {
- struct arm_smmu_device smmu;
- void __iomem *bases[NUM_SMMU_INSTANCES];
+ struct arm_smmu_device smmu;
+ void __iomem *bases[MAX_SMMU_INSTANCES];
+ unsigned int num_instances;
+ struct tegra_mc *mc;
};
+static inline struct nvidia_smmu *to_nvidia_smmu(struct arm_smmu_device *smmu)
+{
+ return container_of(smmu, struct nvidia_smmu, smmu);
+}
+
static inline void __iomem *nvidia_smmu_page(struct arm_smmu_device *smmu,
unsigned int inst, int page)
{
@@ -47,9 +63,10 @@ static u32 nvidia_smmu_read_reg(struct arm_smmu_device *smmu,
static void nvidia_smmu_write_reg(struct arm_smmu_device *smmu,
int page, int offset, u32 val)
{
+ struct nvidia_smmu *nvidia = to_nvidia_smmu(smmu);
unsigned int i;
- for (i = 0; i < NUM_SMMU_INSTANCES; i++) {
+ for (i = 0; i < nvidia->num_instances; i++) {
void __iomem *reg = nvidia_smmu_page(smmu, i, page) + offset;
writel_relaxed(val, reg);
@@ -67,9 +84,10 @@ static u64 nvidia_smmu_read_reg64(struct arm_smmu_device *smmu,
static void nvidia_smmu_write_reg64(struct arm_smmu_device *smmu,
int page, int offset, u64 val)
{
+ struct nvidia_smmu *nvidia = to_nvidia_smmu(smmu);
unsigned int i;
- for (i = 0; i < NUM_SMMU_INSTANCES; i++) {
+ for (i = 0; i < nvidia->num_instances; i++) {
void __iomem *reg = nvidia_smmu_page(smmu, i, page) + offset;
writeq_relaxed(val, reg);
@@ -79,6 +97,7 @@ static void nvidia_smmu_write_reg64(struct arm_smmu_device *smmu,
static void nvidia_smmu_tlb_sync(struct arm_smmu_device *smmu, int page,
int sync, int status)
{
+ struct nvidia_smmu *nvidia = to_nvidia_smmu(smmu);
unsigned int delay;
arm_smmu_writel(smmu, page, sync, 0);
@@ -90,7 +109,7 @@ static void nvidia_smmu_tlb_sync(struct arm_smmu_device *smmu, int page,
u32 val = 0;
unsigned int i;
- for (i = 0; i < NUM_SMMU_INSTANCES; i++) {
+ for (i = 0; i < nvidia->num_instances; i++) {
void __iomem *reg;
reg = nvidia_smmu_page(smmu, i, page) + status;
@@ -112,9 +131,10 @@ static void nvidia_smmu_tlb_sync(struct arm_smmu_device *smmu, int page,
static int nvidia_smmu_reset(struct arm_smmu_device *smmu)
{
+ struct nvidia_smmu *nvidia = to_nvidia_smmu(smmu);
unsigned int i;
- for (i = 0; i < NUM_SMMU_INSTANCES; i++) {
+ for (i = 0; i < nvidia->num_instances; i++) {
u32 val;
void __iomem *reg = nvidia_smmu_page(smmu, i, ARM_SMMU_GR0) +
ARM_SMMU_GR0_sGFSR;
@@ -157,8 +177,9 @@ static irqreturn_t nvidia_smmu_global_fault(int irq, void *dev)
unsigned int inst;
irqreturn_t ret = IRQ_NONE;
struct arm_smmu_device *smmu = dev;
+ struct nvidia_smmu *nvidia = to_nvidia_smmu(smmu);
- for (inst = 0; inst < NUM_SMMU_INSTANCES; inst++) {
+ for (inst = 0; inst < nvidia->num_instances; inst++) {
irqreturn_t irq_ret;
irq_ret = nvidia_smmu_global_fault_inst(irq, smmu, inst);
@@ -202,11 +223,13 @@ static irqreturn_t nvidia_smmu_context_fault(int irq, void *dev)
struct arm_smmu_device *smmu;
struct iommu_domain *domain = dev;
struct arm_smmu_domain *smmu_domain;
+ struct nvidia_smmu *nvidia;
smmu_domain = container_of(domain, struct arm_smmu_domain, domain);
smmu = smmu_domain->smmu;
+ nvidia = to_nvidia_smmu(smmu);
- for (inst = 0; inst < NUM_SMMU_INSTANCES; inst++) {
+ for (inst = 0; inst < nvidia->num_instances; inst++) {
irqreturn_t irq_ret;
/*
@@ -224,6 +247,17 @@ static irqreturn_t nvidia_smmu_context_fault(int irq, void *dev)
return ret;
}
+static void nvidia_smmu_probe_finalize(struct arm_smmu_device *smmu, struct device *dev)
+{
+ struct nvidia_smmu *nvidia = to_nvidia_smmu(smmu);
+ int err;
+
+ err = tegra_mc_probe_device(nvidia->mc, dev);
+ if (err < 0)
+ dev_err(smmu->dev, "memory controller probe failed for %s: %d\n",
+ dev_name(dev), err);
+}
+
static const struct arm_smmu_impl nvidia_smmu_impl = {
.read_reg = nvidia_smmu_read_reg,
.write_reg = nvidia_smmu_write_reg,
@@ -233,6 +267,11 @@ static const struct arm_smmu_impl nvidia_smmu_impl = {
.tlb_sync = nvidia_smmu_tlb_sync,
.global_fault = nvidia_smmu_global_fault,
.context_fault = nvidia_smmu_context_fault,
+ .probe_finalize = nvidia_smmu_probe_finalize,
+};
+
+static const struct arm_smmu_impl nvidia_smmu_single_impl = {
+ .probe_finalize = nvidia_smmu_probe_finalize,
};
struct arm_smmu_device *nvidia_smmu_impl_init(struct arm_smmu_device *smmu)
@@ -241,23 +280,36 @@ struct arm_smmu_device *nvidia_smmu_impl_init(struct arm_smmu_device *smmu)
struct device *dev = smmu->dev;
struct nvidia_smmu *nvidia_smmu;
struct platform_device *pdev = to_platform_device(dev);
+ unsigned int i;
nvidia_smmu = devm_krealloc(dev, smmu, sizeof(*nvidia_smmu), GFP_KERNEL);
if (!nvidia_smmu)
return ERR_PTR(-ENOMEM);
+ nvidia_smmu->mc = devm_tegra_memory_controller_get(dev);
+ if (IS_ERR(nvidia_smmu->mc))
+ return ERR_CAST(nvidia_smmu->mc);
+
/* Instance 0 is ioremapped by arm-smmu.c. */
nvidia_smmu->bases[0] = smmu->base;
+ nvidia_smmu->num_instances++;
+
+ for (i = 1; i < MAX_SMMU_INSTANCES; i++) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res)
+ break;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!res)
- return ERR_PTR(-ENODEV);
+ nvidia_smmu->bases[i] = devm_ioremap_resource(dev, res);
+ if (IS_ERR(nvidia_smmu->bases[i]))
+ return ERR_CAST(nvidia_smmu->bases[i]);
- nvidia_smmu->bases[1] = devm_ioremap_resource(dev, res);
- if (IS_ERR(nvidia_smmu->bases[1]))
- return ERR_CAST(nvidia_smmu->bases[1]);
+ nvidia_smmu->num_instances++;
+ }
- nvidia_smmu->smmu.impl = &nvidia_smmu_impl;
+ if (nvidia_smmu->num_instances == 1)
+ nvidia_smmu->smmu.impl = &nvidia_smmu_single_impl;
+ else
+ nvidia_smmu->smmu.impl = &nvidia_smmu_impl;
return &nvidia_smmu->smmu;
}
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
index 61fc645c1325..9b9d13ec5a88 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
@@ -3,6 +3,7 @@
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/
+#include <linux/acpi.h>
#include <linux/adreno-smmu-priv.h>
#include <linux/of_device.h>
#include <linux/qcom_scm.h>
@@ -177,6 +178,16 @@ static int qcom_adreno_smmu_alloc_context_bank(struct arm_smmu_domain *smmu_doma
return __arm_smmu_alloc_bitmap(smmu->context_map, start, count);
}
+static bool qcom_adreno_can_do_ttbr1(struct arm_smmu_device *smmu)
+{
+ const struct device_node *np = smmu->dev->of_node;
+
+ if (of_device_is_compatible(np, "qcom,msm8996-smmu-v2"))
+ return false;
+
+ return true;
+}
+
static int qcom_adreno_smmu_init_context(struct arm_smmu_domain *smmu_domain,
struct io_pgtable_cfg *pgtbl_cfg, struct device *dev)
{
@@ -191,7 +202,8 @@ static int qcom_adreno_smmu_init_context(struct arm_smmu_domain *smmu_domain,
* be AARCH64 stage 1 but double check because the arm-smmu code assumes
* that is the case when the TTBR1 quirk is enabled
*/
- if ((smmu_domain->stage == ARM_SMMU_DOMAIN_S1) &&
+ if (qcom_adreno_can_do_ttbr1(smmu_domain->smmu) &&
+ (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) &&
(smmu_domain->cfg.fmt == ARM_SMMU_CTX_FMT_AARCH64))
pgtbl_cfg->quirks |= IO_PGTABLE_QUIRK_ARM_TTBR1;
@@ -216,6 +228,7 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = {
{ .compatible = "qcom,mdss" },
{ .compatible = "qcom,sc7180-mdss" },
{ .compatible = "qcom,sc7180-mss-pil" },
+ { .compatible = "qcom,sc7280-mdss" },
{ .compatible = "qcom,sc8180x-mdss" },
{ .compatible = "qcom,sdm845-mdss" },
{ .compatible = "qcom,sdm845-mss-pil" },
@@ -380,24 +393,48 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu,
static const struct of_device_id __maybe_unused qcom_smmu_impl_of_match[] = {
{ .compatible = "qcom,msm8998-smmu-v2" },
{ .compatible = "qcom,sc7180-smmu-500" },
+ { .compatible = "qcom,sc7280-smmu-500" },
{ .compatible = "qcom,sc8180x-smmu-500" },
{ .compatible = "qcom,sdm630-smmu-v2" },
{ .compatible = "qcom,sdm845-smmu-500" },
+ { .compatible = "qcom,sm6125-smmu-500" },
{ .compatible = "qcom,sm8150-smmu-500" },
{ .compatible = "qcom,sm8250-smmu-500" },
{ .compatible = "qcom,sm8350-smmu-500" },
{ }
};
+#ifdef CONFIG_ACPI
+static struct acpi_platform_list qcom_acpi_platlist[] = {
+ { "LENOVO", "CB-01 ", 0x8180, ACPI_SIG_IORT, equal, "QCOM SMMU" },
+ { "QCOM ", "QCOMEDK2", 0x8180, ACPI_SIG_IORT, equal, "QCOM SMMU" },
+ { }
+};
+#endif
+
struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu)
{
const struct device_node *np = smmu->dev->of_node;
- if (of_match_node(qcom_smmu_impl_of_match, np))
- return qcom_smmu_create(smmu, &qcom_smmu_impl);
+#ifdef CONFIG_ACPI
+ if (np == NULL) {
+ /* Match platform for ACPI boot */
+ if (acpi_match_platform_list(qcom_acpi_platlist) >= 0)
+ return qcom_smmu_create(smmu, &qcom_smmu_impl);
+ }
+#endif
+ /*
+ * Do not change this order of implementation, i.e., first adreno
+ * smmu impl and then apss smmu since we can have both implementing
+ * arm,mmu-500 in which case we will miss setting adreno smmu specific
+ * features if the order is changed.
+ */
if (of_device_is_compatible(np, "qcom,adreno-smmu"))
return qcom_smmu_create(smmu, &qcom_adreno_smmu_impl);
+ if (of_match_node(qcom_smmu_impl_of_match, np))
+ return qcom_smmu_create(smmu, &qcom_smmu_impl);
+
return smmu;
}
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index b4b32d31fc06..f22dbeb1e510 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -31,7 +31,6 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
-#include <linux/of_iommu.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -74,7 +73,7 @@ static bool using_legacy_binding, using_generic_binding;
static inline int arm_smmu_rpm_get(struct arm_smmu_device *smmu)
{
if (pm_runtime_enabled(smmu->dev))
- return pm_runtime_get_sync(smmu->dev);
+ return pm_runtime_resume_and_get(smmu->dev);
return 0;
}
@@ -1276,6 +1275,7 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
u64 phys;
unsigned long va, flags;
int ret, idx = cfg->cbndx;
+ phys_addr_t addr = 0;
ret = arm_smmu_rpm_get(smmu);
if (ret < 0)
@@ -1295,6 +1295,7 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
dev_err(dev,
"iova to phys timed out on %pad. Falling back to software table walk.\n",
&iova);
+ arm_smmu_rpm_put(smmu);
return ops->iova_to_phys(ops, iova);
}
@@ -1303,12 +1304,14 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
if (phys & ARM_SMMU_CB_PAR_F) {
dev_err(dev, "translation fault!\n");
dev_err(dev, "PAR = 0x%llx\n", phys);
- return 0;
+ goto out;
}
+ addr = (phys & GENMASK_ULL(39, 12)) | (iova & 0xfff);
+out:
arm_smmu_rpm_put(smmu);
- return (phys & GENMASK_ULL(39, 12)) | (iova & 0xfff);
+ return addr;
}
static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,
@@ -1455,6 +1458,18 @@ static void arm_smmu_release_device(struct device *dev)
iommu_fwspec_free(dev);
}
+static void arm_smmu_probe_finalize(struct device *dev)
+{
+ struct arm_smmu_master_cfg *cfg;
+ struct arm_smmu_device *smmu;
+
+ cfg = dev_iommu_priv_get(dev);
+ smmu = cfg->smmu;
+
+ if (smmu->impl && smmu->impl->probe_finalize)
+ smmu->impl->probe_finalize(smmu, dev);
+}
+
static struct iommu_group *arm_smmu_device_group(struct device *dev)
{
struct arm_smmu_master_cfg *cfg = dev_iommu_priv_get(dev);
@@ -1574,6 +1589,7 @@ static struct iommu_ops arm_smmu_ops = {
.iova_to_phys = arm_smmu_iova_to_phys,
.probe_device = arm_smmu_probe_device,
.release_device = arm_smmu_release_device,
+ .probe_finalize = arm_smmu_probe_finalize,
.device_group = arm_smmu_device_group,
.enable_nesting = arm_smmu_enable_nesting,
.set_pgtable_quirks = arm_smmu_set_pgtable_quirks,
@@ -2169,7 +2185,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
err = iommu_device_register(&smmu->iommu, &arm_smmu_ops, dev);
if (err) {
dev_err(dev, "Failed to register iommu\n");
- return err;
+ goto err_sysfs_remove;
}
platform_set_drvdata(pdev, smmu);
@@ -2192,10 +2208,19 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
* any device which might need it, so we want the bus ops in place
* ready to handle default domain setup as soon as any SMMU exists.
*/
- if (!using_legacy_binding)
- return arm_smmu_bus_init(&arm_smmu_ops);
+ if (!using_legacy_binding) {
+ err = arm_smmu_bus_init(&arm_smmu_ops);
+ if (err)
+ goto err_unregister_device;
+ }
return 0;
+
+err_unregister_device:
+ iommu_device_unregister(&smmu->iommu);
+err_sysfs_remove:
+ iommu_device_sysfs_remove(&smmu->iommu);
+ return err;
}
static int arm_smmu_device_remove(struct platform_device *pdev)
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.h b/drivers/iommu/arm/arm-smmu/arm-smmu.h
index 84c21c4b0691..a50271595960 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.h
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.h
@@ -441,6 +441,7 @@ struct arm_smmu_impl {
struct device *dev, int start);
void (*write_s2cr)(struct arm_smmu_device *smmu, int idx);
void (*write_sctlr)(struct arm_smmu_device *smmu, int idx, u32 reg);
+ void (*probe_finalize)(struct arm_smmu_device *smmu, struct device *dev);
};
#define INVALID_SMENDX -1
diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
index 4294abe389b2..021cf8f65ffc 100644
--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
@@ -25,7 +25,6 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
-#include <linux/of_iommu.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 7bcdd1205535..98ba927aee1a 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -243,9 +243,11 @@ resv_iova:
lo = iova_pfn(iovad, start);
hi = iova_pfn(iovad, end);
reserve_iova(iovad, lo, hi);
- } else {
+ } else if (end < start) {
/* dma_ranges list should be sorted */
- dev_err(&dev->dev, "Failed to reserve IOVA\n");
+ dev_err(&dev->dev,
+ "Failed to reserve IOVA [%pa-%pa]\n",
+ &start, &end);
return -EINVAL;
}
@@ -319,16 +321,16 @@ static bool dev_is_untrusted(struct device *dev)
* iommu_dma_init_domain - Initialise a DMA mapping domain
* @domain: IOMMU domain previously prepared by iommu_get_dma_cookie()
* @base: IOVA at which the mappable address space starts
- * @size: Size of IOVA space
+ * @limit: Last address of the IOVA space
* @dev: Device the domain is being initialised for
*
- * @base and @size should be exact multiples of IOMMU page granularity to
+ * @base and @limit + 1 should be exact multiples of IOMMU page granularity to
* avoid rounding surprises. If necessary, we reserve the page at address 0
* 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.
*/
static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
- u64 size, struct device *dev)
+ dma_addr_t limit, struct device *dev)
{
struct iommu_dma_cookie *cookie = domain->iova_cookie;
unsigned long order, base_pfn;
@@ -346,7 +348,7 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
/* Check the domain allows at least some access to the device... */
if (domain->geometry.force_aperture) {
if (base > domain->geometry.aperture_end ||
- base + size <= domain->geometry.aperture_start) {
+ limit < domain->geometry.aperture_start) {
pr_warn("specified DMA range outside IOMMU capability\n");
return -EFAULT;
}
@@ -1308,7 +1310,7 @@ static const struct dma_map_ops iommu_dma_ops = {
* 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)
+void iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 dma_limit)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
@@ -1320,7 +1322,7 @@ void iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size)
* 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))
+ if (iommu_dma_init_domain(domain, dma_base, dma_limit, dev))
goto out_err;
dev->dma_ops = &iommu_dma_ops;
}
@@ -1330,6 +1332,7 @@ out_err:
pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
dev_name(dev));
}
+EXPORT_SYMBOL_GPL(iommu_setup_dma_ops);
static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
phys_addr_t msi_addr, struct iommu_domain *domain)
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 7623d8c371f5..d0fbf1d10e18 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -17,7 +17,6 @@
#include <linux/kmemleak.h>
#include <linux/list.h>
#include <linux/of.h>
-#include <linux/of_iommu.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/iommu/intel/Kconfig b/drivers/iommu/intel/Kconfig
index 28a3d1596c76..43ebd8af11c5 100644
--- a/drivers/iommu/intel/Kconfig
+++ b/drivers/iommu/intel/Kconfig
@@ -3,6 +3,9 @@
config DMAR_TABLE
bool
+config DMAR_PERF
+ bool
+
config INTEL_IOMMU
bool "Support for Intel IOMMU using DMA Remapping Devices"
depends on PCI_MSI && ACPI && (X86 || IA64)
@@ -14,6 +17,7 @@ config INTEL_IOMMU
select SWIOTLB
select IOASID
select IOMMU_DMA
+ select PCI_ATS
help
DMA remapping (DMAR) devices support enables independent address
translations for Direct Memory Access (DMA) from devices.
@@ -24,6 +28,7 @@ config INTEL_IOMMU
config INTEL_IOMMU_DEBUGFS
bool "Export Intel IOMMU internals in Debugfs"
depends on INTEL_IOMMU && IOMMU_DEBUGFS
+ select DMAR_PERF
help
!!!WARNING!!!
@@ -41,6 +46,7 @@ config INTEL_IOMMU_SVM
select PCI_PRI
select MMU_NOTIFIER
select IOASID
+ select IOMMU_SVA_LIB
help
Shared Virtual Memory (SVM) provides a facility for devices
to access DMA resources through process address space by
diff --git a/drivers/iommu/intel/Makefile b/drivers/iommu/intel/Makefile
index ae236ec7d219..fa0dae16441c 100644
--- a/drivers/iommu/intel/Makefile
+++ b/drivers/iommu/intel/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_DMAR_TABLE) += dmar.o
obj-$(CONFIG_INTEL_IOMMU) += iommu.o pasid.o
obj-$(CONFIG_DMAR_TABLE) += trace.o cap_audit.o
+obj-$(CONFIG_DMAR_PERF) += perf.o
obj-$(CONFIG_INTEL_IOMMU_DEBUGFS) += debugfs.o
obj-$(CONFIG_INTEL_IOMMU_SVM) += svm.o
obj-$(CONFIG_IRQ_REMAP) += irq_remapping.o
diff --git a/drivers/iommu/intel/debugfs.c b/drivers/iommu/intel/debugfs.c
index efea7f02abd9..62e23ff3c987 100644
--- a/drivers/iommu/intel/debugfs.c
+++ b/drivers/iommu/intel/debugfs.c
@@ -16,6 +16,7 @@
#include <asm/irq_remapping.h>
#include "pasid.h"
+#include "perf.h"
struct tbl_walk {
u16 bus;
@@ -31,6 +32,9 @@ struct iommu_regset {
const char *regs;
};
+#define DEBUG_BUFFER_SIZE 1024
+static char debug_buf[DEBUG_BUFFER_SIZE];
+
#define IOMMU_REGSET_ENTRY(_reg_) \
{ DMAR_##_reg_##_REG, __stringify(_reg_) }
@@ -538,6 +542,111 @@ static int ir_translation_struct_show(struct seq_file *m, void *unused)
DEFINE_SHOW_ATTRIBUTE(ir_translation_struct);
#endif
+static void latency_show_one(struct seq_file *m, struct intel_iommu *iommu,
+ struct dmar_drhd_unit *drhd)
+{
+ int ret;
+
+ seq_printf(m, "IOMMU: %s Register Base Address: %llx\n",
+ iommu->name, drhd->reg_base_addr);
+
+ ret = dmar_latency_snapshot(iommu, debug_buf, DEBUG_BUFFER_SIZE);
+ if (ret < 0)
+ seq_puts(m, "Failed to get latency snapshot");
+ else
+ seq_puts(m, debug_buf);
+ seq_puts(m, "\n");
+}
+
+static int latency_show(struct seq_file *m, void *v)
+{
+ struct dmar_drhd_unit *drhd;
+ struct intel_iommu *iommu;
+
+ rcu_read_lock();
+ for_each_active_iommu(iommu, drhd)
+ latency_show_one(m, iommu, drhd);
+ rcu_read_unlock();
+
+ return 0;
+}
+
+static int dmar_perf_latency_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, latency_show, NULL);
+}
+
+static ssize_t dmar_perf_latency_write(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct dmar_drhd_unit *drhd;
+ struct intel_iommu *iommu;
+ int counting;
+ char buf[64];
+
+ if (cnt > 63)
+ cnt = 63;
+
+ if (copy_from_user(&buf, ubuf, cnt))
+ return -EFAULT;
+
+ buf[cnt] = 0;
+
+ if (kstrtoint(buf, 0, &counting))
+ return -EINVAL;
+
+ switch (counting) {
+ case 0:
+ rcu_read_lock();
+ for_each_active_iommu(iommu, drhd) {
+ dmar_latency_disable(iommu, DMAR_LATENCY_INV_IOTLB);
+ dmar_latency_disable(iommu, DMAR_LATENCY_INV_DEVTLB);
+ dmar_latency_disable(iommu, DMAR_LATENCY_INV_IEC);
+ dmar_latency_disable(iommu, DMAR_LATENCY_PRQ);
+ }
+ rcu_read_unlock();
+ break;
+ case 1:
+ rcu_read_lock();
+ for_each_active_iommu(iommu, drhd)
+ dmar_latency_enable(iommu, DMAR_LATENCY_INV_IOTLB);
+ rcu_read_unlock();
+ break;
+ case 2:
+ rcu_read_lock();
+ for_each_active_iommu(iommu, drhd)
+ dmar_latency_enable(iommu, DMAR_LATENCY_INV_DEVTLB);
+ rcu_read_unlock();
+ break;
+ case 3:
+ rcu_read_lock();
+ for_each_active_iommu(iommu, drhd)
+ dmar_latency_enable(iommu, DMAR_LATENCY_INV_IEC);
+ rcu_read_unlock();
+ break;
+ case 4:
+ rcu_read_lock();
+ for_each_active_iommu(iommu, drhd)
+ dmar_latency_enable(iommu, DMAR_LATENCY_PRQ);
+ rcu_read_unlock();
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *ppos += cnt;
+ return cnt;
+}
+
+static const struct file_operations dmar_perf_latency_fops = {
+ .open = dmar_perf_latency_open,
+ .write = dmar_perf_latency_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
void __init intel_iommu_debugfs_init(void)
{
struct dentry *intel_iommu_debug = debugfs_create_dir("intel",
@@ -556,4 +665,6 @@ void __init intel_iommu_debugfs_init(void)
debugfs_create_file("ir_translation_struct", 0444, intel_iommu_debug,
NULL, &ir_translation_struct_fops);
#endif
+ debugfs_create_file("dmar_perf_latency", 0644, intel_iommu_debug,
+ NULL, &dmar_perf_latency_fops);
}
diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index 84057cb9596c..d66f79acd14d 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -34,6 +34,7 @@
#include <trace/events/intel_iommu.h>
#include "../irq_remapping.h"
+#include "perf.h"
typedef int (*dmar_res_handler_t)(struct acpi_dmar_header *, void *);
struct dmar_res_callback {
@@ -1342,15 +1343,33 @@ int qi_submit_sync(struct intel_iommu *iommu, struct qi_desc *desc,
unsigned int count, unsigned long options)
{
struct q_inval *qi = iommu->qi;
+ s64 devtlb_start_ktime = 0;
+ s64 iotlb_start_ktime = 0;
+ s64 iec_start_ktime = 0;
struct qi_desc wait_desc;
int wait_index, index;
unsigned long flags;
int offset, shift;
int rc, i;
+ u64 type;
if (!qi)
return 0;
+ type = desc->qw0 & GENMASK_ULL(3, 0);
+
+ if ((type == QI_IOTLB_TYPE || type == QI_EIOTLB_TYPE) &&
+ dmar_latency_enabled(iommu, DMAR_LATENCY_INV_IOTLB))
+ iotlb_start_ktime = ktime_to_ns(ktime_get());
+
+ if ((type == QI_DIOTLB_TYPE || type == QI_DEIOTLB_TYPE) &&
+ dmar_latency_enabled(iommu, DMAR_LATENCY_INV_DEVTLB))
+ devtlb_start_ktime = ktime_to_ns(ktime_get());
+
+ if (type == QI_IEC_TYPE &&
+ dmar_latency_enabled(iommu, DMAR_LATENCY_INV_IEC))
+ iec_start_ktime = ktime_to_ns(ktime_get());
+
restart:
rc = 0;
@@ -1425,6 +1444,18 @@ restart:
if (rc == -EAGAIN)
goto restart;
+ if (iotlb_start_ktime)
+ dmar_latency_update(iommu, DMAR_LATENCY_INV_IOTLB,
+ ktime_to_ns(ktime_get()) - iotlb_start_ktime);
+
+ if (devtlb_start_ktime)
+ dmar_latency_update(iommu, DMAR_LATENCY_INV_DEVTLB,
+ ktime_to_ns(ktime_get()) - devtlb_start_ktime);
+
+ if (iec_start_ktime)
+ dmar_latency_update(iommu, DMAR_LATENCY_INV_IEC,
+ ktime_to_ns(ktime_get()) - iec_start_ktime);
+
return rc;
}
@@ -1913,16 +1944,23 @@ static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
reason = dmar_get_fault_reason(fault_reason, &fault_type);
if (fault_type == INTR_REMAP)
- pr_err("[INTR-REMAP] Request device [%02x:%02x.%d] fault index %llx [fault reason %02d] %s\n",
- source_id >> 8, PCI_SLOT(source_id & 0xFF),
- PCI_FUNC(source_id & 0xFF), addr >> 48,
- fault_reason, reason);
- else
- pr_err("[%s] Request device [%02x:%02x.%d] PASID %x fault addr %llx [fault reason %02d] %s\n",
+ pr_err("[INTR-REMAP] Request device [0x%02x:0x%02x.%d] fault index 0x%llx [fault reason 0x%02x] %s\n",
+ source_id >> 8, PCI_SLOT(source_id & 0xFF),
+ PCI_FUNC(source_id & 0xFF), addr >> 48,
+ fault_reason, reason);
+ else if (pasid == INVALID_IOASID)
+ pr_err("[%s NO_PASID] Request device [0x%02x:0x%02x.%d] fault addr 0x%llx [fault reason 0x%02x] %s\n",
type ? "DMA Read" : "DMA Write",
source_id >> 8, PCI_SLOT(source_id & 0xFF),
- PCI_FUNC(source_id & 0xFF), pasid, addr,
+ PCI_FUNC(source_id & 0xFF), addr,
fault_reason, reason);
+ else
+ pr_err("[%s PASID 0x%x] Request device [0x%02x:0x%02x.%d] fault addr 0x%llx [fault reason 0x%02x] %s\n",
+ type ? "DMA Read" : "DMA Write", pasid,
+ source_id >> 8, PCI_SLOT(source_id & 0xFF),
+ PCI_FUNC(source_id & 0xFF), addr,
+ fault_reason, reason);
+
return 0;
}
@@ -1989,7 +2027,7 @@ irqreturn_t dmar_fault(int irq, void *dev_id)
if (!ratelimited)
/* Using pasid -1 if pasid is not present */
dmar_fault_do_one(iommu, type, fault_reason,
- pasid_present ? pasid : -1,
+ pasid_present ? pasid : INVALID_IOASID,
source_id, guest_addr);
fault_index++;
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index be35284a2016..dd22fc7d5176 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -46,6 +46,7 @@
#include <asm/iommu.h>
#include "../irq_remapping.h"
+#include "../iommu-sva-lib.h"
#include "pasid.h"
#include "cap_audit.h"
@@ -564,7 +565,7 @@ static inline int domain_pfn_supported(struct dmar_domain *domain,
static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
{
unsigned long sagaw;
- int agaw = -1;
+ int agaw;
sagaw = cap_sagaw(iommu->cap);
for (agaw = width_to_agaw(max_gaw);
@@ -625,12 +626,12 @@ static void domain_update_iommu_coherency(struct dmar_domain *domain)
bool found = false;
int i;
- domain->iommu_coherency = 1;
+ domain->iommu_coherency = true;
for_each_domain_iommu(i, domain) {
found = true;
if (!iommu_paging_structure_coherency(g_iommus[i])) {
- domain->iommu_coherency = 0;
+ domain->iommu_coherency = false;
break;
}
}
@@ -641,18 +642,18 @@ static void domain_update_iommu_coherency(struct dmar_domain *domain)
rcu_read_lock();
for_each_active_iommu(iommu, drhd) {
if (!iommu_paging_structure_coherency(iommu)) {
- domain->iommu_coherency = 0;
+ domain->iommu_coherency = false;
break;
}
}
rcu_read_unlock();
}
-static int domain_update_iommu_snooping(struct intel_iommu *skip)
+static bool domain_update_iommu_snooping(struct intel_iommu *skip)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu;
- int ret = 1;
+ bool ret = true;
rcu_read_lock();
for_each_active_iommu(iommu, drhd) {
@@ -665,7 +666,7 @@ static int domain_update_iommu_snooping(struct intel_iommu *skip)
*/
if (!sm_supported(iommu) &&
!ecap_sc_support(iommu->ecap)) {
- ret = 0;
+ ret = false;
break;
}
}
@@ -682,9 +683,8 @@ static int domain_update_iommu_superpage(struct dmar_domain *domain,
struct intel_iommu *iommu;
int mask = 0x3;
- if (!intel_iommu_superpage) {
+ if (!intel_iommu_superpage)
return 0;
- }
/* set iommu_superpage to the smallest common denominator */
rcu_read_lock();
@@ -1919,7 +1919,6 @@ static int domain_attach_iommu(struct dmar_domain *domain,
assert_spin_locked(&iommu->lock);
domain->iommu_refcnt[iommu->seq_id] += 1;
- domain->iommu_count += 1;
if (domain->iommu_refcnt[iommu->seq_id] == 1) {
ndomains = cap_ndoms(iommu->cap);
num = find_first_zero_bit(iommu->domain_ids, ndomains);
@@ -1927,7 +1926,6 @@ static int domain_attach_iommu(struct dmar_domain *domain,
if (num >= ndomains) {
pr_err("%s: No free domain ids\n", iommu->name);
domain->iommu_refcnt[iommu->seq_id] -= 1;
- domain->iommu_count -= 1;
return -ENOSPC;
}
@@ -1943,16 +1941,15 @@ static int domain_attach_iommu(struct dmar_domain *domain,
return 0;
}
-static int domain_detach_iommu(struct dmar_domain *domain,
- struct intel_iommu *iommu)
+static void domain_detach_iommu(struct dmar_domain *domain,
+ struct intel_iommu *iommu)
{
- int num, count;
+ int num;
assert_spin_locked(&device_domain_lock);
assert_spin_locked(&iommu->lock);
domain->iommu_refcnt[iommu->seq_id] -= 1;
- count = --domain->iommu_count;
if (domain->iommu_refcnt[iommu->seq_id] == 0) {
num = domain->iommu_did[iommu->seq_id];
clear_bit(num, iommu->domain_ids);
@@ -1961,8 +1958,6 @@ static int domain_detach_iommu(struct dmar_domain *domain,
domain_update_iommu_cap(domain);
domain->iommu_did[iommu->seq_id] = 0;
}
-
- return count;
}
static inline int guestwidth_to_adjustwidth(int gaw)
@@ -2434,10 +2429,11 @@ __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
return 0;
}
-static void domain_context_clear_one(struct intel_iommu *iommu, u8 bus, u8 devfn)
+static void domain_context_clear_one(struct device_domain_info *info, u8 bus, u8 devfn)
{
- unsigned long flags;
+ struct intel_iommu *iommu = info->iommu;
struct context_entry *context;
+ unsigned long flags;
u16 did_old;
if (!iommu)
@@ -2449,7 +2445,16 @@ static void domain_context_clear_one(struct intel_iommu *iommu, u8 bus, u8 devfn
spin_unlock_irqrestore(&iommu->lock, flags);
return;
}
- did_old = context_domain_id(context);
+
+ if (sm_supported(iommu)) {
+ if (hw_pass_through && domain_type_is_si(info->domain))
+ did_old = FLPT_DEFAULT_DID;
+ else
+ did_old = info->domain->iommu_did[iommu->seq_id];
+ } else {
+ did_old = context_domain_id(context);
+ }
+
context_clear_entry(context);
__iommu_flush_cache(iommu, context, sizeof(*context));
spin_unlock_irqrestore(&iommu->lock, flags);
@@ -2467,6 +2472,8 @@ static void domain_context_clear_one(struct intel_iommu *iommu, u8 bus, u8 devfn
0,
0,
DMA_TLB_DSI_FLUSH);
+
+ __iommu_flush_dev_iotlb(info, 0, MAX_AGAW_PFN_WIDTH);
}
static inline void unlink_domain_info(struct device_domain_info *info)
@@ -4138,62 +4145,56 @@ static inline struct intel_iommu *dev_to_intel_iommu(struct device *dev)
return container_of(iommu_dev, struct intel_iommu, iommu);
}
-static ssize_t intel_iommu_show_version(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct intel_iommu *iommu = dev_to_intel_iommu(dev);
u32 ver = readl(iommu->reg + DMAR_VER_REG);
return sprintf(buf, "%d:%d\n",
DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver));
}
-static DEVICE_ATTR(version, S_IRUGO, intel_iommu_show_version, NULL);
+static DEVICE_ATTR_RO(version);
-static ssize_t intel_iommu_show_address(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t address_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct intel_iommu *iommu = dev_to_intel_iommu(dev);
return sprintf(buf, "%llx\n", iommu->reg_phys);
}
-static DEVICE_ATTR(address, S_IRUGO, intel_iommu_show_address, NULL);
+static DEVICE_ATTR_RO(address);
-static ssize_t intel_iommu_show_cap(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t cap_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct intel_iommu *iommu = dev_to_intel_iommu(dev);
return sprintf(buf, "%llx\n", iommu->cap);
}
-static DEVICE_ATTR(cap, S_IRUGO, intel_iommu_show_cap, NULL);
+static DEVICE_ATTR_RO(cap);
-static ssize_t intel_iommu_show_ecap(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t ecap_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct intel_iommu *iommu = dev_to_intel_iommu(dev);
return sprintf(buf, "%llx\n", iommu->ecap);
}
-static DEVICE_ATTR(ecap, S_IRUGO, intel_iommu_show_ecap, NULL);
+static DEVICE_ATTR_RO(ecap);
-static ssize_t intel_iommu_show_ndoms(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t domains_supported_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct intel_iommu *iommu = dev_to_intel_iommu(dev);
return sprintf(buf, "%ld\n", cap_ndoms(iommu->cap));
}
-static DEVICE_ATTR(domains_supported, S_IRUGO, intel_iommu_show_ndoms, NULL);
+static DEVICE_ATTR_RO(domains_supported);
-static ssize_t intel_iommu_show_ndoms_used(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t domains_used_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct intel_iommu *iommu = dev_to_intel_iommu(dev);
return sprintf(buf, "%d\n", bitmap_weight(iommu->domain_ids,
cap_ndoms(iommu->cap)));
}
-static DEVICE_ATTR(domains_used, S_IRUGO, intel_iommu_show_ndoms_used, NULL);
+static DEVICE_ATTR_RO(domains_used);
static struct attribute *intel_iommu_attrs[] = {
&dev_attr_version.attr,
@@ -4436,9 +4437,9 @@ out_free_dmar:
static int domain_context_clear_one_cb(struct pci_dev *pdev, u16 alias, void *opaque)
{
- struct intel_iommu *iommu = opaque;
+ struct device_domain_info *info = opaque;
- domain_context_clear_one(iommu, PCI_BUS_NUM(alias), alias & 0xff);
+ domain_context_clear_one(info, PCI_BUS_NUM(alias), alias & 0xff);
return 0;
}
@@ -4448,12 +4449,13 @@ static int domain_context_clear_one_cb(struct pci_dev *pdev, u16 alias, void *op
* devices, unbinding the driver from any one of them will possibly leave
* the others unable to operate.
*/
-static void domain_context_clear(struct intel_iommu *iommu, struct device *dev)
+static void domain_context_clear(struct device_domain_info *info)
{
- if (!iommu || !dev || !dev_is_pci(dev))
+ if (!info->iommu || !info->dev || !dev_is_pci(info->dev))
return;
- pci_for_each_dma_alias(to_pci_dev(dev), &domain_context_clear_one_cb, iommu);
+ pci_for_each_dma_alias(to_pci_dev(info->dev),
+ &domain_context_clear_one_cb, info);
}
static void __dmar_remove_one_dev_info(struct device_domain_info *info)
@@ -4470,14 +4472,13 @@ static void __dmar_remove_one_dev_info(struct device_domain_info *info)
iommu = info->iommu;
domain = info->domain;
- if (info->dev) {
+ if (info->dev && !dev_is_real_dma_subdevice(info->dev)) {
if (dev_is_pci(info->dev) && sm_supported(iommu))
intel_pasid_tear_down_entry(iommu, info->dev,
PASID_RID2PASID, false);
iommu_disable_dev_iotlb(info);
- if (!dev_is_real_dma_subdevice(info->dev))
- domain_context_clear(iommu, info->dev);
+ domain_context_clear(info);
intel_pasid_free_table(info->dev);
}
@@ -4511,13 +4512,13 @@ static int md_domain_init(struct dmar_domain *domain, int 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_coherency = false;
+ domain->iommu_snooping = false;
domain->iommu_superpage = 0;
domain->max_addr = 0;
/* always allocate the top pgd */
- domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
+ domain->pgd = alloc_pgtable_page(domain->nid);
if (!domain->pgd)
return -ENOMEM;
domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
@@ -4757,6 +4758,13 @@ static int prepare_domain_attach_device(struct iommu_domain *domain,
if (!iommu)
return -ENODEV;
+ if ((dmar_domain->flags & DOMAIN_FLAG_NESTING_MODE) &&
+ !ecap_nest(iommu->ecap)) {
+ dev_err(dev, "%s: iommu not support nested translation\n",
+ iommu->name);
+ return -EINVAL;
+ }
+
/* check if this iommu agaw is sufficient for max mapped address */
addr_width = agaw_to_width(iommu->agaw);
if (addr_width > cap_mgaw(iommu->cap))
@@ -4778,8 +4786,7 @@ static int prepare_domain_attach_device(struct iommu_domain *domain,
pte = dmar_domain->pgd;
if (dma_pte_present(pte)) {
- dmar_domain->pgd = (struct dma_pte *)
- phys_to_virt(dma_pte_addr(pte));
+ dmar_domain->pgd = phys_to_virt(dma_pte_addr(pte));
free_pgtable_page(pte);
}
dmar_domain->agaw--;
@@ -5129,7 +5136,7 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
static bool intel_iommu_capable(enum iommu_cap cap)
{
if (cap == IOMMU_CAP_CACHE_COHERENCY)
- return domain_update_iommu_snooping(NULL) == 1;
+ return domain_update_iommu_snooping(NULL);
if (cap == IOMMU_CAP_INTR_REMAP)
return irq_remapping_enabled == 1;
@@ -5165,13 +5172,10 @@ static void intel_iommu_release_device(struct device *dev)
static void intel_iommu_probe_finalize(struct device *dev)
{
- dma_addr_t base = IOVA_START_PFN << VTD_PAGE_SHIFT;
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
- struct dmar_domain *dmar_domain = to_dmar_domain(domain);
if (domain && domain->type == IOMMU_DOMAIN_DMA)
- iommu_setup_dma_ops(dev, base,
- __DOMAIN_MAX_ADDR(dmar_domain->gaw) - base);
+ iommu_setup_dma_ops(dev, 0, U64_MAX);
else
set_dma_ops(dev, NULL);
}
@@ -5331,6 +5335,48 @@ static int intel_iommu_disable_auxd(struct device *dev)
return 0;
}
+static int intel_iommu_enable_sva(struct device *dev)
+{
+ struct device_domain_info *info = get_domain_info(dev);
+ struct intel_iommu *iommu;
+ int ret;
+
+ if (!info || dmar_disabled)
+ return -EINVAL;
+
+ iommu = info->iommu;
+ if (!iommu)
+ return -EINVAL;
+
+ if (!(iommu->flags & VTD_FLAG_SVM_CAPABLE))
+ return -ENODEV;
+
+ if (intel_iommu_enable_pasid(iommu, dev))
+ return -ENODEV;
+
+ if (!info->pasid_enabled || !info->pri_enabled || !info->ats_enabled)
+ return -EINVAL;
+
+ ret = iopf_queue_add_device(iommu->iopf_queue, dev);
+ if (!ret)
+ ret = iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev);
+
+ return ret;
+}
+
+static int intel_iommu_disable_sva(struct device *dev)
+{
+ struct device_domain_info *info = get_domain_info(dev);
+ struct intel_iommu *iommu = info->iommu;
+ int ret;
+
+ ret = iommu_unregister_device_fault_handler(dev);
+ if (!ret)
+ ret = iopf_queue_remove_device(iommu->iopf_queue, dev);
+
+ return ret;
+}
+
/*
* A PCI express designated vendor specific extended capability is defined
* in the section 3.7 of Intel scalable I/O virtualization technical spec
@@ -5392,35 +5438,37 @@ intel_iommu_dev_has_feat(struct device *dev, enum iommu_dev_features feat)
static int
intel_iommu_dev_enable_feat(struct device *dev, enum iommu_dev_features feat)
{
- if (feat == IOMMU_DEV_FEAT_AUX)
+ switch (feat) {
+ case IOMMU_DEV_FEAT_AUX:
return intel_iommu_enable_auxd(dev);
- if (feat == IOMMU_DEV_FEAT_IOPF)
+ case IOMMU_DEV_FEAT_IOPF:
return intel_iommu_dev_has_feat(dev, feat) ? 0 : -ENODEV;
- if (feat == IOMMU_DEV_FEAT_SVA) {
- struct device_domain_info *info = get_domain_info(dev);
-
- if (!info)
- return -EINVAL;
+ case IOMMU_DEV_FEAT_SVA:
+ return intel_iommu_enable_sva(dev);
- if (!info->pasid_enabled || !info->pri_enabled || !info->ats_enabled)
- return -EINVAL;
-
- if (info->iommu->flags & VTD_FLAG_SVM_CAPABLE)
- return 0;
+ default:
+ return -ENODEV;
}
-
- return -ENODEV;
}
static int
intel_iommu_dev_disable_feat(struct device *dev, enum iommu_dev_features feat)
{
- if (feat == IOMMU_DEV_FEAT_AUX)
+ switch (feat) {
+ case IOMMU_DEV_FEAT_AUX:
return intel_iommu_disable_auxd(dev);
- return -ENODEV;
+ case IOMMU_DEV_FEAT_IOPF:
+ return 0;
+
+ case IOMMU_DEV_FEAT_SVA:
+ return intel_iommu_disable_sva(dev);
+
+ default:
+ return -ENODEV;
+ }
}
static bool
@@ -5457,7 +5505,7 @@ intel_iommu_enable_nesting(struct iommu_domain *domain)
int ret = -ENODEV;
spin_lock_irqsave(&device_domain_lock, flags);
- if (nested_mode_support() && list_empty(&dmar_domain->devices)) {
+ if (list_empty(&dmar_domain->devices)) {
dmar_domain->flags |= DOMAIN_FLAG_NESTING_MODE;
dmar_domain->flags &= ~DOMAIN_FLAG_USE_FIRST_LEVEL;
ret = 0;
diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
index 72dc84821dad..c6cf44a6c923 100644
--- a/drivers/iommu/intel/pasid.c
+++ b/drivers/iommu/intel/pasid.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* intel-pasid.c - PASID idr, table and entry manipulation
*
* Copyright (C) 2018 Intel Corporation
diff --git a/drivers/iommu/intel/perf.c b/drivers/iommu/intel/perf.c
new file mode 100644
index 000000000000..73b7ec705552
--- /dev/null
+++ b/drivers/iommu/intel/perf.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * perf.c - performance monitor
+ *
+ * Copyright (C) 2021 Intel Corporation
+ *
+ * Author: Lu Baolu <baolu.lu@linux.intel.com>
+ * Fenghua Yu <fenghua.yu@intel.com>
+ */
+
+#include <linux/spinlock.h>
+#include <linux/intel-iommu.h>
+
+#include "perf.h"
+
+static DEFINE_SPINLOCK(latency_lock);
+
+bool dmar_latency_enabled(struct intel_iommu *iommu, enum latency_type type)
+{
+ struct latency_statistic *lstat = iommu->perf_statistic;
+
+ return lstat && lstat[type].enabled;
+}
+
+int dmar_latency_enable(struct intel_iommu *iommu, enum latency_type type)
+{
+ struct latency_statistic *lstat;
+ unsigned long flags;
+ int ret = -EBUSY;
+
+ if (dmar_latency_enabled(iommu, type))
+ return 0;
+
+ spin_lock_irqsave(&latency_lock, flags);
+ if (!iommu->perf_statistic) {
+ iommu->perf_statistic = kzalloc(sizeof(*lstat) * DMAR_LATENCY_NUM,
+ GFP_ATOMIC);
+ if (!iommu->perf_statistic) {
+ ret = -ENOMEM;
+ goto unlock_out;
+ }
+ }
+
+ lstat = iommu->perf_statistic;
+
+ if (!lstat[type].enabled) {
+ lstat[type].enabled = true;
+ lstat[type].counter[COUNTS_MIN] = UINT_MAX;
+ ret = 0;
+ }
+unlock_out:
+ spin_unlock_irqrestore(&latency_lock, flags);
+
+ return ret;
+}
+
+void dmar_latency_disable(struct intel_iommu *iommu, enum latency_type type)
+{
+ struct latency_statistic *lstat = iommu->perf_statistic;
+ unsigned long flags;
+
+ if (!dmar_latency_enabled(iommu, type))
+ return;
+
+ spin_lock_irqsave(&latency_lock, flags);
+ memset(&lstat[type], 0, sizeof(*lstat) * DMAR_LATENCY_NUM);
+ spin_unlock_irqrestore(&latency_lock, flags);
+}
+
+void dmar_latency_update(struct intel_iommu *iommu, enum latency_type type, u64 latency)
+{
+ struct latency_statistic *lstat = iommu->perf_statistic;
+ unsigned long flags;
+ u64 min, max;
+
+ if (!dmar_latency_enabled(iommu, type))
+ return;
+
+ spin_lock_irqsave(&latency_lock, flags);
+ if (latency < 100)
+ lstat[type].counter[COUNTS_10e2]++;
+ else if (latency < 1000)
+ lstat[type].counter[COUNTS_10e3]++;
+ else if (latency < 10000)
+ lstat[type].counter[COUNTS_10e4]++;
+ else if (latency < 100000)
+ lstat[type].counter[COUNTS_10e5]++;
+ else if (latency < 1000000)
+ lstat[type].counter[COUNTS_10e6]++;
+ else if (latency < 10000000)
+ lstat[type].counter[COUNTS_10e7]++;
+ else
+ lstat[type].counter[COUNTS_10e8_plus]++;
+
+ min = lstat[type].counter[COUNTS_MIN];
+ max = lstat[type].counter[COUNTS_MAX];
+ lstat[type].counter[COUNTS_MIN] = min_t(u64, min, latency);
+ lstat[type].counter[COUNTS_MAX] = max_t(u64, max, latency);
+ lstat[type].counter[COUNTS_SUM] += latency;
+ lstat[type].samples++;
+ spin_unlock_irqrestore(&latency_lock, flags);
+}
+
+static char *latency_counter_names[] = {
+ " <0.1us",
+ " 0.1us-1us", " 1us-10us", " 10us-100us",
+ " 100us-1ms", " 1ms-10ms", " >=10ms",
+ " min(us)", " max(us)", " average(us)"
+};
+
+static char *latency_type_names[] = {
+ " inv_iotlb", " inv_devtlb", " inv_iec",
+ " svm_prq"
+};
+
+int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
+{
+ struct latency_statistic *lstat = iommu->perf_statistic;
+ unsigned long flags;
+ int bytes = 0, i, j;
+
+ memset(str, 0, size);
+
+ for (i = 0; i < COUNTS_NUM; i++)
+ bytes += snprintf(str + bytes, size - bytes,
+ "%s", latency_counter_names[i]);
+
+ spin_lock_irqsave(&latency_lock, flags);
+ for (i = 0; i < DMAR_LATENCY_NUM; i++) {
+ if (!dmar_latency_enabled(iommu, i))
+ continue;
+
+ bytes += snprintf(str + bytes, size - bytes,
+ "\n%s", latency_type_names[i]);
+
+ for (j = 0; j < COUNTS_NUM; j++) {
+ u64 val = lstat[i].counter[j];
+
+ switch (j) {
+ case COUNTS_MIN:
+ if (val == UINT_MAX)
+ val = 0;
+ else
+ val = div_u64(val, 1000);
+ break;
+ case COUNTS_MAX:
+ val = div_u64(val, 1000);
+ break;
+ case COUNTS_SUM:
+ if (lstat[i].samples)
+ val = div_u64(val, (lstat[i].samples * 1000));
+ else
+ val = 0;
+ break;
+ default:
+ break;
+ }
+
+ bytes += snprintf(str + bytes, size - bytes,
+ "%12lld", val);
+ }
+ }
+ spin_unlock_irqrestore(&latency_lock, flags);
+
+ return bytes;
+}
diff --git a/drivers/iommu/intel/perf.h b/drivers/iommu/intel/perf.h
new file mode 100644
index 000000000000..fd6db8049d1a
--- /dev/null
+++ b/drivers/iommu/intel/perf.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * perf.h - performance monitor header
+ *
+ * Copyright (C) 2021 Intel Corporation
+ *
+ * Author: Lu Baolu <baolu.lu@linux.intel.com>
+ */
+
+enum latency_type {
+ DMAR_LATENCY_INV_IOTLB = 0,
+ DMAR_LATENCY_INV_DEVTLB,
+ DMAR_LATENCY_INV_IEC,
+ DMAR_LATENCY_PRQ,
+ DMAR_LATENCY_NUM
+};
+
+enum latency_count {
+ COUNTS_10e2 = 0, /* < 0.1us */
+ COUNTS_10e3, /* 0.1us ~ 1us */
+ COUNTS_10e4, /* 1us ~ 10us */
+ COUNTS_10e5, /* 10us ~ 100us */
+ COUNTS_10e6, /* 100us ~ 1ms */
+ COUNTS_10e7, /* 1ms ~ 10ms */
+ COUNTS_10e8_plus, /* 10ms and plus*/
+ COUNTS_MIN,
+ COUNTS_MAX,
+ COUNTS_SUM,
+ COUNTS_NUM
+};
+
+struct latency_statistic {
+ bool enabled;
+ u64 counter[COUNTS_NUM];
+ u64 samples;
+};
+
+#ifdef CONFIG_DMAR_PERF
+int dmar_latency_enable(struct intel_iommu *iommu, enum latency_type type);
+void dmar_latency_disable(struct intel_iommu *iommu, enum latency_type type);
+bool dmar_latency_enabled(struct intel_iommu *iommu, enum latency_type type);
+void dmar_latency_update(struct intel_iommu *iommu, enum latency_type type,
+ u64 latency);
+int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size);
+#else
+static inline int
+dmar_latency_enable(struct intel_iommu *iommu, enum latency_type type)
+{
+ return -EINVAL;
+}
+
+static inline void
+dmar_latency_disable(struct intel_iommu *iommu, enum latency_type type)
+{
+}
+
+static inline bool
+dmar_latency_enabled(struct intel_iommu *iommu, enum latency_type type)
+{
+ return false;
+}
+
+static inline void
+dmar_latency_update(struct intel_iommu *iommu, enum latency_type type, u64 latency)
+{
+}
+
+static inline int
+dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
+{
+ return 0;
+}
+#endif /* CONFIG_DMAR_PERF */
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index 5165cea90421..9b0f22bc0514 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -17,19 +17,76 @@
#include <linux/dmar.h>
#include <linux/interrupt.h>
#include <linux/mm_types.h>
+#include <linux/xarray.h>
#include <linux/ioasid.h>
#include <asm/page.h>
#include <asm/fpu/api.h>
+#include <trace/events/intel_iommu.h>
#include "pasid.h"
+#include "perf.h"
+#include "../iommu-sva-lib.h"
static irqreturn_t prq_event_thread(int irq, void *d);
static void intel_svm_drain_prq(struct device *dev, u32 pasid);
+#define to_intel_svm_dev(handle) container_of(handle, struct intel_svm_dev, sva)
#define PRQ_ORDER 0
+static DEFINE_XARRAY_ALLOC(pasid_private_array);
+static int pasid_private_add(ioasid_t pasid, void *priv)
+{
+ return xa_alloc(&pasid_private_array, &pasid, priv,
+ XA_LIMIT(pasid, pasid), GFP_ATOMIC);
+}
+
+static void pasid_private_remove(ioasid_t pasid)
+{
+ xa_erase(&pasid_private_array, pasid);
+}
+
+static void *pasid_private_find(ioasid_t pasid)
+{
+ return xa_load(&pasid_private_array, pasid);
+}
+
+static struct intel_svm_dev *
+svm_lookup_device_by_sid(struct intel_svm *svm, u16 sid)
+{
+ struct intel_svm_dev *sdev = NULL, *t;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(t, &svm->devs, list) {
+ if (t->sid == sid) {
+ sdev = t;
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ return sdev;
+}
+
+static struct intel_svm_dev *
+svm_lookup_device_by_dev(struct intel_svm *svm, struct device *dev)
+{
+ struct intel_svm_dev *sdev = NULL, *t;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(t, &svm->devs, list) {
+ if (t->dev == dev) {
+ sdev = t;
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ return sdev;
+}
+
int intel_svm_enable_prq(struct intel_iommu *iommu)
{
+ struct iopf_queue *iopfq;
struct page *pages;
int irq, ret;
@@ -46,13 +103,20 @@ int intel_svm_enable_prq(struct intel_iommu *iommu)
pr_err("IOMMU: %s: Failed to create IRQ vector for page request queue\n",
iommu->name);
ret = -EINVAL;
- err:
- free_pages((unsigned long)iommu->prq, PRQ_ORDER);
- iommu->prq = NULL;
- return ret;
+ goto free_prq;
}
iommu->pr_irq = irq;
+ snprintf(iommu->iopfq_name, sizeof(iommu->iopfq_name),
+ "dmar%d-iopfq", iommu->seq_id);
+ iopfq = iopf_queue_alloc(iommu->iopfq_name);
+ if (!iopfq) {
+ pr_err("IOMMU: %s: Failed to allocate iopf queue\n", iommu->name);
+ ret = -ENOMEM;
+ goto free_hwirq;
+ }
+ iommu->iopf_queue = iopfq;
+
snprintf(iommu->prq_name, sizeof(iommu->prq_name), "dmar%d-prq", iommu->seq_id);
ret = request_threaded_irq(irq, NULL, prq_event_thread, IRQF_ONESHOT,
@@ -60,9 +124,7 @@ int intel_svm_enable_prq(struct intel_iommu *iommu)
if (ret) {
pr_err("IOMMU: %s: Failed to request IRQ for page request queue\n",
iommu->name);
- dmar_free_hwirq(irq);
- iommu->pr_irq = 0;
- goto err;
+ goto free_iopfq;
}
dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL);
dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL);
@@ -71,6 +133,18 @@ int intel_svm_enable_prq(struct intel_iommu *iommu)
init_completion(&iommu->prq_complete);
return 0;
+
+free_iopfq:
+ iopf_queue_free(iommu->iopf_queue);
+ iommu->iopf_queue = NULL;
+free_hwirq:
+ dmar_free_hwirq(irq);
+ iommu->pr_irq = 0;
+free_prq:
+ free_pages((unsigned long)iommu->prq, PRQ_ORDER);
+ iommu->prq = NULL;
+
+ return ret;
}
int intel_svm_finish_prq(struct intel_iommu *iommu)
@@ -85,6 +159,11 @@ int intel_svm_finish_prq(struct intel_iommu *iommu)
iommu->pr_irq = 0;
}
+ if (iommu->iopf_queue) {
+ iopf_queue_free(iommu->iopf_queue);
+ iommu->iopf_queue = NULL;
+ }
+
free_pages((unsigned long)iommu->prq, PRQ_ORDER);
iommu->prq = NULL;
@@ -204,17 +283,12 @@ static const struct mmu_notifier_ops intel_mmuops = {
};
static DEFINE_MUTEX(pasid_mutex);
-static LIST_HEAD(global_svm_list);
-
-#define for_each_svm_dev(sdev, svm, d) \
- list_for_each_entry((sdev), &(svm)->devs, list) \
- if ((d) != (sdev)->dev) {} else
static int pasid_to_svm_sdev(struct device *dev, unsigned int pasid,
struct intel_svm **rsvm,
struct intel_svm_dev **rsdev)
{
- struct intel_svm_dev *d, *sdev = NULL;
+ struct intel_svm_dev *sdev = NULL;
struct intel_svm *svm;
/* The caller should hold the pasid_mutex lock */
@@ -224,7 +298,7 @@ static int pasid_to_svm_sdev(struct device *dev, unsigned int pasid,
if (pasid == INVALID_IOASID || pasid >= PASID_MAX)
return -EINVAL;
- svm = ioasid_find(NULL, pasid, NULL);
+ svm = pasid_private_find(pasid);
if (IS_ERR(svm))
return PTR_ERR(svm);
@@ -237,15 +311,7 @@ static int pasid_to_svm_sdev(struct device *dev, unsigned int pasid,
*/
if (WARN_ON(list_empty(&svm->devs)))
return -EINVAL;
-
- rcu_read_lock();
- list_for_each_entry_rcu(d, &svm->devs, list) {
- if (d->dev == dev) {
- sdev = d;
- break;
- }
- }
- rcu_read_unlock();
+ sdev = svm_lookup_device_by_dev(svm, dev);
out:
*rsvm = svm;
@@ -334,7 +400,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
svm->gpasid = data->gpasid;
svm->flags |= SVM_FLAG_GUEST_PASID;
}
- ioasid_set_data(data->hpasid, svm);
+ pasid_private_add(data->hpasid, svm);
INIT_LIST_HEAD_RCU(&svm->devs);
mmput(svm->mm);
}
@@ -388,7 +454,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
list_add_rcu(&sdev->list, &svm->devs);
out:
if (!IS_ERR_OR_NULL(svm) && list_empty(&svm->devs)) {
- ioasid_set_data(data->hpasid, NULL);
+ pasid_private_remove(data->hpasid);
kfree(svm);
}
@@ -431,7 +497,7 @@ int intel_svm_unbind_gpasid(struct device *dev, u32 pasid)
* the unbind, IOMMU driver will get notified
* and perform cleanup.
*/
- ioasid_set_data(pasid, NULL);
+ pasid_private_remove(pasid);
kfree(svm);
}
}
@@ -459,79 +525,81 @@ static void load_pasid(struct mm_struct *mm, u32 pasid)
mutex_unlock(&mm->context.lock);
}
-/* Caller must hold pasid_mutex, mm reference */
-static int
-intel_svm_bind_mm(struct device *dev, unsigned int flags,
- struct mm_struct *mm, struct intel_svm_dev **sd)
+static int intel_svm_alloc_pasid(struct device *dev, struct mm_struct *mm,
+ unsigned int flags)
{
- struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL);
- struct intel_svm *svm = NULL, *t;
- struct device_domain_info *info;
- struct intel_svm_dev *sdev;
- unsigned long iflags;
- int pasid_max;
- int ret;
+ ioasid_t max_pasid = dev_is_pci(dev) ?
+ pci_max_pasids(to_pci_dev(dev)) : intel_pasid_max_id;
- if (!iommu || dmar_disabled)
- return -EINVAL;
+ return iommu_sva_alloc_pasid(mm, PASID_MIN, max_pasid - 1);
+}
- if (!intel_svm_capable(iommu))
- return -ENOTSUPP;
+static void intel_svm_free_pasid(struct mm_struct *mm)
+{
+ iommu_sva_free_pasid(mm);
+}
- if (dev_is_pci(dev)) {
- pasid_max = pci_max_pasids(to_pci_dev(dev));
- if (pasid_max < 0)
- return -EINVAL;
- } else
- pasid_max = 1 << 20;
+static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
+ struct device *dev,
+ struct mm_struct *mm,
+ unsigned int flags)
+{
+ struct device_domain_info *info = get_domain_info(dev);
+ unsigned long iflags, sflags;
+ struct intel_svm_dev *sdev;
+ struct intel_svm *svm;
+ int ret = 0;
- /* Bind supervisor PASID shuld have mm = NULL */
- if (flags & SVM_FLAG_SUPERVISOR_MODE) {
- if (!ecap_srs(iommu->ecap) || mm) {
- pr_err("Supervisor PASID with user provided mm.\n");
- return -EINVAL;
- }
- }
+ svm = pasid_private_find(mm->pasid);
+ if (!svm) {
+ svm = kzalloc(sizeof(*svm), GFP_KERNEL);
+ if (!svm)
+ return ERR_PTR(-ENOMEM);
- list_for_each_entry(t, &global_svm_list, list) {
- if (t->mm != mm)
- continue;
+ svm->pasid = mm->pasid;
+ svm->mm = mm;
+ svm->flags = flags;
+ INIT_LIST_HEAD_RCU(&svm->devs);
- svm = t;
- if (svm->pasid >= pasid_max) {
- dev_warn(dev,
- "Limited PASID width. Cannot use existing PASID %d\n",
- svm->pasid);
- ret = -ENOSPC;
- goto out;
+ if (!(flags & SVM_FLAG_SUPERVISOR_MODE)) {
+ svm->notifier.ops = &intel_mmuops;
+ ret = mmu_notifier_register(&svm->notifier, mm);
+ if (ret) {
+ kfree(svm);
+ return ERR_PTR(ret);
+ }
}
- /* Find the matching device in svm list */
- for_each_svm_dev(sdev, svm, dev) {
- sdev->users++;
- goto success;
+ ret = pasid_private_add(svm->pasid, svm);
+ if (ret) {
+ if (svm->notifier.ops)
+ mmu_notifier_unregister(&svm->notifier, mm);
+ kfree(svm);
+ return ERR_PTR(ret);
}
+ }
- break;
+ /* Find the matching device in svm list */
+ sdev = svm_lookup_device_by_dev(svm, dev);
+ if (sdev) {
+ sdev->users++;
+ goto success;
}
sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
if (!sdev) {
ret = -ENOMEM;
- goto out;
+ goto free_svm;
}
+
sdev->dev = dev;
sdev->iommu = iommu;
-
- ret = intel_iommu_enable_pasid(iommu, dev);
- if (ret) {
- kfree(sdev);
- goto out;
- }
-
- info = get_domain_info(dev);
sdev->did = FLPT_DEFAULT_DID;
sdev->sid = PCI_DEVID(info->bus, info->devfn);
+ sdev->users = 1;
+ sdev->pasid = svm->pasid;
+ sdev->sva.dev = dev;
+ init_rcu_head(&sdev->rcu);
if (info->ats_enabled) {
sdev->dev_iotlb = 1;
sdev->qdep = info->ats_qdep;
@@ -539,95 +607,37 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
sdev->qdep = 0;
}
- /* Finish the setup now we know we're keeping it */
- sdev->users = 1;
- init_rcu_head(&sdev->rcu);
-
- if (!svm) {
- svm = kzalloc(sizeof(*svm), GFP_KERNEL);
- if (!svm) {
- ret = -ENOMEM;
- kfree(sdev);
- goto out;
- }
-
- if (pasid_max > intel_pasid_max_id)
- pasid_max = intel_pasid_max_id;
+ /* Setup the pasid table: */
+ sflags = (flags & SVM_FLAG_SUPERVISOR_MODE) ?
+ PASID_FLAG_SUPERVISOR_MODE : 0;
+ sflags |= cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;
+ spin_lock_irqsave(&iommu->lock, iflags);
+ ret = intel_pasid_setup_first_level(iommu, dev, mm->pgd, mm->pasid,
+ FLPT_DEFAULT_DID, sflags);
+ spin_unlock_irqrestore(&iommu->lock, iflags);
- /* Do not use PASID 0, reserved for RID to PASID */
- svm->pasid = ioasid_alloc(NULL, PASID_MIN,
- pasid_max - 1, svm);
- if (svm->pasid == INVALID_IOASID) {
- kfree(svm);
- kfree(sdev);
- ret = -ENOSPC;
- goto out;
- }
- svm->notifier.ops = &intel_mmuops;
- svm->mm = mm;
- svm->flags = flags;
- INIT_LIST_HEAD_RCU(&svm->devs);
- INIT_LIST_HEAD(&svm->list);
- ret = -ENOMEM;
- if (mm) {
- ret = mmu_notifier_register(&svm->notifier, mm);
- if (ret) {
- ioasid_put(svm->pasid);
- kfree(svm);
- kfree(sdev);
- goto out;
- }
- }
+ if (ret)
+ goto free_sdev;
- spin_lock_irqsave(&iommu->lock, iflags);
- 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) |
- (cpu_feature_enabled(X86_FEATURE_LA57) ?
- PASID_FLAG_FL5LP : 0));
- spin_unlock_irqrestore(&iommu->lock, iflags);
- if (ret) {
- if (mm)
- mmu_notifier_unregister(&svm->notifier, mm);
- ioasid_put(svm->pasid);
- kfree(svm);
- kfree(sdev);
- goto out;
- }
+ /* The newly allocated pasid is loaded to the mm. */
+ if (!(flags & SVM_FLAG_SUPERVISOR_MODE) && list_empty(&svm->devs))
+ load_pasid(mm, svm->pasid);
- list_add_tail(&svm->list, &global_svm_list);
- if (mm) {
- /* The newly allocated pasid is loaded to the mm. */
- load_pasid(mm, svm->pasid);
- }
- } else {
- /*
- * Binding a new device with existing PASID, need to setup
- * the PASID entry.
- */
- spin_lock_irqsave(&iommu->lock, iflags);
- 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) |
- (cpu_feature_enabled(X86_FEATURE_LA57) ?
- PASID_FLAG_FL5LP : 0));
- spin_unlock_irqrestore(&iommu->lock, iflags);
- if (ret) {
- kfree(sdev);
- goto out;
- }
- }
list_add_rcu(&sdev->list, &svm->devs);
success:
- sdev->pasid = svm->pasid;
- sdev->sva.dev = dev;
- if (sd)
- *sd = sdev;
- ret = 0;
-out:
- return ret;
+ return &sdev->sva;
+
+free_sdev:
+ kfree(sdev);
+free_svm:
+ if (list_empty(&svm->devs)) {
+ if (svm->notifier.ops)
+ mmu_notifier_unregister(&svm->notifier, mm);
+ pasid_private_remove(mm->pasid);
+ kfree(svm);
+ }
+
+ return ERR_PTR(ret);
}
/* Caller must hold pasid_mutex */
@@ -636,6 +646,7 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid)
struct intel_svm_dev *sdev;
struct intel_iommu *iommu;
struct intel_svm *svm;
+ struct mm_struct *mm;
int ret = -EINVAL;
iommu = device_to_iommu(dev, NULL, NULL);
@@ -645,6 +656,7 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid)
ret = pasid_to_svm_sdev(dev, pasid, &svm, &sdev);
if (ret)
goto out;
+ mm = svm->mm;
if (sdev) {
sdev->users--;
@@ -663,13 +675,13 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid)
kfree_rcu(sdev, rcu);
if (list_empty(&svm->devs)) {
- ioasid_put(svm->pasid);
- if (svm->mm) {
- mmu_notifier_unregister(&svm->notifier, svm->mm);
+ intel_svm_free_pasid(mm);
+ if (svm->notifier.ops) {
+ mmu_notifier_unregister(&svm->notifier, mm);
/* Clear mm's pasid. */
- load_pasid(svm->mm, PASID_DISABLED);
+ load_pasid(mm, PASID_DISABLED);
}
- list_del(&svm->list);
+ pasid_private_remove(svm->pasid);
/* We mandate that no page faults may be outstanding
* for the PASID when intel_svm_unbind_mm() is called.
* If that is not obeyed, subtle errors will happen.
@@ -714,22 +726,6 @@ struct page_req_dsc {
#define PRQ_RING_MASK ((0x1000 << PRQ_ORDER) - 0x20)
-static bool access_error(struct vm_area_struct *vma, struct page_req_dsc *req)
-{
- unsigned long requested = 0;
-
- if (req->exe_req)
- requested |= VM_EXEC;
-
- if (req->rd_req)
- requested |= VM_READ;
-
- if (req->wr_req)
- requested |= VM_WRITE;
-
- return (requested & ~vma->vm_flags) != 0;
-}
-
static bool is_canonical_address(u64 addr)
{
int shift = 64 - (__VIRTUAL_MASK_SHIFT + 1);
@@ -799,6 +795,8 @@ prq_retry:
goto prq_retry;
}
+ iopf_queue_flush_dev(dev);
+
/*
* Perform steps described in VT-d spec CH7.10 to drain page
* requests and responses in hardware.
@@ -841,8 +839,8 @@ static int prq_to_iommu_prot(struct page_req_dsc *req)
return prot;
}
-static int
-intel_svm_prq_report(struct device *dev, struct page_req_dsc *desc)
+static int intel_svm_prq_report(struct intel_iommu *iommu, struct device *dev,
+ struct page_req_dsc *desc)
{
struct iommu_fault_event event;
@@ -872,159 +870,136 @@ intel_svm_prq_report(struct device *dev, struct page_req_dsc *desc)
*/
event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE;
event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PRIV_DATA;
- memcpy(event.fault.prm.private_data, desc->priv_data,
- sizeof(desc->priv_data));
+ event.fault.prm.private_data[0] = desc->priv_data[0];
+ event.fault.prm.private_data[1] = desc->priv_data[1];
+ } else if (dmar_latency_enabled(iommu, DMAR_LATENCY_PRQ)) {
+ /*
+ * If the private data fields are not used by hardware, use it
+ * to monitor the prq handle latency.
+ */
+ event.fault.prm.private_data[0] = ktime_to_ns(ktime_get());
}
return iommu_report_device_fault(dev, &event);
}
+static void handle_bad_prq_event(struct intel_iommu *iommu,
+ struct page_req_dsc *req, int result)
+{
+ struct qi_desc desc;
+
+ pr_err("%s: Invalid page request: %08llx %08llx\n",
+ iommu->name, ((unsigned long long *)req)[0],
+ ((unsigned long long *)req)[1]);
+
+ /*
+ * Per VT-d spec. v3.0 ch7.7, system software must
+ * respond with page group response if private data
+ * is present (PDP) or last page in group (LPIG) bit
+ * is set. This is an additional VT-d feature beyond
+ * PCI ATS spec.
+ */
+ if (!req->lpig && !req->priv_data_present)
+ return;
+
+ desc.qw0 = QI_PGRP_PASID(req->pasid) |
+ QI_PGRP_DID(req->rid) |
+ QI_PGRP_PASID_P(req->pasid_present) |
+ QI_PGRP_PDP(req->priv_data_present) |
+ QI_PGRP_RESP_CODE(result) |
+ QI_PGRP_RESP_TYPE;
+ desc.qw1 = QI_PGRP_IDX(req->prg_index) |
+ QI_PGRP_LPIG(req->lpig);
+
+ if (req->priv_data_present) {
+ desc.qw2 = req->priv_data[0];
+ desc.qw3 = req->priv_data[1];
+ } else {
+ desc.qw2 = 0;
+ desc.qw3 = 0;
+ }
+
+ qi_submit_sync(iommu, &desc, 1, 0);
+}
+
static irqreturn_t prq_event_thread(int irq, void *d)
{
struct intel_svm_dev *sdev = NULL;
struct intel_iommu *iommu = d;
struct intel_svm *svm = NULL;
- int head, tail, handled = 0;
- unsigned int flags = 0;
+ struct page_req_dsc *req;
+ int head, tail, handled;
+ u64 address;
- /* Clear PPR bit before reading head/tail registers, to
- * ensure that we get a new interrupt if needed. */
+ /*
+ * Clear PPR bit before reading head/tail registers, to ensure that
+ * we get a new interrupt if needed.
+ */
writel(DMA_PRS_PPR, iommu->reg + DMAR_PRS_REG);
tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK;
head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK;
+ handled = (head != tail);
while (head != tail) {
- struct vm_area_struct *vma;
- struct page_req_dsc *req;
- struct qi_desc resp;
- int result;
- vm_fault_t ret;
- u64 address;
-
- handled = 1;
req = &iommu->prq[head / sizeof(*req)];
- result = QI_RESP_INVALID;
address = (u64)req->addr << VTD_PAGE_SHIFT;
- if (!req->pasid_present) {
- pr_err("%s: Page request without PASID: %08llx %08llx\n",
- iommu->name, ((unsigned long long *)req)[0],
- ((unsigned long long *)req)[1]);
- goto no_pasid;
+
+ if (unlikely(!req->pasid_present)) {
+ pr_err("IOMMU: %s: Page request without PASID\n",
+ iommu->name);
+bad_req:
+ svm = NULL;
+ sdev = NULL;
+ handle_bad_prq_event(iommu, req, QI_RESP_INVALID);
+ goto prq_advance;
}
- /* We shall not receive page request for supervisor SVM */
- if (req->pm_req && (req->rd_req | req->wr_req)) {
- pr_err("Unexpected page request in Privilege Mode");
- /* No need to find the matching sdev as for bad_req */
- goto no_pasid;
+
+ if (unlikely(!is_canonical_address(address))) {
+ pr_err("IOMMU: %s: Address is not canonical\n",
+ iommu->name);
+ goto bad_req;
}
- /* DMA read with exec requeset is not supported. */
- if (req->exe_req && req->rd_req) {
- pr_err("Execution request not supported\n");
- goto no_pasid;
+
+ if (unlikely(req->pm_req && (req->rd_req | req->wr_req))) {
+ pr_err("IOMMU: %s: Page request in Privilege Mode\n",
+ iommu->name);
+ goto bad_req;
}
+
+ if (unlikely(req->exe_req && req->rd_req)) {
+ pr_err("IOMMU: %s: Execution request not supported\n",
+ iommu->name);
+ goto bad_req;
+ }
+
if (!svm || svm->pasid != req->pasid) {
- rcu_read_lock();
- svm = ioasid_find(NULL, req->pasid, NULL);
- /* It *can't* go away, because the driver is not permitted
+ /*
+ * It can't go away, because the driver is not permitted
* to unbind the mm while any page faults are outstanding.
- * So we only need RCU to protect the internal idr code. */
- rcu_read_unlock();
- if (IS_ERR_OR_NULL(svm)) {
- pr_err("%s: Page request for invalid PASID %d: %08llx %08llx\n",
- iommu->name, req->pasid, ((unsigned long long *)req)[0],
- ((unsigned long long *)req)[1]);
- goto no_pasid;
- }
+ */
+ svm = pasid_private_find(req->pasid);
+ if (IS_ERR_OR_NULL(svm) || (svm->flags & SVM_FLAG_SUPERVISOR_MODE))
+ goto bad_req;
}
if (!sdev || sdev->sid != req->rid) {
- struct intel_svm_dev *t;
-
- sdev = NULL;
- rcu_read_lock();
- list_for_each_entry_rcu(t, &svm->devs, list) {
- if (t->sid == req->rid) {
- sdev = t;
- break;
- }
- }
- rcu_read_unlock();
+ sdev = svm_lookup_device_by_sid(svm, req->rid);
+ if (!sdev)
+ goto bad_req;
}
- /* Since we're using init_mm.pgd directly, we should never take
- * any faults on kernel addresses. */
- if (!svm->mm)
- goto bad_req;
-
- /* If address is not canonical, return invalid response */
- if (!is_canonical_address(address))
- goto bad_req;
+ sdev->prq_seq_number++;
/*
* If prq is to be handled outside iommu driver via receiver of
* the fault notifiers, we skip the page response here.
*/
- if (svm->flags & SVM_FLAG_GUEST_MODE) {
- if (sdev && !intel_svm_prq_report(sdev->dev, req))
- goto prq_advance;
- else
- goto bad_req;
- }
-
- /* If the mm is already defunct, don't handle faults. */
- if (!mmget_not_zero(svm->mm))
- goto bad_req;
-
- mmap_read_lock(svm->mm);
- vma = find_extend_vma(svm->mm, address);
- if (!vma || address < vma->vm_start)
- goto invalid;
-
- if (access_error(vma, req))
- goto invalid;
+ if (intel_svm_prq_report(iommu, sdev->dev, req))
+ handle_bad_prq_event(iommu, req, QI_RESP_INVALID);
- flags = FAULT_FLAG_USER | FAULT_FLAG_REMOTE;
- if (req->wr_req)
- flags |= FAULT_FLAG_WRITE;
-
- ret = handle_mm_fault(vma, address, flags, NULL);
- if (ret & VM_FAULT_ERROR)
- goto invalid;
-
- result = QI_RESP_SUCCESS;
-invalid:
- mmap_read_unlock(svm->mm);
- mmput(svm->mm);
-bad_req:
- /* We get here in the error case where the PASID lookup failed,
- and these can be NULL. Do not use them below this point! */
- sdev = NULL;
- svm = NULL;
-no_pasid:
- if (req->lpig || req->priv_data_present) {
- /*
- * Per VT-d spec. v3.0 ch7.7, system software must
- * respond with page group response if private data
- * is present (PDP) or last page in group (LPIG) bit
- * is set. This is an additional VT-d feature beyond
- * PCI ATS spec.
- */
- resp.qw0 = QI_PGRP_PASID(req->pasid) |
- QI_PGRP_DID(req->rid) |
- QI_PGRP_PASID_P(req->pasid_present) |
- QI_PGRP_PDP(req->priv_data_present) |
- QI_PGRP_RESP_CODE(result) |
- QI_PGRP_RESP_TYPE;
- resp.qw1 = QI_PGRP_IDX(req->prg_index) |
- QI_PGRP_LPIG(req->lpig);
- resp.qw2 = 0;
- resp.qw3 = 0;
-
- if (req->priv_data_present)
- memcpy(&resp.qw2, req->priv_data,
- sizeof(req->priv_data));
- qi_submit_sync(iommu, &resp, 1, 0);
- }
+ trace_prq_report(iommu, sdev->dev, req->qw_0, req->qw_1,
+ req->priv_data[0], req->priv_data[1],
+ sdev->prq_seq_number);
prq_advance:
head = (head + sizeof(*req)) & PRQ_RING_MASK;
}
@@ -1041,6 +1016,7 @@ prq_advance:
head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK;
tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK;
if (head == tail) {
+ iopf_queue_discard_partial(iommu->iopf_queue);
writel(DMA_PRS_PRO, iommu->reg + DMAR_PRS_REG);
pr_info_ratelimited("IOMMU: %s: PRQ overflow cleared",
iommu->name);
@@ -1053,31 +1029,42 @@ prq_advance:
return IRQ_RETVAL(handled);
}
-#define to_intel_svm_dev(handle) container_of(handle, struct intel_svm_dev, sva)
-struct iommu_sva *
-intel_svm_bind(struct device *dev, struct mm_struct *mm, void *drvdata)
+struct iommu_sva *intel_svm_bind(struct device *dev, struct mm_struct *mm, void *drvdata)
{
- struct iommu_sva *sva = ERR_PTR(-EINVAL);
- struct intel_svm_dev *sdev = NULL;
+ struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL);
unsigned int flags = 0;
+ struct iommu_sva *sva;
int ret;
- /*
- * TODO: Consolidate with generic iommu-sva bind after it is merged.
- * It will require shared SVM data structures, i.e. combine io_mm
- * and intel_svm etc.
- */
if (drvdata)
flags = *(unsigned int *)drvdata;
+
+ if (flags & SVM_FLAG_SUPERVISOR_MODE) {
+ if (!ecap_srs(iommu->ecap)) {
+ dev_err(dev, "%s: Supervisor PASID not supported\n",
+ iommu->name);
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+
+ if (mm) {
+ dev_err(dev, "%s: Supervisor PASID with user provided mm\n",
+ iommu->name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ mm = &init_mm;
+ }
+
mutex_lock(&pasid_mutex);
- ret = intel_svm_bind_mm(dev, flags, mm, &sdev);
- if (ret)
- sva = ERR_PTR(ret);
- else if (sdev)
- sva = &sdev->sva;
- else
- WARN(!sdev, "SVM bind succeeded with no sdev!\n");
+ ret = intel_svm_alloc_pasid(dev, mm, flags);
+ if (ret) {
+ mutex_unlock(&pasid_mutex);
+ return ERR_PTR(ret);
+ }
+ sva = intel_svm_bind_mm(iommu, dev, mm, flags);
+ if (IS_ERR_OR_NULL(sva))
+ intel_svm_free_pasid(mm);
mutex_unlock(&pasid_mutex);
return sva;
@@ -1085,10 +1072,9 @@ intel_svm_bind(struct device *dev, struct mm_struct *mm, void *drvdata)
void intel_svm_unbind(struct iommu_sva *sva)
{
- struct intel_svm_dev *sdev;
+ struct intel_svm_dev *sdev = to_intel_svm_dev(sva);
mutex_lock(&pasid_mutex);
- sdev = to_intel_svm_dev(sva);
intel_svm_unbind_mm(sdev->dev, sdev->pasid);
mutex_unlock(&pasid_mutex);
}
@@ -1194,9 +1180,14 @@ int intel_svm_page_response(struct device *dev,
desc.qw1 = QI_PGRP_IDX(prm->grpid) | QI_PGRP_LPIG(last_page);
desc.qw2 = 0;
desc.qw3 = 0;
- if (private_present)
- memcpy(&desc.qw2, prm->private_data,
- sizeof(prm->private_data));
+
+ if (private_present) {
+ desc.qw2 = prm->private_data[0];
+ desc.qw3 = prm->private_data[1];
+ } else if (prm->private_data[0]) {
+ dmar_latency_update(iommu, DMAR_LATENCY_PRQ,
+ ktime_to_ns(ktime_get()) - prm->private_data[0]);
+ }
qi_submit_sync(iommu, &desc, 1, 0);
}
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 808ab70d5df5..5419c4b9f27a 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -3059,9 +3059,6 @@ static int iommu_change_dev_def_domain(struct iommu_group *group,
int ret, dev_def_dom;
struct device *dev;
- if (!group)
- return -EINVAL;
-
mutex_lock(&group->mutex);
if (group->default_domain != group->domain) {
diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c
index b7ecd5b08039..b6cf5f16123b 100644
--- a/drivers/iommu/iova.c
+++ b/drivers/iommu/iova.c
@@ -412,12 +412,11 @@ private_find_iova(struct iova_domain *iovad, unsigned long pfn)
return NULL;
}
-static void private_free_iova(struct iova_domain *iovad, struct iova *iova)
+static void remove_iova(struct iova_domain *iovad, struct iova *iova)
{
assert_spin_locked(&iovad->iova_rbtree_lock);
__cached_rbnode_delete_update(iovad, iova);
rb_erase(&iova->node, &iovad->rbroot);
- free_iova_mem(iova);
}
/**
@@ -452,8 +451,9 @@ __free_iova(struct iova_domain *iovad, struct iova *iova)
unsigned long flags;
spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
- private_free_iova(iovad, iova);
+ remove_iova(iovad, iova);
spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+ free_iova_mem(iova);
}
EXPORT_SYMBOL_GPL(__free_iova);
@@ -472,10 +472,13 @@ free_iova(struct iova_domain *iovad, unsigned long pfn)
spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
iova = private_find_iova(iovad, pfn);
- if (iova)
- private_free_iova(iovad, iova);
+ if (!iova) {
+ spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+ return;
+ }
+ remove_iova(iovad, iova);
spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
-
+ free_iova_mem(iova);
}
EXPORT_SYMBOL_GPL(free_iova);
@@ -825,7 +828,8 @@ iova_magazine_free_pfns(struct iova_magazine *mag, struct iova_domain *iovad)
if (WARN_ON(!iova))
continue;
- private_free_iova(iovad, iova);
+ remove_iova(iovad, iova);
+ free_iova_mem(iova);
}
spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index aaa6a4d59057..51ea6f00db2f 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -19,7 +19,6 @@
#include <linux/iommu.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_iommu.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/sizes.h>
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index 7880f307cb2d..3a38352b603f 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -18,7 +18,6 @@
#include <linux/iommu.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <linux/of_iommu.h>
#include <asm/cacheflush.h>
#include <linux/sizes.h>
diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index e06b8a0e2b56..6f7c69688ce2 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -19,7 +19,6 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_address.h>
-#include <linux/of_iommu.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index 5915d7b38211..778e66f5f1aa 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -22,7 +22,6 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of_address.h>
-#include <linux/of_iommu.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index a9d2df001149..5696314ae69e 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -19,74 +19,6 @@
#define NO_IOMMU 1
-/**
- * of_get_dma_window - Parse *dma-window property and returns 0 if found.
- *
- * @dn: device node
- * @prefix: prefix for property name if any
- * @index: index to start to parse
- * @busno: Returns busno if supported. Otherwise pass NULL
- * @addr: Returns address that DMA starts
- * @size: Returns the range that DMA can handle
- *
- * This supports different formats flexibly. "prefix" can be
- * configured if any. "busno" and "index" are optionally
- * specified. Set 0(or NULL) if not used.
- */
-int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
- unsigned long *busno, dma_addr_t *addr, size_t *size)
-{
- const __be32 *dma_window, *end;
- int bytes, cur_index = 0;
- char propname[NAME_MAX], addrname[NAME_MAX], sizename[NAME_MAX];
-
- if (!dn || !addr || !size)
- return -EINVAL;
-
- if (!prefix)
- prefix = "";
-
- snprintf(propname, sizeof(propname), "%sdma-window", prefix);
- snprintf(addrname, sizeof(addrname), "%s#dma-address-cells", prefix);
- snprintf(sizename, sizeof(sizename), "%s#dma-size-cells", prefix);
-
- dma_window = of_get_property(dn, propname, &bytes);
- if (!dma_window)
- return -ENODEV;
- end = dma_window + bytes / sizeof(*dma_window);
-
- while (dma_window < end) {
- u32 cells;
- const void *prop;
-
- /* busno is one cell if supported */
- if (busno)
- *busno = be32_to_cpup(dma_window++);
-
- prop = of_get_property(dn, addrname, NULL);
- if (!prop)
- prop = of_get_property(dn, "#address-cells", NULL);
-
- cells = prop ? be32_to_cpup(prop) : of_n_addr_cells(dn);
- if (!cells)
- return -EINVAL;
- *addr = of_read_number(dma_window, cells);
- dma_window += cells;
-
- prop = of_get_property(dn, sizename, NULL);
- cells = prop ? be32_to_cpup(prop) : of_n_size_cells(dn);
- if (!cells)
- return -EINVAL;
- *size = of_read_number(dma_window, cells);
- dma_window += cells;
-
- if (cur_index++ == index)
- break;
- }
- return 0;
-}
-EXPORT_SYMBOL_GPL(of_get_dma_window);
-
static int of_iommu_xlate(struct device *dev,
struct of_phandle_args *iommu_spec)
{
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index 26e517eb0dd3..91749654fd49 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -22,7 +22,6 @@
#include <linux/io.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
-#include <linux/of_iommu.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 7a2932772fdf..9febfb7f3025 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -21,7 +21,6 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/of.h>
-#include <linux/of_iommu.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -96,6 +95,15 @@ static const char * const rk_iommu_clocks[] = {
"aclk", "iface",
};
+struct rk_iommu_ops {
+ phys_addr_t (*pt_address)(u32 dte);
+ u32 (*mk_dtentries)(dma_addr_t pt_dma);
+ u32 (*mk_ptentries)(phys_addr_t page, int prot);
+ phys_addr_t (*dte_addr_phys)(u32 addr);
+ u32 (*dma_addr_dte)(dma_addr_t dt_dma);
+ u64 dma_bit_mask;
+};
+
struct rk_iommu {
struct device *dev;
void __iomem **bases;
@@ -116,6 +124,7 @@ struct rk_iommudata {
};
static struct device *dma_dev;
+static const struct rk_iommu_ops *rk_ops;
static inline void rk_table_flush(struct rk_iommu_domain *dom, dma_addr_t dma,
unsigned int count)
@@ -179,6 +188,33 @@ static inline phys_addr_t rk_dte_pt_address(u32 dte)
return (phys_addr_t)dte & RK_DTE_PT_ADDRESS_MASK;
}
+/*
+ * In v2:
+ * 31:12 - PT address bit 31:0
+ * 11: 8 - PT address bit 35:32
+ * 7: 4 - PT address bit 39:36
+ * 3: 1 - Reserved
+ * 0 - 1 if PT @ PT address is valid
+ */
+#define RK_DTE_PT_ADDRESS_MASK_V2 GENMASK_ULL(31, 4)
+#define DTE_HI_MASK1 GENMASK(11, 8)
+#define DTE_HI_MASK2 GENMASK(7, 4)
+#define DTE_HI_SHIFT1 24 /* shift bit 8 to bit 32 */
+#define DTE_HI_SHIFT2 32 /* shift bit 4 to bit 36 */
+#define PAGE_DESC_HI_MASK1 GENMASK_ULL(39, 36)
+#define PAGE_DESC_HI_MASK2 GENMASK_ULL(35, 32)
+
+static inline phys_addr_t rk_dte_pt_address_v2(u32 dte)
+{
+ u64 dte_v2 = dte;
+
+ dte_v2 = ((dte_v2 & DTE_HI_MASK2) << DTE_HI_SHIFT2) |
+ ((dte_v2 & DTE_HI_MASK1) << DTE_HI_SHIFT1) |
+ (dte_v2 & RK_DTE_PT_ADDRESS_MASK);
+
+ return (phys_addr_t)dte_v2;
+}
+
static inline bool rk_dte_is_pt_valid(u32 dte)
{
return dte & RK_DTE_PT_VALID;
@@ -189,6 +225,15 @@ static inline u32 rk_mk_dte(dma_addr_t pt_dma)
return (pt_dma & RK_DTE_PT_ADDRESS_MASK) | RK_DTE_PT_VALID;
}
+static inline u32 rk_mk_dte_v2(dma_addr_t pt_dma)
+{
+ pt_dma = (pt_dma & RK_DTE_PT_ADDRESS_MASK) |
+ ((pt_dma & PAGE_DESC_HI_MASK1) >> DTE_HI_SHIFT1) |
+ (pt_dma & PAGE_DESC_HI_MASK2) >> DTE_HI_SHIFT2;
+
+ return (pt_dma & RK_DTE_PT_ADDRESS_MASK_V2) | RK_DTE_PT_VALID;
+}
+
/*
* Each PTE has a Page address, some flags and a valid bit:
* +---------------------+---+-------+-+
@@ -215,11 +260,6 @@ static inline u32 rk_mk_dte(dma_addr_t pt_dma)
#define RK_PTE_PAGE_READABLE BIT(1)
#define RK_PTE_PAGE_VALID BIT(0)
-static inline phys_addr_t rk_pte_page_address(u32 pte)
-{
- return (phys_addr_t)pte & RK_PTE_PAGE_ADDRESS_MASK;
-}
-
static inline bool rk_pte_is_page_valid(u32 pte)
{
return pte & RK_PTE_PAGE_VALID;
@@ -235,6 +275,29 @@ static u32 rk_mk_pte(phys_addr_t page, int prot)
return page | flags | RK_PTE_PAGE_VALID;
}
+/*
+ * In v2:
+ * 31:12 - Page address bit 31:0
+ * 11:9 - Page address bit 34:32
+ * 8:4 - Page address bit 39:35
+ * 3 - Security
+ * 2 - Readable
+ * 1 - Writable
+ * 0 - 1 if Page @ Page address is valid
+ */
+#define RK_PTE_PAGE_READABLE_V2 BIT(2)
+#define RK_PTE_PAGE_WRITABLE_V2 BIT(1)
+
+static u32 rk_mk_pte_v2(phys_addr_t page, int prot)
+{
+ u32 flags = 0;
+
+ flags |= (prot & IOMMU_READ) ? RK_PTE_PAGE_READABLE_V2 : 0;
+ flags |= (prot & IOMMU_WRITE) ? RK_PTE_PAGE_WRITABLE_V2 : 0;
+
+ return rk_mk_dte_v2(page) | flags;
+}
+
static u32 rk_mk_pte_invalid(u32 pte)
{
return pte & ~RK_PTE_PAGE_VALID;
@@ -448,10 +511,10 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu)
* and verifying that upper 5 nybbles are read back.
*/
for (i = 0; i < iommu->num_mmu; i++) {
- rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, DTE_ADDR_DUMMY);
+ dte_addr = rk_ops->pt_address(DTE_ADDR_DUMMY);
+ rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, dte_addr);
- dte_addr = rk_iommu_read(iommu->bases[i], RK_MMU_DTE_ADDR);
- if (dte_addr != (DTE_ADDR_DUMMY & RK_DTE_PT_ADDRESS_MASK)) {
+ if (dte_addr != rk_iommu_read(iommu->bases[i], RK_MMU_DTE_ADDR)) {
dev_err(iommu->dev, "Error during raw reset. MMU_DTE_ADDR is not functioning\n");
return -EFAULT;
}
@@ -470,6 +533,33 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu)
return 0;
}
+static inline phys_addr_t rk_dte_addr_phys(u32 addr)
+{
+ return (phys_addr_t)addr;
+}
+
+static inline u32 rk_dma_addr_dte(dma_addr_t dt_dma)
+{
+ return dt_dma;
+}
+
+#define DT_HI_MASK GENMASK_ULL(39, 32)
+#define DTE_BASE_HI_MASK GENMASK(11, 4)
+#define DT_SHIFT 28
+
+static inline phys_addr_t rk_dte_addr_phys_v2(u32 addr)
+{
+ u64 addr64 = addr;
+ return (phys_addr_t)(addr64 & RK_DTE_PT_ADDRESS_MASK) |
+ ((addr64 & DTE_BASE_HI_MASK) << DT_SHIFT);
+}
+
+static inline u32 rk_dma_addr_dte_v2(dma_addr_t dt_dma)
+{
+ return (dt_dma & RK_DTE_PT_ADDRESS_MASK) |
+ ((dt_dma & DT_HI_MASK) >> DT_SHIFT);
+}
+
static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova)
{
void __iomem *base = iommu->bases[index];
@@ -489,7 +579,7 @@ static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova)
page_offset = rk_iova_page_offset(iova);
mmu_dte_addr = rk_iommu_read(base, RK_MMU_DTE_ADDR);
- mmu_dte_addr_phys = (phys_addr_t)mmu_dte_addr;
+ mmu_dte_addr_phys = rk_ops->dte_addr_phys(mmu_dte_addr);
dte_addr_phys = mmu_dte_addr_phys + (4 * dte_index);
dte_addr = phys_to_virt(dte_addr_phys);
@@ -498,14 +588,14 @@ static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova)
if (!rk_dte_is_pt_valid(dte))
goto print_it;
- pte_addr_phys = rk_dte_pt_address(dte) + (pte_index * 4);
+ pte_addr_phys = rk_ops->pt_address(dte) + (pte_index * 4);
pte_addr = phys_to_virt(pte_addr_phys);
pte = *pte_addr;
if (!rk_pte_is_page_valid(pte))
goto print_it;
- page_addr_phys = rk_pte_page_address(pte) + page_offset;
+ page_addr_phys = rk_ops->pt_address(pte) + page_offset;
page_flags = pte & RK_PTE_PAGE_FLAGS_MASK;
print_it:
@@ -601,13 +691,13 @@ static phys_addr_t rk_iommu_iova_to_phys(struct iommu_domain *domain,
if (!rk_dte_is_pt_valid(dte))
goto out;
- pt_phys = rk_dte_pt_address(dte);
+ pt_phys = rk_ops->pt_address(dte);
page_table = (u32 *)phys_to_virt(pt_phys);
pte = page_table[rk_iova_pte_index(iova)];
if (!rk_pte_is_page_valid(pte))
goto out;
- phys = rk_pte_page_address(pte) + rk_iova_page_offset(iova);
+ phys = rk_ops->pt_address(pte) + rk_iova_page_offset(iova);
out:
spin_unlock_irqrestore(&rk_domain->dt_lock, flags);
@@ -679,14 +769,13 @@ static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain,
return ERR_PTR(-ENOMEM);
}
- dte = rk_mk_dte(pt_dma);
+ dte = rk_ops->mk_dtentries(pt_dma);
*dte_addr = dte;
- rk_table_flush(rk_domain, pt_dma, NUM_PT_ENTRIES);
rk_table_flush(rk_domain,
rk_domain->dt_dma + dte_index * sizeof(u32), 1);
done:
- pt_phys = rk_dte_pt_address(dte);
+ pt_phys = rk_ops->pt_address(dte);
return (u32 *)phys_to_virt(pt_phys);
}
@@ -728,7 +817,7 @@ static int rk_iommu_map_iova(struct rk_iommu_domain *rk_domain, u32 *pte_addr,
if (rk_pte_is_page_valid(pte))
goto unwind;
- pte_addr[pte_count] = rk_mk_pte(paddr, prot);
+ pte_addr[pte_count] = rk_ops->mk_ptentries(paddr, prot);
paddr += SPAGE_SIZE;
}
@@ -750,7 +839,7 @@ unwind:
pte_count * SPAGE_SIZE);
iova += pte_count * SPAGE_SIZE;
- page_phys = rk_pte_page_address(pte_addr[pte_count]);
+ page_phys = rk_ops->pt_address(pte_addr[pte_count]);
pr_err("iova: %pad already mapped to %pa cannot remap to phys: %pa prot: %#x\n",
&iova, &page_phys, &paddr, prot);
@@ -785,7 +874,8 @@ static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova,
dte_index = rk_domain->dt[rk_iova_dte_index(iova)];
pte_index = rk_iova_pte_index(iova);
pte_addr = &page_table[pte_index];
- pte_dma = rk_dte_pt_address(dte_index) + pte_index * sizeof(u32);
+
+ pte_dma = rk_ops->pt_address(dte_index) + pte_index * sizeof(u32);
ret = rk_iommu_map_iova(rk_domain, pte_addr, pte_dma, iova,
paddr, size, prot);
@@ -821,7 +911,7 @@ static size_t rk_iommu_unmap(struct iommu_domain *domain, unsigned long _iova,
return 0;
}
- pt_phys = rk_dte_pt_address(dte);
+ pt_phys = rk_ops->pt_address(dte);
pte_addr = (u32 *)phys_to_virt(pt_phys) + rk_iova_pte_index(iova);
pte_dma = pt_phys + rk_iova_pte_index(iova) * sizeof(u32);
unmap_size = rk_iommu_unmap_iova(rk_domain, pte_addr, pte_dma, size);
@@ -879,7 +969,7 @@ static int rk_iommu_enable(struct rk_iommu *iommu)
for (i = 0; i < iommu->num_mmu; i++) {
rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR,
- rk_domain->dt_dma);
+ rk_ops->dma_addr_dte(rk_domain->dt_dma));
rk_iommu_base_command(iommu->bases[i], RK_MMU_CMD_ZAP_CACHE);
rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, RK_MMU_IRQ_MASK);
}
@@ -1004,8 +1094,6 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
goto err_free_dt;
}
- rk_table_flush(rk_domain, rk_domain->dt_dma, NUM_DT_ENTRIES);
-
spin_lock_init(&rk_domain->iommus_lock);
spin_lock_init(&rk_domain->dt_lock);
INIT_LIST_HEAD(&rk_domain->iommus);
@@ -1037,7 +1125,7 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
for (i = 0; i < NUM_DT_ENTRIES; i++) {
u32 dte = rk_domain->dt[i];
if (rk_dte_is_pt_valid(dte)) {
- phys_addr_t pt_phys = rk_dte_pt_address(dte);
+ phys_addr_t pt_phys = rk_ops->pt_address(dte);
u32 *page_table = phys_to_virt(pt_phys);
dma_unmap_single(dma_dev, pt_phys,
SPAGE_SIZE, DMA_TO_DEVICE);
@@ -1127,6 +1215,7 @@ static int rk_iommu_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct rk_iommu *iommu;
struct resource *res;
+ const struct rk_iommu_ops *ops;
int num_res = pdev->num_resources;
int err, i;
@@ -1138,6 +1227,17 @@ static int rk_iommu_probe(struct platform_device *pdev)
iommu->dev = dev;
iommu->num_mmu = 0;
+ ops = of_device_get_match_data(dev);
+ if (!rk_ops)
+ rk_ops = ops;
+
+ /*
+ * That should not happen unless different versions of the
+ * hardware block are embedded the same SoC
+ */
+ if (WARN_ON(rk_ops != ops))
+ return -EINVAL;
+
iommu->bases = devm_kcalloc(dev, num_res, sizeof(*iommu->bases),
GFP_KERNEL);
if (!iommu->bases)
@@ -1226,6 +1326,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
}
}
+ dma_set_mask_and_coherent(dev, rk_ops->dma_bit_mask);
+
return 0;
err_remove_sysfs:
iommu_device_sysfs_remove(&iommu->iommu);
@@ -1277,8 +1379,31 @@ static const struct dev_pm_ops rk_iommu_pm_ops = {
pm_runtime_force_resume)
};
+static struct rk_iommu_ops iommu_data_ops_v1 = {
+ .pt_address = &rk_dte_pt_address,
+ .mk_dtentries = &rk_mk_dte,
+ .mk_ptentries = &rk_mk_pte,
+ .dte_addr_phys = &rk_dte_addr_phys,
+ .dma_addr_dte = &rk_dma_addr_dte,
+ .dma_bit_mask = DMA_BIT_MASK(32),
+};
+
+static struct rk_iommu_ops iommu_data_ops_v2 = {
+ .pt_address = &rk_dte_pt_address_v2,
+ .mk_dtentries = &rk_mk_dte_v2,
+ .mk_ptentries = &rk_mk_pte_v2,
+ .dte_addr_phys = &rk_dte_addr_phys_v2,
+ .dma_addr_dte = &rk_dma_addr_dte_v2,
+ .dma_bit_mask = DMA_BIT_MASK(40),
+};
+
static const struct of_device_id rk_iommu_dt_ids[] = {
- { .compatible = "rockchip,iommu" },
+ { .compatible = "rockchip,iommu",
+ .data = &iommu_data_ops_v1,
+ },
+ { .compatible = "rockchip,rk3568-iommu",
+ .data = &iommu_data_ops_v2,
+ },
{ /* sentinel */ }
};
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 1e98dc63ad13..0a281833f611 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -376,9 +376,9 @@ static void tegra_smmu_enable(struct tegra_smmu *smmu, unsigned int swgroup,
if (client->swgroup != swgroup)
continue;
- value = smmu_readl(smmu, client->smmu.reg);
- value |= BIT(client->smmu.bit);
- smmu_writel(smmu, value, client->smmu.reg);
+ value = smmu_readl(smmu, client->regs.smmu.reg);
+ value |= BIT(client->regs.smmu.bit);
+ smmu_writel(smmu, value, client->regs.smmu.reg);
}
}
@@ -404,9 +404,9 @@ static void tegra_smmu_disable(struct tegra_smmu *smmu, unsigned int swgroup,
if (client->swgroup != swgroup)
continue;
- value = smmu_readl(smmu, client->smmu.reg);
- value &= ~BIT(client->smmu.bit);
- smmu_writel(smmu, value, client->smmu.reg);
+ value = smmu_readl(smmu, client->regs.smmu.reg);
+ value &= ~BIT(client->regs.smmu.bit);
+ smmu_writel(smmu, value, client->regs.smmu.reg);
}
}
@@ -1042,9 +1042,9 @@ static int tegra_smmu_clients_show(struct seq_file *s, void *data)
const struct tegra_mc_client *client = &smmu->soc->clients[i];
const char *status;
- value = smmu_readl(smmu, client->smmu.reg);
+ value = smmu_readl(smmu, client->regs.smmu.reg);
- if (value & BIT(client->smmu.bit))
+ if (value & BIT(client->regs.smmu.bit))
status = "yes";
else
status = "no";
diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c
index c6e5ee4d9cef..6abdcab7273b 100644
--- a/drivers/iommu/virtio-iommu.c
+++ b/drivers/iommu/virtio-iommu.c
@@ -10,11 +10,11 @@
#include <linux/amba/bus.h>
#include <linux/delay.h>
#include <linux/dma-iommu.h>
+#include <linux/dma-map-ops.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>
@@ -904,6 +904,15 @@ err_free_dev:
return ERR_PTR(ret);
}
+static void viommu_probe_finalize(struct device *dev)
+{
+#ifndef CONFIG_ARCH_HAS_SETUP_DMA_OPS
+ /* First clear the DMA ops in case we're switching from a DMA domain */
+ set_dma_ops(dev, NULL);
+ iommu_setup_dma_ops(dev, 0, U64_MAX);
+#endif
+}
+
static void viommu_release_device(struct device *dev)
{
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
@@ -940,6 +949,7 @@ static struct iommu_ops viommu_ops = {
.iova_to_phys = viommu_iova_to_phys,
.iotlb_sync = viommu_iotlb_sync,
.probe_device = viommu_probe_device,
+ .probe_finalize = viommu_probe_finalize,
.release_device = viommu_release_device,
.device_group = viommu_device_group,
.get_resv_regions = viommu_get_resv_regions,
diff --git a/drivers/ipack/carriers/tpci200.c b/drivers/ipack/carriers/tpci200.c
index ec71063fff76..3461b0a7dc62 100644
--- a/drivers/ipack/carriers/tpci200.c
+++ b/drivers/ipack/carriers/tpci200.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
- * tpci200.c
- *
+/*
* driver for the TEWS TPCI-200 device
*
* Copyright (C) 2009-2012 CERN (www.cern.ch)
@@ -596,8 +594,11 @@ static int tpci200_pci_probe(struct pci_dev *pdev,
out_err_bus_register:
tpci200_uninstall(tpci200);
+ /* tpci200->info->cfg_regs is unmapped in tpci200_uninstall */
+ tpci200->info->cfg_regs = NULL;
out_err_install:
- iounmap(tpci200->info->cfg_regs);
+ if (tpci200->info->cfg_regs)
+ iounmap(tpci200->info->cfg_regs);
out_err_ioremap:
pci_release_region(pdev, TPCI200_CFG_MEM_BAR);
out_err_pci_request:
diff --git a/drivers/ipack/carriers/tpci200.h b/drivers/ipack/carriers/tpci200.h
index 2619f827e33f..e79ac64abcff 100644
--- a/drivers/ipack/carriers/tpci200.h
+++ b/drivers/ipack/carriers/tpci200.h
@@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/**
- * tpci200.h
- *
+/*
* driver for the carrier TEWS TPCI-200
*
* Copyright (C) 2009-2012 CERN (www.cern.ch)
diff --git a/drivers/ipack/devices/ipoctal.c b/drivers/ipack/devices/ipoctal.c
index 3940714e4397..20fa02c81070 100644
--- a/drivers/ipack/devices/ipoctal.c
+++ b/drivers/ipack/devices/ipoctal.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
- * ipoctal.c
- *
+/*
* driver for the GE IP-OCTAL boards
*
* Copyright (C) 2009-2012 CERN (www.cern.ch)
@@ -460,14 +458,14 @@ static int ipoctal_write_tty(struct tty_struct *tty,
return char_copied;
}
-static int ipoctal_write_room(struct tty_struct *tty)
+static unsigned int ipoctal_write_room(struct tty_struct *tty)
{
struct ipoctal_channel *channel = tty->driver_data;
return PAGE_SIZE - channel->nb_bytes;
}
-static int ipoctal_chars_in_buffer(struct tty_struct *tty)
+static unsigned int ipoctal_chars_in_buffer(struct tty_struct *tty)
{
struct ipoctal_channel *channel = tty->driver_data;
diff --git a/drivers/ipack/devices/ipoctal.h b/drivers/ipack/devices/ipoctal.h
index 75f83ba774a4..773dc41bd667 100644
--- a/drivers/ipack/devices/ipoctal.h
+++ b/drivers/ipack/devices/ipoctal.h
@@ -1,9 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/**
- * ipoctal.h
- *
+/*
* driver for the IPOCTAL boards
-
+ *
* Copyright (C) 2009-2012 CERN (www.cern.ch)
* Author: Nicolas Serafini, EIC2 SA
* Author: Samuel Iglesias Gonsalvez <siglesias@igalia.com>
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 62543a4eccc0..4d5924e9f766 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -415,7 +415,7 @@ config GOLDFISH_PIC
for Goldfish based virtual platforms.
config QCOM_PDC
- bool "QCOM PDC"
+ tristate "QCOM PDC"
depends on ARCH_QCOM
select IRQ_DOMAIN_HIERARCHY
help
diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c
index 0b85d9a3fbff..552aa04ff063 100644
--- a/drivers/irqchip/exynos-combiner.c
+++ b/drivers/irqchip/exynos-combiner.c
@@ -66,8 +66,9 @@ static void combiner_handle_cascade_irq(struct irq_desc *desc)
{
struct combiner_chip_data *chip_data = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
- unsigned int cascade_irq, combiner_irq;
+ unsigned int combiner_irq;
unsigned long status;
+ int ret;
chained_irq_enter(chip, desc);
@@ -80,12 +81,9 @@ static void combiner_handle_cascade_irq(struct irq_desc *desc)
goto out;
combiner_irq = chip_data->hwirq_offset + __ffs(status);
- cascade_irq = irq_find_mapping(combiner_irq_domain, combiner_irq);
-
- if (unlikely(!cascade_irq))
+ ret = generic_handle_domain_irq(combiner_irq_domain, combiner_irq);
+ if (unlikely(ret))
handle_bad_irq(desc);
- else
- generic_handle_irq(cascade_irq);
out:
chained_irq_exit(chip, desc);
@@ -179,10 +177,8 @@ static void __init combiner_init(void __iomem *combiner_base,
nr_irq = max_nr * IRQ_IN_COMBINER;
combiner_data = kcalloc(max_nr, sizeof (*combiner_data), GFP_KERNEL);
- if (!combiner_data) {
- pr_warn("%s: could not allocate combiner data\n", __func__);
+ if (!combiner_data)
return;
- }
combiner_irq_domain = irq_domain_add_linear(np, nr_irq,
&combiner_irq_domain_ops, combiner_data);
diff --git a/drivers/irqchip/irq-al-fic.c b/drivers/irqchip/irq-al-fic.c
index 0b0a73739756..886de028a901 100644
--- a/drivers/irqchip/irq-al-fic.c
+++ b/drivers/irqchip/irq-al-fic.c
@@ -111,7 +111,6 @@ static void al_fic_irq_handler(struct irq_desc *desc)
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);
@@ -119,10 +118,8 @@ static void al_fic_irq_handler(struct irq_desc *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);
- }
+ for_each_set_bit(hwirq, &pending, NR_FIC_IRQS)
+ generic_handle_domain_irq(domain, hwirq);
chained_irq_exit(irqchip, desc);
}
diff --git a/drivers/irqchip/irq-apple-aic.c b/drivers/irqchip/irq-apple-aic.c
index c179e27062fd..b8c06bd8659e 100644
--- a/drivers/irqchip/irq-apple-aic.c
+++ b/drivers/irqchip/irq-apple-aic.c
@@ -50,6 +50,7 @@
#include <linux/cpuhotplug.h>
#include <linux/io.h>
#include <linux/irqchip.h>
+#include <linux/irqchip/arm-vgic-info.h>
#include <linux/irqdomain.h>
#include <linux/limits.h>
#include <linux/of_address.h>
@@ -787,6 +788,12 @@ static int aic_init_cpu(unsigned int cpu)
return 0;
}
+static struct gic_kvm_info vgic_info __initdata = {
+ .type = GIC_V3,
+ .no_maint_irq_mask = true,
+ .no_hw_deactivation = true,
+};
+
static int __init aic_of_ic_init(struct device_node *node, struct device_node *parent)
{
int i;
@@ -843,6 +850,8 @@ static int __init aic_of_ic_init(struct device_node *node, struct device_node *p
"irqchip/apple-aic/ipi:starting",
aic_init_cpu, NULL);
+ vgic_set_kvm_info(&vgic_info);
+
pr_info("Initialized with %d IRQs, %d FIQs, %d vIPIs\n",
irqc->nr_hw, AIC_NR_FIQ, AIC_NR_SWIPI);
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index 32938dfc0e46..7557ab551295 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -582,20 +582,19 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
for (msinr = PCI_MSI_DOORBELL_START;
msinr < PCI_MSI_DOORBELL_END; msinr++) {
- int irq;
+ unsigned int irq;
if (!(msimask & BIT(msinr)))
continue;
- if (is_chained) {
- irq = irq_find_mapping(armada_370_xp_msi_inner_domain,
- msinr - PCI_MSI_DOORBELL_START);
- generic_handle_irq(irq);
- } else {
- irq = msinr - PCI_MSI_DOORBELL_START;
+ irq = msinr - PCI_MSI_DOORBELL_START;
+
+ if (is_chained)
+ generic_handle_domain_irq(armada_370_xp_msi_inner_domain,
+ irq);
+ else
handle_domain_irq(armada_370_xp_msi_inner_domain,
irq, regs);
- }
}
}
#else
@@ -606,7 +605,6 @@ static void armada_370_xp_mpic_handle_cascade_irq(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned long irqmap, irqn, irqsrc, cpuid;
- unsigned int cascade_irq;
chained_irq_enter(chip, desc);
@@ -628,8 +626,7 @@ static void armada_370_xp_mpic_handle_cascade_irq(struct irq_desc *desc)
continue;
}
- cascade_irq = irq_find_mapping(armada_370_xp_mpic_domain, irqn);
- generic_handle_irq(cascade_irq);
+ generic_handle_domain_irq(armada_370_xp_mpic_domain, irqn);
}
chained_irq_exit(chip, desc);
diff --git a/drivers/irqchip/irq-aspeed-i2c-ic.c b/drivers/irqchip/irq-aspeed-i2c-ic.c
index 8d591c179f81..a47db16ff960 100644
--- a/drivers/irqchip/irq-aspeed-i2c-ic.c
+++ b/drivers/irqchip/irq-aspeed-i2c-ic.c
@@ -34,14 +34,12 @@ static void aspeed_i2c_ic_irq_handler(struct irq_desc *desc)
struct aspeed_i2c_ic *i2c_ic = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned long bit, status;
- unsigned int bus_irq;
chained_irq_enter(chip, desc);
status = readl(i2c_ic->base);
- for_each_set_bit(bit, &status, ASPEED_I2C_IC_NUM_BUS) {
- bus_irq = irq_find_mapping(i2c_ic->irq_domain, bit);
- generic_handle_irq(bus_irq);
- }
+ for_each_set_bit(bit, &status, ASPEED_I2C_IC_NUM_BUS)
+ generic_handle_domain_irq(i2c_ic->irq_domain, bit);
+
chained_irq_exit(chip, desc);
}
diff --git a/drivers/irqchip/irq-aspeed-scu-ic.c b/drivers/irqchip/irq-aspeed-scu-ic.c
index c90a3346b985..f3c6855a4cef 100644
--- a/drivers/irqchip/irq-aspeed-scu-ic.c
+++ b/drivers/irqchip/irq-aspeed-scu-ic.c
@@ -44,7 +44,6 @@ struct aspeed_scu_ic {
static void aspeed_scu_ic_irq_handler(struct irq_desc *desc)
{
- unsigned int irq;
unsigned int sts;
unsigned long bit;
unsigned long enabled;
@@ -74,9 +73,8 @@ static void aspeed_scu_ic_irq_handler(struct irq_desc *desc)
max = scu_ic->num_irqs + bit;
for_each_set_bit_from(bit, &status, max) {
- irq = irq_find_mapping(scu_ic->irq_domain,
- bit - scu_ic->irq_shift);
- generic_handle_irq(irq);
+ generic_handle_domain_irq(scu_ic->irq_domain,
+ bit - scu_ic->irq_shift);
regmap_update_bits(scu_ic->scu, scu_ic->reg, mask,
BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT));
diff --git a/drivers/irqchip/irq-ath79-misc.c b/drivers/irqchip/irq-ath79-misc.c
index 3d641bb6f3f1..92f001a5ff8d 100644
--- a/drivers/irqchip/irq-ath79-misc.c
+++ b/drivers/irqchip/irq-ath79-misc.c
@@ -50,7 +50,7 @@ static void ath79_misc_irq_handler(struct irq_desc *desc)
while (pending) {
int bit = __ffs(pending);
- generic_handle_irq(irq_linear_revmap(domain, bit));
+ generic_handle_domain_irq(domain, bit);
pending &= ~BIT(bit);
}
diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
index a1e004af23e7..adc1556ed332 100644
--- a/drivers/irqchip/irq-bcm2835.c
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -254,7 +254,7 @@ static void bcm2836_chained_handle_irq(struct irq_desc *desc)
u32 hwirq;
while ((hwirq = get_next_armctrl_hwirq()) != ~0)
- generic_handle_irq(irq_linear_revmap(intc.domain, hwirq));
+ generic_handle_domain_irq(intc.domain, hwirq);
}
IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic",
diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c
index 25c9a9c06e41..501facdb4570 100644
--- a/drivers/irqchip/irq-bcm2836.c
+++ b/drivers/irqchip/irq-bcm2836.c
@@ -161,7 +161,7 @@ static void bcm2836_arm_irqchip_handle_ipi(struct irq_desc *desc)
mbox_val = readl_relaxed(intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu);
if (mbox_val) {
int hwirq = ffs(mbox_val) - 1;
- generic_handle_irq(irq_find_mapping(ipi_domain, hwirq));
+ generic_handle_domain_irq(ipi_domain, hwirq);
}
chained_irq_exit(chip, desc);
diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c
index 9dc9bf8cdcc4..a035c385ca7a 100644
--- a/drivers/irqchip/irq-bcm7038-l1.c
+++ b/drivers/irqchip/irq-bcm7038-l1.c
@@ -145,10 +145,8 @@ static void bcm7038_l1_irq_handle(struct irq_desc *desc)
~cpu->mask_cache[idx];
raw_spin_unlock_irqrestore(&intc->lock, flags);
- for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
- generic_handle_irq(irq_find_mapping(intc->domain,
- base + hwirq));
- }
+ for_each_set_bit(hwirq, &pending, IRQS_PER_WORD)
+ generic_handle_domain_irq(intc->domain, base + hwirq);
}
chained_irq_exit(chip, desc);
diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c
index ad59656ccc28..f23d7651ea84 100644
--- a/drivers/irqchip/irq-bcm7120-l2.c
+++ b/drivers/irqchip/irq-bcm7120-l2.c
@@ -74,10 +74,8 @@ static void bcm7120_l2_intc_irq_handle(struct irq_desc *desc)
data->irq_map_mask[idx];
irq_gc_unlock(gc);
- for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
- generic_handle_irq(irq_find_mapping(b->domain,
- base + hwirq));
- }
+ for_each_set_bit(hwirq, &pending, IRQS_PER_WORD)
+ generic_handle_domain_irq(b->domain, base + hwirq);
}
chained_irq_exit(chip, desc);
diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c
index cdd6a42d4efa..8e0911561f2d 100644
--- a/drivers/irqchip/irq-brcmstb-l2.c
+++ b/drivers/irqchip/irq-brcmstb-l2.c
@@ -110,7 +110,7 @@ static void brcmstb_l2_intc_irq_handle(struct irq_desc *desc)
do {
irq = ffs(status) - 1;
status &= ~(1 << irq);
- generic_handle_irq(irq_linear_revmap(b->domain, irq));
+ generic_handle_domain_irq(b->domain, irq);
} while (status);
out:
chained_irq_exit(chip, desc);
diff --git a/drivers/irqchip/irq-dw-apb-ictl.c b/drivers/irqchip/irq-dw-apb-ictl.c
index 54b09d6c407c..a67266e44491 100644
--- a/drivers/irqchip/irq-dw-apb-ictl.c
+++ b/drivers/irqchip/irq-dw-apb-ictl.c
@@ -62,9 +62,8 @@ static void dw_apb_ictl_handle_irq_cascaded(struct irq_desc *desc)
while (stat) {
u32 hwirq = ffs(stat) - 1;
- u32 virq = irq_find_mapping(d, gc->irq_base + hwirq);
+ generic_handle_domain_irq(d, gc->irq_base + hwirq);
- generic_handle_irq(virq);
stat &= ~BIT(hwirq);
}
}
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index f47b41dfd023..a610821c8ff2 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -12,19 +12,6 @@
static DEFINE_RAW_SPINLOCK(irq_controller_lock);
-static const struct gic_kvm_info *gic_kvm_info;
-
-const struct gic_kvm_info *gic_get_kvm_info(void)
-{
- return gic_kvm_info;
-}
-
-void gic_set_kvm_info(const struct gic_kvm_info *info)
-{
- BUG_ON(gic_kvm_info != NULL);
- gic_kvm_info = info;
-}
-
void gic_enable_of_quirks(const struct device_node *np,
const struct gic_quirk *quirks, void *data)
{
diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h
index ccba8b0fe0f5..27e3d4ed4f32 100644
--- a/drivers/irqchip/irq-gic-common.h
+++ b/drivers/irqchip/irq-gic-common.h
@@ -28,6 +28,4 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
void gic_enable_of_quirks(const struct device_node *np,
const struct gic_quirk *quirks, void *data);
-void gic_set_kvm_info(const struct gic_kvm_info *info);
-
#endif /* _IRQ_GIC_COMMON_H */
diff --git a/drivers/irqchip/irq-gic-pm.c b/drivers/irqchip/irq-gic-pm.c
index 1337ceceb59b..b60e1853593f 100644
--- a/drivers/irqchip/irq-gic-pm.c
+++ b/drivers/irqchip/irq-gic-pm.c
@@ -30,10 +30,8 @@ static int gic_runtime_resume(struct device *dev)
int ret;
ret = clk_bulk_prepare_enable(data->num_clocks, chip_pm->clks);
- if (ret) {
- dev_err(dev, "clk_enable failed: %d\n", ret);
+ if (ret)
return ret;
- }
/*
* On the very first resume, the pointer to chip_pm->chip_data
diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index 4116b48e60af..be9ea6fd6f8b 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -323,10 +323,8 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
struct v2m_data *v2m;
v2m = kzalloc(sizeof(struct v2m_data), GFP_KERNEL);
- if (!v2m) {
- pr_err("Failed to allocate struct v2m_data.\n");
+ if (!v2m)
return -ENOMEM;
- }
INIT_LIST_HEAD(&v2m->entry);
v2m->fwnode = fwnode;
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 2e6923c2c8a8..ba39668c3e08 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -4895,10 +4895,8 @@ static int its_init_vpe_domain(void)
entries = roundup_pow_of_two(nr_cpu_ids);
vpe_proxy.vpes = kcalloc(entries, sizeof(*vpe_proxy.vpes),
GFP_KERNEL);
- if (!vpe_proxy.vpes) {
- pr_err("ITS: Can't allocate GICv4 proxy device array\n");
+ if (!vpe_proxy.vpes)
return -ENOMEM;
- }
/* Use the last possible DevID */
devid = GENMASK(device_ids(its) - 1, 0);
@@ -5314,10 +5312,8 @@ static void __init acpi_table_parse_srat_its(void)
its_srat_maps = kmalloc_array(count, sizeof(struct its_srat_map),
GFP_KERNEL);
- if (!its_srat_maps) {
- pr_warn("SRAT: Failed to allocate memory for its_srat_maps!\n");
+ if (!its_srat_maps)
return;
- }
acpi_table_parse_entries(ACPI_SIG_SRAT,
sizeof(struct acpi_table_srat),
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 66d623f91678..e0f4debe64e1 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -103,7 +103,7 @@ EXPORT_SYMBOL(gic_nonsecure_priorities);
/* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */
static refcount_t *ppi_nmi_refs;
-static struct gic_kvm_info gic_v3_kvm_info;
+static struct gic_kvm_info gic_v3_kvm_info __initdata;
static DEFINE_PER_CPU(bool, has_rss);
#define MPIDR_RS(mpidr) (((mpidr) & 0xF0UL) >> 4)
@@ -1886,7 +1886,7 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)
gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis;
gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid;
- gic_set_kvm_info(&gic_v3_kvm_info);
+ vgic_set_kvm_info(&gic_v3_kvm_info);
}
static int __init gic_of_init(struct device_node *node, struct device_node *parent)
@@ -2202,7 +2202,7 @@ static void __init gic_acpi_setup_kvm_info(void)
gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis;
gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid;
- gic_set_kvm_info(&gic_v3_kvm_info);
+ vgic_set_kvm_info(&gic_v3_kvm_info);
}
static int __init
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index b1d9c22caf2e..d329ec3d64d8 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -119,7 +119,7 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly;
-static struct gic_kvm_info gic_v2_kvm_info;
+static struct gic_kvm_info gic_v2_kvm_info __initdata;
static DEFINE_PER_CPU(u32, sgi_intid);
@@ -375,8 +375,9 @@ static void gic_handle_cascade_irq(struct irq_desc *desc)
{
struct gic_chip_data *chip_data = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
- unsigned int cascade_irq, gic_irq;
+ unsigned int gic_irq;
unsigned long status;
+ int ret;
chained_irq_enter(chip, desc);
@@ -386,14 +387,10 @@ static void gic_handle_cascade_irq(struct irq_desc *desc)
if (gic_irq == GICC_INT_SPURIOUS)
goto out;
- cascade_irq = irq_find_mapping(chip_data->domain, gic_irq);
- if (unlikely(gic_irq < 32 || gic_irq > 1020)) {
+ isb();
+ ret = generic_handle_domain_irq(chip_data->domain, gic_irq);
+ if (unlikely(ret))
handle_bad_irq(desc);
- } else {
- isb();
- generic_handle_irq(cascade_irq);
- }
-
out:
chained_irq_exit(chip, desc);
}
@@ -1451,7 +1448,7 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)
return;
if (static_branch_likely(&supports_deactivate_key))
- gic_set_kvm_info(&gic_v2_kvm_info);
+ vgic_set_kvm_info(&gic_v2_kvm_info);
}
int __init
@@ -1618,7 +1615,7 @@ static void __init gic_acpi_setup_kvm_info(void)
gic_v2_kvm_info.maint_irq = irq;
- gic_set_kvm_info(&gic_v2_kvm_info);
+ vgic_set_kvm_info(&gic_v2_kvm_info);
}
static int __init gic_v2_acpi_init(union acpi_subtable_headers *header,
diff --git a/drivers/irqchip/irq-goldfish-pic.c b/drivers/irqchip/irq-goldfish-pic.c
index 4f021530e7f3..513f6edbbe95 100644
--- a/drivers/irqchip/irq-goldfish-pic.c
+++ b/drivers/irqchip/irq-goldfish-pic.c
@@ -34,15 +34,14 @@ static void goldfish_pic_cascade(struct irq_desc *desc)
{
struct goldfish_pic_data *gfpic = irq_desc_get_handler_data(desc);
struct irq_chip *host_chip = irq_desc_get_chip(desc);
- u32 pending, hwirq, virq;
+ u32 pending, hwirq;
chained_irq_enter(host_chip, desc);
pending = readl(gfpic->base + GFPIC_REG_IRQ_PENDING);
while (pending) {
hwirq = __fls(pending);
- virq = irq_linear_revmap(gfpic->irq_domain, hwirq);
- generic_handle_irq(virq);
+ generic_handle_domain_irq(gfpic->irq_domain, hwirq);
pending &= ~(1 << hwirq);
}
diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c
index b6f6aa7b2862..b70ce0d3c092 100644
--- a/drivers/irqchip/irq-i8259.c
+++ b/drivers/irqchip/irq-i8259.c
@@ -333,13 +333,11 @@ static void i8259_irq_dispatch(struct irq_desc *desc)
{
struct irq_domain *domain = irq_desc_get_handler_data(desc);
int hwirq = i8259_poll();
- unsigned int irq;
if (hwirq < 0)
return;
- irq = irq_linear_revmap(domain, hwirq);
- generic_handle_irq(irq);
+ generic_handle_domain_irq(domain, hwirq);
}
int __init i8259_of_init(struct device_node *node, struct device_node *parent)
diff --git a/drivers/irqchip/irq-idt3243x.c b/drivers/irqchip/irq-idt3243x.c
index f0996820077a..0732a0e9af62 100644
--- a/drivers/irqchip/irq-idt3243x.c
+++ b/drivers/irqchip/irq-idt3243x.c
@@ -28,7 +28,7 @@ static void idt_irq_dispatch(struct irq_desc *desc)
{
struct idt_pic_data *idtpic = irq_desc_get_handler_data(desc);
struct irq_chip *host_chip = irq_desc_get_chip(desc);
- u32 pending, hwirq, virq;
+ u32 pending, hwirq;
chained_irq_enter(host_chip, desc);
@@ -36,9 +36,7 @@ static void idt_irq_dispatch(struct irq_desc *desc)
pending &= ~idtpic->gc->mask_cache;
while (pending) {
hwirq = __fls(pending);
- virq = irq_linear_revmap(idtpic->irq_domain, hwirq);
- if (virq)
- generic_handle_irq(virq);
+ generic_handle_domain_irq(idtpic->irq_domain, hwirq);
pending &= ~(1 << hwirq);
}
diff --git a/drivers/irqchip/irq-imgpdc.c b/drivers/irqchip/irq-imgpdc.c
index 698d07f48fed..5831be454673 100644
--- a/drivers/irqchip/irq-imgpdc.c
+++ b/drivers/irqchip/irq-imgpdc.c
@@ -223,7 +223,7 @@ static void pdc_intc_perip_isr(struct irq_desc *desc)
{
unsigned int irq = irq_desc_get_irq(desc);
struct pdc_intc_priv *priv;
- unsigned int i, irq_no;
+ unsigned int i;
priv = (struct pdc_intc_priv *)irq_desc_get_handler_data(desc);
@@ -237,14 +237,13 @@ static void pdc_intc_perip_isr(struct irq_desc *desc)
found:
/* pass on the interrupt */
- irq_no = irq_linear_revmap(priv->domain, i);
- generic_handle_irq(irq_no);
+ generic_handle_domain_irq(priv->domain, i);
}
static void pdc_intc_syswake_isr(struct irq_desc *desc)
{
struct pdc_intc_priv *priv;
- unsigned int syswake, irq_no;
+ unsigned int syswake;
unsigned int status;
priv = (struct pdc_intc_priv *)irq_desc_get_handler_data(desc);
@@ -258,9 +257,7 @@ static void pdc_intc_syswake_isr(struct irq_desc *desc)
if (!(status & 1))
continue;
- irq_no = irq_linear_revmap(priv->domain,
- syswake_to_hwirq(syswake));
- generic_handle_irq(irq_no);
+ generic_handle_domain_irq(priv->domain, syswake_to_hwirq(syswake));
}
}
@@ -316,10 +313,8 @@ static int pdc_intc_probe(struct platform_device *pdev)
/* Allocate driver data */
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- dev_err(&pdev->dev, "cannot allocate device data\n");
+ if (!priv)
return -ENOMEM;
- }
raw_spin_lock_init(&priv->lock);
platform_set_drvdata(pdev, priv);
@@ -356,10 +351,8 @@ static int pdc_intc_probe(struct platform_device *pdev)
/* Get peripheral IRQ numbers */
priv->perip_irqs = devm_kcalloc(&pdev->dev, 4, priv->nr_perips,
GFP_KERNEL);
- if (!priv->perip_irqs) {
- dev_err(&pdev->dev, "cannot allocate perip IRQ list\n");
+ if (!priv->perip_irqs)
return -ENOMEM;
- }
for (i = 0; i < priv->nr_perips; ++i) {
irq = platform_get_irq(pdev, 1 + i);
if (irq < 0)
diff --git a/drivers/irqchip/irq-imx-gpcv2.c b/drivers/irqchip/irq-imx-gpcv2.c
index 7031ef44de4f..5b5a365dbd5e 100644
--- a/drivers/irqchip/irq-imx-gpcv2.c
+++ b/drivers/irqchip/irq-imx-gpcv2.c
@@ -228,10 +228,8 @@ static int __init imx_gpcv2_irqchip_init(struct device_node *node,
}
cd = kzalloc(sizeof(struct gpcv2_irqchip_data), GFP_KERNEL);
- if (!cd) {
- pr_err("%pOF: kzalloc failed!\n", node);
+ if (!cd)
return -ENOMEM;
- }
raw_spin_lock_init(&cd->rlock);
diff --git a/drivers/irqchip/irq-imx-intmux.c b/drivers/irqchip/irq-imx-intmux.c
index 7709f9712cb3..e86ff743e98c 100644
--- a/drivers/irqchip/irq-imx-intmux.c
+++ b/drivers/irqchip/irq-imx-intmux.c
@@ -182,18 +182,15 @@ static void imx_intmux_irq_handler(struct irq_desc *desc)
struct intmux_data *data = container_of(irqchip_data, struct intmux_data,
irqchip_data[idx]);
unsigned long irqstat;
- int pos, virq;
+ int pos;
chained_irq_enter(irq_desc_get_chip(desc), desc);
/* read the interrupt source pending status of this channel */
irqstat = readl_relaxed(data->regs + CHANIPR(idx));
- for_each_set_bit(pos, &irqstat, 32) {
- virq = irq_find_mapping(irqchip_data->domain, pos);
- if (virq)
- generic_handle_irq(virq);
- }
+ for_each_set_bit(pos, &irqstat, 32)
+ generic_handle_domain_irq(irqchip_data->domain, pos);
chained_irq_exit(irq_desc_get_chip(desc), desc);
}
diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
index 1edf7692a790..8d91a02593fc 100644
--- a/drivers/irqchip/irq-imx-irqsteer.c
+++ b/drivers/irqchip/irq-imx-irqsteer.c
@@ -122,7 +122,7 @@ static void imx_irqsteer_irq_handler(struct irq_desc *desc)
for (i = 0; i < 2; i++, hwirq += 32) {
int idx = imx_irqsteer_get_reg_index(data, hwirq);
unsigned long irqmap;
- int pos, virq;
+ int pos;
if (hwirq >= data->reg_num * 32)
break;
@@ -130,11 +130,8 @@ static void imx_irqsteer_irq_handler(struct irq_desc *desc)
irqmap = readl_relaxed(data->regs +
CHANSTATUS(idx, data->reg_num));
- for_each_set_bit(pos, &irqmap, 32) {
- virq = irq_find_mapping(data->domain, pos + hwirq);
- if (virq)
- generic_handle_irq(virq);
- }
+ for_each_set_bit(pos, &irqmap, 32)
+ generic_handle_domain_irq(data->domain, pos + hwirq);
}
chained_irq_exit(irq_desc_get_chip(desc), desc);
diff --git a/drivers/irqchip/irq-ingenic-tcu.c b/drivers/irqchip/irq-ingenic-tcu.c
index b938d1d04d96..34a7d261b710 100644
--- a/drivers/irqchip/irq-ingenic-tcu.c
+++ b/drivers/irqchip/irq-ingenic-tcu.c
@@ -38,7 +38,7 @@ static void ingenic_tcu_intc_cascade(struct irq_desc *desc)
irq_reg &= ~irq_mask;
for_each_set_bit(i, (unsigned long *)&irq_reg, 32)
- generic_handle_irq(irq_linear_revmap(domain, i));
+ generic_handle_domain_irq(domain, i);
chained_irq_exit(irq_chip, desc);
}
diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index ea36bb00be80..cee839ca627e 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -49,8 +49,7 @@ static irqreturn_t intc_cascade(int irq, void *data)
while (pending) {
int bit = __fls(pending);
- irq = irq_linear_revmap(domain, bit + (i * 32));
- generic_handle_irq(irq);
+ generic_handle_domain_irq(domain, bit + (i * 32));
pending &= ~BIT(bit);
}
}
diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c
index 8118ebe80b09..d47c8041e5bc 100644
--- a/drivers/irqchip/irq-keystone.c
+++ b/drivers/irqchip/irq-keystone.c
@@ -89,7 +89,7 @@ static irqreturn_t keystone_irq_handler(int irq, void *keystone_irq)
struct keystone_irq_device *kirq = keystone_irq;
unsigned long wa_lock_flags;
unsigned long pending;
- int src, virq;
+ int src, err;
dev_dbg(kirq->dev, "start irq %d\n", irq);
@@ -104,16 +104,14 @@ static irqreturn_t keystone_irq_handler(int irq, void *keystone_irq)
for (src = 0; src < KEYSTONE_N_IRQ; src++) {
if (BIT(src) & pending) {
- virq = irq_find_mapping(kirq->irqd, src);
- dev_dbg(kirq->dev, "dispatch bit %d, virq %d\n",
- src, virq);
- if (!virq)
- dev_warn(kirq->dev, "spurious irq detected hwirq %d, virq %d\n",
- src, virq);
raw_spin_lock_irqsave(&kirq->wa_lock, wa_lock_flags);
- generic_handle_irq(virq);
+ err = generic_handle_domain_irq(kirq->irqd, src);
raw_spin_unlock_irqrestore(&kirq->wa_lock,
wa_lock_flags);
+
+ if (err)
+ dev_warn_ratelimited(kirq->dev, "spurious irq detected hwirq %d\n",
+ src);
}
}
diff --git a/drivers/irqchip/irq-loongson-htpic.c b/drivers/irqchip/irq-loongson-htpic.c
index 1b801c4fb026..f4abdf156de7 100644
--- a/drivers/irqchip/irq-loongson-htpic.c
+++ b/drivers/irqchip/irq-loongson-htpic.c
@@ -48,7 +48,7 @@ static void htpic_irq_dispatch(struct irq_desc *desc)
break;
}
- generic_handle_irq(irq_linear_revmap(priv->domain, bit));
+ generic_handle_domain_irq(priv->domain, bit);
pending &= ~BIT(bit);
}
chained_irq_exit(chip, desc);
diff --git a/drivers/irqchip/irq-loongson-htvec.c b/drivers/irqchip/irq-loongson-htvec.c
index 6392aafb9a63..60a335d7e64e 100644
--- a/drivers/irqchip/irq-loongson-htvec.c
+++ b/drivers/irqchip/irq-loongson-htvec.c
@@ -47,8 +47,8 @@ static void htvec_irq_dispatch(struct irq_desc *desc)
while (pending) {
int bit = __ffs(pending);
- generic_handle_irq(irq_linear_revmap(priv->htvec_domain, bit +
- VEC_COUNT_PER_REG * i));
+ generic_handle_domain_irq(priv->htvec_domain,
+ bit + VEC_COUNT_PER_REG * i);
pending &= ~BIT(bit);
handled = true;
}
diff --git a/drivers/irqchip/irq-loongson-liointc.c b/drivers/irqchip/irq-loongson-liointc.c
index 8ccb30421806..649c58391618 100644
--- a/drivers/irqchip/irq-loongson-liointc.c
+++ b/drivers/irqchip/irq-loongson-liointc.c
@@ -73,7 +73,7 @@ static void liointc_chained_handle_irq(struct irq_desc *desc)
while (pending) {
int bit = __ffs(pending);
- generic_handle_irq(irq_find_mapping(gc->domain, bit));
+ generic_handle_domain_irq(gc->domain, bit);
pending &= ~BIT(bit);
}
diff --git a/drivers/irqchip/irq-lpc32xx.c b/drivers/irqchip/irq-lpc32xx.c
index 7d9b388afe64..5e6f6e25f2ae 100644
--- a/drivers/irqchip/irq-lpc32xx.c
+++ b/drivers/irqchip/irq-lpc32xx.c
@@ -141,7 +141,7 @@ static void lpc32xx_sic_handler(struct irq_desc *desc)
while (hwirq) {
irq = __ffs(hwirq);
hwirq &= ~BIT(irq);
- generic_handle_irq(irq_find_mapping(ic->domain, irq));
+ generic_handle_domain_irq(ic->domain, irq);
}
chained_irq_exit(chip, desc);
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
index 61dbfda08527..55322da51c56 100644
--- a/drivers/irqchip/irq-ls-scfg-msi.c
+++ b/drivers/irqchip/irq-ls-scfg-msi.c
@@ -194,7 +194,7 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc);
struct ls_scfg_msi *msi_data = msir->msi_data;
unsigned long val;
- int pos, size, virq, hwirq;
+ int pos, size, hwirq;
chained_irq_enter(irq_desc_get_chip(desc), desc);
@@ -206,9 +206,7 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
for_each_set_bit_from(pos, &val, size) {
hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) |
msir->srs;
- virq = irq_find_mapping(msi_data->parent, hwirq);
- if (virq)
- generic_handle_irq(virq);
+ generic_handle_domain_irq(msi_data->parent, hwirq);
}
chained_irq_exit(irq_desc_get_chip(desc), desc);
diff --git a/drivers/irqchip/irq-ls1x.c b/drivers/irqchip/irq-ls1x.c
index 353111a10413..77a3f7dfaaf0 100644
--- a/drivers/irqchip/irq-ls1x.c
+++ b/drivers/irqchip/irq-ls1x.c
@@ -50,7 +50,7 @@ static void ls1x_chained_handle_irq(struct irq_desc *desc)
while (pending) {
int bit = __ffs(pending);
- generic_handle_irq(irq_find_mapping(priv->domain, bit));
+ generic_handle_domain_irq(priv->domain, bit);
pending &= ~BIT(bit);
}
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 2cb45c6b8501..f565317a3da3 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -273,6 +273,12 @@ static int mbigen_of_create_domain(struct platform_device *pdev,
}
#ifdef CONFIG_ACPI
+static const struct acpi_device_id mbigen_acpi_match[] = {
+ { "HISI0152", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, mbigen_acpi_match);
+
static int mbigen_acpi_create_domain(struct platform_device *pdev,
struct mbigen_device *mgn_chip)
{
@@ -369,12 +375,6 @@ static const struct of_device_id mbigen_of_match[] = {
};
MODULE_DEVICE_TABLE(of, mbigen_of_match);
-static const struct acpi_device_id mbigen_acpi_match[] = {
- { "HISI0152", 0 },
- {}
-};
-MODULE_DEVICE_TABLE(acpi, mbigen_acpi_match);
-
static struct platform_driver mbigen_platform_driver = {
.driver = {
.name = "Hisilicon MBIGEN-V2",
diff --git a/drivers/irqchip/irq-mips-cpu.c b/drivers/irqchip/irq-mips-cpu.c
index 0bbb0b2d0dd5..0c7ae71a0af0 100644
--- a/drivers/irqchip/irq-mips-cpu.c
+++ b/drivers/irqchip/irq-mips-cpu.c
@@ -127,7 +127,6 @@ static struct irq_chip mips_mt_cpu_irq_controller = {
asmlinkage void __weak plat_irq_dispatch(void)
{
unsigned long pending = read_c0_cause() & read_c0_status() & ST0_IM;
- unsigned int virq;
int irq;
if (!pending) {
@@ -137,12 +136,15 @@ asmlinkage void __weak plat_irq_dispatch(void)
pending >>= CAUSEB_IP;
while (pending) {
+ struct irq_domain *d;
+
irq = fls(pending) - 1;
if (IS_ENABLED(CONFIG_GENERIC_IRQ_IPI) && irq < 2)
- virq = irq_linear_revmap(ipi_domain, irq);
+ d = ipi_domain;
else
- virq = irq_linear_revmap(irq_domain, irq);
- do_IRQ(virq);
+ d = irq_domain;
+
+ do_domain_IRQ(d, irq);
pending &= ~BIT(irq);
}
}
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index 215885962bb0..54c7092cc61d 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
#include <linux/of_address.h>
#include <linux/percpu.h>
#include <linux/sched.h>
@@ -147,7 +148,7 @@ int gic_get_c0_fdc_int(void)
static void gic_handle_shared_int(bool chained)
{
- unsigned int intr, virq;
+ unsigned int intr;
unsigned long *pcpu_mask;
DECLARE_BITMAP(pending, GIC_MAX_INTRS);
@@ -164,12 +165,12 @@ static void gic_handle_shared_int(bool chained)
bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs);
for_each_set_bit(intr, pending, gic_shared_intrs) {
- virq = irq_linear_revmap(gic_irq_domain,
- GIC_SHARED_TO_HWIRQ(intr));
if (chained)
- generic_handle_irq(virq);
+ generic_handle_domain_irq(gic_irq_domain,
+ GIC_SHARED_TO_HWIRQ(intr));
else
- do_IRQ(virq);
+ do_domain_IRQ(gic_irq_domain,
+ GIC_SHARED_TO_HWIRQ(intr));
}
}
@@ -307,7 +308,7 @@ static struct irq_chip gic_edge_irq_controller = {
static void gic_handle_local_int(bool chained)
{
unsigned long pending, masked;
- unsigned int intr, virq;
+ unsigned int intr;
pending = read_gic_vl_pend();
masked = read_gic_vl_mask();
@@ -315,12 +316,12 @@ static void gic_handle_local_int(bool chained)
bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS);
for_each_set_bit(intr, &pending, GIC_NUM_LOCAL_INTRS) {
- virq = irq_linear_revmap(gic_irq_domain,
- GIC_LOCAL_TO_HWIRQ(intr));
if (chained)
- generic_handle_irq(virq);
+ generic_handle_domain_irq(gic_irq_domain,
+ GIC_LOCAL_TO_HWIRQ(intr));
else
- do_IRQ(virq);
+ do_domain_IRQ(gic_irq_domain,
+ GIC_LOCAL_TO_HWIRQ(intr));
}
}
diff --git a/drivers/irqchip/irq-mscc-ocelot.c b/drivers/irqchip/irq-mscc-ocelot.c
index 8235d98650c1..4d0c3532dbe7 100644
--- a/drivers/irqchip/irq-mscc-ocelot.c
+++ b/drivers/irqchip/irq-mscc-ocelot.c
@@ -107,7 +107,7 @@ static void ocelot_irq_handler(struct irq_desc *desc)
while (reg) {
u32 hwirq = __fls(reg);
- generic_handle_irq(irq_find_mapping(d, hwirq));
+ generic_handle_domain_irq(d, hwirq);
reg &= ~(BIT(hwirq));
}
diff --git a/drivers/irqchip/irq-mvebu-pic.c b/drivers/irqchip/irq-mvebu-pic.c
index eec63951129a..dc1cee4b0fe1 100644
--- a/drivers/irqchip/irq-mvebu-pic.c
+++ b/drivers/irqchip/irq-mvebu-pic.c
@@ -91,15 +91,12 @@ static void mvebu_pic_handle_cascade_irq(struct irq_desc *desc)
struct mvebu_pic *pic = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned long irqmap, irqn;
- unsigned int cascade_irq;
irqmap = readl_relaxed(pic->base + PIC_CAUSE);
chained_irq_enter(chip, desc);
- for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) {
- cascade_irq = irq_find_mapping(pic->domain, irqn);
- generic_handle_irq(cascade_irq);
- }
+ for_each_set_bit(irqn, &irqmap, BITS_PER_LONG)
+ generic_handle_domain_irq(pic->domain, irqn);
chained_irq_exit(chip, desc);
}
diff --git a/drivers/irqchip/irq-mvebu-sei.c b/drivers/irqchip/irq-mvebu-sei.c
index 3a7b7a7f20ca..4ecef6d83777 100644
--- a/drivers/irqchip/irq-mvebu-sei.c
+++ b/drivers/irqchip/irq-mvebu-sei.c
@@ -337,17 +337,12 @@ static void mvebu_sei_handle_cascade_irq(struct irq_desc *desc)
irqmap = readl_relaxed(sei->base + GICP_SECR(idx));
for_each_set_bit(bit, &irqmap, SEI_IRQ_COUNT_PER_REG) {
unsigned long hwirq;
- unsigned int virq;
+ int err;
hwirq = idx * SEI_IRQ_COUNT_PER_REG + bit;
- virq = irq_find_mapping(sei->sei_domain, hwirq);
- if (likely(virq)) {
- generic_handle_irq(virq);
- continue;
- }
-
- dev_warn(sei->dev,
- "Spurious IRQ detected (hwirq %lu)\n", hwirq);
+ err = generic_handle_domain_irq(sei->sei_domain, hwirq);
+ if (unlikely(err))
+ dev_warn(sei->dev, "Spurious IRQ detected (hwirq %lu)\n", hwirq);
}
}
diff --git a/drivers/irqchip/irq-nvic.c b/drivers/irqchip/irq-nvic.c
index f747e2209ea9..b31c4cff4d3a 100644
--- a/drivers/irqchip/irq-nvic.c
+++ b/drivers/irqchip/irq-nvic.c
@@ -40,9 +40,7 @@ static struct irq_domain *nvic_irq_domain;
asmlinkage void __exception_irq_entry
nvic_handle_irq(irq_hw_number_t hwirq, struct pt_regs *regs)
{
- unsigned int irq = irq_linear_revmap(nvic_irq_domain, hwirq);
-
- handle_IRQ(irq, regs);
+ handle_domain_irq(nvic_irq_domain, hwirq, regs);
}
static int nvic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c
index c4b5ffb61954..b6868f7b805a 100644
--- a/drivers/irqchip/irq-orion.c
+++ b/drivers/irqchip/irq-orion.c
@@ -117,7 +117,7 @@ static void orion_bridge_irq_handler(struct irq_desc *desc)
while (stat) {
u32 hwirq = __fls(stat);
- generic_handle_irq(irq_find_mapping(d, gc->irq_base + hwirq));
+ generic_handle_domain_irq(d, gc->irq_base + hwirq);
stat &= ~(1 << hwirq);
}
}
diff --git a/drivers/irqchip/irq-partition-percpu.c b/drivers/irqchip/irq-partition-percpu.c
index 0c4c8ed7064e..89c23a1566dc 100644
--- a/drivers/irqchip/irq-partition-percpu.c
+++ b/drivers/irqchip/irq-partition-percpu.c
@@ -124,13 +124,10 @@ static void partition_handle_irq(struct irq_desc *desc)
break;
}
- if (unlikely(hwirq == part->nr_parts)) {
+ if (unlikely(hwirq == part->nr_parts))
handle_bad_irq(desc);
- } else {
- unsigned int irq;
- irq = irq_find_mapping(part->domain, hwirq);
- generic_handle_irq(irq);
- }
+ else
+ generic_handle_domain_irq(part->domain, hwirq);
chained_irq_exit(chip, desc);
}
diff --git a/drivers/irqchip/irq-pic32-evic.c b/drivers/irqchip/irq-pic32-evic.c
index 34c4b4ffacd1..1d9bb28d13e5 100644
--- a/drivers/irqchip/irq-pic32-evic.c
+++ b/drivers/irqchip/irq-pic32-evic.c
@@ -42,11 +42,10 @@ static void __iomem *evic_base;
asmlinkage void __weak plat_irq_dispatch(void)
{
- unsigned int irq, hwirq;
+ unsigned int hwirq;
hwirq = readl(evic_base + REG_INTSTAT) & 0xFF;
- irq = irq_linear_revmap(evic_irq_domain, hwirq);
- do_IRQ(irq);
+ do_domain_IRQ(evic_irq_domain, hwirq);
}
static struct evic_chip_data *irqd_to_priv(struct irq_data *data)
diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c
index 92fb5780dc10..fa8d89b02ec0 100644
--- a/drivers/irqchip/irq-pruss-intc.c
+++ b/drivers/irqchip/irq-pruss-intc.c
@@ -488,8 +488,7 @@ static void pruss_intc_irq_handler(struct irq_desc *desc)
while (true) {
u32 hipir;
- unsigned int virq;
- int hwirq;
+ int hwirq, err;
/* get highest priority pending PRUSS system event */
hipir = pruss_intc_read_reg(intc, PRU_INTC_HIPIR(host_irq));
@@ -497,16 +496,14 @@ static void pruss_intc_irq_handler(struct irq_desc *desc)
break;
hwirq = hipir & GENMASK(9, 0);
- virq = irq_find_mapping(intc->domain, hwirq);
+ err = generic_handle_domain_irq(intc->domain, hwirq);
/*
* NOTE: manually ACK any system events that do not have a
* handler mapped yet
*/
- if (WARN_ON_ONCE(!virq))
+ if (WARN_ON_ONCE(err))
pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq);
- else
- generic_handle_irq(virq);
}
chained_irq_exit(chip, desc);
diff --git a/drivers/irqchip/irq-realtek-rtl.c b/drivers/irqchip/irq-realtek-rtl.c
index b57c67dfab5b..fd9f275592d2 100644
--- a/drivers/irqchip/irq-realtek-rtl.c
+++ b/drivers/irqchip/irq-realtek-rtl.c
@@ -85,7 +85,7 @@ static void realtek_irq_dispatch(struct irq_desc *desc)
goto out;
}
domain = irq_desc_get_handler_data(desc);
- generic_handle_irq(irq_find_mapping(domain, __ffs(pending)));
+ generic_handle_domain_irq(domain, __ffs(pending));
out:
chained_irq_exit(chip, desc);
diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c
index 11abc09ef76c..07a6d8b42b63 100644
--- a/drivers/irqchip/irq-renesas-irqc.c
+++ b/drivers/irqchip/irq-renesas-irqc.c
@@ -115,7 +115,7 @@ static irqreturn_t irqc_irq_handler(int irq, void *dev_id)
if (ioread32(p->iomem + DETECT_STATUS) & bit) {
iowrite32(bit, p->iomem + DETECT_STATUS);
irqc_dbg(i, "demux2");
- generic_handle_irq(irq_find_mapping(p->irq_domain, i->hw_irq));
+ generic_handle_domain_irq(p->irq_domain, i->hw_irq);
return IRQ_HANDLED;
}
return IRQ_NONE;
diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
index 97d4d04b0a80..cf74cfa82045 100644
--- a/drivers/irqchip/irq-sifive-plic.c
+++ b/drivers/irqchip/irq-sifive-plic.c
@@ -233,13 +233,11 @@ static void plic_handle_irq(struct irq_desc *desc)
chained_irq_enter(chip, desc);
while ((hwirq = readl(claim))) {
- int irq = irq_find_mapping(handler->priv->irqdomain, hwirq);
-
- if (unlikely(irq <= 0))
+ int err = generic_handle_domain_irq(handler->priv->irqdomain,
+ hwirq);
+ if (unlikely(err))
pr_warn_ratelimited("can't find mapping for hwirq %lu\n",
hwirq);
- else
- generic_handle_irq(irq);
}
chained_irq_exit(chip, desc);
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
index 4704f2ee5797..33c76710f845 100644
--- a/drivers/irqchip/irq-stm32-exti.c
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -257,7 +257,7 @@ static void stm32_irq_handler(struct irq_desc *desc)
{
struct irq_domain *domain = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
- unsigned int virq, nbanks = domain->gc->num_chips;
+ unsigned int nbanks = domain->gc->num_chips;
struct irq_chip_generic *gc;
unsigned long pending;
int n, i, irq_base = 0;
@@ -268,11 +268,9 @@ static void stm32_irq_handler(struct irq_desc *desc)
gc = irq_get_domain_generic_chip(domain, irq_base);
while ((pending = stm32_exti_pending(gc))) {
- for_each_set_bit(n, &pending, IRQS_PER_BANK) {
- virq = irq_find_mapping(domain, irq_base + n);
- generic_handle_irq(virq);
- }
- }
+ for_each_set_bit(n, &pending, IRQS_PER_BANK)
+ generic_handle_domain_irq(domain, irq_base + n);
+ }
}
chained_irq_exit(chip, desc);
diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
index 9ea94456b178..8a315d6a3399 100644
--- a/drivers/irqchip/irq-sun4i.c
+++ b/drivers/irqchip/irq-sun4i.c
@@ -147,10 +147,8 @@ static int __init sun4i_ic_of_init(struct device_node *node,
struct device_node *parent)
{
irq_ic_data = kzalloc(sizeof(struct sun4i_irq_chip_data), GFP_KERNEL);
- if (!irq_ic_data) {
- pr_err("kzalloc failed!\n");
+ if (!irq_ic_data)
return -ENOMEM;
- }
irq_ic_data->enable_reg_offset = SUN4I_IRQ_ENABLE_REG_OFFSET;
irq_ic_data->mask_reg_offset = SUN4I_IRQ_MASK_REG_OFFSET;
@@ -164,10 +162,8 @@ static int __init suniv_ic_of_init(struct device_node *node,
struct device_node *parent)
{
irq_ic_data = kzalloc(sizeof(struct sun4i_irq_chip_data), GFP_KERNEL);
- if (!irq_ic_data) {
- pr_err("kzalloc failed!\n");
+ if (!irq_ic_data)
return -ENOMEM;
- }
irq_ic_data->enable_reg_offset = SUNIV_IRQ_ENABLE_REG_OFFSET;
irq_ic_data->mask_reg_offset = SUNIV_IRQ_MASK_REG_OFFSET;
diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c
index 9f2bd0c5d289..21d49791f855 100644
--- a/drivers/irqchip/irq-sunxi-nmi.c
+++ b/drivers/irqchip/irq-sunxi-nmi.c
@@ -88,10 +88,9 @@ static void sunxi_sc_nmi_handle_irq(struct irq_desc *desc)
{
struct irq_domain *domain = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
- unsigned int virq = irq_find_mapping(domain, 0);
chained_irq_enter(chip, desc);
- generic_handle_irq(virq);
+ generic_handle_domain_irq(domain, 0);
chained_irq_exit(chip, desc);
}
diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c
index 9a63b02b8176..8a0e69298e83 100644
--- a/drivers/irqchip/irq-tb10x.c
+++ b/drivers/irqchip/irq-tb10x.c
@@ -91,7 +91,7 @@ static void tb10x_irq_cascade(struct irq_desc *desc)
struct irq_domain *domain = irq_desc_get_handler_data(desc);
unsigned int irq = irq_desc_get_irq(desc);
- generic_handle_irq(irq_find_mapping(domain, irq));
+ generic_handle_domain_irq(domain, irq);
}
static int __init of_tb10x_init_irq(struct device_node *ictl,
diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c
index ca1f593f4d13..97f454ec376b 100644
--- a/drivers/irqchip/irq-ti-sci-inta.c
+++ b/drivers/irqchip/irq-ti-sci-inta.c
@@ -147,7 +147,7 @@ static void ti_sci_inta_irq_handler(struct irq_desc *desc)
struct ti_sci_inta_vint_desc *vint_desc;
struct ti_sci_inta_irq_domain *inta;
struct irq_domain *domain;
- unsigned int virq, bit;
+ unsigned int bit;
unsigned long val;
vint_desc = irq_desc_get_handler_data(desc);
@@ -159,11 +159,8 @@ static void ti_sci_inta_irq_handler(struct irq_desc *desc)
val = readq_relaxed(inta->base + vint_desc->vint_id * 0x1000 +
VINT_STATUS_MASKED_OFFSET);
- for_each_set_bit(bit, &val, MAX_EVENTS_PER_VINT) {
- virq = irq_find_mapping(domain, vint_desc->events[bit].hwirq);
- if (virq)
- generic_handle_irq(virq);
- }
+ for_each_set_bit(bit, &val, MAX_EVENTS_PER_VINT)
+ generic_handle_domain_irq(domain, vint_desc->events[bit].hwirq);
chained_irq_exit(irq_desc_get_chip(desc), desc);
}
diff --git a/drivers/irqchip/irq-ts4800.c b/drivers/irqchip/irq-ts4800.c
index 2325fb3c482b..34337a61b1ef 100644
--- a/drivers/irqchip/irq-ts4800.c
+++ b/drivers/irqchip/irq-ts4800.c
@@ -79,10 +79,9 @@ static void ts4800_ic_chained_handle_irq(struct irq_desc *desc)
do {
unsigned int bit = __ffs(status);
- int irq = irq_find_mapping(data->domain, bit);
+ generic_handle_domain_irq(data->domain, bit);
status &= ~(1 << bit);
- generic_handle_irq(irq);
} while (status);
out:
diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c
index f1386733d3bc..75be350cf82f 100644
--- a/drivers/irqchip/irq-versatile-fpga.c
+++ b/drivers/irqchip/irq-versatile-fpga.c
@@ -85,7 +85,7 @@ static void fpga_irq_handle(struct irq_desc *desc)
unsigned int irq = ffs(status) - 1;
status &= ~(1 << irq);
- generic_handle_irq(irq_find_mapping(f->domain, irq));
+ generic_handle_domain_irq(f->domain, irq);
} while (status);
out:
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 62f3d29f9042..1e1f2d115257 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -225,7 +225,7 @@ static void vic_handle_irq_cascaded(struct irq_desc *desc)
while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
hwirq = ffs(stat) - 1;
- generic_handle_irq(irq_find_mapping(vic->domain, hwirq));
+ generic_handle_domain_irq(vic->domain, hwirq);
}
chained_irq_exit(host_chip, desc);
diff --git a/drivers/irqchip/irq-xilinx-intc.c b/drivers/irqchip/irq-xilinx-intc.c
index 8cd1bfc73057..356a59755d63 100644
--- a/drivers/irqchip/irq-xilinx-intc.c
+++ b/drivers/irqchip/irq-xilinx-intc.c
@@ -110,20 +110,6 @@ static struct irq_chip intc_dev = {
.irq_mask_ack = intc_mask_ack,
};
-static unsigned int xintc_get_irq_local(struct xintc_irq_chip *irqc)
-{
- unsigned int irq = 0;
- u32 hwirq;
-
- hwirq = xintc_read(irqc, IVR);
- if (hwirq != -1U)
- irq = irq_find_mapping(irqc->root_domain, hwirq);
-
- pr_debug("irq-xilinx: hwirq=%d, irq=%d\n", hwirq, irq);
-
- return irq;
-}
-
unsigned int xintc_get_irq(void)
{
unsigned int irq = -1;
@@ -164,15 +150,16 @@ static void xil_intc_irq_handler(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct xintc_irq_chip *irqc;
- u32 pending;
irqc = irq_data_get_irq_handler_data(&desc->irq_data);
chained_irq_enter(chip, desc);
do {
- pending = xintc_get_irq_local(irqc);
- if (pending == 0)
+ u32 hwirq = xintc_read(irqc, IVR);
+
+ if (hwirq == -1U)
break;
- generic_handle_irq(pending);
+
+ generic_handle_domain_irq(irqc->root_domain, hwirq);
} while (true);
chained_irq_exit(chip, desc);
}
diff --git a/drivers/irqchip/qcom-irq-combiner.c b/drivers/irqchip/qcom-irq-combiner.c
index aa54bfcb0433..18e696dc7f4d 100644
--- a/drivers/irqchip/qcom-irq-combiner.c
+++ b/drivers/irqchip/qcom-irq-combiner.c
@@ -53,7 +53,6 @@ static void combiner_handle_irq(struct irq_desc *desc)
chained_irq_enter(chip, desc);
for (reg = 0; reg < combiner->nregs; reg++) {
- int virq;
int hwirq;
u32 bit;
u32 status;
@@ -70,10 +69,7 @@ static void combiner_handle_irq(struct irq_desc *desc)
bit = __ffs(status);
status &= ~(1 << bit);
hwirq = irq_nr(reg, bit);
- virq = irq_find_mapping(combiner->domain, hwirq);
- if (virq > 0)
- generic_handle_irq(virq);
-
+ generic_handle_domain_irq(combiner->domain, hwirq);
}
}
diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index 5dc63c20b67e..32d59202d408 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -11,9 +11,11 @@
#include <linux/irqdomain.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <linux/soc/qcom/irq.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -459,4 +461,8 @@ fail:
return ret;
}
-IRQCHIP_DECLARE(qcom_pdc, "qcom,pdc", qcom_pdc_init);
+IRQCHIP_PLATFORM_DRIVER_BEGIN(qcom_pdc)
+IRQCHIP_MATCH("qcom,pdc", qcom_pdc_init)
+IRQCHIP_PLATFORM_DRIVER_END(qcom_pdc)
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Power Domain Controller");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index fdf87acccd06..d5f9261fa879 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1158,8 +1158,6 @@ static void capinc_tty_flush_chars(struct tty_struct *tty)
struct capiminor *mp = tty->driver_data;
struct sk_buff *skb;
- pr_debug("capinc_tty_flush_chars\n");
-
spin_lock_bh(&mp->outlock);
skb = mp->outskb;
if (skb) {
@@ -1175,18 +1173,18 @@ static void capinc_tty_flush_chars(struct tty_struct *tty)
handle_minor_recv(mp);
}
-static int capinc_tty_write_room(struct tty_struct *tty)
+static unsigned int capinc_tty_write_room(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
- int room;
+ unsigned int room;
room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue);
room *= CAPI_MAX_BLKSIZE;
- pr_debug("capinc_tty_write_room = %d\n", room);
+ pr_debug("capinc_tty_write_room = %u\n", room);
return room;
}
-static int capinc_tty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int capinc_tty_chars_in_buffer(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
@@ -1197,15 +1195,9 @@ static int capinc_tty_chars_in_buffer(struct tty_struct *tty)
return mp->outbytes;
}
-static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
- pr_debug("capinc_tty_set_termios\n");
-}
-
static void capinc_tty_throttle(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
- pr_debug("capinc_tty_throttle\n");
mp->ttyinstop = 1;
}
@@ -1213,7 +1205,6 @@ static void capinc_tty_unthrottle(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
- pr_debug("capinc_tty_unthrottle\n");
mp->ttyinstop = 0;
handle_minor_recv(mp);
}
@@ -1222,7 +1213,6 @@ static void capinc_tty_stop(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
- pr_debug("capinc_tty_stop\n");
mp->ttyoutstop = 1;
}
@@ -1230,7 +1220,6 @@ static void capinc_tty_start(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
- pr_debug("capinc_tty_start\n");
mp->ttyoutstop = 0;
handle_minor_send(mp);
}
@@ -1239,26 +1228,9 @@ static void capinc_tty_hangup(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
- pr_debug("capinc_tty_hangup\n");
tty_port_hangup(&mp->port);
}
-static int capinc_tty_break_ctl(struct tty_struct *tty, int state)
-{
- pr_debug("capinc_tty_break_ctl(%d)\n", state);
- return 0;
-}
-
-static void capinc_tty_flush_buffer(struct tty_struct *tty)
-{
- pr_debug("capinc_tty_flush_buffer\n");
-}
-
-static void capinc_tty_set_ldisc(struct tty_struct *tty)
-{
- pr_debug("capinc_tty_set_ldisc\n");
-}
-
static void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
{
pr_debug("capinc_tty_send_xchar(%d)\n", ch);
@@ -1272,15 +1244,11 @@ static const struct tty_operations capinc_ops = {
.flush_chars = capinc_tty_flush_chars,
.write_room = capinc_tty_write_room,
.chars_in_buffer = capinc_tty_chars_in_buffer,
- .set_termios = capinc_tty_set_termios,
.throttle = capinc_tty_throttle,
.unthrottle = capinc_tty_unthrottle,
.stop = capinc_tty_stop,
.start = capinc_tty_start,
.hangup = capinc_tty_hangup,
- .break_ctl = capinc_tty_break_ctl,
- .flush_buffer = capinc_tty_flush_buffer,
- .set_ldisc = capinc_tty_set_ldisc,
.send_xchar = capinc_tty_send_xchar,
.install = capinc_tty_install,
.cleanup = capinc_tty_cleanup,
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index 56bd2e9db6ed..e501cb03f211 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -2342,7 +2342,7 @@ static void __exit
HFC_cleanup(void)
{
if (timer_pending(&hfc_tl))
- del_timer(&hfc_tl);
+ del_timer_sync(&hfc_tl);
pci_unregister_driver(&hfc_driver);
}
diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c
index 40588692cec7..e11ca6bbc7f4 100644
--- a/drivers/isdn/mISDN/dsp_pipeline.c
+++ b/drivers/isdn/mISDN/dsp_pipeline.c
@@ -17,9 +17,6 @@
#include "dsp.h"
#include "dsp_hwec.h"
-/* uncomment for debugging */
-/*#define PIPELINE_DEBUG*/
-
struct dsp_pipeline_entry {
struct mISDN_dsp_element *elem;
void *p;
@@ -104,10 +101,6 @@ int mISDN_dsp_element_register(struct mISDN_dsp_element *elem)
}
}
-#ifdef PIPELINE_DEBUG
- printk(KERN_DEBUG "%s: %s registered\n", __func__, elem->name);
-#endif
-
return 0;
err2:
@@ -129,10 +122,6 @@ void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem)
list_for_each_entry_safe(entry, n, &dsp_elements, list)
if (entry->elem == elem) {
device_unregister(&entry->dev);
-#ifdef PIPELINE_DEBUG
- printk(KERN_DEBUG "%s: %s unregistered\n",
- __func__, elem->name);
-#endif
return;
}
printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name);
@@ -145,10 +134,6 @@ int dsp_pipeline_module_init(void)
if (IS_ERR(elements_class))
return PTR_ERR(elements_class);
-#ifdef PIPELINE_DEBUG
- printk(KERN_DEBUG "%s: dsp pipeline module initialized\n", __func__);
-#endif
-
dsp_hwec_init();
return 0;
@@ -168,10 +153,6 @@ void dsp_pipeline_module_exit(void)
__func__, entry->elem->name);
kfree(entry);
}
-
-#ifdef PIPELINE_DEBUG
- printk(KERN_DEBUG "%s: dsp pipeline module exited\n", __func__);
-#endif
}
int dsp_pipeline_init(struct dsp_pipeline *pipeline)
@@ -181,10 +162,6 @@ int dsp_pipeline_init(struct dsp_pipeline *pipeline)
INIT_LIST_HEAD(&pipeline->list);
-#ifdef PIPELINE_DEBUG
- printk(KERN_DEBUG "%s: dsp pipeline ready\n", __func__);
-#endif
-
return 0;
}
@@ -210,15 +187,11 @@ void dsp_pipeline_destroy(struct dsp_pipeline *pipeline)
return;
_dsp_pipeline_destroy(pipeline);
-
-#ifdef PIPELINE_DEBUG
- printk(KERN_DEBUG "%s: dsp pipeline destroyed\n", __func__);
-#endif
}
int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
{
- int incomplete = 0, found = 0;
+ int found = 0;
char *dup, *tok, *name, *args;
struct dsp_element_entry *entry, *n;
struct dsp_pipeline_entry *pipeline_entry;
@@ -251,7 +224,6 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
printk(KERN_ERR "%s: failed to add "
"entry to pipeline: %s (out of "
"memory)\n", __func__, elem->name);
- incomplete = 1;
goto _out;
}
pipeline_entry->elem = elem;
@@ -268,20 +240,12 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
if (pipeline_entry->p) {
list_add_tail(&pipeline_entry->
list, &pipeline->list);
-#ifdef PIPELINE_DEBUG
- printk(KERN_DEBUG "%s: created "
- "instance of %s%s%s\n",
- __func__, name, args ?
- " with args " : "", args ?
- args : "");
-#endif
} else {
printk(KERN_ERR "%s: failed "
"to add entry to pipeline: "
"%s (new() returned NULL)\n",
__func__, elem->name);
kfree(pipeline_entry);
- incomplete = 1;
}
}
found = 1;
@@ -290,11 +254,9 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
if (found)
found = 0;
- else {
+ else
printk(KERN_ERR "%s: element not found, skipping: "
"%s\n", __func__, name);
- incomplete = 1;
- }
}
_out:
@@ -303,10 +265,6 @@ _out:
else
pipeline->inuse = 0;
-#ifdef PIPELINE_DEBUG
- printk(KERN_DEBUG "%s: dsp pipeline built%s: %s\n",
- __func__, incomplete ? " incomplete" : "", cfg);
-#endif
kfree(dup);
return 0;
}
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 49d99cb084db..bdf16180f5ff 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -199,6 +199,7 @@ config LEDS_LM3530
config LEDS_LM3532
tristate "LCD Backlight driver for LM3532"
+ select REGMAP_I2C
depends on LEDS_CLASS
depends on I2C
help
@@ -616,7 +617,6 @@ config LEDS_LT3593
tristate "LED driver for LT3593 controllers"
depends on LEDS_CLASS
depends on GPIOLIB || COMPILE_TEST
- depends on OF
help
This option enables support for LEDs driven by a Linear Technology
LT3593 controller. This controller uses a special one-wire pulse
diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c
index 6a63846d10b5..7eb2f44f16be 100644
--- a/drivers/leds/blink/leds-lgm-sso.c
+++ b/drivers/leds/blink/leds-lgm-sso.c
@@ -7,7 +7,8 @@
#include <linux/bitfield.h>
#include <linux/clk.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/leds.h>
@@ -132,8 +133,7 @@ struct sso_led_priv {
struct regmap *mmap;
struct device *dev;
struct platform_device *pdev;
- struct clk *gclk;
- struct clk *fpid_clk;
+ struct clk_bulk_data clocks[2];
u32 fpid_clkrate;
u32 gptc_clkrate;
u32 freq[MAX_FREQ_RANK];
@@ -259,7 +259,7 @@ static void sso_led_brightness_set(struct led_classdev *led_cdev,
1 << desc->pin);
}
- if (!desc->hw_trig && led->gpiod)
+ if (!desc->hw_trig)
gpiod_set_value(led->gpiod, val);
}
@@ -423,7 +423,7 @@ static void sso_gpio_free(struct gpio_chip *chip, unsigned int offset)
static int sso_gpio_get_dir(struct gpio_chip *chip, unsigned int offset)
{
- return GPIOF_DIR_OUT;
+ return GPIO_LINE_DIRECTION_OUT;
}
static int
@@ -763,12 +763,11 @@ static int sso_probe_gpios(struct sso_led_priv *priv)
return sso_gpio_gc_init(dev, priv);
}
-static void sso_clk_disable(void *data)
+static void sso_clock_disable_unprepare(void *data)
{
struct sso_led_priv *priv = data;
- clk_disable_unprepare(priv->fpid_clk);
- clk_disable_unprepare(priv->gclk);
+ clk_bulk_disable_unprepare(ARRAY_SIZE(priv->clocks), priv->clocks);
}
static int intel_sso_led_probe(struct platform_device *pdev)
@@ -785,36 +784,30 @@ static int intel_sso_led_probe(struct platform_device *pdev)
priv->dev = dev;
/* gate clock */
- priv->gclk = devm_clk_get(dev, "sso");
- if (IS_ERR(priv->gclk)) {
- dev_err(dev, "get sso gate clock failed!\n");
- return PTR_ERR(priv->gclk);
- }
+ priv->clocks[0].id = "sso";
+
+ /* fpid clock */
+ priv->clocks[1].id = "fpid";
- ret = clk_prepare_enable(priv->gclk);
+ ret = devm_clk_bulk_get(dev, ARRAY_SIZE(priv->clocks), priv->clocks);
if (ret) {
- dev_err(dev, "Failed to prepare/enable sso gate clock!\n");
+ dev_err(dev, "Getting clocks failed!\n");
return ret;
}
- priv->fpid_clk = devm_clk_get(dev, "fpid");
- if (IS_ERR(priv->fpid_clk)) {
- dev_err(dev, "Failed to get fpid clock!\n");
- return PTR_ERR(priv->fpid_clk);
- }
-
- ret = clk_prepare_enable(priv->fpid_clk);
+ ret = clk_bulk_prepare_enable(ARRAY_SIZE(priv->clocks), priv->clocks);
if (ret) {
- dev_err(dev, "Failed to prepare/enable fpid clock!\n");
+ dev_err(dev, "Failed to prepare and enable clocks!\n");
return ret;
}
- priv->fpid_clkrate = clk_get_rate(priv->fpid_clk);
- ret = devm_add_action_or_reset(dev, sso_clk_disable, priv);
- if (ret) {
- dev_err(dev, "Failed to devm_add_action_or_reset, %d\n", ret);
+ ret = devm_add_action_or_reset(dev, sso_clock_disable_unprepare, priv);
+ if (ret)
return ret;
- }
+
+ priv->fpid_clkrate = clk_get_rate(priv->clocks[1].clk);
+
+ priv->mmap = syscon_node_to_regmap(dev->of_node);
priv->mmap = syscon_node_to_regmap(dev->of_node);
if (IS_ERR(priv->mmap)) {
@@ -859,8 +852,6 @@ static int intel_sso_led_remove(struct platform_device *pdev)
sso_led_shutdown(led);
}
- clk_disable_unprepare(priv->fpid_clk);
- clk_disable_unprepare(priv->gclk);
regmap_exit(priv->mmap);
return 0;
@@ -878,7 +869,7 @@ static struct platform_driver intel_sso_led_driver = {
.remove = intel_sso_led_remove,
.driver = {
.name = "lgm-ssoled",
- .of_match_table = of_match_ptr(of_sso_led_match),
+ .of_match_table = of_sso_led_match,
},
};
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 2e495ff67856..f704391d57a8 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -285,10 +285,6 @@ struct led_classdev *__must_check devm_of_led_get(struct device *dev,
if (!dev)
return ERR_PTR(-EINVAL);
- /* Not using device tree? */
- if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
- return ERR_PTR(-ENOTSUPP);
-
led = of_led_get(dev->of_node, index);
if (IS_ERR(led))
return led;
@@ -513,7 +509,7 @@ static int devm_led_classdev_match(struct device *dev, void *res, void *data)
/**
* devm_led_classdev_unregister() - resource managed led_classdev_unregister()
- * @parent: The device to unregister.
+ * @dev: The device to unregister.
* @led_cdev: the led_classdev structure for this device.
*/
void devm_led_classdev_unregister(struct device *dev,
diff --git a/drivers/leds/leds-as3645a.c b/drivers/leds/leds-as3645a.c
index e8922fa03379..aa3f82be0a9c 100644
--- a/drivers/leds/leds-as3645a.c
+++ b/drivers/leds/leds-as3645a.c
@@ -185,7 +185,7 @@ static int as3645a_read(struct as3645a *flash, u8 addr)
*/
/**
- * as3645a_set_config - Set flash configuration registers
+ * as3645a_set_current - Set flash configuration registers
* @flash: The flash
*
* Configure the hardware with flash, assist and indicator currents, as well as
@@ -545,6 +545,7 @@ static int as3645a_parse_node(struct as3645a *flash,
if (!flash->indicator_node) {
dev_warn(&flash->client->dev,
"can't find indicator node\n");
+ rval = -ENODEV;
goto out_err;
}
diff --git a/drivers/leds/leds-bcm6328.c b/drivers/leds/leds-bcm6328.c
index 226d17d253ed..2d4d87957a30 100644
--- a/drivers/leds/leds-bcm6328.c
+++ b/drivers/leds/leds-bcm6328.c
@@ -93,7 +93,7 @@ static unsigned long bcm6328_led_read(void __iomem *reg)
#endif
}
-/**
+/*
* LEDMode 64 bits / 24 LEDs
* bits [31:0] -> LEDs 8-23
* bits [47:32] -> LEDs 0-7
diff --git a/drivers/leds/leds-blinkm.c b/drivers/leds/leds-blinkm.c
index b4e1fdff4186..bd7d0d5cf3b6 100644
--- a/drivers/leds/leds-blinkm.c
+++ b/drivers/leds/leds-blinkm.c
@@ -480,9 +480,8 @@ static int blinkm_led_blue_set(struct led_classdev *led_cdev,
static void blinkm_init_hw(struct i2c_client *client)
{
- int ret;
- ret = blinkm_transfer_hw(client, BLM_STOP_SCRIPT);
- ret = blinkm_transfer_hw(client, BLM_GO_RGB);
+ blinkm_transfer_hw(client, BLM_STOP_SCRIPT);
+ blinkm_transfer_hw(client, BLM_GO_RGB);
}
static int blinkm_test_run(struct i2c_client *client)
diff --git a/drivers/leds/leds-el15203000.c b/drivers/leds/leds-el15203000.c
index 6ca47f2a2004..76b455e87574 100644
--- a/drivers/leds/leds-el15203000.c
+++ b/drivers/leds/leds-el15203000.c
@@ -68,8 +68,8 @@ enum el15203000_command {
};
struct el15203000_led {
- struct el15203000 *priv;
struct led_classdev ldev;
+ struct el15203000 *priv;
u32 reg;
};
@@ -82,6 +82,8 @@ struct el15203000 {
struct el15203000_led leds[];
};
+#define to_el15203000_led(d) container_of(d, struct el15203000_led, ldev)
+
static int el15203000_cmd(struct el15203000_led *led, u8 brightness)
{
int ret;
@@ -128,9 +130,7 @@ static int el15203000_cmd(struct el15203000_led *led, u8 brightness)
static int el15203000_set_blocking(struct led_classdev *ldev,
enum led_brightness brightness)
{
- struct el15203000_led *led = container_of(ldev,
- struct el15203000_led,
- ldev);
+ struct el15203000_led *led = to_el15203000_led(ldev);
return el15203000_cmd(led, brightness == LED_OFF ? EL_OFF : EL_ON);
}
@@ -139,9 +139,7 @@ static int el15203000_pattern_set_S(struct led_classdev *ldev,
struct led_pattern *pattern,
u32 len, int repeat)
{
- struct el15203000_led *led = container_of(ldev,
- struct el15203000_led,
- ldev);
+ struct el15203000_led *led = to_el15203000_led(ldev);
if (repeat > 0 || len != 2 ||
pattern[0].delta_t != 4000 || pattern[0].brightness != 0 ||
@@ -192,10 +190,8 @@ static int el15203000_pattern_set_P(struct led_classdev *ldev,
struct led_pattern *pattern,
u32 len, int repeat)
{
+ struct el15203000_led *led = to_el15203000_led(ldev);
u8 cmd;
- struct el15203000_led *led = container_of(ldev,
- struct el15203000_led,
- ldev);
if (repeat > 0)
return -EINVAL;
@@ -232,9 +228,7 @@ static int el15203000_pattern_set_P(struct led_classdev *ldev,
static int el15203000_pattern_clear(struct led_classdev *ldev)
{
- struct el15203000_led *led = container_of(ldev,
- struct el15203000_led,
- ldev);
+ struct el15203000_led *led = to_el15203000_led(ldev);
return el15203000_cmd(led, EL_OFF);
}
@@ -251,16 +245,13 @@ static int el15203000_probe_dt(struct el15203000 *priv)
ret = fwnode_property_read_u32(child, "reg", &led->reg);
if (ret) {
dev_err(priv->dev, "LED without ID number");
- fwnode_handle_put(child);
-
- break;
+ goto err_child_out;
}
if (led->reg > U8_MAX) {
dev_err(priv->dev, "LED value %d is invalid", led->reg);
- fwnode_handle_put(child);
-
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_child_out;
}
led->priv = priv;
@@ -282,14 +273,16 @@ static int el15203000_probe_dt(struct el15203000 *priv)
dev_err(priv->dev,
"failed to register LED device %s, err %d",
led->ldev.name, ret);
- fwnode_handle_put(child);
-
- break;
+ goto err_child_out;
}
led++;
}
+ return 0;
+
+err_child_out:
+ fwnode_handle_put(child);
return ret;
}
diff --git a/drivers/leds/leds-gpio-register.c b/drivers/leds/leds-gpio-register.c
index b9187e71e0cf..de3f12c2b80d 100644
--- a/drivers/leds/leds-gpio-register.c
+++ b/drivers/leds/leds-gpio-register.c
@@ -11,6 +11,7 @@
/**
* gpio_led_register_device - register a gpio-led device
* @pdata: the platform data used for the new device
+ * @id: platform ID
*
* Makes a copy of pdata and pdata->leds and registers a new leds-gpio device
* with the result. This allows to have pdata and pdata-leds in .init.rodata
diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c
index 2180255ad339..3b55af9a8c58 100644
--- a/drivers/leds/leds-is31fl32xx.c
+++ b/drivers/leds/leds-is31fl32xx.c
@@ -58,7 +58,8 @@ struct is31fl32xx_priv {
* @pwm_registers_reversed: : true if PWM registers count down instead of up
* @led_control_register_base : address of first LED control register (optional)
* @enable_bits_per_led_control_register: number of LEDs enable bits in each
- * @reset_func: : pointer to reset function
+ * @reset_func : pointer to reset function
+ * @sw_shutdown_func : pointer to software shutdown function
*
* For all optional register addresses, the sentinel value %IS31FL32XX_REG_NONE
* indicates that this chip has no such register.
diff --git a/drivers/leds/leds-ktd2692.c b/drivers/leds/leds-ktd2692.c
index 632f10db4b3f..f341da1503a4 100644
--- a/drivers/leds/leds-ktd2692.c
+++ b/drivers/leds/leds-ktd2692.c
@@ -256,6 +256,17 @@ static void ktd2692_setup(struct ktd2692_context *led)
| KTD2692_REG_FLASH_CURRENT_BASE);
}
+static void regulator_disable_action(void *_data)
+{
+ struct device *dev = _data;
+ struct ktd2692_context *led = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regulator_disable(led->regulator);
+ if (ret)
+ dev_err(dev, "Failed to disable supply: %d\n", ret);
+}
+
static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
struct ktd2692_led_config_data *cfg)
{
@@ -286,8 +297,14 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
if (led->regulator) {
ret = regulator_enable(led->regulator);
- if (ret)
+ if (ret) {
dev_err(dev, "Failed to enable supply: %d\n", ret);
+ } else {
+ ret = devm_add_action_or_reset(dev,
+ regulator_disable_action, dev);
+ if (ret)
+ return ret;
+ }
}
child_node = of_get_next_available_child(np, NULL);
@@ -377,17 +394,9 @@ static int ktd2692_probe(struct platform_device *pdev)
static int ktd2692_remove(struct platform_device *pdev)
{
struct ktd2692_context *led = platform_get_drvdata(pdev);
- int ret;
led_classdev_flash_unregister(&led->fled_cdev);
- if (led->regulator) {
- ret = regulator_disable(led->regulator);
- if (ret)
- dev_err(&pdev->dev,
- "Failed to disable supply: %d\n", ret);
- }
-
mutex_destroy(&led->lock);
return 0;
diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c
index 2db455efd4b1..e72393534b72 100644
--- a/drivers/leds/leds-lm3530.c
+++ b/drivers/leds/leds-lm3530.c
@@ -99,7 +99,7 @@ static struct lm3530_mode_map mode_map[] = {
* @pdata: LM3530 platform data
* @mode: mode of operation - manual, ALS, PWM
* @regulator: regulator
- * @brighness: previous brightness value
+ * @brightness: previous brightness value
* @enable: regulator is enabled
*/
struct lm3530_data {
diff --git a/drivers/leds/leds-lm3532.c b/drivers/leds/leds-lm3532.c
index 0bf25bdde02f..beb53040e09e 100644
--- a/drivers/leds/leds-lm3532.c
+++ b/drivers/leds/leds-lm3532.c
@@ -586,7 +586,6 @@ static int lm3532_parse_node(struct lm3532_data *priv)
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;
}
@@ -601,7 +600,6 @@ static int lm3532_parse_node(struct lm3532_data *priv)
&led->mode);
if (ret) {
dev_err(&priv->client->dev, "ti,led-mode property missing\n");
- fwnode_handle_put(child);
goto child_out;
}
@@ -636,7 +634,6 @@ static int lm3532_parse_node(struct lm3532_data *priv)
led->num_leds);
if (ret) {
dev_err(&priv->client->dev, "led-sources property missing\n");
- fwnode_handle_put(child);
goto child_out;
}
@@ -647,7 +644,6 @@ static int lm3532_parse_node(struct lm3532_data *priv)
if (ret) {
dev_err(&priv->client->dev, "led register err: %d\n",
ret);
- fwnode_handle_put(child);
goto child_out;
}
@@ -655,14 +651,15 @@ static int lm3532_parse_node(struct lm3532_data *priv)
if (ret) {
dev_err(&priv->client->dev, "register init err: %d\n",
ret);
- fwnode_handle_put(child);
goto child_out;
}
i++;
}
+ return 0;
child_out:
+ fwnode_handle_put(child);
return ret;
}
diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c
index aadb03468a40..e009b6d17915 100644
--- a/drivers/leds/leds-lm36274.c
+++ b/drivers/leds/leds-lm36274.c
@@ -7,9 +7,10 @@
#include <linux/err.h>
#include <linux/leds.h>
#include <linux/leds-ti-lmu-common.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/mfd/ti-lmu.h>
#include <linux/mfd/ti-lmu-register.h>
@@ -127,6 +128,7 @@ static int lm36274_probe(struct platform_device *pdev)
ret = lm36274_init(chip);
if (ret) {
+ fwnode_handle_put(init_data.fwnode);
dev_err(chip->dev, "Failed to init the device\n");
return ret;
}
diff --git a/drivers/leds/leds-lm3692x.c b/drivers/leds/leds-lm3692x.c
index e945de45388c..a02756d7ed8f 100644
--- a/drivers/leds/leds-lm3692x.c
+++ b/drivers/leds/leds-lm3692x.c
@@ -96,15 +96,15 @@
#define LM3692X_FAULT_FLAG_OPEN BIT(4)
/**
- * struct lm3692x_led -
- * @lock - Lock for reading/writing the device
- * @client - Pointer to the I2C client
- * @led_dev - LED class device pointer
- * @regmap - Devices register map
- * @enable_gpio - VDDIO/EN gpio to enable communication interface
- * @regulator - LED supply regulator pointer
- * @led_enable - LED sync to be enabled
- * @model_id - Current device model ID enumerated
+ * struct lm3692x_led
+ * @lock: Lock for reading/writing the device
+ * @client: Pointer to the I2C client
+ * @led_dev: LED class device pointer
+ * @regmap: Devices register map
+ * @enable_gpio: VDDIO/EN gpio to enable communication interface
+ * @regulator: LED supply regulator pointer
+ * @led_enable: LED sync to be enabled
+ * @model_id: Current device model ID enumerated
*/
struct lm3692x_led {
struct mutex lock;
@@ -435,6 +435,7 @@ static int lm3692x_probe_dt(struct lm3692x_led *led)
ret = fwnode_property_read_u32(child, "reg", &led->led_enable);
if (ret) {
+ fwnode_handle_put(child);
dev_err(&led->client->dev, "reg DT property missing\n");
return ret;
}
@@ -449,12 +450,11 @@ static int lm3692x_probe_dt(struct lm3692x_led *led)
ret = devm_led_classdev_register_ext(&led->client->dev, &led->led_dev,
&init_data);
- if (ret) {
+ if (ret)
dev_err(&led->client->dev, "led register err: %d\n", ret);
- return ret;
- }
- return 0;
+ fwnode_handle_put(init_data.fwnode);
+ return ret;
}
static int lm3692x_probe(struct i2c_client *client,
diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c
index 7d216cdb91a8..970a4f34791b 100644
--- a/drivers/leds/leds-lm3697.c
+++ b/drivers/leds/leds-lm3697.c
@@ -47,6 +47,8 @@
* @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
+ * @enabled: LED brightness level (or LED_OFF)
+ * @num_leds: Number of LEDs available
*/
struct lm3697_led {
u32 hvled_strings[LM3697_MAX_LED_STRINGS];
@@ -68,6 +70,8 @@ struct lm3697_led {
* @dev: Pointer to the devices device struct
* @lock: Lock for reading/writing the device
* @leds: Array of LED strings
+ * @bank_cfg: OUTPUT_CONFIG register values
+ * @num_banks: Number of control banks
*/
struct lm3697 {
struct gpio_desc *enable_gpio;
@@ -203,11 +207,9 @@ static int lm3697_probe_dt(struct lm3697 *priv)
priv->enable_gpio = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_LOW);
- if (IS_ERR(priv->enable_gpio)) {
- ret = PTR_ERR(priv->enable_gpio);
- dev_err(dev, "Failed to get enable gpio: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(priv->enable_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->enable_gpio),
+ "Failed to get enable GPIO\n");
priv->regulator = devm_regulator_get(dev, "vled");
if (IS_ERR(priv->regulator))
diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c
index 838e6f19d37e..437c711b2a27 100644
--- a/drivers/leds/leds-lp3944.c
+++ b/drivers/leds/leds-lp3944.c
@@ -92,7 +92,7 @@ static int lp3944_reg_write(struct i2c_client *client, u8 reg, u8 value)
}
/**
- * Set the period for DIM status
+ * lp3944_dim_set_period() - Set the period for DIM status
*
* @client: the i2c client
* @dim: either LP3944_DIM0 or LP3944_DIM1
@@ -123,7 +123,7 @@ static int lp3944_dim_set_period(struct i2c_client *client, u8 dim, u16 period)
}
/**
- * Set the duty cycle for DIM status
+ * lp3944_dim_set_dutycycle - Set the duty cycle for DIM status
*
* @client: the i2c client
* @dim: either LP3944_DIM0 or LP3944_DIM1
@@ -155,7 +155,7 @@ static int lp3944_dim_set_dutycycle(struct i2c_client *client, u8 dim,
}
/**
- * Set the led status
+ * lp3944_led_set() - Set the led status
*
* @led: a lp3944_led_data structure
* @status: one of LP3944_LED_STATUS_OFF
diff --git a/drivers/leds/leds-lp50xx.c b/drivers/leds/leds-lp50xx.c
index 06230614fdc5..401df1e2e05d 100644
--- a/drivers/leds/leds-lp50xx.c
+++ b/drivers/leds/leds-lp50xx.c
@@ -490,6 +490,7 @@ static int lp50xx_probe_dt(struct lp50xx *priv)
ret = fwnode_property_read_u32(led_node, "color",
&color_id);
if (ret) {
+ fwnode_handle_put(led_node);
dev_err(priv->dev, "Cannot read color\n");
goto child_out;
}
@@ -512,7 +513,6 @@ static int lp50xx_probe_dt(struct lp50xx *priv)
goto child_out;
}
i++;
- fwnode_handle_put(child);
}
return 0;
diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c
index 81de1346bf5d..d1657c46ee2f 100644
--- a/drivers/leds/leds-lp55xx-common.c
+++ b/drivers/leds/leds-lp55xx-common.c
@@ -694,7 +694,7 @@ struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev,
of_property_read_u8(np, "clock-mode", &pdata->clock_mode);
pdata->enable_gpiod = devm_gpiod_get_optional(dev, "enable",
- GPIOD_ASIS);
+ GPIOD_OUT_LOW);
if (IS_ERR(pdata->enable_gpiod))
return ERR_CAST(pdata->enable_gpiod);
diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c
index f0533a337bc1..3c693d5e3b44 100644
--- a/drivers/leds/leds-lp8860.c
+++ b/drivers/leds/leds-lp8860.c
@@ -85,14 +85,14 @@
#define LP8860_NAME "lp8860"
/**
- * struct lp8860_led -
- * @lock - Lock for reading/writing the device
- * @client - Pointer to the I2C client
- * @led_dev - led class device pointer
- * @regmap - Devices register map
- * @eeprom_regmap - EEPROM register map
- * @enable_gpio - VDDIO/EN gpio to enable communication interface
- * @regulator - LED supply regulator pointer
+ * struct lp8860_led
+ * @lock: Lock for reading/writing the device
+ * @client: Pointer to the I2C client
+ * @led_dev: led class device pointer
+ * @regmap: Devices register map
+ * @eeprom_regmap: EEPROM register map
+ * @enable_gpio: VDDIO/EN gpio to enable communication interface
+ * @regulator: LED supply regulator pointer
*/
struct lp8860_led {
struct mutex lock;
diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c
index 68e06434ac08..3bb52d3165d9 100644
--- a/drivers/leds/leds-lt3593.c
+++ b/drivers/leds/leds-lt3593.c
@@ -7,8 +7,9 @@
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of.h>
+#include <linux/property.h>
#define LED_LT3593_NAME "lt3593"
@@ -68,9 +69,6 @@ static int lt3593_led_probe(struct platform_device *pdev)
struct led_init_data init_data = {};
const char *tmp;
- if (!dev_of_node(dev))
- return -ENODEV;
-
led_data = devm_kzalloc(dev, sizeof(*led_data), GFP_KERNEL);
if (!led_data)
return -ENOMEM;
@@ -119,7 +117,7 @@ static struct platform_driver lt3593_led_driver = {
.probe = lt3593_led_probe,
.driver = {
.name = "leds-lt3593",
- .of_match_table = of_match_ptr(of_lt3593_leds_match),
+ .of_match_table = of_lt3593_leds_match,
},
};
diff --git a/drivers/leds/leds-mlxcpld.c b/drivers/leds/leds-mlxcpld.c
index f4721f8065f0..1355c84a2919 100644
--- a/drivers/leds/leds-mlxcpld.c
+++ b/drivers/leds/leds-mlxcpld.c
@@ -64,10 +64,10 @@
#define MLXCPLD_LED_BLINK_6HZ 83 /* ~83 msec off/on */
/**
- * mlxcpld_param - LED access parameters:
- * @offset - offset for LED access in CPLD device
- * @mask - mask for LED access in CPLD device
- * @base_color - base color code for LED
+ * struct mlxcpld_param - LED access parameters:
+ * @offset: offset for LED access in CPLD device
+ * @mask: mask for LED access in CPLD device
+ * @base_color: base color code for LED
**/
struct mlxcpld_param {
u8 offset;
@@ -76,9 +76,9 @@ struct mlxcpld_param {
};
/**
- * mlxcpld_led_priv - LED private data:
- * @cled - LED class device instance
- * @param - LED CPLD access parameters
+ * struct mlxcpld_led_priv - LED private data:
+ * @cled: LED class device instance
+ * @param: LED CPLD access parameters
**/
struct mlxcpld_led_priv {
struct led_classdev cdev;
@@ -88,12 +88,12 @@ struct mlxcpld_led_priv {
#define cdev_to_priv(c) container_of(c, struct mlxcpld_led_priv, cdev)
/**
- * mlxcpld_led_profile - system LED profile (defined per system class):
- * @offset - offset for LED access in CPLD device
- * @mask - mask for LED access in CPLD device
- * @base_color - base color code
- * @brightness - default brightness setting (on/off)
- * @name - LED name
+ * struct mlxcpld_led_profile - system LED profile (defined per system class):
+ * @offset: offset for LED access in CPLD device
+ * @mask: mask for LED access in CPLD device
+ * @base_color: base color code
+ * @brightness: default brightness setting (on/off)
+ * @name: LED name
**/
struct mlxcpld_led_profile {
u8 offset;
@@ -104,12 +104,12 @@ struct mlxcpld_led_profile {
};
/**
- * mlxcpld_led_pdata - system LED private data
- * @pdev - platform device pointer
- * @pled - LED class device instance
- * @profile - system configuration profile
- * @num_led_instances - number of LED instances
- * @lock - device access lock
+ * struct mlxcpld_led_pdata - system LED private data
+ * @pdev: platform device pointer
+ * @pled: LED class device instance
+ * @profile: system configuration profile
+ * @num_led_instances: number of LED instances
+ * @lock: device access lock
**/
struct mlxcpld_led_pdata {
struct platform_device *pdev;
diff --git a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c
index 82aea1cd0c12..b7855c93bd72 100644
--- a/drivers/leds/leds-mlxreg.c
+++ b/drivers/leds/leds-mlxreg.c
@@ -28,10 +28,11 @@
* struct mlxreg_led_data - led control data:
*
* @data: led configuration data;
- * @led_classdev: led class data;
+ * @led_cdev: led class data;
* @base_color: base led color (other colors have constant offset from base);
* @led_data: led data;
* @data_parent: pointer to private device control data of parent;
+ * @led_cdev_name: class device name
*/
struct mlxreg_led_data {
struct mlxreg_core_data *data;
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index f53f9309ca6c..d71e9fa5c8de 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -101,7 +101,7 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv)
{
struct fwnode_handle *fwnode;
struct led_pwm led;
- int ret = 0;
+ int ret;
memset(&led, 0, sizeof(led));
@@ -111,8 +111,8 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv)
led.name = to_of_node(fwnode)->name;
if (!led.name) {
- fwnode_handle_put(fwnode);
- return -EINVAL;
+ ret = EINVAL;
+ goto err_child_out;
}
led.active_low = fwnode_property_read_bool(fwnode,
@@ -121,12 +121,14 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv)
&led.max_brightness);
ret = led_pwm_add(dev, priv, &led, fwnode);
- if (ret) {
- fwnode_handle_put(fwnode);
- break;
- }
+ if (ret)
+ goto err_child_out;
}
+ return 0;
+
+err_child_out:
+ fwnode_handle_put(fwnode);
return ret;
}
diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c
index 5b9dfdf743ec..cb7bd1353f9f 100644
--- a/drivers/leds/leds-tlc591xx.c
+++ b/drivers/leds/leds-tlc591xx.c
@@ -148,16 +148,20 @@ static int
tlc591xx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct device_node *np = dev_of_node(&client->dev), *child;
+ struct device_node *np, *child;
struct device *dev = &client->dev;
const struct tlc591xx *tlc591xx;
struct tlc591xx_priv *priv;
int err, count, reg;
- tlc591xx = device_get_match_data(dev);
+ np = dev_of_node(dev);
if (!np)
return -ENODEV;
+ tlc591xx = device_get_match_data(dev);
+ if (!tlc591xx)
+ return -ENODEV;
+
count = of_get_available_child_count(np);
if (!count || count > tlc591xx->max_leds)
return -EINVAL;
diff --git a/drivers/leds/leds-turris-omnia.c b/drivers/leds/leds-turris-omnia.c
index 2f9a289ab245..1adfed1c0619 100644
--- a/drivers/leds/leds-turris-omnia.c
+++ b/drivers/leds/leds-turris-omnia.c
@@ -274,6 +274,7 @@ static const struct i2c_device_id omnia_id[] = {
{ "omnia", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, omnia_id);
static struct i2c_driver omnia_leds_driver = {
.probe = omnia_leds_probe,
diff --git a/drivers/leds/trigger/ledtrig-activity.c b/drivers/leds/trigger/ledtrig-activity.c
index 14ba7faaed9e..30bc9df03636 100644
--- a/drivers/leds/trigger/ledtrig-activity.c
+++ b/drivers/leds/trigger/ledtrig-activity.c
@@ -11,6 +11,7 @@
#include <linux/kernel_stat.h>
#include <linux/leds.h>
#include <linux/module.h>
+#include <linux/panic_notifier.h>
#include <linux/reboot.h>
#include <linux/sched.h>
#include <linux/slab.h>
diff --git a/drivers/leds/trigger/ledtrig-cpu.c b/drivers/leds/trigger/ledtrig-cpu.c
index fca62d503590..8af4f9bb9cde 100644
--- a/drivers/leds/trigger/ledtrig-cpu.c
+++ b/drivers/leds/trigger/ledtrig-cpu.c
@@ -43,7 +43,7 @@ static atomic_t num_active_cpus = ATOMIC_INIT(0);
/**
* ledtrig_cpu - emit a CPU event as a trigger
- * @evt: CPU event to be emitted
+ * @ledevt: CPU event to be emitted
*
* Emit a CPU event on a CPU core, which will trigger a
* bound LED to turn on or turn off.
diff --git a/drivers/leds/trigger/ledtrig-heartbeat.c b/drivers/leds/trigger/ledtrig-heartbeat.c
index 36b6709afe9f..7fe0a05574d2 100644
--- a/drivers/leds/trigger/ledtrig-heartbeat.c
+++ b/drivers/leds/trigger/ledtrig-heartbeat.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/panic_notifier.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/sched.h>
diff --git a/drivers/leds/trigger/ledtrig-panic.c b/drivers/leds/trigger/ledtrig-panic.c
index 5751cd032f9d..64abf2e91608 100644
--- a/drivers/leds/trigger/ledtrig-panic.c
+++ b/drivers/leds/trigger/ledtrig-panic.c
@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/notifier.h>
+#include <linux/panic_notifier.h>
#include <linux/leds.h>
#include "../leds.h"
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 40a948c08a0b..cf8a75494833 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -305,7 +305,6 @@ static int __nvm_config_extended(struct nvm_dev *dev,
static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
{
struct nvm_ioctl_create_extended e;
- struct request_queue *tqueue;
struct gendisk *tdisk;
struct nvm_tgt_type *tt;
struct nvm_target *t;
@@ -370,24 +369,16 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
goto err_t;
}
- tdisk = alloc_disk(0);
+ tdisk = blk_alloc_disk(dev->q->node);
if (!tdisk) {
ret = -ENOMEM;
goto err_dev;
}
- tqueue = blk_alloc_queue(dev->q->node);
- if (!tqueue) {
- ret = -ENOMEM;
- goto err_disk;
- }
-
strlcpy(tdisk->disk_name, create->tgtname, sizeof(tdisk->disk_name));
- tdisk->flags = GENHD_FL_EXT_DEVT;
tdisk->major = 0;
tdisk->first_minor = 0;
tdisk->fops = tt->bops;
- tdisk->queue = tqueue;
targetdata = tt->init(tgt_dev, tdisk, create->flags);
if (IS_ERR(targetdata)) {
@@ -396,14 +387,14 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
}
tdisk->private_data = targetdata;
- tqueue->queuedata = targetdata;
+ tdisk->queue->queuedata = targetdata;
mdts = (dev->geo.csecs >> 9) * NVM_MAX_VLBA;
if (dev->geo.mdts) {
mdts = min_t(u32, dev->geo.mdts,
(dev->geo.csecs >> 9) * NVM_MAX_VLBA);
}
- blk_queue_max_hw_sectors(tqueue, mdts);
+ blk_queue_max_hw_sectors(tdisk->queue, mdts);
set_capacity(tdisk, tt->capacity(targetdata));
add_disk(tdisk);
@@ -428,10 +419,7 @@ err_sysfs:
if (tt->exit)
tt->exit(targetdata, true);
err_init:
- blk_cleanup_queue(tqueue);
- tdisk->queue = NULL;
-err_disk:
- put_disk(tdisk);
+ blk_cleanup_disk(tdisk);
err_dev:
nvm_remove_tgt_dev(tgt_dev, 0);
err_t:
@@ -445,10 +433,8 @@ static void __nvm_remove_target(struct nvm_target *t, bool graceful)
{
struct nvm_tgt_type *tt = t->type;
struct gendisk *tdisk = t->disk;
- struct request_queue *q = tdisk->queue;
del_gendisk(tdisk);
- blk_cleanup_queue(q);
if (tt->sysfs_exit)
tt->sysfs_exit(tdisk);
@@ -457,7 +443,7 @@ static void __nvm_remove_target(struct nvm_target *t, bool graceful)
tt->exit(tdisk->private_data, graceful);
nvm_remove_tgt_dev(t->dev, 1);
- put_disk(tdisk);
+ blk_cleanup_disk(tdisk);
module_put(t->type->owner);
list_del(&t->list);
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 68de2c6af727..b4b780ea2ac8 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -160,6 +160,18 @@ config MAILBOX_TEST
Test client to help with testing new Controller driver
implementations.
+config POLARFIRE_SOC_MAILBOX
+ tristate "PolarFire SoC (MPFS) Mailbox"
+ depends on HAS_IOMEM
+ depends on SOC_MICROCHIP_POLARFIRE || COMPILE_TEST
+ help
+ This driver adds support for the PolarFire SoC (MPFS) mailbox controller.
+
+ To compile this driver as a module, choose M here. the
+ module will be called mailbox-mpfs.
+
+ If unsure, say N.
+
config QCOM_APCS_IPC
tristate "Qualcomm APCS IPC driver"
depends on ARCH_QCOM || COMPILE_TEST
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 7194fa92c787..c2089f04887e 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -41,6 +41,8 @@ obj-$(CONFIG_BCM_PDC_MBOX) += bcm-pdc-mailbox.o
obj-$(CONFIG_BCM_FLEXRM_MBOX) += bcm-flexrm-mailbox.o
+obj-$(CONFIG_POLARFIRE_SOC_MAILBOX) += mailbox-mpfs.o
+
obj-$(CONFIG_QCOM_APCS_IPC) += qcom-apcs-ipc-mailbox.o
obj-$(CONFIG_TEGRA_HSP_MBOX) += tegra-hsp.o
diff --git a/drivers/mailbox/arm_mhu.c b/drivers/mailbox/arm_mhu.c
index b7fbf276eb62..22243cabe056 100644
--- a/drivers/mailbox/arm_mhu.c
+++ b/drivers/mailbox/arm_mhu.c
@@ -122,10 +122,8 @@ static int mhu_probe(struct amba_device *adev, const struct amba_id *id)
return -ENOMEM;
mhu->base = devm_ioremap_resource(dev, &adev->res);
- if (IS_ERR(mhu->base)) {
- dev_err(dev, "ioremap failed\n");
+ if (IS_ERR(mhu->base))
return PTR_ERR(mhu->base);
- }
for (i = 0; i < MHU_CHANS; i++) {
mhu->chan[i].con_priv = &mhu->mlink[i];
diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c
index b4f33dc399a0..78073ad1f2f1 100644
--- a/drivers/mailbox/bcm-flexrm-mailbox.c
+++ b/drivers/mailbox/bcm-flexrm-mailbox.c
@@ -1523,7 +1523,6 @@ static int flexrm_mbox_probe(struct platform_device *pdev)
mbox->regs = devm_ioremap_resource(&pdev->dev, iomem);
if (IS_ERR(mbox->regs)) {
ret = PTR_ERR(mbox->regs);
- dev_err(&pdev->dev, "Failed to remap mailbox regs: %d\n", ret);
goto fail;
}
regs_end = mbox->regs + resource_size(iomem);
diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c
index 5b375985f7b8..8d3a4c1fe761 100644
--- a/drivers/mailbox/bcm-pdc-mailbox.c
+++ b/drivers/mailbox/bcm-pdc-mailbox.c
@@ -1577,7 +1577,6 @@ static int pdc_probe(struct platform_device *pdev)
pdcs->pdc_reg_vbase = devm_ioremap_resource(&pdev->dev, pdc_regs);
if (IS_ERR(pdcs->pdc_reg_vbase)) {
err = PTR_ERR(pdcs->pdc_reg_vbase);
- dev_err(&pdev->dev, "Failed to map registers: %d\n", err);
goto cleanup_ring_pool;
}
diff --git a/drivers/mailbox/bcm2835-mailbox.c b/drivers/mailbox/bcm2835-mailbox.c
index 39761d190545..86b7ce3549c5 100644
--- a/drivers/mailbox/bcm2835-mailbox.c
+++ b/drivers/mailbox/bcm2835-mailbox.c
@@ -157,7 +157,6 @@ static int bcm2835_mbox_probe(struct platform_device *pdev)
mbox->regs = devm_ioremap_resource(&pdev->dev, iomem);
if (IS_ERR(mbox->regs)) {
ret = PTR_ERR(mbox->regs);
- dev_err(&pdev->dev, "Failed to remap mailbox regs: %d\n", ret);
return ret;
}
diff --git a/drivers/mailbox/hi3660-mailbox.c b/drivers/mailbox/hi3660-mailbox.c
index 53f4bc2488c5..395ddc250828 100644
--- a/drivers/mailbox/hi3660-mailbox.c
+++ b/drivers/mailbox/hi3660-mailbox.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2017-2018 Hisilicon Limited.
+// Copyright (c) 2017-2018 HiSilicon Limited.
// Copyright (c) 2017-2018 Linaro Limited.
#include <linux/bitops.h>
diff --git a/drivers/mailbox/hi6220-mailbox.c b/drivers/mailbox/hi6220-mailbox.c
index cc236ac7a0b5..560cd09538b1 100644
--- a/drivers/mailbox/hi6220-mailbox.c
+++ b/drivers/mailbox/hi6220-mailbox.c
@@ -2,7 +2,7 @@
/*
* Hisilicon's Hi6220 mailbox driver
*
- * Copyright (c) 2015 Hisilicon Limited.
+ * Copyright (c) 2015 HiSilicon Limited.
* Copyright (c) 2015 Linaro Limited.
*
* Author: Leo Yan <leo.yan@linaro.org>
diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
index 2543c7b6948b..0ce75c6b36b6 100644
--- a/drivers/mailbox/imx-mailbox.c
+++ b/drivers/mailbox/imx-mailbox.c
@@ -15,20 +15,6 @@
#include <linux/pm_runtime.h>
#include <linux/slab.h>
-#define IMX_MU_xSR_GIPn(x) BIT(28 + (3 - (x)))
-#define IMX_MU_xSR_RFn(x) BIT(24 + (3 - (x)))
-#define IMX_MU_xSR_TEn(x) BIT(20 + (3 - (x)))
-#define IMX_MU_xSR_BRDIP BIT(9)
-
-/* General Purpose Interrupt Enable */
-#define IMX_MU_xCR_GIEn(x) BIT(28 + (3 - (x)))
-/* Receive Interrupt Enable */
-#define IMX_MU_xCR_RIEn(x) BIT(24 + (3 - (x)))
-/* Transmit Interrupt Enable */
-#define IMX_MU_xCR_TIEn(x) BIT(20 + (3 - (x)))
-/* General Purpose Interrupt Request */
-#define IMX_MU_xCR_GIRn(x) BIT(16 + (3 - (x)))
-
#define IMX_MU_CHANS 16
/* TX0/RX0/RXDB[0-3] */
#define IMX_MU_SCU_CHANS 6
@@ -41,6 +27,21 @@ enum imx_mu_chan_type {
IMX_MU_TYPE_RXDB, /* Rx doorbell */
};
+enum imx_mu_xcr {
+ IMX_MU_GIER,
+ IMX_MU_GCR,
+ IMX_MU_TCR,
+ IMX_MU_RCR,
+ IMX_MU_xCR_MAX,
+};
+
+enum imx_mu_xsr {
+ IMX_MU_SR,
+ IMX_MU_GSR,
+ IMX_MU_TSR,
+ IMX_MU_RSR,
+};
+
struct imx_sc_rpc_msg_max {
struct imx_sc_rpc_msg hdr;
u32 data[7];
@@ -67,21 +68,41 @@ struct imx_mu_priv {
struct clk *clk;
int irq;
- u32 xcr;
+ u32 xcr[4];
bool side_b;
};
+enum imx_mu_type {
+ IMX_MU_V1,
+ IMX_MU_V2,
+};
+
struct imx_mu_dcfg {
int (*tx)(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, void *data);
int (*rx)(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp);
void (*init)(struct imx_mu_priv *priv);
- u32 xTR[4]; /* Transmit Registers */
- u32 xRR[4]; /* Receive Registers */
- u32 xSR; /* Status Register */
- u32 xCR; /* Control Register */
+ enum imx_mu_type type;
+ u32 xTR; /* Transmit Register0 */
+ u32 xRR; /* Receive Register0 */
+ u32 xSR[4]; /* Status Registers */
+ u32 xCR[4]; /* Control Registers */
};
+#define IMX_MU_xSR_GIPn(type, x) (type == IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x))))
+#define IMX_MU_xSR_RFn(type, x) (type == IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x))))
+#define IMX_MU_xSR_TEn(type, x) (type == IMX_MU_V2 ? BIT(x) : BIT(20 + (3 - (x))))
+
+/* General Purpose Interrupt Enable */
+#define IMX_MU_xCR_GIEn(type, x) (type == IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x))))
+/* Receive Interrupt Enable */
+#define IMX_MU_xCR_RIEn(type, x) (type == IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x))))
+/* Transmit Interrupt Enable */
+#define IMX_MU_xCR_TIEn(type, x) (type == IMX_MU_V2 ? BIT(x) : BIT(20 + (3 - (x))))
+/* General Purpose Interrupt Request */
+#define IMX_MU_xCR_GIRn(type, x) (type == IMX_MU_V2 ? BIT(x) : BIT(16 + (3 - (x))))
+
+
static struct imx_mu_priv *to_imx_mu_priv(struct mbox_controller *mbox)
{
return container_of(mbox, struct imx_mu_priv, mbox);
@@ -97,16 +118,16 @@ static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs)
return ioread32(priv->base + offs);
}
-static u32 imx_mu_xcr_rmw(struct imx_mu_priv *priv, u32 set, u32 clr)
+static u32 imx_mu_xcr_rmw(struct imx_mu_priv *priv, enum imx_mu_xcr type, u32 set, u32 clr)
{
unsigned long flags;
u32 val;
spin_lock_irqsave(&priv->xcr_lock, flags);
- val = imx_mu_read(priv, priv->dcfg->xCR);
+ val = imx_mu_read(priv, priv->dcfg->xCR[type]);
val &= ~clr;
val |= set;
- imx_mu_write(priv, val, priv->dcfg->xCR);
+ imx_mu_write(priv, val, priv->dcfg->xCR[type]);
spin_unlock_irqrestore(&priv->xcr_lock, flags);
return val;
@@ -120,11 +141,11 @@ static int imx_mu_generic_tx(struct imx_mu_priv *priv,
switch (cp->type) {
case IMX_MU_TYPE_TX:
- imx_mu_write(priv, *arg, priv->dcfg->xTR[cp->idx]);
- imx_mu_xcr_rmw(priv, IMX_MU_xCR_TIEn(cp->idx), 0);
+ imx_mu_write(priv, *arg, priv->dcfg->xTR + cp->idx * 4);
+ imx_mu_xcr_rmw(priv, IMX_MU_TCR, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx), 0);
break;
case IMX_MU_TYPE_TXDB:
- imx_mu_xcr_rmw(priv, IMX_MU_xCR_GIRn(cp->idx), 0);
+ imx_mu_xcr_rmw(priv, IMX_MU_GCR, IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx), 0);
tasklet_schedule(&cp->txdb_tasklet);
break;
default:
@@ -140,7 +161,7 @@ static int imx_mu_generic_rx(struct imx_mu_priv *priv,
{
u32 dat;
- dat = imx_mu_read(priv, priv->dcfg->xRR[cp->idx]);
+ dat = imx_mu_read(priv, priv->dcfg->xRR + (cp->idx) * 4);
mbox_chan_received_data(cp->chan, (void *)&dat);
return 0;
@@ -172,20 +193,20 @@ static int imx_mu_scu_tx(struct imx_mu_priv *priv,
}
for (i = 0; i < 4 && i < msg->hdr.size; i++)
- imx_mu_write(priv, *arg++, priv->dcfg->xTR[i % 4]);
+ imx_mu_write(priv, *arg++, priv->dcfg->xTR + (i % 4) * 4);
for (; i < msg->hdr.size; i++) {
- ret = readl_poll_timeout(priv->base + priv->dcfg->xSR,
+ ret = readl_poll_timeout(priv->base + priv->dcfg->xSR[IMX_MU_TSR],
xsr,
- xsr & IMX_MU_xSR_TEn(i % 4),
+ xsr & IMX_MU_xSR_TEn(priv->dcfg->type, i % 4),
0, 100);
if (ret) {
dev_err(priv->dev, "Send data index: %d timeout\n", i);
return ret;
}
- imx_mu_write(priv, *arg++, priv->dcfg->xTR[i % 4]);
+ imx_mu_write(priv, *arg++, priv->dcfg->xTR + (i % 4) * 4);
}
- imx_mu_xcr_rmw(priv, IMX_MU_xCR_TIEn(cp->idx), 0);
+ imx_mu_xcr_rmw(priv, IMX_MU_TCR, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx), 0);
break;
default:
dev_warn_ratelimited(priv->dev, "Send data on wrong channel type: %d\n", cp->type);
@@ -203,8 +224,8 @@ static int imx_mu_scu_rx(struct imx_mu_priv *priv,
int i, ret;
u32 xsr;
- imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_RIEn(0));
- *data++ = imx_mu_read(priv, priv->dcfg->xRR[0]);
+ imx_mu_xcr_rmw(priv, IMX_MU_RCR, 0, IMX_MU_xCR_RIEn(priv->dcfg->type, 0));
+ *data++ = imx_mu_read(priv, priv->dcfg->xRR);
if (msg.hdr.size > sizeof(msg) / 4) {
dev_err(priv->dev, "Maximal message size (%zu bytes) exceeded on RX; got: %i bytes\n", sizeof(msg), msg.hdr.size << 2);
@@ -212,16 +233,16 @@ static int imx_mu_scu_rx(struct imx_mu_priv *priv,
}
for (i = 1; i < msg.hdr.size; i++) {
- ret = readl_poll_timeout(priv->base + priv->dcfg->xSR, xsr,
- xsr & IMX_MU_xSR_RFn(i % 4), 0, 100);
+ ret = readl_poll_timeout(priv->base + priv->dcfg->xSR[IMX_MU_RSR], xsr,
+ xsr & IMX_MU_xSR_RFn(priv->dcfg->type, i % 4), 0, 100);
if (ret) {
dev_err(priv->dev, "timeout read idx %d\n", i);
return ret;
}
- *data++ = imx_mu_read(priv, priv->dcfg->xRR[i % 4]);
+ *data++ = imx_mu_read(priv, priv->dcfg->xRR + (i % 4) * 4);
}
- imx_mu_xcr_rmw(priv, IMX_MU_xCR_RIEn(0), 0);
+ imx_mu_xcr_rmw(priv, IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, 0), 0);
mbox_chan_received_data(cp->chan, (void *)&msg);
return 0;
@@ -241,36 +262,45 @@ static irqreturn_t imx_mu_isr(int irq, void *p)
struct imx_mu_con_priv *cp = chan->con_priv;
u32 val, ctrl;
- ctrl = imx_mu_read(priv, priv->dcfg->xCR);
- val = imx_mu_read(priv, priv->dcfg->xSR);
-
switch (cp->type) {
case IMX_MU_TYPE_TX:
- val &= IMX_MU_xSR_TEn(cp->idx) &
- (ctrl & IMX_MU_xCR_TIEn(cp->idx));
+ ctrl = imx_mu_read(priv, priv->dcfg->xCR[IMX_MU_TCR]);
+ val = imx_mu_read(priv, priv->dcfg->xSR[IMX_MU_TSR]);
+ val &= IMX_MU_xSR_TEn(priv->dcfg->type, cp->idx) &
+ (ctrl & IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx));
break;
case IMX_MU_TYPE_RX:
- val &= IMX_MU_xSR_RFn(cp->idx) &
- (ctrl & IMX_MU_xCR_RIEn(cp->idx));
+ ctrl = imx_mu_read(priv, priv->dcfg->xCR[IMX_MU_RCR]);
+ val = imx_mu_read(priv, priv->dcfg->xSR[IMX_MU_RSR]);
+ val &= IMX_MU_xSR_RFn(priv->dcfg->type, cp->idx) &
+ (ctrl & IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx));
break;
case IMX_MU_TYPE_RXDB:
- val &= IMX_MU_xSR_GIPn(cp->idx) &
- (ctrl & IMX_MU_xCR_GIEn(cp->idx));
+ ctrl = imx_mu_read(priv, priv->dcfg->xCR[IMX_MU_GIER]);
+ val = imx_mu_read(priv, priv->dcfg->xSR[IMX_MU_GSR]);
+ val &= IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx) &
+ (ctrl & IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx));
break;
default:
- break;
+ dev_warn_ratelimited(priv->dev, "Unhandled channel type %d\n",
+ cp->type);
+ return IRQ_NONE;
}
if (!val)
return IRQ_NONE;
- if (val == IMX_MU_xSR_TEn(cp->idx)) {
- imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_TIEn(cp->idx));
+ if ((val == IMX_MU_xSR_TEn(priv->dcfg->type, cp->idx)) &&
+ (cp->type == IMX_MU_TYPE_TX)) {
+ imx_mu_xcr_rmw(priv, IMX_MU_TCR, 0, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx));
mbox_chan_txdone(chan, 0);
- } else if (val == IMX_MU_xSR_RFn(cp->idx)) {
+ } else if ((val == IMX_MU_xSR_RFn(priv->dcfg->type, cp->idx)) &&
+ (cp->type == IMX_MU_TYPE_RX)) {
priv->dcfg->rx(priv, cp);
- } else if (val == IMX_MU_xSR_GIPn(cp->idx)) {
- imx_mu_write(priv, IMX_MU_xSR_GIPn(cp->idx), priv->dcfg->xSR);
+ } else if ((val == IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx)) &&
+ (cp->type == IMX_MU_TYPE_RXDB)) {
+ imx_mu_write(priv, IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx),
+ priv->dcfg->xSR[IMX_MU_GSR]);
mbox_chan_received_data(chan, NULL);
} else {
dev_warn_ratelimited(priv->dev, "Not handled interrupt\n");
@@ -317,10 +347,10 @@ static int imx_mu_startup(struct mbox_chan *chan)
switch (cp->type) {
case IMX_MU_TYPE_RX:
- imx_mu_xcr_rmw(priv, IMX_MU_xCR_RIEn(cp->idx), 0);
+ imx_mu_xcr_rmw(priv, IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx), 0);
break;
case IMX_MU_TYPE_RXDB:
- imx_mu_xcr_rmw(priv, IMX_MU_xCR_GIEn(cp->idx), 0);
+ imx_mu_xcr_rmw(priv, IMX_MU_GIER, IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx), 0);
break;
default:
break;
@@ -342,13 +372,13 @@ static void imx_mu_shutdown(struct mbox_chan *chan)
switch (cp->type) {
case IMX_MU_TYPE_TX:
- imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_TIEn(cp->idx));
+ imx_mu_xcr_rmw(priv, IMX_MU_TCR, 0, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx));
break;
case IMX_MU_TYPE_RX:
- imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_RIEn(cp->idx));
+ imx_mu_xcr_rmw(priv, IMX_MU_RCR, 0, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx));
break;
case IMX_MU_TYPE_RXDB:
- imx_mu_xcr_rmw(priv, 0, IMX_MU_xCR_GIEn(cp->idx));
+ imx_mu_xcr_rmw(priv, IMX_MU_GIER, 0, IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx));
break;
default:
break;
@@ -444,7 +474,8 @@ static void imx_mu_init_generic(struct imx_mu_priv *priv)
return;
/* Set default MU configuration */
- imx_mu_write(priv, 0, priv->dcfg->xCR);
+ for (i = 0; i < IMX_MU_xCR_MAX; i++)
+ imx_mu_write(priv, 0, priv->dcfg->xCR[i]);
}
static void imx_mu_init_scu(struct imx_mu_priv *priv)
@@ -466,7 +497,8 @@ static void imx_mu_init_scu(struct imx_mu_priv *priv)
priv->mbox.of_xlate = imx_mu_scu_xlate;
/* Set default MU configuration */
- imx_mu_write(priv, 0, priv->dcfg->xCR);
+ for (i = 0; i < IMX_MU_xCR_MAX; i++)
+ imx_mu_write(priv, 0, priv->dcfg->xCR[i]);
}
static int imx_mu_probe(struct platform_device *pdev)
@@ -564,35 +596,47 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx6sx = {
.tx = imx_mu_generic_tx,
.rx = imx_mu_generic_rx,
.init = imx_mu_init_generic,
- .xTR = {0x0, 0x4, 0x8, 0xc},
- .xRR = {0x10, 0x14, 0x18, 0x1c},
- .xSR = 0x20,
- .xCR = 0x24,
+ .xTR = 0x0,
+ .xRR = 0x10,
+ .xSR = {0x20, 0x20, 0x20, 0x20},
+ .xCR = {0x24, 0x24, 0x24, 0x24},
};
static const struct imx_mu_dcfg imx_mu_cfg_imx7ulp = {
.tx = imx_mu_generic_tx,
.rx = imx_mu_generic_rx,
.init = imx_mu_init_generic,
- .xTR = {0x20, 0x24, 0x28, 0x2c},
- .xRR = {0x40, 0x44, 0x48, 0x4c},
- .xSR = 0x60,
- .xCR = 0x64,
+ .xTR = 0x20,
+ .xRR = 0x40,
+ .xSR = {0x60, 0x60, 0x60, 0x60},
+ .xCR = {0x64, 0x64, 0x64, 0x64},
+};
+
+static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = {
+ .tx = imx_mu_generic_tx,
+ .rx = imx_mu_generic_rx,
+ .init = imx_mu_init_generic,
+ .type = IMX_MU_V2,
+ .xTR = 0x200,
+ .xRR = 0x280,
+ .xSR = {0xC, 0x118, 0x124, 0x12C},
+ .xCR = {0x110, 0x114, 0x120, 0x128},
};
static const struct imx_mu_dcfg imx_mu_cfg_imx8_scu = {
.tx = imx_mu_scu_tx,
.rx = imx_mu_scu_rx,
.init = imx_mu_init_scu,
- .xTR = {0x0, 0x4, 0x8, 0xc},
- .xRR = {0x10, 0x14, 0x18, 0x1c},
- .xSR = 0x20,
- .xCR = 0x24,
+ .xTR = 0x0,
+ .xRR = 0x10,
+ .xSR = {0x20, 0x20, 0x20, 0x20},
+ .xCR = {0x24, 0x24, 0x24, 0x24},
};
static const struct of_device_id imx_mu_dt_ids[] = {
{ .compatible = "fsl,imx7ulp-mu", .data = &imx_mu_cfg_imx7ulp },
{ .compatible = "fsl,imx6sx-mu", .data = &imx_mu_cfg_imx6sx },
+ { .compatible = "fsl,imx8ulp-mu", .data = &imx_mu_cfg_imx8ulp },
{ .compatible = "fsl,imx8-mu-scu", .data = &imx_mu_cfg_imx8_scu },
{ },
};
@@ -601,9 +645,12 @@ MODULE_DEVICE_TABLE(of, imx_mu_dt_ids);
static int __maybe_unused imx_mu_suspend_noirq(struct device *dev)
{
struct imx_mu_priv *priv = dev_get_drvdata(dev);
+ int i;
- if (!priv->clk)
- priv->xcr = imx_mu_read(priv, priv->dcfg->xCR);
+ if (!priv->clk) {
+ for (i = 0; i < IMX_MU_xCR_MAX; i++)
+ priv->xcr[i] = imx_mu_read(priv, priv->dcfg->xCR[i]);
+ }
return 0;
}
@@ -611,6 +658,7 @@ static int __maybe_unused imx_mu_suspend_noirq(struct device *dev)
static int __maybe_unused imx_mu_resume_noirq(struct device *dev)
{
struct imx_mu_priv *priv = dev_get_drvdata(dev);
+ int i;
/*
* ONLY restore MU when context lost, the TIE could
@@ -620,8 +668,10 @@ static int __maybe_unused imx_mu_resume_noirq(struct device *dev)
* send failed, may lead to system freeze. This issue
* is observed by testing freeze mode suspend.
*/
- if (!imx_mu_read(priv, priv->dcfg->xCR) && !priv->clk)
- imx_mu_write(priv, priv->xcr, priv->dcfg->xCR);
+ if (!imx_mu_read(priv, priv->dcfg->xCR[0]) && !priv->clk) {
+ for (i = 0; i < IMX_MU_xCR_MAX; i++)
+ imx_mu_write(priv, priv->xcr[i], priv->dcfg->xCR[i]);
+ }
return 0;
}
diff --git a/drivers/mailbox/mailbox-mpfs.c b/drivers/mailbox/mailbox-mpfs.c
new file mode 100644
index 000000000000..0d6e2231a2c7
--- /dev/null
+++ b/drivers/mailbox/mailbox-mpfs.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip PolarFire SoC (MPFS) system controller/mailbox controller driver
+ *
+ * Copyright (c) 2020 Microchip Corporation. All rights reserved.
+ *
+ * Author: Conor Dooley <conor.dooley@microchip.com>
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mailbox_controller.h>
+#include <soc/microchip/mpfs.h>
+
+#define SERVICES_CR_OFFSET 0x50u
+#define SERVICES_SR_OFFSET 0x54u
+#define MAILBOX_REG_OFFSET 0x800u
+#define MSS_SYS_MAILBOX_DATA_OFFSET 0u
+#define SCB_MASK_WIDTH 16u
+
+/* SCBCTRL service control register */
+
+#define SCB_CTRL_REQ (0)
+#define SCB_CTRL_REQ_MASK BIT(SCB_CTRL_REQ)
+
+#define SCB_CTRL_BUSY (1)
+#define SCB_CTRL_BUSY_MASK BIT(SCB_CTRL_BUSY)
+
+#define SCB_CTRL_ABORT (2)
+#define SCB_CTRL_ABORT_MASK BIT(SCB_CTRL_ABORT)
+
+#define SCB_CTRL_NOTIFY (3)
+#define SCB_CTRL_NOTIFY_MASK BIT(SCB_CTRL_NOTIFY)
+
+#define SCB_CTRL_POS (16)
+#define SCB_CTRL_MASK GENMASK_ULL(SCB_CTRL_POS + SCB_MASK_WIDTH, SCB_CTRL_POS)
+
+/* SCBCTRL service status register */
+
+#define SCB_STATUS_REQ (0)
+#define SCB_STATUS_REQ_MASK BIT(SCB_STATUS_REQ)
+
+#define SCB_STATUS_BUSY (1)
+#define SCB_STATUS_BUSY_MASK BIT(SCB_STATUS_BUSY)
+
+#define SCB_STATUS_ABORT (2)
+#define SCB_STATUS_ABORT_MASK BIT(SCB_STATUS_ABORT)
+
+#define SCB_STATUS_NOTIFY (3)
+#define SCB_STATUS_NOTIFY_MASK BIT(SCB_STATUS_NOTIFY)
+
+#define SCB_STATUS_POS (16)
+#define SCB_STATUS_MASK GENMASK_ULL(SCB_STATUS_POS + SCB_MASK_WIDTH, SCB_STATUS_POS)
+
+struct mpfs_mbox {
+ struct mbox_controller controller;
+ struct device *dev;
+ int irq;
+ void __iomem *mbox_base;
+ void __iomem *int_reg;
+ struct mbox_chan chans[1];
+ struct mpfs_mss_response *response;
+ u16 resp_offset;
+};
+
+static bool mpfs_mbox_busy(struct mpfs_mbox *mbox)
+{
+ u32 status;
+
+ status = readl_relaxed(mbox->mbox_base + SERVICES_SR_OFFSET);
+
+ return status & SCB_STATUS_BUSY_MASK;
+}
+
+static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data)
+{
+ struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
+ struct mpfs_mss_msg *msg = data;
+ u32 tx_trigger;
+ u16 opt_sel;
+ u32 val = 0u;
+
+ mbox->response = msg->response;
+ mbox->resp_offset = msg->resp_offset;
+
+ if (mpfs_mbox_busy(mbox))
+ return -EBUSY;
+
+ if (msg->cmd_data_size) {
+ u32 index;
+ u8 extra_bits = msg->cmd_data_size & 3;
+ u32 *word_buf = (u32 *)msg->cmd_data;
+
+ for (index = 0; index < (msg->cmd_data_size / 4); index++)
+ writel_relaxed(word_buf[index],
+ mbox->mbox_base + MAILBOX_REG_OFFSET + index * 0x4);
+ if (extra_bits) {
+ u8 i;
+ u8 byte_off = ALIGN_DOWN(msg->cmd_data_size, 4);
+ u8 *byte_buf = msg->cmd_data + byte_off;
+
+ val = readl_relaxed(mbox->mbox_base +
+ MAILBOX_REG_OFFSET + index * 0x4);
+
+ for (i = 0u; i < extra_bits; i++) {
+ val &= ~(0xffu << (i * 8u));
+ val |= (byte_buf[i] << (i * 8u));
+ }
+
+ writel_relaxed(val,
+ mbox->mbox_base + MAILBOX_REG_OFFSET + index * 0x4);
+ }
+ }
+
+ opt_sel = ((msg->mbox_offset << 7u) | (msg->cmd_opcode & 0x7fu));
+ tx_trigger = (opt_sel << SCB_CTRL_POS) & SCB_CTRL_MASK;
+ tx_trigger |= SCB_CTRL_REQ_MASK | SCB_STATUS_NOTIFY_MASK;
+ writel_relaxed(tx_trigger, mbox->mbox_base + SERVICES_CR_OFFSET);
+
+ return 0;
+}
+
+static void mpfs_mbox_rx_data(struct mbox_chan *chan)
+{
+ struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
+ struct mpfs_mss_response *response = mbox->response;
+ u16 num_words = ALIGN((response->resp_size), (4)) / 4U;
+ u32 i;
+
+ if (!response->resp_msg) {
+ dev_err(mbox->dev, "failed to assign memory for response %d\n", -ENOMEM);
+ return;
+ }
+
+ if (!mpfs_mbox_busy(mbox)) {
+ for (i = 0; i < num_words; i++) {
+ response->resp_msg[i] =
+ readl_relaxed(mbox->mbox_base + MAILBOX_REG_OFFSET
+ + mbox->resp_offset + i * 0x4);
+ }
+ }
+
+ mbox_chan_received_data(chan, response);
+}
+
+static irqreturn_t mpfs_mbox_inbox_isr(int irq, void *data)
+{
+ struct mbox_chan *chan = data;
+ struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
+
+ writel_relaxed(0, mbox->int_reg);
+
+ mpfs_mbox_rx_data(chan);
+
+ mbox_chan_txdone(chan, 0);
+ return IRQ_HANDLED;
+}
+
+static int mpfs_mbox_startup(struct mbox_chan *chan)
+{
+ struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
+ int ret = 0;
+
+ if (!mbox)
+ return -EINVAL;
+
+ ret = devm_request_irq(mbox->dev, mbox->irq, mpfs_mbox_inbox_isr, 0, "mpfs-mailbox", chan);
+ if (ret)
+ dev_err(mbox->dev, "failed to register mailbox interrupt:%d\n", ret);
+
+ return ret;
+}
+
+static void mpfs_mbox_shutdown(struct mbox_chan *chan)
+{
+ struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv;
+
+ devm_free_irq(mbox->dev, mbox->irq, chan);
+}
+
+static const struct mbox_chan_ops mpfs_mbox_ops = {
+ .send_data = mpfs_mbox_send_data,
+ .startup = mpfs_mbox_startup,
+ .shutdown = mpfs_mbox_shutdown,
+};
+
+static int mpfs_mbox_probe(struct platform_device *pdev)
+{
+ struct mpfs_mbox *mbox;
+ struct resource *regs;
+ int ret;
+
+ mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
+ if (!mbox)
+ return -ENOMEM;
+
+ mbox->mbox_base = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
+ if (IS_ERR(mbox->mbox_base))
+ return PTR_ERR(mbox->mbox_base);
+
+ mbox->int_reg = devm_platform_get_and_ioremap_resource(pdev, 1, &regs);
+ if (IS_ERR(mbox->int_reg))
+ return PTR_ERR(mbox->int_reg);
+
+ mbox->irq = platform_get_irq(pdev, 0);
+ if (mbox->irq < 0)
+ return mbox->irq;
+
+ mbox->dev = &pdev->dev;
+
+ mbox->chans[0].con_priv = mbox;
+ mbox->controller.dev = mbox->dev;
+ mbox->controller.num_chans = 1;
+ mbox->controller.chans = mbox->chans;
+ mbox->controller.ops = &mpfs_mbox_ops;
+ mbox->controller.txdone_irq = true;
+
+ ret = devm_mbox_controller_register(&pdev->dev, &mbox->controller);
+ if (ret) {
+ dev_err(&pdev->dev, "Registering MPFS mailbox controller failed\n");
+ return ret;
+ }
+ dev_info(&pdev->dev, "Registered MPFS mailbox controller driver\n");
+
+ return 0;
+}
+
+static const struct of_device_id mpfs_mbox_of_match[] = {
+ {.compatible = "microchip,polarfire-soc-mailbox", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mpfs_mbox_of_match);
+
+static struct platform_driver mpfs_mbox_driver = {
+ .driver = {
+ .name = "mpfs-mailbox",
+ .of_match_table = mpfs_mbox_of_match,
+ },
+ .probe = mpfs_mbox_probe,
+};
+module_platform_driver(mpfs_mbox_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
+MODULE_DESCRIPTION("MPFS mailbox controller driver");
diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c
index 5665b6ea8119..67a42b514429 100644
--- a/drivers/mailbox/mtk-cmdq-mailbox.c
+++ b/drivers/mailbox/mtk-cmdq-mailbox.c
@@ -180,7 +180,7 @@ static bool cmdq_thread_is_in_wfe(struct cmdq_thread *thread)
return readl(thread->base + CMDQ_THR_WAIT_TOKEN) & CMDQ_THR_IS_WAITING;
}
-static void cmdq_task_exec_done(struct cmdq_task *task, enum cmdq_cb_status sta)
+static void cmdq_task_exec_done(struct cmdq_task *task, int sta)
{
struct cmdq_task_cb *cb = &task->pkt->async_cb;
struct cmdq_cb_data data;
@@ -188,7 +188,11 @@ static void cmdq_task_exec_done(struct cmdq_task *task, enum cmdq_cb_status sta)
WARN_ON(cb->cb == (cmdq_async_flush_cb)NULL);
data.sta = sta;
data.data = cb->data;
- cb->cb(data);
+ data.pkt = task->pkt;
+ if (cb->cb)
+ cb->cb(data);
+
+ mbox_chan_received_data(task->thread->chan, &data);
list_del(&task->list_entry);
}
@@ -244,10 +248,10 @@ static void cmdq_thread_irq_handler(struct cmdq *cmdq,
curr_task = task;
if (!curr_task || curr_pa == task_end_pa - CMDQ_INST_SIZE) {
- cmdq_task_exec_done(task, CMDQ_CB_NORMAL);
+ cmdq_task_exec_done(task, 0);
kfree(task);
} else if (err) {
- cmdq_task_exec_done(task, CMDQ_CB_ERROR);
+ cmdq_task_exec_done(task, -ENOEXEC);
cmdq_task_handle_error(curr_task);
kfree(task);
}
@@ -415,7 +419,7 @@ static void cmdq_mbox_shutdown(struct mbox_chan *chan)
list_for_each_entry_safe(task, tmp, &thread->task_busy_list,
list_entry) {
- cmdq_task_exec_done(task, CMDQ_CB_ERROR);
+ cmdq_task_exec_done(task, -ECONNABORTED);
kfree(task);
}
@@ -452,11 +456,13 @@ static int cmdq_mbox_flush(struct mbox_chan *chan, unsigned long timeout)
list_for_each_entry_safe(task, tmp, &thread->task_busy_list,
list_entry) {
cb = &task->pkt->async_cb;
- if (cb->cb) {
- data.sta = CMDQ_CB_ERROR;
- data.data = cb->data;
+ data.sta = -ECONNABORTED;
+ data.data = cb->data;
+ data.pkt = task->pkt;
+ if (cb->cb)
cb->cb(data);
- }
+
+ mbox_chan_received_data(task->thread->chan, &data);
list_del(&task->list_entry);
kfree(task);
}
@@ -519,10 +525,8 @@ static int cmdq_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
cmdq->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(cmdq->base)) {
- dev_err(dev, "failed to ioremap gce\n");
+ if (IS_ERR(cmdq->base))
return PTR_ERR(cmdq->base);
- }
cmdq->irq = platform_get_irq(pdev, 0);
if (cmdq->irq < 0)
diff --git a/drivers/mailbox/qcom-apcs-ipc-mailbox.c b/drivers/mailbox/qcom-apcs-ipc-mailbox.c
index f25324d03842..03bdc96dc457 100644
--- a/drivers/mailbox/qcom-apcs-ipc-mailbox.c
+++ b/drivers/mailbox/qcom-apcs-ipc-mailbox.c
@@ -57,6 +57,10 @@ static const struct qcom_apcs_ipc_data sdm660_apcs_data = {
.offset = 8, .clk_name = NULL
};
+static const struct qcom_apcs_ipc_data sm6125_apcs_data = {
+ .offset = 8, .clk_name = NULL
+};
+
static const struct qcom_apcs_ipc_data apps_shared_apcs_data = {
.offset = 12, .clk_name = NULL
};
@@ -132,7 +136,7 @@ static int qcom_apcs_ipc_probe(struct platform_device *pdev)
if (apcs_data->clk_name) {
apcs->clk = platform_device_register_data(&pdev->dev,
apcs_data->clk_name,
- PLATFORM_DEVID_NONE,
+ PLATFORM_DEVID_AUTO,
NULL, 0);
if (IS_ERR(apcs->clk))
dev_err(&pdev->dev, "failed to register APCS clk\n");
@@ -158,6 +162,7 @@ static const struct of_device_id qcom_apcs_ipc_of_match[] = {
{ .compatible = "qcom,ipq6018-apcs-apps-global", .data = &ipq6018_apcs_data },
{ .compatible = "qcom,ipq8074-apcs-apps-global", .data = &ipq8074_apcs_data },
{ .compatible = "qcom,msm8916-apcs-kpss-global", .data = &msm8916_apcs_data },
+ { .compatible = "qcom,msm8939-apcs-kpss-global", .data = &msm8916_apcs_data },
{ .compatible = "qcom,msm8994-apcs-kpss-global", .data = &msm8994_apcs_data },
{ .compatible = "qcom,msm8996-apcs-hmss-global", .data = &msm8996_apcs_data },
{ .compatible = "qcom,msm8998-apcs-hmss-global", .data = &msm8998_apcs_data },
@@ -166,6 +171,7 @@ static const struct of_device_id qcom_apcs_ipc_of_match[] = {
{ .compatible = "qcom,sc8180x-apss-shared", .data = &apps_shared_apcs_data },
{ .compatible = "qcom,sdm660-apcs-hmss-global", .data = &sdm660_apcs_data },
{ .compatible = "qcom,sdm845-apss-shared", .data = &apps_shared_apcs_data },
+ { .compatible = "qcom,sm6125-apcs-hmss-global", .data = &sm6125_apcs_data },
{ .compatible = "qcom,sm8150-apss-shared", .data = &apps_shared_apcs_data },
{ .compatible = "qcom,sdx55-apcs-gcc", .data = &sdx55_apcs_data },
{}
diff --git a/drivers/mailbox/qcom-ipcc.c b/drivers/mailbox/qcom-ipcc.c
index 2d13c72944c6..584700cd1585 100644
--- a/drivers/mailbox/qcom-ipcc.c
+++ b/drivers/mailbox/qcom-ipcc.c
@@ -155,6 +155,11 @@ static int qcom_ipcc_mbox_send_data(struct mbox_chan *chan, void *data)
return 0;
}
+static void qcom_ipcc_mbox_shutdown(struct mbox_chan *chan)
+{
+ chan->con_priv = NULL;
+}
+
static struct mbox_chan *qcom_ipcc_mbox_xlate(struct mbox_controller *mbox,
const struct of_phandle_args *ph)
{
@@ -184,6 +189,7 @@ static struct mbox_chan *qcom_ipcc_mbox_xlate(struct mbox_controller *mbox,
static const struct mbox_chan_ops ipcc_mbox_chan_ops = {
.send_data = qcom_ipcc_mbox_send_data,
+ .shutdown = qcom_ipcc_mbox_shutdown,
};
static int qcom_ipcc_setup_mbox(struct qcom_ipcc *ipcc)
diff --git a/drivers/mcb/mcb-lpc.c b/drivers/mcb/mcb-lpc.c
index 506676754538..53decd89876e 100644
--- a/drivers/mcb/mcb-lpc.c
+++ b/drivers/mcb/mcb-lpc.c
@@ -105,17 +105,8 @@ out_put:
return ret;
}
-static struct resource sc24_fpga_resource = {
- .start = 0xe000e000,
- .end = 0xe000e000 + CHAM_HEADER_SIZE,
- .flags = IORESOURCE_MEM,
-};
-
-static struct resource sc31_fpga_resource = {
- .start = 0xf000e000,
- .end = 0xf000e000 + CHAM_HEADER_SIZE,
- .flags = IORESOURCE_MEM,
-};
+static struct resource sc24_fpga_resource = DEFINE_RES_MEM(0xe000e000, CHAM_HEADER_SIZE);
+static struct resource sc31_fpga_resource = DEFINE_RES_MEM(0xf000e000, CHAM_HEADER_SIZE);
static struct platform_driver mcb_lpc_driver = {
.driver = {
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index f2014385d48b..0602e82a9516 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -47,7 +47,7 @@ config MD_AUTODETECT
If unsure, say Y.
config MD_LINEAR
- tristate "Linear (append) mode"
+ tristate "Linear (append) mode (deprecated)"
depends on BLK_DEV_MD
help
If you say Y here, then your multiple devices driver will be able to
@@ -158,7 +158,7 @@ config MD_RAID456
If unsure, say Y.
config MD_MULTIPATH
- tristate "Multipath I/O support"
+ tristate "Multipath I/O support (deprecated)"
depends on BLK_DEV_MD
help
MD_MULTIPATH provides a simple multi-path personality for use
@@ -169,7 +169,7 @@ config MD_MULTIPATH
If unsure, say N.
config MD_FAULTY
- tristate "Faulty test module for MD"
+ tristate "Faulty test module for MD (deprecated)"
depends on BLK_DEV_MD
help
The "faulty" module allows for a block device that occasionally returns
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index ef7ddc27685c..a74aaf8b1445 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -92,6 +92,10 @@ ifeq ($(CONFIG_DM_UEVENT),y)
dm-mod-objs += dm-uevent.o
endif
+ifeq ($(CONFIG_BLK_DEV_ZONED),y)
+dm-mod-objs += dm-zone.o
+endif
+
ifeq ($(CONFIG_DM_VERITY_FEC),y)
dm-verity-objs += dm-verity-fec.o
endif
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index bea8c4429ae8..185246a0d855 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -890,13 +890,9 @@ static void bcache_device_free(struct bcache_device *d)
if (disk_added)
del_gendisk(disk);
- if (disk->queue)
- blk_cleanup_queue(disk->queue);
-
+ blk_cleanup_disk(disk);
ida_simple_remove(&bcache_device_idx,
first_minor_to_idx(disk->first_minor));
- if (disk_added)
- put_disk(disk);
}
bioset_exit(&d->bio_split);
@@ -946,7 +942,7 @@ static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
BIOSET_NEED_BVECS|BIOSET_NEED_RESCUER))
goto err;
- d->disk = alloc_disk(BCACHE_MINORS);
+ d->disk = blk_alloc_disk(NUMA_NO_NODE);
if (!d->disk)
goto err;
@@ -955,14 +951,11 @@ static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
d->disk->major = bcache_major;
d->disk->first_minor = idx_to_first_minor(idx);
+ d->disk->minors = BCACHE_MINORS;
d->disk->fops = ops;
d->disk->private_data = d;
- q = blk_alloc_queue(NUMA_NO_NODE);
- if (!q)
- return -ENOMEM;
-
- d->disk->queue = q;
+ q = d->disk->queue;
q->limits.max_hw_sectors = UINT_MAX;
q->limits.max_sectors = UINT_MAX;
q->limits.max_segment_size = UINT_MAX;
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index 6ab01ff25747..8e4ced5a2516 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -8,6 +8,7 @@
#include "dm-bio-prison-v2.h"
#include "dm-bio-record.h"
#include "dm-cache-metadata.h"
+#include "dm-io-tracker.h"
#include <linux/dm-io.h>
#include <linux/dm-kcopyd.h>
@@ -39,77 +40,6 @@ DECLARE_DM_KCOPYD_THROTTLE_WITH_MODULE_PARM(cache_copy_throttle,
/*----------------------------------------------------------------*/
-struct io_tracker {
- spinlock_t lock;
-
- /*
- * Sectors of in-flight IO.
- */
- sector_t in_flight;
-
- /*
- * The time, in jiffies, when this device became idle (if it is
- * indeed idle).
- */
- unsigned long idle_time;
- unsigned long last_update_time;
-};
-
-static void iot_init(struct io_tracker *iot)
-{
- spin_lock_init(&iot->lock);
- iot->in_flight = 0ul;
- iot->idle_time = 0ul;
- iot->last_update_time = jiffies;
-}
-
-static bool __iot_idle_for(struct io_tracker *iot, unsigned long jifs)
-{
- if (iot->in_flight)
- return false;
-
- return time_after(jiffies, iot->idle_time + jifs);
-}
-
-static bool iot_idle_for(struct io_tracker *iot, unsigned long jifs)
-{
- bool r;
-
- spin_lock_irq(&iot->lock);
- r = __iot_idle_for(iot, jifs);
- spin_unlock_irq(&iot->lock);
-
- return r;
-}
-
-static void iot_io_begin(struct io_tracker *iot, sector_t len)
-{
- spin_lock_irq(&iot->lock);
- iot->in_flight += len;
- spin_unlock_irq(&iot->lock);
-}
-
-static void __iot_io_end(struct io_tracker *iot, sector_t len)
-{
- if (!len)
- return;
-
- iot->in_flight -= len;
- if (!iot->in_flight)
- iot->idle_time = jiffies;
-}
-
-static void iot_io_end(struct io_tracker *iot, sector_t len)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&iot->lock, flags);
- __iot_io_end(iot, len);
- spin_unlock_irqrestore(&iot->lock, flags);
-}
-
-/*----------------------------------------------------------------*/
-
/*
* Represents a chunk of future work. 'input' allows continuations to pass
* values between themselves, typically error values.
@@ -470,7 +400,7 @@ struct cache {
struct batcher committer;
struct work_struct commit_ws;
- struct io_tracker tracker;
+ struct dm_io_tracker tracker;
mempool_t migration_pool;
@@ -866,7 +796,7 @@ static void accounted_begin(struct cache *cache, struct bio *bio)
if (accountable_bio(cache, bio)) {
pb = get_per_bio_data(bio);
pb->len = bio_sectors(bio);
- iot_io_begin(&cache->tracker, pb->len);
+ dm_iot_io_begin(&cache->tracker, pb->len);
}
}
@@ -874,7 +804,7 @@ static void accounted_complete(struct cache *cache, struct bio *bio)
{
struct per_bio_data *pb = get_per_bio_data(bio);
- iot_io_end(&cache->tracker, pb->len);
+ dm_iot_io_end(&cache->tracker, pb->len);
}
static void accounted_request(struct cache *cache, struct bio *bio)
@@ -1642,7 +1572,7 @@ enum busy {
static enum busy spare_migration_bandwidth(struct cache *cache)
{
- bool idle = iot_idle_for(&cache->tracker, HZ);
+ bool idle = dm_iot_idle_for(&cache->tracker, HZ);
sector_t current_volume = (atomic_read(&cache->nr_io_migrations) + 1) *
cache->sectors_per_block;
@@ -2603,7 +2533,7 @@ static int cache_create(struct cache_args *ca, struct cache **result)
batcher_init(&cache->committer, commit_op, cache,
issue_op, cache, cache->wq);
- iot_init(&cache->tracker);
+ dm_iot_init(&cache->tracker);
init_rwsem(&cache->background_work_lock);
prevent_background_work(cache);
diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h
index 5953ff2bd260..edc1553c4eea 100644
--- a/drivers/md/dm-core.h
+++ b/drivers/md/dm-core.h
@@ -114,8 +114,27 @@ struct mapped_device {
bool init_tio_pdu:1;
struct srcu_struct io_barrier;
+
+#ifdef CONFIG_BLK_DEV_ZONED
+ unsigned int nr_zones;
+ unsigned int *zwp_offset;
+#endif
};
+/*
+ * Bits for the flags field of struct mapped_device.
+ */
+#define DMF_BLOCK_IO_FOR_SUSPEND 0
+#define DMF_SUSPENDED 1
+#define DMF_FROZEN 2
+#define DMF_FREEING 3
+#define DMF_DELETING 4
+#define DMF_NOFLUSH_SUSPENDING 5
+#define DMF_DEFERRED_REMOVE 6
+#define DMF_SUSPENDED_INTERNALLY 7
+#define DMF_POST_SUSPENDING 8
+#define DMF_EMULATE_ZONE_APPEND 9
+
void disable_discard(struct mapped_device *md);
void disable_write_same(struct mapped_device *md);
void disable_write_zeroes(struct mapped_device *md);
@@ -130,6 +149,13 @@ static inline struct dm_stats *dm_get_stats(struct mapped_device *md)
return &md->stats;
}
+static inline bool dm_emulate_zone_append(struct mapped_device *md)
+{
+ if (blk_queue_is_zoned(md->queue))
+ return test_bit(DMF_EMULATE_ZONE_APPEND, &md->flags);
+ return false;
+}
+
#define DM_TABLE_MAX_DEPTH 16
struct dm_table {
@@ -173,6 +199,45 @@ struct dm_table {
#endif
};
+/*
+ * One of these is allocated per clone bio.
+ */
+#define DM_TIO_MAGIC 7282014
+struct dm_target_io {
+ unsigned int magic;
+ struct dm_io *io;
+ struct dm_target *ti;
+ unsigned int target_bio_nr;
+ unsigned int *len_ptr;
+ bool inside_dm_io;
+ struct bio clone;
+};
+
+/*
+ * One of these is allocated per original bio.
+ * It contains the first clone used for that original.
+ */
+#define DM_IO_MAGIC 5191977
+struct dm_io {
+ unsigned int magic;
+ struct mapped_device *md;
+ blk_status_t status;
+ atomic_t io_count;
+ struct bio *orig_bio;
+ unsigned long start_time;
+ spinlock_t endio_lock;
+ struct dm_stats_aux stats_aux;
+ /* last member of dm_target_io is 'struct bio' */
+ struct dm_target_io tio;
+};
+
+static inline void dm_io_inc_pending(struct dm_io *io)
+{
+ atomic_inc(&io->io_count);
+}
+
+void dm_io_dec_pending(struct dm_io *io, blk_status_t error);
+
static inline struct completion *dm_get_completion_from_kobject(struct kobject *kobj)
{
return &container_of(kobj, struct dm_kobject_holder, kobj)->completion;
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index b0ab080f2567..50f4cbd600d5 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -3138,11 +3138,10 @@ static int crypt_report_zones(struct dm_target *ti,
struct dm_report_zones_args *args, unsigned int nr_zones)
{
struct crypt_config *cc = ti->private;
- sector_t sector = cc->start + dm_target_offset(ti, args->next_sector);
- args->start = cc->start;
- return blkdev_report_zones(cc->dev->bdev, sector, nr_zones,
- dm_report_zones_cb, args);
+ return dm_report_zones(cc->dev->bdev, cc->start,
+ cc->start + dm_target_offset(ti, args->next_sector),
+ args, nr_zones);
}
#else
#define crypt_report_zones NULL
@@ -3281,14 +3280,28 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
cc->start = tmpll;
- /*
- * For zoned block devices, we need to preserve the issuer write
- * ordering. To do so, disable write workqueues and force inline
- * encryption completion.
- */
if (bdev_is_zoned(cc->dev->bdev)) {
+ /*
+ * For zoned block devices, we need to preserve the issuer write
+ * ordering. To do so, disable write workqueues and force inline
+ * encryption completion.
+ */
set_bit(DM_CRYPT_NO_WRITE_WORKQUEUE, &cc->flags);
set_bit(DM_CRYPT_WRITE_INLINE, &cc->flags);
+
+ /*
+ * All zone append writes to a zone of a zoned block device will
+ * have the same BIO sector, the start of the zone. When the
+ * cypher IV mode uses sector values, all data targeting a
+ * zone will be encrypted using the first sector numbers of the
+ * zone. This will not result in write errors but will
+ * cause most reads to fail as reads will use the sector values
+ * for the actual data locations, resulting in IV mismatch.
+ * To avoid this problem, ask DM core to emulate zone append
+ * operations with regular writes.
+ */
+ DMDEBUG("Zone append operations will be emulated");
+ ti->emulate_zone_append = true;
}
if (crypt_integrity_aead(cc) || cc->integrity_iv_size) {
diff --git a/drivers/md/dm-era-target.c b/drivers/md/dm-era-target.c
index d9ac7372108c..3b748393fca5 100644
--- a/drivers/md/dm-era-target.c
+++ b/drivers/md/dm-era-target.c
@@ -363,28 +363,32 @@ static void ws_unpack(const struct writeset_disk *disk, struct writeset_metadata
core->root = le64_to_cpu(disk->root);
}
-static void ws_inc(void *context, const void *value)
+static void ws_inc(void *context, const void *value, unsigned count)
{
struct era_metadata *md = context;
struct writeset_disk ws_d;
dm_block_t b;
+ unsigned i;
- memcpy(&ws_d, value, sizeof(ws_d));
- b = le64_to_cpu(ws_d.root);
-
- dm_tm_inc(md->tm, b);
+ for (i = 0; i < count; i++) {
+ memcpy(&ws_d, value + (i * sizeof(ws_d)), sizeof(ws_d));
+ b = le64_to_cpu(ws_d.root);
+ dm_tm_inc(md->tm, b);
+ }
}
-static void ws_dec(void *context, const void *value)
+static void ws_dec(void *context, const void *value, unsigned count)
{
struct era_metadata *md = context;
struct writeset_disk ws_d;
dm_block_t b;
+ unsigned i;
- memcpy(&ws_d, value, sizeof(ws_d));
- b = le64_to_cpu(ws_d.root);
-
- dm_bitset_del(&md->bitset_info, b);
+ for (i = 0; i < count; i++) {
+ memcpy(&ws_d, value + (i * sizeof(ws_d)), sizeof(ws_d));
+ b = le64_to_cpu(ws_d.root);
+ dm_bitset_del(&md->bitset_info, b);
+ }
}
static int ws_eq(void *context, const void *value1, const void *value2)
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index b7fee9936f05..5877220c01ed 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -463,11 +463,10 @@ static int flakey_report_zones(struct dm_target *ti,
struct dm_report_zones_args *args, unsigned int nr_zones)
{
struct flakey_c *fc = ti->private;
- sector_t sector = flakey_map_sector(ti, args->next_sector);
- args->start = fc->start;
- return blkdev_report_zones(fc->dev->bdev, sector, nr_zones,
- dm_report_zones_cb, args);
+ return dm_report_zones(fc->dev->bdev, fc->start,
+ flakey_map_sector(ti, args->next_sector),
+ args, nr_zones);
}
#else
#define flakey_report_zones NULL
diff --git a/drivers/md/dm-io-tracker.h b/drivers/md/dm-io-tracker.h
new file mode 100644
index 000000000000..bdcc6273ebf0
--- /dev/null
+++ b/drivers/md/dm-io-tracker.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2021 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef DM_IO_TRACKER_H
+#define DM_IO_TRACKER_H
+
+#include <linux/jiffies.h>
+
+struct dm_io_tracker {
+ spinlock_t lock;
+
+ /*
+ * Sectors of in-flight IO.
+ */
+ sector_t in_flight;
+
+ /*
+ * The time, in jiffies, when this device became idle
+ * (if it is indeed idle).
+ */
+ unsigned long idle_time;
+ unsigned long last_update_time;
+};
+
+static inline void dm_iot_init(struct dm_io_tracker *iot)
+{
+ spin_lock_init(&iot->lock);
+ iot->in_flight = 0ul;
+ iot->idle_time = 0ul;
+ iot->last_update_time = jiffies;
+}
+
+static inline bool dm_iot_idle_for(struct dm_io_tracker *iot, unsigned long j)
+{
+ bool r = false;
+
+ spin_lock_irq(&iot->lock);
+ if (!iot->in_flight)
+ r = time_after(jiffies, iot->idle_time + j);
+ spin_unlock_irq(&iot->lock);
+
+ return r;
+}
+
+static inline unsigned long dm_iot_idle_time(struct dm_io_tracker *iot)
+{
+ unsigned long r = 0;
+
+ spin_lock_irq(&iot->lock);
+ if (!iot->in_flight)
+ r = jiffies - iot->idle_time;
+ spin_unlock_irq(&iot->lock);
+
+ return r;
+}
+
+static inline void dm_iot_io_begin(struct dm_io_tracker *iot, sector_t len)
+{
+ spin_lock_irq(&iot->lock);
+ iot->in_flight += len;
+ spin_unlock_irq(&iot->lock);
+}
+
+static inline void dm_iot_io_end(struct dm_io_tracker *iot, sector_t len)
+{
+ unsigned long flags;
+
+ if (!len)
+ return;
+
+ spin_lock_irqsave(&iot->lock, flags);
+ iot->in_flight -= len;
+ if (!iot->in_flight)
+ iot->idle_time = jiffies;
+ spin_unlock_irqrestore(&iot->lock, flags);
+}
+
+#endif
diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c
index 1bbe4a34ef4c..37b03ab7e5c9 100644
--- a/drivers/md/dm-kcopyd.c
+++ b/drivers/md/dm-kcopyd.c
@@ -341,7 +341,7 @@ static void client_free_pages(struct dm_kcopyd_client *kc)
struct kcopyd_job {
struct dm_kcopyd_client *kc;
struct list_head list;
- unsigned long flags;
+ unsigned flags;
/*
* Error state of the job.
@@ -418,7 +418,7 @@ static struct kcopyd_job *pop_io_job(struct list_head *jobs,
* constraint and sequential writes that are at the right position.
*/
list_for_each_entry(job, jobs, list) {
- if (job->rw == READ || !test_bit(DM_KCOPYD_WRITE_SEQ, &job->flags)) {
+ if (job->rw == READ || !(job->flags & BIT(DM_KCOPYD_WRITE_SEQ))) {
list_del(&job->list);
return job;
}
@@ -437,9 +437,8 @@ static struct kcopyd_job *pop(struct list_head *jobs,
struct dm_kcopyd_client *kc)
{
struct kcopyd_job *job = NULL;
- unsigned long flags;
- spin_lock_irqsave(&kc->job_lock, flags);
+ spin_lock_irq(&kc->job_lock);
if (!list_empty(jobs)) {
if (jobs == &kc->io_jobs)
@@ -449,7 +448,7 @@ static struct kcopyd_job *pop(struct list_head *jobs,
list_del(&job->list);
}
}
- spin_unlock_irqrestore(&kc->job_lock, flags);
+ spin_unlock_irq(&kc->job_lock);
return job;
}
@@ -467,12 +466,11 @@ static void push(struct list_head *jobs, struct kcopyd_job *job)
static void push_head(struct list_head *jobs, struct kcopyd_job *job)
{
- unsigned long flags;
struct dm_kcopyd_client *kc = job->kc;
- spin_lock_irqsave(&kc->job_lock, flags);
+ spin_lock_irq(&kc->job_lock);
list_add(&job->list, jobs);
- spin_unlock_irqrestore(&kc->job_lock, flags);
+ spin_unlock_irq(&kc->job_lock);
}
/*
@@ -525,7 +523,7 @@ static void complete_io(unsigned long error, void *context)
else
job->read_err = 1;
- if (!test_bit(DM_KCOPYD_IGNORE_ERROR, &job->flags)) {
+ if (!(job->flags & BIT(DM_KCOPYD_IGNORE_ERROR))) {
push(&kc->complete_jobs, job);
wake(kc);
return;
@@ -565,7 +563,7 @@ static int run_io_job(struct kcopyd_job *job)
* If we need to write sequentially and some reads or writes failed,
* no point in continuing.
*/
- if (test_bit(DM_KCOPYD_WRITE_SEQ, &job->flags) &&
+ if (job->flags & BIT(DM_KCOPYD_WRITE_SEQ) &&
job->master_job->write_err) {
job->write_err = job->master_job->write_err;
return -EIO;
@@ -648,7 +646,6 @@ static void do_work(struct work_struct *work)
struct dm_kcopyd_client *kc = container_of(work,
struct dm_kcopyd_client, kcopyd_work);
struct blk_plug plug;
- unsigned long flags;
/*
* The order that these are called is *very* important.
@@ -657,9 +654,9 @@ static void do_work(struct work_struct *work)
* list. io jobs call wake when they complete and it all
* starts again.
*/
- spin_lock_irqsave(&kc->job_lock, flags);
+ spin_lock_irq(&kc->job_lock);
list_splice_tail_init(&kc->callback_jobs, &kc->complete_jobs);
- spin_unlock_irqrestore(&kc->job_lock, flags);
+ spin_unlock_irq(&kc->job_lock);
blk_start_plug(&plug);
process_jobs(&kc->complete_jobs, kc, run_complete_job);
@@ -709,7 +706,7 @@ static void segment_complete(int read_err, unsigned long write_err,
* Only dispatch more work if there hasn't been an error.
*/
if ((!job->read_err && !job->write_err) ||
- test_bit(DM_KCOPYD_IGNORE_ERROR, &job->flags)) {
+ job->flags & BIT(DM_KCOPYD_IGNORE_ERROR)) {
/* get the next chunk of work */
progress = job->progress;
count = job->source.count - progress;
@@ -801,10 +798,10 @@ void dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
* we need to write sequentially. If one of the destination is a
* host-aware device, then leave it to the caller to choose what to do.
*/
- if (!test_bit(DM_KCOPYD_WRITE_SEQ, &job->flags)) {
+ if (!(job->flags & BIT(DM_KCOPYD_WRITE_SEQ))) {
for (i = 0; i < job->num_dests; i++) {
if (bdev_zoned_model(dests[i].bdev) == BLK_ZONED_HM) {
- set_bit(DM_KCOPYD_WRITE_SEQ, &job->flags);
+ job->flags |= BIT(DM_KCOPYD_WRITE_SEQ);
break;
}
}
@@ -813,9 +810,9 @@ void dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
/*
* If we need to write sequentially, errors cannot be ignored.
*/
- if (test_bit(DM_KCOPYD_WRITE_SEQ, &job->flags) &&
- test_bit(DM_KCOPYD_IGNORE_ERROR, &job->flags))
- clear_bit(DM_KCOPYD_IGNORE_ERROR, &job->flags);
+ if (job->flags & BIT(DM_KCOPYD_WRITE_SEQ) &&
+ job->flags & BIT(DM_KCOPYD_IGNORE_ERROR))
+ job->flags &= ~BIT(DM_KCOPYD_IGNORE_ERROR);
if (from) {
job->source = *from;
@@ -983,3 +980,9 @@ void dm_kcopyd_client_destroy(struct dm_kcopyd_client *kc)
kfree(kc);
}
EXPORT_SYMBOL(dm_kcopyd_client_destroy);
+
+void dm_kcopyd_client_flush(struct dm_kcopyd_client *kc)
+{
+ flush_workqueue(kc->kcopyd_wq);
+}
+EXPORT_SYMBOL(dm_kcopyd_client_flush);
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 92db0f5e7f28..c91f1e2e2f65 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -140,11 +140,10 @@ static int linear_report_zones(struct dm_target *ti,
struct dm_report_zones_args *args, unsigned int nr_zones)
{
struct linear_c *lc = ti->private;
- sector_t sector = linear_map_sector(ti, args->next_sector);
- args->start = lc->start;
- return blkdev_report_zones(lc->dev->bdev, sector, nr_zones,
- dm_report_zones_cb, args);
+ return dm_report_zones(lc->dev->bdev, lc->start,
+ linear_map_sector(ti, args->next_sector),
+ args, nr_zones);
}
#else
#define linear_report_zones NULL
diff --git a/drivers/md/dm-ps-io-affinity.c b/drivers/md/dm-ps-io-affinity.c
index 077655cd4fae..cb8e83bfb1a7 100644
--- a/drivers/md/dm-ps-io-affinity.c
+++ b/drivers/md/dm-ps-io-affinity.c
@@ -91,7 +91,6 @@ static int ioa_add_path(struct path_selector *ps, struct dm_path *path,
cpumask_set_cpu(cpu, s->path_mask);
s->path_map[cpu] = pi;
refcount_inc(&pi->refcount);
- continue;
}
if (refcount_dec_and_test(&pi->refcount)) {
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index b0a82f29a2e4..ebb4810cc3b4 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -364,7 +364,7 @@ static void recover(struct mirror_set *ms, struct dm_region *reg)
/* hand to kcopyd */
if (!errors_handled(ms))
- set_bit(DM_KCOPYD_IGNORE_ERROR, &flags);
+ flags |= BIT(DM_KCOPYD_IGNORE_ERROR);
dm_kcopyd_copy(ms->kcopyd_client, &from, ms->nr_mirrors - 1, to,
flags, recovery_complete, reg);
diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c
index 9c3bc3711b33..0dbd48cbdff9 100644
--- a/drivers/md/dm-rq.c
+++ b/drivers/md/dm-rq.c
@@ -530,7 +530,6 @@ static const struct blk_mq_ops dm_mq_ops = {
int dm_mq_init_request_queue(struct mapped_device *md, struct dm_table *t)
{
- struct request_queue *q;
struct dm_target *immutable_tgt;
int err;
@@ -557,12 +556,10 @@ int dm_mq_init_request_queue(struct mapped_device *md, struct dm_table *t)
if (err)
goto out_kfree_tag_set;
- q = blk_mq_init_allocated_queue(md->tag_set, md->queue, true);
- if (IS_ERR(q)) {
- err = PTR_ERR(q);
+ err = blk_mq_init_allocated_queue(md->tag_set, md->queue);
+ if (err)
goto out_tag_set;
- }
-
+ elevator_init_mq(md->queue);
return 0;
out_tag_set:
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index ee47a332b462..0543cdf89e92 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -249,7 +249,7 @@ static int device_area_is_invalid(struct dm_target *ti, struct dm_dev *dev,
* If the target is mapped to zoned block device(s), check
* that the zones are not partially mapped.
*/
- if (bdev_zoned_model(bdev) != BLK_ZONED_NONE) {
+ if (bdev_is_zoned(bdev)) {
unsigned int zone_sectors = bdev_zone_sectors(bdev);
if (start & (zone_sectors - 1)) {
@@ -1244,7 +1244,7 @@ static int dm_keyslot_evict(struct blk_keyslot_manager *ksm,
return args.err;
}
-static struct blk_ksm_ll_ops dm_ksm_ll_ops = {
+static const struct blk_ksm_ll_ops dm_ksm_ll_ops = {
.keyslot_evict = dm_keyslot_evict,
};
@@ -1981,11 +1981,12 @@ static int device_requires_stable_pages(struct dm_target *ti,
return blk_queue_stable_writes(q);
}
-void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
- struct queue_limits *limits)
+int 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;
+ int r;
/*
* Copy table's limits to the DM device's request_queue
@@ -2065,19 +2066,19 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q);
/*
- * For a zoned target, the number of zones should be updated for the
- * correct value to be exposed in sysfs queue/nr_zones. For a BIO based
- * target, this is all that is needed.
+ * For a zoned target, setup the zones related queue attributes
+ * and resources necessary for zone append emulation if necessary.
*/
-#ifdef CONFIG_BLK_DEV_ZONED
if (blk_queue_is_zoned(q)) {
- WARN_ON_ONCE(queue_is_mq(q));
- q->nr_zones = blkdev_nr_zones(t->md->disk);
+ r = dm_set_zones_restrictions(t, q);
+ if (r)
+ return r;
}
-#endif
dm_update_keyslot_manager(q, t);
blk_queue_update_readahead(q);
+
+ return 0;
}
unsigned int dm_table_get_num_targets(struct dm_table *t)
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index e75b20480e46..c88ed14d49e6 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -311,28 +311,53 @@ static void unpack_block_time(uint64_t v, dm_block_t *b, uint32_t *t)
*t = v & ((1 << 24) - 1);
}
-static void data_block_inc(void *context, const void *value_le)
+/*
+ * It's more efficient to call dm_sm_{inc,dec}_blocks as few times as
+ * possible. 'with_runs' reads contiguous runs of blocks, and calls the
+ * given sm function.
+ */
+typedef int (*run_fn)(struct dm_space_map *, dm_block_t, dm_block_t);
+
+static void with_runs(struct dm_space_map *sm, const __le64 *value_le, unsigned count, run_fn fn)
{
- struct dm_space_map *sm = context;
- __le64 v_le;
- uint64_t b;
+ uint64_t b, begin, end;
uint32_t t;
+ bool in_run = false;
+ unsigned i;
- memcpy(&v_le, value_le, sizeof(v_le));
- unpack_block_time(le64_to_cpu(v_le), &b, &t);
- dm_sm_inc_block(sm, b);
+ for (i = 0; i < count; i++, value_le++) {
+ /* We know value_le is 8 byte aligned */
+ unpack_block_time(le64_to_cpu(*value_le), &b, &t);
+
+ if (in_run) {
+ if (b == end) {
+ end++;
+ } else {
+ fn(sm, begin, end);
+ begin = b;
+ end = b + 1;
+ }
+ } else {
+ in_run = true;
+ begin = b;
+ end = b + 1;
+ }
+ }
+
+ if (in_run)
+ fn(sm, begin, end);
}
-static void data_block_dec(void *context, const void *value_le)
+static void data_block_inc(void *context, const void *value_le, unsigned count)
{
- struct dm_space_map *sm = context;
- __le64 v_le;
- uint64_t b;
- uint32_t t;
+ with_runs((struct dm_space_map *) context,
+ (const __le64 *) value_le, count, dm_sm_inc_blocks);
+}
- memcpy(&v_le, value_le, sizeof(v_le));
- unpack_block_time(le64_to_cpu(v_le), &b, &t);
- dm_sm_dec_block(sm, b);
+static void data_block_dec(void *context, const void *value_le, unsigned count)
+{
+ with_runs((struct dm_space_map *) context,
+ (const __le64 *) value_le, count, dm_sm_dec_blocks);
}
static int data_block_equal(void *context, const void *value1_le, const void *value2_le)
@@ -349,27 +374,25 @@ static int data_block_equal(void *context, const void *value1_le, const void *va
return b1 == b2;
}
-static void subtree_inc(void *context, const void *value)
+static void subtree_inc(void *context, const void *value, unsigned count)
{
struct dm_btree_info *info = context;
- __le64 root_le;
- uint64_t root;
+ const __le64 *root_le = value;
+ unsigned i;
- memcpy(&root_le, value, sizeof(root_le));
- root = le64_to_cpu(root_le);
- dm_tm_inc(info->tm, root);
+ for (i = 0; i < count; i++, root_le++)
+ dm_tm_inc(info->tm, le64_to_cpu(*root_le));
}
-static void subtree_dec(void *context, const void *value)
+static void subtree_dec(void *context, const void *value, unsigned count)
{
struct dm_btree_info *info = context;
- __le64 root_le;
- uint64_t root;
+ const __le64 *root_le = value;
+ unsigned i;
- memcpy(&root_le, value, sizeof(root_le));
- root = le64_to_cpu(root_le);
- if (dm_btree_del(info, root))
- DMERR("btree delete failed");
+ for (i = 0; i < count; i++, root_le++)
+ if (dm_btree_del(info, le64_to_cpu(*root_le)))
+ DMERR("btree delete failed");
}
static int subtree_equal(void *context, const void *value1_le, const void *value2_le)
@@ -1761,11 +1784,7 @@ int dm_pool_inc_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_
int r = 0;
pmd_write_lock(pmd);
- for (; b != e; b++) {
- r = dm_sm_inc_block(pmd->data_sm, b);
- if (r)
- break;
- }
+ r = dm_sm_inc_blocks(pmd->data_sm, b, e);
pmd_write_unlock(pmd);
return r;
@@ -1776,11 +1795,7 @@ int dm_pool_dec_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_
int r = 0;
pmd_write_lock(pmd);
- for (; b != e; b++) {
- r = dm_sm_dec_block(pmd->data_sm, b);
- if (r)
- break;
- }
+ r = dm_sm_dec_blocks(pmd->data_sm, b, e);
pmd_write_unlock(pmd);
return r;
diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c
index aecc246ade26..e21e29e81bbf 100644
--- a/drivers/md/dm-writecache.c
+++ b/drivers/md/dm-writecache.c
@@ -15,6 +15,8 @@
#include <linux/dax.h>
#include <linux/pfn_t.h>
#include <linux/libnvdimm.h>
+#include <linux/delay.h>
+#include "dm-io-tracker.h"
#define DM_MSG_PREFIX "writecache"
@@ -28,6 +30,7 @@
#define AUTOCOMMIT_MSEC 1000
#define MAX_AGE_DIV 16
#define MAX_AGE_UNSPECIFIED -1UL
+#define PAUSE_WRITEBACK (HZ * 3)
#define BITMAP_GRANULARITY 65536
#if BITMAP_GRANULARITY < PAGE_SIZE
@@ -123,6 +126,7 @@ struct dm_writecache {
size_t freelist_high_watermark;
size_t freelist_low_watermark;
unsigned long max_age;
+ unsigned long pause;
unsigned uncommitted_blocks;
unsigned autocommit_blocks;
@@ -171,17 +175,22 @@ struct dm_writecache {
bool flush_on_suspend:1;
bool cleaner:1;
bool cleaner_set:1;
+ bool metadata_only:1;
+ bool pause_set:1;
unsigned high_wm_percent_value;
unsigned low_wm_percent_value;
unsigned autocommit_time_value;
unsigned max_age_value;
+ unsigned pause_value;
unsigned writeback_all;
struct workqueue_struct *writeback_wq;
struct work_struct writeback_work;
struct work_struct flush_work;
+ struct dm_io_tracker iot;
+
struct dm_io_client *dm_io;
raw_spinlock_t endio_list_lock;
@@ -532,7 +541,7 @@ static void ssd_commit_superblock(struct dm_writecache *wc)
region.bdev = wc->ssd_dev->bdev;
region.sector = 0;
- region.count = PAGE_SIZE >> SECTOR_SHIFT;
+ region.count = max(4096U, wc->block_size) >> SECTOR_SHIFT;
if (unlikely(region.sector + region.count > wc->metadata_sectors))
region.count = wc->metadata_sectors - region.sector;
@@ -1301,8 +1310,12 @@ static int writecache_map(struct dm_target *ti, struct bio *bio)
writecache_flush(wc);
if (writecache_has_error(wc))
goto unlock_error;
+ if (unlikely(wc->cleaner) || unlikely(wc->metadata_only))
+ goto unlock_remap_origin;
goto unlock_submit;
} else {
+ if (dm_bio_get_target_bio_nr(bio))
+ goto unlock_remap_origin;
writecache_offload_bio(wc, bio);
goto unlock_return;
}
@@ -1360,24 +1373,29 @@ read_next_block:
} else {
do {
bool found_entry = false;
+ bool search_used = false;
if (writecache_has_error(wc))
goto unlock_error;
e = writecache_find_entry(wc, bio->bi_iter.bi_sector, 0);
if (e) {
- if (!writecache_entry_is_committed(wc, e))
+ if (!writecache_entry_is_committed(wc, e)) {
+ search_used = true;
goto bio_copy;
+ }
if (!WC_MODE_PMEM(wc) && !e->write_in_progress) {
wc->overwrote_committed = true;
+ search_used = true;
goto bio_copy;
}
found_entry = true;
} else {
- if (unlikely(wc->cleaner))
+ if (unlikely(wc->cleaner) ||
+ (wc->metadata_only && !(bio->bi_opf & REQ_META)))
goto direct_write;
}
e = writecache_pop_from_freelist(wc, (sector_t)-1);
if (unlikely(!e)) {
- if (!found_entry) {
+ if (!WC_MODE_PMEM(wc) && !found_entry) {
direct_write:
e = writecache_find_entry(wc, bio->bi_iter.bi_sector, WFE_RETURN_FOLLOWING);
if (e) {
@@ -1404,13 +1422,31 @@ bio_copy:
sector_t current_cache_sec = start_cache_sec + (bio_size >> SECTOR_SHIFT);
while (bio_size < bio->bi_iter.bi_size) {
- struct wc_entry *f = writecache_pop_from_freelist(wc, current_cache_sec);
- if (!f)
- break;
- write_original_sector_seq_count(wc, f, bio->bi_iter.bi_sector +
- (bio_size >> SECTOR_SHIFT), wc->seq_count);
- writecache_insert_entry(wc, f);
- wc->uncommitted_blocks++;
+ if (!search_used) {
+ struct wc_entry *f = writecache_pop_from_freelist(wc, current_cache_sec);
+ if (!f)
+ break;
+ write_original_sector_seq_count(wc, f, bio->bi_iter.bi_sector +
+ (bio_size >> SECTOR_SHIFT), wc->seq_count);
+ writecache_insert_entry(wc, f);
+ wc->uncommitted_blocks++;
+ } else {
+ struct wc_entry *f;
+ struct rb_node *next = rb_next(&e->rb_node);
+ if (!next)
+ break;
+ f = container_of(next, struct wc_entry, rb_node);
+ if (f != e + 1)
+ break;
+ if (read_original_sector(wc, f) !=
+ read_original_sector(wc, e) + (wc->block_size >> SECTOR_SHIFT))
+ break;
+ if (unlikely(f->write_in_progress))
+ break;
+ if (writecache_entry_is_committed(wc, f))
+ wc->overwrote_committed = true;
+ e = f;
+ }
bio_size += wc->block_size;
current_cache_sec += wc->block_size >> SECTOR_SHIFT;
}
@@ -1438,6 +1474,12 @@ bio_copy:
}
unlock_remap_origin:
+ if (likely(wc->pause != 0)) {
+ if (bio_op(bio) == REQ_OP_WRITE) {
+ dm_iot_io_begin(&wc->iot, 1);
+ bio->bi_private = (void *)2;
+ }
+ }
bio_set_dev(bio, wc->dev->bdev);
wc_unlock(wc);
return DM_MAPIO_REMAPPED;
@@ -1468,11 +1510,13 @@ static int writecache_end_io(struct dm_target *ti, struct bio *bio, blk_status_t
{
struct dm_writecache *wc = ti->private;
- if (bio->bi_private != NULL) {
+ if (bio->bi_private == (void *)1) {
int dir = bio_data_dir(bio);
if (atomic_dec_and_test(&wc->bio_in_progress[dir]))
if (unlikely(waitqueue_active(&wc->bio_in_progress_wait[dir])))
wake_up(&wc->bio_in_progress_wait[dir]);
+ } else if (bio->bi_private == (void *)2) {
+ dm_iot_io_end(&wc->iot, 1);
}
return 0;
}
@@ -1642,7 +1686,7 @@ pop_from_list:
return 0;
}
-static bool wc_add_block(struct writeback_struct *wb, struct wc_entry *e, gfp_t gfp)
+static bool wc_add_block(struct writeback_struct *wb, struct wc_entry *e)
{
struct dm_writecache *wc = wb->wc;
unsigned block_size = wc->block_size;
@@ -1703,7 +1747,7 @@ static void __writecache_writeback_pmem(struct dm_writecache *wc, struct writeba
max_pages = WB_LIST_INLINE;
}
- BUG_ON(!wc_add_block(wb, e, GFP_NOIO));
+ BUG_ON(!wc_add_block(wb, e));
wb->wc_list[0] = e;
wb->wc_list_n = 1;
@@ -1713,7 +1757,7 @@ static void __writecache_writeback_pmem(struct dm_writecache *wc, struct writeba
if (read_original_sector(wc, f) !=
read_original_sector(wc, e) + (wc->block_size >> SECTOR_SHIFT))
break;
- if (!wc_add_block(wb, f, GFP_NOWAIT | __GFP_NOWARN))
+ if (!wc_add_block(wb, f))
break;
wbl->size--;
list_del(&f->lru);
@@ -1794,6 +1838,27 @@ static void writecache_writeback(struct work_struct *work)
struct writeback_list wbl;
unsigned long n_walked;
+ if (!WC_MODE_PMEM(wc)) {
+ /* Wait for any active kcopyd work on behalf of ssd writeback */
+ dm_kcopyd_client_flush(wc->dm_kcopyd);
+ }
+
+ if (likely(wc->pause != 0)) {
+ while (1) {
+ unsigned long idle;
+ if (unlikely(wc->cleaner) || unlikely(wc->writeback_all) ||
+ unlikely(dm_suspended(wc->ti)))
+ break;
+ idle = dm_iot_idle_time(&wc->iot);
+ if (idle >= wc->pause)
+ break;
+ idle = wc->pause - idle;
+ if (idle > HZ)
+ idle = HZ;
+ schedule_timeout_idle(idle);
+ }
+ }
+
wc_lock(wc);
restart:
if (writecache_has_error(wc)) {
@@ -1822,8 +1887,9 @@ restart:
n_walked++;
if (unlikely(n_walked > WRITEBACK_LATENCY) &&
- likely(!wc->writeback_all) && likely(!dm_suspended(wc->ti))) {
- queue_work(wc->writeback_wq, &wc->writeback_work);
+ likely(!wc->writeback_all)) {
+ if (likely(!dm_suspended(wc->ti)))
+ queue_work(wc->writeback_wq, &wc->writeback_work);
break;
}
@@ -1845,15 +1911,13 @@ restart:
if (unlikely(read_original_sector(wc, f) ==
read_original_sector(wc, e))) {
BUG_ON(!f->write_in_progress);
- list_del(&e->lru);
- list_add(&e->lru, &skipped);
+ list_move(&e->lru, &skipped);
cond_resched();
continue;
}
}
wc->writeback_size++;
- list_del(&e->lru);
- list_add(&e->lru, &wbl.list);
+ list_move(&e->lru, &wbl.list);
wbl.size++;
e->write_in_progress = true;
e->wc_list_contiguous = 1;
@@ -1888,8 +1952,7 @@ restart:
// break;
wc->writeback_size++;
- list_del(&g->lru);
- list_add(&g->lru, &wbl.list);
+ list_move(&g->lru, &wbl.list);
wbl.size++;
g->write_in_progress = true;
g->wc_list_contiguous = BIO_MAX_VECS;
@@ -2065,7 +2128,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
struct wc_memory_superblock s;
static struct dm_arg _args[] = {
- {0, 16, "Invalid number of feature args"},
+ {0, 18, "Invalid number of feature args"},
};
as.argc = argc;
@@ -2109,6 +2172,8 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
INIT_WORK(&wc->writeback_work, writecache_writeback);
INIT_WORK(&wc->flush_work, writecache_flush_work);
+ dm_iot_init(&wc->iot);
+
raw_spin_lock_init(&wc->endio_list_lock);
INIT_LIST_HEAD(&wc->endio_list);
wc->endio_thread = kthread_create(writecache_endio_thread, wc, "writecache_endio");
@@ -2156,6 +2221,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto bad;
}
} else {
+ wc->pause = PAUSE_WRITEBACK;
r = mempool_init_kmalloc_pool(&wc->copy_pool, 1, sizeof(struct copy_struct));
if (r) {
ti->error = "Could not allocate mempool";
@@ -2292,6 +2358,20 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
wc->writeback_fua = false;
wc->writeback_fua_set = true;
} else goto invalid_optional;
+ } else if (!strcasecmp(string, "metadata_only")) {
+ wc->metadata_only = true;
+ } else if (!strcasecmp(string, "pause_writeback") && opt_params >= 1) {
+ unsigned pause_msecs;
+ if (WC_MODE_PMEM(wc))
+ goto invalid_optional;
+ string = dm_shift_arg(&as), opt_params--;
+ if (sscanf(string, "%u%c", &pause_msecs, &dummy) != 1)
+ goto invalid_optional;
+ if (pause_msecs > 60000)
+ goto invalid_optional;
+ wc->pause = msecs_to_jiffies(pause_msecs);
+ wc->pause_set = true;
+ wc->pause_value = pause_msecs;
} else {
invalid_optional:
r = -EINVAL;
@@ -2463,7 +2543,7 @@ overflow:
goto bad;
}
- ti->num_flush_bios = 1;
+ ti->num_flush_bios = WC_MODE_PMEM(wc) ? 1 : 2;
ti->flush_supported = true;
ti->num_discard_bios = 1;
@@ -2515,6 +2595,10 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
extra_args++;
if (wc->writeback_fua_set)
extra_args++;
+ if (wc->metadata_only)
+ extra_args++;
+ if (wc->pause_set)
+ extra_args += 2;
DMEMIT("%u", extra_args);
if (wc->start_sector_set)
@@ -2535,13 +2619,17 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
DMEMIT(" cleaner");
if (wc->writeback_fua_set)
DMEMIT(" %sfua", wc->writeback_fua ? "" : "no");
+ if (wc->metadata_only)
+ DMEMIT(" metadata_only");
+ if (wc->pause_set)
+ DMEMIT(" pause_writeback %u", wc->pause_value);
break;
}
}
static struct target_type writecache_target = {
.name = "writecache",
- .version = {1, 4, 0},
+ .version = {1, 5, 0},
.module = THIS_MODULE,
.ctr = writecache_ctr,
.dtr = writecache_dtr,
diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c
new file mode 100644
index 000000000000..6d82a34438c8
--- /dev/null
+++ b/drivers/md/dm-zone.c
@@ -0,0 +1,660 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Western Digital Corporation or its affiliates.
+ */
+
+#include <linux/blkdev.h>
+#include <linux/mm.h>
+#include <linux/sched/mm.h>
+#include <linux/slab.h>
+
+#include "dm-core.h"
+
+#define DM_MSG_PREFIX "zone"
+
+#define DM_ZONE_INVALID_WP_OFST UINT_MAX
+
+/*
+ * For internal zone reports bypassing the top BIO submission path.
+ */
+static int dm_blk_do_report_zones(struct mapped_device *md, struct dm_table *t,
+ sector_t sector, unsigned int nr_zones,
+ report_zones_cb cb, void *data)
+{
+ struct gendisk *disk = md->disk;
+ int ret;
+ struct dm_report_zones_args args = {
+ .next_sector = sector,
+ .orig_data = data,
+ .orig_cb = cb,
+ };
+
+ do {
+ struct dm_target *tgt;
+
+ tgt = dm_table_find_target(t, args.next_sector);
+ if (WARN_ON_ONCE(!tgt->type->report_zones))
+ return -EIO;
+
+ args.tgt = tgt;
+ ret = tgt->type->report_zones(tgt, &args,
+ nr_zones - args.zone_idx);
+ if (ret < 0)
+ return ret;
+ } while (args.zone_idx < nr_zones &&
+ args.next_sector < get_capacity(disk));
+
+ return args.zone_idx;
+}
+
+/*
+ * User facing dm device block device report zone operation. This calls the
+ * report_zones operation for each target of a device table. This operation is
+ * generally implemented by targets using dm_report_zones().
+ */
+int dm_blk_report_zones(struct gendisk *disk, sector_t sector,
+ unsigned int nr_zones, report_zones_cb cb, void *data)
+{
+ struct mapped_device *md = disk->private_data;
+ struct dm_table *map;
+ int srcu_idx, ret;
+
+ if (dm_suspended_md(md))
+ return -EAGAIN;
+
+ map = dm_get_live_table(md, &srcu_idx);
+ if (!map)
+ return -EIO;
+
+ ret = dm_blk_do_report_zones(md, map, sector, nr_zones, cb, data);
+
+ dm_put_live_table(md, srcu_idx);
+
+ return ret;
+}
+
+static int dm_report_zones_cb(struct blk_zone *zone, unsigned int idx,
+ void *data)
+{
+ struct dm_report_zones_args *args = data;
+ sector_t sector_diff = args->tgt->begin - args->start;
+
+ /*
+ * Ignore zones beyond the target range.
+ */
+ if (zone->start >= args->start + args->tgt->len)
+ return 0;
+
+ /*
+ * Remap the start sector and write pointer position of the zone
+ * to match its position in the target range.
+ */
+ zone->start += sector_diff;
+ if (zone->type != BLK_ZONE_TYPE_CONVENTIONAL) {
+ if (zone->cond == BLK_ZONE_COND_FULL)
+ zone->wp = zone->start + zone->len;
+ else if (zone->cond == BLK_ZONE_COND_EMPTY)
+ zone->wp = zone->start;
+ else
+ zone->wp += sector_diff;
+ }
+
+ args->next_sector = zone->start + zone->len;
+ return args->orig_cb(zone, args->zone_idx++, args->orig_data);
+}
+
+/*
+ * Helper for drivers of zoned targets to implement struct target_type
+ * report_zones operation.
+ */
+int dm_report_zones(struct block_device *bdev, sector_t start, sector_t sector,
+ struct dm_report_zones_args *args, unsigned int nr_zones)
+{
+ /*
+ * Set the target mapping start sector first so that
+ * dm_report_zones_cb() can correctly remap zone information.
+ */
+ args->start = start;
+
+ return blkdev_report_zones(bdev, sector, nr_zones,
+ dm_report_zones_cb, args);
+}
+EXPORT_SYMBOL_GPL(dm_report_zones);
+
+bool dm_is_zone_write(struct mapped_device *md, struct bio *bio)
+{
+ struct request_queue *q = md->queue;
+
+ if (!blk_queue_is_zoned(q))
+ return false;
+
+ switch (bio_op(bio)) {
+ case REQ_OP_WRITE_ZEROES:
+ case REQ_OP_WRITE_SAME:
+ case REQ_OP_WRITE:
+ return !op_is_flush(bio->bi_opf) && bio_sectors(bio);
+ default:
+ return false;
+ }
+}
+
+void dm_cleanup_zoned_dev(struct mapped_device *md)
+{
+ struct request_queue *q = md->queue;
+
+ if (q) {
+ kfree(q->conv_zones_bitmap);
+ q->conv_zones_bitmap = NULL;
+ kfree(q->seq_zones_wlock);
+ q->seq_zones_wlock = NULL;
+ }
+
+ kvfree(md->zwp_offset);
+ md->zwp_offset = NULL;
+ md->nr_zones = 0;
+}
+
+static unsigned int dm_get_zone_wp_offset(struct blk_zone *zone)
+{
+ switch (zone->cond) {
+ case BLK_ZONE_COND_IMP_OPEN:
+ case BLK_ZONE_COND_EXP_OPEN:
+ case BLK_ZONE_COND_CLOSED:
+ return zone->wp - zone->start;
+ case BLK_ZONE_COND_FULL:
+ return zone->len;
+ case BLK_ZONE_COND_EMPTY:
+ case BLK_ZONE_COND_NOT_WP:
+ case BLK_ZONE_COND_OFFLINE:
+ case BLK_ZONE_COND_READONLY:
+ default:
+ /*
+ * Conventional, offline and read-only zones do not have a valid
+ * write pointer. Use 0 as for an empty zone.
+ */
+ return 0;
+ }
+}
+
+static int dm_zone_revalidate_cb(struct blk_zone *zone, unsigned int idx,
+ void *data)
+{
+ struct mapped_device *md = data;
+ struct request_queue *q = md->queue;
+
+ switch (zone->type) {
+ case BLK_ZONE_TYPE_CONVENTIONAL:
+ if (!q->conv_zones_bitmap) {
+ q->conv_zones_bitmap =
+ kcalloc(BITS_TO_LONGS(q->nr_zones),
+ sizeof(unsigned long), GFP_NOIO);
+ if (!q->conv_zones_bitmap)
+ return -ENOMEM;
+ }
+ set_bit(idx, q->conv_zones_bitmap);
+ break;
+ case BLK_ZONE_TYPE_SEQWRITE_REQ:
+ case BLK_ZONE_TYPE_SEQWRITE_PREF:
+ if (!q->seq_zones_wlock) {
+ q->seq_zones_wlock =
+ kcalloc(BITS_TO_LONGS(q->nr_zones),
+ sizeof(unsigned long), GFP_NOIO);
+ if (!q->seq_zones_wlock)
+ return -ENOMEM;
+ }
+ if (!md->zwp_offset) {
+ md->zwp_offset =
+ kvcalloc(q->nr_zones, sizeof(unsigned int),
+ GFP_KERNEL);
+ if (!md->zwp_offset)
+ return -ENOMEM;
+ }
+ md->zwp_offset[idx] = dm_get_zone_wp_offset(zone);
+
+ break;
+ default:
+ DMERR("Invalid zone type 0x%x at sectors %llu",
+ (int)zone->type, zone->start);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/*
+ * Revalidate the zones of a mapped device to initialize resource necessary
+ * for zone append emulation. Note that we cannot simply use the block layer
+ * blk_revalidate_disk_zones() function here as the mapped device is suspended
+ * (this is called from __bind() context).
+ */
+static int dm_revalidate_zones(struct mapped_device *md, struct dm_table *t)
+{
+ struct request_queue *q = md->queue;
+ unsigned int noio_flag;
+ int ret;
+
+ /*
+ * Check if something changed. If yes, cleanup the current resources
+ * and reallocate everything.
+ */
+ if (!q->nr_zones || q->nr_zones != md->nr_zones)
+ dm_cleanup_zoned_dev(md);
+ if (md->nr_zones)
+ return 0;
+
+ /*
+ * Scan all zones to initialize everything. Ensure that all vmalloc
+ * operations in this context are done as if GFP_NOIO was specified.
+ */
+ noio_flag = memalloc_noio_save();
+ ret = dm_blk_do_report_zones(md, t, 0, q->nr_zones,
+ dm_zone_revalidate_cb, md);
+ memalloc_noio_restore(noio_flag);
+ if (ret < 0)
+ goto err;
+ if (ret != q->nr_zones) {
+ ret = -EIO;
+ goto err;
+ }
+
+ md->nr_zones = q->nr_zones;
+
+ return 0;
+
+err:
+ DMERR("Revalidate zones failed %d", ret);
+ dm_cleanup_zoned_dev(md);
+ return ret;
+}
+
+static int device_not_zone_append_capable(struct dm_target *ti,
+ struct dm_dev *dev, sector_t start,
+ sector_t len, void *data)
+{
+ return !blk_queue_is_zoned(bdev_get_queue(dev->bdev));
+}
+
+static bool dm_table_supports_zone_append(struct dm_table *t)
+{
+ struct dm_target *ti;
+ unsigned int i;
+
+ for (i = 0; i < dm_table_get_num_targets(t); i++) {
+ ti = dm_table_get_target(t, i);
+
+ if (ti->emulate_zone_append)
+ return false;
+
+ if (!ti->type->iterate_devices ||
+ ti->type->iterate_devices(ti, device_not_zone_append_capable, NULL))
+ return false;
+ }
+
+ return true;
+}
+
+int dm_set_zones_restrictions(struct dm_table *t, struct request_queue *q)
+{
+ struct mapped_device *md = t->md;
+
+ /*
+ * For a zoned target, the number of zones should be updated for the
+ * correct value to be exposed in sysfs queue/nr_zones.
+ */
+ WARN_ON_ONCE(queue_is_mq(q));
+ q->nr_zones = blkdev_nr_zones(md->disk);
+
+ /* Check if zone append is natively supported */
+ if (dm_table_supports_zone_append(t)) {
+ clear_bit(DMF_EMULATE_ZONE_APPEND, &md->flags);
+ dm_cleanup_zoned_dev(md);
+ return 0;
+ }
+
+ /*
+ * Mark the mapped device as needing zone append emulation and
+ * initialize the emulation resources once the capacity is set.
+ */
+ set_bit(DMF_EMULATE_ZONE_APPEND, &md->flags);
+ if (!get_capacity(md->disk))
+ return 0;
+
+ return dm_revalidate_zones(md, t);
+}
+
+static int dm_update_zone_wp_offset_cb(struct blk_zone *zone, unsigned int idx,
+ void *data)
+{
+ unsigned int *wp_offset = data;
+
+ *wp_offset = dm_get_zone_wp_offset(zone);
+
+ return 0;
+}
+
+static int dm_update_zone_wp_offset(struct mapped_device *md, unsigned int zno,
+ unsigned int *wp_ofst)
+{
+ sector_t sector = zno * blk_queue_zone_sectors(md->queue);
+ unsigned int noio_flag;
+ struct dm_table *t;
+ int srcu_idx, ret;
+
+ t = dm_get_live_table(md, &srcu_idx);
+ if (!t)
+ return -EIO;
+
+ /*
+ * Ensure that all memory allocations in this context are done as if
+ * GFP_NOIO was specified.
+ */
+ noio_flag = memalloc_noio_save();
+ ret = dm_blk_do_report_zones(md, t, sector, 1,
+ dm_update_zone_wp_offset_cb, wp_ofst);
+ memalloc_noio_restore(noio_flag);
+
+ dm_put_live_table(md, srcu_idx);
+
+ if (ret != 1)
+ return -EIO;
+
+ return 0;
+}
+
+/*
+ * First phase of BIO mapping for targets with zone append emulation:
+ * check all BIO that change a zone writer pointer and change zone
+ * append operations into regular write operations.
+ */
+static bool dm_zone_map_bio_begin(struct mapped_device *md,
+ struct bio *orig_bio, struct bio *clone)
+{
+ sector_t zsectors = blk_queue_zone_sectors(md->queue);
+ unsigned int zno = bio_zone_no(orig_bio);
+ unsigned int zwp_offset = READ_ONCE(md->zwp_offset[zno]);
+
+ /*
+ * If the target zone is in an error state, recover by inspecting the
+ * zone to get its current write pointer position. Note that since the
+ * target zone is already locked, a BIO issuing context should never
+ * see the zone write in the DM_ZONE_UPDATING_WP_OFST state.
+ */
+ if (zwp_offset == DM_ZONE_INVALID_WP_OFST) {
+ if (dm_update_zone_wp_offset(md, zno, &zwp_offset))
+ return false;
+ WRITE_ONCE(md->zwp_offset[zno], zwp_offset);
+ }
+
+ switch (bio_op(orig_bio)) {
+ case REQ_OP_ZONE_RESET:
+ case REQ_OP_ZONE_FINISH:
+ return true;
+ case REQ_OP_WRITE_ZEROES:
+ case REQ_OP_WRITE_SAME:
+ case REQ_OP_WRITE:
+ /* Writes must be aligned to the zone write pointer */
+ if ((clone->bi_iter.bi_sector & (zsectors - 1)) != zwp_offset)
+ return false;
+ break;
+ case REQ_OP_ZONE_APPEND:
+ /*
+ * Change zone append operations into a non-mergeable regular
+ * writes directed at the current write pointer position of the
+ * target zone.
+ */
+ clone->bi_opf = REQ_OP_WRITE | REQ_NOMERGE |
+ (orig_bio->bi_opf & (~REQ_OP_MASK));
+ clone->bi_iter.bi_sector =
+ orig_bio->bi_iter.bi_sector + zwp_offset;
+ break;
+ default:
+ DMWARN_LIMIT("Invalid BIO operation");
+ return false;
+ }
+
+ /* Cannot write to a full zone */
+ if (zwp_offset >= zsectors)
+ return false;
+
+ return true;
+}
+
+/*
+ * Second phase of BIO mapping for targets with zone append emulation:
+ * update the zone write pointer offset array to account for the additional
+ * data written to a zone. Note that at this point, the remapped clone BIO
+ * may already have completed, so we do not touch it.
+ */
+static blk_status_t dm_zone_map_bio_end(struct mapped_device *md,
+ struct bio *orig_bio,
+ unsigned int nr_sectors)
+{
+ unsigned int zno = bio_zone_no(orig_bio);
+ unsigned int zwp_offset = READ_ONCE(md->zwp_offset[zno]);
+
+ /* The clone BIO may already have been completed and failed */
+ if (zwp_offset == DM_ZONE_INVALID_WP_OFST)
+ return BLK_STS_IOERR;
+
+ /* Update the zone wp offset */
+ switch (bio_op(orig_bio)) {
+ case REQ_OP_ZONE_RESET:
+ WRITE_ONCE(md->zwp_offset[zno], 0);
+ return BLK_STS_OK;
+ case REQ_OP_ZONE_FINISH:
+ WRITE_ONCE(md->zwp_offset[zno],
+ blk_queue_zone_sectors(md->queue));
+ return BLK_STS_OK;
+ case REQ_OP_WRITE_ZEROES:
+ case REQ_OP_WRITE_SAME:
+ case REQ_OP_WRITE:
+ WRITE_ONCE(md->zwp_offset[zno], zwp_offset + nr_sectors);
+ return BLK_STS_OK;
+ case REQ_OP_ZONE_APPEND:
+ /*
+ * Check that the target did not truncate the write operation
+ * emulating a zone append.
+ */
+ if (nr_sectors != bio_sectors(orig_bio)) {
+ DMWARN_LIMIT("Truncated write for zone append");
+ return BLK_STS_IOERR;
+ }
+ WRITE_ONCE(md->zwp_offset[zno], zwp_offset + nr_sectors);
+ return BLK_STS_OK;
+ default:
+ DMWARN_LIMIT("Invalid BIO operation");
+ return BLK_STS_IOERR;
+ }
+}
+
+static inline void dm_zone_lock(struct request_queue *q,
+ unsigned int zno, struct bio *clone)
+{
+ if (WARN_ON_ONCE(bio_flagged(clone, BIO_ZONE_WRITE_LOCKED)))
+ return;
+
+ wait_on_bit_lock_io(q->seq_zones_wlock, zno, TASK_UNINTERRUPTIBLE);
+ bio_set_flag(clone, BIO_ZONE_WRITE_LOCKED);
+}
+
+static inline void dm_zone_unlock(struct request_queue *q,
+ unsigned int zno, struct bio *clone)
+{
+ if (!bio_flagged(clone, BIO_ZONE_WRITE_LOCKED))
+ return;
+
+ WARN_ON_ONCE(!test_bit(zno, q->seq_zones_wlock));
+ clear_bit_unlock(zno, q->seq_zones_wlock);
+ smp_mb__after_atomic();
+ wake_up_bit(q->seq_zones_wlock, zno);
+
+ bio_clear_flag(clone, BIO_ZONE_WRITE_LOCKED);
+}
+
+static bool dm_need_zone_wp_tracking(struct bio *orig_bio)
+{
+ /*
+ * Special processing is not needed for operations that do not need the
+ * zone write lock, that is, all operations that target conventional
+ * zones and all operations that do not modify directly a sequential
+ * zone write pointer.
+ */
+ if (op_is_flush(orig_bio->bi_opf) && !bio_sectors(orig_bio))
+ return false;
+ switch (bio_op(orig_bio)) {
+ case REQ_OP_WRITE_ZEROES:
+ case REQ_OP_WRITE_SAME:
+ case REQ_OP_WRITE:
+ case REQ_OP_ZONE_RESET:
+ case REQ_OP_ZONE_FINISH:
+ case REQ_OP_ZONE_APPEND:
+ return bio_zone_is_seq(orig_bio);
+ default:
+ return false;
+ }
+}
+
+/*
+ * Special IO mapping for targets needing zone append emulation.
+ */
+int dm_zone_map_bio(struct dm_target_io *tio)
+{
+ struct dm_io *io = tio->io;
+ struct dm_target *ti = tio->ti;
+ struct mapped_device *md = io->md;
+ struct request_queue *q = md->queue;
+ struct bio *orig_bio = io->orig_bio;
+ struct bio *clone = &tio->clone;
+ unsigned int zno;
+ blk_status_t sts;
+ int r;
+
+ /*
+ * IOs that do not change a zone write pointer do not need
+ * any additional special processing.
+ */
+ if (!dm_need_zone_wp_tracking(orig_bio))
+ return ti->type->map(ti, clone);
+
+ /* Lock the target zone */
+ zno = bio_zone_no(orig_bio);
+ dm_zone_lock(q, zno, clone);
+
+ /*
+ * Check that the bio and the target zone write pointer offset are
+ * both valid, and if the bio is a zone append, remap it to a write.
+ */
+ if (!dm_zone_map_bio_begin(md, orig_bio, clone)) {
+ dm_zone_unlock(q, zno, clone);
+ return DM_MAPIO_KILL;
+ }
+
+ /*
+ * The target map function may issue and complete the IO quickly.
+ * Take an extra reference on the IO to make sure it does disappear
+ * until we run dm_zone_map_bio_end().
+ */
+ dm_io_inc_pending(io);
+
+ /* Let the target do its work */
+ r = ti->type->map(ti, clone);
+ switch (r) {
+ case DM_MAPIO_SUBMITTED:
+ /*
+ * The target submitted the clone BIO. The target zone will
+ * be unlocked on completion of the clone.
+ */
+ sts = dm_zone_map_bio_end(md, orig_bio, *tio->len_ptr);
+ break;
+ case DM_MAPIO_REMAPPED:
+ /*
+ * The target only remapped the clone BIO. In case of error,
+ * unlock the target zone here as the clone will not be
+ * submitted.
+ */
+ sts = dm_zone_map_bio_end(md, orig_bio, *tio->len_ptr);
+ if (sts != BLK_STS_OK)
+ dm_zone_unlock(q, zno, clone);
+ break;
+ case DM_MAPIO_REQUEUE:
+ case DM_MAPIO_KILL:
+ default:
+ dm_zone_unlock(q, zno, clone);
+ sts = BLK_STS_IOERR;
+ break;
+ }
+
+ /* Drop the extra reference on the IO */
+ dm_io_dec_pending(io, sts);
+
+ if (sts != BLK_STS_OK)
+ return DM_MAPIO_KILL;
+
+ return r;
+}
+
+/*
+ * IO completion callback called from clone_endio().
+ */
+void dm_zone_endio(struct dm_io *io, struct bio *clone)
+{
+ struct mapped_device *md = io->md;
+ struct request_queue *q = md->queue;
+ struct bio *orig_bio = io->orig_bio;
+ unsigned int zwp_offset;
+ unsigned int zno;
+
+ /*
+ * For targets that do not emulate zone append, we only need to
+ * handle native zone-append bios.
+ */
+ if (!dm_emulate_zone_append(md)) {
+ /*
+ * Get the offset within the zone of the written sector
+ * and add that to the original bio sector position.
+ */
+ if (clone->bi_status == BLK_STS_OK &&
+ bio_op(clone) == REQ_OP_ZONE_APPEND) {
+ sector_t mask = (sector_t)blk_queue_zone_sectors(q) - 1;
+
+ orig_bio->bi_iter.bi_sector +=
+ clone->bi_iter.bi_sector & mask;
+ }
+
+ return;
+ }
+
+ /*
+ * For targets that do emulate zone append, if the clone BIO does not
+ * own the target zone write lock, we have nothing to do.
+ */
+ if (!bio_flagged(clone, BIO_ZONE_WRITE_LOCKED))
+ return;
+
+ zno = bio_zone_no(orig_bio);
+
+ if (clone->bi_status != BLK_STS_OK) {
+ /*
+ * BIOs that modify a zone write pointer may leave the zone
+ * in an unknown state in case of failure (e.g. the write
+ * pointer was only partially advanced). In this case, set
+ * the target zone write pointer as invalid unless it is
+ * already being updated.
+ */
+ WRITE_ONCE(md->zwp_offset[zno], DM_ZONE_INVALID_WP_OFST);
+ } else if (bio_op(orig_bio) == REQ_OP_ZONE_APPEND) {
+ /*
+ * Get the written sector for zone append operation that were
+ * emulated using regular write operations.
+ */
+ zwp_offset = READ_ONCE(md->zwp_offset[zno]);
+ if (WARN_ON_ONCE(zwp_offset < bio_sectors(orig_bio)))
+ WRITE_ONCE(md->zwp_offset[zno],
+ DM_ZONE_INVALID_WP_OFST);
+ else
+ orig_bio->bi_iter.bi_sector +=
+ zwp_offset - bio_sectors(orig_bio);
+ }
+
+ dm_zone_unlock(q, zno, clone);
+}
diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c
index 039d17b28938..ee4626d08557 100644
--- a/drivers/md/dm-zoned-metadata.c
+++ b/drivers/md/dm-zoned-metadata.c
@@ -1390,6 +1390,13 @@ static int dmz_init_zone(struct blk_zone *blkz, unsigned int num, void *data)
return -ENXIO;
}
+ /*
+ * Devices that have zones with a capacity smaller than the zone size
+ * (e.g. NVMe zoned namespaces) are not supported.
+ */
+ if (blkz->capacity != blkz->len)
+ return -ENXIO;
+
switch (blkz->type) {
case BLK_ZONE_TYPE_CONVENTIONAL:
set_bit(DMZ_RND, &zone->flags);
diff --git a/drivers/md/dm-zoned-reclaim.c b/drivers/md/dm-zoned-reclaim.c
index 9c0ecc9568a4..d58db9a27e6c 100644
--- a/drivers/md/dm-zoned-reclaim.c
+++ b/drivers/md/dm-zoned-reclaim.c
@@ -134,7 +134,7 @@ static int dmz_reclaim_copy(struct dmz_reclaim *zrc,
dst_zone_block = dmz_start_block(zmd, dst_zone);
if (dmz_is_seq(dst_zone))
- set_bit(DM_KCOPYD_WRITE_SEQ, &flags);
+ flags |= BIT(DM_KCOPYD_WRITE_SEQ);
while (block < end_block) {
if (src_zone->dev->flags & DMZ_BDEV_DYING)
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index ca2aedd8ee7d..2c5f9e585211 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -74,38 +74,6 @@ struct clone_info {
unsigned sector_count;
};
-/*
- * One of these is allocated per clone bio.
- */
-#define DM_TIO_MAGIC 7282014
-struct dm_target_io {
- unsigned magic;
- struct dm_io *io;
- struct dm_target *ti;
- unsigned target_bio_nr;
- unsigned *len_ptr;
- bool inside_dm_io;
- struct bio clone;
-};
-
-/*
- * One of these is allocated per original bio.
- * It contains the first clone used for that original.
- */
-#define DM_IO_MAGIC 5191977
-struct dm_io {
- unsigned magic;
- struct mapped_device *md;
- blk_status_t status;
- atomic_t io_count;
- struct bio *orig_bio;
- unsigned long start_time;
- spinlock_t endio_lock;
- struct dm_stats_aux stats_aux;
- /* last member of dm_target_io is 'struct bio' */
- struct dm_target_io tio;
-};
-
#define DM_TARGET_IO_BIO_OFFSET (offsetof(struct dm_target_io, clone))
#define DM_IO_BIO_OFFSET \
(offsetof(struct dm_target_io, clone) + offsetof(struct dm_io, tio))
@@ -137,19 +105,6 @@ EXPORT_SYMBOL_GPL(dm_bio_get_target_bio_nr);
#define MINOR_ALLOCED ((void *)-1)
-/*
- * Bits for the md->flags field.
- */
-#define DMF_BLOCK_IO_FOR_SUSPEND 0
-#define DMF_SUSPENDED 1
-#define DMF_FROZEN 2
-#define DMF_FREEING 3
-#define DMF_DELETING 4
-#define DMF_NOFLUSH_SUSPENDING 5
-#define DMF_DEFERRED_REMOVE 6
-#define DMF_SUSPENDED_INTERNALLY 7
-#define DMF_POST_SUSPENDING 8
-
#define DM_NUMA_NODE NUMA_NO_NODE
static int dm_numa_node = DM_NUMA_NODE;
@@ -444,84 +399,6 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return dm_get_geometry(md, geo);
}
-#ifdef CONFIG_BLK_DEV_ZONED
-int dm_report_zones_cb(struct blk_zone *zone, unsigned int idx, void *data)
-{
- struct dm_report_zones_args *args = data;
- sector_t sector_diff = args->tgt->begin - args->start;
-
- /*
- * Ignore zones beyond the target range.
- */
- if (zone->start >= args->start + args->tgt->len)
- return 0;
-
- /*
- * Remap the start sector and write pointer position of the zone
- * to match its position in the target range.
- */
- zone->start += sector_diff;
- if (zone->type != BLK_ZONE_TYPE_CONVENTIONAL) {
- if (zone->cond == BLK_ZONE_COND_FULL)
- zone->wp = zone->start + zone->len;
- else if (zone->cond == BLK_ZONE_COND_EMPTY)
- zone->wp = zone->start;
- else
- zone->wp += sector_diff;
- }
-
- args->next_sector = zone->start + zone->len;
- return args->orig_cb(zone, args->zone_idx++, args->orig_data);
-}
-EXPORT_SYMBOL_GPL(dm_report_zones_cb);
-
-static int dm_blk_report_zones(struct gendisk *disk, sector_t sector,
- unsigned int nr_zones, report_zones_cb cb, void *data)
-{
- struct mapped_device *md = disk->private_data;
- struct dm_table *map;
- int srcu_idx, ret;
- struct dm_report_zones_args args = {
- .next_sector = sector,
- .orig_data = data,
- .orig_cb = cb,
- };
-
- if (dm_suspended_md(md))
- return -EAGAIN;
-
- map = dm_get_live_table(md, &srcu_idx);
- if (!map) {
- ret = -EIO;
- goto out;
- }
-
- do {
- struct dm_target *tgt;
-
- tgt = dm_table_find_target(map, args.next_sector);
- if (WARN_ON_ONCE(!tgt->type->report_zones)) {
- ret = -EIO;
- goto out;
- }
-
- args.tgt = tgt;
- ret = tgt->type->report_zones(tgt, &args,
- nr_zones - args.zone_idx);
- if (ret < 0)
- goto out;
- } while (args.zone_idx < nr_zones &&
- args.next_sector < get_capacity(disk));
-
- ret = args.zone_idx;
-out:
- dm_put_live_table(md, srcu_idx);
- return ret;
-}
-#else
-#define dm_blk_report_zones NULL
-#endif /* CONFIG_BLK_DEV_ZONED */
-
static int dm_prepare_ioctl(struct mapped_device *md, int *srcu_idx,
struct block_device **bdev)
{
@@ -903,7 +780,7 @@ static int __noflush_suspending(struct mapped_device *md)
* Decrements the number of outstanding ios that a bio has been
* cloned into, completing the original io if necc.
*/
-static void dec_pending(struct dm_io *io, blk_status_t error)
+void dm_io_dec_pending(struct dm_io *io, blk_status_t error)
{
unsigned long flags;
blk_status_t io_error;
@@ -919,22 +796,27 @@ static void dec_pending(struct dm_io *io, blk_status_t error)
}
if (atomic_dec_and_test(&io->io_count)) {
+ bio = io->orig_bio;
if (io->status == BLK_STS_DM_REQUEUE) {
/*
* Target requested pushing back the I/O.
*/
spin_lock_irqsave(&md->deferred_lock, flags);
- if (__noflush_suspending(md))
+ if (__noflush_suspending(md) &&
+ !WARN_ON_ONCE(dm_is_zone_write(md, bio))) {
/* NOTE early return due to BLK_STS_DM_REQUEUE below */
- bio_list_add_head(&md->deferred, io->orig_bio);
- else
- /* noflush suspend was interrupted. */
+ bio_list_add_head(&md->deferred, bio);
+ } else {
+ /*
+ * noflush suspend was interrupted or this is
+ * a write to a zoned target.
+ */
io->status = BLK_STS_IOERR;
+ }
spin_unlock_irqrestore(&md->deferred_lock, flags);
}
io_error = io->status;
- bio = io->orig_bio;
end_io_acct(io);
free_io(md, io);
@@ -994,7 +876,6 @@ static void clone_endio(struct bio *bio)
struct dm_io *io = tio->io;
struct mapped_device *md = tio->io->md;
dm_endio_fn endio = tio->ti->type->end_io;
- struct bio *orig_bio = io->orig_bio;
struct request_queue *q = bio->bi_bdev->bd_disk->queue;
if (unlikely(error == BLK_STS_TARGET)) {
@@ -1009,23 +890,22 @@ static void clone_endio(struct bio *bio)
disable_write_zeroes(md);
}
- /*
- * For zone-append bios get offset in zone of the written
- * sector and add that to the original bio sector pos.
- */
- if (bio_op(orig_bio) == REQ_OP_ZONE_APPEND) {
- sector_t written_sector = bio->bi_iter.bi_sector;
- struct request_queue *q = orig_bio->bi_bdev->bd_disk->queue;
- u64 mask = (u64)blk_queue_zone_sectors(q) - 1;
-
- orig_bio->bi_iter.bi_sector += written_sector & mask;
- }
+ if (blk_queue_is_zoned(q))
+ dm_zone_endio(io, bio);
if (endio) {
int r = endio(tio->ti, bio, &error);
switch (r) {
case DM_ENDIO_REQUEUE:
- error = BLK_STS_DM_REQUEUE;
+ /*
+ * Requeuing writes to a sequential zone of a zoned
+ * target will break the sequential write pattern:
+ * fail such IO.
+ */
+ if (WARN_ON_ONCE(dm_is_zone_write(md, bio)))
+ error = BLK_STS_IOERR;
+ else
+ error = BLK_STS_DM_REQUEUE;
fallthrough;
case DM_ENDIO_DONE:
break;
@@ -1044,7 +924,7 @@ static void clone_endio(struct bio *bio)
}
free_tio(tio);
- dec_pending(io, error);
+ dm_io_dec_pending(io, error);
}
/*
@@ -1237,8 +1117,8 @@ static int dm_dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
/*
* A target may call dm_accept_partial_bio only from the map routine. It is
- * allowed for all bio types except REQ_PREFLUSH, REQ_OP_ZONE_RESET,
- * REQ_OP_ZONE_OPEN, REQ_OP_ZONE_CLOSE and REQ_OP_ZONE_FINISH.
+ * allowed for all bio types except REQ_PREFLUSH, REQ_OP_ZONE_* zone management
+ * operations and REQ_OP_ZONE_APPEND (zone append writes).
*
* dm_accept_partial_bio informs the dm that the target only wants to process
* additional n_sectors sectors of the bio and the rest of the data should be
@@ -1268,9 +1148,13 @@ void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors)
{
struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone);
unsigned bi_size = bio->bi_iter.bi_size >> SECTOR_SHIFT;
+
BUG_ON(bio->bi_opf & REQ_PREFLUSH);
+ BUG_ON(op_is_zone_mgmt(bio_op(bio)));
+ BUG_ON(bio_op(bio) == REQ_OP_ZONE_APPEND);
BUG_ON(bi_size > *tio->len_ptr);
BUG_ON(n_sectors > bi_size);
+
*tio->len_ptr -= bi_size - n_sectors;
bio->bi_iter.bi_size = n_sectors << SECTOR_SHIFT;
}
@@ -1308,7 +1192,7 @@ static blk_qc_t __map_bio(struct dm_target_io *tio)
* anything, the target has assumed ownership of
* this io.
*/
- atomic_inc(&io->io_count);
+ dm_io_inc_pending(io);
sector = clone->bi_iter.bi_sector;
if (unlikely(swap_bios_limit(ti, clone))) {
@@ -1319,7 +1203,16 @@ static blk_qc_t __map_bio(struct dm_target_io *tio)
down(&md->swap_bios_semaphore);
}
- r = ti->type->map(ti, clone);
+ /*
+ * Check if the IO needs a special mapping due to zone append emulation
+ * on zoned target. In this case, dm_zone_map_bio() calls the target
+ * map operation.
+ */
+ if (dm_emulate_zone_append(io->md))
+ r = dm_zone_map_bio(tio);
+ else
+ r = ti->type->map(ti, clone);
+
switch (r) {
case DM_MAPIO_SUBMITTED:
break;
@@ -1334,7 +1227,7 @@ static blk_qc_t __map_bio(struct dm_target_io *tio)
up(&md->swap_bios_semaphore);
}
free_tio(tio);
- dec_pending(io, BLK_STS_IOERR);
+ dm_io_dec_pending(io, BLK_STS_IOERR);
break;
case DM_MAPIO_REQUEUE:
if (unlikely(swap_bios_limit(ti, clone))) {
@@ -1342,7 +1235,7 @@ static blk_qc_t __map_bio(struct dm_target_io *tio)
up(&md->swap_bios_semaphore);
}
free_tio(tio);
- dec_pending(io, BLK_STS_DM_REQUEUE);
+ dm_io_dec_pending(io, BLK_STS_DM_REQUEUE);
break;
default:
DMWARN("unimplemented target map return value: %d", r);
@@ -1631,7 +1524,7 @@ static blk_qc_t __split_and_process_bio(struct mapped_device *md,
if (bio->bi_opf & REQ_PREFLUSH) {
error = __send_empty_flush(&ci);
- /* dec_pending submits any data associated with flush */
+ /* dm_io_dec_pending submits any data associated with flush */
} else if (op_is_zone_mgmt(bio_op(bio))) {
ci.bio = bio;
ci.sector_count = 0;
@@ -1672,7 +1565,7 @@ static blk_qc_t __split_and_process_bio(struct mapped_device *md,
}
/* drop the extra reference count */
- dec_pending(ci.io, errno_to_blk_status(error));
+ dm_io_dec_pending(ci.io, errno_to_blk_status(error));
return ret;
}
@@ -1801,13 +1694,13 @@ static void cleanup_mapped_device(struct mapped_device *md)
md->disk->private_data = NULL;
spin_unlock(&_minor_lock);
del_gendisk(md->disk);
- put_disk(md->disk);
}
- if (md->queue) {
+ if (md->queue)
dm_queue_destroy_keyslot_manager(md->queue);
- blk_cleanup_queue(md->queue);
- }
+
+ if (md->disk)
+ blk_cleanup_disk(md->disk);
cleanup_srcu_struct(&md->io_barrier);
@@ -1817,6 +1710,7 @@ static void cleanup_mapped_device(struct mapped_device *md)
mutex_destroy(&md->swap_bios_lock);
dm_mq_cleanup_mapped_device(md);
+ dm_cleanup_zoned_dev(md);
}
/*
@@ -1869,13 +1763,10 @@ static struct mapped_device *alloc_dev(int minor)
* established. If request-based table is loaded: blk-mq will
* override accordingly.
*/
- md->queue = blk_alloc_queue(numa_node_id);
- if (!md->queue)
- goto bad;
-
- md->disk = alloc_disk_node(1, md->numa_node_id);
+ md->disk = blk_alloc_disk(md->numa_node_id);
if (!md->disk)
goto bad;
+ md->queue = md->disk->queue;
init_waitqueue_head(&md->wait);
INIT_WORK(&md->work, dm_wq_work);
@@ -1888,6 +1779,7 @@ static struct mapped_device *alloc_dev(int minor)
md->disk->major = _major;
md->disk->first_minor = minor;
+ md->disk->minors = 1;
md->disk->fops = &dm_blk_dops;
md->disk->queue = md->queue;
md->disk->private_data = md;
@@ -2062,11 +1954,16 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
goto out;
}
+ ret = dm_table_set_restrictions(t, q, limits);
+ if (ret) {
+ old_map = ERR_PTR(ret);
+ goto out;
+ }
+
old_map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
rcu_assign_pointer(md->map, (void *)t);
md->immutable_target_type = dm_table_get_immutable_target_type(t);
- dm_table_set_restrictions(t, q, limits);
if (old_map)
dm_sync_table(md);
@@ -2185,7 +2082,10 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t)
DMERR("Cannot calculate initial queue limits");
return r;
}
- dm_table_set_restrictions(t, md->queue, &limits);
+ r = dm_table_set_restrictions(t, md->queue, &limits);
+ if (r)
+ return r;
+
blk_register_queue(md->disk);
return 0;
@@ -2328,7 +2228,7 @@ static bool md_in_flight_bios(struct mapped_device *md)
return sum != 0;
}
-static int dm_wait_for_bios_completion(struct mapped_device *md, long task_state)
+static int dm_wait_for_bios_completion(struct mapped_device *md, unsigned int task_state)
{
int r = 0;
DEFINE_WAIT(wait);
@@ -2351,7 +2251,7 @@ static int dm_wait_for_bios_completion(struct mapped_device *md, long task_state
return r;
}
-static int dm_wait_for_completion(struct mapped_device *md, long task_state)
+static int dm_wait_for_completion(struct mapped_device *md, unsigned int task_state)
{
int r = 0;
@@ -2478,7 +2378,7 @@ static void unlock_fs(struct mapped_device *md)
* are being added to md->deferred list.
*/
static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
- unsigned suspend_flags, long task_state,
+ unsigned suspend_flags, unsigned int task_state,
int dmf_suspended_flag)
{
bool do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG;
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index b441ad772c18..742d9c80efe1 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -45,6 +45,8 @@ struct dm_dev_internal {
struct dm_table;
struct dm_md_mempools;
+struct dm_target_io;
+struct dm_io;
/*-----------------------------------------------------------------
* Internal table functions.
@@ -56,8 +58,8 @@ struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector);
bool dm_table_has_no_data_devices(struct dm_table *table);
int dm_calculate_queue_limits(struct dm_table *table,
struct queue_limits *limits);
-void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
- struct queue_limits *limits);
+int dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
+ struct queue_limits *limits);
struct list_head *dm_table_get_devices(struct dm_table *t);
void dm_table_presuspend_targets(struct dm_table *t);
void dm_table_presuspend_undo_targets(struct dm_table *t);
@@ -100,6 +102,30 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t);
*/
#define dm_target_hybrid(t) (dm_target_bio_based(t) && dm_target_request_based(t))
+/*
+ * Zoned targets related functions.
+ */
+int dm_set_zones_restrictions(struct dm_table *t, struct request_queue *q);
+void dm_zone_endio(struct dm_io *io, struct bio *clone);
+#ifdef CONFIG_BLK_DEV_ZONED
+void dm_cleanup_zoned_dev(struct mapped_device *md);
+int dm_blk_report_zones(struct gendisk *disk, sector_t sector,
+ unsigned int nr_zones, report_zones_cb cb, void *data);
+bool dm_is_zone_write(struct mapped_device *md, struct bio *bio);
+int dm_zone_map_bio(struct dm_target_io *io);
+#else
+static inline void dm_cleanup_zoned_dev(struct mapped_device *md) {}
+#define dm_blk_report_zones NULL
+static inline bool dm_is_zone_write(struct mapped_device *md, struct bio *bio)
+{
+ return false;
+}
+static inline int dm_zone_map_bio(struct dm_target_io *tio)
+{
+ return DM_MAPIO_KILL;
+}
+#endif
+
/*-----------------------------------------------------------------
* A registry of target types.
*---------------------------------------------------------------*/
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index ea3130e11680..e29c6298ef5c 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -2616,7 +2616,7 @@ static struct attribute *md_bitmap_attrs[] = {
&max_backlog_used.attr,
NULL
};
-struct attribute_group md_bitmap_group = {
+const struct attribute_group md_bitmap_group = {
.name = "bitmap",
.attrs = md_bitmap_attrs,
};
diff --git a/drivers/md/md-faulty.c b/drivers/md/md-faulty.c
index fda4cb3f936f..c0dc6f2ef4a3 100644
--- a/drivers/md/md-faulty.c
+++ b/drivers/md/md-faulty.c
@@ -357,7 +357,7 @@ static void raid_exit(void)
module_init(raid_init);
module_exit(raid_exit);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Fault injection personality for MD");
+MODULE_DESCRIPTION("Fault injection personality for MD (deprecated)");
MODULE_ALIAS("md-personality-10"); /* faulty */
MODULE_ALIAS("md-faulty");
MODULE_ALIAS("md-level--5");
diff --git a/drivers/md/md-linear.c b/drivers/md/md-linear.c
index 63ed8329a98d..1ff51647a682 100644
--- a/drivers/md/md-linear.c
+++ b/drivers/md/md-linear.c
@@ -312,7 +312,7 @@ static void linear_exit (void)
module_init(linear_init);
module_exit(linear_exit);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Linear device concatenation personality for MD");
+MODULE_DESCRIPTION("Linear device concatenation personality for MD (deprecated)");
MODULE_ALIAS("md-personality-1"); /* LINEAR - deprecated*/
MODULE_ALIAS("md-linear");
MODULE_ALIAS("md-level--1");
diff --git a/drivers/md/md-multipath.c b/drivers/md/md-multipath.c
index 776bbe542db5..e7d6486f090f 100644
--- a/drivers/md/md-multipath.c
+++ b/drivers/md/md-multipath.c
@@ -471,7 +471,7 @@ static void __exit multipath_exit (void)
module_init(multipath_init);
module_exit(multipath_exit);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("simple multi-path personality for MD");
+MODULE_DESCRIPTION("simple multi-path personality for MD (deprecated)");
MODULE_ALIAS("md-personality-7"); /* MULTIPATH */
MODULE_ALIAS("md-multipath");
MODULE_ALIAS("md-level--4");
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 49f897fbb89b..ae8fe54ea358 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -441,30 +441,6 @@ check_suspended:
}
EXPORT_SYMBOL(md_handle_request);
-struct md_io {
- struct mddev *mddev;
- bio_end_io_t *orig_bi_end_io;
- void *orig_bi_private;
- struct block_device *orig_bi_bdev;
- unsigned long start_time;
-};
-
-static void md_end_io(struct bio *bio)
-{
- struct md_io *md_io = bio->bi_private;
- struct mddev *mddev = md_io->mddev;
-
- bio_end_io_acct_remapped(bio, md_io->start_time, md_io->orig_bi_bdev);
-
- bio->bi_end_io = md_io->orig_bi_end_io;
- bio->bi_private = md_io->orig_bi_private;
-
- mempool_free(md_io, &mddev->md_io_pool);
-
- if (bio->bi_end_io)
- bio->bi_end_io(bio);
-}
-
static blk_qc_t md_submit_bio(struct bio *bio)
{
const int rw = bio_data_dir(bio);
@@ -489,21 +465,6 @@ static blk_qc_t md_submit_bio(struct bio *bio)
return BLK_QC_T_NONE;
}
- if (bio->bi_end_io != md_end_io) {
- struct md_io *md_io;
-
- md_io = mempool_alloc(&mddev->md_io_pool, GFP_NOIO);
- md_io->mddev = mddev;
- md_io->orig_bi_end_io = bio->bi_end_io;
- md_io->orig_bi_private = bio->bi_private;
- md_io->orig_bi_bdev = bio->bi_bdev;
-
- bio->bi_end_io = md_end_io;
- bio->bi_private = md_io;
-
- md_io->start_time = bio_start_io_acct(bio);
- }
-
/* bio could be mergeable after passing to underlayer */
bio->bi_opf &= ~REQ_NOMERGE;
@@ -824,7 +785,7 @@ out_free_new:
return ERR_PTR(error);
}
-static struct attribute_group md_redundancy_group;
+static const struct attribute_group md_redundancy_group;
void mddev_unlock(struct mddev *mddev)
{
@@ -841,7 +802,7 @@ void mddev_unlock(struct mddev *mddev)
* test it under the same mutex to ensure its correct value
* is seen.
*/
- struct attribute_group *to_remove = mddev->to_remove;
+ const struct attribute_group *to_remove = mddev->to_remove;
mddev->to_remove = NULL;
mddev->sysfs_active = 1;
mutex_unlock(&mddev->reconfig_mutex);
@@ -2379,7 +2340,15 @@ int md_integrity_register(struct mddev *mddev)
bdev_get_integrity(reference->bdev));
pr_debug("md: data integrity enabled on %s\n", mdname(mddev));
- if (bioset_integrity_create(&mddev->bio_set, BIO_POOL_SIZE)) {
+ if (bioset_integrity_create(&mddev->bio_set, BIO_POOL_SIZE) ||
+ (mddev->level != 1 && mddev->level != 10 &&
+ bioset_integrity_create(&mddev->io_acct_set, BIO_POOL_SIZE))) {
+ /*
+ * No need to handle the failure of bioset_integrity_create,
+ * because the function is called by md_run() -> pers->run(),
+ * md_run calls bioset_exit -> bioset_integrity_free in case
+ * of failure case.
+ */
pr_err("md: failed to create integrity pool for %s\n",
mdname(mddev));
return -EINVAL;
@@ -5538,7 +5507,7 @@ static struct attribute *md_redundancy_attrs[] = {
&md_degraded.attr,
NULL,
};
-static struct attribute_group md_redundancy_group = {
+static const struct attribute_group md_redundancy_group = {
.name = NULL,
.attrs = md_redundancy_attrs,
};
@@ -5598,17 +5567,16 @@ static void md_free(struct kobject *ko)
if (mddev->sysfs_level)
sysfs_put(mddev->sysfs_level);
- if (mddev->gendisk)
+ if (mddev->gendisk) {
del_gendisk(mddev->gendisk);
- if (mddev->queue)
- blk_cleanup_queue(mddev->queue);
- if (mddev->gendisk)
- put_disk(mddev->gendisk);
+ blk_cleanup_disk(mddev->gendisk);
+ }
percpu_ref_exit(&mddev->writes_pending);
bioset_exit(&mddev->bio_set);
bioset_exit(&mddev->sync_set);
- mempool_exit(&mddev->md_io_pool);
+ if (mddev->level != 1 && mddev->level != 10)
+ bioset_exit(&mddev->io_acct_set);
kfree(mddev);
}
@@ -5705,26 +5673,14 @@ static int md_alloc(dev_t dev, char *name)
*/
mddev->hold_active = UNTIL_STOP;
- error = mempool_init_kmalloc_pool(&mddev->md_io_pool, BIO_POOL_SIZE,
- sizeof(struct md_io));
- if (error)
- goto abort;
-
error = -ENOMEM;
- mddev->queue = blk_alloc_queue(NUMA_NO_NODE);
- if (!mddev->queue)
+ disk = blk_alloc_disk(NUMA_NO_NODE);
+ if (!disk)
goto abort;
- blk_set_stacking_limits(&mddev->queue->limits);
-
- disk = alloc_disk(1 << shift);
- if (!disk) {
- blk_cleanup_queue(mddev->queue);
- mddev->queue = NULL;
- goto abort;
- }
disk->major = MAJOR(mddev->unit);
disk->first_minor = unit << shift;
+ disk->minors = 1 << shift;
if (name)
strcpy(disk->disk_name, name);
else if (partitioned)
@@ -5733,7 +5689,9 @@ static int md_alloc(dev_t dev, char *name)
sprintf(disk->disk_name, "md%d", unit);
disk->fops = &md_fops;
disk->private_data = mddev;
- disk->queue = mddev->queue;
+
+ mddev->queue = disk->queue;
+ blk_set_stacking_limits(&mddev->queue->limits);
blk_queue_write_cache(mddev->queue, true, true);
/* Allow extended partitions. This makes the
* 'mdp' device redundant, but we can't really
@@ -5907,7 +5865,14 @@ int md_run(struct mddev *mddev)
if (!bioset_initialized(&mddev->sync_set)) {
err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
if (err)
- return err;
+ goto exit_bio_set;
+ }
+ if (mddev->level != 1 && mddev->level != 10 &&
+ !bioset_initialized(&mddev->io_acct_set)) {
+ err = bioset_init(&mddev->io_acct_set, BIO_POOL_SIZE,
+ offsetof(struct md_io_acct, bio_clone), 0);
+ if (err)
+ goto exit_sync_set;
}
spin_lock(&pers_lock);
@@ -6035,6 +6000,7 @@ int md_run(struct mddev *mddev)
blk_queue_flag_set(QUEUE_FLAG_NONROT, mddev->queue);
else
blk_queue_flag_clear(QUEUE_FLAG_NONROT, mddev->queue);
+ blk_queue_flag_set(QUEUE_FLAG_IO_STAT, mddev->queue);
}
if (pers->sync_request) {
if (mddev->kobj.sd &&
@@ -6084,8 +6050,12 @@ bitmap_abort:
module_put(pers->owner);
md_bitmap_destroy(mddev);
abort:
- bioset_exit(&mddev->bio_set);
+ if (mddev->level != 1 && mddev->level != 10)
+ bioset_exit(&mddev->io_acct_set);
+exit_sync_set:
bioset_exit(&mddev->sync_set);
+exit_bio_set:
+ bioset_exit(&mddev->bio_set);
return err;
}
EXPORT_SYMBOL_GPL(md_run);
@@ -6309,6 +6279,8 @@ void md_stop(struct mddev *mddev)
__md_stop(mddev);
bioset_exit(&mddev->bio_set);
bioset_exit(&mddev->sync_set);
+ if (mddev->level != 1 && mddev->level != 10)
+ bioset_exit(&mddev->io_acct_set);
}
EXPORT_SYMBOL_GPL(md_stop);
@@ -8613,6 +8585,41 @@ void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
}
EXPORT_SYMBOL_GPL(md_submit_discard_bio);
+static void md_end_io_acct(struct bio *bio)
+{
+ struct md_io_acct *md_io_acct = bio->bi_private;
+ struct bio *orig_bio = md_io_acct->orig_bio;
+
+ orig_bio->bi_status = bio->bi_status;
+
+ bio_end_io_acct(orig_bio, md_io_acct->start_time);
+ bio_put(bio);
+ bio_endio(orig_bio);
+}
+
+/*
+ * Used by personalities that don't already clone the bio and thus can't
+ * easily add the timestamp to their extended bio structure.
+ */
+void md_account_bio(struct mddev *mddev, struct bio **bio)
+{
+ struct md_io_acct *md_io_acct;
+ struct bio *clone;
+
+ if (!blk_queue_io_stat((*bio)->bi_bdev->bd_disk->queue))
+ return;
+
+ clone = bio_clone_fast(*bio, GFP_NOIO, &mddev->io_acct_set);
+ md_io_acct = container_of(clone, struct md_io_acct, bio_clone);
+ md_io_acct->orig_bio = *bio;
+ md_io_acct->start_time = bio_start_io_acct(*bio);
+
+ clone->bi_end_io = md_end_io_acct;
+ clone->bi_private = md_io_acct;
+ *bio = clone;
+}
+EXPORT_SYMBOL_GPL(md_account_bio);
+
/* md_allow_write(mddev)
* Calling this ensures that the array is marked 'active' so that writes
* may proceed without blocking. It is important to call this before
diff --git a/drivers/md/md.h b/drivers/md/md.h
index fb7eab58cfd5..832547cf038f 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -395,10 +395,10 @@ struct mddev {
* that we are never stopping an array while it is open.
* 'reconfig_mutex' protects all other reconfiguration.
* These locks are separate due to conflicting interactions
- * with bdev->bd_mutex.
+ * with disk->open_mutex.
* Lock ordering is:
- * reconfig_mutex -> bd_mutex
- * bd_mutex -> open_mutex: e.g. __blkdev_get -> md_open
+ * reconfig_mutex -> disk->open_mutex
+ * disk->open_mutex -> open_mutex: e.g. __blkdev_get -> md_open
*/
struct mutex open_mutex;
struct mutex reconfig_mutex;
@@ -481,13 +481,13 @@ struct mddev {
atomic_t max_corr_read_errors; /* max read retries */
struct list_head all_mddevs;
- struct attribute_group *to_remove;
+ const struct attribute_group *to_remove;
struct bio_set bio_set;
struct bio_set sync_set; /* for sync operations like
* metadata and bitmap writes
*/
- mempool_t md_io_pool;
+ struct bio_set io_acct_set; /* for raid0 and raid5 io accounting */
/* Generic flush handling.
* The last to finish preflush schedules a worker to submit
@@ -613,7 +613,7 @@ struct md_sysfs_entry {
ssize_t (*show)(struct mddev *, char *);
ssize_t (*store)(struct mddev *, const char *, size_t);
};
-extern struct attribute_group md_bitmap_group;
+extern const struct attribute_group md_bitmap_group;
static inline struct kernfs_node *sysfs_get_dirent_safe(struct kernfs_node *sd, char *name)
{
@@ -684,6 +684,12 @@ struct md_thread {
void *private;
};
+struct md_io_acct {
+ struct bio *orig_bio;
+ unsigned long start_time;
+ struct bio bio_clone;
+};
+
#define THREAD_WAKEUP 0
static inline void safe_put_page(struct page *p)
@@ -715,6 +721,7 @@ extern void md_error(struct mddev *mddev, struct md_rdev *rdev);
extern void md_finish_reshape(struct mddev *mddev);
void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
struct bio *bio, sector_t start, sector_t size);
+void md_account_bio(struct mddev *mddev, struct bio **bio);
extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio);
extern void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
diff --git a/drivers/md/persistent-data/dm-array.c b/drivers/md/persistent-data/dm-array.c
index 185dc60360b5..3a963d783a86 100644
--- a/drivers/md/persistent-data/dm-array.c
+++ b/drivers/md/persistent-data/dm-array.c
@@ -108,12 +108,10 @@ static void *element_at(struct dm_array_info *info, struct array_block *ab,
* in an array block.
*/
static void on_entries(struct dm_array_info *info, struct array_block *ab,
- void (*fn)(void *, const void *))
+ void (*fn)(void *, const void *, unsigned))
{
- unsigned i, nr_entries = le32_to_cpu(ab->nr_entries);
-
- for (i = 0; i < nr_entries; i++)
- fn(info->value_type.context, element_at(info, ab, i));
+ unsigned nr_entries = le32_to_cpu(ab->nr_entries);
+ fn(info->value_type.context, element_at(info, ab, 0), nr_entries);
}
/*
@@ -175,19 +173,18 @@ static int alloc_ablock(struct dm_array_info *info, size_t size_of_block,
static void fill_ablock(struct dm_array_info *info, struct array_block *ab,
const void *value, unsigned new_nr)
{
- unsigned i;
- uint32_t nr_entries;
+ uint32_t nr_entries, delta, i;
struct dm_btree_value_type *vt = &info->value_type;
BUG_ON(new_nr > le32_to_cpu(ab->max_entries));
BUG_ON(new_nr < le32_to_cpu(ab->nr_entries));
nr_entries = le32_to_cpu(ab->nr_entries);
- for (i = nr_entries; i < new_nr; i++) {
- if (vt->inc)
- vt->inc(vt->context, value);
+ delta = new_nr - nr_entries;
+ if (vt->inc)
+ vt->inc(vt->context, value, delta);
+ for (i = nr_entries; i < new_nr; i++)
memcpy(element_at(info, ab, i), value, vt->size);
- }
ab->nr_entries = cpu_to_le32(new_nr);
}
@@ -199,17 +196,16 @@ static void fill_ablock(struct dm_array_info *info, struct array_block *ab,
static void trim_ablock(struct dm_array_info *info, struct array_block *ab,
unsigned new_nr)
{
- unsigned i;
- uint32_t nr_entries;
+ uint32_t nr_entries, delta;
struct dm_btree_value_type *vt = &info->value_type;
BUG_ON(new_nr > le32_to_cpu(ab->max_entries));
BUG_ON(new_nr > le32_to_cpu(ab->nr_entries));
nr_entries = le32_to_cpu(ab->nr_entries);
- for (i = nr_entries; i > new_nr; i--)
- if (vt->dec)
- vt->dec(vt->context, element_at(info, ab, i - 1));
+ delta = nr_entries - new_nr;
+ if (vt->dec)
+ vt->dec(vt->context, element_at(info, ab, new_nr - 1), delta);
ab->nr_entries = cpu_to_le32(new_nr);
}
@@ -573,16 +569,17 @@ static int grow(struct resize *resize)
* These are the value_type functions for the btree elements, which point
* to array blocks.
*/
-static void block_inc(void *context, const void *value)
+static void block_inc(void *context, const void *value, unsigned count)
{
- __le64 block_le;
+ const __le64 *block_le = value;
struct dm_array_info *info = context;
+ unsigned i;
- memcpy(&block_le, value, sizeof(block_le));
- dm_tm_inc(info->btree_info.tm, le64_to_cpu(block_le));
+ for (i = 0; i < count; i++, block_le++)
+ dm_tm_inc(info->btree_info.tm, le64_to_cpu(*block_le));
}
-static void block_dec(void *context, const void *value)
+static void __block_dec(void *context, const void *value)
{
int r;
uint64_t b;
@@ -621,6 +618,13 @@ static void block_dec(void *context, const void *value)
dm_tm_dec(info->btree_info.tm, b);
}
+static void block_dec(void *context, const void *value, unsigned count)
+{
+ unsigned i;
+ for (i = 0; i < count; i++, value += sizeof(__le64))
+ __block_dec(context, value);
+}
+
static int block_equal(void *context, const void *value1, const void *value2)
{
return !memcmp(value1, value2, sizeof(__le64));
@@ -711,7 +715,7 @@ static int populate_ablock_with_values(struct dm_array_info *info, struct array_
return r;
if (vt->inc)
- vt->inc(vt->context, element_at(info, ab, i));
+ vt->inc(vt->context, element_at(info, ab, i), 1);
}
ab->nr_entries = cpu_to_le32(new_nr);
@@ -822,9 +826,9 @@ static int array_set_value(struct dm_array_info *info, dm_block_t root,
old_value = element_at(info, ab, entry);
if (vt->dec &&
(!vt->equal || !vt->equal(vt->context, old_value, value))) {
- vt->dec(vt->context, old_value);
+ vt->dec(vt->context, old_value, 1);
if (vt->inc)
- vt->inc(vt->context, value);
+ vt->inc(vt->context, value, 1);
}
memcpy(old_value, value, info->value_type.size);
diff --git a/drivers/md/persistent-data/dm-btree-internal.h b/drivers/md/persistent-data/dm-btree-internal.h
index b1788853a355..893edb426dba 100644
--- a/drivers/md/persistent-data/dm-btree-internal.h
+++ b/drivers/md/persistent-data/dm-btree-internal.h
@@ -144,4 +144,17 @@ extern struct dm_block_validator btree_node_validator;
extern void init_le64_type(struct dm_transaction_manager *tm,
struct dm_btree_value_type *vt);
+/*
+ * This returns a shadowed btree leaf that you may modify. In practise
+ * this means overwrites only, since an insert could cause a node to
+ * be split. Useful if you need access to the old value to calculate the
+ * new one.
+ *
+ * This only works with single level btrees. The given key must be present in
+ * the tree, otherwise -EINVAL will be returned.
+ */
+int btree_get_overwrite_leaf(struct dm_btree_info *info, dm_block_t root,
+ uint64_t key, int *index,
+ dm_block_t *new_root, struct dm_block **leaf);
+
#endif /* DM_BTREE_INTERNAL_H */
diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c
index eff04fa23dfa..70532335c7c7 100644
--- a/drivers/md/persistent-data/dm-btree-remove.c
+++ b/drivers/md/persistent-data/dm-btree-remove.c
@@ -544,12 +544,13 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
if (info->value_type.dec)
info->value_type.dec(info->value_type.context,
- value_ptr(n, index));
+ value_ptr(n, index), 1);
delete_at(n, index);
}
- *new_root = shadow_root(&spine);
+ if (!r)
+ *new_root = shadow_root(&spine);
exit_shadow_spine(&spine);
return r;
@@ -653,7 +654,7 @@ static int remove_one(struct dm_btree_info *info, dm_block_t root,
if (k >= keys[last_level] && k < end_key) {
if (info->value_type.dec)
info->value_type.dec(info->value_type.context,
- value_ptr(n, index));
+ value_ptr(n, index), 1);
delete_at(n, index);
keys[last_level] = k + 1ull;
diff --git a/drivers/md/persistent-data/dm-btree-spine.c b/drivers/md/persistent-data/dm-btree-spine.c
index 2061ab865567..f5bd76ed8fe6 100644
--- a/drivers/md/persistent-data/dm-btree-spine.c
+++ b/drivers/md/persistent-data/dm-btree-spine.c
@@ -236,22 +236,14 @@ dm_block_t shadow_root(struct shadow_spine *s)
return s->root;
}
-static void le64_inc(void *context, const void *value_le)
+static void le64_inc(void *context, const void *value_le, unsigned count)
{
- struct dm_transaction_manager *tm = context;
- __le64 v_le;
-
- memcpy(&v_le, value_le, sizeof(v_le));
- dm_tm_inc(tm, le64_to_cpu(v_le));
+ dm_tm_with_runs(context, value_le, count, dm_tm_inc_range);
}
-static void le64_dec(void *context, const void *value_le)
+static void le64_dec(void *context, const void *value_le, unsigned count)
{
- struct dm_transaction_manager *tm = context;
- __le64 v_le;
-
- memcpy(&v_le, value_le, sizeof(v_le));
- dm_tm_dec(tm, le64_to_cpu(v_le));
+ dm_tm_with_runs(context, value_le, count, dm_tm_dec_range);
}
static int le64_equal(void *context, const void *value1_le, const void *value2_le)
diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c
index ef6e78d45d5b..0703ca7a7d9a 100644
--- a/drivers/md/persistent-data/dm-btree.c
+++ b/drivers/md/persistent-data/dm-btree.c
@@ -71,15 +71,13 @@ static int upper_bound(struct btree_node *n, uint64_t key)
void inc_children(struct dm_transaction_manager *tm, struct btree_node *n,
struct dm_btree_value_type *vt)
{
- unsigned i;
uint32_t nr_entries = le32_to_cpu(n->header.nr_entries);
if (le32_to_cpu(n->header.flags) & INTERNAL_NODE)
- for (i = 0; i < nr_entries; i++)
- dm_tm_inc(tm, value64(n, i));
+ dm_tm_with_runs(tm, value_ptr(n, 0), nr_entries, dm_tm_inc_range);
+
else if (vt->inc)
- for (i = 0; i < nr_entries; i++)
- vt->inc(vt->context, value_ptr(n, i));
+ vt->inc(vt->context, value_ptr(n, 0), nr_entries);
}
static int insert_at(size_t value_size, struct btree_node *node, unsigned index,
@@ -318,13 +316,9 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
goto out;
} else {
- if (info->value_type.dec) {
- unsigned i;
-
- for (i = 0; i < f->nr_children; i++)
- info->value_type.dec(info->value_type.context,
- value_ptr(f->n, i));
- }
+ if (info->value_type.dec)
+ info->value_type.dec(info->value_type.context,
+ value_ptr(f->n, 0), f->nr_children);
pop_frame(s);
}
}
@@ -500,6 +494,122 @@ out:
EXPORT_SYMBOL_GPL(dm_btree_lookup_next);
+/*----------------------------------------------------------------*/
+
+/*
+ * Copies entries from one region of a btree node to another. The regions
+ * must not overlap.
+ */
+static void copy_entries(struct btree_node *dest, unsigned dest_offset,
+ struct btree_node *src, unsigned src_offset,
+ unsigned count)
+{
+ size_t value_size = le32_to_cpu(dest->header.value_size);
+ memcpy(dest->keys + dest_offset, src->keys + src_offset, count * sizeof(uint64_t));
+ memcpy(value_ptr(dest, dest_offset), value_ptr(src, src_offset), count * value_size);
+}
+
+/*
+ * Moves entries from one region fo a btree node to another. The regions
+ * may overlap.
+ */
+static void move_entries(struct btree_node *dest, unsigned dest_offset,
+ struct btree_node *src, unsigned src_offset,
+ unsigned count)
+{
+ size_t value_size = le32_to_cpu(dest->header.value_size);
+ memmove(dest->keys + dest_offset, src->keys + src_offset, count * sizeof(uint64_t));
+ memmove(value_ptr(dest, dest_offset), value_ptr(src, src_offset), count * value_size);
+}
+
+/*
+ * Erases the first 'count' entries of a btree node, shifting following
+ * entries down into their place.
+ */
+static void shift_down(struct btree_node *n, unsigned count)
+{
+ move_entries(n, 0, n, count, le32_to_cpu(n->header.nr_entries) - count);
+}
+
+/*
+ * Moves entries in a btree node up 'count' places, making space for
+ * new entries at the start of the node.
+ */
+static void shift_up(struct btree_node *n, unsigned count)
+{
+ move_entries(n, count, n, 0, le32_to_cpu(n->header.nr_entries));
+}
+
+/*
+ * Redistributes entries between two btree nodes to make them
+ * have similar numbers of entries.
+ */
+static void redistribute2(struct btree_node *left, struct btree_node *right)
+{
+ unsigned nr_left = le32_to_cpu(left->header.nr_entries);
+ unsigned nr_right = le32_to_cpu(right->header.nr_entries);
+ unsigned total = nr_left + nr_right;
+ unsigned target_left = total / 2;
+ unsigned target_right = total - target_left;
+
+ if (nr_left < target_left) {
+ unsigned delta = target_left - nr_left;
+ copy_entries(left, nr_left, right, 0, delta);
+ shift_down(right, delta);
+ } else if (nr_left > target_left) {
+ unsigned delta = nr_left - target_left;
+ if (nr_right)
+ shift_up(right, delta);
+ copy_entries(right, 0, left, target_left, delta);
+ }
+
+ left->header.nr_entries = cpu_to_le32(target_left);
+ right->header.nr_entries = cpu_to_le32(target_right);
+}
+
+/*
+ * Redistribute entries between three nodes. Assumes the central
+ * node is empty.
+ */
+static void redistribute3(struct btree_node *left, struct btree_node *center,
+ struct btree_node *right)
+{
+ unsigned nr_left = le32_to_cpu(left->header.nr_entries);
+ unsigned nr_center = le32_to_cpu(center->header.nr_entries);
+ unsigned nr_right = le32_to_cpu(right->header.nr_entries);
+ unsigned total, target_left, target_center, target_right;
+
+ BUG_ON(nr_center);
+
+ total = nr_left + nr_right;
+ target_left = total / 3;
+ target_center = (total - target_left) / 2;
+ target_right = (total - target_left - target_center);
+
+ if (nr_left < target_left) {
+ unsigned left_short = target_left - nr_left;
+ copy_entries(left, nr_left, right, 0, left_short);
+ copy_entries(center, 0, right, left_short, target_center);
+ shift_down(right, nr_right - target_right);
+
+ } else if (nr_left < (target_left + target_center)) {
+ unsigned left_to_center = nr_left - target_left;
+ copy_entries(center, 0, left, target_left, left_to_center);
+ copy_entries(center, left_to_center, right, 0, target_center - left_to_center);
+ shift_down(right, nr_right - target_right);
+
+ } else {
+ unsigned right_short = target_right - nr_right;
+ shift_up(right, right_short);
+ copy_entries(right, 0, left, nr_left - right_short, right_short);
+ copy_entries(center, 0, left, target_left, nr_left - target_left);
+ }
+
+ left->header.nr_entries = cpu_to_le32(target_left);
+ center->header.nr_entries = cpu_to_le32(target_center);
+ right->header.nr_entries = cpu_to_le32(target_right);
+}
+
/*
* Splits a node by creating a sibling node and shifting half the nodes
* contents across. Assumes there is a parent node, and it has room for
@@ -530,12 +640,10 @@ EXPORT_SYMBOL_GPL(dm_btree_lookup_next);
*
* Where A* is a shadow of A.
*/
-static int btree_split_sibling(struct shadow_spine *s, unsigned parent_index,
- uint64_t key)
+static int split_one_into_two(struct shadow_spine *s, unsigned parent_index,
+ struct dm_btree_value_type *vt, uint64_t key)
{
int r;
- size_t size;
- unsigned nr_left, nr_right;
struct dm_block *left, *right, *parent;
struct btree_node *ln, *rn, *pn;
__le64 location;
@@ -549,36 +657,18 @@ static int btree_split_sibling(struct shadow_spine *s, unsigned parent_index,
ln = dm_block_data(left);
rn = dm_block_data(right);
- nr_left = le32_to_cpu(ln->header.nr_entries) / 2;
- nr_right = le32_to_cpu(ln->header.nr_entries) - nr_left;
-
- ln->header.nr_entries = cpu_to_le32(nr_left);
-
rn->header.flags = ln->header.flags;
- rn->header.nr_entries = cpu_to_le32(nr_right);
+ rn->header.nr_entries = cpu_to_le32(0);
rn->header.max_entries = ln->header.max_entries;
rn->header.value_size = ln->header.value_size;
- memcpy(rn->keys, ln->keys + nr_left, nr_right * sizeof(rn->keys[0]));
-
- size = le32_to_cpu(ln->header.flags) & INTERNAL_NODE ?
- sizeof(uint64_t) : s->info->value_type.size;
- memcpy(value_ptr(rn, 0), value_ptr(ln, nr_left),
- size * nr_right);
+ redistribute2(ln, rn);
- /*
- * Patch up the parent
- */
+ /* patch up the parent */
parent = shadow_parent(s);
-
pn = dm_block_data(parent);
- location = cpu_to_le64(dm_block_location(left));
- __dm_bless_for_disk(&location);
- memcpy_disk(value_ptr(pn, parent_index),
- &location, sizeof(__le64));
location = cpu_to_le64(dm_block_location(right));
__dm_bless_for_disk(&location);
-
r = insert_at(sizeof(__le64), pn, parent_index + 1,
le64_to_cpu(rn->keys[0]), &location);
if (r) {
@@ -586,6 +676,7 @@ static int btree_split_sibling(struct shadow_spine *s, unsigned parent_index,
return r;
}
+ /* patch up the spine */
if (key < le64_to_cpu(rn->keys[0])) {
unlock_block(s->info, right);
s->nodes[1] = left;
@@ -598,6 +689,121 @@ static int btree_split_sibling(struct shadow_spine *s, unsigned parent_index,
}
/*
+ * We often need to modify a sibling node. This function shadows a particular
+ * child of the given parent node. Making sure to update the parent to point
+ * to the new shadow.
+ */
+static int shadow_child(struct dm_btree_info *info, struct dm_btree_value_type *vt,
+ struct btree_node *parent, unsigned index,
+ struct dm_block **result)
+{
+ int r, inc;
+ dm_block_t root;
+ struct btree_node *node;
+
+ root = value64(parent, index);
+
+ r = dm_tm_shadow_block(info->tm, root, &btree_node_validator,
+ result, &inc);
+ if (r)
+ return r;
+
+ node = dm_block_data(*result);
+
+ if (inc)
+ inc_children(info->tm, node, vt);
+
+ *((__le64 *) value_ptr(parent, index)) =
+ cpu_to_le64(dm_block_location(*result));
+
+ return 0;
+}
+
+/*
+ * Splits two nodes into three. This is more work, but results in fuller
+ * nodes, so saves metadata space.
+ */
+static int split_two_into_three(struct shadow_spine *s, unsigned parent_index,
+ struct dm_btree_value_type *vt, uint64_t key)
+{
+ int r;
+ unsigned middle_index;
+ struct dm_block *left, *middle, *right, *parent;
+ struct btree_node *ln, *rn, *mn, *pn;
+ __le64 location;
+
+ parent = shadow_parent(s);
+ pn = dm_block_data(parent);
+
+ if (parent_index == 0) {
+ middle_index = 1;
+ left = shadow_current(s);
+ r = shadow_child(s->info, vt, pn, parent_index + 1, &right);
+ if (r)
+ return r;
+ } else {
+ middle_index = parent_index;
+ right = shadow_current(s);
+ r = shadow_child(s->info, vt, pn, parent_index - 1, &left);
+ if (r)
+ return r;
+ }
+
+ r = new_block(s->info, &middle);
+ if (r < 0)
+ return r;
+
+ ln = dm_block_data(left);
+ mn = dm_block_data(middle);
+ rn = dm_block_data(right);
+
+ mn->header.nr_entries = cpu_to_le32(0);
+ mn->header.flags = ln->header.flags;
+ mn->header.max_entries = ln->header.max_entries;
+ mn->header.value_size = ln->header.value_size;
+
+ redistribute3(ln, mn, rn);
+
+ /* patch up the parent */
+ pn->keys[middle_index] = rn->keys[0];
+ location = cpu_to_le64(dm_block_location(middle));
+ __dm_bless_for_disk(&location);
+ r = insert_at(sizeof(__le64), pn, middle_index,
+ le64_to_cpu(mn->keys[0]), &location);
+ if (r) {
+ if (shadow_current(s) != left)
+ unlock_block(s->info, left);
+
+ unlock_block(s->info, middle);
+
+ if (shadow_current(s) != right)
+ unlock_block(s->info, right);
+
+ return r;
+ }
+
+
+ /* patch up the spine */
+ if (key < le64_to_cpu(mn->keys[0])) {
+ unlock_block(s->info, middle);
+ unlock_block(s->info, right);
+ s->nodes[1] = left;
+ } else if (key < le64_to_cpu(rn->keys[0])) {
+ unlock_block(s->info, left);
+ unlock_block(s->info, right);
+ s->nodes[1] = middle;
+ } else {
+ unlock_block(s->info, left);
+ unlock_block(s->info, middle);
+ s->nodes[1] = right;
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------*/
+
+/*
* Splits a node by creating two new children beneath the given node.
*
* Before:
@@ -690,6 +896,186 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key)
return 0;
}
+/*----------------------------------------------------------------*/
+
+/*
+ * Redistributes a node's entries with its left sibling.
+ */
+static int rebalance_left(struct shadow_spine *s, struct dm_btree_value_type *vt,
+ unsigned parent_index, uint64_t key)
+{
+ int r;
+ struct dm_block *sib;
+ struct btree_node *left, *right, *parent = dm_block_data(shadow_parent(s));
+
+ r = shadow_child(s->info, vt, parent, parent_index - 1, &sib);
+ if (r)
+ return r;
+
+ left = dm_block_data(sib);
+ right = dm_block_data(shadow_current(s));
+ redistribute2(left, right);
+ *key_ptr(parent, parent_index) = right->keys[0];
+
+ if (key < le64_to_cpu(right->keys[0])) {
+ unlock_block(s->info, s->nodes[1]);
+ s->nodes[1] = sib;
+ } else {
+ unlock_block(s->info, sib);
+ }
+
+ return 0;
+}
+
+/*
+ * Redistributes a nodes entries with its right sibling.
+ */
+static int rebalance_right(struct shadow_spine *s, struct dm_btree_value_type *vt,
+ unsigned parent_index, uint64_t key)
+{
+ int r;
+ struct dm_block *sib;
+ struct btree_node *left, *right, *parent = dm_block_data(shadow_parent(s));
+
+ r = shadow_child(s->info, vt, parent, parent_index + 1, &sib);
+ if (r)
+ return r;
+
+ left = dm_block_data(shadow_current(s));
+ right = dm_block_data(sib);
+ redistribute2(left, right);
+ *key_ptr(parent, parent_index + 1) = right->keys[0];
+
+ if (key < le64_to_cpu(right->keys[0])) {
+ unlock_block(s->info, sib);
+ } else {
+ unlock_block(s->info, s->nodes[1]);
+ s->nodes[1] = sib;
+ }
+
+ return 0;
+}
+
+/*
+ * Returns the number of spare entries in a node.
+ */
+static int get_node_free_space(struct dm_btree_info *info, dm_block_t b, unsigned *space)
+{
+ int r;
+ unsigned nr_entries;
+ struct dm_block *block;
+ struct btree_node *node;
+
+ r = bn_read_lock(info, b, &block);
+ if (r)
+ return r;
+
+ node = dm_block_data(block);
+ nr_entries = le32_to_cpu(node->header.nr_entries);
+ *space = le32_to_cpu(node->header.max_entries) - nr_entries;
+
+ unlock_block(info, block);
+ return 0;
+}
+
+/*
+ * Make space in a node, either by moving some entries to a sibling,
+ * or creating a new sibling node. SPACE_THRESHOLD defines the minimum
+ * number of free entries that must be in the sibling to make the move
+ * worth while. If the siblings are shared (eg, part of a snapshot),
+ * then they are not touched, since this break sharing and so consume
+ * more space than we save.
+ */
+#define SPACE_THRESHOLD 8
+static int rebalance_or_split(struct shadow_spine *s, struct dm_btree_value_type *vt,
+ unsigned parent_index, uint64_t key)
+{
+ int r;
+ struct btree_node *parent = dm_block_data(shadow_parent(s));
+ unsigned nr_parent = le32_to_cpu(parent->header.nr_entries);
+ unsigned free_space;
+ int left_shared = 0, right_shared = 0;
+
+ /* Should we move entries to the left sibling? */
+ if (parent_index > 0) {
+ dm_block_t left_b = value64(parent, parent_index - 1);
+ r = dm_tm_block_is_shared(s->info->tm, left_b, &left_shared);
+ if (r)
+ return r;
+
+ if (!left_shared) {
+ r = get_node_free_space(s->info, left_b, &free_space);
+ if (r)
+ return r;
+
+ if (free_space >= SPACE_THRESHOLD)
+ return rebalance_left(s, vt, parent_index, key);
+ }
+ }
+
+ /* Should we move entries to the right sibling? */
+ if (parent_index < (nr_parent - 1)) {
+ dm_block_t right_b = value64(parent, parent_index + 1);
+ r = dm_tm_block_is_shared(s->info->tm, right_b, &right_shared);
+ if (r)
+ return r;
+
+ if (!right_shared) {
+ r = get_node_free_space(s->info, right_b, &free_space);
+ if (r)
+ return r;
+
+ if (free_space >= SPACE_THRESHOLD)
+ return rebalance_right(s, vt, parent_index, key);
+ }
+ }
+
+ /*
+ * We need to split the node, normally we split two nodes
+ * into three. But when inserting a sequence that is either
+ * monotonically increasing or decreasing it's better to split
+ * a single node into two.
+ */
+ if (left_shared || right_shared || (nr_parent <= 2) ||
+ (parent_index == 0) || (parent_index + 1 == nr_parent)) {
+ return split_one_into_two(s, parent_index, vt, key);
+ } else {
+ return split_two_into_three(s, parent_index, vt, key);
+ }
+}
+
+/*
+ * Does the node contain a particular key?
+ */
+static bool contains_key(struct btree_node *node, uint64_t key)
+{
+ int i = lower_bound(node, key);
+
+ if (i >= 0 && le64_to_cpu(node->keys[i]) == key)
+ return true;
+
+ return false;
+}
+
+/*
+ * In general we preemptively make sure there's a free entry in every
+ * node on the spine when doing an insert. But we can avoid that with
+ * leaf nodes if we know it's an overwrite.
+ */
+static bool has_space_for_insert(struct btree_node *node, uint64_t key)
+{
+ if (node->header.nr_entries == node->header.max_entries) {
+ if (le32_to_cpu(node->header.flags) & LEAF_NODE) {
+ /* we don't need space if it's an overwrite */
+ return contains_key(node, key);
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
static int btree_insert_raw(struct shadow_spine *s, dm_block_t root,
struct dm_btree_value_type *vt,
uint64_t key, unsigned *index)
@@ -719,17 +1105,18 @@ static int btree_insert_raw(struct shadow_spine *s, dm_block_t root,
node = dm_block_data(shadow_current(s));
- if (node->header.nr_entries == node->header.max_entries) {
+ if (!has_space_for_insert(node, key)) {
if (top)
r = btree_split_beneath(s, key);
else
- r = btree_split_sibling(s, i, key);
+ r = rebalance_or_split(s, vt, i, key);
if (r < 0)
return r;
- }
- node = dm_block_data(shadow_current(s));
+ /* making space can cause the current node to change */
+ node = dm_block_data(shadow_current(s));
+ }
i = lower_bound(node, key);
@@ -753,6 +1140,77 @@ static int btree_insert_raw(struct shadow_spine *s, dm_block_t root,
return 0;
}
+static int __btree_get_overwrite_leaf(struct shadow_spine *s, dm_block_t root,
+ uint64_t key, int *index)
+{
+ int r, i = -1;
+ struct btree_node *node;
+
+ *index = 0;
+ for (;;) {
+ r = shadow_step(s, root, &s->info->value_type);
+ if (r < 0)
+ return r;
+
+ node = dm_block_data(shadow_current(s));
+
+ /*
+ * We have to patch up the parent node, ugly, but I don't
+ * see a way to do this automatically as part of the spine
+ * op.
+ */
+ if (shadow_has_parent(s) && i >= 0) {
+ __le64 location = cpu_to_le64(dm_block_location(shadow_current(s)));
+
+ __dm_bless_for_disk(&location);
+ memcpy_disk(value_ptr(dm_block_data(shadow_parent(s)), i),
+ &location, sizeof(__le64));
+ }
+
+ node = dm_block_data(shadow_current(s));
+ i = lower_bound(node, key);
+
+ BUG_ON(i < 0);
+ BUG_ON(i >= le32_to_cpu(node->header.nr_entries));
+
+ if (le32_to_cpu(node->header.flags) & LEAF_NODE) {
+ if (key != le64_to_cpu(node->keys[i]))
+ return -EINVAL;
+ break;
+ }
+
+ root = value64(node, i);
+ }
+
+ *index = i;
+ return 0;
+}
+
+int btree_get_overwrite_leaf(struct dm_btree_info *info, dm_block_t root,
+ uint64_t key, int *index,
+ dm_block_t *new_root, struct dm_block **leaf)
+{
+ int r;
+ struct shadow_spine spine;
+
+ BUG_ON(info->levels > 1);
+ init_shadow_spine(&spine, info);
+ r = __btree_get_overwrite_leaf(&spine, root, key, index);
+ if (!r) {
+ *new_root = shadow_root(&spine);
+ *leaf = shadow_current(&spine);
+
+ /*
+ * Decrement the count so exit_shadow_spine() doesn't
+ * unlock the leaf.
+ */
+ spine.count--;
+ }
+ exit_shadow_spine(&spine);
+
+ return r;
+}
+
static bool need_insert(struct btree_node *node, uint64_t *keys,
unsigned level, unsigned index)
{
@@ -829,7 +1287,7 @@ static int insert(struct dm_btree_info *info, dm_block_t root,
value_ptr(n, index),
value))) {
info->value_type.dec(info->value_type.context,
- value_ptr(n, index));
+ value_ptr(n, index), 1);
}
memcpy_disk(value_ptr(n, index),
value, info->value_type.size);
diff --git a/drivers/md/persistent-data/dm-btree.h b/drivers/md/persistent-data/dm-btree.h
index 3dc5bb1a4748..d2ae5aa4d00b 100644
--- a/drivers/md/persistent-data/dm-btree.h
+++ b/drivers/md/persistent-data/dm-btree.h
@@ -51,21 +51,21 @@ struct dm_btree_value_type {
*/
/*
- * The btree is making a duplicate of the value, for instance
+ * The btree is making a duplicate of a run of values, for instance
* because previously-shared btree nodes have now diverged.
* @value argument is the new copy that the copy function may modify.
* (Probably it just wants to increment a reference count
* somewhere.) This method is _not_ called for insertion of a new
* value: It is assumed the ref count is already 1.
*/
- void (*inc)(void *context, const void *value);
+ void (*inc)(void *context, const void *value, unsigned count);
/*
- * This value is being deleted. The btree takes care of freeing
+ * These values are being deleted. The btree takes care of freeing
* the memory pointed to by @value. Often the del function just
- * needs to decrement a reference count somewhere.
+ * needs to decrement a reference counts somewhere.
*/
- void (*dec)(void *context, const void *value);
+ void (*dec)(void *context, const void *value, unsigned count);
/*
* A test for equality between two values. When a value is
diff --git a/drivers/md/persistent-data/dm-space-map-common.c b/drivers/md/persistent-data/dm-space-map-common.c
index a213bf11738f..4a6a2a9b4eb4 100644
--- a/drivers/md/persistent-data/dm-space-map-common.c
+++ b/drivers/md/persistent-data/dm-space-map-common.c
@@ -6,6 +6,8 @@
#include "dm-space-map-common.h"
#include "dm-transaction-manager.h"
+#include "dm-btree-internal.h"
+#include "dm-persistent-data-internal.h"
#include <linux/bitops.h>
#include <linux/device-mapper.h>
@@ -409,12 +411,13 @@ int sm_ll_find_common_free_block(struct ll_disk *old_ll, struct ll_disk *new_ll,
return r;
}
-static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b,
- int (*mutator)(void *context, uint32_t old, uint32_t *new),
- void *context, enum allocation_event *ev)
+/*----------------------------------------------------------------*/
+
+int sm_ll_insert(struct ll_disk *ll, dm_block_t b,
+ uint32_t ref_count, int32_t *nr_allocations)
{
int r;
- uint32_t bit, old, ref_count;
+ uint32_t bit, old;
struct dm_block *nb;
dm_block_t index = b;
struct disk_index_entry ie_disk;
@@ -433,10 +436,9 @@ static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b,
return r;
}
ie_disk.blocknr = cpu_to_le64(dm_block_location(nb));
-
bm_le = dm_bitmap_data(nb);
- old = sm_lookup_bitmap(bm_le, bit);
+ old = sm_lookup_bitmap(bm_le, bit);
if (old > 2) {
r = sm_ll_lookup_big_ref_count(ll, b, &old);
if (r < 0) {
@@ -445,7 +447,6 @@ static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b,
}
}
- r = mutator(context, old, &ref_count);
if (r) {
dm_tm_unlock(ll->tm, nb);
return r;
@@ -453,7 +454,6 @@ static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b,
if (ref_count <= 2) {
sm_set_bitmap(bm_le, bit, ref_count);
-
dm_tm_unlock(ll->tm, nb);
if (old > 2) {
@@ -480,62 +480,459 @@ static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b,
}
if (ref_count && !old) {
- *ev = SM_ALLOC;
+ *nr_allocations = 1;
ll->nr_allocated++;
le32_add_cpu(&ie_disk.nr_free, -1);
if (le32_to_cpu(ie_disk.none_free_before) == bit)
ie_disk.none_free_before = cpu_to_le32(bit + 1);
} else if (old && !ref_count) {
- *ev = SM_FREE;
+ *nr_allocations = -1;
ll->nr_allocated--;
le32_add_cpu(&ie_disk.nr_free, 1);
ie_disk.none_free_before = cpu_to_le32(min(le32_to_cpu(ie_disk.none_free_before), bit));
} else
- *ev = SM_NONE;
+ *nr_allocations = 0;
return ll->save_ie(ll, index, &ie_disk);
}
-static int set_ref_count(void *context, uint32_t old, uint32_t *new)
+/*----------------------------------------------------------------*/
+
+/*
+ * Holds useful intermediate results for the range based inc and dec
+ * operations.
+ */
+struct inc_context {
+ struct disk_index_entry ie_disk;
+ struct dm_block *bitmap_block;
+ void *bitmap;
+
+ struct dm_block *overflow_leaf;
+};
+
+static inline void init_inc_context(struct inc_context *ic)
+{
+ ic->bitmap_block = NULL;
+ ic->bitmap = NULL;
+ ic->overflow_leaf = NULL;
+}
+
+static inline void exit_inc_context(struct ll_disk *ll, struct inc_context *ic)
+{
+ if (ic->bitmap_block)
+ dm_tm_unlock(ll->tm, ic->bitmap_block);
+ if (ic->overflow_leaf)
+ dm_tm_unlock(ll->tm, ic->overflow_leaf);
+}
+
+static inline void reset_inc_context(struct ll_disk *ll, struct inc_context *ic)
+{
+ exit_inc_context(ll, ic);
+ init_inc_context(ic);
+}
+
+/*
+ * Confirms a btree node contains a particular key at an index.
+ */
+static bool contains_key(struct btree_node *n, uint64_t key, int index)
+{
+ return index >= 0 &&
+ index < le32_to_cpu(n->header.nr_entries) &&
+ le64_to_cpu(n->keys[index]) == key;
+}
+
+static int __sm_ll_inc_overflow(struct ll_disk *ll, dm_block_t b, struct inc_context *ic)
{
- *new = *((uint32_t *) context);
+ int r;
+ int index;
+ struct btree_node *n;
+ __le32 *v_ptr;
+ uint32_t rc;
+
+ /*
+ * bitmap_block needs to be unlocked because getting the
+ * overflow_leaf may need to allocate, and thus use the space map.
+ */
+ reset_inc_context(ll, ic);
+
+ r = btree_get_overwrite_leaf(&ll->ref_count_info, ll->ref_count_root,
+ b, &index, &ll->ref_count_root, &ic->overflow_leaf);
+ if (r < 0)
+ return r;
+
+ n = dm_block_data(ic->overflow_leaf);
+
+ if (!contains_key(n, b, index)) {
+ DMERR("overflow btree is missing an entry");
+ return -EINVAL;
+ }
+
+ v_ptr = value_ptr(n, index);
+ rc = le32_to_cpu(*v_ptr) + 1;
+ *v_ptr = cpu_to_le32(rc);
+
return 0;
}
-int sm_ll_insert(struct ll_disk *ll, dm_block_t b,
- uint32_t ref_count, enum allocation_event *ev)
+static int sm_ll_inc_overflow(struct ll_disk *ll, dm_block_t b, struct inc_context *ic)
+{
+ int index;
+ struct btree_node *n;
+ __le32 *v_ptr;
+ uint32_t rc;
+
+ /*
+ * Do we already have the correct overflow leaf?
+ */
+ if (ic->overflow_leaf) {
+ n = dm_block_data(ic->overflow_leaf);
+ index = lower_bound(n, b);
+ if (contains_key(n, b, index)) {
+ v_ptr = value_ptr(n, index);
+ rc = le32_to_cpu(*v_ptr) + 1;
+ *v_ptr = cpu_to_le32(rc);
+
+ return 0;
+ }
+ }
+
+ return __sm_ll_inc_overflow(ll, b, ic);
+}
+
+static inline int shadow_bitmap(struct ll_disk *ll, struct inc_context *ic)
+{
+ int r, inc;
+ r = dm_tm_shadow_block(ll->tm, le64_to_cpu(ic->ie_disk.blocknr),
+ &dm_sm_bitmap_validator, &ic->bitmap_block, &inc);
+ if (r < 0) {
+ DMERR("dm_tm_shadow_block() failed");
+ return r;
+ }
+ ic->ie_disk.blocknr = cpu_to_le64(dm_block_location(ic->bitmap_block));
+ ic->bitmap = dm_bitmap_data(ic->bitmap_block);
+ return 0;
+}
+
+/*
+ * Once shadow_bitmap has been called, which always happens at the start of inc/dec,
+ * we can reopen the bitmap with a simple write lock, rather than re calling
+ * dm_tm_shadow_block().
+ */
+static inline int ensure_bitmap(struct ll_disk *ll, struct inc_context *ic)
+{
+ if (!ic->bitmap_block) {
+ int r = dm_bm_write_lock(dm_tm_get_bm(ll->tm), le64_to_cpu(ic->ie_disk.blocknr),
+ &dm_sm_bitmap_validator, &ic->bitmap_block);
+ if (r) {
+ DMERR("unable to re-get write lock for bitmap");
+ return r;
+ }
+ ic->bitmap = dm_bitmap_data(ic->bitmap_block);
+ }
+
+ return 0;
+}
+
+/*
+ * Loops round incrementing entries in a single bitmap.
+ */
+static inline int sm_ll_inc_bitmap(struct ll_disk *ll, dm_block_t b,
+ uint32_t bit, uint32_t bit_end,
+ int32_t *nr_allocations, dm_block_t *new_b,
+ struct inc_context *ic)
+{
+ int r;
+ __le32 le_rc;
+ uint32_t old;
+
+ for (; bit != bit_end; bit++, b++) {
+ /*
+ * We only need to drop the bitmap if we need to find a new btree
+ * leaf for the overflow. So if it was dropped last iteration,
+ * we now re-get it.
+ */
+ r = ensure_bitmap(ll, ic);
+ if (r)
+ return r;
+
+ old = sm_lookup_bitmap(ic->bitmap, bit);
+ switch (old) {
+ case 0:
+ /* inc bitmap, adjust nr_allocated */
+ sm_set_bitmap(ic->bitmap, bit, 1);
+ (*nr_allocations)++;
+ ll->nr_allocated++;
+ le32_add_cpu(&ic->ie_disk.nr_free, -1);
+ if (le32_to_cpu(ic->ie_disk.none_free_before) == bit)
+ ic->ie_disk.none_free_before = cpu_to_le32(bit + 1);
+ break;
+
+ case 1:
+ /* inc bitmap */
+ sm_set_bitmap(ic->bitmap, bit, 2);
+ break;
+
+ case 2:
+ /* inc bitmap and insert into overflow */
+ sm_set_bitmap(ic->bitmap, bit, 3);
+ reset_inc_context(ll, ic);
+
+ le_rc = cpu_to_le32(3);
+ __dm_bless_for_disk(&le_rc);
+ r = dm_btree_insert(&ll->ref_count_info, ll->ref_count_root,
+ &b, &le_rc, &ll->ref_count_root);
+ if (r < 0) {
+ DMERR("ref count insert failed");
+ return r;
+ }
+ break;
+
+ default:
+ /*
+ * inc within the overflow tree only.
+ */
+ r = sm_ll_inc_overflow(ll, b, ic);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ *new_b = b;
+ return 0;
+}
+
+/*
+ * Finds a bitmap that contains entries in the block range, and increments
+ * them.
+ */
+static int __sm_ll_inc(struct ll_disk *ll, dm_block_t b, dm_block_t e,
+ int32_t *nr_allocations, dm_block_t *new_b)
{
- return sm_ll_mutate(ll, b, set_ref_count, &ref_count, ev);
+ int r;
+ struct inc_context ic;
+ uint32_t bit, bit_end;
+ dm_block_t index = b;
+
+ init_inc_context(&ic);
+
+ bit = do_div(index, ll->entries_per_block);
+ r = ll->load_ie(ll, index, &ic.ie_disk);
+ if (r < 0)
+ return r;
+
+ r = shadow_bitmap(ll, &ic);
+ if (r)
+ return r;
+
+ bit_end = min(bit + (e - b), (dm_block_t) ll->entries_per_block);
+ r = sm_ll_inc_bitmap(ll, b, bit, bit_end, nr_allocations, new_b, &ic);
+
+ exit_inc_context(ll, &ic);
+
+ if (r)
+ return r;
+
+ return ll->save_ie(ll, index, &ic.ie_disk);
}
-static int inc_ref_count(void *context, uint32_t old, uint32_t *new)
+int sm_ll_inc(struct ll_disk *ll, dm_block_t b, dm_block_t e,
+ int32_t *nr_allocations)
{
- *new = old + 1;
+ *nr_allocations = 0;
+ while (b != e) {
+ int r = __sm_ll_inc(ll, b, e, nr_allocations, &b);
+ if (r)
+ return r;
+ }
+
return 0;
}
-int sm_ll_inc(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev)
+/*----------------------------------------------------------------*/
+
+static int __sm_ll_del_overflow(struct ll_disk *ll, dm_block_t b,
+ struct inc_context *ic)
{
- return sm_ll_mutate(ll, b, inc_ref_count, NULL, ev);
+ reset_inc_context(ll, ic);
+ return dm_btree_remove(&ll->ref_count_info, ll->ref_count_root,
+ &b, &ll->ref_count_root);
}
-static int dec_ref_count(void *context, uint32_t old, uint32_t *new)
+static int __sm_ll_dec_overflow(struct ll_disk *ll, dm_block_t b,
+ struct inc_context *ic, uint32_t *old_rc)
{
- if (!old) {
- DMERR_LIMIT("unable to decrement a reference count below 0");
+ int r;
+ int index = -1;
+ struct btree_node *n;
+ __le32 *v_ptr;
+ uint32_t rc;
+
+ reset_inc_context(ll, ic);
+ r = btree_get_overwrite_leaf(&ll->ref_count_info, ll->ref_count_root,
+ b, &index, &ll->ref_count_root, &ic->overflow_leaf);
+ if (r < 0)
+ return r;
+
+ n = dm_block_data(ic->overflow_leaf);
+
+ if (!contains_key(n, b, index)) {
+ DMERR("overflow btree is missing an entry");
return -EINVAL;
}
- *new = old - 1;
+ v_ptr = value_ptr(n, index);
+ rc = le32_to_cpu(*v_ptr);
+ *old_rc = rc;
+
+ if (rc == 3) {
+ return __sm_ll_del_overflow(ll, b, ic);
+ } else {
+ rc--;
+ *v_ptr = cpu_to_le32(rc);
+ return 0;
+ }
+}
+
+static int sm_ll_dec_overflow(struct ll_disk *ll, dm_block_t b,
+ struct inc_context *ic, uint32_t *old_rc)
+{
+ /*
+ * Do we already have the correct overflow leaf?
+ */
+ if (ic->overflow_leaf) {
+ int index;
+ struct btree_node *n;
+ __le32 *v_ptr;
+ uint32_t rc;
+
+ n = dm_block_data(ic->overflow_leaf);
+ index = lower_bound(n, b);
+ if (contains_key(n, b, index)) {
+ v_ptr = value_ptr(n, index);
+ rc = le32_to_cpu(*v_ptr);
+ *old_rc = rc;
+
+ if (rc > 3) {
+ rc--;
+ *v_ptr = cpu_to_le32(rc);
+ return 0;
+ } else {
+ return __sm_ll_del_overflow(ll, b, ic);
+ }
+
+ }
+ }
+
+ return __sm_ll_dec_overflow(ll, b, ic, old_rc);
+}
+
+/*
+ * Loops round incrementing entries in a single bitmap.
+ */
+static inline int sm_ll_dec_bitmap(struct ll_disk *ll, dm_block_t b,
+ uint32_t bit, uint32_t bit_end,
+ struct inc_context *ic,
+ int32_t *nr_allocations, dm_block_t *new_b)
+{
+ int r;
+ uint32_t old;
+
+ for (; bit != bit_end; bit++, b++) {
+ /*
+ * We only need to drop the bitmap if we need to find a new btree
+ * leaf for the overflow. So if it was dropped last iteration,
+ * we now re-get it.
+ */
+ r = ensure_bitmap(ll, ic);
+ if (r)
+ return r;
+
+ old = sm_lookup_bitmap(ic->bitmap, bit);
+ switch (old) {
+ case 0:
+ DMERR("unable to decrement block");
+ return -EINVAL;
+
+ case 1:
+ /* dec bitmap */
+ sm_set_bitmap(ic->bitmap, bit, 0);
+ (*nr_allocations)--;
+ ll->nr_allocated--;
+ le32_add_cpu(&ic->ie_disk.nr_free, 1);
+ ic->ie_disk.none_free_before =
+ cpu_to_le32(min(le32_to_cpu(ic->ie_disk.none_free_before), bit));
+ break;
+
+ case 2:
+ /* dec bitmap and insert into overflow */
+ sm_set_bitmap(ic->bitmap, bit, 1);
+ break;
+
+ case 3:
+ r = sm_ll_dec_overflow(ll, b, ic, &old);
+ if (r < 0)
+ return r;
+
+ if (old == 3) {
+ r = ensure_bitmap(ll, ic);
+ if (r)
+ return r;
+
+ sm_set_bitmap(ic->bitmap, bit, 2);
+ }
+ break;
+ }
+ }
+
+ *new_b = b;
return 0;
}
-int sm_ll_dec(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev)
+static int __sm_ll_dec(struct ll_disk *ll, dm_block_t b, dm_block_t e,
+ int32_t *nr_allocations, dm_block_t *new_b)
+{
+ int r;
+ uint32_t bit, bit_end;
+ struct inc_context ic;
+ dm_block_t index = b;
+
+ init_inc_context(&ic);
+
+ bit = do_div(index, ll->entries_per_block);
+ r = ll->load_ie(ll, index, &ic.ie_disk);
+ if (r < 0)
+ return r;
+
+ r = shadow_bitmap(ll, &ic);
+ if (r)
+ return r;
+
+ bit_end = min(bit + (e - b), (dm_block_t) ll->entries_per_block);
+ r = sm_ll_dec_bitmap(ll, b, bit, bit_end, &ic, nr_allocations, new_b);
+ exit_inc_context(ll, &ic);
+
+ if (r)
+ return r;
+
+ return ll->save_ie(ll, index, &ic.ie_disk);
+}
+
+int sm_ll_dec(struct ll_disk *ll, dm_block_t b, dm_block_t e,
+ int32_t *nr_allocations)
{
- return sm_ll_mutate(ll, b, dec_ref_count, NULL, ev);
+ *nr_allocations = 0;
+ while (b != e) {
+ int r = __sm_ll_dec(ll, b, e, nr_allocations, &b);
+ if (r)
+ return r;
+ }
+
+ return 0;
}
+/*----------------------------------------------------------------*/
+
int sm_ll_commit(struct ll_disk *ll)
{
int r = 0;
@@ -687,28 +1084,92 @@ int sm_ll_open_metadata(struct ll_disk *ll, struct dm_transaction_manager *tm,
/*----------------------------------------------------------------*/
+static inline int ie_cache_writeback(struct ll_disk *ll, struct ie_cache *iec)
+{
+ iec->dirty = false;
+ __dm_bless_for_disk(iec->ie);
+ return dm_btree_insert(&ll->bitmap_info, ll->bitmap_root,
+ &iec->index, &iec->ie, &ll->bitmap_root);
+}
+
+static inline unsigned hash_index(dm_block_t index)
+{
+ return dm_hash_block(index, IE_CACHE_MASK);
+}
+
static int disk_ll_load_ie(struct ll_disk *ll, dm_block_t index,
struct disk_index_entry *ie)
{
- return dm_btree_lookup(&ll->bitmap_info, ll->bitmap_root, &index, ie);
+ int r;
+ unsigned h = hash_index(index);
+ struct ie_cache *iec = ll->ie_cache + h;
+
+ if (iec->valid) {
+ if (iec->index == index) {
+ memcpy(ie, &iec->ie, sizeof(*ie));
+ return 0;
+ }
+
+ if (iec->dirty) {
+ r = ie_cache_writeback(ll, iec);
+ if (r)
+ return r;
+ }
+ }
+
+ r = dm_btree_lookup(&ll->bitmap_info, ll->bitmap_root, &index, ie);
+ if (!r) {
+ iec->valid = true;
+ iec->dirty = false;
+ iec->index = index;
+ memcpy(&iec->ie, ie, sizeof(*ie));
+ }
+
+ return r;
}
static int disk_ll_save_ie(struct ll_disk *ll, dm_block_t index,
struct disk_index_entry *ie)
{
- __dm_bless_for_disk(ie);
- return dm_btree_insert(&ll->bitmap_info, ll->bitmap_root,
- &index, ie, &ll->bitmap_root);
+ int r;
+ unsigned h = hash_index(index);
+ struct ie_cache *iec = ll->ie_cache + h;
+
+ ll->bitmap_index_changed = true;
+ if (iec->valid) {
+ if (iec->index == index) {
+ memcpy(&iec->ie, ie, sizeof(*ie));
+ iec->dirty = true;
+ return 0;
+ }
+
+ if (iec->dirty) {
+ r = ie_cache_writeback(ll, iec);
+ if (r)
+ return r;
+ }
+ }
+
+ iec->valid = true;
+ iec->dirty = true;
+ iec->index = index;
+ memcpy(&iec->ie, ie, sizeof(*ie));
+ return 0;
}
static int disk_ll_init_index(struct ll_disk *ll)
{
+ unsigned i;
+ for (i = 0; i < IE_CACHE_SIZE; i++) {
+ struct ie_cache *iec = ll->ie_cache + i;
+ iec->valid = false;
+ iec->dirty = false;
+ }
return dm_btree_empty(&ll->bitmap_info, &ll->bitmap_root);
}
static int disk_ll_open(struct ll_disk *ll)
{
- /* nothing to do */
return 0;
}
@@ -719,7 +1180,16 @@ static dm_block_t disk_ll_max_entries(struct ll_disk *ll)
static int disk_ll_commit(struct ll_disk *ll)
{
- return 0;
+ int r = 0;
+ unsigned i;
+
+ for (i = 0; i < IE_CACHE_SIZE; i++) {
+ struct ie_cache *iec = ll->ie_cache + i;
+ if (iec->valid && iec->dirty)
+ r = ie_cache_writeback(ll, iec);
+ }
+
+ return r;
}
int sm_ll_new_disk(struct ll_disk *ll, struct dm_transaction_manager *tm)
diff --git a/drivers/md/persistent-data/dm-space-map-common.h b/drivers/md/persistent-data/dm-space-map-common.h
index 87e17909ef52..706ceb85d680 100644
--- a/drivers/md/persistent-data/dm-space-map-common.h
+++ b/drivers/md/persistent-data/dm-space-map-common.h
@@ -54,6 +54,20 @@ typedef int (*open_index_fn)(struct ll_disk *ll);
typedef dm_block_t (*max_index_entries_fn)(struct ll_disk *ll);
typedef int (*commit_fn)(struct ll_disk *ll);
+/*
+ * A lot of time can be wasted reading and writing the same
+ * index entry. So we cache a few entries.
+ */
+#define IE_CACHE_SIZE 64
+#define IE_CACHE_MASK (IE_CACHE_SIZE - 1)
+
+struct ie_cache {
+ bool valid;
+ bool dirty;
+ dm_block_t index;
+ struct disk_index_entry ie;
+};
+
struct ll_disk {
struct dm_transaction_manager *tm;
struct dm_btree_info bitmap_info;
@@ -79,6 +93,8 @@ struct ll_disk {
max_index_entries_fn max_entries;
commit_fn commit;
bool bitmap_index_changed:1;
+
+ struct ie_cache ie_cache[IE_CACHE_SIZE];
};
struct disk_sm_root {
@@ -96,12 +112,6 @@ struct disk_bitmap_header {
__le64 blocknr;
} __attribute__ ((packed, aligned(8)));
-enum allocation_event {
- SM_NONE,
- SM_ALLOC,
- SM_FREE,
-};
-
/*----------------------------------------------------------------*/
int sm_ll_extend(struct ll_disk *ll, dm_block_t extra_blocks);
@@ -111,9 +121,15 @@ int sm_ll_find_free_block(struct ll_disk *ll, dm_block_t begin,
dm_block_t end, dm_block_t *result);
int sm_ll_find_common_free_block(struct ll_disk *old_ll, struct ll_disk *new_ll,
dm_block_t begin, dm_block_t end, dm_block_t *result);
-int sm_ll_insert(struct ll_disk *ll, dm_block_t b, uint32_t ref_count, enum allocation_event *ev);
-int sm_ll_inc(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev);
-int sm_ll_dec(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev);
+
+/*
+ * The next three functions return (via nr_allocations) the net number of
+ * allocations that were made. This number may be negative if there were
+ * more frees than allocs.
+ */
+int sm_ll_insert(struct ll_disk *ll, dm_block_t b, uint32_t ref_count, int32_t *nr_allocations);
+int sm_ll_inc(struct ll_disk *ll, dm_block_t b, dm_block_t e, int32_t *nr_allocations);
+int sm_ll_dec(struct ll_disk *ll, dm_block_t b, dm_block_t e, int32_t *nr_allocations);
int sm_ll_commit(struct ll_disk *ll);
int sm_ll_new_metadata(struct ll_disk *ll, struct dm_transaction_manager *tm);
diff --git a/drivers/md/persistent-data/dm-space-map-disk.c b/drivers/md/persistent-data/dm-space-map-disk.c
index 61f56909e00b..d0a8d5e73c28 100644
--- a/drivers/md/persistent-data/dm-space-map-disk.c
+++ b/drivers/md/persistent-data/dm-space-map-disk.c
@@ -87,76 +87,39 @@ static int sm_disk_set_count(struct dm_space_map *sm, dm_block_t b,
uint32_t count)
{
int r;
- uint32_t old_count;
- enum allocation_event ev;
+ int32_t nr_allocations;
struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
- r = sm_ll_insert(&smd->ll, b, count, &ev);
+ r = sm_ll_insert(&smd->ll, b, count, &nr_allocations);
if (!r) {
- switch (ev) {
- case SM_NONE:
- break;
-
- case SM_ALLOC:
- /*
- * This _must_ be free in the prior transaction
- * otherwise we've lost atomicity.
- */
- smd->nr_allocated_this_transaction++;
- break;
-
- case SM_FREE:
- /*
- * It's only free if it's also free in the last
- * transaction.
- */
- r = sm_ll_lookup(&smd->old_ll, b, &old_count);
- if (r)
- return r;
-
- if (!old_count)
- smd->nr_allocated_this_transaction--;
- break;
- }
+ smd->nr_allocated_this_transaction += nr_allocations;
}
return r;
}
-static int sm_disk_inc_block(struct dm_space_map *sm, dm_block_t b)
+static int sm_disk_inc_blocks(struct dm_space_map *sm, dm_block_t b, dm_block_t e)
{
int r;
- enum allocation_event ev;
+ int32_t nr_allocations;
struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
- r = sm_ll_inc(&smd->ll, b, &ev);
- if (!r && (ev == SM_ALLOC))
- /*
- * This _must_ be free in the prior transaction
- * otherwise we've lost atomicity.
- */
- smd->nr_allocated_this_transaction++;
+ r = sm_ll_inc(&smd->ll, b, e, &nr_allocations);
+ if (!r)
+ smd->nr_allocated_this_transaction += nr_allocations;
return r;
}
-static int sm_disk_dec_block(struct dm_space_map *sm, dm_block_t b)
+static int sm_disk_dec_blocks(struct dm_space_map *sm, dm_block_t b, dm_block_t e)
{
int r;
- uint32_t old_count;
- enum allocation_event ev;
+ int32_t nr_allocations;
struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
- r = sm_ll_dec(&smd->ll, b, &ev);
- if (!r && (ev == SM_FREE)) {
- /*
- * It's only free if it's also free in the last
- * transaction.
- */
- r = sm_ll_lookup(&smd->old_ll, b, &old_count);
- if (!r && !old_count)
- smd->nr_allocated_this_transaction--;
- }
+ r = sm_ll_dec(&smd->ll, b, e, &nr_allocations);
+ if (!r)
+ smd->nr_allocated_this_transaction += nr_allocations;
return r;
}
@@ -164,21 +127,28 @@ static int sm_disk_dec_block(struct dm_space_map *sm, dm_block_t b)
static int sm_disk_new_block(struct dm_space_map *sm, dm_block_t *b)
{
int r;
- enum allocation_event ev;
+ int32_t nr_allocations;
struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
/*
* Any block we allocate has to be free in both the old and current ll.
*/
r = sm_ll_find_common_free_block(&smd->old_ll, &smd->ll, smd->begin, smd->ll.nr_blocks, b);
+ if (r == -ENOSPC) {
+ /*
+ * There's no free block between smd->begin and the end of the metadata device.
+ * We search before smd->begin in case something has been freed.
+ */
+ r = sm_ll_find_common_free_block(&smd->old_ll, &smd->ll, 0, smd->begin, b);
+ }
+
if (r)
return r;
smd->begin = *b + 1;
- r = sm_ll_inc(&smd->ll, *b, &ev);
+ r = sm_ll_inc(&smd->ll, *b, *b + 1, &nr_allocations);
if (!r) {
- BUG_ON(ev != SM_ALLOC);
- smd->nr_allocated_this_transaction++;
+ smd->nr_allocated_this_transaction += nr_allocations;
}
return r;
@@ -194,7 +164,6 @@ static int sm_disk_commit(struct dm_space_map *sm)
return r;
memcpy(&smd->old_ll, &smd->ll, sizeof(smd->old_ll));
- smd->begin = 0;
smd->nr_allocated_this_transaction = 0;
return 0;
@@ -235,8 +204,8 @@ static struct dm_space_map ops = {
.get_count = sm_disk_get_count,
.count_is_more_than_one = sm_disk_count_is_more_than_one,
.set_count = sm_disk_set_count,
- .inc_block = sm_disk_inc_block,
- .dec_block = sm_disk_dec_block,
+ .inc_blocks = sm_disk_inc_blocks,
+ .dec_blocks = sm_disk_dec_blocks,
.new_block = sm_disk_new_block,
.commit = sm_disk_commit,
.root_size = sm_disk_root_size,
diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c
index 9e3c64ec2026..392ae26134a4 100644
--- a/drivers/md/persistent-data/dm-space-map-metadata.c
+++ b/drivers/md/persistent-data/dm-space-map-metadata.c
@@ -89,7 +89,8 @@ enum block_op_type {
struct block_op {
enum block_op_type type;
- dm_block_t block;
+ dm_block_t b;
+ dm_block_t e;
};
struct bop_ring_buffer {
@@ -116,7 +117,7 @@ static unsigned brb_next(struct bop_ring_buffer *brb, unsigned old)
}
static int brb_push(struct bop_ring_buffer *brb,
- enum block_op_type type, dm_block_t b)
+ enum block_op_type type, dm_block_t b, dm_block_t e)
{
struct block_op *bop;
unsigned next = brb_next(brb, brb->end);
@@ -130,7 +131,8 @@ static int brb_push(struct bop_ring_buffer *brb,
bop = brb->bops + brb->end;
bop->type = type;
- bop->block = b;
+ bop->b = b;
+ bop->e = e;
brb->end = next;
@@ -145,9 +147,7 @@ static int brb_peek(struct bop_ring_buffer *brb, struct block_op *result)
return -ENODATA;
bop = brb->bops + brb->begin;
- result->type = bop->type;
- result->block = bop->block;
-
+ memcpy(result, bop, sizeof(*result));
return 0;
}
@@ -178,10 +178,9 @@ struct sm_metadata {
struct threshold threshold;
};
-static int add_bop(struct sm_metadata *smm, enum block_op_type type, dm_block_t b)
+static int add_bop(struct sm_metadata *smm, enum block_op_type type, dm_block_t b, dm_block_t e)
{
- int r = brb_push(&smm->uncommitted, type, b);
-
+ int r = brb_push(&smm->uncommitted, type, b, e);
if (r) {
DMERR("too many recursive allocations");
return -ENOMEM;
@@ -193,15 +192,15 @@ static int add_bop(struct sm_metadata *smm, enum block_op_type type, dm_block_t
static int commit_bop(struct sm_metadata *smm, struct block_op *op)
{
int r = 0;
- enum allocation_event ev;
+ int32_t nr_allocations;
switch (op->type) {
case BOP_INC:
- r = sm_ll_inc(&smm->ll, op->block, &ev);
+ r = sm_ll_inc(&smm->ll, op->b, op->e, &nr_allocations);
break;
case BOP_DEC:
- r = sm_ll_dec(&smm->ll, op->block, &ev);
+ r = sm_ll_dec(&smm->ll, op->b, op->e, &nr_allocations);
break;
}
@@ -314,7 +313,7 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
i = brb_next(&smm->uncommitted, i)) {
struct block_op *op = smm->uncommitted.bops + i;
- if (op->block != b)
+ if (b < op->b || b >= op->e)
continue;
switch (op->type) {
@@ -355,7 +354,7 @@ static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm,
struct block_op *op = smm->uncommitted.bops + i;
- if (op->block != b)
+ if (b < op->b || b >= op->e)
continue;
switch (op->type) {
@@ -393,7 +392,7 @@ static int sm_metadata_set_count(struct dm_space_map *sm, dm_block_t b,
uint32_t count)
{
int r, r2;
- enum allocation_event ev;
+ int32_t nr_allocations;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
if (smm->recursion_count) {
@@ -402,40 +401,42 @@ static int sm_metadata_set_count(struct dm_space_map *sm, dm_block_t b,
}
in(smm);
- r = sm_ll_insert(&smm->ll, b, count, &ev);
+ r = sm_ll_insert(&smm->ll, b, count, &nr_allocations);
r2 = out(smm);
return combine_errors(r, r2);
}
-static int sm_metadata_inc_block(struct dm_space_map *sm, dm_block_t b)
+static int sm_metadata_inc_blocks(struct dm_space_map *sm, dm_block_t b, dm_block_t e)
{
int r, r2 = 0;
- enum allocation_event ev;
+ int32_t nr_allocations;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
- if (recursing(smm))
- r = add_bop(smm, BOP_INC, b);
- else {
+ if (recursing(smm)) {
+ r = add_bop(smm, BOP_INC, b, e);
+ if (r)
+ return r;
+ } else {
in(smm);
- r = sm_ll_inc(&smm->ll, b, &ev);
+ r = sm_ll_inc(&smm->ll, b, e, &nr_allocations);
r2 = out(smm);
}
return combine_errors(r, r2);
}
-static int sm_metadata_dec_block(struct dm_space_map *sm, dm_block_t b)
+static int sm_metadata_dec_blocks(struct dm_space_map *sm, dm_block_t b, dm_block_t e)
{
int r, r2 = 0;
- enum allocation_event ev;
+ int32_t nr_allocations;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
if (recursing(smm))
- r = add_bop(smm, BOP_DEC, b);
+ r = add_bop(smm, BOP_DEC, b, e);
else {
in(smm);
- r = sm_ll_dec(&smm->ll, b, &ev);
+ r = sm_ll_dec(&smm->ll, b, e, &nr_allocations);
r2 = out(smm);
}
@@ -445,23 +446,31 @@ static int sm_metadata_dec_block(struct dm_space_map *sm, dm_block_t b)
static int sm_metadata_new_block_(struct dm_space_map *sm, dm_block_t *b)
{
int r, r2 = 0;
- enum allocation_event ev;
+ int32_t nr_allocations;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
/*
* Any block we allocate has to be free in both the old and current ll.
*/
r = sm_ll_find_common_free_block(&smm->old_ll, &smm->ll, smm->begin, smm->ll.nr_blocks, b);
+ if (r == -ENOSPC) {
+ /*
+ * There's no free block between smm->begin and the end of the metadata device.
+ * We search before smm->begin in case something has been freed.
+ */
+ r = sm_ll_find_common_free_block(&smm->old_ll, &smm->ll, 0, smm->begin, b);
+ }
+
if (r)
return r;
smm->begin = *b + 1;
if (recursing(smm))
- r = add_bop(smm, BOP_INC, *b);
+ r = add_bop(smm, BOP_INC, *b, *b + 1);
else {
in(smm);
- r = sm_ll_inc(&smm->ll, *b, &ev);
+ r = sm_ll_inc(&smm->ll, *b, *b + 1, &nr_allocations);
r2 = out(smm);
}
@@ -503,7 +512,6 @@ static int sm_metadata_commit(struct dm_space_map *sm)
return r;
memcpy(&smm->old_ll, &smm->ll, sizeof(smm->old_ll));
- smm->begin = 0;
smm->allocated_this_transaction = 0;
return 0;
@@ -556,8 +564,8 @@ static const struct dm_space_map ops = {
.get_count = sm_metadata_get_count,
.count_is_more_than_one = sm_metadata_count_is_more_than_one,
.set_count = sm_metadata_set_count,
- .inc_block = sm_metadata_inc_block,
- .dec_block = sm_metadata_dec_block,
+ .inc_blocks = sm_metadata_inc_blocks,
+ .dec_blocks = sm_metadata_dec_blocks,
.new_block = sm_metadata_new_block,
.commit = sm_metadata_commit,
.root_size = sm_metadata_root_size,
@@ -641,18 +649,28 @@ static int sm_bootstrap_new_block(struct dm_space_map *sm, dm_block_t *b)
return 0;
}
-static int sm_bootstrap_inc_block(struct dm_space_map *sm, dm_block_t b)
+static int sm_bootstrap_inc_blocks(struct dm_space_map *sm, dm_block_t b, dm_block_t e)
{
+ int r;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
- return add_bop(smm, BOP_INC, b);
+ r = add_bop(smm, BOP_INC, b, e);
+ if (r)
+ return r;
+
+ return 0;
}
-static int sm_bootstrap_dec_block(struct dm_space_map *sm, dm_block_t b)
+static int sm_bootstrap_dec_blocks(struct dm_space_map *sm, dm_block_t b, dm_block_t e)
{
+ int r;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
- return add_bop(smm, BOP_DEC, b);
+ r = add_bop(smm, BOP_DEC, b, e);
+ if (r)
+ return r;
+
+ return 0;
}
static int sm_bootstrap_commit(struct dm_space_map *sm)
@@ -683,8 +701,8 @@ static const struct dm_space_map bootstrap_ops = {
.get_count = sm_bootstrap_get_count,
.count_is_more_than_one = sm_bootstrap_count_is_more_than_one,
.set_count = sm_bootstrap_set_count,
- .inc_block = sm_bootstrap_inc_block,
- .dec_block = sm_bootstrap_dec_block,
+ .inc_blocks = sm_bootstrap_inc_blocks,
+ .dec_blocks = sm_bootstrap_dec_blocks,
.new_block = sm_bootstrap_new_block,
.commit = sm_bootstrap_commit,
.root_size = sm_bootstrap_root_size,
@@ -696,7 +714,7 @@ static const struct dm_space_map bootstrap_ops = {
static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
{
- int r, i;
+ int r;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
dm_block_t old_len = smm->ll.nr_blocks;
@@ -718,9 +736,7 @@ static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
* allocate any new blocks.
*/
do {
- for (i = old_len; !r && i < smm->begin; i++)
- r = add_bop(smm, BOP_INC, i);
-
+ r = add_bop(smm, BOP_INC, old_len, smm->begin);
if (r)
goto out;
@@ -767,7 +783,6 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
dm_block_t superblock)
{
int r;
- dm_block_t i;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
smm->begin = superblock + 1;
@@ -792,9 +807,7 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
* Now we need to update the newly created data structures with the
* allocated blocks that they were built from.
*/
- for (i = superblock; !r && i < smm->begin; i++)
- r = add_bop(smm, BOP_INC, i);
-
+ r = add_bop(smm, BOP_INC, superblock, smm->begin);
if (r)
return r;
diff --git a/drivers/md/persistent-data/dm-space-map.h b/drivers/md/persistent-data/dm-space-map.h
index 3e6d1153b7c4..a015cd11f6e9 100644
--- a/drivers/md/persistent-data/dm-space-map.h
+++ b/drivers/md/persistent-data/dm-space-map.h
@@ -46,8 +46,8 @@ struct dm_space_map {
int (*commit)(struct dm_space_map *sm);
- int (*inc_block)(struct dm_space_map *sm, dm_block_t b);
- int (*dec_block)(struct dm_space_map *sm, dm_block_t b);
+ int (*inc_blocks)(struct dm_space_map *sm, dm_block_t b, dm_block_t e);
+ int (*dec_blocks)(struct dm_space_map *sm, dm_block_t b, dm_block_t e);
/*
* new_block will increment the returned block.
@@ -117,14 +117,24 @@ static inline int dm_sm_commit(struct dm_space_map *sm)
return sm->commit(sm);
}
+static inline int dm_sm_inc_blocks(struct dm_space_map *sm, dm_block_t b, dm_block_t e)
+{
+ return sm->inc_blocks(sm, b, e);
+}
+
static inline int dm_sm_inc_block(struct dm_space_map *sm, dm_block_t b)
{
- return sm->inc_block(sm, b);
+ return dm_sm_inc_blocks(sm, b, b + 1);
+}
+
+static inline int dm_sm_dec_blocks(struct dm_space_map *sm, dm_block_t b, dm_block_t e)
+{
+ return sm->dec_blocks(sm, b, e);
}
static inline int dm_sm_dec_block(struct dm_space_map *sm, dm_block_t b)
{
- return sm->dec_block(sm, b);
+ return dm_sm_dec_blocks(sm, b, b + 1);
}
static inline int dm_sm_new_block(struct dm_space_map *sm, dm_block_t *b)
diff --git a/drivers/md/persistent-data/dm-transaction-manager.c b/drivers/md/persistent-data/dm-transaction-manager.c
index abe2c5dd0993..16643fc974e8 100644
--- a/drivers/md/persistent-data/dm-transaction-manager.c
+++ b/drivers/md/persistent-data/dm-transaction-manager.c
@@ -359,6 +359,17 @@ void dm_tm_inc(struct dm_transaction_manager *tm, dm_block_t b)
}
EXPORT_SYMBOL_GPL(dm_tm_inc);
+void dm_tm_inc_range(struct dm_transaction_manager *tm, dm_block_t b, dm_block_t e)
+{
+ /*
+ * The non-blocking clone doesn't support this.
+ */
+ BUG_ON(tm->is_clone);
+
+ dm_sm_inc_blocks(tm->sm, b, e);
+}
+EXPORT_SYMBOL_GPL(dm_tm_inc_range);
+
void dm_tm_dec(struct dm_transaction_manager *tm, dm_block_t b)
{
/*
@@ -370,6 +381,47 @@ void dm_tm_dec(struct dm_transaction_manager *tm, dm_block_t b)
}
EXPORT_SYMBOL_GPL(dm_tm_dec);
+void dm_tm_dec_range(struct dm_transaction_manager *tm, dm_block_t b, dm_block_t e)
+{
+ /*
+ * The non-blocking clone doesn't support this.
+ */
+ BUG_ON(tm->is_clone);
+
+ dm_sm_dec_blocks(tm->sm, b, e);
+}
+EXPORT_SYMBOL_GPL(dm_tm_dec_range);
+
+void dm_tm_with_runs(struct dm_transaction_manager *tm,
+ const __le64 *value_le, unsigned count, dm_tm_run_fn fn)
+{
+ uint64_t b, begin, end;
+ bool in_run = false;
+ unsigned i;
+
+ for (i = 0; i < count; i++, value_le++) {
+ b = le64_to_cpu(*value_le);
+
+ if (in_run) {
+ if (b == end)
+ end++;
+ else {
+ fn(tm, begin, end);
+ begin = b;
+ end = b + 1;
+ }
+ } else {
+ in_run = true;
+ begin = b;
+ end = b + 1;
+ }
+ }
+
+ if (in_run)
+ fn(tm, begin, end);
+}
+EXPORT_SYMBOL_GPL(dm_tm_with_runs);
+
int dm_tm_ref(struct dm_transaction_manager *tm, dm_block_t b,
uint32_t *result)
{
@@ -379,6 +431,15 @@ int dm_tm_ref(struct dm_transaction_manager *tm, dm_block_t b,
return dm_sm_get_count(tm->sm, b, result);
}
+int dm_tm_block_is_shared(struct dm_transaction_manager *tm, dm_block_t b,
+ int *result)
+{
+ if (tm->is_clone)
+ return -EWOULDBLOCK;
+
+ return dm_sm_count_is_more_than_one(tm->sm, b, result);
+}
+
struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm)
{
return tm->bm;
diff --git a/drivers/md/persistent-data/dm-transaction-manager.h b/drivers/md/persistent-data/dm-transaction-manager.h
index f3a18be68f30..906c02ed0365 100644
--- a/drivers/md/persistent-data/dm-transaction-manager.h
+++ b/drivers/md/persistent-data/dm-transaction-manager.h
@@ -100,11 +100,27 @@ void dm_tm_unlock(struct dm_transaction_manager *tm, struct dm_block *b);
* Functions for altering the reference count of a block directly.
*/
void dm_tm_inc(struct dm_transaction_manager *tm, dm_block_t b);
-
+void dm_tm_inc_range(struct dm_transaction_manager *tm, dm_block_t b, dm_block_t e);
void dm_tm_dec(struct dm_transaction_manager *tm, dm_block_t b);
+void dm_tm_dec_range(struct dm_transaction_manager *tm, dm_block_t b, dm_block_t e);
+
+/*
+ * Builds up runs of adjacent blocks, and then calls the given fn
+ * (typically dm_tm_inc/dec). Very useful when you have to perform
+ * the same tm operation on all values in a btree leaf.
+ */
+typedef void (*dm_tm_run_fn)(struct dm_transaction_manager *, dm_block_t, dm_block_t);
+void dm_tm_with_runs(struct dm_transaction_manager *tm,
+ const __le64 *value_le, unsigned count, dm_tm_run_fn fn);
-int dm_tm_ref(struct dm_transaction_manager *tm, dm_block_t b,
- uint32_t *result);
+int dm_tm_ref(struct dm_transaction_manager *tm, dm_block_t b, uint32_t *result);
+
+/*
+ * Finds out if a given block is shared (ie. has a reference count higher
+ * than one).
+ */
+int dm_tm_block_is_shared(struct dm_transaction_manager *tm, dm_block_t b,
+ int *result);
struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm);
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index e5d7411cba9b..62c8b6adac70 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -546,6 +546,9 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
bio = split;
}
+ if (bio->bi_pool != &mddev->bio_set)
+ md_account_bio(mddev, &bio);
+
orig_sector = sector;
zone = find_zone(mddev->private, &sector);
switch (conf->layout) {
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index ced076ba560e..51f2547c2007 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -300,6 +300,8 @@ static void call_bio_endio(struct r1bio *r1_bio)
if (!test_bit(R1BIO_Uptodate, &r1_bio->state))
bio->bi_status = BLK_STS_IOERR;
+ if (blk_queue_io_stat(bio->bi_bdev->bd_disk->queue))
+ bio_end_io_acct(bio, r1_bio->start_time);
bio_endio(bio);
}
@@ -1210,7 +1212,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
int max_sectors;
int rdisk;
- bool print_msg = !!r1_bio;
+ bool r1bio_existed = !!r1_bio;
char b[BDEVNAME_SIZE];
/*
@@ -1220,7 +1222,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
*/
gfp_t gfp = r1_bio ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;
- if (print_msg) {
+ if (r1bio_existed) {
/* Need to get the block device name carefully */
struct md_rdev *rdev;
rcu_read_lock();
@@ -1252,7 +1254,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
if (rdisk < 0) {
/* couldn't find anywhere to read from */
- if (print_msg) {
+ if (r1bio_existed) {
pr_crit_ratelimited("md/raid1:%s: %s: unrecoverable I/O read error for block %llu\n",
mdname(mddev),
b,
@@ -1263,7 +1265,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
}
mirror = conf->mirrors + rdisk;
- if (print_msg)
+ if (r1bio_existed)
pr_info_ratelimited("md/raid1:%s: redirecting sector %llu to other mirror: %s\n",
mdname(mddev),
(unsigned long long)r1_bio->sector,
@@ -1292,6 +1294,9 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
r1_bio->read_disk = rdisk;
+ if (!r1bio_existed && blk_queue_io_stat(bio->bi_bdev->bd_disk->queue))
+ r1_bio->start_time = bio_start_io_acct(bio);
+
read_bio = bio_clone_fast(bio, gfp, &mddev->bio_set);
r1_bio->bios[rdisk] = read_bio;
@@ -1461,6 +1466,8 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
r1_bio->sectors = max_sectors;
}
+ if (blk_queue_io_stat(bio->bi_bdev->bd_disk->queue))
+ r1_bio->start_time = bio_start_io_acct(bio);
atomic_set(&r1_bio->remaining, 1);
atomic_set(&r1_bio->behind_remaining, 0);
diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h
index b7eb09e8c025..ccf10e59b116 100644
--- a/drivers/md/raid1.h
+++ b/drivers/md/raid1.h
@@ -158,6 +158,7 @@ struct r1bio {
sector_t sector;
int sectors;
unsigned long state;
+ unsigned long start_time;
struct mddev *mddev;
/*
* original bio going to /dev/mdx
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 13f5e6b2a73d..16977e8e075d 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -297,6 +297,8 @@ static void raid_end_bio_io(struct r10bio *r10_bio)
if (!test_bit(R10BIO_Uptodate, &r10_bio->state))
bio->bi_status = BLK_STS_IOERR;
+ if (blk_queue_io_stat(bio->bi_bdev->bd_disk->queue))
+ bio_end_io_acct(bio, r10_bio->start_time);
bio_endio(bio);
/*
* Wake up any possible resync thread that waits for the device
@@ -1184,6 +1186,8 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
}
slot = r10_bio->read_slot;
+ if (blk_queue_io_stat(bio->bi_bdev->bd_disk->queue))
+ r10_bio->start_time = bio_start_io_acct(bio);
read_bio = bio_clone_fast(bio, gfp, &mddev->bio_set);
r10_bio->devs[slot].bio = read_bio;
@@ -1483,6 +1487,8 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
r10_bio->master_bio = bio;
}
+ if (blk_queue_io_stat(bio->bi_bdev->bd_disk->queue))
+ r10_bio->start_time = bio_start_io_acct(bio);
atomic_set(&r10_bio->remaining, 1);
md_bitmap_startwrite(mddev->bitmap, r10_bio->sector, r10_bio->sectors, 0);
diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h
index 1461fd55311b..c34bb196790e 100644
--- a/drivers/md/raid10.h
+++ b/drivers/md/raid10.h
@@ -124,6 +124,7 @@ struct r10bio {
sector_t sector; /* virtual sector number */
int sectors;
unsigned long state;
+ unsigned long start_time;
struct mddev *mddev;
/*
* original bio going to /dev/mdx
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 7d4ff8a5c55e..b8436e4930ed 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5362,11 +5362,13 @@ static struct bio *remove_bio_from_retry(struct r5conf *conf,
*/
static void raid5_align_endio(struct bio *bi)
{
- struct bio* raid_bi = bi->bi_private;
+ struct md_io_acct *md_io_acct = bi->bi_private;
+ struct bio *raid_bi = md_io_acct->orig_bio;
struct mddev *mddev;
struct r5conf *conf;
struct md_rdev *rdev;
blk_status_t error = bi->bi_status;
+ unsigned long start_time = md_io_acct->start_time;
bio_put(bi);
@@ -5378,6 +5380,8 @@ static void raid5_align_endio(struct bio *bi)
rdev_dec_pending(rdev, conf->mddev);
if (!error) {
+ if (blk_queue_io_stat(raid_bi->bi_bdev->bd_disk->queue))
+ bio_end_io_acct(raid_bi, start_time);
bio_endio(raid_bi);
if (atomic_dec_and_test(&conf->active_aligned_reads))
wake_up(&conf->wait_for_quiescent);
@@ -5396,6 +5400,8 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio)
struct md_rdev *rdev;
sector_t sector, end_sector, first_bad;
int bad_sectors, dd_idx;
+ struct md_io_acct *md_io_acct;
+ bool did_inc;
if (!in_chunk_boundary(mddev, raid_bio)) {
pr_debug("%s: non aligned\n", __func__);
@@ -5425,29 +5431,46 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio)
atomic_inc(&rdev->nr_pending);
rcu_read_unlock();
- align_bio = bio_clone_fast(raid_bio, GFP_NOIO, &mddev->bio_set);
- bio_set_dev(align_bio, rdev->bdev);
- align_bio->bi_end_io = raid5_align_endio;
- align_bio->bi_private = raid_bio;
- align_bio->bi_iter.bi_sector = sector;
-
- raid_bio->bi_next = (void *)rdev;
-
- if (is_badblock(rdev, sector, bio_sectors(align_bio), &first_bad,
+ if (is_badblock(rdev, sector, bio_sectors(raid_bio), &first_bad,
&bad_sectors)) {
- bio_put(align_bio);
+ bio_put(raid_bio);
rdev_dec_pending(rdev, mddev);
return 0;
}
+ align_bio = bio_clone_fast(raid_bio, GFP_NOIO, &mddev->io_acct_set);
+ md_io_acct = container_of(align_bio, struct md_io_acct, bio_clone);
+ raid_bio->bi_next = (void *)rdev;
+ if (blk_queue_io_stat(raid_bio->bi_bdev->bd_disk->queue))
+ md_io_acct->start_time = bio_start_io_acct(raid_bio);
+ md_io_acct->orig_bio = raid_bio;
+
+ bio_set_dev(align_bio, rdev->bdev);
+ align_bio->bi_end_io = raid5_align_endio;
+ align_bio->bi_private = md_io_acct;
+ align_bio->bi_iter.bi_sector = sector;
+
/* No reshape active, so we can trust rdev->data_offset */
align_bio->bi_iter.bi_sector += rdev->data_offset;
- spin_lock_irq(&conf->device_lock);
- wait_event_lock_irq(conf->wait_for_quiescent, conf->quiesce == 0,
- conf->device_lock);
- atomic_inc(&conf->active_aligned_reads);
- spin_unlock_irq(&conf->device_lock);
+ did_inc = false;
+ if (conf->quiesce == 0) {
+ atomic_inc(&conf->active_aligned_reads);
+ did_inc = true;
+ }
+ /* need a memory barrier to detect the race with raid5_quiesce() */
+ if (!did_inc || smp_load_acquire(&conf->quiesce) != 0) {
+ /* quiesce is in progress, so we need to undo io activation and wait
+ * for it to finish
+ */
+ if (did_inc && atomic_dec_and_test(&conf->active_aligned_reads))
+ wake_up(&conf->wait_for_quiescent);
+ spin_lock_irq(&conf->device_lock);
+ wait_event_lock_irq(conf->wait_for_quiescent, conf->quiesce == 0,
+ conf->device_lock);
+ atomic_inc(&conf->active_aligned_reads);
+ spin_unlock_irq(&conf->device_lock);
+ }
if (mddev->gendisk)
trace_block_bio_remap(align_bio, disk_devt(mddev->gendisk),
@@ -5796,6 +5819,7 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
last_sector = bio_end_sector(bi);
bi->bi_next = NULL;
+ md_account_bio(mddev, &bi);
prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
for (; logical_sector < last_sector; logical_sector += RAID5_STRIPE_SECTORS(conf)) {
int previous;
@@ -6928,7 +6952,7 @@ static struct attribute *raid5_attrs[] = {
&ppl_write_hint.attr,
NULL,
};
-static struct attribute_group raid5_attrs_group = {
+static const struct attribute_group raid5_attrs_group = {
.name = NULL,
.attrs = raid5_attrs,
};
@@ -8334,7 +8358,10 @@ static void raid5_quiesce(struct mddev *mddev, int quiesce)
* active stripes can drain
*/
r5c_flush_cache(conf, INT_MAX);
- conf->quiesce = 2;
+ /* need a memory barrier to make sure read_one_chunk() sees
+ * quiesce started and reverts to slow (locked) path.
+ */
+ smp_store_release(&conf->quiesce, 2);
wait_event_cmd(conf->wait_for_quiescent,
atomic_read(&conf->active_stripes) == 0 &&
atomic_read(&conf->active_aligned_reads) == 0,
diff --git a/drivers/media/cec/platform/s5p/s5p_cec.c b/drivers/media/cec/platform/s5p/s5p_cec.c
index 2a3e7ffefe0a..028a09a7531e 100644
--- a/drivers/media/cec/platform/s5p/s5p_cec.c
+++ b/drivers/media/cec/platform/s5p/s5p_cec.c
@@ -35,10 +35,13 @@ MODULE_PARM_DESC(debug, "debug level (0-2)");
static int s5p_cec_adap_enable(struct cec_adapter *adap, bool enable)
{
+ int ret;
struct s5p_cec_dev *cec = cec_get_drvdata(adap);
if (enable) {
- pm_runtime_get_sync(cec->dev);
+ ret = pm_runtime_resume_and_get(cec->dev);
+ if (ret < 0)
+ return ret;
s5p_cec_reset(cec);
@@ -51,7 +54,7 @@ static int s5p_cec_adap_enable(struct cec_adapter *adap, bool enable)
} else {
s5p_cec_mask_tx_interrupts(cec);
s5p_cec_mask_rx_interrupts(cec);
- pm_runtime_disable(cec->dev);
+ pm_runtime_put(cec->dev);
}
return 0;
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 4ea03b7899a8..0f6bde0f793e 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -13,6 +13,10 @@ config VIDEO_TVEEPROM
tristate
depends on I2C
+config TTPCI_EEPROM
+ tristate
+ depends on I2C
+
config CYPRESS_FIRMWARE
tristate
depends on USB
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index b71e4b62eea5..55b5a1900124 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -3,3 +3,4 @@ obj-y += b2c2/ saa7146/ siano/ v4l2-tpg/ videobuf2/
obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o
+obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c
index 410cc3ac6f94..bceaf91faa15 100644
--- a/drivers/media/common/siano/smscoreapi.c
+++ b/drivers/media/common/siano/smscoreapi.c
@@ -908,7 +908,7 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
void *buffer, size_t size)
{
struct sms_firmware *firmware = (struct sms_firmware *) buffer;
- struct sms_msg_data4 *msg;
+ struct sms_msg_data5 *msg;
u32 mem_address, calc_checksum = 0;
u32 i, *ptr;
u8 *payload = firmware->payload;
@@ -989,24 +989,20 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
goto exit_fw_download;
if (coredev->mode == DEVICE_MODE_NONE) {
- struct sms_msg_data *trigger_msg =
- (struct sms_msg_data *) msg;
-
pr_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ\n");
SMS_INIT_MSG(&msg->x_msg_header,
MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
- sizeof(struct sms_msg_hdr) +
- sizeof(u32) * 5);
+ sizeof(*msg));
- trigger_msg->msg_data[0] = firmware->start_address;
+ msg->msg_data[0] = firmware->start_address;
/* Entry point */
- trigger_msg->msg_data[1] = 6; /* Priority */
- trigger_msg->msg_data[2] = 0x200; /* Stack size */
- trigger_msg->msg_data[3] = 0; /* Parameter */
- trigger_msg->msg_data[4] = 4; /* Task ID */
+ msg->msg_data[1] = 6; /* Priority */
+ msg->msg_data[2] = 0x200; /* Stack size */
+ msg->msg_data[3] = 0; /* Parameter */
+ msg->msg_data[4] = 4; /* Task ID */
- rc = smscore_sendrequest_and_wait(coredev, trigger_msg,
- trigger_msg->x_msg_header.msg_length,
+ rc = smscore_sendrequest_and_wait(coredev, msg,
+ msg->x_msg_header.msg_length,
&coredev->trigger_done);
} else {
SMS_INIT_MSG(&msg->x_msg_header, MSG_SW_RELOAD_EXEC_REQ,
diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h
index 4a6b9f4c44ac..f8789ee0d554 100644
--- a/drivers/media/common/siano/smscoreapi.h
+++ b/drivers/media/common/siano/smscoreapi.h
@@ -624,9 +624,9 @@ struct sms_msg_data2 {
u32 msg_data[2];
};
-struct sms_msg_data4 {
+struct sms_msg_data5 {
struct sms_msg_hdr x_msg_header;
- u32 msg_data[4];
+ u32 msg_data[5];
};
struct sms_data_download {
diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c
index cd5bafe9a3ac..f80caaa333da 100644
--- a/drivers/media/common/siano/smsdvb-main.c
+++ b/drivers/media/common/siano/smsdvb-main.c
@@ -26,8 +26,8 @@ Copyright (C) 2006-2008, Uri Shkolnik
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-static struct list_head g_smsdvb_clients;
-static struct mutex g_smsdvb_clientslock;
+static LIST_HEAD(g_smsdvb_clients);
+static DEFINE_MUTEX(g_smsdvb_clientslock);
static u32 sms_to_guard_interval_table[] = {
[0] = GUARD_INTERVAL_1_32,
@@ -1212,6 +1212,10 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
return 0;
media_graph_error:
+ mutex_lock(&g_smsdvb_clientslock);
+ list_del(&client->entry);
+ mutex_unlock(&g_smsdvb_clientslock);
+
smsdvb_debugfs_release(client);
client_error:
@@ -1236,9 +1240,6 @@ static int __init smsdvb_module_init(void)
{
int rc;
- INIT_LIST_HEAD(&g_smsdvb_clients);
- mutex_init(&g_smsdvb_clientslock);
-
smsdvb_debugfs_register();
rc = smscore_register_hotplug(smsdvb_hotplug);
diff --git a/drivers/media/pci/ttpci/ttpci-eeprom.c b/drivers/media/common/ttpci-eeprom.c
index ef8746684d31..ef8746684d31 100644
--- a/drivers/media/pci/ttpci/ttpci-eeprom.c
+++ b/drivers/media/common/ttpci-eeprom.c
diff --git a/drivers/media/pci/ttpci/ttpci-eeprom.h b/drivers/media/common/ttpci-eeprom.h
index ee741867ba47..ee741867ba47 100644
--- a/drivers/media/pci/ttpci/ttpci-eeprom.h
+++ b/drivers/media/common/ttpci-eeprom.h
diff --git a/drivers/media/common/videobuf2/frame_vector.c b/drivers/media/common/videobuf2/frame_vector.c
index 381158320a90..ce879f6f8f82 100644
--- a/drivers/media/common/videobuf2/frame_vector.c
+++ b/drivers/media/common/videobuf2/frame_vector.c
@@ -64,7 +64,7 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
do {
unsigned long *nums = frame_vector_pfns(vec);
- vma = find_vma_intersection(mm, start, start + 1);
+ vma = vma_lookup(mm, start);
if (!vma)
break;
diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
index 7e96f67c60ba..2988bb38ceb1 100644
--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
@@ -939,6 +939,20 @@ void vb2_queue_release(struct vb2_queue *q)
}
EXPORT_SYMBOL_GPL(vb2_queue_release);
+int vb2_queue_change_type(struct vb2_queue *q, unsigned int type)
+{
+ if (type == q->type)
+ return 0;
+
+ if (vb2_is_busy(q))
+ return -EBUSY;
+
+ q->type = type;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_queue_change_type);
+
__poll_t vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
{
struct video_device *vfd = video_devdata(file);
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index f14a872d1268..5d5a48475a54 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -720,7 +720,7 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
secfeed,
dvb_dmxdev_section_callback);
- if (ret < 0) {
+ if (!*secfeed) {
pr_err("DVB (%s): could not alloc feed\n",
__func__);
return ret;
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
index b7e4a3371176..15a08d8c69ef 100644
--- a/drivers/media/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -1386,6 +1386,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file,
err = -EINVAL;
goto out_unlock;
}
+ slot = array_index_nospec(slot, ca->slot_count);
info->type = CA_CI_LINK;
info->flags = 0;
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index a6915582d1a6..258637d762d6 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -23,6 +23,7 @@
#include <linux/poll.h>
#include <linux/semaphore.h>
#include <linux/module.h>
+#include <linux/nospec.h>
#include <linux/list.h>
#include <linux/freezer.h>
#include <linux/jiffies.h>
@@ -1063,107 +1064,97 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
return 0;
}
-#define _DTV_CMD(n, s, b) \
-[n] = { \
- .name = #n, \
- .cmd = n, \
- .set = s,\
- .buffer = b \
-}
-
-struct dtv_cmds_h {
- char *name; /* A display name for debugging purposes */
+#define _DTV_CMD(n) \
+ [n] = #n
- __u32 cmd; /* A unique ID */
-
- /* Flags */
- __u32 set:1; /* Either a set or get property */
- __u32 buffer:1; /* Does this property use the buffer? */
- __u32 reserved:30; /* Align */
-};
-
-static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
- _DTV_CMD(DTV_TUNE, 1, 0),
- _DTV_CMD(DTV_CLEAR, 1, 0),
+static char *dtv_cmds[DTV_MAX_COMMAND + 1] = {
+ _DTV_CMD(DTV_TUNE),
+ _DTV_CMD(DTV_CLEAR),
/* Set */
- _DTV_CMD(DTV_FREQUENCY, 1, 0),
- _DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0),
- _DTV_CMD(DTV_MODULATION, 1, 0),
- _DTV_CMD(DTV_INVERSION, 1, 0),
- _DTV_CMD(DTV_DISEQC_MASTER, 1, 1),
- _DTV_CMD(DTV_SYMBOL_RATE, 1, 0),
- _DTV_CMD(DTV_INNER_FEC, 1, 0),
- _DTV_CMD(DTV_VOLTAGE, 1, 0),
- _DTV_CMD(DTV_TONE, 1, 0),
- _DTV_CMD(DTV_PILOT, 1, 0),
- _DTV_CMD(DTV_ROLLOFF, 1, 0),
- _DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0),
- _DTV_CMD(DTV_HIERARCHY, 1, 0),
- _DTV_CMD(DTV_CODE_RATE_HP, 1, 0),
- _DTV_CMD(DTV_CODE_RATE_LP, 1, 0),
- _DTV_CMD(DTV_GUARD_INTERVAL, 1, 0),
- _DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0),
- _DTV_CMD(DTV_INTERLEAVING, 1, 0),
-
- _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0),
- _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0),
- _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0),
- _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0),
- _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0),
-
- _DTV_CMD(DTV_STREAM_ID, 1, 0),
- _DTV_CMD(DTV_DVBT2_PLP_ID_LEGACY, 1, 0),
- _DTV_CMD(DTV_SCRAMBLING_SEQUENCE_INDEX, 1, 0),
- _DTV_CMD(DTV_LNA, 1, 0),
+ _DTV_CMD(DTV_FREQUENCY),
+ _DTV_CMD(DTV_BANDWIDTH_HZ),
+ _DTV_CMD(DTV_MODULATION),
+ _DTV_CMD(DTV_INVERSION),
+ _DTV_CMD(DTV_DISEQC_MASTER),
+ _DTV_CMD(DTV_SYMBOL_RATE),
+ _DTV_CMD(DTV_INNER_FEC),
+ _DTV_CMD(DTV_VOLTAGE),
+ _DTV_CMD(DTV_TONE),
+ _DTV_CMD(DTV_PILOT),
+ _DTV_CMD(DTV_ROLLOFF),
+ _DTV_CMD(DTV_DELIVERY_SYSTEM),
+ _DTV_CMD(DTV_HIERARCHY),
+ _DTV_CMD(DTV_CODE_RATE_HP),
+ _DTV_CMD(DTV_CODE_RATE_LP),
+ _DTV_CMD(DTV_GUARD_INTERVAL),
+ _DTV_CMD(DTV_TRANSMISSION_MODE),
+ _DTV_CMD(DTV_INTERLEAVING),
+
+ _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION),
+ _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING),
+ _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID),
+ _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX),
+ _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT),
+ _DTV_CMD(DTV_ISDBT_LAYER_ENABLED),
+ _DTV_CMD(DTV_ISDBT_LAYERA_FEC),
+ _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION),
+ _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT),
+ _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING),
+ _DTV_CMD(DTV_ISDBT_LAYERB_FEC),
+ _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION),
+ _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT),
+ _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING),
+ _DTV_CMD(DTV_ISDBT_LAYERC_FEC),
+ _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION),
+ _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT),
+ _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING),
+
+ _DTV_CMD(DTV_STREAM_ID),
+ _DTV_CMD(DTV_DVBT2_PLP_ID_LEGACY),
+ _DTV_CMD(DTV_SCRAMBLING_SEQUENCE_INDEX),
+ _DTV_CMD(DTV_LNA),
/* Get */
- _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
- _DTV_CMD(DTV_API_VERSION, 0, 0),
-
- _DTV_CMD(DTV_ENUM_DELSYS, 0, 0),
-
- _DTV_CMD(DTV_ATSCMH_PARADE_ID, 1, 0),
- _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 1, 0),
-
- _DTV_CMD(DTV_ATSCMH_FIC_VER, 0, 0),
- _DTV_CMD(DTV_ATSCMH_NOG, 0, 0),
- _DTV_CMD(DTV_ATSCMH_TNOG, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SGN, 0, 0),
- _DTV_CMD(DTV_ATSCMH_PRC, 0, 0),
- _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE, 0, 0),
- _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI, 0, 0),
- _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0),
+ _DTV_CMD(DTV_DISEQC_SLAVE_REPLY),
+ _DTV_CMD(DTV_API_VERSION),
+
+ _DTV_CMD(DTV_ENUM_DELSYS),
+
+ _DTV_CMD(DTV_ATSCMH_PARADE_ID),
+ _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE),
+
+ _DTV_CMD(DTV_ATSCMH_FIC_VER),
+ _DTV_CMD(DTV_ATSCMH_NOG),
+ _DTV_CMD(DTV_ATSCMH_TNOG),
+ _DTV_CMD(DTV_ATSCMH_SGN),
+ _DTV_CMD(DTV_ATSCMH_PRC),
+ _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE),
+ _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI),
+ _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC),
+ _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D),
/* Statistics API */
- _DTV_CMD(DTV_STAT_SIGNAL_STRENGTH, 0, 0),
- _DTV_CMD(DTV_STAT_CNR, 0, 0),
- _DTV_CMD(DTV_STAT_PRE_ERROR_BIT_COUNT, 0, 0),
- _DTV_CMD(DTV_STAT_PRE_TOTAL_BIT_COUNT, 0, 0),
- _DTV_CMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0, 0),
- _DTV_CMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0, 0),
- _DTV_CMD(DTV_STAT_ERROR_BLOCK_COUNT, 0, 0),
- _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0),
+ _DTV_CMD(DTV_STAT_SIGNAL_STRENGTH),
+ _DTV_CMD(DTV_STAT_CNR),
+ _DTV_CMD(DTV_STAT_PRE_ERROR_BIT_COUNT),
+ _DTV_CMD(DTV_STAT_PRE_TOTAL_BIT_COUNT),
+ _DTV_CMD(DTV_STAT_POST_ERROR_BIT_COUNT),
+ _DTV_CMD(DTV_STAT_POST_TOTAL_BIT_COUNT),
+ _DTV_CMD(DTV_STAT_ERROR_BLOCK_COUNT),
+ _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT),
};
+static char *dtv_cmd_name(u32 cmd)
+{
+ cmd = array_index_nospec(cmd, DTV_MAX_COMMAND);
+ return dtv_cmds[cmd];
+}
+
/* Synchronise the legacy tuning parameters into the cache, so that demodulator
* drivers can use a single set_frontend tuning function, regardless of whether
* it's being used for the legacy or new API, reducing code and complexity.
@@ -1346,6 +1337,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
struct file *file)
{
int ncaps;
+ unsigned int len = 1;
switch (tvp->cmd) {
case DTV_ENUM_DELSYS:
@@ -1355,6 +1347,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
ncaps++;
}
tvp->u.buffer.len = ncaps;
+ len = ncaps;
break;
case DTV_FREQUENCY:
tvp->u.data = c->frequency;
@@ -1532,27 +1525,51 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
/* Fill quality measures */
case DTV_STAT_SIGNAL_STRENGTH:
tvp->u.st = c->strength;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
case DTV_STAT_CNR:
tvp->u.st = c->cnr;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
case DTV_STAT_PRE_ERROR_BIT_COUNT:
tvp->u.st = c->pre_bit_error;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
case DTV_STAT_PRE_TOTAL_BIT_COUNT:
tvp->u.st = c->pre_bit_count;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
case DTV_STAT_POST_ERROR_BIT_COUNT:
tvp->u.st = c->post_bit_error;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
case DTV_STAT_POST_TOTAL_BIT_COUNT:
tvp->u.st = c->post_bit_count;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
case DTV_STAT_ERROR_BLOCK_COUNT:
tvp->u.st = c->block_error;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
case DTV_STAT_TOTAL_BLOCK_COUNT:
tvp->u.st = c->block_count;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
default:
dev_dbg(fe->dvb->device,
@@ -1561,18 +1578,13 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
return -EINVAL;
}
- if (!dtv_cmds[tvp->cmd].buffer)
- dev_dbg(fe->dvb->device,
- "%s: GET cmd 0x%08x (%s) = 0x%08x\n",
- __func__, tvp->cmd, dtv_cmds[tvp->cmd].name,
- tvp->u.data);
- else
- dev_dbg(fe->dvb->device,
- "%s: GET cmd 0x%08x (%s) len %d: %*ph\n",
- __func__,
- tvp->cmd, dtv_cmds[tvp->cmd].name,
- tvp->u.buffer.len,
- tvp->u.buffer.len, tvp->u.buffer.data);
+ if (len < 1)
+ len = 1;
+
+ dev_dbg(fe->dvb->device,
+ "%s: GET cmd 0x%08x (%s) len %d: %*ph\n",
+ __func__, tvp->cmd, dtv_cmd_name(tvp->cmd),
+ tvp->u.buffer.len, tvp->u.buffer.len, tvp->u.buffer.data);
return 0;
}
@@ -1870,7 +1882,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
else
dev_dbg(fe->dvb->device,
"%s: SET cmd 0x%08x (%s) to 0x%08x\n",
- __func__, cmd, dtv_cmds[cmd].name, data);
+ __func__, cmd, dtv_cmd_name(cmd), data);
switch (cmd) {
case DTV_CLEAR:
/*
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index 89620da983ba..dddebea644bb 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -45,6 +45,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/nospec.h>
#include <linux/etherdevice.h>
#include <linux/dvb/net.h>
#include <linux/uio.h>
@@ -1462,14 +1463,20 @@ static int dvb_net_do_ioctl(struct file *file,
struct net_device *netdev;
struct dvb_net_priv *priv_data;
struct dvb_net_if *dvbnetif = parg;
+ int if_num = dvbnetif->if_num;
- if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
- !dvbnet->state[dvbnetif->if_num]) {
+ if (if_num >= DVB_NET_DEVICES_MAX) {
ret = -EINVAL;
goto ioctl_error;
}
+ if_num = array_index_nospec(if_num, DVB_NET_DEVICES_MAX);
- netdev = dvbnet->device[dvbnetif->if_num];
+ if (!dvbnet->state[if_num]) {
+ ret = -EINVAL;
+ goto ioctl_error;
+ }
+
+ netdev = dvbnet->device[if_num];
priv_data = netdev_priv(netdev);
dvbnetif->pid=priv_data->pid;
@@ -1522,14 +1529,20 @@ static int dvb_net_do_ioctl(struct file *file,
struct net_device *netdev;
struct dvb_net_priv *priv_data;
struct __dvb_net_if_old *dvbnetif = parg;
+ int if_num = dvbnetif->if_num;
+
+ if (if_num >= DVB_NET_DEVICES_MAX) {
+ ret = -EINVAL;
+ goto ioctl_error;
+ }
+ if_num = array_index_nospec(if_num, DVB_NET_DEVICES_MAX);
- if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
- !dvbnet->state[dvbnetif->if_num]) {
+ if (!dvbnet->state[if_num]) {
ret = -EINVAL;
goto ioctl_error;
}
- netdev = dvbnet->device[dvbnetif->if_num];
+ netdev = dvbnet->device[if_num];
priv_data = netdev_priv(netdev);
dvbnetif->pid=priv_data->pid;
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 3862ddc86ec4..795d9bfaba5c 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -506,6 +506,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
break;
if (minor == MAX_DVB_MINORS) {
+ list_del (&dvbdev->list_head);
kfree(dvbdevfops);
kfree(dvbdev);
up_write(&minor_rwsem);
@@ -526,6 +527,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
__func__);
dvb_media_device_free(dvbdev);
+ list_del (&dvbdev->list_head);
kfree(dvbdevfops);
kfree(dvbdev);
mutex_unlock(&dvbdev_register_lock);
@@ -541,6 +543,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n",
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
dvb_media_device_free(dvbdev);
+ list_del (&dvbdev->list_head);
kfree(dvbdevfops);
kfree(dvbdev);
return PTR_ERR(clsdev);
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 3468b07b62fe..2c1ed98d43c5 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -323,18 +323,6 @@ config DVB_TDA10071
comment "DVB-T (terrestrial) frontends"
depends on DVB_CORE
-config DVB_SP8870
- tristate "Spase sp8870 based"
- depends on DVB_CORE && I2C
- default m if !MEDIA_SUBDRV_AUTOSELECT
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
-
- This driver needs external firmware. Please use the command
- "<kerneldir>/scripts/get_dvb_firmware sp8870" to
- download/extract it, and then copy it to /usr/lib/hotplug/firmware
- or /lib/firmware (depending on configuration of firmware hotplug).
-
config DVB_SP887X
tristate "Spase sp887x based"
depends on DVB_CORE && I2C
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index b9f47d68e14e..d32e4c0be576 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -20,7 +20,6 @@ obj-$(CONFIG_DVB_PLL) += dvb-pll.o
obj-$(CONFIG_DVB_STV0299) += stv0299.o
obj-$(CONFIG_DVB_STB0899) += stb0899.o
obj-$(CONFIG_DVB_STB6100) += stb6100.o
-obj-$(CONFIG_DVB_SP8870) += sp8870.o
obj-$(CONFIG_DVB_CX22700) += cx22700.o
obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
obj-$(CONFIG_DVB_CX24110) += cx24110.o
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.h b/drivers/media/dvb-frontends/drx39xyj/drxj.h
index d62412f71c88..232b3b0d68c8 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drxj.h
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.h
@@ -75,9 +75,9 @@ TYPEDEFS
u16 result_len;
/*< result length in byte */
u16 *parameter;
- /*< General purpous param */
+ /*< General purpose param */
u16 *result;
- /*< General purpous param */};
+ /*< General purpose param */};
/*============================================================================*/
/*============================================================================*/
@@ -131,7 +131,7 @@ TYPEDEFS
DRXJ_CFG_MAX /* dummy, never to be used */};
/*
-* /struct enum drxj_cfg_smart_ant_io * smart antenna i/o.
+* /enum drxj_cfg_smart_ant_io * smart antenna i/o.
*/
enum drxj_cfg_smart_ant_io {
DRXJ_SMT_ANT_OUTPUT = 0,
@@ -139,7 +139,7 @@ enum drxj_cfg_smart_ant_io {
};
/*
-* /struct struct drxj_cfg_smart_ant * Set smart antenna.
+* /struct drxj_cfg_smart_ant * Set smart antenna.
*/
struct drxj_cfg_smart_ant {
enum drxj_cfg_smart_ant_io io;
@@ -159,7 +159,7 @@ struct drxj_agc_status {
/* DRXJ_CFG_AGC_RF, DRXJ_CFG_AGC_IF */
/*
-* /struct enum drxj_agc_ctrl_mode * Available AGCs modes in the DRXJ.
+* /enum drxj_agc_ctrl_mode * Available AGCs modes in the DRXJ.
*/
enum drxj_agc_ctrl_mode {
DRX_AGC_CTRL_AUTO = 0,
@@ -167,7 +167,7 @@ struct drxj_agc_status {
DRX_AGC_CTRL_OFF};
/*
-* /struct struct drxj_cfg_agc * Generic interface for all AGCs present on the DRXJ.
+* /struct drxj_cfg_agc * Generic interface for all AGCs present on the DRXJ.
*/
struct drxj_cfg_agc {
enum drx_standard standard; /* standard for which these settings apply */
@@ -183,7 +183,7 @@ struct drxj_agc_status {
/* DRXJ_CFG_PRE_SAW */
/*
-* /struct struct drxj_cfg_pre_saw * Interface to configure pre SAW sense.
+* /struct drxj_cfg_pre_saw * Interface to configure pre SAW sense.
*/
struct drxj_cfg_pre_saw {
enum drx_standard standard; /* standard to which these settings apply */
@@ -193,7 +193,7 @@ struct drxj_agc_status {
/* DRXJ_CFG_AFE_GAIN */
/*
-* /struct struct drxj_cfg_afe_gain * Interface to configure gain of AFE (LNA + PGA).
+* /struct drxj_cfg_afe_gain * Interface to configure gain of AFE (LNA + PGA).
*/
struct drxj_cfg_afe_gain {
enum drx_standard standard; /* standard to which these settings apply */
@@ -220,14 +220,14 @@ struct drxj_agc_status {
};
/*
-* /struct struct drxj_cfg_vsb_misc * symbol error rate
+* /struct drxj_cfg_vsb_misc * symbol error rate
*/
struct drxj_cfg_vsb_misc {
u32 symb_error;
/*< symbol error rate sps */};
/*
-* /enum enum drxj_mpeg_output_clock_rate * Mpeg output clock rate.
+* /enum drxj_mpeg_output_clock_rate * Mpeg output clock rate.
*
*/
enum drxj_mpeg_start_width {
@@ -235,7 +235,7 @@ struct drxj_agc_status {
DRXJ_MPEG_START_WIDTH_8CLKCYC};
/*
-* /enum enum drxj_mpeg_output_clock_rate * Mpeg output clock rate.
+* /enum drxj_mpeg_output_clock_rate * Mpeg output clock rate.
*
*/
enum drxj_mpeg_output_clock_rate {
@@ -261,7 +261,7 @@ struct drxj_agc_status {
enum drxj_mpeg_start_width mpeg_start_width; /*< set MPEG output start width */};
/*
-* /enum enum drxj_xtal_freq * Supported external crystal reference frequency.
+* /enum drxj_xtal_freq * Supported external crystal reference frequency.
*/
enum drxj_xtal_freq {
DRXJ_XTAL_FREQ_RSVD,
@@ -270,14 +270,15 @@ struct drxj_agc_status {
DRXJ_XTAL_FREQ_4MHZ};
/*
-* /enum enum drxj_xtal_freq * Supported external crystal reference frequency.
+* /enum drxj_xtal_freq * Supported external crystal reference frequency.
*/
enum drxji2c_speed {
DRXJ_I2C_SPEED_400KBPS,
DRXJ_I2C_SPEED_100KBPS};
/*
-* /struct struct drxj_cfg_hw_cfg * Get hw configuration, such as crystal reference frequency, I2C speed, etc...
+* /struct drxj_cfg_hw_cfg * Get hw configuration, such as crystal
+* reference frequency, I2C speed, etc...
*/
struct drxj_cfg_hw_cfg {
enum drxj_xtal_freq xtal_freq;
@@ -364,7 +365,7 @@ struct drxj_cfg_oob_misc {
DRXJ_SIF_ATTENUATION_9DB};
/*
-* /struct struct drxj_cfg_atv_output * SIF attenuation setting.
+* /struct drxj_cfg_atv_output * SIF attenuation setting.
*
*/
struct drxj_cfg_atv_output {
@@ -453,10 +454,10 @@ struct drxj_cfg_atv_output {
enum drxuio_mode uio_gpio_mode; /*< current mode of ASEL pin */
enum drxuio_mode uio_irqn_mode; /*< current mode of IRQN pin */
- /* IQM fs frequecy shift and inversion */
+ /* IQM fs frequency shift and inversion */
u32 iqm_fs_rate_ofs; /*< frequency shifter setting after setchannel */
bool pos_image; /*< True: positive image */
- /* IQM RC frequecy shift */
+ /* IQM RC frequency shift */
u32 iqm_rc_rate_ofs; /*< frequency shifter setting after setchannel */
/* ATV configuration */
diff --git a/drivers/media/dvb-frontends/mxl692.c b/drivers/media/dvb-frontends/mxl692.c
index 83030643aba7..a246db683cdf 100644
--- a/drivers/media/dvb-frontends/mxl692.c
+++ b/drivers/media/dvb-frontends/mxl692.c
@@ -224,7 +224,9 @@ static int mxl692_validate_fw_header(struct mxl692_dev *dev,
u32 ix, temp;
__be32 *local_buf = NULL;
u8 temp_cksum = 0;
- const u8 fw_hdr[] = { 0x4D, 0x31, 0x10, 0x02, 0x40, 0x00, 0x00, 0x80 };
+ static const u8 fw_hdr[] = {
+ 0x4D, 0x31, 0x10, 0x02, 0x40, 0x00, 0x00, 0x80
+ };
if (memcmp(buffer, fw_hdr, 8) != 0) {
status = -EINVAL;
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index ef6feb299d46..1a2f0d2adadf 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -1130,8 +1130,6 @@ static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv,
f->fmt.sdr.pixelformat = dev->pixelformat;
f->fmt.sdr.buffersize = dev->buffersize;
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
-
return 0;
}
@@ -1149,7 +1147,6 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
if (vb2_is_busy(q))
return -EBUSY;
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
for (i = 0; i < dev->num_formats; i++) {
if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
dev->pixelformat = formats[i].pixelformat;
@@ -1177,7 +1174,6 @@ static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv,
dev_dbg(&pdev->dev, "pixelformat fourcc %4.4s\n",
(char *)&f->fmt.sdr.pixelformat);
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
for (i = 0; i < dev->num_formats; i++) {
if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
f->fmt.sdr.buffersize = formats[i].buffersize;
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 462c0e059754..588f8eb95984 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -217,6 +217,7 @@ config VIDEO_ADV7180
depends on GPIOLIB && VIDEO_V4L2 && I2C
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
+ select V4L2_ASYNC
help
Support for the Analog Devices ADV7180 video decoder.
@@ -534,6 +535,7 @@ config VIDEO_ADV7175
config VIDEO_ADV7343
tristate "ADV7343 video encoder"
depends on I2C
+ select V4L2_ASYNC
help
Support for Analog Devices I2C bus based ADV7343 encoder.
@@ -652,6 +654,7 @@ config SDR_MAX2175
tristate "Maxim 2175 RF to Bits tuner"
depends on VIDEO_V4L2 && MEDIA_SDR_SUPPORT && I2C
select REGMAP_I2C
+ select V4L2_ASYNC
help
Support for Maxim 2175 tuner. It is an advanced analog/digital
radio receiver with RF-to-Bits front-end designed for SDR solutions.
@@ -668,6 +671,7 @@ menu "Miscellaneous helper chips"
config VIDEO_THS7303
tristate "THS7303/53 Video Amplifier"
depends on VIDEO_V4L2 && I2C
+ select V4L2_ASYNC
help
Support for TI THS7303/53 video amplifier
@@ -738,6 +742,17 @@ config VIDEO_HI556
To compile this driver as a module, choose M here: the
module will be called hi556.
+config VIDEO_IMX208
+ tristate "Sony IMX208 sensor support"
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ depends on MEDIA_CAMERA_SUPPORT
+ help
+ This is a Video4Linux2 sensor driver for the Sony
+ IMX208 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx208.
+
config VIDEO_IMX214
tristate "Sony IMX214 sensor support"
depends on GPIOLIB && I2C && VIDEO_V4L2
@@ -1341,6 +1356,7 @@ config VIDEO_AD5820
tristate "AD5820 lens voice coil support"
depends on GPIOLIB && I2C && VIDEO_V4L2
select MEDIA_CONTROLLER
+ select V4L2_ASYNC
help
This is a driver for the AD5820 camera lens voice coil.
It is used for example in Nokia N900 (RX-51).
@@ -1350,6 +1366,7 @@ config VIDEO_AK7375
depends on I2C && VIDEO_V4L2
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
+ select V4L2_ASYNC
help
This is a driver for the AK7375 camera lens voice coil.
AK7375 is a 12 bit DAC with 120mA output current sink
@@ -1361,6 +1378,7 @@ config VIDEO_DW9714
depends on I2C && VIDEO_V4L2
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
+ select V4L2_ASYNC
help
This is a driver for the DW9714 camera lens voice coil.
DW9714 is a 10 bit DAC with 120mA output current sink
@@ -1384,6 +1402,7 @@ config VIDEO_DW9807_VCM
depends on I2C && VIDEO_V4L2
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
+ select V4L2_ASYNC
help
This is a driver for the DW9807 camera lens voice coil.
DW9807 is a 10 bit DAC with 100mA output current sink
@@ -1399,6 +1418,7 @@ config VIDEO_ADP1653
tristate "ADP1653 flash support"
depends on I2C && VIDEO_V4L2
select MEDIA_CONTROLLER
+ select V4L2_ASYNC
help
This is a driver for the ADP1653 flash controller. It is used for
example in Nokia N900.
@@ -1408,6 +1428,7 @@ config VIDEO_LM3560
depends on I2C && VIDEO_V4L2
select MEDIA_CONTROLLER
select REGMAP_I2C
+ select V4L2_ASYNC
help
This is a driver for the lm3560 dual flash controllers. It controls
flash, torch LEDs.
@@ -1417,6 +1438,7 @@ config VIDEO_LM3646
depends on I2C && VIDEO_V4L2
select MEDIA_CONTROLLER
select REGMAP_I2C
+ select V4L2_ASYNC
help
This is a driver for the lm3646 dual flash controllers. It controls
flash, torch LEDs.
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 0c067beca066..1168fa6b84ed 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -116,6 +116,7 @@ obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
obj-$(CONFIG_VIDEO_HI556) += hi556.o
+obj-$(CONFIG_VIDEO_IMX208) += imx208.o
obj-$(CONFIG_VIDEO_IMX214) += imx214.o
obj-$(CONFIG_VIDEO_IMX219) += imx219.o
obj-$(CONFIG_VIDEO_IMX258) += imx258.o
diff --git a/drivers/media/i2c/adv7170.c b/drivers/media/i2c/adv7170.c
index e4e8fda51ad8..714e31f993e1 100644
--- a/drivers/media/i2c/adv7170.c
+++ b/drivers/media/i2c/adv7170.c
@@ -250,7 +250,7 @@ static int adv7170_s_routing(struct v4l2_subdev *sd,
}
static int adv7170_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index >= ARRAY_SIZE(adv7170_codes))
@@ -261,7 +261,7 @@ static int adv7170_enum_mbus_code(struct v4l2_subdev *sd,
}
static int adv7170_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -284,7 +284,7 @@ static int adv7170_get_fmt(struct v4l2_subdev *sd,
}
static int adv7170_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
diff --git a/drivers/media/i2c/adv7175.c b/drivers/media/i2c/adv7175.c
index 0cdd8e033197..1813f67f0fe1 100644
--- a/drivers/media/i2c/adv7175.c
+++ b/drivers/media/i2c/adv7175.c
@@ -288,7 +288,7 @@ static int adv7175_s_routing(struct v4l2_subdev *sd,
}
static int adv7175_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index >= ARRAY_SIZE(adv7175_codes))
@@ -299,7 +299,7 @@ static int adv7175_enum_mbus_code(struct v4l2_subdev *sd,
}
static int adv7175_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -322,7 +322,7 @@ static int adv7175_get_fmt(struct v4l2_subdev *sd,
}
static int adv7175_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 44bb6fe85644..fa5bc55bc944 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -633,7 +633,7 @@ static void adv7180_exit_controls(struct adv7180_state *state)
}
static int adv7180_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index != 0)
@@ -699,13 +699,13 @@ static int adv7180_set_field_mode(struct adv7180_state *state)
}
static int adv7180_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct adv7180_state *state = to_state(sd);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- format->format = *v4l2_subdev_get_try_format(sd, cfg, 0);
+ format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0);
} else {
adv7180_mbus_fmt(sd, &format->format);
format->format.field = state->field;
@@ -715,7 +715,7 @@ static int adv7180_get_pad_format(struct v4l2_subdev *sd,
}
static int adv7180_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct adv7180_state *state = to_state(sd);
@@ -742,7 +742,7 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd,
adv7180_set_power(state, true);
}
} else {
- framefmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
*framefmt = format->format;
}
@@ -750,14 +750,14 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd,
}
static int adv7180_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = {
- .which = cfg ? V4L2_SUBDEV_FORMAT_TRY
- : V4L2_SUBDEV_FORMAT_ACTIVE,
+ .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
+ : V4L2_SUBDEV_FORMAT_ACTIVE,
};
- return adv7180_set_pad_format(sd, cfg, &fmt);
+ return adv7180_set_pad_format(sd, sd_state, &fmt);
}
static int adv7180_get_mbus_config(struct v4l2_subdev *sd,
diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c
index 8bcd632c081a..92cafdea3f1f 100644
--- a/drivers/media/i2c/adv7183.c
+++ b/drivers/media/i2c/adv7183.c
@@ -409,7 +409,7 @@ static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status)
}
static int adv7183_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index > 0)
@@ -420,7 +420,7 @@ static int adv7183_enum_mbus_code(struct v4l2_subdev *sd,
}
static int adv7183_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct adv7183 *decoder = to_adv7183(sd);
@@ -443,12 +443,12 @@ static int adv7183_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
decoder->fmt = *fmt;
else
- cfg->try_fmt = *fmt;
+ sd_state->pads->try_fmt = *fmt;
return 0;
}
static int adv7183_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct adv7183 *decoder = to_adv7183(sd);
diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c
index 4052cf67bf16..02eabe10ab97 100644
--- a/drivers/media/i2c/adv748x/adv748x-afe.c
+++ b/drivers/media/i2c/adv748x/adv748x-afe.c
@@ -331,7 +331,7 @@ static int adv748x_afe_propagate_pixelrate(struct adv748x_afe *afe)
}
static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index != 0)
@@ -343,7 +343,7 @@ static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd,
}
static int adv748x_afe_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct adv748x_afe *afe = adv748x_sd_to_afe(sd);
@@ -354,7 +354,8 @@ static int adv748x_afe_get_format(struct v4l2_subdev *sd,
return -EINVAL;
if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) {
- mbusformat = v4l2_subdev_get_try_format(sd, cfg, sdformat->pad);
+ mbusformat = v4l2_subdev_get_try_format(sd, sd_state,
+ sdformat->pad);
sdformat->format = *mbusformat;
} else {
adv748x_afe_fill_format(afe, &sdformat->format);
@@ -365,7 +366,7 @@ static int adv748x_afe_get_format(struct v4l2_subdev *sd,
}
static int adv748x_afe_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct v4l2_mbus_framefmt *mbusformat;
@@ -375,9 +376,9 @@ static int adv748x_afe_set_format(struct v4l2_subdev *sd,
return -EINVAL;
if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- return adv748x_afe_get_format(sd, cfg, sdformat);
+ return adv748x_afe_get_format(sd, sd_state, sdformat);
- mbusformat = v4l2_subdev_get_try_format(sd, cfg, sdformat->pad);
+ mbusformat = v4l2_subdev_get_try_format(sd, sd_state, sdformat->pad);
*mbusformat = sdformat->format;
return 0;
diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index fa9278a08fde..589e9644fcdc 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -141,26 +141,26 @@ static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = {
static struct v4l2_mbus_framefmt *
adv748x_csi2_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, u32 which)
{
struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(sd, cfg, pad);
+ return v4l2_subdev_get_try_format(sd, sd_state, pad);
return &tx->format;
}
static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
struct adv748x_state *state = tx->state;
struct v4l2_mbus_framefmt *mbusformat;
- mbusformat = adv748x_csi2_get_pad_format(sd, cfg, sdformat->pad,
+ mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
sdformat->which);
if (!mbusformat)
return -EINVAL;
@@ -175,7 +175,7 @@ static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
}
static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
@@ -183,7 +183,7 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mbusformat;
int ret = 0;
- mbusformat = adv748x_csi2_get_pad_format(sd, cfg, sdformat->pad,
+ mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
sdformat->which);
if (!mbusformat)
return -EINVAL;
@@ -193,7 +193,7 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
if (sdformat->pad == ADV748X_CSI2_SOURCE) {
const struct v4l2_mbus_framefmt *sink_fmt;
- sink_fmt = adv748x_csi2_get_pad_format(sd, cfg,
+ sink_fmt = adv748x_csi2_get_pad_format(sd, sd_state,
ADV748X_CSI2_SINK,
sdformat->which);
diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c
index c557f8fdf11a..52fa7bd75660 100644
--- a/drivers/media/i2c/adv748x/adv748x-hdmi.c
+++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c
@@ -409,7 +409,7 @@ static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi *hdmi)
}
static int adv748x_hdmi_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index != 0)
@@ -421,7 +421,7 @@ static int adv748x_hdmi_enum_mbus_code(struct v4l2_subdev *sd,
}
static int adv748x_hdmi_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
@@ -431,7 +431,8 @@ static int adv748x_hdmi_get_format(struct v4l2_subdev *sd,
return -EINVAL;
if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) {
- mbusformat = v4l2_subdev_get_try_format(sd, cfg, sdformat->pad);
+ mbusformat = v4l2_subdev_get_try_format(sd, sd_state,
+ sdformat->pad);
sdformat->format = *mbusformat;
} else {
adv748x_hdmi_fill_format(hdmi, &sdformat->format);
@@ -442,7 +443,7 @@ static int adv748x_hdmi_get_format(struct v4l2_subdev *sd,
}
static int adv748x_hdmi_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct v4l2_mbus_framefmt *mbusformat;
@@ -451,9 +452,9 @@ static int adv748x_hdmi_set_format(struct v4l2_subdev *sd,
return -EINVAL;
if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- return adv748x_hdmi_get_format(sd, cfg, sdformat);
+ return adv748x_hdmi_get_format(sd, sd_state, sdformat);
- mbusformat = v4l2_subdev_get_try_format(sd, cfg, sdformat->pad);
+ mbusformat = v4l2_subdev_get_try_format(sd, sd_state, sdformat->pad);
*mbusformat = sdformat->format;
return 0;
diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c
index 5fc6c06edda1..41f4e749a859 100644
--- a/drivers/media/i2c/adv7511-v4l2.c
+++ b/drivers/media/i2c/adv7511-v4l2.c
@@ -1216,7 +1216,7 @@ static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
}
static int adv7511_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad != 0)
@@ -1247,7 +1247,7 @@ static void adv7511_fill_format(struct adv7511_state *state,
}
static int adv7511_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct adv7511_state *state = get_adv7511_state(sd);
@@ -1261,7 +1261,7 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
format->format.code = fmt->code;
format->format.colorspace = fmt->colorspace;
format->format.ycbcr_enc = fmt->ycbcr_enc;
@@ -1279,7 +1279,7 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd,
}
static int adv7511_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct adv7511_state *state = get_adv7511_state(sd);
@@ -1316,7 +1316,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
fmt->code = format->format.code;
fmt->colorspace = format->format.colorspace;
fmt->ycbcr_enc = format->format.ycbcr_enc;
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 3049aa2fd0f0..122e1fdccd96 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -1833,7 +1833,7 @@ static int adv76xx_s_routing(struct v4l2_subdev *sd,
}
static int adv76xx_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct adv76xx_state *state = to_state(sd);
@@ -1913,7 +1913,7 @@ static void adv76xx_setup_format(struct adv76xx_state *state)
}
static int adv76xx_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct adv76xx_state *state = to_state(sd);
@@ -1926,7 +1926,7 @@ static int adv76xx_get_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
format->format.code = fmt->code;
} else {
format->format.code = state->format->code;
@@ -1936,7 +1936,7 @@ static int adv76xx_get_format(struct v4l2_subdev *sd,
}
static int adv76xx_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct adv76xx_state *state = to_state(sd);
@@ -1956,7 +1956,7 @@ static int adv76xx_get_selection(struct v4l2_subdev *sd,
}
static int adv76xx_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct adv76xx_state *state = to_state(sd);
@@ -1975,7 +1975,7 @@ static int adv76xx_set_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
fmt->code = format->format.code;
} else {
state->format = info;
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index ff10af757b99..7f8acbdf0db4 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -98,12 +98,12 @@ struct adv7842_state {
v4l2_std_id norm;
struct {
- u8 edid[256];
+ u8 edid[512];
u32 blocks;
u32 present;
} hdmi_edid;
struct {
- u8 edid[256];
+ u8 edid[128];
u32 blocks;
u32 present;
} vga_edid;
@@ -720,6 +720,9 @@ static int edid_write_vga_segment(struct v4l2_subdev *sd)
v4l2_dbg(2, debug, sd, "%s: write EDID on VGA port\n", __func__);
+ if (!state->vga_edid.present)
+ return 0;
+
/* HPA disable on port A and B */
io_write_and_or(sd, 0x20, 0xcf, 0x00);
@@ -763,7 +766,7 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port)
struct adv7842_state *state = to_state(sd);
const u8 *edid = state->hdmi_edid.edid;
u32 blocks = state->hdmi_edid.blocks;
- int spa_loc;
+ unsigned int spa_loc;
u16 pa, parent_pa;
int err = 0;
int i;
@@ -796,12 +799,14 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port)
pa = (edid[spa_loc] << 8) | edid[spa_loc + 1];
}
- /* edid segment pointer '0' for HDMI ports */
- rep_write_and_or(sd, 0x77, 0xef, 0x00);
- for (i = 0; !err && i < blocks * 128; i += I2C_SMBUS_BLOCK_MAX)
+ for (i = 0; !err && i < blocks * 128; i += I2C_SMBUS_BLOCK_MAX) {
+ /* set edid segment pointer for HDMI ports */
+ if (i % 256 == 0)
+ rep_write_and_or(sd, 0x77, 0xef, i >= 256 ? 0x10 : 0x00);
err = i2c_smbus_write_i2c_block_data(state->i2c_edid, i,
I2C_SMBUS_BLOCK_MAX, edid + i);
+ }
if (err)
return err;
@@ -1988,7 +1993,7 @@ static int adv7842_s_routing(struct v4l2_subdev *sd,
}
static int adv7842_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(adv7842_formats))
@@ -2064,7 +2069,7 @@ static void adv7842_setup_format(struct adv7842_state *state)
}
static int adv7842_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct adv7842_state *state = to_state(sd);
@@ -2092,7 +2097,7 @@ static int adv7842_get_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
format->format.code = fmt->code;
} else {
format->format.code = state->format->code;
@@ -2102,7 +2107,7 @@ static int adv7842_get_format(struct v4l2_subdev *sd,
}
static int adv7842_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct adv7842_state *state = to_state(sd);
@@ -2112,7 +2117,7 @@ static int adv7842_set_format(struct v4l2_subdev *sd,
return -EINVAL;
if (state->mode == ADV7842_MODE_SDP)
- return adv7842_get_format(sd, cfg, format);
+ return adv7842_get_format(sd, sd_state, format);
info = adv7842_format_info(state, format->format.code);
if (info == NULL)
@@ -2124,7 +2129,7 @@ static int adv7842_set_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
fmt->code = format->format.code;
} else {
state->format = info;
@@ -2491,9 +2496,17 @@ static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
return 0;
}
+/*
+ * If the VGA_EDID_ENABLE bit is set (Repeater Map 0x7f, bit 7), then
+ * the first two blocks of the EDID are for the HDMI, and the first block
+ * of segment 1 (i.e. the third block of the EDID) is for VGA.
+ * So if a VGA EDID is installed, then the maximum size of the HDMI EDID
+ * is 2 blocks.
+ */
static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
{
struct adv7842_state *state = to_state(sd);
+ unsigned int max_blocks = e->pad == ADV7842_EDID_PORT_VGA ? 1 : 4;
int err = 0;
memset(e->reserved, 0, sizeof(e->reserved));
@@ -2502,8 +2515,12 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
return -EINVAL;
if (e->start_block != 0)
return -EINVAL;
- if (e->blocks > 2) {
- e->blocks = 2;
+ if (e->pad < ADV7842_EDID_PORT_VGA && state->vga_edid.blocks)
+ max_blocks = 2;
+ if (e->pad == ADV7842_EDID_PORT_VGA && state->hdmi_edid.blocks > 2)
+ return -EBUSY;
+ if (e->blocks > max_blocks) {
+ e->blocks = max_blocks;
return -E2BIG;
}
@@ -2514,20 +2531,20 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
switch (e->pad) {
case ADV7842_EDID_PORT_VGA:
- memset(&state->vga_edid.edid, 0, 256);
+ memset(state->vga_edid.edid, 0, sizeof(state->vga_edid.edid));
state->vga_edid.blocks = e->blocks;
state->vga_edid.present = e->blocks ? 0x1 : 0x0;
if (e->blocks)
- memcpy(&state->vga_edid.edid, e->edid, 128 * e->blocks);
+ memcpy(state->vga_edid.edid, e->edid, 128);
err = edid_write_vga_segment(sd);
break;
case ADV7842_EDID_PORT_A:
case ADV7842_EDID_PORT_B:
- memset(&state->hdmi_edid.edid, 0, 256);
+ memset(state->hdmi_edid.edid, 0, sizeof(state->hdmi_edid.edid));
state->hdmi_edid.blocks = e->blocks;
if (e->blocks) {
state->hdmi_edid.present |= 0x04 << e->pad;
- memcpy(&state->hdmi_edid.edid, e->edid, 128 * e->blocks);
+ memcpy(state->hdmi_edid.edid, e->edid, 128 * e->blocks);
} else {
state->hdmi_edid.present &= ~(0x04 << e->pad);
adv7842_s_detect_tx_5v_ctrl(sd);
diff --git a/drivers/media/i2c/ak7375.c b/drivers/media/i2c/ak7375.c
index e1f94ee0f48f..40b1a4aa846c 100644
--- a/drivers/media/i2c/ak7375.c
+++ b/drivers/media/i2c/ak7375.c
@@ -87,15 +87,7 @@ static const struct v4l2_ctrl_ops ak7375_vcm_ctrl_ops = {
static int ak7375_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- int ret;
-
- ret = pm_runtime_get_sync(sd->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(sd->dev);
- return ret;
- }
-
- return 0;
+ return pm_runtime_resume_and_get(sd->dev);
}
static int ak7375_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c
index 1adaf470c75a..dc569d5a4d9d 100644
--- a/drivers/media/i2c/ak881x.c
+++ b/drivers/media/i2c/ak881x.c
@@ -91,7 +91,7 @@ static int ak881x_s_register(struct v4l2_subdev *sd,
#endif
static int ak881x_fill_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -111,7 +111,7 @@ static int ak881x_fill_fmt(struct v4l2_subdev *sd,
}
static int ak881x_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index)
@@ -122,7 +122,7 @@ static int ak881x_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ak881x_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c
index 9dc3f45da3dc..a9403a227c6b 100644
--- a/drivers/media/i2c/ccs/ccs-core.c
+++ b/drivers/media/i2c/ccs/ccs-core.c
@@ -1880,21 +1880,33 @@ static int ccs_pm_get_init(struct ccs_sensor *sensor)
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
int rval;
+ /*
+ * It can't use pm_runtime_resume_and_get() here, as the driver
+ * relies at the returned value to detect if the device was already
+ * active or not.
+ */
rval = pm_runtime_get_sync(&client->dev);
- if (rval < 0) {
- pm_runtime_put_noidle(&client->dev);
+ if (rval < 0)
+ goto error;
- return rval;
- } else if (!rval) {
- rval = v4l2_ctrl_handler_setup(&sensor->pixel_array->
- ctrl_handler);
- if (rval)
- return rval;
+ /* Device was already active, so don't set controls */
+ if (rval == 1)
+ return 0;
- return v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler);
- }
+ /* Restore V4L2 controls to the previously suspended device */
+ rval = v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler);
+ if (rval)
+ goto error;
+
+ rval = v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler);
+ if (rval)
+ goto error;
+ /* Keep PM runtime usage_count incremented on success */
return 0;
+error:
+ pm_runtime_put(&client->dev);
+ return rval;
}
static int ccs_set_stream(struct v4l2_subdev *subdev, int enable)
@@ -1932,7 +1944,7 @@ static int ccs_set_stream(struct v4l2_subdev *subdev, int enable)
}
static int ccs_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct i2c_client *client = v4l2_get_subdevdata(subdev);
@@ -1985,13 +1997,13 @@ static u32 __ccs_get_mbus_code(struct v4l2_subdev *subdev, unsigned int pad)
}
static int __ccs_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ccs_subdev *ssd = to_ccs_subdev(subdev);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- fmt->format = *v4l2_subdev_get_try_format(subdev, cfg,
+ fmt->format = *v4l2_subdev_get_try_format(subdev, sd_state,
fmt->pad);
} else {
struct v4l2_rect *r;
@@ -2011,21 +2023,21 @@ static int __ccs_get_format(struct v4l2_subdev *subdev,
}
static int ccs_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ccs_sensor *sensor = to_ccs_sensor(subdev);
int rval;
mutex_lock(&sensor->mutex);
- rval = __ccs_get_format(subdev, cfg, fmt);
+ rval = __ccs_get_format(subdev, sd_state, fmt);
mutex_unlock(&sensor->mutex);
return rval;
}
static void ccs_get_crop_compose(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_rect **crops,
struct v4l2_rect **comps, int which)
{
@@ -2042,24 +2054,25 @@ static void ccs_get_crop_compose(struct v4l2_subdev *subdev,
if (crops) {
for (i = 0; i < subdev->entity.num_pads; i++)
crops[i] = v4l2_subdev_get_try_crop(subdev,
- cfg, i);
+ sd_state,
+ i);
}
if (comps)
- *comps = v4l2_subdev_get_try_compose(subdev, cfg,
+ *comps = v4l2_subdev_get_try_compose(subdev, sd_state,
CCS_PAD_SINK);
}
}
/* Changes require propagation only on sink pad. */
static void ccs_propagate(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg, int which,
+ struct v4l2_subdev_state *sd_state, int which,
int target)
{
struct ccs_sensor *sensor = to_ccs_sensor(subdev);
struct ccs_subdev *ssd = to_ccs_subdev(subdev);
struct v4l2_rect *comp, *crops[CCS_PADS];
- ccs_get_crop_compose(subdev, cfg, crops, &comp, which);
+ ccs_get_crop_compose(subdev, sd_state, crops, &comp, which);
switch (target) {
case V4L2_SEL_TGT_CROP:
@@ -2099,7 +2112,7 @@ static const struct ccs_csi_data_format
}
static int ccs_set_format_source(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ccs_sensor *sensor = to_ccs_sensor(subdev);
@@ -2110,7 +2123,7 @@ static int ccs_set_format_source(struct v4l2_subdev *subdev,
unsigned int i;
int rval;
- rval = __ccs_get_format(subdev, cfg, fmt);
+ rval = __ccs_get_format(subdev, sd_state, fmt);
if (rval)
return rval;
@@ -2152,7 +2165,7 @@ static int ccs_set_format_source(struct v4l2_subdev *subdev,
}
static int ccs_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ccs_sensor *sensor = to_ccs_sensor(subdev);
@@ -2164,7 +2177,7 @@ static int ccs_set_format(struct v4l2_subdev *subdev,
if (fmt->pad == ssd->source_pad) {
int rval;
- rval = ccs_set_format_source(subdev, cfg, fmt);
+ rval = ccs_set_format_source(subdev, sd_state, fmt);
mutex_unlock(&sensor->mutex);
@@ -2186,7 +2199,7 @@ static int ccs_set_format(struct v4l2_subdev *subdev,
CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE),
CCS_LIM(sensor, MAX_Y_OUTPUT_SIZE));
- ccs_get_crop_compose(subdev, cfg, crops, NULL, fmt->which);
+ ccs_get_crop_compose(subdev, sd_state, crops, NULL, fmt->which);
crops[ssd->sink_pad]->left = 0;
crops[ssd->sink_pad]->top = 0;
@@ -2194,7 +2207,7 @@ static int ccs_set_format(struct v4l2_subdev *subdev,
crops[ssd->sink_pad]->height = fmt->format.height;
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
ssd->sink_fmt = *crops[ssd->sink_pad];
- ccs_propagate(subdev, cfg, fmt->which, V4L2_SEL_TGT_CROP);
+ ccs_propagate(subdev, sd_state, fmt->which, V4L2_SEL_TGT_CROP);
mutex_unlock(&sensor->mutex);
@@ -2246,7 +2259,7 @@ static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w,
}
static void ccs_set_compose_binner(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel,
struct v4l2_rect **crops,
struct v4l2_rect *comp)
@@ -2294,7 +2307,7 @@ static void ccs_set_compose_binner(struct v4l2_subdev *subdev,
* result.
*/
static void ccs_set_compose_scaler(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel,
struct v4l2_rect **crops,
struct v4l2_rect *comp)
@@ -2409,25 +2422,25 @@ static void ccs_set_compose_scaler(struct v4l2_subdev *subdev,
}
/* We're only called on source pads. This function sets scaling. */
static int ccs_set_compose(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct ccs_sensor *sensor = to_ccs_sensor(subdev);
struct ccs_subdev *ssd = to_ccs_subdev(subdev);
struct v4l2_rect *comp, *crops[CCS_PADS];
- ccs_get_crop_compose(subdev, cfg, crops, &comp, sel->which);
+ ccs_get_crop_compose(subdev, sd_state, crops, &comp, sel->which);
sel->r.top = 0;
sel->r.left = 0;
if (ssd == sensor->binner)
- ccs_set_compose_binner(subdev, cfg, sel, crops, comp);
+ ccs_set_compose_binner(subdev, sd_state, sel, crops, comp);
else
- ccs_set_compose_scaler(subdev, cfg, sel, crops, comp);
+ ccs_set_compose_scaler(subdev, sd_state, sel, crops, comp);
*comp = sel->r;
- ccs_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_COMPOSE);
+ ccs_propagate(subdev, sd_state, sel->which, V4L2_SEL_TGT_COMPOSE);
if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return ccs_pll_blanking_update(sensor);
@@ -2474,7 +2487,7 @@ static int __ccs_sel_supported(struct v4l2_subdev *subdev,
}
static int ccs_set_crop(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct ccs_sensor *sensor = to_ccs_sensor(subdev);
@@ -2482,7 +2495,7 @@ static int ccs_set_crop(struct v4l2_subdev *subdev,
struct v4l2_rect *src_size, *crops[CCS_PADS];
struct v4l2_rect _r;
- ccs_get_crop_compose(subdev, cfg, crops, NULL, sel->which);
+ ccs_get_crop_compose(subdev, sd_state, crops, NULL, sel->which);
if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
if (sel->pad == ssd->sink_pad)
@@ -2493,16 +2506,18 @@ static int ccs_set_crop(struct v4l2_subdev *subdev,
if (sel->pad == ssd->sink_pad) {
_r.left = 0;
_r.top = 0;
- _r.width = v4l2_subdev_get_try_format(subdev, cfg,
+ _r.width = v4l2_subdev_get_try_format(subdev,
+ sd_state,
sel->pad)
->width;
- _r.height = v4l2_subdev_get_try_format(subdev, cfg,
+ _r.height = v4l2_subdev_get_try_format(subdev,
+ sd_state,
sel->pad)
->height;
src_size = &_r;
} else {
src_size = v4l2_subdev_get_try_compose(
- subdev, cfg, ssd->sink_pad);
+ subdev, sd_state, ssd->sink_pad);
}
}
@@ -2520,7 +2535,7 @@ static int ccs_set_crop(struct v4l2_subdev *subdev,
*crops[sel->pad] = sel->r;
if (ssd != sensor->pixel_array && sel->pad == CCS_PAD_SINK)
- ccs_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_CROP);
+ ccs_propagate(subdev, sd_state, sel->which, V4L2_SEL_TGT_CROP);
return 0;
}
@@ -2534,7 +2549,7 @@ static void ccs_get_native_size(struct ccs_subdev *ssd, struct v4l2_rect *r)
}
static int __ccs_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct ccs_sensor *sensor = to_ccs_sensor(subdev);
@@ -2547,13 +2562,14 @@ static int __ccs_get_selection(struct v4l2_subdev *subdev,
if (ret)
return ret;
- ccs_get_crop_compose(subdev, cfg, crops, &comp, sel->which);
+ ccs_get_crop_compose(subdev, sd_state, crops, &comp, sel->which);
if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
sink_fmt = ssd->sink_fmt;
} else {
struct v4l2_mbus_framefmt *fmt =
- v4l2_subdev_get_try_format(subdev, cfg, ssd->sink_pad);
+ v4l2_subdev_get_try_format(subdev, sd_state,
+ ssd->sink_pad);
sink_fmt.left = 0;
sink_fmt.top = 0;
@@ -2584,21 +2600,21 @@ static int __ccs_get_selection(struct v4l2_subdev *subdev,
}
static int ccs_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct ccs_sensor *sensor = to_ccs_sensor(subdev);
int rval;
mutex_lock(&sensor->mutex);
- rval = __ccs_get_selection(subdev, cfg, sel);
+ rval = __ccs_get_selection(subdev, sd_state, sel);
mutex_unlock(&sensor->mutex);
return rval;
}
static int ccs_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct ccs_sensor *sensor = to_ccs_sensor(subdev);
@@ -2622,10 +2638,10 @@ static int ccs_set_selection(struct v4l2_subdev *subdev,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- ret = ccs_set_crop(subdev, cfg, sel);
+ ret = ccs_set_crop(subdev, sd_state, sel);
break;
case V4L2_SEL_TGT_COMPOSE:
- ret = ccs_set_compose(subdev, cfg, sel);
+ ret = ccs_set_compose(subdev, sd_state, sel);
break;
default:
ret = -EINVAL;
@@ -3016,9 +3032,9 @@ static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
for (i = 0; i < ssd->npads; i++) {
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->pad, i);
+ v4l2_subdev_get_try_format(sd, fh->state, i);
struct v4l2_rect *try_crop =
- v4l2_subdev_get_try_crop(sd, fh->pad, i);
+ v4l2_subdev_get_try_crop(sd, fh->state, i);
struct v4l2_rect *try_comp;
ccs_get_native_size(ssd, try_crop);
@@ -3031,7 +3047,7 @@ static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
if (ssd != sensor->pixel_array)
continue;
- try_comp = v4l2_subdev_get_try_compose(sd, fh->pad, i);
+ try_comp = v4l2_subdev_get_try_compose(sd, fh->state, i);
*try_comp = *try_crop;
}
@@ -3089,12 +3105,9 @@ static int __maybe_unused ccs_suspend(struct device *dev)
bool streaming = sensor->streaming;
int rval;
- rval = pm_runtime_get_sync(dev);
- if (rval < 0) {
- pm_runtime_put_noidle(dev);
-
- return -EAGAIN;
- }
+ rval = pm_runtime_resume_and_get(dev);
+ if (rval < 0)
+ return rval;
if (sensor->streaming)
ccs_stop_streaming(sensor);
diff --git a/drivers/media/i2c/ccs/ccs-limits.c b/drivers/media/i2c/ccs/ccs-limits.c
index f5511789ac83..4969fa425317 100644
--- a/drivers/media/i2c/ccs/ccs-limits.c
+++ b/drivers/media/i2c/ccs/ccs-limits.c
@@ -1,5 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
/* Copyright (C) 2019--2020 Intel Corporation */
+/*
+ * Generated by Documentation/driver-api/media/drivers/ccs/mk-ccs-regs;
+ * do not modify.
+ */
#include "ccs-limits.h"
#include "ccs-regs.h"
diff --git a/drivers/media/i2c/ccs/ccs-limits.h b/drivers/media/i2c/ccs/ccs-limits.h
index 1efa43c23a2e..551d3ee9d04e 100644
--- a/drivers/media/i2c/ccs/ccs-limits.h
+++ b/drivers/media/i2c/ccs/ccs-limits.h
@@ -1,5 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */
/* Copyright (C) 2019--2020 Intel Corporation */
+/*
+ * Generated by Documentation/driver-api/media/drivers/ccs/mk-ccs-regs;
+ * do not modify.
+ */
#ifndef __CCS_LIMITS_H__
#define __CCS_LIMITS_H__
diff --git a/drivers/media/i2c/ccs/ccs-regs.h b/drivers/media/i2c/ccs/ccs-regs.h
index 4b3e5df2121f..6ce84c5ecf20 100644
--- a/drivers/media/i2c/ccs/ccs-regs.h
+++ b/drivers/media/i2c/ccs/ccs-regs.h
@@ -1,5 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */
/* Copyright (C) 2019--2020 Intel Corporation */
+/*
+ * Generated by Documentation/driver-api/media/drivers/ccs/mk-ccs-regs;
+ * do not modify.
+ */
#ifndef __CCS_REGS_H__
#define __CCS_REGS_H__
@@ -202,7 +206,7 @@
#define CCS_R_OP_PIX_CLK_DIV (0x0308 | CCS_FL_16BIT)
#define CCS_R_OP_SYS_CLK_DIV (0x030a | CCS_FL_16BIT)
#define CCS_R_OP_PRE_PLL_CLK_DIV (0x030c | CCS_FL_16BIT)
-#define CCS_R_OP_PLL_MULTIPLIER (0x031e | CCS_FL_16BIT)
+#define CCS_R_OP_PLL_MULTIPLIER (0x030e | CCS_FL_16BIT)
#define CCS_R_PLL_MODE 0x0310
#define CCS_PLL_MODE_SHIFT 0U
#define CCS_PLL_MODE_MASK 0x1
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index e2e935f78986..dc31944c7d5b 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -1746,7 +1746,7 @@ 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_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
diff --git a/drivers/media/i2c/dw9714.c b/drivers/media/i2c/dw9714.c
index 3f0b082f863f..c8b4292512dc 100644
--- a/drivers/media/i2c/dw9714.c
+++ b/drivers/media/i2c/dw9714.c
@@ -85,15 +85,7 @@ static const struct v4l2_ctrl_ops dw9714_vcm_ctrl_ops = {
static int dw9714_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- int rval;
-
- rval = pm_runtime_get_sync(sd->dev);
- if (rval < 0) {
- pm_runtime_put_noidle(sd->dev);
- return rval;
- }
-
- return 0;
+ return pm_runtime_resume_and_get(sd->dev);
}
static int dw9714_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
diff --git a/drivers/media/i2c/dw9768.c b/drivers/media/i2c/dw9768.c
index 8b8cb4b077b5..c086580efac7 100644
--- a/drivers/media/i2c/dw9768.c
+++ b/drivers/media/i2c/dw9768.c
@@ -374,15 +374,7 @@ static const struct v4l2_ctrl_ops dw9768_ctrl_ops = {
static int dw9768_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- int ret;
-
- ret = pm_runtime_get_sync(sd->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(sd->dev);
- return ret;
- }
-
- return 0;
+ return pm_runtime_resume_and_get(sd->dev);
}
static int dw9768_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
diff --git a/drivers/media/i2c/dw9807-vcm.c b/drivers/media/i2c/dw9807-vcm.c
index 438a44b76da8..95e06f13bc9e 100644
--- a/drivers/media/i2c/dw9807-vcm.c
+++ b/drivers/media/i2c/dw9807-vcm.c
@@ -130,15 +130,7 @@ static const struct v4l2_ctrl_ops dw9807_vcm_ctrl_ops = {
static int dw9807_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- int rval;
-
- rval = pm_runtime_get_sync(sd->dev);
- if (rval < 0) {
- pm_runtime_put_noidle(sd->dev);
- return rval;
- }
-
- return 0;
+ return pm_runtime_resume_and_get(sd->dev);
}
static int dw9807_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c
index bb3eac5e005e..c7b91c0c03b5 100644
--- a/drivers/media/i2c/et8ek8/et8ek8_driver.c
+++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c
@@ -882,7 +882,7 @@ out:
*/
#define MAX_FMTS 4
static int et8ek8_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct et8ek8_reglist **list =
@@ -920,7 +920,7 @@ static int et8ek8_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int et8ek8_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct et8ek8_reglist **list =
@@ -958,7 +958,7 @@ static int et8ek8_enum_frame_size(struct v4l2_subdev *subdev,
}
static int et8ek8_enum_frame_ival(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
struct et8ek8_reglist **list =
@@ -990,12 +990,13 @@ static int et8ek8_enum_frame_ival(struct v4l2_subdev *subdev,
static struct v4l2_mbus_framefmt *
__et8ek8_get_pad_format(struct et8ek8_sensor *sensor,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&sensor->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&sensor->subdev, sd_state,
+ pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &sensor->format;
default:
@@ -1004,13 +1005,14 @@ __et8ek8_get_pad_format(struct et8ek8_sensor *sensor,
}
static int et8ek8_get_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
struct v4l2_mbus_framefmt *format;
- format = __et8ek8_get_pad_format(sensor, cfg, fmt->pad, fmt->which);
+ format = __et8ek8_get_pad_format(sensor, sd_state, fmt->pad,
+ fmt->which);
if (!format)
return -EINVAL;
@@ -1020,14 +1022,15 @@ static int et8ek8_get_pad_format(struct v4l2_subdev *subdev,
}
static int et8ek8_set_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
struct v4l2_mbus_framefmt *format;
struct et8ek8_reglist *reglist;
- format = __et8ek8_get_pad_format(sensor, cfg, fmt->pad, fmt->which);
+ format = __et8ek8_get_pad_format(sensor, sd_state, fmt->pad,
+ fmt->which);
if (!format)
return -EINVAL;
@@ -1327,7 +1330,7 @@ static int et8ek8_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
struct et8ek8_reglist *reglist;
reglist = et8ek8_reglist_find_type(&meta_reglist, ET8EK8_REGLIST_MODE);
- format = __et8ek8_get_pad_format(sensor, fh->pad, 0,
+ format = __et8ek8_get_pad_format(sensor, fh->state, 0,
V4L2_SUBDEV_FORMAT_TRY);
et8ek8_reglist_to_mbus(reglist, format);
diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c
index 6f05c1138e3b..8db1cbedc1fd 100644
--- a/drivers/media/i2c/hi556.c
+++ b/drivers/media/i2c/hi556.c
@@ -813,9 +813,8 @@ static int hi556_set_stream(struct v4l2_subdev *sd, int enable)
mutex_lock(&hi556->mutex);
if (enable) {
- ret = pm_runtime_get_sync(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
mutex_unlock(&hi556->mutex);
return ret;
}
@@ -876,7 +875,7 @@ error:
}
static int hi556_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct hi556 *hi556 = to_hi556(sd);
@@ -891,7 +890,7 @@ static int hi556_set_format(struct v4l2_subdev *sd,
mutex_lock(&hi556->mutex);
hi556_assign_pad_format(mode, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+ *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
} else {
hi556->cur_mode = mode;
__v4l2_ctrl_s_ctrl(hi556->link_freq, mode->link_freq_index);
@@ -918,14 +917,15 @@ static int hi556_set_format(struct v4l2_subdev *sd,
}
static int hi556_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct hi556 *hi556 = to_hi556(sd);
mutex_lock(&hi556->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&hi556->sd, cfg,
+ fmt->format = *v4l2_subdev_get_try_format(&hi556->sd,
+ sd_state,
fmt->pad);
else
hi556_assign_pad_format(hi556->cur_mode, &fmt->format);
@@ -936,7 +936,7 @@ static int hi556_get_format(struct v4l2_subdev *sd,
}
static int hi556_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
@@ -948,7 +948,7 @@ static int hi556_enum_mbus_code(struct v4l2_subdev *sd,
}
static int hi556_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -971,7 +971,7 @@ static int hi556_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_lock(&hi556->mutex);
hi556_assign_pad_format(&supported_modes[0],
- v4l2_subdev_get_try_format(sd, fh->pad, 0));
+ v4l2_subdev_get_try_format(sd, fh->state, 0));
mutex_unlock(&hi556->mutex);
return 0;
diff --git a/drivers/media/i2c/imx208.c b/drivers/media/i2c/imx208.c
new file mode 100644
index 000000000000..6f3d9c1b5879
--- /dev/null
+++ b/drivers/media/i2c/imx208.c
@@ -0,0 +1,1088 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2021 Intel Corporation
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <asm/unaligned.h>
+
+#define IMX208_REG_MODE_SELECT 0x0100
+#define IMX208_MODE_STANDBY 0x00
+#define IMX208_MODE_STREAMING 0x01
+
+/* Chip ID */
+#define IMX208_REG_CHIP_ID 0x0000
+#define IMX208_CHIP_ID 0x0208
+
+/* V_TIMING internal */
+#define IMX208_REG_VTS 0x0340
+#define IMX208_VTS_60FPS 0x0472
+#define IMX208_VTS_BINNING 0x0239
+#define IMX208_VTS_60FPS_MIN 0x0458
+#define IMX208_VTS_BINNING_MIN 0x0230
+#define IMX208_VTS_MAX 0xffff
+
+/* HBLANK control - read only */
+#define IMX208_PPL_384MHZ 2248
+#define IMX208_PPL_96MHZ 2248
+
+/* Exposure control */
+#define IMX208_REG_EXPOSURE 0x0202
+#define IMX208_EXPOSURE_MIN 4
+#define IMX208_EXPOSURE_STEP 1
+#define IMX208_EXPOSURE_DEFAULT 0x190
+#define IMX208_EXPOSURE_MAX 65535
+
+/* Analog gain control */
+#define IMX208_REG_ANALOG_GAIN 0x0204
+#define IMX208_ANA_GAIN_MIN 0
+#define IMX208_ANA_GAIN_MAX 0x00e0
+#define IMX208_ANA_GAIN_STEP 1
+#define IMX208_ANA_GAIN_DEFAULT 0x0
+
+/* Digital gain control */
+#define IMX208_REG_GR_DIGITAL_GAIN 0x020e
+#define IMX208_REG_R_DIGITAL_GAIN 0x0210
+#define IMX208_REG_B_DIGITAL_GAIN 0x0212
+#define IMX208_REG_GB_DIGITAL_GAIN 0x0214
+#define IMX208_DIGITAL_GAIN_SHIFT 8
+
+/* Orientation */
+#define IMX208_REG_ORIENTATION_CONTROL 0x0101
+
+/* Test Pattern Control */
+#define IMX208_REG_TEST_PATTERN_MODE 0x0600
+#define IMX208_TEST_PATTERN_DISABLE 0x0
+#define IMX208_TEST_PATTERN_SOLID_COLOR 0x1
+#define IMX208_TEST_PATTERN_COLOR_BARS 0x2
+#define IMX208_TEST_PATTERN_GREY_COLOR 0x3
+#define IMX208_TEST_PATTERN_PN9 0x4
+#define IMX208_TEST_PATTERN_FIX_1 0x100
+#define IMX208_TEST_PATTERN_FIX_2 0x101
+#define IMX208_TEST_PATTERN_FIX_3 0x102
+#define IMX208_TEST_PATTERN_FIX_4 0x103
+#define IMX208_TEST_PATTERN_FIX_5 0x104
+#define IMX208_TEST_PATTERN_FIX_6 0x105
+
+/* OTP Access */
+#define IMX208_OTP_BASE 0x3500
+#define IMX208_OTP_SIZE 40
+
+struct imx208_reg {
+ u16 address;
+ u8 val;
+};
+
+struct imx208_reg_list {
+ u32 num_of_regs;
+ const struct imx208_reg *regs;
+};
+
+/* Link frequency config */
+struct imx208_link_freq_config {
+ u32 pixels_per_line;
+
+ /* PLL registers for this link frequency */
+ struct imx208_reg_list reg_list;
+};
+
+/* Mode : resolution and related config&values */
+struct imx208_mode {
+ /* Frame width */
+ u32 width;
+ /* Frame height */
+ u32 height;
+
+ /* V-timing */
+ u32 vts_def;
+ u32 vts_min;
+
+ /* Index of Link frequency config to be used */
+ u32 link_freq_index;
+ /* Default register values */
+ struct imx208_reg_list reg_list;
+};
+
+static const struct imx208_reg pll_ctrl_reg[] = {
+ {0x0305, 0x02},
+ {0x0307, 0x50},
+ {0x303C, 0x3C},
+};
+
+static const struct imx208_reg mode_1936x1096_60fps_regs[] = {
+ {0x0340, 0x04},
+ {0x0341, 0x72},
+ {0x0342, 0x04},
+ {0x0343, 0x64},
+ {0x034C, 0x07},
+ {0x034D, 0x90},
+ {0x034E, 0x04},
+ {0x034F, 0x48},
+ {0x0381, 0x01},
+ {0x0383, 0x01},
+ {0x0385, 0x01},
+ {0x0387, 0x01},
+ {0x3048, 0x00},
+ {0x3050, 0x01},
+ {0x30D5, 0x00},
+ {0x3301, 0x00},
+ {0x3318, 0x62},
+ {0x0202, 0x01},
+ {0x0203, 0x90},
+ {0x0205, 0x00},
+};
+
+static const struct imx208_reg mode_968_548_60fps_regs[] = {
+ {0x0340, 0x02},
+ {0x0341, 0x39},
+ {0x0342, 0x08},
+ {0x0343, 0xC8},
+ {0x034C, 0x03},
+ {0x034D, 0xC8},
+ {0x034E, 0x02},
+ {0x034F, 0x24},
+ {0x0381, 0x01},
+ {0x0383, 0x03},
+ {0x0385, 0x01},
+ {0x0387, 0x03},
+ {0x3048, 0x01},
+ {0x3050, 0x02},
+ {0x30D5, 0x03},
+ {0x3301, 0x10},
+ {0x3318, 0x75},
+ {0x0202, 0x01},
+ {0x0203, 0x90},
+ {0x0205, 0x00},
+};
+
+static const s64 imx208_discrete_digital_gain[] = {
+ 1, 2, 4, 8, 16,
+};
+
+static const char * const imx208_test_pattern_menu[] = {
+ "Disabled",
+ "Solid Color",
+ "100% Color Bar",
+ "Fade to Grey Color Bar",
+ "PN9",
+ "Fixed Pattern1",
+ "Fixed Pattern2",
+ "Fixed Pattern3",
+ "Fixed Pattern4",
+ "Fixed Pattern5",
+ "Fixed Pattern6"
+};
+
+static const int imx208_test_pattern_val[] = {
+ IMX208_TEST_PATTERN_DISABLE,
+ IMX208_TEST_PATTERN_SOLID_COLOR,
+ IMX208_TEST_PATTERN_COLOR_BARS,
+ IMX208_TEST_PATTERN_GREY_COLOR,
+ IMX208_TEST_PATTERN_PN9,
+ IMX208_TEST_PATTERN_FIX_1,
+ IMX208_TEST_PATTERN_FIX_2,
+ IMX208_TEST_PATTERN_FIX_3,
+ IMX208_TEST_PATTERN_FIX_4,
+ IMX208_TEST_PATTERN_FIX_5,
+ IMX208_TEST_PATTERN_FIX_6,
+};
+
+/* Configurations for supported link frequencies */
+#define IMX208_MHZ (1000 * 1000ULL)
+#define IMX208_LINK_FREQ_384MHZ (384ULL * IMX208_MHZ)
+#define IMX208_LINK_FREQ_96MHZ (96ULL * IMX208_MHZ)
+
+#define IMX208_DATA_RATE_DOUBLE 2
+#define IMX208_NUM_OF_LANES 2
+#define IMX208_PIXEL_BITS 10
+
+enum {
+ IMX208_LINK_FREQ_384MHZ_INDEX,
+ IMX208_LINK_FREQ_96MHZ_INDEX,
+};
+
+/*
+ * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
+ * data rate => double data rate; number of lanes => 2; bits per pixel => 10
+ */
+static u64 link_freq_to_pixel_rate(u64 f)
+{
+ f *= IMX208_DATA_RATE_DOUBLE * IMX208_NUM_OF_LANES;
+ do_div(f, IMX208_PIXEL_BITS);
+
+ return f;
+}
+
+/* Menu items for LINK_FREQ V4L2 control */
+static const s64 link_freq_menu_items[] = {
+ [IMX208_LINK_FREQ_384MHZ_INDEX] = IMX208_LINK_FREQ_384MHZ,
+ [IMX208_LINK_FREQ_96MHZ_INDEX] = IMX208_LINK_FREQ_96MHZ,
+};
+
+/* Link frequency configs */
+static const struct imx208_link_freq_config link_freq_configs[] = {
+ [IMX208_LINK_FREQ_384MHZ_INDEX] = {
+ .pixels_per_line = IMX208_PPL_384MHZ,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(pll_ctrl_reg),
+ .regs = pll_ctrl_reg,
+ }
+ },
+ [IMX208_LINK_FREQ_96MHZ_INDEX] = {
+ .pixels_per_line = IMX208_PPL_96MHZ,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(pll_ctrl_reg),
+ .regs = pll_ctrl_reg,
+ }
+ },
+};
+
+/* Mode configs */
+static const struct imx208_mode supported_modes[] = {
+ {
+ .width = 1936,
+ .height = 1096,
+ .vts_def = IMX208_VTS_60FPS,
+ .vts_min = IMX208_VTS_60FPS_MIN,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1936x1096_60fps_regs),
+ .regs = mode_1936x1096_60fps_regs,
+ },
+ .link_freq_index = IMX208_LINK_FREQ_384MHZ_INDEX,
+ },
+ {
+ .width = 968,
+ .height = 548,
+ .vts_def = IMX208_VTS_BINNING,
+ .vts_min = IMX208_VTS_BINNING_MIN,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_968_548_60fps_regs),
+ .regs = mode_968_548_60fps_regs,
+ },
+ .link_freq_index = IMX208_LINK_FREQ_96MHZ_INDEX,
+ },
+};
+
+struct imx208 {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ /* V4L2 Controls */
+ struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *pixel_rate;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *hflip;
+
+ /* Current mode */
+ const struct imx208_mode *cur_mode;
+
+ /*
+ * Mutex for serialized access:
+ * Protect sensor set pad format and start/stop streaming safely.
+ * Protect access to sensor v4l2 controls.
+ */
+ struct mutex imx208_mx;
+
+ /* Streaming on/off */
+ bool streaming;
+
+ /* OTP data */
+ bool otp_read;
+ char otp_data[IMX208_OTP_SIZE];
+};
+
+static inline struct imx208 *to_imx208(struct v4l2_subdev *_sd)
+{
+ return container_of(_sd, struct imx208, sd);
+}
+
+/* Get bayer order based on flip setting. */
+static u32 imx208_get_format_code(struct imx208 *imx208)
+{
+ /*
+ * Only one bayer order is supported.
+ * It depends on the flip settings.
+ */
+ static const u32 codes[2][2] = {
+ { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, },
+ { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, },
+ };
+
+ return codes[imx208->vflip->val][imx208->hflip->val];
+}
+
+/* Read registers up to 4 at a time */
+static int imx208_read_reg(struct imx208 *imx208, u16 reg, u32 len, u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+ struct i2c_msg msgs[2];
+ u8 addr_buf[2] = { reg >> 8, reg & 0xff };
+ u8 data_buf[4] = { 0, };
+ int ret;
+
+ if (len > 4)
+ return -EINVAL;
+
+ /* Write register address */
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = ARRAY_SIZE(addr_buf);
+ msgs[0].buf = addr_buf;
+
+ /* Read data from register */
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = &data_buf[4 - len];
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
+
+ *val = get_unaligned_be32(data_buf);
+
+ return 0;
+}
+
+/* Write registers up to 4 at a time */
+static int imx208_write_reg(struct imx208 *imx208, u16 reg, u32 len, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+ u8 buf[6];
+
+ if (len > 4)
+ return -EINVAL;
+
+ put_unaligned_be16(reg, buf);
+ put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
+ if (i2c_master_send(client, buf, len + 2) != len + 2)
+ return -EIO;
+
+ return 0;
+}
+
+/* Write a list of registers */
+static int imx208_write_regs(struct imx208 *imx208,
+ const struct imx208_reg *regs, u32 len)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < len; i++) {
+ ret = imx208_write_reg(imx208, regs[i].address, 1,
+ regs[i].val);
+ if (ret) {
+ dev_err_ratelimited(&client->dev,
+ "Failed to write reg 0x%4.4x. error = %d\n",
+ regs[i].address, ret);
+
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* Open sub-device */
+static int imx208_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *try_fmt =
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
+
+ /* Initialize try_fmt */
+ try_fmt->width = supported_modes[0].width;
+ try_fmt->height = supported_modes[0].height;
+ try_fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
+ try_fmt->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int imx208_update_digital_gain(struct imx208 *imx208, u32 len, u32 val)
+{
+ int ret;
+
+ val = imx208_discrete_digital_gain[val] << IMX208_DIGITAL_GAIN_SHIFT;
+
+ ret = imx208_write_reg(imx208, IMX208_REG_GR_DIGITAL_GAIN, 2, val);
+ if (ret)
+ return ret;
+
+ ret = imx208_write_reg(imx208, IMX208_REG_GB_DIGITAL_GAIN, 2, val);
+ if (ret)
+ return ret;
+
+ ret = imx208_write_reg(imx208, IMX208_REG_R_DIGITAL_GAIN, 2, val);
+ if (ret)
+ return ret;
+
+ return imx208_write_reg(imx208, IMX208_REG_B_DIGITAL_GAIN, 2, val);
+}
+
+static int imx208_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct imx208 *imx208 =
+ container_of(ctrl->handler, struct imx208, ctrl_handler);
+ struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+ int ret;
+
+ /*
+ * Applying V4L2 control value only happens
+ * when power is up for streaming
+ */
+ if (!pm_runtime_get_if_in_use(&client->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = imx208_write_reg(imx208, IMX208_REG_ANALOG_GAIN,
+ 2, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ ret = imx208_write_reg(imx208, IMX208_REG_EXPOSURE,
+ 2, ctrl->val);
+ break;
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = imx208_update_digital_gain(imx208, 2, ctrl->val);
+ break;
+ case V4L2_CID_VBLANK:
+ /* Update VTS that meets expected vertical blanking */
+ ret = imx208_write_reg(imx208, IMX208_REG_VTS, 2,
+ imx208->cur_mode->height + ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = imx208_write_reg(imx208, IMX208_REG_TEST_PATTERN_MODE,
+ 2, imx208_test_pattern_val[ctrl->val]);
+ break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ ret = imx208_write_reg(imx208, IMX208_REG_ORIENTATION_CONTROL,
+ 1,
+ imx208->hflip->val |
+ imx208->vflip->val << 1);
+ break;
+ default:
+ ret = -EINVAL;
+ dev_err(&client->dev,
+ "ctrl(id:0x%x,val:0x%x) is not handled\n",
+ ctrl->id, ctrl->val);
+ break;
+ }
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops imx208_ctrl_ops = {
+ .s_ctrl = imx208_set_ctrl,
+};
+
+static const struct v4l2_ctrl_config imx208_digital_gain_control = {
+ .ops = &imx208_ctrl_ops,
+ .id = V4L2_CID_DIGITAL_GAIN,
+ .name = "Digital Gain",
+ .type = V4L2_CTRL_TYPE_INTEGER_MENU,
+ .min = 0,
+ .max = ARRAY_SIZE(imx208_discrete_digital_gain) - 1,
+ .step = 0,
+ .def = 0,
+ .menu_skip_mask = 0,
+ .qmenu_int = imx208_discrete_digital_gain,
+};
+
+static int imx208_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct imx208 *imx208 = to_imx208(sd);
+
+ if (code->index > 0)
+ return -EINVAL;
+
+ code->code = imx208_get_format_code(imx208);
+
+ return 0;
+}
+
+static int imx208_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct imx208 *imx208 = to_imx208(sd);
+
+ if (fse->index >= ARRAY_SIZE(supported_modes))
+ return -EINVAL;
+
+ if (fse->code != imx208_get_format_code(imx208))
+ return -EINVAL;
+
+ fse->min_width = supported_modes[fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->min_height = supported_modes[fse->index].height;
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+
+static void imx208_mode_to_pad_format(struct imx208 *imx208,
+ const struct imx208_mode *mode,
+ struct v4l2_subdev_format *fmt)
+{
+ fmt->format.width = mode->width;
+ fmt->format.height = mode->height;
+ fmt->format.code = imx208_get_format_code(imx208);
+ fmt->format.field = V4L2_FIELD_NONE;
+}
+
+static int __imx208_get_pad_format(struct imx208 *imx208,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+ fmt->format = *v4l2_subdev_get_try_format(&imx208->sd,
+ sd_state,
+ fmt->pad);
+ else
+ imx208_mode_to_pad_format(imx208, imx208->cur_mode, fmt);
+
+ return 0;
+}
+
+static int imx208_get_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct imx208 *imx208 = to_imx208(sd);
+ int ret;
+
+ mutex_lock(&imx208->imx208_mx);
+ ret = __imx208_get_pad_format(imx208, sd_state, fmt);
+ mutex_unlock(&imx208->imx208_mx);
+
+ return ret;
+}
+
+static int imx208_set_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct imx208 *imx208 = to_imx208(sd);
+ const struct imx208_mode *mode;
+ s32 vblank_def;
+ s32 vblank_min;
+ s64 h_blank;
+ s64 pixel_rate;
+ s64 link_freq;
+
+ mutex_lock(&imx208->imx208_mx);
+
+ fmt->format.code = imx208_get_format_code(imx208);
+ mode = v4l2_find_nearest_size(supported_modes,
+ ARRAY_SIZE(supported_modes), width, height,
+ fmt->format.width, fmt->format.height);
+ imx208_mode_to_pad_format(imx208, mode, fmt);
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
+ } else {
+ imx208->cur_mode = mode;
+ __v4l2_ctrl_s_ctrl(imx208->link_freq, mode->link_freq_index);
+ link_freq = link_freq_menu_items[mode->link_freq_index];
+ pixel_rate = link_freq_to_pixel_rate(link_freq);
+ __v4l2_ctrl_s_ctrl_int64(imx208->pixel_rate, pixel_rate);
+ /* Update limits and set FPS to default */
+ vblank_def = imx208->cur_mode->vts_def -
+ imx208->cur_mode->height;
+ vblank_min = imx208->cur_mode->vts_min -
+ imx208->cur_mode->height;
+ __v4l2_ctrl_modify_range(imx208->vblank, vblank_min,
+ IMX208_VTS_MAX - imx208->cur_mode->height,
+ 1, vblank_def);
+ __v4l2_ctrl_s_ctrl(imx208->vblank, vblank_def);
+ h_blank =
+ link_freq_configs[mode->link_freq_index].pixels_per_line
+ - imx208->cur_mode->width;
+ __v4l2_ctrl_modify_range(imx208->hblank, h_blank,
+ h_blank, 1, h_blank);
+ }
+
+ mutex_unlock(&imx208->imx208_mx);
+
+ return 0;
+}
+
+/* Start streaming */
+static int imx208_start_streaming(struct imx208 *imx208)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+ const struct imx208_reg_list *reg_list;
+ int ret, link_freq_index;
+
+ /* Setup PLL */
+ link_freq_index = imx208->cur_mode->link_freq_index;
+ reg_list = &link_freq_configs[link_freq_index].reg_list;
+ ret = imx208_write_regs(imx208, reg_list->regs, reg_list->num_of_regs);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set plls\n", __func__);
+ return ret;
+ }
+
+ /* Apply default values of current mode */
+ reg_list = &imx208->cur_mode->reg_list;
+ ret = imx208_write_regs(imx208, reg_list->regs, reg_list->num_of_regs);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set mode\n", __func__);
+ return ret;
+ }
+
+ /* Apply customized values from user */
+ ret = __v4l2_ctrl_handler_setup(imx208->sd.ctrl_handler);
+ if (ret)
+ return ret;
+
+ /* set stream on register */
+ return imx208_write_reg(imx208, IMX208_REG_MODE_SELECT,
+ 1, IMX208_MODE_STREAMING);
+}
+
+/* Stop streaming */
+static int imx208_stop_streaming(struct imx208 *imx208)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+ int ret;
+
+ /* set stream off register */
+ ret = imx208_write_reg(imx208, IMX208_REG_MODE_SELECT,
+ 1, IMX208_MODE_STANDBY);
+ if (ret)
+ dev_err(&client->dev, "%s failed to set stream\n", __func__);
+
+ /*
+ * Return success even if it was an error, as there is nothing the
+ * caller can do about it.
+ */
+ return 0;
+}
+
+static int imx208_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct imx208 *imx208 = to_imx208(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ mutex_lock(&imx208->imx208_mx);
+ if (imx208->streaming == enable) {
+ mutex_unlock(&imx208->imx208_mx);
+ return 0;
+ }
+
+ if (enable) {
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0)
+ goto err_rpm_put;
+
+ /*
+ * Apply default & customized values
+ * and then start streaming.
+ */
+ ret = imx208_start_streaming(imx208);
+ if (ret)
+ goto err_rpm_put;
+ } else {
+ imx208_stop_streaming(imx208);
+ pm_runtime_put(&client->dev);
+ }
+
+ imx208->streaming = enable;
+ mutex_unlock(&imx208->imx208_mx);
+
+ /* vflip and hflip cannot change during streaming */
+ v4l2_ctrl_grab(imx208->vflip, enable);
+ v4l2_ctrl_grab(imx208->hflip, enable);
+
+ return ret;
+
+err_rpm_put:
+ pm_runtime_put(&client->dev);
+ mutex_unlock(&imx208->imx208_mx);
+
+ return ret;
+}
+
+static int __maybe_unused imx208_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx208 *imx208 = to_imx208(sd);
+
+ if (imx208->streaming)
+ imx208_stop_streaming(imx208);
+
+ return 0;
+}
+
+static int __maybe_unused imx208_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx208 *imx208 = to_imx208(sd);
+ int ret;
+
+ if (imx208->streaming) {
+ ret = imx208_start_streaming(imx208);
+ if (ret)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ imx208_stop_streaming(imx208);
+ imx208->streaming = 0;
+
+ return ret;
+}
+
+/* Verify chip ID */
+static int imx208_identify_module(struct imx208 *imx208)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+ int ret;
+ u32 val;
+
+ ret = imx208_read_reg(imx208, IMX208_REG_CHIP_ID,
+ 2, &val);
+ if (ret) {
+ dev_err(&client->dev, "failed to read chip id %x\n",
+ IMX208_CHIP_ID);
+ return ret;
+ }
+
+ if (val != IMX208_CHIP_ID) {
+ dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
+ IMX208_CHIP_ID, val);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops imx208_video_ops = {
+ .s_stream = imx208_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops imx208_pad_ops = {
+ .enum_mbus_code = imx208_enum_mbus_code,
+ .get_fmt = imx208_get_pad_format,
+ .set_fmt = imx208_set_pad_format,
+ .enum_frame_size = imx208_enum_frame_size,
+};
+
+static const struct v4l2_subdev_ops imx208_subdev_ops = {
+ .video = &imx208_video_ops,
+ .pad = &imx208_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops imx208_internal_ops = {
+ .open = imx208_open,
+};
+
+static int imx208_read_otp(struct imx208 *imx208)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+ struct i2c_msg msgs[2];
+ u8 addr_buf[2] = { IMX208_OTP_BASE >> 8, IMX208_OTP_BASE & 0xff };
+ int ret = 0;
+
+ mutex_lock(&imx208->imx208_mx);
+
+ if (imx208->otp_read)
+ goto out_unlock;
+
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(&client->dev);
+ goto out_unlock;
+ }
+
+ /* Write register address */
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = ARRAY_SIZE(addr_buf);
+ msgs[0].buf = addr_buf;
+
+ /* Read data from registers */
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = sizeof(imx208->otp_data);
+ msgs[1].buf = imx208->otp_data;
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret == ARRAY_SIZE(msgs)) {
+ imx208->otp_read = true;
+ ret = 0;
+ }
+
+ pm_runtime_put(&client->dev);
+
+out_unlock:
+ mutex_unlock(&imx208->imx208_mx);
+
+ return ret;
+}
+
+static ssize_t otp_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(kobj_to_dev(kobj));
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx208 *imx208 = to_imx208(sd);
+ int ret;
+
+ ret = imx208_read_otp(imx208);
+ if (ret)
+ return ret;
+
+ memcpy(buf, &imx208->otp_data[off], count);
+ return count;
+}
+
+static const BIN_ATTR_RO(otp, IMX208_OTP_SIZE);
+
+/* Initialize control handlers */
+static int imx208_init_controls(struct imx208 *imx208)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd);
+ struct v4l2_ctrl_handler *ctrl_hdlr = &imx208->ctrl_handler;
+ s64 exposure_max;
+ s64 vblank_def;
+ s64 vblank_min;
+ s64 pixel_rate_min;
+ s64 pixel_rate_max;
+ int ret;
+
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
+ if (ret)
+ return ret;
+
+ mutex_init(&imx208->imx208_mx);
+ ctrl_hdlr->lock = &imx208->imx208_mx;
+ imx208->link_freq =
+ v4l2_ctrl_new_int_menu(ctrl_hdlr,
+ &imx208_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(link_freq_menu_items) - 1,
+ 0, link_freq_menu_items);
+
+ if (imx208->link_freq)
+ imx208->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]);
+ pixel_rate_min =
+ link_freq_to_pixel_rate(link_freq_menu_items[ARRAY_SIZE(link_freq_menu_items) - 1]);
+ /* By default, PIXEL_RATE is read only */
+ imx208->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops,
+ V4L2_CID_PIXEL_RATE,
+ pixel_rate_min, pixel_rate_max,
+ 1, pixel_rate_max);
+
+ vblank_def = imx208->cur_mode->vts_def - imx208->cur_mode->height;
+ vblank_min = imx208->cur_mode->vts_min - imx208->cur_mode->height;
+ imx208->vblank =
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops, V4L2_CID_VBLANK,
+ vblank_min,
+ IMX208_VTS_MAX - imx208->cur_mode->height, 1,
+ vblank_def);
+
+ imx208->hblank =
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops, V4L2_CID_HBLANK,
+ IMX208_PPL_384MHZ - imx208->cur_mode->width,
+ IMX208_PPL_384MHZ - imx208->cur_mode->width,
+ 1,
+ IMX208_PPL_384MHZ - imx208->cur_mode->width);
+
+ if (imx208->hblank)
+ imx208->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ exposure_max = imx208->cur_mode->vts_def - 8;
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops, V4L2_CID_EXPOSURE,
+ IMX208_EXPOSURE_MIN, exposure_max,
+ IMX208_EXPOSURE_STEP, IMX208_EXPOSURE_DEFAULT);
+
+ imx208->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ imx208->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx208_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ IMX208_ANA_GAIN_MIN, IMX208_ANA_GAIN_MAX,
+ IMX208_ANA_GAIN_STEP, IMX208_ANA_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_custom(ctrl_hdlr, &imx208_digital_gain_control, NULL);
+
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx208_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx208_test_pattern_menu) - 1,
+ 0, 0, imx208_test_pattern_menu);
+
+ if (ctrl_hdlr->error) {
+ ret = ctrl_hdlr->error;
+ dev_err(&client->dev, "%s control init failed (%d)\n",
+ __func__, ret);
+ goto error;
+ }
+
+ imx208->sd.ctrl_handler = ctrl_hdlr;
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+ mutex_destroy(&imx208->imx208_mx);
+
+ return ret;
+}
+
+static void imx208_free_controls(struct imx208 *imx208)
+{
+ v4l2_ctrl_handler_free(imx208->sd.ctrl_handler);
+}
+
+static int imx208_probe(struct i2c_client *client)
+{
+ struct imx208 *imx208;
+ int ret;
+ u32 val = 0;
+
+ device_property_read_u32(&client->dev, "clock-frequency", &val);
+ if (val != 19200000) {
+ dev_err(&client->dev,
+ "Unsupported clock-frequency %u. Expected 19200000.\n",
+ val);
+ return -EINVAL;
+ }
+
+ imx208 = devm_kzalloc(&client->dev, sizeof(*imx208), GFP_KERNEL);
+ if (!imx208)
+ return -ENOMEM;
+
+ /* Initialize subdev */
+ v4l2_i2c_subdev_init(&imx208->sd, client, &imx208_subdev_ops);
+
+ /* Check module identity */
+ ret = imx208_identify_module(imx208);
+ if (ret) {
+ dev_err(&client->dev, "failed to find sensor: %d", ret);
+ goto error_probe;
+ }
+
+ /* Set default mode to max resolution */
+ imx208->cur_mode = &supported_modes[0];
+
+ ret = imx208_init_controls(imx208);
+ if (ret) {
+ dev_err(&client->dev, "failed to init controls: %d", ret);
+ goto error_probe;
+ }
+
+ /* Initialize subdev */
+ imx208->sd.internal_ops = &imx208_internal_ops;
+ imx208->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ imx208->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ /* Initialize source pad */
+ imx208->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&imx208->sd.entity, 1, &imx208->pad);
+ if (ret) {
+ dev_err(&client->dev, "%s failed:%d\n", __func__, ret);
+ goto error_handler_free;
+ }
+
+ ret = v4l2_async_register_subdev_sensor(&imx208->sd);
+ if (ret < 0)
+ goto error_media_entity;
+
+ ret = device_create_bin_file(&client->dev, &bin_attr_otp);
+ if (ret) {
+ dev_err(&client->dev, "sysfs otp creation failed\n");
+ goto error_async_subdev;
+ }
+
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_enable(&client->dev);
+ pm_runtime_idle(&client->dev);
+
+ return 0;
+
+error_async_subdev:
+ v4l2_async_unregister_subdev(&imx208->sd);
+
+error_media_entity:
+ media_entity_cleanup(&imx208->sd.entity);
+
+error_handler_free:
+ imx208_free_controls(imx208);
+
+error_probe:
+ mutex_destroy(&imx208->imx208_mx);
+
+ return ret;
+}
+
+static int imx208_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx208 *imx208 = to_imx208(sd);
+
+ device_remove_bin_file(&client->dev, &bin_attr_otp);
+ v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ imx208_free_controls(imx208);
+
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
+ mutex_destroy(&imx208->imx208_mx);
+
+ return 0;
+}
+
+static const struct dev_pm_ops imx208_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(imx208_suspend, imx208_resume)
+};
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id imx208_acpi_ids[] = {
+ { "INT3478" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(acpi, imx208_acpi_ids);
+#endif
+
+static struct i2c_driver imx208_i2c_driver = {
+ .driver = {
+ .name = "imx208",
+ .pm = &imx208_pm_ops,
+ .acpi_match_table = ACPI_PTR(imx208_acpi_ids),
+ },
+ .probe_new = imx208_probe,
+ .remove = imx208_remove,
+};
+
+module_i2c_driver(imx208_i2c_driver);
+
+MODULE_AUTHOR("Yeh, Andy <andy.yeh@intel.com>");
+MODULE_AUTHOR("Chen, Ping-chung <ping-chung.chen@intel.com>");
+MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>");
+MODULE_DESCRIPTION("Sony IMX208 sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index e8b281e432e8..83c1737abeec 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -474,7 +474,7 @@ static int __maybe_unused imx214_power_off(struct device *dev)
}
static int imx214_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
@@ -486,7 +486,7 @@ static int imx214_enum_mbus_code(struct v4l2_subdev *sd,
}
static int imx214_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->code != IMX214_MBUS_CODE)
@@ -534,13 +534,13 @@ static const struct v4l2_subdev_core_ops imx214_core_ops = {
static struct v4l2_mbus_framefmt *
__imx214_get_pad_format(struct imx214 *imx214,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&imx214->sd, cfg, pad);
+ return v4l2_subdev_get_try_format(&imx214->sd, sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &imx214->fmt;
default:
@@ -549,13 +549,14 @@ __imx214_get_pad_format(struct imx214 *imx214,
}
static int imx214_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct imx214 *imx214 = to_imx214(sd);
mutex_lock(&imx214->mutex);
- format->format = *__imx214_get_pad_format(imx214, cfg, format->pad,
+ format->format = *__imx214_get_pad_format(imx214, sd_state,
+ format->pad,
format->which);
mutex_unlock(&imx214->mutex);
@@ -563,12 +564,13 @@ static int imx214_get_format(struct v4l2_subdev *sd,
}
static struct v4l2_rect *
-__imx214_get_pad_crop(struct imx214 *imx214, struct v4l2_subdev_pad_config *cfg,
+__imx214_get_pad_crop(struct imx214 *imx214,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&imx214->sd, cfg, pad);
+ return v4l2_subdev_get_try_crop(&imx214->sd, sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &imx214->crop;
default:
@@ -577,7 +579,7 @@ __imx214_get_pad_crop(struct imx214 *imx214, struct v4l2_subdev_pad_config *cfg,
}
static int imx214_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct imx214 *imx214 = to_imx214(sd);
@@ -587,7 +589,8 @@ static int imx214_set_format(struct v4l2_subdev *sd,
mutex_lock(&imx214->mutex);
- __crop = __imx214_get_pad_crop(imx214, cfg, format->pad, format->which);
+ __crop = __imx214_get_pad_crop(imx214, sd_state, format->pad,
+ format->which);
mode = v4l2_find_nearest_size(imx214_modes,
ARRAY_SIZE(imx214_modes), width, height,
@@ -597,7 +600,7 @@ static int imx214_set_format(struct v4l2_subdev *sd,
__crop->width = mode->width;
__crop->height = mode->height;
- __format = __imx214_get_pad_format(imx214, cfg, format->pad,
+ __format = __imx214_get_pad_format(imx214, sd_state, format->pad,
format->which);
__format->width = __crop->width;
__format->height = __crop->height;
@@ -617,7 +620,7 @@ static int imx214_set_format(struct v4l2_subdev *sd,
}
static int imx214_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct imx214 *imx214 = to_imx214(sd);
@@ -626,22 +629,22 @@ static int imx214_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
mutex_lock(&imx214->mutex);
- sel->r = *__imx214_get_pad_crop(imx214, cfg, sel->pad,
+ sel->r = *__imx214_get_pad_crop(imx214, sd_state, sel->pad,
sel->which);
mutex_unlock(&imx214->mutex);
return 0;
}
static int imx214_entity_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = { };
- fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
fmt.format.width = imx214_modes[0].width;
fmt.format.height = imx214_modes[0].height;
- imx214_set_format(subdev, cfg, &fmt);
+ imx214_set_format(subdev, sd_state, &fmt);
return 0;
}
@@ -776,11 +779,9 @@ static int imx214_s_stream(struct v4l2_subdev *subdev, int enable)
return 0;
if (enable) {
- ret = pm_runtime_get_sync(imx214->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(imx214->dev);
+ ret = pm_runtime_resume_and_get(imx214->dev);
+ if (ret < 0)
return ret;
- }
ret = imx214_start_streaming(imx214);
if (ret < 0)
@@ -810,7 +811,7 @@ static int imx214_g_frame_interval(struct v4l2_subdev *subdev,
}
static int imx214_enum_frame_interval(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
const struct imx214_mode *mode;
diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index 1054ffedaefd..e10af3f74b38 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -689,7 +689,7 @@ static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct imx219 *imx219 = to_imx219(sd);
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
struct v4l2_rect *try_crop;
mutex_lock(&imx219->mutex);
@@ -702,7 +702,7 @@ static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
try_fmt->field = V4L2_FIELD_NONE;
/* Initialize try_crop rectangle. */
- try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0);
+ try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
try_crop->top = IMX219_PIXEL_ARRAY_TOP;
try_crop->left = IMX219_PIXEL_ARRAY_LEFT;
try_crop->width = IMX219_PIXEL_ARRAY_WIDTH;
@@ -803,7 +803,7 @@ static const struct v4l2_ctrl_ops imx219_ctrl_ops = {
};
static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct imx219 *imx219 = to_imx219(sd);
@@ -819,7 +819,7 @@ static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
}
static int imx219_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct imx219 *imx219 = to_imx219(sd);
@@ -863,12 +863,13 @@ static void imx219_update_pad_format(struct imx219 *imx219,
}
static int __imx219_get_pad_format(struct imx219 *imx219,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(&imx219->sd, cfg, fmt->pad);
+ v4l2_subdev_get_try_format(&imx219->sd, sd_state,
+ fmt->pad);
/* update the code which could change due to vflip or hflip: */
try_fmt->code = imx219_get_format_code(imx219, try_fmt->code);
fmt->format = *try_fmt;
@@ -882,21 +883,21 @@ static int __imx219_get_pad_format(struct imx219 *imx219,
}
static int imx219_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imx219 *imx219 = to_imx219(sd);
int ret;
mutex_lock(&imx219->mutex);
- ret = __imx219_get_pad_format(imx219, cfg, fmt);
+ ret = __imx219_get_pad_format(imx219, sd_state, fmt);
mutex_unlock(&imx219->mutex);
return ret;
}
static int imx219_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imx219 *imx219 = to_imx219(sd);
@@ -922,7 +923,7 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
imx219_update_pad_format(imx219, mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*framefmt = fmt->format;
} else if (imx219->mode != mode ||
imx219->fmt.code != fmt->format.code) {
@@ -979,12 +980,13 @@ static int imx219_set_framefmt(struct imx219 *imx219)
}
static const struct v4l2_rect *
-__imx219_get_pad_crop(struct imx219 *imx219, struct v4l2_subdev_pad_config *cfg,
+__imx219_get_pad_crop(struct imx219 *imx219,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&imx219->sd, cfg, pad);
+ return v4l2_subdev_get_try_crop(&imx219->sd, sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &imx219->mode->crop;
}
@@ -993,7 +995,7 @@ __imx219_get_pad_crop(struct imx219 *imx219, struct v4l2_subdev_pad_config *cfg,
}
static int imx219_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
switch (sel->target) {
@@ -1001,7 +1003,7 @@ static int imx219_get_selection(struct v4l2_subdev *sd,
struct imx219 *imx219 = to_imx219(sd);
mutex_lock(&imx219->mutex);
- sel->r = *__imx219_get_pad_crop(imx219, cfg, sel->pad,
+ sel->r = *__imx219_get_pad_crop(imx219, sd_state, sel->pad,
sel->which);
mutex_unlock(&imx219->mutex);
@@ -1035,11 +1037,9 @@ static int imx219_start_streaming(struct imx219 *imx219)
const struct imx219_reg_list *reg_list;
int ret;
- ret = pm_runtime_get_sync(&client->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
return ret;
- }
/* Apply default values of current mode */
reg_list = &imx219->mode->reg_list;
diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index a017ec4e0f50..7ab9e5f9f267 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -710,7 +710,7 @@ static int imx258_write_regs(struct imx258 *imx258,
static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
/* Initialize try_fmt */
try_fmt->width = supported_modes[0].width;
@@ -820,7 +820,7 @@ static const struct v4l2_ctrl_ops imx258_ctrl_ops = {
};
static int imx258_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
/* Only one bayer order(GRBG) is supported */
@@ -833,7 +833,7 @@ static int imx258_enum_mbus_code(struct v4l2_subdev *sd,
}
static int imx258_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -860,11 +860,12 @@ static void imx258_update_pad_format(const struct imx258_mode *mode,
}
static int __imx258_get_pad_format(struct imx258 *imx258,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&imx258->sd, cfg,
+ fmt->format = *v4l2_subdev_get_try_format(&imx258->sd,
+ sd_state,
fmt->pad);
else
imx258_update_pad_format(imx258->cur_mode, fmt);
@@ -873,21 +874,21 @@ static int __imx258_get_pad_format(struct imx258 *imx258,
}
static int imx258_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imx258 *imx258 = to_imx258(sd);
int ret;
mutex_lock(&imx258->mutex);
- ret = __imx258_get_pad_format(imx258, cfg, fmt);
+ ret = __imx258_get_pad_format(imx258, sd_state, fmt);
mutex_unlock(&imx258->mutex);
return ret;
}
static int imx258_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imx258 *imx258 = to_imx258(sd);
@@ -909,7 +910,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
imx258_update_pad_format(mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
imx258->cur_mode = mode;
@@ -1039,11 +1040,9 @@ static int imx258_set_stream(struct v4l2_subdev *sd, int enable)
}
if (enable) {
- ret = pm_runtime_get_sync(&client->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
goto err_unlock;
- }
/*
* Apply default & customized values
diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c
index cdccaab3043a..0dce92872176 100644
--- a/drivers/media/i2c/imx274.c
+++ b/drivers/media/i2c/imx274.c
@@ -996,7 +996,7 @@ static int imx274_binning_goodness(struct stimx274 *imx274,
* Must be called with imx274->lock locked.
*
* @imx274: The device object
- * @cfg: The pad config we are editing for TRY requests
+ * @sd_state: The subdev state we are editing for TRY requests
* @which: V4L2_SUBDEV_FORMAT_ACTIVE or V4L2_SUBDEV_FORMAT_TRY from the caller
* @width: Input-output parameter: set to the desired width before
* the call, contains the chosen value after returning successfully
@@ -1005,7 +1005,7 @@ static int imx274_binning_goodness(struct stimx274 *imx274,
* available (when called from set_fmt)
*/
static int __imx274_change_compose(struct stimx274 *imx274,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
u32 which,
u32 *width,
u32 *height,
@@ -1019,8 +1019,8 @@ static int __imx274_change_compose(struct stimx274 *imx274,
int best_goodness = INT_MIN;
if (which == V4L2_SUBDEV_FORMAT_TRY) {
- cur_crop = &cfg->try_crop;
- tgt_fmt = &cfg->try_fmt;
+ cur_crop = &sd_state->pads->try_crop;
+ tgt_fmt = &sd_state->pads->try_fmt;
} else {
cur_crop = &imx274->crop;
tgt_fmt = &imx274->format;
@@ -1061,7 +1061,7 @@ static int __imx274_change_compose(struct stimx274 *imx274,
/**
* imx274_get_fmt - Get the pad format
* @sd: Pointer to V4L2 Sub device structure
- * @cfg: Pointer to sub device pad information structure
+ * @sd_state: Pointer to sub device state structure
* @fmt: Pointer to pad level media bus format
*
* This function is used to get the pad format information.
@@ -1069,7 +1069,7 @@ static int __imx274_change_compose(struct stimx274 *imx274,
* Return: 0 on success
*/
static int imx274_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct stimx274 *imx274 = to_imx274(sd);
@@ -1083,7 +1083,7 @@ static int imx274_get_fmt(struct v4l2_subdev *sd,
/**
* imx274_set_fmt - This is used to set the pad format
* @sd: Pointer to V4L2 Sub device structure
- * @cfg: Pointer to sub device pad information structure
+ * @sd_state: Pointer to sub device state information structure
* @format: Pointer to pad level media bus format
*
* This function is used to set the pad format.
@@ -1091,7 +1091,7 @@ static int imx274_get_fmt(struct v4l2_subdev *sd,
* Return: 0 on success
*/
static int imx274_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -1100,7 +1100,7 @@ static int imx274_set_fmt(struct v4l2_subdev *sd,
mutex_lock(&imx274->lock);
- err = __imx274_change_compose(imx274, cfg, format->which,
+ err = __imx274_change_compose(imx274, sd_state, format->which,
&fmt->width, &fmt->height, 0);
if (err)
@@ -1113,7 +1113,7 @@ static int imx274_set_fmt(struct v4l2_subdev *sd,
*/
fmt->field = V4L2_FIELD_NONE;
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- cfg->try_fmt = *fmt;
+ sd_state->pads->try_fmt = *fmt;
else
imx274->format = *fmt;
@@ -1124,7 +1124,7 @@ out:
}
static int imx274_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct stimx274 *imx274 = to_imx274(sd);
@@ -1144,8 +1144,8 @@ static int imx274_get_selection(struct v4l2_subdev *sd,
}
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- src_crop = &cfg->try_crop;
- src_fmt = &cfg->try_fmt;
+ src_crop = &sd_state->pads->try_crop;
+ src_fmt = &sd_state->pads->try_fmt;
} else {
src_crop = &imx274->crop;
src_fmt = &imx274->format;
@@ -1179,7 +1179,7 @@ static int imx274_get_selection(struct v4l2_subdev *sd,
}
static int imx274_set_selection_crop(struct stimx274 *imx274,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct v4l2_rect *tgt_crop;
@@ -1216,7 +1216,7 @@ static int imx274_set_selection_crop(struct stimx274 *imx274,
sel->r = new_crop;
if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
- tgt_crop = &cfg->try_crop;
+ tgt_crop = &sd_state->pads->try_crop;
else
tgt_crop = &imx274->crop;
@@ -1230,7 +1230,7 @@ static int imx274_set_selection_crop(struct stimx274 *imx274,
/* if crop size changed then reset the output image size */
if (size_changed)
- __imx274_change_compose(imx274, cfg, sel->which,
+ __imx274_change_compose(imx274, sd_state, sel->which,
&new_crop.width, &new_crop.height,
sel->flags);
@@ -1240,7 +1240,7 @@ static int imx274_set_selection_crop(struct stimx274 *imx274,
}
static int imx274_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct stimx274 *imx274 = to_imx274(sd);
@@ -1249,13 +1249,13 @@ static int imx274_set_selection(struct v4l2_subdev *sd,
return -EINVAL;
if (sel->target == V4L2_SEL_TGT_CROP)
- return imx274_set_selection_crop(imx274, cfg, sel);
+ return imx274_set_selection_crop(imx274, sd_state, sel);
if (sel->target == V4L2_SEL_TGT_COMPOSE) {
int err;
mutex_lock(&imx274->lock);
- err = __imx274_change_compose(imx274, cfg, sel->which,
+ err = __imx274_change_compose(imx274, sd_state, sel->which,
&sel->r.width, &sel->r.height,
sel->flags);
mutex_unlock(&imx274->lock);
@@ -1441,9 +1441,8 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on)
mutex_lock(&imx274->lock);
if (on) {
- ret = pm_runtime_get_sync(&imx274->client->dev);
+ ret = pm_runtime_resume_and_get(&imx274->client->dev);
if (ret < 0) {
- pm_runtime_put_noidle(&imx274->client->dev);
mutex_unlock(&imx274->lock);
return ret;
}
diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c
index 6319a42057d2..bf7a6c37ca5d 100644
--- a/drivers/media/i2c/imx290.c
+++ b/drivers/media/i2c/imx290.c
@@ -516,7 +516,7 @@ static const struct v4l2_ctrl_ops imx290_ctrl_ops = {
};
static int imx290_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(imx290_formats))
@@ -528,7 +528,7 @@ static int imx290_enum_mbus_code(struct v4l2_subdev *sd,
}
static int imx290_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
const struct imx290 *imx290 = to_imx290(sd);
@@ -550,7 +550,7 @@ static int imx290_enum_frame_size(struct v4l2_subdev *sd,
}
static int imx290_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imx290 *imx290 = to_imx290(sd);
@@ -559,7 +559,7 @@ static int imx290_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&imx290->lock);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- framefmt = v4l2_subdev_get_try_format(&imx290->sd, cfg,
+ framefmt = v4l2_subdev_get_try_format(&imx290->sd, sd_state,
fmt->pad);
else
framefmt = &imx290->current_format;
@@ -596,8 +596,8 @@ static u64 imx290_calc_pixel_rate(struct imx290 *imx290)
}
static int imx290_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
{
struct imx290 *imx290 = to_imx290(sd);
const struct imx290_mode *mode;
@@ -624,7 +624,7 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
fmt->format.field = V4L2_FIELD_NONE;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- format = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ format = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
} else {
format = &imx290->current_format;
imx290->current_mode = mode;
@@ -646,15 +646,15 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
}
static int imx290_entity_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = { 0 };
- fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
fmt.format.width = 1920;
fmt.format.height = 1080;
- imx290_set_fmt(subdev, cfg, &fmt);
+ imx290_set_fmt(subdev, sd_state, &fmt);
return 0;
}
@@ -764,11 +764,9 @@ static int imx290_set_stream(struct v4l2_subdev *sd, int enable)
int ret = 0;
if (enable) {
- ret = pm_runtime_get_sync(imx290->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(imx290->dev);
+ ret = pm_runtime_resume_and_get(imx290->dev);
+ if (ret < 0)
goto unlock_and_return;
- }
ret = imx290_start_streaming(imx290);
if (ret) {
diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c
index 38540323a156..dba0854ab5aa 100644
--- a/drivers/media/i2c/imx319.c
+++ b/drivers/media/i2c/imx319.c
@@ -1860,7 +1860,7 @@ static int imx319_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct imx319 *imx319 = to_imx319(sd);
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
mutex_lock(&imx319->mutex);
@@ -1947,7 +1947,7 @@ static const struct v4l2_ctrl_ops imx319_ctrl_ops = {
};
static int imx319_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct imx319 *imx319 = to_imx319(sd);
@@ -1963,7 +1963,7 @@ static int imx319_enum_mbus_code(struct v4l2_subdev *sd,
}
static int imx319_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct imx319 *imx319 = to_imx319(sd);
@@ -1997,14 +1997,14 @@ static void imx319_update_pad_format(struct imx319 *imx319,
}
static int imx319_do_get_pad_format(struct imx319 *imx319,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *framefmt;
struct v4l2_subdev *sd = &imx319->sd;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
imx319_update_pad_format(imx319, imx319->cur_mode, fmt);
@@ -2014,14 +2014,14 @@ static int imx319_do_get_pad_format(struct imx319 *imx319,
}
static int imx319_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imx319 *imx319 = to_imx319(sd);
int ret;
mutex_lock(&imx319->mutex);
- ret = imx319_do_get_pad_format(imx319, cfg, fmt);
+ ret = imx319_do_get_pad_format(imx319, sd_state, fmt);
mutex_unlock(&imx319->mutex);
return ret;
@@ -2029,7 +2029,7 @@ static int imx319_get_pad_format(struct v4l2_subdev *sd,
static int
imx319_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imx319 *imx319 = to_imx319(sd);
@@ -2055,7 +2055,7 @@ imx319_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
imx319_update_pad_format(imx319, mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
imx319->cur_mode = mode;
@@ -2141,11 +2141,9 @@ static int imx319_set_stream(struct v4l2_subdev *sd, int enable)
}
if (enable) {
- ret = pm_runtime_get_sync(&client->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
goto err_unlock;
- }
/*
* Apply default & customized values
diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c
index 047aa7658d21..062125501788 100644
--- a/drivers/media/i2c/imx334.c
+++ b/drivers/media/i2c/imx334.c
@@ -497,13 +497,13 @@ static const struct v4l2_ctrl_ops imx334_ctrl_ops = {
/**
* imx334_enum_mbus_code() - Enumerate V4L2 sub-device mbus codes
* @sd: pointer to imx334 V4L2 sub-device structure
- * @cfg: V4L2 sub-device pad configuration
+ * @sd_state: V4L2 sub-device state
* @code: V4L2 sub-device code enumeration need to be filled
*
* Return: 0 if successful, error code otherwise.
*/
static int imx334_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
@@ -517,13 +517,13 @@ static int imx334_enum_mbus_code(struct v4l2_subdev *sd,
/**
* imx334_enum_frame_size() - Enumerate V4L2 sub-device frame sizes
* @sd: pointer to imx334 V4L2 sub-device structure
- * @cfg: V4L2 sub-device pad configuration
+ * @sd_state: V4L2 sub-device state
* @fsize: V4L2 sub-device size enumeration need to be filled
*
* Return: 0 if successful, error code otherwise.
*/
static int imx334_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fsize)
{
if (fsize->index > 0)
@@ -564,13 +564,13 @@ static void imx334_fill_pad_format(struct imx334 *imx334,
/**
* imx334_get_pad_format() - Get subdevice pad format
* @sd: pointer to imx334 V4L2 sub-device structure
- * @cfg: V4L2 sub-device pad configuration
+ * @sd_state: V4L2 sub-device state
* @fmt: V4L2 sub-device format need to be set
*
* Return: 0 if successful, error code otherwise.
*/
static int imx334_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imx334 *imx334 = to_imx334(sd);
@@ -580,7 +580,7 @@ static int imx334_get_pad_format(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *framefmt;
- framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
imx334_fill_pad_format(imx334, imx334->cur_mode, fmt);
@@ -594,13 +594,13 @@ static int imx334_get_pad_format(struct v4l2_subdev *sd,
/**
* imx334_set_pad_format() - Set subdevice pad format
* @sd: pointer to imx334 V4L2 sub-device structure
- * @cfg: V4L2 sub-device pad configuration
+ * @sd_state: V4L2 sub-device state
* @fmt: V4L2 sub-device format need to be set
*
* Return: 0 if successful, error code otherwise.
*/
static int imx334_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imx334 *imx334 = to_imx334(sd);
@@ -615,7 +615,7 @@ static int imx334_set_pad_format(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *framefmt;
- framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
ret = imx334_update_controls(imx334, mode);
@@ -631,20 +631,20 @@ static int imx334_set_pad_format(struct v4l2_subdev *sd,
/**
* imx334_init_pad_cfg() - Initialize sub-device pad configuration
* @sd: pointer to imx334 V4L2 sub-device structure
- * @cfg: V4L2 sub-device pad configuration
+ * @sd_state: V4L2 sub-device state
*
* Return: 0 if successful, error code otherwise.
*/
static int imx334_init_pad_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct imx334 *imx334 = to_imx334(sd);
struct v4l2_subdev_format fmt = { 0 };
- fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
imx334_fill_pad_format(imx334, &supported_mode, &fmt);
- return imx334_set_pad_format(sd, cfg, &fmt);
+ return imx334_set_pad_format(sd, sd_state, &fmt);
}
/**
@@ -717,9 +717,9 @@ static int imx334_set_stream(struct v4l2_subdev *sd, int enable)
}
if (enable) {
- ret = pm_runtime_get_sync(imx334->dev);
- if (ret)
- goto error_power_off;
+ ret = pm_runtime_resume_and_get(imx334->dev);
+ if (ret < 0)
+ goto error_unlock;
ret = imx334_start_streaming(imx334);
if (ret)
@@ -737,6 +737,7 @@ static int imx334_set_stream(struct v4l2_subdev *sd, int enable)
error_power_off:
pm_runtime_put(imx334->dev);
+error_unlock:
mutex_unlock(&imx334->mutex);
return ret;
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index ccedcd4c520a..cb51c81786bd 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -1161,7 +1161,7 @@ static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct imx355 *imx355 = to_imx355(sd);
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
mutex_lock(&imx355->mutex);
@@ -1248,7 +1248,7 @@ static const struct v4l2_ctrl_ops imx355_ctrl_ops = {
};
static int imx355_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct imx355 *imx355 = to_imx355(sd);
@@ -1264,7 +1264,7 @@ static int imx355_enum_mbus_code(struct v4l2_subdev *sd,
}
static int imx355_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct imx355 *imx355 = to_imx355(sd);
@@ -1298,14 +1298,14 @@ static void imx355_update_pad_format(struct imx355 *imx355,
}
static int imx355_do_get_pad_format(struct imx355 *imx355,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *framefmt;
struct v4l2_subdev *sd = &imx355->sd;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
imx355_update_pad_format(imx355, imx355->cur_mode, fmt);
@@ -1315,14 +1315,14 @@ static int imx355_do_get_pad_format(struct imx355 *imx355,
}
static int imx355_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imx355 *imx355 = to_imx355(sd);
int ret;
mutex_lock(&imx355->mutex);
- ret = imx355_do_get_pad_format(imx355, cfg, fmt);
+ ret = imx355_do_get_pad_format(imx355, sd_state, fmt);
mutex_unlock(&imx355->mutex);
return ret;
@@ -1330,7 +1330,7 @@ static int imx355_get_pad_format(struct v4l2_subdev *sd,
static int
imx355_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imx355 *imx355 = to_imx355(sd);
@@ -1356,7 +1356,7 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
imx355_update_pad_format(imx355, mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
imx355->cur_mode = mode;
@@ -1442,11 +1442,9 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
}
if (enable) {
- ret = pm_runtime_get_sync(&client->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
goto err_unlock;
- }
/*
* Apply default & customized values
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index e8119ad0bc71..92376592455e 100644
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -678,8 +678,8 @@ static int zilog_tx(struct rc_dev *rcdev, unsigned int *txbuf,
goto out_unlock;
}
- i = i2c_master_recv(ir->tx_c, buf, 1);
- if (i != 1) {
+ ret = i2c_master_recv(ir->tx_c, buf, 1);
+ if (ret != 1) {
dev_err(&ir->rc->dev, "i2c_master_recv failed with %d\n", ret);
ret = -EIO;
goto out_unlock;
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c
index 21666d705e37..e29be0242f07 100644
--- a/drivers/media/i2c/m5mols/m5mols_core.c
+++ b/drivers/media/i2c/m5mols/m5mols_core.c
@@ -539,17 +539,19 @@ static int __find_resolution(struct v4l2_subdev *sd,
}
static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which,
enum m5mols_restype type)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return cfg ? v4l2_subdev_get_try_format(&info->sd, cfg, 0) : NULL;
+ return sd_state ? v4l2_subdev_get_try_format(&info->sd,
+ sd_state, 0) : NULL;
return &info->ffmt[type];
}
-static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int m5mols_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct m5mols_info *info = to_m5mols(sd);
@@ -558,7 +560,7 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
mutex_lock(&info->lock);
- format = __find_format(info, cfg, fmt->which, info->res_type);
+ format = __find_format(info, sd_state, fmt->which, info->res_type);
if (format)
fmt->format = *format;
else
@@ -568,7 +570,8 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
return ret;
}
-static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int m5mols_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct m5mols_info *info = to_m5mols(sd);
@@ -582,7 +585,7 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
if (ret < 0)
return ret;
- sfmt = __find_format(info, cfg, fmt->which, type);
+ sfmt = __find_format(info, sd_state, fmt->which, type);
if (!sfmt)
return 0;
@@ -648,7 +651,7 @@ static int m5mols_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
static int m5mols_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (!code || code->index >= SIZE_DEFAULT_FFMT)
@@ -909,7 +912,9 @@ static const struct v4l2_subdev_core_ops m5mols_core_ops = {
*/
static int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd,
+ fh->state,
+ 0);
*format = m5mols_default_ffmt[0];
return 0;
diff --git a/drivers/media/i2c/max9271.c b/drivers/media/i2c/max9271.c
index c495582dcff6..ff86c8c4ea61 100644
--- a/drivers/media/i2c/max9271.c
+++ b/drivers/media/i2c/max9271.c
@@ -80,6 +80,18 @@ static int max9271_pclk_detect(struct max9271_device *dev)
return -EIO;
}
+void max9271_wake_up(struct max9271_device *dev)
+{
+ /*
+ * Use the chip default address as this function has to be called
+ * before any other one.
+ */
+ dev->client->addr = MAX9271_DEFAULT_ADDR;
+ i2c_smbus_read_byte(dev->client);
+ usleep_range(5000, 8000);
+}
+EXPORT_SYMBOL_GPL(max9271_wake_up);
+
int max9271_set_serial_link(struct max9271_device *dev, bool enable)
{
int ret;
@@ -106,7 +118,10 @@ int max9271_set_serial_link(struct max9271_device *dev, bool enable)
* Short delays here appear to show bit-errors in the writes following.
* Therefore a conservative delay seems best here.
*/
- max9271_write(dev, 0x04, val);
+ ret = max9271_write(dev, 0x04, val);
+ if (ret < 0)
+ return ret;
+
usleep_range(5000, 8000);
return 0;
@@ -118,7 +133,7 @@ int max9271_configure_i2c(struct max9271_device *dev, u8 i2c_config)
int ret;
ret = max9271_write(dev, 0x0d, i2c_config);
- if (ret)
+ if (ret < 0)
return ret;
/* The delay required after an I2C bus configuration change is not
@@ -143,7 +158,10 @@ int max9271_set_high_threshold(struct max9271_device *dev, bool enable)
* Enable or disable reverse channel high threshold to increase
* immunity to power supply noise.
*/
- max9271_write(dev, 0x08, enable ? ret | BIT(0) : ret & ~BIT(0));
+ ret = max9271_write(dev, 0x08, enable ? ret | BIT(0) : ret & ~BIT(0));
+ if (ret < 0)
+ return ret;
+
usleep_range(2000, 2500);
return 0;
@@ -152,6 +170,8 @@ EXPORT_SYMBOL_GPL(max9271_set_high_threshold);
int max9271_configure_gmsl_link(struct max9271_device *dev)
{
+ int ret;
+
/*
* Configure the GMSL link:
*
@@ -162,16 +182,24 @@ int max9271_configure_gmsl_link(struct max9271_device *dev)
*
* TODO: Make the GMSL link configuration parametric.
*/
- max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN |
- MAX9271_EDC_1BIT_PARITY);
+ ret = max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN |
+ MAX9271_EDC_1BIT_PARITY);
+ if (ret < 0)
+ return ret;
+
usleep_range(5000, 8000);
/*
* Adjust spread spectrum to +4% and auto-detect pixel clock
* and serial link rate.
*/
- max9271_write(dev, 0x02, MAX9271_SPREAD_SPECT_4 | MAX9271_R02_RES |
- MAX9271_PCLK_AUTODETECT | MAX9271_SERIAL_AUTODETECT);
+ ret = max9271_write(dev, 0x02,
+ MAX9271_SPREAD_SPECT_4 | MAX9271_R02_RES |
+ MAX9271_PCLK_AUTODETECT |
+ MAX9271_SERIAL_AUTODETECT);
+ if (ret < 0)
+ return ret;
+
usleep_range(5000, 8000);
return 0;
diff --git a/drivers/media/i2c/max9271.h b/drivers/media/i2c/max9271.h
index d78fb21441e9..dc5e4e70ba6f 100644
--- a/drivers/media/i2c/max9271.h
+++ b/drivers/media/i2c/max9271.h
@@ -86,6 +86,15 @@ struct max9271_device {
};
/**
+ * max9271_wake_up() - Wake up the serializer by issuing an i2c transaction
+ * @dev: The max9271 device
+ *
+ * This function shall be called before any other interaction with the
+ * serializer.
+ */
+void max9271_wake_up(struct max9271_device *dev);
+
+/**
* max9271_set_serial_link() - Enable/disable serial link
* @dev: The max9271 device
* @enable: Serial link enable/disable flag
diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index 6fd4d59fcc72..1aa2c58fd38c 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -113,6 +113,7 @@
#define MAX9286_REV_TRF(n) ((n) << 4)
#define MAX9286_REV_AMP(n) ((((n) - 30) / 10) << 1) /* in mV */
#define MAX9286_REV_AMP_X BIT(0)
+#define MAX9286_REV_AMP_HIGH 170
/* Register 0x3f */
#define MAX9286_EN_REV_CFG BIT(6)
#define MAX9286_REV_FLEN(n) ((n) - 20)
@@ -163,7 +164,9 @@ struct max9286_priv {
unsigned int mux_channel;
bool mux_open;
- u32 reverse_channel_mv;
+ /* The initial reverse control channel amplitude. */
+ u32 init_rev_chan_mv;
+ u32 rev_chan_mv;
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *pixelrate;
@@ -287,9 +290,8 @@ static int max9286_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
priv->mux_channel = chan;
- max9286_i2c_mux_configure(priv,
- MAX9286_FWDCCEN(chan) |
- MAX9286_REVCCEN(chan));
+ max9286_i2c_mux_configure(priv, MAX9286_FWDCCEN(chan) |
+ MAX9286_REVCCEN(chan));
return 0;
}
@@ -341,8 +343,15 @@ static void max9286_configure_i2c(struct max9286_priv *priv, bool localack)
static void max9286_reverse_channel_setup(struct max9286_priv *priv,
unsigned int chan_amplitude)
{
+ u8 chan_config;
+
+ if (priv->rev_chan_mv == chan_amplitude)
+ return;
+
+ priv->rev_chan_mv = chan_amplitude;
+
/* Reverse channel transmission time: default to 1. */
- u8 chan_config = MAX9286_REV_TRF(1);
+ chan_config = MAX9286_REV_TRF(1);
/*
* Reverse channel setup.
@@ -547,9 +556,9 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
subdev->name, src_pad, index);
/*
- * We can only register v4l2_async_notifiers, which do not provide a
- * means to register a complete callback. bound_sources allows us to
- * identify when all remote serializers have completed their probe.
+ * As we register a subdev notifiers we won't get a .complete() callback
+ * here, so we have to use bound_sources to identify when all remote
+ * serializers have probed.
*/
if (priv->bound_sources != priv->source_mask)
return 0;
@@ -559,19 +568,13 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
* channels:
*
* - Increase the reverse channel amplitude to compensate for the
- * remote ends high threshold, if not done already
+ * remote ends high threshold
* - Verify all configuration links are properly detected
* - Disable auto-ack as communication on the control channel are now
* stable.
*/
- if (priv->reverse_channel_mv < 170)
- max9286_reverse_channel_setup(priv, 170);
+ max9286_reverse_channel_setup(priv, MAX9286_REV_AMP_HIGH);
max9286_check_config_link(priv, priv->source_mask);
-
- /*
- * Re-configure I2C with local acknowledge disabled after cameras have
- * probed.
- */
max9286_configure_i2c(priv, false);
return max9286_set_pixelrate(priv);
@@ -712,7 +715,7 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
}
static int max9286_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index > 0)
@@ -725,12 +728,12 @@ static int max9286_enum_mbus_code(struct v4l2_subdev *sd,
static struct v4l2_mbus_framefmt *
max9286_get_pad_format(struct max9286_priv *priv,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, u32 which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&priv->sd, cfg, pad);
+ return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &priv->fmt[pad];
default:
@@ -739,7 +742,7 @@ max9286_get_pad_format(struct max9286_priv *priv,
}
static int max9286_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct max9286_priv *priv = sd_to_max9286(sd);
@@ -760,7 +763,8 @@ static int max9286_set_fmt(struct v4l2_subdev *sd,
break;
}
- cfg_fmt = max9286_get_pad_format(priv, cfg, format->pad, format->which);
+ cfg_fmt = max9286_get_pad_format(priv, sd_state, format->pad,
+ format->which);
if (!cfg_fmt)
return -EINVAL;
@@ -772,7 +776,7 @@ static int max9286_set_fmt(struct v4l2_subdev *sd,
}
static int max9286_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct max9286_priv *priv = sd_to_max9286(sd);
@@ -788,7 +792,7 @@ static int max9286_get_fmt(struct v4l2_subdev *sd,
if (pad == MAX9286_SRC_PAD)
pad = __ffs(priv->bound_sources);
- cfg_fmt = max9286_get_pad_format(priv, cfg, pad, format->which);
+ cfg_fmt = max9286_get_pad_format(priv, sd_state, pad, format->which);
if (!cfg_fmt)
return -EINVAL;
@@ -832,7 +836,7 @@ static int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
unsigned int i;
for (i = 0; i < MAX9286_N_SINKS; i++) {
- format = v4l2_subdev_get_try_format(subdev, fh->pad, i);
+ format = v4l2_subdev_get_try_format(subdev, fh->state, i);
max9286_init_format(format);
}
@@ -972,7 +976,7 @@ static int max9286_setup(struct max9286_priv *priv)
* only. This should be disabled after the mux is initialised.
*/
max9286_configure_i2c(priv, true);
- max9286_reverse_channel_setup(priv, priv->reverse_channel_mv);
+ max9286_reverse_channel_setup(priv, priv->init_rev_chan_mv);
/*
* Enable GMSL links, mask unused ones and autodetect link
@@ -1237,9 +1241,9 @@ static int max9286_parse_dt(struct max9286_priv *priv)
if (of_property_read_u32(dev->of_node,
"maxim,reverse-channel-microvolt",
&reverse_channel_microvolt))
- priv->reverse_channel_mv = 170;
+ priv->init_rev_chan_mv = 170;
else
- priv->reverse_channel_mv = reverse_channel_microvolt / 1000U;
+ priv->init_rev_chan_mv = reverse_channel_microvolt / 1000U;
priv->route_mask = priv->source_mask;
diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c
index ff212335326a..4a1410ebb4c8 100644
--- a/drivers/media/i2c/ml86v7667.c
+++ b/drivers/media/i2c/ml86v7667.c
@@ -188,7 +188,7 @@ static int ml86v7667_g_input_status(struct v4l2_subdev *sd, u32 *status)
}
static int ml86v7667_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index > 0)
@@ -200,7 +200,7 @@ static int ml86v7667_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ml86v7667_fill_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ml86v7667_priv *priv = to_ml86v7667(sd);
diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c
index 3b0ba8ed5233..c9f0bd997ea7 100644
--- a/drivers/media/i2c/mt9m001.c
+++ b/drivers/media/i2c/mt9m001.c
@@ -217,9 +217,9 @@ static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable)
goto done;
if (enable) {
- ret = pm_runtime_get_sync(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
if (ret < 0)
- goto put_unlock;
+ goto unlock;
ret = mt9m001_apply_selection(sd);
if (ret)
@@ -247,13 +247,14 @@ done:
put_unlock:
pm_runtime_put(&client->dev);
+unlock:
mutex_unlock(&mt9m001->mutex);
return ret;
}
static int mt9m001_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -294,7 +295,7 @@ static int mt9m001_set_selection(struct v4l2_subdev *sd,
}
static int mt9m001_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -319,7 +320,7 @@ static int mt9m001_get_selection(struct v4l2_subdev *sd,
}
static int mt9m001_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -330,7 +331,7 @@ static int mt9m001_get_fmt(struct v4l2_subdev *sd,
return -EINVAL;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
format->format = *mf;
return 0;
}
@@ -376,7 +377,7 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd,
}
static int mt9m001_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -410,7 +411,7 @@ static int mt9m001_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return mt9m001_s_fmt(sd, fmt, mf);
- cfg->try_fmt = *mf;
+ sd_state->pads->try_fmt = *mf;
return 0;
}
@@ -656,12 +657,12 @@ static const struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
};
static int mt9m001_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, cfg, 0);
+ v4l2_subdev_get_try_format(sd, sd_state, 0);
try_fmt->width = MT9M001_MAX_WIDTH;
try_fmt->height = MT9M001_MAX_HEIGHT;
@@ -676,7 +677,7 @@ static int mt9m001_init_cfg(struct v4l2_subdev *sd,
}
static int mt9m001_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -834,6 +835,10 @@ static int mt9m001_remove(struct i2c_client *client)
{
struct mt9m001 *mt9m001 = to_mt9m001(client);
+ /*
+ * As it increments RPM usage_count even on errors, we don't need to
+ * check the returned code here.
+ */
pm_runtime_get_sync(&client->dev);
v4l2_async_unregister_subdev(&mt9m001->subdev);
diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c
index 5a4c0f9d1eee..ba0c0ea91c95 100644
--- a/drivers/media/i2c/mt9m032.c
+++ b/drivers/media/i2c/mt9m032.c
@@ -304,7 +304,7 @@ static int mt9m032_setup_pll(struct mt9m032 *sensor)
*/
static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index != 0)
@@ -315,7 +315,7 @@ static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index != 0 || fse->code != MEDIA_BUS_FMT_Y8_1X8)
@@ -332,18 +332,19 @@ static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev,
/**
* __mt9m032_get_pad_crop() - get crop rect
* @sensor: pointer to the sensor struct
- * @cfg: v4l2_subdev_pad_config for getting the try crop rect from
+ * @sd_state: v4l2_subdev_state for getting the try crop rect from
* @which: select try or active crop rect
*
* Returns a pointer the current active or fh relative try crop rect
*/
static struct v4l2_rect *
-__mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_pad_config *cfg,
+__mt9m032_get_pad_crop(struct mt9m032 *sensor,
+ struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&sensor->subdev, cfg, 0);
+ return v4l2_subdev_get_try_crop(&sensor->subdev, sd_state, 0);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &sensor->crop;
default:
@@ -354,18 +355,20 @@ __mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_pad_config *cf
/**
* __mt9m032_get_pad_format() - get format
* @sensor: pointer to the sensor struct
- * @cfg: v4l2_subdev_pad_config for getting the try format from
+ * @sd_state: v4l2_subdev_state for getting the try format from
* @which: select try or active format
*
* Returns a pointer the current active or fh relative try format
*/
static struct v4l2_mbus_framefmt *
-__mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_pad_config *cfg,
+__mt9m032_get_pad_format(struct mt9m032 *sensor,
+ struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&sensor->subdev, cfg, 0);
+ return v4l2_subdev_get_try_format(&sensor->subdev, sd_state,
+ 0);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &sensor->format;
default:
@@ -374,20 +377,20 @@ __mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_pad_config *
}
static int mt9m032_get_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct mt9m032 *sensor = to_mt9m032(subdev);
mutex_lock(&sensor->lock);
- fmt->format = *__mt9m032_get_pad_format(sensor, cfg, fmt->which);
+ fmt->format = *__mt9m032_get_pad_format(sensor, sd_state, fmt->which);
mutex_unlock(&sensor->lock);
return 0;
}
static int mt9m032_set_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct mt9m032 *sensor = to_mt9m032(subdev);
@@ -401,7 +404,7 @@ static int mt9m032_set_pad_format(struct v4l2_subdev *subdev,
}
/* Scaling is not supported, the format is thus fixed. */
- fmt->format = *__mt9m032_get_pad_format(sensor, cfg, fmt->which);
+ fmt->format = *__mt9m032_get_pad_format(sensor, sd_state, fmt->which);
ret = 0;
done:
@@ -410,7 +413,7 @@ done:
}
static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct mt9m032 *sensor = to_mt9m032(subdev);
@@ -419,14 +422,14 @@ static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev,
return -EINVAL;
mutex_lock(&sensor->lock);
- sel->r = *__mt9m032_get_pad_crop(sensor, cfg, sel->which);
+ sel->r = *__mt9m032_get_pad_crop(sensor, sd_state, sel->which);
mutex_unlock(&sensor->lock);
return 0;
}
static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct mt9m032 *sensor = to_mt9m032(subdev);
@@ -462,13 +465,14 @@ static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev,
rect.height = min_t(unsigned int, rect.height,
MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
- __crop = __mt9m032_get_pad_crop(sensor, cfg, sel->which);
+ __crop = __mt9m032_get_pad_crop(sensor, sd_state, sel->which);
if (rect.width != __crop->width || rect.height != __crop->height) {
/* Reset the output image size if the crop rectangle size has
* been modified.
*/
- format = __mt9m032_get_pad_format(sensor, cfg, sel->which);
+ format = __mt9m032_get_pad_format(sensor, sd_state,
+ sel->which);
format->width = rect.width;
format->height = rect.height;
}
diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
index 0e11734f75aa..91a44359bcd3 100644
--- a/drivers/media/i2c/mt9m111.c
+++ b/drivers/media/i2c/mt9m111.c
@@ -449,7 +449,7 @@ static int mt9m111_reset(struct mt9m111 *mt9m111)
}
static int mt9m111_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -493,7 +493,7 @@ static int mt9m111_set_selection(struct v4l2_subdev *sd,
}
static int mt9m111_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -518,7 +518,7 @@ static int mt9m111_get_selection(struct v4l2_subdev *sd,
}
static int mt9m111_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -529,7 +529,7 @@ static int mt9m111_get_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
- mf = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
format->format = *mf;
return 0;
#else
@@ -624,7 +624,7 @@ static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
}
static int mt9m111_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -678,7 +678,7 @@ static int mt9m111_set_fmt(struct v4l2_subdev *sd,
mf->xfer_func = V4L2_XFER_FUNC_DEFAULT;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *mf;
+ sd_state->pads->try_fmt = *mf;
return 0;
}
@@ -1100,7 +1100,7 @@ static int mt9m111_s_frame_interval(struct v4l2_subdev *sd,
}
static int mt9m111_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index >= ARRAY_SIZE(mt9m111_colour_fmts))
@@ -1119,11 +1119,11 @@ static int mt9m111_s_stream(struct v4l2_subdev *sd, int enable)
}
static int mt9m111_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
struct v4l2_mbus_framefmt *format =
- v4l2_subdev_get_try_format(sd, cfg, 0);
+ v4l2_subdev_get_try_format(sd, sd_state, 0);
format->width = MT9M111_MAX_WIDTH;
format->height = MT9M111_MAX_HEIGHT;
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index a633b934d93e..6eb88ef99783 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -470,7 +470,7 @@ static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable)
}
static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -483,7 +483,7 @@ static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -501,12 +501,14 @@ static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev,
}
static struct v4l2_mbus_framefmt *
-__mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_pad_config *cfg,
+__mt9p031_get_pad_format(struct mt9p031 *mt9p031,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, u32 which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&mt9p031->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&mt9p031->subdev, sd_state,
+ pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9p031->format;
default:
@@ -515,12 +517,14 @@ __mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_pad_config
}
static struct v4l2_rect *
-__mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_pad_config *cfg,
- unsigned int pad, u32 which)
+__mt9p031_get_pad_crop(struct mt9p031 *mt9p031,
+ struct v4l2_subdev_state *sd_state,
+ unsigned int pad, u32 which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&mt9p031->subdev, cfg, pad);
+ return v4l2_subdev_get_try_crop(&mt9p031->subdev, sd_state,
+ pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9p031->crop;
default:
@@ -529,18 +533,18 @@ __mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_pad_config *c
}
static int mt9p031_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
- fmt->format = *__mt9p031_get_pad_format(mt9p031, cfg, fmt->pad,
+ fmt->format = *__mt9p031_get_pad_format(mt9p031, sd_state, fmt->pad,
fmt->which);
return 0;
}
static int mt9p031_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -551,7 +555,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev,
unsigned int hratio;
unsigned int vratio;
- __crop = __mt9p031_get_pad_crop(mt9p031, cfg, format->pad,
+ __crop = __mt9p031_get_pad_crop(mt9p031, sd_state, format->pad,
format->which);
/* Clamp the width and height to avoid dividing by zero. */
@@ -567,7 +571,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev,
hratio = DIV_ROUND_CLOSEST(__crop->width, width);
vratio = DIV_ROUND_CLOSEST(__crop->height, height);
- __format = __mt9p031_get_pad_format(mt9p031, cfg, format->pad,
+ __format = __mt9p031_get_pad_format(mt9p031, sd_state, format->pad,
format->which);
__format->width = __crop->width / hratio;
__format->height = __crop->height / vratio;
@@ -578,7 +582,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev,
}
static int mt9p031_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -586,12 +590,13 @@ static int mt9p031_get_selection(struct v4l2_subdev *subdev,
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- sel->r = *__mt9p031_get_pad_crop(mt9p031, cfg, sel->pad, sel->which);
+ sel->r = *__mt9p031_get_pad_crop(mt9p031, sd_state, sel->pad,
+ sel->which);
return 0;
}
static int mt9p031_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
@@ -621,13 +626,15 @@ static int mt9p031_set_selection(struct v4l2_subdev *subdev,
rect.height = min_t(unsigned int, rect.height,
MT9P031_PIXEL_ARRAY_HEIGHT - rect.top);
- __crop = __mt9p031_get_pad_crop(mt9p031, cfg, sel->pad, sel->which);
+ __crop = __mt9p031_get_pad_crop(mt9p031, sd_state, sel->pad,
+ sel->which);
if (rect.width != __crop->width || rect.height != __crop->height) {
/* Reset the output image size if the crop rectangle size has
* been modified.
*/
- __format = __mt9p031_get_pad_format(mt9p031, cfg, sel->pad,
+ __format = __mt9p031_get_pad_format(mt9p031, sd_state,
+ sel->pad,
sel->which);
__format->width = rect.width;
__format->height = rect.height;
@@ -942,13 +949,13 @@ static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0);
+ crop = v4l2_subdev_get_try_crop(subdev, fh->state, 0);
crop->left = MT9P031_COLUMN_START_DEF;
crop->top = MT9P031_ROW_START_DEF;
crop->width = MT9P031_WINDOW_WIDTH_DEF;
crop->height = MT9P031_WINDOW_HEIGHT_DEF;
- format = v4l2_subdev_get_try_format(subdev, fh->pad, 0);
+ format = v4l2_subdev_get_try_format(subdev, fh->state, 0);
if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
format->code = MEDIA_BUS_FMT_Y12_1X12;
diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c
index 2e96ff5234b4..b651ee4a26e8 100644
--- a/drivers/media/i2c/mt9t001.c
+++ b/drivers/media/i2c/mt9t001.c
@@ -252,12 +252,14 @@ e_power:
*/
static struct v4l2_mbus_framefmt *
-__mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_pad_config *cfg,
+__mt9t001_get_pad_format(struct mt9t001 *mt9t001,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&mt9t001->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&mt9t001->subdev, sd_state,
+ pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9t001->format;
default:
@@ -266,12 +268,14 @@ __mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_pad_config
}
static struct v4l2_rect *
-__mt9t001_get_pad_crop(struct mt9t001 *mt9t001, struct v4l2_subdev_pad_config *cfg,
+__mt9t001_get_pad_crop(struct mt9t001 *mt9t001,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&mt9t001->subdev, cfg, pad);
+ return v4l2_subdev_get_try_crop(&mt9t001->subdev, sd_state,
+ pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9t001->crop;
default:
@@ -335,7 +339,7 @@ static int mt9t001_s_stream(struct v4l2_subdev *subdev, int enable)
}
static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
@@ -346,7 +350,7 @@ static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= 8 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
@@ -361,18 +365,19 @@ static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev,
}
static int mt9t001_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct mt9t001 *mt9t001 = to_mt9t001(subdev);
- format->format = *__mt9t001_get_pad_format(mt9t001, cfg, format->pad,
+ format->format = *__mt9t001_get_pad_format(mt9t001, sd_state,
+ format->pad,
format->which);
return 0;
}
static int mt9t001_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct mt9t001 *mt9t001 = to_mt9t001(subdev);
@@ -383,7 +388,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev,
unsigned int hratio;
unsigned int vratio;
- __crop = __mt9t001_get_pad_crop(mt9t001, cfg, format->pad,
+ __crop = __mt9t001_get_pad_crop(mt9t001, sd_state, format->pad,
format->which);
/* Clamp the width and height to avoid dividing by zero. */
@@ -399,7 +404,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev,
hratio = DIV_ROUND_CLOSEST(__crop->width, width);
vratio = DIV_ROUND_CLOSEST(__crop->height, height);
- __format = __mt9t001_get_pad_format(mt9t001, cfg, format->pad,
+ __format = __mt9t001_get_pad_format(mt9t001, sd_state, format->pad,
format->which);
__format->width = __crop->width / hratio;
__format->height = __crop->height / vratio;
@@ -410,7 +415,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev,
}
static int mt9t001_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct mt9t001 *mt9t001 = to_mt9t001(subdev);
@@ -418,12 +423,13 @@ static int mt9t001_get_selection(struct v4l2_subdev *subdev,
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- sel->r = *__mt9t001_get_pad_crop(mt9t001, cfg, sel->pad, sel->which);
+ sel->r = *__mt9t001_get_pad_crop(mt9t001, sd_state, sel->pad,
+ sel->which);
return 0;
}
static int mt9t001_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct mt9t001 *mt9t001 = to_mt9t001(subdev);
@@ -455,13 +461,15 @@ static int mt9t001_set_selection(struct v4l2_subdev *subdev,
rect.height = min_t(unsigned int, rect.height,
MT9T001_PIXEL_ARRAY_HEIGHT - rect.top);
- __crop = __mt9t001_get_pad_crop(mt9t001, cfg, sel->pad, sel->which);
+ __crop = __mt9t001_get_pad_crop(mt9t001, sd_state, sel->pad,
+ sel->which);
if (rect.width != __crop->width || rect.height != __crop->height) {
/* Reset the output image size if the crop rectangle size has
* been modified.
*/
- __format = __mt9t001_get_pad_format(mt9t001, cfg, sel->pad,
+ __format = __mt9t001_get_pad_format(mt9t001, sd_state,
+ sel->pad,
sel->which);
__format->width = rect.width;
__format->height = rect.height;
@@ -798,13 +806,13 @@ static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0);
+ crop = v4l2_subdev_get_try_crop(subdev, fh->state, 0);
crop->left = MT9T001_COLUMN_START_DEF;
crop->top = MT9T001_ROW_START_DEF;
crop->width = MT9T001_WINDOW_WIDTH_DEF + 1;
crop->height = MT9T001_WINDOW_HEIGHT_DEF + 1;
- format = v4l2_subdev_get_try_format(subdev, fh->pad, 0);
+ format = v4l2_subdev_get_try_format(subdev, fh->state, 0);
format->code = MEDIA_BUS_FMT_SGRBG10_1X10;
format->width = MT9T001_WINDOW_WIDTH_DEF + 1;
format->height = MT9T001_WINDOW_HEIGHT_DEF + 1;
diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c
index ae3c336eadf5..8d2e3caa9b28 100644
--- a/drivers/media/i2c/mt9t112.c
+++ b/drivers/media/i2c/mt9t112.c
@@ -872,8 +872,8 @@ static int mt9t112_set_params(struct mt9t112_priv *priv,
}
static int mt9t112_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_selection *sel)
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t112_priv *priv = to_mt9t112(client);
@@ -897,7 +897,7 @@ static int mt9t112_get_selection(struct v4l2_subdev *sd,
}
static int mt9t112_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -912,7 +912,7 @@ static int mt9t112_set_selection(struct v4l2_subdev *sd,
}
static int mt9t112_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -953,7 +953,7 @@ static int mt9t112_s_fmt(struct v4l2_subdev *sd,
}
static int mt9t112_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -982,13 +982,13 @@ static int mt9t112_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return mt9t112_s_fmt(sd, mf);
- cfg->try_fmt = *mf;
+ sd_state->pads->try_fmt = *mf;
return 0;
}
static int mt9t112_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
index 46ef74a2ca36..7699e64e1127 100644
--- a/drivers/media/i2c/mt9v011.c
+++ b/drivers/media/i2c/mt9v011.c
@@ -327,7 +327,7 @@ static int mt9v011_reset(struct v4l2_subdev *sd, u32 val)
}
static int mt9v011_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index > 0)
@@ -338,7 +338,7 @@ static int mt9v011_enum_mbus_code(struct v4l2_subdev *sd,
}
static int mt9v011_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -358,7 +358,7 @@ static int mt9v011_set_fmt(struct v4l2_subdev *sd,
set_res(sd);
} else {
- cfg->try_fmt = *fmt;
+ sd_state->pads->try_fmt = *fmt;
}
return 0;
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index 5bd3ae82992f..4cfdd3dfbd42 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -349,12 +349,14 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
*/
static struct v4l2_mbus_framefmt *
-__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *cfg,
+__mt9v032_get_pad_format(struct mt9v032 *mt9v032,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&mt9v032->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&mt9v032->subdev, sd_state,
+ pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9v032->format;
default:
@@ -363,12 +365,14 @@ __mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config
}
static struct v4l2_rect *
-__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *cfg,
+__mt9v032_get_pad_crop(struct mt9v032 *mt9v032,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&mt9v032->subdev, cfg, pad);
+ return v4l2_subdev_get_try_crop(&mt9v032->subdev, sd_state,
+ pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9v032->crop;
default:
@@ -425,7 +429,7 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
}
static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -438,7 +442,7 @@ static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -457,12 +461,13 @@ static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
}
static int mt9v032_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
- format->format = *__mt9v032_get_pad_format(mt9v032, cfg, format->pad,
+ format->format = *__mt9v032_get_pad_format(mt9v032, sd_state,
+ format->pad,
format->which);
return 0;
}
@@ -492,7 +497,7 @@ static unsigned int mt9v032_calc_ratio(unsigned int input, unsigned int output)
}
static int mt9v032_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -503,7 +508,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
unsigned int hratio;
unsigned int vratio;
- __crop = __mt9v032_get_pad_crop(mt9v032, cfg, format->pad,
+ __crop = __mt9v032_get_pad_crop(mt9v032, sd_state, format->pad,
format->which);
/* Clamp the width and height to avoid dividing by zero. */
@@ -519,7 +524,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
hratio = mt9v032_calc_ratio(__crop->width, width);
vratio = mt9v032_calc_ratio(__crop->height, height);
- __format = __mt9v032_get_pad_format(mt9v032, cfg, format->pad,
+ __format = __mt9v032_get_pad_format(mt9v032, sd_state, format->pad,
format->which);
__format->width = __crop->width / hratio;
__format->height = __crop->height / vratio;
@@ -536,7 +541,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
}
static int mt9v032_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -544,12 +549,13 @@ static int mt9v032_get_selection(struct v4l2_subdev *subdev,
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- sel->r = *__mt9v032_get_pad_crop(mt9v032, cfg, sel->pad, sel->which);
+ sel->r = *__mt9v032_get_pad_crop(mt9v032, sd_state, sel->pad,
+ sel->which);
return 0;
}
static int mt9v032_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
@@ -581,13 +587,15 @@ static int mt9v032_set_selection(struct v4l2_subdev *subdev,
rect.height = min_t(unsigned int,
rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
- __crop = __mt9v032_get_pad_crop(mt9v032, cfg, sel->pad, sel->which);
+ __crop = __mt9v032_get_pad_crop(mt9v032, sd_state, sel->pad,
+ sel->which);
if (rect.width != __crop->width || rect.height != __crop->height) {
/* Reset the output image size if the crop rectangle size has
* been modified.
*/
- __format = __mt9v032_get_pad_format(mt9v032, cfg, sel->pad,
+ __format = __mt9v032_get_pad_format(mt9v032, sd_state,
+ sel->pad,
sel->which);
__format->width = rect.width;
__format->height = rect.height;
@@ -922,13 +930,13 @@ static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0);
+ crop = v4l2_subdev_get_try_crop(subdev, fh->state, 0);
crop->left = MT9V032_COLUMN_START_DEF;
crop->top = MT9V032_ROW_START_DEF;
crop->width = MT9V032_WINDOW_WIDTH_DEF;
crop->height = MT9V032_WINDOW_HEIGHT_DEF;
- format = v4l2_subdev_get_try_format(subdev, fh->pad, 0);
+ format = v4l2_subdev_get_try_format(subdev, fh->state, 0);
if (mt9v032->model->color)
format->code = MEDIA_BUS_FMT_SGRBG10_1X10;
diff --git a/drivers/media/i2c/mt9v111.c b/drivers/media/i2c/mt9v111.c
index 97c7527b74ed..2dc4a0f24ce8 100644
--- a/drivers/media/i2c/mt9v111.c
+++ b/drivers/media/i2c/mt9v111.c
@@ -791,16 +791,16 @@ static int mt9v111_g_frame_interval(struct v4l2_subdev *sd,
static struct v4l2_mbus_framefmt *__mt9v111_get_pad_format(
struct mt9v111_dev *mt9v111,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
#if IS_ENABLED(CONFIG_VIDEO_V4L2_SUBDEV_API)
- return v4l2_subdev_get_try_format(&mt9v111->sd, cfg, pad);
+ return v4l2_subdev_get_try_format(&mt9v111->sd, sd_state, pad);
#else
- return &cfg->try_fmt;
+ return &sd_state->pads->try_fmt;
#endif
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9v111->fmt;
@@ -810,7 +810,7 @@ static struct v4l2_mbus_framefmt *__mt9v111_get_pad_format(
}
static int mt9v111_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index > ARRAY_SIZE(mt9v111_formats) - 1)
@@ -822,7 +822,7 @@ static int mt9v111_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int mt9v111_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
unsigned int i;
@@ -845,7 +845,7 @@ static int mt9v111_enum_frame_interval(struct v4l2_subdev *sd,
}
static int mt9v111_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->pad || fse->index >= ARRAY_SIZE(mt9v111_frame_sizes))
@@ -860,7 +860,7 @@ static int mt9v111_enum_frame_size(struct v4l2_subdev *subdev,
}
static int mt9v111_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct mt9v111_dev *mt9v111 = sd_to_mt9v111(subdev);
@@ -869,7 +869,8 @@ static int mt9v111_get_format(struct v4l2_subdev *subdev,
return -EINVAL;
mutex_lock(&mt9v111->stream_mutex);
- format->format = *__mt9v111_get_pad_format(mt9v111, cfg, format->pad,
+ format->format = *__mt9v111_get_pad_format(mt9v111, sd_state,
+ format->pad,
format->which);
mutex_unlock(&mt9v111->stream_mutex);
@@ -877,7 +878,7 @@ static int mt9v111_get_format(struct v4l2_subdev *subdev,
}
static int mt9v111_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct mt9v111_dev *mt9v111 = sd_to_mt9v111(subdev);
@@ -925,7 +926,7 @@ static int mt9v111_set_format(struct v4l2_subdev *subdev,
new_fmt.height = mt9v111_frame_sizes[idx].height;
/* Update the device (or pad) format if it has changed. */
- __fmt = __mt9v111_get_pad_format(mt9v111, cfg, format->pad,
+ __fmt = __mt9v111_get_pad_format(mt9v111, sd_state, format->pad,
format->which);
/* Format hasn't changed, stop here. */
@@ -954,9 +955,9 @@ done:
}
static int mt9v111_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
- cfg->try_fmt = mt9v111_def_fmt;
+ sd_state->pads->try_fmt = mt9v111_def_fmt;
return 0;
}
diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c
index 87d76a7f691a..f3ac379ef34a 100644
--- a/drivers/media/i2c/noon010pc30.c
+++ b/drivers/media/i2c/noon010pc30.c
@@ -488,7 +488,7 @@ unlock:
}
static int noon010_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(noon010_formats))
@@ -499,15 +499,15 @@ static int noon010_enum_mbus_code(struct v4l2_subdev *sd,
}
static int noon010_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct noon010_info *info = to_noon010(sd);
struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- if (cfg) {
- mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ if (sd_state) {
+ mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
fmt->format = *mf;
}
return 0;
@@ -539,7 +539,8 @@ static const struct noon010_format *noon010_try_fmt(struct v4l2_subdev *sd,
return &noon010_formats[i];
}
-static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int noon010_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct noon010_info *info = to_noon010(sd);
@@ -554,8 +555,8 @@ static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
fmt->format.field = V4L2_FIELD_NONE;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- if (cfg) {
- mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ if (sd_state) {
+ mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
*mf = fmt->format;
}
return 0;
@@ -637,7 +638,9 @@ static int noon010_log_status(struct v4l2_subdev *sd)
static int noon010_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd,
+ fh->state,
+ 0);
mf->width = noon010_sizes[0].width;
mf->height = noon010_sizes[0].height;
diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c
index c47b1d45d8fd..a3ce5500d355 100644
--- a/drivers/media/i2c/ov02a10.c
+++ b/drivers/media/i2c/ov02a10.c
@@ -295,7 +295,7 @@ static void ov02a10_fill_fmt(const struct ov02a10_mode *mode,
}
static int ov02a10_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov02a10 *ov02a10 = to_ov02a10(sd);
@@ -315,7 +315,7 @@ static int ov02a10_set_fmt(struct v4l2_subdev *sd,
ov02a10_fill_fmt(ov02a10->cur_mode, mbus_fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- frame_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+ frame_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
else
frame_fmt = &ov02a10->fmt;
@@ -327,7 +327,7 @@ out_unlock:
}
static int ov02a10_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov02a10 *ov02a10 = to_ov02a10(sd);
@@ -336,7 +336,8 @@ static int ov02a10_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&ov02a10->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
+ fmt->pad);
} else {
fmt->format = ov02a10->fmt;
mbus_fmt->code = ov02a10->fmt.code;
@@ -349,7 +350,7 @@ static int ov02a10_get_fmt(struct v4l2_subdev *sd,
}
static int ov02a10_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct ov02a10 *ov02a10 = to_ov02a10(sd);
@@ -363,7 +364,7 @@ static int ov02a10_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov02a10_enum_frame_sizes(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -511,7 +512,7 @@ static int __ov02a10_stop_stream(struct ov02a10 *ov02a10)
}
static int ov02a10_entity_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = {
.which = V4L2_SUBDEV_FORMAT_TRY,
@@ -521,7 +522,7 @@ static int ov02a10_entity_init_cfg(struct v4l2_subdev *sd,
}
};
- ov02a10_set_fmt(sd, cfg, &fmt);
+ ov02a10_set_fmt(sd, sd_state, &fmt);
return 0;
}
@@ -540,11 +541,9 @@ static int ov02a10_s_stream(struct v4l2_subdev *sd, int on)
}
if (on) {
- ret = pm_runtime_get_sync(&client->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
goto unlock_and_return;
- }
ret = __ov02a10_start_stream(ov02a10);
if (ret) {
diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c
index 4a2885ff0cbe..7fc70af53e45 100644
--- a/drivers/media/i2c/ov13858.c
+++ b/drivers/media/i2c/ov13858.c
@@ -1150,7 +1150,7 @@ static int ov13858_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct ov13858 *ov13858 = to_ov13858(sd);
struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd,
- fh->pad,
+ fh->state,
0);
mutex_lock(&ov13858->mutex);
@@ -1275,7 +1275,7 @@ static const struct v4l2_ctrl_ops ov13858_ctrl_ops = {
};
static int ov13858_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
/* Only one bayer order(GRBG) is supported */
@@ -1288,7 +1288,7 @@ static int ov13858_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov13858_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -1315,14 +1315,14 @@ static void ov13858_update_pad_format(const struct ov13858_mode *mode,
}
static int ov13858_do_get_pad_format(struct ov13858 *ov13858,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *framefmt;
struct v4l2_subdev *sd = &ov13858->sd;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
ov13858_update_pad_format(ov13858->cur_mode, fmt);
@@ -1332,14 +1332,14 @@ static int ov13858_do_get_pad_format(struct ov13858 *ov13858,
}
static int ov13858_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov13858 *ov13858 = to_ov13858(sd);
int ret;
mutex_lock(&ov13858->mutex);
- ret = ov13858_do_get_pad_format(ov13858, cfg, fmt);
+ ret = ov13858_do_get_pad_format(ov13858, sd_state, fmt);
mutex_unlock(&ov13858->mutex);
return ret;
@@ -1347,7 +1347,7 @@ static int ov13858_get_pad_format(struct v4l2_subdev *sd,
static int
ov13858_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov13858 *ov13858 = to_ov13858(sd);
@@ -1371,7 +1371,7 @@ ov13858_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
ov13858_update_pad_format(mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
ov13858->cur_mode = mode;
@@ -1472,11 +1472,9 @@ static int ov13858_set_stream(struct v4l2_subdev *sd, int enable)
}
if (enable) {
- ret = pm_runtime_get_sync(&client->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
goto err_unlock;
- }
/*
* Apply default & customized values
diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c
index 4a4bd5b665a1..4b75da55b260 100644
--- a/drivers/media/i2c/ov2640.c
+++ b/drivers/media/i2c/ov2640.c
@@ -913,7 +913,7 @@ err:
}
static int ov2640_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -925,7 +925,7 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
- mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
format->format = *mf;
return 0;
#else
@@ -946,7 +946,7 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd,
}
static int ov2640_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -996,7 +996,7 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd,
/* select format */
priv->cfmt_code = mf->code;
} else {
- cfg->try_fmt = *mf;
+ sd_state->pads->try_fmt = *mf;
}
out:
mutex_unlock(&priv->lock);
@@ -1005,11 +1005,11 @@ out:
}
static int ov2640_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, cfg, 0);
+ v4l2_subdev_get_try_format(sd, sd_state, 0);
const struct ov2640_win_size *win =
ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT);
@@ -1026,7 +1026,7 @@ static int ov2640_init_cfg(struct v4l2_subdev *sd,
}
static int ov2640_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index >= ARRAY_SIZE(ov2640_codes))
@@ -1037,7 +1037,7 @@ static int ov2640_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov2640_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c
index 42f64175a6df..13ded5b2aa66 100644
--- a/drivers/media/i2c/ov2659.c
+++ b/drivers/media/i2c/ov2659.c
@@ -204,6 +204,7 @@ struct ov2659 {
struct i2c_client *client;
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *link_frequency;
+ struct clk *clk;
const struct ov2659_framesize *frame_size;
struct sensor_register *format_ctrl_regs;
struct ov2659_pll_ctrl pll;
@@ -979,7 +980,7 @@ static int ov2659_init(struct v4l2_subdev *sd, u32 val)
*/
static int ov2659_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -995,7 +996,7 @@ static int ov2659_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov2659_enum_frame_sizes(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1021,7 +1022,7 @@ static int ov2659_enum_frame_sizes(struct v4l2_subdev *sd,
}
static int ov2659_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1033,7 +1034,7 @@ static int ov2659_get_fmt(struct v4l2_subdev *sd,
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
mutex_lock(&ov2659->lock);
fmt->format = *mf;
mutex_unlock(&ov2659->lock);
@@ -1083,7 +1084,7 @@ static void __ov2659_try_frame_size(struct v4l2_mbus_framefmt *mf,
}
static int ov2659_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1113,7 +1114,7 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
- mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*mf = fmt->format;
#endif
} else {
@@ -1186,11 +1187,9 @@ static int ov2659_s_stream(struct v4l2_subdev *sd, int on)
goto unlock;
}
- ret = pm_runtime_get_sync(&client->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
goto unlock;
- }
ret = ov2659_init(sd, 0);
if (!ret)
@@ -1270,6 +1269,8 @@ static int ov2659_power_off(struct device *dev)
gpiod_set_value(ov2659->pwdn_gpio, 1);
+ clk_disable_unprepare(ov2659->clk);
+
return 0;
}
@@ -1278,9 +1279,17 @@ static int ov2659_power_on(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct ov2659 *ov2659 = to_ov2659(sd);
+ int ret;
dev_dbg(&client->dev, "%s:\n", __func__);
+ ret = clk_prepare_enable(ov2659->clk);
+ if (ret) {
+ dev_err(&client->dev, "%s: failed to enable clock\n",
+ __func__);
+ return ret;
+ }
+
gpiod_set_value(ov2659->pwdn_gpio, 0);
if (ov2659->resetb_gpio) {
@@ -1302,7 +1311,7 @@ static int ov2659_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format =
- v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
dev_dbg(&client->dev, "%s:\n", __func__);
@@ -1368,8 +1377,7 @@ static int ov2659_detect(struct v4l2_subdev *sd)
id = OV265X_ID(pid, ver);
if (id != OV2659_ID) {
dev_err(&client->dev,
- "Sensor detection failed (%04X, %d)\n",
- id, ret);
+ "Sensor detection failed (%04X)\n", id);
ret = -ENODEV;
} else {
dev_info(&client->dev, "Found OV%04X sensor\n", id);
@@ -1425,7 +1433,6 @@ static int ov2659_probe(struct i2c_client *client)
const struct ov2659_platform_data *pdata = ov2659_get_pdata(client);
struct v4l2_subdev *sd;
struct ov2659 *ov2659;
- struct clk *clk;
int ret;
if (!pdata) {
@@ -1440,11 +1447,11 @@ static int ov2659_probe(struct i2c_client *client)
ov2659->pdata = pdata;
ov2659->client = client;
- clk = devm_clk_get(&client->dev, "xvclk");
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ov2659->clk = devm_clk_get(&client->dev, "xvclk");
+ if (IS_ERR(ov2659->clk))
+ return PTR_ERR(ov2659->clk);
- ov2659->xvclk_frequency = clk_get_rate(clk);
+ ov2659->xvclk_frequency = clk_get_rate(ov2659->clk);
if (ov2659->xvclk_frequency < 6000000 ||
ov2659->xvclk_frequency > 27000000)
return -EINVAL;
@@ -1506,7 +1513,9 @@ static int ov2659_probe(struct i2c_client *client)
ov2659->frame_size = &ov2659_framesizes[2];
ov2659->format_ctrl_regs = ov2659_formats[0].format_ctrl_regs;
- ov2659_power_on(&client->dev);
+ ret = ov2659_power_on(&client->dev);
+ if (ret < 0)
+ goto error;
ret = ov2659_detect(sd);
if (ret < 0)
diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c
index 178dfe985a25..906c711f6821 100644
--- a/drivers/media/i2c/ov2680.c
+++ b/drivers/media/i2c/ov2680.c
@@ -645,7 +645,7 @@ unlock:
}
static int ov2680_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct ov2680_dev *sensor = to_ov2680_dev(sd);
@@ -659,7 +659,7 @@ static int ov2680_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov2680_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov2680_dev *sensor = to_ov2680_dev(sd);
@@ -673,7 +673,8 @@ static int ov2680_get_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
- fmt = v4l2_subdev_get_try_format(&sensor->sd, cfg, format->pad);
+ fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
+ format->pad);
#else
ret = -EINVAL;
#endif
@@ -690,7 +691,7 @@ static int ov2680_get_fmt(struct v4l2_subdev *sd,
}
static int ov2680_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov2680_dev *sensor = to_ov2680_dev(sd);
@@ -721,7 +722,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
- try_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+ try_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
format->format = *try_fmt;
#endif
goto unlock;
@@ -743,22 +744,22 @@ unlock:
}
static int ov2680_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = {
- .which = cfg ? V4L2_SUBDEV_FORMAT_TRY
- : V4L2_SUBDEV_FORMAT_ACTIVE,
+ .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
+ : V4L2_SUBDEV_FORMAT_ACTIVE,
.format = {
.width = 800,
.height = 600,
}
};
- return ov2680_set_fmt(sd, cfg, &fmt);
+ return ov2680_set_fmt(sd, sd_state, &fmt);
}
static int ov2680_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
int index = fse->index;
@@ -775,7 +776,7 @@ static int ov2680_enum_frame_size(struct v4l2_subdev *sd,
}
static int ov2680_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
struct v4l2_fract tpf;
diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c
index 49a2dcedb347..b6e010ea3249 100644
--- a/drivers/media/i2c/ov2685.c
+++ b/drivers/media/i2c/ov2685.c
@@ -328,7 +328,7 @@ static void ov2685_fill_fmt(const struct ov2685_mode *mode,
}
static int ov2685_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov2685 *ov2685 = to_ov2685(sd);
@@ -341,7 +341,7 @@ static int ov2685_set_fmt(struct v4l2_subdev *sd,
}
static int ov2685_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov2685 *ov2685 = to_ov2685(sd);
@@ -353,7 +353,7 @@ static int ov2685_get_fmt(struct v4l2_subdev *sd,
}
static int ov2685_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(supported_modes))
@@ -365,7 +365,7 @@ static int ov2685_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov2685_enum_frame_sizes(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
int index = fse->index;
@@ -456,11 +456,10 @@ static int ov2685_s_stream(struct v4l2_subdev *sd, int on)
goto unlock_and_return;
if (on) {
- ret = pm_runtime_get_sync(&ov2685->client->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
+ ret = pm_runtime_resume_and_get(&ov2685->client->dev);
+ if (ret < 0)
goto unlock_and_return;
- }
+
ret = __v4l2_ctrl_handler_setup(&ov2685->ctrl_handler);
if (ret) {
pm_runtime_put(&client->dev);
@@ -494,7 +493,7 @@ static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_lock(&ov2685->mutex);
- try_fmt = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ try_fmt = v4l2_subdev_get_try_format(sd, fh->state, 0);
/* Initialize try_fmt */
ov2685_fill_fmt(&supported_modes[0], try_fmt);
diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c
index 0f3f17f3c426..599369a3d192 100644
--- a/drivers/media/i2c/ov2740.c
+++ b/drivers/media/i2c/ov2740.c
@@ -751,9 +751,8 @@ static int ov2740_set_stream(struct v4l2_subdev *sd, int enable)
mutex_lock(&ov2740->mutex);
if (enable) {
- ret = pm_runtime_get_sync(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
mutex_unlock(&ov2740->mutex);
return ret;
}
@@ -811,7 +810,7 @@ exit:
}
static int ov2740_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov2740 *ov2740 = to_ov2740(sd);
@@ -826,7 +825,7 @@ static int ov2740_set_format(struct v4l2_subdev *sd,
mutex_lock(&ov2740->mutex);
ov2740_update_pad_format(mode, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+ *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
} else {
ov2740->cur_mode = mode;
__v4l2_ctrl_s_ctrl(ov2740->link_freq, mode->link_freq_index);
@@ -851,14 +850,15 @@ static int ov2740_set_format(struct v4l2_subdev *sd,
}
static int ov2740_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov2740 *ov2740 = to_ov2740(sd);
mutex_lock(&ov2740->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&ov2740->sd, cfg,
+ fmt->format = *v4l2_subdev_get_try_format(&ov2740->sd,
+ sd_state,
fmt->pad);
else
ov2740_update_pad_format(ov2740->cur_mode, &fmt->format);
@@ -869,7 +869,7 @@ static int ov2740_get_format(struct v4l2_subdev *sd,
}
static int ov2740_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
@@ -881,7 +881,7 @@ static int ov2740_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov2740_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -904,7 +904,7 @@ static int ov2740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_lock(&ov2740->mutex);
ov2740_update_pad_format(&supported_modes[0],
- v4l2_subdev_get_try_format(sd, fh->pad, 0));
+ v4l2_subdev_get_try_format(sd, fh->state, 0));
mutex_unlock(&ov2740->mutex);
return 0;
@@ -1049,9 +1049,8 @@ static int ov2740_nvmem_read(void *priv, unsigned int off, void *val,
goto exit;
}
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0) {
- pm_runtime_put_noidle(dev);
goto exit;
}
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 5b9cc71df473..f6e1e51e0375 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -2227,7 +2227,7 @@ find_mode:
}
static int ov5640_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov5640_dev *sensor = to_ov5640_dev(sd);
@@ -2239,7 +2239,7 @@ static int ov5640_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&sensor->lock);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt = v4l2_subdev_get_try_format(&sensor->sd, cfg,
+ fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
format->pad);
else
fmt = &sensor->fmt;
@@ -2285,7 +2285,7 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
}
static int ov5640_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov5640_dev *sensor = to_ov5640_dev(sd);
@@ -2310,7 +2310,7 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd,
goto out;
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+ fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
else
fmt = &sensor->fmt;
@@ -2818,7 +2818,7 @@ free_ctrls:
}
static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->pad != 0)
@@ -2838,7 +2838,7 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
static int ov5640_enum_frame_interval(
struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
struct ov5640_dev *sensor = to_ov5640_dev(sd);
@@ -2924,7 +2924,7 @@ out:
}
static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad != 0)
diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c
index a6c17d15d754..368fa21e675e 100644
--- a/drivers/media/i2c/ov5645.c
+++ b/drivers/media/i2c/ov5645.c
@@ -837,7 +837,7 @@ static const struct v4l2_ctrl_ops ov5645_ctrl_ops = {
};
static int ov5645_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
@@ -849,7 +849,7 @@ static int ov5645_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov5645_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->code != MEDIA_BUS_FMT_UYVY8_2X8)
@@ -868,13 +868,13 @@ static int ov5645_enum_frame_size(struct v4l2_subdev *subdev,
static struct v4l2_mbus_framefmt *
__ov5645_get_pad_format(struct ov5645 *ov5645,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&ov5645->sd, cfg, pad);
+ return v4l2_subdev_get_try_format(&ov5645->sd, sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &ov5645->fmt;
default:
@@ -883,23 +883,25 @@ __ov5645_get_pad_format(struct ov5645 *ov5645,
}
static int ov5645_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov5645 *ov5645 = to_ov5645(sd);
- format->format = *__ov5645_get_pad_format(ov5645, cfg, format->pad,
+ format->format = *__ov5645_get_pad_format(ov5645, sd_state,
+ format->pad,
format->which);
return 0;
}
static struct v4l2_rect *
-__ov5645_get_pad_crop(struct ov5645 *ov5645, struct v4l2_subdev_pad_config *cfg,
+__ov5645_get_pad_crop(struct ov5645 *ov5645,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&ov5645->sd, cfg, pad);
+ return v4l2_subdev_get_try_crop(&ov5645->sd, sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &ov5645->crop;
default:
@@ -908,7 +910,7 @@ __ov5645_get_pad_crop(struct ov5645 *ov5645, struct v4l2_subdev_pad_config *cfg,
}
static int ov5645_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov5645 *ov5645 = to_ov5645(sd);
@@ -917,8 +919,8 @@ static int ov5645_set_format(struct v4l2_subdev *sd,
const struct ov5645_mode_info *new_mode;
int ret;
- __crop = __ov5645_get_pad_crop(ov5645, cfg, format->pad,
- format->which);
+ __crop = __ov5645_get_pad_crop(ov5645, sd_state, format->pad,
+ format->which);
new_mode = v4l2_find_nearest_size(ov5645_mode_info_data,
ARRAY_SIZE(ov5645_mode_info_data),
@@ -942,8 +944,8 @@ static int ov5645_set_format(struct v4l2_subdev *sd,
ov5645->current_mode = new_mode;
}
- __format = __ov5645_get_pad_format(ov5645, cfg, format->pad,
- format->which);
+ __format = __ov5645_get_pad_format(ov5645, sd_state, format->pad,
+ format->which);
__format->width = __crop->width;
__format->height = __crop->height;
__format->code = MEDIA_BUS_FMT_UYVY8_2X8;
@@ -956,21 +958,21 @@ static int ov5645_set_format(struct v4l2_subdev *sd,
}
static int ov5645_entity_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = { 0 };
- fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
fmt.format.width = 1920;
fmt.format.height = 1080;
- ov5645_set_format(subdev, cfg, &fmt);
+ ov5645_set_format(subdev, sd_state, &fmt);
return 0;
}
static int ov5645_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct ov5645 *ov5645 = to_ov5645(sd);
@@ -978,7 +980,7 @@ static int ov5645_get_selection(struct v4l2_subdev *sd,
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- sel->r = *__ov5645_get_pad_crop(ov5645, cfg, sel->pad,
+ sel->r = *__ov5645_get_pad_crop(ov5645, sd_state, sel->pad,
sel->which);
return 0;
}
diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 1cefa15729ce..d346d18ce629 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -856,12 +856,13 @@ static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
};
static const struct v4l2_rect *
-__ov5647_get_pad_crop(struct ov5647 *ov5647, struct v4l2_subdev_pad_config *cfg,
+__ov5647_get_pad_crop(struct ov5647 *ov5647,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&ov5647->sd, cfg, pad);
+ return v4l2_subdev_get_try_crop(&ov5647->sd, sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &ov5647->mode->crop;
}
@@ -882,20 +883,20 @@ static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
}
if (enable) {
- ret = pm_runtime_get_sync(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
if (ret < 0)
goto error_unlock;
ret = ov5647_stream_on(sd);
if (ret < 0) {
dev_err(&client->dev, "stream start failed: %d\n", ret);
- goto error_unlock;
+ goto error_pm;
}
} else {
ret = ov5647_stream_off(sd);
if (ret < 0) {
dev_err(&client->dev, "stream stop failed: %d\n", ret);
- goto error_unlock;
+ goto error_pm;
}
pm_runtime_put(&client->dev);
}
@@ -905,8 +906,9 @@ static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
-error_unlock:
+error_pm:
pm_runtime_put(&client->dev);
+error_unlock:
mutex_unlock(&sensor->lock);
return ret;
@@ -917,7 +919,7 @@ static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = {
};
static int ov5647_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
@@ -929,7 +931,7 @@ static int ov5647_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
const struct v4l2_mbus_framefmt *fmt;
@@ -948,7 +950,7 @@ static int ov5647_enum_frame_size(struct v4l2_subdev *sd,
}
static int ov5647_get_pad_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -958,7 +960,8 @@ static int ov5647_get_pad_fmt(struct v4l2_subdev *sd,
mutex_lock(&sensor->lock);
switch (format->which) {
case V4L2_SUBDEV_FORMAT_TRY:
- sensor_format = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ sensor_format = v4l2_subdev_get_try_format(sd, sd_state,
+ format->pad);
break;
default:
sensor_format = &sensor->mode->format;
@@ -972,7 +975,7 @@ static int ov5647_get_pad_fmt(struct v4l2_subdev *sd,
}
static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -986,7 +989,7 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
/* Update the sensor mode and apply at it at streamon time. */
mutex_lock(&sensor->lock);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, cfg, format->pad) = mode->format;
+ *v4l2_subdev_get_try_format(sd, sd_state, format->pad) = mode->format;
} else {
int exposure_max, exposure_def;
int hblank, vblank;
@@ -1019,7 +1022,7 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
}
static int ov5647_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
switch (sel->target) {
@@ -1027,7 +1030,7 @@ static int ov5647_get_selection(struct v4l2_subdev *sd,
struct ov5647 *sensor = to_sensor(sd);
mutex_lock(&sensor->lock);
- sel->r = *__ov5647_get_pad_crop(sensor, cfg, sel->pad,
+ sel->r = *__ov5647_get_pad_crop(sensor, sd_state, sel->pad,
sel->which);
mutex_unlock(&sensor->lock);
@@ -1103,8 +1106,8 @@ static int ov5647_detect(struct v4l2_subdev *sd)
static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *format =
- v4l2_subdev_get_try_format(sd, fh->pad, 0);
- struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0);
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
+ struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
crop->left = OV5647_PIXEL_ARRAY_LEFT;
crop->top = OV5647_PIXEL_ARRAY_TOP;
diff --git a/drivers/media/i2c/ov5648.c b/drivers/media/i2c/ov5648.c
index 3ecb4a3e8773..947d437ed0ef 100644
--- a/drivers/media/i2c/ov5648.c
+++ b/drivers/media/i2c/ov5648.c
@@ -2132,11 +2132,9 @@ static int ov5648_s_stream(struct v4l2_subdev *subdev, int enable)
int ret;
if (enable) {
- ret = pm_runtime_get_sync(sensor->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(sensor->dev);
+ ret = pm_runtime_resume_and_get(sensor->dev);
+ if (ret < 0)
return ret;
- }
}
mutex_lock(&sensor->mutex);
@@ -2190,7 +2188,7 @@ static const struct v4l2_subdev_video_ops ov5648_subdev_video_ops = {
/* Subdev Pad Operations */
static int ov5648_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *config,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code_enum)
{
if (code_enum->index >= ARRAY_SIZE(ov5648_mbus_codes))
@@ -2219,7 +2217,7 @@ static void ov5648_mbus_format_fill(struct v4l2_mbus_framefmt *mbus_format,
}
static int ov5648_get_fmt(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *config,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
@@ -2228,7 +2226,7 @@ static int ov5648_get_fmt(struct v4l2_subdev *subdev,
mutex_lock(&sensor->mutex);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *mbus_format = *v4l2_subdev_get_try_format(subdev, config,
+ *mbus_format = *v4l2_subdev_get_try_format(subdev, sd_state,
format->pad);
else
ov5648_mbus_format_fill(mbus_format, sensor->state.mbus_code,
@@ -2240,7 +2238,7 @@ static int ov5648_get_fmt(struct v4l2_subdev *subdev,
}
static int ov5648_set_fmt(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *config,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
@@ -2281,7 +2279,7 @@ static int ov5648_set_fmt(struct v4l2_subdev *subdev,
ov5648_mbus_format_fill(mbus_format, mbus_code, mode);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *v4l2_subdev_get_try_format(subdev, config, format->pad) =
+ *v4l2_subdev_get_try_format(subdev, sd_state, format->pad) =
*mbus_format;
else if (sensor->state.mode != mode ||
sensor->state.mbus_code != mbus_code)
@@ -2294,7 +2292,7 @@ complete:
}
static int ov5648_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *config,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *size_enum)
{
const struct ov5648_mode *mode;
@@ -2311,7 +2309,7 @@ static int ov5648_enum_frame_size(struct v4l2_subdev *subdev,
}
static int ov5648_enum_frame_interval(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *config,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *interval_enum)
{
const struct ov5648_mode *mode = NULL;
diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c
index dee7df8dd100..49189926afd6 100644
--- a/drivers/media/i2c/ov5670.c
+++ b/drivers/media/i2c/ov5670.c
@@ -1937,7 +1937,7 @@ static int ov5670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct ov5670 *ov5670 = to_ov5670(sd);
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
mutex_lock(&ov5670->mutex);
@@ -2153,7 +2153,7 @@ error:
}
static int ov5670_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
/* Only one bayer order GRBG is supported */
@@ -2166,7 +2166,7 @@ static int ov5670_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov5670_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -2193,11 +2193,12 @@ static void ov5670_update_pad_format(const struct ov5670_mode *mode,
}
static int ov5670_do_get_pad_format(struct ov5670 *ov5670,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&ov5670->sd, cfg,
+ fmt->format = *v4l2_subdev_get_try_format(&ov5670->sd,
+ sd_state,
fmt->pad);
else
ov5670_update_pad_format(ov5670->cur_mode, fmt);
@@ -2206,21 +2207,21 @@ static int ov5670_do_get_pad_format(struct ov5670 *ov5670,
}
static int ov5670_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov5670 *ov5670 = to_ov5670(sd);
int ret;
mutex_lock(&ov5670->mutex);
- ret = ov5670_do_get_pad_format(ov5670, cfg, fmt);
+ ret = ov5670_do_get_pad_format(ov5670, sd_state, fmt);
mutex_unlock(&ov5670->mutex);
return ret;
}
static int ov5670_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov5670 *ov5670 = to_ov5670(sd);
@@ -2238,7 +2239,7 @@ static int ov5670_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
ov5670_update_pad_format(mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+ *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
} else {
ov5670->cur_mode = mode;
__v4l2_ctrl_s_ctrl(ov5670->link_freq, mode->link_freq_index);
@@ -2347,11 +2348,9 @@ static int ov5670_set_stream(struct v4l2_subdev *sd, int enable)
goto unlock_and_return;
if (enable) {
- ret = pm_runtime_get_sync(&client->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
goto unlock_and_return;
- }
ret = ov5670_start_streaming(ov5670);
if (ret)
diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c
index dea32859459a..da5850b7ad07 100644
--- a/drivers/media/i2c/ov5675.c
+++ b/drivers/media/i2c/ov5675.c
@@ -863,9 +863,8 @@ static int ov5675_set_stream(struct v4l2_subdev *sd, int enable)
mutex_lock(&ov5675->mutex);
if (enable) {
- ret = pm_runtime_get_sync(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
mutex_unlock(&ov5675->mutex);
return ret;
}
@@ -924,7 +923,7 @@ static int __maybe_unused ov5675_resume(struct device *dev)
}
static int ov5675_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov5675 *ov5675 = to_ov5675(sd);
@@ -939,7 +938,7 @@ static int ov5675_set_format(struct v4l2_subdev *sd,
mutex_lock(&ov5675->mutex);
ov5675_update_pad_format(mode, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+ *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
} else {
ov5675->cur_mode = mode;
__v4l2_ctrl_s_ctrl(ov5675->link_freq, mode->link_freq_index);
@@ -965,14 +964,15 @@ static int ov5675_set_format(struct v4l2_subdev *sd,
}
static int ov5675_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov5675 *ov5675 = to_ov5675(sd);
mutex_lock(&ov5675->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&ov5675->sd, cfg,
+ fmt->format = *v4l2_subdev_get_try_format(&ov5675->sd,
+ sd_state,
fmt->pad);
else
ov5675_update_pad_format(ov5675->cur_mode, &fmt->format);
@@ -983,7 +983,7 @@ static int ov5675_get_format(struct v4l2_subdev *sd,
}
static int ov5675_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
@@ -995,7 +995,7 @@ static int ov5675_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov5675_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -1018,7 +1018,7 @@ static int ov5675_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_lock(&ov5675->mutex);
ov5675_update_pad_format(&supported_modes[0],
- v4l2_subdev_get_try_format(sd, fh->pad, 0));
+ v4l2_subdev_get_try_format(sd, fh->state, 0));
mutex_unlock(&ov5675->mutex);
return 0;
diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c
index 09bee57a241d..439385938a51 100644
--- a/drivers/media/i2c/ov5695.c
+++ b/drivers/media/i2c/ov5695.c
@@ -806,7 +806,7 @@ ov5695_find_best_fit(struct v4l2_subdev_format *fmt)
}
static int ov5695_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov5695 *ov5695 = to_ov5695(sd);
@@ -822,7 +822,7 @@ static int ov5695_set_fmt(struct v4l2_subdev *sd,
fmt->format.field = V4L2_FIELD_NONE;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
- *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+ *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
#endif
} else {
ov5695->cur_mode = mode;
@@ -841,7 +841,7 @@ static int ov5695_set_fmt(struct v4l2_subdev *sd,
}
static int ov5695_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov5695 *ov5695 = to_ov5695(sd);
@@ -850,7 +850,8 @@ static int ov5695_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&ov5695->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
- fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
+ fmt->pad);
#else
mutex_unlock(&ov5695->mutex);
return -EINVAL;
@@ -867,7 +868,7 @@ static int ov5695_get_fmt(struct v4l2_subdev *sd,
}
static int ov5695_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index != 0)
@@ -878,7 +879,7 @@ static int ov5695_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov5695_enum_frame_sizes(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -946,11 +947,9 @@ static int ov5695_s_stream(struct v4l2_subdev *sd, int on)
goto unlock_and_return;
if (on) {
- ret = pm_runtime_get_sync(&client->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
goto unlock_and_return;
- }
ret = __ov5695_start_stream(ov5695);
if (ret) {
@@ -1054,7 +1053,7 @@ static int ov5695_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct ov5695 *ov5695 = to_ov5695(sd);
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
const struct ov5695_mode *def_mode = &supported_modes[0];
mutex_lock(&ov5695->mutex);
diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 85dd13694bd2..f67412150b16 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -467,7 +467,7 @@ static int ov6650_s_power(struct v4l2_subdev *sd, int on)
}
static int ov6650_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -492,7 +492,7 @@ static int ov6650_get_selection(struct v4l2_subdev *sd,
}
static int ov6650_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -535,7 +535,7 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,
}
static int ov6650_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -550,9 +550,9 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd,
/* update media bus format code and frame size */
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf->width = cfg->try_fmt.width;
- mf->height = cfg->try_fmt.height;
- mf->code = cfg->try_fmt.code;
+ mf->width = sd_state->pads->try_fmt.width;
+ mf->height = sd_state->pads->try_fmt.height;
+ mf->code = sd_state->pads->try_fmt.code;
} else {
mf->width = priv->rect.width >> priv->half_scale;
@@ -668,7 +668,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
}
static int ov6650_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -701,15 +701,15 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
/* store media bus format code and frame size in pad config */
- cfg->try_fmt.width = mf->width;
- cfg->try_fmt.height = mf->height;
- cfg->try_fmt.code = mf->code;
+ sd_state->pads->try_fmt.width = mf->width;
+ sd_state->pads->try_fmt.height = mf->height;
+ sd_state->pads->try_fmt.code = mf->code;
/* return default mbus frame format updated with pad config */
*mf = ov6650_def_fmt;
- mf->width = cfg->try_fmt.width;
- mf->height = cfg->try_fmt.height;
- mf->code = cfg->try_fmt.code;
+ mf->width = sd_state->pads->try_fmt.width;
+ mf->height = sd_state->pads->try_fmt.height;
+ mf->code = sd_state->pads->try_fmt.code;
} else {
/* apply new media bus format code and frame size */
@@ -728,7 +728,7 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
}
static int ov6650_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index >= ARRAY_SIZE(ov6650_codes))
diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c
index 0c10203f822b..ebb299f207e5 100644
--- a/drivers/media/i2c/ov7251.c
+++ b/drivers/media/i2c/ov7251.c
@@ -898,7 +898,7 @@ static const struct v4l2_ctrl_ops ov7251_ctrl_ops = {
};
static int ov7251_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
@@ -910,7 +910,7 @@ static int ov7251_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov7251_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->code != MEDIA_BUS_FMT_Y10_1X10)
@@ -928,7 +928,7 @@ static int ov7251_enum_frame_size(struct v4l2_subdev *subdev,
}
static int ov7251_enum_frame_ival(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
unsigned int index = fie->index;
@@ -950,13 +950,13 @@ static int ov7251_enum_frame_ival(struct v4l2_subdev *subdev,
static struct v4l2_mbus_framefmt *
__ov7251_get_pad_format(struct ov7251 *ov7251,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&ov7251->sd, cfg, pad);
+ return v4l2_subdev_get_try_format(&ov7251->sd, sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &ov7251->fmt;
default:
@@ -965,13 +965,14 @@ __ov7251_get_pad_format(struct ov7251 *ov7251,
}
static int ov7251_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov7251 *ov7251 = to_ov7251(sd);
mutex_lock(&ov7251->lock);
- format->format = *__ov7251_get_pad_format(ov7251, cfg, format->pad,
+ format->format = *__ov7251_get_pad_format(ov7251, sd_state,
+ format->pad,
format->which);
mutex_unlock(&ov7251->lock);
@@ -979,12 +980,13 @@ static int ov7251_get_format(struct v4l2_subdev *sd,
}
static struct v4l2_rect *
-__ov7251_get_pad_crop(struct ov7251 *ov7251, struct v4l2_subdev_pad_config *cfg,
+__ov7251_get_pad_crop(struct ov7251 *ov7251,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&ov7251->sd, cfg, pad);
+ return v4l2_subdev_get_try_crop(&ov7251->sd, sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &ov7251->crop;
default:
@@ -1027,7 +1029,7 @@ ov7251_find_mode_by_ival(struct ov7251 *ov7251, struct v4l2_fract *timeperframe)
}
static int ov7251_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov7251 *ov7251 = to_ov7251(sd);
@@ -1038,7 +1040,8 @@ static int ov7251_set_format(struct v4l2_subdev *sd,
mutex_lock(&ov7251->lock);
- __crop = __ov7251_get_pad_crop(ov7251, cfg, format->pad, format->which);
+ __crop = __ov7251_get_pad_crop(ov7251, sd_state, format->pad,
+ format->which);
new_mode = v4l2_find_nearest_size(ov7251_mode_info_data,
ARRAY_SIZE(ov7251_mode_info_data),
@@ -1077,7 +1080,7 @@ static int ov7251_set_format(struct v4l2_subdev *sd,
ov7251->current_mode = new_mode;
}
- __format = __ov7251_get_pad_format(ov7251, cfg, format->pad,
+ __format = __ov7251_get_pad_format(ov7251, sd_state, format->pad,
format->which);
__format->width = __crop->width;
__format->height = __crop->height;
@@ -1098,24 +1101,24 @@ exit:
}
static int ov7251_entity_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = {
- .which = cfg ? V4L2_SUBDEV_FORMAT_TRY
- : V4L2_SUBDEV_FORMAT_ACTIVE,
+ .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
+ : V4L2_SUBDEV_FORMAT_ACTIVE,
.format = {
.width = 640,
.height = 480
}
};
- ov7251_set_format(subdev, cfg, &fmt);
+ ov7251_set_format(subdev, sd_state, &fmt);
return 0;
}
static int ov7251_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct ov7251 *ov7251 = to_ov7251(sd);
@@ -1124,7 +1127,7 @@ static int ov7251_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
mutex_lock(&ov7251->lock);
- sel->r = *__ov7251_get_pad_crop(ov7251, cfg, sel->pad,
+ sel->r = *__ov7251_get_pad_crop(ov7251, sd_state, sel->pad,
sel->which);
mutex_unlock(&ov7251->lock);
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index d2df811b1a40..196746423116 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -960,7 +960,7 @@ static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop,
static int ov7670_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index >= N_OV7670_FMTS)
@@ -1105,7 +1105,7 @@ static int ov7670_apply_fmt(struct v4l2_subdev *sd)
* Set a format.
*/
static int ov7670_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov7670_info *info = to_state(sd);
@@ -1122,7 +1122,8 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
if (ret)
return ret;
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
- mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state,
+ format->pad);
*mbus_fmt = format->format;
#endif
return 0;
@@ -1144,7 +1145,7 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
}
static int ov7670_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov7670_info *info = to_state(sd);
@@ -1154,7 +1155,7 @@ static int ov7670_get_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
- mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+ mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
format->format = *mbus_fmt;
return 0;
#else
@@ -1202,7 +1203,7 @@ static int ov7670_s_frame_interval(struct v4l2_subdev *sd,
static int ov7670_frame_rates[] = { 30, 15, 10, 5, 1 };
static int ov7670_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
struct ov7670_info *info = to_state(sd);
@@ -1241,7 +1242,7 @@ static int ov7670_enum_frame_interval(struct v4l2_subdev *sd,
* Frame size enumeration
*/
static int ov7670_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct ov7670_info *info = to_state(sd);
@@ -1724,7 +1725,7 @@ static void ov7670_get_default_format(struct v4l2_subdev *sd,
static int ov7670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *format =
- v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
ov7670_get_default_format(sd, format);
diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c
index d94cf2d39c2a..78602a2f70b0 100644
--- a/drivers/media/i2c/ov772x.c
+++ b/drivers/media/i2c/ov772x.c
@@ -1157,7 +1157,7 @@ ov772x_set_fmt_error:
}
static int ov772x_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct ov772x_priv *priv = to_ov772x(sd);
@@ -1179,7 +1179,7 @@ static int ov772x_get_selection(struct v4l2_subdev *sd,
}
static int ov772x_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -1198,7 +1198,7 @@ static int ov772x_get_fmt(struct v4l2_subdev *sd,
}
static int ov772x_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov772x_priv *priv = to_ov772x(sd);
@@ -1222,7 +1222,7 @@ static int ov772x_set_fmt(struct v4l2_subdev *sd,
mf->xfer_func = V4L2_XFER_FUNC_DEFAULT;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *mf;
+ sd_state->pads->try_fmt = *mf;
return 0;
}
@@ -1320,7 +1320,7 @@ static const struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
};
static int ov772x_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
if (fie->pad || fie->index >= ARRAY_SIZE(ov772x_frame_intervals))
@@ -1338,7 +1338,7 @@ static int ov772x_enum_frame_interval(struct v4l2_subdev *sd,
}
static int ov772x_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index >= ARRAY_SIZE(ov772x_cfmts))
diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
index 47a9003d29d6..2539cfee85c8 100644
--- a/drivers/media/i2c/ov7740.c
+++ b/drivers/media/i2c/ov7740.c
@@ -624,11 +624,9 @@ static int ov7740_set_stream(struct v4l2_subdev *sd, int enable)
}
if (enable) {
- ret = pm_runtime_get_sync(&client->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
goto err_unlock;
- }
ret = ov7740_start_streaming(ov7740);
if (ret)
@@ -709,7 +707,7 @@ static const struct ov7740_pixfmt ov7740_formats[] = {
#define N_OV7740_FMTS ARRAY_SIZE(ov7740_formats)
static int ov7740_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index >= N_OV7740_FMTS)
@@ -721,7 +719,7 @@ static int ov7740_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov7740_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
if (fie->pad)
@@ -740,7 +738,7 @@ static int ov7740_enum_frame_interval(struct v4l2_subdev *sd,
}
static int ov7740_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->pad)
@@ -803,7 +801,7 @@ static int ov7740_try_fmt_internal(struct v4l2_subdev *sd,
}
static int ov7740_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
@@ -825,7 +823,8 @@ static int ov7740_set_fmt(struct v4l2_subdev *sd,
if (ret)
goto error;
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
- mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state,
+ format->pad);
*mbus_fmt = format->format;
#endif
mutex_unlock(&ov7740->mutex);
@@ -848,7 +847,7 @@ error:
}
static int ov7740_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
@@ -860,7 +859,7 @@ static int ov7740_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&ov7740->mutex);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
- mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+ mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
format->format = *mbus_fmt;
ret = 0;
#else
@@ -905,7 +904,7 @@ static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
struct v4l2_mbus_framefmt *format =
- v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
mutex_lock(&ov7740->mutex);
ov7740_get_default_format(sd, format);
diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c
index e3af3ea277af..88e19f30d376 100644
--- a/drivers/media/i2c/ov8856.c
+++ b/drivers/media/i2c/ov8856.c
@@ -18,8 +18,6 @@
#define OV8856_REG_VALUE_16BIT 2
#define OV8856_REG_VALUE_24BIT 3
-#define OV8856_LINK_FREQ_360MHZ 360000000ULL
-#define OV8856_LINK_FREQ_180MHZ 180000000ULL
#define OV8856_SCLK 144000000ULL
#define OV8856_XVCLK_19_2 19200000
#define OV8856_DATA_LANES 4
@@ -78,6 +76,29 @@
#define OV8856_TEST_PATTERN_ENABLE BIT(7)
#define OV8856_TEST_PATTERN_BAR_SHIFT 2
+#define NUM_REGS 7
+#define NUM_MODE_REGS 187
+#define NUM_MODE_REGS_2 200
+
+/* Flip Mirror Controls from sensor */
+#define OV8856_REG_FORMAT1 0x3820
+#define OV8856_REG_FORMAT2 0x3821
+#define OV8856_REG_FORMAT1_OP_1 BIT(1)
+#define OV8856_REG_FORMAT1_OP_2 BIT(2)
+#define OV8856_REG_FORMAT1_OP_3 BIT(6)
+#define OV8856_REG_FORMAT2_OP_1 BIT(1)
+#define OV8856_REG_FORMAT2_OP_2 BIT(2)
+#define OV8856_REG_FORMAT2_OP_3 BIT(6)
+#define OV8856_REG_FLIP_OPT_1 0x376b
+#define OV8856_REG_FLIP_OPT_2 0x5001
+#define OV8856_REG_FLIP_OPT_3 0x502e
+#define OV8856_REG_MIRROR_OPT_1 0x5004
+#define OV8856_REG_FLIP_OP_0 BIT(0)
+#define OV8856_REG_FLIP_OP_1 BIT(1)
+#define OV8856_REG_FLIP_OP_2 BIT(2)
+#define OV8856_REG_MIRROR_OP_1 BIT(1)
+#define OV8856_REG_MIRROR_OP_2 BIT(2)
+
#define to_ov8856(_sd) container_of(_sd, struct ov8856, sd)
static const char * const ov8856_supply_names[] = {
@@ -86,11 +107,6 @@ static const char * const ov8856_supply_names[] = {
"dvdd", /* Digital core power */
};
-enum {
- OV8856_LINK_FREQ_720MBPS,
- OV8856_LINK_FREQ_360MBPS,
-};
-
struct ov8856_reg {
u16 address;
u8 val;
@@ -126,891 +142,1242 @@ struct ov8856_mode {
/* Sensor register settings for this resolution */
const struct ov8856_reg_list reg_list;
+
+ /* Number of data lanes */
+ u8 data_lanes;
};
-static const struct ov8856_reg mipi_data_rate_720mbps[] = {
- {0x0103, 0x01},
- {0x0100, 0x00},
- {0x0302, 0x4b},
- {0x0303, 0x01},
- {0x030b, 0x02},
- {0x030d, 0x4b},
- {0x031e, 0x0c},
+struct ov8856_mipi_data_rates {
+ const struct ov8856_reg regs_0[NUM_REGS];
+ const struct ov8856_reg regs_1[NUM_REGS];
};
-static const struct ov8856_reg mipi_data_rate_360mbps[] = {
- {0x0103, 0x01},
- {0x0100, 0x00},
- {0x0302, 0x4b},
- {0x0303, 0x03},
- {0x030b, 0x02},
- {0x030d, 0x4b},
- {0x031e, 0x0c},
+static const struct ov8856_mipi_data_rates mipi_data_rate_lane_2 = {
+ //mipi_data_rate_1440mbps
+ {
+ {0x0103, 0x01},
+ {0x0100, 0x00},
+ {0x0302, 0x43},
+ {0x0303, 0x00},
+ {0x030b, 0x02},
+ {0x030d, 0x4b},
+ {0x031e, 0x0c}
+ },
+ //mipi_data_rate_720mbps
+ {
+ {0x0103, 0x01},
+ {0x0100, 0x00},
+ {0x0302, 0x4b},
+ {0x0303, 0x01},
+ {0x030b, 0x02},
+ {0x030d, 0x4b},
+ {0x031e, 0x0c}
+ }
};
-static const struct ov8856_reg mode_3280x2464_regs[] = {
- {0x3000, 0x20},
- {0x3003, 0x08},
- {0x300e, 0x20},
- {0x3010, 0x00},
- {0x3015, 0x84},
- {0x3018, 0x72},
- {0x3021, 0x23},
- {0x3033, 0x24},
- {0x3500, 0x00},
- {0x3501, 0x9a},
- {0x3502, 0x20},
- {0x3503, 0x08},
- {0x3505, 0x83},
- {0x3508, 0x01},
- {0x3509, 0x80},
- {0x350c, 0x00},
- {0x350d, 0x80},
- {0x350e, 0x04},
- {0x350f, 0x00},
- {0x3510, 0x00},
- {0x3511, 0x02},
- {0x3512, 0x00},
- {0x3600, 0x72},
- {0x3601, 0x40},
- {0x3602, 0x30},
- {0x3610, 0xc5},
- {0x3611, 0x58},
- {0x3612, 0x5c},
- {0x3613, 0xca},
- {0x3614, 0x20},
- {0x3628, 0xff},
- {0x3629, 0xff},
- {0x362a, 0xff},
- {0x3633, 0x10},
- {0x3634, 0x10},
- {0x3635, 0x10},
- {0x3636, 0x10},
- {0x3663, 0x08},
- {0x3669, 0x34},
- {0x366e, 0x10},
- {0x3706, 0x86},
- {0x370b, 0x7e},
- {0x3714, 0x23},
- {0x3730, 0x12},
- {0x3733, 0x10},
- {0x3764, 0x00},
- {0x3765, 0x00},
- {0x3769, 0x62},
- {0x376a, 0x2a},
- {0x376b, 0x30},
- {0x3780, 0x00},
- {0x3781, 0x24},
- {0x3782, 0x00},
- {0x3783, 0x23},
- {0x3798, 0x2f},
- {0x37a1, 0x60},
- {0x37a8, 0x6a},
- {0x37ab, 0x3f},
- {0x37c2, 0x04},
- {0x37c3, 0xf1},
- {0x37c9, 0x80},
- {0x37cb, 0x16},
- {0x37cc, 0x16},
- {0x37cd, 0x16},
- {0x37ce, 0x16},
- {0x3800, 0x00},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0x06},
- {0x3804, 0x0c},
- {0x3805, 0xdf},
- {0x3806, 0x09},
- {0x3807, 0xa7},
- {0x3808, 0x0c},
- {0x3809, 0xd0},
- {0x380a, 0x09},
- {0x380b, 0xa0},
- {0x380c, 0x07},
- {0x380d, 0x88},
- {0x380e, 0x09},
- {0x380f, 0xb8},
- {0x3810, 0x00},
- {0x3811, 0x00},
- {0x3812, 0x00},
- {0x3813, 0x01},
- {0x3814, 0x01},
- {0x3815, 0x01},
- {0x3816, 0x00},
- {0x3817, 0x00},
- {0x3818, 0x00},
- {0x3819, 0x10},
- {0x3820, 0x80},
- {0x3821, 0x46},
- {0x382a, 0x01},
- {0x382b, 0x01},
- {0x3830, 0x06},
- {0x3836, 0x02},
- {0x3862, 0x04},
- {0x3863, 0x08},
- {0x3cc0, 0x33},
- {0x3d85, 0x17},
- {0x3d8c, 0x73},
- {0x3d8d, 0xde},
- {0x4001, 0xe0},
- {0x4003, 0x40},
- {0x4008, 0x00},
- {0x4009, 0x0b},
- {0x400a, 0x00},
- {0x400b, 0x84},
- {0x400f, 0x80},
- {0x4010, 0xf0},
- {0x4011, 0xff},
- {0x4012, 0x02},
- {0x4013, 0x01},
- {0x4014, 0x01},
- {0x4015, 0x01},
- {0x4042, 0x00},
- {0x4043, 0x80},
- {0x4044, 0x00},
- {0x4045, 0x80},
- {0x4046, 0x00},
- {0x4047, 0x80},
- {0x4048, 0x00},
- {0x4049, 0x80},
- {0x4041, 0x03},
- {0x404c, 0x20},
- {0x404d, 0x00},
- {0x404e, 0x20},
- {0x4203, 0x80},
- {0x4307, 0x30},
- {0x4317, 0x00},
- {0x4503, 0x08},
- {0x4601, 0x80},
- {0x4800, 0x44},
- {0x4816, 0x53},
- {0x481b, 0x58},
- {0x481f, 0x27},
- {0x4837, 0x16},
- {0x483c, 0x0f},
- {0x484b, 0x05},
- {0x5000, 0x57},
- {0x5001, 0x0a},
- {0x5004, 0x04},
- {0x502e, 0x03},
- {0x5030, 0x41},
- {0x5780, 0x14},
- {0x5781, 0x0f},
- {0x5782, 0x44},
- {0x5783, 0x02},
- {0x5784, 0x01},
- {0x5785, 0x01},
- {0x5786, 0x00},
- {0x5787, 0x04},
- {0x5788, 0x02},
- {0x5789, 0x0f},
- {0x578a, 0xfd},
- {0x578b, 0xf5},
- {0x578c, 0xf5},
- {0x578d, 0x03},
- {0x578e, 0x08},
- {0x578f, 0x0c},
- {0x5790, 0x08},
- {0x5791, 0x04},
- {0x5792, 0x00},
- {0x5793, 0x52},
- {0x5794, 0xa3},
- {0x5795, 0x02},
- {0x5796, 0x20},
- {0x5797, 0x20},
- {0x5798, 0xd5},
- {0x5799, 0xd5},
- {0x579a, 0x00},
- {0x579b, 0x50},
- {0x579c, 0x00},
- {0x579d, 0x2c},
- {0x579e, 0x0c},
- {0x579f, 0x40},
- {0x57a0, 0x09},
- {0x57a1, 0x40},
- {0x59f8, 0x3d},
- {0x5a08, 0x02},
- {0x5b00, 0x02},
- {0x5b01, 0x10},
- {0x5b02, 0x03},
- {0x5b03, 0xcf},
- {0x5b05, 0x6c},
- {0x5e00, 0x00}
+static const struct ov8856_mipi_data_rates mipi_data_rate_lane_4 = {
+ //mipi_data_rate_720mbps
+ {
+ {0x0103, 0x01},
+ {0x0100, 0x00},
+ {0x0302, 0x4b},
+ {0x0303, 0x01},
+ {0x030b, 0x02},
+ {0x030d, 0x4b},
+ {0x031e, 0x0c}
+ },
+ //mipi_data_rate_360mbps
+ {
+ {0x0103, 0x01},
+ {0x0100, 0x00},
+ {0x0302, 0x4b},
+ {0x0303, 0x03},
+ {0x030b, 0x02},
+ {0x030d, 0x4b},
+ {0x031e, 0x0c}
+ }
};
-static const struct ov8856_reg mode_3264x2448_regs[] = {
- {0x0103, 0x01},
- {0x0302, 0x3c},
- {0x0303, 0x01},
- {0x031e, 0x0c},
- {0x3000, 0x20},
- {0x3003, 0x08},
- {0x300e, 0x20},
- {0x3010, 0x00},
- {0x3015, 0x84},
- {0x3018, 0x72},
- {0x3021, 0x23},
- {0x3033, 0x24},
- {0x3500, 0x00},
- {0x3501, 0x9a},
- {0x3502, 0x20},
- {0x3503, 0x08},
- {0x3505, 0x83},
- {0x3508, 0x01},
- {0x3509, 0x80},
- {0x350c, 0x00},
- {0x350d, 0x80},
- {0x350e, 0x04},
- {0x350f, 0x00},
- {0x3510, 0x00},
- {0x3511, 0x02},
- {0x3512, 0x00},
- {0x3600, 0x72},
- {0x3601, 0x40},
- {0x3602, 0x30},
- {0x3610, 0xc5},
- {0x3611, 0x58},
- {0x3612, 0x5c},
- {0x3613, 0xca},
- {0x3614, 0x60},
- {0x3628, 0xff},
- {0x3629, 0xff},
- {0x362a, 0xff},
- {0x3633, 0x10},
- {0x3634, 0x10},
- {0x3635, 0x10},
- {0x3636, 0x10},
- {0x3663, 0x08},
- {0x3669, 0x34},
- {0x366d, 0x00},
- {0x366e, 0x10},
- {0x3706, 0x86},
- {0x370b, 0x7e},
- {0x3714, 0x23},
- {0x3730, 0x12},
- {0x3733, 0x10},
- {0x3764, 0x00},
- {0x3765, 0x00},
- {0x3769, 0x62},
- {0x376a, 0x2a},
- {0x376b, 0x30},
- {0x3780, 0x00},
- {0x3781, 0x24},
- {0x3782, 0x00},
- {0x3783, 0x23},
- {0x3798, 0x2f},
- {0x37a1, 0x60},
- {0x37a8, 0x6a},
- {0x37ab, 0x3f},
- {0x37c2, 0x04},
- {0x37c3, 0xf1},
- {0x37c9, 0x80},
- {0x37cb, 0x16},
- {0x37cc, 0x16},
- {0x37cd, 0x16},
- {0x37ce, 0x16},
- {0x3800, 0x00},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0x0c},
- {0x3804, 0x0c},
- {0x3805, 0xdf},
- {0x3806, 0x09},
- {0x3807, 0xa3},
- {0x3808, 0x0c},
- {0x3809, 0xc0},
- {0x380a, 0x09},
- {0x380b, 0x90},
- {0x380c, 0x07},
- {0x380d, 0x8c},
- {0x380e, 0x09},
- {0x380f, 0xb2},
- {0x3810, 0x00},
- {0x3811, 0x04},
- {0x3812, 0x00},
- {0x3813, 0x01},
- {0x3814, 0x01},
- {0x3815, 0x01},
- {0x3816, 0x00},
- {0x3817, 0x00},
- {0x3818, 0x00},
- {0x3819, 0x10},
- {0x3820, 0x80},
- {0x3821, 0x46},
- {0x382a, 0x01},
- {0x382b, 0x01},
- {0x3830, 0x06},
- {0x3836, 0x02},
- {0x3862, 0x04},
- {0x3863, 0x08},
- {0x3cc0, 0x33},
- {0x3d85, 0x17},
- {0x3d8c, 0x73},
- {0x3d8d, 0xde},
- {0x4001, 0xe0},
- {0x4003, 0x40},
- {0x4008, 0x00},
- {0x4009, 0x0b},
- {0x400a, 0x00},
- {0x400b, 0x84},
- {0x400f, 0x80},
- {0x4010, 0xf0},
- {0x4011, 0xff},
- {0x4012, 0x02},
- {0x4013, 0x01},
- {0x4014, 0x01},
- {0x4015, 0x01},
- {0x4042, 0x00},
- {0x4043, 0x80},
- {0x4044, 0x00},
- {0x4045, 0x80},
- {0x4046, 0x00},
- {0x4047, 0x80},
- {0x4048, 0x00},
- {0x4049, 0x80},
- {0x4041, 0x03},
- {0x404c, 0x20},
- {0x404d, 0x00},
- {0x404e, 0x20},
- {0x4203, 0x80},
- {0x4307, 0x30},
- {0x4317, 0x00},
- {0x4502, 0x50},
- {0x4503, 0x08},
- {0x4601, 0x80},
- {0x4800, 0x44},
- {0x4816, 0x53},
- {0x481b, 0x50},
- {0x481f, 0x27},
- {0x4823, 0x3c},
- {0x482b, 0x00},
- {0x4831, 0x66},
- {0x4837, 0x16},
- {0x483c, 0x0f},
- {0x484b, 0x05},
- {0x5000, 0x77},
- {0x5001, 0x0a},
- {0x5003, 0xc8},
- {0x5004, 0x04},
- {0x5006, 0x00},
- {0x5007, 0x00},
- {0x502e, 0x03},
- {0x5030, 0x41},
- {0x5780, 0x14},
- {0x5781, 0x0f},
- {0x5782, 0x44},
- {0x5783, 0x02},
- {0x5784, 0x01},
- {0x5785, 0x01},
- {0x5786, 0x00},
- {0x5787, 0x04},
- {0x5788, 0x02},
- {0x5789, 0x0f},
- {0x578a, 0xfd},
- {0x578b, 0xf5},
- {0x578c, 0xf5},
- {0x578d, 0x03},
- {0x578e, 0x08},
- {0x578f, 0x0c},
- {0x5790, 0x08},
- {0x5791, 0x04},
- {0x5792, 0x00},
- {0x5793, 0x52},
- {0x5794, 0xa3},
- {0x5795, 0x02},
- {0x5796, 0x20},
- {0x5797, 0x20},
- {0x5798, 0xd5},
- {0x5799, 0xd5},
- {0x579a, 0x00},
- {0x579b, 0x50},
- {0x579c, 0x00},
- {0x579d, 0x2c},
- {0x579e, 0x0c},
- {0x579f, 0x40},
- {0x57a0, 0x09},
- {0x57a1, 0x40},
- {0x59f8, 0x3d},
- {0x5a08, 0x02},
- {0x5b00, 0x02},
- {0x5b01, 0x10},
- {0x5b02, 0x03},
- {0x5b03, 0xcf},
- {0x5b05, 0x6c},
- {0x5e00, 0x00},
- {0x5e10, 0xfc}
+static const struct ov8856_reg lane_2_mode_3280x2464[] = {
+ /* 3280x2464 resolution */
+ {0x3000, 0x20},
+ {0x3003, 0x08},
+ {0x300e, 0x20},
+ {0x3010, 0x00},
+ {0x3015, 0x84},
+ {0x3018, 0x32},
+ {0x3021, 0x23},
+ {0x3033, 0x24},
+ {0x3500, 0x00},
+ {0x3501, 0x9a},
+ {0x3502, 0x20},
+ {0x3503, 0x08},
+ {0x3505, 0x83},
+ {0x3508, 0x01},
+ {0x3509, 0x80},
+ {0x350c, 0x00},
+ {0x350d, 0x80},
+ {0x350e, 0x04},
+ {0x350f, 0x00},
+ {0x3510, 0x00},
+ {0x3511, 0x02},
+ {0x3512, 0x00},
+ {0x3600, 0x72},
+ {0x3601, 0x40},
+ {0x3602, 0x30},
+ {0x3610, 0xc5},
+ {0x3611, 0x58},
+ {0x3612, 0x5c},
+ {0x3613, 0xca},
+ {0x3614, 0x50},
+ {0x3628, 0xff},
+ {0x3629, 0xff},
+ {0x362a, 0xff},
+ {0x3633, 0x10},
+ {0x3634, 0x10},
+ {0x3635, 0x10},
+ {0x3636, 0x10},
+ {0x3663, 0x08},
+ {0x3669, 0x34},
+ {0x366e, 0x10},
+ {0x3706, 0x86},
+ {0x370b, 0x7e},
+ {0x3714, 0x23},
+ {0x3730, 0x12},
+ {0x3733, 0x10},
+ {0x3764, 0x00},
+ {0x3765, 0x00},
+ {0x3769, 0x62},
+ {0x376a, 0x2a},
+ {0x376b, 0x30},
+ {0x3780, 0x00},
+ {0x3781, 0x24},
+ {0x3782, 0x00},
+ {0x3783, 0x23},
+ {0x3798, 0x2f},
+ {0x37a1, 0x60},
+ {0x37a8, 0x6a},
+ {0x37ab, 0x3f},
+ {0x37c2, 0x04},
+ {0x37c3, 0xf1},
+ {0x37c9, 0x80},
+ {0x37cb, 0x16},
+ {0x37cc, 0x16},
+ {0x37cd, 0x16},
+ {0x37ce, 0x16},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x06},
+ {0x3804, 0x0c},
+ {0x3805, 0xdf},
+ {0x3806, 0x09},
+ {0x3807, 0xa7},
+ {0x3808, 0x0c},
+ {0x3809, 0xd0},
+ {0x380a, 0x09},
+ {0x380b, 0xa0},
+ {0x380c, 0x07},
+ {0x380d, 0x88},
+ {0x380e, 0x09},
+ {0x380f, 0xb8},
+ {0x3810, 0x00},
+ {0x3811, 0x00},
+ {0x3812, 0x00},
+ {0x3813, 0x01},
+ {0x3814, 0x01},
+ {0x3815, 0x01},
+ {0x3816, 0x00},
+ {0x3817, 0x00},
+ {0x3818, 0x00},
+ {0x3819, 0x00},
+ {0x3820, 0x80},
+ {0x3821, 0x46},
+ {0x382a, 0x01},
+ {0x382b, 0x01},
+ {0x3830, 0x06},
+ {0x3836, 0x02},
+ {0x3837, 0x10},
+ {0x3862, 0x04},
+ {0x3863, 0x08},
+ {0x3cc0, 0x33},
+ {0x3d85, 0x14},
+ {0x3d8c, 0x73},
+ {0x3d8d, 0xde},
+ {0x4001, 0xe0},
+ {0x4003, 0x40},
+ {0x4008, 0x00},
+ {0x4009, 0x0b},
+ {0x400a, 0x00},
+ {0x400b, 0x84},
+ {0x400f, 0x80},
+ {0x4010, 0xf0},
+ {0x4011, 0xff},
+ {0x4012, 0x02},
+ {0x4013, 0x01},
+ {0x4014, 0x01},
+ {0x4015, 0x01},
+ {0x4042, 0x00},
+ {0x4043, 0x80},
+ {0x4044, 0x00},
+ {0x4045, 0x80},
+ {0x4046, 0x00},
+ {0x4047, 0x80},
+ {0x4048, 0x00},
+ {0x4049, 0x80},
+ {0x4041, 0x03},
+ {0x404c, 0x20},
+ {0x404d, 0x00},
+ {0x404e, 0x20},
+ {0x4203, 0x80},
+ {0x4307, 0x30},
+ {0x4317, 0x00},
+ {0x4503, 0x08},
+ {0x4601, 0x80},
+ {0x4800, 0x44},
+ {0x4816, 0x53},
+ {0x481b, 0x58},
+ {0x481f, 0x27},
+ {0x4837, 0x0c},
+ {0x483c, 0x0f},
+ {0x484b, 0x05},
+ {0x5000, 0x57},
+ {0x5001, 0x0a},
+ {0x5004, 0x04},
+ {0x502e, 0x03},
+ {0x5030, 0x41},
+ {0x5795, 0x02},
+ {0x5796, 0x20},
+ {0x5797, 0x20},
+ {0x5798, 0xd5},
+ {0x5799, 0xd5},
+ {0x579a, 0x00},
+ {0x579b, 0x50},
+ {0x579c, 0x00},
+ {0x579d, 0x2c},
+ {0x579e, 0x0c},
+ {0x579f, 0x40},
+ {0x57a0, 0x09},
+ {0x57a1, 0x40},
+ {0x5780, 0x14},
+ {0x5781, 0x0f},
+ {0x5782, 0x44},
+ {0x5783, 0x02},
+ {0x5784, 0x01},
+ {0x5785, 0x01},
+ {0x5786, 0x00},
+ {0x5787, 0x04},
+ {0x5788, 0x02},
+ {0x5789, 0x0f},
+ {0x578a, 0xfd},
+ {0x578b, 0xf5},
+ {0x578c, 0xf5},
+ {0x578d, 0x03},
+ {0x578e, 0x08},
+ {0x578f, 0x0c},
+ {0x5790, 0x08},
+ {0x5791, 0x04},
+ {0x5792, 0x00},
+ {0x5793, 0x52},
+ {0x5794, 0xa3},
+ {0x59f8, 0x3d},
+ {0x5a08, 0x02},
+ {0x5b00, 0x02},
+ {0x5b01, 0x10},
+ {0x5b02, 0x03},
+ {0x5b03, 0xcf},
+ {0x5b05, 0x6c},
+ {0x5e00, 0x00}
};
-static const struct ov8856_reg mode_1640x1232_regs[] = {
- {0x3000, 0x20},
- {0x3003, 0x08},
- {0x300e, 0x20},
- {0x3010, 0x00},
- {0x3015, 0x84},
- {0x3018, 0x72},
- {0x3021, 0x23},
- {0x3033, 0x24},
- {0x3500, 0x00},
- {0x3501, 0x4c},
- {0x3502, 0xe0},
- {0x3503, 0x08},
- {0x3505, 0x83},
- {0x3508, 0x01},
- {0x3509, 0x80},
- {0x350c, 0x00},
- {0x350d, 0x80},
- {0x350e, 0x04},
- {0x350f, 0x00},
- {0x3510, 0x00},
- {0x3511, 0x02},
- {0x3512, 0x00},
- {0x3600, 0x72},
- {0x3601, 0x40},
- {0x3602, 0x30},
- {0x3610, 0xc5},
- {0x3611, 0x58},
- {0x3612, 0x5c},
- {0x3613, 0xca},
- {0x3614, 0x20},
- {0x3628, 0xff},
- {0x3629, 0xff},
- {0x362a, 0xff},
- {0x3633, 0x10},
- {0x3634, 0x10},
- {0x3635, 0x10},
- {0x3636, 0x10},
- {0x3663, 0x08},
- {0x3669, 0x34},
- {0x366e, 0x08},
- {0x3706, 0x86},
- {0x370b, 0x7e},
- {0x3714, 0x27},
- {0x3730, 0x12},
- {0x3733, 0x10},
- {0x3764, 0x00},
- {0x3765, 0x00},
- {0x3769, 0x62},
- {0x376a, 0x2a},
- {0x376b, 0x30},
- {0x3780, 0x00},
- {0x3781, 0x24},
- {0x3782, 0x00},
- {0x3783, 0x23},
- {0x3798, 0x2f},
- {0x37a1, 0x60},
- {0x37a8, 0x6a},
- {0x37ab, 0x3f},
- {0x37c2, 0x14},
- {0x37c3, 0xf1},
- {0x37c9, 0x80},
- {0x37cb, 0x16},
- {0x37cc, 0x16},
- {0x37cd, 0x16},
- {0x37ce, 0x16},
- {0x3800, 0x00},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0x06},
- {0x3804, 0x0c},
- {0x3805, 0xdf},
- {0x3806, 0x09},
- {0x3807, 0xa7},
- {0x3808, 0x06},
- {0x3809, 0x68},
- {0x380a, 0x04},
- {0x380b, 0xd0},
- {0x380c, 0x0e},
- {0x380d, 0xec},
- {0x380e, 0x04},
- {0x380f, 0xe8},
- {0x3810, 0x00},
- {0x3811, 0x00},
- {0x3812, 0x00},
- {0x3813, 0x01},
- {0x3814, 0x03},
- {0x3815, 0x01},
- {0x3816, 0x00},
- {0x3817, 0x00},
- {0x3818, 0x00},
- {0x3819, 0x10},
- {0x3820, 0x90},
- {0x3821, 0x67},
- {0x382a, 0x03},
- {0x382b, 0x01},
- {0x3830, 0x06},
- {0x3836, 0x02},
- {0x3862, 0x04},
- {0x3863, 0x08},
- {0x3cc0, 0x33},
- {0x3d85, 0x17},
- {0x3d8c, 0x73},
- {0x3d8d, 0xde},
- {0x4001, 0xe0},
- {0x4003, 0x40},
- {0x4008, 0x00},
- {0x4009, 0x05},
- {0x400a, 0x00},
- {0x400b, 0x84},
- {0x400f, 0x80},
- {0x4010, 0xf0},
- {0x4011, 0xff},
- {0x4012, 0x02},
- {0x4013, 0x01},
- {0x4014, 0x01},
- {0x4015, 0x01},
- {0x4042, 0x00},
- {0x4043, 0x80},
- {0x4044, 0x00},
- {0x4045, 0x80},
- {0x4046, 0x00},
- {0x4047, 0x80},
- {0x4048, 0x00},
- {0x4049, 0x80},
- {0x4041, 0x03},
- {0x404c, 0x20},
- {0x404d, 0x00},
- {0x404e, 0x20},
- {0x4203, 0x80},
- {0x4307, 0x30},
- {0x4317, 0x00},
- {0x4503, 0x08},
- {0x4601, 0x80},
- {0x4800, 0x44},
- {0x4816, 0x53},
- {0x481b, 0x58},
- {0x481f, 0x27},
- {0x4837, 0x16},
- {0x483c, 0x0f},
- {0x484b, 0x05},
- {0x5000, 0x57},
- {0x5001, 0x0a},
- {0x5004, 0x04},
- {0x502e, 0x03},
- {0x5030, 0x41},
- {0x5780, 0x14},
- {0x5781, 0x0f},
- {0x5782, 0x44},
- {0x5783, 0x02},
- {0x5784, 0x01},
- {0x5785, 0x01},
- {0x5786, 0x00},
- {0x5787, 0x04},
- {0x5788, 0x02},
- {0x5789, 0x0f},
- {0x578a, 0xfd},
- {0x578b, 0xf5},
- {0x578c, 0xf5},
- {0x578d, 0x03},
- {0x578e, 0x08},
- {0x578f, 0x0c},
- {0x5790, 0x08},
- {0x5791, 0x04},
- {0x5792, 0x00},
- {0x5793, 0x52},
- {0x5794, 0xa3},
- {0x5795, 0x00},
- {0x5796, 0x10},
- {0x5797, 0x10},
- {0x5798, 0x73},
- {0x5799, 0x73},
- {0x579a, 0x00},
- {0x579b, 0x28},
- {0x579c, 0x00},
- {0x579d, 0x16},
- {0x579e, 0x06},
- {0x579f, 0x20},
- {0x57a0, 0x04},
- {0x57a1, 0xa0},
- {0x59f8, 0x3d},
- {0x5a08, 0x02},
- {0x5b00, 0x02},
- {0x5b01, 0x10},
- {0x5b02, 0x03},
- {0x5b03, 0xcf},
- {0x5b05, 0x6c},
- {0x5e00, 0x00}
+static const struct ov8856_reg lane_2_mode_1640x1232[] = {
+ /* 1640x1232 resolution */
+ {0x3000, 0x20},
+ {0x3003, 0x08},
+ {0x300e, 0x20},
+ {0x3010, 0x00},
+ {0x3015, 0x84},
+ {0x3018, 0x32},
+ {0x3021, 0x23},
+ {0x3033, 0x24},
+ {0x3500, 0x00},
+ {0x3501, 0x4c},
+ {0x3502, 0xe0},
+ {0x3503, 0x08},
+ {0x3505, 0x83},
+ {0x3508, 0x01},
+ {0x3509, 0x80},
+ {0x350c, 0x00},
+ {0x350d, 0x80},
+ {0x350e, 0x04},
+ {0x350f, 0x00},
+ {0x3510, 0x00},
+ {0x3511, 0x02},
+ {0x3512, 0x00},
+ {0x3600, 0x72},
+ {0x3601, 0x40},
+ {0x3602, 0x30},
+ {0x3610, 0xc5},
+ {0x3611, 0x58},
+ {0x3612, 0x5c},
+ {0x3613, 0xca},
+ {0x3614, 0x50},
+ {0x3628, 0xff},
+ {0x3629, 0xff},
+ {0x362a, 0xff},
+ {0x3633, 0x10},
+ {0x3634, 0x10},
+ {0x3635, 0x10},
+ {0x3636, 0x10},
+ {0x3663, 0x08},
+ {0x3669, 0x34},
+ {0x366e, 0x08},
+ {0x3706, 0x86},
+ {0x370b, 0x7e},
+ {0x3714, 0x27},
+ {0x3730, 0x12},
+ {0x3733, 0x10},
+ {0x3764, 0x00},
+ {0x3765, 0x00},
+ {0x3769, 0x62},
+ {0x376a, 0x2a},
+ {0x376b, 0x30},
+ {0x3780, 0x00},
+ {0x3781, 0x24},
+ {0x3782, 0x00},
+ {0x3783, 0x23},
+ {0x3798, 0x2f},
+ {0x37a1, 0x60},
+ {0x37a8, 0x6a},
+ {0x37ab, 0x3f},
+ {0x37c2, 0x14},
+ {0x37c3, 0xf1},
+ {0x37c9, 0x80},
+ {0x37cb, 0x16},
+ {0x37cc, 0x16},
+ {0x37cd, 0x16},
+ {0x37ce, 0x16},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0c},
+ {0x3805, 0xdf},
+ {0x3806, 0x09},
+ {0x3807, 0xaf},
+ {0x3808, 0x06},
+ {0x3809, 0x68},
+ {0x380a, 0x04},
+ {0x380b, 0xd0},
+ {0x380c, 0x0c},
+ {0x380d, 0x60},
+ {0x380e, 0x05},
+ {0x380f, 0xea},
+ {0x3810, 0x00},
+ {0x3811, 0x04},
+ {0x3812, 0x00},
+ {0x3813, 0x05},
+ {0x3814, 0x03},
+ {0x3815, 0x01},
+ {0x3816, 0x00},
+ {0x3817, 0x00},
+ {0x3818, 0x00},
+ {0x3819, 0x00},
+ {0x3820, 0x90},
+ {0x3821, 0x67},
+ {0x382a, 0x03},
+ {0x382b, 0x01},
+ {0x3830, 0x06},
+ {0x3836, 0x02},
+ {0x3837, 0x10},
+ {0x3862, 0x04},
+ {0x3863, 0x08},
+ {0x3cc0, 0x33},
+ {0x3d85, 0x14},
+ {0x3d8c, 0x73},
+ {0x3d8d, 0xde},
+ {0x4001, 0xe0},
+ {0x4003, 0x40},
+ {0x4008, 0x00},
+ {0x4009, 0x05},
+ {0x400a, 0x00},
+ {0x400b, 0x84},
+ {0x400f, 0x80},
+ {0x4010, 0xf0},
+ {0x4011, 0xff},
+ {0x4012, 0x02},
+ {0x4013, 0x01},
+ {0x4014, 0x01},
+ {0x4015, 0x01},
+ {0x4042, 0x00},
+ {0x4043, 0x80},
+ {0x4044, 0x00},
+ {0x4045, 0x80},
+ {0x4046, 0x00},
+ {0x4047, 0x80},
+ {0x4048, 0x00},
+ {0x4049, 0x80},
+ {0x4041, 0x03},
+ {0x404c, 0x20},
+ {0x404d, 0x00},
+ {0x404e, 0x20},
+ {0x4203, 0x80},
+ {0x4307, 0x30},
+ {0x4317, 0x00},
+ {0x4503, 0x08},
+ {0x4601, 0x80},
+ {0x4800, 0x44},
+ {0x4816, 0x53},
+ {0x481b, 0x58},
+ {0x481f, 0x27},
+ {0x4837, 0x16},
+ {0x483c, 0x0f},
+ {0x484b, 0x05},
+ {0x5000, 0x57},
+ {0x5001, 0x0a},
+ {0x5004, 0x04},
+ {0x502e, 0x03},
+ {0x5030, 0x41},
+ {0x5795, 0x00},
+ {0x5796, 0x10},
+ {0x5797, 0x10},
+ {0x5798, 0x73},
+ {0x5799, 0x73},
+ {0x579a, 0x00},
+ {0x579b, 0x28},
+ {0x579c, 0x00},
+ {0x579d, 0x16},
+ {0x579e, 0x06},
+ {0x579f, 0x20},
+ {0x57a0, 0x04},
+ {0x57a1, 0xa0},
+ {0x5780, 0x14},
+ {0x5781, 0x0f},
+ {0x5782, 0x44},
+ {0x5783, 0x02},
+ {0x5784, 0x01},
+ {0x5785, 0x01},
+ {0x5786, 0x00},
+ {0x5787, 0x04},
+ {0x5788, 0x02},
+ {0x5789, 0x0f},
+ {0x578a, 0xfd},
+ {0x578b, 0xf5},
+ {0x578c, 0xf5},
+ {0x578d, 0x03},
+ {0x578e, 0x08},
+ {0x578f, 0x0c},
+ {0x5790, 0x08},
+ {0x5791, 0x04},
+ {0x5792, 0x00},
+ {0x5793, 0x52},
+ {0x5794, 0xa3},
+ {0x59f8, 0x3d},
+ {0x5a08, 0x02},
+ {0x5b00, 0x02},
+ {0x5b01, 0x10},
+ {0x5b02, 0x03},
+ {0x5b03, 0xcf},
+ {0x5b05, 0x6c},
+ {0x5e00, 0x00}
};
-static const struct ov8856_reg mode_1632x1224_regs[] = {
- {0x0103, 0x01},
- {0x0302, 0x3c},
- {0x0303, 0x01},
- {0x031e, 0x0c},
- {0x3000, 0x20},
- {0x3003, 0x08},
- {0x300e, 0x20},
- {0x3010, 0x00},
- {0x3015, 0x84},
- {0x3018, 0x72},
- {0x3021, 0x23},
- {0x3033, 0x24},
- {0x3500, 0x00},
- {0x3501, 0x4c},
- {0x3502, 0xe0},
- {0x3503, 0x08},
- {0x3505, 0x83},
- {0x3508, 0x01},
- {0x3509, 0x80},
- {0x350c, 0x00},
- {0x350d, 0x80},
- {0x350e, 0x04},
- {0x350f, 0x00},
- {0x3510, 0x00},
- {0x3511, 0x02},
- {0x3512, 0x00},
- {0x3600, 0x72},
- {0x3601, 0x40},
- {0x3602, 0x30},
- {0x3610, 0xc5},
- {0x3611, 0x58},
- {0x3612, 0x5c},
- {0x3613, 0xca},
- {0x3614, 0x60},
- {0x3628, 0xff},
- {0x3629, 0xff},
- {0x362a, 0xff},
- {0x3633, 0x10},
- {0x3634, 0x10},
- {0x3635, 0x10},
- {0x3636, 0x10},
- {0x3663, 0x08},
- {0x3669, 0x34},
- {0x366d, 0x00},
- {0x366e, 0x08},
- {0x3706, 0x86},
- {0x370b, 0x7e},
- {0x3714, 0x27},
- {0x3730, 0x12},
- {0x3733, 0x10},
- {0x3764, 0x00},
- {0x3765, 0x00},
- {0x3769, 0x62},
- {0x376a, 0x2a},
- {0x376b, 0x30},
- {0x3780, 0x00},
- {0x3781, 0x24},
- {0x3782, 0x00},
- {0x3783, 0x23},
- {0x3798, 0x2f},
- {0x37a1, 0x60},
- {0x37a8, 0x6a},
- {0x37ab, 0x3f},
- {0x37c2, 0x14},
- {0x37c3, 0xf1},
- {0x37c9, 0x80},
- {0x37cb, 0x16},
- {0x37cc, 0x16},
- {0x37cd, 0x16},
- {0x37ce, 0x16},
- {0x3800, 0x00},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0x0c},
- {0x3804, 0x0c},
- {0x3805, 0xdf},
- {0x3806, 0x09},
- {0x3807, 0xa3},
- {0x3808, 0x06},
- {0x3809, 0x60},
- {0x380a, 0x04},
- {0x380b, 0xc8},
- {0x380c, 0x07},
- {0x380d, 0x8c},
- {0x380e, 0x09},
- {0x380f, 0xb2},
- {0x3810, 0x00},
- {0x3811, 0x02},
- {0x3812, 0x00},
- {0x3813, 0x01},
- {0x3814, 0x03},
- {0x3815, 0x01},
- {0x3816, 0x00},
- {0x3817, 0x00},
- {0x3818, 0x00},
- {0x3819, 0x10},
- {0x3820, 0x80},
- {0x3821, 0x47},
- {0x382a, 0x03},
- {0x382b, 0x01},
- {0x3830, 0x06},
- {0x3836, 0x02},
- {0x3862, 0x04},
- {0x3863, 0x08},
- {0x3cc0, 0x33},
- {0x3d85, 0x17},
- {0x3d8c, 0x73},
- {0x3d8d, 0xde},
- {0x4001, 0xe0},
- {0x4003, 0x40},
- {0x4008, 0x00},
- {0x4009, 0x05},
- {0x400a, 0x00},
- {0x400b, 0x84},
- {0x400f, 0x80},
- {0x4010, 0xf0},
- {0x4011, 0xff},
- {0x4012, 0x02},
- {0x4013, 0x01},
- {0x4014, 0x01},
- {0x4015, 0x01},
- {0x4042, 0x00},
- {0x4043, 0x80},
- {0x4044, 0x00},
- {0x4045, 0x80},
- {0x4046, 0x00},
- {0x4047, 0x80},
- {0x4048, 0x00},
- {0x4049, 0x80},
- {0x4041, 0x03},
- {0x404c, 0x20},
- {0x404d, 0x00},
- {0x404e, 0x20},
- {0x4203, 0x80},
- {0x4307, 0x30},
- {0x4317, 0x00},
- {0x4502, 0x50},
- {0x4503, 0x08},
- {0x4601, 0x80},
- {0x4800, 0x44},
- {0x4816, 0x53},
- {0x481b, 0x50},
- {0x481f, 0x27},
- {0x4823, 0x3c},
- {0x482b, 0x00},
- {0x4831, 0x66},
- {0x4837, 0x16},
- {0x483c, 0x0f},
- {0x484b, 0x05},
- {0x5000, 0x77},
- {0x5001, 0x0a},
- {0x5003, 0xc8},
- {0x5004, 0x04},
- {0x5006, 0x00},
- {0x5007, 0x00},
- {0x502e, 0x03},
- {0x5030, 0x41},
- {0x5795, 0x00},
- {0x5796, 0x10},
- {0x5797, 0x10},
- {0x5798, 0x73},
- {0x5799, 0x73},
- {0x579a, 0x00},
- {0x579b, 0x28},
- {0x579c, 0x00},
- {0x579d, 0x16},
- {0x579e, 0x06},
- {0x579f, 0x20},
- {0x57a0, 0x04},
- {0x57a1, 0xa0},
- {0x5780, 0x14},
- {0x5781, 0x0f},
- {0x5782, 0x44},
- {0x5783, 0x02},
- {0x5784, 0x01},
- {0x5785, 0x01},
- {0x5786, 0x00},
- {0x5787, 0x04},
- {0x5788, 0x02},
- {0x5789, 0x0f},
- {0x578a, 0xfd},
- {0x578b, 0xf5},
- {0x578c, 0xf5},
- {0x578d, 0x03},
- {0x578e, 0x08},
- {0x578f, 0x0c},
- {0x5790, 0x08},
- {0x5791, 0x04},
- {0x5792, 0x00},
- {0x5793, 0x52},
- {0x5794, 0xa3},
- {0x59f8, 0x3d},
- {0x5a08, 0x02},
- {0x5b00, 0x02},
- {0x5b01, 0x10},
- {0x5b02, 0x03},
- {0x5b03, 0xcf},
- {0x5b05, 0x6c},
- {0x5e00, 0x00},
- {0x5e10, 0xfc}
+static const struct ov8856_reg lane_4_mode_3280x2464[] = {
+ /* 3280x2464 resolution */
+ {0x3000, 0x20},
+ {0x3003, 0x08},
+ {0x300e, 0x20},
+ {0x3010, 0x00},
+ {0x3015, 0x84},
+ {0x3018, 0x72},
+ {0x3021, 0x23},
+ {0x3033, 0x24},
+ {0x3500, 0x00},
+ {0x3501, 0x9a},
+ {0x3502, 0x20},
+ {0x3503, 0x08},
+ {0x3505, 0x83},
+ {0x3508, 0x01},
+ {0x3509, 0x80},
+ {0x350c, 0x00},
+ {0x350d, 0x80},
+ {0x350e, 0x04},
+ {0x350f, 0x00},
+ {0x3510, 0x00},
+ {0x3511, 0x02},
+ {0x3512, 0x00},
+ {0x3600, 0x72},
+ {0x3601, 0x40},
+ {0x3602, 0x30},
+ {0x3610, 0xc5},
+ {0x3611, 0x58},
+ {0x3612, 0x5c},
+ {0x3613, 0xca},
+ {0x3614, 0x20},
+ {0x3628, 0xff},
+ {0x3629, 0xff},
+ {0x362a, 0xff},
+ {0x3633, 0x10},
+ {0x3634, 0x10},
+ {0x3635, 0x10},
+ {0x3636, 0x10},
+ {0x3663, 0x08},
+ {0x3669, 0x34},
+ {0x366e, 0x10},
+ {0x3706, 0x86},
+ {0x370b, 0x7e},
+ {0x3714, 0x23},
+ {0x3730, 0x12},
+ {0x3733, 0x10},
+ {0x3764, 0x00},
+ {0x3765, 0x00},
+ {0x3769, 0x62},
+ {0x376a, 0x2a},
+ {0x376b, 0x30},
+ {0x3780, 0x00},
+ {0x3781, 0x24},
+ {0x3782, 0x00},
+ {0x3783, 0x23},
+ {0x3798, 0x2f},
+ {0x37a1, 0x60},
+ {0x37a8, 0x6a},
+ {0x37ab, 0x3f},
+ {0x37c2, 0x04},
+ {0x37c3, 0xf1},
+ {0x37c9, 0x80},
+ {0x37cb, 0x16},
+ {0x37cc, 0x16},
+ {0x37cd, 0x16},
+ {0x37ce, 0x16},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x06},
+ {0x3804, 0x0c},
+ {0x3805, 0xdf},
+ {0x3806, 0x09},
+ {0x3807, 0xa7},
+ {0x3808, 0x0c},
+ {0x3809, 0xd0},
+ {0x380a, 0x09},
+ {0x380b, 0xa0},
+ {0x380c, 0x07},
+ {0x380d, 0x88},
+ {0x380e, 0x09},
+ {0x380f, 0xb8},
+ {0x3810, 0x00},
+ {0x3811, 0x00},
+ {0x3812, 0x00},
+ {0x3813, 0x01},
+ {0x3814, 0x01},
+ {0x3815, 0x01},
+ {0x3816, 0x00},
+ {0x3817, 0x00},
+ {0x3818, 0x00},
+ {0x3819, 0x10},
+ {0x3820, 0x80},
+ {0x3821, 0x46},
+ {0x382a, 0x01},
+ {0x382b, 0x01},
+ {0x3830, 0x06},
+ {0x3836, 0x02},
+ {0x3862, 0x04},
+ {0x3863, 0x08},
+ {0x3cc0, 0x33},
+ {0x3d85, 0x17},
+ {0x3d8c, 0x73},
+ {0x3d8d, 0xde},
+ {0x4001, 0xe0},
+ {0x4003, 0x40},
+ {0x4008, 0x00},
+ {0x4009, 0x0b},
+ {0x400a, 0x00},
+ {0x400b, 0x84},
+ {0x400f, 0x80},
+ {0x4010, 0xf0},
+ {0x4011, 0xff},
+ {0x4012, 0x02},
+ {0x4013, 0x01},
+ {0x4014, 0x01},
+ {0x4015, 0x01},
+ {0x4042, 0x00},
+ {0x4043, 0x80},
+ {0x4044, 0x00},
+ {0x4045, 0x80},
+ {0x4046, 0x00},
+ {0x4047, 0x80},
+ {0x4048, 0x00},
+ {0x4049, 0x80},
+ {0x4041, 0x03},
+ {0x404c, 0x20},
+ {0x404d, 0x00},
+ {0x404e, 0x20},
+ {0x4203, 0x80},
+ {0x4307, 0x30},
+ {0x4317, 0x00},
+ {0x4503, 0x08},
+ {0x4601, 0x80},
+ {0x4800, 0x44},
+ {0x4816, 0x53},
+ {0x481b, 0x58},
+ {0x481f, 0x27},
+ {0x4837, 0x16},
+ {0x483c, 0x0f},
+ {0x484b, 0x05},
+ {0x5000, 0x57},
+ {0x5001, 0x0a},
+ {0x5004, 0x04},
+ {0x502e, 0x03},
+ {0x5030, 0x41},
+ {0x5780, 0x14},
+ {0x5781, 0x0f},
+ {0x5782, 0x44},
+ {0x5783, 0x02},
+ {0x5784, 0x01},
+ {0x5785, 0x01},
+ {0x5786, 0x00},
+ {0x5787, 0x04},
+ {0x5788, 0x02},
+ {0x5789, 0x0f},
+ {0x578a, 0xfd},
+ {0x578b, 0xf5},
+ {0x578c, 0xf5},
+ {0x578d, 0x03},
+ {0x578e, 0x08},
+ {0x578f, 0x0c},
+ {0x5790, 0x08},
+ {0x5791, 0x04},
+ {0x5792, 0x00},
+ {0x5793, 0x52},
+ {0x5794, 0xa3},
+ {0x5795, 0x02},
+ {0x5796, 0x20},
+ {0x5797, 0x20},
+ {0x5798, 0xd5},
+ {0x5799, 0xd5},
+ {0x579a, 0x00},
+ {0x579b, 0x50},
+ {0x579c, 0x00},
+ {0x579d, 0x2c},
+ {0x579e, 0x0c},
+ {0x579f, 0x40},
+ {0x57a0, 0x09},
+ {0x57a1, 0x40},
+ {0x59f8, 0x3d},
+ {0x5a08, 0x02},
+ {0x5b00, 0x02},
+ {0x5b01, 0x10},
+ {0x5b02, 0x03},
+ {0x5b03, 0xcf},
+ {0x5b05, 0x6c},
+ {0x5e00, 0x00}
};
-static const char * const ov8856_test_pattern_menu[] = {
- "Disabled",
- "Standard Color Bar",
- "Top-Bottom Darker Color Bar",
- "Right-Left Darker Color Bar",
- "Bottom-Top Darker Color Bar"
+static const struct ov8856_reg lane_4_mode_1640x1232[] = {
+ /* 1640x1232 resolution */
+ {0x3000, 0x20},
+ {0x3003, 0x08},
+ {0x300e, 0x20},
+ {0x3010, 0x00},
+ {0x3015, 0x84},
+ {0x3018, 0x72},
+ {0x3021, 0x23},
+ {0x3033, 0x24},
+ {0x3500, 0x00},
+ {0x3501, 0x4c},
+ {0x3502, 0xe0},
+ {0x3503, 0x08},
+ {0x3505, 0x83},
+ {0x3508, 0x01},
+ {0x3509, 0x80},
+ {0x350c, 0x00},
+ {0x350d, 0x80},
+ {0x350e, 0x04},
+ {0x350f, 0x00},
+ {0x3510, 0x00},
+ {0x3511, 0x02},
+ {0x3512, 0x00},
+ {0x3600, 0x72},
+ {0x3601, 0x40},
+ {0x3602, 0x30},
+ {0x3610, 0xc5},
+ {0x3611, 0x58},
+ {0x3612, 0x5c},
+ {0x3613, 0xca},
+ {0x3614, 0x20},
+ {0x3628, 0xff},
+ {0x3629, 0xff},
+ {0x362a, 0xff},
+ {0x3633, 0x10},
+ {0x3634, 0x10},
+ {0x3635, 0x10},
+ {0x3636, 0x10},
+ {0x3663, 0x08},
+ {0x3669, 0x34},
+ {0x366e, 0x08},
+ {0x3706, 0x86},
+ {0x370b, 0x7e},
+ {0x3714, 0x27},
+ {0x3730, 0x12},
+ {0x3733, 0x10},
+ {0x3764, 0x00},
+ {0x3765, 0x00},
+ {0x3769, 0x62},
+ {0x376a, 0x2a},
+ {0x376b, 0x30},
+ {0x3780, 0x00},
+ {0x3781, 0x24},
+ {0x3782, 0x00},
+ {0x3783, 0x23},
+ {0x3798, 0x2f},
+ {0x37a1, 0x60},
+ {0x37a8, 0x6a},
+ {0x37ab, 0x3f},
+ {0x37c2, 0x14},
+ {0x37c3, 0xf1},
+ {0x37c9, 0x80},
+ {0x37cb, 0x16},
+ {0x37cc, 0x16},
+ {0x37cd, 0x16},
+ {0x37ce, 0x16},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0c},
+ {0x3805, 0xdf},
+ {0x3806, 0x09},
+ {0x3807, 0xaf},
+ {0x3808, 0x06},
+ {0x3809, 0x68},
+ {0x380a, 0x04},
+ {0x380b, 0xd0},
+ {0x380c, 0x0e},
+ {0x380d, 0xec},
+ {0x380e, 0x04},
+ {0x380f, 0xe8},
+ {0x3810, 0x00},
+ {0x3811, 0x04},
+ {0x3812, 0x00},
+ {0x3813, 0x05},
+ {0x3814, 0x03},
+ {0x3815, 0x01},
+ {0x3816, 0x00},
+ {0x3817, 0x00},
+ {0x3818, 0x00},
+ {0x3819, 0x10},
+ {0x3820, 0x90},
+ {0x3821, 0x67},
+ {0x382a, 0x03},
+ {0x382b, 0x01},
+ {0x3830, 0x06},
+ {0x3836, 0x02},
+ {0x3862, 0x04},
+ {0x3863, 0x08},
+ {0x3cc0, 0x33},
+ {0x3d85, 0x17},
+ {0x3d8c, 0x73},
+ {0x3d8d, 0xde},
+ {0x4001, 0xe0},
+ {0x4003, 0x40},
+ {0x4008, 0x00},
+ {0x4009, 0x05},
+ {0x400a, 0x00},
+ {0x400b, 0x84},
+ {0x400f, 0x80},
+ {0x4010, 0xf0},
+ {0x4011, 0xff},
+ {0x4012, 0x02},
+ {0x4013, 0x01},
+ {0x4014, 0x01},
+ {0x4015, 0x01},
+ {0x4042, 0x00},
+ {0x4043, 0x80},
+ {0x4044, 0x00},
+ {0x4045, 0x80},
+ {0x4046, 0x00},
+ {0x4047, 0x80},
+ {0x4048, 0x00},
+ {0x4049, 0x80},
+ {0x4041, 0x03},
+ {0x404c, 0x20},
+ {0x404d, 0x00},
+ {0x404e, 0x20},
+ {0x4203, 0x80},
+ {0x4307, 0x30},
+ {0x4317, 0x00},
+ {0x4503, 0x08},
+ {0x4601, 0x80},
+ {0x4800, 0x44},
+ {0x4816, 0x53},
+ {0x481b, 0x58},
+ {0x481f, 0x27},
+ {0x4837, 0x16},
+ {0x483c, 0x0f},
+ {0x484b, 0x05},
+ {0x5000, 0x57},
+ {0x5001, 0x0a},
+ {0x5004, 0x04},
+ {0x502e, 0x03},
+ {0x5030, 0x41},
+ {0x5780, 0x14},
+ {0x5781, 0x0f},
+ {0x5782, 0x44},
+ {0x5783, 0x02},
+ {0x5784, 0x01},
+ {0x5785, 0x01},
+ {0x5786, 0x00},
+ {0x5787, 0x04},
+ {0x5788, 0x02},
+ {0x5789, 0x0f},
+ {0x578a, 0xfd},
+ {0x578b, 0xf5},
+ {0x578c, 0xf5},
+ {0x578d, 0x03},
+ {0x578e, 0x08},
+ {0x578f, 0x0c},
+ {0x5790, 0x08},
+ {0x5791, 0x04},
+ {0x5792, 0x00},
+ {0x5793, 0x52},
+ {0x5794, 0xa3},
+ {0x5795, 0x00},
+ {0x5796, 0x10},
+ {0x5797, 0x10},
+ {0x5798, 0x73},
+ {0x5799, 0x73},
+ {0x579a, 0x00},
+ {0x579b, 0x28},
+ {0x579c, 0x00},
+ {0x579d, 0x16},
+ {0x579e, 0x06},
+ {0x579f, 0x20},
+ {0x57a0, 0x04},
+ {0x57a1, 0xa0},
+ {0x59f8, 0x3d},
+ {0x5a08, 0x02},
+ {0x5b00, 0x02},
+ {0x5b01, 0x10},
+ {0x5b02, 0x03},
+ {0x5b03, 0xcf},
+ {0x5b05, 0x6c},
+ {0x5e00, 0x00}
};
-static const s64 link_freq_menu_items[] = {
- OV8856_LINK_FREQ_360MHZ,
- OV8856_LINK_FREQ_180MHZ
+static const struct ov8856_reg lane_4_mode_3264x2448[] = {
+ /* 3264x2448 resolution */
+ {0x0103, 0x01},
+ {0x0302, 0x3c},
+ {0x0303, 0x01},
+ {0x031e, 0x0c},
+ {0x3000, 0x20},
+ {0x3003, 0x08},
+ {0x300e, 0x20},
+ {0x3010, 0x00},
+ {0x3015, 0x84},
+ {0x3018, 0x72},
+ {0x3021, 0x23},
+ {0x3033, 0x24},
+ {0x3500, 0x00},
+ {0x3501, 0x9a},
+ {0x3502, 0x20},
+ {0x3503, 0x08},
+ {0x3505, 0x83},
+ {0x3508, 0x01},
+ {0x3509, 0x80},
+ {0x350c, 0x00},
+ {0x350d, 0x80},
+ {0x350e, 0x04},
+ {0x350f, 0x00},
+ {0x3510, 0x00},
+ {0x3511, 0x02},
+ {0x3512, 0x00},
+ {0x3600, 0x72},
+ {0x3601, 0x40},
+ {0x3602, 0x30},
+ {0x3610, 0xc5},
+ {0x3611, 0x58},
+ {0x3612, 0x5c},
+ {0x3613, 0xca},
+ {0x3614, 0x60},
+ {0x3628, 0xff},
+ {0x3629, 0xff},
+ {0x362a, 0xff},
+ {0x3633, 0x10},
+ {0x3634, 0x10},
+ {0x3635, 0x10},
+ {0x3636, 0x10},
+ {0x3663, 0x08},
+ {0x3669, 0x34},
+ {0x366d, 0x00},
+ {0x366e, 0x10},
+ {0x3706, 0x86},
+ {0x370b, 0x7e},
+ {0x3714, 0x23},
+ {0x3730, 0x12},
+ {0x3733, 0x10},
+ {0x3764, 0x00},
+ {0x3765, 0x00},
+ {0x3769, 0x62},
+ {0x376a, 0x2a},
+ {0x376b, 0x30},
+ {0x3780, 0x00},
+ {0x3781, 0x24},
+ {0x3782, 0x00},
+ {0x3783, 0x23},
+ {0x3798, 0x2f},
+ {0x37a1, 0x60},
+ {0x37a8, 0x6a},
+ {0x37ab, 0x3f},
+ {0x37c2, 0x04},
+ {0x37c3, 0xf1},
+ {0x37c9, 0x80},
+ {0x37cb, 0x16},
+ {0x37cc, 0x16},
+ {0x37cd, 0x16},
+ {0x37ce, 0x16},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x0c},
+ {0x3804, 0x0c},
+ {0x3805, 0xdf},
+ {0x3806, 0x09},
+ {0x3807, 0xa3},
+ {0x3808, 0x0c},
+ {0x3809, 0xc0},
+ {0x380a, 0x09},
+ {0x380b, 0x90},
+ {0x380c, 0x07},
+ {0x380d, 0x8c},
+ {0x380e, 0x09},
+ {0x380f, 0xb2},
+ {0x3810, 0x00},
+ {0x3811, 0x04},
+ {0x3812, 0x00},
+ {0x3813, 0x01},
+ {0x3814, 0x01},
+ {0x3815, 0x01},
+ {0x3816, 0x00},
+ {0x3817, 0x00},
+ {0x3818, 0x00},
+ {0x3819, 0x10},
+ {0x3820, 0x80},
+ {0x3821, 0x46},
+ {0x382a, 0x01},
+ {0x382b, 0x01},
+ {0x3830, 0x06},
+ {0x3836, 0x02},
+ {0x3862, 0x04},
+ {0x3863, 0x08},
+ {0x3cc0, 0x33},
+ {0x3d85, 0x17},
+ {0x3d8c, 0x73},
+ {0x3d8d, 0xde},
+ {0x4001, 0xe0},
+ {0x4003, 0x40},
+ {0x4008, 0x00},
+ {0x4009, 0x0b},
+ {0x400a, 0x00},
+ {0x400b, 0x84},
+ {0x400f, 0x80},
+ {0x4010, 0xf0},
+ {0x4011, 0xff},
+ {0x4012, 0x02},
+ {0x4013, 0x01},
+ {0x4014, 0x01},
+ {0x4015, 0x01},
+ {0x4042, 0x00},
+ {0x4043, 0x80},
+ {0x4044, 0x00},
+ {0x4045, 0x80},
+ {0x4046, 0x00},
+ {0x4047, 0x80},
+ {0x4048, 0x00},
+ {0x4049, 0x80},
+ {0x4041, 0x03},
+ {0x404c, 0x20},
+ {0x404d, 0x00},
+ {0x404e, 0x20},
+ {0x4203, 0x80},
+ {0x4307, 0x30},
+ {0x4317, 0x00},
+ {0x4502, 0x50},
+ {0x4503, 0x08},
+ {0x4601, 0x80},
+ {0x4800, 0x44},
+ {0x4816, 0x53},
+ {0x481b, 0x50},
+ {0x481f, 0x27},
+ {0x4823, 0x3c},
+ {0x482b, 0x00},
+ {0x4831, 0x66},
+ {0x4837, 0x16},
+ {0x483c, 0x0f},
+ {0x484b, 0x05},
+ {0x5000, 0x77},
+ {0x5001, 0x0a},
+ {0x5003, 0xc8},
+ {0x5004, 0x04},
+ {0x5006, 0x00},
+ {0x5007, 0x00},
+ {0x502e, 0x03},
+ {0x5030, 0x41},
+ {0x5780, 0x14},
+ {0x5781, 0x0f},
+ {0x5782, 0x44},
+ {0x5783, 0x02},
+ {0x5784, 0x01},
+ {0x5785, 0x01},
+ {0x5786, 0x00},
+ {0x5787, 0x04},
+ {0x5788, 0x02},
+ {0x5789, 0x0f},
+ {0x578a, 0xfd},
+ {0x578b, 0xf5},
+ {0x578c, 0xf5},
+ {0x578d, 0x03},
+ {0x578e, 0x08},
+ {0x578f, 0x0c},
+ {0x5790, 0x08},
+ {0x5791, 0x04},
+ {0x5792, 0x00},
+ {0x5793, 0x52},
+ {0x5794, 0xa3},
+ {0x5795, 0x02},
+ {0x5796, 0x20},
+ {0x5797, 0x20},
+ {0x5798, 0xd5},
+ {0x5799, 0xd5},
+ {0x579a, 0x00},
+ {0x579b, 0x50},
+ {0x579c, 0x00},
+ {0x579d, 0x2c},
+ {0x579e, 0x0c},
+ {0x579f, 0x40},
+ {0x57a0, 0x09},
+ {0x57a1, 0x40},
+ {0x59f8, 0x3d},
+ {0x5a08, 0x02},
+ {0x5b00, 0x02},
+ {0x5b01, 0x10},
+ {0x5b02, 0x03},
+ {0x5b03, 0xcf},
+ {0x5b05, 0x6c},
+ {0x5e00, 0x00},
+ {0x5e10, 0xfc}
};
-static const struct ov8856_link_freq_config link_freq_configs[] = {
- [OV8856_LINK_FREQ_720MBPS] = {
- .reg_list = {
- .num_of_regs = ARRAY_SIZE(mipi_data_rate_720mbps),
- .regs = mipi_data_rate_720mbps,
- }
- },
- [OV8856_LINK_FREQ_360MBPS] = {
- .reg_list = {
- .num_of_regs = ARRAY_SIZE(mipi_data_rate_360mbps),
- .regs = mipi_data_rate_360mbps,
- }
- }
+static const struct ov8856_reg lane_4_mode_1632x1224[] = {
+ /* 1632x1224 resolution */
+ {0x0103, 0x01},
+ {0x0302, 0x3c},
+ {0x0303, 0x01},
+ {0x031e, 0x0c},
+ {0x3000, 0x20},
+ {0x3003, 0x08},
+ {0x300e, 0x20},
+ {0x3010, 0x00},
+ {0x3015, 0x84},
+ {0x3018, 0x72},
+ {0x3021, 0x23},
+ {0x3033, 0x24},
+ {0x3500, 0x00},
+ {0x3501, 0x4c},
+ {0x3502, 0xe0},
+ {0x3503, 0x08},
+ {0x3505, 0x83},
+ {0x3508, 0x01},
+ {0x3509, 0x80},
+ {0x350c, 0x00},
+ {0x350d, 0x80},
+ {0x350e, 0x04},
+ {0x350f, 0x00},
+ {0x3510, 0x00},
+ {0x3511, 0x02},
+ {0x3512, 0x00},
+ {0x3600, 0x72},
+ {0x3601, 0x40},
+ {0x3602, 0x30},
+ {0x3610, 0xc5},
+ {0x3611, 0x58},
+ {0x3612, 0x5c},
+ {0x3613, 0xca},
+ {0x3614, 0x60},
+ {0x3628, 0xff},
+ {0x3629, 0xff},
+ {0x362a, 0xff},
+ {0x3633, 0x10},
+ {0x3634, 0x10},
+ {0x3635, 0x10},
+ {0x3636, 0x10},
+ {0x3663, 0x08},
+ {0x3669, 0x34},
+ {0x366d, 0x00},
+ {0x366e, 0x08},
+ {0x3706, 0x86},
+ {0x370b, 0x7e},
+ {0x3714, 0x27},
+ {0x3730, 0x12},
+ {0x3733, 0x10},
+ {0x3764, 0x00},
+ {0x3765, 0x00},
+ {0x3769, 0x62},
+ {0x376a, 0x2a},
+ {0x376b, 0x30},
+ {0x3780, 0x00},
+ {0x3781, 0x24},
+ {0x3782, 0x00},
+ {0x3783, 0x23},
+ {0x3798, 0x2f},
+ {0x37a1, 0x60},
+ {0x37a8, 0x6a},
+ {0x37ab, 0x3f},
+ {0x37c2, 0x14},
+ {0x37c3, 0xf1},
+ {0x37c9, 0x80},
+ {0x37cb, 0x16},
+ {0x37cc, 0x16},
+ {0x37cd, 0x16},
+ {0x37ce, 0x16},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x0c},
+ {0x3804, 0x0c},
+ {0x3805, 0xdf},
+ {0x3806, 0x09},
+ {0x3807, 0xa3},
+ {0x3808, 0x06},
+ {0x3809, 0x60},
+ {0x380a, 0x04},
+ {0x380b, 0xc8},
+ {0x380c, 0x07},
+ {0x380d, 0x8c},
+ {0x380e, 0x09},
+ {0x380f, 0xb2},
+ {0x3810, 0x00},
+ {0x3811, 0x02},
+ {0x3812, 0x00},
+ {0x3813, 0x01},
+ {0x3814, 0x03},
+ {0x3815, 0x01},
+ {0x3816, 0x00},
+ {0x3817, 0x00},
+ {0x3818, 0x00},
+ {0x3819, 0x10},
+ {0x3820, 0x80},
+ {0x3821, 0x47},
+ {0x382a, 0x03},
+ {0x382b, 0x01},
+ {0x3830, 0x06},
+ {0x3836, 0x02},
+ {0x3862, 0x04},
+ {0x3863, 0x08},
+ {0x3cc0, 0x33},
+ {0x3d85, 0x17},
+ {0x3d8c, 0x73},
+ {0x3d8d, 0xde},
+ {0x4001, 0xe0},
+ {0x4003, 0x40},
+ {0x4008, 0x00},
+ {0x4009, 0x05},
+ {0x400a, 0x00},
+ {0x400b, 0x84},
+ {0x400f, 0x80},
+ {0x4010, 0xf0},
+ {0x4011, 0xff},
+ {0x4012, 0x02},
+ {0x4013, 0x01},
+ {0x4014, 0x01},
+ {0x4015, 0x01},
+ {0x4042, 0x00},
+ {0x4043, 0x80},
+ {0x4044, 0x00},
+ {0x4045, 0x80},
+ {0x4046, 0x00},
+ {0x4047, 0x80},
+ {0x4048, 0x00},
+ {0x4049, 0x80},
+ {0x4041, 0x03},
+ {0x404c, 0x20},
+ {0x404d, 0x00},
+ {0x404e, 0x20},
+ {0x4203, 0x80},
+ {0x4307, 0x30},
+ {0x4317, 0x00},
+ {0x4502, 0x50},
+ {0x4503, 0x08},
+ {0x4601, 0x80},
+ {0x4800, 0x44},
+ {0x4816, 0x53},
+ {0x481b, 0x50},
+ {0x481f, 0x27},
+ {0x4823, 0x3c},
+ {0x482b, 0x00},
+ {0x4831, 0x66},
+ {0x4837, 0x16},
+ {0x483c, 0x0f},
+ {0x484b, 0x05},
+ {0x5000, 0x77},
+ {0x5001, 0x0a},
+ {0x5003, 0xc8},
+ {0x5004, 0x04},
+ {0x5006, 0x00},
+ {0x5007, 0x00},
+ {0x502e, 0x03},
+ {0x5030, 0x41},
+ {0x5795, 0x00},
+ {0x5796, 0x10},
+ {0x5797, 0x10},
+ {0x5798, 0x73},
+ {0x5799, 0x73},
+ {0x579a, 0x00},
+ {0x579b, 0x28},
+ {0x579c, 0x00},
+ {0x579d, 0x16},
+ {0x579e, 0x06},
+ {0x579f, 0x20},
+ {0x57a0, 0x04},
+ {0x57a1, 0xa0},
+ {0x5780, 0x14},
+ {0x5781, 0x0f},
+ {0x5782, 0x44},
+ {0x5783, 0x02},
+ {0x5784, 0x01},
+ {0x5785, 0x01},
+ {0x5786, 0x00},
+ {0x5787, 0x04},
+ {0x5788, 0x02},
+ {0x5789, 0x0f},
+ {0x578a, 0xfd},
+ {0x578b, 0xf5},
+ {0x578c, 0xf5},
+ {0x578d, 0x03},
+ {0x578e, 0x08},
+ {0x578f, 0x0c},
+ {0x5790, 0x08},
+ {0x5791, 0x04},
+ {0x5792, 0x00},
+ {0x5793, 0x52},
+ {0x5794, 0xa3},
+ {0x59f8, 0x3d},
+ {0x5a08, 0x02},
+ {0x5b00, 0x02},
+ {0x5b01, 0x10},
+ {0x5b02, 0x03},
+ {0x5b03, 0xcf},
+ {0x5b05, 0x6c},
+ {0x5e00, 0x00},
+ {0x5e10, 0xfc}
};
-static const struct ov8856_mode supported_modes[] = {
- {
- .width = 3280,
- .height = 2464,
- .hts = 1928,
- .vts_def = 2488,
- .vts_min = 2488,
- .reg_list = {
- .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
- .regs = mode_3280x2464_regs,
- },
- .link_freq_index = OV8856_LINK_FREQ_720MBPS,
- },
- {
- .width = 3264,
- .height = 2448,
- .hts = 1932,
- .vts_def = 2482,
- .vts_min = 2482,
- .reg_list = {
- .num_of_regs = ARRAY_SIZE(mode_3264x2448_regs),
- .regs = mode_3264x2448_regs,
- },
- .link_freq_index = OV8856_LINK_FREQ_720MBPS,
- },
- {
- .width = 1640,
- .height = 1232,
- .hts = 3820,
- .vts_def = 1256,
- .vts_min = 1256,
- .reg_list = {
- .num_of_regs = ARRAY_SIZE(mode_1640x1232_regs),
- .regs = mode_1640x1232_regs,
- },
- .link_freq_index = OV8856_LINK_FREQ_360MBPS,
- },
- {
- .width = 1632,
- .height = 1224,
- .hts = 1932,
- .vts_def = 2482,
- .vts_min = 2482,
- .reg_list = {
- .num_of_regs = ARRAY_SIZE(mode_1632x1224_regs),
- .regs = mode_1632x1224_regs,
- },
- .link_freq_index = OV8856_LINK_FREQ_360MBPS,
- }
+static const char * const ov8856_test_pattern_menu[] = {
+ "Disabled",
+ "Standard Color Bar",
+ "Top-Bottom Darker Color Bar",
+ "Right-Left Darker Color Bar",
+ "Bottom-Top Darker Color Bar"
};
struct ov8856 {
@@ -1037,20 +1404,173 @@ struct ov8856 {
/* Streaming on/off */
bool streaming;
+
+ /* lanes index */
+ u8 nlanes;
+
+ const struct ov8856_lane_cfg *priv_lane;
+ u8 modes_size;
+};
+
+struct ov8856_lane_cfg {
+ const s64 link_freq_menu_items[2];
+ const struct ov8856_link_freq_config link_freq_configs[2];
+ const struct ov8856_mode supported_modes[4];
+};
+
+static const struct ov8856_lane_cfg lane_cfg_2 = {
+ {
+ 720000000,
+ 360000000,
+ },
+ {{
+ .reg_list = {
+ .num_of_regs =
+ ARRAY_SIZE(mipi_data_rate_lane_2.regs_0),
+ .regs = mipi_data_rate_lane_2.regs_0,
+ }
+ },
+ {
+ .reg_list = {
+ .num_of_regs =
+ ARRAY_SIZE(mipi_data_rate_lane_2.regs_1),
+ .regs = mipi_data_rate_lane_2.regs_1,
+ }
+ }},
+ {{
+ .width = 3280,
+ .height = 2464,
+ .hts = 1928,
+ .vts_def = 2488,
+ .vts_min = 2488,
+ .reg_list = {
+ .num_of_regs =
+ ARRAY_SIZE(lane_2_mode_3280x2464),
+ .regs = lane_2_mode_3280x2464,
+ },
+ .link_freq_index = 0,
+ .data_lanes = 2,
+ },
+ {
+ .width = 1640,
+ .height = 1232,
+ .hts = 3168,
+ .vts_def = 1514,
+ .vts_min = 1514,
+ .reg_list = {
+ .num_of_regs =
+ ARRAY_SIZE(lane_2_mode_1640x1232),
+ .regs = lane_2_mode_1640x1232,
+ },
+ .link_freq_index = 1,
+ .data_lanes = 2,
+ }}
};
-static u64 to_pixel_rate(u32 f_index)
+static const struct ov8856_lane_cfg lane_cfg_4 = {
+ {
+ 360000000,
+ 180000000,
+ },
+ {{
+ .reg_list = {
+ .num_of_regs =
+ ARRAY_SIZE(mipi_data_rate_lane_4.regs_0),
+ .regs = mipi_data_rate_lane_4.regs_0,
+ }
+ },
+ {
+ .reg_list = {
+ .num_of_regs =
+ ARRAY_SIZE(mipi_data_rate_lane_4.regs_1),
+ .regs = mipi_data_rate_lane_4.regs_1,
+ }
+ }},
+ {{
+ .width = 3280,
+ .height = 2464,
+ .hts = 1928,
+ .vts_def = 2488,
+ .vts_min = 2488,
+ .reg_list = {
+ .num_of_regs =
+ ARRAY_SIZE(lane_4_mode_3280x2464),
+ .regs = lane_4_mode_3280x2464,
+ },
+ .link_freq_index = 0,
+ .data_lanes = 4,
+ },
+ {
+ .width = 1640,
+ .height = 1232,
+ .hts = 3820,
+ .vts_def = 1256,
+ .vts_min = 1256,
+ .reg_list = {
+ .num_of_regs =
+ ARRAY_SIZE(lane_4_mode_1640x1232),
+ .regs = lane_4_mode_1640x1232,
+ },
+ .link_freq_index = 1,
+ .data_lanes = 4,
+ },
+ {
+ .width = 3264,
+ .height = 2448,
+ .hts = 1932,
+ .vts_def = 2482,
+ .vts_min = 2482,
+ .reg_list = {
+ .num_of_regs =
+ ARRAY_SIZE(lane_4_mode_3264x2448),
+ .regs = lane_4_mode_3264x2448,
+ },
+ .link_freq_index = 0,
+ .data_lanes = 4,
+ },
+ {
+ .width = 1632,
+ .height = 1224,
+ .hts = 1932,
+ .vts_def = 2482,
+ .vts_min = 2482,
+ .reg_list = {
+ .num_of_regs =
+ ARRAY_SIZE(lane_4_mode_1632x1224),
+ .regs = lane_4_mode_1632x1224,
+ },
+ .link_freq_index = 1,
+ .data_lanes = 4,
+ }}
+};
+
+static unsigned int ov8856_modes_num(const struct ov8856 *ov8856)
{
- u64 pixel_rate = link_freq_menu_items[f_index] * 2 * OV8856_DATA_LANES;
+ unsigned int i, count = 0;
+
+ for (i = 0; i < ARRAY_SIZE(ov8856->priv_lane->supported_modes); i++) {
+ if (ov8856->priv_lane->supported_modes[i].width == 0)
+ break;
+ count++;
+ }
+
+ return count;
+}
+
+static u64 to_rate(const s64 *link_freq_menu_items,
+ u32 f_index, u8 nlanes)
+{
+ u64 pixel_rate = link_freq_menu_items[f_index] * 2 * nlanes;
do_div(pixel_rate, OV8856_RGB_DEPTH);
return pixel_rate;
}
-static u64 to_pixels_per_line(u32 hts, u32 f_index)
+static u64 to_pixels_per_line(const s64 *link_freq_menu_items, u32 hts,
+ u32 f_index, u8 nlanes)
{
- u64 ppl = hts * to_pixel_rate(f_index);
+ u64 ppl = hts * to_rate(link_freq_menu_items, f_index, nlanes);
do_div(ppl, OV8856_SCLK);
@@ -1152,6 +1672,93 @@ static int ov8856_test_pattern(struct ov8856 *ov8856, u32 pattern)
OV8856_REG_VALUE_08BIT, pattern);
}
+static int ov8856_set_ctrl_hflip(struct ov8856 *ov8856, u32 ctrl_val)
+{
+ int ret;
+ u32 val;
+
+ ret = ov8856_read_reg(ov8856, OV8856_REG_MIRROR_OPT_1,
+ OV8856_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ ret = ov8856_write_reg(ov8856, OV8856_REG_MIRROR_OPT_1,
+ OV8856_REG_VALUE_08BIT,
+ ctrl_val ? val & ~OV8856_REG_MIRROR_OP_2 :
+ val | OV8856_REG_MIRROR_OP_2);
+
+ if (ret)
+ return ret;
+
+ ret = ov8856_read_reg(ov8856, OV8856_REG_FORMAT2,
+ OV8856_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ return ov8856_write_reg(ov8856, OV8856_REG_FORMAT2,
+ OV8856_REG_VALUE_08BIT,
+ ctrl_val ? val & ~OV8856_REG_FORMAT2_OP_1 &
+ ~OV8856_REG_FORMAT2_OP_2 &
+ ~OV8856_REG_FORMAT2_OP_3 :
+ val | OV8856_REG_FORMAT2_OP_1 |
+ OV8856_REG_FORMAT2_OP_2 |
+ OV8856_REG_FORMAT2_OP_3);
+}
+
+static int ov8856_set_ctrl_vflip(struct ov8856 *ov8856, u8 ctrl_val)
+{
+ int ret;
+ u32 val;
+
+ ret = ov8856_read_reg(ov8856, OV8856_REG_FLIP_OPT_1,
+ OV8856_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ ret = ov8856_write_reg(ov8856, OV8856_REG_FLIP_OPT_1,
+ OV8856_REG_VALUE_08BIT,
+ ctrl_val ? val | OV8856_REG_FLIP_OP_1 |
+ OV8856_REG_FLIP_OP_2 :
+ val & ~OV8856_REG_FLIP_OP_1 &
+ ~OV8856_REG_FLIP_OP_2);
+
+ ret = ov8856_read_reg(ov8856, OV8856_REG_FLIP_OPT_2,
+ OV8856_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ ret = ov8856_write_reg(ov8856, OV8856_REG_FLIP_OPT_2,
+ OV8856_REG_VALUE_08BIT,
+ ctrl_val ? val | OV8856_REG_FLIP_OP_2 :
+ val & ~OV8856_REG_FLIP_OP_2);
+
+ ret = ov8856_read_reg(ov8856, OV8856_REG_FLIP_OPT_3,
+ OV8856_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ ret = ov8856_write_reg(ov8856, OV8856_REG_FLIP_OPT_3,
+ OV8856_REG_VALUE_08BIT,
+ ctrl_val ? val & ~OV8856_REG_FLIP_OP_0 &
+ ~OV8856_REG_FLIP_OP_1 :
+ val | OV8856_REG_FLIP_OP_0 |
+ OV8856_REG_FLIP_OP_1);
+
+ ret = ov8856_read_reg(ov8856, OV8856_REG_FORMAT1,
+ OV8856_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ return ov8856_write_reg(ov8856, OV8856_REG_FORMAT1,
+ OV8856_REG_VALUE_08BIT,
+ ctrl_val ? val | OV8856_REG_FORMAT1_OP_1 |
+ OV8856_REG_FORMAT1_OP_3 |
+ OV8856_REG_FORMAT1_OP_2 :
+ val & ~OV8856_REG_FORMAT1_OP_1 &
+ ~OV8856_REG_FORMAT1_OP_3 &
+ ~OV8856_REG_FORMAT1_OP_2);
+}
+
static int ov8856_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct ov8856 *ov8856 = container_of(ctrl->handler,
@@ -1201,6 +1808,14 @@ static int ov8856_set_ctrl(struct v4l2_ctrl *ctrl)
ret = ov8856_test_pattern(ov8856, ctrl->val);
break;
+ case V4L2_CID_HFLIP:
+ ret = ov8856_set_ctrl_hflip(ov8856, ctrl->val);
+ break;
+
+ case V4L2_CID_VFLIP:
+ ret = ov8856_set_ctrl_vflip(ov8856, ctrl->val);
+ break;
+
default:
ret = -EINVAL;
break;
@@ -1229,23 +1844,32 @@ static int ov8856_init_controls(struct ov8856 *ov8856)
ctrl_hdlr->lock = &ov8856->mutex;
ov8856->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov8856_ctrl_ops,
V4L2_CID_LINK_FREQ,
- ARRAY_SIZE(link_freq_menu_items) - 1,
- 0, link_freq_menu_items);
+ ARRAY_SIZE
+ (ov8856->priv_lane->link_freq_menu_items)
+ - 1,
+ 0, ov8856->priv_lane->link_freq_menu_items);
if (ov8856->link_freq)
ov8856->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
ov8856->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops,
V4L2_CID_PIXEL_RATE, 0,
- to_pixel_rate(OV8856_LINK_FREQ_720MBPS),
- 1,
- to_pixel_rate(OV8856_LINK_FREQ_720MBPS));
+ to_rate(ov8856->priv_lane->link_freq_menu_items,
+ 0,
+ ov8856->cur_mode->data_lanes), 1,
+ to_rate(ov8856->priv_lane->link_freq_menu_items,
+ 0,
+ ov8856->cur_mode->data_lanes));
ov8856->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops,
V4L2_CID_VBLANK,
ov8856->cur_mode->vts_min - ov8856->cur_mode->height,
OV8856_VTS_MAX - ov8856->cur_mode->height, 1,
- ov8856->cur_mode->vts_def - ov8856->cur_mode->height);
- h_blank = to_pixels_per_line(ov8856->cur_mode->hts,
- ov8856->cur_mode->link_freq_index) - ov8856->cur_mode->width;
+ ov8856->cur_mode->vts_def -
+ ov8856->cur_mode->height);
+ h_blank = to_pixels_per_line(ov8856->priv_lane->link_freq_menu_items,
+ ov8856->cur_mode->hts,
+ ov8856->cur_mode->link_freq_index,
+ ov8856->cur_mode->data_lanes) -
+ ov8856->cur_mode->width;
ov8856->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops,
V4L2_CID_HBLANK, h_blank, h_blank, 1,
h_blank);
@@ -1268,6 +1892,10 @@ static int ov8856_init_controls(struct ov8856 *ov8856)
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(ov8856_test_pattern_menu) - 1,
0, 0, ov8856_test_pattern_menu);
+ v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
if (ctrl_hdlr->error)
return ctrl_hdlr->error;
@@ -1292,7 +1920,8 @@ static int ov8856_start_streaming(struct ov8856 *ov8856)
int link_freq_index, ret;
link_freq_index = ov8856->cur_mode->link_freq_index;
- reg_list = &link_freq_configs[link_freq_index].reg_list;
+ reg_list = &ov8856->priv_lane->link_freq_configs[link_freq_index].reg_list;
+
ret = ov8856_write_reg_list(ov8856, reg_list);
if (ret) {
dev_err(&client->dev, "failed to set plls");
@@ -1340,9 +1969,8 @@ static int ov8856_set_stream(struct v4l2_subdev *sd, int enable)
mutex_lock(&ov8856->mutex);
if (enable) {
- ret = pm_runtime_get_sync(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
mutex_unlock(&ov8856->mutex);
return ret;
}
@@ -1455,27 +2083,29 @@ static int __maybe_unused ov8856_resume(struct device *dev)
}
static int ov8856_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov8856 *ov8856 = to_ov8856(sd);
const struct ov8856_mode *mode;
s32 vblank_def, h_blank;
- mode = v4l2_find_nearest_size(supported_modes,
- ARRAY_SIZE(supported_modes), width,
- height, fmt->format.width,
+ mode = v4l2_find_nearest_size(ov8856->priv_lane->supported_modes,
+ ov8856->modes_size,
+ width, height, fmt->format.width,
fmt->format.height);
mutex_lock(&ov8856->mutex);
ov8856_update_pad_format(mode, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+ *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
} else {
ov8856->cur_mode = mode;
__v4l2_ctrl_s_ctrl(ov8856->link_freq, mode->link_freq_index);
__v4l2_ctrl_s_ctrl_int64(ov8856->pixel_rate,
- to_pixel_rate(mode->link_freq_index));
+ to_rate(ov8856->priv_lane->link_freq_menu_items,
+ mode->link_freq_index,
+ ov8856->cur_mode->data_lanes));
/* Update limits and set FPS to default */
vblank_def = mode->vts_def - mode->height;
@@ -1484,8 +2114,11 @@ static int ov8856_set_format(struct v4l2_subdev *sd,
OV8856_VTS_MAX - mode->height, 1,
vblank_def);
__v4l2_ctrl_s_ctrl(ov8856->vblank, vblank_def);
- h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index) -
- mode->width;
+ h_blank = to_pixels_per_line(ov8856->priv_lane->link_freq_menu_items,
+ mode->hts,
+ mode->link_freq_index,
+ ov8856->cur_mode->data_lanes)
+ - mode->width;
__v4l2_ctrl_modify_range(ov8856->hblank, h_blank, h_blank, 1,
h_blank);
}
@@ -1496,14 +2129,15 @@ static int ov8856_set_format(struct v4l2_subdev *sd,
}
static int ov8856_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov8856 *ov8856 = to_ov8856(sd);
mutex_lock(&ov8856->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&ov8856->sd, cfg,
+ fmt->format = *v4l2_subdev_get_try_format(&ov8856->sd,
+ sd_state,
fmt->pad);
else
ov8856_update_pad_format(ov8856->cur_mode, &fmt->format);
@@ -1514,7 +2148,7 @@ static int ov8856_get_format(struct v4l2_subdev *sd,
}
static int ov8856_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
/* Only one bayer order GRBG is supported */
@@ -1527,18 +2161,20 @@ static int ov8856_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov8856_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
- if (fse->index >= ARRAY_SIZE(supported_modes))
+ struct ov8856 *ov8856 = to_ov8856(sd);
+
+ if (fse->index >= ov8856->modes_size)
return -EINVAL;
if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
return -EINVAL;
- fse->min_width = supported_modes[fse->index].width;
+ fse->min_width = ov8856->priv_lane->supported_modes[fse->index].width;
fse->max_width = fse->min_width;
- fse->min_height = supported_modes[fse->index].height;
+ fse->min_height = ov8856->priv_lane->supported_modes[fse->index].height;
fse->max_height = fse->min_height;
return 0;
@@ -1549,8 +2185,8 @@ static int ov8856_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
struct ov8856 *ov8856 = to_ov8856(sd);
mutex_lock(&ov8856->mutex);
- ov8856_update_pad_format(&supported_modes[0],
- v4l2_subdev_get_try_format(sd, fh->pad, 0));
+ ov8856_update_pad_format(&ov8856->priv_lane->supported_modes[0],
+ v4l2_subdev_get_try_format(sd, fh->state, 0));
mutex_unlock(&ov8856->mutex);
return 0;
@@ -1696,29 +2332,40 @@ static int ov8856_get_hwcfg(struct ov8856 *ov8856, struct device *dev)
if (ret)
return ret;
- if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV8856_DATA_LANES) {
+ /* Get number of data lanes */
+ if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2 &&
+ bus_cfg.bus.mipi_csi2.num_data_lanes != 4) {
dev_err(dev, "number of CSI2 data lanes %d is not supported",
bus_cfg.bus.mipi_csi2.num_data_lanes);
ret = -EINVAL;
goto check_hwcfg_error;
}
+ dev_dbg(dev, "Using %u data lanes\n", ov8856->cur_mode->data_lanes);
+
+ if (bus_cfg.bus.mipi_csi2.num_data_lanes == 2)
+ ov8856->priv_lane = &lane_cfg_2;
+ else
+ ov8856->priv_lane = &lane_cfg_4;
+
+ ov8856->modes_size = ov8856_modes_num(ov8856);
+
if (!bus_cfg.nr_of_link_frequencies) {
dev_err(dev, "no link frequencies defined");
ret = -EINVAL;
goto check_hwcfg_error;
}
- for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) {
+ for (i = 0; i < ARRAY_SIZE(ov8856->priv_lane->link_freq_menu_items); i++) {
for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) {
- if (link_freq_menu_items[i] ==
- bus_cfg.link_frequencies[j])
+ if (ov8856->priv_lane->link_freq_menu_items[i] ==
+ bus_cfg.link_frequencies[j])
break;
}
if (j == bus_cfg.nr_of_link_frequencies) {
dev_err(dev, "no link frequency %lld supported",
- link_freq_menu_items[i]);
+ ov8856->priv_lane->link_freq_menu_items[i]);
ret = -EINVAL;
goto check_hwcfg_error;
}
@@ -1777,7 +2424,7 @@ static int ov8856_probe(struct i2c_client *client)
}
mutex_init(&ov8856->mutex);
- ov8856->cur_mode = &supported_modes[0];
+ ov8856->cur_mode = &ov8856->priv_lane->supported_modes[0];
ret = ov8856_init_controls(ov8856);
if (ret) {
dev_err(&client->dev, "failed to init controls: %d", ret);
diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c
index 9ecf180635ee..ce50f3ea87b8 100644
--- a/drivers/media/i2c/ov8865.c
+++ b/drivers/media/i2c/ov8865.c
@@ -2497,11 +2497,9 @@ static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable)
int ret;
if (enable) {
- ret = pm_runtime_get_sync(sensor->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(sensor->dev);
+ ret = pm_runtime_resume_and_get(sensor->dev);
+ if (ret < 0)
return ret;
- }
}
mutex_lock(&sensor->mutex);
@@ -2544,7 +2542,7 @@ static const struct v4l2_subdev_video_ops ov8865_subdev_video_ops = {
/* Subdev Pad Operations */
static int ov8865_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *config,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code_enum)
{
if (code_enum->index >= ARRAY_SIZE(ov8865_mbus_codes))
@@ -2573,7 +2571,7 @@ static void ov8865_mbus_format_fill(struct v4l2_mbus_framefmt *mbus_format,
}
static int ov8865_get_fmt(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *config,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev);
@@ -2582,7 +2580,7 @@ static int ov8865_get_fmt(struct v4l2_subdev *subdev,
mutex_lock(&sensor->mutex);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *mbus_format = *v4l2_subdev_get_try_format(subdev, config,
+ *mbus_format = *v4l2_subdev_get_try_format(subdev, sd_state,
format->pad);
else
ov8865_mbus_format_fill(mbus_format, sensor->state.mbus_code,
@@ -2594,7 +2592,7 @@ static int ov8865_get_fmt(struct v4l2_subdev *subdev,
}
static int ov8865_set_fmt(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *config,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev);
@@ -2635,7 +2633,7 @@ static int ov8865_set_fmt(struct v4l2_subdev *subdev,
ov8865_mbus_format_fill(mbus_format, mbus_code, mode);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *v4l2_subdev_get_try_format(subdev, config, format->pad) =
+ *v4l2_subdev_get_try_format(subdev, sd_state, format->pad) =
*mbus_format;
else if (sensor->state.mode != mode ||
sensor->state.mbus_code != mbus_code)
@@ -2648,7 +2646,7 @@ complete:
}
static int ov8865_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *config,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *size_enum)
{
const struct ov8865_mode *mode;
@@ -2665,7 +2663,7 @@ static int ov8865_enum_frame_size(struct v4l2_subdev *subdev,
}
static int ov8865_enum_frame_interval(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *config,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *interval_enum)
{
const struct ov8865_mode *mode = NULL;
@@ -2691,7 +2689,7 @@ static int ov8865_enum_frame_interval(struct v4l2_subdev *subdev,
}
}
- if (mode_index == ARRAY_SIZE(ov8865_modes) || !mode)
+ if (mode_index == ARRAY_SIZE(ov8865_modes))
return -EINVAL;
interval_enum->interval = mode->frame_interval;
diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c
index d36b04c49628..0bab8c2cf160 100644
--- a/drivers/media/i2c/ov9640.c
+++ b/drivers/media/i2c/ov9640.c
@@ -519,7 +519,7 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd,
}
static int ov9640_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -547,13 +547,13 @@ static int ov9640_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return ov9640_s_fmt(sd, mf);
- cfg->try_fmt = *mf;
+ sd_state->pads->try_fmt = *mf;
return 0;
}
static int ov9640_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index >= ARRAY_SIZE(ov9640_codes))
@@ -565,7 +565,7 @@ static int ov9640_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov9640_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index 4fe68aa55789..c313e11a9754 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -1070,7 +1070,7 @@ static void ov965x_get_default_format(struct v4l2_mbus_framefmt *mf)
}
static int ov965x_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(ov965x_formats))
@@ -1081,7 +1081,7 @@ static int ov965x_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov965x_enum_frame_sizes(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
int i = ARRAY_SIZE(ov965x_formats);
@@ -1167,14 +1167,14 @@ static int ov965x_s_frame_interval(struct v4l2_subdev *sd,
}
static int ov965x_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov965x *ov965x = to_ov965x(sd);
struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
fmt->format = *mf;
return 0;
}
@@ -1212,7 +1212,7 @@ static void __ov965x_try_frame_size(struct v4l2_mbus_framefmt *mf,
}
static int ov965x_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
unsigned int index = ARRAY_SIZE(ov965x_formats);
@@ -1234,8 +1234,9 @@ static int ov965x_set_fmt(struct v4l2_subdev *sd,
mutex_lock(&ov965x->lock);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- if (cfg) {
- mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ if (sd_state) {
+ mf = v4l2_subdev_get_try_format(sd, sd_state,
+ fmt->pad);
*mf = fmt->format;
}
} else {
@@ -1364,7 +1365,7 @@ static int ov965x_s_stream(struct v4l2_subdev *sd, int on)
static int ov965x_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *mf =
- v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
ov965x_get_default_format(mf);
return 0;
@@ -1479,8 +1480,8 @@ static int ov965x_detect_sensor(struct v4l2_subdev *sd)
if (ov965x->id == OV9650_ID || ov965x->id == OV9652_ID) {
v4l2_info(sd, "Found OV%04X sensor\n", ov965x->id);
} else {
- v4l2_err(sd, "Sensor detection failed (%04X, %d)\n",
- ov965x->id, ret);
+ v4l2_err(sd, "Sensor detection failed (%04X)\n",
+ ov965x->id);
ret = -ENODEV;
}
}
diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c
index b7309a551cae..af50c66cf5ce 100644
--- a/drivers/media/i2c/ov9734.c
+++ b/drivers/media/i2c/ov9734.c
@@ -644,9 +644,8 @@ static int ov9734_set_stream(struct v4l2_subdev *sd, int enable)
}
if (enable) {
- ret = pm_runtime_get_sync(&client->dev);
+ ret = pm_runtime_resume_and_get(&client->dev);
if (ret < 0) {
- pm_runtime_put_noidle(&client->dev);
mutex_unlock(&ov9734->mutex);
return ret;
}
@@ -706,7 +705,7 @@ exit:
}
static int ov9734_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov9734 *ov9734 = to_ov9734(sd);
@@ -721,7 +720,7 @@ static int ov9734_set_format(struct v4l2_subdev *sd,
mutex_lock(&ov9734->mutex);
ov9734_update_pad_format(mode, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+ *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
} else {
ov9734->cur_mode = mode;
__v4l2_ctrl_s_ctrl(ov9734->link_freq, mode->link_freq_index);
@@ -747,14 +746,15 @@ static int ov9734_set_format(struct v4l2_subdev *sd,
}
static int ov9734_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ov9734 *ov9734 = to_ov9734(sd);
mutex_lock(&ov9734->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&ov9734->sd, cfg,
+ fmt->format = *v4l2_subdev_get_try_format(&ov9734->sd,
+ sd_state,
fmt->pad);
else
ov9734_update_pad_format(ov9734->cur_mode, &fmt->format);
@@ -765,7 +765,7 @@ static int ov9734_get_format(struct v4l2_subdev *sd,
}
static int ov9734_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
@@ -777,7 +777,7 @@ static int ov9734_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov9734_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -800,7 +800,7 @@ static int ov9734_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_lock(&ov9734->mutex);
ov9734_update_pad_format(&supported_modes[0],
- v4l2_subdev_get_try_format(sd, fh->pad, 0));
+ v4l2_subdev_get_try_format(sd, fh->state, 0));
mutex_unlock(&ov9734->mutex);
return 0;
diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
index 90eb73f0e6e9..025a610de893 100644
--- a/drivers/media/i2c/rdacm20.c
+++ b/drivers/media/i2c/rdacm20.c
@@ -312,7 +312,7 @@ static const struct ov10635_reg {
struct rdacm20_device {
struct device *dev;
- struct max9271_device *serializer;
+ struct max9271_device serializer;
struct i2c_client *sensor;
struct v4l2_subdev sd;
struct media_pad pad;
@@ -399,11 +399,11 @@ static int rdacm20_s_stream(struct v4l2_subdev *sd, int enable)
{
struct rdacm20_device *dev = sd_to_rdacm20(sd);
- return max9271_set_serial_link(dev->serializer, enable);
+ return max9271_set_serial_link(&dev->serializer, enable);
}
static int rdacm20_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index > 0)
@@ -415,7 +415,7 @@ static int rdacm20_enum_mbus_code(struct v4l2_subdev *sd,
}
static int rdacm20_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -455,12 +455,10 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
unsigned int retry = 3;
int ret;
- /* Verify communication with the MAX9271: ping to wakeup. */
- dev->serializer->client->addr = MAX9271_DEFAULT_ADDR;
- i2c_smbus_read_byte(dev->serializer->client);
+ max9271_wake_up(&dev->serializer);
/* Serial link disabled during config as it needs a valid pixel clock. */
- ret = max9271_set_serial_link(dev->serializer, false);
+ ret = max9271_set_serial_link(&dev->serializer, false);
if (ret)
return ret;
@@ -468,38 +466,48 @@ static int rdacm20_initialize(struct rdacm20_device *dev)
* Ensure that we have a good link configuration before attempting to
* identify the device.
*/
- max9271_configure_i2c(dev->serializer, MAX9271_I2CSLVSH_469NS_234NS |
- MAX9271_I2CSLVTO_1024US |
- MAX9271_I2CMSTBT_105KBPS);
-
- max9271_configure_gmsl_link(dev->serializer);
-
- ret = max9271_verify_id(dev->serializer);
- if (ret < 0)
- return ret;
-
- ret = max9271_set_address(dev->serializer, dev->addrs[0]);
- if (ret < 0)
+ ret = max9271_configure_i2c(&dev->serializer,
+ MAX9271_I2CSLVSH_469NS_234NS |
+ MAX9271_I2CSLVTO_1024US |
+ MAX9271_I2CMSTBT_105KBPS);
+ if (ret)
return ret;
- dev->serializer->client->addr = dev->addrs[0];
/*
- * Reset the sensor by cycling the OV10635 reset signal connected to the
- * MAX9271 GPIO1 and verify communication with the OV10635.
+ * Hold OV10635 in reset during max9271 configuration. The reset signal
+ * has to be asserted for at least 200 microseconds.
*/
- ret = max9271_enable_gpios(dev->serializer, MAX9271_GPIO1OUT);
+ ret = max9271_enable_gpios(&dev->serializer, MAX9271_GPIO1OUT);
+ if (ret)
+ return ret;
+
+ ret = max9271_clear_gpios(&dev->serializer, MAX9271_GPIO1OUT);
if (ret)
return ret;
+ usleep_range(200, 500);
- ret = max9271_clear_gpios(dev->serializer, MAX9271_GPIO1OUT);
+ ret = max9271_configure_gmsl_link(&dev->serializer);
if (ret)
return ret;
- usleep_range(10000, 15000);
- ret = max9271_set_gpios(dev->serializer, MAX9271_GPIO1OUT);
+ ret = max9271_verify_id(&dev->serializer);
+ if (ret < 0)
+ return ret;
+
+ ret = max9271_set_address(&dev->serializer, dev->addrs[0]);
+ if (ret < 0)
+ return ret;
+ dev->serializer.client->addr = dev->addrs[0];
+
+ /*
+ * Release ov10635 from reset and initialize it. The image sensor
+ * requires at least 2048 XVCLK cycles (85 micro-seconds at 24MHz)
+ * before being available. Stay safe and wait up to 500 micro-seconds.
+ */
+ ret = max9271_set_gpios(&dev->serializer, MAX9271_GPIO1OUT);
if (ret)
return ret;
- usleep_range(10000, 15000);
+ usleep_range(100, 500);
again:
ret = ov10635_read16(dev, OV10635_PID);
@@ -539,9 +547,21 @@ again:
if (ret)
return ret;
- dev_info(dev->dev, "Identified MAX9271 + OV10635 device\n");
+ dev_info(dev->dev, "Identified RDACM20 camera module\n");
- return 0;
+ /*
+ * Set reverse channel high threshold to increase noise immunity.
+ *
+ * This should be compensated by increasing the reverse channel
+ * amplitude on the remote deserializer side.
+ *
+ * TODO Inspect the embedded MCU programming sequence to make sure
+ * there are no conflicts with the configuration applied here.
+ *
+ * TODO Clarify the embedded MCU startup delay to avoid write
+ * collisions on the I2C bus.
+ */
+ return max9271_set_high_threshold(&dev->serializer, true);
}
static int rdacm20_probe(struct i2c_client *client)
@@ -554,13 +574,7 @@ static int rdacm20_probe(struct i2c_client *client)
if (!dev)
return -ENOMEM;
dev->dev = &client->dev;
-
- dev->serializer = devm_kzalloc(&client->dev, sizeof(*dev->serializer),
- GFP_KERNEL);
- if (!dev->serializer)
- return -ENOMEM;
-
- dev->serializer->client = client;
+ dev->serializer.client = client;
ret = of_property_read_u32_array(client->dev.of_node, "reg",
dev->addrs, 2);
diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c
index 179d107f494c..12ec5467ed1e 100644
--- a/drivers/media/i2c/rdacm21.c
+++ b/drivers/media/i2c/rdacm21.c
@@ -69,6 +69,7 @@
#define OV490_ISP_VSIZE_LOW 0x80820062
#define OV490_ISP_VSIZE_HIGH 0x80820063
+#define OV10640_PID_TIMEOUT 20
#define OV10640_ID_HIGH 0xa6
#define OV10640_CHIP_ID 0x300a
#define OV10640_PIXEL_RATE 55000000
@@ -281,7 +282,7 @@ static int rdacm21_s_stream(struct v4l2_subdev *sd, int enable)
}
static int rdacm21_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index > 0)
@@ -293,7 +294,7 @@ static int rdacm21_enum_mbus_code(struct v4l2_subdev *sd,
}
static int rdacm21_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -329,30 +330,51 @@ static const struct v4l2_subdev_ops rdacm21_subdev_ops = {
.pad = &rdacm21_subdev_pad_ops,
};
-static int ov10640_initialize(struct rdacm21_device *dev)
+static void ov10640_power_up(struct rdacm21_device *dev)
{
- u8 val;
-
- /* Power-up OV10640 by setting RESETB and PWDNB pins high. */
+ /* Enable GPIO0#0 (reset) and GPIO1#0 (pwdn) as output lines. */
ov490_write_reg(dev, OV490_GPIO_SEL0, OV490_GPIO0);
ov490_write_reg(dev, OV490_GPIO_SEL1, OV490_SPWDN0);
ov490_write_reg(dev, OV490_GPIO_DIRECTION0, OV490_GPIO0);
ov490_write_reg(dev, OV490_GPIO_DIRECTION1, OV490_SPWDN0);
+
+ /* Power up OV10640 and then reset it. */
+ ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE1, OV490_SPWDN0);
+ usleep_range(1500, 3000);
+
+ ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, 0x00);
+ usleep_range(1500, 3000);
ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, OV490_GPIO0);
- ov490_write_reg(dev, OV490_GPIO_OUTPUT_VALUE0, OV490_SPWDN0);
usleep_range(3000, 5000);
+}
- /* Read OV10640 ID to test communications. */
- ov490_write_reg(dev, OV490_SCCB_SLAVE0_DIR, OV490_SCCB_SLAVE_READ);
- ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_HIGH, OV10640_CHIP_ID >> 8);
- ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW, OV10640_CHIP_ID & 0xff);
-
- /* Trigger SCCB slave transaction and give it some time to complete. */
- ov490_write_reg(dev, OV490_HOST_CMD, OV490_HOST_CMD_TRIGGER);
- usleep_range(1000, 1500);
+static int ov10640_check_id(struct rdacm21_device *dev)
+{
+ unsigned int i;
+ u8 val;
- ov490_read_reg(dev, OV490_SCCB_SLAVE0_DIR, &val);
- if (val != OV10640_ID_HIGH) {
+ /* Read OV10640 ID to test communications. */
+ for (i = 0; i < OV10640_PID_TIMEOUT; ++i) {
+ ov490_write_reg(dev, OV490_SCCB_SLAVE0_DIR,
+ OV490_SCCB_SLAVE_READ);
+ ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_HIGH,
+ OV10640_CHIP_ID >> 8);
+ ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW,
+ OV10640_CHIP_ID & 0xff);
+
+ /*
+ * Trigger SCCB slave transaction and give it some time
+ * to complete.
+ */
+ ov490_write_reg(dev, OV490_HOST_CMD, OV490_HOST_CMD_TRIGGER);
+ usleep_range(1000, 1500);
+
+ ov490_read_reg(dev, OV490_SCCB_SLAVE0_DIR, &val);
+ if (val == OV10640_ID_HIGH)
+ break;
+ usleep_range(1000, 1500);
+ }
+ if (i == OV10640_PID_TIMEOUT) {
dev_err(dev->dev, "OV10640 ID mismatch: (0x%02x)\n", val);
return -ENODEV;
}
@@ -368,6 +390,8 @@ static int ov490_initialize(struct rdacm21_device *dev)
unsigned int i;
int ret;
+ ov10640_power_up(dev);
+
/*
* Read OV490 Id to test communications. Give it up to 40msec to
* exit from reset.
@@ -405,7 +429,7 @@ static int ov490_initialize(struct rdacm21_device *dev)
return -ENODEV;
}
- ret = ov10640_initialize(dev);
+ ret = ov10640_check_id(dev);
if (ret)
return ret;
@@ -450,10 +474,7 @@ static int rdacm21_initialize(struct rdacm21_device *dev)
{
int ret;
- /* Verify communication with the MAX9271: ping to wakeup. */
- dev->serializer.client->addr = MAX9271_DEFAULT_ADDR;
- i2c_smbus_read_byte(dev->serializer.client);
- usleep_range(3000, 5000);
+ max9271_wake_up(&dev->serializer);
/* Enable reverse channel and disable the serial link. */
ret = max9271_set_serial_link(&dev->serializer, false);
@@ -472,7 +493,10 @@ static int rdacm21_initialize(struct rdacm21_device *dev)
if (ret)
return ret;
- /* Enable GPIO1 and hold OV490 in reset during max9271 configuration. */
+ /*
+ * Enable GPIO1 and hold OV490 in reset during max9271 configuration.
+ * The reset signal has to be asserted for at least 250 useconds.
+ */
ret = max9271_enable_gpios(&dev->serializer, MAX9271_GPIO1OUT);
if (ret)
return ret;
@@ -480,6 +504,7 @@ static int rdacm21_initialize(struct rdacm21_device *dev)
ret = max9271_clear_gpios(&dev->serializer, MAX9271_GPIO1OUT);
if (ret)
return ret;
+ usleep_range(250, 500);
ret = max9271_configure_gmsl_link(&dev->serializer);
if (ret)
diff --git a/drivers/media/i2c/rj54n1cb0c.c b/drivers/media/i2c/rj54n1cb0c.c
index 4cc51e001874..2e4018c26912 100644
--- a/drivers/media/i2c/rj54n1cb0c.c
+++ b/drivers/media/i2c/rj54n1cb0c.c
@@ -488,7 +488,7 @@ static int reg_write_multiple(struct i2c_client *client,
}
static int rj54n1_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index >= ARRAY_SIZE(rj54n1_colour_fmts))
@@ -541,7 +541,7 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
s32 *out_w, s32 *out_h);
static int rj54n1_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -578,7 +578,7 @@ static int rj54n1_set_selection(struct v4l2_subdev *sd,
}
static int rj54n1_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -603,7 +603,7 @@ static int rj54n1_get_selection(struct v4l2_subdev *sd,
}
static int rj54n1_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -973,7 +973,7 @@ static int rj54n1_reg_init(struct i2c_client *client)
}
static int rj54n1_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -1009,7 +1009,7 @@ static int rj54n1_set_fmt(struct v4l2_subdev *sd,
&mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *mf;
+ sd_state->pads->try_fmt = *mf;
return 0;
}
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index 5b4c4a3547c9..e2b88c5e4f98 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -817,7 +817,7 @@ static const struct s5c73m3_frame_size *s5c73m3_find_frame_size(
}
static void s5c73m3_oif_try_format(struct s5c73m3 *state,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt,
const struct s5c73m3_frame_size **fs)
{
@@ -844,8 +844,8 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state,
*fs = state->oif_pix_size[RES_ISP];
else
*fs = s5c73m3_find_frame_size(
- v4l2_subdev_get_try_format(sd, cfg,
- OIF_ISP_PAD),
+ v4l2_subdev_get_try_format(sd, sd_state,
+ OIF_ISP_PAD),
RES_ISP);
break;
}
@@ -854,7 +854,7 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state,
}
static void s5c73m3_try_format(struct s5c73m3 *state,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt,
const struct s5c73m3_frame_size **fs)
{
@@ -946,7 +946,7 @@ static int s5c73m3_oif_s_frame_interval(struct v4l2_subdev *sd,
}
static int s5c73m3_oif_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
@@ -984,7 +984,7 @@ static int s5c73m3_oif_get_pad_code(int pad, int index)
}
static int s5c73m3_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd);
@@ -992,7 +992,8 @@ static int s5c73m3_get_fmt(struct v4l2_subdev *sd,
u32 code;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
+ fmt->pad);
return 0;
}
@@ -1018,7 +1019,7 @@ static int s5c73m3_get_fmt(struct v4l2_subdev *sd,
}
static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
@@ -1026,7 +1027,8 @@ static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd,
u32 code;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
+ fmt->pad);
return 0;
}
@@ -1056,7 +1058,7 @@ static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd,
}
static int s5c73m3_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
const struct s5c73m3_frame_size *frame_size = NULL;
@@ -1066,10 +1068,10 @@ static int s5c73m3_set_fmt(struct v4l2_subdev *sd,
mutex_lock(&state->lock);
- s5c73m3_try_format(state, cfg, fmt, &frame_size);
+ s5c73m3_try_format(state, sd_state, fmt, &frame_size);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*mf = fmt->format;
} else {
switch (fmt->pad) {
@@ -1095,7 +1097,7 @@ static int s5c73m3_set_fmt(struct v4l2_subdev *sd,
}
static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
const struct s5c73m3_frame_size *frame_size = NULL;
@@ -1105,13 +1107,14 @@ static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd,
mutex_lock(&state->lock);
- s5c73m3_oif_try_format(state, cfg, fmt, &frame_size);
+ s5c73m3_oif_try_format(state, sd_state, fmt, &frame_size);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*mf = fmt->format;
if (fmt->pad == OIF_ISP_PAD) {
- mf = v4l2_subdev_get_try_format(sd, cfg, OIF_SOURCE_PAD);
+ mf = v4l2_subdev_get_try_format(sd, sd_state,
+ OIF_SOURCE_PAD);
mf->width = fmt->format.width;
mf->height = fmt->format.height;
}
@@ -1183,7 +1186,7 @@ static int s5c73m3_oif_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
}
static int s5c73m3_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
static const int codes[] = {
@@ -1199,7 +1202,7 @@ static int s5c73m3_enum_mbus_code(struct v4l2_subdev *sd,
}
static int s5c73m3_oif_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
int ret;
@@ -1214,7 +1217,7 @@ static int s5c73m3_oif_enum_mbus_code(struct v4l2_subdev *sd,
}
static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
int idx;
@@ -1241,7 +1244,7 @@ static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd,
}
static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
@@ -1259,7 +1262,7 @@ static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd,
if (fse->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, cfg,
+ mf = v4l2_subdev_get_try_format(sd, sd_state,
OIF_ISP_PAD);
w = mf->width;
@@ -1315,11 +1318,11 @@ static int s5c73m3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, fh->pad, S5C73M3_ISP_PAD);
+ mf = v4l2_subdev_get_try_format(sd, fh->state, S5C73M3_ISP_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
S5C73M3_ISP_FMT);
- mf = v4l2_subdev_get_try_format(sd, fh->pad, S5C73M3_JPEG_PAD);
+ mf = v4l2_subdev_get_try_format(sd, fh->state, S5C73M3_JPEG_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1],
S5C73M3_JPEG_FMT);
@@ -1330,15 +1333,15 @@ static int s5c73m3_oif_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_ISP_PAD);
+ mf = v4l2_subdev_get_try_format(sd, fh->state, OIF_ISP_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
S5C73M3_ISP_FMT);
- mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_JPEG_PAD);
+ mf = v4l2_subdev_get_try_format(sd, fh->state, OIF_JPEG_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1],
S5C73M3_JPEG_FMT);
- mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_SOURCE_PAD);
+ mf = v4l2_subdev_get_try_format(sd, fh->state, OIF_SOURCE_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
S5C73M3_ISP_FMT);
return 0;
@@ -1386,7 +1389,7 @@ static int __s5c73m3_power_on(struct s5c73m3 *state)
s5c73m3_gpio_deassert(state, STBY);
usleep_range(100, 200);
- s5c73m3_gpio_deassert(state, RST);
+ s5c73m3_gpio_deassert(state, RSET);
usleep_range(50, 100);
return 0;
@@ -1401,7 +1404,7 @@ static int __s5c73m3_power_off(struct s5c73m3 *state)
{
int i, ret;
- if (s5c73m3_gpio_assert(state, RST))
+ if (s5c73m3_gpio_assert(state, RSET))
usleep_range(10, 50);
if (s5c73m3_gpio_assert(state, STBY))
@@ -1606,7 +1609,7 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state)
state->mclk_frequency = pdata->mclk_frequency;
state->gpio[STBY] = pdata->gpio_stby;
- state->gpio[RST] = pdata->gpio_reset;
+ state->gpio[RSET] = pdata->gpio_reset;
return 0;
}
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h
index ef7e85b34263..c3fcfdd3ea66 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3.h
+++ b/drivers/media/i2c/s5c73m3/s5c73m3.h
@@ -353,7 +353,7 @@ struct s5c73m3_ctrls {
enum s5c73m3_gpio_id {
STBY,
- RST,
+ RSET,
GPIO_NUM,
};
diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c
index b2d53417badf..af9a305242cd 100644
--- a/drivers/media/i2c/s5k4ecgx.c
+++ b/drivers/media/i2c/s5k4ecgx.c
@@ -173,7 +173,7 @@ static const char * const s5k4ecgx_supply_names[] = {
enum s5k4ecgx_gpio_id {
STBY,
- RST,
+ RSET,
GPIO_NUM,
};
@@ -476,7 +476,7 @@ static int __s5k4ecgx_power_on(struct s5k4ecgx *priv)
if (s5k4ecgx_gpio_set_value(priv, STBY, priv->gpio[STBY].level))
usleep_range(30, 50);
- if (s5k4ecgx_gpio_set_value(priv, RST, priv->gpio[RST].level))
+ if (s5k4ecgx_gpio_set_value(priv, RSET, priv->gpio[RSET].level))
usleep_range(30, 50);
return 0;
@@ -484,7 +484,7 @@ static int __s5k4ecgx_power_on(struct s5k4ecgx *priv)
static int __s5k4ecgx_power_off(struct s5k4ecgx *priv)
{
- if (s5k4ecgx_gpio_set_value(priv, RST, !priv->gpio[RST].level))
+ if (s5k4ecgx_gpio_set_value(priv, RSET, !priv->gpio[RSET].level))
usleep_range(30, 50);
if (s5k4ecgx_gpio_set_value(priv, STBY, !priv->gpio[STBY].level))
@@ -525,7 +525,7 @@ static int s5k4ecgx_try_frame_size(struct v4l2_mbus_framefmt *mf,
}
static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(s5k4ecgx_formats))
@@ -535,15 +535,16 @@ static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
-static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
+static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
{
struct s5k4ecgx *priv = to_s5k4ecgx(sd);
struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- if (cfg) {
- mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ if (sd_state) {
+ mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
fmt->format = *mf;
}
return 0;
@@ -575,7 +576,8 @@ static const struct s5k4ecgx_pixfmt *s5k4ecgx_try_fmt(struct v4l2_subdev *sd,
return &s5k4ecgx_formats[i];
}
-static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct s5k4ecgx *priv = to_s5k4ecgx(sd);
@@ -590,8 +592,8 @@ static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_confi
fmt->format.field = V4L2_FIELD_NONE;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- if (cfg) {
- mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ if (sd_state) {
+ mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
*mf = fmt->format;
}
return 0;
@@ -686,7 +688,9 @@ static int s5k4ecgx_registered(struct v4l2_subdev *sd)
*/
static int s5k4ecgx_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd,
+ fh->state,
+ 0);
mf->width = s5k4ecgx_prev_sizes[0].size.width;
mf->height = s5k4ecgx_prev_sizes[0].size.height;
@@ -872,7 +876,7 @@ static int s5k4ecgx_config_gpios(struct s5k4ecgx *priv,
int ret;
priv->gpio[STBY].gpio = -EINVAL;
- priv->gpio[RST].gpio = -EINVAL;
+ priv->gpio[RSET].gpio = -EINVAL;
ret = s5k4ecgx_config_gpio(gpio->gpio, gpio->level, "S5K4ECGX_STBY");
@@ -891,7 +895,7 @@ static int s5k4ecgx_config_gpios(struct s5k4ecgx *priv,
s5k4ecgx_free_gpios(priv);
return ret;
}
- priv->gpio[RST] = *gpio;
+ priv->gpio[RSET] = *gpio;
if (gpio_is_valid(gpio->gpio))
gpio_set_value(gpio->gpio, 0);
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 6e702b57c37d..6a5dceb699a8 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -235,7 +235,7 @@ struct s5k5baf_gpio {
enum s5k5baf_gpio_id {
STBY,
- RST,
+ RSET,
NUM_GPIOS,
};
@@ -969,7 +969,7 @@ static int s5k5baf_power_on(struct s5k5baf *state)
s5k5baf_gpio_deassert(state, STBY);
usleep_range(50, 100);
- s5k5baf_gpio_deassert(state, RST);
+ s5k5baf_gpio_deassert(state, RSET);
return 0;
err_reg_dis:
@@ -987,7 +987,7 @@ static int s5k5baf_power_off(struct s5k5baf *state)
state->apply_cfg = 0;
state->apply_crop = 0;
- s5k5baf_gpio_assert(state, RST);
+ s5k5baf_gpio_assert(state, RSET);
s5k5baf_gpio_assert(state, STBY);
if (!IS_ERR(state->clock))
@@ -1180,7 +1180,7 @@ static int s5k5baf_s_frame_interval(struct v4l2_subdev *sd,
* V4L2 subdev pad level and video operations
*/
static int s5k5baf_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
if (fie->index > S5K5BAF_MAX_FR_TIME - S5K5BAF_MIN_FR_TIME ||
@@ -1199,7 +1199,7 @@ static int s5k5baf_enum_frame_interval(struct v4l2_subdev *sd,
}
static int s5k5baf_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad == PAD_CIS) {
@@ -1217,7 +1217,7 @@ static int s5k5baf_enum_mbus_code(struct v4l2_subdev *sd,
}
static int s5k5baf_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
int i;
@@ -1274,15 +1274,16 @@ static int s5k5baf_try_isp_format(struct v4l2_mbus_framefmt *mf)
return pixfmt;
}
-static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
+static int s5k5baf_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
{
struct s5k5baf *state = to_s5k5baf(sd);
const struct s5k5baf_pixfmt *pixfmt;
struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
fmt->format = *mf;
return 0;
}
@@ -1304,8 +1305,9 @@ static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
return 0;
}
-static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
+static int s5k5baf_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *mf = &fmt->format;
struct s5k5baf *state = to_s5k5baf(sd);
@@ -1315,7 +1317,7 @@ static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
mf->field = V4L2_FIELD_NONE;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = *mf;
+ *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = *mf;
return 0;
}
@@ -1367,7 +1369,7 @@ static int s5k5baf_is_bound_target(u32 target)
}
static int s5k5baf_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
enum selection_rect rtype;
@@ -1387,9 +1389,11 @@ static int s5k5baf_get_selection(struct v4l2_subdev *sd,
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
if (rtype == R_COMPOSE)
- sel->r = *v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
+ sel->r = *v4l2_subdev_get_try_compose(sd, sd_state,
+ sel->pad);
else
- sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+ sel->r = *v4l2_subdev_get_try_crop(sd, sd_state,
+ sel->pad);
return 0;
}
@@ -1458,7 +1462,7 @@ static bool s5k5baf_cmp_rect(const struct v4l2_rect *r1,
}
static int s5k5baf_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
static enum selection_rect rtype;
@@ -1479,9 +1483,12 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
rects = (struct v4l2_rect * []) {
&s5k5baf_cis_rect,
- v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS),
- v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT)
+ v4l2_subdev_get_try_crop(sd, sd_state,
+ PAD_CIS),
+ v4l2_subdev_get_try_compose(sd, sd_state,
+ PAD_CIS),
+ v4l2_subdev_get_try_crop(sd, sd_state,
+ PAD_OUT)
};
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
@@ -1699,22 +1706,22 @@ static int s5k5baf_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, fh->pad, PAD_CIS);
+ mf = v4l2_subdev_get_try_format(sd, fh->state, PAD_CIS);
s5k5baf_try_cis_format(mf);
if (s5k5baf_is_cis_subdev(sd))
return 0;
- mf = v4l2_subdev_get_try_format(sd, fh->pad, PAD_OUT);
+ mf = v4l2_subdev_get_try_format(sd, fh->state, PAD_OUT);
mf->colorspace = s5k5baf_formats[0].colorspace;
mf->code = s5k5baf_formats[0].code;
mf->width = s5k5baf_cis_rect.width;
mf->height = s5k5baf_cis_rect.height;
mf->field = V4L2_FIELD_NONE;
- *v4l2_subdev_get_try_crop(sd, fh->pad, PAD_CIS) = s5k5baf_cis_rect;
- *v4l2_subdev_get_try_compose(sd, fh->pad, PAD_CIS) = s5k5baf_cis_rect;
- *v4l2_subdev_get_try_crop(sd, fh->pad, PAD_OUT) = s5k5baf_cis_rect;
+ *v4l2_subdev_get_try_crop(sd, fh->state, PAD_CIS) = s5k5baf_cis_rect;
+ *v4l2_subdev_get_try_compose(sd, fh->state, PAD_CIS) = s5k5baf_cis_rect;
+ *v4l2_subdev_get_try_crop(sd, fh->state, PAD_OUT) = s5k5baf_cis_rect;
return 0;
}
diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c
index f26c168ef942..b97dd6149e90 100644
--- a/drivers/media/i2c/s5k6a3.c
+++ b/drivers/media/i2c/s5k6a3.c
@@ -99,7 +99,7 @@ static const struct v4l2_mbus_framefmt *find_sensor_format(
}
static int s5k6a3_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(s5k6a3_formats))
@@ -123,17 +123,18 @@ static void s5k6a3_try_format(struct v4l2_mbus_framefmt *mf)
}
static struct v4l2_mbus_framefmt *__s5k6a3_get_format(
- struct s5k6a3 *sensor, struct v4l2_subdev_pad_config *cfg,
+ struct s5k6a3 *sensor, struct v4l2_subdev_state *sd_state,
u32 pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return cfg ? v4l2_subdev_get_try_format(&sensor->subdev, cfg, pad) : NULL;
+ return sd_state ? v4l2_subdev_get_try_format(&sensor->subdev,
+ sd_state, pad) : NULL;
return &sensor->format;
}
static int s5k6a3_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct s5k6a3 *sensor = sd_to_s5k6a3(sd);
@@ -141,7 +142,7 @@ static int s5k6a3_set_fmt(struct v4l2_subdev *sd,
s5k6a3_try_format(&fmt->format);
- mf = __s5k6a3_get_format(sensor, cfg, fmt->pad, fmt->which);
+ mf = __s5k6a3_get_format(sensor, sd_state, fmt->pad, fmt->which);
if (mf) {
mutex_lock(&sensor->lock);
*mf = fmt->format;
@@ -151,13 +152,13 @@ static int s5k6a3_set_fmt(struct v4l2_subdev *sd,
}
static int s5k6a3_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct s5k6a3 *sensor = sd_to_s5k6a3(sd);
struct v4l2_mbus_framefmt *mf;
- mf = __s5k6a3_get_format(sensor, cfg, fmt->pad, fmt->which);
+ mf = __s5k6a3_get_format(sensor, sd_state, fmt->pad, fmt->which);
mutex_lock(&sensor->lock);
fmt->format = *mf;
@@ -173,7 +174,9 @@ static const struct v4l2_subdev_pad_ops s5k6a3_pad_ops = {
static int s5k6a3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd,
+ fh->state,
+ 0);
*format = s5k6a3_formats[0];
format->width = S5K6A3_DEFAULT_WIDTH;
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
index 038e38500760..105a4b7d8354 100644
--- a/drivers/media/i2c/s5k6aa.c
+++ b/drivers/media/i2c/s5k6aa.c
@@ -177,7 +177,7 @@ static const char * const s5k6aa_supply_names[] = {
enum s5k6aa_gpio_id {
STBY,
- RST,
+ RSET,
GPIO_NUM,
};
@@ -841,7 +841,7 @@ static int __s5k6aa_power_on(struct s5k6aa *s5k6aa)
ret = s5k6aa->s_power(1);
usleep_range(4000, 5000);
- if (s5k6aa_gpio_deassert(s5k6aa, RST))
+ if (s5k6aa_gpio_deassert(s5k6aa, RSET))
msleep(20);
return ret;
@@ -851,7 +851,7 @@ static int __s5k6aa_power_off(struct s5k6aa *s5k6aa)
{
int ret;
- if (s5k6aa_gpio_assert(s5k6aa, RST))
+ if (s5k6aa_gpio_assert(s5k6aa, RSET))
usleep_range(100, 150);
if (s5k6aa->s_power) {
@@ -997,7 +997,7 @@ static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd,
* V4L2 subdev pad level and video operations
*/
static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1024,7 +1024,7 @@ static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd,
}
static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(s5k6aa_formats))
@@ -1035,7 +1035,7 @@ static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd,
}
static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
int i = ARRAY_SIZE(s5k6aa_formats);
@@ -1057,14 +1057,15 @@ static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd,
}
static struct v4l2_rect *
-__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_pad_config *cfg,
+__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa,
+ struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
return &s5k6aa->ccd_rect;
WARN_ON(which != V4L2_SUBDEV_FORMAT_TRY);
- return v4l2_subdev_get_try_crop(&s5k6aa->sd, cfg, 0);
+ return v4l2_subdev_get_try_crop(&s5k6aa->sd, sd_state, 0);
}
static void s5k6aa_try_format(struct s5k6aa *s5k6aa,
@@ -1088,7 +1089,8 @@ static void s5k6aa_try_format(struct s5k6aa *s5k6aa,
mf->field = V4L2_FIELD_NONE;
}
-static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int s5k6aa_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1097,7 +1099,7 @@ static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
memset(fmt->reserved, 0, sizeof(fmt->reserved));
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
fmt->format = *mf;
return 0;
}
@@ -1109,7 +1111,8 @@ static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
return 0;
}
-static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int s5k6aa_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1122,8 +1125,8 @@ static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
s5k6aa_try_format(s5k6aa, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
- crop = v4l2_subdev_get_try_crop(sd, cfg, 0);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ crop = v4l2_subdev_get_try_crop(sd, sd_state, 0);
} else {
if (s5k6aa->streaming) {
ret = -EBUSY;
@@ -1163,7 +1166,7 @@ static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
}
static int s5k6aa_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1175,7 +1178,7 @@ static int s5k6aa_get_selection(struct v4l2_subdev *sd,
memset(sel->reserved, 0, sizeof(sel->reserved));
mutex_lock(&s5k6aa->lock);
- rect = __s5k6aa_get_crop_rect(s5k6aa, cfg, sel->which);
+ rect = __s5k6aa_get_crop_rect(s5k6aa, sd_state, sel->which);
sel->r = *rect;
mutex_unlock(&s5k6aa->lock);
@@ -1186,7 +1189,7 @@ static int s5k6aa_get_selection(struct v4l2_subdev *sd,
}
static int s5k6aa_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct s5k6aa *s5k6aa = to_s5k6aa(sd);
@@ -1198,13 +1201,13 @@ static int s5k6aa_set_selection(struct v4l2_subdev *sd,
return -EINVAL;
mutex_lock(&s5k6aa->lock);
- crop_r = __s5k6aa_get_crop_rect(s5k6aa, cfg, sel->which);
+ crop_r = __s5k6aa_get_crop_rect(s5k6aa, sd_state, sel->which);
if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
mf = &s5k6aa->preset->mbus_fmt;
s5k6aa->apply_crop = 1;
} else {
- mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
}
v4l_bound_align_image(&sel->r.width, mf->width,
S5K6AA_WIN_WIDTH_MAX, 1,
@@ -1425,8 +1428,10 @@ static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa)
*/
static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
- struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0);
+ struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd,
+ fh->state,
+ 0);
+ struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
format->colorspace = s5k6aa_formats[0].colorspace;
format->code = s5k6aa_formats[0].code;
@@ -1510,7 +1515,7 @@ static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa,
int ret;
s5k6aa->gpio[STBY].gpio = -EINVAL;
- s5k6aa->gpio[RST].gpio = -EINVAL;
+ s5k6aa->gpio[RSET].gpio = -EINVAL;
gpio = &pdata->gpio_stby;
if (gpio_is_valid(gpio->gpio)) {
@@ -1533,7 +1538,7 @@ static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa,
if (ret < 0)
return ret;
- s5k6aa->gpio[RST] = *gpio;
+ s5k6aa->gpio[RSET] = *gpio;
}
return 0;
diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c
index ecb491d5f2ab..d1e0716bdfff 100644
--- a/drivers/media/i2c/saa6588.c
+++ b/drivers/media/i2c/saa6588.c
@@ -380,7 +380,7 @@ static void saa6588_configure(struct saa6588 *s)
/* ---------------------------------------------------------------------- */
-static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+static long saa6588_command(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct saa6588 *s = to_saa6588(sd);
struct saa6588_command *a = arg;
@@ -433,7 +433,7 @@ static int saa6588_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops saa6588_core_ops = {
- .ioctl = saa6588_ioctl,
+ .command = saa6588_command,
};
static const struct v4l2_subdev_tuner_ops saa6588_tuner_ops = {
diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c
index 6171ced809bb..a7f043cad149 100644
--- a/drivers/media/i2c/saa6752hs.c
+++ b/drivers/media/i2c/saa6752hs.c
@@ -543,7 +543,7 @@ static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes)
}
static int saa6752hs_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *f = &format->format;
@@ -563,7 +563,7 @@ static int saa6752hs_get_fmt(struct v4l2_subdev *sd,
}
static int saa6752hs_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *f = &format->format;
@@ -595,7 +595,7 @@ static int saa6752hs_set_fmt(struct v4l2_subdev *sd,
f->colorspace = V4L2_COLORSPACE_SMPTE170M;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *f;
+ sd_state->pads->try_fmt = *f;
return 0;
}
diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c
index 88dc6baac639..a958bbc2c33d 100644
--- a/drivers/media/i2c/saa7115.c
+++ b/drivers/media/i2c/saa7115.c
@@ -1167,7 +1167,7 @@ static int saa711x_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
}
static int saa711x_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c
index ba103a6a1875..adf905360171 100644
--- a/drivers/media/i2c/saa717x.c
+++ b/drivers/media/i2c/saa717x.c
@@ -980,7 +980,7 @@ static int saa717x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regi
#endif
static int saa717x_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c
index 46924024faa8..19c0252df2f1 100644
--- a/drivers/media/i2c/sr030pc30.c
+++ b/drivers/media/i2c/sr030pc30.c
@@ -468,7 +468,7 @@ static int sr030pc30_s_ctrl(struct v4l2_ctrl *ctrl)
}
static int sr030pc30_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (!code || code->pad ||
@@ -480,7 +480,7 @@ static int sr030pc30_enum_mbus_code(struct v4l2_subdev *sd,
}
static int sr030pc30_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf;
@@ -525,7 +525,7 @@ static const struct sr030pc30_format *try_fmt(struct v4l2_subdev *sd,
/* Return nearest media bus frame format. */
static int sr030pc30_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct sr030pc30_info *info = sd ? to_sr030pc30(sd) : NULL;
@@ -541,7 +541,7 @@ static int sr030pc30_set_fmt(struct v4l2_subdev *sd,
fmt = try_fmt(sd, mf);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *mf;
+ sd_state->pads->try_fmt = *mf;
return 0;
}
diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c
index 7f07ef56fbbd..f630b88cbfaa 100644
--- a/drivers/media/i2c/st-mipid02.c
+++ b/drivers/media/i2c/st-mipid02.c
@@ -643,7 +643,7 @@ out:
}
static int mipid02_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct mipid02_dev *bridge = to_mipid02_dev(sd);
@@ -670,7 +670,7 @@ static int mipid02_enum_mbus_code(struct v4l2_subdev *sd,
}
static int mipid02_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
@@ -687,7 +687,8 @@ static int mipid02_get_fmt(struct v4l2_subdev *sd,
return -EINVAL;
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt = v4l2_subdev_get_try_format(&bridge->sd, cfg, format->pad);
+ fmt = v4l2_subdev_get_try_format(&bridge->sd, sd_state,
+ format->pad);
else
fmt = &bridge->fmt;
@@ -704,7 +705,7 @@ static int mipid02_get_fmt(struct v4l2_subdev *sd,
}
static void mipid02_set_fmt_source(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct mipid02_dev *bridge = to_mipid02_dev(sd);
@@ -718,11 +719,11 @@ static void mipid02_set_fmt_source(struct v4l2_subdev *sd,
if (format->which != V4L2_SUBDEV_FORMAT_TRY)
return;
- *v4l2_subdev_get_try_format(sd, cfg, format->pad) = format->format;
+ *v4l2_subdev_get_try_format(sd, sd_state, format->pad) = format->format;
}
static void mipid02_set_fmt_sink(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct mipid02_dev *bridge = to_mipid02_dev(sd);
@@ -731,7 +732,7 @@ static void mipid02_set_fmt_sink(struct v4l2_subdev *sd,
format->format.code = get_fmt_code(format->format.code);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
else
fmt = &bridge->fmt;
@@ -739,7 +740,7 @@ static void mipid02_set_fmt_sink(struct v4l2_subdev *sd,
}
static int mipid02_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct mipid02_dev *bridge = to_mipid02_dev(sd);
@@ -762,9 +763,9 @@ static int mipid02_set_fmt(struct v4l2_subdev *sd,
}
if (format->pad == MIPID02_SOURCE)
- mipid02_set_fmt_source(sd, cfg, format);
+ mipid02_set_fmt_source(sd, sd_state, format);
else
- mipid02_set_fmt_sink(sd, cfg, format);
+ mipid02_set_fmt_sink(sd, sd_state, format);
error:
mutex_unlock(&bridge->lock);
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 1b309bb743c7..3205cd8298dd 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -1649,7 +1649,7 @@ static int tc358743_s_stream(struct v4l2_subdev *sd, int enable)
/* --------------- PAD OPS --------------- */
static int tc358743_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
switch (code->index) {
@@ -1666,7 +1666,7 @@ static int tc358743_enum_mbus_code(struct v4l2_subdev *sd,
}
static int tc358743_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct tc358743_state *state = to_state(sd);
@@ -1702,13 +1702,13 @@ static int tc358743_get_fmt(struct v4l2_subdev *sd,
}
static int tc358743_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct tc358743_state *state = to_state(sd);
u32 code = format->format.code; /* is overwritten by get_fmt */
- int ret = tc358743_get_fmt(sd, cfg, format);
+ int ret = tc358743_get_fmt(sd, sd_state, format);
format->format.code = code;
@@ -1974,6 +1974,7 @@ static int tc358743_probe_of(struct tc358743_state *state)
bps_pr_lane = 2 * endpoint.link_frequencies[0];
if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) {
dev_err(dev, "unsupported bps per lane: %u bps\n", bps_pr_lane);
+ ret = -EINVAL;
goto disable_clk;
}
diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c
index 89bb7e6dc7a4..91e6db847bb5 100644
--- a/drivers/media/i2c/tda1997x.c
+++ b/drivers/media/i2c/tda1997x.c
@@ -1718,19 +1718,19 @@ static const struct v4l2_subdev_video_ops tda1997x_video_ops = {
*/
static int tda1997x_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct tda1997x_state *state = to_state(sd);
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
mf->code = state->mbus_codes[0];
return 0;
}
static int tda1997x_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct tda1997x_state *state = to_state(sd);
@@ -1762,7 +1762,7 @@ static void tda1997x_fill_format(struct tda1997x_state *state,
}
static int tda1997x_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct tda1997x_state *state = to_state(sd);
@@ -1775,7 +1775,7 @@ static int tda1997x_get_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
format->format.code = fmt->code;
} else
format->format.code = state->mbus_code;
@@ -1784,7 +1784,7 @@ static int tda1997x_get_format(struct v4l2_subdev *sd,
}
static int tda1997x_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct tda1997x_state *state = to_state(sd);
@@ -1809,7 +1809,7 @@ static int tda1997x_set_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
*fmt = format->format;
} else {
int ret = tda1997x_setup_format(state, format->format.code);
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index a7fbe5b400c2..cee60f945036 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -853,13 +853,13 @@ static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = {
/**
* tvp514x_enum_mbus_code() - V4L2 decoder interface handler for enum_mbus_code
* @sd: pointer to standard V4L2 sub-device structure
- * @cfg: pad configuration
+ * @sd_state: subdev state
* @code: pointer to v4l2_subdev_mbus_code_enum structure
*
* Enumertaes mbus codes supported
*/
static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
u32 pad = code->pad;
@@ -880,13 +880,13 @@ static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd,
/**
* tvp514x_get_pad_format() - V4L2 decoder interface handler for get pad format
* @sd: pointer to standard V4L2 sub-device structure
- * @cfg: pad configuration
+ * @sd_state: subdev state
* @format: pointer to v4l2_subdev_format structure
*
* Retrieves pad format which is active or tried based on requirement
*/
static int tvp514x_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
@@ -912,13 +912,13 @@ static int tvp514x_get_pad_format(struct v4l2_subdev *sd,
/**
* tvp514x_set_pad_format() - V4L2 decoder interface handler for set pad format
* @sd: pointer to standard V4L2 sub-device structure
- * @cfg: pad configuration
+ * @sd_state: subdev state
* @fmt: pointer to v4l2_subdev_format structure
*
* Set pad format for the output pad
*/
static int tvp514x_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index e26e3f544054..30c63552556d 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -1027,7 +1027,7 @@ static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop)
static struct v4l2_rect *
tvp5150_get_pad_crop(struct tvp5150 *decoder,
- struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+ struct v4l2_subdev_state *sd_state, unsigned int pad,
enum v4l2_subdev_format_whence which)
{
switch (which) {
@@ -1035,7 +1035,7 @@ tvp5150_get_pad_crop(struct tvp5150 *decoder,
return &decoder->rect;
case V4L2_SUBDEV_FORMAT_TRY:
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
- return v4l2_subdev_get_try_crop(&decoder->sd, cfg, pad);
+ return v4l2_subdev_get_try_crop(&decoder->sd, sd_state, pad);
#else
return ERR_PTR(-EINVAL);
#endif
@@ -1045,7 +1045,7 @@ tvp5150_get_pad_crop(struct tvp5150 *decoder,
}
static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *f;
@@ -1104,7 +1104,7 @@ static void tvp5150_set_hw_selection(struct v4l2_subdev *sd,
}
static int tvp5150_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct tvp5150 *decoder = to_tvp5150(sd);
@@ -1138,7 +1138,7 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
sel->which == V4L2_SUBDEV_FORMAT_TRY)
return 0;
- crop = tvp5150_get_pad_crop(decoder, cfg, sel->pad, sel->which);
+ crop = tvp5150_get_pad_crop(decoder, sd_state, sel->pad, sel->which);
if (IS_ERR(crop))
return PTR_ERR(crop);
@@ -1156,7 +1156,7 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
}
static int tvp5150_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
@@ -1180,7 +1180,7 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
sel->r.height = TVP5150_V_MAX_OTHERS;
return 0;
case V4L2_SEL_TGT_CROP:
- crop = tvp5150_get_pad_crop(decoder, cfg, sel->pad,
+ crop = tvp5150_get_pad_crop(decoder, sd_state, sel->pad,
sel->which);
if (IS_ERR(crop))
return PTR_ERR(crop);
@@ -1208,7 +1208,7 @@ static int tvp5150_get_mbus_config(struct v4l2_subdev *sd,
V4L2 subdev pad ops
****************************************************************************/
static int tvp5150_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct tvp5150 *decoder = to_tvp5150(sd);
v4l2_std_id std;
@@ -1229,7 +1229,7 @@ static int tvp5150_init_cfg(struct v4l2_subdev *sd,
}
static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index)
@@ -1240,7 +1240,7 @@ static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd,
}
static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct tvp5150 *decoder = to_tvp5150(sd);
@@ -1448,11 +1448,9 @@ static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
TVP5150_MISC_CTL_CLOCK_OE;
if (enable) {
- ret = pm_runtime_get_sync(sd->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(sd->dev);
+ ret = pm_runtime_resume_and_get(sd->dev);
+ if (ret < 0)
return ret;
- }
tvp5150_enable(sd);
@@ -1675,15 +1673,7 @@ err:
static int tvp5150_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- int ret;
-
- ret = pm_runtime_get_sync(sd->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(sd->dev);
- return ret;
- }
-
- return 0;
+ return pm_runtime_resume_and_get(sd->dev);
}
static int tvp5150_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index ada4ec5ef782..2de18833b07b 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -797,7 +797,8 @@ static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = {
* Enumerate supported digital video formats for pad.
*/
static int
-tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+tvp7002_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
/* Check requested format index is within range */
@@ -818,7 +819,8 @@ tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cf
* get video format for pad.
*/
static int
-tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+tvp7002_get_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct tvp7002 *tvp7002 = to_tvp7002(sd);
@@ -841,10 +843,11 @@ tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cf
* set video format for pad.
*/
static int
-tvp7002_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+tvp7002_set_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
- return tvp7002_get_pad_format(sd, cfg, fmt);
+ return tvp7002_get_pad_format(sd, sd_state, fmt);
}
/* V4L2 core operation handlers */
diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c
index a25a350b0ddc..09f5b3986928 100644
--- a/drivers/media/i2c/tw9910.c
+++ b/drivers/media/i2c/tw9910.c
@@ -720,7 +720,7 @@ tw9910_set_fmt_error:
}
static int tw9910_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -746,7 +746,7 @@ static int tw9910_get_selection(struct v4l2_subdev *sd,
}
static int tw9910_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -797,7 +797,7 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd,
}
static int tw9910_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *mf = &format->format;
@@ -829,7 +829,7 @@ static int tw9910_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return tw9910_s_fmt(sd, mf);
- cfg->try_fmt = *mf;
+ sd_state->pads->try_fmt = *mf;
return 0;
}
@@ -886,7 +886,7 @@ static const struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
};
static int tw9910_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index)
diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c
index 0465832a4090..de12f38f347c 100644
--- a/drivers/media/i2c/video-i2c.c
+++ b/drivers/media/i2c/video-i2c.c
@@ -286,11 +286,9 @@ static int amg88xx_read(struct device *dev, enum hwmon_sensor_types type,
__le16 buf;
int tmp;
- tmp = pm_runtime_get_sync(regmap_get_device(data->regmap));
- if (tmp < 0) {
- pm_runtime_put_noidle(regmap_get_device(data->regmap));
+ tmp = pm_runtime_resume_and_get(regmap_get_device(data->regmap));
+ if (tmp < 0)
return tmp;
- }
tmp = regmap_bulk_read(data->regmap, AMG88XX_REG_TTHL, &buf, 2);
pm_runtime_mark_last_busy(regmap_get_device(data->regmap));
@@ -512,11 +510,9 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
if (data->kthread_vid_cap)
return 0;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
goto error_del_list;
- }
ret = data->chip->setup(data);
if (ret)
diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c
index c292c92e37b9..29003dec6f2d 100644
--- a/drivers/media/i2c/vs6624.c
+++ b/drivers/media/i2c/vs6624.c
@@ -546,7 +546,7 @@ static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl)
}
static int vs6624_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index >= ARRAY_SIZE(vs6624_formats))
@@ -557,7 +557,7 @@ static int vs6624_enum_mbus_code(struct v4l2_subdev *sd,
}
static int vs6624_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -587,7 +587,7 @@ static int vs6624_set_fmt(struct v4l2_subdev *sd,
fmt->colorspace = vs6624_formats[index].colorspace;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *fmt;
+ sd_state->pads->try_fmt = *fmt;
return 0;
}
@@ -637,7 +637,7 @@ static int vs6624_set_fmt(struct v4l2_subdev *sd,
}
static int vs6624_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct vs6624 *sensor = to_vs6624(sd);
diff --git a/drivers/media/mc/Makefile b/drivers/media/mc/Makefile
index 119037f0e686..2b7af42ba59c 100644
--- a/drivers/media/mc/Makefile
+++ b/drivers/media/mc/Makefile
@@ -3,7 +3,7 @@
mc-objs := mc-device.o mc-devnode.o mc-entity.o \
mc-request.o
-ifeq ($(CONFIG_USB),y)
+ifneq ($(CONFIG_USB),)
mc-objs += mc-dev-allocator.o
endif
diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
index 678b99771cfa..f40f41977142 100644
--- a/drivers/media/mc/mc-entity.c
+++ b/drivers/media/mc/mc-entity.c
@@ -323,7 +323,7 @@ static void media_graph_walk_iter(struct media_graph *graph)
return;
}
- /* Get the entity in the other end of the link . */
+ /* Get the entity at the other end of the link. */
next = media_entity_other(entity, link);
/* Has the entity already been visited? */
diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c
index c0782fd96c59..addb8f2d8939 100644
--- a/drivers/media/mc/mc-request.c
+++ b/drivers/media/mc/mc-request.c
@@ -414,7 +414,8 @@ int media_request_object_bind(struct media_request *req,
spin_lock_irqsave(&req->lock, flags);
- if (WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING))
+ if (WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING &&
+ req->state != MEDIA_REQUEST_STATE_QUEUED))
goto unlock;
obj->req = req;
diff --git a/drivers/media/pci/bt8xx/bt878.c b/drivers/media/pci/bt8xx/bt878.c
index 78dd35c9b65d..90972d6952f1 100644
--- a/drivers/media/pci/bt8xx/bt878.c
+++ b/drivers/media/pci/bt8xx/bt878.c
@@ -300,7 +300,8 @@ static irqreturn_t bt878_irq(int irq, void *dev_id)
}
if (astat & BT878_ARISCI) {
bt->finished_block = (stat & BT878_ARISCS) >> 28;
- tasklet_schedule(&bt->tasklet);
+ if (bt->tasklet.callback)
+ tasklet_schedule(&bt->tasklet);
break;
}
count++;
@@ -477,6 +478,9 @@ static int bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
btwrite(0, BT878_AINT_MASK);
bt878_num++;
+ if (!bt->tasklet.func)
+ tasklet_disable(&bt->tasklet);
+
return 0;
fail2:
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index 1f62a9d8ea1d..0e9df8b35ac6 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -3179,7 +3179,7 @@ static int radio_release(struct file *file)
btv->radio_user--;
- bttv_call_all(btv, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
+ bttv_call_all(btv, core, command, SAA6588_CMD_CLOSE, &cmd);
if (btv->radio_user == 0)
btv->has_radio_tuner = 0;
@@ -3260,7 +3260,7 @@ static ssize_t radio_read(struct file *file, char __user *data,
cmd.result = -ENODEV;
radio_enable(btv);
- bttv_call_all(btv, core, ioctl, SAA6588_CMD_READ, &cmd);
+ bttv_call_all(btv, core, command, SAA6588_CMD_READ, &cmd);
return cmd.result;
}
@@ -3281,7 +3281,7 @@ static __poll_t radio_poll(struct file *file, poll_table *wait)
cmd.instance = file;
cmd.event_list = wait;
cmd.poll_mask = res;
- bttv_call_all(btv, core, ioctl, SAA6588_CMD_POLL, &cmd);
+ bttv_call_all(btv, core, command, SAA6588_CMD_POLL, &cmd);
return cmd.poll_mask;
}
diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c
index 839503e654f4..16af58f2f93c 100644
--- a/drivers/media/pci/cobalt/cobalt-driver.c
+++ b/drivers/media/pci/cobalt/cobalt-driver.c
@@ -667,6 +667,7 @@ static int cobalt_probe(struct pci_dev *pci_dev,
return -ENOMEM;
cobalt->pci_dev = pci_dev;
cobalt->instance = i;
+ mutex_init(&cobalt->pci_lock);
retval = v4l2_device_register(&pci_dev->dev, &cobalt->v4l2_dev);
if (retval) {
diff --git a/drivers/media/pci/cobalt/cobalt-driver.h b/drivers/media/pci/cobalt/cobalt-driver.h
index bca68572b324..12c33e035904 100644
--- a/drivers/media/pci/cobalt/cobalt-driver.h
+++ b/drivers/media/pci/cobalt/cobalt-driver.h
@@ -251,6 +251,8 @@ struct cobalt {
int instance;
struct pci_dev *pci_dev;
struct v4l2_device v4l2_dev;
+ /* serialize PCI access in cobalt_s_bit_sysctrl() */
+ struct mutex pci_lock;
void __iomem *bar0, *bar1;
@@ -320,10 +322,13 @@ static inline u32 cobalt_g_sysctrl(struct cobalt *cobalt)
static inline void cobalt_s_bit_sysctrl(struct cobalt *cobalt,
int bit, int val)
{
- u32 ctrl = cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE);
+ u32 ctrl;
+ mutex_lock(&cobalt->pci_lock);
+ ctrl = cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE);
cobalt_write_bar1(cobalt, COBALT_SYS_CTRL_BASE,
(ctrl & ~(1UL << bit)) | (val << bit));
+ mutex_unlock(&cobalt->pci_lock);
}
static inline u32 cobalt_g_sysstat(struct cobalt *cobalt)
diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c
index 11cfe35fd730..76e5a504df8c 100644
--- a/drivers/media/pci/cx18/cx18-av-core.c
+++ b/drivers/media/pci/cx18/cx18-av-core.c
@@ -930,7 +930,7 @@ static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl)
}
static int cx18_av_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c
index c83814c052d3..29fb1311e443 100644
--- a/drivers/media/pci/cx88/cx88-alsa.c
+++ b/drivers/media/pci/cx88/cx88-alsa.c
@@ -357,8 +357,8 @@ static int dsp_buffer_free(struct cx88_audio_dev *chip)
cx88_alsa_dma_unmap(chip);
cx88_alsa_dma_free(chip->buf);
if (risc->cpu)
- pci_free_consistent(chip->pci, risc->size,
- risc->cpu, risc->dma);
+ dma_free_coherent(&chip->pci->dev, risc->size, risc->cpu,
+ risc->dma);
kfree(chip->buf);
chip->buf = NULL;
@@ -868,7 +868,7 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci,
return err;
}
- err = pci_set_dma_mask(pci, DMA_BIT_MASK(32));
+ err = dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
if (err) {
dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n", core->name);
cx88_core_put(core, pci);
diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c
index fa4ca002ed19..d5da3bd5695d 100644
--- a/drivers/media/pci/cx88/cx88-blackbird.c
+++ b/drivers/media/pci/cx88/cx88-blackbird.c
@@ -685,7 +685,8 @@ static void buffer_finish(struct vb2_buffer *vb)
struct cx88_riscmem *risc = &buf->risc;
if (risc->cpu)
- pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
+ dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu,
+ risc->dma);
memset(risc, 0, sizeof(*risc));
}
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c
index 48c8a3429542..89d4d5a3ba34 100644
--- a/drivers/media/pci/cx88/cx88-core.c
+++ b/drivers/media/pci/cx88/cx88-core.c
@@ -152,7 +152,8 @@ int cx88_risc_buffer(struct pci_dev *pci, struct cx88_riscmem *risc,
instructions += 4;
risc->size = instructions * 8;
risc->dma = 0;
- risc->cpu = pci_zalloc_consistent(pci, risc->size, &risc->dma);
+ risc->cpu = dma_alloc_coherent(&pci->dev, risc->size, &risc->dma,
+ GFP_KERNEL);
if (!risc->cpu)
return -ENOMEM;
@@ -190,7 +191,8 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct cx88_riscmem *risc,
instructions += 3;
risc->size = instructions * 8;
risc->dma = 0;
- risc->cpu = pci_zalloc_consistent(pci, risc->size, &risc->dma);
+ risc->cpu = dma_alloc_coherent(&pci->dev, risc->size, &risc->dma,
+ GFP_KERNEL);
if (!risc->cpu)
return -ENOMEM;
diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c
index 202ff9e8c257..2087f2491c42 100644
--- a/drivers/media/pci/cx88/cx88-dvb.c
+++ b/drivers/media/pci/cx88/cx88-dvb.c
@@ -103,7 +103,8 @@ static void buffer_finish(struct vb2_buffer *vb)
struct cx88_riscmem *risc = &buf->risc;
if (risc->cpu)
- pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
+ dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu,
+ risc->dma);
memset(risc, 0, sizeof(*risc));
}
diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c
index a3edb548afde..680e1e3fe89b 100644
--- a/drivers/media/pci/cx88/cx88-mpeg.c
+++ b/drivers/media/pci/cx88/cx88-mpeg.c
@@ -226,8 +226,8 @@ int cx8802_buf_prepare(struct vb2_queue *q, struct cx8802_dev *dev,
dev->ts_packet_size, dev->ts_packet_count, 0);
if (rc) {
if (risc->cpu)
- pci_free_consistent(dev->pci, risc->size,
- risc->cpu, risc->dma);
+ dma_free_coherent(&dev->pci->dev, risc->size,
+ risc->cpu, risc->dma);
memset(risc, 0, sizeof(*risc));
return rc;
}
@@ -386,7 +386,7 @@ static int cx8802_init_common(struct cx8802_dev *dev)
if (pci_enable_device(dev->pci))
return -EIO;
pci_set_master(dev->pci);
- err = pci_set_dma_mask(dev->pci, DMA_BIT_MASK(32));
+ err = dma_set_mask(&dev->pci->dev, DMA_BIT_MASK(32));
if (err) {
pr_err("Oops: no 32bit PCI DMA ???\n");
return -EIO;
diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c
index 58489ea0c1da..a075788c64d4 100644
--- a/drivers/media/pci/cx88/cx88-vbi.c
+++ b/drivers/media/pci/cx88/cx88-vbi.c
@@ -159,7 +159,8 @@ static void buffer_finish(struct vb2_buffer *vb)
struct cx88_riscmem *risc = &buf->risc;
if (risc->cpu)
- pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
+ dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu,
+ risc->dma);
memset(risc, 0, sizeof(*risc));
}
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index 8cffdacf6007..c17ad9f7d822 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -492,7 +492,8 @@ static void buffer_finish(struct vb2_buffer *vb)
struct cx88_riscmem *risc = &buf->risc;
if (risc->cpu)
- pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
+ dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu,
+ risc->dma);
memset(risc, 0, sizeof(*risc));
}
@@ -1288,7 +1289,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
(unsigned long long)pci_resource_start(pci_dev, 0));
pci_set_master(pci_dev);
- err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
+ err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32));
if (err) {
pr_err("Oops: no 32bit PCI DMA ???\n");
goto fail_core;
diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c
index e8511787c1e4..4657e99df033 100644
--- a/drivers/media/pci/intel/ipu3/cio2-bridge.c
+++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c
@@ -173,14 +173,15 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
int ret;
for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) {
- if (!adev->status.enabled)
+ if (!adev->status.enabled) {
+ acpi_dev_put(adev);
continue;
+ }
if (bridge->n_sensors >= CIO2_NUM_PORTS) {
+ acpi_dev_put(adev);
dev_err(&cio2->dev, "Exceeded available CIO2 ports\n");
- cio2_bridge_unregister_sensors(bridge);
- ret = -EINVAL;
- goto err_out;
+ return -EINVAL;
}
sensor = &bridge->sensors[bridge->n_sensors];
@@ -228,7 +229,6 @@ err_free_swnodes:
software_node_unregister_nodes(sensor->swnodes);
err_put_adev:
acpi_dev_put(sensor->adev);
-err_out:
return ret;
}
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
index fecef85bd62e..47db0ee0fcbf 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
@@ -975,10 +975,9 @@ static int cio2_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
cio2->cur_queue = q;
atomic_set(&q->frame_sequence, 0);
- r = pm_runtime_get_sync(&cio2->pci_dev->dev);
+ r = pm_runtime_resume_and_get(&cio2->pci_dev->dev);
if (r < 0) {
dev_info(&cio2->pci_dev->dev, "failed to set power %d\n", r);
- pm_runtime_put_noidle(&cio2->pci_dev->dev);
return r;
}
@@ -1200,11 +1199,11 @@ static int cio2_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
};
/* Initialize try_fmt */
- format = v4l2_subdev_get_try_format(sd, fh->pad, CIO2_PAD_SINK);
+ format = v4l2_subdev_get_try_format(sd, fh->state, CIO2_PAD_SINK);
*format = fmt_default;
/* same as sink */
- format = v4l2_subdev_get_try_format(sd, fh->pad, CIO2_PAD_SOURCE);
+ format = v4l2_subdev_get_try_format(sd, fh->state, CIO2_PAD_SOURCE);
*format = fmt_default;
return 0;
@@ -1218,7 +1217,7 @@ static int cio2_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
* return -EINVAL or zero on success
*/
static int cio2_subdev_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev);
@@ -1226,7 +1225,8 @@ static int cio2_subdev_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&q->subdev_lock);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
+ fmt->pad);
else
fmt->format = q->subdev_fmt;
@@ -1243,7 +1243,7 @@ static int cio2_subdev_get_fmt(struct v4l2_subdev *sd,
* return -EINVAL or zero on success
*/
static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev);
@@ -1256,10 +1256,10 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
* source always propagates from sink
*/
if (fmt->pad == CIO2_PAD_SOURCE)
- return cio2_subdev_get_fmt(sd, cfg, fmt);
+ return cio2_subdev_get_fmt(sd, sd_state, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- mbus = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ mbus = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
else
mbus = &q->subdev_fmt;
@@ -1284,7 +1284,7 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
}
static int cio2_subdev_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(formats))
diff --git a/drivers/media/pci/ivtv/Kconfig b/drivers/media/pci/ivtv/Kconfig
index c729e54692c4..e70502902b73 100644
--- a/drivers/media/pci/ivtv/Kconfig
+++ b/drivers/media/pci/ivtv/Kconfig
@@ -29,18 +29,6 @@ config VIDEO_IVTV
To compile this driver as a module, choose M here: the
module will be called ivtv.
-config VIDEO_IVTV_DEPRECATED_IOCTLS
- bool "enable the DVB ioctls abuse on ivtv driver"
- depends on VIDEO_IVTV
- help
- Enable the usage of the a DVB set of ioctls that were abused by
- IVTV driver for a while.
-
- Those ioctls were not needed for a long time, as IVTV implements
- the proper V4L2 ioctls since kernel 3.3.
-
- If unsure, say N.
-
config VIDEO_IVTV_ALSA
tristate "Conexant cx23415/cx23416 ALSA interface for PCM audio capture"
depends on VIDEO_IVTV && SND
diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h
index e5efe525ad7b..4cf92dee6527 100644
--- a/drivers/media/pci/ivtv/ivtv-driver.h
+++ b/drivers/media/pci/ivtv/ivtv-driver.h
@@ -57,8 +57,6 @@
#include <linux/uaccess.h>
#include <asm/byteorder.h>
-#include <linux/dvb/video.h>
-#include <linux/dvb/audio.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c
index 35dccb31174c..da19b2e95e6c 100644
--- a/drivers/media/pci/ivtv/ivtv-ioctl.c
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.c
@@ -23,11 +23,6 @@
#include <media/i2c/saa7127.h>
#include <media/tveeprom.h>
#include <media/v4l2-event.h>
-#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
-#include <linux/compat.h>
-#include <linux/dvb/audio.h>
-#include <linux/dvb/video.h>
-#endif
u16 ivtv_service2vbi(int type)
{
@@ -1606,38 +1601,11 @@ static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder
return ivtv_video_command(itv, id, dec, true);
}
-#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
-static __inline__ void warn_deprecated_ioctl(const char *name)
-{
- pr_warn_once("warning: the %s ioctl is deprecated. Don't use it, as it will be removed soon\n",
- name);
-}
-
-#ifdef CONFIG_COMPAT
-struct compat_video_event {
- __s32 type;
- /* unused, make sure to use atomic time for y2038 if it ever gets used */
- compat_long_t timestamp;
- union {
- video_size_t size;
- unsigned int frame_rate; /* in frames per 1000sec */
- unsigned char vsync_field; /* unknown/odd/even/progressive */
- } u;
-};
-#define VIDEO_GET_EVENT32 _IOR('o', 28, struct compat_video_event)
-#endif
-
-#endif
-
static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
{
struct ivtv_open_id *id = fh2id(filp->private_data);
struct ivtv *itv = id->itv;
struct ivtv_stream *s = &itv->streams[id->type];
-#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
- int nonblocking = filp->f_flags & O_NONBLOCK;
- unsigned long iarg = (unsigned long)arg;
-#endif
switch (cmd) {
case IVTV_IOC_DMA_FRAME: {
@@ -1669,169 +1637,6 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
return ivtv_passthrough_mode(itv, *(int *)arg != 0);
-#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
- case VIDEO_GET_PTS: {
- s64 *pts = arg;
- s64 frame;
-
- warn_deprecated_ioctl("VIDEO_GET_PTS");
- if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
- *pts = s->dma_pts;
- break;
- }
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return -EINVAL;
- return ivtv_g_pts_frame(itv, pts, &frame);
- }
-
- case VIDEO_GET_FRAME_COUNT: {
- s64 *frame = arg;
- s64 pts;
-
- warn_deprecated_ioctl("VIDEO_GET_FRAME_COUNT");
- if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
- *frame = 0;
- break;
- }
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return -EINVAL;
- return ivtv_g_pts_frame(itv, &pts, frame);
- }
-
- case VIDEO_PLAY: {
- struct v4l2_decoder_cmd dc;
-
- warn_deprecated_ioctl("VIDEO_PLAY");
- memset(&dc, 0, sizeof(dc));
- dc.cmd = V4L2_DEC_CMD_START;
- return ivtv_video_command(itv, id, &dc, 0);
- }
-
- case VIDEO_STOP: {
- struct v4l2_decoder_cmd dc;
-
- warn_deprecated_ioctl("VIDEO_STOP");
- memset(&dc, 0, sizeof(dc));
- dc.cmd = V4L2_DEC_CMD_STOP;
- dc.flags = V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY;
- return ivtv_video_command(itv, id, &dc, 0);
- }
-
- case VIDEO_FREEZE: {
- struct v4l2_decoder_cmd dc;
-
- warn_deprecated_ioctl("VIDEO_FREEZE");
- memset(&dc, 0, sizeof(dc));
- dc.cmd = V4L2_DEC_CMD_PAUSE;
- return ivtv_video_command(itv, id, &dc, 0);
- }
-
- case VIDEO_CONTINUE: {
- struct v4l2_decoder_cmd dc;
-
- warn_deprecated_ioctl("VIDEO_CONTINUE");
- memset(&dc, 0, sizeof(dc));
- dc.cmd = V4L2_DEC_CMD_RESUME;
- return ivtv_video_command(itv, id, &dc, 0);
- }
-
- case VIDEO_COMMAND:
- case VIDEO_TRY_COMMAND: {
- /* Note: struct v4l2_decoder_cmd has the same layout as
- struct video_command */
- struct v4l2_decoder_cmd *dc = arg;
- int try = (cmd == VIDEO_TRY_COMMAND);
-
- if (try)
- warn_deprecated_ioctl("VIDEO_TRY_COMMAND");
- else
- warn_deprecated_ioctl("VIDEO_COMMAND");
- return ivtv_video_command(itv, id, dc, try);
- }
-
-#ifdef CONFIG_COMPAT
- case VIDEO_GET_EVENT32:
-#endif
- case VIDEO_GET_EVENT: {
-#ifdef CONFIG_COMPAT
- struct compat_video_event *ev32 = arg;
-#endif
- struct video_event *ev = arg;
- DEFINE_WAIT(wait);
-
- warn_deprecated_ioctl("VIDEO_GET_EVENT");
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return -EINVAL;
- memset(ev, 0, sizeof(*ev));
- set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
-
- while (1) {
- if (test_and_clear_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags))
- ev->type = VIDEO_EVENT_DECODER_STOPPED;
- else if (test_and_clear_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags)) {
- unsigned char vsync_field;
-
- ev->type = VIDEO_EVENT_VSYNC;
- vsync_field = test_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags) ?
- VIDEO_VSYNC_FIELD_ODD : VIDEO_VSYNC_FIELD_EVEN;
- if (itv->output_mode == OUT_UDMA_YUV &&
- (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) ==
- IVTV_YUV_MODE_PROGRESSIVE) {
- vsync_field = VIDEO_VSYNC_FIELD_PROGRESSIVE;
- }
-#ifdef CONFIG_COMPAT
- if (cmd == VIDEO_GET_EVENT32)
- ev32->u.vsync_field = vsync_field;
- else
-#endif
- ev->u.vsync_field = vsync_field;
- }
- if (ev->type)
- return 0;
- if (nonblocking)
- return -EAGAIN;
- /* Wait for event. Note that serialize_lock is locked,
- so to allow other processes to access the driver while
- we are waiting unlock first and later lock again. */
- mutex_unlock(&itv->serialize_lock);
- prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE);
- if (!test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags) &&
- !test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags))
- schedule();
- finish_wait(&itv->event_waitq, &wait);
- mutex_lock(&itv->serialize_lock);
- if (signal_pending(current)) {
- /* return if a signal was received */
- IVTV_DEBUG_INFO("User stopped wait for event\n");
- return -EINTR;
- }
- }
- break;
- }
-
- case VIDEO_SELECT_SOURCE:
- warn_deprecated_ioctl("VIDEO_SELECT_SOURCE");
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return -EINVAL;
- return ivtv_passthrough_mode(itv, iarg == VIDEO_SOURCE_DEMUX);
-
- case AUDIO_SET_MUTE:
- warn_deprecated_ioctl("AUDIO_SET_MUTE");
- itv->speed_mute_audio = iarg;
- return 0;
-
- case AUDIO_CHANNEL_SELECT:
- warn_deprecated_ioctl("AUDIO_CHANNEL_SELECT");
- if (iarg > AUDIO_STEREO_SWAPPED)
- return -EINVAL;
- return v4l2_ctrl_s_ctrl(itv->ctrl_audio_playback, iarg + 1);
-
- case AUDIO_BILINGUAL_CHANNEL_SELECT:
- warn_deprecated_ioctl("AUDIO_BILINGUAL_CHANNEL_SELECT");
- if (iarg > AUDIO_STEREO_SWAPPED)
- return -EINVAL;
- return v4l2_ctrl_s_ctrl(itv->ctrl_audio_multilingual_playback, iarg + 1);
-#endif
default:
return -EINVAL;
}
@@ -1846,17 +1651,6 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
if (!valid_prio) {
switch (cmd) {
case IVTV_IOC_PASSTHROUGH_MODE:
-#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
- case VIDEO_PLAY:
- case VIDEO_STOP:
- case VIDEO_FREEZE:
- case VIDEO_CONTINUE:
- case VIDEO_COMMAND:
- case VIDEO_SELECT_SOURCE:
- case AUDIO_SET_MUTE:
- case AUDIO_CHANNEL_SELECT:
- case AUDIO_BILINGUAL_CHANNEL_SELECT:
-#endif
return -EBUSY;
}
}
@@ -1874,21 +1668,6 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
case IVTV_IOC_DMA_FRAME:
case IVTV_IOC_PASSTHROUGH_MODE:
-#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
- case VIDEO_GET_PTS:
- case VIDEO_GET_FRAME_COUNT:
- case VIDEO_GET_EVENT:
- case VIDEO_PLAY:
- case VIDEO_STOP:
- case VIDEO_FREEZE:
- case VIDEO_CONTINUE:
- case VIDEO_COMMAND:
- case VIDEO_TRY_COMMAND:
- case VIDEO_SELECT_SOURCE:
- case AUDIO_SET_MUTE:
- case AUDIO_CHANNEL_SELECT:
- case AUDIO_BILINGUAL_CHANNEL_SELECT:
-#endif
return ivtv_decoder_ioctls(file, cmd, (void *)arg);
default:
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index efb757d5168a..47158ab3956b 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -1031,7 +1031,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
dev->media_dev = kzalloc(sizeof(*dev->media_dev), GFP_KERNEL);
if (!dev->media_dev) {
err = -ENOMEM;
- goto fail0;
+ goto err_free_dev;
}
media_device_pci_init(dev->media_dev, pci_dev, dev->name);
dev->v4l2_dev.mdev = dev->media_dev;
@@ -1039,13 +1039,13 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
if (err)
- goto fail0;
+ goto err_free_dev;
/* pci init */
dev->pci = pci_dev;
if (pci_enable_device(pci_dev)) {
err = -EIO;
- goto fail1;
+ goto err_v4l2_unregister;
}
/* pci quirks */
@@ -1095,7 +1095,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
if (err) {
pr_warn("%s: Oops: no 32bit PCI DMA ???\n", dev->name);
- goto fail1;
+ goto err_v4l2_unregister;
}
/* board config */
@@ -1129,7 +1129,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
err = -EBUSY;
pr_err("%s: can't get MMIO memory @ 0x%llx\n",
dev->name,(unsigned long long)pci_resource_start(pci_dev,0));
- goto fail1;
+ goto err_v4l2_unregister;
}
dev->lmmio = ioremap(pci_resource_start(pci_dev, 0),
pci_resource_len(pci_dev, 0));
@@ -1138,7 +1138,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
err = -EIO;
pr_err("%s: can't ioremap() MMIO memory\n",
dev->name);
- goto fail2;
+ goto err_release_mem_reg;
}
/* initialize hardware #1 */
@@ -1151,7 +1151,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
if (err < 0) {
pr_err("%s: can't get IRQ %d\n",
dev->name,pci_dev->irq);
- goto fail3;
+ goto err_iounmap;
}
/* wait a bit, register i2c bus */
@@ -1217,7 +1217,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
if (err < 0) {
pr_info("%s: can't register video device\n",
dev->name);
- goto fail4;
+ goto err_unregister_video;
}
pr_info("%s: registered device %s [v4l2]\n",
dev->name, video_device_node_name(dev->video_dev));
@@ -1234,7 +1234,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
vbi_nr[dev->nr]);
if (err < 0)
- goto fail4;
+ goto err_unregister_video;
pr_info("%s: registered device %s\n",
dev->name, video_device_node_name(dev->vbi_dev));
@@ -1248,7 +1248,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
radio_nr[dev->nr]);
if (err < 0)
- goto fail4;
+ goto err_unregister_video;
pr_info("%s: registered device %s\n",
dev->name, video_device_node_name(dev->radio_dev));
}
@@ -1259,7 +1259,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
err = v4l2_mc_create_media_graph(dev->media_dev);
if (err) {
pr_err("failed to create media graph\n");
- goto fail4;
+ goto err_unregister_video;
}
#endif
/* everything worked */
@@ -1277,25 +1277,28 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
*/
#ifdef CONFIG_MEDIA_CONTROLLER
err = media_device_register(dev->media_dev);
- if (err)
- goto fail4;
+ if (err) {
+ media_device_cleanup(dev->media_dev);
+ goto err_unregister_video;
+ }
#endif
return 0;
- fail4:
+err_unregister_video:
saa7134_unregister_video(dev);
+ list_del(&dev->devlist);
saa7134_i2c_unregister(dev);
free_irq(pci_dev->irq, dev);
- fail3:
+err_iounmap:
saa7134_hwfini(dev);
iounmap(dev->lmmio);
- fail2:
+err_release_mem_reg:
release_mem_region(pci_resource_start(pci_dev,0),
pci_resource_len(pci_dev,0));
- fail1:
+err_v4l2_unregister:
v4l2_device_unregister(&dev->v4l2_dev);
- fail0:
+err_free_dev:
#ifdef CONFIG_MEDIA_CONTROLLER
kfree(dev->media_dev);
#endif
@@ -1524,7 +1527,6 @@ static struct pci_driver saa7134_pci_driver = {
static int __init saa7134_init(void)
{
- INIT_LIST_HEAD(&saa7134_devlist);
pr_info("saa7130/34: v4l2 driver version %s loaded\n",
SAA7134_VERSION);
return pci_register_driver(&saa7134_pci_driver);
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index 76a37fbd8458..aafbb34765b0 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -138,12 +138,15 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv,
{
struct saa7134_dev *dev = video_drvdata(file);
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = {
+ .pads = &pad_cfg
+ };
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED);
- saa_call_all(dev, pad, set_fmt, &pad_cfg, &format);
+ saa_call_all(dev, pad, set_fmt, &pad_state, &format);
v4l2_fill_pix_format(&f->fmt.pix, &format.format);
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
diff --git a/drivers/media/pci/saa7134/saa7134-tvaudio.c b/drivers/media/pci/saa7134/saa7134-tvaudio.c
index aa0895d2d735..9e0c442abc76 100644
--- a/drivers/media/pci/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/pci/saa7134/saa7134-tvaudio.c
@@ -871,7 +871,7 @@ void saa7134_enable_i2s(struct saa7134_dev *dev)
switch (dev->pci->device) {
case PCI_DEVICE_ID_PHILIPS_SAA7133:
case PCI_DEVICE_ID_PHILIPS_SAA7135:
- /* Set I2S format (SONY)  */
+ /* Set I2S format (SONY) */
saa_writeb(SAA7133_I2S_AUDIO_CONTROL, 0x00);
/* Start I2S */
saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x11);
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 0f9d6b9edb90..374c8e1087de 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -1181,7 +1181,7 @@ static int video_release(struct file *file)
saa_call_all(dev, tuner, standby);
if (vdev->vfl_type == VFL_TYPE_RADIO)
- saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
+ saa_call_all(dev, core, command, SAA6588_CMD_CLOSE, &cmd);
mutex_unlock(&dev->lock);
return 0;
@@ -1200,7 +1200,7 @@ static ssize_t radio_read(struct file *file, char __user *data,
cmd.result = -ENODEV;
mutex_lock(&dev->lock);
- saa_call_all(dev, core, ioctl, SAA6588_CMD_READ, &cmd);
+ saa_call_all(dev, core, command, SAA6588_CMD_READ, &cmd);
mutex_unlock(&dev->lock);
return cmd.result;
@@ -1216,7 +1216,7 @@ static __poll_t radio_poll(struct file *file, poll_table *wait)
cmd.event_list = wait;
cmd.poll_mask = 0;
mutex_lock(&dev->lock);
- saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd);
+ saa_call_all(dev, core, command, SAA6588_CMD_POLL, &cmd);
mutex_unlock(&dev->lock);
return rc | cmd.poll_mask;
diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig
index 8a362ee9105f..65a6832a6b96 100644
--- a/drivers/media/pci/ttpci/Kconfig
+++ b/drivers/media/pci/ttpci/Kconfig
@@ -1,56 +1,4 @@
# 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
- depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
- select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT
- select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
- select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
- select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT
- select DVB_SP8870 if MEDIA_SUBDRV_AUTOSELECT
- select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT
- select DVB_L64781 if MEDIA_SUBDRV_AUTOSELECT
- select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
- help
- Support for SAA7146 and AV7110 based DVB cards as produced
- by Fujitsu-Siemens, Technotrend, Hauppauge and others.
-
- This driver only supports the fullfeatured cards with
- onboard MPEG2 decoder.
-
- This driver needs an external firmware. Please use the script
- "<kerneldir>/scripts/get_dvb_firmware av7110" to
- download/extract it, and then copy it to /usr/lib/hotplug/firmware
- or /lib/firmware (depending on configuration of firmware hotplug).
-
- Alternatively, you can download the file and use the kernel's
- EXTRA_FIRMWARE configuration option to build it into your
- kernel image by adding the filename to the EXTRA_FIRMWARE
- configuration option string.
-
- Say Y if you own such a card and want to use it.
-
-config DVB_AV7110_OSD
- bool "AV7110 OSD support"
- depends on DVB_AV7110
- default y if DVB_AV7110=y || DVB_AV7110=m
- help
- The AV7110 firmware provides some code to generate an OnScreenDisplay
- on the video output. This is kind of nonstandard and not guaranteed to
- be maintained.
-
- Anyway, some popular DVB software like VDR uses this OSD to render
- its menus, so say Y if you want to use this software.
-
- All other people say N.
-
config DVB_BUDGET_CORE
tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)"
depends on DVB_CORE && PCI && I2C
@@ -136,25 +84,3 @@ config DVB_BUDGET_AV
To compile this driver as a module, choose M here: the
module will be called budget-av.
-
-config DVB_BUDGET_PATCH
- tristate "AV7110 cards with Budget Patch"
- depends on DVB_BUDGET_CORE && I2C
- depends on DVB_AV7110
- select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
- select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
- select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT
- help
- Support for Budget Patch (full TS) modification on
- SAA7146+AV7110 based cards (DVB-S cards). This
- driver doesn't use onboard MPEG2 decoder. The
- card is driven in Budget-only mode. Card is
- required to have loaded firmware to tune properly.
- Firmware can be loaded by insertion and removal of
- standard AV7110 driver prior to loading this
- driver.
-
- Say Y if you own such a card and want to use it.
-
- To compile this driver as a module, choose M here: the
- module will be called budget-patch.
diff --git a/drivers/media/pci/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile
index 9b44c479fcdd..b0708f6e40cc 100644
--- a/drivers/media/pci/ttpci/Makefile
+++ b/drivers/media/pci/ttpci/Makefile
@@ -1,22 +1,13 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the kernel SAA7146 FULL TS DVB device driver
-# and the AV7110 DVB device driver
#
-dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o dvb_filter.o
-
-ifdef CONFIG_DVB_AV7110_IR
-dvb-ttpci-objs += av7110_ir.o
-endif
-
-obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
obj-$(CONFIG_DVB_BUDGET) += budget.o
obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o
obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o
-obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
-obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
ccflags-y += -I $(srctree)/drivers/media/dvb-frontends/
ccflags-y += -I $(srctree)/drivers/media/tuners
+ccflags-y += -I $(srctree)/drivers/media/common
diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c
index d405eea5c37f..5d5796f24469 100644
--- a/drivers/media/pci/ttpci/budget-core.c
+++ b/drivers/media/pci/ttpci/budget-core.c
@@ -180,7 +180,8 @@ static void vpeirq(struct tasklet_struct *t)
u32 count;
/* Ensure streamed PCI data is synced to CPU */
- pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE);
+ dma_sync_sg_for_cpu(&budget->dev->pci->dev, budget->pt.slist,
+ budget->pt.nents, DMA_FROM_DEVICE);
/* nearest lower position divisible by 188 */
newdma -= newdma % 188;
diff --git a/drivers/media/pci/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h
index a7463daf39f1..bd87432e6cde 100644
--- a/drivers/media/pci/ttpci/budget.h
+++ b/drivers/media/pci/ttpci/budget.h
@@ -8,7 +8,6 @@
#include <media/demux.h>
#include <media/dvb_demux.h>
#include <media/dmxdev.h>
-#include "dvb_filter.h"
#include <media/dvb_net.h>
#include <linux/module.h>
@@ -28,6 +27,7 @@ extern int budget_debug;
__func__, ##arg); \
} while (0)
+#define TS_SIZE 188
struct budget_info {
char *name;
diff --git a/drivers/media/pci/tw5864/tw5864-reg.h b/drivers/media/pci/tw5864/tw5864-reg.h
index a74f30f2f78e..a26a439c4dc0 100644
--- a/drivers/media/pci/tw5864/tw5864-reg.h
+++ b/drivers/media/pci/tw5864/tw5864-reg.h
@@ -289,13 +289,13 @@
/* OSD enable bit for each channel */
#define TW5864_DSP_OSD_ENABLE 0x0228
-/* 0x0280 ~ 0x029c – Motion Vector for 1st 4x4 Block, e.g., 80 (X), 84 (Y) */
+/* 0x0280 ~ 0x029c - Motion Vector for 1st 4x4 Block, e.g., 80 (X), 84 (Y) */
#define TW5864_ME_MV_VEC1 0x0280
-/* 0x02a0 ~ 0x02bc – Motion Vector for 2nd 4x4 Block, e.g., A0 (X), A4 (Y) */
+/* 0x02a0 ~ 0x02bc - Motion Vector for 2nd 4x4 Block, e.g., A0 (X), A4 (Y) */
#define TW5864_ME_MV_VEC2 0x02a0
-/* 0x02c0 ~ 0x02dc – Motion Vector for 3rd 4x4 Block, e.g., C0 (X), C4 (Y) */
+/* 0x02c0 ~ 0x02dc - Motion Vector for 3rd 4x4 Block, e.g., C0 (X), C4 (Y) */
#define TW5864_ME_MV_VEC3 0x02c0
-/* 0x02e0 ~ 0x02fc – Motion Vector for 4th 4x4 Block, e.g., E0 (X), E4 (Y) */
+/* 0x02e0 ~ 0x02fc - Motion Vector for 4th 4x4 Block, e.g., E0 (X), E4 (Y) */
#define TW5864_ME_MV_VEC4 0x02e0
/*
@@ -462,13 +462,13 @@
#define TW5864_VLC_BUF 0x100c
/* Define controls in register TW5864_VLC_BUF */
-/* VLC BK0 full status, write ‘1’ to clear */
+/* VLC BK0 full status, write '1' to clear */
#define TW5864_VLC_BK0_FULL BIT(0)
-/* VLC BK1 full status, write ‘1’ to clear */
+/* VLC BK1 full status, write '1' to clear */
#define TW5864_VLC_BK1_FULL BIT(1)
-/* VLC end slice status, write ‘1’ to clear */
+/* VLC end slice status, write '1' to clear */
#define TW5864_VLC_END_SLICE BIT(2)
-/* VLC Buffer overflow status, write ‘1’ to clear */
+/* VLC Buffer overflow status, write '1' to clear */
#define TW5864_DSP_RD_OF BIT(3)
/* VLC string length in either buffer 0 or 1 at end of frame */
#define TW5864_VLC_STREAM_LEN_SHIFT 4
@@ -476,7 +476,7 @@
/* [15:0] Total coefficient number in a frame */
#define TW5864_TOTAL_COEF_NO 0x1010
-/* [0] VLC Encoder Interrupt. Write ‘1’ to clear */
+/* [0] VLC Encoder Interrupt. Write '1' to clear */
#define TW5864_VLC_DSP_INTR 0x1014
/* [31:0] VLC stream CRC checksum */
#define TW5864_VLC_STREAM_CRC 0x1018
@@ -494,7 +494,7 @@
*/
#define TW5864_VLC_RD_BRST BIT(1)
-/* 0x2000 ~ 0x2ffc -- H264 Stream Memory Map */
+/* 0x2000 ~ 0x2ffc - H264 Stream Memory Map */
/*
* A word is 4 bytes. I.e.,
* VLC_STREAM_MEM[0] address: 0x2000
@@ -506,7 +506,7 @@
#define TW5864_VLC_STREAM_MEM_MAX_OFFSET 0x3ff
#define TW5864_VLC_STREAM_MEM(offset) (TW5864_VLC_STREAM_MEM_START + 4 * offset)
-/* 0x4000 ~ 0x4ffc -- Audio Register Map */
+/* 0x4000 ~ 0x4ffc - Audio Register Map */
/* [31:0] config 1ms cnt = Realtime clk/1000 */
#define TW5864_CFG_1MS_CNT 0x4000
@@ -688,10 +688,10 @@
/*
* [1:0]
- * 2’b00 phase set to 180 degree
- * 2’b01 phase set to 270 degree
- * 2’b10 phase set to 0 degree
- * 2’b11 phase set to 90 degree
+ * 2'b00 phase set to 180 degree
+ * 2'b01 phase set to 270 degree
+ * 2'b10 phase set to 0 degree
+ * 2'b11 phase set to 90 degree
*/
#define TW5864_I2C_PHASE_CFG 0x800c
@@ -826,7 +826,7 @@
/* SPLL_IREF, SPLL_LPX4, SPLL_CPX4, SPLL_PD, SPLL_DBG */
#define TW5864_SPLL 0x8028
-/* 0x8800 ~ 0x88fc -- Interrupt Register Map */
+/* 0x8800 ~ 0x88fc - Interrupt Register Map */
/*
* Trigger mode of interrupt source 0 ~ 15
* 1 Edge trigger mode
@@ -909,7 +909,7 @@
#define TW5864_INTR_I2C_DONE BIT(25)
#define TW5864_INTR_AD BIT(26)
-/* 0x9000 ~ 0x920c -- Video Capture (VIF) Register Map */
+/* 0x9000 ~ 0x920c - Video Capture (VIF) Register Map */
/*
* H264EN_CH_STATUS[n] Status of Vsync synchronized H264EN_CH_EN (Read Only)
* 1 Channel Enabled
@@ -1009,7 +1009,7 @@
/* GPIO Output Enable of Group n */
#define TW5864_GPIO_OEN (0xff << 8)
-/* 0xa000 ~ 0xa8ff – DDR Controller Register Map */
+/* 0xa000 ~ 0xa8ff - DDR Controller Register Map */
/* DDR Controller A */
/*
* [2:0] Data valid counter after read command to DDR. This is the delay value
@@ -1111,7 +1111,7 @@
*/
#define TW5864_DDR_B_OFFSET 0x0800
-/* 0xb004 ~ 0xb018 – HW version/ARB12 Register Map */
+/* 0xb004 ~ 0xb018 - HW version/ARB12 Register Map */
/* [15:0] Default is C013 */
#define TW5864_HW_VERSION 0xb004
@@ -1145,7 +1145,7 @@
/* ARB12 maximum value of time out counter (default 15"h1FF) */
#define TW5864_ARB12_TIME_OUT_CNT 0x7fff
-/* 0xb800 ~ 0xb80c -- Indirect Access Register Map */
+/* 0xb800 ~ 0xb80c - Indirect Access Register Map */
/*
* Spec says:
* In order to access the indirect register space, the following procedure is
@@ -1177,7 +1177,7 @@
/* [31:0] Data used to read/write indirect register space */
#define TW5864_IND_DATA 0xb804
-/* 0xc000 ~ 0xc7fc -- Preview Register Map */
+/* 0xc000 ~ 0xc7fc - Preview Register Map */
/* Mostly skipped this section. */
/*
* [15:0] Status of Vsync Synchronized PCI_PV_CH_EN (Read Only)
@@ -1192,12 +1192,12 @@
*/
#define TW5864_PCI_PV_CH_EN 0xc004
-/* 0xc800 ~ 0xc804 -- JPEG Capture Register Map */
+/* 0xc800 ~ 0xc804 - JPEG Capture Register Map */
/* Skipped. */
-/* 0xd000 ~ 0xd0fc -- JPEG Control Register Map */
+/* 0xd000 ~ 0xd0fc - JPEG Control Register Map */
/* Skipped. */
-/* 0xe000 ~ 0xfc04 – Motion Vector Register Map */
+/* 0xe000 ~ 0xfc04 - Motion Vector Register Map */
/* ME Motion Vector data (Four Byte Each) 0xe000 ~ 0xe7fc */
#define TW5864_ME_MV_VEC_START 0xe000
@@ -1231,7 +1231,7 @@
*/
#define TW5864_MPI_DDR_SEL2 BIT(15)
-/* 0x18000 ~ 0x181fc – PCI Master/Slave Control Map */
+/* 0x18000 ~ 0x181fc - PCI Master/Slave Control Map */
#define TW5864_PCI_INTR_STATUS 0x18000
/* Define controls in register TW5864_PCI_INTR_STATUS */
/* vlc done */
@@ -1400,11 +1400,11 @@
#define TW5864_VLC_STREAM_BASE_ADDR 0x18080
/* MV stream base address */
#define TW5864_MV_STREAM_BASE_ADDR 0x18084
-/* 0x180a0 – 0x180bc: audio burst base address. Skipped. */
-/* 0x180c0 ~ 0x180dc – JPEG Push Mode Buffer Base Address. Skipped. */
-/* 0x18100 – 0x1817c: preview burst base address. Skipped. */
+/* 0x180a0 ~ 0x180bc: audio burst base address. Skipped. */
+/* 0x180c0 ~ 0x180dc: JPEG Push Mode Buffer Base Address. Skipped. */
+/* 0x18100 ~ 0x1817c: preview burst base address. Skipped. */
-/* 0x80000 ~ 0x87fff -- DDR Burst RW Register Map */
+/* 0x80000 ~ 0x87fff - DDR Burst RW Register Map */
#define TW5864_DDR_CTL 0x80000
/* Define controls in register TW5864_DDR_CTL */
#define TW5864_BRST_LENGTH_SHIFT 2
@@ -1516,7 +1516,7 @@
* Vertical Sharpness Control. Writable.
* 0 = None (default)
* 7 = Highest
- * **Note: VSHP must be set to ‘0’ if COMB = 0
+ * **Note: VSHP must be set to '0' if COMB = 0
*/
#define TW5864_INDIR_VIN_1_VSHP 0x07
@@ -1595,7 +1595,7 @@
#define TW5864_INDIR_VIN_9_CNTRST(channel) (0x009 + channel * 0x010)
/*
- * These bits control the brightness. They have value of –128 to 127 in 2's
+ * These bits control the brightness. They have value of -128 to 127 in 2's
* complement form. Positive value increases brightness. A value 0 has no
* effect on the data. The default is 00h.
*/
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index eedc14aafb32..73ce083c2fc6 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin/
obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel/
obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel/
+obj-$(CONFIG_VIDEO_ATMEL_XISC) += atmel/
obj-$(CONFIG_VIDEO_STM32_DCMI) += stm32/
diff --git a/drivers/media/platform/allegro-dvt/nal-h264.c b/drivers/media/platform/allegro-dvt/nal-h264.c
index 94dd9266d850..0ab2fcbee1b9 100644
--- a/drivers/media/platform/allegro-dvt/nal-h264.c
+++ b/drivers/media/platform/allegro-dvt/nal-h264.c
@@ -25,7 +25,7 @@
#include "nal-rbsp.h"
/*
- * See Rec. ITU-T H.264 (04/2017) Table 7-1 – NAL unit type codes, syntax
+ * 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 {
diff --git a/drivers/media/platform/allegro-dvt/nal-hevc.c b/drivers/media/platform/allegro-dvt/nal-hevc.c
index 5db540c69bfe..15a352e45831 100644
--- a/drivers/media/platform/allegro-dvt/nal-hevc.c
+++ b/drivers/media/platform/allegro-dvt/nal-hevc.c
@@ -25,7 +25,7 @@
#include "nal-rbsp.h"
/*
- * See Rec. ITU-T H.265 (02/2018) Table 7-1 – NAL unit type codes and NAL unit
+ * See Rec. ITU-T H.265 (02/2018) Table 7-1 - NAL unit type codes and NAL unit
* type classes
*/
enum nal_unit_type {
diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c
index 6cdc77dda0e4..1c9cb9e05fdf 100644
--- a/drivers/media/platform/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/am437x/am437x-vpfe.c
@@ -1021,7 +1021,9 @@ static int vpfe_initialize_device(struct vpfe_device *vpfe)
if (ret)
return ret;
- pm_runtime_get_sync(vpfe->pdev);
+ ret = pm_runtime_resume_and_get(vpfe->pdev);
+ if (ret < 0)
+ return ret;
vpfe_config_enable(&vpfe->ccdc, 1);
@@ -2443,7 +2445,11 @@ static int vpfe_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
/* for now just enable it here instead of waiting for the open */
- pm_runtime_get_sync(&pdev->dev);
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret < 0) {
+ vpfe_err(vpfe, "Unable to resume device.\n");
+ goto probe_out_v4l2_unregister;
+ }
vpfe_ccdc_config_defaults(ccdc);
@@ -2530,6 +2536,11 @@ static int vpfe_suspend(struct device *dev)
/* only do full suspend if streaming has started */
if (vb2_start_streaming_called(&vpfe->buffer_queue)) {
+ /*
+ * ignore RPM resume errors here, as it is already too late.
+ * A check like that should happen earlier, either at
+ * open() or just before start streaming.
+ */
pm_runtime_get_sync(dev);
vpfe_config_enable(ccdc, 1);
diff --git a/drivers/media/platform/atmel/Kconfig b/drivers/media/platform/atmel/Kconfig
index 1850fe7f9360..99b51213f871 100644
--- a/drivers/media/platform/atmel/Kconfig
+++ b/drivers/media/platform/atmel/Kconfig
@@ -12,6 +12,17 @@ config VIDEO_ATMEL_ISC
This module makes the ATMEL Image Sensor Controller available
as a v4l2 device.
+config VIDEO_ATMEL_XISC
+ tristate "ATMEL eXtended Image Sensor Controller (XISC) support"
+ depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API
+ depends on ARCH_AT91 || COMPILE_TEST
+ select VIDEOBUF2_DMA_CONTIG
+ select REGMAP_MMIO
+ select V4L2_FWNODE
+ help
+ This module makes the ATMEL eXtended Image Sensor Controller
+ available as a v4l2 device.
+
config VIDEO_ATMEL_ISI
tristate "ATMEL Image Sensor Interface (ISI) support"
depends on VIDEO_V4L2 && OF
diff --git a/drivers/media/platform/atmel/Makefile b/drivers/media/platform/atmel/Makefile
index 2dba38994a70..c5c01556c653 100644
--- a/drivers/media/platform/atmel/Makefile
+++ b/drivers/media/platform/atmel/Makefile
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
atmel-isc-objs = atmel-sama5d2-isc.o atmel-isc-base.o
+atmel-xisc-objs = atmel-sama7g5-isc.o atmel-isc-base.o
obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o
obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o
+obj-$(CONFIG_VIDEO_ATMEL_XISC) += atmel-xisc.o
diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/platform/atmel/atmel-isc-base.c
index fe3ec8d0eaee..19daa49bf604 100644
--- a/drivers/media/platform/atmel/atmel-isc-base.c
+++ b/drivers/media/platform/atmel/atmel-isc-base.c
@@ -45,179 +45,6 @@ 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* */
-const struct isc_format controller_formats[] = {
- {
- .fourcc = V4L2_PIX_FMT_ARGB444,
- },
- {
- .fourcc = V4L2_PIX_FMT_ARGB555,
- },
- {
- .fourcc = V4L2_PIX_FMT_RGB565,
- },
- {
- .fourcc = V4L2_PIX_FMT_ABGR32,
- },
- {
- .fourcc = V4L2_PIX_FMT_XBGR32,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUV420,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUYV,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUV422P,
- },
- {
- .fourcc = V4L2_PIX_FMT_GREY,
- },
- {
- .fourcc = V4L2_PIX_FMT_Y10,
- },
-};
-
-/* This is a list of formats that the ISC can receive as *input* */
-struct isc_format formats_list[] = {
- {
- .fourcc = V4L2_PIX_FMT_SBGGR8,
- .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
- .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- .cfa_baycfg = ISC_BAY_CFG_BGBG,
- },
- {
- .fourcc = V4L2_PIX_FMT_SGBRG8,
- .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
- .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- .cfa_baycfg = ISC_BAY_CFG_GBGB,
- },
- {
- .fourcc = V4L2_PIX_FMT_SGRBG8,
- .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
- .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- .cfa_baycfg = ISC_BAY_CFG_GRGR,
- },
- {
- .fourcc = V4L2_PIX_FMT_SRGGB8,
- .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
- .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- .cfa_baycfg = ISC_BAY_CFG_RGRG,
- },
- {
- .fourcc = V4L2_PIX_FMT_SBGGR10,
- .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
- .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
- .cfa_baycfg = ISC_BAY_CFG_RGRG,
- },
- {
- .fourcc = V4L2_PIX_FMT_SGBRG10,
- .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
- .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
- .cfa_baycfg = ISC_BAY_CFG_GBGB,
- },
- {
- .fourcc = V4L2_PIX_FMT_SGRBG10,
- .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
- .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
- .cfa_baycfg = ISC_BAY_CFG_GRGR,
- },
- {
- .fourcc = V4L2_PIX_FMT_SRGGB10,
- .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
- .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
- .cfa_baycfg = ISC_BAY_CFG_RGRG,
- },
- {
- .fourcc = V4L2_PIX_FMT_SBGGR12,
- .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
- .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
- .cfa_baycfg = ISC_BAY_CFG_BGBG,
- },
- {
- .fourcc = V4L2_PIX_FMT_SGBRG12,
- .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
- .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
- .cfa_baycfg = ISC_BAY_CFG_GBGB,
- },
- {
- .fourcc = V4L2_PIX_FMT_SGRBG12,
- .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
- .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
- .cfa_baycfg = ISC_BAY_CFG_GRGR,
- },
- {
- .fourcc = V4L2_PIX_FMT_SRGGB12,
- .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
- .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
- .cfa_baycfg = ISC_BAY_CFG_RGRG,
- },
- {
- .fourcc = V4L2_PIX_FMT_GREY,
- .mbus_code = MEDIA_BUS_FMT_Y8_1X8,
- .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUYV,
- .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
- .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- },
- {
- .fourcc = V4L2_PIX_FMT_RGB565,
- .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
- .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- },
- {
- .fourcc = V4L2_PIX_FMT_Y10,
- .mbus_code = MEDIA_BUS_FMT_Y10_1X10,
- .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
- },
-
-};
-
-/* Gamma table with gamma 1/2.2 */
-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,
- 0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F,
- 0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E,
- 0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C,
- 0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B,
- 0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A,
- 0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A,
- 0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A,
- 0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009,
- 0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 },
-
- /* 1 --> gamma 1/2 */
- { 0x7F, 0x800034, 0xB50028, 0xDE0021, 0x100001E, 0x11E001B,
- 0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013,
- 0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F,
- 0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D,
- 0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B,
- 0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A,
- 0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A,
- 0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009,
- 0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009,
- 0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009,
- 0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 },
-
- /* 2 --> gamma 1/2.2 */
- { 0x99, 0x9B0038, 0xD4002A, 0xFF0023, 0x122001F, 0x141001B,
- 0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012,
- 0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F,
- 0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C,
- 0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B,
- 0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A,
- 0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009,
- 0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009,
- 0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008,
- 0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007,
- 0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 },
-};
-
#define ISC_IS_FORMAT_RAW(mbus_code) \
(((mbus_code) & 0xf000) == 0x3000)
@@ -294,9 +121,13 @@ static int isc_wait_clk_stable(struct clk_hw *hw)
static int isc_clk_prepare(struct clk_hw *hw)
{
struct isc_clk *isc_clk = to_isc_clk(hw);
+ int ret;
- if (isc_clk->id == ISC_ISPCK)
- pm_runtime_get_sync(isc_clk->dev);
+ if (isc_clk->id == ISC_ISPCK) {
+ ret = pm_runtime_resume_and_get(isc_clk->dev);
+ if (ret < 0)
+ return ret;
+ }
return isc_wait_clk_stable(hw);
}
@@ -319,8 +150,8 @@ static int isc_clk_enable(struct clk_hw *hw)
unsigned long flags;
unsigned int status;
- dev_dbg(isc_clk->dev, "ISC CLK: %s, div = %d, parent id = %d\n",
- __func__, isc_clk->div, isc_clk->parent_id);
+ dev_dbg(isc_clk->dev, "ISC CLK: %s, id = %d, div = %d, parent id = %d\n",
+ __func__, id, isc_clk->div, isc_clk->parent_id);
spin_lock_irqsave(&isc_clk->lock, flags);
regmap_update_bits(regmap, ISC_CLKCFG,
@@ -353,9 +184,13 @@ static int isc_clk_is_enabled(struct clk_hw *hw)
{
struct isc_clk *isc_clk = to_isc_clk(hw);
u32 status;
+ int ret;
- if (isc_clk->id == ISC_ISPCK)
- pm_runtime_get_sync(isc_clk->dev);
+ if (isc_clk->id == ISC_ISPCK) {
+ ret = pm_runtime_resume_and_get(isc_clk->dev);
+ if (ret < 0)
+ return 0;
+ }
regmap_read(isc_clk->regmap, ISC_CLKSR, &status);
@@ -635,16 +470,20 @@ static void isc_start_dma(struct isc_device *isc)
ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN);
addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0);
- regmap_write(regmap, ISC_DAD0, addr0);
+ regmap_write(regmap, ISC_DAD0 + isc->offsets.dma, addr0);
switch (isc->config.fourcc) {
case V4L2_PIX_FMT_YUV420:
- regmap_write(regmap, ISC_DAD1, addr0 + (sizeimage * 2) / 3);
- regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 5) / 6);
+ regmap_write(regmap, ISC_DAD1 + isc->offsets.dma,
+ addr0 + (sizeimage * 2) / 3);
+ regmap_write(regmap, ISC_DAD2 + isc->offsets.dma,
+ addr0 + (sizeimage * 5) / 6);
break;
case V4L2_PIX_FMT_YUV422P:
- regmap_write(regmap, ISC_DAD1, addr0 + sizeimage / 2);
- regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 3) / 4);
+ regmap_write(regmap, ISC_DAD1 + isc->offsets.dma,
+ addr0 + sizeimage / 2);
+ regmap_write(regmap, ISC_DAD2 + isc->offsets.dma,
+ addr0 + (sizeimage * 3) / 4);
break;
default:
break;
@@ -652,7 +491,8 @@ 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);
+ regmap_write(regmap, ISC_DCTRL + isc->offsets.dma,
+ dctrl_dview | ISC_DCTRL_IE_IS);
spin_lock(&isc->awb_lock);
regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE);
spin_unlock(&isc->awb_lock);
@@ -683,21 +523,16 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL);
- gamma = &isc_gamma_table[ctrls->gamma_index][0];
+ gamma = &isc->gamma_table[ctrls->gamma_index][0];
regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES);
regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES);
regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES);
- /* Convert RGB to YUV */
- regmap_write(regmap, ISC_CSC_YR_YG, 0x42 | (0x81 << 16));
- regmap_write(regmap, ISC_CSC_YB_OY, 0x19 | (0x10 << 16));
- regmap_write(regmap, ISC_CSC_CBR_CBG, 0xFDA | (0xFB6 << 16));
- regmap_write(regmap, ISC_CSC_CBB_OCB, 0x70 | (0x80 << 16));
- regmap_write(regmap, ISC_CSC_CRR_CRG, 0x70 | (0xFA2 << 16));
- regmap_write(regmap, ISC_CSC_CRB_OCR, 0xFEE | (0x80 << 16));
-
- regmap_write(regmap, ISC_CBC_BRIGHT, ctrls->brightness);
- regmap_write(regmap, ISC_CBC_CONTRAST, ctrls->contrast);
+ isc->config_dpc(isc);
+ isc->config_csc(isc);
+ isc->config_cbc(isc);
+ isc->config_cc(isc);
+ isc->config_gam(isc);
}
static int isc_update_profile(struct isc_device *isc)
@@ -728,12 +563,13 @@ static void isc_set_histogram(struct isc_device *isc, bool enable)
struct isc_ctrls *ctrls = &isc->ctrls;
if (enable) {
- regmap_write(regmap, ISC_HIS_CFG,
+ regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his,
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_HIS_CTRL + isc->offsets.his,
+ ISC_HIS_CTRL_EN);
regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE);
ctrls->hist_id = ISC_HIS_CFG_MODE_GR;
isc_update_profile(isc);
@@ -742,7 +578,8 @@ static void isc_set_histogram(struct isc_device *isc, bool enable)
ctrls->hist_stat = HIST_ENABLED;
} else {
regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE);
- regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_DIS);
+ regmap_write(regmap, ISC_HIS_CTRL + isc->offsets.his,
+ ISC_HIS_CTRL_DIS);
ctrls->hist_stat = HIST_DISABLED;
}
@@ -751,28 +588,25 @@ static void isc_set_histogram(struct isc_device *isc, bool enable)
static int isc_configure(struct isc_device *isc)
{
struct regmap *regmap = isc->regmap;
- u32 pfe_cfg0, rlp_mode, dcfg, mask, pipeline;
+ u32 pfe_cfg0, dcfg, mask, pipeline;
struct isc_subdev_entity *subdev = isc->current_subdev;
pfe_cfg0 = isc->config.sd_format->pfe_cfg0_bps;
- rlp_mode = isc->config.rlp_cfg_mode;
pipeline = isc->config.bits_pipeline;
- dcfg = isc->config.dcfg_imode |
- ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
+ dcfg = isc->config.dcfg_imode | isc->dcfg;
pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE;
mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW |
ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW |
ISC_PFE_CFG0_MODE_MASK | ISC_PFE_CFG0_CCIR_CRC |
- ISC_PFE_CFG0_CCIR656;
+ ISC_PFE_CFG0_CCIR656 | ISC_PFE_CFG0_MIPI;
regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0);
- regmap_update_bits(regmap, ISC_RLP_CFG, ISC_RLP_CFG_MODE_MASK,
- rlp_mode);
+ isc->config_rlp(isc);
- regmap_write(regmap, ISC_DCFG, dcfg);
+ regmap_write(regmap, ISC_DCFG + isc->offsets.dma, dcfg);
/* Set the pipeline */
isc_set_pipeline(isc, pipeline);
@@ -807,7 +641,12 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
goto err_start_stream;
}
- pm_runtime_get_sync(isc->dev);
+ ret = pm_runtime_resume_and_get(isc->dev);
+ if (ret < 0) {
+ v4l2_err(&isc->v4l2_dev, "RPM resume failed in subdev %d\n",
+ ret);
+ goto err_pm_get;
+ }
ret = isc_configure(isc);
if (unlikely(ret))
@@ -838,7 +677,7 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
err_configure:
pm_runtime_put_sync(isc->dev);
-
+err_pm_get:
v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0);
err_start_stream:
@@ -938,7 +777,7 @@ static int isc_querycap(struct file *file, void *priv,
{
struct isc_device *isc = video_drvdata(file);
- strscpy(cap->driver, ATMEL_ISC_NAME, sizeof(cap->driver));
+ strscpy(cap->driver, "microchip-isc", sizeof(cap->driver));
strscpy(cap->card, "Atmel Image Sensor Controller", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", isc->v4l2_dev.name);
@@ -949,25 +788,25 @@ static int isc_querycap(struct file *file, void *priv,
static int isc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
+ struct isc_device *isc = video_drvdata(file);
u32 index = f->index;
u32 i, supported_index;
- if (index < ARRAY_SIZE(controller_formats)) {
- f->pixelformat = controller_formats[index].fourcc;
+ if (index < isc->controller_formats_size) {
+ f->pixelformat = isc->controller_formats[index].fourcc;
return 0;
}
- index -= ARRAY_SIZE(controller_formats);
+ index -= isc->controller_formats_size;
- i = 0;
supported_index = 0;
- for (i = 0; i < ARRAY_SIZE(formats_list); i++) {
- if (!ISC_IS_FORMAT_RAW(formats_list[i].mbus_code) ||
- !formats_list[i].sd_support)
+ for (i = 0; i < isc->formats_list_size; i++) {
+ if (!ISC_IS_FORMAT_RAW(isc->formats_list[i].mbus_code) ||
+ !isc->formats_list[i].sd_support)
continue;
if (supported_index == index) {
- f->pixelformat = formats_list[i].fourcc;
+ f->pixelformat = isc->formats_list[i].fourcc;
return 0;
}
supported_index++;
@@ -1016,6 +855,8 @@ static int isc_try_validate_formats(struct isc_device *isc)
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YUV422P:
case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
ret = 0;
yuv = true;
break;
@@ -1030,6 +871,7 @@ static int isc_try_validate_formats(struct isc_device *isc)
break;
case V4L2_PIX_FMT_GREY:
case V4L2_PIX_FMT_Y10:
+ case V4L2_PIX_FMT_Y16:
ret = 0;
grey = true;
break;
@@ -1060,6 +902,8 @@ static int isc_try_validate_formats(struct isc_device *isc)
*/
static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump)
{
+ isc->try_config.rlp_cfg_mode = 0;
+
switch (isc->try_config.fourcc) {
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
@@ -1126,7 +970,19 @@ static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump)
isc->try_config.bpp = 16;
break;
case V4L2_PIX_FMT_YUYV:
- isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC;
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_YUYV;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_UYVY;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ break;
+ case V4L2_PIX_FMT_VYUY:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_VYUY;
isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
isc->try_config.bpp = 16;
@@ -1137,8 +993,11 @@ static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump)
isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
isc->try_config.bpp = 8;
break;
+ case V4L2_PIX_FMT_Y16:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY10 | ISC_RLP_CFG_LSH;
+ fallthrough;
case V4L2_PIX_FMT_Y10:
- isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY10;
+ isc->try_config.rlp_cfg_mode |= ISC_RLP_CFG_MODE_DATY10;
isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
isc->try_config.bpp = 16;
@@ -1172,7 +1031,8 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
/* if sensor format is RAW, we convert inside ISC */
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
- WB_ENABLE | GAM_ENABLES;
+ WB_ENABLE | GAM_ENABLES | DPC_BLCENABLE |
+ CC_ENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
@@ -1181,8 +1041,9 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
/* if sensor format is RAW, we convert inside ISC */
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
- CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
- SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE;
+ CSC_ENABLE | GAM_ENABLES | WB_ENABLE |
+ SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE |
+ DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
@@ -1192,39 +1053,49 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
- SUB422_ENABLE | CBC_ENABLE;
+ SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
break;
case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
/* if sensor format is RAW, we convert inside ISC */
if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
- SUB422_ENABLE | CBC_ENABLE;
+ SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
break;
case V4L2_PIX_FMT_GREY:
- if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
+ case V4L2_PIX_FMT_Y16:
/* if sensor format is RAW, we convert inside ISC */
+ if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
isc->try_config.bits_pipeline = CFA_ENABLE |
CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
- CBC_ENABLE;
+ CBC_ENABLE | DPC_BLCENABLE;
} else {
isc->try_config.bits_pipeline = 0x0;
}
break;
default:
- isc->try_config.bits_pipeline = 0x0;
+ if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code))
+ isc->try_config.bits_pipeline = WB_ENABLE | DPC_BLCENABLE;
+ else
+ isc->try_config.bits_pipeline = 0x0;
}
+
+ /* Tune the pipeline to product specific */
+ isc->adapt_pipeline(isc);
+
return 0;
}
static void isc_try_fse(struct isc_device *isc,
- struct v4l2_subdev_pad_config *pad_cfg)
+ struct v4l2_subdev_state *sd_state)
{
int ret;
struct v4l2_subdev_frame_size_enum fse = {};
@@ -1240,17 +1111,17 @@ static void isc_try_fse(struct isc_device *isc,
fse.which = V4L2_SUBDEV_FORMAT_TRY;
ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size,
- pad_cfg, &fse);
+ sd_state, &fse);
/*
* Attempt to obtain format size from subdev. If not available,
* just use the maximum ISC can receive.
*/
if (ret) {
- pad_cfg->try_crop.width = ISC_MAX_SUPPORT_WIDTH;
- pad_cfg->try_crop.height = ISC_MAX_SUPPORT_HEIGHT;
+ sd_state->pads->try_crop.width = isc->max_width;
+ sd_state->pads->try_crop.height = isc->max_height;
} else {
- pad_cfg->try_crop.width = fse.max_width;
- pad_cfg->try_crop.height = fse.max_height;
+ sd_state->pads->try_crop.width = fse.max_width;
+ sd_state->pads->try_crop.height = fse.max_height;
}
}
@@ -1261,6 +1132,9 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
struct isc_format *sd_fmt = NULL, *direct_fmt = NULL;
struct v4l2_pix_format *pixfmt = &f->fmt.pix;
struct v4l2_subdev_pad_config pad_cfg = {};
+ struct v4l2_subdev_state pad_state = {
+ .pads = &pad_cfg
+ };
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -1324,10 +1198,10 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
isc->try_config.sd_format = sd_fmt;
/* Limit to Atmel ISC hardware capabilities */
- if (pixfmt->width > ISC_MAX_SUPPORT_WIDTH)
- pixfmt->width = ISC_MAX_SUPPORT_WIDTH;
- if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT)
- pixfmt->height = ISC_MAX_SUPPORT_HEIGHT;
+ if (pixfmt->width > isc->max_width)
+ pixfmt->width = isc->max_width;
+ if (pixfmt->height > isc->max_height)
+ pixfmt->height = isc->max_height;
/*
* The mbus format is the one the subdev outputs.
@@ -1358,16 +1232,22 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
goto isc_try_fmt_err;
/* Obtain frame sizes if possible to have crop requirements ready */
- isc_try_fse(isc, &pad_cfg);
+ isc_try_fse(isc, &pad_state);
v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code);
ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt,
- &pad_cfg, &format);
+ &pad_state, &format);
if (ret < 0)
goto isc_try_fmt_subdev_err;
v4l2_fill_pix_format(pixfmt, &format.format);
+ /* Limit to Atmel ISC hardware capabilities */
+ if (pixfmt->width > isc->max_width)
+ pixfmt->width = isc->max_width;
+ if (pixfmt->height > isc->max_height)
+ pixfmt->height = isc->max_height;
+
pixfmt->field = V4L2_FIELD_NONE;
pixfmt->bytesperline = (pixfmt->width * isc->try_config.bpp) >> 3;
pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
@@ -1403,6 +1283,12 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
if (ret < 0)
return ret;
+ /* Limit to Atmel ISC hardware capabilities */
+ if (f->fmt.pix.width > isc->max_width)
+ f->fmt.pix.width = isc->max_width;
+ if (f->fmt.pix.height > isc->max_height)
+ f->fmt.pix.height = isc->max_height;
+
isc->fmt = *f;
if (isc->try_config.sd_format && isc->config.sd_format &&
@@ -1496,8 +1382,8 @@ static int isc_enum_framesizes(struct file *file, void *fh,
if (isc->user_formats[i]->fourcc == fsize->pixel_format)
ret = 0;
- for (i = 0; i < ARRAY_SIZE(controller_formats); i++)
- if (controller_formats[i].fourcc == fsize->pixel_format)
+ for (i = 0; i < isc->controller_formats_size; i++)
+ if (isc->controller_formats[i].fourcc == fsize->pixel_format)
ret = 0;
if (ret)
@@ -1533,8 +1419,8 @@ static int isc_enum_frameintervals(struct file *file, void *fh,
if (isc->user_formats[i]->fourcc == fival->pixel_format)
ret = 0;
- for (i = 0; i < ARRAY_SIZE(controller_formats); i++)
- if (controller_formats[i].fourcc == fival->pixel_format)
+ for (i = 0; i < isc->controller_formats_size; i++)
+ if (isc->controller_formats[i].fourcc == fival->pixel_format)
ret = 0;
if (ret)
@@ -1704,7 +1590,8 @@ static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
*min = 0;
*max = HIST_ENTRIES;
- regmap_bulk_read(regmap, ISC_HIS_ENTRY, hist_entry, HIST_ENTRIES);
+ regmap_bulk_read(regmap, ISC_HIS_ENTRY + isc->offsets.his_entry,
+ hist_entry, HIST_ENTRIES);
*hist_count = 0;
/*
@@ -1809,6 +1696,7 @@ static void isc_awb_work(struct work_struct *w)
u32 baysel;
unsigned long flags;
u32 min, max;
+ int ret;
/* streaming is not active anymore */
if (isc->stop)
@@ -1831,7 +1719,9 @@ static void isc_awb_work(struct work_struct *w)
ctrls->hist_id = hist_id;
baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT;
- pm_runtime_get_sync(isc->dev);
+ ret = pm_runtime_resume_and_get(isc->dev);
+ if (ret < 0)
+ return;
/*
* only update if we have all the required histograms and controls
@@ -1860,7 +1750,8 @@ static void isc_awb_work(struct work_struct *w)
ctrls->awb = ISC_WB_NONE;
}
}
- regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR);
+ regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his,
+ hist_id | baysel | ISC_HIS_CFG_RAR);
isc_update_profile(isc);
/* if awb has been disabled, we don't need to start another histogram */
if (ctrls->awb)
@@ -2065,12 +1956,14 @@ static int isc_ctrl_init(struct isc_device *isc)
if (ret < 0)
return ret;
+ /* Initialize product specific controls. For example, contrast */
+ isc->config_ctrls(isc, ops);
+
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_GAMMA, 0, isc->gamma_max, 1,
+ isc->gamma_max);
isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
V4L2_CID_AUTO_WHITE_BALANCE,
0, 1, 1, 1);
@@ -2138,12 +2031,13 @@ static void isc_async_unbind(struct v4l2_async_notifier *notifier,
v4l2_ctrl_handler_free(&isc->ctrls.handler);
}
-static struct isc_format *find_format_by_code(unsigned int code, int *index)
+static struct isc_format *find_format_by_code(struct isc_device *isc,
+ unsigned int code, int *index)
{
- struct isc_format *fmt = &formats_list[0];
+ struct isc_format *fmt = &isc->formats_list[0];
unsigned int i;
- for (i = 0; i < ARRAY_SIZE(formats_list); i++) {
+ for (i = 0; i < isc->formats_list_size; i++) {
if (fmt->mbus_code == code) {
*index = i;
return fmt;
@@ -2160,7 +2054,7 @@ static int isc_formats_init(struct isc_device *isc)
struct isc_format *fmt;
struct v4l2_subdev *subdev = isc->current_subdev->sd;
unsigned int num_fmts, i, j;
- u32 list_size = ARRAY_SIZE(formats_list);
+ u32 list_size = isc->formats_list_size;
struct v4l2_subdev_mbus_code_enum mbus_code = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
};
@@ -2170,7 +2064,7 @@ static int isc_formats_init(struct isc_device *isc)
NULL, &mbus_code)) {
mbus_code.index++;
- fmt = find_format_by_code(mbus_code.code, &i);
+ fmt = find_format_by_code(isc, mbus_code.code, &i);
if (!fmt) {
v4l2_warn(&isc->v4l2_dev, "Mbus code %x not supported\n",
mbus_code.code);
@@ -2191,7 +2085,7 @@ static int isc_formats_init(struct isc_device *isc)
if (!isc->user_formats)
return -ENOMEM;
- fmt = &formats_list[0];
+ fmt = &isc->formats_list[0];
for (i = 0, j = 0; i < list_size; i++) {
if (fmt->sd_support)
isc->user_formats[j++] = fmt;
@@ -2287,7 +2181,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
}
/* Register video device */
- strscpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name));
+ strscpy(vdev->name, "microchip-isc", sizeof(vdev->name));
vdev->release = video_device_release_empty;
vdev->fops = &isc_fops;
vdev->ioctl_ops = &isc_ioctl_ops;
@@ -2338,8 +2232,14 @@ int isc_pipeline_init(struct isc_device *isc)
struct regmap_field *regs;
unsigned int i;
- /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */
+ /*
+ * DPCEN-->GDCEN-->BLCEN-->WB-->CFA-->CC-->
+ * GAM-->VHXS-->CSC-->CBC-->SUB422-->SUB420
+ */
const struct reg_field regfields[ISC_PIPE_LINE_NODE_NUM] = {
+ REG_FIELD(ISC_DPC_CTRL, 0, 0),
+ REG_FIELD(ISC_DPC_CTRL, 1, 1),
+ REG_FIELD(ISC_DPC_CTRL, 2, 2),
REG_FIELD(ISC_WB_CTRL, 0, 0),
REG_FIELD(ISC_CFA_CTRL, 0, 0),
REG_FIELD(ISC_CC_CTRL, 0, 0),
@@ -2347,10 +2247,11 @@ int isc_pipeline_init(struct isc_device *isc)
REG_FIELD(ISC_GAM_CTRL, 1, 1),
REG_FIELD(ISC_GAM_CTRL, 2, 2),
REG_FIELD(ISC_GAM_CTRL, 3, 3),
- REG_FIELD(ISC_CSC_CTRL, 0, 0),
- REG_FIELD(ISC_CBC_CTRL, 0, 0),
- REG_FIELD(ISC_SUB422_CTRL, 0, 0),
- REG_FIELD(ISC_SUB420_CTRL, 0, 0),
+ REG_FIELD(ISC_VHXS_CTRL, 0, 0),
+ REG_FIELD(ISC_CSC_CTRL + isc->offsets.csc, 0, 0),
+ REG_FIELD(ISC_CBC_CTRL + isc->offsets.cbc, 0, 0),
+ REG_FIELD(ISC_SUB422_CTRL + isc->offsets.sub422, 0, 0),
+ REG_FIELD(ISC_SUB420_CTRL + isc->offsets.sub420, 0, 0),
};
for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) {
@@ -2365,7 +2266,7 @@ int isc_pipeline_init(struct isc_device *isc)
}
/* regmap configuration */
-#define ATMEL_ISC_REG_MAX 0xbfc
+#define ATMEL_ISC_REG_MAX 0xd5c
const struct regmap_config isc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
diff --git a/drivers/media/platform/atmel/atmel-isc-regs.h b/drivers/media/platform/atmel/atmel-isc-regs.h
index f1e160ed4351..d06b72228d4f 100644
--- a/drivers/media/platform/atmel/atmel-isc-regs.h
+++ b/drivers/media/platform/atmel/atmel-isc-regs.h
@@ -26,6 +26,7 @@
#define ISC_PFE_CFG0_PPOL_LOW BIT(2)
#define ISC_PFE_CFG0_CCIR656 BIT(9)
#define ISC_PFE_CFG0_CCIR_CRC BIT(10)
+#define ISC_PFE_CFG0_MIPI BIT(14)
#define ISC_PFE_CFG0_MODE_PROGRESSIVE (0x0 << 4)
#define ISC_PFE_CFG0_MODE_MASK GENMASK(6, 4)
@@ -90,6 +91,46 @@
#define ISC_INT_DDONE BIT(8)
#define ISC_INT_HISDONE BIT(12)
+/* ISC DPC Control Register */
+#define ISC_DPC_CTRL 0x40
+
+#define ISC_DPC_CTRL_DPCEN BIT(0)
+#define ISC_DPC_CTRL_GDCEN BIT(1)
+#define ISC_DPC_CTRL_BLCEN BIT(2)
+
+/* ISC DPC Config Register */
+#define ISC_DPC_CFG 0x44
+
+#define ISC_DPC_CFG_BAYSEL_SHIFT 0
+
+#define ISC_DPC_CFG_EITPOL BIT(4)
+
+#define ISC_DPC_CFG_TA_ENABLE BIT(14)
+#define ISC_DPC_CFG_TC_ENABLE BIT(13)
+#define ISC_DPC_CFG_TM_ENABLE BIT(12)
+
+#define ISC_DPC_CFG_RE_MODE BIT(17)
+
+#define ISC_DPC_CFG_GDCCLP_SHIFT 20
+#define ISC_DPC_CFG_GDCCLP_MASK GENMASK(22, 20)
+
+#define ISC_DPC_CFG_BLOFF_SHIFT 24
+#define ISC_DPC_CFG_BLOFF_MASK GENMASK(31, 24)
+
+#define ISC_DPC_CFG_BAYCFG_SHIFT 0
+#define ISC_DPC_CFG_BAYCFG_MASK GENMASK(1, 0)
+/* ISC DPC Threshold Median Register */
+#define ISC_DPC_THRESHM 0x48
+
+/* ISC DPC Threshold Closest Register */
+#define ISC_DPC_THRESHC 0x4C
+
+/* ISC DPC Threshold Average Register */
+#define ISC_DPC_THRESHA 0x50
+
+/* ISC DPC STatus Register */
+#define ISC_DPC_SR 0x54
+
/* ISC White Balance Control Register */
#define ISC_WB_CTRL 0x00000058
@@ -144,6 +185,8 @@
/* ISC Gamma Correction Control Register */
#define ISC_GAM_CTRL 0x00000094
+#define ISC_GAM_CTRL_BIPART BIT(4)
+
/* ISC_Gamma Correction Blue Entry Register */
#define ISC_GAM_BENTRY 0x00000098
@@ -153,6 +196,38 @@
/* ISC_Gamma Correction Green Entry Register */
#define ISC_GAM_RENTRY 0x00000298
+/* ISC VHXS Control Register */
+#define ISC_VHXS_CTRL 0x398
+
+/* ISC VHXS Source Size Register */
+#define ISC_VHXS_SS 0x39C
+
+/* ISC VHXS Destination Size Register */
+#define ISC_VHXS_DS 0x3A0
+
+/* ISC Vertical Factor Register */
+#define ISC_VXS_FACT 0x3a4
+
+/* ISC Horizontal Factor Register */
+#define ISC_HXS_FACT 0x3a8
+
+/* ISC Vertical Config Register */
+#define ISC_VXS_CFG 0x3ac
+
+/* ISC Horizontal Config Register */
+#define ISC_HXS_CFG 0x3b0
+
+/* ISC Vertical Tap Register */
+#define ISC_VXS_TAP 0x3b4
+
+/* ISC Horizontal Tap Register */
+#define ISC_HXS_TAP 0x434
+
+/* Offset for CSC register specific to sama5d2 product */
+#define ISC_SAMA5D2_CSC_OFFSET 0
+/* Offset for CSC register specific to sama7g5 product */
+#define ISC_SAMA7G5_CSC_OFFSET 0x11c
+
/* Color Space Conversion Control Register */
#define ISC_CSC_CTRL 0x00000398
@@ -174,6 +249,11 @@
/* Color Space Conversion CRB OCR Register */
#define ISC_CSC_CRB_OCR 0x000003b0
+/* Offset for CBC register specific to sama5d2 product */
+#define ISC_SAMA5D2_CBC_OFFSET 0
+/* Offset for CBC register specific to sama7g5 product */
+#define ISC_SAMA7G5_CBC_OFFSET 0x11c
+
/* Contrast And Brightness Control Register */
#define ISC_CBC_CTRL 0x000003b4
@@ -188,12 +268,30 @@
#define ISC_CBC_CONTRAST 0x000003c0
#define ISC_CBC_CONTRAST_MASK GENMASK(11, 0)
+/* Hue Register */
+#define ISC_CBCHS_HUE 0x4e0
+/* Saturation Register */
+#define ISC_CBCHS_SAT 0x4e4
+
+/* Offset for SUB422 register specific to sama5d2 product */
+#define ISC_SAMA5D2_SUB422_OFFSET 0
+/* Offset for SUB422 register specific to sama7g5 product */
+#define ISC_SAMA7G5_SUB422_OFFSET 0x124
+
/* Subsampling 4:4:4 to 4:2:2 Control Register */
#define ISC_SUB422_CTRL 0x000003c4
+/* Offset for SUB420 register specific to sama5d2 product */
+#define ISC_SAMA5D2_SUB420_OFFSET 0
+/* Offset for SUB420 register specific to sama7g5 product */
+#define ISC_SAMA7G5_SUB420_OFFSET 0x124
/* Subsampling 4:2:2 to 4:2:0 Control Register */
#define ISC_SUB420_CTRL 0x000003cc
+/* Offset for RLP register specific to sama5d2 product */
+#define ISC_SAMA5D2_RLP_OFFSET 0
+/* Offset for RLP register specific to sama7g5 product */
+#define ISC_SAMA7G5_RLP_OFFSET 0x124
/* Rounding, Limiting and Packing Configuration Register */
#define ISC_RLP_CFG 0x000003d0
@@ -210,8 +308,22 @@
#define ISC_RLP_CFG_MODE_ARGB32 0xa
#define ISC_RLP_CFG_MODE_YYCC 0xb
#define ISC_RLP_CFG_MODE_YYCC_LIMITED 0xc
+#define ISC_RLP_CFG_MODE_YCYC 0xd
#define ISC_RLP_CFG_MODE_MASK GENMASK(3, 0)
+#define ISC_RLP_CFG_LSH BIT(5)
+
+#define ISC_RLP_CFG_YMODE_YUYV (3 << 6)
+#define ISC_RLP_CFG_YMODE_YVYU (2 << 6)
+#define ISC_RLP_CFG_YMODE_VYUY (0 << 6)
+#define ISC_RLP_CFG_YMODE_UYVY (1 << 6)
+
+#define ISC_RLP_CFG_YMODE_MASK GENMASK(7, 6)
+
+/* Offset for HIS register specific to sama5d2 product */
+#define ISC_SAMA5D2_HIS_OFFSET 0
+/* Offset for HIS register specific to sama7g5 product */
+#define ISC_SAMA7G5_HIS_OFFSET 0x124
/* Histogram Control Register */
#define ISC_HIS_CTRL 0x000003d4
@@ -233,6 +345,11 @@
#define ISC_HIS_CFG_RAR BIT(8)
+/* Offset for DMA register specific to sama5d2 product */
+#define ISC_SAMA5D2_DMA_OFFSET 0
+/* Offset for DMA register specific to sama7g5 product */
+#define ISC_SAMA7G5_DMA_OFFSET 0x13c
+
/* DMA Configuration Register */
#define ISC_DCFG 0x000003e0
#define ISC_DCFG_IMODE_PACKED8 0x0
@@ -248,13 +365,15 @@
#define ISC_DCFG_YMBSIZE_BEATS4 (0x1 << 4)
#define ISC_DCFG_YMBSIZE_BEATS8 (0x2 << 4)
#define ISC_DCFG_YMBSIZE_BEATS16 (0x3 << 4)
-#define ISC_DCFG_YMBSIZE_MASK GENMASK(5, 4)
+#define ISC_DCFG_YMBSIZE_BEATS32 (0x4 << 4)
+#define ISC_DCFG_YMBSIZE_MASK GENMASK(6, 4)
#define ISC_DCFG_CMBSIZE_SINGLE (0x0 << 8)
#define ISC_DCFG_CMBSIZE_BEATS4 (0x1 << 8)
#define ISC_DCFG_CMBSIZE_BEATS8 (0x2 << 8)
#define ISC_DCFG_CMBSIZE_BEATS16 (0x3 << 8)
-#define ISC_DCFG_CMBSIZE_MASK GENMASK(9, 8)
+#define ISC_DCFG_CMBSIZE_BEATS32 (0x4 << 8)
+#define ISC_DCFG_CMBSIZE_MASK GENMASK(10, 8)
/* DMA Control Register */
#define ISC_DCTRL 0x000003e4
@@ -278,6 +397,16 @@
/* DMA Address 2 Register */
#define ISC_DAD2 0x000003fc
+/* Offset for version register specific to sama5d2 product */
+#define ISC_SAMA5D2_VERSION_OFFSET 0
+#define ISC_SAMA7G5_VERSION_OFFSET 0x13c
+/* Version Register */
+#define ISC_VERSION 0x0000040c
+
+/* Offset for version register specific to sama5d2 product */
+#define ISC_SAMA5D2_HIS_ENTRY_OFFSET 0
+/* Offset for version register specific to sama7g5 product */
+#define ISC_SAMA7G5_HIS_ENTRY_OFFSET 0x14c
/* Histogram Entry */
#define ISC_HIS_ENTRY 0x00000410
diff --git a/drivers/media/platform/atmel/atmel-isc.h b/drivers/media/platform/atmel/atmel-isc.h
index fab8eca58d93..19cc60dfcbe0 100644
--- a/drivers/media/platform/atmel/atmel-isc.h
+++ b/drivers/media/platform/atmel/atmel-isc.h
@@ -10,9 +10,6 @@
*/
#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 {
@@ -71,17 +68,21 @@ struct isc_format {
};
/* 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 DPC_DPCENABLE BIT(0)
+#define DPC_GDCENABLE BIT(1)
+#define DPC_BLCENABLE BIT(2)
+#define WB_ENABLE BIT(3)
+#define CFA_ENABLE BIT(4)
+#define CC_ENABLE BIT(5)
+#define GAM_ENABLE BIT(6)
+#define GAM_BENABLE BIT(7)
+#define GAM_GENABLE BIT(8)
+#define GAM_RENABLE BIT(9)
+#define VHXS_ENABLE BIT(10)
+#define CSC_ENABLE BIT(11)
+#define CBC_ENABLE BIT(12)
+#define SUB422_ENABLE BIT(13)
+#define SUB420_ENABLE BIT(14)
#define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE)
@@ -145,7 +146,31 @@ struct isc_ctrls {
u32 hist_minmax[HIST_BAYER][2];
};
-#define ISC_PIPE_LINE_NODE_NUM 11
+#define ISC_PIPE_LINE_NODE_NUM 15
+
+/*
+ * struct isc_reg_offsets - ISC device register offsets
+ * @csc: Offset for the CSC register
+ * @cbc: Offset for the CBC register
+ * @sub422: Offset for the SUB422 register
+ * @sub420: Offset for the SUB420 register
+ * @rlp: Offset for the RLP register
+ * @his: Offset for the HIS related registers
+ * @dma: Offset for the DMA related registers
+ * @version: Offset for the version register
+ * @his_entry: Offset for the HIS entries registers
+ */
+struct isc_reg_offsets {
+ u32 csc;
+ u32 cbc;
+ u32 sub422;
+ u32 sub420;
+ u32 rlp;
+ u32 his;
+ u32 dma;
+ u32 version;
+ u32 his_entry;
+};
/*
* struct isc_device - ISC device driver data/config struct
@@ -153,6 +178,7 @@ struct isc_ctrls {
* @hclock: Hclock clock input (refer datasheet)
* @ispck: iscpck clock (refer datasheet)
* @isc_clks: ISC clocks
+ * @dcfg: DMA master configuration, architecture dependent
*
* @dev: Registered device driver
* @v4l2_dev: v4l2 registered device
@@ -187,12 +213,46 @@ struct isc_ctrls {
*
* @current_subdev: current subdevice: the sensor
* @subdev_entities: list of subdevice entitites
+ *
+ * @gamma_table: pointer to the table with gamma values, has
+ * gamma_max sets of GAMMA_ENTRIES entries each
+ * @gamma_max: maximum number of sets of inside the gamma_table
+ *
+ * @max_width: maximum frame width, dependent on the internal RAM
+ * @max_height: maximum frame height, dependent on the internal RAM
+ *
+ * @config_dpc: pointer to a function that initializes product
+ * specific DPC module
+ * @config_csc: pointer to a function that initializes product
+ * specific CSC module
+ * @config_cbc: pointer to a function that initializes product
+ * specific CBC module
+ * @config_cc: pointer to a function that initializes product
+ * specific CC module
+ * @config_gam: pointer to a function that initializes product
+ * specific GAMMA module
+ * @config_rlp: pointer to a function that initializes product
+ * specific RLP module
+ * @config_ctrls: pointer to a functoin that initializes product
+ * specific v4l2 controls.
+ *
+ * @adapt_pipeline: pointer to a function that adapts the pipeline bits
+ * to the product specific pipeline
+ *
+ * @offsets: struct holding the product specific register offsets
+ * @controller_formats: pointer to the array of possible formats that the
+ * controller can output
+ * @formats_list: pointer to the array of possible formats that can
+ * be used as an input to the controller
+ * @controller_formats_size: size of controller_formats array
+ * @formats_list_size: size of formats_list array
*/
struct isc_device {
struct regmap *regmap;
struct clk *hclock;
struct clk *ispck;
struct isc_clk isc_clks[2];
+ u32 dcfg;
struct device *dev;
struct v4l2_device v4l2_dev;
@@ -245,16 +305,36 @@ struct isc_device {
struct v4l2_ctrl *gr_off_ctrl;
struct v4l2_ctrl *gb_off_ctrl;
};
-};
-#define GAMMA_MAX 2
#define GAMMA_ENTRIES 64
+ /* pointer to the defined gamma table */
+ const u32 (*gamma_table)[GAMMA_ENTRIES];
+ u32 gamma_max;
+
+ u32 max_width;
+ u32 max_height;
+
+ struct {
+ void (*config_dpc)(struct isc_device *isc);
+ void (*config_csc)(struct isc_device *isc);
+ void (*config_cbc)(struct isc_device *isc);
+ void (*config_cc)(struct isc_device *isc);
+ void (*config_gam)(struct isc_device *isc);
+ void (*config_rlp)(struct isc_device *isc);
-#define ATMEL_ISC_NAME "atmel-isc"
+ void (*config_ctrls)(struct isc_device *isc,
+ const struct v4l2_ctrl_ops *ops);
+
+ void (*adapt_pipeline)(struct isc_device *isc);
+ };
+
+ struct isc_reg_offsets offsets;
+ const struct isc_format *controller_formats;
+ struct isc_format *formats_list;
+ u32 controller_formats_size;
+ u32 formats_list_size;
+};
-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;
diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c
index e392b3efe363..095d80c4f59e 100644
--- a/drivers/media/platform/atmel/atmel-isi.c
+++ b/drivers/media/platform/atmel/atmel-isi.c
@@ -422,7 +422,9 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
struct frame_buffer *buf, *node;
int ret;
- pm_runtime_get_sync(isi->dev);
+ ret = pm_runtime_resume_and_get(isi->dev);
+ if (ret < 0)
+ return ret;
/* Enable stream on the sub device */
ret = v4l2_subdev_call(isi->entity.subdev, video, s_stream, 1);
@@ -555,7 +557,7 @@ static const struct isi_format *find_format_by_fourcc(struct atmel_isi *isi,
}
static void isi_try_fse(struct atmel_isi *isi, const struct isi_format *isi_fmt,
- struct v4l2_subdev_pad_config *pad_cfg)
+ struct v4l2_subdev_state *sd_state)
{
int ret;
struct v4l2_subdev_frame_size_enum fse = {
@@ -564,17 +566,17 @@ static void isi_try_fse(struct atmel_isi *isi, const struct isi_format *isi_fmt,
};
ret = v4l2_subdev_call(isi->entity.subdev, pad, enum_frame_size,
- pad_cfg, &fse);
+ sd_state, &fse);
/*
* Attempt to obtain format size from subdev. If not available,
* just use the maximum ISI can receive.
*/
if (ret) {
- pad_cfg->try_crop.width = MAX_SUPPORT_WIDTH;
- pad_cfg->try_crop.height = MAX_SUPPORT_HEIGHT;
+ sd_state->pads->try_crop.width = MAX_SUPPORT_WIDTH;
+ sd_state->pads->try_crop.height = MAX_SUPPORT_HEIGHT;
} else {
- pad_cfg->try_crop.width = fse.max_width;
- pad_cfg->try_crop.height = fse.max_height;
+ sd_state->pads->try_crop.width = fse.max_width;
+ sd_state->pads->try_crop.height = fse.max_height;
}
}
@@ -584,6 +586,9 @@ static int isi_try_fmt(struct atmel_isi *isi, struct v4l2_format *f,
const struct isi_format *isi_fmt;
struct v4l2_pix_format *pixfmt = &f->fmt.pix;
struct v4l2_subdev_pad_config pad_cfg = {};
+ struct v4l2_subdev_state pad_state = {
+ .pads = &pad_cfg
+ };
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -601,10 +606,10 @@ static int isi_try_fmt(struct atmel_isi *isi, struct v4l2_format *f,
v4l2_fill_mbus_format(&format.format, pixfmt, isi_fmt->mbus_code);
- isi_try_fse(isi, isi_fmt, &pad_cfg);
+ isi_try_fse(isi, isi_fmt, &pad_state);
ret = v4l2_subdev_call(isi->entity.subdev, pad, set_fmt,
- &pad_cfg, &format);
+ &pad_state, &format);
if (ret < 0)
return ret;
@@ -782,9 +787,10 @@ static int isi_enum_frameintervals(struct file *file, void *fh,
return 0;
}
-static void isi_camera_set_bus_param(struct atmel_isi *isi)
+static int isi_camera_set_bus_param(struct atmel_isi *isi)
{
u32 cfg1 = 0;
+ int ret;
/* set bus param for ISI */
if (isi->pdata.hsync_act_low)
@@ -801,12 +807,16 @@ static void isi_camera_set_bus_param(struct atmel_isi *isi)
cfg1 |= ISI_CFG1_THMASK_BEATS_16;
/* Enable PM and peripheral clock before operate isi registers */
- pm_runtime_get_sync(isi->dev);
+ ret = pm_runtime_resume_and_get(isi->dev);
+ if (ret < 0)
+ return ret;
isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
isi_writel(isi, ISI_CFG1, cfg1);
pm_runtime_put(isi->dev);
+
+ return 0;
}
/* -----------------------------------------------------------------------*/
@@ -1085,7 +1095,11 @@ static int isi_graph_notify_complete(struct v4l2_async_notifier *notifier)
dev_err(isi->dev, "No supported mediabus format found\n");
return ret;
}
- isi_camera_set_bus_param(isi);
+ ret = isi_camera_set_bus_param(isi);
+ if (ret) {
+ dev_err(isi->dev, "Can't wake up device\n");
+ return ret;
+ }
ret = isi_set_default_fmt(isi);
if (ret) {
diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c
index 61d9885765f4..925aa80a139b 100644
--- a/drivers/media/platform/atmel/atmel-sama5d2-isc.c
+++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c
@@ -49,10 +49,262 @@
#include "atmel-isc-regs.h"
#include "atmel-isc.h"
-#define ISC_MAX_SUPPORT_WIDTH 2592
-#define ISC_MAX_SUPPORT_HEIGHT 1944
+#define ISC_SAMA5D2_MAX_SUPPORT_WIDTH 2592
+#define ISC_SAMA5D2_MAX_SUPPORT_HEIGHT 1944
-#define ISC_CLK_MAX_DIV 255
+#define ISC_SAMA5D2_PIPELINE \
+ (WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
+ CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
+
+/* This is a list of the formats that the ISC can *output* */
+static const struct isc_format sama5d2_controller_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_ARGB444,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_ARGB555,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_ABGR32,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_XBGR32,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_Y10,
+ },
+};
+
+/* This is a list of formats that the ISC can receive as *input* */
+static struct isc_format sama5d2_formats_list[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_BGBG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_GBGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_GRGR,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_GBGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_GRGR,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR12,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_BGBG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG12,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_GBGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_GRGR,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB12,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .mbus_code = MEDIA_BUS_FMT_Y8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_Y10,
+ .mbus_code = MEDIA_BUS_FMT_Y10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ },
+
+};
+
+static void isc_sama5d2_config_csc(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+
+ /* Convert RGB to YUV */
+ regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
+ 0x42 | (0x81 << 16));
+ regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
+ 0x19 | (0x10 << 16));
+ regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
+ 0xFDA | (0xFB6 << 16));
+ regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
+ 0x70 | (0x80 << 16));
+ regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
+ 0x70 | (0xFA2 << 16));
+ regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
+ 0xFEE | (0x80 << 16));
+}
+
+static void isc_sama5d2_config_cbc(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+
+ regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc,
+ isc->ctrls.brightness);
+ regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc,
+ isc->ctrls.contrast);
+}
+
+static void isc_sama5d2_config_cc(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+
+ /* Configure each register at the neutral fixed point 1.0 or 0.0 */
+ regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
+ regmap_write(regmap, ISC_CC_RB_OR, 0);
+ regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
+ regmap_write(regmap, ISC_CC_GB_OG, 0);
+ regmap_write(regmap, ISC_CC_BR_BG, 0);
+ regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
+}
+
+static void isc_sama5d2_config_ctrls(struct isc_device *isc,
+ const struct v4l2_ctrl_ops *ops)
+{
+ struct isc_ctrls *ctrls = &isc->ctrls;
+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+
+ ctrls->contrast = 256;
+
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
+}
+
+static void isc_sama5d2_config_dpc(struct isc_device *isc)
+{
+ /* This module is not present on sama5d2 pipeline */
+}
+
+static void isc_sama5d2_config_gam(struct isc_device *isc)
+{
+ /* No specific gamma configuration */
+}
+
+static void isc_sama5d2_config_rlp(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+ u32 rlp_mode = isc->config.rlp_cfg_mode;
+
+ regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
+ ISC_RLP_CFG_MODE_MASK, rlp_mode);
+}
+
+static void isc_sama5d2_adapt_pipeline(struct isc_device *isc)
+{
+ isc->try_config.bits_pipeline &= ISC_SAMA5D2_PIPELINE;
+}
+
+/* Gamma table with gamma 1/2.2 */
+static const u32 isc_sama5d2_gamma_table[][GAMMA_ENTRIES] = {
+ /* 0 --> gamma 1/1.8 */
+ { 0x65, 0x66002F, 0x950025, 0xBB0020, 0xDB001D, 0xF8001A,
+ 0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012,
+ 0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F,
+ 0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E,
+ 0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C,
+ 0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B,
+ 0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A,
+ 0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A,
+ 0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A,
+ 0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009,
+ 0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 },
+
+ /* 1 --> gamma 1/2 */
+ { 0x7F, 0x800034, 0xB50028, 0xDE0021, 0x100001E, 0x11E001B,
+ 0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013,
+ 0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F,
+ 0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D,
+ 0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B,
+ 0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A,
+ 0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A,
+ 0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009,
+ 0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009,
+ 0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009,
+ 0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 },
+
+ /* 2 --> gamma 1/2.2 */
+ { 0x99, 0x9B0038, 0xD4002A, 0xFF0023, 0x122001F, 0x141001B,
+ 0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012,
+ 0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F,
+ 0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C,
+ 0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B,
+ 0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A,
+ 0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009,
+ 0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009,
+ 0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008,
+ 0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007,
+ 0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 },
+};
static int isc_parse_dt(struct device *dev, struct isc_device *isc)
{
@@ -118,6 +370,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
struct isc_subdev_entity *subdev_entity;
int irq;
int ret;
+ u32 ver;
isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
if (!isc)
@@ -143,13 +396,47 @@ static int atmel_isc_probe(struct platform_device *pdev)
return irq;
ret = devm_request_irq(dev, irq, isc_interrupt, 0,
- ATMEL_ISC_NAME, isc);
+ "atmel-sama5d2-isc", isc);
if (ret < 0) {
dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
irq, ret);
return ret;
}
+ isc->gamma_table = isc_sama5d2_gamma_table;
+ isc->gamma_max = 2;
+
+ isc->max_width = ISC_SAMA5D2_MAX_SUPPORT_WIDTH;
+ isc->max_height = ISC_SAMA5D2_MAX_SUPPORT_HEIGHT;
+
+ isc->config_dpc = isc_sama5d2_config_dpc;
+ isc->config_csc = isc_sama5d2_config_csc;
+ isc->config_cbc = isc_sama5d2_config_cbc;
+ isc->config_cc = isc_sama5d2_config_cc;
+ isc->config_gam = isc_sama5d2_config_gam;
+ isc->config_rlp = isc_sama5d2_config_rlp;
+ isc->config_ctrls = isc_sama5d2_config_ctrls;
+
+ isc->adapt_pipeline = isc_sama5d2_adapt_pipeline;
+
+ isc->offsets.csc = ISC_SAMA5D2_CSC_OFFSET;
+ isc->offsets.cbc = ISC_SAMA5D2_CBC_OFFSET;
+ isc->offsets.sub422 = ISC_SAMA5D2_SUB422_OFFSET;
+ isc->offsets.sub420 = ISC_SAMA5D2_SUB420_OFFSET;
+ isc->offsets.rlp = ISC_SAMA5D2_RLP_OFFSET;
+ isc->offsets.his = ISC_SAMA5D2_HIS_OFFSET;
+ isc->offsets.dma = ISC_SAMA5D2_DMA_OFFSET;
+ isc->offsets.version = ISC_SAMA5D2_VERSION_OFFSET;
+ isc->offsets.his_entry = ISC_SAMA5D2_HIS_ENTRY_OFFSET;
+
+ isc->controller_formats = sama5d2_controller_formats;
+ isc->controller_formats_size = ARRAY_SIZE(sama5d2_controller_formats);
+ isc->formats_list = sama5d2_formats_list;
+ isc->formats_list_size = ARRAY_SIZE(sama5d2_formats_list);
+
+ /* sama5d2-isc - 8 bits per beat */
+ isc->dcfg = ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
+
ret = isc_pipeline_init(isc);
if (ret)
return ret;
@@ -241,6 +528,9 @@ static int atmel_isc_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
pm_request_idle(dev);
+ regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
+ dev_info(dev, "Microchip ISC version %x\n", ver);
+
return 0;
cleanup_subdev:
@@ -319,7 +609,7 @@ static struct platform_driver atmel_isc_driver = {
.probe = atmel_isc_probe,
.remove = atmel_isc_remove,
.driver = {
- .name = ATMEL_ISC_NAME,
+ .name = "atmel-sama5d2-isc",
.pm = &atmel_isc_dev_pm_ops,
.of_match_table = of_match_ptr(atmel_isc_of_match),
},
diff --git a/drivers/media/platform/atmel/atmel-sama7g5-isc.c b/drivers/media/platform/atmel/atmel-sama7g5-isc.c
new file mode 100644
index 000000000000..f2785131ff56
--- /dev/null
+++ b/drivers/media/platform/atmel/atmel-sama7g5-isc.c
@@ -0,0 +1,630 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip eXtended Image Sensor Controller (XISC) driver
+ *
+ * Copyright (C) 2019-2021 Microchip Technology, Inc. and its subsidiaries
+ *
+ * Author: Eugen Hristev <eugen.hristev@microchip.com>
+ *
+ * Sensor-->PFE-->DPC-->WB-->CFA-->CC-->GAM-->VHXS-->CSC-->CBHS-->SUB-->RLP-->DMA-->HIS
+ *
+ * ISC video pipeline integrates the following submodules:
+ * PFE: Parallel Front End to sample the camera sensor input stream
+ * DPC: Defective Pixel Correction with black offset correction, green disparity
+ * correction and defective pixel correction (3 modules total)
+ * WB: Programmable white balance in the Bayer domain
+ * CFA: Color filter array interpolation module
+ * CC: Programmable color correction
+ * GAM: Gamma correction
+ *VHXS: Vertical and Horizontal Scaler
+ * CSC: Programmable color space conversion
+ *CBHS: Contrast Brightness Hue and Saturation control
+ * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
+ * RLP: This module performs rounding, range limiting
+ * and packing of the incoming data
+ * DMA: This module performs DMA master accesses to write frames to external RAM
+ * HIS: Histogram module performs statistic counters on the frames
+ */
+
+#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_SAMA7G5_MAX_SUPPORT_WIDTH 3264
+#define ISC_SAMA7G5_MAX_SUPPORT_HEIGHT 2464
+
+#define ISC_SAMA7G5_PIPELINE \
+ (WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
+ CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
+
+/* This is a list of the formats that the ISC can *output* */
+static const struct isc_format sama7g5_controller_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_ARGB444,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_ARGB555,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_ABGR32,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_XBGR32,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_Y10,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_Y16,
+ },
+};
+
+/* This is a list of formats that the ISC can receive as *input* */
+static struct isc_format sama7g5_formats_list[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_BGBG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_GBGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_GRGR,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_GBGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_GRGR,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR12,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_BGBG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG12,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_GBGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_GRGR,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB12,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .mbus_code = MEDIA_BUS_FMT_Y8_1X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_Y10,
+ .mbus_code = MEDIA_BUS_FMT_Y10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ },
+
+};
+
+static void isc_sama7g5_config_csc(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+
+ /* Convert RGB to YUV */
+ regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
+ 0x42 | (0x81 << 16));
+ regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
+ 0x19 | (0x10 << 16));
+ regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
+ 0xFDA | (0xFB6 << 16));
+ regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
+ 0x70 | (0x80 << 16));
+ regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
+ 0x70 | (0xFA2 << 16));
+ regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
+ 0xFEE | (0x80 << 16));
+}
+
+static void isc_sama7g5_config_cbc(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+
+ /* Configure what is set via v4l2 ctrls */
+ regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, isc->ctrls.brightness);
+ regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, isc->ctrls.contrast);
+ /* Configure Hue and Saturation as neutral midpoint */
+ regmap_write(regmap, ISC_CBCHS_HUE, 0);
+ regmap_write(regmap, ISC_CBCHS_SAT, (1 << 4));
+}
+
+static void isc_sama7g5_config_cc(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+
+ /* Configure each register at the neutral fixed point 1.0 or 0.0 */
+ regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
+ regmap_write(regmap, ISC_CC_RB_OR, 0);
+ regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
+ regmap_write(regmap, ISC_CC_GB_OG, 0);
+ regmap_write(regmap, ISC_CC_BR_BG, 0);
+ regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
+}
+
+static void isc_sama7g5_config_ctrls(struct isc_device *isc,
+ const struct v4l2_ctrl_ops *ops)
+{
+ struct isc_ctrls *ctrls = &isc->ctrls;
+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+
+ ctrls->contrast = 16;
+
+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 16);
+}
+
+static void isc_sama7g5_config_dpc(struct isc_device *isc)
+{
+ u32 bay_cfg = isc->config.sd_format->cfa_baycfg;
+ struct regmap *regmap = isc->regmap;
+
+ regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BLOFF_MASK,
+ (64 << ISC_DPC_CFG_BLOFF_SHIFT));
+ regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BAYCFG_MASK,
+ (bay_cfg << ISC_DPC_CFG_BAYCFG_SHIFT));
+}
+
+static void isc_sama7g5_config_gam(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+
+ regmap_update_bits(regmap, ISC_GAM_CTRL, ISC_GAM_CTRL_BIPART,
+ ISC_GAM_CTRL_BIPART);
+}
+
+static void isc_sama7g5_config_rlp(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+ u32 rlp_mode = isc->config.rlp_cfg_mode;
+
+ regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
+ ISC_RLP_CFG_MODE_MASK | ISC_RLP_CFG_LSH |
+ ISC_RLP_CFG_YMODE_MASK, rlp_mode);
+}
+
+static void isc_sama7g5_adapt_pipeline(struct isc_device *isc)
+{
+ isc->try_config.bits_pipeline &= ISC_SAMA7G5_PIPELINE;
+}
+
+/* Gamma table with gamma 1/2.2 */
+static const u32 isc_sama7g5_gamma_table[][GAMMA_ENTRIES] = {
+ /* index 0 --> gamma bipartite */
+ {
+ 0x980, 0x4c0320, 0x650260, 0x7801e0, 0x8701a0, 0x940180,
+ 0xa00160, 0xab0120, 0xb40120, 0xbd0120, 0xc60100, 0xce0100,
+ 0xd600e0, 0xdd00e0, 0xe400e0, 0xeb00c0, 0xf100c0, 0xf700c0,
+ 0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
+ 0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
+ 0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
+ 0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
+ 0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
+ 0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
+ 0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
+ 0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
+};
+
+static int xisc_parse_dt(struct device *dev, struct isc_device *isc)
+{
+ struct device_node *np = dev->of_node;
+ struct device_node *epn = NULL;
+ struct isc_subdev_entity *subdev_entity;
+ unsigned int flags;
+ int ret;
+ bool mipi_mode;
+
+ INIT_LIST_HEAD(&isc->subdev_entities);
+
+ mipi_mode = of_property_read_bool(np, "microchip,mipi-mode");
+
+ while (1) {
+ struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
+
+ epn = of_graph_get_next_endpoint(np, epn);
+ if (!epn)
+ return 0;
+
+ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
+ &v4l2_epn);
+ if (ret) {
+ 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) {
+ ret = -ENOMEM;
+ break;
+ }
+ subdev_entity->epn = epn;
+
+ 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;
+
+ if (mipi_mode)
+ subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_MIPI;
+
+ list_add_tail(&subdev_entity->list, &isc->subdev_entities);
+ }
+ of_node_put(epn);
+
+ return ret;
+}
+
+static int microchip_xisc_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;
+ u32 ver;
+
+ 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)
+ return irq;
+
+ ret = devm_request_irq(dev, irq, isc_interrupt, 0,
+ "microchip-sama7g5-xisc", isc);
+ if (ret < 0) {
+ dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
+ irq, ret);
+ return ret;
+ }
+
+ isc->gamma_table = isc_sama7g5_gamma_table;
+ isc->gamma_max = 0;
+
+ isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
+ isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
+
+ isc->config_dpc = isc_sama7g5_config_dpc;
+ isc->config_csc = isc_sama7g5_config_csc;
+ isc->config_cbc = isc_sama7g5_config_cbc;
+ isc->config_cc = isc_sama7g5_config_cc;
+ isc->config_gam = isc_sama7g5_config_gam;
+ isc->config_rlp = isc_sama7g5_config_rlp;
+ isc->config_ctrls = isc_sama7g5_config_ctrls;
+
+ isc->adapt_pipeline = isc_sama7g5_adapt_pipeline;
+
+ isc->offsets.csc = ISC_SAMA7G5_CSC_OFFSET;
+ isc->offsets.cbc = ISC_SAMA7G5_CBC_OFFSET;
+ isc->offsets.sub422 = ISC_SAMA7G5_SUB422_OFFSET;
+ isc->offsets.sub420 = ISC_SAMA7G5_SUB420_OFFSET;
+ isc->offsets.rlp = ISC_SAMA7G5_RLP_OFFSET;
+ isc->offsets.his = ISC_SAMA7G5_HIS_OFFSET;
+ isc->offsets.dma = ISC_SAMA7G5_DMA_OFFSET;
+ isc->offsets.version = ISC_SAMA7G5_VERSION_OFFSET;
+ isc->offsets.his_entry = ISC_SAMA7G5_HIS_ENTRY_OFFSET;
+
+ isc->controller_formats = sama7g5_controller_formats;
+ isc->controller_formats_size = ARRAY_SIZE(sama7g5_controller_formats);
+ isc->formats_list = sama7g5_formats_list;
+ isc->formats_list_size = ARRAY_SIZE(sama7g5_formats_list);
+
+ /* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */
+ isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32;
+
+ 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 = xisc_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) {
+ struct v4l2_async_subdev *asd;
+
+ v4l2_async_notifier_init(&subdev_entity->notifier);
+
+ asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+ &subdev_entity->notifier,
+ of_fwnode_handle(subdev_entity->epn),
+ struct v4l2_async_subdev);
+
+ of_node_put(subdev_entity->epn);
+ subdev_entity->epn = NULL;
+
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(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);
+
+ regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
+ dev_info(dev, "Microchip XISC version %x\n", ver);
+
+ 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 microchip_xisc_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 xisc_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 xisc_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 microchip_xisc_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL)
+};
+
+static const struct of_device_id microchip_xisc_of_match[] = {
+ { .compatible = "microchip,sama7g5-isc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
+
+static struct platform_driver microchip_xisc_driver = {
+ .probe = microchip_xisc_probe,
+ .remove = microchip_xisc_remove,
+ .driver = {
+ .name = "microchip-sama7g5-xisc",
+ .pm = &microchip_xisc_dev_pm_ops,
+ .of_match_table = of_match_ptr(microchip_xisc_of_match),
+ },
+};
+
+module_platform_driver(microchip_xisc_driver);
+
+MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
+MODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c
index c68a3eac62cd..f2b4ddd31177 100644
--- a/drivers/media/platform/cadence/cdns-csi2rx.c
+++ b/drivers/media/platform/cadence/cdns-csi2rx.c
@@ -282,6 +282,7 @@ static int csi2rx_get_resources(struct csi2rx_priv *csi2rx,
struct resource *res;
unsigned char i;
u32 dev_cfg;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
csi2rx->base = devm_ioremap_resource(&pdev->dev, res);
@@ -315,7 +316,12 @@ static int csi2rx_get_resources(struct csi2rx_priv *csi2rx,
return -EINVAL;
}
- clk_prepare_enable(csi2rx->p_clk);
+ ret = clk_prepare_enable(csi2rx->p_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't prepare and enable P clock\n");
+ return ret;
+ }
+
dev_cfg = readl(csi2rx->base + CSI2RX_DEVICE_CFG_REG);
clk_disable_unprepare(csi2rx->p_clk);
diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c
index e4d08acfbb49..5a67fba73ddd 100644
--- a/drivers/media/platform/cadence/cdns-csi2tx.c
+++ b/drivers/media/platform/cadence/cdns-csi2tx.c
@@ -156,7 +156,7 @@ static const struct csi2tx_fmt *csi2tx_get_fmt_from_mbus(u32 mbus)
}
static int csi2tx_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad || code->index >= ARRAY_SIZE(csi2tx_formats))
@@ -169,20 +169,20 @@ static int csi2tx_enum_mbus_code(struct v4l2_subdev *subdev,
static struct v4l2_mbus_framefmt *
__csi2tx_get_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct csi2tx_priv *csi2tx = v4l2_subdev_to_csi2tx(subdev);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(subdev, cfg,
+ return v4l2_subdev_get_try_format(subdev, sd_state,
fmt->pad);
return &csi2tx->pad_fmts[fmt->pad];
}
static int csi2tx_get_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
const struct v4l2_mbus_framefmt *format;
@@ -191,7 +191,7 @@ static int csi2tx_get_pad_format(struct v4l2_subdev *subdev,
if (fmt->pad == CSI2TX_PAD_SOURCE)
return -EINVAL;
- format = __csi2tx_get_pad_format(subdev, cfg, fmt);
+ format = __csi2tx_get_pad_format(subdev, sd_state, fmt);
if (!format)
return -EINVAL;
@@ -201,7 +201,7 @@ static int csi2tx_get_pad_format(struct v4l2_subdev *subdev,
}
static int csi2tx_set_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
const struct v4l2_mbus_framefmt *src_format = &fmt->format;
@@ -214,7 +214,7 @@ static int csi2tx_set_pad_format(struct v4l2_subdev *subdev,
if (!csi2tx_get_fmt_from_mbus(fmt->format.code))
src_format = &fmt_default;
- dst_format = __csi2tx_get_pad_format(subdev, cfg, fmt);
+ dst_format = __csi2tx_get_pad_format(subdev, sd_state, fmt);
if (!dst_format)
return -EINVAL;
@@ -436,6 +436,7 @@ static int csi2tx_get_resources(struct csi2tx_priv *csi2tx,
struct resource *res;
unsigned int i;
u32 dev_cfg;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
csi2tx->base = devm_ioremap_resource(&pdev->dev, res);
@@ -454,7 +455,12 @@ static int csi2tx_get_resources(struct csi2tx_priv *csi2tx,
return PTR_ERR(csi2tx->esc_clk);
}
- clk_prepare_enable(csi2tx->p_clk);
+ ret = clk_prepare_enable(csi2tx->p_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't prepare and enable p_clk\n");
+ return ret;
+ }
+
dev_cfg = readl(csi2tx->base + CSI2TX_DEVICE_CONFIG_REG);
clk_disable_unprepare(csi2tx->p_clk);
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index bd666c858fa1..0e312b0842d7 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -1935,7 +1935,7 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
if (name && parent) {
buf->blob.data = buf->vaddr;
buf->blob.size = size;
- buf->dentry = debugfs_create_blob(name, 0644, parent,
+ buf->dentry = debugfs_create_blob(name, 0444, parent,
&buf->blob);
}
@@ -2660,7 +2660,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->dev);
+ ret = pm_runtime_resume_and_get(dev->dev);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret);
goto err_pm_get;
@@ -2668,7 +2668,7 @@ static int coda_open(struct file *file)
ret = clk_prepare_enable(dev->clk_per);
if (ret)
- goto err_pm_get;
+ goto err_clk_enable;
ret = clk_prepare_enable(dev->clk_ahb);
if (ret)
@@ -2707,8 +2707,9 @@ err_ctx_init:
clk_disable_unprepare(dev->clk_ahb);
err_clk_ahb:
clk_disable_unprepare(dev->clk_per);
-err_pm_get:
+err_clk_enable:
pm_runtime_put_sync(dev->dev);
+err_pm_get:
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
err_coda_name_init:
@@ -3232,7 +3233,7 @@ static int coda_probe(struct platform_device *pdev)
memset(dev->iram.vaddr, 0, dev->iram.size);
dev->iram.blob.data = dev->iram.vaddr;
dev->iram.blob.size = dev->iram.size;
- dev->iram.dentry = debugfs_create_blob("iram", 0644,
+ dev->iram.dentry = debugfs_create_blob("iram", 0444,
dev->debugfs_root,
&dev->iram.blob);
}
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
index d19bad997f30..bf3c3e76b921 100644
--- a/drivers/media/platform/davinci/vpbe_display.c
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -47,7 +47,7 @@ static int venc_is_second_field(struct vpbe_display *disp_dev)
ret = v4l2_subdev_call(vpbe_dev->venc,
core,
- ioctl,
+ command,
VENC_GET_FLD,
&val);
if (ret < 0) {
diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c
index 8caa084e5704..bde241c26d79 100644
--- a/drivers/media/platform/davinci/vpbe_venc.c
+++ b/drivers/media/platform/davinci/vpbe_venc.c
@@ -521,9 +521,7 @@ static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
return ret;
}
-static long venc_ioctl(struct v4l2_subdev *sd,
- unsigned int cmd,
- void *arg)
+static long venc_command(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
u32 val;
@@ -542,7 +540,7 @@ static long venc_ioctl(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_core_ops venc_core_ops = {
- .ioctl = venc_ioctl,
+ .command = venc_command,
};
static const struct v4l2_subdev_video_ops venc_video_ops = {
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index 8d2e165bf7de..c034e25dd9aa 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -99,7 +99,7 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb)
* vpif_buffer_queue_setup : Callback function for buffer setup.
* @vq: vb2_queue ptr
* @nbuffers: ptr to number of buffers requested by application
- * @nplanes:: contains number of distinct video planes needed to hold a frame
+ * @nplanes: contains number of distinct video planes needed to hold a frame
* @sizes: contains the size (in bytes) of each plane.
* @alloc_devs: ptr to allocation context
*
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index e5f61d9b221d..59f6b782e104 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -101,7 +101,7 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb)
* vpif_buffer_queue_setup : Callback function for buffer setup.
* @vq: vb2_queue ptr
* @nbuffers: ptr to number of buffers requested by application
- * @nplanes:: contains number of distinct video planes needed to hold a frame
+ * @nplanes: contains number of distinct video planes needed to hold a frame
* @sizes: contains the size (in bytes) of each plane.
* @alloc_devs: ptr to allocation context
*
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 9f41c2e7097a..f49f3322f835 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1210,18 +1210,19 @@ static int gsc_remove(struct platform_device *pdev)
struct gsc_dev *gsc = platform_get_drvdata(pdev);
int i;
- pm_runtime_get_sync(&pdev->dev);
-
gsc_unregister_m2m_device(gsc);
v4l2_device_unregister(&gsc->v4l2_dev);
vb2_dma_contig_clear_max_seg_size(&pdev->dev);
- for (i = 0; i < gsc->num_clocks; i++)
- clk_disable_unprepare(gsc->clock[i]);
- pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ for (i = 0; i < gsc->num_clocks; i++)
+ clk_disable_unprepare(gsc->clock[i]);
+
+ pm_runtime_set_suspended(&pdev->dev);
+
dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
return 0;
}
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
index 27a3c92c73bc..f1cf847d1cc2 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -56,10 +56,8 @@ static void __gsc_m2m_job_abort(struct gsc_ctx *ctx)
static int gsc_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct gsc_ctx *ctx = q->drv_priv;
- int ret;
- ret = pm_runtime_get_sync(&ctx->gsc_dev->pdev->dev);
- return ret > 0 ? 0 : ret;
+ return pm_runtime_resume_and_get(&ctx->gsc_dev->pdev->dev);
}
static void __gsc_m2m_cleanup_queue(struct gsc_ctx *ctx)
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index 13c838d3f947..7ff4024003f4 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -478,11 +478,9 @@ static int fimc_capture_open(struct file *file)
goto unlock;
set_bit(ST_CAPT_BUSY, &fimc->state);
- ret = pm_runtime_get_sync(&fimc->pdev->dev);
- if (ret < 0) {
- pm_runtime_put_sync(&fimc->pdev->dev);
+ ret = pm_runtime_resume_and_get(&fimc->pdev->dev);
+ if (ret < 0)
goto unlock;
- }
ret = v4l2_fh_open(file);
if (ret) {
@@ -1456,7 +1454,7 @@ void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
}
static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct fimc_fmt *fmt;
@@ -1469,7 +1467,7 @@ static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd,
}
static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
@@ -1478,7 +1476,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
fmt->format = *mf;
return 0;
}
@@ -1510,7 +1508,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
}
static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
@@ -1533,7 +1531,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
mf->colorspace = V4L2_COLORSPACE_JPEG;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*mf = fmt->format;
return 0;
}
@@ -1576,7 +1574,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
}
static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
@@ -1603,10 +1601,10 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
return 0;
case V4L2_SEL_TGT_CROP:
- try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+ try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
break;
case V4L2_SEL_TGT_COMPOSE:
- try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
+ try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad);
f = &ctx->d_frame;
break;
default:
@@ -1632,7 +1630,7 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
}
static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
@@ -1650,10 +1648,10 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+ try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
break;
case V4L2_SEL_TGT_COMPOSE:
- try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
+ try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad);
f = &ctx->d_frame;
break;
default:
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
index 972d9601d236..e55e411038f4 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -436,7 +436,7 @@ done:
static int fimc_is_request_firmware(struct fimc_is *is, const char *fw_name)
{
return request_firmware_nowait(THIS_MODULE,
- FW_ACTION_HOTPLUG, fw_name, &is->pdev->dev,
+ FW_ACTION_UEVENT, fw_name, &is->pdev->dev,
GFP_KERNEL, is, fimc_is_load_firmware);
}
@@ -828,9 +828,9 @@ static int fimc_is_probe(struct platform_device *pdev)
goto err_irq;
}
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
- goto err_pm;
+ goto err_irq;
vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c
index 612b9872afc8..83688a7982f7 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp-video.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c
@@ -275,7 +275,7 @@ static int isp_video_open(struct file *file)
if (ret < 0)
goto unlock;
- ret = pm_runtime_get_sync(&isp->pdev->dev);
+ ret = pm_runtime_resume_and_get(&isp->pdev->dev);
if (ret < 0)
goto rel_fh;
@@ -293,7 +293,6 @@ static int isp_video_open(struct file *file)
if (!ret)
goto unlock;
rel_fh:
- pm_runtime_put_noidle(&isp->pdev->dev);
v4l2_fh_release(file);
unlock:
mutex_unlock(&isp->video_lock);
@@ -306,17 +305,20 @@ static int isp_video_release(struct file *file)
struct fimc_is_video *ivc = &isp->video_capture;
struct media_entity *entity = &ivc->ve.vdev.entity;
struct media_device *mdev = entity->graph_obj.mdev;
+ bool is_singular_file;
mutex_lock(&isp->video_lock);
- if (v4l2_fh_is_singular_file(file) && ivc->streaming) {
+ is_singular_file = v4l2_fh_is_singular_file(file);
+
+ if (is_singular_file && ivc->streaming) {
media_pipeline_stop(entity);
ivc->streaming = 0;
}
_vb2_fop_release(file, NULL);
- if (v4l2_fh_is_singular_file(file)) {
+ if (is_singular_file) {
fimc_pipeline_call(&ivc->ve, close);
mutex_lock(&mdev->graph_mutex);
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
index a77c49b18511..855235bea46d 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -106,7 +106,7 @@ static const struct media_entity_operations fimc_is_subdev_media_ops = {
};
static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
const struct fimc_fmt *fmt;
@@ -119,14 +119,14 @@ static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd,
}
static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct fimc_isp *isp = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf = &fmt->format;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *mf = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ *mf = *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
return 0;
}
@@ -156,7 +156,7 @@ static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd,
}
static void __isp_subdev_try_format(struct fimc_isp *isp,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *mf = &fmt->format;
@@ -172,8 +172,9 @@ static void __isp_subdev_try_format(struct fimc_isp *isp,
mf->code = MEDIA_BUS_FMT_SGRBG10_1X10;
} else {
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- format = v4l2_subdev_get_try_format(&isp->subdev, cfg,
- FIMC_ISP_SD_PAD_SINK);
+ format = v4l2_subdev_get_try_format(&isp->subdev,
+ sd_state,
+ FIMC_ISP_SD_PAD_SINK);
else
format = &isp->sink_fmt;
@@ -191,7 +192,7 @@ static void __isp_subdev_try_format(struct fimc_isp *isp,
}
static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct fimc_isp *isp = v4l2_get_subdevdata(sd);
@@ -203,10 +204,10 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
__func__, fmt->pad, mf->code, mf->width, mf->height);
mutex_lock(&isp->subdev_lock);
- __isp_subdev_try_format(isp, cfg, fmt);
+ __isp_subdev_try_format(isp, sd_state, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*mf = fmt->format;
/* Propagate format to the source pads */
@@ -217,8 +218,10 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
for (pad = FIMC_ISP_SD_PAD_SRC_FIFO;
pad < FIMC_ISP_SD_PADS_NUM; pad++) {
format.pad = pad;
- __isp_subdev_try_format(isp, cfg, &format);
- mf = v4l2_subdev_get_try_format(sd, cfg, pad);
+ __isp_subdev_try_format(isp, sd_state,
+ &format);
+ mf = v4l2_subdev_get_try_format(sd, sd_state,
+ pad);
*mf = format.format;
}
}
@@ -230,7 +233,8 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
isp->sink_fmt = *mf;
format.pad = FIMC_ISP_SD_PAD_SRC_DMA;
- __isp_subdev_try_format(isp, cfg, &format);
+ __isp_subdev_try_format(isp, sd_state,
+ &format);
isp->src_fmt = format.format;
__is_set_frame_size(is, &isp->src_fmt);
@@ -304,11 +308,10 @@ static int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on)
pr_debug("on: %d\n", on);
if (on) {
- ret = pm_runtime_get_sync(&is->pdev->dev);
- if (ret < 0) {
- pm_runtime_put(&is->pdev->dev);
+ ret = pm_runtime_resume_and_get(&is->pdev->dev);
+ if (ret < 0)
return ret;
- }
+
set_bit(IS_ST_PWR_ON, &is->state);
ret = fimc_is_start_firmware(is);
@@ -371,15 +374,18 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd,
.field = V4L2_FIELD_NONE,
};
- format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SINK);
+ format = v4l2_subdev_get_try_format(sd, fh->state,
+ FIMC_ISP_SD_PAD_SINK);
*format = fmt;
- format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SRC_FIFO);
+ format = v4l2_subdev_get_try_format(sd, fh->state,
+ FIMC_ISP_SD_PAD_SRC_FIFO);
fmt.width = DEFAULT_PREVIEW_STILL_WIDTH;
fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT;
*format = fmt;
- format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SRC_DMA);
+ format = v4l2_subdev_get_try_format(sd, fh->state,
+ FIMC_ISP_SD_PAD_SRC_DMA);
*format = fmt;
return 0;
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index fe20af3a7178..aaa3af0493ce 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -469,9 +469,9 @@ static int fimc_lite_open(struct file *file)
}
set_bit(ST_FLITE_IN_USE, &fimc->state);
- ret = pm_runtime_get_sync(&fimc->pdev->dev);
+ ret = pm_runtime_resume_and_get(&fimc->pdev->dev);
if (ret < 0)
- goto err_pm;
+ goto err_in_use;
ret = v4l2_fh_open(file);
if (ret < 0)
@@ -499,6 +499,7 @@ static int fimc_lite_open(struct file *file)
v4l2_fh_release(file);
err_pm:
pm_runtime_put_sync(&fimc->pdev->dev);
+err_in_use:
clear_bit(ST_FLITE_IN_USE, &fimc->state);
unlock:
mutex_unlock(&fimc->lock);
@@ -549,7 +550,7 @@ static const struct v4l2_file_operations fimc_lite_fops = {
*/
static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct flite_drvdata *dd = fimc->dd;
@@ -573,14 +574,16 @@ static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc,
struct v4l2_rect *rect;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sink_fmt = v4l2_subdev_get_try_format(&fimc->subdev, cfg,
- FLITE_SD_PAD_SINK);
+ sink_fmt = v4l2_subdev_get_try_format(&fimc->subdev,
+ sd_state,
+ FLITE_SD_PAD_SINK);
mf->code = sink_fmt->code;
mf->colorspace = sink_fmt->colorspace;
- rect = v4l2_subdev_get_try_crop(&fimc->subdev, cfg,
- FLITE_SD_PAD_SINK);
+ rect = v4l2_subdev_get_try_crop(&fimc->subdev,
+ sd_state,
+ FLITE_SD_PAD_SINK);
} else {
mf->code = sink->fmt->mbus_code;
mf->colorspace = sink->fmt->colorspace;
@@ -1001,7 +1004,7 @@ static const struct media_entity_operations fimc_lite_subdev_media_ops = {
};
static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
const struct fimc_fmt *fmt;
@@ -1015,16 +1018,16 @@ static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
static struct v4l2_mbus_framefmt *__fimc_lite_subdev_get_try_fmt(
struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg, unsigned int pad)
+ struct v4l2_subdev_state *sd_state, unsigned int pad)
{
if (pad != FLITE_SD_PAD_SINK)
pad = FLITE_SD_PAD_SOURCE_DMA;
- return v4l2_subdev_get_try_format(sd, cfg, pad);
+ return v4l2_subdev_get_try_format(sd, sd_state, pad);
}
static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
@@ -1032,7 +1035,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
struct flite_frame *f = &fimc->inp_frame;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = __fimc_lite_subdev_get_try_fmt(sd, cfg, fmt->pad);
+ mf = __fimc_lite_subdev_get_try_fmt(sd, sd_state, fmt->pad);
fmt->format = *mf;
return 0;
}
@@ -1055,7 +1058,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
}
static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
@@ -1077,17 +1080,18 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
return -EBUSY;
}
- ffmt = fimc_lite_subdev_try_fmt(fimc, cfg, fmt);
+ ffmt = fimc_lite_subdev_try_fmt(fimc, sd_state, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *src_fmt;
- mf = __fimc_lite_subdev_get_try_fmt(sd, cfg, fmt->pad);
+ mf = __fimc_lite_subdev_get_try_fmt(sd, sd_state, fmt->pad);
*mf = fmt->format;
if (fmt->pad == FLITE_SD_PAD_SINK) {
unsigned int pad = FLITE_SD_PAD_SOURCE_DMA;
- src_fmt = __fimc_lite_subdev_get_try_fmt(sd, cfg, pad);
+ src_fmt = __fimc_lite_subdev_get_try_fmt(sd, sd_state,
+ pad);
*src_fmt = *mf;
}
@@ -1115,7 +1119,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
}
static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
@@ -1127,7 +1131,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+ sel->r = *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
return 0;
}
@@ -1150,7 +1154,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
}
static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
@@ -1164,7 +1168,7 @@ static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd,
fimc_lite_try_crop(fimc, &sel->r);
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_crop(sd, cfg, sel->pad) = sel->r;
+ *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad) = sel->r;
} else {
unsigned long flags;
spin_lock_irqsave(&fimc->slock, flags);
diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c
index c9704a147e5c..df8e2aa454d8 100644
--- a/drivers/media/platform/exynos4-is/fimc-m2m.c
+++ b/drivers/media/platform/exynos4-is/fimc-m2m.c
@@ -73,17 +73,14 @@ static void fimc_m2m_shutdown(struct fimc_ctx *ctx)
static int start_streaming(struct vb2_queue *q, unsigned int count)
{
struct fimc_ctx *ctx = q->drv_priv;
- int ret;
- ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev);
- return ret > 0 ? 0 : ret;
+ return pm_runtime_resume_and_get(&ctx->fimc_dev->pdev->dev);
}
static void stop_streaming(struct vb2_queue *q)
{
struct fimc_ctx *ctx = q->drv_priv;
-
fimc_m2m_shutdown(ctx);
fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
pm_runtime_put(&ctx->fimc_dev->pdev->dev);
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index 13d192ba4aa6..3b8a24bb724c 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -512,11 +512,9 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
if (!fmd->pmf)
return -ENXIO;
- ret = pm_runtime_get_sync(fmd->pmf);
- if (ret < 0) {
- pm_runtime_put(fmd->pmf);
+ ret = pm_runtime_resume_and_get(fmd->pmf);
+ if (ret < 0)
return ret;
- }
fmd->num_sensors = 0;
@@ -1286,13 +1284,11 @@ static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO,
static int cam_clk_prepare(struct clk_hw *hw)
{
struct cam_clk *camclk = to_cam_clk(hw);
- int ret;
if (camclk->fmd->pmf == NULL)
return -ENODEV;
- ret = pm_runtime_get_sync(camclk->fmd->pmf);
- return ret < 0 ? ret : 0;
+ return pm_runtime_resume_and_get(camclk->fmd->pmf);
}
static void cam_clk_unprepare(struct clk_hw *hw)
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index 1aac167abb17..32b23329b033 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -494,7 +494,7 @@ static int s5pcsis_s_power(struct v4l2_subdev *sd, int on)
struct device *dev = &state->pdev->dev;
if (on)
- return pm_runtime_get_sync(dev);
+ return pm_runtime_resume_and_get(dev);
return pm_runtime_put_sync(dev);
}
@@ -509,11 +509,9 @@ static int s5pcsis_s_stream(struct v4l2_subdev *sd, int enable)
if (enable) {
s5pcsis_clear_counters(state);
- ret = pm_runtime_get_sync(&state->pdev->dev);
- if (ret && ret != 1) {
- pm_runtime_put_noidle(&state->pdev->dev);
+ ret = pm_runtime_resume_and_get(&state->pdev->dev);
+ if (ret < 0)
return ret;
- }
}
mutex_lock(&state->lock);
@@ -535,11 +533,11 @@ unlock:
if (!enable)
pm_runtime_put(&state->pdev->dev);
- return ret == 1 ? 0 : ret;
+ return ret;
}
static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(s5pcsis_formats))
@@ -567,23 +565,25 @@ static struct csis_pix_format const *s5pcsis_try_format(
}
static struct v4l2_mbus_framefmt *__s5pcsis_get_format(
- struct csis_state *state, struct v4l2_subdev_pad_config *cfg,
+ struct csis_state *state, struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return cfg ? v4l2_subdev_get_try_format(&state->sd, cfg, 0) : NULL;
+ return sd_state ? v4l2_subdev_get_try_format(&state->sd,
+ sd_state, 0) : NULL;
return &state->format;
}
-static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int s5pcsis_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct csis_state *state = sd_to_csis_state(sd);
struct csis_pix_format const *csis_fmt;
struct v4l2_mbus_framefmt *mf;
- mf = __s5pcsis_get_format(state, cfg, fmt->which);
+ mf = __s5pcsis_get_format(state, sd_state, fmt->which);
if (fmt->pad == CSIS_PAD_SOURCE) {
if (mf) {
@@ -604,13 +604,14 @@ static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
return 0;
}
-static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int s5pcsis_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct csis_state *state = sd_to_csis_state(sd);
struct v4l2_mbus_framefmt *mf;
- mf = __s5pcsis_get_format(state, cfg, fmt->which);
+ mf = __s5pcsis_get_format(state, sd_state, fmt->which);
if (!mf)
return -EINVAL;
diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/imx-jpeg/mxc-jpeg.c
index 03b9264af068..755138063ee6 100644
--- a/drivers/media/platform/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.c
@@ -62,7 +62,7 @@
#include "mxc-jpeg-hw.h"
#include "mxc-jpeg.h"
-static struct mxc_jpeg_fmt mxc_formats[] = {
+static const struct mxc_jpeg_fmt mxc_formats[] = {
{
.name = "JPEG",
.fourcc = V4L2_PIX_FMT_JPEG,
@@ -341,7 +341,7 @@ static inline struct mxc_jpeg_ctx *mxc_jpeg_fh_to_ctx(struct v4l2_fh *fh)
return container_of(fh, struct mxc_jpeg_ctx, fh);
}
-static int enum_fmt(struct mxc_jpeg_fmt *mxc_formats, int n,
+static int enum_fmt(const struct mxc_jpeg_fmt *mxc_formats, int n,
struct v4l2_fmtdesc *f, u32 type)
{
int i, num = 0;
@@ -368,13 +368,13 @@ static int enum_fmt(struct mxc_jpeg_fmt *mxc_formats, int n,
return 0;
}
-static struct mxc_jpeg_fmt *mxc_jpeg_find_format(struct mxc_jpeg_ctx *ctx,
- u32 pixelformat)
+static const struct mxc_jpeg_fmt *mxc_jpeg_find_format(struct mxc_jpeg_ctx *ctx,
+ u32 pixelformat)
{
unsigned int k;
for (k = 0; k < MXC_JPEG_NUM_FORMATS; k++) {
- struct mxc_jpeg_fmt *fmt = &mxc_formats[k];
+ const struct mxc_jpeg_fmt *fmt = &mxc_formats[k];
if (fmt->fourcc == pixelformat)
return fmt;
@@ -1536,7 +1536,7 @@ static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
MXC_JPEG_FMT_TYPE_RAW);
}
-static int mxc_jpeg_try_fmt(struct v4l2_format *f, struct mxc_jpeg_fmt *fmt,
+static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fmt,
struct mxc_jpeg_ctx *ctx, int q_type)
{
struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
@@ -1612,7 +1612,7 @@ static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
struct device *dev = jpeg->dev;
- struct mxc_jpeg_fmt *fmt;
+ const struct mxc_jpeg_fmt *fmt;
u32 fourcc = f->fmt.pix_mp.pixelformat;
int q_type = (jpeg->mode == MXC_JPEG_DECODE) ?
@@ -1643,7 +1643,7 @@ static int mxc_jpeg_try_fmt_vid_out(struct file *file, void *priv,
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
struct device *dev = jpeg->dev;
- struct mxc_jpeg_fmt *fmt;
+ const struct mxc_jpeg_fmt *fmt;
u32 fourcc = f->fmt.pix_mp.pixelformat;
int q_type = (jpeg->mode == MXC_JPEG_ENCODE) ?
@@ -1890,7 +1890,7 @@ static const struct v4l2_file_operations mxc_jpeg_fops = {
.mmap = v4l2_m2m_fop_mmap,
};
-static struct v4l2_m2m_ops mxc_jpeg_m2m_ops = {
+static const struct v4l2_m2m_ops mxc_jpeg_m2m_ops = {
.device_run = mxc_jpeg_device_run,
};
diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/imx-jpeg/mxc-jpeg.h
index 7697de490d2e..4c210852e876 100644
--- a/drivers/media/platform/imx-jpeg/mxc-jpeg.h
+++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.h
@@ -51,7 +51,7 @@ enum mxc_jpeg_mode {
* @flags: flags describing format applicability
*/
struct mxc_jpeg_fmt {
- char *name;
+ const char *name;
u32 fourcc;
enum v4l2_jpeg_chroma_subsampling subsampling;
int nc;
@@ -74,14 +74,14 @@ struct mxc_jpeg_desc {
} __packed;
struct mxc_jpeg_q_data {
- struct mxc_jpeg_fmt *fmt;
- u32 sizeimage[MXC_JPEG_MAX_PLANES];
- u32 bytesperline[MXC_JPEG_MAX_PLANES];
- int w;
- int w_adjusted;
- int h;
- int h_adjusted;
- unsigned int sequence;
+ const struct mxc_jpeg_fmt *fmt;
+ u32 sizeimage[MXC_JPEG_MAX_PLANES];
+ u32 bytesperline[MXC_JPEG_MAX_PLANES];
+ int w;
+ int w_adjusted;
+ int h;
+ int h_adjusted;
+ unsigned int sequence;
};
struct mxc_jpeg_ctx {
diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c
index baac86f3d153..9aa374fa8b36 100644
--- a/drivers/media/platform/marvell-ccic/cafe-driver.c
+++ b/drivers/media/platform/marvell-ccic/cafe-driver.c
@@ -486,6 +486,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
struct cafe_camera *cam;
struct mcam_camera *mcam;
struct v4l2_async_subdev *asd;
+ struct i2c_client *i2c_dev;
/*
* Start putting together one of our big camera structures.
@@ -561,11 +562,16 @@ static int cafe_pci_probe(struct pci_dev *pdev,
clkdev_create(mcam->mclk, "xclk", "%d-%04x",
i2c_adapter_id(cam->i2c_adapter), ov7670_info.addr);
- if (!IS_ERR(i2c_new_client_device(cam->i2c_adapter, &ov7670_info))) {
- cam->registered = 1;
- return 0;
+ i2c_dev = i2c_new_client_device(cam->i2c_adapter, &ov7670_info);
+ if (IS_ERR(i2c_dev)) {
+ ret = PTR_ERR(i2c_dev);
+ goto out_mccic_shutdown;
}
+ cam->registered = 1;
+ return 0;
+
+out_mccic_shutdown:
mccic_shutdown(mcam);
out_smbus_shutdown:
cafe_smbus_shutdown(cam);
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index 141bf5d97a04..070a0f3fc337 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -918,6 +918,7 @@ 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;
+ int ret;
/*
* Clock the sensor appropriately. Controller clock should
@@ -931,7 +932,9 @@ static int mclk_enable(struct clk_hw *hw)
mclk_div = 2;
}
- pm_runtime_get_sync(cam->dev);
+ ret = pm_runtime_resume_and_get(cam->dev);
+ if (ret < 0)
+ return ret;
clk_enable(cam->clk[0]);
mcam_reg_write(cam, REG_CLKCTRL, (mclk_src << 29) | mclk_div);
mcam_ctlr_power_up(cam);
@@ -1347,6 +1350,9 @@ static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
struct mcam_format_struct *f;
struct v4l2_pix_format *pix = &fmt->fmt.pix;
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = {
+ .pads = &pad_cfg
+ };
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -1355,7 +1361,7 @@ static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
f = mcam_find_format(pix->pixelformat);
pix->pixelformat = f->pixelformat;
v4l2_fill_mbus_format(&format.format, pix, f->mbus_code);
- ret = sensor_call(cam, pad, set_fmt, &pad_cfg, &format);
+ ret = sensor_call(cam, pad, set_fmt, &pad_state, &format);
v4l2_fill_pix_format(pix, &format.format);
pix->bytesperline = pix->width * f->bpp;
switch (f->pixelformat) {
@@ -1611,7 +1617,9 @@ static int mcam_v4l_open(struct file *filp)
ret = sensor_call(cam, core, s_power, 1);
if (ret)
goto out;
- pm_runtime_get_sync(cam->dev);
+ ret = pm_runtime_resume_and_get(cam->dev);
+ if (ret < 0)
+ goto out;
__mcam_cam_reset(cam);
mcam_set_config_needed(cam, 1);
}
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
index 88a23bce569d..a89c7b206eef 100644
--- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
@@ -920,7 +920,7 @@ static void mtk_jpeg_enc_device_run(void *priv)
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
- ret = pm_runtime_get_sync(jpeg->dev);
+ ret = pm_runtime_resume_and_get(jpeg->dev);
if (ret < 0)
goto enc_end;
@@ -973,7 +973,7 @@ static void mtk_jpeg_dec_device_run(void *priv)
return;
}
- ret = pm_runtime_get_sync(jpeg->dev);
+ ret = pm_runtime_resume_and_get(jpeg->dev);
if (ret < 0)
goto dec_end;
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
index ace4528cdc5e..f14779e7596e 100644
--- a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
@@ -391,12 +391,12 @@ static int mtk_mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
struct mtk_mdp_ctx *ctx = q->drv_priv;
int ret;
- ret = pm_runtime_get_sync(&ctx->mdp_dev->pdev->dev);
+ ret = pm_runtime_resume_and_get(&ctx->mdp_dev->pdev->dev);
if (ret < 0)
- mtk_mdp_dbg(1, "[%d] pm_runtime_get_sync failed:%d",
+ mtk_mdp_dbg(1, "[%d] pm_runtime_resume_and_get failed:%d",
ctx->id, ret);
- return 0;
+ return ret;
}
static void *mtk_mdp_m2m_buf_remove(struct mtk_mdp_ctx *ctx,
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 147dfef1638d..f87dc47d9e63 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -126,7 +126,9 @@ static int fops_vcodec_open(struct file *file)
mtk_vcodec_dec_set_default_params(ctx);
if (v4l2_fh_is_singular(&ctx->fh)) {
- mtk_vcodec_dec_pw_on(&dev->pm);
+ ret = mtk_vcodec_dec_pw_on(&dev->pm);
+ if (ret < 0)
+ goto err_load_fw;
/*
* Does nothing if firmware was already loaded.
*/
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 ddee7046ce42..6038db96f71c 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
@@ -88,13 +88,15 @@ void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev)
put_device(dev->pm.larbvdec);
}
-void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm)
+int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm)
{
int ret;
- ret = pm_runtime_get_sync(pm->dev);
+ ret = pm_runtime_resume_and_get(pm->dev);
if (ret)
- mtk_v4l2_err("pm_runtime_get_sync fail %d", ret);
+ mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret);
+
+ return ret;
}
void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm)
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 872d8bf8cfaf..280aeaefdb65 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
@@ -12,7 +12,7 @@
int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *dev);
void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev);
-void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm);
+int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm);
void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm);
void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm);
void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
index d03cca95e99b..c6c7672fecfb 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -25,7 +25,7 @@
#define MTK_V4L2_BENCHMARK 0
#define WAIT_INTR_TIMEOUT_MS 1000
-/**
+/*
* enum mtk_hw_reg_idx - MTK hw register base index
*/
enum mtk_hw_reg_idx {
@@ -49,7 +49,7 @@ enum mtk_hw_reg_idx {
NUM_MAX_VCODEC_REG_BASE
};
-/**
+/*
* enum mtk_instance_type - The type of an MTK Vcodec instance.
*/
enum mtk_instance_type {
@@ -74,7 +74,7 @@ enum mtk_instance_state {
MTK_STATE_ABORT = 4,
};
-/**
+/*
* enum mtk_encode_param - General encoding parameters type
*/
enum mtk_encode_param {
@@ -92,7 +92,7 @@ enum mtk_fmt_type {
MTK_FMT_FRAME = 2,
};
-/**
+/*
* struct mtk_video_fmt - Structure used to store information about pixelformats
*/
struct mtk_video_fmt {
@@ -102,7 +102,7 @@ struct mtk_video_fmt {
u32 flags;
};
-/**
+/*
* struct mtk_codec_framesizes - Structure used to store information about
* framesizes
*/
@@ -111,7 +111,7 @@ struct mtk_codec_framesizes {
struct v4l2_frmsize_stepwise stepwise;
};
-/**
+/*
* enum mtk_q_type - Type of queue
*/
enum mtk_q_type {
@@ -119,7 +119,7 @@ enum mtk_q_type {
MTK_Q_DATA_DST = 1,
};
-/**
+/*
* struct mtk_q_data - Structure used to store information about queue
*/
struct mtk_q_data {
@@ -168,7 +168,7 @@ struct mtk_enc_params {
unsigned int force_intra;
};
-/**
+/*
* struct mtk_vcodec_clk_info - Structure used to store clock name
*/
struct mtk_vcodec_clk_info {
@@ -176,7 +176,7 @@ struct mtk_vcodec_clk_info {
struct clk *vcodec_clk;
};
-/**
+/*
* struct mtk_vcodec_clk - Structure used to store vcodec clock information
*/
struct mtk_vcodec_clk {
@@ -184,7 +184,7 @@ struct mtk_vcodec_clk {
int clk_num;
};
-/**
+/*
* struct mtk_vcodec_pm - Power management data structure
*/
struct mtk_vcodec_pm {
@@ -255,6 +255,7 @@ struct vdec_pic_info {
* @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
* @quantization: enum v4l2_quantization, colorspace quantization
* @xfer_func: enum v4l2_xfer_func, colorspace transfer function
+ * @decoded_frame_cnt: number of decoded frames
* @lock: protect variables accessed by V4L2 threads and worker thread such as
* mtk_video_dec_buf.
*/
@@ -302,6 +303,7 @@ struct mtk_vcodec_ctx {
enum mtk_chip {
MTK_MT8173,
MTK_MT8183,
+ MTK_MT8192,
};
/**
@@ -310,7 +312,7 @@ enum mtk_chip {
* @chip: chip this encoder is compatible with
*
* @uses_ext: whether the encoder uses the extended firmware messaging format
- * @min_birate: minimum supported encoding bitrate
+ * @min_bitrate: minimum supported encoding bitrate
* @max_bitrate: maximum supported encoding bitrate
* @capture_formats: array of supported capture formats
* @num_capture_formats: number of entries in capture_formats
@@ -347,10 +349,12 @@ struct mtk_vcodec_enc_pdata {
* @curr_ctx: The context that is waiting for codec hardware
*
* @reg_base: Mapped address of MTK Vcodec registers.
+ * @venc_pdata: encoder IC-specific data
*
* @fw_handler: used to communicate with the firmware.
* @id_counter: used to identify current opened instance
*
+ * @decode_workqueue: decode work queue
* @encode_workqueue: encode work queue
*
* @int_cond: used to identify interrupt condition happen
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
index 4831052f475d..416f356af363 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
@@ -19,23 +19,30 @@
#define MTK_VENC_MIN_W 160U
#define MTK_VENC_MIN_H 128U
-#define MTK_VENC_MAX_W 1920U
-#define MTK_VENC_MAX_H 1088U
+#define MTK_VENC_HD_MAX_W 1920U
+#define MTK_VENC_HD_MAX_H 1088U
+#define MTK_VENC_4K_MAX_W 3840U
+#define MTK_VENC_4K_MAX_H 2176U
+
#define DFT_CFG_WIDTH MTK_VENC_MIN_W
#define DFT_CFG_HEIGHT MTK_VENC_MIN_H
#define MTK_MAX_CTRLS_HINT 20
#define MTK_DEFAULT_FRAMERATE_NUM 1001
#define MTK_DEFAULT_FRAMERATE_DENOM 30000
+#define MTK_VENC_4K_CAPABILITY_ENABLE BIT(0)
static void mtk_venc_worker(struct work_struct *work);
-static const struct v4l2_frmsize_stepwise mtk_venc_framesizes = {
- MTK_VENC_MIN_W, MTK_VENC_MAX_W, 16,
- MTK_VENC_MIN_H, MTK_VENC_MAX_H, 16,
+static const struct v4l2_frmsize_stepwise mtk_venc_hd_framesizes = {
+ MTK_VENC_MIN_W, MTK_VENC_HD_MAX_W, 16,
+ MTK_VENC_MIN_H, MTK_VENC_HD_MAX_H, 16,
};
-#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_venc_framesizes)
+static const struct v4l2_frmsize_stepwise mtk_venc_4k_framesizes = {
+ MTK_VENC_MIN_W, MTK_VENC_4K_MAX_W, 16,
+ MTK_VENC_MIN_H, MTK_VENC_4K_MAX_H, 16,
+};
static int vidioc_venc_s_ctrl(struct v4l2_ctrl *ctrl)
{
@@ -151,17 +158,22 @@ static int vidioc_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
const struct mtk_video_fmt *fmt;
+ struct mtk_vcodec_ctx *ctx = fh_to_ctx(fh);
if (fsize->index != 0)
return -EINVAL;
fmt = mtk_venc_find_format(fsize->pixel_format,
- fh_to_ctx(fh)->dev->venc_pdata);
+ ctx->dev->venc_pdata);
if (!fmt)
return -EINVAL;
fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
- fsize->stepwise = mtk_venc_framesizes;
+
+ if (ctx->dev->enc_capability & MTK_VENC_4K_CAPABILITY_ENABLE)
+ fsize->stepwise = mtk_venc_4k_framesizes;
+ else
+ fsize->stepwise = mtk_venc_hd_framesizes;
return 0;
}
@@ -248,7 +260,7 @@ static struct mtk_q_data *mtk_venc_get_q_data(struct mtk_vcodec_ctx *ctx,
/* 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,
+static int vidioc_try_fmt(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f,
const struct mtk_video_fmt *fmt)
{
struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
@@ -260,13 +272,22 @@ static int vidioc_try_fmt(struct v4l2_format *f,
pix_fmt_mp->plane_fmt[0].bytesperline = 0;
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
int tmp_w, tmp_h;
+ unsigned int max_width, max_height;
+
+ if (ctx->dev->enc_capability & MTK_VENC_4K_CAPABILITY_ENABLE) {
+ max_width = MTK_VENC_4K_MAX_W;
+ max_height = MTK_VENC_4K_MAX_H;
+ } else {
+ max_width = MTK_VENC_HD_MAX_W;
+ max_height = MTK_VENC_HD_MAX_H;
+ }
pix_fmt_mp->height = clamp(pix_fmt_mp->height,
MTK_VENC_MIN_H,
- MTK_VENC_MAX_H);
+ max_height);
pix_fmt_mp->width = clamp(pix_fmt_mp->width,
MTK_VENC_MIN_W,
- MTK_VENC_MAX_W);
+ max_width);
/* find next closer width align 16, heign align 32, size align
* 64 rectangle
@@ -275,16 +296,16 @@ static int vidioc_try_fmt(struct v4l2_format *f,
tmp_h = pix_fmt_mp->height;
v4l_bound_align_image(&pix_fmt_mp->width,
MTK_VENC_MIN_W,
- MTK_VENC_MAX_W, 4,
+ max_width, 4,
&pix_fmt_mp->height,
MTK_VENC_MIN_H,
- MTK_VENC_MAX_H, 5, 6);
+ max_height, 5, 6);
if (pix_fmt_mp->width < tmp_w &&
- (pix_fmt_mp->width + 16) <= MTK_VENC_MAX_W)
+ (pix_fmt_mp->width + 16) <= max_width)
pix_fmt_mp->width += 16;
if (pix_fmt_mp->height < tmp_h &&
- (pix_fmt_mp->height + 32) <= MTK_VENC_MAX_H)
+ (pix_fmt_mp->height + 32) <= max_height)
pix_fmt_mp->height += 32;
mtk_v4l2_debug(0,
@@ -405,7 +426,7 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv,
}
q_data->fmt = fmt;
- ret = vidioc_try_fmt(f, q_data->fmt);
+ ret = vidioc_try_fmt(ctx, f, q_data->fmt);
if (ret)
return ret;
@@ -443,7 +464,6 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv,
struct mtk_q_data *q_data;
int ret, i;
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);
if (!vq) {
@@ -468,20 +488,13 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv,
f->fmt.pix.pixelformat = fmt->fourcc;
}
- pix_fmt_mp->height = clamp(pix_fmt_mp->height,
- MTK_VENC_MIN_H,
- MTK_VENC_MAX_H);
- pix_fmt_mp->width = clamp(pix_fmt_mp->width,
- MTK_VENC_MIN_W,
- MTK_VENC_MAX_W);
-
- q_data->visible_width = f->fmt.pix_mp.width;
- q_data->visible_height = f->fmt.pix_mp.height;
- q_data->fmt = fmt;
- ret = vidioc_try_fmt(f, q_data->fmt);
+ ret = vidioc_try_fmt(ctx, f, fmt);
if (ret)
return ret;
+ q_data->fmt = fmt;
+ q_data->visible_width = f->fmt.pix_mp.width;
+ q_data->visible_height = f->fmt.pix_mp.height;
q_data->coded_width = f->fmt.pix_mp.width;
q_data->coded_height = f->fmt.pix_mp.height;
@@ -553,7 +566,7 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
f->fmt.pix_mp.quantization = ctx->quantization;
f->fmt.pix_mp.xfer_func = ctx->xfer_func;
- return vidioc_try_fmt(f, fmt);
+ return vidioc_try_fmt(ctx, f, fmt);
}
static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
@@ -575,7 +588,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
}
- return vidioc_try_fmt(f, fmt);
+ return vidioc_try_fmt(ctx, f, fmt);
}
static int vidioc_venc_g_selection(struct file *file, void *priv,
@@ -1179,16 +1192,16 @@ void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx)
v4l_bound_align_image(&q_data->coded_width,
MTK_VENC_MIN_W,
- MTK_VENC_MAX_W, 4,
+ MTK_VENC_HD_MAX_W, 4,
&q_data->coded_height,
MTK_VENC_MIN_H,
- MTK_VENC_MAX_H, 5, 6);
+ MTK_VENC_HD_MAX_H, 5, 6);
if (q_data->coded_width < DFT_CFG_WIDTH &&
- (q_data->coded_width + 16) <= MTK_VENC_MAX_W)
+ (q_data->coded_width + 16) <= MTK_VENC_HD_MAX_W)
q_data->coded_width += 16;
if (q_data->coded_height < DFT_CFG_HEIGHT &&
- (q_data->coded_height + 32) <= MTK_VENC_MAX_H)
+ (q_data->coded_height + 32) <= MTK_VENC_HD_MAX_H)
q_data->coded_height += 32;
q_data->sizeimage[0] =
@@ -1218,6 +1231,12 @@ int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx)
{
const struct v4l2_ctrl_ops *ops = &mtk_vcodec_enc_ctrl_ops;
struct v4l2_ctrl_handler *handler = &ctx->ctrl_hdl;
+ u8 h264_max_level;
+
+ if (ctx->dev->enc_capability & MTK_VENC_4K_CAPABILITY_ENABLE)
+ h264_max_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
+ else
+ h264_max_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
v4l2_ctrl_handler_init(handler, MTK_MAX_CTRLS_HINT);
@@ -1248,8 +1267,9 @@ int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx)
V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
0, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL,
- V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
- 0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
+ h264_max_level,
+ 0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
+
if (handler->error) {
mtk_v4l2_err("Init control handler fail %d",
handler->error);
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 7d7b8cfc2cc5..45d1870c83dd 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
@@ -361,6 +361,9 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
goto err_event_workq;
}
+ if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL))
+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
+
ret = video_register_device(vfd_enc, VFL_TYPE_VIDEO, 1);
if (ret) {
mtk_v4l2_err("Failed to register video device");
@@ -422,12 +425,26 @@ static const struct mtk_vcodec_enc_pdata mt8183_pdata = {
.core_id = VENC_SYS,
};
+static const struct mtk_vcodec_enc_pdata mt8192_pdata = {
+ .chip = MTK_MT8192,
+ .uses_ext = true,
+ /* MT8192 supports the same capture formats as MT8183 */
+ .capture_formats = mtk_video_formats_capture_mt8183,
+ .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_mt8183),
+ /* MT8192 supports the same output formats as MT8173 */
+ .output_formats = mtk_video_formats_output_mt8173,
+ .num_output_formats = ARRAY_SIZE(mtk_video_formats_output_mt8173),
+ .min_bitrate = 64,
+ .max_bitrate = 100000000,
+ .core_id = VENC_SYS,
+};
static const struct of_device_id mtk_vcodec_enc_match[] = {
{.compatible = "mediatek,mt8173-vcodec-enc",
.data = &mt8173_avc_pdata},
{.compatible = "mediatek,mt8173-vcodec-enc-vp8",
.data = &mt8173_vp8_pdata},
{.compatible = "mediatek,mt8183-vcodec-enc", .data = &mt8183_pdata},
+ {.compatible = "mediatek,mt8192-vcodec-enc", .data = &mt8192_pdata},
{},
};
MODULE_DEVICE_TABLE(of, mtk_vcodec_enc_match);
diff --git a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
index 47a1c1c0fd04..68e8d5cb16d7 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
+++ b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
@@ -7,7 +7,7 @@
#ifndef _VDEC_IPI_MSG_H_
#define _VDEC_IPI_MSG_H_
-/**
+/*
* enum vdec_ipi_msgid - message id between AP and VPU
* @AP_IPIMSG_XXX : AP to VPU cmd message id
* @VPU_IPIMSG_XXX_ACK : VPU ack AP cmd message id
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 d0123dfc5f93..b6a4f2074fa5 100644
--- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
+++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
@@ -215,6 +215,10 @@ static unsigned int h264_get_level(struct venc_h264_inst *inst,
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:
mtk_vcodec_debug(inst, "unsupported level %d", level);
return 31;
diff --git a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
index 5f53d4255c36..587a2cf15b76 100644
--- a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
+++ b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
@@ -12,7 +12,7 @@
#define AP_IPIMSG_VENC_BASE 0xC000
#define VPU_IPIMSG_VENC_BASE 0xD000
-/**
+/*
* enum venc_ipi_msg_id - message id between AP and VPU
* (ipi stands for inter-processor interrupt)
* @AP_IPIMSG_ENC_XXX: AP to VPU cmd message id
@@ -111,7 +111,7 @@ struct venc_ap_ipi_msg_deinit {
uint32_t vpu_inst_addr;
};
-/**
+/*
* enum venc_ipi_msg_status - VPU ack AP cmd status
*/
enum venc_ipi_msg_status {
diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c
index c8a56271b259..ec290dde59cf 100644
--- a/drivers/media/platform/mtk-vpu/mtk_vpu.c
+++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c
@@ -821,13 +821,11 @@ static int mtk_vpu_probe(struct platform_device *pdev)
return -ENOMEM;
vpu->dev = &pdev->dev;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tcm");
- vpu->reg.tcm = devm_ioremap_resource(dev, res);
+ vpu->reg.tcm = devm_platform_ioremap_resource_byname(pdev, "tcm");
if (IS_ERR((__force void *)vpu->reg.tcm))
return PTR_ERR((__force void *)vpu->reg.tcm);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_reg");
- vpu->reg.cfg = devm_ioremap_resource(dev, res);
+ vpu->reg.cfg = devm_platform_ioremap_resource_byname(pdev, "cfg_reg");
if (IS_ERR((__force void *)vpu->reg.cfg))
return PTR_ERR((__force void *)vpu->reg.cfg);
@@ -987,6 +985,12 @@ static int mtk_vpu_suspend(struct device *dev)
return ret;
}
+ if (!vpu_running(vpu)) {
+ vpu_clock_disable(vpu);
+ clk_unprepare(vpu->clk);
+ return 0;
+ }
+
mutex_lock(&vpu->vpu_mutex);
/* disable vpu timer interrupt */
vpu_cfg_writel(vpu, vpu_cfg_readl(vpu, VPU_INT_STATUS) | VPU_IDLE_STATE,
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index 4e8905ef362f..108b5e9f82cb 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -29,7 +29,8 @@
#define CCDC_MIN_HEIGHT 32
static struct v4l2_mbus_framefmt *
-__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg,
+__ccdc_get_format(struct isp_ccdc_device *ccdc,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which);
static const unsigned int ccdc_fmts[] = {
@@ -1936,21 +1937,25 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
}
static struct v4l2_mbus_framefmt *
-__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg,
+__ccdc_get_format(struct isp_ccdc_device *ccdc,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&ccdc->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&ccdc->subdev, sd_state,
+ pad);
else
return &ccdc->formats[pad];
}
static struct v4l2_rect *
-__ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg,
+__ccdc_get_crop(struct isp_ccdc_device *ccdc,
+ struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&ccdc->subdev, cfg, CCDC_PAD_SOURCE_OF);
+ return v4l2_subdev_get_try_crop(&ccdc->subdev, sd_state,
+ CCDC_PAD_SOURCE_OF);
else
return &ccdc->crop;
}
@@ -1963,7 +1968,8 @@ __ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg
* @fmt: Format
*/
static void
-ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg,
+ccdc_try_format(struct isp_ccdc_device *ccdc,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -1999,7 +2005,8 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg
case CCDC_PAD_SOURCE_OF:
pixelcode = fmt->code;
field = fmt->field;
- *fmt = *__ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, which);
+ *fmt = *__ccdc_get_format(ccdc, sd_state, CCDC_PAD_SINK,
+ which);
/* In SYNC mode the bridge converts YUV formats from 2X8 to
* 1X16. In BT.656 no such conversion occurs. As we don't know
@@ -2024,7 +2031,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg
}
/* Hardcode the output size to the crop rectangle size. */
- crop = __ccdc_get_crop(ccdc, cfg, which);
+ crop = __ccdc_get_crop(ccdc, sd_state, which);
fmt->width = crop->width;
fmt->height = crop->height;
@@ -2041,7 +2048,8 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg
break;
case CCDC_PAD_SOURCE_VP:
- *fmt = *__ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, which);
+ *fmt = *__ccdc_get_format(ccdc, sd_state, CCDC_PAD_SINK,
+ which);
/* The video port interface truncates the data to 10 bits. */
info = omap3isp_video_format_info(fmt->code);
@@ -2118,7 +2126,7 @@ static void ccdc_try_crop(struct isp_ccdc_device *ccdc,
* return -EINVAL or zero on success
*/
static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
@@ -2133,7 +2141,7 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
break;
case CCDC_PAD_SOURCE_OF:
- format = __ccdc_get_format(ccdc, cfg, code->pad,
+ format = __ccdc_get_format(ccdc, sd_state, code->pad,
code->which);
if (format->code == MEDIA_BUS_FMT_YUYV8_2X8 ||
@@ -2164,7 +2172,7 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index != 0)
return -EINVAL;
- format = __ccdc_get_format(ccdc, cfg, code->pad,
+ format = __ccdc_get_format(ccdc, sd_state, code->pad,
code->which);
/* A pixel code equal to 0 means that the video port doesn't
@@ -2184,7 +2192,7 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
@@ -2196,7 +2204,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- ccdc_try_format(ccdc, cfg, fse->pad, &format, fse->which);
+ ccdc_try_format(ccdc, sd_state, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -2206,7 +2214,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- ccdc_try_format(ccdc, cfg, fse->pad, &format, fse->which);
+ ccdc_try_format(ccdc, sd_state, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -2224,7 +2232,8 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
*
* Return 0 on success or a negative error code otherwise.
*/
-static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int ccdc_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
@@ -2240,12 +2249,13 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_con
sel->r.width = INT_MAX;
sel->r.height = INT_MAX;
- format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, sel->which);
+ format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SINK,
+ sel->which);
ccdc_try_crop(ccdc, format, &sel->r);
break;
case V4L2_SEL_TGT_CROP:
- sel->r = *__ccdc_get_crop(ccdc, cfg, sel->which);
+ sel->r = *__ccdc_get_crop(ccdc, sd_state, sel->which);
break;
default:
@@ -2266,7 +2276,8 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_con
*
* Return 0 on success or a negative error code otherwise.
*/
-static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int ccdc_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
@@ -2285,17 +2296,19 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_con
* rectangle.
*/
if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
- sel->r = *__ccdc_get_crop(ccdc, cfg, sel->which);
+ sel->r = *__ccdc_get_crop(ccdc, sd_state, sel->which);
return 0;
}
- format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, sel->which);
+ format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SINK, sel->which);
ccdc_try_crop(ccdc, format, &sel->r);
- *__ccdc_get_crop(ccdc, cfg, sel->which) = sel->r;
+ *__ccdc_get_crop(ccdc, sd_state, sel->which) = sel->r;
/* Update the source format. */
- format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, sel->which);
- ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, format, sel->which);
+ format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SOURCE_OF,
+ sel->which);
+ ccdc_try_format(ccdc, sd_state, CCDC_PAD_SOURCE_OF, format,
+ sel->which);
return 0;
}
@@ -2309,13 +2322,14 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_con
* Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
* to the format type.
*/
-static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int ccdc_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __ccdc_get_format(ccdc, cfg, fmt->pad, fmt->which);
+ format = __ccdc_get_format(ccdc, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
@@ -2332,24 +2346,25 @@ static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
* Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
* to the format type.
*/
-static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int ccdc_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- format = __ccdc_get_format(ccdc, cfg, fmt->pad, fmt->which);
+ format = __ccdc_get_format(ccdc, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- ccdc_try_format(ccdc, cfg, fmt->pad, &fmt->format, fmt->which);
+ ccdc_try_format(ccdc, sd_state, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == CCDC_PAD_SINK) {
/* Reset the crop rectangle. */
- crop = __ccdc_get_crop(ccdc, cfg, fmt->which);
+ crop = __ccdc_get_crop(ccdc, sd_state, fmt->which);
crop->left = 0;
crop->top = 0;
crop->width = fmt->format.width;
@@ -2358,16 +2373,16 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
ccdc_try_crop(ccdc, &fmt->format, crop);
/* Update the source formats. */
- format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_OF,
+ format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SOURCE_OF,
fmt->which);
*format = fmt->format;
- ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, format,
+ ccdc_try_format(ccdc, sd_state, CCDC_PAD_SOURCE_OF, format,
fmt->which);
- format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_VP,
+ format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SOURCE_VP,
fmt->which);
*format = fmt->format;
- ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_VP, format,
+ ccdc_try_format(ccdc, sd_state, CCDC_PAD_SOURCE_VP, format,
fmt->which);
}
@@ -2454,7 +2469,7 @@ static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
- ccdc_set_format(sd, fh ? fh->pad : NULL, &format);
+ ccdc_set_format(sd, fh ? fh->state : NULL, &format);
return 0;
}
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
index d0a49cdfd22d..acb58b6ddba1 100644
--- a/drivers/media/platform/omap3isp/ispccp2.c
+++ b/drivers/media/platform/omap3isp/ispccp2.c
@@ -618,11 +618,13 @@ static const unsigned int ccp2_fmts[] = {
* return format structure or NULL on error
*/
static struct v4l2_mbus_framefmt *
-__ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_pad_config *cfg,
- unsigned int pad, enum v4l2_subdev_format_whence which)
+__ccp2_get_format(struct isp_ccp2_device *ccp2,
+ struct v4l2_subdev_state *sd_state,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&ccp2->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&ccp2->subdev, sd_state,
+ pad);
else
return &ccp2->formats[pad];
}
@@ -636,7 +638,8 @@ __ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_pad_config *c
* @which : wanted subdev format
*/
static void ccp2_try_format(struct isp_ccp2_device *ccp2,
- struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+ struct v4l2_subdev_state *sd_state,
+ unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -670,7 +673,8 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2,
* When CCP2 write to memory feature will be added this
* should be changed properly.
*/
- format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SINK, which);
+ format = __ccp2_get_format(ccp2, sd_state, CCP2_PAD_SINK,
+ which);
memcpy(fmt, format, sizeof(*fmt));
fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
break;
@@ -688,7 +692,7 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2,
* return -EINVAL or zero on success
*/
static int ccp2_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
@@ -703,8 +707,8 @@ static int ccp2_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index != 0)
return -EINVAL;
- format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SINK,
- code->which);
+ format = __ccp2_get_format(ccp2, sd_state, CCP2_PAD_SINK,
+ code->which);
code->code = format->code;
}
@@ -712,7 +716,7 @@ static int ccp2_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
@@ -724,7 +728,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- ccp2_try_format(ccp2, cfg, fse->pad, &format, fse->which);
+ ccp2_try_format(ccp2, sd_state, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -734,7 +738,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- ccp2_try_format(ccp2, cfg, fse->pad, &format, fse->which);
+ ccp2_try_format(ccp2, sd_state, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -748,13 +752,14 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
* @fmt : pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
-static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
+static int ccp2_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
{
struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __ccp2_get_format(ccp2, cfg, fmt->pad, fmt->which);
+ format = __ccp2_get_format(ccp2, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
@@ -769,25 +774,27 @@ static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
* @fmt : pointer to v4l2 subdev format structure
* returns zero
*/
-static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
+static int ccp2_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
{
struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __ccp2_get_format(ccp2, cfg, fmt->pad, fmt->which);
+ format = __ccp2_get_format(ccp2, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- ccp2_try_format(ccp2, cfg, fmt->pad, &fmt->format, fmt->which);
+ ccp2_try_format(ccp2, sd_state, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == CCP2_PAD_SINK) {
- format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SOURCE,
+ format = __ccp2_get_format(ccp2, sd_state, CCP2_PAD_SOURCE,
fmt->which);
*format = fmt->format;
- ccp2_try_format(ccp2, cfg, CCP2_PAD_SOURCE, format, fmt->which);
+ ccp2_try_format(ccp2, sd_state, CCP2_PAD_SOURCE, format,
+ fmt->which);
}
return 0;
@@ -812,7 +819,7 @@ static int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
- ccp2_set_format(sd, fh ? fh->pad : NULL, &format);
+ ccp2_set_format(sd, fh ? fh->state : NULL, &format);
return 0;
}
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c
index fd493c5e4e24..6302e0c94034 100644
--- a/drivers/media/platform/omap3isp/ispcsi2.c
+++ b/drivers/media/platform/omap3isp/ispcsi2.c
@@ -827,17 +827,20 @@ static const struct isp_video_operations csi2_ispvideo_ops = {
*/
static struct v4l2_mbus_framefmt *
-__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg,
+__csi2_get_format(struct isp_csi2_device *csi2,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&csi2->subdev, sd_state,
+ pad);
else
return &csi2->formats[pad];
}
static void
-csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg,
+csi2_try_format(struct isp_csi2_device *csi2,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -867,7 +870,8 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg
* compression.
*/
pixelcode = fmt->code;
- format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, which);
+ format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SINK,
+ which);
memcpy(fmt, format, sizeof(*fmt));
/*
@@ -893,7 +897,7 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg
* return -EINVAL or zero on success
*/
static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
@@ -906,7 +910,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
code->code = csi2_input_fmts[code->index];
} else {
- format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK,
+ format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SINK,
code->which);
switch (code->index) {
case 0:
@@ -930,7 +934,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
}
static int csi2_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
@@ -942,7 +946,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- csi2_try_format(csi2, cfg, fse->pad, &format, fse->which);
+ csi2_try_format(csi2, sd_state, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -952,7 +956,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- csi2_try_format(csi2, cfg, fse->pad, &format, fse->which);
+ csi2_try_format(csi2, sd_state, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -966,13 +970,14 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
* @fmt: pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
-static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int csi2_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which);
+ format = __csi2_get_format(csi2, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
@@ -987,25 +992,27 @@ static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config
* @fmt: pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
-static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int csi2_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which);
+ format = __csi2_get_format(csi2, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- csi2_try_format(csi2, cfg, fmt->pad, &fmt->format, fmt->which);
+ csi2_try_format(csi2, sd_state, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == CSI2_PAD_SINK) {
- format = __csi2_get_format(csi2, cfg, CSI2_PAD_SOURCE,
+ format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SOURCE,
fmt->which);
*format = fmt->format;
- csi2_try_format(csi2, cfg, CSI2_PAD_SOURCE, format, fmt->which);
+ csi2_try_format(csi2, sd_state, CSI2_PAD_SOURCE, format,
+ fmt->which);
}
return 0;
@@ -1030,7 +1037,7 @@ static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
- csi2_set_format(sd, fh ? fh->pad : NULL, &format);
+ csi2_set_format(sd, fh ? fh->state : NULL, &format);
return 0;
}
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c
index 607b7685c982..53aedec7990d 100644
--- a/drivers/media/platform/omap3isp/isppreview.c
+++ b/drivers/media/platform/omap3isp/isppreview.c
@@ -1679,21 +1679,25 @@ static int preview_set_stream(struct v4l2_subdev *sd, int enable)
}
static struct v4l2_mbus_framefmt *
-__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg,
+__preview_get_format(struct isp_prev_device *prev,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&prev->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&prev->subdev, sd_state,
+ pad);
else
return &prev->formats[pad];
}
static struct v4l2_rect *
-__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg,
+__preview_get_crop(struct isp_prev_device *prev,
+ struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&prev->subdev, cfg, PREV_PAD_SINK);
+ return v4l2_subdev_get_try_crop(&prev->subdev, sd_state,
+ PREV_PAD_SINK);
else
return &prev->crop;
}
@@ -1729,7 +1733,8 @@ static const unsigned int preview_output_fmts[] = {
* engine limits and the format and crop rectangles on other pads.
*/
static void preview_try_format(struct isp_prev_device *prev,
- struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+ struct v4l2_subdev_state *sd_state,
+ unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -1770,7 +1775,8 @@ static void preview_try_format(struct isp_prev_device *prev,
case PREV_PAD_SOURCE:
pixelcode = fmt->code;
- *fmt = *__preview_get_format(prev, cfg, PREV_PAD_SINK, which);
+ *fmt = *__preview_get_format(prev, sd_state, PREV_PAD_SINK,
+ which);
switch (pixelcode) {
case MEDIA_BUS_FMT_YUYV8_1X16:
@@ -1788,7 +1794,7 @@ static void preview_try_format(struct isp_prev_device *prev,
* is not supported yet, hardcode the output size to the crop
* rectangle size.
*/
- crop = __preview_get_crop(prev, cfg, which);
+ crop = __preview_get_crop(prev, sd_state, which);
fmt->width = crop->width;
fmt->height = crop->height;
@@ -1862,7 +1868,7 @@ static void preview_try_crop(struct isp_prev_device *prev,
* return -EINVAL or zero on success
*/
static int preview_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
switch (code->pad) {
@@ -1886,7 +1892,7 @@ static int preview_enum_mbus_code(struct v4l2_subdev *sd,
}
static int preview_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
@@ -1898,7 +1904,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- preview_try_format(prev, cfg, fse->pad, &format, fse->which);
+ preview_try_format(prev, sd_state, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -1908,7 +1914,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- preview_try_format(prev, cfg, fse->pad, &format, fse->which);
+ preview_try_format(prev, sd_state, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -1926,7 +1932,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd,
* Return 0 on success or a negative error code otherwise.
*/
static int preview_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
@@ -1942,13 +1948,13 @@ static int preview_get_selection(struct v4l2_subdev *sd,
sel->r.width = INT_MAX;
sel->r.height = INT_MAX;
- format = __preview_get_format(prev, cfg, PREV_PAD_SINK,
+ format = __preview_get_format(prev, sd_state, PREV_PAD_SINK,
sel->which);
preview_try_crop(prev, format, &sel->r);
break;
case V4L2_SEL_TGT_CROP:
- sel->r = *__preview_get_crop(prev, cfg, sel->which);
+ sel->r = *__preview_get_crop(prev, sd_state, sel->which);
break;
default:
@@ -1969,7 +1975,7 @@ static int preview_get_selection(struct v4l2_subdev *sd,
* Return 0 on success or a negative error code otherwise.
*/
static int preview_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
@@ -1988,17 +1994,20 @@ static int preview_set_selection(struct v4l2_subdev *sd,
* rectangle.
*/
if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
- sel->r = *__preview_get_crop(prev, cfg, sel->which);
+ sel->r = *__preview_get_crop(prev, sd_state, sel->which);
return 0;
}
- format = __preview_get_format(prev, cfg, PREV_PAD_SINK, sel->which);
+ format = __preview_get_format(prev, sd_state, PREV_PAD_SINK,
+ sel->which);
preview_try_crop(prev, format, &sel->r);
- *__preview_get_crop(prev, cfg, sel->which) = sel->r;
+ *__preview_get_crop(prev, sd_state, sel->which) = sel->r;
/* Update the source format. */
- format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE, sel->which);
- preview_try_format(prev, cfg, PREV_PAD_SOURCE, format, sel->which);
+ format = __preview_get_format(prev, sd_state, PREV_PAD_SOURCE,
+ sel->which);
+ preview_try_format(prev, sd_state, PREV_PAD_SOURCE, format,
+ sel->which);
return 0;
}
@@ -2010,13 +2019,14 @@ static int preview_set_selection(struct v4l2_subdev *sd,
* @fmt: pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
-static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int preview_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __preview_get_format(prev, cfg, fmt->pad, fmt->which);
+ format = __preview_get_format(prev, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
@@ -2031,24 +2041,25 @@ static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_con
* @fmt: pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
-static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int preview_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- format = __preview_get_format(prev, cfg, fmt->pad, fmt->which);
+ format = __preview_get_format(prev, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- preview_try_format(prev, cfg, fmt->pad, &fmt->format, fmt->which);
+ preview_try_format(prev, sd_state, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == PREV_PAD_SINK) {
/* Reset the crop rectangle. */
- crop = __preview_get_crop(prev, cfg, fmt->which);
+ crop = __preview_get_crop(prev, sd_state, fmt->which);
crop->left = 0;
crop->top = 0;
crop->width = fmt->format.width;
@@ -2057,9 +2068,9 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_con
preview_try_crop(prev, &fmt->format, crop);
/* Update the source format. */
- format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE,
+ format = __preview_get_format(prev, sd_state, PREV_PAD_SOURCE,
fmt->which);
- preview_try_format(prev, cfg, PREV_PAD_SOURCE, format,
+ preview_try_format(prev, sd_state, PREV_PAD_SOURCE, format,
fmt->which);
}
@@ -2086,7 +2097,7 @@ static int preview_init_formats(struct v4l2_subdev *sd,
format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
- preview_set_format(sd, fh ? fh->pad : NULL, &format);
+ preview_set_format(sd, fh ? fh->state : NULL, &format);
return 0;
}
diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c
index 78d9dd7ea2da..ed2fb0c7a57e 100644
--- a/drivers/media/platform/omap3isp/ispresizer.c
+++ b/drivers/media/platform/omap3isp/ispresizer.c
@@ -114,11 +114,12 @@ static const struct isprsz_coef filter_coefs = {
* return zero
*/
static struct v4l2_mbus_framefmt *
-__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_pad_config *cfg,
+__resizer_get_format(struct isp_res_device *res,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&res->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&res->subdev, sd_state, pad);
else
return &res->formats[pad];
}
@@ -130,11 +131,13 @@ __resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_pad_config *
* @which : wanted subdev crop rectangle
*/
static struct v4l2_rect *
-__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_pad_config *cfg,
+__resizer_get_crop(struct isp_res_device *res,
+ struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&res->subdev, cfg, RESZ_PAD_SINK);
+ return v4l2_subdev_get_try_crop(&res->subdev, sd_state,
+ RESZ_PAD_SINK);
else
return &res->crop.request;
}
@@ -1220,7 +1223,7 @@ static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
* Return 0 on success or a negative error code otherwise.
*/
static int resizer_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct isp_res_device *res = v4l2_get_subdevdata(sd);
@@ -1231,9 +1234,9 @@ static int resizer_get_selection(struct v4l2_subdev *sd,
if (sel->pad != RESZ_PAD_SINK)
return -EINVAL;
- format_sink = __resizer_get_format(res, cfg, RESZ_PAD_SINK,
+ format_sink = __resizer_get_format(res, sd_state, RESZ_PAD_SINK,
sel->which);
- format_source = __resizer_get_format(res, cfg, RESZ_PAD_SOURCE,
+ format_source = __resizer_get_format(res, sd_state, RESZ_PAD_SOURCE,
sel->which);
switch (sel->target) {
@@ -1248,7 +1251,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd,
break;
case V4L2_SEL_TGT_CROP:
- sel->r = *__resizer_get_crop(res, cfg, sel->which);
+ sel->r = *__resizer_get_crop(res, sd_state, sel->which);
resizer_calc_ratios(res, &sel->r, format_source, &ratio);
break;
@@ -1273,7 +1276,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd,
* Return 0 on success or a negative error code otherwise.
*/
static int resizer_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct isp_res_device *res = v4l2_get_subdevdata(sd);
@@ -1287,9 +1290,9 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
sel->pad != RESZ_PAD_SINK)
return -EINVAL;
- format_sink = __resizer_get_format(res, cfg, RESZ_PAD_SINK,
+ format_sink = __resizer_get_format(res, sd_state, RESZ_PAD_SINK,
sel->which);
- format_source = *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE,
+ format_source = *__resizer_get_format(res, sd_state, RESZ_PAD_SOURCE,
sel->which);
dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n",
@@ -1307,7 +1310,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
* stored the mangled rectangle.
*/
resizer_try_crop(format_sink, &format_source, &sel->r);
- *__resizer_get_crop(res, cfg, sel->which) = sel->r;
+ *__resizer_get_crop(res, sd_state, sel->which) = sel->r;
resizer_calc_ratios(res, &sel->r, &format_source, &ratio);
dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n",
@@ -1317,7 +1320,8 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
format_source.width, format_source.height);
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which) =
+ *__resizer_get_format(res, sd_state, RESZ_PAD_SOURCE,
+ sel->which) =
format_source;
return 0;
}
@@ -1328,7 +1332,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
*/
spin_lock_irqsave(&res->lock, flags);
- *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which) =
+ *__resizer_get_format(res, sd_state, RESZ_PAD_SOURCE, sel->which) =
format_source;
res->ratio = ratio;
@@ -1371,7 +1375,8 @@ static unsigned int resizer_max_in_width(struct isp_res_device *res)
* @which : wanted subdev format
*/
static void resizer_try_format(struct isp_res_device *res,
- struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+ struct v4l2_subdev_state *sd_state,
+ unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -1392,10 +1397,11 @@ static void resizer_try_format(struct isp_res_device *res,
break;
case RESZ_PAD_SOURCE:
- format = __resizer_get_format(res, cfg, RESZ_PAD_SINK, which);
+ format = __resizer_get_format(res, sd_state, RESZ_PAD_SINK,
+ which);
fmt->code = format->code;
- crop = *__resizer_get_crop(res, cfg, which);
+ crop = *__resizer_get_crop(res, sd_state, which);
resizer_calc_ratios(res, &crop, fmt, &ratio);
break;
}
@@ -1412,7 +1418,7 @@ static void resizer_try_format(struct isp_res_device *res,
* return -EINVAL or zero on success
*/
static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct isp_res_device *res = v4l2_get_subdevdata(sd);
@@ -1427,7 +1433,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index != 0)
return -EINVAL;
- format = __resizer_get_format(res, cfg, RESZ_PAD_SINK,
+ format = __resizer_get_format(res, sd_state, RESZ_PAD_SINK,
code->which);
code->code = format->code;
}
@@ -1436,7 +1442,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
}
static int resizer_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct isp_res_device *res = v4l2_get_subdevdata(sd);
@@ -1448,7 +1454,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- resizer_try_format(res, cfg, fse->pad, &format, fse->which);
+ resizer_try_format(res, sd_state, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -1458,7 +1464,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- resizer_try_format(res, cfg, fse->pad, &format, fse->which);
+ resizer_try_format(res, sd_state, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -1472,13 +1478,14 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
* @fmt : pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
-static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int resizer_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct isp_res_device *res = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __resizer_get_format(res, cfg, fmt->pad, fmt->which);
+ format = __resizer_get_format(res, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
@@ -1493,33 +1500,34 @@ static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_con
* @fmt : pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
-static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+static int resizer_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct isp_res_device *res = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- format = __resizer_get_format(res, cfg, fmt->pad, fmt->which);
+ format = __resizer_get_format(res, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- resizer_try_format(res, cfg, fmt->pad, &fmt->format, fmt->which);
+ resizer_try_format(res, sd_state, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
if (fmt->pad == RESZ_PAD_SINK) {
/* reset crop rectangle */
- crop = __resizer_get_crop(res, cfg, fmt->which);
+ crop = __resizer_get_crop(res, sd_state, fmt->which);
crop->left = 0;
crop->top = 0;
crop->width = fmt->format.width;
crop->height = fmt->format.height;
/* Propagate the format from sink to source */
- format = __resizer_get_format(res, cfg, RESZ_PAD_SOURCE,
+ format = __resizer_get_format(res, sd_state, RESZ_PAD_SOURCE,
fmt->which);
*format = fmt->format;
- resizer_try_format(res, cfg, RESZ_PAD_SOURCE, format,
+ resizer_try_format(res, sd_state, RESZ_PAD_SOURCE, format,
fmt->which);
}
@@ -1570,7 +1578,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd,
format.format.code = MEDIA_BUS_FMT_YUYV8_1X16;
format.format.width = 4096;
format.format.height = 4096;
- resizer_set_format(sd, fh ? fh->pad : NULL, &format);
+ resizer_set_format(sd, fh ? fh->state : NULL, &format);
return 0;
}
diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c
index dd510ee9b58a..ec4c010644ca 100644
--- a/drivers/media/platform/pxa_camera.c
+++ b/drivers/media/platform/pxa_camera.c
@@ -1792,6 +1792,9 @@ static int pxac_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
const struct pxa_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = {
+ .pads = &pad_cfg
+ };
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -1816,7 +1819,7 @@ static int pxac_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0);
v4l2_fill_mbus_format(mf, pix, xlate->code);
- ret = sensor_call(pcdev, pad, set_fmt, &pad_cfg, &format);
+ ret = sensor_call(pcdev, pad, set_fmt, &pad_state, &format);
if (ret < 0)
return ret;
diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index cc11fbfdae13..a1637b78568b 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -156,11 +156,9 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
int ret;
if (on) {
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
return ret;
- }
ret = regulator_enable(csid->vdda);
if (ret < 0) {
@@ -247,12 +245,13 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)
*/
static struct v4l2_mbus_framefmt *
__csid_get_format(struct csid_device *csid,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csid->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&csid->subdev, sd_state,
+ pad);
return &csid->fmt[pad];
}
@@ -266,7 +265,7 @@ __csid_get_format(struct csid_device *csid,
* @which: wanted subdev format
*/
static void csid_try_format(struct csid_device *csid,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
@@ -299,7 +298,7 @@ static void csid_try_format(struct csid_device *csid,
/* keep pad formats in sync */
u32 code = fmt->code;
- *fmt = *__csid_get_format(csid, cfg,
+ *fmt = *__csid_get_format(csid, sd_state,
MSM_CSID_PAD_SINK, which);
fmt->code = csid->ops->src_pad_code(csid, fmt->code, 0, code);
} else {
@@ -333,7 +332,7 @@ static void csid_try_format(struct csid_device *csid,
* return -EINVAL or zero on success
*/
static int csid_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct csid_device *csid = v4l2_get_subdevdata(sd);
@@ -347,7 +346,7 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd,
if (csid->testgen_mode->cur.val == 0) {
struct v4l2_mbus_framefmt *sink_fmt;
- sink_fmt = __csid_get_format(csid, cfg,
+ sink_fmt = __csid_get_format(csid, sd_state,
MSM_CSID_PAD_SINK,
code->which);
@@ -374,7 +373,7 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd,
* return -EINVAL or zero on success
*/
static int csid_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct csid_device *csid = v4l2_get_subdevdata(sd);
@@ -386,7 +385,7 @@ static int csid_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- csid_try_format(csid, cfg, fse->pad, &format, fse->which);
+ csid_try_format(csid, sd_state, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -396,7 +395,7 @@ static int csid_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- csid_try_format(csid, cfg, fse->pad, &format, fse->which);
+ csid_try_format(csid, sd_state, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -412,13 +411,13 @@ static int csid_enum_frame_size(struct v4l2_subdev *sd,
* Return -EINVAL or zero on success
*/
static int csid_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct csid_device *csid = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __csid_get_format(csid, cfg, fmt->pad, fmt->which);
+ format = __csid_get_format(csid, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
@@ -436,26 +435,26 @@ static int csid_get_format(struct v4l2_subdev *sd,
* Return -EINVAL or zero on success
*/
static int csid_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct csid_device *csid = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __csid_get_format(csid, cfg, fmt->pad, fmt->which);
+ format = __csid_get_format(csid, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- csid_try_format(csid, cfg, fmt->pad, &fmt->format, fmt->which);
+ csid_try_format(csid, sd_state, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == MSM_CSID_PAD_SINK) {
- format = __csid_get_format(csid, cfg, MSM_CSID_PAD_SRC,
+ format = __csid_get_format(csid, sd_state, MSM_CSID_PAD_SRC,
fmt->which);
*format = fmt->format;
- csid_try_format(csid, cfg, MSM_CSID_PAD_SRC, format,
+ csid_try_format(csid, sd_state, MSM_CSID_PAD_SRC, format,
fmt->which);
}
@@ -484,7 +483,7 @@ static int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
}
};
- return csid_set_format(sd, fh ? fh->pad : NULL, &format);
+ return csid_set_format(sd, fh ? fh->state : NULL, &format);
}
/*
@@ -566,8 +565,7 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
/* Memory */
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
- csid->base = devm_ioremap_resource(dev, r);
+ csid->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
if (IS_ERR(csid->base))
return PTR_ERR(csid->base);
@@ -584,14 +582,13 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d",
dev_name(dev), MSM_CSID_NAME, csid->id);
ret = devm_request_irq(dev, csid->irq, csid->ops->isr,
- IRQF_TRIGGER_RISING, csid->irq_name, csid);
+ IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN,
+ csid->irq_name, csid);
if (ret < 0) {
dev_err(dev, "request_irq failed: %d\n", ret);
return ret;
}
- disable_irq(csid->irq);
-
/* Clocks */
csid->nclocks = 0;
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c
index b3c3bf19e522..24eec16197e7 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.c
@@ -197,11 +197,9 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on)
if (on) {
int ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
return ret;
- }
ret = csiphy_set_clock_rates(csiphy);
if (ret < 0) {
@@ -340,12 +338,13 @@ static int csiphy_set_stream(struct v4l2_subdev *sd, int enable)
*/
static struct v4l2_mbus_framefmt *
__csiphy_get_format(struct csiphy_device *csiphy,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csiphy->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&csiphy->subdev, sd_state,
+ pad);
return &csiphy->fmt[pad];
}
@@ -359,7 +358,7 @@ __csiphy_get_format(struct csiphy_device *csiphy,
* @which: wanted subdev format
*/
static void csiphy_try_format(struct csiphy_device *csiphy,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
@@ -389,7 +388,8 @@ static void csiphy_try_format(struct csiphy_device *csiphy,
case MSM_CSIPHY_PAD_SRC:
/* Set and return a format same as sink pad */
- *fmt = *__csiphy_get_format(csiphy, cfg, MSM_CSID_PAD_SINK,
+ *fmt = *__csiphy_get_format(csiphy, sd_state,
+ MSM_CSID_PAD_SINK,
which);
break;
@@ -404,7 +404,7 @@ static void csiphy_try_format(struct csiphy_device *csiphy,
* return -EINVAL or zero on success
*/
static int csiphy_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
@@ -419,7 +419,8 @@ static int csiphy_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index > 0)
return -EINVAL;
- format = __csiphy_get_format(csiphy, cfg, MSM_CSIPHY_PAD_SINK,
+ format = __csiphy_get_format(csiphy, sd_state,
+ MSM_CSIPHY_PAD_SINK,
code->which);
code->code = format->code;
@@ -436,7 +437,7 @@ static int csiphy_enum_mbus_code(struct v4l2_subdev *sd,
* return -EINVAL or zero on success
*/
static int csiphy_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
@@ -448,7 +449,7 @@ static int csiphy_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- csiphy_try_format(csiphy, cfg, fse->pad, &format, fse->which);
+ csiphy_try_format(csiphy, sd_state, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -458,7 +459,7 @@ static int csiphy_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- csiphy_try_format(csiphy, cfg, fse->pad, &format, fse->which);
+ csiphy_try_format(csiphy, sd_state, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -474,13 +475,13 @@ static int csiphy_enum_frame_size(struct v4l2_subdev *sd,
* Return -EINVAL or zero on success
*/
static int csiphy_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __csiphy_get_format(csiphy, cfg, fmt->pad, fmt->which);
+ format = __csiphy_get_format(csiphy, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
@@ -498,26 +499,29 @@ static int csiphy_get_format(struct v4l2_subdev *sd,
* Return -EINVAL or zero on success
*/
static int csiphy_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct csiphy_device *csiphy = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __csiphy_get_format(csiphy, cfg, fmt->pad, fmt->which);
+ format = __csiphy_get_format(csiphy, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- csiphy_try_format(csiphy, cfg, fmt->pad, &fmt->format, fmt->which);
+ csiphy_try_format(csiphy, sd_state, fmt->pad, &fmt->format,
+ fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == MSM_CSIPHY_PAD_SINK) {
- format = __csiphy_get_format(csiphy, cfg, MSM_CSIPHY_PAD_SRC,
+ format = __csiphy_get_format(csiphy, sd_state,
+ MSM_CSIPHY_PAD_SRC,
fmt->which);
*format = fmt->format;
- csiphy_try_format(csiphy, cfg, MSM_CSIPHY_PAD_SRC, format,
+ csiphy_try_format(csiphy, sd_state, MSM_CSIPHY_PAD_SRC,
+ format,
fmt->which);
}
@@ -547,7 +551,7 @@ static int csiphy_init_formats(struct v4l2_subdev *sd,
}
};
- return csiphy_set_format(sd, fh ? fh->pad : NULL, &format);
+ return csiphy_set_format(sd, fh ? fh->state : NULL, &format);
}
/*
@@ -591,16 +595,14 @@ int msm_csiphy_subdev_init(struct camss *camss,
/* Memory */
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
- csiphy->base = devm_ioremap_resource(dev, r);
+ csiphy->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
if (IS_ERR(csiphy->base))
return PTR_ERR(csiphy->base);
if (camss->version == CAMSS_8x16 ||
camss->version == CAMSS_8x96) {
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- res->reg[1]);
- csiphy->base_clk_mux = devm_ioremap_resource(dev, r);
+ csiphy->base_clk_mux =
+ devm_platform_ioremap_resource_byname(pdev, res->reg[1]);
if (IS_ERR(csiphy->base_clk_mux))
return PTR_ERR(csiphy->base_clk_mux);
} else {
@@ -621,14 +623,13 @@ int msm_csiphy_subdev_init(struct camss *camss,
dev_name(dev), MSM_CSIPHY_NAME, csiphy->id);
ret = devm_request_irq(dev, csiphy->irq, csiphy->ops->isr,
- IRQF_TRIGGER_RISING, csiphy->irq_name, csiphy);
+ IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN,
+ csiphy->irq_name, csiphy);
if (ret < 0) {
dev_err(dev, "request_irq failed: %d\n", ret);
return ret;
}
- disable_irq(csiphy->irq);
-
/* Clocks */
csiphy->nclocks = 0;
diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
index 37611c8861da..ba5d65f6ef34 100644
--- a/drivers/media/platform/qcom/camss/camss-ispif.c
+++ b/drivers/media/platform/qcom/camss/camss-ispif.c
@@ -372,11 +372,9 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on)
goto exit;
}
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
goto exit;
- }
ret = camss_enable_clocks(ispif->nclocks, ispif->clock, dev);
if (ret < 0) {
@@ -876,12 +874,13 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
*/
static struct v4l2_mbus_framefmt *
__ispif_get_format(struct ispif_line *line,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&line->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&line->subdev, sd_state,
+ pad);
return &line->fmt[pad];
}
@@ -895,7 +894,7 @@ __ispif_get_format(struct ispif_line *line,
* @which: wanted subdev format
*/
static void ispif_try_format(struct ispif_line *line,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
@@ -925,7 +924,7 @@ static void ispif_try_format(struct ispif_line *line,
case MSM_ISPIF_PAD_SRC:
/* Set and return a format same as sink pad */
- *fmt = *__ispif_get_format(line, cfg, MSM_ISPIF_PAD_SINK,
+ *fmt = *__ispif_get_format(line, sd_state, MSM_ISPIF_PAD_SINK,
which);
break;
@@ -942,7 +941,7 @@ static void ispif_try_format(struct ispif_line *line,
* return -EINVAL or zero on success
*/
static int ispif_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct ispif_line *line = v4l2_get_subdevdata(sd);
@@ -957,7 +956,8 @@ static int ispif_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index > 0)
return -EINVAL;
- format = __ispif_get_format(line, cfg, MSM_ISPIF_PAD_SINK,
+ format = __ispif_get_format(line, sd_state,
+ MSM_ISPIF_PAD_SINK,
code->which);
code->code = format->code;
@@ -974,7 +974,7 @@ static int ispif_enum_mbus_code(struct v4l2_subdev *sd,
* return -EINVAL or zero on success
*/
static int ispif_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct ispif_line *line = v4l2_get_subdevdata(sd);
@@ -986,7 +986,7 @@ static int ispif_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- ispif_try_format(line, cfg, fse->pad, &format, fse->which);
+ ispif_try_format(line, sd_state, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -996,7 +996,7 @@ static int ispif_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- ispif_try_format(line, cfg, fse->pad, &format, fse->which);
+ ispif_try_format(line, sd_state, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -1012,13 +1012,13 @@ static int ispif_enum_frame_size(struct v4l2_subdev *sd,
* Return -EINVAL or zero on success
*/
static int ispif_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ispif_line *line = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __ispif_get_format(line, cfg, fmt->pad, fmt->which);
+ format = __ispif_get_format(line, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
@@ -1036,26 +1036,26 @@ static int ispif_get_format(struct v4l2_subdev *sd,
* Return -EINVAL or zero on success
*/
static int ispif_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct ispif_line *line = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __ispif_get_format(line, cfg, fmt->pad, fmt->which);
+ format = __ispif_get_format(line, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- ispif_try_format(line, cfg, fmt->pad, &fmt->format, fmt->which);
+ ispif_try_format(line, sd_state, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == MSM_ISPIF_PAD_SINK) {
- format = __ispif_get_format(line, cfg, MSM_ISPIF_PAD_SRC,
+ format = __ispif_get_format(line, sd_state, MSM_ISPIF_PAD_SRC,
fmt->which);
*format = fmt->format;
- ispif_try_format(line, cfg, MSM_ISPIF_PAD_SRC, format,
+ ispif_try_format(line, sd_state, MSM_ISPIF_PAD_SRC, format,
fmt->which);
}
@@ -1084,7 +1084,7 @@ static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
}
};
- return ispif_set_format(sd, fh ? fh->pad : NULL, &format);
+ return ispif_set_format(sd, fh ? fh->state : NULL, &format);
}
/*
@@ -1143,13 +1143,11 @@ int msm_ispif_subdev_init(struct camss *camss,
/* Memory */
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
- ispif->base = devm_ioremap_resource(dev, r);
+ ispif->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
if (IS_ERR(ispif->base))
return PTR_ERR(ispif->base);
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[1]);
- ispif->base_clk_mux = devm_ioremap_resource(dev, r);
+ ispif->base_clk_mux = devm_platform_ioremap_resource_byname(pdev, res->reg[1]);
if (IS_ERR(ispif->base_clk_mux))
return PTR_ERR(ispif->base_clk_mux);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 15695fd466c4..e0f3a36f3f3f 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -584,9 +584,9 @@ static int vfe_get(struct vfe_device *vfe)
if (ret < 0)
goto error_pm_domain;
- ret = pm_runtime_get_sync(vfe->camss->dev);
+ ret = pm_runtime_resume_and_get(vfe->camss->dev);
if (ret < 0)
- goto error_pm_runtime_get;
+ goto error_domain_off;
ret = vfe_set_clock_rates(vfe);
if (ret < 0)
@@ -620,6 +620,7 @@ error_reset:
error_pm_runtime_get:
pm_runtime_put_sync(vfe->camss->dev);
+error_domain_off:
vfe->ops->pm_domain_off(vfe);
error_pm_domain:
@@ -762,12 +763,13 @@ static int vfe_set_stream(struct v4l2_subdev *sd, int enable)
*/
static struct v4l2_mbus_framefmt *
__vfe_get_format(struct vfe_line *line,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&line->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&line->subdev, sd_state,
+ pad);
return &line->fmt[pad];
}
@@ -782,11 +784,11 @@ __vfe_get_format(struct vfe_line *line,
*/
static struct v4l2_rect *
__vfe_get_compose(struct vfe_line *line,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_compose(&line->subdev, cfg,
+ return v4l2_subdev_get_try_compose(&line->subdev, sd_state,
MSM_VFE_PAD_SINK);
return &line->compose;
@@ -802,11 +804,11 @@ __vfe_get_compose(struct vfe_line *line,
*/
static struct v4l2_rect *
__vfe_get_crop(struct vfe_line *line,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&line->subdev, cfg,
+ return v4l2_subdev_get_try_crop(&line->subdev, sd_state,
MSM_VFE_PAD_SRC);
return &line->crop;
@@ -821,7 +823,7 @@ __vfe_get_crop(struct vfe_line *line,
* @which: wanted subdev format
*/
static void vfe_try_format(struct vfe_line *line,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
@@ -853,14 +855,15 @@ static void vfe_try_format(struct vfe_line *line,
/* Set and return a format same as sink pad */
code = fmt->code;
- *fmt = *__vfe_get_format(line, cfg, MSM_VFE_PAD_SINK, which);
+ *fmt = *__vfe_get_format(line, sd_state, MSM_VFE_PAD_SINK,
+ which);
fmt->code = vfe_src_pad_code(line, fmt->code, 0, code);
if (line->id == VFE_LINE_PIX) {
struct v4l2_rect *rect;
- rect = __vfe_get_crop(line, cfg, which);
+ rect = __vfe_get_crop(line, sd_state, which);
fmt->width = rect->width;
fmt->height = rect->height;
@@ -880,13 +883,13 @@ static void vfe_try_format(struct vfe_line *line,
* @which: wanted subdev format
*/
static void vfe_try_compose(struct vfe_line *line,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_rect *rect,
enum v4l2_subdev_format_whence which)
{
struct v4l2_mbus_framefmt *fmt;
- fmt = __vfe_get_format(line, cfg, MSM_VFE_PAD_SINK, which);
+ fmt = __vfe_get_format(line, sd_state, MSM_VFE_PAD_SINK, which);
if (rect->width > fmt->width)
rect->width = fmt->width;
@@ -919,13 +922,13 @@ static void vfe_try_compose(struct vfe_line *line,
* @which: wanted subdev format
*/
static void vfe_try_crop(struct vfe_line *line,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_rect *rect,
enum v4l2_subdev_format_whence which)
{
struct v4l2_rect *compose;
- compose = __vfe_get_compose(line, cfg, which);
+ compose = __vfe_get_compose(line, sd_state, which);
if (rect->width > compose->width)
rect->width = compose->width;
@@ -963,7 +966,7 @@ static void vfe_try_crop(struct vfe_line *line,
* return -EINVAL or zero on success
*/
static int vfe_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct vfe_line *line = v4l2_get_subdevdata(sd);
@@ -976,7 +979,7 @@ static int vfe_enum_mbus_code(struct v4l2_subdev *sd,
} else {
struct v4l2_mbus_framefmt *sink_fmt;
- sink_fmt = __vfe_get_format(line, cfg, MSM_VFE_PAD_SINK,
+ sink_fmt = __vfe_get_format(line, sd_state, MSM_VFE_PAD_SINK,
code->which);
code->code = vfe_src_pad_code(line, sink_fmt->code,
@@ -997,7 +1000,7 @@ static int vfe_enum_mbus_code(struct v4l2_subdev *sd,
* Return -EINVAL or zero on success
*/
static int vfe_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct vfe_line *line = v4l2_get_subdevdata(sd);
@@ -1009,7 +1012,7 @@ static int vfe_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- vfe_try_format(line, cfg, fse->pad, &format, fse->which);
+ vfe_try_format(line, sd_state, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -1019,7 +1022,7 @@ static int vfe_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- vfe_try_format(line, cfg, fse->pad, &format, fse->which);
+ vfe_try_format(line, sd_state, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -1035,13 +1038,13 @@ static int vfe_enum_frame_size(struct v4l2_subdev *sd,
* Return -EINVAL or zero on success
*/
static int vfe_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vfe_line *line = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __vfe_get_format(line, cfg, fmt->pad, fmt->which);
+ format = __vfe_get_format(line, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
@@ -1051,7 +1054,7 @@ static int vfe_get_format(struct v4l2_subdev *sd,
}
static int vfe_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel);
/*
@@ -1063,17 +1066,17 @@ static int vfe_set_selection(struct v4l2_subdev *sd,
* Return -EINVAL or zero on success
*/
static int vfe_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vfe_line *line = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __vfe_get_format(line, cfg, fmt->pad, fmt->which);
+ format = __vfe_get_format(line, sd_state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- vfe_try_format(line, cfg, fmt->pad, &fmt->format, fmt->which);
+ vfe_try_format(line, sd_state, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
if (fmt->pad == MSM_VFE_PAD_SINK) {
@@ -1081,11 +1084,11 @@ static int vfe_set_format(struct v4l2_subdev *sd,
int ret;
/* Propagate the format from sink to source */
- format = __vfe_get_format(line, cfg, MSM_VFE_PAD_SRC,
+ format = __vfe_get_format(line, sd_state, MSM_VFE_PAD_SRC,
fmt->which);
*format = fmt->format;
- vfe_try_format(line, cfg, MSM_VFE_PAD_SRC, format,
+ vfe_try_format(line, sd_state, MSM_VFE_PAD_SRC, format,
fmt->which);
if (line->id != VFE_LINE_PIX)
@@ -1097,7 +1100,7 @@ static int vfe_set_format(struct v4l2_subdev *sd,
sel.target = V4L2_SEL_TGT_COMPOSE;
sel.r.width = fmt->format.width;
sel.r.height = fmt->format.height;
- ret = vfe_set_selection(sd, cfg, &sel);
+ ret = vfe_set_selection(sd, sd_state, &sel);
if (ret < 0)
return ret;
}
@@ -1114,7 +1117,7 @@ static int vfe_set_format(struct v4l2_subdev *sd,
* Return -EINVAL or zero on success
*/
static int vfe_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct vfe_line *line = v4l2_get_subdevdata(sd);
@@ -1130,7 +1133,7 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
fmt.pad = sel->pad;
fmt.which = sel->which;
- ret = vfe_get_format(sd, cfg, &fmt);
+ ret = vfe_get_format(sd, sd_state, &fmt);
if (ret < 0)
return ret;
@@ -1140,7 +1143,7 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
sel->r.height = fmt.format.height;
break;
case V4L2_SEL_TGT_COMPOSE:
- rect = __vfe_get_compose(line, cfg, sel->which);
+ rect = __vfe_get_compose(line, sd_state, sel->which);
if (rect == NULL)
return -EINVAL;
@@ -1152,7 +1155,7 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
else if (sel->pad == MSM_VFE_PAD_SRC)
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- rect = __vfe_get_compose(line, cfg, sel->which);
+ rect = __vfe_get_compose(line, sd_state, sel->which);
if (rect == NULL)
return -EINVAL;
@@ -1162,7 +1165,7 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
sel->r.height = rect->height;
break;
case V4L2_SEL_TGT_CROP:
- rect = __vfe_get_crop(line, cfg, sel->which);
+ rect = __vfe_get_crop(line, sd_state, sel->which);
if (rect == NULL)
return -EINVAL;
@@ -1184,7 +1187,7 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
* Return -EINVAL or zero on success
*/
static int vfe_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct vfe_line *line = v4l2_get_subdevdata(sd);
@@ -1198,11 +1201,11 @@ static int vfe_set_selection(struct v4l2_subdev *sd,
sel->pad == MSM_VFE_PAD_SINK) {
struct v4l2_subdev_selection crop = { 0 };
- rect = __vfe_get_compose(line, cfg, sel->which);
+ rect = __vfe_get_compose(line, sd_state, sel->which);
if (rect == NULL)
return -EINVAL;
- vfe_try_compose(line, cfg, &sel->r, sel->which);
+ vfe_try_compose(line, sd_state, &sel->r, sel->which);
*rect = sel->r;
/* Reset source crop selection */
@@ -1210,28 +1213,28 @@ static int vfe_set_selection(struct v4l2_subdev *sd,
crop.pad = MSM_VFE_PAD_SRC;
crop.target = V4L2_SEL_TGT_CROP;
crop.r = *rect;
- ret = vfe_set_selection(sd, cfg, &crop);
+ ret = vfe_set_selection(sd, sd_state, &crop);
} else if (sel->target == V4L2_SEL_TGT_CROP &&
sel->pad == MSM_VFE_PAD_SRC) {
struct v4l2_subdev_format fmt = { 0 };
- rect = __vfe_get_crop(line, cfg, sel->which);
+ rect = __vfe_get_crop(line, sd_state, sel->which);
if (rect == NULL)
return -EINVAL;
- vfe_try_crop(line, cfg, &sel->r, sel->which);
+ vfe_try_crop(line, sd_state, &sel->r, sel->which);
*rect = sel->r;
/* Reset source pad format width and height */
fmt.which = sel->which;
fmt.pad = MSM_VFE_PAD_SRC;
- ret = vfe_get_format(sd, cfg, &fmt);
+ ret = vfe_get_format(sd, sd_state, &fmt);
if (ret < 0)
return ret;
fmt.format.width = rect->width;
fmt.format.height = rect->height;
- ret = vfe_set_format(sd, cfg, &fmt);
+ ret = vfe_set_format(sd, sd_state, &fmt);
} else {
ret = -EINVAL;
}
@@ -1261,7 +1264,7 @@ static int vfe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
}
};
- return vfe_set_format(sd, fh ? fh->pad : NULL, &format);
+ return vfe_set_format(sd, fh ? fh->state : NULL, &format);
}
/*
@@ -1301,8 +1304,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
/* Memory */
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
- vfe->base = devm_ioremap_resource(dev, r);
+ vfe->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
if (IS_ERR(vfe->base)) {
dev_err(dev, "could not map memory\n");
return PTR_ERR(vfe->base);
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index 54bac7ec14c5..91b15842c555 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -78,22 +78,32 @@ static const struct hfi_core_ops venus_core_ops = {
.event_notify = venus_event_notify,
};
+#define RPM_WAIT_FOR_IDLE_MAX_ATTEMPTS 10
+
static void venus_sys_error_handler(struct work_struct *work)
{
struct venus_core *core =
container_of(work, struct venus_core, work.work);
- int ret = 0;
-
- pm_runtime_get_sync(core->dev);
+ int ret, i, max_attempts = RPM_WAIT_FOR_IDLE_MAX_ATTEMPTS;
+ const char *err_msg = "";
+ bool failed = false;
+
+ ret = pm_runtime_get_sync(core->dev);
+ if (ret < 0) {
+ err_msg = "resume runtime PM";
+ max_attempts = 0;
+ failed = true;
+ }
hfi_core_deinit(core, true);
- dev_warn(core->dev, "system error has occurred, starting recovery!\n");
-
mutex_lock(&core->lock);
- while (pm_runtime_active(core->dev_dec) || pm_runtime_active(core->dev_enc))
+ for (i = 0; i < max_attempts; i++) {
+ if (!pm_runtime_active(core->dev_dec) && !pm_runtime_active(core->dev_enc))
+ break;
msleep(10);
+ }
venus_shutdown(core);
@@ -101,31 +111,55 @@ static void venus_sys_error_handler(struct work_struct *work)
pm_runtime_put_sync(core->dev);
- while (core->pmdomains[0] && pm_runtime_active(core->pmdomains[0]))
+ for (i = 0; i < max_attempts; i++) {
+ if (!core->pmdomains[0] || !pm_runtime_active(core->pmdomains[0]))
+ break;
usleep_range(1000, 1500);
+ }
hfi_reinit(core);
- pm_runtime_get_sync(core->dev);
+ ret = pm_runtime_get_sync(core->dev);
+ if (ret < 0) {
+ err_msg = "resume runtime PM";
+ failed = true;
+ }
- ret |= venus_boot(core);
- ret |= hfi_core_resume(core, true);
+ ret = venus_boot(core);
+ if (ret && !failed) {
+ err_msg = "boot Venus";
+ failed = true;
+ }
+
+ ret = hfi_core_resume(core, true);
+ if (ret && !failed) {
+ err_msg = "resume HFI";
+ failed = true;
+ }
enable_irq(core->irq);
mutex_unlock(&core->lock);
- ret |= hfi_core_init(core);
+ ret = hfi_core_init(core);
+ if (ret && !failed) {
+ err_msg = "init HFI";
+ failed = true;
+ }
pm_runtime_put_sync(core->dev);
- if (ret) {
+ if (failed) {
disable_irq_nosync(core->irq);
- dev_warn(core->dev, "recovery failed (%d)\n", ret);
+ dev_warn_ratelimited(core->dev,
+ "System error has occurred, recovery failed to %s\n",
+ err_msg);
schedule_delayed_work(&core->work, msecs_to_jiffies(10));
return;
}
+ dev_warn(core->dev, "system error has occurred (recovered)\n");
+
mutex_lock(&core->lock);
core->sys_error = false;
mutex_unlock(&core->lock);
diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h
index 745f226a523f..8df2d497d706 100644
--- a/drivers/media/platform/qcom/venus/core.h
+++ b/drivers/media/platform/qcom/venus/core.h
@@ -155,7 +155,6 @@ struct venus_core {
struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX];
struct icc_path *video_path;
struct icc_path *cpucfg_path;
- struct opp_table *opp_table;
bool has_opp_table;
struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX];
struct device_link *opp_dl_venus;
@@ -293,6 +292,7 @@ struct clock_data {
unsigned long freq;
unsigned long vpp_freq;
unsigned long vsp_freq;
+ unsigned long low_power_freq;
};
#define to_venus_buffer(ptr) container_of(ptr, struct venus_buffer, vb)
@@ -316,6 +316,10 @@ struct venus_ts_metadata {
struct v4l2_timecode tc;
};
+enum venus_inst_modes {
+ VENUS_LOW_POWER = BIT(0),
+};
+
/**
* struct venus_inst - holds per instance parameters
*
@@ -445,6 +449,7 @@ struct venus_inst {
unsigned int pic_struct;
bool next_buf_last;
bool drain_active;
+ enum venus_inst_modes flags;
};
#define IS_V1(core) ((core)->res->hfi_version == HFI_VERSION_1XX)
diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c
index b813d6dba481..1fe6d463dc99 100644
--- a/drivers/media/platform/qcom/venus/helpers.c
+++ b/drivers/media/platform/qcom/venus/helpers.c
@@ -595,8 +595,7 @@ static int platform_get_bufreq(struct venus_inst *inst, u32 buftype,
params.dec.is_secondary_output =
inst->opb_buftype == HFI_BUFFER_OUTPUT2;
params.dec.is_interlaced =
- inst->pic_struct != HFI_INTERLACE_FRAME_PROGRESSIVE ?
- true : false;
+ inst->pic_struct != HFI_INTERLACE_FRAME_PROGRESSIVE;
} else {
params.width = inst->out_width;
params.height = inst->out_height;
@@ -1627,6 +1626,8 @@ int venus_helper_session_init(struct venus_inst *inst)
session_type);
inst->clk_data.vsp_freq = hfi_platform_get_codec_vsp_freq(version, codec,
session_type);
+ inst->clk_data.low_power_freq = hfi_platform_get_codec_lp_freq(version, codec,
+ session_type);
return 0;
}
diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c
index 11a8347e5f5c..f51024786991 100644
--- a/drivers/media/platform/qcom/venus/hfi_cmds.c
+++ b/drivers/media/platform/qcom/venus/hfi_cmds.c
@@ -3,6 +3,7 @@
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
+#include <linux/overflow.h>
#include <linux/errno.h>
#include <linux/hash.h>
@@ -27,7 +28,7 @@ void pkt_sys_idle_indicator(struct hfi_sys_set_property_pkt *pkt, u32 enable)
{
struct hfi_enable *hfi = (struct hfi_enable *)&pkt->data[1];
- pkt->hdr.size = sizeof(*pkt) + sizeof(*hfi) + sizeof(u32);
+ pkt->hdr.size = struct_size(pkt, data, 1) + sizeof(*hfi);
pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY;
pkt->num_properties = 1;
pkt->data[0] = HFI_PROPERTY_SYS_IDLE_INDICATOR;
@@ -39,7 +40,7 @@ void pkt_sys_debug_config(struct hfi_sys_set_property_pkt *pkt, u32 mode,
{
struct hfi_debug_config *hfi;
- pkt->hdr.size = sizeof(*pkt) + sizeof(*hfi) + sizeof(u32);
+ pkt->hdr.size = struct_size(pkt, data, 1) + sizeof(*hfi);
pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY;
pkt->num_properties = 1;
pkt->data[0] = HFI_PROPERTY_SYS_DEBUG_CONFIG;
@@ -50,7 +51,7 @@ void pkt_sys_debug_config(struct hfi_sys_set_property_pkt *pkt, u32 mode,
void pkt_sys_coverage_config(struct hfi_sys_set_property_pkt *pkt, u32 mode)
{
- pkt->hdr.size = sizeof(*pkt) + sizeof(u32);
+ pkt->hdr.size = struct_size(pkt, data, 2);
pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY;
pkt->num_properties = 1;
pkt->data[0] = HFI_PROPERTY_SYS_CONFIG_COVERAGE;
@@ -116,7 +117,7 @@ void pkt_sys_power_control(struct hfi_sys_set_property_pkt *pkt, u32 enable)
{
struct hfi_enable *hfi = (struct hfi_enable *)&pkt->data[1];
- pkt->hdr.size = sizeof(*pkt) + sizeof(*hfi) + sizeof(u32);
+ pkt->hdr.size = struct_size(pkt, data, 1) + sizeof(*hfi);
pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY;
pkt->num_properties = 1;
pkt->data[0] = HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL;
@@ -1226,6 +1227,17 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt,
pkt->shdr.hdr.size += sizeof(u32) + sizeof(*hdr10);
break;
}
+ case HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR: {
+ struct hfi_conceal_color_v4 *color = prop_data;
+ u32 *in = pdata;
+
+ color->conceal_color_8bit = *in & 0xff;
+ color->conceal_color_8bit |= ((*in >> 10) & 0xff) << 8;
+ color->conceal_color_8bit |= ((*in >> 20) & 0xff) << 16;
+ color->conceal_color_10bit = *in;
+ pkt->shdr.hdr.size += sizeof(u32) + sizeof(*color);
+ break;
+ }
case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE:
case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
@@ -1279,17 +1291,6 @@ pkt_session_set_property_6xx(struct hfi_session_set_property_pkt *pkt,
pkt->shdr.hdr.size += sizeof(u32) + sizeof(*cq);
break;
}
- case HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR: {
- struct hfi_conceal_color_v4 *color = prop_data;
- u32 *in = pdata;
-
- color->conceal_color_8bit = *in & 0xff;
- color->conceal_color_8bit |= ((*in >> 10) & 0xff) << 8;
- color->conceal_color_8bit |= ((*in >> 20) & 0xff) << 16;
- color->conceal_color_10bit = *in;
- pkt->shdr.hdr.size += sizeof(u32) + sizeof(*color);
- break;
- }
default:
return pkt_session_set_property_4xx(pkt, cookie, ptype, pdata);
}
diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.h b/drivers/media/platform/qcom/venus/hfi_cmds.h
index 83705e237f1c..327ed90a2788 100644
--- a/drivers/media/platform/qcom/venus/hfi_cmds.h
+++ b/drivers/media/platform/qcom/venus/hfi_cmds.h
@@ -68,7 +68,7 @@ struct hfi_sys_release_resource_pkt {
struct hfi_sys_set_property_pkt {
struct hfi_pkt_hdr hdr;
u32 num_properties;
- u32 data[1];
+ u32 data[];
};
struct hfi_sys_get_property_pkt {
diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h
index 63cd347a62da..b0a9beb4163c 100644
--- a/drivers/media/platform/qcom/venus/hfi_helper.h
+++ b/drivers/media/platform/qcom/venus/hfi_helper.h
@@ -415,9 +415,6 @@
#define HFI_BUFFER_MODE_RING 0x1000002
#define HFI_BUFFER_MODE_DYNAMIC 0x1000003
-#define HFI_VENC_PERFMODE_MAX_QUALITY 0x1
-#define HFI_VENC_PERFMODE_POWER_SAVE 0x2
-
/*
* HFI_PROPERTY_SYS_COMMON_START
* HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x0000
@@ -848,6 +845,13 @@ struct hfi_framesize {
u32 height;
};
+#define HFI_VENC_PERFMODE_MAX_QUALITY 0x1
+#define HFI_VENC_PERFMODE_POWER_SAVE 0x2
+
+struct hfi_perf_mode {
+ u32 video_perf_mode;
+};
+
#define VIDC_CORE_ID_DEFAULT 0
#define VIDC_CORE_ID_1 1
#define VIDC_CORE_ID_2 2
diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c
index a2d436d407b2..d9fde66f6fa8 100644
--- a/drivers/media/platform/qcom/venus/hfi_msgs.c
+++ b/drivers/media/platform/qcom/venus/hfi_msgs.c
@@ -251,11 +251,11 @@ sys_get_prop_image_version(struct device *dev,
req_bytes = pkt->hdr.size - sizeof(*pkt);
- if (req_bytes < VER_STR_SZ || !pkt->data[1] || pkt->num_properties > 1)
+ if (req_bytes < VER_STR_SZ || !pkt->data[0] || pkt->num_properties > 1)
/* bad packet */
return;
- img_ver = (u8 *)&pkt->data[1];
+ img_ver = pkt->data;
dev_dbg(dev, VDBGL "F/W version: %s\n", img_ver);
@@ -277,7 +277,7 @@ static void hfi_sys_property_info(struct venus_core *core,
return;
}
- switch (pkt->data[0]) {
+ switch (pkt->property) {
case HFI_PROPERTY_SYS_IMAGE_VERSION:
sys_get_prop_image_version(dev, pkt);
break;
@@ -338,7 +338,7 @@ session_get_prop_profile_level(struct hfi_msg_session_property_info_pkt *pkt,
/* bad packet */
return HFI_ERR_SESSION_INVALID_PARAMETER;
- hfi = (struct hfi_profile_level *)&pkt->data[1];
+ hfi = (struct hfi_profile_level *)&pkt->data[0];
profile_level->profile = hfi->profile;
profile_level->level = hfi->level;
@@ -355,11 +355,11 @@ session_get_prop_buf_req(struct hfi_msg_session_property_info_pkt *pkt,
req_bytes = pkt->shdr.hdr.size - sizeof(*pkt);
- if (!req_bytes || req_bytes % sizeof(*buf_req) || !pkt->data[1])
+ if (!req_bytes || req_bytes % sizeof(*buf_req) || !pkt->data[0])
/* bad packet */
return HFI_ERR_SESSION_INVALID_PARAMETER;
- buf_req = (struct hfi_buffer_requirements *)&pkt->data[1];
+ buf_req = (struct hfi_buffer_requirements *)&pkt->data[0];
if (!buf_req)
return HFI_ERR_SESSION_INVALID_PARAMETER;
@@ -391,7 +391,7 @@ static void hfi_session_prop_info(struct venus_core *core,
goto done;
}
- switch (pkt->data[0]) {
+ switch (pkt->property) {
case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
memset(hprop->bufreq, 0, sizeof(hprop->bufreq));
error = session_get_prop_buf_req(pkt, hprop->bufreq);
@@ -404,7 +404,7 @@ static void hfi_session_prop_info(struct venus_core *core,
case HFI_PROPERTY_CONFIG_VDEC_ENTROPY:
break;
default:
- dev_dbg(dev, VDBGM "unknown property id:%x\n", pkt->data[0]);
+ dev_dbg(dev, VDBGM "unknown property id:%x\n", pkt->property);
return;
}
diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.h b/drivers/media/platform/qcom/venus/hfi_msgs.h
index 526d9f5b487b..510513697335 100644
--- a/drivers/media/platform/qcom/venus/hfi_msgs.h
+++ b/drivers/media/platform/qcom/venus/hfi_msgs.h
@@ -113,7 +113,8 @@ struct hfi_msg_sys_ping_ack_pkt {
struct hfi_msg_sys_property_info_pkt {
struct hfi_pkt_hdr hdr;
u32 num_properties;
- u32 data[1];
+ u32 property;
+ u8 data[];
};
struct hfi_msg_session_load_resources_done_pkt {
@@ -233,7 +234,8 @@ struct hfi_msg_session_parse_sequence_header_done_pkt {
struct hfi_msg_session_property_info_pkt {
struct hfi_session_hdr_pkt shdr;
u32 num_properties;
- u32 data[1];
+ u32 property;
+ u8 data[];
};
struct hfi_msg_session_release_resources_done_pkt {
diff --git a/drivers/media/platform/qcom/venus/hfi_platform.c b/drivers/media/platform/qcom/venus/hfi_platform.c
index 8f47804e973f..f5b4e1f4764f 100644
--- a/drivers/media/platform/qcom/venus/hfi_platform.c
+++ b/drivers/media/platform/qcom/venus/hfi_platform.c
@@ -50,6 +50,22 @@ hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 codec, u32 session
return freq;
}
+unsigned long
+hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec, u32 session_type)
+{
+ const struct hfi_platform *plat;
+ unsigned long freq = 0;
+
+ plat = hfi_platform_get(version);
+ if (!plat)
+ return 0;
+
+ if (plat->codec_lp_freq)
+ freq = plat->codec_lp_freq(session_type, codec);
+
+ return freq;
+}
+
u8 hfi_platform_num_vpp_pipes(enum hfi_version version)
{
const struct hfi_platform *plat;
diff --git a/drivers/media/platform/qcom/venus/hfi_platform.h b/drivers/media/platform/qcom/venus/hfi_platform.h
index 3819bb2b36bd..2dbe608c53af 100644
--- a/drivers/media/platform/qcom/venus/hfi_platform.h
+++ b/drivers/media/platform/qcom/venus/hfi_platform.h
@@ -43,11 +43,13 @@ struct hfi_platform_codec_freq_data {
u32 session_type;
unsigned long vpp_freq;
unsigned long vsp_freq;
+ unsigned long low_power_freq;
};
struct hfi_platform {
unsigned long (*codec_vpp_freq)(u32 session_type, u32 codec);
unsigned long (*codec_vsp_freq)(u32 session_type, u32 codec);
+ unsigned long (*codec_lp_freq)(u32 session_type, u32 codec);
void (*codecs)(u32 *enc_codecs, u32 *dec_codecs, u32 *count);
const struct hfi_plat_caps *(*capabilities)(unsigned int *entries);
u8 (*num_vpp_pipes)(void);
@@ -63,5 +65,7 @@ unsigned long hfi_platform_get_codec_vpp_freq(enum hfi_version version, u32 code
u32 session_type);
unsigned long hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 codec,
u32 session_type);
+unsigned long hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec,
+ u32 session_type);
u8 hfi_platform_num_vpp_pipes(enum hfi_version version);
#endif
diff --git a/drivers/media/platform/qcom/venus/hfi_platform_v4.c b/drivers/media/platform/qcom/venus/hfi_platform_v4.c
index 3848bb6d7408..3f7f5277a50e 100644
--- a/drivers/media/platform/qcom/venus/hfi_platform_v4.c
+++ b/drivers/media/platform/qcom/venus/hfi_platform_v4.c
@@ -262,14 +262,14 @@ static void get_codecs(u32 *enc_codecs, u32 *dec_codecs, u32 *count)
}
static const struct hfi_platform_codec_freq_data codec_freq_data[] = {
- { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 10 },
- { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 10 },
- { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 10 },
- { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 10 },
- { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 10 },
- { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 10 },
- { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 10 },
- { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 10 },
+ { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 10, 320 },
+ { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 10, 320 },
+ { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 10, 320 },
+ { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
+ { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
+ { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
+ { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
+ { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
};
static const struct hfi_platform_codec_freq_data *
@@ -311,9 +311,21 @@ static unsigned long codec_vsp_freq(u32 session_type, u32 codec)
return 0;
}
+static unsigned long codec_lp_freq(u32 session_type, u32 codec)
+{
+ const struct hfi_platform_codec_freq_data *data;
+
+ data = get_codec_freq_data(session_type, codec);
+ if (data)
+ return data->low_power_freq;
+
+ return 0;
+}
+
const struct hfi_platform hfi_plat_v4 = {
.codec_vpp_freq = codec_vpp_freq,
.codec_vsp_freq = codec_vsp_freq,
+ .codec_lp_freq = codec_lp_freq,
.codecs = get_codecs,
.capabilities = get_capabilities,
};
diff --git a/drivers/media/platform/qcom/venus/hfi_platform_v6.c b/drivers/media/platform/qcom/venus/hfi_platform_v6.c
index dd1a03911b6c..d8243b22568a 100644
--- a/drivers/media/platform/qcom/venus/hfi_platform_v6.c
+++ b/drivers/media/platform/qcom/venus/hfi_platform_v6.c
@@ -262,14 +262,14 @@ static void get_codecs(u32 *enc_codecs, u32 *dec_codecs, u32 *count)
}
static const struct hfi_platform_codec_freq_data codec_freq_data[] = {
- { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 25 },
- { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 25 },
- { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 60 },
- { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 25 },
- { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 25 },
- { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 25 },
- { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 60 },
- { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 60 },
+ { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 25, 320 },
+ { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 25, 320 },
+ { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 60, 320 },
+ { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 25, 200 },
+ { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 25, 200 },
+ { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 25, 200 },
+ { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 60, 200 },
+ { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 60, 200 },
};
static const struct hfi_platform_codec_freq_data *
@@ -311,6 +311,17 @@ static unsigned long codec_vsp_freq(u32 session_type, u32 codec)
return 0;
}
+static unsigned long codec_lp_freq(u32 session_type, u32 codec)
+{
+ const struct hfi_platform_codec_freq_data *data;
+
+ data = get_codec_freq_data(session_type, codec);
+ if (data)
+ return data->low_power_freq;
+
+ return 0;
+}
+
static u8 num_vpp_pipes(void)
{
return 4;
@@ -319,6 +330,7 @@ static u8 num_vpp_pipes(void)
const struct hfi_platform hfi_plat_v6 = {
.codec_vpp_freq = codec_vpp_freq,
.codec_vsp_freq = codec_vsp_freq,
+ .codec_lp_freq = codec_lp_freq,
.codecs = get_codecs,
.capabilities = get_capabilities,
.num_vpp_pipes = num_vpp_pipes,
diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c
index c7e1ebec47ee..3e2345eb47f7 100644
--- a/drivers/media/platform/qcom/venus/pm_helpers.c
+++ b/drivers/media/platform/qcom/venus/pm_helpers.c
@@ -300,16 +300,15 @@ static int core_get_v1(struct venus_core *core)
if (ret)
return ret;
- core->opp_table = dev_pm_opp_set_clkname(core->dev, "core");
- if (IS_ERR(core->opp_table))
- return PTR_ERR(core->opp_table);
+ ret = devm_pm_opp_set_clkname(core->dev, "core");
+ if (ret)
+ return ret;
return 0;
}
static void core_put_v1(struct venus_core *core)
{
- dev_pm_opp_put_clkname(core->opp_table);
}
static int core_power_v1(struct venus_core *core, int on)
@@ -524,8 +523,50 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
return 0;
}
+static inline int power_save_mode_enable(struct venus_inst *inst,
+ bool enable)
+{
+ struct venc_controls *enc_ctr = &inst->controls.enc;
+ const u32 ptype = HFI_PROPERTY_CONFIG_VENC_PERF_MODE;
+ u32 venc_mode;
+ int ret = 0;
+
+ if (inst->session_type != VIDC_SESSION_TYPE_ENC)
+ return 0;
+
+ if (enc_ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)
+ enable = false;
+
+ venc_mode = enable ? HFI_VENC_PERFMODE_POWER_SAVE :
+ HFI_VENC_PERFMODE_MAX_QUALITY;
+
+ ret = hfi_session_set_property(inst, ptype, &venc_mode);
+ if (ret)
+ return ret;
+
+ inst->flags = enable ? inst->flags | VENUS_LOW_POWER :
+ inst->flags & ~VENUS_LOW_POWER;
+
+ return ret;
+}
+
+static int move_core_to_power_save_mode(struct venus_core *core,
+ u32 core_id)
+{
+ struct venus_inst *inst = NULL;
+
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+ if (inst->clk_data.core_id == core_id &&
+ inst->session_type == VIDC_SESSION_TYPE_ENC)
+ power_save_mode_enable(inst, true);
+ }
+ mutex_unlock(&core->lock);
+ return 0;
+}
+
static void
-min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load)
+min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load, bool low_power)
{
u32 mbs_per_sec, load, core1_load = 0, core2_load = 0;
u32 cores_max = core_num_max(inst);
@@ -543,7 +584,14 @@ min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load)
if (inst_pos->state != INST_START)
continue;
- vpp_freq = inst_pos->clk_data.vpp_freq;
+ if (inst->session_type == VIDC_SESSION_TYPE_DEC)
+ vpp_freq = inst_pos->clk_data.vpp_freq;
+ else if (inst->session_type == VIDC_SESSION_TYPE_ENC)
+ vpp_freq = low_power ? inst_pos->clk_data.vpp_freq :
+ inst_pos->clk_data.low_power_freq;
+ else
+ continue;
+
coreid = inst_pos->clk_data.core_id;
mbs_per_sec = load_per_instance(inst_pos);
@@ -575,9 +623,11 @@ static int decide_core(struct venus_inst *inst)
{
const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE;
struct venus_core *core = inst->core;
- u32 min_coreid, min_load, inst_load;
+ u32 min_coreid, min_load, cur_inst_load;
+ u32 min_lp_coreid, min_lp_load, cur_inst_lp_load;
struct hfi_videocores_usage_type cu;
unsigned long max_freq;
+ int ret = 0;
if (legacy_binding) {
if (inst->session_type == VIDC_SESSION_TYPE_DEC)
@@ -591,23 +641,43 @@ static int decide_core(struct venus_inst *inst)
if (inst->clk_data.core_id != VIDC_CORE_ID_DEFAULT)
return 0;
- inst_load = load_per_instance(inst);
- inst_load *= inst->clk_data.vpp_freq;
- max_freq = core->res->freq_tbl[0].freq;
+ cur_inst_load = load_per_instance(inst);
+ cur_inst_load *= inst->clk_data.vpp_freq;
+ /*TODO : divide this inst->load by work_route */
- min_loaded_core(inst, &min_coreid, &min_load);
+ cur_inst_lp_load = load_per_instance(inst);
+ cur_inst_lp_load *= inst->clk_data.low_power_freq;
+ /*TODO : divide this inst->load by work_route */
- if ((inst_load + min_load) > max_freq) {
- dev_warn(core->dev, "HW is overloaded, needed: %u max: %lu\n",
- inst_load, max_freq);
+ max_freq = core->res->freq_tbl[0].freq;
+
+ min_loaded_core(inst, &min_coreid, &min_load, false);
+ min_loaded_core(inst, &min_lp_coreid, &min_lp_load, true);
+
+ if (cur_inst_load + min_load <= max_freq) {
+ inst->clk_data.core_id = min_coreid;
+ cu.video_core_enable_mask = min_coreid;
+ } else if (cur_inst_lp_load + min_load <= max_freq) {
+ /* Move current instance to LP and return */
+ inst->clk_data.core_id = min_coreid;
+ cu.video_core_enable_mask = min_coreid;
+ power_save_mode_enable(inst, true);
+ } else if (cur_inst_lp_load + min_lp_load <= max_freq) {
+ /* Move all instances to LP mode and return */
+ inst->clk_data.core_id = min_lp_coreid;
+ cu.video_core_enable_mask = min_lp_coreid;
+ move_core_to_power_save_mode(core, min_lp_coreid);
+ } else {
+ dev_warn(core->dev, "HW can't support this load");
return -EINVAL;
}
- inst->clk_data.core_id = min_coreid;
- cu.video_core_enable_mask = min_coreid;
-
done:
- return hfi_session_set_property(inst, ptype, &cu);
+ ret = hfi_session_set_property(inst, ptype, &cu);
+ if (ret)
+ return ret;
+
+ return ret;
}
static int acquire_core(struct venus_inst *inst)
@@ -788,7 +858,6 @@ static int venc_power_v4(struct device *dev, int on)
static int vcodec_domains_get(struct venus_core *core)
{
int ret;
- struct opp_table *opp_table;
struct device **opp_virt_dev;
struct device *dev = core->dev;
const struct venus_resources *res = core->res;
@@ -811,11 +880,9 @@ skip_pmdomains:
return 0;
/* Attach the power domain for setting performance state */
- opp_table = dev_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
- if (IS_ERR(opp_table)) {
- ret = PTR_ERR(opp_table);
+ ret = devm_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
+ if (ret)
goto opp_attach_err;
- }
core->opp_pmdomain = *opp_virt_dev;
core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain,
@@ -824,13 +891,11 @@ skip_pmdomains:
DL_FLAG_STATELESS);
if (!core->opp_dl_venus) {
ret = -ENODEV;
- goto opp_dl_add_err;
+ goto opp_attach_err;
}
return 0;
-opp_dl_add_err:
- dev_pm_opp_detach_genpd(core->opp_table);
opp_attach_err:
for (i = 0; i < res->vcodec_pmdomains_num; i++) {
if (IS_ERR_OR_NULL(core->pmdomains[i]))
@@ -861,8 +926,6 @@ skip_pmdomains:
if (core->opp_dl_venus)
device_link_del(core->opp_dl_venus);
-
- dev_pm_opp_detach_genpd(core->opp_table);
}
static int core_resets_reset(struct venus_core *core)
@@ -941,45 +1004,33 @@ static int core_get_v4(struct venus_core *core)
if (legacy_binding)
return 0;
- core->opp_table = dev_pm_opp_set_clkname(dev, "core");
- if (IS_ERR(core->opp_table))
- return PTR_ERR(core->opp_table);
+ ret = devm_pm_opp_set_clkname(dev, "core");
+ if (ret)
+ return ret;
if (core->res->opp_pmdomain) {
- ret = dev_pm_opp_of_add_table(dev);
+ ret = devm_pm_opp_of_add_table(dev);
if (!ret) {
core->has_opp_table = true;
} else if (ret != -ENODEV) {
dev_err(dev, "invalid OPP table in device tree\n");
- dev_pm_opp_put_clkname(core->opp_table);
return ret;
}
}
ret = vcodec_domains_get(core);
- if (ret) {
- if (core->has_opp_table)
- dev_pm_opp_of_remove_table(dev);
- dev_pm_opp_put_clkname(core->opp_table);
+ if (ret)
return ret;
- }
return 0;
}
static void core_put_v4(struct venus_core *core)
{
- struct device *dev = core->dev;
-
if (legacy_binding)
return;
vcodec_domains_put(core);
-
- if (core->has_opp_table)
- dev_pm_opp_of_remove_table(dev);
- dev_pm_opp_put_clkname(core->opp_table);
-
}
static int core_power_v4(struct venus_core *core, int on)
@@ -990,9 +1041,8 @@ static int core_power_v4(struct venus_core *core, int on)
if (on == POWER_ON) {
if (pmctrl) {
- ret = pm_runtime_get_sync(pmctrl);
+ ret = pm_runtime_resume_and_get(pmctrl);
if (ret < 0) {
- pm_runtime_put_noidle(pmctrl);
return ret;
}
}
@@ -1026,7 +1076,7 @@ static int core_power_v4(struct venus_core *core, int on)
static unsigned long calculate_inst_freq(struct venus_inst *inst,
unsigned long filled_len)
{
- unsigned long vpp_freq = 0, vsp_freq = 0;
+ unsigned long vpp_freq_per_mb = 0, vpp_freq = 0, vsp_freq = 0;
u32 fps = (u32)inst->fps;
u32 mbs_per_sec;
@@ -1035,7 +1085,12 @@ static unsigned long calculate_inst_freq(struct venus_inst *inst,
if (inst->state != INST_START)
return 0;
- vpp_freq = mbs_per_sec * inst->clk_data.vpp_freq;
+ if (inst->session_type == VIDC_SESSION_TYPE_ENC)
+ vpp_freq_per_mb = inst->flags & VENUS_LOW_POWER ?
+ inst->clk_data.low_power_freq :
+ inst->clk_data.vpp_freq;
+
+ vpp_freq = mbs_per_sec * vpp_freq_per_mb;
/* 21 / 20 is overhead factor */
vpp_freq += vpp_freq / 20;
vsp_freq = mbs_per_sec * inst->clk_data.vsp_freq;
diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
index ddb7cd39424e..198e47eb63f4 100644
--- a/drivers/media/platform/qcom/venus/vdec.c
+++ b/drivers/media/platform/qcom/venus/vdec.c
@@ -568,10 +568,10 @@ static int vdec_pm_get(struct venus_inst *inst)
int ret;
mutex_lock(&core->pm_lock);
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
mutex_unlock(&core->pm_lock);
- return ret < 0 ? ret : 0;
+ return ret;
}
static int vdec_pm_put(struct venus_inst *inst, bool autosuspend)
@@ -601,7 +601,7 @@ static int vdec_pm_get_put(struct venus_inst *inst)
mutex_lock(&core->pm_lock);
if (pm_runtime_suspended(dev)) {
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
goto error;
diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
index 4a7291f934b6..8dd49d4f124c 100644
--- a/drivers/media/platform/qcom/venus/venc.c
+++ b/drivers/media/platform/qcom/venus/venc.c
@@ -1205,9 +1205,9 @@ static int venc_open(struct file *file)
venus_helper_init_instance(inst);
- ret = pm_runtime_get_sync(core->dev_enc);
+ ret = pm_runtime_resume_and_get(core->dev_enc);
if (ret < 0)
- goto err_put_sync;
+ goto err_free;
ret = venc_ctrl_init(inst);
if (ret)
@@ -1252,6 +1252,7 @@ err_ctrl_deinit:
venc_ctrl_deinit(inst);
err_put_sync:
pm_runtime_put_sync(core->dev_enc);
+err_free:
kfree(inst);
return ret;
}
diff --git a/drivers/media/platform/rcar-fcp.c b/drivers/media/platform/rcar-fcp.c
index 5c03318ae07b..eb59a3ba6d0f 100644
--- a/drivers/media/platform/rcar-fcp.c
+++ b/drivers/media/platform/rcar-fcp.c
@@ -96,18 +96,10 @@ EXPORT_SYMBOL_GPL(rcar_fcp_get_device);
*/
int rcar_fcp_enable(struct rcar_fcp_device *fcp)
{
- int ret;
-
if (!fcp)
return 0;
- ret = pm_runtime_get_sync(fcp->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(fcp->dev);
- return ret;
- }
-
- return 0;
+ return pm_runtime_resume_and_get(fcp->dev);
}
EXPORT_SYMBOL_GPL(rcar_fcp_enable);
diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
index cb3025992817..33957cc9118c 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -1363,6 +1363,10 @@ static const struct of_device_id rvin_of_id_table[] = {
.data = &rcar_info_r8a7796,
},
{
+ .compatible = "renesas,vin-r8a77961",
+ .data = &rcar_info_r8a7796,
+ },
+ {
.compatible = "renesas,vin-r8a77965",
.data = &rcar_info_r8a77965,
},
diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index e06cd512aba2..e28eff039688 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -320,10 +320,12 @@ static const struct rcar_csi2_format rcar_csi2_formats[] = {
{ .code = MEDIA_BUS_FMT_YUYV8_1X16, .datatype = 0x1e, .bpp = 16 },
{ .code = MEDIA_BUS_FMT_UYVY8_2X8, .datatype = 0x1e, .bpp = 16 },
{ .code = MEDIA_BUS_FMT_YUYV10_2X10, .datatype = 0x1e, .bpp = 20 },
+ { .code = MEDIA_BUS_FMT_Y10_1X10, .datatype = 0x2b, .bpp = 10 },
{ .code = MEDIA_BUS_FMT_SBGGR8_1X8, .datatype = 0x2a, .bpp = 8 },
{ .code = MEDIA_BUS_FMT_SGBRG8_1X8, .datatype = 0x2a, .bpp = 8 },
{ .code = MEDIA_BUS_FMT_SGRBG8_1X8, .datatype = 0x2a, .bpp = 8 },
{ .code = MEDIA_BUS_FMT_SRGGB8_1X8, .datatype = 0x2a, .bpp = 8 },
+ { .code = MEDIA_BUS_FMT_Y8_1X8, .datatype = 0x2a, .bpp = 8 },
};
static const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code)
@@ -406,10 +408,17 @@ static void rcsi2_enter_standby(struct rcar_csi2 *priv)
pm_runtime_put(priv->dev);
}
-static void rcsi2_exit_standby(struct rcar_csi2 *priv)
+static int rcsi2_exit_standby(struct rcar_csi2 *priv)
{
- pm_runtime_get_sync(priv->dev);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret < 0)
+ return ret;
+
reset_control_deassert(priv->rstc);
+
+ return 0;
}
static int rcsi2_wait_phy_start(struct rcar_csi2 *priv,
@@ -657,7 +666,9 @@ static int rcsi2_start(struct rcar_csi2 *priv)
{
int ret;
- rcsi2_exit_standby(priv);
+ ret = rcsi2_exit_standby(priv);
+ if (ret < 0)
+ return ret;
ret = rcsi2_start_receiver(priv);
if (ret) {
@@ -708,7 +719,7 @@ out:
}
static int rcsi2_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct rcar_csi2 *priv = sd_to_csi2(sd);
@@ -720,7 +731,7 @@ static int rcsi2_set_pad_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
priv->mf = format->format;
} else {
- framefmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
*framefmt = format->format;
}
@@ -728,7 +739,7 @@ static int rcsi2_set_pad_format(struct v4l2_subdev *sd,
}
static int rcsi2_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct rcar_csi2 *priv = sd_to_csi2(sd);
@@ -736,7 +747,7 @@ static int rcsi2_get_pad_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
format->format = priv->mf;
else
- format->format = *v4l2_subdev_get_try_format(sd, cfg, 0);
+ format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0);
return 0;
}
@@ -1112,6 +1123,11 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = {
.num_channels = 4,
};
+static const struct rcar_csi2_info rcar_csi2_info_r8a77961 = {
+ .hsfreqrange = hsfreqrange_m3w_h3es1,
+ .num_channels = 4,
+};
+
static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = {
.init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
.hsfreqrange = hsfreqrange_h3_v3h_m3n,
@@ -1165,6 +1181,10 @@ static const struct of_device_id rcar_csi2_of_table[] = {
.data = &rcar_csi2_info_r8a7796,
},
{
+ .compatible = "renesas,r8a77961-csi2",
+ .data = &rcar_csi2_info_r8a77961,
+ },
+ {
.compatible = "renesas,r8a77965-csi2",
.data = &rcar_csi2_info_r8a77965,
},
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index f30dafbdf61c..f5f722ab1d4e 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -1458,11 +1458,9 @@ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel)
u32 vnmc;
int ret;
- ret = pm_runtime_get_sync(vin->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(vin->dev);
+ ret = pm_runtime_resume_and_get(vin->dev);
+ if (ret < 0)
return ret;
- }
/* Make register writes take effect immediately. */
vnmc = rvin_read(vin, VNMC_REG);
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c
index 457a65bf6b66..cca15a10c0b3 100644
--- a/drivers/media/platform/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c
@@ -243,7 +243,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
struct v4l2_rect *src_rect)
{
struct v4l2_subdev *sd = vin_to_source(vin);
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
struct v4l2_subdev_format format = {
.which = which,
.pad = vin->parallel.source_pad,
@@ -252,8 +252,8 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
u32 width, height;
int ret;
- pad_cfg = v4l2_subdev_alloc_pad_config(sd);
- if (pad_cfg == NULL)
+ sd_state = v4l2_subdev_alloc_state(sd);
+ if (sd_state == NULL)
return -ENOMEM;
if (!rvin_format_from_pixel(vin, pix->pixelformat))
@@ -266,7 +266,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
width = pix->width;
height = pix->height;
- ret = v4l2_subdev_call(sd, pad, set_fmt, pad_cfg, &format);
+ ret = v4l2_subdev_call(sd, pad, set_fmt, sd_state, &format);
if (ret < 0 && ret != -ENOIOCTLCMD)
goto done;
ret = 0;
@@ -288,7 +288,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
rvin_format_align(vin, pix);
done:
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
return ret;
}
@@ -870,11 +870,9 @@ static int rvin_open(struct file *file)
struct rvin_dev *vin = video_drvdata(file);
int ret;
- ret = pm_runtime_get_sync(vin->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(vin->dev);
+ ret = pm_runtime_resume_and_get(vin->dev);
+ if (ret < 0)
return ret;
- }
ret = mutex_lock_interruptible(&vin->lock);
if (ret)
diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c
index 01c1fbb97bf6..89aac60066d9 100644
--- a/drivers/media/platform/rcar_fdp1.c
+++ b/drivers/media/platform/rcar_fdp1.c
@@ -2117,9 +2117,7 @@ static int fdp1_open(struct file *file)
if (ctx->hdl.error) {
ret = ctx->hdl.error;
- v4l2_ctrl_handler_free(&ctx->hdl);
- kfree(ctx);
- goto done;
+ goto error_ctx;
}
ctx->fh.ctrl_handler = &ctx->hdl;
@@ -2133,20 +2131,27 @@ static int fdp1_open(struct file *file)
if (IS_ERR(ctx->fh.m2m_ctx)) {
ret = PTR_ERR(ctx->fh.m2m_ctx);
-
- v4l2_ctrl_handler_free(&ctx->hdl);
- kfree(ctx);
- goto done;
+ goto error_ctx;
}
/* Perform any power management required */
- pm_runtime_get_sync(fdp1->dev);
+ ret = pm_runtime_resume_and_get(fdp1->dev);
+ if (ret < 0)
+ goto error_pm;
v4l2_fh_add(&ctx->fh);
dprintk(fdp1, "Created instance: %p, m2m_ctx: %p\n",
ctx, ctx->fh.m2m_ctx);
+ mutex_unlock(&fdp1->dev_mutex);
+ return 0;
+
+error_pm:
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+error_ctx:
+ v4l2_ctrl_handler_free(&ctx->hdl);
+ kfree(ctx);
done:
mutex_unlock(&fdp1->dev_mutex);
return ret;
@@ -2351,7 +2356,9 @@ static int fdp1_probe(struct platform_device *pdev)
/* Power up the cells to read HW */
pm_runtime_enable(&pdev->dev);
- pm_runtime_get_sync(fdp1->dev);
+ ret = pm_runtime_resume_and_get(fdp1->dev);
+ if (ret < 0)
+ goto disable_pm;
hw_version = fdp1_read(fdp1, FD1_IP_INTDATA);
switch (hw_version) {
@@ -2380,6 +2387,9 @@ static int fdp1_probe(struct platform_device *pdev)
return 0;
+disable_pm:
+ pm_runtime_disable(fdp1->dev);
+
release_m2m:
v4l2_m2m_release(fdp1->m2m_dev);
diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c
index a7c198c17deb..f57158bf2b11 100644
--- a/drivers/media/platform/rcar_jpu.c
+++ b/drivers/media/platform/rcar_jpu.c
@@ -42,7 +42,7 @@
/*
* Align JPEG header end to cache line to make sure we will not have any issues
- * with cache; additionally to requerment (33.3.27 R01UH0501EJ0100 Rev.1.00)
+ * with cache; additionally to requirement (33.3.27 R01UH0501EJ0100 Rev.1.00)
*/
#define JPU_JPEG_HDR_SIZE (ALIGN(0x258, L1_CACHE_BYTES))
#define JPU_JPEG_MAX_BYTES_PER_PIXEL 2 /* 16 bit precision format */
@@ -121,7 +121,7 @@
#define JCCMD_JEND (1 << 2)
#define JCCMD_JSRT (1 << 0)
-/* JPEG code quantanization table number register */
+/* JPEG code quantization table number register */
#define JCQTN 0x0c
#define JCQTN_SHIFT(t) (((t) - 1) << 1)
@@ -1644,7 +1644,7 @@ static int jpu_probe(struct platform_device *pdev)
goto device_register_rollback;
}
- /* fill in qantization and Huffman tables for encoder */
+ /* fill in quantization and Huffman tables for encoder */
for (i = 0; i < JPU_MAX_QUALITY; i++)
jpu_generate_hdr(i, (unsigned char *)jpeg_hdrs[i]);
diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c
index cd137101d41e..f432032c7084 100644
--- a/drivers/media/platform/renesas-ceu.c
+++ b/drivers/media/platform/renesas-ceu.c
@@ -794,6 +794,9 @@ static int __ceu_try_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt
struct v4l2_pix_format_mplane *pix = &v4l2_fmt->fmt.pix_mp;
struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd;
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = {
+ .pads = &pad_cfg
+ };
const struct ceu_fmt *ceu_fmt;
u32 mbus_code_old;
u32 mbus_code;
@@ -850,13 +853,13 @@ static int __ceu_try_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt
* time.
*/
sd_format.format.code = mbus_code;
- ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, &pad_cfg, &sd_format);
+ ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, &pad_state, &sd_format);
if (ret) {
if (ret == -EINVAL) {
/* fallback */
sd_format.format.code = mbus_code_old;
ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt,
- &pad_cfg, &sd_format);
+ &pad_state, &sd_format);
}
if (ret)
@@ -1099,10 +1102,10 @@ static int ceu_open(struct file *file)
mutex_lock(&ceudev->mlock);
/* Causes soft-reset and sensor power on on first open */
- pm_runtime_get_sync(ceudev->dev);
+ ret = pm_runtime_resume_and_get(ceudev->dev);
mutex_unlock(&ceudev->mlock);
- return 0;
+ return ret;
}
static int ceu_release(struct file *file)
diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index bf9a75b75083..81508ed5abf3 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -79,9 +79,8 @@ static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count)
struct rockchip_rga *rga = ctx->rga;
int ret;
- ret = pm_runtime_get_sync(rga->dev);
+ ret = pm_runtime_resume_and_get(rga->dev);
if (ret < 0) {
- pm_runtime_put_noidle(rga->dev);
rga_buf_return_buffers(q, VB2_BUF_STATE_QUEUED);
return ret;
}
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 9d122429706e..bf3fd71ec3af 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -866,7 +866,9 @@ static int rga_probe(struct platform_device *pdev)
goto unreg_video_dev;
}
- pm_runtime_get_sync(rga->dev);
+ ret = pm_runtime_resume_and_get(rga->dev);
+ if (ret < 0)
+ goto unreg_video_dev;
rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
index 5f6c9d1623e4..60cd2200e7ae 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
@@ -830,8 +830,8 @@ static void rkisp1_return_all_buffers(struct rkisp1_capture *cap,
}
/*
- * Most of registers inside rockchip ISP1 have shadow register since
- * they must be not be changed during processing a frame.
+ * Most registers inside the rockchip ISP1 have shadow register since
+ * they must not be changed while processing a frame.
* Usually, each sub-module updates its shadow register after
* processing the last pixel of a frame.
*/
@@ -847,14 +847,14 @@ static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap)
spin_lock_irq(&cap->buf.lock);
rkisp1_set_next_buf(cap);
cap->ops->enable(cap);
- /* It's safe to config ACTIVE and SHADOW regs for the
+ /* It's safe to configure ACTIVE and SHADOW registers for the
* first stream. While when the second is starting, do NOT
- * force update because it also update the first one.
+ * force update because it also updates the first one.
*
- * The latter case would drop one more buf(that is 2) since
- * there's not buf in shadow when the second FE received. This's
- * also required because the second FE maybe corrupt especially
- * when run at 120fps.
+ * The latter case would drop one more buffer(that is 2) since
+ * there's no buffer in a shadow register when the second FE received.
+ * This's also required because the second FE maybe corrupt
+ * especially when run at 120fps.
*/
if (!other->is_streaming) {
/* force cfg update */
@@ -1003,9 +1003,8 @@ rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count)
if (ret)
goto err_pipeline_stop;
- ret = pm_runtime_get_sync(cap->rkisp1->dev);
+ ret = pm_runtime_resume_and_get(cap->rkisp1->dev);
if (ret < 0) {
- pm_runtime_put_noidle(cap->rkisp1->dev);
dev_err(cap->rkisp1->dev, "power up failed %d\n", ret);
goto err_destroy_dummy;
}
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
index 2e5b57e3aedc..d596bc040005 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
@@ -208,24 +208,30 @@ static struct v4l2_subdev *rkisp1_get_remote_sensor(struct v4l2_subdev *sd)
static struct v4l2_mbus_framefmt *
rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, u32 which)
{
+ struct v4l2_subdev_state state = {
+ .pads = isp->pad_cfg
+ };
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&isp->sd, cfg, pad);
+ return v4l2_subdev_get_try_format(&isp->sd, sd_state, pad);
else
- return v4l2_subdev_get_try_format(&isp->sd, isp->pad_cfg, pad);
+ return v4l2_subdev_get_try_format(&isp->sd, &state, pad);
}
static struct v4l2_rect *
rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, u32 which)
{
+ struct v4l2_subdev_state state = {
+ .pads = isp->pad_cfg
+ };
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&isp->sd, cfg, pad);
+ return v4l2_subdev_get_try_crop(&isp->sd, sd_state, pad);
else
- return v4l2_subdev_get_try_crop(&isp->sd, isp->pad_cfg, pad);
+ return v4l2_subdev_get_try_crop(&isp->sd, &state, pad);
}
/* ----------------------------------------------------------------------------
@@ -561,7 +567,7 @@ static void rkisp1_isp_start(struct rkisp1_device *rkisp1)
*/
static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
unsigned int i, dir;
@@ -601,7 +607,7 @@ static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd,
}
static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
const struct rkisp1_isp_mbus_info *mbus_info;
@@ -634,37 +640,37 @@ static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd,
}
static int rkisp1_isp_init_config(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
struct v4l2_rect *sink_crop, *src_crop;
- sink_fmt = v4l2_subdev_get_try_format(sd, cfg,
+ sink_fmt = v4l2_subdev_get_try_format(sd, sd_state,
RKISP1_ISP_PAD_SINK_VIDEO);
sink_fmt->width = RKISP1_DEFAULT_WIDTH;
sink_fmt->height = RKISP1_DEFAULT_HEIGHT;
sink_fmt->field = V4L2_FIELD_NONE;
sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT;
- sink_crop = v4l2_subdev_get_try_crop(sd, cfg,
+ sink_crop = v4l2_subdev_get_try_crop(sd, sd_state,
RKISP1_ISP_PAD_SINK_VIDEO);
sink_crop->width = RKISP1_DEFAULT_WIDTH;
sink_crop->height = RKISP1_DEFAULT_HEIGHT;
sink_crop->left = 0;
sink_crop->top = 0;
- src_fmt = v4l2_subdev_get_try_format(sd, cfg,
+ src_fmt = v4l2_subdev_get_try_format(sd, sd_state,
RKISP1_ISP_PAD_SOURCE_VIDEO);
*src_fmt = *sink_fmt;
src_fmt->code = RKISP1_DEF_SRC_PAD_FMT;
- src_crop = v4l2_subdev_get_try_crop(sd, cfg,
+ src_crop = v4l2_subdev_get_try_crop(sd, sd_state,
RKISP1_ISP_PAD_SOURCE_VIDEO);
*src_crop = *sink_crop;
- sink_fmt = v4l2_subdev_get_try_format(sd, cfg,
+ sink_fmt = v4l2_subdev_get_try_format(sd, sd_state,
RKISP1_ISP_PAD_SINK_PARAMS);
- src_fmt = v4l2_subdev_get_try_format(sd, cfg,
+ src_fmt = v4l2_subdev_get_try_format(sd, sd_state,
RKISP1_ISP_PAD_SOURCE_STATS);
sink_fmt->width = 0;
sink_fmt->height = 0;
@@ -676,7 +682,7 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd,
}
static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_mbus_framefmt *format,
unsigned int which)
{
@@ -684,9 +690,9 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
struct v4l2_mbus_framefmt *src_fmt;
const struct v4l2_rect *src_crop;
- src_fmt = rkisp1_isp_get_pad_fmt(isp, cfg,
+ src_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state,
RKISP1_ISP_PAD_SOURCE_VIDEO, which);
- src_crop = rkisp1_isp_get_pad_crop(isp, cfg,
+ src_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
RKISP1_ISP_PAD_SOURCE_VIDEO, which);
src_fmt->code = format->code;
@@ -717,17 +723,17 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
}
static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_rect *r, unsigned int which)
{
struct v4l2_mbus_framefmt *src_fmt;
const struct v4l2_rect *sink_crop;
struct v4l2_rect *src_crop;
- src_crop = rkisp1_isp_get_pad_crop(isp, cfg,
+ src_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
RKISP1_ISP_PAD_SOURCE_VIDEO,
which);
- sink_crop = rkisp1_isp_get_pad_crop(isp, cfg,
+ sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
RKISP1_ISP_PAD_SINK_VIDEO,
which);
@@ -740,21 +746,23 @@ static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp,
*r = *src_crop;
/* Propagate to out format */
- src_fmt = rkisp1_isp_get_pad_fmt(isp, cfg,
+ src_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state,
RKISP1_ISP_PAD_SOURCE_VIDEO, which);
- rkisp1_isp_set_src_fmt(isp, cfg, src_fmt, which);
+ rkisp1_isp_set_src_fmt(isp, sd_state, src_fmt, which);
}
static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_rect *r, unsigned int which)
{
struct v4l2_rect *sink_crop, *src_crop;
struct v4l2_mbus_framefmt *sink_fmt;
- sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO,
+ sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO,
which);
- sink_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO,
+ sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO,
which);
sink_crop->left = ALIGN(r->left, 2);
@@ -766,13 +774,13 @@ static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp,
*r = *sink_crop;
/* Propagate to out crop */
- src_crop = rkisp1_isp_get_pad_crop(isp, cfg,
+ src_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
RKISP1_ISP_PAD_SOURCE_VIDEO, which);
- rkisp1_isp_set_src_crop(isp, cfg, src_crop, which);
+ rkisp1_isp_set_src_crop(isp, sd_state, src_crop, which);
}
static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_mbus_framefmt *format,
unsigned int which)
{
@@ -780,7 +788,8 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp,
struct v4l2_mbus_framefmt *sink_fmt;
struct v4l2_rect *sink_crop;
- sink_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO,
+ sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO,
which);
sink_fmt->code = format->code;
mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
@@ -801,36 +810,40 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp,
*format = *sink_fmt;
/* Propagate to in crop */
- sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO,
+ sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO,
which);
- rkisp1_isp_set_sink_crop(isp, cfg, sink_crop, which);
+ rkisp1_isp_set_sink_crop(isp, sd_state, sink_crop, which);
}
static int rkisp1_isp_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
mutex_lock(&isp->ops_lock);
- fmt->format = *rkisp1_isp_get_pad_fmt(isp, cfg, fmt->pad, fmt->which);
+ fmt->format = *rkisp1_isp_get_pad_fmt(isp, sd_state, fmt->pad,
+ fmt->which);
mutex_unlock(&isp->ops_lock);
return 0;
}
static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
mutex_lock(&isp->ops_lock);
if (fmt->pad == RKISP1_ISP_PAD_SINK_VIDEO)
- rkisp1_isp_set_sink_fmt(isp, cfg, &fmt->format, fmt->which);
+ rkisp1_isp_set_sink_fmt(isp, sd_state, &fmt->format,
+ fmt->which);
else if (fmt->pad == RKISP1_ISP_PAD_SOURCE_VIDEO)
- rkisp1_isp_set_src_fmt(isp, cfg, &fmt->format, fmt->which);
+ rkisp1_isp_set_src_fmt(isp, sd_state, &fmt->format,
+ fmt->which);
else
- fmt->format = *rkisp1_isp_get_pad_fmt(isp, cfg, fmt->pad,
+ fmt->format = *rkisp1_isp_get_pad_fmt(isp, sd_state, fmt->pad,
fmt->which);
mutex_unlock(&isp->ops_lock);
@@ -838,7 +851,7 @@ static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd,
}
static int rkisp1_isp_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
@@ -854,20 +867,20 @@ static int rkisp1_isp_get_selection(struct v4l2_subdev *sd,
if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) {
struct v4l2_mbus_framefmt *fmt;
- fmt = rkisp1_isp_get_pad_fmt(isp, cfg, sel->pad,
+ fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, sel->pad,
sel->which);
sel->r.height = fmt->height;
sel->r.width = fmt->width;
sel->r.left = 0;
sel->r.top = 0;
} else {
- sel->r = *rkisp1_isp_get_pad_crop(isp, cfg,
- RKISP1_ISP_PAD_SINK_VIDEO,
- sel->which);
+ sel->r = *rkisp1_isp_get_pad_crop(isp, sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO,
+ sel->which);
}
break;
case V4L2_SEL_TGT_CROP:
- sel->r = *rkisp1_isp_get_pad_crop(isp, cfg, sel->pad,
+ sel->r = *rkisp1_isp_get_pad_crop(isp, sd_state, sel->pad,
sel->which);
break;
default:
@@ -878,7 +891,7 @@ static int rkisp1_isp_get_selection(struct v4l2_subdev *sd,
}
static int rkisp1_isp_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct rkisp1_device *rkisp1 =
@@ -893,9 +906,9 @@ static int rkisp1_isp_set_selection(struct v4l2_subdev *sd,
sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
mutex_lock(&isp->ops_lock);
if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO)
- rkisp1_isp_set_sink_crop(isp, cfg, &sel->r, sel->which);
+ rkisp1_isp_set_sink_crop(isp, sd_state, &sel->r, sel->which);
else if (sel->pad == RKISP1_ISP_PAD_SOURCE_VIDEO)
- rkisp1_isp_set_src_crop(isp, cfg, &sel->r, sel->which);
+ rkisp1_isp_set_src_crop(isp, sd_state, &sel->r, sel->which);
else
ret = -EINVAL;
@@ -1037,6 +1050,9 @@ static const struct v4l2_subdev_ops rkisp1_isp_ops = {
int rkisp1_isp_register(struct rkisp1_device *rkisp1)
{
+ struct v4l2_subdev_state state = {
+ .pads = rkisp1->isp.pad_cfg
+ };
struct rkisp1_isp *isp = &rkisp1->isp;
struct media_pad *pads = isp->pads;
struct v4l2_subdev *sd = &isp->sd;
@@ -1069,7 +1085,7 @@ int rkisp1_isp_register(struct rkisp1_device *rkisp1)
goto err_cleanup_media_entity;
}
- rkisp1_isp_init_config(sd, rkisp1->isp.pad_cfg);
+ rkisp1_isp_init_config(sd, &state);
return 0;
err_cleanup_media_entity:
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
index b6beddd988d0..529c6e21815f 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
@@ -1258,7 +1258,10 @@ void rkisp1_params_configure(struct rkisp1_params *params,
rkisp1_params_config_parameter(params);
}
-/* Not called when the camera active, thus not isr protection. */
+/*
+ * Not called when the camera is active, therefore there is no need to acquire
+ * a lock.
+ */
void rkisp1_params_disable(struct rkisp1_params *params)
{
rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPCC_MODE,
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
index 79deed8adcea..2070f4b06705 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
@@ -180,24 +180,30 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_sp = {
static struct v4l2_mbus_framefmt *
rkisp1_rsz_get_pad_fmt(struct rkisp1_resizer *rsz,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, u32 which)
{
+ struct v4l2_subdev_state state = {
+ .pads = rsz->pad_cfg
+ };
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&rsz->sd, cfg, pad);
+ return v4l2_subdev_get_try_format(&rsz->sd, sd_state, pad);
else
- return v4l2_subdev_get_try_format(&rsz->sd, rsz->pad_cfg, pad);
+ return v4l2_subdev_get_try_format(&rsz->sd, &state, pad);
}
static struct v4l2_rect *
rkisp1_rsz_get_pad_crop(struct rkisp1_resizer *rsz,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, u32 which)
{
+ struct v4l2_subdev_state state = {
+ .pads = rsz->pad_cfg
+ };
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&rsz->sd, cfg, pad);
+ return v4l2_subdev_get_try_crop(&rsz->sd, sd_state, pad);
else
- return v4l2_subdev_get_try_crop(&rsz->sd, rsz->pad_cfg, pad);
+ return v4l2_subdev_get_try_crop(&rsz->sd, &state, pad);
}
/* ----------------------------------------------------------------------------
@@ -451,12 +457,15 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz,
*/
static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct rkisp1_resizer *rsz =
container_of(sd, struct rkisp1_resizer, sd);
struct v4l2_subdev_pad_config dummy_cfg;
+ struct v4l2_subdev_state pad_state = {
+ .pads = &dummy_cfg
+ };
u32 pad = code->pad;
int ret;
@@ -481,7 +490,7 @@ static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd,
/* supported mbus codes on the sink pad are the same as isp src pad */
code->pad = RKISP1_ISP_PAD_SOURCE_VIDEO;
ret = v4l2_subdev_call(&rsz->rkisp1->isp.sd, pad, enum_mbus_code,
- &dummy_cfg, code);
+ &pad_state, code);
/* restore pad */
code->pad = pad;
@@ -490,24 +499,27 @@ static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd,
}
static int rkisp1_rsz_init_config(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
struct v4l2_rect *sink_crop;
- sink_fmt = v4l2_subdev_get_try_format(sd, cfg, RKISP1_RSZ_PAD_SRC);
+ sink_fmt = v4l2_subdev_get_try_format(sd, sd_state,
+ RKISP1_RSZ_PAD_SRC);
sink_fmt->width = RKISP1_DEFAULT_WIDTH;
sink_fmt->height = RKISP1_DEFAULT_HEIGHT;
sink_fmt->field = V4L2_FIELD_NONE;
sink_fmt->code = RKISP1_DEF_FMT;
- sink_crop = v4l2_subdev_get_try_crop(sd, cfg, RKISP1_RSZ_PAD_SINK);
+ sink_crop = v4l2_subdev_get_try_crop(sd, sd_state,
+ RKISP1_RSZ_PAD_SINK);
sink_crop->width = RKISP1_DEFAULT_WIDTH;
sink_crop->height = RKISP1_DEFAULT_HEIGHT;
sink_crop->left = 0;
sink_crop->top = 0;
- src_fmt = v4l2_subdev_get_try_format(sd, cfg, RKISP1_RSZ_PAD_SINK);
+ src_fmt = v4l2_subdev_get_try_format(sd, sd_state,
+ RKISP1_RSZ_PAD_SINK);
*src_fmt = *sink_fmt;
/* NOTE: there is no crop in the source pad, only in the sink */
@@ -516,15 +528,17 @@ static int rkisp1_rsz_init_config(struct v4l2_subdev *sd,
}
static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_mbus_framefmt *format,
unsigned int which)
{
const struct rkisp1_isp_mbus_info *sink_mbus_info;
struct v4l2_mbus_framefmt *src_fmt, *sink_fmt;
- sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, which);
- src_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SRC, which);
+ sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK,
+ which);
+ src_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SRC,
+ which);
sink_mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
/* for YUV formats, userspace can change the mbus code on the src pad if it is supported */
@@ -543,7 +557,7 @@ static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz,
}
static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_rect *r,
unsigned int which)
{
@@ -551,8 +565,10 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz,
struct v4l2_mbus_framefmt *sink_fmt;
struct v4l2_rect *sink_crop;
- sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, which);
- sink_crop = rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK,
+ sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK,
+ which);
+ sink_crop = rkisp1_rsz_get_pad_crop(rsz, sd_state,
+ RKISP1_RSZ_PAD_SINK,
which);
/* Not crop for MP bayer raw data */
@@ -579,7 +595,7 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz,
}
static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_mbus_framefmt *format,
unsigned int which)
{
@@ -587,9 +603,12 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz,
struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
struct v4l2_rect *sink_crop;
- sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, which);
- src_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SRC, which);
- sink_crop = rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK,
+ sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK,
+ which);
+ src_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SRC,
+ which);
+ sink_crop = rkisp1_rsz_get_pad_crop(rsz, sd_state,
+ RKISP1_RSZ_PAD_SINK,
which);
if (rsz->id == RKISP1_SELFPATH)
sink_fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
@@ -617,24 +636,25 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz,
*format = *sink_fmt;
/* Update sink crop */
- rkisp1_rsz_set_sink_crop(rsz, cfg, sink_crop, which);
+ rkisp1_rsz_set_sink_crop(rsz, sd_state, sink_crop, which);
}
static int rkisp1_rsz_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct rkisp1_resizer *rsz =
container_of(sd, struct rkisp1_resizer, sd);
mutex_lock(&rsz->ops_lock);
- fmt->format = *rkisp1_rsz_get_pad_fmt(rsz, cfg, fmt->pad, fmt->which);
+ fmt->format = *rkisp1_rsz_get_pad_fmt(rsz, sd_state, fmt->pad,
+ fmt->which);
mutex_unlock(&rsz->ops_lock);
return 0;
}
static int rkisp1_rsz_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct rkisp1_resizer *rsz =
@@ -642,16 +662,18 @@ static int rkisp1_rsz_set_fmt(struct v4l2_subdev *sd,
mutex_lock(&rsz->ops_lock);
if (fmt->pad == RKISP1_RSZ_PAD_SINK)
- rkisp1_rsz_set_sink_fmt(rsz, cfg, &fmt->format, fmt->which);
+ rkisp1_rsz_set_sink_fmt(rsz, sd_state, &fmt->format,
+ fmt->which);
else
- rkisp1_rsz_set_src_fmt(rsz, cfg, &fmt->format, fmt->which);
+ rkisp1_rsz_set_src_fmt(rsz, sd_state, &fmt->format,
+ fmt->which);
mutex_unlock(&rsz->ops_lock);
return 0;
}
static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct rkisp1_resizer *rsz =
@@ -665,7 +687,8 @@ static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd,
mutex_lock(&rsz->ops_lock);
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- mf_sink = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK,
+ mf_sink = rkisp1_rsz_get_pad_fmt(rsz, sd_state,
+ RKISP1_RSZ_PAD_SINK,
sel->which);
sel->r.height = mf_sink->height;
sel->r.width = mf_sink->width;
@@ -673,7 +696,8 @@ static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd,
sel->r.top = 0;
break;
case V4L2_SEL_TGT_CROP:
- sel->r = *rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK,
+ sel->r = *rkisp1_rsz_get_pad_crop(rsz, sd_state,
+ RKISP1_RSZ_PAD_SINK,
sel->which);
break;
default:
@@ -685,7 +709,7 @@ static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd,
}
static int rkisp1_rsz_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct rkisp1_resizer *rsz =
@@ -698,7 +722,7 @@ static int rkisp1_rsz_set_selection(struct v4l2_subdev *sd,
sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
mutex_lock(&rsz->ops_lock);
- rkisp1_rsz_set_sink_crop(rsz, cfg, &sel->r, sel->which);
+ rkisp1_rsz_set_sink_crop(rsz, sd_state, &sel->r, sel->which);
mutex_unlock(&rsz->ops_lock);
return 0;
@@ -764,6 +788,9 @@ static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz)
static int rkisp1_rsz_register(struct rkisp1_resizer *rsz)
{
+ struct v4l2_subdev_state state = {
+ .pads = rsz->pad_cfg
+ };
static const char * const dev_names[] = {
RKISP1_RSZ_MP_DEV_NAME,
RKISP1_RSZ_SP_DEV_NAME
@@ -802,7 +829,7 @@ static int rkisp1_rsz_register(struct rkisp1_resizer *rsz)
goto err_cleanup_media_entity;
}
- rkisp1_rsz_init_config(sd, rsz->pad_cfg);
+ rkisp1_rsz_init_config(sd, &state);
return 0;
err_cleanup_media_entity:
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index 9ca49af29542..140854ab4dd8 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -547,7 +547,7 @@ static int s3c_camif_open(struct file *file)
if (ret < 0)
goto unlock;
- ret = pm_runtime_get_sync(camif->dev);
+ ret = pm_runtime_resume_and_get(camif->dev);
if (ret < 0)
goto err_pm;
@@ -1199,7 +1199,7 @@ static const u32 camif_mbus_formats[] = {
*/
static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(camif_mbus_formats))
@@ -1210,14 +1210,14 @@ static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd,
}
static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct camif_dev *camif = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf = &fmt->format;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
fmt->format = *mf;
return 0;
}
@@ -1278,7 +1278,7 @@ static void __camif_subdev_try_format(struct camif_dev *camif,
}
static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct camif_dev *camif = v4l2_get_subdevdata(sd);
@@ -1306,7 +1306,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
__camif_subdev_try_format(camif, mf, fmt->pad);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
*mf = fmt->format;
mutex_unlock(&camif->lock);
return 0;
@@ -1345,7 +1345,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
}
static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct camif_dev *camif = v4l2_get_subdevdata(sd);
@@ -1358,7 +1358,7 @@ static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+ sel->r = *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
return 0;
}
@@ -1432,7 +1432,7 @@ static void __camif_try_crop(struct camif_dev *camif, struct v4l2_rect *r)
}
static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct camif_dev *camif = v4l2_get_subdevdata(sd);
@@ -1446,7 +1446,7 @@ static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd,
__camif_try_crop(camif, &sel->r);
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_crop(sd, cfg, sel->pad) = sel->r;
+ *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad) = sel->r;
} else {
unsigned long flags;
unsigned int i;
diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c
index 4c3c00d59c92..e1d51fd3e700 100644
--- a/drivers/media/platform/s3c-camif/camif-core.c
+++ b/drivers/media/platform/s3c-camif/camif-core.c
@@ -460,9 +460,9 @@ static int s3c_camif_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
- goto err_pm;
+ goto err_disable;
ret = camif_media_dev_init(camif);
if (ret < 0)
@@ -502,6 +502,7 @@ err_sens:
camif_unregister_media_entities(camif);
err_pm:
pm_runtime_put(dev);
+err_disable:
pm_runtime_disable(dev);
camif_clk_put(camif);
err_clk:
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c
index 15bcb7f6e113..1cb5eaabf340 100644
--- a/drivers/media/platform/s5p-g2d/g2d.c
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -276,6 +276,9 @@ static int g2d_release(struct file *file)
struct g2d_dev *dev = video_drvdata(file);
struct g2d_ctx *ctx = fh2ctx(file->private_data);
+ mutex_lock(&dev->mutex);
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+ mutex_unlock(&dev->mutex);
v4l2_ctrl_handler_free(&ctx->ctrl_handler);
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 026111505f5a..d402e456f27d 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -2566,11 +2566,8 @@ static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
- int ret;
-
- ret = pm_runtime_get_sync(ctx->jpeg->dev);
- return ret > 0 ? 0 : ret;
+ return pm_runtime_resume_and_get(ctx->jpeg->dev);
}
static void s5p_jpeg_stop_streaming(struct vb2_queue *q)
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index a92a9ca6e87e..c1d3bda8385b 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -172,6 +172,7 @@ static struct mfc_control controls[] = {
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 16383,
+ .step = 1,
.default_value = 0,
},
{
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
index 62d2320a7218..88b7d33c9197 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
@@ -78,11 +78,9 @@ int s5p_mfc_power_on(void)
{
int i, ret = 0;
- ret = pm_runtime_get_sync(pm->device);
- if (ret < 0) {
- pm_runtime_put_noidle(pm->device);
+ ret = pm_runtime_resume_and_get(pm->device);
+ if (ret < 0)
return ret;
- }
/* clock control */
for (i = 0; i < pm->num_clocks; i++) {
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c
index 4ac48441f22c..ca4310e26c49 100644
--- a/drivers/media/platform/sh_vou.c
+++ b/drivers/media/platform/sh_vou.c
@@ -1133,7 +1133,11 @@ static int sh_vou_open(struct file *file)
if (v4l2_fh_is_singular_file(file) &&
vou_dev->status == SH_VOU_INITIALISING) {
/* First open */
- pm_runtime_get_sync(vou_dev->v4l2_dev.dev);
+ err = pm_runtime_resume_and_get(vou_dev->v4l2_dev.dev);
+ if (err < 0) {
+ v4l2_fh_release(file);
+ goto done_open;
+ }
err = sh_vou_hw_init(vou_dev);
if (err < 0) {
pm_runtime_put(vou_dev->v4l2_dev.dev);
diff --git a/drivers/media/platform/sti/bdisp/Makefile b/drivers/media/platform/sti/bdisp/Makefile
index caf7ccd193ea..39ade0a34723 100644
--- a/drivers/media/platform/sti/bdisp/Makefile
+++ b/drivers/media/platform/sti/bdisp/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_VIDEO_STI_BDISP) := bdisp.o
+obj-$(CONFIG_VIDEO_STI_BDISP) += bdisp.o
bdisp-objs := bdisp-v4l2.o bdisp-hw.o bdisp-debug.o
diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
index 060ca85f64d5..6413cd279125 100644
--- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
+++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
@@ -499,7 +499,7 @@ static int bdisp_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct bdisp_ctx *ctx = q->drv_priv;
struct vb2_v4l2_buffer *buf;
- int ret = pm_runtime_get_sync(ctx->bdisp_dev->dev);
+ int ret = pm_runtime_resume_and_get(ctx->bdisp_dev->dev);
if (ret < 0) {
dev_err(ctx->bdisp_dev->dev, "failed to set runtime PM\n");
@@ -1318,7 +1318,6 @@ static int bdisp_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
bdisp->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(bdisp->regs)) {
- dev_err(dev, "failed to get regs\n");
ret = PTR_ERR(bdisp->regs);
goto err_wq;
}
@@ -1364,10 +1363,10 @@ static int bdisp_probe(struct platform_device *pdev)
/* Power management */
pm_runtime_enable(dev);
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0) {
dev_err(dev, "failed to set PM\n");
- goto err_pm;
+ goto err_remove;
}
/* Filters */
@@ -1395,6 +1394,7 @@ err_filter:
bdisp_hw_free_filters(bdisp->dev);
err_pm:
pm_runtime_put(dev);
+err_remove:
bdisp_debugfs_remove(bdisp);
v4l2_device_unregister(&bdisp->v4l2_dev);
err_clk:
diff --git a/drivers/media/platform/sti/delta/Makefile b/drivers/media/platform/sti/delta/Makefile
index 92b37e216f00..32412fa4c632 100644
--- a/drivers/media/platform/sti/delta/Makefile
+++ b/drivers/media/platform/sti/delta/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_VIDEO_STI_DELTA_DRIVER) := st-delta.o
+obj-$(CONFIG_VIDEO_STI_DELTA_DRIVER) += st-delta.o
st-delta-y := delta-v4l2.o delta-mem.o delta-ipc.o delta-debug.o
# MJPEG support
diff --git a/drivers/media/platform/sti/delta/delta-v4l2.c b/drivers/media/platform/sti/delta/delta-v4l2.c
index c691b3d81549..c887a31ebb54 100644
--- a/drivers/media/platform/sti/delta/delta-v4l2.c
+++ b/drivers/media/platform/sti/delta/delta-v4l2.c
@@ -954,10 +954,8 @@ static void delta_run_work(struct work_struct *work)
/* enable the hardware */
if (!dec->pm) {
ret = delta_get_sync(ctx);
- if (ret) {
- delta_put_autosuspend(ctx);
+ if (ret)
goto err;
- }
}
/* decode this access unit */
@@ -1009,7 +1007,6 @@ static void delta_run_work(struct work_struct *work)
dev_err(delta->dev,
"%s NULL decoded frame\n",
ctx->name);
- ret = -EIO;
goto out;
}
@@ -1277,9 +1274,9 @@ int delta_get_sync(struct delta_ctx *ctx)
int ret = 0;
/* enable the hardware */
- ret = pm_runtime_get_sync(delta->dev);
+ ret = pm_runtime_resume_and_get(delta->dev);
if (ret < 0) {
- dev_err(delta->dev, "%s pm_runtime_get_sync failed (%d)\n",
+ dev_err(delta->dev, "%s pm_runtime_resume_and_get failed (%d)\n",
__func__, ret);
return ret;
}
diff --git a/drivers/media/platform/sti/hva/Makefile b/drivers/media/platform/sti/hva/Makefile
index 74b41ec52f97..b5a5478bdd01 100644
--- a/drivers/media/platform/sti/hva/Makefile
+++ b/drivers/media/platform/sti/hva/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_VIDEO_STI_HVA) := st-hva.o
+obj-$(CONFIG_VIDEO_STI_HVA) += st-hva.o
st-hva-y := hva-v4l2.o hva-hw.o hva-mem.o hva-h264.o
st-hva-$(CONFIG_VIDEO_STI_HVA_DEBUGFS) += hva-debugfs.o
diff --git a/drivers/media/platform/sti/hva/hva-hw.c b/drivers/media/platform/sti/hva/hva-hw.c
index f59811e27f51..30fb1aa4a351 100644
--- a/drivers/media/platform/sti/hva/hva-hw.c
+++ b/drivers/media/platform/sti/hva/hva-hw.c
@@ -130,8 +130,7 @@ static irqreturn_t hva_hw_its_irq_thread(int irq, void *arg)
ctx_id = (hva->sts_reg & 0xFF00) >> 8;
if (ctx_id >= HVA_MAX_INSTANCES) {
dev_err(dev, "%s %s: bad context identifier: %d\n",
- ctx->name, __func__, ctx_id);
- ctx->hw_err = true;
+ HVA_PREFIX, __func__, ctx_id);
goto out;
}
@@ -270,9 +269,8 @@ static unsigned long int hva_hw_get_ip_version(struct hva_dev *hva)
struct device *dev = hva_to_dev(hva);
unsigned long int version;
- if (pm_runtime_get_sync(dev) < 0) {
+ if (pm_runtime_resume_and_get(dev) < 0) {
dev_err(dev, "%s failed to get pm_runtime\n", HVA_PREFIX);
- pm_runtime_put_noidle(dev);
mutex_unlock(&hva->protect_mutex);
return -EFAULT;
}
@@ -386,10 +384,10 @@ int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva)
pm_runtime_set_suspended(dev);
pm_runtime_enable(dev);
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0) {
dev_err(dev, "%s failed to set PM\n", HVA_PREFIX);
- goto err_pm;
+ goto err_clk;
}
/* check IP hardware version */
@@ -462,6 +460,7 @@ int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd,
u8 client_id = ctx->id;
int ret;
u32 reg = 0;
+ bool got_pm = false;
mutex_lock(&hva->protect_mutex);
@@ -469,12 +468,13 @@ int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd,
enable_irq(hva->irq_its);
enable_irq(hva->irq_err);
- if (pm_runtime_get_sync(dev) < 0) {
+ if (pm_runtime_resume_and_get(dev) < 0) {
dev_err(dev, "%s failed to get pm_runtime\n", ctx->name);
ctx->sys_errors++;
ret = -EFAULT;
goto out;
}
+ got_pm = true;
reg = readl_relaxed(hva->regs + HVA_HIF_REG_CLK_GATING);
switch (cmd) {
@@ -537,7 +537,8 @@ out:
dev_dbg(dev, "%s unknown command 0x%x\n", ctx->name, cmd);
}
- pm_runtime_put_autosuspend(dev);
+ if (got_pm)
+ pm_runtime_put_autosuspend(dev);
mutex_unlock(&hva->protect_mutex);
return ret;
@@ -553,9 +554,8 @@ void hva_hw_dump_regs(struct hva_dev *hva, struct seq_file *s)
mutex_lock(&hva->protect_mutex);
- if (pm_runtime_get_sync(dev) < 0) {
+ if (pm_runtime_resume_and_get(dev) < 0) {
seq_puts(s, "Cannot wake up IP\n");
- pm_runtime_put_noidle(dev);
mutex_unlock(&hva->protect_mutex);
return;
}
diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
index d9b4ad0abf0c..d914ccef9831 100644
--- a/drivers/media/platform/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/stm32/stm32-dcmi.c
@@ -600,7 +600,7 @@ static struct media_entity *dcmi_find_source(struct stm32_dcmi *dcmi)
}
static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi,
- struct v4l2_subdev_pad_config *pad_cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct media_entity *entity = &dcmi->source->entity;
@@ -642,7 +642,7 @@ static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi,
format->format.width, format->format.height);
fmt.pad = pad->index;
- ret = v4l2_subdev_call(subdev, pad, set_fmt, pad_cfg, &fmt);
+ ret = v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &fmt);
if (ret < 0) {
dev_err(dcmi->dev, "%s: Failed to set format 0x%x %ux%u on \"%s\":%d pad (%d)\n",
__func__, format->format.code,
@@ -723,11 +723,11 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
u32 val = 0;
int ret;
- ret = pm_runtime_get_sync(dcmi->dev);
+ ret = pm_runtime_resume_and_get(dcmi->dev);
if (ret < 0) {
dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync (%d)\n",
__func__, ret);
- goto err_pm_put;
+ goto err_unlocked;
}
ret = media_pipeline_start(&dcmi->vdev->entity, &dcmi->pipeline);
@@ -848,6 +848,7 @@ err_media_pipeline_stop:
err_pm_put:
pm_runtime_put(dcmi->dev);
+err_unlocked:
spin_lock_irq(&dcmi->irqlock);
/*
* Return all buffers to vb2 in QUEUED state.
@@ -977,6 +978,9 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f,
struct dcmi_framesize sd_fsize;
struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = {
+ .pads = &pad_cfg
+ };
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -1012,7 +1016,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f,
v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code);
ret = v4l2_subdev_call(dcmi->source, pad, set_fmt,
- &pad_cfg, &format);
+ &pad_state, &format);
if (ret < 0)
return ret;
@@ -1162,6 +1166,9 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi,
.which = V4L2_SUBDEV_FORMAT_TRY,
};
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = {
+ .pads = &pad_cfg
+ };
int ret;
sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat);
@@ -1175,7 +1182,7 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi,
v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code);
ret = v4l2_subdev_call(dcmi->source, pad, set_fmt,
- &pad_cfg, &format);
+ &pad_state, &format);
if (ret < 0)
return ret;
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c
index 4785faddf630..3872027ed2fa 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c
@@ -206,9 +206,9 @@ static int sun4i_csi_open(struct file *file)
if (ret)
return ret;
- ret = pm_runtime_get_sync(csi->dev);
+ ret = pm_runtime_resume_and_get(csi->dev);
if (ret < 0)
- goto err_pm_put;
+ goto err_unlock;
ret = v4l2_pipeline_pm_get(&csi->vdev.entity);
if (ret)
@@ -227,6 +227,8 @@ err_pipeline_pm_put:
err_pm_put:
pm_runtime_put(csi->dev);
+
+err_unlock:
mutex_unlock(&csi->lock);
return ret;
@@ -269,25 +271,26 @@ static const struct v4l2_mbus_framefmt sun4i_csi_pad_fmt_default = {
};
static int sun4i_csi_subdev_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(subdev, cfg, CSI_SUBDEV_SINK);
+ fmt = v4l2_subdev_get_try_format(subdev, sd_state, CSI_SUBDEV_SINK);
*fmt = sun4i_csi_pad_fmt_default;
return 0;
}
static int sun4i_csi_subdev_get_fmt(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct sun4i_csi *csi = container_of(subdev, struct sun4i_csi, subdev);
struct v4l2_mbus_framefmt *subdev_fmt;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- subdev_fmt = v4l2_subdev_get_try_format(subdev, cfg, fmt->pad);
+ subdev_fmt = v4l2_subdev_get_try_format(subdev, sd_state,
+ fmt->pad);
else
subdev_fmt = &csi->subdev_fmt;
@@ -297,14 +300,15 @@ static int sun4i_csi_subdev_get_fmt(struct v4l2_subdev *subdev,
}
static int sun4i_csi_subdev_set_fmt(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct sun4i_csi *csi = container_of(subdev, struct sun4i_csi, subdev);
struct v4l2_mbus_framefmt *subdev_fmt;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- subdev_fmt = v4l2_subdev_get_try_format(subdev, cfg, fmt->pad);
+ subdev_fmt = v4l2_subdev_get_try_format(subdev, sd_state,
+ fmt->pad);
else
subdev_fmt = &csi->subdev_fmt;
@@ -323,7 +327,7 @@ static int sun4i_csi_subdev_set_fmt(struct v4l2_subdev *subdev,
static int
sun4i_csi_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *mbus)
{
if (mbus->index >= ARRAY_SIZE(sun4i_csi_formats))
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
index 3181d0781b61..07b2161392d2 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
@@ -481,8 +481,10 @@ static int sun6i_video_open(struct file *file)
goto fh_release;
/* check if already powered */
- if (!v4l2_fh_is_singular_file(file))
+ if (!v4l2_fh_is_singular_file(file)) {
+ ret = -EBUSY;
goto unlock;
+ }
ret = sun6i_csi_set_power(video->csi, true);
if (ret < 0)
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
index 3f81dd17755c..fbcca59a0517 100644
--- a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
+++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
@@ -494,7 +494,7 @@ static int rotate_start_streaming(struct vb2_queue *vq, unsigned int count)
struct device *dev = ctx->dev->dev;
int ret;
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0) {
dev_err(dev, "Failed to enable module\n");
diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c
index cbe6114908de..124a4e2bdefe 100644
--- a/drivers/media/platform/ti-vpe/cal-camerarx.c
+++ b/drivers/media/platform/ti-vpe/cal-camerarx.c
@@ -586,12 +586,12 @@ static inline struct cal_camerarx *to_cal_camerarx(struct v4l2_subdev *sd)
static struct v4l2_mbus_framefmt *
cal_camerarx_get_pad_format(struct cal_camerarx *phy,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, u32 which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&phy->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&phy->subdev, sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &phy->formats[pad];
default:
@@ -611,7 +611,7 @@ static int cal_camerarx_sd_s_stream(struct v4l2_subdev *sd, int enable)
}
static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct cal_camerarx *phy = to_cal_camerarx(sd);
@@ -623,7 +623,7 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index > 0)
return -EINVAL;
- fmt = cal_camerarx_get_pad_format(phy, cfg,
+ fmt = cal_camerarx_get_pad_format(phy, sd_state,
CAL_CAMERARX_PAD_SINK,
code->which);
code->code = fmt->code;
@@ -639,7 +639,7 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
}
static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct cal_camerarx *phy = to_cal_camerarx(sd);
@@ -652,7 +652,7 @@ static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd,
if (fse->pad == CAL_CAMERARX_PAD_SOURCE) {
struct v4l2_mbus_framefmt *fmt;
- fmt = cal_camerarx_get_pad_format(phy, cfg,
+ fmt = cal_camerarx_get_pad_format(phy, sd_state,
CAL_CAMERARX_PAD_SINK,
fse->which);
if (fse->code != fmt->code)
@@ -679,20 +679,21 @@ static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd,
}
static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct cal_camerarx *phy = to_cal_camerarx(sd);
struct v4l2_mbus_framefmt *fmt;
- fmt = cal_camerarx_get_pad_format(phy, cfg, format->pad, format->which);
+ fmt = cal_camerarx_get_pad_format(phy, sd_state, format->pad,
+ format->which);
format->format = *fmt;
return 0;
}
static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct cal_camerarx *phy = to_cal_camerarx(sd);
@@ -702,7 +703,7 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
/* No transcoding, source and sink formats must match. */
if (format->pad == CAL_CAMERARX_PAD_SOURCE)
- return cal_camerarx_sd_get_fmt(sd, cfg, format);
+ return cal_camerarx_sd_get_fmt(sd, sd_state, format);
/*
* Default to the first format is the requested media bus code isn't
@@ -727,11 +728,13 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
format->format.code = fmtinfo->code;
/* Store the format and propagate it to the source pad. */
- fmt = cal_camerarx_get_pad_format(phy, cfg, CAL_CAMERARX_PAD_SINK,
+ fmt = cal_camerarx_get_pad_format(phy, sd_state,
+ CAL_CAMERARX_PAD_SINK,
format->which);
*fmt = format->format;
- fmt = cal_camerarx_get_pad_format(phy, cfg, CAL_CAMERARX_PAD_SOURCE,
+ fmt = cal_camerarx_get_pad_format(phy, sd_state,
+ CAL_CAMERARX_PAD_SOURCE,
format->which);
*fmt = format->format;
@@ -742,11 +745,11 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
}
static int cal_camerarx_sd_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format format = {
- .which = cfg ? V4L2_SUBDEV_FORMAT_TRY
- : V4L2_SUBDEV_FORMAT_ACTIVE,
+ .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
+ : V4L2_SUBDEV_FORMAT_ACTIVE,
.pad = CAL_CAMERARX_PAD_SINK,
.format = {
.width = 640,
@@ -760,7 +763,7 @@ static int cal_camerarx_sd_init_cfg(struct v4l2_subdev *sd,
},
};
- return cal_camerarx_sd_set_fmt(sd, cfg, &format);
+ return cal_camerarx_sd_set_fmt(sd, sd_state, &format);
}
static const struct v4l2_subdev_video_ops cal_camerarx_video_ops = {
diff --git a/drivers/media/platform/ti-vpe/cal-video.c b/drivers/media/platform/ti-vpe/cal-video.c
index 7b7436a355ee..15fb5360cf13 100644
--- a/drivers/media/platform/ti-vpe/cal-video.c
+++ b/drivers/media/platform/ti-vpe/cal-video.c
@@ -700,7 +700,9 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
- pm_runtime_get_sync(ctx->cal->dev);
+ ret = pm_runtime_resume_and_get(ctx->cal->dev);
+ if (ret < 0)
+ goto error_pipeline;
cal_ctx_set_dma_addr(ctx, addr);
cal_ctx_start(ctx);
diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c
index 2e2bef91b2b0..76fe7a8b33f6 100644
--- a/drivers/media/platform/ti-vpe/cal.c
+++ b/drivers/media/platform/ti-vpe/cal.c
@@ -1024,7 +1024,7 @@ static int cal_probe(struct platform_device *pdev)
/* Read the revision and hardware info to verify hardware access. */
pm_runtime_enable(&pdev->dev);
- ret = pm_runtime_get_sync(&pdev->dev);
+ ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret)
goto error_pm_runtime;
@@ -1098,10 +1098,11 @@ static int cal_remove(struct platform_device *pdev)
{
struct cal_dev *cal = platform_get_drvdata(pdev);
unsigned int i;
+ int ret;
cal_dbg(1, cal, "Removing %s\n", CAL_MODULE_NAME);
- pm_runtime_get_sync(&pdev->dev);
+ ret = pm_runtime_resume_and_get(&pdev->dev);
cal_media_unregister(cal);
@@ -1115,7 +1116,8 @@ static int cal_remove(struct platform_device *pdev)
for (i = 0; i < cal->data->num_csi2_phy; i++)
cal_camerarx_destroy(cal->phy[i]);
- pm_runtime_put_sync(&pdev->dev);
+ if (ret >= 0)
+ pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c
index 10251b787674..5b1c5d96a407 100644
--- a/drivers/media/platform/ti-vpe/vpe.c
+++ b/drivers/media/platform/ti-vpe/vpe.c
@@ -2471,11 +2471,9 @@ static int vpe_runtime_get(struct platform_device *pdev)
dev_dbg(&pdev->dev, "vpe_runtime_get\n");
- r = pm_runtime_get_sync(&pdev->dev);
+ r = pm_runtime_resume_and_get(&pdev->dev);
WARN_ON(r < 0);
- if (r)
- pm_runtime_put_noidle(&pdev->dev);
- return r < 0 ? r : 0;
+ return r;
}
static void vpe_runtime_put(struct platform_device *pdev)
@@ -2580,7 +2578,7 @@ static int vpe_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
ret = vpe_runtime_get(pdev);
- if (ret)
+ if (ret < 0)
goto rel_m2m;
/* Perform clk enable followed by reset */
diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c
index ed0ad68c5c48..3655573e8581 100644
--- a/drivers/media/platform/via-camera.c
+++ b/drivers/media/platform/via-camera.c
@@ -844,6 +844,9 @@ static int viacam_do_try_fmt(struct via_camera *cam,
{
int ret;
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = {
+ .pads = &pad_cfg
+ };
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -852,7 +855,7 @@ static int viacam_do_try_fmt(struct via_camera *cam,
upix->pixelformat = f->pixelformat;
viacam_fmt_pre(upix, spix);
v4l2_fill_mbus_format(&format.format, spix, f->mbus_code);
- ret = sensor_call(cam, pad, set_fmt, &pad_cfg, &format);
+ ret = sensor_call(cam, pad, set_fmt, &pad_state, &format);
v4l2_fill_pix_format(spix, &format.format);
viacam_fmt_post(upix, spix);
return ret;
diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c
index 133122e38515..905005e271ca 100644
--- a/drivers/media/platform/video-mux.c
+++ b/drivers/media/platform/video-mux.c
@@ -140,14 +140,14 @@ static const struct v4l2_subdev_video_ops video_mux_subdev_video_ops = {
static struct v4l2_mbus_framefmt *
__video_mux_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, u32 which)
{
struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(sd, cfg, pad);
+ return v4l2_subdev_get_try_format(sd, sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &vmux->format_mbus[pad];
default:
@@ -156,14 +156,15 @@ __video_mux_get_pad_format(struct v4l2_subdev *sd,
}
static int video_mux_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
mutex_lock(&vmux->lock);
- sdformat->format = *__video_mux_get_pad_format(sd, cfg, sdformat->pad,
+ sdformat->format = *__video_mux_get_pad_format(sd, sd_state,
+ sdformat->pad,
sdformat->which);
mutex_unlock(&vmux->lock);
@@ -172,7 +173,7 @@ static int video_mux_get_format(struct v4l2_subdev *sd,
}
static int video_mux_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
@@ -180,12 +181,13 @@ static int video_mux_set_format(struct v4l2_subdev *sd,
struct media_pad *pad = &vmux->pads[sdformat->pad];
u16 source_pad = sd->entity.num_pads - 1;
- mbusformat = __video_mux_get_pad_format(sd, cfg, sdformat->pad,
- sdformat->which);
+ mbusformat = __video_mux_get_pad_format(sd, sd_state, sdformat->pad,
+ sdformat->which);
if (!mbusformat)
return -EINVAL;
- source_mbusformat = __video_mux_get_pad_format(sd, cfg, source_pad,
+ source_mbusformat = __video_mux_get_pad_format(sd, sd_state,
+ source_pad,
sdformat->which);
if (!source_mbusformat)
return -EINVAL;
@@ -310,7 +312,7 @@ static int video_mux_set_format(struct v4l2_subdev *sd,
}
static int video_mux_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
struct v4l2_mbus_framefmt *mbusformat;
@@ -319,7 +321,7 @@ static int video_mux_init_cfg(struct v4l2_subdev *sd,
mutex_lock(&vmux->lock);
for (i = 0; i < sd->entity.num_pads; i++) {
- mbusformat = v4l2_subdev_get_try_format(sd, cfg, i);
+ mbusformat = v4l2_subdev_get_try_format(sd, sd_state, i);
*mbusformat = video_mux_format_mbus_default;
}
@@ -362,7 +364,7 @@ static int video_mux_async_register(struct video_mux *vmux,
for (i = 0; i < num_input_pads; i++) {
struct v4l2_async_subdev *asd;
- struct fwnode_handle *ep;
+ struct fwnode_handle *ep, *remote_ep;
ep = fwnode_graph_get_endpoint_by_id(
dev_fwnode(vmux->subdev.dev), i, 0,
@@ -370,6 +372,14 @@ static int video_mux_async_register(struct video_mux *vmux,
if (!ep)
continue;
+ /* Skip dangling endpoints for backwards compatibility */
+ remote_ep = fwnode_graph_get_remote_endpoint(ep);
+ if (!remote_ep) {
+ fwnode_handle_put(ep);
+ continue;
+ }
+ fwnode_handle_put(remote_ep);
+
asd = v4l2_async_notifier_add_fwnode_remote_subdev(
&vmux->notifier, ep, struct v4l2_async_subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_brx.c b/drivers/media/platform/vsp1/vsp1_brx.c
index 2d86c718a5cf..89385b4cabe5 100644
--- a/drivers/media/platform/vsp1/vsp1_brx.c
+++ b/drivers/media/platform/vsp1/vsp1_brx.c
@@ -65,7 +65,7 @@ static const struct v4l2_ctrl_ops brx_ctrl_ops = {
*/
static int brx_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
@@ -73,12 +73,12 @@ static int brx_enum_mbus_code(struct v4l2_subdev *subdev,
MEDIA_BUS_FMT_AYUV8_1X32,
};
- return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
+ return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, codes,
ARRAY_SIZE(codes));
}
static int brx_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index)
@@ -97,14 +97,14 @@ static int brx_enum_frame_size(struct v4l2_subdev *subdev,
}
static struct v4l2_rect *brx_get_compose(struct vsp1_brx *brx,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad)
{
- return v4l2_subdev_get_try_compose(&brx->entity.subdev, cfg, pad);
+ return v4l2_subdev_get_try_compose(&brx->entity.subdev, sd_state, pad);
}
static void brx_try_format(struct vsp1_brx *brx,
- struct v4l2_subdev_pad_config *config,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, struct v4l2_mbus_framefmt *fmt)
{
struct v4l2_mbus_framefmt *format;
@@ -119,7 +119,7 @@ static void brx_try_format(struct vsp1_brx *brx,
default:
/* The BRx can't perform format conversion. */
- format = vsp1_entity_get_pad_format(&brx->entity, config,
+ format = vsp1_entity_get_pad_format(&brx->entity, sd_state,
BRX_PAD_SINK(0));
fmt->code = format->code;
break;
@@ -132,17 +132,18 @@ static void brx_try_format(struct vsp1_brx *brx,
}
static int brx_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vsp1_brx *brx = to_brx(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
int ret = 0;
mutex_lock(&brx->entity.lock);
- config = vsp1_entity_get_pad_config(&brx->entity, cfg, fmt->which);
+ config = vsp1_entity_get_pad_config(&brx->entity, sd_state,
+ fmt->which);
if (!config) {
ret = -EINVAL;
goto done;
@@ -181,11 +182,11 @@ done:
}
static int brx_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct vsp1_brx *brx = to_brx(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
if (sel->pad == brx->entity.source_pad)
return -EINVAL;
@@ -199,7 +200,7 @@ static int brx_get_selection(struct v4l2_subdev *subdev,
return 0;
case V4L2_SEL_TGT_COMPOSE:
- config = vsp1_entity_get_pad_config(&brx->entity, cfg,
+ config = vsp1_entity_get_pad_config(&brx->entity, sd_state,
sel->which);
if (!config)
return -EINVAL;
@@ -215,11 +216,11 @@ static int brx_get_selection(struct v4l2_subdev *subdev,
}
static int brx_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct vsp1_brx *brx = to_brx(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *compose;
int ret = 0;
@@ -232,7 +233,8 @@ static int brx_set_selection(struct v4l2_subdev *subdev,
mutex_lock(&brx->entity.lock);
- config = vsp1_entity_get_pad_config(&brx->entity, cfg, sel->which);
+ config = vsp1_entity_get_pad_config(&brx->entity, sd_state,
+ sel->which);
if (!config) {
ret = -EINVAL;
goto done;
diff --git a/drivers/media/platform/vsp1/vsp1_clu.c b/drivers/media/platform/vsp1/vsp1_clu.c
index a47b23bf5abf..c5217fee24f1 100644
--- a/drivers/media/platform/vsp1/vsp1_clu.c
+++ b/drivers/media/platform/vsp1/vsp1_clu.c
@@ -123,27 +123,28 @@ static const unsigned int clu_codes[] = {
};
static int clu_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- return vsp1_subdev_enum_mbus_code(subdev, cfg, code, clu_codes,
+ return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, clu_codes,
ARRAY_SIZE(clu_codes));
}
static int clu_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
- return vsp1_subdev_enum_frame_size(subdev, cfg, fse, CLU_MIN_SIZE,
+ return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
+ CLU_MIN_SIZE,
CLU_MIN_SIZE, CLU_MAX_SIZE,
CLU_MAX_SIZE);
}
static int clu_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
- return vsp1_subdev_set_pad_format(subdev, cfg, fmt, clu_codes,
+ return vsp1_subdev_set_pad_format(subdev, sd_state, fmt, clu_codes,
ARRAY_SIZE(clu_codes),
CLU_MIN_SIZE, CLU_MIN_SIZE,
CLU_MAX_SIZE, CLU_MAX_SIZE);
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index aa66e4f5f3f3..de442d6c9926 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -559,15 +559,7 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
*/
int vsp1_device_get(struct vsp1_device *vsp1)
{
- int ret;
-
- ret = pm_runtime_get_sync(vsp1->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(vsp1->dev);
- return ret;
- }
-
- return 0;
+ return pm_runtime_resume_and_get(vsp1->dev);
}
/*
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index aa9d2286056e..6f51e5c75543 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -103,7 +103,7 @@ void vsp1_entity_configure_partition(struct vsp1_entity *entity,
/**
* vsp1_entity_get_pad_config - Get the pad configuration for an entity
* @entity: the entity
- * @cfg: the TRY pad configuration
+ * @sd_state: the TRY state
* @which: configuration selector (ACTIVE or TRY)
*
* When called with which set to V4L2_SUBDEV_FORMAT_ACTIVE the caller must hold
@@ -114,9 +114,9 @@ void vsp1_entity_configure_partition(struct vsp1_entity *entity,
* and simply returned when requested. The ACTIVE configuration comes from the
* entity structure.
*/
-struct v4l2_subdev_pad_config *
+struct v4l2_subdev_state *
vsp1_entity_get_pad_config(struct vsp1_entity *entity,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
switch (which) {
@@ -124,14 +124,14 @@ vsp1_entity_get_pad_config(struct vsp1_entity *entity,
return entity->config;
case V4L2_SUBDEV_FORMAT_TRY:
default:
- return cfg;
+ return sd_state;
}
}
/**
* vsp1_entity_get_pad_format - Get a pad format from storage for an entity
* @entity: the entity
- * @cfg: the configuration storage
+ * @sd_state: the state storage
* @pad: the pad number
*
* Return the format stored in the given configuration for an entity's pad. The
@@ -139,16 +139,16 @@ vsp1_entity_get_pad_config(struct vsp1_entity *entity,
*/
struct v4l2_mbus_framefmt *
vsp1_entity_get_pad_format(struct vsp1_entity *entity,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad)
{
- return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&entity->subdev, sd_state, pad);
}
/**
* vsp1_entity_get_pad_selection - Get a pad selection from storage for entity
* @entity: the entity
- * @cfg: the configuration storage
+ * @sd_state: the state storage
* @pad: the pad number
* @target: the selection target
*
@@ -158,14 +158,16 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
*/
struct v4l2_rect *
vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, unsigned int target)
{
switch (target) {
case V4L2_SEL_TGT_COMPOSE:
- return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad);
+ return v4l2_subdev_get_try_compose(&entity->subdev, sd_state,
+ pad);
case V4L2_SEL_TGT_CROP:
- return v4l2_subdev_get_try_crop(&entity->subdev, cfg, pad);
+ return v4l2_subdev_get_try_crop(&entity->subdev, sd_state,
+ pad);
default:
return NULL;
}
@@ -180,7 +182,7 @@ vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
* function can be used as a handler for the subdev pad::init_cfg operation.
*/
int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format format;
unsigned int pad;
@@ -189,10 +191,10 @@ int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
memset(&format, 0, sizeof(format));
format.pad = pad;
- format.which = cfg ? V4L2_SUBDEV_FORMAT_TRY
+ format.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
: V4L2_SUBDEV_FORMAT_ACTIVE;
- v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format);
+ v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &format);
}
return 0;
@@ -208,13 +210,13 @@ int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
* a direct drop-in for the operation handler.
*/
int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vsp1_entity *entity = to_vsp1_entity(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
- config = vsp1_entity_get_pad_config(entity, cfg, fmt->which);
+ config = vsp1_entity_get_pad_config(entity, sd_state, fmt->which);
if (!config)
return -EINVAL;
@@ -239,7 +241,7 @@ int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
* the sink pad.
*/
int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code,
const unsigned int *codes, unsigned int ncodes)
{
@@ -251,7 +253,7 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
code->code = codes[code->index];
} else {
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
/*
@@ -261,7 +263,8 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
if (code->index)
return -EINVAL;
- config = vsp1_entity_get_pad_config(entity, cfg, code->which);
+ config = vsp1_entity_get_pad_config(entity, sd_state,
+ code->which);
if (!config)
return -EINVAL;
@@ -290,17 +293,17 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
* source pad size identical to the sink pad.
*/
int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse,
unsigned int min_width, unsigned int min_height,
unsigned int max_width, unsigned int max_height)
{
struct vsp1_entity *entity = to_vsp1_entity(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
int ret = 0;
- config = vsp1_entity_get_pad_config(entity, cfg, fse->which);
+ config = vsp1_entity_get_pad_config(entity, sd_state, fse->which);
if (!config)
return -EINVAL;
@@ -353,14 +356,14 @@ done:
* source pad.
*/
int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt,
const unsigned int *codes, unsigned int ncodes,
unsigned int min_width, unsigned int min_height,
unsigned int max_width, unsigned int max_height)
{
struct vsp1_entity *entity = to_vsp1_entity(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *selection;
unsigned int i;
@@ -368,7 +371,7 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
mutex_lock(&entity->lock);
- config = vsp1_entity_get_pad_config(entity, cfg, fmt->which);
+ config = vsp1_entity_get_pad_config(entity, sd_state, fmt->which);
if (!config) {
ret = -EINVAL;
goto done;
@@ -672,7 +675,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
* Allocate the pad configuration to store formats and selection
* rectangles.
*/
- entity->config = v4l2_subdev_alloc_pad_config(&entity->subdev);
+ entity->config = v4l2_subdev_alloc_state(&entity->subdev);
if (entity->config == NULL) {
media_entity_cleanup(&entity->subdev.entity);
return -ENOMEM;
@@ -687,6 +690,6 @@ void vsp1_entity_destroy(struct vsp1_entity *entity)
entity->ops->destroy(entity);
if (entity->subdev.ctrl_handler)
v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
- v4l2_subdev_free_pad_config(entity->config);
+ v4l2_subdev_free_state(entity->config);
media_entity_cleanup(&entity->subdev.entity);
}
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index a1ceb37bb837..f22724439cdc 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -115,7 +115,7 @@ struct vsp1_entity {
unsigned int sink_pad;
struct v4l2_subdev subdev;
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct mutex lock; /* Protects the pad config */
};
@@ -136,20 +136,20 @@ int vsp1_entity_link_setup(struct media_entity *entity,
const struct media_pad *local,
const struct media_pad *remote, u32 flags);
-struct v4l2_subdev_pad_config *
+struct v4l2_subdev_state *
vsp1_entity_get_pad_config(struct vsp1_entity *entity,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which);
struct v4l2_mbus_framefmt *
vsp1_entity_get_pad_format(struct vsp1_entity *entity,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad);
struct v4l2_rect *
vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, unsigned int target);
int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg);
+ struct v4l2_subdev_state *sd_state);
void vsp1_entity_route_setup(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
@@ -173,20 +173,20 @@ void vsp1_entity_configure_partition(struct vsp1_entity *entity,
struct media_pad *vsp1_entity_remote_pad(struct media_pad *pad);
int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt);
int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt,
const unsigned int *codes, unsigned int ncodes,
unsigned int min_width, unsigned int min_height,
unsigned int max_width, unsigned int max_height);
int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code,
const unsigned int *codes, unsigned int ncodes);
int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse,
unsigned int min_w, unsigned int min_h,
unsigned int max_w, unsigned int max_h);
diff --git a/drivers/media/platform/vsp1/vsp1_histo.c b/drivers/media/platform/vsp1/vsp1_histo.c
index a91e142bcb94..5e5013d2cd2a 100644
--- a/drivers/media/platform/vsp1/vsp1_histo.c
+++ b/drivers/media/platform/vsp1/vsp1_histo.c
@@ -170,7 +170,7 @@ static const struct vb2_ops histo_video_queue_qops = {
*/
static int histo_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct vsp1_histogram *histo = subdev_to_histo(subdev);
@@ -180,28 +180,30 @@ static int histo_enum_mbus_code(struct v4l2_subdev *subdev,
return 0;
}
- return vsp1_subdev_enum_mbus_code(subdev, cfg, code, histo->formats,
+ return vsp1_subdev_enum_mbus_code(subdev, sd_state, code,
+ histo->formats,
histo->num_formats);
}
static int histo_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->pad != HISTO_PAD_SINK)
return -EINVAL;
- return vsp1_subdev_enum_frame_size(subdev, cfg, fse, HISTO_MIN_SIZE,
+ return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
+ HISTO_MIN_SIZE,
HISTO_MIN_SIZE, HISTO_MAX_SIZE,
HISTO_MAX_SIZE);
}
static int histo_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct vsp1_histogram *histo = subdev_to_histo(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
int ret = 0;
@@ -211,7 +213,8 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
mutex_lock(&histo->entity.lock);
- config = vsp1_entity_get_pad_config(&histo->entity, cfg, sel->which);
+ config = vsp1_entity_get_pad_config(&histo->entity, sd_state,
+ sel->which);
if (!config) {
ret = -EINVAL;
goto done;
@@ -256,15 +259,15 @@ done:
}
static int histo_set_crop(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *config,
- struct v4l2_subdev_selection *sel)
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
{
struct vsp1_histogram *histo = subdev_to_histo(subdev);
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *selection;
/* The crop rectangle must be inside the input frame. */
- format = vsp1_entity_get_pad_format(&histo->entity, config,
+ format = vsp1_entity_get_pad_format(&histo->entity, sd_state,
HISTO_PAD_SINK);
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
@@ -274,11 +277,11 @@ static int histo_set_crop(struct v4l2_subdev *subdev,
format->height - sel->r.top);
/* Set the crop rectangle and reset the compose rectangle. */
- selection = vsp1_entity_get_pad_selection(&histo->entity, config,
+ selection = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
sel->pad, V4L2_SEL_TGT_CROP);
*selection = sel->r;
- selection = vsp1_entity_get_pad_selection(&histo->entity, config,
+ selection = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
sel->pad,
V4L2_SEL_TGT_COMPOSE);
*selection = sel->r;
@@ -287,7 +290,7 @@ static int histo_set_crop(struct v4l2_subdev *subdev,
}
static int histo_set_compose(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *config,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct vsp1_histogram *histo = subdev_to_histo(subdev);
@@ -303,7 +306,8 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
sel->r.left = 0;
sel->r.top = 0;
- crop = vsp1_entity_get_pad_selection(&histo->entity, config, sel->pad,
+ crop = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
+ sel->pad,
V4L2_SEL_TGT_CROP);
/*
@@ -329,7 +333,7 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
ratio = 1 << (crop->height * 2 / sel->r.height / 3);
sel->r.height = crop->height / ratio;
- compose = vsp1_entity_get_pad_selection(&histo->entity, config,
+ compose = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
sel->pad,
V4L2_SEL_TGT_COMPOSE);
*compose = sel->r;
@@ -338,11 +342,11 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
}
static int histo_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct vsp1_histogram *histo = subdev_to_histo(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
int ret;
if (sel->pad != HISTO_PAD_SINK)
@@ -350,7 +354,8 @@ static int histo_set_selection(struct v4l2_subdev *subdev,
mutex_lock(&histo->entity.lock);
- config = vsp1_entity_get_pad_config(&histo->entity, cfg, sel->which);
+ config = vsp1_entity_get_pad_config(&histo->entity, sd_state,
+ sel->which);
if (!config) {
ret = -EINVAL;
goto done;
@@ -369,7 +374,7 @@ done:
}
static int histo_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
if (fmt->pad == HISTO_PAD_SOURCE) {
@@ -381,19 +386,19 @@ static int histo_get_format(struct v4l2_subdev *subdev,
return 0;
}
- return vsp1_subdev_get_pad_format(subdev, cfg, fmt);
+ return vsp1_subdev_get_pad_format(subdev, sd_state, fmt);
}
static int histo_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vsp1_histogram *histo = subdev_to_histo(subdev);
if (fmt->pad != HISTO_PAD_SINK)
- return histo_get_format(subdev, cfg, fmt);
+ return histo_get_format(subdev, sd_state, fmt);
- return vsp1_subdev_set_pad_format(subdev, cfg, fmt,
+ return vsp1_subdev_set_pad_format(subdev, sd_state, fmt,
histo->formats, histo->num_formats,
HISTO_MIN_SIZE, HISTO_MIN_SIZE,
HISTO_MAX_SIZE, HISTO_MAX_SIZE);
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index d5ebd9d08c8a..361a870380c2 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -34,7 +34,7 @@ static inline void vsp1_hsit_write(struct vsp1_hsit *hsit,
*/
static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct vsp1_hsit *hsit = to_hsit(subdev);
@@ -52,26 +52,28 @@ static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int hsit_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
- return vsp1_subdev_enum_frame_size(subdev, cfg, fse, HSIT_MIN_SIZE,
+ return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
+ HSIT_MIN_SIZE,
HSIT_MIN_SIZE, HSIT_MAX_SIZE,
HSIT_MAX_SIZE);
}
static int hsit_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vsp1_hsit *hsit = to_hsit(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
int ret = 0;
mutex_lock(&hsit->entity.lock);
- config = vsp1_entity_get_pad_config(&hsit->entity, cfg, fmt->which);
+ config = vsp1_entity_get_pad_config(&hsit->entity, sd_state,
+ fmt->which);
if (!config) {
ret = -EINVAL;
goto done;
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 14ed5d7bd061..6a6857ac9327 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -40,27 +40,28 @@ static const unsigned int lif_codes[] = {
};
static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- return vsp1_subdev_enum_mbus_code(subdev, cfg, code, lif_codes,
+ return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, lif_codes,
ARRAY_SIZE(lif_codes));
}
static int lif_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
- return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LIF_MIN_SIZE,
+ return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
+ LIF_MIN_SIZE,
LIF_MIN_SIZE, LIF_MAX_SIZE,
LIF_MAX_SIZE);
}
static int lif_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
- return vsp1_subdev_set_pad_format(subdev, cfg, fmt, lif_codes,
+ return vsp1_subdev_set_pad_format(subdev, sd_state, fmt, lif_codes,
ARRAY_SIZE(lif_codes),
LIF_MIN_SIZE, LIF_MIN_SIZE,
LIF_MAX_SIZE, LIF_MAX_SIZE);
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index 9f88842d7048..ac6802a325f5 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -99,27 +99,28 @@ static const unsigned int lut_codes[] = {
};
static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- return vsp1_subdev_enum_mbus_code(subdev, cfg, code, lut_codes,
+ return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, lut_codes,
ARRAY_SIZE(lut_codes));
}
static int lut_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
- return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LUT_MIN_SIZE,
+ return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
+ LUT_MIN_SIZE,
LUT_MIN_SIZE, LUT_MAX_SIZE,
LUT_MAX_SIZE);
}
static int lut_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
- return vsp1_subdev_set_pad_format(subdev, cfg, fmt, lut_codes,
+ return vsp1_subdev_set_pad_format(subdev, sd_state, fmt, lut_codes,
ARRAY_SIZE(lut_codes),
LUT_MIN_SIZE, LUT_MIN_SIZE,
LUT_MAX_SIZE, LUT_MAX_SIZE);
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 049bdd958e56..22a82d218152 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -17,9 +17,9 @@
#define RWPF_MIN_HEIGHT 1
struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
- struct v4l2_subdev_pad_config *config)
+ struct v4l2_subdev_state *sd_state)
{
- return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, config,
+ return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, sd_state,
RWPF_PAD_SINK);
}
@@ -28,7 +28,7 @@ struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
*/
static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
@@ -46,28 +46,30 @@ static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
}
static int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
- return vsp1_subdev_enum_frame_size(subdev, cfg, fse, RWPF_MIN_WIDTH,
+ return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
+ RWPF_MIN_WIDTH,
RWPF_MIN_HEIGHT, rwpf->max_width,
rwpf->max_height);
}
static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
int ret = 0;
mutex_lock(&rwpf->entity.lock);
- config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, fmt->which);
+ config = vsp1_entity_get_pad_config(&rwpf->entity, sd_state,
+ fmt->which);
if (!config) {
ret = -EINVAL;
goto done;
@@ -128,11 +130,11 @@ done:
}
static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
int ret = 0;
@@ -145,7 +147,8 @@ static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
mutex_lock(&rwpf->entity.lock);
- config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which);
+ config = vsp1_entity_get_pad_config(&rwpf->entity, sd_state,
+ sel->which);
if (!config) {
ret = -EINVAL;
goto done;
@@ -176,11 +179,11 @@ done:
}
static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
int ret = 0;
@@ -197,7 +200,8 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
mutex_lock(&rwpf->entity.lock);
- config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which);
+ config = vsp1_entity_get_pad_config(&rwpf->entity, sd_state,
+ sel->which);
if (!config) {
ret = -EINVAL;
goto done;
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 2f3582590618..eac5c04c2239 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -84,6 +84,6 @@ int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols);
extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops;
struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
- struct v4l2_subdev_pad_config *config);
+ struct v4l2_subdev_state *sd_state);
#endif /* __VSP1_RWPF_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 2b65457ee12f..b614a2aea461 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -106,7 +106,7 @@ static const struct v4l2_ctrl_config sru_intensity_control = {
*/
static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
@@ -114,20 +114,21 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
MEDIA_BUS_FMT_AYUV8_1X32,
};
- return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
+ return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, codes,
ARRAY_SIZE(codes));
}
static int sru_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct vsp1_sru *sru = to_sru(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
int ret = 0;
- config = vsp1_entity_get_pad_config(&sru->entity, cfg, fse->which);
+ config = vsp1_entity_get_pad_config(&sru->entity, sd_state,
+ fse->which);
if (!config)
return -EINVAL;
@@ -164,7 +165,7 @@ done:
}
static void sru_try_format(struct vsp1_sru *sru,
- struct v4l2_subdev_pad_config *config,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, struct v4l2_mbus_framefmt *fmt)
{
struct v4l2_mbus_framefmt *format;
@@ -184,7 +185,7 @@ static void sru_try_format(struct vsp1_sru *sru,
case SRU_PAD_SOURCE:
/* The SRU can't perform format conversion. */
- format = vsp1_entity_get_pad_format(&sru->entity, config,
+ format = vsp1_entity_get_pad_format(&sru->entity, sd_state,
SRU_PAD_SINK);
fmt->code = format->code;
@@ -216,17 +217,18 @@ static void sru_try_format(struct vsp1_sru *sru,
}
static int sru_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vsp1_sru *sru = to_sru(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
int ret = 0;
mutex_lock(&sru->entity.lock);
- config = vsp1_entity_get_pad_config(&sru->entity, cfg, fmt->which);
+ config = vsp1_entity_get_pad_config(&sru->entity, sd_state,
+ fmt->which);
if (!config) {
ret = -EINVAL;
goto done;
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 5fc04c082d1a..1c290cda005a 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -111,7 +111,7 @@ static unsigned int uds_compute_ratio(unsigned int input, unsigned int output)
*/
static int uds_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
@@ -119,20 +119,21 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev,
MEDIA_BUS_FMT_AYUV8_1X32,
};
- return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
+ return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, codes,
ARRAY_SIZE(codes));
}
static int uds_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct vsp1_uds *uds = to_uds(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
int ret = 0;
- config = vsp1_entity_get_pad_config(&uds->entity, cfg, fse->which);
+ config = vsp1_entity_get_pad_config(&uds->entity, sd_state,
+ fse->which);
if (!config)
return -EINVAL;
@@ -164,7 +165,7 @@ done:
}
static void uds_try_format(struct vsp1_uds *uds,
- struct v4l2_subdev_pad_config *config,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, struct v4l2_mbus_framefmt *fmt)
{
struct v4l2_mbus_framefmt *format;
@@ -184,7 +185,7 @@ static void uds_try_format(struct vsp1_uds *uds,
case UDS_PAD_SOURCE:
/* The UDS scales but can't perform format conversion. */
- format = vsp1_entity_get_pad_format(&uds->entity, config,
+ format = vsp1_entity_get_pad_format(&uds->entity, sd_state,
UDS_PAD_SINK);
fmt->code = format->code;
@@ -200,17 +201,18 @@ static void uds_try_format(struct vsp1_uds *uds,
}
static int uds_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vsp1_uds *uds = to_uds(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
int ret = 0;
mutex_lock(&uds->entity.lock);
- config = vsp1_entity_get_pad_config(&uds->entity, cfg, fmt->which);
+ config = vsp1_entity_get_pad_config(&uds->entity, sd_state,
+ fmt->which);
if (!config) {
ret = -EINVAL;
goto done;
diff --git a/drivers/media/platform/vsp1/vsp1_uif.c b/drivers/media/platform/vsp1/vsp1_uif.c
index 467d1072577b..83d7f17df80e 100644
--- a/drivers/media/platform/vsp1/vsp1_uif.c
+++ b/drivers/media/platform/vsp1/vsp1_uif.c
@@ -54,38 +54,39 @@ static const unsigned int uif_codes[] = {
};
static int uif_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- return vsp1_subdev_enum_mbus_code(subdev, cfg, code, uif_codes,
+ return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, uif_codes,
ARRAY_SIZE(uif_codes));
}
static int uif_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
- return vsp1_subdev_enum_frame_size(subdev, cfg, fse, UIF_MIN_SIZE,
+ return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
+ UIF_MIN_SIZE,
UIF_MIN_SIZE, UIF_MAX_SIZE,
UIF_MAX_SIZE);
}
static int uif_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
- return vsp1_subdev_set_pad_format(subdev, cfg, fmt, uif_codes,
+ return vsp1_subdev_set_pad_format(subdev, sd_state, fmt, uif_codes,
ARRAY_SIZE(uif_codes),
UIF_MIN_SIZE, UIF_MIN_SIZE,
UIF_MAX_SIZE, UIF_MAX_SIZE);
}
static int uif_get_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct vsp1_uif *uif = to_uif(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
int ret = 0;
@@ -94,7 +95,8 @@ static int uif_get_selection(struct v4l2_subdev *subdev,
mutex_lock(&uif->entity.lock);
- config = vsp1_entity_get_pad_config(&uif->entity, cfg, sel->which);
+ config = vsp1_entity_get_pad_config(&uif->entity, sd_state,
+ sel->which);
if (!config) {
ret = -EINVAL;
goto done;
@@ -127,11 +129,11 @@ done:
}
static int uif_set_selection(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct vsp1_uif *uif = to_uif(subdev);
- struct v4l2_subdev_pad_config *config;
+ struct v4l2_subdev_state *config;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *selection;
int ret = 0;
@@ -142,7 +144,8 @@ static int uif_set_selection(struct v4l2_subdev *subdev,
mutex_lock(&uif->entity.lock);
- config = vsp1_entity_get_pad_config(&uif->entity, cfg, sel->which);
+ config = vsp1_entity_get_pad_config(&uif->entity, sd_state,
+ sel->which);
if (!config) {
ret = -EINVAL;
goto done;
diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c
index fff7ddec6745..b1baf9d7b6ec 100644
--- a/drivers/media/platform/xilinx/xilinx-csi2rxss.c
+++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c
@@ -681,12 +681,13 @@ stream_done:
static struct v4l2_mbus_framefmt *
__xcsi2rxss_get_pad_format(struct xcsi2rxss_state *xcsi2rxss,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, u32 which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&xcsi2rxss->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&xcsi2rxss->subdev,
+ sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &xcsi2rxss->format;
default:
@@ -697,7 +698,7 @@ __xcsi2rxss_get_pad_format(struct xcsi2rxss_state *xcsi2rxss,
/**
* xcsi2rxss_init_cfg - Initialise the pad format config to default
* @sd: Pointer to V4L2 Sub device structure
- * @cfg: Pointer to sub device pad information structure
+ * @sd_state: Pointer to sub device state structure
*
* This function is used to initialize the pad format with the default
* values.
@@ -705,7 +706,7 @@ __xcsi2rxss_get_pad_format(struct xcsi2rxss_state *xcsi2rxss,
* Return: 0 on success
*/
static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
struct v4l2_mbus_framefmt *format;
@@ -713,7 +714,7 @@ static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd,
mutex_lock(&xcsi2rxss->lock);
for (i = 0; i < XCSI_MEDIA_PADS; i++) {
- format = v4l2_subdev_get_try_format(sd, cfg, i);
+ format = v4l2_subdev_get_try_format(sd, sd_state, i);
*format = xcsi2rxss->default_format;
}
mutex_unlock(&xcsi2rxss->lock);
@@ -724,7 +725,7 @@ static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd,
/**
* xcsi2rxss_get_format - Get the pad format
* @sd: Pointer to V4L2 Sub device structure
- * @cfg: Pointer to sub device pad information structure
+ * @sd_state: Pointer to sub device state structure
* @fmt: Pointer to pad level media bus format
*
* This function is used to get the pad format information.
@@ -732,13 +733,14 @@ static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd,
* Return: 0 on success
*/
static int xcsi2rxss_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
mutex_lock(&xcsi2rxss->lock);
- fmt->format = *__xcsi2rxss_get_pad_format(xcsi2rxss, cfg, fmt->pad,
+ fmt->format = *__xcsi2rxss_get_pad_format(xcsi2rxss, sd_state,
+ fmt->pad,
fmt->which);
mutex_unlock(&xcsi2rxss->lock);
@@ -748,7 +750,7 @@ static int xcsi2rxss_get_format(struct v4l2_subdev *sd,
/**
* xcsi2rxss_set_format - This is used to set the pad format
* @sd: Pointer to V4L2 Sub device structure
- * @cfg: Pointer to sub device pad information structure
+ * @sd_state: Pointer to sub device state structure
* @fmt: Pointer to pad level media bus format
*
* This function is used to set the pad format. Since the pad format is fixed
@@ -759,7 +761,7 @@ static int xcsi2rxss_get_format(struct v4l2_subdev *sd,
* Return: 0 on success
*/
static int xcsi2rxss_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
@@ -773,7 +775,7 @@ static int xcsi2rxss_set_format(struct v4l2_subdev *sd,
* CSI format cannot be changed at runtime.
* Ensure that format to set is copied to over to CSI pad format
*/
- __format = __xcsi2rxss_get_pad_format(xcsi2rxss, cfg,
+ __format = __xcsi2rxss_get_pad_format(xcsi2rxss, sd_state,
fmt->pad, fmt->which);
/* only sink pad format can be updated */
@@ -811,7 +813,7 @@ static int xcsi2rxss_set_format(struct v4l2_subdev *sd,
* Return: -EINVAL or zero on success
*/
static int xcsi2rxss_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct xcsi2rxss_state *state = to_xcsi2rxssstate(sd);
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index 2a56201cb853..338c3661d809 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -26,7 +26,6 @@
#include "xilinx-vip.h"
#include "xilinx-vipp.h"
-#define XVIP_DMA_DEF_FORMAT V4L2_PIX_FMT_YUYV
#define XVIP_DMA_DEF_WIDTH 1920
#define XVIP_DMA_DEF_HEIGHT 1080
@@ -549,8 +548,6 @@ __xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix,
* requested format isn't supported.
*/
info = xvip_get_format_by_fourcc(pix->pixelformat);
- if (IS_ERR(info))
- info = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT);
pix->pixelformat = info->fourcc;
pix->field = V4L2_FIELD_NONE;
@@ -660,7 +657,7 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
INIT_LIST_HEAD(&dma->queued_bufs);
spin_lock_init(&dma->queued_lock);
- dma->fmtinfo = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT);
+ dma->fmtinfo = xvip_get_format_by_fourcc(V4L2_PIX_FMT_YUYV);
dma->format.pixelformat = dma->fmtinfo->fourcc;
dma->format.colorspace = V4L2_COLORSPACE_SRGB;
dma->format.field = V4L2_FIELD_NONE;
diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c
index ed01bedb5db6..0f2d5a0edf0c 100644
--- a/drivers/media/platform/xilinx/xilinx-tpg.c
+++ b/drivers/media/platform/xilinx/xilinx-tpg.c
@@ -251,12 +251,13 @@ static int xtpg_s_stream(struct v4l2_subdev *subdev, int enable)
static struct v4l2_mbus_framefmt *
__xtpg_get_pad_format(struct xtpg_device *xtpg,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad, u32 which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&xtpg->xvip.subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&xtpg->xvip.subdev,
+ sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &xtpg->formats[pad];
default:
@@ -265,25 +266,26 @@ __xtpg_get_pad_format(struct xtpg_device *xtpg,
}
static int xtpg_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct xtpg_device *xtpg = to_tpg(subdev);
- fmt->format = *__xtpg_get_pad_format(xtpg, cfg, fmt->pad, fmt->which);
+ fmt->format = *__xtpg_get_pad_format(xtpg, sd_state, fmt->pad,
+ fmt->which);
return 0;
}
static int xtpg_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct xtpg_device *xtpg = to_tpg(subdev);
struct v4l2_mbus_framefmt *__format;
u32 bayer_phase;
- __format = __xtpg_get_pad_format(xtpg, cfg, fmt->pad, fmt->which);
+ __format = __xtpg_get_pad_format(xtpg, sd_state, fmt->pad, fmt->which);
/* In two pads mode the source pad format is always identical to the
* sink pad format.
@@ -306,7 +308,8 @@ static int xtpg_set_format(struct v4l2_subdev *subdev,
/* Propagate the format to the source pad. */
if (xtpg->npads == 2) {
- __format = __xtpg_get_pad_format(xtpg, cfg, 1, fmt->which);
+ __format = __xtpg_get_pad_format(xtpg, sd_state, 1,
+ fmt->which);
*__format = fmt->format;
}
@@ -318,12 +321,12 @@ static int xtpg_set_format(struct v4l2_subdev *subdev,
*/
static int xtpg_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad);
+ format = v4l2_subdev_get_try_format(subdev, sd_state, fse->pad);
if (fse->index || fse->code != format->code)
return -EINVAL;
@@ -351,11 +354,11 @@ static int xtpg_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
struct xtpg_device *xtpg = to_tpg(subdev);
struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_try_format(subdev, fh->pad, 0);
+ format = v4l2_subdev_get_try_format(subdev, fh->state, 0);
*format = xtpg->default_format;
if (xtpg->npads == 2) {
- format = v4l2_subdev_get_try_format(subdev, fh->pad, 1);
+ format = v4l2_subdev_get_try_format(subdev, fh->state, 1);
*format = xtpg->default_format;
}
diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c
index 6ad61b08a31a..425a32dd5d19 100644
--- a/drivers/media/platform/xilinx/xilinx-vip.c
+++ b/drivers/media/platform/xilinx/xilinx-vip.c
@@ -70,8 +70,8 @@ EXPORT_SYMBOL_GPL(xvip_get_format_by_code);
* @fourcc: the format 4CC
*
* Return: a pointer to the format information structure corresponding to the
- * given V4L2 format @fourcc, or ERR_PTR if no corresponding format can be
- * found.
+ * given V4L2 format @fourcc. If not found, return a pointer to the first
+ * available format (V4L2_PIX_FMT_YUYV).
*/
const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc)
{
@@ -84,7 +84,7 @@ const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc)
return format;
}
- return ERR_PTR(-EINVAL);
+ return &xvip_video_formats[0];
}
EXPORT_SYMBOL_GPL(xvip_get_format_by_fourcc);
@@ -234,7 +234,7 @@ EXPORT_SYMBOL_GPL(xvip_cleanup_resources);
/**
* xvip_enum_mbus_code - Enumerate the media format code
* @subdev: V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @code: returning media bus code
*
* Enumerate the media bus code of the subdevice. Return the corresponding
@@ -246,7 +246,7 @@ EXPORT_SYMBOL_GPL(xvip_cleanup_resources);
* is not valid.
*/
int xvip_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct v4l2_mbus_framefmt *format;
@@ -260,7 +260,7 @@ int xvip_enum_mbus_code(struct v4l2_subdev *subdev,
if (code->index)
return -EINVAL;
- format = v4l2_subdev_get_try_format(subdev, cfg, code->pad);
+ format = v4l2_subdev_get_try_format(subdev, sd_state, code->pad);
code->code = format->code;
@@ -271,7 +271,7 @@ EXPORT_SYMBOL_GPL(xvip_enum_mbus_code);
/**
* xvip_enum_frame_size - Enumerate the media bus frame size
* @subdev: V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fse: returning media bus frame size
*
* This function is a drop-in implementation of the subdev enum_frame_size pad
@@ -284,7 +284,7 @@ EXPORT_SYMBOL_GPL(xvip_enum_mbus_code);
* if the index or the code is not valid.
*/
int xvip_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct v4l2_mbus_framefmt *format;
@@ -295,7 +295,7 @@ int xvip_enum_frame_size(struct v4l2_subdev *subdev,
if (fse->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return -EINVAL;
- format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad);
+ format = v4l2_subdev_get_try_format(subdev, sd_state, fse->pad);
if (fse->index || fse->code != format->code)
return -EINVAL;
diff --git a/drivers/media/platform/xilinx/xilinx-vip.h b/drivers/media/platform/xilinx/xilinx-vip.h
index a528a32ea1dc..d0b0e0600952 100644
--- a/drivers/media/platform/xilinx/xilinx-vip.h
+++ b/drivers/media/platform/xilinx/xilinx-vip.h
@@ -125,10 +125,10 @@ const struct xvip_video_format *xvip_of_get_format(struct device_node *node);
void xvip_set_format_size(struct v4l2_mbus_framefmt *format,
const struct v4l2_subdev_format *fmt);
int xvip_enum_mbus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code);
int xvip_enum_frame_size(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse);
static inline u32 xvip_read(struct xvip_device *xvip, u32 addr)
diff --git a/drivers/media/radio/si4713/radio-platform-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c
index a7dfe5f55c18..433f9642786d 100644
--- a/drivers/media/radio/si4713/radio-platform-si4713.c
+++ b/drivers/media/radio/si4713/radio-platform-si4713.c
@@ -110,7 +110,7 @@ static long radio_si4713_default(struct file *file, void *p,
ioctl, cmd, arg);
}
-static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = {
+static const struct v4l2_ioctl_ops radio_si4713_ioctl_ops = {
.vidioc_querycap = radio_si4713_querycap,
.vidioc_g_modulator = radio_si4713_g_modulator,
.vidioc_s_modulator = radio_si4713_s_modulator,
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index f016b35c2b17..d0a8326b75c2 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -19,7 +19,6 @@ source "drivers/media/rc/keymaps/Kconfig"
config LIRC
bool "LIRC user interface"
- depends on RC_CORE
help
Enable this option to enable the Linux Infrared Remote
Control user interface (e.g. /dev/lirc*). This interface
@@ -41,12 +40,10 @@ config BPF_LIRC_MODE2
menuconfig RC_DECODERS
bool "Remote controller decoders"
- depends on RC_CORE
if RC_DECODERS
config IR_NEC_DECODER
tristate "Enable IR raw decoder for the NEC protocol"
- depends on RC_CORE
select BITREVERSE
help
@@ -55,7 +52,6 @@ config IR_NEC_DECODER
config IR_RC5_DECODER
tristate "Enable IR raw decoder for the RC-5 protocol"
- depends on RC_CORE
select BITREVERSE
help
@@ -64,7 +60,6 @@ config IR_RC5_DECODER
config IR_RC6_DECODER
tristate "Enable IR raw decoder for the RC6 protocol"
- depends on RC_CORE
select BITREVERSE
help
@@ -73,7 +68,6 @@ config IR_RC6_DECODER
config IR_JVC_DECODER
tristate "Enable IR raw decoder for the JVC protocol"
- depends on RC_CORE
select BITREVERSE
help
@@ -82,7 +76,6 @@ config IR_JVC_DECODER
config IR_SONY_DECODER
tristate "Enable IR raw decoder for the Sony protocol"
- depends on RC_CORE
select BITREVERSE
help
@@ -91,7 +84,6 @@ config IR_SONY_DECODER
config IR_SANYO_DECODER
tristate "Enable IR raw decoder for the Sanyo protocol"
- depends on RC_CORE
select BITREVERSE
help
@@ -101,7 +93,6 @@ config IR_SANYO_DECODER
config IR_SHARP_DECODER
tristate "Enable IR raw decoder for the Sharp protocol"
- depends on RC_CORE
select BITREVERSE
help
@@ -111,7 +102,6 @@ config IR_SHARP_DECODER
config IR_MCE_KBD_DECODER
tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol"
- depends on RC_CORE
select BITREVERSE
help
@@ -121,7 +111,6 @@ config IR_MCE_KBD_DECODER
config IR_XMP_DECODER
tristate "Enable IR raw decoder for the XMP protocol"
- depends on RC_CORE
select BITREVERSE
help
@@ -130,7 +119,6 @@ config IR_XMP_DECODER
config IR_IMON_DECODER
tristate "Enable IR raw decoder for the iMON protocol"
- depends on RC_CORE
help
Enable this option if you have iMON PAD or Antec Veris infrared
remote control and you would like to use it with a raw IR
@@ -138,7 +126,6 @@ config IR_IMON_DECODER
config IR_RCMM_DECODER
tristate "Enable IR raw decoder for the RC-MM protocol"
- depends on RC_CORE
help
Enable this option when you have IR with RC-MM protocol, and
you need the software decoder. The driver supports 12,
@@ -153,15 +140,12 @@ endif #RC_DECODERS
menuconfig RC_DEVICES
bool "Remote Controller devices"
- depends on RC_CORE
if RC_DEVICES
config RC_ATI_REMOTE
tristate "ATI / X10 based USB RF remote controls"
- depends on USB_ARCH_HAS_HCD
- depends on RC_CORE
- select USB
+ depends on USB
help
Say Y here if you want to use an X10 based USB remote control.
These are RF remotes with USB receivers.
@@ -179,7 +163,6 @@ config RC_ATI_REMOTE
config IR_ENE
tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)"
depends on PNP || COMPILE_TEST
- depends on RC_CORE
help
Say Y here to enable support for integrated infrared receiver
/transceiver made by ENE.
@@ -192,7 +175,6 @@ config IR_ENE
config IR_HIX5HD2
tristate "Hisilicon hix5hd2 IR remote control"
- depends on RC_CORE
depends on OF || COMPILE_TEST
help
Say Y here if you want to use hisilicon hix5hd2 remote control.
@@ -203,9 +185,7 @@ config IR_HIX5HD2
config IR_IMON
tristate "SoundGraph iMON Receiver and Display"
- depends on USB_ARCH_HAS_HCD
- depends on RC_CORE
- select USB
+ depends on USB
help
Say Y here if you want to use a SoundGraph iMON (aka Antec Veris)
IR Receiver and/or LCD/VFD/VGA display.
@@ -215,9 +195,7 @@ config IR_IMON
config IR_IMON_RAW
tristate "SoundGraph iMON Receiver (early raw IR models)"
- depends on USB_ARCH_HAS_HCD
- depends on RC_CORE
- select USB
+ depends on USB
help
Say Y here if you want to use a SoundGraph iMON IR Receiver,
early raw models.
@@ -227,9 +205,7 @@ config IR_IMON_RAW
config IR_MCEUSB
tristate "Windows Media Center Ed. eHome Infrared Transceiver"
- depends on USB_ARCH_HAS_HCD
- depends on RC_CORE
- select USB
+ depends on USB
help
Say Y here if you want to use a Windows Media Center Edition
eHome Infrared Transceiver.
@@ -240,7 +216,6 @@ config IR_MCEUSB
config IR_ITE_CIR
tristate "ITE Tech Inc. IT8712/IT8512 Consumer Infrared Transceiver"
depends on PNP || COMPILE_TEST
- depends on RC_CORE
help
Say Y here to enable support for integrated infrared receivers
/transceivers made by ITE Tech Inc. These are found in
@@ -253,7 +228,6 @@ config IR_ITE_CIR
config IR_FINTEK
tristate "Fintek Consumer Infrared Transceiver"
depends on PNP || COMPILE_TEST
- depends on RC_CORE
help
Say Y here to enable support for integrated infrared receiver
/transceiver made by Fintek. This chip is found on assorted
@@ -264,7 +238,6 @@ config IR_FINTEK
config IR_MESON
tristate "Amlogic Meson IR remote receiver"
- depends on RC_CORE
depends on ARCH_MESON || COMPILE_TEST
help
Say Y if you want to use the IR remote receiver available
@@ -275,7 +248,6 @@ config IR_MESON
config IR_MTK
tristate "Mediatek IR remote receiver"
- depends on RC_CORE
depends on ARCH_MEDIATEK || COMPILE_TEST
help
Say Y if you want to use the IR remote receiver available
@@ -287,7 +259,6 @@ config IR_MTK
config IR_NUVOTON
tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
depends on PNP || COMPILE_TEST
- depends on RC_CORE
help
Say Y here to enable support for integrated infrared receiver
/transceiver made by Nuvoton (formerly Winbond). This chip is
@@ -299,11 +270,9 @@ config IR_NUVOTON
config IR_REDRAT3
tristate "RedRat3 IR Transceiver"
- depends on USB_ARCH_HAS_HCD
- depends on RC_CORE
+ depends on USB
select NEW_LEDS
select LEDS_CLASS
- select USB
help
Say Y here if you want to use a RedRat3 Infrared Transceiver.
@@ -322,9 +291,7 @@ config IR_SPI
config IR_STREAMZAP
tristate "Streamzap PC Remote IR Receiver"
- depends on USB_ARCH_HAS_HCD
- depends on RC_CORE
- select USB
+ depends on USB
help
Say Y here if you want to use a Streamzap PC Remote
Infrared Receiver.
@@ -335,7 +302,6 @@ config IR_STREAMZAP
config IR_WINBOND_CIR
tristate "Winbond IR remote control"
depends on (X86 && PNP) || COMPILE_TEST
- depends on RC_CORE
select NEW_LEDS
select LEDS_CLASS
select BITREVERSE
@@ -350,9 +316,7 @@ config IR_WINBOND_CIR
config IR_IGORPLUGUSB
tristate "IgorPlug-USB IR Receiver"
- depends on USB_ARCH_HAS_HCD
- depends on RC_CORE
- select USB
+ depends on USB
help
Say Y here if you want to use the IgorPlug-USB IR Receiver by
Igor Cesko. This device is included on the Fit-PC2.
@@ -365,9 +329,7 @@ config IR_IGORPLUGUSB
config IR_IGUANA
tristate "IguanaWorks USB IR Transceiver"
- depends on USB_ARCH_HAS_HCD
- depends on RC_CORE
- select USB
+ depends on USB
help
Say Y here if you want to use the IguanaWorks USB IR Transceiver.
Both infrared receive and send are supported. If you want to
@@ -381,9 +343,7 @@ config IR_IGUANA
config IR_TTUSBIR
tristate "TechnoTrend USB IR Receiver"
- depends on USB_ARCH_HAS_HCD
- depends on RC_CORE
- select USB
+ depends on USB
select NEW_LEDS
select LEDS_CLASS
help
@@ -407,7 +367,6 @@ source "drivers/media/rc/img-ir/Kconfig"
config RC_LOOPBACK
tristate "Remote Control Loopback Driver"
- depends on RC_CORE
help
Say Y here if you want support for the remote control loopback
driver which allows TX data to be sent back as RX data.
@@ -420,7 +379,6 @@ config RC_LOOPBACK
config IR_GPIO_CIR
tristate "GPIO IR remote control"
- depends on RC_CORE
depends on (OF && GPIOLIB) || COMPILE_TEST
help
Say Y if you want to use GPIO based IR Receiver.
@@ -430,7 +388,6 @@ config IR_GPIO_CIR
config IR_GPIO_TX
tristate "GPIO IR Bit Banging Transmitter"
- depends on RC_CORE
depends on LIRC
depends on (OF && GPIOLIB) || COMPILE_TEST
help
@@ -442,7 +399,6 @@ config IR_GPIO_TX
config IR_PWM_TX
tristate "PWM IR transmitter"
- depends on RC_CORE
depends on LIRC
depends on PWM
depends on OF || COMPILE_TEST
@@ -455,7 +411,6 @@ config IR_PWM_TX
config RC_ST
tristate "ST remote control receiver"
- depends on RC_CORE
depends on ARCH_STI || COMPILE_TEST
help
Say Y here if you want support for ST remote control driver
@@ -466,7 +421,6 @@ config RC_ST
config IR_SUNXI
tristate "SUNXI IR remote control"
- depends on RC_CORE
depends on ARCH_SUNXI || COMPILE_TEST
help
Say Y if you want to use sunXi internal IR Controller
@@ -476,7 +430,6 @@ config IR_SUNXI
config IR_SERIAL
tristate "Homebrew Serial Port Receiver"
- depends on RC_CORE
help
Say Y if you want to use Homebrew Serial Port Receivers and
Transceivers.
@@ -492,28 +445,15 @@ config IR_SERIAL_TRANSMITTER
config IR_SIR
tristate "Built-in SIR IrDA port"
- depends on RC_CORE
help
Say Y if you want to use a IrDA SIR port Transceivers.
To compile this driver as a module, choose M here: the module will
be called sir-ir.
-config IR_TANGO
- tristate "Sigma Designs SMP86xx IR decoder"
- depends on RC_CORE
- depends on ARCH_TANGO || COMPILE_TEST
- help
- Adds support for the HW IR decoder embedded on Sigma Designs
- Tango-based systems (SMP86xx, SMP87xx).
- The HW decoder supports NEC, RC-5, RC-6 IR protocols.
- When compiled as a module, look for tango-ir.
-
config RC_XBOX_DVD
tristate "Xbox DVD Movie Playback Kit"
- depends on RC_CORE
- depends on USB_ARCH_HAS_HCD
- select USB
+ depends on USB
help
Say Y here if you want to use the Xbox DVD Movie Playback Kit.
These are IR remotes with USB receivers for the Original Xbox (2001).
@@ -523,8 +463,7 @@ config RC_XBOX_DVD
config IR_TOY
tristate "Infrared Toy and IR Droid"
- depends on RC_CORE
- depends on USB_ARCH_HAS_HCD
+ depends on USB
help
Say Y here if you want to use the Infrared Toy or IR Droid, USB
versions.
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index f31002288f7c..692e9b6b203f 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -48,6 +48,5 @@ obj-$(CONFIG_IR_IMG) += img-ir/
obj-$(CONFIG_IR_SERIAL) += serial_ir.o
obj-$(CONFIG_IR_SIR) += sir_ir.o
obj-$(CONFIG_IR_MTK) += mtk-cir.o
-obj-$(CONFIG_IR_TANGO) += tango-ir.o
obj-$(CONFIG_RC_XBOX_DVD) += xbox_remote.o
obj-$(CONFIG_IR_TOY) += ir_toy.o
diff --git a/drivers/media/rc/bpf-lirc.c b/drivers/media/rc/bpf-lirc.c
index 3fe3edd80876..afae0afe3f81 100644
--- a/drivers/media/rc/bpf-lirc.c
+++ b/drivers/media/rc/bpf-lirc.c
@@ -326,7 +326,8 @@ int lirc_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr)
}
if (attr->query.prog_cnt != 0 && prog_ids && cnt)
- ret = bpf_prog_array_copy_to_user(progs, prog_ids, cnt);
+ ret = bpf_prog_array_copy_to_user(progs, prog_ids,
+ attr->query.prog_cnt);
unlock:
mutex_unlock(&ir_raw_handler_lock);
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index a7962ca2ac8e..2ca4e86c7b9f 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -780,7 +780,7 @@ static int send_set_imon_clock(struct imon_context *ictx,
/*
* These are the sysfs functions to handle the association on the iMON 2.4G LT.
*/
-static ssize_t show_associate_remote(struct device *d,
+static ssize_t associate_remote_show(struct device *d,
struct device_attribute *attr,
char *buf)
{
@@ -800,7 +800,7 @@ static ssize_t show_associate_remote(struct device *d,
return strlen(buf);
}
-static ssize_t store_associate_remote(struct device *d,
+static ssize_t associate_remote_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -822,7 +822,7 @@ static ssize_t store_associate_remote(struct device *d,
/*
* sysfs functions to control internal imon clock
*/
-static ssize_t show_imon_clock(struct device *d,
+static ssize_t imon_clock_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct imon_context *ictx = dev_get_drvdata(d);
@@ -848,7 +848,7 @@ static ssize_t show_imon_clock(struct device *d,
return len;
}
-static ssize_t store_imon_clock(struct device *d,
+static ssize_t imon_clock_store(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -895,11 +895,8 @@ exit:
}
-static DEVICE_ATTR(imon_clock, S_IWUSR | S_IRUGO, show_imon_clock,
- store_imon_clock);
-
-static DEVICE_ATTR(associate_remote, S_IWUSR | S_IRUGO, show_associate_remote,
- store_associate_remote);
+static DEVICE_ATTR_RW(imon_clock);
+static DEVICE_ATTR_RW(associate_remote);
static struct attribute *imon_display_sysfs_entries[] = {
&dev_attr_imon_clock.attr,
diff --git a/drivers/media/rc/ite-cir.h b/drivers/media/rc/ite-cir.h
index ce7a40b10828..4b4294d77555 100644
--- a/drivers/media/rc/ite-cir.h
+++ b/drivers/media/rc/ite-cir.h
@@ -167,7 +167,7 @@ struct ite_dev {
* hardware data obtained from:
*
* IT8712F
- * Environment Control – Low Pin Count Input / Output
+ * Environment Control - Low Pin Count Input / Output
* (EC - LPC I/O)
* Preliminary Specification V0. 81
*/
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 50b2833dbe4f..5fe5c9e1a46d 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-budget-ci-old.o \
rc-cinergy-1400.o \
rc-cinergy.o \
+ rc-ct-90405.o \
rc-d680-dmb.o \
rc-delock-61959.o \
rc-dib0700-nec.o \
@@ -100,7 +101,6 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-reddo.o \
rc-snapstream-firefly.o \
rc-streamzap.o \
- rc-tango.o \
rc-tanix-tx3mini.o \
rc-tanix-tx5max.o \
rc-tbs-nec.o \
diff --git a/drivers/media/rc/keymaps/rc-ct-90405.c b/drivers/media/rc/keymaps/rc-ct-90405.c
new file mode 100644
index 000000000000..8914c83c9d9f
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-ct-90405.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Toshiba CT-90405 remote controller keytable
+ *
+ * Copyright (C) 2021 Alexander Voronov <avv.0@ya.ru>
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+static struct rc_map_table ct_90405[] = {
+ { 0x4014, KEY_SWITCHVIDEOMODE },
+ { 0x4012, KEY_POWER },
+ { 0x4044, KEY_TV },
+ { 0x40be43, KEY_3D_MODE },
+ { 0x400c, KEY_SUBTITLE },
+ { 0x4001, KEY_NUMERIC_1 },
+ { 0x4002, KEY_NUMERIC_2 },
+ { 0x4003, KEY_NUMERIC_3 },
+ { 0x4004, KEY_NUMERIC_4 },
+ { 0x4005, KEY_NUMERIC_5 },
+ { 0x4006, KEY_NUMERIC_6 },
+ { 0x4007, KEY_NUMERIC_7 },
+ { 0x4008, KEY_NUMERIC_8 },
+ { 0x4009, KEY_NUMERIC_9 },
+ { 0x4062, KEY_AUDIO_DESC },
+ { 0x4000, KEY_NUMERIC_0 },
+ { 0x401a, KEY_VOLUMEUP },
+ { 0x401e, KEY_VOLUMEDOWN },
+ { 0x4016, KEY_INFO },
+ { 0x4010, KEY_MUTE },
+ { 0x401b, KEY_CHANNELUP },
+ { 0x401f, KEY_CHANNELDOWN },
+ { 0x40da, KEY_VENDOR },
+ { 0x4066, KEY_PLAYER },
+ { 0x4017, KEY_TEXT },
+ { 0x4047, KEY_LIST },
+ { 0x4073, KEY_PAGEUP },
+ { 0x4045, KEY_PROGRAM },
+ { 0x4043, KEY_EXIT },
+ { 0x4074, KEY_PAGEDOWN },
+ { 0x4064, KEY_BACK },
+ { 0x405b, KEY_MENU },
+ { 0x4019, KEY_UP },
+ { 0x4040, KEY_RIGHT },
+ { 0x401d, KEY_DOWN },
+ { 0x4042, KEY_LEFT },
+ { 0x4021, KEY_OK },
+ { 0x4053, KEY_REWIND },
+ { 0x4067, KEY_PLAY },
+ { 0x400d, KEY_FASTFORWARD },
+ { 0x4054, KEY_PREVIOUS },
+ { 0x4068, KEY_STOP },
+ { 0x406a, KEY_PAUSE },
+ { 0x4015, KEY_NEXT },
+ { 0x4048, KEY_RED },
+ { 0x4049, KEY_GREEN },
+ { 0x404a, KEY_YELLOW },
+ { 0x404b, KEY_BLUE },
+ { 0x406f, KEY_RECORD }
+};
+
+static struct rc_map_list ct_90405_map = {
+ .map = {
+ .scan = ct_90405,
+ .size = ARRAY_SIZE(ct_90405),
+ .rc_proto = RC_PROTO_NEC,
+ .name = RC_MAP_CT_90405,
+ }
+};
+
+static int __init init_rc_map_ct_90405(void)
+{
+ return rc_map_register(&ct_90405_map);
+}
+
+static void __exit exit_rc_map_ct_90405(void)
+{
+ rc_map_unregister(&ct_90405_map);
+}
+
+module_init(init_rc_map_ct_90405)
+module_exit(exit_rc_map_ct_90405)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexander Voronov <avv.0@ya.ru>");
diff --git a/drivers/media/rc/keymaps/rc-tango.c b/drivers/media/rc/keymaps/rc-tango.c
deleted file mode 100644
index 2b9cef6ef5b5..000000000000
--- a/drivers/media/rc/keymaps/rc-tango.c
+++ /dev/null
@@ -1,89 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2017 Sigma Designs
- */
-
-#include <linux/module.h>
-#include <media/rc-map.h>
-
-static struct rc_map_table tango_table[] = {
- { 0x4cb4a, KEY_POWER },
- { 0x4cb48, KEY_FILE },
- { 0x4cb0f, KEY_SETUP },
- { 0x4cb4d, KEY_SUSPEND },
- { 0x4cb4e, KEY_VOLUMEUP },
- { 0x4cb44, KEY_EJECTCD },
- { 0x4cb13, KEY_TV },
- { 0x4cb51, KEY_MUTE },
- { 0x4cb52, KEY_VOLUMEDOWN },
-
- { 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 },
-
- { 0x4cb47, KEY_BACK },
- { 0x4cb05, KEY_SWITCHVIDEOMODE },
- { 0x4cb06, KEY_UP },
- { 0x4cb43, KEY_LEFT },
- { 0x4cb01, KEY_RIGHT },
- { 0x4cb0a, KEY_DOWN },
- { 0x4cb02, KEY_ENTER },
- { 0x4cb4b, KEY_INFO },
- { 0x4cb09, KEY_HOME },
-
- { 0x4cb53, KEY_MENU },
- { 0x4cb12, KEY_PREVIOUS },
- { 0x4cb50, KEY_PLAY },
- { 0x4cb11, KEY_NEXT },
- { 0x4cb4f, KEY_TITLE },
- { 0x4cb0e, KEY_REWIND },
- { 0x4cb4c, KEY_STOP },
- { 0x4cb0d, KEY_FORWARD },
- { 0x4cb57, KEY_MEDIA_REPEAT },
- { 0x4cb16, KEY_ANGLE },
- { 0x4cb54, KEY_PAUSE },
- { 0x4cb15, KEY_SLOW },
- { 0x4cb5b, KEY_TIME },
- { 0x4cb1a, KEY_AUDIO },
- { 0x4cb58, KEY_SUBTITLE },
- { 0x4cb19, KEY_ZOOM },
-
- { 0x4cb5f, KEY_RED },
- { 0x4cb1e, KEY_GREEN },
- { 0x4cb5c, KEY_YELLOW },
- { 0x4cb1d, KEY_BLUE },
-};
-
-static struct rc_map_list tango_map = {
- .map = {
- .scan = tango_table,
- .size = ARRAY_SIZE(tango_table),
- .rc_proto = RC_PROTO_NECX,
- .name = RC_MAP_TANGO,
- }
-};
-
-static int __init init_rc_map_tango(void)
-{
- return rc_map_register(&tango_map);
-}
-
-static void __exit exit_rc_map_tango(void)
-{
- rc_map_unregister(&tango_map);
-}
-
-module_init(init_rc_map_tango)
-module_exit(exit_rc_map_tango)
-
-MODULE_AUTHOR("Sigma Designs");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c
index 3237fef5d502..d79d1e3996b2 100644
--- a/drivers/media/rc/st_rc.c
+++ b/drivers/media/rc/st_rc.c
@@ -157,8 +157,9 @@ static irqreturn_t st_rc_rx_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
-static void st_rc_hardware_init(struct st_rc_device *dev)
+static int st_rc_hardware_init(struct st_rc_device *dev)
{
+ int ret;
int baseclock, freqdiff;
unsigned int rx_max_symbol_per = MAX_SYMB_TIME;
unsigned int rx_sampling_freq_div;
@@ -166,7 +167,12 @@ static void st_rc_hardware_init(struct st_rc_device *dev)
/* Enable the IP */
reset_control_deassert(dev->rstc);
- clk_prepare_enable(dev->sys_clock);
+ ret = clk_prepare_enable(dev->sys_clock);
+ if (ret) {
+ dev_err(dev->dev, "Failed to prepare/enable system clock\n");
+ return ret;
+ }
+
baseclock = clk_get_rate(dev->sys_clock);
/* IRB input pins are inverted internally from high to low. */
@@ -184,6 +190,8 @@ static void st_rc_hardware_init(struct st_rc_device *dev)
}
writel(rx_max_symbol_per, dev->rx_base + IRB_MAX_SYM_PERIOD);
+
+ return 0;
}
static int st_rc_remove(struct platform_device *pdev)
@@ -287,7 +295,9 @@ static int st_rc_probe(struct platform_device *pdev)
rc_dev->dev = dev;
platform_set_drvdata(pdev, rc_dev);
- st_rc_hardware_init(rc_dev);
+ ret = st_rc_hardware_init(rc_dev);
+ if (ret)
+ goto err;
rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
/* rx sampling rate is 10Mhz */
@@ -359,6 +369,7 @@ static int st_rc_suspend(struct device *dev)
static int st_rc_resume(struct device *dev)
{
+ int ret;
struct st_rc_device *rc_dev = dev_get_drvdata(dev);
struct rc_dev *rdev = rc_dev->rdev;
@@ -367,7 +378,10 @@ static int st_rc_resume(struct device *dev)
rc_dev->irq_wake = 0;
} else {
pinctrl_pm_select_default_state(dev);
- st_rc_hardware_init(rc_dev);
+ ret = st_rc_hardware_init(rc_dev);
+ if (ret)
+ return ret;
+
if (rdev->users) {
writel(IRB_RX_INTS, rc_dev->rx_base + IRB_RX_INT_EN);
writel(0x01, rc_dev->rx_base + IRB_RX_EN);
diff --git a/drivers/media/rc/tango-ir.c b/drivers/media/rc/tango-ir.c
deleted file mode 100644
index b8eb5bc4d9be..000000000000
--- a/drivers/media/rc/tango-ir.c
+++ /dev/null
@@ -1,267 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2015 Mans Rullgard <mans@mansr.com>
- */
-
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/of.h>
-#include <media/rc-core.h>
-
-#define DRIVER_NAME "tango-ir"
-
-#define IR_NEC_CTRL 0x00
-#define IR_NEC_DATA 0x04
-#define IR_CTRL 0x08
-#define IR_RC5_CLK_DIV 0x0c
-#define IR_RC5_DATA 0x10
-#define IR_INT 0x14
-
-#define NEC_TIME_BASE 560
-#define RC5_TIME_BASE 1778
-
-#define RC6_CTRL 0x00
-#define RC6_CLKDIV 0x04
-#define RC6_DATA0 0x08
-#define RC6_DATA1 0x0c
-#define RC6_DATA2 0x10
-#define RC6_DATA3 0x14
-#define RC6_DATA4 0x18
-
-#define RC6_CARRIER 36000
-#define RC6_TIME_BASE 16
-
-#define NEC_CAP(n) ((n) << 24)
-#define GPIO_SEL(n) ((n) << 16)
-#define DISABLE_NEC (BIT(4) | BIT(8))
-#define ENABLE_RC5 (BIT(0) | BIT(9))
-#define ENABLE_RC6 (BIT(0) | BIT(7))
-#define ACK_IR_INT (BIT(0) | BIT(1))
-#define ACK_RC6_INT (BIT(31))
-
-#define NEC_ANY (RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32)
-
-struct tango_ir {
- void __iomem *rc5_base;
- void __iomem *rc6_base;
- struct rc_dev *rc;
- struct clk *clk;
-};
-
-static void tango_ir_handle_nec(struct tango_ir *ir)
-{
- u32 v, code;
- enum rc_proto proto;
-
- v = readl_relaxed(ir->rc5_base + IR_NEC_DATA);
- if (!v) {
- rc_repeat(ir->rc);
- return;
- }
-
- code = ir_nec_bytes_to_scancode(v, v >> 8, v >> 16, v >> 24, &proto);
- rc_keydown(ir->rc, proto, code, 0);
-}
-
-static void tango_ir_handle_rc5(struct tango_ir *ir)
-{
- u32 data, field, toggle, addr, cmd, code;
-
- data = readl_relaxed(ir->rc5_base + IR_RC5_DATA);
- if (data & BIT(31))
- return;
-
- field = data >> 12 & 1;
- toggle = data >> 11 & 1;
- addr = data >> 6 & 0x1f;
- cmd = (data & 0x3f) | (field ^ 1) << 6;
-
- code = RC_SCANCODE_RC5(addr, cmd);
- rc_keydown(ir->rc, RC_PROTO_RC5, code, toggle);
-}
-
-static void tango_ir_handle_rc6(struct tango_ir *ir)
-{
- u32 data0, data1, toggle, mode, addr, cmd, code;
-
- data0 = readl_relaxed(ir->rc6_base + RC6_DATA0);
- data1 = readl_relaxed(ir->rc6_base + RC6_DATA1);
-
- mode = data0 >> 1 & 7;
- if (mode != 0)
- return;
-
- toggle = data0 & 1;
- addr = data0 >> 16;
- cmd = data1;
-
- code = RC_SCANCODE_RC6_0(addr, cmd);
- rc_keydown(ir->rc, RC_PROTO_RC6_0, code, toggle);
-}
-
-static irqreturn_t tango_ir_irq(int irq, void *dev_id)
-{
- struct tango_ir *ir = dev_id;
- unsigned int rc5_stat;
- unsigned int rc6_stat;
-
- rc5_stat = readl_relaxed(ir->rc5_base + IR_INT);
- writel_relaxed(rc5_stat, ir->rc5_base + IR_INT);
-
- rc6_stat = readl_relaxed(ir->rc6_base + RC6_CTRL);
- writel_relaxed(rc6_stat, ir->rc6_base + RC6_CTRL);
-
- if (!(rc5_stat & 3) && !(rc6_stat & BIT(31)))
- return IRQ_NONE;
-
- if (rc5_stat & BIT(0))
- tango_ir_handle_rc5(ir);
-
- if (rc5_stat & BIT(1))
- tango_ir_handle_nec(ir);
-
- if (rc6_stat & BIT(31))
- tango_ir_handle_rc6(ir);
-
- return IRQ_HANDLED;
-}
-
-static int tango_change_protocol(struct rc_dev *dev, u64 *rc_type)
-{
- struct tango_ir *ir = dev->priv;
- u32 rc5_ctrl = DISABLE_NEC;
- u32 rc6_ctrl = 0;
-
- if (*rc_type & NEC_ANY)
- rc5_ctrl = 0;
-
- if (*rc_type & RC_PROTO_BIT_RC5)
- rc5_ctrl |= ENABLE_RC5;
-
- if (*rc_type & RC_PROTO_BIT_RC6_0)
- rc6_ctrl = ENABLE_RC6;
-
- writel_relaxed(rc5_ctrl, ir->rc5_base + IR_CTRL);
- writel_relaxed(rc6_ctrl, ir->rc6_base + RC6_CTRL);
-
- return 0;
-}
-
-static int tango_ir_probe(struct platform_device *pdev)
-{
- const char *map_name = RC_MAP_TANGO;
- struct device *dev = &pdev->dev;
- struct rc_dev *rc;
- struct tango_ir *ir;
- u64 clkrate, clkdiv;
- int irq, err;
- u32 val;
-
- irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return -EINVAL;
-
- ir = devm_kzalloc(dev, sizeof(*ir), GFP_KERNEL);
- if (!ir)
- return -ENOMEM;
-
- ir->rc5_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(ir->rc5_base))
- return PTR_ERR(ir->rc5_base);
-
- ir->rc6_base = devm_platform_ioremap_resource(pdev, 1);
- if (IS_ERR(ir->rc6_base))
- return PTR_ERR(ir->rc6_base);
-
- ir->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(ir->clk))
- return PTR_ERR(ir->clk);
-
- rc = devm_rc_allocate_device(dev, RC_DRIVER_SCANCODE);
- if (!rc)
- return -ENOMEM;
-
- of_property_read_string(dev->of_node, "linux,rc-map-name", &map_name);
-
- rc->device_name = DRIVER_NAME;
- rc->driver_name = DRIVER_NAME;
- rc->input_phys = DRIVER_NAME "/input0";
- rc->map_name = map_name;
- rc->allowed_protocols = NEC_ANY | RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_0;
- rc->change_protocol = tango_change_protocol;
- rc->priv = ir;
- ir->rc = rc;
-
- err = clk_prepare_enable(ir->clk);
- if (err)
- return err;
-
- clkrate = clk_get_rate(ir->clk);
-
- clkdiv = clkrate * NEC_TIME_BASE;
- do_div(clkdiv, 1000000);
-
- val = NEC_CAP(31) | GPIO_SEL(12) | clkdiv;
- writel_relaxed(val, ir->rc5_base + IR_NEC_CTRL);
-
- clkdiv = clkrate * RC5_TIME_BASE;
- do_div(clkdiv, 1000000);
-
- writel_relaxed(DISABLE_NEC, ir->rc5_base + IR_CTRL);
- writel_relaxed(clkdiv, ir->rc5_base + IR_RC5_CLK_DIV);
- writel_relaxed(ACK_IR_INT, ir->rc5_base + IR_INT);
-
- clkdiv = clkrate * RC6_TIME_BASE;
- do_div(clkdiv, RC6_CARRIER);
-
- writel_relaxed(ACK_RC6_INT, ir->rc6_base + RC6_CTRL);
- writel_relaxed((clkdiv >> 2) << 18 | clkdiv, ir->rc6_base + RC6_CLKDIV);
-
- err = devm_request_irq(dev, irq, tango_ir_irq, IRQF_SHARED,
- dev_name(dev), ir);
- if (err)
- goto err_clk;
-
- err = devm_rc_register_device(dev, rc);
- if (err)
- goto err_clk;
-
- platform_set_drvdata(pdev, ir);
- return 0;
-
-err_clk:
- clk_disable_unprepare(ir->clk);
- return err;
-}
-
-static int tango_ir_remove(struct platform_device *pdev)
-{
- struct tango_ir *ir = platform_get_drvdata(pdev);
-
- clk_disable_unprepare(ir->clk);
- return 0;
-}
-
-static const struct of_device_id tango_ir_dt_ids[] = {
- { .compatible = "sigma,smp8642-ir" },
- { }
-};
-MODULE_DEVICE_TABLE(of, tango_ir_dt_ids);
-
-static struct platform_driver tango_ir_driver = {
- .probe = tango_ir_probe,
- .remove = tango_ir_remove,
- .driver = {
- .name = DRIVER_NAME,
- .of_match_table = tango_ir_dt_ids,
- },
-};
-module_platform_driver(tango_ir_driver);
-
-MODULE_DESCRIPTION("SMP86xx IR decoder driver");
-MODULE_AUTHOR("Mans Rullgard <mans@mansr.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c
index 931ec0727cd3..e5094fff04c5 100644
--- a/drivers/media/spi/cxd2880-spi.c
+++ b/drivers/media/spi/cxd2880-spi.c
@@ -147,7 +147,7 @@ static int cxd2880_spi_read_ts(struct spi_device *spi,
ret = spi_sync(spi, &message);
if (ret)
- pr_err("spi_write_then_read failed\n");
+ pr_err("spi_sync failed\n");
return ret;
}
@@ -401,7 +401,7 @@ static int cxd2880_start_feed(struct dvb_demux_feed *feed)
dvb_spi,
"cxd2880_ts_read");
if (IS_ERR(dvb_spi->cxd2880_ts_read_thread)) {
- pr_err("kthread_run failed/\n");
+ pr_err("kthread_run failed\n");
kfree(dvb_spi->ts_buf);
dvb_spi->ts_buf = NULL;
memset(&dvb_spi->filter_config, 0,
@@ -448,7 +448,7 @@ static int cxd2880_stop_feed(struct dvb_demux_feed *feed)
* in dvb_spi->all_pid_feed_count.
*/
if (dvb_spi->all_pid_feed_count <= 0) {
- pr_err("PID %d not found.\n", feed->pid);
+ pr_err("PID %d not found\n", feed->pid);
return -EINVAL;
}
dvb_spi->all_pid_feed_count--;
@@ -485,7 +485,7 @@ static int cxd2880_stop_feed(struct dvb_demux_feed *feed)
ret_stop = kthread_stop(dvb_spi->cxd2880_ts_read_thread);
if (ret_stop) {
- pr_err("'kthread_stop failed. (%d)\n", ret_stop);
+ pr_err("kthread_stop failed. (%d)\n", ret_stop);
ret = ret_stop;
}
kfree(dvb_spi->ts_buf);
@@ -512,7 +512,7 @@ cxd2880_spi_probe(struct spi_device *spi)
struct cxd2880_config config;
if (!spi) {
- pr_err("invalid arg.\n");
+ pr_err("invalid arg\n");
return -EINVAL;
}
@@ -596,7 +596,7 @@ cxd2880_spi_probe(struct spi_device *spi)
ret = dvb_spi->demux.dmx.connect_frontend(&dvb_spi->demux.dmx,
&dvb_spi->dmx_fe);
if (ret < 0) {
- pr_err("dvb_register_frontend() failed\n");
+ pr_err("connect_frontend() failed\n");
goto fail_fe_conn;
}
diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c
index a24624353f9e..d714fe50afe5 100644
--- a/drivers/media/test-drivers/vim2m.c
+++ b/drivers/media/test-drivers/vim2m.c
@@ -624,11 +624,6 @@ static void device_work(struct work_struct *w)
curr_ctx = container_of(w, struct vim2m_ctx, work_run.work);
- if (!curr_ctx) {
- pr_err("Instance released before the end of transaction\n");
- return;
- }
-
vim2m_dev = curr_ctx->dev;
src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
diff --git a/drivers/media/test-drivers/vimc/vimc-debayer.c b/drivers/media/test-drivers/vimc/vimc-debayer.c
index c3f6fef34f68..2d06cdbacc76 100644
--- a/drivers/media/test-drivers/vimc/vimc-debayer.c
+++ b/drivers/media/test-drivers/vimc/vimc-debayer.c
@@ -150,17 +150,17 @@ static bool vimc_deb_src_code_is_valid(u32 code)
}
static int vimc_deb_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf;
unsigned int i;
- mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
*mf = sink_fmt_default;
for (i = 1; i < sd->entity.num_pads; i++) {
- mf = v4l2_subdev_get_try_format(sd, cfg, i);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, i);
*mf = sink_fmt_default;
mf->code = vdeb->src_code;
}
@@ -169,7 +169,7 @@ static int vimc_deb_init_cfg(struct v4l2_subdev *sd,
}
static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (VIMC_IS_SRC(code->pad)) {
@@ -188,7 +188,7 @@ static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd,
}
static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index)
@@ -213,14 +213,14 @@ static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd,
}
static int vimc_deb_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
/* Get the current sink format */
fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
- *v4l2_subdev_get_try_format(sd, cfg, 0) :
+ *v4l2_subdev_get_try_format(sd, sd_state, 0) :
vdeb->sink_fmt;
/* Set the right code for the source pad */
@@ -251,7 +251,7 @@ static void vimc_deb_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt)
}
static int vimc_deb_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
@@ -266,8 +266,8 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd,
sink_fmt = &vdeb->sink_fmt;
src_code = &vdeb->src_code;
} else {
- sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
- src_code = &v4l2_subdev_get_try_format(sd, cfg, 1)->code;
+ sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ src_code = &v4l2_subdev_get_try_format(sd, sd_state, 1)->code;
}
/*
diff --git a/drivers/media/test-drivers/vimc/vimc-scaler.c b/drivers/media/test-drivers/vimc/vimc-scaler.c
index 121fa7d62a2e..06880dd0b6ac 100644
--- a/drivers/media/test-drivers/vimc/vimc-scaler.c
+++ b/drivers/media/test-drivers/vimc/vimc-scaler.c
@@ -84,20 +84,20 @@ static void vimc_sca_adjust_sink_crop(struct v4l2_rect *r,
}
static int vimc_sca_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *mf;
struct v4l2_rect *r;
unsigned int i;
- mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
*mf = sink_fmt_default;
- r = v4l2_subdev_get_try_crop(sd, cfg, 0);
+ r = v4l2_subdev_get_try_crop(sd, sd_state, 0);
*r = crop_rect_default;
for (i = 1; i < sd->entity.num_pads; i++) {
- mf = v4l2_subdev_get_try_format(sd, cfg, i);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, i);
*mf = sink_fmt_default;
mf->width = mf->width * sca_mult;
mf->height = mf->height * sca_mult;
@@ -107,7 +107,7 @@ static int vimc_sca_init_cfg(struct v4l2_subdev *sd,
}
static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
u32 mbus_code = vimc_mbus_code_by_index(code->index);
@@ -128,7 +128,7 @@ static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd,
}
static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
const struct vimc_pix_map *vpix;
@@ -156,7 +156,7 @@ static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd,
}
static int vimc_sca_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
@@ -164,8 +164,8 @@ static int vimc_sca_get_fmt(struct v4l2_subdev *sd,
/* Get the current sink format */
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- format->format = *v4l2_subdev_get_try_format(sd, cfg, 0);
- crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
+ format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0);
+ crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0);
} else {
format->format = vsca->sink_fmt;
crop_rect = &vsca->crop_rect;
@@ -201,7 +201,7 @@ static void vimc_sca_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt)
}
static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
@@ -216,8 +216,8 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
sink_fmt = &vsca->sink_fmt;
crop_rect = &vsca->crop_rect;
} else {
- sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
- crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
+ sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0);
}
/*
@@ -254,7 +254,7 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
}
static int vimc_sca_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
@@ -268,8 +268,8 @@ static int vimc_sca_get_selection(struct v4l2_subdev *sd,
sink_fmt = &vsca->sink_fmt;
crop_rect = &vsca->crop_rect;
} else {
- sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
- crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
+ sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0);
}
switch (sel->target) {
@@ -287,7 +287,7 @@ static int vimc_sca_get_selection(struct v4l2_subdev *sd,
}
static int vimc_sca_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
@@ -305,8 +305,8 @@ static int vimc_sca_set_selection(struct v4l2_subdev *sd,
crop_rect = &vsca->crop_rect;
sink_fmt = &vsca->sink_fmt;
} else {
- crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
- sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+ crop_rect = v4l2_subdev_get_try_crop(sd, sd_state, 0);
+ sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
}
switch (sel->target) {
diff --git a/drivers/media/test-drivers/vimc/vimc-sensor.c b/drivers/media/test-drivers/vimc/vimc-sensor.c
index ba5db5a150b4..74ab79cadb5d 100644
--- a/drivers/media/test-drivers/vimc/vimc-sensor.c
+++ b/drivers/media/test-drivers/vimc/vimc-sensor.c
@@ -42,14 +42,14 @@ static const struct v4l2_mbus_framefmt fmt_default = {
};
static int vimc_sen_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
unsigned int i;
for (i = 0; i < sd->entity.num_pads; i++) {
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, cfg, i);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, i);
*mf = fmt_default;
}
@@ -57,7 +57,7 @@ static int vimc_sen_init_cfg(struct v4l2_subdev *sd,
}
static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
u32 mbus_code = vimc_mbus_code_by_index(code->index);
@@ -71,7 +71,7 @@ static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd,
}
static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
const struct vimc_pix_map *vpix;
@@ -93,14 +93,14 @@ static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd,
}
static int vimc_sen_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vimc_sen_device *vsen =
container_of(sd, struct vimc_sen_device, sd);
fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
- *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) :
+ *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) :
vsen->mbus_format;
return 0;
@@ -146,7 +146,7 @@ static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
}
static int vimc_sen_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct vimc_sen_device *vsen = v4l2_get_subdevdata(sd);
@@ -159,7 +159,7 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd,
mf = &vsen->mbus_format;
} else {
- mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
}
/* Set the new format */
diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c
index ca0ebf6ad9cc..d2bd2653cf54 100644
--- a/drivers/media/test-drivers/vivid/vivid-core.c
+++ b/drivers/media/test-drivers/vivid/vivid-core.c
@@ -656,6 +656,46 @@ static const struct v4l2_file_operations vivid_radio_fops = {
.unlocked_ioctl = video_ioctl2,
};
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct video_device *vdev = video_devdata(file);
+ int r;
+
+ /*
+ * Sliced and raw VBI capture share the same queue so we must
+ * change the type.
+ */
+ if (p->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ||
+ p->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ r = vb2_queue_change_type(vdev->queue, p->type);
+ if (r)
+ return r;
+ }
+
+ return vb2_ioctl_reqbufs(file, priv, p);
+}
+
+static int vidioc_create_bufs(struct file *file, void *priv,
+ struct v4l2_create_buffers *p)
+{
+ struct video_device *vdev = video_devdata(file);
+ int r;
+
+ /*
+ * Sliced and raw VBI capture share the same queue so we must
+ * change the type.
+ */
+ if (p->format.type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ||
+ p->format.type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ r = vb2_queue_change_type(vdev->queue, p->format.type);
+ if (r)
+ return r;
+ }
+
+ return vb2_ioctl_create_bufs(file, priv, p);
+}
+
static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
@@ -717,8 +757,8 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_g_fbuf = vidioc_g_fbuf,
.vidioc_s_fbuf = vidioc_s_fbuf,
- .vidioc_reqbufs = vb2_ioctl_reqbufs,
- .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_create_bufs = vidioc_create_bufs,
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf,
diff --git a/drivers/media/test-drivers/vivid/vivid-core.h b/drivers/media/test-drivers/vivid/vivid-core.h
index cdff6cd264d0..1e3c4f5a9413 100644
--- a/drivers/media/test-drivers/vivid/vivid-core.h
+++ b/drivers/media/test-drivers/vivid/vivid-core.h
@@ -429,7 +429,6 @@ struct vivid_dev {
u32 vbi_cap_seq_start;
u32 vbi_cap_seq_count;
bool vbi_cap_streaming;
- bool stream_sliced_vbi_cap;
u32 meta_cap_seq_start;
u32 meta_cap_seq_count;
bool meta_cap_streaming;
diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
index c0dc609c1358..9da730ccfa94 100644
--- a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
@@ -752,7 +752,7 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev,
v4l2_ctrl_request_setup(vbi_cap_buf->vb.vb2_buf.req_obj.req,
&dev->ctrl_hdl_vbi_cap);
- if (dev->stream_sliced_vbi_cap)
+ if (vbi_cap_buf->vb.vb2_buf.type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
vivid_sliced_vbi_cap_process(dev, vbi_cap_buf);
else
vivid_raw_vbi_cap_process(dev, vbi_cap_buf);
diff --git a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
index a1e52708b7ca..265db2114671 100644
--- a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
@@ -455,7 +455,6 @@ int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f)
f->fmt.sdr.pixelformat = dev->sdr_pixelformat;
f->fmt.sdr.buffersize = dev->sdr_buffersize;
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
return 0;
}
@@ -468,7 +467,6 @@ int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f)
if (vb2_is_busy(q))
return -EBUSY;
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
for (i = 0; i < ARRAY_SIZE(formats); i++) {
if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
dev->sdr_pixelformat = formats[i].pixelformat;
@@ -488,7 +486,6 @@ int vidioc_try_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f)
{
int i;
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
for (i = 0; i < ARRAY_SIZE(formats); i++) {
if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
f->fmt.sdr.buffersize = formats[i].buffersize;
diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c
index 1a9348eea781..b65b02eeeb97 100644
--- a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c
@@ -255,10 +255,8 @@ int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
if (ret)
return ret;
- if (dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q))
+ if (f->type != V4L2_BUF_TYPE_VBI_CAPTURE && vb2_is_busy(&dev->vb_vbi_cap_q))
return -EBUSY;
- dev->stream_sliced_vbi_cap = false;
- dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_VBI_CAPTURE;
return 0;
}
@@ -322,11 +320,9 @@ int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format
if (ret)
return ret;
- if (!dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q))
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE && vb2_is_busy(&dev->vb_vbi_cap_q))
return -EBUSY;
dev->service_set_cap = vbi->service_set;
- dev->stream_sliced_vbi_cap = true;
- dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
return 0;
}
diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig
index 00feadb217d8..f97153df3c84 100644
--- a/drivers/media/usb/Kconfig
+++ b/drivers/media/usb/Kconfig
@@ -1,10 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-# This Kconfig option is also used by the legacy av7110 driver
-config TTPCI_EEPROM
- tristate
- depends on I2C
-
if USB && MEDIA_SUPPORT
menuconfig MEDIA_USB_SUPPORT
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
index 751703db06f5..7a81be7970b2 100644
--- a/drivers/media/usb/airspy/airspy.c
+++ b/drivers/media/usb/airspy/airspy.c
@@ -632,7 +632,6 @@ static int airspy_g_fmt_sdr_cap(struct file *file, void *priv,
f->fmt.sdr.pixelformat = s->pixelformat;
f->fmt.sdr.buffersize = s->buffersize;
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
return 0;
}
@@ -647,7 +646,6 @@ static int airspy_s_fmt_sdr_cap(struct file *file, void *priv,
if (vb2_is_busy(q))
return -EBUSY;
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
for (i = 0; i < NUM_FORMATS; i++) {
if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
s->pixelformat = formats[i].pixelformat;
@@ -670,7 +668,6 @@ static int airspy_try_fmt_sdr_cap(struct file *file, void *priv,
{
int i;
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
for (i = 0; i < NUM_FORMATS; i++) {
if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
f->fmt.sdr.buffersize = formats[i].buffersize;
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index a8a72d5fbd12..caefac07af92 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -199,8 +199,8 @@ static int au0828_media_device_init(struct au0828_dev *dev,
struct media_device *mdev;
mdev = media_device_usb_allocate(udev, KBUILD_MODNAME, THIS_MODULE);
- if (!mdev)
- return -ENOMEM;
+ if (IS_ERR(mdev))
+ return PTR_ERR(mdev);
dev->media_dev = mdev;
#endif
diff --git a/drivers/media/usb/cpia2/cpia2.h b/drivers/media/usb/cpia2/cpia2.h
index 50835f5f7512..57b7f1ea68da 100644
--- a/drivers/media/usb/cpia2/cpia2.h
+++ b/drivers/media/usb/cpia2/cpia2.h
@@ -429,6 +429,7 @@ int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd);
int cpia2_do_command(struct camera_data *cam,
unsigned int command,
unsigned char direction, unsigned char param);
+void cpia2_deinit_camera_struct(struct camera_data *cam, struct usb_interface *intf);
struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf);
int cpia2_init_camera(struct camera_data *cam);
int cpia2_allocate_buffers(struct camera_data *cam);
diff --git a/drivers/media/usb/cpia2/cpia2_core.c b/drivers/media/usb/cpia2/cpia2_core.c
index e747548ab286..b5a2d06fb356 100644
--- a/drivers/media/usb/cpia2/cpia2_core.c
+++ b/drivers/media/usb/cpia2/cpia2_core.c
@@ -2167,6 +2167,18 @@ static void reset_camera_struct(struct camera_data *cam)
*
* cpia2_init_camera_struct
*
+ * Deinitialize camera struct
+ *****************************************************************************/
+void cpia2_deinit_camera_struct(struct camera_data *cam, struct usb_interface *intf)
+{
+ v4l2_device_unregister(&cam->v4l2_dev);
+ kfree(cam);
+}
+
+/******************************************************************************
+ *
+ * cpia2_init_camera_struct
+ *
* Initializes camera struct, does not call reset to fill in defaults.
*****************************************************************************/
struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf)
diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c
index 3ab80a7b4498..76aac06f9fb8 100644
--- a/drivers/media/usb/cpia2/cpia2_usb.c
+++ b/drivers/media/usb/cpia2/cpia2_usb.c
@@ -844,15 +844,13 @@ static int cpia2_usb_probe(struct usb_interface *intf,
ret = set_alternate(cam, USBIF_CMDONLY);
if (ret < 0) {
ERR("%s: usb_set_interface error (ret = %d)\n", __func__, ret);
- kfree(cam);
- return ret;
+ goto alt_err;
}
if((ret = cpia2_init_camera(cam)) < 0) {
ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret);
- kfree(cam);
- return ret;
+ goto alt_err;
}
LOG(" CPiA Version: %d.%02d (%d.%d)\n",
cam->params.version.firmware_revision_hi,
@@ -872,11 +870,14 @@ static int cpia2_usb_probe(struct usb_interface *intf,
ret = cpia2_register_camera(cam);
if (ret < 0) {
ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret);
- kfree(cam);
- return ret;
+ goto alt_err;
}
return 0;
+
+alt_err:
+ cpia2_deinit_camera_struct(cam, intf);
+ return ret;
}
/******************************************************************************
diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c
index 69d5c628a797..926ecfc9b64a 100644
--- a/drivers/media/usb/cpia2/cpia2_v4l.c
+++ b/drivers/media/usb/cpia2/cpia2_v4l.c
@@ -140,10 +140,10 @@ static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
loff_t *off)
{
struct camera_data *cam = video_drvdata(file);
- int noblock = file->f_flags&O_NONBLOCK;
+ int noblock = file->f_flags & O_NONBLOCK;
ssize_t ret;
- if(!cam)
+ if (!cam)
return -EINVAL;
if (mutex_lock_interruptible(&cam->v4l2_lock))
@@ -153,7 +153,6 @@ static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
return ret;
}
-
/******************************************************************************
*
* cpia2_v4l_poll
@@ -170,7 +169,6 @@ static __poll_t cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait
return res;
}
-
static int sync(struct camera_data *cam, int frame_nr)
{
struct framebuf *frame = &cam->buffers[frame_nr];
@@ -247,8 +245,8 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v
break;
}
- if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0)
- memset(vc->bus_info,0, sizeof(vc->bus_info));
+ if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) < 0)
+ memset(vc->bus_info, 0, sizeof(vc->bus_info));
return 0;
}
@@ -289,7 +287,7 @@ static int cpia2_s_input(struct file *file, void *fh, unsigned int i)
*****************************************************************************/
static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_fmtdesc *f)
+ struct v4l2_fmtdesc *f)
{
if (f->index > 1)
return -EINVAL;
@@ -310,13 +308,13 @@ static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh,
*****************************************************************************/
static int cpia2_try_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct camera_data *cam = video_drvdata(file);
if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG &&
f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
+ return -EINVAL;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.bytesperline = 0;
@@ -371,19 +369,20 @@ static int cpia2_try_fmt_vid_cap(struct file *file, void *fh,
*****************************************************************************/
static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct camera_data *cam = video_drvdata(file);
int err, frame;
err = cpia2_try_fmt_vid_cap(file, _fh, f);
- if(err != 0)
+ if (err != 0)
return err;
cam->pixelformat = f->fmt.pix.pixelformat;
/* NOTE: This should be set to 1 for MJPEG, but some apps don't handle
- * the missing Huffman table properly. */
+ * the missing Huffman table properly.
+ */
cam->params.compression.inhibit_htables = 0;
/*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/
@@ -421,7 +420,7 @@ static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh,
*****************************************************************************/
static int cpia2_g_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct camera_data *cam = video_drvdata(file);
@@ -547,9 +546,8 @@ static const struct {
};
static int cpia2_enum_framesizes(struct file *file, void *fh,
- struct v4l2_frmsizeenum *fsize)
+ struct v4l2_frmsizeenum *fsize)
{
-
if (fsize->pixel_format != V4L2_PIX_FMT_MJPEG &&
fsize->pixel_format != V4L2_PIX_FMT_JPEG)
return -EINVAL;
@@ -563,7 +561,7 @@ static int cpia2_enum_framesizes(struct file *file, void *fh,
}
static int cpia2_enum_frameintervals(struct file *file, void *fh,
- struct v4l2_frmivalenum *fival)
+ struct v4l2_frmivalenum *fival)
{
struct camera_data *cam = video_drvdata(file);
int max = ARRAY_SIZE(framerate_controls) - 1;
@@ -665,19 +663,18 @@ static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompres
parms->quality = 80; // TODO: Can this be made meaningful?
parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI;
- if(!cam->params.compression.inhibit_htables) {
+ if (!cam->params.compression.inhibit_htables)
parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT;
- }
parms->APPn = cam->APPn;
parms->APP_len = cam->APP_len;
- if(cam->APP_len > 0) {
+ if (cam->APP_len > 0) {
memcpy(parms->APP_data, cam->APP_data, cam->APP_len);
parms->jpeg_markers |= V4L2_JPEG_MARKER_APP;
}
parms->COM_len = cam->COM_len;
- if(cam->COM_len > 0) {
+ if (cam->COM_len > 0) {
memcpy(parms->COM_data, cam->COM_data, cam->COM_len);
parms->jpeg_markers |= JPEG_MARKER_COM;
}
@@ -698,7 +695,7 @@ static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompres
*****************************************************************************/
static int cpia2_s_jpegcomp(struct file *file, void *fh,
- const struct v4l2_jpegcompression *parms)
+ const struct v4l2_jpegcompression *parms)
{
struct camera_data *cam = video_drvdata(file);
@@ -708,9 +705,9 @@ static int cpia2_s_jpegcomp(struct file *file, void *fh,
cam->params.compression.inhibit_htables =
!(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT);
- if(parms->APP_len != 0) {
- if(parms->APP_len > 0 &&
- parms->APP_len <= sizeof(cam->APP_data) &&
+ if (parms->APP_len != 0) {
+ if (parms->APP_len > 0 &&
+ parms->APP_len <= sizeof(cam->APP_data) &&
parms->APPn >= 0 && parms->APPn <= 15) {
cam->APPn = parms->APPn;
cam->APP_len = parms->APP_len;
@@ -724,9 +721,9 @@ static int cpia2_s_jpegcomp(struct file *file, void *fh,
cam->APP_len = 0;
}
- if(parms->COM_len != 0) {
- if(parms->COM_len > 0 &&
- parms->COM_len <= sizeof(cam->COM_data)) {
+ if (parms->COM_len != 0) {
+ if (parms->COM_len > 0 &&
+ parms->COM_len <= sizeof(cam->COM_data)) {
cam->COM_len = parms->COM_len;
memcpy(cam->COM_data, parms->COM_data, parms->COM_len);
} else {
@@ -751,8 +748,8 @@ static int cpia2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers
{
struct camera_data *cam = video_drvdata(file);
- if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- req->memory != V4L2_MEMORY_MMAP)
+ if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ req->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames);
@@ -774,8 +771,8 @@ static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{
struct camera_data *cam = video_drvdata(file);
- if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- buf->index >= cam->num_frames)
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ buf->index >= cam->num_frames)
return -EINVAL;
buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
@@ -783,7 +780,7 @@ static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
buf->memory = V4L2_MEMORY_MMAP;
- if(cam->mmapped)
+ if (cam->mmapped)
buf->flags = V4L2_BUF_FLAG_MAPPED;
else
buf->flags = 0;
@@ -806,8 +803,8 @@ static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
}
DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n",
- buf->index, buf->m.offset, buf->flags, buf->sequence,
- buf->bytesused);
+ buf->index, buf->m.offset, buf->flags, buf->sequence,
+ buf->bytesused);
return 0;
}
@@ -824,14 +821,14 @@ static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{
struct camera_data *cam = video_drvdata(file);
- if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- buf->memory != V4L2_MEMORY_MMAP ||
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ buf->memory != V4L2_MEMORY_MMAP ||
buf->index >= cam->num_frames)
return -EINVAL;
DBG("QBUF #%d\n", buf->index);
- if(cam->buffers[buf->index].status == FRAME_READY)
+ if (cam->buffers[buf->index].status == FRAME_READY)
cam->buffers[buf->index].status = FRAME_EMPTY;
return 0;
@@ -849,9 +846,10 @@ static int find_earliest_filled_buffer(struct camera_data *cam)
{
int i;
int found = -1;
- for (i=0; i<cam->num_frames; i++) {
- if(cam->buffers[i].status == FRAME_READY) {
- if(found < 0) {
+
+ for (i = 0; i < cam->num_frames; i++) {
+ if (cam->buffers[i].status == FRAME_READY) {
+ if (found < 0) {
found = i;
} else {
/* find which buffer is earlier */
@@ -876,22 +874,23 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
struct camera_data *cam = video_drvdata(file);
int frame;
- if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- buf->memory != V4L2_MEMORY_MMAP)
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ buf->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
frame = find_earliest_filled_buffer(cam);
- if(frame < 0 && file->f_flags&O_NONBLOCK)
+ if (frame < 0 && file->f_flags & O_NONBLOCK)
return -EAGAIN;
- if(frame < 0) {
+ if (frame < 0) {
/* Wait for a frame to become available */
- struct framebuf *cb=cam->curbuff;
+ struct framebuf *cb = cam->curbuff;
+
mutex_unlock(&cam->v4l2_lock);
wait_event_interruptible(cam->wq_stream,
!video_is_registered(&cam->vdev) ||
- (cb=cam->curbuff)->status == FRAME_READY);
+ (cb = cam->curbuff)->status == FRAME_READY);
mutex_lock(&cam->v4l2_lock);
if (signal_pending(current))
return -ERESTARTSYS;
@@ -900,7 +899,6 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
frame = cb->num;
}
-
buf->index = frame;
buf->bytesused = cam->buffers[buf->index].length;
buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE
@@ -931,7 +929,7 @@ static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
if (!cam->streaming) {
ret = cpia2_usb_stream_start(cam,
- cam->params.camera_state.stream_mode);
+ cam->params.camera_state.stream_mode);
if (!ret)
v4l2_ctrl_grab(cam->usb_alt, true);
}
@@ -969,7 +967,7 @@ static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
return -ERESTARTSYS;
retval = cpia2_remap_buffer(cam, area);
- if(!retval)
+ if (!retval)
cam->stream_fh = file->private_data;
mutex_unlock(&cam->v4l2_lock);
return retval;
@@ -1080,39 +1078,42 @@ int cpia2_register_camera(struct camera_data *cam)
v4l2_ctrl_handler_init(hdl, 12);
v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_BRIGHTNESS,
- cam->params.pnp_id.device_type == DEVICE_STV_672 ? 1 : 0,
- 255, 1, DEFAULT_BRIGHTNESS);
+ V4L2_CID_BRIGHTNESS,
+ cam->params.pnp_id.device_type == DEVICE_STV_672 ? 1 : 0,
+ 255, 1, DEFAULT_BRIGHTNESS);
v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 255, 1, DEFAULT_CONTRAST);
+ V4L2_CID_CONTRAST, 0, 255, 1, DEFAULT_CONTRAST);
v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_SATURATION, 0, 255, 1, DEFAULT_SATURATION);
+ V4L2_CID_SATURATION, 0, 255, 1, DEFAULT_SATURATION);
v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_JPEG_ACTIVE_MARKER, 0,
- V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
- V4L2_JPEG_ACTIVE_MARKER_DHT);
+ V4L2_CID_JPEG_ACTIVE_MARKER, 0,
+ V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
+ V4L2_JPEG_ACTIVE_MARKER_DHT);
v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_JPEG_COMPRESSION_QUALITY, 1,
- 100, 1, 100);
+ V4L2_CID_JPEG_COMPRESSION_QUALITY, 1,
+ 100, 1, 100);
cpia2_usb_alt.def = alternate;
cam->usb_alt = v4l2_ctrl_new_custom(hdl, &cpia2_usb_alt, NULL);
/* VP5 Only */
if (cam->params.pnp_id.device_type != DEVICE_STV_672)
v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
/* Flicker control only valid for 672 */
if (cam->params.pnp_id.device_type == DEVICE_STV_672)
v4l2_ctrl_new_std_menu(hdl, &cpia2_ctrl_ops,
- V4L2_CID_POWER_LINE_FREQUENCY,
- V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0);
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+ 0, 0);
/* Light control only valid for the QX5 Microscope */
if (cam->params.pnp_id.product == 0x151) {
cam->top_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0);
+ V4L2_CID_ILLUMINATORS_1,
+ 0, 1, 1, 0);
cam->bottom_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0);
+ V4L2_CID_ILLUMINATORS_2,
+ 0, 1, 1, 0);
v4l2_ctrl_cluster(2, &cam->top_light);
}
@@ -1159,28 +1160,28 @@ void cpia2_unregister_camera(struct camera_data *cam)
*****************************************************************************/
static void __init check_parameters(void)
{
- if(buffer_size < PAGE_SIZE) {
+ if (buffer_size < PAGE_SIZE) {
buffer_size = PAGE_SIZE;
LOG("buffer_size too small, setting to %d\n", buffer_size);
- } else if(buffer_size > 1024*1024) {
+ } else if (buffer_size > 1024 * 1024) {
/* arbitrary upper limiit */
- buffer_size = 1024*1024;
+ buffer_size = 1024 * 1024;
LOG("buffer_size ridiculously large, setting to %d\n",
buffer_size);
} else {
- buffer_size += PAGE_SIZE-1;
- buffer_size &= ~(PAGE_SIZE-1);
+ buffer_size += PAGE_SIZE - 1;
+ buffer_size &= ~(PAGE_SIZE - 1);
}
- if(num_buffers < 1) {
+ if (num_buffers < 1) {
num_buffers = 1;
LOG("num_buffers too small, setting to %d\n", num_buffers);
- } else if(num_buffers > VIDEO_MAX_FRAME) {
+ } else if (num_buffers > VIDEO_MAX_FRAME) {
num_buffers = VIDEO_MAX_FRAME;
LOG("num_buffers too large, setting to %d\n", num_buffers);
}
- if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) {
+ if (alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) {
alternate = DEFAULT_ALT;
LOG("alternate specified is invalid, using %d\n", alternate);
}
@@ -1197,7 +1198,6 @@ static void __init check_parameters(void)
/************ Module Stuff ***************/
-
/******************************************************************************
*
* cpia2_init/module_init
@@ -1211,7 +1211,6 @@ static int __init cpia2_init(void)
return cpia2_usb_init();
}
-
/******************************************************************************
*
* cpia2_exit/module_exit
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index 1b6d4e4c52ca..fe4d886442a4 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -1122,11 +1122,6 @@ static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
return ret;
}
-static int lme2510_get_adapter_count(struct dvb_usb_device *d)
-{
- return 1;
-}
-
static int lme2510_identify_state(struct dvb_usb_device *d, const char **name)
{
struct lme2510_state *st = d->priv;
@@ -1211,12 +1206,12 @@ static struct dvb_usb_device_properties lme2510_props = {
.frontend_attach = dm04_lme2510_frontend_attach,
.tuner_attach = dm04_lme2510_tuner,
.get_stream_config = lme2510_get_stream_config,
- .get_adapter_count = lme2510_get_adapter_count,
.streaming_ctrl = lme2510_streaming_ctrl,
.get_rc_config = lme2510_get_rc_config,
.exit = lme2510_exit,
+ .num_adapters = 1,
.adapter = {
{
.caps = DVB_USB_ADAP_HAS_PID_FILTER|
@@ -1227,8 +1222,6 @@ static struct dvb_usb_device_properties lme2510_props = {
.stream =
DVB_USB_STREAM_BULK(0x86, 10, 4096),
},
- {
- }
},
};
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 97ed17a141bb..83705730e37e 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -612,8 +612,9 @@ static int rtl28xxu_read_config(struct dvb_usb_device *d)
static int rtl28xxu_identify_state(struct dvb_usb_device *d, const char **name)
{
struct rtl28xxu_dev *dev = d_to_priv(d);
+ u8 buf[1];
int ret;
- struct rtl28xxu_req req_demod_i2c = {0x0020, CMD_I2C_DA_RD, 0, NULL};
+ struct rtl28xxu_req req_demod_i2c = {0x0020, CMD_I2C_DA_RD, 1, buf};
dev_dbg(&d->intf->dev, "\n");
@@ -1776,7 +1777,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
ir_raw_event_store_with_filter(d->rc_dev, &ev);
}
- /* 'flush' ir_raw_event_store_with_filter() */
+ /* 'flush' ir_raw_event_store_with_filter() */
ir_raw_event_handle(d->rc_dev);
exit:
return ret;
diff --git a/drivers/media/usb/dvb-usb/Makefile b/drivers/media/usb/dvb-usb/Makefile
index 28e4806a87cd..c22514948db2 100644
--- a/drivers/media/usb/dvb-usb/Makefile
+++ b/drivers/media/usb/dvb-usb/Makefile
@@ -83,4 +83,4 @@ obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o
ccflags-y += -I$(srctree)/drivers/media/dvb-frontends/
# due to tuner-xc3028
ccflags-y += -I$(srctree)/drivers/media/tuners
-ccflags-y += -I$(srctree)/drivers/media/pci/ttpci
+ccflags-y += -I$(srctree)/drivers/media/common
diff --git a/drivers/media/usb/dvb-usb/cinergyT2-core.c b/drivers/media/usb/dvb-usb/cinergyT2-core.c
index 969a7ec71dff..23f1093d28f8 100644
--- a/drivers/media/usb/dvb-usb/cinergyT2-core.c
+++ b/drivers/media/usb/dvb-usb/cinergyT2-core.c
@@ -29,10 +29,8 @@ struct cinergyt2_state {
unsigned char data[64];
};
-/* We are missing a release hook with usb_device data */
-static struct dvb_usb_device *cinergyt2_usb_device;
-
-static struct dvb_usb_device_properties cinergyt2_properties;
+/* Forward declaration */
+static const struct dvb_usb_device_properties cinergyt2_properties;
static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable)
{
@@ -78,13 +76,12 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
ret = dvb_usb_generic_rw(d, st->data, 1, st->data, 3, 0);
if (ret < 0) {
+ if (adap->fe_adap[0].fe)
+ adap->fe_adap[0].fe->ops.release(adap->fe_adap[0].fe);
deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep state info\n");
}
mutex_unlock(&d->data_mutex);
- /* Copy this pointer as we are gonna need it in the release phase */
- cinergyt2_usb_device = adap->dev;
-
return ret;
}
@@ -203,7 +200,7 @@ static struct usb_device_id cinergyt2_usb_table[] = {
MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table);
-static struct dvb_usb_device_properties cinergyt2_properties = {
+static const struct dvb_usb_device_properties cinergyt2_properties = {
.size_of_priv = sizeof(struct cinergyt2_state),
.num_adapters = 1,
.adapter = {
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index 761992ad05e2..7707de7bae7c 100644
--- a/drivers/media/usb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -1947,7 +1947,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
.size_of_priv = sizeof(struct cxusb_state),
- .num_adapters = 2,
+ .num_adapters = 1,
.adapter = {
{
.num_frontends = 1,
diff --git a/drivers/media/usb/dvb-usb/dtv5100.c b/drivers/media/usb/dvb-usb/dtv5100.c
index fba06932a9e0..1c13e493322c 100644
--- a/drivers/media/usb/dvb-usb/dtv5100.c
+++ b/drivers/media/usb/dvb-usb/dtv5100.c
@@ -26,6 +26,7 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
{
struct dtv5100_state *st = d->priv;
+ unsigned int pipe;
u8 request;
u8 type;
u16 value;
@@ -34,6 +35,7 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
switch (wlen) {
case 1:
/* write { reg }, read { value } */
+ pipe = usb_rcvctrlpipe(d->udev, 0);
request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ :
DTV5100_TUNER_READ);
type = USB_TYPE_VENDOR | USB_DIR_IN;
@@ -41,6 +43,7 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
break;
case 2:
/* write { reg, value } */
+ pipe = usb_sndctrlpipe(d->udev, 0);
request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE :
DTV5100_TUNER_WRITE);
type = USB_TYPE_VENDOR | USB_DIR_OUT;
@@ -54,7 +57,7 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr,
memcpy(st->data, rbuf, rlen);
msleep(1); /* avoid I2C errors */
- return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request,
+ return usb_control_msg(d->udev, pipe, request,
type, value, index, st->data, rlen,
DTV5100_USB_TIMEOUT);
}
@@ -141,7 +144,7 @@ static int dtv5100_probe(struct usb_interface *intf,
/* initialize non qt1010/zl10353 part? */
for (i = 0; dtv5100_init[i].request; i++) {
- ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
dtv5100_init[i].request,
USB_TYPE_VENDOR | USB_DIR_OUT,
dtv5100_init[i].value,
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index ba9292e2a587..c1e0dccb7408 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -4065,15 +4065,15 @@ static int em28xx_usb_probe(struct usb_interface *intf,
dev->dev_next->dvb_max_pkt_size_isoc = dev->dvb_max_pkt_size_isoc_ts2;
dev->dev_next->dvb_alt_isoc = dev->dvb_alt_isoc;
- /* Configuare hardware to support TS2*/
+ /* Configure hardware to support TS2*/
if (dev->dvb_xfer_bulk) {
- /* The ep4 and ep5 are configuared for BULK */
+ /* The ep4 and ep5 are configured for BULK */
em28xx_write_reg(dev, 0x0b, 0x96);
mdelay(100);
em28xx_write_reg(dev, 0x0b, 0x80);
mdelay(100);
} else {
- /* The ep4 and ep5 are configuared for ISO */
+ /* The ep4 and ep5 are configured for ISO */
em28xx_write_reg(dev, 0x0b, 0x96);
mdelay(100);
em28xx_write_reg(dev, 0x0b, 0x82);
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 5aa15a7a49de..59529cbf9cd0 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -720,7 +720,8 @@ static int em28xx_ir_init(struct em28xx *dev)
dev->board.has_ir_i2c = 0;
dev_warn(&dev->intf->dev,
"No i2c IR remote control device found.\n");
- return -ENODEV;
+ err = -ENODEV;
+ goto ref_put;
}
}
@@ -735,7 +736,7 @@ static int em28xx_ir_init(struct em28xx *dev)
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
if (!ir)
- return -ENOMEM;
+ goto ref_put;
rc = rc_allocate_device(RC_DRIVER_SCANCODE);
if (!rc)
goto error;
@@ -839,6 +840,9 @@ error:
dev->ir = NULL;
rc_free_device(rc);
kfree(ir);
+ref_put:
+ em28xx_shutdown_buttons(dev);
+ kref_put(&dev->ref, em28xx_free_device);
return err;
}
diff --git a/drivers/media/usb/go7007/s2250-board.c b/drivers/media/usb/go7007/s2250-board.c
index b9e45124673b..c742cc88fac5 100644
--- a/drivers/media/usb/go7007/s2250-board.c
+++ b/drivers/media/usb/go7007/s2250-board.c
@@ -398,7 +398,7 @@ static int s2250_s_ctrl(struct v4l2_ctrl *ctrl)
}
static int s2250_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c
index d93d384286c1..46ed95483e22 100644
--- a/drivers/media/usb/gspca/cpia1.c
+++ b/drivers/media/usb/gspca/cpia1.c
@@ -365,8 +365,9 @@ struct sd {
static const struct v4l2_pix_format mode[] = {
{160, 120, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,
/* The sizeimage is trial and error, as with low framerates
- the camera will pad out usb frames, making the image
- data larger then strictly necessary */
+ * the camera will pad out usb frames, making the image
+ * data larger than strictly necessary
+ */
.bytesperline = 160,
.sizeimage = 65536,
.colorspace = V4L2_COLORSPACE_SRGB,
diff --git a/drivers/media/usb/gspca/gl860/gl860.c b/drivers/media/usb/gspca/gl860/gl860.c
index 2c05ea2598e7..ce4ee8bc75c8 100644
--- a/drivers/media/usb/gspca/gl860/gl860.c
+++ b/drivers/media/usb/gspca/gl860/gl860.c
@@ -561,8 +561,8 @@ int gl860_RTx(struct gspca_dev *gspca_dev,
len, 400 + 200 * (len > 1));
memcpy(pdata, gspca_dev->usb_buf, len);
} else {
- r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- req, pref, val, index, NULL, len, 400);
+ gspca_err(gspca_dev, "zero-length read request\n");
+ r = -EINVAL;
}
}
diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c
index cd6776c3163b..bffa94e76da5 100644
--- a/drivers/media/usb/gspca/ov519.c
+++ b/drivers/media/usb/gspca/ov519.c
@@ -614,7 +614,7 @@ static const struct ov_i2c_regvals norm_3620b[] = {
/*
* From the datasheet: "Note that after writing to register COMH
* (0x12) to change the sensor mode, registers related to the
- * sensor’s cropping window will be reset back to their default
+ * sensor's cropping window will be reset back to their default
* values."
*
* "wait 4096 external clock ... to make sure the sensor is
diff --git a/drivers/media/usb/gspca/sq905.c b/drivers/media/usb/gspca/sq905.c
index 949111070971..32504ebcfd4d 100644
--- a/drivers/media/usb/gspca/sq905.c
+++ b/drivers/media/usb/gspca/sq905.c
@@ -116,7 +116,7 @@ static int sq905_command(struct gspca_dev *gspca_dev, u16 index)
}
ret = usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
USB_REQ_SYNCH_FRAME, /* request */
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
SQ905_PING, 0, gspca_dev->usb_buf, 1,
diff --git a/drivers/media/usb/gspca/sunplus.c b/drivers/media/usb/gspca/sunplus.c
index ace3da40006e..971dee0a56da 100644
--- a/drivers/media/usb/gspca/sunplus.c
+++ b/drivers/media/usb/gspca/sunplus.c
@@ -242,6 +242,10 @@ static void reg_r(struct gspca_dev *gspca_dev,
gspca_err(gspca_dev, "reg_r: buffer overflow\n");
return;
}
+ if (len == 0) {
+ gspca_err(gspca_dev, "reg_r: zero-length read\n");
+ return;
+ }
if (gspca_dev->usb_err < 0)
return;
ret = usb_control_msg(gspca_dev->dev,
@@ -250,7 +254,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, /* value */
index,
- len ? gspca_dev->usb_buf : NULL, len,
+ gspca_dev->usb_buf, len,
500);
if (ret < 0) {
pr_err("reg_r err %d\n", ret);
@@ -727,7 +731,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
case MegaImageVI:
reg_w_riv(gspca_dev, 0xf0, 0, 0);
spca504B_WaitCmdStatus(gspca_dev);
- reg_r(gspca_dev, 0xf0, 4, 0);
+ reg_w_riv(gspca_dev, 0xf0, 4, 0);
spca504B_WaitCmdStatus(gspca_dev);
break;
default:
diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
index cec841ad7495..3e535be2c520 100644
--- a/drivers/media/usb/hackrf/hackrf.c
+++ b/drivers/media/usb/hackrf/hackrf.c
@@ -929,7 +929,6 @@ static int hackrf_s_fmt_sdr(struct file *file, void *priv,
if (vb2_is_busy(q))
return -EBUSY;
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
for (i = 0; i < NUM_FORMATS; i++) {
if (f->fmt.sdr.pixelformat == formats[i].pixelformat) {
dev->pixelformat = formats[i].pixelformat;
@@ -955,7 +954,6 @@ static int hackrf_g_fmt_sdr(struct file *file, void *priv,
dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
(char *)&dev->pixelformat);
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
f->fmt.sdr.pixelformat = dev->pixelformat;
f->fmt.sdr.buffersize = dev->buffersize;
@@ -971,7 +969,6 @@ static int hackrf_try_fmt_sdr(struct file *file, void *priv,
dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
(char *)&f->fmt.sdr.pixelformat);
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
for (i = 0; i < NUM_FORMATS; i++) {
if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
f->fmt.sdr.buffersize = formats[i].buffersize;
diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c
index 63882a5248ae..71de6b4c4e4c 100644
--- a/drivers/media/usb/msi2500/msi2500.c
+++ b/drivers/media/usb/msi2500/msi2500.c
@@ -912,7 +912,6 @@ static int msi2500_g_fmt_sdr_cap(struct file *file, void *priv,
f->fmt.sdr.pixelformat = dev->pixelformat;
f->fmt.sdr.buffersize = dev->buffersize;
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
return 0;
}
@@ -930,7 +929,6 @@ static int msi2500_s_fmt_sdr_cap(struct file *file, void *priv,
if (vb2_is_busy(q))
return -EBUSY;
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
for (i = 0; i < dev->num_formats; i++) {
if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
dev->pixelformat = formats[i].pixelformat;
@@ -957,7 +955,6 @@ static int msi2500_try_fmt_sdr_cap(struct file *file, void *priv,
dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
(char *)&f->fmt.sdr.pixelformat);
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
for (i = 0; i < dev->num_formats; i++) {
if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
f->fmt.sdr.buffersize = formats[i].buffersize;
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index f4a727918e35..d38dee1792e4 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -2676,9 +2676,8 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
pvr2_stream_destroy(hdw->vid_stream);
hdw->vid_stream = NULL;
}
- pvr2_i2c_core_done(hdw);
v4l2_device_unregister(&hdw->v4l2_dev);
- pvr2_hdw_remove_usb_stuff(hdw);
+ pvr2_hdw_disconnect(hdw);
mutex_lock(&pvr2_unit_mtx);
do {
if ((hdw->unit_number >= 0) &&
@@ -2705,6 +2704,7 @@ void pvr2_hdw_disconnect(struct pvr2_hdw *hdw)
{
pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_disconnect(hdw=%p)",hdw);
LOCK_TAKE(hdw->big_lock);
+ pvr2_i2c_core_done(hdw);
LOCK_TAKE(hdw->ctl_lock);
pvr2_hdw_remove_usb_stuff(hdw);
LOCK_GIVE(hdw->ctl_lock);
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index 4af55e2478be..3b0e4ed75d99 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -767,8 +767,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
if (fmt == NULL)
return -EINVAL;
- field = f->fmt.pix.field;
-
dprintk(vc->dev, 50, "%s NTSC: %d suggested width: %d, height: %d\n",
__func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height);
if (is_ntsc) {
diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c
index a852ee5f7ac9..bfda46a36dc5 100644
--- a/drivers/media/usb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c
@@ -324,10 +324,10 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
if (!b)
return -ENOMEM;
- if ((result = mutex_lock_interruptible(&dec->usb_mutex))) {
- kfree(b);
+ result = mutex_lock_interruptible(&dec->usb_mutex);
+ if (result) {
printk("%s: Failed to lock usb mutex.\n", __func__);
- return result;
+ goto err;
}
b[0] = 0xaa;
@@ -349,9 +349,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
if (result) {
printk("%s: command bulk message failed: error %d\n",
__func__, result);
- mutex_unlock(&dec->usb_mutex);
- kfree(b);
- return result;
+ goto err;
}
result = usb_bulk_msg(dec->udev, dec->result_pipe, b,
@@ -360,9 +358,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
if (result) {
printk("%s: result bulk message failed: error %d\n",
__func__, result);
- mutex_unlock(&dec->usb_mutex);
- kfree(b);
- return result;
+ goto err;
} else {
if (debug) {
printk(KERN_DEBUG "%s: result: %*ph\n",
@@ -373,12 +369,13 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
*result_length = b[3];
if (cmd_result && b[3] > 0)
memcpy(cmd_result, &b[4], b[3]);
+ }
- mutex_unlock(&dec->usb_mutex);
+err:
+ mutex_unlock(&dec->usb_mutex);
- kfree(b);
- return 0;
- }
+ kfree(b);
+ return result;
}
static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode,
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index a777b389a66e..e16464606b14 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -127,10 +127,37 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
struct uvc_streaming_control *ctrl)
{
+ static const struct usb_device_id elgato_cam_link_4k = {
+ USB_DEVICE(0x0fd9, 0x0066)
+ };
struct uvc_format *format = NULL;
struct uvc_frame *frame = NULL;
unsigned int i;
+ /*
+ * The response of the Elgato Cam Link 4K is incorrect: The second byte
+ * contains bFormatIndex (instead of being the second byte of bmHint).
+ * The first byte is always zero. The third byte is always 1.
+ *
+ * The UVC 1.5 class specification defines the first five bits in the
+ * bmHint bitfield. The remaining bits are reserved and should be zero.
+ * Therefore a valid bmHint will be less than 32.
+ *
+ * Latest Elgato Cam Link 4K firmware as of 2021-03-23 needs this fix.
+ * MCU: 20.02.19, FPGA: 67
+ */
+ if (usb_match_one_id(stream->dev->intf, &elgato_cam_link_4k) &&
+ ctrl->bmHint > 255) {
+ u8 corrected_format_index = ctrl->bmHint >> 8;
+
+ uvc_dbg(stream->dev, VIDEO,
+ "Correct USB video probe response from {bmHint: 0x%04x, bFormatIndex: %u} to {bmHint: 0x%04x, bFormatIndex: %u}\n",
+ ctrl->bmHint, ctrl->bFormatIndex,
+ 1, corrected_format_index);
+ ctrl->bmHint = 1;
+ ctrl->bFormatIndex = corrected_format_index;
+ }
+
for (i = 0; i < stream->nformats; ++i) {
if (stream->format[i].index == ctrl->bFormatIndex) {
format = &stream->format[i];
diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c
index 1ef611e08323..538a330046ec 100644
--- a/drivers/media/usb/zr364xx/zr364xx.c
+++ b/drivers/media/usb/zr364xx/zr364xx.c
@@ -1032,6 +1032,7 @@ static int zr364xx_start_readpipe(struct zr364xx_camera *cam)
DBG("submitting URB %p\n", pipe_info->stream_urb);
retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
if (retval) {
+ usb_free_urb(pipe_info->stream_urb);
printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n");
return retval;
}
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index bf49f83cb86f..02dc1787e953 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -62,6 +62,7 @@ config V4L2_FLASH_LED_CLASS
tristate "V4L2 flash API for LED flash class devices"
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on LEDS_CLASS_FLASH
+ select V4L2_ASYNC
help
Say Y here to enable V4L2 flash API support for LED flash
class drivers.
@@ -70,6 +71,10 @@ config V4L2_FLASH_LED_CLASS
config V4L2_FWNODE
tristate
+ select V4L2_ASYNC
+
+config V4L2_ASYNC
+ tristate
# Used by drivers that need Videobuf modules
config VIDEOBUF_GEN
diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
index e4cd589b99a5..66a78c556c98 100644
--- a/drivers/media/v4l2-core/Makefile
+++ b/drivers/media/v4l2-core/Makefile
@@ -6,16 +6,18 @@
tuner-objs := tuner-core.o
videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
- v4l2-event.o v4l2-ctrls.o v4l2-subdev.o \
- v4l2-async.o v4l2-common.o
+ v4l2-event.o v4l2-subdev.o v4l2-common.o \
+ v4l2-ctrls-core.o v4l2-ctrls-api.o \
+ v4l2-ctrls-request.o v4l2-ctrls-defs.o
videodev-$(CONFIG_COMPAT) += v4l2-compat-ioctl32.o
videodev-$(CONFIG_TRACEPOINTS) += v4l2-trace.o
videodev-$(CONFIG_MEDIA_CONTROLLER) += v4l2-mc.o
videodev-$(CONFIG_SPI) += v4l2-spi.o
videodev-$(CONFIG_VIDEO_V4L2_I2C) += v4l2-i2c.o
-obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o
obj-$(CONFIG_VIDEO_V4L2) += videodev.o
+obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o
+obj-$(CONFIG_V4L2_ASYNC) += v4l2-async.o
obj-$(CONFIG_VIDEO_V4L2) += v4l2-dv-timings.o
obj-$(CONFIG_VIDEO_TUNER) += tuner.o
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index e638aa8aecb7..cd9e78c63791 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -854,8 +854,27 @@ static int pending_subdevs_show(struct seq_file *s, void *data)
}
DEFINE_SHOW_ATTRIBUTE(pending_subdevs);
-void v4l2_async_debug_init(struct dentry *debugfs_dir)
+static struct dentry *v4l2_async_debugfs_dir;
+
+static int __init v4l2_async_init(void)
{
- debugfs_create_file("pending_async_subdevices", 0444, debugfs_dir, NULL,
+ v4l2_async_debugfs_dir = debugfs_create_dir("v4l2-async", NULL);
+ debugfs_create_file("pending_async_subdevices", 0444,
+ v4l2_async_debugfs_dir, NULL,
&pending_subdevs_fops);
+
+ return 0;
+}
+
+static void __exit v4l2_async_exit(void)
+{
+ debugfs_remove_recursive(v4l2_async_debugfs_dir);
}
+
+subsys_initcall(v4l2_async_init);
+module_exit(v4l2_async_exit);
+
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
+MODULE_AUTHOR("Ezequiel Garcia <ezequiel@collabora.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 0ca75f6784c5..47aff3b19742 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -1244,6 +1244,9 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
if (!file->f_op->unlocked_ioctl)
return ret;
+ if (!video_is_registered(vdev))
+ return -ENODEV;
+
if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
ret = file->f_op->unlocked_ioctl(file, cmd,
(unsigned long)compat_ptr(arg));
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c
new file mode 100644
index 000000000000..db9baa0bd05f
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c
@@ -0,0 +1,1225 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * V4L2 controls framework uAPI implementation:
+ *
+ * Copyright (C) 2010-2021 Hans Verkuil <hverkuil-cisco@xs4all.nl>
+ */
+
+#define pr_fmt(fmt) "v4l2-ctrls: " fmt
+
+#include <linux/export.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+
+#include "v4l2-ctrls-priv.h"
+
+/* Internal temporary helper struct, one for each v4l2_ext_control */
+struct v4l2_ctrl_helper {
+ /* Pointer to the control reference of the master control */
+ struct v4l2_ctrl_ref *mref;
+ /* The control ref corresponding to the v4l2_ext_control ID field. */
+ struct v4l2_ctrl_ref *ref;
+ /*
+ * v4l2_ext_control index of the next control belonging to the
+ * same cluster, or 0 if there isn't any.
+ */
+ u32 next;
+};
+
+/*
+ * Helper functions to copy control payload data from kernel space to
+ * user space and vice versa.
+ */
+
+/* Helper function: copy the given control value back to the caller */
+static int ptr_to_user(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl,
+ union v4l2_ctrl_ptr ptr)
+{
+ u32 len;
+
+ if (ctrl->is_ptr && !ctrl->is_string)
+ return copy_to_user(c->ptr, ptr.p_const, c->size) ?
+ -EFAULT : 0;
+
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_STRING:
+ len = strlen(ptr.p_char);
+ if (c->size < len + 1) {
+ c->size = ctrl->elem_size;
+ return -ENOSPC;
+ }
+ return copy_to_user(c->string, ptr.p_char, len + 1) ?
+ -EFAULT : 0;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ c->value64 = *ptr.p_s64;
+ break;
+ default:
+ c->value = *ptr.p_s32;
+ break;
+ }
+ return 0;
+}
+
+/* Helper function: copy the current control value back to the caller */
+static int cur_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
+{
+ return ptr_to_user(c, ctrl, ctrl->p_cur);
+}
+
+/* Helper function: copy the new control value back to the caller */
+static int new_to_user(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl)
+{
+ return ptr_to_user(c, ctrl, ctrl->p_new);
+}
+
+/* Helper function: copy the request value back to the caller */
+static int req_to_user(struct v4l2_ext_control *c,
+ struct v4l2_ctrl_ref *ref)
+{
+ return ptr_to_user(c, ref->ctrl, ref->p_req);
+}
+
+/* Helper function: copy the initial control value back to the caller */
+static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
+{
+ int idx;
+
+ for (idx = 0; idx < ctrl->elems; idx++)
+ ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
+
+ return ptr_to_user(c, ctrl, ctrl->p_new);
+}
+
+/* Helper function: copy the caller-provider value to the given control value */
+static int user_to_ptr(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl,
+ union v4l2_ctrl_ptr ptr)
+{
+ int ret;
+ u32 size;
+
+ ctrl->is_new = 1;
+ if (ctrl->is_ptr && !ctrl->is_string) {
+ unsigned int idx;
+
+ ret = copy_from_user(ptr.p, c->ptr, c->size) ? -EFAULT : 0;
+ if (ret || !ctrl->is_array)
+ return ret;
+ for (idx = c->size / ctrl->elem_size; idx < ctrl->elems; idx++)
+ ctrl->type_ops->init(ctrl, idx, ptr);
+ return 0;
+ }
+
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_INTEGER64:
+ *ptr.p_s64 = c->value64;
+ break;
+ case V4L2_CTRL_TYPE_STRING:
+ size = c->size;
+ if (size == 0)
+ return -ERANGE;
+ if (size > ctrl->maximum + 1)
+ size = ctrl->maximum + 1;
+ ret = copy_from_user(ptr.p_char, c->string, size) ? -EFAULT : 0;
+ if (!ret) {
+ char last = ptr.p_char[size - 1];
+
+ ptr.p_char[size - 1] = 0;
+ /*
+ * If the string was longer than ctrl->maximum,
+ * then return an error.
+ */
+ if (strlen(ptr.p_char) == ctrl->maximum && last)
+ return -ERANGE;
+ }
+ return ret;
+ default:
+ *ptr.p_s32 = c->value;
+ break;
+ }
+ return 0;
+}
+
+/* Helper function: copy the caller-provider value as the new control value */
+static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
+{
+ return user_to_ptr(c, ctrl, ctrl->p_new);
+}
+
+/*
+ * VIDIOC_G/TRY/S_EXT_CTRLS implementation
+ */
+
+/*
+ * Some general notes on the atomic requirements of VIDIOC_G/TRY/S_EXT_CTRLS:
+ *
+ * It is not a fully atomic operation, just best-effort only. After all, if
+ * multiple controls have to be set through multiple i2c writes (for example)
+ * then some initial writes may succeed while others fail. Thus leaving the
+ * system in an inconsistent state. The question is how much effort you are
+ * willing to spend on trying to make something atomic that really isn't.
+ *
+ * From the point of view of an application the main requirement is that
+ * when you call VIDIOC_S_EXT_CTRLS and some values are invalid then an
+ * error should be returned without actually affecting any controls.
+ *
+ * If all the values are correct, then it is acceptable to just give up
+ * in case of low-level errors.
+ *
+ * It is important though that the application can tell when only a partial
+ * configuration was done. The way we do that is through the error_idx field
+ * of struct v4l2_ext_controls: if that is equal to the count field then no
+ * controls were affected. Otherwise all controls before that index were
+ * successful in performing their 'get' or 'set' operation, the control at
+ * the given index failed, and you don't know what happened with the controls
+ * after the failed one. Since if they were part of a control cluster they
+ * could have been successfully processed (if a cluster member was encountered
+ * at index < error_idx), they could have failed (if a cluster member was at
+ * error_idx), or they may not have been processed yet (if the first cluster
+ * member appeared after error_idx).
+ *
+ * It is all fairly theoretical, though. In practice all you can do is to
+ * bail out. If error_idx == count, then it is an application bug. If
+ * error_idx < count then it is only an application bug if the error code was
+ * EBUSY. That usually means that something started streaming just when you
+ * tried to set the controls. In all other cases it is a driver/hardware
+ * problem and all you can do is to retry or bail out.
+ *
+ * Note that these rules do not apply to VIDIOC_TRY_EXT_CTRLS: since that
+ * never modifies controls the error_idx is just set to whatever control
+ * has an invalid value.
+ */
+
+/*
+ * Prepare for the extended g/s/try functions.
+ * Find the controls in the control array and do some basic checks.
+ */
+static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ext_controls *cs,
+ struct v4l2_ctrl_helper *helpers,
+ struct video_device *vdev,
+ bool get)
+{
+ struct v4l2_ctrl_helper *h;
+ bool have_clusters = false;
+ u32 i;
+
+ for (i = 0, h = helpers; i < cs->count; i++, h++) {
+ struct v4l2_ext_control *c = &cs->controls[i];
+ struct v4l2_ctrl_ref *ref;
+ struct v4l2_ctrl *ctrl;
+ u32 id = c->id & V4L2_CTRL_ID_MASK;
+
+ cs->error_idx = i;
+
+ if (cs->which &&
+ cs->which != V4L2_CTRL_WHICH_DEF_VAL &&
+ cs->which != V4L2_CTRL_WHICH_REQUEST_VAL &&
+ V4L2_CTRL_ID2WHICH(id) != cs->which) {
+ dprintk(vdev,
+ "invalid which 0x%x or control id 0x%x\n",
+ cs->which, id);
+ return -EINVAL;
+ }
+
+ /*
+ * Old-style private controls are not allowed for
+ * extended controls.
+ */
+ if (id >= V4L2_CID_PRIVATE_BASE) {
+ dprintk(vdev,
+ "old-style private controls not allowed\n");
+ return -EINVAL;
+ }
+ ref = find_ref_lock(hdl, id);
+ if (!ref) {
+ dprintk(vdev, "cannot find control id 0x%x\n", id);
+ return -EINVAL;
+ }
+ h->ref = ref;
+ ctrl = ref->ctrl;
+ if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED) {
+ dprintk(vdev, "control id 0x%x is disabled\n", id);
+ return -EINVAL;
+ }
+
+ if (ctrl->cluster[0]->ncontrols > 1)
+ have_clusters = true;
+ if (ctrl->cluster[0] != ctrl)
+ ref = find_ref_lock(hdl, ctrl->cluster[0]->id);
+ if (ctrl->is_ptr && !ctrl->is_string) {
+ unsigned int tot_size = ctrl->elems * ctrl->elem_size;
+
+ if (c->size < tot_size) {
+ /*
+ * In the get case the application first
+ * queries to obtain the size of the control.
+ */
+ if (get) {
+ c->size = tot_size;
+ return -ENOSPC;
+ }
+ dprintk(vdev,
+ "pointer control id 0x%x size too small, %d bytes but %d bytes needed\n",
+ id, c->size, tot_size);
+ return -EFAULT;
+ }
+ c->size = tot_size;
+ }
+ /* Store the ref to the master control of the cluster */
+ h->mref = ref;
+ /*
+ * Initially set next to 0, meaning that there is no other
+ * control in this helper array belonging to the same
+ * cluster.
+ */
+ h->next = 0;
+ }
+
+ /*
+ * We are done if there were no controls that belong to a multi-
+ * control cluster.
+ */
+ if (!have_clusters)
+ return 0;
+
+ /*
+ * The code below figures out in O(n) time which controls in the list
+ * belong to the same cluster.
+ */
+
+ /* This has to be done with the handler lock taken. */
+ mutex_lock(hdl->lock);
+
+ /* First zero the helper field in the master control references */
+ for (i = 0; i < cs->count; i++)
+ helpers[i].mref->helper = NULL;
+ for (i = 0, h = helpers; i < cs->count; i++, h++) {
+ struct v4l2_ctrl_ref *mref = h->mref;
+
+ /*
+ * If the mref->helper is set, then it points to an earlier
+ * helper that belongs to the same cluster.
+ */
+ if (mref->helper) {
+ /*
+ * Set the next field of mref->helper to the current
+ * index: this means that the earlier helper now
+ * points to the next helper in the same cluster.
+ */
+ mref->helper->next = i;
+ /*
+ * mref should be set only for the first helper in the
+ * cluster, clear the others.
+ */
+ h->mref = NULL;
+ }
+ /* Point the mref helper to the current helper struct. */
+ mref->helper = h;
+ }
+ mutex_unlock(hdl->lock);
+ return 0;
+}
+
+/*
+ * Handles the corner case where cs->count == 0. It checks whether the
+ * specified control class exists. If that class ID is 0, then it checks
+ * whether there are any controls at all.
+ */
+static int class_check(struct v4l2_ctrl_handler *hdl, u32 which)
+{
+ if (which == 0 || which == V4L2_CTRL_WHICH_DEF_VAL ||
+ which == V4L2_CTRL_WHICH_REQUEST_VAL)
+ return 0;
+ return find_ref_lock(hdl, which | 1) ? 0 : -EINVAL;
+}
+
+/*
+ * Get extended controls. Allocates the helpers array if needed.
+ *
+ * Note that v4l2_g_ext_ctrls_common() with 'which' set to
+ * V4L2_CTRL_WHICH_REQUEST_VAL is only called if the request was
+ * completed, and in that case valid_p_req is true for all controls.
+ */
+int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ext_controls *cs,
+ struct video_device *vdev)
+{
+ struct v4l2_ctrl_helper helper[4];
+ struct v4l2_ctrl_helper *helpers = helper;
+ int ret;
+ int i, j;
+ bool is_default, is_request;
+
+ is_default = (cs->which == V4L2_CTRL_WHICH_DEF_VAL);
+ is_request = (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL);
+
+ cs->error_idx = cs->count;
+ cs->which = V4L2_CTRL_ID2WHICH(cs->which);
+
+ if (!hdl)
+ return -EINVAL;
+
+ if (cs->count == 0)
+ return class_check(hdl, cs->which);
+
+ if (cs->count > ARRAY_SIZE(helper)) {
+ helpers = kvmalloc_array(cs->count, sizeof(helper[0]),
+ GFP_KERNEL);
+ if (!helpers)
+ return -ENOMEM;
+ }
+
+ ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, true);
+ cs->error_idx = cs->count;
+
+ for (i = 0; !ret && i < cs->count; i++)
+ if (helpers[i].ref->ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
+ ret = -EACCES;
+
+ for (i = 0; !ret && i < cs->count; i++) {
+ struct v4l2_ctrl *master;
+ bool is_volatile = false;
+ u32 idx = i;
+
+ if (!helpers[i].mref)
+ continue;
+
+ master = helpers[i].mref->ctrl;
+ cs->error_idx = i;
+
+ v4l2_ctrl_lock(master);
+
+ /*
+ * g_volatile_ctrl will update the new control values.
+ * This makes no sense for V4L2_CTRL_WHICH_DEF_VAL and
+ * V4L2_CTRL_WHICH_REQUEST_VAL. In the case of requests
+ * it is v4l2_ctrl_request_complete() that copies the
+ * volatile controls at the time of request completion
+ * to the request, so you don't want to do that again.
+ */
+ if (!is_default && !is_request &&
+ ((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
+ (master->has_volatiles && !is_cur_manual(master)))) {
+ for (j = 0; j < master->ncontrols; j++)
+ cur_to_new(master->cluster[j]);
+ ret = call_op(master, g_volatile_ctrl);
+ is_volatile = true;
+ }
+
+ if (ret) {
+ v4l2_ctrl_unlock(master);
+ break;
+ }
+
+ /*
+ * Copy the default value (if is_default is true), the
+ * request value (if is_request is true and p_req is valid),
+ * the new volatile value (if is_volatile is true) or the
+ * current value.
+ */
+ do {
+ struct v4l2_ctrl_ref *ref = helpers[idx].ref;
+
+ if (is_default)
+ ret = def_to_user(cs->controls + idx, ref->ctrl);
+ else if (is_request && ref->valid_p_req)
+ ret = req_to_user(cs->controls + idx, ref);
+ else if (is_volatile)
+ ret = new_to_user(cs->controls + idx, ref->ctrl);
+ else
+ ret = cur_to_user(cs->controls + idx, ref->ctrl);
+ idx = helpers[idx].next;
+ } while (!ret && idx);
+
+ v4l2_ctrl_unlock(master);
+ }
+
+ if (cs->count > ARRAY_SIZE(helper))
+ kvfree(helpers);
+ return ret;
+}
+
+int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
+ struct media_device *mdev, struct v4l2_ext_controls *cs)
+{
+ if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL)
+ return v4l2_g_ext_ctrls_request(hdl, vdev, mdev, cs);
+
+ return v4l2_g_ext_ctrls_common(hdl, cs, vdev);
+}
+EXPORT_SYMBOL(v4l2_g_ext_ctrls);
+
+/* Validate controls. */
+static int validate_ctrls(struct v4l2_ext_controls *cs,
+ struct v4l2_ctrl_helper *helpers,
+ struct video_device *vdev,
+ bool set)
+{
+ unsigned int i;
+ int ret = 0;
+
+ cs->error_idx = cs->count;
+ for (i = 0; i < cs->count; i++) {
+ struct v4l2_ctrl *ctrl = helpers[i].ref->ctrl;
+ union v4l2_ctrl_ptr p_new;
+
+ cs->error_idx = i;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) {
+ dprintk(vdev,
+ "control id 0x%x is read-only\n",
+ ctrl->id);
+ return -EACCES;
+ }
+ /*
+ * This test is also done in try_set_control_cluster() which
+ * is called in atomic context, so that has the final say,
+ * but it makes sense to do an up-front check as well. Once
+ * an error occurs in try_set_control_cluster() some other
+ * controls may have been set already and we want to do a
+ * best-effort to avoid that.
+ */
+ if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) {
+ dprintk(vdev,
+ "control id 0x%x is grabbed, cannot set\n",
+ ctrl->id);
+ return -EBUSY;
+ }
+ /*
+ * Skip validation for now if the payload needs to be copied
+ * from userspace into kernelspace. We'll validate those later.
+ */
+ if (ctrl->is_ptr)
+ continue;
+ if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
+ p_new.p_s64 = &cs->controls[i].value64;
+ else
+ p_new.p_s32 = &cs->controls[i].value;
+ ret = validate_new(ctrl, p_new);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+/* Try or try-and-set controls */
+int try_set_ext_ctrls_common(struct v4l2_fh *fh,
+ struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ext_controls *cs,
+ struct video_device *vdev, bool set)
+{
+ struct v4l2_ctrl_helper helper[4];
+ struct v4l2_ctrl_helper *helpers = helper;
+ unsigned int i, j;
+ int ret;
+
+ cs->error_idx = cs->count;
+
+ /* Default value cannot be changed */
+ if (cs->which == V4L2_CTRL_WHICH_DEF_VAL) {
+ dprintk(vdev, "%s: cannot change default value\n",
+ video_device_node_name(vdev));
+ return -EINVAL;
+ }
+
+ cs->which = V4L2_CTRL_ID2WHICH(cs->which);
+
+ if (!hdl) {
+ dprintk(vdev, "%s: invalid null control handler\n",
+ video_device_node_name(vdev));
+ return -EINVAL;
+ }
+
+ if (cs->count == 0)
+ return class_check(hdl, cs->which);
+
+ if (cs->count > ARRAY_SIZE(helper)) {
+ helpers = kvmalloc_array(cs->count, sizeof(helper[0]),
+ GFP_KERNEL);
+ if (!helpers)
+ return -ENOMEM;
+ }
+ ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, false);
+ if (!ret)
+ ret = validate_ctrls(cs, helpers, vdev, set);
+ if (ret && set)
+ cs->error_idx = cs->count;
+ for (i = 0; !ret && i < cs->count; i++) {
+ struct v4l2_ctrl *master;
+ u32 idx = i;
+
+ if (!helpers[i].mref)
+ continue;
+
+ cs->error_idx = i;
+ master = helpers[i].mref->ctrl;
+ v4l2_ctrl_lock(master);
+
+ /* Reset the 'is_new' flags of the cluster */
+ for (j = 0; j < master->ncontrols; j++)
+ if (master->cluster[j])
+ master->cluster[j]->is_new = 0;
+
+ /*
+ * For volatile autoclusters that are currently in auto mode
+ * we need to discover if it will be set to manual mode.
+ * If so, then we have to copy the current volatile values
+ * first since those will become the new manual values (which
+ * may be overwritten by explicit new values from this set
+ * of controls).
+ */
+ if (master->is_auto && master->has_volatiles &&
+ !is_cur_manual(master)) {
+ /* Pick an initial non-manual value */
+ s32 new_auto_val = master->manual_mode_value + 1;
+ u32 tmp_idx = idx;
+
+ do {
+ /*
+ * Check if the auto control is part of the
+ * list, and remember the new value.
+ */
+ if (helpers[tmp_idx].ref->ctrl == master)
+ new_auto_val = cs->controls[tmp_idx].value;
+ tmp_idx = helpers[tmp_idx].next;
+ } while (tmp_idx);
+ /*
+ * If the new value == the manual value, then copy
+ * the current volatile values.
+ */
+ if (new_auto_val == master->manual_mode_value)
+ update_from_auto_cluster(master);
+ }
+
+ /*
+ * Copy the new caller-supplied control values.
+ * user_to_new() sets 'is_new' to 1.
+ */
+ do {
+ struct v4l2_ctrl *ctrl = helpers[idx].ref->ctrl;
+
+ ret = user_to_new(cs->controls + idx, ctrl);
+ if (!ret && ctrl->is_ptr) {
+ ret = validate_new(ctrl, ctrl->p_new);
+ if (ret)
+ dprintk(vdev,
+ "failed to validate control %s (%d)\n",
+ v4l2_ctrl_get_name(ctrl->id), ret);
+ }
+ idx = helpers[idx].next;
+ } while (!ret && idx);
+
+ if (!ret)
+ ret = try_or_set_cluster(fh, master,
+ !hdl->req_obj.req && set, 0);
+ if (!ret && hdl->req_obj.req && set) {
+ for (j = 0; j < master->ncontrols; j++) {
+ struct v4l2_ctrl_ref *ref =
+ find_ref(hdl, master->cluster[j]->id);
+
+ new_to_req(ref);
+ }
+ }
+
+ /* Copy the new values back to userspace. */
+ if (!ret) {
+ idx = i;
+ do {
+ ret = new_to_user(cs->controls + idx,
+ helpers[idx].ref->ctrl);
+ idx = helpers[idx].next;
+ } while (!ret && idx);
+ }
+ v4l2_ctrl_unlock(master);
+ }
+
+ if (cs->count > ARRAY_SIZE(helper))
+ kvfree(helpers);
+ return ret;
+}
+
+static int try_set_ext_ctrls(struct v4l2_fh *fh,
+ struct v4l2_ctrl_handler *hdl,
+ struct video_device *vdev,
+ struct media_device *mdev,
+ struct v4l2_ext_controls *cs, bool set)
+{
+ int ret;
+
+ if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL)
+ return try_set_ext_ctrls_request(fh, hdl, vdev, mdev, cs, set);
+
+ ret = try_set_ext_ctrls_common(fh, hdl, cs, vdev, set);
+ if (ret)
+ dprintk(vdev,
+ "%s: try_set_ext_ctrls_common failed (%d)\n",
+ video_device_node_name(vdev), ret);
+
+ return ret;
+}
+
+int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl,
+ struct video_device *vdev,
+ struct media_device *mdev,
+ struct v4l2_ext_controls *cs)
+{
+ return try_set_ext_ctrls(NULL, hdl, vdev, mdev, cs, false);
+}
+EXPORT_SYMBOL(v4l2_try_ext_ctrls);
+
+int v4l2_s_ext_ctrls(struct v4l2_fh *fh,
+ struct v4l2_ctrl_handler *hdl,
+ struct video_device *vdev,
+ struct media_device *mdev,
+ struct v4l2_ext_controls *cs)
+{
+ return try_set_ext_ctrls(fh, hdl, vdev, mdev, cs, true);
+}
+EXPORT_SYMBOL(v4l2_s_ext_ctrls);
+
+/*
+ * VIDIOC_G/S_CTRL implementation
+ */
+
+/* Helper function to get a single control */
+static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
+{
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+ int ret = 0;
+ int i;
+
+ /* Compound controls are not supported. The new_to_user() and
+ * cur_to_user() calls below would need to be modified not to access
+ * userspace memory when called from get_ctrl().
+ */
+ if (!ctrl->is_int && ctrl->type != V4L2_CTRL_TYPE_INTEGER64)
+ return -EINVAL;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
+ return -EACCES;
+
+ v4l2_ctrl_lock(master);
+ /* g_volatile_ctrl will update the current control values */
+ if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
+ for (i = 0; i < master->ncontrols; i++)
+ cur_to_new(master->cluster[i]);
+ ret = call_op(master, g_volatile_ctrl);
+ new_to_user(c, ctrl);
+ } else {
+ cur_to_user(c, ctrl);
+ }
+ v4l2_ctrl_unlock(master);
+ return ret;
+}
+
+int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
+{
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
+ struct v4l2_ext_control c;
+ int ret;
+
+ if (!ctrl || !ctrl->is_int)
+ return -EINVAL;
+ ret = get_ctrl(ctrl, &c);
+ control->value = c.value;
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_g_ctrl);
+
+/* Helper function for VIDIOC_S_CTRL compatibility */
+static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
+{
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+ int ret;
+ int i;
+
+ /* Reset the 'is_new' flags of the cluster */
+ for (i = 0; i < master->ncontrols; i++)
+ if (master->cluster[i])
+ master->cluster[i]->is_new = 0;
+
+ ret = validate_new(ctrl, ctrl->p_new);
+ if (ret)
+ return ret;
+
+ /*
+ * For autoclusters with volatiles that are switched from auto to
+ * manual mode we have to update the current volatile values since
+ * those will become the initial manual values after such a switch.
+ */
+ if (master->is_auto && master->has_volatiles && ctrl == master &&
+ !is_cur_manual(master) && ctrl->val == master->manual_mode_value)
+ update_from_auto_cluster(master);
+
+ ctrl->is_new = 1;
+ return try_or_set_cluster(fh, master, true, ch_flags);
+}
+
+/* Helper function for VIDIOC_S_CTRL compatibility */
+static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
+ struct v4l2_ext_control *c)
+{
+ int ret;
+
+ v4l2_ctrl_lock(ctrl);
+ user_to_new(c, ctrl);
+ ret = set_ctrl(fh, ctrl, 0);
+ if (!ret)
+ cur_to_user(c, ctrl);
+ v4l2_ctrl_unlock(ctrl);
+ return ret;
+}
+
+int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
+ struct v4l2_control *control)
+{
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
+ struct v4l2_ext_control c = { control->id };
+ int ret;
+
+ if (!ctrl || !ctrl->is_int)
+ return -EINVAL;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
+ return -EACCES;
+
+ c.value = control->value;
+ ret = set_ctrl_lock(fh, ctrl, &c);
+ control->value = c.value;
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_s_ctrl);
+
+/*
+ * Helper functions for drivers to get/set controls.
+ */
+
+s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_ext_control c;
+
+ /* It's a driver bug if this happens. */
+ if (WARN_ON(!ctrl->is_int))
+ return 0;
+ c.value = 0;
+ get_ctrl(ctrl, &c);
+ return c.value;
+}
+EXPORT_SYMBOL(v4l2_ctrl_g_ctrl);
+
+s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_ext_control c;
+
+ /* It's a driver bug if this happens. */
+ if (WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64))
+ return 0;
+ c.value64 = 0;
+ get_ctrl(ctrl, &c);
+ return c.value64;
+}
+EXPORT_SYMBOL(v4l2_ctrl_g_ctrl_int64);
+
+int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
+{
+ lockdep_assert_held(ctrl->handler->lock);
+
+ /* It's a driver bug if this happens. */
+ if (WARN_ON(!ctrl->is_int))
+ return -EINVAL;
+ ctrl->val = val;
+ return set_ctrl(NULL, ctrl, 0);
+}
+EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl);
+
+int __v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
+{
+ lockdep_assert_held(ctrl->handler->lock);
+
+ /* It's a driver bug if this happens. */
+ if (WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64))
+ return -EINVAL;
+ *ctrl->p_new.p_s64 = val;
+ return set_ctrl(NULL, ctrl, 0);
+}
+EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_int64);
+
+int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s)
+{
+ lockdep_assert_held(ctrl->handler->lock);
+
+ /* It's a driver bug if this happens. */
+ if (WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING))
+ return -EINVAL;
+ strscpy(ctrl->p_new.p_char, s, ctrl->maximum + 1);
+ return set_ctrl(NULL, ctrl, 0);
+}
+EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string);
+
+int __v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl,
+ enum v4l2_ctrl_type type, const void *p)
+{
+ lockdep_assert_held(ctrl->handler->lock);
+
+ /* It's a driver bug if this happens. */
+ if (WARN_ON(ctrl->type != type))
+ return -EINVAL;
+ memcpy(ctrl->p_new.p, p, ctrl->elems * ctrl->elem_size);
+ return set_ctrl(NULL, ctrl, 0);
+}
+EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_compound);
+
+/*
+ * Modify the range of a control.
+ */
+int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
+ s64 min, s64 max, u64 step, s64 def)
+{
+ bool value_changed;
+ bool range_changed = false;
+ int ret;
+
+ lockdep_assert_held(ctrl->handler->lock);
+
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ case V4L2_CTRL_TYPE_INTEGER64:
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ case V4L2_CTRL_TYPE_MENU:
+ case V4L2_CTRL_TYPE_INTEGER_MENU:
+ case V4L2_CTRL_TYPE_BITMASK:
+ case V4L2_CTRL_TYPE_U8:
+ case V4L2_CTRL_TYPE_U16:
+ case V4L2_CTRL_TYPE_U32:
+ if (ctrl->is_array)
+ return -EINVAL;
+ ret = check_range(ctrl->type, min, max, step, def);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (ctrl->minimum != min || ctrl->maximum != max ||
+ ctrl->step != step || ctrl->default_value != def) {
+ range_changed = true;
+ ctrl->minimum = min;
+ ctrl->maximum = max;
+ ctrl->step = step;
+ ctrl->default_value = def;
+ }
+ cur_to_new(ctrl);
+ if (validate_new(ctrl, ctrl->p_new)) {
+ if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
+ *ctrl->p_new.p_s64 = def;
+ else
+ *ctrl->p_new.p_s32 = def;
+ }
+
+ if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
+ value_changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64;
+ else
+ value_changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32;
+ if (value_changed)
+ ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
+ else if (range_changed)
+ send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
+ return ret;
+}
+EXPORT_SYMBOL(__v4l2_ctrl_modify_range);
+
+/* Implement VIDIOC_QUERY_EXT_CTRL */
+int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctrl *qc)
+{
+ const unsigned int next_flags = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
+ u32 id = qc->id & V4L2_CTRL_ID_MASK;
+ struct v4l2_ctrl_ref *ref;
+ struct v4l2_ctrl *ctrl;
+
+ if (!hdl)
+ return -EINVAL;
+
+ mutex_lock(hdl->lock);
+
+ /* Try to find it */
+ ref = find_ref(hdl, id);
+
+ if ((qc->id & next_flags) && !list_empty(&hdl->ctrl_refs)) {
+ bool is_compound;
+ /* Match any control that is not hidden */
+ unsigned int mask = 1;
+ bool match = false;
+
+ if ((qc->id & next_flags) == V4L2_CTRL_FLAG_NEXT_COMPOUND) {
+ /* Match any hidden control */
+ match = true;
+ } else if ((qc->id & next_flags) == next_flags) {
+ /* Match any control, compound or not */
+ mask = 0;
+ }
+
+ /* Find the next control with ID > qc->id */
+
+ /* Did we reach the end of the control list? */
+ if (id >= node2id(hdl->ctrl_refs.prev)) {
+ ref = NULL; /* Yes, so there is no next control */
+ } else if (ref) {
+ /*
+ * We found a control with the given ID, so just get
+ * the next valid one in the list.
+ */
+ list_for_each_entry_continue(ref, &hdl->ctrl_refs, node) {
+ is_compound = ref->ctrl->is_array ||
+ ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES;
+ if (id < ref->ctrl->id &&
+ (is_compound & mask) == match)
+ break;
+ }
+ if (&ref->node == &hdl->ctrl_refs)
+ ref = NULL;
+ } else {
+ /*
+ * No control with the given ID exists, so start
+ * searching for the next largest ID. We know there
+ * is one, otherwise the first 'if' above would have
+ * been true.
+ */
+ list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+ is_compound = ref->ctrl->is_array ||
+ ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES;
+ if (id < ref->ctrl->id &&
+ (is_compound & mask) == match)
+ break;
+ }
+ if (&ref->node == &hdl->ctrl_refs)
+ ref = NULL;
+ }
+ }
+ mutex_unlock(hdl->lock);
+
+ if (!ref)
+ return -EINVAL;
+
+ ctrl = ref->ctrl;
+ memset(qc, 0, sizeof(*qc));
+ if (id >= V4L2_CID_PRIVATE_BASE)
+ qc->id = id;
+ else
+ qc->id = ctrl->id;
+ strscpy(qc->name, ctrl->name, sizeof(qc->name));
+ qc->flags = user_flags(ctrl);
+ qc->type = ctrl->type;
+ qc->elem_size = ctrl->elem_size;
+ qc->elems = ctrl->elems;
+ qc->nr_of_dims = ctrl->nr_of_dims;
+ memcpy(qc->dims, ctrl->dims, qc->nr_of_dims * sizeof(qc->dims[0]));
+ qc->minimum = ctrl->minimum;
+ qc->maximum = ctrl->maximum;
+ qc->default_value = ctrl->default_value;
+ if (ctrl->type == V4L2_CTRL_TYPE_MENU ||
+ ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
+ qc->step = 1;
+ else
+ qc->step = ctrl->step;
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_query_ext_ctrl);
+
+/* Implement VIDIOC_QUERYCTRL */
+int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
+{
+ struct v4l2_query_ext_ctrl qec = { qc->id };
+ int rc;
+
+ rc = v4l2_query_ext_ctrl(hdl, &qec);
+ if (rc)
+ return rc;
+
+ qc->id = qec.id;
+ qc->type = qec.type;
+ qc->flags = qec.flags;
+ strscpy(qc->name, qec.name, sizeof(qc->name));
+ switch (qc->type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ case V4L2_CTRL_TYPE_MENU:
+ case V4L2_CTRL_TYPE_INTEGER_MENU:
+ case V4L2_CTRL_TYPE_STRING:
+ case V4L2_CTRL_TYPE_BITMASK:
+ qc->minimum = qec.minimum;
+ qc->maximum = qec.maximum;
+ qc->step = qec.step;
+ qc->default_value = qec.default_value;
+ break;
+ default:
+ qc->minimum = 0;
+ qc->maximum = 0;
+ qc->step = 0;
+ qc->default_value = 0;
+ break;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_queryctrl);
+
+/* Implement VIDIOC_QUERYMENU */
+int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
+{
+ struct v4l2_ctrl *ctrl;
+ u32 i = qm->index;
+
+ ctrl = v4l2_ctrl_find(hdl, qm->id);
+ if (!ctrl)
+ return -EINVAL;
+
+ qm->reserved = 0;
+ /* Sanity checks */
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_MENU:
+ if (!ctrl->qmenu)
+ return -EINVAL;
+ break;
+ case V4L2_CTRL_TYPE_INTEGER_MENU:
+ if (!ctrl->qmenu_int)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (i < ctrl->minimum || i > ctrl->maximum)
+ return -EINVAL;
+
+ /* Use mask to see if this menu item should be skipped */
+ if (ctrl->menu_skip_mask & (1ULL << i))
+ return -EINVAL;
+ /* Empty menu items should also be skipped */
+ if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
+ if (!ctrl->qmenu[i] || ctrl->qmenu[i][0] == '\0')
+ return -EINVAL;
+ strscpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
+ } else {
+ qm->value = ctrl->qmenu_int[i];
+ }
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_querymenu);
+
+/*
+ * VIDIOC_LOG_STATUS helpers
+ */
+
+int v4l2_ctrl_log_status(struct file *file, void *fh)
+{
+ struct video_device *vfd = video_devdata(file);
+ struct v4l2_fh *vfh = file->private_data;
+
+ if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev)
+ v4l2_ctrl_handler_log_status(vfh->ctrl_handler,
+ vfd->v4l2_dev->name);
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_log_status);
+
+int v4l2_ctrl_subdev_log_status(struct v4l2_subdev *sd)
+{
+ v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_subdev_log_status);
+
+/*
+ * VIDIOC_(UN)SUBSCRIBE_EVENT implementation
+ */
+
+static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev,
+ unsigned int elems)
+{
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
+
+ if (!ctrl)
+ return -EINVAL;
+
+ v4l2_ctrl_lock(ctrl);
+ list_add_tail(&sev->node, &ctrl->ev_subs);
+ if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS &&
+ (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL))
+ send_initial_event(sev->fh, ctrl);
+ v4l2_ctrl_unlock(ctrl);
+ return 0;
+}
+
+static void v4l2_ctrl_del_event(struct v4l2_subscribed_event *sev)
+{
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
+
+ if (!ctrl)
+ return;
+
+ v4l2_ctrl_lock(ctrl);
+ list_del(&sev->node);
+ v4l2_ctrl_unlock(ctrl);
+}
+
+void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new)
+{
+ u32 old_changes = old->u.ctrl.changes;
+
+ old->u.ctrl = new->u.ctrl;
+ old->u.ctrl.changes |= old_changes;
+}
+EXPORT_SYMBOL(v4l2_ctrl_replace);
+
+void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new)
+{
+ new->u.ctrl.changes |= old->u.ctrl.changes;
+}
+EXPORT_SYMBOL(v4l2_ctrl_merge);
+
+const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops = {
+ .add = v4l2_ctrl_add_event,
+ .del = v4l2_ctrl_del_event,
+ .replace = v4l2_ctrl_replace,
+ .merge = v4l2_ctrl_merge,
+};
+EXPORT_SYMBOL(v4l2_ctrl_sub_ev_ops);
+
+int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ if (sub->type == V4L2_EVENT_CTRL)
+ return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(v4l2_ctrl_subscribe_event);
+
+int v4l2_ctrl_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ if (!sd->ctrl_handler)
+ return -EINVAL;
+ return v4l2_ctrl_subscribe_event(fh, sub);
+}
+EXPORT_SYMBOL(v4l2_ctrl_subdev_subscribe_event);
+
+/*
+ * poll helper
+ */
+__poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct v4l2_fh *fh = file->private_data;
+
+ poll_wait(file, &fh->wait, wait);
+ if (v4l2_event_pending(fh))
+ return EPOLLPRI;
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_poll);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
new file mode 100644
index 000000000000..c4b5082849b6
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -0,0 +1,1946 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * V4L2 controls framework core implementation.
+ *
+ * Copyright (C) 2010-2021 Hans Verkuil <hverkuil-cisco@xs4all.nl>
+ */
+
+#include <linux/export.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+
+#include "v4l2-ctrls-priv.h"
+
+static const union v4l2_ctrl_ptr ptr_null;
+
+static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl,
+ u32 changes)
+{
+ memset(ev, 0, sizeof(*ev));
+ ev->type = V4L2_EVENT_CTRL;
+ ev->id = ctrl->id;
+ ev->u.ctrl.changes = changes;
+ ev->u.ctrl.type = ctrl->type;
+ ev->u.ctrl.flags = user_flags(ctrl);
+ if (ctrl->is_ptr)
+ ev->u.ctrl.value64 = 0;
+ else
+ ev->u.ctrl.value64 = *ctrl->p_cur.p_s64;
+ ev->u.ctrl.minimum = ctrl->minimum;
+ ev->u.ctrl.maximum = ctrl->maximum;
+ if (ctrl->type == V4L2_CTRL_TYPE_MENU
+ || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
+ ev->u.ctrl.step = 1;
+ else
+ ev->u.ctrl.step = ctrl->step;
+ ev->u.ctrl.default_value = ctrl->default_value;
+}
+
+void send_initial_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_event ev;
+ u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
+
+ if (!(ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY))
+ changes |= V4L2_EVENT_CTRL_CH_VALUE;
+ fill_event(&ev, ctrl, changes);
+ v4l2_event_queue_fh(fh, &ev);
+}
+
+void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
+{
+ struct v4l2_event ev;
+ struct v4l2_subscribed_event *sev;
+
+ if (list_empty(&ctrl->ev_subs))
+ return;
+ fill_event(&ev, ctrl, changes);
+
+ list_for_each_entry(sev, &ctrl->ev_subs, node)
+ if (sev->fh != fh ||
+ (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK))
+ v4l2_event_queue_fh(sev->fh, &ev);
+}
+
+static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx,
+ union v4l2_ctrl_ptr ptr1,
+ union v4l2_ctrl_ptr ptr2)
+{
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_BUTTON:
+ return false;
+ case V4L2_CTRL_TYPE_STRING:
+ idx *= ctrl->elem_size;
+ /* strings are always 0-terminated */
+ return !strcmp(ptr1.p_char + idx, ptr2.p_char + idx);
+ case V4L2_CTRL_TYPE_INTEGER64:
+ return ptr1.p_s64[idx] == ptr2.p_s64[idx];
+ case V4L2_CTRL_TYPE_U8:
+ return ptr1.p_u8[idx] == ptr2.p_u8[idx];
+ case V4L2_CTRL_TYPE_U16:
+ return ptr1.p_u16[idx] == ptr2.p_u16[idx];
+ case V4L2_CTRL_TYPE_U32:
+ return ptr1.p_u32[idx] == ptr2.p_u32[idx];
+ default:
+ if (ctrl->is_int)
+ return ptr1.p_s32[idx] == ptr2.p_s32[idx];
+ idx *= ctrl->elem_size;
+ return !memcmp(ptr1.p_const + idx, ptr2.p_const + idx,
+ ctrl->elem_size);
+ }
+}
+
+/* Default intra MPEG-2 quantisation coefficients, from the specification. */
+static const u8 mpeg2_intra_quant_matrix[64] = {
+ 8, 16, 16, 19, 16, 19, 22, 22,
+ 22, 22, 22, 22, 26, 24, 26, 27,
+ 27, 27, 26, 26, 26, 26, 27, 27,
+ 27, 29, 29, 29, 34, 34, 34, 29,
+ 29, 29, 27, 27, 29, 29, 32, 32,
+ 34, 34, 37, 38, 37, 35, 35, 34,
+ 35, 38, 38, 40, 40, 40, 48, 48,
+ 46, 46, 56, 56, 58, 69, 69, 83
+};
+
+static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx,
+ union v4l2_ctrl_ptr ptr)
+{
+ struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence;
+ struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture;
+ struct v4l2_ctrl_mpeg2_quantisation *p_mpeg2_quant;
+ struct v4l2_ctrl_vp8_frame *p_vp8_frame;
+ struct v4l2_ctrl_fwht_params *p_fwht_params;
+ void *p = ptr.p + idx * ctrl->elem_size;
+
+ if (ctrl->p_def.p_const)
+ memcpy(p, ctrl->p_def.p_const, ctrl->elem_size);
+ else
+ memset(p, 0, ctrl->elem_size);
+
+ switch ((u32)ctrl->type) {
+ case V4L2_CTRL_TYPE_MPEG2_SEQUENCE:
+ p_mpeg2_sequence = p;
+
+ /* 4:2:0 */
+ p_mpeg2_sequence->chroma_format = 1;
+ break;
+ case V4L2_CTRL_TYPE_MPEG2_PICTURE:
+ p_mpeg2_picture = p;
+
+ /* interlaced top field */
+ p_mpeg2_picture->picture_structure = V4L2_MPEG2_PIC_TOP_FIELD;
+ p_mpeg2_picture->picture_coding_type =
+ V4L2_MPEG2_PIC_CODING_TYPE_I;
+ break;
+ case V4L2_CTRL_TYPE_MPEG2_QUANTISATION:
+ p_mpeg2_quant = p;
+
+ memcpy(p_mpeg2_quant->intra_quantiser_matrix,
+ mpeg2_intra_quant_matrix,
+ ARRAY_SIZE(mpeg2_intra_quant_matrix));
+ /*
+ * The default non-intra MPEG-2 quantisation
+ * coefficients are all 16, as per the specification.
+ */
+ memset(p_mpeg2_quant->non_intra_quantiser_matrix, 16,
+ sizeof(p_mpeg2_quant->non_intra_quantiser_matrix));
+ break;
+ case V4L2_CTRL_TYPE_VP8_FRAME:
+ p_vp8_frame = p;
+ p_vp8_frame->num_dct_parts = 1;
+ break;
+ case V4L2_CTRL_TYPE_FWHT_PARAMS:
+ p_fwht_params = p;
+ p_fwht_params->version = V4L2_FWHT_VERSION;
+ p_fwht_params->width = 1280;
+ p_fwht_params->height = 720;
+ p_fwht_params->flags = V4L2_FWHT_FL_PIXENC_YUV |
+ (2 << V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET);
+ break;
+ }
+}
+
+static void std_init(const struct v4l2_ctrl *ctrl, u32 idx,
+ union v4l2_ctrl_ptr ptr)
+{
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_STRING:
+ idx *= ctrl->elem_size;
+ memset(ptr.p_char + idx, ' ', ctrl->minimum);
+ ptr.p_char[idx + ctrl->minimum] = '\0';
+ break;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ ptr.p_s64[idx] = ctrl->default_value;
+ break;
+ case V4L2_CTRL_TYPE_INTEGER:
+ case V4L2_CTRL_TYPE_INTEGER_MENU:
+ case V4L2_CTRL_TYPE_MENU:
+ case V4L2_CTRL_TYPE_BITMASK:
+ 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;
+ case V4L2_CTRL_TYPE_U16:
+ ptr.p_u16[idx] = ctrl->default_value;
+ break;
+ case V4L2_CTRL_TYPE_U32:
+ ptr.p_u32[idx] = ctrl->default_value;
+ break;
+ default:
+ std_init_compound(ctrl, idx, ptr);
+ break;
+ }
+}
+
+static void std_log(const struct v4l2_ctrl *ctrl)
+{
+ union v4l2_ctrl_ptr ptr = ctrl->p_cur;
+
+ if (ctrl->is_array) {
+ unsigned i;
+
+ for (i = 0; i < ctrl->nr_of_dims; i++)
+ pr_cont("[%u]", ctrl->dims[i]);
+ pr_cont(" ");
+ }
+
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ pr_cont("%d", *ptr.p_s32);
+ break;
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ pr_cont("%s", *ptr.p_s32 ? "true" : "false");
+ break;
+ case V4L2_CTRL_TYPE_MENU:
+ pr_cont("%s", ctrl->qmenu[*ptr.p_s32]);
+ break;
+ case V4L2_CTRL_TYPE_INTEGER_MENU:
+ pr_cont("%lld", ctrl->qmenu_int[*ptr.p_s32]);
+ break;
+ case V4L2_CTRL_TYPE_BITMASK:
+ pr_cont("0x%08x", *ptr.p_s32);
+ break;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ pr_cont("%lld", *ptr.p_s64);
+ break;
+ case V4L2_CTRL_TYPE_STRING:
+ pr_cont("%s", ptr.p_char);
+ break;
+ case V4L2_CTRL_TYPE_U8:
+ pr_cont("%u", (unsigned)*ptr.p_u8);
+ break;
+ case V4L2_CTRL_TYPE_U16:
+ pr_cont("%u", (unsigned)*ptr.p_u16);
+ break;
+ case V4L2_CTRL_TYPE_U32:
+ pr_cont("%u", (unsigned)*ptr.p_u32);
+ break;
+ case V4L2_CTRL_TYPE_H264_SPS:
+ pr_cont("H264_SPS");
+ break;
+ case V4L2_CTRL_TYPE_H264_PPS:
+ pr_cont("H264_PPS");
+ break;
+ case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
+ pr_cont("H264_SCALING_MATRIX");
+ break;
+ case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
+ pr_cont("H264_SLICE_PARAMS");
+ break;
+ case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
+ pr_cont("H264_DECODE_PARAMS");
+ break;
+ case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
+ pr_cont("H264_PRED_WEIGHTS");
+ break;
+ case V4L2_CTRL_TYPE_FWHT_PARAMS:
+ pr_cont("FWHT_PARAMS");
+ break;
+ case V4L2_CTRL_TYPE_VP8_FRAME:
+ pr_cont("VP8_FRAME");
+ break;
+ case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
+ pr_cont("HDR10_CLL_INFO");
+ break;
+ case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
+ pr_cont("HDR10_MASTERING_DISPLAY");
+ break;
+ case V4L2_CTRL_TYPE_MPEG2_QUANTISATION:
+ pr_cont("MPEG2_QUANTISATION");
+ break;
+ case V4L2_CTRL_TYPE_MPEG2_SEQUENCE:
+ pr_cont("MPEG2_SEQUENCE");
+ break;
+ case V4L2_CTRL_TYPE_MPEG2_PICTURE:
+ pr_cont("MPEG2_PICTURE");
+ break;
+ default:
+ pr_cont("unknown type %d", ctrl->type);
+ break;
+ }
+}
+
+/*
+ * Round towards the closest legal value. Be careful when we are
+ * close to the maximum range of the control type to prevent
+ * wrap-arounds.
+ */
+#define ROUND_TO_RANGE(val, offset_type, ctrl) \
+({ \
+ offset_type offset; \
+ if ((ctrl)->maximum >= 0 && \
+ val >= (ctrl)->maximum - (s32)((ctrl)->step / 2)) \
+ val = (ctrl)->maximum; \
+ else \
+ val += (s32)((ctrl)->step / 2); \
+ val = clamp_t(typeof(val), val, \
+ (ctrl)->minimum, (ctrl)->maximum); \
+ offset = (val) - (ctrl)->minimum; \
+ offset = (ctrl)->step * (offset / (u32)(ctrl)->step); \
+ val = (ctrl)->minimum + offset; \
+ 0; \
+})
+
+/* Validate a new control */
+
+#define zero_padding(s) \
+ memset(&(s).padding, 0, sizeof((s).padding))
+#define zero_reserved(s) \
+ memset(&(s).reserved, 0, sizeof((s).reserved))
+
+/*
+ * Compound controls validation requires setting unused fields/flags to zero
+ * in order to properly detect unchanged controls with std_equal's memcmp.
+ */
+static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
+ union v4l2_ctrl_ptr ptr)
+{
+ struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence;
+ struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture;
+ struct v4l2_ctrl_vp8_frame *p_vp8_frame;
+ struct v4l2_ctrl_fwht_params *p_fwht_params;
+ struct v4l2_ctrl_h264_sps *p_h264_sps;
+ struct v4l2_ctrl_h264_pps *p_h264_pps;
+ struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights;
+ struct v4l2_ctrl_h264_slice_params *p_h264_slice_params;
+ struct v4l2_ctrl_h264_decode_params *p_h264_dec_params;
+ struct v4l2_ctrl_hevc_sps *p_hevc_sps;
+ struct v4l2_ctrl_hevc_pps *p_hevc_pps;
+ struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params;
+ struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering;
+ struct v4l2_ctrl_hevc_decode_params *p_hevc_decode_params;
+ struct v4l2_area *area;
+ void *p = ptr.p + idx * ctrl->elem_size;
+ unsigned int i;
+
+ switch ((u32)ctrl->type) {
+ case V4L2_CTRL_TYPE_MPEG2_SEQUENCE:
+ p_mpeg2_sequence = p;
+
+ switch (p_mpeg2_sequence->chroma_format) {
+ case 1: /* 4:2:0 */
+ case 2: /* 4:2:2 */
+ case 3: /* 4:4:4 */
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case V4L2_CTRL_TYPE_MPEG2_PICTURE:
+ p_mpeg2_picture = p;
+
+ switch (p_mpeg2_picture->intra_dc_precision) {
+ case 0: /* 8 bits */
+ case 1: /* 9 bits */
+ case 2: /* 10 bits */
+ case 3: /* 11 bits */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (p_mpeg2_picture->picture_structure) {
+ case V4L2_MPEG2_PIC_TOP_FIELD:
+ case V4L2_MPEG2_PIC_BOTTOM_FIELD:
+ case V4L2_MPEG2_PIC_FRAME:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (p_mpeg2_picture->picture_coding_type) {
+ case V4L2_MPEG2_PIC_CODING_TYPE_I:
+ case V4L2_MPEG2_PIC_CODING_TYPE_P:
+ case V4L2_MPEG2_PIC_CODING_TYPE_B:
+ break;
+ default:
+ return -EINVAL;
+ }
+ zero_reserved(*p_mpeg2_picture);
+ break;
+
+ case V4L2_CTRL_TYPE_MPEG2_QUANTISATION:
+ break;
+
+ case V4L2_CTRL_TYPE_FWHT_PARAMS:
+ p_fwht_params = p;
+ if (p_fwht_params->version < V4L2_FWHT_VERSION)
+ return -EINVAL;
+ if (!p_fwht_params->width || !p_fwht_params->height)
+ return -EINVAL;
+ break;
+
+ case V4L2_CTRL_TYPE_H264_SPS:
+ p_h264_sps = p;
+
+ /* Some syntax elements are only conditionally valid */
+ if (p_h264_sps->pic_order_cnt_type != 0) {
+ p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 = 0;
+ } else if (p_h264_sps->pic_order_cnt_type != 1) {
+ p_h264_sps->num_ref_frames_in_pic_order_cnt_cycle = 0;
+ p_h264_sps->offset_for_non_ref_pic = 0;
+ p_h264_sps->offset_for_top_to_bottom_field = 0;
+ memset(&p_h264_sps->offset_for_ref_frame, 0,
+ sizeof(p_h264_sps->offset_for_ref_frame));
+ }
+
+ if (!V4L2_H264_SPS_HAS_CHROMA_FORMAT(p_h264_sps)) {
+ p_h264_sps->chroma_format_idc = 1;
+ p_h264_sps->bit_depth_luma_minus8 = 0;
+ p_h264_sps->bit_depth_chroma_minus8 = 0;
+
+ p_h264_sps->flags &=
+ ~V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS;
+
+ if (p_h264_sps->chroma_format_idc < 3)
+ p_h264_sps->flags &=
+ ~V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE;
+ }
+
+ if (p_h264_sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)
+ p_h264_sps->flags &=
+ ~V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD;
+
+ /*
+ * Chroma 4:2:2 format require at least High 4:2:2 profile.
+ *
+ * The H264 specification and well-known parser implementations
+ * use profile-idc values directly, as that is clearer and
+ * less ambiguous. We do the same here.
+ */
+ if (p_h264_sps->profile_idc < 122 &&
+ p_h264_sps->chroma_format_idc > 1)
+ return -EINVAL;
+ /* Chroma 4:4:4 format require at least High 4:2:2 profile */
+ if (p_h264_sps->profile_idc < 244 &&
+ p_h264_sps->chroma_format_idc > 2)
+ return -EINVAL;
+ if (p_h264_sps->chroma_format_idc > 3)
+ return -EINVAL;
+
+ if (p_h264_sps->bit_depth_luma_minus8 > 6)
+ return -EINVAL;
+ if (p_h264_sps->bit_depth_chroma_minus8 > 6)
+ return -EINVAL;
+ if (p_h264_sps->log2_max_frame_num_minus4 > 12)
+ return -EINVAL;
+ if (p_h264_sps->pic_order_cnt_type > 2)
+ return -EINVAL;
+ if (p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 > 12)
+ return -EINVAL;
+ if (p_h264_sps->max_num_ref_frames > V4L2_H264_REF_LIST_LEN)
+ return -EINVAL;
+ break;
+
+ case V4L2_CTRL_TYPE_H264_PPS:
+ p_h264_pps = p;
+
+ if (p_h264_pps->num_slice_groups_minus1 > 7)
+ return -EINVAL;
+ if (p_h264_pps->num_ref_idx_l0_default_active_minus1 >
+ (V4L2_H264_REF_LIST_LEN - 1))
+ return -EINVAL;
+ if (p_h264_pps->num_ref_idx_l1_default_active_minus1 >
+ (V4L2_H264_REF_LIST_LEN - 1))
+ return -EINVAL;
+ if (p_h264_pps->weighted_bipred_idc > 2)
+ return -EINVAL;
+ /*
+ * pic_init_qp_minus26 shall be in the range of
+ * -(26 + QpBdOffset_y) to +25, inclusive,
+ * where QpBdOffset_y is 6 * bit_depth_luma_minus8
+ */
+ if (p_h264_pps->pic_init_qp_minus26 < -62 ||
+ p_h264_pps->pic_init_qp_minus26 > 25)
+ return -EINVAL;
+ if (p_h264_pps->pic_init_qs_minus26 < -26 ||
+ p_h264_pps->pic_init_qs_minus26 > 25)
+ return -EINVAL;
+ if (p_h264_pps->chroma_qp_index_offset < -12 ||
+ p_h264_pps->chroma_qp_index_offset > 12)
+ return -EINVAL;
+ if (p_h264_pps->second_chroma_qp_index_offset < -12 ||
+ p_h264_pps->second_chroma_qp_index_offset > 12)
+ return -EINVAL;
+ break;
+
+ case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
+ break;
+
+ case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
+ p_h264_pred_weights = p;
+
+ if (p_h264_pred_weights->luma_log2_weight_denom > 7)
+ return -EINVAL;
+ if (p_h264_pred_weights->chroma_log2_weight_denom > 7)
+ return -EINVAL;
+ break;
+
+ case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
+ p_h264_slice_params = p;
+
+ if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B)
+ p_h264_slice_params->flags &=
+ ~V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED;
+
+ if (p_h264_slice_params->colour_plane_id > 2)
+ return -EINVAL;
+ if (p_h264_slice_params->cabac_init_idc > 2)
+ return -EINVAL;
+ if (p_h264_slice_params->disable_deblocking_filter_idc > 2)
+ return -EINVAL;
+ if (p_h264_slice_params->slice_alpha_c0_offset_div2 < -6 ||
+ p_h264_slice_params->slice_alpha_c0_offset_div2 > 6)
+ return -EINVAL;
+ if (p_h264_slice_params->slice_beta_offset_div2 < -6 ||
+ p_h264_slice_params->slice_beta_offset_div2 > 6)
+ return -EINVAL;
+
+ if (p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_I ||
+ p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_SI)
+ p_h264_slice_params->num_ref_idx_l0_active_minus1 = 0;
+ if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B)
+ p_h264_slice_params->num_ref_idx_l1_active_minus1 = 0;
+
+ if (p_h264_slice_params->num_ref_idx_l0_active_minus1 >
+ (V4L2_H264_REF_LIST_LEN - 1))
+ return -EINVAL;
+ if (p_h264_slice_params->num_ref_idx_l1_active_minus1 >
+ (V4L2_H264_REF_LIST_LEN - 1))
+ return -EINVAL;
+ zero_reserved(*p_h264_slice_params);
+ break;
+
+ case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
+ p_h264_dec_params = p;
+
+ if (p_h264_dec_params->nal_ref_idc > 3)
+ return -EINVAL;
+ for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
+ struct v4l2_h264_dpb_entry *dpb_entry =
+ &p_h264_dec_params->dpb[i];
+
+ zero_reserved(*dpb_entry);
+ }
+ zero_reserved(*p_h264_dec_params);
+ break;
+
+ case V4L2_CTRL_TYPE_VP8_FRAME:
+ p_vp8_frame = p;
+
+ switch (p_vp8_frame->num_dct_parts) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ return -EINVAL;
+ }
+ zero_padding(p_vp8_frame->segment);
+ zero_padding(p_vp8_frame->lf);
+ zero_padding(p_vp8_frame->quant);
+ zero_padding(p_vp8_frame->entropy);
+ zero_padding(p_vp8_frame->coder_state);
+ break;
+
+ case V4L2_CTRL_TYPE_HEVC_SPS:
+ p_hevc_sps = p;
+
+ if (!(p_hevc_sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED)) {
+ p_hevc_sps->pcm_sample_bit_depth_luma_minus1 = 0;
+ p_hevc_sps->pcm_sample_bit_depth_chroma_minus1 = 0;
+ p_hevc_sps->log2_min_pcm_luma_coding_block_size_minus3 = 0;
+ p_hevc_sps->log2_diff_max_min_pcm_luma_coding_block_size = 0;
+ }
+
+ if (!(p_hevc_sps->flags &
+ V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT))
+ p_hevc_sps->num_long_term_ref_pics_sps = 0;
+ break;
+
+ case V4L2_CTRL_TYPE_HEVC_PPS:
+ p_hevc_pps = p;
+
+ if (!(p_hevc_pps->flags &
+ V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED))
+ p_hevc_pps->diff_cu_qp_delta_depth = 0;
+
+ if (!(p_hevc_pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED)) {
+ p_hevc_pps->num_tile_columns_minus1 = 0;
+ p_hevc_pps->num_tile_rows_minus1 = 0;
+ memset(&p_hevc_pps->column_width_minus1, 0,
+ sizeof(p_hevc_pps->column_width_minus1));
+ memset(&p_hevc_pps->row_height_minus1, 0,
+ sizeof(p_hevc_pps->row_height_minus1));
+
+ p_hevc_pps->flags &=
+ ~V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED;
+ }
+
+ if (p_hevc_pps->flags &
+ V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER) {
+ p_hevc_pps->pps_beta_offset_div2 = 0;
+ p_hevc_pps->pps_tc_offset_div2 = 0;
+ }
+
+ zero_padding(*p_hevc_pps);
+ break;
+
+ case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS:
+ p_hevc_decode_params = p;
+
+ if (p_hevc_decode_params->num_active_dpb_entries >
+ V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
+ return -EINVAL;
+
+ for (i = 0; i < p_hevc_decode_params->num_active_dpb_entries;
+ i++) {
+ struct v4l2_hevc_dpb_entry *dpb_entry =
+ &p_hevc_decode_params->dpb[i];
+
+ zero_padding(*dpb_entry);
+ }
+ break;
+
+ case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
+ p_hevc_slice_params = p;
+
+ zero_padding(p_hevc_slice_params->pred_weight_table);
+ zero_padding(*p_hevc_slice_params);
+ break;
+
+ case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
+ break;
+
+ case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
+ p_hdr10_mastering = p;
+
+ for (i = 0; i < 3; ++i) {
+ if (p_hdr10_mastering->display_primaries_x[i] <
+ V4L2_HDR10_MASTERING_PRIMARIES_X_LOW ||
+ p_hdr10_mastering->display_primaries_x[i] >
+ V4L2_HDR10_MASTERING_PRIMARIES_X_HIGH ||
+ p_hdr10_mastering->display_primaries_y[i] <
+ V4L2_HDR10_MASTERING_PRIMARIES_Y_LOW ||
+ p_hdr10_mastering->display_primaries_y[i] >
+ V4L2_HDR10_MASTERING_PRIMARIES_Y_HIGH)
+ return -EINVAL;
+ }
+
+ if (p_hdr10_mastering->white_point_x <
+ V4L2_HDR10_MASTERING_WHITE_POINT_X_LOW ||
+ p_hdr10_mastering->white_point_x >
+ V4L2_HDR10_MASTERING_WHITE_POINT_X_HIGH ||
+ p_hdr10_mastering->white_point_y <
+ V4L2_HDR10_MASTERING_WHITE_POINT_Y_LOW ||
+ p_hdr10_mastering->white_point_y >
+ V4L2_HDR10_MASTERING_WHITE_POINT_Y_HIGH)
+ return -EINVAL;
+
+ if (p_hdr10_mastering->max_display_mastering_luminance <
+ V4L2_HDR10_MASTERING_MAX_LUMA_LOW ||
+ p_hdr10_mastering->max_display_mastering_luminance >
+ V4L2_HDR10_MASTERING_MAX_LUMA_HIGH ||
+ p_hdr10_mastering->min_display_mastering_luminance <
+ V4L2_HDR10_MASTERING_MIN_LUMA_LOW ||
+ p_hdr10_mastering->min_display_mastering_luminance >
+ V4L2_HDR10_MASTERING_MIN_LUMA_HIGH)
+ return -EINVAL;
+
+ /* The following restriction comes from ITU-T Rec. H.265 spec */
+ if (p_hdr10_mastering->max_display_mastering_luminance ==
+ V4L2_HDR10_MASTERING_MAX_LUMA_LOW &&
+ p_hdr10_mastering->min_display_mastering_luminance ==
+ V4L2_HDR10_MASTERING_MIN_LUMA_HIGH)
+ return -EINVAL;
+
+ break;
+
+ case V4L2_CTRL_TYPE_AREA:
+ area = p;
+ if (!area->width || !area->height)
+ return -EINVAL;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
+ union v4l2_ctrl_ptr ptr)
+{
+ size_t len;
+ u64 offset;
+ s64 val;
+
+ switch ((u32)ctrl->type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ return ROUND_TO_RANGE(ptr.p_s32[idx], u32, ctrl);
+ case V4L2_CTRL_TYPE_INTEGER64:
+ /*
+ * We can't use the ROUND_TO_RANGE define here due to
+ * the u64 divide that needs special care.
+ */
+ val = ptr.p_s64[idx];
+ if (ctrl->maximum >= 0 && val >= ctrl->maximum - (s64)(ctrl->step / 2))
+ val = ctrl->maximum;
+ else
+ val += (s64)(ctrl->step / 2);
+ val = clamp_t(s64, val, ctrl->minimum, ctrl->maximum);
+ offset = val - ctrl->minimum;
+ do_div(offset, ctrl->step);
+ ptr.p_s64[idx] = ctrl->minimum + offset * ctrl->step;
+ return 0;
+ case V4L2_CTRL_TYPE_U8:
+ return ROUND_TO_RANGE(ptr.p_u8[idx], u8, ctrl);
+ case V4L2_CTRL_TYPE_U16:
+ return ROUND_TO_RANGE(ptr.p_u16[idx], u16, ctrl);
+ case V4L2_CTRL_TYPE_U32:
+ return ROUND_TO_RANGE(ptr.p_u32[idx], u32, ctrl);
+
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ ptr.p_s32[idx] = !!ptr.p_s32[idx];
+ return 0;
+
+ case V4L2_CTRL_TYPE_MENU:
+ case V4L2_CTRL_TYPE_INTEGER_MENU:
+ if (ptr.p_s32[idx] < ctrl->minimum || ptr.p_s32[idx] > ctrl->maximum)
+ return -ERANGE;
+ if (ptr.p_s32[idx] < BITS_PER_LONG_LONG &&
+ (ctrl->menu_skip_mask & BIT_ULL(ptr.p_s32[idx])))
+ return -EINVAL;
+ if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
+ ctrl->qmenu[ptr.p_s32[idx]][0] == '\0')
+ return -EINVAL;
+ return 0;
+
+ case V4L2_CTRL_TYPE_BITMASK:
+ ptr.p_s32[idx] &= ctrl->maximum;
+ return 0;
+
+ case V4L2_CTRL_TYPE_BUTTON:
+ case V4L2_CTRL_TYPE_CTRL_CLASS:
+ ptr.p_s32[idx] = 0;
+ return 0;
+
+ case V4L2_CTRL_TYPE_STRING:
+ idx *= ctrl->elem_size;
+ len = strlen(ptr.p_char + idx);
+ if (len < ctrl->minimum)
+ return -ERANGE;
+ if ((len - (u32)ctrl->minimum) % (u32)ctrl->step)
+ return -ERANGE;
+ return 0;
+
+ default:
+ return std_validate_compound(ctrl, idx, ptr);
+ }
+}
+
+static const struct v4l2_ctrl_type_ops std_type_ops = {
+ .equal = std_equal,
+ .init = std_init,
+ .log = std_log,
+ .validate = std_validate,
+};
+
+void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv)
+{
+ if (!ctrl)
+ return;
+ if (!notify) {
+ ctrl->call_notify = 0;
+ return;
+ }
+ if (WARN_ON(ctrl->handler->notify && ctrl->handler->notify != notify))
+ return;
+ ctrl->handler->notify = notify;
+ ctrl->handler->notify_priv = priv;
+ ctrl->call_notify = 1;
+}
+EXPORT_SYMBOL(v4l2_ctrl_notify);
+
+/* Copy the one value to another. */
+static void ptr_to_ptr(struct v4l2_ctrl *ctrl,
+ union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to)
+{
+ if (ctrl == NULL)
+ return;
+ memcpy(to.p, from.p_const, ctrl->elems * ctrl->elem_size);
+}
+
+/* Copy the new value to the current value. */
+void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
+{
+ bool changed;
+
+ if (ctrl == NULL)
+ return;
+
+ /* has_changed is set by cluster_changed */
+ changed = ctrl->has_changed;
+ if (changed)
+ ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur);
+
+ if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
+ /* Note: CH_FLAGS is only set for auto clusters. */
+ ctrl->flags &=
+ ~(V4L2_CTRL_FLAG_INACTIVE | V4L2_CTRL_FLAG_VOLATILE);
+ if (!is_cur_manual(ctrl->cluster[0])) {
+ ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ if (ctrl->cluster[0]->has_volatiles)
+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ }
+ fh = NULL;
+ }
+ if (changed || ch_flags) {
+ /* If a control was changed that was not one of the controls
+ modified by the application, then send the event to all. */
+ if (!ctrl->is_new)
+ fh = NULL;
+ send_event(fh, ctrl,
+ (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) | ch_flags);
+ if (ctrl->call_notify && changed && ctrl->handler->notify)
+ ctrl->handler->notify(ctrl, ctrl->handler->notify_priv);
+ }
+}
+
+/* Copy the current value to the new value */
+void cur_to_new(struct v4l2_ctrl *ctrl)
+{
+ if (ctrl == NULL)
+ return;
+ ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new);
+}
+
+/* Copy the new value to the request value */
+void new_to_req(struct v4l2_ctrl_ref *ref)
+{
+ if (!ref)
+ return;
+ ptr_to_ptr(ref->ctrl, ref->ctrl->p_new, ref->p_req);
+ ref->valid_p_req = true;
+}
+
+/* Copy the current value to the request value */
+void cur_to_req(struct v4l2_ctrl_ref *ref)
+{
+ if (!ref)
+ return;
+ ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->p_req);
+ ref->valid_p_req = true;
+}
+
+/* Copy the request value to the new value */
+void req_to_new(struct v4l2_ctrl_ref *ref)
+{
+ if (!ref)
+ return;
+ if (ref->valid_p_req)
+ ptr_to_ptr(ref->ctrl, ref->p_req, ref->ctrl->p_new);
+ else
+ ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->ctrl->p_new);
+}
+
+/* Control range checking */
+int check_range(enum v4l2_ctrl_type type,
+ s64 min, s64 max, u64 step, s64 def)
+{
+ switch (type) {
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ if (step != 1 || max > 1 || min < 0)
+ return -ERANGE;
+ fallthrough;
+ case V4L2_CTRL_TYPE_U8:
+ case V4L2_CTRL_TYPE_U16:
+ case V4L2_CTRL_TYPE_U32:
+ case V4L2_CTRL_TYPE_INTEGER:
+ case V4L2_CTRL_TYPE_INTEGER64:
+ if (step == 0 || min > max || def < min || def > max)
+ return -ERANGE;
+ return 0;
+ case V4L2_CTRL_TYPE_BITMASK:
+ if (step || min || !max || (def & ~max))
+ return -ERANGE;
+ return 0;
+ case V4L2_CTRL_TYPE_MENU:
+ case V4L2_CTRL_TYPE_INTEGER_MENU:
+ if (min > max || def < min || def > max)
+ return -ERANGE;
+ /* Note: step == menu_skip_mask for menu controls.
+ So here we check if the default value is masked out. */
+ if (step && ((1 << def) & step))
+ return -EINVAL;
+ return 0;
+ case V4L2_CTRL_TYPE_STRING:
+ if (min > max || min < 0 || step < 1 || def)
+ return -ERANGE;
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+/* Validate a new control */
+int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new)
+{
+ unsigned idx;
+ int err = 0;
+
+ for (idx = 0; !err && idx < ctrl->elems; idx++)
+ err = ctrl->type_ops->validate(ctrl, idx, p_new);
+ return err;
+}
+
+/* Set the handler's error code if it wasn't set earlier already */
+static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err)
+{
+ if (hdl->error == 0)
+ hdl->error = err;
+ return err;
+}
+
+/* Initialize the handler */
+int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl,
+ unsigned nr_of_controls_hint,
+ struct lock_class_key *key, const char *name)
+{
+ mutex_init(&hdl->_lock);
+ hdl->lock = &hdl->_lock;
+ lockdep_set_class_and_name(hdl->lock, key, name);
+ INIT_LIST_HEAD(&hdl->ctrls);
+ INIT_LIST_HEAD(&hdl->ctrl_refs);
+ hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;
+ hdl->buckets = kvmalloc_array(hdl->nr_of_buckets,
+ sizeof(hdl->buckets[0]),
+ GFP_KERNEL | __GFP_ZERO);
+ hdl->error = hdl->buckets ? 0 : -ENOMEM;
+ v4l2_ctrl_handler_init_request(hdl);
+ return hdl->error;
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_init_class);
+
+/* Free all controls and control refs */
+void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
+{
+ struct v4l2_ctrl_ref *ref, *next_ref;
+ struct v4l2_ctrl *ctrl, *next_ctrl;
+ struct v4l2_subscribed_event *sev, *next_sev;
+
+ if (hdl == NULL || hdl->buckets == NULL)
+ return;
+
+ v4l2_ctrl_handler_free_request(hdl);
+
+ mutex_lock(hdl->lock);
+ /* Free all nodes */
+ list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) {
+ list_del(&ref->node);
+ kfree(ref);
+ }
+ /* Free all controls owned by the handler */
+ list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) {
+ list_del(&ctrl->node);
+ list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
+ list_del(&sev->node);
+ kvfree(ctrl);
+ }
+ kvfree(hdl->buckets);
+ hdl->buckets = NULL;
+ hdl->cached = NULL;
+ hdl->error = 0;
+ mutex_unlock(hdl->lock);
+ mutex_destroy(&hdl->_lock);
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_free);
+
+/* For backwards compatibility: V4L2_CID_PRIVATE_BASE should no longer
+ be used except in G_CTRL, S_CTRL, QUERYCTRL and QUERYMENU when dealing
+ with applications that do not use the NEXT_CTRL flag.
+
+ We just find the n-th private user control. It's O(N), but that should not
+ be an issue in this particular case. */
+static struct v4l2_ctrl_ref *find_private_ref(
+ struct v4l2_ctrl_handler *hdl, u32 id)
+{
+ struct v4l2_ctrl_ref *ref;
+
+ id -= V4L2_CID_PRIVATE_BASE;
+ list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+ /* Search for private user controls that are compatible with
+ VIDIOC_G/S_CTRL. */
+ if (V4L2_CTRL_ID2WHICH(ref->ctrl->id) == V4L2_CTRL_CLASS_USER &&
+ V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) {
+ if (!ref->ctrl->is_int)
+ continue;
+ if (id == 0)
+ return ref;
+ id--;
+ }
+ }
+ return NULL;
+}
+
+/* Find a control with the given ID. */
+struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id)
+{
+ struct v4l2_ctrl_ref *ref;
+ int bucket;
+
+ id &= V4L2_CTRL_ID_MASK;
+
+ /* Old-style private controls need special handling */
+ if (id >= V4L2_CID_PRIVATE_BASE)
+ return find_private_ref(hdl, id);
+ bucket = id % hdl->nr_of_buckets;
+
+ /* Simple optimization: cache the last control found */
+ if (hdl->cached && hdl->cached->ctrl->id == id)
+ return hdl->cached;
+
+ /* Not in cache, search the hash */
+ ref = hdl->buckets ? hdl->buckets[bucket] : NULL;
+ while (ref && ref->ctrl->id != id)
+ ref = ref->next;
+
+ if (ref)
+ hdl->cached = ref; /* cache it! */
+ return ref;
+}
+
+/* Find a control with the given ID. Take the handler's lock first. */
+struct v4l2_ctrl_ref *find_ref_lock(struct v4l2_ctrl_handler *hdl, u32 id)
+{
+ struct v4l2_ctrl_ref *ref = NULL;
+
+ if (hdl) {
+ mutex_lock(hdl->lock);
+ ref = find_ref(hdl, id);
+ mutex_unlock(hdl->lock);
+ }
+ return ref;
+}
+
+/* Find a control with the given ID. */
+struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
+{
+ struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
+
+ return ref ? ref->ctrl : NULL;
+}
+EXPORT_SYMBOL(v4l2_ctrl_find);
+
+/* Allocate a new v4l2_ctrl_ref and hook it into the handler. */
+int handler_new_ref(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ctrl *ctrl,
+ struct v4l2_ctrl_ref **ctrl_ref,
+ bool from_other_dev, bool allocate_req)
+{
+ struct v4l2_ctrl_ref *ref;
+ struct v4l2_ctrl_ref *new_ref;
+ u32 id = ctrl->id;
+ u32 class_ctrl = V4L2_CTRL_ID2WHICH(id) | 1;
+ int bucket = id % hdl->nr_of_buckets; /* which bucket to use */
+ unsigned int size_extra_req = 0;
+
+ if (ctrl_ref)
+ *ctrl_ref = NULL;
+
+ /*
+ * Automatically add the control class if it is not yet present and
+ * the new control is not a compound control.
+ */
+ if (ctrl->type < V4L2_CTRL_COMPOUND_TYPES &&
+ id != class_ctrl && find_ref_lock(hdl, class_ctrl) == NULL)
+ if (!v4l2_ctrl_new_std(hdl, NULL, class_ctrl, 0, 0, 0, 0))
+ return hdl->error;
+
+ if (hdl->error)
+ return hdl->error;
+
+ if (allocate_req)
+ size_extra_req = ctrl->elems * ctrl->elem_size;
+ new_ref = kzalloc(sizeof(*new_ref) + size_extra_req, GFP_KERNEL);
+ if (!new_ref)
+ return handler_set_err(hdl, -ENOMEM);
+ new_ref->ctrl = ctrl;
+ new_ref->from_other_dev = from_other_dev;
+ if (size_extra_req)
+ new_ref->p_req.p = &new_ref[1];
+
+ INIT_LIST_HEAD(&new_ref->node);
+
+ mutex_lock(hdl->lock);
+
+ /* Add immediately at the end of the list if the list is empty, or if
+ the last element in the list has a lower ID.
+ This ensures that when elements are added in ascending order the
+ insertion is an O(1) operation. */
+ if (list_empty(&hdl->ctrl_refs) || id > node2id(hdl->ctrl_refs.prev)) {
+ list_add_tail(&new_ref->node, &hdl->ctrl_refs);
+ goto insert_in_hash;
+ }
+
+ /* Find insert position in sorted list */
+ list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+ if (ref->ctrl->id < id)
+ continue;
+ /* Don't add duplicates */
+ if (ref->ctrl->id == id) {
+ kfree(new_ref);
+ goto unlock;
+ }
+ list_add(&new_ref->node, ref->node.prev);
+ break;
+ }
+
+insert_in_hash:
+ /* Insert the control node in the hash */
+ new_ref->next = hdl->buckets[bucket];
+ 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);
+ return 0;
+}
+
+/* Add a new control */
+static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ const struct v4l2_ctrl_type_ops *type_ops,
+ u32 id, const char *name, enum v4l2_ctrl_type type,
+ s64 min, s64 max, u64 step, s64 def,
+ const u32 dims[V4L2_CTRL_MAX_DIMS], u32 elem_size,
+ u32 flags, const char * const *qmenu,
+ const s64 *qmenu_int, const union v4l2_ctrl_ptr p_def,
+ void *priv)
+{
+ struct v4l2_ctrl *ctrl;
+ unsigned sz_extra;
+ unsigned nr_of_dims = 0;
+ unsigned elems = 1;
+ bool is_array;
+ unsigned tot_ctrl_size;
+ unsigned idx;
+ void *data;
+ int err;
+
+ if (hdl->error)
+ return NULL;
+
+ while (dims && dims[nr_of_dims]) {
+ elems *= dims[nr_of_dims];
+ nr_of_dims++;
+ if (nr_of_dims == V4L2_CTRL_MAX_DIMS)
+ break;
+ }
+ is_array = nr_of_dims > 0;
+
+ /* Prefill elem_size for all types handled by std_type_ops */
+ switch ((u32)type) {
+ case V4L2_CTRL_TYPE_INTEGER64:
+ elem_size = sizeof(s64);
+ break;
+ case V4L2_CTRL_TYPE_STRING:
+ elem_size = max + 1;
+ break;
+ case V4L2_CTRL_TYPE_U8:
+ elem_size = sizeof(u8);
+ break;
+ case V4L2_CTRL_TYPE_U16:
+ elem_size = sizeof(u16);
+ break;
+ case V4L2_CTRL_TYPE_U32:
+ elem_size = sizeof(u32);
+ break;
+ case V4L2_CTRL_TYPE_MPEG2_SEQUENCE:
+ elem_size = sizeof(struct v4l2_ctrl_mpeg2_sequence);
+ break;
+ case V4L2_CTRL_TYPE_MPEG2_PICTURE:
+ elem_size = sizeof(struct v4l2_ctrl_mpeg2_picture);
+ break;
+ case V4L2_CTRL_TYPE_MPEG2_QUANTISATION:
+ elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantisation);
+ break;
+ 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;
+ case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
+ elem_size = sizeof(struct v4l2_ctrl_h264_pred_weights);
+ break;
+ case V4L2_CTRL_TYPE_VP8_FRAME:
+ elem_size = sizeof(struct v4l2_ctrl_vp8_frame);
+ break;
+ case V4L2_CTRL_TYPE_HEVC_SPS:
+ elem_size = sizeof(struct v4l2_ctrl_hevc_sps);
+ break;
+ case V4L2_CTRL_TYPE_HEVC_PPS:
+ elem_size = sizeof(struct v4l2_ctrl_hevc_pps);
+ break;
+ case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
+ elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params);
+ break;
+ case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS:
+ elem_size = sizeof(struct v4l2_ctrl_hevc_decode_params);
+ break;
+ case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
+ elem_size = sizeof(struct v4l2_ctrl_hdr10_cll_info);
+ break;
+ case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
+ elem_size = sizeof(struct v4l2_ctrl_hdr10_mastering_display);
+ break;
+ case V4L2_CTRL_TYPE_AREA:
+ elem_size = sizeof(struct v4l2_area);
+ break;
+ default:
+ if (type < V4L2_CTRL_COMPOUND_TYPES)
+ elem_size = sizeof(s32);
+ break;
+ }
+ tot_ctrl_size = elem_size * elems;
+
+ /* Sanity checks */
+ if (id == 0 || name == NULL || !elem_size ||
+ id >= V4L2_CID_PRIVATE_BASE ||
+ (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
+ (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) {
+ handler_set_err(hdl, -ERANGE);
+ return NULL;
+ }
+ err = check_range(type, min, max, step, def);
+ if (err) {
+ handler_set_err(hdl, err);
+ return NULL;
+ }
+ if (is_array &&
+ (type == V4L2_CTRL_TYPE_BUTTON ||
+ type == V4L2_CTRL_TYPE_CTRL_CLASS)) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+
+ sz_extra = 0;
+ if (type == V4L2_CTRL_TYPE_BUTTON)
+ flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
+ V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+ else if (type == V4L2_CTRL_TYPE_CTRL_CLASS)
+ flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ else if (type == V4L2_CTRL_TYPE_INTEGER64 ||
+ type == V4L2_CTRL_TYPE_STRING ||
+ type >= V4L2_CTRL_COMPOUND_TYPES ||
+ is_array)
+ sz_extra += 2 * tot_ctrl_size;
+
+ if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const)
+ sz_extra += elem_size;
+
+ ctrl = kvzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
+ if (ctrl == NULL) {
+ handler_set_err(hdl, -ENOMEM);
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&ctrl->node);
+ INIT_LIST_HEAD(&ctrl->ev_subs);
+ ctrl->handler = hdl;
+ ctrl->ops = ops;
+ ctrl->type_ops = type_ops ? type_ops : &std_type_ops;
+ ctrl->id = id;
+ ctrl->name = name;
+ ctrl->type = type;
+ ctrl->flags = flags;
+ ctrl->minimum = min;
+ ctrl->maximum = max;
+ ctrl->step = step;
+ ctrl->default_value = def;
+ ctrl->is_string = !is_array && type == V4L2_CTRL_TYPE_STRING;
+ ctrl->is_ptr = is_array || type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string;
+ ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
+ ctrl->is_array = is_array;
+ ctrl->elems = elems;
+ ctrl->nr_of_dims = nr_of_dims;
+ if (nr_of_dims)
+ memcpy(ctrl->dims, dims, nr_of_dims * sizeof(dims[0]));
+ ctrl->elem_size = elem_size;
+ if (type == V4L2_CTRL_TYPE_MENU)
+ ctrl->qmenu = qmenu;
+ else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
+ ctrl->qmenu_int = qmenu_int;
+ ctrl->priv = priv;
+ ctrl->cur.val = ctrl->val = def;
+ data = &ctrl[1];
+
+ if (!ctrl->is_int) {
+ ctrl->p_new.p = data;
+ ctrl->p_cur.p = data + tot_ctrl_size;
+ } else {
+ ctrl->p_new.p = &ctrl->val;
+ ctrl->p_cur.p = &ctrl->cur.val;
+ }
+
+ if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) {
+ ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size;
+ memcpy(ctrl->p_def.p, p_def.p_const, elem_size);
+ }
+
+ for (idx = 0; idx < elems; idx++) {
+ ctrl->type_ops->init(ctrl, idx, ctrl->p_cur);
+ ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
+ }
+
+ if (handler_new_ref(hdl, ctrl, NULL, false, false)) {
+ kvfree(ctrl);
+ return NULL;
+ }
+ mutex_lock(hdl->lock);
+ list_add_tail(&ctrl->node, &hdl->ctrls);
+ mutex_unlock(hdl->lock);
+ return ctrl;
+}
+
+struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_config *cfg, void *priv)
+{
+ bool is_menu;
+ struct v4l2_ctrl *ctrl;
+ const char *name = cfg->name;
+ const char * const *qmenu = cfg->qmenu;
+ const s64 *qmenu_int = cfg->qmenu_int;
+ enum v4l2_ctrl_type type = cfg->type;
+ u32 flags = cfg->flags;
+ s64 min = cfg->min;
+ s64 max = cfg->max;
+ u64 step = cfg->step;
+ s64 def = cfg->def;
+
+ if (name == NULL)
+ v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
+ &def, &flags);
+
+ 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 (type == V4L2_CTRL_TYPE_MENU && !qmenu) {
+ qmenu = v4l2_ctrl_get_menu(cfg->id);
+ } else if (type == V4L2_CTRL_TYPE_INTEGER_MENU && !qmenu_int) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+
+ ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name,
+ type, min, max,
+ is_menu ? cfg->menu_skip_mask : step, def,
+ cfg->dims, cfg->elem_size,
+ flags, qmenu, qmenu_int, cfg->p_def, priv);
+ if (ctrl)
+ ctrl->is_private = cfg->is_private;
+ return ctrl;
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_custom);
+
+/* Helper function for standard non-menu controls */
+struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, s64 min, s64 max, u64 step, s64 def)
+{
+ const char *name;
+ enum v4l2_ctrl_type type;
+ u32 flags;
+
+ v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+ if (type == V4L2_CTRL_TYPE_MENU ||
+ type == V4L2_CTRL_TYPE_INTEGER_MENU ||
+ type >= V4L2_CTRL_COMPOUND_TYPES) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+ return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
+ min, max, step, def, NULL, 0,
+ flags, NULL, NULL, ptr_null, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_std);
+
+/* Helper function for standard menu controls */
+struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, u8 _max, u64 mask, u8 _def)
+{
+ const char * const *qmenu = NULL;
+ const s64 *qmenu_int = NULL;
+ unsigned int qmenu_int_len = 0;
+ const char *name;
+ enum v4l2_ctrl_type type;
+ s64 min;
+ s64 max = _max;
+ s64 def = _def;
+ u64 step;
+ u32 flags;
+
+ v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+
+ if (type == V4L2_CTRL_TYPE_MENU)
+ qmenu = v4l2_ctrl_get_menu(id);
+ else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
+ qmenu_int = v4l2_ctrl_get_int_menu(id, &qmenu_int_len);
+
+ if ((!qmenu && !qmenu_int) || (qmenu_int && max > qmenu_int_len)) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+ return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
+ 0, max, mask, def, NULL, 0,
+ flags, qmenu, qmenu_int, ptr_null, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
+
+/* Helper function for standard menu controls with driver defined menu */
+struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops, u32 id, u8 _max,
+ u64 mask, u8 _def, const char * const *qmenu)
+{
+ enum v4l2_ctrl_type type;
+ const char *name;
+ u32 flags;
+ u64 step;
+ s64 min;
+ s64 max = _max;
+ s64 def = _def;
+
+ /* v4l2_ctrl_new_std_menu_items() should only be called for
+ * standard controls without a standard menu.
+ */
+ if (v4l2_ctrl_get_menu(id)) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+
+ v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+ if (type != V4L2_CTRL_TYPE_MENU || qmenu == NULL) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+ return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
+ 0, max, mask, def, NULL, 0,
+ flags, qmenu, NULL, ptr_null, NULL);
+
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
+
+/* Helper function for standard compound controls */
+struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops, u32 id,
+ const union v4l2_ctrl_ptr p_def)
+{
+ const char *name;
+ enum v4l2_ctrl_type type;
+ u32 flags;
+ s64 min, max, step, def;
+
+ v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+ if (type < V4L2_CTRL_COMPOUND_TYPES) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+ return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
+ min, max, step, def, NULL, 0,
+ flags, NULL, NULL, p_def, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_std_compound);
+
+/* Helper function for standard integer menu controls */
+struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, u8 _max, u8 _def, const s64 *qmenu_int)
+{
+ const char *name;
+ enum v4l2_ctrl_type type;
+ s64 min;
+ u64 step;
+ s64 max = _max;
+ s64 def = _def;
+ u32 flags;
+
+ v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+ if (type != V4L2_CTRL_TYPE_INTEGER_MENU) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+ return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
+ 0, max, 0, def, NULL, 0,
+ flags, NULL, qmenu_int, ptr_null, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
+
+/* Add the controls from another handler to our own. */
+int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ctrl_handler *add,
+ bool (*filter)(const struct v4l2_ctrl *ctrl),
+ bool from_other_dev)
+{
+ struct v4l2_ctrl_ref *ref;
+ int ret = 0;
+
+ /* Do nothing if either handler is NULL or if they are the same */
+ if (!hdl || !add || hdl == add)
+ return 0;
+ if (hdl->error)
+ return hdl->error;
+ mutex_lock(add->lock);
+ list_for_each_entry(ref, &add->ctrl_refs, node) {
+ struct v4l2_ctrl *ctrl = ref->ctrl;
+
+ /* Skip handler-private controls. */
+ if (ctrl->is_private)
+ continue;
+ /* And control classes */
+ if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+ continue;
+ /* Filter any unwanted controls */
+ if (filter && !filter(ctrl))
+ continue;
+ ret = handler_new_ref(hdl, ctrl, NULL, from_other_dev, false);
+ if (ret)
+ break;
+ }
+ mutex_unlock(add->lock);
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_ctrl_add_handler);
+
+bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl)
+{
+ if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_TX)
+ return true;
+ if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_RX)
+ return true;
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+EXPORT_SYMBOL(v4l2_ctrl_radio_filter);
+
+/* Cluster controls */
+void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
+{
+ bool has_volatiles = false;
+ int i;
+
+ /* The first control is the master control and it must not be NULL */
+ if (WARN_ON(ncontrols == 0 || controls[0] == NULL))
+ return;
+
+ for (i = 0; i < ncontrols; i++) {
+ if (controls[i]) {
+ controls[i]->cluster = controls;
+ controls[i]->ncontrols = ncontrols;
+ if (controls[i]->flags & V4L2_CTRL_FLAG_VOLATILE)
+ has_volatiles = true;
+ }
+ }
+ controls[0]->has_volatiles = has_volatiles;
+}
+EXPORT_SYMBOL(v4l2_ctrl_cluster);
+
+void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
+ u8 manual_val, bool set_volatile)
+{
+ struct v4l2_ctrl *master = controls[0];
+ u32 flag = 0;
+ int i;
+
+ v4l2_ctrl_cluster(ncontrols, controls);
+ WARN_ON(ncontrols <= 1);
+ WARN_ON(manual_val < master->minimum || manual_val > master->maximum);
+ WARN_ON(set_volatile && !has_op(master, g_volatile_ctrl));
+ master->is_auto = true;
+ master->has_volatiles = set_volatile;
+ master->manual_mode_value = manual_val;
+ master->flags |= V4L2_CTRL_FLAG_UPDATE;
+
+ if (!is_cur_manual(master))
+ flag = V4L2_CTRL_FLAG_INACTIVE |
+ (set_volatile ? V4L2_CTRL_FLAG_VOLATILE : 0);
+
+ for (i = 1; i < ncontrols; i++)
+ if (controls[i])
+ controls[i]->flags |= flag;
+}
+EXPORT_SYMBOL(v4l2_ctrl_auto_cluster);
+
+/*
+ * Obtain the current volatile values of an autocluster and mark them
+ * as new.
+ */
+void update_from_auto_cluster(struct v4l2_ctrl *master)
+{
+ int i;
+
+ for (i = 1; i < master->ncontrols; i++)
+ cur_to_new(master->cluster[i]);
+ if (!call_op(master, g_volatile_ctrl))
+ for (i = 1; i < master->ncontrols; i++)
+ if (master->cluster[i])
+ master->cluster[i]->is_new = 1;
+}
+
+/*
+ * Return non-zero if one or more of the controls in the cluster has a new
+ * value that differs from the current value.
+ */
+static int cluster_changed(struct v4l2_ctrl *master)
+{
+ bool changed = false;
+ unsigned int idx;
+ int i;
+
+ for (i = 0; i < master->ncontrols; i++) {
+ struct v4l2_ctrl *ctrl = master->cluster[i];
+ bool ctrl_changed = false;
+
+ if (!ctrl)
+ continue;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_EXECUTE_ON_WRITE) {
+ changed = true;
+ ctrl_changed = true;
+ }
+
+ /*
+ * Set has_changed to false to avoid generating
+ * the event V4L2_EVENT_CTRL_CH_VALUE
+ */
+ if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
+ ctrl->has_changed = false;
+ continue;
+ }
+
+ for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++)
+ ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
+ ctrl->p_cur, ctrl->p_new);
+ ctrl->has_changed = ctrl_changed;
+ changed |= ctrl->has_changed;
+ }
+ return changed;
+}
+
+/*
+ * Core function that calls try/s_ctrl and ensures that the new value is
+ * copied to the current value on a set.
+ * Must be called with ctrl->handler->lock held.
+ */
+int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
+ bool set, u32 ch_flags)
+{
+ bool update_flag;
+ int ret;
+ int i;
+
+ /*
+ * Go through the cluster and either validate the new value or
+ * (if no new value was set), copy the current value to the new
+ * value, ensuring a consistent view for the control ops when
+ * called.
+ */
+ for (i = 0; i < master->ncontrols; i++) {
+ struct v4l2_ctrl *ctrl = master->cluster[i];
+
+ if (!ctrl)
+ continue;
+
+ if (!ctrl->is_new) {
+ cur_to_new(ctrl);
+ continue;
+ }
+ /*
+ * Check again: it may have changed since the
+ * previous check in try_or_set_ext_ctrls().
+ */
+ if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
+ return -EBUSY;
+ }
+
+ ret = call_op(master, try_ctrl);
+
+ /* Don't set if there is no change */
+ if (ret || !set || !cluster_changed(master))
+ return ret;
+ ret = call_op(master, s_ctrl);
+ if (ret)
+ return ret;
+
+ /* If OK, then make the new values permanent. */
+ update_flag = is_cur_manual(master) != is_new_manual(master);
+
+ for (i = 0; i < master->ncontrols; i++) {
+ /*
+ * If we switch from auto to manual mode, and this cluster
+ * contains volatile controls, then all non-master controls
+ * have to be marked as changed. The 'new' value contains
+ * the volatile value (obtained by update_from_auto_cluster),
+ * which now has to become the current value.
+ */
+ if (i && update_flag && is_new_manual(master) &&
+ master->has_volatiles && master->cluster[i])
+ master->cluster[i]->has_changed = true;
+
+ new_to_cur(fh, master->cluster[i], ch_flags |
+ ((update_flag && i > 0) ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
+ }
+ return 0;
+}
+
+/* Activate/deactivate a control. */
+void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active)
+{
+ /* invert since the actual flag is called 'inactive' */
+ bool inactive = !active;
+ bool old;
+
+ if (ctrl == NULL)
+ return;
+
+ if (inactive)
+ /* set V4L2_CTRL_FLAG_INACTIVE */
+ old = test_and_set_bit(4, &ctrl->flags);
+ else
+ /* clear V4L2_CTRL_FLAG_INACTIVE */
+ old = test_and_clear_bit(4, &ctrl->flags);
+ if (old != inactive)
+ send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
+}
+EXPORT_SYMBOL(v4l2_ctrl_activate);
+
+void __v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)
+{
+ bool old;
+
+ if (ctrl == NULL)
+ return;
+
+ lockdep_assert_held(ctrl->handler->lock);
+
+ if (grabbed)
+ /* set V4L2_CTRL_FLAG_GRABBED */
+ old = test_and_set_bit(1, &ctrl->flags);
+ else
+ /* clear V4L2_CTRL_FLAG_GRABBED */
+ old = test_and_clear_bit(1, &ctrl->flags);
+ if (old != grabbed)
+ send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
+}
+EXPORT_SYMBOL(__v4l2_ctrl_grab);
+
+/* Call s_ctrl for all controls owned by the handler */
+int __v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
+{
+ struct v4l2_ctrl *ctrl;
+ int ret = 0;
+
+ if (hdl == NULL)
+ return 0;
+
+ lockdep_assert_held(hdl->lock);
+
+ list_for_each_entry(ctrl, &hdl->ctrls, node)
+ ctrl->done = false;
+
+ list_for_each_entry(ctrl, &hdl->ctrls, node) {
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+ int i;
+
+ /* Skip if this control was already handled by a cluster. */
+ /* Skip button controls and read-only controls. */
+ if (ctrl->done || ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+ (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
+ continue;
+
+ for (i = 0; i < master->ncontrols; i++) {
+ if (master->cluster[i]) {
+ cur_to_new(master->cluster[i]);
+ master->cluster[i]->is_new = 1;
+ master->cluster[i]->done = true;
+ }
+ }
+ ret = call_op(master, s_ctrl);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__v4l2_ctrl_handler_setup);
+
+int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
+{
+ int ret;
+
+ if (hdl == NULL)
+ return 0;
+
+ mutex_lock(hdl->lock);
+ ret = __v4l2_ctrl_handler_setup(hdl);
+ mutex_unlock(hdl->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_setup);
+
+/* Log the control name and value */
+static void log_ctrl(const struct v4l2_ctrl *ctrl,
+ const char *prefix, const char *colon)
+{
+ if (ctrl->flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_WRITE_ONLY))
+ return;
+ if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+ return;
+
+ pr_info("%s%s%s: ", prefix, colon, ctrl->name);
+
+ ctrl->type_ops->log(ctrl);
+
+ if (ctrl->flags & (V4L2_CTRL_FLAG_INACTIVE |
+ V4L2_CTRL_FLAG_GRABBED |
+ V4L2_CTRL_FLAG_VOLATILE)) {
+ if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+ pr_cont(" inactive");
+ if (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)
+ pr_cont(" grabbed");
+ if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE)
+ pr_cont(" volatile");
+ }
+ pr_cont("\n");
+}
+
+/* Log all controls owned by the handler */
+void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl,
+ const char *prefix)
+{
+ struct v4l2_ctrl *ctrl;
+ const char *colon = "";
+ int len;
+
+ if (!hdl)
+ return;
+ if (!prefix)
+ prefix = "";
+ len = strlen(prefix);
+ if (len && prefix[len - 1] != ' ')
+ colon = ": ";
+ mutex_lock(hdl->lock);
+ list_for_each_entry(ctrl, &hdl->ctrls, node)
+ if (!(ctrl->flags & V4L2_CTRL_FLAG_DISABLED))
+ log_ctrl(ctrl, prefix, colon);
+ mutex_unlock(hdl->lock);
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_log_status);
+
+int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ctrl_ops,
+ const struct v4l2_fwnode_device_properties *p)
+{
+ if (p->orientation != V4L2_FWNODE_PROPERTY_UNSET) {
+ u32 orientation_ctrl;
+
+ switch (p->orientation) {
+ case V4L2_FWNODE_ORIENTATION_FRONT:
+ orientation_ctrl = V4L2_CAMERA_ORIENTATION_FRONT;
+ break;
+ case V4L2_FWNODE_ORIENTATION_BACK:
+ orientation_ctrl = V4L2_CAMERA_ORIENTATION_BACK;
+ break;
+ case V4L2_FWNODE_ORIENTATION_EXTERNAL:
+ orientation_ctrl = V4L2_CAMERA_ORIENTATION_EXTERNAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (!v4l2_ctrl_new_std_menu(hdl, ctrl_ops,
+ V4L2_CID_CAMERA_ORIENTATION,
+ V4L2_CAMERA_ORIENTATION_EXTERNAL, 0,
+ orientation_ctrl))
+ return hdl->error;
+ }
+
+ if (p->rotation != V4L2_FWNODE_PROPERTY_UNSET) {
+ if (!v4l2_ctrl_new_std(hdl, ctrl_ops,
+ V4L2_CID_CAMERA_SENSOR_ROTATION,
+ p->rotation, p->rotation, 1,
+ p->rotation))
+ return hdl->error;
+ }
+
+ return hdl->error;
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_fwnode_properties);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
new file mode 100644
index 000000000000..b6344bbf1e00
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
@@ -0,0 +1,1579 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * V4L2 controls framework control definitions.
+ *
+ * Copyright (C) 2010-2021 Hans Verkuil <hverkuil-cisco@xs4all.nl>
+ */
+
+#include <linux/export.h>
+#include <media/v4l2-ctrls.h>
+
+/*
+ * Returns NULL or a character pointer array containing the menu for
+ * the given control ID. The pointer array ends with a NULL pointer.
+ * An empty string signifies a menu entry that is invalid. This allows
+ * drivers to disable certain options if it is not supported.
+ */
+const char * const *v4l2_ctrl_get_menu(u32 id)
+{
+ static const char * const mpeg_audio_sampling_freq[] = {
+ "44.1 kHz",
+ "48 kHz",
+ "32 kHz",
+ NULL
+ };
+ static const char * const mpeg_audio_encoding[] = {
+ "MPEG-1/2 Layer I",
+ "MPEG-1/2 Layer II",
+ "MPEG-1/2 Layer III",
+ "MPEG-2/4 AAC",
+ "AC-3",
+ NULL
+ };
+ static const char * const mpeg_audio_l1_bitrate[] = {
+ "32 kbps",
+ "64 kbps",
+ "96 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "288 kbps",
+ "320 kbps",
+ "352 kbps",
+ "384 kbps",
+ "416 kbps",
+ "448 kbps",
+ NULL
+ };
+ static const char * const mpeg_audio_l2_bitrate[] = {
+ "32 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ "384 kbps",
+ NULL
+ };
+ static const char * const mpeg_audio_l3_bitrate[] = {
+ "32 kbps",
+ "40 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ NULL
+ };
+ static const char * const mpeg_audio_ac3_bitrate[] = {
+ "32 kbps",
+ "40 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ "384 kbps",
+ "448 kbps",
+ "512 kbps",
+ "576 kbps",
+ "640 kbps",
+ NULL
+ };
+ static const char * const mpeg_audio_mode[] = {
+ "Stereo",
+ "Joint Stereo",
+ "Dual",
+ "Mono",
+ NULL
+ };
+ static const char * const mpeg_audio_mode_extension[] = {
+ "Bound 4",
+ "Bound 8",
+ "Bound 12",
+ "Bound 16",
+ NULL
+ };
+ static const char * const mpeg_audio_emphasis[] = {
+ "No Emphasis",
+ "50/15 us",
+ "CCITT J17",
+ NULL
+ };
+ static const char * const mpeg_audio_crc[] = {
+ "No CRC",
+ "16-bit CRC",
+ NULL
+ };
+ static const char * const mpeg_audio_dec_playback[] = {
+ "Auto",
+ "Stereo",
+ "Left",
+ "Right",
+ "Mono",
+ "Swapped Stereo",
+ NULL
+ };
+ static const char * const mpeg_video_encoding[] = {
+ "MPEG-1",
+ "MPEG-2",
+ "MPEG-4 AVC",
+ NULL
+ };
+ static const char * const mpeg_video_aspect[] = {
+ "1x1",
+ "4x3",
+ "16x9",
+ "2.21x1",
+ NULL
+ };
+ static const char * const mpeg_video_bitrate_mode[] = {
+ "Variable Bitrate",
+ "Constant Bitrate",
+ "Constant Quality",
+ NULL
+ };
+ static const char * const mpeg_stream_type[] = {
+ "MPEG-2 Program Stream",
+ "MPEG-2 Transport Stream",
+ "MPEG-1 System Stream",
+ "MPEG-2 DVD-compatible Stream",
+ "MPEG-1 VCD-compatible Stream",
+ "MPEG-2 SVCD-compatible Stream",
+ NULL
+ };
+ static const char * const mpeg_stream_vbi_fmt[] = {
+ "No VBI",
+ "Private Packet, IVTV Format",
+ NULL
+ };
+ static const char * const camera_power_line_frequency[] = {
+ "Disabled",
+ "50 Hz",
+ "60 Hz",
+ "Auto",
+ NULL
+ };
+ static const char * const camera_exposure_auto[] = {
+ "Auto Mode",
+ "Manual Mode",
+ "Shutter Priority Mode",
+ "Aperture Priority Mode",
+ NULL
+ };
+ static const char * const camera_exposure_metering[] = {
+ "Average",
+ "Center Weighted",
+ "Spot",
+ "Matrix",
+ NULL
+ };
+ static const char * const camera_auto_focus_range[] = {
+ "Auto",
+ "Normal",
+ "Macro",
+ "Infinity",
+ NULL
+ };
+ static const char * const colorfx[] = {
+ "None",
+ "Black & White",
+ "Sepia",
+ "Negative",
+ "Emboss",
+ "Sketch",
+ "Sky Blue",
+ "Grass Green",
+ "Skin Whiten",
+ "Vivid",
+ "Aqua",
+ "Art Freeze",
+ "Silhouette",
+ "Solarization",
+ "Antique",
+ "Set Cb/Cr",
+ NULL
+ };
+ static const char * const auto_n_preset_white_balance[] = {
+ "Manual",
+ "Auto",
+ "Incandescent",
+ "Fluorescent",
+ "Fluorescent H",
+ "Horizon",
+ "Daylight",
+ "Flash",
+ "Cloudy",
+ "Shade",
+ NULL,
+ };
+ static const char * const camera_iso_sensitivity_auto[] = {
+ "Manual",
+ "Auto",
+ NULL
+ };
+ static const char * const scene_mode[] = {
+ "None",
+ "Backlight",
+ "Beach/Snow",
+ "Candle Light",
+ "Dusk/Dawn",
+ "Fall Colors",
+ "Fireworks",
+ "Landscape",
+ "Night",
+ "Party/Indoor",
+ "Portrait",
+ "Sports",
+ "Sunset",
+ "Text",
+ NULL
+ };
+ static const char * const tune_emphasis[] = {
+ "None",
+ "50 Microseconds",
+ "75 Microseconds",
+ NULL,
+ };
+ static const char * const header_mode[] = {
+ "Separate Buffer",
+ "Joined With 1st Frame",
+ NULL,
+ };
+ static const char * const multi_slice[] = {
+ "Single",
+ "Max Macroblocks",
+ "Max Bytes",
+ NULL,
+ };
+ static const char * const entropy_mode[] = {
+ "CAVLC",
+ "CABAC",
+ NULL,
+ };
+ static const char * const mpeg_h264_level[] = {
+ "1",
+ "1b",
+ "1.1",
+ "1.2",
+ "1.3",
+ "2",
+ "2.1",
+ "2.2",
+ "3",
+ "3.1",
+ "3.2",
+ "4",
+ "4.1",
+ "4.2",
+ "5",
+ "5.1",
+ "5.2",
+ "6.0",
+ "6.1",
+ "6.2",
+ NULL,
+ };
+ static const char * const h264_loop_filter[] = {
+ "Enabled",
+ "Disabled",
+ "Disabled at Slice Boundary",
+ NULL,
+ };
+ static const char * const h264_profile[] = {
+ "Baseline",
+ "Constrained Baseline",
+ "Main",
+ "Extended",
+ "High",
+ "High 10",
+ "High 422",
+ "High 444 Predictive",
+ "High 10 Intra",
+ "High 422 Intra",
+ "High 444 Intra",
+ "CAVLC 444 Intra",
+ "Scalable Baseline",
+ "Scalable High",
+ "Scalable High Intra",
+ "Stereo High",
+ "Multiview High",
+ "Constrained High",
+ NULL,
+ };
+ static const char * const vui_sar_idc[] = {
+ "Unspecified",
+ "1:1",
+ "12:11",
+ "10:11",
+ "16:11",
+ "40:33",
+ "24:11",
+ "20:11",
+ "32:11",
+ "80:33",
+ "18:11",
+ "15:11",
+ "64:33",
+ "160:99",
+ "4:3",
+ "3:2",
+ "2:1",
+ "Extended SAR",
+ NULL,
+ };
+ static const char * const h264_fp_arrangement_type[] = {
+ "Checkerboard",
+ "Column",
+ "Row",
+ "Side by Side",
+ "Top Bottom",
+ "Temporal",
+ NULL,
+ };
+ static const char * const h264_fmo_map_type[] = {
+ "Interleaved Slices",
+ "Scattered Slices",
+ "Foreground with Leftover",
+ "Box Out",
+ "Raster Scan",
+ "Wipe Scan",
+ "Explicit",
+ NULL,
+ };
+ static const char * const h264_decode_mode[] = {
+ "Slice-Based",
+ "Frame-Based",
+ NULL,
+ };
+ static const char * const h264_start_code[] = {
+ "No Start Code",
+ "Annex B Start Code",
+ NULL,
+ };
+ static const char * const h264_hierarchical_coding_type[] = {
+ "Hier Coding B",
+ "Hier Coding P",
+ 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",
+ "1",
+ "2",
+ "3",
+ "3b",
+ "4",
+ "5",
+ NULL,
+ };
+ static const char * const mpeg4_profile[] = {
+ "Simple",
+ "Advanced Simple",
+ "Core",
+ "Simple Scalable",
+ "Advanced Coding Efficiency",
+ NULL,
+ };
+
+ static const char * const vpx_golden_frame_sel[] = {
+ "Use Previous Frame",
+ "Use Previous Specific Frame",
+ NULL,
+ };
+ static const char * const vp8_profile[] = {
+ "0",
+ "1",
+ "2",
+ "3",
+ NULL,
+ };
+ static const char * const vp9_profile[] = {
+ "0",
+ "1",
+ "2",
+ "3",
+ NULL,
+ };
+ static const char * const vp9_level[] = {
+ "1",
+ "1.1",
+ "2",
+ "2.1",
+ "3",
+ "3.1",
+ "4",
+ "4.1",
+ "5",
+ "5.1",
+ "5.2",
+ "6",
+ "6.1",
+ "6.2",
+ NULL,
+ };
+
+ static const char * const flash_led_mode[] = {
+ "Off",
+ "Flash",
+ "Torch",
+ NULL,
+ };
+ static const char * const flash_strobe_source[] = {
+ "Software",
+ "External",
+ NULL,
+ };
+
+ static const char * const jpeg_chroma_subsampling[] = {
+ "4:4:4",
+ "4:2:2",
+ "4:2:0",
+ "4:1:1",
+ "4:1:0",
+ "Gray",
+ NULL,
+ };
+ static const char * const dv_tx_mode[] = {
+ "DVI-D",
+ "HDMI",
+ NULL,
+ };
+ static const char * const dv_rgb_range[] = {
+ "Automatic",
+ "RGB Limited Range (16-235)",
+ "RGB Full Range (0-255)",
+ NULL,
+ };
+ static const char * const dv_it_content_type[] = {
+ "Graphics",
+ "Photo",
+ "Cinema",
+ "Game",
+ "No IT Content",
+ NULL,
+ };
+ static const char * const detect_md_mode[] = {
+ "Disabled",
+ "Global",
+ "Threshold Grid",
+ "Region Grid",
+ NULL,
+ };
+
+ static const char * const hevc_profile[] = {
+ "Main",
+ "Main Still Picture",
+ "Main 10",
+ NULL,
+ };
+ static const char * const hevc_level[] = {
+ "1",
+ "2",
+ "2.1",
+ "3",
+ "3.1",
+ "4",
+ "4.1",
+ "5",
+ "5.1",
+ "5.2",
+ "6",
+ "6.1",
+ "6.2",
+ NULL,
+ };
+ static const char * const hevc_hierarchial_coding_type[] = {
+ "B",
+ "P",
+ NULL,
+ };
+ static const char * const hevc_refresh_type[] = {
+ "None",
+ "CRA",
+ "IDR",
+ NULL,
+ };
+ static const char * const hevc_size_of_length_field[] = {
+ "0",
+ "1",
+ "2",
+ "4",
+ NULL,
+ };
+ static const char * const hevc_tier[] = {
+ "Main",
+ "High",
+ NULL,
+ };
+ static const char * const hevc_loop_filter_mode[] = {
+ "Disabled",
+ "Enabled",
+ "Disabled at slice boundary",
+ "NULL",
+ };
+ static const char * const hevc_decode_mode[] = {
+ "Slice-Based",
+ "Frame-Based",
+ NULL,
+ };
+ static const char * const hevc_start_code[] = {
+ "No Start Code",
+ "Annex B Start Code",
+ NULL,
+ };
+ static const char * const camera_orientation[] = {
+ "Front",
+ "Back",
+ "External",
+ NULL,
+ };
+ static const char * const mpeg_video_frame_skip[] = {
+ "Disabled",
+ "Level Limit",
+ "VBV/CPB Limit",
+ NULL,
+ };
+
+ switch (id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ return mpeg_audio_sampling_freq;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return mpeg_audio_encoding;
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ return mpeg_audio_l1_bitrate;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return mpeg_audio_l2_bitrate;
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return mpeg_audio_l3_bitrate;
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ return mpeg_audio_ac3_bitrate;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ return mpeg_audio_mode;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ return mpeg_audio_mode_extension;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ return mpeg_audio_emphasis;
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ return mpeg_audio_crc;
+ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
+ case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK:
+ return mpeg_audio_dec_playback;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ return mpeg_video_encoding;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return mpeg_video_aspect;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ return mpeg_video_bitrate_mode;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return mpeg_stream_type;
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ return mpeg_stream_vbi_fmt;
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ return camera_power_line_frequency;
+ case V4L2_CID_EXPOSURE_AUTO:
+ return camera_exposure_auto;
+ case V4L2_CID_EXPOSURE_METERING:
+ return camera_exposure_metering;
+ case V4L2_CID_AUTO_FOCUS_RANGE:
+ return camera_auto_focus_range;
+ case V4L2_CID_COLORFX:
+ return colorfx;
+ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+ return auto_n_preset_white_balance;
+ case V4L2_CID_ISO_SENSITIVITY_AUTO:
+ return camera_iso_sensitivity_auto;
+ case V4L2_CID_SCENE_MODE:
+ return scene_mode;
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ return tune_emphasis;
+ case V4L2_CID_TUNE_DEEMPHASIS:
+ return tune_emphasis;
+ case V4L2_CID_FLASH_LED_MODE:
+ return flash_led_mode;
+ case V4L2_CID_FLASH_STROBE_SOURCE:
+ return flash_strobe_source;
+ case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+ return header_mode;
+ case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
+ return mpeg_video_frame_skip;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ return multi_slice;
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+ return entropy_mode;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ return mpeg_h264_level;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ return h264_loop_filter;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ return h264_profile;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+ return vui_sar_idc;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE:
+ return h264_fp_arrangement_type;
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE:
+ return h264_fmo_map_type;
+ case V4L2_CID_STATELESS_H264_DECODE_MODE:
+ return h264_decode_mode;
+ case V4L2_CID_STATELESS_H264_START_CODE:
+ return h264_start_code;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE:
+ return h264_hierarchical_coding_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:
+ return mpeg4_profile;
+ case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
+ return vpx_golden_frame_sel;
+ case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
+ return vp8_profile;
+ case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
+ return vp9_profile;
+ case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
+ return vp9_level;
+ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+ return jpeg_chroma_subsampling;
+ case V4L2_CID_DV_TX_MODE:
+ return dv_tx_mode;
+ case V4L2_CID_DV_TX_RGB_RANGE:
+ case V4L2_CID_DV_RX_RGB_RANGE:
+ return dv_rgb_range;
+ case V4L2_CID_DV_TX_IT_CONTENT_TYPE:
+ case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
+ return dv_it_content_type;
+ case V4L2_CID_DETECT_MD_MODE:
+ return detect_md_mode;
+ case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+ return hevc_profile;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
+ return hevc_level;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE:
+ return hevc_hierarchial_coding_type;
+ case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
+ return hevc_refresh_type;
+ case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
+ return hevc_size_of_length_field;
+ case V4L2_CID_MPEG_VIDEO_HEVC_TIER:
+ return hevc_tier;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
+ return hevc_loop_filter_mode;
+ case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE:
+ return hevc_decode_mode;
+ case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE:
+ return hevc_start_code;
+ case V4L2_CID_CAMERA_ORIENTATION:
+ return camera_orientation;
+ default:
+ return NULL;
+ }
+}
+EXPORT_SYMBOL(v4l2_ctrl_get_menu);
+
+#define __v4l2_qmenu_int_len(arr, len) ({ *(len) = ARRAY_SIZE(arr); (arr); })
+/*
+ * Returns NULL or an s64 type array containing the menu for given
+ * control ID. The total number of the menu items is returned in @len.
+ */
+const s64 *v4l2_ctrl_get_int_menu(u32 id, u32 *len)
+{
+ static const s64 qmenu_int_vpx_num_partitions[] = {
+ 1, 2, 4, 8,
+ };
+
+ static const s64 qmenu_int_vpx_num_ref_frames[] = {
+ 1, 2, 3,
+ };
+
+ switch (id) {
+ case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS:
+ return __v4l2_qmenu_int_len(qmenu_int_vpx_num_partitions, len);
+ case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES:
+ return __v4l2_qmenu_int_len(qmenu_int_vpx_num_ref_frames, len);
+ default:
+ *len = 0;
+ return NULL;
+ }
+}
+EXPORT_SYMBOL(v4l2_ctrl_get_int_menu);
+
+/* Return the control name. */
+const char *v4l2_ctrl_get_name(u32 id)
+{
+ switch (id) {
+ /* USER controls */
+ /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+ case V4L2_CID_USER_CLASS: return "User Controls";
+ case V4L2_CID_BRIGHTNESS: return "Brightness";
+ case V4L2_CID_CONTRAST: return "Contrast";
+ case V4L2_CID_SATURATION: return "Saturation";
+ case V4L2_CID_HUE: return "Hue";
+ case V4L2_CID_AUDIO_VOLUME: return "Volume";
+ case V4L2_CID_AUDIO_BALANCE: return "Balance";
+ case V4L2_CID_AUDIO_BASS: return "Bass";
+ case V4L2_CID_AUDIO_TREBLE: return "Treble";
+ case V4L2_CID_AUDIO_MUTE: return "Mute";
+ case V4L2_CID_AUDIO_LOUDNESS: return "Loudness";
+ case V4L2_CID_BLACK_LEVEL: return "Black Level";
+ case V4L2_CID_AUTO_WHITE_BALANCE: return "White Balance, Automatic";
+ case V4L2_CID_DO_WHITE_BALANCE: return "Do White Balance";
+ case V4L2_CID_RED_BALANCE: return "Red Balance";
+ case V4L2_CID_BLUE_BALANCE: return "Blue Balance";
+ case V4L2_CID_GAMMA: return "Gamma";
+ case V4L2_CID_EXPOSURE: return "Exposure";
+ case V4L2_CID_AUTOGAIN: return "Gain, Automatic";
+ case V4L2_CID_GAIN: return "Gain";
+ case V4L2_CID_HFLIP: return "Horizontal Flip";
+ case V4L2_CID_VFLIP: return "Vertical Flip";
+ case V4L2_CID_POWER_LINE_FREQUENCY: return "Power Line Frequency";
+ case V4L2_CID_HUE_AUTO: return "Hue, Automatic";
+ case V4L2_CID_WHITE_BALANCE_TEMPERATURE: return "White Balance Temperature";
+ case V4L2_CID_SHARPNESS: return "Sharpness";
+ case V4L2_CID_BACKLIGHT_COMPENSATION: return "Backlight Compensation";
+ case V4L2_CID_CHROMA_AGC: return "Chroma AGC";
+ case V4L2_CID_COLOR_KILLER: return "Color Killer";
+ case V4L2_CID_COLORFX: return "Color Effects";
+ case V4L2_CID_AUTOBRIGHTNESS: return "Brightness, Automatic";
+ case V4L2_CID_BAND_STOP_FILTER: return "Band-Stop Filter";
+ case V4L2_CID_ROTATE: return "Rotate";
+ case V4L2_CID_BG_COLOR: return "Background Color";
+ case V4L2_CID_CHROMA_GAIN: return "Chroma Gain";
+ case V4L2_CID_ILLUMINATORS_1: return "Illuminator 1";
+ case V4L2_CID_ILLUMINATORS_2: return "Illuminator 2";
+ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: return "Min Number of Capture Buffers";
+ case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: return "Min Number of Output Buffers";
+ case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component";
+ case V4L2_CID_COLORFX_CBCR: return "Color Effects, CbCr";
+
+ /*
+ * Codec controls
+ *
+ * The MPEG controls are applicable to all codec controls
+ * and the 'MPEG' part of the define is historical.
+ *
+ * Keep the order of the 'case's the same as in videodev2.h!
+ */
+ case V4L2_CID_CODEC_CLASS: return "Codec Controls";
+ case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type";
+ case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID";
+ case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID";
+ case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID";
+ case V4L2_CID_MPEG_STREAM_VBI_FMT: return "Stream VBI Format";
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency";
+ case V4L2_CID_MPEG_AUDIO_ENCODING: return "Audio Encoding";
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate";
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate";
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate";
+ case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode";
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension";
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS: return "Audio Emphasis";
+ case V4L2_CID_MPEG_AUDIO_CRC: return "Audio CRC";
+ case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute";
+ case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate";
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate";
+ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: return "Audio Playback";
+ case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: return "Audio Multilingual Playback";
+ case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding";
+ case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect";
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames";
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: return "Video GOP Size";
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: return "Video GOP Closure";
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN: return "Video Pulldown";
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: return "Video Bitrate Mode";
+ case V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY: return "Constant Quality";
+ case V4L2_CID_MPEG_VIDEO_BITRATE: return "Video Bitrate";
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: return "Video Peak Bitrate";
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
+ case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute";
+ case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV";
+ case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: return "Decoder Slice Interface";
+ case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: return "MPEG4 Loop Filter Enable";
+ case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: return "Number of Intra Refresh MBs";
+ case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: return "Frame Level Rate Control Enable";
+ case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: return "H264 MB Level Rate Control";
+ case V4L2_CID_MPEG_VIDEO_HEADER_MODE: return "Sequence Header Mode";
+ case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC: return "Max Number of Reference Pics";
+ case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: return "Frame Skip Mode";
+ case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: return "Display Delay";
+ case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: return "Display Delay Enable";
+ case V4L2_CID_MPEG_VIDEO_AU_DELIMITER: return "Generate Access Unit Delimiters";
+ case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: return "H263 I-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: return "H263 P-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: return "H263 B-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_H263_MIN_QP: return "H263 Minimum QP Value";
+ case V4L2_CID_MPEG_VIDEO_H263_MAX_QP: return "H263 Maximum QP Value";
+ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: return "H264 I-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: return "H264 P-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: return "H264 B-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: return "H264 Maximum QP Value";
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: return "H264 Minimum QP Value";
+ case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: return "H264 8x8 Transform Enable";
+ case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: return "H264 CPB Buffer Size";
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: return "H264 Entropy Mode";
+ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: return "H264 I-Frame Period";
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL: return "H264 Level";
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: return "H264 Loop Filter Alpha Offset";
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: return "H264 Loop Filter Beta Offset";
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: return "H264 Loop Filter Mode";
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE: return "H264 Profile";
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT: return "Vertical Size of SAR";
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH: return "Horizontal Size of SAR";
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: return "Aspect Ratio VUI Enable";
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: return "VUI Aspect Ratio IDC";
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING: return "H264 Enable Frame Packing SEI";
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0: return "H264 Set Curr. Frame as Frame0";
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: return "H264 FP Arrangement Type";
+ case V4L2_CID_MPEG_VIDEO_H264_FMO: return "H264 Flexible MB Ordering";
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: return "H264 Map Type for FMO";
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP: return "H264 FMO Number of Slice Groups";
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION: return "H264 FMO Direction of Change";
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE: return "H264 FMO Size of 1st Slice Grp";
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH: return "H264 FMO No. of Consecutive MBs";
+ case V4L2_CID_MPEG_VIDEO_H264_ASO: return "H264 Arbitrary Slice Ordering";
+ case V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER: return "H264 ASO Slice Order";
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING: return "Enable H264 Hierarchical Coding";
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: return "H264 Hierarchical Coding Type";
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:return "H264 Number of HC Layers";
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP:
+ return "H264 Set QP Value for HC Layers";
+ case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION:
+ return "H264 Constrained Intra Pred";
+ case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: return "H264 Chroma QP Index Offset";
+ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP: return "H264 I-Frame Minimum QP Value";
+ 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_B_FRAME_MIN_QP: return "H264 B-Frame Minimum QP Value";
+ case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP: return "H264 B-Frame Maximum QP Value";
+ case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR: return "H264 Hierarchical Lay 0 Bitrate";
+ case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR: return "H264 Hierarchical Lay 1 Bitrate";
+ case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR: return "H264 Hierarchical Lay 2 Bitrate";
+ case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR: return "H264 Hierarchical Lay 3 Bitrate";
+ case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR: return "H264 Hierarchical Lay 4 Bitrate";
+ case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR: return "H264 Hierarchical Lay 5 Bitrate";
+ case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L6_BR: return "H264 Hierarchical Lay 6 Bitrate";
+ 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";
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP: return "MPEG4 Minimum QP Value";
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP: return "MPEG4 Maximum QP Value";
+ case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: return "MPEG4 Level";
+ case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: return "MPEG4 Profile";
+ case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: return "Quarter Pixel Search Enable";
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: return "Maximum Bytes in a Slice";
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: return "Number of MBs in a Slice";
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: return "Slice Partitioning Method";
+ case V4L2_CID_MPEG_VIDEO_VBV_SIZE: return "VBV Buffer Size";
+ case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS";
+ case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count";
+ case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR: return "Video Decoder Conceal Color";
+ case V4L2_CID_MPEG_VIDEO_VBV_DELAY: return "Initial Delay for VBV Control";
+ case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: return "Horizontal MV Search Range";
+ case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: return "Vertical MV Search Range";
+ case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: return "Repeat Sequence Header";
+ case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: return "Force Key Frame";
+ case V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID: return "Base Layer Priority ID";
+ case V4L2_CID_MPEG_VIDEO_LTR_COUNT: return "LTR Count";
+ case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: return "Frame LTR Index";
+ case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: return "Use LTR Frames";
+ case V4L2_CID_FWHT_I_FRAME_QP: return "FWHT I-Frame QP Value";
+ case V4L2_CID_FWHT_P_FRAME_QP: return "FWHT P-Frame QP Value";
+
+ /* VPX controls */
+ case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: return "VPX Number of Partitions";
+ case V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4: return "VPX Intra Mode Decision Disable";
+ case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES: return "VPX No. of Refs for P Frame";
+ case V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL: return "VPX Loop Filter Level Range";
+ case V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS: return "VPX Deblocking Effect Control";
+ case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD: return "VPX Golden Frame Refresh Period";
+ case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: return "VPX Golden Frame Indicator";
+ case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP: return "VPX Minimum QP Value";
+ case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP: return "VPX Maximum QP Value";
+ case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP: return "VPX I-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: return "VPX P-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: return "VP8 Profile";
+ case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: return "VP9 Profile";
+ case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: return "VP9 Level";
+
+ /* HEVC controls */
+ case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: return "HEVC I-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: return "HEVC P-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: return "HEVC B-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: return "HEVC Minimum QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: return "HEVC Maximum QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP: return "HEVC I-Frame Minimum QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP: return "HEVC I-Frame Maximum QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP: return "HEVC P-Frame Minimum QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP: return "HEVC P-Frame Maximum QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP: return "HEVC B-Frame Minimum QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP: return "HEVC B-Frame Maximum QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: return "HEVC Profile";
+ case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: return "HEVC Level";
+ case V4L2_CID_MPEG_VIDEO_HEVC_TIER: return "HEVC Tier";
+ case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION: return "HEVC Frame Rate Resolution";
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH: return "HEVC Maximum Coding Unit Depth";
+ case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: return "HEVC Refresh Type";
+ case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: return "HEVC Constant Intra Prediction";
+ case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: return "HEVC Lossless Encoding";
+ case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: return "HEVC Wavefront";
+ case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: return "HEVC Loop Filter";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP: return "HEVC QP Values";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: return "HEVC Hierarchical Coding Type";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: return "HEVC Hierarchical Coding Layer";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP: return "HEVC Hierarchical Layer 0 QP";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP: return "HEVC Hierarchical Layer 1 QP";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP: return "HEVC Hierarchical Layer 2 QP";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP: return "HEVC Hierarchical Layer 3 QP";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP: return "HEVC Hierarchical Layer 4 QP";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP: return "HEVC Hierarchical Layer 5 QP";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP: return "HEVC Hierarchical Layer 6 QP";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: return "HEVC Hierarchical Lay 0 BitRate";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: return "HEVC Hierarchical Lay 1 BitRate";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: return "HEVC Hierarchical Lay 2 BitRate";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: return "HEVC Hierarchical Lay 3 BitRate";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: return "HEVC Hierarchical Lay 4 BitRate";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: return "HEVC Hierarchical Lay 5 BitRate";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR: return "HEVC Hierarchical Lay 6 BitRate";
+ case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB: return "HEVC General PB";
+ case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID: return "HEVC Temporal ID";
+ case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: return "HEVC Strong Intra Smoothing";
+ case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT: return "HEVC Intra PU Split";
+ case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: return "HEVC TMV Prediction";
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: return "HEVC Max Num of Candidate MVs";
+ case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE: return "HEVC ENC Without Startcode";
+ case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: return "HEVC Num of I-Frame b/w 2 IDR";
+ case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: return "HEVC Loop Filter Beta Offset";
+ case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: return "HEVC Loop Filter TC Offset";
+ case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: return "HEVC Size of Length Field";
+ case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: return "Reference Frames for a P-Frame";
+ case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: return "Prepend SPS and PPS to IDR";
+ case V4L2_CID_MPEG_VIDEO_HEVC_SPS: return "HEVC Sequence Parameter Set";
+ case V4L2_CID_MPEG_VIDEO_HEVC_PPS: return "HEVC Picture Parameter Set";
+ case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters";
+ case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS: return "HEVC Decode Parameters";
+ case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: return "HEVC Decode Mode";
+ case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: return "HEVC Start Code";
+
+ /* CAMERA controls */
+ /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+ case V4L2_CID_CAMERA_CLASS: return "Camera Controls";
+ case V4L2_CID_EXPOSURE_AUTO: return "Auto Exposure";
+ case V4L2_CID_EXPOSURE_ABSOLUTE: return "Exposure Time, Absolute";
+ case V4L2_CID_EXPOSURE_AUTO_PRIORITY: return "Exposure, Dynamic Framerate";
+ case V4L2_CID_PAN_RELATIVE: return "Pan, Relative";
+ case V4L2_CID_TILT_RELATIVE: return "Tilt, Relative";
+ case V4L2_CID_PAN_RESET: return "Pan, Reset";
+ case V4L2_CID_TILT_RESET: return "Tilt, Reset";
+ case V4L2_CID_PAN_ABSOLUTE: return "Pan, Absolute";
+ case V4L2_CID_TILT_ABSOLUTE: return "Tilt, Absolute";
+ case V4L2_CID_FOCUS_ABSOLUTE: return "Focus, Absolute";
+ case V4L2_CID_FOCUS_RELATIVE: return "Focus, Relative";
+ case V4L2_CID_FOCUS_AUTO: return "Focus, Automatic Continuous";
+ case V4L2_CID_ZOOM_ABSOLUTE: return "Zoom, Absolute";
+ case V4L2_CID_ZOOM_RELATIVE: return "Zoom, Relative";
+ case V4L2_CID_ZOOM_CONTINUOUS: return "Zoom, Continuous";
+ case V4L2_CID_PRIVACY: return "Privacy";
+ case V4L2_CID_IRIS_ABSOLUTE: return "Iris, Absolute";
+ case V4L2_CID_IRIS_RELATIVE: return "Iris, Relative";
+ case V4L2_CID_AUTO_EXPOSURE_BIAS: return "Auto Exposure, Bias";
+ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: return "White Balance, Auto & Preset";
+ case V4L2_CID_WIDE_DYNAMIC_RANGE: return "Wide Dynamic Range";
+ case V4L2_CID_IMAGE_STABILIZATION: return "Image Stabilization";
+ case V4L2_CID_ISO_SENSITIVITY: return "ISO Sensitivity";
+ case V4L2_CID_ISO_SENSITIVITY_AUTO: return "ISO Sensitivity, Auto";
+ case V4L2_CID_EXPOSURE_METERING: return "Exposure, Metering Mode";
+ case V4L2_CID_SCENE_MODE: return "Scene Mode";
+ case V4L2_CID_3A_LOCK: return "3A Lock";
+ case V4L2_CID_AUTO_FOCUS_START: return "Auto Focus, Start";
+ case V4L2_CID_AUTO_FOCUS_STOP: return "Auto Focus, Stop";
+ case V4L2_CID_AUTO_FOCUS_STATUS: return "Auto Focus, Status";
+ case V4L2_CID_AUTO_FOCUS_RANGE: return "Auto Focus, Range";
+ case V4L2_CID_PAN_SPEED: return "Pan, Speed";
+ case V4L2_CID_TILT_SPEED: return "Tilt, Speed";
+ case V4L2_CID_UNIT_CELL_SIZE: return "Unit Cell Size";
+ case V4L2_CID_CAMERA_ORIENTATION: return "Camera Orientation";
+ case V4L2_CID_CAMERA_SENSOR_ROTATION: return "Camera Sensor Rotation";
+
+ /* FM Radio Modulator controls */
+ /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+ case V4L2_CID_FM_TX_CLASS: return "FM Radio Modulator Controls";
+ case V4L2_CID_RDS_TX_DEVIATION: return "RDS Signal Deviation";
+ case V4L2_CID_RDS_TX_PI: return "RDS Program ID";
+ case V4L2_CID_RDS_TX_PTY: return "RDS Program Type";
+ case V4L2_CID_RDS_TX_PS_NAME: return "RDS PS Name";
+ case V4L2_CID_RDS_TX_RADIO_TEXT: return "RDS Radio Text";
+ case V4L2_CID_RDS_TX_MONO_STEREO: return "RDS Stereo";
+ case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD: return "RDS Artificial Head";
+ case V4L2_CID_RDS_TX_COMPRESSED: return "RDS Compressed";
+ case V4L2_CID_RDS_TX_DYNAMIC_PTY: return "RDS Dynamic PTY";
+ case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement";
+ case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM: return "RDS Traffic Program";
+ case V4L2_CID_RDS_TX_MUSIC_SPEECH: return "RDS Music";
+ case V4L2_CID_RDS_TX_ALT_FREQS_ENABLE: return "RDS Enable Alt Frequencies";
+ case V4L2_CID_RDS_TX_ALT_FREQS: return "RDS Alternate Frequencies";
+ case V4L2_CID_AUDIO_LIMITER_ENABLED: return "Audio Limiter Feature Enabled";
+ case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
+ case V4L2_CID_AUDIO_LIMITER_DEVIATION: return "Audio Limiter Deviation";
+ case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Enabled";
+ case V4L2_CID_AUDIO_COMPRESSION_GAIN: return "Audio Compression Gain";
+ case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold";
+ case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time";
+ case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: return "Audio Compression Release Time";
+ case V4L2_CID_PILOT_TONE_ENABLED: return "Pilot Tone Feature Enabled";
+ case V4L2_CID_PILOT_TONE_DEVIATION: return "Pilot Tone Deviation";
+ case V4L2_CID_PILOT_TONE_FREQUENCY: return "Pilot Tone Frequency";
+ case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-Emphasis";
+ case V4L2_CID_TUNE_POWER_LEVEL: return "Tune Power Level";
+ case V4L2_CID_TUNE_ANTENNA_CAPACITOR: return "Tune Antenna Capacitor";
+
+ /* Flash controls */
+ /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+ case V4L2_CID_FLASH_CLASS: return "Flash Controls";
+ case V4L2_CID_FLASH_LED_MODE: return "LED Mode";
+ case V4L2_CID_FLASH_STROBE_SOURCE: return "Strobe Source";
+ case V4L2_CID_FLASH_STROBE: return "Strobe";
+ case V4L2_CID_FLASH_STROBE_STOP: return "Stop Strobe";
+ case V4L2_CID_FLASH_STROBE_STATUS: return "Strobe Status";
+ case V4L2_CID_FLASH_TIMEOUT: return "Strobe Timeout";
+ case V4L2_CID_FLASH_INTENSITY: return "Intensity, Flash Mode";
+ case V4L2_CID_FLASH_TORCH_INTENSITY: return "Intensity, Torch Mode";
+ case V4L2_CID_FLASH_INDICATOR_INTENSITY: return "Intensity, Indicator";
+ case V4L2_CID_FLASH_FAULT: return "Faults";
+ case V4L2_CID_FLASH_CHARGE: return "Charge";
+ case V4L2_CID_FLASH_READY: return "Ready to Strobe";
+
+ /* JPEG encoder controls */
+ /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+ case V4L2_CID_JPEG_CLASS: return "JPEG Compression Controls";
+ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: return "Chroma Subsampling";
+ case V4L2_CID_JPEG_RESTART_INTERVAL: return "Restart Interval";
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY: return "Compression Quality";
+ case V4L2_CID_JPEG_ACTIVE_MARKER: return "Active Markers";
+
+ /* Image source controls */
+ /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+ case V4L2_CID_IMAGE_SOURCE_CLASS: return "Image Source Controls";
+ case V4L2_CID_VBLANK: return "Vertical Blanking";
+ case V4L2_CID_HBLANK: return "Horizontal Blanking";
+ case V4L2_CID_ANALOGUE_GAIN: return "Analogue Gain";
+ case V4L2_CID_TEST_PATTERN_RED: return "Red Pixel Value";
+ case V4L2_CID_TEST_PATTERN_GREENR: return "Green (Red) Pixel Value";
+ case V4L2_CID_TEST_PATTERN_BLUE: return "Blue Pixel Value";
+ case V4L2_CID_TEST_PATTERN_GREENB: return "Green (Blue) Pixel Value";
+
+ /* Image processing controls */
+ /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+ case V4L2_CID_IMAGE_PROC_CLASS: return "Image Processing Controls";
+ case V4L2_CID_LINK_FREQ: return "Link Frequency";
+ case V4L2_CID_PIXEL_RATE: return "Pixel Rate";
+ case V4L2_CID_TEST_PATTERN: return "Test Pattern";
+ case V4L2_CID_DEINTERLACING_MODE: return "Deinterlacing Mode";
+ case V4L2_CID_DIGITAL_GAIN: return "Digital Gain";
+
+ /* DV controls */
+ /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+ case V4L2_CID_DV_CLASS: return "Digital Video Controls";
+ case V4L2_CID_DV_TX_HOTPLUG: return "Hotplug Present";
+ case V4L2_CID_DV_TX_RXSENSE: return "RxSense Present";
+ case V4L2_CID_DV_TX_EDID_PRESENT: return "EDID Present";
+ case V4L2_CID_DV_TX_MODE: return "Transmit Mode";
+ case V4L2_CID_DV_TX_RGB_RANGE: return "Tx RGB Quantization Range";
+ case V4L2_CID_DV_TX_IT_CONTENT_TYPE: return "Tx IT Content Type";
+ case V4L2_CID_DV_RX_POWER_PRESENT: return "Power Present";
+ case V4L2_CID_DV_RX_RGB_RANGE: return "Rx RGB Quantization Range";
+ case V4L2_CID_DV_RX_IT_CONTENT_TYPE: return "Rx IT Content Type";
+
+ case V4L2_CID_FM_RX_CLASS: return "FM Radio Receiver Controls";
+ case V4L2_CID_TUNE_DEEMPHASIS: return "De-Emphasis";
+ case V4L2_CID_RDS_RECEPTION: return "RDS Reception";
+ case V4L2_CID_RF_TUNER_CLASS: return "RF Tuner Controls";
+ case V4L2_CID_RF_TUNER_RF_GAIN: return "RF Gain";
+ case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: return "LNA Gain, Auto";
+ case V4L2_CID_RF_TUNER_LNA_GAIN: return "LNA Gain";
+ case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: return "Mixer Gain, Auto";
+ case V4L2_CID_RF_TUNER_MIXER_GAIN: return "Mixer Gain";
+ case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: return "IF Gain, Auto";
+ case V4L2_CID_RF_TUNER_IF_GAIN: return "IF Gain";
+ case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: return "Bandwidth, Auto";
+ case V4L2_CID_RF_TUNER_BANDWIDTH: return "Bandwidth";
+ case V4L2_CID_RF_TUNER_PLL_LOCK: return "PLL Lock";
+ case V4L2_CID_RDS_RX_PTY: return "RDS Program Type";
+ case V4L2_CID_RDS_RX_PS_NAME: return "RDS PS Name";
+ case V4L2_CID_RDS_RX_RADIO_TEXT: return "RDS Radio Text";
+ case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement";
+ case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM: return "RDS Traffic Program";
+ case V4L2_CID_RDS_RX_MUSIC_SPEECH: return "RDS Music";
+
+ /* Detection controls */
+ /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+ case V4L2_CID_DETECT_CLASS: return "Detection Controls";
+ case V4L2_CID_DETECT_MD_MODE: return "Motion Detection Mode";
+ case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD: return "MD Global Threshold";
+ case V4L2_CID_DETECT_MD_THRESHOLD_GRID: return "MD Threshold Grid";
+ case V4L2_CID_DETECT_MD_REGION_GRID: return "MD Region Grid";
+
+ /* Stateless Codec controls */
+ /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+ case V4L2_CID_CODEC_STATELESS_CLASS: return "Stateless Codec Controls";
+ case V4L2_CID_STATELESS_H264_DECODE_MODE: return "H264 Decode Mode";
+ case V4L2_CID_STATELESS_H264_START_CODE: return "H264 Start Code";
+ case V4L2_CID_STATELESS_H264_SPS: return "H264 Sequence Parameter Set";
+ case V4L2_CID_STATELESS_H264_PPS: return "H264 Picture Parameter Set";
+ case V4L2_CID_STATELESS_H264_SCALING_MATRIX: return "H264 Scaling Matrix";
+ case V4L2_CID_STATELESS_H264_PRED_WEIGHTS: return "H264 Prediction Weight Table";
+ case V4L2_CID_STATELESS_H264_SLICE_PARAMS: return "H264 Slice Parameters";
+ case V4L2_CID_STATELESS_H264_DECODE_PARAMS: return "H264 Decode Parameters";
+ case V4L2_CID_STATELESS_FWHT_PARAMS: return "FWHT Stateless Parameters";
+ case V4L2_CID_STATELESS_VP8_FRAME: return "VP8 Frame Parameters";
+ case V4L2_CID_STATELESS_MPEG2_SEQUENCE: return "MPEG-2 Sequence Header";
+ case V4L2_CID_STATELESS_MPEG2_PICTURE: return "MPEG-2 Picture Header";
+ case V4L2_CID_STATELESS_MPEG2_QUANTISATION: return "MPEG-2 Quantisation Matrices";
+
+ /* Colorimetry controls */
+ /* Keep the order of the 'case's the same as in v4l2-controls.h! */
+ case V4L2_CID_COLORIMETRY_CLASS: return "Colorimetry Controls";
+ case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO: return "HDR10 Content Light Info";
+ case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY: return "HDR10 Mastering Display";
+ default:
+ return NULL;
+ }
+}
+EXPORT_SYMBOL(v4l2_ctrl_get_name);
+
+void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
+ s64 *min, s64 *max, u64 *step, s64 *def, u32 *flags)
+{
+ *name = v4l2_ctrl_get_name(id);
+ *flags = 0;
+
+ switch (id) {
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ case V4L2_CID_AUTOGAIN:
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ case V4L2_CID_HUE_AUTO:
+ case V4L2_CID_CHROMA_AGC:
+ case V4L2_CID_COLOR_KILLER:
+ case V4L2_CID_AUTOBRIGHTNESS:
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ case V4L2_CID_MPEG_VIDEO_MUTE:
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+ case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
+ case V4L2_CID_FOCUS_AUTO:
+ case V4L2_CID_PRIVACY:
+ case V4L2_CID_AUDIO_LIMITER_ENABLED:
+ case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
+ case V4L2_CID_PILOT_TONE_ENABLED:
+ case V4L2_CID_ILLUMINATORS_1:
+ case V4L2_CID_ILLUMINATORS_2:
+ case V4L2_CID_FLASH_STROBE_STATUS:
+ case V4L2_CID_FLASH_CHARGE:
+ case V4L2_CID_FLASH_READY:
+ case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
+ case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
+ case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE:
+ case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+ case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
+ case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
+ case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
+ case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER:
+ case V4L2_CID_MPEG_VIDEO_AU_DELIMITER:
+ case V4L2_CID_WIDE_DYNAMIC_RANGE:
+ case V4L2_CID_IMAGE_STABILIZATION:
+ case V4L2_CID_RDS_RECEPTION:
+ case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:
+ case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO:
+ case V4L2_CID_RF_TUNER_IF_GAIN_AUTO:
+ case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
+ case V4L2_CID_RF_TUNER_PLL_LOCK:
+ case V4L2_CID_RDS_TX_MONO_STEREO:
+ case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD:
+ case V4L2_CID_RDS_TX_COMPRESSED:
+ case V4L2_CID_RDS_TX_DYNAMIC_PTY:
+ case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT:
+ case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:
+ case V4L2_CID_RDS_TX_MUSIC_SPEECH:
+ case V4L2_CID_RDS_TX_ALT_FREQS_ENABLE:
+ case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT:
+ case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM:
+ case V4L2_CID_RDS_RX_MUSIC_SPEECH:
+ *type = V4L2_CTRL_TYPE_BOOLEAN;
+ *min = 0;
+ *max = *step = 1;
+ break;
+ case V4L2_CID_ROTATE:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ *flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE:
+ case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE:
+ case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ break;
+ case V4L2_CID_MPEG_VIDEO_LTR_COUNT:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ break;
+ case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ *flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+ break;
+ case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES:
+ *type = V4L2_CTRL_TYPE_BITMASK;
+ *flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+ break;
+ case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
+ case V4L2_CID_PAN_RESET:
+ case V4L2_CID_TILT_RESET:
+ case V4L2_CID_FLASH_STROBE:
+ 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;
+ *min = *max = *step = *def = 0;
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
+ case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK:
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ case V4L2_CID_EXPOSURE_AUTO:
+ case V4L2_CID_AUTO_FOCUS_RANGE:
+ case V4L2_CID_COLORFX:
+ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ case V4L2_CID_FLASH_LED_MODE:
+ case V4L2_CID_FLASH_STROBE_SOURCE:
+ case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+ case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ 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_H264_HIERARCHICAL_CODING_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:
+ case V4L2_CID_ISO_SENSITIVITY_AUTO:
+ case V4L2_CID_EXPOSURE_METERING:
+ case V4L2_CID_SCENE_MODE:
+ case V4L2_CID_DV_TX_MODE:
+ case V4L2_CID_DV_TX_RGB_RANGE:
+ case V4L2_CID_DV_TX_IT_CONTENT_TYPE:
+ case V4L2_CID_DV_RX_RGB_RANGE:
+ case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
+ case V4L2_CID_TEST_PATTERN:
+ case V4L2_CID_DEINTERLACING_MODE:
+ case V4L2_CID_TUNE_DEEMPHASIS:
+ case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
+ case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
+ case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
+ case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
+ case V4L2_CID_DETECT_MD_MODE:
+ case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+ case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE:
+ case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
+ case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
+ case V4L2_CID_MPEG_VIDEO_HEVC_TIER:
+ case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
+ case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE:
+ case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE:
+ case V4L2_CID_STATELESS_H264_DECODE_MODE:
+ case V4L2_CID_STATELESS_H264_START_CODE:
+ case V4L2_CID_CAMERA_ORIENTATION:
+ *type = V4L2_CTRL_TYPE_MENU;
+ break;
+ case V4L2_CID_LINK_FREQ:
+ *type = V4L2_CTRL_TYPE_INTEGER_MENU;
+ break;
+ case V4L2_CID_RDS_TX_PS_NAME:
+ case V4L2_CID_RDS_TX_RADIO_TEXT:
+ case V4L2_CID_RDS_RX_PS_NAME:
+ case V4L2_CID_RDS_RX_RADIO_TEXT:
+ *type = V4L2_CTRL_TYPE_STRING;
+ break;
+ case V4L2_CID_ISO_SENSITIVITY:
+ case V4L2_CID_AUTO_EXPOSURE_BIAS:
+ case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS:
+ case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES:
+ *type = V4L2_CTRL_TYPE_INTEGER_MENU;
+ break;
+ case V4L2_CID_USER_CLASS:
+ case V4L2_CID_CAMERA_CLASS:
+ case V4L2_CID_CODEC_CLASS:
+ case V4L2_CID_FM_TX_CLASS:
+ case V4L2_CID_FLASH_CLASS:
+ case V4L2_CID_JPEG_CLASS:
+ case V4L2_CID_IMAGE_SOURCE_CLASS:
+ case V4L2_CID_IMAGE_PROC_CLASS:
+ case V4L2_CID_DV_CLASS:
+ case V4L2_CID_FM_RX_CLASS:
+ case V4L2_CID_RF_TUNER_CLASS:
+ case V4L2_CID_DETECT_CLASS:
+ case V4L2_CID_CODEC_STATELESS_CLASS:
+ case V4L2_CID_COLORIMETRY_CLASS:
+ *type = V4L2_CTRL_TYPE_CTRL_CLASS;
+ /* You can neither read nor write these */
+ *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
+ *min = *max = *step = *def = 0;
+ break;
+ case V4L2_CID_BG_COLOR:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ *step = 1;
+ *min = 0;
+ /* Max is calculated as RGB888 that is 2^24 */
+ *max = 0xFFFFFF;
+ break;
+ case V4L2_CID_FLASH_FAULT:
+ case V4L2_CID_JPEG_ACTIVE_MARKER:
+ case V4L2_CID_3A_LOCK:
+ case V4L2_CID_AUTO_FOCUS_STATUS:
+ case V4L2_CID_DV_TX_HOTPLUG:
+ case V4L2_CID_DV_TX_RXSENSE:
+ case V4L2_CID_DV_TX_EDID_PRESENT:
+ case V4L2_CID_DV_RX_POWER_PRESENT:
+ *type = V4L2_CTRL_TYPE_BITMASK;
+ break;
+ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+ case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ break;
+ case V4L2_CID_MPEG_VIDEO_DEC_PTS:
+ *type = V4L2_CTRL_TYPE_INTEGER64;
+ *flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY;
+ *min = *def = 0;
+ *max = 0x1ffffffffLL;
+ *step = 1;
+ break;
+ case V4L2_CID_MPEG_VIDEO_DEC_FRAME:
+ *type = V4L2_CTRL_TYPE_INTEGER64;
+ *flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY;
+ *min = *def = 0;
+ *max = 0x7fffffffffffffffLL;
+ *step = 1;
+ break;
+ case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR:
+ *type = V4L2_CTRL_TYPE_INTEGER64;
+ *min = 0;
+ /* default for 8 bit black, luma is 16, chroma is 128 */
+ *def = 0x8000800010LL;
+ *max = 0xffffffffffffLL;
+ *step = 1;
+ break;
+ case V4L2_CID_PIXEL_RATE:
+ *type = V4L2_CTRL_TYPE_INTEGER64;
+ *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ break;
+ case V4L2_CID_DETECT_MD_REGION_GRID:
+ *type = V4L2_CTRL_TYPE_U8;
+ break;
+ case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
+ *type = V4L2_CTRL_TYPE_U16;
+ break;
+ case V4L2_CID_RDS_TX_ALT_FREQS:
+ *type = V4L2_CTRL_TYPE_U32;
+ break;
+ case V4L2_CID_STATELESS_MPEG2_SEQUENCE:
+ *type = V4L2_CTRL_TYPE_MPEG2_SEQUENCE;
+ break;
+ case V4L2_CID_STATELESS_MPEG2_PICTURE:
+ *type = V4L2_CTRL_TYPE_MPEG2_PICTURE;
+ break;
+ case V4L2_CID_STATELESS_MPEG2_QUANTISATION:
+ *type = V4L2_CTRL_TYPE_MPEG2_QUANTISATION;
+ break;
+ case V4L2_CID_STATELESS_FWHT_PARAMS:
+ *type = V4L2_CTRL_TYPE_FWHT_PARAMS;
+ break;
+ case V4L2_CID_STATELESS_H264_SPS:
+ *type = V4L2_CTRL_TYPE_H264_SPS;
+ break;
+ case V4L2_CID_STATELESS_H264_PPS:
+ *type = V4L2_CTRL_TYPE_H264_PPS;
+ break;
+ case V4L2_CID_STATELESS_H264_SCALING_MATRIX:
+ *type = V4L2_CTRL_TYPE_H264_SCALING_MATRIX;
+ break;
+ case V4L2_CID_STATELESS_H264_SLICE_PARAMS:
+ *type = V4L2_CTRL_TYPE_H264_SLICE_PARAMS;
+ break;
+ case V4L2_CID_STATELESS_H264_DECODE_PARAMS:
+ *type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS;
+ break;
+ case V4L2_CID_STATELESS_H264_PRED_WEIGHTS:
+ *type = V4L2_CTRL_TYPE_H264_PRED_WEIGHTS;
+ break;
+ case V4L2_CID_STATELESS_VP8_FRAME:
+ *type = V4L2_CTRL_TYPE_VP8_FRAME;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_SPS:
+ *type = V4L2_CTRL_TYPE_HEVC_SPS;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_PPS:
+ *type = V4L2_CTRL_TYPE_HEVC_PPS;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS:
+ *type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS:
+ *type = V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS;
+ break;
+ case V4L2_CID_UNIT_CELL_SIZE:
+ *type = V4L2_CTRL_TYPE_AREA;
+ *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ break;
+ case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO:
+ *type = V4L2_CTRL_TYPE_HDR10_CLL_INFO;
+ break;
+ case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY:
+ *type = V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY;
+ break;
+ default:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ break;
+ }
+ switch (id) {
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ *flags |= V4L2_CTRL_FLAG_UPDATE;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ case V4L2_CID_RED_BALANCE:
+ case V4L2_CID_BLUE_BALANCE:
+ case V4L2_CID_GAMMA:
+ case V4L2_CID_SHARPNESS:
+ case V4L2_CID_CHROMA_GAIN:
+ case V4L2_CID_RDS_TX_DEVIATION:
+ case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
+ case V4L2_CID_AUDIO_LIMITER_DEVIATION:
+ case V4L2_CID_AUDIO_COMPRESSION_GAIN:
+ case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
+ case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
+ case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
+ case V4L2_CID_PILOT_TONE_DEVIATION:
+ case V4L2_CID_PILOT_TONE_FREQUENCY:
+ case V4L2_CID_TUNE_POWER_LEVEL:
+ case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+ case V4L2_CID_RF_TUNER_RF_GAIN:
+ case V4L2_CID_RF_TUNER_LNA_GAIN:
+ case V4L2_CID_RF_TUNER_MIXER_GAIN:
+ case V4L2_CID_RF_TUNER_IF_GAIN:
+ case V4L2_CID_RF_TUNER_BANDWIDTH:
+ case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
+ *flags |= V4L2_CTRL_FLAG_SLIDER;
+ break;
+ case V4L2_CID_PAN_RELATIVE:
+ case V4L2_CID_TILT_RELATIVE:
+ case V4L2_CID_FOCUS_RELATIVE:
+ case V4L2_CID_IRIS_RELATIVE:
+ case V4L2_CID_ZOOM_RELATIVE:
+ *flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
+ V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
+ break;
+ case V4L2_CID_FLASH_STROBE_STATUS:
+ case V4L2_CID_AUTO_FOCUS_STATUS:
+ case V4L2_CID_FLASH_READY:
+ case V4L2_CID_DV_TX_HOTPLUG:
+ case V4L2_CID_DV_TX_RXSENSE:
+ case V4L2_CID_DV_TX_EDID_PRESENT:
+ case V4L2_CID_DV_RX_POWER_PRESENT:
+ case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
+ case V4L2_CID_RDS_RX_PTY:
+ case V4L2_CID_RDS_RX_PS_NAME:
+ case V4L2_CID_RDS_RX_RADIO_TEXT:
+ case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT:
+ case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM:
+ case V4L2_CID_RDS_RX_MUSIC_SPEECH:
+ case V4L2_CID_CAMERA_ORIENTATION:
+ case V4L2_CID_CAMERA_SENSOR_ROTATION:
+ *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ break;
+ case V4L2_CID_RF_TUNER_PLL_LOCK:
+ *flags |= V4L2_CTRL_FLAG_VOLATILE;
+ break;
+ }
+}
+EXPORT_SYMBOL(v4l2_ctrl_fill);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-priv.h b/drivers/media/v4l2-core/v4l2-ctrls-priv.h
new file mode 100644
index 000000000000..d4bf2c716f97
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-ctrls-priv.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * V4L2 controls framework private header.
+ *
+ * Copyright (C) 2010-2021 Hans Verkuil <hverkuil-cisco@xs4all.nl>
+ */
+
+#ifndef _V4L2_CTRLS_PRIV_H_
+#define _V4L2_CTRLS_PRIV_H_
+
+#define dprintk(vdev, fmt, arg...) do { \
+ if (!WARN_ON(!(vdev)) && ((vdev)->dev_debug & V4L2_DEV_DEBUG_CTRL)) \
+ printk(KERN_DEBUG pr_fmt("%s: %s: " fmt), \
+ __func__, video_device_node_name(vdev), ##arg); \
+} while (0)
+
+#define has_op(master, op) \
+ ((master)->ops && (master)->ops->op)
+#define call_op(master, op) \
+ (has_op(master, op) ? (master)->ops->op(master) : 0)
+
+static inline u32 node2id(struct list_head *node)
+{
+ return list_entry(node, struct v4l2_ctrl_ref, node)->ctrl->id;
+}
+
+/*
+ * Small helper function to determine if the autocluster is set to manual
+ * mode.
+ */
+static inline bool is_cur_manual(const struct v4l2_ctrl *master)
+{
+ return master->is_auto && master->cur.val == master->manual_mode_value;
+}
+
+/*
+ * Small helper function to determine if the autocluster will be set to manual
+ * mode.
+ */
+static inline bool is_new_manual(const struct v4l2_ctrl *master)
+{
+ return master->is_auto && master->val == master->manual_mode_value;
+}
+
+static inline u32 user_flags(const struct v4l2_ctrl *ctrl)
+{
+ u32 flags = ctrl->flags;
+
+ if (ctrl->is_ptr)
+ flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
+
+ return flags;
+}
+
+/* v4l2-ctrls-core.c */
+void cur_to_new(struct v4l2_ctrl *ctrl);
+void cur_to_req(struct v4l2_ctrl_ref *ref);
+void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags);
+void new_to_req(struct v4l2_ctrl_ref *ref);
+void req_to_new(struct v4l2_ctrl_ref *ref);
+void send_initial_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl);
+void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes);
+int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new);
+int handler_new_ref(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ctrl *ctrl,
+ struct v4l2_ctrl_ref **ctrl_ref,
+ bool from_other_dev, bool allocate_req);
+struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id);
+struct v4l2_ctrl_ref *find_ref_lock(struct v4l2_ctrl_handler *hdl, u32 id);
+int check_range(enum v4l2_ctrl_type type,
+ s64 min, s64 max, u64 step, s64 def);
+void update_from_auto_cluster(struct v4l2_ctrl *master);
+int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
+ bool set, u32 ch_flags);
+
+/* v4l2-ctrls-api.c */
+int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ext_controls *cs,
+ struct video_device *vdev);
+int try_set_ext_ctrls_common(struct v4l2_fh *fh,
+ struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ext_controls *cs,
+ struct video_device *vdev, bool set);
+
+/* v4l2-ctrls-request.c */
+void v4l2_ctrl_handler_init_request(struct v4l2_ctrl_handler *hdl);
+void v4l2_ctrl_handler_free_request(struct v4l2_ctrl_handler *hdl);
+int v4l2_g_ext_ctrls_request(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
+ struct media_device *mdev, struct v4l2_ext_controls *cs);
+int try_set_ext_ctrls_request(struct v4l2_fh *fh,
+ struct v4l2_ctrl_handler *hdl,
+ struct video_device *vdev,
+ struct media_device *mdev,
+ struct v4l2_ext_controls *cs, bool set);
+
+#endif
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-request.c b/drivers/media/v4l2-core/v4l2-ctrls-request.c
new file mode 100644
index 000000000000..7d098f287fd9
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-ctrls-request.c
@@ -0,0 +1,496 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * V4L2 controls framework Request API implementation.
+ *
+ * Copyright (C) 2018-2021 Hans Verkuil <hverkuil-cisco@xs4all.nl>
+ */
+
+#define pr_fmt(fmt) "v4l2-ctrls: " fmt
+
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+
+#include "v4l2-ctrls-priv.h"
+
+/* Initialize the request-related fields in a control handler */
+void v4l2_ctrl_handler_init_request(struct v4l2_ctrl_handler *hdl)
+{
+ INIT_LIST_HEAD(&hdl->requests);
+ INIT_LIST_HEAD(&hdl->requests_queued);
+ hdl->request_is_queued = false;
+ media_request_object_init(&hdl->req_obj);
+}
+
+/* Free the request-related fields in a control handler */
+void v4l2_ctrl_handler_free_request(struct v4l2_ctrl_handler *hdl)
+{
+ struct v4l2_ctrl_handler *req, *next_req;
+
+ /*
+ * Do nothing if this isn't the main handler or the main
+ * handler is not used in any request.
+ *
+ * The main handler can be identified by having a NULL ops pointer in
+ * the request object.
+ */
+ if (hdl->req_obj.ops || list_empty(&hdl->requests))
+ return;
+
+ /*
+ * If the main handler is freed and it is used by handler objects in
+ * outstanding requests, then unbind and put those objects before
+ * freeing the main handler.
+ */
+ list_for_each_entry_safe(req, next_req, &hdl->requests, requests) {
+ media_request_object_unbind(&req->req_obj);
+ media_request_object_put(&req->req_obj);
+ }
+}
+
+static int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_handler *from)
+{
+ struct v4l2_ctrl_ref *ref;
+ int err = 0;
+
+ if (WARN_ON(!hdl || hdl == from))
+ return -EINVAL;
+
+ if (hdl->error)
+ return hdl->error;
+
+ WARN_ON(hdl->lock != &hdl->_lock);
+
+ mutex_lock(from->lock);
+ list_for_each_entry(ref, &from->ctrl_refs, node) {
+ struct v4l2_ctrl *ctrl = ref->ctrl;
+ struct v4l2_ctrl_ref *new_ref;
+
+ /* Skip refs inherited from other devices */
+ if (ref->from_other_dev)
+ continue;
+ err = handler_new_ref(hdl, ctrl, &new_ref, false, true);
+ if (err)
+ break;
+ }
+ mutex_unlock(from->lock);
+ return err;
+}
+
+static void v4l2_ctrl_request_queue(struct media_request_object *obj)
+{
+ struct v4l2_ctrl_handler *hdl =
+ container_of(obj, struct v4l2_ctrl_handler, req_obj);
+ struct v4l2_ctrl_handler *main_hdl = obj->priv;
+
+ mutex_lock(main_hdl->lock);
+ list_add_tail(&hdl->requests_queued, &main_hdl->requests_queued);
+ hdl->request_is_queued = true;
+ mutex_unlock(main_hdl->lock);
+}
+
+static void v4l2_ctrl_request_unbind(struct media_request_object *obj)
+{
+ struct v4l2_ctrl_handler *hdl =
+ container_of(obj, struct v4l2_ctrl_handler, req_obj);
+ struct v4l2_ctrl_handler *main_hdl = obj->priv;
+
+ mutex_lock(main_hdl->lock);
+ list_del_init(&hdl->requests);
+ if (hdl->request_is_queued) {
+ list_del_init(&hdl->requests_queued);
+ hdl->request_is_queued = false;
+ }
+ mutex_unlock(main_hdl->lock);
+}
+
+static void v4l2_ctrl_request_release(struct media_request_object *obj)
+{
+ struct v4l2_ctrl_handler *hdl =
+ container_of(obj, struct v4l2_ctrl_handler, req_obj);
+
+ v4l2_ctrl_handler_free(hdl);
+ kfree(hdl);
+}
+
+static const struct media_request_object_ops req_ops = {
+ .queue = v4l2_ctrl_request_queue,
+ .unbind = v4l2_ctrl_request_unbind,
+ .release = v4l2_ctrl_request_release,
+};
+
+struct v4l2_ctrl_handler *v4l2_ctrl_request_hdl_find(struct media_request *req,
+ struct v4l2_ctrl_handler *parent)
+{
+ struct media_request_object *obj;
+
+ if (WARN_ON(req->state != MEDIA_REQUEST_STATE_VALIDATING &&
+ req->state != MEDIA_REQUEST_STATE_QUEUED))
+ return NULL;
+
+ obj = media_request_object_find(req, &req_ops, parent);
+ if (obj)
+ return container_of(obj, struct v4l2_ctrl_handler, req_obj);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_find);
+
+struct v4l2_ctrl *
+v4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
+{
+ struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
+
+ return (ref && ref->valid_p_req) ? ref->ctrl : NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_ctrl_find);
+
+static int v4l2_ctrl_request_bind(struct media_request *req,
+ struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ctrl_handler *from)
+{
+ int ret;
+
+ ret = v4l2_ctrl_request_clone(hdl, from);
+
+ if (!ret) {
+ ret = media_request_object_bind(req, &req_ops,
+ from, false, &hdl->req_obj);
+ if (!ret) {
+ mutex_lock(from->lock);
+ list_add_tail(&hdl->requests, &from->requests);
+ mutex_unlock(from->lock);
+ }
+ }
+ return ret;
+}
+
+static struct media_request_object *
+v4l2_ctrls_find_req_obj(struct v4l2_ctrl_handler *hdl,
+ struct media_request *req, bool set)
+{
+ struct media_request_object *obj;
+ struct v4l2_ctrl_handler *new_hdl;
+ int ret;
+
+ if (IS_ERR(req))
+ return ERR_CAST(req);
+
+ if (set && WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING))
+ return ERR_PTR(-EBUSY);
+
+ obj = media_request_object_find(req, &req_ops, hdl);
+ if (obj)
+ return obj;
+ /*
+ * If there are no controls in this completed request,
+ * then that can only happen if:
+ *
+ * 1) no controls were present in the queued request, and
+ * 2) v4l2_ctrl_request_complete() could not allocate a
+ * control handler object to store the completed state in.
+ *
+ * So return ENOMEM to indicate that there was an out-of-memory
+ * error.
+ */
+ if (!set)
+ return ERR_PTR(-ENOMEM);
+
+ new_hdl = kzalloc(sizeof(*new_hdl), GFP_KERNEL);
+ if (!new_hdl)
+ return ERR_PTR(-ENOMEM);
+
+ obj = &new_hdl->req_obj;
+ ret = v4l2_ctrl_handler_init(new_hdl, (hdl->nr_of_buckets - 1) * 8);
+ if (!ret)
+ ret = v4l2_ctrl_request_bind(req, new_hdl, hdl);
+ if (ret) {
+ v4l2_ctrl_handler_free(new_hdl);
+ kfree(new_hdl);
+ return ERR_PTR(ret);
+ }
+
+ media_request_object_get(obj);
+ return obj;
+}
+
+int v4l2_g_ext_ctrls_request(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
+ struct media_device *mdev, struct v4l2_ext_controls *cs)
+{
+ struct media_request_object *obj = NULL;
+ struct media_request *req = NULL;
+ int ret;
+
+ if (!mdev || cs->request_fd < 0)
+ return -EINVAL;
+
+ req = media_request_get_by_fd(mdev, cs->request_fd);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ if (req->state != MEDIA_REQUEST_STATE_COMPLETE) {
+ media_request_put(req);
+ return -EACCES;
+ }
+
+ ret = media_request_lock_for_access(req);
+ if (ret) {
+ media_request_put(req);
+ return ret;
+ }
+
+ obj = v4l2_ctrls_find_req_obj(hdl, req, false);
+ if (IS_ERR(obj)) {
+ media_request_unlock_for_access(req);
+ media_request_put(req);
+ return PTR_ERR(obj);
+ }
+
+ hdl = container_of(obj, struct v4l2_ctrl_handler,
+ req_obj);
+ ret = v4l2_g_ext_ctrls_common(hdl, cs, vdev);
+
+ media_request_unlock_for_access(req);
+ media_request_object_put(obj);
+ media_request_put(req);
+ return ret;
+}
+
+int try_set_ext_ctrls_request(struct v4l2_fh *fh,
+ struct v4l2_ctrl_handler *hdl,
+ struct video_device *vdev,
+ struct media_device *mdev,
+ struct v4l2_ext_controls *cs, bool set)
+{
+ struct media_request_object *obj = NULL;
+ struct media_request *req = NULL;
+ int ret;
+
+ if (!mdev) {
+ dprintk(vdev, "%s: missing media device\n",
+ video_device_node_name(vdev));
+ return -EINVAL;
+ }
+
+ if (cs->request_fd < 0) {
+ dprintk(vdev, "%s: invalid request fd %d\n",
+ video_device_node_name(vdev), cs->request_fd);
+ return -EINVAL;
+ }
+
+ req = media_request_get_by_fd(mdev, cs->request_fd);
+ if (IS_ERR(req)) {
+ dprintk(vdev, "%s: cannot find request fd %d\n",
+ video_device_node_name(vdev), cs->request_fd);
+ return PTR_ERR(req);
+ }
+
+ ret = media_request_lock_for_update(req);
+ if (ret) {
+ dprintk(vdev, "%s: cannot lock request fd %d\n",
+ video_device_node_name(vdev), cs->request_fd);
+ media_request_put(req);
+ return ret;
+ }
+
+ obj = v4l2_ctrls_find_req_obj(hdl, req, set);
+ if (IS_ERR(obj)) {
+ dprintk(vdev,
+ "%s: cannot find request object for request fd %d\n",
+ video_device_node_name(vdev),
+ cs->request_fd);
+ media_request_unlock_for_update(req);
+ media_request_put(req);
+ return PTR_ERR(obj);
+ }
+
+ hdl = container_of(obj, struct v4l2_ctrl_handler,
+ req_obj);
+ ret = try_set_ext_ctrls_common(fh, hdl, cs, vdev, set);
+ if (ret)
+ dprintk(vdev,
+ "%s: try_set_ext_ctrls_common failed (%d)\n",
+ video_device_node_name(vdev), ret);
+
+ media_request_unlock_for_update(req);
+ media_request_object_put(obj);
+ media_request_put(req);
+
+ return ret;
+}
+
+void v4l2_ctrl_request_complete(struct media_request *req,
+ struct v4l2_ctrl_handler *main_hdl)
+{
+ struct media_request_object *obj;
+ struct v4l2_ctrl_handler *hdl;
+ struct v4l2_ctrl_ref *ref;
+
+ if (!req || !main_hdl)
+ return;
+
+ /*
+ * Note that it is valid if nothing was found. It means
+ * that this request doesn't have any controls and so just
+ * wants to leave the controls unchanged.
+ */
+ obj = media_request_object_find(req, &req_ops, main_hdl);
+ if (!obj) {
+ int ret;
+
+ /* Create a new request so the driver can return controls */
+ hdl = kzalloc(sizeof(*hdl), GFP_KERNEL);
+ if (!hdl)
+ return;
+
+ ret = v4l2_ctrl_handler_init(hdl, (main_hdl->nr_of_buckets - 1) * 8);
+ if (!ret)
+ ret = v4l2_ctrl_request_bind(req, hdl, main_hdl);
+ if (ret) {
+ v4l2_ctrl_handler_free(hdl);
+ kfree(hdl);
+ return;
+ }
+ hdl->request_is_queued = true;
+ obj = media_request_object_find(req, &req_ops, main_hdl);
+ }
+ hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
+
+ list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+ struct v4l2_ctrl *ctrl = ref->ctrl;
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+ unsigned int i;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
+ v4l2_ctrl_lock(master);
+ /* g_volatile_ctrl will update the current control values */
+ for (i = 0; i < master->ncontrols; i++)
+ cur_to_new(master->cluster[i]);
+ call_op(master, g_volatile_ctrl);
+ new_to_req(ref);
+ v4l2_ctrl_unlock(master);
+ continue;
+ }
+ if (ref->valid_p_req)
+ continue;
+
+ /* Copy the current control value into the request */
+ v4l2_ctrl_lock(ctrl);
+ cur_to_req(ref);
+ v4l2_ctrl_unlock(ctrl);
+ }
+
+ mutex_lock(main_hdl->lock);
+ WARN_ON(!hdl->request_is_queued);
+ list_del_init(&hdl->requests_queued);
+ hdl->request_is_queued = false;
+ mutex_unlock(main_hdl->lock);
+ media_request_object_complete(obj);
+ media_request_object_put(obj);
+}
+EXPORT_SYMBOL(v4l2_ctrl_request_complete);
+
+int v4l2_ctrl_request_setup(struct media_request *req,
+ struct v4l2_ctrl_handler *main_hdl)
+{
+ struct media_request_object *obj;
+ struct v4l2_ctrl_handler *hdl;
+ struct v4l2_ctrl_ref *ref;
+ int ret = 0;
+
+ if (!req || !main_hdl)
+ return 0;
+
+ if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
+ return -EBUSY;
+
+ /*
+ * Note that it is valid if nothing was found. It means
+ * that this request doesn't have any controls and so just
+ * wants to leave the controls unchanged.
+ */
+ obj = media_request_object_find(req, &req_ops, main_hdl);
+ if (!obj)
+ return 0;
+ if (obj->completed) {
+ media_request_object_put(obj);
+ return -EBUSY;
+ }
+ hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
+
+ list_for_each_entry(ref, &hdl->ctrl_refs, node)
+ ref->req_done = false;
+
+ list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+ struct v4l2_ctrl *ctrl = ref->ctrl;
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+ bool have_new_data = false;
+ int i;
+
+ /*
+ * Skip if this control was already handled by a cluster.
+ * Skip button controls and read-only controls.
+ */
+ if (ref->req_done || (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
+ continue;
+
+ v4l2_ctrl_lock(master);
+ for (i = 0; i < master->ncontrols; i++) {
+ if (master->cluster[i]) {
+ struct v4l2_ctrl_ref *r =
+ find_ref(hdl, master->cluster[i]->id);
+
+ if (r->valid_p_req) {
+ have_new_data = true;
+ break;
+ }
+ }
+ }
+ if (!have_new_data) {
+ v4l2_ctrl_unlock(master);
+ continue;
+ }
+
+ for (i = 0; i < master->ncontrols; i++) {
+ if (master->cluster[i]) {
+ struct v4l2_ctrl_ref *r =
+ find_ref(hdl, master->cluster[i]->id);
+
+ req_to_new(r);
+ master->cluster[i]->is_new = 1;
+ r->req_done = true;
+ }
+ }
+ /*
+ * For volatile autoclusters that are currently in auto mode
+ * we need to discover if it will be set to manual mode.
+ * If so, then we have to copy the current volatile values
+ * first since those will become the new manual values (which
+ * may be overwritten by explicit new values from this set
+ * of controls).
+ */
+ if (master->is_auto && master->has_volatiles &&
+ !is_cur_manual(master)) {
+ s32 new_auto_val = *master->p_new.p_s32;
+
+ /*
+ * If the new value == the manual value, then copy
+ * the current volatile values.
+ */
+ if (new_auto_val == master->manual_mode_value)
+ update_from_auto_cluster(master);
+ }
+
+ ret = try_or_set_cluster(NULL, master, true, 0);
+ v4l2_ctrl_unlock(master);
+
+ if (ret)
+ break;
+ }
+
+ media_request_object_put(obj);
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_ctrl_request_setup);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
deleted file mode 100644
index 0d7fe1bd975a..000000000000
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ /dev/null
@@ -1,5035 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- V4L2 controls framework implementation.
-
- Copyright (C) 2010 Hans Verkuil <hverkuil@xs4all.nl>
-
- */
-
-#define pr_fmt(fmt) "v4l2-ctrls: " fmt
-
-#include <linux/ctype.h>
-#include <linux/export.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-dev.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-fwnode.h>
-#include <media/v4l2-ioctl.h>
-
-#define dprintk(vdev, fmt, arg...) do { \
- if (!WARN_ON(!(vdev)) && ((vdev)->dev_debug & V4L2_DEV_DEBUG_CTRL)) \
- printk(KERN_DEBUG pr_fmt("%s: %s: " fmt), \
- __func__, video_device_node_name(vdev), ##arg); \
-} while (0)
-
-#define has_op(master, op) \
- (master->ops && master->ops->op)
-#define call_op(master, op) \
- (has_op(master, op) ? master->ops->op(master) : 0)
-
-static const union v4l2_ctrl_ptr ptr_null;
-
-/* Internal temporary helper struct, one for each v4l2_ext_control */
-struct v4l2_ctrl_helper {
- /* Pointer to the control reference of the master control */
- struct v4l2_ctrl_ref *mref;
- /* The control ref corresponding to the v4l2_ext_control ID field. */
- struct v4l2_ctrl_ref *ref;
- /* v4l2_ext_control index of the next control belonging to the
- same cluster, or 0 if there isn't any. */
- u32 next;
-};
-
-/* Small helper function to determine if the autocluster is set to manual
- mode. */
-static bool is_cur_manual(const struct v4l2_ctrl *master)
-{
- return master->is_auto && master->cur.val == master->manual_mode_value;
-}
-
-/* Same as above, but this checks the against the new value instead of the
- current value. */
-static bool is_new_manual(const struct v4l2_ctrl *master)
-{
- return master->is_auto && master->val == master->manual_mode_value;
-}
-
-/* Returns NULL or a character pointer array containing the menu for
- the given control ID. The pointer array ends with a NULL pointer.
- An empty string signifies a menu entry that is invalid. This allows
- drivers to disable certain options if it is not supported. */
-const char * const *v4l2_ctrl_get_menu(u32 id)
-{
- static const char * const mpeg_audio_sampling_freq[] = {
- "44.1 kHz",
- "48 kHz",
- "32 kHz",
- NULL
- };
- static const char * const mpeg_audio_encoding[] = {
- "MPEG-1/2 Layer I",
- "MPEG-1/2 Layer II",
- "MPEG-1/2 Layer III",
- "MPEG-2/4 AAC",
- "AC-3",
- NULL
- };
- static const char * const mpeg_audio_l1_bitrate[] = {
- "32 kbps",
- "64 kbps",
- "96 kbps",
- "128 kbps",
- "160 kbps",
- "192 kbps",
- "224 kbps",
- "256 kbps",
- "288 kbps",
- "320 kbps",
- "352 kbps",
- "384 kbps",
- "416 kbps",
- "448 kbps",
- NULL
- };
- static const char * const mpeg_audio_l2_bitrate[] = {
- "32 kbps",
- "48 kbps",
- "56 kbps",
- "64 kbps",
- "80 kbps",
- "96 kbps",
- "112 kbps",
- "128 kbps",
- "160 kbps",
- "192 kbps",
- "224 kbps",
- "256 kbps",
- "320 kbps",
- "384 kbps",
- NULL
- };
- static const char * const mpeg_audio_l3_bitrate[] = {
- "32 kbps",
- "40 kbps",
- "48 kbps",
- "56 kbps",
- "64 kbps",
- "80 kbps",
- "96 kbps",
- "112 kbps",
- "128 kbps",
- "160 kbps",
- "192 kbps",
- "224 kbps",
- "256 kbps",
- "320 kbps",
- NULL
- };
- static const char * const mpeg_audio_ac3_bitrate[] = {
- "32 kbps",
- "40 kbps",
- "48 kbps",
- "56 kbps",
- "64 kbps",
- "80 kbps",
- "96 kbps",
- "112 kbps",
- "128 kbps",
- "160 kbps",
- "192 kbps",
- "224 kbps",
- "256 kbps",
- "320 kbps",
- "384 kbps",
- "448 kbps",
- "512 kbps",
- "576 kbps",
- "640 kbps",
- NULL
- };
- static const char * const mpeg_audio_mode[] = {
- "Stereo",
- "Joint Stereo",
- "Dual",
- "Mono",
- NULL
- };
- static const char * const mpeg_audio_mode_extension[] = {
- "Bound 4",
- "Bound 8",
- "Bound 12",
- "Bound 16",
- NULL
- };
- static const char * const mpeg_audio_emphasis[] = {
- "No Emphasis",
- "50/15 us",
- "CCITT J17",
- NULL
- };
- static const char * const mpeg_audio_crc[] = {
- "No CRC",
- "16-bit CRC",
- NULL
- };
- static const char * const mpeg_audio_dec_playback[] = {
- "Auto",
- "Stereo",
- "Left",
- "Right",
- "Mono",
- "Swapped Stereo",
- NULL
- };
- static const char * const mpeg_video_encoding[] = {
- "MPEG-1",
- "MPEG-2",
- "MPEG-4 AVC",
- NULL
- };
- static const char * const mpeg_video_aspect[] = {
- "1x1",
- "4x3",
- "16x9",
- "2.21x1",
- NULL
- };
- static const char * const mpeg_video_bitrate_mode[] = {
- "Variable Bitrate",
- "Constant Bitrate",
- "Constant Quality",
- NULL
- };
- static const char * const mpeg_stream_type[] = {
- "MPEG-2 Program Stream",
- "MPEG-2 Transport Stream",
- "MPEG-1 System Stream",
- "MPEG-2 DVD-compatible Stream",
- "MPEG-1 VCD-compatible Stream",
- "MPEG-2 SVCD-compatible Stream",
- NULL
- };
- static const char * const mpeg_stream_vbi_fmt[] = {
- "No VBI",
- "Private Packet, IVTV Format",
- NULL
- };
- static const char * const camera_power_line_frequency[] = {
- "Disabled",
- "50 Hz",
- "60 Hz",
- "Auto",
- NULL
- };
- static const char * const camera_exposure_auto[] = {
- "Auto Mode",
- "Manual Mode",
- "Shutter Priority Mode",
- "Aperture Priority Mode",
- NULL
- };
- static const char * const camera_exposure_metering[] = {
- "Average",
- "Center Weighted",
- "Spot",
- "Matrix",
- NULL
- };
- static const char * const camera_auto_focus_range[] = {
- "Auto",
- "Normal",
- "Macro",
- "Infinity",
- NULL
- };
- static const char * const colorfx[] = {
- "None",
- "Black & White",
- "Sepia",
- "Negative",
- "Emboss",
- "Sketch",
- "Sky Blue",
- "Grass Green",
- "Skin Whiten",
- "Vivid",
- "Aqua",
- "Art Freeze",
- "Silhouette",
- "Solarization",
- "Antique",
- "Set Cb/Cr",
- NULL
- };
- static const char * const auto_n_preset_white_balance[] = {
- "Manual",
- "Auto",
- "Incandescent",
- "Fluorescent",
- "Fluorescent H",
- "Horizon",
- "Daylight",
- "Flash",
- "Cloudy",
- "Shade",
- NULL,
- };
- static const char * const camera_iso_sensitivity_auto[] = {
- "Manual",
- "Auto",
- NULL
- };
- static const char * const scene_mode[] = {
- "None",
- "Backlight",
- "Beach/Snow",
- "Candle Light",
- "Dusk/Dawn",
- "Fall Colors",
- "Fireworks",
- "Landscape",
- "Night",
- "Party/Indoor",
- "Portrait",
- "Sports",
- "Sunset",
- "Text",
- NULL
- };
- static const char * const tune_emphasis[] = {
- "None",
- "50 Microseconds",
- "75 Microseconds",
- NULL,
- };
- static const char * const header_mode[] = {
- "Separate Buffer",
- "Joined With 1st Frame",
- NULL,
- };
- static const char * const multi_slice[] = {
- "Single",
- "Max Macroblocks",
- "Max Bytes",
- NULL,
- };
- static const char * const entropy_mode[] = {
- "CAVLC",
- "CABAC",
- NULL,
- };
- static const char * const mpeg_h264_level[] = {
- "1",
- "1b",
- "1.1",
- "1.2",
- "1.3",
- "2",
- "2.1",
- "2.2",
- "3",
- "3.1",
- "3.2",
- "4",
- "4.1",
- "4.2",
- "5",
- "5.1",
- "5.2",
- "6.0",
- "6.1",
- "6.2",
- NULL,
- };
- static const char * const h264_loop_filter[] = {
- "Enabled",
- "Disabled",
- "Disabled at Slice Boundary",
- NULL,
- };
- static const char * const h264_profile[] = {
- "Baseline",
- "Constrained Baseline",
- "Main",
- "Extended",
- "High",
- "High 10",
- "High 422",
- "High 444 Predictive",
- "High 10 Intra",
- "High 422 Intra",
- "High 444 Intra",
- "CAVLC 444 Intra",
- "Scalable Baseline",
- "Scalable High",
- "Scalable High Intra",
- "Stereo High",
- "Multiview High",
- "Constrained High",
- NULL,
- };
- static const char * const vui_sar_idc[] = {
- "Unspecified",
- "1:1",
- "12:11",
- "10:11",
- "16:11",
- "40:33",
- "24:11",
- "20:11",
- "32:11",
- "80:33",
- "18:11",
- "15:11",
- "64:33",
- "160:99",
- "4:3",
- "3:2",
- "2:1",
- "Extended SAR",
- NULL,
- };
- static const char * const h264_fp_arrangement_type[] = {
- "Checkerboard",
- "Column",
- "Row",
- "Side by Side",
- "Top Bottom",
- "Temporal",
- NULL,
- };
- static const char * const h264_fmo_map_type[] = {
- "Interleaved Slices",
- "Scattered Slices",
- "Foreground with Leftover",
- "Box Out",
- "Raster Scan",
- "Wipe Scan",
- "Explicit",
- NULL,
- };
- static const char * const h264_decode_mode[] = {
- "Slice-Based",
- "Frame-Based",
- NULL,
- };
- static const char * const h264_start_code[] = {
- "No Start Code",
- "Annex B Start Code",
- NULL,
- };
- static const char * const h264_hierarchical_coding_type[] = {
- "Hier Coding B",
- "Hier Coding P",
- 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",
- "1",
- "2",
- "3",
- "3b",
- "4",
- "5",
- NULL,
- };
- static const char * const mpeg4_profile[] = {
- "Simple",
- "Advanced Simple",
- "Core",
- "Simple Scalable",
- "Advanced Coding Efficiency",
- NULL,
- };
-
- static const char * const vpx_golden_frame_sel[] = {
- "Use Previous Frame",
- "Use Previous Specific Frame",
- NULL,
- };
- static const char * const vp8_profile[] = {
- "0",
- "1",
- "2",
- "3",
- NULL,
- };
- static const char * const vp9_profile[] = {
- "0",
- "1",
- "2",
- "3",
- NULL,
- };
- static const char * const vp9_level[] = {
- "1",
- "1.1",
- "2",
- "2.1",
- "3",
- "3.1",
- "4",
- "4.1",
- "5",
- "5.1",
- "5.2",
- "6",
- "6.1",
- "6.2",
- NULL,
- };
-
- static const char * const flash_led_mode[] = {
- "Off",
- "Flash",
- "Torch",
- NULL,
- };
- static const char * const flash_strobe_source[] = {
- "Software",
- "External",
- NULL,
- };
-
- static const char * const jpeg_chroma_subsampling[] = {
- "4:4:4",
- "4:2:2",
- "4:2:0",
- "4:1:1",
- "4:1:0",
- "Gray",
- NULL,
- };
- static const char * const dv_tx_mode[] = {
- "DVI-D",
- "HDMI",
- NULL,
- };
- static const char * const dv_rgb_range[] = {
- "Automatic",
- "RGB Limited Range (16-235)",
- "RGB Full Range (0-255)",
- NULL,
- };
- static const char * const dv_it_content_type[] = {
- "Graphics",
- "Photo",
- "Cinema",
- "Game",
- "No IT Content",
- NULL,
- };
- static const char * const detect_md_mode[] = {
- "Disabled",
- "Global",
- "Threshold Grid",
- "Region Grid",
- NULL,
- };
-
- static const char * const hevc_profile[] = {
- "Main",
- "Main Still Picture",
- "Main 10",
- NULL,
- };
- static const char * const hevc_level[] = {
- "1",
- "2",
- "2.1",
- "3",
- "3.1",
- "4",
- "4.1",
- "5",
- "5.1",
- "5.2",
- "6",
- "6.1",
- "6.2",
- NULL,
- };
- static const char * const hevc_hierarchial_coding_type[] = {
- "B",
- "P",
- NULL,
- };
- static const char * const hevc_refresh_type[] = {
- "None",
- "CRA",
- "IDR",
- NULL,
- };
- static const char * const hevc_size_of_length_field[] = {
- "0",
- "1",
- "2",
- "4",
- NULL,
- };
- static const char * const hevc_tier[] = {
- "Main",
- "High",
- NULL,
- };
- static const char * const hevc_loop_filter_mode[] = {
- "Disabled",
- "Enabled",
- "Disabled at slice boundary",
- "NULL",
- };
- static const char * const hevc_decode_mode[] = {
- "Slice-Based",
- "Frame-Based",
- NULL,
- };
- static const char * const hevc_start_code[] = {
- "No Start Code",
- "Annex B Start Code",
- NULL,
- };
- static const char * const camera_orientation[] = {
- "Front",
- "Back",
- "External",
- NULL,
- };
- static const char * const mpeg_video_frame_skip[] = {
- "Disabled",
- "Level Limit",
- "VBV/CPB Limit",
- NULL,
- };
-
- switch (id) {
- case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
- return mpeg_audio_sampling_freq;
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- return mpeg_audio_encoding;
- case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
- return mpeg_audio_l1_bitrate;
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
- return mpeg_audio_l2_bitrate;
- case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
- return mpeg_audio_l3_bitrate;
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
- return mpeg_audio_ac3_bitrate;
- case V4L2_CID_MPEG_AUDIO_MODE:
- return mpeg_audio_mode;
- case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
- return mpeg_audio_mode_extension;
- case V4L2_CID_MPEG_AUDIO_EMPHASIS:
- return mpeg_audio_emphasis;
- case V4L2_CID_MPEG_AUDIO_CRC:
- return mpeg_audio_crc;
- case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
- case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK:
- return mpeg_audio_dec_playback;
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- return mpeg_video_encoding;
- case V4L2_CID_MPEG_VIDEO_ASPECT:
- return mpeg_video_aspect;
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- return mpeg_video_bitrate_mode;
- case V4L2_CID_MPEG_STREAM_TYPE:
- return mpeg_stream_type;
- case V4L2_CID_MPEG_STREAM_VBI_FMT:
- return mpeg_stream_vbi_fmt;
- case V4L2_CID_POWER_LINE_FREQUENCY:
- return camera_power_line_frequency;
- case V4L2_CID_EXPOSURE_AUTO:
- return camera_exposure_auto;
- case V4L2_CID_EXPOSURE_METERING:
- return camera_exposure_metering;
- case V4L2_CID_AUTO_FOCUS_RANGE:
- return camera_auto_focus_range;
- case V4L2_CID_COLORFX:
- return colorfx;
- case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
- return auto_n_preset_white_balance;
- case V4L2_CID_ISO_SENSITIVITY_AUTO:
- return camera_iso_sensitivity_auto;
- case V4L2_CID_SCENE_MODE:
- return scene_mode;
- case V4L2_CID_TUNE_PREEMPHASIS:
- return tune_emphasis;
- case V4L2_CID_TUNE_DEEMPHASIS:
- return tune_emphasis;
- case V4L2_CID_FLASH_LED_MODE:
- return flash_led_mode;
- case V4L2_CID_FLASH_STROBE_SOURCE:
- return flash_strobe_source;
- case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
- return header_mode;
- case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
- return mpeg_video_frame_skip;
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
- return multi_slice;
- case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
- return entropy_mode;
- case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
- return mpeg_h264_level;
- case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
- return h264_loop_filter;
- case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
- return h264_profile;
- case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
- return vui_sar_idc;
- case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE:
- return h264_fp_arrangement_type;
- case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE:
- return h264_fmo_map_type;
- case V4L2_CID_STATELESS_H264_DECODE_MODE:
- return h264_decode_mode;
- case V4L2_CID_STATELESS_H264_START_CODE:
- return h264_start_code;
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE:
- return h264_hierarchical_coding_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:
- return mpeg4_profile;
- case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
- return vpx_golden_frame_sel;
- case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
- return vp8_profile;
- case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
- return vp9_profile;
- case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
- return vp9_level;
- case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
- return jpeg_chroma_subsampling;
- case V4L2_CID_DV_TX_MODE:
- return dv_tx_mode;
- case V4L2_CID_DV_TX_RGB_RANGE:
- case V4L2_CID_DV_RX_RGB_RANGE:
- return dv_rgb_range;
- case V4L2_CID_DV_TX_IT_CONTENT_TYPE:
- case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
- return dv_it_content_type;
- case V4L2_CID_DETECT_MD_MODE:
- return detect_md_mode;
- case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
- return hevc_profile;
- case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
- return hevc_level;
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE:
- return hevc_hierarchial_coding_type;
- case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
- return hevc_refresh_type;
- case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
- return hevc_size_of_length_field;
- case V4L2_CID_MPEG_VIDEO_HEVC_TIER:
- return hevc_tier;
- case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
- return hevc_loop_filter_mode;
- case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE:
- return hevc_decode_mode;
- case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE:
- return hevc_start_code;
- case V4L2_CID_CAMERA_ORIENTATION:
- return camera_orientation;
- default:
- return NULL;
- }
-}
-EXPORT_SYMBOL(v4l2_ctrl_get_menu);
-
-#define __v4l2_qmenu_int_len(arr, len) ({ *(len) = ARRAY_SIZE(arr); arr; })
-/*
- * Returns NULL or an s64 type array containing the menu for given
- * control ID. The total number of the menu items is returned in @len.
- */
-const s64 *v4l2_ctrl_get_int_menu(u32 id, u32 *len)
-{
- static const s64 qmenu_int_vpx_num_partitions[] = {
- 1, 2, 4, 8,
- };
-
- static const s64 qmenu_int_vpx_num_ref_frames[] = {
- 1, 2, 3,
- };
-
- switch (id) {
- case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS:
- return __v4l2_qmenu_int_len(qmenu_int_vpx_num_partitions, len);
- case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES:
- return __v4l2_qmenu_int_len(qmenu_int_vpx_num_ref_frames, len);
- default:
- *len = 0;
- return NULL;
- }
-}
-EXPORT_SYMBOL(v4l2_ctrl_get_int_menu);
-
-/* Return the control name. */
-const char *v4l2_ctrl_get_name(u32 id)
-{
- switch (id) {
- /* USER controls */
- /* Keep the order of the 'case's the same as in v4l2-controls.h! */
- case V4L2_CID_USER_CLASS: return "User Controls";
- case V4L2_CID_BRIGHTNESS: return "Brightness";
- case V4L2_CID_CONTRAST: return "Contrast";
- case V4L2_CID_SATURATION: return "Saturation";
- case V4L2_CID_HUE: return "Hue";
- case V4L2_CID_AUDIO_VOLUME: return "Volume";
- case V4L2_CID_AUDIO_BALANCE: return "Balance";
- case V4L2_CID_AUDIO_BASS: return "Bass";
- case V4L2_CID_AUDIO_TREBLE: return "Treble";
- case V4L2_CID_AUDIO_MUTE: return "Mute";
- case V4L2_CID_AUDIO_LOUDNESS: return "Loudness";
- case V4L2_CID_BLACK_LEVEL: return "Black Level";
- case V4L2_CID_AUTO_WHITE_BALANCE: return "White Balance, Automatic";
- case V4L2_CID_DO_WHITE_BALANCE: return "Do White Balance";
- case V4L2_CID_RED_BALANCE: return "Red Balance";
- case V4L2_CID_BLUE_BALANCE: return "Blue Balance";
- case V4L2_CID_GAMMA: return "Gamma";
- case V4L2_CID_EXPOSURE: return "Exposure";
- case V4L2_CID_AUTOGAIN: return "Gain, Automatic";
- case V4L2_CID_GAIN: return "Gain";
- case V4L2_CID_HFLIP: return "Horizontal Flip";
- case V4L2_CID_VFLIP: return "Vertical Flip";
- case V4L2_CID_POWER_LINE_FREQUENCY: return "Power Line Frequency";
- case V4L2_CID_HUE_AUTO: return "Hue, Automatic";
- case V4L2_CID_WHITE_BALANCE_TEMPERATURE: return "White Balance Temperature";
- case V4L2_CID_SHARPNESS: return "Sharpness";
- case V4L2_CID_BACKLIGHT_COMPENSATION: return "Backlight Compensation";
- case V4L2_CID_CHROMA_AGC: return "Chroma AGC";
- case V4L2_CID_COLOR_KILLER: return "Color Killer";
- case V4L2_CID_COLORFX: return "Color Effects";
- case V4L2_CID_AUTOBRIGHTNESS: return "Brightness, Automatic";
- case V4L2_CID_BAND_STOP_FILTER: return "Band-Stop Filter";
- case V4L2_CID_ROTATE: return "Rotate";
- case V4L2_CID_BG_COLOR: return "Background Color";
- case V4L2_CID_CHROMA_GAIN: return "Chroma Gain";
- case V4L2_CID_ILLUMINATORS_1: return "Illuminator 1";
- case V4L2_CID_ILLUMINATORS_2: return "Illuminator 2";
- case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: return "Min Number of Capture Buffers";
- case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: return "Min Number of Output Buffers";
- case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component";
- case V4L2_CID_COLORFX_CBCR: return "Color Effects, CbCr";
-
- /* Codec controls */
- /* The MPEG controls are applicable to all codec controls
- * and the 'MPEG' part of the define is historical */
- /* Keep the order of the 'case's the same as in videodev2.h! */
- case V4L2_CID_CODEC_CLASS: return "Codec Controls";
- case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type";
- case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID";
- case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID";
- case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID";
- case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID";
- case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID";
- case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID";
- case V4L2_CID_MPEG_STREAM_VBI_FMT: return "Stream VBI Format";
- case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency";
- case V4L2_CID_MPEG_AUDIO_ENCODING: return "Audio Encoding";
- case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate";
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate";
- case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate";
- case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode";
- case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension";
- case V4L2_CID_MPEG_AUDIO_EMPHASIS: return "Audio Emphasis";
- case V4L2_CID_MPEG_AUDIO_CRC: return "Audio CRC";
- case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute";
- case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate";
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate";
- case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: return "Audio Playback";
- case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: return "Audio Multilingual Playback";
- case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding";
- case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect";
- case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames";
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE: return "Video GOP Size";
- case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: return "Video GOP Closure";
- case V4L2_CID_MPEG_VIDEO_PULLDOWN: return "Video Pulldown";
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: return "Video Bitrate Mode";
- case V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY: return "Constant Quality";
- case V4L2_CID_MPEG_VIDEO_BITRATE: return "Video Bitrate";
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: return "Video Peak Bitrate";
- case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
- case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute";
- case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV";
- case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: return "Decoder Slice Interface";
- case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: return "MPEG4 Loop Filter Enable";
- case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: return "Number of Intra Refresh MBs";
- case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: return "Frame Level Rate Control Enable";
- case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: return "H264 MB Level Rate Control";
- case V4L2_CID_MPEG_VIDEO_HEADER_MODE: return "Sequence Header Mode";
- case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC: return "Max Number of Reference Pics";
- case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: return "Frame Skip Mode";
- case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: return "Display Delay";
- case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: return "Display Delay Enable";
- case V4L2_CID_MPEG_VIDEO_AU_DELIMITER: return "Generate Access Unit Delimiters";
- case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: return "H263 I-Frame QP Value";
- case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: return "H263 P-Frame QP Value";
- case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: return "H263 B-Frame QP Value";
- case V4L2_CID_MPEG_VIDEO_H263_MIN_QP: return "H263 Minimum QP Value";
- case V4L2_CID_MPEG_VIDEO_H263_MAX_QP: return "H263 Maximum QP Value";
- case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: return "H264 I-Frame QP Value";
- case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: return "H264 P-Frame QP Value";
- case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: return "H264 B-Frame QP Value";
- case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: return "H264 Maximum QP Value";
- case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: return "H264 Minimum QP Value";
- case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: return "H264 8x8 Transform Enable";
- case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: return "H264 CPB Buffer Size";
- case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: return "H264 Entropy Mode";
- case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: return "H264 I-Frame Period";
- case V4L2_CID_MPEG_VIDEO_H264_LEVEL: return "H264 Level";
- case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: return "H264 Loop Filter Alpha Offset";
- case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: return "H264 Loop Filter Beta Offset";
- case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: return "H264 Loop Filter Mode";
- case V4L2_CID_MPEG_VIDEO_H264_PROFILE: return "H264 Profile";
- case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT: return "Vertical Size of SAR";
- case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH: return "Horizontal Size of SAR";
- case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: return "Aspect Ratio VUI Enable";
- case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: return "VUI Aspect Ratio IDC";
- case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING: return "H264 Enable Frame Packing SEI";
- case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0: return "H264 Set Curr. Frame as Frame0";
- case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: return "H264 FP Arrangement Type";
- case V4L2_CID_MPEG_VIDEO_H264_FMO: return "H264 Flexible MB Ordering";
- case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: return "H264 Map Type for FMO";
- case V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP: return "H264 FMO Number of Slice Groups";
- case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION: return "H264 FMO Direction of Change";
- case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE: return "H264 FMO Size of 1st Slice Grp";
- case V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH: return "H264 FMO No. of Consecutive MBs";
- case V4L2_CID_MPEG_VIDEO_H264_ASO: return "H264 Arbitrary Slice Ordering";
- case V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER: return "H264 ASO Slice Order";
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING: return "Enable H264 Hierarchical Coding";
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: return "H264 Hierarchical Coding Type";
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:return "H264 Number of HC Layers";
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP:
- return "H264 Set QP Value for HC Layers";
- case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION:
- return "H264 Constrained Intra Pred";
- case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: return "H264 Chroma QP Index Offset";
- case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP: return "H264 I-Frame Minimum QP Value";
- 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_B_FRAME_MIN_QP: return "H264 B-Frame Minimum QP Value";
- case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP: return "H264 B-Frame Maximum QP Value";
- case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR: return "H264 Hierarchical Lay 0 Bitrate";
- case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR: return "H264 Hierarchical Lay 1 Bitrate";
- case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR: return "H264 Hierarchical Lay 2 Bitrate";
- case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR: return "H264 Hierarchical Lay 3 Bitrate";
- case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR: return "H264 Hierarchical Lay 4 Bitrate";
- case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR: return "H264 Hierarchical Lay 5 Bitrate";
- case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L6_BR: return "H264 Hierarchical Lay 6 Bitrate";
- 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";
- case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP: return "MPEG4 Minimum QP Value";
- case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP: return "MPEG4 Maximum QP Value";
- case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: return "MPEG4 Level";
- case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: return "MPEG4 Profile";
- case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: return "Quarter Pixel Search Enable";
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: return "Maximum Bytes in a Slice";
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: return "Number of MBs in a Slice";
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: return "Slice Partitioning Method";
- case V4L2_CID_MPEG_VIDEO_VBV_SIZE: return "VBV Buffer Size";
- case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS";
- case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count";
- case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR: return "Video Decoder Conceal Color";
- case V4L2_CID_MPEG_VIDEO_VBV_DELAY: return "Initial Delay for VBV Control";
- case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: return "Horizontal MV Search Range";
- case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: return "Vertical MV Search Range";
- case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: return "Repeat Sequence Header";
- case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: return "Force Key Frame";
- case V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID: return "Base Layer Priority ID";
- case V4L2_CID_MPEG_VIDEO_LTR_COUNT: return "LTR Count";
- case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: return "Frame LTR Index";
- case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: return "Use LTR Frames";
- case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS: return "MPEG-2 Slice Parameters";
- case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION: return "MPEG-2 Quantization Matrices";
- case V4L2_CID_FWHT_I_FRAME_QP: return "FWHT I-Frame QP Value";
- case V4L2_CID_FWHT_P_FRAME_QP: return "FWHT P-Frame QP Value";
-
- /* VPX controls */
- case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: return "VPX Number of Partitions";
- case V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4: return "VPX Intra Mode Decision Disable";
- case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES: return "VPX No. of Refs for P Frame";
- case V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL: return "VPX Loop Filter Level Range";
- case V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS: return "VPX Deblocking Effect Control";
- case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD: return "VPX Golden Frame Refresh Period";
- case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: return "VPX Golden Frame Indicator";
- case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP: return "VPX Minimum QP Value";
- case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP: return "VPX Maximum QP Value";
- case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP: return "VPX I-Frame QP Value";
- case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: return "VPX P-Frame QP Value";
- case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: return "VP8 Profile";
- case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: return "VP9 Profile";
- case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: return "VP9 Level";
-
- /* HEVC controls */
- case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: return "HEVC I-Frame QP Value";
- case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: return "HEVC P-Frame QP Value";
- case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: return "HEVC B-Frame QP Value";
- case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: return "HEVC Minimum QP Value";
- case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: return "HEVC Maximum QP Value";
- case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP: return "HEVC I-Frame Minimum QP Value";
- case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP: return "HEVC I-Frame Maximum QP Value";
- case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP: return "HEVC P-Frame Minimum QP Value";
- case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP: return "HEVC P-Frame Maximum QP Value";
- case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP: return "HEVC B-Frame Minimum QP Value";
- case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP: return "HEVC B-Frame Maximum QP Value";
- case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: return "HEVC Profile";
- case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: return "HEVC Level";
- case V4L2_CID_MPEG_VIDEO_HEVC_TIER: return "HEVC Tier";
- case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION: return "HEVC Frame Rate Resolution";
- case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH: return "HEVC Maximum Coding Unit Depth";
- case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: return "HEVC Refresh Type";
- case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: return "HEVC Constant Intra Prediction";
- case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: return "HEVC Lossless Encoding";
- case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: return "HEVC Wavefront";
- case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: return "HEVC Loop Filter";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP: return "HEVC QP Values";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: return "HEVC Hierarchical Coding Type";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: return "HEVC Hierarchical Coding Layer";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP: return "HEVC Hierarchical Layer 0 QP";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP: return "HEVC Hierarchical Layer 1 QP";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP: return "HEVC Hierarchical Layer 2 QP";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP: return "HEVC Hierarchical Layer 3 QP";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP: return "HEVC Hierarchical Layer 4 QP";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP: return "HEVC Hierarchical Layer 5 QP";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP: return "HEVC Hierarchical Layer 6 QP";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: return "HEVC Hierarchical Lay 0 BitRate";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: return "HEVC Hierarchical Lay 1 BitRate";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: return "HEVC Hierarchical Lay 2 BitRate";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: return "HEVC Hierarchical Lay 3 BitRate";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: return "HEVC Hierarchical Lay 4 BitRate";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: return "HEVC Hierarchical Lay 5 BitRate";
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR: return "HEVC Hierarchical Lay 6 BitRate";
- case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB: return "HEVC General PB";
- case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID: return "HEVC Temporal ID";
- case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: return "HEVC Strong Intra Smoothing";
- case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT: return "HEVC Intra PU Split";
- case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: return "HEVC TMV Prediction";
- case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: return "HEVC Max Num of Candidate MVs";
- case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE: return "HEVC ENC Without Startcode";
- case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: return "HEVC Num of I-Frame b/w 2 IDR";
- case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: return "HEVC Loop Filter Beta Offset";
- case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: return "HEVC Loop Filter TC Offset";
- case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: return "HEVC Size of Length Field";
- case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: return "Reference Frames for a P-Frame";
- case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: return "Prepend SPS and PPS to IDR";
- case V4L2_CID_MPEG_VIDEO_HEVC_SPS: return "HEVC Sequence Parameter Set";
- case V4L2_CID_MPEG_VIDEO_HEVC_PPS: return "HEVC Picture Parameter Set";
- case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters";
- case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: return "HEVC Decode Mode";
- case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: return "HEVC Start Code";
-
- /* CAMERA controls */
- /* Keep the order of the 'case's the same as in v4l2-controls.h! */
- case V4L2_CID_CAMERA_CLASS: return "Camera Controls";
- case V4L2_CID_EXPOSURE_AUTO: return "Auto Exposure";
- case V4L2_CID_EXPOSURE_ABSOLUTE: return "Exposure Time, Absolute";
- case V4L2_CID_EXPOSURE_AUTO_PRIORITY: return "Exposure, Dynamic Framerate";
- case V4L2_CID_PAN_RELATIVE: return "Pan, Relative";
- case V4L2_CID_TILT_RELATIVE: return "Tilt, Relative";
- case V4L2_CID_PAN_RESET: return "Pan, Reset";
- case V4L2_CID_TILT_RESET: return "Tilt, Reset";
- case V4L2_CID_PAN_ABSOLUTE: return "Pan, Absolute";
- case V4L2_CID_TILT_ABSOLUTE: return "Tilt, Absolute";
- case V4L2_CID_FOCUS_ABSOLUTE: return "Focus, Absolute";
- case V4L2_CID_FOCUS_RELATIVE: return "Focus, Relative";
- case V4L2_CID_FOCUS_AUTO: return "Focus, Automatic Continuous";
- case V4L2_CID_ZOOM_ABSOLUTE: return "Zoom, Absolute";
- case V4L2_CID_ZOOM_RELATIVE: return "Zoom, Relative";
- case V4L2_CID_ZOOM_CONTINUOUS: return "Zoom, Continuous";
- case V4L2_CID_PRIVACY: return "Privacy";
- case V4L2_CID_IRIS_ABSOLUTE: return "Iris, Absolute";
- case V4L2_CID_IRIS_RELATIVE: return "Iris, Relative";
- case V4L2_CID_AUTO_EXPOSURE_BIAS: return "Auto Exposure, Bias";
- case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: return "White Balance, Auto & Preset";
- case V4L2_CID_WIDE_DYNAMIC_RANGE: return "Wide Dynamic Range";
- case V4L2_CID_IMAGE_STABILIZATION: return "Image Stabilization";
- case V4L2_CID_ISO_SENSITIVITY: return "ISO Sensitivity";
- case V4L2_CID_ISO_SENSITIVITY_AUTO: return "ISO Sensitivity, Auto";
- case V4L2_CID_EXPOSURE_METERING: return "Exposure, Metering Mode";
- case V4L2_CID_SCENE_MODE: return "Scene Mode";
- case V4L2_CID_3A_LOCK: return "3A Lock";
- case V4L2_CID_AUTO_FOCUS_START: return "Auto Focus, Start";
- case V4L2_CID_AUTO_FOCUS_STOP: return "Auto Focus, Stop";
- case V4L2_CID_AUTO_FOCUS_STATUS: return "Auto Focus, Status";
- case V4L2_CID_AUTO_FOCUS_RANGE: return "Auto Focus, Range";
- case V4L2_CID_PAN_SPEED: return "Pan, Speed";
- case V4L2_CID_TILT_SPEED: return "Tilt, Speed";
- case V4L2_CID_UNIT_CELL_SIZE: return "Unit Cell Size";
- case V4L2_CID_CAMERA_ORIENTATION: return "Camera Orientation";
- case V4L2_CID_CAMERA_SENSOR_ROTATION: return "Camera Sensor Rotation";
-
- /* FM Radio Modulator controls */
- /* Keep the order of the 'case's the same as in v4l2-controls.h! */
- case V4L2_CID_FM_TX_CLASS: return "FM Radio Modulator Controls";
- case V4L2_CID_RDS_TX_DEVIATION: return "RDS Signal Deviation";
- case V4L2_CID_RDS_TX_PI: return "RDS Program ID";
- case V4L2_CID_RDS_TX_PTY: return "RDS Program Type";
- case V4L2_CID_RDS_TX_PS_NAME: return "RDS PS Name";
- case V4L2_CID_RDS_TX_RADIO_TEXT: return "RDS Radio Text";
- case V4L2_CID_RDS_TX_MONO_STEREO: return "RDS Stereo";
- case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD: return "RDS Artificial Head";
- case V4L2_CID_RDS_TX_COMPRESSED: return "RDS Compressed";
- case V4L2_CID_RDS_TX_DYNAMIC_PTY: return "RDS Dynamic PTY";
- case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement";
- case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM: return "RDS Traffic Program";
- case V4L2_CID_RDS_TX_MUSIC_SPEECH: return "RDS Music";
- case V4L2_CID_RDS_TX_ALT_FREQS_ENABLE: return "RDS Enable Alt Frequencies";
- case V4L2_CID_RDS_TX_ALT_FREQS: return "RDS Alternate Frequencies";
- case V4L2_CID_AUDIO_LIMITER_ENABLED: return "Audio Limiter Feature Enabled";
- case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
- case V4L2_CID_AUDIO_LIMITER_DEVIATION: return "Audio Limiter Deviation";
- case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Enabled";
- case V4L2_CID_AUDIO_COMPRESSION_GAIN: return "Audio Compression Gain";
- case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold";
- case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time";
- case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: return "Audio Compression Release Time";
- case V4L2_CID_PILOT_TONE_ENABLED: return "Pilot Tone Feature Enabled";
- case V4L2_CID_PILOT_TONE_DEVIATION: return "Pilot Tone Deviation";
- case V4L2_CID_PILOT_TONE_FREQUENCY: return "Pilot Tone Frequency";
- case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-Emphasis";
- case V4L2_CID_TUNE_POWER_LEVEL: return "Tune Power Level";
- case V4L2_CID_TUNE_ANTENNA_CAPACITOR: return "Tune Antenna Capacitor";
-
- /* Flash controls */
- /* Keep the order of the 'case's the same as in v4l2-controls.h! */
- case V4L2_CID_FLASH_CLASS: return "Flash Controls";
- case V4L2_CID_FLASH_LED_MODE: return "LED Mode";
- case V4L2_CID_FLASH_STROBE_SOURCE: return "Strobe Source";
- case V4L2_CID_FLASH_STROBE: return "Strobe";
- case V4L2_CID_FLASH_STROBE_STOP: return "Stop Strobe";
- case V4L2_CID_FLASH_STROBE_STATUS: return "Strobe Status";
- case V4L2_CID_FLASH_TIMEOUT: return "Strobe Timeout";
- case V4L2_CID_FLASH_INTENSITY: return "Intensity, Flash Mode";
- case V4L2_CID_FLASH_TORCH_INTENSITY: return "Intensity, Torch Mode";
- case V4L2_CID_FLASH_INDICATOR_INTENSITY: return "Intensity, Indicator";
- case V4L2_CID_FLASH_FAULT: return "Faults";
- case V4L2_CID_FLASH_CHARGE: return "Charge";
- case V4L2_CID_FLASH_READY: return "Ready to Strobe";
-
- /* JPEG encoder controls */
- /* Keep the order of the 'case's the same as in v4l2-controls.h! */
- case V4L2_CID_JPEG_CLASS: return "JPEG Compression Controls";
- case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: return "Chroma Subsampling";
- case V4L2_CID_JPEG_RESTART_INTERVAL: return "Restart Interval";
- case V4L2_CID_JPEG_COMPRESSION_QUALITY: return "Compression Quality";
- case V4L2_CID_JPEG_ACTIVE_MARKER: return "Active Markers";
-
- /* Image source controls */
- /* Keep the order of the 'case's the same as in v4l2-controls.h! */
- case V4L2_CID_IMAGE_SOURCE_CLASS: return "Image Source Controls";
- case V4L2_CID_VBLANK: return "Vertical Blanking";
- case V4L2_CID_HBLANK: return "Horizontal Blanking";
- case V4L2_CID_ANALOGUE_GAIN: return "Analogue Gain";
- case V4L2_CID_TEST_PATTERN_RED: return "Red Pixel Value";
- case V4L2_CID_TEST_PATTERN_GREENR: return "Green (Red) Pixel Value";
- case V4L2_CID_TEST_PATTERN_BLUE: return "Blue Pixel Value";
- case V4L2_CID_TEST_PATTERN_GREENB: return "Green (Blue) Pixel Value";
-
- /* Image processing controls */
- /* Keep the order of the 'case's the same as in v4l2-controls.h! */
- case V4L2_CID_IMAGE_PROC_CLASS: return "Image Processing Controls";
- case V4L2_CID_LINK_FREQ: return "Link Frequency";
- case V4L2_CID_PIXEL_RATE: return "Pixel Rate";
- case V4L2_CID_TEST_PATTERN: return "Test Pattern";
- case V4L2_CID_DEINTERLACING_MODE: return "Deinterlacing Mode";
- case V4L2_CID_DIGITAL_GAIN: return "Digital Gain";
-
- /* DV controls */
- /* Keep the order of the 'case's the same as in v4l2-controls.h! */
- case V4L2_CID_DV_CLASS: return "Digital Video Controls";
- case V4L2_CID_DV_TX_HOTPLUG: return "Hotplug Present";
- case V4L2_CID_DV_TX_RXSENSE: return "RxSense Present";
- case V4L2_CID_DV_TX_EDID_PRESENT: return "EDID Present";
- case V4L2_CID_DV_TX_MODE: return "Transmit Mode";
- case V4L2_CID_DV_TX_RGB_RANGE: return "Tx RGB Quantization Range";
- case V4L2_CID_DV_TX_IT_CONTENT_TYPE: return "Tx IT Content Type";
- case V4L2_CID_DV_RX_POWER_PRESENT: return "Power Present";
- case V4L2_CID_DV_RX_RGB_RANGE: return "Rx RGB Quantization Range";
- case V4L2_CID_DV_RX_IT_CONTENT_TYPE: return "Rx IT Content Type";
-
- case V4L2_CID_FM_RX_CLASS: return "FM Radio Receiver Controls";
- case V4L2_CID_TUNE_DEEMPHASIS: return "De-Emphasis";
- case V4L2_CID_RDS_RECEPTION: return "RDS Reception";
- case V4L2_CID_RF_TUNER_CLASS: return "RF Tuner Controls";
- case V4L2_CID_RF_TUNER_RF_GAIN: return "RF Gain";
- case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: return "LNA Gain, Auto";
- case V4L2_CID_RF_TUNER_LNA_GAIN: return "LNA Gain";
- case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: return "Mixer Gain, Auto";
- case V4L2_CID_RF_TUNER_MIXER_GAIN: return "Mixer Gain";
- case V4L2_CID_RF_TUNER_IF_GAIN_AUTO: return "IF Gain, Auto";
- case V4L2_CID_RF_TUNER_IF_GAIN: return "IF Gain";
- case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: return "Bandwidth, Auto";
- case V4L2_CID_RF_TUNER_BANDWIDTH: return "Bandwidth";
- case V4L2_CID_RF_TUNER_PLL_LOCK: return "PLL Lock";
- case V4L2_CID_RDS_RX_PTY: return "RDS Program Type";
- case V4L2_CID_RDS_RX_PS_NAME: return "RDS PS Name";
- case V4L2_CID_RDS_RX_RADIO_TEXT: return "RDS Radio Text";
- case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement";
- case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM: return "RDS Traffic Program";
- case V4L2_CID_RDS_RX_MUSIC_SPEECH: return "RDS Music";
-
- /* Detection controls */
- /* Keep the order of the 'case's the same as in v4l2-controls.h! */
- case V4L2_CID_DETECT_CLASS: return "Detection Controls";
- case V4L2_CID_DETECT_MD_MODE: return "Motion Detection Mode";
- case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD: return "MD Global Threshold";
- case V4L2_CID_DETECT_MD_THRESHOLD_GRID: return "MD Threshold Grid";
- case V4L2_CID_DETECT_MD_REGION_GRID: return "MD Region Grid";
-
- /* Stateless Codec controls */
- /* Keep the order of the 'case's the same as in v4l2-controls.h! */
- case V4L2_CID_CODEC_STATELESS_CLASS: return "Stateless Codec Controls";
- case V4L2_CID_STATELESS_H264_DECODE_MODE: return "H264 Decode Mode";
- case V4L2_CID_STATELESS_H264_START_CODE: return "H264 Start Code";
- case V4L2_CID_STATELESS_H264_SPS: return "H264 Sequence Parameter Set";
- case V4L2_CID_STATELESS_H264_PPS: return "H264 Picture Parameter Set";
- case V4L2_CID_STATELESS_H264_SCALING_MATRIX: return "H264 Scaling Matrix";
- case V4L2_CID_STATELESS_H264_PRED_WEIGHTS: return "H264 Prediction Weight Table";
- case V4L2_CID_STATELESS_H264_SLICE_PARAMS: return "H264 Slice Parameters";
- case V4L2_CID_STATELESS_H264_DECODE_PARAMS: return "H264 Decode Parameters";
- case V4L2_CID_STATELESS_FWHT_PARAMS: return "FWHT Stateless Parameters";
- case V4L2_CID_STATELESS_VP8_FRAME: return "VP8 Frame Parameters";
-
- /* Colorimetry controls */
- /* Keep the order of the 'case's the same as in v4l2-controls.h! */
- case V4L2_CID_COLORIMETRY_CLASS: return "Colorimetry Controls";
- case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO: return "HDR10 Content Light Info";
- case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY: return "HDR10 Mastering Display";
- default:
- return NULL;
- }
-}
-EXPORT_SYMBOL(v4l2_ctrl_get_name);
-
-void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
- s64 *min, s64 *max, u64 *step, s64 *def, u32 *flags)
-{
- *name = v4l2_ctrl_get_name(id);
- *flags = 0;
-
- switch (id) {
- case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_LOUDNESS:
- case V4L2_CID_AUTO_WHITE_BALANCE:
- case V4L2_CID_AUTOGAIN:
- case V4L2_CID_HFLIP:
- case V4L2_CID_VFLIP:
- case V4L2_CID_HUE_AUTO:
- case V4L2_CID_CHROMA_AGC:
- case V4L2_CID_COLOR_KILLER:
- case V4L2_CID_AUTOBRIGHTNESS:
- case V4L2_CID_MPEG_AUDIO_MUTE:
- case V4L2_CID_MPEG_VIDEO_MUTE:
- case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
- case V4L2_CID_MPEG_VIDEO_PULLDOWN:
- case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
- case V4L2_CID_FOCUS_AUTO:
- case V4L2_CID_PRIVACY:
- case V4L2_CID_AUDIO_LIMITER_ENABLED:
- case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
- case V4L2_CID_PILOT_TONE_ENABLED:
- case V4L2_CID_ILLUMINATORS_1:
- case V4L2_CID_ILLUMINATORS_2:
- case V4L2_CID_FLASH_STROBE_STATUS:
- case V4L2_CID_FLASH_CHARGE:
- case V4L2_CID_FLASH_READY:
- case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
- case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
- case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE:
- case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
- case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
- case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
- case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
- case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
- case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER:
- case V4L2_CID_MPEG_VIDEO_AU_DELIMITER:
- case V4L2_CID_WIDE_DYNAMIC_RANGE:
- case V4L2_CID_IMAGE_STABILIZATION:
- case V4L2_CID_RDS_RECEPTION:
- case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:
- case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO:
- case V4L2_CID_RF_TUNER_IF_GAIN_AUTO:
- case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
- case V4L2_CID_RF_TUNER_PLL_LOCK:
- case V4L2_CID_RDS_TX_MONO_STEREO:
- case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD:
- case V4L2_CID_RDS_TX_COMPRESSED:
- case V4L2_CID_RDS_TX_DYNAMIC_PTY:
- case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT:
- case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:
- case V4L2_CID_RDS_TX_MUSIC_SPEECH:
- case V4L2_CID_RDS_TX_ALT_FREQS_ENABLE:
- case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT:
- case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM:
- case V4L2_CID_RDS_RX_MUSIC_SPEECH:
- *type = V4L2_CTRL_TYPE_BOOLEAN;
- *min = 0;
- *max = *step = 1;
- break;
- case V4L2_CID_ROTATE:
- *type = V4L2_CTRL_TYPE_INTEGER;
- *flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
- break;
- case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE:
- case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE:
- case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY:
- *type = V4L2_CTRL_TYPE_INTEGER;
- break;
- case V4L2_CID_MPEG_VIDEO_LTR_COUNT:
- *type = V4L2_CTRL_TYPE_INTEGER;
- break;
- case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX:
- *type = V4L2_CTRL_TYPE_INTEGER;
- *flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
- break;
- case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES:
- *type = V4L2_CTRL_TYPE_BITMASK;
- *flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
- break;
- case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
- case V4L2_CID_PAN_RESET:
- case V4L2_CID_TILT_RESET:
- case V4L2_CID_FLASH_STROBE:
- 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;
- *min = *max = *step = *def = 0;
- break;
- case V4L2_CID_POWER_LINE_FREQUENCY:
- case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
- case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
- case V4L2_CID_MPEG_AUDIO_MODE:
- case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
- case V4L2_CID_MPEG_AUDIO_EMPHASIS:
- case V4L2_CID_MPEG_AUDIO_CRC:
- case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
- case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK:
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- case V4L2_CID_MPEG_VIDEO_ASPECT:
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- case V4L2_CID_MPEG_STREAM_TYPE:
- case V4L2_CID_MPEG_STREAM_VBI_FMT:
- case V4L2_CID_EXPOSURE_AUTO:
- case V4L2_CID_AUTO_FOCUS_RANGE:
- case V4L2_CID_COLORFX:
- case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
- case V4L2_CID_TUNE_PREEMPHASIS:
- case V4L2_CID_FLASH_LED_MODE:
- case V4L2_CID_FLASH_STROBE_SOURCE:
- case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
- case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
- case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
- case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
- case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
- case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
- 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_H264_HIERARCHICAL_CODING_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:
- case V4L2_CID_ISO_SENSITIVITY_AUTO:
- case V4L2_CID_EXPOSURE_METERING:
- case V4L2_CID_SCENE_MODE:
- case V4L2_CID_DV_TX_MODE:
- case V4L2_CID_DV_TX_RGB_RANGE:
- case V4L2_CID_DV_TX_IT_CONTENT_TYPE:
- case V4L2_CID_DV_RX_RGB_RANGE:
- case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
- case V4L2_CID_TEST_PATTERN:
- case V4L2_CID_DEINTERLACING_MODE:
- case V4L2_CID_TUNE_DEEMPHASIS:
- case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
- case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
- case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
- case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
- case V4L2_CID_DETECT_MD_MODE:
- case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
- case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
- case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE:
- case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
- case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
- case V4L2_CID_MPEG_VIDEO_HEVC_TIER:
- case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
- case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE:
- case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE:
- case V4L2_CID_STATELESS_H264_DECODE_MODE:
- case V4L2_CID_STATELESS_H264_START_CODE:
- case V4L2_CID_CAMERA_ORIENTATION:
- *type = V4L2_CTRL_TYPE_MENU;
- break;
- case V4L2_CID_LINK_FREQ:
- *type = V4L2_CTRL_TYPE_INTEGER_MENU;
- break;
- case V4L2_CID_RDS_TX_PS_NAME:
- case V4L2_CID_RDS_TX_RADIO_TEXT:
- case V4L2_CID_RDS_RX_PS_NAME:
- case V4L2_CID_RDS_RX_RADIO_TEXT:
- *type = V4L2_CTRL_TYPE_STRING;
- break;
- case V4L2_CID_ISO_SENSITIVITY:
- case V4L2_CID_AUTO_EXPOSURE_BIAS:
- case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS:
- case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES:
- *type = V4L2_CTRL_TYPE_INTEGER_MENU;
- break;
- case V4L2_CID_USER_CLASS:
- case V4L2_CID_CAMERA_CLASS:
- case V4L2_CID_CODEC_CLASS:
- case V4L2_CID_FM_TX_CLASS:
- case V4L2_CID_FLASH_CLASS:
- case V4L2_CID_JPEG_CLASS:
- case V4L2_CID_IMAGE_SOURCE_CLASS:
- case V4L2_CID_IMAGE_PROC_CLASS:
- case V4L2_CID_DV_CLASS:
- case V4L2_CID_FM_RX_CLASS:
- case V4L2_CID_RF_TUNER_CLASS:
- case V4L2_CID_DETECT_CLASS:
- case V4L2_CID_CODEC_STATELESS_CLASS:
- case V4L2_CID_COLORIMETRY_CLASS:
- *type = V4L2_CTRL_TYPE_CTRL_CLASS;
- /* You can neither read nor write these */
- *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
- *min = *max = *step = *def = 0;
- break;
- case V4L2_CID_BG_COLOR:
- *type = V4L2_CTRL_TYPE_INTEGER;
- *step = 1;
- *min = 0;
- /* Max is calculated as RGB888 that is 2^24 */
- *max = 0xFFFFFF;
- break;
- case V4L2_CID_FLASH_FAULT:
- case V4L2_CID_JPEG_ACTIVE_MARKER:
- case V4L2_CID_3A_LOCK:
- case V4L2_CID_AUTO_FOCUS_STATUS:
- case V4L2_CID_DV_TX_HOTPLUG:
- case V4L2_CID_DV_TX_RXSENSE:
- case V4L2_CID_DV_TX_EDID_PRESENT:
- case V4L2_CID_DV_RX_POWER_PRESENT:
- *type = V4L2_CTRL_TYPE_BITMASK;
- break;
- case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
- case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
- *type = V4L2_CTRL_TYPE_INTEGER;
- *flags |= V4L2_CTRL_FLAG_READ_ONLY;
- break;
- case V4L2_CID_MPEG_VIDEO_DEC_PTS:
- *type = V4L2_CTRL_TYPE_INTEGER64;
- *flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY;
- *min = *def = 0;
- *max = 0x1ffffffffLL;
- *step = 1;
- break;
- case V4L2_CID_MPEG_VIDEO_DEC_FRAME:
- *type = V4L2_CTRL_TYPE_INTEGER64;
- *flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY;
- *min = *def = 0;
- *max = 0x7fffffffffffffffLL;
- *step = 1;
- break;
- case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR:
- *type = V4L2_CTRL_TYPE_INTEGER64;
- *min = 0;
- /* default for 8 bit black, luma is 16, chroma is 128 */
- *def = 0x8000800010LL;
- *max = 0xffffffffffffLL;
- *step = 1;
- break;
- case V4L2_CID_PIXEL_RATE:
- *type = V4L2_CTRL_TYPE_INTEGER64;
- *flags |= V4L2_CTRL_FLAG_READ_ONLY;
- break;
- case V4L2_CID_DETECT_MD_REGION_GRID:
- *type = V4L2_CTRL_TYPE_U8;
- break;
- case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
- *type = V4L2_CTRL_TYPE_U16;
- break;
- case V4L2_CID_RDS_TX_ALT_FREQS:
- *type = V4L2_CTRL_TYPE_U32;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS:
- *type = V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION:
- *type = V4L2_CTRL_TYPE_MPEG2_QUANTIZATION;
- break;
- case V4L2_CID_STATELESS_FWHT_PARAMS:
- *type = V4L2_CTRL_TYPE_FWHT_PARAMS;
- break;
- case V4L2_CID_STATELESS_H264_SPS:
- *type = V4L2_CTRL_TYPE_H264_SPS;
- break;
- case V4L2_CID_STATELESS_H264_PPS:
- *type = V4L2_CTRL_TYPE_H264_PPS;
- break;
- case V4L2_CID_STATELESS_H264_SCALING_MATRIX:
- *type = V4L2_CTRL_TYPE_H264_SCALING_MATRIX;
- break;
- case V4L2_CID_STATELESS_H264_SLICE_PARAMS:
- *type = V4L2_CTRL_TYPE_H264_SLICE_PARAMS;
- break;
- case V4L2_CID_STATELESS_H264_DECODE_PARAMS:
- *type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS;
- break;
- case V4L2_CID_STATELESS_H264_PRED_WEIGHTS:
- *type = V4L2_CTRL_TYPE_H264_PRED_WEIGHTS;
- break;
- case V4L2_CID_STATELESS_VP8_FRAME:
- *type = V4L2_CTRL_TYPE_VP8_FRAME;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_SPS:
- *type = V4L2_CTRL_TYPE_HEVC_SPS;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_PPS:
- *type = V4L2_CTRL_TYPE_HEVC_PPS;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS:
- *type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS;
- break;
- case V4L2_CID_UNIT_CELL_SIZE:
- *type = V4L2_CTRL_TYPE_AREA;
- *flags |= V4L2_CTRL_FLAG_READ_ONLY;
- break;
- case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO:
- *type = V4L2_CTRL_TYPE_HDR10_CLL_INFO;
- break;
- case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY:
- *type = V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY;
- break;
- default:
- *type = V4L2_CTRL_TYPE_INTEGER;
- break;
- }
- switch (id) {
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- case V4L2_CID_MPEG_AUDIO_MODE:
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- case V4L2_CID_MPEG_VIDEO_B_FRAMES:
- case V4L2_CID_MPEG_STREAM_TYPE:
- *flags |= V4L2_CTRL_FLAG_UPDATE;
- break;
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_BRIGHTNESS:
- case V4L2_CID_CONTRAST:
- case V4L2_CID_SATURATION:
- case V4L2_CID_HUE:
- case V4L2_CID_RED_BALANCE:
- case V4L2_CID_BLUE_BALANCE:
- case V4L2_CID_GAMMA:
- case V4L2_CID_SHARPNESS:
- case V4L2_CID_CHROMA_GAIN:
- case V4L2_CID_RDS_TX_DEVIATION:
- case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
- case V4L2_CID_AUDIO_LIMITER_DEVIATION:
- case V4L2_CID_AUDIO_COMPRESSION_GAIN:
- case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
- case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
- case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
- case V4L2_CID_PILOT_TONE_DEVIATION:
- case V4L2_CID_PILOT_TONE_FREQUENCY:
- case V4L2_CID_TUNE_POWER_LEVEL:
- case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
- case V4L2_CID_RF_TUNER_RF_GAIN:
- case V4L2_CID_RF_TUNER_LNA_GAIN:
- case V4L2_CID_RF_TUNER_MIXER_GAIN:
- case V4L2_CID_RF_TUNER_IF_GAIN:
- case V4L2_CID_RF_TUNER_BANDWIDTH:
- case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
- *flags |= V4L2_CTRL_FLAG_SLIDER;
- break;
- case V4L2_CID_PAN_RELATIVE:
- case V4L2_CID_TILT_RELATIVE:
- case V4L2_CID_FOCUS_RELATIVE:
- case V4L2_CID_IRIS_RELATIVE:
- case V4L2_CID_ZOOM_RELATIVE:
- *flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
- V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
- break;
- case V4L2_CID_FLASH_STROBE_STATUS:
- case V4L2_CID_AUTO_FOCUS_STATUS:
- case V4L2_CID_FLASH_READY:
- case V4L2_CID_DV_TX_HOTPLUG:
- case V4L2_CID_DV_TX_RXSENSE:
- case V4L2_CID_DV_TX_EDID_PRESENT:
- case V4L2_CID_DV_RX_POWER_PRESENT:
- case V4L2_CID_DV_RX_IT_CONTENT_TYPE:
- case V4L2_CID_RDS_RX_PTY:
- case V4L2_CID_RDS_RX_PS_NAME:
- case V4L2_CID_RDS_RX_RADIO_TEXT:
- case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT:
- case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM:
- case V4L2_CID_RDS_RX_MUSIC_SPEECH:
- case V4L2_CID_CAMERA_ORIENTATION:
- case V4L2_CID_CAMERA_SENSOR_ROTATION:
- *flags |= V4L2_CTRL_FLAG_READ_ONLY;
- break;
- case V4L2_CID_RF_TUNER_PLL_LOCK:
- *flags |= V4L2_CTRL_FLAG_VOLATILE;
- break;
- }
-}
-EXPORT_SYMBOL(v4l2_ctrl_fill);
-
-static u32 user_flags(const struct v4l2_ctrl *ctrl)
-{
- u32 flags = ctrl->flags;
-
- if (ctrl->is_ptr)
- flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
-
- return flags;
-}
-
-static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes)
-{
- memset(ev, 0, sizeof(*ev));
- ev->type = V4L2_EVENT_CTRL;
- ev->id = ctrl->id;
- ev->u.ctrl.changes = changes;
- ev->u.ctrl.type = ctrl->type;
- ev->u.ctrl.flags = user_flags(ctrl);
- if (ctrl->is_ptr)
- ev->u.ctrl.value64 = 0;
- else
- ev->u.ctrl.value64 = *ctrl->p_cur.p_s64;
- ev->u.ctrl.minimum = ctrl->minimum;
- ev->u.ctrl.maximum = ctrl->maximum;
- if (ctrl->type == V4L2_CTRL_TYPE_MENU
- || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
- ev->u.ctrl.step = 1;
- else
- ev->u.ctrl.step = ctrl->step;
- ev->u.ctrl.default_value = ctrl->default_value;
-}
-
-static void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
-{
- struct v4l2_event ev;
- struct v4l2_subscribed_event *sev;
-
- if (list_empty(&ctrl->ev_subs))
- return;
- fill_event(&ev, ctrl, changes);
-
- list_for_each_entry(sev, &ctrl->ev_subs, node)
- if (sev->fh != fh ||
- (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK))
- v4l2_event_queue_fh(sev->fh, &ev);
-}
-
-static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx,
- union v4l2_ctrl_ptr ptr1,
- union v4l2_ctrl_ptr ptr2)
-{
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_BUTTON:
- return false;
- case V4L2_CTRL_TYPE_STRING:
- idx *= ctrl->elem_size;
- /* strings are always 0-terminated */
- return !strcmp(ptr1.p_char + idx, ptr2.p_char + idx);
- case V4L2_CTRL_TYPE_INTEGER64:
- return ptr1.p_s64[idx] == ptr2.p_s64[idx];
- case V4L2_CTRL_TYPE_U8:
- return ptr1.p_u8[idx] == ptr2.p_u8[idx];
- case V4L2_CTRL_TYPE_U16:
- return ptr1.p_u16[idx] == ptr2.p_u16[idx];
- case V4L2_CTRL_TYPE_U32:
- return ptr1.p_u32[idx] == ptr2.p_u32[idx];
- default:
- if (ctrl->is_int)
- return ptr1.p_s32[idx] == ptr2.p_s32[idx];
- idx *= ctrl->elem_size;
- return !memcmp(ptr1.p_const + idx, ptr2.p_const + idx,
- ctrl->elem_size);
- }
-}
-
-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;
- struct v4l2_ctrl_vp8_frame *p_vp8_frame;
- struct v4l2_ctrl_fwht_params *p_fwht_params;
- void *p = ptr.p + idx * ctrl->elem_size;
-
- if (ctrl->p_def.p_const)
- memcpy(p, ctrl->p_def.p_const, ctrl->elem_size);
- else
- 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;
- case V4L2_CTRL_TYPE_VP8_FRAME:
- p_vp8_frame = p;
- p_vp8_frame->num_dct_parts = 1;
- break;
- case V4L2_CTRL_TYPE_FWHT_PARAMS:
- p_fwht_params = p;
- p_fwht_params->version = V4L2_FWHT_VERSION;
- p_fwht_params->width = 1280;
- p_fwht_params->height = 720;
- p_fwht_params->flags = V4L2_FWHT_FL_PIXENC_YUV |
- (2 << V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET);
- break;
- }
-}
-
-static void std_init(const struct v4l2_ctrl *ctrl, u32 idx,
- union v4l2_ctrl_ptr ptr)
-{
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_STRING:
- idx *= ctrl->elem_size;
- memset(ptr.p_char + idx, ' ', ctrl->minimum);
- ptr.p_char[idx + ctrl->minimum] = '\0';
- break;
- case V4L2_CTRL_TYPE_INTEGER64:
- ptr.p_s64[idx] = ctrl->default_value;
- break;
- case V4L2_CTRL_TYPE_INTEGER:
- case V4L2_CTRL_TYPE_INTEGER_MENU:
- case V4L2_CTRL_TYPE_MENU:
- case V4L2_CTRL_TYPE_BITMASK:
- 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;
- case V4L2_CTRL_TYPE_U16:
- ptr.p_u16[idx] = ctrl->default_value;
- break;
- case V4L2_CTRL_TYPE_U32:
- ptr.p_u32[idx] = ctrl->default_value;
- break;
- default:
- std_init_compound(ctrl, idx, ptr);
- break;
- }
-}
-
-static void std_log(const struct v4l2_ctrl *ctrl)
-{
- union v4l2_ctrl_ptr ptr = ctrl->p_cur;
-
- if (ctrl->is_array) {
- unsigned i;
-
- for (i = 0; i < ctrl->nr_of_dims; i++)
- pr_cont("[%u]", ctrl->dims[i]);
- pr_cont(" ");
- }
-
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_INTEGER:
- pr_cont("%d", *ptr.p_s32);
- break;
- case V4L2_CTRL_TYPE_BOOLEAN:
- pr_cont("%s", *ptr.p_s32 ? "true" : "false");
- break;
- case V4L2_CTRL_TYPE_MENU:
- pr_cont("%s", ctrl->qmenu[*ptr.p_s32]);
- break;
- case V4L2_CTRL_TYPE_INTEGER_MENU:
- pr_cont("%lld", ctrl->qmenu_int[*ptr.p_s32]);
- break;
- case V4L2_CTRL_TYPE_BITMASK:
- pr_cont("0x%08x", *ptr.p_s32);
- break;
- case V4L2_CTRL_TYPE_INTEGER64:
- pr_cont("%lld", *ptr.p_s64);
- break;
- case V4L2_CTRL_TYPE_STRING:
- pr_cont("%s", ptr.p_char);
- break;
- case V4L2_CTRL_TYPE_U8:
- pr_cont("%u", (unsigned)*ptr.p_u8);
- break;
- case V4L2_CTRL_TYPE_U16:
- pr_cont("%u", (unsigned)*ptr.p_u16);
- break;
- case V4L2_CTRL_TYPE_U32:
- pr_cont("%u", (unsigned)*ptr.p_u32);
- break;
- case V4L2_CTRL_TYPE_H264_SPS:
- pr_cont("H264_SPS");
- break;
- case V4L2_CTRL_TYPE_H264_PPS:
- pr_cont("H264_PPS");
- break;
- case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
- pr_cont("H264_SCALING_MATRIX");
- break;
- case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
- pr_cont("H264_SLICE_PARAMS");
- break;
- case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
- pr_cont("H264_DECODE_PARAMS");
- break;
- case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
- pr_cont("H264_PRED_WEIGHTS");
- break;
- case V4L2_CTRL_TYPE_FWHT_PARAMS:
- pr_cont("FWHT_PARAMS");
- break;
- case V4L2_CTRL_TYPE_VP8_FRAME:
- pr_cont("VP8_FRAME");
- break;
- case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
- pr_cont("HDR10_CLL_INFO");
- break;
- case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
- pr_cont("HDR10_MASTERING_DISPLAY");
- break;
- default:
- pr_cont("unknown type %d", ctrl->type);
- break;
- }
-}
-
-/*
- * Round towards the closest legal value. Be careful when we are
- * close to the maximum range of the control type to prevent
- * wrap-arounds.
- */
-#define ROUND_TO_RANGE(val, offset_type, ctrl) \
-({ \
- offset_type offset; \
- if ((ctrl)->maximum >= 0 && \
- val >= (ctrl)->maximum - (s32)((ctrl)->step / 2)) \
- val = (ctrl)->maximum; \
- else \
- val += (s32)((ctrl)->step / 2); \
- val = clamp_t(typeof(val), val, \
- (ctrl)->minimum, (ctrl)->maximum); \
- offset = (val) - (ctrl)->minimum; \
- offset = (ctrl)->step * (offset / (u32)(ctrl)->step); \
- val = (ctrl)->minimum + offset; \
- 0; \
-})
-
-/* Validate a new control */
-
-#define zero_padding(s) \
- memset(&(s).padding, 0, sizeof((s).padding))
-#define zero_reserved(s) \
- memset(&(s).reserved, 0, sizeof((s).reserved))
-
-/*
- * Compound controls validation requires setting unused fields/flags to zero
- * in order to properly detect unchanged controls with std_equal's memcmp.
- */
-static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
- union v4l2_ctrl_ptr ptr)
-{
- struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params;
- struct v4l2_ctrl_vp8_frame *p_vp8_frame;
- struct v4l2_ctrl_fwht_params *p_fwht_params;
- struct v4l2_ctrl_h264_sps *p_h264_sps;
- struct v4l2_ctrl_h264_pps *p_h264_pps;
- struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights;
- struct v4l2_ctrl_h264_slice_params *p_h264_slice_params;
- struct v4l2_ctrl_h264_decode_params *p_h264_dec_params;
- struct v4l2_ctrl_hevc_sps *p_hevc_sps;
- struct v4l2_ctrl_hevc_pps *p_hevc_pps;
- struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params;
- struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering;
- struct v4l2_area *area;
- void *p = ptr.p + idx * ctrl->elem_size;
- unsigned int i;
-
- switch ((u32)ctrl->type) {
- case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS:
- p_mpeg2_slice_params = p;
-
- switch (p_mpeg2_slice_params->sequence.chroma_format) {
- case 1: /* 4:2:0 */
- case 2: /* 4:2:2 */
- case 3: /* 4:4:4 */
- break;
- default:
- return -EINVAL;
- }
-
- switch (p_mpeg2_slice_params->picture.intra_dc_precision) {
- case 0: /* 8 bits */
- case 1: /* 9 bits */
- case 2: /* 10 bits */
- case 3: /* 11 bits */
- break;
- default:
- return -EINVAL;
- }
-
- switch (p_mpeg2_slice_params->picture.picture_structure) {
- case 1: /* interlaced top field */
- case 2: /* interlaced bottom field */
- case 3: /* progressive */
- break;
- default:
- return -EINVAL;
- }
-
- switch (p_mpeg2_slice_params->picture.picture_coding_type) {
- case V4L2_MPEG2_PICTURE_CODING_TYPE_I:
- case V4L2_MPEG2_PICTURE_CODING_TYPE_P:
- case V4L2_MPEG2_PICTURE_CODING_TYPE_B:
- break;
- default:
- return -EINVAL;
- }
-
- break;
-
- case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION:
- break;
-
- case V4L2_CTRL_TYPE_FWHT_PARAMS:
- p_fwht_params = p;
- if (p_fwht_params->version < V4L2_FWHT_VERSION)
- return -EINVAL;
- if (!p_fwht_params->width || !p_fwht_params->height)
- return -EINVAL;
- break;
-
- case V4L2_CTRL_TYPE_H264_SPS:
- p_h264_sps = p;
-
- /* Some syntax elements are only conditionally valid */
- if (p_h264_sps->pic_order_cnt_type != 0) {
- p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 = 0;
- } else if (p_h264_sps->pic_order_cnt_type != 1) {
- p_h264_sps->num_ref_frames_in_pic_order_cnt_cycle = 0;
- p_h264_sps->offset_for_non_ref_pic = 0;
- p_h264_sps->offset_for_top_to_bottom_field = 0;
- memset(&p_h264_sps->offset_for_ref_frame, 0,
- sizeof(p_h264_sps->offset_for_ref_frame));
- }
-
- if (!V4L2_H264_SPS_HAS_CHROMA_FORMAT(p_h264_sps)) {
- p_h264_sps->chroma_format_idc = 1;
- p_h264_sps->bit_depth_luma_minus8 = 0;
- p_h264_sps->bit_depth_chroma_minus8 = 0;
-
- p_h264_sps->flags &=
- ~V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS;
-
- if (p_h264_sps->chroma_format_idc < 3)
- p_h264_sps->flags &=
- ~V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE;
- }
-
- if (p_h264_sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)
- p_h264_sps->flags &=
- ~V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD;
-
- /*
- * Chroma 4:2:2 format require at least High 4:2:2 profile.
- *
- * The H264 specification and well-known parser implementations
- * use profile-idc values directly, as that is clearer and
- * less ambiguous. We do the same here.
- */
- if (p_h264_sps->profile_idc < 122 &&
- p_h264_sps->chroma_format_idc > 1)
- return -EINVAL;
- /* Chroma 4:4:4 format require at least High 4:2:2 profile */
- if (p_h264_sps->profile_idc < 244 &&
- p_h264_sps->chroma_format_idc > 2)
- return -EINVAL;
- if (p_h264_sps->chroma_format_idc > 3)
- return -EINVAL;
-
- if (p_h264_sps->bit_depth_luma_minus8 > 6)
- return -EINVAL;
- if (p_h264_sps->bit_depth_chroma_minus8 > 6)
- return -EINVAL;
- if (p_h264_sps->log2_max_frame_num_minus4 > 12)
- return -EINVAL;
- if (p_h264_sps->pic_order_cnt_type > 2)
- return -EINVAL;
- if (p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 > 12)
- return -EINVAL;
- if (p_h264_sps->max_num_ref_frames > V4L2_H264_REF_LIST_LEN)
- return -EINVAL;
- break;
-
- case V4L2_CTRL_TYPE_H264_PPS:
- p_h264_pps = p;
-
- if (p_h264_pps->num_slice_groups_minus1 > 7)
- return -EINVAL;
- if (p_h264_pps->num_ref_idx_l0_default_active_minus1 >
- (V4L2_H264_REF_LIST_LEN - 1))
- return -EINVAL;
- if (p_h264_pps->num_ref_idx_l1_default_active_minus1 >
- (V4L2_H264_REF_LIST_LEN - 1))
- return -EINVAL;
- if (p_h264_pps->weighted_bipred_idc > 2)
- return -EINVAL;
- /*
- * pic_init_qp_minus26 shall be in the range of
- * -(26 + QpBdOffset_y) to +25, inclusive,
- * where QpBdOffset_y is 6 * bit_depth_luma_minus8
- */
- if (p_h264_pps->pic_init_qp_minus26 < -62 ||
- p_h264_pps->pic_init_qp_minus26 > 25)
- return -EINVAL;
- if (p_h264_pps->pic_init_qs_minus26 < -26 ||
- p_h264_pps->pic_init_qs_minus26 > 25)
- return -EINVAL;
- if (p_h264_pps->chroma_qp_index_offset < -12 ||
- p_h264_pps->chroma_qp_index_offset > 12)
- return -EINVAL;
- if (p_h264_pps->second_chroma_qp_index_offset < -12 ||
- p_h264_pps->second_chroma_qp_index_offset > 12)
- return -EINVAL;
- break;
-
- case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
- break;
-
- case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
- p_h264_pred_weights = p;
-
- if (p_h264_pred_weights->luma_log2_weight_denom > 7)
- return -EINVAL;
- if (p_h264_pred_weights->chroma_log2_weight_denom > 7)
- return -EINVAL;
- break;
-
- case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
- p_h264_slice_params = p;
-
- if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B)
- p_h264_slice_params->flags &=
- ~V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED;
-
- if (p_h264_slice_params->colour_plane_id > 2)
- return -EINVAL;
- if (p_h264_slice_params->cabac_init_idc > 2)
- return -EINVAL;
- if (p_h264_slice_params->disable_deblocking_filter_idc > 2)
- return -EINVAL;
- if (p_h264_slice_params->slice_alpha_c0_offset_div2 < -6 ||
- p_h264_slice_params->slice_alpha_c0_offset_div2 > 6)
- return -EINVAL;
- if (p_h264_slice_params->slice_beta_offset_div2 < -6 ||
- p_h264_slice_params->slice_beta_offset_div2 > 6)
- return -EINVAL;
-
- if (p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_I ||
- p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_SI)
- p_h264_slice_params->num_ref_idx_l0_active_minus1 = 0;
- if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B)
- p_h264_slice_params->num_ref_idx_l1_active_minus1 = 0;
-
- if (p_h264_slice_params->num_ref_idx_l0_active_minus1 >
- (V4L2_H264_REF_LIST_LEN - 1))
- return -EINVAL;
- if (p_h264_slice_params->num_ref_idx_l1_active_minus1 >
- (V4L2_H264_REF_LIST_LEN - 1))
- return -EINVAL;
- zero_reserved(*p_h264_slice_params);
- break;
-
- case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
- p_h264_dec_params = p;
-
- if (p_h264_dec_params->nal_ref_idc > 3)
- return -EINVAL;
- for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
- struct v4l2_h264_dpb_entry *dpb_entry =
- &p_h264_dec_params->dpb[i];
-
- zero_reserved(*dpb_entry);
- }
- zero_reserved(*p_h264_dec_params);
- break;
-
- case V4L2_CTRL_TYPE_VP8_FRAME:
- p_vp8_frame = p;
-
- switch (p_vp8_frame->num_dct_parts) {
- case 1:
- case 2:
- case 4:
- case 8:
- break;
- default:
- return -EINVAL;
- }
- zero_padding(p_vp8_frame->segment);
- zero_padding(p_vp8_frame->lf);
- zero_padding(p_vp8_frame->quant);
- zero_padding(p_vp8_frame->entropy);
- zero_padding(p_vp8_frame->coder_state);
- break;
-
- case V4L2_CTRL_TYPE_HEVC_SPS:
- p_hevc_sps = p;
-
- if (!(p_hevc_sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED)) {
- p_hevc_sps->pcm_sample_bit_depth_luma_minus1 = 0;
- p_hevc_sps->pcm_sample_bit_depth_chroma_minus1 = 0;
- p_hevc_sps->log2_min_pcm_luma_coding_block_size_minus3 = 0;
- p_hevc_sps->log2_diff_max_min_pcm_luma_coding_block_size = 0;
- }
-
- if (!(p_hevc_sps->flags &
- V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT))
- p_hevc_sps->num_long_term_ref_pics_sps = 0;
- break;
-
- case V4L2_CTRL_TYPE_HEVC_PPS:
- p_hevc_pps = p;
-
- if (!(p_hevc_pps->flags &
- V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED))
- p_hevc_pps->diff_cu_qp_delta_depth = 0;
-
- if (!(p_hevc_pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED)) {
- p_hevc_pps->num_tile_columns_minus1 = 0;
- p_hevc_pps->num_tile_rows_minus1 = 0;
- memset(&p_hevc_pps->column_width_minus1, 0,
- sizeof(p_hevc_pps->column_width_minus1));
- memset(&p_hevc_pps->row_height_minus1, 0,
- sizeof(p_hevc_pps->row_height_minus1));
-
- p_hevc_pps->flags &=
- ~V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED;
- }
-
- if (p_hevc_pps->flags &
- V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER) {
- p_hevc_pps->pps_beta_offset_div2 = 0;
- p_hevc_pps->pps_tc_offset_div2 = 0;
- }
-
- zero_padding(*p_hevc_pps);
- break;
-
- case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
- p_hevc_slice_params = p;
-
- if (p_hevc_slice_params->num_active_dpb_entries >
- V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
- return -EINVAL;
-
- zero_padding(p_hevc_slice_params->pred_weight_table);
-
- for (i = 0; i < p_hevc_slice_params->num_active_dpb_entries;
- i++) {
- struct v4l2_hevc_dpb_entry *dpb_entry =
- &p_hevc_slice_params->dpb[i];
-
- zero_padding(*dpb_entry);
- }
-
- zero_padding(*p_hevc_slice_params);
- break;
-
- case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
- break;
-
- case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
- p_hdr10_mastering = p;
-
- for (i = 0; i < 3; ++i) {
- if (p_hdr10_mastering->display_primaries_x[i] <
- V4L2_HDR10_MASTERING_PRIMARIES_X_LOW ||
- p_hdr10_mastering->display_primaries_x[i] >
- V4L2_HDR10_MASTERING_PRIMARIES_X_HIGH ||
- p_hdr10_mastering->display_primaries_y[i] <
- V4L2_HDR10_MASTERING_PRIMARIES_Y_LOW ||
- p_hdr10_mastering->display_primaries_y[i] >
- V4L2_HDR10_MASTERING_PRIMARIES_Y_HIGH)
- return -EINVAL;
- }
-
- if (p_hdr10_mastering->white_point_x <
- V4L2_HDR10_MASTERING_WHITE_POINT_X_LOW ||
- p_hdr10_mastering->white_point_x >
- V4L2_HDR10_MASTERING_WHITE_POINT_X_HIGH ||
- p_hdr10_mastering->white_point_y <
- V4L2_HDR10_MASTERING_WHITE_POINT_Y_LOW ||
- p_hdr10_mastering->white_point_y >
- V4L2_HDR10_MASTERING_WHITE_POINT_Y_HIGH)
- return -EINVAL;
-
- if (p_hdr10_mastering->max_display_mastering_luminance <
- V4L2_HDR10_MASTERING_MAX_LUMA_LOW ||
- p_hdr10_mastering->max_display_mastering_luminance >
- V4L2_HDR10_MASTERING_MAX_LUMA_HIGH ||
- p_hdr10_mastering->min_display_mastering_luminance <
- V4L2_HDR10_MASTERING_MIN_LUMA_LOW ||
- p_hdr10_mastering->min_display_mastering_luminance >
- V4L2_HDR10_MASTERING_MIN_LUMA_HIGH)
- return -EINVAL;
-
- /* The following restriction comes from ITU-T Rec. H.265 spec */
- if (p_hdr10_mastering->max_display_mastering_luminance ==
- V4L2_HDR10_MASTERING_MAX_LUMA_LOW &&
- p_hdr10_mastering->min_display_mastering_luminance ==
- V4L2_HDR10_MASTERING_MIN_LUMA_HIGH)
- return -EINVAL;
-
- break;
-
- case V4L2_CTRL_TYPE_AREA:
- area = p;
- if (!area->width || !area->height)
- return -EINVAL;
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
- union v4l2_ctrl_ptr ptr)
-{
- size_t len;
- u64 offset;
- s64 val;
-
- switch ((u32)ctrl->type) {
- case V4L2_CTRL_TYPE_INTEGER:
- return ROUND_TO_RANGE(ptr.p_s32[idx], u32, ctrl);
- case V4L2_CTRL_TYPE_INTEGER64:
- /*
- * We can't use the ROUND_TO_RANGE define here due to
- * the u64 divide that needs special care.
- */
- val = ptr.p_s64[idx];
- if (ctrl->maximum >= 0 && val >= ctrl->maximum - (s64)(ctrl->step / 2))
- val = ctrl->maximum;
- else
- val += (s64)(ctrl->step / 2);
- val = clamp_t(s64, val, ctrl->minimum, ctrl->maximum);
- offset = val - ctrl->minimum;
- do_div(offset, ctrl->step);
- ptr.p_s64[idx] = ctrl->minimum + offset * ctrl->step;
- return 0;
- case V4L2_CTRL_TYPE_U8:
- return ROUND_TO_RANGE(ptr.p_u8[idx], u8, ctrl);
- case V4L2_CTRL_TYPE_U16:
- return ROUND_TO_RANGE(ptr.p_u16[idx], u16, ctrl);
- case V4L2_CTRL_TYPE_U32:
- return ROUND_TO_RANGE(ptr.p_u32[idx], u32, ctrl);
-
- case V4L2_CTRL_TYPE_BOOLEAN:
- ptr.p_s32[idx] = !!ptr.p_s32[idx];
- return 0;
-
- case V4L2_CTRL_TYPE_MENU:
- case V4L2_CTRL_TYPE_INTEGER_MENU:
- if (ptr.p_s32[idx] < ctrl->minimum || ptr.p_s32[idx] > ctrl->maximum)
- return -ERANGE;
- if (ptr.p_s32[idx] < BITS_PER_LONG_LONG &&
- (ctrl->menu_skip_mask & BIT_ULL(ptr.p_s32[idx])))
- return -EINVAL;
- if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
- ctrl->qmenu[ptr.p_s32[idx]][0] == '\0')
- return -EINVAL;
- return 0;
-
- case V4L2_CTRL_TYPE_BITMASK:
- ptr.p_s32[idx] &= ctrl->maximum;
- return 0;
-
- case V4L2_CTRL_TYPE_BUTTON:
- case V4L2_CTRL_TYPE_CTRL_CLASS:
- ptr.p_s32[idx] = 0;
- return 0;
-
- case V4L2_CTRL_TYPE_STRING:
- idx *= ctrl->elem_size;
- len = strlen(ptr.p_char + idx);
- if (len < ctrl->minimum)
- return -ERANGE;
- if ((len - (u32)ctrl->minimum) % (u32)ctrl->step)
- return -ERANGE;
- return 0;
-
- default:
- return std_validate_compound(ctrl, idx, ptr);
- }
-}
-
-static const struct v4l2_ctrl_type_ops std_type_ops = {
- .equal = std_equal,
- .init = std_init,
- .log = std_log,
- .validate = std_validate,
-};
-
-/* Helper function: copy the given control value back to the caller */
-static int ptr_to_user(struct v4l2_ext_control *c,
- struct v4l2_ctrl *ctrl,
- union v4l2_ctrl_ptr ptr)
-{
- u32 len;
-
- if (ctrl->is_ptr && !ctrl->is_string)
- return copy_to_user(c->ptr, ptr.p_const, c->size) ?
- -EFAULT : 0;
-
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_STRING:
- len = strlen(ptr.p_char);
- if (c->size < len + 1) {
- c->size = ctrl->elem_size;
- return -ENOSPC;
- }
- return copy_to_user(c->string, ptr.p_char, len + 1) ?
- -EFAULT : 0;
- case V4L2_CTRL_TYPE_INTEGER64:
- c->value64 = *ptr.p_s64;
- break;
- default:
- c->value = *ptr.p_s32;
- break;
- }
- return 0;
-}
-
-/* Helper function: copy the current control value back to the caller */
-static int cur_to_user(struct v4l2_ext_control *c,
- struct v4l2_ctrl *ctrl)
-{
- return ptr_to_user(c, ctrl, ctrl->p_cur);
-}
-
-/* Helper function: copy the new control value back to the caller */
-static int new_to_user(struct v4l2_ext_control *c,
- struct v4l2_ctrl *ctrl)
-{
- return ptr_to_user(c, ctrl, ctrl->p_new);
-}
-
-/* Helper function: copy the request value back to the caller */
-static int req_to_user(struct v4l2_ext_control *c,
- struct v4l2_ctrl_ref *ref)
-{
- return ptr_to_user(c, ref->ctrl, ref->p_req);
-}
-
-/* Helper function: copy the initial control value back to the caller */
-static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
-{
- int idx;
-
- for (idx = 0; idx < ctrl->elems; idx++)
- ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
-
- return ptr_to_user(c, ctrl, ctrl->p_new);
-}
-
-/* Helper function: copy the caller-provider value to the given control value */
-static int user_to_ptr(struct v4l2_ext_control *c,
- struct v4l2_ctrl *ctrl,
- union v4l2_ctrl_ptr ptr)
-{
- int ret;
- u32 size;
-
- ctrl->is_new = 1;
- if (ctrl->is_ptr && !ctrl->is_string) {
- unsigned idx;
-
- ret = copy_from_user(ptr.p, c->ptr, c->size) ? -EFAULT : 0;
- if (ret || !ctrl->is_array)
- return ret;
- for (idx = c->size / ctrl->elem_size; idx < ctrl->elems; idx++)
- ctrl->type_ops->init(ctrl, idx, ptr);
- return 0;
- }
-
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_INTEGER64:
- *ptr.p_s64 = c->value64;
- break;
- case V4L2_CTRL_TYPE_STRING:
- size = c->size;
- if (size == 0)
- return -ERANGE;
- if (size > ctrl->maximum + 1)
- size = ctrl->maximum + 1;
- ret = copy_from_user(ptr.p_char, c->string, size) ? -EFAULT : 0;
- if (!ret) {
- char last = ptr.p_char[size - 1];
-
- ptr.p_char[size - 1] = 0;
- /* If the string was longer than ctrl->maximum,
- then return an error. */
- if (strlen(ptr.p_char) == ctrl->maximum && last)
- return -ERANGE;
- }
- return ret;
- default:
- *ptr.p_s32 = c->value;
- break;
- }
- return 0;
-}
-
-/* Helper function: copy the caller-provider value as the new control value */
-static int user_to_new(struct v4l2_ext_control *c,
- struct v4l2_ctrl *ctrl)
-{
- return user_to_ptr(c, ctrl, ctrl->p_new);
-}
-
-/* Copy the one value to another. */
-static void ptr_to_ptr(struct v4l2_ctrl *ctrl,
- union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to)
-{
- if (ctrl == NULL)
- return;
- memcpy(to.p, from.p_const, ctrl->elems * ctrl->elem_size);
-}
-
-/* Copy the new value to the current value. */
-static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
-{
- bool changed;
-
- if (ctrl == NULL)
- return;
-
- /* has_changed is set by cluster_changed */
- changed = ctrl->has_changed;
- if (changed)
- ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur);
-
- if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
- /* Note: CH_FLAGS is only set for auto clusters. */
- ctrl->flags &=
- ~(V4L2_CTRL_FLAG_INACTIVE | V4L2_CTRL_FLAG_VOLATILE);
- if (!is_cur_manual(ctrl->cluster[0])) {
- ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- if (ctrl->cluster[0]->has_volatiles)
- ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
- }
- fh = NULL;
- }
- if (changed || ch_flags) {
- /* If a control was changed that was not one of the controls
- modified by the application, then send the event to all. */
- if (!ctrl->is_new)
- fh = NULL;
- send_event(fh, ctrl,
- (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) | ch_flags);
- if (ctrl->call_notify && changed && ctrl->handler->notify)
- ctrl->handler->notify(ctrl, ctrl->handler->notify_priv);
- }
-}
-
-/* Copy the current value to the new value */
-static void cur_to_new(struct v4l2_ctrl *ctrl)
-{
- if (ctrl == NULL)
- return;
- ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new);
-}
-
-/* Copy the new value to the request value */
-static void new_to_req(struct v4l2_ctrl_ref *ref)
-{
- if (!ref)
- return;
- ptr_to_ptr(ref->ctrl, ref->ctrl->p_new, ref->p_req);
- ref->valid_p_req = true;
-}
-
-/* Copy the current value to the request value */
-static void cur_to_req(struct v4l2_ctrl_ref *ref)
-{
- if (!ref)
- return;
- ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->p_req);
- ref->valid_p_req = true;
-}
-
-/* Copy the request value to the new value */
-static void req_to_new(struct v4l2_ctrl_ref *ref)
-{
- if (!ref)
- return;
- if (ref->valid_p_req)
- ptr_to_ptr(ref->ctrl, ref->p_req, ref->ctrl->p_new);
- else
- ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->ctrl->p_new);
-}
-
-/* Return non-zero if one or more of the controls in the cluster has a new
- value that differs from the current value. */
-static int cluster_changed(struct v4l2_ctrl *master)
-{
- bool changed = false;
- unsigned idx;
- int i;
-
- for (i = 0; i < master->ncontrols; i++) {
- struct v4l2_ctrl *ctrl = master->cluster[i];
- bool ctrl_changed = false;
-
- if (ctrl == NULL)
- continue;
-
- if (ctrl->flags & V4L2_CTRL_FLAG_EXECUTE_ON_WRITE)
- changed = ctrl_changed = true;
-
- /*
- * Set has_changed to false to avoid generating
- * the event V4L2_EVENT_CTRL_CH_VALUE
- */
- if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
- ctrl->has_changed = false;
- continue;
- }
-
- for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++)
- ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
- ctrl->p_cur, ctrl->p_new);
- ctrl->has_changed = ctrl_changed;
- changed |= ctrl->has_changed;
- }
- return changed;
-}
-
-/* Control range checking */
-static int check_range(enum v4l2_ctrl_type type,
- s64 min, s64 max, u64 step, s64 def)
-{
- switch (type) {
- case V4L2_CTRL_TYPE_BOOLEAN:
- if (step != 1 || max > 1 || min < 0)
- return -ERANGE;
- fallthrough;
- case V4L2_CTRL_TYPE_U8:
- case V4L2_CTRL_TYPE_U16:
- case V4L2_CTRL_TYPE_U32:
- case V4L2_CTRL_TYPE_INTEGER:
- case V4L2_CTRL_TYPE_INTEGER64:
- if (step == 0 || min > max || def < min || def > max)
- return -ERANGE;
- return 0;
- case V4L2_CTRL_TYPE_BITMASK:
- if (step || min || !max || (def & ~max))
- return -ERANGE;
- return 0;
- case V4L2_CTRL_TYPE_MENU:
- case V4L2_CTRL_TYPE_INTEGER_MENU:
- if (min > max || def < min || def > max)
- return -ERANGE;
- /* Note: step == menu_skip_mask for menu controls.
- So here we check if the default value is masked out. */
- if (step && ((1 << def) & step))
- return -EINVAL;
- return 0;
- case V4L2_CTRL_TYPE_STRING:
- if (min > max || min < 0 || step < 1 || def)
- return -ERANGE;
- return 0;
- default:
- return 0;
- }
-}
-
-/* Validate a new control */
-static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new)
-{
- unsigned idx;
- int err = 0;
-
- for (idx = 0; !err && idx < ctrl->elems; idx++)
- err = ctrl->type_ops->validate(ctrl, idx, p_new);
- return err;
-}
-
-static inline u32 node2id(struct list_head *node)
-{
- return list_entry(node, struct v4l2_ctrl_ref, node)->ctrl->id;
-}
-
-/* Set the handler's error code if it wasn't set earlier already */
-static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err)
-{
- if (hdl->error == 0)
- hdl->error = err;
- return err;
-}
-
-/* Initialize the handler */
-int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl,
- unsigned nr_of_controls_hint,
- struct lock_class_key *key, const char *name)
-{
- mutex_init(&hdl->_lock);
- hdl->lock = &hdl->_lock;
- lockdep_set_class_and_name(hdl->lock, key, name);
- INIT_LIST_HEAD(&hdl->ctrls);
- INIT_LIST_HEAD(&hdl->ctrl_refs);
- INIT_LIST_HEAD(&hdl->requests);
- INIT_LIST_HEAD(&hdl->requests_queued);
- hdl->request_is_queued = false;
- hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;
- hdl->buckets = kvmalloc_array(hdl->nr_of_buckets,
- sizeof(hdl->buckets[0]),
- GFP_KERNEL | __GFP_ZERO);
- hdl->error = hdl->buckets ? 0 : -ENOMEM;
- media_request_object_init(&hdl->req_obj);
- return hdl->error;
-}
-EXPORT_SYMBOL(v4l2_ctrl_handler_init_class);
-
-/* Free all controls and control refs */
-void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
-{
- struct v4l2_ctrl_ref *ref, *next_ref;
- struct v4l2_ctrl *ctrl, *next_ctrl;
- struct v4l2_subscribed_event *sev, *next_sev;
-
- if (hdl == NULL || hdl->buckets == NULL)
- return;
-
- /*
- * If the main handler is freed and it is used by handler objects in
- * outstanding requests, then unbind and put those objects before
- * freeing the main handler.
- *
- * The main handler can be identified by having a NULL ops pointer in
- * the request object.
- */
- if (!hdl->req_obj.ops && !list_empty(&hdl->requests)) {
- struct v4l2_ctrl_handler *req, *next_req;
-
- list_for_each_entry_safe(req, next_req, &hdl->requests, requests) {
- media_request_object_unbind(&req->req_obj);
- media_request_object_put(&req->req_obj);
- }
- }
- mutex_lock(hdl->lock);
- /* Free all nodes */
- list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) {
- list_del(&ref->node);
- kfree(ref);
- }
- /* Free all controls owned by the handler */
- list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) {
- list_del(&ctrl->node);
- list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
- list_del(&sev->node);
- kvfree(ctrl);
- }
- kvfree(hdl->buckets);
- hdl->buckets = NULL;
- hdl->cached = NULL;
- hdl->error = 0;
- mutex_unlock(hdl->lock);
- mutex_destroy(&hdl->_lock);
-}
-EXPORT_SYMBOL(v4l2_ctrl_handler_free);
-
-/* For backwards compatibility: V4L2_CID_PRIVATE_BASE should no longer
- be used except in G_CTRL, S_CTRL, QUERYCTRL and QUERYMENU when dealing
- with applications that do not use the NEXT_CTRL flag.
-
- We just find the n-th private user control. It's O(N), but that should not
- be an issue in this particular case. */
-static struct v4l2_ctrl_ref *find_private_ref(
- struct v4l2_ctrl_handler *hdl, u32 id)
-{
- struct v4l2_ctrl_ref *ref;
-
- id -= V4L2_CID_PRIVATE_BASE;
- list_for_each_entry(ref, &hdl->ctrl_refs, node) {
- /* Search for private user controls that are compatible with
- VIDIOC_G/S_CTRL. */
- if (V4L2_CTRL_ID2WHICH(ref->ctrl->id) == V4L2_CTRL_CLASS_USER &&
- V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) {
- if (!ref->ctrl->is_int)
- continue;
- if (id == 0)
- return ref;
- id--;
- }
- }
- return NULL;
-}
-
-/* Find a control with the given ID. */
-static struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id)
-{
- struct v4l2_ctrl_ref *ref;
- int bucket;
-
- id &= V4L2_CTRL_ID_MASK;
-
- /* Old-style private controls need special handling */
- if (id >= V4L2_CID_PRIVATE_BASE)
- return find_private_ref(hdl, id);
- bucket = id % hdl->nr_of_buckets;
-
- /* Simple optimization: cache the last control found */
- if (hdl->cached && hdl->cached->ctrl->id == id)
- return hdl->cached;
-
- /* Not in cache, search the hash */
- ref = hdl->buckets ? hdl->buckets[bucket] : NULL;
- while (ref && ref->ctrl->id != id)
- ref = ref->next;
-
- if (ref)
- hdl->cached = ref; /* cache it! */
- return ref;
-}
-
-/* Find a control with the given ID. Take the handler's lock first. */
-static struct v4l2_ctrl_ref *find_ref_lock(
- struct v4l2_ctrl_handler *hdl, u32 id)
-{
- struct v4l2_ctrl_ref *ref = NULL;
-
- if (hdl) {
- mutex_lock(hdl->lock);
- ref = find_ref(hdl, id);
- mutex_unlock(hdl->lock);
- }
- return ref;
-}
-
-/* Find a control with the given ID. */
-struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
-{
- struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
-
- return ref ? ref->ctrl : NULL;
-}
-EXPORT_SYMBOL(v4l2_ctrl_find);
-
-/* Allocate a new v4l2_ctrl_ref and hook it into the handler. */
-static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
- struct v4l2_ctrl *ctrl,
- struct v4l2_ctrl_ref **ctrl_ref,
- bool from_other_dev, bool allocate_req)
-{
- struct v4l2_ctrl_ref *ref;
- struct v4l2_ctrl_ref *new_ref;
- u32 id = ctrl->id;
- u32 class_ctrl = V4L2_CTRL_ID2WHICH(id) | 1;
- int bucket = id % hdl->nr_of_buckets; /* which bucket to use */
- unsigned int size_extra_req = 0;
-
- if (ctrl_ref)
- *ctrl_ref = NULL;
-
- /*
- * Automatically add the control class if it is not yet present and
- * the new control is not a compound control.
- */
- if (ctrl->type < V4L2_CTRL_COMPOUND_TYPES &&
- id != class_ctrl && find_ref_lock(hdl, class_ctrl) == NULL)
- if (!v4l2_ctrl_new_std(hdl, NULL, class_ctrl, 0, 0, 0, 0))
- return hdl->error;
-
- if (hdl->error)
- return hdl->error;
-
- if (allocate_req)
- size_extra_req = ctrl->elems * ctrl->elem_size;
- new_ref = kzalloc(sizeof(*new_ref) + size_extra_req, GFP_KERNEL);
- if (!new_ref)
- return handler_set_err(hdl, -ENOMEM);
- new_ref->ctrl = ctrl;
- new_ref->from_other_dev = from_other_dev;
- if (size_extra_req)
- new_ref->p_req.p = &new_ref[1];
-
- INIT_LIST_HEAD(&new_ref->node);
-
- mutex_lock(hdl->lock);
-
- /* Add immediately at the end of the list if the list is empty, or if
- the last element in the list has a lower ID.
- This ensures that when elements are added in ascending order the
- insertion is an O(1) operation. */
- if (list_empty(&hdl->ctrl_refs) || id > node2id(hdl->ctrl_refs.prev)) {
- list_add_tail(&new_ref->node, &hdl->ctrl_refs);
- goto insert_in_hash;
- }
-
- /* Find insert position in sorted list */
- list_for_each_entry(ref, &hdl->ctrl_refs, node) {
- if (ref->ctrl->id < id)
- continue;
- /* Don't add duplicates */
- if (ref->ctrl->id == id) {
- kfree(new_ref);
- goto unlock;
- }
- list_add(&new_ref->node, ref->node.prev);
- break;
- }
-
-insert_in_hash:
- /* Insert the control node in the hash */
- new_ref->next = hdl->buckets[bucket];
- 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);
- return 0;
-}
-
-/* Add a new control */
-static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_ops *ops,
- const struct v4l2_ctrl_type_ops *type_ops,
- u32 id, const char *name, enum v4l2_ctrl_type type,
- s64 min, s64 max, u64 step, s64 def,
- const u32 dims[V4L2_CTRL_MAX_DIMS], u32 elem_size,
- u32 flags, const char * const *qmenu,
- const s64 *qmenu_int, const union v4l2_ctrl_ptr p_def,
- void *priv)
-{
- struct v4l2_ctrl *ctrl;
- unsigned sz_extra;
- unsigned nr_of_dims = 0;
- unsigned elems = 1;
- bool is_array;
- unsigned tot_ctrl_size;
- unsigned idx;
- void *data;
- int err;
-
- if (hdl->error)
- return NULL;
-
- while (dims && dims[nr_of_dims]) {
- elems *= dims[nr_of_dims];
- nr_of_dims++;
- if (nr_of_dims == V4L2_CTRL_MAX_DIMS)
- break;
- }
- is_array = nr_of_dims > 0;
-
- /* Prefill elem_size for all types handled by std_type_ops */
- switch ((u32)type) {
- case V4L2_CTRL_TYPE_INTEGER64:
- elem_size = sizeof(s64);
- break;
- case V4L2_CTRL_TYPE_STRING:
- elem_size = max + 1;
- break;
- case V4L2_CTRL_TYPE_U8:
- elem_size = sizeof(u8);
- break;
- case V4L2_CTRL_TYPE_U16:
- elem_size = sizeof(u16);
- break;
- case V4L2_CTRL_TYPE_U32:
- elem_size = sizeof(u32);
- break;
- case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS:
- elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params);
- break;
- case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION:
- elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization);
- break;
- 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;
- case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
- elem_size = sizeof(struct v4l2_ctrl_h264_pred_weights);
- break;
- case V4L2_CTRL_TYPE_VP8_FRAME:
- elem_size = sizeof(struct v4l2_ctrl_vp8_frame);
- break;
- case V4L2_CTRL_TYPE_HEVC_SPS:
- elem_size = sizeof(struct v4l2_ctrl_hevc_sps);
- break;
- case V4L2_CTRL_TYPE_HEVC_PPS:
- elem_size = sizeof(struct v4l2_ctrl_hevc_pps);
- break;
- case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
- elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params);
- break;
- case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
- elem_size = sizeof(struct v4l2_ctrl_hdr10_cll_info);
- break;
- case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
- elem_size = sizeof(struct v4l2_ctrl_hdr10_mastering_display);
- break;
- case V4L2_CTRL_TYPE_AREA:
- elem_size = sizeof(struct v4l2_area);
- break;
- default:
- if (type < V4L2_CTRL_COMPOUND_TYPES)
- elem_size = sizeof(s32);
- break;
- }
- tot_ctrl_size = elem_size * elems;
-
- /* Sanity checks */
- if (id == 0 || name == NULL || !elem_size ||
- id >= V4L2_CID_PRIVATE_BASE ||
- (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
- (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) {
- handler_set_err(hdl, -ERANGE);
- return NULL;
- }
- err = check_range(type, min, max, step, def);
- if (err) {
- handler_set_err(hdl, err);
- return NULL;
- }
- if (is_array &&
- (type == V4L2_CTRL_TYPE_BUTTON ||
- type == V4L2_CTRL_TYPE_CTRL_CLASS)) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
-
- sz_extra = 0;
- if (type == V4L2_CTRL_TYPE_BUTTON)
- flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
- V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
- else if (type == V4L2_CTRL_TYPE_CTRL_CLASS)
- flags |= V4L2_CTRL_FLAG_READ_ONLY;
- else if (type == V4L2_CTRL_TYPE_INTEGER64 ||
- type == V4L2_CTRL_TYPE_STRING ||
- type >= V4L2_CTRL_COMPOUND_TYPES ||
- is_array)
- sz_extra += 2 * tot_ctrl_size;
-
- if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const)
- sz_extra += elem_size;
-
- ctrl = kvzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
- if (ctrl == NULL) {
- handler_set_err(hdl, -ENOMEM);
- return NULL;
- }
-
- INIT_LIST_HEAD(&ctrl->node);
- INIT_LIST_HEAD(&ctrl->ev_subs);
- ctrl->handler = hdl;
- ctrl->ops = ops;
- ctrl->type_ops = type_ops ? type_ops : &std_type_ops;
- ctrl->id = id;
- ctrl->name = name;
- ctrl->type = type;
- ctrl->flags = flags;
- ctrl->minimum = min;
- ctrl->maximum = max;
- ctrl->step = step;
- ctrl->default_value = def;
- ctrl->is_string = !is_array && type == V4L2_CTRL_TYPE_STRING;
- ctrl->is_ptr = is_array || type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string;
- ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
- ctrl->is_array = is_array;
- ctrl->elems = elems;
- ctrl->nr_of_dims = nr_of_dims;
- if (nr_of_dims)
- memcpy(ctrl->dims, dims, nr_of_dims * sizeof(dims[0]));
- ctrl->elem_size = elem_size;
- if (type == V4L2_CTRL_TYPE_MENU)
- ctrl->qmenu = qmenu;
- else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
- ctrl->qmenu_int = qmenu_int;
- ctrl->priv = priv;
- ctrl->cur.val = ctrl->val = def;
- data = &ctrl[1];
-
- if (!ctrl->is_int) {
- ctrl->p_new.p = data;
- ctrl->p_cur.p = data + tot_ctrl_size;
- } else {
- ctrl->p_new.p = &ctrl->val;
- ctrl->p_cur.p = &ctrl->cur.val;
- }
-
- if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) {
- ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size;
- memcpy(ctrl->p_def.p, p_def.p_const, elem_size);
- }
-
- for (idx = 0; idx < elems; idx++) {
- ctrl->type_ops->init(ctrl, idx, ctrl->p_cur);
- ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
- }
-
- if (handler_new_ref(hdl, ctrl, NULL, false, false)) {
- kvfree(ctrl);
- return NULL;
- }
- mutex_lock(hdl->lock);
- list_add_tail(&ctrl->node, &hdl->ctrls);
- mutex_unlock(hdl->lock);
- return ctrl;
-}
-
-struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_config *cfg, void *priv)
-{
- bool is_menu;
- struct v4l2_ctrl *ctrl;
- const char *name = cfg->name;
- const char * const *qmenu = cfg->qmenu;
- const s64 *qmenu_int = cfg->qmenu_int;
- enum v4l2_ctrl_type type = cfg->type;
- u32 flags = cfg->flags;
- s64 min = cfg->min;
- s64 max = cfg->max;
- u64 step = cfg->step;
- s64 def = cfg->def;
-
- if (name == NULL)
- v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
- &def, &flags);
-
- 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 (type == V4L2_CTRL_TYPE_MENU && !qmenu) {
- qmenu = v4l2_ctrl_get_menu(cfg->id);
- } else if (type == V4L2_CTRL_TYPE_INTEGER_MENU && !qmenu_int) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
-
- ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name,
- type, min, max,
- is_menu ? cfg->menu_skip_mask : step, def,
- cfg->dims, cfg->elem_size,
- flags, qmenu, qmenu_int, cfg->p_def, priv);
- if (ctrl)
- ctrl->is_private = cfg->is_private;
- return ctrl;
-}
-EXPORT_SYMBOL(v4l2_ctrl_new_custom);
-
-/* Helper function for standard non-menu controls */
-struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_ops *ops,
- u32 id, s64 min, s64 max, u64 step, s64 def)
-{
- const char *name;
- enum v4l2_ctrl_type type;
- u32 flags;
-
- v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
- if (type == V4L2_CTRL_TYPE_MENU ||
- type == V4L2_CTRL_TYPE_INTEGER_MENU ||
- type >= V4L2_CTRL_COMPOUND_TYPES) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
- min, max, step, def, NULL, 0,
- flags, NULL, NULL, ptr_null, NULL);
-}
-EXPORT_SYMBOL(v4l2_ctrl_new_std);
-
-/* Helper function for standard menu controls */
-struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_ops *ops,
- u32 id, u8 _max, u64 mask, u8 _def)
-{
- const char * const *qmenu = NULL;
- const s64 *qmenu_int = NULL;
- unsigned int qmenu_int_len = 0;
- const char *name;
- enum v4l2_ctrl_type type;
- s64 min;
- s64 max = _max;
- s64 def = _def;
- u64 step;
- u32 flags;
-
- v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
-
- if (type == V4L2_CTRL_TYPE_MENU)
- qmenu = v4l2_ctrl_get_menu(id);
- else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
- qmenu_int = v4l2_ctrl_get_int_menu(id, &qmenu_int_len);
-
- if ((!qmenu && !qmenu_int) || (qmenu_int && max > qmenu_int_len)) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
- 0, max, mask, def, NULL, 0,
- flags, qmenu, qmenu_int, ptr_null, NULL);
-}
-EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
-
-/* Helper function for standard menu controls with driver defined menu */
-struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_ops *ops, u32 id, u8 _max,
- u64 mask, u8 _def, const char * const *qmenu)
-{
- enum v4l2_ctrl_type type;
- const char *name;
- u32 flags;
- u64 step;
- s64 min;
- s64 max = _max;
- s64 def = _def;
-
- /* v4l2_ctrl_new_std_menu_items() should only be called for
- * standard controls without a standard menu.
- */
- if (v4l2_ctrl_get_menu(id)) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
-
- v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
- if (type != V4L2_CTRL_TYPE_MENU || qmenu == NULL) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
- 0, max, mask, def, NULL, 0,
- flags, qmenu, NULL, ptr_null, NULL);
-
-}
-EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
-
-/* Helper function for standard compound controls */
-struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_ops *ops, u32 id,
- const union v4l2_ctrl_ptr p_def)
-{
- const char *name;
- enum v4l2_ctrl_type type;
- u32 flags;
- s64 min, max, step, def;
-
- v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
- if (type < V4L2_CTRL_COMPOUND_TYPES) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
- min, max, step, def, NULL, 0,
- flags, NULL, NULL, p_def, NULL);
-}
-EXPORT_SYMBOL(v4l2_ctrl_new_std_compound);
-
-/* Helper function for standard integer menu controls */
-struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_ops *ops,
- u32 id, u8 _max, u8 _def, const s64 *qmenu_int)
-{
- const char *name;
- enum v4l2_ctrl_type type;
- s64 min;
- u64 step;
- s64 max = _max;
- s64 def = _def;
- u32 flags;
-
- v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
- if (type != V4L2_CTRL_TYPE_INTEGER_MENU) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
- 0, max, 0, def, NULL, 0,
- flags, NULL, qmenu_int, ptr_null, NULL);
-}
-EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
-
-/* Add the controls from another handler to our own. */
-int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
- struct v4l2_ctrl_handler *add,
- bool (*filter)(const struct v4l2_ctrl *ctrl),
- bool from_other_dev)
-{
- struct v4l2_ctrl_ref *ref;
- int ret = 0;
-
- /* Do nothing if either handler is NULL or if they are the same */
- if (!hdl || !add || hdl == add)
- return 0;
- if (hdl->error)
- return hdl->error;
- mutex_lock(add->lock);
- list_for_each_entry(ref, &add->ctrl_refs, node) {
- struct v4l2_ctrl *ctrl = ref->ctrl;
-
- /* Skip handler-private controls. */
- if (ctrl->is_private)
- continue;
- /* And control classes */
- if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
- continue;
- /* Filter any unwanted controls */
- if (filter && !filter(ctrl))
- continue;
- ret = handler_new_ref(hdl, ctrl, NULL, from_other_dev, false);
- if (ret)
- break;
- }
- mutex_unlock(add->lock);
- return ret;
-}
-EXPORT_SYMBOL(v4l2_ctrl_add_handler);
-
-bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl)
-{
- if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_TX)
- return true;
- if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_RX)
- return true;
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_AUDIO_LOUDNESS:
- return true;
- default:
- break;
- }
- return false;
-}
-EXPORT_SYMBOL(v4l2_ctrl_radio_filter);
-
-/* Cluster controls */
-void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
-{
- bool has_volatiles = false;
- int i;
-
- /* The first control is the master control and it must not be NULL */
- if (WARN_ON(ncontrols == 0 || controls[0] == NULL))
- return;
-
- for (i = 0; i < ncontrols; i++) {
- if (controls[i]) {
- controls[i]->cluster = controls;
- controls[i]->ncontrols = ncontrols;
- if (controls[i]->flags & V4L2_CTRL_FLAG_VOLATILE)
- has_volatiles = true;
- }
- }
- controls[0]->has_volatiles = has_volatiles;
-}
-EXPORT_SYMBOL(v4l2_ctrl_cluster);
-
-void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
- u8 manual_val, bool set_volatile)
-{
- struct v4l2_ctrl *master = controls[0];
- u32 flag = 0;
- int i;
-
- v4l2_ctrl_cluster(ncontrols, controls);
- WARN_ON(ncontrols <= 1);
- WARN_ON(manual_val < master->minimum || manual_val > master->maximum);
- WARN_ON(set_volatile && !has_op(master, g_volatile_ctrl));
- master->is_auto = true;
- master->has_volatiles = set_volatile;
- master->manual_mode_value = manual_val;
- master->flags |= V4L2_CTRL_FLAG_UPDATE;
-
- if (!is_cur_manual(master))
- flag = V4L2_CTRL_FLAG_INACTIVE |
- (set_volatile ? V4L2_CTRL_FLAG_VOLATILE : 0);
-
- for (i = 1; i < ncontrols; i++)
- if (controls[i])
- controls[i]->flags |= flag;
-}
-EXPORT_SYMBOL(v4l2_ctrl_auto_cluster);
-
-/* Activate/deactivate a control. */
-void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active)
-{
- /* invert since the actual flag is called 'inactive' */
- bool inactive = !active;
- bool old;
-
- if (ctrl == NULL)
- return;
-
- if (inactive)
- /* set V4L2_CTRL_FLAG_INACTIVE */
- old = test_and_set_bit(4, &ctrl->flags);
- else
- /* clear V4L2_CTRL_FLAG_INACTIVE */
- old = test_and_clear_bit(4, &ctrl->flags);
- if (old != inactive)
- send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
-}
-EXPORT_SYMBOL(v4l2_ctrl_activate);
-
-void __v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)
-{
- bool old;
-
- if (ctrl == NULL)
- return;
-
- lockdep_assert_held(ctrl->handler->lock);
-
- if (grabbed)
- /* set V4L2_CTRL_FLAG_GRABBED */
- old = test_and_set_bit(1, &ctrl->flags);
- else
- /* clear V4L2_CTRL_FLAG_GRABBED */
- old = test_and_clear_bit(1, &ctrl->flags);
- if (old != grabbed)
- send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
-}
-EXPORT_SYMBOL(__v4l2_ctrl_grab);
-
-/* Log the control name and value */
-static void log_ctrl(const struct v4l2_ctrl *ctrl,
- const char *prefix, const char *colon)
-{
- if (ctrl->flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_WRITE_ONLY))
- return;
- if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
- return;
-
- pr_info("%s%s%s: ", prefix, colon, ctrl->name);
-
- ctrl->type_ops->log(ctrl);
-
- if (ctrl->flags & (V4L2_CTRL_FLAG_INACTIVE |
- V4L2_CTRL_FLAG_GRABBED |
- V4L2_CTRL_FLAG_VOLATILE)) {
- if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
- pr_cont(" inactive");
- if (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)
- pr_cont(" grabbed");
- if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE)
- pr_cont(" volatile");
- }
- pr_cont("\n");
-}
-
-/* Log all controls owned by the handler */
-void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl,
- const char *prefix)
-{
- struct v4l2_ctrl *ctrl;
- const char *colon = "";
- int len;
-
- if (hdl == NULL)
- return;
- if (prefix == NULL)
- prefix = "";
- len = strlen(prefix);
- if (len && prefix[len - 1] != ' ')
- colon = ": ";
- mutex_lock(hdl->lock);
- list_for_each_entry(ctrl, &hdl->ctrls, node)
- if (!(ctrl->flags & V4L2_CTRL_FLAG_DISABLED))
- log_ctrl(ctrl, prefix, colon);
- mutex_unlock(hdl->lock);
-}
-EXPORT_SYMBOL(v4l2_ctrl_handler_log_status);
-
-int v4l2_ctrl_subdev_log_status(struct v4l2_subdev *sd)
-{
- v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
- return 0;
-}
-EXPORT_SYMBOL(v4l2_ctrl_subdev_log_status);
-
-/* Call s_ctrl for all controls owned by the handler */
-int __v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
-{
- struct v4l2_ctrl *ctrl;
- int ret = 0;
-
- if (hdl == NULL)
- return 0;
-
- lockdep_assert_held(hdl->lock);
-
- list_for_each_entry(ctrl, &hdl->ctrls, node)
- ctrl->done = false;
-
- list_for_each_entry(ctrl, &hdl->ctrls, node) {
- struct v4l2_ctrl *master = ctrl->cluster[0];
- int i;
-
- /* Skip if this control was already handled by a cluster. */
- /* Skip button controls and read-only controls. */
- if (ctrl->done || ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
- (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
- continue;
-
- for (i = 0; i < master->ncontrols; i++) {
- if (master->cluster[i]) {
- cur_to_new(master->cluster[i]);
- master->cluster[i]->is_new = 1;
- master->cluster[i]->done = true;
- }
- }
- ret = call_op(master, s_ctrl);
- if (ret)
- break;
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(__v4l2_ctrl_handler_setup);
-
-int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
-{
- int ret;
-
- if (hdl == NULL)
- return 0;
-
- mutex_lock(hdl->lock);
- ret = __v4l2_ctrl_handler_setup(hdl);
- mutex_unlock(hdl->lock);
-
- return ret;
-}
-EXPORT_SYMBOL(v4l2_ctrl_handler_setup);
-
-/* Implement VIDIOC_QUERY_EXT_CTRL */
-int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctrl *qc)
-{
- const unsigned next_flags = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
- u32 id = qc->id & V4L2_CTRL_ID_MASK;
- struct v4l2_ctrl_ref *ref;
- struct v4l2_ctrl *ctrl;
-
- if (hdl == NULL)
- return -EINVAL;
-
- mutex_lock(hdl->lock);
-
- /* Try to find it */
- ref = find_ref(hdl, id);
-
- if ((qc->id & next_flags) && !list_empty(&hdl->ctrl_refs)) {
- bool is_compound;
- /* Match any control that is not hidden */
- unsigned mask = 1;
- bool match = false;
-
- if ((qc->id & next_flags) == V4L2_CTRL_FLAG_NEXT_COMPOUND) {
- /* Match any hidden control */
- match = true;
- } else if ((qc->id & next_flags) == next_flags) {
- /* Match any control, compound or not */
- mask = 0;
- }
-
- /* Find the next control with ID > qc->id */
-
- /* Did we reach the end of the control list? */
- if (id >= node2id(hdl->ctrl_refs.prev)) {
- ref = NULL; /* Yes, so there is no next control */
- } else if (ref) {
- /* We found a control with the given ID, so just get
- the next valid one in the list. */
- list_for_each_entry_continue(ref, &hdl->ctrl_refs, node) {
- is_compound = ref->ctrl->is_array ||
- ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES;
- if (id < ref->ctrl->id &&
- (is_compound & mask) == match)
- break;
- }
- if (&ref->node == &hdl->ctrl_refs)
- ref = NULL;
- } else {
- /* No control with the given ID exists, so start
- searching for the next largest ID. We know there
- is one, otherwise the first 'if' above would have
- been true. */
- list_for_each_entry(ref, &hdl->ctrl_refs, node) {
- is_compound = ref->ctrl->is_array ||
- ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES;
- if (id < ref->ctrl->id &&
- (is_compound & mask) == match)
- break;
- }
- if (&ref->node == &hdl->ctrl_refs)
- ref = NULL;
- }
- }
- mutex_unlock(hdl->lock);
-
- if (!ref)
- return -EINVAL;
-
- ctrl = ref->ctrl;
- memset(qc, 0, sizeof(*qc));
- if (id >= V4L2_CID_PRIVATE_BASE)
- qc->id = id;
- else
- qc->id = ctrl->id;
- strscpy(qc->name, ctrl->name, sizeof(qc->name));
- qc->flags = user_flags(ctrl);
- qc->type = ctrl->type;
- qc->elem_size = ctrl->elem_size;
- qc->elems = ctrl->elems;
- qc->nr_of_dims = ctrl->nr_of_dims;
- memcpy(qc->dims, ctrl->dims, qc->nr_of_dims * sizeof(qc->dims[0]));
- qc->minimum = ctrl->minimum;
- qc->maximum = ctrl->maximum;
- qc->default_value = ctrl->default_value;
- if (ctrl->type == V4L2_CTRL_TYPE_MENU
- || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
- qc->step = 1;
- else
- qc->step = ctrl->step;
- return 0;
-}
-EXPORT_SYMBOL(v4l2_query_ext_ctrl);
-
-/* Implement VIDIOC_QUERYCTRL */
-int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
-{
- struct v4l2_query_ext_ctrl qec = { qc->id };
- int rc;
-
- rc = v4l2_query_ext_ctrl(hdl, &qec);
- if (rc)
- return rc;
-
- qc->id = qec.id;
- qc->type = qec.type;
- qc->flags = qec.flags;
- strscpy(qc->name, qec.name, sizeof(qc->name));
- switch (qc->type) {
- case V4L2_CTRL_TYPE_INTEGER:
- case V4L2_CTRL_TYPE_BOOLEAN:
- case V4L2_CTRL_TYPE_MENU:
- case V4L2_CTRL_TYPE_INTEGER_MENU:
- case V4L2_CTRL_TYPE_STRING:
- case V4L2_CTRL_TYPE_BITMASK:
- qc->minimum = qec.minimum;
- qc->maximum = qec.maximum;
- qc->step = qec.step;
- qc->default_value = qec.default_value;
- break;
- default:
- qc->minimum = 0;
- qc->maximum = 0;
- qc->step = 0;
- qc->default_value = 0;
- break;
- }
- return 0;
-}
-EXPORT_SYMBOL(v4l2_queryctrl);
-
-/* Implement VIDIOC_QUERYMENU */
-int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
-{
- struct v4l2_ctrl *ctrl;
- u32 i = qm->index;
-
- ctrl = v4l2_ctrl_find(hdl, qm->id);
- if (!ctrl)
- return -EINVAL;
-
- qm->reserved = 0;
- /* Sanity checks */
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_MENU:
- if (ctrl->qmenu == NULL)
- return -EINVAL;
- break;
- case V4L2_CTRL_TYPE_INTEGER_MENU:
- if (ctrl->qmenu_int == NULL)
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
-
- if (i < ctrl->minimum || i > ctrl->maximum)
- return -EINVAL;
-
- /* Use mask to see if this menu item should be skipped */
- if (ctrl->menu_skip_mask & (1ULL << i))
- return -EINVAL;
- /* Empty menu items should also be skipped */
- if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
- if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
- return -EINVAL;
- strscpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
- } else {
- qm->value = ctrl->qmenu_int[i];
- }
- return 0;
-}
-EXPORT_SYMBOL(v4l2_querymenu);
-
-static int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_handler *from)
-{
- struct v4l2_ctrl_ref *ref;
- int err = 0;
-
- if (WARN_ON(!hdl || hdl == from))
- return -EINVAL;
-
- if (hdl->error)
- return hdl->error;
-
- WARN_ON(hdl->lock != &hdl->_lock);
-
- mutex_lock(from->lock);
- list_for_each_entry(ref, &from->ctrl_refs, node) {
- struct v4l2_ctrl *ctrl = ref->ctrl;
- struct v4l2_ctrl_ref *new_ref;
-
- /* Skip refs inherited from other devices */
- if (ref->from_other_dev)
- continue;
- err = handler_new_ref(hdl, ctrl, &new_ref, false, true);
- if (err)
- break;
- }
- mutex_unlock(from->lock);
- return err;
-}
-
-static void v4l2_ctrl_request_queue(struct media_request_object *obj)
-{
- struct v4l2_ctrl_handler *hdl =
- container_of(obj, struct v4l2_ctrl_handler, req_obj);
- struct v4l2_ctrl_handler *main_hdl = obj->priv;
-
- mutex_lock(main_hdl->lock);
- list_add_tail(&hdl->requests_queued, &main_hdl->requests_queued);
- hdl->request_is_queued = true;
- mutex_unlock(main_hdl->lock);
-}
-
-static void v4l2_ctrl_request_unbind(struct media_request_object *obj)
-{
- struct v4l2_ctrl_handler *hdl =
- container_of(obj, struct v4l2_ctrl_handler, req_obj);
- struct v4l2_ctrl_handler *main_hdl = obj->priv;
-
- mutex_lock(main_hdl->lock);
- list_del_init(&hdl->requests);
- if (hdl->request_is_queued) {
- list_del_init(&hdl->requests_queued);
- hdl->request_is_queued = false;
- }
- mutex_unlock(main_hdl->lock);
-}
-
-static void v4l2_ctrl_request_release(struct media_request_object *obj)
-{
- struct v4l2_ctrl_handler *hdl =
- container_of(obj, struct v4l2_ctrl_handler, req_obj);
-
- v4l2_ctrl_handler_free(hdl);
- kfree(hdl);
-}
-
-static const struct media_request_object_ops req_ops = {
- .queue = v4l2_ctrl_request_queue,
- .unbind = v4l2_ctrl_request_unbind,
- .release = v4l2_ctrl_request_release,
-};
-
-struct v4l2_ctrl_handler *v4l2_ctrl_request_hdl_find(struct media_request *req,
- struct v4l2_ctrl_handler *parent)
-{
- struct media_request_object *obj;
-
- if (WARN_ON(req->state != MEDIA_REQUEST_STATE_VALIDATING &&
- req->state != MEDIA_REQUEST_STATE_QUEUED))
- return NULL;
-
- obj = media_request_object_find(req, &req_ops, parent);
- if (obj)
- return container_of(obj, struct v4l2_ctrl_handler, req_obj);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_find);
-
-struct v4l2_ctrl *
-v4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
-{
- struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
-
- return (ref && ref->valid_p_req) ? ref->ctrl : NULL;
-}
-EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_ctrl_find);
-
-static int v4l2_ctrl_request_bind(struct media_request *req,
- struct v4l2_ctrl_handler *hdl,
- struct v4l2_ctrl_handler *from)
-{
- int ret;
-
- ret = v4l2_ctrl_request_clone(hdl, from);
-
- if (!ret) {
- ret = media_request_object_bind(req, &req_ops,
- from, false, &hdl->req_obj);
- if (!ret) {
- mutex_lock(from->lock);
- list_add_tail(&hdl->requests, &from->requests);
- mutex_unlock(from->lock);
- }
- }
- return ret;
-}
-
-/* Some general notes on the atomic requirements of VIDIOC_G/TRY/S_EXT_CTRLS:
-
- It is not a fully atomic operation, just best-effort only. After all, if
- multiple controls have to be set through multiple i2c writes (for example)
- then some initial writes may succeed while others fail. Thus leaving the
- system in an inconsistent state. The question is how much effort you are
- willing to spend on trying to make something atomic that really isn't.
-
- From the point of view of an application the main requirement is that
- when you call VIDIOC_S_EXT_CTRLS and some values are invalid then an
- error should be returned without actually affecting any controls.
-
- If all the values are correct, then it is acceptable to just give up
- in case of low-level errors.
-
- It is important though that the application can tell when only a partial
- configuration was done. The way we do that is through the error_idx field
- of struct v4l2_ext_controls: if that is equal to the count field then no
- controls were affected. Otherwise all controls before that index were
- successful in performing their 'get' or 'set' operation, the control at
- the given index failed, and you don't know what happened with the controls
- after the failed one. Since if they were part of a control cluster they
- could have been successfully processed (if a cluster member was encountered
- at index < error_idx), they could have failed (if a cluster member was at
- error_idx), or they may not have been processed yet (if the first cluster
- member appeared after error_idx).
-
- It is all fairly theoretical, though. In practice all you can do is to
- bail out. If error_idx == count, then it is an application bug. If
- error_idx < count then it is only an application bug if the error code was
- EBUSY. That usually means that something started streaming just when you
- tried to set the controls. In all other cases it is a driver/hardware
- problem and all you can do is to retry or bail out.
-
- Note that these rules do not apply to VIDIOC_TRY_EXT_CTRLS: since that
- never modifies controls the error_idx is just set to whatever control
- has an invalid value.
- */
-
-/* Prepare for the extended g/s/try functions.
- Find the controls in the control array and do some basic checks. */
-static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
- struct v4l2_ext_controls *cs,
- struct v4l2_ctrl_helper *helpers,
- struct video_device *vdev,
- bool get)
-{
- struct v4l2_ctrl_helper *h;
- bool have_clusters = false;
- u32 i;
-
- for (i = 0, h = helpers; i < cs->count; i++, h++) {
- struct v4l2_ext_control *c = &cs->controls[i];
- struct v4l2_ctrl_ref *ref;
- struct v4l2_ctrl *ctrl;
- u32 id = c->id & V4L2_CTRL_ID_MASK;
-
- cs->error_idx = i;
-
- if (cs->which &&
- cs->which != V4L2_CTRL_WHICH_DEF_VAL &&
- cs->which != V4L2_CTRL_WHICH_REQUEST_VAL &&
- V4L2_CTRL_ID2WHICH(id) != cs->which) {
- dprintk(vdev,
- "invalid which 0x%x or control id 0x%x\n",
- cs->which, id);
- return -EINVAL;
- }
-
- /* Old-style private controls are not allowed for
- extended controls */
- if (id >= V4L2_CID_PRIVATE_BASE) {
- dprintk(vdev,
- "old-style private controls not allowed\n");
- return -EINVAL;
- }
- ref = find_ref_lock(hdl, id);
- if (ref == NULL) {
- dprintk(vdev, "cannot find control id 0x%x\n", id);
- return -EINVAL;
- }
- h->ref = ref;
- ctrl = ref->ctrl;
- if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED) {
- dprintk(vdev, "control id 0x%x is disabled\n", id);
- return -EINVAL;
- }
-
- if (ctrl->cluster[0]->ncontrols > 1)
- have_clusters = true;
- if (ctrl->cluster[0] != ctrl)
- ref = find_ref_lock(hdl, ctrl->cluster[0]->id);
- if (ctrl->is_ptr && !ctrl->is_string) {
- unsigned tot_size = ctrl->elems * ctrl->elem_size;
-
- if (c->size < tot_size) {
- /*
- * In the get case the application first
- * queries to obtain the size of the control.
- */
- if (get) {
- c->size = tot_size;
- return -ENOSPC;
- }
- dprintk(vdev,
- "pointer control id 0x%x size too small, %d bytes but %d bytes needed\n",
- id, c->size, tot_size);
- return -EFAULT;
- }
- c->size = tot_size;
- }
- /* Store the ref to the master control of the cluster */
- h->mref = ref;
- /* Initially set next to 0, meaning that there is no other
- control in this helper array belonging to the same
- cluster */
- h->next = 0;
- }
-
- /* We are done if there were no controls that belong to a multi-
- control cluster. */
- if (!have_clusters)
- return 0;
-
- /* The code below figures out in O(n) time which controls in the list
- belong to the same cluster. */
-
- /* This has to be done with the handler lock taken. */
- mutex_lock(hdl->lock);
-
- /* First zero the helper field in the master control references */
- for (i = 0; i < cs->count; i++)
- helpers[i].mref->helper = NULL;
- for (i = 0, h = helpers; i < cs->count; i++, h++) {
- struct v4l2_ctrl_ref *mref = h->mref;
-
- /* If the mref->helper is set, then it points to an earlier
- helper that belongs to the same cluster. */
- if (mref->helper) {
- /* Set the next field of mref->helper to the current
- index: this means that that earlier helper now
- points to the next helper in the same cluster. */
- mref->helper->next = i;
- /* mref should be set only for the first helper in the
- cluster, clear the others. */
- h->mref = NULL;
- }
- /* Point the mref helper to the current helper struct. */
- mref->helper = h;
- }
- mutex_unlock(hdl->lock);
- return 0;
-}
-
-/* Handles the corner case where cs->count == 0. It checks whether the
- specified control class exists. If that class ID is 0, then it checks
- whether there are any controls at all. */
-static int class_check(struct v4l2_ctrl_handler *hdl, u32 which)
-{
- if (which == 0 || which == V4L2_CTRL_WHICH_DEF_VAL ||
- which == V4L2_CTRL_WHICH_REQUEST_VAL)
- return 0;
- return find_ref_lock(hdl, which | 1) ? 0 : -EINVAL;
-}
-
-/*
- * Get extended controls. Allocates the helpers array if needed.
- *
- * Note that v4l2_g_ext_ctrls_common() with 'which' set to
- * V4L2_CTRL_WHICH_REQUEST_VAL is only called if the request was
- * completed, and in that case valid_p_req is true for all controls.
- */
-static int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
- struct v4l2_ext_controls *cs,
- struct video_device *vdev)
-{
- struct v4l2_ctrl_helper helper[4];
- struct v4l2_ctrl_helper *helpers = helper;
- int ret;
- int i, j;
- bool is_default, is_request;
-
- is_default = (cs->which == V4L2_CTRL_WHICH_DEF_VAL);
- is_request = (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL);
-
- cs->error_idx = cs->count;
- cs->which = V4L2_CTRL_ID2WHICH(cs->which);
-
- if (hdl == NULL)
- return -EINVAL;
-
- if (cs->count == 0)
- return class_check(hdl, cs->which);
-
- if (cs->count > ARRAY_SIZE(helper)) {
- helpers = kvmalloc_array(cs->count, sizeof(helper[0]),
- GFP_KERNEL);
- if (helpers == NULL)
- return -ENOMEM;
- }
-
- ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, true);
- cs->error_idx = cs->count;
-
- for (i = 0; !ret && i < cs->count; i++)
- if (helpers[i].ref->ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
- ret = -EACCES;
-
- for (i = 0; !ret && i < cs->count; i++) {
- struct v4l2_ctrl *master;
- bool is_volatile = false;
- u32 idx = i;
-
- if (helpers[i].mref == NULL)
- continue;
-
- master = helpers[i].mref->ctrl;
- cs->error_idx = i;
-
- v4l2_ctrl_lock(master);
-
- /*
- * g_volatile_ctrl will update the new control values.
- * This makes no sense for V4L2_CTRL_WHICH_DEF_VAL and
- * V4L2_CTRL_WHICH_REQUEST_VAL. In the case of requests
- * it is v4l2_ctrl_request_complete() that copies the
- * volatile controls at the time of request completion
- * to the request, so you don't want to do that again.
- */
- if (!is_default && !is_request &&
- ((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
- (master->has_volatiles && !is_cur_manual(master)))) {
- for (j = 0; j < master->ncontrols; j++)
- cur_to_new(master->cluster[j]);
- ret = call_op(master, g_volatile_ctrl);
- is_volatile = true;
- }
-
- if (ret) {
- v4l2_ctrl_unlock(master);
- break;
- }
-
- /*
- * Copy the default value (if is_default is true), the
- * request value (if is_request is true and p_req is valid),
- * the new volatile value (if is_volatile is true) or the
- * current value.
- */
- do {
- struct v4l2_ctrl_ref *ref = helpers[idx].ref;
-
- if (is_default)
- ret = def_to_user(cs->controls + idx, ref->ctrl);
- else if (is_request && ref->valid_p_req)
- ret = req_to_user(cs->controls + idx, ref);
- else if (is_volatile)
- ret = new_to_user(cs->controls + idx, ref->ctrl);
- else
- ret = cur_to_user(cs->controls + idx, ref->ctrl);
- idx = helpers[idx].next;
- } while (!ret && idx);
-
- v4l2_ctrl_unlock(master);
- }
-
- if (cs->count > ARRAY_SIZE(helper))
- kvfree(helpers);
- return ret;
-}
-
-static struct media_request_object *
-v4l2_ctrls_find_req_obj(struct v4l2_ctrl_handler *hdl,
- struct media_request *req, bool set)
-{
- struct media_request_object *obj;
- struct v4l2_ctrl_handler *new_hdl;
- int ret;
-
- if (IS_ERR(req))
- return ERR_CAST(req);
-
- if (set && WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING))
- return ERR_PTR(-EBUSY);
-
- obj = media_request_object_find(req, &req_ops, hdl);
- if (obj)
- return obj;
- if (!set)
- return ERR_PTR(-ENOENT);
-
- new_hdl = kzalloc(sizeof(*new_hdl), GFP_KERNEL);
- if (!new_hdl)
- return ERR_PTR(-ENOMEM);
-
- obj = &new_hdl->req_obj;
- ret = v4l2_ctrl_handler_init(new_hdl, (hdl->nr_of_buckets - 1) * 8);
- if (!ret)
- ret = v4l2_ctrl_request_bind(req, new_hdl, hdl);
- if (ret) {
- kfree(new_hdl);
-
- return ERR_PTR(ret);
- }
-
- media_request_object_get(obj);
- return obj;
-}
-
-int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
- struct media_device *mdev, struct v4l2_ext_controls *cs)
-{
- struct media_request_object *obj = NULL;
- struct media_request *req = NULL;
- int ret;
-
- if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL) {
- if (!mdev || cs->request_fd < 0)
- return -EINVAL;
-
- req = media_request_get_by_fd(mdev, cs->request_fd);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- if (req->state != MEDIA_REQUEST_STATE_COMPLETE) {
- media_request_put(req);
- return -EACCES;
- }
-
- ret = media_request_lock_for_access(req);
- if (ret) {
- media_request_put(req);
- return ret;
- }
-
- obj = v4l2_ctrls_find_req_obj(hdl, req, false);
- if (IS_ERR(obj)) {
- media_request_unlock_for_access(req);
- media_request_put(req);
- return PTR_ERR(obj);
- }
-
- hdl = container_of(obj, struct v4l2_ctrl_handler,
- req_obj);
- }
-
- ret = v4l2_g_ext_ctrls_common(hdl, cs, vdev);
-
- if (obj) {
- media_request_unlock_for_access(req);
- media_request_object_put(obj);
- media_request_put(req);
- }
- return ret;
-}
-EXPORT_SYMBOL(v4l2_g_ext_ctrls);
-
-/* Helper function to get a single control */
-static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
-{
- struct v4l2_ctrl *master = ctrl->cluster[0];
- int ret = 0;
- int i;
-
- /* Compound controls are not supported. The new_to_user() and
- * cur_to_user() calls below would need to be modified not to access
- * userspace memory when called from get_ctrl().
- */
- if (!ctrl->is_int && ctrl->type != V4L2_CTRL_TYPE_INTEGER64)
- return -EINVAL;
-
- if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
- return -EACCES;
-
- v4l2_ctrl_lock(master);
- /* g_volatile_ctrl will update the current control values */
- if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
- for (i = 0; i < master->ncontrols; i++)
- cur_to_new(master->cluster[i]);
- ret = call_op(master, g_volatile_ctrl);
- new_to_user(c, ctrl);
- } else {
- cur_to_user(c, ctrl);
- }
- v4l2_ctrl_unlock(master);
- return ret;
-}
-
-int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
-{
- struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
- struct v4l2_ext_control c;
- int ret;
-
- if (ctrl == NULL || !ctrl->is_int)
- return -EINVAL;
- ret = get_ctrl(ctrl, &c);
- control->value = c.value;
- return ret;
-}
-EXPORT_SYMBOL(v4l2_g_ctrl);
-
-s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct v4l2_ext_control c;
-
- /* It's a driver bug if this happens. */
- if (WARN_ON(!ctrl->is_int))
- return 0;
- c.value = 0;
- get_ctrl(ctrl, &c);
- return c.value;
-}
-EXPORT_SYMBOL(v4l2_ctrl_g_ctrl);
-
-s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl)
-{
- struct v4l2_ext_control c;
-
- /* It's a driver bug if this happens. */
- if (WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64))
- return 0;
- c.value64 = 0;
- get_ctrl(ctrl, &c);
- return c.value64;
-}
-EXPORT_SYMBOL(v4l2_ctrl_g_ctrl_int64);
-
-
-/* Core function that calls try/s_ctrl and ensures that the new value is
- copied to the current value on a set.
- Must be called with ctrl->handler->lock held. */
-static int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
- bool set, u32 ch_flags)
-{
- bool update_flag;
- int ret;
- int i;
-
- /* Go through the cluster and either validate the new value or
- (if no new value was set), copy the current value to the new
- value, ensuring a consistent view for the control ops when
- called. */
- for (i = 0; i < master->ncontrols; i++) {
- struct v4l2_ctrl *ctrl = master->cluster[i];
-
- if (ctrl == NULL)
- continue;
-
- if (!ctrl->is_new) {
- cur_to_new(ctrl);
- continue;
- }
- /* Check again: it may have changed since the
- previous check in try_or_set_ext_ctrls(). */
- if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
- return -EBUSY;
- }
-
- ret = call_op(master, try_ctrl);
-
- /* Don't set if there is no change */
- if (ret || !set || !cluster_changed(master))
- return ret;
- ret = call_op(master, s_ctrl);
- if (ret)
- return ret;
-
- /* If OK, then make the new values permanent. */
- update_flag = is_cur_manual(master) != is_new_manual(master);
-
- for (i = 0; i < master->ncontrols; i++) {
- /*
- * If we switch from auto to manual mode, and this cluster
- * contains volatile controls, then all non-master controls
- * have to be marked as changed. The 'new' value contains
- * the volatile value (obtained by update_from_auto_cluster),
- * which now has to become the current value.
- */
- if (i && update_flag && is_new_manual(master) &&
- master->has_volatiles && master->cluster[i])
- master->cluster[i]->has_changed = true;
-
- new_to_cur(fh, master->cluster[i], ch_flags |
- ((update_flag && i > 0) ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
- }
- return 0;
-}
-
-/* Validate controls. */
-static int validate_ctrls(struct v4l2_ext_controls *cs,
- struct v4l2_ctrl_helper *helpers,
- struct video_device *vdev,
- bool set)
-{
- unsigned i;
- int ret = 0;
-
- cs->error_idx = cs->count;
- for (i = 0; i < cs->count; i++) {
- struct v4l2_ctrl *ctrl = helpers[i].ref->ctrl;
- union v4l2_ctrl_ptr p_new;
-
- cs->error_idx = i;
-
- if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) {
- dprintk(vdev,
- "control id 0x%x is read-only\n",
- ctrl->id);
- return -EACCES;
- }
- /* This test is also done in try_set_control_cluster() which
- is called in atomic context, so that has the final say,
- but it makes sense to do an up-front check as well. Once
- an error occurs in try_set_control_cluster() some other
- controls may have been set already and we want to do a
- best-effort to avoid that. */
- if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) {
- dprintk(vdev,
- "control id 0x%x is grabbed, cannot set\n",
- ctrl->id);
- return -EBUSY;
- }
- /*
- * Skip validation for now if the payload needs to be copied
- * from userspace into kernelspace. We'll validate those later.
- */
- if (ctrl->is_ptr)
- continue;
- if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
- p_new.p_s64 = &cs->controls[i].value64;
- else
- p_new.p_s32 = &cs->controls[i].value;
- ret = validate_new(ctrl, p_new);
- if (ret)
- return ret;
- }
- return 0;
-}
-
-/* Obtain the current volatile values of an autocluster and mark them
- as new. */
-static void update_from_auto_cluster(struct v4l2_ctrl *master)
-{
- int i;
-
- for (i = 1; i < master->ncontrols; i++)
- cur_to_new(master->cluster[i]);
- if (!call_op(master, g_volatile_ctrl))
- for (i = 1; i < master->ncontrols; i++)
- if (master->cluster[i])
- master->cluster[i]->is_new = 1;
-}
-
-/* Try or try-and-set controls */
-static int try_set_ext_ctrls_common(struct v4l2_fh *fh,
- struct v4l2_ctrl_handler *hdl,
- struct v4l2_ext_controls *cs,
- struct video_device *vdev, bool set)
-{
- struct v4l2_ctrl_helper helper[4];
- struct v4l2_ctrl_helper *helpers = helper;
- unsigned i, j;
- int ret;
-
- cs->error_idx = cs->count;
-
- /* Default value cannot be changed */
- if (cs->which == V4L2_CTRL_WHICH_DEF_VAL) {
- dprintk(vdev, "%s: cannot change default value\n",
- video_device_node_name(vdev));
- return -EINVAL;
- }
-
- cs->which = V4L2_CTRL_ID2WHICH(cs->which);
-
- if (hdl == NULL) {
- dprintk(vdev, "%s: invalid null control handler\n",
- video_device_node_name(vdev));
- return -EINVAL;
- }
-
- if (cs->count == 0)
- return class_check(hdl, cs->which);
-
- if (cs->count > ARRAY_SIZE(helper)) {
- helpers = kvmalloc_array(cs->count, sizeof(helper[0]),
- GFP_KERNEL);
- if (!helpers)
- return -ENOMEM;
- }
- ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, false);
- if (!ret)
- ret = validate_ctrls(cs, helpers, vdev, set);
- if (ret && set)
- cs->error_idx = cs->count;
- for (i = 0; !ret && i < cs->count; i++) {
- struct v4l2_ctrl *master;
- u32 idx = i;
-
- if (helpers[i].mref == NULL)
- continue;
-
- cs->error_idx = i;
- master = helpers[i].mref->ctrl;
- v4l2_ctrl_lock(master);
-
- /* Reset the 'is_new' flags of the cluster */
- for (j = 0; j < master->ncontrols; j++)
- if (master->cluster[j])
- master->cluster[j]->is_new = 0;
-
- /* For volatile autoclusters that are currently in auto mode
- we need to discover if it will be set to manual mode.
- If so, then we have to copy the current volatile values
- first since those will become the new manual values (which
- may be overwritten by explicit new values from this set
- of controls). */
- if (master->is_auto && master->has_volatiles &&
- !is_cur_manual(master)) {
- /* Pick an initial non-manual value */
- s32 new_auto_val = master->manual_mode_value + 1;
- u32 tmp_idx = idx;
-
- do {
- /* Check if the auto control is part of the
- list, and remember the new value. */
- if (helpers[tmp_idx].ref->ctrl == master)
- new_auto_val = cs->controls[tmp_idx].value;
- tmp_idx = helpers[tmp_idx].next;
- } while (tmp_idx);
- /* If the new value == the manual value, then copy
- the current volatile values. */
- if (new_auto_val == master->manual_mode_value)
- update_from_auto_cluster(master);
- }
-
- /* Copy the new caller-supplied control values.
- user_to_new() sets 'is_new' to 1. */
- do {
- struct v4l2_ctrl *ctrl = helpers[idx].ref->ctrl;
-
- ret = user_to_new(cs->controls + idx, ctrl);
- if (!ret && ctrl->is_ptr) {
- ret = validate_new(ctrl, ctrl->p_new);
- if (ret)
- dprintk(vdev,
- "failed to validate control %s (%d)\n",
- v4l2_ctrl_get_name(ctrl->id), ret);
- }
- idx = helpers[idx].next;
- } while (!ret && idx);
-
- if (!ret)
- ret = try_or_set_cluster(fh, master,
- !hdl->req_obj.req && set, 0);
- if (!ret && hdl->req_obj.req && set) {
- for (j = 0; j < master->ncontrols; j++) {
- struct v4l2_ctrl_ref *ref =
- find_ref(hdl, master->cluster[j]->id);
-
- new_to_req(ref);
- }
- }
-
- /* Copy the new values back to userspace. */
- if (!ret) {
- idx = i;
- do {
- ret = new_to_user(cs->controls + idx,
- helpers[idx].ref->ctrl);
- idx = helpers[idx].next;
- } while (!ret && idx);
- }
- v4l2_ctrl_unlock(master);
- }
-
- if (cs->count > ARRAY_SIZE(helper))
- kvfree(helpers);
- return ret;
-}
-
-static int try_set_ext_ctrls(struct v4l2_fh *fh,
- struct v4l2_ctrl_handler *hdl,
- struct video_device *vdev,
- struct media_device *mdev,
- struct v4l2_ext_controls *cs, bool set)
-{
- struct media_request_object *obj = NULL;
- struct media_request *req = NULL;
- int ret;
-
- if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL) {
- if (!mdev) {
- dprintk(vdev, "%s: missing media device\n",
- video_device_node_name(vdev));
- return -EINVAL;
- }
-
- if (cs->request_fd < 0) {
- dprintk(vdev, "%s: invalid request fd %d\n",
- video_device_node_name(vdev), cs->request_fd);
- return -EINVAL;
- }
-
- req = media_request_get_by_fd(mdev, cs->request_fd);
- if (IS_ERR(req)) {
- dprintk(vdev, "%s: cannot find request fd %d\n",
- video_device_node_name(vdev), cs->request_fd);
- return PTR_ERR(req);
- }
-
- ret = media_request_lock_for_update(req);
- if (ret) {
- dprintk(vdev, "%s: cannot lock request fd %d\n",
- video_device_node_name(vdev), cs->request_fd);
- media_request_put(req);
- return ret;
- }
-
- obj = v4l2_ctrls_find_req_obj(hdl, req, set);
- if (IS_ERR(obj)) {
- dprintk(vdev,
- "%s: cannot find request object for request fd %d\n",
- video_device_node_name(vdev),
- cs->request_fd);
- media_request_unlock_for_update(req);
- media_request_put(req);
- return PTR_ERR(obj);
- }
- hdl = container_of(obj, struct v4l2_ctrl_handler,
- req_obj);
- }
-
- ret = try_set_ext_ctrls_common(fh, hdl, cs, vdev, set);
- if (ret)
- dprintk(vdev,
- "%s: try_set_ext_ctrls_common failed (%d)\n",
- video_device_node_name(vdev), ret);
-
- if (obj) {
- media_request_unlock_for_update(req);
- media_request_object_put(obj);
- media_request_put(req);
- }
-
- return ret;
-}
-
-int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl,
- struct video_device *vdev,
- struct media_device *mdev,
- struct v4l2_ext_controls *cs)
-{
- return try_set_ext_ctrls(NULL, hdl, vdev, mdev, cs, false);
-}
-EXPORT_SYMBOL(v4l2_try_ext_ctrls);
-
-int v4l2_s_ext_ctrls(struct v4l2_fh *fh,
- struct v4l2_ctrl_handler *hdl,
- struct video_device *vdev,
- struct media_device *mdev,
- struct v4l2_ext_controls *cs)
-{
- return try_set_ext_ctrls(fh, hdl, vdev, mdev, cs, true);
-}
-EXPORT_SYMBOL(v4l2_s_ext_ctrls);
-
-/* Helper function for VIDIOC_S_CTRL compatibility */
-static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
-{
- struct v4l2_ctrl *master = ctrl->cluster[0];
- int ret;
- int i;
-
- /* Reset the 'is_new' flags of the cluster */
- for (i = 0; i < master->ncontrols; i++)
- if (master->cluster[i])
- master->cluster[i]->is_new = 0;
-
- ret = validate_new(ctrl, ctrl->p_new);
- if (ret)
- return ret;
-
- /* For autoclusters with volatiles that are switched from auto to
- manual mode we have to update the current volatile values since
- those will become the initial manual values after such a switch. */
- if (master->is_auto && master->has_volatiles && ctrl == master &&
- !is_cur_manual(master) && ctrl->val == master->manual_mode_value)
- update_from_auto_cluster(master);
-
- ctrl->is_new = 1;
- return try_or_set_cluster(fh, master, true, ch_flags);
-}
-
-/* Helper function for VIDIOC_S_CTRL compatibility */
-static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
- struct v4l2_ext_control *c)
-{
- int ret;
-
- v4l2_ctrl_lock(ctrl);
- user_to_new(c, ctrl);
- ret = set_ctrl(fh, ctrl, 0);
- if (!ret)
- cur_to_user(c, ctrl);
- v4l2_ctrl_unlock(ctrl);
- return ret;
-}
-
-int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
- struct v4l2_control *control)
-{
- struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
- struct v4l2_ext_control c = { control->id };
- int ret;
-
- if (ctrl == NULL || !ctrl->is_int)
- return -EINVAL;
-
- if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
- return -EACCES;
-
- c.value = control->value;
- ret = set_ctrl_lock(fh, ctrl, &c);
- control->value = c.value;
- return ret;
-}
-EXPORT_SYMBOL(v4l2_s_ctrl);
-
-int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
-{
- lockdep_assert_held(ctrl->handler->lock);
-
- /* It's a driver bug if this happens. */
- if (WARN_ON(!ctrl->is_int))
- return -EINVAL;
- ctrl->val = val;
- return set_ctrl(NULL, ctrl, 0);
-}
-EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl);
-
-int __v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
-{
- lockdep_assert_held(ctrl->handler->lock);
-
- /* It's a driver bug if this happens. */
- if (WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64))
- return -EINVAL;
- *ctrl->p_new.p_s64 = val;
- return set_ctrl(NULL, ctrl, 0);
-}
-EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_int64);
-
-int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s)
-{
- lockdep_assert_held(ctrl->handler->lock);
-
- /* It's a driver bug if this happens. */
- if (WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING))
- return -EINVAL;
- strscpy(ctrl->p_new.p_char, s, ctrl->maximum + 1);
- return set_ctrl(NULL, ctrl, 0);
-}
-EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string);
-
-int __v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl,
- enum v4l2_ctrl_type type, const void *p)
-{
- lockdep_assert_held(ctrl->handler->lock);
-
- /* It's a driver bug if this happens. */
- if (WARN_ON(ctrl->type != type))
- return -EINVAL;
- memcpy(ctrl->p_new.p, p, ctrl->elems * ctrl->elem_size);
- return set_ctrl(NULL, ctrl, 0);
-}
-EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_compound);
-
-void v4l2_ctrl_request_complete(struct media_request *req,
- struct v4l2_ctrl_handler *main_hdl)
-{
- struct media_request_object *obj;
- struct v4l2_ctrl_handler *hdl;
- struct v4l2_ctrl_ref *ref;
-
- if (!req || !main_hdl)
- return;
-
- /*
- * Note that it is valid if nothing was found. It means
- * that this request doesn't have any controls and so just
- * wants to leave the controls unchanged.
- */
- obj = media_request_object_find(req, &req_ops, main_hdl);
- if (!obj)
- return;
- hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
-
- list_for_each_entry(ref, &hdl->ctrl_refs, node) {
- struct v4l2_ctrl *ctrl = ref->ctrl;
- struct v4l2_ctrl *master = ctrl->cluster[0];
- unsigned int i;
-
- if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
- v4l2_ctrl_lock(master);
- /* g_volatile_ctrl will update the current control values */
- for (i = 0; i < master->ncontrols; i++)
- cur_to_new(master->cluster[i]);
- call_op(master, g_volatile_ctrl);
- new_to_req(ref);
- v4l2_ctrl_unlock(master);
- continue;
- }
- if (ref->valid_p_req)
- continue;
-
- /* Copy the current control value into the request */
- v4l2_ctrl_lock(ctrl);
- cur_to_req(ref);
- v4l2_ctrl_unlock(ctrl);
- }
-
- mutex_lock(main_hdl->lock);
- WARN_ON(!hdl->request_is_queued);
- list_del_init(&hdl->requests_queued);
- hdl->request_is_queued = false;
- mutex_unlock(main_hdl->lock);
- media_request_object_complete(obj);
- media_request_object_put(obj);
-}
-EXPORT_SYMBOL(v4l2_ctrl_request_complete);
-
-int v4l2_ctrl_request_setup(struct media_request *req,
- struct v4l2_ctrl_handler *main_hdl)
-{
- struct media_request_object *obj;
- struct v4l2_ctrl_handler *hdl;
- struct v4l2_ctrl_ref *ref;
- int ret = 0;
-
- if (!req || !main_hdl)
- return 0;
-
- if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
- return -EBUSY;
-
- /*
- * Note that it is valid if nothing was found. It means
- * that this request doesn't have any controls and so just
- * wants to leave the controls unchanged.
- */
- obj = media_request_object_find(req, &req_ops, main_hdl);
- if (!obj)
- return 0;
- if (obj->completed) {
- media_request_object_put(obj);
- return -EBUSY;
- }
- hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
-
- list_for_each_entry(ref, &hdl->ctrl_refs, node)
- ref->req_done = false;
-
- list_for_each_entry(ref, &hdl->ctrl_refs, node) {
- struct v4l2_ctrl *ctrl = ref->ctrl;
- struct v4l2_ctrl *master = ctrl->cluster[0];
- bool have_new_data = false;
- int i;
-
- /*
- * Skip if this control was already handled by a cluster.
- * Skip button controls and read-only controls.
- */
- if (ref->req_done || (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
- continue;
-
- v4l2_ctrl_lock(master);
- for (i = 0; i < master->ncontrols; i++) {
- if (master->cluster[i]) {
- struct v4l2_ctrl_ref *r =
- find_ref(hdl, master->cluster[i]->id);
-
- if (r->valid_p_req) {
- have_new_data = true;
- break;
- }
- }
- }
- if (!have_new_data) {
- v4l2_ctrl_unlock(master);
- continue;
- }
-
- for (i = 0; i < master->ncontrols; i++) {
- if (master->cluster[i]) {
- struct v4l2_ctrl_ref *r =
- find_ref(hdl, master->cluster[i]->id);
-
- req_to_new(r);
- master->cluster[i]->is_new = 1;
- r->req_done = true;
- }
- }
- /*
- * For volatile autoclusters that are currently in auto mode
- * we need to discover if it will be set to manual mode.
- * If so, then we have to copy the current volatile values
- * first since those will become the new manual values (which
- * may be overwritten by explicit new values from this set
- * of controls).
- */
- if (master->is_auto && master->has_volatiles &&
- !is_cur_manual(master)) {
- s32 new_auto_val = *master->p_new.p_s32;
-
- /*
- * If the new value == the manual value, then copy
- * the current volatile values.
- */
- if (new_auto_val == master->manual_mode_value)
- update_from_auto_cluster(master);
- }
-
- ret = try_or_set_cluster(NULL, master, true, 0);
- v4l2_ctrl_unlock(master);
-
- if (ret)
- break;
- }
-
- media_request_object_put(obj);
- return ret;
-}
-EXPORT_SYMBOL(v4l2_ctrl_request_setup);
-
-void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv)
-{
- if (ctrl == NULL)
- return;
- if (notify == NULL) {
- ctrl->call_notify = 0;
- return;
- }
- if (WARN_ON(ctrl->handler->notify && ctrl->handler->notify != notify))
- return;
- ctrl->handler->notify = notify;
- ctrl->handler->notify_priv = priv;
- ctrl->call_notify = 1;
-}
-EXPORT_SYMBOL(v4l2_ctrl_notify);
-
-int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
- s64 min, s64 max, u64 step, s64 def)
-{
- bool value_changed;
- bool range_changed = false;
- int ret;
-
- lockdep_assert_held(ctrl->handler->lock);
-
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_INTEGER:
- case V4L2_CTRL_TYPE_INTEGER64:
- case V4L2_CTRL_TYPE_BOOLEAN:
- case V4L2_CTRL_TYPE_MENU:
- case V4L2_CTRL_TYPE_INTEGER_MENU:
- case V4L2_CTRL_TYPE_BITMASK:
- case V4L2_CTRL_TYPE_U8:
- case V4L2_CTRL_TYPE_U16:
- case V4L2_CTRL_TYPE_U32:
- if (ctrl->is_array)
- return -EINVAL;
- ret = check_range(ctrl->type, min, max, step, def);
- if (ret)
- return ret;
- break;
- default:
- return -EINVAL;
- }
- if ((ctrl->minimum != min) || (ctrl->maximum != max) ||
- (ctrl->step != step) || ctrl->default_value != def) {
- range_changed = true;
- ctrl->minimum = min;
- ctrl->maximum = max;
- ctrl->step = step;
- ctrl->default_value = def;
- }
- cur_to_new(ctrl);
- if (validate_new(ctrl, ctrl->p_new)) {
- if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
- *ctrl->p_new.p_s64 = def;
- else
- *ctrl->p_new.p_s32 = def;
- }
-
- if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
- value_changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64;
- else
- value_changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32;
- if (value_changed)
- ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
- else if (range_changed)
- send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
- return ret;
-}
-EXPORT_SYMBOL(__v4l2_ctrl_modify_range);
-
-static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
-{
- struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
-
- if (ctrl == NULL)
- return -EINVAL;
-
- v4l2_ctrl_lock(ctrl);
- list_add_tail(&sev->node, &ctrl->ev_subs);
- if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS &&
- (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL)) {
- struct v4l2_event ev;
- u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
-
- if (!(ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY))
- changes |= V4L2_EVENT_CTRL_CH_VALUE;
- fill_event(&ev, ctrl, changes);
- /* Mark the queue as active, allowing this initial
- event to be accepted. */
- sev->elems = elems;
- v4l2_event_queue_fh(sev->fh, &ev);
- }
- v4l2_ctrl_unlock(ctrl);
- return 0;
-}
-
-static void v4l2_ctrl_del_event(struct v4l2_subscribed_event *sev)
-{
- struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
-
- if (ctrl == NULL)
- return;
-
- v4l2_ctrl_lock(ctrl);
- list_del(&sev->node);
- v4l2_ctrl_unlock(ctrl);
-}
-
-void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new)
-{
- u32 old_changes = old->u.ctrl.changes;
-
- old->u.ctrl = new->u.ctrl;
- old->u.ctrl.changes |= old_changes;
-}
-EXPORT_SYMBOL(v4l2_ctrl_replace);
-
-void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new)
-{
- new->u.ctrl.changes |= old->u.ctrl.changes;
-}
-EXPORT_SYMBOL(v4l2_ctrl_merge);
-
-const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops = {
- .add = v4l2_ctrl_add_event,
- .del = v4l2_ctrl_del_event,
- .replace = v4l2_ctrl_replace,
- .merge = v4l2_ctrl_merge,
-};
-EXPORT_SYMBOL(v4l2_ctrl_sub_ev_ops);
-
-int v4l2_ctrl_log_status(struct file *file, void *fh)
-{
- struct video_device *vfd = video_devdata(file);
- struct v4l2_fh *vfh = file->private_data;
-
- if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev)
- v4l2_ctrl_handler_log_status(vfh->ctrl_handler,
- vfd->v4l2_dev->name);
- return 0;
-}
-EXPORT_SYMBOL(v4l2_ctrl_log_status);
-
-int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub)
-{
- if (sub->type == V4L2_EVENT_CTRL)
- return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops);
- return -EINVAL;
-}
-EXPORT_SYMBOL(v4l2_ctrl_subscribe_event);
-
-int v4l2_ctrl_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
- struct v4l2_event_subscription *sub)
-{
- if (!sd->ctrl_handler)
- return -EINVAL;
- return v4l2_ctrl_subscribe_event(fh, sub);
-}
-EXPORT_SYMBOL(v4l2_ctrl_subdev_subscribe_event);
-
-__poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct v4l2_fh *fh = file->private_data;
-
- poll_wait(file, &fh->wait, wait);
- if (v4l2_event_pending(fh))
- return EPOLLPRI;
- return 0;
-}
-EXPORT_SYMBOL(v4l2_ctrl_poll);
-
-int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_ops *ctrl_ops,
- const struct v4l2_fwnode_device_properties *p)
-{
- if (p->orientation != V4L2_FWNODE_PROPERTY_UNSET) {
- u32 orientation_ctrl;
-
- switch (p->orientation) {
- case V4L2_FWNODE_ORIENTATION_FRONT:
- orientation_ctrl = V4L2_CAMERA_ORIENTATION_FRONT;
- break;
- case V4L2_FWNODE_ORIENTATION_BACK:
- orientation_ctrl = V4L2_CAMERA_ORIENTATION_BACK;
- break;
- case V4L2_FWNODE_ORIENTATION_EXTERNAL:
- orientation_ctrl = V4L2_CAMERA_ORIENTATION_EXTERNAL;
- break;
- default:
- return -EINVAL;
- }
- if (!v4l2_ctrl_new_std_menu(hdl, ctrl_ops,
- V4L2_CID_CAMERA_ORIENTATION,
- V4L2_CAMERA_ORIENTATION_EXTERNAL, 0,
- orientation_ctrl))
- return hdl->error;
- }
-
- if (p->rotation != V4L2_FWNODE_PROPERTY_UNSET) {
- if (!v4l2_ctrl_new_std(hdl, ctrl_ops,
- V4L2_CID_CAMERA_SENSOR_ROTATION,
- p->rotation, p->rotation, 1,
- p->rotation))
- return hdl->error;
- }
-
- return hdl->error;
-}
-EXPORT_SYMBOL(v4l2_ctrl_new_fwnode_properties);
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 7d0edf3530be..d03ace324db0 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -39,8 +39,6 @@
__func__, ##arg); \
} while (0)
-static struct dentry *v4l2_debugfs_dir;
-
/*
* sysfs stuff
*/
@@ -520,9 +518,8 @@ static int get_index(struct video_device *vdev)
return find_first_zero_bit(used, VIDEO_NUM_DEVICES);
}
-#define SET_VALID_IOCTL(ops, cmd, op) \
- if (ops->op) \
- set_bit(_IOC_NR(cmd), valid_ioctls)
+#define SET_VALID_IOCTL(ops, cmd, op) \
+ do { if ((ops)->op) set_bit(_IOC_NR(cmd), valid_ioctls); } while (0)
/* This determines which ioctls are actually implemented in the driver.
It's a one-time thing which simplifies video_ioctl2 as it can just do
@@ -1121,8 +1118,6 @@ static int __init videodev_init(void)
return -EIO;
}
- v4l2_debugfs_dir = debugfs_create_dir("video4linux", NULL);
- v4l2_async_debug_init(v4l2_debugfs_dir);
return 0;
}
@@ -1130,7 +1125,6 @@ static void __exit videodev_exit(void)
{
dev_t dev = MKDEV(VIDEO_MAJOR, 0);
- debugfs_remove_recursive(v4l2_debugfs_dir);
class_unregister(&video_class);
unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
}
diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c
index caad58bde326..c5ce9f11ad7b 100644
--- a/drivers/media/v4l2-core/v4l2-event.c
+++ b/drivers/media/v4l2-core/v4l2-event.c
@@ -18,7 +18,7 @@
#include <linux/slab.h>
#include <linux/export.h>
-static unsigned sev_pos(const struct v4l2_subscribed_event *sev, unsigned idx)
+static unsigned int sev_pos(const struct v4l2_subscribed_event *sev, unsigned int idx)
{
idx += sev->first;
return idx >= sev->elems ? idx - sev->elems : idx;
@@ -221,12 +221,12 @@ static void __v4l2_event_unsubscribe(struct v4l2_subscribed_event *sev)
}
int v4l2_event_subscribe(struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub, unsigned elems,
+ const struct v4l2_event_subscription *sub, unsigned int elems,
const struct v4l2_subscribed_event_ops *ops)
{
struct v4l2_subscribed_event *sev, *found_ev;
unsigned long flags;
- unsigned i;
+ unsigned int i;
int ret = 0;
if (sub->type == V4L2_EVENT_ALL)
diff --git a/drivers/media/v4l2-core/v4l2-fh.c b/drivers/media/v4l2-core/v4l2-fh.c
index 684574f58e82..90eec79ee995 100644
--- a/drivers/media/v4l2-core/v4l2-fh.c
+++ b/drivers/media/v4l2-core/v4l2-fh.c
@@ -96,6 +96,7 @@ int v4l2_fh_release(struct file *filp)
v4l2_fh_del(fh);
v4l2_fh_exit(fh);
kfree(fh);
+ filp->private_data = NULL;
}
return 0;
}
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 2673f51aafa4..05d5db3d85e5 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -3072,8 +3072,8 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
static unsigned int video_translate_cmd(unsigned int cmd)
{
+#if !defined(CONFIG_64BIT) && defined(CONFIG_COMPAT_32BIT_TIME)
switch (cmd) {
-#ifdef CONFIG_COMPAT_32BIT_TIME
case VIDIOC_DQEVENT_TIME32:
return VIDIOC_DQEVENT;
case VIDIOC_QUERYBUF_TIME32:
@@ -3084,8 +3084,8 @@ static unsigned int video_translate_cmd(unsigned int cmd)
return VIDIOC_DQBUF;
case VIDIOC_PREPARE_BUF_TIME32:
return VIDIOC_PREPARE_BUF;
-#endif
}
+#endif
if (in_compat_syscall())
return v4l2_compat_translate_cmd(cmd);
@@ -3124,10 +3124,12 @@ static int video_get_user(void __user *arg, void *parg,
if (copy_from_user(parg, (void __user *)arg, n))
err = -EFAULT;
} else if (in_compat_syscall()) {
+ memset(parg, 0, n);
err = v4l2_compat_get_user(arg, parg, cmd);
} else {
+ memset(parg, 0, n);
+#if !defined(CONFIG_64BIT) && defined(CONFIG_COMPAT_32BIT_TIME)
switch (cmd) {
-#ifdef CONFIG_COMPAT_32BIT_TIME
case VIDIOC_QUERYBUF_TIME32:
case VIDIOC_QBUF_TIME32:
case VIDIOC_DQBUF_TIME32:
@@ -3140,23 +3142,23 @@ static int video_get_user(void __user *arg, void *parg,
*vb = (struct v4l2_buffer) {
.index = vb32.index,
- .type = vb32.type,
- .bytesused = vb32.bytesused,
- .flags = vb32.flags,
- .field = vb32.field,
- .timestamp.tv_sec = vb32.timestamp.tv_sec,
- .timestamp.tv_usec = vb32.timestamp.tv_usec,
- .timecode = vb32.timecode,
- .sequence = vb32.sequence,
- .memory = vb32.memory,
- .m.userptr = vb32.m.userptr,
- .length = vb32.length,
- .request_fd = vb32.request_fd,
+ .type = vb32.type,
+ .bytesused = vb32.bytesused,
+ .flags = vb32.flags,
+ .field = vb32.field,
+ .timestamp.tv_sec = vb32.timestamp.tv_sec,
+ .timestamp.tv_usec = vb32.timestamp.tv_usec,
+ .timecode = vb32.timecode,
+ .sequence = vb32.sequence,
+ .memory = vb32.memory,
+ .m.userptr = vb32.m.userptr,
+ .length = vb32.length,
+ .request_fd = vb32.request_fd,
};
break;
}
-#endif
}
+#endif
}
/* zero out anything we don't copy from userspace */
@@ -3181,8 +3183,8 @@ static int video_put_user(void __user *arg, void *parg,
if (in_compat_syscall())
return v4l2_compat_put_user(arg, parg, cmd);
+#if !defined(CONFIG_64BIT) && defined(CONFIG_COMPAT_32BIT_TIME)
switch (cmd) {
-#ifdef CONFIG_COMPAT_32BIT_TIME
case VIDIOC_DQEVENT_TIME32: {
struct v4l2_event *ev = parg;
struct v4l2_event_time32 ev32;
@@ -3230,8 +3232,8 @@ static int video_put_user(void __user *arg, void *parg,
return -EFAULT;
break;
}
-#endif
}
+#endif
return 0;
}
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 956dafab43d4..5d27a27cc2f2 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -26,19 +26,21 @@
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
{
- if (sd->entity.num_pads) {
- fh->pad = v4l2_subdev_alloc_pad_config(sd);
- if (fh->pad == NULL)
- return -ENOMEM;
- }
+ struct v4l2_subdev_state *state;
+
+ state = v4l2_subdev_alloc_state(sd);
+ if (IS_ERR(state))
+ return PTR_ERR(state);
+
+ fh->state = state;
return 0;
}
static void subdev_fh_free(struct v4l2_subdev_fh *fh)
{
- v4l2_subdev_free_pad_config(fh->pad);
- fh->pad = NULL;
+ v4l2_subdev_free_state(fh->state);
+ fh->state = NULL;
}
static int subdev_open(struct file *file)
@@ -146,63 +148,63 @@ static inline int check_pad(struct v4l2_subdev *sd, u32 pad)
return 0;
}
-static int check_cfg(u32 which, struct v4l2_subdev_pad_config *cfg)
+static int check_state_pads(u32 which, struct v4l2_subdev_state *state)
{
- if (which == V4L2_SUBDEV_FORMAT_TRY && !cfg)
+ if (which == V4L2_SUBDEV_FORMAT_TRY && (!state || !state->pads))
return -EINVAL;
return 0;
}
static inline int check_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
if (!format)
return -EINVAL;
return check_which(format->which) ? : check_pad(sd, format->pad) ? :
- check_cfg(format->which, cfg);
+ check_state_pads(format->which, state);
}
static int call_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
- return check_format(sd, cfg, format) ? :
- sd->ops->pad->get_fmt(sd, cfg, format);
+ return check_format(sd, state, format) ? :
+ sd->ops->pad->get_fmt(sd, state, format);
}
static int call_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
- return check_format(sd, cfg, format) ? :
- sd->ops->pad->set_fmt(sd, cfg, format);
+ return check_format(sd, state, format) ? :
+ sd->ops->pad->set_fmt(sd, state, format);
}
static int call_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (!code)
return -EINVAL;
return check_which(code->which) ? : check_pad(sd, code->pad) ? :
- check_cfg(code->which, cfg) ? :
- sd->ops->pad->enum_mbus_code(sd, cfg, code);
+ check_state_pads(code->which, state) ? :
+ sd->ops->pad->enum_mbus_code(sd, state, code);
}
static int call_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (!fse)
return -EINVAL;
return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
- check_cfg(fse->which, cfg) ? :
- sd->ops->pad->enum_frame_size(sd, cfg, fse);
+ check_state_pads(fse->which, state) ? :
+ sd->ops->pad->enum_frame_size(sd, state, fse);
}
static inline int check_frame_interval(struct v4l2_subdev *sd,
@@ -229,42 +231,42 @@ static int call_s_frame_interval(struct v4l2_subdev *sd,
}
static int call_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *state,
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);
+ check_state_pads(fie->which, state) ? :
+ sd->ops->pad->enum_frame_interval(sd, state, fie);
}
static inline int check_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_selection *sel)
{
if (!sel)
return -EINVAL;
return check_which(sel->which) ? : check_pad(sd, sel->pad) ? :
- check_cfg(sel->which, cfg);
+ check_state_pads(sel->which, state);
}
static int call_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_selection *sel)
{
- return check_selection(sd, cfg, sel) ? :
- sd->ops->pad->get_selection(sd, cfg, sel);
+ return check_selection(sd, state, sel) ? :
+ sd->ops->pad->get_selection(sd, state, sel);
}
static int call_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_selection *sel)
{
- return check_selection(sd, cfg, sel) ? :
- sd->ops->pad->set_selection(sd, cfg, sel);
+ return check_selection(sd, state, sel) ? :
+ sd->ops->pad->set_selection(sd, state, sel);
}
static inline int check_edid(struct v4l2_subdev *sd,
@@ -428,30 +430,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
- case VIDIOC_DQEVENT_TIME32: {
- struct v4l2_event_time32 *ev32 = arg;
- struct v4l2_event ev = { };
-
- if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
- return -ENOIOCTLCMD;
-
- rval = v4l2_event_dequeue(vfh, &ev, file->f_flags & O_NONBLOCK);
-
- *ev32 = (struct v4l2_event_time32) {
- .type = ev.type,
- .pending = ev.pending,
- .sequence = ev.sequence,
- .timestamp.tv_sec = ev.timestamp.tv_sec,
- .timestamp.tv_nsec = ev.timestamp.tv_nsec,
- .id = ev.id,
- };
-
- memcpy(&ev32->u, &ev.u, sizeof(ev.u));
- memcpy(&ev32->reserved, &ev.reserved, sizeof(ev.reserved));
-
- return rval;
- }
-
case VIDIOC_SUBSCRIBE_EVENT:
return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
@@ -506,7 +484,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
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);
+ return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->state, format);
}
case VIDIOC_SUBDEV_S_FMT: {
@@ -517,7 +495,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
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);
+ return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->state, format);
}
case VIDIOC_SUBDEV_G_CROP: {
@@ -531,7 +509,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
sel.target = V4L2_SEL_TGT_CROP;
rval = v4l2_subdev_call(
- sd, pad, get_selection, subdev_fh->pad, &sel);
+ sd, pad, get_selection, subdev_fh->state, &sel);
crop->rect = sel.r;
@@ -553,7 +531,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
sel.r = crop->rect;
rval = v4l2_subdev_call(
- sd, pad, set_selection, subdev_fh->pad, &sel);
+ sd, pad, set_selection, subdev_fh->state, &sel);
crop->rect = sel.r;
@@ -564,7 +542,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_subdev_mbus_code_enum *code = arg;
memset(code->reserved, 0, sizeof(code->reserved));
- return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad,
+ return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->state,
code);
}
@@ -572,7 +550,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_subdev_frame_size_enum *fse = arg;
memset(fse->reserved, 0, sizeof(fse->reserved));
- return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad,
+ return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->state,
fse);
}
@@ -597,7 +575,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_subdev_frame_interval_enum *fie = arg;
memset(fie->reserved, 0, sizeof(fie->reserved));
- return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad,
+ return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->state,
fie);
}
@@ -606,7 +584,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
memset(sel->reserved, 0, sizeof(sel->reserved));
return v4l2_subdev_call(
- sd, pad, get_selection, subdev_fh->pad, sel);
+ sd, pad, get_selection, subdev_fh->state, sel);
}
case VIDIOC_SUBDEV_S_SELECTION: {
@@ -617,7 +595,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
memset(sel->reserved, 0, sizeof(sel->reserved));
return v4l2_subdev_call(
- sd, pad, set_selection, subdev_fh->pad, sel);
+ sd, pad, set_selection, subdev_fh->state, sel);
}
case VIDIOC_G_EDID: {
@@ -892,35 +870,51 @@ int v4l2_subdev_link_validate(struct media_link *link)
}
EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
-struct v4l2_subdev_pad_config *
-v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd)
+struct v4l2_subdev_state *v4l2_subdev_alloc_state(struct v4l2_subdev *sd)
{
- struct v4l2_subdev_pad_config *cfg;
+ struct v4l2_subdev_state *state;
int ret;
- if (!sd->entity.num_pads)
- return NULL;
-
- cfg = kvmalloc_array(sd->entity.num_pads, sizeof(*cfg),
- GFP_KERNEL | __GFP_ZERO);
- if (!cfg)
- return NULL;
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return ERR_PTR(-ENOMEM);
- ret = v4l2_subdev_call(sd, pad, init_cfg, cfg);
- if (ret < 0 && ret != -ENOIOCTLCMD) {
- kvfree(cfg);
- return NULL;
+ if (sd->entity.num_pads) {
+ state->pads = kvmalloc_array(sd->entity.num_pads,
+ sizeof(*state->pads),
+ GFP_KERNEL | __GFP_ZERO);
+ if (!state->pads) {
+ ret = -ENOMEM;
+ goto err;
+ }
}
- return cfg;
+ ret = v4l2_subdev_call(sd, pad, init_cfg, state);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ goto err;
+
+ return state;
+
+err:
+ if (state && state->pads)
+ kvfree(state->pads);
+
+ kfree(state);
+
+ return ERR_PTR(ret);
}
-EXPORT_SYMBOL_GPL(v4l2_subdev_alloc_pad_config);
+EXPORT_SYMBOL_GPL(v4l2_subdev_alloc_state);
-void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg)
+void v4l2_subdev_free_state(struct v4l2_subdev_state *state)
{
- kvfree(cfg);
+ if (!state)
+ return;
+
+ kvfree(state->pads);
+ kfree(state);
}
-EXPORT_SYMBOL_GPL(v4l2_subdev_free_pad_config);
+EXPORT_SYMBOL_GPL(v4l2_subdev_free_state);
+
#endif /* CONFIG_MEDIA_CONTROLLER */
void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c
index 8dd0562de287..f75e5eedeee0 100644
--- a/drivers/media/v4l2-core/videobuf-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf-dma-sg.c
@@ -423,7 +423,6 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
videobuf_queue_unlock(q);
kfree(map);
}
- return;
}
/*
diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c
index 14386d0b5f57..c267283b01fd 100644
--- a/drivers/memory/atmel-ebi.c
+++ b/drivers/memory/atmel-ebi.c
@@ -600,8 +600,10 @@ static int atmel_ebi_probe(struct platform_device *pdev)
child);
ret = atmel_ebi_dev_disable(ebi, child);
- if (ret)
+ if (ret) {
+ of_node_put(child);
return ret;
+ }
}
}
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
index f7825eef5894..762d0c0f0716 100644
--- a/drivers/memory/emif.c
+++ b/drivers/memory/emif.c
@@ -41,7 +41,6 @@
* @node: node in the device list
* @base: base address of memory-mapped IO registers.
* @dev: device pointer.
- * @addressing table with addressing information from the spec
* @regs_cache: An array of 'struct emif_regs' that stores
* calculated register values for different
* frequencies, to avoid re-calculating them on
@@ -61,7 +60,6 @@ struct emif_data {
unsigned long irq_state;
void __iomem *base;
struct device *dev;
- const struct lpddr2_addressing *addressing;
struct emif_regs *regs_cache[EMIF_MAX_NUM_FREQUENCIES];
struct emif_regs *curr_regs;
struct emif_platform_data *plat_data;
@@ -72,7 +70,6 @@ struct emif_data {
static struct emif_data *emif1;
static DEFINE_SPINLOCK(emif_lock);
static unsigned long irq_state;
-static u32 t_ck; /* DDR clock period in ps */
static LIST_HEAD(device_list);
#ifdef CONFIG_DEBUG_FS
@@ -170,15 +167,6 @@ static inline void __exit emif_debugfs_exit(struct emif_data *emif)
#endif
/*
- * Calculate the period of DDR clock from frequency value
- */
-static void set_ddr_clk_period(u32 freq)
-{
- /* Divide 10^12 by frequency to get period in ps */
- t_ck = (u32)DIV_ROUND_UP_ULL(1000000000000ull, freq);
-}
-
-/*
* Get bus width used by EMIF. Note that this may be different from the
* bus width of the DDR devices used. For instance two 16-bit DDR devices
* may be connected to a given CS of EMIF. In this case bus width as far
@@ -196,19 +184,6 @@ static u32 get_emif_bus_width(struct emif_data *emif)
return width;
}
-/*
- * Get the CL from SDRAM_CONFIG register
- */
-static u32 get_cl(struct emif_data *emif)
-{
- u32 cl;
- void __iomem *base = emif->base;
-
- cl = (readl(base + EMIF_SDRAM_CONFIG) & CL_MASK) >> CL_SHIFT;
-
- return cl;
-}
-
static void set_lpmode(struct emif_data *emif, u8 lpmode)
{
u32 temp;
@@ -328,203 +303,6 @@ static const struct lpddr2_addressing *get_addressing_table(
return &lpddr2_jedec_addressing_table[index];
}
-/*
- * Find the the right timing table from the array of timing
- * tables of the device using DDR clock frequency
- */
-static const struct lpddr2_timings *get_timings_table(struct emif_data *emif,
- u32 freq)
-{
- u32 i, min, max, freq_nearest;
- const struct lpddr2_timings *timings = NULL;
- const struct lpddr2_timings *timings_arr = emif->plat_data->timings;
- struct device *dev = emif->dev;
-
- /* Start with a very high frequency - 1GHz */
- freq_nearest = 1000000000;
-
- /*
- * Find the timings table such that:
- * 1. the frequency range covers the required frequency(safe) AND
- * 2. the max_freq is closest to the required frequency(optimal)
- */
- for (i = 0; i < emif->plat_data->timings_arr_size; i++) {
- max = timings_arr[i].max_freq;
- min = timings_arr[i].min_freq;
- if ((freq >= min) && (freq <= max) && (max < freq_nearest)) {
- freq_nearest = max;
- timings = &timings_arr[i];
- }
- }
-
- if (!timings)
- dev_err(dev, "%s: couldn't find timings for - %dHz\n",
- __func__, freq);
-
- dev_dbg(dev, "%s: timings table: freq %d, speed bin freq %d\n",
- __func__, freq, freq_nearest);
-
- return timings;
-}
-
-static u32 get_sdram_ref_ctrl_shdw(u32 freq,
- const struct lpddr2_addressing *addressing)
-{
- u32 ref_ctrl_shdw = 0, val = 0, freq_khz, t_refi;
-
- /* Scale down frequency and t_refi to avoid overflow */
- freq_khz = freq / 1000;
- t_refi = addressing->tREFI_ns / 100;
-
- /*
- * refresh rate to be set is 'tREFI(in us) * freq in MHz
- * division by 10000 to account for change in units
- */
- val = t_refi * freq_khz / 10000;
- ref_ctrl_shdw |= val << REFRESH_RATE_SHIFT;
-
- return ref_ctrl_shdw;
-}
-
-static u32 get_sdram_tim_1_shdw(const struct lpddr2_timings *timings,
- const struct lpddr2_min_tck *min_tck,
- const struct lpddr2_addressing *addressing)
-{
- u32 tim1 = 0, val = 0;
-
- val = max(min_tck->tWTR, DIV_ROUND_UP(timings->tWTR, t_ck)) - 1;
- tim1 |= val << T_WTR_SHIFT;
-
- if (addressing->num_banks == B8)
- val = DIV_ROUND_UP(timings->tFAW, t_ck*4);
- else
- val = max(min_tck->tRRD, DIV_ROUND_UP(timings->tRRD, t_ck));
- tim1 |= (val - 1) << T_RRD_SHIFT;
-
- val = DIV_ROUND_UP(timings->tRAS_min + timings->tRPab, t_ck) - 1;
- tim1 |= val << T_RC_SHIFT;
-
- val = max(min_tck->tRASmin, DIV_ROUND_UP(timings->tRAS_min, t_ck));
- tim1 |= (val - 1) << T_RAS_SHIFT;
-
- val = max(min_tck->tWR, DIV_ROUND_UP(timings->tWR, t_ck)) - 1;
- tim1 |= val << T_WR_SHIFT;
-
- val = max(min_tck->tRCD, DIV_ROUND_UP(timings->tRCD, t_ck)) - 1;
- tim1 |= val << T_RCD_SHIFT;
-
- val = max(min_tck->tRPab, DIV_ROUND_UP(timings->tRPab, t_ck)) - 1;
- tim1 |= val << T_RP_SHIFT;
-
- return tim1;
-}
-
-static u32 get_sdram_tim_1_shdw_derated(const struct lpddr2_timings *timings,
- const struct lpddr2_min_tck *min_tck,
- const struct lpddr2_addressing *addressing)
-{
- u32 tim1 = 0, val = 0;
-
- val = max(min_tck->tWTR, DIV_ROUND_UP(timings->tWTR, t_ck)) - 1;
- tim1 = val << T_WTR_SHIFT;
-
- /*
- * tFAW is approximately 4 times tRRD. So add 1875*4 = 7500ps
- * to tFAW for de-rating
- */
- if (addressing->num_banks == B8) {
- val = DIV_ROUND_UP(timings->tFAW + 7500, 4 * t_ck) - 1;
- } else {
- val = DIV_ROUND_UP(timings->tRRD + 1875, t_ck);
- val = max(min_tck->tRRD, val) - 1;
- }
- tim1 |= val << T_RRD_SHIFT;
-
- val = DIV_ROUND_UP(timings->tRAS_min + timings->tRPab + 1875, t_ck);
- tim1 |= (val - 1) << T_RC_SHIFT;
-
- val = DIV_ROUND_UP(timings->tRAS_min + 1875, t_ck);
- val = max(min_tck->tRASmin, val) - 1;
- tim1 |= val << T_RAS_SHIFT;
-
- val = max(min_tck->tWR, DIV_ROUND_UP(timings->tWR, t_ck)) - 1;
- tim1 |= val << T_WR_SHIFT;
-
- val = max(min_tck->tRCD, DIV_ROUND_UP(timings->tRCD + 1875, t_ck));
- tim1 |= (val - 1) << T_RCD_SHIFT;
-
- val = max(min_tck->tRPab, DIV_ROUND_UP(timings->tRPab + 1875, t_ck));
- tim1 |= (val - 1) << T_RP_SHIFT;
-
- return tim1;
-}
-
-static u32 get_sdram_tim_2_shdw(const struct lpddr2_timings *timings,
- const struct lpddr2_min_tck *min_tck,
- const struct lpddr2_addressing *addressing,
- u32 type)
-{
- u32 tim2 = 0, val = 0;
-
- val = min_tck->tCKE - 1;
- tim2 |= val << T_CKE_SHIFT;
-
- val = max(min_tck->tRTP, DIV_ROUND_UP(timings->tRTP, t_ck)) - 1;
- tim2 |= val << T_RTP_SHIFT;
-
- /* tXSNR = tRFCab_ps + 10 ns(tRFCab_ps for LPDDR2). */
- val = DIV_ROUND_UP(addressing->tRFCab_ps + 10000, t_ck) - 1;
- tim2 |= val << T_XSNR_SHIFT;
-
- /* XSRD same as XSNR for LPDDR2 */
- tim2 |= val << T_XSRD_SHIFT;
-
- val = max(min_tck->tXP, DIV_ROUND_UP(timings->tXP, t_ck)) - 1;
- tim2 |= val << T_XP_SHIFT;
-
- return tim2;
-}
-
-static u32 get_sdram_tim_3_shdw(const struct lpddr2_timings *timings,
- const struct lpddr2_min_tck *min_tck,
- const struct lpddr2_addressing *addressing,
- u32 type, u32 ip_rev, u32 derated)
-{
- u32 tim3 = 0, val = 0, t_dqsck;
-
- val = timings->tRAS_max_ns / addressing->tREFI_ns - 1;
- val = val > 0xF ? 0xF : val;
- tim3 |= val << T_RAS_MAX_SHIFT;
-
- val = DIV_ROUND_UP(addressing->tRFCab_ps, t_ck) - 1;
- tim3 |= val << T_RFC_SHIFT;
-
- t_dqsck = (derated == EMIF_DERATED_TIMINGS) ?
- timings->tDQSCK_max_derated : timings->tDQSCK_max;
- if (ip_rev == EMIF_4D5)
- val = DIV_ROUND_UP(t_dqsck + 1000, t_ck) - 1;
- else
- val = DIV_ROUND_UP(t_dqsck, t_ck) - 1;
-
- tim3 |= val << T_TDQSCKMAX_SHIFT;
-
- val = DIV_ROUND_UP(timings->tZQCS, t_ck) - 1;
- tim3 |= val << ZQ_ZQCS_SHIFT;
-
- val = DIV_ROUND_UP(timings->tCKESR, t_ck);
- val = max(min_tck->tCKESR, val) - 1;
- tim3 |= val << T_CKESR_SHIFT;
-
- if (ip_rev == EMIF_4D5) {
- tim3 |= (EMIF_T_CSTA - 1) << T_CSTA_SHIFT;
-
- val = DIV_ROUND_UP(EMIF_T_PDLL_UL, 128) - 1;
- tim3 |= val << T_PDLL_UL_SHIFT;
- }
-
- return tim3;
-}
-
static u32 get_zq_config_reg(const struct lpddr2_addressing *addressing,
bool cs1_used, bool cal_resistors_per_cs)
{
@@ -589,117 +367,6 @@ static u32 get_temp_alert_config(const struct lpddr2_addressing *addressing,
return alert;
}
-static u32 get_read_idle_ctrl_shdw(u8 volt_ramp)
-{
- u32 idle = 0, val = 0;
-
- /*
- * Maximum value in normal conditions and increased frequency
- * when voltage is ramping
- */
- if (volt_ramp)
- val = READ_IDLE_INTERVAL_DVFS / t_ck / 64 - 1;
- else
- val = 0x1FF;
-
- /*
- * READ_IDLE_CTRL register in EMIF4D has same offset and fields
- * as DLL_CALIB_CTRL in EMIF4D5, so use the same shifts
- */
- idle |= val << DLL_CALIB_INTERVAL_SHIFT;
- idle |= EMIF_READ_IDLE_LEN_VAL << ACK_WAIT_SHIFT;
-
- return idle;
-}
-
-static u32 get_dll_calib_ctrl_shdw(u8 volt_ramp)
-{
- u32 calib = 0, val = 0;
-
- if (volt_ramp == DDR_VOLTAGE_RAMPING)
- val = DLL_CALIB_INTERVAL_DVFS / t_ck / 16 - 1;
- else
- val = 0; /* Disabled when voltage is stable */
-
- calib |= val << DLL_CALIB_INTERVAL_SHIFT;
- calib |= DLL_CALIB_ACK_WAIT_VAL << ACK_WAIT_SHIFT;
-
- return calib;
-}
-
-static u32 get_ddr_phy_ctrl_1_attilaphy_4d(const struct lpddr2_timings *timings,
- u32 freq, u8 RL)
-{
- u32 phy = EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY, val = 0;
-
- val = RL + DIV_ROUND_UP(timings->tDQSCK_max, t_ck) - 1;
- phy |= val << READ_LATENCY_SHIFT_4D;
-
- if (freq <= 100000000)
- val = EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY;
- else if (freq <= 200000000)
- val = EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY;
- else
- val = EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY;
-
- phy |= val << DLL_SLAVE_DLY_CTRL_SHIFT_4D;
-
- return phy;
-}
-
-static u32 get_phy_ctrl_1_intelliphy_4d5(u32 freq, u8 cl)
-{
- u32 phy = EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY, half_delay;
-
- /*
- * DLL operates at 266 MHz. If DDR frequency is near 266 MHz,
- * half-delay is not needed else set half-delay
- */
- if (freq >= 265000000 && freq < 267000000)
- half_delay = 0;
- else
- half_delay = 1;
-
- phy |= half_delay << DLL_HALF_DELAY_SHIFT_4D5;
- phy |= ((cl + DIV_ROUND_UP(EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS,
- t_ck) - 1) << READ_LATENCY_SHIFT_4D5);
-
- return phy;
-}
-
-static u32 get_ext_phy_ctrl_2_intelliphy_4d5(void)
-{
- u32 fifo_we_slave_ratio;
-
- fifo_we_slave_ratio = DIV_ROUND_CLOSEST(
- EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256, t_ck);
-
- return fifo_we_slave_ratio | fifo_we_slave_ratio << 11 |
- fifo_we_slave_ratio << 22;
-}
-
-static u32 get_ext_phy_ctrl_3_intelliphy_4d5(void)
-{
- u32 fifo_we_slave_ratio;
-
- fifo_we_slave_ratio = DIV_ROUND_CLOSEST(
- EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256, t_ck);
-
- return fifo_we_slave_ratio >> 10 | fifo_we_slave_ratio << 1 |
- fifo_we_slave_ratio << 12 | fifo_we_slave_ratio << 23;
-}
-
-static u32 get_ext_phy_ctrl_4_intelliphy_4d5(void)
-{
- u32 fifo_we_slave_ratio;
-
- fifo_we_slave_ratio = DIV_ROUND_CLOSEST(
- EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256, t_ck);
-
- return fifo_we_slave_ratio >> 9 | fifo_we_slave_ratio << 2 |
- fifo_we_slave_ratio << 13;
-}
-
static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev)
{
u32 pwr_mgmt_ctrl = 0, timeout;
@@ -822,51 +489,6 @@ static void get_temperature_level(struct emif_data *emif)
}
/*
- * Program EMIF shadow registers that are not dependent on temperature
- * or voltage
- */
-static void setup_registers(struct emif_data *emif, struct emif_regs *regs)
-{
- void __iomem *base = emif->base;
-
- writel(regs->sdram_tim2_shdw, base + EMIF_SDRAM_TIMING_2_SHDW);
- writel(regs->phy_ctrl_1_shdw, base + EMIF_DDR_PHY_CTRL_1_SHDW);
- writel(regs->pwr_mgmt_ctrl_shdw,
- base + EMIF_POWER_MANAGEMENT_CTRL_SHDW);
-
- /* Settings specific for EMIF4D5 */
- if (emif->plat_data->ip_rev != EMIF_4D5)
- return;
- writel(regs->ext_phy_ctrl_2_shdw, base + EMIF_EXT_PHY_CTRL_2_SHDW);
- writel(regs->ext_phy_ctrl_3_shdw, base + EMIF_EXT_PHY_CTRL_3_SHDW);
- writel(regs->ext_phy_ctrl_4_shdw, base + EMIF_EXT_PHY_CTRL_4_SHDW);
-}
-
-/*
- * When voltage ramps dll calibration and forced read idle should
- * happen more often
- */
-static void setup_volt_sensitive_regs(struct emif_data *emif,
- struct emif_regs *regs, u32 volt_state)
-{
- u32 calib_ctrl;
- void __iomem *base = emif->base;
-
- /*
- * EMIF_READ_IDLE_CTRL in EMIF4D refers to the same register as
- * EMIF_DLL_CALIB_CTRL in EMIF4D5 and dll_calib_ctrl_shadow_*
- * is an alias of the respective read_idle_ctrl_shdw_* (members of
- * a union). So, the below code takes care of both cases
- */
- if (volt_state == DDR_VOLTAGE_RAMPING)
- calib_ctrl = regs->dll_calib_ctrl_shdw_volt_ramp;
- else
- calib_ctrl = regs->dll_calib_ctrl_shdw_normal;
-
- writel(calib_ctrl, base + EMIF_DLL_CALIB_CTRL_SHDW);
-}
-
-/*
* setup_temperature_sensitive_regs() - set the timings for temperature
* sensitive registers. This happens once at initialisation time based
* on the temperature at boot time and subsequently based on the temperature
@@ -1508,7 +1130,6 @@ static int __init_or_module emif_probe(struct platform_device *pdev)
}
list_add(&emif->node, &device_list);
- emif->addressing = get_addressing_table(emif->plat_data->device_info);
/* Save pointers to each other in emif and device structures */
emif->dev = &pdev->dev;
@@ -1563,305 +1184,6 @@ static void emif_shutdown(struct platform_device *pdev)
disable_and_clear_all_interrupts(emif);
}
-static int get_emif_reg_values(struct emif_data *emif, u32 freq,
- struct emif_regs *regs)
-{
- u32 ip_rev, phy_type;
- u32 cl, type;
- const struct lpddr2_timings *timings;
- const struct lpddr2_min_tck *min_tck;
- const struct ddr_device_info *device_info;
- const struct lpddr2_addressing *addressing;
- struct emif_data *emif_for_calc;
- struct device *dev;
-
- dev = emif->dev;
- /*
- * If the devices on this EMIF instance is duplicate of EMIF1,
- * use EMIF1 details for the calculation
- */
- emif_for_calc = emif->duplicate ? emif1 : emif;
- timings = get_timings_table(emif_for_calc, freq);
- addressing = emif_for_calc->addressing;
- if (!timings || !addressing) {
- dev_err(dev, "%s: not enough data available for %dHz",
- __func__, freq);
- return -1;
- }
-
- device_info = emif_for_calc->plat_data->device_info;
- type = device_info->type;
- ip_rev = emif_for_calc->plat_data->ip_rev;
- phy_type = emif_for_calc->plat_data->phy_type;
-
- min_tck = emif_for_calc->plat_data->min_tck;
-
- set_ddr_clk_period(freq);
-
- regs->ref_ctrl_shdw = get_sdram_ref_ctrl_shdw(freq, addressing);
- regs->sdram_tim1_shdw = get_sdram_tim_1_shdw(timings, min_tck,
- addressing);
- regs->sdram_tim2_shdw = get_sdram_tim_2_shdw(timings, min_tck,
- addressing, type);
- regs->sdram_tim3_shdw = get_sdram_tim_3_shdw(timings, min_tck,
- addressing, type, ip_rev, EMIF_NORMAL_TIMINGS);
-
- cl = get_cl(emif);
-
- if (phy_type == EMIF_PHY_TYPE_ATTILAPHY && ip_rev == EMIF_4D) {
- regs->phy_ctrl_1_shdw = get_ddr_phy_ctrl_1_attilaphy_4d(
- timings, freq, cl);
- } else if (phy_type == EMIF_PHY_TYPE_INTELLIPHY && ip_rev == EMIF_4D5) {
- regs->phy_ctrl_1_shdw = get_phy_ctrl_1_intelliphy_4d5(freq, cl);
- regs->ext_phy_ctrl_2_shdw = get_ext_phy_ctrl_2_intelliphy_4d5();
- regs->ext_phy_ctrl_3_shdw = get_ext_phy_ctrl_3_intelliphy_4d5();
- regs->ext_phy_ctrl_4_shdw = get_ext_phy_ctrl_4_intelliphy_4d5();
- } else {
- return -1;
- }
-
- /* Only timeout values in pwr_mgmt_ctrl_shdw register */
- regs->pwr_mgmt_ctrl_shdw =
- get_pwr_mgmt_ctrl(freq, emif_for_calc, ip_rev) &
- (CS_TIM_MASK | SR_TIM_MASK | PD_TIM_MASK);
-
- if (ip_rev & EMIF_4D) {
- regs->read_idle_ctrl_shdw_normal =
- get_read_idle_ctrl_shdw(DDR_VOLTAGE_STABLE);
-
- regs->read_idle_ctrl_shdw_volt_ramp =
- get_read_idle_ctrl_shdw(DDR_VOLTAGE_RAMPING);
- } else if (ip_rev & EMIF_4D5) {
- regs->dll_calib_ctrl_shdw_normal =
- get_dll_calib_ctrl_shdw(DDR_VOLTAGE_STABLE);
-
- regs->dll_calib_ctrl_shdw_volt_ramp =
- get_dll_calib_ctrl_shdw(DDR_VOLTAGE_RAMPING);
- }
-
- if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4) {
- regs->ref_ctrl_shdw_derated = get_sdram_ref_ctrl_shdw(freq / 4,
- addressing);
-
- regs->sdram_tim1_shdw_derated =
- get_sdram_tim_1_shdw_derated(timings, min_tck,
- addressing);
-
- regs->sdram_tim3_shdw_derated = get_sdram_tim_3_shdw(timings,
- min_tck, addressing, type, ip_rev,
- EMIF_DERATED_TIMINGS);
- }
-
- regs->freq = freq;
-
- return 0;
-}
-
-/*
- * get_regs() - gets the cached emif_regs structure for a given EMIF instance
- * given frequency(freq):
- *
- * As an optimisation, every EMIF instance other than EMIF1 shares the
- * register cache with EMIF1 if the devices connected on this instance
- * are same as that on EMIF1(indicated by the duplicate flag)
- *
- * If we do not have an entry corresponding to the frequency given, we
- * allocate a new entry and calculate the values
- *
- * Upon finding the right reg dump, save it in curr_regs. It can be
- * directly used for thermal de-rating and voltage ramping changes.
- */
-static struct emif_regs *get_regs(struct emif_data *emif, u32 freq)
-{
- int i;
- struct emif_regs **regs_cache;
- struct emif_regs *regs = NULL;
- struct device *dev;
-
- dev = emif->dev;
- if (emif->curr_regs && emif->curr_regs->freq == freq) {
- dev_dbg(dev, "%s: using curr_regs - %u Hz", __func__, freq);
- return emif->curr_regs;
- }
-
- if (emif->duplicate)
- regs_cache = emif1->regs_cache;
- else
- regs_cache = emif->regs_cache;
-
- for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) {
- if (regs_cache[i]->freq == freq) {
- regs = regs_cache[i];
- dev_dbg(dev,
- "%s: reg dump found in reg cache for %u Hz\n",
- __func__, freq);
- break;
- }
- }
-
- /*
- * If we don't have an entry for this frequency in the cache create one
- * and calculate the values
- */
- if (!regs) {
- regs = devm_kzalloc(emif->dev, sizeof(*regs), GFP_ATOMIC);
- if (!regs)
- return NULL;
-
- if (get_emif_reg_values(emif, freq, regs)) {
- devm_kfree(emif->dev, regs);
- return NULL;
- }
-
- /*
- * Now look for an un-used entry in the cache and save the
- * newly created struct. If there are no free entries
- * over-write the last entry
- */
- for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++)
- ;
-
- if (i >= EMIF_MAX_NUM_FREQUENCIES) {
- dev_warn(dev, "%s: regs_cache full - reusing a slot!!\n",
- __func__);
- i = EMIF_MAX_NUM_FREQUENCIES - 1;
- devm_kfree(emif->dev, regs_cache[i]);
- }
- regs_cache[i] = regs;
- }
-
- return regs;
-}
-
-static void do_volt_notify_handling(struct emif_data *emif, u32 volt_state)
-{
- dev_dbg(emif->dev, "%s: voltage notification : %d", __func__,
- volt_state);
-
- if (!emif->curr_regs) {
- dev_err(emif->dev,
- "%s: volt-notify before registers are ready: %d\n",
- __func__, volt_state);
- return;
- }
-
- setup_volt_sensitive_regs(emif, emif->curr_regs, volt_state);
-}
-
-/*
- * TODO: voltage notify handling should be hooked up to
- * regulator framework as soon as the necessary support
- * is available in mainline kernel. This function is un-used
- * right now.
- */
-static void __attribute__((unused)) volt_notify_handling(u32 volt_state)
-{
- struct emif_data *emif;
-
- spin_lock_irqsave(&emif_lock, irq_state);
-
- list_for_each_entry(emif, &device_list, node)
- do_volt_notify_handling(emif, volt_state);
- do_freq_update();
-
- spin_unlock_irqrestore(&emif_lock, irq_state);
-}
-
-static void do_freq_pre_notify_handling(struct emif_data *emif, u32 new_freq)
-{
- struct emif_regs *regs;
-
- regs = get_regs(emif, new_freq);
- if (!regs)
- return;
-
- emif->curr_regs = regs;
-
- /*
- * Update the shadow registers:
- * Temperature and voltage-ramp sensitive settings are also configured
- * in terms of DDR cycles. So, we need to update them too when there
- * is a freq change
- */
- dev_dbg(emif->dev, "%s: setting up shadow registers for %uHz",
- __func__, new_freq);
- setup_registers(emif, regs);
- setup_temperature_sensitive_regs(emif, regs);
- setup_volt_sensitive_regs(emif, regs, DDR_VOLTAGE_STABLE);
-
- /*
- * Part of workaround for errata i728. See do_freq_update()
- * for more details
- */
- if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
- set_lpmode(emif, EMIF_LP_MODE_DISABLE);
-}
-
-/*
- * TODO: frequency notify handling should be hooked up to
- * clock framework as soon as the necessary support is
- * available in mainline kernel. This function is un-used
- * right now.
- */
-static void __attribute__((unused)) freq_pre_notify_handling(u32 new_freq)
-{
- struct emif_data *emif;
-
- /*
- * NOTE: we are taking the spin-lock here and releases it
- * only in post-notifier. This doesn't look good and
- * Sparse complains about it, but this seems to be
- * un-avoidable. We need to lock a sequence of events
- * that is split between EMIF and clock framework.
- *
- * 1. EMIF driver updates EMIF timings in shadow registers in the
- * frequency pre-notify callback from clock framework
- * 2. clock framework sets up the registers for the new frequency
- * 3. clock framework initiates a hw-sequence that updates
- * the frequency EMIF timings synchronously.
- *
- * All these 3 steps should be performed as an atomic operation
- * vis-a-vis similar sequence in the EMIF interrupt handler
- * for temperature events. Otherwise, there could be race
- * conditions that could result in incorrect EMIF timings for
- * a given frequency
- */
- spin_lock_irqsave(&emif_lock, irq_state);
-
- list_for_each_entry(emif, &device_list, node)
- do_freq_pre_notify_handling(emif, new_freq);
-}
-
-static void do_freq_post_notify_handling(struct emif_data *emif)
-{
- /*
- * Part of workaround for errata i728. See do_freq_update()
- * for more details
- */
- if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
- set_lpmode(emif, EMIF_LP_MODE_SELF_REFRESH);
-}
-
-/*
- * TODO: frequency notify handling should be hooked up to
- * clock framework as soon as the necessary support is
- * available in mainline kernel. This function is un-used
- * right now.
- */
-static void __attribute__((unused)) freq_post_notify_handling(void)
-{
- struct emif_data *emif;
-
- list_for_each_entry(emif, &device_list, node)
- do_freq_post_notify_handling(emif);
-
- /*
- * Lock is done in pre-notify handler. See freq_pre_notify_handling()
- * for more details
- */
- spin_unlock_irqrestore(&emif_lock, irq_state);
-}
-
#if defined(CONFIG_OF)
static const struct of_device_id emif_of_match[] = {
{ .compatible = "ti,emif-4d" },
diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c
index 89f99b5b6450..d062c2f8250f 100644
--- a/drivers/memory/fsl_ifc.c
+++ b/drivers/memory/fsl_ifc.c
@@ -97,7 +97,6 @@ static int fsl_ifc_ctrl_remove(struct platform_device *dev)
iounmap(ctrl->gregs);
dev_set_drvdata(&dev->dev, NULL);
- kfree(ctrl);
return 0;
}
@@ -209,7 +208,8 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");
- fsl_ifc_ctrl_dev = kzalloc(sizeof(*fsl_ifc_ctrl_dev), GFP_KERNEL);
+ fsl_ifc_ctrl_dev = devm_kzalloc(&dev->dev, sizeof(*fsl_ifc_ctrl_dev),
+ GFP_KERNEL);
if (!fsl_ifc_ctrl_dev)
return -ENOMEM;
@@ -219,8 +219,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
fsl_ifc_ctrl_dev->gregs = of_iomap(dev->dev.of_node, 0);
if (!fsl_ifc_ctrl_dev->gregs) {
dev_err(&dev->dev, "failed to get memory region\n");
- ret = -ENODEV;
- goto err;
+ return -ENODEV;
}
if (of_property_read_bool(dev->dev.of_node, "little-endian")) {
@@ -295,6 +294,7 @@ err_irq:
free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
err:
+ iounmap(fsl_ifc_ctrl_dev->gregs);
return ret;
}
diff --git a/drivers/memory/pl353-smc.c b/drivers/memory/pl353-smc.c
index 9c0a28416777..f84b98278745 100644
--- a/drivers/memory/pl353-smc.c
+++ b/drivers/memory/pl353-smc.c
@@ -8,263 +8,22 @@
*/
#include <linux/clk.h>
-#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/pl353-smc.h>
#include <linux/amba/bus.h>
-/* Register definitions */
-#define PL353_SMC_MEMC_STATUS_OFFS 0 /* Controller status reg, RO */
-#define PL353_SMC_CFG_CLR_OFFS 0xC /* Clear config reg, WO */
-#define PL353_SMC_DIRECT_CMD_OFFS 0x10 /* Direct command reg, WO */
-#define PL353_SMC_SET_CYCLES_OFFS 0x14 /* Set cycles register, WO */
-#define PL353_SMC_SET_OPMODE_OFFS 0x18 /* Set opmode register, WO */
-#define PL353_SMC_ECC_STATUS_OFFS 0x400 /* ECC status register */
-#define PL353_SMC_ECC_MEMCFG_OFFS 0x404 /* ECC mem config reg */
-#define PL353_SMC_ECC_MEMCMD1_OFFS 0x408 /* ECC mem cmd1 reg */
-#define PL353_SMC_ECC_MEMCMD2_OFFS 0x40C /* ECC mem cmd2 reg */
-#define PL353_SMC_ECC_VALUE0_OFFS 0x418 /* ECC value 0 reg */
-
-/* Controller status register specific constants */
-#define PL353_SMC_MEMC_STATUS_RAW_INT_1_SHIFT 6
-
-/* Clear configuration register specific constants */
-#define PL353_SMC_CFG_CLR_INT_CLR_1 0x10
-#define PL353_SMC_CFG_CLR_ECC_INT_DIS_1 0x40
-#define PL353_SMC_CFG_CLR_INT_DIS_1 0x2
-#define PL353_SMC_CFG_CLR_DEFAULT_MASK (PL353_SMC_CFG_CLR_INT_CLR_1 | \
- PL353_SMC_CFG_CLR_ECC_INT_DIS_1 | \
- PL353_SMC_CFG_CLR_INT_DIS_1)
-
-/* Set cycles register specific constants */
-#define PL353_SMC_SET_CYCLES_T0_MASK 0xF
-#define PL353_SMC_SET_CYCLES_T0_SHIFT 0
-#define PL353_SMC_SET_CYCLES_T1_MASK 0xF
-#define PL353_SMC_SET_CYCLES_T1_SHIFT 4
-#define PL353_SMC_SET_CYCLES_T2_MASK 0x7
-#define PL353_SMC_SET_CYCLES_T2_SHIFT 8
-#define PL353_SMC_SET_CYCLES_T3_MASK 0x7
-#define PL353_SMC_SET_CYCLES_T3_SHIFT 11
-#define PL353_SMC_SET_CYCLES_T4_MASK 0x7
-#define PL353_SMC_SET_CYCLES_T4_SHIFT 14
-#define PL353_SMC_SET_CYCLES_T5_MASK 0x7
-#define PL353_SMC_SET_CYCLES_T5_SHIFT 17
-#define PL353_SMC_SET_CYCLES_T6_MASK 0xF
-#define PL353_SMC_SET_CYCLES_T6_SHIFT 20
-
-/* ECC status register specific constants */
-#define PL353_SMC_ECC_STATUS_BUSY BIT(6)
-#define PL353_SMC_ECC_REG_SIZE_OFFS 4
-
-/* ECC memory config register specific constants */
-#define PL353_SMC_ECC_MEMCFG_MODE_MASK 0xC
-#define PL353_SMC_ECC_MEMCFG_MODE_SHIFT 2
-#define PL353_SMC_ECC_MEMCFG_PGSIZE_MASK 0x3
-
-#define PL353_SMC_DC_UPT_NAND_REGS ((4 << 23) | /* CS: NAND chip */ \
- (2 << 21)) /* UpdateRegs operation */
-
-#define PL353_NAND_ECC_CMD1 ((0x80) | /* Write command */ \
- (0 << 8) | /* Read command */ \
- (0x30 << 16) | /* Read End command */ \
- (1 << 24)) /* Read End command calid */
-
-#define PL353_NAND_ECC_CMD2 ((0x85) | /* Write col change cmd */ \
- (5 << 8) | /* Read col change cmd */ \
- (0xE0 << 16) | /* Read col change end cmd */ \
- (1 << 24)) /* Read col change end cmd valid */
-#define PL353_NAND_ECC_BUSY_TIMEOUT (1 * HZ)
/**
* struct pl353_smc_data - Private smc driver structure
* @memclk: Pointer to the peripheral clock
- * @aclk: Pointer to the APER clock
+ * @aclk: Pointer to the AXI peripheral clock
*/
struct pl353_smc_data {
struct clk *memclk;
struct clk *aclk;
};
-/* SMC virtual register base */
-static void __iomem *pl353_smc_base;
-
-/**
- * pl353_smc_set_buswidth - Set memory buswidth
- * @bw: Memory buswidth (8 | 16)
- * Return: 0 on success or negative errno.
- */
-int pl353_smc_set_buswidth(unsigned int bw)
-{
- if (bw != PL353_SMC_MEM_WIDTH_8 && bw != PL353_SMC_MEM_WIDTH_16)
- return -EINVAL;
-
- writel(bw, pl353_smc_base + PL353_SMC_SET_OPMODE_OFFS);
- writel(PL353_SMC_DC_UPT_NAND_REGS, pl353_smc_base +
- PL353_SMC_DIRECT_CMD_OFFS);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(pl353_smc_set_buswidth);
-
-/**
- * pl353_smc_set_cycles - Set memory timing parameters
- * @timings: NAND controller timing parameters
- *
- * Sets NAND chip specific timing parameters.
- */
-void pl353_smc_set_cycles(u32 timings[])
-{
- /*
- * Set write pulse timing. This one is easy to extract:
- *
- * NWE_PULSE = tWP
- */
- timings[0] &= PL353_SMC_SET_CYCLES_T0_MASK;
- timings[1] = (timings[1] & PL353_SMC_SET_CYCLES_T1_MASK) <<
- PL353_SMC_SET_CYCLES_T1_SHIFT;
- timings[2] = (timings[2] & PL353_SMC_SET_CYCLES_T2_MASK) <<
- PL353_SMC_SET_CYCLES_T2_SHIFT;
- timings[3] = (timings[3] & PL353_SMC_SET_CYCLES_T3_MASK) <<
- PL353_SMC_SET_CYCLES_T3_SHIFT;
- timings[4] = (timings[4] & PL353_SMC_SET_CYCLES_T4_MASK) <<
- PL353_SMC_SET_CYCLES_T4_SHIFT;
- timings[5] = (timings[5] & PL353_SMC_SET_CYCLES_T5_MASK) <<
- PL353_SMC_SET_CYCLES_T5_SHIFT;
- timings[6] = (timings[6] & PL353_SMC_SET_CYCLES_T6_MASK) <<
- PL353_SMC_SET_CYCLES_T6_SHIFT;
- timings[0] |= timings[1] | timings[2] | timings[3] |
- timings[4] | timings[5] | timings[6];
-
- writel(timings[0], pl353_smc_base + PL353_SMC_SET_CYCLES_OFFS);
- writel(PL353_SMC_DC_UPT_NAND_REGS, pl353_smc_base +
- PL353_SMC_DIRECT_CMD_OFFS);
-}
-EXPORT_SYMBOL_GPL(pl353_smc_set_cycles);
-
-/**
- * pl353_smc_ecc_is_busy - Read ecc busy flag
- * Return: the ecc_status bit from the ecc_status register. 1 = busy, 0 = idle
- */
-bool pl353_smc_ecc_is_busy(void)
-{
- return ((readl(pl353_smc_base + PL353_SMC_ECC_STATUS_OFFS) &
- PL353_SMC_ECC_STATUS_BUSY) == PL353_SMC_ECC_STATUS_BUSY);
-}
-EXPORT_SYMBOL_GPL(pl353_smc_ecc_is_busy);
-
-/**
- * pl353_smc_get_ecc_val - Read ecc_valueN registers
- * @ecc_reg: Index of the ecc_value reg (0..3)
- * Return: the content of the requested ecc_value register.
- *
- * There are four valid ecc_value registers. The argument is truncated to stay
- * within this valid boundary.
- */
-u32 pl353_smc_get_ecc_val(int ecc_reg)
-{
- u32 addr, reg;
-
- addr = PL353_SMC_ECC_VALUE0_OFFS +
- (ecc_reg * PL353_SMC_ECC_REG_SIZE_OFFS);
- reg = readl(pl353_smc_base + addr);
-
- return reg;
-}
-EXPORT_SYMBOL_GPL(pl353_smc_get_ecc_val);
-
-/**
- * pl353_smc_get_nand_int_status_raw - Get NAND interrupt status bit
- * Return: the raw_int_status1 bit from the memc_status register
- */
-int pl353_smc_get_nand_int_status_raw(void)
-{
- u32 reg;
-
- reg = readl(pl353_smc_base + PL353_SMC_MEMC_STATUS_OFFS);
- reg >>= PL353_SMC_MEMC_STATUS_RAW_INT_1_SHIFT;
- reg &= 1;
-
- return reg;
-}
-EXPORT_SYMBOL_GPL(pl353_smc_get_nand_int_status_raw);
-
-/**
- * pl353_smc_clr_nand_int - Clear NAND interrupt
- */
-void pl353_smc_clr_nand_int(void)
-{
- writel(PL353_SMC_CFG_CLR_INT_CLR_1,
- pl353_smc_base + PL353_SMC_CFG_CLR_OFFS);
-}
-EXPORT_SYMBOL_GPL(pl353_smc_clr_nand_int);
-
-/**
- * pl353_smc_set_ecc_mode - Set SMC ECC mode
- * @mode: ECC mode (BYPASS, APB, MEM)
- * Return: 0 on success or negative errno.
- */
-int pl353_smc_set_ecc_mode(enum pl353_smc_ecc_mode mode)
-{
- u32 reg;
- int ret = 0;
-
- switch (mode) {
- case PL353_SMC_ECCMODE_BYPASS:
- case PL353_SMC_ECCMODE_APB:
- case PL353_SMC_ECCMODE_MEM:
-
- reg = readl(pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS);
- reg &= ~PL353_SMC_ECC_MEMCFG_MODE_MASK;
- reg |= mode << PL353_SMC_ECC_MEMCFG_MODE_SHIFT;
- writel(reg, pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS);
-
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(pl353_smc_set_ecc_mode);
-
-/**
- * pl353_smc_set_ecc_pg_size - Set SMC ECC page size
- * @pg_sz: ECC page size
- * Return: 0 on success or negative errno.
- */
-int pl353_smc_set_ecc_pg_size(unsigned int pg_sz)
-{
- u32 reg, sz;
-
- switch (pg_sz) {
- case 0:
- sz = 0;
- break;
- case SZ_512:
- sz = 1;
- break;
- case SZ_1K:
- sz = 2;
- break;
- case SZ_2K:
- sz = 3;
- break;
- default:
- return -EINVAL;
- }
-
- reg = readl(pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS);
- reg &= ~PL353_SMC_ECC_MEMCFG_PGSIZE_MASK;
- reg |= sz;
- writel(reg, pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(pl353_smc_set_ecc_pg_size);
-
static int __maybe_unused pl353_smc_suspend(struct device *dev)
{
struct pl353_smc_data *pl353_smc = dev_get_drvdata(dev);
@@ -277,8 +36,8 @@ static int __maybe_unused pl353_smc_suspend(struct device *dev)
static int __maybe_unused pl353_smc_resume(struct device *dev)
{
- int ret;
struct pl353_smc_data *pl353_smc = dev_get_drvdata(dev);
+ int ret;
ret = clk_enable(pl353_smc->aclk);
if (ret) {
@@ -296,77 +55,31 @@ static int __maybe_unused pl353_smc_resume(struct device *dev)
return ret;
}
-static struct amba_driver pl353_smc_driver;
-
static SIMPLE_DEV_PM_OPS(pl353_smc_dev_pm_ops, pl353_smc_suspend,
pl353_smc_resume);
-/**
- * pl353_smc_init_nand_interface - Initialize the NAND interface
- * @adev: Pointer to the amba_device struct
- * @nand_node: Pointer to the pl353_nand device_node struct
- */
-static void pl353_smc_init_nand_interface(struct amba_device *adev,
- struct device_node *nand_node)
-{
- unsigned long timeout;
-
- pl353_smc_set_buswidth(PL353_SMC_MEM_WIDTH_8);
- writel(PL353_SMC_CFG_CLR_INT_CLR_1,
- pl353_smc_base + PL353_SMC_CFG_CLR_OFFS);
- writel(PL353_SMC_DC_UPT_NAND_REGS, pl353_smc_base +
- PL353_SMC_DIRECT_CMD_OFFS);
-
- timeout = jiffies + PL353_NAND_ECC_BUSY_TIMEOUT;
- /* Wait till the ECC operation is complete */
- do {
- if (pl353_smc_ecc_is_busy())
- cpu_relax();
- else
- break;
- } while (!time_after_eq(jiffies, timeout));
-
- if (time_after_eq(jiffies, timeout))
- return;
-
- writel(PL353_NAND_ECC_CMD1,
- pl353_smc_base + PL353_SMC_ECC_MEMCMD1_OFFS);
- writel(PL353_NAND_ECC_CMD2,
- pl353_smc_base + PL353_SMC_ECC_MEMCMD2_OFFS);
-}
-
static const struct of_device_id pl353_smc_supported_children[] = {
{
.compatible = "cfi-flash"
},
{
.compatible = "arm,pl353-nand-r2p1",
- .data = pl353_smc_init_nand_interface
},
{}
};
static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id)
{
+ struct device_node *of_node = adev->dev.of_node;
+ const struct of_device_id *match = NULL;
struct pl353_smc_data *pl353_smc;
struct device_node *child;
- struct resource *res;
int err;
- struct device_node *of_node = adev->dev.of_node;
- static void (*init)(struct amba_device *adev,
- struct device_node *nand_node);
- const struct of_device_id *match = NULL;
pl353_smc = devm_kzalloc(&adev->dev, sizeof(*pl353_smc), GFP_KERNEL);
if (!pl353_smc)
return -ENOMEM;
- /* Get the NAND controller virtual address */
- res = &adev->res;
- pl353_smc_base = devm_ioremap_resource(&adev->dev, res);
- if (IS_ERR(pl353_smc_base))
- return PTR_ERR(pl353_smc_base);
-
pl353_smc->aclk = devm_clk_get(&adev->dev, "apb_pclk");
if (IS_ERR(pl353_smc->aclk)) {
dev_err(&adev->dev, "aclk clock not found.\n");
@@ -388,15 +101,11 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id)
err = clk_prepare_enable(pl353_smc->memclk);
if (err) {
dev_err(&adev->dev, "Unable to enable memory clock.\n");
- goto out_clk_dis_aper;
+ goto disable_axi_clk;
}
amba_set_drvdata(adev, pl353_smc);
- /* clear interrupts */
- writel(PL353_SMC_CFG_CLR_DEFAULT_MASK,
- pl353_smc_base + PL353_SMC_CFG_CLR_OFFS);
-
/* Find compatible children. Only a single child is supported */
for_each_available_child_of_node(of_node, child) {
match = of_match_node(pl353_smc_supported_children, child);
@@ -407,20 +116,18 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id)
break;
}
if (!match) {
+ err = -ENODEV;
dev_err(&adev->dev, "no matching children\n");
- goto out_clk_disable;
+ goto disable_mem_clk;
}
- init = match->data;
- if (init)
- init(adev, child);
of_platform_device_create(child, NULL, &adev->dev);
return 0;
-out_clk_disable:
+disable_mem_clk:
clk_disable_unprepare(pl353_smc->memclk);
-out_clk_dis_aper:
+disable_axi_clk:
clk_disable_unprepare(pl353_smc->aclk);
return err;
@@ -436,8 +143,8 @@ static void pl353_smc_remove(struct amba_device *adev)
static const struct amba_id pl353_ids[] = {
{
- .id = 0x00041353,
- .mask = 0x000fffff,
+ .id = 0x00041353,
+ .mask = 0x000fffff,
},
{ 0, 0 },
};
diff --git a/drivers/memory/stm32-fmc2-ebi.c b/drivers/memory/stm32-fmc2-ebi.c
index 4d5758c419c5..ffec26a99313 100644
--- a/drivers/memory/stm32-fmc2-ebi.c
+++ b/drivers/memory/stm32-fmc2-ebi.c
@@ -1048,16 +1048,19 @@ static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi)
if (ret) {
dev_err(dev, "could not retrieve reg property: %d\n",
ret);
+ of_node_put(child);
return ret;
}
if (bank >= FMC2_MAX_BANKS) {
dev_err(dev, "invalid reg value: %d\n", bank);
+ of_node_put(child);
return -EINVAL;
}
if (ebi->bank_assigned & BIT(bank)) {
dev_err(dev, "bank already assigned: %d\n", bank);
+ of_node_put(child);
return -EINVAL;
}
@@ -1066,6 +1069,7 @@ static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi)
if (ret) {
dev_err(dev, "setup chip select %d failed: %d\n",
bank, ret);
+ of_node_put(child);
return ret;
}
}
diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig
index a70967a56e52..f9bae36c03a3 100644
--- a/drivers/memory/tegra/Kconfig
+++ b/drivers/memory/tegra/Kconfig
@@ -2,16 +2,18 @@
config TEGRA_MC
bool "NVIDIA Tegra Memory Controller support"
default y
- depends on ARCH_TEGRA
+ depends on ARCH_TEGRA || (COMPILE_TEST && COMMON_CLK)
select INTERCONNECT
help
This driver supports the Memory Controller (MC) hardware found on
NVIDIA Tegra SoCs.
+if TEGRA_MC
+
config TEGRA20_EMC
tristate "NVIDIA Tegra20 External Memory Controller driver"
default y
- depends on TEGRA_MC && ARCH_TEGRA_2x_SOC
+ depends on ARCH_TEGRA_2x_SOC || COMPILE_TEST
select DEVFREQ_GOV_SIMPLE_ONDEMAND
select PM_DEVFREQ
help
@@ -23,7 +25,7 @@ config TEGRA20_EMC
config TEGRA30_EMC
tristate "NVIDIA Tegra30 External Memory Controller driver"
default y
- depends on TEGRA_MC && ARCH_TEGRA_3x_SOC
+ depends on ARCH_TEGRA_3x_SOC || COMPILE_TEST
select PM_OPP
help
This driver is for the External Memory Controller (EMC) found on
@@ -34,8 +36,8 @@ config TEGRA30_EMC
config TEGRA124_EMC
tristate "NVIDIA Tegra124 External Memory Controller driver"
default y
- depends on TEGRA_MC && ARCH_TEGRA_124_SOC
- select TEGRA124_CLK_EMC
+ depends on ARCH_TEGRA_124_SOC || COMPILE_TEST
+ select TEGRA124_CLK_EMC if ARCH_TEGRA
select PM_OPP
help
This driver is for the External Memory Controller (EMC) found on
@@ -45,14 +47,16 @@ config TEGRA124_EMC
config TEGRA210_EMC_TABLE
bool
- depends on ARCH_TEGRA_210_SOC
+ depends on ARCH_TEGRA_210_SOC || COMPILE_TEST
config TEGRA210_EMC
tristate "NVIDIA Tegra210 External Memory Controller driver"
- depends on TEGRA_MC && ARCH_TEGRA_210_SOC
+ depends on ARCH_TEGRA_210_SOC || COMPILE_TEST
select TEGRA210_EMC_TABLE
help
This driver is for the External Memory Controller (EMC) found on
Tegra210 chips. The EMC controls the external DRAM on the board.
This driver is required to change memory timings / clock rate for
external memory.
+
+endif
diff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile
index 6c1a2ecc6628..c992e87782d2 100644
--- a/drivers/memory/tegra/Makefile
+++ b/drivers/memory/tegra/Makefile
@@ -7,6 +7,8 @@ tegra-mc-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114.o
tegra-mc-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124.o
tegra-mc-$(CONFIG_ARCH_TEGRA_132_SOC) += tegra124.o
tegra-mc-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
+tegra-mc-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o
+tegra-mc-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186.o tegra194.o
obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
@@ -15,7 +17,7 @@ obj-$(CONFIG_TEGRA30_EMC) += tegra30-emc.o
obj-$(CONFIG_TEGRA124_EMC) += tegra124-emc.o
obj-$(CONFIG_TEGRA210_EMC_TABLE) += tegra210-emc-table.o
obj-$(CONFIG_TEGRA210_EMC) += tegra210-emc.o
-obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o tegra186-emc.o
-obj-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186.o tegra186-emc.o
+obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186-emc.o
+obj-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186-emc.o
tegra210-emc-y := tegra210-emc-core.o tegra210-emc-cc-r21021.o
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
index e58c3e5baea0..3c5aae7abf35 100644
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -39,7 +39,13 @@ static const struct of_device_id tegra_mc_of_match[] = {
#ifdef CONFIG_ARCH_TEGRA_210_SOC
{ .compatible = "nvidia,tegra210-mc", .data = &tegra210_mc_soc },
#endif
- { }
+#ifdef CONFIG_ARCH_TEGRA_186_SOC
+ { .compatible = "nvidia,tegra186-mc", .data = &tegra186_mc_soc },
+#endif
+#ifdef CONFIG_ARCH_TEGRA_194_SOC
+ { .compatible = "nvidia,tegra194-mc", .data = &tegra194_mc_soc },
+#endif
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
@@ -91,6 +97,15 @@ struct tegra_mc *devm_tegra_memory_controller_get(struct device *dev)
}
EXPORT_SYMBOL_GPL(devm_tegra_memory_controller_get);
+int tegra_mc_probe_device(struct tegra_mc *mc, struct device *dev)
+{
+ if (mc->soc->ops && mc->soc->ops->probe_device)
+ return mc->soc->ops->probe_device(mc, dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_mc_probe_device);
+
static int tegra_mc_block_dma_common(struct tegra_mc *mc,
const struct tegra_mc_reset *rst)
{
@@ -299,38 +314,6 @@ static int tegra_mc_reset_setup(struct tegra_mc *mc)
return 0;
}
-static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
-{
- unsigned long long tick;
- unsigned int i;
- u32 value;
-
- /* compute the number of MC clock cycles per tick */
- tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk);
- do_div(tick, NSEC_PER_SEC);
-
- value = mc_readl(mc, MC_EMEM_ARB_CFG);
- value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK;
- value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick);
- mc_writel(mc, value, MC_EMEM_ARB_CFG);
-
- /* write latency allowance defaults */
- for (i = 0; i < mc->soc->num_clients; i++) {
- const struct tegra_mc_la *la = &mc->soc->clients[i].la;
- u32 value;
-
- value = mc_readl(mc, la->reg);
- value &= ~(la->mask << la->shift);
- value |= (la->def & la->mask) << la->shift;
- mc_writel(mc, value, la->reg);
- }
-
- /* latch new values */
- mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL);
-
- return 0;
-}
-
int tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate)
{
unsigned int i;
@@ -368,6 +351,43 @@ unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc)
}
EXPORT_SYMBOL_GPL(tegra_mc_get_emem_device_count);
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_114_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_124_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_132_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_210_SOC)
+static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
+{
+ unsigned long long tick;
+ unsigned int i;
+ u32 value;
+
+ /* compute the number of MC clock cycles per tick */
+ tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk);
+ do_div(tick, NSEC_PER_SEC);
+
+ value = mc_readl(mc, MC_EMEM_ARB_CFG);
+ value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK;
+ value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick);
+ mc_writel(mc, value, MC_EMEM_ARB_CFG);
+
+ /* write latency allowance defaults */
+ for (i = 0; i < mc->soc->num_clients; i++) {
+ const struct tegra_mc_client *client = &mc->soc->clients[i];
+ u32 value;
+
+ value = mc_readl(mc, client->regs.la.reg);
+ value &= ~(client->regs.la.mask << client->regs.la.shift);
+ value |= (client->regs.la.def & client->regs.la.mask) << client->regs.la.shift;
+ mc_writel(mc, value, client->regs.la.reg);
+ }
+
+ /* latch new values */
+ mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL);
+
+ return 0;
+}
+
static int load_one_timing(struct tegra_mc *mc,
struct tegra_mc_timing *timing,
struct device_node *node)
@@ -459,27 +479,35 @@ static int tegra_mc_setup_timings(struct tegra_mc *mc)
return 0;
}
-static const char *const status_names[32] = {
- [ 1] = "External interrupt",
- [ 6] = "EMEM address decode error",
- [ 7] = "GART page fault",
- [ 8] = "Security violation",
- [ 9] = "EMEM arbitration error",
- [10] = "Page fault",
- [11] = "Invalid APB ASID update",
- [12] = "VPR violation",
- [13] = "Secure carveout violation",
- [16] = "MTS carveout violation",
-};
+int tegra30_mc_probe(struct tegra_mc *mc)
+{
+ int err;
-static const char *const error_names[8] = {
- [2] = "EMEM decode error",
- [3] = "TrustZone violation",
- [4] = "Carveout violation",
- [6] = "SMMU translation error",
-};
+ mc->clk = devm_clk_get_optional(mc->dev, "mc");
+ if (IS_ERR(mc->clk)) {
+ dev_err(mc->dev, "failed to get MC clock: %ld\n", PTR_ERR(mc->clk));
+ return PTR_ERR(mc->clk);
+ }
+
+ /* ensure that debug features are disabled */
+ mc_writel(mc, 0x00000000, MC_TIMING_CONTROL_DBG);
+
+ err = tegra_mc_setup_latency_allowance(mc);
+ if (err < 0) {
+ dev_err(mc->dev, "failed to setup latency allowance: %d\n", err);
+ return err;
+ }
-static irqreturn_t tegra_mc_irq(int irq, void *data)
+ err = tegra_mc_setup_timings(mc);
+ if (err < 0) {
+ dev_err(mc->dev, "failed to setup timings: %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
{
struct tegra_mc *mc = data;
unsigned long status;
@@ -491,7 +519,7 @@ static irqreturn_t tegra_mc_irq(int irq, void *data)
return IRQ_NONE;
for_each_set_bit(bit, &status, 32) {
- const char *error = status_names[bit] ?: "unknown";
+ const char *error = tegra_mc_status_names[bit] ?: "unknown";
const char *client = "unknown", *desc;
const char *direction, *secure;
phys_addr_t addr = 0;
@@ -531,7 +559,7 @@ static irqreturn_t tegra_mc_irq(int irq, void *data)
type = (value & MC_ERR_STATUS_TYPE_MASK) >>
MC_ERR_STATUS_TYPE_SHIFT;
- desc = error_names[type];
+ desc = tegra_mc_error_names[type];
switch (value & MC_ERR_STATUS_TYPE_MASK) {
case MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE:
@@ -576,78 +604,31 @@ static irqreturn_t tegra_mc_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static __maybe_unused irqreturn_t tegra20_mc_irq(int irq, void *data)
-{
- struct tegra_mc *mc = data;
- unsigned long status;
- unsigned int bit;
-
- /* mask all interrupts to avoid flooding */
- status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
- if (!status)
- return IRQ_NONE;
-
- for_each_set_bit(bit, &status, 32) {
- const char *direction = "read", *secure = "";
- const char *error = status_names[bit];
- const char *client, *desc;
- phys_addr_t addr;
- u32 value, reg;
- u8 id, type;
-
- switch (BIT(bit)) {
- case MC_INT_DECERR_EMEM:
- reg = MC_DECERR_EMEM_OTHERS_STATUS;
- value = mc_readl(mc, reg);
-
- id = value & mc->soc->client_id_mask;
- desc = error_names[2];
-
- if (value & BIT(31))
- direction = "write";
- break;
-
- case MC_INT_INVALID_GART_PAGE:
- reg = MC_GART_ERROR_REQ;
- value = mc_readl(mc, reg);
-
- id = (value >> 1) & mc->soc->client_id_mask;
- desc = error_names[2];
-
- if (value & BIT(0))
- direction = "write";
- break;
-
- case MC_INT_SECURITY_VIOLATION:
- reg = MC_SECURITY_VIOLATION_STATUS;
- value = mc_readl(mc, reg);
-
- id = value & mc->soc->client_id_mask;
- type = (value & BIT(30)) ? 4 : 3;
- desc = error_names[type];
- secure = "secure ";
-
- if (value & BIT(31))
- direction = "write";
- break;
-
- default:
- continue;
- }
-
- client = mc->soc->clients[id].name;
- addr = mc_readl(mc, reg + sizeof(u32));
-
- dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s)\n",
- client, secure, direction, &addr, error,
- desc);
- }
+const struct tegra_mc_ops tegra30_mc_ops = {
+ .probe = tegra30_mc_probe,
+ .handle_irq = tegra30_mc_handle_irq,
+};
+#endif
- /* clear interrupts */
- mc_writel(mc, status, MC_INTSTATUS);
+const char *const tegra_mc_status_names[32] = {
+ [ 1] = "External interrupt",
+ [ 6] = "EMEM address decode error",
+ [ 7] = "GART page fault",
+ [ 8] = "Security violation",
+ [ 9] = "EMEM arbitration error",
+ [10] = "Page fault",
+ [11] = "Invalid APB ASID update",
+ [12] = "VPR violation",
+ [13] = "Secure carveout violation",
+ [16] = "MTS carveout violation",
+};
- return IRQ_HANDLED;
-}
+const char *const tegra_mc_error_names[8] = {
+ [2] = "EMEM decode error",
+ [3] = "TrustZone violation",
+ [4] = "Carveout violation",
+ [6] = "SMMU translation error",
+};
/*
* Memory Controller (MC) has few Memory Clients that are issuing memory
@@ -748,7 +729,6 @@ static int tegra_mc_probe(struct platform_device *pdev)
{
struct resource *res;
struct tegra_mc *mc;
- void *isr;
u64 mask;
int err;
@@ -777,70 +757,38 @@ static int tegra_mc_probe(struct platform_device *pdev)
if (IS_ERR(mc->regs))
return PTR_ERR(mc->regs);
- mc->clk = devm_clk_get(&pdev->dev, "mc");
- if (IS_ERR(mc->clk)) {
- dev_err(&pdev->dev, "failed to get MC clock: %ld\n",
- PTR_ERR(mc->clk));
- return PTR_ERR(mc->clk);
+ mc->debugfs.root = debugfs_create_dir("mc", NULL);
+
+ if (mc->soc->ops && mc->soc->ops->probe) {
+ err = mc->soc->ops->probe(mc);
+ if (err < 0)
+ return err;
}
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- if (mc->soc == &tegra20_mc_soc) {
- isr = tegra20_mc_irq;
- } else
-#endif
- {
- /* ensure that debug features are disabled */
- mc_writel(mc, 0x00000000, MC_TIMING_CONTROL_DBG);
+ if (mc->soc->ops && mc->soc->ops->handle_irq) {
+ mc->irq = platform_get_irq(pdev, 0);
+ if (mc->irq < 0)
+ return mc->irq;
- err = tegra_mc_setup_latency_allowance(mc);
- if (err < 0) {
- dev_err(&pdev->dev,
- "failed to setup latency allowance: %d\n",
- err);
- return err;
- }
+ WARN(!mc->soc->client_id_mask, "missing client ID mask for this SoC\n");
- isr = tegra_mc_irq;
+ mc_writel(mc, mc->soc->intmask, MC_INTMASK);
- err = tegra_mc_setup_timings(mc);
+ err = devm_request_irq(&pdev->dev, mc->irq, mc->soc->ops->handle_irq, 0,
+ dev_name(&pdev->dev), mc);
if (err < 0) {
- dev_err(&pdev->dev, "failed to setup timings: %d\n",
+ dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq,
err);
return err;
}
}
- mc->irq = platform_get_irq(pdev, 0);
- if (mc->irq < 0)
- return mc->irq;
-
- WARN(!mc->soc->client_id_mask, "missing client ID mask for this SoC\n");
-
- mc_writel(mc, mc->soc->intmask, MC_INTMASK);
-
- err = devm_request_irq(&pdev->dev, mc->irq, isr, 0,
- dev_name(&pdev->dev), mc);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq,
- err);
- return err;
- }
-
- mc->debugfs.root = debugfs_create_dir("mc", NULL);
-
- if (mc->soc->init) {
- err = mc->soc->init(mc);
+ if (mc->soc->reset_ops) {
+ err = tegra_mc_reset_setup(mc);
if (err < 0)
- dev_err(&pdev->dev, "failed to initialize SoC driver: %d\n",
- err);
+ dev_err(&pdev->dev, "failed to register reset controller: %d\n", err);
}
- err = tegra_mc_reset_setup(mc);
- if (err < 0)
- dev_err(&pdev->dev, "failed to register reset controller: %d\n",
- err);
-
err = tegra_mc_interconnect_setup(mc);
if (err < 0)
dev_err(&pdev->dev, "failed to initialize interconnect: %d\n",
@@ -867,37 +815,28 @@ static int tegra_mc_probe(struct platform_device *pdev)
return 0;
}
-static int tegra_mc_suspend(struct device *dev)
+static int __maybe_unused tegra_mc_suspend(struct device *dev)
{
struct tegra_mc *mc = dev_get_drvdata(dev);
- int err;
- if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) {
- err = tegra_gart_suspend(mc->gart);
- if (err)
- return err;
- }
+ if (mc->soc->ops && mc->soc->ops->suspend)
+ return mc->soc->ops->suspend(mc);
return 0;
}
-static int tegra_mc_resume(struct device *dev)
+static int __maybe_unused tegra_mc_resume(struct device *dev)
{
struct tegra_mc *mc = dev_get_drvdata(dev);
- int err;
- if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) {
- err = tegra_gart_resume(mc->gart);
- if (err)
- return err;
- }
+ if (mc->soc->ops && mc->soc->ops->resume)
+ return mc->soc->ops->resume(mc);
return 0;
}
static const struct dev_pm_ops tegra_mc_pm_ops = {
- .suspend = tegra_mc_suspend,
- .resume = tegra_mc_resume,
+ SET_SYSTEM_SLEEP_PM_OPS(tegra_mc_suspend, tegra_mc_resume)
};
static struct platform_driver tegra_mc_driver = {
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h
index 1ee34f0da4f7..1e492989c363 100644
--- a/drivers/memory/tegra/mc.h
+++ b/drivers/memory/tegra/mc.h
@@ -129,6 +129,31 @@ extern const struct tegra_mc_soc tegra132_mc_soc;
extern const struct tegra_mc_soc tegra210_mc_soc;
#endif
+#ifdef CONFIG_ARCH_TEGRA_186_SOC
+extern const struct tegra_mc_soc tegra186_mc_soc;
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_194_SOC
+extern const struct tegra_mc_soc tegra194_mc_soc;
+#endif
+
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_114_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_124_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_132_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_210_SOC)
+int tegra30_mc_probe(struct tegra_mc *mc);
+extern const struct tegra_mc_ops tegra30_mc_ops;
+#endif
+
+#if defined(CONFIG_ARCH_TEGRA_186_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_194_SOC)
+extern const struct tegra_mc_ops tegra186_mc_ops;
+#endif
+
+extern const char * const tegra_mc_status_names[32];
+extern const char * const tegra_mc_error_names[8];
+
/*
* These IDs are for internal use of Tegra ICC drivers. The ID numbers are
* chosen such that they don't conflict with the device-tree ICC node IDs.
diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c
index ed376ba2d2fe..41350570c815 100644
--- a/drivers/memory/tegra/tegra114.c
+++ b/drivers/memory/tegra/tegra114.c
@@ -15,883 +15,1013 @@ static const struct tegra_mc_client tegra114_mc_clients[] = {
.id = 0x00,
.name = "ptcr",
.swgroup = TEGRA_SWGROUP_PTC,
- .la = {
- .reg = 0x34c,
- .shift = 0,
- .mask = 0xff,
- .def = 0x0,
+ .regs = {
+ .la = {
+ .reg = 0x34c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0,
+ },
},
}, {
.id = 0x01,
.name = "display0a",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 1,
- },
- .la = {
- .reg = 0x2e8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x4e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x2e8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
},
}, {
.id = 0x02,
.name = "display0ab",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 2,
- },
- .la = {
- .reg = 0x2f4,
- .shift = 0,
- .mask = 0xff,
- .def = 0x4e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x2f4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
},
}, {
.id = 0x03,
.name = "display0b",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 3,
- },
- .la = {
- .reg = 0x2e8,
- .shift = 16,
- .mask = 0xff,
- .def = 0x4e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x2e8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
},
}, {
.id = 0x04,
.name = "display0bb",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 4,
- },
- .la = {
- .reg = 0x2f4,
- .shift = 16,
- .mask = 0xff,
- .def = 0x4e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x2f4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
},
}, {
.id = 0x05,
.name = "display0c",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 5,
- },
- .la = {
- .reg = 0x2ec,
- .shift = 0,
- .mask = 0xff,
- .def = 0x4e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x2ec,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
},
}, {
.id = 0x06,
.name = "display0cb",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 6,
- },
- .la = {
- .reg = 0x2f8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x4e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 6,
+ },
+ .la = {
+ .reg = 0x2f8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
},
}, {
.id = 0x09,
.name = "eppup",
.swgroup = TEGRA_SWGROUP_EPP,
- .smmu = {
- .reg = 0x228,
- .bit = 9,
- },
- .la = {
- .reg = 0x300,
- .shift = 0,
- .mask = 0xff,
- .def = 0x33,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 9,
+ },
+ .la = {
+ .reg = 0x300,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x33,
+ },
},
}, {
.id = 0x0a,
.name = "g2pr",
.swgroup = TEGRA_SWGROUP_G2,
- .smmu = {
- .reg = 0x228,
- .bit = 10,
- },
- .la = {
- .reg = 0x308,
- .shift = 0,
- .mask = 0xff,
- .def = 0x09,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 10,
+ },
+ .la = {
+ .reg = 0x308,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x09,
+ },
},
}, {
.id = 0x0b,
.name = "g2sr",
.swgroup = TEGRA_SWGROUP_G2,
- .smmu = {
- .reg = 0x228,
- .bit = 11,
- },
- .la = {
- .reg = 0x308,
- .shift = 16,
- .mask = 0xff,
- .def = 0x09,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x308,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x09,
+ },
},
}, {
.id = 0x0f,
.name = "avpcarm7r",
.swgroup = TEGRA_SWGROUP_AVPC,
- .smmu = {
- .reg = 0x228,
- .bit = 15,
- },
- .la = {
- .reg = 0x2e4,
- .shift = 0,
- .mask = 0xff,
- .def = 0x04,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 15,
+ },
+ .la = {
+ .reg = 0x2e4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
},
}, {
.id = 0x10,
.name = "displayhc",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 16,
- },
- .la = {
- .reg = 0x2f0,
- .shift = 0,
- .mask = 0xff,
- .def = 0x68,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x2f0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x68,
+ },
},
}, {
.id = 0x11,
.name = "displayhcb",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 17,
- },
- .la = {
- .reg = 0x2fc,
- .shift = 0,
- .mask = 0xff,
- .def = 0x68,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x2fc,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x68,
+ },
},
}, {
.id = 0x12,
.name = "fdcdrd",
.swgroup = TEGRA_SWGROUP_NV,
- .smmu = {
- .reg = 0x228,
- .bit = 18,
- },
- .la = {
- .reg = 0x334,
- .shift = 0,
- .mask = 0xff,
- .def = 0x0c,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 18,
+ },
+ .la = {
+ .reg = 0x334,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0c,
+ },
},
}, {
.id = 0x13,
.name = "fdcdrd2",
.swgroup = TEGRA_SWGROUP_NV,
- .smmu = {
- .reg = 0x228,
- .bit = 19,
- },
- .la = {
- .reg = 0x33c,
- .shift = 0,
- .mask = 0xff,
- .def = 0x0c,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 19,
+ },
+ .la = {
+ .reg = 0x33c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0c,
+ },
},
}, {
.id = 0x14,
.name = "g2dr",
.swgroup = TEGRA_SWGROUP_G2,
- .smmu = {
- .reg = 0x228,
- .bit = 20,
- },
- .la = {
- .reg = 0x30c,
- .shift = 0,
- .mask = 0xff,
- .def = 0x0a,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 20,
+ },
+ .la = {
+ .reg = 0x30c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0a,
+ },
},
}, {
.id = 0x15,
.name = "hdar",
.swgroup = TEGRA_SWGROUP_HDA,
- .smmu = {
- .reg = 0x228,
- .bit = 21,
- },
- .la = {
- .reg = 0x318,
- .shift = 0,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x318,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
}, {
.id = 0x16,
.name = "host1xdmar",
.swgroup = TEGRA_SWGROUP_HC,
- .smmu = {
- .reg = 0x228,
- .bit = 22,
- },
- .la = {
- .reg = 0x310,
- .shift = 0,
- .mask = 0xff,
- .def = 0x10,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x310,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x10,
+ },
},
}, {
.id = 0x17,
.name = "host1xr",
.swgroup = TEGRA_SWGROUP_HC,
- .smmu = {
- .reg = 0x228,
- .bit = 23,
- },
- .la = {
- .reg = 0x310,
- .shift = 16,
- .mask = 0xff,
- .def = 0xa5,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 23,
+ },
+ .la = {
+ .reg = 0x310,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xa5,
+ },
},
}, {
.id = 0x18,
.name = "idxsrd",
.swgroup = TEGRA_SWGROUP_NV,
- .smmu = {
- .reg = 0x228,
- .bit = 24,
- },
- .la = {
- .reg = 0x334,
- .shift = 16,
- .mask = 0xff,
- .def = 0x0b,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 24,
+ },
+ .la = {
+ .reg = 0x334,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0b,
+ },
},
}, {
.id = 0x1c,
.name = "msencsrd",
.swgroup = TEGRA_SWGROUP_MSENC,
- .smmu = {
- .reg = 0x228,
- .bit = 28,
- },
- .la = {
- .reg = 0x328,
- .shift = 0,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 28,
+ },
+ .la = {
+ .reg = 0x328,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x1d,
.name = "ppcsahbdmar",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x228,
- .bit = 29,
- },
- .la = {
- .reg = 0x344,
- .shift = 0,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 29,
+ },
+ .la = {
+ .reg = 0x344,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
}, {
.id = 0x1e,
.name = "ppcsahbslvr",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x228,
- .bit = 30,
- },
- .la = {
- .reg = 0x344,
- .shift = 16,
- .mask = 0xff,
- .def = 0xe8,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 30,
+ },
+ .la = {
+ .reg = 0x344,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xe8,
+ },
},
}, {
.id = 0x20,
.name = "texl2srd",
.swgroup = TEGRA_SWGROUP_NV,
- .smmu = {
- .reg = 0x22c,
- .bit = 0,
- },
- .la = {
- .reg = 0x338,
- .shift = 0,
- .mask = 0xff,
- .def = 0x0c,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 0,
+ },
+ .la = {
+ .reg = 0x338,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0c,
+ },
},
}, {
.id = 0x22,
.name = "vdebsevr",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 2,
- },
- .la = {
- .reg = 0x354,
- .shift = 0,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x354,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
}, {
.id = 0x23,
.name = "vdember",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 3,
- },
- .la = {
- .reg = 0x354,
- .shift = 16,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x354,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
}, {
.id = 0x24,
.name = "vdemcer",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 4,
- },
- .la = {
- .reg = 0x358,
- .shift = 0,
- .mask = 0xff,
- .def = 0xb8,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x358,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xb8,
+ },
},
}, {
.id = 0x25,
.name = "vdetper",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 5,
- },
- .la = {
- .reg = 0x358,
- .shift = 16,
- .mask = 0xff,
- .def = 0xee,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x358,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xee,
+ },
},
}, {
.id = 0x26,
.name = "mpcorelpr",
.swgroup = TEGRA_SWGROUP_MPCORELP,
- .la = {
- .reg = 0x324,
- .shift = 0,
- .mask = 0xff,
- .def = 0x04,
+ .regs = {
+ .la = {
+ .reg = 0x324,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
},
}, {
.id = 0x27,
.name = "mpcorer",
.swgroup = TEGRA_SWGROUP_MPCORE,
- .la = {
- .reg = 0x320,
- .shift = 0,
- .mask = 0xff,
- .def = 0x04,
+ .regs = {
+ .la = {
+ .reg = 0x320,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
},
}, {
.id = 0x28,
.name = "eppu",
.swgroup = TEGRA_SWGROUP_EPP,
- .smmu = {
- .reg = 0x22c,
- .bit = 8,
- },
- .la = {
- .reg = 0x300,
- .shift = 16,
- .mask = 0xff,
- .def = 0x33,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 8,
+ },
+ .la = {
+ .reg = 0x300,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x33,
+ },
},
}, {
.id = 0x29,
.name = "eppv",
.swgroup = TEGRA_SWGROUP_EPP,
- .smmu = {
- .reg = 0x22c,
- .bit = 9,
- },
- .la = {
- .reg = 0x304,
- .shift = 0,
- .mask = 0xff,
- .def = 0x6c,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 9,
+ },
+ .la = {
+ .reg = 0x304,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x6c,
+ },
},
}, {
.id = 0x2a,
.name = "eppy",
.swgroup = TEGRA_SWGROUP_EPP,
- .smmu = {
- .reg = 0x22c,
- .bit = 10,
- },
- .la = {
- .reg = 0x304,
- .shift = 16,
- .mask = 0xff,
- .def = 0x6c,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 10,
+ },
+ .la = {
+ .reg = 0x304,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x6c,
+ },
},
}, {
.id = 0x2b,
.name = "msencswr",
.swgroup = TEGRA_SWGROUP_MSENC,
- .smmu = {
- .reg = 0x22c,
- .bit = 11,
- },
- .la = {
- .reg = 0x328,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x328,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x2c,
.name = "viwsb",
.swgroup = TEGRA_SWGROUP_VI,
- .smmu = {
- .reg = 0x22c,
- .bit = 12,
- },
- .la = {
- .reg = 0x364,
- .shift = 0,
- .mask = 0xff,
- .def = 0x47,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 12,
+ },
+ .la = {
+ .reg = 0x364,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x47,
+ },
},
}, {
.id = 0x2d,
.name = "viwu",
.swgroup = TEGRA_SWGROUP_VI,
- .smmu = {
- .reg = 0x22c,
- .bit = 13,
- },
- .la = {
- .reg = 0x368,
- .shift = 0,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 13,
+ },
+ .la = {
+ .reg = 0x368,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
}, {
.id = 0x2e,
.name = "viwv",
.swgroup = TEGRA_SWGROUP_VI,
- .smmu = {
- .reg = 0x22c,
- .bit = 14,
- },
- .la = {
- .reg = 0x368,
- .shift = 16,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 14,
+ },
+ .la = {
+ .reg = 0x368,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
}, {
.id = 0x2f,
.name = "viwy",
.swgroup = TEGRA_SWGROUP_VI,
- .smmu = {
- .reg = 0x22c,
- .bit = 15,
- },
- .la = {
- .reg = 0x36c,
- .shift = 0,
- .mask = 0xff,
- .def = 0x47,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 15,
+ },
+ .la = {
+ .reg = 0x36c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x47,
+ },
},
}, {
.id = 0x30,
.name = "g2dw",
.swgroup = TEGRA_SWGROUP_G2,
- .smmu = {
- .reg = 0x22c,
- .bit = 16,
- },
- .la = {
- .reg = 0x30c,
- .shift = 16,
- .mask = 0xff,
- .def = 0x9,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x30c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x9,
+ },
},
}, {
.id = 0x32,
.name = "avpcarm7w",
.swgroup = TEGRA_SWGROUP_AVPC,
- .smmu = {
- .reg = 0x22c,
- .bit = 18,
- },
- .la = {
- .reg = 0x2e4,
- .shift = 16,
- .mask = 0xff,
- .def = 0x0e,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 18,
+ },
+ .la = {
+ .reg = 0x2e4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0e,
+ },
},
}, {
.id = 0x33,
.name = "fdcdwr",
.swgroup = TEGRA_SWGROUP_NV,
- .smmu = {
- .reg = 0x22c,
- .bit = 19,
- },
- .la = {
- .reg = 0x338,
- .shift = 16,
- .mask = 0xff,
- .def = 0x10,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 19,
+ },
+ .la = {
+ .reg = 0x338,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x10,
+ },
},
}, {
.id = 0x34,
.name = "fdcdwr2",
.swgroup = TEGRA_SWGROUP_NV,
- .smmu = {
- .reg = 0x22c,
- .bit = 20,
- },
- .la = {
- .reg = 0x340,
- .shift = 0,
- .mask = 0xff,
- .def = 0x10,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 20,
+ },
+ .la = {
+ .reg = 0x340,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x10,
+ },
},
}, {
.id = 0x35,
.name = "hdaw",
.swgroup = TEGRA_SWGROUP_HDA,
- .smmu = {
- .reg = 0x22c,
- .bit = 21,
- },
- .la = {
- .reg = 0x318,
- .shift = 16,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x318,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
}, {
.id = 0x36,
.name = "host1xw",
.swgroup = TEGRA_SWGROUP_HC,
- .smmu = {
- .reg = 0x22c,
- .bit = 22,
- },
- .la = {
- .reg = 0x314,
- .shift = 0,
- .mask = 0xff,
- .def = 0x25,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x314,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x25,
+ },
},
}, {
.id = 0x37,
.name = "ispw",
.swgroup = TEGRA_SWGROUP_ISP,
- .smmu = {
- .reg = 0x22c,
- .bit = 23,
- },
- .la = {
- .reg = 0x31c,
- .shift = 0,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 23,
+ },
+ .la = {
+ .reg = 0x31c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
}, {
.id = 0x38,
.name = "mpcorelpw",
.swgroup = TEGRA_SWGROUP_MPCORELP,
- .la = {
- .reg = 0x324,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .la = {
+ .reg = 0x324,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x39,
.name = "mpcorew",
.swgroup = TEGRA_SWGROUP_MPCORE,
- .la = {
- .reg = 0x320,
- .shift = 16,
- .mask = 0xff,
- .def = 0x0e,
+ .regs = {
+ .la = {
+ .reg = 0x320,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0e,
+ },
},
}, {
.id = 0x3b,
.name = "ppcsahbdmaw",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x22c,
- .bit = 27,
- },
- .la = {
- .reg = 0x348,
- .shift = 0,
- .mask = 0xff,
- .def = 0xa5,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 27,
+ },
+ .la = {
+ .reg = 0x348,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xa5,
+ },
},
}, {
.id = 0x3c,
.name = "ppcsahbslvw",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x22c,
- .bit = 28,
- },
- .la = {
- .reg = 0x348,
- .shift = 16,
- .mask = 0xff,
- .def = 0xe8,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 28,
+ },
+ .la = {
+ .reg = 0x348,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xe8,
+ },
},
}, {
.id = 0x3e,
.name = "vdebsevw",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 30,
- },
- .la = {
- .reg = 0x35c,
- .shift = 0,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 30,
+ },
+ .la = {
+ .reg = 0x35c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
}, {
.id = 0x3f,
.name = "vdedbgw",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 31,
- },
- .la = {
- .reg = 0x35c,
- .shift = 16,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 31,
+ },
+ .la = {
+ .reg = 0x35c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
}, {
.id = 0x40,
.name = "vdembew",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x230,
- .bit = 0,
- },
- .la = {
- .reg = 0x360,
- .shift = 0,
- .mask = 0xff,
- .def = 0x89,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 0,
+ },
+ .la = {
+ .reg = 0x360,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x89,
+ },
},
}, {
.id = 0x41,
.name = "vdetpmw",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x230,
- .bit = 1,
- },
- .la = {
- .reg = 0x360,
- .shift = 16,
- .mask = 0xff,
- .def = 0x59,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x360,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x59,
+ },
},
}, {
.id = 0x4a,
.name = "xusb_hostr",
.swgroup = TEGRA_SWGROUP_XUSB_HOST,
- .smmu = {
- .reg = 0x230,
- .bit = 10,
- },
- .la = {
- .reg = 0x37c,
- .shift = 0,
- .mask = 0xff,
- .def = 0xa5,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 10,
+ },
+ .la = {
+ .reg = 0x37c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xa5,
+ },
},
}, {
.id = 0x4b,
.name = "xusb_hostw",
.swgroup = TEGRA_SWGROUP_XUSB_HOST,
- .smmu = {
- .reg = 0x230,
- .bit = 11,
- },
- .la = {
- .reg = 0x37c,
- .shift = 16,
- .mask = 0xff,
- .def = 0xa5,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x37c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xa5,
+ },
},
}, {
.id = 0x4c,
.name = "xusb_devr",
.swgroup = TEGRA_SWGROUP_XUSB_DEV,
- .smmu = {
- .reg = 0x230,
- .bit = 12,
- },
- .la = {
- .reg = 0x380,
- .shift = 0,
- .mask = 0xff,
- .def = 0xa5,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 12,
+ },
+ .la = {
+ .reg = 0x380,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xa5,
+ },
},
}, {
.id = 0x4d,
.name = "xusb_devw",
.swgroup = TEGRA_SWGROUP_XUSB_DEV,
- .smmu = {
- .reg = 0x230,
- .bit = 13,
- },
- .la = {
- .reg = 0x380,
- .shift = 16,
- .mask = 0xff,
- .def = 0xa5,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 13,
+ },
+ .la = {
+ .reg = 0x380,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xa5,
+ },
},
}, {
.id = 0x4e,
.name = "fdcdwr3",
.swgroup = TEGRA_SWGROUP_NV,
- .smmu = {
- .reg = 0x230,
- .bit = 14,
- },
- .la = {
- .reg = 0x388,
- .shift = 0,
- .mask = 0xff,
- .def = 0x10,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 14,
+ },
+ .la = {
+ .reg = 0x388,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x10,
+ },
},
}, {
.id = 0x4f,
.name = "fdcdrd3",
.swgroup = TEGRA_SWGROUP_NV,
- .smmu = {
- .reg = 0x230,
- .bit = 15,
- },
- .la = {
- .reg = 0x384,
- .shift = 0,
- .mask = 0xff,
- .def = 0x0c,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 15,
+ },
+ .la = {
+ .reg = 0x384,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0c,
+ },
},
}, {
.id = 0x50,
.name = "fdcwr4",
.swgroup = TEGRA_SWGROUP_NV,
- .smmu = {
- .reg = 0x230,
- .bit = 16,
- },
- .la = {
- .reg = 0x388,
- .shift = 16,
- .mask = 0xff,
- .def = 0x10,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x388,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x10,
+ },
},
}, {
.id = 0x51,
.name = "fdcrd4",
.swgroup = TEGRA_SWGROUP_NV,
- .smmu = {
- .reg = 0x230,
- .bit = 17,
- },
- .la = {
- .reg = 0x384,
- .shift = 16,
- .mask = 0xff,
- .def = 0x0c,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x384,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0c,
+ },
},
}, {
.id = 0x52,
.name = "emucifr",
.swgroup = TEGRA_SWGROUP_EMUCIF,
- .la = {
- .reg = 0x38c,
- .shift = 0,
- .mask = 0xff,
- .def = 0x04,
+ .regs = {
+ .la = {
+ .reg = 0x38c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
},
}, {
.id = 0x53,
.name = "emucifw",
.swgroup = TEGRA_SWGROUP_EMUCIF,
- .la = {
- .reg = 0x38c,
- .shift = 16,
- .mask = 0xff,
- .def = 0x0e,
+ .regs = {
+ .la = {
+ .reg = 0x38c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0e,
+ },
},
}, {
.id = 0x54,
.name = "tsecsrd",
.swgroup = TEGRA_SWGROUP_TSEC,
- .smmu = {
- .reg = 0x230,
- .bit = 20,
- },
- .la = {
- .reg = 0x390,
- .shift = 0,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 20,
+ },
+ .la = {
+ .reg = 0x390,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
}, {
.id = 0x55,
.name = "tsecswr",
.swgroup = TEGRA_SWGROUP_TSEC,
- .smmu = {
- .reg = 0x230,
- .bit = 21,
- },
- .la = {
- .reg = 0x390,
- .shift = 16,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x390,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
},
};
@@ -983,4 +1113,5 @@ const struct tegra_mc_soc tegra114_mc_soc = {
.reset_ops = &tegra_mc_reset_ops_common,
.resets = tegra114_mc_resets,
.num_resets = ARRAY_SIZE(tegra114_mc_resets),
+ .ops = &tegra30_mc_ops,
};
diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c
index 5699d909abc2..908f8d5392b2 100644
--- a/drivers/memory/tegra/tegra124-emc.c
+++ b/drivers/memory/tegra/tegra124-emc.c
@@ -272,8 +272,8 @@
#define EMC_PUTERM_ADJ 0x574
#define DRAM_DEV_SEL_ALL 0
-#define DRAM_DEV_SEL_0 (2 << 30)
-#define DRAM_DEV_SEL_1 (1 << 30)
+#define DRAM_DEV_SEL_0 BIT(31)
+#define DRAM_DEV_SEL_1 BIT(30)
#define EMC_CFG_POWER_FEATURES_MASK \
(EMC_CFG_DYN_SREF | EMC_CFG_DRAM_ACPD | EMC_CFG_DRAM_CLKSTOP_SR | \
@@ -1269,10 +1269,6 @@ static void emc_debugfs_init(struct device *dev, struct tegra_emc *emc)
}
emc->debugfs.root = debugfs_create_dir("emc", NULL);
- if (!emc->debugfs.root) {
- dev_err(dev, "failed to create debugfs directory\n");
- return;
- }
debugfs_create_file("available_rates", 0444, emc->debugfs.root, emc,
&tegra_emc_debug_available_rates_fops);
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
index 459211f50c08..d780a84241fe 100644
--- a/drivers/memory/tegra/tegra124.c
+++ b/drivers/memory/tegra/tegra124.c
@@ -16,921 +16,1055 @@ static const struct tegra_mc_client tegra124_mc_clients[] = {
.id = 0x00,
.name = "ptcr",
.swgroup = TEGRA_SWGROUP_PTC,
- .la = {
- .reg = 0x34c,
- .shift = 0,
- .mask = 0xff,
- .def = 0x0,
+ .regs = {
+ .la = {
+ .reg = 0x34c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0,
+ },
},
}, {
.id = 0x01,
.name = "display0a",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 1,
- },
- .la = {
- .reg = 0x2e8,
- .shift = 0,
- .mask = 0xff,
- .def = 0xc2,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x2e8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xc2,
+ },
},
}, {
.id = 0x02,
.name = "display0ab",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 2,
- },
- .la = {
- .reg = 0x2f4,
- .shift = 0,
- .mask = 0xff,
- .def = 0xc6,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x2f4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xc6,
+ },
},
}, {
.id = 0x03,
.name = "display0b",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 3,
- },
- .la = {
- .reg = 0x2e8,
- .shift = 16,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x2e8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
}, {
.id = 0x04,
.name = "display0bb",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 4,
- },
- .la = {
- .reg = 0x2f4,
- .shift = 16,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x2f4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
}, {
.id = 0x05,
.name = "display0c",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 5,
- },
- .la = {
- .reg = 0x2ec,
- .shift = 0,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x2ec,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
}, {
.id = 0x06,
.name = "display0cb",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 6,
- },
- .la = {
- .reg = 0x2f8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 6,
+ },
+ .la = {
+ .reg = 0x2f8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
}, {
.id = 0x0e,
.name = "afir",
.swgroup = TEGRA_SWGROUP_AFI,
- .smmu = {
- .reg = 0x228,
- .bit = 14,
- },
- .la = {
- .reg = 0x2e0,
- .shift = 0,
- .mask = 0xff,
- .def = 0x13,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 14,
+ },
+ .la = {
+ .reg = 0x2e0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x13,
+ },
},
}, {
.id = 0x0f,
.name = "avpcarm7r",
.swgroup = TEGRA_SWGROUP_AVPC,
- .smmu = {
- .reg = 0x228,
- .bit = 15,
- },
- .la = {
- .reg = 0x2e4,
- .shift = 0,
- .mask = 0xff,
- .def = 0x04,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 15,
+ },
+ .la = {
+ .reg = 0x2e4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
},
}, {
.id = 0x10,
.name = "displayhc",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 16,
- },
- .la = {
- .reg = 0x2f0,
- .shift = 0,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x2f0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
}, {
.id = 0x11,
.name = "displayhcb",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 17,
- },
- .la = {
- .reg = 0x2fc,
- .shift = 0,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x2fc,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
}, {
.id = 0x15,
.name = "hdar",
.swgroup = TEGRA_SWGROUP_HDA,
- .smmu = {
- .reg = 0x228,
- .bit = 21,
- },
- .la = {
- .reg = 0x318,
- .shift = 0,
- .mask = 0xff,
- .def = 0x24,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x318,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x24,
+ },
},
}, {
.id = 0x16,
.name = "host1xdmar",
.swgroup = TEGRA_SWGROUP_HC,
- .smmu = {
- .reg = 0x228,
- .bit = 22,
- },
- .la = {
- .reg = 0x310,
- .shift = 0,
- .mask = 0xff,
- .def = 0x1e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x310,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1e,
+ },
},
}, {
.id = 0x17,
.name = "host1xr",
.swgroup = TEGRA_SWGROUP_HC,
- .smmu = {
- .reg = 0x228,
- .bit = 23,
- },
- .la = {
- .reg = 0x310,
- .shift = 16,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 23,
+ },
+ .la = {
+ .reg = 0x310,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
}, {
.id = 0x1c,
.name = "msencsrd",
.swgroup = TEGRA_SWGROUP_MSENC,
- .smmu = {
- .reg = 0x228,
- .bit = 28,
- },
- .la = {
- .reg = 0x328,
- .shift = 0,
- .mask = 0xff,
- .def = 0x23,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 28,
+ },
+ .la = {
+ .reg = 0x328,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x23,
+ },
},
}, {
.id = 0x1d,
.name = "ppcsahbdmar",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x228,
- .bit = 29,
- },
- .la = {
- .reg = 0x344,
- .shift = 0,
- .mask = 0xff,
- .def = 0x49,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 29,
+ },
+ .la = {
+ .reg = 0x344,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x49,
+ },
},
}, {
.id = 0x1e,
.name = "ppcsahbslvr",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x228,
- .bit = 30,
- },
- .la = {
- .reg = 0x344,
- .shift = 16,
- .mask = 0xff,
- .def = 0x1a,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 30,
+ },
+ .la = {
+ .reg = 0x344,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x1a,
+ },
},
}, {
.id = 0x1f,
.name = "satar",
.swgroup = TEGRA_SWGROUP_SATA,
- .smmu = {
- .reg = 0x228,
- .bit = 31,
- },
- .la = {
- .reg = 0x350,
- .shift = 0,
- .mask = 0xff,
- .def = 0x65,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 31,
+ },
+ .la = {
+ .reg = 0x350,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x65,
+ },
},
}, {
.id = 0x22,
.name = "vdebsevr",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 2,
- },
- .la = {
- .reg = 0x354,
- .shift = 0,
- .mask = 0xff,
- .def = 0x4f,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x354,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4f,
+ },
},
}, {
.id = 0x23,
.name = "vdember",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 3,
- },
- .la = {
- .reg = 0x354,
- .shift = 16,
- .mask = 0xff,
- .def = 0x3d,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x354,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x3d,
+ },
},
}, {
.id = 0x24,
.name = "vdemcer",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 4,
- },
- .la = {
- .reg = 0x358,
- .shift = 0,
- .mask = 0xff,
- .def = 0x66,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x358,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x66,
+ },
},
}, {
.id = 0x25,
.name = "vdetper",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 5,
- },
- .la = {
- .reg = 0x358,
- .shift = 16,
- .mask = 0xff,
- .def = 0xa5,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x358,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xa5,
+ },
},
}, {
.id = 0x26,
.name = "mpcorelpr",
.swgroup = TEGRA_SWGROUP_MPCORELP,
- .la = {
- .reg = 0x324,
- .shift = 0,
- .mask = 0xff,
- .def = 0x04,
+ .regs = {
+ .la = {
+ .reg = 0x324,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
},
}, {
.id = 0x27,
.name = "mpcorer",
.swgroup = TEGRA_SWGROUP_MPCORE,
- .la = {
- .reg = 0x320,
- .shift = 0,
- .mask = 0xff,
- .def = 0x04,
+ .regs = {
+ .la = {
+ .reg = 0x320,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
},
}, {
.id = 0x2b,
.name = "msencswr",
.swgroup = TEGRA_SWGROUP_MSENC,
- .smmu = {
- .reg = 0x22c,
- .bit = 11,
- },
- .la = {
- .reg = 0x328,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x328,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x31,
.name = "afiw",
.swgroup = TEGRA_SWGROUP_AFI,
- .smmu = {
- .reg = 0x22c,
- .bit = 17,
- },
- .la = {
- .reg = 0x2e0,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x2e0,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x32,
.name = "avpcarm7w",
.swgroup = TEGRA_SWGROUP_AVPC,
- .smmu = {
- .reg = 0x22c,
- .bit = 18,
- },
- .la = {
- .reg = 0x2e4,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 18,
+ },
+ .la = {
+ .reg = 0x2e4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x35,
.name = "hdaw",
.swgroup = TEGRA_SWGROUP_HDA,
- .smmu = {
- .reg = 0x22c,
- .bit = 21,
- },
- .la = {
- .reg = 0x318,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x318,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x36,
.name = "host1xw",
.swgroup = TEGRA_SWGROUP_HC,
- .smmu = {
- .reg = 0x22c,
- .bit = 22,
- },
- .la = {
- .reg = 0x314,
- .shift = 0,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x314,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x38,
.name = "mpcorelpw",
.swgroup = TEGRA_SWGROUP_MPCORELP,
- .la = {
- .reg = 0x324,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .la = {
+ .reg = 0x324,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x39,
.name = "mpcorew",
.swgroup = TEGRA_SWGROUP_MPCORE,
- .la = {
- .reg = 0x320,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .la = {
+ .reg = 0x320,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x3b,
.name = "ppcsahbdmaw",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x22c,
- .bit = 27,
- },
- .la = {
- .reg = 0x348,
- .shift = 0,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 27,
+ },
+ .la = {
+ .reg = 0x348,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x3c,
.name = "ppcsahbslvw",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x22c,
- .bit = 28,
- },
- .la = {
- .reg = 0x348,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 28,
+ },
+ .la = {
+ .reg = 0x348,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x3d,
.name = "sataw",
.swgroup = TEGRA_SWGROUP_SATA,
- .smmu = {
- .reg = 0x22c,
- .bit = 29,
- },
- .la = {
- .reg = 0x350,
- .shift = 16,
- .mask = 0xff,
- .def = 0x65,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 29,
+ },
+ .la = {
+ .reg = 0x350,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x65,
+ },
},
}, {
.id = 0x3e,
.name = "vdebsevw",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 30,
- },
- .la = {
- .reg = 0x35c,
- .shift = 0,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 30,
+ },
+ .la = {
+ .reg = 0x35c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x3f,
.name = "vdedbgw",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 31,
- },
- .la = {
- .reg = 0x35c,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 31,
+ },
+ .la = {
+ .reg = 0x35c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x40,
.name = "vdembew",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x230,
- .bit = 0,
- },
- .la = {
- .reg = 0x360,
- .shift = 0,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 0,
+ },
+ .la = {
+ .reg = 0x360,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x41,
.name = "vdetpmw",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x230,
- .bit = 1,
- },
- .la = {
- .reg = 0x360,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x360,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x44,
.name = "ispra",
.swgroup = TEGRA_SWGROUP_ISP2,
- .smmu = {
- .reg = 0x230,
- .bit = 4,
- },
- .la = {
- .reg = 0x370,
- .shift = 0,
- .mask = 0xff,
- .def = 0x18,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x370,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x18,
+ },
},
}, {
.id = 0x46,
.name = "ispwa",
.swgroup = TEGRA_SWGROUP_ISP2,
- .smmu = {
- .reg = 0x230,
- .bit = 6,
- },
- .la = {
- .reg = 0x374,
- .shift = 0,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 6,
+ },
+ .la = {
+ .reg = 0x374,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x47,
.name = "ispwb",
.swgroup = TEGRA_SWGROUP_ISP2,
- .smmu = {
- .reg = 0x230,
- .bit = 7,
- },
- .la = {
- .reg = 0x374,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 7,
+ },
+ .la = {
+ .reg = 0x374,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x4a,
.name = "xusb_hostr",
.swgroup = TEGRA_SWGROUP_XUSB_HOST,
- .smmu = {
- .reg = 0x230,
- .bit = 10,
- },
- .la = {
- .reg = 0x37c,
- .shift = 0,
- .mask = 0xff,
- .def = 0x39,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 10,
+ },
+ .la = {
+ .reg = 0x37c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x39,
+ },
},
}, {
.id = 0x4b,
.name = "xusb_hostw",
.swgroup = TEGRA_SWGROUP_XUSB_HOST,
- .smmu = {
- .reg = 0x230,
- .bit = 11,
- },
- .la = {
- .reg = 0x37c,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x37c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x4c,
.name = "xusb_devr",
.swgroup = TEGRA_SWGROUP_XUSB_DEV,
- .smmu = {
- .reg = 0x230,
- .bit = 12,
- },
- .la = {
- .reg = 0x380,
- .shift = 0,
- .mask = 0xff,
- .def = 0x39,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 12,
+ },
+ .la = {
+ .reg = 0x380,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x39,
+ },
},
}, {
.id = 0x4d,
.name = "xusb_devw",
.swgroup = TEGRA_SWGROUP_XUSB_DEV,
- .smmu = {
- .reg = 0x230,
- .bit = 13,
- },
- .la = {
- .reg = 0x380,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 13,
+ },
+ .la = {
+ .reg = 0x380,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x4e,
.name = "isprab",
.swgroup = TEGRA_SWGROUP_ISP2B,
- .smmu = {
- .reg = 0x230,
- .bit = 14,
- },
- .la = {
- .reg = 0x384,
- .shift = 0,
- .mask = 0xff,
- .def = 0x18,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 14,
+ },
+ .la = {
+ .reg = 0x384,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x18,
+ },
},
}, {
.id = 0x50,
.name = "ispwab",
.swgroup = TEGRA_SWGROUP_ISP2B,
- .smmu = {
- .reg = 0x230,
- .bit = 16,
- },
- .la = {
- .reg = 0x388,
- .shift = 0,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x388,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x51,
.name = "ispwbb",
.swgroup = TEGRA_SWGROUP_ISP2B,
- .smmu = {
- .reg = 0x230,
- .bit = 17,
- },
- .la = {
- .reg = 0x388,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x388,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x54,
.name = "tsecsrd",
.swgroup = TEGRA_SWGROUP_TSEC,
- .smmu = {
- .reg = 0x230,
- .bit = 20,
- },
- .la = {
- .reg = 0x390,
- .shift = 0,
- .mask = 0xff,
- .def = 0x9b,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 20,
+ },
+ .la = {
+ .reg = 0x390,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x9b,
+ },
},
}, {
.id = 0x55,
.name = "tsecswr",
.swgroup = TEGRA_SWGROUP_TSEC,
- .smmu = {
- .reg = 0x230,
- .bit = 21,
- },
- .la = {
- .reg = 0x390,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x390,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x56,
.name = "a9avpscr",
.swgroup = TEGRA_SWGROUP_A9AVP,
- .smmu = {
- .reg = 0x230,
- .bit = 22,
- },
- .la = {
- .reg = 0x3a4,
- .shift = 0,
- .mask = 0xff,
- .def = 0x04,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x3a4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
},
}, {
.id = 0x57,
.name = "a9avpscw",
.swgroup = TEGRA_SWGROUP_A9AVP,
- .smmu = {
- .reg = 0x230,
- .bit = 23,
- },
- .la = {
- .reg = 0x3a4,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 23,
+ },
+ .la = {
+ .reg = 0x3a4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x58,
.name = "gpusrd",
.swgroup = TEGRA_SWGROUP_GPU,
- .smmu = {
- /* read-only */
- .reg = 0x230,
- .bit = 24,
- },
- .la = {
- .reg = 0x3c8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x1a,
+ .regs = {
+ .smmu = {
+ /* read-only */
+ .reg = 0x230,
+ .bit = 24,
+ },
+ .la = {
+ .reg = 0x3c8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1a,
+ },
},
}, {
.id = 0x59,
.name = "gpuswr",
.swgroup = TEGRA_SWGROUP_GPU,
- .smmu = {
- /* read-only */
- .reg = 0x230,
- .bit = 25,
- },
- .la = {
- .reg = 0x3c8,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ /* read-only */
+ .reg = 0x230,
+ .bit = 25,
+ },
+ .la = {
+ .reg = 0x3c8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x5a,
.name = "displayt",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x230,
- .bit = 26,
- },
- .la = {
- .reg = 0x2f0,
- .shift = 16,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 26,
+ },
+ .la = {
+ .reg = 0x2f0,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
}, {
.id = 0x60,
.name = "sdmmcra",
.swgroup = TEGRA_SWGROUP_SDMMC1A,
- .smmu = {
- .reg = 0x234,
- .bit = 0,
- },
- .la = {
- .reg = 0x3b8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x49,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 0,
+ },
+ .la = {
+ .reg = 0x3b8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x49,
+ },
},
}, {
.id = 0x61,
.name = "sdmmcraa",
.swgroup = TEGRA_SWGROUP_SDMMC2A,
- .smmu = {
- .reg = 0x234,
- .bit = 1,
- },
- .la = {
- .reg = 0x3bc,
- .shift = 0,
- .mask = 0xff,
- .def = 0x49,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x3bc,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x49,
+ },
},
}, {
.id = 0x62,
.name = "sdmmcr",
.swgroup = TEGRA_SWGROUP_SDMMC3A,
- .smmu = {
- .reg = 0x234,
- .bit = 2,
- },
- .la = {
- .reg = 0x3c0,
- .shift = 0,
- .mask = 0xff,
- .def = 0x49,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x3c0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x49,
+ },
},
}, {
.id = 0x63,
.swgroup = TEGRA_SWGROUP_SDMMC4A,
.name = "sdmmcrab",
- .smmu = {
- .reg = 0x234,
- .bit = 3,
- },
- .la = {
- .reg = 0x3c4,
- .shift = 0,
- .mask = 0xff,
- .def = 0x49,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x3c4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x49,
+ },
},
}, {
.id = 0x64,
.name = "sdmmcwa",
.swgroup = TEGRA_SWGROUP_SDMMC1A,
- .smmu = {
- .reg = 0x234,
- .bit = 4,
- },
- .la = {
- .reg = 0x3b8,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x3b8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x65,
.name = "sdmmcwaa",
.swgroup = TEGRA_SWGROUP_SDMMC2A,
- .smmu = {
- .reg = 0x234,
- .bit = 5,
- },
- .la = {
- .reg = 0x3bc,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x3bc,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x66,
.name = "sdmmcw",
.swgroup = TEGRA_SWGROUP_SDMMC3A,
- .smmu = {
- .reg = 0x234,
- .bit = 6,
- },
- .la = {
- .reg = 0x3c0,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 6,
+ },
+ .la = {
+ .reg = 0x3c0,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x67,
.name = "sdmmcwab",
.swgroup = TEGRA_SWGROUP_SDMMC4A,
- .smmu = {
- .reg = 0x234,
- .bit = 7,
- },
- .la = {
- .reg = 0x3c4,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 7,
+ },
+ .la = {
+ .reg = 0x3c4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x6c,
.name = "vicsrd",
.swgroup = TEGRA_SWGROUP_VIC,
- .smmu = {
- .reg = 0x234,
- .bit = 12,
- },
- .la = {
- .reg = 0x394,
- .shift = 0,
- .mask = 0xff,
- .def = 0x1a,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 12,
+ },
+ .la = {
+ .reg = 0x394,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1a,
+ },
},
}, {
.id = 0x6d,
.name = "vicswr",
.swgroup = TEGRA_SWGROUP_VIC,
- .smmu = {
- .reg = 0x234,
- .bit = 13,
- },
- .la = {
- .reg = 0x394,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 13,
+ },
+ .la = {
+ .reg = 0x394,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x72,
.name = "viw",
.swgroup = TEGRA_SWGROUP_VI,
- .smmu = {
- .reg = 0x234,
- .bit = 18,
- },
- .la = {
- .reg = 0x398,
- .shift = 0,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 18,
+ },
+ .la = {
+ .reg = 0x398,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x73,
.name = "displayd",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x234,
- .bit = 19,
- },
- .la = {
- .reg = 0x3c8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 19,
+ },
+ .la = {
+ .reg = 0x3c8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
},
};
@@ -1140,6 +1274,7 @@ const struct tegra_mc_soc tegra124_mc_soc = {
.resets = tegra124_mc_resets,
.num_resets = ARRAY_SIZE(tegra124_mc_resets),
.icc_ops = &tegra124_mc_icc_ops,
+ .ops = &tegra30_mc_ops,
};
#endif /* CONFIG_ARCH_TEGRA_124_SOC */
@@ -1171,5 +1306,6 @@ const struct tegra_mc_soc tegra132_mc_soc = {
.resets = tegra124_mc_resets,
.num_resets = ARRAY_SIZE(tegra124_mc_resets),
.icc_ops = &tegra124_mc_icc_ops,
+ .ops = &tegra30_mc_ops,
};
#endif /* CONFIG_ARCH_TEGRA_132_SOC */
diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c
index e25c954dde2e..e65eac5764d4 100644
--- a/drivers/memory/tegra/tegra186.c
+++ b/drivers/memory/tegra/tegra186.c
@@ -1,1605 +1,878 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2017-2021 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/io.h>
+#include <linux/iommu.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <soc/tegra/mc.h>
+
#if defined(CONFIG_ARCH_TEGRA_186_SOC)
#include <dt-bindings/memory/tegra186-mc.h>
#endif
-#if defined(CONFIG_ARCH_TEGRA_194_SOC)
-#include <dt-bindings/memory/tegra194-mc.h>
-#endif
-
-struct tegra186_mc_client {
- const char *name;
- unsigned int sid;
- struct {
- unsigned int override;
- unsigned int security;
- } regs;
-};
-
-struct tegra186_mc_soc {
- const struct tegra186_mc_client *clients;
- unsigned int num_clients;
-};
-
-struct tegra186_mc {
- struct device *dev;
- void __iomem *regs;
-
- const struct tegra186_mc_soc *soc;
-};
+#define MC_SID_STREAMID_OVERRIDE_MASK GENMASK(7, 0)
+#define MC_SID_STREAMID_SECURITY_WRITE_ACCESS_DISABLED BIT(16)
+#define MC_SID_STREAMID_SECURITY_OVERRIDE BIT(8)
-static void tegra186_mc_program_sid(struct tegra186_mc *mc)
+static void tegra186_mc_program_sid(struct tegra_mc *mc)
{
unsigned int i;
for (i = 0; i < mc->soc->num_clients; i++) {
- const struct tegra186_mc_client *client = &mc->soc->clients[i];
+ const struct tegra_mc_client *client = &mc->soc->clients[i];
u32 override, security;
- override = readl(mc->regs + client->regs.override);
- security = readl(mc->regs + client->regs.security);
+ override = readl(mc->regs + client->regs.sid.override);
+ security = readl(mc->regs + client->regs.sid.security);
dev_dbg(mc->dev, "client %s: override: %x security: %x\n",
client->name, override, security);
dev_dbg(mc->dev, "setting SID %u for %s\n", client->sid,
client->name);
- writel(client->sid, mc->regs + client->regs.override);
+ writel(client->sid, mc->regs + client->regs.sid.override);
- override = readl(mc->regs + client->regs.override);
- security = readl(mc->regs + client->regs.security);
+ override = readl(mc->regs + client->regs.sid.override);
+ security = readl(mc->regs + client->regs.sid.security);
dev_dbg(mc->dev, "client %s: override: %x security: %x\n",
client->name, override, security);
}
}
+static int tegra186_mc_probe(struct tegra_mc *mc)
+{
+ int err;
+
+ err = of_platform_populate(mc->dev->of_node, NULL, NULL, mc->dev);
+ if (err < 0)
+ return err;
+
+ tegra186_mc_program_sid(mc);
+
+ return 0;
+}
+
+static void tegra186_mc_remove(struct tegra_mc *mc)
+{
+ of_platform_depopulate(mc->dev);
+}
+
+static int tegra186_mc_resume(struct tegra_mc *mc)
+{
+ tegra186_mc_program_sid(mc);
+
+ return 0;
+}
+
+static void tegra186_mc_client_sid_override(struct tegra_mc *mc,
+ const struct tegra_mc_client *client,
+ unsigned int sid)
+{
+ u32 value, old;
+
+ value = readl(mc->regs + client->regs.sid.security);
+ if ((value & MC_SID_STREAMID_SECURITY_OVERRIDE) == 0) {
+ /*
+ * If the secure firmware has locked this down the override
+ * for this memory client, there's nothing we can do here.
+ */
+ if (value & MC_SID_STREAMID_SECURITY_WRITE_ACCESS_DISABLED)
+ return;
+
+ /*
+ * Otherwise, try to set the override itself. Typically the
+ * secure firmware will never have set this configuration.
+ * Instead, it will either have disabled write access to
+ * this field, or it will already have set an explicit
+ * override itself.
+ */
+ WARN_ON((value & MC_SID_STREAMID_SECURITY_OVERRIDE) == 0);
+
+ value |= MC_SID_STREAMID_SECURITY_OVERRIDE;
+ writel(value, mc->regs + client->regs.sid.security);
+ }
+
+ value = readl(mc->regs + client->regs.sid.override);
+ old = value & MC_SID_STREAMID_OVERRIDE_MASK;
+
+ if (old != sid) {
+ dev_dbg(mc->dev, "overriding SID %x for %s with %x\n", old,
+ client->name, sid);
+ writel(sid, mc->regs + client->regs.sid.override);
+ }
+}
+
+static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev)
+{
+#if IS_ENABLED(CONFIG_IOMMU_API)
+ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+ struct of_phandle_args args;
+ unsigned int i, index = 0;
+
+ while (!of_parse_phandle_with_args(dev->of_node, "interconnects", "#interconnect-cells",
+ index, &args)) {
+ if (args.np == mc->dev->of_node && args.args_count != 0) {
+ for (i = 0; i < mc->soc->num_clients; i++) {
+ const struct tegra_mc_client *client = &mc->soc->clients[i];
+
+ if (client->id == args.args[0]) {
+ u32 sid = fwspec->ids[0] & MC_SID_STREAMID_OVERRIDE_MASK;
+
+ tegra186_mc_client_sid_override(mc, client, sid);
+ }
+ }
+ }
+
+ index++;
+ }
+#endif
+
+ return 0;
+}
+
+const struct tegra_mc_ops tegra186_mc_ops = {
+ .probe = tegra186_mc_probe,
+ .remove = tegra186_mc_remove,
+ .resume = tegra186_mc_resume,
+ .probe_device = tegra186_mc_probe_device,
+};
+
#if defined(CONFIG_ARCH_TEGRA_186_SOC)
-static const struct tegra186_mc_client tegra186_mc_clients[] = {
+static const struct tegra_mc_client tegra186_mc_clients[] = {
{
+ .id = TEGRA186_MEMORY_CLIENT_PTCR,
.name = "ptcr",
.sid = TEGRA186_SID_PASSTHROUGH,
.regs = {
- .override = 0x000,
- .security = 0x004,
+ .sid = {
+ .override = 0x000,
+ .security = 0x004,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_AFIR,
.name = "afir",
.sid = TEGRA186_SID_AFI,
.regs = {
- .override = 0x070,
- .security = 0x074,
+ .sid = {
+ .override = 0x070,
+ .security = 0x074,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_HDAR,
.name = "hdar",
.sid = TEGRA186_SID_HDA,
.regs = {
- .override = 0x0a8,
- .security = 0x0ac,
+ .sid = {
+ .override = 0x0a8,
+ .security = 0x0ac,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_HOST1XDMAR,
.name = "host1xdmar",
.sid = TEGRA186_SID_HOST1X,
.regs = {
- .override = 0x0b0,
- .security = 0x0b4,
+ .sid = {
+ .override = 0x0b0,
+ .security = 0x0b4,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_NVENCSRD,
.name = "nvencsrd",
.sid = TEGRA186_SID_NVENC,
.regs = {
- .override = 0x0e0,
- .security = 0x0e4,
+ .sid = {
+ .override = 0x0e0,
+ .security = 0x0e4,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SATAR,
.name = "satar",
.sid = TEGRA186_SID_SATA,
.regs = {
- .override = 0x0f8,
- .security = 0x0fc,
+ .sid = {
+ .override = 0x0f8,
+ .security = 0x0fc,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_MPCORER,
.name = "mpcorer",
.sid = TEGRA186_SID_PASSTHROUGH,
.regs = {
- .override = 0x138,
- .security = 0x13c,
+ .sid = {
+ .override = 0x138,
+ .security = 0x13c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_NVENCSWR,
.name = "nvencswr",
.sid = TEGRA186_SID_NVENC,
.regs = {
- .override = 0x158,
- .security = 0x15c,
+ .sid = {
+ .override = 0x158,
+ .security = 0x15c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_AFIW,
.name = "afiw",
.sid = TEGRA186_SID_AFI,
.regs = {
- .override = 0x188,
- .security = 0x18c,
+ .sid = {
+ .override = 0x188,
+ .security = 0x18c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_HDAW,
.name = "hdaw",
.sid = TEGRA186_SID_HDA,
.regs = {
- .override = 0x1a8,
- .security = 0x1ac,
+ .sid = {
+ .override = 0x1a8,
+ .security = 0x1ac,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_MPCOREW,
.name = "mpcorew",
.sid = TEGRA186_SID_PASSTHROUGH,
.regs = {
- .override = 0x1c8,
- .security = 0x1cc,
+ .sid = {
+ .override = 0x1c8,
+ .security = 0x1cc,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SATAW,
.name = "sataw",
.sid = TEGRA186_SID_SATA,
.regs = {
- .override = 0x1e8,
- .security = 0x1ec,
+ .sid = {
+ .override = 0x1e8,
+ .security = 0x1ec,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_ISPRA,
.name = "ispra",
.sid = TEGRA186_SID_ISP,
.regs = {
- .override = 0x220,
- .security = 0x224,
+ .sid = {
+ .override = 0x220,
+ .security = 0x224,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_ISPWA,
.name = "ispwa",
.sid = TEGRA186_SID_ISP,
.regs = {
- .override = 0x230,
- .security = 0x234,
+ .sid = {
+ .override = 0x230,
+ .security = 0x234,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_ISPWB,
.name = "ispwb",
.sid = TEGRA186_SID_ISP,
.regs = {
- .override = 0x238,
- .security = 0x23c,
+ .sid = {
+ .override = 0x238,
+ .security = 0x23c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_XUSB_HOSTR,
.name = "xusb_hostr",
.sid = TEGRA186_SID_XUSB_HOST,
.regs = {
- .override = 0x250,
- .security = 0x254,
+ .sid = {
+ .override = 0x250,
+ .security = 0x254,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_XUSB_HOSTW,
.name = "xusb_hostw",
.sid = TEGRA186_SID_XUSB_HOST,
.regs = {
- .override = 0x258,
- .security = 0x25c,
+ .sid = {
+ .override = 0x258,
+ .security = 0x25c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_XUSB_DEVR,
.name = "xusb_devr",
.sid = TEGRA186_SID_XUSB_DEV,
.regs = {
- .override = 0x260,
- .security = 0x264,
+ .sid = {
+ .override = 0x260,
+ .security = 0x264,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_XUSB_DEVW,
.name = "xusb_devw",
.sid = TEGRA186_SID_XUSB_DEV,
.regs = {
- .override = 0x268,
- .security = 0x26c,
+ .sid = {
+ .override = 0x268,
+ .security = 0x26c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_TSECSRD,
.name = "tsecsrd",
.sid = TEGRA186_SID_TSEC,
.regs = {
- .override = 0x2a0,
- .security = 0x2a4,
+ .sid = {
+ .override = 0x2a0,
+ .security = 0x2a4,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_TSECSWR,
.name = "tsecswr",
.sid = TEGRA186_SID_TSEC,
.regs = {
- .override = 0x2a8,
- .security = 0x2ac,
+ .sid = {
+ .override = 0x2a8,
+ .security = 0x2ac,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_GPUSRD,
.name = "gpusrd",
.sid = TEGRA186_SID_GPU,
.regs = {
- .override = 0x2c0,
- .security = 0x2c4,
+ .sid = {
+ .override = 0x2c0,
+ .security = 0x2c4,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_GPUSWR,
.name = "gpuswr",
.sid = TEGRA186_SID_GPU,
.regs = {
- .override = 0x2c8,
- .security = 0x2cc,
+ .sid = {
+ .override = 0x2c8,
+ .security = 0x2cc,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SDMMCRA,
.name = "sdmmcra",
.sid = TEGRA186_SID_SDMMC1,
.regs = {
- .override = 0x300,
- .security = 0x304,
+ .sid = {
+ .override = 0x300,
+ .security = 0x304,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SDMMCRAA,
.name = "sdmmcraa",
.sid = TEGRA186_SID_SDMMC2,
.regs = {
- .override = 0x308,
- .security = 0x30c,
+ .sid = {
+ .override = 0x308,
+ .security = 0x30c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SDMMCR,
.name = "sdmmcr",
.sid = TEGRA186_SID_SDMMC3,
.regs = {
- .override = 0x310,
- .security = 0x314,
+ .sid = {
+ .override = 0x310,
+ .security = 0x314,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SDMMCRAB,
.name = "sdmmcrab",
.sid = TEGRA186_SID_SDMMC4,
.regs = {
- .override = 0x318,
- .security = 0x31c,
+ .sid = {
+ .override = 0x318,
+ .security = 0x31c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SDMMCWA,
.name = "sdmmcwa",
.sid = TEGRA186_SID_SDMMC1,
.regs = {
- .override = 0x320,
- .security = 0x324,
+ .sid = {
+ .override = 0x320,
+ .security = 0x324,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SDMMCWAA,
.name = "sdmmcwaa",
.sid = TEGRA186_SID_SDMMC2,
.regs = {
- .override = 0x328,
- .security = 0x32c,
+ .sid = {
+ .override = 0x328,
+ .security = 0x32c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SDMMCW,
.name = "sdmmcw",
.sid = TEGRA186_SID_SDMMC3,
.regs = {
- .override = 0x330,
- .security = 0x334,
+ .sid = {
+ .override = 0x330,
+ .security = 0x334,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SDMMCWAB,
.name = "sdmmcwab",
.sid = TEGRA186_SID_SDMMC4,
.regs = {
- .override = 0x338,
- .security = 0x33c,
+ .sid = {
+ .override = 0x338,
+ .security = 0x33c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_VICSRD,
.name = "vicsrd",
.sid = TEGRA186_SID_VIC,
.regs = {
- .override = 0x360,
- .security = 0x364,
+ .sid = {
+ .override = 0x360,
+ .security = 0x364,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_VICSWR,
.name = "vicswr",
.sid = TEGRA186_SID_VIC,
.regs = {
- .override = 0x368,
- .security = 0x36c,
+ .sid = {
+ .override = 0x368,
+ .security = 0x36c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_VIW,
.name = "viw",
.sid = TEGRA186_SID_VI,
.regs = {
- .override = 0x390,
- .security = 0x394,
+ .sid = {
+ .override = 0x390,
+ .security = 0x394,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_NVDECSRD,
.name = "nvdecsrd",
.sid = TEGRA186_SID_NVDEC,
.regs = {
- .override = 0x3c0,
- .security = 0x3c4,
+ .sid = {
+ .override = 0x3c0,
+ .security = 0x3c4,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_NVDECSWR,
.name = "nvdecswr",
.sid = TEGRA186_SID_NVDEC,
.regs = {
- .override = 0x3c8,
- .security = 0x3cc,
+ .sid = {
+ .override = 0x3c8,
+ .security = 0x3cc,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_APER,
.name = "aper",
.sid = TEGRA186_SID_APE,
.regs = {
- .override = 0x3d0,
- .security = 0x3d4,
+ .sid = {
+ .override = 0x3d0,
+ .security = 0x3d4,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_APEW,
.name = "apew",
.sid = TEGRA186_SID_APE,
.regs = {
- .override = 0x3d8,
- .security = 0x3dc,
+ .sid = {
+ .override = 0x3d8,
+ .security = 0x3dc,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_NVJPGSRD,
.name = "nvjpgsrd",
.sid = TEGRA186_SID_NVJPG,
.regs = {
- .override = 0x3f0,
- .security = 0x3f4,
+ .sid = {
+ .override = 0x3f0,
+ .security = 0x3f4,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_NVJPGSWR,
.name = "nvjpgswr",
.sid = TEGRA186_SID_NVJPG,
.regs = {
- .override = 0x3f8,
- .security = 0x3fc,
+ .sid = {
+ .override = 0x3f8,
+ .security = 0x3fc,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SESRD,
.name = "sesrd",
.sid = TEGRA186_SID_SE,
.regs = {
- .override = 0x400,
- .security = 0x404,
+ .sid = {
+ .override = 0x400,
+ .security = 0x404,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SESWR,
.name = "seswr",
.sid = TEGRA186_SID_SE,
.regs = {
- .override = 0x408,
- .security = 0x40c,
+ .sid = {
+ .override = 0x408,
+ .security = 0x40c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_ETRR,
.name = "etrr",
.sid = TEGRA186_SID_ETR,
.regs = {
- .override = 0x420,
- .security = 0x424,
+ .sid = {
+ .override = 0x420,
+ .security = 0x424,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_ETRW,
.name = "etrw",
.sid = TEGRA186_SID_ETR,
.regs = {
- .override = 0x428,
- .security = 0x42c,
+ .sid = {
+ .override = 0x428,
+ .security = 0x42c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_TSECSRDB,
.name = "tsecsrdb",
.sid = TEGRA186_SID_TSECB,
.regs = {
- .override = 0x430,
- .security = 0x434,
+ .sid = {
+ .override = 0x430,
+ .security = 0x434,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_TSECSWRB,
.name = "tsecswrb",
.sid = TEGRA186_SID_TSECB,
.regs = {
- .override = 0x438,
- .security = 0x43c,
+ .sid = {
+ .override = 0x438,
+ .security = 0x43c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_GPUSRD2,
.name = "gpusrd2",
.sid = TEGRA186_SID_GPU,
.regs = {
- .override = 0x440,
- .security = 0x444,
+ .sid = {
+ .override = 0x440,
+ .security = 0x444,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_GPUSWR2,
.name = "gpuswr2",
.sid = TEGRA186_SID_GPU,
.regs = {
- .override = 0x448,
- .security = 0x44c,
+ .sid = {
+ .override = 0x448,
+ .security = 0x44c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_AXISR,
.name = "axisr",
.sid = TEGRA186_SID_GPCDMA_0,
.regs = {
- .override = 0x460,
- .security = 0x464,
+ .sid = {
+ .override = 0x460,
+ .security = 0x464,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_AXISW,
.name = "axisw",
.sid = TEGRA186_SID_GPCDMA_0,
.regs = {
- .override = 0x468,
- .security = 0x46c,
+ .sid = {
+ .override = 0x468,
+ .security = 0x46c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_EQOSR,
.name = "eqosr",
.sid = TEGRA186_SID_EQOS,
.regs = {
- .override = 0x470,
- .security = 0x474,
+ .sid = {
+ .override = 0x470,
+ .security = 0x474,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_EQOSW,
.name = "eqosw",
.sid = TEGRA186_SID_EQOS,
.regs = {
- .override = 0x478,
- .security = 0x47c,
+ .sid = {
+ .override = 0x478,
+ .security = 0x47c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_UFSHCR,
.name = "ufshcr",
.sid = TEGRA186_SID_UFSHC,
.regs = {
- .override = 0x480,
- .security = 0x484,
+ .sid = {
+ .override = 0x480,
+ .security = 0x484,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_UFSHCW,
.name = "ufshcw",
.sid = TEGRA186_SID_UFSHC,
.regs = {
- .override = 0x488,
- .security = 0x48c,
+ .sid = {
+ .override = 0x488,
+ .security = 0x48c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_NVDISPLAYR,
.name = "nvdisplayr",
.sid = TEGRA186_SID_NVDISPLAY,
.regs = {
- .override = 0x490,
- .security = 0x494,
+ .sid = {
+ .override = 0x490,
+ .security = 0x494,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_BPMPR,
.name = "bpmpr",
.sid = TEGRA186_SID_BPMP,
.regs = {
- .override = 0x498,
- .security = 0x49c,
+ .sid = {
+ .override = 0x498,
+ .security = 0x49c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_BPMPW,
.name = "bpmpw",
.sid = TEGRA186_SID_BPMP,
.regs = {
- .override = 0x4a0,
- .security = 0x4a4,
+ .sid = {
+ .override = 0x4a0,
+ .security = 0x4a4,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_BPMPDMAR,
.name = "bpmpdmar",
.sid = TEGRA186_SID_BPMP,
.regs = {
- .override = 0x4a8,
- .security = 0x4ac,
+ .sid = {
+ .override = 0x4a8,
+ .security = 0x4ac,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_BPMPDMAW,
.name = "bpmpdmaw",
.sid = TEGRA186_SID_BPMP,
.regs = {
- .override = 0x4b0,
- .security = 0x4b4,
+ .sid = {
+ .override = 0x4b0,
+ .security = 0x4b4,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_AONR,
.name = "aonr",
.sid = TEGRA186_SID_AON,
.regs = {
- .override = 0x4b8,
- .security = 0x4bc,
+ .sid = {
+ .override = 0x4b8,
+ .security = 0x4bc,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_AONW,
.name = "aonw",
.sid = TEGRA186_SID_AON,
.regs = {
- .override = 0x4c0,
- .security = 0x4c4,
+ .sid = {
+ .override = 0x4c0,
+ .security = 0x4c4,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_AONDMAR,
.name = "aondmar",
.sid = TEGRA186_SID_AON,
.regs = {
- .override = 0x4c8,
- .security = 0x4cc,
+ .sid = {
+ .override = 0x4c8,
+ .security = 0x4cc,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_AONDMAW,
.name = "aondmaw",
.sid = TEGRA186_SID_AON,
.regs = {
- .override = 0x4d0,
- .security = 0x4d4,
+ .sid = {
+ .override = 0x4d0,
+ .security = 0x4d4,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SCER,
.name = "scer",
.sid = TEGRA186_SID_SCE,
.regs = {
- .override = 0x4d8,
- .security = 0x4dc,
+ .sid = {
+ .override = 0x4d8,
+ .security = 0x4dc,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SCEW,
.name = "scew",
.sid = TEGRA186_SID_SCE,
.regs = {
- .override = 0x4e0,
- .security = 0x4e4,
+ .sid = {
+ .override = 0x4e0,
+ .security = 0x4e4,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SCEDMAR,
.name = "scedmar",
.sid = TEGRA186_SID_SCE,
.regs = {
- .override = 0x4e8,
- .security = 0x4ec,
+ .sid = {
+ .override = 0x4e8,
+ .security = 0x4ec,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_SCEDMAW,
.name = "scedmaw",
.sid = TEGRA186_SID_SCE,
.regs = {
- .override = 0x4f0,
- .security = 0x4f4,
+ .sid = {
+ .override = 0x4f0,
+ .security = 0x4f4,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_APEDMAR,
.name = "apedmar",
.sid = TEGRA186_SID_APE,
.regs = {
- .override = 0x4f8,
- .security = 0x4fc,
+ .sid = {
+ .override = 0x4f8,
+ .security = 0x4fc,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_APEDMAW,
.name = "apedmaw",
.sid = TEGRA186_SID_APE,
.regs = {
- .override = 0x500,
- .security = 0x504,
+ .sid = {
+ .override = 0x500,
+ .security = 0x504,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_NVDISPLAYR1,
.name = "nvdisplayr1",
.sid = TEGRA186_SID_NVDISPLAY,
.regs = {
- .override = 0x508,
- .security = 0x50c,
+ .sid = {
+ .override = 0x508,
+ .security = 0x50c,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_VICSRD1,
.name = "vicsrd1",
.sid = TEGRA186_SID_VIC,
.regs = {
- .override = 0x510,
- .security = 0x514,
+ .sid = {
+ .override = 0x510,
+ .security = 0x514,
+ },
},
}, {
+ .id = TEGRA186_MEMORY_CLIENT_NVDECSRD1,
.name = "nvdecsrd1",
.sid = TEGRA186_SID_NVDEC,
.regs = {
- .override = 0x518,
- .security = 0x51c,
+ .sid = {
+ .override = 0x518,
+ .security = 0x51c,
+ },
},
},
};
-static const struct tegra186_mc_soc tegra186_mc_soc = {
+const struct tegra_mc_soc tegra186_mc_soc = {
.num_clients = ARRAY_SIZE(tegra186_mc_clients),
.clients = tegra186_mc_clients,
+ .num_address_bits = 40,
+ .ops = &tegra186_mc_ops,
};
#endif
-
-#if defined(CONFIG_ARCH_TEGRA_194_SOC)
-static const struct tegra186_mc_client tegra194_mc_clients[] = {
- {
- .name = "ptcr",
- .sid = TEGRA194_SID_PASSTHROUGH,
- .regs = {
- .override = 0x000,
- .security = 0x004,
- },
- }, {
- .name = "miu7r",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x008,
- .security = 0x00c,
- },
- }, {
- .name = "miu7w",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x010,
- .security = 0x014,
- },
- }, {
- .name = "hdar",
- .sid = TEGRA194_SID_HDA,
- .regs = {
- .override = 0x0a8,
- .security = 0x0ac,
- },
- }, {
- .name = "host1xdmar",
- .sid = TEGRA194_SID_HOST1X,
- .regs = {
- .override = 0x0b0,
- .security = 0x0b4,
- },
- }, {
- .name = "nvencsrd",
- .sid = TEGRA194_SID_NVENC,
- .regs = {
- .override = 0x0e0,
- .security = 0x0e4,
- },
- }, {
- .name = "satar",
- .sid = TEGRA194_SID_SATA,
- .regs = {
- .override = 0x0f8,
- .security = 0x0fc,
- },
- }, {
- .name = "mpcorer",
- .sid = TEGRA194_SID_PASSTHROUGH,
- .regs = {
- .override = 0x138,
- .security = 0x13c,
- },
- }, {
- .name = "nvencswr",
- .sid = TEGRA194_SID_NVENC,
- .regs = {
- .override = 0x158,
- .security = 0x15c,
- },
- }, {
- .name = "hdaw",
- .sid = TEGRA194_SID_HDA,
- .regs = {
- .override = 0x1a8,
- .security = 0x1ac,
- },
- }, {
- .name = "mpcorew",
- .sid = TEGRA194_SID_PASSTHROUGH,
- .regs = {
- .override = 0x1c8,
- .security = 0x1cc,
- },
- }, {
- .name = "sataw",
- .sid = TEGRA194_SID_SATA,
- .regs = {
- .override = 0x1e8,
- .security = 0x1ec,
- },
- }, {
- .name = "ispra",
- .sid = TEGRA194_SID_ISP,
- .regs = {
- .override = 0x220,
- .security = 0x224,
- },
- }, {
- .name = "ispfalr",
- .sid = TEGRA194_SID_ISP_FALCON,
- .regs = {
- .override = 0x228,
- .security = 0x22c,
- },
- }, {
- .name = "ispwa",
- .sid = TEGRA194_SID_ISP,
- .regs = {
- .override = 0x230,
- .security = 0x234,
- },
- }, {
- .name = "ispwb",
- .sid = TEGRA194_SID_ISP,
- .regs = {
- .override = 0x238,
- .security = 0x23c,
- },
- }, {
- .name = "xusb_hostr",
- .sid = TEGRA194_SID_XUSB_HOST,
- .regs = {
- .override = 0x250,
- .security = 0x254,
- },
- }, {
- .name = "xusb_hostw",
- .sid = TEGRA194_SID_XUSB_HOST,
- .regs = {
- .override = 0x258,
- .security = 0x25c,
- },
- }, {
- .name = "xusb_devr",
- .sid = TEGRA194_SID_XUSB_DEV,
- .regs = {
- .override = 0x260,
- .security = 0x264,
- },
- }, {
- .name = "xusb_devw",
- .sid = TEGRA194_SID_XUSB_DEV,
- .regs = {
- .override = 0x268,
- .security = 0x26c,
- },
- }, {
- .name = "sdmmcra",
- .sid = TEGRA194_SID_SDMMC1,
- .regs = {
- .override = 0x300,
- .security = 0x304,
- },
- }, {
- .name = "sdmmcr",
- .sid = TEGRA194_SID_SDMMC3,
- .regs = {
- .override = 0x310,
- .security = 0x314,
- },
- }, {
- .name = "sdmmcrab",
- .sid = TEGRA194_SID_SDMMC4,
- .regs = {
- .override = 0x318,
- .security = 0x31c,
- },
- }, {
- .name = "sdmmcwa",
- .sid = TEGRA194_SID_SDMMC1,
- .regs = {
- .override = 0x320,
- .security = 0x324,
- },
- }, {
- .name = "sdmmcw",
- .sid = TEGRA194_SID_SDMMC3,
- .regs = {
- .override = 0x330,
- .security = 0x334,
- },
- }, {
- .name = "sdmmcwab",
- .sid = TEGRA194_SID_SDMMC4,
- .regs = {
- .override = 0x338,
- .security = 0x33c,
- },
- }, {
- .name = "vicsrd",
- .sid = TEGRA194_SID_VIC,
- .regs = {
- .override = 0x360,
- .security = 0x364,
- },
- }, {
- .name = "vicswr",
- .sid = TEGRA194_SID_VIC,
- .regs = {
- .override = 0x368,
- .security = 0x36c,
- },
- }, {
- .name = "viw",
- .sid = TEGRA194_SID_VI,
- .regs = {
- .override = 0x390,
- .security = 0x394,
- },
- }, {
- .name = "nvdecsrd",
- .sid = TEGRA194_SID_NVDEC,
- .regs = {
- .override = 0x3c0,
- .security = 0x3c4,
- },
- }, {
- .name = "nvdecswr",
- .sid = TEGRA194_SID_NVDEC,
- .regs = {
- .override = 0x3c8,
- .security = 0x3cc,
- },
- }, {
- .name = "aper",
- .sid = TEGRA194_SID_APE,
- .regs = {
- .override = 0x3c0,
- .security = 0x3c4,
- },
- }, {
- .name = "apew",
- .sid = TEGRA194_SID_APE,
- .regs = {
- .override = 0x3d0,
- .security = 0x3d4,
- },
- }, {
- .name = "nvjpgsrd",
- .sid = TEGRA194_SID_NVJPG,
- .regs = {
- .override = 0x3f0,
- .security = 0x3f4,
- },
- }, {
- .name = "nvjpgswr",
- .sid = TEGRA194_SID_NVJPG,
- .regs = {
- .override = 0x3f0,
- .security = 0x3f4,
- },
- }, {
- .name = "axiapr",
- .sid = TEGRA194_SID_PASSTHROUGH,
- .regs = {
- .override = 0x410,
- .security = 0x414,
- },
- }, {
- .name = "axiapw",
- .sid = TEGRA194_SID_PASSTHROUGH,
- .regs = {
- .override = 0x418,
- .security = 0x41c,
- },
- }, {
- .name = "etrr",
- .sid = TEGRA194_SID_ETR,
- .regs = {
- .override = 0x420,
- .security = 0x424,
- },
- }, {
- .name = "etrw",
- .sid = TEGRA194_SID_ETR,
- .regs = {
- .override = 0x428,
- .security = 0x42c,
- },
- }, {
- .name = "axisr",
- .sid = TEGRA194_SID_PASSTHROUGH,
- .regs = {
- .override = 0x460,
- .security = 0x464,
- },
- }, {
- .name = "axisw",
- .sid = TEGRA194_SID_PASSTHROUGH,
- .regs = {
- .override = 0x468,
- .security = 0x46c,
- },
- }, {
- .name = "eqosr",
- .sid = TEGRA194_SID_EQOS,
- .regs = {
- .override = 0x470,
- .security = 0x474,
- },
- }, {
- .name = "eqosw",
- .sid = TEGRA194_SID_EQOS,
- .regs = {
- .override = 0x478,
- .security = 0x47c,
- },
- }, {
- .name = "ufshcr",
- .sid = TEGRA194_SID_UFSHC,
- .regs = {
- .override = 0x480,
- .security = 0x484,
- },
- }, {
- .name = "ufshcw",
- .sid = TEGRA194_SID_UFSHC,
- .regs = {
- .override = 0x488,
- .security = 0x48c,
- },
- }, {
- .name = "nvdisplayr",
- .sid = TEGRA194_SID_NVDISPLAY,
- .regs = {
- .override = 0x490,
- .security = 0x494,
- },
- }, {
- .name = "bpmpr",
- .sid = TEGRA194_SID_BPMP,
- .regs = {
- .override = 0x498,
- .security = 0x49c,
- },
- }, {
- .name = "bpmpw",
- .sid = TEGRA194_SID_BPMP,
- .regs = {
- .override = 0x4a0,
- .security = 0x4a4,
- },
- }, {
- .name = "bpmpdmar",
- .sid = TEGRA194_SID_BPMP,
- .regs = {
- .override = 0x4a8,
- .security = 0x4ac,
- },
- }, {
- .name = "bpmpdmaw",
- .sid = TEGRA194_SID_BPMP,
- .regs = {
- .override = 0x4b0,
- .security = 0x4b4,
- },
- }, {
- .name = "aonr",
- .sid = TEGRA194_SID_AON,
- .regs = {
- .override = 0x4b8,
- .security = 0x4bc,
- },
- }, {
- .name = "aonw",
- .sid = TEGRA194_SID_AON,
- .regs = {
- .override = 0x4c0,
- .security = 0x4c4,
- },
- }, {
- .name = "aondmar",
- .sid = TEGRA194_SID_AON,
- .regs = {
- .override = 0x4c8,
- .security = 0x4cc,
- },
- }, {
- .name = "aondmaw",
- .sid = TEGRA194_SID_AON,
- .regs = {
- .override = 0x4d0,
- .security = 0x4d4,
- },
- }, {
- .name = "scer",
- .sid = TEGRA194_SID_SCE,
- .regs = {
- .override = 0x4d8,
- .security = 0x4dc,
- },
- }, {
- .name = "scew",
- .sid = TEGRA194_SID_SCE,
- .regs = {
- .override = 0x4e0,
- .security = 0x4e4,
- },
- }, {
- .name = "scedmar",
- .sid = TEGRA194_SID_SCE,
- .regs = {
- .override = 0x4e8,
- .security = 0x4ec,
- },
- }, {
- .name = "scedmaw",
- .sid = TEGRA194_SID_SCE,
- .regs = {
- .override = 0x4f0,
- .security = 0x4f4,
- },
- }, {
- .name = "apedmar",
- .sid = TEGRA194_SID_APE,
- .regs = {
- .override = 0x4f8,
- .security = 0x4fc,
- },
- }, {
- .name = "apedmaw",
- .sid = TEGRA194_SID_APE,
- .regs = {
- .override = 0x500,
- .security = 0x504,
- },
- }, {
- .name = "nvdisplayr1",
- .sid = TEGRA194_SID_NVDISPLAY,
- .regs = {
- .override = 0x508,
- .security = 0x50c,
- },
- }, {
- .name = "vicsrd1",
- .sid = TEGRA194_SID_VIC,
- .regs = {
- .override = 0x510,
- .security = 0x514,
- },
- }, {
- .name = "nvdecsrd1",
- .sid = TEGRA194_SID_NVDEC,
- .regs = {
- .override = 0x518,
- .security = 0x51c,
- },
- }, {
- .name = "miu0r",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x530,
- .security = 0x534,
- },
- }, {
- .name = "miu0w",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x538,
- .security = 0x53c,
- },
- }, {
- .name = "miu1r",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x540,
- .security = 0x544,
- },
- }, {
- .name = "miu1w",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x548,
- .security = 0x54c,
- },
- }, {
- .name = "miu2r",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x570,
- .security = 0x574,
- },
- }, {
- .name = "miu2w",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x578,
- .security = 0x57c,
- },
- }, {
- .name = "miu3r",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x580,
- .security = 0x584,
- },
- }, {
- .name = "miu3w",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x588,
- .security = 0x58c,
- },
- }, {
- .name = "miu4r",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x590,
- .security = 0x594,
- },
- }, {
- .name = "miu4w",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x598,
- .security = 0x59c,
- },
- }, {
- .name = "dpmur",
- .sid = TEGRA194_SID_PASSTHROUGH,
- .regs = {
- .override = 0x598,
- .security = 0x59c,
- },
- }, {
- .name = "vifalr",
- .sid = TEGRA194_SID_VI_FALCON,
- .regs = {
- .override = 0x5e0,
- .security = 0x5e4,
- },
- }, {
- .name = "vifalw",
- .sid = TEGRA194_SID_VI_FALCON,
- .regs = {
- .override = 0x5e8,
- .security = 0x5ec,
- },
- }, {
- .name = "dla0rda",
- .sid = TEGRA194_SID_NVDLA0,
- .regs = {
- .override = 0x5f0,
- .security = 0x5f4,
- },
- }, {
- .name = "dla0falrdb",
- .sid = TEGRA194_SID_NVDLA0,
- .regs = {
- .override = 0x5f8,
- .security = 0x5fc,
- },
- }, {
- .name = "dla0wra",
- .sid = TEGRA194_SID_NVDLA0,
- .regs = {
- .override = 0x600,
- .security = 0x604,
- },
- }, {
- .name = "dla0falwrb",
- .sid = TEGRA194_SID_NVDLA0,
- .regs = {
- .override = 0x608,
- .security = 0x60c,
- },
- }, {
- .name = "dla1rda",
- .sid = TEGRA194_SID_NVDLA1,
- .regs = {
- .override = 0x610,
- .security = 0x614,
- },
- }, {
- .name = "dla1falrdb",
- .sid = TEGRA194_SID_NVDLA1,
- .regs = {
- .override = 0x618,
- .security = 0x61c,
- },
- }, {
- .name = "dla1wra",
- .sid = TEGRA194_SID_NVDLA1,
- .regs = {
- .override = 0x620,
- .security = 0x624,
- },
- }, {
- .name = "dla1falwrb",
- .sid = TEGRA194_SID_NVDLA1,
- .regs = {
- .override = 0x628,
- .security = 0x62c,
- },
- }, {
- .name = "pva0rda",
- .sid = TEGRA194_SID_PVA0,
- .regs = {
- .override = 0x630,
- .security = 0x634,
- },
- }, {
- .name = "pva0rdb",
- .sid = TEGRA194_SID_PVA0,
- .regs = {
- .override = 0x638,
- .security = 0x63c,
- },
- }, {
- .name = "pva0rdc",
- .sid = TEGRA194_SID_PVA0,
- .regs = {
- .override = 0x640,
- .security = 0x644,
- },
- }, {
- .name = "pva0wra",
- .sid = TEGRA194_SID_PVA0,
- .regs = {
- .override = 0x648,
- .security = 0x64c,
- },
- }, {
- .name = "pva0wrb",
- .sid = TEGRA194_SID_PVA0,
- .regs = {
- .override = 0x650,
- .security = 0x654,
- },
- }, {
- .name = "pva0wrc",
- .sid = TEGRA194_SID_PVA0,
- .regs = {
- .override = 0x658,
- .security = 0x65c,
- },
- }, {
- .name = "pva1rda",
- .sid = TEGRA194_SID_PVA1,
- .regs = {
- .override = 0x660,
- .security = 0x664,
- },
- }, {
- .name = "pva1rdb",
- .sid = TEGRA194_SID_PVA1,
- .regs = {
- .override = 0x668,
- .security = 0x66c,
- },
- }, {
- .name = "pva1rdc",
- .sid = TEGRA194_SID_PVA1,
- .regs = {
- .override = 0x670,
- .security = 0x674,
- },
- }, {
- .name = "pva1wra",
- .sid = TEGRA194_SID_PVA1,
- .regs = {
- .override = 0x678,
- .security = 0x67c,
- },
- }, {
- .name = "pva1wrb",
- .sid = TEGRA194_SID_PVA1,
- .regs = {
- .override = 0x680,
- .security = 0x684,
- },
- }, {
- .name = "pva1wrc",
- .sid = TEGRA194_SID_PVA1,
- .regs = {
- .override = 0x688,
- .security = 0x68c,
- },
- }, {
- .name = "rcer",
- .sid = TEGRA194_SID_RCE,
- .regs = {
- .override = 0x690,
- .security = 0x694,
- },
- }, {
- .name = "rcew",
- .sid = TEGRA194_SID_RCE,
- .regs = {
- .override = 0x698,
- .security = 0x69c,
- },
- }, {
- .name = "rcedmar",
- .sid = TEGRA194_SID_RCE,
- .regs = {
- .override = 0x6a0,
- .security = 0x6a4,
- },
- }, {
- .name = "rcedmaw",
- .sid = TEGRA194_SID_RCE,
- .regs = {
- .override = 0x6a8,
- .security = 0x6ac,
- },
- }, {
- .name = "nvenc1srd",
- .sid = TEGRA194_SID_NVENC1,
- .regs = {
- .override = 0x6b0,
- .security = 0x6b4,
- },
- }, {
- .name = "nvenc1swr",
- .sid = TEGRA194_SID_NVENC1,
- .regs = {
- .override = 0x6b8,
- .security = 0x6bc,
- },
- }, {
- .name = "pcie0r",
- .sid = TEGRA194_SID_PCIE0,
- .regs = {
- .override = 0x6c0,
- .security = 0x6c4,
- },
- }, {
- .name = "pcie0w",
- .sid = TEGRA194_SID_PCIE0,
- .regs = {
- .override = 0x6c8,
- .security = 0x6cc,
- },
- }, {
- .name = "pcie1r",
- .sid = TEGRA194_SID_PCIE1,
- .regs = {
- .override = 0x6d0,
- .security = 0x6d4,
- },
- }, {
- .name = "pcie1w",
- .sid = TEGRA194_SID_PCIE1,
- .regs = {
- .override = 0x6d8,
- .security = 0x6dc,
- },
- }, {
- .name = "pcie2ar",
- .sid = TEGRA194_SID_PCIE2,
- .regs = {
- .override = 0x6e0,
- .security = 0x6e4,
- },
- }, {
- .name = "pcie2aw",
- .sid = TEGRA194_SID_PCIE2,
- .regs = {
- .override = 0x6e8,
- .security = 0x6ec,
- },
- }, {
- .name = "pcie3r",
- .sid = TEGRA194_SID_PCIE3,
- .regs = {
- .override = 0x6f0,
- .security = 0x6f4,
- },
- }, {
- .name = "pcie3w",
- .sid = TEGRA194_SID_PCIE3,
- .regs = {
- .override = 0x6f8,
- .security = 0x6fc,
- },
- }, {
- .name = "pcie4r",
- .sid = TEGRA194_SID_PCIE4,
- .regs = {
- .override = 0x700,
- .security = 0x704,
- },
- }, {
- .name = "pcie4w",
- .sid = TEGRA194_SID_PCIE4,
- .regs = {
- .override = 0x708,
- .security = 0x70c,
- },
- }, {
- .name = "pcie5r",
- .sid = TEGRA194_SID_PCIE5,
- .regs = {
- .override = 0x710,
- .security = 0x714,
- },
- }, {
- .name = "pcie5w",
- .sid = TEGRA194_SID_PCIE5,
- .regs = {
- .override = 0x718,
- .security = 0x71c,
- },
- }, {
- .name = "ispfalw",
- .sid = TEGRA194_SID_ISP_FALCON,
- .regs = {
- .override = 0x720,
- .security = 0x724,
- },
- }, {
- .name = "dla0rda1",
- .sid = TEGRA194_SID_NVDLA0,
- .regs = {
- .override = 0x748,
- .security = 0x74c,
- },
- }, {
- .name = "dla1rda1",
- .sid = TEGRA194_SID_NVDLA1,
- .regs = {
- .override = 0x750,
- .security = 0x754,
- },
- }, {
- .name = "pva0rda1",
- .sid = TEGRA194_SID_PVA0,
- .regs = {
- .override = 0x758,
- .security = 0x75c,
- },
- }, {
- .name = "pva0rdb1",
- .sid = TEGRA194_SID_PVA0,
- .regs = {
- .override = 0x760,
- .security = 0x764,
- },
- }, {
- .name = "pva1rda1",
- .sid = TEGRA194_SID_PVA1,
- .regs = {
- .override = 0x768,
- .security = 0x76c,
- },
- }, {
- .name = "pva1rdb1",
- .sid = TEGRA194_SID_PVA1,
- .regs = {
- .override = 0x770,
- .security = 0x774,
- },
- }, {
- .name = "pcie5r1",
- .sid = TEGRA194_SID_PCIE5,
- .regs = {
- .override = 0x778,
- .security = 0x77c,
- },
- }, {
- .name = "nvencsrd1",
- .sid = TEGRA194_SID_NVENC,
- .regs = {
- .override = 0x780,
- .security = 0x784,
- },
- }, {
- .name = "nvenc1srd1",
- .sid = TEGRA194_SID_NVENC1,
- .regs = {
- .override = 0x788,
- .security = 0x78c,
- },
- }, {
- .name = "ispra1",
- .sid = TEGRA194_SID_ISP,
- .regs = {
- .override = 0x790,
- .security = 0x794,
- },
- }, {
- .name = "pcie0r1",
- .sid = TEGRA194_SID_PCIE0,
- .regs = {
- .override = 0x798,
- .security = 0x79c,
- },
- }, {
- .name = "nvdec1srd",
- .sid = TEGRA194_SID_NVDEC1,
- .regs = {
- .override = 0x7c8,
- .security = 0x7cc,
- },
- }, {
- .name = "nvdec1srd1",
- .sid = TEGRA194_SID_NVDEC1,
- .regs = {
- .override = 0x7d0,
- .security = 0x7d4,
- },
- }, {
- .name = "nvdec1swr",
- .sid = TEGRA194_SID_NVDEC1,
- .regs = {
- .override = 0x7d8,
- .security = 0x7dc,
- },
- }, {
- .name = "miu5r",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x7e0,
- .security = 0x7e4,
- },
- }, {
- .name = "miu5w",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x7e8,
- .security = 0x7ec,
- },
- }, {
- .name = "miu6r",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x7f0,
- .security = 0x7f4,
- },
- }, {
- .name = "miu6w",
- .sid = TEGRA194_SID_MIU,
- .regs = {
- .override = 0x7f8,
- .security = 0x7fc,
- },
- },
-};
-
-static const struct tegra186_mc_soc tegra194_mc_soc = {
- .num_clients = ARRAY_SIZE(tegra194_mc_clients),
- .clients = tegra194_mc_clients,
-};
-#endif
-
-static int tegra186_mc_probe(struct platform_device *pdev)
-{
- struct tegra186_mc *mc;
- struct resource *res;
- int err;
-
- mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
- if (!mc)
- return -ENOMEM;
-
- mc->soc = of_device_get_match_data(&pdev->dev);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mc->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(mc->regs))
- return PTR_ERR(mc->regs);
-
- mc->dev = &pdev->dev;
-
- err = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
- if (err < 0)
- return err;
-
- platform_set_drvdata(pdev, mc);
- tegra186_mc_program_sid(mc);
-
- return 0;
-}
-
-static int tegra186_mc_remove(struct platform_device *pdev)
-{
- struct tegra186_mc *mc = platform_get_drvdata(pdev);
-
- of_platform_depopulate(mc->dev);
-
- return 0;
-}
-
-static const struct of_device_id tegra186_mc_of_match[] = {
-#if defined(CONFIG_ARCH_TEGRA_186_SOC)
- { .compatible = "nvidia,tegra186-mc", .data = &tegra186_mc_soc },
-#endif
-#if defined(CONFIG_ARCH_TEGRA_194_SOC)
- { .compatible = "nvidia,tegra194-mc", .data = &tegra194_mc_soc },
-#endif
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, tegra186_mc_of_match);
-
-static int __maybe_unused tegra186_mc_suspend(struct device *dev)
-{
- return 0;
-}
-
-static int __maybe_unused tegra186_mc_resume(struct device *dev)
-{
- struct tegra186_mc *mc = dev_get_drvdata(dev);
-
- tegra186_mc_program_sid(mc);
-
- return 0;
-}
-
-static const struct dev_pm_ops tegra186_mc_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(tegra186_mc_suspend, tegra186_mc_resume)
-};
-
-static struct platform_driver tegra186_mc_driver = {
- .driver = {
- .name = "tegra186-mc",
- .of_match_table = tegra186_mc_of_match,
- .pm = &tegra186_mc_pm_ops,
- .suppress_bind_attrs = true,
- },
- .probe = tegra186_mc_probe,
- .remove = tegra186_mc_remove,
-};
-module_platform_driver(tegra186_mc_driver);
-
-MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
-MODULE_DESCRIPTION("NVIDIA Tegra186 Memory Controller driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/memory/tegra/tegra194.c b/drivers/memory/tegra/tegra194.c
new file mode 100644
index 000000000000..cab998b8bd5c
--- /dev/null
+++ b/drivers/memory/tegra/tegra194.c
@@ -0,0 +1,1351 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2021 NVIDIA CORPORATION. All rights reserved.
+ */
+
+#include <soc/tegra/mc.h>
+
+#include <dt-bindings/memory/tegra194-mc.h>
+
+#include "mc.h"
+
+static const struct tegra_mc_client tegra194_mc_clients[] = {
+ {
+ .id = TEGRA194_MEMORY_CLIENT_PTCR,
+ .name = "ptcr",
+ .sid = TEGRA194_SID_PASSTHROUGH,
+ .regs = {
+ .sid = {
+ .override = 0x000,
+ .security = 0x004,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU7R,
+ .name = "miu7r",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x008,
+ .security = 0x00c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU7W,
+ .name = "miu7w",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x010,
+ .security = 0x014,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_HDAR,
+ .name = "hdar",
+ .sid = TEGRA194_SID_HDA,
+ .regs = {
+ .sid = {
+ .override = 0x0a8,
+ .security = 0x0ac,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_HOST1XDMAR,
+ .name = "host1xdmar",
+ .sid = TEGRA194_SID_HOST1X,
+ .regs = {
+ .sid = {
+ .override = 0x0b0,
+ .security = 0x0b4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVENCSRD,
+ .name = "nvencsrd",
+ .sid = TEGRA194_SID_NVENC,
+ .regs = {
+ .sid = {
+ .override = 0x0e0,
+ .security = 0x0e4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_SATAR,
+ .name = "satar",
+ .sid = TEGRA194_SID_SATA,
+ .regs = {
+ .sid = {
+ .override = 0x0f8,
+ .security = 0x0fc,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MPCORER,
+ .name = "mpcorer",
+ .sid = TEGRA194_SID_PASSTHROUGH,
+ .regs = {
+ .sid = {
+ .override = 0x138,
+ .security = 0x13c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVENCSWR,
+ .name = "nvencswr",
+ .sid = TEGRA194_SID_NVENC,
+ .regs = {
+ .sid = {
+ .override = 0x158,
+ .security = 0x15c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_HDAW,
+ .name = "hdaw",
+ .sid = TEGRA194_SID_HDA,
+ .regs = {
+ .sid = {
+ .override = 0x1a8,
+ .security = 0x1ac,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MPCOREW,
+ .name = "mpcorew",
+ .sid = TEGRA194_SID_PASSTHROUGH,
+ .regs = {
+ .sid = {
+ .override = 0x1c8,
+ .security = 0x1cc,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_SATAW,
+ .name = "sataw",
+ .sid = TEGRA194_SID_SATA,
+ .regs = {
+ .sid = {
+ .override = 0x1e8,
+ .security = 0x1ec,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_ISPRA,
+ .name = "ispra",
+ .sid = TEGRA194_SID_ISP,
+ .regs = {
+ .sid = {
+ .override = 0x220,
+ .security = 0x224,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_ISPFALR,
+ .name = "ispfalr",
+ .sid = TEGRA194_SID_ISP_FALCON,
+ .regs = {
+ .sid = {
+ .override = 0x228,
+ .security = 0x22c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_ISPWA,
+ .name = "ispwa",
+ .sid = TEGRA194_SID_ISP,
+ .regs = {
+ .sid = {
+ .override = 0x230,
+ .security = 0x234,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_ISPWB,
+ .name = "ispwb",
+ .sid = TEGRA194_SID_ISP,
+ .regs = {
+ .sid = {
+ .override = 0x238,
+ .security = 0x23c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_XUSB_HOSTR,
+ .name = "xusb_hostr",
+ .sid = TEGRA194_SID_XUSB_HOST,
+ .regs = {
+ .sid = {
+ .override = 0x250,
+ .security = 0x254,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_XUSB_HOSTW,
+ .name = "xusb_hostw",
+ .sid = TEGRA194_SID_XUSB_HOST,
+ .regs = {
+ .sid = {
+ .override = 0x258,
+ .security = 0x25c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_XUSB_DEVR,
+ .name = "xusb_devr",
+ .sid = TEGRA194_SID_XUSB_DEV,
+ .regs = {
+ .sid = {
+ .override = 0x260,
+ .security = 0x264,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_XUSB_DEVW,
+ .name = "xusb_devw",
+ .sid = TEGRA194_SID_XUSB_DEV,
+ .regs = {
+ .sid = {
+ .override = 0x268,
+ .security = 0x26c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_SDMMCRA,
+ .name = "sdmmcra",
+ .sid = TEGRA194_SID_SDMMC1,
+ .regs = {
+ .sid = {
+ .override = 0x300,
+ .security = 0x304,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_SDMMCR,
+ .name = "sdmmcr",
+ .sid = TEGRA194_SID_SDMMC3,
+ .regs = {
+ .sid = {
+ .override = 0x310,
+ .security = 0x314,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_SDMMCRAB,
+ .name = "sdmmcrab",
+ .sid = TEGRA194_SID_SDMMC4,
+ .regs = {
+ .sid = {
+ .override = 0x318,
+ .security = 0x31c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_SDMMCWA,
+ .name = "sdmmcwa",
+ .sid = TEGRA194_SID_SDMMC1,
+ .regs = {
+ .sid = {
+ .override = 0x320,
+ .security = 0x324,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_SDMMCW,
+ .name = "sdmmcw",
+ .sid = TEGRA194_SID_SDMMC3,
+ .regs = {
+ .sid = {
+ .override = 0x330,
+ .security = 0x334,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_SDMMCWAB,
+ .name = "sdmmcwab",
+ .sid = TEGRA194_SID_SDMMC4,
+ .regs = {
+ .sid = {
+ .override = 0x338,
+ .security = 0x33c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_VICSRD,
+ .name = "vicsrd",
+ .sid = TEGRA194_SID_VIC,
+ .regs = {
+ .sid = {
+ .override = 0x360,
+ .security = 0x364,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_VICSWR,
+ .name = "vicswr",
+ .sid = TEGRA194_SID_VIC,
+ .regs = {
+ .sid = {
+ .override = 0x368,
+ .security = 0x36c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_VIW,
+ .name = "viw",
+ .sid = TEGRA194_SID_VI,
+ .regs = {
+ .sid = {
+ .override = 0x390,
+ .security = 0x394,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVDECSRD,
+ .name = "nvdecsrd",
+ .sid = TEGRA194_SID_NVDEC,
+ .regs = {
+ .sid = {
+ .override = 0x3c0,
+ .security = 0x3c4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVDECSWR,
+ .name = "nvdecswr",
+ .sid = TEGRA194_SID_NVDEC,
+ .regs = {
+ .sid = {
+ .override = 0x3c8,
+ .security = 0x3cc,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_APER,
+ .name = "aper",
+ .sid = TEGRA194_SID_APE,
+ .regs = {
+ .sid = {
+ .override = 0x3c0,
+ .security = 0x3c4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_APEW,
+ .name = "apew",
+ .sid = TEGRA194_SID_APE,
+ .regs = {
+ .sid = {
+ .override = 0x3d0,
+ .security = 0x3d4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVJPGSRD,
+ .name = "nvjpgsrd",
+ .sid = TEGRA194_SID_NVJPG,
+ .regs = {
+ .sid = {
+ .override = 0x3f0,
+ .security = 0x3f4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVJPGSWR,
+ .name = "nvjpgswr",
+ .sid = TEGRA194_SID_NVJPG,
+ .regs = {
+ .sid = {
+ .override = 0x3f0,
+ .security = 0x3f4,
+ },
+ },
+ }, {
+ .name = "axiapr",
+ .id = TEGRA194_MEMORY_CLIENT_AXIAPR,
+ .sid = TEGRA194_SID_PASSTHROUGH,
+ .regs = {
+ .sid = {
+ .override = 0x410,
+ .security = 0x414,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_AXIAPW,
+ .name = "axiapw",
+ .sid = TEGRA194_SID_PASSTHROUGH,
+ .regs = {
+ .sid = {
+ .override = 0x418,
+ .security = 0x41c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_ETRR,
+ .name = "etrr",
+ .sid = TEGRA194_SID_ETR,
+ .regs = {
+ .sid = {
+ .override = 0x420,
+ .security = 0x424,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_ETRW,
+ .name = "etrw",
+ .sid = TEGRA194_SID_ETR,
+ .regs = {
+ .sid = {
+ .override = 0x428,
+ .security = 0x42c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_AXISR,
+ .name = "axisr",
+ .sid = TEGRA194_SID_PASSTHROUGH,
+ .regs = {
+ .sid = {
+ .override = 0x460,
+ .security = 0x464,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_AXISW,
+ .name = "axisw",
+ .sid = TEGRA194_SID_PASSTHROUGH,
+ .regs = {
+ .sid = {
+ .override = 0x468,
+ .security = 0x46c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_EQOSR,
+ .name = "eqosr",
+ .sid = TEGRA194_SID_EQOS,
+ .regs = {
+ .sid = {
+ .override = 0x470,
+ .security = 0x474,
+ },
+ },
+ }, {
+ .name = "eqosw",
+ .id = TEGRA194_MEMORY_CLIENT_EQOSW,
+ .sid = TEGRA194_SID_EQOS,
+ .regs = {
+ .sid = {
+ .override = 0x478,
+ .security = 0x47c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_UFSHCR,
+ .name = "ufshcr",
+ .sid = TEGRA194_SID_UFSHC,
+ .regs = {
+ .sid = {
+ .override = 0x480,
+ .security = 0x484,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_UFSHCW,
+ .name = "ufshcw",
+ .sid = TEGRA194_SID_UFSHC,
+ .regs = {
+ .sid = {
+ .override = 0x488,
+ .security = 0x48c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVDISPLAYR,
+ .name = "nvdisplayr",
+ .sid = TEGRA194_SID_NVDISPLAY,
+ .regs = {
+ .sid = {
+ .override = 0x490,
+ .security = 0x494,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_BPMPR,
+ .name = "bpmpr",
+ .sid = TEGRA194_SID_BPMP,
+ .regs = {
+ .sid = {
+ .override = 0x498,
+ .security = 0x49c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_BPMPW,
+ .name = "bpmpw",
+ .sid = TEGRA194_SID_BPMP,
+ .regs = {
+ .sid = {
+ .override = 0x4a0,
+ .security = 0x4a4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_BPMPDMAR,
+ .name = "bpmpdmar",
+ .sid = TEGRA194_SID_BPMP,
+ .regs = {
+ .sid = {
+ .override = 0x4a8,
+ .security = 0x4ac,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_BPMPDMAW,
+ .name = "bpmpdmaw",
+ .sid = TEGRA194_SID_BPMP,
+ .regs = {
+ .sid = {
+ .override = 0x4b0,
+ .security = 0x4b4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_AONR,
+ .name = "aonr",
+ .sid = TEGRA194_SID_AON,
+ .regs = {
+ .sid = {
+ .override = 0x4b8,
+ .security = 0x4bc,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_AONW,
+ .name = "aonw",
+ .sid = TEGRA194_SID_AON,
+ .regs = {
+ .sid = {
+ .override = 0x4c0,
+ .security = 0x4c4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_AONDMAR,
+ .name = "aondmar",
+ .sid = TEGRA194_SID_AON,
+ .regs = {
+ .sid = {
+ .override = 0x4c8,
+ .security = 0x4cc,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_AONDMAW,
+ .name = "aondmaw",
+ .sid = TEGRA194_SID_AON,
+ .regs = {
+ .sid = {
+ .override = 0x4d0,
+ .security = 0x4d4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_SCER,
+ .name = "scer",
+ .sid = TEGRA194_SID_SCE,
+ .regs = {
+ .sid = {
+ .override = 0x4d8,
+ .security = 0x4dc,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_SCEW,
+ .name = "scew",
+ .sid = TEGRA194_SID_SCE,
+ .regs = {
+ .sid = {
+ .override = 0x4e0,
+ .security = 0x4e4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_SCEDMAR,
+ .name = "scedmar",
+ .sid = TEGRA194_SID_SCE,
+ .regs = {
+ .sid = {
+ .override = 0x4e8,
+ .security = 0x4ec,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_SCEDMAW,
+ .name = "scedmaw",
+ .sid = TEGRA194_SID_SCE,
+ .regs = {
+ .sid = {
+ .override = 0x4f0,
+ .security = 0x4f4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_APEDMAR,
+ .name = "apedmar",
+ .sid = TEGRA194_SID_APE,
+ .regs = {
+ .sid = {
+ .override = 0x4f8,
+ .security = 0x4fc,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_APEDMAW,
+ .name = "apedmaw",
+ .sid = TEGRA194_SID_APE,
+ .regs = {
+ .sid = {
+ .override = 0x500,
+ .security = 0x504,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVDISPLAYR1,
+ .name = "nvdisplayr1",
+ .sid = TEGRA194_SID_NVDISPLAY,
+ .regs = {
+ .sid = {
+ .override = 0x508,
+ .security = 0x50c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_VICSRD1,
+ .name = "vicsrd1",
+ .sid = TEGRA194_SID_VIC,
+ .regs = {
+ .sid = {
+ .override = 0x510,
+ .security = 0x514,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVDECSRD1,
+ .name = "nvdecsrd1",
+ .sid = TEGRA194_SID_NVDEC,
+ .regs = {
+ .sid = {
+ .override = 0x518,
+ .security = 0x51c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU0R,
+ .name = "miu0r",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x530,
+ .security = 0x534,
+ },
+ },
+ }, {
+ .name = "miu0w",
+ .id = TEGRA194_MEMORY_CLIENT_MIU0W,
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x538,
+ .security = 0x53c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU1R,
+ .name = "miu1r",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x540,
+ .security = 0x544,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU1W,
+ .name = "miu1w",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x548,
+ .security = 0x54c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU2R,
+ .name = "miu2r",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x570,
+ .security = 0x574,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU2W,
+ .name = "miu2w",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x578,
+ .security = 0x57c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU3R,
+ .name = "miu3r",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x580,
+ .security = 0x584,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU3W,
+ .name = "miu3w",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x588,
+ .security = 0x58c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU4R,
+ .name = "miu4r",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x590,
+ .security = 0x594,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU4W,
+ .name = "miu4w",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x598,
+ .security = 0x59c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_DPMUR,
+ .name = "dpmur",
+ .sid = TEGRA194_SID_PASSTHROUGH,
+ .regs = {
+ .sid = {
+ .override = 0x598,
+ .security = 0x59c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_VIFALR,
+ .name = "vifalr",
+ .sid = TEGRA194_SID_VI_FALCON,
+ .regs = {
+ .sid = {
+ .override = 0x5e0,
+ .security = 0x5e4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_VIFALW,
+ .name = "vifalw",
+ .sid = TEGRA194_SID_VI_FALCON,
+ .regs = {
+ .sid = {
+ .override = 0x5e8,
+ .security = 0x5ec,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_DLA0RDA,
+ .name = "dla0rda",
+ .sid = TEGRA194_SID_NVDLA0,
+ .regs = {
+ .sid = {
+ .override = 0x5f0,
+ .security = 0x5f4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_DLA0FALRDB,
+ .name = "dla0falrdb",
+ .sid = TEGRA194_SID_NVDLA0,
+ .regs = {
+ .sid = {
+ .override = 0x5f8,
+ .security = 0x5fc,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_DLA0WRA,
+ .name = "dla0wra",
+ .sid = TEGRA194_SID_NVDLA0,
+ .regs = {
+ .sid = {
+ .override = 0x600,
+ .security = 0x604,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_DLA0FALWRB,
+ .name = "dla0falwrb",
+ .sid = TEGRA194_SID_NVDLA0,
+ .regs = {
+ .sid = {
+ .override = 0x608,
+ .security = 0x60c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_DLA1RDA,
+ .name = "dla1rda",
+ .sid = TEGRA194_SID_NVDLA1,
+ .regs = {
+ .sid = {
+ .override = 0x610,
+ .security = 0x614,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_DLA1FALRDB,
+ .name = "dla1falrdb",
+ .sid = TEGRA194_SID_NVDLA1,
+ .regs = {
+ .sid = {
+ .override = 0x618,
+ .security = 0x61c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_DLA1WRA,
+ .name = "dla1wra",
+ .sid = TEGRA194_SID_NVDLA1,
+ .regs = {
+ .sid = {
+ .override = 0x620,
+ .security = 0x624,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_DLA1FALWRB,
+ .name = "dla1falwrb",
+ .sid = TEGRA194_SID_NVDLA1,
+ .regs = {
+ .sid = {
+ .override = 0x628,
+ .security = 0x62c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA0RDA,
+ .name = "pva0rda",
+ .sid = TEGRA194_SID_PVA0,
+ .regs = {
+ .sid = {
+ .override = 0x630,
+ .security = 0x634,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA0RDB,
+ .name = "pva0rdb",
+ .sid = TEGRA194_SID_PVA0,
+ .regs = {
+ .sid = {
+ .override = 0x638,
+ .security = 0x63c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA0RDC,
+ .name = "pva0rdc",
+ .sid = TEGRA194_SID_PVA0,
+ .regs = {
+ .sid = {
+ .override = 0x640,
+ .security = 0x644,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA0WRA,
+ .name = "pva0wra",
+ .sid = TEGRA194_SID_PVA0,
+ .regs = {
+ .sid = {
+ .override = 0x648,
+ .security = 0x64c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA0WRB,
+ .name = "pva0wrb",
+ .sid = TEGRA194_SID_PVA0,
+ .regs = {
+ .sid = {
+ .override = 0x650,
+ .security = 0x654,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA0WRC,
+ .name = "pva0wrc",
+ .sid = TEGRA194_SID_PVA0,
+ .regs = {
+ .sid = {
+ .override = 0x658,
+ .security = 0x65c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA1RDA,
+ .name = "pva1rda",
+ .sid = TEGRA194_SID_PVA1,
+ .regs = {
+ .sid = {
+ .override = 0x660,
+ .security = 0x664,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA1RDB,
+ .name = "pva1rdb",
+ .sid = TEGRA194_SID_PVA1,
+ .regs = {
+ .sid = {
+ .override = 0x668,
+ .security = 0x66c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA1RDC,
+ .name = "pva1rdc",
+ .sid = TEGRA194_SID_PVA1,
+ .regs = {
+ .sid = {
+ .override = 0x670,
+ .security = 0x674,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA1WRA,
+ .name = "pva1wra",
+ .sid = TEGRA194_SID_PVA1,
+ .regs = {
+ .sid = {
+ .override = 0x678,
+ .security = 0x67c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA1WRB,
+ .name = "pva1wrb",
+ .sid = TEGRA194_SID_PVA1,
+ .regs = {
+ .sid = {
+ .override = 0x680,
+ .security = 0x684,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA1WRC,
+ .name = "pva1wrc",
+ .sid = TEGRA194_SID_PVA1,
+ .regs = {
+ .sid = {
+ .override = 0x688,
+ .security = 0x68c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_RCER,
+ .name = "rcer",
+ .sid = TEGRA194_SID_RCE,
+ .regs = {
+ .sid = {
+ .override = 0x690,
+ .security = 0x694,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_RCEW,
+ .name = "rcew",
+ .sid = TEGRA194_SID_RCE,
+ .regs = {
+ .sid = {
+ .override = 0x698,
+ .security = 0x69c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_RCEDMAR,
+ .name = "rcedmar",
+ .sid = TEGRA194_SID_RCE,
+ .regs = {
+ .sid = {
+ .override = 0x6a0,
+ .security = 0x6a4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_RCEDMAW,
+ .name = "rcedmaw",
+ .sid = TEGRA194_SID_RCE,
+ .regs = {
+ .sid = {
+ .override = 0x6a8,
+ .security = 0x6ac,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVENC1SRD,
+ .name = "nvenc1srd",
+ .sid = TEGRA194_SID_NVENC1,
+ .regs = {
+ .sid = {
+ .override = 0x6b0,
+ .security = 0x6b4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVENC1SWR,
+ .name = "nvenc1swr",
+ .sid = TEGRA194_SID_NVENC1,
+ .regs = {
+ .sid = {
+ .override = 0x6b8,
+ .security = 0x6bc,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PCIE0R,
+ .name = "pcie0r",
+ .sid = TEGRA194_SID_PCIE0,
+ .regs = {
+ .sid = {
+ .override = 0x6c0,
+ .security = 0x6c4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PCIE0W,
+ .name = "pcie0w",
+ .sid = TEGRA194_SID_PCIE0,
+ .regs = {
+ .sid = {
+ .override = 0x6c8,
+ .security = 0x6cc,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PCIE1R,
+ .name = "pcie1r",
+ .sid = TEGRA194_SID_PCIE1,
+ .regs = {
+ .sid = {
+ .override = 0x6d0,
+ .security = 0x6d4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PCIE1W,
+ .name = "pcie1w",
+ .sid = TEGRA194_SID_PCIE1,
+ .regs = {
+ .sid = {
+ .override = 0x6d8,
+ .security = 0x6dc,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PCIE2AR,
+ .name = "pcie2ar",
+ .sid = TEGRA194_SID_PCIE2,
+ .regs = {
+ .sid = {
+ .override = 0x6e0,
+ .security = 0x6e4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PCIE2AW,
+ .name = "pcie2aw",
+ .sid = TEGRA194_SID_PCIE2,
+ .regs = {
+ .sid = {
+ .override = 0x6e8,
+ .security = 0x6ec,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PCIE3R,
+ .name = "pcie3r",
+ .sid = TEGRA194_SID_PCIE3,
+ .regs = {
+ .sid = {
+ .override = 0x6f0,
+ .security = 0x6f4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PCIE3W,
+ .name = "pcie3w",
+ .sid = TEGRA194_SID_PCIE3,
+ .regs = {
+ .sid = {
+ .override = 0x6f8,
+ .security = 0x6fc,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PCIE4R,
+ .name = "pcie4r",
+ .sid = TEGRA194_SID_PCIE4,
+ .regs = {
+ .sid = {
+ .override = 0x700,
+ .security = 0x704,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PCIE4W,
+ .name = "pcie4w",
+ .sid = TEGRA194_SID_PCIE4,
+ .regs = {
+ .sid = {
+ .override = 0x708,
+ .security = 0x70c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PCIE5R,
+ .name = "pcie5r",
+ .sid = TEGRA194_SID_PCIE5,
+ .regs = {
+ .sid = {
+ .override = 0x710,
+ .security = 0x714,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PCIE5W,
+ .name = "pcie5w",
+ .sid = TEGRA194_SID_PCIE5,
+ .regs = {
+ .sid = {
+ .override = 0x718,
+ .security = 0x71c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_ISPFALW,
+ .name = "ispfalw",
+ .sid = TEGRA194_SID_ISP_FALCON,
+ .regs = {
+ .sid = {
+ .override = 0x720,
+ .security = 0x724,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_DLA0RDA1,
+ .name = "dla0rda1",
+ .sid = TEGRA194_SID_NVDLA0,
+ .regs = {
+ .sid = {
+ .override = 0x748,
+ .security = 0x74c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_DLA1RDA1,
+ .name = "dla1rda1",
+ .sid = TEGRA194_SID_NVDLA1,
+ .regs = {
+ .sid = {
+ .override = 0x750,
+ .security = 0x754,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA0RDA1,
+ .name = "pva0rda1",
+ .sid = TEGRA194_SID_PVA0,
+ .regs = {
+ .sid = {
+ .override = 0x758,
+ .security = 0x75c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA0RDB1,
+ .name = "pva0rdb1",
+ .sid = TEGRA194_SID_PVA0,
+ .regs = {
+ .sid = {
+ .override = 0x760,
+ .security = 0x764,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA1RDA1,
+ .name = "pva1rda1",
+ .sid = TEGRA194_SID_PVA1,
+ .regs = {
+ .sid = {
+ .override = 0x768,
+ .security = 0x76c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PVA1RDB1,
+ .name = "pva1rdb1",
+ .sid = TEGRA194_SID_PVA1,
+ .regs = {
+ .sid = {
+ .override = 0x770,
+ .security = 0x774,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PCIE5R1,
+ .name = "pcie5r1",
+ .sid = TEGRA194_SID_PCIE5,
+ .regs = {
+ .sid = {
+ .override = 0x778,
+ .security = 0x77c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVENCSRD1,
+ .name = "nvencsrd1",
+ .sid = TEGRA194_SID_NVENC,
+ .regs = {
+ .sid = {
+ .override = 0x780,
+ .security = 0x784,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVENC1SRD1,
+ .name = "nvenc1srd1",
+ .sid = TEGRA194_SID_NVENC1,
+ .regs = {
+ .sid = {
+ .override = 0x788,
+ .security = 0x78c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_ISPRA1,
+ .name = "ispra1",
+ .sid = TEGRA194_SID_ISP,
+ .regs = {
+ .sid = {
+ .override = 0x790,
+ .security = 0x794,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_PCIE0R1,
+ .name = "pcie0r1",
+ .sid = TEGRA194_SID_PCIE0,
+ .regs = {
+ .sid = {
+ .override = 0x798,
+ .security = 0x79c,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVDEC1SRD,
+ .name = "nvdec1srd",
+ .sid = TEGRA194_SID_NVDEC1,
+ .regs = {
+ .sid = {
+ .override = 0x7c8,
+ .security = 0x7cc,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVDEC1SRD1,
+ .name = "nvdec1srd1",
+ .sid = TEGRA194_SID_NVDEC1,
+ .regs = {
+ .sid = {
+ .override = 0x7d0,
+ .security = 0x7d4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_NVDEC1SWR,
+ .name = "nvdec1swr",
+ .sid = TEGRA194_SID_NVDEC1,
+ .regs = {
+ .sid = {
+ .override = 0x7d8,
+ .security = 0x7dc,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU5R,
+ .name = "miu5r",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x7e0,
+ .security = 0x7e4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU5W,
+ .name = "miu5w",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x7e8,
+ .security = 0x7ec,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU6R,
+ .name = "miu6r",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x7f0,
+ .security = 0x7f4,
+ },
+ },
+ }, {
+ .id = TEGRA194_MEMORY_CLIENT_MIU6W,
+ .name = "miu6w",
+ .sid = TEGRA194_SID_MIU,
+ .regs = {
+ .sid = {
+ .override = 0x7f8,
+ .security = 0x7fc,
+ },
+ },
+ },
+};
+
+const struct tegra_mc_soc tegra194_mc_soc = {
+ .num_clients = ARRAY_SIZE(tegra194_mc_clients),
+ .clients = tegra194_mc_clients,
+ .num_address_bits = 40,
+ .ops = &tegra186_mc_ops,
+};
diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c
index da8a0da8da79..c3462dbc8c22 100644
--- a/drivers/memory/tegra/tegra20-emc.c
+++ b/drivers/memory/tegra/tegra20-emc.c
@@ -776,10 +776,6 @@ static void tegra_emc_debugfs_init(struct tegra_emc *emc)
}
emc->debugfs.root = debugfs_create_dir("emc", NULL);
- if (!emc->debugfs.root) {
- dev_err(emc->dev, "failed to create debugfs directory\n");
- return;
- }
debugfs_create_file("available_rates", 0444, emc->debugfs.root,
emc, &tegra_emc_debug_available_rates_fops);
@@ -908,49 +904,6 @@ err_msg:
return err;
}
-static int tegra_emc_opp_table_init(struct tegra_emc *emc)
-{
- u32 hw_version = BIT(tegra_sku_info.soc_process_id);
- struct opp_table *hw_opp_table;
- int err;
-
- hw_opp_table = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1);
- err = PTR_ERR_OR_ZERO(hw_opp_table);
- if (err) {
- dev_err(emc->dev, "failed to set OPP supported HW: %d\n", err);
- return err;
- }
-
- err = dev_pm_opp_of_add_table(emc->dev);
- if (err) {
- if (err == -ENODEV)
- dev_err(emc->dev, "OPP table not found, please update your device tree\n");
- else
- dev_err(emc->dev, "failed to add OPP table: %d\n", err);
-
- goto put_hw_table;
- }
-
- dev_info_once(emc->dev, "OPP HW ver. 0x%x, current clock rate %lu MHz\n",
- hw_version, clk_get_rate(emc->clk) / 1000000);
-
- /* first dummy rate-set initializes voltage state */
- err = dev_pm_opp_set_rate(emc->dev, clk_get_rate(emc->clk));
- if (err) {
- dev_err(emc->dev, "failed to initialize OPP clock: %d\n", err);
- goto remove_table;
- }
-
- return 0;
-
-remove_table:
- dev_pm_opp_of_remove_table(emc->dev);
-put_hw_table:
- dev_pm_opp_put_supported_hw(hw_opp_table);
-
- return err;
-}
-
static void devm_tegra_emc_unset_callback(void *data)
{
tegra20_clk_set_emc_round_callback(NULL, NULL);
@@ -1077,6 +1030,7 @@ static int tegra_emc_devfreq_init(struct tegra_emc *emc)
static int tegra_emc_probe(struct platform_device *pdev)
{
+ struct tegra_core_opp_params opp_params = {};
struct device_node *np;
struct tegra_emc *emc;
int irq, err;
@@ -1122,7 +1076,9 @@ static int tegra_emc_probe(struct platform_device *pdev)
if (err)
return err;
- err = tegra_emc_opp_table_init(emc);
+ opp_params.init_state = true;
+
+ err = devm_tegra_core_dev_init_opp_table(&pdev->dev, &opp_params);
if (err)
return err;
diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c
index 2db68a913b7a..fcd7738fcb53 100644
--- a/drivers/memory/tegra/tegra20.c
+++ b/drivers/memory/tegra/tegra20.c
@@ -679,7 +679,7 @@ static int tegra20_mc_stats_show(struct seq_file *s, void *unused)
return 0;
}
-static int tegra20_mc_init(struct tegra_mc *mc)
+static int tegra20_mc_probe(struct tegra_mc *mc)
{
debugfs_create_devm_seqfile(mc->dev, "stats", mc->debugfs.root,
tegra20_mc_stats_show);
@@ -687,6 +687,112 @@ static int tegra20_mc_init(struct tegra_mc *mc)
return 0;
}
+static int tegra20_mc_suspend(struct tegra_mc *mc)
+{
+ int err;
+
+ if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) {
+ err = tegra_gart_suspend(mc->gart);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int tegra20_mc_resume(struct tegra_mc *mc)
+{
+ int err;
+
+ if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) {
+ err = tegra_gart_resume(mc->gart);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static irqreturn_t tegra20_mc_handle_irq(int irq, void *data)
+{
+ struct tegra_mc *mc = data;
+ unsigned long status;
+ unsigned int bit;
+
+ /* mask all interrupts to avoid flooding */
+ status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
+ if (!status)
+ return IRQ_NONE;
+
+ for_each_set_bit(bit, &status, 32) {
+ const char *error = tegra_mc_status_names[bit];
+ const char *direction = "read", *secure = "";
+ const char *client, *desc;
+ phys_addr_t addr;
+ u32 value, reg;
+ u8 id, type;
+
+ switch (BIT(bit)) {
+ case MC_INT_DECERR_EMEM:
+ reg = MC_DECERR_EMEM_OTHERS_STATUS;
+ value = mc_readl(mc, reg);
+
+ id = value & mc->soc->client_id_mask;
+ desc = tegra_mc_error_names[2];
+
+ if (value & BIT(31))
+ direction = "write";
+ break;
+
+ case MC_INT_INVALID_GART_PAGE:
+ reg = MC_GART_ERROR_REQ;
+ value = mc_readl(mc, reg);
+
+ id = (value >> 1) & mc->soc->client_id_mask;
+ desc = tegra_mc_error_names[2];
+
+ if (value & BIT(0))
+ direction = "write";
+ break;
+
+ case MC_INT_SECURITY_VIOLATION:
+ reg = MC_SECURITY_VIOLATION_STATUS;
+ value = mc_readl(mc, reg);
+
+ id = value & mc->soc->client_id_mask;
+ type = (value & BIT(30)) ? 4 : 3;
+ desc = tegra_mc_error_names[type];
+ secure = "secure ";
+
+ if (value & BIT(31))
+ direction = "write";
+ break;
+
+ default:
+ continue;
+ }
+
+ client = mc->soc->clients[id].name;
+ addr = mc_readl(mc, reg + sizeof(u32));
+
+ dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s)\n",
+ client, secure, direction, &addr, error,
+ desc);
+ }
+
+ /* clear interrupts */
+ mc_writel(mc, status, MC_INTSTATUS);
+
+ return IRQ_HANDLED;
+}
+
+static const struct tegra_mc_ops tegra20_mc_ops = {
+ .probe = tegra20_mc_probe,
+ .suspend = tegra20_mc_suspend,
+ .resume = tegra20_mc_resume,
+ .handle_irq = tegra20_mc_handle_irq,
+};
+
const struct tegra_mc_soc tegra20_mc_soc = {
.clients = tegra20_mc_clients,
.num_clients = ARRAY_SIZE(tegra20_mc_clients),
@@ -698,5 +804,5 @@ const struct tegra_mc_soc tegra20_mc_soc = {
.resets = tegra20_mc_resets,
.num_resets = ARRAY_SIZE(tegra20_mc_resets),
.icc_ops = &tegra20_mc_icc_ops,
- .init = tegra20_mc_init,
+ .ops = &tegra20_mc_ops,
};
diff --git a/drivers/memory/tegra/tegra210-emc-core.c b/drivers/memory/tegra/tegra210-emc-core.c
index 5f224796e32e..06c0f17fa429 100644
--- a/drivers/memory/tegra/tegra210-emc-core.c
+++ b/drivers/memory/tegra/tegra210-emc-core.c
@@ -1759,10 +1759,6 @@ static void tegra210_emc_debugfs_init(struct tegra210_emc *emc)
}
emc->debugfs.root = debugfs_create_dir("emc", NULL);
- if (!emc->debugfs.root) {
- dev_err(dev, "failed to create debugfs directory\n");
- return;
- }
debugfs_create_file("available_rates", 0444, emc->debugfs.root, emc,
&tegra210_emc_debug_available_rates_fops);
diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c
index b3bbc5a05ba1..8ab6498dbe7d 100644
--- a/drivers/memory/tegra/tegra210.c
+++ b/drivers/memory/tegra/tegra210.c
@@ -16,1005 +16,1149 @@ static const struct tegra_mc_client tegra210_mc_clients[] = {
.id = 0x01,
.name = "display0a",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 1,
- },
- .la = {
- .reg = 0x2e8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x1e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x2e8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1e,
+ },
},
}, {
.id = 0x02,
.name = "display0ab",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 2,
- },
- .la = {
- .reg = 0x2f4,
- .shift = 0,
- .mask = 0xff,
- .def = 0x1e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x2f4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1e,
+ },
},
}, {
.id = 0x03,
.name = "display0b",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 3,
- },
- .la = {
- .reg = 0x2e8,
- .shift = 16,
- .mask = 0xff,
- .def = 0x1e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x2e8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x1e,
+ },
},
}, {
.id = 0x04,
.name = "display0bb",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 4,
- },
- .la = {
- .reg = 0x2f4,
- .shift = 16,
- .mask = 0xff,
- .def = 0x1e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x2f4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x1e,
+ },
},
}, {
.id = 0x05,
.name = "display0c",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 5,
- },
- .la = {
- .reg = 0x2ec,
- .shift = 0,
- .mask = 0xff,
- .def = 0x1e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x2ec,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1e,
+ },
},
}, {
.id = 0x06,
.name = "display0cb",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 6,
- },
- .la = {
- .reg = 0x2f8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x1e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 6,
+ },
+ .la = {
+ .reg = 0x2f8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1e,
+ },
},
}, {
.id = 0x0e,
.name = "afir",
.swgroup = TEGRA_SWGROUP_AFI,
- .smmu = {
- .reg = 0x228,
- .bit = 14,
- },
- .la = {
- .reg = 0x2e0,
- .shift = 0,
- .mask = 0xff,
- .def = 0x2e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 14,
+ },
+ .la = {
+ .reg = 0x2e0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x2e,
+ },
},
}, {
.id = 0x0f,
.name = "avpcarm7r",
.swgroup = TEGRA_SWGROUP_AVPC,
- .smmu = {
- .reg = 0x228,
- .bit = 15,
- },
- .la = {
- .reg = 0x2e4,
- .shift = 0,
- .mask = 0xff,
- .def = 0x04,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 15,
+ },
+ .la = {
+ .reg = 0x2e4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
},
}, {
.id = 0x10,
.name = "displayhc",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 16,
- },
- .la = {
- .reg = 0x2f0,
- .shift = 0,
- .mask = 0xff,
- .def = 0x1e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x2f0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1e,
+ },
},
}, {
.id = 0x11,
.name = "displayhcb",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 17,
- },
- .la = {
- .reg = 0x2fc,
- .shift = 0,
- .mask = 0xff,
- .def = 0x1e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x2fc,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1e,
+ },
},
}, {
.id = 0x15,
.name = "hdar",
.swgroup = TEGRA_SWGROUP_HDA,
- .smmu = {
- .reg = 0x228,
- .bit = 21,
- },
- .la = {
- .reg = 0x318,
- .shift = 0,
- .mask = 0xff,
- .def = 0x24,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x318,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x24,
+ },
},
}, {
.id = 0x16,
.name = "host1xdmar",
.swgroup = TEGRA_SWGROUP_HC,
- .smmu = {
- .reg = 0x228,
- .bit = 22,
- },
- .la = {
- .reg = 0x310,
- .shift = 0,
- .mask = 0xff,
- .def = 0x1e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x310,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1e,
+ },
},
}, {
.id = 0x17,
.name = "host1xr",
.swgroup = TEGRA_SWGROUP_HC,
- .smmu = {
- .reg = 0x228,
- .bit = 23,
- },
- .la = {
- .reg = 0x310,
- .shift = 16,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 23,
+ },
+ .la = {
+ .reg = 0x310,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
}, {
.id = 0x1c,
.name = "nvencsrd",
.swgroup = TEGRA_SWGROUP_NVENC,
- .smmu = {
- .reg = 0x228,
- .bit = 28,
- },
- .la = {
- .reg = 0x328,
- .shift = 0,
- .mask = 0xff,
- .def = 0x23,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 28,
+ },
+ .la = {
+ .reg = 0x328,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x23,
+ },
},
}, {
.id = 0x1d,
.name = "ppcsahbdmar",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x228,
- .bit = 29,
- },
- .la = {
- .reg = 0x344,
- .shift = 0,
- .mask = 0xff,
- .def = 0x49,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 29,
+ },
+ .la = {
+ .reg = 0x344,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x49,
+ },
},
}, {
.id = 0x1e,
.name = "ppcsahbslvr",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x228,
- .bit = 30,
- },
- .la = {
- .reg = 0x344,
- .shift = 16,
- .mask = 0xff,
- .def = 0x1a,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 30,
+ },
+ .la = {
+ .reg = 0x344,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x1a,
+ },
},
}, {
.id = 0x1f,
.name = "satar",
.swgroup = TEGRA_SWGROUP_SATA,
- .smmu = {
- .reg = 0x228,
- .bit = 31,
- },
- .la = {
- .reg = 0x350,
- .shift = 0,
- .mask = 0xff,
- .def = 0x65,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 31,
+ },
+ .la = {
+ .reg = 0x350,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x65,
+ },
},
}, {
.id = 0x27,
.name = "mpcorer",
.swgroup = TEGRA_SWGROUP_MPCORE,
- .la = {
- .reg = 0x320,
- .shift = 0,
- .mask = 0xff,
- .def = 0x04,
+ .regs = {
+ .la = {
+ .reg = 0x320,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
},
}, {
.id = 0x2b,
.name = "nvencswr",
.swgroup = TEGRA_SWGROUP_NVENC,
- .smmu = {
- .reg = 0x22c,
- .bit = 11,
- },
- .la = {
- .reg = 0x328,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x328,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x31,
.name = "afiw",
.swgroup = TEGRA_SWGROUP_AFI,
- .smmu = {
- .reg = 0x22c,
- .bit = 17,
- },
- .la = {
- .reg = 0x2e0,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x2e0,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x32,
.name = "avpcarm7w",
.swgroup = TEGRA_SWGROUP_AVPC,
- .smmu = {
- .reg = 0x22c,
- .bit = 18,
- },
- .la = {
- .reg = 0x2e4,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 18,
+ },
+ .la = {
+ .reg = 0x2e4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x35,
.name = "hdaw",
.swgroup = TEGRA_SWGROUP_HDA,
- .smmu = {
- .reg = 0x22c,
- .bit = 21,
- },
- .la = {
- .reg = 0x318,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x318,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x36,
.name = "host1xw",
.swgroup = TEGRA_SWGROUP_HC,
- .smmu = {
- .reg = 0x22c,
- .bit = 22,
- },
- .la = {
- .reg = 0x314,
- .shift = 0,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x314,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x39,
.name = "mpcorew",
.swgroup = TEGRA_SWGROUP_MPCORE,
- .la = {
- .reg = 0x320,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .la = {
+ .reg = 0x320,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x3b,
.name = "ppcsahbdmaw",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x22c,
- .bit = 27,
- },
- .la = {
- .reg = 0x348,
- .shift = 0,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 27,
+ },
+ .la = {
+ .reg = 0x348,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x3c,
.name = "ppcsahbslvw",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x22c,
- .bit = 28,
- },
- .la = {
- .reg = 0x348,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 28,
+ },
+ .la = {
+ .reg = 0x348,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x3d,
.name = "sataw",
.swgroup = TEGRA_SWGROUP_SATA,
- .smmu = {
- .reg = 0x22c,
- .bit = 29,
- },
- .la = {
- .reg = 0x350,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 29,
+ },
+ .la = {
+ .reg = 0x350,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x44,
.name = "ispra",
.swgroup = TEGRA_SWGROUP_ISP2,
- .smmu = {
- .reg = 0x230,
- .bit = 4,
- },
- .la = {
- .reg = 0x370,
- .shift = 0,
- .mask = 0xff,
- .def = 0x18,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x370,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x18,
+ },
},
}, {
.id = 0x46,
.name = "ispwa",
.swgroup = TEGRA_SWGROUP_ISP2,
- .smmu = {
- .reg = 0x230,
- .bit = 6,
- },
- .la = {
- .reg = 0x374,
- .shift = 0,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 6,
+ },
+ .la = {
+ .reg = 0x374,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x47,
.name = "ispwb",
.swgroup = TEGRA_SWGROUP_ISP2,
- .smmu = {
- .reg = 0x230,
- .bit = 7,
- },
- .la = {
- .reg = 0x374,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 7,
+ },
+ .la = {
+ .reg = 0x374,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x4a,
.name = "xusb_hostr",
.swgroup = TEGRA_SWGROUP_XUSB_HOST,
- .smmu = {
- .reg = 0x230,
- .bit = 10,
- },
- .la = {
- .reg = 0x37c,
- .shift = 0,
- .mask = 0xff,
- .def = 0x7a,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 10,
+ },
+ .la = {
+ .reg = 0x37c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x7a,
+ },
},
}, {
.id = 0x4b,
.name = "xusb_hostw",
.swgroup = TEGRA_SWGROUP_XUSB_HOST,
- .smmu = {
- .reg = 0x230,
- .bit = 11,
- },
- .la = {
- .reg = 0x37c,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x37c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x4c,
.name = "xusb_devr",
.swgroup = TEGRA_SWGROUP_XUSB_DEV,
- .smmu = {
- .reg = 0x230,
- .bit = 12,
- },
- .la = {
- .reg = 0x380,
- .shift = 0,
- .mask = 0xff,
- .def = 0x39,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 12,
+ },
+ .la = {
+ .reg = 0x380,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x39,
+ },
},
}, {
.id = 0x4d,
.name = "xusb_devw",
.swgroup = TEGRA_SWGROUP_XUSB_DEV,
- .smmu = {
- .reg = 0x230,
- .bit = 13,
- },
- .la = {
- .reg = 0x380,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 13,
+ },
+ .la = {
+ .reg = 0x380,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x4e,
.name = "isprab",
.swgroup = TEGRA_SWGROUP_ISP2B,
- .smmu = {
- .reg = 0x230,
- .bit = 14,
- },
- .la = {
- .reg = 0x384,
- .shift = 0,
- .mask = 0xff,
- .def = 0x18,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 14,
+ },
+ .la = {
+ .reg = 0x384,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x18,
+ },
},
}, {
.id = 0x50,
.name = "ispwab",
.swgroup = TEGRA_SWGROUP_ISP2B,
- .smmu = {
- .reg = 0x230,
- .bit = 16,
- },
- .la = {
- .reg = 0x388,
- .shift = 0,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x388,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x51,
.name = "ispwbb",
.swgroup = TEGRA_SWGROUP_ISP2B,
- .smmu = {
- .reg = 0x230,
- .bit = 17,
- },
- .la = {
- .reg = 0x388,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x388,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x54,
.name = "tsecsrd",
.swgroup = TEGRA_SWGROUP_TSEC,
- .smmu = {
- .reg = 0x230,
- .bit = 20,
- },
- .la = {
- .reg = 0x390,
- .shift = 0,
- .mask = 0xff,
- .def = 0x9b,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 20,
+ },
+ .la = {
+ .reg = 0x390,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x9b,
+ },
},
}, {
.id = 0x55,
.name = "tsecswr",
.swgroup = TEGRA_SWGROUP_TSEC,
- .smmu = {
- .reg = 0x230,
- .bit = 21,
- },
- .la = {
- .reg = 0x390,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x390,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x56,
.name = "a9avpscr",
.swgroup = TEGRA_SWGROUP_A9AVP,
- .smmu = {
- .reg = 0x230,
- .bit = 22,
- },
- .la = {
- .reg = 0x3a4,
- .shift = 0,
- .mask = 0xff,
- .def = 0x04,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x3a4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
},
}, {
.id = 0x57,
.name = "a9avpscw",
.swgroup = TEGRA_SWGROUP_A9AVP,
- .smmu = {
- .reg = 0x230,
- .bit = 23,
- },
- .la = {
- .reg = 0x3a4,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 23,
+ },
+ .la = {
+ .reg = 0x3a4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x58,
.name = "gpusrd",
.swgroup = TEGRA_SWGROUP_GPU,
- .smmu = {
- /* read-only */
- .reg = 0x230,
- .bit = 24,
- },
- .la = {
- .reg = 0x3c8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x1a,
+ .regs = {
+ .smmu = {
+ /* read-only */
+ .reg = 0x230,
+ .bit = 24,
+ },
+ .la = {
+ .reg = 0x3c8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1a,
+ },
},
}, {
.id = 0x59,
.name = "gpuswr",
.swgroup = TEGRA_SWGROUP_GPU,
- .smmu = {
- /* read-only */
- .reg = 0x230,
- .bit = 25,
- },
- .la = {
- .reg = 0x3c8,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ /* read-only */
+ .reg = 0x230,
+ .bit = 25,
+ },
+ .la = {
+ .reg = 0x3c8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x5a,
.name = "displayt",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x230,
- .bit = 26,
- },
- .la = {
- .reg = 0x2f0,
- .shift = 16,
- .mask = 0xff,
- .def = 0x1e,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 26,
+ },
+ .la = {
+ .reg = 0x2f0,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x1e,
+ },
},
}, {
.id = 0x60,
.name = "sdmmcra",
.swgroup = TEGRA_SWGROUP_SDMMC1A,
- .smmu = {
- .reg = 0x234,
- .bit = 0,
- },
- .la = {
- .reg = 0x3b8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x49,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 0,
+ },
+ .la = {
+ .reg = 0x3b8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x49,
+ },
},
}, {
.id = 0x61,
.name = "sdmmcraa",
.swgroup = TEGRA_SWGROUP_SDMMC2A,
- .smmu = {
- .reg = 0x234,
- .bit = 1,
- },
- .la = {
- .reg = 0x3bc,
- .shift = 0,
- .mask = 0xff,
- .def = 0x5a,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x3bc,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x5a,
+ },
},
}, {
.id = 0x62,
.name = "sdmmcr",
.swgroup = TEGRA_SWGROUP_SDMMC3A,
- .smmu = {
- .reg = 0x234,
- .bit = 2,
- },
- .la = {
- .reg = 0x3c0,
- .shift = 0,
- .mask = 0xff,
- .def = 0x49,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x3c0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x49,
+ },
},
}, {
.id = 0x63,
.swgroup = TEGRA_SWGROUP_SDMMC4A,
.name = "sdmmcrab",
- .smmu = {
- .reg = 0x234,
- .bit = 3,
- },
- .la = {
- .reg = 0x3c4,
- .shift = 0,
- .mask = 0xff,
- .def = 0x5a,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x3c4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x5a,
+ },
},
}, {
.id = 0x64,
.name = "sdmmcwa",
.swgroup = TEGRA_SWGROUP_SDMMC1A,
- .smmu = {
- .reg = 0x234,
- .bit = 4,
- },
- .la = {
- .reg = 0x3b8,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x3b8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x65,
.name = "sdmmcwaa",
.swgroup = TEGRA_SWGROUP_SDMMC2A,
- .smmu = {
- .reg = 0x234,
- .bit = 5,
- },
- .la = {
- .reg = 0x3bc,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x3bc,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x66,
.name = "sdmmcw",
.swgroup = TEGRA_SWGROUP_SDMMC3A,
- .smmu = {
- .reg = 0x234,
- .bit = 6,
- },
- .la = {
- .reg = 0x3c0,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 6,
+ },
+ .la = {
+ .reg = 0x3c0,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x67,
.name = "sdmmcwab",
.swgroup = TEGRA_SWGROUP_SDMMC4A,
- .smmu = {
- .reg = 0x234,
- .bit = 7,
- },
- .la = {
- .reg = 0x3c4,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 7,
+ },
+ .la = {
+ .reg = 0x3c4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x6c,
.name = "vicsrd",
.swgroup = TEGRA_SWGROUP_VIC,
- .smmu = {
- .reg = 0x234,
- .bit = 12,
- },
- .la = {
- .reg = 0x394,
- .shift = 0,
- .mask = 0xff,
- .def = 0x1a,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 12,
+ },
+ .la = {
+ .reg = 0x394,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1a,
+ },
},
}, {
.id = 0x6d,
.name = "vicswr",
.swgroup = TEGRA_SWGROUP_VIC,
- .smmu = {
- .reg = 0x234,
- .bit = 13,
- },
- .la = {
- .reg = 0x394,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 13,
+ },
+ .la = {
+ .reg = 0x394,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x72,
.name = "viw",
.swgroup = TEGRA_SWGROUP_VI,
- .smmu = {
- .reg = 0x234,
- .bit = 18,
- },
- .la = {
- .reg = 0x398,
- .shift = 0,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 18,
+ },
+ .la = {
+ .reg = 0x398,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x73,
.name = "displayd",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x234,
- .bit = 19,
- },
- .la = {
- .reg = 0x3c8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 19,
+ },
+ .la = {
+ .reg = 0x3c8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
}, {
.id = 0x78,
.name = "nvdecsrd",
.swgroup = TEGRA_SWGROUP_NVDEC,
- .smmu = {
- .reg = 0x234,
- .bit = 24,
- },
- .la = {
- .reg = 0x3d8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x23,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 24,
+ },
+ .la = {
+ .reg = 0x3d8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x23,
+ },
},
}, {
.id = 0x79,
.name = "nvdecswr",
.swgroup = TEGRA_SWGROUP_NVDEC,
- .smmu = {
- .reg = 0x234,
- .bit = 25,
- },
- .la = {
- .reg = 0x3d8,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 25,
+ },
+ .la = {
+ .reg = 0x3d8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x7a,
.name = "aper",
.swgroup = TEGRA_SWGROUP_APE,
- .smmu = {
- .reg = 0x234,
- .bit = 26,
- },
- .la = {
- .reg = 0x3dc,
- .shift = 0,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 26,
+ },
+ .la = {
+ .reg = 0x3dc,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
}, {
.id = 0x7b,
.name = "apew",
.swgroup = TEGRA_SWGROUP_APE,
- .smmu = {
- .reg = 0x234,
- .bit = 27,
- },
- .la = {
- .reg = 0x3dc,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 27,
+ },
+ .la = {
+ .reg = 0x3dc,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x7e,
.name = "nvjpgsrd",
.swgroup = TEGRA_SWGROUP_NVJPG,
- .smmu = {
- .reg = 0x234,
- .bit = 30,
- },
- .la = {
- .reg = 0x3e4,
- .shift = 0,
- .mask = 0xff,
- .def = 0x23,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 30,
+ },
+ .la = {
+ .reg = 0x3e4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x23,
+ },
},
}, {
.id = 0x7f,
.name = "nvjpgswr",
.swgroup = TEGRA_SWGROUP_NVJPG,
- .smmu = {
- .reg = 0x234,
- .bit = 31,
- },
- .la = {
- .reg = 0x3e4,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x234,
+ .bit = 31,
+ },
+ .la = {
+ .reg = 0x3e4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x80,
.name = "sesrd",
.swgroup = TEGRA_SWGROUP_SE,
- .smmu = {
- .reg = 0xb98,
- .bit = 0,
- },
- .la = {
- .reg = 0x3e0,
- .shift = 0,
- .mask = 0xff,
- .def = 0x2e,
+ .regs = {
+ .smmu = {
+ .reg = 0xb98,
+ .bit = 0,
+ },
+ .la = {
+ .reg = 0x3e0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x2e,
+ },
},
}, {
.id = 0x81,
.name = "seswr",
.swgroup = TEGRA_SWGROUP_SE,
- .smmu = {
- .reg = 0xb98,
- .bit = 1,
- },
- .la = {
- .reg = 0x3e0,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0xb98,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x3e0,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x82,
.name = "axiapr",
.swgroup = TEGRA_SWGROUP_AXIAP,
- .smmu = {
- .reg = 0xb98,
- .bit = 2,
- },
- .la = {
- .reg = 0x3a0,
- .shift = 0,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0xb98,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x3a0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
}, {
.id = 0x83,
.name = "axiapw",
.swgroup = TEGRA_SWGROUP_AXIAP,
- .smmu = {
- .reg = 0xb98,
- .bit = 3,
- },
- .la = {
- .reg = 0x3a0,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0xb98,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x3a0,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x84,
.name = "etrr",
.swgroup = TEGRA_SWGROUP_ETR,
- .smmu = {
- .reg = 0xb98,
- .bit = 4,
- },
- .la = {
- .reg = 0x3ec,
- .shift = 0,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0xb98,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x3ec,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
}, {
.id = 0x85,
.name = "etrw",
.swgroup = TEGRA_SWGROUP_ETR,
- .smmu = {
- .reg = 0xb98,
- .bit = 5,
- },
- .la = {
- .reg = 0x3ec,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0xb98,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x3ec,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x86,
.name = "tsecsrdb",
.swgroup = TEGRA_SWGROUP_TSECB,
- .smmu = {
- .reg = 0xb98,
- .bit = 6,
- },
- .la = {
- .reg = 0x3f0,
- .shift = 0,
- .mask = 0xff,
- .def = 0x9b,
+ .regs = {
+ .smmu = {
+ .reg = 0xb98,
+ .bit = 6,
+ },
+ .la = {
+ .reg = 0x3f0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x9b,
+ },
},
}, {
.id = 0x87,
.name = "tsecswrb",
.swgroup = TEGRA_SWGROUP_TSECB,
- .smmu = {
- .reg = 0xb98,
- .bit = 7,
- },
- .la = {
- .reg = 0x3f0,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0xb98,
+ .bit = 7,
+ },
+ .la = {
+ .reg = 0x3f0,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
}, {
.id = 0x88,
.name = "gpusrd2",
.swgroup = TEGRA_SWGROUP_GPU,
- .smmu = {
- /* read-only */
- .reg = 0xb98,
- .bit = 8,
- },
- .la = {
- .reg = 0x3e8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x1a,
+ .regs = {
+ .smmu = {
+ /* read-only */
+ .reg = 0xb98,
+ .bit = 8,
+ },
+ .la = {
+ .reg = 0x3e8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1a,
+ },
},
}, {
.id = 0x89,
.name = "gpuswr2",
.swgroup = TEGRA_SWGROUP_GPU,
- .smmu = {
- /* read-only */
- .reg = 0xb98,
- .bit = 9,
- },
- .la = {
- .reg = 0x3e8,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ /* read-only */
+ .reg = 0xb98,
+ .bit = 9,
+ },
+ .la = {
+ .reg = 0x3e8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
},
};
@@ -1142,4 +1286,5 @@ const struct tegra_mc_soc tegra210_mc_soc = {
.reset_ops = &tegra_mc_reset_ops_common,
.resets = tegra210_mc_resets,
.num_resets = ARRAY_SIZE(tegra210_mc_resets),
+ .ops = &tegra30_mc_ops,
};
diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c
index 829f6d673c96..7e21a852f2e1 100644
--- a/drivers/memory/tegra/tegra30-emc.c
+++ b/drivers/memory/tegra/tegra30-emc.c
@@ -150,8 +150,8 @@
#define EMC_SELF_REF_CMD_ENABLED BIT(0)
#define DRAM_DEV_SEL_ALL (0 << 30)
-#define DRAM_DEV_SEL_0 (2 << 30)
-#define DRAM_DEV_SEL_1 (1 << 30)
+#define DRAM_DEV_SEL_0 BIT(31)
+#define DRAM_DEV_SEL_1 BIT(30)
#define DRAM_BROADCAST(num) \
((num) > 1 ? DRAM_DEV_SEL_ALL : DRAM_DEV_SEL_0)
@@ -1354,10 +1354,6 @@ static void tegra_emc_debugfs_init(struct tegra_emc *emc)
}
emc->debugfs.root = debugfs_create_dir("emc", NULL);
- if (!emc->debugfs.root) {
- dev_err(emc->dev, "failed to create debugfs directory\n");
- return;
- }
debugfs_create_file("available_rates", 0444, emc->debugfs.root,
emc, &tegra_emc_debug_available_rates_fops);
@@ -1480,49 +1476,6 @@ err_msg:
return err;
}
-static int tegra_emc_opp_table_init(struct tegra_emc *emc)
-{
- u32 hw_version = BIT(tegra_sku_info.soc_speedo_id);
- struct opp_table *hw_opp_table;
- int err;
-
- hw_opp_table = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1);
- err = PTR_ERR_OR_ZERO(hw_opp_table);
- if (err) {
- dev_err(emc->dev, "failed to set OPP supported HW: %d\n", err);
- return err;
- }
-
- err = dev_pm_opp_of_add_table(emc->dev);
- if (err) {
- if (err == -ENODEV)
- dev_err(emc->dev, "OPP table not found, please update your device tree\n");
- else
- dev_err(emc->dev, "failed to add OPP table: %d\n", err);
-
- goto put_hw_table;
- }
-
- dev_info_once(emc->dev, "OPP HW ver. 0x%x, current clock rate %lu MHz\n",
- hw_version, clk_get_rate(emc->clk) / 1000000);
-
- /* first dummy rate-set initializes voltage state */
- err = dev_pm_opp_set_rate(emc->dev, clk_get_rate(emc->clk));
- if (err) {
- dev_err(emc->dev, "failed to initialize OPP clock: %d\n", err);
- goto remove_table;
- }
-
- return 0;
-
-remove_table:
- dev_pm_opp_of_remove_table(emc->dev);
-put_hw_table:
- dev_pm_opp_put_supported_hw(hw_opp_table);
-
- return err;
-}
-
static void devm_tegra_emc_unset_callback(void *data)
{
tegra20_clk_set_emc_round_callback(NULL, NULL);
@@ -1568,6 +1521,7 @@ static int tegra_emc_init_clk(struct tegra_emc *emc)
static int tegra_emc_probe(struct platform_device *pdev)
{
+ struct tegra_core_opp_params opp_params = {};
struct device_node *np;
struct tegra_emc *emc;
int err;
@@ -1617,7 +1571,9 @@ static int tegra_emc_probe(struct platform_device *pdev)
if (err)
return err;
- err = tegra_emc_opp_table_init(emc);
+ opp_params.init_state = true;
+
+ err = devm_tegra_core_dev_init_opp_table(&pdev->dev, &opp_params);
if (err)
return err;
diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
index ea849003014b..84316357513d 100644
--- a/drivers/memory/tegra/tegra30.c
+++ b/drivers/memory/tegra/tegra30.c
@@ -37,970 +37,1102 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
.id = 0x00,
.name = "ptcr",
.swgroup = TEGRA_SWGROUP_PTC,
- .la = {
- .reg = 0x34c,
- .shift = 0,
- .mask = 0xff,
- .def = 0x0,
+ .regs = {
+ .la = {
+ .reg = 0x34c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0,
+ },
},
.fifo_size = 16 * 2,
}, {
.id = 0x01,
.name = "display0a",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 1,
- },
- .la = {
- .reg = 0x2e8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x4e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x2e8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
},
.fifo_size = 16 * 128,
}, {
.id = 0x02,
.name = "display0ab",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 2,
- },
- .la = {
- .reg = 0x2f4,
- .shift = 0,
- .mask = 0xff,
- .def = 0x4e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x2f4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
},
.fifo_size = 16 * 128,
}, {
.id = 0x03,
.name = "display0b",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 3,
- },
- .la = {
- .reg = 0x2e8,
- .shift = 16,
- .mask = 0xff,
- .def = 0x4e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x2e8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x04,
.name = "display0bb",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 4,
- },
- .la = {
- .reg = 0x2f4,
- .shift = 16,
- .mask = 0xff,
- .def = 0x4e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x2f4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x05,
.name = "display0c",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 5,
- },
- .la = {
- .reg = 0x2ec,
- .shift = 0,
- .mask = 0xff,
- .def = 0x4e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x2ec,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
},
.fifo_size = 16 * 128,
}, {
.id = 0x06,
.name = "display0cb",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 6,
- },
- .la = {
- .reg = 0x2f8,
- .shift = 0,
- .mask = 0xff,
- .def = 0x4e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 6,
+ },
+ .la = {
+ .reg = 0x2f8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
},
.fifo_size = 16 * 128,
}, {
.id = 0x07,
.name = "display1b",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 7,
- },
- .la = {
- .reg = 0x2ec,
- .shift = 16,
- .mask = 0xff,
- .def = 0x4e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 7,
+ },
+ .la = {
+ .reg = 0x2ec,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x08,
.name = "display1bb",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 8,
- },
- .la = {
- .reg = 0x2f8,
- .shift = 16,
- .mask = 0xff,
- .def = 0x4e,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 8,
+ },
+ .la = {
+ .reg = 0x2f8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x09,
.name = "eppup",
.swgroup = TEGRA_SWGROUP_EPP,
- .smmu = {
- .reg = 0x228,
- .bit = 9,
- },
- .la = {
- .reg = 0x300,
- .shift = 0,
- .mask = 0xff,
- .def = 0x17,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 9,
+ },
+ .la = {
+ .reg = 0x300,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x17,
+ },
},
.fifo_size = 16 * 8,
}, {
.id = 0x0a,
.name = "g2pr",
.swgroup = TEGRA_SWGROUP_G2,
- .smmu = {
- .reg = 0x228,
- .bit = 10,
- },
- .la = {
- .reg = 0x308,
- .shift = 0,
- .mask = 0xff,
- .def = 0x09,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 10,
+ },
+ .la = {
+ .reg = 0x308,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x09,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x0b,
.name = "g2sr",
.swgroup = TEGRA_SWGROUP_G2,
- .smmu = {
- .reg = 0x228,
- .bit = 11,
- },
- .la = {
- .reg = 0x308,
- .shift = 16,
- .mask = 0xff,
- .def = 0x09,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x308,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x09,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x0c,
.name = "mpeunifbr",
.swgroup = TEGRA_SWGROUP_MPE,
- .smmu = {
- .reg = 0x228,
- .bit = 12,
- },
- .la = {
- .reg = 0x328,
- .shift = 0,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 12,
+ },
+ .la = {
+ .reg = 0x328,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
.fifo_size = 16 * 8,
}, {
.id = 0x0d,
.name = "viruv",
.swgroup = TEGRA_SWGROUP_VI,
- .smmu = {
- .reg = 0x228,
- .bit = 13,
- },
- .la = {
- .reg = 0x364,
- .shift = 0,
- .mask = 0xff,
- .def = 0x2c,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 13,
+ },
+ .la = {
+ .reg = 0x364,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x2c,
+ },
},
.fifo_size = 16 * 8,
}, {
.id = 0x0e,
.name = "afir",
.swgroup = TEGRA_SWGROUP_AFI,
- .smmu = {
- .reg = 0x228,
- .bit = 14,
- },
- .la = {
- .reg = 0x2e0,
- .shift = 0,
- .mask = 0xff,
- .def = 0x10,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 14,
+ },
+ .la = {
+ .reg = 0x2e0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x10,
+ },
},
.fifo_size = 16 * 32,
}, {
.id = 0x0f,
.name = "avpcarm7r",
.swgroup = TEGRA_SWGROUP_AVPC,
- .smmu = {
- .reg = 0x228,
- .bit = 15,
- },
- .la = {
- .reg = 0x2e4,
- .shift = 0,
- .mask = 0xff,
- .def = 0x04,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 15,
+ },
+ .la = {
+ .reg = 0x2e4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
},
.fifo_size = 16 * 2,
}, {
.id = 0x10,
.name = "displayhc",
.swgroup = TEGRA_SWGROUP_DC,
- .smmu = {
- .reg = 0x228,
- .bit = 16,
- },
- .la = {
- .reg = 0x2f0,
- .shift = 0,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x2f0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
.fifo_size = 16 * 2,
}, {
.id = 0x11,
.name = "displayhcb",
.swgroup = TEGRA_SWGROUP_DCB,
- .smmu = {
- .reg = 0x228,
- .bit = 17,
- },
- .la = {
- .reg = 0x2fc,
- .shift = 0,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x2fc,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
.fifo_size = 16 * 2,
}, {
.id = 0x12,
.name = "fdcdrd",
.swgroup = TEGRA_SWGROUP_NV,
- .smmu = {
- .reg = 0x228,
- .bit = 18,
- },
- .la = {
- .reg = 0x334,
- .shift = 0,
- .mask = 0xff,
- .def = 0x0a,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 18,
+ },
+ .la = {
+ .reg = 0x334,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0a,
+ },
},
.fifo_size = 16 * 48,
}, {
.id = 0x13,
.name = "fdcdrd2",
.swgroup = TEGRA_SWGROUP_NV2,
- .smmu = {
- .reg = 0x228,
- .bit = 19,
- },
- .la = {
- .reg = 0x33c,
- .shift = 0,
- .mask = 0xff,
- .def = 0x0a,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 19,
+ },
+ .la = {
+ .reg = 0x33c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0a,
+ },
},
.fifo_size = 16 * 48,
}, {
.id = 0x14,
.name = "g2dr",
.swgroup = TEGRA_SWGROUP_G2,
- .smmu = {
- .reg = 0x228,
- .bit = 20,
- },
- .la = {
- .reg = 0x30c,
- .shift = 0,
- .mask = 0xff,
- .def = 0x0a,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 20,
+ },
+ .la = {
+ .reg = 0x30c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0a,
+ },
},
.fifo_size = 16 * 48,
}, {
.id = 0x15,
.name = "hdar",
.swgroup = TEGRA_SWGROUP_HDA,
- .smmu = {
- .reg = 0x228,
- .bit = 21,
- },
- .la = {
- .reg = 0x318,
- .shift = 0,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x318,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
.fifo_size = 16 * 16,
}, {
.id = 0x16,
.name = "host1xdmar",
.swgroup = TEGRA_SWGROUP_HC,
- .smmu = {
- .reg = 0x228,
- .bit = 22,
- },
- .la = {
- .reg = 0x310,
- .shift = 0,
- .mask = 0xff,
- .def = 0x05,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x310,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x05,
+ },
},
.fifo_size = 16 * 16,
}, {
.id = 0x17,
.name = "host1xr",
.swgroup = TEGRA_SWGROUP_HC,
- .smmu = {
- .reg = 0x228,
- .bit = 23,
- },
- .la = {
- .reg = 0x310,
- .shift = 16,
- .mask = 0xff,
- .def = 0x50,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 23,
+ },
+ .la = {
+ .reg = 0x310,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x50,
+ },
},
.fifo_size = 16 * 8,
}, {
.id = 0x18,
.name = "idxsrd",
.swgroup = TEGRA_SWGROUP_NV,
- .smmu = {
- .reg = 0x228,
- .bit = 24,
- },
- .la = {
- .reg = 0x334,
- .shift = 16,
- .mask = 0xff,
- .def = 0x13,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 24,
+ },
+ .la = {
+ .reg = 0x334,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x13,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x19,
.name = "idxsrd2",
.swgroup = TEGRA_SWGROUP_NV2,
- .smmu = {
- .reg = 0x228,
- .bit = 25,
- },
- .la = {
- .reg = 0x33c,
- .shift = 16,
- .mask = 0xff,
- .def = 0x13,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 25,
+ },
+ .la = {
+ .reg = 0x33c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x13,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x1a,
.name = "mpe_ipred",
.swgroup = TEGRA_SWGROUP_MPE,
- .smmu = {
- .reg = 0x228,
- .bit = 26,
- },
- .la = {
- .reg = 0x328,
- .shift = 16,
- .mask = 0xff,
- .def = 0x80,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 26,
+ },
+ .la = {
+ .reg = 0x328,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
},
.fifo_size = 16 * 2,
}, {
.id = 0x1b,
.name = "mpeamemrd",
.swgroup = TEGRA_SWGROUP_MPE,
- .smmu = {
- .reg = 0x228,
- .bit = 27,
- },
- .la = {
- .reg = 0x32c,
- .shift = 0,
- .mask = 0xff,
- .def = 0x42,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 27,
+ },
+ .la = {
+ .reg = 0x32c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x42,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x1c,
.name = "mpecsrd",
.swgroup = TEGRA_SWGROUP_MPE,
- .smmu = {
- .reg = 0x228,
- .bit = 28,
- },
- .la = {
- .reg = 0x32c,
- .shift = 16,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 28,
+ },
+ .la = {
+ .reg = 0x32c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
.fifo_size = 16 * 8,
}, {
.id = 0x1d,
.name = "ppcsahbdmar",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x228,
- .bit = 29,
- },
- .la = {
- .reg = 0x344,
- .shift = 0,
- .mask = 0xff,
- .def = 0x10,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 29,
+ },
+ .la = {
+ .reg = 0x344,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x10,
+ },
},
.fifo_size = 16 * 2,
}, {
.id = 0x1e,
.name = "ppcsahbslvr",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x228,
- .bit = 30,
- },
- .la = {
- .reg = 0x344,
- .shift = 16,
- .mask = 0xff,
- .def = 0x12,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 30,
+ },
+ .la = {
+ .reg = 0x344,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x12,
+ },
},
.fifo_size = 16 * 8,
}, {
.id = 0x1f,
.name = "satar",
.swgroup = TEGRA_SWGROUP_SATA,
- .smmu = {
- .reg = 0x228,
- .bit = 31,
- },
- .la = {
- .reg = 0x350,
- .shift = 0,
- .mask = 0xff,
- .def = 0x33,
+ .regs = {
+ .smmu = {
+ .reg = 0x228,
+ .bit = 31,
+ },
+ .la = {
+ .reg = 0x350,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x33,
+ },
},
.fifo_size = 16 * 32,
}, {
.id = 0x20,
.name = "texsrd",
.swgroup = TEGRA_SWGROUP_NV,
- .smmu = {
- .reg = 0x22c,
- .bit = 0,
- },
- .la = {
- .reg = 0x338,
- .shift = 0,
- .mask = 0xff,
- .def = 0x13,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 0,
+ },
+ .la = {
+ .reg = 0x338,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x13,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x21,
.name = "texsrd2",
.swgroup = TEGRA_SWGROUP_NV2,
- .smmu = {
- .reg = 0x22c,
- .bit = 1,
- },
- .la = {
- .reg = 0x340,
- .shift = 0,
- .mask = 0xff,
- .def = 0x13,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x340,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x13,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x22,
.name = "vdebsevr",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 2,
- },
- .la = {
- .reg = 0x354,
- .shift = 0,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x354,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
.fifo_size = 16 * 8,
}, {
.id = 0x23,
.name = "vdember",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 3,
- },
- .la = {
- .reg = 0x354,
- .shift = 16,
- .mask = 0xff,
- .def = 0xd0,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x354,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xd0,
+ },
},
.fifo_size = 16 * 4,
}, {
.id = 0x24,
.name = "vdemcer",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 4,
- },
- .la = {
- .reg = 0x358,
- .shift = 0,
- .mask = 0xff,
- .def = 0x2a,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x358,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x2a,
+ },
},
.fifo_size = 16 * 16,
}, {
.id = 0x25,
.name = "vdetper",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 5,
- },
- .la = {
- .reg = 0x358,
- .shift = 16,
- .mask = 0xff,
- .def = 0x74,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x358,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x74,
+ },
},
.fifo_size = 16 * 16,
}, {
.id = 0x26,
.name = "mpcorelpr",
.swgroup = TEGRA_SWGROUP_MPCORELP,
- .la = {
- .reg = 0x324,
- .shift = 0,
- .mask = 0xff,
- .def = 0x04,
+ .regs = {
+ .la = {
+ .reg = 0x324,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
},
.fifo_size = 16 * 14,
}, {
.id = 0x27,
.name = "mpcorer",
.swgroup = TEGRA_SWGROUP_MPCORE,
- .la = {
- .reg = 0x320,
- .shift = 0,
- .mask = 0xff,
- .def = 0x04,
+ .regs = {
+ .la = {
+ .reg = 0x320,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
},
.fifo_size = 16 * 14,
}, {
.id = 0x28,
.name = "eppu",
.swgroup = TEGRA_SWGROUP_EPP,
- .smmu = {
- .reg = 0x22c,
- .bit = 8,
- },
- .la = {
- .reg = 0x300,
- .shift = 16,
- .mask = 0xff,
- .def = 0x6c,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 8,
+ },
+ .la = {
+ .reg = 0x300,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x6c,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x29,
.name = "eppv",
.swgroup = TEGRA_SWGROUP_EPP,
- .smmu = {
- .reg = 0x22c,
- .bit = 9,
- },
- .la = {
- .reg = 0x304,
- .shift = 0,
- .mask = 0xff,
- .def = 0x6c,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 9,
+ },
+ .la = {
+ .reg = 0x304,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x6c,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x2a,
.name = "eppy",
.swgroup = TEGRA_SWGROUP_EPP,
- .smmu = {
- .reg = 0x22c,
- .bit = 10,
- },
- .la = {
- .reg = 0x304,
- .shift = 16,
- .mask = 0xff,
- .def = 0x6c,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 10,
+ },
+ .la = {
+ .reg = 0x304,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x6c,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x2b,
.name = "mpeunifbw",
.swgroup = TEGRA_SWGROUP_MPE,
- .smmu = {
- .reg = 0x22c,
- .bit = 11,
- },
- .la = {
- .reg = 0x330,
- .shift = 0,
- .mask = 0xff,
- .def = 0x13,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x330,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x13,
+ },
},
.fifo_size = 16 * 8,
}, {
.id = 0x2c,
.name = "viwsb",
.swgroup = TEGRA_SWGROUP_VI,
- .smmu = {
- .reg = 0x22c,
- .bit = 12,
- },
- .la = {
- .reg = 0x364,
- .shift = 16,
- .mask = 0xff,
- .def = 0x12,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 12,
+ },
+ .la = {
+ .reg = 0x364,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x12,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x2d,
.name = "viwu",
.swgroup = TEGRA_SWGROUP_VI,
- .smmu = {
- .reg = 0x22c,
- .bit = 13,
- },
- .la = {
- .reg = 0x368,
- .shift = 0,
- .mask = 0xff,
- .def = 0xb2,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 13,
+ },
+ .la = {
+ .reg = 0x368,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xb2,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x2e,
.name = "viwv",
.swgroup = TEGRA_SWGROUP_VI,
- .smmu = {
- .reg = 0x22c,
- .bit = 14,
- },
- .la = {
- .reg = 0x368,
- .shift = 16,
- .mask = 0xff,
- .def = 0xb2,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 14,
+ },
+ .la = {
+ .reg = 0x368,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xb2,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x2f,
.name = "viwy",
.swgroup = TEGRA_SWGROUP_VI,
- .smmu = {
- .reg = 0x22c,
- .bit = 15,
- },
- .la = {
- .reg = 0x36c,
- .shift = 0,
- .mask = 0xff,
- .def = 0x12,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 15,
+ },
+ .la = {
+ .reg = 0x36c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x12,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x30,
.name = "g2dw",
.swgroup = TEGRA_SWGROUP_G2,
- .smmu = {
- .reg = 0x22c,
- .bit = 16,
- },
- .la = {
- .reg = 0x30c,
- .shift = 16,
- .mask = 0xff,
- .def = 0x9,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x30c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x9,
+ },
},
.fifo_size = 16 * 128,
}, {
.id = 0x31,
.name = "afiw",
.swgroup = TEGRA_SWGROUP_AFI,
- .smmu = {
- .reg = 0x22c,
- .bit = 17,
- },
- .la = {
- .reg = 0x2e0,
- .shift = 16,
- .mask = 0xff,
- .def = 0x0c,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x2e0,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0c,
+ },
},
.fifo_size = 16 * 32,
}, {
.id = 0x32,
.name = "avpcarm7w",
.swgroup = TEGRA_SWGROUP_AVPC,
- .smmu = {
- .reg = 0x22c,
- .bit = 18,
- },
- .la = {
- .reg = 0x2e4,
- .shift = 16,
- .mask = 0xff,
- .def = 0x0e,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 18,
+ },
+ .la = {
+ .reg = 0x2e4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0e,
+ },
},
.fifo_size = 16 * 2,
}, {
.id = 0x33,
.name = "fdcdwr",
.swgroup = TEGRA_SWGROUP_NV,
- .smmu = {
- .reg = 0x22c,
- .bit = 19,
- },
- .la = {
- .reg = 0x338,
- .shift = 16,
- .mask = 0xff,
- .def = 0x0a,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 19,
+ },
+ .la = {
+ .reg = 0x338,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0a,
+ },
},
.fifo_size = 16 * 48,
}, {
.id = 0x34,
.name = "fdcdwr2",
.swgroup = TEGRA_SWGROUP_NV2,
- .smmu = {
- .reg = 0x22c,
- .bit = 20,
- },
- .la = {
- .reg = 0x340,
- .shift = 16,
- .mask = 0xff,
- .def = 0x0a,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 20,
+ },
+ .la = {
+ .reg = 0x340,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0a,
+ },
},
.fifo_size = 16 * 48,
}, {
.id = 0x35,
.name = "hdaw",
.swgroup = TEGRA_SWGROUP_HDA,
- .smmu = {
- .reg = 0x22c,
- .bit = 21,
- },
- .la = {
- .reg = 0x318,
- .shift = 16,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x318,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
.fifo_size = 16 * 16,
}, {
.id = 0x36,
.name = "host1xw",
.swgroup = TEGRA_SWGROUP_HC,
- .smmu = {
- .reg = 0x22c,
- .bit = 22,
- },
- .la = {
- .reg = 0x314,
- .shift = 0,
- .mask = 0xff,
- .def = 0x10,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x314,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x10,
+ },
},
.fifo_size = 16 * 32,
}, {
.id = 0x37,
.name = "ispw",
.swgroup = TEGRA_SWGROUP_ISP,
- .smmu = {
- .reg = 0x22c,
- .bit = 23,
- },
- .la = {
- .reg = 0x31c,
- .shift = 0,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 23,
+ },
+ .la = {
+ .reg = 0x31c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
.fifo_size = 16 * 64,
}, {
.id = 0x38,
.name = "mpcorelpw",
.swgroup = TEGRA_SWGROUP_MPCORELP,
- .la = {
- .reg = 0x324,
- .shift = 16,
- .mask = 0xff,
- .def = 0x0e,
+ .regs = {
+ .la = {
+ .reg = 0x324,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0e,
+ },
},
.fifo_size = 16 * 24,
}, {
.id = 0x39,
.name = "mpcorew",
.swgroup = TEGRA_SWGROUP_MPCORE,
- .la = {
- .reg = 0x320,
- .shift = 16,
- .mask = 0xff,
- .def = 0x0e,
+ .regs = {
+ .la = {
+ .reg = 0x320,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0e,
+ },
},
.fifo_size = 16 * 24,
}, {
.id = 0x3a,
.name = "mpecswr",
.swgroup = TEGRA_SWGROUP_MPE,
- .smmu = {
- .reg = 0x22c,
- .bit = 26,
- },
- .la = {
- .reg = 0x330,
- .shift = 16,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 26,
+ },
+ .la = {
+ .reg = 0x330,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
.fifo_size = 16 * 8,
}, {
.id = 0x3b,
.name = "ppcsahbdmaw",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x22c,
- .bit = 27,
- },
- .la = {
- .reg = 0x348,
- .shift = 0,
- .mask = 0xff,
- .def = 0x10,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 27,
+ },
+ .la = {
+ .reg = 0x348,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x10,
+ },
},
.fifo_size = 16 * 2,
}, {
.id = 0x3c,
.name = "ppcsahbslvw",
.swgroup = TEGRA_SWGROUP_PPCS,
- .smmu = {
- .reg = 0x22c,
- .bit = 28,
- },
- .la = {
- .reg = 0x348,
- .shift = 16,
- .mask = 0xff,
- .def = 0x06,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 28,
+ },
+ .la = {
+ .reg = 0x348,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x06,
+ },
},
.fifo_size = 16 * 4,
}, {
.id = 0x3d,
.name = "sataw",
.swgroup = TEGRA_SWGROUP_SATA,
- .smmu = {
- .reg = 0x22c,
- .bit = 29,
- },
- .la = {
- .reg = 0x350,
- .shift = 16,
- .mask = 0xff,
- .def = 0x33,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 29,
+ },
+ .la = {
+ .reg = 0x350,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x33,
+ },
},
.fifo_size = 16 * 32,
}, {
.id = 0x3e,
.name = "vdebsevw",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 30,
- },
- .la = {
- .reg = 0x35c,
- .shift = 0,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 30,
+ },
+ .la = {
+ .reg = 0x35c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
.fifo_size = 16 * 4,
}, {
.id = 0x3f,
.name = "vdedbgw",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x22c,
- .bit = 31,
- },
- .la = {
- .reg = 0x35c,
- .shift = 16,
- .mask = 0xff,
- .def = 0xff,
+ .regs = {
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 31,
+ },
+ .la = {
+ .reg = 0x35c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
},
.fifo_size = 16 * 16,
}, {
.id = 0x40,
.name = "vdembew",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x230,
- .bit = 0,
- },
- .la = {
- .reg = 0x360,
- .shift = 0,
- .mask = 0xff,
- .def = 0x42,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 0,
+ },
+ .la = {
+ .reg = 0x360,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x42,
+ },
},
.fifo_size = 16 * 2,
}, {
.id = 0x41,
.name = "vdetpmw",
.swgroup = TEGRA_SWGROUP_VDE,
- .smmu = {
- .reg = 0x230,
- .bit = 1,
- },
- .la = {
- .reg = 0x360,
- .shift = 16,
- .mask = 0xff,
- .def = 0x2a,
+ .regs = {
+ .smmu = {
+ .reg = 0x230,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x360,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x2a,
+ },
},
.fifo_size = 16 * 16,
},
@@ -1089,7 +1221,6 @@ static void tegra30_mc_tune_client_latency(struct tegra_mc *mc,
unsigned int bandwidth_mbytes_sec)
{
u32 arb_tolerance_compensation_nsec, arb_tolerance_compensation_div;
- const struct tegra_mc_la *la = &client->la;
unsigned int fifo_size = client->fifo_size;
u32 arb_nsec, la_ticks, value;
@@ -1149,12 +1280,12 @@ static void tegra30_mc_tune_client_latency(struct tegra_mc *mc,
* request.
*/
la_ticks = arb_nsec / mc->tick;
- la_ticks = min(la_ticks, la->mask);
+ la_ticks = min(la_ticks, client->regs.la.mask);
- value = mc_readl(mc, la->reg);
- value &= ~(la->mask << la->shift);
- value |= la_ticks << la->shift;
- mc_writel(mc, value, la->reg);
+ value = mc_readl(mc, client->regs.la.reg);
+ value &= ~(client->regs.la.mask << client->regs.la.shift);
+ value |= la_ticks << client->regs.la.shift;
+ mc_writel(mc, value, client->regs.la.reg);
}
static int tegra30_mc_icc_set(struct icc_node *src, struct icc_node *dst)
@@ -1268,4 +1399,5 @@ const struct tegra_mc_soc tegra30_mc_soc = {
.resets = tegra30_mc_resets,
.num_resets = ARRAY_SIZE(tegra30_mc_resets),
.icc_ops = &tegra30_mc_icc_ops,
+ .ops = &tegra30_mc_ops,
};
diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c
index 8004dd64d09a..4a4573fa7b0f 100644
--- a/drivers/memstick/core/ms_block.c
+++ b/drivers/memstick/core/ms_block.c
@@ -129,7 +129,7 @@ static int msb_sg_compare_to_buffer(struct scatterlist *sg,
* Each zone consists of 512 eraseblocks, out of which in first
* zone 494 are used and 496 are for all following zones.
* Therefore zone #0 hosts blocks 0-493, zone #1 blocks 494-988, etc...
-*/
+ */
static int msb_get_zone_from_lba(int lba)
{
if (lba < 494)
@@ -348,8 +348,9 @@ again:
switch (msb->state) {
case MSB_RP_SEND_BLOCK_ADDRESS:
/* msb_write_regs sometimes "fails" because it needs to update
- the reg window, and thus it returns request for that.
- Then we stay in this state and retry */
+ * the reg window, and thus it returns request for that.
+ * Then we stay in this state and retry
+ */
if (!msb_write_regs(msb,
offsetof(struct ms_register, param),
sizeof(struct ms_param_register),
@@ -368,7 +369,8 @@ again:
case MSB_RP_SEND_INT_REQ:
msb->state = MSB_RP_RECEIVE_INT_REQ_RESULT;
/* If dont actually need to send the int read request (only in
- serial mode), then just fall through */
+ * serial mode), then just fall through
+ */
if (msb_read_int_reg(msb, -1))
return 0;
fallthrough;
@@ -702,7 +704,8 @@ static int h_msb_parallel_switch(struct memstick_dev *card,
case MSB_PS_SWICH_HOST:
/* Set parallel interface on our side + send a dummy request
- to see if card responds */
+ * to see if card responds
+ */
host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PAR4);
memstick_init_req(mrq, MS_TPC_GET_INT, NULL, 1);
msb->state = MSB_PS_CONFIRM;
@@ -821,6 +824,7 @@ static int msb_mark_page_bad(struct msb_data *msb, int pba, int page)
static int msb_erase_block(struct msb_data *msb, u16 pba)
{
int error, try;
+
if (msb->read_only)
return -EROFS;
@@ -997,6 +1001,7 @@ static int msb_write_block(struct msb_data *msb,
u16 pba, u32 lba, struct scatterlist *sg, int offset)
{
int error, current_try = 1;
+
BUG_ON(sg->length < msb->page_size);
if (msb->read_only)
@@ -1045,11 +1050,12 @@ static int msb_write_block(struct msb_data *msb,
error = msb_run_state_machine(msb, h_msb_write_block);
/* Sector we just wrote to is assumed erased since its pba
- was erased. If it wasn't erased, write will succeed
- and will just clear the bits that were set in the block
- thus test that what we have written,
- matches what we expect.
- We do trust the blocks that we erased */
+ * was erased. If it wasn't erased, write will succeed
+ * and will just clear the bits that were set in the block
+ * thus test that what we have written,
+ * matches what we expect.
+ * We do trust the blocks that we erased
+ */
if (!error && (verify_writes ||
!test_bit(pba, msb->erased_blocks_bitmap)))
error = msb_verify_block(msb, pba, sg, offset);
@@ -1493,6 +1499,7 @@ static int msb_ftl_scan(struct msb_data *msb)
static void msb_cache_flush_timer(struct timer_list *t)
{
struct msb_data *msb = from_timer(msb, t, cache_flush_timer);
+
msb->need_flush_cache = true;
queue_work(msb->io_queue, &msb->io_work);
}
@@ -1673,7 +1680,8 @@ static int msb_cache_read(struct msb_data *msb, int lba,
* This table content isn't that importaint,
* One could put here different values, providing that they still
* cover whole disk.
- * 64 MB entry is what windows reports for my 64M memstick */
+ * 64 MB entry is what windows reports for my 64M memstick
+ */
static const struct chs_entry chs_table[] = {
/* size sectors cylynders heads */
@@ -1706,8 +1714,9 @@ static int msb_init_card(struct memstick_dev *card)
return error;
/* Due to a bug in Jmicron driver written by Alex Dubov,
- its serial mode barely works,
- so we switch to parallel mode right away */
+ * its serial mode barely works,
+ * so we switch to parallel mode right away
+ */
if (host->caps & MEMSTICK_CAP_PAR4)
msb_switch_to_parallel(msb);
@@ -2033,6 +2042,7 @@ static blk_status_t msb_queue_rq(struct blk_mq_hw_ctx *hctx,
static int msb_check_card(struct memstick_dev *card)
{
struct msb_data *msb = memstick_get_drvdata(card);
+
return (msb->card_dead == 0);
}
@@ -2110,21 +2120,17 @@ static int msb_init_disk(struct memstick_dev *card)
if (msb->disk_id < 0)
return msb->disk_id;
- msb->disk = alloc_disk(0);
- if (!msb->disk) {
- rc = -ENOMEM;
+ rc = blk_mq_alloc_sq_tag_set(&msb->tag_set, &msb_mq_ops, 2,
+ BLK_MQ_F_SHOULD_MERGE);
+ if (rc)
goto out_release_id;
- }
- msb->queue = blk_mq_init_sq_queue(&msb->tag_set, &msb_mq_ops, 2,
- BLK_MQ_F_SHOULD_MERGE);
- if (IS_ERR(msb->queue)) {
- rc = PTR_ERR(msb->queue);
- msb->queue = NULL;
- goto out_put_disk;
+ msb->disk = blk_mq_alloc_disk(&msb->tag_set, card);
+ if (IS_ERR(msb->disk)) {
+ rc = PTR_ERR(msb->disk);
+ goto out_free_tag_set;
}
-
- msb->queue->queuedata = card;
+ msb->queue = msb->disk->queue;
blk_queue_max_hw_sectors(msb->queue, MS_BLOCK_MAX_PAGES);
blk_queue_max_segments(msb->queue, MS_BLOCK_MAX_SEGS);
@@ -2135,8 +2141,6 @@ static int msb_init_disk(struct memstick_dev *card)
sprintf(msb->disk->disk_name, "msblk%d", msb->disk_id);
msb->disk->fops = &msb_bdops;
msb->disk->private_data = msb;
- msb->disk->queue = msb->queue;
- msb->disk->flags |= GENHD_FL_EXT_DEVT;
capacity = msb->pages_in_block * msb->logical_block_count;
capacity *= (msb->page_size / 512);
@@ -2156,8 +2160,8 @@ static int msb_init_disk(struct memstick_dev *card)
dbg("Disk added");
return 0;
-out_put_disk:
- put_disk(msb->disk);
+out_free_tag_set:
+ blk_mq_free_tag_set(&msb->tag_set);
out_release_id:
mutex_lock(&msb_disk_lock);
idr_remove(&msb_disk_idr, msb->disk_id);
@@ -2333,6 +2337,7 @@ static struct memstick_driver msb_driver = {
static int __init msb_init(void)
{
int rc = memstick_register_driver(&msb_driver);
+
if (rc)
pr_err("failed to register memstick driver (error %d)\n", rc);
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index cf7fe0d58ee7..22778d0e24f5 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -1205,21 +1205,17 @@ static int mspro_block_init_disk(struct memstick_dev *card)
if (disk_id < 0)
return disk_id;
- msb->disk = alloc_disk(1 << MSPRO_BLOCK_PART_SHIFT);
- if (!msb->disk) {
- rc = -ENOMEM;
+ rc = blk_mq_alloc_sq_tag_set(&msb->tag_set, &mspro_mq_ops, 2,
+ BLK_MQ_F_SHOULD_MERGE);
+ if (rc)
goto out_release_id;
- }
- msb->queue = blk_mq_init_sq_queue(&msb->tag_set, &mspro_mq_ops, 2,
- BLK_MQ_F_SHOULD_MERGE);
- if (IS_ERR(msb->queue)) {
- rc = PTR_ERR(msb->queue);
- msb->queue = NULL;
- goto out_put_disk;
+ msb->disk = blk_mq_alloc_disk(&msb->tag_set, card);
+ if (IS_ERR(msb->disk)) {
+ rc = PTR_ERR(msb->disk);
+ goto out_free_tag_set;
}
-
- msb->queue->queuedata = card;
+ msb->queue = msb->disk->queue;
blk_queue_max_hw_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES);
blk_queue_max_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS);
@@ -1228,10 +1224,10 @@ static int mspro_block_init_disk(struct memstick_dev *card)
msb->disk->major = major;
msb->disk->first_minor = disk_id << MSPRO_BLOCK_PART_SHIFT;
+ msb->disk->minors = 1 << MSPRO_BLOCK_PART_SHIFT;
msb->disk->fops = &ms_block_bdops;
msb->usage_count = 1;
msb->disk->private_data = msb;
- msb->disk->queue = msb->queue;
sprintf(msb->disk->disk_name, "mspblk%d", disk_id);
@@ -1247,8 +1243,8 @@ static int mspro_block_init_disk(struct memstick_dev *card)
msb->active = 1;
return 0;
-out_put_disk:
- put_disk(msb->disk);
+out_free_tag_set:
+ blk_mq_free_tag_set(&msb->tag_set);
out_release_id:
mutex_lock(&mspro_block_disk_lock);
idr_remove(&mspro_block_disk_idr, disk_id);
diff --git a/drivers/memstick/host/rtsx_usb_ms.c b/drivers/memstick/host/rtsx_usb_ms.c
index 102dbb8080da..29271ad4728a 100644
--- a/drivers/memstick/host/rtsx_usb_ms.c
+++ b/drivers/memstick/host/rtsx_usb_ms.c
@@ -799,9 +799,9 @@ static int rtsx_usb_ms_drv_probe(struct platform_device *pdev)
return 0;
err_out:
- memstick_free_host(msh);
pm_runtime_disable(ms_dev(host));
pm_runtime_put_noidle(ms_dev(host));
+ memstick_free_host(msh);
return err;
}
@@ -828,9 +828,6 @@ static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
}
mutex_unlock(&host->host_mutex);
- memstick_remove_host(msh);
- memstick_free_host(msh);
-
/* Balance possible unbalanced usage count
* e.g. unconditional module removal
*/
@@ -838,10 +835,11 @@ static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
pm_runtime_put(ms_dev(host));
pm_runtime_disable(ms_dev(host));
- platform_set_drvdata(pdev, NULL);
-
+ memstick_remove_host(msh);
dev_dbg(ms_dev(host),
": Realtek USB Memstick controller has been removed\n");
+ memstick_free_host(msh);
+ platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index f4f89cf23631..7f7abc9069f7 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -6993,8 +6993,6 @@ mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
ioc->ioc_reset_in_progress = 1;
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
- rc = -1;
-
for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
if (MptResetHandlers[cb_idx])
mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index 0484e9c15c09..572333fadd68 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -331,8 +331,8 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
break;
data_sz = hdr.PageLength * 4;
- ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz,
- &page0_dma);
+ ppage0_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz,
+ &page0_dma, GFP_KERNEL);
rc = -ENOMEM;
if (!ppage0_alloc)
break;
@@ -367,8 +367,8 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
*p_p0 = *ppage0_alloc; /* save data */
*p_pp0++ = p_p0++; /* save addr */
}
- pci_free_consistent(ioc->pcidev, data_sz,
- (u8 *) ppage0_alloc, page0_dma);
+ dma_free_coherent(&ioc->pcidev->dev, data_sz,
+ ppage0_alloc, page0_dma);
if (rc != 0)
break;
@@ -763,7 +763,8 @@ mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
data_sz = hdr.PageLength * 4;
rc = -ENOMEM;
- ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
+ ppage0_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz,
+ &page0_dma, GFP_KERNEL);
if (ppage0_alloc) {
try_again:
@@ -817,7 +818,8 @@ mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
mptfc_display_port_link_speed(ioc, portnum, pp0dest);
}
- pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
+ dma_free_coherent(&ioc->pcidev->dev, data_sz, ppage0_alloc,
+ page0_dma);
}
return rc;
@@ -904,9 +906,8 @@ start_over:
if (data_sz < sizeof(FCPortPage1_t))
data_sz = sizeof(FCPortPage1_t);
- page1_alloc = pci_alloc_consistent(ioc->pcidev,
- data_sz,
- &page1_dma);
+ page1_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz,
+ &page1_dma, GFP_KERNEL);
if (!page1_alloc)
return -ENOMEM;
}
@@ -916,8 +917,8 @@ start_over:
data_sz = ioc->fc_data.fc_port_page1[portnum].pg_sz;
if (hdr.PageLength * 4 > data_sz) {
ioc->fc_data.fc_port_page1[portnum].data = NULL;
- pci_free_consistent(ioc->pcidev, data_sz, (u8 *)
- page1_alloc, page1_dma);
+ dma_free_coherent(&ioc->pcidev->dev, data_sz,
+ page1_alloc, page1_dma);
goto start_over;
}
}
@@ -932,8 +933,8 @@ start_over:
}
else {
ioc->fc_data.fc_port_page1[portnum].data = NULL;
- pci_free_consistent(ioc->pcidev, data_sz, (u8 *)
- page1_alloc, page1_dma);
+ dma_free_coherent(&ioc->pcidev->dev, data_sz, page1_alloc,
+ page1_dma);
}
return rc;
@@ -1514,10 +1515,10 @@ static void mptfc_remove(struct pci_dev *pdev)
for (ii=0; ii<ioc->facts.NumberOfPorts; ii++) {
if (ioc->fc_data.fc_port_page1[ii].data) {
- pci_free_consistent(ioc->pcidev,
- ioc->fc_data.fc_port_page1[ii].pg_sz,
- (u8 *) ioc->fc_data.fc_port_page1[ii].data,
- ioc->fc_data.fc_port_page1[ii].dma);
+ dma_free_coherent(&ioc->pcidev->dev,
+ ioc->fc_data.fc_port_page1[ii].pg_sz,
+ ioc->fc_data.fc_port_page1[ii].data,
+ ioc->fc_data.fc_port_page1[ii].dma);
ioc->fc_data.fc_port_page1[ii].data = NULL;
}
}
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index e0a65a348502..85285ba8e817 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -86,7 +86,7 @@ MODULE_PARM_DESC(mpt_pt_clear,
" Clear persistency table: enable=1 "
"(default=MPTSCSIH_PT_CLEAR=0)");
-/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
+/* scsi-mid layer global parameter is max_report_luns, which is 511 */
#define MPTSAS_MAX_LUN (16895)
static int max_lun = MPTSAS_MAX_LUN;
module_param(max_lun, int, 0);
@@ -420,12 +420,14 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
}
/**
- * mptsas_find_portinfo_by_sas_address -
+ * mptsas_find_portinfo_by_sas_address - find and return portinfo for
+ * this sas_address
* @ioc: Pointer to MPT_ADAPTER structure
- * @handle:
+ * @sas_address: expander sas address
*
- * This function should be called with the sas_topology_mutex already held
+ * This function should be called with the sas_topology_mutex already held.
*
+ * Return: %NULL if not found.
**/
static struct mptsas_portinfo *
mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
@@ -567,12 +569,14 @@ starget)
}
/**
- * mptsas_add_device_component -
+ * mptsas_add_device_component - adds a new device component to our lists
* @ioc: Pointer to MPT_ADAPTER structure
- * @channel: fw mapped id's
- * @id:
- * @sas_address:
- * @device_info:
+ * @channel: channel number
+ * @id: Logical Target ID for reset (if appropriate)
+ * @sas_address: expander sas address
+ * @device_info: specific bits (flags) for devices
+ * @slot: enclosure slot ID
+ * @enclosure_logical_id: enclosure WWN
*
**/
static void
@@ -634,10 +638,10 @@ mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
}
/**
- * mptsas_add_device_component_by_fw -
+ * mptsas_add_device_component_by_fw - adds a new device component by FW ID
* @ioc: Pointer to MPT_ADAPTER structure
- * @channel: fw mapped id's
- * @id:
+ * @channel: channel number
+ * @id: Logical Target ID
*
**/
static void
@@ -668,8 +672,7 @@ mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
/**
* mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list
* @ioc: Pointer to MPT_ADAPTER structure
- * @channel: fw mapped id's
- * @id:
+ * @starget: SCSI target for this SCSI device
*
**/
static void
@@ -771,9 +774,9 @@ mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
}
/**
- * mptsas_add_device_component_starget -
+ * mptsas_add_device_component_starget - adds a SCSI target device component
* @ioc: Pointer to MPT_ADAPTER structure
- * @starget:
+ * @starget: SCSI target for this SCSI device
*
**/
static void
@@ -806,7 +809,7 @@ mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
* mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached
* @ioc: Pointer to MPT_ADAPTER structure
* @channel: os mapped id's
- * @id:
+ * @id: Logical Target ID
*
**/
static void
@@ -978,11 +981,12 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
}
/**
- * csmisas_find_vtarget
+ * mptsas_find_vtarget - find a virtual target device (FC LUN device or
+ * SCSI target device)
*
- * @ioc
- * @volume_id
- * @volume_bus
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @channel: channel number
+ * @id: Logical Target ID
*
**/
static VirtTarget *
@@ -1047,15 +1051,14 @@ mptsas_queue_rescan(MPT_ADAPTER *ioc)
/**
- * mptsas_target_reset
- *
- * Issues TARGET_RESET to end device using handshaking method
+ * mptsas_target_reset - Issues TARGET_RESET to end device using
+ * handshaking method
*
- * @ioc
- * @channel
- * @id
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @channel: channel number
+ * @id: Logical Target ID for reset
*
- * Returns (1) success
+ * Return: (1) success
* (0) failure
*
**/
@@ -1119,15 +1122,15 @@ mptsas_block_io_starget(struct scsi_target *starget)
}
/**
- * mptsas_target_reset_queue
+ * mptsas_target_reset_queue - queue a target reset
*
- * Receive request for TARGET_RESET after receiving an firmware
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @sas_event_data: SAS Device Status Change Event data
+ *
+ * Receive request for TARGET_RESET after receiving a firmware
* event NOT_RESPONDING_EVENT, then put command in link list
* and queue if task_queue already in use.
*
- * @ioc
- * @sas_event_data
- *
**/
static void
mptsas_target_reset_queue(MPT_ADAPTER *ioc,
@@ -1207,9 +1210,11 @@ mptsas_schedule_target_reset(void *iocp)
/**
* mptsas_taskmgmt_complete - complete SAS task management function
* @ioc: Pointer to MPT_ADAPTER structure
+ * @mf: MPT message frame
+ * @mr: SCSI Task Management Reply structure ptr (may be %NULL)
*
* Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
- * queue to finish off removing device from upper layers. then send next
+ * queue to finish off removing device from upper layers, then send next
* TARGET_RESET in the queue.
**/
static int
@@ -1300,10 +1305,10 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
}
/**
- * mptscsih_ioc_reset
+ * mptsas_ioc_reset - issue an IOC reset for this reset phase
*
- * @ioc
- * @reset_phase
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @reset_phase: id of phase of reset
*
**/
static int
@@ -1350,7 +1355,7 @@ mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
/**
- * enum device_state -
+ * enum device_state - TUR device state
* @DEVICE_RETRY: need to retry the TUR
* @DEVICE_ERROR: TUR return error, don't add device
* @DEVICE_READY: device can be added
@@ -1941,7 +1946,7 @@ mptsas_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt)
}
/**
- * mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout
+ * mptsas_eh_timed_out - resets the scsi_cmnd timeout
* if the device under question is currently in the
* device removal delay.
* @sc: scsi command that the midlayer is about to time out
@@ -2839,14 +2844,15 @@ struct rep_manu_reply{
};
/**
- * mptsas_exp_repmanufacture_info -
+ * mptsas_exp_repmanufacture_info - sets expander manufacturer info
* @ioc: per adapter object
* @sas_address: expander sas address
* @edev: the sas_expander_device object
*
- * Fills in the sas_expander_device object when SMP port is created.
+ * For an edge expander or a fanout expander:
+ * fills in the sas_expander_device object when SMP port is created.
*
- * Returns 0 for success, non-zero for failure.
+ * Return: 0 for success, non-zero for failure.
*/
static int
mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
@@ -3284,7 +3290,7 @@ static int mptsas_probe_one_phy(struct device *dev,
rphy_to_expander_device(rphy));
}
- /* If the device exists,verify it wasn't previously flagged
+ /* If the device exists, verify it wasn't previously flagged
as a missing device. If so, clear it */
vtarget = mptsas_find_vtarget(ioc,
phy_info->attached.channel,
@@ -3611,8 +3617,7 @@ static void mptsas_expander_delete(MPT_ADAPTER *ioc,
/**
* mptsas_send_expander_event - expanders events
- * @ioc: Pointer to MPT_ADAPTER structure
- * @expander_data: event data
+ * @fw_event: event data
*
*
* This function handles adding, removing, and refreshing
@@ -3657,9 +3662,9 @@ mptsas_send_expander_event(struct fw_event_work *fw_event)
/**
- * mptsas_expander_add -
+ * mptsas_expander_add - adds a newly discovered expander
* @ioc: Pointer to MPT_ADAPTER structure
- * @handle:
+ * @handle: device handle
*
*/
static struct mptsas_portinfo *
@@ -4000,9 +4005,9 @@ mptsas_probe_devices(MPT_ADAPTER *ioc)
}
/**
- * mptsas_scan_sas_topology -
+ * mptsas_scan_sas_topology - scans new SAS topology
+ * (part of probe or rescan)
* @ioc: Pointer to MPT_ADAPTER structure
- * @sas_address:
*
**/
static void
@@ -4150,11 +4155,12 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
}
/**
- * mptsas_find_phyinfo_by_phys_disk_num -
+ * mptsas_find_phyinfo_by_phys_disk_num - find phyinfo for the
+ * specified @phys_disk_num
* @ioc: Pointer to MPT_ADAPTER structure
- * @phys_disk_num:
- * @channel:
- * @id:
+ * @phys_disk_num: (hot plug) physical disk number (for RAID support)
+ * @channel: channel number
+ * @id: Logical Target ID
*
**/
static struct mptsas_phyinfo *
@@ -4773,8 +4779,9 @@ mptsas_send_raid_event(struct fw_event_work *fw_event)
* @lun: Logical unit for reset (if appropriate)
* @task_context: Context for the task to be aborted
* @timeout: timeout for task management control
+ * @issue_reset: set to 1 on return if reset is needed, else 0
*
- * return 0 on success and -1 on failure:
+ * Return: 0 on success or -1 on failure.
*
*/
static int
@@ -4847,9 +4854,9 @@ mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
/**
* mptsas_broadcast_primitive_work - Handle broadcast primitives
- * @work: work queue payload containing info describing the event
+ * @fw_event: work queue payload containing info describing the event
*
- * this will be handled in workqueue context.
+ * This will be handled in workqueue context.
*/
static void
mptsas_broadcast_primitive_work(struct fw_event_work *fw_event)
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c
index c7f964996a91..eaf9845633b4 100644
--- a/drivers/mfd/88pm800.c
+++ b/drivers/mfd/88pm800.c
@@ -122,12 +122,7 @@ static const struct i2c_device_id pm80x_id_table[] = {
MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
static const struct resource rtc_resources[] = {
- {
- .name = "88pm80x-rtc",
- .start = PM800_IRQ_RTC,
- .end = PM800_IRQ_RTC,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(PM800_IRQ_RTC, "88pm80x-rtc"),
};
static struct mfd_cell rtc_devs[] = {
@@ -140,12 +135,7 @@ static struct mfd_cell rtc_devs[] = {
};
static struct resource onkey_resources[] = {
- {
- .name = "88pm80x-onkey",
- .start = PM800_IRQ_ONKEY,
- .end = PM800_IRQ_ONKEY,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(PM800_IRQ_ONKEY, "88pm80x-onkey"),
};
static const struct mfd_cell onkey_devs[] = {
diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c
index 39f2302e137b..ada6c513302b 100644
--- a/drivers/mfd/88pm805.c
+++ b/drivers/mfd/88pm805.c
@@ -54,27 +54,14 @@ enum {
};
static struct resource codec_resources[] = {
- {
- /* Headset microphone insertion or removal */
- .name = "micin",
- .start = PM805_IRQ_MIC_DET,
- .end = PM805_IRQ_MIC_DET,
- .flags = IORESOURCE_IRQ,
- },
- {
- /* Audio short HP1 */
- .name = "audio-short1",
- .start = PM805_IRQ_HP1_SHRT,
- .end = PM805_IRQ_HP1_SHRT,
- .flags = IORESOURCE_IRQ,
- },
- {
- /* Audio short HP2 */
- .name = "audio-short2",
- .start = PM805_IRQ_HP2_SHRT,
- .end = PM805_IRQ_HP2_SHRT,
- .flags = IORESOURCE_IRQ,
- },
+ /* Headset microphone insertion or removal */
+ DEFINE_RES_IRQ_NAMED(PM805_IRQ_MIC_DET, "micin"),
+
+ /* Audio short HP1 */
+ DEFINE_RES_IRQ_NAMED(PM805_IRQ_HP1_SHRT, "audio-short1"),
+
+ /* Audio short HP2 */
+ DEFINE_RES_IRQ_NAMED(PM805_IRQ_HP2_SHRT, "audio-short2"),
};
static const struct mfd_cell codec_devs[] = {
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 5c7f2b100191..6a3fd2d75f96 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -465,6 +465,7 @@ config MFD_MP2629
tristate "Monolithic Power Systems MP2629 ADC and Battery charger"
depends on I2C
select REGMAP_I2C
+ select MFD_CORE
help
Select this option to enable support for Monolithic Power Systems
battery charger. This provides ADC, thermal and battery charger power
@@ -902,6 +903,7 @@ config MFD_MT6360
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
+ select CRC8
depends on I2C
help
Say Y here to enable MT6360 PMU/PMIC/LDO functional support.
@@ -1076,6 +1078,16 @@ config MFD_RDC321X
southbridge which provides access to GPIOs and Watchdog using the
southbridge PCI device configuration space.
+config MFD_RT4831
+ tristate "Richtek RT4831 four channel WLED and Display Bias Voltage"
+ depends on I2C
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ This enables support for the Richtek RT4831 that includes 4 channel
+ WLED driving and Display Bias Voltage. It's commonly used to provide
+ power to the LCD display and LCD backlight.
+
config MFD_RT5033
tristate "Richtek RT5033 Power Management IC"
depends on I2C
@@ -1133,6 +1145,7 @@ config MFD_RN5T618
config MFD_SEC_CORE
tristate "Samsung Electronics PMIC Series Support"
depends on I2C=y
+ depends on OF || COMPILE_TEST
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
@@ -1499,24 +1512,6 @@ config MFD_TPS65217
This driver can also be built as a module. If so, the module
will be called tps65217.
-config MFD_TPS68470
- bool "TI TPS68470 Power Management / LED chips"
- depends on ACPI && PCI && I2C=y
- depends on I2C_DESIGNWARE_PLATFORM=y
- select MFD_CORE
- select REGMAP_I2C
- help
- If you say yes here you get support for the TPS68470 series of
- Power Management / LED chips.
-
- These include voltage regulators, LEDs and other features
- that are often used in portable devices.
-
- This option is a bool as it provides an ACPI operation
- region, which must be available before any of the devices
- using this are probed. This option also configures the
- designware-i2c driver to be built-in, for the same reason.
-
config MFD_TI_LP873X
tristate "TI LP873X Power Management IC"
depends on I2C
@@ -1788,7 +1783,7 @@ config MFD_ARIZONA
select REGMAP
select REGMAP_IRQ
select MFD_CORE
- bool
+ tristate
config MFD_ARIZONA_I2C
tristate "Cirrus Logic/Wolfson Microelectronics Arizona platform with I2C"
@@ -2105,6 +2100,20 @@ config MFD_ACER_A500_EC
The controller itself is ENE KB930, it is running firmware
customized for the specific needs of the Acer A500 hardware.
+config MFD_QCOM_PM8008
+ tristate "QCOM PM8008 Power Management IC"
+ depends on I2C && OF
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ help
+ Select this option to get support for the Qualcomm Technologies, Inc.
+ PM8008 PMIC chip. PM8008 is a dedicated camera PMIC that integrates
+ all the necessary power management, housekeeping, and interface
+ support functions into a single IC. This driver provides common
+ support for accessing the device by instantiating all the child nodes
+ under it in the device tree. Additional drivers must be enabled in
+ order to use the functionality of the device.
+
menu "Multimedia Capabilities Port drivers"
depends on ARCH_SA1100
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 4f6d2b8a5f76..8116c19d5fd4 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -41,24 +41,24 @@ obj-$(CONFIG_MFD_TQMX86) += tqmx86.o
obj-$(CONFIG_MFD_LOCHNAGAR) += lochnagar-i2c.o
-obj-$(CONFIG_MFD_ARIZONA) += arizona-core.o
-obj-$(CONFIG_MFD_ARIZONA) += arizona-irq.o
+arizona-objs := arizona-core.o arizona-irq.o
+obj-$(CONFIG_MFD_ARIZONA) += arizona.o
obj-$(CONFIG_MFD_ARIZONA_I2C) += arizona-i2c.o
obj-$(CONFIG_MFD_ARIZONA_SPI) += arizona-spi.o
ifeq ($(CONFIG_MFD_WM5102),y)
-obj-$(CONFIG_MFD_ARIZONA) += wm5102-tables.o
+arizona-objs += wm5102-tables.o
endif
ifeq ($(CONFIG_MFD_WM5110),y)
-obj-$(CONFIG_MFD_ARIZONA) += wm5110-tables.o
+arizona-objs += wm5110-tables.o
endif
ifeq ($(CONFIG_MFD_WM8997),y)
-obj-$(CONFIG_MFD_ARIZONA) += wm8997-tables.o
+arizona-objs += wm8997-tables.o
endif
ifeq ($(CONFIG_MFD_WM8998),y)
-obj-$(CONFIG_MFD_ARIZONA) += wm8998-tables.o
+arizona-objs += wm8998-tables.o
endif
ifeq ($(CONFIG_MFD_CS47L24),y)
-obj-$(CONFIG_MFD_ARIZONA) += cs47l24-tables.o
+arizona-objs += cs47l24-tables.o
endif
obj-$(CONFIG_MFD_WCD934X) += wcd934x.o
obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
@@ -105,7 +105,6 @@ obj-$(CONFIG_MFD_TPS65910) += tps65910.o
obj-$(CONFIG_MFD_TPS65912) += tps65912-core.o
obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o
obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o
-obj-$(CONFIG_MFD_TPS68470) += tps68470.o
obj-$(CONFIG_MFD_TPS80031) += tps80031.o
obj-$(CONFIG_MENELAUS) += menelaus.o
@@ -234,6 +233,7 @@ obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o
obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o
obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o
obj-$(CONFIG_MFD_DLN2) += dln2.o
+obj-$(CONFIG_MFD_RT4831) += rt4831.o
obj-$(CONFIG_MFD_RT5033) += rt5033.o
obj-$(CONFIG_MFD_SKY81452) += sky81452.o
@@ -264,6 +264,7 @@ obj-$(CONFIG_MFD_ROHM_BD957XMUF) += rohm-bd9576.o
obj-$(CONFIG_MFD_STMFX) += stmfx.o
obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o
obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o
+obj-$(CONFIG_MFD_QCOM_PM8008) += qcom-pm8008.o
obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index c2ba498ad302..30489670ea52 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -827,8 +827,8 @@ static const struct mfd_cell ab8540_cut2_devs[] = {
},
};
-static ssize_t show_chip_id(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t chip_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct ab8500 *ab8500;
@@ -848,8 +848,8 @@ static ssize_t show_chip_id(struct device *dev,
* 0x40 Power on key 1 pressed longer than 10 seconds
* 0x80 DB8500 thermal shutdown
*/
-static ssize_t show_switch_off_status(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t switch_off_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
int ret;
u8 value;
@@ -883,8 +883,8 @@ void ab8500_override_turn_on_stat(u8 mask, u8 set)
* 0x40 UsbIDDetect
* 0x80 Reserved
*/
-static ssize_t show_turn_on_status(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t turn_on_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
int ret;
u8 value;
@@ -912,8 +912,8 @@ static ssize_t show_turn_on_status(struct device *dev,
return sprintf(buf, "%#x\n", value);
}
-static ssize_t show_turn_on_status_2(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t turn_on_status_2_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
int ret;
u8 value;
@@ -927,8 +927,8 @@ static ssize_t show_turn_on_status_2(struct device *dev,
return sprintf(buf, "%#x\n", (value & 0x1));
}
-static ssize_t show_ab9540_dbbrstn(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t dbbrstn_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct ab8500 *ab8500;
int ret;
@@ -945,7 +945,7 @@ static ssize_t show_ab9540_dbbrstn(struct device *dev,
(value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
}
-static ssize_t store_ab9540_dbbrstn(struct device *dev,
+static ssize_t dbbrstn_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct ab8500 *ab8500;
@@ -980,12 +980,11 @@ exit:
return ret;
}
-static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
-static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
-static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
-static DEVICE_ATTR(turn_on_status_2, S_IRUGO, show_turn_on_status_2, NULL);
-static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
- show_ab9540_dbbrstn, store_ab9540_dbbrstn);
+static DEVICE_ATTR_RO(chip_id);
+static DEVICE_ATTR_RO(switch_off_status);
+static DEVICE_ATTR_RO(turn_on_status);
+static DEVICE_ATTR_RO(turn_on_status_2);
+static DEVICE_ATTR_RW(dbbrstn);
static struct attribute *ab8500_sysfs_entries[] = {
&dev_attr_chip_id.attr,
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index ce6fe6de34f8..9323b1e3a69e 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -1447,3 +1447,5 @@ int arizona_dev_exit(struct arizona *arizona)
return 0;
}
EXPORT_SYMBOL_GPL(arizona_dev_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/as3722.c b/drivers/mfd/as3722.c
index 59dfeff71592..38665efae4f0 100644
--- a/drivers/mfd/as3722.c
+++ b/drivers/mfd/as3722.c
@@ -24,21 +24,11 @@
#define AS3722_DEVICE_ID 0x0C
static const struct resource as3722_rtc_resource[] = {
- {
- .name = "as3722-rtc-alarm",
- .start = AS3722_IRQ_RTC_ALARM,
- .end = AS3722_IRQ_RTC_ALARM,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(AS3722_IRQ_RTC_ALARM, "as3722-rtc-alarm"),
};
static const struct resource as3722_adc_resource[] = {
- {
- .name = "as3722-adc",
- .start = AS3722_IRQ_ADC,
- .end = AS3722_IRQ_ADC,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(AS3722_IRQ_ADC, "as3722-adc"),
};
static const struct mfd_cell as3722_devs[] = {
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index a6bd2134cea2..8d58c8df46cf 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -723,16 +723,8 @@ static struct tmio_mmc_data asic3_mmc_data = {
};
static struct resource asic3_mmc_resources[] = {
- {
- .start = ASIC3_SD_CTRL_BASE,
- .end = ASIC3_SD_CTRL_BASE + 0x3ff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = 0,
- .end = 0,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_MEM(ASIC3_SD_CTRL_BASE, 0x400),
+ DEFINE_RES_IRQ(0)
};
static int asic3_mmc_enable(struct platform_device *pdev)
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 3eae04e24ac8..4145a38b3890 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -884,8 +884,13 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
axp20x->regmap_irq_chip = &axp803_regmap_irq_chip;
break;
case AXP806_ID:
+ /*
+ * Don't register the power key part if in slave mode or
+ * if there is no interrupt line.
+ */
if (of_property_read_bool(axp20x->dev->of_node,
- "x-powers,self-working-mode")) {
+ "x-powers,self-working-mode") &&
+ axp20x->irq > 0) {
axp20x->nr_cells = ARRAY_SIZE(axp806_self_working_cells);
axp20x->cells = axp806_self_working_cells;
} else {
@@ -959,12 +964,17 @@ int axp20x_device_probe(struct axp20x_dev *axp20x)
AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE);
}
- ret = regmap_add_irq_chip(axp20x->regmap, axp20x->irq,
- IRQF_ONESHOT | IRQF_SHARED | axp20x->irq_flags,
- -1, axp20x->regmap_irq_chip, &axp20x->regmap_irqc);
- if (ret) {
- dev_err(axp20x->dev, "failed to add irq chip: %d\n", ret);
- return ret;
+ /* Only if there is an interrupt line connected towards the CPU. */
+ if (axp20x->irq > 0) {
+ ret = regmap_add_irq_chip(axp20x->regmap, axp20x->irq,
+ IRQF_ONESHOT | IRQF_SHARED | axp20x->irq_flags,
+ -1, axp20x->regmap_irq_chip,
+ &axp20x->regmap_irqc);
+ if (ret) {
+ dev_err(axp20x->dev, "failed to add irq chip: %d\n",
+ ret);
+ return ret;
+ }
}
ret = mfd_add_devices(axp20x->dev, -1, axp20x->cells,
diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c
index d07b43d7c761..8c08d1c55726 100644
--- a/drivers/mfd/cros_ec_dev.c
+++ b/drivers/mfd/cros_ec_dev.c
@@ -5,6 +5,7 @@
* Copyright (C) 2014 Google, Inc.
*/
+#include <linux/dmi.h>
#include <linux/kconfig.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
@@ -112,8 +113,12 @@ static const struct cros_feature_to_cells cros_subdevices[] = {
static const struct mfd_cell cros_ec_platform_cells[] = {
{ .name = "cros-ec-chardev", },
{ .name = "cros-ec-debugfs", },
- { .name = "cros-ec-lightbar", },
{ .name = "cros-ec-sysfs", },
+ { .name = "cros-ec-pchg", },
+};
+
+static const struct mfd_cell cros_ec_lightbar_cells[] = {
+ { .name = "cros-ec-lightbar", }
};
static const struct mfd_cell cros_ec_vbc_cells[] = {
@@ -207,6 +212,20 @@ static int ec_device_probe(struct platform_device *pdev)
}
/*
+ * Lightbar is a special case. Newer devices support autodetection,
+ * but older ones do not.
+ */
+ if (cros_ec_check_features(ec, EC_FEATURE_LIGHTBAR) ||
+ dmi_match(DMI_PRODUCT_NAME, "Link")) {
+ retval = mfd_add_hotplug_devices(ec->dev,
+ cros_ec_lightbar_cells,
+ ARRAY_SIZE(cros_ec_lightbar_cells));
+ if (retval)
+ dev_warn(ec->dev, "failed to add lightbar: %d\n",
+ retval);
+ }
+
+ /*
* The PD notifier driver cell is separate since it only needs to be
* explicitly added on platforms that don't have the PD notifier ACPI
* device entry defined.
diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c
index 47556d2d9abe..8de93db35f3a 100644
--- a/drivers/mfd/da9052-i2c.c
+++ b/drivers/mfd/da9052-i2c.c
@@ -113,6 +113,7 @@ static const struct i2c_device_id da9052_i2c_id[] = {
{"da9053-bc", DA9053_BC},
{}
};
+MODULE_DEVICE_TABLE(i2c, da9052_i2c_id);
#ifdef CONFIG_OF
static const struct of_device_id dialog_dt_ids[] = {
@@ -154,13 +155,8 @@ static int da9052_i2c_probe(struct i2c_client *client,
return ret;
#ifdef CONFIG_OF
- if (!id) {
- struct device_node *np = client->dev.of_node;
- const struct of_device_id *deviceid;
-
- deviceid = of_match_node(dialog_dt_ids, np);
- id = deviceid->data;
- }
+ if (!id)
+ id = of_device_get_match_data(&client->dev);
#endif
if (!id) {
diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c
index d074d213e661..c3bcbd8905c6 100644
--- a/drivers/mfd/da9055-core.c
+++ b/drivers/mfd/da9055-core.c
@@ -254,41 +254,19 @@ const struct regmap_config da9055_regmap_config = {
};
EXPORT_SYMBOL_GPL(da9055_regmap_config);
-static const struct resource da9055_onkey_resource = {
- .name = "ONKEY",
- .start = DA9055_IRQ_NONKEY,
- .end = DA9055_IRQ_NONKEY,
- .flags = IORESOURCE_IRQ,
-};
+static const struct resource da9055_onkey_resource =
+ DEFINE_RES_IRQ_NAMED(DA9055_IRQ_NONKEY, "ONKEY");
static const struct resource da9055_rtc_resource[] = {
- {
- .name = "ALM",
- .start = DA9055_IRQ_ALARM,
- .end = DA9055_IRQ_ALARM,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "TICK",
- .start = DA9055_IRQ_TICK,
- .end = DA9055_IRQ_TICK,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(DA9055_IRQ_ALARM, "ALM"),
+ DEFINE_RES_IRQ_NAMED(DA9055_IRQ_TICK, "TICK"),
};
-static const struct resource da9055_hwmon_resource = {
- .name = "HWMON",
- .start = DA9055_IRQ_HWMON,
- .end = DA9055_IRQ_HWMON,
- .flags = IORESOURCE_IRQ,
-};
+static const struct resource da9055_hwmon_resource =
+ DEFINE_RES_IRQ_NAMED(DA9055_IRQ_HWMON, "HWMON");
-static const struct resource da9055_ld05_6_resource = {
- .name = "REGULATOR",
- .start = DA9055_IRQ_REGULATOR,
- .end = DA9055_IRQ_REGULATOR,
- .flags = IORESOURCE_IRQ,
-};
+static const struct resource da9055_ld05_6_resource =
+ DEFINE_RES_IRQ_NAMED(DA9055_IRQ_REGULATOR, "REGULATOR");
static const struct mfd_cell da9055_devs[] = {
{
diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c
index 8d913375152d..01f8e10dfa55 100644
--- a/drivers/mfd/da9062-core.c
+++ b/drivers/mfd/da9062-core.c
@@ -9,6 +9,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/interrupt.h>
+#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/irq.h>
#include <linux/mfd/core.h>
@@ -622,7 +623,6 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct da9062 *chip;
- const struct of_device_id *match;
unsigned int irq_base;
const struct mfd_cell *cell;
const struct regmap_irq_chip *irq_chip;
@@ -635,15 +635,10 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
if (!chip)
return -ENOMEM;
- if (i2c->dev.of_node) {
- match = of_match_node(da9062_dt_ids, i2c->dev.of_node);
- if (!match)
- return -EINVAL;
-
- chip->chip_type = (uintptr_t)match->data;
- } else {
+ if (i2c->dev.of_node)
+ chip->chip_type = (uintptr_t)of_device_get_match_data(&i2c->dev);
+ else
chip->chip_type = id->driver_data;
- }
i2c_set_clientdata(i2c, chip);
chip->dev = &i2c->dev;
diff --git a/drivers/mfd/da9063-i2c.c b/drivers/mfd/da9063-i2c.c
index 783a14af18e2..4b7f707b7952 100644
--- a/drivers/mfd/da9063-i2c.c
+++ b/drivers/mfd/da9063-i2c.c
@@ -448,7 +448,7 @@ static int da9063_i2c_probe(struct i2c_client *i2c,
DA9063_TWOWIRE_TO);
if (ret < 0) {
dev_err(da9063->dev, "Failed to set Two-Wire Bus Mode.\n");
- return -EIO;
+ return ret;
}
}
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 167faac9b75b..3bde7fda755f 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -616,7 +616,7 @@ enum romcode_read prcmu_get_rc_p2a(void)
}
/**
- * prcmu_get_current_mode - Return the current XP70 power mode
+ * prcmu_get_xp70_current_state - Return the current XP70 power mode
* Returns: Returns the current AP(ARM) power mode: init,
* apBoot, apExecute, apDeepSleep, apSleep, apIdle, apReset
*/
@@ -898,7 +898,7 @@ unlock_and_return:
}
/**
- * db8500_set_ape_opp - set the appropriate APE OPP
+ * db8500_prcmu_set_ape_opp - set the appropriate APE OPP
* @opp: The new APE operating point to which transition is to be made
* Returns: 0 on success, non-zero on failure
*
@@ -2297,7 +2297,7 @@ u16 db8500_prcmu_get_reset_code(void)
}
/**
- * db8500_prcmu_reset_modem - ask the PRCMU to reset modem
+ * db8500_prcmu_modem_reset - ask the PRCMU to reset modem
*/
void db8500_prcmu_modem_reset(void)
{
diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c
index d3c86a7a3805..6909d075d017 100644
--- a/drivers/mfd/hi655x-pmic.c
+++ b/drivers/mfd/hi655x-pmic.c
@@ -2,7 +2,7 @@
/*
* Device driver for MFD hi655x PMIC
*
- * Copyright (c) 2016 Hisilicon.
+ * Copyright (c) 2016 HiSilicon Ltd.
*
* Authors:
* Chen Feng <puck.chen@hisilicon.com>
diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c
index 79c53617489c..c54d19fb184c 100644
--- a/drivers/mfd/intel-lpss-pci.c
+++ b/drivers/mfd/intel-lpss-pci.c
@@ -310,6 +310,19 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x51ea), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x51eb), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x51fb), (kernel_ulong_t)&bxt_info },
+ /* ADL-M */
+ { PCI_VDEVICE(INTEL, 0x54a8), (kernel_ulong_t)&bxt_uart_info },
+ { PCI_VDEVICE(INTEL, 0x54a9), (kernel_ulong_t)&bxt_uart_info },
+ { PCI_VDEVICE(INTEL, 0x54aa), (kernel_ulong_t)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0x54ab), (kernel_ulong_t)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0x54c5), (kernel_ulong_t)&bxt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x54c6), (kernel_ulong_t)&bxt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x54c7), (kernel_ulong_t)&bxt_uart_info },
+ { PCI_VDEVICE(INTEL, 0x54e8), (kernel_ulong_t)&bxt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x54e9), (kernel_ulong_t)&bxt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x54ea), (kernel_ulong_t)&bxt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x54eb), (kernel_ulong_t)&bxt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x54fb), (kernel_ulong_t)&bxt_info },
/* APL */
{ PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info },
diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c
index 47d0d3a69a58..bc069c4daa60 100644
--- a/drivers/mfd/intel_soc_pmic_bxtwc.c
+++ b/drivers/mfd/intel_soc_pmic_bxtwc.c
@@ -330,14 +330,14 @@ static int regmap_ipc_byte_reg_write(void *context, unsigned int reg,
/* sysfs interfaces to r/w PMIC registers, required by initial script */
static unsigned long bxtwc_reg_addr;
-static ssize_t bxtwc_reg_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t addr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
return sprintf(buf, "0x%lx\n", bxtwc_reg_addr);
}
-static ssize_t bxtwc_reg_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t addr_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
if (kstrtoul(buf, 0, &bxtwc_reg_addr)) {
dev_err(dev, "Invalid register address\n");
@@ -346,8 +346,8 @@ static ssize_t bxtwc_reg_store(struct device *dev,
return (ssize_t)count;
}
-static ssize_t bxtwc_val_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t val_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
int ret;
unsigned int val;
@@ -362,8 +362,8 @@ static ssize_t bxtwc_val_show(struct device *dev,
return sprintf(buf, "0x%02x\n", val);
}
-static ssize_t bxtwc_val_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t val_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
int ret;
unsigned int val;
@@ -382,8 +382,8 @@ static ssize_t bxtwc_val_store(struct device *dev,
return count;
}
-static DEVICE_ATTR(addr, S_IWUSR | S_IRUSR, bxtwc_reg_show, bxtwc_reg_store);
-static DEVICE_ATTR(val, S_IWUSR | S_IRUSR, bxtwc_val_show, bxtwc_val_store);
+static DEVICE_ATTR_ADMIN_RW(addr);
+static DEVICE_ATTR_ADMIN_RW(val);
static struct attribute *bxtwc_attrs[] = {
&dev_attr_addr.attr,
&dev_attr_val.attr,
diff --git a/drivers/mfd/ioc3.c b/drivers/mfd/ioc3.c
index c73ec78f255b..99b9c113f964 100644
--- a/drivers/mfd/ioc3.c
+++ b/drivers/mfd/ioc3.c
@@ -14,6 +14,7 @@
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/pci.h>
diff --git a/drivers/mfd/iqs62x.c b/drivers/mfd/iqs62x.c
index d1fc38a78acb..9805cf191245 100644
--- a/drivers/mfd/iqs62x.c
+++ b/drivers/mfd/iqs62x.c
@@ -998,7 +998,7 @@ static int iqs62x_probe(struct i2c_client *client)
device_property_read_string(&client->dev, "firmware-name", &fw_name);
- ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
fw_name ? : iqs62x->dev_desc->fw_name,
&client->dev, GFP_KERNEL, iqs62x,
iqs62x_firmware_load);
diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c
index 3df4e9a2998f..70eba4ce496f 100644
--- a/drivers/mfd/janz-cmodio.c
+++ b/drivers/mfd/janz-cmodio.c
@@ -149,15 +149,15 @@ static int cmodio_probe_submodules(struct cmodio_device *priv)
* SYSFS Attributes
*/
-static ssize_t mbus_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t modulbus_number_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct cmodio_device *priv = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%x\n", priv->hex);
}
-static DEVICE_ATTR(modulbus_number, S_IRUGO, mbus_show, NULL);
+static DEVICE_ATTR_RO(modulbus_number);
static struct attribute *cmodio_sysfs_attrs[] = {
&dev_attr_modulbus_number.attr,
diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c
index 9166075c1f32..bb26241c73bd 100644
--- a/drivers/mfd/kempld-core.c
+++ b/drivers/mfd/kempld-core.c
@@ -344,16 +344,16 @@ static const char *kempld_get_type_string(struct kempld_device_data *pld)
return version_type;
}
-static ssize_t kempld_version_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t pld_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct kempld_device_data *pld = dev_get_drvdata(dev);
return scnprintf(buf, PAGE_SIZE, "%s\n", pld->info.version);
}
-static ssize_t kempld_specification_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t pld_specification_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct kempld_device_data *pld = dev_get_drvdata(dev);
@@ -361,18 +361,17 @@ static ssize_t kempld_specification_show(struct device *dev,
pld->info.spec_minor);
}
-static ssize_t kempld_type_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t pld_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct kempld_device_data *pld = dev_get_drvdata(dev);
return scnprintf(buf, PAGE_SIZE, "%s\n", kempld_get_type_string(pld));
}
-static DEVICE_ATTR(pld_version, S_IRUGO, kempld_version_show, NULL);
-static DEVICE_ATTR(pld_specification, S_IRUGO, kempld_specification_show,
- NULL);
-static DEVICE_ATTR(pld_type, S_IRUGO, kempld_type_show, NULL);
+static DEVICE_ATTR_RO(pld_version);
+static DEVICE_ATTR_RO(pld_specification);
+static DEVICE_ATTR_RO(pld_type);
static struct attribute *pld_attributes[] = {
&dev_attr_pld_version.attr,
diff --git a/drivers/mfd/lp87565.c b/drivers/mfd/lp87565.c
index 9c21483d9653..a52ab76febb3 100644
--- a/drivers/mfd/lp87565.c
+++ b/drivers/mfd/lp87565.c
@@ -5,6 +5,7 @@
* Author: Keerthy <j-keerthy@ti.com>
*/
+#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
@@ -64,6 +65,24 @@ static int lp87565_probe(struct i2c_client *client,
return ret;
}
+ lp87565->reset_gpio = devm_gpiod_get_optional(lp87565->dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(lp87565->reset_gpio)) {
+ ret = PTR_ERR(lp87565->reset_gpio);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+ }
+
+ if (lp87565->reset_gpio) {
+ gpiod_set_value_cansleep(lp87565->reset_gpio, 1);
+ /* The minimum assertion time is undocumented, just guess */
+ usleep_range(2000, 4000);
+
+ gpiod_set_value_cansleep(lp87565->reset_gpio, 0);
+ /* Min 1.2 ms before first I2C transaction */
+ usleep_range(1500, 3000);
+ }
+
ret = regmap_read(lp87565->regmap, LP87565_REG_OTP_REV, &otpid);
if (ret) {
dev_err(lp87565->dev, "Failed to read OTP ID\n");
@@ -83,6 +102,13 @@ static int lp87565_probe(struct i2c_client *client,
NULL, 0, NULL);
}
+static void lp87565_shutdown(struct i2c_client *client)
+{
+ struct lp87565 *lp87565 = i2c_get_clientdata(client);
+
+ gpiod_set_value_cansleep(lp87565->reset_gpio, 1);
+}
+
static const struct i2c_device_id lp87565_id_table[] = {
{ "lp87565-q1", 0 },
{ },
@@ -95,6 +121,7 @@ static struct i2c_driver lp87565_driver = {
.of_match_table = of_lp87565_match_table,
},
.probe = lp87565_probe,
+ .shutdown = lp87565_shutdown,
.id_table = lp87565_id_table,
};
module_i2c_driver(lp87565_driver);
diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c
index d44baafd9d14..41f566e6a096 100644
--- a/drivers/mfd/max8907.c
+++ b/drivers/mfd/max8907.c
@@ -228,11 +228,9 @@ static int max8907_i2c_probe(struct i2c_client *i2c,
goto err_regmap_rtc;
}
- irq_set_status_flags(max8907->i2c_gen->irq, IRQ_NOAUTOEN);
-
ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq,
- IRQF_ONESHOT | IRQF_SHARED, -1,
- &max8907_chg_irq_chip,
+ IRQF_ONESHOT | IRQF_SHARED,
+ -1, &max8907_chg_irq_chip,
&max8907->irqc_chg);
if (ret != 0) {
dev_err(&i2c->dev, "failed to add chg irq chip: %d\n", ret);
@@ -255,8 +253,6 @@ static int max8907_i2c_probe(struct i2c_client *i2c,
goto err_irqc_rtc;
}
- enable_irq(max8907->i2c_gen->irq);
-
ret = mfd_add_devices(max8907->dev, -1, max8907_cells,
ARRAY_SIZE(max8907_cells), NULL, 0, NULL);
if (ret != 0) {
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
index 68d8f2b95287..2141de78115d 100644
--- a/drivers/mfd/max8997.c
+++ b/drivers/mfd/max8997.c
@@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
@@ -145,11 +146,9 @@ static struct max8997_platform_data *max8997_i2c_parse_dt_pdata(
static inline unsigned long max8997_i2c_get_driver_data(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
- const struct of_device_id *match;
- match = of_match_node(max8997_pmic_dt_match, i2c->dev.of_node);
- return (unsigned long)match->data;
- }
+ if (i2c->dev.of_node)
+ return (unsigned long)of_device_get_match_data(&i2c->dev);
+
return id->driver_data;
}
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c
index 785f8e9841b7..0eb15e611b67 100644
--- a/drivers/mfd/max8998.c
+++ b/drivers/mfd/max8998.c
@@ -12,6 +12,7 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
@@ -155,11 +156,8 @@ static struct max8998_platform_data *max8998_i2c_parse_dt_pdata(
static inline unsigned long max8998_i2c_get_driver_data(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
- const struct of_device_id *match;
- match = of_match_node(max8998_dt_match, i2c->dev.of_node);
- return (unsigned long)match->data;
- }
+ if (i2c->dev.of_node)
+ return (unsigned long)of_device_get_match_data(&i2c->dev);
return id->driver_data;
}
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 6f02b8022c6d..79f5c6a18815 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -266,18 +266,18 @@ static int mfd_add_device(struct device *parent, int id,
if (has_acpi_companion(&pdev->dev)) {
ret = acpi_check_resource_conflict(&res[r]);
if (ret)
- goto fail_of_entry;
+ goto fail_res_conflict;
}
}
}
ret = platform_device_add_resources(pdev, res, cell->num_resources);
if (ret)
- goto fail_of_entry;
+ goto fail_res_conflict;
ret = platform_device_add(pdev);
if (ret)
- goto fail_of_entry;
+ goto fail_res_conflict;
if (cell->pm_runtime_no_callbacks)
pm_runtime_no_callbacks(&pdev->dev);
@@ -286,13 +286,15 @@ static int mfd_add_device(struct device *parent, int id,
return 0;
+fail_res_conflict:
+ if (cell->swnode)
+ device_remove_software_node(&pdev->dev);
fail_of_entry:
list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
if (of_entry->dev == &pdev->dev) {
list_del(&of_entry->list);
kfree(of_entry);
}
- device_remove_software_node(&pdev->dev);
fail_alias:
regulator_bulk_unregister_supply_alias(&pdev->dev,
cell->parent_supplies,
@@ -358,11 +360,12 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
if (level && cell->level > *level)
return 0;
+ if (cell->swnode)
+ device_remove_software_node(&pdev->dev);
+
regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
cell->num_parent_supplies);
- device_remove_software_node(&pdev->dev);
-
platform_device_unregister(pdev);
return 0;
}
diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c
index 30d82bfe5b02..6fb206da2729 100644
--- a/drivers/mfd/motorola-cpcap.c
+++ b/drivers/mfd/motorola-cpcap.c
@@ -327,6 +327,10 @@ static int cpcap_probe(struct spi_device *spi)
if (ret)
return ret;
+ /* Parent SPI controller uses DMA, CPCAP and child devices do not */
+ spi->dev.coherent_dma_mask = 0;
+ spi->dev.dma_mask = &spi->dev.coherent_dma_mask;
+
return devm_mfd_add_devices(&spi->dev, 0, cpcap_mfd_devices,
ARRAY_SIZE(cpcap_mfd_devices), NULL, 0, NULL);
}
diff --git a/drivers/mfd/mt6358-irq.c b/drivers/mfd/mt6358-irq.c
index db734f2831ff..83f3ffbdbb4c 100644
--- a/drivers/mfd/mt6358-irq.c
+++ b/drivers/mfd/mt6358-irq.c
@@ -5,6 +5,8 @@
#include <linux/interrupt.h>
#include <linux/mfd/mt6358/core.h>
#include <linux/mfd/mt6358/registers.h>
+#include <linux/mfd/mt6359/core.h>
+#include <linux/mfd/mt6359/registers.h>
#include <linux/mfd/mt6397/core.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -13,7 +15,9 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
-static struct irq_top_t mt6358_ints[] = {
+#define MTK_PMIC_REG_WIDTH 16
+
+static const struct irq_top_t mt6358_ints[] = {
MT6358_TOP_GEN(BUCK),
MT6358_TOP_GEN(LDO),
MT6358_TOP_GEN(PSC),
@@ -24,6 +28,31 @@ static struct irq_top_t mt6358_ints[] = {
MT6358_TOP_GEN(MISC),
};
+static const struct irq_top_t mt6359_ints[] = {
+ MT6359_TOP_GEN(BUCK),
+ MT6359_TOP_GEN(LDO),
+ MT6359_TOP_GEN(PSC),
+ MT6359_TOP_GEN(SCK),
+ MT6359_TOP_GEN(BM),
+ MT6359_TOP_GEN(HK),
+ MT6359_TOP_GEN(AUD),
+ MT6359_TOP_GEN(MISC),
+};
+
+static struct pmic_irq_data mt6358_irqd = {
+ .num_top = ARRAY_SIZE(mt6358_ints),
+ .num_pmic_irqs = MT6358_IRQ_NR,
+ .top_int_status_reg = MT6358_TOP_INT_STATUS0,
+ .pmic_ints = mt6358_ints,
+};
+
+static struct pmic_irq_data mt6359_irqd = {
+ .num_top = ARRAY_SIZE(mt6359_ints),
+ .num_pmic_irqs = MT6359_IRQ_NR,
+ .top_int_status_reg = MT6359_TOP_INT_STATUS0,
+ .pmic_ints = mt6359_ints,
+};
+
static void pmic_irq_enable(struct irq_data *data)
{
unsigned int hwirq = irqd_to_hwirq(data);
@@ -62,15 +91,15 @@ static void pmic_irq_sync_unlock(struct irq_data *data)
/* Find out the IRQ group */
top_gp = 0;
while ((top_gp + 1) < irqd->num_top &&
- i >= mt6358_ints[top_gp + 1].hwirq_base)
+ i >= irqd->pmic_ints[top_gp + 1].hwirq_base)
top_gp++;
/* Find the IRQ registers */
- gp_offset = i - mt6358_ints[top_gp].hwirq_base;
- int_regs = gp_offset / MT6358_REG_WIDTH;
- shift = gp_offset % MT6358_REG_WIDTH;
- en_reg = mt6358_ints[top_gp].en_reg +
- (mt6358_ints[top_gp].en_reg_shift * int_regs);
+ gp_offset = i - irqd->pmic_ints[top_gp].hwirq_base;
+ int_regs = gp_offset / MTK_PMIC_REG_WIDTH;
+ shift = gp_offset % MTK_PMIC_REG_WIDTH;
+ en_reg = irqd->pmic_ints[top_gp].en_reg +
+ (irqd->pmic_ints[top_gp].en_reg_shift * int_regs);
regmap_update_bits(chip->regmap, en_reg, BIT(shift),
irqd->enable_hwirq[i] << shift);
@@ -95,10 +124,11 @@ static void mt6358_irq_sp_handler(struct mt6397_chip *chip,
unsigned int irq_status, sta_reg, status;
unsigned int hwirq, virq;
int i, j, ret;
+ struct pmic_irq_data *irqd = chip->irq_data;
- for (i = 0; i < mt6358_ints[top_gp].num_int_regs; i++) {
- sta_reg = mt6358_ints[top_gp].sta_reg +
- mt6358_ints[top_gp].sta_reg_shift * i;
+ for (i = 0; i < irqd->pmic_ints[top_gp].num_int_regs; i++) {
+ sta_reg = irqd->pmic_ints[top_gp].sta_reg +
+ irqd->pmic_ints[top_gp].sta_reg_shift * i;
ret = regmap_read(chip->regmap, sta_reg, &irq_status);
if (ret) {
@@ -114,8 +144,8 @@ static void mt6358_irq_sp_handler(struct mt6397_chip *chip,
do {
j = __ffs(status);
- hwirq = mt6358_ints[top_gp].hwirq_base +
- MT6358_REG_WIDTH * i + j;
+ hwirq = irqd->pmic_ints[top_gp].hwirq_base +
+ MTK_PMIC_REG_WIDTH * i + j;
virq = irq_find_mapping(chip->irq_domain, hwirq);
if (virq)
@@ -131,12 +161,12 @@ static void mt6358_irq_sp_handler(struct mt6397_chip *chip,
static irqreturn_t mt6358_irq_handler(int irq, void *data)
{
struct mt6397_chip *chip = data;
- struct pmic_irq_data *mt6358_irq_data = chip->irq_data;
+ struct pmic_irq_data *irqd = chip->irq_data;
unsigned int bit, i, top_irq_status = 0;
int ret;
ret = regmap_read(chip->regmap,
- mt6358_irq_data->top_int_status_reg,
+ irqd->top_int_status_reg,
&top_irq_status);
if (ret) {
dev_err(chip->dev,
@@ -144,8 +174,8 @@ static irqreturn_t mt6358_irq_handler(int irq, void *data)
return IRQ_NONE;
}
- for (i = 0; i < mt6358_irq_data->num_top; i++) {
- bit = BIT(mt6358_ints[i].top_offset);
+ for (i = 0; i < irqd->num_top; i++) {
+ bit = BIT(irqd->pmic_ints[i].top_offset);
if (top_irq_status & bit) {
mt6358_irq_sp_handler(chip, i);
top_irq_status &= ~bit;
@@ -180,17 +210,22 @@ int mt6358_irq_init(struct mt6397_chip *chip)
int i, j, ret;
struct pmic_irq_data *irqd;
- irqd = devm_kzalloc(chip->dev, sizeof(*irqd), GFP_KERNEL);
- if (!irqd)
- return -ENOMEM;
+ switch (chip->chip_id) {
+ case MT6358_CHIP_ID:
+ chip->irq_data = &mt6358_irqd;
+ break;
- chip->irq_data = irqd;
+ case MT6359_CHIP_ID:
+ chip->irq_data = &mt6359_irqd;
+ break;
- mutex_init(&chip->irqlock);
- irqd->top_int_status_reg = MT6358_TOP_INT_STATUS0;
- irqd->num_pmic_irqs = MT6358_IRQ_NR;
- irqd->num_top = ARRAY_SIZE(mt6358_ints);
+ default:
+ dev_err(chip->dev, "unsupported chip: 0x%x\n", chip->chip_id);
+ return -ENODEV;
+ }
+ mutex_init(&chip->irqlock);
+ irqd = chip->irq_data;
irqd->enable_hwirq = devm_kcalloc(chip->dev,
irqd->num_pmic_irqs,
sizeof(*irqd->enable_hwirq),
@@ -207,10 +242,10 @@ int mt6358_irq_init(struct mt6397_chip *chip)
/* Disable all interrupts for initializing */
for (i = 0; i < irqd->num_top; i++) {
- for (j = 0; j < mt6358_ints[i].num_int_regs; j++)
+ for (j = 0; j < irqd->pmic_ints[i].num_int_regs; j++)
regmap_write(chip->regmap,
- mt6358_ints[i].en_reg +
- mt6358_ints[i].en_reg_shift * j, 0);
+ irqd->pmic_ints[i].en_reg +
+ irqd->pmic_ints[i].en_reg_shift * j, 0);
}
chip->irq_domain = irq_domain_add_linear(chip->dev->of_node,
diff --git a/drivers/mfd/mt6360-core.c b/drivers/mfd/mt6360-core.c
index 480722acf706..e628953548ce 100644
--- a/drivers/mfd/mt6360-core.c
+++ b/drivers/mfd/mt6360-core.c
@@ -5,121 +5,180 @@
* Author: Gene Chen <gene_chen@richtek.com>
*/
+#include <linux/crc8.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+enum {
+ MT6360_SLAVE_TCPC = 0,
+ MT6360_SLAVE_PMIC,
+ MT6360_SLAVE_LDO,
+ MT6360_SLAVE_PMU,
+ MT6360_SLAVE_MAX,
+};
+
+struct mt6360_ddata {
+ struct i2c_client *i2c[MT6360_SLAVE_MAX];
+ struct device *dev;
+ struct regmap *regmap;
+ struct regmap_irq_chip_data *irq_data;
+ unsigned int chip_rev;
+ u8 crc8_tbl[CRC8_TABLE_SIZE];
+};
-#include <linux/mfd/mt6360.h>
+#define MT6360_TCPC_SLAVEID 0x4E
+#define MT6360_PMIC_SLAVEID 0x1A
+#define MT6360_LDO_SLAVEID 0x64
+#define MT6360_PMU_SLAVEID 0x34
+
+#define MT6360_REG_TCPCSTART 0x00
+#define MT6360_REG_TCPCEND 0xFF
+#define MT6360_REG_PMICSTART 0x100
+#define MT6360_REG_PMICEND 0x13B
+#define MT6360_REG_LDOSTART 0x200
+#define MT6360_REG_LDOEND 0x21C
+#define MT6360_REG_PMUSTART 0x300
+#define MT6360_PMU_DEV_INFO 0x300
+#define MT6360_PMU_CHG_IRQ1 0x3D0
+#define MT6360_PMU_CHG_MASK1 0x3F0
+#define MT6360_REG_PMUEND 0x3FF
+
+#define MT6360_PMU_IRQ_REGNUM 16
+
+#define CHIP_VEN_MASK 0xF0
+#define CHIP_VEN_MT6360 0x50
+#define CHIP_REV_MASK 0x0F
+
+#define MT6360_ADDRESS_MASK 0x3F
+#define MT6360_DATA_SIZE_1_BYTE 0x00
+#define MT6360_DATA_SIZE_2_BYTES 0x40
+#define MT6360_DATA_SIZE_3_BYTES 0x80
+#define MT6360_DATA_SIZE_4_BYTES 0xC0
+
+#define MT6360_CRC8_POLYNOMIAL 0x7
+
+#define MT6360_CRC_I2C_ADDR_SIZE 1
+#define MT6360_CRC_REG_ADDR_SIZE 1
+/* prealloca read size = i2c device addr + i2c reg addr + val ... + crc8 */
+#define MT6360_ALLOC_READ_SIZE(_size) (_size + 3)
+/* prealloca write size = i2c device addr + i2c reg addr + val ... + crc8 + dummy byte */
+#define MT6360_ALLOC_WRITE_SIZE(_size) (_size + 4)
+#define MT6360_CRC_PREDATA_OFFSET (MT6360_CRC_I2C_ADDR_SIZE + MT6360_CRC_REG_ADDR_SIZE)
+#define MT6360_CRC_CRC8_SIZE 1
+#define MT6360_CRC_DUMMY_BYTE_SIZE 1
+#define MT6360_REGMAP_REG_BYTE_SIZE 2
+#define I2C_ADDR_XLATE_8BIT(_addr, _rw) (((_addr & 0x7F) << 1) + _rw)
/* reg 0 -> 0 ~ 7 */
-#define MT6360_CHG_TREG_EVT (4)
-#define MT6360_CHG_AICR_EVT (5)
-#define MT6360_CHG_MIVR_EVT (6)
-#define MT6360_PWR_RDY_EVT (7)
+#define MT6360_CHG_TREG_EVT 4
+#define MT6360_CHG_AICR_EVT 5
+#define MT6360_CHG_MIVR_EVT 6
+#define MT6360_PWR_RDY_EVT 7
/* REG 1 -> 8 ~ 15 */
-#define MT6360_CHG_BATSYSUV_EVT (9)
-#define MT6360_FLED_CHG_VINOVP_EVT (11)
-#define MT6360_CHG_VSYSUV_EVT (12)
-#define MT6360_CHG_VSYSOV_EVT (13)
-#define MT6360_CHG_VBATOV_EVT (14)
-#define MT6360_CHG_VBUSOV_EVT (15)
+#define MT6360_CHG_BATSYSUV_EVT 9
+#define MT6360_FLED_CHG_VINOVP_EVT 11
+#define MT6360_CHG_VSYSUV_EVT 12
+#define MT6360_CHG_VSYSOV_EVT 13
+#define MT6360_CHG_VBATOV_EVT 14
+#define MT6360_CHG_VBUSOV_EVT 15
/* REG 2 -> 16 ~ 23 */
/* REG 3 -> 24 ~ 31 */
-#define MT6360_WD_PMU_DET (25)
-#define MT6360_WD_PMU_DONE (26)
-#define MT6360_CHG_TMRI (27)
-#define MT6360_CHG_ADPBADI (29)
-#define MT6360_CHG_RVPI (30)
-#define MT6360_OTPI (31)
+#define MT6360_WD_PMU_DET 25
+#define MT6360_WD_PMU_DONE 26
+#define MT6360_CHG_TMRI 27
+#define MT6360_CHG_ADPBADI 29
+#define MT6360_CHG_RVPI 30
+#define MT6360_OTPI 31
/* REG 4 -> 32 ~ 39 */
-#define MT6360_CHG_AICCMEASL (32)
-#define MT6360_CHGDET_DONEI (34)
-#define MT6360_WDTMRI (35)
-#define MT6360_SSFINISHI (36)
-#define MT6360_CHG_RECHGI (37)
-#define MT6360_CHG_TERMI (38)
-#define MT6360_CHG_IEOCI (39)
+#define MT6360_CHG_AICCMEASL 32
+#define MT6360_CHGDET_DONEI 34
+#define MT6360_WDTMRI 35
+#define MT6360_SSFINISHI 36
+#define MT6360_CHG_RECHGI 37
+#define MT6360_CHG_TERMI 38
+#define MT6360_CHG_IEOCI 39
/* REG 5 -> 40 ~ 47 */
-#define MT6360_PUMPX_DONEI (40)
-#define MT6360_BAT_OVP_ADC_EVT (41)
-#define MT6360_TYPEC_OTP_EVT (42)
-#define MT6360_ADC_WAKEUP_EVT (43)
-#define MT6360_ADC_DONEI (44)
-#define MT6360_BST_BATUVI (45)
-#define MT6360_BST_VBUSOVI (46)
-#define MT6360_BST_OLPI (47)
+#define MT6360_PUMPX_DONEI 40
+#define MT6360_BAT_OVP_ADC_EVT 41
+#define MT6360_TYPEC_OTP_EVT 42
+#define MT6360_ADC_WAKEUP_EVT 43
+#define MT6360_ADC_DONEI 44
+#define MT6360_BST_BATUVI 45
+#define MT6360_BST_VBUSOVI 46
+#define MT6360_BST_OLPI 47
/* REG 6 -> 48 ~ 55 */
-#define MT6360_ATTACH_I (48)
-#define MT6360_DETACH_I (49)
-#define MT6360_QC30_STPDONE (51)
-#define MT6360_QC_VBUSDET_DONE (52)
-#define MT6360_HVDCP_DET (53)
-#define MT6360_CHGDETI (54)
-#define MT6360_DCDTI (55)
+#define MT6360_ATTACH_I 48
+#define MT6360_DETACH_I 49
+#define MT6360_QC30_STPDONE 51
+#define MT6360_QC_VBUSDET_DONE 52
+#define MT6360_HVDCP_DET 53
+#define MT6360_CHGDETI 54
+#define MT6360_DCDTI 55
/* REG 7 -> 56 ~ 63 */
-#define MT6360_FOD_DONE_EVT (56)
-#define MT6360_FOD_OV_EVT (57)
-#define MT6360_CHRDET_UVP_EVT (58)
-#define MT6360_CHRDET_OVP_EVT (59)
-#define MT6360_CHRDET_EXT_EVT (60)
-#define MT6360_FOD_LR_EVT (61)
-#define MT6360_FOD_HR_EVT (62)
-#define MT6360_FOD_DISCHG_FAIL_EVT (63)
+#define MT6360_FOD_DONE_EVT 56
+#define MT6360_FOD_OV_EVT 57
+#define MT6360_CHRDET_UVP_EVT 58
+#define MT6360_CHRDET_OVP_EVT 59
+#define MT6360_CHRDET_EXT_EVT 60
+#define MT6360_FOD_LR_EVT 61
+#define MT6360_FOD_HR_EVT 62
+#define MT6360_FOD_DISCHG_FAIL_EVT 63
/* REG 8 -> 64 ~ 71 */
-#define MT6360_USBID_EVT (64)
-#define MT6360_APWDTRST_EVT (65)
-#define MT6360_EN_EVT (66)
-#define MT6360_QONB_RST_EVT (67)
-#define MT6360_MRSTB_EVT (68)
-#define MT6360_OTP_EVT (69)
-#define MT6360_VDDAOV_EVT (70)
-#define MT6360_SYSUV_EVT (71)
+#define MT6360_USBID_EVT 64
+#define MT6360_APWDTRST_EVT 65
+#define MT6360_EN_EVT 66
+#define MT6360_QONB_RST_EVT 67
+#define MT6360_MRSTB_EVT 68
+#define MT6360_OTP_EVT 69
+#define MT6360_VDDAOV_EVT 70
+#define MT6360_SYSUV_EVT 71
/* REG 9 -> 72 ~ 79 */
-#define MT6360_FLED_STRBPIN_EVT (72)
-#define MT6360_FLED_TORPIN_EVT (73)
-#define MT6360_FLED_TX_EVT (74)
-#define MT6360_FLED_LVF_EVT (75)
-#define MT6360_FLED2_SHORT_EVT (78)
-#define MT6360_FLED1_SHORT_EVT (79)
+#define MT6360_FLED_STRBPIN_EVT 72
+#define MT6360_FLED_TORPIN_EVT 73
+#define MT6360_FLED_TX_EVT 74
+#define MT6360_FLED_LVF_EVT 75
+#define MT6360_FLED2_SHORT_EVT 78
+#define MT6360_FLED1_SHORT_EVT 79
/* REG 10 -> 80 ~ 87 */
-#define MT6360_FLED2_STRB_EVT (80)
-#define MT6360_FLED1_STRB_EVT (81)
-#define MT6360_FLED2_STRB_TO_EVT (82)
-#define MT6360_FLED1_STRB_TO_EVT (83)
-#define MT6360_FLED2_TOR_EVT (84)
-#define MT6360_FLED1_TOR_EVT (85)
+#define MT6360_FLED2_STRB_EVT 80
+#define MT6360_FLED1_STRB_EVT 81
+#define MT6360_FLED2_STRB_TO_EVT 82
+#define MT6360_FLED1_STRB_TO_EVT 83
+#define MT6360_FLED2_TOR_EVT 84
+#define MT6360_FLED1_TOR_EVT 85
/* REG 11 -> 88 ~ 95 */
/* REG 12 -> 96 ~ 103 */
-#define MT6360_BUCK1_PGB_EVT (96)
-#define MT6360_BUCK1_OC_EVT (100)
-#define MT6360_BUCK1_OV_EVT (101)
-#define MT6360_BUCK1_UV_EVT (102)
+#define MT6360_BUCK1_PGB_EVT 96
+#define MT6360_BUCK1_OC_EVT 100
+#define MT6360_BUCK1_OV_EVT 101
+#define MT6360_BUCK1_UV_EVT 102
/* REG 13 -> 104 ~ 111 */
-#define MT6360_BUCK2_PGB_EVT (104)
-#define MT6360_BUCK2_OC_EVT (108)
-#define MT6360_BUCK2_OV_EVT (109)
-#define MT6360_BUCK2_UV_EVT (110)
+#define MT6360_BUCK2_PGB_EVT 104
+#define MT6360_BUCK2_OC_EVT 108
+#define MT6360_BUCK2_OV_EVT 109
+#define MT6360_BUCK2_UV_EVT 110
/* REG 14 -> 112 ~ 119 */
-#define MT6360_LDO1_OC_EVT (113)
-#define MT6360_LDO2_OC_EVT (114)
-#define MT6360_LDO3_OC_EVT (115)
-#define MT6360_LDO5_OC_EVT (117)
-#define MT6360_LDO6_OC_EVT (118)
-#define MT6360_LDO7_OC_EVT (119)
+#define MT6360_LDO1_OC_EVT 113
+#define MT6360_LDO2_OC_EVT 114
+#define MT6360_LDO3_OC_EVT 115
+#define MT6360_LDO5_OC_EVT 117
+#define MT6360_LDO6_OC_EVT 118
+#define MT6360_LDO7_OC_EVT 119
/* REG 15 -> 120 ~ 127 */
-#define MT6360_LDO1_PGB_EVT (121)
-#define MT6360_LDO2_PGB_EVT (122)
-#define MT6360_LDO3_PGB_EVT (123)
-#define MT6360_LDO5_PGB_EVT (125)
-#define MT6360_LDO6_PGB_EVT (126)
-#define MT6360_LDO7_PGB_EVT (127)
-
-static const struct regmap_irq mt6360_pmu_irqs[] = {
+#define MT6360_LDO1_PGB_EVT 121
+#define MT6360_LDO2_PGB_EVT 122
+#define MT6360_LDO3_PGB_EVT 123
+#define MT6360_LDO5_PGB_EVT 125
+#define MT6360_LDO6_PGB_EVT 126
+#define MT6360_LDO7_PGB_EVT 127
+
+static const struct regmap_irq mt6360_irqs[] = {
REGMAP_IRQ_REG_LINE(MT6360_CHG_TREG_EVT, 8),
REGMAP_IRQ_REG_LINE(MT6360_CHG_AICR_EVT, 8),
REGMAP_IRQ_REG_LINE(MT6360_CHG_MIVR_EVT, 8),
@@ -208,30 +267,16 @@ static const struct regmap_irq mt6360_pmu_irqs[] = {
REGMAP_IRQ_REG_LINE(MT6360_LDO7_PGB_EVT, 8),
};
-static int mt6360_pmu_handle_post_irq(void *irq_drv_data)
-{
- struct mt6360_pmu_data *mpd = irq_drv_data;
-
- return regmap_update_bits(mpd->regmap,
- MT6360_PMU_IRQ_SET, MT6360_IRQ_RETRIG, MT6360_IRQ_RETRIG);
-}
-
-static struct regmap_irq_chip mt6360_pmu_irq_chip = {
- .irqs = mt6360_pmu_irqs,
- .num_irqs = ARRAY_SIZE(mt6360_pmu_irqs),
+static const struct regmap_irq_chip mt6360_irq_chip = {
+ .name = "mt6360_irqs",
+ .irqs = mt6360_irqs,
+ .num_irqs = ARRAY_SIZE(mt6360_irqs),
.num_regs = MT6360_PMU_IRQ_REGNUM,
.mask_base = MT6360_PMU_CHG_MASK1,
.status_base = MT6360_PMU_CHG_IRQ1,
.ack_base = MT6360_PMU_CHG_IRQ1,
.init_ack_masked = true,
.use_ack = true,
- .handle_post_irq = mt6360_pmu_handle_post_irq,
-};
-
-static const struct regmap_config mt6360_pmu_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = MT6360_PMU_MAXREG,
};
static const struct resource mt6360_adc_resources[] = {
@@ -265,7 +310,7 @@ static const struct resource mt6360_led_resources[] = {
DEFINE_RES_IRQ_NAMED(MT6360_FLED1_STRB_TO_EVT, "fled1_strb_to_evt"),
};
-static const struct resource mt6360_pmic_resources[] = {
+static const struct resource mt6360_regulator_resources[] = {
DEFINE_RES_IRQ_NAMED(MT6360_BUCK1_PGB_EVT, "buck1_pgb_evt"),
DEFINE_RES_IRQ_NAMED(MT6360_BUCK1_OC_EVT, "buck1_oc_evt"),
DEFINE_RES_IRQ_NAMED(MT6360_BUCK1_OV_EVT, "buck1_ov_evt"),
@@ -278,9 +323,6 @@ static const struct resource mt6360_pmic_resources[] = {
DEFINE_RES_IRQ_NAMED(MT6360_LDO7_OC_EVT, "ldo7_oc_evt"),
DEFINE_RES_IRQ_NAMED(MT6360_LDO6_PGB_EVT, "ldo6_pgb_evt"),
DEFINE_RES_IRQ_NAMED(MT6360_LDO7_PGB_EVT, "ldo7_pgb_evt"),
-};
-
-static const struct resource mt6360_ldo_resources[] = {
DEFINE_RES_IRQ_NAMED(MT6360_LDO1_OC_EVT, "ldo1_oc_evt"),
DEFINE_RES_IRQ_NAMED(MT6360_LDO2_OC_EVT, "ldo2_oc_evt"),
DEFINE_RES_IRQ_NAMED(MT6360_LDO3_OC_EVT, "ldo3_oc_evt"),
@@ -292,84 +334,241 @@ static const struct resource mt6360_ldo_resources[] = {
};
static const struct mfd_cell mt6360_devs[] = {
- MFD_CELL_OF("mt6360_adc", mt6360_adc_resources,
- NULL, 0, 0, "mediatek,mt6360_adc"),
- MFD_CELL_OF("mt6360_chg", mt6360_chg_resources,
- NULL, 0, 0, "mediatek,mt6360_chg"),
- MFD_CELL_OF("mt6360_led", mt6360_led_resources,
- NULL, 0, 0, "mediatek,mt6360_led"),
- MFD_CELL_OF("mt6360_pmic", mt6360_pmic_resources,
- NULL, 0, 0, "mediatek,mt6360_pmic"),
- MFD_CELL_OF("mt6360_ldo", mt6360_ldo_resources,
- NULL, 0, 0, "mediatek,mt6360_ldo"),
- MFD_CELL_OF("mt6360_tcpc", NULL,
- NULL, 0, 0, "mediatek,mt6360_tcpc"),
+ MFD_CELL_OF("mt6360-adc", mt6360_adc_resources,
+ NULL, 0, 0, "mediatek,mt6360-adc"),
+ MFD_CELL_OF("mt6360-chg", mt6360_chg_resources,
+ NULL, 0, 0, "mediatek,mt6360-chg"),
+ MFD_CELL_OF("mt6360-led", mt6360_led_resources,
+ NULL, 0, 0, "mediatek,mt6360-led"),
+ MFD_CELL_RES("mt6360-regulator", mt6360_regulator_resources),
+ MFD_CELL_OF("mt6360-tcpc", NULL,
+ NULL, 0, 0, "mediatek,mt6360-tcpc"),
};
+static int mt6360_check_vendor_info(struct mt6360_ddata *ddata)
+{
+ u32 info;
+ int ret;
+
+ ret = regmap_read(ddata->regmap, MT6360_PMU_DEV_INFO, &info);
+ if (ret < 0)
+ return ret;
+
+ if ((info & CHIP_VEN_MASK) != CHIP_VEN_MT6360) {
+ dev_err(ddata->dev, "Device not supported\n");
+ return -ENODEV;
+ }
+
+ ddata->chip_rev = info & CHIP_REV_MASK;
+
+ return 0;
+}
+
static const unsigned short mt6360_slave_addr[MT6360_SLAVE_MAX] = {
- MT6360_PMU_SLAVEID,
+ MT6360_TCPC_SLAVEID,
MT6360_PMIC_SLAVEID,
MT6360_LDO_SLAVEID,
- MT6360_TCPC_SLAVEID,
+ MT6360_PMU_SLAVEID,
};
-static int mt6360_pmu_probe(struct i2c_client *client)
+static int mt6360_xlate_pmicldo_addr(u8 *addr, int rw_size)
{
- struct mt6360_pmu_data *mpd;
- unsigned int reg_data;
- int i, ret;
+ /* Address is already in encoded [5:0] */
+ *addr &= MT6360_ADDRESS_MASK;
+
+ switch (rw_size) {
+ case 1:
+ *addr |= MT6360_DATA_SIZE_1_BYTE;
+ break;
+ case 2:
+ *addr |= MT6360_DATA_SIZE_2_BYTES;
+ break;
+ case 3:
+ *addr |= MT6360_DATA_SIZE_3_BYTES;
+ break;
+ case 4:
+ *addr |= MT6360_DATA_SIZE_4_BYTES;
+ break;
+ default:
+ return -EINVAL;
+ }
- mpd = devm_kzalloc(&client->dev, sizeof(*mpd), GFP_KERNEL);
- if (!mpd)
+ return 0;
+}
+
+static int mt6360_regmap_read(void *context, const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ struct mt6360_ddata *ddata = context;
+ u8 bank = *(u8 *)reg;
+ u8 reg_addr = *(u8 *)(reg + 1);
+ struct i2c_client *i2c = ddata->i2c[bank];
+ bool crc_needed = false;
+ u8 *buf;
+ int buf_len = MT6360_ALLOC_READ_SIZE(val_size);
+ int read_size = val_size;
+ u8 crc;
+ int ret;
+
+ if (bank == MT6360_SLAVE_PMIC || bank == MT6360_SLAVE_LDO) {
+ crc_needed = true;
+ ret = mt6360_xlate_pmicldo_addr(&reg_addr, val_size);
+ if (ret < 0)
+ return ret;
+ read_size += MT6360_CRC_CRC8_SIZE;
+ }
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
return -ENOMEM;
- mpd->dev = &client->dev;
- i2c_set_clientdata(client, mpd);
+ buf[0] = I2C_ADDR_XLATE_8BIT(i2c->addr, I2C_SMBUS_READ);
+ buf[1] = reg_addr;
- mpd->regmap = devm_regmap_init_i2c(client, &mt6360_pmu_regmap_config);
- if (IS_ERR(mpd->regmap)) {
- dev_err(&client->dev, "Failed to register regmap\n");
- return PTR_ERR(mpd->regmap);
+ ret = i2c_smbus_read_i2c_block_data(i2c, reg_addr, read_size,
+ buf + MT6360_CRC_PREDATA_OFFSET);
+ if (ret < 0)
+ goto out;
+ else if (ret != read_size) {
+ ret = -EIO;
+ goto out;
}
- ret = regmap_read(mpd->regmap, MT6360_PMU_DEV_INFO, &reg_data);
- if (ret) {
- dev_err(&client->dev, "Device not found\n");
- return ret;
+ if (crc_needed) {
+ crc = crc8(ddata->crc8_tbl, buf, val_size + MT6360_CRC_PREDATA_OFFSET, 0);
+ if (crc != buf[val_size + MT6360_CRC_PREDATA_OFFSET]) {
+ ret = -EIO;
+ goto out;
+ }
}
- mpd->chip_rev = reg_data & CHIP_REV_MASK;
- if (mpd->chip_rev != CHIP_VEN_MT6360) {
- dev_err(&client->dev, "Device not supported\n");
- return -ENODEV;
+ memcpy(val, buf + MT6360_CRC_PREDATA_OFFSET, val_size);
+out:
+ kfree(buf);
+ return (ret < 0) ? ret : 0;
+}
+
+static int mt6360_regmap_write(void *context, const void *val, size_t val_size)
+{
+ struct mt6360_ddata *ddata = context;
+ u8 bank = *(u8 *)val;
+ u8 reg_addr = *(u8 *)(val + 1);
+ struct i2c_client *i2c = ddata->i2c[bank];
+ bool crc_needed = false;
+ u8 *buf;
+ int buf_len = MT6360_ALLOC_WRITE_SIZE(val_size);
+ int write_size = val_size - MT6360_REGMAP_REG_BYTE_SIZE;
+ int ret;
+
+ if (bank == MT6360_SLAVE_PMIC || bank == MT6360_SLAVE_LDO) {
+ crc_needed = true;
+ ret = mt6360_xlate_pmicldo_addr(&reg_addr, val_size - MT6360_REGMAP_REG_BYTE_SIZE);
+ if (ret < 0)
+ return ret;
}
- mt6360_pmu_irq_chip.irq_drv_data = mpd;
- ret = devm_regmap_add_irq_chip(&client->dev, mpd->regmap, client->irq,
- IRQF_TRIGGER_FALLING, 0,
- &mt6360_pmu_irq_chip, &mpd->irq_data);
- if (ret) {
- dev_err(&client->dev, "Failed to add Regmap IRQ Chip\n");
- return ret;
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ buf[0] = I2C_ADDR_XLATE_8BIT(i2c->addr, I2C_SMBUS_WRITE);
+ buf[1] = reg_addr;
+ memcpy(buf + MT6360_CRC_PREDATA_OFFSET, val + MT6360_REGMAP_REG_BYTE_SIZE, write_size);
+
+ if (crc_needed) {
+ buf[val_size] = crc8(ddata->crc8_tbl, buf, val_size, 0);
+ write_size += (MT6360_CRC_CRC8_SIZE + MT6360_CRC_DUMMY_BYTE_SIZE);
}
- mpd->i2c[0] = client;
- for (i = 1; i < MT6360_SLAVE_MAX; i++) {
- mpd->i2c[i] = devm_i2c_new_dummy_device(&client->dev,
- client->adapter,
- mt6360_slave_addr[i]);
- if (IS_ERR(mpd->i2c[i])) {
+ ret = i2c_smbus_write_i2c_block_data(i2c, reg_addr, write_size,
+ buf + MT6360_CRC_PREDATA_OFFSET);
+
+ kfree(buf);
+ return ret;
+}
+
+static const struct regmap_bus mt6360_regmap_bus = {
+ .read = mt6360_regmap_read,
+ .write = mt6360_regmap_write,
+
+ /* Due to PMIC and LDO CRC access size limit */
+ .max_raw_read = 4,
+ .max_raw_write = 4,
+};
+
+static bool mt6360_is_readwrite_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MT6360_REG_TCPCSTART ... MT6360_REG_TCPCEND:
+ fallthrough;
+ case MT6360_REG_PMICSTART ... MT6360_REG_PMICEND:
+ fallthrough;
+ case MT6360_REG_LDOSTART ... MT6360_REG_LDOEND:
+ fallthrough;
+ case MT6360_REG_PMUSTART ... MT6360_REG_PMUEND:
+ return true;
+ }
+
+ return false;
+}
+
+static const struct regmap_config mt6360_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .max_register = MT6360_REG_PMUEND,
+ .writeable_reg = mt6360_is_readwrite_reg,
+ .readable_reg = mt6360_is_readwrite_reg,
+};
+
+static int mt6360_probe(struct i2c_client *client)
+{
+ struct mt6360_ddata *ddata;
+ int i, ret;
+
+ ddata = devm_kzalloc(&client->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ ddata->dev = &client->dev;
+ i2c_set_clientdata(client, ddata);
+
+ for (i = 0; i < MT6360_SLAVE_MAX - 1; i++) {
+ ddata->i2c[i] = devm_i2c_new_dummy_device(&client->dev,
+ client->adapter,
+ mt6360_slave_addr[i]);
+ if (IS_ERR(ddata->i2c[i])) {
dev_err(&client->dev,
"Failed to get new dummy I2C device for address 0x%x",
mt6360_slave_addr[i]);
- return PTR_ERR(mpd->i2c[i]);
+ return PTR_ERR(ddata->i2c[i]);
}
- i2c_set_clientdata(mpd->i2c[i], mpd);
+ }
+ ddata->i2c[MT6360_SLAVE_MAX - 1] = client;
+
+ crc8_populate_msb(ddata->crc8_tbl, MT6360_CRC8_POLYNOMIAL);
+ ddata->regmap = devm_regmap_init(ddata->dev, &mt6360_regmap_bus, ddata,
+ &mt6360_regmap_config);
+ if (IS_ERR(ddata->regmap)) {
+ dev_err(&client->dev, "Failed to register regmap\n");
+ return PTR_ERR(ddata->regmap);
+ }
+
+ ret = mt6360_check_vendor_info(ddata);
+ if (ret)
+ return ret;
+
+ ret = devm_regmap_add_irq_chip(&client->dev, ddata->regmap, client->irq,
+ 0, 0, &mt6360_irq_chip,
+ &ddata->irq_data);
+ if (ret) {
+ dev_err(&client->dev, "Failed to add Regmap IRQ Chip\n");
+ return ret;
}
ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO,
mt6360_devs, ARRAY_SIZE(mt6360_devs), NULL,
- 0, regmap_irq_get_domain(mpd->irq_data));
+ 0, regmap_irq_get_domain(ddata->irq_data));
if (ret) {
dev_err(&client->dev,
"Failed to register subordinate devices\n");
@@ -379,7 +578,7 @@ static int mt6360_pmu_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused mt6360_pmu_suspend(struct device *dev)
+static int __maybe_unused mt6360_suspend(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
@@ -389,7 +588,7 @@ static int __maybe_unused mt6360_pmu_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused mt6360_pmu_resume(struct device *dev)
+static int __maybe_unused mt6360_resume(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
@@ -400,25 +599,24 @@ static int __maybe_unused mt6360_pmu_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(mt6360_pmu_pm_ops,
- mt6360_pmu_suspend, mt6360_pmu_resume);
+static SIMPLE_DEV_PM_OPS(mt6360_pm_ops, mt6360_suspend, mt6360_resume);
-static const struct of_device_id __maybe_unused mt6360_pmu_of_id[] = {
- { .compatible = "mediatek,mt6360_pmu", },
+static const struct of_device_id __maybe_unused mt6360_of_id[] = {
+ { .compatible = "mediatek,mt6360", },
{},
};
-MODULE_DEVICE_TABLE(of, mt6360_pmu_of_id);
+MODULE_DEVICE_TABLE(of, mt6360_of_id);
-static struct i2c_driver mt6360_pmu_driver = {
+static struct i2c_driver mt6360_driver = {
.driver = {
- .name = "mt6360_pmu",
- .pm = &mt6360_pmu_pm_ops,
- .of_match_table = of_match_ptr(mt6360_pmu_of_id),
+ .name = "mt6360",
+ .pm = &mt6360_pm_ops,
+ .of_match_table = of_match_ptr(mt6360_of_id),
},
- .probe_new = mt6360_pmu_probe,
+ .probe_new = mt6360_probe,
};
-module_i2c_driver(mt6360_pmu_driver);
+module_i2c_driver(mt6360_driver);
MODULE_AUTHOR("Gene Chen <gene_chen@richtek.com>");
-MODULE_DESCRIPTION("MT6360 PMU I2C Driver");
+MODULE_DESCRIPTION("MT6360 I2C Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
index 7518d74c3b4c..bddb40054b9e 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
@@ -13,9 +13,11 @@
#include <linux/mfd/core.h>
#include <linux/mfd/mt6323/core.h>
#include <linux/mfd/mt6358/core.h>
+#include <linux/mfd/mt6359/core.h>
#include <linux/mfd/mt6397/core.h>
#include <linux/mfd/mt6323/registers.h>
#include <linux/mfd/mt6358/registers.h>
+#include <linux/mfd/mt6359/registers.h>
#include <linux/mfd/mt6397/registers.h>
#define MT6323_RTC_BASE 0x8000
@@ -45,14 +47,21 @@ static const struct resource mt6397_rtc_resources[] = {
DEFINE_RES_IRQ(MT6397_IRQ_RTC),
};
+static const struct resource mt6358_keys_resources[] = {
+ DEFINE_RES_IRQ_NAMED(MT6358_IRQ_PWRKEY, "powerkey"),
+ DEFINE_RES_IRQ_NAMED(MT6358_IRQ_HOMEKEY, "homekey"),
+ DEFINE_RES_IRQ_NAMED(MT6358_IRQ_PWRKEY_R, "powerkey_r"),
+ DEFINE_RES_IRQ_NAMED(MT6358_IRQ_HOMEKEY_R, "homekey_r"),
+};
+
static const struct resource mt6323_keys_resources[] = {
- DEFINE_RES_IRQ(MT6323_IRQ_STATUS_PWRKEY),
- DEFINE_RES_IRQ(MT6323_IRQ_STATUS_FCHRKEY),
+ DEFINE_RES_IRQ_NAMED(MT6323_IRQ_STATUS_PWRKEY, "powerkey"),
+ DEFINE_RES_IRQ_NAMED(MT6323_IRQ_STATUS_FCHRKEY, "homekey"),
};
static const struct resource mt6397_keys_resources[] = {
- DEFINE_RES_IRQ(MT6397_IRQ_PWRKEY),
- DEFINE_RES_IRQ(MT6397_IRQ_HOMEKEY),
+ DEFINE_RES_IRQ_NAMED(MT6397_IRQ_PWRKEY, "powerkey"),
+ DEFINE_RES_IRQ_NAMED(MT6397_IRQ_HOMEKEY, "homekey"),
};
static const struct resource mt6323_pwrc_resources[] = {
@@ -96,9 +105,25 @@ static const struct mfd_cell mt6358_devs[] = {
}, {
.name = "mt6358-sound",
.of_compatible = "mediatek,mt6358-sound"
+ }, {
+ .name = "mt6358-keys",
+ .num_resources = ARRAY_SIZE(mt6358_keys_resources),
+ .resources = mt6358_keys_resources,
+ .of_compatible = "mediatek,mt6358-keys"
},
};
+static const struct mfd_cell mt6359_devs[] = {
+ { .name = "mt6359-regulator", },
+ {
+ .name = "mt6359-rtc",
+ .num_resources = ARRAY_SIZE(mt6358_rtc_resources),
+ .resources = mt6358_rtc_resources,
+ .of_compatible = "mediatek,mt6358-rtc",
+ },
+ { .name = "mt6359-sound", },
+};
+
static const struct mfd_cell mt6397_devs[] = {
{
.name = "mt6397-rtc",
@@ -149,6 +174,14 @@ static const struct chip_data mt6358_core = {
.irq_init = mt6358_irq_init,
};
+static const struct chip_data mt6359_core = {
+ .cid_addr = MT6359_SWCID,
+ .cid_shift = 8,
+ .cells = mt6359_devs,
+ .cell_size = ARRAY_SIZE(mt6359_devs),
+ .irq_init = mt6358_irq_init,
+};
+
static const struct chip_data mt6397_core = {
.cid_addr = MT6397_CID,
.cid_shift = 0,
@@ -219,6 +252,9 @@ static const struct of_device_id mt6397_of_match[] = {
.compatible = "mediatek,mt6358",
.data = &mt6358_core,
}, {
+ .compatible = "mediatek,mt6359",
+ .data = &mt6359_core,
+ }, {
.compatible = "mediatek,mt6397",
.data = &mt6397_core,
}, {
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 2a3a240b4619..787d2ae86375 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI
*
* Copyright (C) 2011-2013 Texas Instruments Incorporated - https://www.ti.com
diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c
index 16fad79c73f1..080d7970a377 100644
--- a/drivers/mfd/omap-usb-tll.c
+++ b/drivers/mfd/omap-usb-tll.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI
*
* Copyright (C) 2012-2013 Texas Instruments Incorporated - https://www.ti.com
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c
index 148bcd6120f4..e9c565cf0f54 100644
--- a/drivers/mfd/pcf50633-core.c
+++ b/drivers/mfd/pcf50633-core.c
@@ -77,8 +77,8 @@ int pcf50633_reg_clear_bits(struct pcf50633 *pcf, u8 reg, u8 val)
EXPORT_SYMBOL_GPL(pcf50633_reg_clear_bits);
/* sysfs attributes */
-static ssize_t show_dump_regs(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t dump_regs_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct pcf50633 *pcf = dev_get_drvdata(dev);
u8 dump[16];
@@ -106,10 +106,10 @@ static ssize_t show_dump_regs(struct device *dev, struct device_attribute *attr,
return buf1 - buf;
}
-static DEVICE_ATTR(dump_regs, 0400, show_dump_regs, NULL);
+static DEVICE_ATTR_ADMIN_RO(dump_regs);
-static ssize_t show_resume_reason(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t resume_reason_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct pcf50633 *pcf = dev_get_drvdata(dev);
int n;
@@ -123,7 +123,7 @@ static ssize_t show_resume_reason(struct device *dev,
return n;
}
-static DEVICE_ATTR(resume_reason, 0400, show_resume_reason, NULL);
+static DEVICE_ATTR_ADMIN_RO(resume_reason);
static struct attribute *pcf_sysfs_entries[] = {
&dev_attr_dump_regs.attr,
diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c
new file mode 100644
index 000000000000..c472d7f8103c
--- /dev/null
+++ b/drivers/mfd/qcom-pm8008.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/bitops.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/mfd/qcom-pm8008.h>
+
+#define I2C_INTR_STATUS_BASE 0x0550
+#define INT_RT_STS_OFFSET 0x10
+#define INT_SET_TYPE_OFFSET 0x11
+#define INT_POL_HIGH_OFFSET 0x12
+#define INT_POL_LOW_OFFSET 0x13
+#define INT_LATCHED_CLR_OFFSET 0x14
+#define INT_EN_SET_OFFSET 0x15
+#define INT_EN_CLR_OFFSET 0x16
+#define INT_LATCHED_STS_OFFSET 0x18
+
+enum {
+ PM8008_MISC,
+ PM8008_TEMP_ALARM,
+ PM8008_GPIO1,
+ PM8008_GPIO2,
+ PM8008_NUM_PERIPHS,
+};
+
+#define PM8008_PERIPH_0_BASE 0x900
+#define PM8008_PERIPH_1_BASE 0x2400
+#define PM8008_PERIPH_2_BASE 0xC000
+#define PM8008_PERIPH_3_BASE 0xC100
+
+#define PM8008_TEMP_ALARM_ADDR PM8008_PERIPH_1_BASE
+#define PM8008_GPIO1_ADDR PM8008_PERIPH_2_BASE
+#define PM8008_GPIO2_ADDR PM8008_PERIPH_3_BASE
+
+#define PM8008_STATUS_BASE (PM8008_PERIPH_0_BASE | INT_LATCHED_STS_OFFSET)
+#define PM8008_MASK_BASE (PM8008_PERIPH_0_BASE | INT_EN_SET_OFFSET)
+#define PM8008_UNMASK_BASE (PM8008_PERIPH_0_BASE | INT_EN_CLR_OFFSET)
+#define PM8008_TYPE_BASE (PM8008_PERIPH_0_BASE | INT_SET_TYPE_OFFSET)
+#define PM8008_ACK_BASE (PM8008_PERIPH_0_BASE | INT_LATCHED_CLR_OFFSET)
+#define PM8008_POLARITY_HI_BASE (PM8008_PERIPH_0_BASE | INT_POL_HIGH_OFFSET)
+#define PM8008_POLARITY_LO_BASE (PM8008_PERIPH_0_BASE | INT_POL_LOW_OFFSET)
+
+#define PM8008_PERIPH_OFFSET(paddr) (paddr - PM8008_PERIPH_0_BASE)
+
+struct pm8008_data {
+ struct device *dev;
+ struct regmap *regmap;
+ int irq;
+ struct regmap_irq_chip_data *irq_data;
+};
+
+static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
+static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
+static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
+static unsigned int p3_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_3_BASE)};
+
+static struct regmap_irq_sub_irq_map pm8008_sub_reg_offsets[] = {
+ REGMAP_IRQ_MAIN_REG_OFFSET(p0_offs),
+ REGMAP_IRQ_MAIN_REG_OFFSET(p1_offs),
+ REGMAP_IRQ_MAIN_REG_OFFSET(p2_offs),
+ REGMAP_IRQ_MAIN_REG_OFFSET(p3_offs),
+};
+
+static unsigned int pm8008_virt_regs[] = {
+ PM8008_POLARITY_HI_BASE,
+ PM8008_POLARITY_LO_BASE,
+};
+
+enum {
+ POLARITY_HI_INDEX,
+ POLARITY_LO_INDEX,
+ PM8008_NUM_VIRT_REGS,
+};
+
+static struct regmap_irq pm8008_irqs[] = {
+ REGMAP_IRQ_REG(PM8008_IRQ_MISC_UVLO, PM8008_MISC, BIT(0)),
+ REGMAP_IRQ_REG(PM8008_IRQ_MISC_OVLO, PM8008_MISC, BIT(1)),
+ REGMAP_IRQ_REG(PM8008_IRQ_MISC_OTST2, PM8008_MISC, BIT(2)),
+ REGMAP_IRQ_REG(PM8008_IRQ_MISC_OTST3, PM8008_MISC, BIT(3)),
+ REGMAP_IRQ_REG(PM8008_IRQ_MISC_LDO_OCP, PM8008_MISC, BIT(4)),
+ REGMAP_IRQ_REG(PM8008_IRQ_TEMP_ALARM, PM8008_TEMP_ALARM, BIT(0)),
+ REGMAP_IRQ_REG(PM8008_IRQ_GPIO1, PM8008_GPIO1, BIT(0)),
+ REGMAP_IRQ_REG(PM8008_IRQ_GPIO2, PM8008_GPIO2, BIT(0)),
+};
+
+static int pm8008_set_type_virt(unsigned int **virt_buf,
+ unsigned int type, unsigned long hwirq,
+ int reg)
+{
+ switch (type) {
+ case IRQ_TYPE_EDGE_FALLING:
+ case IRQ_TYPE_LEVEL_LOW:
+ virt_buf[POLARITY_HI_INDEX][reg] &= ~pm8008_irqs[hwirq].mask;
+ virt_buf[POLARITY_LO_INDEX][reg] |= pm8008_irqs[hwirq].mask;
+ break;
+
+ case IRQ_TYPE_EDGE_RISING:
+ case IRQ_TYPE_LEVEL_HIGH:
+ virt_buf[POLARITY_HI_INDEX][reg] |= pm8008_irqs[hwirq].mask;
+ virt_buf[POLARITY_LO_INDEX][reg] &= ~pm8008_irqs[hwirq].mask;
+ break;
+
+ case IRQ_TYPE_EDGE_BOTH:
+ virt_buf[POLARITY_HI_INDEX][reg] |= pm8008_irqs[hwirq].mask;
+ virt_buf[POLARITY_LO_INDEX][reg] |= pm8008_irqs[hwirq].mask;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct regmap_irq_chip pm8008_irq_chip = {
+ .name = "pm8008_irq",
+ .main_status = I2C_INTR_STATUS_BASE,
+ .num_main_regs = 1,
+ .num_virt_regs = PM8008_NUM_VIRT_REGS,
+ .irqs = pm8008_irqs,
+ .num_irqs = ARRAY_SIZE(pm8008_irqs),
+ .num_regs = PM8008_NUM_PERIPHS,
+ .not_fixed_stride = true,
+ .sub_reg_offsets = pm8008_sub_reg_offsets,
+ .set_type_virt = pm8008_set_type_virt,
+ .status_base = PM8008_STATUS_BASE,
+ .mask_base = PM8008_MASK_BASE,
+ .unmask_base = PM8008_UNMASK_BASE,
+ .type_base = PM8008_TYPE_BASE,
+ .ack_base = PM8008_ACK_BASE,
+ .virt_reg_base = pm8008_virt_regs,
+ .num_type_reg = PM8008_NUM_PERIPHS,
+};
+
+static struct regmap_config qcom_mfd_regmap_cfg = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0xFFFF,
+};
+
+static int pm8008_init(struct pm8008_data *chip)
+{
+ int rc;
+
+ /*
+ * Set TEMP_ALARM peripheral's TYPE so that the regmap-irq framework
+ * reads this as the default value instead of zero, the HW default.
+ * This is required to enable the writing of TYPE registers in
+ * regmap_irq_sync_unlock().
+ */
+ rc = regmap_write(chip->regmap,
+ (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET),
+ BIT(0));
+ if (rc)
+ return rc;
+
+ /* Do the same for GPIO1 and GPIO2 peripherals */
+ rc = regmap_write(chip->regmap,
+ (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
+ if (rc)
+ return rc;
+
+ rc = regmap_write(chip->regmap,
+ (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
+
+ return rc;
+}
+
+static int pm8008_probe_irq_peripherals(struct pm8008_data *chip,
+ int client_irq)
+{
+ int rc, i;
+ struct regmap_irq_type *type;
+ struct regmap_irq_chip_data *irq_data;
+
+ rc = pm8008_init(chip);
+ if (rc) {
+ dev_err(chip->dev, "Init failed: %d\n", rc);
+ return rc;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pm8008_irqs); i++) {
+ type = &pm8008_irqs[i].type;
+
+ type->type_reg_offset = pm8008_irqs[i].reg_offset;
+ type->type_rising_val = pm8008_irqs[i].mask;
+ type->type_falling_val = pm8008_irqs[i].mask;
+ type->type_level_high_val = 0;
+ type->type_level_low_val = 0;
+
+ if (type->type_reg_offset == PM8008_MISC)
+ type->types_supported = IRQ_TYPE_EDGE_RISING;
+ else
+ type->types_supported = (IRQ_TYPE_EDGE_BOTH |
+ IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
+ }
+
+ rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq,
+ IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
+ if (rc) {
+ dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int pm8008_probe(struct i2c_client *client)
+{
+ int rc;
+ struct pm8008_data *chip;
+
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->dev = &client->dev;
+ chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
+ if (!chip->regmap)
+ return -ENODEV;
+
+ i2c_set_clientdata(client, chip);
+
+ if (of_property_read_bool(chip->dev->of_node, "interrupt-controller")) {
+ rc = pm8008_probe_irq_peripherals(chip, client->irq);
+ if (rc)
+ dev_err(chip->dev, "Failed to probe irq periphs: %d\n", rc);
+ }
+
+ return devm_of_platform_populate(chip->dev);
+}
+
+static const struct of_device_id pm8008_match[] = {
+ { .compatible = "qcom,pm8008", },
+ { },
+};
+
+static struct i2c_driver pm8008_mfd_driver = {
+ .driver = {
+ .name = "pm8008",
+ .of_match_table = pm8008_match,
+ },
+ .probe_new = pm8008_probe,
+};
+module_i2c_driver(pm8008_mfd_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("i2c:qcom-pm8008");
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
index ad923dd4e007..77ccd31ca1d9 100644
--- a/drivers/mfd/rk808.c
+++ b/drivers/mfd/rk808.c
@@ -65,6 +65,7 @@ static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg)
switch (reg) {
case RK817_SECONDS_REG ... RK817_WEEKS_REG:
case RK817_RTC_STATUS_REG:
+ case RK817_CODEC_DTOP_LPT_SRST:
case RK817_INT_STS_REG0:
case RK817_INT_STS_REG1:
case RK817_INT_STS_REG2:
@@ -163,6 +164,7 @@ static const struct mfd_cell rk817s[] = {
.num_resources = ARRAY_SIZE(rk817_rtc_resources),
.resources = &rk817_rtc_resources[0],
},
+ { .name = "rk817-codec",},
};
static const struct mfd_cell rk818s[] = {
@@ -201,6 +203,85 @@ static const struct rk808_reg_data rk808_pre_init_reg[] = {
static const struct rk808_reg_data rk817_pre_init_reg[] = {
{RK817_RTC_CTRL_REG, RTC_STOP, RTC_STOP},
+ /* Codec specific registers */
+ { RK817_CODEC_DTOP_VUCTL, MASK_ALL, 0x03 },
+ { RK817_CODEC_DTOP_VUCTIME, MASK_ALL, 0x00 },
+ { RK817_CODEC_DTOP_LPT_SRST, MASK_ALL, 0x00 },
+ { RK817_CODEC_DTOP_DIGEN_CLKE, MASK_ALL, 0x00 },
+ /* from vendor driver, CODEC_AREF_RTCFG0 not defined in data sheet */
+ { RK817_CODEC_AREF_RTCFG0, MASK_ALL, 0x00 },
+ { RK817_CODEC_AREF_RTCFG1, MASK_ALL, 0x06 },
+ { RK817_CODEC_AADC_CFG0, MASK_ALL, 0xc8 },
+ /* from vendor driver, CODEC_AADC_CFG1 not defined in data sheet */
+ { RK817_CODEC_AADC_CFG1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_VOLL, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_VOLR, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_SR_ACL0, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_ALC1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_ALC2, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_NG, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_HPF, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_RVOLL, MASK_ALL, 0xff },
+ { RK817_CODEC_DADC_RVOLR, MASK_ALL, 0xff },
+ { RK817_CODEC_AMIC_CFG0, MASK_ALL, 0x70 },
+ { RK817_CODEC_AMIC_CFG1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_PGA_GAIN, MASK_ALL, 0x66 },
+ { RK817_CODEC_DMIC_LMT1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_LMT2, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_NG1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_NG2, MASK_ALL, 0x00 },
+ /* from vendor driver, CODEC_ADAC_CFG0 not defined in data sheet */
+ { RK817_CODEC_ADAC_CFG0, MASK_ALL, 0x00 },
+ { RK817_CODEC_ADAC_CFG1, MASK_ALL, 0x07 },
+ { RK817_CODEC_DDAC_POPD_DACST, MASK_ALL, 0x82 },
+ { RK817_CODEC_DDAC_VOLL, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_VOLR, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_SR_LMT0, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_LMT1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_LMT2, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_MUTE_MIXCTL, MASK_ALL, 0xa0 },
+ { RK817_CODEC_DDAC_RVOLL, MASK_ALL, 0xff },
+ { RK817_CODEC_DADC_RVOLR, MASK_ALL, 0xff },
+ { RK817_CODEC_AMIC_CFG0, MASK_ALL, 0x70 },
+ { RK817_CODEC_AMIC_CFG1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_PGA_GAIN, MASK_ALL, 0x66 },
+ { RK817_CODEC_DMIC_LMT1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_LMT2, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_NG1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_NG2, MASK_ALL, 0x00 },
+ /* from vendor driver, CODEC_ADAC_CFG0 not defined in data sheet */
+ { RK817_CODEC_ADAC_CFG0, MASK_ALL, 0x00 },
+ { RK817_CODEC_ADAC_CFG1, MASK_ALL, 0x07 },
+ { RK817_CODEC_DDAC_POPD_DACST, MASK_ALL, 0x82 },
+ { RK817_CODEC_DDAC_VOLL, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_VOLR, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_SR_LMT0, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_LMT1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_LMT2, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_MUTE_MIXCTL, MASK_ALL, 0xa0 },
+ { RK817_CODEC_DDAC_RVOLL, MASK_ALL, 0xff },
+ { RK817_CODEC_DDAC_RVOLR, MASK_ALL, 0xff },
+ { RK817_CODEC_AHP_ANTI0, MASK_ALL, 0x00 },
+ { RK817_CODEC_AHP_ANTI1, MASK_ALL, 0x00 },
+ { RK817_CODEC_AHP_CFG0, MASK_ALL, 0xe0 },
+ { RK817_CODEC_AHP_CFG1, MASK_ALL, 0x1f },
+ { RK817_CODEC_AHP_CP, MASK_ALL, 0x09 },
+ { RK817_CODEC_ACLASSD_CFG1, MASK_ALL, 0x69 },
+ { RK817_CODEC_ACLASSD_CFG2, MASK_ALL, 0x44 },
+ { RK817_CODEC_APLL_CFG0, MASK_ALL, 0x04 },
+ { RK817_CODEC_APLL_CFG1, MASK_ALL, 0x00 },
+ { RK817_CODEC_APLL_CFG2, MASK_ALL, 0x30 },
+ { RK817_CODEC_APLL_CFG3, MASK_ALL, 0x19 },
+ { RK817_CODEC_APLL_CFG4, MASK_ALL, 0x65 },
+ { RK817_CODEC_APLL_CFG5, MASK_ALL, 0x01 },
+ { RK817_CODEC_DI2S_CKM, MASK_ALL, 0x01 },
+ { RK817_CODEC_DI2S_RSD, MASK_ALL, 0x00 },
+ { RK817_CODEC_DI2S_RXCR1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DI2S_RXCR2, MASK_ALL, 0x17 },
+ { RK817_CODEC_DI2S_RXCMD_TSD, MASK_ALL, 0x00 },
+ { RK817_CODEC_DI2S_TXCR1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DI2S_TXCR2, MASK_ALL, 0x17 },
+ { RK817_CODEC_DI2S_TXCR3_TXCMD, MASK_ALL, 0x00 },
{RK817_GPIO_INT_CFG, RK817_INT_POL_MSK, RK817_INT_POL_L},
{RK817_SYS_CFG(1), RK817_HOTDIE_TEMP_MSK | RK817_TSD_TEMP_MSK,
RK817_HOTDIE_105 | RK817_TSD_140},
diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c
index 6ed04e6dbc78..384acb459427 100644
--- a/drivers/mfd/rn5t618.c
+++ b/drivers/mfd/rn5t618.c
@@ -107,7 +107,7 @@ static int rn5t618_irq_init(struct rn5t618 *rn5t618)
ret = devm_regmap_add_irq_chip(rn5t618->dev, rn5t618->regmap,
rn5t618->irq,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
0, irq_chip, &rn5t618->irq_data);
if (ret)
dev_err(rn5t618->dev, "Failed to register IRQ chip\n");
diff --git a/drivers/mfd/rt4831.c b/drivers/mfd/rt4831.c
new file mode 100644
index 000000000000..b169781ac675
--- /dev/null
+++ b/drivers/mfd/rt4831.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Richtek Technology Corp.
+ *
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#define RT4831_REG_REVISION 0x01
+#define RT4831_REG_ENABLE 0x08
+#define RT4831_REG_I2CPROT 0x15
+
+#define RICHTEK_VENDOR_ID 0x03
+#define RT4831_VID_MASK GENMASK(1, 0)
+#define RT4831_RESET_MASK BIT(7)
+#define RT4831_I2CSAFETMR_MASK BIT(0)
+
+static const struct mfd_cell rt4831_subdevs[] = {
+ MFD_CELL_OF("rt4831-backlight", NULL, NULL, 0, 0, "richtek,rt4831-backlight"),
+ MFD_CELL_NAME("rt4831-regulator")
+};
+
+static bool rt4831_is_accessible_reg(struct device *dev, unsigned int reg)
+{
+ if (reg >= RT4831_REG_REVISION && reg <= RT4831_REG_I2CPROT)
+ return true;
+ return false;
+}
+
+static const struct regmap_config rt4831_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RT4831_REG_I2CPROT,
+
+ .readable_reg = rt4831_is_accessible_reg,
+ .writeable_reg = rt4831_is_accessible_reg,
+};
+
+static int rt4831_probe(struct i2c_client *client)
+{
+ struct gpio_desc *enable_gpio;
+ struct regmap *regmap;
+ unsigned int chip_id;
+ int ret;
+
+ enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_HIGH);
+ if (IS_ERR(enable_gpio)) {
+ dev_err(&client->dev, "Failed to get 'enable' GPIO\n");
+ return PTR_ERR(enable_gpio);
+ }
+
+ regmap = devm_regmap_init_i2c(client, &rt4831_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "Failed to initialize regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ ret = regmap_read(regmap, RT4831_REG_REVISION, &chip_id);
+ if (ret) {
+ dev_err(&client->dev, "Failed to get H/W revision\n");
+ return ret;
+ }
+
+ if ((chip_id & RT4831_VID_MASK) != RICHTEK_VENDOR_ID) {
+ dev_err(&client->dev, "Chip vendor ID 0x%02x not matched\n", chip_id);
+ return -ENODEV;
+ }
+
+ /*
+ * Used to prevent the abnormal shutdown.
+ * If SCL/SDA both keep low for one second to reset HW.
+ */
+ ret = regmap_update_bits(regmap, RT4831_REG_I2CPROT, RT4831_I2CSAFETMR_MASK,
+ RT4831_I2CSAFETMR_MASK);
+ if (ret) {
+ dev_err(&client->dev, "Failed to enable I2C safety timer\n");
+ return ret;
+ }
+
+ return devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO, rt4831_subdevs,
+ ARRAY_SIZE(rt4831_subdevs), NULL, 0, NULL);
+}
+
+static int rt4831_remove(struct i2c_client *client)
+{
+ struct regmap *regmap = dev_get_regmap(&client->dev, NULL);
+
+ /* Disable WLED and DSV outputs */
+ return regmap_update_bits(regmap, RT4831_REG_ENABLE, RT4831_RESET_MASK, RT4831_RESET_MASK);
+}
+
+static const struct of_device_id __maybe_unused rt4831_of_match[] = {
+ { .compatible = "richtek,rt4831", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rt4831_of_match);
+
+static struct i2c_driver rt4831_driver = {
+ .driver = {
+ .name = "rt4831",
+ .of_match_table = rt4831_of_match,
+ },
+ .probe_new = rt4831_probe,
+ .remove = rt4831_remove,
+};
+module_i2c_driver(rt4831_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c
index 8d55992da19e..1fb29c45f5cf 100644
--- a/drivers/mfd/sec-core.c
+++ b/drivers/mfd/sec-core.c
@@ -10,6 +10,7 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
@@ -93,7 +94,6 @@ static const struct mfd_cell s2mpu02_devs[] = {
{ .name = "s2mpu02-regulator", },
};
-#ifdef CONFIG_OF
static const struct of_device_id sec_dt_match[] = {
{
.compatible = "samsung,s5m8767-pmic",
@@ -121,7 +121,6 @@ static const struct of_device_id sec_dt_match[] = {
},
};
MODULE_DEVICE_TABLE(of, sec_dt_match);
-#endif
static bool s2mpa01_volatile(struct device *dev, unsigned int reg)
{
@@ -281,7 +280,6 @@ static void sec_pmic_configure(struct sec_pmic_dev *sec_pmic)
}
}
-#ifdef CONFIG_OF
/*
* Only the common platform data elements for s5m8767 are parsed here from the
* device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and
@@ -300,48 +298,20 @@ sec_pmic_i2c_parse_dt_pdata(struct device *dev)
if (!pd)
return ERR_PTR(-ENOMEM);
- /*
- * ToDo: the 'wakeup' member in the platform data is more of a linux
- * specfic information. Hence, there is no binding for that yet and
- * not parsed here.
- */
-
pd->manual_poweroff = of_property_read_bool(dev->of_node,
"samsung,s2mps11-acokb-ground");
pd->disable_wrstbi = of_property_read_bool(dev->of_node,
"samsung,s2mps11-wrstbi-ground");
return pd;
}
-#else
-static struct sec_platform_data *
-sec_pmic_i2c_parse_dt_pdata(struct device *dev)
-{
- return NULL;
-}
-#endif
-
-static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c,
- const struct i2c_device_id *id)
-{
-#ifdef CONFIG_OF
- if (i2c->dev.of_node) {
- const struct of_device_id *match;
-
- match = of_match_node(sec_dt_match, i2c->dev.of_node);
- return (unsigned long)match->data;
- }
-#endif
- return id->driver_data;
-}
static int sec_pmic_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev);
const struct regmap_config *regmap;
+ struct sec_platform_data *pdata;
const struct mfd_cell *sec_devs;
struct sec_pmic_dev *sec_pmic;
- unsigned long device_type;
int ret, num_sec_devs;
sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev),
@@ -353,23 +323,16 @@ static int sec_pmic_probe(struct i2c_client *i2c,
sec_pmic->dev = &i2c->dev;
sec_pmic->i2c = i2c;
sec_pmic->irq = i2c->irq;
- device_type = sec_i2c_get_driver_data(i2c, id);
-
- if (sec_pmic->dev->of_node) {
- pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev);
- if (IS_ERR(pdata)) {
- ret = PTR_ERR(pdata);
- return ret;
- }
- pdata->device_type = device_type;
- }
- if (pdata) {
- sec_pmic->device_type = pdata->device_type;
- sec_pmic->irq_base = pdata->irq_base;
- sec_pmic->wakeup = pdata->wakeup;
- sec_pmic->pdata = pdata;
+
+ pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev);
+ if (IS_ERR(pdata)) {
+ ret = PTR_ERR(pdata);
+ return ret;
}
+ sec_pmic->device_type = (unsigned long)of_device_get_match_data(sec_pmic->dev);
+ sec_pmic->pdata = pdata;
+
switch (sec_pmic->device_type) {
case S2MPA01:
regmap = &s2mpa01_regmap_config;
@@ -408,9 +371,6 @@ static int sec_pmic_probe(struct i2c_client *i2c,
return ret;
}
- if (pdata && pdata->cfg_pmic_irq)
- pdata->cfg_pmic_irq();
-
sec_irq_init(sec_pmic);
pm_runtime_set_active(sec_pmic->dev);
@@ -462,7 +422,6 @@ static int sec_pmic_probe(struct i2c_client *i2c,
if (ret)
return ret;
- device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup);
sec_pmic_configure(sec_pmic);
sec_pmic_dump_rev(sec_pmic);
@@ -533,21 +492,14 @@ static int sec_pmic_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume);
-static const struct i2c_device_id sec_pmic_id[] = {
- { "sec_pmic", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, sec_pmic_id);
-
static struct i2c_driver sec_pmic_driver = {
.driver = {
.name = "sec_pmic",
.pm = &sec_pmic_pm_ops,
- .of_match_table = of_match_ptr(sec_dt_match),
+ .of_match_table = sec_dt_match,
},
.probe = sec_pmic_probe,
.shutdown = sec_pmic_shutdown,
- .id_table = sec_pmic_id,
};
module_i2c_driver(sec_pmic_driver);
diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c
index a98c5d165039..e473c2fb42d5 100644
--- a/drivers/mfd/sec-irq.c
+++ b/drivers/mfd/sec-irq.c
@@ -444,7 +444,6 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
if (!sec_pmic->irq) {
dev_warn(sec_pmic->dev,
"No interrupt specified, no interrupts\n");
- sec_pmic->irq_base = 0;
return 0;
}
@@ -482,8 +481,7 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
ret = devm_regmap_add_irq_chip(sec_pmic->dev, sec_pmic->regmap_pmic,
sec_pmic->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- sec_pmic->irq_base, sec_irq_chip,
- &sec_pmic->irq_data);
+ 0, sec_irq_chip, &sec_pmic->irq_data);
if (ret != 0) {
dev_err(sec_pmic->dev, "Failed to register IRQ chip: %d\n", ret);
return ret;
diff --git a/drivers/mfd/si476x-cmd.c b/drivers/mfd/si476x-cmd.c
index d15b3e783369..f32f1fb93e37 100644
--- a/drivers/mfd/si476x-cmd.c
+++ b/drivers/mfd/si476x-cmd.c
@@ -390,7 +390,7 @@ static int si476x_cmd_tune_seek_freq(struct si476x_core *core,
}
/**
- * si476x_cmd_func_info() - send 'FUNC_INFO' command to the device
+ * si476x_core_cmd_func_info() - send 'FUNC_INFO' command to the device
* @core: device to send the command to
* @info: struct si476x_func_info to fill all the information
* returned by the command
@@ -424,7 +424,7 @@ int si476x_core_cmd_func_info(struct si476x_core *core,
EXPORT_SYMBOL_GPL(si476x_core_cmd_func_info);
/**
- * si476x_cmd_set_property() - send 'SET_PROPERTY' command to the device
+ * si476x_core_cmd_set_property() - send 'SET_PROPERTY' command to the device
* @core: device to send the command to
* @property: property address
* @value: property value
@@ -452,7 +452,7 @@ int si476x_core_cmd_set_property(struct si476x_core *core,
EXPORT_SYMBOL_GPL(si476x_core_cmd_set_property);
/**
- * si476x_cmd_get_property() - send 'GET_PROPERTY' command to the device
+ * si476x_core_cmd_get_property() - send 'GET_PROPERTY' command to the device
* @core: device to send the command to
* @property: property address
*
@@ -481,7 +481,7 @@ int si476x_core_cmd_get_property(struct si476x_core *core, u16 property)
EXPORT_SYMBOL_GPL(si476x_core_cmd_get_property);
/**
- * si476x_cmd_dig_audio_pin_cfg() - send 'DIG_AUDIO_PIN_CFG' command to
+ * si476x_core_cmd_dig_audio_pin_cfg() - send 'DIG_AUDIO_PIN_CFG' command to
* the device
* @core: device to send the command to
* @dclk: DCLK pin function configuration:
@@ -539,7 +539,7 @@ int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *core,
EXPORT_SYMBOL_GPL(si476x_core_cmd_dig_audio_pin_cfg);
/**
- * si476x_cmd_zif_pin_cfg - send 'ZIF_PIN_CFG_COMMAND'
+ * si476x_core_cmd_zif_pin_cfg - send 'ZIF_PIN_CFG_COMMAND'
* @core: - device to send the command to
* @iqclk: - IQCL pin function configuration:
* SI476X_IQCLK_NOOP - do not modify the behaviour
@@ -588,7 +588,7 @@ int si476x_core_cmd_zif_pin_cfg(struct si476x_core *core,
EXPORT_SYMBOL_GPL(si476x_core_cmd_zif_pin_cfg);
/**
- * si476x_cmd_ic_link_gpo_ctl_pin_cfg - send
+ * si476x_core_cmd_ic_link_gpo_ctl_pin_cfg - send
* 'IC_LINK_GPIO_CTL_PIN_CFG' comand to the device
* @core: - device to send the command to
* @icin: - ICIN pin function configuration:
@@ -645,7 +645,7 @@ int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *core,
EXPORT_SYMBOL_GPL(si476x_core_cmd_ic_link_gpo_ctl_pin_cfg);
/**
- * si476x_cmd_ana_audio_pin_cfg - send 'ANA_AUDIO_PIN_CFG' to the
+ * si476x_core_cmd_ana_audio_pin_cfg - send 'ANA_AUDIO_PIN_CFG' to the
* device
* @core: - device to send the command to
* @lrout: - LROUT pin function configuration:
@@ -674,7 +674,7 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_ana_audio_pin_cfg);
/**
- * si476x_cmd_intb_pin_cfg - send 'INTB_PIN_CFG' command to the device
+ * si476x_core_cmd_intb_pin_cfg_a10 - send 'INTB_PIN_CFG' command to the device
* @core: - device to send the command to
* @intb: - INTB pin function configuration:
* SI476X_INTB_NOOP - do not modify the behaviour
@@ -726,12 +726,12 @@ static int si476x_core_cmd_intb_pin_cfg_a20(struct si476x_core *core,
/**
- * si476x_cmd_am_rsq_status - send 'AM_RSQ_STATUS' command to the
+ * si476x_core_cmd_am_rsq_status - send 'AM_RSQ_STATUS' command to the
* device
* @core: - device to send the command to
* @rsqargs: - pointer to a structure containing a group of sub-args
* relevant to sending the RSQ status command
- * @report: - all signal quality information retured by the command
+ * @report: - all signal quality information returned by the command
* (if NULL then the output of the command is ignored)
*
* Function returns 0 on success and negative error code on failure
@@ -856,7 +856,7 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_am_acf_status);
/**
- * si476x_cmd_fm_seek_start - send 'FM_SEEK_START' command to the
+ * si476x_core_cmd_fm_seek_start - send 'FM_SEEK_START' command to the
* device
* @core: - device to send the command to
* @seekup: - if set the direction of the search is 'up'
@@ -884,7 +884,7 @@ int si476x_core_cmd_fm_seek_start(struct si476x_core *core,
EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_seek_start);
/**
- * si476x_cmd_fm_rds_status - send 'FM_RDS_STATUS' command to the
+ * si476x_core_cmd_fm_rds_status - send 'FM_RDS_STATUS' command to the
* device
* @core: - device to send the command to
* @status_only: - if set the data is not removed from RDSFIFO,
@@ -892,7 +892,7 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_seek_start);
* rest RDS data contains the last valid info received
* @mtfifo: if set the command clears RDS receive FIFO
* @intack: if set the command clards the RDSINT bit.
- * @report: - all signal quality information retured by the command
+ * @report: - all signal quality information returned by the command
* (if NULL then the output of the command is ignored)
*
* Function returns 0 on success and negative error code on failure
@@ -1032,7 +1032,7 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_div_status);
/**
- * si476x_cmd_am_seek_start - send 'FM_SEEK_START' command to the
+ * si476x_core_cmd_am_seek_start - send 'FM_SEEK_START' command to the
* device
* @core: - device to send the command to
* @seekup: - if set the direction of the search is 'up'
diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c
index c1d7b845244e..a2635c2d9d1a 100644
--- a/drivers/mfd/si476x-i2c.c
+++ b/drivers/mfd/si476x-i2c.c
@@ -350,7 +350,7 @@ static inline void si476x_core_start_rds_drainer_once(struct si476x_core *core)
mutex_unlock(&core->rds_drainer_status_lock);
}
/**
- * si476x_drain_rds_fifo() - RDS buffer drainer.
+ * si476x_core_drain_rds_fifo() - RDS buffer drainer.
* @work: struct work_struct being ppassed to the function by the
* kernel.
*
@@ -454,7 +454,7 @@ int si476x_core_i2c_xfer(struct si476x_core *core,
EXPORT_SYMBOL_GPL(si476x_core_i2c_xfer);
/**
- * si476x_get_status()
+ * si476x_core_get_status()
* @core: Core device structure
*
* Get the status byte of the core device by berforming one byte I2C
@@ -473,7 +473,7 @@ static int si476x_core_get_status(struct si476x_core *core)
}
/**
- * si476x_get_and_signal_status() - IRQ dispatcher
+ * si476x_core_get_and_signal_status() - IRQ dispatcher
* @core: Core device structure
*
* Dispatch the arrived interrupt request based on the value of the
@@ -532,7 +532,7 @@ static irqreturn_t si476x_core_interrupt(int irq, void *dev)
}
/**
- * si476x_firmware_version_to_revision()
+ * si476x_core_fwver_to_revision()
* @core: Core device structure
* @func: Selects the boot function of the device:
* *_BOOTLOADER - Boot loader
@@ -603,7 +603,7 @@ unknown_revision:
}
/**
- * si476x_get_revision_info()
+ * si476x_core_get_revision_info()
* @core: Core device structure
*
* Get the firmware version number of the device. It is done in
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index 6d2f4a0a901d..bc0a2c38653e 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -1190,13 +1190,13 @@ static int sm501_register_gpio_i2c(struct sm501_devdata *sm,
return 0;
}
-/* sm501_dbg_regs
+/* dbg_regs_show
*
* Debug attribute to attach to parent device to show core registers
*/
-static ssize_t sm501_dbg_regs(struct device *dev,
- struct device_attribute *attr, char *buff)
+static ssize_t dbg_regs_show(struct device *dev,
+ struct device_attribute *attr, char *buff)
{
struct sm501_devdata *sm = dev_get_drvdata(dev) ;
unsigned int reg;
@@ -1213,7 +1213,7 @@ static ssize_t sm501_dbg_regs(struct device *dev,
}
-static DEVICE_ATTR(dbg_regs, 0444, sm501_dbg_regs, NULL);
+static DEVICE_ATTR_RO(dbg_regs);
/* sm501_init_reg
*
diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c
index 61aa020199f5..cd2f45257dc1 100644
--- a/drivers/mfd/stmpe-i2c.c
+++ b/drivers/mfd/stmpe-i2c.c
@@ -109,7 +109,7 @@ static const struct i2c_device_id stmpe_i2c_id[] = {
{ "stmpe2403", STMPE2403 },
{ }
};
-MODULE_DEVICE_TABLE(i2c, stmpe_id);
+MODULE_DEVICE_TABLE(i2c, stmpe_i2c_id);
static struct i2c_driver stmpe_i2c_driver = {
.driver = {
diff --git a/drivers/mfd/sun6i-prcm.c b/drivers/mfd/sun6i-prcm.c
index c31927d4bbbe..ee03db0b8485 100644
--- a/drivers/mfd/sun6i-prcm.c
+++ b/drivers/mfd/sun6i-prcm.c
@@ -20,43 +20,23 @@ struct prcm_data {
};
static const struct resource sun6i_a31_ar100_clk_res[] = {
- {
- .start = 0x0,
- .end = 0x3,
- .flags = IORESOURCE_MEM,
- },
+ DEFINE_RES_MEM(0x0, 4)
};
static const struct resource sun6i_a31_apb0_clk_res[] = {
- {
- .start = 0xc,
- .end = 0xf,
- .flags = IORESOURCE_MEM,
- },
+ DEFINE_RES_MEM(0xc, 4)
};
static const struct resource sun6i_a31_apb0_gates_clk_res[] = {
- {
- .start = 0x28,
- .end = 0x2b,
- .flags = IORESOURCE_MEM,
- },
+ DEFINE_RES_MEM(0x28, 4)
};
static const struct resource sun6i_a31_ir_clk_res[] = {
- {
- .start = 0x54,
- .end = 0x57,
- .flags = IORESOURCE_MEM,
- },
+ DEFINE_RES_MEM(0x54, 4)
};
static const struct resource sun6i_a31_apb0_rstc_res[] = {
- {
- .start = 0xb0,
- .end = 0xb3,
- .flags = IORESOURCE_MEM,
- },
+ DEFINE_RES_MEM(0xb0, 4)
};
static const struct resource sun8i_codec_analog_res[] = {
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index c6f139b2e0c0..765c0210cb52 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -108,6 +108,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
syscon_config.max_register = resource_size(&res) - reg_io_width;
regmap = regmap_init_mmio(NULL, base, &syscon_config);
+ kfree(syscon_config.name);
if (IS_ERR(regmap)) {
pr_err("regmap init failed\n");
ret = PTR_ERR(regmap);
@@ -144,7 +145,6 @@ err_clk:
regmap_exit(regmap);
err_regmap:
iounmap(base);
- kfree(syscon_config.name);
err_map:
kfree(syscon);
return ERR_PTR(ret);
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 70da0c4ae457..5369c67e3280 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -37,16 +37,8 @@ enum {
};
static const struct resource t7l66xb_mmc_resources[] = {
- {
- .start = 0x800,
- .end = 0x9ff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = IRQ_T7L66XB_MMC,
- .end = IRQ_T7L66XB_MMC,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_MEM(0x800, 0x200),
+ DEFINE_RES_IRQ(IRQ_T7L66XB_MMC)
};
#define SCR_REVID 0x08 /* b Revision ID */
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c
index faecbca6dba3..9393ee60a656 100644
--- a/drivers/mfd/timberdale.c
+++ b/drivers/mfd/timberdale.c
@@ -623,8 +623,8 @@ static const struct mfd_cell timberdale_cells_bar2[] = {
},
};
-static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t fw_ver_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct timberdale_device *priv = dev_get_drvdata(dev);
@@ -632,7 +632,7 @@ static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr,
priv->fw.config);
}
-static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
+static DEVICE_ATTR_RO(fw_ver);
/*--------------------------------------------------------------------------*/
diff --git a/drivers/mfd/tps68470.c b/drivers/mfd/tps68470.c
deleted file mode 100644
index 4a4df4ffd18c..000000000000
--- a/drivers/mfd/tps68470.c
+++ /dev/null
@@ -1,97 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * TPS68470 chip Parent driver
- *
- * Copyright (C) 2017 Intel Corporation
- *
- * Authors:
- * Rajmohan Mani <rajmohan.mani@intel.com>
- * Tianshu Qiu <tian.shu.qiu@intel.com>
- * Jian Xu Zheng <jian.xu.zheng@intel.com>
- * Yuning Pu <yuning.pu@intel.com>
- */
-
-#include <linux/acpi.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/tps68470.h>
-#include <linux/regmap.h>
-
-static const struct mfd_cell tps68470s[] = {
- { .name = "tps68470-gpio" },
- { .name = "tps68470_pmic_opregion" },
-};
-
-static const struct regmap_config tps68470_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = TPS68470_REG_MAX,
-};
-
-static int tps68470_chip_init(struct device *dev, struct regmap *regmap)
-{
- unsigned int version;
- int ret;
-
- /* Force software reset */
- ret = regmap_write(regmap, TPS68470_REG_RESET, TPS68470_REG_RESET_MASK);
- if (ret)
- return ret;
-
- ret = regmap_read(regmap, TPS68470_REG_REVID, &version);
- if (ret) {
- dev_err(dev, "Failed to read revision register: %d\n", ret);
- return ret;
- }
-
- dev_info(dev, "TPS68470 REVID: 0x%x\n", version);
-
- return 0;
-}
-
-static int tps68470_probe(struct i2c_client *client)
-{
- struct device *dev = &client->dev;
- struct regmap *regmap;
- int ret;
-
- regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);
- if (IS_ERR(regmap)) {
- dev_err(dev, "devm_regmap_init_i2c Error %ld\n",
- PTR_ERR(regmap));
- return PTR_ERR(regmap);
- }
-
- i2c_set_clientdata(client, regmap);
-
- ret = tps68470_chip_init(dev, regmap);
- if (ret < 0) {
- dev_err(dev, "TPS68470 Init Error %d\n", ret);
- return ret;
- }
-
- ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, tps68470s,
- ARRAY_SIZE(tps68470s), NULL, 0, NULL);
- if (ret < 0) {
- dev_err(dev, "devm_mfd_add_devices failed: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static const struct acpi_device_id tps68470_acpi_ids[] = {
- {"INT3472"},
- {},
-};
-
-static struct i2c_driver tps68470_driver = {
- .driver = {
- .name = "tps68470",
- .acpi_match_table = tps68470_acpi_ids,
- },
- .probe_new = tps68470_probe,
-};
-builtin_i2c_driver(tps68470_driver);
diff --git a/drivers/mfd/tps80031.c b/drivers/mfd/tps80031.c
index 902e33548dd0..3c4e62c3406a 100644
--- a/drivers/mfd/tps80031.c
+++ b/drivers/mfd/tps80031.c
@@ -35,11 +35,7 @@
#include <linux/slab.h>
static const struct resource tps80031_rtc_resources[] = {
- {
- .start = TPS80031_INT_RTC_ALARM,
- .end = TPS80031_INT_RTC_ALARM,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ(TPS80031_INT_RTC_ALARM),
};
/* TPS80031 sub mfd devices */
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 20cf8cfe4f3b..289b556dede2 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -485,7 +485,7 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
EXPORT_SYMBOL(twl_i2c_read);
/**
- * twl_regcache_bypass - Configure the regcache bypass for the regmap associated
+ * twl_set_regcache_bypass - Configure the regcache bypass for the regmap associated
* with the module
* @mod_no: module number
* @enable: Regcache bypass state
diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c
index ecc9e9fc331d..6a389737c615 100644
--- a/drivers/mfd/ucb1x00-assabet.c
+++ b/drivers/mfd/ucb1x00-assabet.c
@@ -28,7 +28,7 @@ static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
ucb1x00_adc_disable(ucb); \
return sprintf(buf, "%d\n", val); \
} \
-static DEVICE_ATTR(name,0444,name##_show,NULL)
+static DEVICE_ATTR_RO(name)
UCB1X00_ATTR(vbatt, UCB_ADC_INP_AD1);
UCB1X00_ATTR(vcharger, UCB_ADC_INP_AD0);
diff --git a/drivers/mfd/wcd934x.c b/drivers/mfd/wcd934x.c
index c274d733b656..aa19a6a4fdbf 100644
--- a/drivers/mfd/wcd934x.c
+++ b/drivers/mfd/wcd934x.c
@@ -17,6 +17,21 @@
#include <linux/regulator/consumer.h>
#include <linux/slimbus.h>
+#define WCD934X_REGMAP_IRQ_REG(_irq, _off, _mask) \
+ [_irq] = { \
+ .reg_offset = (_off), \
+ .mask = (_mask), \
+ .type = { \
+ .type_reg_offset = (_off), \
+ .types_supported = IRQ_TYPE_EDGE_BOTH, \
+ .type_reg_mask = (_mask), \
+ .type_level_low_val = (_mask), \
+ .type_level_high_val = (_mask), \
+ .type_falling_val = 0, \
+ .type_rising_val = 0, \
+ }, \
+ }
+
static const struct mfd_cell wcd934x_devices[] = {
{
.name = "wcd934x-codec",
@@ -30,32 +45,15 @@ static const struct mfd_cell wcd934x_devices[] = {
};
static const struct regmap_irq wcd934x_irqs[] = {
- [WCD934X_IRQ_SLIMBUS] = {
- .reg_offset = 0,
- .mask = BIT(0),
- .type = {
- .type_reg_offset = 0,
- .types_supported = IRQ_TYPE_EDGE_BOTH,
- .type_reg_mask = BIT(0),
- .type_level_low_val = BIT(0),
- .type_level_high_val = BIT(0),
- .type_falling_val = 0,
- .type_rising_val = 0,
- },
- },
- [WCD934X_IRQ_SOUNDWIRE] = {
- .reg_offset = 2,
- .mask = BIT(4),
- .type = {
- .type_reg_offset = 2,
- .types_supported = IRQ_TYPE_EDGE_BOTH,
- .type_reg_mask = BIT(4),
- .type_level_low_val = BIT(4),
- .type_level_high_val = BIT(4),
- .type_falling_val = 0,
- .type_rising_val = 0,
- },
- },
+ WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_SLIMBUS, 0, BIT(0)),
+ WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_HPH_PA_OCPL_FAULT, 0, BIT(2)),
+ WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_HPH_PA_OCPR_FAULT, 0, BIT(3)),
+ WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_MBHC_SW_DET, 1, BIT(0)),
+ WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_MBHC_ELECT_INS_REM_DET, 1, BIT(1)),
+ WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_MBHC_BUTTON_PRESS_DET, 1, BIT(2)),
+ WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET, 1, BIT(3)),
+ WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 1, BIT(4)),
+ WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_SOUNDWIRE, 2, BIT(4)),
};
static const struct regmap_irq_chip wcd934x_regmap_irq_chip = {
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index bcef08f58fb3..d2f444d2ae78 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -109,7 +109,7 @@ static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
}
/**
- * wm831x_reg_unlock: Unlock user keyed registers
+ * wm831x_reg_lock: Unlock user keyed registers
*
* The WM831x has a user key preventing writes to particularly
* critical registers. This function locks those registers,
@@ -622,18 +622,8 @@ static const struct resource wm831x_dcdc1_resources[] = {
.end = WM831X_DC1_DVS_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_DC1,
- .end = WM831X_IRQ_UV_DC1,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "HC",
- .start = WM831X_IRQ_HC_DC1,
- .end = WM831X_IRQ_HC_DC1,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_DC1, "UV"),
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_HC_DC1, "HC"),
};
@@ -643,18 +633,8 @@ static const struct resource wm831x_dcdc2_resources[] = {
.end = WM831X_DC2_DVS_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_DC2,
- .end = WM831X_IRQ_UV_DC2,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "HC",
- .start = WM831X_IRQ_HC_DC2,
- .end = WM831X_IRQ_HC_DC2,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_DC2, "UV"),
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_HC_DC2, "HC"),
};
static const struct resource wm831x_dcdc3_resources[] = {
@@ -663,12 +643,7 @@ static const struct resource wm831x_dcdc3_resources[] = {
.end = WM831X_DC3_SLEEP_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_DC3,
- .end = WM831X_IRQ_UV_DC3,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_DC3, "UV"),
};
static const struct resource wm831x_dcdc4_resources[] = {
@@ -677,12 +652,7 @@ static const struct resource wm831x_dcdc4_resources[] = {
.end = WM831X_DC4_SLEEP_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_DC4,
- .end = WM831X_IRQ_UV_DC4,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_DC4, "UV"),
};
static const struct resource wm8320_dcdc4_buck_resources[] = {
@@ -691,12 +661,7 @@ static const struct resource wm8320_dcdc4_buck_resources[] = {
.end = WM832X_DC4_SLEEP_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_DC4,
- .end = WM831X_IRQ_UV_DC4,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_DC4, "UV"),
};
static const struct resource wm831x_gpio_resources[] = {
@@ -713,11 +678,7 @@ static const struct resource wm831x_isink1_resources[] = {
.end = WM831X_CURRENT_SINK_1,
.flags = IORESOURCE_REG,
},
- {
- .start = WM831X_IRQ_CS1,
- .end = WM831X_IRQ_CS1,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ(WM831X_IRQ_CS1),
};
static const struct resource wm831x_isink2_resources[] = {
@@ -726,11 +687,7 @@ static const struct resource wm831x_isink2_resources[] = {
.end = WM831X_CURRENT_SINK_2,
.flags = IORESOURCE_REG,
},
- {
- .start = WM831X_IRQ_CS2,
- .end = WM831X_IRQ_CS2,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ(WM831X_IRQ_CS2),
};
static const struct resource wm831x_ldo1_resources[] = {
@@ -739,12 +696,7 @@ static const struct resource wm831x_ldo1_resources[] = {
.end = WM831X_LDO1_SLEEP_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_LDO1,
- .end = WM831X_IRQ_UV_LDO1,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO1, "UV"),
};
static const struct resource wm831x_ldo2_resources[] = {
@@ -753,12 +705,7 @@ static const struct resource wm831x_ldo2_resources[] = {
.end = WM831X_LDO2_SLEEP_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_LDO2,
- .end = WM831X_IRQ_UV_LDO2,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO2, "UV"),
};
static const struct resource wm831x_ldo3_resources[] = {
@@ -767,12 +714,7 @@ static const struct resource wm831x_ldo3_resources[] = {
.end = WM831X_LDO3_SLEEP_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_LDO3,
- .end = WM831X_IRQ_UV_LDO3,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO3, "UV"),
};
static const struct resource wm831x_ldo4_resources[] = {
@@ -781,12 +723,7 @@ static const struct resource wm831x_ldo4_resources[] = {
.end = WM831X_LDO4_SLEEP_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_LDO4,
- .end = WM831X_IRQ_UV_LDO4,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO4, "UV"),
};
static const struct resource wm831x_ldo5_resources[] = {
@@ -795,12 +732,7 @@ static const struct resource wm831x_ldo5_resources[] = {
.end = WM831X_LDO5_SLEEP_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_LDO5,
- .end = WM831X_IRQ_UV_LDO5,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO5, "UV"),
};
static const struct resource wm831x_ldo6_resources[] = {
@@ -809,12 +741,7 @@ static const struct resource wm831x_ldo6_resources[] = {
.end = WM831X_LDO6_SLEEP_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_LDO6,
- .end = WM831X_IRQ_UV_LDO6,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO6, "UV"),
};
static const struct resource wm831x_ldo7_resources[] = {
@@ -823,12 +750,7 @@ static const struct resource wm831x_ldo7_resources[] = {
.end = WM831X_LDO7_SLEEP_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_LDO7,
- .end = WM831X_IRQ_UV_LDO7,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO7, "UV"),
};
static const struct resource wm831x_ldo8_resources[] = {
@@ -837,12 +759,7 @@ static const struct resource wm831x_ldo8_resources[] = {
.end = WM831X_LDO8_SLEEP_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_LDO8,
- .end = WM831X_IRQ_UV_LDO8,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO8, "UV"),
};
static const struct resource wm831x_ldo9_resources[] = {
@@ -851,12 +768,7 @@ static const struct resource wm831x_ldo9_resources[] = {
.end = WM831X_LDO9_SLEEP_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_LDO9,
- .end = WM831X_IRQ_UV_LDO9,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO9, "UV"),
};
static const struct resource wm831x_ldo10_resources[] = {
@@ -865,12 +777,7 @@ static const struct resource wm831x_ldo10_resources[] = {
.end = WM831X_LDO10_SLEEP_CONTROL,
.flags = IORESOURCE_REG,
},
- {
- .name = "UV",
- .start = WM831X_IRQ_UV_LDO10,
- .end = WM831X_IRQ_UV_LDO10,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO10, "UV"),
};
static const struct resource wm831x_ldo11_resources[] = {
@@ -882,96 +789,27 @@ static const struct resource wm831x_ldo11_resources[] = {
};
static const struct resource wm831x_on_resources[] = {
- {
- .start = WM831X_IRQ_ON,
- .end = WM831X_IRQ_ON,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ(WM831X_IRQ_ON),
};
static const struct resource wm831x_power_resources[] = {
- {
- .name = "SYSLO",
- .start = WM831X_IRQ_PPM_SYSLO,
- .end = WM831X_IRQ_PPM_SYSLO,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "PWR SRC",
- .start = WM831X_IRQ_PPM_PWR_SRC,
- .end = WM831X_IRQ_PPM_PWR_SRC,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "USB CURR",
- .start = WM831X_IRQ_PPM_USB_CURR,
- .end = WM831X_IRQ_PPM_USB_CURR,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "BATT HOT",
- .start = WM831X_IRQ_CHG_BATT_HOT,
- .end = WM831X_IRQ_CHG_BATT_HOT,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "BATT COLD",
- .start = WM831X_IRQ_CHG_BATT_COLD,
- .end = WM831X_IRQ_CHG_BATT_COLD,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "BATT FAIL",
- .start = WM831X_IRQ_CHG_BATT_FAIL,
- .end = WM831X_IRQ_CHG_BATT_FAIL,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "OV",
- .start = WM831X_IRQ_CHG_OV,
- .end = WM831X_IRQ_CHG_OV,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "END",
- .start = WM831X_IRQ_CHG_END,
- .end = WM831X_IRQ_CHG_END,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "TO",
- .start = WM831X_IRQ_CHG_TO,
- .end = WM831X_IRQ_CHG_TO,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "MODE",
- .start = WM831X_IRQ_CHG_MODE,
- .end = WM831X_IRQ_CHG_MODE,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "START",
- .start = WM831X_IRQ_CHG_START,
- .end = WM831X_IRQ_CHG_START,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_PPM_SYSLO, "SYSLO"),
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_PPM_PWR_SRC, "PWR SRC"),
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_PPM_USB_CURR, "USB CURR"),
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_BATT_HOT, "BATT HOT"),
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_BATT_COLD, "BATT COLD"),
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_BATT_FAIL, "BATT FAIL"),
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_OV, "OV"),
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_END, "END"),
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_TO, "TO"),
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_MODE, "MODE"),
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_START, "START"),
};
static const struct resource wm831x_rtc_resources[] = {
- {
- .name = "PER",
- .start = WM831X_IRQ_RTC_PER,
- .end = WM831X_IRQ_RTC_PER,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ALM",
- .start = WM831X_IRQ_RTC_ALM,
- .end = WM831X_IRQ_RTC_ALM,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_RTC_PER, "PER"),
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_RTC_ALM, "ALM"),
};
static const struct resource wm831x_status1_resources[] = {
@@ -991,26 +829,12 @@ static const struct resource wm831x_status2_resources[] = {
};
static const struct resource wm831x_touch_resources[] = {
- {
- .name = "TCHPD",
- .start = WM831X_IRQ_TCHPD,
- .end = WM831X_IRQ_TCHPD,
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "TCHDATA",
- .start = WM831X_IRQ_TCHDATA,
- .end = WM831X_IRQ_TCHDATA,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_TCHPD, "TCHPD"),
+ DEFINE_RES_IRQ_NAMED(WM831X_IRQ_TCHDATA, "TCHDATA"),
};
static const struct resource wm831x_wdt_resources[] = {
- {
- .start = WM831X_IRQ_WDOG_TO,
- .end = WM831X_IRQ_WDOG_TO,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_IRQ(WM831X_IRQ_WDOG_TO),
};
static const struct mfd_cell wm8310_devs[] = {
diff --git a/drivers/mfd/wm831x-otp.c b/drivers/mfd/wm831x-otp.c
index afe59d52dd74..25f5d9fe33a1 100644
--- a/drivers/mfd/wm831x-otp.c
+++ b/drivers/mfd/wm831x-otp.c
@@ -38,8 +38,8 @@ static int wm831x_unique_id_read(struct wm831x *wm831x, char *id)
return 0;
}
-static ssize_t wm831x_unique_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t unique_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct wm831x *wm831x = dev_get_drvdata(dev);
int rval;
@@ -52,7 +52,7 @@ static ssize_t wm831x_unique_id_show(struct device *dev,
return sprintf(buf, "%*phN\n", WM831X_UNIQUE_ID_LEN, id);
}
-static DEVICE_ATTR(unique_id, 0444, wm831x_unique_id_show, NULL);
+static DEVICE_ATTR_RO(unique_id);
int wm831x_otp_init(struct wm831x *wm831x)
{
diff --git a/drivers/misc/bcm-vk/bcm_vk_dev.c b/drivers/misc/bcm-vk/bcm_vk_dev.c
index 6bfea3210389..ad639ee85b2a 100644
--- a/drivers/misc/bcm-vk/bcm_vk_dev.c
+++ b/drivers/misc/bcm-vk/bcm_vk_dev.c
@@ -9,6 +9,7 @@
#include <linux/fs.h>
#include <linux/idr.h>
#include <linux/interrupt.h>
+#include <linux/panic_notifier.h>
#include <linux/kref.h>
#include <linux/module.h>
#include <linux/mutex.h>
diff --git a/drivers/misc/bcm-vk/bcm_vk_msg.c b/drivers/misc/bcm-vk/bcm_vk_msg.c
index f40cf08a6192..066b9ef7fcd7 100644
--- a/drivers/misc/bcm-vk/bcm_vk_msg.c
+++ b/drivers/misc/bcm-vk/bcm_vk_msg.c
@@ -354,8 +354,7 @@ static void bcm_vk_drain_all_pend(struct device *dev,
for (num = 0; num < chan->q_nr; num++) {
list_for_each_entry_safe(entry, tmp, &chan->pendq[num], node) {
if ((!ctx) || (entry->ctx->idx == ctx->idx)) {
- list_del(&entry->node);
- list_add_tail(&entry->node, &del_q);
+ list_move_tail(&entry->node, &del_q);
}
}
}
@@ -701,8 +700,7 @@ int bcm_vk_send_shutdown_msg(struct bcm_vk *vk, u32 shut_type,
return -EINVAL;
}
- entry = kzalloc(sizeof(*entry) +
- sizeof(struct vk_msg_blk), GFP_KERNEL);
+ entry = kzalloc(struct_size(entry, to_v_msg, 1), GFP_KERNEL);
if (!entry)
return -ENOMEM;
diff --git a/drivers/misc/bcm-vk/bcm_vk_msg.h b/drivers/misc/bcm-vk/bcm_vk_msg.h
index 4eaad84825d6..56784c8896d8 100644
--- a/drivers/misc/bcm-vk/bcm_vk_msg.h
+++ b/drivers/misc/bcm-vk/bcm_vk_msg.h
@@ -116,7 +116,7 @@ struct bcm_vk_wkent {
u32 usr_msg_id;
u32 to_v_blks;
u32 seq_num;
- struct vk_msg_blk to_v_msg[0];
+ struct vk_msg_blk to_v_msg[];
};
/* queue stats counters */
diff --git a/drivers/misc/bcm-vk/bcm_vk_tty.c b/drivers/misc/bcm-vk/bcm_vk_tty.c
index 4d02692ecfc7..dae9eeed84a2 100644
--- a/drivers/misc/bcm-vk/bcm_vk_tty.c
+++ b/drivers/misc/bcm-vk/bcm_vk_tty.c
@@ -214,7 +214,7 @@ static int bcm_vk_tty_write(struct tty_struct *tty,
return count;
}
-static int bcm_vk_tty_write_room(struct tty_struct *tty)
+static unsigned int bcm_vk_tty_write_room(struct tty_struct *tty)
{
struct bcm_vk *vk = dev_get_drvdata(tty->dev);
diff --git a/drivers/misc/cardreader/alcor_pci.c b/drivers/misc/cardreader/alcor_pci.c
index cd402c89189e..de6d44a158bb 100644
--- a/drivers/misc/cardreader/alcor_pci.c
+++ b/drivers/misc/cardreader/alcor_pci.c
@@ -139,7 +139,13 @@ static void alcor_pci_init_check_aspm(struct alcor_pci_priv *priv)
u32 val32;
priv->pdev_cap_off = alcor_pci_find_cap_offset(priv, priv->pdev);
- priv->parent_cap_off = alcor_pci_find_cap_offset(priv,
+ /*
+ * A device might be attached to root complex directly and
+ * priv->parent_pdev will be NULL. In this case we don't check its
+ * capability and disable ASPM completely.
+ */
+ if (priv->parent_pdev)
+ priv->parent_cap_off = alcor_pci_find_cap_offset(priv,
priv->parent_pdev);
if ((priv->pdev_cap_off == 0) || (priv->parent_cap_off == 0)) {
diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c
index bd3bd32333c5..3dbdce96fae0 100644
--- a/drivers/misc/cxl/file.c
+++ b/drivers/misc/cxl/file.c
@@ -569,7 +569,8 @@ static int cxl_add_chardev(struct cxl_afu *afu, dev_t devt, struct cdev *cdev,
int rc;
cdev_init(cdev, fops);
- if ((rc = cdev_add(cdev, devt, 1))) {
+ rc = cdev_add(cdev, devt, 1);
+ if (rc) {
dev_err(&afu->dev, "Unable to add %s chardev: %i\n", desc, rc);
return rc;
}
@@ -577,8 +578,8 @@ static int cxl_add_chardev(struct cxl_afu *afu, dev_t devt, struct cdev *cdev,
dev = device_create(cxl_class, &afu->dev, devt, afu,
"afu%i.%i%s", afu->adapter->adapter_num, afu->slice, postfix);
if (IS_ERR(dev)) {
- dev_err(&afu->dev, "Unable to create %s chardev in sysfs: %i\n", desc, rc);
rc = PTR_ERR(dev);
+ dev_err(&afu->dev, "Unable to create %s chardev in sysfs: %i\n", desc, rc);
goto err;
}
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 0f791bfdc1f5..f0a7531f354c 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -32,12 +32,13 @@ config EEPROM_AT24
will be called at24.
config EEPROM_AT25
- tristate "SPI EEPROMs from most vendors"
+ tristate "SPI EEPROMs (FRAMs) from most vendors"
depends on SPI && SYSFS
select NVMEM
select NVMEM_SYSFS
help
- Enable this driver to get read/write support to most SPI EEPROMs,
+ Enable this driver to get read/write support to most SPI EEPROMs
+ and Cypress FRAMs,
after you configure the board init code to know about each eeprom
on your target board.
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index b76e4901b4a4..4d09b672ac3c 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* at25.c -- support most SPI EEPROMs, such as Atmel AT25 models
+ * and Cypress FRAMs FM25 models
*
* Copyright (C) 2006 David Brownell
*/
@@ -16,6 +17,9 @@
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
#include <linux/property.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/math.h>
/*
* NOTE: this is an *EEPROM* driver. The vagaries of product naming
@@ -27,6 +31,7 @@
* AT25M02, AT25128B
*/
+#define FM25_SN_LEN 8 /* serial number length */
struct at25_data {
struct spi_device *spi;
struct mutex lock;
@@ -34,6 +39,7 @@ struct at25_data {
unsigned addrlen;
struct nvmem_config nvmem_config;
struct nvmem_device *nvmem;
+ u8 sernum[FM25_SN_LEN];
};
#define AT25_WREN 0x06 /* latch the write enable */
@@ -42,6 +48,9 @@ struct at25_data {
#define AT25_WRSR 0x01 /* write status register */
#define AT25_READ 0x03 /* read byte(s) */
#define AT25_WRITE 0x02 /* write byte(s)/sector */
+#define FM25_SLEEP 0xb9 /* enter sleep mode */
+#define FM25_RDID 0x9f /* read device ID */
+#define FM25_RDSN 0xc3 /* read S/N */
#define AT25_SR_nRDY 0x01 /* nRDY = write-in-progress */
#define AT25_SR_WEN 0x02 /* write enable (latched) */
@@ -51,6 +60,8 @@ struct at25_data {
#define AT25_INSTR_BIT3 0x08 /* Additional address bit in instr */
+#define FM25_ID_LEN 9 /* ID length */
+
#define EE_MAXADDRLEN 3 /* 24 bit addresses, up to 2 MBytes */
/* Specs often allow 5 msec for a page write, sometimes 20 msec;
@@ -129,6 +140,51 @@ static int at25_ee_read(void *priv, unsigned int offset,
return status;
}
+/*
+ * read extra registers as ID or serial number
+ */
+static int fm25_aux_read(struct at25_data *at25, u8 *buf, uint8_t command,
+ int len)
+{
+ int status;
+ struct spi_transfer t[2];
+ struct spi_message m;
+
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
+
+ t[0].tx_buf = &command;
+ t[0].len = 1;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].rx_buf = buf;
+ t[1].len = len;
+ spi_message_add_tail(&t[1], &m);
+
+ mutex_lock(&at25->lock);
+
+ status = spi_sync(at25->spi, &m);
+ dev_dbg(&at25->spi->dev, "read %d aux bytes --> %d\n", len, status);
+
+ mutex_unlock(&at25->lock);
+ return status;
+}
+
+static ssize_t sernum_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct at25_data *at25;
+
+ at25 = dev_get_drvdata(dev);
+ return sysfs_emit(buf, "%*ph\n", (int)sizeof(at25->sernum), at25->sernum);
+}
+static DEVICE_ATTR_RO(sernum);
+
+static struct attribute *sernum_attrs[] = {
+ &dev_attr_sernum.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(sernum);
+
static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count)
{
struct at25_data *at25 = priv;
@@ -303,34 +359,39 @@ static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
return 0;
}
+static const struct of_device_id at25_of_match[] = {
+ { .compatible = "atmel,at25",},
+ { .compatible = "cypress,fm25",},
+ { }
+};
+MODULE_DEVICE_TABLE(of, at25_of_match);
+
static int at25_probe(struct spi_device *spi)
{
struct at25_data *at25 = NULL;
struct spi_eeprom chip;
int err;
int sr;
- int addrlen;
+ u8 id[FM25_ID_LEN];
+ u8 sernum[FM25_SN_LEN];
+ int i;
+ const struct of_device_id *match;
+ bool is_fram = 0;
+
+ match = of_match_device(of_match_ptr(at25_of_match), &spi->dev);
+ if (match && !strcmp(match->compatible, "cypress,fm25"))
+ is_fram = 1;
/* Chip description */
if (!spi->dev.platform_data) {
- err = at25_fw_to_chip(&spi->dev, &chip);
- if (err)
- return err;
+ if (!is_fram) {
+ err = at25_fw_to_chip(&spi->dev, &chip);
+ if (err)
+ return err;
+ }
} else
chip = *(struct spi_eeprom *)spi->dev.platform_data;
- /* For now we only support 8/16/24 bit addressing */
- if (chip.flags & EE_ADDR1)
- addrlen = 1;
- else if (chip.flags & EE_ADDR2)
- addrlen = 2;
- else if (chip.flags & EE_ADDR3)
- addrlen = 3;
- else {
- dev_dbg(&spi->dev, "unsupported address type\n");
- return -EINVAL;
- }
-
/* Ping the chip ... the status register is pretty portable,
* unlike probing manufacturer IDs. We do expect that system
* firmware didn't write it in the past few milliseconds!
@@ -349,9 +410,51 @@ static int at25_probe(struct spi_device *spi)
at25->chip = chip;
at25->spi = spi;
spi_set_drvdata(spi, at25);
- at25->addrlen = addrlen;
- at25->nvmem_config.type = NVMEM_TYPE_EEPROM;
+ if (is_fram) {
+ /* Get ID of chip */
+ fm25_aux_read(at25, id, FM25_RDID, FM25_ID_LEN);
+ if (id[6] != 0xc2) {
+ dev_err(&spi->dev,
+ "Error: no Cypress FRAM (id %02x)\n", id[6]);
+ return -ENODEV;
+ }
+ /* set size found in ID */
+ if (id[7] < 0x21 || id[7] > 0x26) {
+ dev_err(&spi->dev, "Error: unsupported size (id %02x)\n", id[7]);
+ return -ENODEV;
+ }
+ chip.byte_len = int_pow(2, id[7] - 0x21 + 4) * 1024;
+
+ if (at25->chip.byte_len > 64 * 1024)
+ at25->chip.flags |= EE_ADDR3;
+ else
+ at25->chip.flags |= EE_ADDR2;
+
+ if (id[8]) {
+ fm25_aux_read(at25, sernum, FM25_RDSN, FM25_SN_LEN);
+ /* swap byte order */
+ for (i = 0; i < FM25_SN_LEN; i++)
+ at25->sernum[i] = sernum[FM25_SN_LEN - 1 - i];
+ }
+
+ at25->chip.page_size = PAGE_SIZE;
+ strncpy(at25->chip.name, "fm25", sizeof(at25->chip.name));
+ }
+
+ /* For now we only support 8/16/24 bit addressing */
+ if (at25->chip.flags & EE_ADDR1)
+ at25->addrlen = 1;
+ else if (at25->chip.flags & EE_ADDR2)
+ at25->addrlen = 2;
+ else if (at25->chip.flags & EE_ADDR3)
+ at25->addrlen = 3;
+ else {
+ dev_dbg(&spi->dev, "unsupported address type\n");
+ return -EINVAL;
+ }
+
+ at25->nvmem_config.type = is_fram ? NVMEM_TYPE_FRAM : NVMEM_TYPE_EEPROM;
at25->nvmem_config.name = dev_name(&spi->dev);
at25->nvmem_config.dev = &spi->dev;
at25->nvmem_config.read_only = chip.flags & EE_READONLY;
@@ -370,27 +473,22 @@ static int at25_probe(struct spi_device *spi)
if (IS_ERR(at25->nvmem))
return PTR_ERR(at25->nvmem);
- dev_info(&spi->dev, "%d %s %s eeprom%s, pagesize %u\n",
- (chip.byte_len < 1024) ? chip.byte_len : (chip.byte_len / 1024),
- (chip.byte_len < 1024) ? "Byte" : "KByte",
- at25->chip.name,
- (chip.flags & EE_READONLY) ? " (readonly)" : "",
- at25->chip.page_size);
+ dev_info(&spi->dev, "%d %s %s %s%s, pagesize %u\n",
+ (chip.byte_len < 1024) ? chip.byte_len : (chip.byte_len / 1024),
+ (chip.byte_len < 1024) ? "Byte" : "KByte",
+ at25->chip.name, is_fram ? "fram" : "eeprom",
+ (chip.flags & EE_READONLY) ? " (readonly)" : "",
+ at25->chip.page_size);
return 0;
}
/*-------------------------------------------------------------------------*/
-static const struct of_device_id at25_of_match[] = {
- { .compatible = "atmel,at25", },
- { }
-};
-MODULE_DEVICE_TABLE(of, at25_of_match);
-
static struct spi_driver at25_driver = {
.driver = {
.name = "at25",
.of_match_table = at25_of_match,
+ .dev_groups = sernum_groups,
},
.probe = at25_probe,
};
diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c
index 252e15ba65e1..bb9c4512c968 100644
--- a/drivers/misc/eeprom/ee1004.c
+++ b/drivers/misc/eeprom/ee1004.c
@@ -32,16 +32,17 @@
*/
#define EE1004_ADDR_SET_PAGE 0x36
-#define EE1004_EEPROM_SIZE 512
+#define EE1004_NUM_PAGES 2
#define EE1004_PAGE_SIZE 256
#define EE1004_PAGE_SHIFT 8
+#define EE1004_EEPROM_SIZE (EE1004_PAGE_SIZE * EE1004_NUM_PAGES)
/*
* Mutex protects ee1004_set_page and ee1004_dev_count, and must be held
* from page selection to end of read.
*/
static DEFINE_MUTEX(ee1004_bus_lock);
-static struct i2c_client *ee1004_set_page[2];
+static struct i2c_client *ee1004_set_page[EE1004_NUM_PAGES];
static unsigned int ee1004_dev_count;
static int ee1004_current_page;
@@ -71,40 +72,58 @@ static int ee1004_get_current_page(void)
return 0;
}
+static int ee1004_set_current_page(struct device *dev, int page)
+{
+ int ret;
+
+ if (page == ee1004_current_page)
+ return 0;
+
+ /* Data is ignored */
+ ret = i2c_smbus_write_byte(ee1004_set_page[page], 0x00);
+ /*
+ * 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 (ret == -ENXIO && ee1004_get_current_page() == page)
+ ret = 0;
+ if (ret < 0) {
+ dev_err(dev, "Failed to select page %d (%d)\n", page, ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "Selected page %d\n", page);
+ ee1004_current_page = page;
+
+ return 0;
+}
+
static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf,
unsigned int offset, size_t count)
{
- int status;
+ int status, page;
+
+ page = offset >> EE1004_PAGE_SHIFT;
+ offset &= (1 << EE1004_PAGE_SHIFT) - 1;
+
+ status = ee1004_set_current_page(&client->dev, page);
+ if (status)
+ return status;
- if (count > I2C_SMBUS_BLOCK_MAX)
- count = I2C_SMBUS_BLOCK_MAX;
/* Can't cross page boundaries */
- if (unlikely(offset + count > EE1004_PAGE_SIZE))
+ if (offset + count > EE1004_PAGE_SIZE)
count = EE1004_PAGE_SIZE - offset;
- status = i2c_smbus_read_i2c_block_data_or_emulated(client, offset,
- count, buf);
- dev_dbg(&client->dev, "read %zu@%d --> %d\n", count, offset, status);
-
- return status;
+ return i2c_smbus_read_i2c_block_data_or_emulated(client, offset, count, buf);
}
-static ssize_t ee1004_read(struct file *filp, struct kobject *kobj,
+static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct device *dev = kobj_to_dev(kobj);
- struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_client *client = kobj_to_i2c_client(kobj);
size_t requested = count;
- int page;
-
- if (unlikely(!count))
- return count;
-
- page = off >> EE1004_PAGE_SHIFT;
- if (unlikely(page > 1))
- return 0;
- off &= (1 << EE1004_PAGE_SHIFT) - 1;
+ int ret = 0;
/*
* Read data from chip, protecting against concurrent access to
@@ -113,139 +132,85 @@ static ssize_t ee1004_read(struct file *filp, struct kobject *kobj,
mutex_lock(&ee1004_bus_lock);
while (count) {
- int status;
-
- /* Select page */
- if (page != ee1004_current_page) {
- /* 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);
- mutex_unlock(&ee1004_bus_lock);
- return status;
- }
- dev_dbg(dev, "Selected page %d\n", page);
- ee1004_current_page = page;
- }
-
- status = ee1004_eeprom_read(client, buf, off, count);
- if (status < 0) {
- mutex_unlock(&ee1004_bus_lock);
- return status;
- }
- buf += status;
- off += status;
- count -= status;
+ ret = ee1004_eeprom_read(client, buf, off, count);
+ if (ret < 0)
+ goto out;
- if (off == EE1004_PAGE_SIZE) {
- page++;
- off = 0;
- }
+ buf += ret;
+ off += ret;
+ count -= ret;
}
-
+out:
mutex_unlock(&ee1004_bus_lock);
- return requested;
+ return ret < 0 ? ret : requested;
}
-static const struct bin_attribute eeprom_attr = {
- .attr = {
- .name = "eeprom",
- .mode = 0444,
- },
- .size = EE1004_EEPROM_SIZE,
- .read = ee1004_read,
+static BIN_ATTR_RO(eeprom, EE1004_EEPROM_SIZE);
+
+static struct bin_attribute *ee1004_attrs[] = {
+ &bin_attr_eeprom,
+ NULL
};
-static int ee1004_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+BIN_ATTRIBUTE_GROUPS(ee1004);
+
+static void ee1004_cleanup(int idx)
+{
+ if (--ee1004_dev_count == 0)
+ while (--idx >= 0) {
+ i2c_unregister_device(ee1004_set_page[idx]);
+ ee1004_set_page[idx] = NULL;
+ }
+}
+
+static int ee1004_probe(struct i2c_client *client)
{
int err, cnr = 0;
- const char *slow = NULL;
/* Make sure we can operate on this adapter */
if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_READ_BYTE |
- I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
- if (i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_READ_BYTE |
- I2C_FUNC_SMBUS_READ_WORD_DATA))
- slow = "word";
- else if (i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_READ_BYTE |
- I2C_FUNC_SMBUS_READ_BYTE_DATA))
- slow = "byte";
- else
- return -EPFNOSUPPORT;
- }
+ I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_READ_I2C_BLOCK) &&
+ !i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA))
+ return -EPFNOSUPPORT;
/* Use 2 dummy devices for page select command */
mutex_lock(&ee1004_bus_lock);
if (++ee1004_dev_count == 1) {
- for (cnr = 0; cnr < 2; cnr++) {
- ee1004_set_page[cnr] = i2c_new_dummy_device(client->adapter,
- EE1004_ADDR_SET_PAGE + cnr);
- if (IS_ERR(ee1004_set_page[cnr])) {
- dev_err(&client->dev,
- "address 0x%02x unavailable\n",
- EE1004_ADDR_SET_PAGE + cnr);
- err = PTR_ERR(ee1004_set_page[cnr]);
+ for (cnr = 0; cnr < EE1004_NUM_PAGES; cnr++) {
+ struct i2c_client *cl;
+
+ cl = i2c_new_dummy_device(client->adapter, EE1004_ADDR_SET_PAGE + cnr);
+ if (IS_ERR(cl)) {
+ err = PTR_ERR(cl);
goto err_clients;
}
+ ee1004_set_page[cnr] = cl;
}
- } else if (i2c_adapter_id(client->adapter) !=
- i2c_adapter_id(ee1004_set_page[0]->adapter)) {
+
+ /* Remember current page to avoid unneeded page select */
+ err = ee1004_get_current_page();
+ if (err < 0)
+ goto err_clients;
+ dev_dbg(&client->dev, "Currently selected page: %d\n", err);
+ ee1004_current_page = err;
+ } else if (client->adapter != ee1004_set_page[0]->adapter) {
dev_err(&client->dev,
"Driver only supports devices on a single I2C bus\n");
err = -EOPNOTSUPP;
goto err_clients;
}
-
- /* Remember current page to avoid unneeded page select */
- err = ee1004_get_current_page();
- if (err < 0)
- goto err_clients;
- ee1004_current_page = err;
- dev_dbg(&client->dev, "Currently selected page: %d\n",
- ee1004_current_page);
mutex_unlock(&ee1004_bus_lock);
- /* Create the sysfs eeprom file */
- err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
- if (err)
- goto err_clients_lock;
-
dev_info(&client->dev,
"%u byte EE1004-compliant SPD EEPROM, read-only\n",
EE1004_EEPROM_SIZE);
- if (slow)
- dev_notice(&client->dev,
- "Falling back to %s reads, performance will suffer\n",
- slow);
return 0;
- err_clients_lock:
- mutex_lock(&ee1004_bus_lock);
err_clients:
- if (--ee1004_dev_count == 0) {
- for (cnr--; cnr >= 0; cnr--) {
- i2c_unregister_device(ee1004_set_page[cnr]);
- ee1004_set_page[cnr] = NULL;
- }
- }
+ ee1004_cleanup(cnr);
mutex_unlock(&ee1004_bus_lock);
return err;
@@ -253,18 +218,9 @@ static int ee1004_probe(struct i2c_client *client,
static int ee1004_remove(struct i2c_client *client)
{
- int i;
-
- sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
-
/* Remove page select clients if this is the last device */
mutex_lock(&ee1004_bus_lock);
- if (--ee1004_dev_count == 0) {
- for (i = 0; i < 2; i++) {
- i2c_unregister_device(ee1004_set_page[i]);
- ee1004_set_page[i] = NULL;
- }
- }
+ ee1004_cleanup(EE1004_NUM_PAGES);
mutex_unlock(&ee1004_bus_lock);
return 0;
@@ -275,8 +231,9 @@ static int ee1004_remove(struct i2c_client *client)
static struct i2c_driver ee1004_driver = {
.driver = {
.name = "ee1004",
+ .dev_groups = ee1004_groups,
},
- .probe = ee1004_probe,
+ .probe_new = ee1004_probe,
.remove = ee1004_remove,
.id_table = ee1004_ids,
};
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index 80114f4c80ad..29d8971ec558 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
@@ -9,6 +9,7 @@
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
+#include <linux/log2.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
@@ -28,14 +29,29 @@
struct eeprom_93xx46_devtype_data {
unsigned int quirks;
+ unsigned char flags;
+};
+
+static const struct eeprom_93xx46_devtype_data at93c46_data = {
+ .flags = EE_SIZE1K,
+};
+
+static const struct eeprom_93xx46_devtype_data at93c56_data = {
+ .flags = EE_SIZE2K,
+};
+
+static const struct eeprom_93xx46_devtype_data at93c66_data = {
+ .flags = EE_SIZE4K,
};
static const struct eeprom_93xx46_devtype_data atmel_at93c46d_data = {
+ .flags = EE_SIZE1K,
.quirks = EEPROM_93XX46_QUIRK_SINGLE_WORD_READ |
EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH,
};
static const struct eeprom_93xx46_devtype_data microchip_93lc46b_data = {
+ .flags = EE_SIZE1K,
.quirks = EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE,
};
@@ -70,6 +86,7 @@ static int eeprom_93xx46_read(void *priv, unsigned int off,
struct eeprom_93xx46_dev *edev = priv;
char *buf = val;
int err = 0;
+ int bits;
if (unlikely(off >= edev->size))
return 0;
@@ -83,21 +100,21 @@ static int eeprom_93xx46_read(void *priv, unsigned int off,
if (edev->pdata->prepare)
edev->pdata->prepare(edev);
+ /* The opcode in front of the address is three bits. */
+ bits = edev->addrlen + 3;
+
while (count) {
struct spi_message m;
struct spi_transfer t[2] = { { 0 } };
u16 cmd_addr = OP_READ << edev->addrlen;
size_t nbytes = count;
- int bits;
- if (edev->addrlen == 7) {
- cmd_addr |= off & 0x7f;
- bits = 10;
+ if (edev->pdata->flags & EE_ADDR8) {
+ cmd_addr |= off;
if (has_quirk_single_word_read(edev))
nbytes = 1;
} else {
- cmd_addr |= (off >> 1) & 0x3f;
- bits = 9;
+ cmd_addr |= (off >> 1);
if (has_quirk_single_word_read(edev))
nbytes = 2;
}
@@ -152,14 +169,14 @@ static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on)
int bits, ret;
u16 cmd_addr;
+ /* The opcode in front of the address is three bits. */
+ bits = edev->addrlen + 3;
+
cmd_addr = OP_START << edev->addrlen;
- if (edev->addrlen == 7) {
+ if (edev->pdata->flags & EE_ADDR8)
cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS) << 1;
- bits = 10;
- } else {
+ else
cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS);
- bits = 9;
- }
if (has_quirk_instruction_length(edev)) {
cmd_addr <<= 2;
@@ -205,15 +222,19 @@ eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev,
int bits, data_len, ret;
u16 cmd_addr;
+ if (unlikely(off >= edev->size))
+ return -EINVAL;
+
+ /* The opcode in front of the address is three bits. */
+ bits = edev->addrlen + 3;
+
cmd_addr = OP_WRITE << edev->addrlen;
- if (edev->addrlen == 7) {
- cmd_addr |= off & 0x7f;
- bits = 10;
+ if (edev->pdata->flags & EE_ADDR8) {
+ cmd_addr |= off;
data_len = 1;
} else {
- cmd_addr |= (off >> 1) & 0x3f;
- bits = 9;
+ cmd_addr |= (off >> 1);
data_len = 2;
}
@@ -253,7 +274,7 @@ static int eeprom_93xx46_write(void *priv, unsigned int off,
return count;
/* only write even number of bytes on 16-bit devices */
- if (edev->addrlen == 6) {
+ if (edev->pdata->flags & EE_ADDR16) {
step = 2;
count &= ~1;
}
@@ -295,14 +316,14 @@ static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev)
int bits, ret;
u16 cmd_addr;
+ /* The opcode in front of the address is three bits. */
+ bits = edev->addrlen + 3;
+
cmd_addr = OP_START << edev->addrlen;
- if (edev->addrlen == 7) {
+ if (edev->pdata->flags & EE_ADDR8)
cmd_addr |= ADDR_ERAL << 1;
- bits = 10;
- } else {
+ else
cmd_addr |= ADDR_ERAL;
- bits = 9;
- }
if (has_quirk_instruction_length(edev)) {
cmd_addr <<= 2;
@@ -375,8 +396,11 @@ static void select_deassert(void *context)
}
static const struct of_device_id eeprom_93xx46_of_table[] = {
- { .compatible = "eeprom-93xx46", },
+ { .compatible = "eeprom-93xx46", .data = &at93c46_data, },
+ { .compatible = "atmel,at93c46", .data = &at93c46_data, },
{ .compatible = "atmel,at93c46d", .data = &atmel_at93c46d_data, },
+ { .compatible = "atmel,at93c56", .data = &at93c56_data, },
+ { .compatible = "atmel,at93c66", .data = &at93c66_data, },
{ .compatible = "microchip,93lc46b", .data = &microchip_93lc46b_data, },
{}
};
@@ -426,6 +450,7 @@ static int eeprom_93xx46_probe_dt(struct spi_device *spi)
const struct eeprom_93xx46_devtype_data *data = of_id->data;
pd->quirks = data->quirks;
+ pd->flags |= data->flags;
}
spi->dev.platform_data = pd;
@@ -455,10 +480,21 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
if (!edev)
return -ENOMEM;
+ if (pd->flags & EE_SIZE1K)
+ edev->size = 128;
+ else if (pd->flags & EE_SIZE2K)
+ edev->size = 256;
+ else if (pd->flags & EE_SIZE4K)
+ edev->size = 512;
+ else {
+ dev_err(&spi->dev, "unspecified size\n");
+ return -EINVAL;
+ }
+
if (pd->flags & EE_ADDR8)
- edev->addrlen = 7;
+ edev->addrlen = ilog2(edev->size);
else if (pd->flags & EE_ADDR16)
- edev->addrlen = 6;
+ edev->addrlen = ilog2(edev->size) - 1;
else {
dev_err(&spi->dev, "unspecified address type\n");
return -EINVAL;
@@ -469,7 +505,6 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
edev->spi = spi;
edev->pdata = pd;
- edev->size = 128;
edev->nvmem_config.type = NVMEM_TYPE_EEPROM;
edev->nvmem_config.name = dev_name(&spi->dev);
edev->nvmem_config.dev = &spi->dev;
@@ -489,8 +524,9 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
if (IS_ERR(edev->nvmem))
return PTR_ERR(edev->nvmem);
- dev_info(&spi->dev, "%d-bit eeprom %s\n",
+ dev_info(&spi->dev, "%d-bit eeprom containing %d bytes %s\n",
(pd->flags & EE_ADDR8) ? 8 : 16,
+ edev->size,
(pd->flags & EE_READONLY) ? "(readonly)" : "");
if (!(pd->flags & EE_READONLY)) {
diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c
index 81c70e5bc168..b0cff4b152da 100644
--- a/drivers/misc/eeprom/idt_89hpesx.c
+++ b/drivers/misc/eeprom/idt_89hpesx.c
@@ -1,38 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * This file is provided under a GPLv2 license. When using or
- * redistributing this file, you may do so under that license.
- *
- * GPL LICENSE SUMMARY
- *
* Copyright (C) 2016 T-Platforms. 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 that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR 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, it can be found <http://www.gnu.org/licenses/>.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * 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.
- *
* IDT PCIe-switch NTB Linux driver
*
* Contact Information:
@@ -1126,11 +1095,10 @@ static void idt_get_fw_data(struct idt_89hpesx_dev *pdev)
device_for_each_child_node(dev, fwnode) {
ee_id = idt_ee_match_id(fwnode);
- if (!ee_id) {
- dev_warn(dev, "Skip unsupported EEPROM device");
- continue;
- } else
+ if (ee_id)
break;
+
+ dev_warn(dev, "Skip unsupported EEPROM device %pfw\n", fwnode);
}
/* If there is no fwnode EEPROM device, then set zero size */
@@ -1161,6 +1129,7 @@ static void idt_get_fw_data(struct idt_89hpesx_dev *pdev)
else /* if (!fwnode_property_read_bool(node, "read-only")) */
pdev->eero = false;
+ fwnode_handle_put(fwnode);
dev_info(dev, "EEPROM of %d bytes found by 0x%x",
pdev->eesize, pdev->eeaddr);
}
diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c
index af3c497defb1..80c60fb41bbc 100644
--- a/drivers/misc/habanalabs/common/command_submission.c
+++ b/drivers/misc/habanalabs/common/command_submission.c
@@ -556,6 +556,13 @@ out:
else if (!cs->submitted)
cs->fence->error = -EBUSY;
+ if (unlikely(cs->skip_reset_on_timeout)) {
+ dev_err(hdev->dev,
+ "Command submission %llu completed after %llu (s)\n",
+ cs->sequence,
+ div_u64(jiffies - cs->submission_time_jiffies, HZ));
+ }
+
if (cs->timestamp)
cs->fence->timestamp = ktime_get();
complete_all(&cs->fence->completion);
@@ -571,6 +578,8 @@ static void cs_timedout(struct work_struct *work)
int rc;
struct hl_cs *cs = container_of(work, struct hl_cs,
work_tdr.work);
+ bool skip_reset_on_timeout = cs->skip_reset_on_timeout;
+
rc = cs_get_unless_zero(cs);
if (!rc)
return;
@@ -581,7 +590,8 @@ static void cs_timedout(struct work_struct *work)
}
/* Mark the CS is timed out so we won't try to cancel its TDR */
- cs->timedout = true;
+ if (likely(!skip_reset_on_timeout))
+ cs->timedout = true;
hdev = cs->ctx->hdev;
@@ -613,10 +623,12 @@ static void cs_timedout(struct work_struct *work)
cs_put(cs);
- if (hdev->reset_on_lockup)
- hl_device_reset(hdev, 0);
- else
- hdev->needs_reset = true;
+ if (likely(!skip_reset_on_timeout)) {
+ if (hdev->reset_on_lockup)
+ hl_device_reset(hdev, HL_RESET_TDR);
+ else
+ hdev->needs_reset = true;
+ }
}
static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx,
@@ -650,6 +662,10 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx,
cs->type = cs_type;
cs->timestamp = !!(flags & HL_CS_FLAGS_TIMESTAMP);
cs->timeout_jiffies = timeout;
+ cs->skip_reset_on_timeout =
+ hdev->skip_reset_on_timeout ||
+ !!(flags & HL_CS_FLAGS_SKIP_RESET_ON_TIMEOUT);
+ cs->submission_time_jiffies = jiffies;
INIT_LIST_HEAD(&cs->job_list);
INIT_DELAYED_WORK(&cs->work_tdr, cs_timedout);
kref_init(&cs->refcount);
@@ -1481,6 +1497,61 @@ out:
return rc;
}
+/*
+ * hl_cs_signal_sob_wraparound_handler: handle SOB value wrapaound case.
+ * if the SOB value reaches the max value move to the other SOB reserved
+ * to the queue.
+ * Note that this function must be called while hw_queues_lock is taken.
+ */
+int hl_cs_signal_sob_wraparound_handler(struct hl_device *hdev, u32 q_idx,
+ struct hl_hw_sob **hw_sob, u32 count)
+{
+ struct hl_sync_stream_properties *prop;
+ struct hl_hw_sob *sob = *hw_sob, *other_sob;
+ u8 other_sob_offset;
+
+ prop = &hdev->kernel_queues[q_idx].sync_stream_prop;
+
+ kref_get(&sob->kref);
+
+ /* check for wraparound */
+ if (prop->next_sob_val + count >= HL_MAX_SOB_VAL) {
+ /*
+ * Decrement as we reached the max value.
+ * The release function won't be called here as we've
+ * just incremented the refcount right before calling this
+ * function.
+ */
+ kref_put(&sob->kref, hl_sob_reset_error);
+
+ /*
+ * check the other sob value, if it still in use then fail
+ * otherwise make the switch
+ */
+ other_sob_offset = (prop->curr_sob_offset + 1) % HL_RSVD_SOBS;
+ other_sob = &prop->hw_sob[other_sob_offset];
+
+ if (kref_read(&other_sob->kref) != 1) {
+ dev_err(hdev->dev, "error: Cannot switch SOBs q_idx: %d\n",
+ q_idx);
+ return -EINVAL;
+ }
+
+ prop->next_sob_val = 1;
+
+ /* only two SOBs are currently in use */
+ prop->curr_sob_offset = other_sob_offset;
+ *hw_sob = other_sob;
+
+ dev_dbg(hdev->dev, "switched to SOB %d, q_idx: %d\n",
+ prop->curr_sob_offset, q_idx);
+ } else {
+ prop->next_sob_val += count;
+ }
+
+ return 0;
+}
+
static int cs_ioctl_extract_signal_seq(struct hl_device *hdev,
struct hl_cs_chunk *chunk, u64 *signal_seq, struct hl_ctx *ctx)
{
diff --git a/drivers/misc/habanalabs/common/context.c b/drivers/misc/habanalabs/common/context.c
index 62d705889ca8..19b6b045219e 100644
--- a/drivers/misc/habanalabs/common/context.c
+++ b/drivers/misc/habanalabs/common/context.c
@@ -12,7 +12,6 @@
static void hl_ctx_fini(struct hl_ctx *ctx)
{
struct hl_device *hdev = ctx->hdev;
- u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0};
int i;
/* Release all allocated pending cb's, those cb's were never
@@ -57,14 +56,6 @@ static void hl_ctx_fini(struct hl_ctx *ctx)
/* Scrub both SRAM and DRAM */
hdev->asic_funcs->scrub_device_mem(hdev, 0, 0);
-
- if ((!hdev->pldm) && (hdev->pdev) &&
- (!hdev->asic_funcs->is_device_idle(hdev,
- idle_mask,
- HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL)))
- dev_notice(hdev->dev,
- "device not idle after user context is closed (0x%llx, 0x%llx)\n",
- idle_mask[0], idle_mask[1]);
} else {
dev_dbg(hdev->dev, "closing kernel context\n");
hdev->asic_funcs->ctx_fini(ctx);
diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habanalabs/common/debugfs.c
index 8381155578a0..703d79fb6f3f 100644
--- a/drivers/misc/habanalabs/common/debugfs.c
+++ b/drivers/misc/habanalabs/common/debugfs.c
@@ -1278,6 +1278,11 @@ void hl_debugfs_add_device(struct hl_device *hdev)
dev_entry->root,
&dev_entry->blob_desc);
+ debugfs_create_x8("skip_reset_on_timeout",
+ 0644,
+ dev_entry->root,
+ &hdev->skip_reset_on_timeout);
+
for (i = 0, entry = dev_entry->entry_arr ; i < count ; i++, entry++) {
debugfs_create_file(hl_debugfs_list[i].name,
0444,
diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c
index 00e92b678828..ff4cbde289c0 100644
--- a/drivers/misc/habanalabs/common/device.c
+++ b/drivers/misc/habanalabs/common/device.c
@@ -51,6 +51,8 @@ bool hl_device_operational(struct hl_device *hdev,
static void hpriv_release(struct kref *ref)
{
+ u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0};
+ bool device_is_idle = true;
struct hl_fpriv *hpriv;
struct hl_device *hdev;
@@ -71,8 +73,20 @@ static void hpriv_release(struct kref *ref)
kfree(hpriv);
- if (hdev->reset_upon_device_release)
- hl_device_reset(hdev, 0);
+ if ((!hdev->pldm) && (hdev->pdev) &&
+ (!hdev->asic_funcs->is_device_idle(hdev,
+ idle_mask,
+ HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL))) {
+ dev_err(hdev->dev,
+ "device not idle after user context is closed (0x%llx_%llx)\n",
+ idle_mask[1], idle_mask[0]);
+
+ device_is_idle = false;
+ }
+
+ if ((hdev->reset_if_device_not_idle && !device_is_idle)
+ || hdev->reset_upon_device_release)
+ hl_device_reset(hdev, HL_RESET_DEVICE_RELEASE);
}
void hl_hpriv_get(struct hl_fpriv *hpriv)
@@ -118,6 +132,9 @@ static int hl_device_release(struct inode *inode, struct file *filp)
dev_warn(hdev->dev,
"Device is still in use because there are live CS and/or memory mappings\n");
+ hdev->last_open_session_duration_jif =
+ jiffies - hdev->last_successful_open_jif;
+
return 0;
}
@@ -868,7 +885,7 @@ static void device_disable_open_processes(struct hl_device *hdev)
int hl_device_reset(struct hl_device *hdev, u32 flags)
{
u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0};
- bool hard_reset, from_hard_reset_thread;
+ bool hard_reset, from_hard_reset_thread, hard_instead_soft = false;
int i, rc;
if (!hdev->init_done) {
@@ -880,11 +897,28 @@ int hl_device_reset(struct hl_device *hdev, u32 flags)
hard_reset = (flags & HL_RESET_HARD) != 0;
from_hard_reset_thread = (flags & HL_RESET_FROM_RESET_THREAD) != 0;
- if ((!hard_reset) && (!hdev->supports_soft_reset)) {
- dev_dbg(hdev->dev, "Doing hard-reset instead of soft-reset\n");
+ if (!hard_reset && !hdev->supports_soft_reset) {
+ hard_instead_soft = true;
+ hard_reset = true;
+ }
+
+ if (hdev->reset_upon_device_release &&
+ (flags & HL_RESET_DEVICE_RELEASE)) {
+ dev_dbg(hdev->dev,
+ "Perform %s-reset upon device release\n",
+ hard_reset ? "hard" : "soft");
+ goto do_reset;
+ }
+
+ if (!hard_reset && !hdev->allow_external_soft_reset) {
+ hard_instead_soft = true;
hard_reset = true;
}
+ if (hard_instead_soft)
+ dev_dbg(hdev->dev, "Doing hard-reset instead of soft-reset\n");
+
+do_reset:
/* Re-entry of reset thread */
if (from_hard_reset_thread && hdev->process_kill_trial_cnt)
goto kill_processes;
@@ -901,6 +935,19 @@ int hl_device_reset(struct hl_device *hdev, u32 flags)
return 0;
/*
+ * 'reset cause' is being updated here, because getting here
+ * means that it's the 1st time and the last time we're here
+ * ('in_reset' makes sure of it). This makes sure that
+ * 'reset_cause' will continue holding its 1st recorded reason!
+ */
+ if (flags & HL_RESET_HEARTBEAT)
+ hdev->curr_reset_cause = HL_RESET_CAUSE_HEARTBEAT;
+ else if (flags & HL_RESET_TDR)
+ hdev->curr_reset_cause = HL_RESET_CAUSE_TDR;
+ else
+ hdev->curr_reset_cause = HL_RESET_CAUSE_UNKNOWN;
+
+ /*
* if reset is due to heartbeat, device CPU is no responsive in
* which case no point sending PCI disable message to it
*/
@@ -943,9 +990,8 @@ again:
hdev->process_kill_trial_cnt = 0;
/*
- * Because the reset function can't run from interrupt or
- * from heartbeat work, we need to call the reset function
- * from a dedicated work
+ * Because the reset function can't run from heartbeat work,
+ * we need to call the reset function from a dedicated work.
*/
queue_delayed_work(hdev->device_reset_work.wq,
&hdev->device_reset_work.reset_work, 0);
@@ -1096,8 +1142,8 @@ kill_processes:
if (!hdev->asic_funcs->is_device_idle(hdev, idle_mask,
HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL)) {
dev_err(hdev->dev,
- "device is not idle (mask %#llx %#llx) after reset\n",
- idle_mask[0], idle_mask[1]);
+ "device is not idle (mask 0x%llx_%llx) after reset\n",
+ idle_mask[1], idle_mask[0]);
rc = -EIO;
goto out_err;
}
@@ -1334,8 +1380,9 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
}
/*
- * From this point, in case of an error, add char devices and create
- * sysfs nodes as part of the error flow, to allow debugging.
+ * From this point, override rc (=0) in case of an error to allow
+ * debugging (by adding char devices and create sysfs nodes as part of
+ * the error flow).
*/
add_cdev_sysfs_on_err = true;
@@ -1369,7 +1416,7 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
dev_info(hdev->dev, "Found %s device with %lluGB DRAM\n",
hdev->asic_name,
- hdev->asic_prop.dram_size / 1024 / 1024 / 1024);
+ hdev->asic_prop.dram_size / SZ_1G);
rc = hl_vm_init(hdev);
if (rc) {
@@ -1475,6 +1522,7 @@ out_disabled:
void hl_device_fini(struct hl_device *hdev)
{
ktime_t timeout;
+ u64 reset_sec;
int i, rc;
dev_info(hdev->dev, "Removing device\n");
@@ -1482,6 +1530,11 @@ void hl_device_fini(struct hl_device *hdev)
hdev->device_fini_pending = 1;
flush_delayed_work(&hdev->device_reset_work.reset_work);
+ if (hdev->pldm)
+ reset_sec = HL_PLDM_HARD_RESET_MAX_TIMEOUT;
+ else
+ reset_sec = HL_HARD_RESET_MAX_TIMEOUT;
+
/*
* This function is competing with the reset function, so try to
* take the reset atomic and if we are already in middle of reset,
@@ -1490,8 +1543,7 @@ void hl_device_fini(struct hl_device *hdev)
* ports, the hard reset could take between 10-30 seconds
*/
- timeout = ktime_add_us(ktime_get(),
- HL_HARD_RESET_MAX_TIMEOUT * 1000 * 1000);
+ timeout = ktime_add_us(ktime_get(), reset_sec * 1000 * 1000);
rc = atomic_cmpxchg(&hdev->in_reset, 0, 1);
while (rc) {
usleep_range(50, 200);
diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c
index 0713b2c12d54..2e4d04ec6b53 100644
--- a/drivers/misc/habanalabs/common/firmware_if.c
+++ b/drivers/misc/habanalabs/common/firmware_if.c
@@ -9,42 +9,63 @@
#include "../include/common/hl_boot_if.h"
#include <linux/firmware.h>
+#include <linux/crc32.h>
#include <linux/slab.h>
+#include <linux/ctype.h>
-#define FW_FILE_MAX_SIZE 0x1400000 /* maximum size of 20MB */
-/**
- * hl_fw_load_fw_to_device() - Load F/W code to device's memory.
- *
- * @hdev: pointer to hl_device structure.
- * @fw_name: the firmware image name
- * @dst: IO memory mapped address space to copy firmware to
- * @src_offset: offset in src FW to copy from
- * @size: amount of bytes to copy (0 to copy the whole binary)
- *
- * Copy fw code from firmware file to device memory.
- *
- * Return: 0 on success, non-zero for failure.
- */
-int hl_fw_load_fw_to_device(struct hl_device *hdev, const char *fw_name,
- void __iomem *dst, u32 src_offset, u32 size)
+#define FW_FILE_MAX_SIZE 0x1400000 /* maximum size of 20MB */
+
+#define FW_CPU_STATUS_POLL_INTERVAL_USEC 10000
+
+static char *extract_fw_ver_from_str(const char *fw_str)
+{
+ char *str, *fw_ver, *whitespace;
+
+ fw_ver = kmalloc(16, GFP_KERNEL);
+ if (!fw_ver)
+ return NULL;
+
+ str = strnstr(fw_str, "fw-", VERSION_MAX_LEN);
+ if (!str)
+ goto free_fw_ver;
+
+ /* Skip the fw- part */
+ str += 3;
+
+ /* Copy until the next whitespace */
+ whitespace = strnstr(str, " ", 15);
+ if (!whitespace)
+ goto free_fw_ver;
+
+ strscpy(fw_ver, str, whitespace - str + 1);
+
+ return fw_ver;
+
+free_fw_ver:
+ kfree(fw_ver);
+ return NULL;
+}
+
+static int hl_request_fw(struct hl_device *hdev,
+ const struct firmware **firmware_p,
+ const char *fw_name)
{
- const struct firmware *fw;
- const void *fw_data;
size_t fw_size;
int rc;
- rc = request_firmware(&fw, fw_name, hdev->dev);
+ rc = request_firmware(firmware_p, fw_name, hdev->dev);
if (rc) {
- dev_err(hdev->dev, "Firmware file %s is not found!\n", fw_name);
+ dev_err(hdev->dev, "Firmware file %s is not found! (error %d)\n",
+ fw_name, rc);
goto out;
}
- fw_size = fw->size;
+ fw_size = (*firmware_p)->size;
if ((fw_size % 4) != 0) {
dev_err(hdev->dev, "Illegal %s firmware size %zu\n",
- fw_name, fw_size);
+ fw_name, fw_size);
rc = -EINVAL;
- goto out;
+ goto release_fw;
}
dev_dbg(hdev->dev, "%s firmware size == %zu\n", fw_name, fw_size);
@@ -54,26 +75,125 @@ int hl_fw_load_fw_to_device(struct hl_device *hdev, const char *fw_name,
"FW file size %zu exceeds maximum of %u bytes\n",
fw_size, FW_FILE_MAX_SIZE);
rc = -EINVAL;
- goto out;
+ goto release_fw;
}
- if (size - src_offset > fw_size) {
+ return 0;
+
+release_fw:
+ release_firmware(*firmware_p);
+out:
+ return rc;
+}
+
+/**
+ * hl_release_firmware() - release FW
+ *
+ * @fw: fw descriptor
+ *
+ * note: this inline function added to serve as a comprehensive mirror for the
+ * hl_request_fw function.
+ */
+static inline void hl_release_firmware(const struct firmware *fw)
+{
+ release_firmware(fw);
+}
+
+/**
+ * hl_fw_copy_fw_to_device() - copy FW to device
+ *
+ * @hdev: pointer to hl_device structure.
+ * @fw: fw descriptor
+ * @dst: IO memory mapped address space to copy firmware to
+ * @src_offset: offset in src FW to copy from
+ * @size: amount of bytes to copy (0 to copy the whole binary)
+ *
+ * actual copy of FW binary data to device, shared by static and dynamic loaders
+ */
+static int hl_fw_copy_fw_to_device(struct hl_device *hdev,
+ const struct firmware *fw, void __iomem *dst,
+ u32 src_offset, u32 size)
+{
+ const void *fw_data;
+
+ /* size 0 indicates to copy the whole file */
+ if (!size)
+ size = fw->size;
+
+ if (src_offset + size > fw->size) {
dev_err(hdev->dev,
"size to copy(%u) and offset(%u) are invalid\n",
size, src_offset);
- rc = -EINVAL;
- goto out;
+ return -EINVAL;
}
- if (size)
- fw_size = size;
-
fw_data = (const void *) fw->data;
- memcpy_toio(dst, fw_data + src_offset, fw_size);
+ memcpy_toio(dst, fw_data + src_offset, size);
+ return 0;
+}
-out:
- release_firmware(fw);
+/**
+ * hl_fw_copy_msg_to_device() - copy message to device
+ *
+ * @hdev: pointer to hl_device structure.
+ * @msg: message
+ * @dst: IO memory mapped address space to copy firmware to
+ * @src_offset: offset in src message to copy from
+ * @size: amount of bytes to copy (0 to copy the whole binary)
+ *
+ * actual copy of message data to device.
+ */
+static int hl_fw_copy_msg_to_device(struct hl_device *hdev,
+ struct lkd_msg_comms *msg, void __iomem *dst,
+ u32 src_offset, u32 size)
+{
+ void *msg_data;
+
+ /* size 0 indicates to copy the whole file */
+ if (!size)
+ size = sizeof(struct lkd_msg_comms);
+
+ if (src_offset + size > sizeof(struct lkd_msg_comms)) {
+ dev_err(hdev->dev,
+ "size to copy(%u) and offset(%u) are invalid\n",
+ size, src_offset);
+ return -EINVAL;
+ }
+
+ msg_data = (void *) msg;
+
+ memcpy_toio(dst, msg_data + src_offset, size);
+
+ return 0;
+}
+
+/**
+ * hl_fw_load_fw_to_device() - Load F/W code to device's memory.
+ *
+ * @hdev: pointer to hl_device structure.
+ * @fw_name: the firmware image name
+ * @dst: IO memory mapped address space to copy firmware to
+ * @src_offset: offset in src FW to copy from
+ * @size: amount of bytes to copy (0 to copy the whole binary)
+ *
+ * Copy fw code from firmware file to device memory.
+ *
+ * Return: 0 on success, non-zero for failure.
+ */
+int hl_fw_load_fw_to_device(struct hl_device *hdev, const char *fw_name,
+ void __iomem *dst, u32 src_offset, u32 size)
+{
+ const struct firmware *fw;
+ int rc;
+
+ rc = hl_request_fw(hdev, &fw, fw_name);
+ if (rc)
+ return rc;
+
+ rc = hl_fw_copy_fw_to_device(hdev, fw, dst, src_offset, size);
+
+ hl_release_firmware(fw);
return rc;
}
@@ -91,6 +211,7 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,
u16 len, u32 timeout, u64 *result)
{
struct hl_hw_queue *queue = &hdev->kernel_queues[hw_queue_id];
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
struct cpucp_packet *pkt;
dma_addr_t pkt_dma_addr;
u32 tmp, expected_ack_val;
@@ -117,7 +238,7 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,
}
/* set fence to a non valid value */
- pkt->fence = UINT_MAX;
+ pkt->fence = cpu_to_le32(UINT_MAX);
rc = hl_hw_queue_send_cb_no_cmpl(hdev, hw_queue_id, len, pkt_dma_addr);
if (rc) {
@@ -125,8 +246,7 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,
goto out;
}
- if (hdev->asic_prop.fw_app_security_map &
- CPU_BOOT_DEV_STS0_PKT_PI_ACK_EN)
+ if (prop->fw_app_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_PKT_PI_ACK_EN)
expected_ack_val = queue->pi;
else
expected_ack_val = CPUCP_PACKET_FENCE_VAL;
@@ -272,10 +392,11 @@ void hl_fw_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size,
int hl_fw_send_heartbeat(struct hl_device *hdev)
{
- struct cpucp_packet hb_pkt = {};
+ struct cpucp_packet hb_pkt;
u64 result;
int rc;
+ memset(&hb_pkt, 0, sizeof(hb_pkt));
hb_pkt.ctl = cpu_to_le32(CPUCP_PACKET_TEST <<
CPUCP_PKT_CTL_OPCODE_SHIFT);
hb_pkt.value = cpu_to_le64(CPUCP_PACKET_FENCE_VAL);
@@ -284,29 +405,24 @@ int hl_fw_send_heartbeat(struct hl_device *hdev)
sizeof(hb_pkt), 0, &result);
if ((rc) || (result != CPUCP_PACKET_FENCE_VAL))
+ return -EIO;
+
+ if (le32_to_cpu(hb_pkt.status_mask) &
+ CPUCP_PKT_HB_STATUS_EQ_FAULT_MASK) {
+ dev_warn(hdev->dev, "FW reported EQ fault during heartbeat\n");
rc = -EIO;
+ }
return rc;
}
-static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg,
- u32 cpu_security_boot_status_reg)
+static bool fw_report_boot_dev0(struct hl_device *hdev, u32 err_val,
+ u32 sts_val)
{
- u32 err_val, security_val;
bool err_exists = false;
- /* Some of the firmware status codes are deprecated in newer f/w
- * versions. In those versions, the errors are reported
- * in different registers. Therefore, we need to check those
- * registers and print the exact errors. Moreover, there
- * may be multiple errors, so we need to report on each error
- * separately. Some of the error codes might indicate a state
- * that is not an error per-se, but it is an error in production
- * environment
- */
- err_val = RREG32(boot_err0_reg);
if (!(err_val & CPU_BOOT_ERR0_ENABLED))
- return 0;
+ return false;
if (err_val & CPU_BOOT_ERR0_DRAM_INIT_FAIL) {
dev_err(hdev->dev,
@@ -377,44 +493,120 @@ static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg,
err_exists = true;
}
+ if (err_val & CPU_BOOT_ERR0_PRI_IMG_VER_FAIL) {
+ dev_warn(hdev->dev,
+ "Device boot warning - Failed to load preboot primary image\n");
+ /* This is a warning so we don't want it to disable the
+ * device as we have a secondary preboot image
+ */
+ err_val &= ~CPU_BOOT_ERR0_PRI_IMG_VER_FAIL;
+ }
+
+ if (err_val & CPU_BOOT_ERR0_SEC_IMG_VER_FAIL) {
+ dev_err(hdev->dev, "Device boot error - Failed to load preboot secondary image\n");
+ err_exists = true;
+ }
+
if (err_val & CPU_BOOT_ERR0_PLL_FAIL) {
dev_err(hdev->dev, "Device boot error - PLL failure\n");
err_exists = true;
}
if (err_val & CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL) {
- dev_err(hdev->dev,
- "Device boot error - device unusable\n");
- err_exists = true;
+ /* Ignore this bit, don't prevent driver loading */
+ dev_dbg(hdev->dev, "device unusable status is set\n");
+ err_val &= ~CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL;
}
- security_val = RREG32(cpu_security_boot_status_reg);
- if (security_val & CPU_BOOT_DEV_STS0_ENABLED)
- dev_dbg(hdev->dev, "Device security status %#x\n",
- security_val);
+ if (sts_val & CPU_BOOT_DEV_STS0_ENABLED)
+ dev_dbg(hdev->dev, "Device status0 %#x\n", sts_val);
if (!err_exists && (err_val & ~CPU_BOOT_ERR0_ENABLED)) {
dev_err(hdev->dev,
- "Device boot error - unknown error 0x%08x\n",
- err_val);
+ "Device boot error - unknown ERR0 error 0x%08x\n", err_val);
err_exists = true;
}
+ /* return error only if it's in the predefined mask */
if (err_exists && ((err_val & ~CPU_BOOT_ERR0_ENABLED) &
lower_32_bits(hdev->boot_error_status_mask)))
+ return true;
+
+ return false;
+}
+
+/* placeholder for ERR1 as no errors defined there yet */
+static bool fw_report_boot_dev1(struct hl_device *hdev, u32 err_val,
+ u32 sts_val)
+{
+ /*
+ * keep this variable to preserve the logic of the function.
+ * this way it would require less modifications when error will be
+ * added to DEV_ERR1
+ */
+ bool err_exists = false;
+
+ if (!(err_val & CPU_BOOT_ERR1_ENABLED))
+ return false;
+
+ if (sts_val & CPU_BOOT_DEV_STS1_ENABLED)
+ dev_dbg(hdev->dev, "Device status1 %#x\n", sts_val);
+
+ if (!err_exists && (err_val & ~CPU_BOOT_ERR1_ENABLED)) {
+ dev_err(hdev->dev,
+ "Device boot error - unknown ERR1 error 0x%08x\n",
+ err_val);
+ err_exists = true;
+ }
+
+ /* return error only if it's in the predefined mask */
+ if (err_exists && ((err_val & ~CPU_BOOT_ERR1_ENABLED) &
+ upper_32_bits(hdev->boot_error_status_mask)))
+ return true;
+
+ return false;
+}
+
+static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg,
+ u32 boot_err1_reg, u32 cpu_boot_dev_status0_reg,
+ u32 cpu_boot_dev_status1_reg)
+{
+ u32 err_val, status_val;
+ bool err_exists = false;
+
+ /* Some of the firmware status codes are deprecated in newer f/w
+ * versions. In those versions, the errors are reported
+ * in different registers. Therefore, we need to check those
+ * registers and print the exact errors. Moreover, there
+ * may be multiple errors, so we need to report on each error
+ * separately. Some of the error codes might indicate a state
+ * that is not an error per-se, but it is an error in production
+ * environment
+ */
+ err_val = RREG32(boot_err0_reg);
+ status_val = RREG32(cpu_boot_dev_status0_reg);
+ err_exists = fw_report_boot_dev0(hdev, err_val, status_val);
+
+ err_val = RREG32(boot_err1_reg);
+ status_val = RREG32(cpu_boot_dev_status1_reg);
+ err_exists |= fw_report_boot_dev1(hdev, err_val, status_val);
+
+ if (err_exists)
return -EIO;
return 0;
}
int hl_fw_cpucp_info_get(struct hl_device *hdev,
- u32 cpu_security_boot_status_reg,
- u32 boot_err0_reg)
+ u32 sts_boot_dev_sts0_reg,
+ u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg,
+ u32 boot_err1_reg)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
struct cpucp_packet pkt = {};
- void *cpucp_info_cpu_addr;
dma_addr_t cpucp_info_dma_addr;
+ void *cpucp_info_cpu_addr;
+ char *kernel_ver;
u64 result;
int rc;
@@ -443,7 +635,8 @@ int hl_fw_cpucp_info_get(struct hl_device *hdev,
goto out;
}
- rc = fw_read_errors(hdev, boot_err0_reg, cpu_security_boot_status_reg);
+ rc = fw_read_errors(hdev, boot_err0_reg, boot_err1_reg,
+ sts_boot_dev_sts0_reg, sts_boot_dev_sts1_reg);
if (rc) {
dev_err(hdev->dev, "Errors in device boot\n");
goto out;
@@ -460,10 +653,27 @@ int hl_fw_cpucp_info_get(struct hl_device *hdev,
goto out;
}
+ kernel_ver = extract_fw_ver_from_str(prop->cpucp_info.kernel_version);
+ if (kernel_ver) {
+ dev_info(hdev->dev, "Linux version %s", kernel_ver);
+ kfree(kernel_ver);
+ }
+
+ /* assume EQ code doesn't need to check eqe index */
+ hdev->event_queue.check_eqe_index = false;
+
/* Read FW application security bits again */
- if (hdev->asic_prop.fw_security_status_valid)
- hdev->asic_prop.fw_app_security_map =
- RREG32(cpu_security_boot_status_reg);
+ if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid) {
+ hdev->asic_prop.fw_app_cpu_boot_dev_sts0 =
+ RREG32(sts_boot_dev_sts0_reg);
+ if (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 &
+ CPU_BOOT_DEV_STS0_EQ_INDEX_EN)
+ hdev->event_queue.check_eqe_index = true;
+ }
+
+ if (hdev->asic_prop.fw_cpu_boot_dev_sts1_valid)
+ hdev->asic_prop.fw_app_cpu_boot_dev_sts1 =
+ RREG32(sts_boot_dev_sts1_reg);
out:
hdev->asic_funcs->cpu_accessible_dma_pool_free(hdev,
@@ -501,7 +711,8 @@ static int hl_fw_send_msi_info_msg(struct hl_device *hdev)
pkt->length = cpu_to_le32(CPUCP_NUM_OF_MSI_TYPES);
- hdev->asic_funcs->get_msi_info((u32 *)&pkt->data);
+ memset((void *) &pkt->data, 0xFF, data_size);
+ hdev->asic_funcs->get_msi_info(pkt->data);
pkt->cpucp_pkt.ctl = cpu_to_le32(CPUCP_PACKET_MSI_INFO_SET <<
CPUCP_PKT_CTL_OPCODE_SHIFT);
@@ -526,13 +737,15 @@ static int hl_fw_send_msi_info_msg(struct hl_device *hdev)
}
int hl_fw_cpucp_handshake(struct hl_device *hdev,
- u32 cpu_security_boot_status_reg,
- u32 boot_err0_reg)
+ u32 sts_boot_dev_sts0_reg,
+ u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg,
+ u32 boot_err1_reg)
{
int rc;
- rc = hl_fw_cpucp_info_get(hdev, cpu_security_boot_status_reg,
- boot_err0_reg);
+ rc = hl_fw_cpucp_info_get(hdev, sts_boot_dev_sts0_reg,
+ sts_boot_dev_sts1_reg, boot_err0_reg,
+ boot_err1_reg);
if (rc)
return rc;
@@ -667,8 +880,8 @@ int get_used_pll_index(struct hl_device *hdev, u32 input_pll_index,
bool dynamic_pll;
int fw_pll_idx;
- dynamic_pll = prop->fw_security_status_valid &&
- (prop->fw_app_security_map & CPU_BOOT_DEV_STS0_DYN_PLL_EN);
+ dynamic_pll = !!(prop->fw_app_cpu_boot_dev_sts0 &
+ CPU_BOOT_DEV_STS0_DYN_PLL_EN);
if (!dynamic_pll) {
/*
@@ -759,6 +972,47 @@ int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power)
return rc;
}
+void hl_fw_ask_hard_reset_without_linux(struct hl_device *hdev)
+{
+ struct static_fw_load_mgr *static_loader =
+ &hdev->fw_loader.static_loader;
+ int rc;
+
+ if (hdev->asic_prop.dynamic_fw_load) {
+ rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader,
+ COMMS_RST_DEV, 0, false,
+ hdev->fw_loader.cpu_timeout);
+ if (rc)
+ dev_warn(hdev->dev, "Failed sending COMMS_RST_DEV\n");
+ } else {
+ WREG32(static_loader->kmd_msg_to_cpu_reg, KMD_MSG_RST_DEV);
+ }
+}
+
+void hl_fw_ask_halt_machine_without_linux(struct hl_device *hdev)
+{
+ struct static_fw_load_mgr *static_loader =
+ &hdev->fw_loader.static_loader;
+ int rc;
+
+ if (hdev->device_cpu_is_halted)
+ return;
+
+ /* Stop device CPU to make sure nothing bad happens */
+ if (hdev->asic_prop.dynamic_fw_load) {
+ rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader,
+ COMMS_GOTO_WFE, 0, true,
+ hdev->fw_loader.cpu_timeout);
+ if (rc)
+ dev_warn(hdev->dev, "Failed sending COMMS_GOTO_WFE\n");
+ } else {
+ WREG32(static_loader->kmd_msg_to_cpu_reg, KMD_MSG_GOTO_WFE);
+ msleep(static_loader->cpu_reset_wait_msec);
+ }
+
+ hdev->device_cpu_is_halted = true;
+}
+
static void detect_cpu_boot_status(struct hl_device *hdev, u32 status)
{
/* Some of the status codes below are deprecated in newer f/w
@@ -767,63 +1021,59 @@ static void detect_cpu_boot_status(struct hl_device *hdev, u32 status)
switch (status) {
case CPU_BOOT_STATUS_NA:
dev_err(hdev->dev,
- "Device boot error - BTL did NOT run\n");
+ "Device boot progress - BTL did NOT run\n");
break;
case CPU_BOOT_STATUS_IN_WFE:
dev_err(hdev->dev,
- "Device boot error - Stuck inside WFE loop\n");
+ "Device boot progress - Stuck inside WFE loop\n");
break;
case CPU_BOOT_STATUS_IN_BTL:
dev_err(hdev->dev,
- "Device boot error - Stuck in BTL\n");
+ "Device boot progress - Stuck in BTL\n");
break;
case CPU_BOOT_STATUS_IN_PREBOOT:
dev_err(hdev->dev,
- "Device boot error - Stuck in Preboot\n");
+ "Device boot progress - Stuck in Preboot\n");
break;
case CPU_BOOT_STATUS_IN_SPL:
dev_err(hdev->dev,
- "Device boot error - Stuck in SPL\n");
+ "Device boot progress - Stuck in SPL\n");
break;
case CPU_BOOT_STATUS_IN_UBOOT:
dev_err(hdev->dev,
- "Device boot error - Stuck in u-boot\n");
+ "Device boot progress - Stuck in u-boot\n");
break;
case CPU_BOOT_STATUS_DRAM_INIT_FAIL:
dev_err(hdev->dev,
- "Device boot error - DRAM initialization failed\n");
+ "Device boot progress - DRAM initialization failed\n");
break;
case CPU_BOOT_STATUS_UBOOT_NOT_READY:
dev_err(hdev->dev,
- "Device boot error - u-boot stopped by user\n");
+ "Device boot progress - Cannot boot\n");
break;
case CPU_BOOT_STATUS_TS_INIT_FAIL:
dev_err(hdev->dev,
- "Device boot error - Thermal Sensor initialization failed\n");
+ "Device boot progress - Thermal Sensor initialization failed\n");
break;
default:
dev_err(hdev->dev,
- "Device boot error - Invalid status code %d\n",
+ "Device boot progress - Invalid status code %d\n",
status);
break;
}
}
-int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg,
- u32 cpu_security_boot_status_reg, u32 boot_err0_reg,
- u32 timeout)
+static int hl_fw_read_preboot_caps(struct hl_device *hdev,
+ u32 cpu_boot_status_reg,
+ u32 sts_boot_dev_sts0_reg,
+ u32 sts_boot_dev_sts1_reg,
+ u32 boot_err0_reg, u32 boot_err1_reg,
+ u32 timeout)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
- u32 status, security_status;
+ u32 status, reg_val;
int rc;
- /* pldm was added for cases in which we use preboot on pldm and want
- * to load boot fit, but we can't wait for preboot because it runs
- * very slowly
- */
- if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU) || hdev->pldm)
- return 0;
-
/* Need to check two possible scenarios:
*
* CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT - for newer firmwares where
@@ -842,29 +1092,145 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg,
(status == CPU_BOOT_STATUS_READY_TO_BOOT) ||
(status == CPU_BOOT_STATUS_SRAM_AVAIL) ||
(status == CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT),
- 10000,
+ FW_CPU_STATUS_POLL_INTERVAL_USEC,
timeout);
if (rc) {
- dev_err(hdev->dev, "Failed to read preboot version\n");
+ dev_err(hdev->dev, "CPU boot ready status timeout\n");
detect_cpu_boot_status(hdev, status);
/* If we read all FF, then something is totally wrong, no point
* of reading specific errors
*/
if (status != -1)
- fw_read_errors(hdev, boot_err0_reg,
- cpu_security_boot_status_reg);
+ fw_read_errors(hdev, boot_err0_reg, boot_err1_reg,
+ sts_boot_dev_sts0_reg,
+ sts_boot_dev_sts1_reg);
return -EIO;
}
- rc = hdev->asic_funcs->read_device_fw_version(hdev, FW_COMP_PREBOOT);
- if (rc)
- return rc;
+ /*
+ * the registers DEV_STS* contain FW capabilities/features.
+ * We can rely on this registers only if bit CPU_BOOT_DEV_STS*_ENABLED
+ * is set.
+ * In the first read of this register we store the value of this
+ * register ONLY if the register is enabled (which will be propagated
+ * to next stages) and also mark the register as valid.
+ * In case it is not enabled the stored value will be left 0- all
+ * caps/features are off
+ */
+ reg_val = RREG32(sts_boot_dev_sts0_reg);
+ if (reg_val & CPU_BOOT_DEV_STS0_ENABLED) {
+ prop->fw_cpu_boot_dev_sts0_valid = true;
+ prop->fw_preboot_cpu_boot_dev_sts0 = reg_val;
+ }
+
+ reg_val = RREG32(sts_boot_dev_sts1_reg);
+ if (reg_val & CPU_BOOT_DEV_STS1_ENABLED) {
+ prop->fw_cpu_boot_dev_sts1_valid = true;
+ prop->fw_preboot_cpu_boot_dev_sts1 = reg_val;
+ }
- security_status = RREG32(cpu_security_boot_status_reg);
+ prop->dynamic_fw_load = !!(prop->fw_preboot_cpu_boot_dev_sts0 &
+ CPU_BOOT_DEV_STS0_FW_LD_COM_EN);
+
+ /* initialize FW loader once we know what load protocol is used */
+ hdev->asic_funcs->init_firmware_loader(hdev);
+
+ dev_dbg(hdev->dev, "Attempting %s FW load\n",
+ prop->dynamic_fw_load ? "dynamic" : "legacy");
+ return 0;
+}
- /* We read security status multiple times during boot:
+static int hl_fw_static_read_device_fw_version(struct hl_device *hdev,
+ enum hl_fw_component fwc)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ struct fw_load_mgr *fw_loader = &hdev->fw_loader;
+ struct static_fw_load_mgr *static_loader;
+ char *dest, *boot_ver, *preboot_ver;
+ u32 ver_off, limit;
+ const char *name;
+ char btl_ver[32];
+
+ static_loader = &hdev->fw_loader.static_loader;
+
+ switch (fwc) {
+ case FW_COMP_BOOT_FIT:
+ ver_off = RREG32(static_loader->boot_fit_version_offset_reg);
+ dest = prop->uboot_ver;
+ name = "Boot-fit";
+ limit = static_loader->boot_fit_version_max_off;
+ break;
+ case FW_COMP_PREBOOT:
+ ver_off = RREG32(static_loader->preboot_version_offset_reg);
+ dest = prop->preboot_ver;
+ name = "Preboot";
+ limit = static_loader->preboot_version_max_off;
+ break;
+ default:
+ dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc);
+ return -EIO;
+ }
+
+ ver_off &= static_loader->sram_offset_mask;
+
+ if (ver_off < limit) {
+ memcpy_fromio(dest,
+ hdev->pcie_bar[fw_loader->sram_bar_id] + ver_off,
+ VERSION_MAX_LEN);
+ } else {
+ dev_err(hdev->dev, "%s version offset (0x%x) is above SRAM\n",
+ name, ver_off);
+ strscpy(dest, "unavailable", VERSION_MAX_LEN);
+ return -EIO;
+ }
+
+ if (fwc == FW_COMP_BOOT_FIT) {
+ boot_ver = extract_fw_ver_from_str(prop->uboot_ver);
+ if (boot_ver) {
+ dev_info(hdev->dev, "boot-fit version %s\n", boot_ver);
+ kfree(boot_ver);
+ }
+ } else if (fwc == FW_COMP_PREBOOT) {
+ preboot_ver = strnstr(prop->preboot_ver, "Preboot",
+ VERSION_MAX_LEN);
+ if (preboot_ver && preboot_ver != prop->preboot_ver) {
+ strscpy(btl_ver, prop->preboot_ver,
+ min((int) (preboot_ver - prop->preboot_ver),
+ 31));
+ dev_info(hdev->dev, "%s\n", btl_ver);
+ }
+
+ preboot_ver = extract_fw_ver_from_str(prop->preboot_ver);
+ if (preboot_ver) {
+ dev_info(hdev->dev, "preboot version %s\n",
+ preboot_ver);
+ kfree(preboot_ver);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * hl_fw_preboot_update_state - update internal data structures during
+ * handshake with preboot
+ *
+ *
+ * @hdev: pointer to the habanalabs device structure
+ *
+ * @return 0 on success, otherwise non-zero error code
+ */
+static void hl_fw_preboot_update_state(struct hl_device *hdev)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ u32 cpu_boot_dev_sts0, cpu_boot_dev_sts1;
+
+ cpu_boot_dev_sts0 = prop->fw_preboot_cpu_boot_dev_sts0;
+ cpu_boot_dev_sts1 = prop->fw_preboot_cpu_boot_dev_sts1;
+
+ /* We read boot_dev_sts registers multiple times during boot:
* 1. preboot - a. Check whether the security status bits are valid
* b. Check whether fw security is enabled
* c. Check whether hard reset is done by preboot
@@ -874,48 +1240,1121 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg,
* b. Check whether hard reset is done by fw app
*
* Preboot:
- * Check security status bit (CPU_BOOT_DEV_STS0_ENABLED), if it is set
+ * Check security status bit (CPU_BOOT_DEV_STS0_ENABLED). If set, then-
* check security enabled bit (CPU_BOOT_DEV_STS0_SECURITY_EN)
+ * If set, then mark GIC controller to be disabled.
*/
- if (security_status & CPU_BOOT_DEV_STS0_ENABLED) {
- prop->fw_security_status_valid = 1;
+ prop->hard_reset_done_by_fw =
+ !!(cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN);
- /* FW security should be derived from PCI ID, we keep this
- * check for backward compatibility
- */
- if (security_status & CPU_BOOT_DEV_STS0_SECURITY_EN)
- prop->fw_security_disabled = false;
+ dev_dbg(hdev->dev, "Firmware preboot boot device status0 %#x\n",
+ cpu_boot_dev_sts0);
+
+ dev_dbg(hdev->dev, "Firmware preboot boot device status1 %#x\n",
+ cpu_boot_dev_sts1);
+
+ dev_dbg(hdev->dev, "Firmware preboot hard-reset is %s\n",
+ prop->hard_reset_done_by_fw ? "enabled" : "disabled");
+
+ dev_dbg(hdev->dev, "firmware-level security is %s\n",
+ prop->fw_security_enabled ? "enabled" : "disabled");
+
+ dev_dbg(hdev->dev, "GIC controller is %s\n",
+ prop->gic_interrupts_enable ? "enabled" : "disabled");
+}
+
+static int hl_fw_static_read_preboot_status(struct hl_device *hdev)
+{
+ int rc;
+
+ rc = hl_fw_static_read_device_fw_version(hdev, FW_COMP_PREBOOT);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg,
+ u32 sts_boot_dev_sts0_reg,
+ u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg,
+ u32 boot_err1_reg, u32 timeout)
+{
+ int rc;
+
+ /* pldm was added for cases in which we use preboot on pldm and want
+ * to load boot fit, but we can't wait for preboot because it runs
+ * very slowly
+ */
+ if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU) || hdev->pldm)
+ return 0;
+
+ /*
+ * In order to determine boot method (static VS dymanic) we need to
+ * read the boot caps register
+ */
+ rc = hl_fw_read_preboot_caps(hdev, cpu_boot_status_reg,
+ sts_boot_dev_sts0_reg,
+ sts_boot_dev_sts1_reg, boot_err0_reg,
+ boot_err1_reg, timeout);
+ if (rc)
+ return rc;
+
+ hl_fw_preboot_update_state(hdev);
- if (security_status & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN)
+ /* no need to read preboot status in dynamic load */
+ if (hdev->asic_prop.dynamic_fw_load)
+ return 0;
+
+ return hl_fw_static_read_preboot_status(hdev);
+}
+
+/* associate string with COMM status */
+static char *hl_dynamic_fw_status_str[COMMS_STS_INVLD_LAST] = {
+ [COMMS_STS_NOOP] = "NOOP",
+ [COMMS_STS_ACK] = "ACK",
+ [COMMS_STS_OK] = "OK",
+ [COMMS_STS_ERR] = "ERR",
+ [COMMS_STS_VALID_ERR] = "VALID_ERR",
+ [COMMS_STS_TIMEOUT_ERR] = "TIMEOUT_ERR",
+};
+
+/**
+ * hl_fw_dynamic_report_error_status - report error status
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @status: value of FW status register
+ * @expected_status: the expected status
+ */
+static void hl_fw_dynamic_report_error_status(struct hl_device *hdev,
+ u32 status,
+ enum comms_sts expected_status)
+{
+ enum comms_sts comm_status =
+ FIELD_GET(COMMS_STATUS_STATUS_MASK, status);
+
+ if (comm_status < COMMS_STS_INVLD_LAST)
+ dev_err(hdev->dev, "Device status %s, expected status: %s\n",
+ hl_dynamic_fw_status_str[comm_status],
+ hl_dynamic_fw_status_str[expected_status]);
+ else
+ dev_err(hdev->dev, "Device status unknown %d, expected status: %s\n",
+ comm_status,
+ hl_dynamic_fw_status_str[expected_status]);
+}
+
+/**
+ * hl_fw_dynamic_send_cmd - send LKD to FW cmd
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fw_loader: managing structure for loading device's FW
+ * @cmd: LKD to FW cmd code
+ * @size: size of next FW component to be loaded (0 if not necessary)
+ *
+ * LDK to FW exact command layout is defined at struct comms_command.
+ * note: the size argument is used only when the next FW component should be
+ * loaded, otherwise it shall be 0. the size is used by the FW in later
+ * protocol stages and when sending only indicating the amount of memory
+ * to be allocated by the FW to receive the next boot component.
+ */
+static void hl_fw_dynamic_send_cmd(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader,
+ enum comms_cmd cmd, unsigned int size)
+{
+ struct cpu_dyn_regs *dyn_regs;
+ u32 val;
+
+ dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs;
+
+ val = FIELD_PREP(COMMS_COMMAND_CMD_MASK, cmd);
+ val |= FIELD_PREP(COMMS_COMMAND_SIZE_MASK, size);
+
+ WREG32(le32_to_cpu(dyn_regs->kmd_msg_to_cpu), val);
+}
+
+/**
+ * hl_fw_dynamic_extract_fw_response - update the FW response
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fw_loader: managing structure for loading device's FW
+ * @response: FW response
+ * @status: the status read from CPU status register
+ *
+ * @return 0 on success, otherwise non-zero error code
+ */
+static int hl_fw_dynamic_extract_fw_response(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader,
+ struct fw_response *response,
+ u32 status)
+{
+ response->status = FIELD_GET(COMMS_STATUS_STATUS_MASK, status);
+ response->ram_offset = FIELD_GET(COMMS_STATUS_OFFSET_MASK, status) <<
+ COMMS_STATUS_OFFSET_ALIGN_SHIFT;
+ response->ram_type = FIELD_GET(COMMS_STATUS_RAM_TYPE_MASK, status);
+
+ if ((response->ram_type != COMMS_SRAM) &&
+ (response->ram_type != COMMS_DRAM)) {
+ dev_err(hdev->dev, "FW status: invalid RAM type %u\n",
+ response->ram_type);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * hl_fw_dynamic_wait_for_status - wait for status in dynamic FW load
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fw_loader: managing structure for loading device's FW
+ * @expected_status: expected status to wait for
+ * @timeout: timeout for status wait
+ *
+ * @return 0 on success, otherwise non-zero error code
+ *
+ * waiting for status from FW include polling the FW status register until
+ * expected status is received or timeout occurs (whatever occurs first).
+ */
+static int hl_fw_dynamic_wait_for_status(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader,
+ enum comms_sts expected_status,
+ u32 timeout)
+{
+ struct cpu_dyn_regs *dyn_regs;
+ u32 status;
+ int rc;
+
+ dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs;
+
+ /* Wait for expected status */
+ rc = hl_poll_timeout(
+ hdev,
+ le32_to_cpu(dyn_regs->cpu_cmd_status_to_host),
+ status,
+ FIELD_GET(COMMS_STATUS_STATUS_MASK, status) == expected_status,
+ FW_CPU_STATUS_POLL_INTERVAL_USEC,
+ timeout);
+
+ if (rc) {
+ hl_fw_dynamic_report_error_status(hdev, status,
+ expected_status);
+ return -EIO;
+ }
+
+ /*
+ * skip storing FW response for NOOP to preserve the actual desired
+ * FW status
+ */
+ if (expected_status == COMMS_STS_NOOP)
+ return 0;
+
+ rc = hl_fw_dynamic_extract_fw_response(hdev, fw_loader,
+ &fw_loader->dynamic_loader.response,
+ status);
+ return rc;
+}
+
+/**
+ * hl_fw_dynamic_send_clear_cmd - send clear command to FW
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fw_loader: managing structure for loading device's FW
+ *
+ * @return 0 on success, otherwise non-zero error code
+ *
+ * after command cycle between LKD to FW CPU (i.e. LKD got an expected status
+ * from FW) we need to clear the CPU status register in order to avoid garbage
+ * between command cycles.
+ * This is done by sending clear command and polling the CPU to LKD status
+ * register to hold the status NOOP
+ */
+static int hl_fw_dynamic_send_clear_cmd(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader)
+{
+ hl_fw_dynamic_send_cmd(hdev, fw_loader, COMMS_CLR_STS, 0);
+
+ return hl_fw_dynamic_wait_for_status(hdev, fw_loader, COMMS_STS_NOOP,
+ fw_loader->cpu_timeout);
+}
+
+/**
+ * hl_fw_dynamic_send_protocol_cmd - send LKD to FW cmd and wait for ACK
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fw_loader: managing structure for loading device's FW
+ * @cmd: LKD to FW cmd code
+ * @size: size of next FW component to be loaded (0 if not necessary)
+ * @wait_ok: if true also wait for OK response from FW
+ * @timeout: timeout for status wait
+ *
+ * @return 0 on success, otherwise non-zero error code
+ *
+ * brief:
+ * when sending protocol command we have the following steps:
+ * - send clear (clear command and verify clear status register)
+ * - send the actual protocol command
+ * - wait for ACK on the protocol command
+ * - send clear
+ * - send NOOP
+ * if, in addition, the specific protocol command should wait for OK then:
+ * - wait for OK
+ * - send clear
+ * - send NOOP
+ *
+ * NOTES:
+ * send clear: this is necessary in order to clear the status register to avoid
+ * leftovers between command
+ * NOOP command: necessary to avoid loop on the clear command by the FW
+ */
+int hl_fw_dynamic_send_protocol_cmd(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader,
+ enum comms_cmd cmd, unsigned int size,
+ bool wait_ok, u32 timeout)
+{
+ int rc;
+
+ /* first send clear command to clean former commands */
+ rc = hl_fw_dynamic_send_clear_cmd(hdev, fw_loader);
+
+ /* send the actual command */
+ hl_fw_dynamic_send_cmd(hdev, fw_loader, cmd, size);
+
+ /* wait for ACK for the command */
+ rc = hl_fw_dynamic_wait_for_status(hdev, fw_loader, COMMS_STS_ACK,
+ timeout);
+ if (rc)
+ return rc;
+
+ /* clear command to prepare for NOOP command */
+ rc = hl_fw_dynamic_send_clear_cmd(hdev, fw_loader);
+ if (rc)
+ return rc;
+
+ /* send the actual NOOP command */
+ hl_fw_dynamic_send_cmd(hdev, fw_loader, COMMS_NOOP, 0);
+
+ if (!wait_ok)
+ return 0;
+
+ rc = hl_fw_dynamic_wait_for_status(hdev, fw_loader, COMMS_STS_OK,
+ timeout);
+ if (rc)
+ return rc;
+
+ /* clear command to prepare for NOOP command */
+ rc = hl_fw_dynamic_send_clear_cmd(hdev, fw_loader);
+ if (rc)
+ return rc;
+
+ /* send the actual NOOP command */
+ hl_fw_dynamic_send_cmd(hdev, fw_loader, COMMS_NOOP, 0);
+
+ return 0;
+}
+
+/**
+ * hl_fw_compat_crc32 - CRC compatible with FW
+ *
+ * @data: pointer to the data
+ * @size: size of the data
+ *
+ * @return the CRC32 result
+ *
+ * NOTE: kernel's CRC32 differ's from standard CRC32 calculation.
+ * in order to be aligned we need to flip the bits of both the input
+ * initial CRC and kernel's CRC32 result.
+ * in addition both sides use initial CRC of 0,
+ */
+static u32 hl_fw_compat_crc32(u8 *data, size_t size)
+{
+ return ~crc32_le(~((u32)0), data, size);
+}
+
+/**
+ * hl_fw_dynamic_validate_memory_bound - validate memory bounds for memory
+ * transfer (image or descriptor) between
+ * host and FW
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @addr: device address of memory transfer
+ * @size: memory transter size
+ * @region: PCI memory region
+ *
+ * @return 0 on success, otherwise non-zero error code
+ */
+static int hl_fw_dynamic_validate_memory_bound(struct hl_device *hdev,
+ u64 addr, size_t size,
+ struct pci_mem_region *region)
+{
+ u64 end_addr;
+
+ /* now make sure that the memory transfer is within region's bounds */
+ end_addr = addr + size;
+ if (end_addr >= region->region_base + region->region_size) {
+ dev_err(hdev->dev,
+ "dynamic FW load: memory transfer end address out of memory region bounds. addr: %llx\n",
+ end_addr);
+ return -EIO;
+ }
+
+ /*
+ * now make sure memory transfer is within predefined BAR bounds.
+ * this is to make sure we do not need to set the bar (e.g. for DRAM
+ * memory transfers)
+ */
+ if (end_addr >= region->region_base - region->offset_in_bar +
+ region->bar_size) {
+ dev_err(hdev->dev,
+ "FW image beyond PCI BAR bounds\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * hl_fw_dynamic_validate_descriptor - validate FW descriptor
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fw_loader: managing structure for loading device's FW
+ * @fw_desc: the descriptor form FW
+ *
+ * @return 0 on success, otherwise non-zero error code
+ */
+static int hl_fw_dynamic_validate_descriptor(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader,
+ struct lkd_fw_comms_desc *fw_desc)
+{
+ struct pci_mem_region *region;
+ enum pci_region region_id;
+ size_t data_size;
+ u32 data_crc32;
+ u8 *data_ptr;
+ u64 addr;
+ int rc;
+
+ if (le32_to_cpu(fw_desc->header.magic) != HL_COMMS_DESC_MAGIC) {
+ dev_err(hdev->dev, "Invalid magic for dynamic FW descriptor (%x)\n",
+ fw_desc->header.magic);
+ return -EIO;
+ }
+
+ if (fw_desc->header.version != HL_COMMS_DESC_VER) {
+ dev_err(hdev->dev, "Invalid version for dynamic FW descriptor (%x)\n",
+ fw_desc->header.version);
+ return -EIO;
+ }
+
+ /*
+ * calc CRC32 of data without header.
+ * note that no alignment/stride address issues here as all structures
+ * are 64 bit padded
+ */
+ data_size = sizeof(struct lkd_fw_comms_desc) -
+ sizeof(struct comms_desc_header);
+ data_ptr = (u8 *)fw_desc + sizeof(struct comms_desc_header);
+
+ if (le16_to_cpu(fw_desc->header.size) != data_size) {
+ dev_err(hdev->dev,
+ "Invalid descriptor size 0x%x, expected size 0x%zx\n",
+ le16_to_cpu(fw_desc->header.size), data_size);
+ return -EIO;
+ }
+
+ data_crc32 = hl_fw_compat_crc32(data_ptr, data_size);
+
+ if (data_crc32 != le32_to_cpu(fw_desc->header.crc32)) {
+ dev_err(hdev->dev,
+ "CRC32 mismatch for dynamic FW descriptor (%x:%x)\n",
+ data_crc32, fw_desc->header.crc32);
+ return -EIO;
+ }
+
+ /* find memory region to which to copy the image */
+ addr = le64_to_cpu(fw_desc->img_addr);
+ region_id = hl_get_pci_memory_region(hdev, addr);
+ if ((region_id != PCI_REGION_SRAM) &&
+ ((region_id != PCI_REGION_DRAM))) {
+ dev_err(hdev->dev,
+ "Invalid region to copy FW image address=%llx\n", addr);
+ return -EIO;
+ }
+
+ region = &hdev->pci_mem_region[region_id];
+
+ /* store the region for the copy stage */
+ fw_loader->dynamic_loader.image_region = region;
+
+ /*
+ * here we know that the start address is valid, now make sure that the
+ * image is within region's bounds
+ */
+ rc = hl_fw_dynamic_validate_memory_bound(hdev, addr,
+ fw_loader->dynamic_loader.fw_image_size,
+ region);
+ if (rc) {
+ dev_err(hdev->dev,
+ "invalid mem transfer request for FW image\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static int hl_fw_dynamic_validate_response(struct hl_device *hdev,
+ struct fw_response *response,
+ struct pci_mem_region *region)
+{
+ u64 device_addr;
+ int rc;
+
+ device_addr = region->region_base + response->ram_offset;
+
+ /*
+ * validate that the descriptor is within region's bounds
+ * Note that as the start address was supplied according to the RAM
+ * type- testing only the end address is enough
+ */
+ rc = hl_fw_dynamic_validate_memory_bound(hdev, device_addr,
+ sizeof(struct lkd_fw_comms_desc),
+ region);
+ return rc;
+}
+
+/**
+ * hl_fw_dynamic_read_and_validate_descriptor - read and validate FW descriptor
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fw_loader: managing structure for loading device's FW
+ *
+ * @return 0 on success, otherwise non-zero error code
+ */
+static int hl_fw_dynamic_read_and_validate_descriptor(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader)
+{
+ struct lkd_fw_comms_desc *fw_desc;
+ struct pci_mem_region *region;
+ struct fw_response *response;
+ enum pci_region region_id;
+ void __iomem *src;
+ int rc;
+
+ fw_desc = &fw_loader->dynamic_loader.comm_desc;
+ response = &fw_loader->dynamic_loader.response;
+
+ region_id = (response->ram_type == COMMS_SRAM) ?
+ PCI_REGION_SRAM : PCI_REGION_DRAM;
+
+ region = &hdev->pci_mem_region[region_id];
+
+ rc = hl_fw_dynamic_validate_response(hdev, response, region);
+ if (rc) {
+ dev_err(hdev->dev,
+ "invalid mem transfer request for FW descriptor\n");
+ return rc;
+ }
+
+ /* extract address copy the descriptor from */
+ src = hdev->pcie_bar[region->bar_id] + region->offset_in_bar +
+ response->ram_offset;
+ memcpy_fromio(fw_desc, src, sizeof(struct lkd_fw_comms_desc));
+
+ return hl_fw_dynamic_validate_descriptor(hdev, fw_loader, fw_desc);
+}
+
+/**
+ * hl_fw_dynamic_request_descriptor - handshake with CPU to get FW descriptor
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fw_loader: managing structure for loading device's FW
+ * @next_image_size: size to allocate for next FW component
+ *
+ * @return 0 on success, otherwise non-zero error code
+ */
+static int hl_fw_dynamic_request_descriptor(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader,
+ size_t next_image_size)
+{
+ int rc;
+
+ rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_PREP_DESC,
+ next_image_size, true,
+ fw_loader->cpu_timeout);
+ if (rc)
+ return rc;
+
+ return hl_fw_dynamic_read_and_validate_descriptor(hdev, fw_loader);
+}
+
+/**
+ * hl_fw_dynamic_read_device_fw_version - read FW version to exposed properties
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fwc: the firmware component
+ * @fw_version: fw component's version string
+ */
+static void hl_fw_dynamic_read_device_fw_version(struct hl_device *hdev,
+ enum hl_fw_component fwc,
+ const char *fw_version)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ char *preboot_ver, *boot_ver;
+ char btl_ver[32];
+
+ switch (fwc) {
+ case FW_COMP_BOOT_FIT:
+ strscpy(prop->uboot_ver, fw_version, VERSION_MAX_LEN);
+ boot_ver = extract_fw_ver_from_str(prop->uboot_ver);
+ if (boot_ver) {
+ dev_info(hdev->dev, "boot-fit version %s\n", boot_ver);
+ kfree(boot_ver);
+ }
+
+ break;
+ case FW_COMP_PREBOOT:
+ strscpy(prop->preboot_ver, fw_version, VERSION_MAX_LEN);
+ preboot_ver = strnstr(prop->preboot_ver, "Preboot",
+ VERSION_MAX_LEN);
+ if (preboot_ver && preboot_ver != prop->preboot_ver) {
+ strscpy(btl_ver, prop->preboot_ver,
+ min((int) (preboot_ver - prop->preboot_ver),
+ 31));
+ dev_info(hdev->dev, "%s\n", btl_ver);
+ }
+
+ preboot_ver = extract_fw_ver_from_str(prop->preboot_ver);
+ if (preboot_ver) {
+ dev_info(hdev->dev, "preboot version %s\n",
+ preboot_ver);
+ kfree(preboot_ver);
+ }
+
+ break;
+ default:
+ dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc);
+ return;
+ }
+}
+
+/**
+ * hl_fw_dynamic_copy_image - copy image to memory allocated by the FW
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fw: fw descriptor
+ * @fw_loader: managing structure for loading device's FW
+ */
+static int hl_fw_dynamic_copy_image(struct hl_device *hdev,
+ const struct firmware *fw,
+ struct fw_load_mgr *fw_loader)
+{
+ struct lkd_fw_comms_desc *fw_desc;
+ struct pci_mem_region *region;
+ void __iomem *dest;
+ u64 addr;
+ int rc;
+
+ fw_desc = &fw_loader->dynamic_loader.comm_desc;
+ addr = le64_to_cpu(fw_desc->img_addr);
+
+ /* find memory region to which to copy the image */
+ region = fw_loader->dynamic_loader.image_region;
+
+ dest = hdev->pcie_bar[region->bar_id] + region->offset_in_bar +
+ (addr - region->region_base);
+
+ rc = hl_fw_copy_fw_to_device(hdev, fw, dest,
+ fw_loader->boot_fit_img.src_off,
+ fw_loader->boot_fit_img.copy_size);
+
+ return rc;
+}
+
+/**
+ * hl_fw_dynamic_copy_msg - copy msg to memory allocated by the FW
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @msg: message
+ * @fw_loader: managing structure for loading device's FW
+ */
+static int hl_fw_dynamic_copy_msg(struct hl_device *hdev,
+ struct lkd_msg_comms *msg, struct fw_load_mgr *fw_loader)
+{
+ struct lkd_fw_comms_desc *fw_desc;
+ struct pci_mem_region *region;
+ void __iomem *dest;
+ u64 addr;
+ int rc;
+
+ fw_desc = &fw_loader->dynamic_loader.comm_desc;
+ addr = le64_to_cpu(fw_desc->img_addr);
+
+ /* find memory region to which to copy the image */
+ region = fw_loader->dynamic_loader.image_region;
+
+ dest = hdev->pcie_bar[region->bar_id] + region->offset_in_bar +
+ (addr - region->region_base);
+
+ rc = hl_fw_copy_msg_to_device(hdev, msg, dest, 0, 0);
+
+ return rc;
+}
+
+/**
+ * hl_fw_boot_fit_update_state - update internal data structures after boot-fit
+ * is loaded
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @cpu_boot_dev_sts0_reg: register holding CPU boot dev status 0
+ * @cpu_boot_dev_sts1_reg: register holding CPU boot dev status 1
+ *
+ * @return 0 on success, otherwise non-zero error code
+ */
+static void hl_fw_boot_fit_update_state(struct hl_device *hdev,
+ u32 cpu_boot_dev_sts0_reg,
+ u32 cpu_boot_dev_sts1_reg)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+
+ /* Clear reset status since we need to read it again from boot CPU */
+ prop->hard_reset_done_by_fw = false;
+
+ /* Read boot_cpu status bits */
+ if (prop->fw_preboot_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_ENABLED) {
+ prop->fw_bootfit_cpu_boot_dev_sts0 =
+ RREG32(cpu_boot_dev_sts0_reg);
+
+ if (prop->fw_bootfit_cpu_boot_dev_sts0 &
+ CPU_BOOT_DEV_STS0_FW_HARD_RST_EN)
prop->hard_reset_done_by_fw = true;
- } else {
- prop->fw_security_status_valid = 0;
+
+ dev_dbg(hdev->dev, "Firmware boot CPU status0 %#x\n",
+ prop->fw_bootfit_cpu_boot_dev_sts0);
}
- dev_dbg(hdev->dev, "Firmware preboot security status %#x\n",
- security_status);
+ if (prop->fw_cpu_boot_dev_sts1_valid) {
+ prop->fw_bootfit_cpu_boot_dev_sts1 =
+ RREG32(cpu_boot_dev_sts1_reg);
- dev_dbg(hdev->dev, "Firmware preboot hard-reset is %s\n",
+ dev_dbg(hdev->dev, "Firmware boot CPU status1 %#x\n",
+ prop->fw_bootfit_cpu_boot_dev_sts1);
+ }
+
+ dev_dbg(hdev->dev, "Firmware boot CPU hard-reset is %s\n",
prop->hard_reset_done_by_fw ? "enabled" : "disabled");
+}
+
+static void hl_fw_dynamic_update_linux_interrupt_if(struct hl_device *hdev)
+{
+ struct cpu_dyn_regs *dyn_regs =
+ &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
+
+ /* Check whether all 3 interrupt interfaces are set, if not use a
+ * single interface
+ */
+ if (!hdev->asic_prop.gic_interrupts_enable &&
+ !(hdev->asic_prop.fw_app_cpu_boot_dev_sts0 &
+ CPU_BOOT_DEV_STS0_MULTI_IRQ_POLL_EN)) {
+ dyn_regs->gic_host_halt_irq = dyn_regs->gic_host_irq_ctrl;
+ dyn_regs->gic_host_ints_irq = dyn_regs->gic_host_irq_ctrl;
+
+ dev_warn(hdev->dev,
+ "Using a single interrupt interface towards cpucp");
+ }
+}
+/**
+ * hl_fw_dynamic_load_image - load FW image using dynamic protocol
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fw_loader: managing structure for loading device's FW
+ * @load_fwc: the FW component to be loaded
+ * @img_ld_timeout: image load timeout
+ *
+ * @return 0 on success, otherwise non-zero error code
+ */
+static int hl_fw_dynamic_load_image(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader,
+ enum hl_fw_component load_fwc,
+ u32 img_ld_timeout)
+{
+ enum hl_fw_component cur_fwc;
+ const struct firmware *fw;
+ char *fw_name;
+ int rc = 0;
+
+ /*
+ * when loading image we have one of 2 scenarios:
+ * 1. current FW component is preboot and we want to load boot-fit
+ * 2. current FW component is boot-fit and we want to load linux
+ */
+ if (load_fwc == FW_COMP_BOOT_FIT) {
+ cur_fwc = FW_COMP_PREBOOT;
+ fw_name = fw_loader->boot_fit_img.image_name;
+ } else {
+ cur_fwc = FW_COMP_BOOT_FIT;
+ fw_name = fw_loader->linux_img.image_name;
+ }
+
+ /* request FW in order to communicate to FW the size to be allocated */
+ rc = hl_request_fw(hdev, &fw, fw_name);
+ if (rc)
+ return rc;
+
+ /* store the image size for future validation */
+ fw_loader->dynamic_loader.fw_image_size = fw->size;
+
+ rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader, fw->size);
+ if (rc)
+ goto release_fw;
+
+ /* read preboot version */
+ hl_fw_dynamic_read_device_fw_version(hdev, cur_fwc,
+ fw_loader->dynamic_loader.comm_desc.cur_fw_ver);
+
+
+ /* update state according to boot stage */
+ if (cur_fwc == FW_COMP_BOOT_FIT) {
+ struct cpu_dyn_regs *dyn_regs;
+
+ dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs;
+ hl_fw_boot_fit_update_state(hdev,
+ le32_to_cpu(dyn_regs->cpu_boot_dev_sts0),
+ le32_to_cpu(dyn_regs->cpu_boot_dev_sts1));
+ }
+
+ /* copy boot fit to space allocated by FW */
+ rc = hl_fw_dynamic_copy_image(hdev, fw, fw_loader);
+ if (rc)
+ goto release_fw;
- dev_info(hdev->dev, "firmware-level security is %s\n",
- prop->fw_security_disabled ? "disabled" : "enabled");
+ rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_DATA_RDY,
+ 0, true,
+ fw_loader->cpu_timeout);
+ if (rc)
+ goto release_fw;
+
+ rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_EXEC,
+ 0, false,
+ img_ld_timeout);
+release_fw:
+ hl_release_firmware(fw);
+ return rc;
+}
+
+static int hl_fw_dynamic_wait_for_boot_fit_active(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader)
+{
+ struct dynamic_fw_load_mgr *dyn_loader;
+ u32 status;
+ int rc;
+
+ dyn_loader = &fw_loader->dynamic_loader;
+
+ /* Make sure CPU boot-loader is running */
+ rc = hl_poll_timeout(
+ hdev,
+ le32_to_cpu(dyn_loader->comm_desc.cpu_dyn_regs.cpu_boot_status),
+ status,
+ (status == CPU_BOOT_STATUS_NIC_FW_RDY) ||
+ (status == CPU_BOOT_STATUS_READY_TO_BOOT),
+ FW_CPU_STATUS_POLL_INTERVAL_USEC,
+ dyn_loader->wait_for_bl_timeout);
+ if (rc) {
+ dev_err(hdev->dev, "failed to wait for boot\n");
+ return rc;
+ }
+
+ dev_dbg(hdev->dev, "uboot status = %d\n", status);
return 0;
}
-int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg,
- u32 msg_to_cpu_reg, u32 cpu_msg_status_reg,
- u32 cpu_security_boot_status_reg, u32 boot_err0_reg,
- bool skip_bmc, u32 cpu_timeout, u32 boot_fit_timeout)
+static int hl_fw_dynamic_wait_for_linux_active(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader)
{
- struct asic_fixed_properties *prop = &hdev->asic_prop;
+ struct dynamic_fw_load_mgr *dyn_loader;
u32 status;
int rc;
+ dyn_loader = &fw_loader->dynamic_loader;
+
+ /* Make sure CPU boot-loader is running */
+
+ rc = hl_poll_timeout(
+ hdev,
+ le32_to_cpu(dyn_loader->comm_desc.cpu_dyn_regs.cpu_boot_status),
+ status,
+ (status == CPU_BOOT_STATUS_SRAM_AVAIL),
+ FW_CPU_STATUS_POLL_INTERVAL_USEC,
+ fw_loader->cpu_timeout);
+ if (rc) {
+ dev_err(hdev->dev, "failed to wait for Linux\n");
+ return rc;
+ }
+
+ dev_dbg(hdev->dev, "Boot status = %d\n", status);
+ return 0;
+}
+
+/**
+ * hl_fw_linux_update_state - update internal data structures after Linux
+ * is loaded.
+ * Note: Linux initialization is comprised mainly
+ * of two stages - loading kernel (SRAM_AVAIL)
+ * & loading ARMCP.
+ * Therefore reading boot device status in any of
+ * these stages might result in different values.
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @cpu_boot_dev_sts0_reg: register holding CPU boot dev status 0
+ * @cpu_boot_dev_sts1_reg: register holding CPU boot dev status 1
+ *
+ * @return 0 on success, otherwise non-zero error code
+ */
+static void hl_fw_linux_update_state(struct hl_device *hdev,
+ u32 cpu_boot_dev_sts0_reg,
+ u32 cpu_boot_dev_sts1_reg)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+
+ hdev->fw_loader.linux_loaded = true;
+
+ /* Clear reset status since we need to read again from app */
+ prop->hard_reset_done_by_fw = false;
+
+ /* Read FW application security bits */
+ if (prop->fw_cpu_boot_dev_sts0_valid) {
+ prop->fw_app_cpu_boot_dev_sts0 =
+ RREG32(cpu_boot_dev_sts0_reg);
+
+ if (prop->fw_app_cpu_boot_dev_sts0 &
+ CPU_BOOT_DEV_STS0_FW_HARD_RST_EN)
+ prop->hard_reset_done_by_fw = true;
+
+ if (prop->fw_app_cpu_boot_dev_sts0 &
+ CPU_BOOT_DEV_STS0_GIC_PRIVILEGED_EN)
+ prop->gic_interrupts_enable = false;
+
+ dev_dbg(hdev->dev,
+ "Firmware application CPU status0 %#x\n",
+ prop->fw_app_cpu_boot_dev_sts0);
+
+ dev_dbg(hdev->dev, "GIC controller is %s\n",
+ prop->gic_interrupts_enable ?
+ "enabled" : "disabled");
+ }
+
+ if (prop->fw_cpu_boot_dev_sts1_valid) {
+ prop->fw_app_cpu_boot_dev_sts1 =
+ RREG32(cpu_boot_dev_sts1_reg);
+
+ dev_dbg(hdev->dev,
+ "Firmware application CPU status1 %#x\n",
+ prop->fw_app_cpu_boot_dev_sts1);
+ }
+
+ dev_dbg(hdev->dev, "Firmware application CPU hard-reset is %s\n",
+ prop->hard_reset_done_by_fw ? "enabled" : "disabled");
+
+ dev_info(hdev->dev, "Successfully loaded firmware to device\n");
+}
+
+/**
+ * hl_fw_dynamic_report_reset_cause - send a COMMS message with the cause
+ * of the newly triggered hard reset
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fw_loader: managing structure for loading device's FW
+ * @reset_cause: enumerated cause for the recent hard reset
+ *
+ * @return 0 on success, otherwise non-zero error code
+ */
+static int hl_fw_dynamic_report_reset_cause(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader,
+ enum comms_reset_cause reset_cause)
+{
+ struct lkd_msg_comms msg;
+ int rc;
+
+ memset(&msg, 0, sizeof(msg));
+
+ /* create message to be sent */
+ msg.header.type = HL_COMMS_RESET_CAUSE_TYPE;
+ msg.header.size = cpu_to_le16(sizeof(struct comms_msg_header));
+ msg.header.magic = cpu_to_le32(HL_COMMS_MSG_MAGIC);
+
+ msg.reset_cause = reset_cause;
+
+ rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader,
+ sizeof(struct lkd_msg_comms));
+ if (rc)
+ return rc;
+
+ /* copy message to space allocated by FW */
+ rc = hl_fw_dynamic_copy_msg(hdev, &msg, fw_loader);
+ if (rc)
+ return rc;
+
+ rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_DATA_RDY,
+ 0, true,
+ fw_loader->cpu_timeout);
+ if (rc)
+ return rc;
+
+ rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_EXEC,
+ 0, true,
+ fw_loader->cpu_timeout);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+/**
+ * hl_fw_dynamic_init_cpu - initialize the device CPU using dynamic protocol
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fw_loader: managing structure for loading device's FW
+ *
+ * @return 0 on success, otherwise non-zero error code
+ *
+ * brief: the dynamic protocol is master (LKD) slave (FW CPU) protocol.
+ * the communication is done using registers:
+ * - LKD command register
+ * - FW status register
+ * the protocol is race free. this goal is achieved by splitting the requests
+ * and response to known synchronization points between the LKD and the FW.
+ * each response to LKD request is known and bound to a predefined timeout.
+ * in case of timeout expiration without the desired status from FW- the
+ * protocol (and hence the boot) will fail.
+ */
+static int hl_fw_dynamic_init_cpu(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader)
+{
+ struct cpu_dyn_regs *dyn_regs;
+ int rc;
+
+ dev_info(hdev->dev,
+ "Loading firmware to device, may take some time...\n");
+
+ dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs;
+
+ rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_RST_STATE,
+ 0, true,
+ fw_loader->cpu_timeout);
+ if (rc)
+ goto protocol_err;
+
+ if (hdev->curr_reset_cause) {
+ rc = hl_fw_dynamic_report_reset_cause(hdev, fw_loader,
+ hdev->curr_reset_cause);
+ if (rc)
+ goto protocol_err;
+
+ /* Clear current reset cause */
+ hdev->curr_reset_cause = HL_RESET_CAUSE_UNKNOWN;
+ }
+
+ if (!(hdev->fw_components & FW_TYPE_BOOT_CPU)) {
+ rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader, 0);
+ if (rc)
+ goto protocol_err;
+
+ /* read preboot version */
+ hl_fw_dynamic_read_device_fw_version(hdev, FW_COMP_PREBOOT,
+ fw_loader->dynamic_loader.comm_desc.cur_fw_ver);
+ return 0;
+ }
+
+ /* load boot fit to FW */
+ rc = hl_fw_dynamic_load_image(hdev, fw_loader, FW_COMP_BOOT_FIT,
+ fw_loader->boot_fit_timeout);
+ if (rc) {
+ dev_err(hdev->dev, "failed to load boot fit\n");
+ goto protocol_err;
+ }
+
+ rc = hl_fw_dynamic_wait_for_boot_fit_active(hdev, fw_loader);
+ if (rc)
+ goto protocol_err;
+
+ /* Enable DRAM scrambling before Linux boot and after successful
+ * UBoot
+ */
+ hdev->asic_funcs->init_cpu_scrambler_dram(hdev);
+
+ if (!(hdev->fw_components & FW_TYPE_LINUX)) {
+ dev_info(hdev->dev, "Skip loading Linux F/W\n");
+ return 0;
+ }
+
+ if (fw_loader->skip_bmc) {
+ rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader,
+ COMMS_SKIP_BMC, 0,
+ true,
+ fw_loader->cpu_timeout);
+ if (rc) {
+ dev_err(hdev->dev, "failed to load boot fit\n");
+ goto protocol_err;
+ }
+ }
+
+ /* load Linux image to FW */
+ rc = hl_fw_dynamic_load_image(hdev, fw_loader, FW_COMP_LINUX,
+ fw_loader->cpu_timeout);
+ if (rc) {
+ dev_err(hdev->dev, "failed to load Linux\n");
+ goto protocol_err;
+ }
+
+ rc = hl_fw_dynamic_wait_for_linux_active(hdev, fw_loader);
+ if (rc)
+ goto protocol_err;
+
+ hl_fw_linux_update_state(hdev, le32_to_cpu(dyn_regs->cpu_boot_dev_sts0),
+ le32_to_cpu(dyn_regs->cpu_boot_dev_sts1));
+
+ hl_fw_dynamic_update_linux_interrupt_if(hdev);
+
+ return 0;
+
+protocol_err:
+ fw_read_errors(hdev, le32_to_cpu(dyn_regs->cpu_boot_err0),
+ le32_to_cpu(dyn_regs->cpu_boot_err1),
+ le32_to_cpu(dyn_regs->cpu_boot_dev_sts0),
+ le32_to_cpu(dyn_regs->cpu_boot_dev_sts1));
+ return rc;
+}
+
+/**
+ * hl_fw_static_init_cpu - initialize the device CPU using static protocol
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fw_loader: managing structure for loading device's FW
+ *
+ * @return 0 on success, otherwise non-zero error code
+ */
+static int hl_fw_static_init_cpu(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader)
+{
+ u32 cpu_msg_status_reg, cpu_timeout, msg_to_cpu_reg, status;
+ u32 cpu_boot_dev_status0_reg, cpu_boot_dev_status1_reg;
+ struct static_fw_load_mgr *static_loader;
+ u32 cpu_boot_status_reg;
+ int rc;
+
if (!(hdev->fw_components & FW_TYPE_BOOT_CPU))
return 0;
+ /* init common loader parameters */
+ cpu_timeout = fw_loader->cpu_timeout;
+
+ /* init static loader parameters */
+ static_loader = &fw_loader->static_loader;
+ cpu_msg_status_reg = static_loader->cpu_cmd_status_to_host_reg;
+ msg_to_cpu_reg = static_loader->kmd_msg_to_cpu_reg;
+ cpu_boot_dev_status0_reg = static_loader->cpu_boot_dev_status0_reg;
+ cpu_boot_dev_status1_reg = static_loader->cpu_boot_dev_status1_reg;
+ cpu_boot_status_reg = static_loader->cpu_boot_status_reg;
+
dev_info(hdev->dev, "Going to wait for device boot (up to %lds)\n",
cpu_timeout / USEC_PER_SEC);
@@ -925,8 +2364,8 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg,
cpu_boot_status_reg,
status,
status == CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT,
- 10000,
- boot_fit_timeout);
+ FW_CPU_STATUS_POLL_INTERVAL_USEC,
+ fw_loader->boot_fit_timeout);
if (rc) {
dev_dbg(hdev->dev,
@@ -948,8 +2387,8 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg,
cpu_msg_status_reg,
status,
status == CPU_MSG_OK,
- 10000,
- boot_fit_timeout);
+ FW_CPU_STATUS_POLL_INTERVAL_USEC,
+ fw_loader->boot_fit_timeout);
if (rc) {
dev_err(hdev->dev,
@@ -970,33 +2409,17 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg,
(status == CPU_BOOT_STATUS_NIC_FW_RDY) ||
(status == CPU_BOOT_STATUS_READY_TO_BOOT) ||
(status == CPU_BOOT_STATUS_SRAM_AVAIL),
- 10000,
+ FW_CPU_STATUS_POLL_INTERVAL_USEC,
cpu_timeout);
dev_dbg(hdev->dev, "uboot status = %d\n", status);
/* Read U-Boot version now in case we will later fail */
- hdev->asic_funcs->read_device_fw_version(hdev, FW_COMP_UBOOT);
-
- /* Clear reset status since we need to read it again from boot CPU */
- prop->hard_reset_done_by_fw = false;
-
- /* Read boot_cpu security bits */
- if (prop->fw_security_status_valid) {
- prop->fw_boot_cpu_security_map =
- RREG32(cpu_security_boot_status_reg);
-
- if (prop->fw_boot_cpu_security_map &
- CPU_BOOT_DEV_STS0_FW_HARD_RST_EN)
- prop->hard_reset_done_by_fw = true;
-
- dev_dbg(hdev->dev,
- "Firmware boot CPU security status %#x\n",
- prop->fw_boot_cpu_security_map);
- }
+ hl_fw_static_read_device_fw_version(hdev, FW_COMP_BOOT_FIT);
- dev_dbg(hdev->dev, "Firmware boot CPU hard-reset is %s\n",
- prop->hard_reset_done_by_fw ? "enabled" : "disabled");
+ /* update state according to boot stage */
+ hl_fw_boot_fit_update_state(hdev, cpu_boot_dev_status0_reg,
+ cpu_boot_dev_status1_reg);
if (rc) {
detect_cpu_boot_status(hdev, status);
@@ -1004,13 +2427,21 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg,
goto out;
}
+ /* Enable DRAM scrambling before Linux boot and after successful
+ * UBoot
+ */
+ hdev->asic_funcs->init_cpu_scrambler_dram(hdev);
+
if (!(hdev->fw_components & FW_TYPE_LINUX)) {
dev_info(hdev->dev, "Skip loading Linux F/W\n");
+ rc = 0;
goto out;
}
- if (status == CPU_BOOT_STATUS_SRAM_AVAIL)
+ if (status == CPU_BOOT_STATUS_SRAM_AVAIL) {
+ rc = 0;
goto out;
+ }
dev_info(hdev->dev,
"Loading firmware to device, may take some time...\n");
@@ -1019,7 +2450,7 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg,
if (rc)
goto out;
- if (skip_bmc) {
+ if (fw_loader->skip_bmc) {
WREG32(msg_to_cpu_reg, KMD_MSG_SKIP_BMC);
rc = hl_poll_timeout(
@@ -1027,7 +2458,7 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg,
cpu_boot_status_reg,
status,
(status == CPU_BOOT_STATUS_BMC_WAITING_SKIPPED),
- 10000,
+ FW_CPU_STATUS_POLL_INTERVAL_USEC,
cpu_timeout);
if (rc) {
@@ -1047,7 +2478,7 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg,
cpu_boot_status_reg,
status,
(status == CPU_BOOT_STATUS_SRAM_AVAIL),
- 10000,
+ FW_CPU_STATUS_POLL_INTERVAL_USEC,
cpu_timeout);
/* Clear message */
@@ -1066,36 +2497,43 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg,
goto out;
}
- rc = fw_read_errors(hdev, boot_err0_reg, cpu_security_boot_status_reg);
+ rc = fw_read_errors(hdev, fw_loader->static_loader.boot_err0_reg,
+ fw_loader->static_loader.boot_err1_reg,
+ cpu_boot_dev_status0_reg,
+ cpu_boot_dev_status1_reg);
if (rc)
return rc;
- /* Clear reset status since we need to read again from app */
- prop->hard_reset_done_by_fw = false;
-
- /* Read FW application security bits */
- if (prop->fw_security_status_valid) {
- prop->fw_app_security_map =
- RREG32(cpu_security_boot_status_reg);
-
- if (prop->fw_app_security_map &
- CPU_BOOT_DEV_STS0_FW_HARD_RST_EN)
- prop->hard_reset_done_by_fw = true;
-
- dev_dbg(hdev->dev,
- "Firmware application CPU security status %#x\n",
- prop->fw_app_security_map);
- }
-
- dev_dbg(hdev->dev, "Firmware application CPU hard-reset is %s\n",
- prop->hard_reset_done_by_fw ? "enabled" : "disabled");
-
- dev_info(hdev->dev, "Successfully loaded firmware to device\n");
+ hl_fw_linux_update_state(hdev, cpu_boot_dev_status0_reg,
+ cpu_boot_dev_status1_reg);
return 0;
out:
- fw_read_errors(hdev, boot_err0_reg, cpu_security_boot_status_reg);
+ fw_read_errors(hdev, fw_loader->static_loader.boot_err0_reg,
+ fw_loader->static_loader.boot_err1_reg,
+ cpu_boot_dev_status0_reg,
+ cpu_boot_dev_status1_reg);
return rc;
}
+
+/**
+ * hl_fw_init_cpu - initialize the device CPU
+ *
+ * @hdev: pointer to the habanalabs device structure
+ *
+ * @return 0 on success, otherwise non-zero error code
+ *
+ * perform necessary initializations for device's CPU. takes into account if
+ * init protocol is static or dynamic.
+ */
+int hl_fw_init_cpu(struct hl_device *hdev)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ struct fw_load_mgr *fw_loader = &hdev->fw_loader;
+
+ return prop->dynamic_fw_load ?
+ hl_fw_dynamic_init_cpu(hdev, fw_loader) :
+ hl_fw_static_init_cpu(hdev, fw_loader);
+}
diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h
index 6579f8767abd..6b3cdd7e068a 100644
--- a/drivers/misc/habanalabs/common/habanalabs.h
+++ b/drivers/misc/habanalabs/common/habanalabs.h
@@ -48,6 +48,7 @@
#define HL_PENDING_RESET_LONG_SEC 60
#define HL_HARD_RESET_MAX_TIMEOUT 120
+#define HL_PLDM_HARD_RESET_MAX_TIMEOUT (HL_HARD_RESET_MAX_TIMEOUT * 3)
#define HL_DEVICE_TIMEOUT_USEC 1000000 /* 1 s */
@@ -115,10 +116,18 @@ enum hl_mmu_page_table_location {
*
* - HL_RESET_HEARTBEAT
* Set if reset is due to heartbeat
+ *
+ * - HL_RESET_TDR
+ * Set if reset is due to TDR
+ *
+ * - HL_RESET_DEVICE_RELEASE
+ * Set if reset is due to device release
*/
#define HL_RESET_HARD (1 << 0)
#define HL_RESET_FROM_RESET_THREAD (1 << 1)
#define HL_RESET_HEARTBEAT (1 << 2)
+#define HL_RESET_TDR (1 << 3)
+#define HL_RESET_DEVICE_RELEASE (1 << 4)
#define HL_MAX_SOBS_PER_MONITOR 8
@@ -178,12 +187,14 @@ enum hl_pci_match_mode {
/**
* enum hl_fw_component - F/W components to read version through registers.
- * @FW_COMP_UBOOT: u-boot.
+ * @FW_COMP_BOOT_FIT: boot fit.
* @FW_COMP_PREBOOT: preboot.
+ * @FW_COMP_LINUX: linux.
*/
enum hl_fw_component {
- FW_COMP_UBOOT,
- FW_COMP_PREBOOT
+ FW_COMP_BOOT_FIT,
+ FW_COMP_PREBOOT,
+ FW_COMP_LINUX,
};
/**
@@ -420,12 +431,24 @@ struct hl_mmu_properties {
* @cb_pool_cb_size: size of each CB in the CB pool.
* @max_pending_cs: maximum of concurrent pending command submissions
* @max_queues: maximum amount of queues in the system
- * @fw_boot_cpu_security_map: bitmap representation of boot cpu security status
- * reported by FW, bit description can be found in
- * CPU_BOOT_DEV_STS*
- * @fw_app_security_map: bitmap representation of application security status
- * reported by FW, bit description can be found in
- * CPU_BOOT_DEV_STS*
+ * @fw_preboot_cpu_boot_dev_sts0: bitmap representation of preboot cpu
+ * capabilities reported by FW, bit description
+ * can be found in CPU_BOOT_DEV_STS0
+ * @fw_preboot_cpu_boot_dev_sts1: bitmap representation of preboot cpu
+ * capabilities reported by FW, bit description
+ * can be found in CPU_BOOT_DEV_STS1
+ * @fw_bootfit_cpu_boot_dev_sts0: bitmap representation of boot cpu security
+ * status reported by FW, bit description can be
+ * found in CPU_BOOT_DEV_STS0
+ * @fw_bootfit_cpu_boot_dev_sts1: bitmap representation of boot cpu security
+ * status reported by FW, bit description can be
+ * found in CPU_BOOT_DEV_STS1
+ * @fw_app_cpu_boot_dev_sts0: bitmap representation of application security
+ * status reported by FW, bit description can be
+ * found in CPU_BOOT_DEV_STS0
+ * @fw_app_cpu_boot_dev_sts1: bitmap representation of application security
+ * status reported by FW, bit description can be
+ * found in CPU_BOOT_DEV_STS1
* @collective_first_sob: first sync object available for collective use
* @collective_first_mon: first monitor available for collective use
* @sync_stream_first_sob: first sync object available for sync stream use
@@ -438,14 +461,19 @@ struct hl_mmu_properties {
* @user_interrupt_count: number of user interrupts.
* @tpc_enabled_mask: which TPCs are enabled.
* @completion_queues_count: number of completion queues.
- * @fw_security_disabled: true if security measures are disabled in firmware,
- * false otherwise
- * @fw_security_status_valid: security status bits are valid and can be fetched
- * from BOOT_DEV_STS0
+ * @fw_security_enabled: true if security measures are enabled in firmware,
+ * false otherwise
+ * @fw_cpu_boot_dev_sts0_valid: status bits are valid and can be fetched from
+ * BOOT_DEV_STS0
+ * @fw_cpu_boot_dev_sts1_valid: status bits are valid and can be fetched from
+ * BOOT_DEV_STS1
* @dram_supports_virtual_memory: is there an MMU towards the DRAM
* @hard_reset_done_by_fw: true if firmware is handling hard reset flow
* @num_functional_hbms: number of functional HBMs in each DCORE.
* @iatu_done_by_fw: true if iATU configuration is being done by FW.
+ * @dynamic_fw_load: is dynamic FW load is supported.
+ * @gic_interrupts_enable: true if FW is not blocking GIC controller,
+ * false otherwise.
*/
struct asic_fixed_properties {
struct hw_queue_properties *hw_queues_props;
@@ -491,8 +519,12 @@ struct asic_fixed_properties {
u32 cb_pool_cb_size;
u32 max_pending_cs;
u32 max_queues;
- u32 fw_boot_cpu_security_map;
- u32 fw_app_security_map;
+ u32 fw_preboot_cpu_boot_dev_sts0;
+ u32 fw_preboot_cpu_boot_dev_sts1;
+ u32 fw_bootfit_cpu_boot_dev_sts0;
+ u32 fw_bootfit_cpu_boot_dev_sts1;
+ u32 fw_app_cpu_boot_dev_sts0;
+ u32 fw_app_cpu_boot_dev_sts1;
u16 collective_first_sob;
u16 collective_first_mon;
u16 sync_stream_first_sob;
@@ -504,12 +536,15 @@ struct asic_fixed_properties {
u16 user_interrupt_count;
u8 tpc_enabled_mask;
u8 completion_queues_count;
- u8 fw_security_disabled;
- u8 fw_security_status_valid;
+ u8 fw_security_enabled;
+ u8 fw_cpu_boot_dev_sts0_valid;
+ u8 fw_cpu_boot_dev_sts1_valid;
u8 dram_supports_virtual_memory;
u8 hard_reset_done_by_fw;
u8 num_functional_hbms;
u8 iatu_done_by_fw;
+ u8 dynamic_fw_load;
+ u8 gic_interrupts_enable;
};
/**
@@ -750,12 +785,19 @@ struct hl_user_pending_interrupt {
* @kernel_address: holds the queue's kernel virtual address
* @bus_address: holds the queue's DMA address
* @ci: ci inside the queue
+ * @prev_eqe_index: the index of the previous event queue entry. The index of
+ * the current entry's index must be +1 of the previous one.
+ * @check_eqe_index: do we need to check the index of the current entry vs. the
+ * previous one. This is for backward compatibility with older
+ * firmwares
*/
struct hl_eq {
struct hl_device *hdev;
void *kernel_address;
dma_addr_t bus_address;
u32 ci;
+ u32 prev_eqe_index;
+ bool check_eqe_index;
};
@@ -812,6 +854,132 @@ enum div_select_defs {
DIV_SEL_DIVIDED_PLL = 3,
};
+enum pci_region {
+ PCI_REGION_CFG,
+ PCI_REGION_SRAM,
+ PCI_REGION_DRAM,
+ PCI_REGION_SP_SRAM,
+ PCI_REGION_NUMBER,
+};
+
+/**
+ * struct pci_mem_region - describe memory region in a PCI bar
+ * @region_base: region base address
+ * @region_size: region size
+ * @bar_size: size of the BAR
+ * @offset_in_bar: region offset into the bar
+ * @bar_id: bar ID of the region
+ * @used: if used 1, otherwise 0
+ */
+struct pci_mem_region {
+ u64 region_base;
+ u64 region_size;
+ u64 bar_size;
+ u32 offset_in_bar;
+ u8 bar_id;
+ u8 used;
+};
+
+/**
+ * struct static_fw_load_mgr - static FW load manager
+ * @preboot_version_max_off: max offset to preboot version
+ * @boot_fit_version_max_off: max offset to boot fit version
+ * @kmd_msg_to_cpu_reg: register address for KDM->CPU messages
+ * @cpu_cmd_status_to_host_reg: register address for CPU command status response
+ * @cpu_boot_status_reg: boot status register
+ * @cpu_boot_dev_status0_reg: boot device status register 0
+ * @cpu_boot_dev_status1_reg: boot device status register 1
+ * @boot_err0_reg: boot error register 0
+ * @boot_err1_reg: boot error register 1
+ * @preboot_version_offset_reg: SRAM offset to preboot version register
+ * @boot_fit_version_offset_reg: SRAM offset to boot fit version register
+ * @sram_offset_mask: mask for getting offset into the SRAM
+ * @cpu_reset_wait_msec: used when setting WFE via kmd_msg_to_cpu_reg
+ */
+struct static_fw_load_mgr {
+ u64 preboot_version_max_off;
+ u64 boot_fit_version_max_off;
+ u32 kmd_msg_to_cpu_reg;
+ u32 cpu_cmd_status_to_host_reg;
+ u32 cpu_boot_status_reg;
+ u32 cpu_boot_dev_status0_reg;
+ u32 cpu_boot_dev_status1_reg;
+ u32 boot_err0_reg;
+ u32 boot_err1_reg;
+ u32 preboot_version_offset_reg;
+ u32 boot_fit_version_offset_reg;
+ u32 sram_offset_mask;
+ u32 cpu_reset_wait_msec;
+};
+
+/**
+ * struct fw_response - FW response to LKD command
+ * @ram_offset: descriptor offset into the RAM
+ * @ram_type: RAM type containing the descriptor (SRAM/DRAM)
+ * @status: command status
+ */
+struct fw_response {
+ u32 ram_offset;
+ u8 ram_type;
+ u8 status;
+};
+
+/**
+ * struct dynamic_fw_load_mgr - dynamic FW load manager
+ * @response: FW to LKD response
+ * @comm_desc: the communication descriptor with FW
+ * @image_region: region to copy the FW image to
+ * @fw_image_size: size of FW image to load
+ * @wait_for_bl_timeout: timeout for waiting for boot loader to respond
+ */
+struct dynamic_fw_load_mgr {
+ struct fw_response response;
+ struct lkd_fw_comms_desc comm_desc;
+ struct pci_mem_region *image_region;
+ size_t fw_image_size;
+ u32 wait_for_bl_timeout;
+};
+
+/**
+ * struct fw_image_props - properties of FW image
+ * @image_name: name of the image
+ * @src_off: offset in src FW to copy from
+ * @copy_size: amount of bytes to copy (0 to copy the whole binary)
+ */
+struct fw_image_props {
+ char *image_name;
+ u32 src_off;
+ u32 copy_size;
+};
+
+/**
+ * struct fw_load_mgr - manager FW loading process
+ * @dynamic_loader: specific structure for dynamic load
+ * @static_loader: specific structure for static load
+ * @boot_fit_img: boot fit image properties
+ * @linux_img: linux image properties
+ * @cpu_timeout: CPU response timeout in usec
+ * @boot_fit_timeout: Boot fit load timeout in usec
+ * @skip_bmc: should BMC be skipped
+ * @sram_bar_id: SRAM bar ID
+ * @dram_bar_id: DRAM bar ID
+ * @linux_loaded: true if linux was loaded so far
+ */
+struct fw_load_mgr {
+ union {
+ struct dynamic_fw_load_mgr dynamic_loader;
+ struct static_fw_load_mgr static_loader;
+ };
+ struct fw_image_props boot_fit_img;
+ struct fw_image_props linux_img;
+ u32 cpu_timeout;
+ u32 boot_fit_timeout;
+ u8 skip_bmc;
+ u8 sram_bar_id;
+ u8 dram_bar_id;
+ u8 linux_loaded;
+};
+
/**
* struct hl_asic_funcs - ASIC specific functions that are can be called from
* common code.
@@ -901,8 +1069,6 @@ enum div_select_defs {
* @ctx_fini: context dependent cleanup.
* @get_clk_rate: Retrieve the ASIC current and maximum clock rate in MHz
* @get_queue_id_for_cq: Get the H/W queue id related to the given CQ index.
- * @read_device_fw_version: read the device's firmware versions that are
- * contained in registers
* @load_firmware_to_device: load the firmware to the device's memory
* @load_boot_fit_to_device: load boot fit to device's memory
* @get_signal_cb_size: Get signal CB size.
@@ -933,6 +1099,8 @@ enum div_select_defs {
* @get_msi_info: Retrieve asic-specific MSI ID of the f/w async event
* @map_pll_idx_to_fw_idx: convert driver specific per asic PLL index to
* generic f/w compatible PLL Indexes
+ * @init_firmware_loader: initialize data for FW loader.
+ * @init_cpu_scrambler_dram: Enable CPU specific DRAM scrambling
*/
struct hl_asic_funcs {
int (*early_init)(struct hl_device *hdev);
@@ -1006,7 +1174,7 @@ struct hl_asic_funcs {
int (*mmu_invalidate_cache)(struct hl_device *hdev, bool is_hard,
u32 flags);
int (*mmu_invalidate_cache_range)(struct hl_device *hdev, bool is_hard,
- u32 asid, u64 va, u64 size);
+ u32 flags, u32 asid, u64 va, u64 size);
int (*send_heartbeat)(struct hl_device *hdev);
void (*set_clock_gating)(struct hl_device *hdev);
void (*disable_clock_gating)(struct hl_device *hdev);
@@ -1030,8 +1198,6 @@ struct hl_asic_funcs {
void (*ctx_fini)(struct hl_ctx *ctx);
int (*get_clk_rate)(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk);
u32 (*get_queue_id_for_cq)(struct hl_device *hdev, u32 cq_idx);
- int (*read_device_fw_version)(struct hl_device *hdev,
- enum hl_fw_component fwc);
int (*load_firmware_to_device)(struct hl_device *hdev);
int (*load_boot_fit_to_device)(struct hl_device *hdev);
u32 (*get_signal_cb_size)(struct hl_device *hdev);
@@ -1056,8 +1222,10 @@ struct hl_asic_funcs {
int (*hw_block_mmap)(struct hl_device *hdev, struct vm_area_struct *vma,
u32 block_id, u32 block_size);
void (*enable_events_from_fw)(struct hl_device *hdev);
- void (*get_msi_info)(u32 *table);
+ void (*get_msi_info)(__le32 *table);
int (*map_pll_idx_to_fw_idx)(u32 pll_idx);
+ void (*init_firmware_loader)(struct hl_device *hdev);
+ void (*init_cpu_scrambler_dram)(struct hl_device *hdev);
};
@@ -1262,6 +1430,7 @@ struct hl_userptr {
* @staged_sequence: the sequence of the staged submission this CS is part of,
* relevant only if staged_cs is set.
* @timeout_jiffies: cs timeout in jiffies.
+ * @submission_time_jiffies: submission time of the cs
* @type: CS_TYPE_*.
* @submitted: true if CS was submitted to H/W.
* @completed: true if CS was completed by device.
@@ -1274,6 +1443,8 @@ struct hl_userptr {
* @staged_first: true if this is the first staged CS and we need to receive
* timeout for this CS.
* @staged_cs: true if this CS is part of a staged submission.
+ * @skip_reset_on_timeout: true if we shall not reset the device in case
+ * timeout occurs (debug scenario).
*/
struct hl_cs {
u16 *jobs_in_queue_cnt;
@@ -1291,6 +1462,7 @@ struct hl_cs {
u64 sequence;
u64 staged_sequence;
u64 timeout_jiffies;
+ u64 submission_time_jiffies;
enum hl_cs_type type;
u8 submitted;
u8 completed;
@@ -1301,6 +1473,7 @@ struct hl_cs {
u8 staged_last;
u8 staged_first;
u8 staged_cs;
+ u8 skip_reset_on_timeout;
};
/**
@@ -1922,7 +2095,7 @@ struct hl_mmu_funcs {
* @kernel_queues: array of hl_hw_queue.
* @cs_mirror_list: CS mirror list for TDR.
* @cs_mirror_lock: protects cs_mirror_list.
- * @kernel_cb_mgr: command buffer manager for creating/destroying/handling CGs.
+ * @kernel_cb_mgr: command buffer manager for creating/destroying/handling CBs.
* @event_queue: event queue for IRQ from CPU-CP.
* @dma_pool: DMA pool for small allocations.
* @cpu_accessible_dma_mem: Host <-> CPU-CP shared memory CPU address.
@@ -1954,6 +2127,8 @@ struct hl_mmu_funcs {
* @aggregated_cs_counters: aggregated cs counters among all contexts
* @mmu_priv: device-specific MMU data.
* @mmu_func: device-related MMU functions.
+ * @fw_loader: FW loader manager.
+ * @pci_mem_region: array of memory regions in the PCI
* @dram_used_mem: current DRAM memory consumption.
* @timeout_jiffies: device CS timeout value.
* @max_power: the max power of the device, as configured by the sysadmin. This
@@ -1968,6 +2143,11 @@ struct hl_mmu_funcs {
* the error will be ignored by the driver during
* device initialization. Mainly used to debug and
* workaround firmware bugs
+ * @last_successful_open_jif: timestamp (jiffies) of the last successful
+ * device open.
+ * @last_open_session_duration_jif: duration (jiffies) of the last device open
+ * session.
+ * @open_counter: number of successful device open operations.
* @in_reset: is device in reset flow.
* @curr_pll_profile: current PLL profile.
* @card_type: Various ASICs have several card types. This indicates the card
@@ -2007,6 +2187,8 @@ struct hl_mmu_funcs {
* @collective_mon_idx: helper index for collective initialization
* @supports_coresight: is CoreSight supported.
* @supports_soft_reset: is soft reset supported.
+ * @allow_external_soft_reset: true if soft reset initiated by user or TDR is
+ * allowed.
* @supports_cb_mapping: is mapping a CB to the device's MMU supported.
* @needs_reset: true if reset_on_lockup is false and device should be reset
* due to lockup.
@@ -2015,6 +2197,14 @@ struct hl_mmu_funcs {
* @device_fini_pending: true if device_fini was called and might be
* waiting for the reset thread to finish
* @supports_staged_submission: true if staged submissions are supported
+ * @curr_reset_cause: saves an enumerated reset cause when a hard reset is
+ * triggered, and cleared after it is shared with preboot.
+ * @skip_reset_on_timeout: Skip device reset if CS has timed out, wait for it to
+ * complete instead.
+ * @device_cpu_is_halted: Flag to indicate whether the device CPU was already
+ * halted. We can't halt it again because the COMMS
+ * protocol will throw an error. Relevant only for
+ * cases where Linux was not loaded to device CPU
*/
struct hl_device {
struct pci_dev *pdev;
@@ -2079,11 +2269,18 @@ struct hl_device {
struct hl_mmu_priv mmu_priv;
struct hl_mmu_funcs mmu_func[MMU_NUM_PGT_LOCATIONS];
+ struct fw_load_mgr fw_loader;
+
+ struct pci_mem_region pci_mem_region[PCI_REGION_NUMBER];
+
atomic64_t dram_used_mem;
u64 timeout_jiffies;
u64 max_power;
u64 clock_gating_mask;
u64 boot_error_status_mask;
+ u64 last_successful_open_jif;
+ u64 last_open_session_duration_jif;
+ u64 open_counter;
atomic_t in_reset;
enum hl_pll_frequency curr_pll_profile;
enum cpucp_card_types card_type;
@@ -2116,11 +2313,15 @@ struct hl_device {
u8 collective_mon_idx;
u8 supports_coresight;
u8 supports_soft_reset;
+ u8 allow_external_soft_reset;
u8 supports_cb_mapping;
u8 needs_reset;
u8 process_kill_trial_cnt;
u8 device_fini_pending;
u8 supports_staged_submission;
+ u8 curr_reset_cause;
+ u8 skip_reset_on_timeout;
+ u8 device_cpu_is_halted;
/* Parameters for bring-up */
u64 nic_ports_mask;
@@ -2138,6 +2339,7 @@ struct hl_device {
u8 rl_enable;
u8 reset_on_preboot_fail;
u8 reset_upon_device_release;
+ u8 reset_if_device_not_idle;
};
@@ -2384,11 +2586,13 @@ void hl_fw_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size,
void *vaddr);
int hl_fw_send_heartbeat(struct hl_device *hdev);
int hl_fw_cpucp_info_get(struct hl_device *hdev,
- u32 cpu_security_boot_status_reg,
- u32 boot_err0_reg);
+ u32 sts_boot_dev_sts0_reg,
+ u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg,
+ u32 boot_err1_reg);
int hl_fw_cpucp_handshake(struct hl_device *hdev,
- u32 cpu_security_boot_status_reg,
- u32 boot_err0_reg);
+ u32 sts_boot_dev_sts0_reg,
+ u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg,
+ u32 boot_err1_reg);
int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size);
int hl_fw_cpucp_pci_counters_get(struct hl_device *hdev,
struct hl_info_pci_counters *counters);
@@ -2399,14 +2603,17 @@ int get_used_pll_index(struct hl_device *hdev, u32 input_pll_index,
int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u32 pll_index,
u16 *pll_freq_arr);
int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power);
-int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg,
- u32 msg_to_cpu_reg, u32 cpu_msg_status_reg,
- u32 cpu_security_boot_status_reg, u32 boot_err0_reg,
- bool skip_bmc, u32 cpu_timeout, u32 boot_fit_timeout);
+void hl_fw_ask_hard_reset_without_linux(struct hl_device *hdev);
+void hl_fw_ask_halt_machine_without_linux(struct hl_device *hdev);
+int hl_fw_init_cpu(struct hl_device *hdev);
int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg,
- u32 cpu_security_boot_status_reg, u32 boot_err0_reg,
- u32 timeout);
-
+ u32 sts_boot_dev_sts0_reg,
+ u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg,
+ u32 boot_err1_reg, u32 timeout);
+int hl_fw_dynamic_send_protocol_cmd(struct hl_device *hdev,
+ struct fw_load_mgr *fw_loader,
+ enum comms_cmd cmd, unsigned int size,
+ bool wait_ok, u32 timeout);
int hl_pci_bars_map(struct hl_device *hdev, const char * const name[3],
bool is_wc[3]);
int hl_pci_elbi_read(struct hl_device *hdev, u64 addr, u32 *data);
@@ -2415,6 +2622,7 @@ int hl_pci_set_inbound_region(struct hl_device *hdev, u8 region,
struct hl_inbound_pci_region *pci_region);
int hl_pci_set_outbound_region(struct hl_device *hdev,
struct hl_outbound_pci_region *pci_region);
+enum pci_region hl_get_pci_memory_region(struct hl_device *hdev, u64 addr);
int hl_pci_init(struct hl_device *hdev);
void hl_pci_fini(struct hl_device *hdev);
@@ -2443,6 +2651,8 @@ int hl_set_voltage(struct hl_device *hdev,
int hl_set_current(struct hl_device *hdev,
int sensor_index, u32 attr, long value);
void hl_release_pending_user_interrupts(struct hl_device *hdev);
+int hl_cs_signal_sob_wraparound_handler(struct hl_device *hdev, u32 q_idx,
+ struct hl_hw_sob **hw_sob, u32 count);
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c
index 64d1530db985..4194cda2d04c 100644
--- a/drivers/misc/habanalabs/common/habanalabs_drv.c
+++ b/drivers/misc/habanalabs/common/habanalabs_drv.c
@@ -29,7 +29,7 @@ static DEFINE_MUTEX(hl_devs_idr_lock);
static int timeout_locked = 30;
static int reset_on_lockup = 1;
-static int memory_scrub = 1;
+static int memory_scrub;
static ulong boot_error_status_mask = ULONG_MAX;
module_param(timeout_locked, int, 0444);
@@ -42,7 +42,7 @@ MODULE_PARM_DESC(reset_on_lockup,
module_param(memory_scrub, int, 0444);
MODULE_PARM_DESC(memory_scrub,
- "Scrub device memory in various states (0 = no, 1 = yes, default yes)");
+ "Scrub device memory in various states (0 = no, 1 = yes, default no)");
module_param(boot_error_status_mask, ulong, 0444);
MODULE_PARM_DESC(boot_error_status_mask,
@@ -187,6 +187,9 @@ int hl_device_open(struct inode *inode, struct file *filp)
hl_debugfs_add_file(hpriv);
+ hdev->open_counter++;
+ hdev->last_successful_open_jif = jiffies;
+
return 0;
out_err:
@@ -264,6 +267,7 @@ static void set_driver_behavior_per_device(struct hl_device *hdev)
hdev->bmc_enable = 1;
hdev->hard_reset_on_fw_events = 1;
hdev->reset_on_preboot_fail = 1;
+ hdev->reset_if_device_not_idle = 1;
hdev->reset_pcilink = 0;
hdev->axi_drain = 0;
@@ -308,10 +312,10 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev,
}
if (pdev)
- hdev->asic_prop.fw_security_disabled =
- !is_asic_secured(pdev->device);
+ hdev->asic_prop.fw_security_enabled =
+ is_asic_secured(hdev->asic_type);
else
- hdev->asic_prop.fw_security_disabled = true;
+ hdev->asic_prop.fw_security_enabled = false;
/* Assign status description string */
strncpy(hdev->status[HL_DEVICE_STATUS_MALFUNCTION],
@@ -325,11 +329,14 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev,
hdev->reset_on_lockup = reset_on_lockup;
hdev->memory_scrub = memory_scrub;
hdev->boot_error_status_mask = boot_error_status_mask;
+ hdev->stop_on_err = true;
hdev->pldm = 0;
set_driver_behavior_per_device(hdev);
+ hdev->curr_reset_cause = HL_RESET_CAUSE_UNKNOWN;
+
if (timeout_locked)
hdev->timeout_jiffies = msecs_to_jiffies(timeout_locked * 1000);
else
@@ -464,6 +471,7 @@ static int hl_pci_probe(struct pci_dev *pdev,
return 0;
disable_device:
+ pci_disable_pcie_error_reporting(pdev);
pci_set_drvdata(pdev, NULL);
destroy_hdev(hdev);
@@ -572,7 +580,11 @@ static struct pci_driver hl_pci_driver = {
.probe = hl_pci_probe,
.remove = hl_pci_remove,
.shutdown = hl_pci_remove,
- .driver.pm = &hl_pm_ops,
+ .driver = {
+ .name = HL_NAME,
+ .pm = &hl_pm_ops,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
.err_handler = &hl_pci_err_handler,
};
diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/misc/habanalabs/common/habanalabs_ioctl.c
index 33841c272eb6..f4dda7b4acdd 100644
--- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c
+++ b/drivers/misc/habanalabs/common/habanalabs_ioctl.c
@@ -95,7 +95,7 @@ static int hw_ip_info(struct hl_device *hdev, struct hl_info_args *args)
hw_ip.first_available_interrupt_id =
prop->first_available_user_msix_interrupt;
return copy_to_user(out, &hw_ip,
- min((size_t)size, sizeof(hw_ip))) ? -EFAULT : 0;
+ min((size_t) size, sizeof(hw_ip))) ? -EFAULT : 0;
}
static int hw_events_info(struct hl_device *hdev, bool aggregate,
@@ -460,6 +460,24 @@ static int power_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
min((size_t) max_size, sizeof(power_info))) ? -EFAULT : 0;
}
+static int open_stats_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
+{
+ struct hl_device *hdev = hpriv->hdev;
+ u32 max_size = args->return_size;
+ struct hl_open_stats_info open_stats_info = {0};
+ void __user *out = (void __user *) (uintptr_t) args->return_pointer;
+
+ if ((!max_size) || (!out))
+ return -EINVAL;
+
+ open_stats_info.last_open_period_ms = jiffies64_to_msecs(
+ hdev->last_open_session_duration_jif);
+ open_stats_info.open_counter = hdev->open_counter;
+
+ return copy_to_user(out, &open_stats_info,
+ min((size_t) max_size, sizeof(open_stats_info))) ? -EFAULT : 0;
+}
+
static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data,
struct device *dev)
{
@@ -543,6 +561,9 @@ static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data,
case HL_INFO_POWER:
return power_info(hpriv, args);
+ case HL_INFO_OPEN_STATS:
+ return open_stats_info(hpriv, args);
+
default:
dev_err(dev, "Invalid request %d\n", args->op);
rc = -ENOTTY;
diff --git a/drivers/misc/habanalabs/common/hw_queue.c b/drivers/misc/habanalabs/common/hw_queue.c
index 173438461835..bcabfdbf1e01 100644
--- a/drivers/misc/habanalabs/common/hw_queue.c
+++ b/drivers/misc/habanalabs/common/hw_queue.c
@@ -410,19 +410,20 @@ static void hw_queue_schedule_job(struct hl_cs_job *job)
ext_and_hw_queue_submit_bd(hdev, q, ctl, len, ptr);
}
-static void init_signal_cs(struct hl_device *hdev,
+static int init_signal_cs(struct hl_device *hdev,
struct hl_cs_job *job, struct hl_cs_compl *cs_cmpl)
{
struct hl_sync_stream_properties *prop;
struct hl_hw_sob *hw_sob;
u32 q_idx;
+ int rc = 0;
q_idx = job->hw_queue_id;
prop = &hdev->kernel_queues[q_idx].sync_stream_prop;
hw_sob = &prop->hw_sob[prop->curr_sob_offset];
cs_cmpl->hw_sob = hw_sob;
- cs_cmpl->sob_val = prop->next_sob_val++;
+ cs_cmpl->sob_val = prop->next_sob_val;
dev_dbg(hdev->dev,
"generate signal CB, sob_id: %d, sob val: 0x%x, q_idx: %d\n",
@@ -434,24 +435,9 @@ static void init_signal_cs(struct hl_device *hdev,
hdev->asic_funcs->gen_signal_cb(hdev, job->patched_cb,
cs_cmpl->hw_sob->sob_id, 0, true);
- kref_get(&hw_sob->kref);
+ rc = hl_cs_signal_sob_wraparound_handler(hdev, q_idx, &hw_sob, 1);
- /* check for wraparound */
- if (prop->next_sob_val == HL_MAX_SOB_VAL) {
- /*
- * Decrement as we reached the max value.
- * The release function won't be called here as we've
- * just incremented the refcount.
- */
- kref_put(&hw_sob->kref, hl_sob_reset_error);
- prop->next_sob_val = 1;
- /* only two SOBs are currently in use */
- prop->curr_sob_offset =
- (prop->curr_sob_offset + 1) % HL_RSVD_SOBS;
-
- dev_dbg(hdev->dev, "switched to SOB %d, q_idx: %d\n",
- prop->curr_sob_offset, q_idx);
- }
+ return rc;
}
static void init_wait_cs(struct hl_device *hdev, struct hl_cs *cs,
@@ -504,22 +490,25 @@ static void init_wait_cs(struct hl_device *hdev, struct hl_cs *cs,
*
* H/W queues spinlock should be taken before calling this function
*/
-static void init_signal_wait_cs(struct hl_cs *cs)
+static int init_signal_wait_cs(struct hl_cs *cs)
{
struct hl_ctx *ctx = cs->ctx;
struct hl_device *hdev = ctx->hdev;
struct hl_cs_job *job;
struct hl_cs_compl *cs_cmpl =
container_of(cs->fence, struct hl_cs_compl, base_fence);
+ int rc = 0;
/* There is only one job in a signal/wait CS */
job = list_first_entry(&cs->job_list, struct hl_cs_job,
cs_node);
if (cs->type & CS_TYPE_SIGNAL)
- init_signal_cs(hdev, job, cs_cmpl);
+ rc = init_signal_cs(hdev, job, cs_cmpl);
else if (cs->type & CS_TYPE_WAIT)
init_wait_cs(hdev, cs, job, cs_cmpl);
+
+ return rc;
}
/*
@@ -590,11 +579,16 @@ int hl_hw_queue_schedule_cs(struct hl_cs *cs)
}
}
- if ((cs->type == CS_TYPE_SIGNAL) || (cs->type == CS_TYPE_WAIT))
- init_signal_wait_cs(cs);
- else if (cs->type == CS_TYPE_COLLECTIVE_WAIT)
+ if ((cs->type == CS_TYPE_SIGNAL) || (cs->type == CS_TYPE_WAIT)) {
+ rc = init_signal_wait_cs(cs);
+ if (rc) {
+ dev_err(hdev->dev, "Failed to submit signal cs\n");
+ goto unroll_cq_resv;
+ }
+ } else if (cs->type == CS_TYPE_COLLECTIVE_WAIT)
hdev->asic_funcs->collective_wait_init_cs(cs);
+
spin_lock(&hdev->cs_mirror_lock);
/* Verify staged CS exists and add to the staged list */
diff --git a/drivers/misc/habanalabs/common/irq.c b/drivers/misc/habanalabs/common/irq.c
index 27129868c711..39b14a933393 100644
--- a/drivers/misc/habanalabs/common/irq.c
+++ b/drivers/misc/habanalabs/common/irq.c
@@ -207,17 +207,33 @@ irqreturn_t hl_irq_handler_eq(int irq, void *arg)
struct hl_eq_entry *eq_entry;
struct hl_eq_entry *eq_base;
struct hl_eqe_work *handle_eqe_work;
+ bool entry_ready;
+ u32 cur_eqe;
+ u16 cur_eqe_index;
eq_base = eq->kernel_address;
while (1) {
- bool entry_ready =
- ((le32_to_cpu(eq_base[eq->ci].hdr.ctl) &
- EQ_CTL_READY_MASK) >> EQ_CTL_READY_SHIFT);
+ cur_eqe = le32_to_cpu(eq_base[eq->ci].hdr.ctl);
+ entry_ready = !!FIELD_GET(EQ_CTL_READY_MASK, cur_eqe);
if (!entry_ready)
break;
+ cur_eqe_index = FIELD_GET(EQ_CTL_INDEX_MASK, cur_eqe);
+ if ((hdev->event_queue.check_eqe_index) &&
+ (((eq->prev_eqe_index + 1) & EQ_CTL_INDEX_MASK)
+ != cur_eqe_index)) {
+ dev_dbg(hdev->dev,
+ "EQE 0x%x in queue is ready but index does not match %d!=%d",
+ eq_base[eq->ci].hdr.ctl,
+ ((eq->prev_eqe_index + 1) & EQ_CTL_INDEX_MASK),
+ cur_eqe_index);
+ break;
+ }
+
+ eq->prev_eqe_index++;
+
eq_entry = &eq_base[eq->ci];
/*
@@ -341,6 +357,7 @@ int hl_eq_init(struct hl_device *hdev, struct hl_eq *q)
q->hdev = hdev;
q->kernel_address = p;
q->ci = 0;
+ q->prev_eqe_index = 0;
return 0;
}
@@ -365,6 +382,7 @@ void hl_eq_fini(struct hl_device *hdev, struct hl_eq *q)
void hl_eq_reset(struct hl_device *hdev, struct hl_eq *q)
{
q->ci = 0;
+ q->prev_eqe_index = 0;
/*
* It's not enough to just reset the PI/CI because the H/W may have
diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c
index 2938cbbafbbc..af339ce1ab4f 100644
--- a/drivers/misc/habanalabs/common/memory.c
+++ b/drivers/misc/habanalabs/common/memory.c
@@ -570,8 +570,10 @@ static u64 get_va_block(struct hl_device *hdev,
if ((is_align_pow_2 && (hint_addr & (va_block_align - 1))) ||
(!is_align_pow_2 &&
do_div(tmp_hint_addr, va_range->page_size))) {
- dev_info(hdev->dev, "Hint address 0x%llx will be ignored\n",
- hint_addr);
+
+ dev_dbg(hdev->dev,
+ "Hint address 0x%llx will be ignored because it is not aligned\n",
+ hint_addr);
hint_addr = 0;
}
@@ -1117,7 +1119,8 @@ static int map_device_va(struct hl_ctx *ctx, struct hl_mem_in *args,
goto map_err;
}
- rc = hdev->asic_funcs->mmu_invalidate_cache(hdev, false, *vm_type);
+ rc = hdev->asic_funcs->mmu_invalidate_cache_range(hdev, false,
+ *vm_type, ctx->asid, ret_vaddr, phys_pg_pack->total_size);
mutex_unlock(&ctx->mmu_lock);
@@ -1261,8 +1264,9 @@ static int unmap_device_va(struct hl_ctx *ctx, struct hl_mem_in *args,
* at the loop end rather than for each iteration
*/
if (!ctx_free)
- rc = hdev->asic_funcs->mmu_invalidate_cache(hdev, true,
- *vm_type);
+ rc = hdev->asic_funcs->mmu_invalidate_cache_range(hdev, true,
+ *vm_type, ctx->asid, vaddr,
+ phys_pg_pack->total_size);
mutex_unlock(&ctx->mmu_lock);
@@ -1369,12 +1373,7 @@ int hl_hw_block_mmap(struct hl_fpriv *hpriv, struct vm_area_struct *vma)
/* Driver only allows mapping of a complete HW block */
block_size = vma->vm_end - vma->vm_start;
-#ifdef _HAS_TYPE_ARG_IN_ACCESS_OK
- if (!access_ok(VERIFY_WRITE,
- (void __user *) (uintptr_t) vma->vm_start, block_size)) {
-#else
if (!access_ok((void __user *) (uintptr_t) vma->vm_start, block_size)) {
-#endif
dev_err(hdev->dev,
"user pointer is invalid - 0x%lx\n",
vma->vm_start);
@@ -1608,7 +1607,8 @@ static int get_user_memory(struct hl_device *hdev, u64 addr, u64 size,
if (rc != npages) {
dev_err(hdev->dev,
- "Failed to map host memory, user ptr probably wrong\n");
+ "Failed (%d) to pin host memory with user ptr 0x%llx, size 0x%llx, npages %d\n",
+ rc, addr, size, npages);
if (rc < 0)
goto destroy_pages;
npages = rc;
diff --git a/drivers/misc/habanalabs/common/mmu/mmu.c b/drivers/misc/habanalabs/common/mmu/mmu.c
index b37189956b14..792d25b79ea6 100644
--- a/drivers/misc/habanalabs/common/mmu/mmu.c
+++ b/drivers/misc/habanalabs/common/mmu/mmu.c
@@ -501,12 +501,20 @@ static void hl_mmu_pa_page_with_offset(struct hl_ctx *ctx, u64 virt_addr,
if ((hops->range_type == HL_VA_RANGE_TYPE_DRAM) &&
!is_power_of_2(prop->dram_page_size)) {
- u32 bit;
+ unsigned long dram_page_size = prop->dram_page_size;
u64 page_offset_mask;
u64 phys_addr_mask;
+ u32 bit;
- bit = __ffs64((u64)prop->dram_page_size);
- page_offset_mask = ((1ull << bit) - 1);
+ /*
+ * find last set bit in page_size to cover all bits of page
+ * offset. note that 1 has to be added to bit index.
+ * note that the internal ulong variable is used to avoid
+ * alignment issue.
+ */
+ bit = find_last_bit(&dram_page_size,
+ sizeof(dram_page_size) * BITS_PER_BYTE) + 1;
+ page_offset_mask = (BIT_ULL(bit) - 1);
phys_addr_mask = ~page_offset_mask;
*phys_addr = (tmp_phys_addr & phys_addr_mask) |
(virt_addr & page_offset_mask);
diff --git a/drivers/misc/habanalabs/common/pci/pci.c b/drivers/misc/habanalabs/common/pci/pci.c
index e941b7eef346..d5bedf5ba011 100644
--- a/drivers/misc/habanalabs/common/pci/pci.c
+++ b/drivers/misc/habanalabs/common/pci/pci.c
@@ -10,7 +10,7 @@
#include <linux/pci.h>
-#define HL_PLDM_PCI_ELBI_TIMEOUT_MSEC (HL_PCI_ELBI_TIMEOUT_MSEC * 10)
+#define HL_PLDM_PCI_ELBI_TIMEOUT_MSEC (HL_PCI_ELBI_TIMEOUT_MSEC * 100)
#define IATU_REGION_CTRL_REGION_EN_MASK BIT(31)
#define IATU_REGION_CTRL_MATCH_MODE_MASK BIT(30)
@@ -360,6 +360,32 @@ int hl_pci_set_outbound_region(struct hl_device *hdev,
}
/**
+ * hl_get_pci_memory_region() - get PCI region for given address
+ * @hdev: Pointer to hl_device structure.
+ * @addr: device address
+ *
+ * @return region index on success, otherwise PCI_REGION_NUMBER (invalid
+ * region index)
+ */
+enum pci_region hl_get_pci_memory_region(struct hl_device *hdev, u64 addr)
+{
+ int i;
+
+ for (i = 0 ; i < PCI_REGION_NUMBER ; i++) {
+ struct pci_mem_region *region = &hdev->pci_mem_region[i];
+
+ if (!region->used)
+ continue;
+
+ if ((addr >= region->region_base) &&
+ (addr < region->region_base + region->region_size))
+ return i;
+ }
+
+ return PCI_REGION_NUMBER;
+}
+
+/**
* hl_pci_init() - PCI initialization code.
* @hdev: Pointer to hl_device structure.
*
@@ -395,6 +421,12 @@ int hl_pci_init(struct hl_device *hdev)
goto unmap_pci_bars;
}
+ /* Driver must sleep in order for FW to finish the iATU configuration */
+ if (hdev->asic_prop.iatu_done_by_fw) {
+ usleep_range(2000, 3000);
+ hdev->asic_funcs->set_dma_mask_from_fw(hdev);
+ }
+
rc = dma_set_mask_and_coherent(&pdev->dev,
DMA_BIT_MASK(hdev->dma_mask));
if (rc) {
diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/misc/habanalabs/common/sysfs.c
index c9f649b31e3a..db72df282ef8 100644
--- a/drivers/misc/habanalabs/common/sysfs.c
+++ b/drivers/misc/habanalabs/common/sysfs.c
@@ -208,7 +208,7 @@ static ssize_t soft_reset_store(struct device *dev,
goto out;
}
- if (!hdev->supports_soft_reset) {
+ if (!hdev->allow_external_soft_reset) {
dev_err(hdev->dev, "Device does not support soft-reset\n");
goto out;
}
diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c
index 9e4a6bb3acd1..aa8a0ca5aca2 100644
--- a/drivers/misc/habanalabs/gaudi/gaudi.c
+++ b/drivers/misc/habanalabs/gaudi/gaudi.c
@@ -78,6 +78,7 @@
#define GAUDI_PLDM_TPC_KERNEL_WAIT_USEC (HL_DEVICE_TIMEOUT_USEC * 30)
#define GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC 1000000 /* 1s */
#define GAUDI_MSG_TO_CPU_TIMEOUT_USEC 4000000 /* 4s */
+#define GAUDI_WAIT_FOR_BL_TIMEOUT_USEC 15000000 /* 15s */
#define GAUDI_QMAN0_FENCE_VAL 0x72E91AB9
@@ -409,7 +410,7 @@ static inline void set_default_power_values(struct hl_device *hdev)
}
}
-static int gaudi_get_fixed_properties(struct hl_device *hdev)
+static int gaudi_set_fixed_properties(struct hl_device *hdev)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
u32 num_sync_stream_queues = 0;
@@ -545,8 +546,10 @@ static int gaudi_get_fixed_properties(struct hl_device *hdev)
for (i = 0 ; i < HL_MAX_DCORES ; i++)
prop->first_available_cq[i] = USHRT_MAX;
- prop->fw_security_status_valid = false;
+ prop->fw_cpu_boot_dev_sts0_valid = false;
+ prop->fw_cpu_boot_dev_sts1_valid = false;
prop->hard_reset_done_by_fw = false;
+ prop->gic_interrupts_enable = true;
return 0;
}
@@ -577,6 +580,9 @@ static u64 gaudi_set_hbm_bar_base(struct hl_device *hdev, u64 addr)
if ((gaudi) && (gaudi->hbm_bar_cur_addr == addr))
return old_addr;
+ if (hdev->asic_prop.iatu_done_by_fw)
+ return U64_MAX;
+
/* Inbound Region 2 - Bar 4 - Point to HBM */
pci_region.mode = PCI_BAR_MATCH_MODE;
pci_region.bar = HBM_BAR_ID;
@@ -599,10 +605,8 @@ static int gaudi_init_iatu(struct hl_device *hdev)
struct hl_outbound_pci_region outbound_region;
int rc;
- if (hdev->asic_prop.iatu_done_by_fw) {
- hdev->asic_funcs->set_dma_mask_from_fw(hdev);
+ if (hdev->asic_prop.iatu_done_by_fw)
return 0;
- }
/* Inbound Region 0 - Bar 0 - Point to SRAM + CFG */
inbound_region.mode = PCI_BAR_MATCH_MODE;
@@ -651,9 +655,9 @@ static int gaudi_early_init(struct hl_device *hdev)
u32 fw_boot_status;
int rc;
- rc = gaudi_get_fixed_properties(hdev);
+ rc = gaudi_set_fixed_properties(hdev);
if (rc) {
- dev_err(hdev->dev, "Failed to get fixed properties\n");
+ dev_err(hdev->dev, "Failed setting fixed properties\n");
return rc;
}
@@ -683,8 +687,14 @@ static int gaudi_early_init(struct hl_device *hdev)
prop->dram_pci_bar_size = pci_resource_len(pdev, HBM_BAR_ID);
/* If FW security is enabled at this point it means no access to ELBI */
- if (!hdev->asic_prop.fw_security_disabled) {
+ if (hdev->asic_prop.fw_security_enabled) {
hdev->asic_prop.iatu_done_by_fw = true;
+
+ /*
+ * GIC-security-bit can ONLY be set by CPUCP, so in this stage
+ * decision can only be taken based on PCI ID security.
+ */
+ hdev->asic_prop.gic_interrupts_enable = false;
goto pci_init;
}
@@ -707,8 +717,10 @@ pci_init:
* version to determine whether we run with a security-enabled firmware
*/
rc = hl_fw_read_preboot_status(hdev, mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS,
- mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0,
- GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC);
+ mmCPU_BOOT_DEV_STS0,
+ mmCPU_BOOT_DEV_STS1, mmCPU_BOOT_ERR0,
+ mmCPU_BOOT_ERR1,
+ GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC);
if (rc) {
if (hdev->reset_on_preboot_fail)
hdev->asic_funcs->hw_fini(hdev, true);
@@ -751,7 +763,14 @@ static int gaudi_fetch_psoc_frequency(struct hl_device *hdev)
u16 pll_freq_arr[HL_PLL_NUM_OUTPUTS], freq;
int rc;
- if (hdev->asic_prop.fw_security_disabled) {
+ if (hdev->asic_prop.fw_security_enabled) {
+ rc = hl_fw_cpucp_pll_info_get(hdev, HL_GAUDI_CPU_PLL, pll_freq_arr);
+
+ if (rc)
+ return rc;
+
+ freq = pll_freq_arr[2];
+ } else {
/* Backward compatibility */
div_fctr = RREG32(mmPSOC_CPU_PLL_DIV_FACTOR_2);
div_sel = RREG32(mmPSOC_CPU_PLL_DIV_SEL_2);
@@ -779,13 +798,6 @@ static int gaudi_fetch_psoc_frequency(struct hl_device *hdev)
div_sel);
freq = 0;
}
- } else {
- rc = hl_fw_cpucp_pll_info_get(hdev, HL_GAUDI_CPU_PLL, pll_freq_arr);
-
- if (rc)
- return rc;
-
- freq = pll_freq_arr[2];
}
prop->psoc_timestamp_frequency = freq;
@@ -988,9 +1000,27 @@ static void gaudi_sob_group_reset_error(struct kref *ref)
hw_sob_group->base_sob_id);
}
+static void gaudi_collective_mstr_sob_mask_set(struct gaudi_device *gaudi)
+{
+ struct gaudi_collective_properties *prop;
+ int i;
+
+ prop = &gaudi->collective_props;
+
+ memset(prop->mstr_sob_mask, 0, sizeof(prop->mstr_sob_mask));
+
+ for (i = 0 ; i < NIC_NUMBER_OF_ENGINES ; i++)
+ if (gaudi->hw_cap_initialized & BIT(HW_CAP_NIC_SHIFT + i))
+ prop->mstr_sob_mask[i / HL_MAX_SOBS_PER_MONITOR] |=
+ BIT(i % HL_MAX_SOBS_PER_MONITOR);
+ /* Set collective engine bit */
+ prop->mstr_sob_mask[i / HL_MAX_SOBS_PER_MONITOR] |=
+ BIT(i % HL_MAX_SOBS_PER_MONITOR);
+}
+
static int gaudi_collective_init(struct hl_device *hdev)
{
- u32 i, master_monitor_sobs, sob_id, reserved_sobs_per_group;
+ u32 i, sob_id, reserved_sobs_per_group;
struct gaudi_collective_properties *prop;
struct gaudi_device *gaudi;
@@ -1016,22 +1046,7 @@ static int gaudi_collective_init(struct hl_device *hdev)
gaudi_collective_map_sobs(hdev, i);
}
- prop->mstr_sob_mask[0] = 0;
- master_monitor_sobs = HL_MAX_SOBS_PER_MONITOR;
- for (i = 0 ; i < master_monitor_sobs ; i++)
- if (gaudi->hw_cap_initialized & BIT(HW_CAP_NIC_SHIFT + i))
- prop->mstr_sob_mask[0] |= BIT(i);
-
- prop->mstr_sob_mask[1] = 0;
- master_monitor_sobs =
- NIC_NUMBER_OF_ENGINES - HL_MAX_SOBS_PER_MONITOR;
- for (i = 0 ; i < master_monitor_sobs; i++) {
- if (gaudi->hw_cap_initialized & BIT(HW_CAP_NIC_SHIFT + i))
- prop->mstr_sob_mask[1] |= BIT(i);
- }
-
- /* Set collective engine bit */
- prop->mstr_sob_mask[1] |= BIT(i);
+ gaudi_collective_mstr_sob_mask_set(gaudi);
return 0;
}
@@ -1513,7 +1528,7 @@ static int gaudi_alloc_cpu_accessible_dma_mem(struct hl_device *hdev)
hdev->cpu_pci_msb_addr =
GAUDI_CPU_PCI_MSB_ADDR(hdev->cpu_accessible_dma_address);
- if (hdev->asic_prop.fw_security_disabled)
+ if (!hdev->asic_prop.fw_security_enabled)
GAUDI_PCI_TO_CPU_ADDR(hdev->cpu_accessible_dma_address);
free_dma_mem_arr:
@@ -1590,6 +1605,48 @@ free_internal_qmans_pq_mem:
return rc;
}
+static void gaudi_set_pci_memory_regions(struct hl_device *hdev)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ struct pci_mem_region *region;
+
+ /* CFG */
+ region = &hdev->pci_mem_region[PCI_REGION_CFG];
+ region->region_base = CFG_BASE;
+ region->region_size = CFG_SIZE;
+ region->offset_in_bar = CFG_BASE - SPI_FLASH_BASE_ADDR;
+ region->bar_size = CFG_BAR_SIZE;
+ region->bar_id = CFG_BAR_ID;
+ region->used = 1;
+
+ /* SRAM */
+ region = &hdev->pci_mem_region[PCI_REGION_SRAM];
+ region->region_base = SRAM_BASE_ADDR;
+ region->region_size = SRAM_SIZE;
+ region->offset_in_bar = 0;
+ region->bar_size = SRAM_BAR_SIZE;
+ region->bar_id = SRAM_BAR_ID;
+ region->used = 1;
+
+ /* DRAM */
+ region = &hdev->pci_mem_region[PCI_REGION_DRAM];
+ region->region_base = DRAM_PHYS_BASE;
+ region->region_size = hdev->asic_prop.dram_size;
+ region->offset_in_bar = 0;
+ region->bar_size = prop->dram_pci_bar_size;
+ region->bar_id = HBM_BAR_ID;
+ region->used = 1;
+
+ /* SP SRAM */
+ region = &hdev->pci_mem_region[PCI_REGION_SP_SRAM];
+ region->region_base = PSOC_SCRATCHPAD_ADDR;
+ region->region_size = PSOC_SCRATCHPAD_SIZE;
+ region->offset_in_bar = PSOC_SCRATCHPAD_ADDR - SPI_FLASH_BASE_ADDR;
+ region->bar_size = CFG_BAR_SIZE;
+ region->bar_id = CFG_BAR_ID;
+ region->used = 1;
+}
+
static int gaudi_sw_init(struct hl_device *hdev)
{
struct gaudi_device *gaudi;
@@ -1664,12 +1721,14 @@ static int gaudi_sw_init(struct hl_device *hdev)
hdev->supports_coresight = true;
hdev->supports_staged_submission = true;
+ gaudi_set_pci_memory_regions(hdev);
+
return 0;
free_cpu_accessible_dma_pool:
gen_pool_destroy(hdev->cpu_accessible_dma_pool);
free_cpu_dma_mem:
- if (hdev->asic_prop.fw_security_disabled)
+ if (!hdev->asic_prop.fw_security_enabled)
GAUDI_CPU_TO_PCI_ADDR(hdev->cpu_accessible_dma_address,
hdev->cpu_pci_msb_addr);
hdev->asic_funcs->asic_dma_free_coherent(hdev,
@@ -1691,7 +1750,7 @@ static int gaudi_sw_fini(struct hl_device *hdev)
gen_pool_destroy(hdev->cpu_accessible_dma_pool);
- if (hdev->asic_prop.fw_security_disabled)
+ if (!hdev->asic_prop.fw_security_enabled)
GAUDI_CPU_TO_PCI_ADDR(hdev->cpu_accessible_dma_address,
hdev->cpu_pci_msb_addr);
@@ -1879,12 +1938,11 @@ static void gaudi_init_scrambler_sram(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
- if (!hdev->asic_prop.fw_security_disabled)
+ if (hdev->asic_prop.fw_security_enabled)
return;
- if (hdev->asic_prop.fw_security_status_valid &&
- (hdev->asic_prop.fw_app_security_map &
- CPU_BOOT_DEV_STS0_SRAM_SCR_EN))
+ if (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 &
+ CPU_BOOT_DEV_STS0_SRAM_SCR_EN)
return;
if (gaudi->hw_cap_initialized & HW_CAP_SRAM_SCRAMBLER)
@@ -1951,12 +2009,11 @@ static void gaudi_init_scrambler_hbm(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
- if (!hdev->asic_prop.fw_security_disabled)
+ if (hdev->asic_prop.fw_security_enabled)
return;
- if (hdev->asic_prop.fw_security_status_valid &&
- (hdev->asic_prop.fw_boot_cpu_security_map &
- CPU_BOOT_DEV_STS0_DRAM_SCR_EN))
+ if (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 &
+ CPU_BOOT_DEV_STS0_DRAM_SCR_EN)
return;
if (gaudi->hw_cap_initialized & HW_CAP_HBM_SCRAMBLER)
@@ -2021,12 +2078,11 @@ static void gaudi_init_scrambler_hbm(struct hl_device *hdev)
static void gaudi_init_e2e(struct hl_device *hdev)
{
- if (!hdev->asic_prop.fw_security_disabled)
+ if (hdev->asic_prop.fw_security_enabled)
return;
- if (hdev->asic_prop.fw_security_status_valid &&
- (hdev->asic_prop.fw_boot_cpu_security_map &
- CPU_BOOT_DEV_STS0_E2E_CRED_EN))
+ if (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 &
+ CPU_BOOT_DEV_STS0_E2E_CRED_EN)
return;
WREG32(mmSIF_RTR_CTRL_0_E2E_HBM_WR_SIZE, 247 >> 3);
@@ -2396,12 +2452,11 @@ static void gaudi_init_hbm_cred(struct hl_device *hdev)
{
uint32_t hbm0_wr, hbm1_wr, hbm0_rd, hbm1_rd;
- if (!hdev->asic_prop.fw_security_disabled)
+ if (hdev->asic_prop.fw_security_enabled)
return;
- if (hdev->asic_prop.fw_security_status_valid &&
- (hdev->asic_prop.fw_boot_cpu_security_map &
- CPU_BOOT_DEV_STS0_HBM_CRED_EN))
+ if (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 &
+ CPU_BOOT_DEV_STS0_HBM_CRED_EN)
return;
hbm0_wr = 0x33333333;
@@ -2487,10 +2542,12 @@ static void gaudi_init_golden_registers(struct hl_device *hdev)
static void gaudi_init_pci_dma_qman(struct hl_device *hdev, int dma_id,
int qman_id, dma_addr_t qman_pq_addr)
{
+ struct cpu_dyn_regs *dyn_regs =
+ &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi;
u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi;
u32 q_off, dma_qm_offset;
- u32 dma_qm_err_cfg;
+ u32 dma_qm_err_cfg, irq_handler_offset;
dma_qm_offset = dma_id * DMA_QMAN_OFFSET;
@@ -2539,20 +2596,23 @@ static void gaudi_init_pci_dma_qman(struct hl_device *hdev, int dma_id,
/* The following configuration is needed only once per QMAN */
if (qman_id == 0) {
+ irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
+ mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
+ le32_to_cpu(dyn_regs->gic_dma_qm_irq_ctrl);
+
/* Configure RAZWI IRQ */
dma_qm_err_cfg = PCI_DMA_QMAN_GLBL_ERR_CFG_MSG_EN_MASK;
- if (hdev->stop_on_err) {
+ if (hdev->stop_on_err)
dma_qm_err_cfg |=
PCI_DMA_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK;
- }
WREG32(mmDMA0_QM_GLBL_ERR_CFG + dma_qm_offset, dma_qm_err_cfg);
+
WREG32(mmDMA0_QM_GLBL_ERR_ADDR_LO + dma_qm_offset,
- lower_32_bits(CFG_BASE +
- mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR));
+ lower_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmDMA0_QM_GLBL_ERR_ADDR_HI + dma_qm_offset,
- upper_32_bits(CFG_BASE +
- mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR));
+ upper_32_bits(CFG_BASE + irq_handler_offset));
+
WREG32(mmDMA0_QM_GLBL_ERR_WDATA + dma_qm_offset,
gaudi_irq_map_table[GAUDI_EVENT_DMA0_QM].cpu_id +
dma_id);
@@ -2573,8 +2633,11 @@ static void gaudi_init_pci_dma_qman(struct hl_device *hdev, int dma_id,
static void gaudi_init_dma_core(struct hl_device *hdev, int dma_id)
{
- u32 dma_offset = dma_id * DMA_CORE_OFFSET;
+ struct cpu_dyn_regs *dyn_regs =
+ &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 dma_err_cfg = 1 << DMA0_CORE_ERR_CFG_ERR_MSG_EN_SHIFT;
+ u32 dma_offset = dma_id * DMA_CORE_OFFSET;
+ u32 irq_handler_offset;
/* Set to maximum possible according to physical size */
WREG32(mmDMA0_CORE_RD_MAX_OUTSTAND + dma_offset, 0);
@@ -2588,10 +2651,16 @@ static void gaudi_init_dma_core(struct hl_device *hdev, int dma_id)
dma_err_cfg |= 1 << DMA0_CORE_ERR_CFG_STOP_ON_ERR_SHIFT;
WREG32(mmDMA0_CORE_ERR_CFG + dma_offset, dma_err_cfg);
+
+ irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
+ mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
+ le32_to_cpu(dyn_regs->gic_dma_core_irq_ctrl);
+
WREG32(mmDMA0_CORE_ERRMSG_ADDR_LO + dma_offset,
- lower_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR));
+ lower_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmDMA0_CORE_ERRMSG_ADDR_HI + dma_offset,
- upper_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR));
+ upper_32_bits(CFG_BASE + irq_handler_offset));
+
WREG32(mmDMA0_CORE_ERRMSG_WDATA + dma_offset,
gaudi_irq_map_table[GAUDI_EVENT_DMA0_CORE].cpu_id + dma_id);
WREG32(mmDMA0_CORE_PROT + dma_offset,
@@ -2654,10 +2723,12 @@ static void gaudi_init_pci_dma_qmans(struct hl_device *hdev)
static void gaudi_init_hbm_dma_qman(struct hl_device *hdev, int dma_id,
int qman_id, u64 qman_base_addr)
{
+ struct cpu_dyn_regs *dyn_regs =
+ &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi;
u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi;
+ u32 dma_qm_err_cfg, irq_handler_offset;
u32 q_off, dma_qm_offset;
- u32 dma_qm_err_cfg;
dma_qm_offset = dma_id * DMA_QMAN_OFFSET;
@@ -2697,6 +2768,10 @@ static void gaudi_init_hbm_dma_qman(struct hl_device *hdev, int dma_id,
WREG32(mmDMA0_QM_CP_LDMA_DST_BASE_LO_OFFSET_0 + q_off,
QMAN_CPDMA_DST_OFFSET);
} else {
+ irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
+ mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
+ le32_to_cpu(dyn_regs->gic_dma_qm_irq_ctrl);
+
WREG32(mmDMA0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off,
QMAN_LDMA_SIZE_OFFSET);
WREG32(mmDMA0_QM_CP_LDMA_SRC_BASE_LO_OFFSET_0 + q_off,
@@ -2706,18 +2781,17 @@ static void gaudi_init_hbm_dma_qman(struct hl_device *hdev, int dma_id,
/* Configure RAZWI IRQ */
dma_qm_err_cfg = HBM_DMA_QMAN_GLBL_ERR_CFG_MSG_EN_MASK;
- if (hdev->stop_on_err) {
+ if (hdev->stop_on_err)
dma_qm_err_cfg |=
HBM_DMA_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK;
- }
+
WREG32(mmDMA0_QM_GLBL_ERR_CFG + dma_qm_offset, dma_qm_err_cfg);
WREG32(mmDMA0_QM_GLBL_ERR_ADDR_LO + dma_qm_offset,
- lower_32_bits(CFG_BASE +
- mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR));
+ lower_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmDMA0_QM_GLBL_ERR_ADDR_HI + dma_qm_offset,
- upper_32_bits(CFG_BASE +
- mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR));
+ upper_32_bits(CFG_BASE + irq_handler_offset));
+
WREG32(mmDMA0_QM_GLBL_ERR_WDATA + dma_qm_offset,
gaudi_irq_map_table[GAUDI_EVENT_DMA0_QM].cpu_id +
dma_id);
@@ -2792,8 +2866,11 @@ static void gaudi_init_hbm_dma_qmans(struct hl_device *hdev)
static void gaudi_init_mme_qman(struct hl_device *hdev, u32 mme_offset,
int qman_id, u64 qman_base_addr)
{
+ struct cpu_dyn_regs *dyn_regs =
+ &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 mtr_base_lo, mtr_base_hi;
u32 so_base_lo, so_base_hi;
+ u32 irq_handler_offset;
u32 q_off, mme_id;
u32 mme_qm_err_cfg;
@@ -2825,6 +2902,10 @@ static void gaudi_init_mme_qman(struct hl_device *hdev, u32 mme_offset,
WREG32(mmMME0_QM_CP_LDMA_DST_BASE_LO_OFFSET_0 + q_off,
QMAN_CPDMA_DST_OFFSET);
} else {
+ irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
+ mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
+ le32_to_cpu(dyn_regs->gic_mme_qm_irq_ctrl);
+
WREG32(mmMME0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off,
QMAN_LDMA_SIZE_OFFSET);
WREG32(mmMME0_QM_CP_LDMA_SRC_BASE_LO_OFFSET_0 + q_off,
@@ -2834,20 +2915,20 @@ static void gaudi_init_mme_qman(struct hl_device *hdev, u32 mme_offset,
/* Configure RAZWI IRQ */
mme_id = mme_offset /
- (mmMME1_QM_GLBL_CFG0 - mmMME0_QM_GLBL_CFG0);
+ (mmMME1_QM_GLBL_CFG0 - mmMME0_QM_GLBL_CFG0) / 2;
mme_qm_err_cfg = MME_QMAN_GLBL_ERR_CFG_MSG_EN_MASK;
- if (hdev->stop_on_err) {
+ if (hdev->stop_on_err)
mme_qm_err_cfg |=
MME_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK;
- }
+
WREG32(mmMME0_QM_GLBL_ERR_CFG + mme_offset, mme_qm_err_cfg);
+
WREG32(mmMME0_QM_GLBL_ERR_ADDR_LO + mme_offset,
- lower_32_bits(CFG_BASE +
- mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR));
+ lower_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmMME0_QM_GLBL_ERR_ADDR_HI + mme_offset,
- upper_32_bits(CFG_BASE +
- mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR));
+ upper_32_bits(CFG_BASE + irq_handler_offset));
+
WREG32(mmMME0_QM_GLBL_ERR_WDATA + mme_offset,
gaudi_irq_map_table[GAUDI_EVENT_MME0_QM].cpu_id +
mme_id);
@@ -2912,10 +2993,12 @@ static void gaudi_init_mme_qmans(struct hl_device *hdev)
static void gaudi_init_tpc_qman(struct hl_device *hdev, u32 tpc_offset,
int qman_id, u64 qman_base_addr)
{
+ struct cpu_dyn_regs *dyn_regs =
+ &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi;
u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi;
+ u32 tpc_qm_err_cfg, irq_handler_offset;
u32 q_off, tpc_id;
- u32 tpc_qm_err_cfg;
mtr_base_en_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
@@ -2956,6 +3039,10 @@ static void gaudi_init_tpc_qman(struct hl_device *hdev, u32 tpc_offset,
WREG32(mmTPC0_QM_CP_LDMA_DST_BASE_LO_OFFSET_0 + q_off,
QMAN_CPDMA_DST_OFFSET);
} else {
+ irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
+ mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
+ le32_to_cpu(dyn_regs->gic_tpc_qm_irq_ctrl);
+
WREG32(mmTPC0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off,
QMAN_LDMA_SIZE_OFFSET);
WREG32(mmTPC0_QM_CP_LDMA_SRC_BASE_LO_OFFSET_0 + q_off,
@@ -2965,18 +3052,17 @@ static void gaudi_init_tpc_qman(struct hl_device *hdev, u32 tpc_offset,
/* Configure RAZWI IRQ */
tpc_qm_err_cfg = TPC_QMAN_GLBL_ERR_CFG_MSG_EN_MASK;
- if (hdev->stop_on_err) {
+ if (hdev->stop_on_err)
tpc_qm_err_cfg |=
TPC_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK;
- }
WREG32(mmTPC0_QM_GLBL_ERR_CFG + tpc_offset, tpc_qm_err_cfg);
+
WREG32(mmTPC0_QM_GLBL_ERR_ADDR_LO + tpc_offset,
- lower_32_bits(CFG_BASE +
- mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR));
+ lower_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmTPC0_QM_GLBL_ERR_ADDR_HI + tpc_offset,
- upper_32_bits(CFG_BASE +
- mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR));
+ upper_32_bits(CFG_BASE + irq_handler_offset));
+
WREG32(mmTPC0_QM_GLBL_ERR_WDATA + tpc_offset,
gaudi_irq_map_table[GAUDI_EVENT_TPC0_QM].cpu_id +
tpc_id);
@@ -3059,10 +3145,12 @@ static void gaudi_init_tpc_qmans(struct hl_device *hdev)
static void gaudi_init_nic_qman(struct hl_device *hdev, u32 nic_offset,
int qman_id, u64 qman_base_addr, int nic_id)
{
+ struct cpu_dyn_regs *dyn_regs =
+ &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi;
u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi;
+ u32 nic_qm_err_cfg, irq_handler_offset;
u32 q_off;
- u32 nic_qm_err_cfg;
mtr_base_en_lo = lower_32_bits(CFG_BASE +
mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0);
@@ -3109,20 +3197,23 @@ static void gaudi_init_nic_qman(struct hl_device *hdev, u32 nic_offset,
WREG32(mmNIC0_QM0_CP_MSG_BASE3_ADDR_HI_0 + q_off, so_base_ws_hi);
if (qman_id == 0) {
+ irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
+ mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
+ le32_to_cpu(dyn_regs->gic_nic_qm_irq_ctrl);
+
/* Configure RAZWI IRQ */
nic_qm_err_cfg = NIC_QMAN_GLBL_ERR_CFG_MSG_EN_MASK;
- if (hdev->stop_on_err) {
+ if (hdev->stop_on_err)
nic_qm_err_cfg |=
NIC_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK;
- }
WREG32(mmNIC0_QM0_GLBL_ERR_CFG + nic_offset, nic_qm_err_cfg);
+
WREG32(mmNIC0_QM0_GLBL_ERR_ADDR_LO + nic_offset,
- lower_32_bits(CFG_BASE +
- mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR));
+ lower_32_bits(CFG_BASE + irq_handler_offset));
WREG32(mmNIC0_QM0_GLBL_ERR_ADDR_HI + nic_offset,
- upper_32_bits(CFG_BASE +
- mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR));
+ upper_32_bits(CFG_BASE + irq_handler_offset));
+
WREG32(mmNIC0_QM0_GLBL_ERR_WDATA + nic_offset,
gaudi_irq_map_table[GAUDI_EVENT_NIC0_QM0].cpu_id +
nic_id);
@@ -3475,7 +3566,7 @@ static void gaudi_set_clock_gating(struct hl_device *hdev)
if (hdev->in_debug)
return;
- if (!hdev->asic_prop.fw_security_disabled)
+ if (hdev->asic_prop.fw_security_enabled)
return;
for (i = GAUDI_PCI_DMA_1, qman_offset = 0 ; i < GAUDI_HBM_DMA_1 ; i++) {
@@ -3535,7 +3626,7 @@ static void gaudi_disable_clock_gating(struct hl_device *hdev)
u32 qman_offset;
int i;
- if (!hdev->asic_prop.fw_security_disabled)
+ if (hdev->asic_prop.fw_security_enabled)
return;
for (i = 0, qman_offset = 0 ; i < DMA_NUMBER_OF_CHANNELS ; i++) {
@@ -3674,9 +3765,6 @@ static int gaudi_load_firmware_to_device(struct hl_device *hdev)
{
void __iomem *dst;
- /* HBM scrambler must be initialized before pushing F/W to HBM */
- gaudi_init_scrambler_hbm(hdev);
-
dst = hdev->pcie_bar[HBM_BAR_ID] + LINUX_FW_OFFSET;
return hl_fw_load_fw_to_device(hdev, GAUDI_LINUX_FW_FILE, dst, 0, 0);
@@ -3691,42 +3779,71 @@ static int gaudi_load_boot_fit_to_device(struct hl_device *hdev)
return hl_fw_load_fw_to_device(hdev, GAUDI_BOOT_FIT_FILE, dst, 0, 0);
}
-static int gaudi_read_device_fw_version(struct hl_device *hdev,
- enum hl_fw_component fwc)
+static void gaudi_init_dynamic_firmware_loader(struct hl_device *hdev)
{
- const char *name;
- u32 ver_off;
- char *dest;
+ struct dynamic_fw_load_mgr *dynamic_loader;
+ struct cpu_dyn_regs *dyn_regs;
- switch (fwc) {
- case FW_COMP_UBOOT:
- ver_off = RREG32(mmUBOOT_VER_OFFSET);
- dest = hdev->asic_prop.uboot_ver;
- name = "U-Boot";
- break;
- case FW_COMP_PREBOOT:
- ver_off = RREG32(mmPREBOOT_VER_OFFSET);
- dest = hdev->asic_prop.preboot_ver;
- name = "Preboot";
- break;
- default:
- dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc);
- return -EIO;
- }
+ dynamic_loader = &hdev->fw_loader.dynamic_loader;
- ver_off &= ~((u32)SRAM_BASE_ADDR);
+ /*
+ * here we update initial values for few specific dynamic regs (as
+ * before reading the first descriptor from FW those value has to be
+ * hard-coded) in later stages of the protocol those values will be
+ * updated automatically by reading the FW descriptor so data there
+ * will always be up-to-date
+ */
+ dyn_regs = &dynamic_loader->comm_desc.cpu_dyn_regs;
+ dyn_regs->kmd_msg_to_cpu =
+ cpu_to_le32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU);
+ dyn_regs->cpu_cmd_status_to_host =
+ cpu_to_le32(mmCPU_CMD_STATUS_TO_HOST);
- if (ver_off < SRAM_SIZE - VERSION_MAX_LEN) {
- memcpy_fromio(dest, hdev->pcie_bar[SRAM_BAR_ID] + ver_off,
- VERSION_MAX_LEN);
- } else {
- dev_err(hdev->dev, "%s version offset (0x%x) is above SRAM\n",
- name, ver_off);
- strcpy(dest, "unavailable");
- return -EIO;
- }
+ dynamic_loader->wait_for_bl_timeout = GAUDI_WAIT_FOR_BL_TIMEOUT_USEC;
+}
- return 0;
+static void gaudi_init_static_firmware_loader(struct hl_device *hdev)
+{
+ struct static_fw_load_mgr *static_loader;
+
+ static_loader = &hdev->fw_loader.static_loader;
+
+ static_loader->preboot_version_max_off = SRAM_SIZE - VERSION_MAX_LEN;
+ static_loader->boot_fit_version_max_off = SRAM_SIZE - VERSION_MAX_LEN;
+ static_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU;
+ static_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST;
+ static_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS;
+ static_loader->cpu_boot_dev_status0_reg = mmCPU_BOOT_DEV_STS0;
+ static_loader->cpu_boot_dev_status1_reg = mmCPU_BOOT_DEV_STS1;
+ static_loader->boot_err0_reg = mmCPU_BOOT_ERR0;
+ static_loader->boot_err1_reg = mmCPU_BOOT_ERR1;
+ static_loader->preboot_version_offset_reg = mmPREBOOT_VER_OFFSET;
+ static_loader->boot_fit_version_offset_reg = mmUBOOT_VER_OFFSET;
+ static_loader->sram_offset_mask = ~(lower_32_bits(SRAM_BASE_ADDR));
+ static_loader->cpu_reset_wait_msec = hdev->pldm ?
+ GAUDI_PLDM_RESET_WAIT_MSEC :
+ GAUDI_CPU_RESET_WAIT_MSEC;
+}
+
+static void gaudi_init_firmware_loader(struct hl_device *hdev)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ struct fw_load_mgr *fw_loader = &hdev->fw_loader;
+
+ /* fill common fields */
+ fw_loader->linux_loaded = false;
+ fw_loader->boot_fit_img.image_name = GAUDI_BOOT_FIT_FILE;
+ fw_loader->linux_img.image_name = GAUDI_LINUX_FW_FILE;
+ fw_loader->cpu_timeout = GAUDI_CPU_TIMEOUT_USEC;
+ fw_loader->boot_fit_timeout = GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC;
+ fw_loader->skip_bmc = !hdev->bmc_enable;
+ fw_loader->sram_bar_id = SRAM_BAR_ID;
+ fw_loader->dram_bar_id = HBM_BAR_ID;
+
+ if (prop->dynamic_fw_load)
+ gaudi_init_dynamic_firmware_loader(hdev);
+ else
+ gaudi_init_static_firmware_loader(hdev);
}
static int gaudi_init_cpu(struct hl_device *hdev)
@@ -3744,15 +3861,10 @@ static int gaudi_init_cpu(struct hl_device *hdev)
* The device CPU works with 40 bits addresses.
* This register sets the extension to 50 bits.
*/
- if (hdev->asic_prop.fw_security_disabled)
+ if (!hdev->asic_prop.fw_security_enabled)
WREG32(mmCPU_IF_CPU_MSB_ADDR, hdev->cpu_pci_msb_addr);
- rc = hl_fw_init_cpu(hdev, mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS,
- mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU,
- mmCPU_CMD_STATUS_TO_HOST,
- mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0,
- !hdev->bmc_enable, GAUDI_CPU_TIMEOUT_USEC,
- GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC);
+ rc = hl_fw_init_cpu(hdev);
if (rc)
return rc;
@@ -3764,10 +3876,12 @@ static int gaudi_init_cpu(struct hl_device *hdev)
static int gaudi_init_cpu_queues(struct hl_device *hdev, u32 cpu_timeout)
{
- struct gaudi_device *gaudi = hdev->asic_specific;
+ struct cpu_dyn_regs *dyn_regs =
+ &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
struct asic_fixed_properties *prop = &hdev->asic_prop;
+ struct gaudi_device *gaudi = hdev->asic_specific;
+ u32 status, irq_handler_offset;
struct hl_eq *eq;
- u32 status;
struct hl_hw_queue *cpu_pq =
&hdev->kernel_queues[GAUDI_QUEUE_ID_CPU_PQ];
int err;
@@ -3806,7 +3920,12 @@ static int gaudi_init_cpu_queues(struct hl_device *hdev, u32 cpu_timeout)
WREG32(mmCPU_IF_QUEUE_INIT,
PQ_INIT_STATUS_READY_FOR_CP_SINGLE_MSI);
- WREG32(mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR, GAUDI_EVENT_PI_UPDATE);
+ irq_handler_offset = prop->gic_interrupts_enable ?
+ mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
+ le32_to_cpu(dyn_regs->gic_host_pi_upd_irq);
+
+ WREG32(irq_handler_offset,
+ gaudi_irq_map_table[GAUDI_EVENT_PI_UPDATE].cpu_id);
err = hl_poll_timeout(
hdev,
@@ -3823,8 +3942,10 @@ static int gaudi_init_cpu_queues(struct hl_device *hdev, u32 cpu_timeout)
}
/* update FW application security bits */
- if (prop->fw_security_status_valid)
- prop->fw_app_security_map = RREG32(mmCPU_BOOT_DEV_STS0);
+ if (prop->fw_cpu_boot_dev_sts0_valid)
+ prop->fw_app_cpu_boot_dev_sts0 = RREG32(mmCPU_BOOT_DEV_STS0);
+ if (prop->fw_cpu_boot_dev_sts1_valid)
+ prop->fw_app_cpu_boot_dev_sts1 = RREG32(mmCPU_BOOT_DEV_STS1);
gaudi->hw_cap_initialized |= HW_CAP_CPU_Q;
return 0;
@@ -3835,7 +3956,7 @@ static void gaudi_pre_hw_init(struct hl_device *hdev)
/* Perform read from the device to make sure device is up */
RREG32(mmHW_STATE);
- if (hdev->asic_prop.fw_security_disabled) {
+ if (!hdev->asic_prop.fw_security_enabled) {
/* Set the access through PCI bars (Linux driver only) as
* secured
*/
@@ -3860,13 +3981,27 @@ static void gaudi_pre_hw_init(struct hl_device *hdev)
static int gaudi_hw_init(struct hl_device *hdev)
{
+ struct gaudi_device *gaudi = hdev->asic_specific;
int rc;
gaudi_pre_hw_init(hdev);
- gaudi_init_pci_dma_qmans(hdev);
+ /* If iATU is done by FW, the HBM bar ALWAYS points to DRAM_PHYS_BASE.
+ * So we set it here and if anyone tries to move it later to
+ * a different address, there will be an error
+ */
+ if (hdev->asic_prop.iatu_done_by_fw)
+ gaudi->hbm_bar_cur_addr = DRAM_PHYS_BASE;
- gaudi_init_hbm_dma_qmans(hdev);
+ /*
+ * Before pushing u-boot/linux to device, need to set the hbm bar to
+ * base address of dram
+ */
+ if (gaudi_set_hbm_bar_base(hdev, DRAM_PHYS_BASE) == U64_MAX) {
+ dev_err(hdev->dev,
+ "failed to map HBM bar to DRAM base address\n");
+ return -EIO;
+ }
rc = gaudi_init_cpu(hdev);
if (rc) {
@@ -3895,6 +4030,10 @@ static int gaudi_hw_init(struct hl_device *hdev)
gaudi_init_security(hdev);
+ gaudi_init_pci_dma_qmans(hdev);
+
+ gaudi_init_hbm_dma_qmans(hdev);
+
gaudi_init_mme_qmans(hdev);
gaudi_init_tpc_qmans(hdev);
@@ -3934,8 +4073,11 @@ disable_queues:
static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset)
{
+ struct cpu_dyn_regs *dyn_regs =
+ &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
+ u32 status, reset_timeout_ms, cpu_timeout_ms, irq_handler_offset;
struct gaudi_device *gaudi = hdev->asic_specific;
- u32 status, reset_timeout_ms, cpu_timeout_ms;
+ bool driver_performs_reset;
if (!hard_reset) {
dev_err(hdev->dev, "GAUDI doesn't support soft-reset\n");
@@ -3950,26 +4092,35 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset)
cpu_timeout_ms = GAUDI_CPU_RESET_WAIT_MSEC;
}
+ driver_performs_reset = !!(!hdev->asic_prop.fw_security_enabled &&
+ !hdev->asic_prop.hard_reset_done_by_fw);
+
/* Set device to handle FLR by H/W as we will put the device CPU to
* halt mode
*/
- if (hdev->asic_prop.fw_security_disabled &&
- !hdev->asic_prop.hard_reset_done_by_fw)
+ if (driver_performs_reset)
WREG32(mmPCIE_AUX_FLR_CTRL, (PCIE_AUX_FLR_CTRL_HW_CTRL_MASK |
PCIE_AUX_FLR_CTRL_INT_MASK_MASK));
- /* I don't know what is the state of the CPU so make sure it is
- * stopped in any means necessary
+ /* If linux is loaded in the device CPU we need to communicate with it
+ * via the GIC. Otherwise, we need to use COMMS or the MSG_TO_CPU
+ * registers in case of old F/Ws
*/
- if (hdev->asic_prop.hard_reset_done_by_fw)
- WREG32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU, KMD_MSG_RST_DEV);
- else
- WREG32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU, KMD_MSG_GOTO_WFE);
+ if (hdev->fw_loader.linux_loaded) {
+ irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
+ mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
+ le32_to_cpu(dyn_regs->gic_host_halt_irq);
- WREG32(mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR, GAUDI_EVENT_HALT_MACHINE);
+ WREG32(irq_handler_offset,
+ gaudi_irq_map_table[GAUDI_EVENT_HALT_MACHINE].cpu_id);
+ } else {
+ if (hdev->asic_prop.hard_reset_done_by_fw)
+ hl_fw_ask_hard_reset_without_linux(hdev);
+ else
+ hl_fw_ask_halt_machine_without_linux(hdev);
+ }
- if (hdev->asic_prop.fw_security_disabled &&
- !hdev->asic_prop.hard_reset_done_by_fw) {
+ if (driver_performs_reset) {
/* Configure the reset registers. Must be done as early as
* possible in case we fail during H/W initialization
@@ -4003,8 +4154,7 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset)
WREG32(mmPREBOOT_PCIE_EN, LKD_HARD_RESET_MAGIC);
/* Restart BTL/BLR upon hard-reset */
- if (hdev->asic_prop.fw_security_disabled)
- WREG32(mmPSOC_GLOBAL_CONF_BOOT_SEQ_RE_START, 1);
+ WREG32(mmPSOC_GLOBAL_CONF_BOOT_SEQ_RE_START, 1);
WREG32(mmPSOC_GLOBAL_CONF_SW_ALL_RST,
1 << PSOC_GLOBAL_CONF_SW_ALL_RST_IND_SHIFT);
@@ -4041,6 +4191,8 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset)
HW_CAP_CLK_GATE);
memset(gaudi->events_stat, 0, sizeof(gaudi->events_stat));
+
+ hdev->device_cpu_is_halted = false;
}
}
@@ -4078,10 +4230,12 @@ static int gaudi_cb_mmap(struct hl_device *hdev, struct vm_area_struct *vma,
static void gaudi_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi)
{
+ struct cpu_dyn_regs *dyn_regs =
+ &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
+ u32 db_reg_offset, db_value, dma_qm_offset, q_off, irq_handler_offset;
struct gaudi_device *gaudi = hdev->asic_specific;
- u32 db_reg_offset, db_value, dma_qm_offset, q_off;
- int dma_id;
bool invalid_queue = false;
+ int dma_id;
switch (hw_queue_id) {
case GAUDI_QUEUE_ID_DMA_0_0...GAUDI_QUEUE_ID_DMA_0_3:
@@ -4307,164 +4461,84 @@ static void gaudi_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi)
db_reg_offset = mmTPC7_QM_PQ_PI_3;
break;
- case GAUDI_QUEUE_ID_NIC_0_0:
- db_reg_offset = mmNIC0_QM0_PQ_PI_0;
- break;
-
- case GAUDI_QUEUE_ID_NIC_0_1:
- db_reg_offset = mmNIC0_QM0_PQ_PI_1;
- break;
-
- case GAUDI_QUEUE_ID_NIC_0_2:
- db_reg_offset = mmNIC0_QM0_PQ_PI_2;
- break;
-
- case GAUDI_QUEUE_ID_NIC_0_3:
- db_reg_offset = mmNIC0_QM0_PQ_PI_3;
- break;
-
- case GAUDI_QUEUE_ID_NIC_1_0:
- db_reg_offset = mmNIC0_QM1_PQ_PI_0;
- break;
-
- case GAUDI_QUEUE_ID_NIC_1_1:
- db_reg_offset = mmNIC0_QM1_PQ_PI_1;
- break;
-
- case GAUDI_QUEUE_ID_NIC_1_2:
- db_reg_offset = mmNIC0_QM1_PQ_PI_2;
- break;
-
- case GAUDI_QUEUE_ID_NIC_1_3:
- db_reg_offset = mmNIC0_QM1_PQ_PI_3;
- break;
-
- case GAUDI_QUEUE_ID_NIC_2_0:
- db_reg_offset = mmNIC1_QM0_PQ_PI_0;
- break;
-
- case GAUDI_QUEUE_ID_NIC_2_1:
- db_reg_offset = mmNIC1_QM0_PQ_PI_1;
- break;
-
- case GAUDI_QUEUE_ID_NIC_2_2:
- db_reg_offset = mmNIC1_QM0_PQ_PI_2;
- break;
-
- case GAUDI_QUEUE_ID_NIC_2_3:
- db_reg_offset = mmNIC1_QM0_PQ_PI_3;
- break;
-
- case GAUDI_QUEUE_ID_NIC_3_0:
- db_reg_offset = mmNIC1_QM1_PQ_PI_0;
- break;
-
- case GAUDI_QUEUE_ID_NIC_3_1:
- db_reg_offset = mmNIC1_QM1_PQ_PI_1;
- break;
-
- case GAUDI_QUEUE_ID_NIC_3_2:
- db_reg_offset = mmNIC1_QM1_PQ_PI_2;
- break;
-
- case GAUDI_QUEUE_ID_NIC_3_3:
- db_reg_offset = mmNIC1_QM1_PQ_PI_3;
- break;
-
- case GAUDI_QUEUE_ID_NIC_4_0:
- db_reg_offset = mmNIC2_QM0_PQ_PI_0;
- break;
-
- case GAUDI_QUEUE_ID_NIC_4_1:
- db_reg_offset = mmNIC2_QM0_PQ_PI_1;
- break;
-
- case GAUDI_QUEUE_ID_NIC_4_2:
- db_reg_offset = mmNIC2_QM0_PQ_PI_2;
- break;
-
- case GAUDI_QUEUE_ID_NIC_4_3:
- db_reg_offset = mmNIC2_QM0_PQ_PI_3;
- break;
-
- case GAUDI_QUEUE_ID_NIC_5_0:
- db_reg_offset = mmNIC2_QM1_PQ_PI_0;
- break;
+ case GAUDI_QUEUE_ID_NIC_0_0...GAUDI_QUEUE_ID_NIC_0_3:
+ if (!(gaudi->hw_cap_initialized & HW_CAP_NIC0))
+ invalid_queue = true;
- case GAUDI_QUEUE_ID_NIC_5_1:
- db_reg_offset = mmNIC2_QM1_PQ_PI_1;
+ q_off = ((hw_queue_id - 1) & 0x3) * 4;
+ db_reg_offset = mmNIC0_QM0_PQ_PI_0 + q_off;
break;
- case GAUDI_QUEUE_ID_NIC_5_2:
- db_reg_offset = mmNIC2_QM1_PQ_PI_2;
- break;
+ case GAUDI_QUEUE_ID_NIC_1_0...GAUDI_QUEUE_ID_NIC_1_3:
+ if (!(gaudi->hw_cap_initialized & HW_CAP_NIC1))
+ invalid_queue = true;
- case GAUDI_QUEUE_ID_NIC_5_3:
- db_reg_offset = mmNIC2_QM1_PQ_PI_3;
+ q_off = ((hw_queue_id - 1) & 0x3) * 4;
+ db_reg_offset = mmNIC0_QM1_PQ_PI_0 + q_off;
break;
- case GAUDI_QUEUE_ID_NIC_6_0:
- db_reg_offset = mmNIC3_QM0_PQ_PI_0;
- break;
+ case GAUDI_QUEUE_ID_NIC_2_0...GAUDI_QUEUE_ID_NIC_2_3:
+ if (!(gaudi->hw_cap_initialized & HW_CAP_NIC2))
+ invalid_queue = true;
- case GAUDI_QUEUE_ID_NIC_6_1:
- db_reg_offset = mmNIC3_QM0_PQ_PI_1;
+ q_off = ((hw_queue_id - 1) & 0x3) * 4;
+ db_reg_offset = mmNIC1_QM0_PQ_PI_0 + q_off;
break;
- case GAUDI_QUEUE_ID_NIC_6_2:
- db_reg_offset = mmNIC3_QM0_PQ_PI_2;
- break;
+ case GAUDI_QUEUE_ID_NIC_3_0...GAUDI_QUEUE_ID_NIC_3_3:
+ if (!(gaudi->hw_cap_initialized & HW_CAP_NIC3))
+ invalid_queue = true;
- case GAUDI_QUEUE_ID_NIC_6_3:
- db_reg_offset = mmNIC3_QM0_PQ_PI_3;
+ q_off = ((hw_queue_id - 1) & 0x3) * 4;
+ db_reg_offset = mmNIC1_QM1_PQ_PI_0 + q_off;
break;
- case GAUDI_QUEUE_ID_NIC_7_0:
- db_reg_offset = mmNIC3_QM1_PQ_PI_0;
- break;
+ case GAUDI_QUEUE_ID_NIC_4_0...GAUDI_QUEUE_ID_NIC_4_3:
+ if (!(gaudi->hw_cap_initialized & HW_CAP_NIC4))
+ invalid_queue = true;
- case GAUDI_QUEUE_ID_NIC_7_1:
- db_reg_offset = mmNIC3_QM1_PQ_PI_1;
+ q_off = ((hw_queue_id - 1) & 0x3) * 4;
+ db_reg_offset = mmNIC2_QM0_PQ_PI_0 + q_off;
break;
- case GAUDI_QUEUE_ID_NIC_7_2:
- db_reg_offset = mmNIC3_QM1_PQ_PI_2;
- break;
+ case GAUDI_QUEUE_ID_NIC_5_0...GAUDI_QUEUE_ID_NIC_5_3:
+ if (!(gaudi->hw_cap_initialized & HW_CAP_NIC5))
+ invalid_queue = true;
- case GAUDI_QUEUE_ID_NIC_7_3:
- db_reg_offset = mmNIC3_QM1_PQ_PI_3;
+ q_off = ((hw_queue_id - 1) & 0x3) * 4;
+ db_reg_offset = mmNIC2_QM1_PQ_PI_0 + q_off;
break;
- case GAUDI_QUEUE_ID_NIC_8_0:
- db_reg_offset = mmNIC4_QM0_PQ_PI_0;
- break;
+ case GAUDI_QUEUE_ID_NIC_6_0...GAUDI_QUEUE_ID_NIC_6_3:
+ if (!(gaudi->hw_cap_initialized & HW_CAP_NIC6))
+ invalid_queue = true;
- case GAUDI_QUEUE_ID_NIC_8_1:
- db_reg_offset = mmNIC4_QM0_PQ_PI_1;
+ q_off = ((hw_queue_id - 1) & 0x3) * 4;
+ db_reg_offset = mmNIC3_QM0_PQ_PI_0 + q_off;
break;
- case GAUDI_QUEUE_ID_NIC_8_2:
- db_reg_offset = mmNIC4_QM0_PQ_PI_2;
- break;
+ case GAUDI_QUEUE_ID_NIC_7_0...GAUDI_QUEUE_ID_NIC_7_3:
+ if (!(gaudi->hw_cap_initialized & HW_CAP_NIC7))
+ invalid_queue = true;
- case GAUDI_QUEUE_ID_NIC_8_3:
- db_reg_offset = mmNIC4_QM0_PQ_PI_3;
+ q_off = ((hw_queue_id - 1) & 0x3) * 4;
+ db_reg_offset = mmNIC3_QM1_PQ_PI_0 + q_off;
break;
- case GAUDI_QUEUE_ID_NIC_9_0:
- db_reg_offset = mmNIC4_QM1_PQ_PI_0;
- break;
+ case GAUDI_QUEUE_ID_NIC_8_0...GAUDI_QUEUE_ID_NIC_8_3:
+ if (!(gaudi->hw_cap_initialized & HW_CAP_NIC8))
+ invalid_queue = true;
- case GAUDI_QUEUE_ID_NIC_9_1:
- db_reg_offset = mmNIC4_QM1_PQ_PI_1;
+ q_off = ((hw_queue_id - 1) & 0x3) * 4;
+ db_reg_offset = mmNIC4_QM0_PQ_PI_0 + q_off;
break;
- case GAUDI_QUEUE_ID_NIC_9_2:
- db_reg_offset = mmNIC4_QM1_PQ_PI_2;
- break;
+ case GAUDI_QUEUE_ID_NIC_9_0...GAUDI_QUEUE_ID_NIC_9_3:
+ if (!(gaudi->hw_cap_initialized & HW_CAP_NIC9))
+ invalid_queue = true;
- case GAUDI_QUEUE_ID_NIC_9_3:
- db_reg_offset = mmNIC4_QM1_PQ_PI_3;
+ q_off = ((hw_queue_id - 1) & 0x3) * 4;
+ db_reg_offset = mmNIC4_QM1_PQ_PI_0 + q_off;
break;
default:
@@ -4486,8 +4560,13 @@ static void gaudi_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi)
if (hw_queue_id == GAUDI_QUEUE_ID_CPU_PQ) {
/* make sure device CPU will read latest data from host */
mb();
- WREG32(mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR,
- GAUDI_EVENT_PI_UPDATE);
+
+ irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
+ mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
+ le32_to_cpu(dyn_regs->gic_host_pi_upd_irq);
+
+ WREG32(irq_handler_offset,
+ gaudi_irq_map_table[GAUDI_EVENT_PI_UPDATE].cpu_id);
}
}
@@ -4934,6 +5013,7 @@ already_pinned:
return 0;
unpin_memory:
+ list_del(&userptr->job_node);
hl_unpin_host_memory(hdev, userptr);
free_userptr:
kfree(userptr);
@@ -6513,7 +6593,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid)
gaudi_mmu_prepare_reg(hdev, mmMME2_ACC_WBC, asid);
gaudi_mmu_prepare_reg(hdev, mmMME3_ACC_WBC, asid);
- if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC0) {
+ if (gaudi->hw_cap_initialized & HW_CAP_NIC0) {
gaudi_mmu_prepare_reg(hdev, mmNIC0_QM0_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC0_QM0_GLBL_NON_SECURE_PROPS_1,
@@ -6526,7 +6606,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid)
asid);
}
- if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC1) {
+ if (gaudi->hw_cap_initialized & HW_CAP_NIC1) {
gaudi_mmu_prepare_reg(hdev, mmNIC0_QM1_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC0_QM1_GLBL_NON_SECURE_PROPS_1,
@@ -6539,7 +6619,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid)
asid);
}
- if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC2) {
+ if (gaudi->hw_cap_initialized & HW_CAP_NIC2) {
gaudi_mmu_prepare_reg(hdev, mmNIC1_QM0_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC1_QM0_GLBL_NON_SECURE_PROPS_1,
@@ -6552,7 +6632,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid)
asid);
}
- if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC3) {
+ if (gaudi->hw_cap_initialized & HW_CAP_NIC3) {
gaudi_mmu_prepare_reg(hdev, mmNIC1_QM1_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC1_QM1_GLBL_NON_SECURE_PROPS_1,
@@ -6565,7 +6645,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid)
asid);
}
- if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC4) {
+ if (gaudi->hw_cap_initialized & HW_CAP_NIC4) {
gaudi_mmu_prepare_reg(hdev, mmNIC2_QM0_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC2_QM0_GLBL_NON_SECURE_PROPS_1,
@@ -6578,7 +6658,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid)
asid);
}
- if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC5) {
+ if (gaudi->hw_cap_initialized & HW_CAP_NIC5) {
gaudi_mmu_prepare_reg(hdev, mmNIC2_QM1_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC2_QM1_GLBL_NON_SECURE_PROPS_1,
@@ -6591,7 +6671,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid)
asid);
}
- if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC6) {
+ if (gaudi->hw_cap_initialized & HW_CAP_NIC6) {
gaudi_mmu_prepare_reg(hdev, mmNIC3_QM0_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC3_QM0_GLBL_NON_SECURE_PROPS_1,
@@ -6604,7 +6684,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid)
asid);
}
- if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC7) {
+ if (gaudi->hw_cap_initialized & HW_CAP_NIC7) {
gaudi_mmu_prepare_reg(hdev, mmNIC3_QM1_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC3_QM1_GLBL_NON_SECURE_PROPS_1,
@@ -6617,7 +6697,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid)
asid);
}
- if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC8) {
+ if (gaudi->hw_cap_initialized & HW_CAP_NIC8) {
gaudi_mmu_prepare_reg(hdev, mmNIC4_QM0_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC4_QM0_GLBL_NON_SECURE_PROPS_1,
@@ -6630,7 +6710,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid)
asid);
}
- if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC9) {
+ if (gaudi->hw_cap_initialized & HW_CAP_NIC9) {
gaudi_mmu_prepare_reg(hdev, mmNIC4_QM1_GLBL_NON_SECURE_PROPS_0,
asid);
gaudi_mmu_prepare_reg(hdev, mmNIC4_QM1_GLBL_NON_SECURE_PROPS_1,
@@ -7044,14 +7124,158 @@ enable_clk_gate:
return rc;
}
+/*
+ * gaudi_queue_idx_dec - decrement queue index (pi/ci) and handle wrap
+ *
+ * @idx: the current pi/ci value
+ * @q_len: the queue length (power of 2)
+ *
+ * @return the cyclically decremented index
+ */
+static inline u32 gaudi_queue_idx_dec(u32 idx, u32 q_len)
+{
+ u32 mask = q_len - 1;
+
+ /*
+ * modular decrement is equivalent to adding (queue_size -1)
+ * later we take LSBs to make sure the value is in the
+ * range [0, queue_len - 1]
+ */
+ return (idx + q_len - 1) & mask;
+}
+
+/**
+ * gaudi_print_sw_config_stream_data - print SW config stream data
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @stream: the QMAN's stream
+ * @qman_base: base address of QMAN registers block
+ */
+static void gaudi_print_sw_config_stream_data(struct hl_device *hdev, u32 stream,
+ u64 qman_base)
+{
+ u64 cq_ptr_lo, cq_ptr_hi, cq_tsize, cq_ptr;
+ u32 cq_ptr_lo_off, size;
+
+ cq_ptr_lo_off = mmTPC0_QM_CQ_PTR_LO_1 - mmTPC0_QM_CQ_PTR_LO_0;
+
+ cq_ptr_lo = qman_base + (mmTPC0_QM_CQ_PTR_LO_0 - mmTPC0_QM_BASE) +
+ stream * cq_ptr_lo_off;
+ cq_ptr_hi = cq_ptr_lo +
+ (mmTPC0_QM_CQ_PTR_HI_0 - mmTPC0_QM_CQ_PTR_LO_0);
+ cq_tsize = cq_ptr_lo +
+ (mmTPC0_QM_CQ_TSIZE_0 - mmTPC0_QM_CQ_PTR_LO_0);
+
+ cq_ptr = (((u64) RREG32(cq_ptr_hi)) << 32) | RREG32(cq_ptr_lo);
+ size = RREG32(cq_tsize);
+ dev_info(hdev->dev, "stop on err: stream: %u, addr: %#llx, size: %x\n",
+ stream, cq_ptr, size);
+}
+
+/**
+ * gaudi_print_last_pqes_on_err - print last PQEs on error
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @qid_base: first QID of the QMAN (out of 4 streams)
+ * @stream: the QMAN's stream
+ * @qman_base: base address of QMAN registers block
+ * @pr_sw_conf: if true print the SW config stream data (CQ PTR and SIZE)
+ */
+static void gaudi_print_last_pqes_on_err(struct hl_device *hdev, u32 qid_base,
+ u32 stream, u64 qman_base,
+ bool pr_sw_conf)
+{
+ u32 ci, qm_ci_stream_off, queue_len;
+ struct hl_hw_queue *q;
+ u64 pq_ci;
+ int i;
+
+ q = &hdev->kernel_queues[qid_base + stream];
+
+ qm_ci_stream_off = mmTPC0_QM_PQ_CI_1 - mmTPC0_QM_PQ_CI_0;
+ pq_ci = qman_base + (mmTPC0_QM_PQ_CI_0 - mmTPC0_QM_BASE) +
+ stream * qm_ci_stream_off;
+
+ queue_len = (q->queue_type == QUEUE_TYPE_INT) ?
+ q->int_queue_len : HL_QUEUE_LENGTH;
+
+ hdev->asic_funcs->hw_queues_lock(hdev);
+
+ if (pr_sw_conf)
+ gaudi_print_sw_config_stream_data(hdev, stream, qman_base);
+
+ ci = RREG32(pq_ci);
+
+ /* we should start printing form ci -1 */
+ ci = gaudi_queue_idx_dec(ci, queue_len);
+
+ for (i = 0; i < PQ_FETCHER_CACHE_SIZE; i++) {
+ struct hl_bd *bd;
+ u64 addr;
+ u32 len;
+
+ bd = q->kernel_address;
+ bd += ci;
+
+ len = le32_to_cpu(bd->len);
+ /* len 0 means uninitialized entry- break */
+ if (!len)
+ break;
+
+ addr = le64_to_cpu(bd->ptr);
+
+ dev_info(hdev->dev, "stop on err PQE(stream %u): ci: %u, addr: %#llx, size: %x\n",
+ stream, ci, addr, len);
+
+ /* get previous ci, wrap if needed */
+ ci = gaudi_queue_idx_dec(ci, queue_len);
+ }
+
+ hdev->asic_funcs->hw_queues_unlock(hdev);
+}
+
+/**
+ * print_qman_data_on_err - extract QMAN data on error
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @qid_base: first QID of the QMAN (out of 4 streams)
+ * @stream: the QMAN's stream
+ * @qman_base: base address of QMAN registers block
+ *
+ * This function attempt to exatract as much data as possible on QMAN error.
+ * On upper CP print the SW config stream data and last 8 PQEs.
+ * On lower CP print SW config data and last PQEs of ALL 4 upper CPs
+ */
+static void print_qman_data_on_err(struct hl_device *hdev, u32 qid_base,
+ u32 stream, u64 qman_base)
+{
+ u32 i;
+
+ if (stream != QMAN_STREAMS) {
+ gaudi_print_last_pqes_on_err(hdev, qid_base, stream, qman_base,
+ true);
+ return;
+ }
+
+ gaudi_print_sw_config_stream_data(hdev, stream, qman_base);
+
+ for (i = 0; i < QMAN_STREAMS; i++)
+ gaudi_print_last_pqes_on_err(hdev, qid_base, i, qman_base,
+ false);
+}
+
static void gaudi_handle_qman_err_generic(struct hl_device *hdev,
const char *qm_name,
- u64 glbl_sts_addr,
- u64 arb_err_addr)
+ u64 qman_base,
+ u32 qid_base)
{
u32 i, j, glbl_sts_val, arb_err_val, glbl_sts_clr_val;
+ u64 glbl_sts_addr, arb_err_addr;
char reg_desc[32];
+ glbl_sts_addr = qman_base + (mmTPC0_QM_GLBL_STS1_0 - mmTPC0_QM_BASE);
+ arb_err_addr = qman_base + (mmTPC0_QM_ARB_ERR_CAUSE - mmTPC0_QM_BASE);
+
/* Iterate through all stream GLBL_STS1 registers + Lower CP */
for (i = 0 ; i < QMAN_STREAMS + 1 ; i++) {
glbl_sts_clr_val = 0;
@@ -7078,6 +7302,8 @@ static void gaudi_handle_qman_err_generic(struct hl_device *hdev,
/* Write 1 clear errors */
if (!hdev->stop_on_err)
WREG32(glbl_sts_addr + 4 * i, glbl_sts_clr_val);
+ else
+ print_qman_data_on_err(hdev, qid_base, i, qman_base);
}
arb_err_val = RREG32(arb_err_addr);
@@ -7222,90 +7448,88 @@ static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type,
static void gaudi_handle_qman_err(struct hl_device *hdev, u16 event_type)
{
- u64 glbl_sts_addr, arb_err_addr;
- u8 index;
+ u64 qman_base;
char desc[32];
+ u32 qid_base;
+ u8 index;
switch (event_type) {
case GAUDI_EVENT_TPC0_QM ... GAUDI_EVENT_TPC7_QM:
index = event_type - GAUDI_EVENT_TPC0_QM;
- glbl_sts_addr =
- mmTPC0_QM_GLBL_STS1_0 + index * TPC_QMAN_OFFSET;
- arb_err_addr =
- mmTPC0_QM_ARB_ERR_CAUSE + index * TPC_QMAN_OFFSET;
+ qid_base = GAUDI_QUEUE_ID_TPC_0_0 + index * QMAN_STREAMS;
+ qman_base = mmTPC0_QM_BASE + index * TPC_QMAN_OFFSET;
snprintf(desc, ARRAY_SIZE(desc), "%s%d", "TPC_QM", index);
break;
case GAUDI_EVENT_MME0_QM ... GAUDI_EVENT_MME2_QM:
index = event_type - GAUDI_EVENT_MME0_QM;
- glbl_sts_addr =
- mmMME0_QM_GLBL_STS1_0 + index * MME_QMAN_OFFSET;
- arb_err_addr =
- mmMME0_QM_ARB_ERR_CAUSE + index * MME_QMAN_OFFSET;
+ qid_base = GAUDI_QUEUE_ID_MME_0_0 + index * QMAN_STREAMS;
+ qman_base = mmMME0_QM_BASE + index * MME_QMAN_OFFSET;
snprintf(desc, ARRAY_SIZE(desc), "%s%d", "MME_QM", index);
break;
case GAUDI_EVENT_DMA0_QM ... GAUDI_EVENT_DMA7_QM:
index = event_type - GAUDI_EVENT_DMA0_QM;
- glbl_sts_addr =
- mmDMA0_QM_GLBL_STS1_0 + index * DMA_QMAN_OFFSET;
- arb_err_addr =
- mmDMA0_QM_ARB_ERR_CAUSE + index * DMA_QMAN_OFFSET;
+ qid_base = GAUDI_QUEUE_ID_DMA_0_0 + index * QMAN_STREAMS;
+ /* skip GAUDI_QUEUE_ID_CPU_PQ if necessary */
+ if (index > 1)
+ qid_base++;
+ qman_base = mmDMA0_QM_BASE + index * DMA_QMAN_OFFSET;
snprintf(desc, ARRAY_SIZE(desc), "%s%d", "DMA_QM", index);
break;
case GAUDI_EVENT_NIC0_QM0:
- glbl_sts_addr = mmNIC0_QM0_GLBL_STS1_0;
- arb_err_addr = mmNIC0_QM0_ARB_ERR_CAUSE;
+ qid_base = GAUDI_QUEUE_ID_NIC_0_0;
+ qman_base = mmNIC0_QM0_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC0_QM0");
break;
case GAUDI_EVENT_NIC0_QM1:
- glbl_sts_addr = mmNIC0_QM1_GLBL_STS1_0;
- arb_err_addr = mmNIC0_QM1_ARB_ERR_CAUSE;
+ qid_base = GAUDI_QUEUE_ID_NIC_1_0;
+ qman_base = mmNIC0_QM1_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC0_QM1");
break;
case GAUDI_EVENT_NIC1_QM0:
- glbl_sts_addr = mmNIC1_QM0_GLBL_STS1_0;
- arb_err_addr = mmNIC1_QM0_ARB_ERR_CAUSE;
+ qid_base = GAUDI_QUEUE_ID_NIC_2_0;
+ qman_base = mmNIC1_QM0_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC1_QM0");
break;
case GAUDI_EVENT_NIC1_QM1:
- glbl_sts_addr = mmNIC1_QM1_GLBL_STS1_0;
- arb_err_addr = mmNIC1_QM1_ARB_ERR_CAUSE;
+ qid_base = GAUDI_QUEUE_ID_NIC_3_0;
+ qman_base = mmNIC1_QM1_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC1_QM1");
break;
case GAUDI_EVENT_NIC2_QM0:
- glbl_sts_addr = mmNIC2_QM0_GLBL_STS1_0;
- arb_err_addr = mmNIC2_QM0_ARB_ERR_CAUSE;
+ qid_base = GAUDI_QUEUE_ID_NIC_4_0;
+ qman_base = mmNIC2_QM0_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC2_QM0");
break;
case GAUDI_EVENT_NIC2_QM1:
- glbl_sts_addr = mmNIC2_QM1_GLBL_STS1_0;
- arb_err_addr = mmNIC2_QM1_ARB_ERR_CAUSE;
+ qid_base = GAUDI_QUEUE_ID_NIC_5_0;
+ qman_base = mmNIC2_QM1_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC2_QM1");
break;
case GAUDI_EVENT_NIC3_QM0:
- glbl_sts_addr = mmNIC3_QM0_GLBL_STS1_0;
- arb_err_addr = mmNIC3_QM0_ARB_ERR_CAUSE;
+ qid_base = GAUDI_QUEUE_ID_NIC_6_0;
+ qman_base = mmNIC3_QM0_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC3_QM0");
break;
case GAUDI_EVENT_NIC3_QM1:
- glbl_sts_addr = mmNIC3_QM1_GLBL_STS1_0;
- arb_err_addr = mmNIC3_QM1_ARB_ERR_CAUSE;
+ qid_base = GAUDI_QUEUE_ID_NIC_7_0;
+ qman_base = mmNIC3_QM1_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC3_QM1");
break;
case GAUDI_EVENT_NIC4_QM0:
- glbl_sts_addr = mmNIC4_QM0_GLBL_STS1_0;
- arb_err_addr = mmNIC4_QM0_ARB_ERR_CAUSE;
+ qid_base = GAUDI_QUEUE_ID_NIC_8_0;
+ qman_base = mmNIC4_QM0_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC4_QM0");
break;
case GAUDI_EVENT_NIC4_QM1:
- glbl_sts_addr = mmNIC4_QM1_GLBL_STS1_0;
- arb_err_addr = mmNIC4_QM1_ARB_ERR_CAUSE;
+ qid_base = GAUDI_QUEUE_ID_NIC_9_0;
+ qman_base = mmNIC4_QM1_BASE;
snprintf(desc, ARRAY_SIZE(desc), "NIC4_QM1");
break;
default:
return;
}
- gaudi_handle_qman_err_generic(hdev, desc, glbl_sts_addr, arb_err_addr);
+ gaudi_handle_qman_err_generic(hdev, desc, qman_base, qid_base);
}
static void gaudi_print_irq_info(struct hl_device *hdev, u16 event_type,
@@ -7332,6 +7556,16 @@ static void gaudi_print_out_of_sync_info(struct hl_device *hdev,
sync_err->pi, sync_err->ci, q->pi, atomic_read(&q->ci));
}
+static void gaudi_print_fw_alive_info(struct hl_device *hdev,
+ struct hl_eq_fw_alive *fw_alive)
+{
+ dev_err(hdev->dev,
+ "FW alive report: severity=%s, process_id=%u, thread_id=%u, uptime=%llu seconds\n",
+ (fw_alive->severity == FW_ALIVE_SEVERITY_MINOR) ?
+ "Minor" : "Critical", fw_alive->process_id,
+ fw_alive->thread_id, fw_alive->uptime_seconds);
+}
+
static int gaudi_soft_reset_late_init(struct hl_device *hdev)
{
struct gaudi_device *gaudi = hdev->asic_specific;
@@ -7346,11 +7580,10 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device,
struct hl_eq_hbm_ecc_data *hbm_ecc_data)
{
u32 base, val, val2, wr_par, rd_par, ca_par, derr, serr, type, ch;
- int err = 0;
+ int rc = 0;
- if (hdev->asic_prop.fw_security_status_valid &&
- (hdev->asic_prop.fw_app_security_map &
- CPU_BOOT_DEV_STS0_HBM_ECC_EN)) {
+ if (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 &
+ CPU_BOOT_DEV_STS0_HBM_ECC_EN) {
if (!hbm_ecc_data) {
dev_err(hdev->dev, "No FW ECC data");
return 0;
@@ -7379,13 +7612,10 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device,
device, ch, hbm_ecc_data->first_addr, type,
hbm_ecc_data->sec_cont_cnt, hbm_ecc_data->sec_cnt,
hbm_ecc_data->dec_cnt);
-
- err = 1;
-
return 0;
}
- if (!hdev->asic_prop.fw_security_disabled) {
+ if (hdev->asic_prop.fw_security_enabled) {
dev_info(hdev->dev, "Cannot access MC regs for ECC data while security is enabled\n");
return 0;
}
@@ -7395,7 +7625,7 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device,
val = RREG32_MASK(base + ch * 0x1000 + 0x06C, 0x0000FFFF);
val = (val & 0xFF) | ((val >> 8) & 0xFF);
if (val) {
- err = 1;
+ rc = -EIO;
dev_err(hdev->dev,
"HBM%d pc%d interrupts info: WR_PAR=%d, RD_PAR=%d, CA_PAR=%d, SERR=%d, DERR=%d\n",
device, ch * 2, val & 0x1, (val >> 1) & 0x1,
@@ -7415,7 +7645,7 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device,
val = RREG32_MASK(base + ch * 0x1000 + 0x07C, 0x0000FFFF);
val = (val & 0xFF) | ((val >> 8) & 0xFF);
if (val) {
- err = 1;
+ rc = -EIO;
dev_err(hdev->dev,
"HBM%d pc%d interrupts info: WR_PAR=%d, RD_PAR=%d, CA_PAR=%d, SERR=%d, DERR=%d\n",
device, ch * 2 + 1, val & 0x1, (val >> 1) & 0x1,
@@ -7444,7 +7674,7 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device,
val = RREG32(base + 0x8F30);
val2 = RREG32(base + 0x8F34);
if (val | val2) {
- err = 1;
+ rc = -EIO;
dev_err(hdev->dev,
"HBM %d MC SRAM SERR info: Reg 0x8F30=0x%x, Reg 0x8F34=0x%x\n",
device, val, val2);
@@ -7452,13 +7682,13 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device,
val = RREG32(base + 0x8F40);
val2 = RREG32(base + 0x8F44);
if (val | val2) {
- err = 1;
+ rc = -EIO;
dev_err(hdev->dev,
"HBM %d MC SRAM DERR info: Reg 0x8F40=0x%x, Reg 0x8F44=0x%x\n",
device, val, val2);
}
- return err;
+ return rc;
}
static int gaudi_hbm_event_to_dev(u16 hbm_event_type)
@@ -7604,6 +7834,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev,
case GAUDI_EVENT_DMA_IF0_DERR ... GAUDI_EVENT_DMA_IF3_DERR:
case GAUDI_EVENT_HBM_0_DERR ... GAUDI_EVENT_HBM_3_DERR:
case GAUDI_EVENT_MMU_DERR:
+ case GAUDI_EVENT_NIC0_CS_DBG_DERR ... GAUDI_EVENT_NIC4_CS_DBG_DERR:
gaudi_print_irq_info(hdev, event_type, true);
gaudi_handle_ecc_event(hdev, event_type, &eq_entry->ecc_data);
goto reset_device;
@@ -7786,6 +8017,11 @@ static void gaudi_handle_eqe(struct hl_device *hdev,
gaudi_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err);
goto reset_device;
+ case GAUDI_EVENT_FW_ALIVE_S:
+ gaudi_print_irq_info(hdev, event_type, false);
+ gaudi_print_fw_alive_info(hdev, &eq_entry->fw_alive);
+ goto reset_device;
+
default:
dev_err(hdev->dev, "Received invalid H/W interrupt %d\n",
event_type);
@@ -7856,52 +8092,13 @@ static int gaudi_mmu_invalidate_cache(struct hl_device *hdev, bool is_hard,
}
static int gaudi_mmu_invalidate_cache_range(struct hl_device *hdev,
- bool is_hard, u32 asid, u64 va, u64 size)
+ bool is_hard, u32 flags,
+ u32 asid, u64 va, u64 size)
{
- struct gaudi_device *gaudi = hdev->asic_specific;
- u32 status, timeout_usec;
- u32 inv_data;
- u32 pi;
- int rc;
-
- if (!(gaudi->hw_cap_initialized & HW_CAP_MMU) ||
- hdev->hard_reset_pending)
- return 0;
-
- if (hdev->pldm)
- timeout_usec = GAUDI_PLDM_MMU_TIMEOUT_USEC;
- else
- timeout_usec = MMU_CONFIG_TIMEOUT_USEC;
-
- /*
- * TODO: currently invalidate entire L0 & L1 as in regular hard
- * invalidation. Need to apply invalidation of specific cache
- * lines with mask of ASID & VA & size.
- * Note that L1 with be flushed entirely in any case.
+ /* Treat as invalidate all because there is no range invalidation
+ * in Gaudi
*/
-
- /* L0 & L1 invalidation */
- inv_data = RREG32(mmSTLB_CACHE_INV);
- /* PI is 8 bit */
- pi = ((inv_data & STLB_CACHE_INV_PRODUCER_INDEX_MASK) + 1) & 0xFF;
- WREG32(mmSTLB_CACHE_INV,
- (inv_data & STLB_CACHE_INV_INDEX_MASK_MASK) | pi);
-
- rc = hl_poll_timeout(
- hdev,
- mmSTLB_INV_CONSUMER_INDEX,
- status,
- status == pi,
- 1000,
- timeout_usec);
-
- if (rc) {
- dev_err_ratelimited(hdev->dev,
- "MMU cache invalidation timeout\n");
- hl_device_reset(hdev, HL_RESET_HARD);
- }
-
- return rc;
+ return hdev->asic_funcs->mmu_invalidate_cache(hdev, is_hard, flags);
}
static int gaudi_mmu_update_asid_hop0_addr(struct hl_device *hdev,
@@ -7956,7 +8153,9 @@ static int gaudi_cpucp_info_get(struct hl_device *hdev)
if (!(gaudi->hw_cap_initialized & HW_CAP_CPU_Q))
return 0;
- rc = hl_fw_cpucp_handshake(hdev, mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0);
+ rc = hl_fw_cpucp_handshake(hdev, mmCPU_BOOT_DEV_STS0,
+ mmCPU_BOOT_DEV_STS1, mmCPU_BOOT_ERR0,
+ mmCPU_BOOT_ERR1);
if (rc)
return rc;
@@ -8077,7 +8276,7 @@ static bool gaudi_is_device_idle(struct hl_device *hdev, u64 *mask_arr,
for (i = 0 ; i < (NIC_NUMBER_OF_ENGINES / 2) ; i++) {
offset = i * NIC_MACRO_QMAN_OFFSET;
port = 2 * i;
- if (hdev->nic_ports_mask & BIT(port)) {
+ if (gaudi->hw_cap_initialized & BIT(HW_CAP_NIC_SHIFT + port)) {
qm_glbl_sts0 = RREG32(mmNIC0_QM0_GLBL_STS0 + offset);
qm_cgm_sts = RREG32(mmNIC0_QM0_CGM_STS + offset);
is_eng_idle = IS_QM_IDLE(qm_glbl_sts0, qm_cgm_sts);
@@ -8092,7 +8291,7 @@ static bool gaudi_is_device_idle(struct hl_device *hdev, u64 *mask_arr,
}
port = 2 * i + 1;
- if (hdev->nic_ports_mask & BIT(port)) {
+ if (gaudi->hw_cap_initialized & BIT(HW_CAP_NIC_SHIFT + port)) {
qm_glbl_sts0 = RREG32(mmNIC0_QM1_GLBL_STS0 + offset);
qm_cgm_sts = RREG32(mmNIC0_QM1_CGM_STS + offset);
is_eng_idle = IS_QM_IDLE(qm_glbl_sts0, qm_cgm_sts);
@@ -8306,8 +8505,10 @@ static int gaudi_internal_cb_pool_init(struct hl_device *hdev,
HL_VA_RANGE_TYPE_HOST, HOST_SPACE_INTERNAL_CB_SZ,
HL_MMU_VA_ALIGNMENT_NOT_NEEDED);
- if (!hdev->internal_cb_va_base)
+ if (!hdev->internal_cb_va_base) {
+ rc = -ENOMEM;
goto destroy_internal_cb_pool;
+ }
mutex_lock(&ctx->mmu_lock);
rc = hl_mmu_map_contiguous(ctx, hdev->internal_cb_va_base,
@@ -8749,7 +8950,14 @@ static int gaudi_block_mmap(struct hl_device *hdev,
static void gaudi_enable_events_from_fw(struct hl_device *hdev)
{
- WREG32(mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR, GAUDI_EVENT_INTS_REGISTER);
+ struct cpu_dyn_regs *dyn_regs =
+ &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs;
+ u32 irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ?
+ mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR :
+ le32_to_cpu(dyn_regs->gic_host_ints_irq);
+
+ WREG32(irq_handler_offset,
+ gaudi_irq_map_table[GAUDI_EVENT_INTS_REGISTER].cpu_id);
}
static int gaudi_map_pll_idx_to_fw_idx(u32 pll_idx)
@@ -8834,7 +9042,6 @@ static const struct hl_asic_funcs gaudi_funcs = {
.ctx_fini = gaudi_ctx_fini,
.get_clk_rate = gaudi_get_clk_rate,
.get_queue_id_for_cq = gaudi_get_queue_id_for_cq,
- .read_device_fw_version = gaudi_read_device_fw_version,
.load_firmware_to_device = gaudi_load_firmware_to_device,
.load_boot_fit_to_device = gaudi_load_boot_fit_to_device,
.get_signal_cb_size = gaudi_get_signal_cb_size,
@@ -8853,7 +9060,9 @@ static const struct hl_asic_funcs gaudi_funcs = {
.get_hw_block_id = gaudi_get_hw_block_id,
.hw_block_mmap = gaudi_block_mmap,
.enable_events_from_fw = gaudi_enable_events_from_fw,
- .map_pll_idx_to_fw_idx = gaudi_map_pll_idx_to_fw_idx
+ .map_pll_idx_to_fw_idx = gaudi_map_pll_idx_to_fw_idx,
+ .init_firmware_loader = gaudi_init_firmware_loader,
+ .init_cpu_scrambler_dram = gaudi_init_scrambler_hbm
};
/**
diff --git a/drivers/misc/habanalabs/gaudi/gaudiP.h b/drivers/misc/habanalabs/gaudi/gaudiP.h
index 5929be81ec23..957bf3720f70 100644
--- a/drivers/misc/habanalabs/gaudi/gaudiP.h
+++ b/drivers/misc/habanalabs/gaudi/gaudiP.h
@@ -82,6 +82,7 @@
QMAN_STREAMS)
#define QMAN_STREAMS 4
+#define PQ_FETCHER_CACHE_SIZE 8
#define DMA_QMAN_OFFSET (mmDMA1_QM_BASE - mmDMA0_QM_BASE)
#define TPC_QMAN_OFFSET (mmTPC1_QM_BASE - mmTPC0_QM_BASE)
diff --git a/drivers/misc/habanalabs/gaudi/gaudi_coresight.c b/drivers/misc/habanalabs/gaudi/gaudi_coresight.c
index 6e56fa1c6c69..c2a27ed1c4d1 100644
--- a/drivers/misc/habanalabs/gaudi/gaudi_coresight.c
+++ b/drivers/misc/habanalabs/gaudi/gaudi_coresight.c
@@ -424,7 +424,7 @@ static int gaudi_config_stm(struct hl_device *hdev,
if (frequency == 0)
frequency = input->frequency;
WREG32(base_reg + 0xE8C, frequency);
- WREG32(base_reg + 0xE90, 0x7FF);
+ WREG32(base_reg + 0xE90, 0x1F00);
/* SW-2176 - SW WA for HW bug */
if ((CFG_BASE + base_reg) >= mmDMA_CH_0_CS_STM_BASE &&
@@ -434,7 +434,7 @@ static int gaudi_config_stm(struct hl_device *hdev,
WREG32(base_reg + 0xE6C, 0x0);
}
- WREG32(base_reg + 0xE80, 0x27 | (input->id << 16));
+ WREG32(base_reg + 0xE80, 0x23 | (input->id << 16));
} else {
WREG32(base_reg + 0xE80, 4);
WREG32(base_reg + 0xD64, 0);
@@ -634,7 +634,7 @@ static int gaudi_config_etr(struct hl_device *hdev,
WREG32(mmPSOC_ETR_BUFWM, 0x3FFC);
WREG32(mmPSOC_ETR_RSZ, input->buffer_size);
WREG32(mmPSOC_ETR_MODE, input->sink_mode);
- if (hdev->asic_prop.fw_security_disabled) {
+ if (!hdev->asic_prop.fw_security_enabled) {
/* make ETR not privileged */
val = FIELD_PREP(
PSOC_ETR_AXICTL_PROTCTRLBIT0_MASK, 0);
diff --git a/drivers/misc/habanalabs/gaudi/gaudi_security.c b/drivers/misc/habanalabs/gaudi/gaudi_security.c
index 9a706c5980ef..0d3240f1f7d7 100644
--- a/drivers/misc/habanalabs/gaudi/gaudi_security.c
+++ b/drivers/misc/habanalabs/gaudi/gaudi_security.c
@@ -1448,7 +1448,7 @@ static void gaudi_init_dma_protection_bits(struct hl_device *hdev)
u32 pb_addr, mask;
u8 word_offset;
- if (hdev->asic_prop.fw_security_disabled) {
+ if (!hdev->asic_prop.fw_security_enabled) {
gaudi_pb_set_block(hdev, mmDMA_IF_E_S_BASE);
gaudi_pb_set_block(hdev, mmDMA_IF_E_S_DOWN_CH0_BASE);
gaudi_pb_set_block(hdev, mmDMA_IF_E_S_DOWN_CH1_BASE);
@@ -9135,7 +9135,7 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev)
u32 pb_addr, mask;
u8 word_offset;
- if (hdev->asic_prop.fw_security_disabled) {
+ if (!hdev->asic_prop.fw_security_enabled) {
gaudi_pb_set_block(hdev, mmTPC0_E2E_CRED_BASE);
gaudi_pb_set_block(hdev, mmTPC1_E2E_CRED_BASE);
gaudi_pb_set_block(hdev, mmTPC2_E2E_CRED_BASE);
@@ -12818,7 +12818,7 @@ static void gaudi_init_protection_bits(struct hl_device *hdev)
* secured
*/
- if (hdev->asic_prop.fw_security_disabled) {
+ if (!hdev->asic_prop.fw_security_enabled) {
gaudi_pb_set_block(hdev, mmIF_E_PLL_BASE);
gaudi_pb_set_block(hdev, mmMESH_W_PLL_BASE);
gaudi_pb_set_block(hdev, mmSRAM_W_PLL_BASE);
@@ -13023,7 +13023,7 @@ void gaudi_init_security(struct hl_device *hdev)
* property configuration of MME SBAB and ACC to be non-privileged and
* non-secured
*/
- if (hdev->asic_prop.fw_security_disabled) {
+ if (!hdev->asic_prop.fw_security_enabled) {
WREG32(mmMME0_SBAB_PROT, 0x2);
WREG32(mmMME0_ACC_PROT, 0x2);
WREG32(mmMME1_SBAB_PROT, 0x2);
@@ -13032,11 +13032,12 @@ void gaudi_init_security(struct hl_device *hdev)
WREG32(mmMME2_ACC_PROT, 0x2);
WREG32(mmMME3_SBAB_PROT, 0x2);
WREG32(mmMME3_ACC_PROT, 0x2);
- }
- /* On RAZWI, 0 will be returned from RR and 0xBABA0BAD from PB */
- if (hdev->asic_prop.fw_security_disabled)
+ /*
+ * On RAZWI, 0 will be returned from RR and 0xBABA0BAD from PB
+ */
WREG32(0xC01B28, 0x1);
+ }
gaudi_init_range_registers_lbw(hdev);
diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c
index e0ad2a269779..755e08cf2ecc 100644
--- a/drivers/misc/habanalabs/goya/goya.c
+++ b/drivers/misc/habanalabs/goya/goya.c
@@ -87,6 +87,7 @@
#define GOYA_PLDM_QMAN0_TIMEOUT_USEC (HL_DEVICE_TIMEOUT_USEC * 30)
#define GOYA_BOOT_FIT_REQ_TIMEOUT_USEC 1000000 /* 1s */
#define GOYA_MSG_TO_CPU_TIMEOUT_USEC 4000000 /* 4s */
+#define GOYA_WAIT_FOR_BL_TIMEOUT_USEC 15000000 /* 15s */
#define GOYA_QMAN0_FENCE_VAL 0xD169B243
@@ -354,7 +355,7 @@ 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);
-int goya_get_fixed_properties(struct hl_device *hdev)
+int goya_set_fixed_properties(struct hl_device *hdev)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
int i;
@@ -460,8 +461,10 @@ int goya_get_fixed_properties(struct hl_device *hdev)
for (i = 0 ; i < HL_MAX_DCORES ; i++)
prop->first_available_cq[i] = USHRT_MAX;
- prop->fw_security_status_valid = false;
+ prop->fw_cpu_boot_dev_sts0_valid = false;
+ prop->fw_cpu_boot_dev_sts1_valid = false;
prop->hard_reset_done_by_fw = false;
+ prop->gic_interrupts_enable = true;
return 0;
}
@@ -531,10 +534,8 @@ static int goya_init_iatu(struct hl_device *hdev)
struct hl_outbound_pci_region outbound_region;
int rc;
- if (hdev->asic_prop.iatu_done_by_fw) {
- hdev->asic_funcs->set_dma_mask_from_fw(hdev);
+ if (hdev->asic_prop.iatu_done_by_fw)
return 0;
- }
/* Inbound Region 0 - Bar 0 - Point to SRAM and CFG */
inbound_region.mode = PCI_BAR_MATCH_MODE;
@@ -586,7 +587,7 @@ static int goya_early_init(struct hl_device *hdev)
u32 fw_boot_status, val;
int rc;
- rc = goya_get_fixed_properties(hdev);
+ rc = goya_set_fixed_properties(hdev);
if (rc) {
dev_err(hdev->dev, "Failed to get fixed properties\n");
return rc;
@@ -618,7 +619,7 @@ static int goya_early_init(struct hl_device *hdev)
prop->dram_pci_bar_size = pci_resource_len(pdev, DDR_BAR_ID);
/* If FW security is enabled at this point it means no access to ELBI */
- if (!hdev->asic_prop.fw_security_disabled) {
+ if (hdev->asic_prop.fw_security_enabled) {
hdev->asic_prop.iatu_done_by_fw = true;
goto pci_init;
}
@@ -642,8 +643,10 @@ pci_init:
* version to determine whether we run with a security-enabled firmware
*/
rc = hl_fw_read_preboot_status(hdev, mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS,
- mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0,
- GOYA_BOOT_FIT_REQ_TIMEOUT_USEC);
+ mmCPU_BOOT_DEV_STS0,
+ mmCPU_BOOT_DEV_STS1, mmCPU_BOOT_ERR0,
+ mmCPU_BOOT_ERR1,
+ GOYA_BOOT_FIT_REQ_TIMEOUT_USEC);
if (rc) {
if (hdev->reset_on_preboot_fail)
hdev->asic_funcs->hw_fini(hdev, true);
@@ -723,7 +726,15 @@ static void goya_fetch_psoc_frequency(struct hl_device *hdev)
u16 pll_freq_arr[HL_PLL_NUM_OUTPUTS], freq;
int rc;
- if (hdev->asic_prop.fw_security_disabled) {
+ if (hdev->asic_prop.fw_security_enabled) {
+ rc = hl_fw_cpucp_pll_info_get(hdev, HL_GOYA_PCI_PLL,
+ pll_freq_arr);
+
+ if (rc)
+ return;
+
+ freq = pll_freq_arr[1];
+ } else {
div_fctr = RREG32(mmPSOC_PCI_PLL_DIV_FACTOR_1);
div_sel = RREG32(mmPSOC_PCI_PLL_DIV_SEL_1);
nr = RREG32(mmPSOC_PCI_PLL_NR);
@@ -750,14 +761,6 @@ static void goya_fetch_psoc_frequency(struct hl_device *hdev)
div_sel);
freq = 0;
}
- } else {
- rc = hl_fw_cpucp_pll_info_get(hdev, HL_GOYA_PCI_PLL,
- pll_freq_arr);
-
- if (rc)
- return;
-
- freq = pll_freq_arr[1];
}
prop->psoc_timestamp_frequency = freq;
@@ -849,6 +852,39 @@ void goya_late_fini(struct hl_device *hdev)
hdev->hl_chip_info->info = NULL;
}
+static void goya_set_pci_memory_regions(struct hl_device *hdev)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ struct pci_mem_region *region;
+
+ /* CFG */
+ region = &hdev->pci_mem_region[PCI_REGION_CFG];
+ region->region_base = CFG_BASE;
+ region->region_size = CFG_SIZE;
+ region->offset_in_bar = CFG_BASE - SRAM_BASE_ADDR;
+ region->bar_size = CFG_BAR_SIZE;
+ region->bar_id = SRAM_CFG_BAR_ID;
+ region->used = 1;
+
+ /* SRAM */
+ region = &hdev->pci_mem_region[PCI_REGION_SRAM];
+ region->region_base = SRAM_BASE_ADDR;
+ region->region_size = SRAM_SIZE;
+ region->offset_in_bar = 0;
+ region->bar_size = CFG_BAR_SIZE;
+ region->bar_id = SRAM_CFG_BAR_ID;
+ region->used = 1;
+
+ /* DRAM */
+ region = &hdev->pci_mem_region[PCI_REGION_DRAM];
+ region->region_base = DRAM_PHYS_BASE;
+ region->region_size = hdev->asic_prop.dram_size;
+ region->offset_in_bar = 0;
+ region->bar_size = prop->dram_pci_bar_size;
+ region->bar_id = DDR_BAR_ID;
+ region->used = 1;
+}
+
/*
* goya_sw_init - Goya software initialization code
*
@@ -918,6 +954,9 @@ static int goya_sw_init(struct hl_device *hdev)
spin_lock_init(&goya->hw_queues_lock);
hdev->supports_coresight = true;
hdev->supports_soft_reset = true;
+ hdev->allow_external_soft_reset = true;
+
+ goya_set_pci_memory_regions(hdev);
return 0;
@@ -1263,8 +1302,11 @@ int goya_init_cpu_queues(struct hl_device *hdev)
}
/* update FW application security bits */
- if (prop->fw_security_status_valid)
- prop->fw_app_security_map = RREG32(mmCPU_BOOT_DEV_STS0);
+ if (prop->fw_cpu_boot_dev_sts0_valid)
+ prop->fw_app_cpu_boot_dev_sts0 = RREG32(mmCPU_BOOT_DEV_STS0);
+
+ if (prop->fw_cpu_boot_dev_sts1_valid)
+ prop->fw_app_cpu_boot_dev_sts1 = RREG32(mmCPU_BOOT_DEV_STS1);
goya->hw_cap_initialized |= HW_CAP_CPU_Q;
return 0;
@@ -2402,47 +2444,67 @@ static int goya_load_boot_fit_to_device(struct hl_device *hdev)
return hl_fw_load_fw_to_device(hdev, GOYA_BOOT_FIT_FILE, dst, 0, 0);
}
-/*
- * FW component passes an offset from SRAM_BASE_ADDR in SCRATCHPAD_xx.
- * The version string should be located by that offset.
- */
-static int goya_read_device_fw_version(struct hl_device *hdev,
- enum hl_fw_component fwc)
-{
- const char *name;
- u32 ver_off;
- char *dest;
-
- switch (fwc) {
- case FW_COMP_UBOOT:
- ver_off = RREG32(mmUBOOT_VER_OFFSET);
- dest = hdev->asic_prop.uboot_ver;
- name = "U-Boot";
- break;
- case FW_COMP_PREBOOT:
- ver_off = RREG32(mmPREBOOT_VER_OFFSET);
- dest = hdev->asic_prop.preboot_ver;
- name = "Preboot";
- break;
- default:
- dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc);
- return -EIO;
- }
+static void goya_init_dynamic_firmware_loader(struct hl_device *hdev)
+{
+ struct dynamic_fw_load_mgr *dynamic_loader;
+ struct cpu_dyn_regs *dyn_regs;
- ver_off &= ~((u32)SRAM_BASE_ADDR);
+ dynamic_loader = &hdev->fw_loader.dynamic_loader;
- if (ver_off < SRAM_SIZE - VERSION_MAX_LEN) {
- memcpy_fromio(dest, hdev->pcie_bar[SRAM_CFG_BAR_ID] + ver_off,
- VERSION_MAX_LEN);
- } else {
- dev_err(hdev->dev, "%s version offset (0x%x) is above SRAM\n",
- name, ver_off);
- strcpy(dest, "unavailable");
+ /*
+ * here we update initial values for few specific dynamic regs (as
+ * before reading the first descriptor from FW those value has to be
+ * hard-coded) in later stages of the protocol those values will be
+ * updated automatically by reading the FW descriptor so data there
+ * will always be up-to-date
+ */
+ dyn_regs = &dynamic_loader->comm_desc.cpu_dyn_regs;
+ dyn_regs->kmd_msg_to_cpu =
+ cpu_to_le32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU);
+ dyn_regs->cpu_cmd_status_to_host =
+ cpu_to_le32(mmCPU_CMD_STATUS_TO_HOST);
- return -EIO;
- }
+ dynamic_loader->wait_for_bl_timeout = GOYA_WAIT_FOR_BL_TIMEOUT_USEC;
+}
- return 0;
+static void goya_init_static_firmware_loader(struct hl_device *hdev)
+{
+ struct static_fw_load_mgr *static_loader;
+
+ static_loader = &hdev->fw_loader.static_loader;
+
+ static_loader->preboot_version_max_off = SRAM_SIZE - VERSION_MAX_LEN;
+ static_loader->boot_fit_version_max_off = SRAM_SIZE - VERSION_MAX_LEN;
+ static_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU;
+ static_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST;
+ static_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS;
+ static_loader->cpu_boot_dev_status0_reg = mmCPU_BOOT_DEV_STS0;
+ static_loader->cpu_boot_dev_status1_reg = mmCPU_BOOT_DEV_STS1;
+ static_loader->boot_err0_reg = mmCPU_BOOT_ERR0;
+ static_loader->boot_err1_reg = mmCPU_BOOT_ERR1;
+ static_loader->preboot_version_offset_reg = mmPREBOOT_VER_OFFSET;
+ static_loader->boot_fit_version_offset_reg = mmUBOOT_VER_OFFSET;
+ static_loader->sram_offset_mask = ~(lower_32_bits(SRAM_BASE_ADDR));
+}
+
+static void goya_init_firmware_loader(struct hl_device *hdev)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ struct fw_load_mgr *fw_loader = &hdev->fw_loader;
+
+ /* fill common fields */
+ fw_loader->boot_fit_img.image_name = GOYA_BOOT_FIT_FILE;
+ fw_loader->linux_img.image_name = GOYA_LINUX_FW_FILE;
+ fw_loader->cpu_timeout = GOYA_CPU_TIMEOUT_USEC;
+ fw_loader->boot_fit_timeout = GOYA_BOOT_FIT_REQ_TIMEOUT_USEC;
+ fw_loader->skip_bmc = false;
+ fw_loader->sram_bar_id = SRAM_CFG_BAR_ID;
+ fw_loader->dram_bar_id = DDR_BAR_ID;
+
+ if (prop->dynamic_fw_load)
+ goya_init_dynamic_firmware_loader(hdev);
+ else
+ goya_init_static_firmware_loader(hdev);
}
static int goya_init_cpu(struct hl_device *hdev)
@@ -2466,12 +2528,7 @@ static int goya_init_cpu(struct hl_device *hdev)
return -EIO;
}
- rc = hl_fw_init_cpu(hdev, mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS,
- mmPSOC_GLOBAL_CONF_UBOOT_MAGIC,
- mmCPU_CMD_STATUS_TO_HOST,
- mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0,
- false, GOYA_CPU_TIMEOUT_USEC,
- GOYA_BOOT_FIT_REQ_TIMEOUT_USEC);
+ rc = hl_fw_init_cpu(hdev);
if (rc)
return rc;
@@ -2881,7 +2938,7 @@ void *goya_get_int_queue_base(struct hl_device *hdev, u32 queue_id,
*dma_handle = hdev->asic_prop.sram_base_address;
- base = (void *) hdev->pcie_bar[SRAM_CFG_BAR_ID];
+ base = (__force void *) hdev->pcie_bar[SRAM_CFG_BAR_ID];
switch (queue_id) {
case GOYA_QUEUE_ID_MME:
@@ -3270,6 +3327,7 @@ already_pinned:
return 0;
unpin_memory:
+ list_del(&userptr->job_node);
hl_unpin_host_memory(hdev, userptr);
free_userptr:
kfree(userptr);
@@ -5169,54 +5227,13 @@ static int goya_mmu_invalidate_cache(struct hl_device *hdev, bool is_hard,
}
static int goya_mmu_invalidate_cache_range(struct hl_device *hdev,
- bool is_hard, u32 asid, u64 va, u64 size)
+ bool is_hard, u32 flags,
+ u32 asid, u64 va, u64 size)
{
- struct goya_device *goya = hdev->asic_specific;
- u32 status, timeout_usec, inv_data, pi;
- int rc;
-
- if (!(goya->hw_cap_initialized & HW_CAP_MMU) ||
- hdev->hard_reset_pending)
- return 0;
-
- /* no need in L1 only invalidation in Goya */
- if (!is_hard)
- return 0;
-
- if (hdev->pldm)
- timeout_usec = GOYA_PLDM_MMU_TIMEOUT_USEC;
- else
- timeout_usec = MMU_CONFIG_TIMEOUT_USEC;
-
- /*
- * TODO: currently invalidate entire L0 & L1 as in regular hard
- * invalidation. Need to apply invalidation of specific cache lines with
- * mask of ASID & VA & size.
- * Note that L1 with be flushed entirely in any case.
+ /* Treat as invalidate all because there is no range invalidation
+ * in Goya
*/
-
- /* L0 & L1 invalidation */
- inv_data = RREG32(mmSTLB_CACHE_INV);
- /* PI is 8 bit */
- pi = ((inv_data & STLB_CACHE_INV_PRODUCER_INDEX_MASK) + 1) & 0xFF;
- WREG32(mmSTLB_CACHE_INV,
- (inv_data & STLB_CACHE_INV_INDEX_MASK_MASK) | pi);
-
- rc = hl_poll_timeout(
- hdev,
- mmSTLB_INV_CONSUMER_INDEX,
- status,
- status == pi,
- 1000,
- timeout_usec);
-
- if (rc) {
- dev_err_ratelimited(hdev->dev,
- "MMU cache invalidation timeout\n");
- hl_device_reset(hdev, HL_RESET_HARD);
- }
-
- return rc;
+ return hdev->asic_funcs->mmu_invalidate_cache(hdev, is_hard, flags);
}
int goya_send_heartbeat(struct hl_device *hdev)
@@ -5239,7 +5256,9 @@ int goya_cpucp_info_get(struct hl_device *hdev)
if (!(goya->hw_cap_initialized & HW_CAP_CPU_Q))
return 0;
- rc = hl_fw_cpucp_handshake(hdev, mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0);
+ rc = hl_fw_cpucp_handshake(hdev, mmCPU_BOOT_DEV_STS0,
+ mmCPU_BOOT_DEV_STS1, mmCPU_BOOT_ERR0,
+ mmCPU_BOOT_ERR1);
if (rc)
return rc;
@@ -5385,6 +5404,11 @@ static int goya_get_eeprom_data(struct hl_device *hdev, void *data,
return hl_fw_get_eeprom_data(hdev, data, max_size);
}
+static void goya_cpu_init_scrambler_dram(struct hl_device *hdev)
+{
+
+}
+
static int goya_ctx_init(struct hl_ctx *ctx)
{
if (ctx->asid != HL_KERNEL_ASID_ID)
@@ -5565,7 +5589,6 @@ static const struct hl_asic_funcs goya_funcs = {
.ctx_fini = goya_ctx_fini,
.get_clk_rate = goya_get_clk_rate,
.get_queue_id_for_cq = goya_get_queue_id_for_cq,
- .read_device_fw_version = goya_read_device_fw_version,
.load_firmware_to_device = goya_load_firmware_to_device,
.load_boot_fit_to_device = goya_load_boot_fit_to_device,
.get_signal_cb_size = goya_get_signal_cb_size,
@@ -5584,7 +5607,9 @@ static const struct hl_asic_funcs goya_funcs = {
.get_hw_block_id = goya_get_hw_block_id,
.hw_block_mmap = goya_block_mmap,
.enable_events_from_fw = goya_enable_events_from_fw,
- .map_pll_idx_to_fw_idx = goya_map_pll_idx_to_fw_idx
+ .map_pll_idx_to_fw_idx = goya_map_pll_idx_to_fw_idx,
+ .init_firmware_loader = goya_init_firmware_loader,
+ .init_cpu_scrambler_dram = goya_cpu_init_scrambler_dram
};
/*
diff --git a/drivers/misc/habanalabs/goya/goyaP.h b/drivers/misc/habanalabs/goya/goyaP.h
index ef8c6c8b5c8d..0b05da614729 100644
--- a/drivers/misc/habanalabs/goya/goyaP.h
+++ b/drivers/misc/habanalabs/goya/goyaP.h
@@ -168,7 +168,7 @@ struct goya_device {
u8 device_cpu_mmu_mappings_done;
};
-int goya_get_fixed_properties(struct hl_device *hdev);
+int goya_set_fixed_properties(struct hl_device *hdev);
int goya_mmu_init(struct hl_device *hdev);
void goya_init_dma_qmans(struct hl_device *hdev);
void goya_init_mme_qmans(struct hl_device *hdev);
diff --git a/drivers/misc/habanalabs/goya/goya_coresight.c b/drivers/misc/habanalabs/goya/goya_coresight.c
index 6b7445cca580..c55c100fdd24 100644
--- a/drivers/misc/habanalabs/goya/goya_coresight.c
+++ b/drivers/misc/habanalabs/goya/goya_coresight.c
@@ -434,7 +434,7 @@ static int goya_config_etr(struct hl_device *hdev,
WREG32(mmPSOC_ETR_BUFWM, 0x3FFC);
WREG32(mmPSOC_ETR_RSZ, input->buffer_size);
WREG32(mmPSOC_ETR_MODE, input->sink_mode);
- if (hdev->asic_prop.fw_security_disabled) {
+ if (!hdev->asic_prop.fw_security_enabled) {
/* make ETR not privileged */
val = FIELD_PREP(PSOC_ETR_AXICTL_PROTCTRLBIT0_MASK, 0);
/* make ETR non-secured (inverted logic) */
diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/misc/habanalabs/include/common/cpucp_if.h
index 27cd0ba99aa3..80b1d5a9d9f1 100644
--- a/drivers/misc/habanalabs/include/common/cpucp_if.h
+++ b/drivers/misc/habanalabs/include/common/cpucp_if.h
@@ -84,6 +84,20 @@ struct hl_eq_sm_sei_data {
__u8 pad[3];
};
+enum hl_fw_alive_severity {
+ FW_ALIVE_SEVERITY_MINOR,
+ FW_ALIVE_SEVERITY_CRITICAL
+};
+
+struct hl_eq_fw_alive {
+ __le64 uptime_seconds;
+ __le32 process_id;
+ __le32 thread_id;
+ /* enum hl_fw_alive_severity */
+ __u8 severity;
+ __u8 pad[7];
+};
+
struct hl_eq_entry {
struct hl_eq_header hdr;
union {
@@ -91,6 +105,7 @@ struct hl_eq_entry {
struct hl_eq_hbm_ecc_data hbm_ecc_data;
struct hl_eq_sm_sei_data sm_sei_data;
struct cpucp_pkt_sync_err pkt_sync_err;
+ struct hl_eq_fw_alive fw_alive;
__le64 data[7];
};
};
@@ -103,11 +118,16 @@ struct hl_eq_entry {
#define EQ_CTL_EVENT_TYPE_SHIFT 16
#define EQ_CTL_EVENT_TYPE_MASK 0x03FF0000
+#define EQ_CTL_INDEX_SHIFT 0
+#define EQ_CTL_INDEX_MASK 0x0000FFFF
+
enum pq_init_status {
PQ_INIT_STATUS_NA = 0,
PQ_INIT_STATUS_READY_FOR_CP,
PQ_INIT_STATUS_READY_FOR_HOST,
- PQ_INIT_STATUS_READY_FOR_CP_SINGLE_MSI
+ PQ_INIT_STATUS_READY_FOR_CP_SINGLE_MSI,
+ PQ_INIT_STATUS_LEN_NOT_POWER_OF_TWO_ERR,
+ PQ_INIT_STATUS_ILLEGAL_Q_ADDR_ERR
};
/*
@@ -384,6 +404,20 @@ enum cpucp_packet_id {
#define CPUCP_PKT_RES_PLL_OUT3_SHIFT 48
#define CPUCP_PKT_RES_PLL_OUT3_MASK 0xFFFF000000000000ull
+#define CPUCP_PKT_VAL_PFC_IN1_SHIFT 0
+#define CPUCP_PKT_VAL_PFC_IN1_MASK 0x0000000000000001ull
+#define CPUCP_PKT_VAL_PFC_IN2_SHIFT 1
+#define CPUCP_PKT_VAL_PFC_IN2_MASK 0x000000000000001Eull
+
+#define CPUCP_PKT_VAL_LPBK_IN1_SHIFT 0
+#define CPUCP_PKT_VAL_LPBK_IN1_MASK 0x0000000000000001ull
+#define CPUCP_PKT_VAL_LPBK_IN2_SHIFT 1
+#define CPUCP_PKT_VAL_LPBK_IN2_MASK 0x000000000000001Eull
+
+/* heartbeat status bits */
+#define CPUCP_PKT_HB_STATUS_EQ_FAULT_SHIFT 0
+#define CPUCP_PKT_HB_STATUS_EQ_FAULT_MASK 0x00000001
+
struct cpucp_packet {
union {
__le64 value; /* For SET packets */
@@ -425,6 +459,12 @@ struct cpucp_packet {
/* For get CpuCP info/EEPROM data/NIC info */
__le32 data_max_size;
+
+ /*
+ * For any general status bitmask. Shall be used whenever the
+ * result cannot be used to hold general purpose data.
+ */
+ __le32 status_mask;
};
__le32 reserved;
@@ -629,6 +669,8 @@ struct cpucp_security_info {
* @card_name: card name that will be displayed in HWMON subsystem on the host
* @sec_info: security information
* @pll_map: Bit map of supported PLLs for current ASIC version.
+ * @mme_binning_mask: MME binning mask,
+ * (0 = functional, 1 = binned)
*/
struct cpucp_info {
struct cpucp_sensor sensors[CPUCP_MAX_SENSORS];
@@ -651,6 +693,7 @@ struct cpucp_info {
struct cpucp_security_info sec_info;
__le32 reserved6;
__u8 pll_map[PLL_MAP_LEN];
+ __le64 mme_binning_mask;
};
struct cpucp_mac_addr {
diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h
index e0a259e0495c..fa8a5ad2d438 100644
--- a/drivers/misc/habanalabs/include/common/hl_boot_if.h
+++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h
@@ -8,7 +8,7 @@
#ifndef HL_BOOT_IF_H
#define HL_BOOT_IF_H
-#define LKD_HARD_RESET_MAGIC 0xED7BD694
+#define LKD_HARD_RESET_MAGIC 0xED7BD694 /* deprecated - do not use */
#define HL_POWER9_HOST_MAGIC 0x1DA30009
#define BOOT_FIT_SRAM_OFFSET 0x200000
@@ -99,6 +99,7 @@
#define CPU_BOOT_ERR0_PLL_FAIL (1 << 12)
#define CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL (1 << 13)
#define CPU_BOOT_ERR0_ENABLED (1 << 31)
+#define CPU_BOOT_ERR1_ENABLED (1 << 31)
/*
* BOOT DEVICE STATUS bits in BOOT_DEVICE_STS registers
@@ -190,6 +191,24 @@
* PLLs.
* Initialized in: linux
*
+ * CPU_BOOT_DEV_STS0_GIC_PRIVILEGED_EN GIC access permission only from
+ * previleged entity. FW sets this status
+ * bit for host. If this bit is set then
+ * GIC can not be accessed from host.
+ * Initialized in: linux
+ *
+ * CPU_BOOT_DEV_STS0_EQ_INDEX_EN Event Queue (EQ) index is a running
+ * index for each new event sent to host.
+ * This is used as a method in host to
+ * identify that the waiting event in
+ * queue is actually a new event which
+ * was not served before.
+ * Initialized in: linux
+ *
+ * CPU_BOOT_DEV_STS0_MULTI_IRQ_POLL_EN Use multiple scratchpad interfaces to
+ * prevent IRQs overriding each other.
+ * Initialized in: linux
+ *
* CPU_BOOT_DEV_STS0_ENABLED Device status register enabled.
* This is a main indication that the
* running FW populates the device status
@@ -218,7 +237,11 @@
#define CPU_BOOT_DEV_STS0_FW_LD_COM_EN (1 << 16)
#define CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN (1 << 17)
#define CPU_BOOT_DEV_STS0_DYN_PLL_EN (1 << 19)
+#define CPU_BOOT_DEV_STS0_GIC_PRIVILEGED_EN (1 << 20)
+#define CPU_BOOT_DEV_STS0_EQ_INDEX_EN (1 << 21)
+#define CPU_BOOT_DEV_STS0_MULTI_IRQ_POLL_EN (1 << 22)
#define CPU_BOOT_DEV_STS0_ENABLED (1 << 31)
+#define CPU_BOOT_DEV_STS1_ENABLED (1 << 31)
enum cpu_boot_status {
CPU_BOOT_STATUS_NA = 0, /* Default value after reset of chip */
@@ -264,46 +287,98 @@ enum cpu_msg_status {
/* communication registers mapping - consider ABI when changing */
struct cpu_dyn_regs {
- uint32_t cpu_pq_base_addr_low;
- uint32_t cpu_pq_base_addr_high;
- uint32_t cpu_pq_length;
- uint32_t cpu_pq_init_status;
- uint32_t cpu_eq_base_addr_low;
- uint32_t cpu_eq_base_addr_high;
- uint32_t cpu_eq_length;
- uint32_t cpu_eq_ci;
- uint32_t cpu_cq_base_addr_low;
- uint32_t cpu_cq_base_addr_high;
- uint32_t cpu_cq_length;
- uint32_t cpu_pf_pq_pi;
- uint32_t cpu_boot_dev_sts0;
- uint32_t cpu_boot_dev_sts1;
- uint32_t cpu_boot_err0;
- uint32_t cpu_boot_err1;
- uint32_t cpu_boot_status;
- uint32_t fw_upd_sts;
- uint32_t fw_upd_cmd;
- uint32_t fw_upd_pending_sts;
- uint32_t fuse_ver_offset;
- uint32_t preboot_ver_offset;
- uint32_t uboot_ver_offset;
- uint32_t hw_state;
- uint32_t kmd_msg_to_cpu;
- uint32_t cpu_cmd_status_to_host;
- uint32_t reserved1[32]; /* reserve for future use */
+ __le32 cpu_pq_base_addr_low;
+ __le32 cpu_pq_base_addr_high;
+ __le32 cpu_pq_length;
+ __le32 cpu_pq_init_status;
+ __le32 cpu_eq_base_addr_low;
+ __le32 cpu_eq_base_addr_high;
+ __le32 cpu_eq_length;
+ __le32 cpu_eq_ci;
+ __le32 cpu_cq_base_addr_low;
+ __le32 cpu_cq_base_addr_high;
+ __le32 cpu_cq_length;
+ __le32 cpu_pf_pq_pi;
+ __le32 cpu_boot_dev_sts0;
+ __le32 cpu_boot_dev_sts1;
+ __le32 cpu_boot_err0;
+ __le32 cpu_boot_err1;
+ __le32 cpu_boot_status;
+ __le32 fw_upd_sts;
+ __le32 fw_upd_cmd;
+ __le32 fw_upd_pending_sts;
+ __le32 fuse_ver_offset;
+ __le32 preboot_ver_offset;
+ __le32 uboot_ver_offset;
+ __le32 hw_state;
+ __le32 kmd_msg_to_cpu;
+ __le32 cpu_cmd_status_to_host;
+ union {
+ __le32 gic_host_irq_ctrl;
+ __le32 gic_host_pi_upd_irq;
+ };
+ __le32 gic_tpc_qm_irq_ctrl;
+ __le32 gic_mme_qm_irq_ctrl;
+ __le32 gic_dma_qm_irq_ctrl;
+ __le32 gic_nic_qm_irq_ctrl;
+ __le32 gic_dma_core_irq_ctrl;
+ __le32 gic_host_halt_irq;
+ __le32 gic_host_ints_irq;
+ __le32 reserved1[24]; /* reserve for future use */
};
+/* TODO: remove the desc magic after the code is updated to use message */
/* HCDM - Habana Communications Descriptor Magic */
#define HL_COMMS_DESC_MAGIC 0x4843444D
#define HL_COMMS_DESC_VER 1
+/* HCMv - Habana Communications Message + header version */
+#define HL_COMMS_MSG_MAGIC_VALUE 0x48434D00
+#define HL_COMMS_MSG_MAGIC_MASK 0xFFFFFF00
+#define HL_COMMS_MSG_MAGIC_VER_MASK 0xFF
+
+#define HL_COMMS_MSG_MAGIC_VER(ver) (HL_COMMS_MSG_MAGIC_VALUE | \
+ ((ver) & HL_COMMS_MSG_MAGIC_VER_MASK))
+#define HL_COMMS_MSG_MAGIC_V0 HL_COMMS_DESC_MAGIC
+#define HL_COMMS_MSG_MAGIC_V1 HL_COMMS_MSG_MAGIC_VER(1)
+
+#define HL_COMMS_MSG_MAGIC HL_COMMS_MSG_MAGIC_V1
+
+#define HL_COMMS_MSG_MAGIC_VALIDATE_MAGIC(magic) \
+ (((magic) & HL_COMMS_MSG_MAGIC_MASK) == \
+ HL_COMMS_MSG_MAGIC_VALUE)
+
+#define HL_COMMS_MSG_MAGIC_VALIDATE_VERSION(magic, ver) \
+ (((magic) & HL_COMMS_MSG_MAGIC_VER_MASK) >= \
+ ((ver) & HL_COMMS_MSG_MAGIC_VER_MASK))
+
+#define HL_COMMS_MSG_MAGIC_VALIDATE(magic, ver) \
+ (HL_COMMS_MSG_MAGIC_VALIDATE_MAGIC((magic)) && \
+ HL_COMMS_MSG_MAGIC_VALIDATE_VERSION((magic), (ver)))
+
+enum comms_msg_type {
+ HL_COMMS_DESC_TYPE = 0,
+ HL_COMMS_RESET_CAUSE_TYPE = 1,
+};
+
+/* TODO: remove this struct after the code is updated to use message */
/* this is the comms descriptor header - meta data */
struct comms_desc_header {
- uint32_t magic; /* magic for validation */
- uint32_t crc32; /* CRC32 of the descriptor w/o header */
- uint16_t size; /* size of the descriptor w/o header */
- uint8_t version; /* descriptor version */
- uint8_t reserved[5]; /* pad to 64 bit */
+ __le32 magic; /* magic for validation */
+ __le32 crc32; /* CRC32 of the descriptor w/o header */
+ __le16 size; /* size of the descriptor w/o header */
+ __u8 version; /* descriptor version */
+ __u8 reserved[5]; /* pad to 64 bit */
+};
+
+/* this is the comms message header - meta data */
+struct comms_msg_header {
+ __le32 magic; /* magic for validation */
+ __le32 crc32; /* CRC32 of the message w/o header */
+ __le16 size; /* size of the message w/o header */
+ __u8 version; /* message payload version */
+ __u8 type; /* message type */
+ __u8 reserved[4]; /* pad to 64 bit */
};
/* this is the main FW descriptor - consider ABI when changing */
@@ -314,7 +389,36 @@ struct lkd_fw_comms_desc {
char cur_fw_ver[VERSION_MAX_LEN];
/* can be used for 1 more version w/o ABI change */
char reserved0[VERSION_MAX_LEN];
- uint64_t img_addr; /* address for next FW component load */
+ __le64 img_addr; /* address for next FW component load */
+};
+
+enum comms_reset_cause {
+ HL_RESET_CAUSE_UNKNOWN = 0,
+ HL_RESET_CAUSE_HEARTBEAT = 1,
+ HL_RESET_CAUSE_TDR = 2,
+};
+
+/* TODO: remove define after struct name is aligned on all projects */
+#define lkd_msg_comms lkd_fw_comms_msg
+
+/* this is the comms message descriptor */
+struct lkd_fw_comms_msg {
+ struct comms_msg_header header;
+ /* union for future expantions of new messages */
+ union {
+ struct {
+ struct cpu_dyn_regs cpu_dyn_regs;
+ char fuse_ver[VERSION_MAX_LEN];
+ char cur_fw_ver[VERSION_MAX_LEN];
+ /* can be used for 1 more version w/o ABI change */
+ char reserved0[VERSION_MAX_LEN];
+ /* address for next FW component load */
+ __le64 img_addr;
+ };
+ struct {
+ __u8 reset_cause;
+ };
+ };
};
/*
@@ -386,11 +490,11 @@ enum comms_cmd {
struct comms_command {
union { /* bit fields are only for FW use */
struct {
- unsigned int size :25; /* 32MB max. */
- unsigned int reserved :2;
+ u32 size :25; /* 32MB max. */
+ u32 reserved :2;
enum comms_cmd cmd :5; /* 32 commands */
};
- unsigned int val;
+ __le32 val;
};
};
@@ -449,11 +553,11 @@ enum comms_ram_types {
struct comms_status {
union { /* bit fields are only for FW use */
struct {
- unsigned int offset :26;
- unsigned int ram_type :2;
+ u32 offset :26;
+ enum comms_ram_types ram_type :2;
enum comms_sts status :4; /* 16 statuses */
};
- unsigned int val;
+ __le32 val;
};
};
diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h
index e8651abf84f2..d966bd4dfea6 100644
--- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h
+++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h
@@ -252,10 +252,11 @@ enum gaudi_async_event_id {
GAUDI_EVENT_HBM3_SPI_0 = 407,
GAUDI_EVENT_HBM3_SPI_1 = 408,
GAUDI_EVENT_PSOC_GPIO_U16_0 = 421,
- GAUDI_EVENT_PI_UPDATE = 484,
- GAUDI_EVENT_HALT_MACHINE = 485,
- GAUDI_EVENT_INTS_REGISTER = 486,
- GAUDI_EVENT_SOFT_RESET = 487,
+ GAUDI_EVENT_NIC0_CS_DBG_DERR = 483,
+ GAUDI_EVENT_NIC1_CS_DBG_DERR = 487,
+ GAUDI_EVENT_NIC2_CS_DBG_DERR = 491,
+ GAUDI_EVENT_NIC3_CS_DBG_DERR = 495,
+ GAUDI_EVENT_NIC4_CS_DBG_DERR = 499,
GAUDI_EVENT_RAZWI_OR_ADC = 548,
GAUDI_EVENT_TPC0_QM = 572,
GAUDI_EVENT_TPC1_QM = 573,
@@ -303,6 +304,11 @@ enum gaudi_async_event_id {
GAUDI_EVENT_NIC3_QP1 = 619,
GAUDI_EVENT_NIC4_QP0 = 620,
GAUDI_EVENT_NIC4_QP1 = 621,
+ GAUDI_EVENT_PI_UPDATE = 635,
+ GAUDI_EVENT_HALT_MACHINE = 636,
+ GAUDI_EVENT_INTS_REGISTER = 637,
+ GAUDI_EVENT_SOFT_RESET = 638,
+ GAUDI_EVENT_FW_ALIVE_S = 645,
GAUDI_EVENT_DEV_RESET_REQ = 646,
GAUDI_EVENT_PKT_QUEUE_OUT_SYNC = 647,
GAUDI_EVENT_FIX_POWER_ENV_S = 658,
diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h
index 3dc79c131805..479b6b038254 100644
--- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h
+++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h
@@ -507,23 +507,28 @@ static struct gaudi_async_events_ids_map gaudi_irq_map_table[] = {
{ .fc_id = 480, .cpu_id = 329, .valid = 0, .name = "" },
{ .fc_id = 481, .cpu_id = 330, .valid = 0, .name = "" },
{ .fc_id = 482, .cpu_id = 331, .valid = 0, .name = "" },
- { .fc_id = 483, .cpu_id = 332, .valid = 0, .name = "" },
- { .fc_id = 484, .cpu_id = 333, .valid = 1, .name = "PI_UPDATE" },
- { .fc_id = 485, .cpu_id = 334, .valid = 1, .name = "HALT_MACHINE" },
- { .fc_id = 486, .cpu_id = 335, .valid = 1, .name = "INTS_REGISTER" },
- { .fc_id = 487, .cpu_id = 336, .valid = 1, .name = "SOFT_RESET" },
+ { .fc_id = 483, .cpu_id = 332, .valid = 1,
+ .name = "NIC0_CS_DBG_DERR" },
+ { .fc_id = 484, .cpu_id = 333, .valid = 0, .name = "" },
+ { .fc_id = 485, .cpu_id = 334, .valid = 0, .name = "" },
+ { .fc_id = 486, .cpu_id = 335, .valid = 0, .name = "" },
+ { .fc_id = 487, .cpu_id = 336, .valid = 1,
+ .name = "NIC1_CS_DBG_DERR" },
{ .fc_id = 488, .cpu_id = 337, .valid = 0, .name = "" },
{ .fc_id = 489, .cpu_id = 338, .valid = 0, .name = "" },
{ .fc_id = 490, .cpu_id = 339, .valid = 0, .name = "" },
- { .fc_id = 491, .cpu_id = 340, .valid = 0, .name = "" },
+ { .fc_id = 491, .cpu_id = 340, .valid = 1,
+ .name = "NIC2_CS_DBG_DERR" },
{ .fc_id = 492, .cpu_id = 341, .valid = 0, .name = "" },
{ .fc_id = 493, .cpu_id = 342, .valid = 0, .name = "" },
{ .fc_id = 494, .cpu_id = 343, .valid = 0, .name = "" },
- { .fc_id = 495, .cpu_id = 344, .valid = 0, .name = "" },
+ { .fc_id = 495, .cpu_id = 344, .valid = 1,
+ .name = "NIC3_CS_DBG_DERR" },
{ .fc_id = 496, .cpu_id = 345, .valid = 0, .name = "" },
{ .fc_id = 497, .cpu_id = 346, .valid = 0, .name = "" },
{ .fc_id = 498, .cpu_id = 347, .valid = 0, .name = "" },
- { .fc_id = 499, .cpu_id = 348, .valid = 0, .name = "" },
+ { .fc_id = 499, .cpu_id = 348, .valid = 1,
+ .name = "NIC4_CS_DBG_DERR" },
{ .fc_id = 500, .cpu_id = 349, .valid = 0, .name = "" },
{ .fc_id = 501, .cpu_id = 350, .valid = 0, .name = "" },
{ .fc_id = 502, .cpu_id = 351, .valid = 0, .name = "" },
@@ -659,17 +664,17 @@ static struct gaudi_async_events_ids_map gaudi_irq_map_table[] = {
{ .fc_id = 632, .cpu_id = 481, .valid = 0, .name = "" },
{ .fc_id = 633, .cpu_id = 482, .valid = 0, .name = "" },
{ .fc_id = 634, .cpu_id = 483, .valid = 0, .name = "" },
- { .fc_id = 635, .cpu_id = 484, .valid = 0, .name = "" },
- { .fc_id = 636, .cpu_id = 485, .valid = 0, .name = "" },
- { .fc_id = 637, .cpu_id = 486, .valid = 0, .name = "" },
- { .fc_id = 638, .cpu_id = 487, .valid = 0, .name = "" },
+ { .fc_id = 635, .cpu_id = 484, .valid = 1, .name = "PI_UPDATE" },
+ { .fc_id = 636, .cpu_id = 485, .valid = 1, .name = "HALT_MACHINE" },
+ { .fc_id = 637, .cpu_id = 486, .valid = 1, .name = "INTS_REGISTER" },
+ { .fc_id = 638, .cpu_id = 487, .valid = 1, .name = "SOFT_RESET" },
{ .fc_id = 639, .cpu_id = 488, .valid = 0, .name = "" },
{ .fc_id = 640, .cpu_id = 489, .valid = 0, .name = "" },
{ .fc_id = 641, .cpu_id = 490, .valid = 0, .name = "" },
{ .fc_id = 642, .cpu_id = 491, .valid = 0, .name = "" },
{ .fc_id = 643, .cpu_id = 492, .valid = 0, .name = "" },
{ .fc_id = 644, .cpu_id = 493, .valid = 0, .name = "" },
- { .fc_id = 645, .cpu_id = 494, .valid = 0, .name = "" },
+ { .fc_id = 645, .cpu_id = 494, .valid = 1, .name = "FW_ALIVE_S" },
{ .fc_id = 646, .cpu_id = 495, .valid = 1, .name = "DEV_RESET_REQ" },
{ .fc_id = 647, .cpu_id = 496, .valid = 1,
.name = "PKT_QUEUE_OUT_SYNC" },
diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h b/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h
index a9f51f9f9e92..34ca4fe50d91 100644
--- a/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h
+++ b/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h
@@ -20,6 +20,9 @@
#define UBOOT_FW_OFFSET 0x100000 /* 1MB in SRAM */
#define LINUX_FW_OFFSET 0x800000 /* 8MB in HBM */
+/* HBM thermal delta in [Deg] added to composite (CTemp) */
+#define HBM_TEMP_ADJUST_COEFF 6
+
enum gaudi_nic_axi_error {
RXB,
RXE,
@@ -27,6 +30,7 @@ enum gaudi_nic_axi_error {
TXE,
QPC_RESP,
NON_AXI_ERR,
+ TMR,
};
/*
@@ -42,6 +46,48 @@ struct eq_nic_sei_event {
__u8 pad[6];
};
+/*
+ * struct gaudi_nic_status - describes the status of a NIC port.
+ * @port: NIC port index.
+ * @bad_format_cnt: e.g. CRC.
+ * @responder_out_of_sequence_psn_cnt: e.g NAK.
+ * @high_ber_reinit_cnt: link reinit due to high BER.
+ * @correctable_err_cnt: e.g. bit-flip.
+ * @uncorrectable_err_cnt: e.g. MAC errors.
+ * @retraining_cnt: re-training counter.
+ * @up: is port up.
+ * @pcs_link: has PCS link.
+ * @phy_ready: is PHY ready.
+ * @auto_neg: is Autoneg enabled.
+ * @timeout_retransmission_cnt: timeout retransmission events
+ * @high_ber_cnt: high ber events
+ */
+struct gaudi_nic_status {
+ __u32 port;
+ __u32 bad_format_cnt;
+ __u32 responder_out_of_sequence_psn_cnt;
+ __u32 high_ber_reinit;
+ __u32 correctable_err_cnt;
+ __u32 uncorrectable_err_cnt;
+ __u32 retraining_cnt;
+ __u8 up;
+ __u8 pcs_link;
+ __u8 phy_ready;
+ __u8 auto_neg;
+ __u32 timeout_retransmission_cnt;
+ __u32 high_ber_cnt;
+};
+
+struct gaudi_flops_2_data {
+ union {
+ struct {
+ __u32 spsram_init_done : 1;
+ __u32 reserved : 31;
+ };
+ __u32 data;
+ };
+};
+
#define GAUDI_PLL_FREQ_LOW 200000000 /* 200 MHz */
#endif /* GAUDI_FW_IF_H */
diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_masks.h b/drivers/misc/habanalabs/include/gaudi/gaudi_masks.h
index b53aeda9a982..9aea7e996654 100644
--- a/drivers/misc/habanalabs/include/gaudi/gaudi_masks.h
+++ b/drivers/misc/habanalabs/include/gaudi/gaudi_masks.h
@@ -66,7 +66,8 @@
#define PCI_DMA_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK (\
(FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_PQF_STOP_ON_ERR_MASK, 0xF)) | \
(FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_CQF_STOP_ON_ERR_MASK, 0xF)) | \
- (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0xF)))
+ (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0xF)) | \
+ (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_ARB_STOP_ON_ERR_MASK, 0x1)))
#define HBM_DMA_QMAN_GLBL_ERR_CFG_MSG_EN_MASK (\
(FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_PQF_ERR_MSG_EN_MASK, 0xF)) | \
@@ -76,7 +77,8 @@
#define HBM_DMA_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK (\
(FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_PQF_STOP_ON_ERR_MASK, 0xF)) | \
(FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_CQF_STOP_ON_ERR_MASK, 0x1F)) | \
- (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0x1F)))
+ (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0x1F)) | \
+ (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_ARB_STOP_ON_ERR_MASK, 0x1)))
#define TPC_QMAN_GLBL_ERR_CFG_MSG_EN_MASK (\
(FIELD_PREP(TPC0_QM_GLBL_ERR_CFG_PQF_ERR_MSG_EN_MASK, 0xF)) | \
@@ -86,7 +88,8 @@
#define TPC_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK (\
(FIELD_PREP(TPC0_QM_GLBL_ERR_CFG_PQF_STOP_ON_ERR_MASK, 0xF)) | \
(FIELD_PREP(TPC0_QM_GLBL_ERR_CFG_CQF_STOP_ON_ERR_MASK, 0x1F)) | \
- (FIELD_PREP(TPC0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0x1F)))
+ (FIELD_PREP(TPC0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0x1F)) | \
+ (FIELD_PREP(TPC0_QM_GLBL_ERR_CFG_ARB_STOP_ON_ERR_MASK, 0x1)))
#define MME_QMAN_GLBL_ERR_CFG_MSG_EN_MASK (\
(FIELD_PREP(MME0_QM_GLBL_ERR_CFG_PQF_ERR_MSG_EN_MASK, 0xF)) | \
@@ -96,7 +99,8 @@
#define MME_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK (\
(FIELD_PREP(MME0_QM_GLBL_ERR_CFG_PQF_STOP_ON_ERR_MASK, 0xF)) | \
(FIELD_PREP(MME0_QM_GLBL_ERR_CFG_CQF_STOP_ON_ERR_MASK, 0x1F)) | \
- (FIELD_PREP(MME0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0x1F)))
+ (FIELD_PREP(MME0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0x1F)) | \
+ (FIELD_PREP(MME0_QM_GLBL_ERR_CFG_ARB_STOP_ON_ERR_MASK, 0x1)))
#define NIC_QMAN_GLBL_ERR_CFG_MSG_EN_MASK (\
(FIELD_PREP(NIC0_QM0_GLBL_ERR_CFG_PQF_ERR_MSG_EN_MASK, 0xF)) | \
@@ -106,7 +110,8 @@
#define NIC_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK (\
(FIELD_PREP(NIC0_QM0_GLBL_ERR_CFG_PQF_STOP_ON_ERR_MASK, 0xF)) | \
(FIELD_PREP(NIC0_QM0_GLBL_ERR_CFG_CQF_STOP_ON_ERR_MASK, 0xF)) | \
- (FIELD_PREP(NIC0_QM0_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0xF)))
+ (FIELD_PREP(NIC0_QM0_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0xF)) | \
+ (FIELD_PREP(NIC0_QM0_GLBL_ERR_CFG_ARB_STOP_ON_ERR_MASK, 0x1)))
#define QMAN_CGM1_PWR_GATE_EN (FIELD_PREP(DMA0_QM_CGM_CFG1_MASK_TH_MASK, 0xA))
diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h b/drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h
index 137afedf5f15..d95d4162ae2c 100644
--- a/drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h
+++ b/drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h
@@ -12,6 +12,16 @@
* PSOC scratch-pad registers
*/
#define mmHW_STATE mmPSOC_GLOBAL_CONF_SCRATCHPAD_0
+/* TODO: remove mmGIC_HOST_IRQ_CTRL_POLL_REG */
+#define mmGIC_HOST_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_1
+#define mmGIC_HOST_PI_UPD_IRQ_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_1
+#define mmGIC_TPC_QM_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_2
+#define mmGIC_MME_QM_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_3
+#define mmGIC_DMA_QM_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_4
+#define mmGIC_NIC_QM_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_5
+#define mmGIC_DMA_CR_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_6
+#define mmGIC_HOST_HALT_IRQ_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_7
+#define mmGIC_HOST_INTS_IRQ_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_8
#define mmCPU_BOOT_DEV_STS0 mmPSOC_GLOBAL_CONF_SCRATCHPAD_20
#define mmCPU_BOOT_DEV_STS1 mmPSOC_GLOBAL_CONF_SCRATCHPAD_21
#define mmFUSE_VER_OFFSET mmPSOC_GLOBAL_CONF_SCRATCHPAD_22
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
index fea3ae9d8686..8d00df9243c4 100644
--- a/drivers/misc/hpilo.c
+++ b/drivers/misc/hpilo.c
@@ -693,6 +693,8 @@ static int ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw)
{
int bar;
unsigned long off;
+ u8 pci_rev_id;
+ int rc;
/* map the memory mapped i/o registers */
hw->mmio_vaddr = pci_iomap(pdev, 1, 0);
@@ -702,7 +704,13 @@ static int ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw)
}
/* map the adapter shared memory region */
- if (pdev->subsystem_device == 0x00E4) {
+ rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev_id);
+ if (rc != 0) {
+ dev_err(&pdev->dev, "Error reading PCI rev id: %d\n", rc);
+ goto out;
+ }
+
+ if (pci_rev_id >= PCI_REV_ID_NECHES) {
bar = 5;
/* Last 8k is reserved for CCBs */
off = pci_resource_len(pdev, bar) - 0x2000;
diff --git a/drivers/misc/hpilo.h b/drivers/misc/hpilo.h
index f69ff645cac9..d57c34680b09 100644
--- a/drivers/misc/hpilo.h
+++ b/drivers/misc/hpilo.h
@@ -10,6 +10,9 @@
#define ILO_NAME "hpilo"
+/* iLO ASIC PCI revision id */
+#define PCI_REV_ID_NECHES 7
+
/* max number of open channel control blocks per device, hw limited to 32 */
#define MAX_CCB 24
/* min number of open channel control blocks per device, hw limited to 32 */
diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c
index 4f5f3bdc814d..59c9a0d95659 100644
--- a/drivers/misc/ibmasm/heartbeat.c
+++ b/drivers/misc/ibmasm/heartbeat.c
@@ -9,6 +9,7 @@
*/
#include <linux/notifier.h>
+#include <linux/panic_notifier.h>
#include "ibmasm.h"
#include "dot_command.h"
#include "lowlevel.h"
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c
index 4edad6c445d3..dc8a06c06c63 100644
--- a/drivers/misc/ibmasm/module.c
+++ b/drivers/misc/ibmasm/module.c
@@ -111,7 +111,7 @@ static int ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
result = ibmasm_init_remote_input_dev(sp);
if (result) {
dev_err(sp->dev, "Failed to initialize remote queue\n");
- goto error_send_message;
+ goto error_init_remote;
}
result = ibmasm_send_driver_vpd(sp);
@@ -131,8 +131,9 @@ static int ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
error_send_message:
- disable_sp_interrupts(sp->base_address);
ibmasm_free_remote_input_dev(sp);
+error_init_remote:
+ disable_sp_interrupts(sp->base_address);
free_irq(sp->irq, (void *)sp);
error_request_irq:
iounmap(sp->base_address);
diff --git a/drivers/misc/ibmasm/remote.h b/drivers/misc/ibmasm/remote.h
index 8d364462aeea..ec4e78ec5a67 100644
--- a/drivers/misc/ibmasm/remote.h
+++ b/drivers/misc/ibmasm/remote.h
@@ -43,7 +43,7 @@
#define REMOTE_BUTTON_MIDDLE 0x02
#define REMOTE_BUTTON_RIGHT 0x04
-/* size of keysym/keycode translation matricies */
+/* size of keysym/keycode translation matrices */
#define XLATE_SIZE 256
struct mouse_input {
diff --git a/drivers/misc/lattice-ecp3-config.c b/drivers/misc/lattice-ecp3-config.c
index 5eaf74447ca1..0f54730c7ed5 100644
--- a/drivers/misc/lattice-ecp3-config.c
+++ b/drivers/misc/lattice-ecp3-config.c
@@ -198,7 +198,7 @@ static int lattice_ecp3_probe(struct spi_device *spi)
spi_set_drvdata(spi, data);
init_completion(&data->fw_loaded);
- err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ err = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
FIRMWARE_NAME, &spi->dev,
GFP_KERNEL, spi, firmware_load);
if (err) {
diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c
index 0e8254d0cf0b..88c218a9f8b3 100644
--- a/drivers/misc/lkdtm/bugs.c
+++ b/drivers/misc/lkdtm/bugs.c
@@ -161,6 +161,9 @@ void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void)
if (*p == 0)
val = 0x87654321;
*p = val;
+
+ if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
+ pr_err("XFAIL: arch has CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS\n");
}
void lkdtm_SOFTLOCKUP(void)
@@ -300,8 +303,10 @@ void lkdtm_CORRUPT_LIST_ADD(void)
if (target[0] == NULL && target[1] == NULL)
pr_err("Overwrite did not happen, but no BUG?!\n");
- else
+ else {
pr_err("list_add() corruption not detected!\n");
+ pr_expected_config(CONFIG_DEBUG_LIST);
+ }
}
void lkdtm_CORRUPT_LIST_DEL(void)
@@ -325,8 +330,10 @@ void lkdtm_CORRUPT_LIST_DEL(void)
if (target[0] == NULL && target[1] == NULL)
pr_err("Overwrite did not happen, but no BUG?!\n");
- else
+ else {
pr_err("list_del() corruption not detected!\n");
+ pr_expected_config(CONFIG_DEBUG_LIST);
+ }
}
/* Test that VMAP_STACK is actually allocating with a leading guard page */
@@ -463,7 +470,7 @@ void lkdtm_DOUBLE_FAULT(void)
#ifdef CONFIG_ARM64
static noinline void change_pac_parameters(void)
{
- if (IS_ENABLED(CONFIG_ARM64_PTR_AUTH)) {
+ if (IS_ENABLED(CONFIG_ARM64_PTR_AUTH_KERNEL)) {
/* Reset the keys of current task */
ptrauth_thread_init_kernel(current);
ptrauth_thread_switch_kernel(current);
@@ -477,8 +484,8 @@ noinline void lkdtm_CORRUPT_PAC(void)
#define CORRUPT_PAC_ITERATE 10
int i;
- if (!IS_ENABLED(CONFIG_ARM64_PTR_AUTH))
- pr_err("FAIL: kernel not built with CONFIG_ARM64_PTR_AUTH\n");
+ if (!IS_ENABLED(CONFIG_ARM64_PTR_AUTH_KERNEL))
+ pr_err("FAIL: kernel not built with CONFIG_ARM64_PTR_AUTH_KERNEL\n");
if (!system_supports_address_auth()) {
pr_err("FAIL: CPU lacks pointer authentication feature\n");
diff --git a/drivers/misc/lkdtm/cfi.c b/drivers/misc/lkdtm/cfi.c
index e73ebdbfa806..c9aeddef1044 100644
--- a/drivers/misc/lkdtm/cfi.c
+++ b/drivers/misc/lkdtm/cfi.c
@@ -38,5 +38,6 @@ void lkdtm_CFI_FORWARD_PROTO(void)
func = (void *)lkdtm_increment_int;
func(&called_count);
- pr_info("Fail: survived mismatched prototype function call!\n");
+ pr_err("FAIL: survived mismatched prototype function call!\n");
+ pr_expected_config(CONFIG_CFI_CLANG);
}
diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c
index 8024b6a5cc7f..9dda87c6b54a 100644
--- a/drivers/misc/lkdtm/core.c
+++ b/drivers/misc/lkdtm/core.c
@@ -26,6 +26,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/debugfs.h>
+#include <linux/init.h>
#define DEFAULT_COUNT 10
@@ -120,11 +121,14 @@ static const struct crashtype crashtypes[] = {
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
CRASHTYPE(FORTIFY_OBJECT),
CRASHTYPE(FORTIFY_SUBOBJECT),
- CRASHTYPE(OVERWRITE_ALLOCATION),
+ CRASHTYPE(SLAB_LINEAR_OVERFLOW),
+ CRASHTYPE(VMALLOC_LINEAR_OVERFLOW),
CRASHTYPE(WRITE_AFTER_FREE),
CRASHTYPE(READ_AFTER_FREE),
CRASHTYPE(WRITE_BUDDY_AFTER_FREE),
CRASHTYPE(READ_BUDDY_AFTER_FREE),
+ CRASHTYPE(SLAB_INIT_ON_ALLOC),
+ CRASHTYPE(BUDDY_INIT_ON_ALLOC),
CRASHTYPE(SLAB_FREE_DOUBLE),
CRASHTYPE(SLAB_FREE_CROSS),
CRASHTYPE(SLAB_FREE_PAGE),
@@ -177,9 +181,7 @@ static const struct crashtype crashtypes[] = {
CRASHTYPE(STACKLEAK_ERASING),
CRASHTYPE(CFI_FORWARD_PROTO),
CRASHTYPE(FORTIFIED_STRSCPY),
-#ifdef CONFIG_X86_32
CRASHTYPE(DOUBLE_FAULT),
-#endif
#ifdef CONFIG_PPC_BOOK3S_64
CRASHTYPE(PPC_SLB_MULTIHIT),
#endif
@@ -399,6 +401,56 @@ static ssize_t direct_entry(struct file *f, const char __user *user_buf,
return count;
}
+#ifndef MODULE
+/*
+ * To avoid needing to export parse_args(), just don't use this code
+ * when LKDTM is built as a module.
+ */
+struct check_cmdline_args {
+ const char *param;
+ int value;
+};
+
+static int lkdtm_parse_one(char *param, char *val,
+ const char *unused, void *arg)
+{
+ struct check_cmdline_args *args = arg;
+
+ /* short circuit if we already found a value. */
+ if (args->value != -ESRCH)
+ return 0;
+ if (strncmp(param, args->param, strlen(args->param)) == 0) {
+ bool bool_result;
+ int ret;
+
+ ret = kstrtobool(val, &bool_result);
+ if (ret == 0)
+ args->value = bool_result;
+ }
+ return 0;
+}
+
+int lkdtm_check_bool_cmdline(const char *param)
+{
+ char *command_line;
+ struct check_cmdline_args args = {
+ .param = param,
+ .value = -ESRCH,
+ };
+
+ command_line = kstrdup(saved_command_line, GFP_KERNEL);
+ if (!command_line)
+ return -ENOMEM;
+
+ parse_args("Setting sysctl args", command_line,
+ NULL, 0, -1, -1, &args, lkdtm_parse_one);
+
+ kfree(command_line);
+
+ return args.value;
+}
+#endif
+
static struct dentry *lkdtm_debugfs_root;
static int __init lkdtm_module_init(void)
diff --git a/drivers/misc/lkdtm/fortify.c b/drivers/misc/lkdtm/fortify.c
index faf29cf04baa..0f51d31b57ca 100644
--- a/drivers/misc/lkdtm/fortify.c
+++ b/drivers/misc/lkdtm/fortify.c
@@ -76,7 +76,8 @@ void lkdtm_FORTIFIED_STRSCPY(void)
*/
strscpy(dst, src, strlen(src));
- pr_warn("FAIL: No overflow in above strscpy()\n");
+ pr_err("FAIL: strscpy() overflow not detected!\n");
+ pr_expected_config(CONFIG_FORTIFY_SOURCE);
kfree(src);
}
diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c
index 1323bc16f113..3d9aae5821a0 100644
--- a/drivers/misc/lkdtm/heap.c
+++ b/drivers/misc/lkdtm/heap.c
@@ -5,6 +5,7 @@
*/
#include "lkdtm.h"
#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <linux/sched.h>
static struct kmem_cache *double_free_cache;
@@ -12,17 +13,36 @@ static struct kmem_cache *a_cache;
static struct kmem_cache *b_cache;
/*
+ * If there aren't guard pages, it's likely that a consecutive allocation will
+ * let us overflow into the second allocation without overwriting something real.
+ */
+void lkdtm_VMALLOC_LINEAR_OVERFLOW(void)
+{
+ char *one, *two;
+
+ one = vzalloc(PAGE_SIZE);
+ two = vzalloc(PAGE_SIZE);
+
+ pr_info("Attempting vmalloc linear overflow ...\n");
+ memset(one, 0xAA, PAGE_SIZE + 1);
+
+ vfree(two);
+ vfree(one);
+}
+
+/*
* This tries to stay within the next largest power-of-2 kmalloc cache
* to avoid actually overwriting anything important if it's not detected
* correctly.
*/
-void lkdtm_OVERWRITE_ALLOCATION(void)
+void lkdtm_SLAB_LINEAR_OVERFLOW(void)
{
size_t len = 1020;
u32 *data = kmalloc(len, GFP_KERNEL);
if (!data)
return;
+ pr_info("Attempting slab linear overflow ...\n");
data[1024 / sizeof(u32)] = 0x12345678;
kfree(data);
}
@@ -89,9 +109,10 @@ void lkdtm_READ_AFTER_FREE(void)
if (saw != *val) {
/* Good! Poisoning happened, so declare a win. */
pr_info("Memory correctly poisoned (%x)\n", saw);
- BUG();
+ } else {
+ pr_err("FAIL: Memory was not poisoned!\n");
+ pr_expected_config_param(CONFIG_INIT_ON_FREE_DEFAULT_ON, "init_on_free");
}
- pr_info("Memory was not poisoned\n");
kfree(val);
}
@@ -145,13 +166,79 @@ void lkdtm_READ_BUDDY_AFTER_FREE(void)
if (saw != *val) {
/* Good! Poisoning happened, so declare a win. */
pr_info("Memory correctly poisoned (%x)\n", saw);
- BUG();
+ } else {
+ pr_err("FAIL: Buddy page was not poisoned!\n");
+ pr_expected_config_param(CONFIG_INIT_ON_FREE_DEFAULT_ON, "init_on_free");
+ }
+
+ kfree(val);
+}
+
+void lkdtm_SLAB_INIT_ON_ALLOC(void)
+{
+ u8 *first;
+ u8 *val;
+
+ first = kmalloc(512, GFP_KERNEL);
+ if (!first) {
+ pr_info("Unable to allocate 512 bytes the first time.\n");
+ return;
+ }
+
+ memset(first, 0xAB, 512);
+ kfree(first);
+
+ val = kmalloc(512, GFP_KERNEL);
+ if (!val) {
+ pr_info("Unable to allocate 512 bytes the second time.\n");
+ return;
+ }
+ if (val != first) {
+ pr_warn("Reallocation missed clobbered memory.\n");
}
- pr_info("Buddy page was not poisoned\n");
+ if (memchr(val, 0xAB, 512) == NULL) {
+ pr_info("Memory appears initialized (%x, no earlier values)\n", *val);
+ } else {
+ pr_err("FAIL: Slab was not initialized\n");
+ pr_expected_config_param(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, "init_on_alloc");
+ }
kfree(val);
}
+void lkdtm_BUDDY_INIT_ON_ALLOC(void)
+{
+ u8 *first;
+ u8 *val;
+
+ first = (u8 *)__get_free_page(GFP_KERNEL);
+ if (!first) {
+ pr_info("Unable to allocate first free page\n");
+ return;
+ }
+
+ memset(first, 0xAB, PAGE_SIZE);
+ free_page((unsigned long)first);
+
+ val = (u8 *)__get_free_page(GFP_KERNEL);
+ if (!val) {
+ pr_info("Unable to allocate second free page\n");
+ return;
+ }
+
+ if (val != first) {
+ pr_warn("Reallocation missed clobbered memory.\n");
+ }
+
+ if (memchr(val, 0xAB, PAGE_SIZE) == NULL) {
+ pr_info("Memory appears initialized (%x, no earlier values)\n", *val);
+ } else {
+ pr_err("FAIL: Slab was not initialized\n");
+ pr_expected_config_param(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, "init_on_alloc");
+ }
+ free_page((unsigned long)val);
+}
+
void lkdtm_SLAB_FREE_DOUBLE(void)
{
int *val;
diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h
index 99f90d3e5e9c..6a30b60519f3 100644
--- a/drivers/misc/lkdtm/lkdtm.h
+++ b/drivers/misc/lkdtm/lkdtm.h
@@ -6,6 +6,47 @@
#include <linux/kernel.h>
+#define pr_expected_config(kconfig) \
+{ \
+ if (IS_ENABLED(kconfig)) \
+ pr_err("Unexpected! This kernel was built with " #kconfig "=y\n"); \
+ else \
+ pr_warn("This is probably expected, since this kernel was built *without* " #kconfig "=y\n"); \
+}
+
+#ifndef MODULE
+int lkdtm_check_bool_cmdline(const char *param);
+#define pr_expected_config_param(kconfig, param) \
+{ \
+ if (IS_ENABLED(kconfig)) { \
+ switch (lkdtm_check_bool_cmdline(param)) { \
+ case 0: \
+ pr_warn("This is probably expected, since this kernel was built with " #kconfig "=y but booted with '" param "=N'\n"); \
+ break; \
+ case 1: \
+ pr_err("Unexpected! This kernel was built with " #kconfig "=y and booted with '" param "=Y'\n"); \
+ break; \
+ default: \
+ pr_err("Unexpected! This kernel was built with " #kconfig "=y (and booted without '" param "' specified)\n"); \
+ } \
+ } else { \
+ switch (lkdtm_check_bool_cmdline(param)) { \
+ case 0: \
+ pr_warn("This is probably expected, as kernel was built *without* " #kconfig "=y and booted with '" param "=N'\n"); \
+ break; \
+ case 1: \
+ pr_err("Unexpected! This kernel was built *without* " #kconfig "=y but booted with '" param "=Y'\n"); \
+ break; \
+ default: \
+ pr_err("This is probably expected, since this kernel was built *without* " #kconfig "=y (and booted without '" param "' specified)\n"); \
+ break; \
+ } \
+ } \
+}
+#else
+#define pr_expected_config_param(kconfig, param) pr_expected_config(kconfig)
+#endif
+
/* bugs.c */
void __init lkdtm_bugs_init(int *recur_param);
void lkdtm_PANIC(void);
@@ -39,11 +80,14 @@ void lkdtm_FORTIFY_SUBOBJECT(void);
/* heap.c */
void __init lkdtm_heap_init(void);
void __exit lkdtm_heap_exit(void);
-void lkdtm_OVERWRITE_ALLOCATION(void);
+void lkdtm_VMALLOC_LINEAR_OVERFLOW(void);
+void lkdtm_SLAB_LINEAR_OVERFLOW(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_INIT_ON_ALLOC(void);
+void lkdtm_BUDDY_INIT_ON_ALLOC(void);
void lkdtm_SLAB_FREE_DOUBLE(void);
void lkdtm_SLAB_FREE_CROSS(void);
void lkdtm_SLAB_FREE_PAGE(void);
diff --git a/drivers/misc/lkdtm/stackleak.c b/drivers/misc/lkdtm/stackleak.c
index d1a5c0705be3..00db21ff115e 100644
--- a/drivers/misc/lkdtm/stackleak.c
+++ b/drivers/misc/lkdtm/stackleak.c
@@ -74,8 +74,8 @@ void lkdtm_STACKLEAK_ERASING(void)
end:
if (test_failed) {
- pr_err("FAIL: the thread stack is NOT properly erased\n");
- dump_stack();
+ pr_err("FAIL: the thread stack is NOT properly erased!\n");
+ pr_expected_config(CONFIG_GCC_PLUGIN_STACKLEAK);
} else {
pr_info("OK: the rest of the thread stack is properly erased\n");
}
diff --git a/drivers/misc/lkdtm/usercopy.c b/drivers/misc/lkdtm/usercopy.c
index 15d220ef35a5..9161ce7ed47a 100644
--- a/drivers/misc/lkdtm/usercopy.c
+++ b/drivers/misc/lkdtm/usercopy.c
@@ -173,6 +173,8 @@ static void do_usercopy_heap_size(bool to_user)
goto free_user;
}
}
+ pr_err("FAIL: bad usercopy not detected!\n");
+ pr_expected_config_param(CONFIG_HARDENED_USERCOPY, "hardened_usercopy");
free_user:
vm_munmap(user_addr, PAGE_SIZE);
@@ -248,6 +250,8 @@ static void do_usercopy_heap_whitelist(bool to_user)
goto free_user;
}
}
+ pr_err("FAIL: bad usercopy not detected!\n");
+ pr_expected_config_param(CONFIG_HARDENED_USERCOPY, "hardened_usercopy");
free_user:
vm_munmap(user_alloc, PAGE_SIZE);
@@ -319,7 +323,8 @@ void lkdtm_USERCOPY_KERNEL(void)
pr_warn("copy_to_user failed, but lacked Oops\n");
goto free_user;
}
- pr_err("FAIL: survived bad copy_to_user()\n");
+ pr_err("FAIL: bad copy_to_user() not detected!\n");
+ pr_expected_config_param(CONFIG_HARDENED_USERCOPY, "hardened_usercopy");
free_user:
vm_munmap(user_addr, PAGE_SIZE);
diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c
index d8e760b11ae3..67844089db21 100644
--- a/drivers/misc/mei/bus-fixup.c
+++ b/drivers/misc/mei/bus-fixup.c
@@ -498,7 +498,7 @@ static struct mei_fixup {
};
/**
- * mei_cldev_fixup - run fixup handlers
+ * mei_cl_bus_dev_fixup - run fixup handlers
*
* @cldev: me client device
*/
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 2cc370adb238..96f4e59c32a5 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -326,7 +326,7 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
}
/**
- * mei_tx_cb_queue - queue tx callback
+ * mei_tx_cb_enqueue - queue tx callback
*
* Locking: called under "dev->device_lock" lock
*
@@ -1726,12 +1726,15 @@ nortpm:
return rets;
}
-static inline u8 mei_ext_hdr_set_vtag(struct mei_ext_hdr *ext, u8 vtag)
+static inline u8 mei_ext_hdr_set_vtag(void *ext, u8 vtag)
{
- ext->type = MEI_EXT_HDR_VTAG;
- ext->ext_payload[0] = vtag;
- ext->length = mei_data2slots(sizeof(*ext));
- return ext->length;
+ struct mei_ext_hdr_vtag *vtag_hdr = ext;
+
+ vtag_hdr->hdr.type = MEI_EXT_HDR_VTAG;
+ vtag_hdr->hdr.length = mei_data2slots(sizeof(*vtag_hdr));
+ vtag_hdr->vtag = vtag;
+ vtag_hdr->reserved = 0;
+ return vtag_hdr->hdr.length;
}
/**
@@ -1745,7 +1748,6 @@ static struct mei_msg_hdr *mei_msg_hdr_init(const struct mei_cl_cb *cb)
{
size_t hdr_len;
struct mei_ext_meta_hdr *meta;
- struct mei_ext_hdr *ext;
struct mei_msg_hdr *mei_hdr;
bool is_ext, is_vtag;
@@ -1764,7 +1766,7 @@ static struct mei_msg_hdr *mei_msg_hdr_init(const struct mei_cl_cb *cb)
hdr_len += sizeof(*meta);
if (is_vtag)
- hdr_len += sizeof(*ext);
+ hdr_len += sizeof(struct mei_ext_hdr_vtag);
setup_hdr:
mei_hdr = kzalloc(hdr_len, GFP_KERNEL);
@@ -2250,7 +2252,7 @@ static void mei_cl_dma_free(struct mei_cl *cl)
}
/**
- * mei_cl_alloc_and_map - send client dma map request
+ * mei_cl_dma_alloc_and_map - send client dma map request
*
* @cl: host client
* @fp: pointer to file structure
@@ -2349,7 +2351,7 @@ out:
}
/**
- * mei_cl_unmap_and_free - send client dma unmap request
+ * mei_cl_dma_unmap - send client dma unmap request
*
* @cl: host client
* @fp: pointer to file structure
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index d0277c7fed10..99b5c1ecc444 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -853,7 +853,7 @@ out:
}
/**
- * mei_hbm_cl_flow_control_res - flow control response from me
+ * mei_hbm_cl_tx_flow_ctrl_creds_res - flow control response from me
*
* @dev: the device structure
* @fctrl: flow control response bus message
diff --git a/drivers/misc/mei/hdcp/Kconfig b/drivers/misc/mei/hdcp/Kconfig
index 95b2d6d37f10..54e1c9526909 100644
--- a/drivers/misc/mei/hdcp/Kconfig
+++ b/drivers/misc/mei/hdcp/Kconfig
@@ -1,4 +1,3 @@
-
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2019, Intel Corporation. All rights reserved.
#
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index cda0829ac589..d3a6c0728645 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -1380,7 +1380,7 @@ static bool mei_me_fw_type_nm(const struct pci_dev *pdev)
.quirk_probe = mei_me_fw_type_nm
/**
- * mei_me_fw_sku_sps_4() - check for sps 4.0 sku
+ * mei_me_fw_type_sps_4() - check for sps 4.0 sku
*
* Read ME FW Status register to check for SPS Firmware.
* The SPS FW is only signaled in the PCI function 0.
@@ -1405,7 +1405,7 @@ static bool mei_me_fw_type_sps_4(const struct pci_dev *pdev)
.quirk_probe = mei_me_fw_type_sps_4
/**
- * mei_me_fw_sku_sps() - check for sps sku
+ * mei_me_fw_type_sps() - check for sps sku
*
* Read ME FW Status register to check for SPS Firmware.
* The SPS FW is only signaled in pci function 0
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index b10606550613..dfd60c916da0 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -235,9 +235,8 @@ enum mei_ext_hdr_type {
struct mei_ext_hdr {
u8 type;
u8 length;
- u8 ext_payload[2];
- u8 hdr[];
-};
+ u8 data[];
+} __packed;
/**
* struct mei_ext_meta_hdr - extend header meta data
@@ -250,8 +249,21 @@ struct mei_ext_meta_hdr {
u8 count;
u8 size;
u8 reserved[2];
- struct mei_ext_hdr hdrs[];
-};
+ u8 hdrs[];
+} __packed;
+
+/**
+ * struct mei_ext_hdr_vtag - extend header for vtag
+ *
+ * @hdr: standard extend header
+ * @vtag: virtual tag
+ * @reserved: reserved
+ */
+struct mei_ext_hdr_vtag {
+ struct mei_ext_hdr hdr;
+ u8 vtag;
+ u8 reserved;
+} __packed;
/*
* Extended header iterator functions
@@ -266,7 +278,7 @@ struct mei_ext_meta_hdr {
*/
static inline struct mei_ext_hdr *mei_ext_begin(struct mei_ext_meta_hdr *meta)
{
- return meta->hdrs;
+ return (struct mei_ext_hdr *)meta->hdrs;
}
/**
@@ -284,7 +296,7 @@ static inline bool mei_ext_last(struct mei_ext_meta_hdr *meta,
}
/**
- *mei_ext_next - following extended header on the TLV list
+ * mei_ext_next - following extended header on the TLV list
*
* @ext: current extend header
*
@@ -295,7 +307,7 @@ static inline bool mei_ext_last(struct mei_ext_meta_hdr *meta,
*/
static inline struct mei_ext_hdr *mei_ext_next(struct mei_ext_hdr *ext)
{
- return (struct mei_ext_hdr *)(ext->hdr + (ext->length * 4));
+ return (struct mei_ext_hdr *)((u8 *)ext + (ext->length * 4));
}
/**
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index aab3ebfa9fc4..a67f4f2d33a9 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -123,13 +123,13 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
if (mei_hdr->extended) {
struct mei_ext_hdr *ext;
- struct mei_ext_hdr *vtag = NULL;
+ struct mei_ext_hdr_vtag *vtag_hdr = NULL;
ext = mei_ext_begin(meta);
do {
switch (ext->type) {
case MEI_EXT_HDR_VTAG:
- vtag = ext;
+ vtag_hdr = (struct mei_ext_hdr_vtag *)ext;
break;
case MEI_EXT_HDR_NONE:
fallthrough;
@@ -141,20 +141,20 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
ext = mei_ext_next(ext);
} while (!mei_ext_last(meta, ext));
- if (!vtag) {
+ if (!vtag_hdr) {
cl_dbg(dev, cl, "vtag not found in extended header.\n");
cb->status = -EPROTO;
goto discard;
}
- cl_dbg(dev, cl, "vtag: %d\n", vtag->ext_payload[0]);
- if (cb->vtag && cb->vtag != vtag->ext_payload[0]) {
+ cl_dbg(dev, cl, "vtag: %d\n", vtag_hdr->vtag);
+ if (cb->vtag && cb->vtag != vtag_hdr->vtag) {
cl_err(dev, cl, "mismatched tag: %d != %d\n",
- cb->vtag, vtag->ext_payload[0]);
+ cb->vtag, vtag_hdr->vtag);
cb->status = -EPROTO;
goto discard;
}
- cb->vtag = vtag->ext_payload[0];
+ cb->vtag = vtag_hdr->vtag;
}
if (!mei_cl_is_connected(cl)) {
@@ -331,7 +331,6 @@ int mei_irq_read_handler(struct mei_device *dev,
struct mei_ext_meta_hdr *meta_hdr = NULL;
struct mei_cl *cl;
int ret;
- u32 ext_meta_hdr_u32;
u32 hdr_size_left;
u32 hdr_size_ext;
int i;
@@ -367,14 +366,12 @@ int mei_irq_read_handler(struct mei_device *dev,
if (mei_hdr->extended) {
if (!dev->rd_msg_hdr[1]) {
- ext_meta_hdr_u32 = mei_read_hdr(dev);
- dev->rd_msg_hdr[1] = ext_meta_hdr_u32;
+ dev->rd_msg_hdr[1] = mei_read_hdr(dev);
dev->rd_msg_hdr_count++;
(*slots)--;
- dev_dbg(dev->dev, "extended header is %08x\n",
- ext_meta_hdr_u32);
+ dev_dbg(dev->dev, "extended header is %08x\n", dev->rd_msg_hdr[1]);
}
- meta_hdr = ((struct mei_ext_meta_hdr *)dev->rd_msg_hdr + 1);
+ meta_hdr = ((struct mei_ext_meta_hdr *)&dev->rd_msg_hdr[1]);
if (check_add_overflow((u32)sizeof(*meta_hdr),
mei_slots2data(meta_hdr->size),
&hdr_size_ext)) {
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 28937b6e7e0c..786f7c8f7f61 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -50,8 +50,6 @@ static int mei_open(struct inode *inode, struct file *file)
int err;
dev = container_of(inode->i_cdev, struct mei_device, cdev);
- if (!dev)
- return -ENODEV;
mutex_lock(&dev->device_lock);
@@ -1104,7 +1102,7 @@ static ssize_t dev_state_show(struct device *device,
static DEVICE_ATTR_RO(dev_state);
/**
- * dev_set_devstate: set to new device state and notify sysfs file.
+ * mei_set_devstate: set to new device state and notify sysfs file.
*
* @dev: mei_device
* @state: new device state
diff --git a/drivers/misc/mei/mei-trace.h b/drivers/misc/mei/mei-trace.h
index df758033dc93..fe46ff2b9d69 100644
--- a/drivers/misc/mei/mei-trace.h
+++ b/drivers/misc/mei/mei-trace.h
@@ -26,7 +26,7 @@ TRACE_EVENT(mei_reg_read,
__field(u32, val)
),
TP_fast_assign(
- __assign_str(dev, dev_name(dev))
+ __assign_str(dev, dev_name(dev));
__entry->reg = reg;
__entry->offs = offs;
__entry->val = val;
@@ -45,7 +45,7 @@ TRACE_EVENT(mei_reg_write,
__field(u32, val)
),
TP_fast_assign(
- __assign_str(dev, dev_name(dev))
+ __assign_str(dev, dev_name(dev));
__entry->reg = reg;
__entry->offs = offs;
__entry->val = val;
@@ -64,7 +64,7 @@ TRACE_EVENT(mei_pci_cfg_read,
__field(u32, val)
),
TP_fast_assign(
- __assign_str(dev, dev_name(dev))
+ __assign_str(dev, dev_name(dev));
__entry->reg = reg;
__entry->offs = offs;
__entry->val = val;
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c
index 4bf26ce61044..aec0483b8e72 100644
--- a/drivers/misc/mei/pci-txe.c
+++ b/drivers/misc/mei/pci-txe.c
@@ -156,7 +156,7 @@ end:
}
/**
- * mei_txe_remove - Device Shutdown Routine
+ * mei_txe_shutdown- Device Shutdown Routine
*
* @pdev: PCI device structure
*
diff --git a/drivers/misc/pvpanic/pvpanic-mmio.c b/drivers/misc/pvpanic/pvpanic-mmio.c
index 4c0841776087..be4016084979 100644
--- a/drivers/misc/pvpanic/pvpanic-mmio.c
+++ b/drivers/misc/pvpanic/pvpanic-mmio.c
@@ -93,7 +93,7 @@ static int pvpanic_mmio_probe(struct platform_device *pdev)
return -EINVAL;
}
- pi = kmalloc(sizeof(*pi), GFP_ATOMIC);
+ pi = devm_kmalloc(dev, sizeof(*pi), GFP_KERNEL);
if (!pi)
return -ENOMEM;
@@ -104,19 +104,7 @@ static int pvpanic_mmio_probe(struct platform_device *pdev)
pi->capability &= ioread8(base);
pi->events = pi->capability;
- dev_set_drvdata(dev, pi);
-
- return pvpanic_probe(pi);
-}
-
-static int pvpanic_mmio_remove(struct platform_device *pdev)
-{
- struct pvpanic_instance *pi = dev_get_drvdata(&pdev->dev);
-
- pvpanic_remove(pi);
- kfree(pi);
-
- return 0;
+ return devm_pvpanic_probe(dev, pi);
}
static const struct of_device_id pvpanic_mmio_match[] = {
@@ -139,6 +127,5 @@ static struct platform_driver pvpanic_mmio_driver = {
.dev_groups = pvpanic_mmio_dev_groups,
},
.probe = pvpanic_mmio_probe,
- .remove = pvpanic_mmio_remove,
};
module_platform_driver(pvpanic_mmio_driver);
diff --git a/drivers/misc/pvpanic/pvpanic-pci.c b/drivers/misc/pvpanic/pvpanic-pci.c
index 9ecc4e8559d5..a43c401017ae 100644
--- a/drivers/misc/pvpanic/pvpanic-pci.c
+++ b/drivers/misc/pvpanic/pvpanic-pci.c
@@ -73,20 +73,19 @@ ATTRIBUTE_GROUPS(pvpanic_pci_dev);
static int pvpanic_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- struct device *dev = &pdev->dev;
struct pvpanic_instance *pi;
void __iomem *base;
int ret;
- ret = pci_enable_device(pdev);
+ ret = pcim_enable_device(pdev);
if (ret < 0)
return ret;
- base = pci_iomap(pdev, 0, 0);
+ base = pcim_iomap(pdev, 0, 0);
if (!base)
return -ENOMEM;
- pi = kmalloc(sizeof(*pi), GFP_ATOMIC);
+ pi = devm_kmalloc(&pdev->dev, sizeof(*pi), GFP_KERNEL);
if (!pi)
return -ENOMEM;
@@ -97,26 +96,13 @@ static int pvpanic_pci_probe(struct pci_dev *pdev,
pi->capability &= ioread8(base);
pi->events = pi->capability;
- dev_set_drvdata(dev, pi);
-
- return pvpanic_probe(pi);
-}
-
-static void pvpanic_pci_remove(struct pci_dev *pdev)
-{
- struct pvpanic_instance *pi = dev_get_drvdata(&pdev->dev);
-
- pvpanic_remove(pi);
- iounmap(pi->base);
- kfree(pi);
- pci_disable_device(pdev);
+ return devm_pvpanic_probe(&pdev->dev, pi);
}
static struct pci_driver pvpanic_pci_driver = {
.name = "pvpanic-pci",
.id_table = pvpanic_pci_id_tbl,
.probe = pvpanic_pci_probe,
- .remove = pvpanic_pci_remove,
.driver = {
.dev_groups = pvpanic_pci_dev_groups,
},
diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c
index 65f70a4da8c0..02b807c788c9 100644
--- a/drivers/misc/pvpanic/pvpanic.c
+++ b/drivers/misc/pvpanic/pvpanic.c
@@ -13,6 +13,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/panic_notifier.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/list.h>
@@ -60,25 +61,10 @@ static struct notifier_block pvpanic_panic_nb = {
.priority = 1, /* let this called before broken drm_fb_helper */
};
-int pvpanic_probe(struct pvpanic_instance *pi)
-{
- if (!pi || !pi->base)
- return -EINVAL;
-
- spin_lock(&pvpanic_lock);
- list_add(&pi->list, &pvpanic_list);
- spin_unlock(&pvpanic_lock);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(pvpanic_probe);
-
-void pvpanic_remove(struct pvpanic_instance *pi)
+static void pvpanic_remove(void *param)
{
struct pvpanic_instance *pi_cur, *pi_next;
-
- if (!pi)
- return;
+ struct pvpanic_instance *pi = param;
spin_lock(&pvpanic_lock);
list_for_each_entry_safe(pi_cur, pi_next, &pvpanic_list, list) {
@@ -89,7 +75,19 @@ void pvpanic_remove(struct pvpanic_instance *pi)
}
spin_unlock(&pvpanic_lock);
}
-EXPORT_SYMBOL_GPL(pvpanic_remove);
+
+int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi)
+{
+ if (!pi || !pi->base)
+ return -EINVAL;
+
+ spin_lock(&pvpanic_lock);
+ list_add(&pi->list, &pvpanic_list);
+ spin_unlock(&pvpanic_lock);
+
+ return devm_add_action_or_reset(dev, pvpanic_remove, pi);
+}
+EXPORT_SYMBOL_GPL(devm_pvpanic_probe);
static int pvpanic_init(void)
{
diff --git a/drivers/misc/pvpanic/pvpanic.h b/drivers/misc/pvpanic/pvpanic.h
index 1afccc2e9fec..493545951754 100644
--- a/drivers/misc/pvpanic/pvpanic.h
+++ b/drivers/misc/pvpanic/pvpanic.h
@@ -15,7 +15,6 @@ struct pvpanic_instance {
struct list_head list;
};
-int pvpanic_probe(struct pvpanic_instance *pi);
-void pvpanic_remove(struct pvpanic_instance *pi);
+int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi);
#endif /* PVPANIC_H_ */
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c
index 723825524ea0..d7ef61e602ed 100644
--- a/drivers/misc/sgi-gru/grufault.c
+++ b/drivers/misc/sgi-gru/grufault.c
@@ -49,8 +49,8 @@ struct vm_area_struct *gru_find_vma(unsigned long vaddr)
{
struct vm_area_struct *vma;
- vma = find_vma(current->mm, vaddr);
- if (vma && vma->vm_start <= vaddr && vma->vm_ops == &gru_vm_ops)
+ vma = vma_lookup(current->mm, vaddr);
+ if (vma && vma->vm_ops == &gru_vm_ops)
return vma;
return NULL;
}
diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c
index 202bf951e909..93638ae2753a 100644
--- a/drivers/misc/sram.c
+++ b/drivers/misc/sram.c
@@ -341,6 +341,7 @@ static int sram_probe(struct platform_device *pdev)
{
struct sram_dev *sram;
int ret;
+ struct resource *res;
int (*init_func)(void);
sram = devm_kzalloc(&pdev->dev, sizeof(*sram), GFP_KERNEL);
@@ -349,10 +350,11 @@ static int sram_probe(struct platform_device *pdev)
sram->dev = &pdev->dev;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (of_property_read_bool(pdev->dev.of_node, "no-memory-wc"))
- sram->virt_base = devm_platform_ioremap_resource(pdev, 0);
+ sram->virt_base = devm_ioremap_resource(&pdev->dev, res);
else
- sram->virt_base = devm_platform_ioremap_resource_wc(pdev, 0);
+ sram->virt_base = devm_ioremap_resource_wc(&pdev->dev, res);
if (IS_ERR(sram->virt_base)) {
dev_err(&pdev->dev, "could not map SRAM registers\n");
return PTR_ERR(sram->virt_base);
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 071844b58073..7f6976a9f508 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -52,13 +52,12 @@ static void remove_channel_from_table(struct st_data_s *st_gdata,
*/
int st_get_uart_wr_room(struct st_data_s *st_gdata)
{
- struct tty_struct *tty;
if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) {
pr_err("tty unavailable to perform write");
return -1;
}
- tty = st_gdata->tty;
- return tty->ops->write_room(tty);
+
+ return tty_write_room(st_gdata->tty);
}
/*
@@ -798,7 +797,7 @@ static void st_tty_close(struct tty_struct *tty)
}
static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
- char *tty_flags, int count)
+ const char *tty_flags, int count)
{
#ifdef VERBOSE
print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
@@ -845,6 +844,7 @@ static void st_tty_flush_buffer(struct tty_struct *tty)
}
static struct tty_ldisc_ops st_ldisc_ops = {
+ .num = N_TI_WL,
.name = "n_st",
.open = st_tty_open,
.close = st_tty_close,
@@ -860,7 +860,7 @@ int st_core_init(struct st_data_s **core_data)
struct st_data_s *st_gdata;
long err;
- err = tty_register_ldisc(N_TI_WL, &st_ldisc_ops);
+ err = tty_register_ldisc(&st_ldisc_ops);
if (err) {
pr_err("error registering %d line discipline %ld",
N_TI_WL, err);
@@ -871,11 +871,8 @@ int st_core_init(struct st_data_s **core_data)
st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL);
if (!st_gdata) {
pr_err("memory allocation failed");
- err = tty_unregister_ldisc(N_TI_WL);
- if (err)
- pr_err("unable to un-register ldisc %ld", err);
err = -ENOMEM;
- return err;
+ goto err_unreg_ldisc;
}
/* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's
@@ -890,17 +887,18 @@ int st_core_init(struct st_data_s **core_data)
err = st_ll_init(st_gdata);
if (err) {
pr_err("error during st_ll initialization(%ld)", err);
- kfree(st_gdata);
- err = tty_unregister_ldisc(N_TI_WL);
- if (err)
- pr_err("unable to un-register ldisc");
- return err;
+ goto err_free_gdata;
}
INIT_WORK(&st_gdata->work_write_wakeup, work_fn_write_wakeup);
*core_data = st_gdata;
return 0;
+err_free_gdata:
+ kfree(st_gdata);
+err_unreg_ldisc:
+ tty_unregister_ldisc(&st_ldisc_ops);
+ return err;
}
void st_core_exit(struct st_data_s *st_gdata)
@@ -918,9 +916,7 @@ void st_core_exit(struct st_data_s *st_gdata)
kfree_skb(st_gdata->rx_skb);
kfree_skb(st_gdata->tx_skb);
/* TTY ldisc cleanup */
- err = tty_unregister_ldisc(N_TI_WL);
- if (err)
- pr_err("unable to un-register ldisc %ld", err);
+ tty_unregister_ldisc(&st_ldisc_ops);
/* free the global data pointer */
kfree(st_gdata);
}
diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c
index bae18ef03dcb..488eeb2811ae 100644
--- a/drivers/misc/uacce/uacce.c
+++ b/drivers/misc/uacce/uacce.c
@@ -387,15 +387,22 @@ static void uacce_release(struct device *dev)
static unsigned int uacce_enable_sva(struct device *parent, unsigned int flags)
{
+ int ret;
+
if (!(flags & UACCE_DEV_SVA))
return flags;
flags &= ~UACCE_DEV_SVA;
- if (iommu_dev_enable_feature(parent, IOMMU_DEV_FEAT_IOPF))
+ ret = iommu_dev_enable_feature(parent, IOMMU_DEV_FEAT_IOPF);
+ if (ret) {
+ dev_err(parent, "failed to enable IOPF feature! ret = %pe\n", ERR_PTR(ret));
return flags;
+ }
- if (iommu_dev_enable_feature(parent, IOMMU_DEV_FEAT_SVA)) {
+ ret = iommu_dev_enable_feature(parent, IOMMU_DEV_FEAT_SVA);
+ if (ret) {
+ dev_err(parent, "failed to enable SVA feature! ret = %pe\n", ERR_PTR(ret));
iommu_dev_disable_feature(parent, IOMMU_DEV_FEAT_IOPF);
return flags;
}
diff --git a/drivers/misc/vmw_vmci/vmci_context.c b/drivers/misc/vmw_vmci/vmci_context.c
index 26ff49fdf0f7..c0b5e339d5a1 100644
--- a/drivers/misc/vmw_vmci/vmci_context.c
+++ b/drivers/misc/vmw_vmci/vmci_context.c
@@ -107,7 +107,7 @@ struct vmci_ctx *vmci_ctx_create(u32 cid, u32 priv_flags,
context = kzalloc(sizeof(*context), GFP_KERNEL);
if (!context) {
pr_warn("Failed to allocate memory for VMCI context\n");
- error = -EINVAL;
+ error = -ENOMEM;
goto err_out;
}
diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
index 23c8448a9c3b..d6e3c650bd11 100644
--- a/drivers/misc/xilinx_sdfec.c
+++ b/drivers/misc/xilinx_sdfec.c
@@ -1013,9 +1013,6 @@ static __poll_t xsdfec_poll(struct file *file, poll_table *wait)
xsdfec = container_of(file->private_data, struct xsdfec_dev, miscdev);
- if (!xsdfec)
- return EPOLLNVAL | EPOLLHUP;
-
poll_wait(file, &xsdfec->waitq, wait);
/* XSDFEC ISR detected an error */
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 689eb9afeeed..9890a1532cb0 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Block driver for media (i.e., flash cards)
*
@@ -201,7 +202,7 @@ static void mmc_blk_put(struct mmc_blk_data *md)
md->usage--;
if (md->usage == 0) {
int devidx = mmc_get_devidx(md->disk);
- blk_put_queue(md->queue.queue);
+
ida_simple_remove(&mmc_blk_ida, devidx);
put_disk(md->disk);
kfree(md);
@@ -1004,6 +1005,12 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
switch (mq_rq->drv_op) {
case MMC_DRV_OP_IOCTL:
+ if (card->ext_csd.cmdq_en) {
+ ret = mmc_cmdq_disable(card);
+ if (ret)
+ break;
+ }
+ fallthrough;
case MMC_DRV_OP_IOCTL_RPMB:
idata = mq_rq->drv_op_data;
for (i = 0, ret = 0; i < mq_rq->ioc_count; i++) {
@@ -1014,6 +1021,8 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
/* Always switch back to main area after RPMB access */
if (rpmb_ioctl)
mmc_blk_part_switch(card, 0);
+ else if (card->reenable_cmdq && !card->ext_csd.cmdq_en)
+ mmc_cmdq_enable(card);
break;
case MMC_DRV_OP_BOOT_WP:
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
@@ -1159,7 +1168,7 @@ static void mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
struct mmc_card *card = md->queue.card;
int ret = 0;
- ret = mmc_flush_cache(card);
+ ret = mmc_flush_cache(card->host);
blk_mq_end_request(req, ret ? BLK_STS_IOERR : BLK_STS_OK);
}
@@ -2310,39 +2319,22 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
*/
md->read_only = mmc_blk_readonly(card);
- md->disk = alloc_disk(perdev_minors);
- if (md->disk == NULL) {
- ret = -ENOMEM;
+ md->disk = mmc_init_queue(&md->queue, card);
+ if (IS_ERR(md->disk)) {
+ ret = PTR_ERR(md->disk);
goto err_kfree;
}
INIT_LIST_HEAD(&md->part);
INIT_LIST_HEAD(&md->rpmbs);
md->usage = 1;
-
- ret = mmc_init_queue(&md->queue, card);
- if (ret)
- goto err_putdisk;
-
md->queue.blkdata = md;
- /*
- * Keep an extra reference to the queue so that we can shutdown the
- * queue (i.e. call blk_cleanup_queue()) while there are still
- * references to the 'md'. The corresponding blk_put_queue() is in
- * mmc_blk_put().
- */
- if (!blk_get_queue(md->queue.queue)) {
- mmc_cleanup_queue(&md->queue);
- ret = -ENODEV;
- goto err_putdisk;
- }
-
md->disk->major = MMC_BLOCK_MAJOR;
+ md->disk->minors = perdev_minors;
md->disk->first_minor = devidx * perdev_minors;
md->disk->fops = &mmc_bdops;
md->disk->private_data = md;
- md->disk->queue = md->queue.queue;
md->parent = parent;
set_disk_ro(md->disk, md->read_only || default_ro);
md->disk->flags = GENHD_FL_EXT_DEVT;
@@ -2391,8 +2383,6 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
return md;
- err_putdisk:
- put_disk(md->disk);
err_kfree:
kfree(md);
out:
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index f194940c5974..95fedcf56e4a 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -937,11 +937,14 @@ int mmc_execute_tuning(struct mmc_card *card)
err = host->ops->execute_tuning(host, opcode);
- if (err)
+ if (err) {
pr_err("%s: tuning execution failed: %d\n",
mmc_hostname(host), err);
- else
+ } else {
+ host->retune_now = 0;
+ host->need_retune = 0;
mmc_retune_enable(host);
+ }
return err;
}
@@ -1582,7 +1585,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
{
struct mmc_command cmd = {};
unsigned int qty = 0, busy_timeout = 0;
- bool use_r1b_resp = false;
+ bool use_r1b_resp;
int err;
mmc_retune_hold(card->host);
@@ -1650,23 +1653,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
cmd.opcode = MMC_ERASE;
cmd.arg = arg;
busy_timeout = mmc_erase_timeout(card, arg, qty);
- /*
- * If the host controller supports busy signalling and the timeout for
- * the erase operation does not exceed the max_busy_timeout, we should
- * use R1B response. Or we need to prevent the host from doing hw busy
- * detection, which is done by converting to a R1 response instead.
- * Note, some hosts requires R1B, which also means they are on their own
- * when it comes to deal with the busy timeout.
- */
- if (!(card->host->caps & MMC_CAP_NEED_RSP_BUSY) &&
- card->host->max_busy_timeout &&
- busy_timeout > card->host->max_busy_timeout) {
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
- } else {
- cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
- cmd.busy_timeout = busy_timeout;
- use_r1b_resp = true;
- }
+ use_r1b_resp = mmc_prepare_busy_cmd(card->host, &cmd, busy_timeout);
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) {
@@ -1687,7 +1674,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
goto out;
/* Let's poll to find out when the erase operation completes. */
- err = mmc_poll_for_busy(card, busy_timeout, MMC_BUSY_ERASE);
+ err = mmc_poll_for_busy(card, busy_timeout, false, MMC_BUSY_ERASE);
out:
mmc_retune_release(card->host);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index db3c9c68875d..0c4de2030b3f 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -30,6 +30,7 @@ struct mmc_bus_ops {
int (*hw_reset)(struct mmc_host *);
int (*sw_reset)(struct mmc_host *);
bool (*cache_enabled)(struct mmc_host *);
+ int (*flush_cache)(struct mmc_host *);
};
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -172,4 +173,12 @@ static inline bool mmc_cache_enabled(struct mmc_host *host)
return false;
}
+static inline int mmc_flush_cache(struct mmc_host *host)
+{
+ if (host->bus_ops->flush_cache)
+ return host->bus_ops->flush_cache(host);
+
+ return 0;
+}
+
#endif
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 9ec84c86c46a..3fdbc801e64a 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -26,6 +26,7 @@
static DECLARE_FAULT_ATTR(fail_default_attr);
static char *fail_request;
module_param(fail_request, charp, 0);
+MODULE_PARM_DESC(fail_request, "default fault injection attributes");
#endif /* CONFIG_FAIL_MMC_REQUEST */
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 0b0577990ddc..eda4a1892c33 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -388,6 +388,9 @@ int mmc_of_parse(struct mmc_host *host)
host->caps2 |= MMC_CAP2_NO_SD;
if (device_property_read_bool(dev, "no-mmc"))
host->caps2 |= MMC_CAP2_NO_MMC;
+ if (device_property_read_bool(dev, "no-mmc-hs400"))
+ host->caps2 &= ~(MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V |
+ MMC_CAP2_HS400_ES);
/* Must be after "non-removable" check */
if (device_property_read_u32(dev, "fixed-emmc-driver-type", &drv_type) == 0) {
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 8674c3e0c02c..838726b68ff3 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -28,6 +28,7 @@
#define DEFAULT_CMD6_TIMEOUT_MS 500
#define MIN_CACHE_EN_TIMEOUT_MS 1600
+#define CACHE_FLUSH_TIMEOUT_MS 30000 /* 30s */
static const unsigned int tran_exp[] = {
10000, 100000, 1000000, 10000000,
@@ -1905,11 +1906,20 @@ static int mmc_can_sleep(struct mmc_card *card)
return card->ext_csd.rev >= 3;
}
+static int mmc_sleep_busy_cb(void *cb_data, bool *busy)
+{
+ struct mmc_host *host = cb_data;
+
+ *busy = host->ops->card_busy(host);
+ return 0;
+}
+
static int mmc_sleep(struct mmc_host *host)
{
struct mmc_command cmd = {};
struct mmc_card *card = host->card;
unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000);
+ bool use_r1b_resp;
int err;
/* Re-tuning can't be done once the card is deselected */
@@ -1922,35 +1932,27 @@ static int mmc_sleep(struct mmc_host *host)
cmd.opcode = MMC_SLEEP_AWAKE;
cmd.arg = card->rca << 16;
cmd.arg |= 1 << 15;
-
- /*
- * If the max_busy_timeout of the host is specified, validate it against
- * the sleep cmd timeout. A failure means we need to prevent the host
- * from doing hw busy detection, which is done by converting to a R1
- * response instead of a R1B. Note, some hosts requires R1B, which also
- * means they are on their own when it comes to deal with the busy
- * timeout.
- */
- if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
- (timeout_ms > host->max_busy_timeout)) {
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- } else {
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- cmd.busy_timeout = timeout_ms;
- }
+ use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd, timeout_ms);
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err)
goto out_release;
/*
- * If the host does not wait while the card signals busy, then we will
- * will have to wait the sleep/awake timeout. Note, we cannot use the
- * SEND_STATUS command to poll the status because that command (and most
- * others) is invalid while the card sleeps.
+ * If the host does not wait while the card signals busy, then we can
+ * try to poll, but only if the host supports HW polling, as the
+ * SEND_STATUS cmd is not allowed. If we can't poll, then we simply need
+ * to wait the sleep/awake timeout.
*/
- if (!cmd.busy_timeout || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+ if (host->caps & MMC_CAP_WAIT_WHILE_BUSY && use_r1b_resp)
+ goto out_release;
+
+ if (!host->ops->card_busy) {
mmc_delay(timeout_ms);
+ goto out_release;
+ }
+
+ err = __mmc_poll_for_busy(card, timeout_ms, &mmc_sleep_busy_cb, host);
out_release:
mmc_retune_release(host);
@@ -2035,6 +2037,25 @@ static bool _mmc_cache_enabled(struct mmc_host *host)
host->card->ext_csd.cache_ctrl & 1;
}
+/*
+ * Flush the internal cache of the eMMC to non-volatile storage.
+ */
+static int _mmc_flush_cache(struct mmc_host *host)
+{
+ int err = 0;
+
+ if (_mmc_cache_enabled(host)) {
+ err = mmc_switch(host->card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_FLUSH_CACHE, 1,
+ CACHE_FLUSH_TIMEOUT_MS);
+ if (err)
+ pr_err("%s: cache flush error %d\n",
+ mmc_hostname(host), err);
+ }
+
+ return err;
+}
+
static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
{
int err = 0;
@@ -2046,7 +2067,7 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
if (mmc_card_suspended(host->card))
goto out;
- err = mmc_flush_cache(host->card);
+ err = _mmc_flush_cache(host);
if (err)
goto out;
@@ -2187,7 +2208,7 @@ static int _mmc_hw_reset(struct mmc_host *host)
* In the case of recovery, we can't expect flushing the cache to work
* always, but we have a go and ignore errors.
*/
- mmc_flush_cache(host->card);
+ _mmc_flush_cache(host);
if ((host->caps & MMC_CAP_HW_RESET) && host->ops->hw_reset &&
mmc_can_reset(card)) {
@@ -2215,6 +2236,7 @@ static const struct mmc_bus_ops mmc_ops = {
.shutdown = mmc_shutdown,
.hw_reset = _mmc_hw_reset,
.cache_enabled = _mmc_cache_enabled,
+ .flush_cache = _mmc_flush_cache,
};
/*
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 5756781fef37..973756ed4016 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -20,7 +20,6 @@
#include "mmc_ops.h"
#define MMC_BKOPS_TIMEOUT_MS (120 * 1000) /* 120s */
-#define MMC_CACHE_FLUSH_TIMEOUT_MS (30 * 1000) /* 30s */
#define MMC_SANITIZE_TIMEOUT_MS (240 * 1000) /* 240s */
static const u8 tuning_blk_pattern_4bit[] = {
@@ -53,6 +52,12 @@ static const u8 tuning_blk_pattern_8bit[] = {
0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
};
+struct mmc_busy_data {
+ struct mmc_card *card;
+ bool retry_crc_err;
+ enum mmc_busy_cmd busy_cmd;
+};
+
int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries)
{
int err;
@@ -246,9 +251,8 @@ mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
* NOTE: void *buf, caller for the buf is required to use DMA-capable
* buffer or on-stack buffer (with some overhead in callee).
*/
-static int
-mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
- u32 opcode, void *buf, unsigned len)
+int mmc_send_adtc_data(struct mmc_card *card, struct mmc_host *host, u32 opcode,
+ u32 args, void *buf, unsigned len)
{
struct mmc_request mrq = {};
struct mmc_command cmd = {};
@@ -259,7 +263,7 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
mrq.data = &data;
cmd.opcode = opcode;
- cmd.arg = 0;
+ cmd.arg = args;
/* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we
* rely on callers to never use this with "native" calls for reading
@@ -305,7 +309,7 @@ static int mmc_spi_send_cxd(struct mmc_host *host, u32 *cxd, u32 opcode)
if (!cxd_tmp)
return -ENOMEM;
- ret = mmc_send_cxd_data(NULL, host, opcode, cxd_tmp, 16);
+ ret = mmc_send_adtc_data(NULL, host, opcode, 0, cxd_tmp, 16);
if (ret)
goto err;
@@ -353,7 +357,7 @@ int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
if (!ext_csd)
return -ENOMEM;
- err = mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, ext_csd,
+ err = mmc_send_adtc_data(card, card->host, MMC_SEND_EXT_CSD, 0, ext_csd,
512);
if (err)
kfree(ext_csd);
@@ -424,10 +428,10 @@ int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal)
return mmc_switch_status_error(card->host, status);
}
-static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
- enum mmc_busy_cmd busy_cmd, bool *busy)
+static int mmc_busy_cb(void *cb_data, bool *busy)
{
- struct mmc_host *host = card->host;
+ struct mmc_busy_data *data = cb_data;
+ struct mmc_host *host = data->card->host;
u32 status = 0;
int err;
@@ -436,22 +440,23 @@ static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
return 0;
}
- err = mmc_send_status(card, &status);
- if (retry_crc_err && err == -EILSEQ) {
+ err = mmc_send_status(data->card, &status);
+ if (data->retry_crc_err && err == -EILSEQ) {
*busy = true;
return 0;
}
if (err)
return err;
- switch (busy_cmd) {
+ switch (data->busy_cmd) {
case MMC_BUSY_CMD6:
- err = mmc_switch_status_error(card->host, status);
+ err = mmc_switch_status_error(host, status);
break;
case MMC_BUSY_ERASE:
err = R1_STATUS(status) ? -EIO : 0;
break;
case MMC_BUSY_HPI:
+ case MMC_BUSY_EXTR_SINGLE:
break;
default:
err = -EINVAL;
@@ -464,9 +469,9 @@ static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
return 0;
}
-static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
- bool send_status, bool retry_crc_err,
- enum mmc_busy_cmd busy_cmd)
+int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+ int (*busy_cb)(void *cb_data, bool *busy),
+ void *cb_data)
{
struct mmc_host *host = card->host;
int err;
@@ -475,16 +480,6 @@ static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
bool expired = false;
bool busy = false;
- /*
- * In cases when not allowed to poll by using CMD13 or because we aren't
- * capable of polling by using ->card_busy(), then rely on waiting the
- * stated timeout to be sufficient.
- */
- if (!send_status && !host->ops->card_busy) {
- mmc_delay(timeout_ms);
- return 0;
- }
-
timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1;
do {
/*
@@ -493,7 +488,7 @@ static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
*/
expired = time_after(jiffies, timeout);
- err = mmc_busy_status(card, retry_crc_err, busy_cmd, &busy);
+ err = (*busy_cb)(cb_data, &busy);
if (err)
return err;
@@ -516,9 +511,36 @@ static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
}
int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
- enum mmc_busy_cmd busy_cmd)
+ bool retry_crc_err, enum mmc_busy_cmd busy_cmd)
+{
+ struct mmc_busy_data cb_data;
+
+ cb_data.card = card;
+ cb_data.retry_crc_err = retry_crc_err;
+ cb_data.busy_cmd = busy_cmd;
+
+ return __mmc_poll_for_busy(card, timeout_ms, &mmc_busy_cb, &cb_data);
+}
+
+bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
+ unsigned int timeout_ms)
{
- return __mmc_poll_for_busy(card, timeout_ms, true, false, busy_cmd);
+ /*
+ * If the max_busy_timeout of the host is specified, make sure it's
+ * enough to fit the used timeout_ms. In case it's not, let's instruct
+ * the host to avoid HW busy detection, by converting to a R1 response
+ * instead of a R1B. Note, some hosts requires R1B, which also means
+ * they are on their own when it comes to deal with the busy timeout.
+ */
+ if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
+ (timeout_ms > host->max_busy_timeout)) {
+ cmd->flags = MMC_CMD_AC | MMC_RSP_SPI_R1 | MMC_RSP_R1;
+ return false;
+ }
+
+ cmd->flags = MMC_CMD_AC | MMC_RSP_SPI_R1B | MMC_RSP_R1B;
+ cmd->busy_timeout = timeout_ms;
+ return true;
}
/**
@@ -543,7 +565,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
struct mmc_host *host = card->host;
int err;
struct mmc_command cmd = {};
- bool use_r1b_resp = true;
+ bool use_r1b_resp;
unsigned char old_timing = host->ios.timing;
mmc_retune_hold(host);
@@ -554,29 +576,12 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
timeout_ms = card->ext_csd.generic_cmd6_time;
}
- /*
- * If the max_busy_timeout of the host is specified, make sure it's
- * enough to fit the used timeout_ms. In case it's not, let's instruct
- * the host to avoid HW busy detection, by converting to a R1 response
- * instead of a R1B. Note, some hosts requires R1B, which also means
- * they are on their own when it comes to deal with the busy timeout.
- */
- if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
- (timeout_ms > host->max_busy_timeout))
- use_r1b_resp = false;
-
cmd.opcode = MMC_SWITCH;
cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
(index << 16) |
(value << 8) |
set;
- cmd.flags = MMC_CMD_AC;
- if (use_r1b_resp) {
- cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
- cmd.busy_timeout = timeout_ms;
- } else {
- cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
- }
+ use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd, timeout_ms);
err = mmc_wait_for_cmd(host, &cmd, retries);
if (err)
@@ -587,9 +592,18 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
mmc_host_is_spi(host))
goto out_tim;
+ /*
+ * If the host doesn't support HW polling via the ->card_busy() ops and
+ * when it's not allowed to poll by using CMD13, then we need to rely on
+ * waiting the stated timeout to be sufficient.
+ */
+ if (!send_status && !host->ops->card_busy) {
+ mmc_delay(timeout_ms);
+ goto out_tim;
+ }
+
/* Let's try to poll to find out when the command is completed. */
- err = __mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err,
- MMC_BUSY_CMD6);
+ err = mmc_poll_for_busy(card, timeout_ms, retry_crc_err, MMC_BUSY_CMD6);
if (err)
goto out;
@@ -686,7 +700,7 @@ out:
}
EXPORT_SYMBOL_GPL(mmc_send_tuning);
-int mmc_abort_tuning(struct mmc_host *host, u32 opcode)
+int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode)
{
struct mmc_command cmd = {};
@@ -709,7 +723,7 @@ int mmc_abort_tuning(struct mmc_host *host, u32 opcode)
return mmc_wait_for_cmd(host, &cmd, 0);
}
-EXPORT_SYMBOL_GPL(mmc_abort_tuning);
+EXPORT_SYMBOL_GPL(mmc_send_abort_tuning);
static int
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
@@ -813,28 +827,17 @@ static int mmc_send_hpi_cmd(struct mmc_card *card)
{
unsigned int busy_timeout_ms = card->ext_csd.out_of_int_time;
struct mmc_host *host = card->host;
- bool use_r1b_resp = true;
+ bool use_r1b_resp = false;
struct mmc_command cmd = {};
int err;
cmd.opcode = card->ext_csd.hpi_cmd;
cmd.arg = card->rca << 16 | 1;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- /*
- * Make sure the host's max_busy_timeout fit the needed timeout for HPI.
- * In case it doesn't, let's instruct the host to avoid HW busy
- * detection, by using a R1 response instead of R1B.
- */
- if (host->max_busy_timeout && busy_timeout_ms > host->max_busy_timeout)
- use_r1b_resp = false;
-
- if (cmd.opcode == MMC_STOP_TRANSMISSION && use_r1b_resp) {
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- cmd.busy_timeout = busy_timeout_ms;
- } else {
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- use_r1b_resp = false;
- }
+ if (cmd.opcode == MMC_STOP_TRANSMISSION)
+ use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd,
+ busy_timeout_ms);
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err) {
@@ -848,7 +851,7 @@ static int mmc_send_hpi_cmd(struct mmc_card *card)
return 0;
/* Let's poll to find out when the HPI request completes. */
- return mmc_poll_for_busy(card, busy_timeout_ms, MMC_BUSY_HPI);
+ return mmc_poll_for_busy(card, busy_timeout_ms, false, MMC_BUSY_HPI);
}
/**
@@ -961,26 +964,6 @@ void mmc_run_bkops(struct mmc_card *card)
}
EXPORT_SYMBOL(mmc_run_bkops);
-/*
- * Flush the cache to the non-volatile storage.
- */
-int mmc_flush_cache(struct mmc_card *card)
-{
- int err = 0;
-
- if (mmc_cache_enabled(card->host)) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_FLUSH_CACHE, 1,
- MMC_CACHE_FLUSH_TIMEOUT_MS);
- if (err)
- pr_err("%s: cache flush error %d\n",
- mmc_hostname(card->host), err);
- }
-
- return err;
-}
-EXPORT_SYMBOL(mmc_flush_cache);
-
static int mmc_cmdq_switch(struct mmc_card *card, bool enable)
{
u8 val = enable ? EXT_CSD_CMDQ_MODE_ENABLED : 0;
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 7bc1cfb0654c..41ab4f573a31 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -14,10 +14,12 @@ enum mmc_busy_cmd {
MMC_BUSY_CMD6,
MMC_BUSY_ERASE,
MMC_BUSY_HPI,
+ MMC_BUSY_EXTR_SINGLE,
};
struct mmc_host;
struct mmc_card;
+struct mmc_command;
int mmc_select_card(struct mmc_card *card);
int mmc_deselect_cards(struct mmc_host *host);
@@ -25,6 +27,8 @@ int mmc_set_dsr(struct mmc_host *host);
int mmc_go_idle(struct mmc_host *host);
int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_set_relative_addr(struct mmc_card *card);
+int mmc_send_adtc_data(struct mmc_card *card, struct mmc_host *host, u32 opcode,
+ u32 args, void *buf, unsigned len);
int mmc_send_csd(struct mmc_card *card, u32 *csd);
int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries);
int mmc_send_status(struct mmc_card *card, u32 *status);
@@ -35,15 +39,19 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width);
int mmc_can_ext_csd(struct mmc_card *card);
int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
+bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
+ unsigned int timeout_ms);
+int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+ int (*busy_cb)(void *cb_data, bool *busy),
+ void *cb_data);
int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
- enum mmc_busy_cmd busy_cmd);
+ bool retry_crc_err, enum mmc_busy_cmd busy_cmd);
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms, unsigned char timing,
bool send_status, bool retry_crc_err, unsigned int retries);
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms);
void mmc_run_bkops(struct mmc_card *card);
-int mmc_flush_cache(struct mmc_card *card);
int mmc_cmdq_enable(struct mmc_card *card);
int mmc_cmdq_disable(struct mmc_card *card);
int mmc_sanitize(struct mmc_card *card, unsigned int timeout_ms);
diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c
index d600e0a4a460..cc3261777637 100644
--- a/drivers/mmc/core/queue.c
+++ b/drivers/mmc/core/queue.c
@@ -424,9 +424,10 @@ static inline bool mmc_merge_capable(struct mmc_host *host)
*
* Initialise a MMC card request queue.
*/
-int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card)
+struct gendisk *mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card)
{
struct mmc_host *host = card->host;
+ struct gendisk *disk;
int ret;
mq->card = card;
@@ -464,26 +465,22 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card)
ret = blk_mq_alloc_tag_set(&mq->tag_set);
if (ret)
- return ret;
+ return ERR_PTR(ret);
+
- mq->queue = blk_mq_init_queue(&mq->tag_set);
- if (IS_ERR(mq->queue)) {
- ret = PTR_ERR(mq->queue);
- goto free_tag_set;
+ disk = blk_mq_alloc_disk(&mq->tag_set, mq);
+ if (IS_ERR(disk)) {
+ blk_mq_free_tag_set(&mq->tag_set);
+ return disk;
}
+ mq->queue = disk->queue;
if (mmc_host_is_spi(host) && host->use_spi_crc)
blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, mq->queue);
-
- mq->queue->queuedata = mq;
blk_queue_rq_timeout(mq->queue, 60 * HZ);
mmc_setup_queue(mq, card);
- return 0;
-
-free_tag_set:
- blk_mq_free_tag_set(&mq->tag_set);
- return ret;
+ return disk;
}
void mmc_queue_suspend(struct mmc_queue *mq)
diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h
index 3319d8ab57d0..9ade3bcbb714 100644
--- a/drivers/mmc/core/queue.h
+++ b/drivers/mmc/core/queue.h
@@ -94,7 +94,7 @@ struct mmc_queue {
struct work_struct complete_work;
};
-extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *);
+struct gendisk *mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card);
extern void mmc_cleanup_queue(struct mmc_queue *);
extern void mmc_queue_suspend(struct mmc_queue *);
extern void mmc_queue_resume(struct mmc_queue *);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 2c48d6504101..4646b7a03db6 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -66,6 +66,14 @@ static const unsigned int sd_au_size[] = {
__res & __mask; \
})
+#define SD_POWEROFF_NOTIFY_TIMEOUT_MS 2000
+#define SD_WRITE_EXTR_SINGLE_TIMEOUT_MS 1000
+
+struct sd_busy_data {
+ struct mmc_card *card;
+ u8 *reg_buf;
+};
+
/*
* Given the decoded CSD structure, decode the raw CID to our CID structure.
*/
@@ -222,7 +230,9 @@ static int mmc_decode_scr(struct mmc_card *card)
else
card->erased_byte = 0x0;
- if (scr->sda_spec3)
+ if (scr->sda_spec4)
+ scr->cmds = UNSTUFF_BITS(resp, 32, 4);
+ else if (scr->sda_spec3)
scr->cmds = UNSTUFF_BITS(resp, 32, 2);
/* SD Spec says: any SD Card shall set at least bits 0 and 2 */
@@ -847,11 +857,13 @@ try_again:
return err;
/*
- * In case CCS and S18A in the response is set, start Signal Voltage
- * Switch procedure. SPI mode doesn't support CMD11.
+ * In case the S18A bit is set in the response, let's start the signal
+ * voltage switch procedure. SPI mode doesn't support CMD11.
+ * Note that, according to the spec, the S18A bit is not valid unless
+ * the CCS bit is set as well. We deliberately deviate from the spec in
+ * regards to this, which allows UHS-I to be supported for SDSC cards.
*/
- if (!mmc_host_is_spi(host) && rocr &&
- ((*rocr & 0x41000000) == 0x41000000)) {
+ if (!mmc_host_is_spi(host) && rocr && (*rocr & 0x01000000)) {
err = mmc_set_uhs_voltage(host, pocr);
if (err == -EAGAIN) {
retries--;
@@ -994,6 +1006,380 @@ static bool mmc_sd_card_using_v18(struct mmc_card *card)
(SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
}
+static int sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset,
+ u8 reg_data)
+{
+ struct mmc_host *host = card->host;
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
+ struct scatterlist sg;
+ u8 *reg_buf;
+
+ reg_buf = kzalloc(512, GFP_KERNEL);
+ if (!reg_buf)
+ return -ENOMEM;
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ /*
+ * Arguments of CMD49:
+ * [31:31] MIO (0 = memory).
+ * [30:27] FNO (function number).
+ * [26:26] MW - mask write mode (0 = disable).
+ * [25:18] page number.
+ * [17:9] offset address.
+ * [8:0] length (0 = 1 byte).
+ */
+ cmd.arg = fno << 27 | page << 18 | offset << 9;
+
+ /* The first byte in the buffer is the data to be written. */
+ reg_buf[0] = reg_data;
+
+ data.flags = MMC_DATA_WRITE;
+ data.blksz = 512;
+ data.blocks = 1;
+ data.sg = &sg;
+ data.sg_len = 1;
+ sg_init_one(&sg, reg_buf, 512);
+
+ cmd.opcode = SD_WRITE_EXTR_SINGLE;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ mmc_set_data_timeout(&data, card);
+ mmc_wait_for_req(host, &mrq);
+
+ kfree(reg_buf);
+
+ /*
+ * Note that, the SD card is allowed to signal busy on DAT0 up to 1s
+ * after the CMD49. Although, let's leave this to be managed by the
+ * caller.
+ */
+
+ if (cmd.error)
+ return cmd.error;
+ if (data.error)
+ return data.error;
+
+ return 0;
+}
+
+static int sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page,
+ u16 offset, u16 len, u8 *reg_buf)
+{
+ u32 cmd_args;
+
+ /*
+ * Command arguments of CMD48:
+ * [31:31] MIO (0 = memory).
+ * [30:27] FNO (function number).
+ * [26:26] reserved (0).
+ * [25:18] page number.
+ * [17:9] offset address.
+ * [8:0] length (0 = 1 byte, 1ff = 512 bytes).
+ */
+ cmd_args = fno << 27 | page << 18 | offset << 9 | (len -1);
+
+ return mmc_send_adtc_data(card, card->host, SD_READ_EXTR_SINGLE,
+ cmd_args, reg_buf, 512);
+}
+
+static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
+ u16 offset)
+{
+ int err;
+ u8 *reg_buf;
+
+ reg_buf = kzalloc(512, GFP_KERNEL);
+ if (!reg_buf)
+ return -ENOMEM;
+
+ /* Read the extension register for power management function. */
+ err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
+ if (err) {
+ pr_warn("%s: error %d reading PM func of ext reg\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ /* PM revision consists of 4 bits. */
+ card->ext_power.rev = reg_buf[0] & 0xf;
+
+ /* Power Off Notification support at bit 4. */
+ if (reg_buf[1] & BIT(4))
+ card->ext_power.feature_support |= SD_EXT_POWER_OFF_NOTIFY;
+
+ /* Power Sustenance support at bit 5. */
+ if (reg_buf[1] & BIT(5))
+ card->ext_power.feature_support |= SD_EXT_POWER_SUSTENANCE;
+
+ /* Power Down Mode support at bit 6. */
+ if (reg_buf[1] & BIT(6))
+ card->ext_power.feature_support |= SD_EXT_POWER_DOWN_MODE;
+
+ card->ext_power.fno = fno;
+ card->ext_power.page = page;
+ card->ext_power.offset = offset;
+
+out:
+ kfree(reg_buf);
+ return err;
+}
+
+static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page,
+ u16 offset)
+{
+ int err;
+ u8 *reg_buf;
+
+ reg_buf = kzalloc(512, GFP_KERNEL);
+ if (!reg_buf)
+ return -ENOMEM;
+
+ err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
+ if (err) {
+ pr_warn("%s: error %d reading PERF func of ext reg\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ /* PERF revision. */
+ card->ext_perf.rev = reg_buf[0];
+
+ /* FX_EVENT support at bit 0. */
+ if (reg_buf[1] & BIT(0))
+ card->ext_perf.feature_support |= SD_EXT_PERF_FX_EVENT;
+
+ /* Card initiated self-maintenance support at bit 0. */
+ if (reg_buf[2] & BIT(0))
+ card->ext_perf.feature_support |= SD_EXT_PERF_CARD_MAINT;
+
+ /* Host initiated self-maintenance support at bit 1. */
+ if (reg_buf[2] & BIT(1))
+ card->ext_perf.feature_support |= SD_EXT_PERF_HOST_MAINT;
+
+ /* Cache support at bit 0. */
+ if (reg_buf[4] & BIT(0))
+ card->ext_perf.feature_support |= SD_EXT_PERF_CACHE;
+
+ /* Command queue support indicated via queue depth bits (0 to 4). */
+ if (reg_buf[6] & 0x1f)
+ card->ext_perf.feature_support |= SD_EXT_PERF_CMD_QUEUE;
+
+ card->ext_perf.fno = fno;
+ card->ext_perf.page = page;
+ card->ext_perf.offset = offset;
+
+out:
+ kfree(reg_buf);
+ return err;
+}
+
+static int sd_parse_ext_reg(struct mmc_card *card, u8 *gen_info_buf,
+ u16 *next_ext_addr)
+{
+ u8 num_regs, fno, page;
+ u16 sfc, offset, ext = *next_ext_addr;
+ u32 reg_addr;
+
+ /*
+ * Parse only one register set per extension, as that is sufficient to
+ * support the standard functions. This means another 48 bytes in the
+ * buffer must be available.
+ */
+ if (ext + 48 > 512)
+ return -EFAULT;
+
+ /* Standard Function Code */
+ memcpy(&sfc, &gen_info_buf[ext], 2);
+
+ /* Address to the next extension. */
+ memcpy(next_ext_addr, &gen_info_buf[ext + 40], 2);
+
+ /* Number of registers for this extension. */
+ num_regs = gen_info_buf[ext + 42];
+
+ /* We support only one register per extension. */
+ if (num_regs != 1)
+ return 0;
+
+ /* Extension register address. */
+ memcpy(&reg_addr, &gen_info_buf[ext + 44], 4);
+
+ /* 9 bits (0 to 8) contains the offset address. */
+ offset = reg_addr & 0x1ff;
+
+ /* 8 bits (9 to 16) contains the page number. */
+ page = reg_addr >> 9 & 0xff ;
+
+ /* 4 bits (18 to 21) contains the function number. */
+ fno = reg_addr >> 18 & 0xf;
+
+ /* Standard Function Code for power management. */
+ if (sfc == 0x1)
+ return sd_parse_ext_reg_power(card, fno, page, offset);
+
+ /* Standard Function Code for performance enhancement. */
+ if (sfc == 0x2)
+ return sd_parse_ext_reg_perf(card, fno, page, offset);
+
+ return 0;
+}
+
+static int sd_read_ext_regs(struct mmc_card *card)
+{
+ int err, i;
+ u8 num_ext, *gen_info_buf;
+ u16 rev, len, next_ext_addr;
+
+ if (mmc_host_is_spi(card->host))
+ return 0;
+
+ if (!(card->scr.cmds & SD_SCR_CMD48_SUPPORT))
+ return 0;
+
+ gen_info_buf = kzalloc(512, GFP_KERNEL);
+ if (!gen_info_buf)
+ return -ENOMEM;
+
+ /*
+ * Read 512 bytes of general info, which is found at function number 0,
+ * at page 0 and with no offset.
+ */
+ err = sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf);
+ if (err) {
+ pr_warn("%s: error %d reading general info of SD ext reg\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ /* General info structure revision. */
+ memcpy(&rev, &gen_info_buf[0], 2);
+
+ /* Length of general info in bytes. */
+ memcpy(&len, &gen_info_buf[2], 2);
+
+ /* Number of extensions to be find. */
+ num_ext = gen_info_buf[4];
+
+ /* We support revision 0, but limit it to 512 bytes for simplicity. */
+ if (rev != 0 || len > 512) {
+ pr_warn("%s: non-supported SD ext reg layout\n",
+ mmc_hostname(card->host));
+ goto out;
+ }
+
+ /*
+ * Parse the extension registers. The first extension should start
+ * immediately after the general info header (16 bytes).
+ */
+ next_ext_addr = 16;
+ for (i = 0; i < num_ext; i++) {
+ err = sd_parse_ext_reg(card, gen_info_buf, &next_ext_addr);
+ if (err) {
+ pr_warn("%s: error %d parsing SD ext reg\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+ }
+
+out:
+ kfree(gen_info_buf);
+ return err;
+}
+
+static bool sd_cache_enabled(struct mmc_host *host)
+{
+ return host->card->ext_perf.feature_enabled & SD_EXT_PERF_CACHE;
+}
+
+static int sd_flush_cache(struct mmc_host *host)
+{
+ struct mmc_card *card = host->card;
+ u8 *reg_buf, fno, page;
+ u16 offset;
+ int err;
+
+ if (!sd_cache_enabled(host))
+ return 0;
+
+ reg_buf = kzalloc(512, GFP_KERNEL);
+ if (!reg_buf)
+ return -ENOMEM;
+
+ /*
+ * Set Flush Cache at bit 0 in the performance enhancement register at
+ * 261 bytes offset.
+ */
+ fno = card->ext_perf.fno;
+ page = card->ext_perf.page;
+ offset = card->ext_perf.offset + 261;
+
+ err = sd_write_ext_reg(card, fno, page, offset, BIT(0));
+ if (err) {
+ pr_warn("%s: error %d writing Cache Flush bit\n",
+ mmc_hostname(host), err);
+ goto out;
+ }
+
+ err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false,
+ MMC_BUSY_EXTR_SINGLE);
+ if (err)
+ goto out;
+
+ /*
+ * Read the Flush Cache bit. The card shall reset it, to confirm that
+ * it's has completed the flushing of the cache.
+ */
+ err = sd_read_ext_reg(card, fno, page, offset, 1, reg_buf);
+ if (err) {
+ pr_warn("%s: error %d reading Cache Flush bit\n",
+ mmc_hostname(host), err);
+ goto out;
+ }
+
+ if (reg_buf[0] & BIT(0))
+ err = -ETIMEDOUT;
+out:
+ kfree(reg_buf);
+ return err;
+}
+
+static int sd_enable_cache(struct mmc_card *card)
+{
+ u8 *reg_buf;
+ int err;
+
+ card->ext_perf.feature_enabled &= ~SD_EXT_PERF_CACHE;
+
+ reg_buf = kzalloc(512, GFP_KERNEL);
+ if (!reg_buf)
+ return -ENOMEM;
+
+ /*
+ * Set Cache Enable at bit 0 in the performance enhancement register at
+ * 260 bytes offset.
+ */
+ err = sd_write_ext_reg(card, card->ext_perf.fno, card->ext_perf.page,
+ card->ext_perf.offset + 260, BIT(0));
+ if (err) {
+ pr_warn("%s: error %d writing Cache Enable bit\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false,
+ MMC_BUSY_EXTR_SINGLE);
+ if (!err)
+ card->ext_perf.feature_enabled |= SD_EXT_PERF_CACHE;
+
+out:
+ kfree(reg_buf);
+ return err;
+}
+
/*
* Handle the detection and initialisation of a card.
*
@@ -1142,6 +1528,20 @@ retry:
}
}
+ if (!oldcard) {
+ /* Read/parse the extension registers. */
+ err = sd_read_ext_regs(card);
+ if (err)
+ goto free_card;
+ }
+
+ /* Enable internal SD cache if supported. */
+ if (card->ext_perf.feature_support & SD_EXT_PERF_CACHE) {
+ err = sd_enable_cache(card);
+ if (err)
+ goto free_card;
+ }
+
if (host->cqe_ops && !host->cqe_enabled) {
err = host->cqe_ops->cqe_enable(host, card);
if (!err) {
@@ -1213,21 +1613,84 @@ static void mmc_sd_detect(struct mmc_host *host)
}
}
+static int sd_can_poweroff_notify(struct mmc_card *card)
+{
+ return card->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY;
+}
+
+static int sd_busy_poweroff_notify_cb(void *cb_data, bool *busy)
+{
+ struct sd_busy_data *data = cb_data;
+ struct mmc_card *card = data->card;
+ int err;
+
+ /*
+ * Read the status register for the power management function. It's at
+ * one byte offset and is one byte long. The Power Off Notification
+ * Ready is bit 0.
+ */
+ err = sd_read_ext_reg(card, card->ext_power.fno, card->ext_power.page,
+ card->ext_power.offset + 1, 1, data->reg_buf);
+ if (err) {
+ pr_warn("%s: error %d reading status reg of PM func\n",
+ mmc_hostname(card->host), err);
+ return err;
+ }
+
+ *busy = !(data->reg_buf[0] & BIT(0));
+ return 0;
+}
+
+static int sd_poweroff_notify(struct mmc_card *card)
+{
+ struct sd_busy_data cb_data;
+ u8 *reg_buf;
+ int err;
+
+ reg_buf = kzalloc(512, GFP_KERNEL);
+ if (!reg_buf)
+ return -ENOMEM;
+
+ /*
+ * Set the Power Off Notification bit in the power management settings
+ * register at 2 bytes offset.
+ */
+ err = sd_write_ext_reg(card, card->ext_power.fno, card->ext_power.page,
+ card->ext_power.offset + 2, BIT(0));
+ if (err) {
+ pr_warn("%s: error %d writing Power Off Notify bit\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ cb_data.card = card;
+ cb_data.reg_buf = reg_buf;
+ err = __mmc_poll_for_busy(card, SD_POWEROFF_NOTIFY_TIMEOUT_MS,
+ &sd_busy_poweroff_notify_cb, &cb_data);
+
+out:
+ kfree(reg_buf);
+ return err;
+}
+
static int _mmc_sd_suspend(struct mmc_host *host)
{
+ struct mmc_card *card = host->card;
int err = 0;
mmc_claim_host(host);
- if (mmc_card_suspended(host->card))
+ if (mmc_card_suspended(card))
goto out;
- if (!mmc_host_is_spi(host))
+ if (sd_can_poweroff_notify(card))
+ err = sd_poweroff_notify(card);
+ else if (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host);
if (!err) {
mmc_power_off(host);
- mmc_card_set_suspended(host->card);
+ mmc_card_set_suspended(card);
}
out:
@@ -1331,6 +1794,8 @@ static const struct mmc_bus_ops mmc_sd_ops = {
.alive = mmc_sd_alive,
.shutdown = mmc_sd_suspend,
.hw_reset = mmc_sd_hw_reset,
+ .cache_enabled = sd_cache_enabled,
+ .flush_cache = sd_flush_cache,
};
/*
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index d61ff811218c..ef8d1dce5af1 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -17,6 +17,7 @@
#include "core.h"
#include "sd_ops.h"
+#include "mmc_ops.h"
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
{
@@ -309,43 +310,18 @@ int mmc_app_send_scr(struct mmc_card *card)
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
u8 value, u8 *resp)
{
- struct mmc_request mrq = {};
- struct mmc_command cmd = {};
- struct mmc_data data = {};
- struct scatterlist sg;
+ u32 cmd_args;
/* NOTE: caller guarantees resp is heap-allocated */
mode = !!mode;
value &= 0xF;
+ cmd_args = mode << 31 | 0x00FFFFFF;
+ cmd_args &= ~(0xF << (group * 4));
+ cmd_args |= value << (group * 4);
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- cmd.opcode = SD_SWITCH;
- cmd.arg = mode << 31 | 0x00FFFFFF;
- cmd.arg &= ~(0xF << (group * 4));
- cmd.arg |= value << (group * 4);
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
-
- data.blksz = 64;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- sg_init_one(&sg, resp, 64);
-
- mmc_set_data_timeout(&data, card);
-
- mmc_wait_for_req(card->host, &mrq);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- return 0;
+ return mmc_send_adtc_data(card, card->host, SD_SWITCH, cmd_args, resp,
+ 64);
}
int mmc_app_sd_status(struct mmc_card *card, void *ssr)
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 3eb94ac2712e..68edf7a615be 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -937,11 +937,9 @@ static void mmc_sdio_detect(struct mmc_host *host)
/* Make sure card is powered before detecting it */
if (host->caps & MMC_CAP_POWER_OFF_CARD) {
- err = pm_runtime_get_sync(&host->card->dev);
- if (err < 0) {
- pm_runtime_put_noidle(&host->card->dev);
+ err = pm_runtime_resume_and_get(&host->card->dev);
+ if (err < 0)
goto out;
- }
}
mmc_claim_host(host);
diff --git a/drivers/mmc/core/sdio_uart.c b/drivers/mmc/core/sdio_uart.c
index be4067281caa..c36242b86b1d 100644
--- a/drivers/mmc/core/sdio_uart.c
+++ b/drivers/mmc/core/sdio_uart.c
@@ -439,7 +439,7 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
tty = tty_port_tty_get(&port->port);
if (tty == NULL || !kfifo_len(xmit) ||
- tty->stopped || tty->hw_stopped) {
+ tty->flow.stopped || tty->hw_stopped) {
sdio_uart_stop_tx(port);
tty_kref_put(tty);
return;
@@ -797,13 +797,13 @@ static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf,
return ret;
}
-static int sdio_uart_write_room(struct tty_struct *tty)
+static unsigned int sdio_uart_write_room(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
return FIFO_SIZE - kfifo_len(&port->xmit_fifo);
}
-static int sdio_uart_chars_in_buffer(struct tty_struct *tty)
+static unsigned int sdio_uart_chars_in_buffer(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
return kfifo_len(&port->xmit_fifo);
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index a4d4c757eea0..71313961cc54 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -329,7 +329,7 @@ config MMC_SDHCI_S3C
config MMC_SDHCI_PXAV3
tristate "Marvell MMP2 SD Host Controller support (PXAV3)"
- depends on CLKDEV_LOOKUP
+ depends on HAVE_CLK
depends on MMC_SDHCI_PLTFM
depends on ARCH_BERLIN || ARCH_MMP || ARCH_MVEBU || COMPILE_TEST
default CPU_MMP2
@@ -342,7 +342,7 @@ config MMC_SDHCI_PXAV3
config MMC_SDHCI_PXAV2
tristate "Marvell PXA9XX SD Host Controller support (PXAV2)"
- depends on CLKDEV_LOOKUP
+ depends on HAVE_CLK
depends on MMC_SDHCI_PLTFM
depends on ARCH_MMP || COMPILE_TEST
default CPU_PXA910
@@ -412,7 +412,7 @@ config MMC_SDHCI_MILBEAUT
config MMC_SDHCI_IPROC
tristate "SDHCI support for the BCM2835 & iProc SD/MMC Controller"
- depends on ARCH_BCM2835 || ARCH_BCM_IPROC || COMPILE_TEST
+ depends on ARCH_BCM2835 || ARCH_BCM_IPROC || ARCH_BRCMSTB || COMPILE_TEST
depends on MMC_SDHCI_PLTFM
depends on OF || ACPI
default ARCH_BCM_IPROC
diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c
index 93b0432bb601..38559a956330 100644
--- a/drivers/mmc/host/cqhci-core.c
+++ b/drivers/mmc/host/cqhci-core.c
@@ -45,17 +45,23 @@ static inline u8 *get_link_desc(struct cqhci_host *cq_host, u8 tag)
return desc + cq_host->task_desc_len;
}
+static inline size_t get_trans_desc_offset(struct cqhci_host *cq_host, u8 tag)
+{
+ return cq_host->trans_desc_len * cq_host->mmc->max_segs * tag;
+}
+
static inline dma_addr_t get_trans_desc_dma(struct cqhci_host *cq_host, u8 tag)
{
- return cq_host->trans_desc_dma_base +
- (cq_host->mmc->max_segs * tag *
- cq_host->trans_desc_len);
+ size_t offset = get_trans_desc_offset(cq_host, tag);
+
+ return cq_host->trans_desc_dma_base + offset;
}
static inline u8 *get_trans_desc(struct cqhci_host *cq_host, u8 tag)
{
- return cq_host->trans_desc_base +
- (cq_host->trans_desc_len * cq_host->mmc->max_segs * tag);
+ size_t offset = get_trans_desc_offset(cq_host, tag);
+
+ return cq_host->trans_desc_base + offset;
}
static void setup_trans_desc(struct cqhci_host *cq_host, u8 tag)
@@ -146,7 +152,7 @@ static void cqhci_dumpregs(struct cqhci_host *cq_host)
}
/*
- * The allocated descriptor table for task, link & transfer descritors
+ * The allocated descriptor table for task, link & transfer descriptors
* looks like:
* |----------|
* |task desc | |->|----------|
@@ -194,8 +200,7 @@ static int cqhci_host_alloc_tdl(struct cqhci_host *cq_host)
cq_host->desc_size = cq_host->slot_sz * cq_host->num_slots;
- cq_host->data_size = cq_host->trans_desc_len * cq_host->mmc->max_segs *
- cq_host->mmc->cqe_qdepth;
+ cq_host->data_size = get_trans_desc_offset(cq_host, cq_host->mmc->cqe_qdepth);
pr_debug("%s: cqhci: desc_size: %zu data_sz: %zu slot-sz: %d\n",
mmc_hostname(cq_host->mmc), cq_host->desc_size, cq_host->data_size,
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 73731cd3ba23..9901208be797 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -17,7 +17,6 @@
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/of.h>
-#include <linux/clk.h>
#include "dw_mmc.h"
#include "dw_mmc-pltfm.h"
diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
index b3c636edbb46..cb1a64a5c256 100644
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -674,7 +674,7 @@ static void jz4740_mmc_send_command(struct jz4740_mmc_host *host,
cmdat |= JZ_MMC_CMDAT_WRITE;
if (host->use_dma) {
/*
- * The 4780's MMC controller has integrated DMA ability
+ * The JZ4780's MMC controller has integrated DMA ability
* in addition to being able to use the external DMA
* controller. It moves DMA control bits to a separate
* register. The DMA_SEL bit chooses the external
@@ -789,6 +789,8 @@ static irqreturn_t jz_mmc_irq_worker(int irq, void *devid)
break;
}
}
+ fallthrough;
+
case JZ4740_MMC_STATE_DONE:
break;
}
@@ -866,7 +868,7 @@ static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate)
writew(div, host->base + JZ_REG_MMC_CLKRT);
if (real_rate > 25000000) {
- if (host->version >= JZ_MMC_X1000) {
+ if (host->version >= JZ_MMC_JZ4780) {
writel(JZ_MMC_LPM_DRV_RISING_QTR_PHASE_DLY |
JZ_MMC_LPM_SMP_RISING_QTR_OR_HALF_PHASE_DLY |
JZ_MMC_LPM_LOW_POWER_MODE_EN,
@@ -959,6 +961,7 @@ static const struct of_device_id jz4740_mmc_of_match[] = {
{ .compatible = "ingenic,jz4740-mmc", .data = (void *) JZ_MMC_JZ4740 },
{ .compatible = "ingenic,jz4725b-mmc", .data = (void *)JZ_MMC_JZ4725B },
{ .compatible = "ingenic,jz4760-mmc", .data = (void *) JZ_MMC_JZ4760 },
+ { .compatible = "ingenic,jz4775-mmc", .data = (void *) JZ_MMC_JZ4780 },
{ .compatible = "ingenic,jz4780-mmc", .data = (void *) JZ_MMC_JZ4780 },
{ .compatible = "ingenic,x1000-mmc", .data = (void *) JZ_MMC_X1000 },
{},
@@ -1013,7 +1016,6 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
host->base = devm_ioremap_resource(&pdev->dev, host->mem_res);
if (IS_ERR(host->base)) {
ret = PTR_ERR(host->base);
- dev_err(&pdev->dev, "Failed to ioremap base memory\n");
goto err_free_host;
}
diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
index 016a6106151a..3f28eb4d17fe 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -165,6 +165,7 @@ struct meson_host {
unsigned int bounce_buf_size;
void *bounce_buf;
+ void __iomem *bounce_iomem_buf;
dma_addr_t bounce_dma_addr;
struct sd_emmc_desc *descs;
dma_addr_t descs_dma_addr;
@@ -745,6 +746,47 @@ static void meson_mmc_desc_chain_transfer(struct mmc_host *mmc, u32 cmd_cfg)
writel(start, host->regs + SD_EMMC_START);
}
+/* local sg copy to buffer version with _to/fromio usage for dram_access_quirk */
+static void meson_mmc_copy_buffer(struct meson_host *host, struct mmc_data *data,
+ size_t buflen, bool to_buffer)
+{
+ unsigned int sg_flags = SG_MITER_ATOMIC;
+ struct scatterlist *sgl = data->sg;
+ unsigned int nents = data->sg_len;
+ struct sg_mapping_iter miter;
+ unsigned int offset = 0;
+
+ if (to_buffer)
+ sg_flags |= SG_MITER_FROM_SG;
+ else
+ sg_flags |= SG_MITER_TO_SG;
+
+ sg_miter_start(&miter, sgl, nents, sg_flags);
+
+ while ((offset < buflen) && sg_miter_next(&miter)) {
+ unsigned int len;
+
+ len = min(miter.length, buflen - offset);
+
+ /* When dram_access_quirk, the bounce buffer is a iomem mapping */
+ if (host->dram_access_quirk) {
+ if (to_buffer)
+ memcpy_toio(host->bounce_iomem_buf + offset, miter.addr, len);
+ else
+ memcpy_fromio(miter.addr, host->bounce_iomem_buf + offset, len);
+ } else {
+ if (to_buffer)
+ memcpy(host->bounce_buf + offset, miter.addr, len);
+ else
+ memcpy(miter.addr, host->bounce_buf + offset, len);
+ }
+
+ offset += len;
+ }
+
+ sg_miter_stop(&miter);
+}
+
static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd)
{
struct meson_host *host = mmc_priv(mmc);
@@ -788,8 +830,7 @@ static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd)
if (data->flags & MMC_DATA_WRITE) {
cmd_cfg |= CMD_CFG_DATA_WR;
WARN_ON(xfer_bytes > host->bounce_buf_size);
- sg_copy_to_buffer(data->sg, data->sg_len,
- host->bounce_buf, xfer_bytes);
+ meson_mmc_copy_buffer(host, data, xfer_bytes, true);
dma_wmb();
}
@@ -958,8 +999,7 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
if (meson_mmc_bounce_buf_read(data)) {
xfer_bytes = data->blksz * data->blocks;
WARN_ON(xfer_bytes > host->bounce_buf_size);
- sg_copy_from_buffer(data->sg, data->sg_len,
- host->bounce_buf, xfer_bytes);
+ meson_mmc_copy_buffer(host, data, xfer_bytes, false);
}
next_cmd = meson_mmc_get_next_command(cmd);
@@ -1179,7 +1219,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
* 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_iomem_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 */
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 9776a03a10f5..65c65bb5737f 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -504,7 +504,7 @@ mmc_spi_command_send(struct mmc_spi_host *host,
/* else: R1 (most commands) */
}
- dev_dbg(&host->spi->dev, " mmc_spi: CMD%d, resp %s\n",
+ dev_dbg(&host->spi->dev, " CMD%d, resp %s\n",
cmd->opcode, maptype(cmd));
/* send command, leaving chipselect active */
@@ -928,8 +928,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
while (length) {
t->len = min(length, blk_size);
- dev_dbg(&host->spi->dev,
- " mmc_spi: %s block, %d bytes\n",
+ dev_dbg(&host->spi->dev, " %s block, %d bytes\n",
(direction == DMA_TO_DEVICE) ? "write" : "read",
t->len);
@@ -974,7 +973,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
int tmp;
const unsigned statlen = sizeof(scratch->status);
- dev_dbg(&spi->dev, " mmc_spi: STOP_TRAN\n");
+ dev_dbg(&spi->dev, " STOP_TRAN\n");
/* Tweak the per-block message we set up earlier by morphing
* it to hold single buffer with the token followed by some
@@ -1175,7 +1174,7 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
canpower = host->pdata && host->pdata->setpower;
- dev_dbg(&host->spi->dev, "mmc_spi: power %s (%d)%s\n",
+ dev_dbg(&host->spi->dev, "power %s (%d)%s\n",
mmc_powerstring(ios->power_mode),
ios->vdd,
canpower ? ", can switch" : "");
@@ -1248,8 +1247,7 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->spi->max_speed_hz = ios->clock;
status = spi_setup(host->spi);
- dev_dbg(&host->spi->dev,
- "mmc_spi: clock to %d Hz, %d\n",
+ dev_dbg(&host->spi->dev, " clock to %d Hz, %d\n",
host->spi->max_speed_hz, status);
}
}
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 898ed1b023df..4dfc246c5f95 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -724,10 +724,8 @@ static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma,
writel(lower_32_bits(dma->gpd_addr), host->base + MSDC_DMA_SA);
}
-static void msdc_prepare_data(struct msdc_host *host, struct mmc_request *mrq)
+static void msdc_prepare_data(struct msdc_host *host, struct mmc_data *data)
{
- struct mmc_data *data = mrq->data;
-
if (!(data->host_cookie & MSDC_PREPARE_FLAG)) {
data->host_cookie |= MSDC_PREPARE_FLAG;
data->sg_count = dma_map_sg(host->dev, data->sg, data->sg_len,
@@ -735,10 +733,8 @@ static void msdc_prepare_data(struct msdc_host *host, struct mmc_request *mrq)
}
}
-static void msdc_unprepare_data(struct msdc_host *host, struct mmc_request *mrq)
+static void msdc_unprepare_data(struct msdc_host *host, struct mmc_data *data)
{
- struct mmc_data *data = mrq->data;
-
if (data->host_cookie & MSDC_ASYNC_FLAG)
return;
@@ -1140,7 +1136,7 @@ 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);
+ msdc_unprepare_data(host, mrq->data);
if (host->error)
msdc_reset_hw(host);
mmc_request_done(mmc_from_priv(host), mrq);
@@ -1311,7 +1307,7 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq = mrq;
if (mrq->data)
- msdc_prepare_data(host, mrq);
+ msdc_prepare_data(host, mrq->data);
/* if SBC is required, we have HW option and SW option.
* if HW option is enabled, and SBC does not have "special" flags,
@@ -1332,7 +1328,7 @@ static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
if (!data)
return;
- msdc_prepare_data(host, mrq);
+ msdc_prepare_data(host, data);
data->host_cookie |= MSDC_ASYNC_FLAG;
}
@@ -1340,19 +1336,18 @@ static void msdc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
int err)
{
struct msdc_host *host = mmc_priv(mmc);
- struct mmc_data *data;
+ struct mmc_data *data = mrq->data;
- data = mrq->data;
if (!data)
return;
+
if (data->host_cookie) {
data->host_cookie &= ~MSDC_ASYNC_FLAG;
- msdc_unprepare_data(host, mrq);
+ msdc_unprepare_data(host, data);
}
}
-static void msdc_data_xfer_next(struct msdc_host *host,
- struct mmc_request *mrq, struct mmc_data *data)
+static void msdc_data_xfer_next(struct msdc_host *host, struct mmc_request *mrq)
{
if (mmc_op_multi(mrq->cmd->opcode) && mrq->stop && !mrq->stop->error &&
!mrq->sbc)
@@ -1411,7 +1406,7 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
(int)data->error, data->bytes_xfered);
}
- msdc_data_xfer_next(host, mrq, data);
+ msdc_data_xfer_next(host, mrq);
done = true;
}
return done;
diff --git a/drivers/mmc/host/of_mmc_spi.c b/drivers/mmc/host/of_mmc_spi.c
index 9d480a05f655..3629550528b6 100644
--- a/drivers/mmc/host/of_mmc_spi.c
+++ b/drivers/mmc/host/of_mmc_spi.c
@@ -22,8 +22,8 @@
MODULE_LICENSE("GPL");
struct of_mmc_spi {
- int detect_irq;
struct mmc_spi_platform_data pdata;
+ int detect_irq;
};
static struct of_mmc_spi *to_of_mmc_spi(struct device *dev)
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index baab4c2e1b53..e49ca0f7fe9a 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -704,7 +704,7 @@ static int renesas_sdhi_execute_tuning(struct mmc_host *mmc, u32 opcode)
set_bit(i, priv->smpcmp);
if (cmd_error)
- mmc_abort_tuning(mmc, opcode);
+ mmc_send_abort_tuning(mmc, opcode);
}
ret = renesas_sdhi_select_tuning(host);
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index 0ca6f6d30b75..8d5929a32d34 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -1578,17 +1578,12 @@ static int s3cmci_probe(struct platform_device *pdev)
goto probe_iounmap;
}
- if (request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host)) {
+ if (request_irq(host->irq, s3cmci_irq, IRQF_NO_AUTOEN, DRIVER_NAME, host)) {
dev_err(&pdev->dev, "failed to request mci interrupt.\n");
ret = -ENOENT;
goto probe_iounmap;
}
- /* We get spurious interrupts even when we have set the IMSK
- * register to ignore everything, so use disable_irq() to make
- * ensure we don't lock the system with un-serviceable requests. */
-
- disable_irq(host->irq);
host->irq_state = false;
/* Depending on the dma state, get a DMA channel to use. */
diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index c3fbf8c825c4..8fe65f172a61 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -822,6 +822,17 @@ static const struct dmi_system_id sdhci_acpi_quirks[] = {
},
.driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT,
},
+ {
+ /*
+ * The Toshiba WT8-B's microSD slot always reports the card being
+ * write-protected.
+ */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TOSHIBA ENCORE 2 WT8-B"),
+ },
+ .driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT,
+ },
{} /* Terminating entry */
};
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index b991cf0e60c5..72c0bf0c1887 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -324,11 +324,6 @@ static inline int is_imx53_esdhc(struct pltfm_imx_data *data)
return data->socdata == &esdhc_imx53_data;
}
-static inline int is_imx6q_usdhc(struct pltfm_imx_data *data)
-{
- return data->socdata == &usdhc_imx6q_data;
-}
-
static inline int esdhc_is_usdhc(struct pltfm_imx_data *data)
{
return !!(data->socdata->flags & ESDHC_FLAG_USDHC);
@@ -427,9 +422,6 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
| FIELD_PREP(SDHCI_RETUNING_MODE_MASK,
SDHCI_TUNING_MODE_3);
- if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
- val |= SDHCI_SUPPORT_HS400;
-
/*
* Do not advertise faster UHS modes if there are no
* pinctrl states for 100MHz/200MHz.
@@ -1591,7 +1583,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
- host->quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400;
+ host->mmc->caps2 |= MMC_CAP2_HS400;
if (imx_data->socdata->flags & ESDHC_FLAG_BROKEN_AUTO_CMD23)
host->quirks2 |= SDHCI_QUIRK2_ACMD23_BROKEN;
@@ -1628,6 +1620,14 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
if (err)
goto disable_ahb_clk;
+ /*
+ * Setup the wakeup capability here, let user to decide
+ * whether need to enable this wakeup through sysfs interface.
+ */
+ if ((host->mmc->pm_caps & MMC_PM_KEEP_POWER) &&
+ (host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ))
+ device_set_wakeup_capable(&pdev->dev, true);
+
pm_runtime_set_active(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
pm_runtime_use_autosuspend(&pdev->dev);
diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
index ddeaf8e1f72f..cce390fe9cf3 100644
--- a/drivers/mmc/host/sdhci-iproc.c
+++ b/drivers/mmc/host/sdhci-iproc.c
@@ -286,11 +286,35 @@ static const struct sdhci_iproc_data bcm2711_data = {
.mmc_caps = MMC_CAP_3_3V_DDR,
};
+static const struct sdhci_pltfm_data sdhci_bcm7211a0_pltfm_data = {
+ .quirks = SDHCI_QUIRK_MISSING_CAPS |
+ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+ SDHCI_QUIRK_BROKEN_DMA |
+ SDHCI_QUIRK_BROKEN_ADMA,
+ .ops = &sdhci_iproc_ops,
+};
+
+#define BCM7211A0_BASE_CLK_MHZ 100
+static const struct sdhci_iproc_data bcm7211a0_data = {
+ .pdata = &sdhci_bcm7211a0_pltfm_data,
+ .caps = ((BCM7211A0_BASE_CLK_MHZ / 2) << SDHCI_TIMEOUT_CLK_SHIFT) |
+ (BCM7211A0_BASE_CLK_MHZ << SDHCI_CLOCK_BASE_SHIFT) |
+ ((0x2 << SDHCI_MAX_BLOCK_SHIFT)
+ & SDHCI_MAX_BLOCK_MASK) |
+ SDHCI_CAN_VDD_330 |
+ SDHCI_CAN_VDD_180 |
+ SDHCI_CAN_DO_SUSPEND |
+ SDHCI_CAN_DO_HISPD,
+ .caps1 = SDHCI_DRIVER_TYPE_C |
+ SDHCI_DRIVER_TYPE_D,
+};
+
static const struct of_device_id sdhci_iproc_of_match[] = {
{ .compatible = "brcm,bcm2835-sdhci", .data = &bcm2835_data },
{ .compatible = "brcm,bcm2711-emmc2", .data = &bcm2711_data },
{ .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_cygnus_data},
{ .compatible = "brcm,sdhci-iproc", .data = &iproc_data },
+ { .compatible = "brcm,bcm7211a0-sdhci", .data = &bcm7211a0_data },
{ }
};
MODULE_DEVICE_TABLE(of, sdhci_iproc_of_match);
@@ -384,6 +408,11 @@ err:
return ret;
}
+static void sdhci_iproc_shutdown(struct platform_device *pdev)
+{
+ sdhci_pltfm_suspend(&pdev->dev);
+}
+
static struct platform_driver sdhci_iproc_driver = {
.driver = {
.name = "sdhci-iproc",
@@ -394,6 +423,7 @@ static struct platform_driver sdhci_iproc_driver = {
},
.probe = sdhci_iproc_probe,
.remove = sdhci_pltfm_unregister,
+ .shutdown = sdhci_iproc_shutdown,
};
module_platform_driver(sdhci_iproc_driver);
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index 839965f7c717..0e7c07ed9690 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -1542,6 +1542,8 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
}
}
+ sdhci_get_of_property(pdev);
+
sdhci_arasan->clk_ahb = devm_clk_get(dev, "clk_ahb");
if (IS_ERR(sdhci_arasan->clk_ahb)) {
ret = dev_err_probe(dev, PTR_ERR(sdhci_arasan->clk_ahb),
@@ -1561,14 +1563,22 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
goto err_pltfm_free;
}
+ /* If clock-frequency property is set, use the provided value */
+ if (pltfm_host->clock &&
+ pltfm_host->clock != clk_get_rate(clk_xin)) {
+ ret = clk_set_rate(clk_xin, pltfm_host->clock);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to set SD clock rate\n");
+ goto clk_dis_ahb;
+ }
+ }
+
ret = clk_prepare_enable(clk_xin);
if (ret) {
dev_err(dev, "Unable to enable SD clock.\n");
goto clk_dis_ahb;
}
- sdhci_get_of_property(pdev);
-
if (of_property_read_bool(np, "xlnx,fails-without-test-cd"))
sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_FORCE_CDTEST;
diff --git a/drivers/mmc/host/sdhci-of-aspeed-test.c b/drivers/mmc/host/sdhci-of-aspeed-test.c
index bb67d159b7d8..1ed4f86291f2 100644
--- a/drivers/mmc/host/sdhci-of-aspeed-test.c
+++ b/drivers/mmc/host/sdhci-of-aspeed-test.c
@@ -26,23 +26,23 @@ static void aspeed_sdhci_phase_ddr52(struct kunit *test)
KUNIT_EXPECT_EQ(test, 15,
aspeed_sdhci_phase_to_tap(NULL, rate, 25));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 0,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 0,
aspeed_sdhci_phase_to_tap(NULL, rate, 180));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 0,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 0,
aspeed_sdhci_phase_to_tap(NULL, rate, 181));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 1,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 1,
aspeed_sdhci_phase_to_tap(NULL, rate, 182));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 1,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 1,
aspeed_sdhci_phase_to_tap(NULL, rate, 183));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 2,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 2,
aspeed_sdhci_phase_to_tap(NULL, rate, 184));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 3,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 3,
aspeed_sdhci_phase_to_tap(NULL, rate, 185));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 14,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 14,
aspeed_sdhci_phase_to_tap(NULL, rate, 203));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 15,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 15,
aspeed_sdhci_phase_to_tap(NULL, rate, 204));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 15,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 15,
aspeed_sdhci_phase_to_tap(NULL, rate, 205));
}
@@ -67,21 +67,21 @@ static void aspeed_sdhci_phase_hs200(struct kunit *test)
KUNIT_EXPECT_EQ(test, 15,
aspeed_sdhci_phase_to_tap(NULL, rate, 96));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK,
aspeed_sdhci_phase_to_tap(NULL, rate, 180));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK,
aspeed_sdhci_phase_to_tap(NULL, rate, 185));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 1,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 1,
aspeed_sdhci_phase_to_tap(NULL, rate, 186));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 1,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 1,
aspeed_sdhci_phase_to_tap(NULL, rate, 187));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 14,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 14,
aspeed_sdhci_phase_to_tap(NULL, rate, 269));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 15,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 15,
aspeed_sdhci_phase_to_tap(NULL, rate, 270));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 15,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 15,
aspeed_sdhci_phase_to_tap(NULL, rate, 271));
- KUNIT_EXPECT_EQ(test, (int)ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 15,
+ KUNIT_EXPECT_EQ(test, ASPEED_SDHCI_TAP_PARAM_INVERT_CLK | 15,
aspeed_sdhci_phase_to_tap(NULL, rate, 276));
}
diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c
index d001c51074a0..6e4e132903a6 100644
--- a/drivers/mmc/host/sdhci-of-aspeed.c
+++ b/drivers/mmc/host/sdhci-of-aspeed.c
@@ -31,6 +31,11 @@
#define ASPEED_SDC_S0_PHASE_OUT_EN GENMASK(1, 0)
#define ASPEED_SDC_PHASE_MAX 31
+/* SDIO{10,20} */
+#define ASPEED_SDC_CAP1_1_8V (0 * 32 + 26)
+/* SDIO{14,24} */
+#define ASPEED_SDC_CAP2_SDR104 (1 * 32 + 1)
+
struct aspeed_sdc {
struct clk *clk;
struct resource *res;
@@ -72,6 +77,37 @@ struct aspeed_sdhci {
const struct aspeed_sdhci_phase_desc *phase_desc;
};
+/*
+ * The function sets the mirror register for updating
+ * capbilities of the current slot.
+ *
+ * slot | capability | caps_reg | mirror_reg
+ * -----|-------------|----------|------------
+ * 0 | CAP1_1_8V | SDIO140 | SDIO10
+ * 0 | CAP2_SDR104 | SDIO144 | SDIO14
+ * 1 | CAP1_1_8V | SDIO240 | SDIO20
+ * 1 | CAP2_SDR104 | SDIO244 | SDIO24
+ */
+static void aspeed_sdc_set_slot_capability(struct sdhci_host *host, struct aspeed_sdc *sdc,
+ int capability, bool enable, u8 slot)
+{
+ u32 mirror_reg_offset;
+ u32 cap_val;
+ u8 cap_reg;
+
+ if (slot > 1)
+ return;
+
+ cap_reg = capability / 32;
+ cap_val = sdhci_readl(host, 0x40 + (cap_reg * 4));
+ if (enable)
+ cap_val |= BIT(capability % 32);
+ else
+ cap_val &= ~BIT(capability % 32);
+ mirror_reg_offset = ((slot + 1) * 0x10) + (cap_reg * 4);
+ writel(cap_val, sdc->regs + mirror_reg_offset);
+}
+
static void aspeed_sdc_configure_8bit_mode(struct aspeed_sdc *sdc,
struct aspeed_sdhci *sdhci,
bool bus8)
@@ -150,7 +186,7 @@ static int aspeed_sdhci_phase_to_tap(struct device *dev, unsigned long rate_hz,
tap = div_u64(phase_period_ps, prop_delay_ps);
if (tap > ASPEED_SDHCI_NR_TAPS) {
- dev_warn(dev,
+ dev_dbg(dev,
"Requested out of range phase tap %d for %d degrees of phase compensation at %luHz, clamping to tap %d\n",
tap, phase_deg, rate_hz, ASPEED_SDHCI_NR_TAPS);
tap = ASPEED_SDHCI_NR_TAPS;
@@ -328,6 +364,7 @@ static inline int aspeed_sdhci_calculate_slot(struct aspeed_sdhci *dev,
static int aspeed_sdhci_probe(struct platform_device *pdev)
{
const struct aspeed_sdhci_pdata *aspeed_pdata;
+ struct device_node *np = pdev->dev.of_node;
struct sdhci_pltfm_host *pltfm_host;
struct aspeed_sdhci *dev;
struct sdhci_host *host;
@@ -372,6 +409,17 @@ static int aspeed_sdhci_probe(struct platform_device *pdev)
sdhci_get_of_property(pdev);
+ if (of_property_read_bool(np, "mmc-hs200-1_8v") ||
+ of_property_read_bool(np, "sd-uhs-sdr104")) {
+ aspeed_sdc_set_slot_capability(host, dev->parent, ASPEED_SDC_CAP1_1_8V,
+ true, slot);
+ }
+
+ if (of_property_read_bool(np, "sd-uhs-sdr104")) {
+ aspeed_sdc_set_slot_capability(host, dev->parent, ASPEED_SDC_CAP2_SDR104,
+ true, slot);
+ }
+
pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pltfm_host->clk))
return PTR_ERR(pltfm_host->clk);
diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index 7893fd3599b6..8f4d1f003f65 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -1173,10 +1173,9 @@ static int sdhci_omap_probe(struct platform_device *pdev)
* as part of pm_runtime_get_sync.
*/
pm_runtime_enable(dev);
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret) {
dev_err(dev, "pm_runtime_get_sync failed\n");
- pm_runtime_put_noidle(dev);
goto err_rpm_disable;
}
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index 061618aa247f..4fd99c1e82ba 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -94,7 +94,7 @@
#define PCIE_GLI_9763E_CFG2 0x8A4
#define GLI_9763E_CFG2_L1DLY GENMASK(28, 19)
-#define GLI_9763E_CFG2_L1DLY_MID 0x50
+#define GLI_9763E_CFG2_L1DLY_MID 0x54
#define PCIE_GLI_9763E_MMC_CTRL 0x960
#define GLI_9763E_HS400_SLOW BIT(3)
@@ -847,7 +847,7 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
pci_read_config_dword(pdev, PCIE_GLI_9763E_CFG2, &value);
value &= ~GLI_9763E_CFG2_L1DLY;
- /* set ASPM L1 entry delay to 20us */
+ /* set ASPM L1 entry delay to 21us */
value |= FIELD_PREP(GLI_9763E_CFG2_L1DLY, GLI_9763E_CFG2_L1DLY_MID);
pci_write_config_dword(pdev, PCIE_GLI_9763E_CFG2, value);
diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c
index 5dc36efff47f..11e375579cfb 100644
--- a/drivers/mmc/host/sdhci-sprd.c
+++ b/drivers/mmc/host/sdhci-sprd.c
@@ -393,6 +393,7 @@ static void sdhci_sprd_request_done(struct sdhci_host *host,
static struct sdhci_ops sdhci_sprd_ops = {
.read_l = sdhci_sprd_readl,
.write_l = sdhci_sprd_writel,
+ .write_w = sdhci_sprd_writew,
.write_b = sdhci_sprd_writeb,
.set_clock = sdhci_sprd_set_clock,
.get_max_clock = sdhci_sprd_get_max_clock,
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index bf238ade1602..aba6e10b8605 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1812,6 +1812,10 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
u16 preset = 0;
switch (host->timing) {
+ case MMC_TIMING_MMC_HS:
+ case MMC_TIMING_SD_HS:
+ preset = sdhci_readw(host, SDHCI_PRESET_FOR_HIGH_SPEED);
+ break;
case MMC_TIMING_UHS_SDR12:
preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12);
break;
@@ -2680,7 +2684,7 @@ void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
sdhci_end_tuning(host);
- mmc_abort_tuning(host->mmc, opcode);
+ mmc_send_abort_tuning(host->mmc, opcode);
}
EXPORT_SYMBOL_GPL(sdhci_abort_tuning);
@@ -4072,9 +4076,13 @@ static void sdhci_allocate_bounce_buffer(struct sdhci_host *host)
bounce_size,
DMA_BIDIRECTIONAL);
ret = dma_mapping_error(mmc_dev(mmc), host->bounce_addr);
- if (ret)
+ if (ret) {
+ devm_kfree(mmc_dev(mmc), host->bounce_buffer);
+ host->bounce_buffer = NULL;
/* Again fall back to max_segs == 1 */
return;
+ }
+
host->bounce_buffer_size = bounce_size;
/* Lie about this since we're bouncing */
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 0770c036e2ff..074dc182b184 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -201,8 +201,10 @@
#define SDHCI_CAPABILITIES 0x40
#define SDHCI_TIMEOUT_CLK_MASK GENMASK(5, 0)
+#define SDHCI_TIMEOUT_CLK_SHIFT 0
#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080
#define SDHCI_CLOCK_BASE_MASK GENMASK(13, 8)
+#define SDHCI_CLOCK_BASE_SHIFT 8
#define SDHCI_CLOCK_V3_BASE_MASK GENMASK(15, 8)
#define SDHCI_MAX_BLOCK_MASK 0x00030000
#define SDHCI_MAX_BLOCK_SHIFT 16
@@ -253,6 +255,7 @@
/* 60-FB reserved */
+#define SDHCI_PRESET_FOR_HIGH_SPEED 0x64
#define SDHCI_PRESET_FOR_SDR12 0x66
#define SDHCI_PRESET_FOR_SDR25 0x68
#define SDHCI_PRESET_FOR_SDR50 0x6A
diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c
index 1fad6e442688..f654afbe8e83 100644
--- a/drivers/mmc/host/sdhci_am654.c
+++ b/drivers/mmc/host/sdhci_am654.c
@@ -809,11 +809,9 @@ static int sdhci_am654_probe(struct platform_device *pdev)
/* Clocks are enabled using pm_runtime */
pm_runtime_enable(dev);
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
goto pm_runtime_disable;
- }
base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(base)) {
diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c
index 615f3d008af1..b9b79b1089a0 100644
--- a/drivers/mmc/host/usdhi6rol0.c
+++ b/drivers/mmc/host/usdhi6rol0.c
@@ -1801,6 +1801,7 @@ static int usdhi6_probe(struct platform_device *pdev)
version = usdhi6_read(host, USDHI6_VERSION);
if ((version & 0xfff) != 0xa0d) {
+ ret = -EPERM;
dev_err(dev, "Version not recognized %x\n", version);
goto e_clk_off;
}
diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c
index a1d098560099..c32df5530b94 100644
--- a/drivers/mmc/host/via-sdmmc.c
+++ b/drivers/mmc/host/via-sdmmc.c
@@ -857,6 +857,9 @@ static void via_sdc_data_isr(struct via_crdr_mmc_host *host, u16 intmask)
{
BUG_ON(intmask == 0);
+ if (!host->data)
+ return;
+
if (intmask & VIA_CRDR_SDSTS_DT)
host->data->error = -ETIMEDOUT;
else if (intmask & (VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC))
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index 739cf63ef6e2..4950d10d3a19 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -2279,7 +2279,7 @@ static int vub300_probe(struct usb_interface *interface,
if (retval < 0)
goto error5;
retval =
- usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+ usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
SET_ROM_WAIT_STATES,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
firmware_rom_wait_states, 0x0000, NULL, 0, HZ);
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c
index 99b7986002f0..6a6a2a21d2ed 100644
--- a/drivers/mtd/chips/cfi_util.c
+++ b/drivers/mtd/chips/cfi_util.c
@@ -108,8 +108,8 @@ map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi
#if BITS_PER_LONG >= 64
case 8:
onecmd |= (onecmd << (chip_mode * 32));
-#endif
fallthrough;
+#endif
case 4:
onecmd |= (onecmd << (chip_mode * 16));
fallthrough;
@@ -164,8 +164,8 @@ unsigned long cfi_merge_status(map_word val, struct map_info *map,
#if BITS_PER_LONG >= 64
case 8:
res |= (onestat >> (chip_mode * 32));
-#endif
fallthrough;
+#endif
case 4:
res |= (onestat >> (chip_mode * 16));
fallthrough;
diff --git a/drivers/mtd/chips/chipreg.c b/drivers/mtd/chips/chipreg.c
index ff86373d7d24..a05e103682a4 100644
--- a/drivers/mtd/chips/chipreg.c
+++ b/drivers/mtd/chips/chipreg.c
@@ -31,14 +31,11 @@ void unregister_mtd_chip_driver(struct mtd_chip_driver *drv)
static struct mtd_chip_driver *get_mtd_chip_driver (const char *name)
{
- struct list_head *pos;
struct mtd_chip_driver *ret = NULL, *this;
spin_lock(&chip_drvs_lock);
- list_for_each(pos, &chip_drvs_list) {
- this = list_entry(pos, typeof(*this), list);
-
+ list_for_each_entry(this, &chip_drvs_list, list) {
if (!strcmp(this->name, name)) {
ret = this;
break;
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 0f4c2d823de8..79cb981ececc 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -89,6 +89,12 @@ config MTD_MCHP23K256
platform data, or a device tree description if you want to
specify device partitioning
+config MTD_MCHP48L640
+ tristate "Microchip 48L640 EERAM"
+ depends on SPI_MASTER
+ help
+ This enables access to Microchip 48L640 EERAM chips, using SPI.
+
config MTD_SPEAR_SMI
tristate "SPEAR MTD NOR Support through SMI controller"
depends on PLAT_SPEAR || COMPILE_TEST
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 991c8d12c016..0362cf6bdc67 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_LART) += lart.o
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
obj-$(CONFIG_MTD_MCHP23K256) += mchp23k256.o
+obj-$(CONFIG_MTD_MCHP48L640) += mchp48l640.o
obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o
obj-$(CONFIG_MTD_SST25L) += sst25l.o
obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o
diff --git a/drivers/mtd/devices/mchp48l640.c b/drivers/mtd/devices/mchp48l640.c
new file mode 100644
index 000000000000..efc2003bd13a
--- /dev/null
+++ b/drivers/mtd/devices/mchp48l640.c
@@ -0,0 +1,373 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Microchip 48L640 64 Kb SPI Serial EERAM
+ *
+ * Copyright Heiko Schocher <hs@denx.de>
+ *
+ * datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/20006055B.pdf
+ *
+ * we set continuous mode but reading/writing more bytes than
+ * pagesize seems to bring chip into state where readden values
+ * are wrong ... no idea why.
+ *
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/sizes.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/of_device.h>
+
+struct mchp48_caps {
+ unsigned int size;
+ unsigned int page_size;
+};
+
+struct mchp48l640_flash {
+ struct spi_device *spi;
+ struct mutex lock;
+ struct mtd_info mtd;
+ const struct mchp48_caps *caps;
+};
+
+#define MCHP48L640_CMD_WREN 0x06
+#define MCHP48L640_CMD_WRDI 0x04
+#define MCHP48L640_CMD_WRITE 0x02
+#define MCHP48L640_CMD_READ 0x03
+#define MCHP48L640_CMD_WRSR 0x01
+#define MCHP48L640_CMD_RDSR 0x05
+
+#define MCHP48L640_STATUS_RDY 0x01
+#define MCHP48L640_STATUS_WEL 0x02
+#define MCHP48L640_STATUS_BP0 0x04
+#define MCHP48L640_STATUS_BP1 0x08
+#define MCHP48L640_STATUS_SWM 0x10
+#define MCHP48L640_STATUS_PRO 0x20
+#define MCHP48L640_STATUS_ASE 0x40
+
+#define MCHP48L640_TIMEOUT 100
+
+#define MAX_CMD_SIZE 0x10
+
+#define to_mchp48l640_flash(x) container_of(x, struct mchp48l640_flash, mtd)
+
+static int mchp48l640_mkcmd(struct mchp48l640_flash *flash, u8 cmd, loff_t addr, char *buf)
+{
+ buf[0] = cmd;
+ buf[1] = addr >> 8;
+ buf[2] = addr;
+
+ return 3;
+}
+
+static int mchp48l640_read_status(struct mchp48l640_flash *flash, int *status)
+{
+ unsigned char cmd[2];
+ int ret;
+
+ cmd[0] = MCHP48L640_CMD_RDSR;
+ cmd[1] = 0x00;
+ mutex_lock(&flash->lock);
+ ret = spi_write_then_read(flash->spi, &cmd[0], 1, &cmd[1], 1);
+ mutex_unlock(&flash->lock);
+ if (!ret)
+ *status = cmd[1];
+ dev_dbg(&flash->spi->dev, "read status ret: %d status: %x", ret, *status);
+
+ return ret;
+}
+
+static int mchp48l640_waitforbit(struct mchp48l640_flash *flash, int bit, bool set)
+{
+ int ret, status;
+ unsigned long deadline;
+
+ deadline = jiffies + msecs_to_jiffies(MCHP48L640_TIMEOUT);
+ do {
+ ret = mchp48l640_read_status(flash, &status);
+ dev_dbg(&flash->spi->dev, "read status ret: %d bit: %x %sset status: %x",
+ ret, bit, (set ? "" : "not"), status);
+ if (ret)
+ return ret;
+
+ if (set) {
+ if ((status & bit) == bit)
+ return 0;
+ } else {
+ if ((status & bit) == 0)
+ return 0;
+ }
+
+ usleep_range(1000, 2000);
+ } while (!time_after_eq(jiffies, deadline));
+
+ dev_err(&flash->spi->dev, "Timeout waiting for bit %x %s set in status register.",
+ bit, (set ? "" : "not"));
+ return -ETIMEDOUT;
+}
+
+static int mchp48l640_write_prepare(struct mchp48l640_flash *flash, bool enable)
+{
+ unsigned char cmd[2];
+ int ret;
+
+ if (enable)
+ cmd[0] = MCHP48L640_CMD_WREN;
+ else
+ cmd[0] = MCHP48L640_CMD_WRDI;
+
+ mutex_lock(&flash->lock);
+ ret = spi_write(flash->spi, cmd, 1);
+ mutex_unlock(&flash->lock);
+
+ if (ret)
+ dev_err(&flash->spi->dev, "write %sable failed ret: %d",
+ (enable ? "en" : "dis"), ret);
+
+ dev_dbg(&flash->spi->dev, "write %sable success ret: %d",
+ (enable ? "en" : "dis"), ret);
+ if (enable)
+ return mchp48l640_waitforbit(flash, MCHP48L640_STATUS_WEL, true);
+
+ return ret;
+}
+
+static int mchp48l640_set_mode(struct mchp48l640_flash *flash)
+{
+ unsigned char cmd[2];
+ int ret;
+
+ ret = mchp48l640_write_prepare(flash, true);
+ if (ret)
+ return ret;
+
+ cmd[0] = MCHP48L640_CMD_WRSR;
+ cmd[1] = MCHP48L640_STATUS_PRO;
+
+ mutex_lock(&flash->lock);
+ ret = spi_write(flash->spi, cmd, 2);
+ mutex_unlock(&flash->lock);
+ if (ret)
+ dev_err(&flash->spi->dev, "Could not set continuous mode ret: %d", ret);
+
+ return mchp48l640_waitforbit(flash, MCHP48L640_STATUS_PRO, true);
+}
+
+static int mchp48l640_wait_rdy(struct mchp48l640_flash *flash)
+{
+ return mchp48l640_waitforbit(flash, MCHP48L640_STATUS_RDY, false);
+};
+
+static int mchp48l640_write_page(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const unsigned char *buf)
+{
+ struct mchp48l640_flash *flash = to_mchp48l640_flash(mtd);
+ unsigned char *cmd;
+ int ret;
+ int cmdlen;
+
+ cmd = kmalloc((3 + len), GFP_KERNEL | GFP_DMA);
+ if (!cmd)
+ return -ENOMEM;
+
+ ret = mchp48l640_wait_rdy(flash);
+ if (ret)
+ goto fail;
+
+ ret = mchp48l640_write_prepare(flash, true);
+ if (ret)
+ goto fail;
+
+ mutex_lock(&flash->lock);
+ cmdlen = mchp48l640_mkcmd(flash, MCHP48L640_CMD_WRITE, to, cmd);
+ memcpy(&cmd[cmdlen], buf, len);
+ ret = spi_write(flash->spi, cmd, cmdlen + len);
+ mutex_unlock(&flash->lock);
+ if (!ret)
+ *retlen += len;
+ else
+ goto fail;
+
+ ret = mchp48l640_waitforbit(flash, MCHP48L640_STATUS_WEL, false);
+ if (ret)
+ goto fail;
+
+ kfree(cmd);
+ return 0;
+fail:
+ kfree(cmd);
+ dev_err(&flash->spi->dev, "write fail with: %d", ret);
+ return ret;
+};
+
+static int mchp48l640_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const unsigned char *buf)
+{
+ struct mchp48l640_flash *flash = to_mchp48l640_flash(mtd);
+ int ret;
+ size_t wlen = 0;
+ loff_t woff = to;
+ size_t ws;
+ size_t page_sz = flash->caps->page_size;
+
+ /*
+ * we set PRO bit (page rollover), but writing length > page size
+ * does result in total chaos, so write in 32 byte chunks.
+ */
+ while (wlen < len) {
+ ws = min((len - wlen), page_sz);
+ ret = mchp48l640_write_page(mtd, woff, ws, retlen, &buf[wlen]);
+ if (ret)
+ return ret;
+ wlen += ws;
+ woff += ws;
+ }
+
+ return ret;
+}
+
+static int mchp48l640_read_page(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, unsigned char *buf)
+{
+ struct mchp48l640_flash *flash = to_mchp48l640_flash(mtd);
+ unsigned char *cmd;
+ int ret;
+ int cmdlen;
+
+ cmd = kmalloc((3 + len), GFP_KERNEL | GFP_DMA);
+ if (!cmd)
+ return -ENOMEM;
+
+ ret = mchp48l640_wait_rdy(flash);
+ if (ret)
+ goto fail;
+
+ mutex_lock(&flash->lock);
+ cmdlen = mchp48l640_mkcmd(flash, MCHP48L640_CMD_READ, from, cmd);
+ ret = spi_write_then_read(flash->spi, cmd, cmdlen, buf, len);
+ mutex_unlock(&flash->lock);
+ if (!ret)
+ *retlen += len;
+
+ return ret;
+
+fail:
+ kfree(cmd);
+ dev_err(&flash->spi->dev, "read fail with: %d", ret);
+ return ret;
+}
+
+static int mchp48l640_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, unsigned char *buf)
+{
+ struct mchp48l640_flash *flash = to_mchp48l640_flash(mtd);
+ int ret;
+ size_t wlen = 0;
+ loff_t woff = from;
+ size_t ws;
+ size_t page_sz = flash->caps->page_size;
+
+ /*
+ * we set PRO bit (page rollover), but if read length > page size
+ * does result in total chaos in result ...
+ */
+ while (wlen < len) {
+ ws = min((len - wlen), page_sz);
+ ret = mchp48l640_read_page(mtd, woff, ws, retlen, &buf[wlen]);
+ if (ret)
+ return ret;
+ wlen += ws;
+ woff += ws;
+ }
+
+ return ret;
+};
+
+static const struct mchp48_caps mchp48l640_caps = {
+ .size = SZ_8K,
+ .page_size = 32,
+};
+
+static int mchp48l640_probe(struct spi_device *spi)
+{
+ struct mchp48l640_flash *flash;
+ struct flash_platform_data *data;
+ int err;
+ int status;
+
+ flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
+ if (!flash)
+ return -ENOMEM;
+
+ flash->spi = spi;
+ mutex_init(&flash->lock);
+ spi_set_drvdata(spi, flash);
+
+ err = mchp48l640_read_status(flash, &status);
+ if (err)
+ return err;
+
+ err = mchp48l640_set_mode(flash);
+ if (err)
+ return err;
+
+ data = dev_get_platdata(&spi->dev);
+
+ flash->caps = of_device_get_match_data(&spi->dev);
+ if (!flash->caps)
+ flash->caps = &mchp48l640_caps;
+
+ mtd_set_of_node(&flash->mtd, spi->dev.of_node);
+ flash->mtd.dev.parent = &spi->dev;
+ flash->mtd.type = MTD_RAM;
+ flash->mtd.flags = MTD_CAP_RAM;
+ flash->mtd.writesize = flash->caps->page_size;
+ flash->mtd.size = flash->caps->size;
+ flash->mtd._read = mchp48l640_read;
+ flash->mtd._write = mchp48l640_write;
+
+ err = mtd_device_register(&flash->mtd, data ? data->parts : NULL,
+ data ? data->nr_parts : 0);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int mchp48l640_remove(struct spi_device *spi)
+{
+ struct mchp48l640_flash *flash = spi_get_drvdata(spi);
+
+ return mtd_device_unregister(&flash->mtd);
+}
+
+static const struct of_device_id mchp48l640_of_table[] = {
+ {
+ .compatible = "microchip,48l640",
+ .data = &mchp48l640_caps,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mchp48l640_of_table);
+
+static struct spi_driver mchp48l640_driver = {
+ .driver = {
+ .name = "mchp48l640",
+ .of_match_table = of_match_ptr(mchp48l640_of_table),
+ },
+ .probe = mchp48l640_probe,
+ .remove = mchp48l640_remove,
+};
+
+module_spi_driver(mchp48l640_driver);
+
+MODULE_DESCRIPTION("MTD SPI driver for Microchip 48l640 EERAM chips");
+MODULE_AUTHOR("Heiko Schocher <hs@denx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:mchp48l640");
diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c
index fb4a6aa24543..08f76ff839a7 100644
--- a/drivers/mtd/devices/ms02-nv.c
+++ b/drivers/mtd/devices/ms02-nv.c
@@ -286,7 +286,6 @@ static int __init ms02nv_init(void)
break;
default:
return -ENODEV;
- break;
}
for (i = 0; i < ARRAY_SIZE(ms02nv_addrs); i++)
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 5b04ae6c3057..6ed6c51fac69 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -270,6 +270,7 @@ static int phram_setup(const char *val)
if (len == 0 || erasesize == 0 || erasesize > len
|| erasesize > UINT_MAX || rem) {
parse_err("illegal erasesize or len\n");
+ ret = -EINVAL;
goto error;
}
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c
index af16d3485de0..6276daa296da 100644
--- a/drivers/mtd/inftlmount.c
+++ b/drivers/mtd/inftlmount.c
@@ -259,20 +259,13 @@ static int find_boot_record(struct INFTLrecord *inftl)
/* Memory alloc */
inftl->PUtable = kmalloc_array(inftl->nb_blocks, sizeof(u16),
GFP_KERNEL);
- if (!inftl->PUtable) {
- printk(KERN_WARNING "INFTL: allocation of PUtable "
- "failed (%zd bytes)\n",
- inftl->nb_blocks * sizeof(u16));
+ if (!inftl->PUtable)
return -ENOMEM;
- }
inftl->VUtable = kmalloc_array(inftl->nb_blocks, sizeof(u16),
GFP_KERNEL);
if (!inftl->VUtable) {
kfree(inftl->PUtable);
- printk(KERN_WARNING "INFTL: allocation of VUtable "
- "failed (%zd bytes)\n",
- inftl->nb_blocks * sizeof(u16));
return -ENOMEM;
}
@@ -330,7 +323,7 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
buf = kmalloc(SECTORSIZE + mtd->oobsize, GFP_KERNEL);
if (!buf)
- return -1;
+ return -ENOMEM;
ret = -1;
for (i = 0; i < len; i += SECTORSIZE) {
@@ -558,12 +551,8 @@ int INFTL_mount(struct INFTLrecord *s)
/* Temporary buffer to store ANAC numbers. */
ANACtable = kcalloc(s->nb_blocks, sizeof(u8), GFP_KERNEL);
- if (!ANACtable) {
- printk(KERN_WARNING "INFTL: allocation of ANACtable "
- "failed (%zd bytes)\n",
- s->nb_blocks * sizeof(u8));
+ if (!ANACtable)
return -ENOMEM;
- }
/*
* First pass is to explore each physical unit, and construct the
diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c
index 42a95ba40f2c..281fcbaa74e7 100644
--- a/drivers/mtd/maps/amd76xrom.c
+++ b/drivers/mtd/maps/amd76xrom.c
@@ -189,10 +189,8 @@ static int amd76xrom_init_one(struct pci_dev *pdev,
if (!map) {
map = kmalloc(sizeof(*map), GFP_KERNEL);
- }
- if (!map) {
- printk(KERN_ERR MOD_NAME ": kmalloc failed");
- goto out;
+ if (!map)
+ goto out;
}
memset(map, 0, sizeof(*map));
INIT_LIST_HEAD(&map->list);
diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c
index 460494212f6a..c0216bc740cc 100644
--- a/drivers/mtd/maps/ck804xrom.c
+++ b/drivers/mtd/maps/ck804xrom.c
@@ -217,12 +217,10 @@ static int __init ck804xrom_init_one(struct pci_dev *pdev,
unsigned long offset;
int i;
- if (!map)
- map = kmalloc(sizeof(*map), GFP_KERNEL);
-
if (!map) {
- printk(KERN_ERR MOD_NAME ": kmalloc failed");
- goto out;
+ map = kmalloc(sizeof(*map), GFP_KERNEL);
+ if (!map)
+ goto out;
}
memset(map, 0, sizeof(*map));
INIT_LIST_HEAD(&map->list);
diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c
index 85e14150a073..15d5b76ff504 100644
--- a/drivers/mtd/maps/esb2rom.c
+++ b/drivers/mtd/maps/esb2rom.c
@@ -277,11 +277,10 @@ static int __init esb2rom_init_one(struct pci_dev *pdev,
unsigned long offset;
int i;
- if (!map)
- map = kmalloc(sizeof(*map), GFP_KERNEL);
if (!map) {
- printk(KERN_ERR MOD_NAME ": kmalloc failed");
- goto out;
+ map = kmalloc(sizeof(*map), GFP_KERNEL);
+ if (!map)
+ goto out;
}
memset(map, 0, sizeof(*map));
INIT_LIST_HEAD(&map->list);
diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c
index fda72c5fd8f9..c8b2793691db 100644
--- a/drivers/mtd/maps/ichxrom.c
+++ b/drivers/mtd/maps/ichxrom.c
@@ -213,10 +213,8 @@ static int __init ichxrom_init_one(struct pci_dev *pdev,
if (!map) {
map = kmalloc(sizeof(*map), GFP_KERNEL);
- }
- if (!map) {
- printk(KERN_ERR MOD_NAME ": kmalloc failed");
- goto out;
+ if (!map)
+ goto out;
}
memset(map, 0, sizeof(*map));
INIT_LIST_HEAD(&map->list);
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c
index 0bec7c791d17..cedd8ef9a6bf 100644
--- a/drivers/mtd/maps/plat-ram.c
+++ b/drivers/mtd/maps/plat-ram.c
@@ -127,7 +127,6 @@ static int platram_probe(struct platform_device *pdev)
info->map.virt = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(info->map.virt)) {
err = PTR_ERR(info->map.virt);
- dev_err(&pdev->dev, "failed to ioremap() region\n");
goto exit_free;
}
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c
index f9cfb084c029..6c0c91bfec05 100644
--- a/drivers/mtd/maps/sun_uflash.c
+++ b/drivers/mtd/maps/sun_uflash.c
@@ -62,10 +62,8 @@ int uflash_devinit(struct platform_device *op, struct device_node *dp)
}
up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL);
- if (!up) {
- printk(KERN_ERR PFX "Cannot allocate struct uflash_dev\n");
+ if (!up)
return -ENOMEM;
- }
/* copy defaults and tweak parameters */
memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ));
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index fb8e12d590a1..6ce4bc57f919 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -30,11 +30,9 @@ static void blktrans_dev_release(struct kref *kref)
struct mtd_blktrans_dev *dev =
container_of(kref, struct mtd_blktrans_dev, ref);
- dev->disk->private_data = NULL;
- blk_cleanup_queue(dev->rq);
+ blk_cleanup_disk(dev->disk);
blk_mq_free_tag_set(dev->tag_set);
kfree(dev->tag_set);
- put_disk(dev->disk);
list_del(&dev->list);
kfree(dev);
}
@@ -354,7 +352,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
if (new->devnum > (MINORMASK >> tr->part_bits) ||
(tr->part_bits && new->devnum >= 27 * 26)) {
mutex_unlock(&blktrans_ref_mutex);
- goto error1;
+ return ret;
}
list_add_tail(&new->list, &tr->devs);
@@ -366,17 +364,29 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
if (!tr->writesect)
new->readonly = 1;
- /* Create gendisk */
ret = -ENOMEM;
- gd = alloc_disk(1 << tr->part_bits);
+ new->tag_set = kzalloc(sizeof(*new->tag_set), GFP_KERNEL);
+ if (!new->tag_set)
+ goto out_list_del;
- if (!gd)
- goto error2;
+ ret = blk_mq_alloc_sq_tag_set(new->tag_set, &mtd_mq_ops, 2,
+ BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING);
+ if (ret)
+ goto out_kfree_tag_set;
+
+ /* Create gendisk */
+ gd = blk_mq_alloc_disk(new->tag_set, new);
+ if (IS_ERR(gd)) {
+ ret = PTR_ERR(gd);
+ goto out_free_tag_set;
+ }
new->disk = gd;
+ new->rq = new->disk->queue;
gd->private_data = new;
gd->major = tr->major;
gd->first_minor = (new->devnum) << tr->part_bits;
+ gd->minors = 1 << tr->part_bits;
gd->fops = &mtd_block_ops;
if (tr->part_bits)
@@ -398,22 +408,9 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
spin_lock_init(&new->queue_lock);
INIT_LIST_HEAD(&new->rq_list);
- new->tag_set = kzalloc(sizeof(*new->tag_set), GFP_KERNEL);
- if (!new->tag_set)
- goto error3;
-
- new->rq = blk_mq_init_sq_queue(new->tag_set, &mtd_mq_ops, 2,
- BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING);
- if (IS_ERR(new->rq)) {
- ret = PTR_ERR(new->rq);
- new->rq = NULL;
- goto error4;
- }
-
if (tr->flush)
blk_queue_write_cache(new->rq, true, false);
- new->rq->queuedata = new;
blk_queue_logical_block_size(new->rq, tr->blksize);
blk_queue_flag_set(QUEUE_FLAG_NONROT, new->rq);
@@ -437,13 +434,13 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
WARN_ON(ret);
}
return 0;
-error4:
+
+out_free_tag_set:
+ blk_mq_free_tag_set(new->tag_set);
+out_kfree_tag_set:
kfree(new->tag_set);
-error3:
- put_disk(new->disk);
-error2:
+out_list_del:
list_del(&new->list);
-error1:
return ret;
}
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 9aaeadd53eb4..b5ccd3037788 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -96,6 +96,12 @@ static void mtd_release(struct device *dev)
device_destroy(&mtd_class, index + 1);
}
+#define MTD_DEVICE_ATTR_RO(name) \
+static DEVICE_ATTR(name, 0444, mtd_##name##_show, NULL)
+
+#define MTD_DEVICE_ATTR_RW(name) \
+static DEVICE_ATTR(name, 0644, mtd_##name##_show, mtd_##name##_store)
+
static ssize_t mtd_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -131,46 +137,45 @@ static ssize_t mtd_type_show(struct device *dev,
type = "unknown";
}
- return snprintf(buf, PAGE_SIZE, "%s\n", type);
+ return sysfs_emit(buf, "%s\n", type);
}
-static DEVICE_ATTR(type, S_IRUGO, mtd_type_show, NULL);
+MTD_DEVICE_ATTR_RO(type);
static ssize_t mtd_flags_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)mtd->flags);
+ return sysfs_emit(buf, "0x%lx\n", (unsigned long)mtd->flags);
}
-static DEVICE_ATTR(flags, S_IRUGO, mtd_flags_show, NULL);
+MTD_DEVICE_ATTR_RO(flags);
static ssize_t mtd_size_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%llu\n",
- (unsigned long long)mtd->size);
+ return sysfs_emit(buf, "%llu\n", (unsigned long long)mtd->size);
}
-static DEVICE_ATTR(size, S_IRUGO, mtd_size_show, NULL);
+MTD_DEVICE_ATTR_RO(size);
static ssize_t mtd_erasesize_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->erasesize);
+ return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->erasesize);
}
-static DEVICE_ATTR(erasesize, S_IRUGO, mtd_erasesize_show, NULL);
+MTD_DEVICE_ATTR_RO(erasesize);
static ssize_t mtd_writesize_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->writesize);
+ return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->writesize);
}
-static DEVICE_ATTR(writesize, S_IRUGO, mtd_writesize_show, NULL);
+MTD_DEVICE_ATTR_RO(writesize);
static ssize_t mtd_subpagesize_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -178,55 +183,54 @@ static ssize_t mtd_subpagesize_show(struct device *dev,
struct mtd_info *mtd = dev_get_drvdata(dev);
unsigned int subpagesize = mtd->writesize >> mtd->subpage_sft;
- return snprintf(buf, PAGE_SIZE, "%u\n", subpagesize);
+ return sysfs_emit(buf, "%u\n", subpagesize);
}
-static DEVICE_ATTR(subpagesize, S_IRUGO, mtd_subpagesize_show, NULL);
+MTD_DEVICE_ATTR_RO(subpagesize);
static ssize_t mtd_oobsize_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->oobsize);
+ return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->oobsize);
}
-static DEVICE_ATTR(oobsize, S_IRUGO, mtd_oobsize_show, NULL);
+MTD_DEVICE_ATTR_RO(oobsize);
static ssize_t mtd_oobavail_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%u\n", mtd->oobavail);
+ return sysfs_emit(buf, "%u\n", mtd->oobavail);
}
-static DEVICE_ATTR(oobavail, S_IRUGO, mtd_oobavail_show, NULL);
+MTD_DEVICE_ATTR_RO(oobavail);
static ssize_t mtd_numeraseregions_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%u\n", mtd->numeraseregions);
+ return sysfs_emit(buf, "%u\n", mtd->numeraseregions);
}
-static DEVICE_ATTR(numeraseregions, S_IRUGO, mtd_numeraseregions_show,
- NULL);
+MTD_DEVICE_ATTR_RO(numeraseregions);
static ssize_t mtd_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n", mtd->name);
+ return sysfs_emit(buf, "%s\n", mtd->name);
}
-static DEVICE_ATTR(name, S_IRUGO, mtd_name_show, NULL);
+MTD_DEVICE_ATTR_RO(name);
static ssize_t mtd_ecc_strength_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_strength);
+ return sysfs_emit(buf, "%u\n", mtd->ecc_strength);
}
-static DEVICE_ATTR(ecc_strength, S_IRUGO, mtd_ecc_strength_show, NULL);
+MTD_DEVICE_ATTR_RO(ecc_strength);
static ssize_t mtd_bitflip_threshold_show(struct device *dev,
struct device_attribute *attr,
@@ -234,7 +238,7 @@ static ssize_t mtd_bitflip_threshold_show(struct device *dev,
{
struct mtd_info *mtd = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%u\n", mtd->bitflip_threshold);
+ return sysfs_emit(buf, "%u\n", mtd->bitflip_threshold);
}
static ssize_t mtd_bitflip_threshold_store(struct device *dev,
@@ -252,60 +256,57 @@ static ssize_t mtd_bitflip_threshold_store(struct device *dev,
mtd->bitflip_threshold = bitflip_threshold;
return count;
}
-static DEVICE_ATTR(bitflip_threshold, S_IRUGO | S_IWUSR,
- mtd_bitflip_threshold_show,
- mtd_bitflip_threshold_store);
+MTD_DEVICE_ATTR_RW(bitflip_threshold);
static ssize_t mtd_ecc_step_size_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_step_size);
+ return sysfs_emit(buf, "%u\n", mtd->ecc_step_size);
}
-static DEVICE_ATTR(ecc_step_size, S_IRUGO, mtd_ecc_step_size_show, NULL);
+MTD_DEVICE_ATTR_RO(ecc_step_size);
-static ssize_t mtd_ecc_stats_corrected_show(struct device *dev,
+static ssize_t mtd_corrected_bits_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats;
- return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stats->corrected);
+ return sysfs_emit(buf, "%u\n", ecc_stats->corrected);
}
-static DEVICE_ATTR(corrected_bits, S_IRUGO,
- mtd_ecc_stats_corrected_show, NULL);
+MTD_DEVICE_ATTR_RO(corrected_bits); /* ecc stats corrected */
-static ssize_t mtd_ecc_stats_errors_show(struct device *dev,
+static ssize_t mtd_ecc_failures_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats;
- return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stats->failed);
+ return sysfs_emit(buf, "%u\n", ecc_stats->failed);
}
-static DEVICE_ATTR(ecc_failures, S_IRUGO, mtd_ecc_stats_errors_show, NULL);
+MTD_DEVICE_ATTR_RO(ecc_failures); /* ecc stats errors */
-static ssize_t mtd_badblocks_show(struct device *dev,
+static ssize_t mtd_bad_blocks_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats;
- return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stats->badblocks);
+ return sysfs_emit(buf, "%u\n", ecc_stats->badblocks);
}
-static DEVICE_ATTR(bad_blocks, S_IRUGO, mtd_badblocks_show, NULL);
+MTD_DEVICE_ATTR_RO(bad_blocks);
-static ssize_t mtd_bbtblocks_show(struct device *dev,
+static ssize_t mtd_bbt_blocks_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
struct mtd_ecc_stats *ecc_stats = &mtd->ecc_stats;
- return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stats->bbtblocks);
+ return sysfs_emit(buf, "%u\n", ecc_stats->bbtblocks);
}
-static DEVICE_ATTR(bbt_blocks, S_IRUGO, mtd_bbtblocks_show, NULL);
+MTD_DEVICE_ATTR_RO(bbt_blocks);
static struct attribute *mtd_attrs[] = {
&dev_attr_type.attr,
@@ -361,6 +362,7 @@ static struct dentry *dfs_dir_mtd;
static void mtd_debugfs_populate(struct mtd_info *mtd)
{
+ struct mtd_info *master = mtd_get_master(mtd);
struct device *dev = &mtd->dev;
struct dentry *root;
@@ -370,12 +372,12 @@ static void mtd_debugfs_populate(struct mtd_info *mtd)
root = debugfs_create_dir(dev_name(dev), dfs_dir_mtd);
mtd->dbg.dfs_dir = root;
- if (mtd->dbg.partid)
- debugfs_create_file("partid", 0400, root, mtd,
+ if (master->dbg.partid)
+ debugfs_create_file("partid", 0400, root, master,
&mtd_partid_debug_fops);
- if (mtd->dbg.partname)
- debugfs_create_file("partname", 0400, root, mtd,
+ if (master->dbg.partname)
+ debugfs_create_file("partname", 0400, root, master,
&mtd_partname_debug_fops);
}
@@ -777,6 +779,148 @@ static void mtd_set_dev_defaults(struct mtd_info *mtd)
mutex_init(&mtd->master.chrdev_lock);
}
+static ssize_t mtd_otp_size(struct mtd_info *mtd, bool is_user)
+{
+ struct otp_info *info;
+ ssize_t size = 0;
+ unsigned int i;
+ size_t retlen;
+ int ret;
+
+ info = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ if (is_user)
+ ret = mtd_get_user_prot_info(mtd, PAGE_SIZE, &retlen, info);
+ else
+ ret = mtd_get_fact_prot_info(mtd, PAGE_SIZE, &retlen, info);
+ if (ret)
+ goto err;
+
+ for (i = 0; i < retlen / sizeof(*info); i++)
+ size += info[i].length;
+
+ kfree(info);
+ return size;
+
+err:
+ kfree(info);
+ return ret;
+}
+
+static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd,
+ const char *compatible,
+ int size,
+ nvmem_reg_read_t reg_read)
+{
+ struct nvmem_device *nvmem = NULL;
+ struct nvmem_config config = {};
+ struct device_node *np;
+
+ /* DT binding is optional */
+ np = of_get_compatible_child(mtd->dev.of_node, compatible);
+
+ /* OTP nvmem will be registered on the physical device */
+ config.dev = mtd->dev.parent;
+ /* just reuse the compatible as name */
+ config.name = compatible;
+ config.id = NVMEM_DEVID_NONE;
+ config.owner = THIS_MODULE;
+ config.type = NVMEM_TYPE_OTP;
+ config.root_only = true;
+ config.reg_read = reg_read;
+ config.size = size;
+ config.of_node = np;
+ config.priv = mtd;
+
+ nvmem = nvmem_register(&config);
+ /* Just ignore if there is no NVMEM support in the kernel */
+ if (IS_ERR(nvmem) && PTR_ERR(nvmem) == -EOPNOTSUPP)
+ nvmem = NULL;
+
+ of_node_put(np);
+
+ return nvmem;
+}
+
+static int mtd_nvmem_user_otp_reg_read(void *priv, unsigned int offset,
+ void *val, size_t bytes)
+{
+ struct mtd_info *mtd = priv;
+ size_t retlen;
+ int ret;
+
+ ret = mtd_read_user_prot_reg(mtd, offset, bytes, &retlen, val);
+ if (ret)
+ return ret;
+
+ return retlen == bytes ? 0 : -EIO;
+}
+
+static int mtd_nvmem_fact_otp_reg_read(void *priv, unsigned int offset,
+ void *val, size_t bytes)
+{
+ struct mtd_info *mtd = priv;
+ size_t retlen;
+ int ret;
+
+ ret = mtd_read_fact_prot_reg(mtd, offset, bytes, &retlen, val);
+ if (ret)
+ return ret;
+
+ return retlen == bytes ? 0 : -EIO;
+}
+
+static int mtd_otp_nvmem_add(struct mtd_info *mtd)
+{
+ struct nvmem_device *nvmem;
+ ssize_t size;
+ int err;
+
+ if (mtd->_get_user_prot_info && mtd->_read_user_prot_reg) {
+ size = mtd_otp_size(mtd, true);
+ if (size < 0)
+ return size;
+
+ if (size > 0) {
+ nvmem = mtd_otp_nvmem_register(mtd, "user-otp", size,
+ mtd_nvmem_user_otp_reg_read);
+ if (IS_ERR(nvmem)) {
+ dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n");
+ return PTR_ERR(nvmem);
+ }
+ mtd->otp_user_nvmem = nvmem;
+ }
+ }
+
+ if (mtd->_get_fact_prot_info && mtd->_read_fact_prot_reg) {
+ size = mtd_otp_size(mtd, false);
+ if (size < 0) {
+ err = size;
+ goto err;
+ }
+
+ if (size > 0) {
+ nvmem = mtd_otp_nvmem_register(mtd, "factory-otp", size,
+ mtd_nvmem_fact_otp_reg_read);
+ if (IS_ERR(nvmem)) {
+ dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n");
+ err = PTR_ERR(nvmem);
+ goto err;
+ }
+ mtd->otp_factory_nvmem = nvmem;
+ }
+ }
+
+ return 0;
+
+err:
+ if (mtd->otp_user_nvmem)
+ nvmem_unregister(mtd->otp_user_nvmem);
+ return err;
+}
+
/**
* mtd_device_parse_register - parse partitions and register an MTD device.
*
@@ -852,6 +996,8 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
register_reboot_notifier(&mtd->reboot_notifier);
}
+ ret = mtd_otp_nvmem_add(mtd);
+
out:
if (ret && device_is_registered(&mtd->dev))
del_mtd_device(mtd);
@@ -873,6 +1019,12 @@ int mtd_device_unregister(struct mtd_info *master)
if (master->_reboot)
unregister_reboot_notifier(&master->reboot_notifier);
+ if (master->otp_user_nvmem)
+ nvmem_unregister(master->otp_user_nvmem);
+
+ if (master->otp_factory_nvmem)
+ nvmem_unregister(master->otp_factory_nvmem);
+
err = del_mtd_partitions(master);
if (err)
return err;
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 862c4a889234..227df24387df 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -401,10 +401,8 @@ static int __init mtdoops_init(void)
cxt->mtd_index = mtd_index;
cxt->oops_buf = vmalloc(record_size);
- if (!cxt->oops_buf) {
- printk(KERN_ERR "mtdoops: failed to allocate buffer workspace\n");
+ if (!cxt->oops_buf)
return -ENOMEM;
- }
memset(cxt->oops_buf, 0xff, record_size);
cxt->oops_buf_busy = 0;
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 665fd9020b76..04af12b66110 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -212,15 +212,14 @@ out_register:
return child;
}
-static ssize_t mtd_partition_offset_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t offset_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%lld\n", mtd->part.offset);
+ return sysfs_emit(buf, "%lld\n", mtd->part.offset);
}
-
-static DEVICE_ATTR(offset, S_IRUGO, mtd_partition_offset_show, NULL);
+static DEVICE_ATTR_RO(offset); /* mtd partition offset */
static const struct attribute *mtd_partition_attrs[] = {
&dev_attr_offset.attr,
diff --git a/drivers/mtd/mtdpstore.c b/drivers/mtd/mtdpstore.c
index a3ae8778f6a9..e13d42c0acb0 100644
--- a/drivers/mtd/mtdpstore.c
+++ b/drivers/mtd/mtdpstore.c
@@ -423,13 +423,13 @@ static void mtdpstore_notify_add(struct mtd_info *mtd)
longcnt = BITS_TO_LONGS(div_u64(mtd->size, mtd->erasesize));
cxt->badmap = kcalloc(longcnt, sizeof(long), GFP_KERNEL);
- cxt->dev.total_size = mtd->size;
/* just support dmesg right now */
cxt->dev.flags = PSTORE_FLAGS_DMESG;
- cxt->dev.read = mtdpstore_read;
- cxt->dev.write = mtdpstore_write;
- cxt->dev.erase = mtdpstore_erase;
- cxt->dev.panic_write = mtdpstore_panic_write;
+ cxt->dev.zone.read = mtdpstore_read;
+ cxt->dev.zone.write = mtdpstore_write;
+ cxt->dev.zone.erase = mtdpstore_erase;
+ cxt->dev.zone.panic_write = mtdpstore_panic_write;
+ cxt->dev.zone.total_size = mtd->size;
ret = register_pstore_device(&cxt->dev);
if (ret) {
diff --git a/drivers/mtd/nand/bbt.c b/drivers/mtd/nand/bbt.c
index 044adf913854..64af6898131d 100644
--- a/drivers/mtd/nand/bbt.c
+++ b/drivers/mtd/nand/bbt.c
@@ -123,7 +123,7 @@ int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry,
unsigned int rbits = bits_per_block + offs - BITS_PER_LONG;
pos[1] &= ~GENMASK(rbits - 1, 0);
- pos[1] |= val >> rbits;
+ pos[1] |= val >> (bits_per_block - rbits);
}
return 0;
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 30f061939560..630728de4b7c 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -453,6 +453,14 @@ config MTD_NAND_ROCKCHIP
NFC v800: RK3308, RV1108
NFC v900: PX30, RK3326
+config MTD_NAND_PL35X
+ tristate "ARM PL35X NAND controller"
+ depends on OF || COMPILE_TEST
+ depends on PL353_SMC
+ help
+ Enables support for PrimeCell SMC PL351 and PL353 NAND
+ controller found on Zynq7000.
+
comment "Misc"
config MTD_SM_COMMON
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
index d011c6c53f8f..2f97958c3a33 100644
--- a/drivers/mtd/nand/raw/Makefile
+++ b/drivers/mtd/nand/raw/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_MTD_NAND_CADENCE) += cadence-nand-controller.o
obj-$(CONFIG_MTD_NAND_ARASAN) += arasan-nand-controller.o
obj-$(CONFIG_MTD_NAND_INTEL_LGM) += intel-nand-controller.o
obj-$(CONFIG_MTD_NAND_ROCKCHIP) += rockchip-nand-controller.o
+obj-$(CONFIG_MTD_NAND_PL35X) += pl35x-nand-controller.o
nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
nand-objs += nand_onfi.o
diff --git a/drivers/mtd/nand/raw/arasan-nand-controller.c b/drivers/mtd/nand/raw/arasan-nand-controller.c
index 549aac00228e..9cbcc698c64d 100644
--- a/drivers/mtd/nand/raw/arasan-nand-controller.c
+++ b/drivers/mtd/nand/raw/arasan-nand-controller.c
@@ -15,6 +15,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/module.h>
@@ -53,6 +54,7 @@
#define PROG_RST BIT(8)
#define PROG_GET_FEATURE BIT(9)
#define PROG_SET_FEATURE BIT(10)
+#define PROG_CHG_RD_COL_ENH BIT(14)
#define INTR_STS_EN_REG 0x14
#define INTR_SIG_EN_REG 0x18
@@ -70,6 +72,15 @@
#define FLASH_STS_REG 0x28
+#define TIMING_REG 0x2C
+#define TCCS_TIME_500NS 0
+#define TCCS_TIME_300NS 3
+#define TCCS_TIME_200NS 2
+#define TCCS_TIME_100NS 1
+#define FAST_TCAD BIT(2)
+#define DQS_BUFF_SEL_IN(x) FIELD_PREP(GENMASK(6, 3), (x))
+#define DQS_BUFF_SEL_OUT(x) FIELD_PREP(GENMASK(18, 15), (x))
+
#define DATA_PORT_REG 0x30
#define ECC_CONF_REG 0x34
@@ -91,7 +102,7 @@
#define DATA_INTERFACE_REG 0x6C
#define DIFACE_SDR_MODE(x) FIELD_PREP(GENMASK(2, 0), (x))
-#define DIFACE_DDR_MODE(x) FIELD_PREP(GENMASK(5, 3), (X))
+#define DIFACE_DDR_MODE(x) FIELD_PREP(GENMASK(5, 3), (x))
#define DIFACE_SDR 0
#define DIFACE_NVDDR BIT(9)
@@ -107,6 +118,8 @@
#define ANFC_XLNX_SDR_DFLT_CORE_CLK 100000000
#define ANFC_XLNX_SDR_HS_CORE_CLK 80000000
+static struct gpio_desc *anfc_default_cs_array[2] = {NULL, NULL};
+
/**
* struct anfc_op - Defines how to execute an operation
* @pkt_reg: Packet register
@@ -137,11 +150,11 @@ struct anfc_op {
* struct anand - Defines the NAND chip related information
* @node: Used to store NAND chips into a list
* @chip: NAND chip information structure
- * @cs: Chip select line
* @rb: Ready-busy line
* @page_sz: Register value of the page_sz field to use
* @clk: Expected clock frequency to use
- * @timings: Data interface timing mode to use
+ * @data_iface: Data interface timing mode to use
+ * @timings: NV-DDR specific timings to use
* @ecc_conf: Hardware ECC configuration value
* @strength: Register value of the ECC strength
* @raddr_cycles: Row address cycle information
@@ -151,14 +164,17 @@ struct anfc_op {
* @errloc: Array of errors located with soft BCH
* @hw_ecc: Buffer to store syndromes computed by hardware
* @bch: BCH structure
+ * @cs_idx: Array of chip-select for this device, values are indexes
+ * of the controller structure @gpio_cs array
+ * @ncs_idx: Size of the @cs_idx array
*/
struct anand {
struct list_head node;
struct nand_chip chip;
- unsigned int cs;
unsigned int rb;
unsigned int page_sz;
unsigned long clk;
+ u32 data_iface;
u32 timings;
u32 ecc_conf;
u32 strength;
@@ -169,6 +185,8 @@ struct anand {
unsigned int *errloc;
u8 *hw_ecc;
struct bch_control *bch;
+ int *cs_idx;
+ int ncs_idx;
};
/**
@@ -179,8 +197,14 @@ struct anand {
* @bus_clk: Pointer to the flash clock
* @controller: Base controller structure
* @chips: List of all NAND chips attached to the controller
- * @assigned_cs: Bitmask describing already assigned CS lines
* @cur_clk: Current clock rate
+ * @cs_array: CS array. Native CS are left empty, the other cells are
+ * populated with their corresponding GPIO descriptor.
+ * @ncs: Size of @cs_array
+ * @cur_cs: Index in @cs_array of the currently in use CS
+ * @native_cs: Currently selected native CS
+ * @spare_cs: Native CS that is not wired (may be selected when a GPIO
+ * CS is in use)
*/
struct arasan_nfc {
struct device *dev;
@@ -189,8 +213,12 @@ struct arasan_nfc {
struct clk *bus_clk;
struct nand_controller controller;
struct list_head chips;
- unsigned long assigned_cs;
unsigned int cur_clk;
+ struct gpio_desc **cs_array;
+ unsigned int ncs;
+ int cur_cs;
+ unsigned int native_cs;
+ unsigned int spare_cs;
};
static struct anand *to_anand(struct nand_chip *nand)
@@ -273,6 +301,72 @@ static int anfc_pkt_len_config(unsigned int len, unsigned int *steps,
return 0;
}
+static bool anfc_is_gpio_cs(struct arasan_nfc *nfc, int nfc_cs)
+{
+ return nfc_cs >= 0 && nfc->cs_array[nfc_cs];
+}
+
+static int anfc_relative_to_absolute_cs(struct anand *anand, int num)
+{
+ return anand->cs_idx[num];
+}
+
+static void anfc_assert_cs(struct arasan_nfc *nfc, unsigned int nfc_cs_idx)
+{
+ /* CS did not change: do nothing */
+ if (nfc->cur_cs == nfc_cs_idx)
+ return;
+
+ /* Deassert the previous CS if it was a GPIO */
+ if (anfc_is_gpio_cs(nfc, nfc->cur_cs))
+ gpiod_set_value_cansleep(nfc->cs_array[nfc->cur_cs], 1);
+
+ /* Assert the new one */
+ if (anfc_is_gpio_cs(nfc, nfc_cs_idx)) {
+ nfc->native_cs = nfc->spare_cs;
+ gpiod_set_value_cansleep(nfc->cs_array[nfc_cs_idx], 0);
+ } else {
+ nfc->native_cs = nfc_cs_idx;
+ }
+
+ nfc->cur_cs = nfc_cs_idx;
+}
+
+static int anfc_select_target(struct nand_chip *chip, int target)
+{
+ struct anand *anand = to_anand(chip);
+ struct arasan_nfc *nfc = to_anfc(chip->controller);
+ unsigned int nfc_cs_idx = anfc_relative_to_absolute_cs(anand, target);
+ int ret;
+
+ anfc_assert_cs(nfc, nfc_cs_idx);
+
+ /* Update the controller timings and the potential ECC configuration */
+ writel_relaxed(anand->data_iface, nfc->base + DATA_INTERFACE_REG);
+ writel_relaxed(anand->timings, nfc->base + TIMING_REG);
+
+ /* Update clock frequency */
+ if (nfc->cur_clk != anand->clk) {
+ clk_disable_unprepare(nfc->controller_clk);
+ ret = clk_set_rate(nfc->controller_clk, anand->clk);
+ if (ret) {
+ dev_err(nfc->dev, "Failed to change clock rate\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(nfc->controller_clk);
+ if (ret) {
+ dev_err(nfc->dev,
+ "Failed to re-enable the controller clock\n");
+ return ret;
+ }
+
+ nfc->cur_clk = anand->clk;
+ }
+
+ return 0;
+}
+
/*
* When using the embedded hardware ECC engine, the controller is in charge of
* feeding the engine with, first, the ECC residue present in the data array.
@@ -315,7 +409,7 @@ static int anfc_read_page_hw_ecc(struct nand_chip *chip, u8 *buf,
.addr2_reg =
((page >> 16) & 0xFF) |
ADDR2_STRENGTH(anand->strength) |
- ADDR2_CS(anand->cs),
+ ADDR2_CS(nfc->native_cs),
.cmd_reg =
CMD_1(NAND_CMD_READ0) |
CMD_2(NAND_CMD_READSTART) |
@@ -401,6 +495,18 @@ static int anfc_read_page_hw_ecc(struct nand_chip *chip, u8 *buf,
return 0;
}
+static int anfc_sel_read_page_hw_ecc(struct nand_chip *chip, u8 *buf,
+ int oob_required, int page)
+{
+ int ret;
+
+ ret = anfc_select_target(chip, chip->cur_cs);
+ if (ret)
+ return ret;
+
+ return anfc_read_page_hw_ecc(chip, buf, oob_required, page);
+};
+
static int anfc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
@@ -420,7 +526,7 @@ static int anfc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
.addr2_reg =
((page >> 16) & 0xFF) |
ADDR2_STRENGTH(anand->strength) |
- ADDR2_CS(anand->cs),
+ ADDR2_CS(nfc->native_cs),
.cmd_reg =
CMD_1(NAND_CMD_SEQIN) |
CMD_2(NAND_CMD_PAGEPROG) |
@@ -461,11 +567,24 @@ static int anfc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
return ret;
}
+static int anfc_sel_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
+ int oob_required, int page)
+{
+ int ret;
+
+ ret = anfc_select_target(chip, chip->cur_cs);
+ if (ret)
+ return ret;
+
+ return anfc_write_page_hw_ecc(chip, buf, oob_required, page);
+};
+
/* NAND framework ->exec_op() hooks and related helpers */
static int anfc_parse_instructions(struct nand_chip *chip,
const struct nand_subop *subop,
struct anfc_op *nfc_op)
{
+ struct arasan_nfc *nfc = to_anfc(chip->controller);
struct anand *anand = to_anand(chip);
const struct nand_op_instr *instr = NULL;
bool first_cmd = true;
@@ -473,7 +592,7 @@ static int anfc_parse_instructions(struct nand_chip *chip,
int ret, i;
memset(nfc_op, 0, sizeof(*nfc_op));
- nfc_op->addr2_reg = ADDR2_CS(anand->cs);
+ nfc_op->addr2_reg = ADDR2_CS(nfc->native_cs);
nfc_op->cmd_reg = CMD_PAGE_SIZE(anand->page_sz);
for (op_id = 0; op_id < subop->ninstrs; op_id++) {
@@ -622,7 +741,23 @@ static int anfc_param_read_type_exec(struct nand_chip *chip,
static int anfc_data_read_type_exec(struct nand_chip *chip,
const struct nand_subop *subop)
{
- return anfc_misc_data_type_exec(chip, subop, PROG_PGRD);
+ u32 prog_reg = PROG_PGRD;
+
+ /*
+ * Experience shows that while in SDR mode sending a CHANGE READ COLUMN
+ * command through the READ PAGE "type" always works fine, when in
+ * NV-DDR mode the same command simply fails. However, it was also
+ * spotted that any CHANGE READ COLUMN command sent through the CHANGE
+ * READ COLUMN ENHANCED "type" would correctly work in both cases (SDR
+ * and NV-DDR). So, for simplicity, let's program the controller with
+ * the CHANGE READ COLUMN ENHANCED "type" whenever we are requested to
+ * perform a CHANGE READ COLUMN operation.
+ */
+ if (subop->instrs[0].ctx.cmd.opcode == NAND_CMD_RNDOUT &&
+ subop->instrs[2].ctx.cmd.opcode == NAND_CMD_RNDOUTSTART)
+ prog_reg = PROG_CHG_RD_COL_ENH;
+
+ return anfc_misc_data_type_exec(chip, subop, prog_reg);
}
static int anfc_param_write_type_exec(struct nand_chip *chip,
@@ -753,37 +888,6 @@ static const struct nand_op_parser anfc_op_parser = NAND_OP_PARSER(
NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
);
-static int anfc_select_target(struct nand_chip *chip, int target)
-{
- struct anand *anand = to_anand(chip);
- struct arasan_nfc *nfc = to_anfc(chip->controller);
- int ret;
-
- /* Update the controller timings and the potential ECC configuration */
- writel_relaxed(anand->timings, nfc->base + DATA_INTERFACE_REG);
-
- /* Update clock frequency */
- if (nfc->cur_clk != anand->clk) {
- clk_disable_unprepare(nfc->controller_clk);
- ret = clk_set_rate(nfc->controller_clk, anand->clk);
- if (ret) {
- dev_err(nfc->dev, "Failed to change clock rate\n");
- return ret;
- }
-
- ret = clk_prepare_enable(nfc->controller_clk);
- if (ret) {
- dev_err(nfc->dev,
- "Failed to re-enable the controller clock\n");
- return ret;
- }
-
- nfc->cur_clk = anand->clk;
- }
-
- return 0;
-}
-
static int anfc_check_op(struct nand_chip *chip,
const struct nand_operation *op)
{
@@ -861,21 +965,79 @@ static int anfc_setup_interface(struct nand_chip *chip, int target,
struct anand *anand = to_anand(chip);
struct arasan_nfc *nfc = to_anfc(chip->controller);
struct device_node *np = nfc->dev->of_node;
+ const struct nand_sdr_timings *sdr;
+ const struct nand_nvddr_timings *nvddr;
+ unsigned int tccs_min, dqs_mode, fast_tcad;
+
+ if (nand_interface_is_nvddr(conf)) {
+ nvddr = nand_get_nvddr_timings(conf);
+ if (IS_ERR(nvddr))
+ return PTR_ERR(nvddr);
+ } else {
+ sdr = nand_get_sdr_timings(conf);
+ if (IS_ERR(sdr))
+ return PTR_ERR(sdr);
+ }
if (target < 0)
return 0;
- anand->timings = DIFACE_SDR | DIFACE_SDR_MODE(conf->timings.mode);
+ if (nand_interface_is_sdr(conf)) {
+ anand->data_iface = DIFACE_SDR |
+ DIFACE_SDR_MODE(conf->timings.mode);
+ anand->timings = 0;
+ } else {
+ anand->data_iface = DIFACE_NVDDR |
+ DIFACE_DDR_MODE(conf->timings.mode);
+
+ if (conf->timings.nvddr.tCCS_min <= 100000)
+ tccs_min = TCCS_TIME_100NS;
+ else if (conf->timings.nvddr.tCCS_min <= 200000)
+ tccs_min = TCCS_TIME_200NS;
+ else if (conf->timings.nvddr.tCCS_min <= 300000)
+ tccs_min = TCCS_TIME_300NS;
+ else
+ tccs_min = TCCS_TIME_500NS;
+
+ fast_tcad = 0;
+ if (conf->timings.nvddr.tCAD_min < 45000)
+ fast_tcad = FAST_TCAD;
+
+ switch (conf->timings.mode) {
+ case 5:
+ case 4:
+ dqs_mode = 2;
+ break;
+ case 3:
+ dqs_mode = 3;
+ break;
+ case 2:
+ dqs_mode = 4;
+ break;
+ case 1:
+ dqs_mode = 5;
+ break;
+ case 0:
+ default:
+ dqs_mode = 6;
+ break;
+ }
+
+ anand->timings = tccs_min | fast_tcad |
+ DQS_BUFF_SEL_IN(dqs_mode) |
+ DQS_BUFF_SEL_OUT(dqs_mode);
+ }
+
anand->clk = ANFC_XLNX_SDR_DFLT_CORE_CLK;
/*
* Due to a hardware bug in the ZynqMP SoC, SDR timing modes 0-1 work
* with f > 90MHz (default clock is 100MHz) but signals are unstable
* with higher modes. Hence we decrease a little bit the clock rate to
- * 80MHz when using modes 2-5 with this SoC.
+ * 80MHz when using SDR modes 2-5 with this SoC.
*/
if (of_device_is_compatible(np, "xlnx,zynqmp-nand-controller") &&
- conf->timings.mode >= 2)
+ nand_interface_is_sdr(conf) && conf->timings.mode >= 2)
anand->clk = ANFC_XLNX_SDR_HS_CORE_CLK;
return 0;
@@ -1007,8 +1169,8 @@ static int anfc_init_hw_ecc_controller(struct arasan_nfc *nfc,
if (!anand->bch)
return -EINVAL;
- ecc->read_page = anfc_read_page_hw_ecc;
- ecc->write_page = anfc_write_page_hw_ecc;
+ ecc->read_page = anfc_sel_read_page_hw_ecc;
+ ecc->write_page = anfc_sel_write_page_hw_ecc;
return 0;
}
@@ -1094,37 +1256,43 @@ static int anfc_chip_init(struct arasan_nfc *nfc, struct device_node *np)
struct anand *anand;
struct nand_chip *chip;
struct mtd_info *mtd;
- int cs, rb, ret;
+ int rb, ret, i;
anand = devm_kzalloc(nfc->dev, sizeof(*anand), GFP_KERNEL);
if (!anand)
return -ENOMEM;
- /* We do not support multiple CS per chip yet */
- if (of_property_count_elems_of_size(np, "reg", sizeof(u32)) != 1) {
+ /* Chip-select init */
+ anand->ncs_idx = of_property_count_elems_of_size(np, "reg", sizeof(u32));
+ if (anand->ncs_idx <= 0 || anand->ncs_idx > nfc->ncs) {
dev_err(nfc->dev, "Invalid reg property\n");
return -EINVAL;
}
- ret = of_property_read_u32(np, "reg", &cs);
- if (ret)
- return ret;
+ anand->cs_idx = devm_kcalloc(nfc->dev, anand->ncs_idx,
+ sizeof(*anand->cs_idx), GFP_KERNEL);
+ if (!anand->cs_idx)
+ return -ENOMEM;
+ for (i = 0; i < anand->ncs_idx; i++) {
+ ret = of_property_read_u32_index(np, "reg", i,
+ &anand->cs_idx[i]);
+ if (ret) {
+ dev_err(nfc->dev, "invalid CS property: %d\n", ret);
+ return ret;
+ }
+ }
+
+ /* Ready-busy init */
ret = of_property_read_u32(np, "nand-rb", &rb);
if (ret)
return ret;
- if (cs >= ANFC_MAX_CS || rb >= ANFC_MAX_CS) {
- dev_err(nfc->dev, "Wrong CS %d or RB %d\n", cs, rb);
- return -EINVAL;
- }
-
- if (test_and_set_bit(cs, &nfc->assigned_cs)) {
- dev_err(nfc->dev, "Already assigned CS %d\n", cs);
+ if (rb >= ANFC_MAX_CS) {
+ dev_err(nfc->dev, "Wrong RB %d\n", rb);
return -EINVAL;
}
- anand->cs = cs;
anand->rb = rb;
chip = &anand->chip;
@@ -1140,7 +1308,7 @@ static int anfc_chip_init(struct arasan_nfc *nfc, struct device_node *np)
return -EINVAL;
}
- ret = nand_scan(chip, 1);
+ ret = nand_scan(chip, anand->ncs_idx);
if (ret) {
dev_err(nfc->dev, "Scan operation failed\n");
return ret;
@@ -1178,7 +1346,7 @@ static int anfc_chips_init(struct arasan_nfc *nfc)
int nchips = of_get_child_count(np);
int ret;
- if (!nchips || nchips > ANFC_MAX_CS) {
+ if (!nchips) {
dev_err(nfc->dev, "Incorrect number of NAND chips (%d)\n",
nchips);
return -EINVAL;
@@ -1203,6 +1371,47 @@ static void anfc_reset(struct arasan_nfc *nfc)
/* Enable interrupt status */
writel_relaxed(EVENT_MASK, nfc->base + INTR_STS_EN_REG);
+
+ nfc->cur_cs = -1;
+}
+
+static int anfc_parse_cs(struct arasan_nfc *nfc)
+{
+ int ret;
+
+ /* Check the gpio-cs property */
+ ret = rawnand_dt_parse_gpio_cs(nfc->dev, &nfc->cs_array, &nfc->ncs);
+ if (ret)
+ return ret;
+
+ /*
+ * The controller native CS cannot be both disabled at the same time.
+ * Hence, only one native CS can be used if GPIO CS are needed, so that
+ * the other is selected when a non-native CS must be asserted (not
+ * wired physically or configured as GPIO instead of NAND CS). In this
+ * case, the "not" chosen CS is assigned to nfc->spare_cs and selected
+ * whenever a GPIO CS must be asserted.
+ */
+ if (nfc->cs_array && nfc->ncs > 2) {
+ if (!nfc->cs_array[0] && !nfc->cs_array[1]) {
+ dev_err(nfc->dev,
+ "Assign a single native CS when using GPIOs\n");
+ return -EINVAL;
+ }
+
+ if (nfc->cs_array[0])
+ nfc->spare_cs = 0;
+ else
+ nfc->spare_cs = 1;
+ }
+
+ if (!nfc->cs_array) {
+ nfc->cs_array = anfc_default_cs_array;
+ nfc->ncs = ANFC_MAX_CS;
+ return 0;
+ }
+
+ return 0;
}
static int anfc_probe(struct platform_device *pdev)
@@ -1241,6 +1450,14 @@ static int anfc_probe(struct platform_device *pdev)
if (ret)
goto disable_controller_clk;
+ ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+ if (ret)
+ goto disable_bus_clk;
+
+ ret = anfc_parse_cs(nfc);
+ if (ret)
+ goto disable_bus_clk;
+
ret = anfc_chips_init(nfc);
if (ret)
goto disable_bus_clk;
diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
index 8aab1017b460..f3276ee9e4fe 100644
--- a/drivers/mtd/nand/raw/atmel/nand-controller.c
+++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
@@ -1246,7 +1246,7 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
nc = to_nand_controller(nand->base.controller);
/* DDR interface not supported. */
- if (conf->type != NAND_SDR_IFACE)
+ if (!nand_interface_is_sdr(conf))
return -ENOTSUPP;
/*
@@ -1524,8 +1524,13 @@ static int atmel_nand_setup_interface(struct nand_chip *chip, int csline,
const struct nand_interface_config *conf)
{
struct atmel_nand *nand = to_atmel_nand(chip);
+ const struct nand_sdr_timings *sdr;
struct atmel_nand_controller *nc;
+ sdr = nand_get_sdr_timings(conf);
+ if (IS_ERR(sdr))
+ return PTR_ERR(sdr);
+
nc = to_nand_controller(nand->base.controller);
if (csline >= nand->numcs ||
@@ -1629,10 +1634,8 @@ static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
}
nand = devm_kzalloc(nc->dev, struct_size(nand, cs, numcs), GFP_KERNEL);
- if (!nand) {
- dev_err(nc->dev, "Failed to allocate NAND object\n");
+ if (!nand)
return ERR_PTR(-ENOMEM);
- }
nand->numcs = numcs;
diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c
index b46786cd53e0..7eec60ea9056 100644
--- a/drivers/mtd/nand/raw/cadence-nand-controller.c
+++ b/drivers/mtd/nand/raw/cadence-nand-controller.c
@@ -2348,9 +2348,9 @@ cadence_nand_setup_interface(struct nand_chip *chip, int chipnr,
* for tRP and tRH timings. If it is NOT possible to sample data
* with optimal tRP/tRH settings, the parameters will be extended.
* If clk_period is 50ns (the lowest value) this condition is met
- * for asynchronous timing modes 1, 2, 3, 4 and 5.
- * If clk_period is 20ns the condition is met only
- * for asynchronous timing mode 5.
+ * for SDR timing modes 1, 2, 3, 4 and 5.
+ * If clk_period is 20ns the condition is met only for SDR timing
+ * mode 5.
*/
if (sdr->tRC_min <= clk_period &&
sdr->tRP_min <= (clk_period / 2) &&
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
index fdc5ed7de083..5e1c3ddae5f8 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.h
@@ -79,7 +79,7 @@ enum gpmi_type {
struct gpmi_devdata {
enum gpmi_type type;
int bch_max_ecc_strength;
- int max_chain_delay; /* See the async EDO mode */
+ int max_chain_delay; /* See the SDR EDO mode */
const char * const *clks;
const int clks_count;
};
diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c
index 8b2122ce6ec3..78c4e05434e2 100644
--- a/drivers/mtd/nand/raw/hisi504_nand.c
+++ b/drivers/mtd/nand/raw/hisi504_nand.c
@@ -761,10 +761,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
host->mmio = devm_ioremap_resource(dev, res);
- if (IS_ERR(host->mmio)) {
- dev_err(dev, "devm_ioremap_resource[1] fail\n");
+ if (IS_ERR(host->mmio))
return PTR_ERR(host->mmio);
- }
mtd->name = "hisi_nand";
mtd->dev.parent = &pdev->dev;
diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h
index 012876e14317..7016e0f38398 100644
--- a/drivers/mtd/nand/raw/internals.h
+++ b/drivers/mtd/nand/raw/internals.h
@@ -90,9 +90,14 @@ void onfi_fill_interface_config(struct nand_chip *chip,
unsigned int timing_mode);
unsigned int
onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings);
+unsigned int
+onfi_find_closest_nvddr_mode(const struct nand_nvddr_timings *spec_timings);
int nand_choose_best_sdr_timings(struct nand_chip *chip,
struct nand_interface_config *iface,
struct nand_sdr_timings *spec_timings);
+int nand_choose_best_nvddr_timings(struct nand_chip *chip,
+ struct nand_interface_config *iface,
+ struct nand_nvddr_timings *spec_timings);
const struct nand_interface_config *nand_get_reset_interface_config(void);
int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
index 79da6b02e209..2455a581fd70 100644
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -451,7 +451,7 @@ struct marvell_nfc_timings {
};
/**
- * Derives a duration in numbers of clock cycles.
+ * TO_CYCLES() - Derives a duration in numbers of clock cycles.
*
* @ps: Duration in pico-seconds
* @period_ns: Clock period in nano-seconds
@@ -3030,8 +3030,10 @@ static int __maybe_unused marvell_nfc_resume(struct device *dev)
return ret;
ret = clk_prepare_enable(nfc->reg_clk);
- if (ret < 0)
+ if (ret < 0) {
+ clk_disable_unprepare(nfc->core_clk);
return ret;
+ }
/*
* Reset nfc->selected_chip so the next command will cause the timing
diff --git a/drivers/mtd/nand/raw/mtk_ecc.c b/drivers/mtd/nand/raw/mtk_ecc.c
index 75f1fa3d4d35..c437d97debb8 100644
--- a/drivers/mtd/nand/raw/mtk_ecc.c
+++ b/drivers/mtd/nand/raw/mtk_ecc.c
@@ -515,10 +515,8 @@ static int mtk_ecc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ecc->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(ecc->regs)) {
- dev_err(dev, "failed to map regs: %ld\n", PTR_ERR(ecc->regs));
+ if (IS_ERR(ecc->regs))
return PTR_ERR(ecc->regs);
- }
ecc->clk = devm_clk_get(dev, NULL);
if (IS_ERR(ecc->clk)) {
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index fb072c444495..57a583149cc0 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -42,6 +42,7 @@
#include <linux/io.h>
#include <linux/mtd/partitions.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include "internals.h"
@@ -647,7 +648,7 @@ static int nand_block_checkbad(struct nand_chip *chip, loff_t ofs, int allowbbt)
*/
int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
{
- const struct nand_sdr_timings *timings;
+ const struct nand_interface_config *conf;
u8 status = 0;
int ret;
@@ -655,8 +656,8 @@ int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
return -ENOTSUPP;
/* Wait tWB before polling the STATUS reg. */
- timings = nand_get_sdr_timings(nand_get_interface_config(chip));
- ndelay(PSEC_TO_NSEC(timings->tWB_max));
+ conf = nand_get_interface_config(chip);
+ ndelay(NAND_COMMON_TIMING_NS(conf, tWB_max));
ret = nand_status_op(chip, NULL);
if (ret)
@@ -832,7 +833,7 @@ static int nand_reset_interface(struct nand_chip *chip, int chipnr)
static int nand_setup_interface(struct nand_chip *chip, int chipnr)
{
const struct nand_controller_ops *ops = chip->controller->ops;
- u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { };
+ u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { }, request;
int ret;
if (!nand_controller_can_setup_interface(chip))
@@ -848,7 +849,12 @@ static int nand_setup_interface(struct nand_chip *chip, int chipnr)
if (!chip->best_interface_config)
return 0;
- tmode_param[0] = chip->best_interface_config->timings.mode;
+ request = chip->best_interface_config->timings.mode;
+ if (nand_interface_is_sdr(chip->best_interface_config))
+ request |= ONFI_DATA_INTERFACE_SDR;
+ else
+ request |= ONFI_DATA_INTERFACE_NVDDR;
+ tmode_param[0] = request;
/* Change the mode on the chip side (if supported by the NAND chip) */
if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) {
@@ -877,9 +883,13 @@ static int nand_setup_interface(struct nand_chip *chip, int chipnr)
if (ret)
goto err_reset_chip;
- if (tmode_param[0] != chip->best_interface_config->timings.mode) {
- pr_warn("timing mode %d not acknowledged by the NAND chip\n",
+ if (request != tmode_param[0]) {
+ pr_warn("%s timing mode %d not acknowledged by the NAND chip\n",
+ nand_interface_is_nvddr(chip->best_interface_config) ? "NV-DDR" : "SDR",
chip->best_interface_config->timings.mode);
+ pr_debug("NAND chip would work in %s timing mode %d\n",
+ tmode_param[0] & ONFI_DATA_INTERFACE_NVDDR ? "NV-DDR" : "SDR",
+ (unsigned int)ONFI_TIMING_MODE_PARAM(tmode_param[0]));
goto err_reset_chip;
}
@@ -935,7 +945,7 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip,
/* Fallback to slower modes */
best_mode = iface->timings.mode;
} else if (chip->parameters.onfi) {
- best_mode = fls(chip->parameters.onfi->async_timing_mode) - 1;
+ best_mode = fls(chip->parameters.onfi->sdr_timing_modes) - 1;
}
for (mode = best_mode; mode >= 0; mode--) {
@@ -943,13 +953,87 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip,
ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY,
iface);
- if (!ret)
+ if (!ret) {
+ chip->best_interface_config = iface;
break;
+ }
}
- chip->best_interface_config = iface;
+ return ret;
+}
- return 0;
+/**
+ * nand_choose_best_nvddr_timings - Pick up the best NVDDR timings that both the
+ * NAND controller and the NAND chip support
+ * @chip: the NAND chip
+ * @iface: the interface configuration (can eventually be updated)
+ * @spec_timings: specific timings, when not fitting the ONFI specification
+ *
+ * If specific timings are provided, use them. Otherwise, retrieve supported
+ * timing modes from ONFI information.
+ */
+int nand_choose_best_nvddr_timings(struct nand_chip *chip,
+ struct nand_interface_config *iface,
+ struct nand_nvddr_timings *spec_timings)
+{
+ const struct nand_controller_ops *ops = chip->controller->ops;
+ int best_mode = 0, mode, ret;
+
+ iface->type = NAND_NVDDR_IFACE;
+
+ if (spec_timings) {
+ iface->timings.nvddr = *spec_timings;
+ iface->timings.mode = onfi_find_closest_nvddr_mode(spec_timings);
+
+ /* Verify the controller supports the requested interface */
+ ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY,
+ iface);
+ if (!ret) {
+ chip->best_interface_config = iface;
+ return ret;
+ }
+
+ /* Fallback to slower modes */
+ best_mode = iface->timings.mode;
+ } else if (chip->parameters.onfi) {
+ best_mode = fls(chip->parameters.onfi->nvddr_timing_modes) - 1;
+ }
+
+ for (mode = best_mode; mode >= 0; mode--) {
+ onfi_fill_interface_config(chip, iface, NAND_NVDDR_IFACE, mode);
+
+ ret = ops->setup_interface(chip, NAND_DATA_IFACE_CHECK_ONLY,
+ iface);
+ if (!ret) {
+ chip->best_interface_config = iface;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * nand_choose_best_timings - Pick up the best NVDDR or SDR timings that both
+ * NAND controller and the NAND chip support
+ * @chip: the NAND chip
+ * @iface: the interface configuration (can eventually be updated)
+ *
+ * If specific timings are provided, use them. Otherwise, retrieve supported
+ * timing modes from ONFI information.
+ */
+static int nand_choose_best_timings(struct nand_chip *chip,
+ struct nand_interface_config *iface)
+{
+ int ret;
+
+ /* Try the fastest timings: NV-DDR */
+ ret = nand_choose_best_nvddr_timings(chip, iface, NULL);
+ if (!ret)
+ return 0;
+
+ /* Fallback to SDR timings otherwise */
+ return nand_choose_best_sdr_timings(chip, iface, NULL);
}
/**
@@ -980,7 +1064,7 @@ static int nand_choose_interface_config(struct nand_chip *chip)
if (chip->ops.choose_interface_config)
ret = chip->ops.choose_interface_config(chip, iface);
else
- ret = nand_choose_best_sdr_timings(chip, iface, NULL);
+ ret = nand_choose_best_timings(chip, iface);
if (ret)
kfree(iface);
@@ -1046,15 +1130,15 @@ static int nand_sp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, void *buf,
unsigned int len)
{
- const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(nand_get_interface_config(chip));
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
struct mtd_info *mtd = nand_to_mtd(chip);
u8 addrs[4];
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_READ0, 0),
- NAND_OP_ADDR(3, addrs, PSEC_TO_NSEC(sdr->tWB_max)),
- NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max),
- PSEC_TO_NSEC(sdr->tRR_min)),
+ NAND_OP_ADDR(3, addrs, NAND_COMMON_TIMING_NS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max),
+ NAND_COMMON_TIMING_NS(conf, tRR_min)),
NAND_OP_DATA_IN(len, buf, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@@ -1089,15 +1173,15 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, void *buf,
unsigned int len)
{
- const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(nand_get_interface_config(chip));
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
u8 addrs[5];
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_READ0, 0),
NAND_OP_ADDR(4, addrs, 0),
- NAND_OP_CMD(NAND_CMD_READSTART, PSEC_TO_NSEC(sdr->tWB_max)),
- NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max),
- PSEC_TO_NSEC(sdr->tRR_min)),
+ NAND_OP_CMD(NAND_CMD_READSTART, NAND_COMMON_TIMING_NS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max),
+ NAND_COMMON_TIMING_NS(conf, tRR_min)),
NAND_OP_DATA_IN(len, buf, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@@ -1186,13 +1270,14 @@ int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
return -EINVAL;
if (nand_has_exec_op(chip)) {
- const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(nand_get_interface_config(chip));
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_PARAM, 0),
- NAND_OP_ADDR(1, &page, PSEC_TO_NSEC(sdr->tWB_max)),
- NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tR_max),
- PSEC_TO_NSEC(sdr->tRR_min)),
+ NAND_OP_ADDR(1, &page,
+ NAND_COMMON_TIMING_NS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max),
+ NAND_COMMON_TIMING_NS(conf, tRR_min)),
NAND_OP_8BIT_DATA_IN(len, buf, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@@ -1241,14 +1326,14 @@ int nand_change_read_column_op(struct nand_chip *chip,
return -ENOTSUPP;
if (nand_has_exec_op(chip)) {
- const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(nand_get_interface_config(chip));
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
u8 addrs[2] = {};
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_RNDOUT, 0),
NAND_OP_ADDR(2, addrs, 0),
NAND_OP_CMD(NAND_CMD_RNDOUTSTART,
- PSEC_TO_NSEC(sdr->tCCS_min)),
+ NAND_COMMON_TIMING_NS(conf, tCCS_min)),
NAND_OP_DATA_IN(len, buf, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@@ -1316,8 +1401,8 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, const void *buf,
unsigned int len, bool prog)
{
- const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(nand_get_interface_config(chip));
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
struct mtd_info *mtd = nand_to_mtd(chip);
u8 addrs[5] = {};
struct nand_op_instr instrs[] = {
@@ -1328,10 +1413,11 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page,
*/
NAND_OP_CMD(NAND_CMD_READ0, 0),
NAND_OP_CMD(NAND_CMD_SEQIN, 0),
- NAND_OP_ADDR(0, addrs, PSEC_TO_NSEC(sdr->tADL_min)),
+ NAND_OP_ADDR(0, addrs, NAND_COMMON_TIMING_NS(conf, tADL_min)),
NAND_OP_DATA_OUT(len, buf, 0),
- NAND_OP_CMD(NAND_CMD_PAGEPROG, PSEC_TO_NSEC(sdr->tWB_max)),
- NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tPROG_max), 0),
+ NAND_OP_CMD(NAND_CMD_PAGEPROG,
+ NAND_COMMON_TIMING_NS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tPROG_max), 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
int naddrs = nand_fill_column_cycles(chip, addrs, offset_in_page);
@@ -1430,12 +1516,13 @@ int nand_prog_page_end_op(struct nand_chip *chip)
u8 status;
if (nand_has_exec_op(chip)) {
- const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(nand_get_interface_config(chip));
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_PAGEPROG,
- PSEC_TO_NSEC(sdr->tWB_max)),
- NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tPROG_max), 0),
+ NAND_COMMON_TIMING_NS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tPROG_max),
+ 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@@ -1548,12 +1635,12 @@ int nand_change_write_column_op(struct nand_chip *chip,
return -ENOTSUPP;
if (nand_has_exec_op(chip)) {
- const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(nand_get_interface_config(chip));
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
u8 addrs[2];
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_RNDIN, 0),
- NAND_OP_ADDR(2, addrs, PSEC_TO_NSEC(sdr->tCCS_min)),
+ NAND_OP_ADDR(2, addrs, NAND_COMMON_TIMING_NS(conf, tCCS_min)),
NAND_OP_DATA_OUT(len, buf, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@@ -1597,26 +1684,46 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
unsigned int len)
{
unsigned int i;
- u8 *id = buf;
+ u8 *id = buf, *ddrbuf = NULL;
if (len && !buf)
return -EINVAL;
if (nand_has_exec_op(chip)) {
- const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(nand_get_interface_config(chip));
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_READID, 0),
- NAND_OP_ADDR(1, &addr, PSEC_TO_NSEC(sdr->tADL_min)),
+ NAND_OP_ADDR(1, &addr,
+ NAND_COMMON_TIMING_NS(conf, tADL_min)),
NAND_OP_8BIT_DATA_IN(len, buf, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
+ int ret;
+
+ /* READ_ID data bytes are received twice in NV-DDR mode */
+ if (len && nand_interface_is_nvddr(conf)) {
+ ddrbuf = kzalloc(len * 2, GFP_KERNEL);
+ if (!ddrbuf)
+ return -ENOMEM;
+
+ instrs[2].ctx.data.len *= 2;
+ instrs[2].ctx.data.buf.in = ddrbuf;
+ }
/* Drop the DATA_IN instruction if len is set to 0. */
if (!len)
op.ninstrs--;
- return nand_exec_op(chip, &op);
+ ret = nand_exec_op(chip, &op);
+ if (!ret && len && nand_interface_is_nvddr(conf)) {
+ for (i = 0; i < len; i++)
+ id[i] = ddrbuf[i * 2];
+ }
+
+ kfree(ddrbuf);
+
+ return ret;
}
chip->legacy.cmdfunc(chip, NAND_CMD_READID, addr, -1);
@@ -1642,19 +1749,31 @@ EXPORT_SYMBOL_GPL(nand_readid_op);
int nand_status_op(struct nand_chip *chip, u8 *status)
{
if (nand_has_exec_op(chip)) {
- const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(nand_get_interface_config(chip));
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
+ u8 ddrstatus[2];
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_STATUS,
- PSEC_TO_NSEC(sdr->tADL_min)),
+ NAND_COMMON_TIMING_NS(conf, tADL_min)),
NAND_OP_8BIT_DATA_IN(1, status, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
+ int ret;
+
+ /* The status data byte will be received twice in NV-DDR mode */
+ if (status && nand_interface_is_nvddr(conf)) {
+ instrs[1].ctx.data.len *= 2;
+ instrs[1].ctx.data.buf.in = ddrstatus;
+ }
if (!status)
op.ninstrs--;
- return nand_exec_op(chip, &op);
+ ret = nand_exec_op(chip, &op);
+ if (!ret && status && nand_interface_is_nvddr(conf))
+ *status = ddrstatus[0];
+
+ return ret;
}
chip->legacy.cmdfunc(chip, NAND_CMD_STATUS, -1, -1);
@@ -1711,15 +1830,16 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
u8 status;
if (nand_has_exec_op(chip)) {
- const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(nand_get_interface_config(chip));
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
u8 addrs[3] = { page, page >> 8, page >> 16 };
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_ERASE1, 0),
NAND_OP_ADDR(2, addrs, 0),
NAND_OP_CMD(NAND_CMD_ERASE2,
- PSEC_TO_MSEC(sdr->tWB_max)),
- NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tBERS_max), 0),
+ NAND_COMMON_TIMING_MS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tBERS_max),
+ 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@@ -1770,14 +1890,17 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature,
int i, ret;
if (nand_has_exec_op(chip)) {
- const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(nand_get_interface_config(chip));
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_SET_FEATURES, 0),
- NAND_OP_ADDR(1, &feature, PSEC_TO_NSEC(sdr->tADL_min)),
+ NAND_OP_ADDR(1, &feature, NAND_COMMON_TIMING_NS(conf,
+ tADL_min)),
NAND_OP_8BIT_DATA_OUT(ONFI_SUBFEATURE_PARAM_LEN, data,
- PSEC_TO_NSEC(sdr->tWB_max)),
- NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tFEAT_max), 0),
+ NAND_COMMON_TIMING_NS(conf,
+ tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tFEAT_max),
+ 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@@ -1813,23 +1936,37 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature,
static int nand_get_features_op(struct nand_chip *chip, u8 feature,
void *data)
{
- u8 *params = data;
+ u8 *params = data, ddrbuf[ONFI_SUBFEATURE_PARAM_LEN * 2];
int i;
if (nand_has_exec_op(chip)) {
- const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(nand_get_interface_config(chip));
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_GET_FEATURES, 0),
- NAND_OP_ADDR(1, &feature, PSEC_TO_NSEC(sdr->tWB_max)),
- NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tFEAT_max),
- PSEC_TO_NSEC(sdr->tRR_min)),
+ NAND_OP_ADDR(1, &feature,
+ NAND_COMMON_TIMING_NS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tFEAT_max),
+ NAND_COMMON_TIMING_NS(conf, tRR_min)),
NAND_OP_8BIT_DATA_IN(ONFI_SUBFEATURE_PARAM_LEN,
data, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
+ int ret;
- return nand_exec_op(chip, &op);
+ /* GET_FEATURE data bytes are received twice in NV-DDR mode */
+ if (nand_interface_is_nvddr(conf)) {
+ instrs[3].ctx.data.len *= 2;
+ instrs[3].ctx.data.buf.in = ddrbuf;
+ }
+
+ ret = nand_exec_op(chip, &op);
+ if (nand_interface_is_nvddr(conf)) {
+ for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; i++)
+ params[i] = ddrbuf[i * 2];
+ }
+
+ return ret;
}
chip->legacy.cmdfunc(chip, NAND_CMD_GET_FEATURES, feature, -1);
@@ -1874,11 +2011,13 @@ static int nand_wait_rdy_op(struct nand_chip *chip, unsigned int timeout_ms,
int nand_reset_op(struct nand_chip *chip)
{
if (nand_has_exec_op(chip)) {
- const struct nand_sdr_timings *sdr =
- nand_get_sdr_timings(nand_get_interface_config(chip));
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
struct nand_op_instr instrs[] = {
- NAND_OP_CMD(NAND_CMD_RESET, PSEC_TO_NSEC(sdr->tWB_max)),
- NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tRST_max), 0),
+ NAND_OP_CMD(NAND_CMD_RESET,
+ NAND_COMMON_TIMING_NS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tRST_max),
+ 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
@@ -1913,17 +2052,50 @@ int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
return -EINVAL;
if (nand_has_exec_op(chip)) {
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
struct nand_op_instr instrs[] = {
NAND_OP_DATA_IN(len, buf, 0),
};
struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
+ u8 *ddrbuf = NULL;
+ int ret, i;
instrs[0].ctx.data.force_8bit = force_8bit;
- if (check_only)
- return nand_check_op(chip, &op);
+ /*
+ * Parameter payloads (ID, status, features, etc) do not go
+ * through the same pipeline as regular data, hence the
+ * force_8bit flag must be set and this also indicates that in
+ * case NV-DDR timings are being used the data will be received
+ * twice.
+ */
+ if (force_8bit && nand_interface_is_nvddr(conf)) {
+ ddrbuf = kzalloc(len * 2, GFP_KERNEL);
+ if (!ddrbuf)
+ return -ENOMEM;
- return nand_exec_op(chip, &op);
+ instrs[0].ctx.data.len *= 2;
+ instrs[0].ctx.data.buf.in = ddrbuf;
+ }
+
+ if (check_only) {
+ ret = nand_check_op(chip, &op);
+ kfree(ddrbuf);
+ return ret;
+ }
+
+ ret = nand_exec_op(chip, &op);
+ if (!ret && force_8bit && nand_interface_is_nvddr(conf)) {
+ u8 *dst = buf;
+
+ for (i = 0; i < len; i++)
+ dst[i] = ddrbuf[i * 2];
+ }
+
+ kfree(ddrbuf);
+
+ return ret;
}
if (check_only)
@@ -3136,13 +3308,13 @@ static int nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
static void nand_wait_readrdy(struct nand_chip *chip)
{
- const struct nand_sdr_timings *sdr;
+ const struct nand_interface_config *conf;
if (!(chip->options & NAND_NEED_READRDY))
return;
- sdr = nand_get_sdr_timings(nand_get_interface_config(chip));
- WARN_ON(nand_wait_rdy_op(chip, PSEC_TO_MSEC(sdr->tR_max), 0));
+ conf = nand_get_interface_config(chip);
+ WARN_ON(nand_wait_rdy_op(chip, NAND_COMMON_TIMING_MS(conf, tR_max), 0));
}
/**
@@ -5078,6 +5250,44 @@ static int of_get_nand_secure_regions(struct nand_chip *chip)
return 0;
}
+/**
+ * rawnand_dt_parse_gpio_cs - Parse the gpio-cs property of a controller
+ * @dev: Device that will be parsed. Also used for managed allocations.
+ * @cs_array: Array of GPIO desc pointers allocated on success
+ * @ncs_array: Number of entries in @cs_array updated on success.
+ * @return 0 on success, an error otherwise.
+ */
+int rawnand_dt_parse_gpio_cs(struct device *dev, struct gpio_desc ***cs_array,
+ unsigned int *ncs_array)
+{
+ struct device_node *np = dev->of_node;
+ struct gpio_desc **descs;
+ int ndescs, i;
+
+ ndescs = of_gpio_named_count(np, "cs-gpios");
+ if (ndescs < 0) {
+ dev_dbg(dev, "No valid cs-gpios property\n");
+ return 0;
+ }
+
+ descs = devm_kcalloc(dev, ndescs, sizeof(*descs), GFP_KERNEL);
+ if (!descs)
+ return -ENOMEM;
+
+ for (i = 0; i < ndescs; i++) {
+ descs[i] = gpiod_get_index_optional(dev, "cs", i,
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(descs[i]))
+ return PTR_ERR(descs[i]);
+ }
+
+ *ncs_array = ndescs;
+ *cs_array = descs;
+
+ return 0;
+}
+EXPORT_SYMBOL(rawnand_dt_parse_gpio_cs);
+
static int rawnand_dt_init(struct nand_chip *chip)
{
struct nand_device *nand = mtd_to_nanddev(nand_to_mtd(chip));
diff --git a/drivers/mtd/nand/raw/nand_legacy.c b/drivers/mtd/nand/raw/nand_legacy.c
index eccc18b266d5..743792edf98d 100644
--- a/drivers/mtd/nand/raw/nand_legacy.c
+++ b/drivers/mtd/nand/raw/nand_legacy.c
@@ -369,7 +369,7 @@ static void nand_ccs_delay(struct nand_chip *chip)
* Wait tCCS_min if it is correctly defined, otherwise wait 500ns
* (which should be safe for all NANDs).
*/
- if (nand_controller_can_setup_interface(chip))
+ if (!IS_ERR(sdr) && nand_controller_can_setup_interface(chip))
ndelay(sdr->tCCS_min / 1000);
else
ndelay(500);
diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c
index 45649e03797d..7586befce7f9 100644
--- a/drivers/mtd/nand/raw/nand_onfi.c
+++ b/drivers/mtd/nand/raw/nand_onfi.c
@@ -315,7 +315,10 @@ int nand_onfi_detect(struct nand_chip *chip)
onfi->tBERS = le16_to_cpu(p->t_bers);
onfi->tR = le16_to_cpu(p->t_r);
onfi->tCCS = le16_to_cpu(p->t_ccs);
- onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode);
+ onfi->fast_tCAD = le16_to_cpu(p->nvddr_nvddr2_features) & BIT(0);
+ onfi->sdr_timing_modes = le16_to_cpu(p->sdr_timing_modes);
+ if (le16_to_cpu(p->features) & ONFI_FEATURE_NV_DDR)
+ onfi->nvddr_timing_modes = le16_to_cpu(p->nvddr_timing_modes);
onfi->vendor_revision = le16_to_cpu(p->vendor_revision);
memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));
chip->parameters.onfi = onfi;
diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c
index 94d832646487..7b41afc372d2 100644
--- a/drivers/mtd/nand/raw/nand_timings.c
+++ b/drivers/mtd/nand/raw/nand_timings.c
@@ -292,6 +292,261 @@ static const struct nand_interface_config onfi_sdr_timings[] = {
},
};
+static const struct nand_interface_config onfi_nvddr_timings[] = {
+ /* Mode 0 */
+ {
+ .type = NAND_NVDDR_IFACE,
+ .timings.mode = 0,
+ .timings.nvddr = {
+ .tCCS_min = 500000,
+ .tR_max = 200000000,
+ .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
+ .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
+ .tAC_min = 3000,
+ .tAC_max = 25000,
+ .tADL_min = 400000,
+ .tCAD_min = 45000,
+ .tCAH_min = 10000,
+ .tCALH_min = 10000,
+ .tCALS_min = 10000,
+ .tCAS_min = 10000,
+ .tCEH_min = 20000,
+ .tCH_min = 10000,
+ .tCK_min = 50000,
+ .tCS_min = 35000,
+ .tDH_min = 5000,
+ .tDQSCK_min = 3000,
+ .tDQSCK_max = 25000,
+ .tDQSD_min = 0,
+ .tDQSD_max = 18000,
+ .tDQSHZ_max = 20000,
+ .tDQSQ_max = 5000,
+ .tDS_min = 5000,
+ .tDSC_min = 50000,
+ .tFEAT_max = 1000000,
+ .tITC_max = 1000000,
+ .tQHS_max = 6000,
+ .tRHW_min = 100000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWHR_min = 80000,
+ .tWRCK_min = 20000,
+ .tWW_min = 100000,
+ },
+ },
+ /* Mode 1 */
+ {
+ .type = NAND_NVDDR_IFACE,
+ .timings.mode = 1,
+ .timings.nvddr = {
+ .tCCS_min = 500000,
+ .tR_max = 200000000,
+ .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
+ .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
+ .tAC_min = 3000,
+ .tAC_max = 25000,
+ .tADL_min = 400000,
+ .tCAD_min = 45000,
+ .tCAH_min = 5000,
+ .tCALH_min = 5000,
+ .tCALS_min = 5000,
+ .tCAS_min = 5000,
+ .tCEH_min = 20000,
+ .tCH_min = 5000,
+ .tCK_min = 30000,
+ .tCS_min = 25000,
+ .tDH_min = 2500,
+ .tDQSCK_min = 3000,
+ .tDQSCK_max = 25000,
+ .tDQSD_min = 0,
+ .tDQSD_max = 18000,
+ .tDQSHZ_max = 20000,
+ .tDQSQ_max = 2500,
+ .tDS_min = 3000,
+ .tDSC_min = 30000,
+ .tFEAT_max = 1000000,
+ .tITC_max = 1000000,
+ .tQHS_max = 3000,
+ .tRHW_min = 100000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWHR_min = 80000,
+ .tWRCK_min = 20000,
+ .tWW_min = 100000,
+ },
+ },
+ /* Mode 2 */
+ {
+ .type = NAND_NVDDR_IFACE,
+ .timings.mode = 2,
+ .timings.nvddr = {
+ .tCCS_min = 500000,
+ .tR_max = 200000000,
+ .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
+ .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
+ .tAC_min = 3000,
+ .tAC_max = 25000,
+ .tADL_min = 400000,
+ .tCAD_min = 45000,
+ .tCAH_min = 4000,
+ .tCALH_min = 4000,
+ .tCALS_min = 4000,
+ .tCAS_min = 4000,
+ .tCEH_min = 20000,
+ .tCH_min = 4000,
+ .tCK_min = 20000,
+ .tCS_min = 15000,
+ .tDH_min = 1700,
+ .tDQSCK_min = 3000,
+ .tDQSCK_max = 25000,
+ .tDQSD_min = 0,
+ .tDQSD_max = 18000,
+ .tDQSHZ_max = 20000,
+ .tDQSQ_max = 1700,
+ .tDS_min = 2000,
+ .tDSC_min = 20000,
+ .tFEAT_max = 1000000,
+ .tITC_max = 1000000,
+ .tQHS_max = 2000,
+ .tRHW_min = 100000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWHR_min = 80000,
+ .tWRCK_min = 20000,
+ .tWW_min = 100000,
+ },
+ },
+ /* Mode 3 */
+ {
+ .type = NAND_NVDDR_IFACE,
+ .timings.mode = 3,
+ .timings.nvddr = {
+ .tCCS_min = 500000,
+ .tR_max = 200000000,
+ .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
+ .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
+ .tAC_min = 3000,
+ .tAC_max = 25000,
+ .tADL_min = 400000,
+ .tCAD_min = 45000,
+ .tCAH_min = 3000,
+ .tCALH_min = 3000,
+ .tCALS_min = 3000,
+ .tCAS_min = 3000,
+ .tCEH_min = 20000,
+ .tCH_min = 3000,
+ .tCK_min = 15000,
+ .tCS_min = 15000,
+ .tDH_min = 1300,
+ .tDQSCK_min = 3000,
+ .tDQSCK_max = 25000,
+ .tDQSD_min = 0,
+ .tDQSD_max = 18000,
+ .tDQSHZ_max = 20000,
+ .tDQSQ_max = 1300,
+ .tDS_min = 1500,
+ .tDSC_min = 15000,
+ .tFEAT_max = 1000000,
+ .tITC_max = 1000000,
+ .tQHS_max = 1500,
+ .tRHW_min = 100000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWHR_min = 80000,
+ .tWRCK_min = 20000,
+ .tWW_min = 100000,
+ },
+ },
+ /* Mode 4 */
+ {
+ .type = NAND_NVDDR_IFACE,
+ .timings.mode = 4,
+ .timings.nvddr = {
+ .tCCS_min = 500000,
+ .tR_max = 200000000,
+ .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
+ .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
+ .tAC_min = 3000,
+ .tAC_max = 25000,
+ .tADL_min = 400000,
+ .tCAD_min = 45000,
+ .tCAH_min = 2500,
+ .tCALH_min = 2500,
+ .tCALS_min = 2500,
+ .tCAS_min = 2500,
+ .tCEH_min = 20000,
+ .tCH_min = 2500,
+ .tCK_min = 12000,
+ .tCS_min = 15000,
+ .tDH_min = 1100,
+ .tDQSCK_min = 3000,
+ .tDQSCK_max = 25000,
+ .tDQSD_min = 0,
+ .tDQSD_max = 18000,
+ .tDQSHZ_max = 20000,
+ .tDQSQ_max = 1000,
+ .tDS_min = 1100,
+ .tDSC_min = 12000,
+ .tFEAT_max = 1000000,
+ .tITC_max = 1000000,
+ .tQHS_max = 1200,
+ .tRHW_min = 100000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWHR_min = 80000,
+ .tWRCK_min = 20000,
+ .tWW_min = 100000,
+ },
+ },
+ /* Mode 5 */
+ {
+ .type = NAND_NVDDR_IFACE,
+ .timings.mode = 5,
+ .timings.nvddr = {
+ .tCCS_min = 500000,
+ .tR_max = 200000000,
+ .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
+ .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
+ .tAC_min = 3000,
+ .tAC_max = 25000,
+ .tADL_min = 400000,
+ .tCAD_min = 45000,
+ .tCAH_min = 2000,
+ .tCALH_min = 2000,
+ .tCALS_min = 2000,
+ .tCAS_min = 2000,
+ .tCEH_min = 20000,
+ .tCH_min = 2000,
+ .tCK_min = 10000,
+ .tCS_min = 15000,
+ .tDH_min = 900,
+ .tDQSCK_min = 3000,
+ .tDQSCK_max = 25000,
+ .tDQSD_min = 0,
+ .tDQSD_max = 18000,
+ .tDQSHZ_max = 20000,
+ .tDQSQ_max = 850,
+ .tDS_min = 900,
+ .tDSC_min = 10000,
+ .tFEAT_max = 1000000,
+ .tITC_max = 1000000,
+ .tQHS_max = 1000,
+ .tRHW_min = 100000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWHR_min = 80000,
+ .tWRCK_min = 20000,
+ .tWW_min = 100000,
+ },
+ },
+};
+
/* All NAND chips share the same reset data interface: SDR mode 0 */
const struct nand_interface_config *nand_get_reset_interface_config(void)
{
@@ -346,23 +601,60 @@ onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings)
}
/**
- * onfi_fill_interface_config - Initialize an interface config from a given
- * ONFI mode
+ * onfi_find_closest_nvddr_mode - Derive the closest ONFI NVDDR timing mode
+ * given a set of timings
+ * @spec_timings: the timings to challenge
+ */
+unsigned int
+onfi_find_closest_nvddr_mode(const struct nand_nvddr_timings *spec_timings)
+{
+ const struct nand_nvddr_timings *onfi_timings;
+ int mode;
+
+ for (mode = ARRAY_SIZE(onfi_nvddr_timings) - 1; mode > 0; mode--) {
+ onfi_timings = &onfi_nvddr_timings[mode].timings.nvddr;
+
+ if (spec_timings->tCCS_min <= onfi_timings->tCCS_min &&
+ spec_timings->tAC_min <= onfi_timings->tAC_min &&
+ spec_timings->tADL_min <= onfi_timings->tADL_min &&
+ spec_timings->tCAD_min <= onfi_timings->tCAD_min &&
+ spec_timings->tCAH_min <= onfi_timings->tCAH_min &&
+ spec_timings->tCALH_min <= onfi_timings->tCALH_min &&
+ spec_timings->tCALS_min <= onfi_timings->tCALS_min &&
+ spec_timings->tCAS_min <= onfi_timings->tCAS_min &&
+ spec_timings->tCEH_min <= onfi_timings->tCEH_min &&
+ spec_timings->tCH_min <= onfi_timings->tCH_min &&
+ spec_timings->tCK_min <= onfi_timings->tCK_min &&
+ spec_timings->tCS_min <= onfi_timings->tCS_min &&
+ spec_timings->tDH_min <= onfi_timings->tDH_min &&
+ spec_timings->tDQSCK_min <= onfi_timings->tDQSCK_min &&
+ spec_timings->tDQSD_min <= onfi_timings->tDQSD_min &&
+ spec_timings->tDS_min <= onfi_timings->tDS_min &&
+ spec_timings->tDSC_min <= onfi_timings->tDSC_min &&
+ spec_timings->tRHW_min <= onfi_timings->tRHW_min &&
+ spec_timings->tRR_min <= onfi_timings->tRR_min &&
+ spec_timings->tWHR_min <= onfi_timings->tWHR_min &&
+ spec_timings->tWRCK_min <= onfi_timings->tWRCK_min &&
+ spec_timings->tWW_min <= onfi_timings->tWW_min)
+ return mode;
+ }
+
+ return 0;
+}
+
+/*
+ * onfi_fill_sdr_interface_config - Initialize a SDR interface config from a
+ * given ONFI mode
* @chip: The NAND chip
* @iface: The interface configuration to fill
- * @type: The interface type
* @timing_mode: The ONFI timing mode
*/
-void onfi_fill_interface_config(struct nand_chip *chip,
- struct nand_interface_config *iface,
- enum nand_interface_type type,
- unsigned int timing_mode)
+static void onfi_fill_sdr_interface_config(struct nand_chip *chip,
+ struct nand_interface_config *iface,
+ unsigned int timing_mode)
{
struct onfi_params *onfi = chip->parameters.onfi;
- if (WARN_ON(type != NAND_SDR_IFACE))
- return;
-
if (WARN_ON(timing_mode >= ARRAY_SIZE(onfi_sdr_timings)))
return;
@@ -385,3 +677,61 @@ void onfi_fill_interface_config(struct nand_chip *chip,
timings->tCCS_min = 1000UL * onfi->tCCS;
}
}
+
+/**
+ * onfi_fill_nvddr_interface_config - Initialize a NVDDR interface config from a
+ * given ONFI mode
+ * @chip: The NAND chip
+ * @iface: The interface configuration to fill
+ * @timing_mode: The ONFI timing mode
+ */
+static void onfi_fill_nvddr_interface_config(struct nand_chip *chip,
+ struct nand_interface_config *iface,
+ unsigned int timing_mode)
+{
+ struct onfi_params *onfi = chip->parameters.onfi;
+
+ if (WARN_ON(timing_mode >= ARRAY_SIZE(onfi_nvddr_timings)))
+ return;
+
+ *iface = onfi_nvddr_timings[timing_mode];
+
+ /*
+ * Initialize timings that cannot be deduced from timing mode:
+ * tPROG, tBERS, tR, tCCS and tCAD.
+ * These information are part of the ONFI parameter page.
+ */
+ if (onfi) {
+ struct nand_nvddr_timings *timings = &iface->timings.nvddr;
+
+ /* microseconds -> picoseconds */
+ timings->tPROG_max = 1000000ULL * onfi->tPROG;
+ timings->tBERS_max = 1000000ULL * onfi->tBERS;
+ timings->tR_max = 1000000ULL * onfi->tR;
+
+ /* nanoseconds -> picoseconds */
+ timings->tCCS_min = 1000UL * onfi->tCCS;
+
+ if (onfi->fast_tCAD)
+ timings->tCAD_min = 25000;
+ }
+}
+
+/**
+ * onfi_fill_interface_config - Initialize an interface config from a given
+ * ONFI mode
+ * @chip: The NAND chip
+ * @iface: The interface configuration to fill
+ * @type: The interface type
+ * @timing_mode: The ONFI timing mode
+ */
+void onfi_fill_interface_config(struct nand_chip *chip,
+ struct nand_interface_config *iface,
+ enum nand_interface_type type,
+ unsigned int timing_mode)
+{
+ if (type == NAND_SDR_IFACE)
+ return onfi_fill_sdr_interface_config(chip, iface, timing_mode);
+ else
+ return onfi_fill_nvddr_interface_config(chip, iface, timing_mode);
+}
diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c
index c75e7a0b101f..b1839eef5b65 100644
--- a/drivers/mtd/nand/raw/omap2.c
+++ b/drivers/mtd/nand/raw/omap2.c
@@ -131,7 +131,7 @@
#define BCH_ECC_SIZE0 0x0 /* ecc_size0 = 0, no oob protection */
#define BCH_ECC_SIZE1 0x20 /* ecc_size1 = 32 */
-#define BADBLOCK_MARKER_LENGTH 2
+#define BBM_LEN 2
static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55,
0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78,
@@ -171,6 +171,10 @@ struct omap_nand_info {
struct device *elm_dev;
/* NAND ready gpio */
struct gpio_desc *ready_gpiod;
+ unsigned int neccpg;
+ unsigned int nsteps_per_eccpg;
+ unsigned int eccpg_size;
+ unsigned int eccpg_bytes;
};
static inline struct omap_nand_info *mtd_to_omap(struct mtd_info *mtd)
@@ -1355,7 +1359,7 @@ static int omap_elm_correct_data(struct nand_chip *chip, u_char *data,
{
struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
struct nand_ecc_ctrl *ecc = &info->nand.ecc;
- int eccsteps = info->nand.ecc.steps;
+ int eccsteps = info->nsteps_per_eccpg;
int i , j, stat = 0;
int eccflag, actual_eccbytes;
struct elm_errorvec err_vec[ERROR_VECTOR_MAX];
@@ -1525,24 +1529,37 @@ static int omap_write_page_bch(struct nand_chip *chip, const uint8_t *buf,
int oob_required, int page)
{
struct mtd_info *mtd = nand_to_mtd(chip);
- int ret;
+ struct omap_nand_info *info = mtd_to_omap(mtd);
uint8_t *ecc_calc = chip->ecc.calc_buf;
+ unsigned int eccpg;
+ int ret;
- nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+ ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+ if (ret)
+ return ret;
- /* Enable GPMC ecc engine */
- chip->ecc.hwctl(chip, NAND_ECC_WRITE);
+ for (eccpg = 0; eccpg < info->neccpg; eccpg++) {
+ /* Enable GPMC ecc engine */
+ chip->ecc.hwctl(chip, NAND_ECC_WRITE);
- /* Write data */
- chip->legacy.write_buf(chip, buf, mtd->writesize);
+ /* Write data */
+ chip->legacy.write_buf(chip, buf + (eccpg * info->eccpg_size),
+ info->eccpg_size);
- /* Update ecc vector from GPMC result registers */
- omap_calculate_ecc_bch_multi(mtd, buf, &ecc_calc[0]);
+ /* Update ecc vector from GPMC result registers */
+ ret = omap_calculate_ecc_bch_multi(mtd,
+ buf + (eccpg * info->eccpg_size),
+ ecc_calc);
+ if (ret)
+ return ret;
- ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
- chip->ecc.total);
- if (ret)
- return ret;
+ ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc,
+ chip->oob_poi,
+ eccpg * info->eccpg_bytes,
+ info->eccpg_bytes);
+ if (ret)
+ return ret;
+ }
/* Write ecc vector to OOB area */
chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
@@ -1566,12 +1583,13 @@ static int omap_write_subpage_bch(struct nand_chip *chip, u32 offset,
int oob_required, int page)
{
struct mtd_info *mtd = nand_to_mtd(chip);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
u8 *ecc_calc = chip->ecc.calc_buf;
int ecc_size = chip->ecc.size;
int ecc_bytes = chip->ecc.bytes;
- int ecc_steps = chip->ecc.steps;
u32 start_step = offset / ecc_size;
u32 end_step = (offset + data_len - 1) / ecc_size;
+ unsigned int eccpg;
int step, ret = 0;
/*
@@ -1580,36 +1598,48 @@ static int omap_write_subpage_bch(struct nand_chip *chip, u32 offset,
* ECC is calculated for all subpages but we choose
* only what we want.
*/
- nand_prog_page_begin_op(chip, page, 0, NULL, 0);
-
- /* Enable GPMC ECC engine */
- chip->ecc.hwctl(chip, NAND_ECC_WRITE);
-
- /* Write data */
- chip->legacy.write_buf(chip, buf, mtd->writesize);
+ ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+ if (ret)
+ return ret;
- for (step = 0; step < ecc_steps; step++) {
- /* mask ECC of un-touched subpages by padding 0xFF */
- if (step < start_step || step > end_step)
- memset(ecc_calc, 0xff, ecc_bytes);
- else
- ret = _omap_calculate_ecc_bch(mtd, buf, ecc_calc, step);
+ for (eccpg = 0; eccpg < info->neccpg; eccpg++) {
+ /* Enable GPMC ECC engine */
+ chip->ecc.hwctl(chip, NAND_ECC_WRITE);
+
+ /* Write data */
+ chip->legacy.write_buf(chip, buf + (eccpg * info->eccpg_size),
+ info->eccpg_size);
+
+ for (step = 0; step < info->nsteps_per_eccpg; step++) {
+ unsigned int base_step = eccpg * info->nsteps_per_eccpg;
+ const u8 *bufoffs = buf + (eccpg * info->eccpg_size);
+
+ /* Mask ECC of un-touched subpages with 0xFFs */
+ if ((step + base_step) < start_step ||
+ (step + base_step) > end_step)
+ memset(ecc_calc + (step * ecc_bytes), 0xff,
+ ecc_bytes);
+ else
+ ret = _omap_calculate_ecc_bch(mtd,
+ bufoffs + (step * ecc_size),
+ ecc_calc + (step * ecc_bytes),
+ step);
+
+ if (ret)
+ return ret;
+ }
+ /*
+ * Copy the calculated ECC for the whole page including the
+ * masked values (0xFF) corresponding to unwritten subpages.
+ */
+ ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi,
+ eccpg * info->eccpg_bytes,
+ info->eccpg_bytes);
if (ret)
return ret;
-
- buf += ecc_size;
- ecc_calc += ecc_bytes;
}
- /* copy calculated ECC for whole page to chip->buffer->oob */
- /* this include masked-value(0xFF) for unwritten subpages */
- ecc_calc = chip->ecc.calc_buf;
- ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
- chip->ecc.total);
- if (ret)
- return ret;
-
/* write OOB buffer to NAND device */
chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
@@ -1634,40 +1664,60 @@ static int omap_read_page_bch(struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
struct mtd_info *mtd = nand_to_mtd(chip);
+ struct omap_nand_info *info = mtd_to_omap(mtd);
uint8_t *ecc_calc = chip->ecc.calc_buf;
uint8_t *ecc_code = chip->ecc.code_buf;
+ unsigned int max_bitflips = 0, eccpg;
int stat, ret;
- unsigned int max_bitflips = 0;
-
- nand_read_page_op(chip, page, 0, NULL, 0);
- /* Enable GPMC ecc engine */
- chip->ecc.hwctl(chip, NAND_ECC_READ);
+ ret = nand_read_page_op(chip, page, 0, NULL, 0);
+ if (ret)
+ return ret;
- /* Read data */
- chip->legacy.read_buf(chip, buf, mtd->writesize);
+ for (eccpg = 0; eccpg < info->neccpg; eccpg++) {
+ /* Enable GPMC ecc engine */
+ chip->ecc.hwctl(chip, NAND_ECC_READ);
- /* Read oob bytes */
- nand_change_read_column_op(chip,
- mtd->writesize + BADBLOCK_MARKER_LENGTH,
- chip->oob_poi + BADBLOCK_MARKER_LENGTH,
- chip->ecc.total, false);
+ /* Read data */
+ ret = nand_change_read_column_op(chip, eccpg * info->eccpg_size,
+ buf + (eccpg * info->eccpg_size),
+ info->eccpg_size, false);
+ if (ret)
+ return ret;
- /* Calculate ecc bytes */
- omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc);
+ /* Read oob bytes */
+ ret = nand_change_read_column_op(chip,
+ mtd->writesize + BBM_LEN +
+ (eccpg * info->eccpg_bytes),
+ chip->oob_poi + BBM_LEN +
+ (eccpg * info->eccpg_bytes),
+ info->eccpg_bytes, false);
+ if (ret)
+ return ret;
- ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
- chip->ecc.total);
- if (ret)
- return ret;
+ /* Calculate ecc bytes */
+ ret = omap_calculate_ecc_bch_multi(mtd,
+ buf + (eccpg * info->eccpg_size),
+ ecc_calc);
+ if (ret)
+ return ret;
- stat = chip->ecc.correct(chip, buf, ecc_code, ecc_calc);
+ ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code,
+ chip->oob_poi,
+ eccpg * info->eccpg_bytes,
+ info->eccpg_bytes);
+ if (ret)
+ return ret;
- if (stat < 0) {
- mtd->ecc_stats.failed++;
- } else {
- mtd->ecc_stats.corrected += stat;
- max_bitflips = max_t(unsigned int, max_bitflips, stat);
+ stat = chip->ecc.correct(chip,
+ buf + (eccpg * info->eccpg_size),
+ ecc_code, ecc_calc);
+ if (stat < 0) {
+ mtd->ecc_stats.failed++;
+ } else {
+ mtd->ecc_stats.corrected += stat;
+ max_bitflips = max_t(unsigned int, max_bitflips, stat);
+ }
}
return max_bitflips;
@@ -1820,7 +1870,7 @@ static int omap_ooblayout_ecc(struct mtd_info *mtd, int section,
{
struct omap_nand_info *info = mtd_to_omap(mtd);
struct nand_chip *chip = &info->nand;
- int off = BADBLOCK_MARKER_LENGTH;
+ int off = BBM_LEN;
if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
!(chip->options & NAND_BUSWIDTH_16))
@@ -1840,7 +1890,7 @@ static int omap_ooblayout_free(struct mtd_info *mtd, int section,
{
struct omap_nand_info *info = mtd_to_omap(mtd);
struct nand_chip *chip = &info->nand;
- int off = BADBLOCK_MARKER_LENGTH;
+ int off = BBM_LEN;
if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
!(chip->options & NAND_BUSWIDTH_16))
@@ -1870,7 +1920,7 @@ static int omap_sw_ooblayout_ecc(struct mtd_info *mtd, int section,
struct nand_device *nand = mtd_to_nanddev(mtd);
unsigned int nsteps = nanddev_get_ecc_nsteps(nand);
unsigned int ecc_bytes = nanddev_get_ecc_bytes_per_step(nand);
- int off = BADBLOCK_MARKER_LENGTH;
+ int off = BBM_LEN;
if (section >= nsteps)
return -ERANGE;
@@ -1891,7 +1941,7 @@ static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section,
struct nand_device *nand = mtd_to_nanddev(mtd);
unsigned int nsteps = nanddev_get_ecc_nsteps(nand);
unsigned int ecc_bytes = nanddev_get_ecc_bytes_per_step(nand);
- int off = BADBLOCK_MARKER_LENGTH;
+ int off = BBM_LEN;
if (section)
return -ERANGE;
@@ -1920,7 +1970,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
struct mtd_info *mtd = nand_to_mtd(chip);
struct omap_nand_info *info = mtd_to_omap(mtd);
struct device *dev = &info->pdev->dev;
- int min_oobbytes = BADBLOCK_MARKER_LENGTH;
+ int min_oobbytes = BBM_LEN;
+ int elm_bch_strength = -1;
int oobbytes_per_step;
dma_cap_mask_t mask;
int err;
@@ -2074,12 +2125,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
chip->ecc.write_subpage = omap_write_subpage_bch;
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
oobbytes_per_step = chip->ecc.bytes;
-
- err = elm_config(info->elm_dev, BCH4_ECC,
- mtd->writesize / chip->ecc.size,
- chip->ecc.size, chip->ecc.bytes);
- if (err < 0)
- return err;
+ elm_bch_strength = BCH4_ECC;
break;
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
@@ -2116,13 +2162,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
chip->ecc.write_subpage = omap_write_subpage_bch;
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
oobbytes_per_step = chip->ecc.bytes;
-
- err = elm_config(info->elm_dev, BCH8_ECC,
- mtd->writesize / chip->ecc.size,
- chip->ecc.size, chip->ecc.bytes);
- if (err < 0)
- return err;
-
+ elm_bch_strength = BCH8_ECC;
break;
case OMAP_ECC_BCH16_CODE_HW:
@@ -2138,19 +2178,32 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
chip->ecc.write_subpage = omap_write_subpage_bch;
mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
oobbytes_per_step = chip->ecc.bytes;
-
- err = elm_config(info->elm_dev, BCH16_ECC,
- mtd->writesize / chip->ecc.size,
- chip->ecc.size, chip->ecc.bytes);
- if (err < 0)
- return err;
-
+ elm_bch_strength = BCH16_ECC;
break;
default:
dev_err(dev, "Invalid or unsupported ECC scheme\n");
return -EINVAL;
}
+ if (elm_bch_strength >= 0) {
+ chip->ecc.steps = mtd->writesize / chip->ecc.size;
+ info->neccpg = chip->ecc.steps / ERROR_VECTOR_MAX;
+ if (info->neccpg) {
+ info->nsteps_per_eccpg = ERROR_VECTOR_MAX;
+ } else {
+ info->neccpg = 1;
+ info->nsteps_per_eccpg = chip->ecc.steps;
+ }
+ info->eccpg_size = info->nsteps_per_eccpg * chip->ecc.size;
+ info->eccpg_bytes = info->nsteps_per_eccpg * chip->ecc.bytes;
+
+ err = elm_config(info->elm_dev, elm_bch_strength,
+ info->nsteps_per_eccpg, chip->ecc.size,
+ chip->ecc.bytes);
+ if (err < 0)
+ return err;
+ }
+
/* Check if NAND device's OOB is enough to store ECC signatures */
min_oobbytes += (oobbytes_per_step *
(mtd->writesize / chip->ecc.size));
diff --git a/drivers/mtd/nand/raw/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c
index 550695a4c1ab..2b21ce04b3ec 100644
--- a/drivers/mtd/nand/raw/omap_elm.c
+++ b/drivers/mtd/nand/raw/omap_elm.c
@@ -116,7 +116,7 @@ int elm_config(struct device *dev, enum bch_ecc bch_type,
return -EINVAL;
}
/* ELM support 8 error syndrome process */
- if (ecc_steps > ERROR_VECTOR_MAX) {
+ if (ecc_steps > ERROR_VECTOR_MAX && ecc_steps % ERROR_VECTOR_MAX) {
dev_err(dev, "unsupported config ecc-step=%d\n", ecc_steps);
return -EINVAL;
}
diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nand/raw/pl35x-nand-controller.c
new file mode 100644
index 000000000000..8a91e069ee2e
--- /dev/null
+++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c
@@ -0,0 +1,1194 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM PL35X NAND flash controller driver
+ *
+ * Copyright (C) 2017 Xilinx, Inc
+ * Author:
+ * Miquel Raynal <miquel.raynal@bootlin.com>
+ * Original work (rewritten):
+ * Punnaiah Choudary Kalluri <punnaia@xilinx.com>
+ * Naga Sureshkumar Relli <nagasure@xilinx.com>
+ */
+
+#include <linux/amba/bus.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/iopoll.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#define PL35X_NANDC_DRIVER_NAME "pl35x-nand-controller"
+
+/* SMC controller status register (RO) */
+#define PL35X_SMC_MEMC_STATUS 0x0
+#define PL35X_SMC_MEMC_STATUS_RAW_INT_STATUS1 BIT(6)
+/* SMC clear config register (WO) */
+#define PL35X_SMC_MEMC_CFG_CLR 0xC
+#define PL35X_SMC_MEMC_CFG_CLR_INT_DIS_1 BIT(1)
+#define PL35X_SMC_MEMC_CFG_CLR_INT_CLR_1 BIT(4)
+#define PL35X_SMC_MEMC_CFG_CLR_ECC_INT_DIS_1 BIT(6)
+/* SMC direct command register (WO) */
+#define PL35X_SMC_DIRECT_CMD 0x10
+#define PL35X_SMC_DIRECT_CMD_NAND_CS (0x4 << 23)
+#define PL35X_SMC_DIRECT_CMD_UPD_REGS (0x2 << 21)
+/* SMC set cycles register (WO) */
+#define PL35X_SMC_CYCLES 0x14
+#define PL35X_SMC_NAND_TRC_CYCLES(x) ((x) << 0)
+#define PL35X_SMC_NAND_TWC_CYCLES(x) ((x) << 4)
+#define PL35X_SMC_NAND_TREA_CYCLES(x) ((x) << 8)
+#define PL35X_SMC_NAND_TWP_CYCLES(x) ((x) << 11)
+#define PL35X_SMC_NAND_TCLR_CYCLES(x) ((x) << 14)
+#define PL35X_SMC_NAND_TAR_CYCLES(x) ((x) << 17)
+#define PL35X_SMC_NAND_TRR_CYCLES(x) ((x) << 20)
+/* SMC set opmode register (WO) */
+#define PL35X_SMC_OPMODE 0x18
+#define PL35X_SMC_OPMODE_BW_8 0
+#define PL35X_SMC_OPMODE_BW_16 1
+/* SMC ECC status register (RO) */
+#define PL35X_SMC_ECC_STATUS 0x400
+#define PL35X_SMC_ECC_STATUS_ECC_BUSY BIT(6)
+/* SMC ECC configuration register */
+#define PL35X_SMC_ECC_CFG 0x404
+#define PL35X_SMC_ECC_CFG_MODE_MASK 0xC
+#define PL35X_SMC_ECC_CFG_MODE_BYPASS 0
+#define PL35X_SMC_ECC_CFG_MODE_APB BIT(2)
+#define PL35X_SMC_ECC_CFG_MODE_MEM BIT(3)
+#define PL35X_SMC_ECC_CFG_PGSIZE_MASK 0x3
+/* SMC ECC command 1 register */
+#define PL35X_SMC_ECC_CMD1 0x408
+#define PL35X_SMC_ECC_CMD1_WRITE(x) ((x) << 0)
+#define PL35X_SMC_ECC_CMD1_READ(x) ((x) << 8)
+#define PL35X_SMC_ECC_CMD1_READ_END(x) ((x) << 16)
+#define PL35X_SMC_ECC_CMD1_READ_END_VALID(x) ((x) << 24)
+/* SMC ECC command 2 register */
+#define PL35X_SMC_ECC_CMD2 0x40C
+#define PL35X_SMC_ECC_CMD2_WRITE_COL_CHG(x) ((x) << 0)
+#define PL35X_SMC_ECC_CMD2_READ_COL_CHG(x) ((x) << 8)
+#define PL35X_SMC_ECC_CMD2_READ_COL_CHG_END(x) ((x) << 16)
+#define PL35X_SMC_ECC_CMD2_READ_COL_CHG_END_VALID(x) ((x) << 24)
+/* SMC ECC value registers (RO) */
+#define PL35X_SMC_ECC_VALUE(x) (0x418 + (4 * (x)))
+#define PL35X_SMC_ECC_VALUE_IS_CORRECTABLE(x) ((x) & BIT(27))
+#define PL35X_SMC_ECC_VALUE_HAS_FAILED(x) ((x) & BIT(28))
+#define PL35X_SMC_ECC_VALUE_IS_VALID(x) ((x) & BIT(30))
+
+/* NAND AXI interface */
+#define PL35X_SMC_CMD_PHASE 0
+#define PL35X_SMC_CMD_PHASE_CMD0(x) ((x) << 3)
+#define PL35X_SMC_CMD_PHASE_CMD1(x) ((x) << 11)
+#define PL35X_SMC_CMD_PHASE_CMD1_VALID BIT(20)
+#define PL35X_SMC_CMD_PHASE_ADDR(pos, x) ((x) << (8 * (pos)))
+#define PL35X_SMC_CMD_PHASE_NADDRS(x) ((x) << 21)
+#define PL35X_SMC_DATA_PHASE BIT(19)
+#define PL35X_SMC_DATA_PHASE_ECC_LAST BIT(10)
+#define PL35X_SMC_DATA_PHASE_CLEAR_CS BIT(21)
+
+#define PL35X_NAND_MAX_CS 1
+#define PL35X_NAND_LAST_XFER_SZ 4
+#define TO_CYCLES(ps, period_ns) (DIV_ROUND_UP((ps) / 1000, period_ns))
+
+#define PL35X_NAND_ECC_BITS_MASK 0xFFF
+#define PL35X_NAND_ECC_BYTE_OFF_MASK 0x1FF
+#define PL35X_NAND_ECC_BIT_OFF_MASK 0x7
+
+struct pl35x_nand_timings {
+ unsigned int t_rc:4;
+ unsigned int t_wc:4;
+ unsigned int t_rea:3;
+ unsigned int t_wp:3;
+ unsigned int t_clr:3;
+ unsigned int t_ar:3;
+ unsigned int t_rr:4;
+ unsigned int rsvd:8;
+};
+
+struct pl35x_nand {
+ struct list_head node;
+ struct nand_chip chip;
+ unsigned int cs;
+ unsigned int addr_cycles;
+ u32 ecc_cfg;
+ u32 timings;
+};
+
+/**
+ * struct pl35x_nandc - NAND flash controller driver structure
+ * @dev: Kernel device
+ * @conf_regs: SMC configuration registers for command phase
+ * @io_regs: NAND data registers for data phase
+ * @controller: Core NAND controller structure
+ * @chip: NAND chip information structure
+ * @selected_chip: NAND chip currently selected by the controller
+ * @assigned_cs: List of assigned CS
+ * @ecc_buf: Temporary buffer to extract ECC bytes
+ */
+struct pl35x_nandc {
+ struct device *dev;
+ void __iomem *conf_regs;
+ void __iomem *io_regs;
+ struct nand_controller controller;
+ struct list_head chips;
+ struct nand_chip *selected_chip;
+ unsigned long assigned_cs;
+ u8 *ecc_buf;
+};
+
+static inline struct pl35x_nandc *to_pl35x_nandc(struct nand_controller *ctrl)
+{
+ return container_of(ctrl, struct pl35x_nandc, controller);
+}
+
+static inline struct pl35x_nand *to_pl35x_nand(struct nand_chip *chip)
+{
+ return container_of(chip, struct pl35x_nand, chip);
+}
+
+static int pl35x_ecc_ooblayout16_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (section >= chip->ecc.steps)
+ return -ERANGE;
+
+ oobregion->offset = (section * chip->ecc.bytes);
+ oobregion->length = chip->ecc.bytes;
+
+ return 0;
+}
+
+static int pl35x_ecc_ooblayout16_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (section >= chip->ecc.steps)
+ return -ERANGE;
+
+ oobregion->offset = (section * chip->ecc.bytes) + 8;
+ oobregion->length = 8;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops pl35x_ecc_ooblayout16_ops = {
+ .ecc = pl35x_ecc_ooblayout16_ecc,
+ .free = pl35x_ecc_ooblayout16_free,
+};
+
+/* Generic flash bbt decriptors */
+static u8 bbt_pattern[] = { 'B', 'b', 't', '0' };
+static u8 mirror_pattern[] = { '1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ .offs = 4,
+ .len = 4,
+ .veroffs = 20,
+ .maxblocks = 4,
+ .pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+ | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ .offs = 4,
+ .len = 4,
+ .veroffs = 20,
+ .maxblocks = 4,
+ .pattern = mirror_pattern
+};
+
+static void pl35x_smc_update_regs(struct pl35x_nandc *nfc)
+{
+ writel(PL35X_SMC_DIRECT_CMD_NAND_CS |
+ PL35X_SMC_DIRECT_CMD_UPD_REGS,
+ nfc->conf_regs + PL35X_SMC_DIRECT_CMD);
+}
+
+static int pl35x_smc_set_buswidth(struct pl35x_nandc *nfc, unsigned int bw)
+{
+ if (bw != PL35X_SMC_OPMODE_BW_8 && bw != PL35X_SMC_OPMODE_BW_16)
+ return -EINVAL;
+
+ writel(bw, nfc->conf_regs + PL35X_SMC_OPMODE);
+ pl35x_smc_update_regs(nfc);
+
+ return 0;
+}
+
+static void pl35x_smc_clear_irq(struct pl35x_nandc *nfc)
+{
+ writel(PL35X_SMC_MEMC_CFG_CLR_INT_CLR_1,
+ nfc->conf_regs + PL35X_SMC_MEMC_CFG_CLR);
+}
+
+static int pl35x_smc_wait_for_irq(struct pl35x_nandc *nfc)
+{
+ u32 reg;
+ int ret;
+
+ ret = readl_poll_timeout(nfc->conf_regs + PL35X_SMC_MEMC_STATUS, reg,
+ reg & PL35X_SMC_MEMC_STATUS_RAW_INT_STATUS1,
+ 10, 1000000);
+ if (ret)
+ dev_err(nfc->dev,
+ "Timeout polling on NAND controller interrupt (0x%x)\n",
+ reg);
+
+ pl35x_smc_clear_irq(nfc);
+
+ return ret;
+}
+
+static int pl35x_smc_wait_for_ecc_done(struct pl35x_nandc *nfc)
+{
+ u32 reg;
+ int ret;
+
+ ret = readl_poll_timeout(nfc->conf_regs + PL35X_SMC_ECC_STATUS, reg,
+ !(reg & PL35X_SMC_ECC_STATUS_ECC_BUSY),
+ 10, 1000000);
+ if (ret)
+ dev_err(nfc->dev,
+ "Timeout polling on ECC controller interrupt\n");
+
+ return ret;
+}
+
+static int pl35x_smc_set_ecc_mode(struct pl35x_nandc *nfc,
+ struct nand_chip *chip,
+ unsigned int mode)
+{
+ struct pl35x_nand *plnand;
+ u32 ecc_cfg;
+
+ ecc_cfg = readl(nfc->conf_regs + PL35X_SMC_ECC_CFG);
+ ecc_cfg &= ~PL35X_SMC_ECC_CFG_MODE_MASK;
+ ecc_cfg |= mode;
+ writel(ecc_cfg, nfc->conf_regs + PL35X_SMC_ECC_CFG);
+
+ if (chip) {
+ plnand = to_pl35x_nand(chip);
+ plnand->ecc_cfg = ecc_cfg;
+ }
+
+ if (mode != PL35X_SMC_ECC_CFG_MODE_BYPASS)
+ return pl35x_smc_wait_for_ecc_done(nfc);
+
+ return 0;
+}
+
+static void pl35x_smc_force_byte_access(struct nand_chip *chip,
+ bool force_8bit)
+{
+ struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
+ int ret;
+
+ if (!(chip->options & NAND_BUSWIDTH_16))
+ return;
+
+ if (force_8bit)
+ ret = pl35x_smc_set_buswidth(nfc, PL35X_SMC_OPMODE_BW_8);
+ else
+ ret = pl35x_smc_set_buswidth(nfc, PL35X_SMC_OPMODE_BW_16);
+
+ if (ret)
+ dev_err(nfc->dev, "Error in Buswidth\n");
+}
+
+static void pl35x_nand_select_target(struct nand_chip *chip,
+ unsigned int die_nr)
+{
+ struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
+ struct pl35x_nand *plnand = to_pl35x_nand(chip);
+
+ if (chip == nfc->selected_chip)
+ return;
+
+ /* Setup the timings */
+ writel(plnand->timings, nfc->conf_regs + PL35X_SMC_CYCLES);
+ pl35x_smc_update_regs(nfc);
+
+ /* Configure the ECC engine */
+ writel(plnand->ecc_cfg, nfc->conf_regs + PL35X_SMC_ECC_CFG);
+
+ nfc->selected_chip = chip;
+}
+
+static void pl35x_nand_read_data_op(struct nand_chip *chip, u8 *in,
+ unsigned int len, bool force_8bit,
+ unsigned int flags, unsigned int last_flags)
+{
+ struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
+ unsigned int buf_end = len / 4;
+ unsigned int in_start = round_down(len, 4);
+ unsigned int data_phase_addr;
+ u32 *buf32 = (u32 *)in;
+ u8 *buf8 = (u8 *)in;
+ int i;
+
+ if (force_8bit)
+ pl35x_smc_force_byte_access(chip, true);
+
+ for (i = 0; i < buf_end; i++) {
+ data_phase_addr = PL35X_SMC_DATA_PHASE + flags;
+ if (i + 1 == buf_end)
+ data_phase_addr = PL35X_SMC_DATA_PHASE + last_flags;
+
+ buf32[i] = readl(nfc->io_regs + data_phase_addr);
+ }
+
+ /* No working extra flags on unaligned data accesses */
+ for (i = in_start; i < len; i++)
+ buf8[i] = readb(nfc->io_regs + PL35X_SMC_DATA_PHASE);
+
+ if (force_8bit)
+ pl35x_smc_force_byte_access(chip, false);
+}
+
+static void pl35x_nand_write_data_op(struct nand_chip *chip, const u8 *out,
+ int len, bool force_8bit,
+ unsigned int flags,
+ unsigned int last_flags)
+{
+ struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
+ unsigned int buf_end = len / 4;
+ unsigned int in_start = round_down(len, 4);
+ const u32 *buf32 = (const u32 *)out;
+ const u8 *buf8 = (const u8 *)out;
+ unsigned int data_phase_addr;
+ int i;
+
+ if (force_8bit)
+ pl35x_smc_force_byte_access(chip, true);
+
+ for (i = 0; i < buf_end; i++) {
+ data_phase_addr = PL35X_SMC_DATA_PHASE + flags;
+ if (i + 1 == buf_end)
+ data_phase_addr = PL35X_SMC_DATA_PHASE + last_flags;
+
+ writel(buf32[i], nfc->io_regs + data_phase_addr);
+ }
+
+ /* No working extra flags on unaligned data accesses */
+ for (i = in_start; i < len; i++)
+ writeb(buf8[i], nfc->io_regs + PL35X_SMC_DATA_PHASE);
+
+ if (force_8bit)
+ pl35x_smc_force_byte_access(chip, false);
+}
+
+static int pl35x_nand_correct_data(struct pl35x_nandc *nfc, unsigned char *buf,
+ unsigned char *read_ecc,
+ unsigned char *calc_ecc)
+{
+ unsigned short ecc_odd, ecc_even, read_ecc_lower, read_ecc_upper;
+ unsigned short calc_ecc_lower, calc_ecc_upper;
+ unsigned short byte_addr, bit_addr;
+
+ read_ecc_lower = (read_ecc[0] | (read_ecc[1] << 8)) &
+ PL35X_NAND_ECC_BITS_MASK;
+ read_ecc_upper = ((read_ecc[1] >> 4) | (read_ecc[2] << 4)) &
+ PL35X_NAND_ECC_BITS_MASK;
+
+ calc_ecc_lower = (calc_ecc[0] | (calc_ecc[1] << 8)) &
+ PL35X_NAND_ECC_BITS_MASK;
+ calc_ecc_upper = ((calc_ecc[1] >> 4) | (calc_ecc[2] << 4)) &
+ PL35X_NAND_ECC_BITS_MASK;
+
+ ecc_odd = read_ecc_lower ^ calc_ecc_lower;
+ ecc_even = read_ecc_upper ^ calc_ecc_upper;
+
+ /* No error */
+ if (likely(!ecc_odd && !ecc_even))
+ return 0;
+
+ /* One error in the main data; to be corrected */
+ if (ecc_odd == (~ecc_even & PL35X_NAND_ECC_BITS_MASK)) {
+ /* Bits [11:3] of error code give the byte offset */
+ byte_addr = (ecc_odd >> 3) & PL35X_NAND_ECC_BYTE_OFF_MASK;
+ /* Bits [2:0] of error code give the bit offset */
+ bit_addr = ecc_odd & PL35X_NAND_ECC_BIT_OFF_MASK;
+ /* Toggle the faulty bit */
+ buf[byte_addr] ^= (BIT(bit_addr));
+
+ return 1;
+ }
+
+ /* One error in the ECC data; no action needed */
+ if (hweight32(ecc_odd | ecc_even) == 1)
+ return 1;
+
+ return -EBADMSG;
+}
+
+static void pl35x_nand_ecc_reg_to_array(struct nand_chip *chip, u32 ecc_reg,
+ u8 *ecc_array)
+{
+ u32 ecc_value = ~ecc_reg;
+ unsigned int ecc_byte;
+
+ for (ecc_byte = 0; ecc_byte < chip->ecc.bytes; ecc_byte++)
+ ecc_array[ecc_byte] = ecc_value >> (8 * ecc_byte);
+}
+
+static int pl35x_nand_read_eccbytes(struct pl35x_nandc *nfc,
+ struct nand_chip *chip, u8 *read_ecc)
+{
+ u32 ecc_value;
+ int chunk;
+
+ for (chunk = 0; chunk < chip->ecc.steps;
+ chunk++, read_ecc += chip->ecc.bytes) {
+ ecc_value = readl(nfc->conf_regs + PL35X_SMC_ECC_VALUE(chunk));
+ if (!PL35X_SMC_ECC_VALUE_IS_VALID(ecc_value))
+ return -EINVAL;
+
+ pl35x_nand_ecc_reg_to_array(chip, ecc_value, read_ecc);
+ }
+
+ return 0;
+}
+
+static int pl35x_nand_recover_data_hwecc(struct pl35x_nandc *nfc,
+ struct nand_chip *chip, u8 *data,
+ u8 *read_ecc)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ unsigned int max_bitflips = 0, chunk;
+ u8 calc_ecc[3];
+ u32 ecc_value;
+ int stats;
+
+ for (chunk = 0; chunk < chip->ecc.steps;
+ chunk++, data += chip->ecc.size, read_ecc += chip->ecc.bytes) {
+ /* Read ECC value for each chunk */
+ ecc_value = readl(nfc->conf_regs + PL35X_SMC_ECC_VALUE(chunk));
+
+ if (!PL35X_SMC_ECC_VALUE_IS_VALID(ecc_value))
+ return -EINVAL;
+
+ if (PL35X_SMC_ECC_VALUE_HAS_FAILED(ecc_value)) {
+ mtd->ecc_stats.failed++;
+ continue;
+ }
+
+ pl35x_nand_ecc_reg_to_array(chip, ecc_value, calc_ecc);
+ stats = pl35x_nand_correct_data(nfc, data, read_ecc, calc_ecc);
+ if (stats < 0) {
+ mtd->ecc_stats.failed++;
+ } else {
+ mtd->ecc_stats.corrected += stats;
+ max_bitflips = max_t(unsigned int, max_bitflips, stats);
+ }
+ }
+
+ return max_bitflips;
+}
+
+static int pl35x_nand_write_page_hwecc(struct nand_chip *chip,
+ const u8 *buf, int oob_required,
+ int page)
+{
+ struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
+ struct pl35x_nand *plnand = to_pl35x_nand(chip);
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ unsigned int first_row = (mtd->writesize <= 512) ? 1 : 2;
+ unsigned int nrows = plnand->addr_cycles;
+ u32 addr1 = 0, addr2 = 0, row;
+ u32 cmd_addr;
+ int i, ret;
+
+ ret = pl35x_smc_set_ecc_mode(nfc, chip, PL35X_SMC_ECC_CFG_MODE_APB);
+ if (ret)
+ return ret;
+
+ cmd_addr = PL35X_SMC_CMD_PHASE |
+ PL35X_SMC_CMD_PHASE_NADDRS(plnand->addr_cycles) |
+ PL35X_SMC_CMD_PHASE_CMD0(NAND_CMD_SEQIN);
+
+ for (i = 0, row = first_row; row < nrows; i++, row++) {
+ u8 addr = page >> ((i * 8) & 0xFF);
+
+ if (row < 4)
+ addr1 |= PL35X_SMC_CMD_PHASE_ADDR(row, addr);
+ else
+ addr2 |= PL35X_SMC_CMD_PHASE_ADDR(row - 4, addr);
+ }
+
+ /* Send the command and address cycles */
+ writel(addr1, nfc->io_regs + cmd_addr);
+ if (plnand->addr_cycles > 4)
+ writel(addr2, nfc->io_regs + cmd_addr);
+
+ /* Write the data with the engine enabled */
+ pl35x_nand_write_data_op(chip, buf, mtd->writesize, false,
+ 0, PL35X_SMC_DATA_PHASE_ECC_LAST);
+ ret = pl35x_smc_wait_for_ecc_done(nfc);
+ if (ret)
+ goto disable_ecc_engine;
+
+ /* Copy the HW calculated ECC bytes in the OOB buffer */
+ ret = pl35x_nand_read_eccbytes(nfc, chip, nfc->ecc_buf);
+ if (ret)
+ goto disable_ecc_engine;
+
+ if (!oob_required)
+ memset(chip->oob_poi, 0xFF, mtd->oobsize);
+
+ ret = mtd_ooblayout_set_eccbytes(mtd, nfc->ecc_buf, chip->oob_poi,
+ 0, chip->ecc.total);
+ if (ret)
+ goto disable_ecc_engine;
+
+ /* Write the spare area with ECC bytes */
+ pl35x_nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false, 0,
+ PL35X_SMC_CMD_PHASE_CMD1(NAND_CMD_PAGEPROG) |
+ PL35X_SMC_CMD_PHASE_CMD1_VALID |
+ PL35X_SMC_DATA_PHASE_CLEAR_CS);
+ ret = pl35x_smc_wait_for_irq(nfc);
+ if (ret)
+ goto disable_ecc_engine;
+
+disable_ecc_engine:
+ pl35x_smc_set_ecc_mode(nfc, chip, PL35X_SMC_ECC_CFG_MODE_BYPASS);
+
+ return ret;
+}
+
+/*
+ * This functions reads data and checks the data integrity by comparing hardware
+ * generated ECC values and read ECC values from spare area.
+ *
+ * There is a limitation with SMC controller: ECC_LAST must be set on the
+ * last data access to tell the ECC engine not to expect any further data.
+ * In practice, this implies to shrink the last data transfert by eg. 4 bytes,
+ * and doing a last 4-byte transfer with the additional bit set. The last block
+ * should be aligned with the end of an ECC block. Because of this limitation,
+ * it is not possible to use the core routines.
+ */
+static int pl35x_nand_read_page_hwecc(struct nand_chip *chip,
+ u8 *buf, int oob_required, int page)
+{
+ const struct nand_sdr_timings *sdr =
+ nand_get_sdr_timings(nand_get_interface_config(chip));
+ struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
+ struct pl35x_nand *plnand = to_pl35x_nand(chip);
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ unsigned int first_row = (mtd->writesize <= 512) ? 1 : 2;
+ unsigned int nrows = plnand->addr_cycles;
+ unsigned int addr1 = 0, addr2 = 0, row;
+ u32 cmd_addr;
+ int i, ret;
+
+ ret = pl35x_smc_set_ecc_mode(nfc, chip, PL35X_SMC_ECC_CFG_MODE_APB);
+ if (ret)
+ return ret;
+
+ cmd_addr = PL35X_SMC_CMD_PHASE |
+ PL35X_SMC_CMD_PHASE_NADDRS(plnand->addr_cycles) |
+ PL35X_SMC_CMD_PHASE_CMD0(NAND_CMD_READ0) |
+ PL35X_SMC_CMD_PHASE_CMD1(NAND_CMD_READSTART) |
+ PL35X_SMC_CMD_PHASE_CMD1_VALID;
+
+ for (i = 0, row = first_row; row < nrows; i++, row++) {
+ u8 addr = page >> ((i * 8) & 0xFF);
+
+ if (row < 4)
+ addr1 |= PL35X_SMC_CMD_PHASE_ADDR(row, addr);
+ else
+ addr2 |= PL35X_SMC_CMD_PHASE_ADDR(row - 4, addr);
+ }
+
+ /* Send the command and address cycles */
+ writel(addr1, nfc->io_regs + cmd_addr);
+ if (plnand->addr_cycles > 4)
+ writel(addr2, nfc->io_regs + cmd_addr);
+
+ /* Wait the data to be available in the NAND cache */
+ ndelay(PSEC_TO_NSEC(sdr->tRR_min));
+ ret = pl35x_smc_wait_for_irq(nfc);
+ if (ret)
+ goto disable_ecc_engine;
+
+ /* Retrieve the raw data with the engine enabled */
+ pl35x_nand_read_data_op(chip, buf, mtd->writesize, false,
+ 0, PL35X_SMC_DATA_PHASE_ECC_LAST);
+ ret = pl35x_smc_wait_for_ecc_done(nfc);
+ if (ret)
+ goto disable_ecc_engine;
+
+ /* Retrieve the stored ECC bytes */
+ pl35x_nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false,
+ 0, PL35X_SMC_DATA_PHASE_CLEAR_CS);
+ ret = mtd_ooblayout_get_eccbytes(mtd, nfc->ecc_buf, chip->oob_poi, 0,
+ chip->ecc.total);
+ if (ret)
+ goto disable_ecc_engine;
+
+ pl35x_smc_set_ecc_mode(nfc, chip, PL35X_SMC_ECC_CFG_MODE_BYPASS);
+
+ /* Correct the data and report failures */
+ return pl35x_nand_recover_data_hwecc(nfc, chip, buf, nfc->ecc_buf);
+
+disable_ecc_engine:
+ pl35x_smc_set_ecc_mode(nfc, chip, PL35X_SMC_ECC_CFG_MODE_BYPASS);
+
+ return ret;
+}
+
+static int pl35x_nand_exec_op(struct nand_chip *chip,
+ const struct nand_subop *subop)
+{
+ struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
+ const struct nand_op_instr *instr, *data_instr = NULL;
+ unsigned int rdy_tim_ms = 0, naddrs = 0, cmds = 0, last_flags = 0;
+ u32 addr1 = 0, addr2 = 0, cmd0 = 0, cmd1 = 0, cmd_addr = 0;
+ unsigned int op_id, len, offset, rdy_del_ns;
+ int last_instr_type = -1;
+ bool cmd1_valid = false;
+ const u8 *addrs;
+ int i, ret;
+
+ for (op_id = 0; op_id < subop->ninstrs; op_id++) {
+ instr = &subop->instrs[op_id];
+
+ switch (instr->type) {
+ case NAND_OP_CMD_INSTR:
+ if (!cmds) {
+ cmd0 = PL35X_SMC_CMD_PHASE_CMD0(instr->ctx.cmd.opcode);
+ } else {
+ cmd1 = PL35X_SMC_CMD_PHASE_CMD1(instr->ctx.cmd.opcode);
+ if (last_instr_type != NAND_OP_DATA_OUT_INSTR)
+ cmd1_valid = true;
+ }
+ cmds++;
+ break;
+
+ case NAND_OP_ADDR_INSTR:
+ offset = nand_subop_get_addr_start_off(subop, op_id);
+ naddrs = nand_subop_get_num_addr_cyc(subop, op_id);
+ addrs = &instr->ctx.addr.addrs[offset];
+ cmd_addr |= PL35X_SMC_CMD_PHASE_NADDRS(naddrs);
+
+ for (i = offset; i < naddrs; i++) {
+ if (i < 4)
+ addr1 |= PL35X_SMC_CMD_PHASE_ADDR(i, addrs[i]);
+ else
+ addr2 |= PL35X_SMC_CMD_PHASE_ADDR(i - 4, addrs[i]);
+ }
+ break;
+
+ case NAND_OP_DATA_IN_INSTR:
+ case NAND_OP_DATA_OUT_INSTR:
+ data_instr = instr;
+ len = nand_subop_get_data_len(subop, op_id);
+ break;
+
+ case NAND_OP_WAITRDY_INSTR:
+ rdy_tim_ms = instr->ctx.waitrdy.timeout_ms;
+ rdy_del_ns = instr->delay_ns;
+ break;
+ }
+
+ last_instr_type = instr->type;
+ }
+
+ /* Command phase */
+ cmd_addr |= PL35X_SMC_CMD_PHASE | cmd0 | cmd1 |
+ (cmd1_valid ? PL35X_SMC_CMD_PHASE_CMD1_VALID : 0);
+ writel(addr1, nfc->io_regs + cmd_addr);
+ if (naddrs > 4)
+ writel(addr2, nfc->io_regs + cmd_addr);
+
+ /* Data phase */
+ if (data_instr && data_instr->type == NAND_OP_DATA_OUT_INSTR) {
+ last_flags = PL35X_SMC_DATA_PHASE_CLEAR_CS;
+ if (cmds == 2)
+ last_flags |= cmd1 | PL35X_SMC_CMD_PHASE_CMD1_VALID;
+
+ pl35x_nand_write_data_op(chip, data_instr->ctx.data.buf.out,
+ len, data_instr->ctx.data.force_8bit,
+ 0, last_flags);
+ }
+
+ if (rdy_tim_ms) {
+ ndelay(rdy_del_ns);
+ ret = pl35x_smc_wait_for_irq(nfc);
+ if (ret)
+ return ret;
+ }
+
+ if (data_instr && data_instr->type == NAND_OP_DATA_IN_INSTR)
+ pl35x_nand_read_data_op(chip, data_instr->ctx.data.buf.in,
+ len, data_instr->ctx.data.force_8bit,
+ 0, PL35X_SMC_DATA_PHASE_CLEAR_CS);
+
+ return 0;
+}
+
+static const struct nand_op_parser pl35x_nandc_op_parser = NAND_OP_PARSER(
+ NAND_OP_PARSER_PATTERN(pl35x_nand_exec_op,
+ NAND_OP_PARSER_PAT_CMD_ELEM(true),
+ NAND_OP_PARSER_PAT_ADDR_ELEM(true, 7),
+ NAND_OP_PARSER_PAT_CMD_ELEM(true),
+ NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
+ NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, 2112)),
+ NAND_OP_PARSER_PATTERN(pl35x_nand_exec_op,
+ NAND_OP_PARSER_PAT_CMD_ELEM(false),
+ NAND_OP_PARSER_PAT_ADDR_ELEM(false, 7),
+ NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, 2112),
+ NAND_OP_PARSER_PAT_CMD_ELEM(false),
+ NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
+ NAND_OP_PARSER_PATTERN(pl35x_nand_exec_op,
+ NAND_OP_PARSER_PAT_CMD_ELEM(false),
+ NAND_OP_PARSER_PAT_ADDR_ELEM(false, 7),
+ NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, 2112),
+ NAND_OP_PARSER_PAT_CMD_ELEM(true),
+ NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
+ );
+
+static int pl35x_nfc_exec_op(struct nand_chip *chip,
+ const struct nand_operation *op,
+ bool check_only)
+{
+ if (!check_only)
+ pl35x_nand_select_target(chip, op->cs);
+
+ return nand_op_parser_exec_op(chip, &pl35x_nandc_op_parser,
+ op, check_only);
+}
+
+static int pl35x_nfc_setup_interface(struct nand_chip *chip, int cs,
+ const struct nand_interface_config *conf)
+{
+ struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
+ struct pl35x_nand *plnand = to_pl35x_nand(chip);
+ struct pl35x_nand_timings tmgs = {};
+ const struct nand_sdr_timings *sdr;
+ unsigned int period_ns, val;
+ struct clk *mclk;
+
+ sdr = nand_get_sdr_timings(conf);
+ if (IS_ERR(sdr))
+ return PTR_ERR(sdr);
+
+ mclk = of_clk_get_by_name(nfc->dev->parent->of_node, "memclk");
+ if (IS_ERR(mclk)) {
+ dev_err(nfc->dev, "Failed to retrieve SMC memclk\n");
+ return PTR_ERR(mclk);
+ }
+
+ /*
+ * SDR timings are given in pico-seconds while NFC timings must be
+ * expressed in NAND controller clock cycles. We use the TO_CYCLE()
+ * macro to convert from one to the other.
+ */
+ period_ns = NSEC_PER_SEC / clk_get_rate(mclk);
+
+ /*
+ * PL35X SMC needs one extra read cycle in SDR Mode 5. This is not
+ * written anywhere in the datasheet but is an empirical observation.
+ */
+ val = TO_CYCLES(sdr->tRC_min, period_ns);
+ if (sdr->tRC_min <= 20000)
+ val++;
+
+ tmgs.t_rc = val;
+ if (tmgs.t_rc != val || tmgs.t_rc < 2)
+ return -EINVAL;
+
+ val = TO_CYCLES(sdr->tWC_min, period_ns);
+ tmgs.t_wc = val;
+ if (tmgs.t_wc != val || tmgs.t_wc < 2)
+ return -EINVAL;
+
+ /*
+ * For all SDR modes, PL35X SMC needs tREA_max being 1,
+ * this is also an empirical result.
+ */
+ tmgs.t_rea = 1;
+
+ val = TO_CYCLES(sdr->tWP_min, period_ns);
+ tmgs.t_wp = val;
+ if (tmgs.t_wp != val || tmgs.t_wp < 1)
+ return -EINVAL;
+
+ val = TO_CYCLES(sdr->tCLR_min, period_ns);
+ tmgs.t_clr = val;
+ if (tmgs.t_clr != val)
+ return -EINVAL;
+
+ val = TO_CYCLES(sdr->tAR_min, period_ns);
+ tmgs.t_ar = val;
+ if (tmgs.t_ar != val)
+ return -EINVAL;
+
+ val = TO_CYCLES(sdr->tRR_min, period_ns);
+ tmgs.t_rr = val;
+ if (tmgs.t_rr != val)
+ return -EINVAL;
+
+ if (cs == NAND_DATA_IFACE_CHECK_ONLY)
+ return 0;
+
+ plnand->timings = PL35X_SMC_NAND_TRC_CYCLES(tmgs.t_rc) |
+ PL35X_SMC_NAND_TWC_CYCLES(tmgs.t_wc) |
+ PL35X_SMC_NAND_TREA_CYCLES(tmgs.t_rea) |
+ PL35X_SMC_NAND_TWP_CYCLES(tmgs.t_wp) |
+ PL35X_SMC_NAND_TCLR_CYCLES(tmgs.t_clr) |
+ PL35X_SMC_NAND_TAR_CYCLES(tmgs.t_ar) |
+ PL35X_SMC_NAND_TRR_CYCLES(tmgs.t_rr);
+
+ return 0;
+}
+
+static void pl35x_smc_set_ecc_pg_size(struct pl35x_nandc *nfc,
+ struct nand_chip *chip,
+ unsigned int pg_sz)
+{
+ struct pl35x_nand *plnand = to_pl35x_nand(chip);
+ u32 sz;
+
+ switch (pg_sz) {
+ case SZ_512:
+ sz = 1;
+ break;
+ case SZ_1K:
+ sz = 2;
+ break;
+ case SZ_2K:
+ sz = 3;
+ break;
+ default:
+ sz = 0;
+ break;
+ }
+
+ plnand->ecc_cfg = readl(nfc->conf_regs + PL35X_SMC_ECC_CFG);
+ plnand->ecc_cfg &= ~PL35X_SMC_ECC_CFG_PGSIZE_MASK;
+ plnand->ecc_cfg |= sz;
+ writel(plnand->ecc_cfg, nfc->conf_regs + PL35X_SMC_ECC_CFG);
+}
+
+static int pl35x_nand_init_hw_ecc_controller(struct pl35x_nandc *nfc,
+ struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int ret = 0;
+
+ if (mtd->writesize < SZ_512 || mtd->writesize > SZ_2K) {
+ dev_err(nfc->dev,
+ "The hardware ECC engine is limited to pages up to 2kiB\n");
+ return -EOPNOTSUPP;
+ }
+
+ chip->ecc.strength = 1;
+ chip->ecc.bytes = 3;
+ chip->ecc.size = SZ_512;
+ chip->ecc.steps = mtd->writesize / chip->ecc.size;
+ chip->ecc.read_page = pl35x_nand_read_page_hwecc;
+ chip->ecc.write_page = pl35x_nand_write_page_hwecc;
+ chip->ecc.write_page_raw = nand_monolithic_write_page_raw;
+ pl35x_smc_set_ecc_pg_size(nfc, chip, mtd->writesize);
+
+ nfc->ecc_buf = devm_kmalloc(nfc->dev, chip->ecc.bytes * chip->ecc.steps,
+ GFP_KERNEL);
+ if (!nfc->ecc_buf)
+ return -ENOMEM;
+
+ switch (mtd->oobsize) {
+ case 16:
+ /* Legacy Xilinx layout */
+ mtd_set_ooblayout(mtd, &pl35x_ecc_ooblayout16_ops);
+ chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
+ break;
+ case 64:
+ mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout());
+ break;
+ default:
+ dev_err(nfc->dev, "Unsupported OOB size\n");
+ return -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+static int pl35x_nand_attach_chip(struct nand_chip *chip)
+{
+ const struct nand_ecc_props *requirements =
+ nanddev_get_ecc_requirements(&chip->base);
+ struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
+ struct pl35x_nand *plnand = to_pl35x_nand(chip);
+ struct mtd_info *mtd = nand_to_mtd(chip);
+ int ret;
+
+ if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_NONE &&
+ (!chip->ecc.size || !chip->ecc.strength)) {
+ if (requirements->step_size && requirements->strength) {
+ chip->ecc.size = requirements->step_size;
+ chip->ecc.strength = requirements->strength;
+ } else {
+ dev_info(nfc->dev,
+ "No minimum ECC strength, using 1b/512B\n");
+ chip->ecc.size = 512;
+ chip->ecc.strength = 1;
+ }
+ }
+
+ if (mtd->writesize <= SZ_512)
+ plnand->addr_cycles = 1;
+ else
+ plnand->addr_cycles = 2;
+
+ if (chip->options & NAND_ROW_ADDR_3)
+ plnand->addr_cycles += 3;
+ else
+ plnand->addr_cycles += 2;
+
+ switch (chip->ecc.engine_type) {
+ case NAND_ECC_ENGINE_TYPE_ON_DIE:
+ /* Keep these legacy BBT descriptors for ON_DIE situations */
+ chip->bbt_td = &bbt_main_descr;
+ chip->bbt_md = &bbt_mirror_descr;
+ fallthrough;
+ case NAND_ECC_ENGINE_TYPE_NONE:
+ case NAND_ECC_ENGINE_TYPE_SOFT:
+ break;
+ case NAND_ECC_ENGINE_TYPE_ON_HOST:
+ ret = pl35x_nand_init_hw_ecc_controller(nfc, chip);
+ if (ret)
+ return ret;
+ break;
+ default:
+ dev_err(nfc->dev, "Unsupported ECC mode: %d\n",
+ chip->ecc.engine_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct nand_controller_ops pl35x_nandc_ops = {
+ .attach_chip = pl35x_nand_attach_chip,
+ .exec_op = pl35x_nfc_exec_op,
+ .setup_interface = pl35x_nfc_setup_interface,
+};
+
+static int pl35x_nand_reset_state(struct pl35x_nandc *nfc)
+{
+ int ret;
+
+ /* Disable interrupts and clear their status */
+ writel(PL35X_SMC_MEMC_CFG_CLR_INT_CLR_1 |
+ PL35X_SMC_MEMC_CFG_CLR_ECC_INT_DIS_1 |
+ PL35X_SMC_MEMC_CFG_CLR_INT_DIS_1,
+ nfc->conf_regs + PL35X_SMC_MEMC_CFG_CLR);
+
+ /* Set default bus width to 8-bit */
+ ret = pl35x_smc_set_buswidth(nfc, PL35X_SMC_OPMODE_BW_8);
+ if (ret)
+ return ret;
+
+ /* Ensure the ECC controller is bypassed by default */
+ ret = pl35x_smc_set_ecc_mode(nfc, NULL, PL35X_SMC_ECC_CFG_MODE_BYPASS);
+ if (ret)
+ return ret;
+
+ /*
+ * Configure the commands that the ECC block uses to detect the
+ * operations it should start/end.
+ */
+ writel(PL35X_SMC_ECC_CMD1_WRITE(NAND_CMD_SEQIN) |
+ PL35X_SMC_ECC_CMD1_READ(NAND_CMD_READ0) |
+ PL35X_SMC_ECC_CMD1_READ_END(NAND_CMD_READSTART) |
+ PL35X_SMC_ECC_CMD1_READ_END_VALID(NAND_CMD_READ1),
+ nfc->conf_regs + PL35X_SMC_ECC_CMD1);
+ writel(PL35X_SMC_ECC_CMD2_WRITE_COL_CHG(NAND_CMD_RNDIN) |
+ PL35X_SMC_ECC_CMD2_READ_COL_CHG(NAND_CMD_RNDOUT) |
+ PL35X_SMC_ECC_CMD2_READ_COL_CHG_END(NAND_CMD_RNDOUTSTART) |
+ PL35X_SMC_ECC_CMD2_READ_COL_CHG_END_VALID(NAND_CMD_READ1),
+ nfc->conf_regs + PL35X_SMC_ECC_CMD2);
+
+ return 0;
+}
+
+static int pl35x_nand_chip_init(struct pl35x_nandc *nfc,
+ struct device_node *np)
+{
+ struct pl35x_nand *plnand;
+ struct nand_chip *chip;
+ struct mtd_info *mtd;
+ int cs, ret;
+
+ plnand = devm_kzalloc(nfc->dev, sizeof(*plnand), GFP_KERNEL);
+ if (!plnand)
+ return -ENOMEM;
+
+ ret = of_property_read_u32(np, "reg", &cs);
+ if (ret)
+ return ret;
+
+ if (cs >= PL35X_NAND_MAX_CS) {
+ dev_err(nfc->dev, "Wrong CS %d\n", cs);
+ return -EINVAL;
+ }
+
+ if (test_and_set_bit(cs, &nfc->assigned_cs)) {
+ dev_err(nfc->dev, "Already assigned CS %d\n", cs);
+ return -EINVAL;
+ }
+
+ plnand->cs = cs;
+
+ chip = &plnand->chip;
+ chip->options = NAND_BUSWIDTH_AUTO | NAND_USES_DMA | NAND_NO_SUBPAGE_WRITE;
+ chip->bbt_options = NAND_BBT_USE_FLASH;
+ chip->controller = &nfc->controller;
+ mtd = nand_to_mtd(chip);
+ mtd->dev.parent = nfc->dev;
+ nand_set_flash_node(chip, nfc->dev->of_node);
+ if (!mtd->name) {
+ mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
+ "%s", PL35X_NANDC_DRIVER_NAME);
+ if (!mtd->name) {
+ dev_err(nfc->dev, "Failed to allocate mtd->name\n");
+ return -ENOMEM;
+ }
+ }
+
+ ret = nand_scan(chip, 1);
+ if (ret)
+ return ret;
+
+ ret = mtd_device_register(mtd, NULL, 0);
+ if (ret) {
+ nand_cleanup(chip);
+ return ret;
+ }
+
+ list_add_tail(&plnand->node, &nfc->chips);
+
+ return ret;
+}
+
+static void pl35x_nand_chips_cleanup(struct pl35x_nandc *nfc)
+{
+ struct pl35x_nand *plnand, *tmp;
+ struct nand_chip *chip;
+ int ret;
+
+ list_for_each_entry_safe(plnand, tmp, &nfc->chips, node) {
+ chip = &plnand->chip;
+ ret = mtd_device_unregister(nand_to_mtd(chip));
+ WARN_ON(ret);
+ nand_cleanup(chip);
+ list_del(&plnand->node);
+ }
+}
+
+static int pl35x_nand_chips_init(struct pl35x_nandc *nfc)
+{
+ struct device_node *np = nfc->dev->of_node, *nand_np;
+ int nchips = of_get_child_count(np);
+ int ret;
+
+ if (!nchips || nchips > PL35X_NAND_MAX_CS) {
+ dev_err(nfc->dev, "Incorrect number of NAND chips (%d)\n",
+ nchips);
+ return -EINVAL;
+ }
+
+ for_each_child_of_node(np, nand_np) {
+ ret = pl35x_nand_chip_init(nfc, nand_np);
+ if (ret) {
+ of_node_put(nand_np);
+ pl35x_nand_chips_cleanup(nfc);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int pl35x_nand_probe(struct platform_device *pdev)
+{
+ struct device *smc_dev = pdev->dev.parent;
+ struct amba_device *smc_amba = to_amba_device(smc_dev);
+ struct pl35x_nandc *nfc;
+ u32 ret;
+
+ nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
+ if (!nfc)
+ return -ENOMEM;
+
+ nfc->dev = &pdev->dev;
+ nand_controller_init(&nfc->controller);
+ nfc->controller.ops = &pl35x_nandc_ops;
+ INIT_LIST_HEAD(&nfc->chips);
+
+ nfc->conf_regs = devm_ioremap_resource(&smc_amba->dev, &smc_amba->res);
+ if (IS_ERR(nfc->conf_regs))
+ return PTR_ERR(nfc->conf_regs);
+
+ nfc->io_regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(nfc->io_regs))
+ return PTR_ERR(nfc->io_regs);
+
+ ret = pl35x_nand_reset_state(nfc);
+ if (ret)
+ return ret;
+
+ ret = pl35x_nand_chips_init(nfc);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, nfc);
+
+ return 0;
+}
+
+static int pl35x_nand_remove(struct platform_device *pdev)
+{
+ struct pl35x_nandc *nfc = platform_get_drvdata(pdev);
+
+ pl35x_nand_chips_cleanup(nfc);
+
+ return 0;
+}
+
+static const struct of_device_id pl35x_nand_of_match[] = {
+ { .compatible = "arm,pl353-nand-r2p1" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pl35x_nand_of_match);
+
+static struct platform_driver pl35x_nandc_driver = {
+ .probe = pl35x_nand_probe,
+ .remove = pl35x_nand_remove,
+ .driver = {
+ .name = PL35X_NANDC_DRIVER_NAME,
+ .of_match_table = pl35x_nand_of_match,
+ },
+};
+module_platform_driver(pl35x_nandc_driver);
+
+MODULE_AUTHOR("Xilinx, Inc.");
+MODULE_ALIAS("platform:" PL35X_NANDC_DRIVER_NAME);
+MODULE_DESCRIPTION("ARM PL35X NAND controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
index a64fb6ce915d..ef0badea4f41 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -734,6 +734,7 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, i
{
struct nand_chip *chip = &host->chip;
u32 cmd, cfg0, cfg1, ecc_bch_cfg;
+ struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
if (read) {
if (host->use_ecc)
@@ -762,7 +763,8 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, i
nandc_set_reg(chip, NAND_DEV0_CFG0, cfg0);
nandc_set_reg(chip, NAND_DEV0_CFG1, cfg1);
nandc_set_reg(chip, NAND_DEV0_ECC_CFG, ecc_bch_cfg);
- nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg);
+ if (!nandc->props->qpic_v2)
+ nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg);
nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
nandc_set_reg(chip, NAND_EXEC_CMD, 1);
@@ -1133,7 +1135,8 @@ static void config_nand_page_read(struct nand_chip *chip)
write_reg_dma(nandc, NAND_ADDR0, 2, 0);
write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
- write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
+ if (!nandc->props->qpic_v2)
+ write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0);
write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0);
write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1,
NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
@@ -1191,8 +1194,9 @@ static void config_nand_page_write(struct nand_chip *chip)
write_reg_dma(nandc, NAND_ADDR0, 2, 0);
write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0);
- write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
- NAND_BAM_NEXT_SGL);
+ if (!nandc->props->qpic_v2)
+ write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1,
+ NAND_BAM_NEXT_SGL);
}
/*
@@ -1248,7 +1252,8 @@ static int nandc_param(struct qcom_nand_host *host)
| 2 << WR_RD_BSY_GAP
| 0 << WIDE_FLASH
| 1 << DEV0_CFG1_ECC_DISABLE);
- nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
+ if (!nandc->props->qpic_v2)
+ nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
/* configure CMD1 and VLD for ONFI param probing in QPIC v1 */
if (!nandc->props->qpic_v2) {
@@ -1850,8 +1855,7 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf,
* ERASED_CW bits are set.
*/
if (host->bch_enabled) {
- erased = (erased_cw & ERASED_CW) == ERASED_CW ?
- true : false;
+ erased = (erased_cw & ERASED_CW) == ERASED_CW;
/*
* For RS ECC, HW reports the erased CW by placing
* special characters at certain offsets in the buffer.
@@ -2689,7 +2693,8 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
| ecc_mode << ECC_MODE
| host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH;
- host->ecc_buf_cfg = 0x203 << NUM_STEPS;
+ if (!nandc->props->qpic_v2)
+ host->ecc_buf_cfg = 0x203 << NUM_STEPS;
host->clrflashstatus = FS_READY_BSY_N;
host->clrreadstatus = 0xc0;
@@ -2882,7 +2887,7 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
return 0;
}
-static const char * const probes[] = { "qcomsmem", NULL };
+static const char * const probes[] = { "cmdlinepart", "ofpart", "qcomsmem", NULL };
static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
struct qcom_nand_host *host,
diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c
index ebe859ca49cb..ed0cf732d20e 100644
--- a/drivers/mtd/nand/raw/r852.c
+++ b/drivers/mtd/nand/raw/r852.c
@@ -583,8 +583,8 @@ static void r852_update_card_detect(struct r852_device *dev)
r852_write_reg(dev, R852_CARD_IRQ_ENABLE, card_detect_reg);
}
-static ssize_t r852_media_type_show(struct device *sys_dev,
- struct device_attribute *attr, char *buf)
+static ssize_t media_type_show(struct device *sys_dev,
+ struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = container_of(sys_dev, struct mtd_info, dev);
struct r852_device *dev = r852_get_dev(mtd);
@@ -593,8 +593,7 @@ static ssize_t r852_media_type_show(struct device *sys_dev,
strcpy(buf, data);
return strlen(data);
}
-
-static DEVICE_ATTR(media_type, S_IRUGO, r852_media_type_show, NULL);
+static DEVICE_ATTR_RO(media_type);
/* Detect properties of card in slot */
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index 923a9e236fcf..ea953e31933e 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -1972,10 +1972,8 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
sunxi_nand = devm_kzalloc(dev, struct_size(sunxi_nand, sels, nsels),
GFP_KERNEL);
- if (!sunxi_nand) {
- dev_err(dev, "could not allocate chip\n");
+ if (!sunxi_nand)
return -ENOMEM;
- }
sunxi_nand->nsels = nsels;
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 17f63f95f4a2..446ba8d43fbc 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -138,20 +138,12 @@ int spinand_select_target(struct spinand_device *spinand, unsigned int target)
return 0;
}
-static int spinand_init_cfg_cache(struct spinand_device *spinand)
+static int spinand_read_cfg(struct spinand_device *spinand)
{
struct nand_device *nand = spinand_to_nand(spinand);
- struct device *dev = &spinand->spimem->spi->dev;
unsigned int target;
int ret;
- spinand->cfg_cache = devm_kcalloc(dev,
- nand->memorg.ntargets,
- sizeof(*spinand->cfg_cache),
- GFP_KERNEL);
- if (!spinand->cfg_cache)
- return -ENOMEM;
-
for (target = 0; target < nand->memorg.ntargets; target++) {
ret = spinand_select_target(spinand, target);
if (ret)
@@ -170,6 +162,21 @@ static int spinand_init_cfg_cache(struct spinand_device *spinand)
return 0;
}
+static int spinand_init_cfg_cache(struct spinand_device *spinand)
+{
+ struct nand_device *nand = spinand_to_nand(spinand);
+ struct device *dev = &spinand->spimem->spi->dev;
+
+ spinand->cfg_cache = devm_kcalloc(dev,
+ nand->memorg.ntargets,
+ sizeof(*spinand->cfg_cache),
+ GFP_KERNEL);
+ if (!spinand->cfg_cache)
+ return -ENOMEM;
+
+ return 0;
+}
+
static int spinand_init_quad_enable(struct spinand_device *spinand)
{
bool enable = false;
@@ -290,6 +297,8 @@ static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand,
{
struct spinand_ondie_ecc_conf *engine_conf = nand->ecc.ctx.priv;
struct spinand_device *spinand = nand_to_spinand(nand);
+ struct mtd_info *mtd = spinand_to_mtd(spinand);
+ int ret;
if (req->mode == MTD_OPS_RAW)
return 0;
@@ -299,7 +308,13 @@ static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand,
return 0;
/* Finish a page write: check the status, report errors/bitflips */
- return spinand_check_ecc_status(spinand, engine_conf->status);
+ ret = spinand_check_ecc_status(spinand, engine_conf->status);
+ if (ret == -EBADMSG)
+ mtd->ecc_stats.failed++;
+ else if (ret > 0)
+ mtd->ecc_stats.corrected += ret;
+
+ return ret;
}
static struct nand_ecc_engine_ops spinand_ondie_ecc_engine_ops = {
@@ -473,20 +488,26 @@ static int spinand_erase_op(struct spinand_device *spinand,
return spi_mem_exec_op(spinand->spimem, &op);
}
-static int spinand_wait(struct spinand_device *spinand, u8 *s)
+static int spinand_wait(struct spinand_device *spinand,
+ unsigned long initial_delay_us,
+ unsigned long poll_delay_us,
+ u8 *s)
{
- unsigned long timeo = jiffies + msecs_to_jiffies(400);
+ struct spi_mem_op op = SPINAND_GET_FEATURE_OP(REG_STATUS,
+ spinand->scratchbuf);
u8 status;
int ret;
- do {
- ret = spinand_read_status(spinand, &status);
- if (ret)
- return ret;
+ ret = spi_mem_poll_status(spinand->spimem, &op, STATUS_BUSY, 0,
+ initial_delay_us,
+ poll_delay_us,
+ SPINAND_WAITRDY_TIMEOUT_MS);
+ if (ret)
+ return ret;
- if (!(status & STATUS_BUSY))
- goto out;
- } while (time_before(jiffies, timeo));
+ status = *spinand->scratchbuf;
+ if (!(status & STATUS_BUSY))
+ goto out;
/*
* Extra read, just in case the STATUS_READY bit has changed
@@ -526,7 +547,10 @@ static int spinand_reset_op(struct spinand_device *spinand)
if (ret)
return ret;
- return spinand_wait(spinand, NULL);
+ return spinand_wait(spinand,
+ SPINAND_RESET_INITIAL_DELAY_US,
+ SPINAND_RESET_POLL_DELAY_US,
+ NULL);
}
static int spinand_lock_block(struct spinand_device *spinand, u8 lock)
@@ -549,7 +573,10 @@ static int spinand_read_page(struct spinand_device *spinand,
if (ret)
return ret;
- ret = spinand_wait(spinand, &status);
+ ret = spinand_wait(spinand,
+ SPINAND_READ_INITIAL_DELAY_US,
+ SPINAND_READ_POLL_DELAY_US,
+ &status);
if (ret < 0)
return ret;
@@ -585,7 +612,10 @@ static int spinand_write_page(struct spinand_device *spinand,
if (ret)
return ret;
- ret = spinand_wait(spinand, &status);
+ ret = spinand_wait(spinand,
+ SPINAND_WRITE_INITIAL_DELAY_US,
+ SPINAND_WRITE_POLL_DELAY_US,
+ &status);
if (!ret && (status & STATUS_PROG_FAILED))
return -EIO;
@@ -620,13 +650,10 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
if (ret < 0 && ret != -EBADMSG)
break;
- if (ret == -EBADMSG) {
+ if (ret == -EBADMSG)
ecc_failed = true;
- mtd->ecc_stats.failed++;
- } else {
- mtd->ecc_stats.corrected += ret;
+ else
max_bitflips = max_t(unsigned int, max_bitflips, ret);
- }
ret = 0;
ops->retlen += iter.req.datalen;
@@ -768,7 +795,11 @@ static int spinand_erase(struct nand_device *nand, const struct nand_pos *pos)
if (ret)
return ret;
- ret = spinand_wait(spinand, &status);
+ ret = spinand_wait(spinand,
+ SPINAND_ERASE_INITIAL_DELAY_US,
+ SPINAND_ERASE_POLL_DELAY_US,
+ &status);
+
if (!ret && (status & STATUS_ERASE_FAILED))
ret = -EIO;
@@ -1074,12 +1105,71 @@ static int spinand_detect(struct spinand_device *spinand)
return 0;
}
+static int spinand_init_flash(struct spinand_device *spinand)
+{
+ struct device *dev = &spinand->spimem->spi->dev;
+ struct nand_device *nand = spinand_to_nand(spinand);
+ int ret, i;
+
+ ret = spinand_read_cfg(spinand);
+ if (ret)
+ return ret;
+
+ ret = spinand_init_quad_enable(spinand);
+ if (ret)
+ return ret;
+
+ ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0);
+ if (ret)
+ return ret;
+
+ ret = spinand_manufacturer_init(spinand);
+ if (ret) {
+ dev_err(dev,
+ "Failed to initialize the SPI NAND chip (err = %d)\n",
+ ret);
+ return ret;
+ }
+
+ /* After power up, all blocks are locked, so unlock them here. */
+ for (i = 0; i < nand->memorg.ntargets; i++) {
+ ret = spinand_select_target(spinand, i);
+ if (ret)
+ break;
+
+ ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED);
+ if (ret)
+ break;
+ }
+
+ if (ret)
+ spinand_manufacturer_cleanup(spinand);
+
+ return ret;
+}
+
+static void spinand_mtd_resume(struct mtd_info *mtd)
+{
+ struct spinand_device *spinand = mtd_to_spinand(mtd);
+ int ret;
+
+ ret = spinand_reset_op(spinand);
+ if (ret)
+ return;
+
+ ret = spinand_init_flash(spinand);
+ if (ret)
+ return;
+
+ spinand_ecc_enable(spinand, false);
+}
+
static int spinand_init(struct spinand_device *spinand)
{
struct device *dev = &spinand->spimem->spi->dev;
struct mtd_info *mtd = spinand_to_mtd(spinand);
struct nand_device *nand = mtd_to_nanddev(mtd);
- int ret, i;
+ int ret;
/*
* We need a scratch buffer because the spi_mem interface requires that
@@ -1112,22 +1202,10 @@ static int spinand_init(struct spinand_device *spinand)
if (ret)
goto err_free_bufs;
- ret = spinand_init_quad_enable(spinand);
- if (ret)
- goto err_free_bufs;
-
- ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0);
+ ret = spinand_init_flash(spinand);
if (ret)
goto err_free_bufs;
- ret = spinand_manufacturer_init(spinand);
- if (ret) {
- dev_err(dev,
- "Failed to initialize the SPI NAND chip (err = %d)\n",
- ret);
- goto err_free_bufs;
- }
-
ret = spinand_create_dirmaps(spinand);
if (ret) {
dev_err(dev,
@@ -1136,17 +1214,6 @@ static int spinand_init(struct spinand_device *spinand)
goto err_manuf_cleanup;
}
- /* After power up, all blocks are locked, so unlock them here. */
- for (i = 0; i < nand->memorg.ntargets; i++) {
- ret = spinand_select_target(spinand, i);
- if (ret)
- goto err_manuf_cleanup;
-
- ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED);
- if (ret)
- goto err_manuf_cleanup;
- }
-
ret = nanddev_init(nand, &spinand_ops, THIS_MODULE);
if (ret)
goto err_manuf_cleanup;
@@ -1167,6 +1234,7 @@ static int spinand_init(struct spinand_device *spinand)
mtd->_block_isreserved = spinand_mtd_block_isreserved;
mtd->_erase = spinand_mtd_erase;
mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks;
+ mtd->_resume = spinand_mtd_resume;
if (nand->ecc.engine) {
ret = mtd_ooblayout_count_freebytes(mtd);
diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index 6701aaa21a49..a9890350db02 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -186,6 +186,118 @@ static const struct spinand_info macronix_spinand_table[] = {
0 /*SPINAND_HAS_QE_BIT*/,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
+
+ SPINAND_INFO("MX35LF2G14AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x20),
+ 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,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF4G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF4GE4AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF2G14AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa0),
+ 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,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF2G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF2GE4AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF2GE4AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(4, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF1G14AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x90),
+ 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,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF1G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF1GE4AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF1GE4AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
+ 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,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+
};
static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index bcd0094f172d..913db0dd6a8d 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -619,7 +619,6 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
return BLOCK_NIL;
}
//printk("Restarting scan\n");
- lastEUN = BLOCK_NIL;
continue;
}
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c
index 444a77bb7692..75e86ed3e678 100644
--- a/drivers/mtd/nftlmount.c
+++ b/drivers/mtd/nftlmount.c
@@ -188,17 +188,14 @@ device is already correct.
/* memory alloc */
nftl->EUNtable = kmalloc_array(nftl->nb_blocks, sizeof(u16),
GFP_KERNEL);
- if (!nftl->EUNtable) {
- printk(KERN_NOTICE "NFTL: allocation of EUNtable failed\n");
+ if (!nftl->EUNtable)
return -ENOMEM;
- }
nftl->ReplUnitTable = kmalloc_array(nftl->nb_blocks,
sizeof(u16),
GFP_KERNEL);
if (!nftl->ReplUnitTable) {
kfree(nftl->EUNtable);
- printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n");
return -ENOMEM;
}
@@ -269,7 +266,7 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int
buf = kmalloc(SECTORSIZE + mtd->oobsize, GFP_KERNEL);
if (!buf)
- return -1;
+ return -ENOMEM;
ret = -1;
for (i = 0; i < len; i += SECTORSIZE) {
diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig
index 9babe678c41b..337ea8b9a4c3 100644
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
@@ -115,7 +115,7 @@ config MTD_AFS_PARTS
config MTD_PARSER_TRX
tristate "Parser for TRX format partitions"
- depends on MTD && (BCM47XX || ARCH_BCM_5301X || COMPILE_TEST)
+ depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || COMPILE_TEST)
help
TRX is a firmware format used by Broadcom on their devices. It
may contain up to 3/4 partitions (depending on the version).
diff --git a/drivers/mtd/parsers/parser_trx.c b/drivers/mtd/parsers/parser_trx.c
index 8541182134d4..4814cf218e17 100644
--- a/drivers/mtd/parsers/parser_trx.c
+++ b/drivers/mtd/parsers/parser_trx.c
@@ -51,13 +51,20 @@ static int parser_trx_parse(struct mtd_info *mtd,
const struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{
+ struct device_node *np = mtd_get_of_node(mtd);
struct mtd_partition *parts;
struct mtd_partition *part;
struct trx_header trx;
size_t bytes_read;
uint8_t curr_part = 0, i = 0;
+ uint32_t trx_magic = TRX_MAGIC;
int err;
+ /* Get different magic from device tree if specified */
+ err = of_property_read_u32(np, "brcm,trx-magic", &trx_magic);
+ if (err != 0 && err != -EINVAL)
+ pr_err("failed to parse \"brcm,trx-magic\" DT attribute, using default: %d\n", err);
+
parts = kcalloc(TRX_PARSER_MAX_PARTS, sizeof(struct mtd_partition),
GFP_KERNEL);
if (!parts)
@@ -70,7 +77,7 @@ static int parser_trx_parse(struct mtd_info *mtd,
return err;
}
- if (trx.magic != TRX_MAGIC) {
+ if (trx.magic != trx_magic) {
kfree(parts);
return -ENOENT;
}
diff --git a/drivers/mtd/parsers/qcomsmempart.c b/drivers/mtd/parsers/qcomsmempart.c
index d9083308f6ba..06a818cd2433 100644
--- a/drivers/mtd/parsers/qcomsmempart.c
+++ b/drivers/mtd/parsers/qcomsmempart.c
@@ -159,6 +159,15 @@ out_free_parts:
return ret;
}
+static void parse_qcomsmem_cleanup(const struct mtd_partition *pparts,
+ int nr_parts)
+{
+ int i;
+
+ for (i = 0; i < nr_parts; i++)
+ kfree(pparts[i].name);
+}
+
static const struct of_device_id qcomsmem_of_match_table[] = {
{ .compatible = "qcom,smem-part" },
{},
@@ -167,6 +176,7 @@ MODULE_DEVICE_TABLE(of, qcomsmem_of_match_table);
static struct mtd_part_parser mtd_parser_qcomsmem = {
.parse_fn = parse_qcomsmem_part,
+ .cleanup = parse_qcomsmem_cleanup,
.name = "qcomsmem",
.of_match_table = qcomsmem_of_match_table,
};
diff --git a/drivers/mtd/parsers/redboot.c b/drivers/mtd/parsers/redboot.c
index 91146bdc4713..feb44a573d44 100644
--- a/drivers/mtd/parsers/redboot.c
+++ b/drivers/mtd/parsers/redboot.c
@@ -17,15 +17,15 @@
#include <linux/module.h>
struct fis_image_desc {
- unsigned char name[16]; // Null terminated name
- uint32_t flash_base; // Address within FLASH of image
- uint32_t mem_base; // Address in memory where it executes
- uint32_t size; // Length of image
- uint32_t entry_point; // Execution entry point
- uint32_t data_length; // Length of actual data
- unsigned char _pad[256-(16+7*sizeof(uint32_t))];
- uint32_t desc_cksum; // Checksum over image descriptor
- uint32_t file_cksum; // Checksum over image data
+ unsigned char name[16]; // Null terminated name
+ u32 flash_base; // Address within FLASH of image
+ u32 mem_base; // Address in memory where it executes
+ u32 size; // Length of image
+ u32 entry_point; // Execution entry point
+ u32 data_length; // Length of actual data
+ unsigned char _pad[256 - (16 + 7 * sizeof(u32))];
+ u32 desc_cksum; // Checksum over image descriptor
+ u32 file_cksum; // Checksum over image data
};
struct fis_list {
@@ -45,6 +45,7 @@ static inline int redboot_checksum(struct fis_image_desc *img)
static void parse_redboot_of(struct mtd_info *master)
{
struct device_node *np;
+ struct device_node *npart;
u32 dirblock;
int ret;
@@ -52,7 +53,11 @@ static void parse_redboot_of(struct mtd_info *master)
if (!np)
return;
- ret = of_property_read_u32(np, "fis-index-block", &dirblock);
+ npart = of_get_child_by_name(np, "partitions");
+ if (!npart)
+ return;
+
+ ret = of_property_read_u32(npart, "fis-index-block", &dirblock);
if (ret)
return;
@@ -85,12 +90,12 @@ static int parse_redboot_partitions(struct mtd_info *master,
parse_redboot_of(master);
- if ( directory < 0 ) {
+ if (directory < 0) {
offset = master->size + directory * master->erasesize;
while (mtd_block_isbad(master, offset)) {
if (!offset) {
- nogood:
- printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n");
+nogood:
+ pr_notice("Failed to find a non-bad block to check for RedBoot partition table\n");
return -EIO;
}
offset -= master->erasesize;
@@ -108,8 +113,8 @@ static int parse_redboot_partitions(struct mtd_info *master,
if (!buf)
return -ENOMEM;
- printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
- master->name, offset);
+ pr_notice("Searching for RedBoot partition table in %s at offset 0x%lx\n",
+ master->name, offset);
ret = mtd_read(master, offset, master->erasesize, &retlen,
(void *)buf);
@@ -145,14 +150,13 @@ static int parse_redboot_partitions(struct mtd_info *master,
&& swab32(buf[i].size) < master->erasesize)) {
int j;
/* Update numslots based on actual FIS directory size */
- numslots = swab32(buf[i].size) / sizeof (struct fis_image_desc);
+ numslots = swab32(buf[i].size) / sizeof(struct fis_image_desc);
for (j = 0; j < numslots; ++j) {
-
/* A single 0xff denotes a deleted entry.
* Two of them in a row is the end of the table.
*/
if (buf[j].name[0] == 0xff) {
- if (buf[j].name[1] == 0xff) {
+ if (buf[j].name[1] == 0xff) {
break;
} else {
continue;
@@ -179,8 +183,8 @@ static int parse_redboot_partitions(struct mtd_info *master,
}
if (i == numslots) {
/* Didn't find it */
- printk(KERN_NOTICE "No RedBoot partition table detected in %s\n",
- master->name);
+ pr_notice("No RedBoot partition table detected in %s\n",
+ master->name);
ret = 0;
goto out;
}
@@ -199,7 +203,7 @@ static int parse_redboot_partitions(struct mtd_info *master,
break;
new_fl = kmalloc(sizeof(struct fis_list), GFP_KERNEL);
- namelen += strlen(buf[i].name)+1;
+ namelen += strlen(buf[i].name) + 1;
if (!new_fl) {
ret = -ENOMEM;
goto out;
@@ -208,13 +212,13 @@ static int parse_redboot_partitions(struct mtd_info *master,
if (data && data->origin)
buf[i].flash_base -= data->origin;
else
- buf[i].flash_base &= master->size-1;
+ buf[i].flash_base &= master->size - 1;
/* I'm sure the JFFS2 code has done me permanent damage.
* I now think the following is _normal_
*/
prev = &fl;
- while(*prev && (*prev)->img->flash_base < new_fl->img->flash_base)
+ while (*prev && (*prev)->img->flash_base < new_fl->img->flash_base)
prev = &(*prev)->next;
new_fl->next = *prev;
*prev = new_fl;
@@ -234,7 +238,7 @@ static int parse_redboot_partitions(struct mtd_info *master,
}
}
#endif
- parts = kzalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL);
+ parts = kzalloc(sizeof(*parts) * nrparts + nulllen + namelen, GFP_KERNEL);
if (!parts) {
ret = -ENOMEM;
@@ -243,23 +247,22 @@ static int parse_redboot_partitions(struct mtd_info *master,
nullname = (char *)&parts[nrparts];
#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
- if (nulllen > 0) {
+ if (nulllen > 0)
strcpy(nullname, nullstring);
- }
#endif
names = nullname + nulllen;
- i=0;
+ i = 0;
#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
if (fl->img->flash_base) {
- parts[0].name = nullname;
- parts[0].size = fl->img->flash_base;
- parts[0].offset = 0;
+ parts[0].name = nullname;
+ parts[0].size = fl->img->flash_base;
+ parts[0].offset = 0;
i++;
}
#endif
- for ( ; i<nrparts; i++) {
+ for ( ; i < nrparts; i++) {
parts[i].size = fl->img->size;
parts[i].offset = fl->img->flash_base;
parts[i].name = names;
@@ -267,17 +270,17 @@ static int parse_redboot_partitions(struct mtd_info *master,
strcpy(names, fl->img->name);
#ifdef CONFIG_MTD_REDBOOT_PARTS_READONLY
if (!memcmp(names, "RedBoot", 8) ||
- !memcmp(names, "RedBoot config", 15) ||
- !memcmp(names, "FIS directory", 14)) {
+ !memcmp(names, "RedBoot config", 15) ||
+ !memcmp(names, "FIS directory", 14)) {
parts[i].mask_flags = MTD_WRITEABLE;
}
#endif
- names += strlen(names)+1;
+ names += strlen(names) + 1;
#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
- if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
+ if (fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
i++;
- parts[i].offset = parts[i-1].size + parts[i-1].offset;
+ parts[i].offset = parts[i - 1].size + parts[i - 1].offset;
parts[i].size = fl->next->img->flash_base - parts[i].offset;
parts[i].name = nullname;
}
@@ -291,6 +294,7 @@ static int parse_redboot_partitions(struct mtd_info *master,
out:
while (fl) {
struct fis_list *old = fl;
+
fl = fl->next;
kfree(old);
}
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
index cce3bf6f99b4..6e0d5ce9b010 100644
--- a/drivers/mtd/rfd_ftl.c
+++ b/drivers/mtd/rfd_ftl.c
@@ -192,11 +192,8 @@ static int scan_header(struct partition *part)
part->sector_map = vmalloc(array_size(sizeof(u_long),
part->sector_count));
- if (!part->sector_map) {
- printk(KERN_ERR PREFIX "'%s': unable to allocate memory for "
- "sector map", part->mbd.mtd->name);
+ if (!part->sector_map)
goto err;
- }
for (i=0; i<part->sector_count; i++)
part->sector_map[i] = -1;
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c
index 4d1ae25507ab..0cff2cda1b5a 100644
--- a/drivers/mtd/sm_ftl.c
+++ b/drivers/mtd/sm_ftl.c
@@ -265,7 +265,8 @@ static int sm_read_sector(struct sm_ftl *ftl,
again:
if (try++) {
/* Avoid infinite recursion on CIS reads, sm_recheck_media
- won't help anyway */
+ * won't help anyway
+ */
if (zone == 0 && block == ftl->cis_block && boffset ==
ftl->cis_boffset)
return ret;
@@ -276,7 +277,8 @@ again:
}
/* Unfortunately, oob read will _always_ succeed,
- despite card removal..... */
+ * despite card removal.....
+ */
ret = mtd_read_oob(mtd, sm_mkoffset(ftl, zone, block, boffset), &ops);
/* Test for unknown errors */
@@ -411,9 +413,10 @@ restart:
/* If write fails. try to erase the block */
/* This is safe, because we never write in blocks
- that contain valuable data.
- This is intended to repair block that are marked
- as erased, but that isn't fully erased*/
+ * that contain valuable data.
+ * This is intended to repair block that are marked
+ * as erased, but that isn't fully erased
+ */
if (sm_erase_block(ftl, zone, block, 0))
return -EIO;
@@ -448,7 +451,8 @@ static void sm_mark_block_bad(struct sm_ftl *ftl, int zone, int block)
/* We aren't checking the return value, because we don't care */
/* This also fails on fake xD cards, but I guess these won't expose
- any bad blocks till fail completely */
+ * any bad blocks till fail completely
+ */
for (boffset = 0; boffset < ftl->block_size; boffset += SM_SECTOR_SIZE)
sm_write_sector(ftl, zone, block, boffset, NULL, &oob);
}
@@ -505,7 +509,8 @@ static int sm_check_block(struct sm_ftl *ftl, int zone, int block)
/* First just check that block doesn't look fishy */
/* Only blocks that are valid or are sliced in two parts, are
- accepted */
+ * accepted
+ */
for (boffset = 0; boffset < ftl->block_size;
boffset += SM_SECTOR_SIZE) {
@@ -554,7 +559,8 @@ static const uint8_t cis_signature[] = {
0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02, 0xDF, 0x01, 0x20
};
/* Find out media parameters.
- * This ideally has to be based on nand id, but for now device size is enough */
+ * This ideally has to be based on nand id, but for now device size is enough
+ */
static int sm_get_media_info(struct sm_ftl *ftl, struct mtd_info *mtd)
{
int i;
@@ -607,7 +613,8 @@ static int sm_get_media_info(struct sm_ftl *ftl, struct mtd_info *mtd)
}
/* Minimum xD size is 16MiB. Also, all xD cards have standard zone
- sizes. SmartMedia cards exist up to 128 MiB and have same layout*/
+ * sizes. SmartMedia cards exist up to 128 MiB and have same layout
+ */
if (size_in_megs >= 16) {
ftl->zone_count = size_in_megs / 16;
ftl->zone_size = 1024;
@@ -782,7 +789,8 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num)
}
/* Test to see if block is erased. It is enough to test
- first sector, because erase happens in one shot */
+ * first sector, because erase happens in one shot
+ */
if (sm_block_erased(&oob)) {
kfifo_in(&zone->free_sectors,
(unsigned char *)&block, 2);
@@ -792,7 +800,8 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num)
/* If block is marked as bad, skip it */
/* This assumes we can trust first sector*/
/* However the way the block valid status is defined, ensures
- very low probability of failure here */
+ * very low probability of failure here
+ */
if (!sm_block_valid(&oob)) {
dbg("PH %04d <-> <marked bad>", block);
continue;
@@ -803,7 +812,8 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num)
/* Invalid LBA means that block is damaged. */
/* We can try to erase it, or mark it as bad, but
- lets leave that to recovery application */
+ * lets leave that to recovery application
+ */
if (lba == -2 || lba >= ftl->max_lba) {
dbg("PH %04d <-> LBA %04d(bad)", block, lba);
continue;
@@ -811,7 +821,8 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num)
/* If there is no collision,
- just put the sector in the FTL table */
+ * just put the sector in the FTL table
+ */
if (zone->lba_to_phys_table[lba] < 0) {
dbg_verbose("PH %04d <-> LBA %04d", block, lba);
zone->lba_to_phys_table[lba] = block;
@@ -834,9 +845,9 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num)
}
/* If both blocks are valid and share same LBA, it means that
- they hold different versions of same data. It not
- known which is more recent, thus just erase one of them
- */
+ * they hold different versions of same data. It not
+ * known which is more recent, thus just erase one of them
+ */
sm_printk("both blocks are valid, erasing the later");
sm_erase_block(ftl, zone_num, block, 1);
}
@@ -845,7 +856,8 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num)
zone->initialized = 1;
/* No free sectors, means that the zone is heavily damaged, write won't
- work, but it can still can be (partially) read */
+ * work, but it can still can be (partially) read
+ */
if (!kfifo_len(&zone->free_sectors)) {
sm_printk("no free blocks in zone %d", zone_num);
return 0;
@@ -952,8 +964,9 @@ restart:
/* If there are no spare blocks, */
/* we could still continue by erasing/writing the current block,
- but for such worn out media it doesn't worth the trouble,
- and the dangers */
+ * but for such worn out media it doesn't worth the trouble,
+ * and the dangers
+ */
if (kfifo_out(&zone->free_sectors,
(unsigned char *)&write_sector, 2) != 2) {
dbg("no free sectors for write!");
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index 136f245c91dc..6b904e439372 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-spi-nor-objs := core.o sfdp.o swp.o otp.o
+spi-nor-objs := core.o sfdp.o swp.o otp.o sysfs.o
spi-nor-objs += atmel.o
spi-nor-objs += catalyst.o
spi-nor-objs += eon.o
diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c
index 825610a2e9dc..1bc53b8bb88a 100644
--- a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c
+++ b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c
@@ -74,6 +74,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x51a4), (unsigned long)&cnl_info },
+ { PCI_VDEVICE(INTEL, 0x54a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
diff --git a/drivers/mtd/spi-nor/controllers/nxp-spifi.c b/drivers/mtd/spi-nor/controllers/nxp-spifi.c
index 5703e8313980..2635c80231bb 100644
--- a/drivers/mtd/spi-nor/controllers/nxp-spifi.c
+++ b/drivers/mtd/spi-nor/controllers/nxp-spifi.c
@@ -326,7 +326,7 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
ctrl |= SPIFI_CTRL_DUAL;
}
- switch (mode & (SPI_CPHA | SPI_CPOL)) {
+ switch (mode & SPI_MODE_X_MASK) {
case SPI_MODE_0:
ctrl &= ~SPIFI_CTRL_MODE3;
break;
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index bd2c7717eb10..cc08bd707378 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -1318,7 +1318,7 @@ static u32 spi_nor_convert_addr(struct spi_nor *nor, loff_t addr)
/*
* Initiate the erasure of a single sector
*/
-static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
+int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
{
int i;
@@ -1411,9 +1411,7 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
continue;
spi_nor_div_by_erase_size(erase, addr, &rem);
- if (rem)
- continue;
- else
+ if (!rem)
return erase;
}
@@ -2839,6 +2837,21 @@ static int spi_nor_init(struct spi_nor *nor)
return 0;
}
+/**
+ * spi_nor_soft_reset() - Perform a software reset
+ * @nor: pointer to 'struct spi_nor'
+ *
+ * Performs a "Soft Reset and Enter Default Protocol Mode" sequence which resets
+ * the device to its power-on-reset state. This is useful when the software has
+ * made some changes to device (volatile) registers and needs to reset it before
+ * shutting down, for example.
+ *
+ * Not every flash supports this sequence. The same set of opcodes might be used
+ * for some other operation on a flash that does not support this. Support for
+ * this sequence can be discovered via SFDP in the BFPT table.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
static void spi_nor_soft_reset(struct spi_nor *nor)
{
struct spi_mem_op op;
@@ -3444,6 +3457,7 @@ static struct spi_mem_driver spi_nor_driver = {
.driver = {
.name = "spi-nor",
.of_match_table = spi_nor_of_table,
+ .dev_groups = spi_nor_sysfs_groups,
},
.id_table = spi_nor_dev_ids,
},
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index 28a2e0be97a3..3348e1dd1445 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -207,6 +207,7 @@ struct spi_nor_otp_organization {
* @read: read from the SPI NOR OTP area.
* @write: write to the SPI NOR OTP area.
* @lock: lock an OTP region.
+ * @erase: erase an OTP region.
* @is_locked: check if an OTP region of the SPI NOR is locked.
*/
struct spi_nor_otp_ops {
@@ -214,6 +215,7 @@ struct spi_nor_otp_ops {
int (*write)(struct spi_nor *nor, loff_t addr, size_t len,
const u8 *buf);
int (*lock)(struct spi_nor *nor, unsigned int region);
+ int (*erase)(struct spi_nor *nor, loff_t addr);
int (*is_locked)(struct spi_nor *nor, unsigned int region);
};
@@ -459,6 +461,16 @@ struct spi_nor_manufacturer {
const struct spi_nor_fixups *fixups;
};
+/**
+ * struct sfdp - SFDP data
+ * @num_dwords: number of entries in the dwords array
+ * @dwords: array of double words of the SFDP data
+ */
+struct sfdp {
+ size_t num_dwords;
+ u32 *dwords;
+};
+
/* Manufacturer drivers. */
extern const struct spi_nor_manufacturer spi_nor_atmel;
extern const struct spi_nor_manufacturer spi_nor_catalyst;
@@ -478,6 +490,8 @@ extern const struct spi_nor_manufacturer spi_nor_winbond;
extern const struct spi_nor_manufacturer spi_nor_xilinx;
extern const struct spi_nor_manufacturer spi_nor_xmc;
+extern const struct attribute_group *spi_nor_sysfs_groups[];
+
void spi_nor_spimem_setup_op(const struct spi_nor *nor,
struct spi_mem_op *op,
const enum spi_nor_protocol proto);
@@ -503,10 +517,12 @@ ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
u8 *buf);
ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
const u8 *buf);
+int spi_nor_erase_sector(struct spi_nor *nor, u32 addr);
int spi_nor_otp_read_secr(struct spi_nor *nor, loff_t addr, size_t len, u8 *buf);
int spi_nor_otp_write_secr(struct spi_nor *nor, loff_t addr, size_t len,
const u8 *buf);
+int spi_nor_otp_erase_secr(struct spi_nor *nor, loff_t addr);
int spi_nor_otp_lock_sr2(struct spi_nor *nor, unsigned int region);
int spi_nor_otp_is_locked_sr2(struct spi_nor *nor, unsigned int region);
diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c
index 42c2cf31702e..27498ed0cc0d 100644
--- a/drivers/mtd/spi-nor/macronix.c
+++ b/drivers/mtd/spi-nor/macronix.c
@@ -49,7 +49,8 @@ static const struct flash_info macronix_parts[] = {
{ "mx25u4035", INFO(0xc22533, 0, 64 * 1024, 8, SECT_4K) },
{ "mx25u8035", INFO(0xc22534, 0, 64 * 1024, 16, SECT_4K) },
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
- { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, SECT_4K) },
+ { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, SECT_4K |
+ SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
{ "mx25r1635f", INFO(0xc22815, 0, 64 * 1024, 32,
SECT_4K | SPI_NOR_DUAL_READ |
@@ -72,7 +73,7 @@ static const struct flash_info macronix_parts[] = {
SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
- { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024,
+ { "mx66l51235f", INFO(0xc2201a, 0, 64 * 1024, 1024,
SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_4B_OPCODES) },
{ "mx66u51235f", INFO(0xc2253a, 0, 64 * 1024, 1024,
diff --git a/drivers/mtd/spi-nor/otp.c b/drivers/mtd/spi-nor/otp.c
index fcf38d260345..983e40b19134 100644
--- a/drivers/mtd/spi-nor/otp.c
+++ b/drivers/mtd/spi-nor/otp.c
@@ -15,14 +15,21 @@
#define spi_nor_otp_n_regions(nor) ((nor)->params->otp.org->n_regions)
/**
- * spi_nor_otp_read_secr() - read OTP data
+ * spi_nor_otp_read_secr() - read security register
* @nor: pointer to 'struct spi_nor'
- * @from: offset to read from
+ * @addr: offset to read from
* @len: number of bytes to read
* @buf: pointer to dst buffer
*
- * Read OTP data from one region by using the SPINOR_OP_RSECR commands. This
- * method is used on GigaDevice and Winbond flashes.
+ * Read a security register by using the SPINOR_OP_RSECR commands.
+ *
+ * In Winbond/GigaDevice datasheets the term "security register" stands for
+ * an one-time-programmable memory area, consisting of multiple bytes (usually
+ * 256). Thus one "security register" maps to one OTP region.
+ *
+ * This method is used on GigaDevice and Winbond flashes.
+ *
+ * Please note, the read must not span multiple registers.
*
* Return: number of bytes read successfully, -errno otherwise
*/
@@ -40,7 +47,6 @@ int spi_nor_otp_read_secr(struct spi_nor *nor, loff_t addr, size_t len, u8 *buf)
rdesc = nor->dirmap.rdesc;
nor->read_opcode = SPINOR_OP_RSECR;
- nor->addr_width = 3;
nor->read_dummy = 8;
nor->read_proto = SNOR_PROTO_1_1_1;
nor->dirmap.rdesc = NULL;
@@ -57,16 +63,20 @@ int spi_nor_otp_read_secr(struct spi_nor *nor, loff_t addr, size_t len, u8 *buf)
}
/**
- * spi_nor_otp_write_secr() - write OTP data
+ * spi_nor_otp_write_secr() - write security register
* @nor: pointer to 'struct spi_nor'
- * @to: offset to write to
+ * @addr: offset to write to
* @len: number of bytes to write
* @buf: pointer to src buffer
*
- * Write OTP data to one region by using the SPINOR_OP_PSECR commands. This
- * method is used on GigaDevice and Winbond flashes.
+ * Write a security register by using the SPINOR_OP_PSECR commands.
+ *
+ * For more information on the term "security register", see the documentation
+ * of spi_nor_otp_read_secr().
*
- * Please note, the write must not span multiple OTP regions.
+ * This method is used on GigaDevice and Winbond flashes.
+ *
+ * Please note, the write must not span multiple registers.
*
* Return: number of bytes written successfully, -errno otherwise
*/
@@ -84,13 +94,12 @@ int spi_nor_otp_write_secr(struct spi_nor *nor, loff_t addr, size_t len,
wdesc = nor->dirmap.wdesc;
nor->program_opcode = SPINOR_OP_PSECR;
- nor->addr_width = 3;
nor->write_proto = SNOR_PROTO_1_1_1;
nor->dirmap.wdesc = NULL;
/*
* We only support a write to one single page. For now all winbond
- * flashes only have one page per OTP region.
+ * flashes only have one page per security register.
*/
ret = spi_nor_write_enable(nor);
if (ret)
@@ -111,6 +120,38 @@ out:
return ret ?: written;
}
+/**
+ * spi_nor_otp_erase_secr() - erase a security register
+ * @nor: pointer to 'struct spi_nor'
+ * @addr: offset of the security register to be erased
+ *
+ * Erase a security register by using the SPINOR_OP_ESECR command.
+ *
+ * For more information on the term "security register", see the documentation
+ * of spi_nor_otp_read_secr().
+ *
+ * This method is used on GigaDevice and Winbond flashes.
+ *
+ * Return: 0 on success, -errno otherwise
+ */
+int spi_nor_otp_erase_secr(struct spi_nor *nor, loff_t addr)
+{
+ u8 erase_opcode = nor->erase_opcode;
+ int ret;
+
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ return ret;
+
+ nor->erase_opcode = SPINOR_OP_ESECR;
+ ret = spi_nor_erase_sector(nor, addr);
+ nor->erase_opcode = erase_opcode;
+ if (ret)
+ return ret;
+
+ return spi_nor_wait_till_ready(nor);
+}
+
static int spi_nor_otp_lock_bit_cr(unsigned int region)
{
static const int lock_bits[] = { SR2_LB1, SR2_LB2, SR2_LB3 };
@@ -240,6 +281,29 @@ out:
return ret;
}
+static int spi_nor_mtd_otp_range_is_locked(struct spi_nor *nor, loff_t ofs,
+ size_t len)
+{
+ const struct spi_nor_otp_ops *ops = nor->params->otp.ops;
+ unsigned int region;
+ int locked;
+
+ /*
+ * If any of the affected OTP regions are locked the entire range is
+ * considered locked.
+ */
+ for (region = spi_nor_otp_offset_to_region(nor, ofs);
+ region <= spi_nor_otp_offset_to_region(nor, ofs + len - 1);
+ region++) {
+ locked = ops->is_locked(nor, region);
+ /* take the branch it is locked or in case of an error */
+ if (locked)
+ return locked;
+ }
+
+ return 0;
+}
+
static int spi_nor_mtd_otp_read_write(struct mtd_info *mtd, loff_t ofs,
size_t total_len, size_t *retlen,
const u8 *buf, bool is_write)
@@ -255,14 +319,26 @@ static int spi_nor_mtd_otp_read_write(struct mtd_info *mtd, loff_t ofs,
if (ofs < 0 || ofs >= spi_nor_otp_size(nor))
return 0;
+ /* don't access beyond the end */
+ total_len = min_t(size_t, total_len, spi_nor_otp_size(nor) - ofs);
+
+ if (!total_len)
+ return 0;
+
ret = spi_nor_lock_and_prep(nor);
if (ret)
return ret;
- /* don't access beyond the end */
- total_len = min_t(size_t, total_len, spi_nor_otp_size(nor) - ofs);
+ if (is_write) {
+ ret = spi_nor_mtd_otp_range_is_locked(nor, ofs, total_len);
+ if (ret < 0) {
+ goto out;
+ } else if (ret) {
+ ret = -EROFS;
+ goto out;
+ }
+ }
- *retlen = 0;
while (total_len) {
/*
* The OTP regions are mapped into a contiguous area starting
@@ -316,6 +392,59 @@ static int spi_nor_mtd_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
return spi_nor_mtd_otp_read_write(mtd, to, len, retlen, buf, true);
}
+static int spi_nor_mtd_otp_erase(struct mtd_info *mtd, loff_t from, size_t len)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ const struct spi_nor_otp_ops *ops = nor->params->otp.ops;
+ const size_t rlen = spi_nor_otp_region_len(nor);
+ unsigned int region;
+ loff_t rstart;
+ int ret;
+
+ /* OTP erase is optional */
+ if (!ops->erase)
+ return -EOPNOTSUPP;
+
+ if (!len)
+ return 0;
+
+ if (from < 0 || (from + len) > spi_nor_otp_size(nor))
+ return -EINVAL;
+
+ /* the user has to explicitly ask for whole regions */
+ if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen))
+ return -EINVAL;
+
+ ret = spi_nor_lock_and_prep(nor);
+ if (ret)
+ return ret;
+
+ ret = spi_nor_mtd_otp_range_is_locked(nor, from, len);
+ if (ret < 0) {
+ goto out;
+ } else if (ret) {
+ ret = -EROFS;
+ goto out;
+ }
+
+ while (len) {
+ region = spi_nor_otp_offset_to_region(nor, from);
+ rstart = spi_nor_otp_region_start(nor, region);
+
+ ret = ops->erase(nor, rstart);
+ if (ret)
+ goto out;
+
+ len -= rlen;
+ from += rlen;
+ }
+
+out:
+ spi_nor_unlock_and_unprep(nor);
+
+ return ret;
+}
+
static int spi_nor_mtd_otp_lock(struct mtd_info *mtd, loff_t from, size_t len)
{
struct spi_nor *nor = mtd_to_spi_nor(mtd);
@@ -374,4 +503,5 @@ void spi_nor_otp_init(struct spi_nor *nor)
mtd->_read_user_prot_reg = spi_nor_mtd_otp_read;
mtd->_write_user_prot_reg = spi_nor_mtd_otp_write;
mtd->_lock_user_prot_reg = spi_nor_mtd_otp_lock;
+ mtd->_erase_user_prot_reg = spi_nor_mtd_otp_erase;
}
diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c
index 23c28e91f698..c500c2118a5d 100644
--- a/drivers/mtd/spi-nor/sfdp.c
+++ b/drivers/mtd/spi-nor/sfdp.c
@@ -16,6 +16,7 @@
(((p)->parameter_table_pointer[2] << 16) | \
((p)->parameter_table_pointer[1] << 8) | \
((p)->parameter_table_pointer[0] << 0))
+#define SFDP_PARAM_HEADER_PARAM_LEN(p) ((p)->length * 4)
#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */
#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */
@@ -1245,6 +1246,8 @@ int spi_nor_parse_sfdp(struct spi_nor *nor)
struct sfdp_parameter_header *param_headers = NULL;
struct sfdp_header header;
struct device *dev = nor->dev;
+ struct sfdp *sfdp;
+ size_t sfdp_size;
size_t psize;
int i, err;
@@ -1267,6 +1270,9 @@ int spi_nor_parse_sfdp(struct spi_nor *nor)
bfpt_header->major != SFDP_JESD216_MAJOR)
return -EINVAL;
+ sfdp_size = SFDP_PARAM_HEADER_PTP(bfpt_header) +
+ SFDP_PARAM_HEADER_PARAM_LEN(bfpt_header);
+
/*
* Allocate memory then read all parameter headers with a single
* Read SFDP command. These parameter headers will actually be parsed
@@ -1294,6 +1300,58 @@ int spi_nor_parse_sfdp(struct spi_nor *nor)
}
/*
+ * Cache the complete SFDP data. It is not (easily) possible to fetch
+ * SFDP after probe time and we need it for the sysfs access.
+ */
+ for (i = 0; i < header.nph; i++) {
+ param_header = &param_headers[i];
+ sfdp_size = max_t(size_t, sfdp_size,
+ SFDP_PARAM_HEADER_PTP(param_header) +
+ SFDP_PARAM_HEADER_PARAM_LEN(param_header));
+ }
+
+ /*
+ * Limit the total size to a reasonable value to avoid allocating too
+ * much memory just of because the flash returned some insane values.
+ */
+ if (sfdp_size > PAGE_SIZE) {
+ dev_dbg(dev, "SFDP data (%zu) too big, truncating\n",
+ sfdp_size);
+ sfdp_size = PAGE_SIZE;
+ }
+
+ sfdp = devm_kzalloc(dev, sizeof(*sfdp), GFP_KERNEL);
+ if (!sfdp) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ /*
+ * The SFDP is organized in chunks of DWORDs. Thus, in theory, the
+ * sfdp_size should be a multiple of DWORDs. But in case a flash
+ * is not spec compliant, make sure that we have enough space to store
+ * the complete SFDP data.
+ */
+ sfdp->num_dwords = DIV_ROUND_UP(sfdp_size, sizeof(*sfdp->dwords));
+ sfdp->dwords = devm_kcalloc(dev, sfdp->num_dwords,
+ sizeof(*sfdp->dwords), GFP_KERNEL);
+ if (!sfdp->dwords) {
+ err = -ENOMEM;
+ devm_kfree(dev, sfdp);
+ goto exit;
+ }
+
+ err = spi_nor_read_sfdp(nor, 0, sfdp_size, sfdp->dwords);
+ if (err < 0) {
+ dev_dbg(dev, "failed to read SFDP data\n");
+ devm_kfree(dev, sfdp->dwords);
+ devm_kfree(dev, sfdp);
+ goto exit;
+ }
+
+ nor->sfdp = sfdp;
+
+ /*
* Check other parameter headers to get the latest revision of
* the basic flash parameter table.
*/
diff --git a/drivers/mtd/spi-nor/sysfs.c b/drivers/mtd/spi-nor/sysfs.c
new file mode 100644
index 000000000000..9aec9d8a98ad
--- /dev/null
+++ b/drivers/mtd/spi-nor/sysfs.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/mtd/spi-nor.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
+#include <linux/sysfs.h>
+
+#include "core.h"
+
+static ssize_t manufacturer_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct spi_mem *spimem = spi_get_drvdata(spi);
+ struct spi_nor *nor = spi_mem_get_drvdata(spimem);
+
+ return sysfs_emit(buf, "%s\n", nor->manufacturer->name);
+}
+static DEVICE_ATTR_RO(manufacturer);
+
+static ssize_t partname_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct spi_mem *spimem = spi_get_drvdata(spi);
+ struct spi_nor *nor = spi_mem_get_drvdata(spimem);
+
+ return sysfs_emit(buf, "%s\n", nor->info->name);
+}
+static DEVICE_ATTR_RO(partname);
+
+static ssize_t jedec_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct spi_mem *spimem = spi_get_drvdata(spi);
+ struct spi_nor *nor = spi_mem_get_drvdata(spimem);
+
+ return sysfs_emit(buf, "%*phN\n", nor->info->id_len, nor->info->id);
+}
+static DEVICE_ATTR_RO(jedec_id);
+
+static struct attribute *spi_nor_sysfs_entries[] = {
+ &dev_attr_manufacturer.attr,
+ &dev_attr_partname.attr,
+ &dev_attr_jedec_id.attr,
+ NULL
+};
+
+static ssize_t sfdp_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct spi_device *spi = to_spi_device(kobj_to_dev(kobj));
+ struct spi_mem *spimem = spi_get_drvdata(spi);
+ struct spi_nor *nor = spi_mem_get_drvdata(spimem);
+ struct sfdp *sfdp = nor->sfdp;
+ size_t sfdp_size = sfdp->num_dwords * sizeof(*sfdp->dwords);
+
+ return memory_read_from_buffer(buf, count, &off, nor->sfdp->dwords,
+ sfdp_size);
+}
+static BIN_ATTR_RO(sfdp, 0);
+
+static struct bin_attribute *spi_nor_sysfs_bin_entries[] = {
+ &bin_attr_sfdp,
+ NULL
+};
+
+static umode_t spi_nor_sysfs_is_bin_visible(struct kobject *kobj,
+ struct bin_attribute *attr, int n)
+{
+ struct spi_device *spi = to_spi_device(kobj_to_dev(kobj));
+ struct spi_mem *spimem = spi_get_drvdata(spi);
+ struct spi_nor *nor = spi_mem_get_drvdata(spimem);
+
+ if (attr == &bin_attr_sfdp && nor->sfdp)
+ return 0444;
+
+ return 0;
+}
+
+static const struct attribute_group spi_nor_sysfs_group = {
+ .name = "spi-nor",
+ .is_bin_visible = spi_nor_sysfs_is_bin_visible,
+ .attrs = spi_nor_sysfs_entries,
+ .bin_attrs = spi_nor_sysfs_bin_entries,
+};
+
+const struct attribute_group *spi_nor_sysfs_groups[] = {
+ &spi_nor_sysfs_group,
+ NULL
+};
diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c
index 9a81c67a60c6..96573f61caf5 100644
--- a/drivers/mtd/spi-nor/winbond.c
+++ b/drivers/mtd/spi-nor/winbond.c
@@ -139,6 +139,7 @@ static int winbond_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
static const struct spi_nor_otp_ops winbond_otp_ops = {
.read = spi_nor_otp_read_secr,
.write = spi_nor_otp_write_secr,
+ .erase = spi_nor_otp_erase_secr,
.lock = spi_nor_otp_lock_sr2,
.is_locked = spi_nor_otp_is_locked_sr2,
};
diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c
index c71daa89bfce..532997e10e29 100644
--- a/drivers/mtd/tests/oobtest.c
+++ b/drivers/mtd/tests/oobtest.c
@@ -506,7 +506,6 @@ static int __init mtd_oobtest_init(void)
err = mtd_write_oob(mtd, addr0, &ops);
if (err) {
pr_info("error occurred as expected\n");
- err = 0;
} else {
pr_err("error: can write past end of OOB\n");
errcnt += 1;
@@ -529,7 +528,6 @@ static int __init mtd_oobtest_init(void)
if (err) {
pr_info("error occurred as expected\n");
- err = 0;
} else {
pr_err("error: can read past end of OOB\n");
errcnt += 1;
@@ -553,7 +551,6 @@ static int __init mtd_oobtest_init(void)
err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
if (err) {
pr_info("error occurred as expected\n");
- err = 0;
} else {
pr_err("error: wrote past end of device\n");
errcnt += 1;
@@ -576,7 +573,6 @@ static int __init mtd_oobtest_init(void)
if (err) {
pr_info("error occurred as expected\n");
- err = 0;
} else {
pr_err("error: read past end of device\n");
errcnt += 1;
@@ -600,7 +596,6 @@ static int __init mtd_oobtest_init(void)
err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
if (err) {
pr_info("error occurred as expected\n");
- err = 0;
} else {
pr_err("error: wrote past end of device\n");
errcnt += 1;
@@ -623,7 +618,6 @@ static int __init mtd_oobtest_init(void)
if (err) {
pr_info("error occurred as expected\n");
- err = 0;
} else {
pr_err("error: read past end of device\n");
errcnt += 1;
@@ -701,6 +695,7 @@ static int __init mtd_oobtest_init(void)
(long long)addr);
errcnt += 1;
if (errcnt > 1000) {
+ err = -EINVAL;
pr_err("error: too many errors\n");
goto out;
}
diff --git a/drivers/mtd/tests/torturetest.c b/drivers/mtd/tests/torturetest.c
index 6787ac5471a9..841689b4d86d 100644
--- a/drivers/mtd/tests/torturetest.c
+++ b/drivers/mtd/tests/torturetest.c
@@ -230,8 +230,6 @@ static int __init tort_init(void)
if (!bad_ebs)
goto out_check_buf;
- err = 0;
-
/* Initialize patterns */
memset(patt_FF, 0xFF, mtd->erasesize);
for (i = 0; i < mtd->erasesize / pgsize; i++) {
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index e1a2ae21dfd3..e003b4b44ffa 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -394,53 +394,46 @@ int ubiblock_create(struct ubi_volume_info *vi)
dev->vol_id = vi->vol_id;
dev->leb_size = vi->usable_leb_size;
+ dev->tag_set.ops = &ubiblock_mq_ops;
+ dev->tag_set.queue_depth = 64;
+ dev->tag_set.numa_node = NUMA_NO_NODE;
+ dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
+ dev->tag_set.cmd_size = sizeof(struct ubiblock_pdu);
+ dev->tag_set.driver_data = dev;
+ dev->tag_set.nr_hw_queues = 1;
+
+ ret = blk_mq_alloc_tag_set(&dev->tag_set);
+ if (ret) {
+ dev_err(disk_to_dev(dev->gd), "blk_mq_alloc_tag_set failed");
+ goto out_free_dev;;
+ }
+
+
/* Initialize the gendisk of this ubiblock device */
- gd = alloc_disk(1);
- if (!gd) {
- pr_err("UBI: block: alloc_disk failed\n");
- ret = -ENODEV;
- goto out_free_dev;
+ gd = blk_mq_alloc_disk(&dev->tag_set, dev);
+ if (IS_ERR(gd)) {
+ ret = PTR_ERR(gd);
+ goto out_free_tags;
}
gd->fops = &ubiblock_ops;
gd->major = ubiblock_major;
+ gd->minors = 1;
gd->first_minor = idr_alloc(&ubiblock_minor_idr, dev, 0, 0, GFP_KERNEL);
if (gd->first_minor < 0) {
dev_err(disk_to_dev(gd),
"block: dynamic minor allocation failed");
ret = -ENODEV;
- goto out_put_disk;
+ goto out_cleanup_disk;
}
gd->private_data = dev;
sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id);
set_capacity(gd, disk_capacity);
dev->gd = gd;
- dev->tag_set.ops = &ubiblock_mq_ops;
- dev->tag_set.queue_depth = 64;
- dev->tag_set.numa_node = NUMA_NO_NODE;
- dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
- dev->tag_set.cmd_size = sizeof(struct ubiblock_pdu);
- dev->tag_set.driver_data = dev;
- dev->tag_set.nr_hw_queues = 1;
-
- ret = blk_mq_alloc_tag_set(&dev->tag_set);
- if (ret) {
- dev_err(disk_to_dev(dev->gd), "blk_mq_alloc_tag_set failed");
- goto out_remove_minor;
- }
-
- dev->rq = blk_mq_init_queue(&dev->tag_set);
- if (IS_ERR(dev->rq)) {
- dev_err(disk_to_dev(gd), "blk_mq_init_queue failed");
- ret = PTR_ERR(dev->rq);
- goto out_free_tags;
- }
+ dev->rq = gd->queue;
blk_queue_max_segments(dev->rq, UBI_MAX_SG_COUNT);
- dev->rq->queuedata = dev;
- dev->gd->queue = dev->rq;
-
/*
* Create one workqueue per volume (per registered block device).
* Rembember workqueues are cheap, they're not threads.
@@ -448,7 +441,7 @@ int ubiblock_create(struct ubi_volume_info *vi)
dev->wq = alloc_workqueue("%s", 0, 0, gd->disk_name);
if (!dev->wq) {
ret = -ENOMEM;
- goto out_free_queue;
+ goto out_remove_minor;
}
list_add_tail(&dev->list, &ubiblock_devices);
@@ -460,14 +453,12 @@ int ubiblock_create(struct ubi_volume_info *vi)
mutex_unlock(&devices_mutex);
return 0;
-out_free_queue:
- blk_cleanup_queue(dev->rq);
-out_free_tags:
- blk_mq_free_tag_set(&dev->tag_set);
out_remove_minor:
idr_remove(&ubiblock_minor_idr, gd->first_minor);
-out_put_disk:
- put_disk(dev->gd);
+out_cleanup_disk:
+ blk_cleanup_disk(dev->gd);
+out_free_tags:
+ blk_mq_free_tag_set(&dev->tag_set);
out_free_dev:
kfree(dev);
out_unlock:
@@ -483,11 +474,10 @@ static void ubiblock_cleanup(struct ubiblock *dev)
/* Flush pending work */
destroy_workqueue(dev->wq);
/* Finally destroy the blk queue */
- blk_cleanup_queue(dev->rq);
- blk_mq_free_tag_set(&dev->tag_set);
dev_info(disk_to_dev(dev->gd), "released");
+ blk_cleanup_disk(dev->gd);
+ blk_mq_free_tag_set(&dev->tag_set);
idr_remove(&ubiblock_minor_idr, dev->gd->first_minor);
- put_disk(dev->gd);
}
int ubiblock_remove(struct ubi_volume_info *vi)
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index ac2bdba8bb1a..3c0c8eca4d51 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -511,7 +511,7 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
n = snprintf(d->dfs_dir_name, UBI_DFS_DIR_LEN + 1, UBI_DFS_DIR_NAME,
ubi->ubi_num);
- if (n == UBI_DFS_DIR_LEN) {
+ if (n > UBI_DFS_DIR_LEN) {
/* The array size is too small */
return -EINVAL;
}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 74dc8e249faa..6977f8248df7 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -262,17 +262,17 @@ config GENEVE
will be called geneve.
config BAREUDP
- tristate "Bare UDP Encapsulation"
- depends on INET
- depends on IPV6 || !IPV6
- select NET_UDP_TUNNEL
- select GRO_CELLS
- help
- This adds a bare UDP tunnel module for tunnelling different
- kinds of traffic like MPLS, IP, etc. inside a UDP tunnel.
-
- To compile this driver as a module, choose M here: the module
- will be called bareudp.
+ tristate "Bare UDP Encapsulation"
+ depends on INET
+ depends on IPV6 || !IPV6
+ select NET_UDP_TUNNEL
+ select GRO_CELLS
+ help
+ This adds a bare UDP tunnel module for tunnelling different
+ kinds of traffic like MPLS, IP, etc. inside a UDP tunnel.
+
+ To compile this driver as a module, choose M here: the module
+ will be called bareudp.
config GTP
tristate "GPRS Tunneling Protocol datapath (GTP-U)"
@@ -431,6 +431,7 @@ config VSOCKMON
config MHI_NET
tristate "MHI network driver"
depends on MHI_BUS
+ select WWAN
help
This is the network driver for MHI bus. It can be used with
QCOM based WWAN modems (like SDX55). Say Y or M.
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index 6b12ce822e51..f0695d68c47e 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -609,12 +609,12 @@ static int cops_nodeid (struct net_device *dev, int nodeid)
if(lp->board == DAYNA)
{
- /* Empty any pending adapter responses. */
+ /* Empty any pending adapter responses. */
while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0)
{
outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupts. */
- if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
- cops_rx(dev); /* Kick any packets waiting. */
+ if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
+ cops_rx(dev); /* Kick any packets waiting. */
schedule();
}
@@ -630,13 +630,13 @@ static int cops_nodeid (struct net_device *dev, int nodeid)
while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
{
outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupt. */
- cops_rx(dev); /* Kick out packets waiting. */
+ cops_rx(dev); /* Kick out packets waiting. */
schedule();
}
/* Not sure what Tangent does if nodeid picked is used. */
if(nodeid == 0) /* Seed. */
- nodeid = jiffies&0xFF; /* Get a random try */
+ nodeid = jiffies&0xFF; /* Get a random try */
outb(2, ioaddr); /* Command length LSB */
outb(0, ioaddr); /* Command length MSB */
outb(LAP_INIT, ioaddr); /* Send LAP_INIT byte */
@@ -651,13 +651,13 @@ static int cops_nodeid (struct net_device *dev, int nodeid)
if(lp->board == DAYNA)
{
- if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
- cops_rx(dev); /* Grab the nodeid put in lp->node_acquire. */
+ if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)
+ cops_rx(dev); /* Grab the nodeid put in lp->node_acquire. */
}
if(lp->board == TANGENT)
{
if(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)
- cops_rx(dev); /* Grab the nodeid put in lp->node_acquire. */
+ cops_rx(dev); /* Grab the nodeid put in lp->node_acquire. */
}
schedule();
}
@@ -719,16 +719,16 @@ static irqreturn_t cops_interrupt(int irq, void *dev_id)
{
do {
outb(0, ioaddr + COPS_CLEAR_INT);
- status=inb(ioaddr+DAYNA_CARD_STATUS);
- if((status&0x03)==DAYNA_RX_REQUEST)
- cops_rx(dev);
- netif_wake_queue(dev);
+ status=inb(ioaddr+DAYNA_CARD_STATUS);
+ if((status&0x03)==DAYNA_RX_REQUEST)
+ cops_rx(dev);
+ netif_wake_queue(dev);
} while(++boguscount < 20);
}
else
{
do {
- status=inb(ioaddr+TANG_CARD_STATUS);
+ status=inb(ioaddr+TANG_CARD_STATUS);
if(status & TANG_RX_READY)
cops_rx(dev);
if(status & TANG_TX_READY)
@@ -855,7 +855,7 @@ static void cops_timeout(struct net_device *dev, unsigned int txqueue)
if(lp->board==TANGENT)
{
if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)
- printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name);
+ printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name);
}
printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name);
cops_jumpstart(dev); /* Restart the card. */
@@ -897,7 +897,7 @@ static netdev_tx_t cops_send_packet(struct sk_buff *skb,
outb(LAP_WRITE, ioaddr);
if(lp->board == DAYNA) /* Check the transmit buffer again. */
- while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
+ while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);
outsb(ioaddr, skb->data, skb->len); /* Send out the data. */
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index c6f73aa3700c..69c270885ff0 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -584,11 +584,13 @@ loop:
printk("%02x ",ltdmacbuf[i]);
printk("\n");
}
+
handlecommand(dev);
- if(0xfa==inb_p(base+6)) {
- /* we timed out, so return */
- goto done;
- }
+
+ if (0xfa == inb_p(base + 6)) {
+ /* we timed out, so return */
+ goto done;
+ }
} else {
/* we don't seem to have a command */
if (!mboxinuse[0]) {
@@ -935,10 +937,10 @@ static netdev_tx_t ltpc_xmit(struct sk_buff *skb, struct net_device *dev)
static int __init ltpc_probe_dma(int base, int dma)
{
int want = (dma == 3) ? 2 : (dma == 1) ? 1 : 3;
- unsigned long timeout;
- unsigned long f;
+ unsigned long timeout;
+ unsigned long f;
- if (want & 1) {
+ if (want & 1) {
if (request_dma(1,"ltpc")) {
want &= ~1;
} else {
diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c
index edfad93e7b68..a7ee0af1af90 100644
--- a/drivers/net/bareudp.c
+++ b/drivers/net/bareudp.c
@@ -133,6 +133,7 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
skb->dev = bareudp->dev;
oiph = skb_network_header(skb);
skb_reset_network_header(skb);
+ skb_reset_mac_header(skb);
if (!IS_ENABLED(CONFIG_IPV6) || family == AF_INET)
err = IP_ECN_decapsulate(oiph, skb);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 3455f2cc13f2..22e5632089ac 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -104,6 +104,7 @@ static void __tlb_clear_slave(struct bonding *bond, struct slave *slave,
index = SLAVE_TLB_INFO(slave).head;
while (index != TLB_NULL_INDEX) {
u32 next_index = tx_hash_table[index].next;
+
tlb_init_table_entry(&tx_hash_table[index], save_load);
index = next_index;
}
@@ -228,7 +229,7 @@ static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index,
{
struct slave *tx_slave;
- /* We don't need to disable softirq here, becase
+ /* We don't need to disable softirq here, because
* tlb_choose_channel() is only called by bond_alb_xmit()
* which already has softirq disabled.
*/
@@ -608,7 +609,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb,
client_info->ip_src = arp->ip_src;
client_info->ip_dst = arp->ip_dst;
- /* arp->mac_dst is broadcast for arp reqeusts.
+ /* arp->mac_dst is broadcast for arp requests.
* will be updated with clients actual unicast mac address
* upon receiving an arp reply.
*/
@@ -628,6 +629,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb,
if (!client_info->assigned) {
u32 prev_tbl_head = bond_info->rx_hashtbl_used_head;
+
bond_info->rx_hashtbl_used_head = hash_index;
client_info->used_next = prev_tbl_head;
if (prev_tbl_head != RLB_NULL_INDEX) {
@@ -830,9 +832,10 @@ static void rlb_purge_src_ip(struct bonding *bond, struct arp_pkt *arp)
while (index != RLB_NULL_INDEX) {
struct rlb_client_info *entry = &(bond_info->rx_hashtbl[index]);
u32 next_index = entry->src_next;
+
if (entry->ip_src == arp->ip_src &&
!ether_addr_equal_64bits(arp->mac_src, entry->mac_src))
- rlb_delete_table_entry(bond, index);
+ rlb_delete_table_entry(bond, index);
index = next_index;
}
spin_unlock_bh(&bond->mode_lock);
@@ -1268,7 +1271,7 @@ unwind:
return res;
}
-/************************ exported alb funcions ************************/
+/************************ exported alb functions ************************/
int bond_alb_initialize(struct bonding *bond, int rlb_enabled)
{
@@ -1547,7 +1550,7 @@ void bond_alb_monitor(struct work_struct *work)
bond_for_each_slave_rcu(bond, slave, iter) {
/* If updating current_active, use all currently
- * user mac addreses (!strict_match). Otherwise, only
+ * user mac addresses (!strict_match). Otherwise, only
* use mac of the slave device.
* In RLB mode, we always use strict matches.
*/
diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c
index f3f86ef68ae0..4f9b4a18c74c 100644
--- a/drivers/net/bonding/bond_debugfs.c
+++ b/drivers/net/bonding/bond_debugfs.c
@@ -88,9 +88,8 @@ void bond_create_debugfs(void)
{
bonding_debug_root = debugfs_create_dir("bonding", NULL);
- if (!bonding_debug_root) {
+ if (!bonding_debug_root)
pr_warn("Warning: Cannot create bonding directory in debugfs\n");
- }
}
void bond_destroy_debugfs(void)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index c5a646d06102..d22d78303311 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -401,24 +401,85 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev,
static int bond_ipsec_add_sa(struct xfrm_state *xs)
{
struct net_device *bond_dev = xs->xso.dev;
+ struct bond_ipsec *ipsec;
struct bonding *bond;
struct slave *slave;
+ int err;
if (!bond_dev)
return -EINVAL;
+ rcu_read_lock();
bond = netdev_priv(bond_dev);
slave = rcu_dereference(bond->curr_active_slave);
- xs->xso.real_dev = slave->dev;
- bond->xs = xs;
+ if (!slave) {
+ rcu_read_unlock();
+ return -ENODEV;
+ }
- if (!(slave->dev->xfrmdev_ops
- && slave->dev->xfrmdev_ops->xdo_dev_state_add)) {
+ if (!slave->dev->xfrmdev_ops ||
+ !slave->dev->xfrmdev_ops->xdo_dev_state_add ||
+ netif_is_bond_master(slave->dev)) {
slave_warn(bond_dev, slave->dev, "Slave does not support ipsec offload\n");
+ rcu_read_unlock();
return -EINVAL;
}
- return slave->dev->xfrmdev_ops->xdo_dev_state_add(xs);
+ ipsec = kmalloc(sizeof(*ipsec), GFP_ATOMIC);
+ if (!ipsec) {
+ rcu_read_unlock();
+ return -ENOMEM;
+ }
+ xs->xso.real_dev = slave->dev;
+
+ err = slave->dev->xfrmdev_ops->xdo_dev_state_add(xs);
+ if (!err) {
+ ipsec->xs = xs;
+ INIT_LIST_HEAD(&ipsec->list);
+ spin_lock_bh(&bond->ipsec_lock);
+ list_add(&ipsec->list, &bond->ipsec_list);
+ spin_unlock_bh(&bond->ipsec_lock);
+ } else {
+ kfree(ipsec);
+ }
+ rcu_read_unlock();
+ return err;
+}
+
+static void bond_ipsec_add_sa_all(struct bonding *bond)
+{
+ struct net_device *bond_dev = bond->dev;
+ struct bond_ipsec *ipsec;
+ struct slave *slave;
+
+ rcu_read_lock();
+ slave = rcu_dereference(bond->curr_active_slave);
+ if (!slave)
+ goto out;
+
+ if (!slave->dev->xfrmdev_ops ||
+ !slave->dev->xfrmdev_ops->xdo_dev_state_add ||
+ netif_is_bond_master(slave->dev)) {
+ spin_lock_bh(&bond->ipsec_lock);
+ if (!list_empty(&bond->ipsec_list))
+ slave_warn(bond_dev, slave->dev,
+ "%s: no slave xdo_dev_state_add\n",
+ __func__);
+ spin_unlock_bh(&bond->ipsec_lock);
+ goto out;
+ }
+
+ spin_lock_bh(&bond->ipsec_lock);
+ list_for_each_entry(ipsec, &bond->ipsec_list, list) {
+ ipsec->xs->xso.real_dev = slave->dev;
+ if (slave->dev->xfrmdev_ops->xdo_dev_state_add(ipsec->xs)) {
+ slave_warn(bond_dev, slave->dev, "%s: failed to add SA\n", __func__);
+ ipsec->xs->xso.real_dev = NULL;
+ }
+ }
+ spin_unlock_bh(&bond->ipsec_lock);
+out:
+ rcu_read_unlock();
}
/**
@@ -428,27 +489,77 @@ static int bond_ipsec_add_sa(struct xfrm_state *xs)
static void bond_ipsec_del_sa(struct xfrm_state *xs)
{
struct net_device *bond_dev = xs->xso.dev;
+ struct bond_ipsec *ipsec;
struct bonding *bond;
struct slave *slave;
if (!bond_dev)
return;
+ rcu_read_lock();
bond = netdev_priv(bond_dev);
slave = rcu_dereference(bond->curr_active_slave);
if (!slave)
- return;
+ goto out;
- xs->xso.real_dev = slave->dev;
+ if (!xs->xso.real_dev)
+ goto out;
- if (!(slave->dev->xfrmdev_ops
- && slave->dev->xfrmdev_ops->xdo_dev_state_delete)) {
+ WARN_ON(xs->xso.real_dev != slave->dev);
+
+ if (!slave->dev->xfrmdev_ops ||
+ !slave->dev->xfrmdev_ops->xdo_dev_state_delete ||
+ netif_is_bond_master(slave->dev)) {
slave_warn(bond_dev, slave->dev, "%s: no slave xdo_dev_state_delete\n", __func__);
- return;
+ goto out;
}
slave->dev->xfrmdev_ops->xdo_dev_state_delete(xs);
+out:
+ spin_lock_bh(&bond->ipsec_lock);
+ list_for_each_entry(ipsec, &bond->ipsec_list, list) {
+ if (ipsec->xs == xs) {
+ list_del(&ipsec->list);
+ kfree(ipsec);
+ break;
+ }
+ }
+ spin_unlock_bh(&bond->ipsec_lock);
+ rcu_read_unlock();
+}
+
+static void bond_ipsec_del_sa_all(struct bonding *bond)
+{
+ struct net_device *bond_dev = bond->dev;
+ struct bond_ipsec *ipsec;
+ struct slave *slave;
+
+ rcu_read_lock();
+ slave = rcu_dereference(bond->curr_active_slave);
+ if (!slave) {
+ rcu_read_unlock();
+ return;
+ }
+
+ spin_lock_bh(&bond->ipsec_lock);
+ list_for_each_entry(ipsec, &bond->ipsec_list, list) {
+ if (!ipsec->xs->xso.real_dev)
+ continue;
+
+ if (!slave->dev->xfrmdev_ops ||
+ !slave->dev->xfrmdev_ops->xdo_dev_state_delete ||
+ netif_is_bond_master(slave->dev)) {
+ slave_warn(bond_dev, slave->dev,
+ "%s: no slave xdo_dev_state_delete\n",
+ __func__);
+ } else {
+ slave->dev->xfrmdev_ops->xdo_dev_state_delete(ipsec->xs);
+ }
+ ipsec->xs->xso.real_dev = NULL;
+ }
+ spin_unlock_bh(&bond->ipsec_lock);
+ rcu_read_unlock();
}
/**
@@ -459,21 +570,37 @@ static void bond_ipsec_del_sa(struct xfrm_state *xs)
static bool bond_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs)
{
struct net_device *bond_dev = xs->xso.dev;
- struct bonding *bond = netdev_priv(bond_dev);
- struct slave *curr_active = rcu_dereference(bond->curr_active_slave);
- struct net_device *slave_dev = curr_active->dev;
+ struct net_device *real_dev;
+ struct slave *curr_active;
+ struct bonding *bond;
+ int err;
- if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP)
- return true;
+ bond = netdev_priv(bond_dev);
+ rcu_read_lock();
+ curr_active = rcu_dereference(bond->curr_active_slave);
+ real_dev = curr_active->dev;
- if (!(slave_dev->xfrmdev_ops
- && slave_dev->xfrmdev_ops->xdo_dev_offload_ok)) {
- slave_warn(bond_dev, slave_dev, "%s: no slave xdo_dev_offload_ok\n", __func__);
- return false;
+ if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
+ err = false;
+ goto out;
+ }
+
+ if (!xs->xso.real_dev) {
+ err = false;
+ goto out;
+ }
+
+ if (!real_dev->xfrmdev_ops ||
+ !real_dev->xfrmdev_ops->xdo_dev_offload_ok ||
+ netif_is_bond_master(real_dev)) {
+ err = false;
+ goto out;
}
- xs->xso.real_dev = slave_dev;
- return slave_dev->xfrmdev_ops->xdo_dev_offload_ok(skb, xs);
+ err = real_dev->xfrmdev_ops->xdo_dev_offload_ok(skb, xs);
+out:
+ rcu_read_unlock();
+ return err;
}
static const struct xfrmdev_ops bond_xfrmdev_ops = {
@@ -620,7 +747,7 @@ static int bond_check_dev_link(struct bonding *bond,
*/
/* Yes, the mii is overlaid on the ifreq.ifr_ifru */
- strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ);
+ strscpy_pad(ifr.ifr_name, slave_dev->name, IFNAMSIZ);
mii = if_mii(&ifr);
if (ioctl(slave_dev, &ifr, SIOCGMIIPHY) == 0) {
mii->reg_num = MII_BMSR;
@@ -990,8 +1117,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
return;
#ifdef CONFIG_XFRM_OFFLOAD
- if (old_active && bond->xs)
- bond_ipsec_del_sa(bond->xs);
+ bond_ipsec_del_sa_all(bond);
#endif /* CONFIG_XFRM_OFFLOAD */
if (new_active) {
@@ -1013,9 +1139,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
if (bond_is_lb(bond))
bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP);
} else {
- if (bond_uses_primary(bond)) {
+ if (bond_uses_primary(bond))
slave_info(bond->dev, new_active->dev, "making interface the new active one\n");
- }
}
}
@@ -1067,10 +1192,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
}
#ifdef CONFIG_XFRM_OFFLOAD
- if (new_active && bond->xs) {
- xfrm_dev_state_flush(dev_net(bond->dev), bond->dev, true);
- bond_ipsec_add_sa(bond->xs);
- }
+ bond_ipsec_add_sa_all(bond);
#endif /* CONFIG_XFRM_OFFLOAD */
/* resend IGMP joins since active slave has changed or
@@ -1601,6 +1723,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
int link_reporting;
int res = 0, i;
+ if (slave_dev->flags & IFF_MASTER &&
+ !netif_is_bond_master(slave_dev)) {
+ NL_SET_ERR_MSG(extack, "Device with IFF_MASTER cannot be enslaved");
+ netdev_err(bond_dev,
+ "Error: Device with IFF_MASTER cannot be enslaved\n");
+ return -EPERM;
+ }
+
if (!bond->params.use_carrier &&
slave_dev->ethtool_ops->get_link == NULL &&
slave_ops->ndo_do_ioctl == NULL) {
@@ -2272,6 +2402,7 @@ static int bond_release_and_destroy(struct net_device *bond_dev,
static void bond_info_query(struct net_device *bond_dev, struct ifbond *info)
{
struct bonding *bond = netdev_priv(bond_dev);
+
bond_fill_ifbond(bond, info);
}
@@ -3319,6 +3450,7 @@ static int bond_master_netdev_event(unsigned long event,
return bond_event_changename(event_bond);
case NETDEV_UNREGISTER:
bond_remove_proc_entry(event_bond);
+ xfrm_dev_state_flush(dev_net(bond_dev), bond_dev, true);
break;
case NETDEV_REGISTER:
bond_create_proc_entry(event_bond);
@@ -4202,16 +4334,16 @@ static u32 bond_rr_gen_slave_id(struct bonding *bond)
slave_id = prandom_u32();
break;
case 1:
- slave_id = bond->rr_tx_counter;
+ slave_id = this_cpu_inc_return(*bond->rr_tx_counter);
break;
default:
reciprocal_packets_per_slave =
bond->params.reciprocal_packets_per_slave;
- slave_id = reciprocal_divide(bond->rr_tx_counter,
+ slave_id = this_cpu_inc_return(*bond->rr_tx_counter);
+ slave_id = reciprocal_divide(slave_id,
reciprocal_packets_per_slave);
break;
}
- bond->rr_tx_counter++;
return slave_id;
}
@@ -4849,8 +4981,12 @@ static const struct device_type bond_type = {
static void bond_destructor(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
+
if (bond->wq)
destroy_workqueue(bond->wq);
+
+ if (bond->rr_tx_counter)
+ free_percpu(bond->rr_tx_counter);
}
void bond_setup(struct net_device *bond_dev)
@@ -4882,7 +5018,8 @@ void bond_setup(struct net_device *bond_dev)
#ifdef CONFIG_XFRM_OFFLOAD
/* set up xfrm device ops (only supported in active-backup right now) */
bond_dev->xfrmdev_ops = &bond_xfrmdev_ops;
- bond->xs = NULL;
+ INIT_LIST_HEAD(&bond->ipsec_list);
+ spin_lock_init(&bond->ipsec_lock);
#endif /* CONFIG_XFRM_OFFLOAD */
/* don't acquire bond device's netif_tx_lock when transmitting */
@@ -5329,10 +5466,8 @@ static int bond_check_params(struct bond_params *params)
(struct reciprocal_value) { 0 };
}
- if (primary) {
- strncpy(params->primary, primary, IFNAMSIZ);
- params->primary[IFNAMSIZ - 1] = 0;
- }
+ if (primary)
+ strscpy_pad(params->primary, primary, sizeof(params->primary));
memcpy(params->arp_targets, arp_target, sizeof(arp_target));
@@ -5351,6 +5486,15 @@ static int bond_init(struct net_device *bond_dev)
if (!bond->wq)
return -ENOMEM;
+ if (BOND_MODE(bond) == BOND_MODE_ROUNDROBIN) {
+ bond->rr_tx_counter = alloc_percpu(u32);
+ if (!bond->rr_tx_counter) {
+ destroy_workqueue(bond->wq);
+ bond->wq = NULL;
+ return -ENOMEM;
+ }
+ }
+
spin_lock_init(&bond->stats_lock);
netdev_lockdep_set_classes(bond_dev);
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index f0f9138e967f..0561ece1ba45 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -598,7 +598,7 @@ static int bond_fill_info(struct sk_buff *skb,
goto nla_put_failure;
if (nla_put_u32(skb, IFLA_BOND_RESEND_IGMP,
- bond->params.resend_igmp))
+ bond->params.resend_igmp))
goto nla_put_failure;
if (nla_put_u8(skb, IFLA_BOND_NUM_PEER_NOTIF,
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index c9d3604ae129..0cf25de6f46d 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -705,7 +705,7 @@ out:
int __bond_opt_set_notify(struct bonding *bond,
unsigned int option, struct bond_opt_value *val)
{
- int ret = -ENOENT;
+ int ret;
ASSERT_RTNL();
@@ -1206,8 +1206,7 @@ static int bond_option_primary_set(struct bonding *bond,
RCU_INIT_POINTER(bond->primary_slave, NULL);
bond_select_active_slave(bond);
}
- strncpy(bond->params.primary, primary, IFNAMSIZ);
- bond->params.primary[IFNAMSIZ - 1] = 0;
+ strscpy_pad(bond->params.primary, primary, IFNAMSIZ);
netdev_dbg(bond->dev, "Recording %s as primary, but it has not been enslaved yet\n",
primary);
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 56d34be5e797..0fb1da361bb1 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -112,6 +112,7 @@ static void bond_info_show_master(struct seq_file *seq)
/* ARP information */
if (bond->params.arp_interval > 0) {
int printed = 0;
+
seq_printf(seq, "ARP Polling Interval (ms): %d\n",
bond->params.arp_interval);
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 2d615a93685e..5f9e9a240226 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -385,6 +385,7 @@ static ssize_t bonding_show_num_peer_notif(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
+
return sprintf(buf, "%d\n", bond->params.num_peer_notif);
}
static DEVICE_ATTR(num_grat_arp, 0644,
@@ -496,6 +497,7 @@ static ssize_t bonding_show_ad_aggregator(struct device *d,
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct ad_info ad_info;
+
count = sprintf(buf, "%d\n",
bond_3ad_get_active_agg_info(bond, &ad_info)
? 0 : ad_info.aggregator_id);
@@ -516,6 +518,7 @@ static ssize_t bonding_show_ad_num_ports(struct device *d,
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct ad_info ad_info;
+
count = sprintf(buf, "%d\n",
bond_3ad_get_active_agg_info(bond, &ad_info)
? 0 : ad_info.ports);
@@ -536,6 +539,7 @@ static ssize_t bonding_show_ad_actor_key(struct device *d,
if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN)) {
struct ad_info ad_info;
+
count = sprintf(buf, "%d\n",
bond_3ad_get_active_agg_info(bond, &ad_info)
? 0 : ad_info.actor_key);
@@ -556,6 +560,7 @@ static ssize_t bonding_show_ad_partner_key(struct device *d,
if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN)) {
struct ad_info ad_info;
+
count = sprintf(buf, "%d\n",
bond_3ad_get_active_agg_info(bond, &ad_info)
? 0 : ad_info.partner_key);
@@ -576,6 +581,7 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d,
if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN)) {
struct ad_info ad_info;
+
if (!bond_3ad_get_active_agg_info(bond, &ad_info))
count = sprintf(buf, "%pM\n", ad_info.partner_system);
}
@@ -660,6 +666,7 @@ static ssize_t bonding_show_tlb_dynamic_lb(struct device *d,
char *buf)
{
struct bonding *bond = to_bond(d);
+
return sprintf(buf, "%d\n", bond->params.tlb_dynamic_lb);
}
static DEVICE_ATTR(tlb_dynamic_lb, 0644,
diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index a77124bc1f4b..709660cb38f8 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -20,15 +20,6 @@ config CAIF_TTY
identified as N_CAIF. When this ldisc is opened from user space
it will redirect the TTY's traffic into the CAIF stack.
-config CAIF_HSI
- tristate "CAIF HSI transport driver"
- depends on CAIF
- default n
- help
- The CAIF low level driver for CAIF over HSI.
- Be aware that if you enable this then you also need to
- enable a low-level HSI driver.
-
config CAIF_VIRTIO
tristate "CAIF virtio transport driver"
depends on CAIF && HAS_DMA
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
index b1918c8c126c..97f664f8016c 100644
--- a/drivers/net/caif/Makefile
+++ b/drivers/net/caif/Makefile
@@ -4,8 +4,5 @@ ccflags-$(CONFIG_CAIF_DEBUG) := -DDEBUG
# Serial interface
obj-$(CONFIG_CAIF_TTY) += caif_serial.o
-# HSI interface
-obj-$(CONFIG_CAIF_HSI) += caif_hsi.o
-
# Virtio interface
obj-$(CONFIG_CAIF_VIRTIO) += caif_virtio.o
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c
deleted file mode 100644
index 3d63b15bbaa1..000000000000
--- a/drivers/net/caif/caif_hsi.c
+++ /dev/null
@@ -1,1454 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) ST-Ericsson AB 2010
- * Author: Daniel Martensson
- * Dmitry.Tarnyagin / dmitry.tarnyagin@lockless.no
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME fmt
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/netdevice.h>
-#include <linux/string.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/if_arp.h>
-#include <linux/timer.h>
-#include <net/rtnetlink.h>
-#include <linux/pkt_sched.h>
-#include <net/caif/caif_layer.h>
-#include <net/caif/caif_hsi.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Daniel Martensson");
-MODULE_DESCRIPTION("CAIF HSI driver");
-
-/* Returns the number of padding bytes for alignment. */
-#define PAD_POW2(x, pow) ((((x)&((pow)-1)) == 0) ? 0 :\
- (((pow)-((x)&((pow)-1)))))
-
-static const struct cfhsi_config hsi_default_config = {
-
- /* Inactivity timeout on HSI, ms */
- .inactivity_timeout = HZ,
-
- /* Aggregation timeout (ms) of zero means no aggregation is done*/
- .aggregation_timeout = 1,
-
- /*
- * HSI link layer flow-control thresholds.
- * Threshold values for the HSI packet queue. Flow-control will be
- * asserted when the number of packets exceeds q_high_mark. It will
- * not be de-asserted before the number of packets drops below
- * q_low_mark.
- * Warning: A high threshold value might increase throughput but it
- * will at the same time prevent channel prioritization and increase
- * the risk of flooding the modem. The high threshold should be above
- * the low.
- */
- .q_high_mark = 100,
- .q_low_mark = 50,
-
- /*
- * HSI padding options.
- * Warning: must be a base of 2 (& operation used) and can not be zero !
- */
- .head_align = 4,
- .tail_align = 4,
-};
-
-#define ON 1
-#define OFF 0
-
-static LIST_HEAD(cfhsi_list);
-
-static void cfhsi_inactivity_tout(struct timer_list *t)
-{
- struct cfhsi *cfhsi = from_timer(cfhsi, t, inactivity_timer);
-
- netdev_dbg(cfhsi->ndev, "%s.\n",
- __func__);
-
- /* Schedule power down work queue. */
- if (!test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
- queue_work(cfhsi->wq, &cfhsi->wake_down_work);
-}
-
-static void cfhsi_update_aggregation_stats(struct cfhsi *cfhsi,
- const struct sk_buff *skb,
- int direction)
-{
- struct caif_payload_info *info;
- int hpad, tpad, len;
-
- info = (struct caif_payload_info *)&skb->cb;
- hpad = 1 + PAD_POW2((info->hdr_len + 1), cfhsi->cfg.head_align);
- tpad = PAD_POW2((skb->len + hpad), cfhsi->cfg.tail_align);
- len = skb->len + hpad + tpad;
-
- if (direction > 0)
- cfhsi->aggregation_len += len;
- else if (direction < 0)
- cfhsi->aggregation_len -= len;
-}
-
-static bool cfhsi_can_send_aggregate(struct cfhsi *cfhsi)
-{
- int i;
-
- if (cfhsi->cfg.aggregation_timeout == 0)
- return true;
-
- for (i = 0; i < CFHSI_PRIO_BEBK; ++i) {
- if (cfhsi->qhead[i].qlen)
- return true;
- }
-
- /* TODO: Use aggregation_len instead */
- if (cfhsi->qhead[CFHSI_PRIO_BEBK].qlen >= CFHSI_MAX_PKTS)
- return true;
-
- return false;
-}
-
-static struct sk_buff *cfhsi_dequeue(struct cfhsi *cfhsi)
-{
- struct sk_buff *skb;
- int i;
-
- for (i = 0; i < CFHSI_PRIO_LAST; ++i) {
- skb = skb_dequeue(&cfhsi->qhead[i]);
- if (skb)
- break;
- }
-
- return skb;
-}
-
-static int cfhsi_tx_queue_len(struct cfhsi *cfhsi)
-{
- int i, len = 0;
- for (i = 0; i < CFHSI_PRIO_LAST; ++i)
- len += skb_queue_len(&cfhsi->qhead[i]);
- return len;
-}
-
-static void cfhsi_abort_tx(struct cfhsi *cfhsi)
-{
- struct sk_buff *skb;
-
- for (;;) {
- spin_lock_bh(&cfhsi->lock);
- skb = cfhsi_dequeue(cfhsi);
- if (!skb)
- break;
-
- cfhsi->ndev->stats.tx_errors++;
- cfhsi->ndev->stats.tx_dropped++;
- cfhsi_update_aggregation_stats(cfhsi, skb, -1);
- spin_unlock_bh(&cfhsi->lock);
- kfree_skb(skb);
- }
- cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
- if (!test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
- mod_timer(&cfhsi->inactivity_timer,
- jiffies + cfhsi->cfg.inactivity_timeout);
- spin_unlock_bh(&cfhsi->lock);
-}
-
-static int cfhsi_flush_fifo(struct cfhsi *cfhsi)
-{
- char buffer[32]; /* Any reasonable value */
- size_t fifo_occupancy;
- int ret;
-
- netdev_dbg(cfhsi->ndev, "%s.\n",
- __func__);
-
- do {
- ret = cfhsi->ops->cfhsi_fifo_occupancy(cfhsi->ops,
- &fifo_occupancy);
- if (ret) {
- netdev_warn(cfhsi->ndev,
- "%s: can't get FIFO occupancy: %d.\n",
- __func__, ret);
- break;
- } else if (!fifo_occupancy)
- /* No more data, exitting normally */
- break;
-
- fifo_occupancy = min(sizeof(buffer), fifo_occupancy);
- set_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits);
- ret = cfhsi->ops->cfhsi_rx(buffer, fifo_occupancy,
- cfhsi->ops);
- if (ret) {
- clear_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits);
- netdev_warn(cfhsi->ndev,
- "%s: can't read data: %d.\n",
- __func__, ret);
- break;
- }
-
- ret = 5 * HZ;
- ret = wait_event_interruptible_timeout(cfhsi->flush_fifo_wait,
- !test_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits), ret);
-
- if (ret < 0) {
- netdev_warn(cfhsi->ndev,
- "%s: can't wait for flush complete: %d.\n",
- __func__, ret);
- break;
- } else if (!ret) {
- ret = -ETIMEDOUT;
- netdev_warn(cfhsi->ndev,
- "%s: timeout waiting for flush complete.\n",
- __func__);
- break;
- }
- } while (1);
-
- return ret;
-}
-
-static int cfhsi_tx_frm(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
-{
- int nfrms = 0;
- int pld_len = 0;
- struct sk_buff *skb;
- u8 *pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ;
-
- skb = cfhsi_dequeue(cfhsi);
- if (!skb)
- return 0;
-
- /* Clear offset. */
- desc->offset = 0;
-
- /* Check if we can embed a CAIF frame. */
- if (skb->len < CFHSI_MAX_EMB_FRM_SZ) {
- struct caif_payload_info *info;
- int hpad;
- int tpad;
-
- /* Calculate needed head alignment and tail alignment. */
- info = (struct caif_payload_info *)&skb->cb;
-
- hpad = 1 + PAD_POW2((info->hdr_len + 1), cfhsi->cfg.head_align);
- tpad = PAD_POW2((skb->len + hpad), cfhsi->cfg.tail_align);
-
- /* Check if frame still fits with added alignment. */
- if ((skb->len + hpad + tpad) <= CFHSI_MAX_EMB_FRM_SZ) {
- u8 *pemb = desc->emb_frm;
- desc->offset = CFHSI_DESC_SHORT_SZ;
- *pemb = (u8)(hpad - 1);
- pemb += hpad;
-
- /* Update network statistics. */
- spin_lock_bh(&cfhsi->lock);
- cfhsi->ndev->stats.tx_packets++;
- cfhsi->ndev->stats.tx_bytes += skb->len;
- cfhsi_update_aggregation_stats(cfhsi, skb, -1);
- spin_unlock_bh(&cfhsi->lock);
-
- /* Copy in embedded CAIF frame. */
- skb_copy_bits(skb, 0, pemb, skb->len);
-
- /* Consume the SKB */
- consume_skb(skb);
- skb = NULL;
- }
- }
-
- /* Create payload CAIF frames. */
- while (nfrms < CFHSI_MAX_PKTS) {
- struct caif_payload_info *info;
- int hpad;
- int tpad;
-
- if (!skb)
- skb = cfhsi_dequeue(cfhsi);
-
- if (!skb)
- break;
-
- /* Calculate needed head alignment and tail alignment. */
- info = (struct caif_payload_info *)&skb->cb;
-
- hpad = 1 + PAD_POW2((info->hdr_len + 1), cfhsi->cfg.head_align);
- tpad = PAD_POW2((skb->len + hpad), cfhsi->cfg.tail_align);
-
- /* Fill in CAIF frame length in descriptor. */
- desc->cffrm_len[nfrms] = hpad + skb->len + tpad;
-
- /* Fill head padding information. */
- *pfrm = (u8)(hpad - 1);
- pfrm += hpad;
-
- /* Update network statistics. */
- spin_lock_bh(&cfhsi->lock);
- cfhsi->ndev->stats.tx_packets++;
- cfhsi->ndev->stats.tx_bytes += skb->len;
- cfhsi_update_aggregation_stats(cfhsi, skb, -1);
- spin_unlock_bh(&cfhsi->lock);
-
- /* Copy in CAIF frame. */
- skb_copy_bits(skb, 0, pfrm, skb->len);
-
- /* Update payload length. */
- pld_len += desc->cffrm_len[nfrms];
-
- /* Update frame pointer. */
- pfrm += skb->len + tpad;
-
- /* Consume the SKB */
- consume_skb(skb);
- skb = NULL;
-
- /* Update number of frames. */
- nfrms++;
- }
-
- /* Unused length fields should be zero-filled (according to SPEC). */
- while (nfrms < CFHSI_MAX_PKTS) {
- desc->cffrm_len[nfrms] = 0x0000;
- nfrms++;
- }
-
- /* Check if we can piggy-back another descriptor. */
- if (cfhsi_can_send_aggregate(cfhsi))
- desc->header |= CFHSI_PIGGY_DESC;
- else
- desc->header &= ~CFHSI_PIGGY_DESC;
-
- return CFHSI_DESC_SZ + pld_len;
-}
-
-static void cfhsi_start_tx(struct cfhsi *cfhsi)
-{
- struct cfhsi_desc *desc = (struct cfhsi_desc *)cfhsi->tx_buf;
- int len, res;
-
- netdev_dbg(cfhsi->ndev, "%s.\n", __func__);
-
- if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
- return;
-
- do {
- /* Create HSI frame. */
- len = cfhsi_tx_frm(desc, cfhsi);
- if (!len) {
- spin_lock_bh(&cfhsi->lock);
- if (unlikely(cfhsi_tx_queue_len(cfhsi))) {
- spin_unlock_bh(&cfhsi->lock);
- res = -EAGAIN;
- continue;
- }
- cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
- /* Start inactivity timer. */
- mod_timer(&cfhsi->inactivity_timer,
- jiffies + cfhsi->cfg.inactivity_timeout);
- spin_unlock_bh(&cfhsi->lock);
- break;
- }
-
- /* Set up new transfer. */
- res = cfhsi->ops->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->ops);
- if (WARN_ON(res < 0))
- netdev_err(cfhsi->ndev, "%s: TX error %d.\n",
- __func__, res);
- } while (res < 0);
-}
-
-static void cfhsi_tx_done(struct cfhsi *cfhsi)
-{
- netdev_dbg(cfhsi->ndev, "%s.\n", __func__);
-
- if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
- return;
-
- /*
- * Send flow on if flow off has been previously signalled
- * and number of packets is below low water mark.
- */
- spin_lock_bh(&cfhsi->lock);
- if (cfhsi->flow_off_sent &&
- cfhsi_tx_queue_len(cfhsi) <= cfhsi->cfg.q_low_mark &&
- cfhsi->cfdev.flowctrl) {
-
- cfhsi->flow_off_sent = 0;
- cfhsi->cfdev.flowctrl(cfhsi->ndev, ON);
- }
-
- if (cfhsi_can_send_aggregate(cfhsi)) {
- spin_unlock_bh(&cfhsi->lock);
- cfhsi_start_tx(cfhsi);
- } else {
- mod_timer(&cfhsi->aggregation_timer,
- jiffies + cfhsi->cfg.aggregation_timeout);
- spin_unlock_bh(&cfhsi->lock);
- }
-
- return;
-}
-
-static void cfhsi_tx_done_cb(struct cfhsi_cb_ops *cb_ops)
-{
- struct cfhsi *cfhsi;
-
- cfhsi = container_of(cb_ops, struct cfhsi, cb_ops);
- netdev_dbg(cfhsi->ndev, "%s.\n",
- __func__);
-
- if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
- return;
- cfhsi_tx_done(cfhsi);
-}
-
-static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
-{
- int xfer_sz = 0;
- int nfrms = 0;
- u16 *plen = NULL;
- u8 *pfrm = NULL;
-
- if ((desc->header & ~CFHSI_PIGGY_DESC) ||
- (desc->offset > CFHSI_MAX_EMB_FRM_SZ)) {
- netdev_err(cfhsi->ndev, "%s: Invalid descriptor.\n",
- __func__);
- return -EPROTO;
- }
-
- /* Check for embedded CAIF frame. */
- if (desc->offset) {
- struct sk_buff *skb;
- int len = 0;
- pfrm = ((u8 *)desc) + desc->offset;
-
- /* Remove offset padding. */
- pfrm += *pfrm + 1;
-
- /* Read length of CAIF frame (little endian). */
- len = *pfrm;
- len |= ((*(pfrm+1)) << 8) & 0xFF00;
- len += 2; /* Add FCS fields. */
-
- /* Sanity check length of CAIF frame. */
- if (unlikely(len > CFHSI_MAX_CAIF_FRAME_SZ)) {
- netdev_err(cfhsi->ndev, "%s: Invalid length.\n",
- __func__);
- return -EPROTO;
- }
-
- /* Allocate SKB (OK even in IRQ context). */
- skb = alloc_skb(len + 1, GFP_ATOMIC);
- if (!skb) {
- netdev_err(cfhsi->ndev, "%s: Out of memory !\n",
- __func__);
- return -ENOMEM;
- }
- caif_assert(skb != NULL);
-
- skb_put_data(skb, pfrm, len);
-
- skb->protocol = htons(ETH_P_CAIF);
- skb_reset_mac_header(skb);
- skb->dev = cfhsi->ndev;
-
- netif_rx_any_context(skb);
-
- /* Update network statistics. */
- cfhsi->ndev->stats.rx_packets++;
- cfhsi->ndev->stats.rx_bytes += len;
- }
-
- /* Calculate transfer length. */
- plen = desc->cffrm_len;
- while (nfrms < CFHSI_MAX_PKTS && *plen) {
- xfer_sz += *plen;
- plen++;
- nfrms++;
- }
-
- /* Check for piggy-backed descriptor. */
- if (desc->header & CFHSI_PIGGY_DESC)
- xfer_sz += CFHSI_DESC_SZ;
-
- if ((xfer_sz % 4) || (xfer_sz > (CFHSI_BUF_SZ_RX - CFHSI_DESC_SZ))) {
- netdev_err(cfhsi->ndev,
- "%s: Invalid payload len: %d, ignored.\n",
- __func__, xfer_sz);
- return -EPROTO;
- }
- return xfer_sz;
-}
-
-static int cfhsi_rx_desc_len(struct cfhsi_desc *desc)
-{
- int xfer_sz = 0;
- int nfrms = 0;
- u16 *plen;
-
- if ((desc->header & ~CFHSI_PIGGY_DESC) ||
- (desc->offset > CFHSI_MAX_EMB_FRM_SZ)) {
-
- pr_err("Invalid descriptor. %x %x\n", desc->header,
- desc->offset);
- return -EPROTO;
- }
-
- /* Calculate transfer length. */
- plen = desc->cffrm_len;
- while (nfrms < CFHSI_MAX_PKTS && *plen) {
- xfer_sz += *plen;
- plen++;
- nfrms++;
- }
-
- if (xfer_sz % 4) {
- pr_err("Invalid payload len: %d, ignored.\n", xfer_sz);
- return -EPROTO;
- }
- return xfer_sz;
-}
-
-static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
-{
- int rx_sz = 0;
- int nfrms = 0;
- u16 *plen = NULL;
- u8 *pfrm = NULL;
-
- /* Sanity check header and offset. */
- if (WARN_ON((desc->header & ~CFHSI_PIGGY_DESC) ||
- (desc->offset > CFHSI_MAX_EMB_FRM_SZ))) {
- netdev_err(cfhsi->ndev, "%s: Invalid descriptor.\n",
- __func__);
- return -EPROTO;
- }
-
- /* Set frame pointer to start of payload. */
- pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ;
- plen = desc->cffrm_len;
-
- /* Skip already processed frames. */
- while (nfrms < cfhsi->rx_state.nfrms) {
- pfrm += *plen;
- rx_sz += *plen;
- plen++;
- nfrms++;
- }
-
- /* Parse payload. */
- while (nfrms < CFHSI_MAX_PKTS && *plen) {
- struct sk_buff *skb;
- u8 *pcffrm = NULL;
- int len;
-
- /* CAIF frame starts after head padding. */
- pcffrm = pfrm + *pfrm + 1;
-
- /* Read length of CAIF frame (little endian). */
- len = *pcffrm;
- len |= ((*(pcffrm + 1)) << 8) & 0xFF00;
- len += 2; /* Add FCS fields. */
-
- /* Sanity check length of CAIF frames. */
- if (unlikely(len > CFHSI_MAX_CAIF_FRAME_SZ)) {
- netdev_err(cfhsi->ndev, "%s: Invalid length.\n",
- __func__);
- return -EPROTO;
- }
-
- /* Allocate SKB (OK even in IRQ context). */
- skb = alloc_skb(len + 1, GFP_ATOMIC);
- if (!skb) {
- netdev_err(cfhsi->ndev, "%s: Out of memory !\n",
- __func__);
- cfhsi->rx_state.nfrms = nfrms;
- return -ENOMEM;
- }
- caif_assert(skb != NULL);
-
- skb_put_data(skb, pcffrm, len);
-
- skb->protocol = htons(ETH_P_CAIF);
- skb_reset_mac_header(skb);
- skb->dev = cfhsi->ndev;
-
- netif_rx_any_context(skb);
-
- /* Update network statistics. */
- cfhsi->ndev->stats.rx_packets++;
- cfhsi->ndev->stats.rx_bytes += len;
-
- pfrm += *plen;
- rx_sz += *plen;
- plen++;
- nfrms++;
- }
-
- return rx_sz;
-}
-
-static void cfhsi_rx_done(struct cfhsi *cfhsi)
-{
- int res;
- int desc_pld_len = 0, rx_len, rx_state;
- struct cfhsi_desc *desc = NULL;
- u8 *rx_ptr, *rx_buf;
- struct cfhsi_desc *piggy_desc = NULL;
-
- desc = (struct cfhsi_desc *)cfhsi->rx_buf;
-
- netdev_dbg(cfhsi->ndev, "%s\n", __func__);
-
- if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
- return;
-
- /* Update inactivity timer if pending. */
- spin_lock_bh(&cfhsi->lock);
- mod_timer_pending(&cfhsi->inactivity_timer,
- jiffies + cfhsi->cfg.inactivity_timeout);
- spin_unlock_bh(&cfhsi->lock);
-
- if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) {
- desc_pld_len = cfhsi_rx_desc_len(desc);
-
- if (desc_pld_len < 0)
- goto out_of_sync;
-
- rx_buf = cfhsi->rx_buf;
- rx_len = desc_pld_len;
- if (desc_pld_len > 0 && (desc->header & CFHSI_PIGGY_DESC))
- rx_len += CFHSI_DESC_SZ;
- if (desc_pld_len == 0)
- rx_buf = cfhsi->rx_flip_buf;
- } else {
- rx_buf = cfhsi->rx_flip_buf;
-
- rx_len = CFHSI_DESC_SZ;
- if (cfhsi->rx_state.pld_len > 0 &&
- (desc->header & CFHSI_PIGGY_DESC)) {
-
- piggy_desc = (struct cfhsi_desc *)
- (desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ +
- cfhsi->rx_state.pld_len);
-
- cfhsi->rx_state.piggy_desc = true;
-
- /* Extract payload len from piggy-backed descriptor. */
- desc_pld_len = cfhsi_rx_desc_len(piggy_desc);
- if (desc_pld_len < 0)
- goto out_of_sync;
-
- if (desc_pld_len > 0) {
- rx_len = desc_pld_len;
- if (piggy_desc->header & CFHSI_PIGGY_DESC)
- rx_len += CFHSI_DESC_SZ;
- }
-
- /*
- * Copy needed information from the piggy-backed
- * descriptor to the descriptor in the start.
- */
- memcpy(rx_buf, (u8 *)piggy_desc,
- CFHSI_DESC_SHORT_SZ);
- }
- }
-
- if (desc_pld_len) {
- rx_state = CFHSI_RX_STATE_PAYLOAD;
- rx_ptr = rx_buf + CFHSI_DESC_SZ;
- } else {
- rx_state = CFHSI_RX_STATE_DESC;
- rx_ptr = rx_buf;
- rx_len = CFHSI_DESC_SZ;
- }
-
- /* Initiate next read */
- if (test_bit(CFHSI_AWAKE, &cfhsi->bits)) {
- /* Set up new transfer. */
- netdev_dbg(cfhsi->ndev, "%s: Start RX.\n",
- __func__);
-
- res = cfhsi->ops->cfhsi_rx(rx_ptr, rx_len,
- cfhsi->ops);
- if (WARN_ON(res < 0)) {
- netdev_err(cfhsi->ndev, "%s: RX error %d.\n",
- __func__, res);
- cfhsi->ndev->stats.rx_errors++;
- cfhsi->ndev->stats.rx_dropped++;
- }
- }
-
- if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) {
- /* Extract payload from descriptor */
- if (cfhsi_rx_desc(desc, cfhsi) < 0)
- goto out_of_sync;
- } else {
- /* Extract payload */
- if (cfhsi_rx_pld(desc, cfhsi) < 0)
- goto out_of_sync;
- if (piggy_desc) {
- /* Extract any payload in piggyback descriptor. */
- if (cfhsi_rx_desc(piggy_desc, cfhsi) < 0)
- goto out_of_sync;
- /* Mark no embedded frame after extracting it */
- piggy_desc->offset = 0;
- }
- }
-
- /* Update state info */
- memset(&cfhsi->rx_state, 0, sizeof(cfhsi->rx_state));
- cfhsi->rx_state.state = rx_state;
- cfhsi->rx_ptr = rx_ptr;
- cfhsi->rx_len = rx_len;
- cfhsi->rx_state.pld_len = desc_pld_len;
- cfhsi->rx_state.piggy_desc = desc->header & CFHSI_PIGGY_DESC;
-
- if (rx_buf != cfhsi->rx_buf)
- swap(cfhsi->rx_buf, cfhsi->rx_flip_buf);
- return;
-
-out_of_sync:
- netdev_err(cfhsi->ndev, "%s: Out of sync.\n", __func__);
- print_hex_dump_bytes("--> ", DUMP_PREFIX_NONE,
- cfhsi->rx_buf, CFHSI_DESC_SZ);
- schedule_work(&cfhsi->out_of_sync_work);
-}
-
-static void cfhsi_rx_slowpath(struct timer_list *t)
-{
- struct cfhsi *cfhsi = from_timer(cfhsi, t, rx_slowpath_timer);
-
- netdev_dbg(cfhsi->ndev, "%s.\n",
- __func__);
-
- cfhsi_rx_done(cfhsi);
-}
-
-static void cfhsi_rx_done_cb(struct cfhsi_cb_ops *cb_ops)
-{
- struct cfhsi *cfhsi;
-
- cfhsi = container_of(cb_ops, struct cfhsi, cb_ops);
- netdev_dbg(cfhsi->ndev, "%s.\n",
- __func__);
-
- if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
- return;
-
- if (test_and_clear_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits))
- wake_up_interruptible(&cfhsi->flush_fifo_wait);
- else
- cfhsi_rx_done(cfhsi);
-}
-
-static void cfhsi_wake_up(struct work_struct *work)
-{
- struct cfhsi *cfhsi = NULL;
- int res;
- int len;
- long ret;
-
- cfhsi = container_of(work, struct cfhsi, wake_up_work);
-
- if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
- return;
-
- if (unlikely(test_bit(CFHSI_AWAKE, &cfhsi->bits))) {
- /* It happenes when wakeup is requested by
- * both ends at the same time. */
- clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
- clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
- return;
- }
-
- /* Activate wake line. */
- cfhsi->ops->cfhsi_wake_up(cfhsi->ops);
-
- netdev_dbg(cfhsi->ndev, "%s: Start waiting.\n",
- __func__);
-
- /* Wait for acknowledge. */
- ret = CFHSI_WAKE_TOUT;
- ret = wait_event_interruptible_timeout(cfhsi->wake_up_wait,
- test_and_clear_bit(CFHSI_WAKE_UP_ACK,
- &cfhsi->bits), ret);
- if (unlikely(ret < 0)) {
- /* Interrupted by signal. */
- netdev_err(cfhsi->ndev, "%s: Signalled: %ld.\n",
- __func__, ret);
-
- clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
- cfhsi->ops->cfhsi_wake_down(cfhsi->ops);
- return;
- } else if (!ret) {
- bool ca_wake = false;
- size_t fifo_occupancy = 0;
-
- /* Wakeup timeout */
- netdev_dbg(cfhsi->ndev, "%s: Timeout.\n",
- __func__);
-
- /* Check FIFO to check if modem has sent something. */
- WARN_ON(cfhsi->ops->cfhsi_fifo_occupancy(cfhsi->ops,
- &fifo_occupancy));
-
- netdev_dbg(cfhsi->ndev, "%s: Bytes in FIFO: %u.\n",
- __func__, (unsigned) fifo_occupancy);
-
- /* Check if we misssed the interrupt. */
- WARN_ON(cfhsi->ops->cfhsi_get_peer_wake(cfhsi->ops,
- &ca_wake));
-
- if (ca_wake) {
- netdev_err(cfhsi->ndev, "%s: CA Wake missed !.\n",
- __func__);
-
- /* Clear the CFHSI_WAKE_UP_ACK bit to prevent race. */
- clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
-
- /* Continue execution. */
- goto wake_ack;
- }
-
- clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
- cfhsi->ops->cfhsi_wake_down(cfhsi->ops);
- return;
- }
-wake_ack:
- netdev_dbg(cfhsi->ndev, "%s: Woken.\n",
- __func__);
-
- /* Clear power up bit. */
- set_bit(CFHSI_AWAKE, &cfhsi->bits);
- clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
-
- /* Resume read operation. */
- netdev_dbg(cfhsi->ndev, "%s: Start RX.\n", __func__);
- res = cfhsi->ops->cfhsi_rx(cfhsi->rx_ptr, cfhsi->rx_len, cfhsi->ops);
-
- if (WARN_ON(res < 0))
- netdev_err(cfhsi->ndev, "%s: RX err %d.\n", __func__, res);
-
- /* Clear power up acknowledment. */
- clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
-
- spin_lock_bh(&cfhsi->lock);
-
- /* Resume transmit if queues are not empty. */
- if (!cfhsi_tx_queue_len(cfhsi)) {
- netdev_dbg(cfhsi->ndev, "%s: Peer wake, start timer.\n",
- __func__);
- /* Start inactivity timer. */
- mod_timer(&cfhsi->inactivity_timer,
- jiffies + cfhsi->cfg.inactivity_timeout);
- spin_unlock_bh(&cfhsi->lock);
- return;
- }
-
- netdev_dbg(cfhsi->ndev, "%s: Host wake.\n",
- __func__);
-
- spin_unlock_bh(&cfhsi->lock);
-
- /* Create HSI frame. */
- len = cfhsi_tx_frm((struct cfhsi_desc *)cfhsi->tx_buf, cfhsi);
-
- if (likely(len > 0)) {
- /* Set up new transfer. */
- res = cfhsi->ops->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->ops);
- if (WARN_ON(res < 0)) {
- netdev_err(cfhsi->ndev, "%s: TX error %d.\n",
- __func__, res);
- cfhsi_abort_tx(cfhsi);
- }
- } else {
- netdev_err(cfhsi->ndev,
- "%s: Failed to create HSI frame: %d.\n",
- __func__, len);
- }
-}
-
-static void cfhsi_wake_down(struct work_struct *work)
-{
- long ret;
- struct cfhsi *cfhsi = NULL;
- size_t fifo_occupancy = 0;
- int retry = CFHSI_WAKE_TOUT;
-
- cfhsi = container_of(work, struct cfhsi, wake_down_work);
- netdev_dbg(cfhsi->ndev, "%s.\n", __func__);
-
- if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
- return;
-
- /* Deactivate wake line. */
- cfhsi->ops->cfhsi_wake_down(cfhsi->ops);
-
- /* Wait for acknowledge. */
- ret = CFHSI_WAKE_TOUT;
- ret = wait_event_interruptible_timeout(cfhsi->wake_down_wait,
- test_and_clear_bit(CFHSI_WAKE_DOWN_ACK,
- &cfhsi->bits), ret);
- if (ret < 0) {
- /* Interrupted by signal. */
- netdev_err(cfhsi->ndev, "%s: Signalled: %ld.\n",
- __func__, ret);
- return;
- } else if (!ret) {
- bool ca_wake = true;
-
- /* Timeout */
- netdev_err(cfhsi->ndev, "%s: Timeout.\n", __func__);
-
- /* Check if we misssed the interrupt. */
- WARN_ON(cfhsi->ops->cfhsi_get_peer_wake(cfhsi->ops,
- &ca_wake));
- if (!ca_wake)
- netdev_err(cfhsi->ndev, "%s: CA Wake missed !.\n",
- __func__);
- }
-
- /* Check FIFO occupancy. */
- while (retry) {
- WARN_ON(cfhsi->ops->cfhsi_fifo_occupancy(cfhsi->ops,
- &fifo_occupancy));
-
- if (!fifo_occupancy)
- break;
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
- retry--;
- }
-
- if (!retry)
- netdev_err(cfhsi->ndev, "%s: FIFO Timeout.\n", __func__);
-
- /* Clear AWAKE condition. */
- clear_bit(CFHSI_AWAKE, &cfhsi->bits);
-
- /* Cancel pending RX requests. */
- cfhsi->ops->cfhsi_rx_cancel(cfhsi->ops);
-}
-
-static void cfhsi_out_of_sync(struct work_struct *work)
-{
- struct cfhsi *cfhsi = NULL;
-
- cfhsi = container_of(work, struct cfhsi, out_of_sync_work);
-
- rtnl_lock();
- dev_close(cfhsi->ndev);
- rtnl_unlock();
-}
-
-static void cfhsi_wake_up_cb(struct cfhsi_cb_ops *cb_ops)
-{
- struct cfhsi *cfhsi = NULL;
-
- cfhsi = container_of(cb_ops, struct cfhsi, cb_ops);
- netdev_dbg(cfhsi->ndev, "%s.\n",
- __func__);
-
- set_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
- wake_up_interruptible(&cfhsi->wake_up_wait);
-
- if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
- return;
-
- /* Schedule wake up work queue if the peer initiates. */
- if (!test_and_set_bit(CFHSI_WAKE_UP, &cfhsi->bits))
- queue_work(cfhsi->wq, &cfhsi->wake_up_work);
-}
-
-static void cfhsi_wake_down_cb(struct cfhsi_cb_ops *cb_ops)
-{
- struct cfhsi *cfhsi = NULL;
-
- cfhsi = container_of(cb_ops, struct cfhsi, cb_ops);
- netdev_dbg(cfhsi->ndev, "%s.\n",
- __func__);
-
- /* Initiating low power is only permitted by the host (us). */
- set_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits);
- wake_up_interruptible(&cfhsi->wake_down_wait);
-}
-
-static void cfhsi_aggregation_tout(struct timer_list *t)
-{
- struct cfhsi *cfhsi = from_timer(cfhsi, t, aggregation_timer);
-
- netdev_dbg(cfhsi->ndev, "%s.\n",
- __func__);
-
- cfhsi_start_tx(cfhsi);
-}
-
-static netdev_tx_t cfhsi_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct cfhsi *cfhsi = NULL;
- int start_xfer = 0;
- int timer_active;
- int prio;
-
- if (!dev)
- return -EINVAL;
-
- cfhsi = netdev_priv(dev);
-
- switch (skb->priority) {
- case TC_PRIO_BESTEFFORT:
- case TC_PRIO_FILLER:
- case TC_PRIO_BULK:
- prio = CFHSI_PRIO_BEBK;
- break;
- case TC_PRIO_INTERACTIVE_BULK:
- prio = CFHSI_PRIO_VI;
- break;
- case TC_PRIO_INTERACTIVE:
- prio = CFHSI_PRIO_VO;
- break;
- case TC_PRIO_CONTROL:
- default:
- prio = CFHSI_PRIO_CTL;
- break;
- }
-
- spin_lock_bh(&cfhsi->lock);
-
- /* Update aggregation statistics */
- cfhsi_update_aggregation_stats(cfhsi, skb, 1);
-
- /* Queue the SKB */
- skb_queue_tail(&cfhsi->qhead[prio], skb);
-
- /* Sanity check; xmit should not be called after unregister_netdev */
- if (WARN_ON(test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))) {
- spin_unlock_bh(&cfhsi->lock);
- cfhsi_abort_tx(cfhsi);
- return -EINVAL;
- }
-
- /* Send flow off if number of packets is above high water mark. */
- if (!cfhsi->flow_off_sent &&
- cfhsi_tx_queue_len(cfhsi) > cfhsi->cfg.q_high_mark &&
- cfhsi->cfdev.flowctrl) {
- cfhsi->flow_off_sent = 1;
- cfhsi->cfdev.flowctrl(cfhsi->ndev, OFF);
- }
-
- if (cfhsi->tx_state == CFHSI_TX_STATE_IDLE) {
- cfhsi->tx_state = CFHSI_TX_STATE_XFER;
- start_xfer = 1;
- }
-
- if (!start_xfer) {
- /* Send aggregate if it is possible */
- bool aggregate_ready =
- cfhsi_can_send_aggregate(cfhsi) &&
- del_timer(&cfhsi->aggregation_timer) > 0;
- spin_unlock_bh(&cfhsi->lock);
- if (aggregate_ready)
- cfhsi_start_tx(cfhsi);
- return NETDEV_TX_OK;
- }
-
- /* Delete inactivity timer if started. */
- timer_active = del_timer_sync(&cfhsi->inactivity_timer);
-
- spin_unlock_bh(&cfhsi->lock);
-
- if (timer_active) {
- struct cfhsi_desc *desc = (struct cfhsi_desc *)cfhsi->tx_buf;
- int len;
- int res;
-
- /* Create HSI frame. */
- len = cfhsi_tx_frm(desc, cfhsi);
- WARN_ON(!len);
-
- /* Set up new transfer. */
- res = cfhsi->ops->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->ops);
- if (WARN_ON(res < 0)) {
- netdev_err(cfhsi->ndev, "%s: TX error %d.\n",
- __func__, res);
- cfhsi_abort_tx(cfhsi);
- }
- } else {
- /* Schedule wake up work queue if the we initiate. */
- if (!test_and_set_bit(CFHSI_WAKE_UP, &cfhsi->bits))
- queue_work(cfhsi->wq, &cfhsi->wake_up_work);
- }
-
- return NETDEV_TX_OK;
-}
-
-static const struct net_device_ops cfhsi_netdevops;
-
-static void cfhsi_setup(struct net_device *dev)
-{
- int i;
- struct cfhsi *cfhsi = netdev_priv(dev);
- dev->features = 0;
- dev->type = ARPHRD_CAIF;
- dev->flags = IFF_POINTOPOINT | IFF_NOARP;
- dev->mtu = CFHSI_MAX_CAIF_FRAME_SZ;
- dev->priv_flags |= IFF_NO_QUEUE;
- dev->needs_free_netdev = true;
- dev->netdev_ops = &cfhsi_netdevops;
- for (i = 0; i < CFHSI_PRIO_LAST; ++i)
- skb_queue_head_init(&cfhsi->qhead[i]);
- cfhsi->cfdev.link_select = CAIF_LINK_HIGH_BANDW;
- cfhsi->cfdev.use_frag = false;
- cfhsi->cfdev.use_stx = false;
- cfhsi->cfdev.use_fcs = false;
- cfhsi->ndev = dev;
- cfhsi->cfg = hsi_default_config;
-}
-
-static int cfhsi_open(struct net_device *ndev)
-{
- struct cfhsi *cfhsi = netdev_priv(ndev);
- int res;
-
- clear_bit(CFHSI_SHUTDOWN, &cfhsi->bits);
-
- /* Initialize state vaiables. */
- cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
- cfhsi->rx_state.state = CFHSI_RX_STATE_DESC;
-
- /* Set flow info */
- cfhsi->flow_off_sent = 0;
-
- /*
- * Allocate a TX buffer with the size of a HSI packet descriptors
- * and the necessary room for CAIF payload frames.
- */
- cfhsi->tx_buf = kzalloc(CFHSI_BUF_SZ_TX, GFP_KERNEL);
- if (!cfhsi->tx_buf) {
- res = -ENODEV;
- goto err_alloc_tx;
- }
-
- /*
- * Allocate a RX buffer with the size of two HSI packet descriptors and
- * the necessary room for CAIF payload frames.
- */
- cfhsi->rx_buf = kzalloc(CFHSI_BUF_SZ_RX, GFP_KERNEL);
- if (!cfhsi->rx_buf) {
- res = -ENODEV;
- goto err_alloc_rx;
- }
-
- cfhsi->rx_flip_buf = kzalloc(CFHSI_BUF_SZ_RX, GFP_KERNEL);
- if (!cfhsi->rx_flip_buf) {
- res = -ENODEV;
- goto err_alloc_rx_flip;
- }
-
- /* Initialize aggregation timeout */
- cfhsi->cfg.aggregation_timeout = hsi_default_config.aggregation_timeout;
-
- /* Initialize recieve vaiables. */
- cfhsi->rx_ptr = cfhsi->rx_buf;
- cfhsi->rx_len = CFHSI_DESC_SZ;
-
- /* Initialize spin locks. */
- spin_lock_init(&cfhsi->lock);
-
- /* Set up the driver. */
- cfhsi->cb_ops.tx_done_cb = cfhsi_tx_done_cb;
- cfhsi->cb_ops.rx_done_cb = cfhsi_rx_done_cb;
- cfhsi->cb_ops.wake_up_cb = cfhsi_wake_up_cb;
- cfhsi->cb_ops.wake_down_cb = cfhsi_wake_down_cb;
-
- /* Initialize the work queues. */
- INIT_WORK(&cfhsi->wake_up_work, cfhsi_wake_up);
- INIT_WORK(&cfhsi->wake_down_work, cfhsi_wake_down);
- INIT_WORK(&cfhsi->out_of_sync_work, cfhsi_out_of_sync);
-
- /* Clear all bit fields. */
- clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
- clear_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits);
- clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
- clear_bit(CFHSI_AWAKE, &cfhsi->bits);
-
- /* Create work thread. */
- cfhsi->wq = alloc_ordered_workqueue(cfhsi->ndev->name, WQ_MEM_RECLAIM);
- if (!cfhsi->wq) {
- netdev_err(cfhsi->ndev, "%s: Failed to create work queue.\n",
- __func__);
- res = -ENODEV;
- goto err_create_wq;
- }
-
- /* Initialize wait queues. */
- init_waitqueue_head(&cfhsi->wake_up_wait);
- init_waitqueue_head(&cfhsi->wake_down_wait);
- init_waitqueue_head(&cfhsi->flush_fifo_wait);
-
- /* Setup the inactivity timer. */
- timer_setup(&cfhsi->inactivity_timer, cfhsi_inactivity_tout, 0);
- /* Setup the slowpath RX timer. */
- timer_setup(&cfhsi->rx_slowpath_timer, cfhsi_rx_slowpath, 0);
- /* Setup the aggregation timer. */
- timer_setup(&cfhsi->aggregation_timer, cfhsi_aggregation_tout, 0);
-
- /* Activate HSI interface. */
- res = cfhsi->ops->cfhsi_up(cfhsi->ops);
- if (res) {
- netdev_err(cfhsi->ndev,
- "%s: can't activate HSI interface: %d.\n",
- __func__, res);
- goto err_activate;
- }
-
- /* Flush FIFO */
- res = cfhsi_flush_fifo(cfhsi);
- if (res) {
- netdev_err(cfhsi->ndev, "%s: Can't flush FIFO: %d.\n",
- __func__, res);
- goto err_net_reg;
- }
- return res;
-
- err_net_reg:
- cfhsi->ops->cfhsi_down(cfhsi->ops);
- err_activate:
- destroy_workqueue(cfhsi->wq);
- err_create_wq:
- kfree(cfhsi->rx_flip_buf);
- err_alloc_rx_flip:
- kfree(cfhsi->rx_buf);
- err_alloc_rx:
- kfree(cfhsi->tx_buf);
- err_alloc_tx:
- return res;
-}
-
-static int cfhsi_close(struct net_device *ndev)
-{
- struct cfhsi *cfhsi = netdev_priv(ndev);
- u8 *tx_buf, *rx_buf, *flip_buf;
-
- /* going to shutdown driver */
- set_bit(CFHSI_SHUTDOWN, &cfhsi->bits);
-
- /* Delete timers if pending */
- del_timer_sync(&cfhsi->inactivity_timer);
- del_timer_sync(&cfhsi->rx_slowpath_timer);
- del_timer_sync(&cfhsi->aggregation_timer);
-
- /* Cancel pending RX request (if any) */
- cfhsi->ops->cfhsi_rx_cancel(cfhsi->ops);
-
- /* Destroy workqueue */
- destroy_workqueue(cfhsi->wq);
-
- /* Store bufferes: will be freed later. */
- tx_buf = cfhsi->tx_buf;
- rx_buf = cfhsi->rx_buf;
- flip_buf = cfhsi->rx_flip_buf;
- /* Flush transmit queues. */
- cfhsi_abort_tx(cfhsi);
-
- /* Deactivate interface */
- cfhsi->ops->cfhsi_down(cfhsi->ops);
-
- /* Free buffers. */
- kfree(tx_buf);
- kfree(rx_buf);
- kfree(flip_buf);
- return 0;
-}
-
-static void cfhsi_uninit(struct net_device *dev)
-{
- struct cfhsi *cfhsi = netdev_priv(dev);
- ASSERT_RTNL();
- symbol_put(cfhsi_get_device);
- list_del(&cfhsi->list);
-}
-
-static const struct net_device_ops cfhsi_netdevops = {
- .ndo_uninit = cfhsi_uninit,
- .ndo_open = cfhsi_open,
- .ndo_stop = cfhsi_close,
- .ndo_start_xmit = cfhsi_xmit
-};
-
-static void cfhsi_netlink_parms(struct nlattr *data[], struct cfhsi *cfhsi)
-{
- int i;
-
- if (!data) {
- pr_debug("no params data found\n");
- return;
- }
-
- i = __IFLA_CAIF_HSI_INACTIVITY_TOUT;
- /*
- * Inactivity timeout in millisecs. Lowest possible value is 1,
- * and highest possible is NEXT_TIMER_MAX_DELTA.
- */
- if (data[i]) {
- u32 inactivity_timeout = nla_get_u32(data[i]);
- /* Pre-calculate inactivity timeout. */
- cfhsi->cfg.inactivity_timeout = inactivity_timeout * HZ / 1000;
- if (cfhsi->cfg.inactivity_timeout == 0)
- cfhsi->cfg.inactivity_timeout = 1;
- else if (cfhsi->cfg.inactivity_timeout > NEXT_TIMER_MAX_DELTA)
- cfhsi->cfg.inactivity_timeout = NEXT_TIMER_MAX_DELTA;
- }
-
- i = __IFLA_CAIF_HSI_AGGREGATION_TOUT;
- if (data[i])
- cfhsi->cfg.aggregation_timeout = nla_get_u32(data[i]);
-
- i = __IFLA_CAIF_HSI_HEAD_ALIGN;
- if (data[i])
- cfhsi->cfg.head_align = nla_get_u32(data[i]);
-
- i = __IFLA_CAIF_HSI_TAIL_ALIGN;
- if (data[i])
- cfhsi->cfg.tail_align = nla_get_u32(data[i]);
-
- i = __IFLA_CAIF_HSI_QHIGH_WATERMARK;
- if (data[i])
- cfhsi->cfg.q_high_mark = nla_get_u32(data[i]);
-
- i = __IFLA_CAIF_HSI_QLOW_WATERMARK;
- if (data[i])
- cfhsi->cfg.q_low_mark = nla_get_u32(data[i]);
-}
-
-static int caif_hsi_changelink(struct net_device *dev, struct nlattr *tb[],
- struct nlattr *data[],
- struct netlink_ext_ack *extack)
-{
- cfhsi_netlink_parms(data, netdev_priv(dev));
- netdev_state_change(dev);
- return 0;
-}
-
-static const struct nla_policy caif_hsi_policy[__IFLA_CAIF_HSI_MAX + 1] = {
- [__IFLA_CAIF_HSI_INACTIVITY_TOUT] = { .type = NLA_U32, .len = 4 },
- [__IFLA_CAIF_HSI_AGGREGATION_TOUT] = { .type = NLA_U32, .len = 4 },
- [__IFLA_CAIF_HSI_HEAD_ALIGN] = { .type = NLA_U32, .len = 4 },
- [__IFLA_CAIF_HSI_TAIL_ALIGN] = { .type = NLA_U32, .len = 4 },
- [__IFLA_CAIF_HSI_QHIGH_WATERMARK] = { .type = NLA_U32, .len = 4 },
- [__IFLA_CAIF_HSI_QLOW_WATERMARK] = { .type = NLA_U32, .len = 4 },
-};
-
-static size_t caif_hsi_get_size(const struct net_device *dev)
-{
- int i;
- size_t s = 0;
- for (i = __IFLA_CAIF_HSI_UNSPEC + 1; i < __IFLA_CAIF_HSI_MAX; i++)
- s += nla_total_size(caif_hsi_policy[i].len);
- return s;
-}
-
-static int caif_hsi_fill_info(struct sk_buff *skb, const struct net_device *dev)
-{
- struct cfhsi *cfhsi = netdev_priv(dev);
-
- if (nla_put_u32(skb, __IFLA_CAIF_HSI_INACTIVITY_TOUT,
- cfhsi->cfg.inactivity_timeout) ||
- nla_put_u32(skb, __IFLA_CAIF_HSI_AGGREGATION_TOUT,
- cfhsi->cfg.aggregation_timeout) ||
- nla_put_u32(skb, __IFLA_CAIF_HSI_HEAD_ALIGN,
- cfhsi->cfg.head_align) ||
- nla_put_u32(skb, __IFLA_CAIF_HSI_TAIL_ALIGN,
- cfhsi->cfg.tail_align) ||
- nla_put_u32(skb, __IFLA_CAIF_HSI_QHIGH_WATERMARK,
- cfhsi->cfg.q_high_mark) ||
- nla_put_u32(skb, __IFLA_CAIF_HSI_QLOW_WATERMARK,
- cfhsi->cfg.q_low_mark))
- return -EMSGSIZE;
-
- return 0;
-}
-
-static int caif_hsi_newlink(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[],
- struct netlink_ext_ack *extack)
-{
- struct cfhsi *cfhsi = NULL;
- struct cfhsi_ops *(*get_ops)(void);
-
- ASSERT_RTNL();
-
- cfhsi = netdev_priv(dev);
- cfhsi_netlink_parms(data, cfhsi);
-
- get_ops = symbol_get(cfhsi_get_ops);
- if (!get_ops) {
- pr_err("%s: failed to get the cfhsi_ops\n", __func__);
- return -ENODEV;
- }
-
- /* Assign the HSI device. */
- cfhsi->ops = (*get_ops)();
- if (!cfhsi->ops) {
- pr_err("%s: failed to get the cfhsi_ops\n", __func__);
- goto err;
- }
-
- /* Assign the driver to this HSI device. */
- cfhsi->ops->cb_ops = &cfhsi->cb_ops;
- if (register_netdevice(dev)) {
- pr_warn("%s: caif_hsi device registration failed\n", __func__);
- goto err;
- }
- /* Add CAIF HSI device to list. */
- list_add_tail(&cfhsi->list, &cfhsi_list);
-
- return 0;
-err:
- symbol_put(cfhsi_get_ops);
- return -ENODEV;
-}
-
-static struct rtnl_link_ops caif_hsi_link_ops __read_mostly = {
- .kind = "cfhsi",
- .priv_size = sizeof(struct cfhsi),
- .setup = cfhsi_setup,
- .maxtype = __IFLA_CAIF_HSI_MAX,
- .policy = caif_hsi_policy,
- .newlink = caif_hsi_newlink,
- .changelink = caif_hsi_changelink,
- .get_size = caif_hsi_get_size,
- .fill_info = caif_hsi_fill_info,
-};
-
-static void __exit cfhsi_exit_module(void)
-{
- struct list_head *list_node;
- struct list_head *n;
- struct cfhsi *cfhsi;
-
- rtnl_link_unregister(&caif_hsi_link_ops);
-
- rtnl_lock();
- list_for_each_safe(list_node, n, &cfhsi_list) {
- cfhsi = list_entry(list_node, struct cfhsi, list);
- unregister_netdevice(cfhsi->ndev);
- }
- rtnl_unlock();
-}
-
-static int __init cfhsi_init_module(void)
-{
- return rtnl_link_register(&caif_hsi_link_ops);
-}
-
-module_init(cfhsi_init_module);
-module_exit(cfhsi_exit_module);
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
index 4ffbfd534f18..2a7af611d43a 100644
--- a/drivers/net/caif/caif_serial.c
+++ b/drivers/net/caif/caif_serial.c
@@ -87,9 +87,9 @@ static void ldisc_tx_wakeup(struct tty_struct *tty);
static inline void update_tty_status(struct ser_device *ser)
{
ser->tty_status =
- ser->tty->stopped << 5 |
- ser->tty->flow_stopped << 3 |
- ser->tty->packet << 2;
+ ser->tty->flow.stopped << 5 |
+ ser->tty->flow.tco_stopped << 3 |
+ ser->tty->ctrl.packet << 2;
}
static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
{
@@ -159,7 +159,7 @@ static inline void debugfs_tx(struct ser_device *ser, const u8 *data, int size)
#endif
static void ldisc_receive(struct tty_struct *tty, const u8 *data,
- char *flags, int count)
+ const char *flags, int count)
{
struct sk_buff *skb = NULL;
struct ser_device *ser;
@@ -380,6 +380,7 @@ static void ldisc_close(struct tty_struct *tty)
/* The line discipline structure. */
static struct tty_ldisc_ops caif_ldisc = {
.owner = THIS_MODULE,
+ .num = N_CAIF,
.name = "n_caif",
.open = ldisc_open,
.close = ldisc_close,
@@ -429,7 +430,7 @@ static int __init caif_ser_init(void)
{
int ret;
- ret = tty_register_ldisc(N_CAIF, &caif_ldisc);
+ ret = tty_register_ldisc(&caif_ldisc);
if (ret < 0)
pr_err("cannot register CAIF ldisc=%d err=%d\n", N_CAIF, ret);
@@ -444,7 +445,7 @@ static void __exit caif_ser_exit(void)
spin_unlock(&ser_lock);
ser_release(NULL);
cancel_work_sync(&ser_release_work);
- tty_unregister_ldisc(N_CAIF);
+ tty_unregister_ldisc(&caif_ldisc);
debugfs_remove_recursive(debugfsdir);
}
diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c
index 106f089eb2a8..91230894692d 100644
--- a/drivers/net/caif/caif_virtio.c
+++ b/drivers/net/caif/caif_virtio.c
@@ -315,7 +315,7 @@ exit:
case 0:
++cfv->stats.rx_napi_complete;
- /* Really out of patckets? (stolen from virtio_net)*/
+ /* Really out of packets? (stolen from virtio_net)*/
napi_complete(napi);
if (unlikely(!vringh_notify_enable_kern(cfv->vr_rx)) &&
napi_schedule_prep(napi)) {
@@ -463,7 +463,7 @@ static int cfv_netdev_close(struct net_device *netdev)
vringh_notify_disable_kern(cfv->vr_rx);
napi_disable(&cfv->napi);
- /* Release any TX buffers on both used and avilable rings */
+ /* Release any TX buffers on both used and available rings */
cfv_release_used_buf(cfv->vq_tx);
spin_lock_irqsave(&cfv->tx_lock, flags);
while ((buf_info = virtqueue_detach_unused_buf(cfv->vq_tx)))
@@ -497,7 +497,7 @@ static struct buf_info *cfv_alloc_and_copy_to_shm(struct cfv_info *cfv,
if (unlikely(!buf_info))
goto err;
- /* Make the IP header aligned in tbe buffer */
+ /* Make the IP header aligned in the buffer */
hdr_ofs = cfv->tx_hr + info->hdr_len;
pad_len = hdr_ofs & (IP_HDR_ALIGN - 1);
buf_info->size = cfv->tx_hr + skb->len + cfv->tx_tr + pad_len;
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index 9ad9b39f480e..04d0bb3ffe89 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -169,7 +169,7 @@ static const struct can_bittiming_const at91_bittiming_const = {
};
#define AT91_IS(_model) \
-static inline int at91_is_sam##_model(const struct at91_priv *priv) \
+static inline int __maybe_unused at91_is_sam##_model(const struct at91_priv *priv) \
{ \
return priv->devtype_data.type == AT91_DEVTYPE_SAM##_model; \
}
diff --git a/drivers/net/can/c_can/Makefile b/drivers/net/can/c_can/Makefile
index e6a94c948531..6fa3b2b9e4b9 100644
--- a/drivers/net/can/c_can/Makefile
+++ b/drivers/net/can/c_can/Makefile
@@ -4,5 +4,10 @@
#
obj-$(CONFIG_CAN_C_CAN) += c_can.o
+
+c_can-objs :=
+c_can-objs += c_can_ethtool.o
+c_can-objs += c_can_main.o
+
obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o
obj-$(CONFIG_CAN_C_CAN_PCI) += c_can_pci.o
diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h
index 06045f610f0e..4247ff80a29c 100644
--- a/drivers/net/can/c_can/c_can.h
+++ b/drivers/net/can/c_can/c_can.h
@@ -205,7 +205,6 @@ struct c_can_priv {
struct c_can_raminit raminit_sys; /* RAMINIT via syscon regmap */
void (*raminit)(const struct c_can_priv *priv, bool enable);
u32 comm_rcv_high;
- u32 rxmasked;
u32 dlc[];
};
@@ -219,4 +218,6 @@ int c_can_power_up(struct net_device *dev);
int c_can_power_down(struct net_device *dev);
#endif
+void c_can_set_ethtool_ops(struct net_device *dev);
+
#endif /* C_CAN_H */
diff --git a/drivers/net/can/c_can/c_can_ethtool.c b/drivers/net/can/c_can/c_can_ethtool.c
new file mode 100644
index 000000000000..cd5f07fca2a5
--- /dev/null
+++ b/drivers/net/can/c_can/c_can_ethtool.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2021, Dario Binacchi <dariobin@libero.it>
+ */
+
+#include <linux/ethtool.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/can/dev.h>
+
+#include "c_can.h"
+
+static void c_can_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *info)
+{
+ struct c_can_priv *priv = netdev_priv(netdev);
+ struct platform_device *pdev = to_platform_device(priv->device);
+
+ strscpy(info->driver, "c_can", sizeof(info->driver));
+ strscpy(info->bus_info, pdev->name, sizeof(info->bus_info));
+}
+
+static void c_can_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct c_can_priv *priv = netdev_priv(netdev);
+
+ ring->rx_max_pending = priv->msg_obj_num;
+ ring->tx_max_pending = priv->msg_obj_num;
+ ring->rx_pending = priv->msg_obj_rx_num;
+ ring->tx_pending = priv->msg_obj_tx_num;
+}
+
+static const struct ethtool_ops c_can_ethtool_ops = {
+ .get_drvinfo = c_can_get_drvinfo,
+ .get_ringparam = c_can_get_ringparam,
+};
+
+void c_can_set_ethtool_ops(struct net_device *netdev)
+{
+ netdev->ethtool_ops = &c_can_ethtool_ops;
+}
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can_main.c
index 313793f6922d..7588f70ca0fe 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can_main.c
@@ -599,7 +599,6 @@ static int c_can_chip_config(struct net_device *dev)
/* Clear all internal status */
atomic_set(&priv->tx_active, 0);
- priv->rxmasked = 0;
priv->tx_dir = 0;
/* set bittiming params */
@@ -1335,6 +1334,7 @@ int register_c_can_dev(struct net_device *dev)
dev->flags |= IFF_ECHO; /* we support local echo */
dev->netdev_ops = &c_can_netdev_ops;
+ c_can_set_ethtool_ops(dev);
err = register_candev(dev);
if (!err)
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index 3cf6de21d19c..bba2a449ac70 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -83,44 +83,25 @@ enum m_can_reg {
#define MRAM_CFG_LEN 8
/* Core Release Register (CREL) */
-#define CREL_REL_SHIFT 28
-#define CREL_REL_MASK (0xF << CREL_REL_SHIFT)
-#define CREL_STEP_SHIFT 24
-#define CREL_STEP_MASK (0xF << CREL_STEP_SHIFT)
-#define CREL_SUBSTEP_SHIFT 20
-#define CREL_SUBSTEP_MASK (0xF << CREL_SUBSTEP_SHIFT)
+#define CREL_REL_MASK GENMASK(31, 28)
+#define CREL_STEP_MASK GENMASK(27, 24)
+#define CREL_SUBSTEP_MASK GENMASK(23, 20)
/* Data Bit Timing & Prescaler Register (DBTP) */
#define DBTP_TDC BIT(23)
-#define DBTP_DBRP_SHIFT 16
-#define DBTP_DBRP_MASK (0x1f << DBTP_DBRP_SHIFT)
-#define DBTP_DTSEG1_SHIFT 8
-#define DBTP_DTSEG1_MASK (0x1f << DBTP_DTSEG1_SHIFT)
-#define DBTP_DTSEG2_SHIFT 4
-#define DBTP_DTSEG2_MASK (0xf << DBTP_DTSEG2_SHIFT)
-#define DBTP_DSJW_SHIFT 0
-#define DBTP_DSJW_MASK (0xf << DBTP_DSJW_SHIFT)
+#define DBTP_DBRP_MASK GENMASK(20, 16)
+#define DBTP_DTSEG1_MASK GENMASK(12, 8)
+#define DBTP_DTSEG2_MASK GENMASK(7, 4)
+#define DBTP_DSJW_MASK GENMASK(3, 0)
/* Transmitter Delay Compensation Register (TDCR) */
-#define TDCR_TDCO_SHIFT 8
-#define TDCR_TDCO_MASK (0x7F << TDCR_TDCO_SHIFT)
-#define TDCR_TDCF_SHIFT 0
-#define TDCR_TDCF_MASK (0x7F << TDCR_TDCF_SHIFT)
+#define TDCR_TDCO_MASK GENMASK(14, 8)
+#define TDCR_TDCF_MASK GENMASK(6, 0)
/* Test Register (TEST) */
#define TEST_LBCK BIT(4)
-/* CC Control Register(CCCR) */
-#define CCCR_CMR_MASK 0x3
-#define CCCR_CMR_SHIFT 10
-#define CCCR_CMR_CANFD 0x1
-#define CCCR_CMR_CANFD_BRS 0x2
-#define CCCR_CMR_CAN 0x3
-#define CCCR_CME_MASK 0x3
-#define CCCR_CME_SHIFT 8
-#define CCCR_CME_CAN 0
-#define CCCR_CME_CANFD 0x1
-#define CCCR_CME_CANFD_BRS 0x2
+/* CC Control Register (CCCR) */
#define CCCR_TXP BIT(14)
#define CCCR_TEST BIT(7)
#define CCCR_DAR BIT(6)
@@ -130,24 +111,31 @@ enum m_can_reg {
#define CCCR_ASM BIT(2)
#define CCCR_CCE BIT(1)
#define CCCR_INIT BIT(0)
-#define CCCR_CANFD 0x10
+/* for version 3.0.x */
+#define CCCR_CMR_MASK GENMASK(11, 10)
+#define CCCR_CMR_CANFD 0x1
+#define CCCR_CMR_CANFD_BRS 0x2
+#define CCCR_CMR_CAN 0x3
+#define CCCR_CME_MASK GENMASK(9, 8)
+#define CCCR_CME_CAN 0
+#define CCCR_CME_CANFD 0x1
+#define CCCR_CME_CANFD_BRS 0x2
/* for version >=3.1.x */
#define CCCR_EFBI BIT(13)
#define CCCR_PXHD BIT(12)
#define CCCR_BRSE BIT(9)
#define CCCR_FDOE BIT(8)
-/* only for version >=3.2.x */
+/* for version >=3.2.x */
#define CCCR_NISO BIT(15)
+/* for version >=3.3.x */
+#define CCCR_WMM BIT(11)
+#define CCCR_UTSU BIT(10)
/* Nominal Bit Timing & Prescaler Register (NBTP) */
-#define NBTP_NSJW_SHIFT 25
-#define NBTP_NSJW_MASK (0x7f << NBTP_NSJW_SHIFT)
-#define NBTP_NBRP_SHIFT 16
-#define NBTP_NBRP_MASK (0x1ff << NBTP_NBRP_SHIFT)
-#define NBTP_NTSEG1_SHIFT 8
-#define NBTP_NTSEG1_MASK (0xff << NBTP_NTSEG1_SHIFT)
-#define NBTP_NTSEG2_SHIFT 0
-#define NBTP_NTSEG2_MASK (0x7f << NBTP_NTSEG2_SHIFT)
+#define NBTP_NSJW_MASK GENMASK(31, 25)
+#define NBTP_NBRP_MASK GENMASK(24, 16)
+#define NBTP_NTSEG1_MASK GENMASK(15, 8)
+#define NBTP_NTSEG2_MASK GENMASK(6, 0)
/* Timestamp Counter Configuration Register (TSCC) */
#define TSCC_TCP_MASK GENMASK(19, 16)
@@ -159,20 +147,18 @@ enum m_can_reg {
/* Timestamp Counter Value Register (TSCV) */
#define TSCV_TSC_MASK GENMASK(15, 0)
-/* Error Counter Register(ECR) */
+/* Error Counter Register (ECR) */
#define ECR_RP BIT(15)
-#define ECR_REC_SHIFT 8
-#define ECR_REC_MASK (0x7f << ECR_REC_SHIFT)
-#define ECR_TEC_SHIFT 0
-#define ECR_TEC_MASK 0xff
+#define ECR_REC_MASK GENMASK(14, 8)
+#define ECR_TEC_MASK GENMASK(7, 0)
-/* Protocol Status Register(PSR) */
+/* Protocol Status Register (PSR) */
#define PSR_BO BIT(7)
#define PSR_EW BIT(6)
#define PSR_EP BIT(5)
-#define PSR_LEC_MASK 0x7
+#define PSR_LEC_MASK GENMASK(2, 0)
-/* Interrupt Register(IR) */
+/* Interrupt Register (IR) */
#define IR_ALL_INT 0xffffffff
/* Renamed bits for versions > 3.1.x */
@@ -221,6 +207,7 @@ enum m_can_reg {
IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \
IR_RF1L | IR_RF0L)
#define IR_ERR_ALL_30X (IR_ERR_STATE | IR_ERR_BUS_30X)
+
/* Interrupts for version >= 3.1.x */
#define IR_ERR_LEC_31X (IR_PED | IR_PEA)
#define IR_ERR_BUS_31X (IR_ERR_LEC_31X | IR_WDI | IR_ELO | IR_BEU | \
@@ -237,58 +224,47 @@ enum m_can_reg {
#define ILE_EINT0 BIT(0)
/* Rx FIFO 0/1 Configuration (RXF0C/RXF1C) */
-#define RXFC_FWM_SHIFT 24
-#define RXFC_FWM_MASK (0x7f << RXFC_FWM_SHIFT)
-#define RXFC_FS_SHIFT 16
-#define RXFC_FS_MASK (0x7f << RXFC_FS_SHIFT)
+#define RXFC_FWM_MASK GENMASK(30, 24)
+#define RXFC_FS_MASK GENMASK(22, 16)
/* Rx FIFO 0/1 Status (RXF0S/RXF1S) */
#define RXFS_RFL BIT(25)
#define RXFS_FF BIT(24)
-#define RXFS_FPI_SHIFT 16
-#define RXFS_FPI_MASK 0x3f0000
-#define RXFS_FGI_SHIFT 8
-#define RXFS_FGI_MASK 0x3f00
-#define RXFS_FFL_MASK 0x7f
+#define RXFS_FPI_MASK GENMASK(21, 16)
+#define RXFS_FGI_MASK GENMASK(13, 8)
+#define RXFS_FFL_MASK GENMASK(6, 0)
/* Rx Buffer / FIFO Element Size Configuration (RXESC) */
-#define M_CAN_RXESC_8BYTES 0x0
-#define M_CAN_RXESC_64BYTES 0x777
+#define RXESC_RBDS_MASK GENMASK(10, 8)
+#define RXESC_F1DS_MASK GENMASK(6, 4)
+#define RXESC_F0DS_MASK GENMASK(2, 0)
+#define RXESC_64B 0x7
-/* Tx Buffer Configuration(TXBC) */
-#define TXBC_NDTB_SHIFT 16
-#define TXBC_NDTB_MASK (0x3f << TXBC_NDTB_SHIFT)
-#define TXBC_TFQS_SHIFT 24
-#define TXBC_TFQS_MASK (0x3f << TXBC_TFQS_SHIFT)
+/* Tx Buffer Configuration (TXBC) */
+#define TXBC_TFQS_MASK GENMASK(29, 24)
+#define TXBC_NDTB_MASK GENMASK(21, 16)
/* Tx FIFO/Queue Status (TXFQS) */
#define TXFQS_TFQF BIT(21)
-#define TXFQS_TFQPI_SHIFT 16
-#define TXFQS_TFQPI_MASK (0x1f << TXFQS_TFQPI_SHIFT)
-#define TXFQS_TFGI_SHIFT 8
-#define TXFQS_TFGI_MASK (0x1f << TXFQS_TFGI_SHIFT)
-#define TXFQS_TFFL_SHIFT 0
-#define TXFQS_TFFL_MASK (0x3f << TXFQS_TFFL_SHIFT)
+#define TXFQS_TFQPI_MASK GENMASK(20, 16)
+#define TXFQS_TFGI_MASK GENMASK(12, 8)
+#define TXFQS_TFFL_MASK GENMASK(5, 0)
-/* Tx Buffer Element Size Configuration(TXESC) */
-#define TXESC_TBDS_8BYTES 0x0
-#define TXESC_TBDS_64BYTES 0x7
+/* Tx Buffer Element Size Configuration (TXESC) */
+#define TXESC_TBDS_MASK GENMASK(2, 0)
+#define TXESC_TBDS_64B 0x7
/* Tx Event FIFO Configuration (TXEFC) */
-#define TXEFC_EFS_SHIFT 16
-#define TXEFC_EFS_MASK (0x3f << TXEFC_EFS_SHIFT)
+#define TXEFC_EFS_MASK GENMASK(21, 16)
/* Tx Event FIFO Status (TXEFS) */
#define TXEFS_TEFL BIT(25)
#define TXEFS_EFF BIT(24)
-#define TXEFS_EFGI_SHIFT 8
-#define TXEFS_EFGI_MASK (0x1f << TXEFS_EFGI_SHIFT)
-#define TXEFS_EFFL_SHIFT 0
-#define TXEFS_EFFL_MASK (0x3f << TXEFS_EFFL_SHIFT)
+#define TXEFS_EFGI_MASK GENMASK(12, 8)
+#define TXEFS_EFFL_MASK GENMASK(5, 0)
/* Tx Event FIFO Acknowledge (TXEFA) */
-#define TXEFA_EFAI_SHIFT 0
-#define TXEFA_EFAI_MASK (0x1f << TXEFA_EFAI_SHIFT)
+#define TXEFA_EFAI_MASK GENMASK(4, 0)
/* Message RAM Configuration (in bytes) */
#define SIDF_ELEMENT_SIZE 4
@@ -324,13 +300,12 @@ enum m_can_reg {
#define TX_BUF_EFC BIT(23)
#define TX_BUF_FDF BIT(21)
#define TX_BUF_BRS BIT(20)
-#define TX_BUF_MM_SHIFT 24
-#define TX_BUF_MM_MASK (0xff << TX_BUF_MM_SHIFT)
+#define TX_BUF_MM_MASK GENMASK(31, 24)
+#define TX_BUF_DLC_MASK GENMASK(19, 16)
/* Tx event FIFO Element */
/* E1 */
-#define TX_EVENT_MM_SHIFT TX_BUF_MM_SHIFT
-#define TX_EVENT_MM_MASK (0xff << TX_EVENT_MM_SHIFT)
+#define TX_EVENT_MM_MASK GENMASK(31, 24)
#define TX_EVENT_TXTS_MASK GENMASK(15, 0)
static inline u32 m_can_read(struct m_can_classdev *cdev, enum m_can_reg reg)
@@ -449,8 +424,8 @@ static void m_can_clean(struct net_device *net)
net->stats.tx_errors++;
if (cdev->version > 30)
- putidx = ((m_can_read(cdev, M_CAN_TXFQS) &
- TXFQS_TFQPI_MASK) >> TXFQS_TFQPI_SHIFT);
+ putidx = FIELD_GET(TXFQS_TFQPI_MASK,
+ m_can_read(cdev, M_CAN_TXFQS));
can_free_echo_skb(cdev->net, putidx, NULL);
cdev->tx_skb = NULL;
@@ -490,7 +465,7 @@ static void m_can_read_fifo(struct net_device *dev, u32 rxfs)
int i;
/* calculate the fifo get index for where to read data */
- fgi = (rxfs & RXFS_FGI_MASK) >> RXFS_FGI_SHIFT;
+ fgi = FIELD_GET(RXFS_FGI_MASK, rxfs);
dlc = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_DLC);
if (dlc & RX_BUF_FDF)
skb = alloc_canfd_skb(dev, &cf);
@@ -663,8 +638,8 @@ static int __m_can_get_berr_counter(const struct net_device *dev,
unsigned int ecr;
ecr = m_can_read(cdev, M_CAN_ECR);
- bec->rxerr = (ecr & ECR_REC_MASK) >> ECR_REC_SHIFT;
- bec->txerr = (ecr & ECR_TEC_MASK) >> ECR_TEC_SHIFT;
+ bec->rxerr = FIELD_GET(ECR_REC_MASK, ecr);
+ bec->txerr = FIELD_GET(ECR_TEC_MASK, ecr);
return 0;
}
@@ -1004,24 +979,23 @@ static void m_can_echo_tx_event(struct net_device *dev)
m_can_txefs = m_can_read(cdev, M_CAN_TXEFS);
/* Get Tx Event fifo element count */
- txe_count = (m_can_txefs & TXEFS_EFFL_MASK) >> TXEFS_EFFL_SHIFT;
+ txe_count = FIELD_GET(TXEFS_EFFL_MASK, m_can_txefs);
/* Get and process all sent elements */
for (i = 0; i < txe_count; i++) {
u32 txe, timestamp = 0;
/* retrieve get index */
- fgi = (m_can_read(cdev, M_CAN_TXEFS) & TXEFS_EFGI_MASK) >>
- TXEFS_EFGI_SHIFT;
+ fgi = FIELD_GET(TXEFS_EFGI_MASK, m_can_read(cdev, M_CAN_TXEFS));
/* get message marker, timestamp */
txe = m_can_txe_fifo_read(cdev, fgi, 4);
- msg_mark = (txe & TX_EVENT_MM_MASK) >> TX_EVENT_MM_SHIFT;
+ msg_mark = FIELD_GET(TX_EVENT_MM_MASK, txe);
timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe);
/* ack txe element */
- m_can_write(cdev, M_CAN_TXEFA, (TXEFA_EFAI_MASK &
- (fgi << TXEFA_EFAI_SHIFT)));
+ m_can_write(cdev, M_CAN_TXEFA, FIELD_PREP(TXEFA_EFAI_MASK,
+ fgi));
/* update stats */
m_can_tx_update_stats(cdev, msg_mark, timestamp);
@@ -1147,8 +1121,10 @@ static int m_can_set_bittiming(struct net_device *dev)
sjw = bt->sjw - 1;
tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
tseg2 = bt->phase_seg2 - 1;
- reg_btp = (brp << NBTP_NBRP_SHIFT) | (sjw << NBTP_NSJW_SHIFT) |
- (tseg1 << NBTP_NTSEG1_SHIFT) | (tseg2 << NBTP_NTSEG2_SHIFT);
+ reg_btp = FIELD_PREP(NBTP_NBRP_MASK, brp) |
+ FIELD_PREP(NBTP_NSJW_MASK, sjw) |
+ FIELD_PREP(NBTP_NTSEG1_MASK, tseg1) |
+ FIELD_PREP(NBTP_NTSEG2_MASK, tseg2);
m_can_write(cdev, M_CAN_NBTP, reg_btp);
if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) {
@@ -1185,13 +1161,13 @@ static int m_can_set_bittiming(struct net_device *dev)
reg_btp |= DBTP_TDC;
m_can_write(cdev, M_CAN_TDCR,
- tdco << TDCR_TDCO_SHIFT);
+ FIELD_PREP(TDCR_TDCO_MASK, tdco));
}
- reg_btp |= (brp << DBTP_DBRP_SHIFT) |
- (sjw << DBTP_DSJW_SHIFT) |
- (tseg1 << DBTP_DTSEG1_SHIFT) |
- (tseg2 << DBTP_DTSEG2_SHIFT);
+ reg_btp = FIELD_PREP(NBTP_NBRP_MASK, brp) |
+ FIELD_PREP(NBTP_NSJW_MASK, sjw) |
+ FIELD_PREP(NBTP_NTSEG1_MASK, tseg1) |
+ FIELD_PREP(NBTP_NTSEG2_MASK, tseg2);
m_can_write(cdev, M_CAN_DBTP, reg_btp);
}
@@ -1217,44 +1193,50 @@ static void m_can_chip_config(struct net_device *dev)
m_can_config_endisable(cdev, true);
/* RX Buffer/FIFO Element Size 64 bytes data field */
- m_can_write(cdev, M_CAN_RXESC, M_CAN_RXESC_64BYTES);
+ m_can_write(cdev, M_CAN_RXESC,
+ FIELD_PREP(RXESC_RBDS_MASK, RXESC_64B) |
+ FIELD_PREP(RXESC_F1DS_MASK, RXESC_64B) |
+ FIELD_PREP(RXESC_F0DS_MASK, RXESC_64B));
/* Accept Non-matching Frames Into FIFO 0 */
m_can_write(cdev, M_CAN_GFC, 0x0);
if (cdev->version == 30) {
/* only support one Tx Buffer currently */
- m_can_write(cdev, M_CAN_TXBC, (1 << TXBC_NDTB_SHIFT) |
+ m_can_write(cdev, M_CAN_TXBC, FIELD_PREP(TXBC_NDTB_MASK, 1) |
cdev->mcfg[MRAM_TXB].off);
} else {
/* TX FIFO is used for newer IP Core versions */
m_can_write(cdev, M_CAN_TXBC,
- (cdev->mcfg[MRAM_TXB].num << TXBC_TFQS_SHIFT) |
- (cdev->mcfg[MRAM_TXB].off));
+ FIELD_PREP(TXBC_TFQS_MASK,
+ cdev->mcfg[MRAM_TXB].num) |
+ cdev->mcfg[MRAM_TXB].off);
}
/* support 64 bytes payload */
- m_can_write(cdev, M_CAN_TXESC, TXESC_TBDS_64BYTES);
+ m_can_write(cdev, M_CAN_TXESC,
+ FIELD_PREP(TXESC_TBDS_MASK, TXESC_TBDS_64B));
/* TX Event FIFO */
if (cdev->version == 30) {
- m_can_write(cdev, M_CAN_TXEFC, (1 << TXEFC_EFS_SHIFT) |
+ m_can_write(cdev, M_CAN_TXEFC,
+ FIELD_PREP(TXEFC_EFS_MASK, 1) |
cdev->mcfg[MRAM_TXE].off);
} else {
/* Full TX Event FIFO is used */
m_can_write(cdev, M_CAN_TXEFC,
- ((cdev->mcfg[MRAM_TXE].num << TXEFC_EFS_SHIFT)
- & TXEFC_EFS_MASK) |
+ FIELD_PREP(TXEFC_EFS_MASK,
+ cdev->mcfg[MRAM_TXE].num) |
cdev->mcfg[MRAM_TXE].off);
}
/* rx fifo configuration, blocking mode, fifo size 1 */
m_can_write(cdev, M_CAN_RXF0C,
- (cdev->mcfg[MRAM_RXF0].num << RXFC_FS_SHIFT) |
+ FIELD_PREP(RXFC_FS_MASK, cdev->mcfg[MRAM_RXF0].num) |
cdev->mcfg[MRAM_RXF0].off);
m_can_write(cdev, M_CAN_RXF1C,
- (cdev->mcfg[MRAM_RXF1].num << RXFC_FS_SHIFT) |
+ FIELD_PREP(RXFC_FS_MASK, cdev->mcfg[MRAM_RXF1].num) |
cdev->mcfg[MRAM_RXF1].off);
cccr = m_can_read(cdev, M_CAN_CCCR);
@@ -1264,11 +1246,11 @@ static void m_can_chip_config(struct net_device *dev)
/* Version 3.0.x */
cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_DAR |
- (CCCR_CMR_MASK << CCCR_CMR_SHIFT) |
- (CCCR_CME_MASK << CCCR_CME_SHIFT));
+ FIELD_PREP(CCCR_CMR_MASK, FIELD_MAX(CCCR_CMR_MASK)) |
+ FIELD_PREP(CCCR_CME_MASK, FIELD_MAX(CCCR_CME_MASK)));
if (cdev->can.ctrlmode & CAN_CTRLMODE_FD)
- cccr |= CCCR_CME_CANFD_BRS << CCCR_CME_SHIFT;
+ cccr |= FIELD_PREP(CCCR_CME_MASK, CCCR_CME_CANFD_BRS);
} else {
/* Version 3.1.x or 3.2.x */
@@ -1372,8 +1354,8 @@ static int m_can_check_core_release(struct m_can_classdev *cdev)
* Example: Version 3.2.1 => rel = 3; step = 2; substep = 1;
*/
crel_reg = m_can_read(cdev, M_CAN_CREL);
- rel = (u8)((crel_reg & CREL_REL_MASK) >> CREL_REL_SHIFT);
- step = (u8)((crel_reg & CREL_STEP_MASK) >> CREL_STEP_SHIFT);
+ rel = (u8)FIELD_GET(CREL_REL_MASK, crel_reg);
+ step = (u8)FIELD_GET(CREL_STEP_MASK, crel_reg);
if (rel == 3) {
/* M_CAN v3.x.y: create return value */
@@ -1593,16 +1575,16 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) {
cccr = m_can_read(cdev, M_CAN_CCCR);
- cccr &= ~(CCCR_CMR_MASK << CCCR_CMR_SHIFT);
+ cccr &= ~CCCR_CMR_MASK;
if (can_is_canfd_skb(skb)) {
if (cf->flags & CANFD_BRS)
- cccr |= CCCR_CMR_CANFD_BRS <<
- CCCR_CMR_SHIFT;
+ cccr |= FIELD_PREP(CCCR_CMR_MASK,
+ CCCR_CMR_CANFD_BRS);
else
- cccr |= CCCR_CMR_CANFD <<
- CCCR_CMR_SHIFT;
+ cccr |= FIELD_PREP(CCCR_CMR_MASK,
+ CCCR_CMR_CANFD);
} else {
- cccr |= CCCR_CMR_CAN << CCCR_CMR_SHIFT;
+ cccr |= FIELD_PREP(CCCR_CMR_MASK, CCCR_CMR_CAN);
}
m_can_write(cdev, M_CAN_CCCR, cccr);
}
@@ -1629,8 +1611,8 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
}
/* get put index for frame */
- putidx = ((m_can_read(cdev, M_CAN_TXFQS) & TXFQS_TFQPI_MASK)
- >> TXFQS_TFQPI_SHIFT);
+ putidx = FIELD_GET(TXFQS_TFQPI_MASK,
+ m_can_read(cdev, M_CAN_TXFQS));
/* Write ID Field to FIFO Element */
m_can_fifo_write(cdev, putidx, M_CAN_FIFO_ID, id);
@@ -1648,9 +1630,9 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
* sending the correct echo frame
*/
m_can_fifo_write(cdev, putidx, M_CAN_FIFO_DLC,
- ((putidx << TX_BUF_MM_SHIFT) &
- TX_BUF_MM_MASK) |
- (can_fd_len2dlc(cf->len) << 16) |
+ FIELD_PREP(TX_BUF_MM_MASK, putidx) |
+ FIELD_PREP(TX_BUF_DLC_MASK,
+ can_fd_len2dlc(cf->len)) |
fdflags | TX_BUF_EFC);
for (i = 0; i < cf->len; i += 4)
@@ -1810,11 +1792,11 @@ static void m_can_of_parse_mram(struct m_can_classdev *cdev,
cdev->mcfg[MRAM_RXF0].off = cdev->mcfg[MRAM_XIDF].off +
cdev->mcfg[MRAM_XIDF].num * XIDF_ELEMENT_SIZE;
cdev->mcfg[MRAM_RXF0].num = mram_config_vals[3] &
- (RXFC_FS_MASK >> RXFC_FS_SHIFT);
+ FIELD_MAX(RXFC_FS_MASK);
cdev->mcfg[MRAM_RXF1].off = cdev->mcfg[MRAM_RXF0].off +
cdev->mcfg[MRAM_RXF0].num * RXF0_ELEMENT_SIZE;
cdev->mcfg[MRAM_RXF1].num = mram_config_vals[4] &
- (RXFC_FS_MASK >> RXFC_FS_SHIFT);
+ FIELD_MAX(RXFC_FS_MASK);
cdev->mcfg[MRAM_RXB].off = cdev->mcfg[MRAM_RXF1].off +
cdev->mcfg[MRAM_RXF1].num * RXF1_ELEMENT_SIZE;
cdev->mcfg[MRAM_RXB].num = mram_config_vals[5];
@@ -1824,7 +1806,7 @@ static void m_can_of_parse_mram(struct m_can_classdev *cdev,
cdev->mcfg[MRAM_TXB].off = cdev->mcfg[MRAM_TXE].off +
cdev->mcfg[MRAM_TXE].num * TXE_ELEMENT_SIZE;
cdev->mcfg[MRAM_TXB].num = mram_config_vals[7] &
- (TXBC_NDTB_MASK >> TXBC_NDTB_SHIFT);
+ FIELD_MAX(TXBC_NDTB_MASK);
dev_dbg(cdev->dev,
"sidf 0x%x %d xidf 0x%x %d rxf0 0x%x %d rxf1 0x%x %d rxb 0x%x %d txe 0x%x %d txb 0x%x %d\n",
diff --git a/drivers/net/can/peak_canfd/peak_canfd.c b/drivers/net/can/peak_canfd/peak_canfd.c
index 00847cbaf7b6..d08718e98e11 100644
--- a/drivers/net/can/peak_canfd/peak_canfd.c
+++ b/drivers/net/can/peak_canfd/peak_canfd.c
@@ -351,8 +351,8 @@ static int pucan_handle_status(struct peak_canfd_priv *priv,
return err;
}
- /* start network queue (echo_skb array is empty) */
- netif_start_queue(ndev);
+ /* wake network queue up (echo_skb array is empty) */
+ netif_wake_queue(ndev);
return 0;
}
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index 31ba6664503d..d42ec7d1bc14 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -467,7 +467,8 @@ static void slc_setup(struct net_device *dev)
*/
static void slcan_receive_buf(struct tty_struct *tty,
- const unsigned char *cp, char *fp, int count)
+ const unsigned char *cp, const char *fp,
+ int count)
{
struct slcan *sl = (struct slcan *) tty->disc_data;
@@ -697,6 +698,7 @@ static int slcan_ioctl(struct tty_struct *tty, struct file *file,
static struct tty_ldisc_ops slc_ldisc = {
.owner = THIS_MODULE,
+ .num = N_SLCAN,
.name = "slcan",
.open = slcan_open,
.close = slcan_close,
@@ -721,7 +723,7 @@ static int __init slcan_init(void)
return -ENOMEM;
/* Fill in our line protocol discipline, and register it */
- status = tty_register_ldisc(N_SLCAN, &slc_ldisc);
+ status = tty_register_ldisc(&slc_ldisc);
if (status) {
printk(KERN_ERR "slcan: can't register line discipline\n");
kfree(slcan_devs);
@@ -782,9 +784,7 @@ static void __exit slcan_exit(void)
kfree(slcan_devs);
slcan_devs = NULL;
- i = tty_unregister_ldisc(N_SLCAN);
- if (i)
- printk(KERN_ERR "slcan: can't unregister ldisc (err %d)\n", i);
+ tty_unregister_ldisc(&slc_ldisc);
}
module_init(slcan_init);
diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c
index c44f3411e561..cfc1325aad10 100644
--- a/drivers/net/can/softing/softing_main.c
+++ b/drivers/net/can/softing/softing_main.c
@@ -239,7 +239,6 @@ static int softing_handle_1(struct softing *card)
DPRAM_INFO_BUSSTATE2 : DPRAM_INFO_BUSSTATE]);
/* timestamp */
tmp_u32 = le32_to_cpup((void *)ptr);
- ptr += 4;
ktime = softing_raw2ktime(card, tmp_u32);
++netdev->stats.rx_errors;
@@ -276,7 +275,6 @@ static int softing_handle_1(struct softing *card)
ktime = softing_raw2ktime(card, tmp_u32);
if (!(msg.can_id & CAN_RTR_FLAG))
memcpy(&msg.data[0], ptr, 8);
- ptr += 8;
/* update socket */
if (cmd & CMD_ACK) {
/* acknowledge, was tx msg */
diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c
index 6f5d6d04a8b9..dd17b8c53e1c 100644
--- a/drivers/net/can/spi/hi311x.c
+++ b/drivers/net/can/spi/hi311x.c
@@ -871,7 +871,7 @@ static int hi3110_can_probe(struct spi_device *spi)
CAN_CTRLMODE_BERR_REPORTING;
if (of_id)
- priv->model = (enum hi3110_model)of_id->data;
+ priv->model = (enum hi3110_model)(uintptr_t)of_id->data;
else
priv->model = spi_get_device_id(spi)->driver_data;
priv->net = net;
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index 173c6614086f..0579ab74f728 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -1330,7 +1330,7 @@ static int mcp251x_can_probe(struct spi_device *spi)
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
if (match)
- priv->model = (enum mcp251x_model)match;
+ priv->model = (enum mcp251x_model)(uintptr_t)match;
else
priv->model = spi_get_device_id(spi)->driver_data;
priv->net = net;
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index e0ae00e34c7b..47c3f408a799 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -560,7 +560,7 @@ mcp251xfd_chip_set_mode(const struct mcp251xfd_priv *priv,
return __mcp251xfd_chip_set_mode(priv, mode_req, false);
}
-static inline int
+static inline int __maybe_unused
mcp251xfd_chip_set_mode_nowait(const struct mcp251xfd_priv *priv,
const u8 mode_req)
{
diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index 3deb9f1cd292..f959215c9d53 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -76,7 +76,9 @@ config CAN_KVASER_USB
- Scania VCI2 (if you have the Kvaser logo on top)
- Kvaser BlackBird v2
- Kvaser Leaf Pro HS v2
+ - Kvaser Hybrid CAN/LIN
- Kvaser Hybrid 2xCAN/LIN
+ - Kvaser Hybrid Pro CAN/LIN
- Kvaser Hybrid Pro 2xCAN/LIN
- Kvaser Memorator 2xHS v2
- Kvaser Memorator Pro 2xHS v2
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 5af69787d9d5..0a37af4a3fa4 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -1053,7 +1053,6 @@ static void ems_usb_disconnect(struct usb_interface *intf)
if (dev) {
unregister_netdev(dev->netdev);
- free_candev(dev->netdev);
unlink_all_urbs(dev);
@@ -1061,6 +1060,8 @@ static void ems_usb_disconnect(struct usb_interface *intf)
kfree(dev->intr_in_buffer);
kfree(dev->tx_msg_buffer);
+
+ free_candev(dev->netdev);
}
}
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
index 90ebcae13409..0cc0fc866a2a 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
@@ -79,16 +79,18 @@
#define USB_USBCAN_PRO_2HS_V2_PRODUCT_ID 264
#define USB_MEMO_2HS_PRODUCT_ID 265
#define USB_MEMO_PRO_2HS_V2_PRODUCT_ID 266
-#define USB_HYBRID_CANLIN_PRODUCT_ID 267
+#define USB_HYBRID_2CANLIN_PRODUCT_ID 267
#define USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID 268
#define USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID 269
-#define USB_HYBRID_PRO_CANLIN_PRODUCT_ID 270
+#define USB_HYBRID_PRO_2CANLIN_PRODUCT_ID 270
#define USB_U100_PRODUCT_ID 273
#define USB_U100P_PRODUCT_ID 274
#define USB_U100S_PRODUCT_ID 275
#define USB_USBCAN_PRO_4HS_PRODUCT_ID 276
+#define USB_HYBRID_CANLIN_PRODUCT_ID 277
+#define USB_HYBRID_PRO_CANLIN_PRODUCT_ID 278
#define USB_HYDRA_PRODUCT_ID_END \
- USB_USBCAN_PRO_4HS_PRODUCT_ID
+ USB_HYBRID_PRO_CANLIN_PRODUCT_ID
static inline bool kvaser_is_leaf(const struct usb_device_id *id)
{
@@ -187,14 +189,16 @@ static const struct usb_device_id kvaser_usb_table[] = {
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_2HS_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_2HS_V2_PRODUCT_ID) },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_2CANLIN_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID) },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_2CANLIN_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_U100_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_U100P_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_U100S_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_4HS_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID) },
{ }
};
MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 3ca6b394dd5f..b23e3488695b 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -728,6 +728,13 @@ static u16 b53_default_pvid(struct b53_device *dev)
return 0;
}
+static bool b53_vlan_port_needs_forced_tagged(struct dsa_switch *ds, int port)
+{
+ struct b53_device *dev = ds->priv;
+
+ return dev->tag_protocol == DSA_TAG_PROTO_NONE && dsa_is_cpu_port(ds, port);
+}
+
int b53_configure_vlan(struct dsa_switch *ds)
{
struct b53_device *dev = ds->priv;
@@ -748,9 +755,20 @@ int b53_configure_vlan(struct dsa_switch *ds)
b53_enable_vlan(dev, -1, dev->vlan_enabled, ds->vlan_filtering);
- b53_for_each_port(dev, i)
+ /* Create an untagged VLAN entry for the default PVID in case
+ * CONFIG_VLAN_8021Q is disabled and there are no calls to
+ * dsa_slave_vlan_rx_add_vid() to create the default VLAN
+ * entry. Do this only when the tagging protocol is not
+ * DSA_TAG_PROTO_NONE
+ */
+ b53_for_each_port(dev, i) {
+ v = &dev->vlans[def_vid];
+ v->members |= BIT(i);
+ if (!b53_vlan_port_needs_forced_tagged(ds, i))
+ v->untag = v->members;
b53_write16(dev, B53_VLAN_PAGE,
B53_VLAN_PORT_DEF_TAG(i), def_vid);
+ }
/* Upon initial call we have not set-up any VLANs, but upon
* system resume, we need to restore all VLAN entries.
@@ -1084,6 +1102,11 @@ static int b53_setup(struct dsa_switch *ds)
unsigned int port;
int ret;
+ /* Request bridge PVID untagged when DSA_TAG_PROTO_NONE is set
+ * which forces the CPU port to be tagged in all VLANs.
+ */
+ ds->untag_bridge_pvid = dev->tag_protocol == DSA_TAG_PROTO_NONE;
+
ret = b53_reset_switch(dev);
if (ret) {
dev_err(ds->dev, "failed to reset switch\n");
@@ -1477,7 +1500,7 @@ int b53_vlan_add(struct dsa_switch *ds, int port,
untagged = true;
vl->members |= BIT(port);
- if (untagged && !dsa_is_cpu_port(ds, port))
+ if (untagged && !b53_vlan_port_needs_forced_tagged(ds, port))
vl->untag |= BIT(port);
else
vl->untag &= ~BIT(port);
@@ -1514,7 +1537,7 @@ int b53_vlan_del(struct dsa_switch *ds, int port,
if (pvid == vlan->vid)
pvid = b53_default_pvid(dev);
- if (untagged && !dsa_is_cpu_port(ds, port))
+ if (untagged && !b53_vlan_port_needs_forced_tagged(ds, port))
vl->untag &= ~(BIT(port));
b53_set_vlan_entry(dev, vlan->vid, vl);
@@ -2660,7 +2683,6 @@ struct b53_device *b53_switch_alloc(struct device *base,
dev->priv = priv;
dev->ops = ops;
ds->ops = &b53_switch_ops;
- ds->untag_bridge_pvid = true;
dev->vlan_enabled = true;
/* Let DSA handle the case were multiple bridges span the same switch
* device and different VLAN awareness settings are requested, which
diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c
index aaa12d73784e..3f4249de70c5 100644
--- a/drivers/net/dsa/b53/b53_srab.c
+++ b/drivers/net/dsa/b53/b53_srab.c
@@ -632,8 +632,7 @@ static int b53_srab_remove(struct platform_device *pdev)
struct b53_srab_priv *priv = dev->priv;
b53_srab_intr_set(priv, false);
- if (dev)
- b53_switch_remove(dev);
+ b53_switch_remove(dev);
return 0;
}
diff --git a/drivers/net/dsa/hirschmann/hellcreek.c b/drivers/net/dsa/hirschmann/hellcreek.c
index 4d78219da253..9fdcc4bde480 100644
--- a/drivers/net/dsa/hirschmann/hellcreek.c
+++ b/drivers/net/dsa/hirschmann/hellcreek.c
@@ -927,7 +927,6 @@ static int hellcreek_fdb_dump(struct dsa_switch *ds, int port,
/* Read table */
for (i = 0; i < hellcreek->fdb_entries; ++i) {
- unsigned char null_addr[ETH_ALEN] = { 0 };
struct hellcreek_fdb_entry entry = { 0 };
/* Read entry */
@@ -937,7 +936,7 @@ static int hellcreek_fdb_dump(struct dsa_switch *ds, int port,
hellcreek_write(hellcreek, 0x00, HR_FDBRDH);
/* Check valid */
- if (!memcmp(entry.mac, null_addr, ETH_ALEN))
+ if (is_zero_ether_addr(entry.mac))
continue;
/* Check port mask */
diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c
index ad509a57a945..560f6843bb65 100644
--- a/drivers/net/dsa/microchip/ksz8795.c
+++ b/drivers/net/dsa/microchip/ksz8795.c
@@ -6,6 +6,7 @@
* Tristram Ha <Tristram.Ha@microchip.com>
*/
+#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/gpio.h>
@@ -15,8 +16,10 @@
#include <linux/phy.h>
#include <linux/etherdevice.h>
#include <linux/if_bridge.h>
+#include <linux/micrel_phy.h>
#include <net/dsa.h>
#include <net/switchdev.h>
+#include <linux/phylink.h>
#include "ksz_common.h"
#include "ksz8795_reg.h"
@@ -727,92 +730,114 @@ static void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
u8 restart, speed, ctrl, link;
const u8 *regs = ksz8->regs;
int processed = true;
+ u8 val1, val2;
u16 data = 0;
u8 p = phy;
switch (reg) {
- case PHY_REG_CTRL:
+ case MII_BMCR:
ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart);
ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed);
ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl);
if (restart & PORT_PHY_LOOPBACK)
- data |= PHY_LOOPBACK;
+ data |= BMCR_LOOPBACK;
if (ctrl & PORT_FORCE_100_MBIT)
- data |= PHY_SPEED_100MBIT;
+ data |= BMCR_SPEED100;
if (ksz_is_ksz88x3(dev)) {
if ((ctrl & PORT_AUTO_NEG_ENABLE))
- data |= PHY_AUTO_NEG_ENABLE;
+ data |= BMCR_ANENABLE;
} else {
if (!(ctrl & PORT_AUTO_NEG_DISABLE))
- data |= PHY_AUTO_NEG_ENABLE;
+ data |= BMCR_ANENABLE;
}
if (restart & PORT_POWER_DOWN)
- data |= PHY_POWER_DOWN;
+ data |= BMCR_PDOWN;
if (restart & PORT_AUTO_NEG_RESTART)
- data |= PHY_AUTO_NEG_RESTART;
+ data |= BMCR_ANRESTART;
if (ctrl & PORT_FORCE_FULL_DUPLEX)
- data |= PHY_FULL_DUPLEX;
+ data |= BMCR_FULLDPLX;
if (speed & PORT_HP_MDIX)
- data |= PHY_HP_MDIX;
+ data |= KSZ886X_BMCR_HP_MDIX;
if (restart & PORT_FORCE_MDIX)
- data |= PHY_FORCE_MDIX;
+ data |= KSZ886X_BMCR_FORCE_MDI;
if (restart & PORT_AUTO_MDIX_DISABLE)
- data |= PHY_AUTO_MDIX_DISABLE;
+ data |= KSZ886X_BMCR_DISABLE_AUTO_MDIX;
if (restart & PORT_TX_DISABLE)
- data |= PHY_TRANSMIT_DISABLE;
+ data |= KSZ886X_BMCR_DISABLE_TRANSMIT;
if (restart & PORT_LED_OFF)
- data |= PHY_LED_DISABLE;
+ data |= KSZ886X_BMCR_DISABLE_LED;
break;
- case PHY_REG_STATUS:
+ case MII_BMSR:
ksz_pread8(dev, p, regs[P_LINK_STATUS], &link);
- data = PHY_100BTX_FD_CAPABLE |
- PHY_100BTX_CAPABLE |
- PHY_10BT_FD_CAPABLE |
- PHY_10BT_CAPABLE |
- PHY_AUTO_NEG_CAPABLE;
+ data = BMSR_100FULL |
+ BMSR_100HALF |
+ BMSR_10FULL |
+ BMSR_10HALF |
+ BMSR_ANEGCAPABLE;
if (link & PORT_AUTO_NEG_COMPLETE)
- data |= PHY_AUTO_NEG_ACKNOWLEDGE;
+ data |= BMSR_ANEGCOMPLETE;
if (link & PORT_STAT_LINK_GOOD)
- data |= PHY_LINK_STATUS;
+ data |= BMSR_LSTATUS;
break;
- case PHY_REG_ID_1:
+ case MII_PHYSID1:
data = KSZ8795_ID_HI;
break;
- case PHY_REG_ID_2:
+ case MII_PHYSID2:
if (ksz_is_ksz88x3(dev))
data = KSZ8863_ID_LO;
else
data = KSZ8795_ID_LO;
break;
- case PHY_REG_AUTO_NEGOTIATION:
+ case MII_ADVERTISE:
ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl);
- data = PHY_AUTO_NEG_802_3;
+ data = ADVERTISE_CSMA;
if (ctrl & PORT_AUTO_NEG_SYM_PAUSE)
- data |= PHY_AUTO_NEG_SYM_PAUSE;
+ data |= ADVERTISE_PAUSE_CAP;
if (ctrl & PORT_AUTO_NEG_100BTX_FD)
- data |= PHY_AUTO_NEG_100BTX_FD;
+ data |= ADVERTISE_100FULL;
if (ctrl & PORT_AUTO_NEG_100BTX)
- data |= PHY_AUTO_NEG_100BTX;
+ data |= ADVERTISE_100HALF;
if (ctrl & PORT_AUTO_NEG_10BT_FD)
- data |= PHY_AUTO_NEG_10BT_FD;
+ data |= ADVERTISE_10FULL;
if (ctrl & PORT_AUTO_NEG_10BT)
- data |= PHY_AUTO_NEG_10BT;
+ data |= ADVERTISE_10HALF;
break;
- case PHY_REG_REMOTE_CAPABILITY:
+ case MII_LPA:
ksz_pread8(dev, p, regs[P_REMOTE_STATUS], &link);
- data = PHY_AUTO_NEG_802_3;
+ data = LPA_SLCT;
if (link & PORT_REMOTE_SYM_PAUSE)
- data |= PHY_AUTO_NEG_SYM_PAUSE;
+ data |= LPA_PAUSE_CAP;
if (link & PORT_REMOTE_100BTX_FD)
- data |= PHY_AUTO_NEG_100BTX_FD;
+ data |= LPA_100FULL;
if (link & PORT_REMOTE_100BTX)
- data |= PHY_AUTO_NEG_100BTX;
+ data |= LPA_100HALF;
if (link & PORT_REMOTE_10BT_FD)
- data |= PHY_AUTO_NEG_10BT_FD;
+ data |= LPA_10FULL;
if (link & PORT_REMOTE_10BT)
- data |= PHY_AUTO_NEG_10BT;
- if (data & ~PHY_AUTO_NEG_802_3)
- data |= PHY_REMOTE_ACKNOWLEDGE_NOT;
+ data |= LPA_10HALF;
+ if (data & ~LPA_SLCT)
+ data |= LPA_LPACK;
+ break;
+ case PHY_REG_LINK_MD:
+ ksz_pread8(dev, p, REG_PORT_LINK_MD_CTRL, &val1);
+ ksz_pread8(dev, p, REG_PORT_LINK_MD_RESULT, &val2);
+ if (val1 & PORT_START_CABLE_DIAG)
+ data |= PHY_START_CABLE_DIAG;
+
+ if (val1 & PORT_CABLE_10M_SHORT)
+ data |= PHY_CABLE_10M_SHORT;
+
+ data |= FIELD_PREP(PHY_CABLE_DIAG_RESULT_M,
+ FIELD_GET(PORT_CABLE_DIAG_RESULT_M, val1));
+
+ data |= FIELD_PREP(PHY_CABLE_FAULT_COUNTER_M,
+ (FIELD_GET(PORT_CABLE_FAULT_COUNTER_H, val1) << 8) |
+ FIELD_GET(PORT_CABLE_FAULT_COUNTER_L, val2));
+ break;
+ case PHY_REG_PHY_CTRL:
+ ksz_pread8(dev, p, regs[P_LINK_STATUS], &link);
+ if (link & PORT_MDIX_STATUS)
+ data |= KSZ886X_CTRL_MDIX_STAT;
break;
default:
processed = false;
@@ -830,14 +855,14 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
u8 p = phy;
switch (reg) {
- case PHY_REG_CTRL:
+ case MII_BMCR:
/* Do not support PHY reset function. */
- if (val & PHY_RESET)
+ if (val & BMCR_RESET)
break;
ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed);
data = speed;
- if (val & PHY_HP_MDIX)
+ if (val & KSZ886X_BMCR_HP_MDIX)
data |= PORT_HP_MDIX;
else
data &= ~PORT_HP_MDIX;
@@ -846,12 +871,12 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl);
data = ctrl;
if (ksz_is_ksz88x3(dev)) {
- if ((val & PHY_AUTO_NEG_ENABLE))
+ if ((val & BMCR_ANENABLE))
data |= PORT_AUTO_NEG_ENABLE;
else
data &= ~PORT_AUTO_NEG_ENABLE;
} else {
- if (!(val & PHY_AUTO_NEG_ENABLE))
+ if (!(val & BMCR_ANENABLE))
data |= PORT_AUTO_NEG_DISABLE;
else
data &= ~PORT_AUTO_NEG_DISABLE;
@@ -861,11 +886,11 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
data |= PORT_AUTO_NEG_DISABLE;
}
- if (val & PHY_SPEED_100MBIT)
+ if (val & BMCR_SPEED100)
data |= PORT_FORCE_100_MBIT;
else
data &= ~PORT_FORCE_100_MBIT;
- if (val & PHY_FULL_DUPLEX)
+ if (val & BMCR_FULLDPLX)
data |= PORT_FORCE_FULL_DUPLEX;
else
data &= ~PORT_FORCE_FULL_DUPLEX;
@@ -873,38 +898,38 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
ksz_pwrite8(dev, p, regs[P_FORCE_CTRL], data);
ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart);
data = restart;
- if (val & PHY_LED_DISABLE)
+ if (val & KSZ886X_BMCR_DISABLE_LED)
data |= PORT_LED_OFF;
else
data &= ~PORT_LED_OFF;
- if (val & PHY_TRANSMIT_DISABLE)
+ if (val & KSZ886X_BMCR_DISABLE_TRANSMIT)
data |= PORT_TX_DISABLE;
else
data &= ~PORT_TX_DISABLE;
- if (val & PHY_AUTO_NEG_RESTART)
+ if (val & BMCR_ANRESTART)
data |= PORT_AUTO_NEG_RESTART;
else
data &= ~(PORT_AUTO_NEG_RESTART);
- if (val & PHY_POWER_DOWN)
+ if (val & BMCR_PDOWN)
data |= PORT_POWER_DOWN;
else
data &= ~PORT_POWER_DOWN;
- if (val & PHY_AUTO_MDIX_DISABLE)
+ if (val & KSZ886X_BMCR_DISABLE_AUTO_MDIX)
data |= PORT_AUTO_MDIX_DISABLE;
else
data &= ~PORT_AUTO_MDIX_DISABLE;
- if (val & PHY_FORCE_MDIX)
+ if (val & KSZ886X_BMCR_FORCE_MDI)
data |= PORT_FORCE_MDIX;
else
data &= ~PORT_FORCE_MDIX;
- if (val & PHY_LOOPBACK)
+ if (val & BMCR_LOOPBACK)
data |= PORT_PHY_LOOPBACK;
else
data &= ~PORT_PHY_LOOPBACK;
if (data != restart)
ksz_pwrite8(dev, p, regs[P_NEG_RESTART_CTRL], data);
break;
- case PHY_REG_AUTO_NEGOTIATION:
+ case MII_ADVERTISE:
ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl);
data = ctrl;
data &= ~(PORT_AUTO_NEG_SYM_PAUSE |
@@ -912,19 +937,23 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
PORT_AUTO_NEG_100BTX |
PORT_AUTO_NEG_10BT_FD |
PORT_AUTO_NEG_10BT);
- if (val & PHY_AUTO_NEG_SYM_PAUSE)
+ if (val & ADVERTISE_PAUSE_CAP)
data |= PORT_AUTO_NEG_SYM_PAUSE;
- if (val & PHY_AUTO_NEG_100BTX_FD)
+ if (val & ADVERTISE_100FULL)
data |= PORT_AUTO_NEG_100BTX_FD;
- if (val & PHY_AUTO_NEG_100BTX)
+ if (val & ADVERTISE_100HALF)
data |= PORT_AUTO_NEG_100BTX;
- if (val & PHY_AUTO_NEG_10BT_FD)
+ if (val & ADVERTISE_10FULL)
data |= PORT_AUTO_NEG_10BT_FD;
- if (val & PHY_AUTO_NEG_10BT)
+ if (val & ADVERTISE_10HALF)
data |= PORT_AUTO_NEG_10BT;
if (data != ctrl)
ksz_pwrite8(dev, p, regs[P_LOCAL_CTRL], data);
break;
+ case PHY_REG_LINK_MD:
+ if (val & PHY_START_CABLE_DIAG)
+ ksz_port_cfg(dev, p, REG_PORT_LINK_MD_CTRL, PORT_START_CABLE_DIAG, true);
+ break;
default:
break;
}
@@ -941,6 +970,18 @@ static enum dsa_tag_protocol ksz8_get_tag_protocol(struct dsa_switch *ds,
DSA_TAG_PROTO_KSZ9893 : DSA_TAG_PROTO_KSZ8795;
}
+static u32 ksz8_sw_get_phy_flags(struct dsa_switch *ds, int port)
+{
+ /* Silicon Errata Sheet (DS80000830A):
+ * Port 1 does not work with LinkMD Cable-Testing.
+ * Port 1 does not respond to received PAUSE control frames.
+ */
+ if (!port)
+ return MICREL_KSZ8_P1_ERRATA;
+
+ return 0;
+}
+
static void ksz8_get_strings(struct dsa_switch *ds, int port,
u32 stringset, uint8_t *buf)
{
@@ -1419,11 +1460,66 @@ static int ksz8_setup(struct dsa_switch *ds)
return 0;
}
+static void ksz8_validate(struct dsa_switch *ds, int port,
+ unsigned long *supported,
+ struct phylink_link_state *state)
+{
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+ struct ksz_device *dev = ds->priv;
+
+ if (port == dev->cpu_port) {
+ if (state->interface != PHY_INTERFACE_MODE_RMII &&
+ state->interface != PHY_INTERFACE_MODE_MII &&
+ state->interface != PHY_INTERFACE_MODE_NA)
+ goto unsupported;
+ } else {
+ if (state->interface != PHY_INTERFACE_MODE_INTERNAL &&
+ state->interface != PHY_INTERFACE_MODE_NA)
+ goto unsupported;
+ }
+
+ /* Allow all the expected bits */
+ phylink_set_port_modes(mask);
+ phylink_set(mask, Autoneg);
+
+ /* Silicon Errata Sheet (DS80000830A):
+ * "Port 1 does not respond to received flow control PAUSE frames"
+ * So, disable Pause support on "Port 1" (port == 0) for all ksz88x3
+ * switches.
+ */
+ if (!ksz_is_ksz88x3(dev) || port)
+ phylink_set(mask, Pause);
+
+ /* Asym pause is not supported on KSZ8863 and KSZ8873 */
+ if (!ksz_is_ksz88x3(dev))
+ phylink_set(mask, Asym_Pause);
+
+ /* 10M and 100M are only supported */
+ phylink_set(mask, 10baseT_Half);
+ phylink_set(mask, 10baseT_Full);
+ phylink_set(mask, 100baseT_Half);
+ phylink_set(mask, 100baseT_Full);
+
+ bitmap_and(supported, supported, mask,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+ bitmap_and(state->advertising, state->advertising, mask,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+
+ return;
+
+unsupported:
+ bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+ dev_err(ds->dev, "Unsupported interface: %s, port: %d\n",
+ phy_modes(state->interface), port);
+}
+
static const struct dsa_switch_ops ksz8_switch_ops = {
.get_tag_protocol = ksz8_get_tag_protocol,
+ .get_phy_flags = ksz8_sw_get_phy_flags,
.setup = ksz8_setup,
.phy_read = ksz_phy_read16,
.phy_write = ksz_phy_write16,
+ .phylink_validate = ksz8_validate,
.phylink_mac_link_down = ksz_mac_link_down,
.port_enable = ksz_enable_port,
.get_strings = ksz8_get_strings,
diff --git a/drivers/net/dsa/microchip/ksz8795_reg.h b/drivers/net/dsa/microchip/ksz8795_reg.h
index c2e52c40a54c..a32355624f31 100644
--- a/drivers/net/dsa/microchip/ksz8795_reg.h
+++ b/drivers/net/dsa/microchip/ksz8795_reg.h
@@ -249,7 +249,7 @@
#define REG_PORT_4_LINK_MD_CTRL 0x4A
#define PORT_CABLE_10M_SHORT BIT(7)
-#define PORT_CABLE_DIAG_RESULT_M 0x3
+#define PORT_CABLE_DIAG_RESULT_M GENMASK(6, 5)
#define PORT_CABLE_DIAG_RESULT_S 5
#define PORT_CABLE_STAT_NORMAL 0
#define PORT_CABLE_STAT_OPEN 1
@@ -744,68 +744,6 @@
#define PORT_ACL_FORCE_DLR_MISS BIT(0)
-#ifndef PHY_REG_CTRL
-#define PHY_REG_CTRL 0
-
-#define PHY_RESET BIT(15)
-#define PHY_LOOPBACK BIT(14)
-#define PHY_SPEED_100MBIT BIT(13)
-#define PHY_AUTO_NEG_ENABLE BIT(12)
-#define PHY_POWER_DOWN BIT(11)
-#define PHY_MII_DISABLE BIT(10)
-#define PHY_AUTO_NEG_RESTART BIT(9)
-#define PHY_FULL_DUPLEX BIT(8)
-#define PHY_COLLISION_TEST_NOT BIT(7)
-#define PHY_HP_MDIX BIT(5)
-#define PHY_FORCE_MDIX BIT(4)
-#define PHY_AUTO_MDIX_DISABLE BIT(3)
-#define PHY_REMOTE_FAULT_DISABLE BIT(2)
-#define PHY_TRANSMIT_DISABLE BIT(1)
-#define PHY_LED_DISABLE BIT(0)
-
-#define PHY_REG_STATUS 1
-
-#define PHY_100BT4_CAPABLE BIT(15)
-#define PHY_100BTX_FD_CAPABLE BIT(14)
-#define PHY_100BTX_CAPABLE BIT(13)
-#define PHY_10BT_FD_CAPABLE BIT(12)
-#define PHY_10BT_CAPABLE BIT(11)
-#define PHY_MII_SUPPRESS_CAPABLE_NOT BIT(6)
-#define PHY_AUTO_NEG_ACKNOWLEDGE BIT(5)
-#define PHY_REMOTE_FAULT BIT(4)
-#define PHY_AUTO_NEG_CAPABLE BIT(3)
-#define PHY_LINK_STATUS BIT(2)
-#define PHY_JABBER_DETECT_NOT BIT(1)
-#define PHY_EXTENDED_CAPABILITY BIT(0)
-
-#define PHY_REG_ID_1 2
-#define PHY_REG_ID_2 3
-
-#define PHY_REG_AUTO_NEGOTIATION 4
-
-#define PHY_AUTO_NEG_NEXT_PAGE_NOT BIT(15)
-#define PHY_AUTO_NEG_REMOTE_FAULT_NOT BIT(13)
-#define PHY_AUTO_NEG_SYM_PAUSE BIT(10)
-#define PHY_AUTO_NEG_100BT4 BIT(9)
-#define PHY_AUTO_NEG_100BTX_FD BIT(8)
-#define PHY_AUTO_NEG_100BTX BIT(7)
-#define PHY_AUTO_NEG_10BT_FD BIT(6)
-#define PHY_AUTO_NEG_10BT BIT(5)
-#define PHY_AUTO_NEG_SELECTOR 0x001F
-#define PHY_AUTO_NEG_802_3 0x0001
-
-#define PHY_REG_REMOTE_CAPABILITY 5
-
-#define PHY_REMOTE_NEXT_PAGE_NOT BIT(15)
-#define PHY_REMOTE_ACKNOWLEDGE_NOT BIT(14)
-#define PHY_REMOTE_REMOTE_FAULT_NOT BIT(13)
-#define PHY_REMOTE_SYM_PAUSE BIT(10)
-#define PHY_REMOTE_100BTX_FD BIT(8)
-#define PHY_REMOTE_100BTX BIT(7)
-#define PHY_REMOTE_10BT_FD BIT(6)
-#define PHY_REMOTE_10BT BIT(5)
-#endif
-
#define KSZ8795_ID_HI 0x0022
#define KSZ8795_ID_LO 0x1550
#define KSZ8863_ID_LO 0x1430
@@ -815,13 +753,14 @@
#define PHY_REG_LINK_MD 0x1D
#define PHY_START_CABLE_DIAG BIT(15)
+#define PHY_CABLE_DIAG_RESULT_M GENMASK(14, 13)
#define PHY_CABLE_DIAG_RESULT 0x6000
#define PHY_CABLE_STAT_NORMAL 0x0000
#define PHY_CABLE_STAT_OPEN 0x2000
#define PHY_CABLE_STAT_SHORT 0x4000
#define PHY_CABLE_STAT_FAILED 0x6000
#define PHY_CABLE_10M_SHORT BIT(12)
-#define PHY_CABLE_FAULT_COUNTER 0x01FF
+#define PHY_CABLE_FAULT_COUNTER_M GENMASK(8, 0)
#define PHY_REG_PHY_CTRL 0x1F
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index a7e5ac60baef..1542bfb8b5e5 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -419,8 +419,10 @@ int ksz_switch_register(struct ksz_device *dev,
if (of_property_read_u32(port, "reg",
&port_num))
continue;
- if (!(dev->port_mask & BIT(port_num)))
+ if (!(dev->port_mask & BIT(port_num))) {
+ of_node_put(port);
return -EINVAL;
+ }
of_get_phy_mode(port,
&dev->ports[port_num].interface);
}
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 9b90f3d3a8f5..93136f7e69f5 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -10,6 +10,7 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/netdevice.h>
+#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/of_platform.h>
@@ -596,18 +597,14 @@ mt7530_mib_reset(struct dsa_switch *ds)
mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_ACTIVATE);
}
-static int mt7530_phy_read(struct dsa_switch *ds, int port, int regnum)
+static int mt7530_phy_read(struct mt7530_priv *priv, int port, int regnum)
{
- struct mt7530_priv *priv = ds->priv;
-
return mdiobus_read_nested(priv->bus, port, regnum);
}
-static int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum,
+static int mt7530_phy_write(struct mt7530_priv *priv, int port, int regnum,
u16 val)
{
- struct mt7530_priv *priv = ds->priv;
-
return mdiobus_write_nested(priv->bus, port, regnum, val);
}
@@ -785,9 +782,8 @@ out:
}
static int
-mt7531_ind_phy_read(struct dsa_switch *ds, int port, int regnum)
+mt7531_ind_phy_read(struct mt7530_priv *priv, int port, int regnum)
{
- struct mt7530_priv *priv = ds->priv;
int devad;
int ret;
@@ -803,10 +799,9 @@ mt7531_ind_phy_read(struct dsa_switch *ds, int port, int regnum)
}
static int
-mt7531_ind_phy_write(struct dsa_switch *ds, int port, int regnum,
+mt7531_ind_phy_write(struct mt7530_priv *priv, int port, int regnum,
u16 data)
{
- struct mt7530_priv *priv = ds->priv;
int devad;
int ret;
@@ -822,6 +817,22 @@ mt7531_ind_phy_write(struct dsa_switch *ds, int port, int regnum,
return ret;
}
+static int
+mt753x_phy_read(struct mii_bus *bus, int port, int regnum)
+{
+ struct mt7530_priv *priv = bus->priv;
+
+ return priv->info->phy_read(priv, port, regnum);
+}
+
+static int
+mt753x_phy_write(struct mii_bus *bus, int port, int regnum, u16 val)
+{
+ struct mt7530_priv *priv = bus->priv;
+
+ return priv->info->phy_write(priv, port, regnum, val);
+}
+
static void
mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset,
uint8_t *data)
@@ -1820,6 +1831,210 @@ mt7530_setup_gpio(struct mt7530_priv *priv)
}
#endif /* CONFIG_GPIOLIB */
+static irqreturn_t
+mt7530_irq_thread_fn(int irq, void *dev_id)
+{
+ struct mt7530_priv *priv = dev_id;
+ bool handled = false;
+ u32 val;
+ int p;
+
+ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
+ val = mt7530_mii_read(priv, MT7530_SYS_INT_STS);
+ mt7530_mii_write(priv, MT7530_SYS_INT_STS, val);
+ mutex_unlock(&priv->bus->mdio_lock);
+
+ for (p = 0; p < MT7530_NUM_PHYS; p++) {
+ if (BIT(p) & val) {
+ unsigned int irq;
+
+ irq = irq_find_mapping(priv->irq_domain, p);
+ handle_nested_irq(irq);
+ handled = true;
+ }
+ }
+
+ return IRQ_RETVAL(handled);
+}
+
+static void
+mt7530_irq_mask(struct irq_data *d)
+{
+ struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
+
+ priv->irq_enable &= ~BIT(d->hwirq);
+}
+
+static void
+mt7530_irq_unmask(struct irq_data *d)
+{
+ struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
+
+ priv->irq_enable |= BIT(d->hwirq);
+}
+
+static void
+mt7530_irq_bus_lock(struct irq_data *d)
+{
+ struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
+
+ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
+}
+
+static void
+mt7530_irq_bus_sync_unlock(struct irq_data *d)
+{
+ struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
+
+ mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable);
+ mutex_unlock(&priv->bus->mdio_lock);
+}
+
+static struct irq_chip mt7530_irq_chip = {
+ .name = KBUILD_MODNAME,
+ .irq_mask = mt7530_irq_mask,
+ .irq_unmask = mt7530_irq_unmask,
+ .irq_bus_lock = mt7530_irq_bus_lock,
+ .irq_bus_sync_unlock = mt7530_irq_bus_sync_unlock,
+};
+
+static int
+mt7530_irq_map(struct irq_domain *domain, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ irq_set_chip_data(irq, domain->host_data);
+ irq_set_chip_and_handler(irq, &mt7530_irq_chip, handle_simple_irq);
+ irq_set_nested_thread(irq, true);
+ irq_set_noprobe(irq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops mt7530_irq_domain_ops = {
+ .map = mt7530_irq_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+static void
+mt7530_setup_mdio_irq(struct mt7530_priv *priv)
+{
+ struct dsa_switch *ds = priv->ds;
+ int p;
+
+ for (p = 0; p < MT7530_NUM_PHYS; p++) {
+ if (BIT(p) & ds->phys_mii_mask) {
+ unsigned int irq;
+
+ irq = irq_create_mapping(priv->irq_domain, p);
+ ds->slave_mii_bus->irq[p] = irq;
+ }
+ }
+}
+
+static int
+mt7530_setup_irq(struct mt7530_priv *priv)
+{
+ struct device *dev = priv->dev;
+ struct device_node *np = dev->of_node;
+ int ret;
+
+ if (!of_property_read_bool(np, "interrupt-controller")) {
+ dev_info(dev, "no interrupt support\n");
+ return 0;
+ }
+
+ priv->irq = of_irq_get(np, 0);
+ if (priv->irq <= 0) {
+ dev_err(dev, "failed to get parent IRQ: %d\n", priv->irq);
+ return priv->irq ? : -EINVAL;
+ }
+
+ priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS,
+ &mt7530_irq_domain_ops, priv);
+ if (!priv->irq_domain) {
+ dev_err(dev, "failed to create IRQ domain\n");
+ return -ENOMEM;
+ }
+
+ /* This register must be set for MT7530 to properly fire interrupts */
+ if (priv->id != ID_MT7531)
+ mt7530_set(priv, MT7530_TOP_SIG_CTRL, TOP_SIG_CTRL_NORMAL);
+
+ ret = request_threaded_irq(priv->irq, NULL, mt7530_irq_thread_fn,
+ IRQF_ONESHOT, KBUILD_MODNAME, priv);
+ if (ret) {
+ irq_domain_remove(priv->irq_domain);
+ dev_err(dev, "failed to request IRQ: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void
+mt7530_free_mdio_irq(struct mt7530_priv *priv)
+{
+ int p;
+
+ for (p = 0; p < MT7530_NUM_PHYS; p++) {
+ if (BIT(p) & priv->ds->phys_mii_mask) {
+ unsigned int irq;
+
+ irq = irq_find_mapping(priv->irq_domain, p);
+ irq_dispose_mapping(irq);
+ }
+ }
+}
+
+static void
+mt7530_free_irq_common(struct mt7530_priv *priv)
+{
+ free_irq(priv->irq, priv);
+ irq_domain_remove(priv->irq_domain);
+}
+
+static void
+mt7530_free_irq(struct mt7530_priv *priv)
+{
+ mt7530_free_mdio_irq(priv);
+ mt7530_free_irq_common(priv);
+}
+
+static int
+mt7530_setup_mdio(struct mt7530_priv *priv)
+{
+ struct dsa_switch *ds = priv->ds;
+ struct device *dev = priv->dev;
+ struct mii_bus *bus;
+ static int idx;
+ int ret;
+
+ bus = devm_mdiobus_alloc(dev);
+ if (!bus)
+ return -ENOMEM;
+
+ ds->slave_mii_bus = bus;
+ bus->priv = priv;
+ bus->name = KBUILD_MODNAME "-mii";
+ snprintf(bus->id, MII_BUS_ID_SIZE, KBUILD_MODNAME "-%d", idx++);
+ bus->read = mt753x_phy_read;
+ bus->write = mt753x_phy_write;
+ bus->parent = dev;
+ bus->phy_mask = ~ds->phys_mii_mask;
+
+ if (priv->irq)
+ mt7530_setup_mdio_irq(priv);
+
+ ret = mdiobus_register(bus);
+ if (ret) {
+ dev_err(dev, "failed to register MDIO bus: %d\n", ret);
+ if (priv->irq)
+ mt7530_free_mdio_irq(priv);
+ }
+
+ return ret;
+}
+
static int
mt7530_setup(struct dsa_switch *ds)
{
@@ -2783,24 +2998,20 @@ static int
mt753x_setup(struct dsa_switch *ds)
{
struct mt7530_priv *priv = ds->priv;
+ int ret = priv->info->sw_setup(ds);
- return priv->info->sw_setup(ds);
-}
-
-static int
-mt753x_phy_read(struct dsa_switch *ds, int port, int regnum)
-{
- struct mt7530_priv *priv = ds->priv;
+ if (ret)
+ return ret;
- return priv->info->phy_read(ds, port, regnum);
-}
+ ret = mt7530_setup_irq(priv);
+ if (ret)
+ return ret;
-static int
-mt753x_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
-{
- struct mt7530_priv *priv = ds->priv;
+ ret = mt7530_setup_mdio(priv);
+ if (ret && priv->irq)
+ mt7530_free_irq_common(priv);
- return priv->info->phy_write(ds, port, regnum, val);
+ return ret;
}
static int mt753x_get_mac_eee(struct dsa_switch *ds, int port,
@@ -2837,8 +3048,6 @@ static const struct dsa_switch_ops mt7530_switch_ops = {
.get_tag_protocol = mtk_get_tag_protocol,
.setup = mt753x_setup,
.get_strings = mt7530_get_strings,
- .phy_read = mt753x_phy_read,
- .phy_write = mt753x_phy_write,
.get_ethtool_stats = mt7530_get_ethtool_stats,
.get_sset_count = mt7530_get_sset_count,
.set_ageing_time = mt7530_set_ageing_time,
@@ -3021,6 +3230,9 @@ mt7530_remove(struct mdio_device *mdiodev)
dev_err(priv->dev, "Failed to disable io pwr: %d\n",
ret);
+ if (priv->irq)
+ mt7530_free_irq(priv);
+
dsa_unregister_switch(priv->ds);
mutex_destroy(&priv->reg_mutex);
}
diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h
index 0204da486f3a..334d610a503d 100644
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -7,6 +7,7 @@
#define __MT7530_H
#define MT7530_NUM_PORTS 7
+#define MT7530_NUM_PHYS 5
#define MT7530_CPU_PORT 6
#define MT7530_NUM_FDB_RECORDS 2048
#define MT7530_ALL_MEMBERS 0xff
@@ -393,6 +394,12 @@ enum mt7531_sgmii_force_duplex {
#define SYS_CTRL_SW_RST BIT(1)
#define SYS_CTRL_REG_RST BIT(0)
+/* Register for system interrupt */
+#define MT7530_SYS_INT_EN 0x7008
+
+/* Register for system interrupt status */
+#define MT7530_SYS_INT_STS 0x700c
+
/* Register for PHY Indirect Access Control */
#define MT7531_PHY_IAC 0x701C
#define MT7531_PHY_ACS_ST BIT(31)
@@ -714,6 +721,8 @@ static const char *p5_intf_modes(unsigned int p5_interface)
}
}
+struct mt7530_priv;
+
/* struct mt753x_info - This is the main data structure for holding the specific
* part for each supported device
* @sw_setup: Holding the handler to a device initialization
@@ -738,8 +747,8 @@ struct mt753x_info {
enum mt753x_id id;
int (*sw_setup)(struct dsa_switch *ds);
- int (*phy_read)(struct dsa_switch *ds, int port, int regnum);
- int (*phy_write)(struct dsa_switch *ds, int port, int regnum, u16 val);
+ int (*phy_read)(struct mt7530_priv *priv, int port, int regnum);
+ int (*phy_write)(struct mt7530_priv *priv, int port, int regnum, u16 val);
int (*pad_setup)(struct dsa_switch *ds, phy_interface_t interface);
int (*cpu_port_config)(struct dsa_switch *ds, int port);
bool (*phy_mode_supported)(struct dsa_switch *ds, int port,
@@ -773,6 +782,10 @@ struct mt753x_info {
* registers
* @p6_interface Holding the current port 6 interface
* @p5_intf_sel: Holding the current port 5 interface select
+ *
+ * @irq: IRQ number of the switch
+ * @irq_domain: IRQ domain of the switch irq_chip
+ * @irq_enable: IRQ enable bits, synced to SYS_INT_EN
*/
struct mt7530_priv {
struct device *dev;
@@ -794,6 +807,9 @@ struct mt7530_priv {
struct mt7530_port ports[MT7530_NUM_PORTS];
/* protect among processes for registers access*/
struct mutex reg_mutex;
+ int irq;
+ struct irq_domain *irq_domain;
+ u32 irq_enable;
};
struct mt7530_hw_vlan_entry {
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index eca285aaf72f..beb41572d04e 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1618,9 +1618,6 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
struct mv88e6xxx_vtu_entry vlan;
int i, err;
- if (!vid)
- return -EOPNOTSUPP;
-
/* DSA and CPU ports have to be members of multiple vlans */
if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
return 0;
@@ -2109,6 +2106,9 @@ static int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
u8 member;
int err;
+ if (!vlan->vid)
+ return 0;
+
err = mv88e6xxx_port_vlan_prepare(ds, port, vlan);
if (err)
return err;
@@ -3583,6 +3583,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
.port_max_speed_mode = mv88e6341_port_max_speed_mode,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_policy = mv88e6352_port_set_policy,
.port_set_frame_mode = mv88e6351_port_set_frame_mode,
.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
@@ -3596,7 +3597,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.port_set_cmode = mv88e6341_port_set_cmode,
.port_setup_message_port = mv88e6xxx_setup_message_port,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
- .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
+ .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
@@ -3606,6 +3607,9 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
.pot_clear = mv88e6xxx_g2_pot_clear,
.reset = mv88e6352_g1_reset,
+ .rmu_disable = mv88e6390_g1_rmu_disable,
+ .atu_get_hash = mv88e6165_g1_atu_get_hash,
+ .atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power,
@@ -3619,6 +3623,11 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.serdes_irq_enable = mv88e6390_serdes_irq_enable,
.serdes_irq_status = mv88e6390_serdes_irq_status,
.gpio_ops = &mv88e6352_gpio_ops,
+ .serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
+ .serdes_get_strings = mv88e6390_serdes_get_strings,
+ .serdes_get_stats = mv88e6390_serdes_get_stats,
+ .serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
+ .serdes_get_regs = mv88e6390_serdes_get_regs,
.phylink_validate = mv88e6341_phylink_validate,
};
@@ -4383,6 +4392,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
.port_max_speed_mode = mv88e6341_port_max_speed_mode,
.port_tag_remap = mv88e6095_port_tag_remap,
+ .port_set_policy = mv88e6352_port_set_policy,
.port_set_frame_mode = mv88e6351_port_set_frame_mode,
.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
@@ -4396,7 +4406,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.port_set_cmode = mv88e6341_port_set_cmode,
.port_setup_message_port = mv88e6xxx_setup_message_port,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
- .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
+ .stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
.stats_get_stats = mv88e6390_stats_get_stats,
@@ -4406,6 +4416,9 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu,
.pot_clear = mv88e6xxx_g2_pot_clear,
.reset = mv88e6352_g1_reset,
+ .rmu_disable = mv88e6390_g1_rmu_disable,
+ .atu_get_hash = mv88e6165_g1_atu_get_hash,
+ .atu_set_hash = mv88e6165_g1_atu_set_hash,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power,
@@ -4421,6 +4434,11 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
+ .serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
+ .serdes_get_strings = mv88e6390_serdes_get_strings,
+ .serdes_get_stats = mv88e6390_serdes_get_stats,
+ .serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
+ .serdes_get_regs = mv88e6390_serdes_get_regs,
.phylink_validate = mv88e6341_phylink_validate,
};
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index e4fbef81bc52..b1d46dd8eaab 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -722,7 +722,7 @@ static struct mv88e6390_serdes_hw_stat mv88e6390_serdes_hw_stats[] = {
int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
{
- if (mv88e6390_serdes_get_lane(chip, port) < 0)
+ if (mv88e6xxx_serdes_get_lane(chip, port) < 0)
return 0;
return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
@@ -734,7 +734,7 @@ int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip,
struct mv88e6390_serdes_hw_stat *stat;
int i;
- if (mv88e6390_serdes_get_lane(chip, port) < 0)
+ if (mv88e6xxx_serdes_get_lane(chip, port) < 0)
return 0;
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
@@ -770,7 +770,7 @@ int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
int lane;
int i;
- lane = mv88e6390_serdes_get_lane(chip, port);
+ lane = mv88e6xxx_serdes_get_lane(chip, port);
if (lane < 0)
return 0;
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index ce607fbaaa3a..a2a15919b960 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -940,6 +940,8 @@ static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port);
+ ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, tx_pause);
+
/* Undo the effects of felix_phylink_mac_link_down:
* enable MAC module
*/
diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c
index 84f93a874d50..deae923c8b7a 100644
--- a/drivers/net/dsa/ocelot/seville_vsc9953.c
+++ b/drivers/net/dsa/ocelot/seville_vsc9953.c
@@ -1206,6 +1206,11 @@ static int seville_probe(struct platform_device *pdev)
felix->info = &seville_info_vsc9953;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ err = -EINVAL;
+ dev_err(&pdev->dev, "Invalid resource\n");
+ goto err_alloc_felix;
+ }
felix->switch_base = res->start;
ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL);
diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index cdaf9f85a2cb..1f63f50f73f1 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -11,6 +11,7 @@
#include <linux/netdevice.h>
#include <net/dsa.h>
#include <linux/of_net.h>
+#include <linux/of_mdio.h>
#include <linux/of_platform.h>
#include <linux/if_bridge.h>
#include <linux/mdio.h>
@@ -88,26 +89,26 @@ qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
*page = regaddr & 0x3ff;
}
-static u32
-qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum)
+static int
+qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val)
{
- u32 val;
int ret;
ret = bus->read(bus, phy_id, regnum);
if (ret >= 0) {
- val = ret;
+ *val = ret;
ret = bus->read(bus, phy_id, regnum + 1);
- val |= ret << 16;
+ *val |= ret << 16;
}
if (ret < 0) {
dev_err_ratelimited(&bus->dev,
"failed to read qca8k 32bit register\n");
+ *val = 0;
return ret;
}
- return val;
+ return 0;
}
static void
@@ -127,82 +128,110 @@ qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val)
"failed to write qca8k 32bit register\n");
}
-static void
+static int
qca8k_set_page(struct mii_bus *bus, u16 page)
{
+ int ret;
+
if (page == qca8k_current_page)
- return;
+ return 0;
- if (bus->write(bus, 0x18, 0, page) < 0)
+ ret = bus->write(bus, 0x18, 0, page);
+ if (ret < 0) {
dev_err_ratelimited(&bus->dev,
"failed to set qca8k page\n");
+ return ret;
+ }
+
qca8k_current_page = page;
+ usleep_range(1000, 2000);
+ return 0;
}
-static u32
-qca8k_read(struct qca8k_priv *priv, u32 reg)
+static int
+qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val)
{
+ struct mii_bus *bus = priv->bus;
u16 r1, r2, page;
- u32 val;
+ int ret;
qca8k_split_addr(reg, &r1, &r2, &page);
- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
- qca8k_set_page(priv->bus, page);
- val = qca8k_mii_read32(priv->bus, 0x10 | r2, r1);
+ ret = qca8k_set_page(bus, page);
+ if (ret < 0)
+ goto exit;
- mutex_unlock(&priv->bus->mdio_lock);
+ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, val);
- return val;
+exit:
+ mutex_unlock(&bus->mdio_lock);
+ return ret;
}
-static void
+static int
qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val)
{
+ struct mii_bus *bus = priv->bus;
u16 r1, r2, page;
+ int ret;
qca8k_split_addr(reg, &r1, &r2, &page);
- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+ ret = qca8k_set_page(bus, page);
+ if (ret < 0)
+ goto exit;
- qca8k_set_page(priv->bus, page);
- qca8k_mii_write32(priv->bus, 0x10 | r2, r1, val);
+ qca8k_mii_write32(bus, 0x10 | r2, r1, val);
- mutex_unlock(&priv->bus->mdio_lock);
+exit:
+ mutex_unlock(&bus->mdio_lock);
+ return ret;
}
-static u32
-qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 val)
+static int
+qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val)
{
+ struct mii_bus *bus = priv->bus;
u16 r1, r2, page;
- u32 ret;
+ u32 val;
+ int ret;
qca8k_split_addr(reg, &r1, &r2, &page);
- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+ ret = qca8k_set_page(bus, page);
+ if (ret < 0)
+ goto exit;
+
+ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val);
+ if (ret < 0)
+ goto exit;
- qca8k_set_page(priv->bus, page);
- ret = qca8k_mii_read32(priv->bus, 0x10 | r2, r1);
- ret &= ~mask;
- ret |= val;
- qca8k_mii_write32(priv->bus, 0x10 | r2, r1, ret);
+ val &= ~mask;
+ val |= write_val;
+ qca8k_mii_write32(bus, 0x10 | r2, r1, val);
- mutex_unlock(&priv->bus->mdio_lock);
+exit:
+ mutex_unlock(&bus->mdio_lock);
return ret;
}
-static void
+static int
qca8k_reg_set(struct qca8k_priv *priv, u32 reg, u32 val)
{
- qca8k_rmw(priv, reg, 0, val);
+ return qca8k_rmw(priv, reg, 0, val);
}
-static void
+static int
qca8k_reg_clear(struct qca8k_priv *priv, u32 reg, u32 val)
{
- qca8k_rmw(priv, reg, val, 0);
+ return qca8k_rmw(priv, reg, val, 0);
}
static int
@@ -210,9 +239,7 @@ qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
- *val = qca8k_read(priv, reg);
-
- return 0;
+ return qca8k_read(priv, reg, val);
}
static int
@@ -220,9 +247,7 @@ qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
- qca8k_write(priv, reg, val);
-
- return 0;
+ return qca8k_write(priv, reg, val);
}
static const struct regmap_range qca8k_readable_ranges[] = {
@@ -262,32 +287,36 @@ static struct regmap_config qca8k_regmap_config = {
static int
qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
{
- unsigned long timeout;
-
- timeout = jiffies + msecs_to_jiffies(20);
+ int ret, ret1;
+ u32 val;
- /* loop until the busy flag has cleared */
- do {
- u32 val = qca8k_read(priv, reg);
- int busy = val & mask;
+ ret = read_poll_timeout(qca8k_read, ret1, !(val & mask),
+ 0, QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false,
+ priv, reg, &val);
- if (!busy)
- break;
- cond_resched();
- } while (!time_after_eq(jiffies, timeout));
+ /* Check if qca8k_read has failed for a different reason
+ * before returning -ETIMEDOUT
+ */
+ if (ret < 0 && ret1 < 0)
+ return ret1;
- return time_after_eq(jiffies, timeout);
+ return ret;
}
-static void
+static int
qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb)
{
- u32 reg[4];
- int i;
+ u32 reg[4], val;
+ int i, ret;
/* load the ARL table into an array */
- for (i = 0; i < 4; i++)
- reg[i] = qca8k_read(priv, QCA8K_REG_ATU_DATA0 + (i * 4));
+ for (i = 0; i < 4; i++) {
+ ret = qca8k_read(priv, QCA8K_REG_ATU_DATA0 + (i * 4), &val);
+ if (ret < 0)
+ return ret;
+
+ reg[i] = val;
+ }
/* vid - 83:72 */
fdb->vid = (reg[2] >> QCA8K_ATU_VID_S) & QCA8K_ATU_VID_M;
@@ -302,6 +331,8 @@ qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb)
fdb->mac[3] = (reg[0] >> QCA8K_ATU_ADDR3_S) & 0xff;
fdb->mac[4] = (reg[0] >> QCA8K_ATU_ADDR4_S) & 0xff;
fdb->mac[5] = reg[0] & 0xff;
+
+ return 0;
}
static void
@@ -334,6 +365,7 @@ static int
qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port)
{
u32 reg;
+ int ret;
/* Set the command and FDB index */
reg = QCA8K_ATU_FUNC_BUSY;
@@ -344,15 +376,20 @@ qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port)
}
/* Write the function register triggering the table access */
- qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg);
+ ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg);
+ if (ret)
+ return ret;
/* wait for completion */
- if (qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY))
- return -1;
+ ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY);
+ if (ret)
+ return ret;
/* Check for table full violation when adding an entry */
if (cmd == QCA8K_FDB_LOAD) {
- reg = qca8k_read(priv, QCA8K_REG_ATU_FUNC);
+ ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, &reg);
+ if (ret < 0)
+ return ret;
if (reg & QCA8K_ATU_FUNC_FULL)
return -1;
}
@@ -367,10 +404,10 @@ qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port)
qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging);
ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port);
- if (ret >= 0)
- qca8k_fdb_read(priv, fdb);
+ if (ret < 0)
+ return ret;
- return ret;
+ return qca8k_fdb_read(priv, fdb);
}
static int
@@ -412,6 +449,7 @@ static int
qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid)
{
u32 reg;
+ int ret;
/* Set the command and VLAN index */
reg = QCA8K_VTU_FUNC1_BUSY;
@@ -419,15 +457,20 @@ qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid)
reg |= vid << QCA8K_VTU_FUNC1_VID_S;
/* Write the function register triggering the table access */
- qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg);
+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg);
+ if (ret)
+ return ret;
/* wait for completion */
- if (qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY))
- return -ETIMEDOUT;
+ ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY);
+ if (ret)
+ return ret;
/* Check for table full violation when adding an entry */
if (cmd == QCA8K_VLAN_LOAD) {
- reg = qca8k_read(priv, QCA8K_REG_VTU_FUNC1);
+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, &reg);
+ if (ret < 0)
+ return ret;
if (reg & QCA8K_VTU_FUNC1_FULL)
return -ENOMEM;
}
@@ -453,7 +496,9 @@ qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged)
if (ret < 0)
goto out;
- reg = qca8k_read(priv, QCA8K_REG_VTU_FUNC0);
+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, &reg);
+ if (ret < 0)
+ goto out;
reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN;
reg &= ~(QCA8K_VTU_FUNC0_EG_MODE_MASK << QCA8K_VTU_FUNC0_EG_MODE_S(port));
if (untagged)
@@ -463,7 +508,9 @@ qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged)
reg |= QCA8K_VTU_FUNC0_EG_MODE_TAG <<
QCA8K_VTU_FUNC0_EG_MODE_S(port);
- qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
+ if (ret)
+ goto out;
ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid);
out:
@@ -484,7 +531,9 @@ qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid)
if (ret < 0)
goto out;
- reg = qca8k_read(priv, QCA8K_REG_VTU_FUNC0);
+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, &reg);
+ if (ret < 0)
+ goto out;
reg &= ~(3 << QCA8K_VTU_FUNC0_EG_MODE_S(port));
reg |= QCA8K_VTU_FUNC0_EG_MODE_NOT <<
QCA8K_VTU_FUNC0_EG_MODE_S(port);
@@ -504,7 +553,9 @@ qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid)
if (del) {
ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid);
} else {
- qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
+ if (ret)
+ goto out;
ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid);
}
@@ -514,15 +565,29 @@ out:
return ret;
}
-static void
+static int
qca8k_mib_init(struct qca8k_priv *priv)
{
+ int ret;
+
mutex_lock(&priv->reg_mutex);
- qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY);
- qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY);
- qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP);
- qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB);
+ ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY);
+ if (ret)
+ goto exit;
+
+ ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY);
+ if (ret)
+ goto exit;
+
+ ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP);
+ if (ret)
+ goto exit;
+
+ ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB);
+
+exit:
mutex_unlock(&priv->reg_mutex);
+ return ret;
}
static void
@@ -556,54 +621,109 @@ qca8k_port_to_phy(int port)
}
static int
-qca8k_mdio_write(struct qca8k_priv *priv, int port, u32 regnum, u16 data)
+qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask)
{
- u32 phy, val;
+ u16 r1, r2, page;
+ u32 val;
+ int ret, ret1;
+
+ qca8k_split_addr(reg, &r1, &r2, &page);
+
+ ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0,
+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false,
+ bus, 0x10 | r2, r1, &val);
+
+ /* Check if qca8k_read has failed for a different reason
+ * before returnting -ETIMEDOUT
+ */
+ if (ret < 0 && ret1 < 0)
+ return ret1;
+
+ return ret;
+}
+
+static int
+qca8k_mdio_write(struct mii_bus *salve_bus, int phy, int regnum, u16 data)
+{
+ struct qca8k_priv *priv = salve_bus->priv;
+ struct mii_bus *bus = priv->bus;
+ u16 r1, r2, page;
+ u32 val;
+ int ret;
if (regnum >= QCA8K_MDIO_MASTER_MAX_REG)
return -EINVAL;
- /* callee is responsible for not passing bad ports,
- * but we still would like to make spills impossible.
- */
- phy = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN |
QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) |
QCA8K_MDIO_MASTER_REG_ADDR(regnum) |
QCA8K_MDIO_MASTER_DATA(data);
- qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val);
+ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page);
+
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+ ret = qca8k_set_page(bus, page);
+ if (ret)
+ goto exit;
+
+ qca8k_mii_write32(bus, 0x10 | r2, r1, val);
- return qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
- QCA8K_MDIO_MASTER_BUSY);
+ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL,
+ QCA8K_MDIO_MASTER_BUSY);
+
+exit:
+ /* even if the busy_wait timeouts try to clear the MASTER_EN */
+ qca8k_mii_write32(bus, 0x10 | r2, r1, 0);
+
+ mutex_unlock(&bus->mdio_lock);
+
+ return ret;
}
static int
-qca8k_mdio_read(struct qca8k_priv *priv, int port, u32 regnum)
+qca8k_mdio_read(struct mii_bus *salve_bus, int phy, int regnum)
{
- u32 phy, val;
+ struct qca8k_priv *priv = salve_bus->priv;
+ struct mii_bus *bus = priv->bus;
+ u16 r1, r2, page;
+ u32 val;
+ int ret;
if (regnum >= QCA8K_MDIO_MASTER_MAX_REG)
return -EINVAL;
- /* callee is responsible for not passing bad ports,
- * but we still would like to make spills impossible.
- */
- phy = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN |
QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) |
QCA8K_MDIO_MASTER_REG_ADDR(regnum);
- qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val);
+ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page);
+
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+ ret = qca8k_set_page(bus, page);
+ if (ret)
+ goto exit;
+
+ qca8k_mii_write32(bus, 0x10 | r2, r1, val);
- if (qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL,
- QCA8K_MDIO_MASTER_BUSY))
- return -ETIMEDOUT;
+ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL,
+ QCA8K_MDIO_MASTER_BUSY);
+ if (ret)
+ goto exit;
+
+ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val);
+
+exit:
+ /* even if the busy_wait timeouts try to clear the MASTER_EN */
+ qca8k_mii_write32(bus, 0x10 | r2, r1, 0);
- val = (qca8k_read(priv, QCA8K_MDIO_MASTER_CTRL) &
- QCA8K_MDIO_MASTER_DATA_MASK);
+ mutex_unlock(&bus->mdio_lock);
+
+ if (ret >= 0)
+ ret = val & QCA8K_MDIO_MASTER_DATA_MASK;
- return val;
+ return ret;
}
static int
@@ -611,7 +731,14 @@ qca8k_phy_write(struct dsa_switch *ds, int port, int regnum, u16 data)
{
struct qca8k_priv *priv = ds->priv;
- return qca8k_mdio_write(priv, port, regnum, data);
+ /* Check if the legacy mapping should be used and the
+ * port is not correctly mapped to the right PHY in the
+ * devicetree
+ */
+ if (priv->legacy_phy_port_mapping)
+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
+
+ return qca8k_mdio_write(priv->bus, port, regnum, data);
}
static int
@@ -620,7 +747,14 @@ qca8k_phy_read(struct dsa_switch *ds, int port, int regnum)
struct qca8k_priv *priv = ds->priv;
int ret;
- ret = qca8k_mdio_read(priv, port, regnum);
+ /* Check if the legacy mapping should be used and the
+ * port is not correctly mapped to the right PHY in the
+ * devicetree
+ */
+ if (priv->legacy_phy_port_mapping)
+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
+
+ ret = qca8k_mdio_read(priv->bus, port, regnum);
if (ret < 0)
return 0xffff;
@@ -629,14 +763,44 @@ qca8k_phy_read(struct dsa_switch *ds, int port, int regnum)
}
static int
+qca8k_mdio_register(struct qca8k_priv *priv, struct device_node *mdio)
+{
+ struct dsa_switch *ds = priv->ds;
+ struct mii_bus *bus;
+
+ bus = devm_mdiobus_alloc(ds->dev);
+
+ if (!bus)
+ return -ENOMEM;
+
+ bus->priv = (void *)priv;
+ bus->name = "qca8k slave mii";
+ bus->read = qca8k_mdio_read;
+ bus->write = qca8k_mdio_write;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d",
+ ds->index);
+
+ bus->parent = ds->dev;
+ bus->phy_mask = ~ds->phys_mii_mask;
+
+ ds->slave_mii_bus = bus;
+
+ return devm_of_mdiobus_register(priv->dev, bus, mdio);
+}
+
+static int
qca8k_setup_mdio_bus(struct qca8k_priv *priv)
{
u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg;
- struct device_node *ports, *port;
+ struct device_node *ports, *port, *mdio;
+ phy_interface_t mode;
int err;
ports = of_get_child_by_name(priv->dev->of_node, "ports");
if (!ports)
+ ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports");
+
+ if (!ports)
return -EINVAL;
for_each_available_child_of_node(ports, port) {
@@ -650,7 +814,10 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
if (!dsa_is_user_port(priv->ds, reg))
continue;
- if (of_property_read_bool(port, "phy-handle"))
+ of_get_phy_mode(port, &mode);
+
+ if (of_property_read_bool(port, "phy-handle") &&
+ mode != PHY_INTERFACE_MODE_INTERNAL)
external_mdio_mask |= BIT(reg);
else
internal_mdio_mask |= BIT(reg);
@@ -683,13 +850,89 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
* a dt-overlay and driver reload changed the configuration
*/
- qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
- QCA8K_MDIO_MASTER_EN);
- return 0;
+ return qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
+ QCA8K_MDIO_MASTER_EN);
+ }
+
+ /* Check if the devicetree declare the port:phy mapping */
+ mdio = of_get_child_by_name(priv->dev->of_node, "mdio");
+ if (of_device_is_available(mdio)) {
+ err = qca8k_mdio_register(priv, mdio);
+ if (err)
+ of_node_put(mdio);
+
+ return err;
}
+ /* If a mapping can't be found the legacy mapping is used,
+ * using the qca8k_port_to_phy function
+ */
+ priv->legacy_phy_port_mapping = true;
priv->ops.phy_read = qca8k_phy_read;
priv->ops.phy_write = qca8k_phy_write;
+
+ return 0;
+}
+
+static int
+qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv)
+{
+ struct device_node *port_dn;
+ phy_interface_t mode;
+ struct dsa_port *dp;
+ u32 val;
+
+ /* CPU port is already checked */
+ dp = dsa_to_port(priv->ds, 0);
+
+ port_dn = dp->dn;
+
+ /* Check if port 0 is set to the correct type */
+ of_get_phy_mode(port_dn, &mode);
+ if (mode != PHY_INTERFACE_MODE_RGMII_ID &&
+ mode != PHY_INTERFACE_MODE_RGMII_RXID &&
+ mode != PHY_INTERFACE_MODE_RGMII_TXID) {
+ return 0;
+ }
+
+ switch (mode) {
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ if (of_property_read_u32(port_dn, "rx-internal-delay-ps", &val))
+ val = 2;
+ else
+ /* Switch regs accept value in ns, convert ps to ns */
+ val = val / 1000;
+
+ if (val > QCA8K_MAX_DELAY) {
+ dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value");
+ val = 3;
+ }
+
+ priv->rgmii_rx_delay = val;
+ /* Stop here if we need to check only for rx delay */
+ if (mode != PHY_INTERFACE_MODE_RGMII_ID)
+ break;
+
+ fallthrough;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ if (of_property_read_u32(port_dn, "tx-internal-delay-ps", &val))
+ val = 1;
+ else
+ /* Switch regs accept value in ns, convert ps to ns */
+ val = val / 1000;
+
+ if (val > QCA8K_MAX_DELAY) {
+ dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value");
+ val = 3;
+ }
+
+ priv->rgmii_tx_delay = val;
+ break;
+ default:
+ return 0;
+ }
+
return 0;
}
@@ -698,10 +941,11 @@ qca8k_setup(struct dsa_switch *ds)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
int ret, i;
+ u32 mask;
/* Make sure that port 0 is the cpu port */
if (!dsa_is_cpu_port(ds, 0)) {
- pr_err("port 0 is not the CPU port\n");
+ dev_err(priv->dev, "port 0 is not the CPU port");
return -EINVAL;
}
@@ -711,76 +955,163 @@ qca8k_setup(struct dsa_switch *ds)
priv->regmap = devm_regmap_init(ds->dev, NULL, priv,
&qca8k_regmap_config);
if (IS_ERR(priv->regmap))
- pr_warn("regmap initialization failed");
+ dev_warn(priv->dev, "regmap initialization failed");
ret = qca8k_setup_mdio_bus(priv);
if (ret)
return ret;
+ ret = qca8k_setup_of_rgmii_delay(priv);
+ if (ret)
+ return ret;
+
/* Enable CPU Port */
- qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,
- QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
+ ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,
+ QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
+ if (ret) {
+ dev_err(priv->dev, "failed enabling CPU port");
+ return ret;
+ }
/* Enable MIB counters */
- qca8k_mib_init(priv);
+ ret = qca8k_mib_init(priv);
+ if (ret)
+ dev_warn(priv->dev, "mib init failed");
/* Enable QCA header mode on the cpu port */
- qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT),
- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S |
- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S);
+ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT),
+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S |
+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S);
+ if (ret) {
+ dev_err(priv->dev, "failed enabling QCA header mode");
+ return ret;
+ }
/* Disable forwarding by default on all ports */
- for (i = 0; i < QCA8K_NUM_PORTS; i++)
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
- QCA8K_PORT_LOOKUP_MEMBER, 0);
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
+ QCA8K_PORT_LOOKUP_MEMBER, 0);
+ if (ret)
+ return ret;
+ }
/* Disable MAC by default on all ports */
for (i = 1; i < QCA8K_NUM_PORTS; i++)
qca8k_port_set_status(priv, i, 0);
/* Forward all unknown frames to CPU port for Linux processing */
- qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S |
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S |
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S |
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);
+ ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
+ BIT(0) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S |
+ BIT(0) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S |
+ BIT(0) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S |
+ BIT(0) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);
+ if (ret)
+ return ret;
/* Setup connection between CPU port & user ports */
for (i = 0; i < QCA8K_NUM_PORTS; i++) {
/* CPU port gets connected to all user ports of the switch */
if (dsa_is_cpu_port(ds, i)) {
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT),
- QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT),
+ QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
+ if (ret)
+ return ret;
}
/* Individual user ports get connected to CPU port only */
if (dsa_is_user_port(ds, i)) {
int shift = 16 * (i % 2);
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
- QCA8K_PORT_LOOKUP_MEMBER,
- BIT(QCA8K_CPU_PORT));
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
+ QCA8K_PORT_LOOKUP_MEMBER,
+ BIT(QCA8K_CPU_PORT));
+ if (ret)
+ return ret;
/* Enable ARP Auto-learning by default */
- qca8k_reg_set(priv, QCA8K_PORT_LOOKUP_CTRL(i),
- QCA8K_PORT_LOOKUP_LEARN);
+ ret = qca8k_reg_set(priv, QCA8K_PORT_LOOKUP_CTRL(i),
+ QCA8K_PORT_LOOKUP_LEARN);
+ if (ret)
+ return ret;
/* For port based vlans to work we need to set the
* default egress vid
*/
- qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i),
- 0xfff << shift,
- QCA8K_PORT_VID_DEF << shift);
- qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i),
- QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) |
- QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF));
+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i),
+ 0xfff << shift,
+ QCA8K_PORT_VID_DEF << shift);
+ if (ret)
+ return ret;
+
+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i),
+ QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) |
+ QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF));
+ if (ret)
+ return ret;
}
}
+ /* The port 5 of the qca8337 have some problem in flood condition. The
+ * original legacy driver had some specific buffer and priority settings
+ * for the different port suggested by the QCA switch team. Add this
+ * missing settings to improve switch stability under load condition.
+ * This problem is limited to qca8337 and other qca8k switch are not affected.
+ */
+ if (priv->switch_id == QCA8K_ID_QCA8337) {
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
+ switch (i) {
+ /* The 2 CPU port and port 5 requires some different
+ * priority than any other ports.
+ */
+ case 0:
+ case 5:
+ case 6:
+ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) |
+ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e);
+ break;
+ default:
+ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) |
+ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19);
+ }
+ qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask);
+
+ mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) |
+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
+ QCA8K_PORT_HOL_CTRL1_WRED_EN;
+ qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i),
+ QCA8K_PORT_HOL_CTRL1_ING_BUF |
+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
+ QCA8K_PORT_HOL_CTRL1_WRED_EN,
+ mask);
+ }
+ }
+
+ /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */
+ if (priv->switch_id == QCA8K_ID_QCA8327) {
+ mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) |
+ QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496);
+ qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH,
+ QCA8K_GLOBAL_FC_GOL_XON_THRES_S |
+ QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S,
+ mask);
+ }
+
/* Setup our port MTUs to match power on defaults */
for (i = 0; i < QCA8K_NUM_PORTS; i++)
priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN;
- qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN);
+ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN);
+ if (ret)
+ dev_warn(priv->dev, "failed setting MTU settings");
/* Flush the FDB table */
qca8k_fdb_flush(priv);
@@ -797,11 +1128,14 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
{
struct qca8k_priv *priv = ds->priv;
u32 reg, val;
+ int ret;
switch (port) {
case 0: /* 1st CPU port */
if (state->interface != PHY_INTERFACE_MODE_RGMII &&
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
state->interface != PHY_INTERFACE_MODE_SGMII)
return;
@@ -817,6 +1151,8 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
case 6: /* 2nd CPU port / external PHY */
if (state->interface != PHY_INTERFACE_MODE_RGMII &&
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
state->interface != PHY_INTERFACE_MODE_SGMII &&
state->interface != PHY_INTERFACE_MODE_1000BASEX)
return;
@@ -840,16 +1176,22 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN);
break;
case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
/* RGMII_ID needs internal delay. This is enabled through
* PORT5_PAD_CTRL for all ports, rather than individual port
* registers
*/
qca8k_write(priv, reg,
QCA8K_PORT_PAD_RGMII_EN |
- QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) |
- QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY));
- qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
+ QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay) |
+ QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay) |
+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |
QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
+ /* QCA8337 requires to set rgmii rx delay */
+ if (priv->switch_id == QCA8K_ID_QCA8337)
+ qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
break;
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_1000BASEX:
@@ -857,7 +1199,9 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN);
/* Enable/disable SerDes auto-negotiation as necessary */
- val = qca8k_read(priv, QCA8K_REG_PWS);
+ ret = qca8k_read(priv, QCA8K_REG_PWS, &val);
+ if (ret)
+ return;
if (phylink_autoneg_inband(mode))
val &= ~QCA8K_PWS_SERDES_AEN_DIS;
else
@@ -865,7 +1209,9 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
qca8k_write(priv, QCA8K_REG_PWS, val);
/* Configure the SGMII parameters */
- val = qca8k_read(priv, QCA8K_REG_SGMII_CTRL);
+ ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val);
+ if (ret)
+ return;
val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX |
QCA8K_SGMII_EN_TX | QCA8K_SGMII_EN_SD;
@@ -903,6 +1249,8 @@ qca8k_phylink_validate(struct dsa_switch *ds, int port,
if (state->interface != PHY_INTERFACE_MODE_NA &&
state->interface != PHY_INTERFACE_MODE_RGMII &&
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
state->interface != PHY_INTERFACE_MODE_SGMII)
goto unsupported;
break;
@@ -913,13 +1261,16 @@ qca8k_phylink_validate(struct dsa_switch *ds, int port,
case 5:
/* Internal PHY */
if (state->interface != PHY_INTERFACE_MODE_NA &&
- state->interface != PHY_INTERFACE_MODE_GMII)
+ state->interface != PHY_INTERFACE_MODE_GMII &&
+ state->interface != PHY_INTERFACE_MODE_INTERNAL)
goto unsupported;
break;
case 6: /* 2nd CPU port / external PHY */
if (state->interface != PHY_INTERFACE_MODE_NA &&
state->interface != PHY_INTERFACE_MODE_RGMII &&
state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID &&
+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID &&
state->interface != PHY_INTERFACE_MODE_SGMII &&
state->interface != PHY_INTERFACE_MODE_1000BASEX)
goto unsupported;
@@ -955,8 +1306,11 @@ qca8k_phylink_mac_link_state(struct dsa_switch *ds, int port,
{
struct qca8k_priv *priv = ds->priv;
u32 reg;
+ int ret;
- reg = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port));
+ ret = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), &reg);
+ if (ret < 0)
+ return ret;
state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP);
state->an_complete = state->link;
@@ -1057,18 +1411,27 @@ qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
const struct qca8k_mib_desc *mib;
- u32 reg, i;
- u64 hi;
+ u32 reg, i, val;
+ u32 hi = 0;
+ int ret;
for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++) {
mib = &ar8327_mib[i];
reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset;
- data[i] = qca8k_read(priv, reg);
+ ret = qca8k_read(priv, reg, &val);
+ if (ret < 0)
+ continue;
+
if (mib->size == 2) {
- hi = qca8k_read(priv, reg + 4);
- data[i] |= hi << 32;
+ ret = qca8k_read(priv, reg + 4, &hi);
+ if (ret < 0)
+ continue;
}
+
+ data[i] = val;
+ if (mib->size == 2)
+ data[i] |= (u64)hi << 32;
}
}
@@ -1087,17 +1450,22 @@ qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee)
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port);
u32 reg;
+ int ret;
mutex_lock(&priv->reg_mutex);
- reg = qca8k_read(priv, QCA8K_REG_EEE_CTRL);
+ ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, &reg);
+ if (ret < 0)
+ goto exit;
+
if (eee->eee_enabled)
reg |= lpi_en;
else
reg &= ~lpi_en;
- qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg);
- mutex_unlock(&priv->reg_mutex);
+ ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg);
- return 0;
+exit:
+ mutex_unlock(&priv->reg_mutex);
+ return ret;
}
static int
@@ -1141,7 +1509,7 @@ qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
int port_mask = BIT(QCA8K_CPU_PORT);
- int i;
+ int i, ret;
for (i = 1; i < QCA8K_NUM_PORTS; i++) {
if (dsa_to_port(ds, i)->bridge_dev != br)
@@ -1149,17 +1517,20 @@ qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br)
/* Add this port to the portvlan mask of the other ports
* in the bridge
*/
- qca8k_reg_set(priv,
- QCA8K_PORT_LOOKUP_CTRL(i),
- BIT(port));
+ ret = qca8k_reg_set(priv,
+ QCA8K_PORT_LOOKUP_CTRL(i),
+ BIT(port));
+ if (ret)
+ return ret;
if (i != port)
port_mask |= BIT(i);
}
+
/* Add all other ports to this ports portvlan mask */
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
- QCA8K_PORT_LOOKUP_MEMBER, port_mask);
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
+ QCA8K_PORT_LOOKUP_MEMBER, port_mask);
- return 0;
+ return ret;
}
static void
@@ -1223,9 +1594,7 @@ qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
mtu = priv->port_mtu[i];
/* Include L2 header / FCS length */
- qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, mtu + ETH_HLEN + ETH_FCS_LEN);
-
- return 0;
+ return qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, mtu + ETH_HLEN + ETH_FCS_LEN);
}
static int
@@ -1298,18 +1667,19 @@ qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
struct netlink_ext_ack *extack)
{
struct qca8k_priv *priv = ds->priv;
+ int ret;
if (vlan_filtering) {
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
- QCA8K_PORT_LOOKUP_VLAN_MODE,
- QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE);
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
+ QCA8K_PORT_LOOKUP_VLAN_MODE,
+ QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE);
} else {
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
- QCA8K_PORT_LOOKUP_VLAN_MODE,
- QCA8K_PORT_LOOKUP_VLAN_MODE_NONE);
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
+ QCA8K_PORT_LOOKUP_VLAN_MODE,
+ QCA8K_PORT_LOOKUP_VLAN_MODE_NONE);
}
- return 0;
+ return ret;
}
static int
@@ -1320,7 +1690,7 @@ qca8k_port_vlan_add(struct dsa_switch *ds, int port,
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
struct qca8k_priv *priv = ds->priv;
- int ret = 0;
+ int ret;
ret = qca8k_vlan_add(priv, port, vlan->vid, untagged);
if (ret) {
@@ -1331,14 +1701,17 @@ qca8k_port_vlan_add(struct dsa_switch *ds, int port,
if (pvid) {
int shift = 16 * (port % 2);
- qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port),
- 0xfff << shift, vlan->vid << shift);
- qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port),
- QCA8K_PORT_VLAN_CVID(vlan->vid) |
- QCA8K_PORT_VLAN_SVID(vlan->vid));
+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port),
+ 0xfff << shift, vlan->vid << shift);
+ if (ret)
+ return ret;
+
+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port),
+ QCA8K_PORT_VLAN_CVID(vlan->vid) |
+ QCA8K_PORT_VLAN_SVID(vlan->vid));
}
- return 0;
+ return ret;
}
static int
@@ -1346,7 +1719,7 @@ qca8k_port_vlan_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan)
{
struct qca8k_priv *priv = ds->priv;
- int ret = 0;
+ int ret;
ret = qca8k_vlan_del(priv, port, vlan->vid);
if (ret)
@@ -1355,6 +1728,22 @@ qca8k_port_vlan_del(struct dsa_switch *ds, int port,
return ret;
}
+static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port)
+{
+ struct qca8k_priv *priv = ds->priv;
+
+ /* Communicate to the phy internal driver the switch revision.
+ * Based on the switch revision different values needs to be
+ * set to the dbg and mmd reg on the phy.
+ * The first 2 bit are used to communicate the switch revision
+ * to the phy driver.
+ */
+ if (port > 0 && port < 6)
+ return priv->switch_revision;
+
+ return 0;
+}
+
static enum dsa_tag_protocol
qca8k_get_tag_protocol(struct dsa_switch *ds, int port,
enum dsa_tag_protocol mp)
@@ -1388,13 +1777,44 @@ static const struct dsa_switch_ops qca8k_switch_ops = {
.phylink_mac_config = qca8k_phylink_mac_config,
.phylink_mac_link_down = qca8k_phylink_mac_link_down,
.phylink_mac_link_up = qca8k_phylink_mac_link_up,
+ .get_phy_flags = qca8k_get_phy_flags,
};
+static int qca8k_read_switch_id(struct qca8k_priv *priv)
+{
+ const struct qca8k_match_data *data;
+ u32 val;
+ u8 id;
+ int ret;
+
+ /* get the switches ID from the compatible */
+ data = of_device_get_match_data(priv->dev);
+ if (!data)
+ return -ENODEV;
+
+ ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val);
+ if (ret < 0)
+ return -ENODEV;
+
+ id = QCA8K_MASK_CTRL_DEVICE_ID(val & QCA8K_MASK_CTRL_DEVICE_ID_MASK);
+ if (id != data->id) {
+ dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id);
+ return -ENODEV;
+ }
+
+ priv->switch_id = id;
+
+ /* Save revision to communicate to the internal PHY driver */
+ priv->switch_revision = (val & QCA8K_MASK_CTRL_REV_ID_MASK);
+
+ return 0;
+}
+
static int
qca8k_sw_probe(struct mdio_device *mdiodev)
{
struct qca8k_priv *priv;
- u32 id;
+ int ret;
/* allocate the private data struct so that we can probe the switches
* ID register
@@ -1420,12 +1840,10 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
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;
- id &= QCA8K_MASK_CTRL_ID_M;
- if (id != QCA8K_ID_QCA8337)
- return -ENODEV;
+ /* Check the detected switch id */
+ ret = qca8k_read_switch_id(priv);
+ if (ret)
+ return ret;
priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL);
if (!priv->ds)
@@ -1490,9 +1908,18 @@ static int qca8k_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(qca8k_pm_ops,
qca8k_suspend, qca8k_resume);
+static const struct qca8k_match_data qca832x = {
+ .id = QCA8K_ID_QCA8327,
+};
+
+static const struct qca8k_match_data qca833x = {
+ .id = QCA8K_ID_QCA8337,
+};
+
static const struct of_device_id qca8k_of_match[] = {
- { .compatible = "qca,qca8334" },
- { .compatible = "qca,qca8337" },
+ { .compatible = "qca,qca8327", .data = &qca832x },
+ { .compatible = "qca,qca8334", .data = &qca833x },
+ { .compatible = "qca,qca8337", .data = &qca833x },
{ /* sentinel */ },
};
diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h
index 7ca4b93e0bb5..ed3b05ad6745 100644
--- a/drivers/net/dsa/qca8k.h
+++ b/drivers/net/dsa/qca8k.h
@@ -15,9 +15,13 @@
#define QCA8K_NUM_PORTS 7
#define QCA8K_MAX_MTU 9000
+#define PHY_ID_QCA8327 0x004dd034
+#define QCA8K_ID_QCA8327 0x12
#define PHY_ID_QCA8337 0x004dd036
#define QCA8K_ID_QCA8337 0x13
+#define QCA8K_BUSY_WAIT_TIMEOUT 2000
+
#define QCA8K_NUM_FDB_RECORDS 2048
#define QCA8K_CPU_PORT 0
@@ -26,18 +30,19 @@
/* Global control registers */
#define QCA8K_REG_MASK_CTRL 0x000
-#define QCA8K_MASK_CTRL_ID_M 0xff
-#define QCA8K_MASK_CTRL_ID_S 8
+#define QCA8K_MASK_CTRL_REV_ID_MASK GENMASK(7, 0)
+#define QCA8K_MASK_CTRL_REV_ID(x) ((x) >> 0)
+#define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8)
+#define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8)
#define QCA8K_REG_PORT0_PAD_CTRL 0x004
#define QCA8K_REG_PORT5_PAD_CTRL 0x008
#define QCA8K_REG_PORT6_PAD_CTRL 0x00c
#define QCA8K_PORT_PAD_RGMII_EN BIT(26)
-#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) \
- ((0x8 + (x & 0x3)) << 22)
-#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) \
- ((0x10 + (x & 0x3)) << 20)
-#define QCA8K_MAX_DELAY 3
+#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) ((x) << 22)
+#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) ((x) << 20)
+#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25)
#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24)
+#define QCA8K_MAX_DELAY 3
#define QCA8K_PORT_PAD_SGMII_EN BIT(7)
#define QCA8K_REG_PWS 0x010
#define QCA8K_PWS_SERDES_AEN_DIS BIT(7)
@@ -164,6 +169,36 @@
#define QCA8K_PORT_LOOKUP_STATE GENMASK(18, 16)
#define QCA8K_PORT_LOOKUP_LEARN BIT(20)
+#define QCA8K_REG_GLOBAL_FC_THRESH 0x800
+#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) ((x) << 16)
+#define QCA8K_GLOBAL_FC_GOL_XON_THRES_S GENMASK(24, 16)
+#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) ((x) << 0)
+#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S GENMASK(8, 0)
+
+#define QCA8K_REG_PORT_HOL_CTRL0(_i) (0x970 + (_i) * 0x8)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF GENMASK(3, 0)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) ((x) << 0)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF GENMASK(7, 4)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) ((x) << 4)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF GENMASK(11, 8)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) ((x) << 8)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF GENMASK(15, 12)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) ((x) << 12)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF GENMASK(19, 16)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) ((x) << 16)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF GENMASK(23, 20)
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) ((x) << 20)
+#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF GENMASK(29, 24)
+#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) ((x) << 24)
+
+#define QCA8K_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8)
+#define QCA8K_PORT_HOL_CTRL1_ING_BUF GENMASK(3, 0)
+#define QCA8K_PORT_HOL_CTRL1_ING(x) ((x) << 0)
+#define QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN BIT(6)
+#define QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN BIT(7)
+#define QCA8K_PORT_HOL_CTRL1_WRED_EN BIT(8)
+#define QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16)
+
/* Pkt edit registers */
#define QCA8K_EGRESS_VLAN(x) (0x0c70 + (4 * (x / 2)))
@@ -211,7 +246,16 @@ struct ar8xxx_port_status {
int enabled;
};
+struct qca8k_match_data {
+ u8 id;
+};
+
struct qca8k_priv {
+ u8 switch_id;
+ u8 switch_revision;
+ u8 rgmii_tx_delay;
+ u8 rgmii_rx_delay;
+ bool legacy_phy_port_mapping;
struct regmap *regmap;
struct mii_bus *bus;
struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS];
diff --git a/drivers/net/dsa/sja1105/Kconfig b/drivers/net/dsa/sja1105/Kconfig
index 5e83b365f17a..b29d41e5e1e7 100644
--- a/drivers/net/dsa/sja1105/Kconfig
+++ b/drivers/net/dsa/sja1105/Kconfig
@@ -3,11 +3,12 @@ config NET_DSA_SJA1105
tristate "NXP SJA1105 Ethernet switch family support"
depends on NET_DSA && SPI
select NET_DSA_TAG_SJA1105
+ select PCS_XPCS
select PACKING
select CRC32
help
- This is the driver for the NXP SJA1105 automotive Ethernet switch
- family. These are 5-port devices and are managed over an SPI
+ This is the driver for the NXP SJA1105 (5-port) and SJA1110 (10-port)
+ automotive Ethernet switch family. These are managed over an SPI
interface. Probing is handled based on OF bindings and so is the
linkage to PHYLINK. The driver supports the following revisions:
- SJA1105E (Gen. 1, No TT-Ethernet)
@@ -16,6 +17,10 @@ tristate "NXP SJA1105 Ethernet switch family support"
- SJA1105Q (Gen. 2, No SGMII, TT-Ethernet)
- SJA1105R (Gen. 2, SGMII, No TT-Ethernet)
- SJA1105S (Gen. 2, SGMII, TT-Ethernet)
+ - SJA1110A (Gen. 3, SGMII, TT-Ethernet, 100base-TX PHY, 10 ports)
+ - SJA1110B (Gen. 3, SGMII, TT-Ethernet, 100base-TX PHY, 9 ports)
+ - SJA1110C (Gen. 3, SGMII, TT-Ethernet, 100base-TX PHY, 7 ports)
+ - SJA1110D (Gen. 3, SGMII, TT-Ethernet, no 100base-TX PHY, 7 ports)
config NET_DSA_SJA1105_PTP
bool "Support for the PTP clock on the NXP SJA1105 Ethernet switch"
diff --git a/drivers/net/dsa/sja1105/Makefile b/drivers/net/dsa/sja1105/Makefile
index a860e3a910be..40d69e6c0bae 100644
--- a/drivers/net/dsa/sja1105/Makefile
+++ b/drivers/net/dsa/sja1105/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_NET_DSA_SJA1105) += sja1105.o
sja1105-objs := \
sja1105_spi.o \
sja1105_main.o \
+ sja1105_mdio.o \
sja1105_flower.o \
sja1105_ethtool.o \
sja1105_devlink.o \
diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h
index f9e87fb33da0..221c7abdef0e 100644
--- a/drivers/net/dsa/sja1105/sja1105.h
+++ b/drivers/net/dsa/sja1105/sja1105.h
@@ -13,14 +13,12 @@
#include <linux/mutex.h>
#include "sja1105_static_config.h"
-#define SJA1105_NUM_PORTS 5
-#define SJA1105_NUM_TC 8
#define SJA1105ET_FDB_BIN_SIZE 4
/* The hardware value is in multiples of 10 ms.
* The passed parameter is in multiples of 1 ms.
*/
#define SJA1105_AGEING_TIME_MS(ms) ((ms) / 10)
-#define SJA1105_NUM_L2_POLICERS 45
+#define SJA1105_NUM_L2_POLICERS SJA1110_MAX_L2_POLICING_COUNT
typedef enum {
SPI_READ = 0,
@@ -30,6 +28,14 @@ typedef enum {
#include "sja1105_tas.h"
#include "sja1105_ptp.h"
+enum sja1105_stats_area {
+ MAC,
+ HL1,
+ HL2,
+ ETHER,
+ __MAX_SJA1105_STATS_AREA,
+};
+
/* Keeps the different addresses between E/T and P/Q/R/S */
struct sja1105_regs {
u64 device_id;
@@ -39,7 +45,6 @@ struct sja1105_regs {
u64 rgu;
u64 vl_status;
u64 config;
- u64 sgmii;
u64 rmii_pll1;
u64 ptppinst;
u64 ptppindur;
@@ -49,23 +54,41 @@ struct sja1105_regs {
u64 ptpclkcorp;
u64 ptpsyncts;
u64 ptpschtm;
- u64 ptpegr_ts[SJA1105_NUM_PORTS];
- u64 pad_mii_tx[SJA1105_NUM_PORTS];
- u64 pad_mii_rx[SJA1105_NUM_PORTS];
- u64 pad_mii_id[SJA1105_NUM_PORTS];
- u64 cgu_idiv[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];
- u64 mii_ext_rx_clk[SJA1105_NUM_PORTS];
- u64 rgmii_tx_clk[SJA1105_NUM_PORTS];
- u64 rmii_ref_clk[SJA1105_NUM_PORTS];
- u64 rmii_ext_tx_clk[SJA1105_NUM_PORTS];
- u64 mac[SJA1105_NUM_PORTS];
- u64 mac_hl1[SJA1105_NUM_PORTS];
- u64 mac_hl2[SJA1105_NUM_PORTS];
- u64 ether_stats[SJA1105_NUM_PORTS];
- u64 qlevel[SJA1105_NUM_PORTS];
+ u64 ptpegr_ts[SJA1105_MAX_NUM_PORTS];
+ u64 pad_mii_tx[SJA1105_MAX_NUM_PORTS];
+ u64 pad_mii_rx[SJA1105_MAX_NUM_PORTS];
+ u64 pad_mii_id[SJA1105_MAX_NUM_PORTS];
+ u64 cgu_idiv[SJA1105_MAX_NUM_PORTS];
+ u64 mii_tx_clk[SJA1105_MAX_NUM_PORTS];
+ u64 mii_rx_clk[SJA1105_MAX_NUM_PORTS];
+ u64 mii_ext_tx_clk[SJA1105_MAX_NUM_PORTS];
+ u64 mii_ext_rx_clk[SJA1105_MAX_NUM_PORTS];
+ u64 rgmii_tx_clk[SJA1105_MAX_NUM_PORTS];
+ u64 rmii_ref_clk[SJA1105_MAX_NUM_PORTS];
+ u64 rmii_ext_tx_clk[SJA1105_MAX_NUM_PORTS];
+ u64 stats[__MAX_SJA1105_STATS_AREA][SJA1105_MAX_NUM_PORTS];
+ u64 mdio_100base_tx;
+ u64 mdio_100base_t1;
+ u64 pcs_base[SJA1105_MAX_NUM_PORTS];
+};
+
+struct sja1105_mdio_private {
+ struct sja1105_private *priv;
+};
+
+enum {
+ SJA1105_SPEED_AUTO,
+ SJA1105_SPEED_10MBPS,
+ SJA1105_SPEED_100MBPS,
+ SJA1105_SPEED_1000MBPS,
+ SJA1105_SPEED_2500MBPS,
+ SJA1105_SPEED_MAX,
+};
+
+enum sja1105_internal_phy_t {
+ SJA1105_NO_PHY = 0,
+ SJA1105_PHY_BASE_TX,
+ SJA1105_PHY_BASE_T1,
};
struct sja1105_info {
@@ -85,6 +108,10 @@ struct sja1105_info {
*/
int ptpegr_ts_bytes;
int num_cbs_shapers;
+ int max_frame_mem;
+ int num_ports;
+ bool multiple_cascade_ports;
+ enum dsa_tag_protocol tag_proto;
const struct sja1105_dynamic_table_ops *dyn_ops;
const struct sja1105_table_ops *static_ops;
const struct sja1105_regs *regs;
@@ -104,7 +131,20 @@ struct sja1105_info {
const unsigned char *addr, u16 vid);
void (*ptp_cmd_packing)(u8 *buf, struct sja1105_ptp_cmd *cmd,
enum packing_op op);
+ bool (*rxtstamp)(struct dsa_switch *ds, int port, struct sk_buff *skb);
+ void (*txtstamp)(struct dsa_switch *ds, int port, struct sk_buff *skb);
+ int (*clocking_setup)(struct sja1105_private *priv);
+ int (*pcs_mdio_read)(struct mii_bus *bus, int phy, int reg);
+ int (*pcs_mdio_write)(struct mii_bus *bus, int phy, int reg, u16 val);
+ int (*disable_microcontroller)(struct sja1105_private *priv);
const char *name;
+ bool supports_mii[SJA1105_MAX_NUM_PORTS];
+ bool supports_rmii[SJA1105_MAX_NUM_PORTS];
+ bool supports_rgmii[SJA1105_MAX_NUM_PORTS];
+ bool supports_sgmii[SJA1105_MAX_NUM_PORTS];
+ bool supports_2500basex[SJA1105_MAX_NUM_PORTS];
+ enum sja1105_internal_phy_t internal_phy[SJA1105_MAX_NUM_PORTS];
+ const u64 port_speed[SJA1105_SPEED_MAX];
};
enum sja1105_key_type {
@@ -202,20 +242,23 @@ enum sja1105_vlan_state {
struct sja1105_private {
struct sja1105_static_config static_config;
- bool rgmii_rx_delay[SJA1105_NUM_PORTS];
- bool rgmii_tx_delay[SJA1105_NUM_PORTS];
+ bool rgmii_rx_delay[SJA1105_MAX_NUM_PORTS];
+ bool rgmii_tx_delay[SJA1105_MAX_NUM_PORTS];
+ phy_interface_t phy_mode[SJA1105_MAX_NUM_PORTS];
+ bool fixed_link[SJA1105_MAX_NUM_PORTS];
bool best_effort_vlan_filtering;
unsigned long learn_ena;
unsigned long ucast_egress_floods;
unsigned long bcast_egress_floods;
const struct sja1105_info *info;
+ size_t max_xfer_len;
struct gpio_desc *reset_gpio;
struct spi_device *spidev;
struct dsa_switch *ds;
struct list_head dsa_8021q_vlans;
struct list_head bridge_vlans;
struct sja1105_flow_block flow_block;
- struct sja1105_port ports[SJA1105_NUM_PORTS];
+ struct sja1105_port ports[SJA1105_MAX_NUM_PORTS];
/* Serializes transmission of management frames so that
* the switch doesn't confuse them with one another.
*/
@@ -224,6 +267,10 @@ struct sja1105_private {
enum sja1105_vlan_state vlan_state;
struct devlink_region **regions;
struct sja1105_cbs_entry *cbs;
+ struct mii_bus *mdio_base_t1;
+ struct mii_bus *mdio_base_tx;
+ struct mii_bus *mdio_pcs;
+ struct dw_xpcs *xpcs[SJA1105_MAX_NUM_PORTS];
struct sja1105_tagger_data tagger_data;
struct sja1105_ptp_data ptp_data;
struct sja1105_tas_data tas_data;
@@ -253,6 +300,14 @@ int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
struct netlink_ext_ack *extack);
void sja1105_frame_memory_partitioning(struct sja1105_private *priv);
+/* From sja1105_mdio.c */
+int sja1105_mdiobus_register(struct dsa_switch *ds);
+void sja1105_mdiobus_unregister(struct dsa_switch *ds);
+int sja1105_pcs_mdio_read(struct mii_bus *bus, int phy, int reg);
+int sja1105_pcs_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val);
+int sja1110_pcs_mdio_read(struct mii_bus *bus, int phy, int reg);
+int sja1110_pcs_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val);
+
/* From sja1105_devlink.c */
int sja1105_devlink_setup(struct dsa_switch *ds);
void sja1105_devlink_teardown(struct dsa_switch *ds);
@@ -286,6 +341,10 @@ extern const struct sja1105_info sja1105p_info;
extern const struct sja1105_info sja1105q_info;
extern const struct sja1105_info sja1105r_info;
extern const struct sja1105_info sja1105s_info;
+extern const struct sja1105_info sja1110a_info;
+extern const struct sja1105_info sja1110b_info;
+extern const struct sja1105_info sja1110c_info;
+extern const struct sja1105_info sja1110d_info;
/* From sja1105_clocking.c */
@@ -301,16 +360,11 @@ typedef enum {
XMII_MODE_SGMII = 3,
} sja1105_phy_interface_t;
-typedef enum {
- SJA1105_SPEED_10MBPS = 3,
- SJA1105_SPEED_100MBPS = 2,
- SJA1105_SPEED_1000MBPS = 1,
- SJA1105_SPEED_AUTO = 0,
-} sja1105_speed_t;
-
int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port);
+int sja1110_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);
+int sja1110_disable_microcontroller(struct sja1105_private *priv);
/* From sja1105_ethtool.c */
void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data);
@@ -331,6 +385,18 @@ enum sja1105_iotag {
SJA1105_S_TAG = 1, /* Outer VLAN header */
};
+enum sja1110_vlan_type {
+ SJA1110_VLAN_INVALID = 0,
+ SJA1110_VLAN_C_TAG = 1, /* Single inner VLAN tag */
+ SJA1110_VLAN_S_TAG = 2, /* Single outer VLAN tag */
+ SJA1110_VLAN_D_TAG = 3, /* Double tagged, use outer tag for lookup */
+};
+
+enum sja1110_shaper_type {
+ SJA1110_LEAKY_BUCKET_SHAPER = 0,
+ SJA1110_CBS_SHAPER = 1,
+};
+
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);
diff --git a/drivers/net/dsa/sja1105/sja1105_clocking.c b/drivers/net/dsa/sja1105/sja1105_clocking.c
index 2a9b8a6a5306..387a1f2f161c 100644
--- a/drivers/net/dsa/sja1105/sja1105_clocking.c
+++ b/drivers/net/dsa/sja1105/sja1105_clocking.c
@@ -6,6 +6,8 @@
#include "sja1105.h"
#define SJA1105_SIZE_CGU_CMD 4
+#define SJA1110_BASE_MCSS_CLK SJA1110_CGU_ADDR(0x70)
+#define SJA1110_BASE_TIMER_CLK SJA1110_CGU_ADDR(0x74)
/* Common structure for CFG_PAD_MIIx_RX and CFG_PAD_MIIx_TX */
struct sja1105_cfg_pad_mii {
@@ -61,6 +63,12 @@ struct sja1105_cgu_pll_ctrl {
u64 pd;
};
+struct sja1110_cgu_outclk {
+ u64 clksrc;
+ u64 autoblock;
+ u64 pd;
+};
+
enum {
CLKSRC_MII0_TX_CLK = 0x00,
CLKSRC_MII0_RX_CLK = 0x01,
@@ -110,6 +118,9 @@ static int sja1105_cgu_idiv_config(struct sja1105_private *priv, int port,
struct sja1105_cgu_idiv idiv;
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ if (regs->cgu_idiv[port] == SJA1105_RSV_ADDR)
+ return 0;
+
if (enabled && factor != 1 && factor != 10) {
dev_err(dev, "idiv factor must be 1 or 10\n");
return -ERANGE;
@@ -159,6 +170,9 @@ static int sja1105_cgu_mii_tx_clk_config(struct sja1105_private *priv,
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
int clksrc;
+ if (regs->mii_tx_clk[port] == SJA1105_RSV_ADDR)
+ return 0;
+
if (role == XMII_MAC)
clksrc = mac_clk_sources[port];
else
@@ -188,6 +202,9 @@ sja1105_cgu_mii_rx_clk_config(struct sja1105_private *priv, int port)
CLKSRC_MII4_RX_CLK,
};
+ if (regs->mii_rx_clk[port] == SJA1105_RSV_ADDR)
+ return 0;
+
/* Payload for packed_buf */
mii_rx_clk.clksrc = clk_sources[port];
mii_rx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
@@ -212,6 +229,9 @@ sja1105_cgu_mii_ext_tx_clk_config(struct sja1105_private *priv, int port)
CLKSRC_IDIV4,
};
+ if (regs->mii_ext_tx_clk[port] == SJA1105_RSV_ADDR)
+ return 0;
+
/* Payload for packed_buf */
mii_ext_tx_clk.clksrc = clk_sources[port];
mii_ext_tx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
@@ -236,6 +256,9 @@ sja1105_cgu_mii_ext_rx_clk_config(struct sja1105_private *priv, int port)
CLKSRC_IDIV4,
};
+ if (regs->mii_ext_rx_clk[port] == SJA1105_RSV_ADDR)
+ return 0;
+
/* Payload for packed_buf */
mii_ext_rx_clk.clksrc = clk_sources[port];
mii_ext_rx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
@@ -313,14 +336,17 @@ sja1105_cgu_pll_control_packing(void *buf, struct sja1105_cgu_pll_ctrl *cmd,
}
static int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv,
- int port, sja1105_speed_t speed)
+ int port, u64 speed)
{
const struct sja1105_regs *regs = priv->info->regs;
struct sja1105_cgu_mii_ctrl txc;
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
int clksrc;
- if (speed == SJA1105_SPEED_1000MBPS) {
+ if (regs->rgmii_tx_clk[port] == SJA1105_RSV_ADDR)
+ return 0;
+
+ if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) {
clksrc = CLKSRC_PLL0;
} else {
int clk_sources[] = {CLKSRC_IDIV0, CLKSRC_IDIV1, CLKSRC_IDIV2,
@@ -368,6 +394,9 @@ static int sja1105_rgmii_cfg_pad_tx_config(struct sja1105_private *priv,
struct sja1105_cfg_pad_mii pad_mii_tx = {0};
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ if (regs->pad_mii_tx[port] == SJA1105_RSV_ADDR)
+ return 0;
+
/* Payload */
pad_mii_tx.d32_os = 3; /* TXD[3:2] output stage: */
/* high noise/high speed */
@@ -394,6 +423,9 @@ static int sja1105_cfg_pad_rx_config(struct sja1105_private *priv, int port)
struct sja1105_cfg_pad_mii pad_mii_rx = {0};
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ if (regs->pad_mii_rx[port] == SJA1105_RSV_ADDR)
+ return 0;
+
/* Payload */
pad_mii_rx.d32_ih = 0; /* RXD[3:2] input stage hysteresis: */
/* non-Schmitt (default) */
@@ -437,6 +469,35 @@ sja1105_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
sja1105_packing(buf, &cmd->txc_pd, 0, 0, size, op);
}
+static void
+sja1110_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;
+ u64 range = 4;
+
+ /* Fields RXC_RANGE and TXC_RANGE select the input frequency range:
+ * 0 = 2.5MHz
+ * 1 = 25MHz
+ * 2 = 50MHz
+ * 3 = 125MHz
+ * 4 = Automatically determined by port speed.
+ * There's no point in defining a structure different than the one for
+ * SJA1105, so just hardcode the frequency range to automatic, just as
+ * before.
+ */
+ sja1105_packing(buf, &cmd->rxc_stable_ovr, 26, 26, size, op);
+ sja1105_packing(buf, &cmd->rxc_delay, 25, 21, size, op);
+ sja1105_packing(buf, &range, 20, 18, size, op);
+ sja1105_packing(buf, &cmd->rxc_bypass, 17, 17, size, op);
+ sja1105_packing(buf, &cmd->rxc_pd, 16, 16, size, op);
+ sja1105_packing(buf, &cmd->txc_stable_ovr, 10, 10, size, op);
+ sja1105_packing(buf, &cmd->txc_delay, 9, 5, size, op);
+ sja1105_packing(buf, &range, 4, 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 u64 sja1105_rgmii_delay(u64 phase)
{
@@ -495,40 +556,65 @@ int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port)
packed_buf, SJA1105_SIZE_CGU_CMD);
}
+int sja1110_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};
+
+ pad_mii_id.rxc_pd = 1;
+ pad_mii_id.txc_pd = 1;
+
+ if (priv->rgmii_rx_delay[port]) {
+ pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
+ /* The "BYPASS" bit in SJA1110 is actually a "don't bypass" */
+ pad_mii_id.rxc_bypass = 1;
+ pad_mii_id.rxc_pd = 0;
+ }
+
+ if (priv->rgmii_tx_delay[port]) {
+ pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
+ pad_mii_id.txc_bypass = 1;
+ pad_mii_id.txc_pd = 0;
+ }
+
+ sja1110_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
+
+ return sja1105_xfer_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;
- sja1105_speed_t speed;
+ u64 speed;
int rc;
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
speed = mac[port].speed;
- dev_dbg(dev, "Configuring port %d RGMII at speed %dMbps\n",
+ dev_dbg(dev, "Configuring port %d RGMII at speed %lldMbps\n",
port, speed);
- switch (speed) {
- case SJA1105_SPEED_1000MBPS:
+ if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) {
/* 1000Mbps, IDIV disabled (125 MHz) */
rc = sja1105_cgu_idiv_config(priv, port, false, 1);
- break;
- case SJA1105_SPEED_100MBPS:
+ } else if (speed == priv->info->port_speed[SJA1105_SPEED_100MBPS]) {
/* 100Mbps, IDIV enabled, divide by 1 (25 MHz) */
rc = sja1105_cgu_idiv_config(priv, port, true, 1);
- break;
- case SJA1105_SPEED_10MBPS:
+ } else if (speed == priv->info->port_speed[SJA1105_SPEED_10MBPS]) {
/* 10Mbps, IDIV enabled, divide by 10 (2.5 MHz) */
rc = sja1105_cgu_idiv_config(priv, port, true, 10);
- break;
- case SJA1105_SPEED_AUTO:
+ } else if (speed == priv->info->port_speed[SJA1105_SPEED_AUTO]) {
/* Skip CGU configuration if there is no speed available
* (e.g. link is not established yet)
*/
dev_dbg(dev, "Speed not available, skipping CGU config\n");
return 0;
- default:
+ } else {
rc = -EINVAL;
}
@@ -546,14 +632,9 @@ static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
dev_err(dev, "Failed to configure Tx pad registers\n");
return rc;
}
+
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);
}
@@ -572,6 +653,9 @@ static int sja1105_cgu_rmii_ref_clk_config(struct sja1105_private *priv,
CLKSRC_MII4_TX_CLK,
};
+ if (regs->rmii_ref_clk[port] == SJA1105_RSV_ADDR)
+ return 0;
+
/* Payload for packed_buf */
ref_clk.clksrc = clk_sources[port];
ref_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
@@ -589,6 +673,9 @@ sja1105_cgu_rmii_ext_tx_clk_config(struct sja1105_private *priv, int port)
struct sja1105_cgu_mii_ctrl ext_tx_clk;
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ if (regs->rmii_ext_tx_clk[port] == SJA1105_RSV_ADDR)
+ return 0;
+
/* Payload for packed_buf */
ext_tx_clk.clksrc = CLKSRC_PLL1;
ext_tx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
@@ -607,6 +694,9 @@ static int sja1105_cgu_rmii_pll_config(struct sja1105_private *priv)
struct device *dev = priv->ds->dev;
int rc;
+ if (regs->rmii_pll1 == SJA1105_RSV_ADDR)
+ return 0;
+
/* PLL1 must be enabled and output 50 Mhz.
* This is done by writing first 0x0A010941 to
* the PLL_1_C register and then deasserting
@@ -721,12 +811,52 @@ int sja1105_clocking_setup_port(struct sja1105_private *priv, int port)
int sja1105_clocking_setup(struct sja1105_private *priv)
{
+ struct dsa_switch *ds = priv->ds;
int port, rc;
- for (port = 0; port < SJA1105_NUM_PORTS; port++) {
+ for (port = 0; port < ds->num_ports; port++) {
rc = sja1105_clocking_setup_port(priv, port);
if (rc < 0)
return rc;
}
return 0;
}
+
+static void
+sja1110_cgu_outclk_packing(void *buf, struct sja1110_cgu_outclk *outclk,
+ enum packing_op op)
+{
+ const int size = 4;
+
+ sja1105_packing(buf, &outclk->clksrc, 27, 24, size, op);
+ sja1105_packing(buf, &outclk->autoblock, 11, 11, size, op);
+ sja1105_packing(buf, &outclk->pd, 0, 0, size, op);
+}
+
+int sja1110_disable_microcontroller(struct sja1105_private *priv)
+{
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ struct sja1110_cgu_outclk outclk_6_c = {
+ .clksrc = 0x3,
+ .pd = true,
+ };
+ struct sja1110_cgu_outclk outclk_7_c = {
+ .clksrc = 0x5,
+ .pd = true,
+ };
+ int rc;
+
+ /* Power down the BASE_TIMER_CLK to disable the watchdog timer */
+ sja1110_cgu_outclk_packing(packed_buf, &outclk_7_c, PACK);
+
+ rc = sja1105_xfer_buf(priv, SPI_WRITE, SJA1110_BASE_TIMER_CLK,
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+ if (rc)
+ return rc;
+
+ /* Power down the BASE_MCSS_CLOCK to gate the microcontroller off */
+ sja1110_cgu_outclk_packing(packed_buf, &outclk_6_c, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, SJA1110_BASE_MCSS_CLK,
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
diff --git a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c
index 12cd04b56803..56fead68ea9f 100644
--- a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c
+++ b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c
@@ -78,6 +78,9 @@
* 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.
+ * OP_VALID_ANYWAY: Reading some tables through the dynamic config
+ * interface is possible even if the VALIDENT bit is not
+ * set in the writeback. So don't error out in that case.
* - .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
@@ -103,6 +106,9 @@
#define SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD \
(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_VL_LOOKUP_ENTRY)
+#define SJA1110_SIZE_VL_POLICING_DYN_CMD \
+ (SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_VL_POLICING_ENTRY)
+
#define SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY \
SJA1105_SIZE_DYN_CMD
@@ -112,9 +118,15 @@
#define SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD \
(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY)
+#define SJA1110_SIZE_L2_LOOKUP_DYN_CMD \
+ (SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_L2_LOOKUP_ENTRY)
+
#define SJA1105_SIZE_VLAN_LOOKUP_DYN_CMD \
(SJA1105_SIZE_DYN_CMD + 4 + SJA1105_SIZE_VLAN_LOOKUP_ENTRY)
+#define SJA1110_SIZE_VLAN_LOOKUP_DYN_CMD \
+ (SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_VLAN_LOOKUP_ENTRY)
+
#define SJA1105_SIZE_L2_FORWARDING_DYN_CMD \
(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_FORWARDING_ENTRY)
@@ -130,12 +142,18 @@
#define SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_DYN_CMD \
(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY)
+#define SJA1110_SIZE_L2_LOOKUP_PARAMS_DYN_CMD \
+ (SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_L2_LOOKUP_PARAMS_ENTRY)
+
#define SJA1105ET_SIZE_GENERAL_PARAMS_DYN_CMD \
SJA1105_SIZE_DYN_CMD
#define SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD \
(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY)
+#define SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD \
+ (SJA1105_SIZE_DYN_CMD + SJA1110_SIZE_GENERAL_PARAMS_ENTRY)
+
#define SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD \
(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY)
@@ -148,8 +166,17 @@
#define SJA1105PQRS_SIZE_CBS_DYN_CMD \
(SJA1105_SIZE_DYN_CMD + SJA1105PQRS_SIZE_CBS_ENTRY)
+#define SJA1110_SIZE_XMII_PARAMS_DYN_CMD \
+ SJA1110_SIZE_XMII_PARAMS_ENTRY
+
+#define SJA1110_SIZE_L2_POLICING_DYN_CMD \
+ (SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_L2_POLICING_ENTRY)
+
+#define SJA1110_SIZE_L2_FORWARDING_PARAMS_DYN_CMD \
+ SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY
+
#define SJA1105_MAX_DYN_CMD_SIZE \
- SJA1105PQRS_SIZE_GENERAL_PARAMS_DYN_CMD
+ SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD
struct sja1105_dyn_cmd {
bool search;
@@ -194,6 +221,19 @@ sja1105pqrs_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
sja1105_packing(p, &cmd->index, 9, 0, size, op);
}
+static void
+sja1110_vl_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;
+
+ 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->index, 11, 0, size, op);
+}
+
static size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -206,11 +246,23 @@ static size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr,
}
static void
-sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
- enum packing_op op)
+sja1110_vl_policing_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+ enum packing_op op)
+{
+ u8 *p = buf + SJA1105_SIZE_VL_LOOKUP_ENTRY;
+ const int size = SJA1105_SIZE_DYN_CMD;
+
+ sja1105_packing(p, &cmd->valid, 31, 31, size, op);
+ sja1105_packing(p, &cmd->rdwrset, 30, 30, size, op);
+ sja1105_packing(p, &cmd->index, 11, 0, size, op);
+}
+
+static void
+sja1105pqrs_common_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+ enum packing_op op, int entry_size)
{
- u8 *p = buf + SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
const int size = SJA1105_SIZE_DYN_CMD;
+ u8 *p = buf + entry_size;
u64 hostcmd;
sja1105_packing(p, &cmd->valid, 31, 31, size, op);
@@ -265,6 +317,24 @@ sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY, op);
}
+static void
+sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+ enum packing_op op)
+{
+ int size = SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY;
+
+ return sja1105pqrs_common_l2_lookup_cmd_packing(buf, cmd, op, size);
+}
+
+static void
+sja1110_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+ enum packing_op op)
+{
+ int size = SJA1110_SIZE_L2_LOOKUP_ENTRY;
+
+ return sja1105pqrs_common_l2_lookup_cmd_packing(buf, cmd, op, size);
+}
+
/* The switch is so retarded that it makes our command/entry abstraction
* crumble apart.
*
@@ -323,6 +393,18 @@ sja1105pqrs_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
return sja1105pqrs_l2_lookup_entry_packing(buf, entry_ptr, op);
}
+static size_t sja1110_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 + SJA1110_SIZE_L2_LOOKUP_ENTRY;
+ const int size = SJA1105_SIZE_DYN_CMD;
+
+ sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
+
+ return sja1110_l2_lookup_entry_packing(buf, entry_ptr, op);
+}
+
static void
sja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
enum packing_op op)
@@ -434,6 +516,39 @@ sja1105_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
SJA1105_SIZE_VLAN_LOOKUP_ENTRY, op);
}
+/* In SJA1110 there is no gap between the command and the data, yay... */
+static void
+sja1110_vlan_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+ enum packing_op op)
+{
+ u8 *p = buf + SJA1110_SIZE_VLAN_LOOKUP_ENTRY;
+ const int size = SJA1105_SIZE_DYN_CMD;
+ u64 type_entry = 0;
+
+ 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);
+ /* Hack: treat 'vlanid' field of struct sja1105_vlan_lookup_entry as
+ * cmd->index.
+ */
+ sja1105_packing(buf, &cmd->index, 38, 27,
+ SJA1110_SIZE_VLAN_LOOKUP_ENTRY, op);
+
+ /* But the VALIDENT bit has disappeared, now we are supposed to
+ * invalidate an entry through the TYPE_ENTRY field of the entry..
+ * This is a hack to transform the non-zero quality of the TYPE_ENTRY
+ * field into a VALIDENT bit.
+ */
+ if (op == PACK && !cmd->valident) {
+ sja1105_packing(buf, &type_entry, 40, 39,
+ SJA1110_SIZE_VLAN_LOOKUP_ENTRY, PACK);
+ } else if (op == UNPACK) {
+ sja1105_packing(buf, &type_entry, 40, 39,
+ SJA1110_SIZE_VLAN_LOOKUP_ENTRY, UNPACK);
+ cmd->valident = !!type_entry;
+ }
+}
+
static void
sja1105_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
enum packing_op op)
@@ -448,6 +563,19 @@ sja1105_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
}
static void
+sja1110_l2_forwarding_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+ enum packing_op op)
+{
+ u8 *p = buf + SJA1105_SIZE_L2_FORWARDING_ENTRY;
+ const int size = SJA1105_SIZE_DYN_CMD;
+
+ 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->index, 4, 0, size, op);
+}
+
+static void
sja1105et_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
enum packing_op op)
{
@@ -502,6 +630,19 @@ sja1105pqrs_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
}
static void
+sja1110_mac_config_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+ enum packing_op op)
+{
+ u8 *p = buf + SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
+ const int size = SJA1105_SIZE_DYN_CMD;
+
+ 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->index, 3, 0, size, op);
+}
+
+static void
sja1105et_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
enum packing_op op)
{
@@ -534,6 +675,18 @@ sja1105pqrs_l2_lookup_params_cmd_packing(void *buf,
}
static void
+sja1110_l2_lookup_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+ enum packing_op op)
+{
+ u8 *p = buf + SJA1110_SIZE_L2_LOOKUP_PARAMS_ENTRY;
+ const int size = SJA1105_SIZE_DYN_CMD;
+
+ 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);
+}
+
+static void
sja1105et_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
enum packing_op op)
{
@@ -568,6 +721,18 @@ sja1105pqrs_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
}
static void
+sja1110_general_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+ enum packing_op op)
+{
+ u8 *p = buf + SJA1110_SIZE_GENERAL_PARAMS_ENTRY;
+ const int size = SJA1105_SIZE_DYN_CMD;
+
+ 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);
+}
+
+static void
sja1105pqrs_avb_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
enum packing_op op)
{
@@ -593,6 +758,20 @@ sja1105_retagging_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
sja1105_packing(p, &cmd->index, 5, 0, size, op);
}
+static void
+sja1110_retagging_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+ enum packing_op op)
+{
+ u8 *p = buf + SJA1105_SIZE_RETAGGING_ENTRY;
+ const int size = SJA1105_SIZE_DYN_CMD;
+
+ 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, 28, 28, size, op);
+ sja1105_packing(p, &cmd->index, 4, 0, size, op);
+}
+
static void sja1105et_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
enum packing_op op)
{
@@ -632,6 +811,18 @@ static void sja1105pqrs_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
sja1105_packing(p, &cmd->index, 3, 0, size, op);
}
+static void sja1110_cbs_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+ enum packing_op op)
+{
+ u8 *p = buf + SJA1105PQRS_SIZE_CBS_ENTRY;
+ const int size = SJA1105_SIZE_DYN_CMD;
+
+ 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->index, 7, 0, size, op);
+}
+
static size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -647,10 +838,44 @@ static size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr,
return size;
}
+static size_t sja1110_cbs_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105PQRS_SIZE_CBS_ENTRY;
+ struct sja1105_cbs_entry *entry = entry_ptr;
+ u64 entry_type = SJA1110_CBS_SHAPER;
+
+ sja1105_packing(buf, &entry_type, 159, 159, size, op);
+ sja1105_packing(buf, &entry->credit_lo, 151, 120, size, op);
+ sja1105_packing(buf, &entry->credit_hi, 119, 88, size, op);
+ sja1105_packing(buf, &entry->send_slope, 87, 56, size, op);
+ sja1105_packing(buf, &entry->idle_slope, 55, 24, size, op);
+ return size;
+}
+
+static void sja1110_dummy_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+ enum packing_op op)
+{
+}
+
+static void
+sja1110_l2_policing_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
+ enum packing_op op)
+{
+ u8 *p = buf + SJA1105_SIZE_L2_POLICING_ENTRY;
+ const int size = SJA1105_SIZE_DYN_CMD;
+
+ 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->index, 6, 0, size, op);
+}
+
#define OP_READ BIT(0)
#define OP_WRITE BIT(1)
#define OP_DEL BIT(2)
#define OP_SEARCH BIT(3)
+#define OP_VALID_ANYWAY BIT(4)
/* SJA1105E/T: First generation */
const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
@@ -673,7 +898,7 @@ const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
[BLK_IDX_MGMT_ROUTE] = {
.entry_packing = sja1105et_mgmt_route_entry_packing,
.cmd_packing = sja1105et_mgmt_route_cmd_packing,
- .access = (OP_READ | OP_WRITE),
+ .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
.max_entry_count = SJA1105_NUM_PORTS,
.packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
.addr = 0x20,
@@ -757,7 +982,7 @@ const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
[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),
+ .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH | OP_VALID_ANYWAY),
.max_entry_count = SJA1105_NUM_PORTS,
.packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
.addr = 0x24,
@@ -828,6 +1053,122 @@ const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
},
};
+/* SJA1110: Third generation */
+const struct sja1105_dynamic_table_ops sja1110_dyn_ops[BLK_IDX_MAX_DYN] = {
+ [BLK_IDX_VL_LOOKUP] = {
+ .entry_packing = sja1110_vl_lookup_entry_packing,
+ .cmd_packing = sja1110_vl_lookup_cmd_packing,
+ .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
+ .max_entry_count = SJA1110_MAX_VL_LOOKUP_COUNT,
+ .packed_size = SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD,
+ .addr = SJA1110_SPI_ADDR(0x124),
+ },
+ [BLK_IDX_VL_POLICING] = {
+ .entry_packing = sja1110_vl_policing_entry_packing,
+ .cmd_packing = sja1110_vl_policing_cmd_packing,
+ .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
+ .max_entry_count = SJA1110_MAX_VL_POLICING_COUNT,
+ .packed_size = SJA1110_SIZE_VL_POLICING_DYN_CMD,
+ .addr = SJA1110_SPI_ADDR(0x310),
+ },
+ [BLK_IDX_L2_LOOKUP] = {
+ .entry_packing = sja1110_dyn_l2_lookup_entry_packing,
+ .cmd_packing = sja1110_l2_lookup_cmd_packing,
+ .access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
+ .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
+ .packed_size = SJA1110_SIZE_L2_LOOKUP_DYN_CMD,
+ .addr = SJA1110_SPI_ADDR(0x8c),
+ },
+ [BLK_IDX_VLAN_LOOKUP] = {
+ .entry_packing = sja1110_vlan_lookup_entry_packing,
+ .cmd_packing = sja1110_vlan_lookup_cmd_packing,
+ .access = (OP_READ | OP_WRITE | OP_DEL),
+ .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
+ .packed_size = SJA1110_SIZE_VLAN_LOOKUP_DYN_CMD,
+ .addr = SJA1110_SPI_ADDR(0xb4),
+ },
+ [BLK_IDX_L2_FORWARDING] = {
+ .entry_packing = sja1110_l2_forwarding_entry_packing,
+ .cmd_packing = sja1110_l2_forwarding_cmd_packing,
+ .max_entry_count = SJA1110_MAX_L2_FORWARDING_COUNT,
+ .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
+ .packed_size = SJA1105_SIZE_L2_FORWARDING_DYN_CMD,
+ .addr = SJA1110_SPI_ADDR(0xa8),
+ },
+ [BLK_IDX_MAC_CONFIG] = {
+ .entry_packing = sja1110_mac_config_entry_packing,
+ .cmd_packing = sja1110_mac_config_cmd_packing,
+ .max_entry_count = SJA1110_MAX_MAC_CONFIG_COUNT,
+ .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
+ .packed_size = SJA1105PQRS_SIZE_MAC_CONFIG_DYN_CMD,
+ .addr = SJA1110_SPI_ADDR(0x134),
+ },
+ [BLK_IDX_L2_LOOKUP_PARAMS] = {
+ .entry_packing = sja1110_l2_lookup_params_entry_packing,
+ .cmd_packing = sja1110_l2_lookup_params_cmd_packing,
+ .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
+ .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
+ .packed_size = SJA1110_SIZE_L2_LOOKUP_PARAMS_DYN_CMD,
+ .addr = SJA1110_SPI_ADDR(0x158),
+ },
+ [BLK_IDX_AVB_PARAMS] = {
+ .entry_packing = sja1105pqrs_avb_params_entry_packing,
+ .cmd_packing = sja1105pqrs_avb_params_cmd_packing,
+ .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
+ .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
+ .packed_size = SJA1105PQRS_SIZE_AVB_PARAMS_DYN_CMD,
+ .addr = SJA1110_SPI_ADDR(0x2000C),
+ },
+ [BLK_IDX_GENERAL_PARAMS] = {
+ .entry_packing = sja1110_general_params_entry_packing,
+ .cmd_packing = sja1110_general_params_cmd_packing,
+ .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
+ .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
+ .packed_size = SJA1110_SIZE_GENERAL_PARAMS_DYN_CMD,
+ .addr = SJA1110_SPI_ADDR(0xe8),
+ },
+ [BLK_IDX_RETAGGING] = {
+ .entry_packing = sja1110_retagging_entry_packing,
+ .cmd_packing = sja1110_retagging_cmd_packing,
+ .max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
+ .access = (OP_READ | OP_WRITE | OP_DEL),
+ .packed_size = SJA1105_SIZE_RETAGGING_DYN_CMD,
+ .addr = SJA1110_SPI_ADDR(0xdc),
+ },
+ [BLK_IDX_CBS] = {
+ .entry_packing = sja1110_cbs_entry_packing,
+ .cmd_packing = sja1110_cbs_cmd_packing,
+ .max_entry_count = SJA1110_MAX_CBS_COUNT,
+ .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
+ .packed_size = SJA1105PQRS_SIZE_CBS_DYN_CMD,
+ .addr = SJA1110_SPI_ADDR(0xc4),
+ },
+ [BLK_IDX_XMII_PARAMS] = {
+ .entry_packing = sja1110_xmii_params_entry_packing,
+ .cmd_packing = sja1110_dummy_cmd_packing,
+ .max_entry_count = SJA1105_MAX_XMII_PARAMS_COUNT,
+ .access = (OP_READ | OP_VALID_ANYWAY),
+ .packed_size = SJA1110_SIZE_XMII_PARAMS_DYN_CMD,
+ .addr = SJA1110_SPI_ADDR(0x3c),
+ },
+ [BLK_IDX_L2_POLICING] = {
+ .entry_packing = sja1110_l2_policing_entry_packing,
+ .cmd_packing = sja1110_l2_policing_cmd_packing,
+ .max_entry_count = SJA1110_MAX_L2_POLICING_COUNT,
+ .access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
+ .packed_size = SJA1110_SIZE_L2_POLICING_DYN_CMD,
+ .addr = SJA1110_SPI_ADDR(0x2fc),
+ },
+ [BLK_IDX_L2_FORWARDING_PARAMS] = {
+ .entry_packing = sja1110_l2_forwarding_params_entry_packing,
+ .cmd_packing = sja1110_dummy_cmd_packing,
+ .max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
+ .access = (OP_READ | OP_VALID_ANYWAY),
+ .packed_size = SJA1110_SIZE_L2_FORWARDING_PARAMS_DYN_CMD,
+ .addr = SJA1110_SPI_ADDR(0x20000),
+ },
+};
+
/* 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.
@@ -911,11 +1252,8 @@ int sja1105_dynamic_config_read(struct sja1105_private *priv,
cmd = (struct sja1105_dyn_cmd) {0};
ops->cmd_packing(packed_buf, &cmd, UNPACK);
- /* UM10944: [valident] will always be found cleared
- * during a read access with MGMTROUTE set.
- * So don't error out in that case.
- */
- if (!cmd.valident && blk_idx != BLK_IDX_MGMT_ROUTE)
+
+ if (!cmd.valident && !(ops->access & OP_VALID_ANYWAY))
return -ENOENT;
cpu_relax();
} while (cmd.valid && --retries);
diff --git a/drivers/net/dsa/sja1105/sja1105_dynamic_config.h b/drivers/net/dsa/sja1105/sja1105_dynamic_config.h
index 28d4eb5efb8b..a1472f80a059 100644
--- a/drivers/net/dsa/sja1105/sja1105_dynamic_config.h
+++ b/drivers/net/dsa/sja1105/sja1105_dynamic_config.h
@@ -36,5 +36,6 @@ struct sja1105_mgmt_entry {
extern const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN];
extern const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN];
+extern const struct sja1105_dynamic_table_ops sja1110_dyn_ops[BLK_IDX_MAX_DYN];
#endif
diff --git a/drivers/net/dsa/sja1105/sja1105_ethtool.c b/drivers/net/dsa/sja1105/sja1105_ethtool.c
index 9133a831ec79..decc6c931dc1 100644
--- a/drivers/net/dsa/sja1105/sja1105_ethtool.c
+++ b/drivers/net/dsa/sja1105/sja1105_ethtool.c
@@ -3,552 +3,627 @@
*/
#include "sja1105.h"
-#define SJA1105_SIZE_MAC_AREA (0x02 * 4)
-#define SJA1105_SIZE_HL1_AREA (0x10 * 4)
-#define SJA1105_SIZE_HL2_AREA (0x4 * 4)
-#define SJA1105_SIZE_QLEVEL_AREA (0x8 * 4) /* 0x4 to 0xB */
-#define SJA1105_SIZE_ETHER_AREA (0x17 * 4)
-
-struct sja1105_port_status_mac {
- u64 n_runt;
- u64 n_soferr;
- u64 n_alignerr;
- u64 n_miierr;
- u64 typeerr;
- u64 sizeerr;
- u64 tctimeout;
- u64 priorerr;
- u64 nomaster;
- u64 memov;
- u64 memerr;
- u64 invtyp;
- u64 intcyov;
- u64 domerr;
- u64 pcfbagdrop;
- u64 spcprior;
- u64 ageprior;
- u64 portdrop;
- u64 lendrop;
- u64 bagdrop;
- u64 policeerr;
- u64 drpnona664err;
- u64 spcerr;
- u64 agedrp;
-};
-
-struct sja1105_port_status_hl1 {
- u64 n_n664err;
- u64 n_vlanerr;
- u64 n_unreleased;
- u64 n_sizeerr;
- u64 n_crcerr;
- u64 n_vlnotfound;
- u64 n_ctpolerr;
- u64 n_polerr;
- u64 n_rxfrmsh;
- u64 n_rxfrm;
- u64 n_rxbytesh;
- u64 n_rxbyte;
- u64 n_txfrmsh;
- u64 n_txfrm;
- u64 n_txbytesh;
- u64 n_txbyte;
+enum sja1105_counter_index {
+ __SJA1105_COUNTER_UNUSED,
+ /* MAC */
+ N_RUNT,
+ N_SOFERR,
+ N_ALIGNERR,
+ N_MIIERR,
+ TYPEERR,
+ SIZEERR,
+ TCTIMEOUT,
+ PRIORERR,
+ NOMASTER,
+ MEMOV,
+ MEMERR,
+ INVTYP,
+ INTCYOV,
+ DOMERR,
+ PCFBAGDROP,
+ SPCPRIOR,
+ AGEPRIOR,
+ PORTDROP,
+ LENDROP,
+ BAGDROP,
+ POLICEERR,
+ DRPNONA664ERR,
+ SPCERR,
+ AGEDRP,
+ /* HL1 */
+ N_N664ERR,
+ N_VLANERR,
+ N_UNRELEASED,
+ N_SIZEERR,
+ N_CRCERR,
+ N_VLNOTFOUND,
+ N_CTPOLERR,
+ N_POLERR,
+ N_RXFRM,
+ N_RXBYTE,
+ N_TXFRM,
+ N_TXBYTE,
+ /* HL2 */
+ N_QFULL,
+ N_PART_DROP,
+ N_EGR_DISABLED,
+ N_NOT_REACH,
+ __MAX_SJA1105ET_PORT_COUNTER,
+ /* P/Q/R/S only */
+ /* ETHER */
+ N_DROPS_NOLEARN = __MAX_SJA1105ET_PORT_COUNTER,
+ N_DROPS_NOROUTE,
+ N_DROPS_ILL_DTAG,
+ N_DROPS_DTAG,
+ N_DROPS_SOTAG,
+ N_DROPS_SITAG,
+ N_DROPS_UTAG,
+ N_TX_BYTES_1024_2047,
+ N_TX_BYTES_512_1023,
+ N_TX_BYTES_256_511,
+ N_TX_BYTES_128_255,
+ N_TX_BYTES_65_127,
+ N_TX_BYTES_64,
+ N_TX_MCAST,
+ N_TX_BCAST,
+ N_RX_BYTES_1024_2047,
+ N_RX_BYTES_512_1023,
+ N_RX_BYTES_256_511,
+ N_RX_BYTES_128_255,
+ N_RX_BYTES_65_127,
+ N_RX_BYTES_64,
+ N_RX_MCAST,
+ N_RX_BCAST,
+ __MAX_SJA1105PQRS_PORT_COUNTER,
};
-struct sja1105_port_status_hl2 {
- u64 n_qfull;
- u64 n_part_drop;
- u64 n_egr_disabled;
- u64 n_not_reach;
- u64 qlevel_hwm[8]; /* Only for P/Q/R/S */
- u64 qlevel[8]; /* Only for P/Q/R/S */
+struct sja1105_port_counter {
+ enum sja1105_stats_area area;
+ const char name[ETH_GSTRING_LEN];
+ int offset;
+ int start;
+ int end;
+ bool is_64bit;
};
-struct sja1105_port_status_ether {
- u64 n_drops_nolearn;
- u64 n_drops_noroute;
- u64 n_drops_ill_dtag;
- u64 n_drops_dtag;
- u64 n_drops_sotag;
- u64 n_drops_sitag;
- u64 n_drops_utag;
- u64 n_tx_bytes_1024_2047;
- u64 n_tx_bytes_512_1023;
- u64 n_tx_bytes_256_511;
- u64 n_tx_bytes_128_255;
- u64 n_tx_bytes_65_127;
- u64 n_tx_bytes_64;
- u64 n_tx_mcast;
- u64 n_tx_bcast;
- u64 n_rx_bytes_1024_2047;
- u64 n_rx_bytes_512_1023;
- u64 n_rx_bytes_256_511;
- u64 n_rx_bytes_128_255;
- u64 n_rx_bytes_65_127;
- u64 n_rx_bytes_64;
- u64 n_rx_mcast;
- u64 n_rx_bcast;
-};
-
-struct sja1105_port_status {
- struct sja1105_port_status_mac mac;
- struct sja1105_port_status_hl1 hl1;
- struct sja1105_port_status_hl2 hl2;
- struct sja1105_port_status_ether ether;
+static const struct sja1105_port_counter sja1105_port_counters[] = {
+ /* MAC-Level Diagnostic Counters */
+ [N_RUNT] = {
+ .area = MAC,
+ .name = "n_runt",
+ .offset = 0,
+ .start = 31,
+ .end = 24,
+ },
+ [N_SOFERR] = {
+ .area = MAC,
+ .name = "n_soferr",
+ .offset = 0x0,
+ .start = 23,
+ .end = 16,
+ },
+ [N_ALIGNERR] = {
+ .area = MAC,
+ .name = "n_alignerr",
+ .offset = 0x0,
+ .start = 15,
+ .end = 8,
+ },
+ [N_MIIERR] = {
+ .area = MAC,
+ .name = "n_miierr",
+ .offset = 0x0,
+ .start = 7,
+ .end = 0,
+ },
+ /* MAC-Level Diagnostic Flags */
+ [TYPEERR] = {
+ .area = MAC,
+ .name = "typeerr",
+ .offset = 0x1,
+ .start = 27,
+ .end = 27,
+ },
+ [SIZEERR] = {
+ .area = MAC,
+ .name = "sizeerr",
+ .offset = 0x1,
+ .start = 26,
+ .end = 26,
+ },
+ [TCTIMEOUT] = {
+ .area = MAC,
+ .name = "tctimeout",
+ .offset = 0x1,
+ .start = 25,
+ .end = 25,
+ },
+ [PRIORERR] = {
+ .area = MAC,
+ .name = "priorerr",
+ .offset = 0x1,
+ .start = 24,
+ .end = 24,
+ },
+ [NOMASTER] = {
+ .area = MAC,
+ .name = "nomaster",
+ .offset = 0x1,
+ .start = 23,
+ .end = 23,
+ },
+ [MEMOV] = {
+ .area = MAC,
+ .name = "memov",
+ .offset = 0x1,
+ .start = 22,
+ .end = 22,
+ },
+ [MEMERR] = {
+ .area = MAC,
+ .name = "memerr",
+ .offset = 0x1,
+ .start = 21,
+ .end = 21,
+ },
+ [INVTYP] = {
+ .area = MAC,
+ .name = "invtyp",
+ .offset = 0x1,
+ .start = 19,
+ .end = 19,
+ },
+ [INTCYOV] = {
+ .area = MAC,
+ .name = "intcyov",
+ .offset = 0x1,
+ .start = 18,
+ .end = 18,
+ },
+ [DOMERR] = {
+ .area = MAC,
+ .name = "domerr",
+ .offset = 0x1,
+ .start = 17,
+ .end = 17,
+ },
+ [PCFBAGDROP] = {
+ .area = MAC,
+ .name = "pcfbagdrop",
+ .offset = 0x1,
+ .start = 16,
+ .end = 16,
+ },
+ [SPCPRIOR] = {
+ .area = MAC,
+ .name = "spcprior",
+ .offset = 0x1,
+ .start = 15,
+ .end = 12,
+ },
+ [AGEPRIOR] = {
+ .area = MAC,
+ .name = "ageprior",
+ .offset = 0x1,
+ .start = 11,
+ .end = 8,
+ },
+ [PORTDROP] = {
+ .area = MAC,
+ .name = "portdrop",
+ .offset = 0x1,
+ .start = 6,
+ .end = 6,
+ },
+ [LENDROP] = {
+ .area = MAC,
+ .name = "lendrop",
+ .offset = 0x1,
+ .start = 5,
+ .end = 5,
+ },
+ [BAGDROP] = {
+ .area = MAC,
+ .name = "bagdrop",
+ .offset = 0x1,
+ .start = 4,
+ .end = 4,
+ },
+ [POLICEERR] = {
+ .area = MAC,
+ .name = "policeerr",
+ .offset = 0x1,
+ .start = 3,
+ .end = 3,
+ },
+ [DRPNONA664ERR] = {
+ .area = MAC,
+ .name = "drpnona664err",
+ .offset = 0x1,
+ .start = 2,
+ .end = 2,
+ },
+ [SPCERR] = {
+ .area = MAC,
+ .name = "spcerr",
+ .offset = 0x1,
+ .start = 1,
+ .end = 1,
+ },
+ [AGEDRP] = {
+ .area = MAC,
+ .name = "agedrp",
+ .offset = 0x1,
+ .start = 0,
+ .end = 0,
+ },
+ /* High-Level Diagnostic Counters */
+ [N_N664ERR] = {
+ .area = HL1,
+ .name = "n_n664err",
+ .offset = 0xF,
+ .start = 31,
+ .end = 0,
+ },
+ [N_VLANERR] = {
+ .area = HL1,
+ .name = "n_vlanerr",
+ .offset = 0xE,
+ .start = 31,
+ .end = 0,
+ },
+ [N_UNRELEASED] = {
+ .area = HL1,
+ .name = "n_unreleased",
+ .offset = 0xD,
+ .start = 31,
+ .end = 0,
+ },
+ [N_SIZEERR] = {
+ .area = HL1,
+ .name = "n_sizeerr",
+ .offset = 0xC,
+ .start = 31,
+ .end = 0,
+ },
+ [N_CRCERR] = {
+ .area = HL1,
+ .name = "n_crcerr",
+ .offset = 0xB,
+ .start = 31,
+ .end = 0,
+ },
+ [N_VLNOTFOUND] = {
+ .area = HL1,
+ .name = "n_vlnotfound",
+ .offset = 0xA,
+ .start = 31,
+ .end = 0,
+ },
+ [N_CTPOLERR] = {
+ .area = HL1,
+ .name = "n_ctpolerr",
+ .offset = 0x9,
+ .start = 31,
+ .end = 0,
+ },
+ [N_POLERR] = {
+ .area = HL1,
+ .name = "n_polerr",
+ .offset = 0x8,
+ .start = 31,
+ .end = 0,
+ },
+ [N_RXFRM] = {
+ .area = HL1,
+ .name = "n_rxfrm",
+ .offset = 0x6,
+ .start = 31,
+ .end = 0,
+ .is_64bit = true,
+ },
+ [N_RXBYTE] = {
+ .area = HL1,
+ .name = "n_rxbyte",
+ .offset = 0x4,
+ .start = 31,
+ .end = 0,
+ .is_64bit = true,
+ },
+ [N_TXFRM] = {
+ .area = HL1,
+ .name = "n_txfrm",
+ .offset = 0x2,
+ .start = 31,
+ .end = 0,
+ .is_64bit = true,
+ },
+ [N_TXBYTE] = {
+ .area = HL1,
+ .name = "n_txbyte",
+ .offset = 0x0,
+ .start = 31,
+ .end = 0,
+ .is_64bit = true,
+ },
+ [N_QFULL] = {
+ .area = HL2,
+ .name = "n_qfull",
+ .offset = 0x3,
+ .start = 31,
+ .end = 0,
+ },
+ [N_PART_DROP] = {
+ .area = HL2,
+ .name = "n_part_drop",
+ .offset = 0x2,
+ .start = 31,
+ .end = 0,
+ },
+ [N_EGR_DISABLED] = {
+ .area = HL2,
+ .name = "n_egr_disabled",
+ .offset = 0x1,
+ .start = 31,
+ .end = 0,
+ },
+ [N_NOT_REACH] = {
+ .area = HL2,
+ .name = "n_not_reach",
+ .offset = 0x0,
+ .start = 31,
+ .end = 0,
+ },
+ /* Ether Stats */
+ [N_DROPS_NOLEARN] = {
+ .area = ETHER,
+ .name = "n_drops_nolearn",
+ .offset = 0x16,
+ .start = 31,
+ .end = 0,
+ },
+ [N_DROPS_NOROUTE] = {
+ .area = ETHER,
+ .name = "n_drops_noroute",
+ .offset = 0x15,
+ .start = 31,
+ .end = 0,
+ },
+ [N_DROPS_ILL_DTAG] = {
+ .area = ETHER,
+ .name = "n_drops_ill_dtag",
+ .offset = 0x14,
+ .start = 31,
+ .end = 0,
+ },
+ [N_DROPS_DTAG] = {
+ .area = ETHER,
+ .name = "n_drops_dtag",
+ .offset = 0x13,
+ .start = 31,
+ .end = 0,
+ },
+ [N_DROPS_SOTAG] = {
+ .area = ETHER,
+ .name = "n_drops_sotag",
+ .offset = 0x12,
+ .start = 31,
+ .end = 0,
+ },
+ [N_DROPS_SITAG] = {
+ .area = ETHER,
+ .name = "n_drops_sitag",
+ .offset = 0x11,
+ .start = 31,
+ .end = 0,
+ },
+ [N_DROPS_UTAG] = {
+ .area = ETHER,
+ .name = "n_drops_utag",
+ .offset = 0x10,
+ .start = 31,
+ .end = 0,
+ },
+ [N_TX_BYTES_1024_2047] = {
+ .area = ETHER,
+ .name = "n_tx_bytes_1024_2047",
+ .offset = 0x0F,
+ .start = 31,
+ .end = 0,
+ },
+ [N_TX_BYTES_512_1023] = {
+ .area = ETHER,
+ .name = "n_tx_bytes_512_1023",
+ .offset = 0x0E,
+ .start = 31,
+ .end = 0,
+ },
+ [N_TX_BYTES_256_511] = {
+ .area = ETHER,
+ .name = "n_tx_bytes_256_511",
+ .offset = 0x0D,
+ .start = 31,
+ .end = 0,
+ },
+ [N_TX_BYTES_128_255] = {
+ .area = ETHER,
+ .name = "n_tx_bytes_128_255",
+ .offset = 0x0C,
+ .start = 31,
+ .end = 0,
+ },
+ [N_TX_BYTES_65_127] = {
+ .area = ETHER,
+ .name = "n_tx_bytes_65_127",
+ .offset = 0x0B,
+ .start = 31,
+ .end = 0,
+ },
+ [N_TX_BYTES_64] = {
+ .area = ETHER,
+ .name = "n_tx_bytes_64",
+ .offset = 0x0A,
+ .start = 31,
+ .end = 0,
+ },
+ [N_TX_MCAST] = {
+ .area = ETHER,
+ .name = "n_tx_mcast",
+ .offset = 0x09,
+ .start = 31,
+ .end = 0,
+ },
+ [N_TX_BCAST] = {
+ .area = ETHER,
+ .name = "n_tx_bcast",
+ .offset = 0x08,
+ .start = 31,
+ .end = 0,
+ },
+ [N_RX_BYTES_1024_2047] = {
+ .area = ETHER,
+ .name = "n_rx_bytes_1024_2047",
+ .offset = 0x07,
+ .start = 31,
+ .end = 0,
+ },
+ [N_RX_BYTES_512_1023] = {
+ .area = ETHER,
+ .name = "n_rx_bytes_512_1023",
+ .offset = 0x06,
+ .start = 31,
+ .end = 0,
+ },
+ [N_RX_BYTES_256_511] = {
+ .area = ETHER,
+ .name = "n_rx_bytes_256_511",
+ .offset = 0x05,
+ .start = 31,
+ .end = 0,
+ },
+ [N_RX_BYTES_128_255] = {
+ .area = ETHER,
+ .name = "n_rx_bytes_128_255",
+ .offset = 0x04,
+ .start = 31,
+ .end = 0,
+ },
+ [N_RX_BYTES_65_127] = {
+ .area = ETHER,
+ .name = "n_rx_bytes_65_127",
+ .offset = 0x03,
+ .start = 31,
+ .end = 0,
+ },
+ [N_RX_BYTES_64] = {
+ .area = ETHER,
+ .name = "n_rx_bytes_64",
+ .offset = 0x02,
+ .start = 31,
+ .end = 0,
+ },
+ [N_RX_MCAST] = {
+ .area = ETHER,
+ .name = "n_rx_mcast",
+ .offset = 0x01,
+ .start = 31,
+ .end = 0,
+ },
+ [N_RX_BCAST] = {
+ .area = ETHER,
+ .name = "n_rx_bcast",
+ .offset = 0x00,
+ .start = 31,
+ .end = 0,
+ },
};
-static void
-sja1105_port_status_mac_unpack(void *buf,
- struct sja1105_port_status_mac *status)
-{
- /* Make pointer arithmetic work on 4 bytes */
- u32 *p = buf;
-
- sja1105_unpack(p + 0x0, &status->n_runt, 31, 24, 4);
- sja1105_unpack(p + 0x0, &status->n_soferr, 23, 16, 4);
- sja1105_unpack(p + 0x0, &status->n_alignerr, 15, 8, 4);
- sja1105_unpack(p + 0x0, &status->n_miierr, 7, 0, 4);
- sja1105_unpack(p + 0x1, &status->typeerr, 27, 27, 4);
- sja1105_unpack(p + 0x1, &status->sizeerr, 26, 26, 4);
- sja1105_unpack(p + 0x1, &status->tctimeout, 25, 25, 4);
- sja1105_unpack(p + 0x1, &status->priorerr, 24, 24, 4);
- sja1105_unpack(p + 0x1, &status->nomaster, 23, 23, 4);
- sja1105_unpack(p + 0x1, &status->memov, 22, 22, 4);
- sja1105_unpack(p + 0x1, &status->memerr, 21, 21, 4);
- sja1105_unpack(p + 0x1, &status->invtyp, 19, 19, 4);
- sja1105_unpack(p + 0x1, &status->intcyov, 18, 18, 4);
- sja1105_unpack(p + 0x1, &status->domerr, 17, 17, 4);
- sja1105_unpack(p + 0x1, &status->pcfbagdrop, 16, 16, 4);
- sja1105_unpack(p + 0x1, &status->spcprior, 15, 12, 4);
- sja1105_unpack(p + 0x1, &status->ageprior, 11, 8, 4);
- sja1105_unpack(p + 0x1, &status->portdrop, 6, 6, 4);
- sja1105_unpack(p + 0x1, &status->lendrop, 5, 5, 4);
- sja1105_unpack(p + 0x1, &status->bagdrop, 4, 4, 4);
- sja1105_unpack(p + 0x1, &status->policeerr, 3, 3, 4);
- sja1105_unpack(p + 0x1, &status->drpnona664err, 2, 2, 4);
- sja1105_unpack(p + 0x1, &status->spcerr, 1, 1, 4);
- sja1105_unpack(p + 0x1, &status->agedrp, 0, 0, 4);
-}
-
-static void
-sja1105_port_status_hl1_unpack(void *buf,
- struct sja1105_port_status_hl1 *status)
-{
- /* Make pointer arithmetic work on 4 bytes */
- u32 *p = buf;
-
- sja1105_unpack(p + 0xF, &status->n_n664err, 31, 0, 4);
- sja1105_unpack(p + 0xE, &status->n_vlanerr, 31, 0, 4);
- sja1105_unpack(p + 0xD, &status->n_unreleased, 31, 0, 4);
- sja1105_unpack(p + 0xC, &status->n_sizeerr, 31, 0, 4);
- sja1105_unpack(p + 0xB, &status->n_crcerr, 31, 0, 4);
- sja1105_unpack(p + 0xA, &status->n_vlnotfound, 31, 0, 4);
- sja1105_unpack(p + 0x9, &status->n_ctpolerr, 31, 0, 4);
- sja1105_unpack(p + 0x8, &status->n_polerr, 31, 0, 4);
- sja1105_unpack(p + 0x7, &status->n_rxfrmsh, 31, 0, 4);
- sja1105_unpack(p + 0x6, &status->n_rxfrm, 31, 0, 4);
- sja1105_unpack(p + 0x5, &status->n_rxbytesh, 31, 0, 4);
- sja1105_unpack(p + 0x4, &status->n_rxbyte, 31, 0, 4);
- sja1105_unpack(p + 0x3, &status->n_txfrmsh, 31, 0, 4);
- sja1105_unpack(p + 0x2, &status->n_txfrm, 31, 0, 4);
- sja1105_unpack(p + 0x1, &status->n_txbytesh, 31, 0, 4);
- sja1105_unpack(p + 0x0, &status->n_txbyte, 31, 0, 4);
- status->n_rxfrm += status->n_rxfrmsh << 32;
- status->n_rxbyte += status->n_rxbytesh << 32;
- status->n_txfrm += status->n_txfrmsh << 32;
- status->n_txbyte += status->n_txbytesh << 32;
-}
-
-static void
-sja1105_port_status_hl2_unpack(void *buf,
- struct sja1105_port_status_hl2 *status)
-{
- /* Make pointer arithmetic work on 4 bytes */
- u32 *p = buf;
-
- sja1105_unpack(p + 0x3, &status->n_qfull, 31, 0, 4);
- sja1105_unpack(p + 0x2, &status->n_part_drop, 31, 0, 4);
- sja1105_unpack(p + 0x1, &status->n_egr_disabled, 31, 0, 4);
- sja1105_unpack(p + 0x0, &status->n_not_reach, 31, 0, 4);
-}
-
-static void
-sja1105pqrs_port_status_qlevel_unpack(void *buf,
- struct sja1105_port_status_hl2 *status)
-{
- /* Make pointer arithmetic work on 4 bytes */
- u32 *p = buf;
- int i;
-
- for (i = 0; i < 8; i++) {
- sja1105_unpack(p + i, &status->qlevel_hwm[i], 24, 16, 4);
- sja1105_unpack(p + i, &status->qlevel[i], 8, 0, 4);
- }
-}
-
-static void
-sja1105pqrs_port_status_ether_unpack(void *buf,
- struct sja1105_port_status_ether *status)
-{
- /* Make pointer arithmetic work on 4 bytes */
- u32 *p = buf;
-
- sja1105_unpack(p + 0x16, &status->n_drops_nolearn, 31, 0, 4);
- sja1105_unpack(p + 0x15, &status->n_drops_noroute, 31, 0, 4);
- sja1105_unpack(p + 0x14, &status->n_drops_ill_dtag, 31, 0, 4);
- sja1105_unpack(p + 0x13, &status->n_drops_dtag, 31, 0, 4);
- sja1105_unpack(p + 0x12, &status->n_drops_sotag, 31, 0, 4);
- sja1105_unpack(p + 0x11, &status->n_drops_sitag, 31, 0, 4);
- sja1105_unpack(p + 0x10, &status->n_drops_utag, 31, 0, 4);
- sja1105_unpack(p + 0x0F, &status->n_tx_bytes_1024_2047, 31, 0, 4);
- sja1105_unpack(p + 0x0E, &status->n_tx_bytes_512_1023, 31, 0, 4);
- sja1105_unpack(p + 0x0D, &status->n_tx_bytes_256_511, 31, 0, 4);
- sja1105_unpack(p + 0x0C, &status->n_tx_bytes_128_255, 31, 0, 4);
- sja1105_unpack(p + 0x0B, &status->n_tx_bytes_65_127, 31, 0, 4);
- sja1105_unpack(p + 0x0A, &status->n_tx_bytes_64, 31, 0, 4);
- sja1105_unpack(p + 0x09, &status->n_tx_mcast, 31, 0, 4);
- sja1105_unpack(p + 0x08, &status->n_tx_bcast, 31, 0, 4);
- sja1105_unpack(p + 0x07, &status->n_rx_bytes_1024_2047, 31, 0, 4);
- sja1105_unpack(p + 0x06, &status->n_rx_bytes_512_1023, 31, 0, 4);
- sja1105_unpack(p + 0x05, &status->n_rx_bytes_256_511, 31, 0, 4);
- sja1105_unpack(p + 0x04, &status->n_rx_bytes_128_255, 31, 0, 4);
- sja1105_unpack(p + 0x03, &status->n_rx_bytes_65_127, 31, 0, 4);
- sja1105_unpack(p + 0x02, &status->n_rx_bytes_64, 31, 0, 4);
- sja1105_unpack(p + 0x01, &status->n_rx_mcast, 31, 0, 4);
- sja1105_unpack(p + 0x00, &status->n_rx_bcast, 31, 0, 4);
-}
-
-static int
-sja1105pqrs_port_status_get_ether(struct sja1105_private *priv,
- struct sja1105_port_status_ether *ether,
- int port)
-{
- const struct sja1105_regs *regs = priv->info->regs;
- u8 packed_buf[SJA1105_SIZE_ETHER_AREA] = {0};
- int rc;
-
- /* Ethernet statistics area */
- rc = sja1105_xfer_buf(priv, SPI_READ, regs->ether_stats[port],
- packed_buf, SJA1105_SIZE_ETHER_AREA);
- if (rc < 0)
- return rc;
-
- sja1105pqrs_port_status_ether_unpack(packed_buf, ether);
-
- return 0;
-}
-
-static int sja1105_port_status_get_mac(struct sja1105_private *priv,
- struct sja1105_port_status_mac *status,
- int port)
-{
- const struct sja1105_regs *regs = priv->info->regs;
- u8 packed_buf[SJA1105_SIZE_MAC_AREA] = {0};
- int rc;
-
- /* MAC area */
- rc = sja1105_xfer_buf(priv, SPI_READ, regs->mac[port], packed_buf,
- SJA1105_SIZE_MAC_AREA);
- if (rc < 0)
- return rc;
-
- sja1105_port_status_mac_unpack(packed_buf, status);
-
- return 0;
-}
-
-static int sja1105_port_status_get_hl1(struct sja1105_private *priv,
- struct sja1105_port_status_hl1 *status,
- int port)
-{
- const struct sja1105_regs *regs = priv->info->regs;
- u8 packed_buf[SJA1105_SIZE_HL1_AREA] = {0};
- int rc;
-
- rc = sja1105_xfer_buf(priv, SPI_READ, regs->mac_hl1[port], packed_buf,
- SJA1105_SIZE_HL1_AREA);
- if (rc < 0)
- return rc;
-
- sja1105_port_status_hl1_unpack(packed_buf, status);
-
- return 0;
-}
-
-static int sja1105_port_status_get_hl2(struct sja1105_private *priv,
- struct sja1105_port_status_hl2 *status,
- int port)
+static int sja1105_port_counter_read(struct sja1105_private *priv, int port,
+ enum sja1105_counter_index idx, u64 *ctr)
{
- const struct sja1105_regs *regs = priv->info->regs;
- u8 packed_buf[SJA1105_SIZE_QLEVEL_AREA] = {0};
+ const struct sja1105_port_counter *c = &sja1105_port_counters[idx];
+ size_t size = c->is_64bit ? 8 : 4;
+ u8 buf[8] = {0};
+ u64 regs;
int rc;
- rc = sja1105_xfer_buf(priv, SPI_READ, regs->mac_hl2[port], packed_buf,
- SJA1105_SIZE_HL2_AREA);
- if (rc < 0)
- return rc;
-
- sja1105_port_status_hl2_unpack(packed_buf, status);
-
- /* Code below is strictly P/Q/R/S specific. */
- if (priv->info->device_id == SJA1105E_DEVICE_ID ||
- priv->info->device_id == SJA1105T_DEVICE_ID)
- return 0;
+ regs = priv->info->regs->stats[c->area][port];
- rc = sja1105_xfer_buf(priv, SPI_READ, regs->qlevel[port], packed_buf,
- SJA1105_SIZE_QLEVEL_AREA);
- if (rc < 0)
+ rc = sja1105_xfer_buf(priv, SPI_READ, regs + c->offset, buf, size);
+ if (rc)
return rc;
- sja1105pqrs_port_status_qlevel_unpack(packed_buf, status);
+ sja1105_unpack(buf, ctr, c->start, c->end, size);
return 0;
}
-static int sja1105_port_status_get(struct sja1105_private *priv,
- struct sja1105_port_status *status,
- int port)
-{
- int rc;
-
- rc = sja1105_port_status_get_mac(priv, &status->mac, port);
- if (rc < 0)
- return rc;
- rc = sja1105_port_status_get_hl1(priv, &status->hl1, port);
- if (rc < 0)
- return rc;
- rc = sja1105_port_status_get_hl2(priv, &status->hl2, port);
- if (rc < 0)
- return rc;
-
- if (priv->info->device_id == SJA1105E_DEVICE_ID ||
- priv->info->device_id == SJA1105T_DEVICE_ID)
- return 0;
-
- return sja1105pqrs_port_status_get_ether(priv, &status->ether, port);
-}
-
-static char sja1105_port_stats[][ETH_GSTRING_LEN] = {
- /* MAC-Level Diagnostic Counters */
- "n_runt",
- "n_soferr",
- "n_alignerr",
- "n_miierr",
- /* MAC-Level Diagnostic Flags */
- "typeerr",
- "sizeerr",
- "tctimeout",
- "priorerr",
- "nomaster",
- "memov",
- "memerr",
- "invtyp",
- "intcyov",
- "domerr",
- "pcfbagdrop",
- "spcprior",
- "ageprior",
- "portdrop",
- "lendrop",
- "bagdrop",
- "policeerr",
- "drpnona664err",
- "spcerr",
- "agedrp",
- /* High-Level Diagnostic Counters */
- "n_n664err",
- "n_vlanerr",
- "n_unreleased",
- "n_sizeerr",
- "n_crcerr",
- "n_vlnotfound",
- "n_ctpolerr",
- "n_polerr",
- "n_rxfrm",
- "n_rxbyte",
- "n_txfrm",
- "n_txbyte",
- "n_qfull",
- "n_part_drop",
- "n_egr_disabled",
- "n_not_reach",
-};
-
-static char sja1105pqrs_extra_port_stats[][ETH_GSTRING_LEN] = {
- /* Queue Levels */
- "qlevel_hwm_0",
- "qlevel_hwm_1",
- "qlevel_hwm_2",
- "qlevel_hwm_3",
- "qlevel_hwm_4",
- "qlevel_hwm_5",
- "qlevel_hwm_6",
- "qlevel_hwm_7",
- "qlevel_0",
- "qlevel_1",
- "qlevel_2",
- "qlevel_3",
- "qlevel_4",
- "qlevel_5",
- "qlevel_6",
- "qlevel_7",
- /* Ether Stats */
- "n_drops_nolearn",
- "n_drops_noroute",
- "n_drops_ill_dtag",
- "n_drops_dtag",
- "n_drops_sotag",
- "n_drops_sitag",
- "n_drops_utag",
- "n_tx_bytes_1024_2047",
- "n_tx_bytes_512_1023",
- "n_tx_bytes_256_511",
- "n_tx_bytes_128_255",
- "n_tx_bytes_65_127",
- "n_tx_bytes_64",
- "n_tx_mcast",
- "n_tx_bcast",
- "n_rx_bytes_1024_2047",
- "n_rx_bytes_512_1023",
- "n_rx_bytes_256_511",
- "n_rx_bytes_128_255",
- "n_rx_bytes_65_127",
- "n_rx_bytes_64",
- "n_rx_mcast",
- "n_rx_bcast",
-};
-
void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
{
struct sja1105_private *priv = ds->priv;
- struct sja1105_port_status *status;
- int rc, i, k = 0;
-
- status = kzalloc(sizeof(*status), GFP_KERNEL);
- if (!status)
- goto out;
-
- rc = sja1105_port_status_get(priv, status, port);
- if (rc < 0) {
- dev_err(ds->dev, "Failed to read port %d counters: %d\n",
- port, rc);
- goto out;
- }
- memset(data, 0, ARRAY_SIZE(sja1105_port_stats) * sizeof(u64));
- data[k++] = status->mac.n_runt;
- data[k++] = status->mac.n_soferr;
- data[k++] = status->mac.n_alignerr;
- data[k++] = status->mac.n_miierr;
- data[k++] = status->mac.typeerr;
- data[k++] = status->mac.sizeerr;
- data[k++] = status->mac.tctimeout;
- data[k++] = status->mac.priorerr;
- data[k++] = status->mac.nomaster;
- data[k++] = status->mac.memov;
- data[k++] = status->mac.memerr;
- data[k++] = status->mac.invtyp;
- data[k++] = status->mac.intcyov;
- data[k++] = status->mac.domerr;
- data[k++] = status->mac.pcfbagdrop;
- data[k++] = status->mac.spcprior;
- data[k++] = status->mac.ageprior;
- data[k++] = status->mac.portdrop;
- data[k++] = status->mac.lendrop;
- data[k++] = status->mac.bagdrop;
- data[k++] = status->mac.policeerr;
- data[k++] = status->mac.drpnona664err;
- data[k++] = status->mac.spcerr;
- data[k++] = status->mac.agedrp;
- data[k++] = status->hl1.n_n664err;
- data[k++] = status->hl1.n_vlanerr;
- data[k++] = status->hl1.n_unreleased;
- data[k++] = status->hl1.n_sizeerr;
- data[k++] = status->hl1.n_crcerr;
- data[k++] = status->hl1.n_vlnotfound;
- data[k++] = status->hl1.n_ctpolerr;
- data[k++] = status->hl1.n_polerr;
- data[k++] = status->hl1.n_rxfrm;
- data[k++] = status->hl1.n_rxbyte;
- data[k++] = status->hl1.n_txfrm;
- data[k++] = status->hl1.n_txbyte;
- data[k++] = status->hl2.n_qfull;
- data[k++] = status->hl2.n_part_drop;
- data[k++] = status->hl2.n_egr_disabled;
- data[k++] = status->hl2.n_not_reach;
+ enum sja1105_counter_index max_ctr, i;
+ int rc, k = 0;
if (priv->info->device_id == SJA1105E_DEVICE_ID ||
priv->info->device_id == SJA1105T_DEVICE_ID)
- goto out;
-
- memset(data + k, 0, ARRAY_SIZE(sja1105pqrs_extra_port_stats) *
- sizeof(u64));
- for (i = 0; i < 8; i++) {
- data[k++] = status->hl2.qlevel_hwm[i];
- data[k++] = status->hl2.qlevel[i];
+ max_ctr = __MAX_SJA1105ET_PORT_COUNTER;
+ else
+ max_ctr = __MAX_SJA1105PQRS_PORT_COUNTER;
+
+ for (i = 0; i < max_ctr; i++) {
+ rc = sja1105_port_counter_read(priv, port, i, &data[k++]);
+ if (rc) {
+ dev_err(ds->dev,
+ "Failed to read port %d counters: %d\n",
+ port, rc);
+ break;
+ }
}
- data[k++] = status->ether.n_drops_nolearn;
- data[k++] = status->ether.n_drops_noroute;
- data[k++] = status->ether.n_drops_ill_dtag;
- data[k++] = status->ether.n_drops_dtag;
- data[k++] = status->ether.n_drops_sotag;
- data[k++] = status->ether.n_drops_sitag;
- data[k++] = status->ether.n_drops_utag;
- data[k++] = status->ether.n_tx_bytes_1024_2047;
- data[k++] = status->ether.n_tx_bytes_512_1023;
- data[k++] = status->ether.n_tx_bytes_256_511;
- data[k++] = status->ether.n_tx_bytes_128_255;
- data[k++] = status->ether.n_tx_bytes_65_127;
- data[k++] = status->ether.n_tx_bytes_64;
- data[k++] = status->ether.n_tx_mcast;
- data[k++] = status->ether.n_tx_bcast;
- data[k++] = status->ether.n_rx_bytes_1024_2047;
- data[k++] = status->ether.n_rx_bytes_512_1023;
- data[k++] = status->ether.n_rx_bytes_256_511;
- data[k++] = status->ether.n_rx_bytes_128_255;
- data[k++] = status->ether.n_rx_bytes_65_127;
- data[k++] = status->ether.n_rx_bytes_64;
- data[k++] = status->ether.n_rx_mcast;
- data[k++] = status->ether.n_rx_bcast;
-out:
- kfree(status);
}
void sja1105_get_strings(struct dsa_switch *ds, int port,
u32 stringset, u8 *data)
{
struct sja1105_private *priv = ds->priv;
- u8 *p = data;
- int i;
+ enum sja1105_counter_index max_ctr, i;
+ char *p = data;
- switch (stringset) {
- case ETH_SS_STATS:
- for (i = 0; i < ARRAY_SIZE(sja1105_port_stats); i++) {
- strlcpy(p, sja1105_port_stats[i], ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
- if (priv->info->device_id == SJA1105E_DEVICE_ID ||
- priv->info->device_id == SJA1105T_DEVICE_ID)
- return;
- for (i = 0; i < ARRAY_SIZE(sja1105pqrs_extra_port_stats); i++) {
- strlcpy(p, sja1105pqrs_extra_port_stats[i],
- ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
- break;
+ if (stringset != ETH_SS_STATS)
+ return;
+
+ if (priv->info->device_id == SJA1105E_DEVICE_ID ||
+ priv->info->device_id == SJA1105T_DEVICE_ID)
+ max_ctr = __MAX_SJA1105ET_PORT_COUNTER;
+ else
+ max_ctr = __MAX_SJA1105PQRS_PORT_COUNTER;
+
+ for (i = 0; i < max_ctr; i++) {
+ strscpy(p, sja1105_port_counters[i].name, ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
}
}
int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset)
{
- int count = ARRAY_SIZE(sja1105_port_stats);
struct sja1105_private *priv = ds->priv;
+ enum sja1105_counter_index max_ctr, i;
+ int sset_count = 0;
if (sset != ETH_SS_STATS)
return -EOPNOTSUPP;
- if (priv->info->device_id == SJA1105PR_DEVICE_ID ||
- priv->info->device_id == SJA1105QS_DEVICE_ID)
- count += ARRAY_SIZE(sja1105pqrs_extra_port_stats);
+ if (priv->info->device_id == SJA1105E_DEVICE_ID ||
+ priv->info->device_id == SJA1105T_DEVICE_ID)
+ max_ctr = __MAX_SJA1105ET_PORT_COUNTER;
+ else
+ max_ctr = __MAX_SJA1105PQRS_PORT_COUNTER;
+
+ for (i = 0; i < max_ctr; i++) {
+ if (!strlen(sja1105_port_counters[i].name))
+ continue;
+
+ sset_count++;
+ }
- return count;
+ return sset_count;
}
diff --git a/drivers/net/dsa/sja1105/sja1105_flower.c b/drivers/net/dsa/sja1105/sja1105_flower.c
index 973761132fc3..6c10ffa968ce 100644
--- a/drivers/net/dsa/sja1105/sja1105_flower.c
+++ b/drivers/net/dsa/sja1105/sja1105_flower.c
@@ -35,6 +35,7 @@ static int sja1105_setup_bcast_policer(struct sja1105_private *priv,
{
struct sja1105_rule *rule = sja1105_rule_find(priv, cookie);
struct sja1105_l2_policing_entry *policing;
+ struct dsa_switch *ds = priv->ds;
bool new_rule = false;
unsigned long p;
int rc;
@@ -59,7 +60,7 @@ static int sja1105_setup_bcast_policer(struct sja1105_private *priv,
policing = priv->static_config.tables[BLK_IDX_L2_POLICING].entries;
- if (policing[(SJA1105_NUM_PORTS * SJA1105_NUM_TC) + port].sharindx != port) {
+ if (policing[(ds->num_ports * SJA1105_NUM_TC) + port].sharindx != port) {
NL_SET_ERR_MSG_MOD(extack,
"Port already has a broadcast policer");
rc = -EEXIST;
@@ -71,8 +72,8 @@ static int sja1105_setup_bcast_policer(struct sja1105_private *priv,
/* Make the broadcast policers of all ports attached to this block
* point to the newly allocated policer
*/
- for_each_set_bit(p, &rule->port_mask, SJA1105_NUM_PORTS) {
- int bcast = (SJA1105_NUM_PORTS * SJA1105_NUM_TC) + p;
+ for_each_set_bit(p, &rule->port_mask, SJA1105_MAX_NUM_PORTS) {
+ int bcast = (ds->num_ports * SJA1105_NUM_TC) + p;
policing[bcast].sharindx = rule->bcast_pol.sharindx;
}
@@ -143,7 +144,7 @@ static int sja1105_setup_tc_policer(struct sja1105_private *priv,
/* Make the policers for traffic class @tc of all ports attached to
* this block point to the newly allocated policer
*/
- for_each_set_bit(p, &rule->port_mask, SJA1105_NUM_PORTS) {
+ for_each_set_bit(p, &rule->port_mask, SJA1105_MAX_NUM_PORTS) {
int index = (p * SJA1105_NUM_TC) + tc;
policing[index].sharindx = rule->tc_pol.sharindx;
@@ -435,7 +436,7 @@ int sja1105_cls_flower_del(struct dsa_switch *ds, int port,
policing = priv->static_config.tables[BLK_IDX_L2_POLICING].entries;
if (rule->type == SJA1105_RULE_BCAST_POLICER) {
- int bcast = (SJA1105_NUM_PORTS * SJA1105_NUM_TC) + port;
+ int bcast = (ds->num_ports * SJA1105_NUM_TC) + port;
old_sharindx = policing[bcast].sharindx;
policing[bcast].sharindx = port;
@@ -486,7 +487,7 @@ void sja1105_flower_setup(struct dsa_switch *ds)
INIT_LIST_HEAD(&priv->flow_block.rules);
- for (port = 0; port < SJA1105_NUM_PORTS; port++)
+ for (port = 0; port < ds->num_ports; port++)
priv->flow_block.l2_policer_used[port] = true;
}
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index b88d9ef45a1f..ced8c9cb29c2 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -16,13 +16,13 @@
#include <linux/of_net.h>
#include <linux/of_mdio.h>
#include <linux/of_device.h>
+#include <linux/pcs/pcs-xpcs.h>
#include <linux/netdev_features.h>
#include <linux/netdevice.h>
#include <linux/if_bridge.h>
#include <linux/if_ether.h>
#include <linux/dsa/8021q.h>
#include "sja1105.h"
-#include "sja1105_sgmii.h"
#include "sja1105_tas.h"
#define SJA1105_UNKNOWN_MULTICAST 0x010000000000ull
@@ -57,14 +57,6 @@ static bool sja1105_can_forward(struct sja1105_l2_forwarding_entry *l2_fwd,
return !!(l2_fwd[from].reach_port & BIT(to));
}
-/* Structure used to temporarily transport device tree
- * settings into sja1105_setup
- */
-struct sja1105_dt_port {
- phy_interface_t phy_mode;
- sja1105_mii_role_t role;
-};
-
static int sja1105_init_mac_settings(struct sja1105_private *priv)
{
struct sja1105_mac_config_entry default_mac = {
@@ -80,7 +72,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
/* Always put the MAC speed in automatic mode, where it can be
* adjusted at runtime by PHYLINK.
*/
- .speed = SJA1105_SPEED_AUTO,
+ .speed = priv->info->port_speed[SJA1105_SPEED_AUTO],
/* No static correction for 1-step 1588 events */
.tp_delin = 0,
.tp_delout = 0,
@@ -107,6 +99,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
.ingress = false,
};
struct sja1105_mac_config_entry *mac;
+ struct dsa_switch *ds = priv->ds;
struct sja1105_table *table;
int i;
@@ -118,50 +111,33 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
table->entry_count = 0;
}
- table->entries = kcalloc(SJA1105_NUM_PORTS,
+ table->entries = kcalloc(table->ops->max_entry_count,
table->ops->unpacked_entry_size, GFP_KERNEL);
if (!table->entries)
return -ENOMEM;
- table->entry_count = SJA1105_NUM_PORTS;
+ table->entry_count = table->ops->max_entry_count;
mac = table->entries;
- for (i = 0; i < SJA1105_NUM_PORTS; i++) {
+ for (i = 0; i < ds->num_ports; i++) {
mac[i] = default_mac;
- if (i == dsa_upstream_port(priv->ds, i)) {
- /* STP doesn't get called for CPU port, so we need to
- * set the I/O parameters statically.
- */
- mac[i].dyn_learn = true;
- mac[i].ingress = true;
- mac[i].egress = true;
- }
+
+ /* Let sja1105_bridge_stp_state_set() keep address learning
+ * enabled for the CPU port.
+ */
+ if (dsa_is_cpu_port(ds, i))
+ priv->learn_ena |= BIT(i);
}
return 0;
}
-static bool sja1105_supports_sgmii(struct sja1105_private *priv, int port)
-{
- if (priv->info->part_no != SJA1105R_PART_NO &&
- priv->info->part_no != SJA1105S_PART_NO)
- return false;
-
- if (port != SJA1105_SGMII_PORT)
- return false;
-
- if (dsa_is_unused_port(priv->ds, port))
- return false;
-
- return true;
-}
-
-static int sja1105_init_mii_settings(struct sja1105_private *priv,
- struct sja1105_dt_port *ports)
+static int sja1105_init_mii_settings(struct sja1105_private *priv)
{
struct device *dev = &priv->spidev->dev;
struct sja1105_xmii_params_entry *mii;
+ struct dsa_switch *ds = priv->ds;
struct sja1105_table *table;
int i;
@@ -173,52 +149,81 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv,
table->entry_count = 0;
}
- table->entries = kcalloc(SJA1105_MAX_XMII_PARAMS_COUNT,
+ table->entries = kcalloc(table->ops->max_entry_count,
table->ops->unpacked_entry_size, GFP_KERNEL);
if (!table->entries)
return -ENOMEM;
/* Override table based on PHYLINK DT bindings */
- table->entry_count = SJA1105_MAX_XMII_PARAMS_COUNT;
+ table->entry_count = table->ops->max_entry_count;
mii = table->entries;
- for (i = 0; i < SJA1105_NUM_PORTS; i++) {
+ for (i = 0; i < ds->num_ports; i++) {
+ sja1105_mii_role_t role = XMII_MAC;
+
if (dsa_is_unused_port(priv->ds, i))
continue;
- switch (ports[i].phy_mode) {
+ switch (priv->phy_mode[i]) {
+ case PHY_INTERFACE_MODE_INTERNAL:
+ if (priv->info->internal_phy[i] == SJA1105_NO_PHY)
+ goto unsupported;
+
+ mii->xmii_mode[i] = XMII_MODE_MII;
+ if (priv->info->internal_phy[i] == SJA1105_PHY_BASE_TX)
+ mii->special[i] = true;
+
+ break;
+ case PHY_INTERFACE_MODE_REVMII:
+ role = XMII_PHY;
+ fallthrough;
case PHY_INTERFACE_MODE_MII:
+ if (!priv->info->supports_mii[i])
+ goto unsupported;
+
mii->xmii_mode[i] = XMII_MODE_MII;
break;
+ case PHY_INTERFACE_MODE_REVRMII:
+ role = XMII_PHY;
+ fallthrough;
case PHY_INTERFACE_MODE_RMII:
+ if (!priv->info->supports_rmii[i])
+ goto unsupported;
+
mii->xmii_mode[i] = XMII_MODE_RMII;
break;
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
+ if (!priv->info->supports_rgmii[i])
+ goto unsupported;
+
mii->xmii_mode[i] = XMII_MODE_RGMII;
break;
case PHY_INTERFACE_MODE_SGMII:
- if (!sja1105_supports_sgmii(priv, i))
- return -EINVAL;
+ if (!priv->info->supports_sgmii[i])
+ goto unsupported;
+
mii->xmii_mode[i] = XMII_MODE_SGMII;
+ mii->special[i] = true;
break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ if (!priv->info->supports_2500basex[i])
+ goto unsupported;
+
+ mii->xmii_mode[i] = XMII_MODE_SGMII;
+ mii->special[i] = true;
+ break;
+unsupported:
default:
- dev_err(dev, "Unsupported PHY mode %s!\n",
- phy_modes(ports[i].phy_mode));
+ dev_err(dev, "Unsupported PHY mode %s on port %d!\n",
+ phy_modes(priv->phy_mode[i]), i);
return -EINVAL;
}
- /* Even though the SerDes port is able to drive SGMII autoneg
- * like a PHY would, from the perspective of the XMII tables,
- * the SGMII port should always be put in MAC mode.
- */
- if (ports[i].phy_mode == PHY_INTERFACE_MODE_SGMII)
- mii->phy_mac[i] = XMII_MAC;
- else
- mii->phy_mac[i] = ports[i].role;
+ mii->phy_mac[i] = role;
}
return 0;
}
@@ -267,8 +272,6 @@ 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),
@@ -276,8 +279,6 @@ static int sja1105_init_l2_lookup_params(struct sja1105_private *priv)
.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
@@ -301,6 +302,23 @@ static int sja1105_init_l2_lookup_params(struct sja1105_private *priv)
.owr_dyn = true,
.drpnolearn = true,
};
+ struct dsa_switch *ds = priv->ds;
+ int port, num_used_ports = 0;
+ struct sja1105_table *table;
+ u64 max_fdb_entries;
+
+ for (port = 0; port < ds->num_ports; port++)
+ if (!dsa_is_unused_port(ds, port))
+ num_used_ports++;
+
+ max_fdb_entries = SJA1105_MAX_L2_LOOKUP_COUNT / num_used_ports;
+
+ for (port = 0; port < ds->num_ports; port++) {
+ if (dsa_is_unused_port(ds, port))
+ continue;
+
+ default_l2_lookup_params.maxaddrp[port] = max_fdb_entries;
+ }
table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS];
@@ -309,12 +327,12 @@ static int sja1105_init_l2_lookup_params(struct sja1105_private *priv)
table->entry_count = 0;
}
- table->entries = kcalloc(SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
+ table->entries = kcalloc(table->ops->max_entry_count,
table->ops->unpacked_entry_size, GFP_KERNEL);
if (!table->entries)
return -ENOMEM;
- table->entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT;
+ table->entry_count = table->ops->max_entry_count;
/* This table only has a single entry */
((struct sja1105_l2_lookup_params_entry *)table->entries)[0] =
@@ -334,6 +352,7 @@ static int sja1105_init_static_vlan(struct sja1105_private *priv)
{
struct sja1105_table *table;
struct sja1105_vlan_lookup_entry pvid = {
+ .type_entry = SJA1110_VLAN_D_TAG,
.ving_mirr = 0,
.vegr_mirr = 0,
.vmemb_port = 0,
@@ -387,6 +406,7 @@ static int sja1105_init_static_vlan(struct sja1105_private *priv)
static int sja1105_init_l2_forwarding(struct sja1105_private *priv)
{
struct sja1105_l2_forwarding_entry *l2fwd;
+ struct dsa_switch *ds = priv->ds;
struct sja1105_table *table;
int i, j;
@@ -397,19 +417,22 @@ static int sja1105_init_l2_forwarding(struct sja1105_private *priv)
table->entry_count = 0;
}
- table->entries = kcalloc(SJA1105_MAX_L2_FORWARDING_COUNT,
+ table->entries = kcalloc(table->ops->max_entry_count,
table->ops->unpacked_entry_size, GFP_KERNEL);
if (!table->entries)
return -ENOMEM;
- table->entry_count = SJA1105_MAX_L2_FORWARDING_COUNT;
+ table->entry_count = table->ops->max_entry_count;
l2fwd = table->entries;
/* First 5 entries define the forwarding rules */
- for (i = 0; i < SJA1105_NUM_PORTS; i++) {
+ for (i = 0; i < ds->num_ports; i++) {
unsigned int upstream = dsa_upstream_port(priv->ds, i);
+ if (dsa_is_unused_port(ds, i))
+ continue;
+
for (j = 0; j < SJA1105_NUM_TC; j++)
l2fwd[i].vlan_pmap[j] = j;
@@ -431,24 +454,66 @@ static int sja1105_init_l2_forwarding(struct sja1105_private *priv)
l2fwd[upstream].bc_domain |= BIT(i);
l2fwd[upstream].fl_domain |= BIT(i);
}
+
/* Next 8 entries define VLAN PCP mapping from ingress to egress.
* Create a one-to-one mapping.
*/
- for (i = 0; i < SJA1105_NUM_TC; i++)
- for (j = 0; j < SJA1105_NUM_PORTS; j++)
- l2fwd[SJA1105_NUM_PORTS + i].vlan_pmap[j] = i;
+ for (i = 0; i < SJA1105_NUM_TC; i++) {
+ for (j = 0; j < ds->num_ports; j++) {
+ if (dsa_is_unused_port(ds, j))
+ continue;
+
+ l2fwd[ds->num_ports + i].vlan_pmap[j] = i;
+ }
+
+ l2fwd[ds->num_ports + i].type_egrpcp2outputq = true;
+ }
+
+ return 0;
+}
+
+static int sja1110_init_pcp_remapping(struct sja1105_private *priv)
+{
+ struct sja1110_pcp_remapping_entry *pcp_remap;
+ struct dsa_switch *ds = priv->ds;
+ struct sja1105_table *table;
+ int port, tc;
+
+ table = &priv->static_config.tables[BLK_IDX_PCP_REMAPPING];
+
+ /* Nothing to do for SJA1105 */
+ if (!table->ops->max_entry_count)
+ return 0;
+
+ if (table->entry_count) {
+ kfree(table->entries);
+ table->entry_count = 0;
+ }
+
+ table->entries = kcalloc(table->ops->max_entry_count,
+ table->ops->unpacked_entry_size, GFP_KERNEL);
+ if (!table->entries)
+ return -ENOMEM;
+
+ table->entry_count = table->ops->max_entry_count;
+
+ pcp_remap = table->entries;
+
+ /* Repeat the configuration done for vlan_pmap */
+ for (port = 0; port < ds->num_ports; port++) {
+ if (dsa_is_unused_port(ds, port))
+ continue;
+
+ for (tc = 0; tc < SJA1105_NUM_TC; tc++)
+ pcp_remap[port].egrpcp[tc] = tc;
+ }
return 0;
}
static int sja1105_init_l2_forwarding_params(struct sja1105_private *priv)
{
- struct sja1105_l2_forwarding_params_entry default_l2fwd_params = {
- /* Disallow dynamic reconfiguration of vlan_pmap */
- .max_dynp = 0,
- /* Use a single memory partition for all ingress queues */
- .part_spc = { SJA1105_MAX_FRAME_MEMORY, 0, 0, 0, 0, 0, 0, 0 },
- };
+ struct sja1105_l2_forwarding_params_entry *l2fwd_params;
struct sja1105_table *table;
table = &priv->static_config.tables[BLK_IDX_L2_FORWARDING_PARAMS];
@@ -458,16 +523,20 @@ static int sja1105_init_l2_forwarding_params(struct sja1105_private *priv)
table->entry_count = 0;
}
- table->entries = kcalloc(SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
+ table->entries = kcalloc(table->ops->max_entry_count,
table->ops->unpacked_entry_size, GFP_KERNEL);
if (!table->entries)
return -ENOMEM;
- table->entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT;
+ table->entry_count = table->ops->max_entry_count;
/* This table only has a single entry */
- ((struct sja1105_l2_forwarding_params_entry *)table->entries)[0] =
- default_l2fwd_params;
+ l2fwd_params = table->entries;
+
+ /* Disallow dynamic reconfiguration of vlan_pmap */
+ l2fwd_params->max_dynp = 0;
+ /* Use a single memory partition for all ingress queues */
+ l2fwd_params->part_spc[0] = priv->info->max_frame_mem;
return 0;
}
@@ -476,16 +545,14 @@ void sja1105_frame_memory_partitioning(struct sja1105_private *priv)
{
struct sja1105_l2_forwarding_params_entry *l2_fwd_params;
struct sja1105_vl_forwarding_params_entry *vl_fwd_params;
+ int max_mem = priv->info->max_frame_mem;
struct sja1105_table *table;
- int max_mem;
/* VLAN retagging is implemented using a loopback port that consumes
* frame buffers. That leaves less for us.
*/
if (priv->vlan_state == SJA1105_VLAN_BEST_EFFORT)
- max_mem = SJA1105_MAX_FRAME_MEMORY_RETAGGING;
- else
- max_mem = SJA1105_MAX_FRAME_MEMORY;
+ max_mem -= SJA1105_FRAME_MEMORY_RETAGGING_OVERHEAD;
table = &priv->static_config.tables[BLK_IDX_L2_FORWARDING_PARAMS];
l2_fwd_params = table->entries;
@@ -507,6 +574,60 @@ void sja1105_frame_memory_partitioning(struct sja1105_private *priv)
vl_fwd_params->partspc[0] = SJA1105_VL_FRAME_MEMORY;
}
+/* SJA1110 TDMACONFIGIDX values:
+ *
+ * | 100 Mbps ports | 1Gbps ports | 2.5Gbps ports | Disabled ports
+ * -----+----------------+---------------+---------------+---------------
+ * 0 | 0, [5:10] | [1:2] | [3:4] | retag
+ * 1 |0, [5:10], retag| [1:2] | [3:4] | -
+ * 2 | 0, [5:10] | [1:3], retag | 4 | -
+ * 3 | 0, [5:10] |[1:2], 4, retag| 3 | -
+ * 4 | 0, 2, [5:10] | 1, retag | [3:4] | -
+ * 5 | 0, 1, [5:10] | 2, retag | [3:4] | -
+ * 14 | 0, [5:10] | [1:4], retag | - | -
+ * 15 | [5:10] | [0:4], retag | - | -
+ */
+static void sja1110_select_tdmaconfigidx(struct sja1105_private *priv)
+{
+ struct sja1105_general_params_entry *general_params;
+ struct sja1105_table *table;
+ bool port_1_is_base_tx;
+ bool port_3_is_2500;
+ bool port_4_is_2500;
+ u64 tdmaconfigidx;
+
+ if (priv->info->device_id != SJA1110_DEVICE_ID)
+ return;
+
+ table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS];
+ general_params = table->entries;
+
+ /* All the settings below are "as opposed to SGMII", which is the
+ * other pinmuxing option.
+ */
+ port_1_is_base_tx = priv->phy_mode[1] == PHY_INTERFACE_MODE_INTERNAL;
+ port_3_is_2500 = priv->phy_mode[3] == PHY_INTERFACE_MODE_2500BASEX;
+ port_4_is_2500 = priv->phy_mode[4] == PHY_INTERFACE_MODE_2500BASEX;
+
+ if (port_1_is_base_tx)
+ /* Retagging port will operate at 1 Gbps */
+ tdmaconfigidx = 5;
+ else if (port_3_is_2500 && port_4_is_2500)
+ /* Retagging port will operate at 100 Mbps */
+ tdmaconfigidx = 1;
+ else if (port_3_is_2500)
+ /* Retagging port will operate at 1 Gbps */
+ tdmaconfigidx = 3;
+ else if (port_4_is_2500)
+ /* Retagging port will operate at 1 Gbps */
+ tdmaconfigidx = 2;
+ else
+ /* Retagging port will operate at 1 Gbps */
+ tdmaconfigidx = 14;
+
+ general_params->tdmaconfigidx = tdmaconfigidx;
+}
+
static int sja1105_init_general_params(struct sja1105_private *priv)
{
struct sja1105_general_params_entry default_general_params = {
@@ -530,17 +651,9 @@ static int sja1105_init_general_params(struct sja1105_private *priv)
* receieved on host_port itself would be dropped, except
* by installing a temporary 'management route'
*/
- .host_port = dsa_upstream_port(priv->ds, 0),
+ .host_port = priv->ds->num_ports,
/* Default to an invalid value */
- .mirr_port = SJA1105_NUM_PORTS,
- /* Link-local traffic received on casc_port will be forwarded
- * to host_port without embedding the source port and device ID
- * info in the destination MAC address (presumably because it
- * is a cascaded port and a downstream SJA switch already did
- * that). Default to an invalid port (to disable the feature)
- * and overwrite this if we find any DSA (cascaded) ports.
- */
- .casc_port = SJA1105_NUM_PORTS,
+ .mirr_port = priv->ds->num_ports,
/* No TTEthernet */
.vllupformat = SJA1105_VL_FORMAT_PSFP,
.vlmarker = 0,
@@ -552,8 +665,22 @@ static int sja1105_init_general_params(struct sja1105_private *priv)
*/
.tpid = ETH_P_SJA1105,
.tpid2 = ETH_P_SJA1105,
+ /* Enable the TTEthernet engine on SJA1110 */
+ .tte_en = true,
+ /* Set up the EtherType for control packets on SJA1110 */
+ .header_type = ETH_P_SJA1110,
};
+ struct sja1105_general_params_entry *general_params;
+ struct dsa_switch *ds = priv->ds;
struct sja1105_table *table;
+ int port;
+
+ for (port = 0; port < ds->num_ports; port++) {
+ if (dsa_is_cpu_port(ds, port)) {
+ default_general_params.host_port = port;
+ break;
+ }
+ }
table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS];
@@ -562,16 +689,32 @@ static int sja1105_init_general_params(struct sja1105_private *priv)
table->entry_count = 0;
}
- table->entries = kcalloc(SJA1105_MAX_GENERAL_PARAMS_COUNT,
+ table->entries = kcalloc(table->ops->max_entry_count,
table->ops->unpacked_entry_size, GFP_KERNEL);
if (!table->entries)
return -ENOMEM;
- table->entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT;
+ table->entry_count = table->ops->max_entry_count;
+
+ general_params = table->entries;
/* This table only has a single entry */
- ((struct sja1105_general_params_entry *)table->entries)[0] =
- default_general_params;
+ general_params[0] = default_general_params;
+
+ sja1110_select_tdmaconfigidx(priv);
+
+ /* Link-local traffic received on casc_port will be forwarded
+ * to host_port without embedding the source port and device ID
+ * info in the destination MAC address, and no RX timestamps will be
+ * taken either (presumably because it is a cascaded port and a
+ * downstream SJA switch already did that).
+ * To disable the feature, we need to do different things depending on
+ * switch generation. On SJA1105 we need to set an invalid port, while
+ * on SJA1110 which support multiple cascaded ports, this field is a
+ * bitmask so it must be left zero.
+ */
+ if (!priv->info->multiple_cascade_ports)
+ general_params->casc_port = ds->num_ports;
return 0;
}
@@ -589,12 +732,12 @@ static int sja1105_init_avb_params(struct sja1105_private *priv)
table->entry_count = 0;
}
- table->entries = kcalloc(SJA1105_MAX_AVB_PARAMS_COUNT,
+ table->entries = kcalloc(table->ops->max_entry_count,
table->ops->unpacked_entry_size, GFP_KERNEL);
if (!table->entries)
return -ENOMEM;
- table->entry_count = SJA1105_MAX_AVB_PARAMS_COUNT;
+ table->entry_count = table->ops->max_entry_count;
avb = table->entries;
@@ -661,6 +804,7 @@ static int sja1105_init_avb_params(struct sja1105_private *priv)
static int sja1105_init_l2_policing(struct sja1105_private *priv)
{
struct sja1105_l2_policing_entry *policing;
+ struct dsa_switch *ds = priv->ds;
struct sja1105_table *table;
int port, tc;
@@ -672,27 +816,31 @@ static int sja1105_init_l2_policing(struct sja1105_private *priv)
table->entry_count = 0;
}
- table->entries = kcalloc(SJA1105_MAX_L2_POLICING_COUNT,
+ table->entries = kcalloc(table->ops->max_entry_count,
table->ops->unpacked_entry_size, GFP_KERNEL);
if (!table->entries)
return -ENOMEM;
- table->entry_count = SJA1105_MAX_L2_POLICING_COUNT;
+ table->entry_count = table->ops->max_entry_count;
policing = table->entries;
/* Setup shared indices for the matchall policers */
- for (port = 0; port < SJA1105_NUM_PORTS; port++) {
- int bcast = (SJA1105_NUM_PORTS * SJA1105_NUM_TC) + port;
+ for (port = 0; port < ds->num_ports; port++) {
+ int mcast = (ds->num_ports * (SJA1105_NUM_TC + 1)) + port;
+ int bcast = (ds->num_ports * SJA1105_NUM_TC) + port;
for (tc = 0; tc < SJA1105_NUM_TC; tc++)
policing[port * SJA1105_NUM_TC + tc].sharindx = port;
policing[bcast].sharindx = port;
+ /* Only SJA1110 has multicast policers */
+ if (mcast <= table->ops->max_entry_count)
+ policing[mcast].sharindx = port;
}
/* Setup the matchall policer parameters */
- for (port = 0; port < SJA1105_NUM_PORTS; port++) {
+ for (port = 0; port < ds->num_ports; port++) {
int mtu = VLAN_ETH_FRAME_LEN + ETH_FCS_LEN;
if (dsa_is_cpu_port(priv->ds, port))
@@ -707,8 +855,7 @@ static int sja1105_init_l2_policing(struct sja1105_private *priv)
return 0;
}
-static int sja1105_static_config_load(struct sja1105_private *priv,
- struct sja1105_dt_port *ports)
+static int sja1105_static_config_load(struct sja1105_private *priv)
{
int rc;
@@ -723,7 +870,7 @@ static int sja1105_static_config_load(struct sja1105_private *priv,
rc = sja1105_init_mac_settings(priv);
if (rc < 0)
return rc;
- rc = sja1105_init_mii_settings(priv, ports);
+ rc = sja1105_init_mii_settings(priv);
if (rc < 0)
return rc;
rc = sja1105_init_static_fdb(priv);
@@ -750,37 +897,39 @@ static int sja1105_static_config_load(struct sja1105_private *priv,
rc = sja1105_init_avb_params(priv);
if (rc < 0)
return rc;
+ rc = sja1110_init_pcp_remapping(priv);
+ if (rc < 0)
+ return rc;
/* Send initial configuration to hardware via SPI */
return sja1105_static_config_upload(priv);
}
-static int sja1105_parse_rgmii_delays(struct sja1105_private *priv,
- const struct sja1105_dt_port *ports)
+static int sja1105_parse_rgmii_delays(struct sja1105_private *priv)
{
- int i;
+ struct dsa_switch *ds = priv->ds;
+ int port;
- for (i = 0; i < SJA1105_NUM_PORTS; i++) {
- if (ports[i].role == XMII_MAC)
+ for (port = 0; port < ds->num_ports; port++) {
+ if (!priv->fixed_link[port])
continue;
- if (ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_RXID ||
- ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
- priv->rgmii_rx_delay[i] = true;
+ if (priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_RXID ||
+ priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_ID)
+ priv->rgmii_rx_delay[port] = true;
- if (ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_TXID ||
- ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
- priv->rgmii_tx_delay[i] = true;
+ if (priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_TXID ||
+ priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_ID)
+ priv->rgmii_tx_delay[port] = true;
- if ((priv->rgmii_rx_delay[i] || priv->rgmii_tx_delay[i]) &&
- !priv->info->setup_rgmii_delay)
+ if ((priv->rgmii_rx_delay[port] || priv->rgmii_tx_delay[port]) &&
+ !priv->info->setup_rgmii_delay)
return -EINVAL;
}
return 0;
}
static int sja1105_parse_ports_node(struct sja1105_private *priv,
- struct sja1105_dt_port *ports,
struct device_node *ports_node)
{
struct device *dev = &priv->spidev->dev;
@@ -809,7 +958,6 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
of_node_put(child);
return -ENODEV;
}
- ports[index].phy_mode = phy_mode;
phy_node = of_parse_phandle(child, "phy-handle", 0);
if (!phy_node) {
@@ -822,25 +970,18 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
/* phy-handle is missing, but fixed-link isn't.
* So it's a fixed link. Default to PHY role.
*/
- ports[index].role = XMII_PHY;
+ priv->fixed_link[index] = true;
} else {
- /* phy-handle present => put port in MAC role */
- ports[index].role = XMII_MAC;
of_node_put(phy_node);
}
- /* The MAC/PHY role can be overridden with explicit bindings */
- if (of_property_read_bool(child, "sja1105,role-mac"))
- ports[index].role = XMII_MAC;
- else if (of_property_read_bool(child, "sja1105,role-phy"))
- ports[index].role = XMII_PHY;
+ priv->phy_mode[index] = phy_mode;
}
return 0;
}
-static int sja1105_parse_dt(struct sja1105_private *priv,
- struct sja1105_dt_port *ports)
+static int sja1105_parse_dt(struct sja1105_private *priv)
{
struct device *dev = &priv->spidev->dev;
struct device_node *switch_node = dev->of_node;
@@ -848,113 +989,41 @@ static int sja1105_parse_dt(struct sja1105_private *priv,
int rc;
ports_node = of_get_child_by_name(switch_node, "ports");
+ if (!ports_node)
+ ports_node = of_get_child_by_name(switch_node, "ethernet-ports");
if (!ports_node) {
dev_err(dev, "Incorrect bindings: absent \"ports\" node\n");
return -ENODEV;
}
- rc = sja1105_parse_ports_node(priv, ports, ports_node);
+ rc = sja1105_parse_ports_node(priv, ports_node);
of_node_put(ports_node);
return rc;
}
-static int sja1105_sgmii_read(struct sja1105_private *priv, int pcs_reg)
-{
- const struct sja1105_regs *regs = priv->info->regs;
- u32 val;
- int rc;
-
- rc = sja1105_xfer_u32(priv, SPI_READ, regs->sgmii + pcs_reg, &val,
- NULL);
- if (rc < 0)
- return rc;
-
- return val;
-}
-
-static int sja1105_sgmii_write(struct sja1105_private *priv, int pcs_reg,
- u16 pcs_val)
-{
- const struct sja1105_regs *regs = priv->info->regs;
- u32 val = pcs_val;
- int rc;
-
- rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->sgmii + pcs_reg, &val,
- NULL);
- if (rc < 0)
- return rc;
-
- return val;
-}
-
-static void sja1105_sgmii_pcs_config(struct sja1105_private *priv,
- bool an_enabled, bool an_master)
+/* Convert link speed from SJA1105 to ethtool encoding */
+static int sja1105_port_speed_to_ethtool(struct sja1105_private *priv,
+ u64 speed)
{
- u16 ac = SJA1105_AC_AUTONEG_MODE_SGMII;
-
- /* DIGITAL_CONTROL_1: Enable vendor-specific MMD1, allow the PHY to
- * stop the clock during LPI mode, make the MAC reconfigure
- * autonomously after PCS autoneg is done, flush the internal FIFOs.
- */
- sja1105_sgmii_write(priv, SJA1105_DC1, SJA1105_DC1_EN_VSMMD1 |
- SJA1105_DC1_CLOCK_STOP_EN |
- SJA1105_DC1_MAC_AUTO_SW |
- SJA1105_DC1_INIT);
- /* DIGITAL_CONTROL_2: No polarity inversion for TX and RX lanes */
- sja1105_sgmii_write(priv, SJA1105_DC2, SJA1105_DC2_TX_POL_INV_DISABLE);
- /* AUTONEG_CONTROL: Use SGMII autoneg */
- if (an_master)
- ac |= SJA1105_AC_PHY_MODE | SJA1105_AC_SGMII_LINK;
- sja1105_sgmii_write(priv, SJA1105_AC, ac);
- /* BASIC_CONTROL: enable in-band AN now, if requested. Otherwise,
- * sja1105_sgmii_pcs_force_speed must be called later for the link
- * to become operational.
- */
- if (an_enabled)
- sja1105_sgmii_write(priv, MII_BMCR,
- BMCR_ANENABLE | BMCR_ANRESTART);
+ if (speed == priv->info->port_speed[SJA1105_SPEED_10MBPS])
+ return SPEED_10;
+ if (speed == priv->info->port_speed[SJA1105_SPEED_100MBPS])
+ return SPEED_100;
+ if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS])
+ return SPEED_1000;
+ if (speed == priv->info->port_speed[SJA1105_SPEED_2500MBPS])
+ return SPEED_2500;
+ return SPEED_UNKNOWN;
}
-static void sja1105_sgmii_pcs_force_speed(struct sja1105_private *priv,
- int speed)
-{
- int pcs_speed;
-
- switch (speed) {
- case SPEED_1000:
- pcs_speed = BMCR_SPEED1000;
- break;
- case SPEED_100:
- pcs_speed = BMCR_SPEED100;
- break;
- case SPEED_10:
- pcs_speed = BMCR_SPEED10;
- break;
- default:
- dev_err(priv->ds->dev, "Invalid speed %d\n", speed);
- return;
- }
- sja1105_sgmii_write(priv, MII_BMCR, pcs_speed | BMCR_FULLDPLX);
-}
-
-/* Convert link speed from SJA1105 to ethtool encoding */
-static int sja1105_speed[] = {
- [SJA1105_SPEED_AUTO] = SPEED_UNKNOWN,
- [SJA1105_SPEED_10MBPS] = SPEED_10,
- [SJA1105_SPEED_100MBPS] = SPEED_100,
- [SJA1105_SPEED_1000MBPS] = SPEED_1000,
-};
-
/* 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)
{
- struct sja1105_xmii_params_entry *mii;
struct sja1105_mac_config_entry *mac;
struct device *dev = priv->ds->dev;
- sja1105_phy_interface_t phy_mode;
- sja1105_speed_t speed;
+ u64 speed;
int rc;
/* On P/Q/R/S, one can read from the device via the MAC reconfiguration
@@ -964,7 +1033,6 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
* 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 SPEED_UNKNOWN:
@@ -975,16 +1043,19 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
* ok for power consumption in case AN will never complete -
* otherwise PHYLINK should come back with a new update.
*/
- speed = SJA1105_SPEED_AUTO;
+ speed = priv->info->port_speed[SJA1105_SPEED_AUTO];
break;
case SPEED_10:
- speed = SJA1105_SPEED_10MBPS;
+ speed = priv->info->port_speed[SJA1105_SPEED_10MBPS];
break;
case SPEED_100:
- speed = SJA1105_SPEED_100MBPS;
+ speed = priv->info->port_speed[SJA1105_SPEED_100MBPS];
break;
case SPEED_1000:
- speed = SJA1105_SPEED_1000MBPS;
+ speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS];
+ break;
+ case SPEED_2500:
+ speed = priv->info->port_speed[SJA1105_SPEED_2500MBPS];
break;
default:
dev_err(dev, "Invalid speed %iMbps\n", speed_mbps);
@@ -998,8 +1069,10 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
* Actually for the SGMII port, the MAC is fixed at 1 Gbps and
* we need to configure the PCS only (if even that).
*/
- if (sja1105_supports_sgmii(priv, port))
- mac[port].speed = SJA1105_SPEED_1000MBPS;
+ if (priv->phy_mode[port] == PHY_INTERFACE_MODE_SGMII)
+ mac[port].speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS];
+ else if (priv->phy_mode[port] == PHY_INTERFACE_MODE_2500BASEX)
+ mac[port].speed = priv->info->port_speed[SJA1105_SPEED_2500MBPS];
else
mac[port].speed = speed;
@@ -1017,8 +1090,7 @@ 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.
*/
- phy_mode = mii->xmii_mode[port];
- if (phy_mode != XMII_MODE_RGMII)
+ if (!phy_interface_mode_is_rgmii(priv->phy_mode[port]))
return 0;
return sja1105_clocking_setup_port(priv, port);
@@ -1034,35 +1106,16 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
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);
- case PHY_INTERFACE_MODE_SGMII:
- return (phy_mode != XMII_MODE_SGMII);
- default:
- return true;
- }
+ return priv->phy_mode[port] != interface;
}
static void sja1105_mac_config(struct dsa_switch *ds, int port,
unsigned int mode,
const struct phylink_link_state *state)
{
+ struct dsa_port *dp = dsa_to_port(ds, port);
struct sja1105_private *priv = ds->priv;
- bool is_sgmii = sja1105_supports_sgmii(priv, port);
+ struct dw_xpcs *xpcs;
if (sja1105_phy_mode_mismatch(priv, port, state->interface)) {
dev_err(ds->dev, "Changing PHY mode to %s not supported!\n",
@@ -1070,14 +1123,10 @@ static void sja1105_mac_config(struct dsa_switch *ds, int port,
return;
}
- if (phylink_autoneg_inband(mode) && !is_sgmii) {
- dev_err(ds->dev, "In-band AN not supported!\n");
- return;
- }
+ xpcs = priv->xpcs[port];
- if (is_sgmii)
- sja1105_sgmii_pcs_config(priv, phylink_autoneg_inband(mode),
- false);
+ if (xpcs)
+ phylink_set_pcs(dp->pl, &xpcs->pcs);
}
static void sja1105_mac_link_down(struct dsa_switch *ds, int port,
@@ -1098,9 +1147,6 @@ static void sja1105_mac_link_up(struct dsa_switch *ds, int port,
sja1105_adjust_port_config(priv, port, speed);
- if (sja1105_supports_sgmii(priv, port) && !phylink_autoneg_inband(mode))
- sja1105_sgmii_pcs_force_speed(priv, speed);
-
sja1105_inhibit_tx(priv, BIT(port), false);
}
@@ -1139,44 +1185,16 @@ static void sja1105_phylink_validate(struct dsa_switch *ds, int port,
if (mii->xmii_mode[port] == XMII_MODE_RGMII ||
mii->xmii_mode[port] == XMII_MODE_SGMII)
phylink_set(mask, 1000baseT_Full);
+ if (priv->info->supports_2500basex[port]) {
+ phylink_set(mask, 2500baseT_Full);
+ phylink_set(mask, 2500baseX_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 sja1105_mac_pcs_get_state(struct dsa_switch *ds, int port,
- struct phylink_link_state *state)
-{
- struct sja1105_private *priv = ds->priv;
- int ais;
-
- /* Read the vendor-specific AUTONEG_INTR_STATUS register */
- ais = sja1105_sgmii_read(priv, SJA1105_AIS);
- if (ais < 0)
- return ais;
-
- switch (SJA1105_AIS_SPEED(ais)) {
- case 0:
- state->speed = SPEED_10;
- break;
- case 1:
- state->speed = SPEED_100;
- break;
- case 2:
- state->speed = SPEED_1000;
- break;
- default:
- dev_err(ds->dev, "Invalid SGMII PCS speed %lu\n",
- SJA1105_AIS_SPEED(ais));
- }
- state->duplex = SJA1105_AIS_DUPLEX_MODE(ais);
- state->an_complete = SJA1105_AIS_COMPLETE(ais);
- state->link = SJA1105_AIS_LINK_STATUS(ais);
-
- return 0;
-}
-
static int
sja1105_find_static_fdb_entry(struct sja1105_private *priv, int port,
const struct sja1105_l2_lookup_entry *requested)
@@ -1635,7 +1653,7 @@ static int sja1105_bridge_member(struct dsa_switch *ds, int port,
l2_fwd = priv->static_config.tables[BLK_IDX_L2_FORWARDING].entries;
- for (i = 0; i < SJA1105_NUM_PORTS; i++) {
+ for (i = 0; i < ds->num_ports; i++) {
/* Add this port to the forwarding matrix of the
* other ports in the same bridge, and viceversa.
*/
@@ -1798,6 +1816,12 @@ static int sja1105_reload_cbs(struct sja1105_private *priv)
{
int rc = 0, i;
+ /* The credit based shapers are only allocated if
+ * CONFIG_NET_SCH_CBS is enabled.
+ */
+ if (!priv->cbs)
+ return 0;
+
for (i = 0; i < priv->info->num_cbs_shapers; i++) {
struct sja1105_cbs_entry *cbs = &priv->cbs[i];
@@ -1833,12 +1857,12 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
{
struct ptp_system_timestamp ptp_sts_before;
struct ptp_system_timestamp ptp_sts_after;
+ int speed_mbps[SJA1105_MAX_NUM_PORTS];
+ u16 bmcr[SJA1105_MAX_NUM_PORTS] = {0};
struct sja1105_mac_config_entry *mac;
- int speed_mbps[SJA1105_NUM_PORTS];
struct dsa_switch *ds = priv->ds;
s64 t1, t2, t3, t4;
s64 t12, t34;
- u16 bmcr = 0;
int rc, i;
s64 now;
@@ -1851,29 +1875,38 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
* 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;
- }
+ for (i = 0; i < ds->num_ports; i++) {
+ u32 reg_addr = mdiobus_c45_addr(MDIO_MMD_VEND2, MDIO_CTRL1);
+
+ speed_mbps[i] = sja1105_port_speed_to_ethtool(priv,
+ mac[i].speed);
+ mac[i].speed = priv->info->port_speed[SJA1105_SPEED_AUTO];
- if (sja1105_supports_sgmii(priv, SJA1105_SGMII_PORT))
- bmcr = sja1105_sgmii_read(priv, MII_BMCR);
+ if (priv->xpcs[i])
+ bmcr[i] = mdiobus_read(priv->mdio_pcs, i, reg_addr);
+ }
/* No PTP operations can run right now */
mutex_lock(&priv->ptp_data.lock);
rc = __sja1105_ptp_gettimex(ds, &now, &ptp_sts_before);
- if (rc < 0)
- goto out_unlock_ptp;
+ if (rc < 0) {
+ mutex_unlock(&priv->ptp_data.lock);
+ goto out;
+ }
/* Reset switch and send updated static configuration */
rc = sja1105_static_config_upload(priv);
- if (rc < 0)
- goto out_unlock_ptp;
+ if (rc < 0) {
+ mutex_unlock(&priv->ptp_data.lock);
+ goto out;
+ }
rc = __sja1105_ptp_settime(ds, 0, &ptp_sts_after);
- if (rc < 0)
- goto out_unlock_ptp;
+ if (rc < 0) {
+ mutex_unlock(&priv->ptp_data.lock);
+ goto out;
+ }
t1 = timespec64_to_ns(&ptp_sts_before.pre_ts);
t2 = timespec64_to_ns(&ptp_sts_before.post_ts);
@@ -1888,7 +1921,6 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
__sja1105_ptp_adjtime(ds, now);
-out_unlock_ptp:
mutex_unlock(&priv->ptp_data.lock);
dev_info(priv->ds->dev,
@@ -1899,32 +1931,48 @@ out_unlock_ptp:
* For these interfaces there is no dynamic configuration
* needed, since PLLs have same settings at all speeds.
*/
- rc = sja1105_clocking_setup(priv);
- if (rc < 0)
- goto out;
+ if (priv->info->clocking_setup) {
+ rc = priv->info->clocking_setup(priv);
+ if (rc < 0)
+ goto out;
+ }
+
+ for (i = 0; i < ds->num_ports; i++) {
+ struct dw_xpcs *xpcs = priv->xpcs[i];
+ unsigned int mode;
- for (i = 0; i < SJA1105_NUM_PORTS; i++) {
rc = sja1105_adjust_port_config(priv, i, speed_mbps[i]);
if (rc < 0)
goto out;
- }
- if (sja1105_supports_sgmii(priv, SJA1105_SGMII_PORT)) {
- bool an_enabled = !!(bmcr & BMCR_ANENABLE);
+ if (!xpcs)
+ continue;
- sja1105_sgmii_pcs_config(priv, an_enabled, false);
+ if (bmcr[i] & BMCR_ANENABLE)
+ mode = MLO_AN_INBAND;
+ else if (priv->fixed_link[i])
+ mode = MLO_AN_FIXED;
+ else
+ mode = MLO_AN_PHY;
+
+ rc = xpcs_do_config(xpcs, priv->phy_mode[i], mode);
+ if (rc < 0)
+ goto out;
- if (!an_enabled) {
+ if (!phylink_autoneg_inband(mode)) {
int speed = SPEED_UNKNOWN;
- if (bmcr & BMCR_SPEED1000)
+ if (priv->phy_mode[i] == PHY_INTERFACE_MODE_2500BASEX)
+ speed = SPEED_2500;
+ else if (bmcr[i] & BMCR_SPEED1000)
speed = SPEED_1000;
- else if (bmcr & BMCR_SPEED100)
+ else if (bmcr[i] & BMCR_SPEED100)
speed = SPEED_100;
else
speed = SPEED_10;
- sja1105_sgmii_pcs_force_speed(priv, speed);
+ xpcs_link_up(&xpcs->pcs, mode, priv->phy_mode[i],
+ speed, DUPLEX_FULL);
}
}
@@ -2032,7 +2080,9 @@ static enum dsa_tag_protocol
sja1105_get_tag_protocol(struct dsa_switch *ds, int port,
enum dsa_tag_protocol mp)
{
- return DSA_TAG_PROTO_SJA1105;
+ struct sja1105_private *priv = ds->priv;
+
+ return priv->info->tag_proto;
}
static int sja1105_find_free_subvlan(u16 *subvlan_map, bool pvid)
@@ -2272,6 +2322,7 @@ sja1105_build_bridge_vlans(struct sja1105_private *priv,
new_vlan[match].vlan_bc |= BIT(v->port);
if (!v->untagged)
new_vlan[match].tag_port |= BIT(v->port);
+ new_vlan[match].type_entry = SJA1110_VLAN_D_TAG;
}
return 0;
@@ -2294,6 +2345,7 @@ sja1105_build_dsa_8021q_vlans(struct sja1105_private *priv,
new_vlan[match].vlan_bc |= BIT(v->port);
if (!v->untagged)
new_vlan[match].tag_port |= BIT(v->port);
+ new_vlan[match].type_entry = SJA1110_VLAN_D_TAG;
}
return 0;
@@ -2354,6 +2406,7 @@ static int sja1105_build_subvlans(struct sja1105_private *priv,
new_vlan[match].tag_port |= BIT(v->port);
/* But it's always tagged towards the CPU */
new_vlan[match].tag_port |= BIT(upstream);
+ new_vlan[match].type_entry = SJA1110_VLAN_D_TAG;
/* The Retagging Table generates packet *clones* with
* the new VLAN. This is a very odd hardware quirk
@@ -2521,6 +2574,7 @@ sja1105_build_crosschip_subvlans(struct sja1105_private *priv,
if (!tmp->untagged)
new_vlan[match].tag_port |= BIT(tmp->port);
new_vlan[match].tag_port |= BIT(upstream);
+ new_vlan[match].type_entry = SJA1110_VLAN_D_TAG;
/* Deny egress of @rx_vid towards our front-panel port.
* This will force the switch to drop it, and we'll see
* only the re-retagged packets (having the original,
@@ -2611,7 +2665,7 @@ out:
static int sja1105_build_vlan_table(struct sja1105_private *priv, bool notify)
{
- u16 subvlan_map[SJA1105_NUM_PORTS][DSA_8021Q_N_SUBVLAN];
+ u16 subvlan_map[SJA1105_MAX_NUM_PORTS][DSA_8021Q_N_SUBVLAN];
struct sja1105_retagging_entry *new_retagging;
struct sja1105_vlan_lookup_entry *new_vlan;
struct sja1105_table *table;
@@ -2958,11 +3012,10 @@ static const struct dsa_8021q_ops sja1105_dsa_8021q_ops = {
*/
static int sja1105_setup(struct dsa_switch *ds)
{
- struct sja1105_dt_port ports[SJA1105_NUM_PORTS];
struct sja1105_private *priv = ds->priv;
int rc;
- rc = sja1105_parse_dt(priv, ports);
+ rc = sja1105_parse_dt(priv);
if (rc < 0) {
dev_err(ds->dev, "Failed to parse DT: %d\n", rc);
return rc;
@@ -2971,7 +3024,7 @@ static int sja1105_setup(struct dsa_switch *ds)
/* Error out early if internal delays are required through DT
* and we can't apply them.
*/
- rc = sja1105_parse_rgmii_delays(priv, ports);
+ rc = sja1105_parse_rgmii_delays(priv);
if (rc < 0) {
dev_err(ds->dev, "RGMII delay not supported\n");
return rc;
@@ -2982,18 +3035,42 @@ static int sja1105_setup(struct dsa_switch *ds)
dev_err(ds->dev, "Failed to register PTP clock: %d\n", rc);
return rc;
}
+
+ rc = sja1105_mdiobus_register(ds);
+ if (rc < 0) {
+ dev_err(ds->dev, "Failed to register MDIO bus: %pe\n",
+ ERR_PTR(rc));
+ goto out_ptp_clock_unregister;
+ }
+
+ if (priv->info->disable_microcontroller) {
+ rc = priv->info->disable_microcontroller(priv);
+ if (rc < 0) {
+ dev_err(ds->dev,
+ "Failed to disable microcontroller: %pe\n",
+ ERR_PTR(rc));
+ goto out_mdiobus_unregister;
+ }
+ }
+
/* Create and send configuration down to device */
- rc = sja1105_static_config_load(priv, ports);
+ rc = sja1105_static_config_load(priv);
if (rc < 0) {
dev_err(ds->dev, "Failed to load static config: %d\n", rc);
- goto out_ptp_clock_unregister;
+ goto out_mdiobus_unregister;
}
+
/* Configure the CGU (PHY link modes and speeds) */
- rc = sja1105_clocking_setup(priv);
- if (rc < 0) {
- dev_err(ds->dev, "Failed to configure MII clocking: %d\n", rc);
- goto out_static_config_free;
+ if (priv->info->clocking_setup) {
+ rc = priv->info->clocking_setup(priv);
+ if (rc < 0) {
+ dev_err(ds->dev,
+ "Failed to configure MII clocking: %pe\n",
+ ERR_PTR(rc));
+ goto out_static_config_free;
+ }
}
+
/* On SJA1105, VLAN filtering per se is always enabled in hardware.
* The only thing we can do to disable it is lie about what the 802.1Q
* EtherType is.
@@ -3029,6 +3106,8 @@ static int sja1105_setup(struct dsa_switch *ds)
out_devlink_teardown:
sja1105_devlink_teardown(ds);
+out_mdiobus_unregister:
+ sja1105_mdiobus_unregister(ds);
out_ptp_clock_unregister:
sja1105_ptp_clock_unregister(ds);
out_static_config_free:
@@ -3043,7 +3122,7 @@ static void sja1105_teardown(struct dsa_switch *ds)
struct sja1105_bridge_vlan *v, *n;
int port;
- for (port = 0; port < SJA1105_NUM_PORTS; port++) {
+ for (port = 0; port < ds->num_ports; port++) {
struct sja1105_port *sp = &priv->ports[port];
if (!dsa_is_user_port(ds, port))
@@ -3246,6 +3325,7 @@ static int sja1105_mirror_apply(struct sja1105_private *priv, int from, int to,
{
struct sja1105_general_params_entry *general_params;
struct sja1105_mac_config_entry *mac;
+ struct dsa_switch *ds = priv->ds;
struct sja1105_table *table;
bool already_enabled;
u64 new_mirr_port;
@@ -3256,7 +3336,7 @@ static int sja1105_mirror_apply(struct sja1105_private *priv, int from, int to,
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
- already_enabled = (general_params->mirr_port != SJA1105_NUM_PORTS);
+ already_enabled = (general_params->mirr_port != ds->num_ports);
if (already_enabled && enabled && general_params->mirr_port != to) {
dev_err(priv->ds->dev,
"Delete mirroring rules towards port %llu first\n",
@@ -3270,7 +3350,7 @@ static int sja1105_mirror_apply(struct sja1105_private *priv, int from, int to,
int port;
/* Anybody still referencing mirr_port? */
- for (port = 0; port < SJA1105_NUM_PORTS; port++) {
+ for (port = 0; port < ds->num_ports; port++) {
if (mac[port].ing_mirr || mac[port].egr_mirr) {
keep = true;
break;
@@ -3278,7 +3358,7 @@ static int sja1105_mirror_apply(struct sja1105_private *priv, int from, int to,
}
/* Unset already_enabled for next time */
if (!keep)
- new_mirr_port = SJA1105_NUM_PORTS;
+ new_mirr_port = ds->num_ports;
}
if (new_mirr_port != general_params->mirr_port) {
general_params->mirr_port = new_mirr_port;
@@ -3489,7 +3569,6 @@ static const struct dsa_switch_ops sja1105_switch_ops = {
.port_change_mtu = sja1105_change_mtu,
.port_max_mtu = sja1105_get_max_mtu,
.phylink_validate = sja1105_phylink_validate,
- .phylink_mac_link_state = sja1105_mac_pcs_get_state,
.phylink_mac_config = sja1105_mac_config,
.phylink_mac_link_up = sja1105_mac_link_up,
.phylink_mac_link_down = sja1105_mac_link_down,
@@ -3584,6 +3663,7 @@ static int sja1105_probe(struct spi_device *spi)
struct sja1105_tagger_data *tagger_data;
struct device *dev = &spi->dev;
struct sja1105_private *priv;
+ size_t max_xfer, max_msg;
struct dsa_switch *ds;
int rc, port;
@@ -3617,6 +3697,33 @@ static int sja1105_probe(struct spi_device *spi)
return rc;
}
+ /* In sja1105_xfer, we send spi_messages composed of two spi_transfers:
+ * a small one for the message header and another one for the current
+ * chunk of the packed buffer.
+ * Check that the restrictions imposed by the SPI controller are
+ * respected: the chunk buffer is smaller than the max transfer size,
+ * and the total length of the chunk plus its message header is smaller
+ * than the max message size.
+ * We do that during probe time since the maximum transfer size is a
+ * runtime invariant.
+ */
+ max_xfer = spi_max_transfer_size(spi);
+ max_msg = spi_max_message_size(spi);
+
+ /* We need to send at least one 64-bit word of SPI payload per message
+ * in order to be able to make useful progress.
+ */
+ if (max_msg < SJA1105_SIZE_SPI_MSG_HEADER + 8) {
+ dev_err(dev, "SPI master cannot send large enough buffers, aborting\n");
+ return -EINVAL;
+ }
+
+ priv->max_xfer_len = SJA1105_SIZE_SPI_MSG_MAXLEN;
+ if (priv->max_xfer_len > max_xfer)
+ priv->max_xfer_len = max_xfer;
+ if (priv->max_xfer_len > max_msg - SJA1105_SIZE_SPI_MSG_HEADER)
+ priv->max_xfer_len = max_msg - SJA1105_SIZE_SPI_MSG_HEADER;
+
priv->info = of_device_get_match_data(dev);
/* Detect hardware device */
@@ -3633,7 +3740,7 @@ static int sja1105_probe(struct spi_device *spi)
return -ENOMEM;
ds->dev = dev;
- ds->num_ports = SJA1105_NUM_PORTS;
+ ds->num_ports = priv->info->num_ports;
ds->ops = &sja1105_switch_ops;
ds->priv = priv;
priv->ds = ds;
@@ -3674,7 +3781,7 @@ static int sja1105_probe(struct spi_device *spi)
}
/* Connections between dsa_port and sja1105_port */
- for (port = 0; port < SJA1105_NUM_PORTS; port++) {
+ for (port = 0; port < ds->num_ports; port++) {
struct sja1105_port *sp = &priv->ports[port];
struct dsa_port *dp = dsa_to_port(ds, port);
struct net_device *slave;
@@ -3737,6 +3844,10 @@ static const struct of_device_id sja1105_dt_ids[] = {
{ .compatible = "nxp,sja1105q", .data = &sja1105q_info },
{ .compatible = "nxp,sja1105r", .data = &sja1105r_info },
{ .compatible = "nxp,sja1105s", .data = &sja1105s_info },
+ { .compatible = "nxp,sja1110a", .data = &sja1110a_info },
+ { .compatible = "nxp,sja1110b", .data = &sja1110b_info },
+ { .compatible = "nxp,sja1110c", .data = &sja1110c_info },
+ { .compatible = "nxp,sja1110d", .data = &sja1110d_info },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, sja1105_dt_ids);
diff --git a/drivers/net/dsa/sja1105/sja1105_mdio.c b/drivers/net/dsa/sja1105/sja1105_mdio.c
new file mode 100644
index 000000000000..19aea8fb76f6
--- /dev/null
+++ b/drivers/net/dsa/sja1105/sja1105_mdio.c
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2021, NXP Semiconductors
+ */
+#include <linux/pcs/pcs-xpcs.h>
+#include <linux/of_mdio.h>
+#include "sja1105.h"
+
+#define SJA1110_PCS_BANK_REG SJA1110_SPI_ADDR(0x3fc)
+
+int sja1105_pcs_mdio_read(struct mii_bus *bus, int phy, int reg)
+{
+ struct sja1105_mdio_private *mdio_priv = bus->priv;
+ struct sja1105_private *priv = mdio_priv->priv;
+ u64 addr;
+ u32 tmp;
+ u16 mmd;
+ int rc;
+
+ if (!(reg & MII_ADDR_C45))
+ return -EINVAL;
+
+ mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
+ addr = (mmd << 16) | (reg & GENMASK(15, 0));
+
+ if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2)
+ return 0xffff;
+
+ if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID1)
+ return NXP_SJA1105_XPCS_ID >> 16;
+ if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID2)
+ return NXP_SJA1105_XPCS_ID & GENMASK(15, 0);
+
+ rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);
+ if (rc < 0)
+ return rc;
+
+ return tmp & 0xffff;
+}
+
+int sja1105_pcs_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
+{
+ struct sja1105_mdio_private *mdio_priv = bus->priv;
+ struct sja1105_private *priv = mdio_priv->priv;
+ u64 addr;
+ u32 tmp;
+ u16 mmd;
+
+ if (!(reg & MII_ADDR_C45))
+ return -EINVAL;
+
+ mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
+ addr = (mmd << 16) | (reg & GENMASK(15, 0));
+ tmp = val;
+
+ if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2)
+ return -EINVAL;
+
+ return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
+}
+
+int sja1110_pcs_mdio_read(struct mii_bus *bus, int phy, int reg)
+{
+ struct sja1105_mdio_private *mdio_priv = bus->priv;
+ struct sja1105_private *priv = mdio_priv->priv;
+ const struct sja1105_regs *regs = priv->info->regs;
+ int offset, bank;
+ u64 addr;
+ u32 tmp;
+ u16 mmd;
+ int rc;
+
+ if (!(reg & MII_ADDR_C45))
+ return -EINVAL;
+
+ if (regs->pcs_base[phy] == SJA1105_RSV_ADDR)
+ return -ENODEV;
+
+ mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
+ addr = (mmd << 16) | (reg & GENMASK(15, 0));
+
+ if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID1)
+ return NXP_SJA1110_XPCS_ID >> 16;
+ if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID2)
+ return NXP_SJA1110_XPCS_ID & GENMASK(15, 0);
+
+ bank = addr >> 8;
+ offset = addr & GENMASK(7, 0);
+
+ /* This addressing scheme reserves register 0xff for the bank address
+ * register, so that can never be addressed.
+ */
+ if (WARN_ON(offset == 0xff))
+ return -ENODEV;
+
+ tmp = bank;
+
+ rc = sja1105_xfer_u32(priv, SPI_WRITE,
+ regs->pcs_base[phy] + SJA1110_PCS_BANK_REG,
+ &tmp, NULL);
+ if (rc < 0)
+ return rc;
+
+ rc = sja1105_xfer_u32(priv, SPI_READ, regs->pcs_base[phy] + offset,
+ &tmp, NULL);
+ if (rc < 0)
+ return rc;
+
+ return tmp & 0xffff;
+}
+
+int sja1110_pcs_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
+{
+ struct sja1105_mdio_private *mdio_priv = bus->priv;
+ struct sja1105_private *priv = mdio_priv->priv;
+ const struct sja1105_regs *regs = priv->info->regs;
+ int offset, bank;
+ u64 addr;
+ u32 tmp;
+ u16 mmd;
+ int rc;
+
+ if (!(reg & MII_ADDR_C45))
+ return -EINVAL;
+
+ if (regs->pcs_base[phy] == SJA1105_RSV_ADDR)
+ return -ENODEV;
+
+ mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
+ addr = (mmd << 16) | (reg & GENMASK(15, 0));
+
+ bank = addr >> 8;
+ offset = addr & GENMASK(7, 0);
+
+ /* This addressing scheme reserves register 0xff for the bank address
+ * register, so that can never be addressed.
+ */
+ if (WARN_ON(offset == 0xff))
+ return -ENODEV;
+
+ tmp = bank;
+
+ rc = sja1105_xfer_u32(priv, SPI_WRITE,
+ regs->pcs_base[phy] + SJA1110_PCS_BANK_REG,
+ &tmp, NULL);
+ if (rc < 0)
+ return rc;
+
+ tmp = val;
+
+ return sja1105_xfer_u32(priv, SPI_WRITE, regs->pcs_base[phy] + offset,
+ &tmp, NULL);
+}
+
+enum sja1105_mdio_opcode {
+ SJA1105_C45_ADDR = 0,
+ SJA1105_C22 = 1,
+ SJA1105_C45_DATA = 2,
+ SJA1105_C45_DATA_AUTOINC = 3,
+};
+
+static u64 sja1105_base_t1_encode_addr(struct sja1105_private *priv,
+ int phy, enum sja1105_mdio_opcode op,
+ int xad)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+
+ return regs->mdio_100base_t1 | (phy << 7) | (op << 5) | (xad << 0);
+}
+
+static int sja1105_base_t1_mdio_read(struct mii_bus *bus, int phy, int reg)
+{
+ struct sja1105_mdio_private *mdio_priv = bus->priv;
+ struct sja1105_private *priv = mdio_priv->priv;
+ u64 addr;
+ u32 tmp;
+ int rc;
+
+ if (reg & MII_ADDR_C45) {
+ u16 mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
+
+ addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR,
+ mmd);
+
+ tmp = reg & MII_REGADDR_C45_MASK;
+
+ rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
+ if (rc < 0)
+ return rc;
+
+ addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA,
+ mmd);
+
+ rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);
+ if (rc < 0)
+ return rc;
+
+ return tmp & 0xffff;
+ }
+
+ /* Clause 22 read */
+ addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f);
+
+ rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);
+ if (rc < 0)
+ return rc;
+
+ return tmp & 0xffff;
+}
+
+static int sja1105_base_t1_mdio_write(struct mii_bus *bus, int phy, int reg,
+ u16 val)
+{
+ struct sja1105_mdio_private *mdio_priv = bus->priv;
+ struct sja1105_private *priv = mdio_priv->priv;
+ u64 addr;
+ u32 tmp;
+ int rc;
+
+ if (reg & MII_ADDR_C45) {
+ u16 mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
+
+ addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR,
+ mmd);
+
+ tmp = reg & MII_REGADDR_C45_MASK;
+
+ rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
+ if (rc < 0)
+ return rc;
+
+ addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA,
+ mmd);
+
+ tmp = val & 0xffff;
+
+ rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+ }
+
+ /* Clause 22 write */
+ addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f);
+
+ tmp = val & 0xffff;
+
+ return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
+}
+
+static int sja1105_base_tx_mdio_read(struct mii_bus *bus, int phy, int reg)
+{
+ struct sja1105_mdio_private *mdio_priv = bus->priv;
+ struct sja1105_private *priv = mdio_priv->priv;
+ const struct sja1105_regs *regs = priv->info->regs;
+ u32 tmp;
+ int rc;
+
+ rc = sja1105_xfer_u32(priv, SPI_READ, regs->mdio_100base_tx + reg,
+ &tmp, NULL);
+ if (rc < 0)
+ return rc;
+
+ return tmp & 0xffff;
+}
+
+static int sja1105_base_tx_mdio_write(struct mii_bus *bus, int phy, int reg,
+ u16 val)
+{
+ struct sja1105_mdio_private *mdio_priv = bus->priv;
+ struct sja1105_private *priv = mdio_priv->priv;
+ const struct sja1105_regs *regs = priv->info->regs;
+ u32 tmp = val;
+
+ return sja1105_xfer_u32(priv, SPI_WRITE, regs->mdio_100base_tx + reg,
+ &tmp, NULL);
+}
+
+static int sja1105_mdiobus_base_tx_register(struct sja1105_private *priv,
+ struct device_node *mdio_node)
+{
+ struct sja1105_mdio_private *mdio_priv;
+ struct device_node *np;
+ struct mii_bus *bus;
+ int rc = 0;
+
+ np = of_find_compatible_node(mdio_node, NULL,
+ "nxp,sja1110-base-tx-mdio");
+ if (!np)
+ return 0;
+
+ if (!of_device_is_available(np))
+ goto out_put_np;
+
+ bus = mdiobus_alloc_size(sizeof(*mdio_priv));
+ if (!bus) {
+ rc = -ENOMEM;
+ goto out_put_np;
+ }
+
+ bus->name = "SJA1110 100base-TX MDIO bus";
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-tx",
+ dev_name(priv->ds->dev));
+ bus->read = sja1105_base_tx_mdio_read;
+ bus->write = sja1105_base_tx_mdio_write;
+ bus->parent = priv->ds->dev;
+ mdio_priv = bus->priv;
+ mdio_priv->priv = priv;
+
+ rc = of_mdiobus_register(bus, np);
+ if (rc) {
+ mdiobus_free(bus);
+ goto out_put_np;
+ }
+
+ priv->mdio_base_tx = bus;
+
+out_put_np:
+ of_node_put(np);
+
+ return rc;
+}
+
+static void sja1105_mdiobus_base_tx_unregister(struct sja1105_private *priv)
+{
+ if (!priv->mdio_base_tx)
+ return;
+
+ mdiobus_unregister(priv->mdio_base_tx);
+ mdiobus_free(priv->mdio_base_tx);
+ priv->mdio_base_tx = NULL;
+}
+
+static int sja1105_mdiobus_base_t1_register(struct sja1105_private *priv,
+ struct device_node *mdio_node)
+{
+ struct sja1105_mdio_private *mdio_priv;
+ struct device_node *np;
+ struct mii_bus *bus;
+ int rc = 0;
+
+ np = of_find_compatible_node(mdio_node, NULL,
+ "nxp,sja1110-base-t1-mdio");
+ if (!np)
+ return 0;
+
+ if (!of_device_is_available(np))
+ goto out_put_np;
+
+ bus = mdiobus_alloc_size(sizeof(*mdio_priv));
+ if (!bus) {
+ rc = -ENOMEM;
+ goto out_put_np;
+ }
+
+ bus->name = "SJA1110 100base-T1 MDIO bus";
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-t1",
+ dev_name(priv->ds->dev));
+ bus->read = sja1105_base_t1_mdio_read;
+ bus->write = sja1105_base_t1_mdio_write;
+ bus->parent = priv->ds->dev;
+ mdio_priv = bus->priv;
+ mdio_priv->priv = priv;
+
+ rc = of_mdiobus_register(bus, np);
+ if (rc) {
+ mdiobus_free(bus);
+ goto out_put_np;
+ }
+
+ priv->mdio_base_t1 = bus;
+
+out_put_np:
+ of_node_put(np);
+
+ return rc;
+}
+
+static void sja1105_mdiobus_base_t1_unregister(struct sja1105_private *priv)
+{
+ if (!priv->mdio_base_t1)
+ return;
+
+ mdiobus_unregister(priv->mdio_base_t1);
+ mdiobus_free(priv->mdio_base_t1);
+ priv->mdio_base_t1 = NULL;
+}
+
+static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv)
+{
+ struct sja1105_mdio_private *mdio_priv;
+ struct dsa_switch *ds = priv->ds;
+ struct mii_bus *bus;
+ int rc = 0;
+ int port;
+
+ if (!priv->info->pcs_mdio_read || !priv->info->pcs_mdio_write)
+ return 0;
+
+ bus = mdiobus_alloc_size(sizeof(*mdio_priv));
+ if (!bus)
+ return -ENOMEM;
+
+ bus->name = "SJA1105 PCS MDIO bus";
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-pcs",
+ dev_name(ds->dev));
+ bus->read = priv->info->pcs_mdio_read;
+ bus->write = priv->info->pcs_mdio_write;
+ bus->parent = ds->dev;
+ /* There is no PHY on this MDIO bus => mask out all PHY addresses
+ * from auto probing.
+ */
+ bus->phy_mask = ~0;
+ mdio_priv = bus->priv;
+ mdio_priv->priv = priv;
+
+ rc = mdiobus_register(bus);
+ if (rc) {
+ mdiobus_free(bus);
+ return rc;
+ }
+
+ for (port = 0; port < ds->num_ports; port++) {
+ struct mdio_device *mdiodev;
+ struct dw_xpcs *xpcs;
+
+ if (dsa_is_unused_port(ds, port))
+ continue;
+
+ if (priv->phy_mode[port] != PHY_INTERFACE_MODE_SGMII &&
+ priv->phy_mode[port] != PHY_INTERFACE_MODE_2500BASEX)
+ continue;
+
+ mdiodev = mdio_device_create(bus, port);
+ if (IS_ERR(mdiodev)) {
+ rc = PTR_ERR(mdiodev);
+ goto out_pcs_free;
+ }
+
+ xpcs = xpcs_create(mdiodev, priv->phy_mode[port]);
+ if (IS_ERR(xpcs)) {
+ rc = PTR_ERR(xpcs);
+ goto out_pcs_free;
+ }
+
+ priv->xpcs[port] = xpcs;
+ }
+
+ priv->mdio_pcs = bus;
+
+ return 0;
+
+out_pcs_free:
+ for (port = 0; port < ds->num_ports; port++) {
+ if (!priv->xpcs[port])
+ continue;
+
+ mdio_device_free(priv->xpcs[port]->mdiodev);
+ xpcs_destroy(priv->xpcs[port]);
+ priv->xpcs[port] = NULL;
+ }
+
+ mdiobus_unregister(bus);
+ mdiobus_free(bus);
+
+ return rc;
+}
+
+static void sja1105_mdiobus_pcs_unregister(struct sja1105_private *priv)
+{
+ struct dsa_switch *ds = priv->ds;
+ int port;
+
+ if (!priv->mdio_pcs)
+ return;
+
+ for (port = 0; port < ds->num_ports; port++) {
+ if (!priv->xpcs[port])
+ continue;
+
+ mdio_device_free(priv->xpcs[port]->mdiodev);
+ xpcs_destroy(priv->xpcs[port]);
+ priv->xpcs[port] = NULL;
+ }
+
+ mdiobus_unregister(priv->mdio_pcs);
+ mdiobus_free(priv->mdio_pcs);
+ priv->mdio_pcs = NULL;
+}
+
+int sja1105_mdiobus_register(struct dsa_switch *ds)
+{
+ struct sja1105_private *priv = ds->priv;
+ const struct sja1105_regs *regs = priv->info->regs;
+ struct device_node *switch_node = ds->dev->of_node;
+ struct device_node *mdio_node;
+ int rc;
+
+ rc = sja1105_mdiobus_pcs_register(priv);
+ if (rc)
+ return rc;
+
+ mdio_node = of_get_child_by_name(switch_node, "mdios");
+ if (!mdio_node)
+ return 0;
+
+ if (!of_device_is_available(mdio_node))
+ goto out_put_mdio_node;
+
+ if (regs->mdio_100base_tx != SJA1105_RSV_ADDR) {
+ rc = sja1105_mdiobus_base_tx_register(priv, mdio_node);
+ if (rc)
+ goto err_put_mdio_node;
+ }
+
+ if (regs->mdio_100base_t1 != SJA1105_RSV_ADDR) {
+ rc = sja1105_mdiobus_base_t1_register(priv, mdio_node);
+ if (rc)
+ goto err_free_base_tx_mdiobus;
+ }
+
+out_put_mdio_node:
+ of_node_put(mdio_node);
+
+ return 0;
+
+err_free_base_tx_mdiobus:
+ sja1105_mdiobus_base_tx_unregister(priv);
+err_put_mdio_node:
+ of_node_put(mdio_node);
+ sja1105_mdiobus_pcs_unregister(priv);
+
+ return rc;
+}
+
+void sja1105_mdiobus_unregister(struct dsa_switch *ds)
+{
+ struct sja1105_private *priv = ds->priv;
+
+ sja1105_mdiobus_base_t1_unregister(priv);
+ sja1105_mdiobus_base_tx_unregister(priv);
+ sja1105_mdiobus_pcs_unregister(priv);
+}
diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c
index 0bc566b9e958..691f6dd7e669 100644
--- a/drivers/net/dsa/sja1105/sja1105_ptp.c
+++ b/drivers/net/dsa/sja1105/sja1105_ptp.c
@@ -79,6 +79,7 @@ static int sja1105_change_rxtstamping(struct sja1105_private *priv,
priv->tagger_data.stampable_skb = NULL;
}
ptp_cancel_worker_sync(ptp_data->clock);
+ skb_queue_purge(&ptp_data->skb_txtstamp_queue);
skb_queue_purge(&ptp_data->skb_rxtstamp_queue);
return sja1105_static_config_reload(priv, SJA1105_RX_HWTSTAMPING);
@@ -397,7 +398,7 @@ static long sja1105_rxtstamp_work(struct ptp_clock_info *ptp)
*shwt = (struct skb_shared_hwtstamps) {0};
- ts = SJA1105_SKB_CB(skb)->meta_tstamp;
+ ts = SJA1105_SKB_CB(skb)->tstamp;
ts = sja1105_tstamp_reconstruct(ds, ticks, ts);
shwt->hwtstamp = ns_to_ktime(sja1105_ticks_to_ns(ts));
@@ -413,9 +414,7 @@ static long sja1105_rxtstamp_work(struct ptp_clock_info *ptp)
return -1;
}
-/* Called from dsa_skb_defer_rx_timestamp */
-bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port,
- struct sk_buff *skb, unsigned int type)
+bool sja1105_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
{
struct sja1105_private *priv = ds->priv;
struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
@@ -431,6 +430,89 @@ bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port,
return true;
}
+bool sja1110_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
+{
+ struct skb_shared_hwtstamps *shwt = skb_hwtstamps(skb);
+ u64 ts = SJA1105_SKB_CB(skb)->tstamp;
+
+ *shwt = (struct skb_shared_hwtstamps) {0};
+
+ shwt->hwtstamp = ns_to_ktime(sja1105_ticks_to_ns(ts));
+
+ /* Don't defer */
+ return false;
+}
+
+/* Called from dsa_skb_defer_rx_timestamp */
+bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *skb, unsigned int type)
+{
+ struct sja1105_private *priv = ds->priv;
+
+ return priv->info->rxtstamp(ds, port, skb);
+}
+
+void sja1110_process_meta_tstamp(struct dsa_switch *ds, int port, u8 ts_id,
+ enum sja1110_meta_tstamp dir, u64 tstamp)
+{
+ struct sja1105_private *priv = ds->priv;
+ struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
+ struct sk_buff *skb, *skb_tmp, *skb_match = NULL;
+ struct skb_shared_hwtstamps shwt = {0};
+
+ /* We don't care about RX timestamps on the CPU port */
+ if (dir == SJA1110_META_TSTAMP_RX)
+ return;
+
+ spin_lock(&ptp_data->skb_txtstamp_queue.lock);
+
+ skb_queue_walk_safe(&ptp_data->skb_txtstamp_queue, skb, skb_tmp) {
+ if (SJA1105_SKB_CB(skb)->ts_id != ts_id)
+ continue;
+
+ __skb_unlink(skb, &ptp_data->skb_txtstamp_queue);
+ skb_match = skb;
+
+ break;
+ }
+
+ spin_unlock(&ptp_data->skb_txtstamp_queue.lock);
+
+ if (WARN_ON(!skb_match))
+ return;
+
+ shwt.hwtstamp = ns_to_ktime(sja1105_ticks_to_ns(tstamp));
+ skb_complete_tx_timestamp(skb_match, &shwt);
+}
+EXPORT_SYMBOL_GPL(sja1110_process_meta_tstamp);
+
+/* In addition to cloning the skb which is done by the common
+ * sja1105_port_txtstamp, we need to generate a timestamp ID and save the
+ * packet to the TX timestamping queue.
+ */
+void sja1110_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
+{
+ struct sk_buff *clone = SJA1105_SKB_CB(skb)->clone;
+ struct sja1105_private *priv = ds->priv;
+ struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
+ struct sja1105_port *sp = &priv->ports[port];
+ u8 ts_id;
+
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+
+ spin_lock(&sp->data->meta_lock);
+
+ ts_id = sp->data->ts_id;
+ /* Deal automatically with 8-bit wraparound */
+ sp->data->ts_id++;
+
+ SJA1105_SKB_CB(clone)->ts_id = ts_id;
+
+ spin_unlock(&sp->data->meta_lock);
+
+ skb_queue_tail(&ptp_data->skb_txtstamp_queue, clone);
+}
+
/* Called from dsa_skb_tx_timestamp. This callback is just to clone
* the skb and have it available in SJA1105_SKB_CB in the .port_deferred_xmit
* callback, where we will timestamp it synchronously.
@@ -449,6 +531,9 @@ void sja1105_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
return;
SJA1105_SKB_CB(skb)->clone = clone;
+
+ if (priv->info->txtstamp)
+ priv->info->txtstamp(ds, port, skb);
}
static int sja1105_ptp_reset(struct dsa_switch *ds)
@@ -865,7 +950,10 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds)
.n_per_out = 1,
};
+ /* Only used on SJA1105 */
skb_queue_head_init(&ptp_data->skb_rxtstamp_queue);
+ /* Only used on SJA1110 */
+ skb_queue_head_init(&ptp_data->skb_txtstamp_queue);
spin_lock_init(&tagger_data->meta_lock);
ptp_data->clock = ptp_clock_register(&ptp_data->caps, ds->dev);
@@ -890,6 +978,7 @@ void sja1105_ptp_clock_unregister(struct dsa_switch *ds)
del_timer_sync(&ptp_data->extts_timer);
ptp_cancel_worker_sync(ptp_data->clock);
+ skb_queue_purge(&ptp_data->skb_txtstamp_queue);
skb_queue_purge(&ptp_data->skb_rxtstamp_queue);
ptp_clock_unregister(ptp_data->clock);
ptp_data->clock = NULL;
diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h
index 34f97f58a355..3c874bb4c17b 100644
--- a/drivers/net/dsa/sja1105/sja1105_ptp.h
+++ b/drivers/net/dsa/sja1105/sja1105_ptp.h
@@ -75,7 +75,12 @@ struct sja1105_ptp_cmd {
struct sja1105_ptp_data {
struct timer_list extts_timer;
+ /* Used only on SJA1105 to reconstruct partial timestamps */
struct sk_buff_head skb_rxtstamp_queue;
+ /* Used on SJA1110 where meta frames are generated only for
+ * 2-step TX timestamps
+ */
+ struct sk_buff_head skb_txtstamp_queue;
struct ptp_clock_info caps;
struct ptp_clock *clock;
struct sja1105_ptp_cmd cmd;
@@ -122,6 +127,10 @@ int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta);
int sja1105_ptp_commit(struct dsa_switch *ds, struct sja1105_ptp_cmd *cmd,
sja1105_spi_rw_mode_t rw);
+bool sja1105_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb);
+bool sja1110_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb);
+void sja1110_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb);
+
#else
struct sja1105_ptp_cmd;
@@ -184,6 +193,10 @@ static inline int sja1105_ptp_commit(struct dsa_switch *ds,
#define sja1105_hwtstamp_set NULL
+#define sja1105_rxtstamp NULL
+#define sja1110_rxtstamp NULL
+#define sja1110_txtstamp NULL
+
#endif /* IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP) */
#endif /* _SJA1105_PTP_H */
diff --git a/drivers/net/dsa/sja1105/sja1105_sgmii.h b/drivers/net/dsa/sja1105/sja1105_sgmii.h
deleted file mode 100644
index 24d9bc046e70..000000000000
--- a/drivers/net/dsa/sja1105/sja1105_sgmii.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/* Copyright 2020, NXP Semiconductors
- */
-#ifndef _SJA1105_SGMII_H
-#define _SJA1105_SGMII_H
-
-#define SJA1105_SGMII_PORT 4
-
-/* DIGITAL_CONTROL_1 (address 1f8000h) */
-#define SJA1105_DC1 0x8000
-#define SJA1105_DC1_VS_RESET BIT(15)
-#define SJA1105_DC1_REMOTE_LOOPBACK BIT(14)
-#define SJA1105_DC1_EN_VSMMD1 BIT(13)
-#define SJA1105_DC1_POWER_SAVE BIT(11)
-#define SJA1105_DC1_CLOCK_STOP_EN BIT(10)
-#define SJA1105_DC1_MAC_AUTO_SW BIT(9)
-#define SJA1105_DC1_INIT BIT(8)
-#define SJA1105_DC1_TX_DISABLE BIT(4)
-#define SJA1105_DC1_AUTONEG_TIMER_OVRR BIT(3)
-#define SJA1105_DC1_BYP_POWERUP BIT(1)
-#define SJA1105_DC1_PHY_MODE_CONTROL BIT(0)
-
-/* DIGITAL_CONTROL_2 register (address 1f80E1h) */
-#define SJA1105_DC2 0x80e1
-#define SJA1105_DC2_TX_POL_INV_DISABLE BIT(4)
-#define SJA1105_DC2_RX_POL_INV BIT(0)
-
-/* DIGITAL_ERROR_CNT register (address 1f80E2h) */
-#define SJA1105_DEC 0x80e2
-#define SJA1105_DEC_ICG_EC_ENA BIT(4)
-#define SJA1105_DEC_CLEAR_ON_READ BIT(0)
-
-/* AUTONEG_CONTROL register (address 1f8001h) */
-#define SJA1105_AC 0x8001
-#define SJA1105_AC_MII_CONTROL BIT(8)
-#define SJA1105_AC_SGMII_LINK BIT(4)
-#define SJA1105_AC_PHY_MODE BIT(3)
-#define SJA1105_AC_AUTONEG_MODE(x) (((x) << 1) & GENMASK(2, 1))
-#define SJA1105_AC_AUTONEG_MODE_SGMII SJA1105_AC_AUTONEG_MODE(2)
-
-/* AUTONEG_INTR_STATUS register (address 1f8002h) */
-#define SJA1105_AIS 0x8002
-#define SJA1105_AIS_LINK_STATUS(x) (!!((x) & BIT(4)))
-#define SJA1105_AIS_SPEED(x) (((x) & GENMASK(3, 2)) >> 2)
-#define SJA1105_AIS_DUPLEX_MODE(x) (!!((x) & BIT(1)))
-#define SJA1105_AIS_COMPLETE(x) (!!((x) & BIT(0)))
-
-/* DEBUG_CONTROL register (address 1f8005h) */
-#define SJA1105_DC 0x8005
-#define SJA1105_DC_SUPPRESS_LOS BIT(4)
-#define SJA1105_DC_RESTART_SYNC BIT(0)
-
-#endif
diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c
index f7a1514f81e8..08cc5dbf2fa6 100644
--- a/drivers/net/dsa/sja1105/sja1105_spi.c
+++ b/drivers/net/dsa/sja1105/sja1105_spi.c
@@ -7,10 +7,6 @@
#include <linux/packing.h>
#include "sja1105.h"
-#define SJA1105_SIZE_RESET_CMD 4
-#define SJA1105_SIZE_SPI_MSG_HEADER 4
-#define SJA1105_SIZE_SPI_MSG_MAXLEN (64 * 4)
-
struct sja1105_chunk {
u8 *buf;
size_t len;
@@ -29,13 +25,6 @@ sja1105_spi_message_pack(void *buf, const struct sja1105_spi_message *msg)
sja1105_pack(buf, &msg->address, 24, 4, size);
}
-#define sja1105_hdr_xfer(xfers, chunk) \
- ((xfers) + 2 * (chunk))
-#define sja1105_chunk_xfer(xfers, chunk) \
- ((xfers) + 2 * (chunk) + 1)
-#define sja1105_hdr_buf(hdr_bufs, chunk) \
- ((hdr_bufs) + (chunk) * SJA1105_SIZE_SPI_MSG_HEADER)
-
/* If @rw is:
* - SPI_WRITE: creates and sends an SPI write message at absolute
* address reg_addr, taking @len bytes from *buf
@@ -46,41 +35,25 @@ static int sja1105_xfer(const struct sja1105_private *priv,
sja1105_spi_rw_mode_t rw, u64 reg_addr, u8 *buf,
size_t len, struct ptp_system_timestamp *ptp_sts)
{
- struct sja1105_chunk chunk = {
- .len = min_t(size_t, len, SJA1105_SIZE_SPI_MSG_MAXLEN),
- .reg_addr = reg_addr,
- .buf = buf,
- };
+ u8 hdr_buf[SJA1105_SIZE_SPI_MSG_HEADER] = {0};
struct spi_device *spi = priv->spidev;
- struct spi_transfer *xfers;
+ struct spi_transfer xfers[2] = {0};
+ struct spi_transfer *chunk_xfer;
+ struct spi_transfer *hdr_xfer;
+ struct sja1105_chunk chunk;
int num_chunks;
int rc, i = 0;
- u8 *hdr_bufs;
- num_chunks = DIV_ROUND_UP(len, SJA1105_SIZE_SPI_MSG_MAXLEN);
+ num_chunks = DIV_ROUND_UP(len, priv->max_xfer_len);
- /* One transfer for each message header, one for each message
- * payload (chunk).
- */
- xfers = kcalloc(2 * num_chunks, sizeof(struct spi_transfer),
- GFP_KERNEL);
- if (!xfers)
- return -ENOMEM;
+ chunk.reg_addr = reg_addr;
+ chunk.buf = buf;
+ chunk.len = min_t(size_t, len, priv->max_xfer_len);
- /* Packed buffers for the num_chunks SPI message headers,
- * stored as a contiguous array
- */
- hdr_bufs = kcalloc(num_chunks, SJA1105_SIZE_SPI_MSG_HEADER,
- GFP_KERNEL);
- if (!hdr_bufs) {
- kfree(xfers);
- return -ENOMEM;
- }
+ hdr_xfer = &xfers[0];
+ chunk_xfer = &xfers[1];
for (i = 0; i < num_chunks; i++) {
- struct spi_transfer *chunk_xfer = sja1105_chunk_xfer(xfers, i);
- struct spi_transfer *hdr_xfer = sja1105_hdr_xfer(xfers, i);
- u8 *hdr_buf = sja1105_hdr_buf(hdr_bufs, i);
struct spi_transfer *ptp_sts_xfer;
struct sja1105_spi_message msg;
@@ -127,21 +100,16 @@ static int sja1105_xfer(const struct sja1105_private *priv,
chunk.buf += chunk.len;
chunk.reg_addr += chunk.len / 4;
chunk.len = min_t(size_t, (ptrdiff_t)(buf + len - chunk.buf),
- SJA1105_SIZE_SPI_MSG_MAXLEN);
+ priv->max_xfer_len);
- /* De-assert the chip select after each chunk. */
- if (chunk.len)
- chunk_xfer->cs_change = 1;
+ rc = spi_sync_transfer(spi, xfers, 2);
+ if (rc < 0) {
+ dev_err(&spi->dev, "SPI transfer failed: %d\n", rc);
+ return rc;
+ }
}
- rc = spi_sync_transfer(spi, xfers, 2 * num_chunks);
- if (rc < 0)
- dev_err(&spi->dev, "SPI transfer failed: %d\n", rc);
-
- kfree(hdr_bufs);
- kfree(xfers);
-
- return rc;
+ return 0;
}
int sja1105_xfer_buf(const struct sja1105_private *priv,
@@ -209,28 +177,34 @@ static int sja1105et_reset_cmd(struct dsa_switch *ds)
{
struct sja1105_private *priv = ds->priv;
const struct sja1105_regs *regs = priv->info->regs;
- u8 packed_buf[SJA1105_SIZE_RESET_CMD] = {0};
- const int size = SJA1105_SIZE_RESET_CMD;
- u64 cold_rst = 1;
+ u32 cold_reset = BIT(3);
- sja1105_pack(packed_buf, &cold_rst, 3, 3, size);
-
- return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgu, packed_buf,
- SJA1105_SIZE_RESET_CMD);
+ /* Cold reset */
+ return sja1105_xfer_u32(priv, SPI_WRITE, regs->rgu, &cold_reset, NULL);
}
static int sja1105pqrs_reset_cmd(struct dsa_switch *ds)
{
struct sja1105_private *priv = ds->priv;
const struct sja1105_regs *regs = priv->info->regs;
- u8 packed_buf[SJA1105_SIZE_RESET_CMD] = {0};
- const int size = SJA1105_SIZE_RESET_CMD;
- u64 cold_rst = 1;
+ u32 cold_reset = BIT(2);
- sja1105_pack(packed_buf, &cold_rst, 2, 2, size);
+ /* Cold reset */
+ return sja1105_xfer_u32(priv, SPI_WRITE, regs->rgu, &cold_reset, NULL);
+}
- return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgu, packed_buf,
- SJA1105_SIZE_RESET_CMD);
+static int sja1110_reset_cmd(struct dsa_switch *ds)
+{
+ struct sja1105_private *priv = ds->priv;
+ const struct sja1105_regs *regs = priv->info->regs;
+ u32 switch_reset = BIT(20);
+
+ /* Only reset the switch core.
+ * A full cold reset would re-enable the BASE_MCSS_CLOCK PLL which
+ * would turn on the microcontroller, potentially letting it execute
+ * code which could interfere with our configuration.
+ */
+ return sja1105_xfer_u32(priv, SPI_WRITE, regs->rgu, &switch_reset, NULL);
}
int sja1105_inhibit_tx(const struct sja1105_private *priv,
@@ -311,7 +285,8 @@ int static_config_buf_prepare_for_upload(struct sja1105_private *priv,
char *final_header_ptr;
int crc_len;
- valid = sja1105_static_config_check_valid(config);
+ valid = sja1105_static_config_check_valid(config,
+ priv->info->max_frame_mem);
if (valid != SJA1105_CONFIG_OK) {
dev_err(&priv->spidev->dev,
sja1105_static_config_error_msg[valid]);
@@ -339,10 +314,10 @@ int static_config_buf_prepare_for_upload(struct sja1105_private *priv,
int sja1105_static_config_upload(struct sja1105_private *priv)
{
- unsigned long port_bitmap = GENMASK_ULL(SJA1105_NUM_PORTS - 1, 0);
struct sja1105_static_config *config = &priv->static_config;
const struct sja1105_regs *regs = priv->info->regs;
struct device *dev = &priv->spidev->dev;
+ struct dsa_switch *ds = priv->ds;
struct sja1105_status status;
int rc, retries = RETRIES;
u8 *config_buf;
@@ -363,7 +338,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, true);
+ rc = sja1105_inhibit_tx(priv, GENMASK_ULL(ds->num_ports - 1, 0), true);
if (rc < 0) {
dev_err(dev, "Failed to inhibit Tx on ports\n");
rc = -ENXIO;
@@ -433,7 +408,7 @@ out:
return rc;
}
-static struct sja1105_regs sja1105et_regs = {
+static const struct sja1105_regs sja1105et_regs = {
.device_id = 0x0,
.prod_id = 0x100BC3,
.status = 0x1,
@@ -446,9 +421,9 @@ static struct sja1105_regs sja1105et_regs = {
.pad_mii_rx = {0x100801, 0x100803, 0x100805, 0x100807, 0x100809},
.rmii_pll1 = 0x10000A,
.cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
- .mac = {0x200, 0x202, 0x204, 0x206, 0x208},
- .mac_hl1 = {0x400, 0x410, 0x420, 0x430, 0x440},
- .mac_hl2 = {0x600, 0x610, 0x620, 0x630, 0x640},
+ .stats[MAC] = {0x200, 0x202, 0x204, 0x206, 0x208},
+ .stats[HL1] = {0x400, 0x410, 0x420, 0x430, 0x440},
+ .stats[HL2] = {0x600, 0x610, 0x620, 0x630, 0x640},
/* UM10944.pdf, Table 78, CGU Register overview */
.mii_tx_clk = {0x100013, 0x10001A, 0x100021, 0x100028, 0x10002F},
.mii_rx_clk = {0x100014, 0x10001B, 0x100022, 0x100029, 0x100030},
@@ -465,9 +440,11 @@ static struct sja1105_regs sja1105et_regs = {
.ptpclkval = 0x18, /* Spans 0x18 to 0x19 */
.ptpclkrate = 0x1A,
.ptpclkcorp = 0x1D,
+ .mdio_100base_tx = SJA1105_RSV_ADDR,
+ .mdio_100base_t1 = SJA1105_RSV_ADDR,
};
-static struct sja1105_regs sja1105pqrs_regs = {
+static const struct sja1105_regs sja1105pqrs_regs = {
.device_id = 0x0,
.prod_id = 0x100BC3,
.status = 0x1,
@@ -479,13 +456,12 @@ static struct sja1105_regs sja1105pqrs_regs = {
.pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
.pad_mii_rx = {0x100801, 0x100803, 0x100805, 0x100807, 0x100809},
.pad_mii_id = {0x100810, 0x100811, 0x100812, 0x100813, 0x100814},
- .sgmii = 0x1F0000,
.rmii_pll1 = 0x10000A,
.cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
- .mac = {0x200, 0x202, 0x204, 0x206, 0x208},
- .mac_hl1 = {0x400, 0x410, 0x420, 0x430, 0x440},
- .mac_hl2 = {0x600, 0x610, 0x620, 0x630, 0x640},
- .ether_stats = {0x1400, 0x1418, 0x1430, 0x1448, 0x1460},
+ .stats[MAC] = {0x200, 0x202, 0x204, 0x206, 0x208},
+ .stats[HL1] = {0x400, 0x410, 0x420, 0x430, 0x440},
+ .stats[HL2] = {0x600, 0x610, 0x620, 0x630, 0x640},
+ .stats[ETHER] = {0x1400, 0x1418, 0x1430, 0x1448, 0x1460},
/* UM11040.pdf, Table 114 */
.mii_tx_clk = {0x100013, 0x100019, 0x10001F, 0x100025, 0x10002B},
.mii_rx_clk = {0x100014, 0x10001A, 0x100020, 0x100026, 0x10002C},
@@ -494,7 +470,6 @@ static struct sja1105_regs sja1105pqrs_regs = {
.rgmii_tx_clk = {0x100016, 0x10001C, 0x100022, 0x100028, 0x10002E},
.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},
.ptpschtm = 0x13, /* Spans 0x13 to 0x14 */
.ptppinst = 0x15,
@@ -504,6 +479,95 @@ static struct sja1105_regs sja1105pqrs_regs = {
.ptpclkrate = 0x1B,
.ptpclkcorp = 0x1E,
.ptpsyncts = 0x1F,
+ .mdio_100base_tx = SJA1105_RSV_ADDR,
+ .mdio_100base_t1 = SJA1105_RSV_ADDR,
+};
+
+static const struct sja1105_regs sja1110_regs = {
+ .device_id = SJA1110_SPI_ADDR(0x0),
+ .prod_id = SJA1110_ACU_ADDR(0xf00),
+ .status = SJA1110_SPI_ADDR(0x4),
+ .port_control = SJA1110_SPI_ADDR(0x50), /* actually INHIB_TX */
+ .vl_status = 0x10000,
+ .config = 0x020000,
+ .rgu = SJA1110_RGU_ADDR(0x100), /* Reset Control Register 0 */
+ /* Ports 2 and 3 are capable of xMII, but there isn't anything to
+ * configure in the CGU/ACU for them.
+ */
+ .pad_mii_tx = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR},
+ .pad_mii_rx = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR},
+ .pad_mii_id = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1110_ACU_ADDR(0x18), SJA1110_ACU_ADDR(0x28),
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR},
+ .rmii_pll1 = SJA1105_RSV_ADDR,
+ .cgu_idiv = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+ .stats[MAC] = {0x200, 0x202, 0x204, 0x206, 0x208, 0x20a,
+ 0x20c, 0x20e, 0x210, 0x212, 0x214},
+ .stats[HL1] = {0x400, 0x410, 0x420, 0x430, 0x440, 0x450,
+ 0x460, 0x470, 0x480, 0x490, 0x4a0},
+ .stats[HL2] = {0x600, 0x610, 0x620, 0x630, 0x640, 0x650,
+ 0x660, 0x670, 0x680, 0x690, 0x6a0},
+ .stats[ETHER] = {0x1400, 0x1418, 0x1430, 0x1448, 0x1460, 0x1478,
+ 0x1490, 0x14a8, 0x14c0, 0x14d8, 0x14f0},
+ .mii_tx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+ .mii_rx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+ .mii_ext_tx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+ .mii_ext_rx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+ .rgmii_tx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+ .rmii_ref_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+ .rmii_ext_tx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR},
+ .ptpschtm = SJA1110_SPI_ADDR(0x54),
+ .ptppinst = SJA1110_SPI_ADDR(0x5c),
+ .ptppindur = SJA1110_SPI_ADDR(0x64),
+ .ptp_control = SJA1110_SPI_ADDR(0x68),
+ .ptpclkval = SJA1110_SPI_ADDR(0x6c),
+ .ptpclkrate = SJA1110_SPI_ADDR(0x74),
+ .ptpclkcorp = SJA1110_SPI_ADDR(0x80),
+ .ptpsyncts = SJA1110_SPI_ADDR(0x84),
+ .mdio_100base_tx = 0x1c2400,
+ .mdio_100base_t1 = 0x1c1000,
+ .pcs_base = {SJA1105_RSV_ADDR, 0x1c1400, 0x1c1800, 0x1c1c00, 0x1c2000,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+ SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
};
const struct sja1105_info sja1105e_info = {
@@ -512,15 +576,30 @@ const struct sja1105_info sja1105e_info = {
.static_ops = sja1105e_table_ops,
.dyn_ops = sja1105et_dyn_ops,
.qinq_tpid = ETH_P_8021Q,
+ .tag_proto = DSA_TAG_PROTO_SJA1105,
.can_limit_mcast_flood = false,
.ptp_ts_bits = 24,
.ptpegr_ts_bytes = 4,
+ .max_frame_mem = SJA1105_MAX_FRAME_MEMORY,
+ .num_ports = SJA1105_NUM_PORTS,
.num_cbs_shapers = SJA1105ET_MAX_CBS_COUNT,
.reset_cmd = sja1105et_reset_cmd,
.fdb_add_cmd = sja1105et_fdb_add,
.fdb_del_cmd = sja1105et_fdb_del,
.ptp_cmd_packing = sja1105et_ptp_cmd_packing,
+ .rxtstamp = sja1105_rxtstamp,
+ .clocking_setup = sja1105_clocking_setup,
.regs = &sja1105et_regs,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 3,
+ [SJA1105_SPEED_100MBPS] = 2,
+ [SJA1105_SPEED_1000MBPS] = 1,
+ [SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
+ },
+ .supports_mii = {true, true, true, true, true},
+ .supports_rmii = {true, true, true, true, true},
+ .supports_rgmii = {true, true, true, true, true},
.name = "SJA1105E",
};
@@ -530,15 +609,30 @@ const struct sja1105_info sja1105t_info = {
.static_ops = sja1105t_table_ops,
.dyn_ops = sja1105et_dyn_ops,
.qinq_tpid = ETH_P_8021Q,
+ .tag_proto = DSA_TAG_PROTO_SJA1105,
.can_limit_mcast_flood = false,
.ptp_ts_bits = 24,
.ptpegr_ts_bytes = 4,
+ .max_frame_mem = SJA1105_MAX_FRAME_MEMORY,
+ .num_ports = SJA1105_NUM_PORTS,
.num_cbs_shapers = SJA1105ET_MAX_CBS_COUNT,
.reset_cmd = sja1105et_reset_cmd,
.fdb_add_cmd = sja1105et_fdb_add,
.fdb_del_cmd = sja1105et_fdb_del,
.ptp_cmd_packing = sja1105et_ptp_cmd_packing,
+ .rxtstamp = sja1105_rxtstamp,
+ .clocking_setup = sja1105_clocking_setup,
.regs = &sja1105et_regs,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 3,
+ [SJA1105_SPEED_100MBPS] = 2,
+ [SJA1105_SPEED_1000MBPS] = 1,
+ [SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
+ },
+ .supports_mii = {true, true, true, true, true},
+ .supports_rmii = {true, true, true, true, true},
+ .supports_rgmii = {true, true, true, true, true},
.name = "SJA1105T",
};
@@ -548,16 +642,31 @@ const struct sja1105_info sja1105p_info = {
.static_ops = sja1105p_table_ops,
.dyn_ops = sja1105pqrs_dyn_ops,
.qinq_tpid = ETH_P_8021AD,
+ .tag_proto = DSA_TAG_PROTO_SJA1105,
.can_limit_mcast_flood = true,
.ptp_ts_bits = 32,
.ptpegr_ts_bytes = 8,
+ .max_frame_mem = SJA1105_MAX_FRAME_MEMORY,
+ .num_ports = SJA1105_NUM_PORTS,
.num_cbs_shapers = SJA1105PQRS_MAX_CBS_COUNT,
.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_packing = sja1105pqrs_ptp_cmd_packing,
+ .rxtstamp = sja1105_rxtstamp,
+ .clocking_setup = sja1105_clocking_setup,
.regs = &sja1105pqrs_regs,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 3,
+ [SJA1105_SPEED_100MBPS] = 2,
+ [SJA1105_SPEED_1000MBPS] = 1,
+ [SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
+ },
+ .supports_mii = {true, true, true, true, true},
+ .supports_rmii = {true, true, true, true, true},
+ .supports_rgmii = {true, true, true, true, true},
.name = "SJA1105P",
};
@@ -567,16 +676,31 @@ const struct sja1105_info sja1105q_info = {
.static_ops = sja1105q_table_ops,
.dyn_ops = sja1105pqrs_dyn_ops,
.qinq_tpid = ETH_P_8021AD,
+ .tag_proto = DSA_TAG_PROTO_SJA1105,
.can_limit_mcast_flood = true,
.ptp_ts_bits = 32,
.ptpegr_ts_bytes = 8,
+ .max_frame_mem = SJA1105_MAX_FRAME_MEMORY,
+ .num_ports = SJA1105_NUM_PORTS,
.num_cbs_shapers = SJA1105PQRS_MAX_CBS_COUNT,
.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_packing = sja1105pqrs_ptp_cmd_packing,
+ .rxtstamp = sja1105_rxtstamp,
+ .clocking_setup = sja1105_clocking_setup,
.regs = &sja1105pqrs_regs,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 3,
+ [SJA1105_SPEED_100MBPS] = 2,
+ [SJA1105_SPEED_1000MBPS] = 1,
+ [SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
+ },
+ .supports_mii = {true, true, true, true, true},
+ .supports_rmii = {true, true, true, true, true},
+ .supports_rgmii = {true, true, true, true, true},
.name = "SJA1105Q",
};
@@ -586,16 +710,34 @@ const struct sja1105_info sja1105r_info = {
.static_ops = sja1105r_table_ops,
.dyn_ops = sja1105pqrs_dyn_ops,
.qinq_tpid = ETH_P_8021AD,
+ .tag_proto = DSA_TAG_PROTO_SJA1105,
.can_limit_mcast_flood = true,
.ptp_ts_bits = 32,
.ptpegr_ts_bytes = 8,
+ .max_frame_mem = SJA1105_MAX_FRAME_MEMORY,
+ .num_ports = SJA1105_NUM_PORTS,
.num_cbs_shapers = SJA1105PQRS_MAX_CBS_COUNT,
.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_packing = sja1105pqrs_ptp_cmd_packing,
+ .rxtstamp = sja1105_rxtstamp,
+ .clocking_setup = sja1105_clocking_setup,
+ .pcs_mdio_read = sja1105_pcs_mdio_read,
+ .pcs_mdio_write = sja1105_pcs_mdio_write,
.regs = &sja1105pqrs_regs,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 3,
+ [SJA1105_SPEED_100MBPS] = 2,
+ [SJA1105_SPEED_1000MBPS] = 1,
+ [SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
+ },
+ .supports_mii = {true, true, true, true, true},
+ .supports_rmii = {true, true, true, true, true},
+ .supports_rgmii = {true, true, true, true, true},
+ .supports_sgmii = {false, false, false, false, true},
.name = "SJA1105R",
};
@@ -606,14 +748,236 @@ const struct sja1105_info sja1105s_info = {
.dyn_ops = sja1105pqrs_dyn_ops,
.regs = &sja1105pqrs_regs,
.qinq_tpid = ETH_P_8021AD,
+ .tag_proto = DSA_TAG_PROTO_SJA1105,
.can_limit_mcast_flood = true,
.ptp_ts_bits = 32,
.ptpegr_ts_bytes = 8,
+ .max_frame_mem = SJA1105_MAX_FRAME_MEMORY,
+ .num_ports = SJA1105_NUM_PORTS,
.num_cbs_shapers = SJA1105PQRS_MAX_CBS_COUNT,
.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_packing = sja1105pqrs_ptp_cmd_packing,
+ .rxtstamp = sja1105_rxtstamp,
+ .clocking_setup = sja1105_clocking_setup,
+ .pcs_mdio_read = sja1105_pcs_mdio_read,
+ .pcs_mdio_write = sja1105_pcs_mdio_write,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 3,
+ [SJA1105_SPEED_100MBPS] = 2,
+ [SJA1105_SPEED_1000MBPS] = 1,
+ [SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
+ },
+ .supports_mii = {true, true, true, true, true},
+ .supports_rmii = {true, true, true, true, true},
+ .supports_rgmii = {true, true, true, true, true},
+ .supports_sgmii = {false, false, false, false, true},
.name = "SJA1105S",
};
+
+const struct sja1105_info sja1110a_info = {
+ .device_id = SJA1110_DEVICE_ID,
+ .part_no = SJA1110A_PART_NO,
+ .static_ops = sja1110_table_ops,
+ .dyn_ops = sja1110_dyn_ops,
+ .regs = &sja1110_regs,
+ .qinq_tpid = ETH_P_8021AD,
+ .tag_proto = DSA_TAG_PROTO_SJA1110,
+ .can_limit_mcast_flood = true,
+ .multiple_cascade_ports = true,
+ .ptp_ts_bits = 32,
+ .ptpegr_ts_bytes = 8,
+ .max_frame_mem = SJA1110_MAX_FRAME_MEMORY,
+ .num_ports = SJA1110_NUM_PORTS,
+ .num_cbs_shapers = SJA1110_MAX_CBS_COUNT,
+ .setup_rgmii_delay = sja1110_setup_rgmii_delay,
+ .reset_cmd = sja1110_reset_cmd,
+ .fdb_add_cmd = sja1105pqrs_fdb_add,
+ .fdb_del_cmd = sja1105pqrs_fdb_del,
+ .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing,
+ .rxtstamp = sja1110_rxtstamp,
+ .txtstamp = sja1110_txtstamp,
+ .disable_microcontroller = sja1110_disable_microcontroller,
+ .pcs_mdio_read = sja1110_pcs_mdio_read,
+ .pcs_mdio_write = sja1110_pcs_mdio_write,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 4,
+ [SJA1105_SPEED_100MBPS] = 3,
+ [SJA1105_SPEED_1000MBPS] = 2,
+ [SJA1105_SPEED_2500MBPS] = 1,
+ },
+ .supports_mii = {true, true, true, true, false,
+ true, true, true, true, true, true},
+ .supports_rmii = {false, false, true, true, false,
+ false, false, false, false, false, false},
+ .supports_rgmii = {false, false, true, true, false,
+ false, false, false, false, false, false},
+ .supports_sgmii = {false, true, true, true, true,
+ false, false, false, false, false, false},
+ .supports_2500basex = {false, false, false, true, true,
+ false, false, false, false, false, false},
+ .internal_phy = {SJA1105_NO_PHY, SJA1105_PHY_BASE_TX,
+ SJA1105_NO_PHY, SJA1105_NO_PHY,
+ SJA1105_NO_PHY, SJA1105_PHY_BASE_T1,
+ SJA1105_PHY_BASE_T1, SJA1105_PHY_BASE_T1,
+ SJA1105_PHY_BASE_T1, SJA1105_PHY_BASE_T1,
+ SJA1105_PHY_BASE_T1},
+ .name = "SJA1110A",
+};
+
+const struct sja1105_info sja1110b_info = {
+ .device_id = SJA1110_DEVICE_ID,
+ .part_no = SJA1110B_PART_NO,
+ .static_ops = sja1110_table_ops,
+ .dyn_ops = sja1110_dyn_ops,
+ .regs = &sja1110_regs,
+ .qinq_tpid = ETH_P_8021AD,
+ .tag_proto = DSA_TAG_PROTO_SJA1110,
+ .can_limit_mcast_flood = true,
+ .multiple_cascade_ports = true,
+ .ptp_ts_bits = 32,
+ .ptpegr_ts_bytes = 8,
+ .max_frame_mem = SJA1110_MAX_FRAME_MEMORY,
+ .num_ports = SJA1110_NUM_PORTS,
+ .num_cbs_shapers = SJA1110_MAX_CBS_COUNT,
+ .setup_rgmii_delay = sja1110_setup_rgmii_delay,
+ .reset_cmd = sja1110_reset_cmd,
+ .fdb_add_cmd = sja1105pqrs_fdb_add,
+ .fdb_del_cmd = sja1105pqrs_fdb_del,
+ .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing,
+ .rxtstamp = sja1110_rxtstamp,
+ .txtstamp = sja1110_txtstamp,
+ .disable_microcontroller = sja1110_disable_microcontroller,
+ .pcs_mdio_read = sja1110_pcs_mdio_read,
+ .pcs_mdio_write = sja1110_pcs_mdio_write,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 4,
+ [SJA1105_SPEED_100MBPS] = 3,
+ [SJA1105_SPEED_1000MBPS] = 2,
+ [SJA1105_SPEED_2500MBPS] = 1,
+ },
+ .supports_mii = {true, true, true, true, false,
+ true, true, true, true, true, false},
+ .supports_rmii = {false, false, true, true, false,
+ false, false, false, false, false, false},
+ .supports_rgmii = {false, false, true, true, false,
+ false, false, false, false, false, false},
+ .supports_sgmii = {false, false, false, true, true,
+ false, false, false, false, false, false},
+ .supports_2500basex = {false, false, false, true, true,
+ false, false, false, false, false, false},
+ .internal_phy = {SJA1105_NO_PHY, SJA1105_PHY_BASE_TX,
+ SJA1105_NO_PHY, SJA1105_NO_PHY,
+ SJA1105_NO_PHY, SJA1105_PHY_BASE_T1,
+ SJA1105_PHY_BASE_T1, SJA1105_PHY_BASE_T1,
+ SJA1105_PHY_BASE_T1, SJA1105_PHY_BASE_T1,
+ SJA1105_NO_PHY},
+ .name = "SJA1110B",
+};
+
+const struct sja1105_info sja1110c_info = {
+ .device_id = SJA1110_DEVICE_ID,
+ .part_no = SJA1110C_PART_NO,
+ .static_ops = sja1110_table_ops,
+ .dyn_ops = sja1110_dyn_ops,
+ .regs = &sja1110_regs,
+ .qinq_tpid = ETH_P_8021AD,
+ .tag_proto = DSA_TAG_PROTO_SJA1110,
+ .can_limit_mcast_flood = true,
+ .multiple_cascade_ports = true,
+ .ptp_ts_bits = 32,
+ .ptpegr_ts_bytes = 8,
+ .max_frame_mem = SJA1110_MAX_FRAME_MEMORY,
+ .num_ports = SJA1110_NUM_PORTS,
+ .num_cbs_shapers = SJA1110_MAX_CBS_COUNT,
+ .setup_rgmii_delay = sja1110_setup_rgmii_delay,
+ .reset_cmd = sja1110_reset_cmd,
+ .fdb_add_cmd = sja1105pqrs_fdb_add,
+ .fdb_del_cmd = sja1105pqrs_fdb_del,
+ .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing,
+ .rxtstamp = sja1110_rxtstamp,
+ .txtstamp = sja1110_txtstamp,
+ .disable_microcontroller = sja1110_disable_microcontroller,
+ .pcs_mdio_read = sja1110_pcs_mdio_read,
+ .pcs_mdio_write = sja1110_pcs_mdio_write,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 4,
+ [SJA1105_SPEED_100MBPS] = 3,
+ [SJA1105_SPEED_1000MBPS] = 2,
+ [SJA1105_SPEED_2500MBPS] = 1,
+ },
+ .supports_mii = {true, true, true, true, false,
+ true, true, true, false, false, false},
+ .supports_rmii = {false, false, true, true, false,
+ false, false, false, false, false, false},
+ .supports_rgmii = {false, false, true, true, false,
+ false, false, false, false, false, false},
+ .supports_sgmii = {false, false, false, false, true,
+ false, false, false, false, false, false},
+ .supports_2500basex = {false, false, false, false, true,
+ false, false, false, false, false, false},
+ .internal_phy = {SJA1105_NO_PHY, SJA1105_PHY_BASE_TX,
+ SJA1105_NO_PHY, SJA1105_NO_PHY,
+ SJA1105_NO_PHY, SJA1105_PHY_BASE_T1,
+ SJA1105_PHY_BASE_T1, SJA1105_PHY_BASE_T1,
+ SJA1105_NO_PHY, SJA1105_NO_PHY,
+ SJA1105_NO_PHY},
+ .name = "SJA1110C",
+};
+
+const struct sja1105_info sja1110d_info = {
+ .device_id = SJA1110_DEVICE_ID,
+ .part_no = SJA1110D_PART_NO,
+ .static_ops = sja1110_table_ops,
+ .dyn_ops = sja1110_dyn_ops,
+ .regs = &sja1110_regs,
+ .qinq_tpid = ETH_P_8021AD,
+ .tag_proto = DSA_TAG_PROTO_SJA1110,
+ .can_limit_mcast_flood = true,
+ .multiple_cascade_ports = true,
+ .ptp_ts_bits = 32,
+ .ptpegr_ts_bytes = 8,
+ .max_frame_mem = SJA1110_MAX_FRAME_MEMORY,
+ .num_ports = SJA1110_NUM_PORTS,
+ .num_cbs_shapers = SJA1110_MAX_CBS_COUNT,
+ .setup_rgmii_delay = sja1110_setup_rgmii_delay,
+ .reset_cmd = sja1110_reset_cmd,
+ .fdb_add_cmd = sja1105pqrs_fdb_add,
+ .fdb_del_cmd = sja1105pqrs_fdb_del,
+ .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing,
+ .rxtstamp = sja1110_rxtstamp,
+ .txtstamp = sja1110_txtstamp,
+ .disable_microcontroller = sja1110_disable_microcontroller,
+ .pcs_mdio_read = sja1110_pcs_mdio_read,
+ .pcs_mdio_write = sja1110_pcs_mdio_write,
+ .port_speed = {
+ [SJA1105_SPEED_AUTO] = 0,
+ [SJA1105_SPEED_10MBPS] = 4,
+ [SJA1105_SPEED_100MBPS] = 3,
+ [SJA1105_SPEED_1000MBPS] = 2,
+ [SJA1105_SPEED_2500MBPS] = 1,
+ },
+ .supports_mii = {true, false, true, false, false,
+ true, true, true, false, false, false},
+ .supports_rmii = {false, false, true, false, false,
+ false, false, false, false, false, false},
+ .supports_rgmii = {false, false, true, false, false,
+ false, false, false, false, false, false},
+ .supports_sgmii = {false, true, true, true, true,
+ false, false, false, false, false, false},
+ .supports_2500basex = {false, false, false, true, true,
+ false, false, false, false, false, false},
+ .internal_phy = {SJA1105_NO_PHY, SJA1105_NO_PHY,
+ SJA1105_NO_PHY, SJA1105_NO_PHY,
+ SJA1105_NO_PHY, SJA1105_PHY_BASE_T1,
+ SJA1105_PHY_BASE_T1, SJA1105_PHY_BASE_T1,
+ SJA1105_NO_PHY, SJA1105_NO_PHY,
+ SJA1105_NO_PHY},
+ .name = "SJA1110D",
+};
diff --git a/drivers/net/dsa/sja1105/sja1105_static_config.c b/drivers/net/dsa/sja1105/sja1105_static_config.c
index a8efb7fac395..7a422ef4deb6 100644
--- a/drivers/net/dsa/sja1105/sja1105_static_config.c
+++ b/drivers/net/dsa/sja1105/sja1105_static_config.c
@@ -180,6 +180,43 @@ size_t sja1105pqrs_general_params_entry_packing(void *buf, void *entry_ptr,
return size;
}
+size_t sja1110_general_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_general_params_entry *entry = entry_ptr;
+ const size_t size = SJA1110_SIZE_GENERAL_PARAMS_ENTRY;
+
+ sja1105_packing(buf, &entry->vllupformat, 447, 447, size, op);
+ sja1105_packing(buf, &entry->mirr_ptacu, 446, 446, size, op);
+ sja1105_packing(buf, &entry->switchid, 445, 442, size, op);
+ sja1105_packing(buf, &entry->hostprio, 441, 439, size, op);
+ sja1105_packing(buf, &entry->mac_fltres1, 438, 391, size, op);
+ sja1105_packing(buf, &entry->mac_fltres0, 390, 343, size, op);
+ sja1105_packing(buf, &entry->mac_flt1, 342, 295, size, op);
+ sja1105_packing(buf, &entry->mac_flt0, 294, 247, size, op);
+ sja1105_packing(buf, &entry->incl_srcpt1, 246, 246, size, op);
+ sja1105_packing(buf, &entry->incl_srcpt0, 245, 245, size, op);
+ sja1105_packing(buf, &entry->send_meta1, 244, 244, size, op);
+ sja1105_packing(buf, &entry->send_meta0, 243, 243, size, op);
+ sja1105_packing(buf, &entry->casc_port, 242, 232, size, op);
+ sja1105_packing(buf, &entry->host_port, 231, 228, size, op);
+ sja1105_packing(buf, &entry->mirr_port, 227, 224, size, op);
+ sja1105_packing(buf, &entry->vlmarker, 223, 192, size, op);
+ sja1105_packing(buf, &entry->vlmask, 191, 160, size, op);
+ sja1105_packing(buf, &entry->tpid2, 159, 144, size, op);
+ sja1105_packing(buf, &entry->ignore2stf, 143, 143, size, op);
+ sja1105_packing(buf, &entry->tpid, 142, 127, size, op);
+ sja1105_packing(buf, &entry->queue_ts, 126, 126, size, op);
+ sja1105_packing(buf, &entry->egrmirrvid, 125, 114, size, op);
+ sja1105_packing(buf, &entry->egrmirrpcp, 113, 111, size, op);
+ sja1105_packing(buf, &entry->egrmirrdei, 110, 110, size, op);
+ sja1105_packing(buf, &entry->replay_port, 109, 106, size, op);
+ sja1105_packing(buf, &entry->tdmaconfigidx, 70, 67, size, op);
+ sja1105_packing(buf, &entry->header_type, 64, 49, size, op);
+ sja1105_packing(buf, &entry->tte_en, 16, 16, size, op);
+ return size;
+}
+
static size_t
sja1105_l2_forwarding_params_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
@@ -195,6 +232,20 @@ sja1105_l2_forwarding_params_entry_packing(void *buf, void *entry_ptr,
return size;
}
+size_t sja1110_l2_forwarding_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_l2_forwarding_params_entry *entry = entry_ptr;
+ const size_t size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY;
+ int offset, i;
+
+ sja1105_packing(buf, &entry->max_dynp, 95, 93, size, op);
+ for (i = 0, offset = 5; i < 8; i++, offset += 11)
+ sja1105_packing(buf, &entry->part_spc[i],
+ offset + 10, offset + 0, size, op);
+ return size;
+}
+
size_t sja1105_l2_forwarding_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -211,6 +262,27 @@ size_t sja1105_l2_forwarding_entry_packing(void *buf, void *entry_ptr,
return size;
}
+size_t sja1110_l2_forwarding_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_l2_forwarding_entry *entry = entry_ptr;
+ const size_t size = SJA1105_SIZE_L2_FORWARDING_ENTRY;
+ int offset, i;
+
+ if (entry->type_egrpcp2outputq) {
+ for (i = 0, offset = 31; i < SJA1110_NUM_PORTS;
+ i++, offset += 3) {
+ sja1105_packing(buf, &entry->vlan_pmap[i],
+ offset + 2, offset + 0, size, op);
+ }
+ } else {
+ sja1105_packing(buf, &entry->bc_domain, 63, 53, size, op);
+ sja1105_packing(buf, &entry->reach_port, 52, 42, size, op);
+ sja1105_packing(buf, &entry->fl_domain, 41, 31, size, op);
+ }
+ return size;
+}
+
static size_t
sja1105et_l2_lookup_params_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
@@ -249,6 +321,28 @@ size_t sja1105pqrs_l2_lookup_params_entry_packing(void *buf, void *entry_ptr,
return size;
}
+size_t sja1110_l2_lookup_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_l2_lookup_params_entry *entry = entry_ptr;
+ const size_t size = SJA1110_SIZE_L2_LOOKUP_PARAMS_ENTRY;
+ int offset, i;
+
+ for (i = 0, offset = 70; i < SJA1110_NUM_PORTS; i++, offset += 11)
+ sja1105_packing(buf, &entry->maxaddrp[i],
+ offset + 10, offset + 0, size, op);
+ sja1105_packing(buf, &entry->maxage, 69, 55, size, op);
+ sja1105_packing(buf, &entry->start_dynspc, 54, 45, size, op);
+ sja1105_packing(buf, &entry->drpnolearn, 44, 34, size, op);
+ sja1105_packing(buf, &entry->shared_learn, 33, 33, size, op);
+ sja1105_packing(buf, &entry->no_enf_hostprt, 32, 32, size, op);
+ sja1105_packing(buf, &entry->no_mgmt_learn, 31, 31, size, op);
+ sja1105_packing(buf, &entry->use_static, 30, 30, size, op);
+ sja1105_packing(buf, &entry->owr_dyn, 29, 29, size, op);
+ sja1105_packing(buf, &entry->learn_once, 28, 28, size, op);
+ return size;
+}
+
size_t sja1105et_l2_lookup_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -291,6 +385,36 @@ size_t sja1105pqrs_l2_lookup_entry_packing(void *buf, void *entry_ptr,
return size;
}
+size_t sja1110_l2_lookup_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1110_SIZE_L2_LOOKUP_ENTRY;
+ struct sja1105_l2_lookup_entry *entry = entry_ptr;
+
+ if (entry->lockeds) {
+ sja1105_packing(buf, &entry->trap, 168, 168, size, op);
+ sja1105_packing(buf, &entry->mirrvlan, 167, 156, size, op);
+ sja1105_packing(buf, &entry->takets, 155, 155, size, op);
+ sja1105_packing(buf, &entry->mirr, 154, 154, size, op);
+ sja1105_packing(buf, &entry->retag, 153, 153, size, op);
+ } else {
+ sja1105_packing(buf, &entry->touched, 168, 168, size, op);
+ sja1105_packing(buf, &entry->age, 167, 153, size, op);
+ }
+ sja1105_packing(buf, &entry->mask_iotag, 152, 152, size, op);
+ sja1105_packing(buf, &entry->mask_vlanid, 151, 140, size, op);
+ sja1105_packing(buf, &entry->mask_macaddr, 139, 92, size, op);
+ sja1105_packing(buf, &entry->mask_srcport, 91, 88, size, op);
+ sja1105_packing(buf, &entry->iotag, 87, 87, size, op);
+ sja1105_packing(buf, &entry->vlanid, 86, 75, size, op);
+ sja1105_packing(buf, &entry->macaddr, 74, 27, size, op);
+ sja1105_packing(buf, &entry->srcport, 26, 23, size, op);
+ sja1105_packing(buf, &entry->destports, 22, 12, size, op);
+ sja1105_packing(buf, &entry->enfport, 11, 11, size, op);
+ sja1105_packing(buf, &entry->index, 10, 1, size, op);
+ return size;
+}
+
static size_t sja1105_l2_policing_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -305,6 +429,20 @@ static size_t sja1105_l2_policing_entry_packing(void *buf, void *entry_ptr,
return size;
}
+size_t sja1110_l2_policing_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_l2_policing_entry *entry = entry_ptr;
+ const size_t size = SJA1105_SIZE_L2_POLICING_ENTRY;
+
+ sja1105_packing(buf, &entry->sharindx, 63, 57, size, op);
+ sja1105_packing(buf, &entry->smax, 56, 39, size, op);
+ sja1105_packing(buf, &entry->rate, 38, 21, size, op);
+ sja1105_packing(buf, &entry->maxlen, 20, 10, size, op);
+ sja1105_packing(buf, &entry->partition, 9, 7, size, op);
+ return size;
+}
+
static size_t sja1105et_mac_config_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -373,6 +511,40 @@ size_t sja1105pqrs_mac_config_entry_packing(void *buf, void *entry_ptr,
return size;
}
+size_t sja1110_mac_config_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
+ struct sja1105_mac_config_entry *entry = entry_ptr;
+ int offset, i;
+
+ for (i = 0, offset = 104; i < 8; i++, offset += 19) {
+ sja1105_packing(buf, &entry->enabled[i],
+ offset + 0, offset + 0, size, op);
+ sja1105_packing(buf, &entry->base[i],
+ offset + 9, offset + 1, size, op);
+ sja1105_packing(buf, &entry->top[i],
+ offset + 18, offset + 10, size, op);
+ }
+ sja1105_packing(buf, &entry->speed, 98, 96, size, op);
+ sja1105_packing(buf, &entry->tp_delin, 95, 80, size, op);
+ sja1105_packing(buf, &entry->tp_delout, 79, 64, size, op);
+ sja1105_packing(buf, &entry->maxage, 63, 56, size, op);
+ sja1105_packing(buf, &entry->vlanprio, 55, 53, size, op);
+ sja1105_packing(buf, &entry->vlanid, 52, 41, size, op);
+ sja1105_packing(buf, &entry->ing_mirr, 40, 40, size, op);
+ sja1105_packing(buf, &entry->egr_mirr, 39, 39, size, op);
+ sja1105_packing(buf, &entry->drpnona664, 38, 38, size, op);
+ sja1105_packing(buf, &entry->drpdtag, 37, 37, size, op);
+ sja1105_packing(buf, &entry->drpuntag, 34, 34, size, op);
+ sja1105_packing(buf, &entry->retag, 33, 33, size, op);
+ sja1105_packing(buf, &entry->dyn_learn, 32, 32, size, op);
+ sja1105_packing(buf, &entry->egress, 31, 31, size, op);
+ sja1105_packing(buf, &entry->ingress, 30, 30, size, op);
+ sja1105_packing(buf, &entry->ifg, 10, 5, size, op);
+ return size;
+}
+
static size_t
sja1105_schedule_entry_points_params_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
@@ -398,6 +570,19 @@ sja1105_schedule_entry_points_entry_packing(void *buf, void *entry_ptr,
return size;
}
+static size_t
+sja1110_schedule_entry_points_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_schedule_entry_points_entry *entry = entry_ptr;
+ const size_t size = SJA1110_SIZE_SCHEDULE_ENTRY_POINTS_ENTRY;
+
+ sja1105_packing(buf, &entry->subschindx, 63, 61, size, op);
+ sja1105_packing(buf, &entry->delta, 60, 43, size, op);
+ sja1105_packing(buf, &entry->address, 42, 31, size, op);
+ return size;
+}
+
static size_t sja1105_schedule_params_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -411,6 +596,19 @@ static size_t sja1105_schedule_params_entry_packing(void *buf, void *entry_ptr,
return size;
}
+static size_t sja1110_schedule_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_schedule_params_entry *entry = entry_ptr;
+ const size_t size = SJA1105_SIZE_SCHEDULE_PARAMS_ENTRY;
+ int offset, i;
+
+ for (i = 0, offset = 0; i < 8; i++, offset += 12)
+ sja1105_packing(buf, &entry->subscheind[i],
+ offset + 11, offset + 0, size, op);
+ return size;
+}
+
static size_t sja1105_schedule_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -430,6 +628,25 @@ static size_t sja1105_schedule_entry_packing(void *buf, void *entry_ptr,
return size;
}
+static size_t sja1110_schedule_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1110_SIZE_SCHEDULE_ENTRY;
+ struct sja1105_schedule_entry *entry = entry_ptr;
+
+ sja1105_packing(buf, &entry->winstindex, 95, 84, size, op);
+ sja1105_packing(buf, &entry->winend, 83, 83, size, op);
+ sja1105_packing(buf, &entry->winst, 82, 82, size, op);
+ sja1105_packing(buf, &entry->destports, 81, 71, size, op);
+ sja1105_packing(buf, &entry->setvalid, 70, 70, size, op);
+ sja1105_packing(buf, &entry->txen, 69, 69, size, op);
+ sja1105_packing(buf, &entry->resmedia_en, 68, 68, size, op);
+ sja1105_packing(buf, &entry->resmedia, 67, 60, size, op);
+ sja1105_packing(buf, &entry->vlindex, 59, 48, size, op);
+ sja1105_packing(buf, &entry->delta, 47, 30, size, op);
+ return size;
+}
+
static size_t
sja1105_vl_forwarding_params_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
@@ -445,6 +662,21 @@ sja1105_vl_forwarding_params_entry_packing(void *buf, void *entry_ptr,
return size;
}
+static size_t
+sja1110_vl_forwarding_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_vl_forwarding_params_entry *entry = entry_ptr;
+ const size_t size = SJA1105_SIZE_VL_FORWARDING_PARAMS_ENTRY;
+ int offset, i;
+
+ for (i = 0, offset = 8; i < 8; i++, offset += 11)
+ sja1105_packing(buf, &entry->partspc[i],
+ offset + 10, offset + 0, size, op);
+ sja1105_packing(buf, &entry->debugen, 7, 7, size, op);
+ return size;
+}
+
static size_t sja1105_vl_forwarding_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -458,6 +690,19 @@ static size_t sja1105_vl_forwarding_entry_packing(void *buf, void *entry_ptr,
return size;
}
+static size_t sja1110_vl_forwarding_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_vl_forwarding_entry *entry = entry_ptr;
+ const size_t size = SJA1105_SIZE_VL_FORWARDING_ENTRY;
+
+ sja1105_packing(buf, &entry->type, 31, 31, size, op);
+ sja1105_packing(buf, &entry->priority, 30, 28, size, op);
+ sja1105_packing(buf, &entry->partition, 27, 25, size, op);
+ sja1105_packing(buf, &entry->destports, 24, 14, size, op);
+ return size;
+}
+
size_t sja1105_vl_lookup_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -492,6 +737,40 @@ size_t sja1105_vl_lookup_entry_packing(void *buf, void *entry_ptr,
return size;
}
+size_t sja1110_vl_lookup_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_vl_lookup_entry *entry = entry_ptr;
+ const size_t size = SJA1105_SIZE_VL_LOOKUP_ENTRY;
+
+ if (entry->format == SJA1105_VL_FORMAT_PSFP) {
+ /* Interpreting vllupformat as 0 */
+ sja1105_packing(buf, &entry->destports,
+ 94, 84, size, op);
+ sja1105_packing(buf, &entry->iscritical,
+ 83, 83, size, op);
+ sja1105_packing(buf, &entry->macaddr,
+ 82, 35, size, op);
+ sja1105_packing(buf, &entry->vlanid,
+ 34, 23, size, op);
+ sja1105_packing(buf, &entry->port,
+ 22, 19, size, op);
+ sja1105_packing(buf, &entry->vlanprior,
+ 18, 16, size, op);
+ } else {
+ /* Interpreting vllupformat as 1 */
+ sja1105_packing(buf, &entry->egrmirr,
+ 94, 84, size, op);
+ sja1105_packing(buf, &entry->ingrmirr,
+ 83, 83, size, op);
+ sja1105_packing(buf, &entry->vlid,
+ 50, 35, size, op);
+ sja1105_packing(buf, &entry->port,
+ 22, 19, size, op);
+ }
+ return size;
+}
+
static size_t sja1105_vl_policing_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -508,6 +787,22 @@ static size_t sja1105_vl_policing_entry_packing(void *buf, void *entry_ptr,
return size;
}
+size_t sja1110_vl_policing_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_vl_policing_entry *entry = entry_ptr;
+ const size_t size = SJA1105_SIZE_VL_POLICING_ENTRY;
+
+ sja1105_packing(buf, &entry->type, 63, 63, size, op);
+ sja1105_packing(buf, &entry->maxlen, 62, 52, size, op);
+ sja1105_packing(buf, &entry->sharindx, 51, 40, size, op);
+ if (entry->type == 0) {
+ sja1105_packing(buf, &entry->bag, 41, 28, size, op);
+ sja1105_packing(buf, &entry->jitter, 27, 18, size, op);
+ }
+ return size;
+}
+
size_t sja1105_vlan_lookup_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -523,6 +818,22 @@ size_t sja1105_vlan_lookup_entry_packing(void *buf, void *entry_ptr,
return size;
}
+size_t sja1110_vlan_lookup_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_vlan_lookup_entry *entry = entry_ptr;
+ const size_t size = SJA1110_SIZE_VLAN_LOOKUP_ENTRY;
+
+ sja1105_packing(buf, &entry->ving_mirr, 95, 85, size, op);
+ sja1105_packing(buf, &entry->vegr_mirr, 84, 74, size, op);
+ sja1105_packing(buf, &entry->vmemb_port, 73, 63, size, op);
+ sja1105_packing(buf, &entry->vlan_bc, 62, 52, size, op);
+ sja1105_packing(buf, &entry->tag_port, 51, 41, size, op);
+ sja1105_packing(buf, &entry->type_entry, 40, 39, size, op);
+ sja1105_packing(buf, &entry->vlanid, 38, 27, size, op);
+ return size;
+}
+
static size_t sja1105_xmii_params_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -539,6 +850,24 @@ static size_t sja1105_xmii_params_entry_packing(void *buf, void *entry_ptr,
return size;
}
+size_t sja1110_xmii_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1110_SIZE_XMII_PARAMS_ENTRY;
+ struct sja1105_xmii_params_entry *entry = entry_ptr;
+ int offset, i;
+
+ for (i = 0, offset = 20; i < SJA1110_NUM_PORTS; i++, offset += 4) {
+ sja1105_packing(buf, &entry->xmii_mode[i],
+ offset + 1, offset + 0, size, op);
+ sja1105_packing(buf, &entry->phy_mac[i],
+ offset + 2, offset + 2, size, op);
+ sja1105_packing(buf, &entry->special[i],
+ offset + 3, offset + 3, size, op);
+ }
+ return size;
+}
+
size_t sja1105_retagging_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -555,6 +884,36 @@ size_t sja1105_retagging_entry_packing(void *buf, void *entry_ptr,
return size;
}
+size_t sja1110_retagging_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1105_retagging_entry *entry = entry_ptr;
+ const size_t size = SJA1105_SIZE_RETAGGING_ENTRY;
+
+ sja1105_packing(buf, &entry->egr_port, 63, 53, size, op);
+ sja1105_packing(buf, &entry->ing_port, 52, 42, size, op);
+ sja1105_packing(buf, &entry->vlan_ing, 41, 30, size, op);
+ sja1105_packing(buf, &entry->vlan_egr, 29, 18, size, op);
+ sja1105_packing(buf, &entry->do_not_learn, 17, 17, size, op);
+ sja1105_packing(buf, &entry->use_dest_ports, 16, 16, size, op);
+ sja1105_packing(buf, &entry->destports, 15, 5, size, op);
+ return size;
+}
+
+static size_t sja1110_pcp_remapping_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ struct sja1110_pcp_remapping_entry *entry = entry_ptr;
+ const size_t size = SJA1110_SIZE_PCP_REMAPPING_ENTRY;
+ int offset, i;
+
+ for (i = 0, offset = 8; i < SJA1105_NUM_TC; i++, offset += 3)
+ sja1105_packing(buf, &entry->egrpcp[i],
+ offset + 2, offset + 0, size, op);
+
+ return size;
+}
+
size_t sja1105_table_header_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -619,6 +978,7 @@ static u64 blk_id_map[BLK_IDX_MAX] = {
[BLK_IDX_GENERAL_PARAMS] = BLKID_GENERAL_PARAMS,
[BLK_IDX_RETAGGING] = BLKID_RETAGGING,
[BLK_IDX_XMII_PARAMS] = BLKID_XMII_PARAMS,
+ [BLK_IDX_PCP_REMAPPING] = BLKID_PCP_REMAPPING,
};
const char *sja1105_static_config_error_msg[] = {
@@ -657,11 +1017,11 @@ const char *sja1105_static_config_error_msg[] = {
};
static sja1105_config_valid_t
-static_config_check_memory_size(const struct sja1105_table *tables)
+static_config_check_memory_size(const struct sja1105_table *tables, int max_mem)
{
const struct sja1105_l2_forwarding_params_entry *l2_fwd_params;
const struct sja1105_vl_forwarding_params_entry *vl_fwd_params;
- int i, max_mem, mem = 0;
+ int i, mem = 0;
l2_fwd_params = tables[BLK_IDX_L2_FORWARDING_PARAMS].entries;
@@ -675,9 +1035,7 @@ static_config_check_memory_size(const struct sja1105_table *tables)
}
if (tables[BLK_IDX_RETAGGING].entry_count)
- max_mem = SJA1105_MAX_FRAME_MEMORY_RETAGGING;
- else
- max_mem = SJA1105_MAX_FRAME_MEMORY;
+ max_mem -= SJA1105_FRAME_MEMORY_RETAGGING_OVERHEAD;
if (mem > max_mem)
return SJA1105_OVERCOMMITTED_FRAME_MEMORY;
@@ -686,15 +1044,15 @@ static_config_check_memory_size(const struct sja1105_table *tables)
}
sja1105_config_valid_t
-sja1105_static_config_check_valid(const struct sja1105_static_config *config)
+sja1105_static_config_check_valid(const struct sja1105_static_config *config,
+ int max_mem)
{
const struct sja1105_table *tables = config->tables;
#define IS_FULL(blk_idx) \
(tables[blk_idx].entry_count == tables[blk_idx].ops->max_entry_count)
if (tables[BLK_IDX_SCHEDULE].entry_count) {
- if (config->device_id != SJA1105T_DEVICE_ID &&
- config->device_id != SJA1105QS_DEVICE_ID)
+ if (!tables[BLK_IDX_SCHEDULE].ops->max_entry_count)
return SJA1105_TTETHERNET_NOT_SUPPORTED;
if (tables[BLK_IDX_SCHEDULE_ENTRY_POINTS].entry_count == 0)
@@ -754,7 +1112,7 @@ sja1105_static_config_check_valid(const struct sja1105_static_config *config)
if (!IS_FULL(BLK_IDX_XMII_PARAMS))
return SJA1105_MISSING_XMII_TABLE;
- return static_config_check_memory_size(tables);
+ return static_config_check_memory_size(tables, max_mem);
#undef IS_FULL
}
@@ -1401,6 +1759,130 @@ const struct sja1105_table_ops sja1105s_table_ops[BLK_IDX_MAX] = {
},
};
+/* SJA1110A: Third generation */
+const struct sja1105_table_ops sja1110_table_ops[BLK_IDX_MAX] = {
+ [BLK_IDX_SCHEDULE] = {
+ .packing = sja1110_schedule_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_schedule_entry),
+ .packed_entry_size = SJA1110_SIZE_SCHEDULE_ENTRY,
+ .max_entry_count = SJA1110_MAX_SCHEDULE_COUNT,
+ },
+ [BLK_IDX_SCHEDULE_ENTRY_POINTS] = {
+ .packing = sja1110_schedule_entry_points_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_schedule_entry_points_entry),
+ .packed_entry_size = SJA1110_SIZE_SCHEDULE_ENTRY_POINTS_ENTRY,
+ .max_entry_count = SJA1105_MAX_SCHEDULE_ENTRY_POINTS_COUNT,
+ },
+ [BLK_IDX_VL_LOOKUP] = {
+ .packing = sja1110_vl_lookup_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_vl_lookup_entry),
+ .packed_entry_size = SJA1105_SIZE_VL_LOOKUP_ENTRY,
+ .max_entry_count = SJA1110_MAX_VL_LOOKUP_COUNT,
+ },
+ [BLK_IDX_VL_POLICING] = {
+ .packing = sja1110_vl_policing_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_vl_policing_entry),
+ .packed_entry_size = SJA1105_SIZE_VL_POLICING_ENTRY,
+ .max_entry_count = SJA1110_MAX_VL_POLICING_COUNT,
+ },
+ [BLK_IDX_VL_FORWARDING] = {
+ .packing = sja1110_vl_forwarding_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_vl_forwarding_entry),
+ .packed_entry_size = SJA1105_SIZE_VL_FORWARDING_ENTRY,
+ .max_entry_count = SJA1110_MAX_VL_FORWARDING_COUNT,
+ },
+ [BLK_IDX_L2_LOOKUP] = {
+ .packing = sja1110_l2_lookup_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_l2_lookup_entry),
+ .packed_entry_size = SJA1110_SIZE_L2_LOOKUP_ENTRY,
+ .max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
+ },
+ [BLK_IDX_L2_POLICING] = {
+ .packing = sja1110_l2_policing_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_l2_policing_entry),
+ .packed_entry_size = SJA1105_SIZE_L2_POLICING_ENTRY,
+ .max_entry_count = SJA1110_MAX_L2_POLICING_COUNT,
+ },
+ [BLK_IDX_VLAN_LOOKUP] = {
+ .packing = sja1110_vlan_lookup_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_vlan_lookup_entry),
+ .packed_entry_size = SJA1110_SIZE_VLAN_LOOKUP_ENTRY,
+ .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
+ },
+ [BLK_IDX_L2_FORWARDING] = {
+ .packing = sja1110_l2_forwarding_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_l2_forwarding_entry),
+ .packed_entry_size = SJA1105_SIZE_L2_FORWARDING_ENTRY,
+ .max_entry_count = SJA1110_MAX_L2_FORWARDING_COUNT,
+ },
+ [BLK_IDX_MAC_CONFIG] = {
+ .packing = sja1110_mac_config_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_mac_config_entry),
+ .packed_entry_size = SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY,
+ .max_entry_count = SJA1110_MAX_MAC_CONFIG_COUNT,
+ },
+ [BLK_IDX_SCHEDULE_PARAMS] = {
+ .packing = sja1110_schedule_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_schedule_params_entry),
+ .packed_entry_size = SJA1105_SIZE_SCHEDULE_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_SCHEDULE_PARAMS_COUNT,
+ },
+ [BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = {
+ .packing = sja1105_schedule_entry_points_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_schedule_entry_points_params_entry),
+ .packed_entry_size = SJA1105_SIZE_SCHEDULE_ENTRY_POINTS_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_SCHEDULE_ENTRY_POINTS_PARAMS_COUNT,
+ },
+ [BLK_IDX_VL_FORWARDING_PARAMS] = {
+ .packing = sja1110_vl_forwarding_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_vl_forwarding_params_entry),
+ .packed_entry_size = SJA1105_SIZE_VL_FORWARDING_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_VL_FORWARDING_PARAMS_COUNT,
+ },
+ [BLK_IDX_L2_LOOKUP_PARAMS] = {
+ .packing = sja1110_l2_lookup_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_l2_lookup_params_entry),
+ .packed_entry_size = SJA1110_SIZE_L2_LOOKUP_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_L2_LOOKUP_PARAMS_COUNT,
+ },
+ [BLK_IDX_L2_FORWARDING_PARAMS] = {
+ .packing = sja1110_l2_forwarding_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_l2_forwarding_params_entry),
+ .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 = sja1110_general_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
+ .packed_entry_size = SJA1110_SIZE_GENERAL_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
+ },
+ [BLK_IDX_RETAGGING] = {
+ .packing = sja1110_retagging_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_retagging_entry),
+ .packed_entry_size = SJA1105_SIZE_RETAGGING_ENTRY,
+ .max_entry_count = SJA1105_MAX_RETAGGING_COUNT,
+ },
+ [BLK_IDX_XMII_PARAMS] = {
+ .packing = sja1110_xmii_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_xmii_params_entry),
+ .packed_entry_size = SJA1110_SIZE_XMII_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_XMII_PARAMS_COUNT,
+ },
+ [BLK_IDX_PCP_REMAPPING] = {
+ .packing = sja1110_pcp_remapping_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1110_pcp_remapping_entry),
+ .packed_entry_size = SJA1110_SIZE_PCP_REMAPPING_ENTRY,
+ .max_entry_count = SJA1110_MAX_PCP_REMAPPING_COUNT,
+ },
+};
+
int sja1105_static_config_init(struct sja1105_static_config *config,
const struct sja1105_table_ops *static_ops,
u64 device_id)
diff --git a/drivers/net/dsa/sja1105/sja1105_static_config.h b/drivers/net/dsa/sja1105/sja1105_static_config.h
index bc7606899289..bce0f5c03d0b 100644
--- a/drivers/net/dsa/sja1105/sja1105_static_config.h
+++ b/drivers/net/dsa/sja1105/sja1105_static_config.h
@@ -9,19 +9,30 @@
#include <linux/types.h>
#include <asm/types.h>
+#define SJA1105_NUM_PORTS 5
+#define SJA1110_NUM_PORTS 11
+#define SJA1105_MAX_NUM_PORTS SJA1110_NUM_PORTS
+#define SJA1105_NUM_TC 8
+
+#define SJA1105_SIZE_SPI_MSG_HEADER 4
+#define SJA1105_SIZE_SPI_MSG_MAXLEN (64 * 4)
#define SJA1105_SIZE_DEVICE_ID 4
#define SJA1105_SIZE_TABLE_HEADER 12
#define SJA1105_SIZE_SCHEDULE_ENTRY 8
+#define SJA1110_SIZE_SCHEDULE_ENTRY 12
#define SJA1105_SIZE_SCHEDULE_ENTRY_POINTS_ENTRY 4
+#define SJA1110_SIZE_SCHEDULE_ENTRY_POINTS_ENTRY 8
#define SJA1105_SIZE_VL_LOOKUP_ENTRY 12
#define SJA1105_SIZE_VL_POLICING_ENTRY 8
#define SJA1105_SIZE_VL_FORWARDING_ENTRY 4
#define SJA1105_SIZE_L2_POLICING_ENTRY 8
#define SJA1105_SIZE_VLAN_LOOKUP_ENTRY 8
+#define SJA1110_SIZE_VLAN_LOOKUP_ENTRY 12
#define SJA1105_SIZE_L2_FORWARDING_ENTRY 8
#define SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY 12
#define SJA1105_SIZE_RETAGGING_ENTRY 8
#define SJA1105_SIZE_XMII_PARAMS_ENTRY 4
+#define SJA1110_SIZE_XMII_PARAMS_ENTRY 8
#define SJA1105_SIZE_SCHEDULE_PARAMS_ENTRY 12
#define SJA1105_SIZE_SCHEDULE_ENTRY_POINTS_PARAMS_ENTRY 4
#define SJA1105_SIZE_VL_FORWARDING_PARAMS_ENTRY 12
@@ -32,11 +43,15 @@
#define SJA1105ET_SIZE_AVB_PARAMS_ENTRY 12
#define SJA1105ET_SIZE_CBS_ENTRY 16
#define SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY 20
+#define SJA1110_SIZE_L2_LOOKUP_ENTRY 24
#define SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY 32
#define SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY 16
+#define SJA1110_SIZE_L2_LOOKUP_PARAMS_ENTRY 28
#define SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY 44
+#define SJA1110_SIZE_GENERAL_PARAMS_ENTRY 56
#define SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY 16
#define SJA1105PQRS_SIZE_CBS_ENTRY 20
+#define SJA1110_SIZE_PCP_REMAPPING_ENTRY 4
/* UM10944.pdf Page 11, Table 2. Configuration Blocks */
enum {
@@ -59,6 +74,7 @@ enum {
BLKID_GENERAL_PARAMS = 0x11,
BLKID_RETAGGING = 0x12,
BLKID_CBS = 0x13,
+ BLKID_PCP_REMAPPING = 0x1C,
BLKID_XMII_PARAMS = 0x4E,
};
@@ -83,6 +99,7 @@ enum sja1105_blk_idx {
BLK_IDX_RETAGGING,
BLK_IDX_CBS,
BLK_IDX_XMII_PARAMS,
+ BLK_IDX_PCP_REMAPPING,
BLK_IDX_MAX,
/* Fake block indices that are only valid for dynamic access */
BLK_IDX_MGMT_ROUTE,
@@ -91,15 +108,22 @@ enum sja1105_blk_idx {
};
#define SJA1105_MAX_SCHEDULE_COUNT 1024
+#define SJA1110_MAX_SCHEDULE_COUNT 4096
#define SJA1105_MAX_SCHEDULE_ENTRY_POINTS_COUNT 2048
#define SJA1105_MAX_VL_LOOKUP_COUNT 1024
+#define SJA1110_MAX_VL_LOOKUP_COUNT 4096
#define SJA1105_MAX_VL_POLICING_COUNT 1024
+#define SJA1110_MAX_VL_POLICING_COUNT 4096
#define SJA1105_MAX_VL_FORWARDING_COUNT 1024
+#define SJA1110_MAX_VL_FORWARDING_COUNT 4096
#define SJA1105_MAX_L2_LOOKUP_COUNT 1024
#define SJA1105_MAX_L2_POLICING_COUNT 45
+#define SJA1110_MAX_L2_POLICING_COUNT 110
#define SJA1105_MAX_VLAN_LOOKUP_COUNT 4096
#define SJA1105_MAX_L2_FORWARDING_COUNT 13
+#define SJA1110_MAX_L2_FORWARDING_COUNT 19
#define SJA1105_MAX_MAC_CONFIG_COUNT 5
+#define SJA1110_MAX_MAC_CONFIG_COUNT 11
#define SJA1105_MAX_SCHEDULE_PARAMS_COUNT 1
#define SJA1105_MAX_SCHEDULE_ENTRY_POINTS_PARAMS_COUNT 1
#define SJA1105_MAX_VL_FORWARDING_PARAMS_COUNT 1
@@ -111,21 +135,40 @@ enum sja1105_blk_idx {
#define SJA1105_MAX_AVB_PARAMS_COUNT 1
#define SJA1105ET_MAX_CBS_COUNT 10
#define SJA1105PQRS_MAX_CBS_COUNT 16
+#define SJA1110_MAX_CBS_COUNT 80
+#define SJA1110_MAX_PCP_REMAPPING_COUNT 11
#define SJA1105_MAX_FRAME_MEMORY 929
-#define SJA1105_MAX_FRAME_MEMORY_RETAGGING 910
+#define SJA1110_MAX_FRAME_MEMORY 1820
+#define SJA1105_FRAME_MEMORY_RETAGGING_OVERHEAD 19
#define SJA1105_VL_FRAME_MEMORY 100
#define SJA1105E_DEVICE_ID 0x9C00000Cull
#define SJA1105T_DEVICE_ID 0x9E00030Eull
#define SJA1105PR_DEVICE_ID 0xAF00030Eull
#define SJA1105QS_DEVICE_ID 0xAE00030Eull
+#define SJA1110_DEVICE_ID 0xB700030Full
#define SJA1105ET_PART_NO 0x9A83
#define SJA1105P_PART_NO 0x9A84
#define SJA1105Q_PART_NO 0x9A85
#define SJA1105R_PART_NO 0x9A86
#define SJA1105S_PART_NO 0x9A87
+#define SJA1110A_PART_NO 0x1110
+#define SJA1110B_PART_NO 0x1111
+#define SJA1110C_PART_NO 0x1112
+#define SJA1110D_PART_NO 0x1113
+
+#define SJA1110_ACU 0x1c4400
+#define SJA1110_RGU 0x1c6000
+#define SJA1110_CGU 0x1c6400
+
+#define SJA1110_SPI_ADDR(x) ((x) / 4)
+#define SJA1110_ACU_ADDR(x) (SJA1110_ACU + SJA1110_SPI_ADDR(x))
+#define SJA1110_CGU_ADDR(x) (SJA1110_CGU + SJA1110_SPI_ADDR(x))
+#define SJA1110_RGU_ADDR(x) (SJA1110_RGU + SJA1110_SPI_ADDR(x))
+
+#define SJA1105_RSV_ADDR 0xffffffffffffffffull
struct sja1105_schedule_entry {
u64 winstindex;
@@ -171,6 +214,10 @@ struct sja1105_general_params_entry {
u64 egrmirrpcp;
u64 egrmirrdei;
u64 replay_port;
+ /* SJA1110 only */
+ u64 tte_en;
+ u64 tdmaconfigidx;
+ u64 header_type;
};
struct sja1105_schedule_entry_points_entry {
@@ -191,6 +238,7 @@ struct sja1105_vlan_lookup_entry {
u64 vlan_bc;
u64 tag_port;
u64 vlanid;
+ u64 type_entry; /* SJA1110 only */
};
struct sja1105_l2_lookup_entry {
@@ -203,11 +251,17 @@ struct sja1105_l2_lookup_entry {
u64 mask_iotag;
u64 mask_vlanid;
u64 mask_macaddr;
+ u64 mask_srcport;
u64 iotag;
+ u64 srcport;
u64 lockeds;
union {
/* LOCKEDS=1: Static FDB entries */
struct {
+ /* TSREG is deprecated in SJA1110, TRAP is supported only
+ * in SJA1110.
+ */
+ u64 trap;
u64 tsreg;
u64 mirrvlan;
u64 takets;
@@ -223,7 +277,7 @@ struct sja1105_l2_lookup_entry {
};
struct sja1105_l2_lookup_params_entry {
- u64 maxaddrp[5]; /* P/Q/R/S only */
+ u64 maxaddrp[SJA1105_MAX_NUM_PORTS]; /* 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 */
@@ -241,7 +295,9 @@ struct sja1105_l2_forwarding_entry {
u64 bc_domain;
u64 reach_port;
u64 fl_domain;
- u64 vlan_pmap[8];
+ /* This is actually max(SJA1105_NUM_TC, SJA1105_MAX_NUM_PORTS) */
+ u64 vlan_pmap[SJA1105_MAX_NUM_PORTS];
+ bool type_egrpcp2outputq;
};
struct sja1105_l2_forwarding_params_entry {
@@ -296,8 +352,8 @@ struct sja1105_retagging_entry {
};
struct sja1105_cbs_entry {
- u64 port;
- u64 prio;
+ u64 port; /* Not used for SJA1110 */
+ u64 prio; /* Not used for SJA1110 */
u64 credit_hi;
u64 credit_lo;
u64 send_slope;
@@ -305,8 +361,19 @@ struct sja1105_cbs_entry {
};
struct sja1105_xmii_params_entry {
- u64 phy_mac[5];
- u64 xmii_mode[5];
+ u64 phy_mac[SJA1105_MAX_NUM_PORTS];
+ u64 xmii_mode[SJA1105_MAX_NUM_PORTS];
+ /* The SJA1110 insists being a snowflake, and requires SGMII,
+ * 2500base-x and internal MII ports connected to the 100base-TX PHY to
+ * set this bit. We set it unconditionally from the high-level logic,
+ * and only sja1110_xmii_params_entry_packing writes it to the static
+ * config. I have no better name for it than "special".
+ */
+ u64 special[SJA1105_MAX_NUM_PORTS];
+};
+
+struct sja1110_pcp_remapping_entry {
+ u64 egrpcp[SJA1105_NUM_TC];
};
enum {
@@ -387,6 +454,7 @@ extern const struct sja1105_table_ops sja1105p_table_ops[BLK_IDX_MAX];
extern const struct sja1105_table_ops sja1105q_table_ops[BLK_IDX_MAX];
extern const struct sja1105_table_ops sja1105r_table_ops[BLK_IDX_MAX];
extern const struct sja1105_table_ops sja1105s_table_ops[BLK_IDX_MAX];
+extern const struct sja1105_table_ops sja1110_table_ops[BLK_IDX_MAX];
size_t sja1105_table_header_packing(void *buf, void *hdr, enum packing_op op);
void
@@ -412,7 +480,8 @@ typedef enum {
extern const char *sja1105_static_config_error_msg[];
sja1105_config_valid_t
-sja1105_static_config_check_valid(const struct sja1105_static_config *config);
+sja1105_static_config_check_valid(const struct sja1105_static_config *config,
+ int max_mem);
void
sja1105_static_config_pack(void *buf, struct sja1105_static_config *config);
int sja1105_static_config_init(struct sja1105_static_config *config,
@@ -433,23 +502,47 @@ void sja1105_packing(void *buf, u64 *val, int start, int end,
/* Common implementations for the static and dynamic configs */
size_t sja1105pqrs_general_params_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
+size_t sja1110_general_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op);
size_t sja1105pqrs_l2_lookup_params_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
+size_t sja1110_l2_lookup_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op);
size_t sja1105_l2_forwarding_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
+size_t sja1110_l2_forwarding_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op);
size_t sja1105pqrs_l2_lookup_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
size_t sja1105et_l2_lookup_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
+size_t sja1110_l2_lookup_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op);
size_t sja1105_vlan_lookup_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
+size_t sja1110_vlan_lookup_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op);
size_t sja1105_retagging_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
+size_t sja1110_retagging_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op);
size_t sja1105pqrs_mac_config_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
+size_t sja1110_mac_config_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op);
size_t sja1105pqrs_avb_params_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
size_t sja1105_vl_lookup_entry_packing(void *buf, void *entry_ptr,
enum packing_op op);
+size_t sja1110_vl_lookup_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op);
+size_t sja1110_vl_policing_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op);
+size_t sja1110_xmii_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op);
+size_t sja1110_l2_policing_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op);
+size_t sja1110_l2_forwarding_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op);
#endif
diff --git a/drivers/net/dsa/sja1105/sja1105_tas.c b/drivers/net/dsa/sja1105/sja1105_tas.c
index 31d8acff1f01..e6153848a950 100644
--- a/drivers/net/dsa/sja1105/sja1105_tas.c
+++ b/drivers/net/dsa/sja1105/sja1105_tas.c
@@ -27,7 +27,7 @@ static int sja1105_tas_set_runtime_params(struct sja1105_private *priv)
tas_data->enabled = false;
- for (port = 0; port < SJA1105_NUM_PORTS; port++) {
+ for (port = 0; port < ds->num_ports; port++) {
const struct tc_taprio_qopt_offload *offload;
offload = tas_data->offload[port];
@@ -164,6 +164,7 @@ int sja1105_init_scheduling(struct sja1105_private *priv)
struct sja1105_tas_data *tas_data = &priv->tas_data;
struct sja1105_gating_config *gating_cfg = &tas_data->gating_cfg;
struct sja1105_schedule_entry *schedule;
+ struct dsa_switch *ds = priv->ds;
struct sja1105_table *table;
int schedule_start_idx;
s64 entry_point_delta;
@@ -207,7 +208,7 @@ int sja1105_init_scheduling(struct sja1105_private *priv)
}
/* Figure out the dimensioning of the problem */
- for (port = 0; port < SJA1105_NUM_PORTS; port++) {
+ for (port = 0; port < ds->num_ports; port++) {
if (tas_data->offload[port]) {
num_entries += tas_data->offload[port]->num_entries;
num_cycles++;
@@ -269,7 +270,7 @@ int sja1105_init_scheduling(struct sja1105_private *priv)
schedule_entry_points_params->clksrc = SJA1105_TAS_CLKSRC_PTP;
schedule_entry_points_params->actsubsch = num_cycles - 1;
- for (port = 0; port < SJA1105_NUM_PORTS; port++) {
+ for (port = 0; port < ds->num_ports; port++) {
const struct tc_taprio_qopt_offload *offload;
/* Relative base time */
s64 rbt;
@@ -468,6 +469,7 @@ bool sja1105_gating_check_conflicts(struct sja1105_private *priv, int port,
struct sja1105_gating_config *gating_cfg = &priv->tas_data.gating_cfg;
size_t num_entries = gating_cfg->num_entries;
struct tc_taprio_qopt_offload *dummy;
+ struct dsa_switch *ds = priv->ds;
struct sja1105_gate_entry *e;
bool conflict;
int i = 0;
@@ -491,7 +493,7 @@ bool sja1105_gating_check_conflicts(struct sja1105_private *priv, int port,
if (port != -1) {
conflict = sja1105_tas_check_conflicts(priv, port, dummy);
} else {
- for (port = 0; port < SJA1105_NUM_PORTS; port++) {
+ for (port = 0; port < ds->num_ports; port++) {
conflict = sja1105_tas_check_conflicts(priv, port,
dummy);
if (conflict)
@@ -554,7 +556,7 @@ int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port,
}
}
- for (other_port = 0; other_port < SJA1105_NUM_PORTS; other_port++) {
+ for (other_port = 0; other_port < ds->num_ports; other_port++) {
if (other_port == port)
continue;
@@ -885,7 +887,7 @@ void sja1105_tas_teardown(struct dsa_switch *ds)
cancel_work_sync(&priv->tas_data.tas_work);
- for (port = 0; port < SJA1105_NUM_PORTS; port++) {
+ for (port = 0; port < ds->num_ports; port++) {
offload = priv->tas_data.offload[port];
if (!offload)
continue;
diff --git a/drivers/net/dsa/sja1105/sja1105_tas.h b/drivers/net/dsa/sja1105/sja1105_tas.h
index 0c173ff51751..c05bd07e8221 100644
--- a/drivers/net/dsa/sja1105/sja1105_tas.h
+++ b/drivers/net/dsa/sja1105/sja1105_tas.h
@@ -39,7 +39,7 @@ struct sja1105_gating_config {
};
struct sja1105_tas_data {
- struct tc_taprio_qopt_offload *offload[SJA1105_NUM_PORTS];
+ struct tc_taprio_qopt_offload *offload[SJA1105_MAX_NUM_PORTS];
struct sja1105_gating_config gating_cfg;
enum sja1105_tas_state state;
enum sja1105_ptp_op last_op;
diff --git a/drivers/net/dsa/sja1105/sja1105_vl.c b/drivers/net/dsa/sja1105/sja1105_vl.c
index ffc4042b4502..f6e13e6c6a18 100644
--- a/drivers/net/dsa/sja1105/sja1105_vl.c
+++ b/drivers/net/dsa/sja1105/sja1105_vl.c
@@ -386,7 +386,7 @@ static int sja1105_init_virtual_links(struct sja1105_private *priv,
if (rule->type != SJA1105_RULE_VL)
continue;
- for_each_set_bit(port, &rule->port_mask, SJA1105_NUM_PORTS) {
+ for_each_set_bit(port, &rule->port_mask, SJA1105_MAX_NUM_PORTS) {
vl_lookup[k].format = SJA1105_VL_FORMAT_PSFP;
vl_lookup[k].port = port;
vl_lookup[k].macaddr = rule->key.vl.dmac;
diff --git a/drivers/net/dsa/xrs700x/xrs700x.c b/drivers/net/dsa/xrs700x/xrs700x.c
index fde6e99274b6..130abb0f1438 100644
--- a/drivers/net/dsa/xrs700x/xrs700x.c
+++ b/drivers/net/dsa/xrs700x/xrs700x.c
@@ -79,6 +79,9 @@ static const struct xrs700x_mib xrs700x_mibs[] = {
XRS700X_MIB(XRS_EARLY_DROP_L, "early_drop", tx_dropped),
};
+static const u8 eth_hsrsup_addr[ETH_ALEN] = {
+ 0x01, 0x15, 0x4e, 0x00, 0x01, 0x00};
+
static void xrs700x_get_strings(struct dsa_switch *ds, int port,
u32 stringset, u8 *data)
{
@@ -329,6 +332,54 @@ static int xrs700x_port_add_bpdu_ipf(struct dsa_switch *ds, int port)
return 0;
}
+/* Add an inbound policy filter which matches the HSR/PRP supervision MAC
+ * range and forwards to the CPU port without discarding duplicates.
+ * This is required to correctly populate the HSR/PRP node_table.
+ * Leave the policy disabled, it will be enabled as needed.
+ */
+static int xrs700x_port_add_hsrsup_ipf(struct dsa_switch *ds, int port,
+ int fwdport)
+{
+ struct xrs700x *priv = ds->priv;
+ unsigned int val = 0;
+ int i = 0;
+ int ret;
+
+ /* Compare 40 bits of the destination MAC address. */
+ ret = regmap_write(priv->regmap, XRS_ETH_ADDR_CFG(port, 1), 40 << 2);
+ if (ret)
+ return ret;
+
+ /* match HSR/PRP supervision destination 01:15:4e:00:01:XX */
+ for (i = 0; i < sizeof(eth_hsrsup_addr); i += 2) {
+ ret = regmap_write(priv->regmap, XRS_ETH_ADDR_0(port, 1) + i,
+ eth_hsrsup_addr[i] |
+ (eth_hsrsup_addr[i + 1] << 8));
+ if (ret)
+ return ret;
+ }
+
+ /* Mirror HSR/PRP supervision to CPU port */
+ for (i = 0; i < ds->num_ports; i++) {
+ if (dsa_is_cpu_port(ds, i))
+ val |= BIT(i);
+ }
+
+ ret = regmap_write(priv->regmap, XRS_ETH_ADDR_FWD_MIRROR(port, 1), val);
+ if (ret)
+ return ret;
+
+ if (fwdport >= 0)
+ val |= BIT(fwdport);
+
+ /* Allow must be set prevent duplicate discard */
+ ret = regmap_write(priv->regmap, XRS_ETH_ADDR_FWD_ALLOW(port, 1), val);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int xrs700x_port_setup(struct dsa_switch *ds, int port)
{
bool cpu_port = dsa_is_cpu_port(ds, port);
@@ -511,6 +562,7 @@ static int xrs700x_hsr_join(struct dsa_switch *ds, int port,
struct net_device *slave;
int ret, i, hsr_pair[2];
enum hsr_version ver;
+ bool fwd = false;
ret = hsr_get_version(hsr, &ver);
if (ret)
@@ -556,6 +608,7 @@ static int xrs700x_hsr_join(struct dsa_switch *ds, int port,
if (ver == HSR_V1) {
val &= ~BIT(partner->index);
val &= ~BIT(port);
+ fwd = true;
}
val &= ~BIT(dsa_upstream_port(ds, port));
regmap_write(priv->regmap, XRS_PORT_FWD_MASK(partner->index), val);
@@ -565,6 +618,23 @@ static int xrs700x_hsr_join(struct dsa_switch *ds, int port,
XRS_PORT_FORWARDING);
regmap_fields_write(priv->ps_forward, port, XRS_PORT_FORWARDING);
+ /* Enable inbound policy which allows HSR/PRP supervision forwarding
+ * to the CPU port without discarding duplicates. Continue to
+ * forward to redundant ports when in HSR mode while discarding
+ * duplicates.
+ */
+ ret = xrs700x_port_add_hsrsup_ipf(ds, partner->index, fwd ? port : -1);
+ if (ret)
+ return ret;
+
+ ret = xrs700x_port_add_hsrsup_ipf(ds, port, fwd ? partner->index : -1);
+ if (ret)
+ return ret;
+
+ regmap_update_bits(priv->regmap,
+ XRS_ETH_ADDR_CFG(partner->index, 1), 1, 1);
+ regmap_update_bits(priv->regmap, XRS_ETH_ADDR_CFG(port, 1), 1, 1);
+
hsr_pair[0] = port;
hsr_pair[1] = partner->index;
for (i = 0; i < ARRAY_SIZE(hsr_pair); i++) {
@@ -611,6 +681,14 @@ static int xrs700x_hsr_leave(struct dsa_switch *ds, int port,
XRS_PORT_FORWARDING);
regmap_fields_write(priv->ps_forward, port, XRS_PORT_FORWARDING);
+ /* Disable inbound policy added by xrs700x_port_add_hsrsup_ipf()
+ * which allows HSR/PRP supervision forwarding to the CPU port without
+ * discarding duplicates.
+ */
+ regmap_update_bits(priv->regmap,
+ XRS_ETH_ADDR_CFG(partner->index, 1), 1, 0);
+ regmap_update_bits(priv->regmap, XRS_ETH_ADDR_CFG(port, 1), 1, 0);
+
hsr_pair[0] = port;
hsr_pair[1] = partner->index;
for (i = 0; i < ARRAY_SIZE(hsr_pair); i++) {
diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c
index 741c67e546d4..7d7d3ffe25c3 100644
--- a/drivers/net/ethernet/3com/3c59x.c
+++ b/drivers/net/ethernet/3com/3c59x.c
@@ -1464,7 +1464,7 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
if (pdev) {
vp->pm_state_valid = 1;
pci_save_state(pdev);
- acpi_set_WOL(dev);
+ acpi_set_WOL(dev);
}
retval = register_netdev(dev);
if (retval == 0)
diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c
index 2488bfdb9133..8c321dfc7b3b 100644
--- a/drivers/net/ethernet/8390/axnet_cs.c
+++ b/drivers/net/ethernet/8390/axnet_cs.c
@@ -767,7 +767,7 @@ module_pcmcia_driver(axnet_cs_driver);
Paul Gortmaker : tweak ANK's above multicast changes a bit.
Paul Gortmaker : update packet statistics for v2.1.x
Alan Cox : support arbitrary stupid port mappings on the
- 68K Macintosh. Support >16bit I/O spaces
+ 68K Macintosh. Support >16bit I/O spaces
Paul Gortmaker : add kmod support for auto-loading of the 8390
module by all drivers that require it.
Alan Cox : Spinlocking work, added 'BUG_83C690'
@@ -1091,7 +1091,7 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id)
long e8390_base;
int interrupts, nr_serviced = 0, i;
struct ei_device *ei_local;
- int handled = 0;
+ int handled = 0;
unsigned long flags;
e8390_base = dev->base_addr;
@@ -1587,12 +1587,12 @@ static void do_set_multicast_list(struct net_device *dev)
}
outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
- if(dev->flags&IFF_PROMISC)
- outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
+ if(dev->flags&IFF_PROMISC)
+ outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
else if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev))
- outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR);
- else
- outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR);
+ outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR);
+ else
+ outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
}
diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c
index 9d3b1e0e425c..cac036706382 100644
--- a/drivers/net/ethernet/8390/pcnet_cs.c
+++ b/drivers/net/ethernet/8390/pcnet_cs.c
@@ -1527,7 +1527,7 @@ static const struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2216-PCMCIA-ETHERNET", 0xdfc6b5b2, 0x5542bfff),
PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA100-PCM-T V2 100/10M LAN PC Card", 0xbb7fbdd7, 0xcd91cc68),
PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA100-PCM V2", 0x36634a66, 0xc6d05997),
- PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM_V2", 0xbb7fBdd7, 0x28e299f8),
+ PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM_V2", 0xbb7fBdd7, 0x28e299f8),
PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA-PCM V3", 0x36634a66, 0x62241d96),
PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8010", 0x5070a7f9, 0x82f96e96),
PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8610", 0x5070a7f9, 0x86741224),
diff --git a/drivers/net/ethernet/8390/smc-ultra.c b/drivers/net/ethernet/8390/smc-ultra.c
index 3fe3b4dfa7c5..1d8ed7357b7f 100644
--- a/drivers/net/ethernet/8390/smc-ultra.c
+++ b/drivers/net/ethernet/8390/smc-ultra.c
@@ -347,11 +347,11 @@ static int __init ultra_probe_isapnp(struct net_device *dev)
idev))) {
/* Avoid already found cards from previous calls */
if (pnp_device_attach(idev) < 0)
- continue;
+ continue;
if (pnp_activate_dev(idev) < 0) {
__again:
- pnp_device_detach(idev);
- continue;
+ pnp_device_detach(idev);
+ continue;
}
/* if no io and irq, search for next */
if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0))
diff --git a/drivers/net/ethernet/8390/stnic.c b/drivers/net/ethernet/8390/stnic.c
index 1f0670cd3ea3..fbbd7f22c142 100644
--- a/drivers/net/ethernet/8390/stnic.c
+++ b/drivers/net/ethernet/8390/stnic.c
@@ -114,7 +114,7 @@ static int __init stnic_probe(void)
/* New style probing API */
dev = alloc_ei_netdev();
if (!dev)
- return -ENOMEM;
+ return -ENOMEM;
#ifdef CONFIG_SH_STANDARD_BIOS
sh_bios_get_node_addr (stnic_eadr);
diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c
index d77fafbc1530..c560ad06f0be 100644
--- a/drivers/net/ethernet/aeroflex/greth.c
+++ b/drivers/net/ethernet/aeroflex/greth.c
@@ -1539,10 +1539,11 @@ static int greth_of_remove(struct platform_device *of_dev)
mdiobus_unregister(greth->mdio);
unregister_netdev(ndev);
- free_netdev(ndev);
of_iounmap(&of_dev->resource[0], greth->regs, resource_size(&of_dev->resource[0]));
+ free_netdev(ndev);
+
return 0;
}
diff --git a/drivers/net/ethernet/alteon/acenic.c b/drivers/net/ethernet/alteon/acenic.c
index 1a7e4df9b3e9..9dc12b13061f 100644
--- a/drivers/net/ethernet/alteon/acenic.c
+++ b/drivers/net/ethernet/alteon/acenic.c
@@ -1883,16 +1883,16 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd)
}
}
- if (ACE_IS_TIGON_I(ap)) {
- struct cmd cmd;
- cmd.evt = C_SET_RX_JUMBO_PRD_IDX;
- cmd.code = 0;
- cmd.idx = 0;
- ace_issue_cmd(ap->regs, &cmd);
- } else {
- writel(0, &((ap->regs)->RxJumboPrd));
- wmb();
- }
+ if (ACE_IS_TIGON_I(ap)) {
+ struct cmd cmd;
+ cmd.evt = C_SET_RX_JUMBO_PRD_IDX;
+ cmd.code = 0;
+ cmd.idx = 0;
+ ace_issue_cmd(ap->regs, &cmd);
+ } else {
+ writel(0, &((ap->regs)->RxJumboPrd));
+ wmb();
+ }
ap->jumbo = 0;
ap->rx_jumbo_skbprd = 0;
@@ -2489,9 +2489,9 @@ restart:
}
}
- wmb();
- ap->tx_prd = idx;
- ace_set_txprd(regs, ap, idx);
+ wmb();
+ ap->tx_prd = idx;
+ ace_set_txprd(regs, ap, idx);
if (flagsize & BD_FLG_COAL_NOW) {
netif_stop_queue(dev);
diff --git a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
index 4164eacc5c28..f5ec35fa4c63 100644
--- a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
+++ b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h
@@ -1042,8 +1042,6 @@ enum ena_admin_aenq_group {
};
enum ena_admin_aenq_notification_syndrome {
- ENA_ADMIN_SUSPEND = 0,
- ENA_ADMIN_RESUME = 1,
ENA_ADMIN_UPDATE_HINTS = 2,
};
diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c
index 764852ead1d6..ab413fc1f68e 100644
--- a/drivers/net/ethernet/amazon/ena/ena_com.c
+++ b/drivers/net/ethernet/amazon/ena/ena_com.c
@@ -1979,7 +1979,8 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
if (rc)
return rc;
- if (get_resp.u.max_queue_ext.version != ENA_FEATURE_MAX_QUEUE_EXT_VER)
+ 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,
diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.c b/drivers/net/ethernet/amazon/ena/ena_eth_com.c
index c3be751e7379..3d6f0a466a9e 100644
--- a/drivers/net/ethernet/amazon/ena/ena_eth_com.c
+++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.c
@@ -151,11 +151,14 @@ static int ena_com_close_bounce_buffer(struct ena_com_io_sq *io_sq)
return 0;
/* bounce buffer was used, so write it and get a new one */
- if (pkt_ctrl->idx) {
+ if (likely(pkt_ctrl->idx)) {
rc = ena_com_write_bounce_buffer_to_dev(io_sq,
pkt_ctrl->curr_bounce_buf);
- if (unlikely(rc))
+ if (unlikely(rc)) {
+ netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
+ "Failed to write bounce buffer to device\n");
return rc;
+ }
pkt_ctrl->curr_bounce_buf =
ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
@@ -185,8 +188,11 @@ static int ena_com_sq_update_llq_tail(struct ena_com_io_sq *io_sq)
if (!pkt_ctrl->descs_left_in_line) {
rc = ena_com_write_bounce_buffer_to_dev(io_sq,
pkt_ctrl->curr_bounce_buf);
- if (unlikely(rc))
+ if (unlikely(rc)) {
+ netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
+ "Failed to write bounce buffer to device\n");
return rc;
+ }
pkt_ctrl->curr_bounce_buf =
ena_com_get_next_bounce_buffer(&io_sq->bounce_buf_ctrl);
@@ -406,8 +412,11 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
}
if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV &&
- !buffer_to_push))
+ !buffer_to_push)) {
+ netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
+ "Push header wasn't provided in LLQ mode\n");
return -EINVAL;
+ }
rc = ena_com_write_header_to_bounce(io_sq, buffer_to_push, header_len);
if (unlikely(rc))
@@ -423,6 +432,9 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
/* If the caller doesn't want to send packets */
if (unlikely(!num_bufs && !header_len)) {
rc = ena_com_close_bounce_buffer(io_sq);
+ if (rc)
+ netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
+ "Failed to write buffers to LLQ\n");
*nb_hw_desc = io_sq->tail - start_tail;
return rc;
}
@@ -482,8 +494,11 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
/* The first desc share the same desc as the header */
if (likely(i != 0)) {
rc = ena_com_sq_update_tail(io_sq);
- if (unlikely(rc))
+ if (unlikely(rc)) {
+ netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
+ "Failed to update sq tail\n");
return rc;
+ }
desc = get_sq_desc(io_sq);
if (unlikely(!desc))
@@ -512,8 +527,11 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq,
desc->len_ctrl |= ENA_ETH_IO_TX_DESC_LAST_MASK;
rc = ena_com_sq_update_tail(io_sq);
- if (unlikely(rc))
+ if (unlikely(rc)) {
+ netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device,
+ "Failed to update sq tail of the last descriptor\n");
return rc;
+ }
rc = ena_com_close_bounce_buffer(io_sq);
diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c
index 2fe7ccee55b2..27dae632efcb 100644
--- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c
+++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c
@@ -233,10 +233,13 @@ int ena_get_sset_count(struct net_device *netdev, int sset)
{
struct ena_adapter *adapter = netdev_priv(netdev);
- if (sset != ETH_SS_STATS)
- return -EOPNOTSUPP;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ena_get_sw_stats_count(adapter) +
+ ena_get_hw_stats_count(adapter);
+ }
- return ena_get_sw_stats_count(adapter) + ena_get_hw_stats_count(adapter);
+ return -EOPNOTSUPP;
}
static void ena_queue_strings(struct ena_adapter *adapter, u8 **data)
@@ -314,10 +317,11 @@ static void ena_get_ethtool_strings(struct net_device *netdev,
{
struct ena_adapter *adapter = netdev_priv(netdev);
- if (sset != ETH_SS_STATS)
- return;
-
- ena_get_strings(adapter, data, adapter->eni_stats_supported);
+ switch (sset) {
+ case ETH_SS_STATS:
+ ena_get_strings(adapter, data, adapter->eni_stats_supported);
+ break;
+ }
}
static int ena_get_link_ksettings(struct net_device *netdev,
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c
index 52571486705e..0e43000614ab 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -35,9 +35,6 @@ MODULE_LICENSE("GPL");
#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | \
NETIF_MSG_TX_DONE | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR)
-static int debug = -1;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
static struct ena_aenq_handlers aenq_handlers;
@@ -89,6 +86,12 @@ static void ena_increase_stat(u64 *statp, u64 cnt,
u64_stats_update_end(syncp);
}
+static void ena_ring_tx_doorbell(struct ena_ring *tx_ring)
+{
+ ena_com_write_sq_doorbell(tx_ring->ena_com_io_sq);
+ ena_increase_stat(&tx_ring->tx_stats.doorbells, 1, &tx_ring->syncp);
+}
+
static void ena_tx_timeout(struct net_device *dev, unsigned int txqueue)
{
struct ena_adapter *adapter = netdev_priv(dev);
@@ -147,7 +150,7 @@ static int ena_xmit_common(struct net_device *dev,
netif_dbg(adapter, tx_queued, dev,
"llq tx max burst size of queue %d achieved, writing doorbell to send burst\n",
ring->qid);
- ena_com_write_sq_doorbell(ring->ena_com_io_sq);
+ ena_ring_tx_doorbell(ring);
}
/* prepare the packet's descriptors to dma engine */
@@ -197,7 +200,6 @@ static int ena_xdp_io_poll(struct napi_struct *napi, int budget)
int ret;
xdp_ring = ena_napi->xdp_ring;
- xdp_ring->first_interrupt = ena_napi->first_interrupt;
xdp_budget = budget;
@@ -229,6 +231,7 @@ static int ena_xdp_io_poll(struct napi_struct *napi, int budget)
xdp_ring->tx_stats.napi_comp += napi_comp_call;
xdp_ring->tx_stats.tx_poll++;
u64_stats_update_end(&xdp_ring->syncp);
+ xdp_ring->tx_stats.last_napi_jiffies = jiffies;
return ret;
}
@@ -318,14 +321,12 @@ static int ena_xdp_xmit_frame(struct ena_ring *xdp_ring,
xdpf->len);
if (rc)
goto error_unmap_dma;
- /* trigger the dma engine. ena_com_write_sq_doorbell()
- * has a mb
+
+ /* trigger the dma engine. ena_ring_tx_doorbell()
+ * calls a memory barrier inside it.
*/
- if (flags & XDP_XMIT_FLUSH) {
- ena_com_write_sq_doorbell(xdp_ring->ena_com_io_sq);
- ena_increase_stat(&xdp_ring->tx_stats.doorbells, 1,
- &xdp_ring->syncp);
- }
+ if (flags & XDP_XMIT_FLUSH)
+ ena_ring_tx_doorbell(xdp_ring);
return rc;
@@ -366,11 +367,8 @@ static int ena_xdp_xmit(struct net_device *dev, int n,
}
/* Ring doorbell to make device aware of the packets */
- if (flags & XDP_XMIT_FLUSH) {
- ena_com_write_sq_doorbell(xdp_ring->ena_com_io_sq);
- ena_increase_stat(&xdp_ring->tx_stats.doorbells, 1,
- &xdp_ring->syncp);
- }
+ if (flags & XDP_XMIT_FLUSH)
+ ena_ring_tx_doorbell(xdp_ring);
spin_unlock(&xdp_ring->xdp_tx_lock);
@@ -385,9 +383,7 @@ static int ena_xdp_execute(struct ena_ring *rx_ring, struct xdp_buff *xdp)
u32 verdict = XDP_PASS;
struct xdp_frame *xdpf;
u64 *xdp_stat;
- int qid;
- rcu_read_lock();
xdp_prog = READ_ONCE(rx_ring->xdp_bpf_prog);
if (!xdp_prog)
@@ -406,8 +402,7 @@ static int ena_xdp_execute(struct ena_ring *rx_ring, struct xdp_buff *xdp)
}
/* Find xmit queue */
- qid = rx_ring->qid + rx_ring->adapter->num_io_queues;
- xdp_ring = &rx_ring->adapter->tx_ring[qid];
+ xdp_ring = rx_ring->xdp_ring;
/* The XDP queues are shared between XDP_TX and XDP_REDIRECT */
spin_lock(&xdp_ring->xdp_tx_lock);
@@ -445,8 +440,6 @@ static int ena_xdp_execute(struct ena_ring *rx_ring, struct xdp_buff *xdp)
ena_increase_stat(xdp_stat, 1, &rx_ring->syncp);
out:
- rcu_read_unlock();
-
return verdict;
}
@@ -534,7 +527,7 @@ static void ena_xdp_exchange_program_rx_in_range(struct ena_adapter *adapter,
rx_ring->rx_headroom = XDP_PACKET_HEADROOM;
} else {
ena_xdp_unregister_rxq_info(rx_ring);
- rx_ring->rx_headroom = 0;
+ rx_ring->rx_headroom = NET_SKB_PAD;
}
}
}
@@ -683,7 +676,6 @@ static void ena_init_io_rings_common(struct ena_adapter *adapter,
ring->ena_dev = adapter->ena_dev;
ring->per_napi_packets = 0;
ring->cpu = 0;
- ring->first_interrupt = false;
ring->no_interrupt_event_cnt = 0;
u64_stats_init(&ring->syncp);
}
@@ -726,7 +718,9 @@ static void ena_init_io_rings(struct ena_adapter *adapter,
rxr->smoothed_interval =
ena_com_get_nonadaptive_moderation_interval_rx(ena_dev);
rxr->empty_rx_queue = 0;
+ rxr->rx_headroom = NET_SKB_PAD;
adapter->ena_napi[i].dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+ rxr->xdp_ring = &adapter->tx_ring[i + adapter->num_io_queues];
}
}
}
@@ -980,47 +974,66 @@ static void ena_free_all_io_rx_resources(struct ena_adapter *adapter)
ena_free_rx_resources(adapter, i);
}
-static int ena_alloc_rx_page(struct ena_ring *rx_ring,
- struct ena_rx_buffer *rx_info, gfp_t gfp)
+static struct page *ena_alloc_map_page(struct ena_ring *rx_ring,
+ dma_addr_t *dma)
{
- int headroom = rx_ring->rx_headroom;
- struct ena_com_buf *ena_buf;
struct page *page;
- dma_addr_t dma;
- /* restore page offset value in case it has been changed by device */
- rx_info->page_offset = headroom;
-
- /* if previous allocated page is not used */
- if (unlikely(rx_info->page))
- return 0;
-
- page = alloc_page(gfp);
- if (unlikely(!page)) {
+ /* This would allocate the page on the same NUMA node the executing code
+ * is running on.
+ */
+ page = dev_alloc_page();
+ if (!page) {
ena_increase_stat(&rx_ring->rx_stats.page_alloc_fail, 1,
&rx_ring->syncp);
- return -ENOMEM;
+ return ERR_PTR(-ENOSPC);
}
/* To enable NIC-side port-mirroring, AKA SPAN port,
* we make the buffer readable from the nic as well
*/
- dma = dma_map_page(rx_ring->dev, page, 0, ENA_PAGE_SIZE,
- DMA_BIDIRECTIONAL);
- if (unlikely(dma_mapping_error(rx_ring->dev, dma))) {
+ *dma = dma_map_page(rx_ring->dev, page, 0, ENA_PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+ if (unlikely(dma_mapping_error(rx_ring->dev, *dma))) {
ena_increase_stat(&rx_ring->rx_stats.dma_mapping_err, 1,
&rx_ring->syncp);
-
__free_page(page);
- return -EIO;
+ return ERR_PTR(-EIO);
}
+
+ return page;
+}
+
+static int ena_alloc_rx_buffer(struct ena_ring *rx_ring,
+ struct ena_rx_buffer *rx_info)
+{
+ int headroom = rx_ring->rx_headroom;
+ struct ena_com_buf *ena_buf;
+ struct page *page;
+ dma_addr_t dma;
+ int tailroom;
+
+ /* restore page offset value in case it has been changed by device */
+ rx_info->page_offset = headroom;
+
+ /* if previous allocated page is not used */
+ if (unlikely(rx_info->page))
+ return 0;
+
+ /* We handle DMA here */
+ page = ena_alloc_map_page(rx_ring, &dma);
+ if (unlikely(IS_ERR(page)))
+ return PTR_ERR(page);
+
netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
"Allocate page %p, rx_info %p\n", page, rx_info);
+ tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
rx_info->page = page;
ena_buf = &rx_info->ena_buf;
ena_buf->paddr = dma + headroom;
- ena_buf->len = ENA_PAGE_SIZE - headroom;
+ ena_buf->len = ENA_PAGE_SIZE - headroom - tailroom;
return 0;
}
@@ -1067,8 +1080,7 @@ static int ena_refill_rx_bufs(struct ena_ring *rx_ring, u32 num)
rx_info = &rx_ring->rx_buffer_info[req_id];
- rc = ena_alloc_rx_page(rx_ring, rx_info,
- GFP_ATOMIC | __GFP_COMP);
+ rc = ena_alloc_rx_buffer(rx_ring, rx_info);
if (unlikely(rc < 0)) {
netif_warn(rx_ring->adapter, rx_err, rx_ring->netdev,
"Failed to allocate buffer for rx queue %d\n",
@@ -1386,21 +1398,23 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget)
return tx_pkts;
}
-static struct sk_buff *ena_alloc_skb(struct ena_ring *rx_ring, bool frags)
+static struct sk_buff *ena_alloc_skb(struct ena_ring *rx_ring, void *first_frag)
{
struct sk_buff *skb;
- if (frags)
- skb = napi_get_frags(rx_ring->napi);
- else
+ if (!first_frag)
skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
rx_ring->rx_copybreak);
+ else
+ skb = build_skb(first_frag, ENA_PAGE_SIZE);
if (unlikely(!skb)) {
ena_increase_stat(&rx_ring->rx_stats.skb_alloc_fail, 1,
&rx_ring->syncp);
+
netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev,
- "Failed to allocate skb. frags: %d\n", frags);
+ "Failed to allocate skb. first_frag %s\n",
+ first_frag ? "provided" : "not provided");
return NULL;
}
@@ -1412,10 +1426,12 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
u32 descs,
u16 *next_to_clean)
{
- struct sk_buff *skb;
struct ena_rx_buffer *rx_info;
u16 len, req_id, buf = 0;
- void *va;
+ struct sk_buff *skb;
+ void *page_addr;
+ u32 page_offset;
+ void *data_addr;
len = ena_bufs[buf].len;
req_id = ena_bufs[buf].req_id;
@@ -1433,12 +1449,14 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
rx_info, rx_info->page);
/* save virt address of first buffer */
- va = page_address(rx_info->page) + rx_info->page_offset;
+ page_addr = page_address(rx_info->page);
+ page_offset = rx_info->page_offset;
+ data_addr = page_addr + page_offset;
- prefetch(va);
+ prefetch(data_addr);
if (len <= rx_ring->rx_copybreak) {
- skb = ena_alloc_skb(rx_ring, false);
+ skb = ena_alloc_skb(rx_ring, NULL);
if (unlikely(!skb))
return NULL;
@@ -1451,7 +1469,7 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
dma_unmap_addr(&rx_info->ena_buf, paddr),
len,
DMA_FROM_DEVICE);
- skb_copy_to_linear_data(skb, va, len);
+ skb_copy_to_linear_data(skb, data_addr, len);
dma_sync_single_for_device(rx_ring->dev,
dma_unmap_addr(&rx_info->ena_buf, paddr),
len,
@@ -1465,16 +1483,18 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
return skb;
}
- skb = ena_alloc_skb(rx_ring, true);
+ ena_unmap_rx_buff(rx_ring, rx_info);
+
+ skb = ena_alloc_skb(rx_ring, page_addr);
if (unlikely(!skb))
return NULL;
- do {
- ena_unmap_rx_buff(rx_ring, rx_info);
-
- skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_info->page,
- rx_info->page_offset, len, ENA_PAGE_SIZE);
+ /* Populate skb's linear part */
+ skb_reserve(skb, page_offset);
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, rx_ring->netdev);
+ do {
netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev,
"RX skb updated. len %d. data_len %d\n",
skb->len, skb->data_len);
@@ -1493,6 +1513,12 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
req_id = ena_bufs[buf].req_id;
rx_info = &rx_ring->rx_buffer_info[req_id];
+
+ ena_unmap_rx_buff(rx_ring, rx_info);
+
+ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_info->page,
+ rx_info->page_offset, len, ENA_PAGE_SIZE);
+
} while (1);
return skb;
@@ -1705,14 +1731,12 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi,
skb_record_rx_queue(skb, rx_ring->qid);
- if (rx_ring->ena_bufs[0].len <= rx_ring->rx_copybreak) {
- total_len += rx_ring->ena_bufs[0].len;
+ if (rx_ring->ena_bufs[0].len <= rx_ring->rx_copybreak)
rx_copybreak_pkt++;
- napi_gro_receive(napi, skb);
- } else {
- total_len += skb->len;
- napi_gro_frags(napi);
- }
+
+ total_len += skb->len;
+
+ napi_gro_receive(napi, skb);
res_budget--;
} while (likely(res_budget));
@@ -1924,9 +1948,6 @@ static int ena_io_poll(struct napi_struct *napi, int budget)
tx_ring = ena_napi->tx_ring;
rx_ring = ena_napi->rx_ring;
- tx_ring->first_interrupt = ena_napi->first_interrupt;
- rx_ring->first_interrupt = ena_napi->first_interrupt;
-
tx_budget = tx_ring->ring_size / ENA_TX_POLL_BUDGET_DIVIDER;
if (!test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags) ||
@@ -1981,6 +2002,8 @@ static int ena_io_poll(struct napi_struct *napi, int budget)
tx_ring->tx_stats.tx_poll++;
u64_stats_update_end(&tx_ring->syncp);
+ tx_ring->tx_stats.last_napi_jiffies = jiffies;
+
return ret;
}
@@ -2005,7 +2028,8 @@ static irqreturn_t ena_intr_msix_io(int irq, void *data)
{
struct ena_napi *ena_napi = data;
- ena_napi->first_interrupt = true;
+ /* Used to check HW health */
+ WRITE_ONCE(ena_napi->first_interrupt, true);
WRITE_ONCE(ena_napi->interrupts_masked, true);
smp_wmb(); /* write interrupts_masked before calling napi */
@@ -3091,14 +3115,11 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
- if (netif_xmit_stopped(txq) || !netdev_xmit_more()) {
- /* trigger the dma engine. ena_com_write_sq_doorbell()
- * has a mb
+ if (netif_xmit_stopped(txq) || !netdev_xmit_more())
+ /* trigger the dma engine. ena_ring_tx_doorbell()
+ * calls a memory barrier inside it.
*/
- ena_com_write_sq_doorbell(tx_ring->ena_com_io_sq);
- ena_increase_stat(&tx_ring->tx_stats.doorbells, 1,
- &tx_ring->syncp);
- }
+ ena_ring_tx_doorbell(tx_ring);
return NETDEV_TX_OK;
@@ -3348,7 +3369,7 @@ static int ena_set_queues_placement_policy(struct pci_dev *pdev,
llq_feature_mask = 1 << ENA_ADMIN_LLQ;
if (!(ena_dev->supported_features & llq_feature_mask)) {
- dev_err(&pdev->dev,
+ dev_warn(&pdev->dev,
"LLQ is not supported Fallback to host mode policy.\n");
ena_dev->tx_mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
return 0;
@@ -3659,7 +3680,9 @@ static void ena_fw_reset_device(struct work_struct *work)
static int check_for_rx_interrupt_queue(struct ena_adapter *adapter,
struct ena_ring *rx_ring)
{
- if (likely(rx_ring->first_interrupt))
+ struct ena_napi *ena_napi = container_of(rx_ring->napi, struct ena_napi, napi);
+
+ if (likely(READ_ONCE(ena_napi->first_interrupt)))
return 0;
if (ena_com_cq_empty(rx_ring->ena_com_io_cq))
@@ -3683,6 +3706,10 @@ static int check_for_rx_interrupt_queue(struct ena_adapter *adapter,
static int check_missing_comp_in_tx_queue(struct ena_adapter *adapter,
struct ena_ring *tx_ring)
{
+ struct ena_napi *ena_napi = container_of(tx_ring->napi, struct ena_napi, napi);
+ unsigned int time_since_last_napi;
+ unsigned int missing_tx_comp_to;
+ bool is_tx_comp_time_expired;
struct ena_tx_buffer *tx_buf;
unsigned long last_jiffies;
u32 missed_tx = 0;
@@ -3696,8 +3723,10 @@ static int check_missing_comp_in_tx_queue(struct ena_adapter *adapter,
/* no pending Tx at this location */
continue;
- if (unlikely(!tx_ring->first_interrupt && time_is_before_jiffies(last_jiffies +
- 2 * adapter->missing_tx_completion_to))) {
+ is_tx_comp_time_expired = time_is_before_jiffies(last_jiffies +
+ 2 * adapter->missing_tx_completion_to);
+
+ if (unlikely(!READ_ONCE(ena_napi->first_interrupt) && is_tx_comp_time_expired)) {
/* If after graceful period interrupt is still not
* received, we schedule a reset
*/
@@ -3710,12 +3739,17 @@ static int check_missing_comp_in_tx_queue(struct ena_adapter *adapter,
return -EIO;
}
- if (unlikely(time_is_before_jiffies(last_jiffies +
- adapter->missing_tx_completion_to))) {
- if (!tx_buf->print_once)
+ is_tx_comp_time_expired = time_is_before_jiffies(last_jiffies +
+ adapter->missing_tx_completion_to);
+
+ if (unlikely(is_tx_comp_time_expired)) {
+ if (!tx_buf->print_once) {
+ time_since_last_napi = jiffies_to_usecs(jiffies - tx_ring->tx_stats.last_napi_jiffies);
+ missing_tx_comp_to = jiffies_to_msecs(adapter->missing_tx_completion_to);
netif_notice(adapter, tx_err, adapter->netdev,
- "Found a Tx that wasn't completed on time, qid %d, index %d.\n",
- tx_ring->qid, i);
+ "Found a Tx that wasn't completed on time, qid %d, index %d. %u usecs have passed since last napi execution. Missing Tx timeout value %u msecs\n",
+ tx_ring->qid, i, time_since_last_napi, missing_tx_comp_to);
+ }
tx_buf->print_once = 1;
missed_tx++;
@@ -4246,7 +4280,7 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->ena_dev = ena_dev;
adapter->netdev = netdev;
adapter->pdev = pdev;
- adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
+ adapter->msg_enable = DEFAULT_MSG_ENABLE;
ena_dev->net_device = netdev;
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h
index 74af15d62ee1..0c39fc2fa345 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.h
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h
@@ -55,12 +55,6 @@
#define ENA_TX_WAKEUP_THRESH (MAX_SKB_FRAGS + 2)
#define ENA_DEFAULT_RX_COPYBREAK (256 - NET_IP_ALIGN)
-/* limit the buffer size to 600 bytes to handle MTU changes from very
- * small to very large, in which case the number of buffers per packet
- * could exceed ENA_PKT_MAX_BUFS
- */
-#define ENA_DEFAULT_MIN_RX_BUFF_ALLOC_SIZE 600
-
#define ENA_MIN_MTU 128
#define ENA_NAME_MAX_LEN 20
@@ -135,12 +129,12 @@ struct ena_irq {
};
struct ena_napi {
- struct napi_struct napi ____cacheline_aligned;
+ u8 first_interrupt ____cacheline_aligned;
+ u8 interrupts_masked;
+ struct napi_struct napi;
struct ena_ring *tx_ring;
struct ena_ring *rx_ring;
struct ena_ring *xdp_ring;
- bool first_interrupt;
- bool interrupts_masked;
u32 qid;
struct dim dim;
};
@@ -212,6 +206,7 @@ struct ena_stats_tx {
u64 llq_buffer_copy;
u64 missed_tx;
u64 unmask_interrupt;
+ u64 last_napi_jiffies;
};
struct ena_stats_rx {
@@ -259,6 +254,10 @@ struct ena_ring {
struct bpf_prog *xdp_bpf_prog;
struct xdp_rxq_info xdp_rxq;
spinlock_t xdp_tx_lock; /* synchronize XDP TX/Redirect traffic */
+ /* Used for rx queues only to point to the xdp tx ring, to
+ * which traffic should be redirected from this rx ring.
+ */
+ struct ena_ring *xdp_ring;
u16 next_to_use;
u16 next_to_clean;
@@ -271,7 +270,6 @@ struct ena_ring {
/* The maximum header length the device can handle */
u8 tx_max_header_size;
- bool first_interrupt;
bool disable_meta_caching;
u16 no_interrupt_event_cnt;
@@ -414,11 +412,6 @@ enum ena_xdp_errors_t {
ENA_XDP_NO_ENOUGH_QUEUES,
};
-static inline bool ena_xdp_queues_present(struct ena_adapter *adapter)
-{
- return adapter->xdp_first_ring != 0;
-}
-
static inline bool ena_xdp_present(struct ena_adapter *adapter)
{
return !!adapter->xdp_bpf_prog;
diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c
index 4a1220cc6f10..9cac5aa75a73 100644
--- a/drivers/net/ethernet/amd/amd8111e.c
+++ b/drivers/net/ethernet/amd/amd8111e.c
@@ -19,14 +19,14 @@ Module Name:
Abstract:
- AMD8111 based 10/100 Ethernet Controller Driver.
+ AMD8111 based 10/100 Ethernet Controller Driver.
Environment:
Kernel Mode
Revision History:
- 3.0.0
+ 3.0.0
Initial Revision.
3.0.1
1. Dynamic interrupt coalescing.
diff --git a/drivers/net/ethernet/amd/amd8111e.h b/drivers/net/ethernet/amd/amd8111e.h
index 493f154eccf4..37da79da5f5e 100644
--- a/drivers/net/ethernet/amd/amd8111e.h
+++ b/drivers/net/ethernet/amd/amd8111e.h
@@ -10,14 +10,14 @@ Module Name:
Abstract:
- AMD8111 based 10/100 Ethernet Controller driver definitions.
+ AMD8111 based 10/100 Ethernet Controller driver definitions.
Environment:
Kernel Mode
Revision History:
- 3.0.0
+ 3.0.0
Initial Revision.
3.0.1
*/
@@ -692,7 +692,7 @@ enum coal_type{
};
enum coal_mode{
- RX_INTR_COAL,
+ RX_INTR_COAL,
TX_INTR_COAL,
DISABLE_COAL,
ENABLE_COAL,
diff --git a/drivers/net/ethernet/amd/atarilance.c b/drivers/net/ethernet/amd/atarilance.c
index c1eab916438f..36f54d13a2eb 100644
--- a/drivers/net/ethernet/amd/atarilance.c
+++ b/drivers/net/ethernet/amd/atarilance.c
@@ -706,7 +706,7 @@ static void lance_init_ring( struct net_device *dev )
CHECK_OFFSET(offset);
MEM->tx_head[i].base = offset;
MEM->tx_head[i].flag = TMD1_OWN_HOST;
- MEM->tx_head[i].base_hi = 0;
+ MEM->tx_head[i].base_hi = 0;
MEM->tx_head[i].length = 0;
MEM->tx_head[i].misc = 0;
offset += PKT_BUF_SZ;
diff --git a/drivers/net/ethernet/amd/declance.c b/drivers/net/ethernet/amd/declance.c
index 7282ce55ffb8..493b0cefcc2a 100644
--- a/drivers/net/ethernet/amd/declance.c
+++ b/drivers/net/ethernet/amd/declance.c
@@ -937,7 +937,7 @@ static netdev_tx_t lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return NETDEV_TX_OK;
+ return NETDEV_TX_OK;
}
static void lance_load_multicast(struct net_device *dev)
diff --git a/drivers/net/ethernet/amd/lance.c b/drivers/net/ethernet/amd/lance.c
index aff44241988c..2178e6b89dbd 100644
--- a/drivers/net/ethernet/amd/lance.c
+++ b/drivers/net/ethernet/amd/lance.c
@@ -780,7 +780,7 @@ lance_open(struct net_device *dev)
outw(0x0002, ioaddr+LANCE_ADDR);
/* Only touch autoselect bit. */
outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
- }
+ }
if (lance_debug > 1)
printk("%s: lance_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
@@ -812,7 +812,7 @@ lance_open(struct net_device *dev)
* We used to clear the InitDone bit, 0x0100, here but Mark Stockton
* reports that doing so triggers a bug in the '974.
*/
- outw(0x0042, ioaddr+LANCE_DATA);
+ outw(0x0042, ioaddr+LANCE_DATA);
if (lance_debug > 2)
printk("%s: LANCE open after %d ticks, init block %#x csr0 %4.4x.\n",
diff --git a/drivers/net/ethernet/amd/ni65.c b/drivers/net/ethernet/amd/ni65.c
index c38edf6f03a3..5c1cfb0c4a42 100644
--- a/drivers/net/ethernet/amd/ni65.c
+++ b/drivers/net/ethernet/amd/ni65.c
@@ -193,7 +193,7 @@ static struct card {
.vendor_id = ni_vendor,
.cardname = "ni6510",
.config = 0x1,
- },
+ },
{
.id0 = NI65_EB_ID0,
.id1 = NI65_EB_ID1,
@@ -204,7 +204,7 @@ static struct card {
.vendor_id = ni_vendor,
.cardname = "ni6510 EtherBlaster",
.config = 0x2,
- },
+ },
{
.id0 = NE2100_ID0,
.id1 = NE2100_ID1,
@@ -1232,15 +1232,15 @@ MODULE_PARM_DESC(dma, "ni6510 ISA DMA channel (ignored for some cards)");
int __init init_module(void)
{
- dev_ni65 = ni65_probe(-1);
+ dev_ni65 = ni65_probe(-1);
return PTR_ERR_OR_ZERO(dev_ni65);
}
void __exit cleanup_module(void)
{
- unregister_netdev(dev_ni65);
- cleanup_card(dev_ni65);
- free_netdev(dev_ni65);
+ unregister_netdev(dev_ni65);
+ cleanup_card(dev_ni65);
+ free_netdev(dev_ni65);
}
#endif /* MODULE */
diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c
index 11c0b13edd30..4019cab87505 100644
--- a/drivers/net/ethernet/amd/nmclan_cs.c
+++ b/drivers/net/ethernet/amd/nmclan_cs.c
@@ -541,7 +541,7 @@ static int mace_init(mace_private *lp, unsigned int ioaddr, char *enet_addr)
if(++ct > 500)
{
pr_err("reset failed, card removed?\n");
- return -1;
+ return -1;
}
udelay(1);
}
@@ -585,11 +585,11 @@ static int mace_init(mace_private *lp, unsigned int ioaddr, char *enet_addr)
ct = 0;
while (mace_read(lp, ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG)
{
- if(++ ct > 500)
- {
+ if(++ ct > 500)
+ {
pr_err("ADDRCHG timeout, card removed?\n");
- return -1;
- }
+ return -1;
+ }
}
/* Set PADR register */
for (i = 0; i < ETH_ALEN; i++)
@@ -655,7 +655,7 @@ static int nmclan_config(struct pcmcia_device *link)
}
if(mace_init(lp, ioaddr, dev->dev_addr) == -1)
- goto failed;
+ goto failed;
/* The if_port symbol can be set when the module is loaded */
if (if_port <= 2)
diff --git a/drivers/net/ethernet/amd/sun3lance.c b/drivers/net/ethernet/amd/sun3lance.c
index 00ae1081254d..f8d7a9387a56 100644
--- a/drivers/net/ethernet/amd/sun3lance.c
+++ b/drivers/net/ethernet/amd/sun3lance.c
@@ -150,7 +150,7 @@ struct lance_memory {
struct lance_private {
volatile unsigned short *iobase;
struct lance_memory *mem;
- int new_rx, new_tx; /* The next free ring entry */
+ int new_rx, new_tx; /* The next free ring entry */
int old_tx, old_rx; /* ring entry to be processed */
/* These two must be longs for set_bit() */
long tx_full;
@@ -465,7 +465,7 @@ static void lance_init_ring( struct net_device *dev )
for( i = 0; i < TX_RING_SIZE; i++ ) {
MEM->tx_head[i].base = dvma_vtob(MEM->tx_data[i]);
MEM->tx_head[i].flag = 0;
- MEM->tx_head[i].base_hi =
+ MEM->tx_head[i].base_hi =
(dvma_vtob(MEM->tx_data[i])) >>16;
MEM->tx_head[i].length = 0;
MEM->tx_head[i].misc = 0;
@@ -581,8 +581,8 @@ lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
AREG = CSR0;
- DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
- dev->name, DREG ));
+ DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
+ dev->name, DREG ));
#ifdef CONFIG_SUN3X
/* this weirdness doesn't appear on sun3... */
@@ -636,8 +636,8 @@ lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Trigger an immediate send poll. */
REGA(CSR0) = CSR0_INEA | CSR0_TDMD | CSR0_STRT;
AREG = CSR0;
- DPRINTK( 2, ( "%s: lance_start_xmit() exiting, csr0 %4.4x.\n",
- dev->name, DREG ));
+ DPRINTK( 2, ( "%s: lance_start_xmit() exiting, csr0 %4.4x.\n",
+ dev->name, DREG ));
dev_kfree_skb(skb);
lp->lock = 0;
diff --git a/drivers/net/ethernet/apple/bmac.c b/drivers/net/ethernet/apple/bmac.c
index 1e4e402f07d7..a989d2df59ad 100644
--- a/drivers/net/ethernet/apple/bmac.c
+++ b/drivers/net/ethernet/apple/bmac.c
@@ -477,26 +477,26 @@ static int bmac_suspend(struct macio_dev *mdev, pm_message_t state)
config = bmread(dev, RXCFG);
bmwrite(dev, RXCFG, (config & ~RxMACEnable));
config = bmread(dev, TXCFG);
- bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+ bmwrite(dev, TXCFG, (config & ~TxMACEnable));
bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
- /* disable rx and tx dma */
+ /* disable rx and tx dma */
rd->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */
td->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */
- /* free some skb's */
- for (i=0; i<N_RX_RING; i++) {
- if (bp->rx_bufs[i] != NULL) {
- dev_kfree_skb(bp->rx_bufs[i]);
- bp->rx_bufs[i] = NULL;
- }
- }
- for (i = 0; i<N_TX_RING; i++) {
+ /* free some skb's */
+ for (i=0; i<N_RX_RING; i++) {
+ if (bp->rx_bufs[i] != NULL) {
+ dev_kfree_skb(bp->rx_bufs[i]);
+ bp->rx_bufs[i] = NULL;
+ }
+ }
+ for (i = 0; i<N_TX_RING; i++) {
if (bp->tx_bufs[i] != NULL) {
dev_kfree_skb(bp->tx_bufs[i]);
bp->tx_bufs[i] = NULL;
}
}
}
- pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
+ pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
return 0;
}
@@ -510,9 +510,9 @@ static int bmac_resume(struct macio_dev *mdev)
bmac_reset_and_enable(dev);
enable_irq(dev->irq);
- enable_irq(bp->tx_dma_intr);
- enable_irq(bp->rx_dma_intr);
- netif_device_attach(dev);
+ enable_irq(bp->tx_dma_intr);
+ enable_irq(bp->rx_dma_intr);
+ netif_device_attach(dev);
return 0;
}
@@ -1599,7 +1599,7 @@ static int bmac_remove(struct macio_dev *mdev)
unregister_netdev(dev);
- free_irq(dev->irq, dev);
+ free_irq(dev->irq, dev);
free_irq(bp->tx_dma_intr, dev);
free_irq(bp->rx_dma_intr, dev);
diff --git a/drivers/net/ethernet/apple/mace.c b/drivers/net/ethernet/apple/mace.c
index 9e5006e59215..4b80e3a52a19 100644
--- a/drivers/net/ethernet/apple/mace.c
+++ b/drivers/net/ethernet/apple/mace.c
@@ -364,9 +364,9 @@ static void mace_reset(struct net_device *dev)
out_8(&mb->iac, 0);
if (mp->port_aaui)
- out_8(&mb->plscc, PORTSEL_AUI + ENPLSIO);
+ out_8(&mb->plscc, PORTSEL_AUI + ENPLSIO);
else
- out_8(&mb->plscc, PORTSEL_GPSI + ENPLSIO);
+ out_8(&mb->plscc, PORTSEL_GPSI + ENPLSIO);
}
static void __mace_set_address(struct net_device *dev, void *addr)
@@ -378,9 +378,9 @@ static void __mace_set_address(struct net_device *dev, void *addr)
/* load up the hardware address */
if (mp->chipid == BROKEN_ADDRCHG_REV)
- out_8(&mb->iac, PHYADDR);
+ out_8(&mb->iac, PHYADDR);
else {
- out_8(&mb->iac, ADDRCHG | PHYADDR);
+ out_8(&mb->iac, ADDRCHG | PHYADDR);
while ((in_8(&mb->iac) & ADDRCHG) != 0)
;
}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_macsec.h b/drivers/net/ethernet/aquantia/atlantic/aq_macsec.h
index f5fba8b8cdea..a47e2710487e 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_macsec.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_macsec.h
@@ -91,7 +91,7 @@ struct aq_macsec_txsc {
u32 hw_sc_idx;
unsigned long tx_sa_idx_busy;
const struct macsec_secy *sw_secy;
- u8 tx_sa_key[MACSEC_NUM_AN][MACSEC_KEYID_LEN];
+ u8 tx_sa_key[MACSEC_NUM_AN][MACSEC_MAX_KEY_LEN];
struct aq_macsec_tx_sc_stats stats;
struct aq_macsec_tx_sa_stats tx_sa_stats[MACSEC_NUM_AN];
};
@@ -101,7 +101,7 @@ struct aq_macsec_rxsc {
unsigned long rx_sa_idx_busy;
const struct macsec_secy *sw_secy;
const struct macsec_rx_sc *sw_rxsc;
- u8 rx_sa_key[MACSEC_NUM_AN][MACSEC_KEYID_LEN];
+ u8 rx_sa_key[MACSEC_NUM_AN][MACSEC_MAX_KEY_LEN];
struct aq_macsec_rx_sa_stats rx_sa_stats[MACSEC_NUM_AN];
};
diff --git a/drivers/net/ethernet/arc/emac_rockchip.c b/drivers/net/ethernet/arc/emac_rockchip.c
index 48ecdf15eddc..1c9ca3bcb871 100644
--- a/drivers/net/ethernet/arc/emac_rockchip.c
+++ b/drivers/net/ethernet/arc/emac_rockchip.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-/**
+/*
* emac-rockchip.c - Rockchip EMAC specific glue layer
*
* Copyright (C) 2014 Romain Perier <romain.perier@gmail.com>
diff --git a/drivers/net/ethernet/atheros/alx/alx.h b/drivers/net/ethernet/atheros/alx/alx.h
index 9d0e74f6b089..693006c5a498 100644
--- a/drivers/net/ethernet/atheros/alx/alx.h
+++ b/drivers/net/ethernet/atheros/alx/alx.h
@@ -137,6 +137,8 @@ struct alx_priv {
/* protects hw.stats */
spinlock_t stats_lock;
+
+ struct mutex mtx;
};
extern const struct ethtool_ops alx_ethtool_ops;
diff --git a/drivers/net/ethernet/atheros/alx/ethtool.c b/drivers/net/ethernet/atheros/alx/ethtool.c
index 2f4eabf652e8..b716adacd815 100644
--- a/drivers/net/ethernet/atheros/alx/ethtool.c
+++ b/drivers/net/ethernet/atheros/alx/ethtool.c
@@ -163,8 +163,10 @@ static int alx_get_link_ksettings(struct net_device *netdev,
}
}
+ mutex_lock(&alx->mtx);
cmd->base.speed = hw->link_speed;
cmd->base.duplex = hw->duplex;
+ mutex_unlock(&alx->mtx);
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
supported);
@@ -181,8 +183,7 @@ static int alx_set_link_ksettings(struct net_device *netdev,
struct alx_hw *hw = &alx->hw;
u32 adv_cfg;
u32 advertising;
-
- ASSERT_RTNL();
+ int ret;
ethtool_convert_link_mode_to_legacy_u32(&advertising,
cmd->link_modes.advertising);
@@ -200,7 +201,12 @@ static int alx_set_link_ksettings(struct net_device *netdev,
}
hw->adv_cfg = adv_cfg;
- return alx_setup_speed_duplex(hw, adv_cfg, hw->flowctrl);
+
+ mutex_lock(&alx->mtx);
+ ret = alx_setup_speed_duplex(hw, adv_cfg, hw->flowctrl);
+ mutex_unlock(&alx->mtx);
+
+ return ret;
}
static void alx_get_pauseparam(struct net_device *netdev,
@@ -209,10 +215,12 @@ static void alx_get_pauseparam(struct net_device *netdev,
struct alx_priv *alx = netdev_priv(netdev);
struct alx_hw *hw = &alx->hw;
+ mutex_lock(&alx->mtx);
pause->autoneg = !!(hw->flowctrl & ALX_FC_ANEG &&
hw->adv_cfg & ADVERTISED_Autoneg);
pause->tx_pause = !!(hw->flowctrl & ALX_FC_TX);
pause->rx_pause = !!(hw->flowctrl & ALX_FC_RX);
+ mutex_unlock(&alx->mtx);
}
@@ -232,7 +240,7 @@ static int alx_set_pauseparam(struct net_device *netdev,
if (pause->autoneg)
fc |= ALX_FC_ANEG;
- ASSERT_RTNL();
+ mutex_lock(&alx->mtx);
/* restart auto-neg for auto-mode */
if (hw->adv_cfg & ADVERTISED_Autoneg) {
@@ -245,8 +253,10 @@ static int alx_set_pauseparam(struct net_device *netdev,
if (reconfig_phy) {
err = alx_setup_speed_duplex(hw, hw->adv_cfg, fc);
- if (err)
+ if (err) {
+ mutex_unlock(&alx->mtx);
return err;
+ }
}
/* flow control on mac */
@@ -254,6 +264,7 @@ static int alx_set_pauseparam(struct net_device *netdev,
alx_cfg_mac_flowcontrol(hw, fc);
hw->flowctrl = fc;
+ mutex_unlock(&alx->mtx);
return 0;
}
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
index 7748b276e5fd..11ef1fbe7aee 100644
--- a/drivers/net/ethernet/atheros/alx/main.c
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2013, 2021 Johannes Berg <johannes@sipsolutions.net>
*
* This file is free software: you may copy, redistribute and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -1091,8 +1091,9 @@ static int alx_init_sw(struct alx_priv *alx)
ALX_MAC_CTRL_RXFC_EN |
ALX_MAC_CTRL_TXFC_EN |
7 << ALX_MAC_CTRL_PRMBLEN_SHIFT;
+ mutex_init(&alx->mtx);
- return err;
+ return 0;
}
@@ -1122,6 +1123,8 @@ static void alx_halt(struct alx_priv *alx)
{
struct alx_hw *hw = &alx->hw;
+ lockdep_assert_held(&alx->mtx);
+
alx_netif_stop(alx);
hw->link_speed = SPEED_UNKNOWN;
hw->duplex = DUPLEX_UNKNOWN;
@@ -1147,6 +1150,8 @@ static void alx_configure(struct alx_priv *alx)
static void alx_activate(struct alx_priv *alx)
{
+ lockdep_assert_held(&alx->mtx);
+
/* hardware setting lost, restore it */
alx_reinit_rings(alx);
alx_configure(alx);
@@ -1161,7 +1166,7 @@ static void alx_activate(struct alx_priv *alx)
static void alx_reinit(struct alx_priv *alx)
{
- ASSERT_RTNL();
+ lockdep_assert_held(&alx->mtx);
alx_halt(alx);
alx_activate(alx);
@@ -1249,6 +1254,8 @@ out_disable_adv_intr:
static void __alx_stop(struct alx_priv *alx)
{
+ lockdep_assert_held(&alx->mtx);
+
alx_free_irq(alx);
cancel_work_sync(&alx->link_check_wk);
@@ -1284,6 +1291,8 @@ static void alx_check_link(struct alx_priv *alx)
int old_speed;
int err;
+ lockdep_assert_held(&alx->mtx);
+
/* clear PHY internal interrupt status, otherwise the main
* interrupt status will be asserted forever
*/
@@ -1338,12 +1347,24 @@ reset:
static int alx_open(struct net_device *netdev)
{
- return __alx_open(netdev_priv(netdev), false);
+ struct alx_priv *alx = netdev_priv(netdev);
+ int ret;
+
+ mutex_lock(&alx->mtx);
+ ret = __alx_open(alx, false);
+ mutex_unlock(&alx->mtx);
+
+ return ret;
}
static int alx_stop(struct net_device *netdev)
{
- __alx_stop(netdev_priv(netdev));
+ struct alx_priv *alx = netdev_priv(netdev);
+
+ mutex_lock(&alx->mtx);
+ __alx_stop(alx);
+ mutex_unlock(&alx->mtx);
+
return 0;
}
@@ -1353,18 +1374,18 @@ static void alx_link_check(struct work_struct *work)
alx = container_of(work, struct alx_priv, link_check_wk);
- rtnl_lock();
+ mutex_lock(&alx->mtx);
alx_check_link(alx);
- rtnl_unlock();
+ mutex_unlock(&alx->mtx);
}
static void alx_reset(struct work_struct *work)
{
struct alx_priv *alx = container_of(work, struct alx_priv, reset_wk);
- rtnl_lock();
+ mutex_lock(&alx->mtx);
alx_reinit(alx);
- rtnl_unlock();
+ mutex_unlock(&alx->mtx);
}
static int alx_tpd_req(struct sk_buff *skb)
@@ -1771,6 +1792,8 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_unmap;
}
+ mutex_lock(&alx->mtx);
+
alx_reset_pcie(hw);
phy_configured = alx_phy_configured(hw);
@@ -1781,7 +1804,7 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = alx_reset_mac(hw);
if (err) {
dev_err(&pdev->dev, "MAC Reset failed, error = %d\n", err);
- goto out_unmap;
+ goto out_unlock;
}
/* setup link to put it in a known good starting state */
@@ -1791,7 +1814,7 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_err(&pdev->dev,
"failed to configure PHY speed/duplex (err=%d)\n",
err);
- goto out_unmap;
+ goto out_unlock;
}
}
@@ -1824,9 +1847,11 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!alx_get_phy_info(hw)) {
dev_err(&pdev->dev, "failed to identify PHY\n");
err = -EIO;
- goto out_unmap;
+ goto out_unlock;
}
+ mutex_unlock(&alx->mtx);
+
INIT_WORK(&alx->link_check_wk, alx_link_check);
INIT_WORK(&alx->reset_wk, alx_reset);
netif_carrier_off(netdev);
@@ -1843,6 +1868,8 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
+out_unlock:
+ mutex_unlock(&alx->mtx);
out_unmap:
iounmap(hw->hw_addr);
out_free_netdev:
@@ -1870,6 +1897,8 @@ static void alx_remove(struct pci_dev *pdev)
pci_disable_pcie_error_reporting(pdev);
pci_disable_device(pdev);
+ mutex_destroy(&alx->mtx);
+
free_netdev(alx->dev);
}
@@ -1881,7 +1910,11 @@ static int alx_suspend(struct device *dev)
if (!netif_running(alx->dev))
return 0;
netif_device_detach(alx->dev);
+
+ mutex_lock(&alx->mtx);
__alx_stop(alx);
+ mutex_unlock(&alx->mtx);
+
return 0;
}
@@ -1891,20 +1924,23 @@ static int alx_resume(struct device *dev)
struct alx_hw *hw = &alx->hw;
int err;
+ mutex_lock(&alx->mtx);
alx_reset_phy(hw);
- if (!netif_running(alx->dev))
- return 0;
+ if (!netif_running(alx->dev)) {
+ err = 0;
+ goto unlock;
+ }
- rtnl_lock();
err = __alx_open(alx, true);
- rtnl_unlock();
if (err)
- return err;
+ goto unlock;
netif_device_attach(alx->dev);
- return 0;
+unlock:
+ mutex_unlock(&alx->mtx);
+ return err;
}
static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume);
@@ -1923,7 +1959,7 @@ static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev,
dev_info(&pdev->dev, "pci error detected\n");
- rtnl_lock();
+ mutex_lock(&alx->mtx);
if (netif_running(netdev)) {
netif_device_detach(netdev);
@@ -1935,7 +1971,7 @@ static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev,
else
pci_disable_device(pdev);
- rtnl_unlock();
+ mutex_unlock(&alx->mtx);
return rc;
}
@@ -1948,7 +1984,7 @@ static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev)
dev_info(&pdev->dev, "pci error slot reset\n");
- rtnl_lock();
+ mutex_lock(&alx->mtx);
if (pci_enable_device(pdev)) {
dev_err(&pdev->dev, "Failed to re-enable PCI device after reset\n");
@@ -1961,7 +1997,7 @@ static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev)
if (!alx_reset_mac(hw))
rc = PCI_ERS_RESULT_RECOVERED;
out:
- rtnl_unlock();
+ mutex_unlock(&alx->mtx);
return rc;
}
@@ -1973,14 +2009,14 @@ static void alx_pci_error_resume(struct pci_dev *pdev)
dev_info(&pdev->dev, "pci error resume\n");
- rtnl_lock();
+ mutex_lock(&alx->mtx);
if (netif_running(netdev)) {
alx_activate(alx);
netif_device_attach(netdev);
}
- rtnl_unlock();
+ mutex_unlock(&alx->mtx);
}
static const struct pci_error_handlers alx_err_handlers = {
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c.h b/drivers/net/ethernet/atheros/atl1c/atl1c.h
index 28ae5c16831e..43d821fe7a54 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c.h
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c.h
@@ -63,7 +63,7 @@
#define AT_MAX_RECEIVE_QUEUE 4
#define AT_DEF_RECEIVE_QUEUE 1
-#define AT_MAX_TRANSMIT_QUEUE 2
+#define AT_MAX_TRANSMIT_QUEUE 4
#define AT_DMA_HI_ADDR_MASK 0xffffffff00000000ULL
#define AT_DMA_LO_ADDR_MASK 0x00000000ffffffffULL
@@ -241,6 +241,8 @@ struct atl1c_tpd_ext_desc {
#define RRS_PACKET_PROT_IS_IPV6_ONLY(word) \
((((word) >> RRS_PROT_ID_SHIFT) & RRS_PROT_ID_MASK) == 6)
+#define RRS_MT_PROT_ID_TCPUDP BIT(19)
+
struct atl1c_recv_ret_status {
__le32 word0;
__le32 rss_hash;
@@ -289,11 +291,7 @@ enum atl1c_nic_type {
athr_l2c_b2,
athr_l1d,
athr_l1d_2,
-};
-
-enum atl1c_trans_queue {
- atl1c_trans_normal = 0,
- atl1c_trans_high = 1
+ athr_mt,
};
struct atl1c_hw_stats {
@@ -472,13 +470,16 @@ struct atl1c_buffer {
/* transimit packet descriptor (tpd) ring */
struct atl1c_tpd_ring {
+ struct atl1c_adapter *adapter;
void *desc; /* descriptor ring virtual address */
dma_addr_t dma; /* descriptor ring physical address */
+ u16 num;
u16 size; /* descriptor ring length in bytes */
u16 count; /* number of descriptors in the ring */
u16 next_to_use;
atomic_t next_to_clean;
struct atl1c_buffer *buffer_info;
+ struct napi_struct napi;
};
/* receive free descriptor (rfd) ring */
@@ -494,27 +495,30 @@ struct atl1c_rfd_ring {
/* receive return descriptor (rrd) ring */
struct atl1c_rrd_ring {
+ struct atl1c_adapter *adapter;
void *desc; /* descriptor ring virtual address */
dma_addr_t dma; /* descriptor ring physical address */
+ u16 num;
u16 size; /* descriptor ring length in bytes */
u16 count; /* number of descriptors in the ring */
u16 next_to_use;
u16 next_to_clean;
+ struct napi_struct napi;
+ struct page *rx_page;
+ unsigned int rx_page_offset;
};
/* board specific private data structure */
struct atl1c_adapter {
struct net_device *netdev;
struct pci_dev *pdev;
- struct napi_struct napi;
- struct napi_struct tx_napi;
- struct page *rx_page;
- unsigned int rx_page_offset;
unsigned int rx_frag_size;
struct atl1c_hw hw;
struct atl1c_hw_stats hw_stats;
struct mii_if_info mii; /* MII interface info */
u16 rx_buffer_len;
+ unsigned int tx_queue_count;
+ unsigned int rx_queue_count;
unsigned long flags;
#define __AT_TESTING 0x0001
@@ -540,8 +544,8 @@ struct atl1c_adapter {
/* All Descriptor memory */
struct atl1c_ring_header ring_header;
struct atl1c_tpd_ring tpd_ring[AT_MAX_TRANSMIT_QUEUE];
- struct atl1c_rfd_ring rfd_ring;
- struct atl1c_rrd_ring rrd_ring;
+ struct atl1c_rfd_ring rfd_ring[AT_MAX_RECEIVE_QUEUE];
+ struct atl1c_rrd_ring rrd_ring[AT_MAX_RECEIVE_QUEUE];
u32 bd_number; /* board number;*/
};
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
index 140358dcf61e..f19370c33444 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
@@ -594,6 +594,11 @@ int atl1c_phy_init(struct atl1c_hw *hw)
int ret_val;
u16 mii_bmcr_data = BMCR_RESET;
+ if (hw->nic_type == athr_mt) {
+ hw->phy_configured = true;
+ return 0;
+ }
+
if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id1) != 0) ||
(atl1c_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id2) != 0)) {
dev_err(&pdev->dev, "Error get phy ID\n");
@@ -636,6 +641,23 @@ int atl1c_phy_init(struct atl1c_hw *hw)
return 0;
}
+bool atl1c_get_link_status(struct atl1c_hw *hw)
+{
+ u16 phy_data;
+
+ if (hw->nic_type == athr_mt) {
+ u32 spd;
+
+ AT_READ_REG(hw, REG_MT_SPEED, &spd);
+ return !!spd;
+ }
+
+ /* MII_BMSR must be read twice */
+ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+ return !!(phy_data & BMSR_LSTATUS);
+}
+
/*
* Detects the current speed and duplex settings of the hardware.
*
@@ -648,6 +670,15 @@ int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex)
int err;
u16 phy_data;
+ if (hw->nic_type == athr_mt) {
+ u32 spd;
+
+ AT_READ_REG(hw, REG_MT_SPEED, &spd);
+ *speed = spd;
+ *duplex = FULL_DUPLEX;
+ return 0;
+ }
+
/* Read PHY Specific Status Register (17) */
err = atl1c_read_phy_reg(hw, MII_GIGA_PSSR, &phy_data);
if (err)
@@ -686,15 +717,12 @@ int atl1c_phy_to_ps_link(struct atl1c_hw *hw)
int ret = 0;
u16 autoneg_advertised = ADVERTISED_10baseT_Half;
u16 save_autoneg_advertised;
- u16 phy_data;
u16 mii_lpa_data;
u16 speed = SPEED_0;
u16 duplex = FULL_DUPLEX;
int i;
- atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
- atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
- if (phy_data & BMSR_LSTATUS) {
+ if (atl1c_get_link_status(hw)) {
atl1c_read_phy_reg(hw, MII_LPA, &mii_lpa_data);
if (mii_lpa_data & LPA_10FULL)
autoneg_advertised = ADVERTISED_10baseT_Full;
@@ -717,9 +745,7 @@ int atl1c_phy_to_ps_link(struct atl1c_hw *hw)
if (mii_lpa_data) {
for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
mdelay(100);
- atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
- atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
- if (phy_data & BMSR_LSTATUS) {
+ if (atl1c_get_link_status(hw)) {
if (atl1c_get_speed_and_duplex(hw, &speed,
&duplex) != 0)
dev_dbg(&pdev->dev,
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
index ce1a123dce2c..c567c920628f 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
@@ -26,6 +26,7 @@ void atl1c_phy_disable(struct atl1c_hw *hw);
void atl1c_hw_set_mac_addr(struct atl1c_hw *hw, u8 *mac_addr);
int atl1c_phy_reset(struct atl1c_hw *hw);
int atl1c_read_mac_addr(struct atl1c_hw *hw);
+bool atl1c_get_link_status(struct atl1c_hw *hw);
int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex);
u32 atl1c_hash_mc_addr(struct atl1c_hw *hw, u8 *mc_addr);
void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value);
@@ -527,15 +528,24 @@ void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed);
#define REG_RX_BASE_ADDR_HI 0x1540
#define REG_TX_BASE_ADDR_HI 0x1544
#define REG_RFD0_HEAD_ADDR_LO 0x1550
+#define REG_RFD1_HEAD_ADDR_LO 0x1554
+#define REG_RFD2_HEAD_ADDR_LO 0x1558
+#define REG_RFD3_HEAD_ADDR_LO 0x155C
#define REG_RFD_RING_SIZE 0x1560
#define RFD_RING_SIZE_MASK 0x0FFF
#define REG_RX_BUF_SIZE 0x1564
#define RX_BUF_SIZE_MASK 0xFFFF
#define REG_RRD0_HEAD_ADDR_LO 0x1568
+#define REG_RRD1_HEAD_ADDR_LO 0x156C
+#define REG_RRD2_HEAD_ADDR_LO 0x1570
+#define REG_RRD3_HEAD_ADDR_LO 0x1574
#define REG_RRD_RING_SIZE 0x1578
#define RRD_RING_SIZE_MASK 0x0FFF
#define REG_TPD_PRI1_ADDR_LO 0x157C
#define REG_TPD_PRI0_ADDR_LO 0x1580
+#define REG_TPD_PRI2_ADDR_LO 0x1F10
+#define REG_TPD_PRI3_ADDR_LO 0x1F14
+
#define REG_TPD_RING_SIZE 0x1584
#define TPD_RING_SIZE_MASK 0xFFFF
@@ -654,15 +664,26 @@ void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed);
/* Mail box */
#define MB_RFDX_PROD_IDX_MASK 0xFFFF
#define REG_MB_RFD0_PROD_IDX 0x15E0
+#define REG_MB_RFD1_PROD_IDX 0x15E4
+#define REG_MB_RFD2_PROD_IDX 0x15E8
+#define REG_MB_RFD3_PROD_IDX 0x15EC
#define REG_TPD_PRI1_PIDX 0x15F0 /* 16bit,hi-tpd producer idx */
#define REG_TPD_PRI0_PIDX 0x15F2 /* 16bit,lo-tpd producer idx */
#define REG_TPD_PRI1_CIDX 0x15F4 /* 16bit,hi-tpd consumer idx */
#define REG_TPD_PRI0_CIDX 0x15F6 /* 16bit,lo-tpd consumer idx */
+#define REG_TPD_PRI3_PIDX 0x1F18
+#define REG_TPD_PRI2_PIDX 0x1F1A
+#define REG_TPD_PRI3_CIDX 0x1F1C
+#define REG_TPD_PRI2_CIDX 0x1F1E
+
#define REG_MB_RFD01_CONS_IDX 0x15F8
#define MB_RFD0_CONS_IDX_MASK 0x0000FFFF
#define MB_RFD1_CONS_IDX_MASK 0xFFFF0000
+#define REG_MB_RFD23_CONS_IDX 0x15FC
+#define MB_RFD2_CONS_IDX_MASK 0x0000FFFF
+#define MB_RFD3_CONS_IDX_MASK 0xFFFF0000
/* Interrupt Status Register */
#define REG_ISR 0x1600
@@ -686,7 +707,7 @@ void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed);
/* GPHY low power state interrupt */
#define ISR_GPHY_LPW 0x00002000
#define ISR_TXQ_TO_RST 0x00004000
-#define ISR_TX_PKT 0x00008000
+#define ISR_TX_PKT_0 0x00008000
#define ISR_RX_PKT_0 0x00010000
#define ISR_RX_PKT_1 0x00020000
#define ISR_RX_PKT_2 0x00040000
@@ -698,6 +719,9 @@ void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed);
#define ISR_NFERR_DETECTED 0x01000000
#define ISR_CERR_DETECTED 0x02000000
#define ISR_PHY_LINKDOWN 0x04000000
+#define ISR_TX_PKT_1 0x10000000
+#define ISR_TX_PKT_2 0x20000000
+#define ISR_TX_PKT_3 0x40000000
#define ISR_DIS_INT 0x80000000
/* Interrupt Mask Register */
@@ -712,11 +736,15 @@ void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed);
ISR_TXQ_TO_RST |\
ISR_DMAW_TO_RST |\
ISR_GPHY |\
- ISR_TX_PKT |\
- ISR_RX_PKT_0 |\
ISR_GPHY_LPW |\
ISR_PHY_LINKDOWN)
+#define ISR_TX_PKT ( \
+ ISR_TX_PKT_0 | \
+ ISR_TX_PKT_1 | \
+ ISR_TX_PKT_2 | \
+ ISR_TX_PKT_3)
+
#define ISR_RX_PKT (\
ISR_RX_PKT_0 |\
ISR_RX_PKT_1 |\
@@ -764,6 +792,14 @@ void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed);
#define REG_DEBUG_DATA0 0x1900
#define REG_DEBUG_DATA1 0x1904
+#define REG_MT_MAGIC 0x1F00
+#define REG_MT_MODE 0x1F04
+#define REG_MT_SPEED 0x1F08
+#define REG_MT_VERSION 0x1F0C
+
+#define MT_MAGIC 0xaabb1234
+#define MT_MODE_4Q BIT(0)
+
#define L1D_MPW_PHYID1 0xD01C /* V7 */
#define L1D_MPW_PHYID2 0xD01D /* V1-V6 */
#define L1D_MPW_PHYID3 0xD01E /* V8 */
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index c6263cf8d3c0..1c6246a5dc22 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -36,18 +36,51 @@ MODULE_AUTHOR("Qualcomm Atheros Inc.");
MODULE_DESCRIPTION("Qualcomm Atheros 100/1000M Ethernet Network Driver");
MODULE_LICENSE("GPL");
+struct atl1c_qregs {
+ u16 tpd_addr_lo;
+ u16 tpd_prod;
+ u16 tpd_cons;
+ u16 rfd_addr_lo;
+ u16 rrd_addr_lo;
+ u16 rfd_prod;
+ u32 tx_isr;
+ u32 rx_isr;
+};
+
+static struct atl1c_qregs atl1c_qregs[AT_MAX_TRANSMIT_QUEUE] = {
+ {
+ REG_TPD_PRI0_ADDR_LO, REG_TPD_PRI0_PIDX, REG_TPD_PRI0_CIDX,
+ REG_RFD0_HEAD_ADDR_LO, REG_RRD0_HEAD_ADDR_LO,
+ REG_MB_RFD0_PROD_IDX, ISR_TX_PKT_0, ISR_RX_PKT_0
+ },
+ {
+ REG_TPD_PRI1_ADDR_LO, REG_TPD_PRI1_PIDX, REG_TPD_PRI1_CIDX,
+ REG_RFD1_HEAD_ADDR_LO, REG_RRD1_HEAD_ADDR_LO,
+ REG_MB_RFD1_PROD_IDX, ISR_TX_PKT_1, ISR_RX_PKT_1
+ },
+ {
+ REG_TPD_PRI2_ADDR_LO, REG_TPD_PRI2_PIDX, REG_TPD_PRI2_CIDX,
+ REG_RFD2_HEAD_ADDR_LO, REG_RRD2_HEAD_ADDR_LO,
+ REG_MB_RFD2_PROD_IDX, ISR_TX_PKT_2, ISR_RX_PKT_2
+ },
+ {
+ REG_TPD_PRI3_ADDR_LO, REG_TPD_PRI3_PIDX, REG_TPD_PRI3_CIDX,
+ REG_RFD3_HEAD_ADDR_LO, REG_RRD3_HEAD_ADDR_LO,
+ REG_MB_RFD3_PROD_IDX, ISR_TX_PKT_3, ISR_RX_PKT_3
+ },
+};
+
static int atl1c_stop_mac(struct atl1c_hw *hw);
static void atl1c_disable_l0s_l1(struct atl1c_hw *hw);
static void atl1c_set_aspm(struct atl1c_hw *hw, u16 link_speed);
static void atl1c_start_mac(struct atl1c_adapter *adapter);
-static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter,
- int *work_done, int work_to_do);
static int atl1c_up(struct atl1c_adapter *adapter);
static void atl1c_down(struct atl1c_adapter *adapter);
static int atl1c_reset_mac(struct atl1c_hw *hw);
static void atl1c_reset_dma_ring(struct atl1c_adapter *adapter);
static int atl1c_configure(struct atl1c_adapter *adapter);
-static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, bool napi_mode);
+static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, u32 queue,
+ bool napi_mode);
static const u32 atl1c_default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE |
@@ -232,15 +265,14 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
struct pci_dev *pdev = adapter->pdev;
int err;
unsigned long flags;
- u16 speed, duplex, phy_data;
+ u16 speed, duplex;
+ bool link;
spin_lock_irqsave(&adapter->mdio_lock, flags);
- /* MII_BMSR must read twise */
- atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
- atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+ link = atl1c_get_link_status(hw);
spin_unlock_irqrestore(&adapter->mdio_lock, flags);
- if ((phy_data & BMSR_LSTATUS) == 0) {
+ if (!link) {
/* link down */
netif_carrier_off(netdev);
hw->hibernate = true;
@@ -284,16 +316,13 @@ static void atl1c_link_chg_event(struct atl1c_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
- u16 phy_data;
- u16 link_up;
+ bool link;
spin_lock(&adapter->mdio_lock);
- atl1c_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
- atl1c_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+ link = atl1c_get_link_status(&adapter->hw);
spin_unlock(&adapter->mdio_lock);
- link_up = phy_data & BMSR_LSTATUS;
/* notify upper layer link down ASAP */
- if (!link_up) {
+ if (!link) {
if (netif_carrier_ok(netdev)) {
/* old link state: Up */
netif_carrier_off(netdev);
@@ -436,7 +465,7 @@ static void atl1c_restore_vlan(struct atl1c_adapter *adapter)
}
/**
- * atl1c_set_mac - Change the Ethernet Address of the NIC
+ * atl1c_set_mac_addr - Change the Ethernet Address of the NIC
* @netdev: network interface device structure
* @p: pointer to an address structure
*
@@ -478,6 +507,9 @@ static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
static netdev_features_t atl1c_fix_features(struct net_device *netdev,
netdev_features_t features)
{
+ struct atl1c_adapter *adapter = netdev_priv(netdev);
+ struct atl1c_hw *hw = &adapter->hw;
+
/*
* Since there is no support for separate rx/tx vlan accel
* enable/disable make sure tx flag is always in same state as rx.
@@ -487,8 +519,10 @@ static netdev_features_t atl1c_fix_features(struct net_device *netdev,
else
features &= ~NETIF_F_HW_VLAN_CTAG_TX;
- if (netdev->mtu > MAX_TSO_FRAME_SIZE)
- features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+ if (hw->nic_type != athr_mt) {
+ if (netdev->mtu > MAX_TSO_FRAME_SIZE)
+ features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+ }
return features;
}
@@ -515,9 +549,12 @@ static void atl1c_set_max_mtu(struct net_device *netdev)
case athr_l1d:
case athr_l1d_2:
netdev->max_mtu = MAX_JUMBO_FRAME_SIZE -
- (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
+ (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
+ break;
+ case athr_mt:
+ netdev->max_mtu = 9500;
break;
- /* The 10/100 devices don't support jumbo packets, max_mtu 1500 */
+ /* The 10/100 devices don't support jumbo packets, max_mtu 1500 */
default:
netdev->max_mtu = ETH_DATA_LEN;
break;
@@ -642,29 +679,26 @@ static int atl1c_alloc_queues(struct atl1c_adapter *adapter)
return 0;
}
-static void atl1c_set_mac_type(struct atl1c_hw *hw)
+static enum atl1c_nic_type atl1c_get_mac_type(struct pci_dev *pdev,
+ u8 __iomem *hw_addr)
{
- switch (hw->device_id) {
+ switch (pdev->device) {
case PCI_DEVICE_ID_ATTANSIC_L2C:
- hw->nic_type = athr_l2c;
- break;
+ return athr_l2c;
case PCI_DEVICE_ID_ATTANSIC_L1C:
- hw->nic_type = athr_l1c;
- break;
+ return athr_l1c;
case PCI_DEVICE_ID_ATHEROS_L2C_B:
- hw->nic_type = athr_l2c_b;
- break;
+ return athr_l2c_b;
case PCI_DEVICE_ID_ATHEROS_L2C_B2:
- hw->nic_type = athr_l2c_b2;
- break;
+ return athr_l2c_b2;
case PCI_DEVICE_ID_ATHEROS_L1D:
- hw->nic_type = athr_l1d;
- break;
+ return athr_l1d;
case PCI_DEVICE_ID_ATHEROS_L1D_2_0:
- hw->nic_type = athr_l1d_2;
- break;
+ if (readl(hw_addr + REG_MT_MAGIC) == MT_MAGIC)
+ return athr_mt;
+ return athr_l1d_2;
default:
- break;
+ return athr_l1c;
}
}
@@ -672,7 +706,6 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
{
u32 link_ctrl_data;
- atl1c_set_mac_type(hw);
AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data);
hw->ctrl_flags = ATL1C_INTR_MODRT_ENABLE |
@@ -763,14 +796,14 @@ static int atl1c_sw_init(struct atl1c_adapter *adapter)
struct atl1c_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
u32 revision;
-
+ int i;
adapter->wol = 0;
device_set_wakeup_enable(&pdev->dev, false);
adapter->link_speed = SPEED_0;
adapter->link_duplex = FULL_DUPLEX;
adapter->tpd_ring[0].count = 1024;
- adapter->rfd_ring.count = 512;
+ adapter->rfd_ring[0].count = 512;
hw->vendor_id = pdev->vendor;
hw->device_id = pdev->device;
@@ -788,6 +821,10 @@ static int atl1c_sw_init(struct atl1c_adapter *adapter)
atl1c_patch_assign(hw);
hw->intr_mask = IMR_NORMAL_MASK;
+ for (i = 0; i < adapter->tx_queue_count; ++i)
+ hw->intr_mask |= atl1c_qregs[i].tx_isr;
+ for (i = 0; i < adapter->rx_queue_count; ++i)
+ hw->intr_mask |= atl1c_qregs[i].rx_isr;
hw->phy_configured = false;
hw->preamble_len = 7;
hw->max_frame_size = adapter->netdev->mtu;
@@ -847,12 +884,12 @@ static inline void atl1c_clean_buffer(struct pci_dev *pdev,
/**
* atl1c_clean_tx_ring - Free Tx-skb
* @adapter: board private structure
- * @type: type of transmit queue
+ * @queue: idx of transmit queue
*/
static void atl1c_clean_tx_ring(struct atl1c_adapter *adapter,
- enum atl1c_trans_queue type)
+ u32 queue)
{
- struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
+ struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[queue];
struct atl1c_buffer *buffer_info;
struct pci_dev *pdev = adapter->pdev;
u16 index, ring_count;
@@ -875,11 +912,12 @@ static void atl1c_clean_tx_ring(struct atl1c_adapter *adapter,
/**
* atl1c_clean_rx_ring - Free rx-reservation skbs
* @adapter: board private structure
+ * @queue: idx of transmit queue
*/
-static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter)
+static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter, u32 queue)
{
- struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring;
- struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring[queue];
+ struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring[queue];
struct atl1c_buffer *buffer_info;
struct pci_dev *pdev = adapter->pdev;
int j;
@@ -902,26 +940,28 @@ static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter)
static void atl1c_init_ring_ptrs(struct atl1c_adapter *adapter)
{
struct atl1c_tpd_ring *tpd_ring = adapter->tpd_ring;
- struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring;
- struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1c_rfd_ring *rfd_ring = adapter->rfd_ring;
+ struct atl1c_rrd_ring *rrd_ring = adapter->rrd_ring;
struct atl1c_buffer *buffer_info;
int i, j;
- for (i = 0; i < AT_MAX_TRANSMIT_QUEUE; i++) {
+ for (i = 0; i < adapter->tx_queue_count; i++) {
tpd_ring[i].next_to_use = 0;
atomic_set(&tpd_ring[i].next_to_clean, 0);
buffer_info = tpd_ring[i].buffer_info;
for (j = 0; j < tpd_ring->count; j++)
ATL1C_SET_BUFFER_STATE(&buffer_info[i],
- ATL1C_BUFFER_FREE);
- }
- rfd_ring->next_to_use = 0;
- rfd_ring->next_to_clean = 0;
- rrd_ring->next_to_use = 0;
- rrd_ring->next_to_clean = 0;
- for (j = 0; j < rfd_ring->count; j++) {
- buffer_info = &rfd_ring->buffer_info[j];
- ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE);
+ ATL1C_BUFFER_FREE);
+ }
+ for (i = 0; i < adapter->rx_queue_count; i++) {
+ rfd_ring[i].next_to_use = 0;
+ rfd_ring[i].next_to_clean = 0;
+ rrd_ring[i].next_to_use = 0;
+ rrd_ring[i].next_to_clean = 0;
+ for (j = 0; j < rfd_ring[i].count; j++) {
+ buffer_info = &rfd_ring[i].buffer_info[j];
+ ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE);
+ }
}
}
@@ -934,25 +974,29 @@ static void atl1c_init_ring_ptrs(struct atl1c_adapter *adapter)
static void atl1c_free_ring_resources(struct atl1c_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
+ int i;
dma_free_coherent(&pdev->dev, adapter->ring_header.size,
adapter->ring_header.desc, adapter->ring_header.dma);
adapter->ring_header.desc = NULL;
/* Note: just free tdp_ring.buffer_info,
- * it contain rfd_ring.buffer_info, do not double free */
+ * it contain rfd_ring.buffer_info, do not double free
+ */
if (adapter->tpd_ring[0].buffer_info) {
kfree(adapter->tpd_ring[0].buffer_info);
adapter->tpd_ring[0].buffer_info = NULL;
}
- if (adapter->rx_page) {
- put_page(adapter->rx_page);
- adapter->rx_page = NULL;
+ for (i = 0; i < adapter->rx_queue_count; ++i) {
+ if (adapter->rrd_ring[i].rx_page) {
+ put_page(adapter->rrd_ring[i].rx_page);
+ adapter->rrd_ring[i].rx_page = NULL;
+ }
}
}
/**
- * atl1c_setup_mem_resources - allocate Tx / RX descriptor resources
+ * atl1c_setup_ring_resources - allocate Tx / RX descriptor resources
* @adapter: board private structure
*
* Return 0 on success, negative on failure
@@ -961,37 +1005,46 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
struct atl1c_tpd_ring *tpd_ring = adapter->tpd_ring;
- struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring;
- struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1c_rfd_ring *rfd_ring = adapter->rfd_ring;
+ struct atl1c_rrd_ring *rrd_ring = adapter->rrd_ring;
struct atl1c_ring_header *ring_header = &adapter->ring_header;
+ int tqc = adapter->tx_queue_count;
+ int rqc = adapter->rx_queue_count;
int size;
int i;
int count = 0;
- int rx_desc_count = 0;
u32 offset = 0;
- rrd_ring->count = rfd_ring->count;
- for (i = 1; i < AT_MAX_TRANSMIT_QUEUE; i++)
+ /* Even though only one tpd queue is actually used, the "high"
+ * priority tpd queue also gets initialized
+ */
+ if (tqc == 1)
+ tqc = 2;
+
+ for (i = 1; i < tqc; i++)
tpd_ring[i].count = tpd_ring[0].count;
- /* 2 tpd queue, one high priority queue,
- * another normal priority queue */
- size = sizeof(struct atl1c_buffer) * (tpd_ring->count * 2 +
- rfd_ring->count);
+ size = sizeof(struct atl1c_buffer) * (tpd_ring->count * tqc +
+ rfd_ring->count * rqc);
tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL);
if (unlikely(!tpd_ring->buffer_info))
goto err_nomem;
- for (i = 0; i < AT_MAX_TRANSMIT_QUEUE; i++) {
- tpd_ring[i].buffer_info =
- (tpd_ring->buffer_info + count);
+ for (i = 0; i < tqc; i++) {
+ tpd_ring[i].adapter = adapter;
+ tpd_ring[i].num = i;
+ tpd_ring[i].buffer_info = (tpd_ring->buffer_info + count);
count += tpd_ring[i].count;
}
- rfd_ring->buffer_info =
- (tpd_ring->buffer_info + count);
- count += rfd_ring->count;
- rx_desc_count += rfd_ring->count;
+ for (i = 0; i < rqc; i++) {
+ rrd_ring[i].adapter = adapter;
+ rrd_ring[i].num = i;
+ rrd_ring[i].count = rfd_ring[0].count;
+ rfd_ring[i].count = rfd_ring[0].count;
+ rfd_ring[i].buffer_info = (tpd_ring->buffer_info + count);
+ count += rfd_ring->count;
+ }
/*
* real ring DMA buffer
@@ -999,9 +1052,9 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter)
* additional bytes tacked onto the end.
*/
ring_header->size = size =
- sizeof(struct atl1c_tpd_desc) * tpd_ring->count * 2 +
- sizeof(struct atl1c_rx_free_desc) * rx_desc_count +
- sizeof(struct atl1c_recv_ret_status) * rx_desc_count +
+ sizeof(struct atl1c_tpd_desc) * tpd_ring->count * tqc +
+ sizeof(struct atl1c_rx_free_desc) * rfd_ring->count * rqc +
+ sizeof(struct atl1c_recv_ret_status) * rfd_ring->count * rqc +
8 * 4;
ring_header->desc = dma_alloc_coherent(&pdev->dev, ring_header->size,
@@ -1014,25 +1067,28 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter)
tpd_ring[0].dma = roundup(ring_header->dma, 8);
offset = tpd_ring[0].dma - ring_header->dma;
- for (i = 0; i < AT_MAX_TRANSMIT_QUEUE; i++) {
+ for (i = 0; i < tqc; i++) {
tpd_ring[i].dma = ring_header->dma + offset;
- tpd_ring[i].desc = (u8 *) ring_header->desc + offset;
+ tpd_ring[i].desc = (u8 *)ring_header->desc + offset;
tpd_ring[i].size =
sizeof(struct atl1c_tpd_desc) * tpd_ring[i].count;
offset += roundup(tpd_ring[i].size, 8);
}
- /* init RFD ring */
- rfd_ring->dma = ring_header->dma + offset;
- rfd_ring->desc = (u8 *) ring_header->desc + offset;
- rfd_ring->size = sizeof(struct atl1c_rx_free_desc) * rfd_ring->count;
- offset += roundup(rfd_ring->size, 8);
+ for (i = 0; i < rqc; i++) {
+ /* init RFD ring */
+ rfd_ring[i].dma = ring_header->dma + offset;
+ rfd_ring[i].desc = (u8 *)ring_header->desc + offset;
+ rfd_ring[i].size = sizeof(struct atl1c_rx_free_desc) *
+ rfd_ring[i].count;
+ offset += roundup(rfd_ring[i].size, 8);
- /* init RRD ring */
- rrd_ring->dma = ring_header->dma + offset;
- rrd_ring->desc = (u8 *) ring_header->desc + offset;
- rrd_ring->size = sizeof(struct atl1c_recv_ret_status) *
- rrd_ring->count;
- offset += roundup(rrd_ring->size, 8);
+ /* init RRD ring */
+ rrd_ring[i].dma = ring_header->dma + offset;
+ rrd_ring[i].desc = (u8 *)ring_header->desc + offset;
+ rrd_ring[i].size = sizeof(struct atl1c_recv_ret_status) *
+ rrd_ring[i].count;
+ offset += roundup(rrd_ring[i].size, 8);
+ }
return 0;
@@ -1044,31 +1100,34 @@ err_nomem:
static void atl1c_configure_des_ring(struct atl1c_adapter *adapter)
{
struct atl1c_hw *hw = &adapter->hw;
- struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring;
- struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring;
- struct atl1c_tpd_ring *tpd_ring = (struct atl1c_tpd_ring *)
- adapter->tpd_ring;
+ struct atl1c_rfd_ring *rfd_ring = adapter->rfd_ring;
+ struct atl1c_rrd_ring *rrd_ring = adapter->rrd_ring;
+ struct atl1c_tpd_ring *tpd_ring = adapter->tpd_ring;
+ int i;
+ int tx_queue_count = adapter->tx_queue_count;
+
+ if (tx_queue_count == 1)
+ tx_queue_count = 2;
/* TPD */
AT_WRITE_REG(hw, REG_TX_BASE_ADDR_HI,
- (u32)((tpd_ring[atl1c_trans_normal].dma &
- AT_DMA_HI_ADDR_MASK) >> 32));
+ (u32)((tpd_ring[0].dma & AT_DMA_HI_ADDR_MASK) >> 32));
/* just enable normal priority TX queue */
- AT_WRITE_REG(hw, REG_TPD_PRI0_ADDR_LO,
- (u32)(tpd_ring[atl1c_trans_normal].dma &
- AT_DMA_LO_ADDR_MASK));
- AT_WRITE_REG(hw, REG_TPD_PRI1_ADDR_LO,
- (u32)(tpd_ring[atl1c_trans_high].dma &
- AT_DMA_LO_ADDR_MASK));
+ for (i = 0; i < tx_queue_count; i++) {
+ AT_WRITE_REG(hw, atl1c_qregs[i].tpd_addr_lo,
+ (u32)(tpd_ring[i].dma & AT_DMA_LO_ADDR_MASK));
+ }
AT_WRITE_REG(hw, REG_TPD_RING_SIZE,
(u32)(tpd_ring[0].count & TPD_RING_SIZE_MASK));
/* RFD */
AT_WRITE_REG(hw, REG_RX_BASE_ADDR_HI,
- (u32)((rfd_ring->dma & AT_DMA_HI_ADDR_MASK) >> 32));
- AT_WRITE_REG(hw, REG_RFD0_HEAD_ADDR_LO,
- (u32)(rfd_ring->dma & AT_DMA_LO_ADDR_MASK));
+ (u32)((rfd_ring->dma & AT_DMA_HI_ADDR_MASK) >> 32));
+ for (i = 0; i < adapter->rx_queue_count; i++) {
+ AT_WRITE_REG(hw, atl1c_qregs[i].rfd_addr_lo,
+ (u32)(rfd_ring[i].dma & AT_DMA_LO_ADDR_MASK));
+ }
AT_WRITE_REG(hw, REG_RFD_RING_SIZE,
rfd_ring->count & RFD_RING_SIZE_MASK);
@@ -1076,8 +1135,10 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter)
adapter->rx_buffer_len & RX_BUF_SIZE_MASK);
/* RRD */
- AT_WRITE_REG(hw, REG_RRD0_HEAD_ADDR_LO,
- (u32)(rrd_ring->dma & AT_DMA_LO_ADDR_MASK));
+ for (i = 0; i < adapter->rx_queue_count; i++) {
+ AT_WRITE_REG(hw, atl1c_qregs[i].rrd_addr_lo,
+ (u32)(rrd_ring[i].dma & AT_DMA_LO_ADDR_MASK));
+ }
AT_WRITE_REG(hw, REG_RRD_RING_SIZE,
(rrd_ring->count & RRD_RING_SIZE_MASK));
@@ -1358,7 +1419,7 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, u16 link_speed)
}
/**
- * atl1c_configure - Configure Transmit&Receive Unit after Reset
+ * atl1c_configure_mac - Configure Transmit&Receive Unit after Reset
* @adapter: board private structure
*
* Configure the Tx /Rx unit of the MAC after a reset.
@@ -1430,14 +1491,28 @@ static int atl1c_configure(struct atl1c_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
int num;
+ int i;
+
+ if (adapter->hw.nic_type == athr_mt) {
+ u32 mode;
+
+ AT_READ_REG(&adapter->hw, REG_MT_MODE, &mode);
+ if (adapter->rx_queue_count == 4)
+ mode |= MT_MODE_4Q;
+ else
+ mode &= ~MT_MODE_4Q;
+ AT_WRITE_REG(&adapter->hw, REG_MT_MODE, mode);
+ }
atl1c_init_ring_ptrs(adapter);
atl1c_set_multi(netdev);
atl1c_restore_vlan(adapter);
- num = atl1c_alloc_rx_buffer(adapter, false);
- if (unlikely(num == 0))
- return -ENOMEM;
+ for (i = 0; i < adapter->rx_queue_count; ++i) {
+ num = atl1c_alloc_rx_buffer(adapter, i, false);
+ if (unlikely(num == 0))
+ return -ENOMEM;
+ }
if (atl1c_configure_mac(adapter))
return -EIO;
@@ -1533,9 +1608,11 @@ static inline void atl1c_clear_phy_int(struct atl1c_adapter *adapter)
static int atl1c_clean_tx(struct napi_struct *napi, int budget)
{
- struct atl1c_adapter *adapter =
- container_of(napi, struct atl1c_adapter, tx_napi);
- struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[atl1c_trans_normal];
+ struct atl1c_tpd_ring *tpd_ring =
+ container_of(napi, struct atl1c_tpd_ring, napi);
+ struct atl1c_adapter *adapter = tpd_ring->adapter;
+ struct netdev_queue *txq =
+ netdev_get_tx_queue(napi->dev, tpd_ring->num);
struct atl1c_buffer *buffer_info;
struct pci_dev *pdev = adapter->pdev;
u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean);
@@ -1543,7 +1620,8 @@ static int atl1c_clean_tx(struct napi_struct *napi, int budget)
unsigned int total_bytes = 0, total_packets = 0;
unsigned long flags;
- AT_READ_REGW(&adapter->hw, REG_TPD_PRI0_CIDX, &hw_next_to_clean);
+ AT_READ_REGW(&adapter->hw, atl1c_qregs[tpd_ring->num].tpd_cons,
+ &hw_next_to_clean);
while (next_to_clean != hw_next_to_clean) {
buffer_info = &tpd_ring->buffer_info[next_to_clean];
@@ -1557,17 +1635,15 @@ static int atl1c_clean_tx(struct napi_struct *napi, int budget)
atomic_set(&tpd_ring->next_to_clean, next_to_clean);
}
- netdev_completed_queue(adapter->netdev, total_packets, total_bytes);
+ netdev_tx_completed_queue(txq, total_packets, total_bytes);
- if (netif_queue_stopped(adapter->netdev) &&
- netif_carrier_ok(adapter->netdev)) {
- netif_wake_queue(adapter->netdev);
- }
+ if (netif_tx_queue_stopped(txq) && netif_carrier_ok(adapter->netdev))
+ netif_tx_wake_queue(txq);
if (total_packets < budget) {
napi_complete_done(napi, total_packets);
spin_lock_irqsave(&adapter->hw.intr_mask_lock, flags);
- adapter->hw.intr_mask |= ISR_TX_PKT;
+ adapter->hw.intr_mask |= atl1c_qregs[tpd_ring->num].tx_isr;
AT_WRITE_REG(&adapter->hw, REG_IMR, adapter->hw.intr_mask);
spin_unlock_irqrestore(&adapter->hw.intr_mask_lock, flags);
return total_packets;
@@ -1575,6 +1651,38 @@ static int atl1c_clean_tx(struct napi_struct *napi, int budget)
return budget;
}
+static void atl1c_intr_rx_tx(struct atl1c_adapter *adapter, u32 status)
+{
+ struct atl1c_hw *hw = &adapter->hw;
+ u32 intr_mask;
+ int i;
+
+ spin_lock(&hw->intr_mask_lock);
+ intr_mask = hw->intr_mask;
+ for (i = 0; i < adapter->rx_queue_count; ++i) {
+ if (!(status & atl1c_qregs[i].rx_isr))
+ continue;
+ if (napi_schedule_prep(&adapter->rrd_ring[i].napi)) {
+ intr_mask &= ~atl1c_qregs[i].rx_isr;
+ __napi_schedule(&adapter->rrd_ring[i].napi);
+ }
+ }
+ for (i = 0; i < adapter->tx_queue_count; ++i) {
+ if (!(status & atl1c_qregs[i].tx_isr))
+ continue;
+ if (napi_schedule_prep(&adapter->tpd_ring[i].napi)) {
+ intr_mask &= ~atl1c_qregs[i].tx_isr;
+ __napi_schedule(&adapter->tpd_ring[i].napi);
+ }
+ }
+
+ if (hw->intr_mask != intr_mask) {
+ hw->intr_mask = intr_mask;
+ AT_WRITE_REG(hw, REG_IMR, hw->intr_mask);
+ }
+ spin_unlock(&hw->intr_mask_lock);
+}
+
/**
* atl1c_intr - Interrupt Handler
* @irq: interrupt number
@@ -1605,24 +1713,8 @@ static irqreturn_t atl1c_intr(int irq, void *data)
atl1c_clear_phy_int(adapter);
/* Ack ISR */
AT_WRITE_REG(hw, REG_ISR, status | ISR_DIS_INT);
- if (status & ISR_RX_PKT) {
- if (likely(napi_schedule_prep(&adapter->napi))) {
- spin_lock(&hw->intr_mask_lock);
- hw->intr_mask &= ~ISR_RX_PKT;
- AT_WRITE_REG(hw, REG_IMR, hw->intr_mask);
- spin_unlock(&hw->intr_mask_lock);
- __napi_schedule(&adapter->napi);
- }
- }
- if (status & ISR_TX_PKT) {
- if (napi_schedule_prep(&adapter->tx_napi)) {
- spin_lock(&hw->intr_mask_lock);
- hw->intr_mask &= ~ISR_TX_PKT;
- AT_WRITE_REG(hw, REG_IMR, hw->intr_mask);
- spin_unlock(&hw->intr_mask_lock);
- __napi_schedule(&adapter->tx_napi);
- }
- }
+ if (status & (ISR_RX_PKT | ISR_TX_PKT))
+ atl1c_intr_rx_tx(adapter, status);
handled = IRQ_HANDLED;
/* check if PCIE PHY Link down */
@@ -1659,6 +1751,11 @@ static irqreturn_t atl1c_intr(int irq, void *data)
static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
struct sk_buff *skb, struct atl1c_recv_ret_status *prrs)
{
+ if (adapter->hw.nic_type == athr_mt) {
+ if (prrs->word3 & RRS_MT_PROT_ID_TCPUDP)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ return;
+ }
/*
* The pid field in RRS in not correct sometimes, so we
* cannot figure out if the packet is fragmented or not,
@@ -1668,44 +1765,47 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
}
static struct sk_buff *atl1c_alloc_skb(struct atl1c_adapter *adapter,
- bool napi_mode)
+ u32 queue, bool napi_mode)
{
+ struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring[queue];
struct sk_buff *skb;
struct page *page;
if (adapter->rx_frag_size > PAGE_SIZE) {
if (likely(napi_mode))
- return napi_alloc_skb(&adapter->napi,
+ return napi_alloc_skb(&rrd_ring->napi,
adapter->rx_buffer_len);
else
return netdev_alloc_skb_ip_align(adapter->netdev,
adapter->rx_buffer_len);
}
- page = adapter->rx_page;
+ page = rrd_ring->rx_page;
if (!page) {
- adapter->rx_page = page = alloc_page(GFP_ATOMIC);
+ page = alloc_page(GFP_ATOMIC);
if (unlikely(!page))
return NULL;
- adapter->rx_page_offset = 0;
+ rrd_ring->rx_page = page;
+ rrd_ring->rx_page_offset = 0;
}
- skb = build_skb(page_address(page) + adapter->rx_page_offset,
+ skb = build_skb(page_address(page) + rrd_ring->rx_page_offset,
adapter->rx_frag_size);
if (likely(skb)) {
skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
- adapter->rx_page_offset += adapter->rx_frag_size;
- if (adapter->rx_page_offset >= PAGE_SIZE)
- adapter->rx_page = NULL;
+ rrd_ring->rx_page_offset += adapter->rx_frag_size;
+ if (rrd_ring->rx_page_offset >= PAGE_SIZE)
+ rrd_ring->rx_page = NULL;
else
get_page(page);
}
return skb;
}
-static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, bool napi_mode)
+static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, u32 queue,
+ bool napi_mode)
{
- struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring[queue];
struct pci_dev *pdev = adapter->pdev;
struct atl1c_buffer *buffer_info, *next_info;
struct sk_buff *skb;
@@ -1724,7 +1824,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, bool napi_mode)
while (next_info->flags & ATL1C_BUFFER_FREE) {
rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use);
- skb = atl1c_alloc_skb(adapter, napi_mode);
+ skb = atl1c_alloc_skb(adapter, queue, napi_mode);
if (unlikely(!skb)) {
if (netif_msg_rx_err(adapter))
dev_warn(&pdev->dev, "alloc rx buffer failed\n");
@@ -1766,8 +1866,8 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, bool napi_mode)
/* TODO: update mailbox here */
wmb();
rfd_ring->next_to_use = rfd_next_to_use;
- AT_WRITE_REG(&adapter->hw, REG_MB_RFD0_PROD_IDX,
- rfd_ring->next_to_use & MB_RFDX_PROD_IDX_MASK);
+ AT_WRITE_REG(&adapter->hw, atl1c_qregs[queue].rfd_prod,
+ rfd_ring->next_to_use & MB_RFDX_PROD_IDX_MASK);
}
return num_alloc;
@@ -1805,22 +1905,33 @@ static void atl1c_clean_rfd(struct atl1c_rfd_ring *rfd_ring,
rfd_ring->next_to_clean = rfd_index;
}
-static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter,
- int *work_done, int work_to_do)
+/**
+ * atl1c_clean_rx - NAPI Rx polling callback
+ * @napi: napi info
+ * @budget: limit of packets to clean
+ */
+static int atl1c_clean_rx(struct napi_struct *napi, int budget)
{
+ struct atl1c_rrd_ring *rrd_ring =
+ container_of(napi, struct atl1c_rrd_ring, napi);
+ struct atl1c_adapter *adapter = rrd_ring->adapter;
u16 rfd_num, rfd_index;
- u16 count = 0;
u16 length;
struct pci_dev *pdev = adapter->pdev;
struct net_device *netdev = adapter->netdev;
- struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring;
- struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring[rrd_ring->num];
struct sk_buff *skb;
struct atl1c_recv_ret_status *rrs;
struct atl1c_buffer *buffer_info;
+ int work_done = 0;
+ unsigned long flags;
+
+ /* Keep link state information with original netdev */
+ if (!netif_carrier_ok(adapter->netdev))
+ goto quit_polling;
while (1) {
- if (*work_done >= work_to_do)
+ if (work_done >= budget)
break;
rrs = ATL1C_RRD_DESC(rrd_ring, rrd_ring->next_to_clean);
if (likely(RRS_RXD_IS_VALID(rrs->word3))) {
@@ -1874,38 +1985,18 @@ rrs_checked:
vlan = le16_to_cpu(vlan);
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan);
}
- napi_gro_receive(&adapter->napi, skb);
+ napi_gro_receive(napi, skb);
- (*work_done)++;
- count++;
+ work_done++;
}
- if (count)
- atl1c_alloc_rx_buffer(adapter, true);
-}
-
-/**
- * atl1c_clean - NAPI Rx polling callback
- * @napi: napi info
- * @budget: limit of packets to clean
- */
-static int atl1c_clean(struct napi_struct *napi, int budget)
-{
- struct atl1c_adapter *adapter =
- container_of(napi, struct atl1c_adapter, napi);
- int work_done = 0;
- unsigned long flags;
-
- /* Keep link state information with original netdev */
- if (!netif_carrier_ok(adapter->netdev))
- goto quit_polling;
- /* just enable one RXQ */
- atl1c_clean_rx_irq(adapter, &work_done, budget);
+ if (work_done)
+ atl1c_alloc_rx_buffer(adapter, rrd_ring->num, true);
if (work_done < budget) {
quit_polling:
napi_complete_done(napi, work_done);
spin_lock_irqsave(&adapter->hw.intr_mask_lock, flags);
- adapter->hw.intr_mask |= ISR_RX_PKT;
+ adapter->hw.intr_mask |= atl1c_qregs[rrd_ring->num].rx_isr;
AT_WRITE_REG(&adapter->hw, REG_IMR, adapter->hw.intr_mask);
spin_unlock_irqrestore(&adapter->hw.intr_mask_lock, flags);
}
@@ -1929,9 +2020,9 @@ static void atl1c_netpoll(struct net_device *netdev)
}
#endif
-static inline u16 atl1c_tpd_avail(struct atl1c_adapter *adapter, enum atl1c_trans_queue type)
+static inline u16 atl1c_tpd_avail(struct atl1c_adapter *adapter, u32 queue)
{
- struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
+ struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[queue];
u16 next_to_use = 0;
u16 next_to_clean = 0;
@@ -1949,9 +2040,9 @@ static inline u16 atl1c_tpd_avail(struct atl1c_adapter *adapter, enum atl1c_tran
* there is enough tpd to use
*/
static struct atl1c_tpd_desc *atl1c_get_tpd(struct atl1c_adapter *adapter,
- enum atl1c_trans_queue type)
+ u32 queue)
{
- struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
+ struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[queue];
struct atl1c_tpd_desc *tpd_desc;
u16 next_to_use = 0;
@@ -1993,7 +2084,7 @@ static u16 atl1c_cal_tpd_req(const struct sk_buff *skb)
static int atl1c_tso_csum(struct atl1c_adapter *adapter,
struct sk_buff *skb,
struct atl1c_tpd_desc **tpd,
- enum atl1c_trans_queue type)
+ u32 queue)
{
struct pci_dev *pdev = adapter->pdev;
unsigned short offload_type;
@@ -2038,7 +2129,7 @@ static int atl1c_tso_csum(struct atl1c_adapter *adapter,
*(struct atl1c_tpd_ext_desc **)(tpd);
memset(etpd, 0, sizeof(struct atl1c_tpd_ext_desc));
- *tpd = atl1c_get_tpd(adapter, type);
+ *tpd = atl1c_get_tpd(adapter, queue);
ipv6_hdr(skb)->payload_len = 0;
/* check payload == 0 byte ? */
hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
@@ -2090,9 +2181,9 @@ check_sum:
static void atl1c_tx_rollback(struct atl1c_adapter *adpt,
struct atl1c_tpd_desc *first_tpd,
- enum atl1c_trans_queue type)
+ u32 queue)
{
- struct atl1c_tpd_ring *tpd_ring = &adpt->tpd_ring[type];
+ struct atl1c_tpd_ring *tpd_ring = &adpt->tpd_ring[queue];
struct atl1c_buffer *buffer_info;
struct atl1c_tpd_desc *tpd;
u16 first_index, index;
@@ -2111,8 +2202,8 @@ static void atl1c_tx_rollback(struct atl1c_adapter *adpt,
}
static int atl1c_tx_map(struct atl1c_adapter *adapter,
- struct sk_buff *skb, struct atl1c_tpd_desc *tpd,
- enum atl1c_trans_queue type)
+ struct sk_buff *skb, struct atl1c_tpd_desc *tpd,
+ u32 queue)
{
struct atl1c_tpd_desc *use_tpd = NULL;
struct atl1c_buffer *buffer_info = NULL;
@@ -2152,7 +2243,7 @@ static int atl1c_tx_map(struct atl1c_adapter *adapter,
if (mapped_len == 0)
use_tpd = tpd;
else {
- use_tpd = atl1c_get_tpd(adapter, type);
+ use_tpd = atl1c_get_tpd(adapter, queue);
memcpy(use_tpd, tpd, sizeof(struct atl1c_tpd_desc));
}
buffer_info = atl1c_get_tx_buffer(adapter, use_tpd);
@@ -2174,7 +2265,7 @@ static int atl1c_tx_map(struct atl1c_adapter *adapter,
for (f = 0; f < nr_frags; f++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[f];
- use_tpd = atl1c_get_tpd(adapter, type);
+ use_tpd = atl1c_get_tpd(adapter, queue);
memcpy(use_tpd, tpd, sizeof(struct atl1c_tpd_desc));
buffer_info = atl1c_get_tx_buffer(adapter, use_tpd);
@@ -2207,23 +2298,22 @@ err_dma:
return -1;
}
-static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb,
- struct atl1c_tpd_desc *tpd, enum atl1c_trans_queue type)
+static void atl1c_tx_queue(struct atl1c_adapter *adapter, u32 queue)
{
- struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
- u16 reg;
+ struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[queue];
- reg = type == atl1c_trans_high ? REG_TPD_PRI1_PIDX : REG_TPD_PRI0_PIDX;
- AT_WRITE_REGW(&adapter->hw, reg, tpd_ring->next_to_use);
+ AT_WRITE_REGW(&adapter->hw, atl1c_qregs[queue].tpd_prod,
+ tpd_ring->next_to_use);
}
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;
+ u32 queue = skb_get_queue_mapping(skb);
+ struct netdev_queue *txq = netdev_get_tx_queue(netdev, queue);
struct atl1c_tpd_desc *tpd;
- enum atl1c_trans_queue type = atl1c_trans_normal;
+ u16 tpd_req;
if (test_bit(__AT_DOWN, &adapter->flags)) {
dev_kfree_skb_any(skb);
@@ -2232,16 +2322,18 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
tpd_req = atl1c_cal_tpd_req(skb);
- if (atl1c_tpd_avail(adapter, type) < tpd_req) {
+ if (atl1c_tpd_avail(adapter, queue) < tpd_req) {
/* no enough descriptor, just stop queue */
- netif_stop_queue(netdev);
+ atl1c_tx_queue(adapter, queue);
+ netif_tx_stop_queue(txq);
return NETDEV_TX_BUSY;
}
- tpd = atl1c_get_tpd(adapter, type);
+ tpd = atl1c_get_tpd(adapter, queue);
/* do TSO and check sum */
- if (atl1c_tso_csum(adapter, skb, &tpd, type) != 0) {
+ if (atl1c_tso_csum(adapter, skb, &tpd, queue) != 0) {
+ atl1c_tx_queue(adapter, queue);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -2259,15 +2351,17 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
if (skb_network_offset(skb) != ETH_HLEN)
tpd->word1 |= 1 << TPD_ETH_TYPE_SHIFT; /* Ethernet frame */
- if (atl1c_tx_map(adapter, skb, tpd, type) < 0) {
+ if (atl1c_tx_map(adapter, skb, tpd, queue) < 0) {
netif_info(adapter, tx_done, adapter->netdev,
"tx-skb dropped due to dma error\n");
/* roll back tpd/buffer */
- atl1c_tx_rollback(adapter, tpd, type);
+ atl1c_tx_rollback(adapter, tpd, queue);
dev_kfree_skb_any(skb);
} else {
- netdev_sent_queue(adapter->netdev, skb->len);
- atl1c_tx_queue(adapter, skb, tpd, type);
+ bool more = netdev_xmit_more();
+
+ if (__netdev_tx_sent_queue(txq, skb->len, more))
+ atl1c_tx_queue(adapter, queue);
}
return NETDEV_TX_OK;
@@ -2321,16 +2415,19 @@ static int atl1c_request_irq(struct atl1c_adapter *adapter)
static void atl1c_reset_dma_ring(struct atl1c_adapter *adapter)
{
+ int i;
/* release tx-pending skbs and reset tx/rx ring index */
- atl1c_clean_tx_ring(adapter, atl1c_trans_normal);
- atl1c_clean_tx_ring(adapter, atl1c_trans_high);
- atl1c_clean_rx_ring(adapter);
+ for (i = 0; i < adapter->tx_queue_count; ++i)
+ atl1c_clean_tx_ring(adapter, i);
+ for (i = 0; i < adapter->rx_queue_count; ++i)
+ atl1c_clean_rx_ring(adapter, i);
}
static int atl1c_up(struct atl1c_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
int err;
+ int i;
netif_carrier_off(netdev);
@@ -2344,20 +2441,24 @@ static int atl1c_up(struct atl1c_adapter *adapter)
atl1c_check_link_status(adapter);
clear_bit(__AT_DOWN, &adapter->flags);
- napi_enable(&adapter->napi);
- napi_enable(&adapter->tx_napi);
+ for (i = 0; i < adapter->tx_queue_count; ++i)
+ napi_enable(&adapter->tpd_ring[i].napi);
+ for (i = 0; i < adapter->rx_queue_count; ++i)
+ napi_enable(&adapter->rrd_ring[i].napi);
atl1c_irq_enable(adapter);
netif_start_queue(netdev);
return err;
err_up:
- atl1c_clean_rx_ring(adapter);
+ for (i = 0; i < adapter->rx_queue_count; ++i)
+ atl1c_clean_rx_ring(adapter, i);
return err;
}
static void atl1c_down(struct atl1c_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
+ int i;
atl1c_del_timer(adapter);
adapter->work_event = 0; /* clear all event */
@@ -2365,8 +2466,10 @@ static void atl1c_down(struct atl1c_adapter *adapter)
* reschedule our watchdog timer */
set_bit(__AT_DOWN, &adapter->flags);
netif_carrier_off(netdev);
- napi_disable(&adapter->napi);
- napi_disable(&adapter->tx_napi);
+ for (i = 0; i < adapter->tx_queue_count; ++i)
+ napi_disable(&adapter->tpd_ring[i].napi);
+ for (i = 0; i < adapter->rx_queue_count; ++i)
+ napi_disable(&adapter->rrd_ring[i].napi);
atl1c_irq_disable(adapter);
atl1c_free_irq(adapter);
/* disable ASPM if device inactive */
@@ -2551,8 +2654,11 @@ static int atl1c_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct net_device *netdev;
struct atl1c_adapter *adapter;
static int cards_found;
-
+ u8 __iomem *hw_addr;
+ enum atl1c_nic_type nic_type;
+ u32 queue_count = 1;
int err = 0;
+ int i;
/* enable device (incl. PCI PM wakeup and hotplug setup) */
err = pci_enable_device_mem(pdev);
@@ -2585,7 +2691,18 @@ static int atl1c_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
- netdev = alloc_etherdev(sizeof(struct atl1c_adapter));
+ hw_addr = pci_ioremap_bar(pdev, 0);
+ if (!hw_addr) {
+ err = -EIO;
+ dev_err(&pdev->dev, "cannot map device registers\n");
+ goto err_ioremap;
+ }
+
+ nic_type = atl1c_get_mac_type(pdev, hw_addr);
+ if (nic_type == athr_mt)
+ queue_count = 4;
+
+ netdev = alloc_etherdev_mq(sizeof(struct atl1c_adapter), queue_count);
if (netdev == NULL) {
err = -ENOMEM;
goto err_alloc_etherdev;
@@ -2601,13 +2718,11 @@ static int atl1c_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->netdev = netdev;
adapter->pdev = pdev;
adapter->hw.adapter = adapter;
+ adapter->hw.nic_type = nic_type;
adapter->msg_enable = netif_msg_init(-1, atl1c_default_msg);
- adapter->hw.hw_addr = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
- if (!adapter->hw.hw_addr) {
- err = -EIO;
- dev_err(&pdev->dev, "cannot map device registers\n");
- goto err_ioremap;
- }
+ adapter->hw.hw_addr = hw_addr;
+ adapter->tx_queue_count = queue_count;
+ adapter->rx_queue_count = queue_count;
/* init mii data */
adapter->mii.dev = netdev;
@@ -2616,8 +2731,12 @@ static int atl1c_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->mii.phy_id_mask = 0x1f;
adapter->mii.reg_num_mask = MDIO_CTRL_REG_MASK;
dev_set_threaded(netdev, true);
- netif_napi_add(netdev, &adapter->napi, atl1c_clean, 64);
- netif_napi_add(netdev, &adapter->tx_napi, atl1c_clean_tx, 64);
+ for (i = 0; i < adapter->rx_queue_count; ++i)
+ netif_napi_add(netdev, &adapter->rrd_ring[i].napi,
+ atl1c_clean_rx, 64);
+ for (i = 0; i < adapter->tx_queue_count; ++i)
+ netif_napi_add(netdev, &adapter->tpd_ring[i].napi,
+ atl1c_clean_tx, 64);
timer_setup(&adapter->phy_config_timer, atl1c_phy_config, 0);
/* setup the private structure */
err = atl1c_sw_init(adapter);
@@ -2670,11 +2789,11 @@ static int atl1c_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_reset:
err_register:
err_sw_init:
- iounmap(adapter->hw.hw_addr);
err_init_netdev:
-err_ioremap:
free_netdev(netdev);
err_alloc_etherdev:
+ iounmap(hw_addr);
+err_ioremap:
pci_release_regions(pdev);
err_pci_reg:
err_dma:
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
index ff9f96de74b8..2eb0a2ab69f6 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -357,7 +357,7 @@ static void atl1e_restore_vlan(struct atl1e_adapter *adapter)
}
/**
- * atl1e_set_mac - Change the Ethernet Address of the NIC
+ * atl1e_set_mac_addr - Change the Ethernet Address of the NIC
* @netdev: network interface device structure
* @p: pointer to an address structure
*
@@ -787,7 +787,7 @@ static void atl1e_free_ring_resources(struct atl1e_adapter *adapter)
}
/**
- * atl1e_setup_mem_resources - allocate Tx / RX descriptor resources
+ * atl1e_setup_ring_resources - allocate Tx / RX descriptor resources
* @adapter: board private structure
*
* Return 0 on success, negative on failure
diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
index eaf96d002fa5..c67201a13cf5 100644
--- a/drivers/net/ethernet/atheros/atlx/atl1.c
+++ b/drivers/net/ethernet/atheros/atlx/atl1.c
@@ -1011,7 +1011,7 @@ static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
}
/**
- * atl1_setup_mem_resources - allocate Tx / RX descriptor resources
+ * atl1_setup_ring_resources - allocate Tx / RX descriptor resources
* @adapter: board private structure
*
* Return 0 on success, negative on failure
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index cb88ffb8f12f..1a02ca600b71 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -206,6 +206,7 @@ config SYSTEMPORT
config BNXT
tristate "Broadcom NetXtreme-C/E support"
depends on PCI
+ imply PTP_1588_CLOCK
select FW_LOADER
select LIBCRC32C
select NET_DEVLINK
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index b455b60a5434..ad2655efe423 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -1556,8 +1556,8 @@ static void b44_setup_pseudo_magicp(struct b44 *bp)
plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
B44_ETHIPV4UDP_HLEN);
- bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, B44_PATTERN_BASE);
- bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, B44_PMASK_BASE);
+ bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, B44_PATTERN_BASE);
+ bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, B44_PMASK_BASE);
/* Raw ethernet II magic packet pattern - pattern 1 */
memset(pwol_pattern, 0, B44_PATTERN_SIZE);
@@ -1565,9 +1565,9 @@ static void b44_setup_pseudo_magicp(struct b44 *bp)
plen1 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
ETH_HLEN);
- bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
+ bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
B44_PATTERN_BASE + B44_PATTERN_SIZE);
- bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
+ bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
B44_PMASK_BASE + B44_PMASK_SIZE);
/* Ipv6 magic packet pattern - pattern 2 */
@@ -1576,9 +1576,9 @@ static void b44_setup_pseudo_magicp(struct b44 *bp)
plen2 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
B44_ETHIPV6UDP_HLEN);
- bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
+ bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
B44_PATTERN_BASE + B44_PATTERN_SIZE + B44_PATTERN_SIZE);
- bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
+ bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
B44_PMASK_BASE + B44_PMASK_SIZE + B44_PMASK_SIZE);
kfree(pwol_pattern);
@@ -1631,9 +1631,9 @@ static void b44_setup_wol(struct b44 *bp)
val = br32(bp, B44_DEVCTRL);
bw32(bp, B44_DEVCTRL, val | DEVCTRL_MPM | DEVCTRL_PFE);
- } else {
- b44_setup_pseudo_magicp(bp);
- }
+ } else {
+ b44_setup_pseudo_magicp(bp);
+ }
b44_setup_wol_pci(bp);
}
@@ -1757,7 +1757,7 @@ static void __b44_set_rx_mode(struct net_device *dev)
__b44_cam_write(bp, zero, i);
bw32(bp, B44_RXCONFIG, val);
- val = br32(bp, B44_CAM_CTRL);
+ val = br32(bp, B44_CAM_CTRL);
bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
}
}
diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c
index 60d908507f51..02a569500234 100644
--- a/drivers/net/ethernet/broadcom/bcm4908_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c
@@ -174,9 +174,6 @@ static int bcm4908_dma_alloc_buf_descs(struct bcm4908_enet *enet,
if (!ring->slots)
goto err_free_buf_descs;
- ring->read_idx = 0;
- ring->write_idx = 0;
-
return 0;
err_free_buf_descs:
@@ -304,6 +301,9 @@ static void bcm4908_enet_dma_ring_init(struct bcm4908_enet *enet,
enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR,
(uint32_t)ring->dma_addr);
+
+ ring->read_idx = 0;
+ ring->write_idx = 0;
}
static void bcm4908_enet_dma_uninit(struct bcm4908_enet *enet)
diff --git a/drivers/net/ethernet/broadcom/bgmac-platform.c b/drivers/net/ethernet/broadcom/bgmac-platform.c
index 9834b77cf4b6..4ab5bf64d353 100644
--- a/drivers/net/ethernet/broadcom/bgmac-platform.c
+++ b/drivers/net/ethernet/broadcom/bgmac-platform.c
@@ -172,7 +172,6 @@ static int bgmac_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct bgmac *bgmac;
- struct resource *regs;
int ret;
bgmac = bgmac_alloc(&pdev->dev);
@@ -206,21 +205,15 @@ static int bgmac_probe(struct platform_device *pdev)
if (IS_ERR(bgmac->plat.base))
return PTR_ERR(bgmac->plat.base);
- regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "idm_base");
- if (regs) {
- bgmac->plat.idm_base = devm_ioremap_resource(&pdev->dev, regs);
- if (IS_ERR(bgmac->plat.idm_base))
- return PTR_ERR(bgmac->plat.idm_base);
+ bgmac->plat.idm_base = devm_platform_ioremap_resource_byname(pdev, "idm_base");
+ if (IS_ERR(bgmac->plat.idm_base))
+ return PTR_ERR(bgmac->plat.idm_base);
+ else
bgmac->feature_flags &= ~BGMAC_FEAT_IDM_MASK;
- }
- regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nicpm_base");
- if (regs) {
- bgmac->plat.nicpm_base = devm_ioremap_resource(&pdev->dev,
- regs);
- if (IS_ERR(bgmac->plat.nicpm_base))
- return PTR_ERR(bgmac->plat.nicpm_base);
- }
+ bgmac->plat.nicpm_base = devm_platform_ioremap_resource_byname(pdev, "nicpm_base");
+ if (IS_ERR(bgmac->plat.nicpm_base))
+ return PTR_ERR(bgmac->plat.nicpm_base);
bgmac->read = platform_bgmac_read;
bgmac->write = platform_bgmac_write;
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index 5bace8a93d73..bee6cfad9fc6 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -572,7 +572,7 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
}
if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
- ret = -EBUSY;
+ ret = -EBUSY;
else
ret = 0;
@@ -3599,7 +3599,7 @@ bnx2_set_rx_mode(struct net_device *dev)
for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
0xffffffff);
- }
+ }
sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
}
else {
@@ -4674,7 +4674,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
if (addr == page_end-4) {
cmd_flags = BNX2_NVM_COMMAND_LAST;
- }
+ }
rc = bnx2_nvram_write_dword(bp, addr,
&flash_buffer[i], cmd_flags);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 281b1c2e04a7..2acbc73dcd18 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -13586,7 +13586,7 @@ static int bnx2x_set_qm_cid_count(struct bnx2x *bp)
}
/**
- * bnx2x_get_num_none_def_sbs - return the number of none default SBs
+ * bnx2x_get_num_non_def_sbs - return the number of none default SBs
* @pdev: pci device
* @cnic_cnt: count
*
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index 6cd1523ad9e5..542c69822649 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -4152,7 +4152,7 @@ void bnx2x_init_mcast_obj(struct bnx2x *bp,
/*************************** Credit handling **********************************/
/**
- * atomic_add_ifless - add if the result is less than a given value.
+ * __atomic_add_ifless - add if the result is less than a given value.
*
* @v: pointer of type atomic_t
* @a: the amount to add to v...
@@ -4180,7 +4180,7 @@ static inline bool __atomic_add_ifless(atomic_t *v, int a, int u)
}
/**
- * atomic_dec_ifmoe - dec if the result is more or equal than a given value.
+ * __atomic_dec_ifmoe - dec if the result is more or equal than a given value.
*
* @v: pointer of type atomic_t
* @a: the amount to dec from v...
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
index 3a716c015415..966d5722c5e2 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
@@ -504,7 +504,6 @@ enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
/* VF side vfpf channel functions */
int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count);
int bnx2x_vfpf_release(struct bnx2x *bp);
-int bnx2x_vfpf_release(struct bnx2x *bp);
int bnx2x_vfpf_init(struct bnx2x *bp);
void bnx2x_vfpf_close_vf(struct bnx2x *bp);
int bnx2x_vfpf_setup_q(struct bnx2x *bp, struct bnx2x_fastpath *fp,
diff --git a/drivers/net/ethernet/broadcom/bnxt/Makefile b/drivers/net/ethernet/broadcom/bnxt/Makefile
index cb97ec56fdec..2b8ae687b3c1 100644
--- a/drivers/net/ethernet/broadcom/bnxt/Makefile
+++ b/drivers/net/ethernet/broadcom/bnxt/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_BNXT) += bnxt_en.o
-bnxt_en-y := bnxt.o bnxt_sriov.o bnxt_ethtool.o bnxt_dcb.o bnxt_ulp.o bnxt_xdp.o bnxt_vfr.o bnxt_devlink.o bnxt_dim.o
+bnxt_en-y := bnxt.o bnxt_sriov.o bnxt_ethtool.o bnxt_dcb.o bnxt_ulp.o bnxt_xdp.o bnxt_ptp.o bnxt_vfr.o bnxt_devlink.o bnxt_dim.o
bnxt_en-$(CONFIG_BNXT_FLOWER_OFFLOAD) += bnxt_tc.o
bnxt_en-$(CONFIG_DEBUG_FS) += bnxt_debugfs.o
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index aef3fccc27a9..f56245eeef7b 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -49,6 +49,8 @@
#include <linux/log2.h>
#include <linux/aer.h>
#include <linux/bitmap.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/timecounter.h>
#include <linux/cpu_rmap.h>
#include <linux/cpumask.h>
#include <net/pkt_cls.h>
@@ -63,6 +65,7 @@
#include "bnxt_ethtool.h"
#include "bnxt_dcb.h"
#include "bnxt_xdp.h"
+#include "bnxt_ptp.h"
#include "bnxt_vfr.h"
#include "bnxt_tc.h"
#include "bnxt_devlink.h"
@@ -418,12 +421,25 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
vlan_tag_flags |= 1 << TX_BD_CFA_META_TPID_SHIFT;
}
- if (unlikely(skb->no_fcs)) {
- lflags |= cpu_to_le32(TX_BD_FLAGS_NO_CRC);
- goto normal_tx;
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+
+ if (ptp && ptp->tx_tstamp_en && !skb_is_gso(skb) &&
+ atomic_dec_if_positive(&ptp->tx_avail) >= 0) {
+ if (!bnxt_ptp_parse(skb, &ptp->tx_seqid)) {
+ lflags |= cpu_to_le32(TX_BD_FLAGS_STAMP);
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ } else {
+ atomic_inc(&bp->ptp_cfg->tx_avail);
+ }
+ }
}
- if (free_size == bp->tx_ring_size && length <= bp->tx_push_thresh) {
+ if (unlikely(skb->no_fcs))
+ lflags |= cpu_to_le32(TX_BD_FLAGS_NO_CRC);
+
+ if (free_size == bp->tx_ring_size && length <= bp->tx_push_thresh &&
+ !lflags) {
struct tx_push_buffer *tx_push_buf = txr->tx_push;
struct tx_push_bd *tx_push = &tx_push_buf->push_bd;
struct tx_bd_ext *tx_push1 = &tx_push->txbd2;
@@ -590,6 +606,8 @@ normal_tx:
netdev_tx_sent_queue(txq, skb->len);
+ skb_tx_timestamp(skb);
+
/* Sync BD data before updating doorbell */
wmb();
@@ -619,6 +637,9 @@ tx_done:
return NETDEV_TX_OK;
tx_dma_error:
+ if (BNXT_TX_PTP_IS_SET(lflags))
+ atomic_inc(&bp->ptp_cfg->tx_avail);
+
last_frag = i;
/* start back at beginning and unmap skb */
@@ -653,6 +674,7 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts)
for (i = 0; i < nr_pkts; i++) {
struct bnxt_sw_tx_bd *tx_buf;
+ bool compl_deferred = false;
struct sk_buff *skb;
int j, last;
@@ -679,12 +701,21 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts)
skb_frag_size(&skb_shinfo(skb)->frags[j]),
PCI_DMA_TODEVICE);
}
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (!bnxt_get_tx_ts_p5(bp, skb))
+ compl_deferred = true;
+ else
+ atomic_inc(&bp->ptp_cfg->tx_avail);
+ }
+ }
next_tx_int:
cons = NEXT_TX(cons);
tx_bytes += skb->len;
- dev_kfree_skb_any(skb);
+ if (!compl_deferred)
+ dev_kfree_skb_any(skb);
}
netdev_tx_completed_queue(txq, nr_pkts, tx_bytes);
@@ -1706,9 +1737,9 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
u8 *data_ptr, agg_bufs, cmp_type;
dma_addr_t dma_addr;
struct sk_buff *skb;
+ u32 flags, misc;
void *data;
int rc = 0;
- u32 misc;
rxcmp = (struct rx_cmp *)
&cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)];
@@ -1806,7 +1837,8 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
goto next_rx_no_len;
}
- len = le32_to_cpu(rxcmp->rx_cmp_len_flags_type) >> RX_CMP_LEN_SHIFT;
+ flags = le32_to_cpu(rxcmp->rx_cmp_len_flags_type);
+ len = flags >> RX_CMP_LEN_SHIFT;
dma_addr = rx_buf->mapping;
if (bnxt_rx_xdp(bp, rxr, cons, data, &data_ptr, &len, event)) {
@@ -1883,6 +1915,24 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
}
}
+ if (unlikely((flags & RX_CMP_FLAGS_ITYPES_MASK) ==
+ RX_CMP_FLAGS_ITYPE_PTP_W_TS)) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ u32 cmpl_ts = le32_to_cpu(rxcmp1->rx_cmp_timestamp);
+ u64 ns, ts;
+
+ if (!bnxt_get_rx_ts_p5(bp, &ts, cmpl_ts)) {
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+
+ spin_lock_bh(&ptp->ptp_lock);
+ ns = timecounter_cyc2time(&ptp->tc, ts);
+ spin_unlock_bh(&ptp->ptp_lock);
+ memset(skb_hwtstamps(skb), 0,
+ sizeof(*skb_hwtstamps(skb)));
+ skb_hwtstamps(skb)->hwtstamp = ns_to_ktime(ns);
+ }
+ }
+ }
bnxt_deliver_skb(bp, bnapi, skb);
rc = 1;
@@ -2184,6 +2234,7 @@ static int bnxt_hwrm_handler(struct bnxt *bp, struct tx_cmp *txcmp)
case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT:
bnxt_async_event_process(bp,
(struct hwrm_async_event_cmpl *)txcmp);
+ break;
default:
break;
@@ -7391,6 +7442,56 @@ hwrm_func_resc_qcaps_exit:
return rc;
}
+/* bp->hwrm_cmd_lock already held. */
+static int __bnxt_hwrm_ptp_qcfg(struct bnxt *bp)
+{
+ struct hwrm_port_mac_ptp_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
+ struct hwrm_port_mac_ptp_qcfg_input req = {0};
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+ u8 flags;
+ int rc;
+
+ if (bp->hwrm_spec_code < 0x10801) {
+ rc = -ENODEV;
+ goto no_ptp;
+ }
+
+ req.port_id = cpu_to_le16(bp->pf.port_id);
+ bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_MAC_PTP_QCFG, -1, -1);
+ rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+ if (rc)
+ goto no_ptp;
+
+ flags = resp->flags;
+ if (!(flags & PORT_MAC_PTP_QCFG_RESP_FLAGS_HWRM_ACCESS)) {
+ rc = -ENODEV;
+ goto no_ptp;
+ }
+ if (!ptp) {
+ ptp = kzalloc(sizeof(*ptp), GFP_KERNEL);
+ if (!ptp)
+ return -ENOMEM;
+ ptp->bp = bp;
+ bp->ptp_cfg = ptp;
+ }
+ if (flags & PORT_MAC_PTP_QCFG_RESP_FLAGS_PARTIAL_DIRECT_ACCESS_REF_CLOCK) {
+ ptp->refclk_regs[0] = le32_to_cpu(resp->ts_ref_clock_reg_lower);
+ ptp->refclk_regs[1] = le32_to_cpu(resp->ts_ref_clock_reg_upper);
+ } else if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ ptp->refclk_regs[0] = BNXT_TS_REG_TIMESYNC_TS0_LOWER;
+ ptp->refclk_regs[1] = BNXT_TS_REG_TIMESYNC_TS0_UPPER;
+ } else {
+ rc = -ENODEV;
+ goto no_ptp;
+ }
+ return 0;
+
+no_ptp:
+ kfree(ptp);
+ bp->ptp_cfg = NULL;
+ return rc;
+}
+
static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
{
int rc = 0;
@@ -7462,6 +7563,8 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
bp->flags &= ~BNXT_FLAG_WOL_CAP;
if (flags & FUNC_QCAPS_RESP_FLAGS_WOL_MAGICPKT_SUPPORTED)
bp->flags |= BNXT_FLAG_WOL_CAP;
+ if (flags & FUNC_QCAPS_RESP_FLAGS_PTP_SUPPORTED)
+ __bnxt_hwrm_ptp_qcfg(bp);
} else {
#ifdef CONFIG_BNXT_SRIOV
struct bnxt_vf_info *vf = &bp->vf;
@@ -10020,6 +10123,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
}
}
+ bnxt_ptp_start(bp);
rc = bnxt_init_nic(bp, irq_re_init);
if (rc) {
netdev_err(bp->dev, "bnxt_init_nic err: %x\n", rc);
@@ -10335,6 +10439,12 @@ static int bnxt_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return bnxt_hwrm_port_phy_write(bp, mdio->phy_id, mdio->reg_num,
mdio->val_in);
+ case SIOCSHWTSTAMP:
+ return bnxt_hwtstamp_set(dev, ifr);
+
+ case SIOCGHWTSTAMP:
+ return bnxt_hwtstamp_get(dev, ifr);
+
default:
/* do nothing */
break;
@@ -12551,6 +12661,8 @@ static void bnxt_remove_one(struct pci_dev *pdev)
if (BNXT_PF(bp))
devlink_port_type_clear(&bp->dl_port);
+
+ bnxt_ptp_clear(bp);
pci_disable_pcie_error_reporting(pdev);
unregister_netdev(dev);
clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
@@ -12571,6 +12683,8 @@ static void bnxt_remove_one(struct pci_dev *pdev)
bnxt_dcb_free(bp);
kfree(bp->edev);
bp->edev = NULL;
+ kfree(bp->ptp_cfg);
+ bp->ptp_cfg = NULL;
kfree(bp->fw_health);
bp->fw_health = NULL;
bnxt_cleanup_pci(bp);
@@ -13132,6 +13246,11 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rc);
}
+ if (bnxt_ptp_init(bp)) {
+ netdev_warn(dev, "PTP initialization failed.\n");
+ kfree(bp->ptp_cfg);
+ bp->ptp_cfg = NULL;
+ }
bnxt_inv_fw_health_reg(bp);
bnxt_dl_register(bp);
@@ -13161,6 +13280,8 @@ init_err_pci_clean:
bnxt_free_hwrm_short_cmd_req(bp);
bnxt_free_hwrm_resources(bp);
bnxt_ethtool_free(bp);
+ kfree(bp->ptp_cfg);
+ bp->ptp_cfg = NULL;
kfree(bp->fw_health);
bp->fw_health = NULL;
bnxt_cleanup_pci(bp);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index 30e47ea343f9..bcf8d00b8c80 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -89,6 +89,8 @@ struct tx_bd_ext {
#define TX_BD_CFA_META_KEY_VLAN (1 << 28)
};
+#define BNXT_TX_PTP_IS_SET(lflags) ((lflags) & cpu_to_le32(TX_BD_FLAGS_STAMP))
+
struct rx_bd {
__le32 rx_bd_len_flags_type;
#define RX_BD_TYPE (0x3f << 0)
@@ -159,6 +161,7 @@ struct rx_cmp {
#define RX_CMP_FLAGS_RSS_VALID (1 << 10)
#define RX_CMP_FLAGS_UNUSED (1 << 11)
#define RX_CMP_FLAGS_ITYPES_SHIFT 12
+ #define RX_CMP_FLAGS_ITYPES_MASK 0xf000
#define RX_CMP_FLAGS_ITYPE_UNKNOWN (0 << 12)
#define RX_CMP_FLAGS_ITYPE_IP (1 << 12)
#define RX_CMP_FLAGS_ITYPE_TCP (2 << 12)
@@ -240,7 +243,7 @@ struct rx_cmp_ext {
#define RX_CMPL_CFA_CODE_MASK (0xffff << 16)
#define RX_CMPL_CFA_CODE_SFT 16
- __le32 rx_cmp_unused3;
+ __le32 rx_cmp_timestamp;
};
#define RX_CMP_L2_ERRORS \
@@ -1362,6 +1365,9 @@ struct bnxt_test_info {
#define BNXT_GRC_REG_CHIP_NUM 0x48
#define BNXT_GRC_REG_BASE 0x260000
+#define BNXT_TS_REG_TIMESYNC_TS0_LOWER 0x640180c
+#define BNXT_TS_REG_TIMESYNC_TS0_UPPER 0x6401810
+
#define BNXT_GRC_BASE_MASK 0xfffff000
#define BNXT_GRC_OFFSET_MASK 0x00000ffc
@@ -2042,6 +2048,8 @@ struct bnxt {
struct bpf_prog *xdp_prog;
+ struct bnxt_ptp_cfg *ptp_cfg;
+
/* devlink interface and vf-rep structs */
struct devlink *dl;
struct devlink_port dl_port;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index c664ec52ebcf..786ca51e669b 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -19,9 +19,13 @@
#include <linux/firmware.h>
#include <linux/utsname.h>
#include <linux/time.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/net_tstamp.h>
+#include <linux/timecounter.h>
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_xdp.h"
+#include "bnxt_ptp.h"
#include "bnxt_ethtool.h"
#include "bnxt_nvm_defs.h" /* NVRAM content constant and structure defs */
#include "bnxt_fw_hdr.h" /* Firmware hdr constant and structure defs */
@@ -3926,6 +3930,35 @@ static int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump,
return 0;
}
+static int bnxt_get_ts_info(struct net_device *dev,
+ struct ethtool_ts_info *info)
+{
+ struct bnxt *bp = netdev_priv(dev);
+ struct bnxt_ptp_cfg *ptp;
+
+ ptp = bp->ptp_cfg;
+ info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE;
+
+ info->phc_index = -1;
+ if (!ptp)
+ return 0;
+
+ info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+ if (ptp->ptp_clock)
+ info->phc_index = ptp_clock_index(ptp->ptp_clock);
+
+ 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) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT);
+ return 0;
+}
+
void bnxt_ethtool_init(struct bnxt *bp)
{
struct hwrm_selftest_qlist_output *resp = bp->hwrm_cmd_resp_addr;
@@ -4172,6 +4205,7 @@ const struct ethtool_ops bnxt_ethtool_ops = {
.nway_reset = bnxt_nway_reset,
.set_phys_id = bnxt_set_phys_id,
.self_test = bnxt_self_test,
+ .get_ts_info = bnxt_get_ts_info,
.reset = bnxt_reset,
.set_dump = bnxt_set_dump,
.get_dump_flag = bnxt_get_dump_flag,
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
index 6199f125bc13..3fc6781c5b98 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
@@ -189,6 +189,8 @@ struct cmd_nums {
#define HWRM_QUEUE_VLANPRI_QCAPS 0x83UL
#define HWRM_QUEUE_VLANPRI2PRI_QCFG 0x84UL
#define HWRM_QUEUE_VLANPRI2PRI_CFG 0x85UL
+ #define HWRM_QUEUE_GLOBAL_CFG 0x86UL
+ #define HWRM_QUEUE_GLOBAL_QCFG 0x87UL
#define HWRM_CFA_L2_FILTER_ALLOC 0x90UL
#define HWRM_CFA_L2_FILTER_FREE 0x91UL
#define HWRM_CFA_L2_FILTER_CFG 0x92UL
@@ -250,6 +252,8 @@ struct cmd_nums {
#define HWRM_PORT_SFP_SIDEBAND_QCFG 0xd7UL
#define HWRM_FW_STATE_UNQUIESCE 0xd8UL
#define HWRM_PORT_DSC_DUMP 0xd9UL
+ #define HWRM_PORT_EP_TX_QCFG 0xdaUL
+ #define HWRM_PORT_EP_TX_CFG 0xdbUL
#define HWRM_TEMP_MONITOR_QUERY 0xe0UL
#define HWRM_REG_POWER_QUERY 0xe1UL
#define HWRM_CORE_FREQUENCY_QUERY 0xe2UL
@@ -305,6 +309,8 @@ struct cmd_nums {
#define HWRM_CFA_EEM_OP 0x123UL
#define HWRM_CFA_ADV_FLOW_MGNT_QCAPS 0x124UL
#define HWRM_CFA_TFLIB 0x125UL
+ #define HWRM_CFA_LAG_GROUP_MEMBER_RGTR 0x126UL
+ #define HWRM_CFA_LAG_GROUP_MEMBER_UNRGTR 0x127UL
#define HWRM_ENGINE_CKV_STATUS 0x12eUL
#define HWRM_ENGINE_CKV_CKEK_ADD 0x12fUL
#define HWRM_ENGINE_CKV_CKEK_DELETE 0x130UL
@@ -356,6 +362,12 @@ struct cmd_nums {
#define HWRM_STAT_EXT_CTX_QUERY 0x199UL
#define HWRM_FUNC_SPD_CFG 0x19aUL
#define HWRM_FUNC_SPD_QCFG 0x19bUL
+ #define HWRM_FUNC_PTP_PIN_QCFG 0x19cUL
+ #define HWRM_FUNC_PTP_PIN_CFG 0x19dUL
+ #define HWRM_FUNC_PTP_CFG 0x19eUL
+ #define HWRM_FUNC_PTP_TS_QUERY 0x19fUL
+ #define HWRM_FUNC_PTP_EXT_CFG 0x1a0UL
+ #define HWRM_FUNC_PTP_EXT_QCFG 0x1a1UL
#define HWRM_SELFTEST_QLIST 0x200UL
#define HWRM_SELFTEST_EXEC 0x201UL
#define HWRM_SELFTEST_IRQ 0x202UL
@@ -373,6 +385,10 @@ struct cmd_nums {
#define HWRM_MFG_PARAM_SEEPROM_SYNC 0x20eUL
#define HWRM_MFG_PARAM_SEEPROM_READ 0x20fUL
#define HWRM_MFG_PARAM_SEEPROM_HEALTH 0x210UL
+ #define HWRM_MFG_PRVSN_EXPORT_CSR 0x211UL
+ #define HWRM_MFG_PRVSN_IMPORT_CERT 0x212UL
+ #define HWRM_MFG_PRVSN_GET_STATE 0x213UL
+ #define HWRM_MFG_GET_NVM_MEASUREMENT 0x214UL
#define HWRM_TF 0x2bcUL
#define HWRM_TF_VERSION_GET 0x2bdUL
#define HWRM_TF_SESSION_OPEN 0x2c6UL
@@ -385,6 +401,7 @@ struct cmd_nums {
#define HWRM_TF_SESSION_RESC_ALLOC 0x2cdUL
#define HWRM_TF_SESSION_RESC_FREE 0x2ceUL
#define HWRM_TF_SESSION_RESC_FLUSH 0x2cfUL
+ #define HWRM_TF_SESSION_RESC_INFO 0x2d0UL
#define HWRM_TF_TBL_TYPE_GET 0x2daUL
#define HWRM_TF_TBL_TYPE_SET 0x2dbUL
#define HWRM_TF_TBL_TYPE_BULK_GET 0x2dcUL
@@ -399,6 +416,7 @@ struct cmd_nums {
#define HWRM_TF_EM_INSERT 0x2eaUL
#define HWRM_TF_EM_DELETE 0x2ebUL
#define HWRM_TF_EM_HASH_INSERT 0x2ecUL
+ #define HWRM_TF_EM_MOVE 0x2edUL
#define HWRM_TF_TCAM_SET 0x2f8UL
#define HWRM_TF_TCAM_GET 0x2f9UL
#define HWRM_TF_TCAM_MOVE 0x2faUL
@@ -427,6 +445,16 @@ struct cmd_nums {
#define HWRM_DBG_QCAPS 0xff20UL
#define HWRM_DBG_QCFG 0xff21UL
#define HWRM_DBG_CRASHDUMP_MEDIUM_CFG 0xff22UL
+ #define HWRM_DBG_USEQ_ALLOC 0xff23UL
+ #define HWRM_DBG_USEQ_FREE 0xff24UL
+ #define HWRM_DBG_USEQ_FLUSH 0xff25UL
+ #define HWRM_DBG_USEQ_QCAPS 0xff26UL
+ #define HWRM_DBG_USEQ_CW_CFG 0xff27UL
+ #define HWRM_DBG_USEQ_SCHED_CFG 0xff28UL
+ #define HWRM_DBG_USEQ_RUN 0xff29UL
+ #define HWRM_DBG_USEQ_DELIVERY_REQ 0xff2aUL
+ #define HWRM_DBG_USEQ_RESP_HDR 0xff2bUL
+ #define HWRM_NVM_DEFRAG 0xffecUL
#define HWRM_NVM_REQ_ARBITRATION 0xffedUL
#define HWRM_NVM_FACTORY_DEFAULTS 0xffeeUL
#define HWRM_NVM_VALIDATE_OPTION 0xffefUL
@@ -471,6 +499,7 @@ struct ret_codes {
#define HWRM_ERR_CODE_HWRM_ERROR 0xfUL
#define HWRM_ERR_CODE_BUSY 0x10UL
#define HWRM_ERR_CODE_RESOURCE_LOCKED 0x11UL
+ #define HWRM_ERR_CODE_PF_UNAVAILABLE 0x12UL
#define HWRM_ERR_CODE_TLV_ENCAPSULATED_RESPONSE 0x8000UL
#define HWRM_ERR_CODE_UNKNOWN_ERR 0xfffeUL
#define HWRM_ERR_CODE_CMD_NOT_SUPPORTED 0xffffUL
@@ -502,8 +531,8 @@ struct hwrm_err_output {
#define HWRM_VERSION_MAJOR 1
#define HWRM_VERSION_MINOR 10
#define HWRM_VERSION_UPDATE 2
-#define HWRM_VERSION_RSVD 16
-#define HWRM_VERSION_STR "1.10.2.16"
+#define HWRM_VERSION_RSVD 47
+#define HWRM_VERSION_STR "1.10.2.47"
/* hwrm_ver_get_input (size:192b/24B) */
struct hwrm_ver_get_input {
@@ -604,7 +633,8 @@ struct hwrm_ver_get_output {
__le16 roce_fw_build;
__le16 roce_fw_patch;
__le16 max_ext_req_len;
- u8 unused_1[5];
+ __le16 max_req_timeout;
+ u8 unused_1[3];
u8 valid;
};
@@ -725,7 +755,10 @@ struct hwrm_async_event_cmpl {
#define ASYNC_EVENT_CMPL_EVENT_ID_DEFERRED_RESPONSE 0x40UL
#define ASYNC_EVENT_CMPL_EVENT_ID_PFC_WATCHDOG_CFG_CHANGE 0x41UL
#define ASYNC_EVENT_CMPL_EVENT_ID_ECHO_REQUEST 0x42UL
- #define ASYNC_EVENT_CMPL_EVENT_ID_MAX_RGTR_EVENT_ID 0x43UL
+ #define ASYNC_EVENT_CMPL_EVENT_ID_PHC_MASTER 0x43UL
+ #define ASYNC_EVENT_CMPL_EVENT_ID_PPS_TIMESTAMP 0x44UL
+ #define ASYNC_EVENT_CMPL_EVENT_ID_ERROR_REPORT 0x45UL
+ #define ASYNC_EVENT_CMPL_EVENT_ID_MAX_RGTR_EVENT_ID 0x46UL
#define ASYNC_EVENT_CMPL_EVENT_ID_FW_TRACE_MSG 0xfeUL
#define ASYNC_EVENT_CMPL_EVENT_ID_HWRM_ERROR 0xffUL
#define ASYNC_EVENT_CMPL_EVENT_ID_LAST ASYNC_EVENT_CMPL_EVENT_ID_HWRM_ERROR
@@ -919,6 +952,8 @@ struct hwrm_async_event_cmpl_vf_cfg_change {
#define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_ID_VF_CFG_CHANGE 0x33UL
#define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_ID_LAST ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_ID_VF_CFG_CHANGE
__le32 event_data2;
+ #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA2_VF_ID_MASK 0xffffUL
+ #define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_EVENT_DATA2_VF_ID_SFT 0
u8 opaque_v;
#define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_V 0x1UL
#define ASYNC_EVENT_CMPL_VF_CFG_CHANGE_OPAQUE_MASK 0xfeUL
@@ -1074,6 +1109,223 @@ struct hwrm_async_event_cmpl_echo_request {
__le32 event_data1;
};
+/* hwrm_async_event_cmpl_phc_master (size:128b/16B) */
+struct hwrm_async_event_cmpl_phc_master {
+ __le16 type;
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_TYPE_MASK 0x3fUL
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_TYPE_SFT 0
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_TYPE_HWRM_ASYNC_EVENT 0x2eUL
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_TYPE_LAST ASYNC_EVENT_CMPL_PHC_MASTER_TYPE_HWRM_ASYNC_EVENT
+ __le16 event_id;
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_EVENT_ID_PHC_MASTER 0x43UL
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_EVENT_ID_LAST ASYNC_EVENT_CMPL_PHC_MASTER_EVENT_ID_PHC_MASTER
+ __le32 event_data2;
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_EVENT_DATA2_PHC_MASTER_FID_MASK 0xffffUL
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_EVENT_DATA2_PHC_MASTER_FID_SFT 0
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_EVENT_DATA2_PHC_SEC_FID_MASK 0xffff0000UL
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_EVENT_DATA2_PHC_SEC_FID_SFT 16
+ u8 opaque_v;
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_V 0x1UL
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_OPAQUE_MASK 0xfeUL
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_OPAQUE_SFT 1
+ u8 timestamp_lo;
+ __le16 timestamp_hi;
+ __le32 event_data1;
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_EVENT_DATA1_FLAGS_MASK 0xfUL
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_EVENT_DATA1_FLAGS_SFT 0
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_EVENT_DATA1_FLAGS_PHC_MASTER 0x1UL
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_EVENT_DATA1_FLAGS_PHC_SECONDARY 0x2UL
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_EVENT_DATA1_FLAGS_PHC_FAILOVER 0x3UL
+ #define ASYNC_EVENT_CMPL_PHC_MASTER_EVENT_DATA1_FLAGS_LAST ASYNC_EVENT_CMPL_PHC_MASTER_EVENT_DATA1_FLAGS_PHC_FAILOVER
+};
+
+/* hwrm_async_event_cmpl_pps_timestamp (size:128b/16B) */
+struct hwrm_async_event_cmpl_pps_timestamp {
+ __le16 type;
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_TYPE_MASK 0x3fUL
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_TYPE_SFT 0
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_TYPE_HWRM_ASYNC_EVENT 0x2eUL
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_TYPE_LAST ASYNC_EVENT_CMPL_PPS_TIMESTAMP_TYPE_HWRM_ASYNC_EVENT
+ __le16 event_id;
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_ID_PPS_TIMESTAMP 0x44UL
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_ID_LAST ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_ID_PPS_TIMESTAMP
+ __le32 event_data2;
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_EVENT_TYPE 0x1UL
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_EVENT_TYPE_INTERNAL 0x0UL
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_EVENT_TYPE_EXTERNAL 0x1UL
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_EVENT_TYPE_LAST ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_EVENT_TYPE_EXTERNAL
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_PIN_NUMBER_MASK 0xeUL
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_PIN_NUMBER_SFT 1
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_PPS_TIMESTAMP_UPPER_MASK 0xffff0UL
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_PPS_TIMESTAMP_UPPER_SFT 4
+ u8 opaque_v;
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_V 0x1UL
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_OPAQUE_MASK 0xfeUL
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_OPAQUE_SFT 1
+ u8 timestamp_lo;
+ __le16 timestamp_hi;
+ __le32 event_data1;
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA1_PPS_TIMESTAMP_LOWER_MASK 0xffffffffUL
+ #define ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA1_PPS_TIMESTAMP_LOWER_SFT 0
+};
+
+/* hwrm_async_event_cmpl_error_report (size:128b/16B) */
+struct hwrm_async_event_cmpl_error_report {
+ __le16 type;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_TYPE_MASK 0x3fUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_TYPE_SFT 0
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_TYPE_HWRM_ASYNC_EVENT 0x2eUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_TYPE_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_TYPE_HWRM_ASYNC_EVENT
+ __le16 event_id;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_EVENT_ID_ERROR_REPORT 0x45UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_EVENT_ID_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_EVENT_ID_ERROR_REPORT
+ __le32 event_data2;
+ u8 opaque_v;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_V 0x1UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_OPAQUE_MASK 0xfeUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_OPAQUE_SFT 1
+ u8 timestamp_lo;
+ __le16 timestamp_hi;
+ __le32 event_data1;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_EVENT_DATA1_ERROR_TYPE_MASK 0xffUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_EVENT_DATA1_ERROR_TYPE_SFT 0
+};
+
+/* hwrm_async_event_cmpl_hwrm_error (size:128b/16B) */
+struct hwrm_async_event_cmpl_hwrm_error {
+ __le16 type;
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_TYPE_MASK 0x3fUL
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_TYPE_SFT 0
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_TYPE_HWRM_ASYNC_EVENT 0x2eUL
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_TYPE_LAST ASYNC_EVENT_CMPL_HWRM_ERROR_TYPE_HWRM_ASYNC_EVENT
+ __le16 event_id;
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_EVENT_ID_HWRM_ERROR 0xffUL
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_EVENT_ID_LAST ASYNC_EVENT_CMPL_HWRM_ERROR_EVENT_ID_HWRM_ERROR
+ __le32 event_data2;
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_EVENT_DATA2_SEVERITY_MASK 0xffUL
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_EVENT_DATA2_SEVERITY_SFT 0
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_EVENT_DATA2_SEVERITY_WARNING 0x0UL
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_EVENT_DATA2_SEVERITY_NONFATAL 0x1UL
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_EVENT_DATA2_SEVERITY_FATAL 0x2UL
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_EVENT_DATA2_SEVERITY_LAST ASYNC_EVENT_CMPL_HWRM_ERROR_EVENT_DATA2_SEVERITY_FATAL
+ u8 opaque_v;
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_V 0x1UL
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_OPAQUE_MASK 0xfeUL
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_OPAQUE_SFT 1
+ u8 timestamp_lo;
+ __le16 timestamp_hi;
+ __le32 event_data1;
+ #define ASYNC_EVENT_CMPL_HWRM_ERROR_EVENT_DATA1_TIMESTAMP 0x1UL
+};
+
+/* hwrm_async_event_cmpl_error_report_base (size:128b/16B) */
+struct hwrm_async_event_cmpl_error_report_base {
+ __le16 type;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_TYPE_MASK 0x3fUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_TYPE_SFT 0
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_TYPE_HWRM_ASYNC_EVENT 0x2eUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_TYPE_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_TYPE_HWRM_ASYNC_EVENT
+ __le16 event_id;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_ID_ERROR_REPORT 0x45UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_ID_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_ID_ERROR_REPORT
+ __le32 event_data2;
+ u8 opaque_v;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_V 0x1UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_OPAQUE_MASK 0xfeUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_OPAQUE_SFT 1
+ u8 timestamp_lo;
+ __le16 timestamp_hi;
+ __le32 event_data1;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_MASK 0xffUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_SFT 0
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_RESERVED 0x0UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_PAUSE_STORM 0x1UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_INVALID_SIGNAL 0x2UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_NVM 0x3UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_NVM
+};
+
+/* hwrm_async_event_cmpl_error_report_pause_storm (size:128b/16B) */
+struct hwrm_async_event_cmpl_error_report_pause_storm {
+ __le16 type;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_TYPE_MASK 0x3fUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_TYPE_SFT 0
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_TYPE_HWRM_ASYNC_EVENT 0x2eUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_TYPE_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_TYPE_HWRM_ASYNC_EVENT
+ __le16 event_id;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_EVENT_ID_ERROR_REPORT 0x45UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_EVENT_ID_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_EVENT_ID_ERROR_REPORT
+ __le32 event_data2;
+ u8 opaque_v;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_V 0x1UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_OPAQUE_MASK 0xfeUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_OPAQUE_SFT 1
+ u8 timestamp_lo;
+ __le16 timestamp_hi;
+ __le32 event_data1;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_EVENT_DATA1_ERROR_TYPE_MASK 0xffUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_EVENT_DATA1_ERROR_TYPE_SFT 0
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_EVENT_DATA1_ERROR_TYPE_PAUSE_STORM 0x1UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_EVENT_DATA1_ERROR_TYPE_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_PAUSE_STORM_EVENT_DATA1_ERROR_TYPE_PAUSE_STORM
+};
+
+/* hwrm_async_event_cmpl_error_report_invalid_signal (size:128b/16B) */
+struct hwrm_async_event_cmpl_error_report_invalid_signal {
+ __le16 type;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_TYPE_MASK 0x3fUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_TYPE_SFT 0
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_TYPE_HWRM_ASYNC_EVENT 0x2eUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_TYPE_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_TYPE_HWRM_ASYNC_EVENT
+ __le16 event_id;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_EVENT_ID_ERROR_REPORT 0x45UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_EVENT_ID_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_EVENT_ID_ERROR_REPORT
+ __le32 event_data2;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_EVENT_DATA2_PIN_ID_MASK 0xffUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_EVENT_DATA2_PIN_ID_SFT 0
+ u8 opaque_v;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_V 0x1UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_OPAQUE_MASK 0xfeUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_OPAQUE_SFT 1
+ u8 timestamp_lo;
+ __le16 timestamp_hi;
+ __le32 event_data1;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_EVENT_DATA1_ERROR_TYPE_MASK 0xffUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_EVENT_DATA1_ERROR_TYPE_SFT 0
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_EVENT_DATA1_ERROR_TYPE_INVALID_SIGNAL 0x2UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_EVENT_DATA1_ERROR_TYPE_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_EVENT_DATA1_ERROR_TYPE_INVALID_SIGNAL
+};
+
+/* hwrm_async_event_cmpl_error_report_nvm (size:128b/16B) */
+struct hwrm_async_event_cmpl_error_report_nvm {
+ __le16 type;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_TYPE_MASK 0x3fUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_TYPE_SFT 0
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_TYPE_HWRM_ASYNC_EVENT 0x2eUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_TYPE_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_TYPE_HWRM_ASYNC_EVENT
+ __le16 event_id;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_ID_ERROR_REPORT 0x45UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_ID_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_ID_ERROR_REPORT
+ __le32 event_data2;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_DATA2_ERR_ADDR_MASK 0xffffffffUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_DATA2_ERR_ADDR_SFT 0
+ u8 opaque_v;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_V 0x1UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_OPAQUE_MASK 0xfeUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_OPAQUE_SFT 1
+ u8 timestamp_lo;
+ __le16 timestamp_hi;
+ __le32 event_data1;
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_DATA1_ERROR_TYPE_MASK 0xffUL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_DATA1_ERROR_TYPE_SFT 0
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_DATA1_ERROR_TYPE_NVM_ERROR 0x3UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_DATA1_ERROR_TYPE_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_DATA1_ERROR_TYPE_NVM_ERROR
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_DATA1_NVM_ERR_TYPE_MASK 0xff00UL
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_DATA1_NVM_ERR_TYPE_SFT 8
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_DATA1_NVM_ERR_TYPE_WRITE (0x1UL << 8)
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_DATA1_NVM_ERR_TYPE_ERASE (0x2UL << 8)
+ #define ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_DATA1_NVM_ERR_TYPE_LAST ASYNC_EVENT_CMPL_ERROR_REPORT_NVM_EVENT_DATA1_NVM_ERR_TYPE_ERASE
+};
+
/* hwrm_func_reset_input (size:192b/24B) */
struct hwrm_func_reset_input {
__le16 req_type;
@@ -1302,7 +1554,7 @@ struct hwrm_func_qcaps_output {
__le32 max_flow_id;
__le32 max_hw_ring_grps;
__le16 max_sp_tx_rings;
- u8 unused_0[2];
+ __le16 max_msix_vfs;
__le32 flags_ext;
#define FUNC_QCAPS_RESP_FLAGS_EXT_ECN_MARK_SUPPORTED 0x1UL
#define FUNC_QCAPS_RESP_FLAGS_EXT_ECN_STATS_SUPPORTED 0x2UL
@@ -1320,6 +1572,14 @@ struct hwrm_func_qcaps_output {
#define FUNC_QCAPS_RESP_FLAGS_EXT_NVM_OPTION_ACTION_SUPPORTED 0x2000UL
#define FUNC_QCAPS_RESP_FLAGS_EXT_BD_METADATA_SUPPORTED 0x4000UL
#define FUNC_QCAPS_RESP_FLAGS_EXT_ECHO_REQUEST_SUPPORTED 0x8000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT_NPAR_1_2_SUPPORTED 0x10000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT_PTP_PTM_SUPPORTED 0x20000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT_PTP_PPS_SUPPORTED 0x40000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT_VF_CFG_ASYNC_FOR_PF_SUPPORTED 0x80000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT_PARTITION_BW_SUPPORTED 0x100000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT_DFLT_VLAN_TPID_PCP_SUPPORTED 0x200000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT_KTLS_SUPPORTED 0x400000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT_EP_RATE_CONTROL 0x800000UL
u8 max_schqs;
u8 mpc_chnls_cap;
#define FUNC_QCAPS_RESP_MPC_CHNLS_CAP_TCE 0x1UL
@@ -1342,7 +1602,7 @@ struct hwrm_func_qcfg_input {
u8 unused_0[6];
};
-/* hwrm_func_qcfg_output (size:768b/96B) */
+/* hwrm_func_qcfg_output (size:832b/104B) */
struct hwrm_func_qcfg_output {
__le16 error_code;
__le16 req_type;
@@ -1366,6 +1626,7 @@ struct hwrm_func_qcfg_output {
#define FUNC_QCFG_RESP_FLAGS_RING_MONITOR_ENABLED 0x800UL
#define FUNC_QCFG_RESP_FLAGS_FAST_RESET_ALLOWED 0x1000UL
#define FUNC_QCFG_RESP_FLAGS_MULTI_ROOT 0x2000UL
+ #define FUNC_QCFG_RESP_FLAGS_ENABLE_RDMA_SRIOV 0x4000UL
u8 mac_address[6];
__le16 pci_id;
__le16 alloc_rsscos_ctx;
@@ -1374,7 +1635,7 @@ struct hwrm_func_qcfg_output {
__le16 alloc_rx_rings;
__le16 alloc_l2_ctx;
__le16 alloc_vnics;
- __le16 mtu;
+ __le16 admin_mtu;
__le16 mru;
__le16 stat_ctx_id;
u8 port_partition_type;
@@ -1383,6 +1644,7 @@ struct hwrm_func_qcfg_output {
#define FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR1_0 0x2UL
#define FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR1_5 0x3UL
#define FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR2_0 0x4UL
+ #define FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR1_2 0x5UL
#define FUNC_QCFG_RESP_PORT_PARTITION_TYPE_UNKNOWN 0xffUL
#define FUNC_QCFG_RESP_PORT_PARTITION_TYPE_LAST FUNC_QCFG_RESP_PORT_PARTITION_TYPE_UNKNOWN
u8 port_pf_cnt;
@@ -1463,11 +1725,35 @@ struct hwrm_func_qcfg_output {
#define FUNC_QCFG_RESP_MPC_CHNLS_TE_CFA_ENABLED 0x4UL
#define FUNC_QCFG_RESP_MPC_CHNLS_RE_CFA_ENABLED 0x8UL
#define FUNC_QCFG_RESP_MPC_CHNLS_PRIMATE_ENABLED 0x10UL
- u8 unused_2[6];
+ u8 unused_2[3];
+ __le32 partition_min_bw;
+ #define FUNC_QCFG_RESP_PARTITION_MIN_BW_BW_VALUE_MASK 0xfffffffUL
+ #define FUNC_QCFG_RESP_PARTITION_MIN_BW_BW_VALUE_SFT 0
+ #define FUNC_QCFG_RESP_PARTITION_MIN_BW_SCALE 0x10000000UL
+ #define FUNC_QCFG_RESP_PARTITION_MIN_BW_SCALE_BITS (0x0UL << 28)
+ #define FUNC_QCFG_RESP_PARTITION_MIN_BW_SCALE_BYTES (0x1UL << 28)
+ #define FUNC_QCFG_RESP_PARTITION_MIN_BW_SCALE_LAST FUNC_QCFG_RESP_PARTITION_MIN_BW_SCALE_BYTES
+ #define FUNC_QCFG_RESP_PARTITION_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
+ #define FUNC_QCFG_RESP_PARTITION_MIN_BW_BW_VALUE_UNIT_SFT 29
+ #define FUNC_QCFG_RESP_PARTITION_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
+ #define FUNC_QCFG_RESP_PARTITION_MIN_BW_BW_VALUE_UNIT_LAST FUNC_QCFG_RESP_PARTITION_MIN_BW_BW_VALUE_UNIT_PERCENT1_100
+ __le32 partition_max_bw;
+ #define FUNC_QCFG_RESP_PARTITION_MAX_BW_BW_VALUE_MASK 0xfffffffUL
+ #define FUNC_QCFG_RESP_PARTITION_MAX_BW_BW_VALUE_SFT 0
+ #define FUNC_QCFG_RESP_PARTITION_MAX_BW_SCALE 0x10000000UL
+ #define FUNC_QCFG_RESP_PARTITION_MAX_BW_SCALE_BITS (0x0UL << 28)
+ #define FUNC_QCFG_RESP_PARTITION_MAX_BW_SCALE_BYTES (0x1UL << 28)
+ #define FUNC_QCFG_RESP_PARTITION_MAX_BW_SCALE_LAST FUNC_QCFG_RESP_PARTITION_MAX_BW_SCALE_BYTES
+ #define FUNC_QCFG_RESP_PARTITION_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
+ #define FUNC_QCFG_RESP_PARTITION_MAX_BW_BW_VALUE_UNIT_SFT 29
+ #define FUNC_QCFG_RESP_PARTITION_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
+ #define FUNC_QCFG_RESP_PARTITION_MAX_BW_BW_VALUE_UNIT_LAST FUNC_QCFG_RESP_PARTITION_MAX_BW_BW_VALUE_UNIT_PERCENT1_100
+ __le16 host_mtu;
+ u8 unused_3;
u8 valid;
};
-/* hwrm_func_cfg_input (size:768b/96B) */
+/* hwrm_func_cfg_input (size:832b/104B) */
struct hwrm_func_cfg_input {
__le16 req_type;
__le16 cmpl_ring;
@@ -1504,7 +1790,7 @@ struct hwrm_func_cfg_input {
#define FUNC_CFG_REQ_FLAGS_BD_METADATA_ENABLE 0x20000000UL
#define FUNC_CFG_REQ_FLAGS_BD_METADATA_DISABLE 0x40000000UL
__le32 enables;
- #define FUNC_CFG_REQ_ENABLES_MTU 0x1UL
+ #define FUNC_CFG_REQ_ENABLES_ADMIN_MTU 0x1UL
#define FUNC_CFG_REQ_ENABLES_MRU 0x2UL
#define FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS 0x4UL
#define FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS 0x8UL
@@ -1530,7 +1816,11 @@ struct hwrm_func_cfg_input {
#define FUNC_CFG_REQ_ENABLES_HOT_RESET_IF_SUPPORT 0x800000UL
#define FUNC_CFG_REQ_ENABLES_SCHQ_ID 0x1000000UL
#define FUNC_CFG_REQ_ENABLES_MPC_CHNLS 0x2000000UL
- __le16 mtu;
+ #define FUNC_CFG_REQ_ENABLES_PARTITION_MIN_BW 0x4000000UL
+ #define FUNC_CFG_REQ_ENABLES_PARTITION_MAX_BW 0x8000000UL
+ #define FUNC_CFG_REQ_ENABLES_TPID 0x10000000UL
+ #define FUNC_CFG_REQ_ENABLES_HOST_MTU 0x20000000UL
+ __le16 admin_mtu;
__le16 mru;
__le16 num_rsscos_ctxs;
__le16 num_cmpl_rings;
@@ -1615,7 +1905,30 @@ struct hwrm_func_cfg_input {
#define FUNC_CFG_REQ_MPC_CHNLS_RE_CFA_DISABLE 0x80UL
#define FUNC_CFG_REQ_MPC_CHNLS_PRIMATE_ENABLE 0x100UL
#define FUNC_CFG_REQ_MPC_CHNLS_PRIMATE_DISABLE 0x200UL
- u8 unused_0[4];
+ __le32 partition_min_bw;
+ #define FUNC_CFG_REQ_PARTITION_MIN_BW_BW_VALUE_MASK 0xfffffffUL
+ #define FUNC_CFG_REQ_PARTITION_MIN_BW_BW_VALUE_SFT 0
+ #define FUNC_CFG_REQ_PARTITION_MIN_BW_SCALE 0x10000000UL
+ #define FUNC_CFG_REQ_PARTITION_MIN_BW_SCALE_BITS (0x0UL << 28)
+ #define FUNC_CFG_REQ_PARTITION_MIN_BW_SCALE_BYTES (0x1UL << 28)
+ #define FUNC_CFG_REQ_PARTITION_MIN_BW_SCALE_LAST FUNC_CFG_REQ_PARTITION_MIN_BW_SCALE_BYTES
+ #define FUNC_CFG_REQ_PARTITION_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
+ #define FUNC_CFG_REQ_PARTITION_MIN_BW_BW_VALUE_UNIT_SFT 29
+ #define FUNC_CFG_REQ_PARTITION_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
+ #define FUNC_CFG_REQ_PARTITION_MIN_BW_BW_VALUE_UNIT_LAST FUNC_CFG_REQ_PARTITION_MIN_BW_BW_VALUE_UNIT_PERCENT1_100
+ __le32 partition_max_bw;
+ #define FUNC_CFG_REQ_PARTITION_MAX_BW_BW_VALUE_MASK 0xfffffffUL
+ #define FUNC_CFG_REQ_PARTITION_MAX_BW_BW_VALUE_SFT 0
+ #define FUNC_CFG_REQ_PARTITION_MAX_BW_SCALE 0x10000000UL
+ #define FUNC_CFG_REQ_PARTITION_MAX_BW_SCALE_BITS (0x0UL << 28)
+ #define FUNC_CFG_REQ_PARTITION_MAX_BW_SCALE_BYTES (0x1UL << 28)
+ #define FUNC_CFG_REQ_PARTITION_MAX_BW_SCALE_LAST FUNC_CFG_REQ_PARTITION_MAX_BW_SCALE_BYTES
+ #define FUNC_CFG_REQ_PARTITION_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
+ #define FUNC_CFG_REQ_PARTITION_MAX_BW_BW_VALUE_UNIT_SFT 29
+ #define FUNC_CFG_REQ_PARTITION_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
+ #define FUNC_CFG_REQ_PARTITION_MAX_BW_BW_VALUE_UNIT_LAST FUNC_CFG_REQ_PARTITION_MAX_BW_BW_VALUE_UNIT_PERCENT1_100
+ __be16 tpid;
+ __le16 host_mtu;
};
/* hwrm_func_cfg_output (size:128b/16B) */
@@ -1777,14 +2090,15 @@ struct hwrm_func_drv_rgtr_input {
__le16 target_id;
__le64 resp_addr;
__le32 flags;
- #define FUNC_DRV_RGTR_REQ_FLAGS_FWD_ALL_MODE 0x1UL
- #define FUNC_DRV_RGTR_REQ_FLAGS_FWD_NONE_MODE 0x2UL
- #define FUNC_DRV_RGTR_REQ_FLAGS_16BIT_VER_MODE 0x4UL
- #define FUNC_DRV_RGTR_REQ_FLAGS_FLOW_HANDLE_64BIT_MODE 0x8UL
- #define FUNC_DRV_RGTR_REQ_FLAGS_HOT_RESET_SUPPORT 0x10UL
- #define FUNC_DRV_RGTR_REQ_FLAGS_ERROR_RECOVERY_SUPPORT 0x20UL
- #define FUNC_DRV_RGTR_REQ_FLAGS_MASTER_SUPPORT 0x40UL
- #define FUNC_DRV_RGTR_REQ_FLAGS_FAST_RESET_SUPPORT 0x80UL
+ #define FUNC_DRV_RGTR_REQ_FLAGS_FWD_ALL_MODE 0x1UL
+ #define FUNC_DRV_RGTR_REQ_FLAGS_FWD_NONE_MODE 0x2UL
+ #define FUNC_DRV_RGTR_REQ_FLAGS_16BIT_VER_MODE 0x4UL
+ #define FUNC_DRV_RGTR_REQ_FLAGS_FLOW_HANDLE_64BIT_MODE 0x8UL
+ #define FUNC_DRV_RGTR_REQ_FLAGS_HOT_RESET_SUPPORT 0x10UL
+ #define FUNC_DRV_RGTR_REQ_FLAGS_ERROR_RECOVERY_SUPPORT 0x20UL
+ #define FUNC_DRV_RGTR_REQ_FLAGS_MASTER_SUPPORT 0x40UL
+ #define FUNC_DRV_RGTR_REQ_FLAGS_FAST_RESET_SUPPORT 0x80UL
+ #define FUNC_DRV_RGTR_REQ_FLAGS_RSS_STRICT_HASH_TYPE_SUPPORT 0x100UL
__le32 enables;
#define FUNC_DRV_RGTR_REQ_ENABLES_OS_TYPE 0x1UL
#define FUNC_DRV_RGTR_REQ_ENABLES_VER 0x2UL
@@ -2047,7 +2361,7 @@ struct hwrm_func_backing_store_qcaps_input {
__le64 resp_addr;
};
-/* hwrm_func_backing_store_qcaps_output (size:704b/88B) */
+/* hwrm_func_backing_store_qcaps_output (size:832b/104B) */
struct hwrm_func_backing_store_qcaps_output {
__le16 error_code;
__le16 req_type;
@@ -2085,6 +2399,8 @@ struct hwrm_func_backing_store_qcaps_output {
#define FUNC_BACKING_STORE_QCAPS_RESP_CTX_INIT_MASK_VNIC 0x8UL
#define FUNC_BACKING_STORE_QCAPS_RESP_CTX_INIT_MASK_STAT 0x10UL
#define FUNC_BACKING_STORE_QCAPS_RESP_CTX_INIT_MASK_MRAV 0x20UL
+ #define FUNC_BACKING_STORE_QCAPS_RESP_CTX_INIT_MASK_TKC 0x40UL
+ #define FUNC_BACKING_STORE_QCAPS_RESP_CTX_INIT_MASK_RKC 0x80UL
u8 qp_init_offset;
u8 srq_init_offset;
u8 cq_init_offset;
@@ -2093,7 +2409,13 @@ struct hwrm_func_backing_store_qcaps_output {
u8 stat_init_offset;
u8 mrav_init_offset;
u8 tqm_fp_rings_count_ext;
- u8 rsvd[5];
+ u8 tkc_init_offset;
+ u8 rkc_init_offset;
+ __le16 tkc_entry_size;
+ __le16 rkc_entry_size;
+ __le32 tkc_max_entries;
+ __le32 rkc_max_entries;
+ u8 rsvd[7];
u8 valid;
};
@@ -2120,7 +2442,7 @@ struct tqm_fp_ring_cfg {
__le64 tqm_ring_page_dir;
};
-/* hwrm_func_backing_store_cfg_input (size:2432b/304B) */
+/* hwrm_func_backing_store_cfg_input (size:2688b/336B) */
struct hwrm_func_backing_store_cfg_input {
__le16 req_type;
__le16 cmpl_ring;
@@ -2150,6 +2472,8 @@ struct hwrm_func_backing_store_cfg_input {
#define FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_RING8 0x10000UL
#define FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_RING9 0x20000UL
#define FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_RING10 0x40000UL
+ #define FUNC_BACKING_STORE_CFG_REQ_ENABLES_TKC 0x80000UL
+ #define FUNC_BACKING_STORE_CFG_REQ_ENABLES_RKC 0x100000UL
u8 qpc_pg_size_qpc_lvl;
#define FUNC_BACKING_STORE_CFG_REQ_QPC_LVL_MASK 0xfUL
#define FUNC_BACKING_STORE_CFG_REQ_QPC_LVL_SFT 0
@@ -2508,6 +2832,45 @@ struct hwrm_func_backing_store_cfg_input {
u8 ring10_unused[3];
__le32 tqm_ring10_num_entries;
__le64 tqm_ring10_page_dir;
+ __le32 tkc_num_entries;
+ __le32 rkc_num_entries;
+ __le64 tkc_page_dir;
+ __le64 rkc_page_dir;
+ __le16 tkc_entry_size;
+ __le16 rkc_entry_size;
+ u8 tkc_pg_size_tkc_lvl;
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_LVL_MASK 0xfUL
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_LVL_SFT 0
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_LVL_LVL_0 0x0UL
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_LVL_LVL_1 0x1UL
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_LVL_LVL_2 0x2UL
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_LVL_LAST FUNC_BACKING_STORE_CFG_REQ_TKC_LVL_LVL_2
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_PG_SIZE_MASK 0xf0UL
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_PG_SIZE_SFT 4
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_PG_SIZE_PG_4K (0x0UL << 4)
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_PG_SIZE_PG_8K (0x1UL << 4)
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_PG_SIZE_PG_64K (0x2UL << 4)
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_PG_SIZE_PG_2M (0x3UL << 4)
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_PG_SIZE_PG_8M (0x4UL << 4)
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_PG_SIZE_PG_1G (0x5UL << 4)
+ #define FUNC_BACKING_STORE_CFG_REQ_TKC_PG_SIZE_LAST FUNC_BACKING_STORE_CFG_REQ_TKC_PG_SIZE_PG_1G
+ u8 rkc_pg_size_rkc_lvl;
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_LVL_MASK 0xfUL
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_LVL_SFT 0
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_LVL_LVL_0 0x0UL
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_LVL_LVL_1 0x1UL
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_LVL_LVL_2 0x2UL
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_LVL_LAST FUNC_BACKING_STORE_CFG_REQ_RKC_LVL_LVL_2
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_PG_SIZE_MASK 0xf0UL
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_PG_SIZE_SFT 4
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_PG_SIZE_PG_4K (0x0UL << 4)
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_PG_SIZE_PG_8K (0x1UL << 4)
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_PG_SIZE_PG_64K (0x2UL << 4)
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_PG_SIZE_PG_2M (0x3UL << 4)
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_PG_SIZE_PG_8M (0x4UL << 4)
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_PG_SIZE_PG_1G (0x5UL << 4)
+ #define FUNC_BACKING_STORE_CFG_REQ_RKC_PG_SIZE_LAST FUNC_BACKING_STORE_CFG_REQ_RKC_PG_SIZE_PG_1G
+ u8 rsvd[2];
};
/* hwrm_func_backing_store_cfg_output (size:128b/16B) */
@@ -2634,6 +2997,212 @@ struct hwrm_func_echo_response_output {
u8 valid;
};
+/* hwrm_func_ptp_pin_qcfg_input (size:192b/24B) */
+struct hwrm_func_ptp_pin_qcfg_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ u8 unused_0[8];
+};
+
+/* hwrm_func_ptp_pin_qcfg_output (size:128b/16B) */
+struct hwrm_func_ptp_pin_qcfg_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ u8 num_pins;
+ u8 state;
+ #define FUNC_PTP_PIN_QCFG_RESP_STATE_PIN0_ENABLED 0x1UL
+ #define FUNC_PTP_PIN_QCFG_RESP_STATE_PIN1_ENABLED 0x2UL
+ #define FUNC_PTP_PIN_QCFG_RESP_STATE_PIN2_ENABLED 0x4UL
+ #define FUNC_PTP_PIN_QCFG_RESP_STATE_PIN3_ENABLED 0x8UL
+ u8 pin0_usage;
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN0_USAGE_NONE 0x0UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN0_USAGE_PPS_IN 0x1UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN0_USAGE_PPS_OUT 0x2UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN0_USAGE_SYNC_IN 0x3UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN0_USAGE_SYNC_OUT 0x4UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN0_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN0_USAGE_SYNC_OUT
+ u8 pin1_usage;
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_NONE 0x0UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_PPS_IN 0x1UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_PPS_OUT 0x2UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_SYNC_IN 0x3UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_SYNC_OUT 0x4UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN1_USAGE_SYNC_OUT
+ u8 pin2_usage;
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_NONE 0x0UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_PPS_IN 0x1UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_PPS_OUT 0x2UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_IN 0x3UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_OUT 0x4UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN2_USAGE_SYNC_OUT
+ u8 pin3_usage;
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_NONE 0x0UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_PPS_IN 0x1UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_PPS_OUT 0x2UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_IN 0x3UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_OUT 0x4UL
+ #define FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_LAST FUNC_PTP_PIN_QCFG_RESP_PIN3_USAGE_SYNC_OUT
+ u8 unused_0;
+ u8 valid;
+};
+
+/* hwrm_func_ptp_pin_cfg_input (size:256b/32B) */
+struct hwrm_func_ptp_pin_cfg_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 enables;
+ #define FUNC_PTP_PIN_CFG_REQ_ENABLES_PIN0_STATE 0x1UL
+ #define FUNC_PTP_PIN_CFG_REQ_ENABLES_PIN0_USAGE 0x2UL
+ #define FUNC_PTP_PIN_CFG_REQ_ENABLES_PIN1_STATE 0x4UL
+ #define FUNC_PTP_PIN_CFG_REQ_ENABLES_PIN1_USAGE 0x8UL
+ #define FUNC_PTP_PIN_CFG_REQ_ENABLES_PIN2_STATE 0x10UL
+ #define FUNC_PTP_PIN_CFG_REQ_ENABLES_PIN2_USAGE 0x20UL
+ #define FUNC_PTP_PIN_CFG_REQ_ENABLES_PIN3_STATE 0x40UL
+ #define FUNC_PTP_PIN_CFG_REQ_ENABLES_PIN3_USAGE 0x80UL
+ u8 pin0_state;
+ #define FUNC_PTP_PIN_CFG_REQ_PIN0_STATE_DISABLED 0x0UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN0_STATE_ENABLED 0x1UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN0_STATE_LAST FUNC_PTP_PIN_CFG_REQ_PIN0_STATE_ENABLED
+ u8 pin0_usage;
+ #define FUNC_PTP_PIN_CFG_REQ_PIN0_USAGE_NONE 0x0UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN0_USAGE_PPS_IN 0x1UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN0_USAGE_PPS_OUT 0x2UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN0_USAGE_SYNC_IN 0x3UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN0_USAGE_SYNC_OUT 0x4UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN0_USAGE_LAST FUNC_PTP_PIN_CFG_REQ_PIN0_USAGE_SYNC_OUT
+ u8 pin1_state;
+ #define FUNC_PTP_PIN_CFG_REQ_PIN1_STATE_DISABLED 0x0UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN1_STATE_ENABLED 0x1UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN1_STATE_LAST FUNC_PTP_PIN_CFG_REQ_PIN1_STATE_ENABLED
+ u8 pin1_usage;
+ #define FUNC_PTP_PIN_CFG_REQ_PIN1_USAGE_NONE 0x0UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN1_USAGE_PPS_IN 0x1UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN1_USAGE_PPS_OUT 0x2UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN1_USAGE_SYNC_IN 0x3UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN1_USAGE_SYNC_OUT 0x4UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN1_USAGE_LAST FUNC_PTP_PIN_CFG_REQ_PIN1_USAGE_SYNC_OUT
+ u8 pin2_state;
+ #define FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_DISABLED 0x0UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_ENABLED 0x1UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_LAST FUNC_PTP_PIN_CFG_REQ_PIN2_STATE_ENABLED
+ u8 pin2_usage;
+ #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_NONE 0x0UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_PPS_IN 0x1UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_PPS_OUT 0x2UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_IN 0x3UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_OUT 0x4UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_LAST FUNC_PTP_PIN_CFG_REQ_PIN2_USAGE_SYNC_OUT
+ u8 pin3_state;
+ #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_DISABLED 0x0UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_ENABLED 0x1UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_LAST FUNC_PTP_PIN_CFG_REQ_PIN3_STATE_ENABLED
+ u8 pin3_usage;
+ #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_NONE 0x0UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_PPS_IN 0x1UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_PPS_OUT 0x2UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_IN 0x3UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_OUT 0x4UL
+ #define FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_LAST FUNC_PTP_PIN_CFG_REQ_PIN3_USAGE_SYNC_OUT
+ u8 unused_0[4];
+};
+
+/* hwrm_func_ptp_pin_cfg_output (size:128b/16B) */
+struct hwrm_func_ptp_pin_cfg_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ u8 unused_0[7];
+ u8 valid;
+};
+
+/* hwrm_func_ptp_cfg_input (size:320b/40B) */
+struct hwrm_func_ptp_cfg_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le16 enables;
+ #define FUNC_PTP_CFG_REQ_ENABLES_PTP_PPS_EVENT 0x1UL
+ #define FUNC_PTP_CFG_REQ_ENABLES_PTP_FREQ_ADJ_DLL_SOURCE 0x2UL
+ #define FUNC_PTP_CFG_REQ_ENABLES_PTP_FREQ_ADJ_DLL_PHASE 0x4UL
+ #define FUNC_PTP_CFG_REQ_ENABLES_PTP_FREQ_ADJ_EXT_PERIOD 0x8UL
+ #define FUNC_PTP_CFG_REQ_ENABLES_PTP_FREQ_ADJ_EXT_UP 0x10UL
+ #define FUNC_PTP_CFG_REQ_ENABLES_PTP_FREQ_ADJ_EXT_PHASE 0x20UL
+ u8 ptp_pps_event;
+ #define FUNC_PTP_CFG_REQ_PTP_PPS_EVENT_INTERNAL 0x1UL
+ #define FUNC_PTP_CFG_REQ_PTP_PPS_EVENT_EXTERNAL 0x2UL
+ u8 ptp_freq_adj_dll_source;
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_SOURCE_NONE 0x0UL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_SOURCE_TSIO_0 0x1UL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_SOURCE_TSIO_1 0x2UL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_SOURCE_TSIO_2 0x3UL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_SOURCE_TSIO_3 0x4UL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_SOURCE_PORT_0 0x5UL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_SOURCE_PORT_1 0x6UL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_SOURCE_PORT_2 0x7UL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_SOURCE_PORT_3 0x8UL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_SOURCE_INVALID 0xffUL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_SOURCE_LAST FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_SOURCE_INVALID
+ u8 ptp_freq_adj_dll_phase;
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_NONE 0x0UL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_4K 0x1UL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_8K 0x2UL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_10M 0x3UL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_LAST FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_10M
+ u8 unused_0[3];
+ __le32 ptp_freq_adj_ext_period;
+ __le32 ptp_freq_adj_ext_up;
+ __le32 ptp_freq_adj_ext_phase_lower;
+ __le32 ptp_freq_adj_ext_phase_upper;
+};
+
+/* hwrm_func_ptp_cfg_output (size:128b/16B) */
+struct hwrm_func_ptp_cfg_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ u8 unused_0[7];
+ u8 valid;
+};
+
+/* hwrm_func_ptp_ts_query_input (size:192b/24B) */
+struct hwrm_func_ptp_ts_query_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le32 flags;
+ #define FUNC_PTP_TS_QUERY_REQ_FLAGS_PPS_TIME 0x1UL
+ #define FUNC_PTP_TS_QUERY_REQ_FLAGS_PTM_TIME 0x2UL
+ u8 unused_0[4];
+};
+
+/* hwrm_func_ptp_ts_query_output (size:320b/40B) */
+struct hwrm_func_ptp_ts_query_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ __le64 pps_event_ts;
+ __le64 ptm_res_local_ts;
+ __le64 ptm_pmstr_ts;
+ __le32 ptm_mstr_prop_dly;
+ u8 unused_0[3];
+ u8 valid;
+};
+
/* hwrm_func_drv_if_change_input (size:192b/24B) */
struct hwrm_func_drv_if_change_input {
__le16 req_type;
@@ -3156,6 +3725,7 @@ struct hwrm_port_mac_cfg_input {
#define PORT_MAC_CFG_REQ_ENABLES_TX_TS_CAPTURE_PTP_MSG_TYPE 0x80UL
#define PORT_MAC_CFG_REQ_ENABLES_COS_FIELD_CFG 0x100UL
#define PORT_MAC_CFG_REQ_ENABLES_PTP_FREQ_ADJ_PPB 0x200UL
+ #define PORT_MAC_CFG_REQ_ENABLES_PTP_ADJ_PHASE 0x400UL
__le16 port_id;
u8 ipg;
u8 lpbk;
@@ -3188,8 +3758,8 @@ struct hwrm_port_mac_cfg_input {
#define PORT_MAC_CFG_REQ_COS_FIELD_CFG_DEFAULT_COS_MASK 0xe0UL
#define PORT_MAC_CFG_REQ_COS_FIELD_CFG_DEFAULT_COS_SFT 5
u8 unused_0[3];
- __s32 ptp_freq_adj_ppb;
- u8 unused_1[4];
+ __le32 ptp_freq_adj_ppb;
+ __le32 ptp_adj_phase;
};
/* hwrm_port_mac_cfg_output (size:128b/16B) */
@@ -3221,16 +3791,17 @@ struct hwrm_port_mac_ptp_qcfg_input {
u8 unused_0[6];
};
-/* hwrm_port_mac_ptp_qcfg_output (size:640b/80B) */
+/* hwrm_port_mac_ptp_qcfg_output (size:704b/88B) */
struct hwrm_port_mac_ptp_qcfg_output {
__le16 error_code;
__le16 req_type;
__le16 seq_id;
__le16 resp_len;
u8 flags;
- #define PORT_MAC_PTP_QCFG_RESP_FLAGS_DIRECT_ACCESS 0x1UL
- #define PORT_MAC_PTP_QCFG_RESP_FLAGS_ONE_STEP_TX_TS 0x4UL
- #define PORT_MAC_PTP_QCFG_RESP_FLAGS_HWRM_ACCESS 0x8UL
+ #define PORT_MAC_PTP_QCFG_RESP_FLAGS_DIRECT_ACCESS 0x1UL
+ #define PORT_MAC_PTP_QCFG_RESP_FLAGS_ONE_STEP_TX_TS 0x4UL
+ #define PORT_MAC_PTP_QCFG_RESP_FLAGS_HWRM_ACCESS 0x8UL
+ #define PORT_MAC_PTP_QCFG_RESP_FLAGS_PARTIAL_DIRECT_ACCESS_REF_CLOCK 0x10UL
u8 unused_0[3];
__le32 rx_ts_reg_off_lower;
__le32 rx_ts_reg_off_upper;
@@ -3247,6 +3818,8 @@ struct hwrm_port_mac_ptp_qcfg_output {
__le32 tx_ts_reg_off_seq_id;
__le32 tx_ts_reg_off_fifo;
__le32 tx_ts_reg_off_granularity;
+ __le32 ts_ref_clock_reg_lower;
+ __le32 ts_ref_clock_reg_upper;
u8 unused_1[7];
u8 valid;
};
@@ -3647,7 +4220,7 @@ struct hwrm_port_lpbk_clr_stats_output {
u8 valid;
};
-/* hwrm_port_ts_query_input (size:192b/24B) */
+/* hwrm_port_ts_query_input (size:256b/32B) */
struct hwrm_port_ts_query_input {
__le16 req_type;
__le16 cmpl_ring;
@@ -3662,6 +4235,11 @@ struct hwrm_port_ts_query_input {
#define PORT_TS_QUERY_REQ_FLAGS_CURRENT_TIME 0x2UL
__le16 port_id;
u8 unused_0[2];
+ __le16 enables;
+ #define PORT_TS_QUERY_REQ_ENABLES_TS_REQ_TIMEOUT 0x1UL
+ #define PORT_TS_QUERY_REQ_ENABLES_PTP_SEQ_ID 0x2UL
+ __le16 ts_req_timeout;
+ __le32 ptp_seq_id;
};
/* hwrm_port_ts_query_output (size:192b/24B) */
@@ -4215,7 +4793,8 @@ struct hwrm_queue_qportcfg_output {
u8 max_configurable_lossless_queues;
u8 queue_cfg_allowed;
u8 queue_cfg_info;
- #define QUEUE_QPORTCFG_RESP_QUEUE_CFG_INFO_ASYM_CFG 0x1UL
+ #define QUEUE_QPORTCFG_RESP_QUEUE_CFG_INFO_ASYM_CFG 0x1UL
+ #define QUEUE_QPORTCFG_RESP_QUEUE_CFG_INFO_USE_PROFILE_TYPE 0x2UL
u8 queue_pfcenable_cfg_allowed;
u8 queue_pri2cos_cfg_allowed;
u8 queue_cos2bw_cfg_allowed;
@@ -5467,6 +6046,7 @@ struct hwrm_vnic_qcaps_output {
#define VNIC_QCAPS_RESP_FLAGS_VNIC_STATE_CAP 0x400UL
#define VNIC_QCAPS_RESP_FLAGS_VIRTIO_NET_VNIC_ALLOC_CAP 0x800UL
#define VNIC_QCAPS_RESP_FLAGS_METADATA_FORMAT_CAP 0x1000UL
+ #define VNIC_QCAPS_RESP_FLAGS_RSS_STRICT_HASH_TYPE_CAP 0x2000UL
__le16 max_aggs_supported;
u8 unused_1[5];
u8 valid;
@@ -7224,6 +7804,7 @@ struct hwrm_cfa_adv_flow_mgnt_qcaps_output {
#define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_RX_ETHERTYPE_IP_SUPPORTED 0x4000UL
#define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_TRUFLOW_CAPABLE 0x8000UL
#define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_L2_FILTER_TRAFFIC_TYPE_L2_ROCE_SUPPORTED 0x10000UL
+ #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_LAG_SUPPORTED 0x20000UL
u8 unused_0[3];
u8 valid;
};
@@ -7914,11 +8495,14 @@ struct hwrm_temp_monitor_query_output {
u8 phy_temp;
u8 om_temp;
u8 flags;
- #define TEMP_MONITOR_QUERY_RESP_FLAGS_TEMP_NOT_AVAILABLE 0x1UL
- #define TEMP_MONITOR_QUERY_RESP_FLAGS_PHY_TEMP_NOT_AVAILABLE 0x2UL
- #define TEMP_MONITOR_QUERY_RESP_FLAGS_OM_NOT_PRESENT 0x4UL
- #define TEMP_MONITOR_QUERY_RESP_FLAGS_OM_TEMP_NOT_AVAILABLE 0x8UL
- u8 unused_0[3];
+ #define TEMP_MONITOR_QUERY_RESP_FLAGS_TEMP_NOT_AVAILABLE 0x1UL
+ #define TEMP_MONITOR_QUERY_RESP_FLAGS_PHY_TEMP_NOT_AVAILABLE 0x2UL
+ #define TEMP_MONITOR_QUERY_RESP_FLAGS_OM_NOT_PRESENT 0x4UL
+ #define TEMP_MONITOR_QUERY_RESP_FLAGS_OM_TEMP_NOT_AVAILABLE 0x8UL
+ #define TEMP_MONITOR_QUERY_RESP_FLAGS_EXT_TEMP_FIELDS_AVAILABLE 0x10UL
+ u8 temp2;
+ u8 phy_temp2;
+ u8 om_temp2;
u8 valid;
};
@@ -8109,6 +8693,7 @@ struct hwrm_dbg_qcaps_output {
#define DBG_QCAPS_RESP_FLAGS_CRASHDUMP_NVM 0x1UL
#define DBG_QCAPS_RESP_FLAGS_CRASHDUMP_HOST_DDR 0x2UL
#define DBG_QCAPS_RESP_FLAGS_CRASHDUMP_SOC_DDR 0x4UL
+ #define DBG_QCAPS_RESP_FLAGS_USEQ 0x8UL
u8 unused_1[3];
u8 valid;
};
@@ -8632,10 +9217,11 @@ struct hwrm_nvm_install_update_output {
/* hwrm_nvm_install_update_cmd_err (size:64b/8B) */
struct hwrm_nvm_install_update_cmd_err {
u8 code;
- #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_UNKNOWN 0x0UL
- #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR 0x1UL
- #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_SPACE 0x2UL
- #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_LAST NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_SPACE
+ #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_UNKNOWN 0x0UL
+ #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR 0x1UL
+ #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_SPACE 0x2UL
+ #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_ANTI_ROLLBACK 0x3UL
+ #define NVM_INSTALL_UPDATE_CMD_ERR_CODE_LAST NVM_INSTALL_UPDATE_CMD_ERR_CODE_ANTI_ROLLBACK
u8 unused_0[7];
};
@@ -8876,6 +9462,7 @@ struct fw_status_reg {
#define FW_STATUS_REG_CRASHDUMP_COMPLETE 0x80000UL
#define FW_STATUS_REG_SHUTDOWN 0x100000UL
#define FW_STATUS_REG_CRASHED_NO_MASTER 0x200000UL
+ #define FW_STATUS_REG_RECOVERING 0x400000UL
};
/* hcomm_status (size:64b/8B) */
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
new file mode 100644
index 000000000000..f698b6bd4ff8
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
@@ -0,0 +1,473 @@
+/* Broadcom NetXtreme-C/E network driver.
+ *
+ * Copyright (c) 2021 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.
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/net_tstamp.h>
+#include <linux/timecounter.h>
+#include <linux/timekeeping.h>
+#include <linux/ptp_classify.h>
+#include "bnxt_hsi.h"
+#include "bnxt.h"
+#include "bnxt_ptp.h"
+
+int bnxt_ptp_parse(struct sk_buff *skb, u16 *seq_id)
+{
+ unsigned int ptp_class;
+ struct ptp_header *hdr;
+
+ ptp_class = ptp_classify_raw(skb);
+
+ switch (ptp_class & PTP_CLASS_VMASK) {
+ case PTP_CLASS_V1:
+ case PTP_CLASS_V2:
+ hdr = ptp_parse_header(skb, ptp_class);
+ if (!hdr)
+ return -EINVAL;
+
+ *seq_id = ntohs(hdr->sequence_id);
+ return 0;
+ default:
+ return -ERANGE;
+ }
+}
+
+static int bnxt_ptp_settime(struct ptp_clock_info *ptp_info,
+ const struct timespec64 *ts)
+{
+ struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
+ ptp_info);
+ u64 ns = timespec64_to_ns(ts);
+
+ spin_lock_bh(&ptp->ptp_lock);
+ timecounter_init(&ptp->tc, &ptp->cc, ns);
+ spin_unlock_bh(&ptp->ptp_lock);
+ return 0;
+}
+
+/* Caller holds ptp_lock */
+static u64 bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts)
+{
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+ u64 ns;
+
+ ptp_read_system_prets(sts);
+ ns = readl(bp->bar0 + ptp->refclk_mapped_regs[0]);
+ ptp_read_system_postts(sts);
+ ns |= (u64)readl(bp->bar0 + ptp->refclk_mapped_regs[1]) << 32;
+ return ns;
+}
+
+static void bnxt_ptp_get_current_time(struct bnxt *bp)
+{
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+
+ if (!ptp)
+ return;
+ spin_lock_bh(&ptp->ptp_lock);
+ WRITE_ONCE(ptp->old_time, ptp->current_time);
+ ptp->current_time = bnxt_refclk_read(bp, NULL);
+ spin_unlock_bh(&ptp->ptp_lock);
+}
+
+static int bnxt_hwrm_port_ts_query(struct bnxt *bp, u32 flags, u64 *ts)
+{
+ struct hwrm_port_ts_query_output *resp = bp->hwrm_cmd_resp_addr;
+ struct hwrm_port_ts_query_input req = {0};
+ int rc;
+
+ bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_TS_QUERY, -1, -1);
+ req.flags = cpu_to_le32(flags);
+ if ((flags & PORT_TS_QUERY_REQ_FLAGS_PATH) ==
+ PORT_TS_QUERY_REQ_FLAGS_PATH_TX) {
+ req.enables = cpu_to_le16(BNXT_PTP_QTS_TX_ENABLES);
+ req.ptp_seq_id = cpu_to_le32(bp->ptp_cfg->tx_seqid);
+ req.ts_req_timeout = cpu_to_le16(BNXT_PTP_QTS_TIMEOUT);
+ }
+ mutex_lock(&bp->hwrm_cmd_lock);
+ rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+ if (!rc)
+ *ts = le64_to_cpu(resp->ptp_msg_ts);
+ mutex_unlock(&bp->hwrm_cmd_lock);
+ return rc;
+}
+
+static int bnxt_ptp_gettimex(struct ptp_clock_info *ptp_info,
+ struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
+ ptp_info);
+ u64 ns, cycles;
+
+ spin_lock_bh(&ptp->ptp_lock);
+ cycles = bnxt_refclk_read(ptp->bp, sts);
+ ns = timecounter_cyc2time(&ptp->tc, cycles);
+ spin_unlock_bh(&ptp->ptp_lock);
+ *ts = ns_to_timespec64(ns);
+
+ return 0;
+}
+
+static int bnxt_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
+{
+ struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
+ ptp_info);
+
+ spin_lock_bh(&ptp->ptp_lock);
+ timecounter_adjtime(&ptp->tc, delta);
+ spin_unlock_bh(&ptp->ptp_lock);
+ return 0;
+}
+
+static int bnxt_ptp_adjfreq(struct ptp_clock_info *ptp_info, s32 ppb)
+{
+ struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
+ ptp_info);
+ struct hwrm_port_mac_cfg_input req = {0};
+ struct bnxt *bp = ptp->bp;
+ int rc;
+
+ bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_MAC_CFG, -1, -1);
+ req.ptp_freq_adj_ppb = cpu_to_le32(ppb);
+ req.enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_PTP_FREQ_ADJ_PPB);
+ rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+ if (rc)
+ netdev_err(ptp->bp->dev,
+ "ptp adjfreq failed. rc = %d\n", rc);
+ return rc;
+}
+
+static int bnxt_ptp_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ return -EOPNOTSUPP;
+}
+
+static int bnxt_hwrm_ptp_cfg(struct bnxt *bp)
+{
+ struct hwrm_port_mac_cfg_input req = {0};
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+ u32 flags = 0;
+
+ bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_MAC_CFG, -1, -1);
+ if (ptp->rx_filter)
+ flags |= PORT_MAC_CFG_REQ_FLAGS_PTP_RX_TS_CAPTURE_ENABLE;
+ else
+ flags |= PORT_MAC_CFG_REQ_FLAGS_PTP_RX_TS_CAPTURE_DISABLE;
+ if (ptp->tx_tstamp_en)
+ flags |= PORT_MAC_CFG_REQ_FLAGS_PTP_TX_TS_CAPTURE_ENABLE;
+ else
+ flags |= PORT_MAC_CFG_REQ_FLAGS_PTP_TX_TS_CAPTURE_DISABLE;
+ req.flags = cpu_to_le32(flags);
+ req.enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_RX_TS_CAPTURE_PTP_MSG_TYPE);
+ req.rx_ts_capture_ptp_msg_type = cpu_to_le16(ptp->rxctl);
+
+ return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+}
+
+int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
+{
+ struct bnxt *bp = netdev_priv(dev);
+ struct hwtstamp_config stmpconf;
+ struct bnxt_ptp_cfg *ptp;
+ u16 old_rxctl;
+ int old_rx_filter, rc;
+ u8 old_tx_tstamp_en;
+
+ ptp = bp->ptp_cfg;
+ if (!ptp)
+ return -EOPNOTSUPP;
+
+ if (copy_from_user(&stmpconf, ifr->ifr_data, sizeof(stmpconf)))
+ return -EFAULT;
+
+ if (stmpconf.flags)
+ return -EINVAL;
+
+ if (stmpconf.tx_type != HWTSTAMP_TX_ON &&
+ stmpconf.tx_type != HWTSTAMP_TX_OFF)
+ return -ERANGE;
+
+ old_rx_filter = ptp->rx_filter;
+ old_rxctl = ptp->rxctl;
+ old_tx_tstamp_en = ptp->tx_tstamp_en;
+ switch (stmpconf.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ ptp->rxctl = 0;
+ ptp->rx_filter = HWTSTAMP_FILTER_NONE;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ ptp->rxctl = BNXT_PTP_MSG_EVENTS;
+ ptp->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ ptp->rxctl = BNXT_PTP_MSG_SYNC;
+ ptp->rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ ptp->rxctl = BNXT_PTP_MSG_DELAY_REQ;
+ ptp->rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ if (stmpconf.tx_type == HWTSTAMP_TX_ON)
+ ptp->tx_tstamp_en = 1;
+ else
+ ptp->tx_tstamp_en = 0;
+
+ rc = bnxt_hwrm_ptp_cfg(bp);
+ if (rc)
+ goto ts_set_err;
+
+ stmpconf.rx_filter = ptp->rx_filter;
+ return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ?
+ -EFAULT : 0;
+
+ts_set_err:
+ ptp->rx_filter = old_rx_filter;
+ ptp->rxctl = old_rxctl;
+ ptp->tx_tstamp_en = old_tx_tstamp_en;
+ return rc;
+}
+
+int bnxt_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
+{
+ struct bnxt *bp = netdev_priv(dev);
+ struct hwtstamp_config stmpconf;
+ struct bnxt_ptp_cfg *ptp;
+
+ ptp = bp->ptp_cfg;
+ if (!ptp)
+ return -EOPNOTSUPP;
+
+ stmpconf.flags = 0;
+ stmpconf.tx_type = ptp->tx_tstamp_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
+
+ stmpconf.rx_filter = ptp->rx_filter;
+ return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ?
+ -EFAULT : 0;
+}
+
+static int bnxt_map_regs(struct bnxt *bp, u32 *reg_arr, int count, int reg_win)
+{
+ u32 reg_base = *reg_arr & BNXT_GRC_BASE_MASK;
+ u32 win_off;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if ((reg_arr[i] & BNXT_GRC_BASE_MASK) != reg_base)
+ return -ERANGE;
+ }
+ win_off = BNXT_GRCPF_REG_WINDOW_BASE_OUT + (reg_win - 1) * 4;
+ writel(reg_base, bp->bar0 + win_off);
+ return 0;
+}
+
+static int bnxt_map_ptp_regs(struct bnxt *bp)
+{
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+ u32 *reg_arr;
+ int rc, i;
+
+ reg_arr = ptp->refclk_regs;
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ rc = bnxt_map_regs(bp, reg_arr, 2, BNXT_PTP_GRC_WIN);
+ if (rc)
+ return rc;
+ for (i = 0; i < 2; i++)
+ ptp->refclk_mapped_regs[i] = BNXT_PTP_GRC_WIN_BASE +
+ (ptp->refclk_regs[i] & BNXT_GRC_OFFSET_MASK);
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static void bnxt_unmap_ptp_regs(struct bnxt *bp)
+{
+ writel(0, bp->bar0 + BNXT_GRCPF_REG_WINDOW_BASE_OUT +
+ (BNXT_PTP_GRC_WIN - 1) * 4);
+}
+
+static u64 bnxt_cc_read(const struct cyclecounter *cc)
+{
+ struct bnxt_ptp_cfg *ptp = container_of(cc, struct bnxt_ptp_cfg, cc);
+
+ return bnxt_refclk_read(ptp->bp, NULL);
+}
+
+static void bnxt_stamp_tx_skb(struct bnxt *bp, struct sk_buff *skb)
+{
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+ struct skb_shared_hwtstamps timestamp;
+ u64 ts = 0, ns = 0;
+ int rc;
+
+ rc = bnxt_hwrm_port_ts_query(bp, PORT_TS_QUERY_REQ_FLAGS_PATH_TX, &ts);
+ if (!rc) {
+ memset(&timestamp, 0, sizeof(timestamp));
+ spin_lock_bh(&ptp->ptp_lock);
+ ns = timecounter_cyc2time(&ptp->tc, ts);
+ spin_unlock_bh(&ptp->ptp_lock);
+ timestamp.hwtstamp = ns_to_ktime(ns);
+ skb_tstamp_tx(ptp->tx_skb, &timestamp);
+ } else {
+ netdev_err(bp->dev, "TS query for TX timer failed rc = %x\n",
+ rc);
+ }
+
+ dev_kfree_skb_any(ptp->tx_skb);
+ ptp->tx_skb = NULL;
+ atomic_inc(&ptp->tx_avail);
+}
+
+static long bnxt_ptp_ts_aux_work(struct ptp_clock_info *ptp_info)
+{
+ struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
+ ptp_info);
+ unsigned long now = jiffies;
+ struct bnxt *bp = ptp->bp;
+
+ if (ptp->tx_skb)
+ bnxt_stamp_tx_skb(bp, ptp->tx_skb);
+
+ if (!time_after_eq(now, ptp->next_period))
+ return ptp->next_period - now;
+
+ bnxt_ptp_get_current_time(bp);
+ ptp->next_period = now + HZ;
+ return HZ;
+}
+
+int bnxt_get_tx_ts_p5(struct bnxt *bp, struct sk_buff *skb)
+{
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+
+ if (ptp->tx_skb) {
+ netdev_err(bp->dev, "deferring skb:one SKB is still outstanding\n");
+ return -EBUSY;
+ }
+ ptp->tx_skb = skb;
+ ptp_schedule_worker(ptp->ptp_clock, 0);
+ return 0;
+}
+
+int bnxt_get_rx_ts_p5(struct bnxt *bp, u64 *ts, u32 pkt_ts)
+{
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+ u64 time;
+
+ if (!ptp)
+ return -ENODEV;
+
+ BNXT_READ_TIME64(ptp, time, ptp->old_time);
+ *ts = (time & BNXT_HI_TIMER_MASK) | pkt_ts;
+ if (pkt_ts < (time & BNXT_LO_TIMER_MASK))
+ *ts += BNXT_LO_TIMER_MASK + 1;
+
+ return 0;
+}
+
+void bnxt_ptp_start(struct bnxt *bp)
+{
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+
+ if (!ptp)
+ return;
+
+ if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ spin_lock_bh(&ptp->ptp_lock);
+ ptp->current_time = bnxt_refclk_read(bp, NULL);
+ WRITE_ONCE(ptp->old_time, ptp->current_time);
+ spin_unlock_bh(&ptp->ptp_lock);
+ ptp_schedule_worker(ptp->ptp_clock, 0);
+ }
+}
+
+static const struct ptp_clock_info bnxt_ptp_caps = {
+ .owner = THIS_MODULE,
+ .name = "bnxt clock",
+ .max_adj = BNXT_MAX_PHC_DRIFT,
+ .n_alarm = 0,
+ .n_ext_ts = 0,
+ .n_per_out = 0,
+ .n_pins = 0,
+ .pps = 0,
+ .adjfreq = bnxt_ptp_adjfreq,
+ .adjtime = bnxt_ptp_adjtime,
+ .do_aux_work = bnxt_ptp_ts_aux_work,
+ .gettimex64 = bnxt_ptp_gettimex,
+ .settime64 = bnxt_ptp_settime,
+ .enable = bnxt_ptp_enable,
+};
+
+int bnxt_ptp_init(struct bnxt *bp)
+{
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+ int rc;
+
+ if (!ptp)
+ return 0;
+
+ rc = bnxt_map_ptp_regs(bp);
+ if (rc)
+ return rc;
+
+ atomic_set(&ptp->tx_avail, BNXT_MAX_TX_TS);
+ spin_lock_init(&ptp->ptp_lock);
+
+ memset(&ptp->cc, 0, sizeof(ptp->cc));
+ ptp->cc.read = bnxt_cc_read;
+ ptp->cc.mask = CYCLECOUNTER_MASK(48);
+ ptp->cc.shift = 0;
+ ptp->cc.mult = 1;
+
+ timecounter_init(&ptp->tc, &ptp->cc, ktime_to_ns(ktime_get_real()));
+
+ ptp->ptp_info = bnxt_ptp_caps;
+ ptp->ptp_clock = ptp_clock_register(&ptp->ptp_info, &bp->pdev->dev);
+ if (IS_ERR(ptp->ptp_clock)) {
+ int err = PTR_ERR(ptp->ptp_clock);
+
+ ptp->ptp_clock = NULL;
+ bnxt_unmap_ptp_regs(bp);
+ return err;
+ }
+
+ return 0;
+}
+
+void bnxt_ptp_clear(struct bnxt *bp)
+{
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+
+ if (!ptp)
+ return;
+
+ if (ptp->ptp_clock)
+ ptp_clock_unregister(ptp->ptp_clock);
+
+ ptp->ptp_clock = NULL;
+ if (ptp->tx_skb) {
+ dev_kfree_skb_any(ptp->tx_skb);
+ ptp->tx_skb = NULL;
+ }
+ bnxt_unmap_ptp_regs(bp);
+}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h
new file mode 100644
index 000000000000..6b6245750e20
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h
@@ -0,0 +1,81 @@
+/* Broadcom NetXtreme-C/E network driver.
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#ifndef BNXT_PTP_H
+#define BNXT_PTP_H
+
+#define BNXT_PTP_GRC_WIN 5
+#define BNXT_PTP_GRC_WIN_BASE 0x5000
+
+#define BNXT_MAX_PHC_DRIFT 31000000
+#define BNXT_LO_TIMER_MASK 0x0000ffffffffUL
+#define BNXT_HI_TIMER_MASK 0xffff00000000UL
+
+#define BNXT_PTP_QTS_TIMEOUT 1000
+#define BNXT_PTP_QTS_TX_ENABLES (PORT_TS_QUERY_REQ_ENABLES_PTP_SEQ_ID | \
+ PORT_TS_QUERY_REQ_ENABLES_TS_REQ_TIMEOUT)
+
+struct bnxt_ptp_cfg {
+ struct ptp_clock_info ptp_info;
+ struct ptp_clock *ptp_clock;
+ struct cyclecounter cc;
+ struct timecounter tc;
+ /* serialize timecounter access */
+ spinlock_t ptp_lock;
+ struct sk_buff *tx_skb;
+ u64 current_time;
+ u64 old_time;
+ unsigned long next_period;
+ u16 tx_seqid;
+ struct bnxt *bp;
+ atomic_t tx_avail;
+#define BNXT_MAX_TX_TS 1
+ u16 rxctl;
+#define BNXT_PTP_MSG_SYNC (1 << 0)
+#define BNXT_PTP_MSG_DELAY_REQ (1 << 1)
+#define BNXT_PTP_MSG_PDELAY_REQ (1 << 2)
+#define BNXT_PTP_MSG_PDELAY_RESP (1 << 3)
+#define BNXT_PTP_MSG_FOLLOW_UP (1 << 8)
+#define BNXT_PTP_MSG_DELAY_RESP (1 << 9)
+#define BNXT_PTP_MSG_PDELAY_RESP_FOLLOW_UP (1 << 10)
+#define BNXT_PTP_MSG_ANNOUNCE (1 << 11)
+#define BNXT_PTP_MSG_SIGNALING (1 << 12)
+#define BNXT_PTP_MSG_MANAGEMENT (1 << 13)
+#define BNXT_PTP_MSG_EVENTS (BNXT_PTP_MSG_SYNC | \
+ BNXT_PTP_MSG_DELAY_REQ | \
+ BNXT_PTP_MSG_PDELAY_REQ | \
+ BNXT_PTP_MSG_PDELAY_RESP)
+ u8 tx_tstamp_en:1;
+ int rx_filter;
+
+ u32 refclk_regs[2];
+ u32 refclk_mapped_regs[2];
+};
+
+#if BITS_PER_LONG == 32
+#define BNXT_READ_TIME64(ptp, dst, src) \
+do { \
+ spin_lock_bh(&(ptp)->ptp_lock); \
+ (dst) = (src); \
+ spin_unlock_bh(&(ptp)->ptp_lock); \
+} while (0)
+#else
+#define BNXT_READ_TIME64(ptp, dst, src) \
+ ((dst) = READ_ONCE(src))
+#endif
+
+int bnxt_ptp_parse(struct sk_buff *skb, u16 *seq_id);
+int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr);
+int bnxt_hwtstamp_get(struct net_device *dev, struct ifreq *ifr);
+int bnxt_get_tx_ts_p5(struct bnxt *bp, struct sk_buff *skb);
+int bnxt_get_rx_ts_p5(struct bnxt *bp, u64 *ts, u32 pkt_ts);
+void bnxt_ptp_start(struct bnxt *bp);
+int bnxt_ptp_init(struct bnxt *bp);
+void bnxt_ptp_clear(struct bnxt *bp);
+#endif
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
index eb00a219aa51..7fa881e1cd80 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
@@ -632,7 +632,7 @@ static int bnxt_hwrm_func_cfg(struct bnxt *bp, int num_vfs)
vf_vnics = (hw_resc->max_vnics - bp->nr_vnics) / num_vfs;
vf_vnics = min_t(u16, vf_vnics, vf_rx_rings);
- req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_MTU |
+ req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_ADMIN_MTU |
FUNC_CFG_REQ_ENABLES_MRU |
FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS |
FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS |
@@ -645,7 +645,7 @@ static int bnxt_hwrm_func_cfg(struct bnxt *bp, int num_vfs)
mtu = bp->dev->mtu + ETH_HLEN + VLAN_HLEN;
req.mru = cpu_to_le16(mtu);
- req.mtu = cpu_to_le16(mtu);
+ req.admin_mtu = cpu_to_le16(mtu);
req.num_rsscos_ctxs = cpu_to_le16(1);
req.num_cmpl_rings = cpu_to_le16(vf_cp_rings);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
index ec9564e584e0..bee6e091a997 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
@@ -138,9 +138,7 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
xdp_prepare_buff(&xdp, *data_ptr - offset, offset, *len, false);
orig_data = xdp.data;
- rcu_read_lock();
act = bpf_prog_run_xdp(xdp_prog, &xdp);
- rcu_read_unlock();
tx_avail = bnxt_tx_avail(bp, txr);
/* If the tx ring is not full, we must not update the rx producer yet
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index fcca023f22e5..db74241935ab 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1640,7 +1640,8 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv,
switch (mode) {
case GENET_POWER_PASSIVE:
- reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS);
+ reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS |
+ EXT_ENERGY_DET_MASK);
if (GENET_IS_V5(priv)) {
reg &= ~(EXT_PWR_DOWN_PHY_EN |
EXT_PWR_DOWN_PHY_RD |
@@ -3237,15 +3238,21 @@ static void bcmgenet_get_hw_addr(struct bcmgenet_priv *priv,
/* Returns a reusable dma control register value */
static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv)
{
+ unsigned int i;
u32 reg;
u32 dma_ctrl;
/* disable DMA */
dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN;
+ for (i = 0; i < priv->hw_params->tx_queues; i++)
+ dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT));
reg = bcmgenet_tdma_readl(priv, DMA_CTRL);
reg &= ~dma_ctrl;
bcmgenet_tdma_writel(priv, reg, DMA_CTRL);
+ dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN;
+ for (i = 0; i < priv->hw_params->rx_queues; i++)
+ dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT));
reg = bcmgenet_rdma_readl(priv, DMA_CTRL);
reg &= ~dma_ctrl;
bcmgenet_rdma_writel(priv, reg, DMA_CTRL);
@@ -3292,7 +3299,6 @@ static int bcmgenet_open(struct net_device *dev)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
unsigned long dma_ctrl;
- u32 reg;
int ret;
netif_dbg(priv, ifup, dev, "bcmgenet_open\n");
@@ -3318,12 +3324,6 @@ static int bcmgenet_open(struct net_device *dev)
bcmgenet_set_hw_addr(priv, dev->dev_addr);
- if (priv->internal_phy) {
- reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
- reg |= EXT_ENERGY_DET_MASK;
- bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
- }
-
/* Disable RX/TX DMA and flush TX queues */
dma_ctrl = bcmgenet_dma_disable(priv);
@@ -4139,7 +4139,6 @@ static int bcmgenet_resume(struct device *d)
struct bcmgenet_priv *priv = netdev_priv(dev);
struct bcmgenet_rxnfc_rule *rule;
unsigned long dma_ctrl;
- u32 reg;
int ret;
if (!netif_running(dev))
@@ -4176,12 +4175,6 @@ static int bcmgenet_resume(struct device *d)
if (rule->state != BCMGENET_RXNFC_STATE_UNUSED)
bcmgenet_hfb_create_rxnfc_filter(priv, rule);
- if (priv->internal_phy) {
- reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
- reg |= EXT_ENERGY_DET_MASK;
- bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
- }
-
/* Disable RX/TX DMA and flush TX queues */
dma_ctrl = bcmgenet_dma_disable(priv);
@@ -4296,3 +4289,4 @@ MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom GENET Ethernet controller driver");
MODULE_ALIAS("platform:bcmgenet");
MODULE_LICENSE("GPL");
+MODULE_SOFTDEP("pre: mdio-bcm-unimac");
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index facde824bcaa..e31a5a397f11 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -186,12 +186,6 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
reg |= CMD_RX_EN;
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
- if (priv->hw_params->flags & GENET_HAS_EXT) {
- reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
- reg &= ~EXT_ENERGY_DET_MASK;
- bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
- }
-
reg = UMAC_IRQ_MPD_R;
if (hfb_enable)
reg |= UMAC_IRQ_HFB_SM | UMAC_IRQ_HFB_MM;
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index 5335244e4577..89d16c587bb7 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -423,6 +423,10 @@ static int bcmgenet_mii_register(struct bcmgenet_priv *priv)
int id, ret;
pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!pres) {
+ dev_err(&pdev->dev, "Invalid resource\n");
+ return -EINVAL;
+ }
memset(&res, 0, sizeof(res));
memset(&ppd, 0, sizeof(ppd));
diff --git a/drivers/net/ethernet/brocade/bna/bfa_cee.c b/drivers/net/ethernet/brocade/bna/bfa_cee.c
index 06f221c44802..eeb05e31713f 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_cee.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_cee.c
@@ -82,7 +82,7 @@ bfa_cee_get_attr_isr(struct bfa_cee *cee, enum bfa_status status)
}
/**
- * bfa_cee_get_attr_isr - CEE ISR for get-stats responses from f/w
+ * bfa_cee_get_stats_isr - CEE ISR for get-stats responses from f/w
*
* @cee: Pointer to the CEE module
* @status: Return status from the f/w
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index a0c7b1167dbb..7d2fe13a52f8 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -4655,8 +4655,7 @@ static int macb_probe(struct platform_device *pdev)
struct macb *bp;
int err, val;
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mem = devm_ioremap_resource(&pdev->dev, regs);
+ mem = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
if (IS_ERR(mem))
return PTR_ERR(mem);
diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
index 353393dea639..8b7b59908a1a 100644
--- a/drivers/net/ethernet/cadence/macb_pci.c
+++ b/drivers/net/ethernet/cadence/macb_pci.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* DOC: Cadence GEM PCI wrapper.
*
* Copyright (C) 2016 Cadence Design Systems - https://www.cadence.com
diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c
index 283918aeb741..5c368a9cbbbc 100644
--- a/drivers/net/ethernet/cadence/macb_ptp.c
+++ b/drivers/net/ethernet/cadence/macb_ptp.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* 1588 PTP support for Cadence GEM device.
*
* Copyright (C) 2017 Cadence Design Systems - https://www.cadence.com
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index bbb453c6a5f7..b6a066404f4b 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -711,7 +711,7 @@ static void xgmac_rx_refill(struct xgmac_priv *priv)
}
/**
- * init_xgmac_dma_desc_rings - init the RX/TX descriptor rings
+ * xgmac_dma_desc_rings_init - init the RX/TX descriptor rings
* @dev: net device structure
* Description: this function initializes the DMA RX/TX descriptors
* and allocates the socket buffers.
@@ -859,7 +859,7 @@ static void xgmac_free_dma_desc_rings(struct xgmac_priv *priv)
}
/**
- * xgmac_tx:
+ * xgmac_tx_complete:
* @priv: private driver structure
* Description: it reclaims resources after transmission completes.
*/
@@ -1040,7 +1040,7 @@ static int xgmac_open(struct net_device *dev)
}
/**
- * xgmac_release - close entry point of the driver
+ * xgmac_stop - close entry point of the driver
* @dev : device pointer.
* Description:
* This is the stop entry point of the driver.
@@ -1812,7 +1812,7 @@ err_alloc:
}
/**
- * xgmac_dvr_remove
+ * xgmac_remove
* @pdev: platform device pointer
* Description: this function resets the TX/RX processes, disables the MAC RX/TX
* changes the link status, releases the DMA descriptor rings,
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
index c33b4e837515..e2b290135fd9 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
@@ -555,9 +555,7 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog,
xdp_prepare_buff(&xdp, hard_start, data - hard_start, len, false);
orig_data = xdp.data;
- rcu_read_lock();
action = bpf_prog_run_xdp(prog, &xdp);
- rcu_read_unlock();
len = xdp.data_end - xdp.data;
/* Check if XDP program has changed headers */
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
index 0c783aadf393..c36fed9c3d73 100644
--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
@@ -594,9 +594,6 @@ static void bgx_lmac_handler(struct net_device *netdev)
struct phy_device *phydev;
int link_changed = 0;
- if (!lmac)
- return;
-
phydev = lmac->phydev;
if (!phydev->link && lmac->last_link)
diff --git a/drivers/net/ethernet/chelsio/cxgb3/adapter.h b/drivers/net/ethernet/chelsio/cxgb3/adapter.h
index f80fbd81b609..6d682b7c7aac 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/adapter.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/adapter.h
@@ -178,7 +178,7 @@ struct sge_txq { /* state for an SGE Tx queue */
unsigned int token; /* WR token */
dma_addr_t phys_addr; /* physical address of the ring */
struct sk_buff_head sendq; /* List of backpressured offload packets */
- struct tasklet_struct qresume_tsk; /* restarts the queue */
+ struct work_struct qresume_task; /* restarts the queue */
unsigned int cntxt_id; /* SGE context id for the Tx q */
unsigned long stops; /* # of times q has been stopped */
unsigned long restarts; /* # of queue restarts */
diff --git a/drivers/net/ethernet/chelsio/cxgb3/common.h b/drivers/net/ethernet/chelsio/cxgb3/common.h
index 1bd7d89666c4..b706f2fbe4f4 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/common.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/common.h
@@ -770,4 +770,6 @@ int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
int phy_addr, const struct mdio_ops *mdio_ops);
int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter,
int phy_addr, const struct mdio_ops *mdio_ops);
+
+extern struct workqueue_struct *cxgb3_wq;
#endif /* __CHELSIO_COMMON_H */
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
index 84ad7261e243..57f210c53afc 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -1273,14 +1273,14 @@ static int cxgb_up(struct adapter *adap)
free_irq(adap->msix_info[0].vec, adap);
goto irq_err;
}
- } else if ((err = request_irq(adap->pdev->irq,
- t3_intr_handler(adap,
- adap->sge.qs[0].rspq.
- polling),
- (adap->flags & USING_MSI) ?
- 0 : IRQF_SHARED,
- adap->name, adap)))
- goto irq_err;
+ } else {
+ err = request_irq(adap->pdev->irq,
+ t3_intr_handler(adap, adap->sge.qs[0].rspq.polling),
+ (adap->flags & USING_MSI) ? 0 : IRQF_SHARED,
+ adap->name, adap);
+ if (err)
+ goto irq_err;
+ }
enable_all_napi(adap);
t3_sge_start(adap);
@@ -3098,8 +3098,9 @@ static void set_nqsets(struct adapter *adap)
nqsets = num_cpus;
if (nqsets < 1 || hwports == 4)
nqsets = 1;
- } else
+ } else {
nqsets = 1;
+ }
for_each_port(adap, i) {
struct port_info *pi = adap2pinfo(adap, i);
diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c
index 1cc3c51eff71..cb5c79c43bc9 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c
@@ -665,7 +665,7 @@ static void t3_reset_qset(struct sge_qset *q)
/**
- * free_qset - free the resources of an SGE queue set
+ * t3_free_qset - free the resources of an SGE queue set
* @adapter: the adapter owning the queue set
* @q: the queue set
*
@@ -1256,7 +1256,7 @@ static inline void t3_stop_tx_queue(struct netdev_queue *txq,
}
/**
- * eth_xmit - add a packet to the Ethernet Tx queue
+ * t3_eth_xmit - add a packet to the Ethernet Tx queue
* @skb: the packet
* @dev: the egress net device
*
@@ -1518,14 +1518,15 @@ static int ctrl_xmit(struct adapter *adap, struct sge_txq *q,
/**
* restart_ctrlq - restart a suspended control queue
- * @t: pointer to the tasklet associated with this handler
+ * @w: pointer to the work associated with this handler
*
* Resumes transmission on a suspended Tx control queue.
*/
-static void restart_ctrlq(struct tasklet_struct *t)
+static void restart_ctrlq(struct work_struct *w)
{
struct sk_buff *skb;
- struct sge_qset *qs = from_tasklet(qs, t, txq[TXQ_CTRL].qresume_tsk);
+ struct sge_qset *qs = container_of(w, struct sge_qset,
+ txq[TXQ_CTRL].qresume_task);
struct sge_txq *q = &qs->txq[TXQ_CTRL];
spin_lock(&q->lock);
@@ -1736,14 +1737,15 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
/**
* restart_offloadq - restart a suspended offload queue
- * @t: pointer to the tasklet associated with this handler
+ * @w: pointer to the work associated with this handler
*
* Resumes transmission on a suspended Tx offload queue.
*/
-static void restart_offloadq(struct tasklet_struct *t)
+static void restart_offloadq(struct work_struct *w)
{
struct sk_buff *skb;
- struct sge_qset *qs = from_tasklet(qs, t, txq[TXQ_OFLD].qresume_tsk);
+ struct sge_qset *qs = container_of(w, struct sge_qset,
+ txq[TXQ_OFLD].qresume_task);
struct sge_txq *q = &qs->txq[TXQ_OFLD];
const struct port_info *pi = netdev_priv(qs->netdev);
struct adapter *adap = pi->adapter;
@@ -1998,13 +2000,17 @@ static void restart_tx(struct sge_qset *qs)
should_restart_tx(&qs->txq[TXQ_OFLD]) &&
test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) {
qs->txq[TXQ_OFLD].restarts++;
- tasklet_schedule(&qs->txq[TXQ_OFLD].qresume_tsk);
+
+ /* The work can be quite lengthy so we use driver's own queue */
+ queue_work(cxgb3_wq, &qs->txq[TXQ_OFLD].qresume_task);
}
if (test_bit(TXQ_CTRL, &qs->txq_stopped) &&
should_restart_tx(&qs->txq[TXQ_CTRL]) &&
test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) {
qs->txq[TXQ_CTRL].restarts++;
- tasklet_schedule(&qs->txq[TXQ_CTRL].qresume_tsk);
+
+ /* The work can be quite lengthy so we use driver's own queue */
+ queue_work(cxgb3_wq, &qs->txq[TXQ_CTRL].qresume_task);
}
}
@@ -3085,8 +3091,8 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
skb_queue_head_init(&q->txq[i].sendq);
}
- tasklet_setup(&q->txq[TXQ_OFLD].qresume_tsk, restart_offloadq);
- tasklet_setup(&q->txq[TXQ_CTRL].qresume_tsk, restart_ctrlq);
+ INIT_WORK(&q->txq[TXQ_OFLD].qresume_task, restart_offloadq);
+ INIT_WORK(&q->txq[TXQ_CTRL].qresume_task, restart_ctrlq);
q->fl[0].gen = q->fl[1].gen = 1;
q->fl[0].size = p->fl_size;
@@ -3276,11 +3282,11 @@ void t3_sge_start(struct adapter *adap)
*
* Can be invoked from interrupt context e.g. error handler.
*
- * Note that this function cannot disable the restart of tasklets as
+ * Note that this function cannot disable the restart of works as
* it cannot wait if called from interrupt context, however the
- * tasklets will have no effect since the doorbells are disabled. The
+ * works will have no effect since the doorbells are disabled. The
* driver will call tg3_sge_stop() later from process context, at
- * which time the tasklets will be stopped if they are still running.
+ * which time the works will be stopped if they are still running.
*/
void t3_sge_stop_dma(struct adapter *adap)
{
@@ -3292,7 +3298,7 @@ void t3_sge_stop_dma(struct adapter *adap)
* @adap: the adapter
*
* Called from process context. Disables the DMA engine and any
- * pending queue restart tasklets.
+ * pending queue restart works.
*/
void t3_sge_stop(struct adapter *adap)
{
@@ -3303,8 +3309,8 @@ void t3_sge_stop(struct adapter *adap)
for (i = 0; i < SGE_QSETS; ++i) {
struct sge_qset *qs = &adap->sge.qs[i];
- tasklet_kill(&qs->txq[TXQ_OFLD].qresume_tsk);
- tasklet_kill(&qs->txq[TXQ_CTRL].qresume_tsk);
+ cancel_work_sync(&qs->txq[TXQ_OFLD].qresume_task);
+ cancel_work_sync(&qs->txq[TXQ_CTRL].qresume_task);
}
}
@@ -3371,7 +3377,7 @@ void t3_sge_prep(struct adapter *adap, struct sge_params *p)
q->coalesce_usecs = 5;
q->rspq_size = 1024;
q->fl_size = 1024;
- q->jumbo_size = 512;
+ q->jumbo_size = 512;
q->txq_size[TXQ_ETH] = 1024;
q->txq_size[TXQ_OFLD] = 1024;
q->txq_size[TXQ_CTRL] = 256;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
index 12fcf84d67ad..163efab27e9b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
@@ -106,8 +106,7 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
if (!list_empty(&ctbl->ce_free_head)) {
ce = list_first_entry(&ctbl->ce_free_head,
struct clip_entry, list);
- list_del(&ce->list);
- INIT_LIST_HEAD(&ce->list);
+ list_del_init(&ce->list);
spin_lock_init(&ce->lock);
refcount_set(&ce->refcnt, 0);
atomic_dec(&ctbl->nfree);
@@ -179,8 +178,7 @@ found:
write_lock_bh(&ctbl->lock);
spin_lock_bh(&ce->lock);
if (refcount_dec_and_test(&ce->refcnt)) {
- list_del(&ce->list);
- INIT_LIST_HEAD(&ce->list);
+ list_del_init(&ce->list);
list_add_tail(&ce->list, &ctbl->ce_free_head);
atomic_inc(&ctbl->nfree);
if (v6)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 762113a04dde..dbf9a0e6601d 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -2643,6 +2643,9 @@ static void detach_ulds(struct adapter *adap)
{
unsigned int i;
+ if (!is_uld(adap))
+ return;
+
mutex_lock(&uld_mutex);
list_del(&adap->list_node);
@@ -3894,7 +3897,6 @@ static const struct net_device_ops cxgb4_mgmt_netdev_ops = {
.ndo_set_vf_vlan = cxgb4_mgmt_set_vf_vlan,
.ndo_set_vf_link_state = cxgb4_mgmt_set_vf_link_state,
};
-#endif
static void cxgb4_mgmt_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
@@ -3909,6 +3911,7 @@ static void cxgb4_mgmt_get_drvinfo(struct net_device *dev,
static const struct ethtool_ops cxgb4_mgmt_ethtool_ops = {
.get_drvinfo = cxgb4_mgmt_get_drvinfo,
};
+#endif
static void notify_fatal_err(struct work_struct *work)
{
@@ -7141,10 +7144,13 @@ static void remove_one(struct pci_dev *pdev)
*/
destroy_workqueue(adapter->workq);
- if (is_uld(adapter)) {
- detach_ulds(adapter);
- t4_uld_clean_up(adapter);
- }
+ detach_ulds(adapter);
+
+ for_each_port(adapter, i)
+ if (adapter->port[i]->reg_state == NETREG_REGISTERED)
+ unregister_netdev(adapter->port[i]);
+
+ t4_uld_clean_up(adapter);
adap_free_hma_mem(adapter);
@@ -7152,10 +7158,6 @@ static void remove_one(struct pci_dev *pdev)
cxgb4_free_mps_ref_entries(adapter);
- for_each_port(adapter, i)
- if (adapter->port[i]->reg_state == NETREG_REGISTERED)
- unregister_netdev(adapter->port[i]);
-
debugfs_remove_recursive(adapter->debugfs_root);
if (!is_t4(adapter->params.chip))
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c
index 70dbee89118e..5bf117d2179f 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c
@@ -446,7 +446,7 @@ void cxgb4_ptp_init(struct adapter *adapter)
}
/**
- * cxgb4_ptp_remove - disable PTP device and stop the overflow check
+ * cxgb4_ptp_stop - disable PTP device and stop the overflow check
* @adapter: board private structure
*
* Stop the PTP support.
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
index 743af9e654aa..17faac715882 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
@@ -581,6 +581,9 @@ void t4_uld_clean_up(struct adapter *adap)
{
unsigned int i;
+ if (!is_uld(adap))
+ return;
+
mutex_lock(&uld_mutex);
for (i = 0; i < CXGB4_ULD_MAX; i++) {
if (!adap->uld[i].handle)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index a0555f4d76fc..6606fb8b3e42 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -6993,7 +6993,7 @@ int t4_fw_bye(struct adapter *adap, unsigned int mbox)
}
/**
- * t4_init_cmd - ask FW to initialize the device
+ * t4_early_init - ask FW to initialize the device
* @adap: the adapter
* @mbox: mailbox to use for the FW command
*
@@ -7792,7 +7792,6 @@ int t4_free_encap_mac_filt(struct adapter *adap, unsigned int viid,
int idx, bool sleep_ok)
{
struct fw_vi_mac_exact *p;
- u8 addr[] = {0, 0, 0, 0, 0, 0};
struct fw_vi_mac_cmd c;
int ret = 0;
u32 exact;
@@ -7809,7 +7808,7 @@ int t4_free_encap_mac_filt(struct adapter *adap, unsigned int viid,
p = c.u.exact;
p->valid_to_idx = cpu_to_be16(FW_VI_MAC_CMD_VALID_F |
FW_VI_MAC_CMD_IDX_V(idx));
- memcpy(p->macaddr, addr, sizeof(p->macaddr));
+ eth_zero_addr(p->macaddr);
ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok);
return ret;
}
@@ -10234,7 +10233,7 @@ out:
}
/**
- * t4_set_vf_mac - Set MAC address for the specified VF
+ * t4_set_vf_mac_acl - Set MAC address for the specified VF
* @adapter: The adapter
* @vf: one of the VFs instantiated by the specified PF
* @naddr: the number of MAC addresses
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
index 95657da0aa4b..7bc80eeb2c21 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
@@ -954,7 +954,7 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *tq,
}
/**
- * check_ring_tx_db - check and potentially ring a TX queue's doorbell
+ * ring_tx_db - check and potentially ring a TX queue's doorbell
* @adapter: the adapter
* @tq: the TX queue
* @n: number of new descriptors to give to HW
diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
index 19dc7dc054a2..bcad69c48074 100644
--- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
+++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
@@ -2134,7 +2134,7 @@ static void chtls_abort_req_rss(struct sock *sk, struct sk_buff *skb)
sk->sk_err = ETIMEDOUT;
if (!sock_flag(sk, SOCK_DEAD))
- sk->sk_error_report(sk);
+ sk_error_report(sk);
if (sk->sk_state == TCP_SYN_RECV && !abort_syn_rcv(sk, skb))
return;
diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c
index 8df6f081f244..c2ebb3388789 100644
--- a/drivers/net/ethernet/cortina/gemini.c
+++ b/drivers/net/ethernet/cortina/gemini.c
@@ -2356,8 +2356,6 @@ static int gemini_ethernet_port_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct gemini_ethernet *geth;
struct net_device *netdev;
- struct resource *gmacres;
- struct resource *dmares;
struct device *parent;
unsigned int id;
int irq;
@@ -2390,24 +2388,18 @@ static int gemini_ethernet_port_probe(struct platform_device *pdev)
port->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
/* DMA memory */
- dmares = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!dmares) {
- dev_err(dev, "no DMA resource\n");
- return -ENODEV;
- }
- port->dma_base = devm_ioremap_resource(dev, dmares);
- if (IS_ERR(port->dma_base))
+ port->dma_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+ if (IS_ERR(port->dma_base)) {
+ dev_err(dev, "get DMA address failed\n");
return PTR_ERR(port->dma_base);
+ }
/* GMAC config memory */
- gmacres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!gmacres) {
- dev_err(dev, "no GMAC resource\n");
- return -ENODEV;
- }
- port->gmac_base = devm_ioremap_resource(dev, gmacres);
- if (IS_ERR(port->gmac_base))
+ port->gmac_base = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
+ if (IS_ERR(port->gmac_base)) {
+ dev_err(dev, "get GMAC address failed\n");
return PTR_ERR(port->gmac_base);
+ }
/* Interrupt */
irq = platform_get_irq(pdev, 0);
@@ -2502,10 +2494,6 @@ static int gemini_ethernet_port_probe(struct platform_device *pdev)
if (ret)
goto unprepare;
- netdev_info(netdev,
- "irq %d, DMA @ 0x%pap, GMAC @ 0x%pap\n",
- port->irq, &dmares->start,
- &gmacres->start);
return 0;
unprepare:
@@ -2544,17 +2532,13 @@ static int gemini_ethernet_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct gemini_ethernet *geth;
unsigned int retry = 5;
- struct resource *res;
u32 val;
/* Global registers */
geth = devm_kzalloc(dev, sizeof(*geth), GFP_KERNEL);
if (!geth)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
- geth->base = devm_ioremap_resource(dev, res);
+ geth->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(geth->base))
return PTR_ERR(geth->base);
geth->dev = dev;
diff --git a/drivers/net/ethernet/dec/tulip/de2104x.c b/drivers/net/ethernet/dec/tulip/de2104x.c
index b018195f0243..117c26fa5909 100644
--- a/drivers/net/ethernet/dec/tulip/de2104x.c
+++ b/drivers/net/ethernet/dec/tulip/de2104x.c
@@ -832,8 +832,8 @@ static struct net_device_stats *de_get_stats(struct net_device *dev)
/* The chip only need report frame silently dropped. */
spin_lock_irq(&de->lock);
- if (netif_running(dev) && netif_device_present(dev))
- __de_get_stats(de);
+ if (netif_running(dev) && netif_device_present(dev))
+ __de_get_stats(de);
spin_unlock_irq(&de->lock);
return &dev->stats;
diff --git a/drivers/net/ethernet/dec/tulip/de4x5.c b/drivers/net/ethernet/dec/tulip/de4x5.c
index 683e328b5461..b125d7faefdf 100644
--- a/drivers/net/ethernet/dec/tulip/de4x5.c
+++ b/drivers/net/ethernet/dec/tulip/de4x5.c
@@ -396,7 +396,7 @@
<earl@exis.net>.
Updated the PCI interface to conform with the latest
version. I hope nothing is broken...
- Add TX done interrupt modification from suggestion
+ Add TX done interrupt modification from suggestion
by <Austin.Donnelly@cl.cam.ac.uk>.
Fix is_anc_capable() bug reported by
<Austin.Donnelly@cl.cam.ac.uk>.
@@ -1499,7 +1499,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
netif_stop_queue(dev);
load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
- lp->stats.tx_bytes += skb->len;
+ lp->stats.tx_bytes += skb->len;
outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */
lp->tx_new = (lp->tx_new + 1) % lp->txRingSize;
@@ -1651,7 +1651,7 @@ de4x5_rx(struct net_device *dev)
/* Update stats */
lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ lp->stats.rx_bytes += pkt_len;
}
}
diff --git a/drivers/net/ethernet/dec/tulip/dmfe.c b/drivers/net/ethernet/dec/tulip/dmfe.c
index 87a27fe2992d..c763b692e164 100644
--- a/drivers/net/ethernet/dec/tulip/dmfe.c
+++ b/drivers/net/ethernet/dec/tulip/dmfe.c
@@ -518,7 +518,7 @@ static void dmfe_remove_one(struct pci_dev *pdev)
DMFE_DBUG(0, "dmfe_remove_one()", 0);
- if (dev) {
+ if (dev) {
unregister_netdev(dev);
pci_iounmap(db->pdev, db->ioaddr);
@@ -567,10 +567,10 @@ static int dmfe_open(struct net_device *dev)
/* CR6 operation mode decision */
if ( !chkmode || (db->chip_id == PCI_DM9132_ID) ||
(db->chip_revision >= 0x30) ) {
- db->cr6_data |= DMFE_TXTH_256;
+ db->cr6_data |= DMFE_TXTH_256;
db->cr0_data = CR0_DEFAULT;
db->dm910x_chk_mode=4; /* Enter the normal mode */
- } else {
+ } else {
db->cr6_data |= CR6_SFT; /* Store & Forward mode */
db->cr0_data = 0;
db->dm910x_chk_mode = 1; /* Enter the check mode */
@@ -903,7 +903,7 @@ static void dmfe_free_tx_pkt(struct net_device *dev, struct dmfe_board_info *db)
}
}
- txptr = txptr->next_tx_desc;
+ txptr = txptr->next_tx_desc;
}/* End of while */
/* Update TX remove pointer to next */
@@ -1121,7 +1121,7 @@ static void dmfe_timer(struct timer_list *t)
void __iomem *ioaddr = db->ioaddr;
u32 tmp_cr8;
unsigned char tmp_cr12;
- unsigned long flags;
+ unsigned long flags;
int link_ok, link_ok_phy;
@@ -1217,7 +1217,7 @@ static void dmfe_timer(struct timer_list *t)
if (link_ok_phy != link_ok) {
DMFE_DBUG (0, "PHY and chip report different link status", 0);
link_ok = link_ok | link_ok_phy;
- }
+ }
if ( !link_ok && netif_carrier_ok(dev)) {
/* Link Failed */
@@ -1699,14 +1699,14 @@ static void dmfe_set_phyxcer(struct dmfe_board_info *db)
if (db->chip_id == PCI_DM9009_ID) phy_reg &= 0x61;
}
- /* Write new capability to Phyxcer Reg4 */
+ /* Write new capability to Phyxcer Reg4 */
if ( !(phy_reg & 0x01e0)) {
phy_reg|=db->PHY_reg4;
db->media_mode|=DMFE_AUTO;
}
dmfe_phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
- /* Restart Auto-Negotiation */
+ /* Restart Auto-Negotiation */
if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
dmfe_phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id);
if ( !db->chip_type )
@@ -1754,7 +1754,7 @@ static void dmfe_process_mode(struct dmfe_board_info *db)
}
dmfe_phy_write(db->ioaddr,
db->phy_addr, 0, phy_reg, db->chip_id);
- if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
+ if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
mdelay(20);
dmfe_phy_write(db->ioaddr,
db->phy_addr, 0, phy_reg, db->chip_id);
diff --git a/drivers/net/ethernet/dec/tulip/pnic2.c b/drivers/net/ethernet/dec/tulip/pnic2.c
index 412adaa7fdf8..72a09156b48b 100644
--- a/drivers/net/ethernet/dec/tulip/pnic2.c
+++ b/drivers/net/ethernet/dec/tulip/pnic2.c
@@ -351,7 +351,7 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
del_timer_sync(&tp->timer);
pnic2_start_nway(dev);
tp->timer.expires = RUN_AT(3*HZ);
- add_timer(&tp->timer);
+ add_timer(&tp->timer);
}
return;
@@ -375,7 +375,7 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
del_timer_sync(&tp->timer);
pnic2_start_nway(dev);
tp->timer.expires = RUN_AT(3*HZ);
- add_timer(&tp->timer);
+ add_timer(&tp->timer);
}
return;
diff --git a/drivers/net/ethernet/dec/tulip/tulip.h b/drivers/net/ethernet/dec/tulip/tulip.h
index 815907259048..0ed598dc7569 100644
--- a/drivers/net/ethernet/dec/tulip/tulip.h
+++ b/drivers/net/ethernet/dec/tulip/tulip.h
@@ -478,7 +478,6 @@ void t21142_lnk_change(struct net_device *dev, int csr5);
void pnic2_lnk_change(struct net_device *dev, int csr5);
void pnic2_timer(struct timer_list *t);
void pnic2_start_nway(struct net_device *dev);
-void pnic2_lnk_change(struct net_device *dev, int csr5);
/* eeprom.c */
void tulip_parse_eeprom(struct net_device *dev);
diff --git a/drivers/net/ethernet/dec/tulip/uli526x.c b/drivers/net/ethernet/dec/tulip/uli526x.c
index 13e73ed15ef0..d67ef7d02d6b 100644
--- a/drivers/net/ethernet/dec/tulip/uli526x.c
+++ b/drivers/net/ethernet/dec/tulip/uli526x.c
@@ -780,7 +780,7 @@ static void uli526x_free_tx_pkt(struct net_device *dev,
}
}
- txptr = txptr->next_tx_desc;
+ txptr = txptr->next_tx_desc;
}/* End of while */
/* Update TX remove pointer to next */
@@ -1015,7 +1015,7 @@ static void uli526x_timer(struct timer_list *t)
struct net_device *dev = pci_get_drvdata(db->pdev);
struct uli_phy_ops *phy = &db->phy;
void __iomem *ioaddr = db->ioaddr;
- unsigned long flags;
+ unsigned long flags;
u8 tmp_cr12 = 0;
u32 tmp_cr8;
@@ -1535,14 +1535,14 @@ static void uli526x_set_phyxcer(struct uli526x_board_info *db)
}
- /* Write new capability to Phyxcer Reg4 */
+ /* Write new capability to Phyxcer Reg4 */
if ( !(phy_reg & 0x01e0)) {
phy_reg|=db->PHY_reg4;
db->media_mode|=ULI526X_AUTO;
}
phy->write(db, db->phy_addr, 4, phy_reg);
- /* Restart Auto-Negotiation */
+ /* Restart Auto-Negotiation */
phy->write(db, db->phy_addr, 0, 0x1200);
udelay(50);
}
@@ -1550,7 +1550,7 @@ static void uli526x_set_phyxcer(struct uli526x_board_info *db)
/*
* Process op-mode
- AUTO mode : PHY controller in Auto-negotiation Mode
+ AUTO mode : PHY controller in Auto-negotiation Mode
* Force mode: PHY controller in force mode with HUB
* N-way force capability with SWITCH
*/
diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c
index 514df170ec5d..f6ff1f76eacb 100644
--- a/drivers/net/ethernet/dec/tulip/winbond-840.c
+++ b/drivers/net/ethernet/dec/tulip/winbond-840.c
@@ -36,7 +36,7 @@
power management.
support for big endian descriptors
Copyright (C) 2001 Manfred Spraul
- * ethtool support (jgarzik)
+ * ethtool support (jgarzik)
* Replace some MII-related magic numbers with constants (jgarzik)
TODO:
@@ -1479,7 +1479,7 @@ static int netdev_close(struct net_device *dev)
np->cur_rx, np->dirty_rx);
}
- /* Stop the chip's Tx and Rx processes. */
+ /* Stop the chip's Tx and Rx processes. */
spin_lock_irq(&np->lock);
netif_device_detach(dev);
update_csr6(dev, 0);
diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c
index ce61f79f3b7c..ee0ca712dd1c 100644
--- a/drivers/net/ethernet/dlink/sundance.c
+++ b/drivers/net/ethernet/dlink/sundance.c
@@ -1847,20 +1847,20 @@ static int netdev_close(struct net_device *dev)
/* Stop the chip's Tx and Rx processes. */
iowrite16(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1);
- for (i = 2000; i > 0; i--) {
- if ((ioread32(ioaddr + DMACtrl) & 0xc000) == 0)
+ for (i = 2000; i > 0; i--) {
+ if ((ioread32(ioaddr + DMACtrl) & 0xc000) == 0)
break;
mdelay(1);
- }
+ }
- iowrite16(GlobalReset | DMAReset | FIFOReset | NetworkReset,
+ iowrite16(GlobalReset | DMAReset | FIFOReset | NetworkReset,
ioaddr + ASIC_HI_WORD(ASICCtrl));
- for (i = 2000; i > 0; i--) {
+ for (i = 2000; i > 0; i--) {
if ((ioread16(ioaddr + ASIC_HI_WORD(ASICCtrl)) & ResetBusy) == 0)
break;
mdelay(1);
- }
+ }
#ifdef __i386__
if (netif_msg_hw(np)) {
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 701c12c9e033..649c5c429bd7 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -550,7 +550,7 @@ int be_process_mcc(struct be_adapter *adapter)
int num = 0, status = 0;
struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
- spin_lock_bh(&adapter->mcc_cq_lock);
+ spin_lock(&adapter->mcc_cq_lock);
while ((compl = be_mcc_compl_get(adapter))) {
if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
@@ -566,7 +566,7 @@ int be_process_mcc(struct be_adapter *adapter)
if (num)
be_cq_notify(adapter, mcc_obj->cq.id, mcc_obj->rearm_cq, num);
- spin_unlock_bh(&adapter->mcc_cq_lock);
+ spin_unlock(&adapter->mcc_cq_lock);
return status;
}
@@ -581,7 +581,9 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
if (be_check_error(adapter, BE_ERROR_ANY))
return -EIO;
+ local_bh_disable();
status = be_process_mcc(adapter);
+ local_bh_enable();
if (atomic_read(&mcc_obj->q.used) == 0)
break;
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 7968568bbe21..361c1c87c183 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -5501,7 +5501,9 @@ static void be_worker(struct work_struct *work)
* mcc completions
*/
if (!netif_running(adapter->netdev)) {
+ local_bh_disable();
be_process_mcc(adapter);
+ local_bh_enable();
goto reschedule;
}
diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c
index e3954d8835e7..f9a288a6ec8c 100644
--- a/drivers/net/ethernet/ezchip/nps_enet.c
+++ b/drivers/net/ethernet/ezchip/nps_enet.c
@@ -607,7 +607,7 @@ static s32 nps_enet_probe(struct platform_device *pdev)
/* Get IRQ number */
priv->irq = platform_get_irq(pdev, 0);
- if (!priv->irq) {
+ if (priv->irq < 0) {
dev_err(dev, "failed to retrieve <irq Rx-Tx> value from device tree\n");
err = -ENODEV;
goto out_netdev;
@@ -630,8 +630,7 @@ static s32 nps_enet_probe(struct platform_device *pdev)
out_netif_api:
netif_napi_del(&priv->napi);
out_netdev:
- if (err)
- free_netdev(ndev);
+ free_netdev(ndev);
return err;
}
@@ -642,8 +641,8 @@ static s32 nps_enet_remove(struct platform_device *pdev)
struct nps_enet_priv *priv = netdev_priv(ndev);
unregister_netdev(ndev);
- free_netdev(ndev);
netif_napi_del(&priv->napi);
+ free_netdev(ndev);
return 0;
}
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index 04421aec2dfd..11dbbfd38770 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -1830,14 +1830,17 @@ static int ftgmac100_probe(struct platform_device *pdev)
if (np && of_get_property(np, "use-ncsi", NULL)) {
if (!IS_ENABLED(CONFIG_NET_NCSI)) {
dev_err(&pdev->dev, "NCSI stack not enabled\n");
+ err = -EINVAL;
goto err_phy_connect;
}
dev_info(&pdev->dev, "Using NCSI interface\n");
priv->use_ncsi = true;
priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler);
- if (!priv->ndev)
+ if (!priv->ndev) {
+ err = -EINVAL;
goto err_phy_connect;
+ }
} else if (np && of_get_property(np, "phy-handle", NULL)) {
struct phy_device *phy;
@@ -1856,6 +1859,7 @@ static int ftgmac100_probe(struct platform_device *pdev)
&ftgmac100_adjust_link);
if (!phy) {
dev_err(&pdev->dev, "Failed to connect to phy\n");
+ err = -EINVAL;
goto err_phy_connect;
}
diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c
index 0908771aa9ac..0f141c14d72d 100644
--- a/drivers/net/ethernet/fealnx.c
+++ b/drivers/net/ethernet/fealnx.c
@@ -144,7 +144,7 @@ struct chip_info {
};
static const struct chip_info skel_netdrv_tbl[] = {
- { "100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
+ { "100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
{ "100/10M Ethernet PCI Adapter", HAS_CHIP_XCVR },
{ "1000/100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
};
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index 177c020bf34a..e6826561cf11 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -2558,13 +2558,9 @@ static u32 dpaa_run_xdp(struct dpaa_priv *priv, struct qm_fd *fd, void *vaddr,
u32 xdp_act;
int err;
- rcu_read_lock();
-
xdp_prog = READ_ONCE(priv->xdp_prog);
- if (!xdp_prog) {
- rcu_read_unlock();
+ if (!xdp_prog)
return XDP_PASS;
- }
xdp_init_buff(&xdp, DPAA_BP_RAW_SIZE - DPAA_TX_PRIV_DATA_SIZE,
&dpaa_fq->xdp_rxq);
@@ -2638,8 +2634,6 @@ static u32 dpaa_run_xdp(struct dpaa_priv *priv, struct qm_fd *fd, void *vaddr,
break;
}
- rcu_read_unlock();
-
return xdp_act;
}
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c
index b87db0846e10..8356af4631fd 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-debugfs.c
@@ -121,10 +121,14 @@ DEFINE_SHOW_ATTRIBUTE(dpaa2_dbg_ch);
void dpaa2_dbg_add(struct dpaa2_eth_priv *priv)
{
+ struct fsl_mc_device *dpni_dev;
struct dentry *dir;
+ char name[10];
/* Create a directory for the interface */
- dir = debugfs_create_dir(priv->net_dev->name, dpaa2_dbg_root);
+ dpni_dev = to_fsl_mc_device(priv->net_dev->dev.parent);
+ snprintf(name, 10, "dpni.%d", dpni_dev->obj_desc.id);
+ dir = debugfs_create_dir(name, dpaa2_dbg_root);
priv->dbg.dir = dir;
/* per-cpu stats file */
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
index e0c3c58e2ac7..973352393bd4 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
@@ -352,8 +352,6 @@ static u32 dpaa2_eth_run_xdp(struct dpaa2_eth_priv *priv,
u32 xdp_act = XDP_PASS;
int err, offset;
- rcu_read_lock();
-
xdp_prog = READ_ONCE(ch->xdp.prog);
if (!xdp_prog)
goto out;
@@ -414,7 +412,6 @@ static u32 dpaa2_eth_run_xdp(struct dpaa2_eth_priv *priv,
ch->xdp.res |= xdp_act;
out:
- rcu_read_unlock();
return xdp_act;
}
@@ -4164,10 +4161,11 @@ static int dpaa2_eth_connect_mac(struct dpaa2_eth_priv *priv)
if (dpaa2_eth_is_type_phy(priv)) {
err = dpaa2_mac_connect(mac);
- if (err) {
- netdev_err(priv->net_dev, "Error connecting to the MAC endpoint\n");
+ if (err && err != -EPROBE_DEFER)
+ netdev_err(priv->net_dev, "Error connecting to the MAC endpoint: %pe",
+ ERR_PTR(err));
+ if (err)
goto err_close_mac;
- }
}
return 0;
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
index ccaf7e35abeb..ae6d382d8735 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
@@ -1,6 +1,9 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* Copyright 2019 NXP */
+#include <linux/acpi.h>
+#include <linux/property.h>
+
#include "dpaa2-eth.h"
#include "dpaa2-mac.h"
@@ -34,39 +37,51 @@ static int phy_mode(enum dpmac_eth_if eth_if, phy_interface_t *if_mode)
return 0;
}
-/* Caller must call of_node_put on the returned value */
-static struct device_node *dpaa2_mac_get_node(u16 dpmac_id)
+static struct fwnode_handle *dpaa2_mac_get_node(struct device *dev,
+ u16 dpmac_id)
{
- struct device_node *dpmacs, *dpmac = NULL;
- u32 id;
+ struct fwnode_handle *fwnode, *parent, *child = NULL;
+ struct device_node *dpmacs = NULL;
int err;
+ u32 id;
- dpmacs = of_find_node_by_name(NULL, "dpmacs");
- if (!dpmacs)
- return NULL;
+ fwnode = dev_fwnode(dev->parent);
+ if (is_of_node(fwnode)) {
+ dpmacs = of_find_node_by_name(NULL, "dpmacs");
+ if (!dpmacs)
+ return NULL;
+ parent = of_fwnode_handle(dpmacs);
+ } else if (is_acpi_node(fwnode)) {
+ parent = fwnode;
+ }
- while ((dpmac = of_get_next_child(dpmacs, dpmac)) != NULL) {
- err = of_property_read_u32(dpmac, "reg", &id);
+ fwnode_for_each_child_node(parent, child) {
+ err = -EINVAL;
+ if (is_acpi_device_node(child))
+ err = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), &id);
+ else if (is_of_node(child))
+ err = of_property_read_u32(to_of_node(child), "reg", &id);
if (err)
continue;
- if (id == dpmac_id)
- break;
- }
+ if (id == dpmac_id) {
+ of_node_put(dpmacs);
+ return child;
+ }
+ }
of_node_put(dpmacs);
-
- return dpmac;
+ return NULL;
}
-static int dpaa2_mac_get_if_mode(struct device_node *node,
+static int dpaa2_mac_get_if_mode(struct fwnode_handle *dpmac_node,
struct dpmac_attr attr)
{
phy_interface_t if_mode;
int err;
- err = of_get_phy_mode(node, &if_mode);
- if (!err)
- return if_mode;
+ err = fwnode_get_phy_mode(dpmac_node);
+ if (err > 0)
+ return err;
err = phy_mode(attr.eth_if, &if_mode);
if (!err)
@@ -235,26 +250,27 @@ static const struct phylink_mac_ops dpaa2_mac_phylink_ops = {
};
static int dpaa2_pcs_create(struct dpaa2_mac *mac,
- struct device_node *dpmac_node, int id)
+ struct fwnode_handle *dpmac_node,
+ int id)
{
struct mdio_device *mdiodev;
- struct device_node *node;
+ struct fwnode_handle *node;
- node = of_parse_phandle(dpmac_node, "pcs-handle", 0);
- if (!node) {
+ node = fwnode_find_reference(dpmac_node, "pcs-handle", 0);
+ if (IS_ERR(node)) {
/* do not error out on old DTS files */
netdev_warn(mac->net_dev, "pcs-handle node not found\n");
return 0;
}
- if (!of_device_is_available(node)) {
+ if (!fwnode_device_is_available(node)) {
netdev_err(mac->net_dev, "pcs-handle node not available\n");
- of_node_put(node);
+ fwnode_handle_put(node);
return -ENODEV;
}
- mdiodev = of_mdio_find_device(node);
- of_node_put(node);
+ mdiodev = fwnode_mdio_find_device(node);
+ fwnode_handle_put(node);
if (!mdiodev)
return -EPROBE_DEFER;
@@ -283,36 +299,33 @@ static void dpaa2_pcs_destroy(struct dpaa2_mac *mac)
int dpaa2_mac_connect(struct dpaa2_mac *mac)
{
struct net_device *net_dev = mac->net_dev;
- struct device_node *dpmac_node;
+ struct fwnode_handle *dpmac_node;
struct phylink *phylink;
int err;
mac->if_link_type = mac->attr.link_type;
- dpmac_node = dpaa2_mac_get_node(mac->attr.id);
+ dpmac_node = mac->fw_node;
if (!dpmac_node) {
netdev_err(net_dev, "No dpmac@%d node found.\n", mac->attr.id);
return -ENODEV;
}
err = dpaa2_mac_get_if_mode(dpmac_node, mac->attr);
- if (err < 0) {
- err = -EINVAL;
- goto err_put_node;
- }
+ if (err < 0)
+ return -EINVAL;
mac->if_mode = err;
/* The MAC does not have the capability to add RGMII delays so
* error out if the interface mode requests them and there is no PHY
* to act upon them
*/
- if (of_phy_is_fixed_link(dpmac_node) &&
+ if (of_phy_is_fixed_link(to_of_node(dpmac_node)) &&
(mac->if_mode == PHY_INTERFACE_MODE_RGMII_ID ||
mac->if_mode == PHY_INTERFACE_MODE_RGMII_RXID ||
mac->if_mode == PHY_INTERFACE_MODE_RGMII_TXID)) {
netdev_err(net_dev, "RGMII delay not supported\n");
- err = -EINVAL;
- goto err_put_node;
+ return -EINVAL;
}
if ((mac->attr.link_type == DPMAC_LINK_TYPE_PHY &&
@@ -320,14 +333,14 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
mac->attr.link_type == DPMAC_LINK_TYPE_BACKPLANE) {
err = dpaa2_pcs_create(mac, dpmac_node, mac->attr.id);
if (err)
- goto err_put_node;
+ return err;
}
mac->phylink_config.dev = &net_dev->dev;
mac->phylink_config.type = PHYLINK_NETDEV;
phylink = phylink_create(&mac->phylink_config,
- of_fwnode_handle(dpmac_node), mac->if_mode,
+ dpmac_node, mac->if_mode,
&dpaa2_mac_phylink_ops);
if (IS_ERR(phylink)) {
err = PTR_ERR(phylink);
@@ -338,22 +351,18 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
if (mac->pcs)
phylink_set_pcs(mac->phylink, &mac->pcs->pcs);
- err = phylink_of_phy_connect(mac->phylink, dpmac_node, 0);
+ err = phylink_fwnode_phy_connect(mac->phylink, dpmac_node, 0);
if (err) {
- netdev_err(net_dev, "phylink_of_phy_connect() = %d\n", err);
+ netdev_err(net_dev, "phylink_fwnode_phy_connect() = %d\n", err);
goto err_phylink_destroy;
}
- of_node_put(dpmac_node);
-
return 0;
err_phylink_destroy:
phylink_destroy(mac->phylink);
err_pcs_destroy:
dpaa2_pcs_destroy(mac);
-err_put_node:
- of_node_put(dpmac_node);
return err;
}
@@ -388,6 +397,12 @@ int dpaa2_mac_open(struct dpaa2_mac *mac)
goto err_close_dpmac;
}
+ /* Find the device node representing the MAC device and link the device
+ * behind the associated netdev to it.
+ */
+ mac->fw_node = dpaa2_mac_get_node(&mac->mc_dev->dev, mac->attr.id);
+ net_dev->dev.of_node = to_of_node(mac->fw_node);
+
return 0;
err_close_dpmac:
@@ -400,6 +415,8 @@ void dpaa2_mac_close(struct dpaa2_mac *mac)
struct fsl_mc_device *dpmac_dev = mac->mc_dev;
dpmac_close(mac->mc_io, 0, dpmac_dev->mc_handle);
+ if (mac->fw_node)
+ fwnode_handle_put(mac->fw_node);
}
static char dpaa2_mac_ethtool_stats[][ETH_GSTRING_LEN] = {
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
index 13d42dd58ec9..7842cbb2207a 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
@@ -24,6 +24,7 @@ struct dpaa2_mac {
phy_interface_t if_mode;
enum dpmac_link_type if_link_type;
struct lynx_pcs *pcs;
+ struct fwnode_handle *fw_node;
};
bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev,
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index 05de37c3b64c..f3d12d0714fb 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -1625,7 +1625,7 @@ static int dpaa2_switch_port_bridge_flags(struct net_device *netdev,
return 0;
}
-static int dpaa2_switch_port_attr_set(struct net_device *netdev,
+static int dpaa2_switch_port_attr_set(struct net_device *netdev, const void *ctx,
const struct switchdev_attr *attr,
struct netlink_ext_ack *extack)
{
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ierb.c b/drivers/net/ethernet/freescale/enetc/enetc_ierb.c
index 8b356c485507..ee1468e3eaa3 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ierb.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ierb.c
@@ -99,15 +99,13 @@ EXPORT_SYMBOL(enetc_ierb_register_pf);
static int enetc_ierb_probe(struct platform_device *pdev)
{
struct enetc_ierb *ierb;
- struct resource *res;
void __iomem *regs;
ierb = devm_kzalloc(&pdev->dev, sizeof(*ierb), GFP_KERNEL);
if (!ierb)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- regs = devm_ioremap_resource(&pdev->dev, res);
+ regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(regs))
return PTR_ERR(regs);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 31274325159a..c84f6c226743 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* Copyright 2017-2019 NXP */
+#include <asm/unaligned.h>
#include <linux/mdio.h>
#include <linux/module.h>
#include <linux/fsl/enetc_mdio.h>
@@ -17,15 +18,15 @@ static void enetc_pf_get_primary_mac_addr(struct enetc_hw *hw, int si, u8 *addr)
u32 upper = __raw_readl(hw->port + ENETC_PSIPMAR0(si));
u16 lower = __raw_readw(hw->port + ENETC_PSIPMAR1(si));
- *(u32 *)addr = upper;
- *(u16 *)(addr + 4) = lower;
+ put_unaligned_le32(upper, addr);
+ put_unaligned_le16(lower, addr + 4);
}
static void enetc_pf_set_primary_mac_addr(struct enetc_hw *hw, int si,
const u8 *addr)
{
- u32 upper = *(const u32 *)addr;
- u16 lower = *(const u16 *)(addr + 4);
+ u32 upper = get_unaligned_le32(addr);
+ u16 lower = get_unaligned_le16(addr + 4);
__raw_writel(upper, hw->port + ENETC_PSIPMAR0(si));
__raw_writew(lower, hw->port + ENETC_PSIPMAR1(si));
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
index af699f2ad095..4577226d3c6a 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
@@ -465,8 +465,13 @@ static int enetc_streamid_hw_set(struct enetc_ndev_priv *priv,
struct streamid_conf *si_conf;
u16 data_size;
dma_addr_t dma;
+ int port;
int err;
+ port = enetc_pf_to_port(priv->si->pdev);
+ if (port < 0)
+ return -EINVAL;
+
if (sid->index >= priv->psfp_cap.max_streamid)
return -EINVAL;
@@ -499,7 +504,7 @@ static int enetc_streamid_hw_set(struct enetc_ndev_priv *priv,
si_conf = &cbd.sid_set;
/* Only one port supported for one entry, set itself */
- si_conf->iports = cpu_to_le32(1 << enetc_pf_to_port(priv->si->pdev));
+ si_conf->iports = cpu_to_le32(1 << port);
si_conf->id_type = 1;
si_conf->oui[2] = 0x0;
si_conf->oui[1] = 0x80;
@@ -524,7 +529,7 @@ static int enetc_streamid_hw_set(struct enetc_ndev_priv *priv,
si_conf->en = 0x80;
si_conf->stream_handle = cpu_to_le32(sid->handle);
- si_conf->iports = cpu_to_le32(1 << enetc_pf_to_port(priv->si->pdev));
+ si_conf->iports = cpu_to_le32(1 << port);
si_conf->id_type = sid->filtertype;
si_conf->oui[2] = 0x0;
si_conf->oui[1] = 0x80;
@@ -567,6 +572,11 @@ static int enetc_streamfilter_hw_set(struct enetc_ndev_priv *priv,
{
struct enetc_cbd cbd = {.cmd = 0};
struct sfi_conf *sfi_config;
+ int port;
+
+ port = enetc_pf_to_port(priv->si->pdev);
+ if (port < 0)
+ return -EINVAL;
cbd.index = cpu_to_le16(sfi->index);
cbd.cls = BDCR_CMD_STREAM_FILTER;
@@ -586,8 +596,7 @@ static int enetc_streamfilter_hw_set(struct enetc_ndev_priv *priv,
}
sfi_config->sg_inst_table_index = cpu_to_le16(sfi->gate_id);
- sfi_config->input_ports =
- cpu_to_le32(1 << enetc_pf_to_port(priv->si->pdev));
+ sfi_config->input_ports = cpu_to_le32(1 << port);
/* The priority value which may be matched against the
* frame’s priority value to determine a match for this entry.
@@ -1548,7 +1557,7 @@ int enetc_setup_tc_psfp(struct net_device *ndev, void *type_data)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct flow_block_offload *f = type_data;
- int err;
+ int port, err;
err = flow_block_cb_setup_simple(f, &enetc_block_cb_list,
enetc_setup_tc_block_cb,
@@ -1558,10 +1567,18 @@ int enetc_setup_tc_psfp(struct net_device *ndev, void *type_data)
switch (f->command) {
case FLOW_BLOCK_BIND:
- set_bit(enetc_pf_to_port(priv->si->pdev), &epsfp.dev_bitmap);
+ port = enetc_pf_to_port(priv->si->pdev);
+ if (port < 0)
+ return -EINVAL;
+
+ set_bit(port, &epsfp.dev_bitmap);
break;
case FLOW_BLOCK_UNBIND:
- clear_bit(enetc_pf_to_port(priv->si->pdev), &epsfp.dev_bitmap);
+ port = enetc_pf_to_port(priv->si->pdev);
+ if (port < 0)
+ return -EINVAL;
+
+ clear_bit(port, &epsfp.dev_bitmap);
if (!epsfp.dev_bitmap)
clean_psfp_all();
break;
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 0602d5d5d2ee..2e002e4b4b4a 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -467,6 +467,11 @@ struct bufdesc_ex {
*/
#define FEC_QUIRK_NO_HARD_RESET (1 << 18)
+/* i.MX6SX ENET IP supports multiple queues (3 queues), use this quirk to
+ * represents this ENET IP.
+ */
+#define FEC_QUIRK_HAS_MULTI_QUEUES (1 << 19)
+
struct bufdesc_prop {
int qid;
/* Address of Rx and Tx buffers */
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index ad82cffc6f3f..8aea707a65a7 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -76,6 +76,8 @@ static void fec_enet_itr_coal_init(struct net_device *ndev);
#define DRIVER_NAME "fec"
+static const u16 fec_enet_vlan_pri_to_queue[8] = {0, 0, 1, 1, 1, 2, 2, 2};
+
/* Pause frame feild and FIFO threshold */
#define FEC_ENET_FCE (1 << 5)
#define FEC_ENET_RSEM_V 0x84
@@ -122,7 +124,7 @@ static const struct fec_devinfo fec_imx6x_info = {
FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE |
- FEC_QUIRK_CLEAR_SETUP_MII,
+ FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES,
};
static const struct fec_devinfo fec_imx6ul_info = {
@@ -421,6 +423,7 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
estatus |= FEC_TX_BD_FTYPE(txq->bd.qid);
if (skb->ip_summed == CHECKSUM_PARTIAL)
estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
+
ebdp->cbd_bdu = 0;
ebdp->cbd_esc = cpu_to_fec32(estatus);
}
@@ -954,7 +957,7 @@ fec_restart(struct net_device *ndev)
* For i.MX6SX SOC, enet use AXI bus, we use disable MAC
* instead of reset MAC itself.
*/
- if (fep->quirks & FEC_QUIRK_HAS_AVB ||
+ if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES ||
((fep->quirks & FEC_QUIRK_NO_HARD_RESET) && fep->link)) {
writel(0, fep->hwp + FEC_ECNTRL);
} else {
@@ -1165,7 +1168,7 @@ fec_stop(struct net_device *ndev)
* instead of reset MAC itself.
*/
if (!(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) {
- if (fep->quirks & FEC_QUIRK_HAS_AVB) {
+ if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) {
writel(0, fep->hwp + FEC_ECNTRL);
} else {
writel(1, fep->hwp + FEC_ECNTRL);
@@ -2570,7 +2573,7 @@ static void fec_enet_itr_coal_set(struct net_device *ndev)
writel(tx_itr, fep->hwp + FEC_TXIC0);
writel(rx_itr, fep->hwp + FEC_RXIC0);
- if (fep->quirks & FEC_QUIRK_HAS_AVB) {
+ if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) {
writel(tx_itr, fep->hwp + FEC_TXIC1);
writel(rx_itr, fep->hwp + FEC_RXIC1);
writel(tx_itr, fep->hwp + FEC_TXIC2);
@@ -3239,10 +3242,40 @@ static int fec_set_features(struct net_device *netdev,
return 0;
}
+static u16 fec_enet_get_raw_vlan_tci(struct sk_buff *skb)
+{
+ struct vlan_ethhdr *vhdr;
+ unsigned short vlan_TCI = 0;
+
+ if (skb->protocol == htons(ETH_P_ALL)) {
+ vhdr = (struct vlan_ethhdr *)(skb->data);
+ vlan_TCI = ntohs(vhdr->h_vlan_TCI);
+ }
+
+ return vlan_TCI;
+}
+
+static u16 fec_enet_select_queue(struct net_device *ndev, struct sk_buff *skb,
+ struct net_device *sb_dev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ u16 vlan_tag;
+
+ if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
+ return netdev_pick_tx(ndev, skb, NULL);
+
+ vlan_tag = fec_enet_get_raw_vlan_tci(skb);
+ if (!vlan_tag)
+ return vlan_tag;
+
+ return fec_enet_vlan_pri_to_queue[vlan_tag >> 13];
+}
+
static const struct net_device_ops fec_netdev_ops = {
.ndo_open = fec_enet_open,
.ndo_stop = fec_enet_close,
.ndo_start_xmit = fec_enet_start_xmit,
+ .ndo_select_queue = fec_enet_select_queue,
.ndo_set_rx_mode = set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
.ndo_tx_timeout = fec_timeout,
@@ -3371,7 +3404,7 @@ static int fec_enet_init(struct net_device *ndev)
fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
}
- if (fep->quirks & FEC_QUIRK_HAS_AVB) {
+ if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) {
fep->tx_align = 0;
fep->rx_align = 0x3f;
}
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index f2945abdb041..9646483137c4 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -274,32 +274,44 @@ static void gfar_configure_coalescing_all(struct gfar_private *priv)
gfar_configure_coalescing(priv, 0xFF, 0xFF);
}
-static struct net_device_stats *gfar_get_stats(struct net_device *dev)
+static void gfar_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
struct gfar_private *priv = netdev_priv(dev);
- unsigned long rx_packets = 0, rx_bytes = 0, rx_dropped = 0;
- unsigned long tx_packets = 0, tx_bytes = 0;
int i;
for (i = 0; i < priv->num_rx_queues; i++) {
- rx_packets += priv->rx_queue[i]->stats.rx_packets;
- rx_bytes += priv->rx_queue[i]->stats.rx_bytes;
- rx_dropped += priv->rx_queue[i]->stats.rx_dropped;
+ stats->rx_packets += priv->rx_queue[i]->stats.rx_packets;
+ stats->rx_bytes += priv->rx_queue[i]->stats.rx_bytes;
+ stats->rx_dropped += priv->rx_queue[i]->stats.rx_dropped;
}
- dev->stats.rx_packets = rx_packets;
- dev->stats.rx_bytes = rx_bytes;
- dev->stats.rx_dropped = rx_dropped;
-
for (i = 0; i < priv->num_tx_queues; i++) {
- tx_bytes += priv->tx_queue[i]->stats.tx_bytes;
- tx_packets += priv->tx_queue[i]->stats.tx_packets;
+ stats->tx_bytes += priv->tx_queue[i]->stats.tx_bytes;
+ stats->tx_packets += priv->tx_queue[i]->stats.tx_packets;
}
- dev->stats.tx_bytes = tx_bytes;
- dev->stats.tx_packets = tx_packets;
+ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+ struct rmon_mib __iomem *rmon = &priv->gfargrp[0].regs->rmon;
+ unsigned long flags;
+ u32 rdrp, car, car_before;
+ u64 rdrp_offset;
+
+ spin_lock_irqsave(&priv->rmon_overflow.lock, flags);
+ car = gfar_read(&rmon->car1) & CAR1_C1RDR;
+ do {
+ car_before = car;
+ rdrp = gfar_read(&rmon->rdrp);
+ car = gfar_read(&rmon->car1) & CAR1_C1RDR;
+ } while (car != car_before);
+ if (car) {
+ priv->rmon_overflow.rdrp++;
+ gfar_write(&rmon->car1, car);
+ }
+ rdrp_offset = priv->rmon_overflow.rdrp;
+ spin_unlock_irqrestore(&priv->rmon_overflow.lock, flags);
- return &dev->stats;
+ stats->rx_missed_errors = rdrp + (rdrp_offset << 16);
+ }
}
/* Set the appropriate hash bit for the given addr */
@@ -390,7 +402,8 @@ static void gfar_ints_enable(struct gfar_private *priv)
for (i = 0; i < priv->num_grps; i++) {
struct gfar __iomem *regs = priv->gfargrp[i].regs;
/* Unmask the interrupts we look for */
- gfar_write(&regs->imask, IMASK_DEFAULT);
+ gfar_write(&regs->imask,
+ IMASK_DEFAULT | priv->rmon_overflow.imask);
}
}
@@ -2298,7 +2311,7 @@ static irqreturn_t gfar_receive(int irq, void *grp_id)
if (likely(napi_schedule_prep(&grp->napi_rx))) {
spin_lock_irqsave(&grp->grplock, flags);
imask = gfar_read(&grp->regs->imask);
- imask &= IMASK_RX_DISABLED;
+ imask &= IMASK_RX_DISABLED | grp->priv->rmon_overflow.imask;
gfar_write(&grp->regs->imask, imask);
spin_unlock_irqrestore(&grp->grplock, flags);
__napi_schedule(&grp->napi_rx);
@@ -2322,7 +2335,7 @@ static irqreturn_t gfar_transmit(int irq, void *grp_id)
if (likely(napi_schedule_prep(&grp->napi_tx))) {
spin_lock_irqsave(&grp->grplock, flags);
imask = gfar_read(&grp->regs->imask);
- imask &= IMASK_TX_DISABLED;
+ imask &= IMASK_TX_DISABLED | grp->priv->rmon_overflow.imask;
gfar_write(&grp->regs->imask, imask);
spin_unlock_irqrestore(&grp->grplock, flags);
__napi_schedule(&grp->napi_tx);
@@ -2693,6 +2706,18 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
}
netif_dbg(priv, tx_err, dev, "Transmit Error\n");
}
+ if (events & IEVENT_MSRO) {
+ struct rmon_mib __iomem *rmon = &regs->rmon;
+ u32 car;
+
+ spin_lock(&priv->rmon_overflow.lock);
+ car = gfar_read(&rmon->car1) & CAR1_C1RDR;
+ if (car) {
+ priv->rmon_overflow.rdrp++;
+ gfar_write(&rmon->car1, car);
+ }
+ spin_unlock(&priv->rmon_overflow.lock);
+ }
if (events & IEVENT_BSY) {
dev->stats.rx_over_errors++;
atomic64_inc(&priv->extra_stats.rx_bsy);
@@ -3109,11 +3134,14 @@ static void gfar_hw_init(struct gfar_private *priv)
/* Zero out the rmon mib registers if it has them */
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
- memset_io(&(regs->rmon), 0, sizeof(struct rmon_mib));
+ memset_io(&regs->rmon, 0, offsetof(struct rmon_mib, car1));
/* Mask off the CAM interrupts */
gfar_write(&regs->rmon.cam1, 0xffffffff);
gfar_write(&regs->rmon.cam2, 0xffffffff);
+ /* Clear the CAR registers (w1c style) */
+ gfar_write(&regs->rmon.car1, 0xffffffff);
+ gfar_write(&regs->rmon.car2, 0xffffffff);
}
/* Initialize ECNTRL */
@@ -3157,7 +3185,7 @@ static const struct net_device_ops gfar_netdev_ops = {
.ndo_set_rx_mode = gfar_set_multi,
.ndo_tx_timeout = gfar_timeout,
.ndo_do_ioctl = gfar_ioctl,
- .ndo_get_stats = gfar_get_stats,
+ .ndo_get_stats64 = gfar_get_stats64,
.ndo_change_carrier = fixed_phy_change_carrier,
.ndo_set_mac_address = gfar_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
@@ -3267,6 +3295,14 @@ static int gfar_probe(struct platform_device *ofdev)
gfar_hw_init(priv);
+ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+ struct rmon_mib __iomem *rmon = &priv->gfargrp[0].regs->rmon;
+
+ spin_lock_init(&priv->rmon_overflow.lock);
+ priv->rmon_overflow.imask = IMASK_MSRO;
+ gfar_write(&rmon->cam1, gfar_read(&rmon->cam1) & ~CAM1_M1RDR);
+ }
+
/* Carrier starts down, phylib will bring it up */
netif_carrier_off(dev);
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index 5ea47df93e5e..ca5e14f908fe 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -445,6 +445,60 @@ struct ethtool_rx_list {
#define RQFPR_PER 0x00000002
#define RQFPR_EER 0x00000001
+/* CAR1 bits */
+#define CAR1_C164 0x80000000
+#define CAR1_C1127 0x40000000
+#define CAR1_C1255 0x20000000
+#define CAR1_C1511 0x10000000
+#define CAR1_C11K 0x08000000
+#define CAR1_C1MAX 0x04000000
+#define CAR1_C1MGV 0x02000000
+#define CAR1_C1REJ 0x00020000
+#define CAR1_C1RBY 0x00010000
+#define CAR1_C1RPK 0x00008000
+#define CAR1_C1RFC 0x00004000
+#define CAR1_C1RMC 0x00002000
+#define CAR1_C1RBC 0x00001000
+#define CAR1_C1RXC 0x00000800
+#define CAR1_C1RXP 0x00000400
+#define CAR1_C1RXU 0x00000200
+#define CAR1_C1RAL 0x00000100
+#define CAR1_C1RFL 0x00000080
+#define CAR1_C1RCD 0x00000040
+#define CAR1_C1RCS 0x00000020
+#define CAR1_C1RUN 0x00000010
+#define CAR1_C1ROV 0x00000008
+#define CAR1_C1RFR 0x00000004
+#define CAR1_C1RJB 0x00000002
+#define CAR1_C1RDR 0x00000001
+
+/* CAM1 bits */
+#define CAM1_M164 0x80000000
+#define CAM1_M1127 0x40000000
+#define CAM1_M1255 0x20000000
+#define CAM1_M1511 0x10000000
+#define CAM1_M11K 0x08000000
+#define CAM1_M1MAX 0x04000000
+#define CAM1_M1MGV 0x02000000
+#define CAM1_M1REJ 0x00020000
+#define CAM1_M1RBY 0x00010000
+#define CAM1_M1RPK 0x00008000
+#define CAM1_M1RFC 0x00004000
+#define CAM1_M1RMC 0x00002000
+#define CAM1_M1RBC 0x00001000
+#define CAM1_M1RXC 0x00000800
+#define CAM1_M1RXP 0x00000400
+#define CAM1_M1RXU 0x00000200
+#define CAM1_M1RAL 0x00000100
+#define CAM1_M1RFL 0x00000080
+#define CAM1_M1RCD 0x00000040
+#define CAM1_M1RCS 0x00000020
+#define CAM1_M1RUN 0x00000010
+#define CAM1_M1ROV 0x00000008
+#define CAM1_M1RFR 0x00000004
+#define CAM1_M1RJB 0x00000002
+#define CAM1_M1RDR 0x00000001
+
/* TxBD status field bits */
#define TXBD_READY 0x8000
#define TXBD_PADCRC 0x4000
@@ -609,6 +663,15 @@ struct rmon_mib
u32 cam2; /* 0x.73c - Carry Mask Register Two */
};
+struct rmon_overflow {
+ /* lock for synchronization of the rdrp field of this struct, and
+ * CAR1/CAR2 registers
+ */
+ spinlock_t lock;
+ u32 imask;
+ u64 rdrp;
+};
+
struct gfar_extra_stats {
atomic64_t rx_alloc_err;
atomic64_t rx_large;
@@ -913,8 +976,8 @@ enum {
* Per TX queue stats
*/
struct tx_q_stats {
- unsigned long tx_packets;
- unsigned long tx_bytes;
+ u64 tx_packets;
+ u64 tx_bytes;
};
/**
@@ -963,9 +1026,9 @@ struct gfar_priv_tx_q {
* Per RX queue stats
*/
struct rx_q_stats {
- unsigned long rx_packets;
- unsigned long rx_bytes;
- unsigned long rx_dropped;
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 rx_dropped;
};
struct gfar_rx_buff {
@@ -1096,6 +1159,7 @@ struct gfar_private {
/* Network Statistics */
struct gfar_extra_stats extra_stats;
+ struct rmon_overflow rmon_overflow;
/* PHY stuff */
phy_interface_t interface;
diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c
index e0936510fa34..0acfafb73db1 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.c
+++ b/drivers/net/ethernet/freescale/ucc_geth.c
@@ -3590,10 +3590,9 @@ static int ucc_geth_probe(struct platform_device* ofdev)
if ((ucc_num < 0) || (ucc_num > 7))
return -ENODEV;
- ug_info = kmalloc(sizeof(*ug_info), GFP_KERNEL);
+ ug_info = kmemdup(&ugeth_primary_info, sizeof(*ug_info), GFP_KERNEL);
if (ug_info == NULL)
return -ENOMEM;
- memcpy(ug_info, &ugeth_primary_info, sizeof(*ug_info));
ug_info->uf_info.ucc_num = ucc_num;
diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c
index bfa2826c5545..0b68852379da 100644
--- a/drivers/net/ethernet/freescale/xgmac_mdio.c
+++ b/drivers/net/ethernet/freescale/xgmac_mdio.c
@@ -2,6 +2,7 @@
* QorIQ 10G MDIO Controller
*
* Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2021 NXP
*
* Authors: Andy Fleming <afleming@freescale.com>
* Timur Tabi <timur@freescale.com>
@@ -11,15 +12,17 @@
* kind, whether express or implied.
*/
-#include <linux/kernel.h>
-#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/acpi_mdio.h>
#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/phy.h>
+#include <linux/kernel.h>
#include <linux/mdio.h>
+#include <linux/module.h>
#include <linux/of_address.h>
-#include <linux/of_platform.h>
#include <linux/of_mdio.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/slab.h>
/* Number of microseconds to wait for a register to respond */
#define TIMEOUT 1000
@@ -243,10 +246,10 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
static int xgmac_mdio_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
- struct mii_bus *bus;
- struct resource *res;
+ struct fwnode_handle *fwnode;
struct mdio_fsl_priv *priv;
+ struct resource *res;
+ struct mii_bus *bus;
int ret;
/* In DPAA-1, MDIO is one of the many FMan sub-devices. The FMan
@@ -279,13 +282,22 @@ static int xgmac_mdio_probe(struct platform_device *pdev)
goto err_ioremap;
}
+ /* For both ACPI and DT cases, endianness of MDIO controller
+ * needs to be specified using "little-endian" property.
+ */
priv->is_little_endian = device_property_read_bool(&pdev->dev,
"little-endian");
priv->has_a011043 = device_property_read_bool(&pdev->dev,
"fsl,erratum-a011043");
- ret = of_mdiobus_register(bus, np);
+ fwnode = pdev->dev.fwnode;
+ if (is_of_node(fwnode))
+ ret = of_mdiobus_register(bus, to_of_node(fwnode));
+ else if (is_acpi_node(fwnode))
+ ret = acpi_mdiobus_register(bus, fwnode);
+ else
+ ret = -EINVAL;
if (ret) {
dev_err(&pdev->dev, "cannot register MDIO bus\n");
goto err_registration;
diff --git a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
index b0c0504950d8..62c0bed82ced 100644
--- a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
+++ b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
@@ -812,9 +812,9 @@ static netdev_tx_t fjn_start_xmit(struct sk_buff *skb,
if (length < ETH_ZLEN)
{
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
+ if (skb_padto(skb, ETH_ZLEN))
+ return NETDEV_TX_OK;
+ length = ETH_ZLEN;
}
netif_stop_queue(dev);
diff --git a/drivers/net/ethernet/google/Kconfig b/drivers/net/ethernet/google/Kconfig
index b8f04d052fda..8641a00f8e63 100644
--- a/drivers/net/ethernet/google/Kconfig
+++ b/drivers/net/ethernet/google/Kconfig
@@ -17,7 +17,7 @@ if NET_VENDOR_GOOGLE
config GVE
tristate "Google Virtual NIC (gVNIC) support"
- depends on PCI_MSI
+ depends on (PCI_MSI && (X86 || CPU_LITTLE_ENDIAN))
help
This driver supports Google Virtual NIC (gVNIC)"
diff --git a/drivers/net/ethernet/google/gve/Makefile b/drivers/net/ethernet/google/gve/Makefile
index 3354ce40eb97..b9a6be76531b 100644
--- a/drivers/net/ethernet/google/gve/Makefile
+++ b/drivers/net/ethernet/google/gve/Makefile
@@ -1,4 +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
+gve-objs := gve_main.o gve_tx.o gve_tx_dqo.o gve_rx.o gve_rx_dqo.o gve_ethtool.o gve_adminq.o gve_utils.o
diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h
index daf07c0f790b..1d3188e8e3b3 100644
--- a/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
* Google virtual Ethernet (gve) driver
*
- * Copyright (C) 2015-2019 Google, Inc.
+ * Copyright (C) 2015-2021 Google, Inc.
*/
#ifndef _GVE_H_
@@ -11,7 +11,9 @@
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/u64_stats_sync.h>
+
#include "gve_desc.h"
+#include "gve_desc_dqo.h"
#ifndef PCI_VENDOR_ID_GOOGLE
#define PCI_VENDOR_ID_GOOGLE 0x1ae0
@@ -40,6 +42,11 @@
#define GVE_DATA_SLOT_ADDR_PAGE_MASK (~(PAGE_SIZE - 1))
+/* PTYPEs are always 10 bits. */
+#define GVE_NUM_PTYPES 1024
+
+#define GVE_RX_BUFFER_SIZE_DQO 2048
+
/* 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 */
@@ -51,7 +58,8 @@ struct gve_rx_desc_queue {
struct gve_rx_slot_page_info {
struct page *page;
void *page_address;
- u8 page_offset; /* flipped to second half? */
+ u32 page_offset; /* offset to write to in page */
+ int pagecnt_bias; /* expected pagecnt if only the driver has a ref */
u8 can_flip;
};
@@ -76,17 +84,117 @@ struct gve_rx_data_queue {
struct gve_priv;
-/* An RX ring that contains a power-of-two sized desc and data ring. */
+/* RX buffer queue for posting buffers to HW.
+ * Each RX (completion) queue has a corresponding buffer queue.
+ */
+struct gve_rx_buf_queue_dqo {
+ struct gve_rx_desc_dqo *desc_ring;
+ dma_addr_t bus;
+ u32 head; /* Pointer to start cleaning buffers at. */
+ u32 tail; /* Last posted buffer index + 1 */
+ u32 mask; /* Mask for indices to the size of the ring */
+};
+
+/* RX completion queue to receive packets from HW. */
+struct gve_rx_compl_queue_dqo {
+ struct gve_rx_compl_desc_dqo *desc_ring;
+ dma_addr_t bus;
+
+ /* Number of slots which did not have a buffer posted yet. We should not
+ * post more buffers than the queue size to avoid HW overrunning the
+ * queue.
+ */
+ int num_free_slots;
+
+ /* HW uses a "generation bit" to notify SW of new descriptors. When a
+ * descriptor's generation bit is different from the current generation,
+ * that descriptor is ready to be consumed by SW.
+ */
+ u8 cur_gen_bit;
+
+ /* Pointer into desc_ring where the next completion descriptor will be
+ * received.
+ */
+ u32 head;
+ u32 mask; /* Mask for indices to the size of the ring */
+};
+
+/* Stores state for tracking buffers posted to HW */
+struct gve_rx_buf_state_dqo {
+ /* The page posted to HW. */
+ struct gve_rx_slot_page_info page_info;
+
+ /* The DMA address corresponding to `page_info`. */
+ dma_addr_t addr;
+
+ /* Last offset into the page when it only had a single reference, at
+ * which point every other offset is free to be reused.
+ */
+ u32 last_single_ref_offset;
+
+ /* Linked list index to next element in the list, or -1 if none */
+ s16 next;
+};
+
+/* `head` and `tail` are indices into an array, or -1 if empty. */
+struct gve_index_list {
+ s16 head;
+ s16 tail;
+};
+
+/* Contains datapath state used to represent an RX queue. */
struct gve_rx_ring {
struct gve_priv *gve;
- struct gve_rx_desc_queue desc;
- struct gve_rx_data_queue data;
+ union {
+ /* GQI fields */
+ struct {
+ struct gve_rx_desc_queue desc;
+ struct gve_rx_data_queue data;
+
+ /* threshold for posting new buffs and descs */
+ u32 db_threshold;
+ };
+
+ /* DQO fields. */
+ struct {
+ struct gve_rx_buf_queue_dqo bufq;
+ struct gve_rx_compl_queue_dqo complq;
+
+ struct gve_rx_buf_state_dqo *buf_states;
+ u16 num_buf_states;
+
+ /* Linked list of gve_rx_buf_state_dqo. Index into
+ * buf_states, or -1 if empty.
+ */
+ s16 free_buf_states;
+
+ /* Linked list of gve_rx_buf_state_dqo. Indexes into
+ * buf_states, or -1 if empty.
+ *
+ * This list contains buf_states which are pointing to
+ * valid buffers.
+ *
+ * We use a FIFO here in order to increase the
+ * probability that buffers can be reused by increasing
+ * the time between usages.
+ */
+ struct gve_index_list recycled_buf_states;
+
+ /* Linked list of gve_rx_buf_state_dqo. Indexes into
+ * buf_states, or -1 if empty.
+ *
+ * This list contains buf_states which have buffers
+ * which cannot be reused yet.
+ */
+ struct gve_index_list used_buf_states;
+ } dqo;
+ };
+
u64 rbytes; /* free-running bytes received */
u64 rpackets; /* free-running packets received */
u32 cnt; /* free-running total number of completed packets */
u32 fill_cnt; /* free-running total number of descs and buffs posted */
u32 mask; /* masks the cnt and fill_cnt to the size of the ring */
- u32 db_threshold; /* threshold for posting new buffs and descs */
u64 rx_copybreak_pkt; /* free-running count of copybreak packets */
u64 rx_copied_pkt; /* free-running total number of copied packets */
u64 rx_skb_alloc_fail; /* free-running count of skb alloc fails */
@@ -97,6 +205,10 @@ struct gve_rx_ring {
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 */
+
+ /* head and tail of skb chain for the current packet or NULL if none */
+ struct sk_buff *skb_head;
+ struct sk_buff *skb_tail;
};
/* A TX desc ring entry */
@@ -137,23 +249,161 @@ struct gve_tx_fifo {
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 */
+/* TX descriptor for DQO format */
+union gve_tx_desc_dqo {
+ struct gve_tx_pkt_desc_dqo pkt;
+ struct gve_tx_tso_context_desc_dqo tso_ctx;
+ struct gve_tx_general_context_desc_dqo general_ctx;
+};
+
+enum gve_packet_state {
+ /* Packet is in free list, available to be allocated.
+ * This should always be zero since state is not explicitly initialized.
+ */
+ GVE_PACKET_STATE_UNALLOCATED,
+ /* Packet is expecting a regular data completion or miss completion */
+ GVE_PACKET_STATE_PENDING_DATA_COMPL,
+ /* Packet has received a miss completion and is expecting a
+ * re-injection completion.
+ */
+ GVE_PACKET_STATE_PENDING_REINJECT_COMPL,
+ /* No valid completion received within the specified timeout. */
+ GVE_PACKET_STATE_TIMED_OUT_COMPL,
+};
+
+struct gve_tx_pending_packet_dqo {
+ struct sk_buff *skb; /* skb for this packet */
+
+ /* 0th element corresponds to the linear portion of `skb`, should be
+ * unmapped with `dma_unmap_single`.
+ *
+ * All others correspond to `skb`'s frags and should be unmapped with
+ * `dma_unmap_page`.
+ */
+ struct gve_tx_dma_buf bufs[MAX_SKB_FRAGS + 1];
+ u16 num_bufs;
+
+ /* Linked list index to next element in the list, or -1 if none */
+ s16 next;
+
+ /* Linked list index to prev element in the list, or -1 if none.
+ * Used for tracking either outstanding miss completions or prematurely
+ * freed packets.
+ */
+ s16 prev;
+
+ /* Identifies the current state of the packet as defined in
+ * `enum gve_packet_state`.
+ */
+ u8 state;
+
+ /* If packet is an outstanding miss completion, then the packet is
+ * freed if the corresponding re-injection completion is not received
+ * before kernel jiffies exceeds timeout_jiffies.
+ */
+ unsigned long timeout_jiffies;
+};
+
+/* Contains datapath state used to represent a TX queue. */
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 */
+ union {
+ /* GQI fields */
+ struct {
+ struct gve_tx_fifo tx_fifo;
+ u32 req; /* driver tracked head pointer */
+ u32 done; /* driver tracked tail pointer */
+ };
+
+ /* DQO fields. */
+ struct {
+ /* Linked list of gve_tx_pending_packet_dqo. Index into
+ * pending_packets, or -1 if empty.
+ *
+ * This is a consumer list owned by the TX path. When it
+ * runs out, the producer list is stolen from the
+ * completion handling path
+ * (dqo_compl.free_pending_packets).
+ */
+ s16 free_pending_packets;
+
+ /* Cached value of `dqo_compl.hw_tx_head` */
+ u32 head;
+ u32 tail; /* Last posted buffer index + 1 */
+
+ /* Index of the last descriptor with "report event" bit
+ * set.
+ */
+ u32 last_re_idx;
+ } dqo_tx;
+ };
/* Cacheline 1 -- Accessed & dirtied during gve_clean_tx_done */
- __be32 last_nic_done ____cacheline_aligned; /* NIC tail pointer */
+ union {
+ /* GQI fields */
+ struct {
+ /* NIC tail pointer */
+ __be32 last_nic_done;
+ };
+
+ /* DQO fields. */
+ struct {
+ u32 head; /* Last read on compl_desc */
+
+ /* Tracks the current gen bit of compl_q */
+ u8 cur_gen_bit;
+
+ /* Linked list of gve_tx_pending_packet_dqo. Index into
+ * pending_packets, or -1 if empty.
+ *
+ * This is the producer list, owned by the completion
+ * handling path. When the consumer list
+ * (dqo_tx.free_pending_packets) is runs out, this list
+ * will be stolen.
+ */
+ atomic_t free_pending_packets;
+
+ /* Last TX ring index fetched by HW */
+ atomic_t hw_tx_head;
+
+ /* List to track pending packets which received a miss
+ * completion but not a corresponding reinjection.
+ */
+ struct gve_index_list miss_completions;
+
+ /* List to track pending packets that were completed
+ * before receiving a valid completion because they
+ * reached a specified timeout.
+ */
+ struct gve_index_list timed_out_completions;
+ } dqo_compl;
+ } ____cacheline_aligned;
u64 pkt_done; /* free-running - total packets completed */
u64 bytes_done; /* free-running - total bytes completed */
u64 dropped_pkt; /* free-running - total packets dropped */
u64 dma_mapping_error; /* count of dma mapping errors */
/* Cacheline 2 -- Read-mostly fields */
- union gve_tx_desc *desc ____cacheline_aligned;
- struct gve_tx_buffer_state *info; /* Maps 1:1 to a desc */
+ union {
+ /* GQI fields */
+ struct {
+ union gve_tx_desc *desc;
+
+ /* Maps 1:1 to a desc */
+ struct gve_tx_buffer_state *info;
+ };
+
+ /* DQO fields. */
+ struct {
+ union gve_tx_desc_dqo *tx_ring;
+ struct gve_tx_compl_desc *compl_ring;
+
+ struct gve_tx_pending_packet_dqo *pending_packets;
+ s16 num_pending_packets;
+
+ u32 complq_mask; /* complq size is complq_mask + 1 */
+ } dqo;
+ } ____cacheline_aligned;
struct netdev_queue *netdev_txq;
struct gve_queue_resources *q_resources; /* head and tail pointer idx */
struct device *dev;
@@ -167,6 +417,7 @@ struct gve_tx_ring {
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 */
+ dma_addr_t complq_bus_dqo; /* dma address of the dqo.compl_ring */
struct u64_stats_sync statss; /* sync stats for 32bit archs */
} ____cacheline_aligned;
@@ -194,6 +445,31 @@ struct gve_qpl_config {
unsigned long *qpl_id_map; /* bitmap of used qpl ids */
};
+struct gve_options_dqo_rda {
+ u16 tx_comp_ring_entries; /* number of tx_comp descriptors */
+ u16 rx_buff_ring_entries; /* number of rx_buff descriptors */
+};
+
+struct gve_ptype {
+ u8 l3_type; /* `gve_l3_type` in gve_adminq.h */
+ u8 l4_type; /* `gve_l4_type` in gve_adminq.h */
+};
+
+struct gve_ptype_lut {
+ struct gve_ptype ptypes[GVE_NUM_PTYPES];
+};
+
+/* GVE_QUEUE_FORMAT_UNSPECIFIED must be zero since 0 is the default value
+ * when the entire configure_device_resources command is zeroed out and the
+ * queue_format is not specified.
+ */
+enum gve_queue_format {
+ GVE_QUEUE_FORMAT_UNSPECIFIED = 0x0,
+ GVE_GQI_RDA_FORMAT = 0x1,
+ GVE_GQI_QPL_FORMAT = 0x2,
+ GVE_DQO_RDA_FORMAT = 0x3,
+};
+
struct gve_priv {
struct net_device *dev;
struct gve_tx_ring *tx; /* array of tx_cfg.num_queues */
@@ -216,7 +492,6 @@ struct gve_priv {
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 */
- u8 raw_addressing; /* 1 if this dev supports raw addressing, 0 otherwise */
struct gve_queue_config tx_cfg;
struct gve_queue_config rx_cfg;
@@ -251,6 +526,7 @@ struct gve_priv {
u32 adminq_set_driver_parameter_cnt;
u32 adminq_report_stats_cnt;
u32 adminq_report_link_speed_cnt;
+ u32 adminq_get_ptype_map_cnt;
/* Global stats */
u32 interface_up_cnt; /* count of times interface turned up since last reset */
@@ -275,6 +551,14 @@ struct gve_priv {
/* Gvnic device link speed from hypervisor. */
u64 link_speed;
+
+ struct gve_options_dqo_rda options_dqo_rda;
+ struct gve_ptype_lut *ptype_lut_dqo;
+
+ /* Must be a power of two. */
+ int data_buffer_size_dqo;
+
+ enum gve_queue_format queue_format;
};
enum gve_service_task_flags_bit {
@@ -454,14 +738,20 @@ static inline u32 gve_rx_idx_to_ntfy(struct gve_priv *priv, u32 queue_idx)
*/
static inline u32 gve_num_tx_qpls(struct gve_priv *priv)
{
- return priv->raw_addressing ? 0 : priv->tx_cfg.num_queues;
+ if (priv->queue_format != GVE_GQI_QPL_FORMAT)
+ return 0;
+
+ 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->raw_addressing ? 0 : priv->rx_cfg.num_queues;
+ if (priv->queue_format != GVE_GQI_QPL_FORMAT)
+ return 0;
+
+ return priv->rx_cfg.num_queues;
}
/* Returns a pointer to the next available tx qpl in the list of qpls
@@ -515,6 +805,12 @@ static inline enum dma_data_direction gve_qpl_dma_dir(struct gve_priv *priv,
return DMA_FROM_DEVICE;
}
+static inline bool gve_is_gqi(struct gve_priv *priv)
+{
+ return priv->queue_format == GVE_GQI_RDA_FORMAT ||
+ priv->queue_format == GVE_GQI_QPL_FORMAT;
+}
+
/* buffers */
int gve_alloc_page(struct gve_priv *priv, struct device *dev,
struct page **page, dma_addr_t *dma,
@@ -525,14 +821,14 @@ void gve_free_page(struct device *dev, struct page *page, dma_addr_t dma,
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);
+void gve_tx_free_rings_gqi(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);
+void gve_rx_free_rings_gqi(struct gve_priv *priv);
bool gve_clean_rx_done(struct gve_rx_ring *rx, int budget,
netdev_features_t feat);
/* Reset */
diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c
index 53864f200599..5bb56b454541 100644
--- a/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Google virtual Ethernet (gve) driver
*
- * Copyright (C) 2015-2019 Google, Inc.
+ * Copyright (C) 2015-2021 Google, Inc.
*/
#include <linux/etherdevice.h>
@@ -18,6 +18,8 @@
"Expected: length=%d, feature_mask=%x.\n" \
"Actual: length=%d, feature_mask=%x.\n"
+#define GVE_DEVICE_OPTION_TOO_BIG_FMT "Length of %s option larger than expected. Possible older version of guest driver.\n"
+
static
struct gve_device_option *gve_get_next_option(struct gve_device_descriptor *descriptor,
struct gve_device_option *option)
@@ -33,28 +35,81 @@ struct gve_device_option *gve_get_next_option(struct gve_device_descriptor *desc
static
void gve_parse_device_option(struct gve_priv *priv,
struct gve_device_descriptor *device_descriptor,
- struct gve_device_option *option)
+ struct gve_device_option *option,
+ struct gve_device_option_gqi_rda **dev_op_gqi_rda,
+ struct gve_device_option_gqi_qpl **dev_op_gqi_qpl,
+ struct gve_device_option_dqo_rda **dev_op_dqo_rda)
{
+ u32 req_feat_mask = be32_to_cpu(option->required_features_mask);
u16 option_length = be16_to_cpu(option->option_length);
u16 option_id = be16_to_cpu(option->option_id);
+ /* If the length or feature mask doesn't match, continue without
+ * enabling the feature.
+ */
switch (option_id) {
- case GVE_DEV_OPT_ID_RAW_ADDRESSING:
- /* If the length or feature mask doesn't match,
- * continue without enabling the feature.
- */
- if (option_length != GVE_DEV_OPT_LEN_RAW_ADDRESSING ||
- option->feat_mask != cpu_to_be32(GVE_DEV_OPT_FEAT_MASK_RAW_ADDRESSING)) {
- dev_warn(&priv->pdev->dev, GVE_DEVICE_OPTION_ERROR_FMT, "Raw Addressing",
- GVE_DEV_OPT_LEN_RAW_ADDRESSING,
- cpu_to_be32(GVE_DEV_OPT_FEAT_MASK_RAW_ADDRESSING),
- option_length, option->feat_mask);
- priv->raw_addressing = 0;
- } else {
- dev_info(&priv->pdev->dev,
- "Raw addressing device option enabled.\n");
- priv->raw_addressing = 1;
+ case GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING:
+ if (option_length != GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING ||
+ req_feat_mask != GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING) {
+ dev_warn(&priv->pdev->dev, GVE_DEVICE_OPTION_ERROR_FMT,
+ "Raw Addressing",
+ GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING,
+ GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING,
+ option_length, req_feat_mask);
+ break;
+ }
+
+ dev_info(&priv->pdev->dev,
+ "Gqi raw addressing device option enabled.\n");
+ priv->queue_format = GVE_GQI_RDA_FORMAT;
+ break;
+ case GVE_DEV_OPT_ID_GQI_RDA:
+ if (option_length < sizeof(**dev_op_gqi_rda) ||
+ req_feat_mask != GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA) {
+ dev_warn(&priv->pdev->dev, GVE_DEVICE_OPTION_ERROR_FMT,
+ "GQI RDA", (int)sizeof(**dev_op_gqi_rda),
+ GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA,
+ option_length, req_feat_mask);
+ break;
+ }
+
+ if (option_length > sizeof(**dev_op_gqi_rda)) {
+ dev_warn(&priv->pdev->dev,
+ GVE_DEVICE_OPTION_TOO_BIG_FMT, "GQI RDA");
+ }
+ *dev_op_gqi_rda = (void *)(option + 1);
+ break;
+ case GVE_DEV_OPT_ID_GQI_QPL:
+ if (option_length < sizeof(**dev_op_gqi_qpl) ||
+ req_feat_mask != GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL) {
+ dev_warn(&priv->pdev->dev, GVE_DEVICE_OPTION_ERROR_FMT,
+ "GQI QPL", (int)sizeof(**dev_op_gqi_qpl),
+ GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL,
+ option_length, req_feat_mask);
+ break;
+ }
+
+ if (option_length > sizeof(**dev_op_gqi_qpl)) {
+ dev_warn(&priv->pdev->dev,
+ GVE_DEVICE_OPTION_TOO_BIG_FMT, "GQI QPL");
+ }
+ *dev_op_gqi_qpl = (void *)(option + 1);
+ break;
+ case GVE_DEV_OPT_ID_DQO_RDA:
+ if (option_length < sizeof(**dev_op_dqo_rda) ||
+ req_feat_mask != GVE_DEV_OPT_REQ_FEAT_MASK_DQO_RDA) {
+ dev_warn(&priv->pdev->dev, GVE_DEVICE_OPTION_ERROR_FMT,
+ "DQO RDA", (int)sizeof(**dev_op_dqo_rda),
+ GVE_DEV_OPT_REQ_FEAT_MASK_DQO_RDA,
+ option_length, req_feat_mask);
+ break;
+ }
+
+ if (option_length > sizeof(**dev_op_dqo_rda)) {
+ dev_warn(&priv->pdev->dev,
+ GVE_DEVICE_OPTION_TOO_BIG_FMT, "DQO RDA");
}
+ *dev_op_dqo_rda = (void *)(option + 1);
break;
default:
/* If we don't recognize the option just continue
@@ -65,6 +120,39 @@ void gve_parse_device_option(struct gve_priv *priv,
}
}
+/* Process all device options for a given describe device call. */
+static int
+gve_process_device_options(struct gve_priv *priv,
+ struct gve_device_descriptor *descriptor,
+ struct gve_device_option_gqi_rda **dev_op_gqi_rda,
+ struct gve_device_option_gqi_qpl **dev_op_gqi_qpl,
+ struct gve_device_option_dqo_rda **dev_op_dqo_rda)
+{
+ const int num_options = be16_to_cpu(descriptor->num_device_options);
+ struct gve_device_option *dev_opt;
+ int i;
+
+ /* The options struct directly follows the device descriptor. */
+ dev_opt = (void *)(descriptor + 1);
+ for (i = 0; i < num_options; i++) {
+ struct gve_device_option *next_opt;
+
+ next_opt = gve_get_next_option(descriptor, dev_opt);
+ if (!next_opt) {
+ dev_err(&priv->dev->dev,
+ "options exceed device_descriptor's total length.\n");
+ return -EINVAL;
+ }
+
+ gve_parse_device_option(priv, descriptor, dev_opt,
+ dev_op_gqi_rda, dev_op_gqi_qpl,
+ dev_op_dqo_rda);
+ dev_opt = next_opt;
+ }
+
+ return 0;
+}
+
int gve_adminq_alloc(struct device *dev, struct gve_priv *priv)
{
priv->adminq = dma_alloc_coherent(dev, PAGE_SIZE,
@@ -88,6 +176,7 @@ int gve_adminq_alloc(struct device *dev, struct gve_priv *priv)
priv->adminq_set_driver_parameter_cnt = 0;
priv->adminq_report_stats_cnt = 0;
priv->adminq_report_link_speed_cnt = 0;
+ priv->adminq_get_ptype_map_cnt = 0;
/* Setup Admin queue with the device */
iowrite32be(priv->adminq_bus_addr / PAGE_SIZE,
@@ -293,6 +382,9 @@ static int gve_adminq_issue_cmd(struct gve_priv *priv,
case GVE_ADMINQ_REPORT_LINK_SPEED:
priv->adminq_report_link_speed_cnt++;
break;
+ case GVE_ADMINQ_GET_PTYPE_MAP:
+ priv->adminq_get_ptype_map_cnt++;
+ break;
default:
dev_err(&priv->pdev->dev, "unknown AQ command opcode %d\n", opcode);
}
@@ -305,7 +397,8 @@ static int gve_adminq_issue_cmd(struct gve_priv *priv,
* The caller is also responsible for making sure there are no commands
* waiting to be executed.
*/
-static int gve_adminq_execute_cmd(struct gve_priv *priv, union gve_adminq_command *cmd_orig)
+static int gve_adminq_execute_cmd(struct gve_priv *priv,
+ union gve_adminq_command *cmd_orig)
{
u32 tail, head;
int err;
@@ -350,6 +443,7 @@ int gve_adminq_configure_device_resources(struct gve_priv *priv,
.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),
+ .queue_format = priv->queue_format,
};
return gve_adminq_execute_cmd(priv, &cmd);
@@ -369,27 +463,32 @@ static 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;
- u32 qpl_id;
- int err;
- qpl_id = priv->raw_addressing ? GVE_RAW_ADDRESSING_QPL_ID : tx->tx_fifo.qpl->id;
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(qpl_id),
.ntfy_id = cpu_to_be32(tx->ntfy_id),
};
- err = gve_adminq_issue_cmd(priv, &cmd);
- if (err)
- return err;
+ if (gve_is_gqi(priv)) {
+ u32 qpl_id = priv->queue_format == GVE_GQI_RDA_FORMAT ?
+ GVE_RAW_ADDRESSING_QPL_ID : tx->tx_fifo.qpl->id;
+
+ cmd.create_tx_queue.queue_page_list_id = cpu_to_be32(qpl_id);
+ } else {
+ cmd.create_tx_queue.tx_ring_size =
+ cpu_to_be16(priv->tx_desc_cnt);
+ cmd.create_tx_queue.tx_comp_ring_addr =
+ cpu_to_be64(tx->complq_bus_dqo);
+ cmd.create_tx_queue.tx_comp_ring_size =
+ cpu_to_be16(priv->options_dqo_rda.tx_comp_ring_entries);
+ }
- return 0;
+ return gve_adminq_issue_cmd(priv, &cmd);
}
int gve_adminq_create_tx_queues(struct gve_priv *priv, u32 num_queues)
@@ -410,28 +509,41 @@ static 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;
- u32 qpl_id;
- int err;
- qpl_id = priv->raw_addressing ? GVE_RAW_ADDRESSING_QPL_ID : rx->data.qpl->id;
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(qpl_id),
};
- err = gve_adminq_issue_cmd(priv, &cmd);
- if (err)
- return err;
+ if (gve_is_gqi(priv)) {
+ u32 qpl_id = priv->queue_format == GVE_GQI_RDA_FORMAT ?
+ GVE_RAW_ADDRESSING_QPL_ID : rx->data.qpl->id;
+
+ cmd.create_rx_queue.rx_desc_ring_addr =
+ cpu_to_be64(rx->desc.bus),
+ cmd.create_rx_queue.rx_data_ring_addr =
+ cpu_to_be64(rx->data.data_bus),
+ cmd.create_rx_queue.index = cpu_to_be32(queue_index);
+ cmd.create_rx_queue.queue_page_list_id = cpu_to_be32(qpl_id);
+ } else {
+ cmd.create_rx_queue.rx_ring_size =
+ cpu_to_be16(priv->rx_desc_cnt);
+ cmd.create_rx_queue.rx_desc_ring_addr =
+ cpu_to_be64(rx->dqo.complq.bus);
+ cmd.create_rx_queue.rx_data_ring_addr =
+ cpu_to_be64(rx->dqo.bufq.bus);
+ cmd.create_rx_queue.packet_buffer_size =
+ cpu_to_be16(priv->data_buffer_size_dqo);
+ cmd.create_rx_queue.rx_buff_ring_size =
+ cpu_to_be16(priv->options_dqo_rda.rx_buff_ring_entries);
+ cmd.create_rx_queue.enable_rsc =
+ !!(priv->dev->features & NETIF_F_LRO);
+ }
- return 0;
+ return gve_adminq_issue_cmd(priv, &cmd);
}
int gve_adminq_create_rx_queues(struct gve_priv *priv, u32 num_queues)
@@ -512,17 +624,51 @@ int gve_adminq_destroy_rx_queues(struct gve_priv *priv, u32 num_queues)
return gve_adminq_kick_and_wait(priv);
}
+static int gve_set_desc_cnt(struct gve_priv *priv,
+ struct gve_device_descriptor *descriptor)
+{
+ priv->tx_desc_cnt = be16_to_cpu(descriptor->tx_queue_entries);
+ if (priv->tx_desc_cnt * sizeof(priv->tx->desc[0]) < PAGE_SIZE) {
+ dev_err(&priv->pdev->dev, "Tx desc count %d too low\n",
+ priv->tx_desc_cnt);
+ return -EINVAL;
+ }
+ priv->rx_desc_cnt = be16_to_cpu(descriptor->rx_queue_entries);
+ if (priv->rx_desc_cnt * sizeof(priv->rx->desc.desc_ring[0])
+ < PAGE_SIZE) {
+ dev_err(&priv->pdev->dev, "Rx desc count %d too low\n",
+ priv->rx_desc_cnt);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int
+gve_set_desc_cnt_dqo(struct gve_priv *priv,
+ const struct gve_device_descriptor *descriptor,
+ const struct gve_device_option_dqo_rda *dev_op_dqo_rda)
+{
+ priv->tx_desc_cnt = be16_to_cpu(descriptor->tx_queue_entries);
+ priv->options_dqo_rda.tx_comp_ring_entries =
+ be16_to_cpu(dev_op_dqo_rda->tx_comp_ring_entries);
+ priv->rx_desc_cnt = be16_to_cpu(descriptor->rx_queue_entries);
+ priv->options_dqo_rda.rx_buff_ring_entries =
+ be16_to_cpu(dev_op_dqo_rda->rx_buff_ring_entries);
+
+ return 0;
+}
+
int gve_adminq_describe_device(struct gve_priv *priv)
{
+ struct gve_device_option_gqi_rda *dev_op_gqi_rda = NULL;
+ struct gve_device_option_gqi_qpl *dev_op_gqi_qpl = NULL;
+ struct gve_device_option_dqo_rda *dev_op_dqo_rda = NULL;
struct gve_device_descriptor *descriptor;
- struct gve_device_option *dev_opt;
union gve_adminq_command cmd;
dma_addr_t descriptor_bus;
- u16 num_options;
int err = 0;
u8 *mac;
u16 mtu;
- int i;
memset(&cmd, 0, sizeof(cmd));
descriptor = dma_alloc_coherent(&priv->pdev->dev, PAGE_SIZE,
@@ -540,21 +686,41 @@ int gve_adminq_describe_device(struct gve_priv *priv)
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) {
- dev_err(&priv->pdev->dev, "Tx desc count %d too low\n", priv->tx_desc_cnt);
- err = -EINVAL;
+ err = gve_process_device_options(priv, descriptor, &dev_op_gqi_rda,
+ &dev_op_gqi_qpl, &dev_op_dqo_rda);
+ if (err)
goto free_device_descriptor;
+
+ /* If the GQI_RAW_ADDRESSING option is not enabled and the queue format
+ * is not set to GqiRda, choose the queue format in a priority order:
+ * DqoRda, GqiRda, GqiQpl. Use GqiQpl as default.
+ */
+ if (priv->queue_format == GVE_GQI_RDA_FORMAT) {
+ dev_info(&priv->pdev->dev,
+ "Driver is running with GQI RDA queue format.\n");
+ } else if (dev_op_dqo_rda) {
+ priv->queue_format = GVE_DQO_RDA_FORMAT;
+ dev_info(&priv->pdev->dev,
+ "Driver is running with DQO RDA queue format.\n");
+ } else if (dev_op_gqi_rda) {
+ priv->queue_format = GVE_GQI_RDA_FORMAT;
+ dev_info(&priv->pdev->dev,
+ "Driver is running with GQI RDA queue format.\n");
+ } else {
+ priv->queue_format = GVE_GQI_QPL_FORMAT;
+ dev_info(&priv->pdev->dev,
+ "Driver is running with GQI QPL queue format.\n");
}
- 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) {
- dev_err(&priv->pdev->dev, "Rx desc count %d too low\n", priv->rx_desc_cnt);
- err = -EINVAL;
- goto free_device_descriptor;
+ if (gve_is_gqi(priv)) {
+ err = gve_set_desc_cnt(priv, descriptor);
+ } else {
+ /* DQO supports LRO. */
+ priv->dev->hw_features |= NETIF_F_LRO;
+ err = gve_set_desc_cnt_dqo(priv, descriptor, dev_op_dqo_rda);
}
+ if (err)
+ goto free_device_descriptor;
+
priv->max_registered_pages =
be64_to_cpu(descriptor->max_registered_pages);
mtu = be16_to_cpu(descriptor->mtu);
@@ -570,32 +736,16 @@ int gve_adminq_describe_device(struct gve_priv *priv)
dev_info(&priv->pdev->dev, "MAC addr: %pM\n", mac);
priv->tx_pages_per_qpl = be16_to_cpu(descriptor->tx_pages_per_qpl);
priv->rx_data_slot_cnt = be16_to_cpu(descriptor->rx_pages_per_qpl);
- if (priv->rx_data_slot_cnt < priv->rx_desc_cnt) {
+
+ if (gve_is_gqi(priv) && priv->rx_data_slot_cnt < priv->rx_desc_cnt) {
dev_err(&priv->pdev->dev, "rx_data_slot_cnt cannot be smaller than rx_desc_cnt, setting rx_desc_cnt down to %d.\n",
priv->rx_data_slot_cnt);
priv->rx_desc_cnt = priv->rx_data_slot_cnt;
}
priv->default_num_queues = be16_to_cpu(descriptor->default_num_queues);
- dev_opt = (void *)(descriptor + 1);
-
- num_options = be16_to_cpu(descriptor->num_device_options);
- for (i = 0; i < num_options; i++) {
- struct gve_device_option *next_opt;
-
- next_opt = gve_get_next_option(descriptor, dev_opt);
- if (!next_opt) {
- dev_err(&priv->dev->dev,
- "options exceed device_descriptor's total length.\n");
- err = -EINVAL;
- goto free_device_descriptor;
- }
-
- gve_parse_device_option(priv, descriptor, dev_opt);
- dev_opt = next_opt;
- }
free_device_descriptor:
- dma_free_coherent(&priv->pdev->dev, sizeof(*descriptor), descriptor,
+ dma_free_coherent(&priv->pdev->dev, PAGE_SIZE, descriptor,
descriptor_bus);
return err;
}
@@ -701,3 +851,41 @@ int gve_adminq_report_link_speed(struct gve_priv *priv)
link_speed_region_bus);
return err;
}
+
+int gve_adminq_get_ptype_map_dqo(struct gve_priv *priv,
+ struct gve_ptype_lut *ptype_lut)
+{
+ struct gve_ptype_map *ptype_map;
+ union gve_adminq_command cmd;
+ dma_addr_t ptype_map_bus;
+ int err = 0;
+ int i;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ptype_map = dma_alloc_coherent(&priv->pdev->dev, sizeof(*ptype_map),
+ &ptype_map_bus, GFP_KERNEL);
+ if (!ptype_map)
+ return -ENOMEM;
+
+ cmd.opcode = cpu_to_be32(GVE_ADMINQ_GET_PTYPE_MAP);
+ cmd.get_ptype_map = (struct gve_adminq_get_ptype_map) {
+ .ptype_map_len = cpu_to_be64(sizeof(*ptype_map)),
+ .ptype_map_addr = cpu_to_be64(ptype_map_bus),
+ };
+
+ err = gve_adminq_execute_cmd(priv, &cmd);
+ if (err)
+ goto err;
+
+ /* Populate ptype_lut. */
+ for (i = 0; i < GVE_NUM_PTYPES; i++) {
+ ptype_lut->ptypes[i].l3_type =
+ ptype_map->ptypes[i].l3_type;
+ ptype_lut->ptypes[i].l4_type =
+ ptype_map->ptypes[i].l4_type;
+ }
+err:
+ dma_free_coherent(&priv->pdev->dev, sizeof(*ptype_map), ptype_map,
+ ptype_map_bus);
+ return err;
+}
diff --git a/drivers/net/ethernet/google/gve/gve_adminq.h b/drivers/net/ethernet/google/gve/gve_adminq.h
index d320c2ffd87c..47c3d8f313fc 100644
--- a/drivers/net/ethernet/google/gve/gve_adminq.h
+++ b/drivers/net/ethernet/google/gve/gve_adminq.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
* Google virtual Ethernet (gve) driver
*
- * Copyright (C) 2015-2019 Google, Inc.
+ * Copyright (C) 2015-2021 Google, Inc.
*/
#ifndef _GVE_ADMINQ_H
@@ -22,7 +22,8 @@ enum gve_adminq_opcodes {
GVE_ADMINQ_DECONFIGURE_DEVICE_RESOURCES = 0x9,
GVE_ADMINQ_SET_DRIVER_PARAMETER = 0xB,
GVE_ADMINQ_REPORT_STATS = 0xC,
- GVE_ADMINQ_REPORT_LINK_SPEED = 0xD
+ GVE_ADMINQ_REPORT_LINK_SPEED = 0xD,
+ GVE_ADMINQ_GET_PTYPE_MAP = 0xE,
};
/* Admin queue status codes */
@@ -82,14 +83,54 @@ static_assert(sizeof(struct gve_device_descriptor) == 40);
struct gve_device_option {
__be16 option_id;
__be16 option_length;
- __be32 feat_mask;
+ __be32 required_features_mask;
};
static_assert(sizeof(struct gve_device_option) == 8);
-#define GVE_DEV_OPT_ID_RAW_ADDRESSING 0x1
-#define GVE_DEV_OPT_LEN_RAW_ADDRESSING 0x0
-#define GVE_DEV_OPT_FEAT_MASK_RAW_ADDRESSING 0x0
+struct gve_device_option_gqi_rda {
+ __be32 supported_features_mask;
+};
+
+static_assert(sizeof(struct gve_device_option_gqi_rda) == 4);
+
+struct gve_device_option_gqi_qpl {
+ __be32 supported_features_mask;
+};
+
+static_assert(sizeof(struct gve_device_option_gqi_qpl) == 4);
+
+struct gve_device_option_dqo_rda {
+ __be32 supported_features_mask;
+ __be16 tx_comp_ring_entries;
+ __be16 rx_buff_ring_entries;
+};
+
+static_assert(sizeof(struct gve_device_option_dqo_rda) == 8);
+
+/* Terminology:
+ *
+ * RDA - Raw DMA Addressing - Buffers associated with SKBs are directly DMA
+ * mapped and read/updated by the device.
+ *
+ * QPL - Queue Page Lists - Driver uses bounce buffers which are DMA mapped with
+ * the device for read/write and data is copied from/to SKBs.
+ */
+enum gve_dev_opt_id {
+ GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING = 0x1,
+ GVE_DEV_OPT_ID_GQI_RDA = 0x2,
+ GVE_DEV_OPT_ID_GQI_QPL = 0x3,
+ GVE_DEV_OPT_ID_DQO_RDA = 0x4,
+};
+
+enum gve_dev_opt_req_feat_mask {
+ GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING = 0x0,
+ GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA = 0x0,
+ GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL = 0x0,
+ GVE_DEV_OPT_REQ_FEAT_MASK_DQO_RDA = 0x0,
+};
+
+#define GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING 0x0
struct gve_adminq_configure_device_resources {
__be64 counter_array;
@@ -98,9 +139,11 @@ struct gve_adminq_configure_device_resources {
__be32 num_irq_dbs;
__be32 irq_db_stride;
__be32 ntfy_blk_msix_base_idx;
+ u8 queue_format;
+ u8 padding[7];
};
-static_assert(sizeof(struct gve_adminq_configure_device_resources) == 32);
+static_assert(sizeof(struct gve_adminq_configure_device_resources) == 40);
struct gve_adminq_register_page_list {
__be32 page_list_id;
@@ -125,9 +168,13 @@ struct gve_adminq_create_tx_queue {
__be64 tx_ring_addr;
__be32 queue_page_list_id;
__be32 ntfy_id;
+ __be64 tx_comp_ring_addr;
+ __be16 tx_ring_size;
+ __be16 tx_comp_ring_size;
+ u8 padding[4];
};
-static_assert(sizeof(struct gve_adminq_create_tx_queue) == 32);
+static_assert(sizeof(struct gve_adminq_create_tx_queue) == 48);
struct gve_adminq_create_rx_queue {
__be32 queue_id;
@@ -138,10 +185,14 @@ struct gve_adminq_create_rx_queue {
__be64 rx_desc_ring_addr;
__be64 rx_data_ring_addr;
__be32 queue_page_list_id;
- u8 padding[4];
+ __be16 rx_ring_size;
+ __be16 packet_buffer_size;
+ __be16 rx_buff_ring_size;
+ u8 enable_rsc;
+ u8 padding[5];
};
-static_assert(sizeof(struct gve_adminq_create_rx_queue) == 48);
+static_assert(sizeof(struct gve_adminq_create_rx_queue) == 56);
/* Queue resources that are shared with the device */
struct gve_queue_resources {
@@ -226,6 +277,41 @@ enum gve_stat_names {
RX_DROPS_INVALID_CHECKSUM = 68,
};
+enum gve_l3_type {
+ /* Must be zero so zero initialized LUT is unknown. */
+ GVE_L3_TYPE_UNKNOWN = 0,
+ GVE_L3_TYPE_OTHER,
+ GVE_L3_TYPE_IPV4,
+ GVE_L3_TYPE_IPV6,
+};
+
+enum gve_l4_type {
+ /* Must be zero so zero initialized LUT is unknown. */
+ GVE_L4_TYPE_UNKNOWN = 0,
+ GVE_L4_TYPE_OTHER,
+ GVE_L4_TYPE_TCP,
+ GVE_L4_TYPE_UDP,
+ GVE_L4_TYPE_ICMP,
+ GVE_L4_TYPE_SCTP,
+};
+
+/* These are control path types for PTYPE which are the same as the data path
+ * types.
+ */
+struct gve_ptype_entry {
+ u8 l3_type;
+ u8 l4_type;
+};
+
+struct gve_ptype_map {
+ struct gve_ptype_entry ptypes[1 << 10]; /* PTYPES are always 10 bits. */
+};
+
+struct gve_adminq_get_ptype_map {
+ __be64 ptype_map_len;
+ __be64 ptype_map_addr;
+};
+
union gve_adminq_command {
struct {
__be32 opcode;
@@ -243,6 +329,7 @@ union gve_adminq_command {
struct gve_adminq_set_driver_parameter set_driver_param;
struct gve_adminq_report_stats report_stats;
struct gve_adminq_report_link_speed report_link_speed;
+ struct gve_adminq_get_ptype_map get_ptype_map;
};
};
u8 reserved[64];
@@ -271,4 +358,9 @@ int gve_adminq_set_mtu(struct gve_priv *priv, u64 mtu);
int gve_adminq_report_stats(struct gve_priv *priv, u64 stats_report_len,
dma_addr_t stats_report_addr, u64 interval);
int gve_adminq_report_link_speed(struct gve_priv *priv);
+
+struct gve_ptype_lut;
+int gve_adminq_get_ptype_map_dqo(struct gve_priv *priv,
+ struct gve_ptype_lut *ptype_lut);
+
#endif /* _GVE_ADMINQ_H */
diff --git a/drivers/net/ethernet/google/gve/gve_desc_dqo.h b/drivers/net/ethernet/google/gve/gve_desc_dqo.h
new file mode 100644
index 000000000000..e8fe9adef7f2
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve_desc_dqo.h
@@ -0,0 +1,256 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ * Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2021 Google, Inc.
+ */
+
+/* GVE DQO Descriptor formats */
+
+#ifndef _GVE_DESC_DQO_H_
+#define _GVE_DESC_DQO_H_
+
+#include <linux/build_bug.h>
+
+#define GVE_TX_MAX_HDR_SIZE_DQO 255
+#define GVE_TX_MIN_TSO_MSS_DQO 88
+
+#ifndef __LITTLE_ENDIAN_BITFIELD
+#error "Only little endian supported"
+#endif
+
+/* Basic TX descriptor (DTYPE 0x0C) */
+struct gve_tx_pkt_desc_dqo {
+ __le64 buf_addr;
+
+ /* Must be GVE_TX_PKT_DESC_DTYPE_DQO (0xc) */
+ u8 dtype: 5;
+
+ /* Denotes the last descriptor of a packet. */
+ u8 end_of_packet: 1;
+ u8 checksum_offload_enable: 1;
+
+ /* If set, will generate a descriptor completion for this descriptor. */
+ u8 report_event: 1;
+ u8 reserved0;
+ __le16 reserved1;
+
+ /* The TX completion associated with this packet will contain this tag.
+ */
+ __le16 compl_tag;
+ u16 buf_size: 14;
+ u16 reserved2: 2;
+} __packed;
+static_assert(sizeof(struct gve_tx_pkt_desc_dqo) == 16);
+
+#define GVE_TX_PKT_DESC_DTYPE_DQO 0xc
+#define GVE_TX_MAX_BUF_SIZE_DQO ((16 * 1024) - 1)
+
+/* Maximum number of data descriptors allowed per packet, or per-TSO segment. */
+#define GVE_TX_MAX_DATA_DESCS 10
+
+/* Min gap between tail and head to avoid cacheline overlap */
+#define GVE_TX_MIN_DESC_PREVENT_CACHE_OVERLAP 4
+
+/* "report_event" on TX packet descriptors may only be reported on the last
+ * descriptor of a TX packet, and they must be spaced apart with at least this
+ * value.
+ */
+#define GVE_TX_MIN_RE_INTERVAL 32
+
+struct gve_tx_context_cmd_dtype {
+ u8 dtype: 5;
+ u8 tso: 1;
+ u8 reserved1: 2;
+
+ u8 reserved2;
+};
+
+static_assert(sizeof(struct gve_tx_context_cmd_dtype) == 2);
+
+/* TX Native TSO Context DTYPE (0x05)
+ *
+ * "flex" fields allow the driver to send additional packet context to HW.
+ */
+struct gve_tx_tso_context_desc_dqo {
+ /* The L4 payload bytes that should be segmented. */
+ u32 tso_total_len: 24;
+ u32 flex10: 8;
+
+ /* Max segment size in TSO excluding headers. */
+ u16 mss: 14;
+ u16 reserved: 2;
+
+ u8 header_len; /* Header length to use for TSO offload */
+ u8 flex11;
+ struct gve_tx_context_cmd_dtype cmd_dtype;
+ u8 flex0;
+ u8 flex5;
+ u8 flex6;
+ u8 flex7;
+ u8 flex8;
+ u8 flex9;
+} __packed;
+static_assert(sizeof(struct gve_tx_tso_context_desc_dqo) == 16);
+
+#define GVE_TX_TSO_CTX_DESC_DTYPE_DQO 0x5
+
+/* General context descriptor for sending metadata. */
+struct gve_tx_general_context_desc_dqo {
+ u8 flex4;
+ u8 flex5;
+ u8 flex6;
+ u8 flex7;
+ u8 flex8;
+ u8 flex9;
+ u8 flex10;
+ u8 flex11;
+ struct gve_tx_context_cmd_dtype cmd_dtype;
+ u16 reserved;
+ u8 flex0;
+ u8 flex1;
+ u8 flex2;
+ u8 flex3;
+} __packed;
+static_assert(sizeof(struct gve_tx_general_context_desc_dqo) == 16);
+
+#define GVE_TX_GENERAL_CTX_DESC_DTYPE_DQO 0x4
+
+/* Logical structure of metadata which is packed into context descriptor flex
+ * fields.
+ */
+struct gve_tx_metadata_dqo {
+ union {
+ struct {
+ u8 version;
+
+ /* If `skb->l4_hash` is set, this value should be
+ * derived from `skb->hash`.
+ *
+ * A zero value means no l4_hash was associated with the
+ * skb.
+ */
+ u16 path_hash: 15;
+
+ /* Should be set to 1 if the flow associated with the
+ * skb had a rehash from the TCP stack.
+ */
+ u16 rehash_event: 1;
+ } __packed;
+ u8 bytes[12];
+ };
+} __packed;
+static_assert(sizeof(struct gve_tx_metadata_dqo) == 12);
+
+#define GVE_TX_METADATA_VERSION_DQO 0
+
+/* TX completion descriptor */
+struct gve_tx_compl_desc {
+ /* For types 0-4 this is the TX queue ID associated with this
+ * completion.
+ */
+ u16 id: 11;
+
+ /* See: GVE_COMPL_TYPE_DQO* */
+ u16 type: 3;
+ u16 reserved0: 1;
+
+ /* Flipped by HW to notify the descriptor is populated. */
+ u16 generation: 1;
+ union {
+ /* For descriptor completions, this is the last index fetched
+ * by HW + 1.
+ */
+ __le16 tx_head;
+
+ /* For packet completions, this is the completion tag set on the
+ * TX packet descriptors.
+ */
+ __le16 completion_tag;
+ };
+ __le32 reserved1;
+} __packed;
+static_assert(sizeof(struct gve_tx_compl_desc) == 8);
+
+#define GVE_COMPL_TYPE_DQO_PKT 0x2 /* Packet completion */
+#define GVE_COMPL_TYPE_DQO_DESC 0x4 /* Descriptor completion */
+#define GVE_COMPL_TYPE_DQO_MISS 0x1 /* Miss path completion */
+#define GVE_COMPL_TYPE_DQO_REINJECTION 0x3 /* Re-injection completion */
+
+/* Descriptor to post buffers to HW on buffer queue. */
+struct gve_rx_desc_dqo {
+ __le16 buf_id; /* ID returned in Rx completion descriptor */
+ __le16 reserved0;
+ __le32 reserved1;
+ __le64 buf_addr; /* DMA address of the buffer */
+ __le64 header_buf_addr;
+ __le64 reserved2;
+} __packed;
+static_assert(sizeof(struct gve_rx_desc_dqo) == 32);
+
+/* Descriptor for HW to notify SW of new packets received on RX queue. */
+struct gve_rx_compl_desc_dqo {
+ /* Must be 1 */
+ u8 rxdid: 4;
+ u8 reserved0: 4;
+
+ /* Packet originated from this system rather than the network. */
+ u8 loopback: 1;
+ /* Set when IPv6 packet contains a destination options header or routing
+ * header.
+ */
+ u8 ipv6_ex_add: 1;
+ /* Invalid packet was received. */
+ u8 rx_error: 1;
+ u8 reserved1: 5;
+
+ u16 packet_type: 10;
+ u16 ip_hdr_err: 1;
+ u16 udp_len_err: 1;
+ u16 raw_cs_invalid: 1;
+ u16 reserved2: 3;
+
+ u16 packet_len: 14;
+ /* Flipped by HW to notify the descriptor is populated. */
+ u16 generation: 1;
+ /* Should be zero. */
+ u16 buffer_queue_id: 1;
+
+ u16 header_len: 10;
+ u16 rsc: 1;
+ u16 split_header: 1;
+ u16 reserved3: 4;
+
+ u8 descriptor_done: 1;
+ u8 end_of_packet: 1;
+ u8 header_buffer_overflow: 1;
+ u8 l3_l4_processed: 1;
+ u8 csum_ip_err: 1;
+ u8 csum_l4_err: 1;
+ u8 csum_external_ip_err: 1;
+ u8 csum_external_udp_err: 1;
+
+ u8 status_error1;
+
+ __le16 reserved5;
+ __le16 buf_id; /* Buffer ID which was sent on the buffer queue. */
+
+ union {
+ /* Packet checksum. */
+ __le16 raw_cs;
+ /* Segment length for RSC packets. */
+ __le16 rsc_seg_len;
+ };
+ __le32 hash;
+ __le32 reserved6;
+ __le64 reserved7;
+} __packed;
+
+static_assert(sizeof(struct gve_rx_compl_desc_dqo) == 32);
+
+/* Ringing the doorbell too often can hurt performance.
+ *
+ * HW requires this value to be at least 8.
+ */
+#define GVE_RX_BUF_THRESH_DQO 32
+
+#endif /* _GVE_DESC_DQO_H_ */
diff --git a/drivers/net/ethernet/google/gve/gve_dqo.h b/drivers/net/ethernet/google/gve/gve_dqo.h
new file mode 100644
index 000000000000..836042364124
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve_dqo.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ * Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2021 Google, Inc.
+ */
+
+#ifndef _GVE_DQO_H_
+#define _GVE_DQO_H_
+
+#include "gve_adminq.h"
+
+#define GVE_ITR_ENABLE_BIT_DQO BIT(0)
+#define GVE_ITR_CLEAR_PBA_BIT_DQO BIT(1)
+#define GVE_ITR_NO_UPDATE_DQO (3 << 3)
+
+#define GVE_ITR_INTERVAL_DQO_SHIFT 5
+#define GVE_ITR_INTERVAL_DQO_MASK ((1 << 12) - 1)
+
+#define GVE_TX_IRQ_RATELIMIT_US_DQO 50
+#define GVE_RX_IRQ_RATELIMIT_US_DQO 20
+
+/* Timeout in seconds to wait for a reinjection completion after receiving
+ * its corresponding miss completion.
+ */
+#define GVE_REINJECT_COMPL_TIMEOUT 1
+
+/* Timeout in seconds to deallocate the completion tag for a packet that was
+ * prematurely freed for not receiving a valid completion. This should be large
+ * enough to rule out the possibility of receiving the corresponding valid
+ * completion after this interval.
+ */
+#define GVE_DEALLOCATE_COMPL_TIMEOUT 60
+
+netdev_tx_t gve_tx_dqo(struct sk_buff *skb, struct net_device *dev);
+bool gve_tx_poll_dqo(struct gve_notify_block *block, bool do_clean);
+int gve_rx_poll_dqo(struct gve_notify_block *block, int budget);
+int gve_tx_alloc_rings_dqo(struct gve_priv *priv);
+void gve_tx_free_rings_dqo(struct gve_priv *priv);
+int gve_rx_alloc_rings_dqo(struct gve_priv *priv);
+void gve_rx_free_rings_dqo(struct gve_priv *priv);
+int gve_clean_tx_done_dqo(struct gve_priv *priv, struct gve_tx_ring *tx,
+ struct napi_struct *napi);
+void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx);
+void gve_rx_write_doorbell_dqo(const struct gve_priv *priv, int queue_idx);
+
+static inline void
+gve_tx_put_doorbell_dqo(const struct gve_priv *priv,
+ const struct gve_queue_resources *q_resources, u32 val)
+{
+ u64 index;
+
+ index = be32_to_cpu(q_resources->db_index);
+ iowrite32(val, &priv->db_bar2[index]);
+}
+
+/* Builds register value to write to DQO IRQ doorbell to enable with specified
+ * ratelimit.
+ */
+static inline u32 gve_set_itr_ratelimit_dqo(u32 ratelimit_us)
+{
+ u32 result = GVE_ITR_ENABLE_BIT_DQO;
+
+ /* Interval has 2us granularity. */
+ ratelimit_us >>= 1;
+
+ ratelimit_us &= GVE_ITR_INTERVAL_DQO_MASK;
+ result |= (ratelimit_us << GVE_ITR_INTERVAL_DQO_SHIFT);
+
+ return result;
+}
+
+static inline void
+gve_write_irq_doorbell_dqo(const struct gve_priv *priv,
+ const struct gve_notify_block *block, u32 val)
+{
+ u32 index = be32_to_cpu(block->irq_db_index);
+
+ iowrite32(val, &priv->db_bar2[index]);
+}
+
+#endif /* _GVE_DQO_H_ */
diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c
index 5fb05cf36b49..716e6240305d 100644
--- a/drivers/net/ethernet/google/gve/gve_ethtool.c
+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Google virtual Ethernet (gve) driver
*
- * Copyright (C) 2015-2019 Google, Inc.
+ * Copyright (C) 2015-2021 Google, Inc.
*/
#include <linux/ethtool.h>
@@ -311,8 +311,16 @@ gve_get_ethtool_stats(struct net_device *netdev,
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;
+ if (gve_is_gqi(priv)) {
+ data[i++] = tx->req;
+ data[i++] = tx->done;
+ } else {
+ /* DQO doesn't currently support
+ * posted/completed descriptor counts;
+ */
+ data[i++] = 0;
+ data[i++] = 0;
+ }
do {
start =
u64_stats_fetch_begin(&priv->tx[ring].statss);
@@ -453,11 +461,16 @@ static int gve_set_tunable(struct net_device *netdev,
switch (etuna->id) {
case ETHTOOL_RX_COPYBREAK:
+ {
+ u32 max_copybreak = gve_is_gqi(priv) ?
+ (PAGE_SIZE / 2) : priv->data_buffer_size_dqo;
+
len = *(u32 *)value;
- if (len > PAGE_SIZE / 2)
+ if (len > max_copybreak)
return -EINVAL;
priv->rx_copybreak = len;
return 0;
+ }
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
index bbc423e93122..099a2bc5ae67 100644
--- a/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Google virtual Ethernet (gve) driver
*
- * Copyright (C) 2015-2019 Google, Inc.
+ * Copyright (C) 2015-2021 Google, Inc.
*/
#include <linux/cpumask.h>
@@ -14,6 +14,7 @@
#include <linux/workqueue.h>
#include <net/sch_generic.h>
#include "gve.h"
+#include "gve_dqo.h"
#include "gve_adminq.h"
#include "gve_register.h"
@@ -26,6 +27,16 @@
const char gve_version_str[] = GVE_VERSION;
static const char gve_version_prefix[] = GVE_VERSION_PREFIX;
+static netdev_tx_t gve_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct gve_priv *priv = netdev_priv(dev);
+
+ if (gve_is_gqi(priv))
+ return gve_tx(skb, dev);
+ else
+ return gve_tx_dqo(skb, dev);
+}
+
static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s)
{
struct gve_priv *priv = netdev_priv(dev);
@@ -155,6 +166,15 @@ static irqreturn_t gve_intr(int irq, void *arg)
return IRQ_HANDLED;
}
+static irqreturn_t gve_intr_dqo(int irq, void *arg)
+{
+ struct gve_notify_block *block = arg;
+
+ /* Interrupts are automatically masked */
+ napi_schedule_irqoff(&block->napi);
+ return IRQ_HANDLED;
+}
+
static int gve_napi_poll(struct napi_struct *napi, int budget)
{
struct gve_notify_block *block;
@@ -191,6 +211,54 @@ static int gve_napi_poll(struct napi_struct *napi, int budget)
return 0;
}
+static int gve_napi_poll_dqo(struct napi_struct *napi, int budget)
+{
+ struct gve_notify_block *block =
+ container_of(napi, struct gve_notify_block, napi);
+ struct gve_priv *priv = block->priv;
+ bool reschedule = false;
+ int work_done = 0;
+
+ /* Clear PCI MSI-X Pending Bit Array (PBA)
+ *
+ * This bit is set if an interrupt event occurs while the vector is
+ * masked. If this bit is set and we reenable the interrupt, it will
+ * fire again. Since we're just about to poll the queue state, we don't
+ * need it to fire again.
+ *
+ * Under high softirq load, it's possible that the interrupt condition
+ * is triggered twice before we got the chance to process it.
+ */
+ gve_write_irq_doorbell_dqo(priv, block,
+ GVE_ITR_NO_UPDATE_DQO | GVE_ITR_CLEAR_PBA_BIT_DQO);
+
+ if (block->tx)
+ reschedule |= gve_tx_poll_dqo(block, /*do_clean=*/true);
+
+ if (block->rx) {
+ work_done = gve_rx_poll_dqo(block, budget);
+ reschedule |= work_done == budget;
+ }
+
+ if (reschedule)
+ return budget;
+
+ if (likely(napi_complete_done(napi, work_done))) {
+ /* Enable interrupts again.
+ *
+ * We don't need to repoll afterwards because HW supports the
+ * PCI MSI-X PBA feature.
+ *
+ * Another interrupt would be triggered if a new event came in
+ * since the last one.
+ */
+ gve_write_irq_doorbell_dqo(priv, block,
+ GVE_ITR_NO_UPDATE_DQO | GVE_ITR_ENABLE_BIT_DQO);
+ }
+
+ return work_done;
+}
+
static int gve_alloc_notify_blocks(struct gve_priv *priv)
{
int num_vecs_requested = priv->num_ntfy_blks + 1;
@@ -264,7 +332,8 @@ static int gve_alloc_notify_blocks(struct gve_priv *priv)
name, i);
block->priv = priv;
err = request_irq(priv->msix_vectors[msix_idx].vector,
- gve_intr, 0, block->name, block);
+ gve_is_gqi(priv) ? gve_intr : gve_intr_dqo,
+ 0, block->name, block);
if (err) {
dev_err(&priv->pdev->dev,
"Failed to receive msix vector %d\n", i);
@@ -346,6 +415,22 @@ static int gve_setup_device_resources(struct gve_priv *priv)
err = -ENXIO;
goto abort_with_stats_report;
}
+
+ if (priv->queue_format == GVE_DQO_RDA_FORMAT) {
+ priv->ptype_lut_dqo = kvzalloc(sizeof(*priv->ptype_lut_dqo),
+ GFP_KERNEL);
+ if (!priv->ptype_lut_dqo) {
+ err = -ENOMEM;
+ goto abort_with_stats_report;
+ }
+ err = gve_adminq_get_ptype_map_dqo(priv, priv->ptype_lut_dqo);
+ if (err) {
+ dev_err(&priv->pdev->dev,
+ "Failed to get ptype map: err=%d\n", err);
+ goto abort_with_ptype_lut;
+ }
+ }
+
err = gve_adminq_report_stats(priv, priv->stats_report_len,
priv->stats_report_bus,
GVE_STATS_REPORT_TIMER_PERIOD);
@@ -354,12 +439,17 @@ static int gve_setup_device_resources(struct gve_priv *priv)
"Failed to report stats: err=%d\n", err);
gve_set_device_resources_ok(priv);
return 0;
+
+abort_with_ptype_lut:
+ kvfree(priv->ptype_lut_dqo);
+ priv->ptype_lut_dqo = NULL;
abort_with_stats_report:
gve_free_stats_report(priv);
abort_with_ntfy_blocks:
gve_free_notify_blocks(priv);
abort_with_counter:
gve_free_counter_array(priv);
+
return err;
}
@@ -386,17 +476,22 @@ static void gve_teardown_device_resources(struct gve_priv *priv)
gve_trigger_reset(priv);
}
}
+
+ kvfree(priv->ptype_lut_dqo);
+ priv->ptype_lut_dqo = NULL;
+
gve_free_counter_array(priv);
gve_free_notify_blocks(priv);
gve_free_stats_report(priv);
gve_clear_device_resources_ok(priv);
}
-static void gve_add_napi(struct gve_priv *priv, int ntfy_idx)
+static void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
+ int (*gve_poll)(struct napi_struct *, int))
{
struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
- netif_napi_add(priv->dev, &block->napi, gve_napi_poll,
+ netif_napi_add(priv->dev, &block->napi, gve_poll,
NAPI_POLL_WEIGHT);
}
@@ -476,31 +571,75 @@ static int gve_create_rings(struct gve_priv *priv)
netif_dbg(priv, drv, priv->dev, "created %d rx queues\n",
priv->rx_cfg.num_queues);
- /* 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.
- */
- for (i = 0; i < priv->rx_cfg.num_queues; i++)
- gve_rx_write_doorbell(priv, &priv->rx[i]);
+ if (gve_is_gqi(priv)) {
+ /* 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.
+ */
+ for (i = 0; i < priv->rx_cfg.num_queues; i++)
+ gve_rx_write_doorbell(priv, &priv->rx[i]);
+ } else {
+ for (i = 0; i < priv->rx_cfg.num_queues; i++) {
+ /* Post buffers and ring doorbell. */
+ gve_rx_post_buffers_dqo(&priv->rx[i]);
+ }
+ }
return 0;
}
+static void add_napi_init_sync_stats(struct gve_priv *priv,
+ int (*napi_poll)(struct napi_struct *napi,
+ int budget))
+{
+ int i;
+
+ /* Add tx napi & init sync stats*/
+ for (i = 0; i < priv->tx_cfg.num_queues; i++) {
+ int ntfy_idx = gve_tx_idx_to_ntfy(priv, i);
+
+ u64_stats_init(&priv->tx[i].statss);
+ priv->tx[i].ntfy_id = ntfy_idx;
+ gve_add_napi(priv, ntfy_idx, napi_poll);
+ }
+ /* Add rx napi & init sync stats*/
+ for (i = 0; i < priv->rx_cfg.num_queues; i++) {
+ int ntfy_idx = gve_rx_idx_to_ntfy(priv, i);
+
+ u64_stats_init(&priv->rx[i].statss);
+ priv->rx[i].ntfy_id = ntfy_idx;
+ gve_add_napi(priv, ntfy_idx, napi_poll);
+ }
+}
+
+static void gve_tx_free_rings(struct gve_priv *priv)
+{
+ if (gve_is_gqi(priv)) {
+ gve_tx_free_rings_gqi(priv);
+ } else {
+ gve_tx_free_rings_dqo(priv);
+ }
+}
+
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 (gve_is_gqi(priv))
+ err = gve_tx_alloc_rings(priv);
+ else
+ err = gve_tx_alloc_rings_dqo(priv);
if (err)
goto free_tx;
+
/* Setup rx rings */
priv->rx = kvzalloc(priv->rx_cfg.num_queues * sizeof(*priv->rx),
GFP_KERNEL);
@@ -508,21 +647,18 @@ static int gve_alloc_rings(struct gve_priv *priv)
err = -ENOMEM;
goto free_tx_queue;
}
- err = gve_rx_alloc_rings(priv);
+
+ if (gve_is_gqi(priv))
+ err = gve_rx_alloc_rings(priv);
+ else
+ err = gve_rx_alloc_rings_dqo(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);
- }
+
+ if (gve_is_gqi(priv))
+ add_napi_init_sync_stats(priv, gve_napi_poll);
+ else
+ add_napi_init_sync_stats(priv, gve_napi_poll_dqo);
return 0;
@@ -560,6 +696,14 @@ static int gve_destroy_rings(struct gve_priv *priv)
return 0;
}
+static void gve_rx_free_rings(struct gve_priv *priv)
+{
+ if (gve_is_gqi(priv))
+ gve_rx_free_rings_gqi(priv);
+ else
+ gve_rx_free_rings_dqo(priv);
+}
+
static void gve_free_rings(struct gve_priv *priv)
{
int ntfy_idx;
@@ -681,7 +825,7 @@ static int gve_alloc_qpls(struct gve_priv *priv)
int err;
/* Raw addressing means no QPLs */
- if (priv->raw_addressing)
+ if (priv->queue_format == GVE_GQI_RDA_FORMAT)
return 0;
priv->qpls = kvzalloc(num_qpls * sizeof(*priv->qpls), GFP_KERNEL);
@@ -725,7 +869,7 @@ static void gve_free_qpls(struct gve_priv *priv)
int i;
/* Raw addressing means no QPLs */
- if (priv->raw_addressing)
+ if (priv->queue_format == GVE_GQI_RDA_FORMAT)
return;
kvfree(priv->qpl_cfg.qpl_id_map);
@@ -759,6 +903,7 @@ static int gve_open(struct net_device *dev)
err = gve_alloc_qpls(priv);
if (err)
return err;
+
err = gve_alloc_rings(priv);
if (err)
goto free_qpls;
@@ -773,9 +918,17 @@ static int gve_open(struct net_device *dev)
err = gve_register_qpls(priv);
if (err)
goto reset;
+
+ if (!gve_is_gqi(priv)) {
+ /* Hard code this for now. This may be tuned in the future for
+ * performance.
+ */
+ priv->data_buffer_size_dqo = GVE_RX_BUFFER_SIZE_DQO;
+ }
err = gve_create_rings(priv);
if (err)
goto reset;
+
gve_set_device_rings_ok(priv);
if (gve_get_report_stats(priv))
@@ -924,14 +1077,26 @@ static void gve_turnup(struct gve_priv *priv)
struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
napi_enable(&block->napi);
- iowrite32be(0, gve_irq_doorbell(priv, block));
+ if (gve_is_gqi(priv)) {
+ iowrite32be(0, gve_irq_doorbell(priv, block));
+ } else {
+ u32 val = gve_set_itr_ratelimit_dqo(GVE_TX_IRQ_RATELIMIT_US_DQO);
+
+ gve_write_irq_doorbell_dqo(priv, block, val);
+ }
}
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));
+ if (gve_is_gqi(priv)) {
+ iowrite32be(0, gve_irq_doorbell(priv, block));
+ } else {
+ u32 val = gve_set_itr_ratelimit_dqo(GVE_RX_IRQ_RATELIMIT_US_DQO);
+
+ gve_write_irq_doorbell_dqo(priv, block, val);
+ }
}
gve_set_napi_enabled(priv);
@@ -945,12 +1110,49 @@ static void gve_tx_timeout(struct net_device *dev, unsigned int txqueue)
priv->tx_timeo_cnt++;
}
+static int gve_set_features(struct net_device *netdev,
+ netdev_features_t features)
+{
+ const netdev_features_t orig_features = netdev->features;
+ struct gve_priv *priv = netdev_priv(netdev);
+ int err;
+
+ if ((netdev->features & NETIF_F_LRO) != (features & NETIF_F_LRO)) {
+ netdev->features ^= NETIF_F_LRO;
+ if (netif_carrier_ok(netdev)) {
+ /* 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(netdev);
+ /* We have already tried to reset in close, just fail
+ * at this point.
+ */
+ if (err)
+ goto err;
+
+ err = gve_open(netdev);
+ if (err)
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ /* Reverts the change on error. */
+ netdev->features = orig_features;
+ netif_err(priv, drv, netdev,
+ "Set features failed! !!! DISABLING ALL QUEUES !!!\n");
+ return err;
+}
+
static const struct net_device_ops gve_netdev_ops = {
- .ndo_start_xmit = gve_tx,
+ .ndo_start_xmit = gve_start_xmit,
.ndo_open = gve_open,
.ndo_stop = gve_close,
.ndo_get_stats64 = gve_get_stats,
.ndo_tx_timeout = gve_tx_timeout,
+ .ndo_set_features = gve_set_features,
};
static void gve_handle_status(struct gve_priv *priv, u32 status)
@@ -994,6 +1196,15 @@ void gve_handle_report_stats(struct gve_priv *priv)
/* tx stats */
if (priv->tx) {
for (idx = 0; idx < priv->tx_cfg.num_queues; idx++) {
+ u32 last_completion = 0;
+ u32 tx_frames = 0;
+
+ /* DQO doesn't currently support these metrics. */
+ if (gve_is_gqi(priv)) {
+ last_completion = priv->tx[idx].done;
+ tx_frames = priv->tx[idx].req;
+ }
+
do {
start = u64_stats_fetch_begin(&priv->tx[idx].statss);
tx_bytes = priv->tx[idx].bytes_done;
@@ -1010,7 +1221,7 @@ void gve_handle_report_stats(struct gve_priv *priv)
};
stats[stats_idx++] = (struct stats) {
.stat_name = cpu_to_be32(TX_FRAMES_SENT),
- .value = cpu_to_be64(priv->tx[idx].req),
+ .value = cpu_to_be64(tx_frames),
.queue_id = cpu_to_be32(idx),
};
stats[stats_idx++] = (struct stats) {
@@ -1020,7 +1231,7 @@ void gve_handle_report_stats(struct gve_priv *priv)
};
stats[stats_idx++] = (struct stats) {
.stat_name = cpu_to_be32(TX_LAST_COMPLETION_PROCESSED),
- .value = cpu_to_be64(priv->tx[idx].done),
+ .value = cpu_to_be64(last_completion),
.queue_id = cpu_to_be32(idx),
};
}
@@ -1088,7 +1299,7 @@ static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device)
if (skip_describe_device)
goto setup_device;
- priv->raw_addressing = false;
+ priv->queue_format = GVE_QUEUE_FORMAT_UNSPECIFIED;
/* Get the initial information we need from the device */
err = gve_adminq_describe_device(priv);
if (err) {
@@ -1096,7 +1307,7 @@ static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device)
"Could not get device information: err=%d\n", err);
goto err;
}
- if (priv->dev->max_mtu > PAGE_SIZE) {
+ if (gve_is_gqi(priv) && priv->dev->max_mtu > PAGE_SIZE) {
priv->dev->max_mtu = PAGE_SIZE;
err = gve_adminq_set_mtu(priv, priv->dev->mtu);
if (err) {
@@ -1258,7 +1469,7 @@ static int gve_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = pci_enable_device(pdev);
if (err)
- return -ENXIO;
+ return err;
err = pci_request_regions(pdev, "gvnic-cfg");
if (err)
@@ -1266,19 +1477,12 @@ static int gve_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
- err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ err = dma_set_mask_and_coherent(&pdev->dev, 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");
@@ -1295,19 +1499,25 @@ static int gve_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
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);
+ max_tx_queues = ioread32be(&reg_bar->max_tx_queues);
+ max_rx_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");
+ err = -ENOMEM;
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 */
+
+ /* Set default and supported features.
+ *
+ * Features might be set in other locations as well (such as
+ * `gve_adminq_describe_device`).
+ */
dev->hw_features = NETIF_F_HIGHDMA;
dev->hw_features |= NETIF_F_SG;
dev->hw_features |= NETIF_F_HW_CSUM;
@@ -1349,13 +1559,17 @@ static int gve_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = register_netdev(dev);
if (err)
- goto abort_with_wq;
+ goto abort_with_gve_init;
dev_info(&pdev->dev, "GVE version %s\n", gve_version_str);
+ dev_info(&pdev->dev, "GVE queue format %d\n", (int)priv->queue_format);
gve_clear_probe_in_progress(priv);
queue_work(priv->gve_wq, &priv->service_task);
return 0;
+abort_with_gve_init:
+ gve_teardown_priv_resources(priv);
+
abort_with_wq:
destroy_workqueue(priv->gve_wq);
@@ -1373,7 +1587,7 @@ abort_with_pci_region:
abort_with_enabled:
pci_disable_device(pdev);
- return -ENXIO;
+ return err;
}
static void gve_remove(struct pci_dev *pdev)
diff --git a/drivers/net/ethernet/google/gve/gve_rx.c b/drivers/net/ethernet/google/gve/gve_rx.c
index bf123fe524c4..bb8261368250 100644
--- a/drivers/net/ethernet/google/gve/gve_rx.c
+++ b/drivers/net/ethernet/google/gve/gve_rx.c
@@ -1,21 +1,14 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Google virtual Ethernet (gve) driver
*
- * Copyright (C) 2015-2019 Google, Inc.
+ * Copyright (C) 2015-2021 Google, Inc.
*/
#include "gve.h"
#include "gve_adminq.h"
+#include "gve_utils.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_buffer(struct device *dev,
struct gve_rx_slot_page_info *page_info,
union gve_rx_data_slot *data_slot)
@@ -137,16 +130,6 @@ alloc_err:
return err;
}
-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];
@@ -165,7 +148,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
slots = priv->rx_data_slot_cnt;
rx->mask = slots - 1;
- rx->data.raw_addressing = priv->raw_addressing;
+ rx->data.raw_addressing = priv->queue_format == GVE_GQI_RDA_FORMAT;
/* alloc rx data ring */
bytes = sizeof(*rx->data.data_ring) * slots;
@@ -255,7 +238,7 @@ int gve_rx_alloc_rings(struct gve_priv *priv)
return err;
}
-void gve_rx_free_rings(struct gve_priv *priv)
+void gve_rx_free_rings_gqi(struct gve_priv *priv)
{
int i;
@@ -279,27 +262,6 @@ static enum pkt_hash_types gve_rss_type(__be16 pkt_flags)
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 ? PAGE_SIZE / 2 : 0);
-
- 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 napi_struct *napi,
struct gve_rx_slot_page_info *page_info,
u16 len)
@@ -310,7 +272,7 @@ static struct sk_buff *gve_rx_add_frags(struct napi_struct *napi,
return NULL;
skb_add_rx_frag(skb, 0, page_info->page,
- (page_info->page_offset ? PAGE_SIZE / 2 : 0) +
+ page_info->page_offset +
GVE_RX_PAD, len, PAGE_SIZE / 2);
return skb;
@@ -321,7 +283,7 @@ static void gve_rx_flip_buff(struct gve_rx_slot_page_info *page_info, __be64 *sl
const __be64 offset = cpu_to_be64(PAGE_SIZE / 2);
/* "flip" to other packet buffer on this page */
- page_info->page_offset ^= 0x1;
+ page_info->page_offset ^= PAGE_SIZE / 2;
*(slot_addr) ^= offset;
}
@@ -388,7 +350,7 @@ gve_rx_qpl(struct device *dev, struct net_device *netdev,
gve_rx_flip_buff(page_info, &data_slot->qpl_offset);
}
} else {
- skb = gve_rx_copy(netdev, napi, page_info, len);
+ skb = gve_rx_copy(netdev, napi, page_info, len, GVE_RX_PAD);
if (skb) {
u64_stats_update_begin(&rx->statss);
rx->rx_copied_pkt++;
@@ -430,7 +392,7 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
if (len <= priv->rx_copybreak) {
/* Just copy small packets */
- skb = gve_rx_copy(dev, napi, page_info, len);
+ skb = gve_rx_copy(dev, napi, page_info, len, GVE_RX_PAD);
u64_stats_update_begin(&rx->statss);
rx->rx_copied_pkt++;
rx->rx_copybreak_pkt++;
diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
new file mode 100644
index 000000000000..8500621b2cd4
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -0,0 +1,756 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2021 Google, Inc.
+ */
+
+#include "gve.h"
+#include "gve_dqo.h"
+#include "gve_adminq.h"
+#include "gve_utils.h"
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <net/ip6_checksum.h>
+#include <net/ipv6.h>
+#include <net/tcp.h>
+
+static int gve_buf_ref_cnt(struct gve_rx_buf_state_dqo *bs)
+{
+ return page_count(bs->page_info.page) - bs->page_info.pagecnt_bias;
+}
+
+static void gve_free_page_dqo(struct gve_priv *priv,
+ struct gve_rx_buf_state_dqo *bs)
+{
+ page_ref_sub(bs->page_info.page, bs->page_info.pagecnt_bias - 1);
+ gve_free_page(&priv->pdev->dev, bs->page_info.page, bs->addr,
+ DMA_FROM_DEVICE);
+ bs->page_info.page = NULL;
+}
+
+static struct gve_rx_buf_state_dqo *gve_alloc_buf_state(struct gve_rx_ring *rx)
+{
+ struct gve_rx_buf_state_dqo *buf_state;
+ s16 buffer_id;
+
+ buffer_id = rx->dqo.free_buf_states;
+ if (unlikely(buffer_id == -1))
+ return NULL;
+
+ buf_state = &rx->dqo.buf_states[buffer_id];
+
+ /* Remove buf_state from free list */
+ rx->dqo.free_buf_states = buf_state->next;
+
+ /* Point buf_state to itself to mark it as allocated */
+ buf_state->next = buffer_id;
+
+ return buf_state;
+}
+
+static bool gve_buf_state_is_allocated(struct gve_rx_ring *rx,
+ struct gve_rx_buf_state_dqo *buf_state)
+{
+ s16 buffer_id = buf_state - rx->dqo.buf_states;
+
+ return buf_state->next == buffer_id;
+}
+
+static void gve_free_buf_state(struct gve_rx_ring *rx,
+ struct gve_rx_buf_state_dqo *buf_state)
+{
+ s16 buffer_id = buf_state - rx->dqo.buf_states;
+
+ buf_state->next = rx->dqo.free_buf_states;
+ rx->dqo.free_buf_states = buffer_id;
+}
+
+static struct gve_rx_buf_state_dqo *
+gve_dequeue_buf_state(struct gve_rx_ring *rx, struct gve_index_list *list)
+{
+ struct gve_rx_buf_state_dqo *buf_state;
+ s16 buffer_id;
+
+ buffer_id = list->head;
+ if (unlikely(buffer_id == -1))
+ return NULL;
+
+ buf_state = &rx->dqo.buf_states[buffer_id];
+
+ /* Remove buf_state from list */
+ list->head = buf_state->next;
+ if (buf_state->next == -1)
+ list->tail = -1;
+
+ /* Point buf_state to itself to mark it as allocated */
+ buf_state->next = buffer_id;
+
+ return buf_state;
+}
+
+static void gve_enqueue_buf_state(struct gve_rx_ring *rx,
+ struct gve_index_list *list,
+ struct gve_rx_buf_state_dqo *buf_state)
+{
+ s16 buffer_id = buf_state - rx->dqo.buf_states;
+
+ buf_state->next = -1;
+
+ if (list->head == -1) {
+ list->head = buffer_id;
+ list->tail = buffer_id;
+ } else {
+ int tail = list->tail;
+
+ rx->dqo.buf_states[tail].next = buffer_id;
+ list->tail = buffer_id;
+ }
+}
+
+static struct gve_rx_buf_state_dqo *
+gve_get_recycled_buf_state(struct gve_rx_ring *rx)
+{
+ struct gve_rx_buf_state_dqo *buf_state;
+ int i;
+
+ /* Recycled buf states are immediately usable. */
+ buf_state = gve_dequeue_buf_state(rx, &rx->dqo.recycled_buf_states);
+ if (likely(buf_state))
+ return buf_state;
+
+ if (unlikely(rx->dqo.used_buf_states.head == -1))
+ return NULL;
+
+ /* Used buf states are only usable when ref count reaches 0, which means
+ * no SKBs refer to them.
+ *
+ * Search a limited number before giving up.
+ */
+ for (i = 0; i < 5; i++) {
+ buf_state = gve_dequeue_buf_state(rx, &rx->dqo.used_buf_states);
+ if (gve_buf_ref_cnt(buf_state) == 0)
+ return buf_state;
+
+ gve_enqueue_buf_state(rx, &rx->dqo.used_buf_states, buf_state);
+ }
+
+ /* If there are no free buf states discard an entry from
+ * `used_buf_states` so it can be used.
+ */
+ if (unlikely(rx->dqo.free_buf_states == -1)) {
+ buf_state = gve_dequeue_buf_state(rx, &rx->dqo.used_buf_states);
+ if (gve_buf_ref_cnt(buf_state) == 0)
+ return buf_state;
+
+ gve_free_page_dqo(rx->gve, buf_state);
+ gve_free_buf_state(rx, buf_state);
+ }
+
+ return NULL;
+}
+
+static int gve_alloc_page_dqo(struct gve_priv *priv,
+ struct gve_rx_buf_state_dqo *buf_state)
+{
+ int err;
+
+ err = gve_alloc_page(priv, &priv->pdev->dev, &buf_state->page_info.page,
+ &buf_state->addr, DMA_FROM_DEVICE);
+ if (err)
+ return err;
+
+ buf_state->page_info.page_offset = 0;
+ buf_state->page_info.page_address =
+ page_address(buf_state->page_info.page);
+ buf_state->last_single_ref_offset = 0;
+
+ /* The page already has 1 ref. */
+ page_ref_add(buf_state->page_info.page, INT_MAX - 1);
+ buf_state->page_info.pagecnt_bias = INT_MAX;
+
+ return 0;
+}
+
+static void gve_rx_free_ring_dqo(struct gve_priv *priv, int idx)
+{
+ struct gve_rx_ring *rx = &priv->rx[idx];
+ struct device *hdev = &priv->pdev->dev;
+ size_t completion_queue_slots;
+ size_t buffer_queue_slots;
+ size_t size;
+ int i;
+
+ completion_queue_slots = rx->dqo.complq.mask + 1;
+ buffer_queue_slots = rx->dqo.bufq.mask + 1;
+
+ gve_rx_remove_from_block(priv, idx);
+
+ if (rx->q_resources) {
+ dma_free_coherent(hdev, sizeof(*rx->q_resources),
+ rx->q_resources, rx->q_resources_bus);
+ rx->q_resources = NULL;
+ }
+
+ for (i = 0; i < rx->dqo.num_buf_states; i++) {
+ struct gve_rx_buf_state_dqo *bs = &rx->dqo.buf_states[i];
+
+ if (bs->page_info.page)
+ gve_free_page_dqo(priv, bs);
+ }
+
+ if (rx->dqo.bufq.desc_ring) {
+ size = sizeof(rx->dqo.bufq.desc_ring[0]) * buffer_queue_slots;
+ dma_free_coherent(hdev, size, rx->dqo.bufq.desc_ring,
+ rx->dqo.bufq.bus);
+ rx->dqo.bufq.desc_ring = NULL;
+ }
+
+ if (rx->dqo.complq.desc_ring) {
+ size = sizeof(rx->dqo.complq.desc_ring[0]) *
+ completion_queue_slots;
+ dma_free_coherent(hdev, size, rx->dqo.complq.desc_ring,
+ rx->dqo.complq.bus);
+ rx->dqo.complq.desc_ring = NULL;
+ }
+
+ kvfree(rx->dqo.buf_states);
+ rx->dqo.buf_states = NULL;
+
+ netif_dbg(priv, drv, priv->dev, "freed rx ring %d\n", idx);
+}
+
+static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx)
+{
+ struct gve_rx_ring *rx = &priv->rx[idx];
+ struct device *hdev = &priv->pdev->dev;
+ size_t size;
+ int i;
+
+ const u32 buffer_queue_slots =
+ priv->options_dqo_rda.rx_buff_ring_entries;
+ const u32 completion_queue_slots = priv->rx_desc_cnt;
+
+ netif_dbg(priv, drv, priv->dev, "allocating rx ring DQO\n");
+
+ memset(rx, 0, sizeof(*rx));
+ rx->gve = priv;
+ rx->q_num = idx;
+ rx->dqo.bufq.mask = buffer_queue_slots - 1;
+ rx->dqo.complq.num_free_slots = completion_queue_slots;
+ rx->dqo.complq.mask = completion_queue_slots - 1;
+ rx->skb_head = NULL;
+ rx->skb_tail = NULL;
+
+ rx->dqo.num_buf_states = min_t(s16, S16_MAX, buffer_queue_slots * 4);
+ rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states,
+ sizeof(rx->dqo.buf_states[0]),
+ GFP_KERNEL);
+ if (!rx->dqo.buf_states)
+ return -ENOMEM;
+
+ /* Set up linked list of buffer IDs */
+ for (i = 0; i < rx->dqo.num_buf_states - 1; i++)
+ rx->dqo.buf_states[i].next = i + 1;
+
+ rx->dqo.buf_states[rx->dqo.num_buf_states - 1].next = -1;
+ rx->dqo.recycled_buf_states.head = -1;
+ rx->dqo.recycled_buf_states.tail = -1;
+ rx->dqo.used_buf_states.head = -1;
+ rx->dqo.used_buf_states.tail = -1;
+
+ /* Allocate RX completion queue */
+ size = sizeof(rx->dqo.complq.desc_ring[0]) *
+ completion_queue_slots;
+ rx->dqo.complq.desc_ring =
+ dma_alloc_coherent(hdev, size, &rx->dqo.complq.bus, GFP_KERNEL);
+ if (!rx->dqo.complq.desc_ring)
+ goto err;
+
+ /* Allocate RX buffer queue */
+ size = sizeof(rx->dqo.bufq.desc_ring[0]) * buffer_queue_slots;
+ rx->dqo.bufq.desc_ring =
+ dma_alloc_coherent(hdev, size, &rx->dqo.bufq.bus, GFP_KERNEL);
+ if (!rx->dqo.bufq.desc_ring)
+ goto err;
+
+ rx->q_resources = dma_alloc_coherent(hdev, sizeof(*rx->q_resources),
+ &rx->q_resources_bus, GFP_KERNEL);
+ if (!rx->q_resources)
+ goto err;
+
+ gve_rx_add_to_block(priv, idx);
+
+ return 0;
+
+err:
+ gve_rx_free_ring_dqo(priv, idx);
+ return -ENOMEM;
+}
+
+void gve_rx_write_doorbell_dqo(const struct gve_priv *priv, int queue_idx)
+{
+ const struct gve_rx_ring *rx = &priv->rx[queue_idx];
+ u64 index = be32_to_cpu(rx->q_resources->db_index);
+
+ iowrite32(rx->dqo.bufq.tail, &priv->db_bar2[index]);
+}
+
+int gve_rx_alloc_rings_dqo(struct gve_priv *priv)
+{
+ int err = 0;
+ int i;
+
+ for (i = 0; i < priv->rx_cfg.num_queues; i++) {
+ err = gve_rx_alloc_ring_dqo(priv, i);
+ if (err) {
+ netif_err(priv, drv, priv->dev,
+ "Failed to alloc rx ring=%d: err=%d\n",
+ i, err);
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ for (i--; i >= 0; i--)
+ gve_rx_free_ring_dqo(priv, i);
+
+ return err;
+}
+
+void gve_rx_free_rings_dqo(struct gve_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->rx_cfg.num_queues; i++)
+ gve_rx_free_ring_dqo(priv, i);
+}
+
+void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx)
+{
+ struct gve_rx_compl_queue_dqo *complq = &rx->dqo.complq;
+ struct gve_rx_buf_queue_dqo *bufq = &rx->dqo.bufq;
+ struct gve_priv *priv = rx->gve;
+ u32 num_avail_slots;
+ u32 num_full_slots;
+ u32 num_posted = 0;
+
+ num_full_slots = (bufq->tail - bufq->head) & bufq->mask;
+ num_avail_slots = bufq->mask - num_full_slots;
+
+ num_avail_slots = min_t(u32, num_avail_slots, complq->num_free_slots);
+ while (num_posted < num_avail_slots) {
+ struct gve_rx_desc_dqo *desc = &bufq->desc_ring[bufq->tail];
+ struct gve_rx_buf_state_dqo *buf_state;
+
+ buf_state = gve_get_recycled_buf_state(rx);
+ if (unlikely(!buf_state)) {
+ buf_state = gve_alloc_buf_state(rx);
+ if (unlikely(!buf_state))
+ break;
+
+ if (unlikely(gve_alloc_page_dqo(priv, buf_state))) {
+ u64_stats_update_begin(&rx->statss);
+ rx->rx_buf_alloc_fail++;
+ u64_stats_update_end(&rx->statss);
+ gve_free_buf_state(rx, buf_state);
+ break;
+ }
+ }
+
+ desc->buf_id = cpu_to_le16(buf_state - rx->dqo.buf_states);
+ desc->buf_addr = cpu_to_le64(buf_state->addr +
+ buf_state->page_info.page_offset);
+
+ bufq->tail = (bufq->tail + 1) & bufq->mask;
+ complq->num_free_slots--;
+ num_posted++;
+
+ if ((bufq->tail & (GVE_RX_BUF_THRESH_DQO - 1)) == 0)
+ gve_rx_write_doorbell_dqo(priv, rx->q_num);
+ }
+
+ rx->fill_cnt += num_posted;
+}
+
+static void gve_try_recycle_buf(struct gve_priv *priv, struct gve_rx_ring *rx,
+ struct gve_rx_buf_state_dqo *buf_state)
+{
+ const int data_buffer_size = priv->data_buffer_size_dqo;
+ int pagecount;
+
+ /* Can't reuse if we only fit one buffer per page */
+ if (data_buffer_size * 2 > PAGE_SIZE)
+ goto mark_used;
+
+ pagecount = gve_buf_ref_cnt(buf_state);
+
+ /* Record the offset when we have a single remaining reference.
+ *
+ * When this happens, we know all of the other offsets of the page are
+ * usable.
+ */
+ if (pagecount == 1) {
+ buf_state->last_single_ref_offset =
+ buf_state->page_info.page_offset;
+ }
+
+ /* Use the next buffer sized chunk in the page. */
+ buf_state->page_info.page_offset += data_buffer_size;
+ buf_state->page_info.page_offset &= (PAGE_SIZE - 1);
+
+ /* If we wrap around to the same offset without ever dropping to 1
+ * reference, then we don't know if this offset was ever freed.
+ */
+ if (buf_state->page_info.page_offset ==
+ buf_state->last_single_ref_offset) {
+ goto mark_used;
+ }
+
+ gve_enqueue_buf_state(rx, &rx->dqo.recycled_buf_states, buf_state);
+ return;
+
+mark_used:
+ gve_enqueue_buf_state(rx, &rx->dqo.used_buf_states, buf_state);
+}
+
+static void gve_rx_skb_csum(struct sk_buff *skb,
+ const struct gve_rx_compl_desc_dqo *desc,
+ struct gve_ptype ptype)
+{
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* HW did not identify and process L3 and L4 headers. */
+ if (unlikely(!desc->l3_l4_processed))
+ return;
+
+ if (ptype.l3_type == GVE_L3_TYPE_IPV4) {
+ if (unlikely(desc->csum_ip_err || desc->csum_external_ip_err))
+ return;
+ } else if (ptype.l3_type == GVE_L3_TYPE_IPV6) {
+ /* Checksum should be skipped if this flag is set. */
+ if (unlikely(desc->ipv6_ex_add))
+ return;
+ }
+
+ if (unlikely(desc->csum_l4_err))
+ return;
+
+ switch (ptype.l4_type) {
+ case GVE_L4_TYPE_TCP:
+ case GVE_L4_TYPE_UDP:
+ case GVE_L4_TYPE_ICMP:
+ case GVE_L4_TYPE_SCTP:
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ break;
+ default:
+ break;
+ }
+}
+
+static void gve_rx_skb_hash(struct sk_buff *skb,
+ const struct gve_rx_compl_desc_dqo *compl_desc,
+ struct gve_ptype ptype)
+{
+ enum pkt_hash_types hash_type = PKT_HASH_TYPE_L2;
+
+ if (ptype.l4_type != GVE_L4_TYPE_UNKNOWN)
+ hash_type = PKT_HASH_TYPE_L4;
+ else if (ptype.l3_type != GVE_L3_TYPE_UNKNOWN)
+ hash_type = PKT_HASH_TYPE_L3;
+
+ skb_set_hash(skb, le32_to_cpu(compl_desc->hash), hash_type);
+}
+
+static void gve_rx_free_skb(struct gve_rx_ring *rx)
+{
+ if (!rx->skb_head)
+ return;
+
+ dev_kfree_skb_any(rx->skb_head);
+ rx->skb_head = NULL;
+ rx->skb_tail = NULL;
+}
+
+/* Chains multi skbs for single rx packet.
+ * Returns 0 if buffer is appended, -1 otherwise.
+ */
+static int gve_rx_append_frags(struct napi_struct *napi,
+ struct gve_rx_buf_state_dqo *buf_state,
+ u16 buf_len, struct gve_rx_ring *rx,
+ struct gve_priv *priv)
+{
+ int num_frags = skb_shinfo(rx->skb_tail)->nr_frags;
+
+ if (unlikely(num_frags == MAX_SKB_FRAGS)) {
+ struct sk_buff *skb;
+
+ skb = napi_alloc_skb(napi, 0);
+ if (!skb)
+ return -1;
+
+ skb_shinfo(rx->skb_tail)->frag_list = skb;
+ rx->skb_tail = skb;
+ num_frags = 0;
+ }
+ if (rx->skb_tail != rx->skb_head) {
+ rx->skb_head->len += buf_len;
+ rx->skb_head->data_len += buf_len;
+ rx->skb_head->truesize += priv->data_buffer_size_dqo;
+ }
+
+ skb_add_rx_frag(rx->skb_tail, num_frags,
+ buf_state->page_info.page,
+ buf_state->page_info.page_offset,
+ buf_len, priv->data_buffer_size_dqo);
+ gve_dec_pagecnt_bias(&buf_state->page_info);
+
+ return 0;
+}
+
+/* Returns 0 if descriptor is completed successfully.
+ * Returns -EINVAL if descriptor is invalid.
+ * Returns -ENOMEM if data cannot be copied to skb.
+ */
+static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx,
+ const struct gve_rx_compl_desc_dqo *compl_desc,
+ int queue_idx)
+{
+ const u16 buffer_id = le16_to_cpu(compl_desc->buf_id);
+ const bool eop = compl_desc->end_of_packet != 0;
+ struct gve_rx_buf_state_dqo *buf_state;
+ struct gve_priv *priv = rx->gve;
+ u16 buf_len;
+
+ if (unlikely(buffer_id >= rx->dqo.num_buf_states)) {
+ net_err_ratelimited("%s: Invalid RX buffer_id=%u\n",
+ priv->dev->name, buffer_id);
+ return -EINVAL;
+ }
+ buf_state = &rx->dqo.buf_states[buffer_id];
+ if (unlikely(!gve_buf_state_is_allocated(rx, buf_state))) {
+ net_err_ratelimited("%s: RX buffer_id is not allocated: %u\n",
+ priv->dev->name, buffer_id);
+ return -EINVAL;
+ }
+
+ if (unlikely(compl_desc->rx_error)) {
+ gve_enqueue_buf_state(rx, &rx->dqo.recycled_buf_states,
+ buf_state);
+ return -EINVAL;
+ }
+
+ buf_len = compl_desc->packet_len;
+
+ /* Page might have not been used for awhile and was likely last written
+ * by a different thread.
+ */
+ prefetch(buf_state->page_info.page);
+
+ /* Sync the portion of dma buffer for CPU to read. */
+ dma_sync_single_range_for_cpu(&priv->pdev->dev, buf_state->addr,
+ buf_state->page_info.page_offset,
+ buf_len, DMA_FROM_DEVICE);
+
+ /* Append to current skb if one exists. */
+ if (rx->skb_head) {
+ if (unlikely(gve_rx_append_frags(napi, buf_state, buf_len, rx,
+ priv)) != 0) {
+ goto error;
+ }
+
+ gve_try_recycle_buf(priv, rx, buf_state);
+ return 0;
+ }
+
+ if (eop && buf_len <= priv->rx_copybreak) {
+ rx->skb_head = gve_rx_copy(priv->dev, napi,
+ &buf_state->page_info, buf_len, 0);
+ if (unlikely(!rx->skb_head))
+ goto error;
+ rx->skb_tail = rx->skb_head;
+
+ u64_stats_update_begin(&rx->statss);
+ rx->rx_copied_pkt++;
+ rx->rx_copybreak_pkt++;
+ u64_stats_update_end(&rx->statss);
+
+ gve_enqueue_buf_state(rx, &rx->dqo.recycled_buf_states,
+ buf_state);
+ return 0;
+ }
+
+ rx->skb_head = napi_get_frags(napi);
+ if (unlikely(!rx->skb_head))
+ goto error;
+ rx->skb_tail = rx->skb_head;
+
+ skb_add_rx_frag(rx->skb_head, 0, buf_state->page_info.page,
+ buf_state->page_info.page_offset, buf_len,
+ priv->data_buffer_size_dqo);
+ gve_dec_pagecnt_bias(&buf_state->page_info);
+
+ gve_try_recycle_buf(priv, rx, buf_state);
+ return 0;
+
+error:
+ gve_enqueue_buf_state(rx, &rx->dqo.recycled_buf_states, buf_state);
+ return -ENOMEM;
+}
+
+static int gve_rx_complete_rsc(struct sk_buff *skb,
+ const struct gve_rx_compl_desc_dqo *desc,
+ struct gve_ptype ptype)
+{
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+
+ /* Only TCP is supported right now. */
+ if (ptype.l4_type != GVE_L4_TYPE_TCP)
+ return -EINVAL;
+
+ switch (ptype.l3_type) {
+ case GVE_L3_TYPE_IPV4:
+ shinfo->gso_type = SKB_GSO_TCPV4;
+ break;
+ case GVE_L3_TYPE_IPV6:
+ shinfo->gso_type = SKB_GSO_TCPV6;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ shinfo->gso_size = le16_to_cpu(desc->rsc_seg_len);
+ return 0;
+}
+
+/* Returns 0 if skb is completed successfully, -1 otherwise. */
+static int gve_rx_complete_skb(struct gve_rx_ring *rx, struct napi_struct *napi,
+ const struct gve_rx_compl_desc_dqo *desc,
+ netdev_features_t feat)
+{
+ struct gve_ptype ptype =
+ rx->gve->ptype_lut_dqo->ptypes[desc->packet_type];
+ int err;
+
+ skb_record_rx_queue(rx->skb_head, rx->q_num);
+
+ if (feat & NETIF_F_RXHASH)
+ gve_rx_skb_hash(rx->skb_head, desc, ptype);
+
+ if (feat & NETIF_F_RXCSUM)
+ gve_rx_skb_csum(rx->skb_head, desc, ptype);
+
+ /* RSC packets must set gso_size otherwise the TCP stack will complain
+ * that packets are larger than MTU.
+ */
+ if (desc->rsc) {
+ err = gve_rx_complete_rsc(rx->skb_head, desc, ptype);
+ if (err < 0)
+ return err;
+ }
+
+ if (skb_headlen(rx->skb_head) == 0)
+ napi_gro_frags(napi);
+ else
+ napi_gro_receive(napi, rx->skb_head);
+
+ return 0;
+}
+
+int gve_rx_poll_dqo(struct gve_notify_block *block, int budget)
+{
+ struct napi_struct *napi = &block->napi;
+ netdev_features_t feat = napi->dev->features;
+
+ struct gve_rx_ring *rx = block->rx;
+ struct gve_rx_compl_queue_dqo *complq = &rx->dqo.complq;
+
+ u32 work_done = 0;
+ u64 bytes = 0;
+ int err;
+
+ while (work_done < budget) {
+ struct gve_rx_compl_desc_dqo *compl_desc =
+ &complq->desc_ring[complq->head];
+ u32 pkt_bytes;
+
+ /* No more new packets */
+ if (compl_desc->generation == complq->cur_gen_bit)
+ break;
+
+ /* Prefetch the next two descriptors. */
+ prefetch(&complq->desc_ring[(complq->head + 1) & complq->mask]);
+ prefetch(&complq->desc_ring[(complq->head + 2) & complq->mask]);
+
+ /* Do not read data until we own the descriptor */
+ dma_rmb();
+
+ err = gve_rx_dqo(napi, rx, compl_desc, rx->q_num);
+ if (err < 0) {
+ gve_rx_free_skb(rx);
+ u64_stats_update_begin(&rx->statss);
+ if (err == -ENOMEM)
+ rx->rx_skb_alloc_fail++;
+ else if (err == -EINVAL)
+ rx->rx_desc_err_dropped_pkt++;
+ u64_stats_update_end(&rx->statss);
+ }
+
+ complq->head = (complq->head + 1) & complq->mask;
+ complq->num_free_slots++;
+
+ /* When the ring wraps, the generation bit is flipped. */
+ complq->cur_gen_bit ^= (complq->head == 0);
+
+ /* Receiving a completion means we have space to post another
+ * buffer on the buffer queue.
+ */
+ {
+ struct gve_rx_buf_queue_dqo *bufq = &rx->dqo.bufq;
+
+ bufq->head = (bufq->head + 1) & bufq->mask;
+ }
+
+ /* Free running counter of completed descriptors */
+ rx->cnt++;
+
+ if (!rx->skb_head)
+ continue;
+
+ if (!compl_desc->end_of_packet)
+ continue;
+
+ work_done++;
+ pkt_bytes = rx->skb_head->len;
+ /* The ethernet header (first ETH_HLEN bytes) is snipped off
+ * by eth_type_trans.
+ */
+ if (skb_headlen(rx->skb_head))
+ pkt_bytes += ETH_HLEN;
+
+ /* gve_rx_complete_skb() will consume skb if successful */
+ if (gve_rx_complete_skb(rx, napi, compl_desc, feat) != 0) {
+ gve_rx_free_skb(rx);
+ u64_stats_update_begin(&rx->statss);
+ rx->rx_desc_err_dropped_pkt++;
+ u64_stats_update_end(&rx->statss);
+ continue;
+ }
+
+ bytes += pkt_bytes;
+ rx->skb_head = NULL;
+ rx->skb_tail = NULL;
+ }
+
+ gve_rx_post_buffers_dqo(rx);
+
+ u64_stats_update_begin(&rx->statss);
+ rx->rpackets += work_done;
+ rx->rbytes += bytes;
+ u64_stats_update_end(&rx->statss);
+
+ return work_done;
+}
diff --git a/drivers/net/ethernet/google/gve/gve_tx.c b/drivers/net/ethernet/google/gve/gve_tx.c
index 3e04a3973d68..665ac795a1ad 100644
--- a/drivers/net/ethernet/google/gve/gve_tx.c
+++ b/drivers/net/ethernet/google/gve/gve_tx.c
@@ -1,11 +1,12 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Google virtual Ethernet (gve) driver
*
- * Copyright (C) 2015-2019 Google, Inc.
+ * Copyright (C) 2015-2021 Google, Inc.
*/
#include "gve.h"
#include "gve_adminq.h"
+#include "gve_utils.h"
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/vmalloc.h>
@@ -131,14 +132,6 @@ 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);
@@ -174,16 +167,6 @@ static void gve_tx_free_ring(struct gve_priv *priv, int idx)
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];
@@ -208,7 +191,7 @@ static int gve_tx_alloc_ring(struct gve_priv *priv, int idx)
if (!tx->desc)
goto abort_with_info;
- tx->raw_addressing = priv->raw_addressing;
+ tx->raw_addressing = priv->queue_format == GVE_GQI_RDA_FORMAT;
tx->dev = &priv->pdev->dev;
if (!tx->raw_addressing) {
tx->tx_fifo.qpl = gve_assign_tx_qpl(priv);
@@ -273,7 +256,7 @@ int gve_tx_alloc_rings(struct gve_priv *priv)
return err;
}
-void gve_tx_free_rings(struct gve_priv *priv)
+void gve_tx_free_rings_gqi(struct gve_priv *priv)
{
int i;
diff --git a/drivers/net/ethernet/google/gve/gve_tx_dqo.c b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
new file mode 100644
index 000000000000..05ddb6a75c38
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -0,0 +1,1030 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2021 Google, Inc.
+ */
+
+#include "gve.h"
+#include "gve_adminq.h"
+#include "gve_utils.h"
+#include "gve_dqo.h"
+#include <linux/tcp.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+
+/* Returns true if a gve_tx_pending_packet_dqo object is available. */
+static bool gve_has_pending_packet(struct gve_tx_ring *tx)
+{
+ /* Check TX path's list. */
+ if (tx->dqo_tx.free_pending_packets != -1)
+ return true;
+
+ /* Check completion handler's list. */
+ if (atomic_read_acquire(&tx->dqo_compl.free_pending_packets) != -1)
+ return true;
+
+ return false;
+}
+
+static struct gve_tx_pending_packet_dqo *
+gve_alloc_pending_packet(struct gve_tx_ring *tx)
+{
+ struct gve_tx_pending_packet_dqo *pending_packet;
+ s16 index;
+
+ index = tx->dqo_tx.free_pending_packets;
+
+ /* No pending_packets available, try to steal the list from the
+ * completion handler.
+ */
+ if (unlikely(index == -1)) {
+ tx->dqo_tx.free_pending_packets =
+ atomic_xchg(&tx->dqo_compl.free_pending_packets, -1);
+ index = tx->dqo_tx.free_pending_packets;
+
+ if (unlikely(index == -1))
+ return NULL;
+ }
+
+ pending_packet = &tx->dqo.pending_packets[index];
+
+ /* Remove pending_packet from free list */
+ tx->dqo_tx.free_pending_packets = pending_packet->next;
+ pending_packet->state = GVE_PACKET_STATE_PENDING_DATA_COMPL;
+
+ return pending_packet;
+}
+
+static void
+gve_free_pending_packet(struct gve_tx_ring *tx,
+ struct gve_tx_pending_packet_dqo *pending_packet)
+{
+ s16 index = pending_packet - tx->dqo.pending_packets;
+
+ pending_packet->state = GVE_PACKET_STATE_UNALLOCATED;
+ while (true) {
+ s16 old_head = atomic_read_acquire(&tx->dqo_compl.free_pending_packets);
+
+ pending_packet->next = old_head;
+ if (atomic_cmpxchg(&tx->dqo_compl.free_pending_packets,
+ old_head, index) == old_head) {
+ break;
+ }
+ }
+}
+
+/* gve_tx_free_desc - Cleans up all pending tx requests and buffers.
+ */
+static void gve_tx_clean_pending_packets(struct gve_tx_ring *tx)
+{
+ int i;
+
+ for (i = 0; i < tx->dqo.num_pending_packets; i++) {
+ struct gve_tx_pending_packet_dqo *cur_state =
+ &tx->dqo.pending_packets[i];
+ int j;
+
+ for (j = 0; j < cur_state->num_bufs; j++) {
+ struct gve_tx_dma_buf *buf = &cur_state->bufs[j];
+
+ if (j == 0) {
+ dma_unmap_single(tx->dev,
+ dma_unmap_addr(buf, dma),
+ dma_unmap_len(buf, len),
+ DMA_TO_DEVICE);
+ } else {
+ dma_unmap_page(tx->dev,
+ dma_unmap_addr(buf, dma),
+ dma_unmap_len(buf, len),
+ DMA_TO_DEVICE);
+ }
+ }
+ if (cur_state->skb) {
+ dev_consume_skb_any(cur_state->skb);
+ cur_state->skb = NULL;
+ }
+ }
+}
+
+static void gve_tx_free_ring_dqo(struct gve_priv *priv, int idx)
+{
+ struct gve_tx_ring *tx = &priv->tx[idx];
+ struct device *hdev = &priv->pdev->dev;
+ size_t bytes;
+
+ gve_tx_remove_from_block(priv, idx);
+
+ if (tx->q_resources) {
+ dma_free_coherent(hdev, sizeof(*tx->q_resources),
+ tx->q_resources, tx->q_resources_bus);
+ tx->q_resources = NULL;
+ }
+
+ if (tx->dqo.compl_ring) {
+ bytes = sizeof(tx->dqo.compl_ring[0]) *
+ (tx->dqo.complq_mask + 1);
+ dma_free_coherent(hdev, bytes, tx->dqo.compl_ring,
+ tx->complq_bus_dqo);
+ tx->dqo.compl_ring = NULL;
+ }
+
+ if (tx->dqo.tx_ring) {
+ bytes = sizeof(tx->dqo.tx_ring[0]) * (tx->mask + 1);
+ dma_free_coherent(hdev, bytes, tx->dqo.tx_ring, tx->bus);
+ tx->dqo.tx_ring = NULL;
+ }
+
+ kvfree(tx->dqo.pending_packets);
+ tx->dqo.pending_packets = NULL;
+
+ netif_dbg(priv, drv, priv->dev, "freed tx queue %d\n", idx);
+}
+
+static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx)
+{
+ struct gve_tx_ring *tx = &priv->tx[idx];
+ struct device *hdev = &priv->pdev->dev;
+ int num_pending_packets;
+ size_t bytes;
+ int i;
+
+ memset(tx, 0, sizeof(*tx));
+ tx->q_num = idx;
+ tx->dev = &priv->pdev->dev;
+ tx->netdev_txq = netdev_get_tx_queue(priv->dev, idx);
+ atomic_set_release(&tx->dqo_compl.hw_tx_head, 0);
+
+ /* Queue sizes must be a power of 2 */
+ tx->mask = priv->tx_desc_cnt - 1;
+ tx->dqo.complq_mask = priv->options_dqo_rda.tx_comp_ring_entries - 1;
+
+ /* The max number of pending packets determines the maximum number of
+ * descriptors which maybe written to the completion queue.
+ *
+ * We must set the number small enough to make sure we never overrun the
+ * completion queue.
+ */
+ num_pending_packets = tx->dqo.complq_mask + 1;
+
+ /* Reserve space for descriptor completions, which will be reported at
+ * most every GVE_TX_MIN_RE_INTERVAL packets.
+ */
+ num_pending_packets -=
+ (tx->dqo.complq_mask + 1) / GVE_TX_MIN_RE_INTERVAL;
+
+ /* Each packet may have at most 2 buffer completions if it receives both
+ * a miss and reinjection completion.
+ */
+ num_pending_packets /= 2;
+
+ tx->dqo.num_pending_packets = min_t(int, num_pending_packets, S16_MAX);
+ tx->dqo.pending_packets = kvcalloc(tx->dqo.num_pending_packets,
+ sizeof(tx->dqo.pending_packets[0]),
+ GFP_KERNEL);
+ if (!tx->dqo.pending_packets)
+ goto err;
+
+ /* Set up linked list of pending packets */
+ for (i = 0; i < tx->dqo.num_pending_packets - 1; i++)
+ tx->dqo.pending_packets[i].next = i + 1;
+
+ tx->dqo.pending_packets[tx->dqo.num_pending_packets - 1].next = -1;
+ atomic_set_release(&tx->dqo_compl.free_pending_packets, -1);
+ tx->dqo_compl.miss_completions.head = -1;
+ tx->dqo_compl.miss_completions.tail = -1;
+ tx->dqo_compl.timed_out_completions.head = -1;
+ tx->dqo_compl.timed_out_completions.tail = -1;
+
+ bytes = sizeof(tx->dqo.tx_ring[0]) * (tx->mask + 1);
+ tx->dqo.tx_ring = dma_alloc_coherent(hdev, bytes, &tx->bus, GFP_KERNEL);
+ if (!tx->dqo.tx_ring)
+ goto err;
+
+ bytes = sizeof(tx->dqo.compl_ring[0]) * (tx->dqo.complq_mask + 1);
+ tx->dqo.compl_ring = dma_alloc_coherent(hdev, bytes,
+ &tx->complq_bus_dqo,
+ GFP_KERNEL);
+ if (!tx->dqo.compl_ring)
+ goto err;
+
+ tx->q_resources = dma_alloc_coherent(hdev, sizeof(*tx->q_resources),
+ &tx->q_resources_bus, GFP_KERNEL);
+ if (!tx->q_resources)
+ goto err;
+
+ gve_tx_add_to_block(priv, idx);
+
+ return 0;
+
+err:
+ gve_tx_free_ring_dqo(priv, idx);
+ return -ENOMEM;
+}
+
+int gve_tx_alloc_rings_dqo(struct gve_priv *priv)
+{
+ int err = 0;
+ int i;
+
+ for (i = 0; i < priv->tx_cfg.num_queues; i++) {
+ err = gve_tx_alloc_ring_dqo(priv, i);
+ if (err) {
+ netif_err(priv, drv, priv->dev,
+ "Failed to alloc tx ring=%d: err=%d\n",
+ i, err);
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ for (i--; i >= 0; i--)
+ gve_tx_free_ring_dqo(priv, i);
+
+ return err;
+}
+
+void gve_tx_free_rings_dqo(struct gve_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->tx_cfg.num_queues; i++) {
+ struct gve_tx_ring *tx = &priv->tx[i];
+
+ gve_clean_tx_done_dqo(priv, tx, /*napi=*/NULL);
+ netdev_tx_reset_queue(tx->netdev_txq);
+ gve_tx_clean_pending_packets(tx);
+
+ gve_tx_free_ring_dqo(priv, i);
+ }
+}
+
+/* Returns the number of slots available in the ring */
+static u32 num_avail_tx_slots(const struct gve_tx_ring *tx)
+{
+ u32 num_used = (tx->dqo_tx.tail - tx->dqo_tx.head) & tx->mask;
+
+ return tx->mask - num_used;
+}
+
+/* Stops the queue if available descriptors is less than 'count'.
+ * Return: 0 if stop is not required.
+ */
+static int gve_maybe_stop_tx_dqo(struct gve_tx_ring *tx, int count)
+{
+ if (likely(gve_has_pending_packet(tx) &&
+ num_avail_tx_slots(tx) >= count))
+ return 0;
+
+ /* Update cached TX head pointer */
+ tx->dqo_tx.head = atomic_read_acquire(&tx->dqo_compl.hw_tx_head);
+
+ if (likely(gve_has_pending_packet(tx) &&
+ num_avail_tx_slots(tx) >= count))
+ return 0;
+
+ /* No space, so stop the queue */
+ tx->stop_queue++;
+ netif_tx_stop_queue(tx->netdev_txq);
+
+ /* Sync with restarting queue in `gve_tx_poll_dqo()` */
+ mb();
+
+ /* After stopping queue, check if we can transmit again in order to
+ * avoid TOCTOU bug.
+ */
+ tx->dqo_tx.head = atomic_read_acquire(&tx->dqo_compl.hw_tx_head);
+
+ if (likely(!gve_has_pending_packet(tx) ||
+ num_avail_tx_slots(tx) < count))
+ return -EBUSY;
+
+ netif_tx_start_queue(tx->netdev_txq);
+ tx->wake_queue++;
+ return 0;
+}
+
+static void gve_extract_tx_metadata_dqo(const struct sk_buff *skb,
+ struct gve_tx_metadata_dqo *metadata)
+{
+ memset(metadata, 0, sizeof(*metadata));
+ metadata->version = GVE_TX_METADATA_VERSION_DQO;
+
+ if (skb->l4_hash) {
+ u16 path_hash = skb->hash ^ (skb->hash >> 16);
+
+ path_hash &= (1 << 15) - 1;
+ if (unlikely(path_hash == 0))
+ path_hash = ~path_hash;
+
+ metadata->path_hash = path_hash;
+ }
+}
+
+static void gve_tx_fill_pkt_desc_dqo(struct gve_tx_ring *tx, u32 *desc_idx,
+ struct sk_buff *skb, u32 len, u64 addr,
+ s16 compl_tag, bool eop, bool is_gso)
+{
+ const bool checksum_offload_en = skb->ip_summed == CHECKSUM_PARTIAL;
+
+ while (len > 0) {
+ struct gve_tx_pkt_desc_dqo *desc =
+ &tx->dqo.tx_ring[*desc_idx].pkt;
+ u32 cur_len = min_t(u32, len, GVE_TX_MAX_BUF_SIZE_DQO);
+ bool cur_eop = eop && cur_len == len;
+
+ *desc = (struct gve_tx_pkt_desc_dqo){
+ .buf_addr = cpu_to_le64(addr),
+ .dtype = GVE_TX_PKT_DESC_DTYPE_DQO,
+ .end_of_packet = cur_eop,
+ .checksum_offload_enable = checksum_offload_en,
+ .compl_tag = cpu_to_le16(compl_tag),
+ .buf_size = cur_len,
+ };
+
+ addr += cur_len;
+ len -= cur_len;
+ *desc_idx = (*desc_idx + 1) & tx->mask;
+ }
+}
+
+/* Validates and prepares `skb` for TSO.
+ *
+ * Returns header length, or < 0 if invalid.
+ */
+static int gve_prep_tso(struct sk_buff *skb)
+{
+ struct tcphdr *tcp;
+ int header_len;
+ u32 paylen;
+ int err;
+
+ /* Note: HW requires MSS (gso_size) to be <= 9728 and the total length
+ * of the TSO to be <= 262143.
+ *
+ * However, we don't validate these because:
+ * - Hypervisor enforces a limit of 9K MTU
+ * - Kernel will not produce a TSO larger than 64k
+ */
+
+ if (unlikely(skb_shinfo(skb)->gso_size < GVE_TX_MIN_TSO_MSS_DQO))
+ return -1;
+
+ /* Needed because we will modify header. */
+ err = skb_cow_head(skb, 0);
+ if (err < 0)
+ return err;
+
+ tcp = tcp_hdr(skb);
+
+ /* Remove payload length from checksum. */
+ paylen = skb->len - skb_transport_offset(skb);
+
+ switch (skb_shinfo(skb)->gso_type) {
+ case SKB_GSO_TCPV4:
+ case SKB_GSO_TCPV6:
+ csum_replace_by_diff(&tcp->check,
+ (__force __wsum)htonl(paylen));
+
+ /* Compute length of segmentation header. */
+ header_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (unlikely(header_len > GVE_TX_MAX_HDR_SIZE_DQO))
+ return -EINVAL;
+
+ return header_len;
+}
+
+static void gve_tx_fill_tso_ctx_desc(struct gve_tx_tso_context_desc_dqo *desc,
+ const struct sk_buff *skb,
+ const struct gve_tx_metadata_dqo *metadata,
+ int header_len)
+{
+ *desc = (struct gve_tx_tso_context_desc_dqo){
+ .header_len = header_len,
+ .cmd_dtype = {
+ .dtype = GVE_TX_TSO_CTX_DESC_DTYPE_DQO,
+ .tso = 1,
+ },
+ .flex0 = metadata->bytes[0],
+ .flex5 = metadata->bytes[5],
+ .flex6 = metadata->bytes[6],
+ .flex7 = metadata->bytes[7],
+ .flex8 = metadata->bytes[8],
+ .flex9 = metadata->bytes[9],
+ .flex10 = metadata->bytes[10],
+ .flex11 = metadata->bytes[11],
+ };
+ desc->tso_total_len = skb->len - header_len;
+ desc->mss = skb_shinfo(skb)->gso_size;
+}
+
+static void
+gve_tx_fill_general_ctx_desc(struct gve_tx_general_context_desc_dqo *desc,
+ const struct gve_tx_metadata_dqo *metadata)
+{
+ *desc = (struct gve_tx_general_context_desc_dqo){
+ .flex0 = metadata->bytes[0],
+ .flex1 = metadata->bytes[1],
+ .flex2 = metadata->bytes[2],
+ .flex3 = metadata->bytes[3],
+ .flex4 = metadata->bytes[4],
+ .flex5 = metadata->bytes[5],
+ .flex6 = metadata->bytes[6],
+ .flex7 = metadata->bytes[7],
+ .flex8 = metadata->bytes[8],
+ .flex9 = metadata->bytes[9],
+ .flex10 = metadata->bytes[10],
+ .flex11 = metadata->bytes[11],
+ .cmd_dtype = {.dtype = GVE_TX_GENERAL_CTX_DESC_DTYPE_DQO},
+ };
+}
+
+/* Returns 0 on success, or < 0 on error.
+ *
+ * Before this function is called, the caller must ensure
+ * gve_has_pending_packet(tx) returns true.
+ */
+static int gve_tx_add_skb_no_copy_dqo(struct gve_tx_ring *tx,
+ struct sk_buff *skb)
+{
+ const struct skb_shared_info *shinfo = skb_shinfo(skb);
+ const bool is_gso = skb_is_gso(skb);
+ u32 desc_idx = tx->dqo_tx.tail;
+
+ struct gve_tx_pending_packet_dqo *pending_packet;
+ struct gve_tx_metadata_dqo metadata;
+ s16 completion_tag;
+ int i;
+
+ pending_packet = gve_alloc_pending_packet(tx);
+ pending_packet->skb = skb;
+ pending_packet->num_bufs = 0;
+ completion_tag = pending_packet - tx->dqo.pending_packets;
+
+ gve_extract_tx_metadata_dqo(skb, &metadata);
+ if (is_gso) {
+ int header_len = gve_prep_tso(skb);
+
+ if (unlikely(header_len < 0))
+ goto err;
+
+ gve_tx_fill_tso_ctx_desc(&tx->dqo.tx_ring[desc_idx].tso_ctx,
+ skb, &metadata, header_len);
+ desc_idx = (desc_idx + 1) & tx->mask;
+ }
+
+ gve_tx_fill_general_ctx_desc(&tx->dqo.tx_ring[desc_idx].general_ctx,
+ &metadata);
+ desc_idx = (desc_idx + 1) & tx->mask;
+
+ /* Note: HW requires that the size of a non-TSO packet be within the
+ * range of [17, 9728].
+ *
+ * We don't double check because
+ * - We limited `netdev->min_mtu` to ETH_MIN_MTU.
+ * - Hypervisor won't allow MTU larger than 9216.
+ */
+
+ /* Map the linear portion of skb */
+ {
+ struct gve_tx_dma_buf *buf =
+ &pending_packet->bufs[pending_packet->num_bufs];
+ u32 len = skb_headlen(skb);
+ dma_addr_t addr;
+
+ addr = dma_map_single(tx->dev, skb->data, len, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(tx->dev, addr)))
+ goto err;
+
+ dma_unmap_len_set(buf, len, len);
+ dma_unmap_addr_set(buf, dma, addr);
+ ++pending_packet->num_bufs;
+
+ gve_tx_fill_pkt_desc_dqo(tx, &desc_idx, skb, len, addr,
+ completion_tag,
+ /*eop=*/shinfo->nr_frags == 0, is_gso);
+ }
+
+ for (i = 0; i < shinfo->nr_frags; i++) {
+ struct gve_tx_dma_buf *buf =
+ &pending_packet->bufs[pending_packet->num_bufs];
+ const skb_frag_t *frag = &shinfo->frags[i];
+ bool is_eop = i == (shinfo->nr_frags - 1);
+ u32 len = skb_frag_size(frag);
+ dma_addr_t addr;
+
+ addr = skb_frag_dma_map(tx->dev, frag, 0, len, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(tx->dev, addr)))
+ goto err;
+
+ dma_unmap_len_set(buf, len, len);
+ dma_unmap_addr_set(buf, dma, addr);
+ ++pending_packet->num_bufs;
+
+ gve_tx_fill_pkt_desc_dqo(tx, &desc_idx, skb, len, addr,
+ completion_tag, is_eop, is_gso);
+ }
+
+ /* Commit the changes to our state */
+ tx->dqo_tx.tail = desc_idx;
+
+ /* Request a descriptor completion on the last descriptor of the
+ * packet if we are allowed to by the HW enforced interval.
+ */
+ {
+ u32 last_desc_idx = (desc_idx - 1) & tx->mask;
+ u32 last_report_event_interval =
+ (last_desc_idx - tx->dqo_tx.last_re_idx) & tx->mask;
+
+ if (unlikely(last_report_event_interval >=
+ GVE_TX_MIN_RE_INTERVAL)) {
+ tx->dqo.tx_ring[last_desc_idx].pkt.report_event = true;
+ tx->dqo_tx.last_re_idx = last_desc_idx;
+ }
+ }
+
+ return 0;
+
+err:
+ for (i = 0; i < pending_packet->num_bufs; i++) {
+ struct gve_tx_dma_buf *buf = &pending_packet->bufs[i];
+
+ if (i == 0) {
+ dma_unmap_single(tx->dev, dma_unmap_addr(buf, dma),
+ dma_unmap_len(buf, len),
+ DMA_TO_DEVICE);
+ } else {
+ dma_unmap_page(tx->dev, dma_unmap_addr(buf, dma),
+ dma_unmap_len(buf, len), DMA_TO_DEVICE);
+ }
+ }
+
+ pending_packet->skb = NULL;
+ pending_packet->num_bufs = 0;
+ gve_free_pending_packet(tx, pending_packet);
+
+ return -1;
+}
+
+static int gve_num_descs_per_buf(size_t size)
+{
+ return DIV_ROUND_UP(size, GVE_TX_MAX_BUF_SIZE_DQO);
+}
+
+static int gve_num_buffer_descs_needed(const struct sk_buff *skb)
+{
+ const struct skb_shared_info *shinfo = skb_shinfo(skb);
+ int num_descs;
+ int i;
+
+ num_descs = gve_num_descs_per_buf(skb_headlen(skb));
+
+ for (i = 0; i < shinfo->nr_frags; i++) {
+ unsigned int frag_size = skb_frag_size(&shinfo->frags[i]);
+
+ num_descs += gve_num_descs_per_buf(frag_size);
+ }
+
+ return num_descs;
+}
+
+/* Returns true if HW is capable of sending TSO represented by `skb`.
+ *
+ * Each segment must not span more than GVE_TX_MAX_DATA_DESCS buffers.
+ * - The header is counted as one buffer for every single segment.
+ * - A buffer which is split between two segments is counted for both.
+ * - If a buffer contains both header and payload, it is counted as two buffers.
+ */
+static bool gve_can_send_tso(const struct sk_buff *skb)
+{
+ const int header_len = skb_checksum_start_offset(skb) + tcp_hdrlen(skb);
+ const int max_bufs_per_seg = GVE_TX_MAX_DATA_DESCS - 1;
+ const struct skb_shared_info *shinfo = skb_shinfo(skb);
+ const int gso_size = shinfo->gso_size;
+ int cur_seg_num_bufs;
+ int cur_seg_size;
+ int i;
+
+ cur_seg_size = skb_headlen(skb) - header_len;
+ cur_seg_num_bufs = cur_seg_size > 0;
+
+ for (i = 0; i < shinfo->nr_frags; i++) {
+ if (cur_seg_size >= gso_size) {
+ cur_seg_size %= gso_size;
+ cur_seg_num_bufs = cur_seg_size > 0;
+ }
+
+ if (unlikely(++cur_seg_num_bufs > max_bufs_per_seg))
+ return false;
+
+ cur_seg_size += skb_frag_size(&shinfo->frags[i]);
+ }
+
+ return true;
+}
+
+/* Attempt to transmit specified SKB.
+ *
+ * Returns 0 if the SKB was transmitted or dropped.
+ * Returns -1 if there is not currently enough space to transmit the SKB.
+ */
+static int gve_try_tx_skb(struct gve_priv *priv, struct gve_tx_ring *tx,
+ struct sk_buff *skb)
+{
+ int num_buffer_descs;
+ int total_num_descs;
+
+ if (skb_is_gso(skb)) {
+ /* If TSO doesn't meet HW requirements, attempt to linearize the
+ * packet.
+ */
+ if (unlikely(!gve_can_send_tso(skb) &&
+ skb_linearize(skb) < 0)) {
+ net_err_ratelimited("%s: Failed to transmit TSO packet\n",
+ priv->dev->name);
+ goto drop;
+ }
+
+ num_buffer_descs = gve_num_buffer_descs_needed(skb);
+ } else {
+ num_buffer_descs = gve_num_buffer_descs_needed(skb);
+
+ if (unlikely(num_buffer_descs > GVE_TX_MAX_DATA_DESCS)) {
+ if (unlikely(skb_linearize(skb) < 0))
+ goto drop;
+
+ num_buffer_descs = 1;
+ }
+ }
+
+ /* Metadata + (optional TSO) + data descriptors. */
+ total_num_descs = 1 + skb_is_gso(skb) + num_buffer_descs;
+ if (unlikely(gve_maybe_stop_tx_dqo(tx, total_num_descs +
+ GVE_TX_MIN_DESC_PREVENT_CACHE_OVERLAP))) {
+ return -1;
+ }
+
+ if (unlikely(gve_tx_add_skb_no_copy_dqo(tx, skb) < 0))
+ goto drop;
+
+ netdev_tx_sent_queue(tx->netdev_txq, skb->len);
+ skb_tx_timestamp(skb);
+ return 0;
+
+drop:
+ tx->dropped_pkt++;
+ dev_kfree_skb_any(skb);
+ return 0;
+}
+
+/* Transmit a given skb and ring the doorbell. */
+netdev_tx_t gve_tx_dqo(struct sk_buff *skb, struct net_device *dev)
+{
+ struct gve_priv *priv = netdev_priv(dev);
+ struct gve_tx_ring *tx;
+
+ tx = &priv->tx[skb_get_queue_mapping(skb)];
+ if (unlikely(gve_try_tx_skb(priv, tx, skb) < 0)) {
+ /* 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.
+ */
+ gve_tx_put_doorbell_dqo(priv, tx->q_resources, tx->dqo_tx.tail);
+ return NETDEV_TX_BUSY;
+ }
+
+ if (!netif_xmit_stopped(tx->netdev_txq) && netdev_xmit_more())
+ return NETDEV_TX_OK;
+
+ gve_tx_put_doorbell_dqo(priv, tx->q_resources, tx->dqo_tx.tail);
+ return NETDEV_TX_OK;
+}
+
+static void add_to_list(struct gve_tx_ring *tx, struct gve_index_list *list,
+ struct gve_tx_pending_packet_dqo *pending_packet)
+{
+ s16 old_tail, index;
+
+ index = pending_packet - tx->dqo.pending_packets;
+ old_tail = list->tail;
+ list->tail = index;
+ if (old_tail == -1)
+ list->head = index;
+ else
+ tx->dqo.pending_packets[old_tail].next = index;
+
+ pending_packet->next = -1;
+ pending_packet->prev = old_tail;
+}
+
+static void remove_from_list(struct gve_tx_ring *tx,
+ struct gve_index_list *list,
+ struct gve_tx_pending_packet_dqo *pending_packet)
+{
+ s16 prev_index, next_index;
+
+ prev_index = pending_packet->prev;
+ next_index = pending_packet->next;
+
+ if (prev_index == -1) {
+ /* Node is head */
+ list->head = next_index;
+ } else {
+ tx->dqo.pending_packets[prev_index].next = next_index;
+ }
+ if (next_index == -1) {
+ /* Node is tail */
+ list->tail = prev_index;
+ } else {
+ tx->dqo.pending_packets[next_index].prev = prev_index;
+ }
+}
+
+static void gve_unmap_packet(struct device *dev,
+ struct gve_tx_pending_packet_dqo *pending_packet)
+{
+ struct gve_tx_dma_buf *buf;
+ int i;
+
+ /* SKB linear portion is guaranteed to be mapped */
+ buf = &pending_packet->bufs[0];
+ dma_unmap_single(dev, dma_unmap_addr(buf, dma),
+ dma_unmap_len(buf, len), DMA_TO_DEVICE);
+ for (i = 1; i < pending_packet->num_bufs; i++) {
+ buf = &pending_packet->bufs[i];
+ dma_unmap_page(dev, dma_unmap_addr(buf, dma),
+ dma_unmap_len(buf, len), DMA_TO_DEVICE);
+ }
+ pending_packet->num_bufs = 0;
+}
+
+/* Completion types and expected behavior:
+ * No Miss compl + Packet compl = Packet completed normally.
+ * Miss compl + Re-inject compl = Packet completed normally.
+ * No Miss compl + Re-inject compl = Skipped i.e. packet not completed.
+ * Miss compl + Packet compl = Skipped i.e. packet not completed.
+ */
+static void gve_handle_packet_completion(struct gve_priv *priv,
+ struct gve_tx_ring *tx, bool is_napi,
+ u16 compl_tag, u64 *bytes, u64 *pkts,
+ bool is_reinjection)
+{
+ struct gve_tx_pending_packet_dqo *pending_packet;
+
+ if (unlikely(compl_tag >= tx->dqo.num_pending_packets)) {
+ net_err_ratelimited("%s: Invalid TX completion tag: %d\n",
+ priv->dev->name, (int)compl_tag);
+ return;
+ }
+
+ pending_packet = &tx->dqo.pending_packets[compl_tag];
+
+ if (unlikely(is_reinjection)) {
+ if (unlikely(pending_packet->state ==
+ GVE_PACKET_STATE_TIMED_OUT_COMPL)) {
+ net_err_ratelimited("%s: Re-injection completion: %d received after timeout.\n",
+ priv->dev->name, (int)compl_tag);
+ /* Packet was already completed as a result of timeout,
+ * so just remove from list and free pending packet.
+ */
+ remove_from_list(tx,
+ &tx->dqo_compl.timed_out_completions,
+ pending_packet);
+ gve_free_pending_packet(tx, pending_packet);
+ return;
+ }
+ if (unlikely(pending_packet->state !=
+ GVE_PACKET_STATE_PENDING_REINJECT_COMPL)) {
+ /* No outstanding miss completion but packet allocated
+ * implies packet receives a re-injection completion
+ * without a a prior miss completion. Return without
+ * completing the packet.
+ */
+ net_err_ratelimited("%s: Re-injection completion received without corresponding miss completion: %d\n",
+ priv->dev->name, (int)compl_tag);
+ return;
+ }
+ remove_from_list(tx, &tx->dqo_compl.miss_completions,
+ pending_packet);
+ } else {
+ /* Packet is allocated but not a pending data completion. */
+ if (unlikely(pending_packet->state !=
+ GVE_PACKET_STATE_PENDING_DATA_COMPL)) {
+ net_err_ratelimited("%s: No pending data completion: %d\n",
+ priv->dev->name, (int)compl_tag);
+ return;
+ }
+ }
+ gve_unmap_packet(tx->dev, pending_packet);
+
+ *bytes += pending_packet->skb->len;
+ (*pkts)++;
+ napi_consume_skb(pending_packet->skb, is_napi);
+ pending_packet->skb = NULL;
+ gve_free_pending_packet(tx, pending_packet);
+}
+
+static void gve_handle_miss_completion(struct gve_priv *priv,
+ struct gve_tx_ring *tx, u16 compl_tag,
+ u64 *bytes, u64 *pkts)
+{
+ struct gve_tx_pending_packet_dqo *pending_packet;
+
+ if (unlikely(compl_tag >= tx->dqo.num_pending_packets)) {
+ net_err_ratelimited("%s: Invalid TX completion tag: %d\n",
+ priv->dev->name, (int)compl_tag);
+ return;
+ }
+
+ pending_packet = &tx->dqo.pending_packets[compl_tag];
+ if (unlikely(pending_packet->state !=
+ GVE_PACKET_STATE_PENDING_DATA_COMPL)) {
+ net_err_ratelimited("%s: Unexpected packet state: %d for completion tag : %d\n",
+ priv->dev->name, (int)pending_packet->state,
+ (int)compl_tag);
+ return;
+ }
+
+ pending_packet->state = GVE_PACKET_STATE_PENDING_REINJECT_COMPL;
+ /* jiffies can wraparound but time comparisons can handle overflows. */
+ pending_packet->timeout_jiffies =
+ jiffies +
+ msecs_to_jiffies(GVE_REINJECT_COMPL_TIMEOUT *
+ MSEC_PER_SEC);
+ add_to_list(tx, &tx->dqo_compl.miss_completions, pending_packet);
+
+ *bytes += pending_packet->skb->len;
+ (*pkts)++;
+}
+
+static void remove_miss_completions(struct gve_priv *priv,
+ struct gve_tx_ring *tx)
+{
+ struct gve_tx_pending_packet_dqo *pending_packet;
+ s16 next_index;
+
+ next_index = tx->dqo_compl.miss_completions.head;
+ while (next_index != -1) {
+ pending_packet = &tx->dqo.pending_packets[next_index];
+ next_index = pending_packet->next;
+ /* Break early because packets should timeout in order. */
+ if (time_is_after_jiffies(pending_packet->timeout_jiffies))
+ break;
+
+ remove_from_list(tx, &tx->dqo_compl.miss_completions,
+ pending_packet);
+ /* Unmap buffers and free skb but do not unallocate packet i.e.
+ * the completion tag is not freed to ensure that the driver
+ * can take appropriate action if a corresponding valid
+ * completion is received later.
+ */
+ gve_unmap_packet(tx->dev, pending_packet);
+ /* This indicates the packet was dropped. */
+ dev_kfree_skb_any(pending_packet->skb);
+ pending_packet->skb = NULL;
+ tx->dropped_pkt++;
+ net_err_ratelimited("%s: No reinjection completion was received for: %d.\n",
+ priv->dev->name,
+ (int)(pending_packet - tx->dqo.pending_packets));
+
+ pending_packet->state = GVE_PACKET_STATE_TIMED_OUT_COMPL;
+ pending_packet->timeout_jiffies =
+ jiffies +
+ msecs_to_jiffies(GVE_DEALLOCATE_COMPL_TIMEOUT *
+ MSEC_PER_SEC);
+ /* Maintain pending packet in another list so the packet can be
+ * unallocated at a later time.
+ */
+ add_to_list(tx, &tx->dqo_compl.timed_out_completions,
+ pending_packet);
+ }
+}
+
+static void remove_timed_out_completions(struct gve_priv *priv,
+ struct gve_tx_ring *tx)
+{
+ struct gve_tx_pending_packet_dqo *pending_packet;
+ s16 next_index;
+
+ next_index = tx->dqo_compl.timed_out_completions.head;
+ while (next_index != -1) {
+ pending_packet = &tx->dqo.pending_packets[next_index];
+ next_index = pending_packet->next;
+ /* Break early because packets should timeout in order. */
+ if (time_is_after_jiffies(pending_packet->timeout_jiffies))
+ break;
+
+ remove_from_list(tx, &tx->dqo_compl.timed_out_completions,
+ pending_packet);
+ gve_free_pending_packet(tx, pending_packet);
+ }
+}
+
+int gve_clean_tx_done_dqo(struct gve_priv *priv, struct gve_tx_ring *tx,
+ struct napi_struct *napi)
+{
+ u64 reinject_compl_bytes = 0;
+ u64 reinject_compl_pkts = 0;
+ int num_descs_cleaned = 0;
+ u64 miss_compl_bytes = 0;
+ u64 miss_compl_pkts = 0;
+ u64 pkt_compl_bytes = 0;
+ u64 pkt_compl_pkts = 0;
+
+ /* Limit in order to avoid blocking for too long */
+ while (!napi || pkt_compl_pkts < napi->weight) {
+ struct gve_tx_compl_desc *compl_desc =
+ &tx->dqo.compl_ring[tx->dqo_compl.head];
+ u16 type;
+
+ if (compl_desc->generation == tx->dqo_compl.cur_gen_bit)
+ break;
+
+ /* Prefetch the next descriptor. */
+ prefetch(&tx->dqo.compl_ring[(tx->dqo_compl.head + 1) &
+ tx->dqo.complq_mask]);
+
+ /* Do not read data until we own the descriptor */
+ dma_rmb();
+ type = compl_desc->type;
+
+ if (type == GVE_COMPL_TYPE_DQO_DESC) {
+ /* This is the last descriptor fetched by HW plus one */
+ u16 tx_head = le16_to_cpu(compl_desc->tx_head);
+
+ atomic_set_release(&tx->dqo_compl.hw_tx_head, tx_head);
+ } else if (type == GVE_COMPL_TYPE_DQO_PKT) {
+ u16 compl_tag = le16_to_cpu(compl_desc->completion_tag);
+
+ gve_handle_packet_completion(priv, tx, !!napi,
+ compl_tag,
+ &pkt_compl_bytes,
+ &pkt_compl_pkts,
+ /*is_reinjection=*/false);
+ } else if (type == GVE_COMPL_TYPE_DQO_MISS) {
+ u16 compl_tag = le16_to_cpu(compl_desc->completion_tag);
+
+ gve_handle_miss_completion(priv, tx, compl_tag,
+ &miss_compl_bytes,
+ &miss_compl_pkts);
+ } else if (type == GVE_COMPL_TYPE_DQO_REINJECTION) {
+ u16 compl_tag = le16_to_cpu(compl_desc->completion_tag);
+
+ gve_handle_packet_completion(priv, tx, !!napi,
+ compl_tag,
+ &reinject_compl_bytes,
+ &reinject_compl_pkts,
+ /*is_reinjection=*/true);
+ }
+
+ tx->dqo_compl.head =
+ (tx->dqo_compl.head + 1) & tx->dqo.complq_mask;
+ /* Flip the generation bit when we wrap around */
+ tx->dqo_compl.cur_gen_bit ^= tx->dqo_compl.head == 0;
+ num_descs_cleaned++;
+ }
+
+ netdev_tx_completed_queue(tx->netdev_txq,
+ pkt_compl_pkts + miss_compl_pkts,
+ pkt_compl_bytes + miss_compl_bytes);
+
+ remove_miss_completions(priv, tx);
+ remove_timed_out_completions(priv, tx);
+
+ u64_stats_update_begin(&tx->statss);
+ tx->bytes_done += pkt_compl_bytes + reinject_compl_bytes;
+ tx->pkt_done += pkt_compl_pkts + reinject_compl_pkts;
+ u64_stats_update_end(&tx->statss);
+ return num_descs_cleaned;
+}
+
+bool gve_tx_poll_dqo(struct gve_notify_block *block, bool do_clean)
+{
+ struct gve_tx_compl_desc *compl_desc;
+ struct gve_tx_ring *tx = block->tx;
+ struct gve_priv *priv = block->priv;
+
+ if (do_clean) {
+ int num_descs_cleaned = gve_clean_tx_done_dqo(priv, tx,
+ &block->napi);
+
+ /* Sync with queue being stopped in `gve_maybe_stop_tx_dqo()` */
+ mb();
+
+ if (netif_tx_queue_stopped(tx->netdev_txq) &&
+ num_descs_cleaned > 0) {
+ tx->wake_queue++;
+ netif_tx_wake_queue(tx->netdev_txq);
+ }
+ }
+
+ /* Return true if we still have work. */
+ compl_desc = &tx->dqo.compl_ring[tx->dqo_compl.head];
+ return compl_desc->generation != tx->dqo_compl.cur_gen_bit;
+}
diff --git a/drivers/net/ethernet/google/gve/gve_utils.c b/drivers/net/ethernet/google/gve/gve_utils.c
new file mode 100644
index 000000000000..93f3dcbeeea9
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve_utils.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2021 Google, Inc.
+ */
+
+#include "gve.h"
+#include "gve_adminq.h"
+#include "gve_utils.h"
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi,
+ struct gve_rx_slot_page_info *page_info, u16 len,
+ u16 pad)
+{
+ struct sk_buff *skb = napi_alloc_skb(napi, len);
+ void *va = page_info->page_address + 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;
+}
+
+void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info)
+{
+ page_info->pagecnt_bias--;
+ if (page_info->pagecnt_bias == 0) {
+ int pagecount = page_count(page_info->page);
+
+ /* If we have run out of bias - set it back up to INT_MAX
+ * minus the existing refs.
+ */
+ page_info->pagecnt_bias = INT_MAX - pagecount;
+
+ /* Set pagecount back up to max. */
+ page_ref_add(page_info->page, INT_MAX - pagecount);
+ }
+}
diff --git a/drivers/net/ethernet/google/gve/gve_utils.h b/drivers/net/ethernet/google/gve/gve_utils.h
new file mode 100644
index 000000000000..79595940b351
--- /dev/null
+++ b/drivers/net/ethernet/google/gve/gve_utils.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ * Google virtual Ethernet (gve) driver
+ *
+ * Copyright (C) 2015-2021 Google, Inc.
+ */
+
+#ifndef _GVE_UTILS_H
+#define _GVE_UTILS_H
+
+#include <linux/etherdevice.h>
+
+#include "gve.h"
+
+void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx);
+void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx);
+
+void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx);
+void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx);
+
+struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi,
+ struct gve_rx_slot_page_info *page_info, u16 len,
+ u16 pad);
+
+/* Decrement pagecnt_bias. Set it back to INT_MAX if it reached zero. */
+void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info);
+
+#endif /* _GVE_UTILS_H */
+
diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig
index 44f9279cdde1..bb062b02fb85 100644
--- a/drivers/net/ethernet/hisilicon/Kconfig
+++ b/drivers/net/ethernet/hisilicon/Kconfig
@@ -102,6 +102,7 @@ config HNS3_HCLGE
tristate "Hisilicon HNS3 HCLGE Acceleration Engine & Compatibility Layer Support"
default m
depends on PCI_MSI
+ imply PTP_1588_CLOCK
help
This selects the HNS3_HCLGE network acceleration engine & its hardware
compatibility layer. The engine would be used in Hisilicon hip08 family of
@@ -130,6 +131,7 @@ config HNS3_ENET
default m
depends on 64BIT && PCI
depends on INET
+ select DIMLIB
help
This selects the Ethernet Driver for Hisilicon Network Subsystem 3 for hip08
family of SoCs. This module depends upon HNAE3 driver to access the HNAE3
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
index c615fbf9094e..75e4ec569da8 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
@@ -462,8 +462,6 @@ static void hns_ae_adjust_link(struct hnae_handle *handle, int speed,
default:
break;
}
-
- return;
}
static void hns_ae_get_ring_bdnum_limit(struct hnae_queue *queue,
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
index f4cf569a2599..f41379de2186 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
@@ -111,7 +111,7 @@ int hns_mac_get_port_info(struct hns_mac_cb *mac_cb,
}
/**
- *hns_mac_is_adjust_link - check is need change mac speed and duplex register
+ *hns_mac_need_adjust_link - check is need change mac speed and duplex register
*@mac_cb: mac device
*@speed: phy device speed
*@duplex:phy device duplex
@@ -374,7 +374,7 @@ static void hns_mac_param_get(struct mac_params *param,
}
/**
- * hns_mac_queue_config_bc_en - set broadcast rx&tx enable
+ * hns_mac_port_config_bc_en - set broadcast rx&tx enable
* @mac_cb: mac device
* @port_num: queue number
* @vlan_id: vlan id`
@@ -597,7 +597,7 @@ int hns_mac_set_autoneg(struct hns_mac_cb *mac_cb, u8 enable)
}
/**
- * hns_mac_set_autoneg - set rx & tx pause parameter
+ * hns_mac_set_pauseparam - set rx & tx pause parameter
* @mac_cb: mac control block
* @rx_en: rx enable or not
* @tx_en: tx enable or not
@@ -914,8 +914,7 @@ static int hns_mac_get_info(struct hns_mac_cb *mac_cb)
}
} else if (is_acpi_node(mac_cb->fw_port)) {
ret = hns_mac_register_phy(mac_cb);
- /*
- * Mac can work well if there is phy or not.If the port don't
+ /* Mac can work well if there is phy or not.If the port don't
* connect with phy, the return value will be ignored. Only
* when there is phy but can't find mdio bus, the return value
* will be handled.
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
index c2a60612f503..fcaf5132b865 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
@@ -227,7 +227,7 @@ hns_dsaf_reg_cnt_clr_ce(struct dsaf_device *dsaf_dev, u32 reg_cnt_clr_ce)
}
/**
- * hns_ppe_qid_cfg - config ppe qid
+ * hns_dsaf_ppe_qid_cfg - config ppe qid
* @dsaf_dev: dsa fabric id
* @qid_cfg: value array
*/
@@ -613,7 +613,7 @@ static void hns_dsaf_tbl_tcam_data_cfg(
}
/**
- * dsaf_tbl_tcam_mcast_cfg - tbl
+ * hns_dsaf_tbl_tcam_mcast_cfg - tbl
* @dsaf_dev: dsa fabric id
* @mcast: addr
*/
@@ -1213,7 +1213,7 @@ void hns_dsaf_get_rx_mac_pause_en(struct dsaf_device *dsaf_dev, int mac_id,
}
/**
- * hns_dsaf_tbl_tcam_init - INT
+ * hns_dsaf_comm_init - INT
* @dsaf_dev: dsa fabric id
*/
static void hns_dsaf_comm_init(struct dsaf_device *dsaf_dev)
@@ -2111,7 +2111,7 @@ static void hns_dsaf_free_dev(struct dsaf_device *dsaf_dev)
}
/**
- * dsaf_pfc_unit_cnt - set pfc unit count
+ * hns_dsaf_pfc_unit_cnt - set pfc unit count
* @dsaf_dev: dsa fabric id
* @mac_id: id in use
* @rate: value array
@@ -2142,7 +2142,7 @@ static void hns_dsaf_pfc_unit_cnt(struct dsaf_device *dsaf_dev, int mac_id,
}
/**
- * dsaf_port_work_rate_cfg - fifo
+ * hns_dsaf_port_work_rate_cfg - fifo
* @dsaf_dev: dsa fabric id
* @mac_id: mac contrl block
* @rate_mode: value array
@@ -2738,7 +2738,7 @@ void hns_dsaf_get_strings(int stringset, u8 *data, int port,
}
/**
- *hns_dsaf_get_sset_count - get dsaf regs count
+ *hns_dsaf_get_regs_count - get dsaf regs count
*return dsaf regs count
*/
int hns_dsaf_get_regs_count(void)
@@ -2949,7 +2949,7 @@ int hns_dsaf_wait_pkt_clean(struct dsaf_device *dsaf_dev, int port)
}
/**
- * dsaf_probe - probo dsaf dev
+ * hns_dsaf_probe - probo dsaf dev
* @pdev: dasf platform device
* return 0 - success , negative --fail
*/
@@ -3004,7 +3004,7 @@ free_dev:
}
/**
- * dsaf_remove - remove dsaf dev
+ * hns_dsaf_remove - remove dsaf dev
* @pdev: dasf platform device
*/
static int hns_dsaf_remove(struct platform_device *pdev)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
index 325e81d30cfd..23d9cbf262c3 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c
@@ -56,31 +56,31 @@ static u32 dsaf_read_sub(struct dsaf_device *dsaf_dev, u32 reg)
}
static void hns_dsaf_acpi_ledctrl_by_port(struct hns_mac_cb *mac_cb, u8 op_type,
- u32 link, u32 port, u32 act)
+ u32 link, u32 port, u32 act)
{
- union acpi_object *obj;
- union acpi_object obj_args[3], argv4;
+ union acpi_object *obj;
+ union acpi_object obj_args[3], argv4;
- obj_args[0].integer.type = ACPI_TYPE_INTEGER;
- obj_args[0].integer.value = link;
- obj_args[1].integer.type = ACPI_TYPE_INTEGER;
- obj_args[1].integer.value = port;
- obj_args[2].integer.type = ACPI_TYPE_INTEGER;
- obj_args[2].integer.value = act;
+ obj_args[0].integer.type = ACPI_TYPE_INTEGER;
+ obj_args[0].integer.value = link;
+ obj_args[1].integer.type = ACPI_TYPE_INTEGER;
+ obj_args[1].integer.value = port;
+ obj_args[2].integer.type = ACPI_TYPE_INTEGER;
+ obj_args[2].integer.value = act;
- argv4.type = ACPI_TYPE_PACKAGE;
- argv4.package.count = 3;
- argv4.package.elements = obj_args;
+ argv4.type = ACPI_TYPE_PACKAGE;
+ argv4.package.count = 3;
+ argv4.package.elements = obj_args;
- obj = acpi_evaluate_dsm(ACPI_HANDLE(mac_cb->dev),
- &hns_dsaf_acpi_dsm_guid, 0, op_type, &argv4);
- if (!obj) {
- dev_warn(mac_cb->dev, "ledctrl fail, link:%d port:%d act:%d!\n",
- link, port, act);
- return;
- }
+ obj = acpi_evaluate_dsm(ACPI_HANDLE(mac_cb->dev),
+ &hns_dsaf_acpi_dsm_guid, 0, op_type, &argv4);
+ if (!obj) {
+ dev_warn(mac_cb->dev, "ledctrl fail, link:%d port:%d act:%d!\n",
+ link, port, act);
+ return;
+ }
- ACPI_FREE(obj);
+ ACPI_FREE(obj);
}
static void hns_dsaf_acpi_locate_ledctrl_by_port(struct hns_mac_cb *mac_cb,
@@ -151,15 +151,15 @@ static void hns_cpld_set_led(struct hns_mac_cb *mac_cb, int link_status,
}
static void hns_cpld_set_led_acpi(struct hns_mac_cb *mac_cb, int link_status,
- u16 speed, int data)
+ u16 speed, int data)
{
- if (!mac_cb) {
- pr_err("cpld_led_set mac_cb is null!\n");
- return;
- }
+ if (!mac_cb) {
+ pr_err("cpld_led_set mac_cb is null!\n");
+ return;
+ }
- hns_dsaf_acpi_ledctrl_by_port(mac_cb, HNS_OP_LED_SET_FUNC,
- link_status, mac_cb->mac_id, data);
+ hns_dsaf_acpi_ledctrl_by_port(mac_cb, HNS_OP_LED_SET_FUNC,
+ link_status, mac_cb->mac_id, data);
}
static void cpld_led_reset(struct hns_mac_cb *mac_cb)
@@ -174,16 +174,16 @@ static void cpld_led_reset(struct hns_mac_cb *mac_cb)
static void cpld_led_reset_acpi(struct hns_mac_cb *mac_cb)
{
- if (!mac_cb) {
- pr_err("cpld_led_reset mac_cb is null!\n");
- return;
- }
+ if (!mac_cb) {
+ pr_err("cpld_led_reset mac_cb is null!\n");
+ return;
+ }
- if (mac_cb->media_type != HNAE_MEDIA_TYPE_FIBER)
- return;
+ if (mac_cb->media_type != HNAE_MEDIA_TYPE_FIBER)
+ return;
- hns_dsaf_acpi_ledctrl_by_port(mac_cb, HNS_OP_LED_SET_FUNC,
- 0, mac_cb->mac_id, 0);
+ hns_dsaf_acpi_ledctrl_by_port(mac_cb, HNS_OP_LED_SET_FUNC,
+ 0, mac_cb->mac_id, 0);
}
static int cpld_set_led_id(struct hns_mac_cb *mac_cb,
@@ -351,7 +351,7 @@ hns_dsaf_srst_chns(struct dsaf_device *dsaf_dev, u32 msk, bool dereset)
}
/**
- * hns_dsaf_srst_chns - reset dsaf channels
+ * hns_dsaf_srst_chns_acpi - reset dsaf channels
* @dsaf_dev: dsaf device struct pointer
* @msk: xbar channels mask value:
* @dereset: false - request reset , true - drop reset
@@ -501,7 +501,7 @@ static void hns_ppe_com_srst(struct dsaf_device *dsaf_dev, bool dereset)
}
/**
- * hns_mac_get_sds_mode - get phy ifterface form serdes mode
+ * hns_mac_get_phy_if - get phy ifterface form serdes mode
* @mac_cb: mac control block
* retuen phy interface
*/
@@ -521,7 +521,7 @@ static phy_interface_t hns_mac_get_phy_if(struct hns_mac_cb *mac_cb)
reg = HNS_MAC_HILINK4_REG;
else
reg = HNS_MAC_HILINK3_REG;
- } else{
+ } else {
if (!HNS_DSAF_IS_DEBUG(mac_cb->dsaf_dev) && mac_id <= 3)
reg = HNS_MAC_HILINK4V2_REG;
else
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
index ff03cafccb66..a7eb87da4e70 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
@@ -296,7 +296,7 @@ int hns_ppe_wait_tx_fifo_clean(struct hns_ppe_cb *ppe_cb)
}
/**
- * ppe_init_hw - init ppe
+ * hns_ppe_init_hw - init ppe
* @ppe_cb: ppe device
*/
static void hns_ppe_init_hw(struct hns_ppe_cb *ppe_cb)
@@ -343,7 +343,7 @@ static void hns_ppe_init_hw(struct hns_ppe_cb *ppe_cb)
}
/**
- * ppe_uninit_hw - uninit ppe
+ * hns_ppe_uninit_hw - uninit ppe
* @ppe_cb: ppe device
*/
static void hns_ppe_uninit_hw(struct hns_ppe_cb *ppe_cb)
@@ -382,7 +382,7 @@ void hns_ppe_uninit(struct dsaf_device *dsaf_dev)
}
/**
- * hns_ppe_reset - reinit ppe/rcb hw
+ * hns_ppe_reset_common - reinit ppe/rcb hw
* @dsaf_dev: dasf device
* @ppe_common_index: the index
* return void
@@ -455,7 +455,7 @@ int hns_ppe_get_regs_count(void)
}
/**
- * ppe_get_strings - get ppe srting
+ * hns_ppe_get_strings - get ppe srting
* @ppe_cb: ppe device
* @stringset: string set type
* @data: output string
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
index 5d5dc6942232..e2ff3ca198d1 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
@@ -913,7 +913,7 @@ int hns_rcb_get_common_regs_count(void)
}
/**
- *rcb_get_sset_count - rcb ring regs count
+ *hns_rcb_get_ring_regs_count - rcb ring regs count
*return regs count
*/
int hns_rcb_get_ring_regs_count(void)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
index be52acd448f9..401fef5f1d07 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
@@ -104,7 +104,7 @@ static void hns_xgmac_rx_enable(struct mac_driver *drv, u32 value)
}
/**
- * hns_xgmac_tx_lf_rf_insert - insert lf rf control about xgmac
+ * hns_xgmac_lf_rf_insert - insert lf rf control about xgmac
* @mac_drv: mac driver
* @mode: inserf rf or lf
*/
@@ -115,7 +115,7 @@ static void hns_xgmac_lf_rf_insert(struct mac_driver *mac_drv, u32 mode)
}
/**
- * hns_xgmac__lf_rf_control_init - initial the lf rf control register
+ * hns_xgmac_lf_rf_control_init - initial the lf rf control register
* @mac_drv: mac driver
*/
static void hns_xgmac_lf_rf_control_init(struct mac_driver *mac_drv)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
index 5e349c0bdecc..ad534f9e41ab 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -770,7 +770,7 @@ static u32 smooth_alg(u32 new_param, u32 old_param)
}
/**
- * hns_nic_adp_coalesce - self adapte coalesce according to rx rate
+ * hns_nic_adpt_coalesce - self adapte coalesce according to rx rate
* @ring_data: pointer to hns_nic_ring_data
**/
static void hns_nic_adpt_coalesce(struct hns_nic_ring_data *ring_data)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
index a2c17af57fde..0a6cda309b24 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
@@ -20,7 +20,7 @@ enum HCLGE_MBX_OPCODE {
HCLGE_MBX_API_NEGOTIATE, /* (VF -> PF) negotiate API version */
HCLGE_MBX_GET_QINFO, /* (VF -> PF) get queue config */
HCLGE_MBX_GET_QDEPTH, /* (VF -> PF) get queue depth */
- HCLGE_MBX_GET_TCINFO, /* (VF -> PF) get TC config */
+ HCLGE_MBX_GET_BASIC_INFO, /* (VF -> PF) get basic info */
HCLGE_MBX_GET_RETA, /* (VF -> PF) get RETA */
HCLGE_MBX_GET_RSS_KEY, /* (VF -> PF) get RSS key */
HCLGE_MBX_GET_MAC_ADDR, /* (VF -> PF) get MAC addr */
@@ -69,6 +69,7 @@ enum hclge_mbx_vlan_cfg_subcode {
HCLGE_MBX_VLAN_RX_OFF_CFG, /* set rx side vlan offload */
HCLGE_MBX_PORT_BASE_VLAN_CFG, /* set port based vlan configuration */
HCLGE_MBX_GET_PORT_BASE_VLAN_STATE, /* get port based vlan state */
+ HCLGE_MBX_ENABLE_VLAN_FILTER,
};
enum hclge_mbx_tbl_cfg_subcode {
@@ -85,6 +86,13 @@ struct hclge_ring_chain_param {
u8 int_gl_index;
};
+struct hclge_basic_info {
+ u8 hw_tc_map;
+ u8 rsv;
+ u16 mbx_api_version;
+ u32 pf_caps;
+};
+
struct hclgevf_mbx_resp_status {
struct mutex mbx_mutex; /* protects against contending sync cmd resp */
u32 origin_mbx_msg;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
index 1d2189047781..e0b7c3c44e7b 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
@@ -91,6 +91,10 @@ enum HNAE3_DEV_CAP_BITS {
HNAE3_DEV_SUPPORT_STASH_B,
HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B,
HNAE3_DEV_SUPPORT_PAUSE_B,
+ HNAE3_DEV_SUPPORT_RAS_IMP_B,
+ HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B,
+ HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B,
+ HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B,
};
#define hnae3_dev_fd_supported(hdev) \
@@ -126,6 +130,9 @@ enum HNAE3_DEV_CAP_BITS {
#define hnae3_dev_phy_imp_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, (hdev)->ae_dev->caps)
+#define hnae3_dev_ras_imp_supported(hdev) \
+ test_bit(HNAE3_DEV_SUPPORT_RAS_IMP_B, (hdev)->ae_dev->caps)
+
#define hnae3_dev_tqp_txrx_indep_supported(hdev) \
test_bit(HNAE3_DEV_SUPPORT_TQP_TXRX_INDEP_B, (hdev)->ae_dev->caps)
@@ -141,18 +148,17 @@ enum HNAE3_DEV_CAP_BITS {
#define hnae3_ae_dev_tqp_txrx_indep_supported(ae_dev) \
test_bit(HNAE3_DEV_SUPPORT_TQP_TXRX_INDEP_B, (ae_dev)->caps)
+#define hnae3_ae_dev_rxd_adv_layout_supported(ae_dev) \
+ test_bit(HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B, (ae_dev)->caps)
+
+enum HNAE3_PF_CAP_BITS {
+ HNAE3_PF_SUPPORT_VLAN_FLTR_MDF_B = 0,
+};
#define ring_ptr_move_fw(ring, p) \
((ring)->p = ((ring)->p + 1) % (ring)->desc_num)
#define ring_ptr_move_bw(ring, p) \
((ring)->p = ((ring)->p - 1 + (ring)->desc_num) % (ring)->desc_num)
-enum hns_desc_type {
- DESC_TYPE_UNKNOWN,
- DESC_TYPE_SKB,
- DESC_TYPE_FRAGLIST_SKB,
- DESC_TYPE_PAGE,
-};
-
struct hnae3_handle;
struct hnae3_queue {
@@ -234,7 +240,6 @@ enum hnae3_reset_type {
HNAE3_FUNC_RESET,
HNAE3_GLOBAL_RESET,
HNAE3_IMP_RESET,
- HNAE3_UNKNOWN_RESET,
HNAE3_NONE_RESET,
HNAE3_MAX_RESET,
};
@@ -246,6 +251,52 @@ enum hnae3_port_base_vlan_state {
HNAE3_PORT_BASE_VLAN_NOCHANGE,
};
+enum hnae3_dbg_cmd {
+ HNAE3_DBG_CMD_TM_NODES,
+ HNAE3_DBG_CMD_TM_PRI,
+ HNAE3_DBG_CMD_TM_QSET,
+ HNAE3_DBG_CMD_TM_MAP,
+ HNAE3_DBG_CMD_TM_PG,
+ HNAE3_DBG_CMD_TM_PORT,
+ HNAE3_DBG_CMD_TC_SCH_INFO,
+ HNAE3_DBG_CMD_QOS_PAUSE_CFG,
+ HNAE3_DBG_CMD_QOS_PRI_MAP,
+ HNAE3_DBG_CMD_QOS_BUF_CFG,
+ HNAE3_DBG_CMD_DEV_INFO,
+ HNAE3_DBG_CMD_TX_BD,
+ HNAE3_DBG_CMD_RX_BD,
+ HNAE3_DBG_CMD_MAC_UC,
+ HNAE3_DBG_CMD_MAC_MC,
+ HNAE3_DBG_CMD_MNG_TBL,
+ HNAE3_DBG_CMD_LOOPBACK,
+ HNAE3_DBG_CMD_PTP_INFO,
+ HNAE3_DBG_CMD_INTERRUPT_INFO,
+ HNAE3_DBG_CMD_RESET_INFO,
+ HNAE3_DBG_CMD_IMP_INFO,
+ HNAE3_DBG_CMD_NCL_CONFIG,
+ HNAE3_DBG_CMD_REG_BIOS_COMMON,
+ HNAE3_DBG_CMD_REG_SSU,
+ HNAE3_DBG_CMD_REG_IGU_EGU,
+ HNAE3_DBG_CMD_REG_RPU,
+ HNAE3_DBG_CMD_REG_NCSI,
+ HNAE3_DBG_CMD_REG_RTC,
+ HNAE3_DBG_CMD_REG_PPP,
+ HNAE3_DBG_CMD_REG_RCB,
+ HNAE3_DBG_CMD_REG_TQP,
+ HNAE3_DBG_CMD_REG_MAC,
+ HNAE3_DBG_CMD_REG_DCB,
+ HNAE3_DBG_CMD_VLAN_CONFIG,
+ HNAE3_DBG_CMD_QUEUE_MAP,
+ HNAE3_DBG_CMD_RX_QUEUE_INFO,
+ HNAE3_DBG_CMD_TX_QUEUE_INFO,
+ HNAE3_DBG_CMD_FD_TCAM,
+ HNAE3_DBG_CMD_FD_COUNTER,
+ HNAE3_DBG_CMD_MAC_TNL_STATUS,
+ HNAE3_DBG_CMD_SERV_INFO,
+ HNAE3_DBG_CMD_UMV_INFO,
+ HNAE3_DBG_CMD_UNKNOWN,
+};
+
struct hnae3_vector_info {
u8 __iomem *io_addr;
int vector;
@@ -470,6 +521,12 @@ struct hnae3_ae_dev {
* Check if any cls flower rule exist
* dbg_read_cmd
* Execute debugfs read command.
+ * set_tx_hwts_info
+ * Save information for 1588 tx packet
+ * get_rx_hwts
+ * Get 1588 rx hwstamp
+ * get_ts_info
+ * Get phc info
*/
struct hnae3_ae_ops {
int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
@@ -585,7 +642,7 @@ struct hnae3_ae_ops {
void (*get_mdix_mode)(struct hnae3_handle *handle,
u8 *tp_mdix_ctrl, u8 *tp_mdix);
- void (*enable_vlan_filter)(struct hnae3_handle *handle, bool enable);
+ int (*enable_vlan_filter)(struct hnae3_handle *handle, bool enable);
int (*set_vlan_filter)(struct hnae3_handle *handle, __be16 proto,
u16 vlan_id, bool is_kill);
int (*set_vf_vlan_filter)(struct hnae3_handle *handle, int vfid,
@@ -622,8 +679,7 @@ struct hnae3_ae_ops {
void (*enable_fd)(struct hnae3_handle *handle, bool enable);
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);
- int (*dbg_read_cmd)(struct hnae3_handle *handle, const char *cmd_buf,
+ int (*dbg_read_cmd)(struct hnae3_handle *handle, enum hnae3_dbg_cmd cmd,
char *buf, int len);
pci_ers_result_t (*handle_hw_ras_error)(struct hnae3_ae_dev *ae_dev);
bool (*get_hw_reset_stat)(struct hnae3_handle *handle);
@@ -656,6 +712,12 @@ struct hnae3_ae_ops {
struct ethtool_link_ksettings *cmd);
int (*set_phy_link_ksettings)(struct hnae3_handle *handle,
const struct ethtool_link_ksettings *cmd);
+ bool (*set_tx_hwts_info)(struct hnae3_handle *handle,
+ struct sk_buff *skb);
+ void (*get_rx_hwts)(struct hnae3_handle *handle, struct sk_buff *skb,
+ u32 nsec, u32 sec);
+ int (*get_ts_info)(struct hnae3_handle *handle,
+ struct ethtool_ts_info *info);
};
struct hnae3_dcb_ops {
@@ -700,6 +762,7 @@ struct hnae3_knic_private_info {
u16 rx_buf_len;
u16 num_tx_desc;
u16 num_rx_desc;
+ u32 tx_spare_buf_size;
struct hnae3_tc_info tc_info;
@@ -738,7 +801,6 @@ struct hnae3_roce_private_info {
#define HNAE3_BPE BIT(2) /* broadcast promisc enable */
#define HNAE3_OVERFLOW_UPE BIT(3) /* unicast mac vlan overflow */
#define HNAE3_OVERFLOW_MPE BIT(4) /* multicast mac vlan overflow */
-#define HNAE3_VLAN_FLTR BIT(5) /* enable vlan filter */
#define HNAE3_UPE (HNAE3_USER_UPE | HNAE3_OVERFLOW_UPE)
#define HNAE3_MPE (HNAE3_USER_MPE | HNAE3_OVERFLOW_MPE)
@@ -786,10 +848,6 @@ struct hnae3_handle {
#define hnae3_get_bit(origin, shift) \
hnae3_get_field(origin, 0x1 << (shift), shift)
-#define HNAE3_DBG_TM_NODES "tm_nodes"
-#define HNAE3_DBG_TM_PRI "tm_priority"
-#define HNAE3_DBG_TM_QSET "tm_qset"
-
int hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev);
void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
index 9d702bd0c7c1..532523069d74 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
@@ -5,46 +5,539 @@
#include <linux/device.h>
#include "hnae3.h"
+#include "hns3_debugfs.h"
#include "hns3_enet.h"
-#define HNS3_DBG_READ_LEN 65536
-#define HNS3_DBG_WRITE_LEN 1024
-
static struct dentry *hns3_dbgfs_root;
-static int hns3_dbg_queue_info(struct hnae3_handle *h,
- const char *cmd_buf)
+static struct hns3_dbg_dentry_info hns3_dbg_dentry[] = {
+ {
+ .name = "tm"
+ },
+ {
+ .name = "tx_bd_info"
+ },
+ {
+ .name = "rx_bd_info"
+ },
+ {
+ .name = "mac_list"
+ },
+ {
+ .name = "reg"
+ },
+ {
+ .name = "queue"
+ },
+ {
+ .name = "fd"
+ },
+ /* keep common at the bottom and add new directory above */
+ {
+ .name = "common"
+ },
+};
+
+static int hns3_dbg_bd_file_init(struct hnae3_handle *handle, unsigned int cmd);
+static int hns3_dbg_common_file_init(struct hnae3_handle *handle,
+ unsigned int cmd);
+
+static struct hns3_dbg_cmd_info hns3_dbg_cmd[] = {
+ {
+ .name = "tm_nodes",
+ .cmd = HNAE3_DBG_CMD_TM_NODES,
+ .dentry = HNS3_DBG_DENTRY_TM,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "tm_priority",
+ .cmd = HNAE3_DBG_CMD_TM_PRI,
+ .dentry = HNS3_DBG_DENTRY_TM,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "tm_qset",
+ .cmd = HNAE3_DBG_CMD_TM_QSET,
+ .dentry = HNS3_DBG_DENTRY_TM,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "tm_map",
+ .cmd = HNAE3_DBG_CMD_TM_MAP,
+ .dentry = HNS3_DBG_DENTRY_TM,
+ .buf_len = HNS3_DBG_READ_LEN_1MB,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "tm_pg",
+ .cmd = HNAE3_DBG_CMD_TM_PG,
+ .dentry = HNS3_DBG_DENTRY_TM,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "tm_port",
+ .cmd = HNAE3_DBG_CMD_TM_PORT,
+ .dentry = HNS3_DBG_DENTRY_TM,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "tc_sch_info",
+ .cmd = HNAE3_DBG_CMD_TC_SCH_INFO,
+ .dentry = HNS3_DBG_DENTRY_TM,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "qos_pause_cfg",
+ .cmd = HNAE3_DBG_CMD_QOS_PAUSE_CFG,
+ .dentry = HNS3_DBG_DENTRY_TM,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "qos_pri_map",
+ .cmd = HNAE3_DBG_CMD_QOS_PRI_MAP,
+ .dentry = HNS3_DBG_DENTRY_TM,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "qos_buf_cfg",
+ .cmd = HNAE3_DBG_CMD_QOS_BUF_CFG,
+ .dentry = HNS3_DBG_DENTRY_TM,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "dev_info",
+ .cmd = HNAE3_DBG_CMD_DEV_INFO,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "tx_bd_queue",
+ .cmd = HNAE3_DBG_CMD_TX_BD,
+ .dentry = HNS3_DBG_DENTRY_TX_BD,
+ .buf_len = HNS3_DBG_READ_LEN_4MB,
+ .init = hns3_dbg_bd_file_init,
+ },
+ {
+ .name = "rx_bd_queue",
+ .cmd = HNAE3_DBG_CMD_RX_BD,
+ .dentry = HNS3_DBG_DENTRY_RX_BD,
+ .buf_len = HNS3_DBG_READ_LEN_4MB,
+ .init = hns3_dbg_bd_file_init,
+ },
+ {
+ .name = "uc",
+ .cmd = HNAE3_DBG_CMD_MAC_UC,
+ .dentry = HNS3_DBG_DENTRY_MAC,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "mc",
+ .cmd = HNAE3_DBG_CMD_MAC_MC,
+ .dentry = HNS3_DBG_DENTRY_MAC,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "mng_tbl",
+ .cmd = HNAE3_DBG_CMD_MNG_TBL,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "loopback",
+ .cmd = HNAE3_DBG_CMD_LOOPBACK,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "interrupt_info",
+ .cmd = HNAE3_DBG_CMD_INTERRUPT_INFO,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "reset_info",
+ .cmd = HNAE3_DBG_CMD_RESET_INFO,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "imp_info",
+ .cmd = HNAE3_DBG_CMD_IMP_INFO,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "ncl_config",
+ .cmd = HNAE3_DBG_CMD_NCL_CONFIG,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN_128KB,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "mac_tnl_status",
+ .cmd = HNAE3_DBG_CMD_MAC_TNL_STATUS,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "bios_common",
+ .cmd = HNAE3_DBG_CMD_REG_BIOS_COMMON,
+ .dentry = HNS3_DBG_DENTRY_REG,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "ssu",
+ .cmd = HNAE3_DBG_CMD_REG_SSU,
+ .dentry = HNS3_DBG_DENTRY_REG,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "igu_egu",
+ .cmd = HNAE3_DBG_CMD_REG_IGU_EGU,
+ .dentry = HNS3_DBG_DENTRY_REG,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "rpu",
+ .cmd = HNAE3_DBG_CMD_REG_RPU,
+ .dentry = HNS3_DBG_DENTRY_REG,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "ncsi",
+ .cmd = HNAE3_DBG_CMD_REG_NCSI,
+ .dentry = HNS3_DBG_DENTRY_REG,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "rtc",
+ .cmd = HNAE3_DBG_CMD_REG_RTC,
+ .dentry = HNS3_DBG_DENTRY_REG,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "ppp",
+ .cmd = HNAE3_DBG_CMD_REG_PPP,
+ .dentry = HNS3_DBG_DENTRY_REG,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "rcb",
+ .cmd = HNAE3_DBG_CMD_REG_RCB,
+ .dentry = HNS3_DBG_DENTRY_REG,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "tqp",
+ .cmd = HNAE3_DBG_CMD_REG_TQP,
+ .dentry = HNS3_DBG_DENTRY_REG,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "mac",
+ .cmd = HNAE3_DBG_CMD_REG_MAC,
+ .dentry = HNS3_DBG_DENTRY_REG,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "dcb",
+ .cmd = HNAE3_DBG_CMD_REG_DCB,
+ .dentry = HNS3_DBG_DENTRY_REG,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "queue_map",
+ .cmd = HNAE3_DBG_CMD_QUEUE_MAP,
+ .dentry = HNS3_DBG_DENTRY_QUEUE,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "rx_queue_info",
+ .cmd = HNAE3_DBG_CMD_RX_QUEUE_INFO,
+ .dentry = HNS3_DBG_DENTRY_QUEUE,
+ .buf_len = HNS3_DBG_READ_LEN_1MB,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "tx_queue_info",
+ .cmd = HNAE3_DBG_CMD_TX_QUEUE_INFO,
+ .dentry = HNS3_DBG_DENTRY_QUEUE,
+ .buf_len = HNS3_DBG_READ_LEN_1MB,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "fd_tcam",
+ .cmd = HNAE3_DBG_CMD_FD_TCAM,
+ .dentry = HNS3_DBG_DENTRY_FD,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "service_task_info",
+ .cmd = HNAE3_DBG_CMD_SERV_INFO,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "vlan_config",
+ .cmd = HNAE3_DBG_CMD_VLAN_CONFIG,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "ptp_info",
+ .cmd = HNAE3_DBG_CMD_PTP_INFO,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "fd_counter",
+ .cmd = HNAE3_DBG_CMD_FD_COUNTER,
+ .dentry = HNS3_DBG_DENTRY_FD,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+ {
+ .name = "umv_info",
+ .cmd = HNAE3_DBG_CMD_UMV_INFO,
+ .dentry = HNS3_DBG_DENTRY_COMMON,
+ .buf_len = HNS3_DBG_READ_LEN,
+ .init = hns3_dbg_common_file_init,
+ },
+};
+
+static struct hns3_dbg_cap_info hns3_dbg_cap[] = {
+ {
+ .name = "support FD",
+ .cap_bit = HNAE3_DEV_SUPPORT_FD_B,
+ }, {
+ .name = "support GRO",
+ .cap_bit = HNAE3_DEV_SUPPORT_GRO_B,
+ }, {
+ .name = "support FEC",
+ .cap_bit = HNAE3_DEV_SUPPORT_FEC_B,
+ }, {
+ .name = "support UDP GSO",
+ .cap_bit = HNAE3_DEV_SUPPORT_UDP_GSO_B,
+ }, {
+ .name = "support PTP",
+ .cap_bit = HNAE3_DEV_SUPPORT_PTP_B,
+ }, {
+ .name = "support INT QL",
+ .cap_bit = HNAE3_DEV_SUPPORT_INT_QL_B,
+ }, {
+ .name = "support HW TX csum",
+ .cap_bit = HNAE3_DEV_SUPPORT_HW_TX_CSUM_B,
+ }, {
+ .name = "support UDP tunnel csum",
+ .cap_bit = HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B,
+ }, {
+ .name = "support TX push",
+ .cap_bit = HNAE3_DEV_SUPPORT_TX_PUSH_B,
+ }, {
+ .name = "support imp-controlled PHY",
+ .cap_bit = HNAE3_DEV_SUPPORT_PHY_IMP_B,
+ }, {
+ .name = "support imp-controlled RAS",
+ .cap_bit = HNAE3_DEV_SUPPORT_RAS_IMP_B,
+ }, {
+ .name = "support rxd advanced layout",
+ .cap_bit = HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B,
+ }, {
+ .name = "support port vlan bypass",
+ .cap_bit = HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B,
+ }, {
+ .name = "support modify vlan filter state",
+ .cap_bit = HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B,
+ }
+};
+
+static void hns3_dbg_fill_content(char *content, u16 len,
+ const struct hns3_dbg_item *items,
+ const char **result, u16 size)
+{
+ char *pos = content;
+ u16 i;
+
+ memset(content, ' ', len);
+ for (i = 0; i < size; i++) {
+ if (result)
+ strncpy(pos, result[i], strlen(result[i]));
+ else
+ strncpy(pos, items[i].name, strlen(items[i].name));
+
+ pos += strlen(items[i].name) + items[i].interval;
+ }
+
+ *pos++ = '\n';
+ *pos++ = '\0';
+}
+
+static const struct hns3_dbg_item tx_spare_info_items[] = {
+ { "QUEUE_ID", 2 },
+ { "COPYBREAK", 2 },
+ { "LEN", 7 },
+ { "NTU", 4 },
+ { "NTC", 4 },
+ { "LTC", 4 },
+ { "DMA", 17 },
+};
+
+static void hns3_dbg_tx_spare_info(struct hns3_enet_ring *ring, char *buf,
+ int len, u32 ring_num, int *pos)
+{
+ char data_str[ARRAY_SIZE(tx_spare_info_items)][HNS3_DBG_DATA_STR_LEN];
+ struct hns3_tx_spare *tx_spare = ring->tx_spare;
+ char *result[ARRAY_SIZE(tx_spare_info_items)];
+ char content[HNS3_DBG_INFO_LEN];
+ u32 i, j;
+
+ if (!tx_spare) {
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "tx spare buffer is not enabled\n");
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(tx_spare_info_items); i++)
+ result[i] = &data_str[i][0];
+
+ *pos += scnprintf(buf + *pos, len - *pos, "tx spare buffer info\n");
+ hns3_dbg_fill_content(content, sizeof(content), tx_spare_info_items,
+ NULL, ARRAY_SIZE(tx_spare_info_items));
+ *pos += scnprintf(buf + *pos, len - *pos, "%s", content);
+
+ for (i = 0; i < ring_num; i++) {
+ j = 0;
+ sprintf(result[j++], "%8u", i);
+ sprintf(result[j++], "%9u", ring->tx_copybreak);
+ sprintf(result[j++], "%3u", tx_spare->len);
+ sprintf(result[j++], "%3u", tx_spare->next_to_use);
+ sprintf(result[j++], "%3u", tx_spare->next_to_clean);
+ sprintf(result[j++], "%3u", tx_spare->last_to_clean);
+ sprintf(result[j++], "%pad", &tx_spare->dma);
+ hns3_dbg_fill_content(content, sizeof(content),
+ tx_spare_info_items,
+ (const char **)result,
+ ARRAY_SIZE(tx_spare_info_items));
+ *pos += scnprintf(buf + *pos, len - *pos, "%s", content);
+ }
+}
+
+static const struct hns3_dbg_item rx_queue_info_items[] = {
+ { "QUEUE_ID", 2 },
+ { "BD_NUM", 2 },
+ { "BD_LEN", 2 },
+ { "TAIL", 2 },
+ { "HEAD", 2 },
+ { "FBDNUM", 2 },
+ { "PKTNUM", 2 },
+ { "COPYBREAK", 2 },
+ { "RING_EN", 2 },
+ { "RX_RING_EN", 2 },
+ { "BASE_ADDR", 10 },
+};
+
+static void hns3_dump_rx_queue_info(struct hns3_enet_ring *ring,
+ struct hnae3_ae_dev *ae_dev, char **result,
+ u32 index)
{
+ u32 base_add_l, base_add_h;
+ u32 j = 0;
+
+ sprintf(result[j++], "%8u", index);
+
+ sprintf(result[j++], "%6u", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_RX_RING_BD_NUM_REG));
+
+ sprintf(result[j++], "%6u", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_RX_RING_BD_LEN_REG));
+
+ sprintf(result[j++], "%4u", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_RX_RING_TAIL_REG));
+
+ sprintf(result[j++], "%4u", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_RX_RING_HEAD_REG));
+
+ sprintf(result[j++], "%6u", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_RX_RING_FBDNUM_REG));
+
+ sprintf(result[j++], "%6u", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_RX_RING_PKTNUM_RECORD_REG));
+ sprintf(result[j++], "%9u", ring->rx_copybreak);
+
+ sprintf(result[j++], "%7s", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_EN_REG) ? "on" : "off");
+
+ if (hnae3_ae_dev_tqp_txrx_indep_supported(ae_dev))
+ sprintf(result[j++], "%10s", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_RX_EN_REG) ? "on" : "off");
+ else
+ sprintf(result[j++], "%10s", "NA");
+
+ base_add_h = readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_RX_RING_BASEADDR_H_REG);
+ base_add_l = readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_RX_RING_BASEADDR_L_REG);
+ sprintf(result[j++], "0x%08x%08x", base_add_h, base_add_l);
+}
+
+static int hns3_dbg_rx_queue_info(struct hnae3_handle *h,
+ char *buf, int len)
+{
+ char data_str[ARRAY_SIZE(rx_queue_info_items)][HNS3_DBG_DATA_STR_LEN];
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
+ char *result[ARRAY_SIZE(rx_queue_info_items)];
struct hns3_nic_priv *priv = h->priv;
+ char content[HNS3_DBG_INFO_LEN];
struct hns3_enet_ring *ring;
- u32 base_add_l, base_add_h;
- u32 queue_num, queue_max;
- u32 value, i;
- int cnt;
+ int pos = 0;
+ u32 i;
if (!priv->ring) {
dev_err(&h->pdev->dev, "priv->ring is NULL\n");
return -EFAULT;
}
- queue_max = h->kinfo.num_tqps;
- cnt = kstrtouint(&cmd_buf[11], 0, &queue_num);
- if (cnt)
- queue_num = 0;
- else
- queue_max = queue_num + 1;
+ for (i = 0; i < ARRAY_SIZE(rx_queue_info_items); i++)
+ result[i] = &data_str[i][0];
- dev_info(&h->pdev->dev, "queue info\n");
-
- if (queue_num >= h->kinfo.num_tqps) {
- dev_err(&h->pdev->dev,
- "Queue number(%u) is out of range(0-%u)\n", queue_num,
- h->kinfo.num_tqps - 1);
- return -EINVAL;
- }
-
- for (i = queue_num; i < queue_max; i++) {
+ hns3_dbg_fill_content(content, sizeof(content), rx_queue_info_items,
+ NULL, ARRAY_SIZE(rx_queue_info_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
+ for (i = 0; i < h->kinfo.num_tqps; i++) {
/* Each cycle needs to determine whether the instance is reset,
* to prevent reference to invalid memory. And need to ensure
* that the following code is executed within 100ms.
@@ -54,491 +547,524 @@ static int hns3_dbg_queue_info(struct hnae3_handle *h,
return -EPERM;
ring = &priv->ring[(u32)(i + h->kinfo.num_tqps)];
- base_add_h = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_RX_RING_BASEADDR_H_REG);
- base_add_l = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_RX_RING_BASEADDR_L_REG);
- dev_info(&h->pdev->dev, "RX(%u) BASE ADD: 0x%08x%08x\n", i,
- base_add_h, base_add_l);
+ hns3_dump_rx_queue_info(ring, ae_dev, result, i);
+ hns3_dbg_fill_content(content, sizeof(content),
+ rx_queue_info_items,
+ (const char **)result,
+ ARRAY_SIZE(rx_queue_info_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
+ }
+
+ return 0;
+}
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_RX_RING_BD_NUM_REG);
- dev_info(&h->pdev->dev, "RX(%u) RING BD NUM: %u\n", i, value);
+static const struct hns3_dbg_item tx_queue_info_items[] = {
+ { "QUEUE_ID", 2 },
+ { "BD_NUM", 2 },
+ { "TC", 2 },
+ { "TAIL", 2 },
+ { "HEAD", 2 },
+ { "FBDNUM", 2 },
+ { "OFFSET", 2 },
+ { "PKTNUM", 2 },
+ { "RING_EN", 2 },
+ { "TX_RING_EN", 2 },
+ { "BASE_ADDR", 10 },
+};
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_RX_RING_BD_LEN_REG);
- dev_info(&h->pdev->dev, "RX(%u) RING BD LEN: %u\n", i, value);
+static void hns3_dump_tx_queue_info(struct hns3_enet_ring *ring,
+ struct hnae3_ae_dev *ae_dev, char **result,
+ u32 index)
+{
+ u32 base_add_l, base_add_h;
+ u32 j = 0;
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_RX_RING_TAIL_REG);
- dev_info(&h->pdev->dev, "RX(%u) RING TAIL: %u\n", i, value);
+ sprintf(result[j++], "%8u", index);
+ sprintf(result[j++], "%6u", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_TX_RING_BD_NUM_REG));
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_RX_RING_HEAD_REG);
- dev_info(&h->pdev->dev, "RX(%u) RING HEAD: %u\n", i, value);
+ sprintf(result[j++], "%2u", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_TX_RING_TC_REG));
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_RX_RING_FBDNUM_REG);
- dev_info(&h->pdev->dev, "RX(%u) RING FBDNUM: %u\n", i, value);
+ sprintf(result[j++], "%4u", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_TX_RING_TAIL_REG));
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_RX_RING_PKTNUM_RECORD_REG);
- dev_info(&h->pdev->dev, "RX(%u) RING PKTNUM: %u\n", i, value);
+ sprintf(result[j++], "%4u", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_TX_RING_HEAD_REG));
- ring = &priv->ring[i];
- base_add_h = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_TX_RING_BASEADDR_H_REG);
- base_add_l = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_TX_RING_BASEADDR_L_REG);
- dev_info(&h->pdev->dev, "TX(%u) BASE ADD: 0x%08x%08x\n", i,
- base_add_h, base_add_l);
-
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_TX_RING_BD_NUM_REG);
- dev_info(&h->pdev->dev, "TX(%u) RING BD NUM: %u\n", i, value);
-
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_TX_RING_TC_REG);
- dev_info(&h->pdev->dev, "TX(%u) RING TC: %u\n", i, value);
-
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_TX_RING_TAIL_REG);
- dev_info(&h->pdev->dev, "TX(%u) RING TAIL: %u\n", i, value);
-
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_TX_RING_HEAD_REG);
- dev_info(&h->pdev->dev, "TX(%u) RING HEAD: %u\n", i, value);
-
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_TX_RING_FBDNUM_REG);
- dev_info(&h->pdev->dev, "TX(%u) RING FBDNUM: %u\n", i, value);
-
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_TX_RING_OFFSET_REG);
- dev_info(&h->pdev->dev, "TX(%u) RING OFFSET: %u\n", i, value);
-
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_TX_RING_PKTNUM_RECORD_REG);
- dev_info(&h->pdev->dev, "TX(%u) RING PKTNUM: %u\n", i, value);
-
- value = readl_relaxed(ring->tqp->io_base + HNS3_RING_EN_REG);
- dev_info(&h->pdev->dev, "TX/RX(%u) RING EN: %s\n", i,
- value ? "enable" : "disable");
-
- if (hnae3_ae_dev_tqp_txrx_indep_supported(ae_dev)) {
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_TX_EN_REG);
- dev_info(&h->pdev->dev, "TX(%u) RING EN: %s\n", i,
- value ? "enable" : "disable");
-
- value = readl_relaxed(ring->tqp->io_base +
- HNS3_RING_RX_EN_REG);
- dev_info(&h->pdev->dev, "RX(%u) RING EN: %s\n", i,
- value ? "enable" : "disable");
- }
+ sprintf(result[j++], "%6u", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_TX_RING_FBDNUM_REG));
+
+ sprintf(result[j++], "%6u", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_TX_RING_OFFSET_REG));
+
+ sprintf(result[j++], "%6u", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_TX_RING_PKTNUM_RECORD_REG));
+
+ sprintf(result[j++], "%7s", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_EN_REG) ? "on" : "off");
+
+ if (hnae3_ae_dev_tqp_txrx_indep_supported(ae_dev))
+ sprintf(result[j++], "%10s", readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_TX_EN_REG) ? "on" : "off");
+ else
+ sprintf(result[j++], "%10s", "NA");
+
+ base_add_h = readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_TX_RING_BASEADDR_H_REG);
+ base_add_l = readl_relaxed(ring->tqp->io_base +
+ HNS3_RING_TX_RING_BASEADDR_L_REG);
+ sprintf(result[j++], "0x%08x%08x", base_add_h, base_add_l);
+}
+
+static int hns3_dbg_tx_queue_info(struct hnae3_handle *h,
+ char *buf, int len)
+{
+ char data_str[ARRAY_SIZE(tx_queue_info_items)][HNS3_DBG_DATA_STR_LEN];
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
+ char *result[ARRAY_SIZE(tx_queue_info_items)];
+ struct hns3_nic_priv *priv = h->priv;
+ char content[HNS3_DBG_INFO_LEN];
+ struct hns3_enet_ring *ring;
+ int pos = 0;
+ u32 i;
+
+ if (!priv->ring) {
+ dev_err(&h->pdev->dev, "priv->ring is NULL\n");
+ return -EFAULT;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(tx_queue_info_items); i++)
+ result[i] = &data_str[i][0];
+
+ hns3_dbg_fill_content(content, sizeof(content), tx_queue_info_items,
+ NULL, ARRAY_SIZE(tx_queue_info_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
+
+ for (i = 0; i < h->kinfo.num_tqps; i++) {
+ /* Each cycle needs to determine whether the instance is reset,
+ * to prevent reference to invalid memory. And need to ensure
+ * that the following code is executed within 100ms.
+ */
+ if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) ||
+ test_bit(HNS3_NIC_STATE_RESETTING, &priv->state))
+ return -EPERM;
- dev_info(&h->pdev->dev, "\n");
+ ring = &priv->ring[i];
+ hns3_dump_tx_queue_info(ring, ae_dev, result, i);
+ hns3_dbg_fill_content(content, sizeof(content),
+ tx_queue_info_items,
+ (const char **)result,
+ ARRAY_SIZE(tx_queue_info_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
}
+ hns3_dbg_tx_spare_info(ring, buf, len, h->kinfo.num_tqps, &pos);
+
return 0;
}
-static int hns3_dbg_queue_map(struct hnae3_handle *h)
+static const struct hns3_dbg_item queue_map_items[] = {
+ { "local_queue_id", 2 },
+ { "global_queue_id", 2 },
+ { "vector_id", 2 },
+};
+
+static int hns3_dbg_queue_map(struct hnae3_handle *h, char *buf, int len)
{
+ char data_str[ARRAY_SIZE(queue_map_items)][HNS3_DBG_DATA_STR_LEN];
+ char *result[ARRAY_SIZE(queue_map_items)];
struct hns3_nic_priv *priv = h->priv;
- int i;
+ char content[HNS3_DBG_INFO_LEN];
+ int pos = 0;
+ int j;
+ u32 i;
if (!h->ae_algo->ops->get_global_queue_id)
return -EOPNOTSUPP;
- dev_info(&h->pdev->dev, "map info for queue id and vector id\n");
- dev_info(&h->pdev->dev,
- "local queue id | global queue id | vector id\n");
- for (i = 0; i < h->kinfo.num_tqps; i++) {
- u16 global_qid;
+ for (i = 0; i < ARRAY_SIZE(queue_map_items); i++)
+ result[i] = &data_str[i][0];
- global_qid = h->ae_algo->ops->get_global_queue_id(h, i);
+ hns3_dbg_fill_content(content, sizeof(content), queue_map_items,
+ NULL, ARRAY_SIZE(queue_map_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
+ for (i = 0; i < h->kinfo.num_tqps; i++) {
if (!priv->ring || !priv->ring[i].tqp_vector)
continue;
-
- dev_info(&h->pdev->dev,
- " %4d %4u %4d\n",
- i, global_qid, priv->ring[i].tqp_vector->vector_irq);
+ j = 0;
+ sprintf(result[j++], "%u", i);
+ sprintf(result[j++], "%u",
+ h->ae_algo->ops->get_global_queue_id(h, i));
+ sprintf(result[j++], "%u",
+ priv->ring[i].tqp_vector->vector_irq);
+ hns3_dbg_fill_content(content, sizeof(content), queue_map_items,
+ (const char **)result,
+ ARRAY_SIZE(queue_map_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
}
return 0;
}
-static int hns3_dbg_bd_info(struct hnae3_handle *h, const char *cmd_buf)
+static const struct hns3_dbg_item rx_bd_info_items[] = {
+ { "BD_IDX", 3 },
+ { "L234_INFO", 2 },
+ { "PKT_LEN", 3 },
+ { "SIZE", 4 },
+ { "RSS_HASH", 4 },
+ { "FD_ID", 2 },
+ { "VLAN_TAG", 2 },
+ { "O_DM_VLAN_ID_FB", 2 },
+ { "OT_VLAN_TAG", 2 },
+ { "BD_BASE_INFO", 2 },
+ { "PTYPE", 2 },
+ { "HW_CSUM", 2 },
+};
+
+static void hns3_dump_rx_bd_info(struct hns3_nic_priv *priv,
+ struct hns3_desc *desc, char **result, int idx)
{
- struct hns3_nic_priv *priv = h->priv;
- struct hns3_desc *rx_desc, *tx_desc;
- struct device *dev = &h->pdev->dev;
- struct hns3_enet_ring *ring;
- u32 tx_index, rx_index;
- u32 q_num, value;
- dma_addr_t addr;
- u16 mss_hw_csum;
- u32 l234info;
- int cnt;
-
- cnt = sscanf(&cmd_buf[8], "%u %u", &q_num, &tx_index);
- if (cnt == 2) {
- rx_index = tx_index;
- } else if (cnt != 1) {
- dev_err(dev, "bd info: bad command string, cnt=%d\n", cnt);
- return -EINVAL;
+ unsigned int j = 0;
+
+ sprintf(result[j++], "%5d", idx);
+ sprintf(result[j++], "%#x", le32_to_cpu(desc->rx.l234_info));
+ sprintf(result[j++], "%7u", le16_to_cpu(desc->rx.pkt_len));
+ sprintf(result[j++], "%4u", le16_to_cpu(desc->rx.size));
+ sprintf(result[j++], "%#x", le32_to_cpu(desc->rx.rss_hash));
+ sprintf(result[j++], "%5u", le16_to_cpu(desc->rx.fd_id));
+ sprintf(result[j++], "%8u", le16_to_cpu(desc->rx.vlan_tag));
+ sprintf(result[j++], "%15u", le16_to_cpu(desc->rx.o_dm_vlan_id_fb));
+ sprintf(result[j++], "%11u", le16_to_cpu(desc->rx.ot_vlan_tag));
+ sprintf(result[j++], "%#x", le32_to_cpu(desc->rx.bd_base_info));
+ if (test_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state)) {
+ u32 ol_info = le32_to_cpu(desc->rx.ol_info);
+
+ sprintf(result[j++], "%5lu", hnae3_get_field(ol_info,
+ HNS3_RXD_PTYPE_M,
+ HNS3_RXD_PTYPE_S));
+ sprintf(result[j++], "%7u", le16_to_cpu(desc->csum));
+ } else {
+ sprintf(result[j++], "NA");
+ sprintf(result[j++], "NA");
}
+}
+
+static int hns3_dbg_rx_bd_info(struct hns3_dbg_data *d, char *buf, int len)
+{
+ char data_str[ARRAY_SIZE(rx_bd_info_items)][HNS3_DBG_DATA_STR_LEN];
+ struct hns3_nic_priv *priv = d->handle->priv;
+ char *result[ARRAY_SIZE(rx_bd_info_items)];
+ char content[HNS3_DBG_INFO_LEN];
+ struct hns3_enet_ring *ring;
+ struct hns3_desc *desc;
+ unsigned int i;
+ int pos = 0;
- if (q_num >= h->kinfo.num_tqps) {
- dev_err(dev, "Queue number(%u) is out of range(0-%u)\n", q_num,
- h->kinfo.num_tqps - 1);
+ if (d->qid >= d->handle->kinfo.num_tqps) {
+ dev_err(&d->handle->pdev->dev,
+ "queue%u is not in use\n", d->qid);
return -EINVAL;
}
- ring = &priv->ring[q_num];
- value = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_TAIL_REG);
- tx_index = (cnt == 1) ? value : tx_index;
+ for (i = 0; i < ARRAY_SIZE(rx_bd_info_items); i++)
+ result[i] = &data_str[i][0];
- if (tx_index >= ring->desc_num) {
- dev_err(dev, "bd index(%u) is out of range(0-%u)\n", tx_index,
- ring->desc_num - 1);
- return -EINVAL;
- }
+ pos += scnprintf(buf + pos, len - pos,
+ "Queue %u rx bd info:\n", d->qid);
+ hns3_dbg_fill_content(content, sizeof(content), rx_bd_info_items,
+ NULL, ARRAY_SIZE(rx_bd_info_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
- tx_desc = &ring->desc[tx_index];
- addr = le64_to_cpu(tx_desc->addr);
- mss_hw_csum = le16_to_cpu(tx_desc->tx.mss_hw_csum);
- dev_info(dev, "TX Queue Num: %u, BD Index: %u\n", q_num, tx_index);
- dev_info(dev, "(TX)addr: %pad\n", &addr);
- dev_info(dev, "(TX)vlan_tag: %u\n", le16_to_cpu(tx_desc->tx.vlan_tag));
- dev_info(dev, "(TX)send_size: %u\n",
- le16_to_cpu(tx_desc->tx.send_size));
-
- if (mss_hw_csum & BIT(HNS3_TXD_HW_CS_B)) {
- u32 offset = le32_to_cpu(tx_desc->tx.ol_type_vlan_len_msec);
- u32 start = le32_to_cpu(tx_desc->tx.type_cs_vlan_tso_len);
-
- dev_info(dev, "(TX)csum start: %u\n",
- hnae3_get_field(start,
- HNS3_TXD_CSUM_START_M,
- HNS3_TXD_CSUM_START_S));
- dev_info(dev, "(TX)csum offset: %u\n",
- hnae3_get_field(offset,
- HNS3_TXD_CSUM_OFFSET_M,
- HNS3_TXD_CSUM_OFFSET_S));
- } else {
- dev_info(dev, "(TX)vlan_tso: %u\n",
- tx_desc->tx.type_cs_vlan_tso);
- dev_info(dev, "(TX)l2_len: %u\n", tx_desc->tx.l2_len);
- dev_info(dev, "(TX)l3_len: %u\n", tx_desc->tx.l3_len);
- dev_info(dev, "(TX)l4_len: %u\n", tx_desc->tx.l4_len);
- dev_info(dev, "(TX)vlan_msec: %u\n",
- tx_desc->tx.ol_type_vlan_msec);
- dev_info(dev, "(TX)ol2_len: %u\n", tx_desc->tx.ol2_len);
- dev_info(dev, "(TX)ol3_len: %u\n", tx_desc->tx.ol3_len);
- dev_info(dev, "(TX)ol4_len: %u\n", tx_desc->tx.ol4_len);
- }
+ ring = &priv->ring[d->qid + d->handle->kinfo.num_tqps];
+ for (i = 0; i < ring->desc_num; i++) {
+ desc = &ring->desc[i];
- dev_info(dev, "(TX)vlan_tag: %u\n",
- le16_to_cpu(tx_desc->tx.outer_vlan_tag));
- dev_info(dev, "(TX)tv: %u\n", le16_to_cpu(tx_desc->tx.tv));
- dev_info(dev, "(TX)paylen_ol4cs: %u\n",
- le32_to_cpu(tx_desc->tx.paylen_ol4cs));
- dev_info(dev, "(TX)vld_ra_ri: %u\n",
- le16_to_cpu(tx_desc->tx.bdtp_fe_sc_vld_ra_ri));
- dev_info(dev, "(TX)mss_hw_csum: %u\n", mss_hw_csum);
-
- ring = &priv->ring[q_num + h->kinfo.num_tqps];
- value = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_TAIL_REG);
- rx_index = (cnt == 1) ? value : tx_index;
- rx_desc = &ring->desc[rx_index];
-
- addr = le64_to_cpu(rx_desc->addr);
- l234info = le32_to_cpu(rx_desc->rx.l234_info);
- dev_info(dev, "RX Queue Num: %u, BD Index: %u\n", q_num, rx_index);
- dev_info(dev, "(RX)addr: %pad\n", &addr);
- dev_info(dev, "(RX)l234_info: %u\n", l234info);
-
- if (l234info & BIT(HNS3_RXD_L2_CSUM_B)) {
- u32 lo, hi;
-
- lo = hnae3_get_field(l234info, HNS3_RXD_L2_CSUM_L_M,
- HNS3_RXD_L2_CSUM_L_S);
- hi = hnae3_get_field(l234info, HNS3_RXD_L2_CSUM_H_M,
- HNS3_RXD_L2_CSUM_H_S);
- dev_info(dev, "(RX)csum: %u\n", lo | hi << 8);
+ hns3_dump_rx_bd_info(priv, desc, result, i);
+ hns3_dbg_fill_content(content, sizeof(content),
+ rx_bd_info_items, (const char **)result,
+ ARRAY_SIZE(rx_bd_info_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
}
- dev_info(dev, "(RX)pkt_len: %u\n", le16_to_cpu(rx_desc->rx.pkt_len));
- dev_info(dev, "(RX)size: %u\n", le16_to_cpu(rx_desc->rx.size));
- dev_info(dev, "(RX)rss_hash: %u\n", le32_to_cpu(rx_desc->rx.rss_hash));
- dev_info(dev, "(RX)fd_id: %u\n", le16_to_cpu(rx_desc->rx.fd_id));
- dev_info(dev, "(RX)vlan_tag: %u\n", le16_to_cpu(rx_desc->rx.vlan_tag));
- dev_info(dev, "(RX)o_dm_vlan_id_fb: %u\n",
- le16_to_cpu(rx_desc->rx.o_dm_vlan_id_fb));
- dev_info(dev, "(RX)ot_vlan_tag: %u\n",
- le16_to_cpu(rx_desc->rx.ot_vlan_tag));
- dev_info(dev, "(RX)bd_base_info: %u\n",
- le32_to_cpu(rx_desc->rx.bd_base_info));
-
return 0;
}
-static void hns3_dbg_help(struct hnae3_handle *h)
-{
-#define HNS3_DBG_BUF_LEN 256
-
- char printf_buf[HNS3_DBG_BUF_LEN];
-
- dev_info(&h->pdev->dev, "available commands\n");
- dev_info(&h->pdev->dev, "queue info <number>\n");
- dev_info(&h->pdev->dev, "queue map\n");
- dev_info(&h->pdev->dev, "bd info <q_num> <bd index>\n");
- dev_info(&h->pdev->dev, "dev capability\n");
- dev_info(&h->pdev->dev, "dev spec\n");
-
- if (!hns3_is_phys_func(h->pdev))
- return;
-
- dev_info(&h->pdev->dev, "dump fd tcam\n");
- dev_info(&h->pdev->dev, "dump tc\n");
- dev_info(&h->pdev->dev, "dump tm map <q_num>\n");
- dev_info(&h->pdev->dev, "dump tm\n");
- dev_info(&h->pdev->dev, "dump qos pause cfg\n");
- dev_info(&h->pdev->dev, "dump qos pri map\n");
- 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");
- dev_info(&h->pdev->dev, "dump loopback\n");
- dev_info(&h->pdev->dev, "dump qs shaper [qs id]\n");
- dev_info(&h->pdev->dev, "dump uc mac list <func id>\n");
- dev_info(&h->pdev->dev, "dump mc mac list <func id>\n");
- dev_info(&h->pdev->dev, "dump intr\n");
-
- memset(printf_buf, 0, HNS3_DBG_BUF_LEN);
- strncat(printf_buf, "dump reg [[bios common] [ssu <port_id>]",
- HNS3_DBG_BUF_LEN - 1);
- strncat(printf_buf + strlen(printf_buf),
- " [igu egu <port_id>] [rpu <tc_queue_num>]",
- HNS3_DBG_BUF_LEN - strlen(printf_buf) - 1);
- strncat(printf_buf + strlen(printf_buf),
- " [rtc] [ppp] [rcb] [tqp <queue_num>] [mac]]\n",
- HNS3_DBG_BUF_LEN - strlen(printf_buf) - 1);
- dev_info(&h->pdev->dev, "%s", printf_buf);
-
- memset(printf_buf, 0, HNS3_DBG_BUF_LEN);
- strncat(printf_buf, "dump reg dcb <port_id> <pri_id> <pg_id>",
- HNS3_DBG_BUF_LEN - 1);
- strncat(printf_buf + strlen(printf_buf), " <rq_id> <nq_id> <qset_id>\n",
- HNS3_DBG_BUF_LEN - strlen(printf_buf) - 1);
- dev_info(&h->pdev->dev, "%s", printf_buf);
-}
+static const struct hns3_dbg_item tx_bd_info_items[] = {
+ { "BD_IDX", 5 },
+ { "ADDRESS", 2 },
+ { "VLAN_TAG", 2 },
+ { "SIZE", 2 },
+ { "T_CS_VLAN_TSO", 2 },
+ { "OT_VLAN_TAG", 3 },
+ { "TV", 2 },
+ { "OLT_VLAN_LEN", 2},
+ { "PAYLEN_OL4CS", 2},
+ { "BD_FE_SC_VLD", 2},
+ { "MSS_HW_CSUM", 0},
+};
-static void hns3_dbg_dev_caps(struct hnae3_handle *h)
+static void hns3_dump_tx_bd_info(struct hns3_nic_priv *priv,
+ struct hns3_desc *desc, char **result, int idx)
{
- struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
- unsigned long *caps;
-
- caps = ae_dev->caps;
-
- dev_info(&h->pdev->dev, "support FD: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_FD_B, caps) ? "yes" : "no");
- dev_info(&h->pdev->dev, "support GRO: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_GRO_B, caps) ? "yes" : "no");
- dev_info(&h->pdev->dev, "support FEC: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_FEC_B, caps) ? "yes" : "no");
- dev_info(&h->pdev->dev, "support UDP GSO: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_UDP_GSO_B, caps) ? "yes" : "no");
- dev_info(&h->pdev->dev, "support PTP: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_PTP_B, caps) ? "yes" : "no");
- dev_info(&h->pdev->dev, "support INT QL: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_INT_QL_B, caps) ? "yes" : "no");
- dev_info(&h->pdev->dev, "support HW TX csum: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_HW_TX_CSUM_B, caps) ? "yes" : "no");
- dev_info(&h->pdev->dev, "support UDP tunnel csum: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B, caps) ?
- "yes" : "no");
- dev_info(&h->pdev->dev, "support PAUSE: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_PAUSE_B, ae_dev->caps) ?
- "yes" : "no");
- dev_info(&h->pdev->dev, "support imp-controlled PHY: %s\n",
- test_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, caps) ? "yes" : "no");
+ unsigned int j = 0;
+
+ sprintf(result[j++], "%6d", idx);
+ sprintf(result[j++], "%#llx", le64_to_cpu(desc->addr));
+ sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.vlan_tag));
+ sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.send_size));
+ sprintf(result[j++], "%#x",
+ le32_to_cpu(desc->tx.type_cs_vlan_tso_len));
+ sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.outer_vlan_tag));
+ sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.tv));
+ sprintf(result[j++], "%10u",
+ le32_to_cpu(desc->tx.ol_type_vlan_len_msec));
+ sprintf(result[j++], "%#x", le32_to_cpu(desc->tx.paylen_ol4cs));
+ sprintf(result[j++], "%#x", le16_to_cpu(desc->tx.bdtp_fe_sc_vld_ra_ri));
+ sprintf(result[j++], "%5u", le16_to_cpu(desc->tx.mss_hw_csum));
}
-static void hns3_dbg_dev_specs(struct hnae3_handle *h)
+static int hns3_dbg_tx_bd_info(struct hns3_dbg_data *d, char *buf, int len)
{
- struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
- struct hnae3_dev_specs *dev_specs = &ae_dev->dev_specs;
- struct hnae3_knic_private_info *kinfo = &h->kinfo;
- struct hns3_nic_priv *priv = h->priv;
-
- dev_info(priv->dev, "MAC entry num: %u\n", dev_specs->mac_entry_num);
- dev_info(priv->dev, "MNG entry num: %u\n", dev_specs->mng_entry_num);
- dev_info(priv->dev, "MAX non tso bd num: %u\n",
- dev_specs->max_non_tso_bd_num);
- dev_info(priv->dev, "RSS ind tbl size: %u\n",
- dev_specs->rss_ind_tbl_size);
- dev_info(priv->dev, "RSS key size: %u\n", dev_specs->rss_key_size);
- dev_info(priv->dev, "RSS size: %u\n", kinfo->rss_size);
- dev_info(priv->dev, "Allocated RSS size: %u\n", kinfo->req_rss_size);
- dev_info(priv->dev, "Task queue pairs numbers: %u\n", kinfo->num_tqps);
-
- dev_info(priv->dev, "RX buffer length: %u\n", kinfo->rx_buf_len);
- dev_info(priv->dev, "Desc num per TX queue: %u\n", kinfo->num_tx_desc);
- dev_info(priv->dev, "Desc num per RX queue: %u\n", kinfo->num_rx_desc);
- dev_info(priv->dev, "Total number of enabled TCs: %u\n",
- kinfo->tc_info.num_tc);
- dev_info(priv->dev, "MAX INT QL: %u\n", dev_specs->int_ql_max);
- dev_info(priv->dev, "MAX INT GL: %u\n", dev_specs->max_int_gl);
- dev_info(priv->dev, "MAX frame size: %u\n", dev_specs->max_frm_size);
- dev_info(priv->dev, "MAX TM RATE: %uMbps\n", dev_specs->max_tm_rate);
- dev_info(priv->dev, "MAX QSET number: %u\n", dev_specs->max_qset_num);
-}
+ char data_str[ARRAY_SIZE(tx_bd_info_items)][HNS3_DBG_DATA_STR_LEN];
+ struct hns3_nic_priv *priv = d->handle->priv;
+ char *result[ARRAY_SIZE(tx_bd_info_items)];
+ char content[HNS3_DBG_INFO_LEN];
+ struct hns3_enet_ring *ring;
+ struct hns3_desc *desc;
+ unsigned int i;
+ int pos = 0;
-static ssize_t hns3_dbg_cmd_read(struct file *filp, char __user *buffer,
- size_t count, loff_t *ppos)
-{
- int uncopy_bytes;
- char *buf;
- int len;
+ if (d->qid >= d->handle->kinfo.num_tqps) {
+ dev_err(&d->handle->pdev->dev,
+ "queue%u is not in use\n", d->qid);
+ return -EINVAL;
+ }
- if (*ppos != 0)
- return 0;
+ for (i = 0; i < ARRAY_SIZE(tx_bd_info_items); i++)
+ result[i] = &data_str[i][0];
- if (count < HNS3_DBG_READ_LEN)
- return -ENOSPC;
+ pos += scnprintf(buf + pos, len - pos,
+ "Queue %u tx bd info:\n", d->qid);
+ hns3_dbg_fill_content(content, sizeof(content), tx_bd_info_items,
+ NULL, ARRAY_SIZE(tx_bd_info_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
- buf = kzalloc(HNS3_DBG_READ_LEN, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ ring = &priv->ring[d->qid];
+ for (i = 0; i < ring->desc_num; i++) {
+ desc = &ring->desc[i];
- len = scnprintf(buf, HNS3_DBG_READ_LEN, "%s\n",
- "Please echo help to cmd to get help information");
- uncopy_bytes = copy_to_user(buffer, buf, len);
+ hns3_dump_tx_bd_info(priv, desc, result, i);
+ hns3_dbg_fill_content(content, sizeof(content),
+ tx_bd_info_items, (const char **)result,
+ ARRAY_SIZE(tx_bd_info_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
+ }
- kfree(buf);
+ return 0;
+}
- if (uncopy_bytes)
- return -EFAULT;
+static void
+hns3_dbg_dev_caps(struct hnae3_handle *h, char *buf, int len, int *pos)
+{
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
+ static const char * const str[] = {"no", "yes"};
+ unsigned long *caps = ae_dev->caps;
+ u32 i, state;
+
+ *pos += scnprintf(buf + *pos, len - *pos, "dev capability:\n");
+
+ for (i = 0; i < ARRAY_SIZE(hns3_dbg_cap); i++) {
+ state = test_bit(hns3_dbg_cap[i].cap_bit, caps);
+ *pos += scnprintf(buf + *pos, len - *pos, "%s: %s\n",
+ hns3_dbg_cap[i].name, str[state]);
+ }
- return (*ppos = len);
+ *pos += scnprintf(buf + *pos, len - *pos, "\n");
}
-static int hns3_dbg_check_cmd(struct hnae3_handle *handle, char *cmd_buf)
+static void
+hns3_dbg_dev_specs(struct hnae3_handle *h, char *buf, int len, int *pos)
{
- int ret = 0;
-
- if (strncmp(cmd_buf, "help", 4) == 0)
- hns3_dbg_help(handle);
- else if (strncmp(cmd_buf, "queue info", 10) == 0)
- ret = hns3_dbg_queue_info(handle, cmd_buf);
- else if (strncmp(cmd_buf, "queue map", 9) == 0)
- ret = hns3_dbg_queue_map(handle);
- else if (strncmp(cmd_buf, "bd info", 7) == 0)
- ret = hns3_dbg_bd_info(handle, cmd_buf);
- else if (strncmp(cmd_buf, "dev capability", 14) == 0)
- hns3_dbg_dev_caps(handle);
- else if (strncmp(cmd_buf, "dev spec", 8) == 0)
- hns3_dbg_dev_specs(handle);
- else if (handle->ae_algo->ops->dbg_run_cmd)
- ret = handle->ae_algo->ops->dbg_run_cmd(handle, cmd_buf);
- else
- ret = -EOPNOTSUPP;
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
+ struct hnae3_dev_specs *dev_specs = &ae_dev->dev_specs;
+ struct hnae3_knic_private_info *kinfo = &h->kinfo;
- return ret;
+ *pos += scnprintf(buf + *pos, len - *pos, "dev_spec:\n");
+ *pos += scnprintf(buf + *pos, len - *pos, "MAC entry num: %u\n",
+ dev_specs->mac_entry_num);
+ *pos += scnprintf(buf + *pos, len - *pos, "MNG entry num: %u\n",
+ dev_specs->mng_entry_num);
+ *pos += scnprintf(buf + *pos, len - *pos, "MAX non tso bd num: %u\n",
+ dev_specs->max_non_tso_bd_num);
+ *pos += scnprintf(buf + *pos, len - *pos, "RSS ind tbl size: %u\n",
+ dev_specs->rss_ind_tbl_size);
+ *pos += scnprintf(buf + *pos, len - *pos, "RSS key size: %u\n",
+ dev_specs->rss_key_size);
+ *pos += scnprintf(buf + *pos, len - *pos, "RSS size: %u\n",
+ kinfo->rss_size);
+ *pos += scnprintf(buf + *pos, len - *pos, "Allocated RSS size: %u\n",
+ kinfo->req_rss_size);
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "Task queue pairs numbers: %u\n",
+ kinfo->num_tqps);
+ *pos += scnprintf(buf + *pos, len - *pos, "RX buffer length: %u\n",
+ kinfo->rx_buf_len);
+ *pos += scnprintf(buf + *pos, len - *pos, "Desc num per TX queue: %u\n",
+ kinfo->num_tx_desc);
+ *pos += scnprintf(buf + *pos, len - *pos, "Desc num per RX queue: %u\n",
+ kinfo->num_rx_desc);
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "Total number of enabled TCs: %u\n",
+ kinfo->tc_info.num_tc);
+ *pos += scnprintf(buf + *pos, len - *pos, "MAX INT QL: %u\n",
+ dev_specs->int_ql_max);
+ *pos += scnprintf(buf + *pos, len - *pos, "MAX INT GL: %u\n",
+ dev_specs->max_int_gl);
+ *pos += scnprintf(buf + *pos, len - *pos, "MAX TM RATE: %u\n",
+ dev_specs->max_tm_rate);
+ *pos += scnprintf(buf + *pos, len - *pos, "MAX QSET number: %u\n",
+ dev_specs->max_qset_num);
}
-static ssize_t hns3_dbg_cmd_write(struct file *filp, const char __user *buffer,
- size_t count, loff_t *ppos)
+static int hns3_dbg_dev_info(struct hnae3_handle *h, char *buf, int len)
{
- struct hnae3_handle *handle = filp->private_data;
- struct hns3_nic_priv *priv = handle->priv;
- char *cmd_buf, *cmd_buf_tmp;
- int uncopied_bytes;
- int ret;
+ int pos = 0;
- if (*ppos != 0)
- return 0;
+ hns3_dbg_dev_caps(h, buf, len, &pos);
- /* Judge if the instance is being reset. */
- if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) ||
- test_bit(HNS3_NIC_STATE_RESETTING, &priv->state))
- return 0;
+ hns3_dbg_dev_specs(h, buf, len, &pos);
- if (count > HNS3_DBG_WRITE_LEN)
- return -ENOSPC;
+ return 0;
+}
- cmd_buf = kzalloc(count + 1, GFP_KERNEL);
- if (!cmd_buf)
- return count;
+static int hns3_dbg_get_cmd_index(struct hnae3_handle *handle,
+ const unsigned char *name, u32 *index)
+{
+ u32 i;
- uncopied_bytes = copy_from_user(cmd_buf, buffer, count);
- if (uncopied_bytes) {
- kfree(cmd_buf);
- return -EFAULT;
+ for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++) {
+ if (!strncmp(name, hns3_dbg_cmd[i].name,
+ strlen(hns3_dbg_cmd[i].name))) {
+ *index = i;
+ return 0;
+ }
}
- cmd_buf[count] = '\0';
+ dev_err(&handle->pdev->dev, "unknown command(%s)\n", name);
+ return -EINVAL;
+}
- cmd_buf_tmp = strchr(cmd_buf, '\n');
- if (cmd_buf_tmp) {
- *cmd_buf_tmp = '\0';
- count = cmd_buf_tmp - cmd_buf + 1;
- }
+static const struct hns3_dbg_func hns3_dbg_cmd_func[] = {
+ {
+ .cmd = HNAE3_DBG_CMD_QUEUE_MAP,
+ .dbg_dump = hns3_dbg_queue_map,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_DEV_INFO,
+ .dbg_dump = hns3_dbg_dev_info,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_TX_BD,
+ .dbg_dump_bd = hns3_dbg_tx_bd_info,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_RX_BD,
+ .dbg_dump_bd = hns3_dbg_rx_bd_info,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_RX_QUEUE_INFO,
+ .dbg_dump = hns3_dbg_rx_queue_info,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_TX_QUEUE_INFO,
+ .dbg_dump = hns3_dbg_tx_queue_info,
+ },
+};
- ret = hns3_dbg_check_cmd(handle, cmd_buf);
- if (ret)
- hns3_dbg_help(handle);
+static int hns3_dbg_read_cmd(struct hns3_dbg_data *dbg_data,
+ enum hnae3_dbg_cmd cmd, char *buf, int len)
+{
+ const struct hnae3_ae_ops *ops = dbg_data->handle->ae_algo->ops;
+ const struct hns3_dbg_func *cmd_func;
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd_func); i++) {
+ if (cmd == hns3_dbg_cmd_func[i].cmd) {
+ cmd_func = &hns3_dbg_cmd_func[i];
+ if (cmd_func->dbg_dump)
+ return cmd_func->dbg_dump(dbg_data->handle, buf,
+ len);
+ else
+ return cmd_func->dbg_dump_bd(dbg_data, buf,
+ len);
+ }
+ }
- kfree(cmd_buf);
- cmd_buf = NULL;
+ if (!ops->dbg_read_cmd)
+ return -EOPNOTSUPP;
- return count;
+ return ops->dbg_read_cmd(dbg_data->handle, cmd, buf, len);
}
static ssize_t hns3_dbg_read(struct file *filp, char __user *buffer,
size_t count, loff_t *ppos)
{
- struct hnae3_handle *handle = filp->private_data;
- const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
+ struct hns3_dbg_data *dbg_data = filp->private_data;
+ struct hnae3_handle *handle = dbg_data->handle;
struct hns3_nic_priv *priv = handle->priv;
- char *cmd_buf, *read_buf;
ssize_t size = 0;
- int ret = 0;
-
- read_buf = kzalloc(HNS3_DBG_READ_LEN, GFP_KERNEL);
- if (!read_buf)
- return -ENOMEM;
+ char **save_buf;
+ char *read_buf;
+ u32 index;
+ int ret;
- cmd_buf = filp->f_path.dentry->d_iname;
+ ret = hns3_dbg_get_cmd_index(handle, filp->f_path.dentry->d_iname,
+ &index);
+ if (ret)
+ return ret;
- if (ops->dbg_read_cmd)
- ret = ops->dbg_read_cmd(handle, cmd_buf, read_buf,
- HNS3_DBG_READ_LEN);
+ save_buf = &hns3_dbg_cmd[index].buf;
- if (ret) {
- dev_info(priv->dev, "unknown command\n");
+ if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) ||
+ test_bit(HNS3_NIC_STATE_RESETTING, &priv->state)) {
+ ret = -EBUSY;
goto out;
}
+ if (*save_buf) {
+ read_buf = *save_buf;
+ } else {
+ read_buf = kvzalloc(hns3_dbg_cmd[index].buf_len, GFP_KERNEL);
+ if (!read_buf)
+ return -ENOMEM;
+
+ /* save the buffer addr until the last read operation */
+ *save_buf = read_buf;
+ }
+
+ /* get data ready for the first time to read */
+ if (!*ppos) {
+ ret = hns3_dbg_read_cmd(dbg_data, hns3_dbg_cmd[index].cmd,
+ read_buf, hns3_dbg_cmd[index].buf_len);
+ if (ret)
+ goto out;
+ }
+
size = simple_read_from_buffer(buffer, count, ppos, read_buf,
strlen(read_buf));
+ if (size > 0)
+ return size;
out:
- kfree(read_buf);
- return size;
-}
+ /* free the buffer for the last read operation */
+ if (*save_buf) {
+ kvfree(*save_buf);
+ *save_buf = NULL;
+ }
-static const struct file_operations hns3_dbg_cmd_fops = {
- .owner = THIS_MODULE,
- .open = simple_open,
- .read = hns3_dbg_cmd_read,
- .write = hns3_dbg_cmd_write,
-};
+ return ret;
+}
static const struct file_operations hns3_dbg_fops = {
.owner = THIS_MODULE,
@@ -546,29 +1072,108 @@ static const struct file_operations hns3_dbg_fops = {
.read = hns3_dbg_read,
};
-void hns3_dbg_init(struct hnae3_handle *handle)
+static int hns3_dbg_bd_file_init(struct hnae3_handle *handle, u32 cmd)
+{
+ struct dentry *entry_dir;
+ struct hns3_dbg_data *data;
+ u16 max_queue_num;
+ unsigned int i;
+
+ entry_dir = hns3_dbg_dentry[hns3_dbg_cmd[cmd].dentry].dentry;
+ max_queue_num = hns3_get_max_available_channels(handle);
+ data = devm_kzalloc(&handle->pdev->dev, max_queue_num * sizeof(*data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ for (i = 0; i < max_queue_num; i++) {
+ char name[HNS3_DBG_FILE_NAME_LEN];
+
+ data[i].handle = handle;
+ data[i].qid = i;
+ sprintf(name, "%s%u", hns3_dbg_cmd[cmd].name, i);
+ debugfs_create_file(name, 0400, entry_dir, &data[i],
+ &hns3_dbg_fops);
+ }
+
+ return 0;
+}
+
+static int
+hns3_dbg_common_file_init(struct hnae3_handle *handle, u32 cmd)
+{
+ struct hns3_dbg_data *data;
+ struct dentry *entry_dir;
+
+ data = devm_kzalloc(&handle->pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->handle = handle;
+ entry_dir = hns3_dbg_dentry[hns3_dbg_cmd[cmd].dentry].dentry;
+ debugfs_create_file(hns3_dbg_cmd[cmd].name, 0400, entry_dir,
+ data, &hns3_dbg_fops);
+
+ return 0;
+}
+
+int hns3_dbg_init(struct hnae3_handle *handle)
{
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
const char *name = pci_name(handle->pdev);
- struct dentry *entry_dir;
+ int ret;
+ u32 i;
+
+ hns3_dbg_dentry[HNS3_DBG_DENTRY_COMMON].dentry =
+ debugfs_create_dir(name, hns3_dbgfs_root);
+ handle->hnae3_dbgfs = hns3_dbg_dentry[HNS3_DBG_DENTRY_COMMON].dentry;
+
+ for (i = 0; i < HNS3_DBG_DENTRY_COMMON; i++)
+ hns3_dbg_dentry[i].dentry =
+ debugfs_create_dir(hns3_dbg_dentry[i].name,
+ handle->hnae3_dbgfs);
+
+ for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++) {
+ if ((hns3_dbg_cmd[i].cmd == HNAE3_DBG_CMD_TM_NODES &&
+ ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2) ||
+ (hns3_dbg_cmd[i].cmd == HNAE3_DBG_CMD_PTP_INFO &&
+ !test_bit(HNAE3_DEV_SUPPORT_PTP_B, ae_dev->caps)))
+ continue;
- handle->hnae3_dbgfs = debugfs_create_dir(name, hns3_dbgfs_root);
+ if (!hns3_dbg_cmd[i].init) {
+ dev_err(&handle->pdev->dev,
+ "cmd %s lack of init func\n",
+ hns3_dbg_cmd[i].name);
+ ret = -EINVAL;
+ goto out;
+ }
- debugfs_create_file("cmd", 0600, handle->hnae3_dbgfs, handle,
- &hns3_dbg_cmd_fops);
+ ret = hns3_dbg_cmd[i].init(handle, i);
+ if (ret) {
+ dev_err(&handle->pdev->dev, "failed to init cmd %s\n",
+ hns3_dbg_cmd[i].name);
+ goto out;
+ }
+ }
- entry_dir = debugfs_create_dir("tm", handle->hnae3_dbgfs);
- if (ae_dev->dev_version > HNAE3_DEVICE_VERSION_V2)
- debugfs_create_file(HNAE3_DBG_TM_NODES, 0600, entry_dir, handle,
- &hns3_dbg_fops);
- debugfs_create_file(HNAE3_DBG_TM_PRI, 0600, entry_dir, handle,
- &hns3_dbg_fops);
- debugfs_create_file(HNAE3_DBG_TM_QSET, 0600, entry_dir, handle,
- &hns3_dbg_fops);
+ return 0;
+
+out:
+ debugfs_remove_recursive(handle->hnae3_dbgfs);
+ handle->hnae3_dbgfs = NULL;
+ return ret;
}
void hns3_dbg_uninit(struct hnae3_handle *handle)
{
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++)
+ if (hns3_dbg_cmd[i].buf) {
+ kvfree(hns3_dbg_cmd[i].buf);
+ hns3_dbg_cmd[i].buf = NULL;
+ }
+
debugfs_remove_recursive(handle->hnae3_dbgfs);
handle->hnae3_dbgfs = NULL;
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h
new file mode 100644
index 000000000000..f3766ff38bb7
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2021 Hisilicon Limited. */
+
+#ifndef __HNS3_DEBUGFS_H
+#define __HNS3_DEBUGFS_H
+
+#define HNS3_DBG_READ_LEN 65536
+#define HNS3_DBG_READ_LEN_128KB 0x20000
+#define HNS3_DBG_READ_LEN_1MB 0x100000
+#define HNS3_DBG_READ_LEN_4MB 0x400000
+#define HNS3_DBG_WRITE_LEN 1024
+
+#define HNS3_DBG_DATA_STR_LEN 32
+#define HNS3_DBG_INFO_LEN 256
+#define HNS3_DBG_ITEM_NAME_LEN 32
+#define HNS3_DBG_FILE_NAME_LEN 16
+
+struct hns3_dbg_item {
+ char name[HNS3_DBG_ITEM_NAME_LEN];
+ u16 interval; /* blank numbers after the item */
+};
+
+struct hns3_dbg_data {
+ struct hnae3_handle *handle;
+ u16 qid;
+};
+
+enum hns3_dbg_dentry_type {
+ HNS3_DBG_DENTRY_TM,
+ HNS3_DBG_DENTRY_TX_BD,
+ HNS3_DBG_DENTRY_RX_BD,
+ HNS3_DBG_DENTRY_MAC,
+ HNS3_DBG_DENTRY_REG,
+ HNS3_DBG_DENTRY_QUEUE,
+ HNS3_DBG_DENTRY_FD,
+ HNS3_DBG_DENTRY_COMMON,
+};
+
+struct hns3_dbg_dentry_info {
+ const char *name;
+ struct dentry *dentry;
+};
+
+struct hns3_dbg_cmd_info {
+ const char *name;
+ enum hnae3_dbg_cmd cmd;
+ enum hns3_dbg_dentry_type dentry;
+ u32 buf_len;
+ char *buf;
+ int (*init)(struct hnae3_handle *handle, unsigned int cmd);
+};
+
+struct hns3_dbg_func {
+ enum hnae3_dbg_cmd cmd;
+ int (*dbg_dump)(struct hnae3_handle *handle, char *buf, int len);
+ int (*dbg_dump_bd)(struct hns3_dbg_data *data, char *buf, int len);
+};
+
+struct hns3_dbg_cap_info {
+ const char *name;
+ enum HNAE3_DEV_CAP_BITS cap_bit;
+};
+
+#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index 026558f8e04b..cdb5f14fb6bc 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -53,6 +53,19 @@ static int debug = -1;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, " Network interface message level setting");
+static unsigned int tx_spare_buf_size;
+module_param(tx_spare_buf_size, uint, 0400);
+MODULE_PARM_DESC(tx_spare_buf_size, "Size used to allocate tx spare buffer");
+
+static unsigned int tx_sgl = 1;
+module_param(tx_sgl, uint, 0600);
+MODULE_PARM_DESC(tx_sgl, "Minimum number of frags when using dma_map_sg() to optimize the IOMMU mapping");
+
+#define HNS3_SGL_SIZE(nfrag) (sizeof(struct scatterlist) * (nfrag) + \
+ sizeof(struct sg_table))
+#define HNS3_MAX_SGL_SIZE ALIGN(HNS3_SGL_SIZE(HNS3_MAX_TSO_BD_NUM),\
+ dma_get_cache_alignment())
+
#define DEFAULT_MSG_LEVEL (NETIF_MSG_PROBE | NETIF_MSG_LINK | \
NETIF_MSG_IFDOWN | NETIF_MSG_IFUP)
@@ -91,11 +104,284 @@ static const struct pci_device_id hns3_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, hns3_pci_tbl);
+#define HNS3_RX_PTYPE_ENTRY(ptype, l, s, t) \
+ { ptype, \
+ l, \
+ CHECKSUM_##s, \
+ HNS3_L3_TYPE_##t, \
+ 1 }
+
+#define HNS3_RX_PTYPE_UNUSED_ENTRY(ptype) \
+ { ptype, 0, CHECKSUM_NONE, HNS3_L3_TYPE_PARSE_FAIL, 0 }
+
+static const struct hns3_rx_ptype hns3_rx_ptype_tbl[] = {
+ HNS3_RX_PTYPE_UNUSED_ENTRY(0),
+ HNS3_RX_PTYPE_ENTRY(1, 0, COMPLETE, ARP),
+ HNS3_RX_PTYPE_ENTRY(2, 0, COMPLETE, RARP),
+ HNS3_RX_PTYPE_ENTRY(3, 0, COMPLETE, LLDP),
+ HNS3_RX_PTYPE_ENTRY(4, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(5, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(6, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(7, 0, COMPLETE, CNM),
+ HNS3_RX_PTYPE_ENTRY(8, 0, NONE, PARSE_FAIL),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(9),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(10),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(11),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(12),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(13),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(14),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(15),
+ HNS3_RX_PTYPE_ENTRY(16, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(17, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(18, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(19, 0, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(20, 0, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(21, 0, NONE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(22, 0, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(23, 0, NONE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(24, 0, NONE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(25, 0, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(26),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(27),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(28),
+ HNS3_RX_PTYPE_ENTRY(29, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(30, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(31, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(32, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(33, 1, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(34, 1, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(35, 1, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(36, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(37, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(38),
+ HNS3_RX_PTYPE_ENTRY(39, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(40, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(41, 1, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(42, 1, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(43, 1, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(44, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(45, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(46),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(47),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(48),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(49),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(50),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(51),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(52),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(53),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(54),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(55),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(56),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(57),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(58),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(59),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(60),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(61),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(62),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(63),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(64),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(65),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(66),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(67),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(68),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(69),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(70),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(71),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(72),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(73),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(74),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(75),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(76),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(77),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(78),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(79),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(80),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(81),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(82),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(83),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(84),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(85),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(86),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(87),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(88),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(89),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(90),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(91),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(92),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(93),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(94),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(95),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(96),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(97),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(98),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(99),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(100),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(101),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(102),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(103),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(104),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(105),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(106),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(107),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(108),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(109),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(110),
+ HNS3_RX_PTYPE_ENTRY(111, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(112, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(113, 0, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(114, 0, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(115, 0, NONE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(116, 0, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(117, 0, NONE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(118, 0, NONE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(119, 0, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(120),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(121),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(122),
+ HNS3_RX_PTYPE_ENTRY(123, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(124, 0, COMPLETE, PARSE_FAIL),
+ HNS3_RX_PTYPE_ENTRY(125, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(126, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(127, 1, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(128, 1, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(129, 1, UNNECESSARY, IPV4),
+ HNS3_RX_PTYPE_ENTRY(130, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_ENTRY(131, 0, COMPLETE, IPV4),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(132),
+ HNS3_RX_PTYPE_ENTRY(133, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(134, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(135, 1, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(136, 1, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(137, 1, UNNECESSARY, IPV6),
+ HNS3_RX_PTYPE_ENTRY(138, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_ENTRY(139, 0, COMPLETE, IPV6),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(140),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(141),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(142),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(143),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(144),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(145),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(146),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(147),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(148),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(149),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(150),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(151),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(152),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(153),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(154),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(155),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(156),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(157),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(158),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(159),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(160),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(161),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(162),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(163),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(164),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(165),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(166),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(167),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(168),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(169),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(170),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(171),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(172),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(173),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(174),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(175),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(176),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(177),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(178),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(179),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(180),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(181),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(182),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(183),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(184),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(185),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(186),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(187),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(188),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(189),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(190),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(191),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(192),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(193),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(194),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(195),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(196),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(197),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(198),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(199),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(200),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(201),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(202),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(203),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(204),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(205),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(206),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(207),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(208),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(209),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(210),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(211),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(212),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(213),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(214),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(215),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(216),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(217),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(218),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(219),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(220),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(221),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(222),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(223),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(224),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(225),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(226),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(227),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(228),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(229),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(230),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(231),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(232),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(233),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(234),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(235),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(236),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(237),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(238),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(239),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(240),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(241),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(242),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(243),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(244),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(245),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(246),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(247),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(248),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(249),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(250),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(251),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(252),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(253),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(254),
+ HNS3_RX_PTYPE_UNUSED_ENTRY(255),
+};
+
+#define HNS3_INVALID_PTYPE \
+ ARRAY_SIZE(hns3_rx_ptype_tbl)
+
static irqreturn_t hns3_irq_handle(int irq, void *vector)
{
struct hns3_enet_tqp_vector *tqp_vector = vector;
napi_schedule_irqoff(&tqp_vector->napi);
+ tqp_vector->event_cnt++;
return IRQ_HANDLED;
}
@@ -199,6 +485,8 @@ static void hns3_vector_disable(struct hns3_enet_tqp_vector *tqp_vector)
disable_irq(tqp_vector->vector_irq);
napi_disable(&tqp_vector->napi);
+ cancel_work_sync(&tqp_vector->rx_group.dim.work);
+ cancel_work_sync(&tqp_vector->tx_group.dim.work);
}
void hns3_set_vector_coalesce_rl(struct hns3_enet_tqp_vector *tqp_vector,
@@ -357,7 +645,7 @@ static int hns3_nic_set_real_num_queue(struct net_device *netdev)
return 0;
}
-static u16 hns3_get_max_available_channels(struct hnae3_handle *h)
+u16 hns3_get_max_available_channels(struct hnae3_handle *h)
{
u16 alloc_tqps, max_rss_size, rss_size;
@@ -633,13 +921,10 @@ static u8 hns3_get_netdev_flags(struct net_device *netdev)
{
u8 flags = 0;
- if (netdev->flags & IFF_PROMISC) {
+ if (netdev->flags & IFF_PROMISC)
flags = HNAE3_USER_UPE | HNAE3_USER_MPE | HNAE3_BPE;
- } else {
- flags |= HNAE3_VLAN_FLTR;
- if (netdev->flags & IFF_ALLMULTI)
- flags |= HNAE3_USER_MPE;
- }
+ else if (netdev->flags & IFF_ALLMULTI)
+ flags = HNAE3_USER_MPE;
return flags;
}
@@ -669,23 +954,202 @@ void hns3_request_update_promisc_mode(struct hnae3_handle *handle)
ops->request_update_promisc_mode(handle);
}
-void hns3_enable_vlan_filter(struct net_device *netdev, bool enable)
+static u32 hns3_tx_spare_space(struct hns3_enet_ring *ring)
{
- struct hns3_nic_priv *priv = netdev_priv(netdev);
- struct hnae3_handle *h = priv->ae_handle;
- struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
- bool last_state;
+ struct hns3_tx_spare *tx_spare = ring->tx_spare;
+ u32 ntc, ntu;
- if (ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2 &&
- h->ae_algo->ops->enable_vlan_filter) {
- last_state = h->netdev_flags & HNAE3_VLAN_FLTR ? true : false;
- if (enable != last_state) {
- netdev_info(netdev,
- "%s vlan filter\n",
- enable ? "enable" : "disable");
- h->ae_algo->ops->enable_vlan_filter(h, enable);
+ /* This smp_load_acquire() pairs with smp_store_release() in
+ * hns3_tx_spare_update() called in tx desc cleaning process.
+ */
+ ntc = smp_load_acquire(&tx_spare->last_to_clean);
+ ntu = tx_spare->next_to_use;
+
+ if (ntc > ntu)
+ return ntc - ntu - 1;
+
+ /* The free tx buffer is divided into two part, so pick the
+ * larger one.
+ */
+ return (ntc > (tx_spare->len - ntu) ? ntc :
+ (tx_spare->len - ntu)) - 1;
+}
+
+static void hns3_tx_spare_update(struct hns3_enet_ring *ring)
+{
+ struct hns3_tx_spare *tx_spare = ring->tx_spare;
+
+ if (!tx_spare ||
+ tx_spare->last_to_clean == tx_spare->next_to_clean)
+ return;
+
+ /* This smp_store_release() pairs with smp_load_acquire() in
+ * hns3_tx_spare_space() called in xmit process.
+ */
+ smp_store_release(&tx_spare->last_to_clean,
+ tx_spare->next_to_clean);
+}
+
+static bool hns3_can_use_tx_bounce(struct hns3_enet_ring *ring,
+ struct sk_buff *skb,
+ u32 space)
+{
+ u32 len = skb->len <= ring->tx_copybreak ? skb->len :
+ skb_headlen(skb);
+
+ if (len > ring->tx_copybreak)
+ return false;
+
+ if (ALIGN(len, dma_get_cache_alignment()) > space) {
+ u64_stats_update_begin(&ring->syncp);
+ ring->stats.tx_spare_full++;
+ u64_stats_update_end(&ring->syncp);
+ return false;
+ }
+
+ return true;
+}
+
+static bool hns3_can_use_tx_sgl(struct hns3_enet_ring *ring,
+ struct sk_buff *skb,
+ u32 space)
+{
+ if (skb->len <= ring->tx_copybreak || !tx_sgl ||
+ (!skb_has_frag_list(skb) &&
+ skb_shinfo(skb)->nr_frags < tx_sgl))
+ return false;
+
+ if (space < HNS3_MAX_SGL_SIZE) {
+ u64_stats_update_begin(&ring->syncp);
+ ring->stats.tx_spare_full++;
+ u64_stats_update_end(&ring->syncp);
+ return false;
+ }
+
+ return true;
+}
+
+static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring)
+{
+ struct hns3_tx_spare *tx_spare;
+ struct page *page;
+ u32 alloc_size;
+ dma_addr_t dma;
+ int order;
+
+ alloc_size = tx_spare_buf_size ? tx_spare_buf_size :
+ ring->tqp->handle->kinfo.tx_spare_buf_size;
+ if (!alloc_size)
+ return;
+
+ order = get_order(alloc_size);
+ tx_spare = devm_kzalloc(ring_to_dev(ring), sizeof(*tx_spare),
+ GFP_KERNEL);
+ if (!tx_spare) {
+ /* The driver still work without the tx spare buffer */
+ dev_warn(ring_to_dev(ring), "failed to allocate hns3_tx_spare\n");
+ return;
+ }
+
+ page = alloc_pages_node(dev_to_node(ring_to_dev(ring)),
+ GFP_KERNEL, order);
+ if (!page) {
+ dev_warn(ring_to_dev(ring), "failed to allocate tx spare pages\n");
+ devm_kfree(ring_to_dev(ring), tx_spare);
+ return;
+ }
+
+ dma = dma_map_page(ring_to_dev(ring), page, 0,
+ PAGE_SIZE << order, DMA_TO_DEVICE);
+ if (dma_mapping_error(ring_to_dev(ring), dma)) {
+ dev_warn(ring_to_dev(ring), "failed to map pages for tx spare\n");
+ put_page(page);
+ devm_kfree(ring_to_dev(ring), tx_spare);
+ return;
+ }
+
+ tx_spare->dma = dma;
+ tx_spare->buf = page_address(page);
+ tx_spare->len = PAGE_SIZE << order;
+ ring->tx_spare = tx_spare;
+}
+
+/* Use hns3_tx_spare_space() to make sure there is enough buffer
+ * before calling below function to allocate tx buffer.
+ */
+static void *hns3_tx_spare_alloc(struct hns3_enet_ring *ring,
+ unsigned int size, dma_addr_t *dma,
+ u32 *cb_len)
+{
+ struct hns3_tx_spare *tx_spare = ring->tx_spare;
+ u32 ntu = tx_spare->next_to_use;
+
+ size = ALIGN(size, dma_get_cache_alignment());
+ *cb_len = size;
+
+ /* Tx spare buffer wraps back here because the end of
+ * freed tx buffer is not enough.
+ */
+ if (ntu + size > tx_spare->len) {
+ *cb_len += (tx_spare->len - ntu);
+ ntu = 0;
+ }
+
+ tx_spare->next_to_use = ntu + size;
+ if (tx_spare->next_to_use == tx_spare->len)
+ tx_spare->next_to_use = 0;
+
+ *dma = tx_spare->dma + ntu;
+
+ return tx_spare->buf + ntu;
+}
+
+static void hns3_tx_spare_rollback(struct hns3_enet_ring *ring, u32 len)
+{
+ struct hns3_tx_spare *tx_spare = ring->tx_spare;
+
+ if (len > tx_spare->next_to_use) {
+ len -= tx_spare->next_to_use;
+ tx_spare->next_to_use = tx_spare->len - len;
+ } else {
+ tx_spare->next_to_use -= len;
+ }
+}
+
+static void hns3_tx_spare_reclaim_cb(struct hns3_enet_ring *ring,
+ struct hns3_desc_cb *cb)
+{
+ struct hns3_tx_spare *tx_spare = ring->tx_spare;
+ u32 ntc = tx_spare->next_to_clean;
+ u32 len = cb->length;
+
+ tx_spare->next_to_clean += len;
+
+ if (tx_spare->next_to_clean >= tx_spare->len) {
+ tx_spare->next_to_clean -= tx_spare->len;
+
+ if (tx_spare->next_to_clean) {
+ ntc = 0;
+ len = tx_spare->next_to_clean;
}
}
+
+ /* This tx spare buffer is only really reclaimed after calling
+ * hns3_tx_spare_update(), so it is still safe to use the info in
+ * the tx buffer to do the dma sync or sg unmapping after
+ * tx_spare->next_to_clean is moved forword.
+ */
+ if (cb->type & (DESC_TYPE_BOUNCE_HEAD | DESC_TYPE_BOUNCE_ALL)) {
+ dma_addr_t dma = tx_spare->dma + ntc;
+
+ dma_sync_single_for_cpu(ring_to_dev(ring), dma, len,
+ DMA_TO_DEVICE);
+ } else {
+ struct sg_table *sgt = tx_spare->buf + ntc;
+
+ dma_unmap_sg(ring_to_dev(ring), sgt->sgl, sgt->orig_nents,
+ DMA_TO_DEVICE);
+ }
}
static int hns3_set_tso(struct sk_buff *skb, u32 *paylen_fdop_ol4cs,
@@ -1159,40 +1623,14 @@ out_hw_tx_csum:
return 0;
}
-static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
- unsigned int size, enum hns_desc_type type)
+static int hns3_fill_desc(struct hns3_enet_ring *ring, dma_addr_t dma,
+ unsigned int size)
{
#define HNS3_LIKELY_BD_NUM 1
- struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use];
struct hns3_desc *desc = &ring->desc[ring->next_to_use];
- struct device *dev = ring_to_dev(ring);
- skb_frag_t *frag;
unsigned int frag_buf_num;
int k, sizeoflast;
- dma_addr_t dma;
-
- if (type == DESC_TYPE_FRAGLIST_SKB ||
- type == DESC_TYPE_SKB) {
- struct sk_buff *skb = (struct sk_buff *)priv;
-
- dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE);
- } else {
- frag = (skb_frag_t *)priv;
- dma = skb_frag_dma_map(dev, frag, 0, size, DMA_TO_DEVICE);
- }
-
- if (unlikely(dma_mapping_error(dev, dma))) {
- u64_stats_update_begin(&ring->syncp);
- ring->stats.sw_err_cnt++;
- u64_stats_update_end(&ring->syncp);
- return -ENOMEM;
- }
-
- desc_cb->priv = priv;
- desc_cb->length = size;
- desc_cb->dma = dma;
- desc_cb->type = type;
if (likely(size <= HNS3_MAX_BD_SIZE)) {
desc->addr = cpu_to_le64(dma);
@@ -1228,6 +1666,52 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
return frag_buf_num;
}
+static int hns3_map_and_fill_desc(struct hns3_enet_ring *ring, void *priv,
+ unsigned int type)
+{
+ struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use];
+ struct device *dev = ring_to_dev(ring);
+ unsigned int size;
+ dma_addr_t dma;
+
+ if (type & (DESC_TYPE_FRAGLIST_SKB | DESC_TYPE_SKB)) {
+ struct sk_buff *skb = (struct sk_buff *)priv;
+
+ size = skb_headlen(skb);
+ if (!size)
+ return 0;
+
+ dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE);
+ } else if (type & DESC_TYPE_BOUNCE_HEAD) {
+ /* Head data has been filled in hns3_handle_tx_bounce(),
+ * just return 0 here.
+ */
+ return 0;
+ } else {
+ skb_frag_t *frag = (skb_frag_t *)priv;
+
+ size = skb_frag_size(frag);
+ if (!size)
+ return 0;
+
+ dma = skb_frag_dma_map(dev, frag, 0, size, DMA_TO_DEVICE);
+ }
+
+ if (unlikely(dma_mapping_error(dev, dma))) {
+ u64_stats_update_begin(&ring->syncp);
+ ring->stats.sw_err_cnt++;
+ u64_stats_update_end(&ring->syncp);
+ return -ENOMEM;
+ }
+
+ desc_cb->priv = priv;
+ desc_cb->length = size;
+ desc_cb->dma = dma;
+ desc_cb->type = type;
+
+ return hns3_fill_desc(ring, dma, size);
+}
+
static unsigned int hns3_skb_bd_num(struct sk_buff *skb, unsigned int *bd_size,
unsigned int bd_num)
{
@@ -1451,6 +1935,7 @@ static void hns3_clear_desc(struct hns3_enet_ring *ring, int next_to_use_orig)
for (i = 0; i < ring->desc_num; i++) {
struct hns3_desc *desc = &ring->desc[ring->next_to_use];
+ struct hns3_desc_cb *desc_cb;
memset(desc, 0, sizeof(*desc));
@@ -1461,52 +1946,44 @@ static void hns3_clear_desc(struct hns3_enet_ring *ring, int next_to_use_orig)
/* rollback one */
ring_ptr_move_bw(ring, next_to_use);
- if (!ring->desc_cb[ring->next_to_use].dma)
+ desc_cb = &ring->desc_cb[ring->next_to_use];
+
+ if (!desc_cb->dma)
continue;
/* unmap the descriptor dma address */
- if (ring->desc_cb[ring->next_to_use].type == DESC_TYPE_SKB ||
- ring->desc_cb[ring->next_to_use].type ==
- DESC_TYPE_FRAGLIST_SKB)
- dma_unmap_single(dev,
- ring->desc_cb[ring->next_to_use].dma,
- ring->desc_cb[ring->next_to_use].length,
- DMA_TO_DEVICE);
- else if (ring->desc_cb[ring->next_to_use].length)
- dma_unmap_page(dev,
- ring->desc_cb[ring->next_to_use].dma,
- ring->desc_cb[ring->next_to_use].length,
+ if (desc_cb->type & (DESC_TYPE_SKB | DESC_TYPE_FRAGLIST_SKB))
+ dma_unmap_single(dev, desc_cb->dma, desc_cb->length,
+ DMA_TO_DEVICE);
+ else if (desc_cb->type &
+ (DESC_TYPE_BOUNCE_HEAD | DESC_TYPE_BOUNCE_ALL))
+ hns3_tx_spare_rollback(ring, desc_cb->length);
+ else if (desc_cb->length)
+ dma_unmap_page(dev, desc_cb->dma, desc_cb->length,
DMA_TO_DEVICE);
- ring->desc_cb[ring->next_to_use].length = 0;
- ring->desc_cb[ring->next_to_use].dma = 0;
- ring->desc_cb[ring->next_to_use].type = DESC_TYPE_UNKNOWN;
+ desc_cb->length = 0;
+ desc_cb->dma = 0;
+ desc_cb->type = DESC_TYPE_UNKNOWN;
}
}
static int hns3_fill_skb_to_desc(struct hns3_enet_ring *ring,
- struct sk_buff *skb, enum hns_desc_type type)
+ struct sk_buff *skb, unsigned int type)
{
- unsigned int size = skb_headlen(skb);
struct sk_buff *frag_skb;
int i, ret, bd_num = 0;
- if (size) {
- ret = hns3_fill_desc(ring, skb, size, type);
- if (unlikely(ret < 0))
- return ret;
+ ret = hns3_map_and_fill_desc(ring, skb, type);
+ if (unlikely(ret < 0))
+ return ret;
- bd_num += ret;
- }
+ bd_num += ret;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- size = skb_frag_size(frag);
- if (!size)
- continue;
-
- ret = hns3_fill_desc(ring, frag, size, DESC_TYPE_PAGE);
+ ret = hns3_map_and_fill_desc(ring, frag, DESC_TYPE_PAGE);
if (unlikely(ret < 0))
return ret;
@@ -1546,6 +2023,153 @@ static void hns3_tx_doorbell(struct hns3_enet_ring *ring, int num,
WRITE_ONCE(ring->last_to_use, ring->next_to_use);
}
+static void hns3_tsyn(struct net_device *netdev, struct sk_buff *skb,
+ struct hns3_desc *desc)
+{
+ struct hnae3_handle *h = hns3_get_handle(netdev);
+
+ if (!(h->ae_algo->ops->set_tx_hwts_info &&
+ h->ae_algo->ops->set_tx_hwts_info(h, skb)))
+ return;
+
+ desc->tx.bdtp_fe_sc_vld_ra_ri |= cpu_to_le16(BIT(HNS3_TXD_TSYN_B));
+}
+
+static int hns3_handle_tx_bounce(struct hns3_enet_ring *ring,
+ struct sk_buff *skb)
+{
+ struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use];
+ unsigned int type = DESC_TYPE_BOUNCE_HEAD;
+ unsigned int size = skb_headlen(skb);
+ dma_addr_t dma;
+ int bd_num = 0;
+ u32 cb_len;
+ void *buf;
+ int ret;
+
+ if (skb->len <= ring->tx_copybreak) {
+ size = skb->len;
+ type = DESC_TYPE_BOUNCE_ALL;
+ }
+
+ /* hns3_can_use_tx_bounce() is called to ensure the below
+ * function can always return the tx buffer.
+ */
+ buf = hns3_tx_spare_alloc(ring, size, &dma, &cb_len);
+
+ ret = skb_copy_bits(skb, 0, buf, size);
+ if (unlikely(ret < 0)) {
+ hns3_tx_spare_rollback(ring, cb_len);
+ u64_stats_update_begin(&ring->syncp);
+ ring->stats.copy_bits_err++;
+ u64_stats_update_end(&ring->syncp);
+ return ret;
+ }
+
+ desc_cb->priv = skb;
+ desc_cb->length = cb_len;
+ desc_cb->dma = dma;
+ desc_cb->type = type;
+
+ bd_num += hns3_fill_desc(ring, dma, size);
+
+ if (type == DESC_TYPE_BOUNCE_HEAD) {
+ ret = hns3_fill_skb_to_desc(ring, skb,
+ DESC_TYPE_BOUNCE_HEAD);
+ if (unlikely(ret < 0))
+ return ret;
+
+ bd_num += ret;
+ }
+
+ dma_sync_single_for_device(ring_to_dev(ring), dma, size,
+ DMA_TO_DEVICE);
+
+ u64_stats_update_begin(&ring->syncp);
+ ring->stats.tx_bounce++;
+ u64_stats_update_end(&ring->syncp);
+ return bd_num;
+}
+
+static int hns3_handle_tx_sgl(struct hns3_enet_ring *ring,
+ struct sk_buff *skb)
+{
+ struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use];
+ u32 nfrag = skb_shinfo(skb)->nr_frags + 1;
+ struct sg_table *sgt;
+ int i, bd_num = 0;
+ dma_addr_t dma;
+ u32 cb_len;
+ int nents;
+
+ if (skb_has_frag_list(skb))
+ nfrag = HNS3_MAX_TSO_BD_NUM;
+
+ /* hns3_can_use_tx_sgl() is called to ensure the below
+ * function can always return the tx buffer.
+ */
+ sgt = hns3_tx_spare_alloc(ring, HNS3_SGL_SIZE(nfrag),
+ &dma, &cb_len);
+
+ /* scatterlist follows by the sg table */
+ sgt->sgl = (struct scatterlist *)(sgt + 1);
+ sg_init_table(sgt->sgl, nfrag);
+ nents = skb_to_sgvec(skb, sgt->sgl, 0, skb->len);
+ if (unlikely(nents < 0)) {
+ hns3_tx_spare_rollback(ring, cb_len);
+ u64_stats_update_begin(&ring->syncp);
+ ring->stats.skb2sgl_err++;
+ u64_stats_update_end(&ring->syncp);
+ return -ENOMEM;
+ }
+
+ sgt->orig_nents = nents;
+ sgt->nents = dma_map_sg(ring_to_dev(ring), sgt->sgl, sgt->orig_nents,
+ DMA_TO_DEVICE);
+ if (unlikely(!sgt->nents)) {
+ hns3_tx_spare_rollback(ring, cb_len);
+ u64_stats_update_begin(&ring->syncp);
+ ring->stats.map_sg_err++;
+ u64_stats_update_end(&ring->syncp);
+ return -ENOMEM;
+ }
+
+ desc_cb->priv = skb;
+ desc_cb->length = cb_len;
+ desc_cb->dma = dma;
+ desc_cb->type = DESC_TYPE_SGL_SKB;
+
+ for (i = 0; i < sgt->nents; i++)
+ bd_num += hns3_fill_desc(ring, sg_dma_address(sgt->sgl + i),
+ sg_dma_len(sgt->sgl + i));
+
+ u64_stats_update_begin(&ring->syncp);
+ ring->stats.tx_sgl++;
+ u64_stats_update_end(&ring->syncp);
+
+ return bd_num;
+}
+
+static int hns3_handle_desc_filling(struct hns3_enet_ring *ring,
+ struct sk_buff *skb)
+{
+ u32 space;
+
+ if (!ring->tx_spare)
+ goto out;
+
+ space = hns3_tx_spare_space(ring);
+
+ if (hns3_can_use_tx_sgl(ring, skb, space))
+ return hns3_handle_tx_sgl(ring, skb);
+
+ if (hns3_can_use_tx_bounce(ring, skb, space))
+ return hns3_handle_tx_bounce(ring, skb);
+
+out:
+ return hns3_fill_skb_to_desc(ring, skb, DESC_TYPE_SKB);
+}
+
netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
@@ -1592,16 +2216,22 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
* zero, which is unlikely, and 'ret > 0' means how many tx desc
* need to be notified to the hw.
*/
- ret = hns3_fill_skb_to_desc(ring, skb, DESC_TYPE_SKB);
+ ret = hns3_handle_desc_filling(ring, skb);
if (unlikely(ret <= 0))
goto fill_err;
pre_ntu = ring->next_to_use ? (ring->next_to_use - 1) :
(ring->desc_num - 1);
+
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
+ hns3_tsyn(netdev, skb, &ring->desc[pre_ntu]);
+
ring->desc[pre_ntu].tx.bdtp_fe_sc_vld_ra_ri |=
cpu_to_le16(BIT(HNS3_TXD_FE_B));
trace_hns3_tx_desc(ring, pre_ntu);
+ skb_tx_timestamp(skb);
+
/* Complete translate all packets */
dev_queue = netdev_get_tx_queue(netdev, ring->queue_index);
doorbell = __netdev_tx_sent_queue(dev_queue, desc_cb->send_bytes,
@@ -1705,6 +2335,14 @@ static int hns3_nic_set_features(struct net_device *netdev,
return -EINVAL;
}
+ if ((changed & NETIF_F_HW_VLAN_CTAG_FILTER) &&
+ h->ae_algo->ops->enable_vlan_filter) {
+ enable = !!(features & NETIF_F_HW_VLAN_CTAG_FILTER);
+ ret = h->ae_algo->ops->enable_vlan_filter(h, enable);
+ if (ret)
+ return ret;
+ }
+
netdev->features = features;
return 0;
}
@@ -1780,6 +2418,9 @@ static void hns3_nic_get_stats64(struct net_device *netdev,
tx_drop += ring->stats.tx_tso_err;
tx_drop += ring->stats.over_max_recursion;
tx_drop += ring->stats.hw_limitation;
+ tx_drop += ring->stats.copy_bits_err;
+ tx_drop += ring->stats.skb2sgl_err;
+ tx_drop += ring->stats.map_sg_err;
tx_errors += ring->stats.sw_err_cnt;
tx_errors += ring->stats.tx_vlan_err;
tx_errors += ring->stats.tx_l4_proto_err;
@@ -1787,6 +2428,9 @@ static void hns3_nic_get_stats64(struct net_device *netdev,
tx_errors += ring->stats.tx_tso_err;
tx_errors += ring->stats.over_max_recursion;
tx_errors += ring->stats.hw_limitation;
+ tx_errors += ring->stats.copy_bits_err;
+ tx_errors += ring->stats.skb2sgl_err;
+ tx_errors += ring->stats.map_sg_err;
} while (u64_stats_fetch_retry_irq(&ring->syncp, start));
/* fetch the rx stats */
@@ -2550,6 +3194,9 @@ static void hns3_set_default_feature(struct net_device *netdev)
netdev->hw_features |= NETIF_F_HW_TC;
netdev->features |= NETIF_F_HW_TC;
}
+
+ if (test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps))
+ netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
}
static int hns3_alloc_buffer(struct hns3_enet_ring *ring,
@@ -2577,7 +3224,8 @@ static int hns3_alloc_buffer(struct hns3_enet_ring *ring,
static void hns3_free_buffer(struct hns3_enet_ring *ring,
struct hns3_desc_cb *cb, int budget)
{
- if (cb->type == DESC_TYPE_SKB)
+ if (cb->type & (DESC_TYPE_SKB | DESC_TYPE_BOUNCE_HEAD |
+ DESC_TYPE_BOUNCE_ALL | DESC_TYPE_SGL_SKB))
napi_consume_skb(cb->priv, budget);
else if (!HNAE3_IS_TX_RING(ring) && cb->pagecnt_bias)
__page_frag_cache_drain(cb->priv, cb->pagecnt_bias);
@@ -2598,12 +3246,15 @@ static int hns3_map_buffer(struct hns3_enet_ring *ring, struct hns3_desc_cb *cb)
static void hns3_unmap_buffer(struct hns3_enet_ring *ring,
struct hns3_desc_cb *cb)
{
- if (cb->type == DESC_TYPE_SKB || cb->type == DESC_TYPE_FRAGLIST_SKB)
+ if (cb->type & (DESC_TYPE_SKB | DESC_TYPE_FRAGLIST_SKB))
dma_unmap_single(ring_to_dev(ring), cb->dma, cb->length,
ring_to_dma_dir(ring));
- else if (cb->length)
+ else if ((cb->type & DESC_TYPE_PAGE) && cb->length)
dma_unmap_page(ring_to_dev(ring), cb->dma, cb->length,
ring_to_dma_dir(ring));
+ else if (cb->type & (DESC_TYPE_BOUNCE_ALL | DESC_TYPE_BOUNCE_HEAD |
+ DESC_TYPE_SGL_SKB))
+ hns3_tx_spare_reclaim_cb(ring, cb);
}
static void hns3_buffer_detach(struct hns3_enet_ring *ring, int i)
@@ -2755,7 +3406,9 @@ static bool hns3_nic_reclaim_desc(struct hns3_enet_ring *ring,
desc_cb = &ring->desc_cb[ntc];
- if (desc_cb->type == DESC_TYPE_SKB) {
+ if (desc_cb->type & (DESC_TYPE_SKB | DESC_TYPE_BOUNCE_ALL |
+ DESC_TYPE_BOUNCE_HEAD |
+ DESC_TYPE_SGL_SKB)) {
(*pkts)++;
(*bytes) += desc_cb->send_bytes;
}
@@ -2778,6 +3431,9 @@ static bool hns3_nic_reclaim_desc(struct hns3_enet_ring *ring,
* ring_space called by hns3_nic_net_xmit.
*/
smp_store_release(&ring->next_to_clean, ntc);
+
+ hns3_tx_spare_update(ring);
+
return true;
}
@@ -2869,7 +3525,7 @@ static void hns3_nic_alloc_rx_buffers(struct hns3_enet_ring *ring,
static bool hns3_can_reuse_page(struct hns3_desc_cb *cb)
{
- return (page_count(cb->priv) - cb->pagecnt_bias) == 1;
+ return page_count(cb->priv) == cb->pagecnt_bias;
}
static void hns3_nic_reuse_page(struct sk_buff *skb, int i,
@@ -2877,40 +3533,74 @@ static void hns3_nic_reuse_page(struct sk_buff *skb, int i,
struct hns3_desc_cb *desc_cb)
{
struct hns3_desc *desc = &ring->desc[ring->next_to_clean];
+ u32 frag_offset = desc_cb->page_offset + pull_len;
int size = le16_to_cpu(desc->rx.size);
u32 truesize = hns3_buf_size(ring);
+ u32 frag_size = size - pull_len;
+ bool reused;
- desc_cb->pagecnt_bias--;
- skb_add_rx_frag(skb, i, desc_cb->priv, desc_cb->page_offset + pull_len,
- size - pull_len, truesize);
+ /* Avoid re-using remote or pfmem page */
+ if (unlikely(!dev_page_is_reusable(desc_cb->priv)))
+ goto out;
- /* Avoid re-using remote and pfmemalloc pages, or the stack is still
- * using the page when page_offset rollback to zero, flag default
- * unreuse
+ reused = hns3_can_reuse_page(desc_cb);
+
+ /* Rx page can be reused when:
+ * 1. Rx page is only owned by the driver when page_offset
+ * is zero, which means 0 @ truesize will be used by
+ * stack after skb_add_rx_frag() is called, and the rest
+ * of rx page can be reused by driver.
+ * Or
+ * 2. Rx page is only owned by the driver when page_offset
+ * is non-zero, which means page_offset @ truesize will
+ * be used by stack after skb_add_rx_frag() is called,
+ * and 0 @ truesize can be reused by driver.
*/
- if (!dev_page_is_reusable(desc_cb->priv) ||
- (!desc_cb->page_offset && !hns3_can_reuse_page(desc_cb))) {
- __page_frag_cache_drain(desc_cb->priv, desc_cb->pagecnt_bias);
- return;
- }
+ if ((!desc_cb->page_offset && reused) ||
+ ((desc_cb->page_offset + truesize + truesize) <=
+ hns3_page_size(ring) && desc_cb->page_offset)) {
+ desc_cb->page_offset += truesize;
+ desc_cb->reuse_flag = 1;
+ } else if (desc_cb->page_offset && reused) {
+ desc_cb->page_offset = 0;
+ desc_cb->reuse_flag = 1;
+ } else if (frag_size <= ring->rx_copybreak) {
+ void *frag = napi_alloc_frag(frag_size);
+
+ if (unlikely(!frag)) {
+ u64_stats_update_begin(&ring->syncp);
+ ring->stats.frag_alloc_err++;
+ u64_stats_update_end(&ring->syncp);
- /* Move offset up to the next cache line */
- desc_cb->page_offset += truesize;
+ hns3_rl_err(ring_to_netdev(ring),
+ "failed to allocate rx frag\n");
+ goto out;
+ }
- if (desc_cb->page_offset + truesize <= hns3_page_size(ring)) {
- desc_cb->reuse_flag = 1;
- } else if (hns3_can_reuse_page(desc_cb)) {
desc_cb->reuse_flag = 1;
- desc_cb->page_offset = 0;
- } else if (desc_cb->pagecnt_bias) {
- __page_frag_cache_drain(desc_cb->priv, desc_cb->pagecnt_bias);
+ memcpy(frag, desc_cb->buf + frag_offset, frag_size);
+ skb_add_rx_frag(skb, i, virt_to_page(frag),
+ offset_in_page(frag), frag_size, frag_size);
+
+ u64_stats_update_begin(&ring->syncp);
+ ring->stats.frag_alloc++;
+ u64_stats_update_end(&ring->syncp);
return;
}
+out:
+ desc_cb->pagecnt_bias--;
+
if (unlikely(!desc_cb->pagecnt_bias)) {
page_ref_add(desc_cb->priv, USHRT_MAX);
desc_cb->pagecnt_bias = USHRT_MAX;
}
+
+ skb_add_rx_frag(skb, i, desc_cb->priv, frag_offset,
+ frag_size, truesize);
+
+ if (unlikely(!desc_cb->reuse_flag))
+ __page_frag_cache_drain(desc_cb->priv, desc_cb->pagecnt_bias);
}
static int hns3_gro_complete(struct sk_buff *skb, u32 l234info)
@@ -2971,51 +3661,31 @@ static int hns3_gro_complete(struct sk_buff *skb, u32 l234info)
return 0;
}
-static void hns3_checksum_complete(struct hns3_enet_ring *ring,
- struct sk_buff *skb, u32 l234info)
+static bool hns3_checksum_complete(struct hns3_enet_ring *ring,
+ struct sk_buff *skb, u32 ptype, u16 csum)
{
- u32 lo, hi;
+ if (ptype == HNS3_INVALID_PTYPE ||
+ hns3_rx_ptype_tbl[ptype].ip_summed != CHECKSUM_COMPLETE)
+ return false;
u64_stats_update_begin(&ring->syncp);
ring->stats.csum_complete++;
u64_stats_update_end(&ring->syncp);
skb->ip_summed = CHECKSUM_COMPLETE;
- lo = hnae3_get_field(l234info, HNS3_RXD_L2_CSUM_L_M,
- HNS3_RXD_L2_CSUM_L_S);
- hi = hnae3_get_field(l234info, HNS3_RXD_L2_CSUM_H_M,
- HNS3_RXD_L2_CSUM_H_S);
- skb->csum = csum_unfold((__force __sum16)(lo | hi << 8));
+ skb->csum = csum_unfold((__force __sum16)csum);
+
+ return true;
}
-static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,
- u32 l234info, u32 bd_base_info, u32 ol_info)
+static void hns3_rx_handle_csum(struct sk_buff *skb, u32 l234info,
+ u32 ol_info, u32 ptype)
{
- struct net_device *netdev = ring_to_netdev(ring);
int l3_type, l4_type;
int ol4_type;
- skb->ip_summed = CHECKSUM_NONE;
-
- skb_checksum_none_assert(skb);
-
- if (!(netdev->features & NETIF_F_RXCSUM))
- return;
-
- if (l234info & BIT(HNS3_RXD_L2_CSUM_B)) {
- hns3_checksum_complete(ring, skb, l234info);
- return;
- }
-
- /* check if hardware has done checksum */
- if (!(bd_base_info & BIT(HNS3_RXD_L3L4P_B)))
- return;
-
- if (unlikely(l234info & (BIT(HNS3_RXD_L3E_B) | BIT(HNS3_RXD_L4E_B) |
- BIT(HNS3_RXD_OL3E_B) |
- BIT(HNS3_RXD_OL4E_B)))) {
- u64_stats_update_begin(&ring->syncp);
- ring->stats.l3l4_csum_err++;
- u64_stats_update_end(&ring->syncp);
+ if (ptype != HNS3_INVALID_PTYPE) {
+ skb->csum_level = hns3_rx_ptype_tbl[ptype].csum_level;
+ skb->ip_summed = hns3_rx_ptype_tbl[ptype].ip_summed;
return;
}
@@ -3045,6 +3715,45 @@ static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,
}
}
+static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb,
+ u32 l234info, u32 bd_base_info, u32 ol_info,
+ u16 csum)
+{
+ struct net_device *netdev = ring_to_netdev(ring);
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ u32 ptype = HNS3_INVALID_PTYPE;
+
+ skb->ip_summed = CHECKSUM_NONE;
+
+ skb_checksum_none_assert(skb);
+
+ if (!(netdev->features & NETIF_F_RXCSUM))
+ return;
+
+ if (test_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state))
+ ptype = hnae3_get_field(ol_info, HNS3_RXD_PTYPE_M,
+ HNS3_RXD_PTYPE_S);
+
+ if (hns3_checksum_complete(ring, skb, ptype, csum))
+ return;
+
+ /* check if hardware has done checksum */
+ if (!(bd_base_info & BIT(HNS3_RXD_L3L4P_B)))
+ return;
+
+ if (unlikely(l234info & (BIT(HNS3_RXD_L3E_B) | BIT(HNS3_RXD_L4E_B) |
+ BIT(HNS3_RXD_OL3E_B) |
+ BIT(HNS3_RXD_OL4E_B)))) {
+ u64_stats_update_begin(&ring->syncp);
+ ring->stats.l3l4_csum_err++;
+ u64_stats_update_end(&ring->syncp);
+
+ return;
+ }
+
+ hns3_rx_handle_csum(skb, l234info, ol_info, ptype);
+}
+
static void hns3_rx_skb(struct hns3_enet_ring *ring, struct sk_buff *skb)
{
if (skb_has_frag_list(skb))
@@ -3226,8 +3935,10 @@ static int hns3_add_frag(struct hns3_enet_ring *ring)
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)
+ u32 bd_base_info, u32 ol_info, u16 csum)
{
+ struct net_device *netdev = ring_to_netdev(ring);
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
u32 l3_type;
skb_shinfo(skb)->gso_size = hnae3_get_field(bd_base_info,
@@ -3235,7 +3946,8 @@ static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring,
HNS3_RXD_GRO_SIZE_S);
/* if there is no HW GRO, do not set gro params */
if (!skb_shinfo(skb)->gso_size) {
- hns3_rx_checksum(ring, skb, l234info, bd_base_info, ol_info);
+ hns3_rx_checksum(ring, skb, l234info, bd_base_info, ol_info,
+ csum);
return 0;
}
@@ -3243,7 +3955,16 @@ static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring,
HNS3_RXD_GRO_COUNT_M,
HNS3_RXD_GRO_COUNT_S);
- l3_type = hnae3_get_field(l234info, HNS3_RXD_L3ID_M, HNS3_RXD_L3ID_S);
+ if (test_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state)) {
+ u32 ptype = hnae3_get_field(ol_info, HNS3_RXD_PTYPE_M,
+ HNS3_RXD_PTYPE_S);
+
+ l3_type = hns3_rx_ptype_tbl[ptype].l3_type;
+ } else {
+ 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)
@@ -3276,6 +3997,7 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb)
struct hns3_desc *desc;
unsigned int len;
int pre_ntc, ret;
+ u16 csum;
/* bdinfo handled below is only valid on the last BD of the
* current packet, and ring->next_to_clean indicates the first
@@ -3287,6 +4009,16 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb)
bd_base_info = le32_to_cpu(desc->rx.bd_base_info);
l234info = le32_to_cpu(desc->rx.l234_info);
ol_info = le32_to_cpu(desc->rx.ol_info);
+ csum = le16_to_cpu(desc->csum);
+
+ if (unlikely(bd_base_info & BIT(HNS3_RXD_TS_VLD_B))) {
+ struct hnae3_handle *h = hns3_get_handle(netdev);
+ u32 nsec = le32_to_cpu(desc->ts_nsec);
+ u32 sec = le32_to_cpu(desc->ts_sec);
+
+ if (h->ae_algo->ops->get_rx_hwts)
+ h->ae_algo->ops->get_rx_hwts(h, skb, nsec, sec);
+ }
/* Based on hw strategy, the tag offloaded will be stored at
* ot_vlan_tag in two layer tag case, and stored at vlan_tag
@@ -3319,7 +4051,7 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb)
/* This is needed in order to enable forwarding support */
ret = hns3_set_gro_and_checksum(ring, skb, l234info,
- bd_base_info, ol_info);
+ bd_base_info, ol_info, csum);
if (unlikely(ret)) {
u64_stats_update_begin(&ring->syncp);
ring->stats.rx_err_cnt++;
@@ -3458,139 +4190,30 @@ out:
return recv_pkts;
}
-static bool hns3_get_new_flow_lvl(struct hns3_enet_ring_group *ring_group)
-{
-#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;
- struct hns3_enet_tqp_vector *tqp_vector;
- int packets_per_msecs, bytes_per_msecs;
- u32 time_passed_ms;
-
- tqp_vector = ring_group->ring->tqp_vector;
- time_passed_ms =
- jiffies_to_msecs(jiffies - tqp_vector->last_jiffies);
- if (!time_passed_ms)
- return false;
-
- do_div(ring_group->total_packets, time_passed_ms);
- packets_per_msecs = ring_group->total_packets;
-
- do_div(ring_group->total_bytes, time_passed_ms);
- bytes_per_msecs = ring_group->total_bytes;
-
- 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)
- new_flow_level = HNS3_FLOW_MID;
- break;
- case HNS3_FLOW_MID:
- if (bytes_per_msecs > HNS3_RX_MID_BYTE_RATE)
- new_flow_level = HNS3_FLOW_HIGH;
- else if (bytes_per_msecs <= HNS3_RX_LOW_BYTE_RATE)
- new_flow_level = HNS3_FLOW_LOW;
- break;
- case HNS3_FLOW_HIGH:
- case HNS3_FLOW_ULTRA:
- default:
- if (bytes_per_msecs <= HNS3_RX_MID_BYTE_RATE)
- new_flow_level = HNS3_FLOW_MID;
- break;
- }
-
- if (packets_per_msecs > HNS3_RX_ULTRA_PACKET_RATE &&
- &tqp_vector->rx_group == ring_group)
- new_flow_level = HNS3_FLOW_ULTRA;
-
- 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)
+static void hns3_update_rx_int_coalesce(struct hns3_enet_tqp_vector *tqp_vector)
{
- 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;
+ struct hns3_enet_ring_group *rx_group = &tqp_vector->rx_group;
+ struct dim_sample sample = {};
- 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;
- case HNS3_FLOW_MID:
- new_int_gl = HNS3_INT_GL_20K;
- break;
- case HNS3_FLOW_HIGH:
- new_int_gl = HNS3_INT_GL_18K;
- break;
- case HNS3_FLOW_ULTRA:
- new_int_gl = HNS3_INT_GL_8K;
- break;
- default:
- break;
- }
+ if (!rx_group->coal.adapt_enable)
+ return;
- if (new_int_gl != ring_group->coal.int_gl) {
- ring_group->coal.int_gl = new_int_gl;
- return true;
- }
- return false;
+ dim_update_sample(tqp_vector->event_cnt, rx_group->total_packets,
+ rx_group->total_bytes, &sample);
+ net_dim(&rx_group->dim, sample);
}
-static void hns3_update_new_int_gl(struct hns3_enet_tqp_vector *tqp_vector)
+static void hns3_update_tx_int_coalesce(struct hns3_enet_tqp_vector *tqp_vector)
{
- struct hns3_enet_ring_group *rx_group = &tqp_vector->rx_group;
struct hns3_enet_ring_group *tx_group = &tqp_vector->tx_group;
- bool rx_update, tx_update;
+ struct dim_sample sample = {};
- /* update param every 1000ms */
- if (time_before(jiffies,
- tqp_vector->last_jiffies + msecs_to_jiffies(1000)))
+ if (!tx_group->coal.adapt_enable)
return;
- if (rx_group->coal.adapt_enable) {
- rx_update = hns3_get_new_int_gl(rx_group);
- if (rx_update)
- hns3_set_vector_coalesce_rx_gl(tqp_vector,
- rx_group->coal.int_gl);
- }
-
- if (tx_group->coal.adapt_enable) {
- tx_update = hns3_get_new_int_gl(tx_group);
- if (tx_update)
- hns3_set_vector_coalesce_tx_gl(tqp_vector,
- tx_group->coal.int_gl);
- }
-
- tqp_vector->last_jiffies = jiffies;
+ dim_update_sample(tqp_vector->event_cnt, tx_group->total_packets,
+ tx_group->total_bytes, &sample);
+ net_dim(&tx_group->dim, sample);
}
static int hns3_nic_common_poll(struct napi_struct *napi, int budget)
@@ -3635,7 +4258,9 @@ static int hns3_nic_common_poll(struct napi_struct *napi, int budget)
if (napi_complete(napi) &&
likely(!test_bit(HNS3_NIC_STATE_DOWN, &priv->state))) {
- hns3_update_new_int_gl(tqp_vector);
+ hns3_update_rx_int_coalesce(tqp_vector);
+ hns3_update_tx_int_coalesce(tqp_vector);
+
hns3_mask_vector_irq(tqp_vector, 1);
}
@@ -3766,6 +4391,54 @@ static void hns3_nic_set_cpumask(struct hns3_nic_priv *priv)
}
}
+static void hns3_rx_dim_work(struct work_struct *work)
+{
+ struct dim *dim = container_of(work, struct dim, work);
+ struct hns3_enet_ring_group *group = container_of(dim,
+ struct hns3_enet_ring_group, dim);
+ struct hns3_enet_tqp_vector *tqp_vector = group->ring->tqp_vector;
+ struct dim_cq_moder cur_moder =
+ net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
+
+ hns3_set_vector_coalesce_rx_gl(group->ring->tqp_vector, cur_moder.usec);
+ tqp_vector->rx_group.coal.int_gl = cur_moder.usec;
+
+ if (cur_moder.pkts < tqp_vector->rx_group.coal.int_ql_max) {
+ hns3_set_vector_coalesce_rx_ql(tqp_vector, cur_moder.pkts);
+ tqp_vector->rx_group.coal.int_ql = cur_moder.pkts;
+ }
+
+ dim->state = DIM_START_MEASURE;
+}
+
+static void hns3_tx_dim_work(struct work_struct *work)
+{
+ struct dim *dim = container_of(work, struct dim, work);
+ struct hns3_enet_ring_group *group = container_of(dim,
+ struct hns3_enet_ring_group, dim);
+ struct hns3_enet_tqp_vector *tqp_vector = group->ring->tqp_vector;
+ struct dim_cq_moder cur_moder =
+ net_dim_get_tx_moderation(dim->mode, dim->profile_ix);
+
+ hns3_set_vector_coalesce_tx_gl(tqp_vector, cur_moder.usec);
+ tqp_vector->tx_group.coal.int_gl = cur_moder.usec;
+
+ if (cur_moder.pkts < tqp_vector->tx_group.coal.int_ql_max) {
+ hns3_set_vector_coalesce_tx_ql(tqp_vector, cur_moder.pkts);
+ tqp_vector->tx_group.coal.int_ql = cur_moder.pkts;
+ }
+
+ dim->state = DIM_START_MEASURE;
+}
+
+static void hns3_nic_init_dim(struct hns3_enet_tqp_vector *tqp_vector)
+{
+ INIT_WORK(&tqp_vector->rx_group.dim.work, hns3_rx_dim_work);
+ tqp_vector->rx_group.dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+ INIT_WORK(&tqp_vector->tx_group.dim.work, hns3_tx_dim_work);
+ tqp_vector->tx_group.dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+}
+
static int hns3_nic_init_vector_data(struct hns3_nic_priv *priv)
{
struct hnae3_handle *h = priv->ae_handle;
@@ -3779,6 +4452,7 @@ static int hns3_nic_init_vector_data(struct hns3_nic_priv *priv)
tqp_vector = &priv->tqp_vector[i];
hns3_vector_coalesce_init_hw(tqp_vector, priv);
tqp_vector->num_tqps = 0;
+ hns3_nic_init_dim(tqp_vector);
}
for (i = 0; i < h->kinfo.num_tqps; i++) {
@@ -3974,10 +4648,13 @@ static void hns3_ring_get_cfg(struct hnae3_queue *q, struct hns3_nic_priv *priv,
ring = &priv->ring[q->tqp_index];
desc_num = priv->ae_handle->kinfo.num_tx_desc;
ring->queue_index = q->tqp_index;
+ ring->tx_copybreak = priv->tx_copybreak;
+ ring->last_to_use = 0;
} else {
ring = &priv->ring[q->tqp_index + queue_num];
desc_num = priv->ae_handle->kinfo.num_rx_desc;
ring->queue_index = q->tqp_index;
+ ring->rx_copybreak = priv->rx_copybreak;
}
hnae3_set_bit(ring->flag, HNAE3_RING_TYPE_B, ring_type);
@@ -3991,7 +4668,6 @@ static void hns3_ring_get_cfg(struct hnae3_queue *q, struct hns3_nic_priv *priv,
ring->desc_num = desc_num;
ring->next_to_use = 0;
ring->next_to_clean = 0;
- ring->last_to_use = 0;
}
static void hns3_queue_to_ring(struct hnae3_queue *tqp,
@@ -4051,6 +4727,8 @@ static int hns3_alloc_ring_memory(struct hns3_enet_ring *ring)
ret = hns3_alloc_ring_buffers(ring);
if (ret)
goto out_with_desc;
+ } else {
+ hns3_init_tx_spare_buffer(ring);
}
return 0;
@@ -4073,9 +4751,18 @@ void hns3_fini_ring(struct hns3_enet_ring *ring)
ring->next_to_use = 0;
ring->last_to_use = 0;
ring->pending_buf = 0;
- if (ring->skb) {
+ if (!HNAE3_IS_TX_RING(ring) && ring->skb) {
dev_kfree_skb_any(ring->skb);
ring->skb = NULL;
+ } else if (HNAE3_IS_TX_RING(ring) && ring->tx_spare) {
+ struct hns3_tx_spare *tx_spare = ring->tx_spare;
+
+ dma_unmap_page(ring_to_dev(ring), tx_spare->dma, tx_spare->len,
+ DMA_TO_DEVICE);
+ free_pages((unsigned long)tx_spare->buf,
+ get_order(tx_spare->len));
+ devm_kfree(ring_to_dev(ring), tx_spare);
+ ring->tx_spare = NULL;
}
}
@@ -4358,13 +5045,21 @@ static int hns3_client_init(struct hnae3_handle *handle)
hns3_dcbnl_setup(handle);
- hns3_dbg_init(handle);
+ ret = hns3_dbg_init(handle);
+ if (ret) {
+ dev_err(priv->dev, "failed to init debugfs, ret = %d\n",
+ ret);
+ goto out_client_start;
+ }
netdev->max_mtu = HNS3_MAX_MTU(ae_dev->dev_specs.max_frm_size);
if (test_bit(HNAE3_DEV_SUPPORT_HW_TX_CSUM_B, ae_dev->caps))
set_bit(HNS3_NIC_STATE_HW_TX_CSUM_ENABLE, &priv->state);
+ if (hnae3_ae_dev_rxd_adv_layout_supported(ae_dev))
+ set_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state);
+
set_bit(HNS3_NIC_STATE_INITED, &priv->state);
if (ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
index daa04aeb0942..15af3d93857b 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
@@ -4,6 +4,7 @@
#ifndef __HNS3_ENET_H
#define __HNS3_ENET_H
+#include <linux/dim.h>
#include <linux/if_vlan.h>
#include "hnae3.h"
@@ -19,6 +20,7 @@ enum hns3_nic_state {
HNS3_NIC_STATE_SERVICE_SCHED,
HNS3_NIC_STATE2_RESET_REQUESTED,
HNS3_NIC_STATE_HW_TX_CSUM_ENABLE,
+ HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE,
HNS3_NIC_STATE_MAX
};
@@ -82,12 +84,6 @@ enum hns3_nic_state {
#define HNS3_RXD_STRP_TAGP_S 13
#define HNS3_RXD_STRP_TAGP_M (0x3 << HNS3_RXD_STRP_TAGP_S)
-#define HNS3_RXD_L2_CSUM_B 15
-#define HNS3_RXD_L2_CSUM_L_S 4
-#define HNS3_RXD_L2_CSUM_L_M (0xff << HNS3_RXD_L2_CSUM_L_S)
-#define HNS3_RXD_L2_CSUM_H_S 24
-#define HNS3_RXD_L2_CSUM_H_M (0xff << HNS3_RXD_L2_CSUM_H_S)
-
#define HNS3_RXD_L2E_B 16
#define HNS3_RXD_L3E_B 17
#define HNS3_RXD_L4E_B 18
@@ -114,6 +110,9 @@ enum hns3_nic_state {
#define HNS3_RXD_FBLI_S 14
#define HNS3_RXD_FBLI_M (0x3 << HNS3_RXD_FBLI_S)
+#define HNS3_RXD_PTYPE_S 4
+#define HNS3_RXD_PTYPE_M GENMASK(11, 4)
+
#define HNS3_RXD_BDTYPE_S 0
#define HNS3_RXD_BDTYPE_M (0xf << HNS3_RXD_BDTYPE_S)
#define HNS3_RXD_VLD_B 4
@@ -123,8 +122,9 @@ enum hns3_nic_state {
#define HNS3_RXD_LUM_B 9
#define HNS3_RXD_CRCP_B 10
#define HNS3_RXD_L3L4P_B 11
-#define HNS3_RXD_TSIND_S 12
-#define HNS3_RXD_TSIND_M (0x7 << HNS3_RXD_TSIND_S)
+#define HNS3_RXD_TSIDX_S 12
+#define HNS3_RXD_TSIDX_M (0x3 << HNS3_RXD_TSIDX_S)
+#define HNS3_RXD_TS_VLD_B 14
#define HNS3_RXD_LKBK_B 15
#define HNS3_RXD_GRO_SIZE_S 16
#define HNS3_RXD_GRO_SIZE_M (0x3fff << HNS3_RXD_GRO_SIZE_S)
@@ -238,7 +238,14 @@ enum hns3_pkt_tun_type {
/* hardware spec ring buffer format */
struct __packed hns3_desc {
- __le64 addr;
+ union {
+ __le64 addr;
+ __le16 csum;
+ struct {
+ __le32 ts_nsec;
+ __le32 ts_sec;
+ };
+ };
union {
struct {
__le16 vlan_tag;
@@ -292,6 +299,16 @@ struct __packed hns3_desc {
};
};
+enum hns3_desc_type {
+ DESC_TYPE_UNKNOWN = 0,
+ DESC_TYPE_SKB = 1 << 0,
+ DESC_TYPE_FRAGLIST_SKB = 1 << 1,
+ DESC_TYPE_PAGE = 1 << 2,
+ DESC_TYPE_BOUNCE_ALL = 1 << 3,
+ DESC_TYPE_BOUNCE_HEAD = 1 << 4,
+ DESC_TYPE_SGL_SKB = 1 << 5,
+};
+
struct hns3_desc_cb {
dma_addr_t dma; /* dma address of this desc */
void *buf; /* cpu addr for a desc */
@@ -366,6 +383,14 @@ enum hns3_pkt_ol4type {
HNS3_OL4_TYPE_UNKNOWN
};
+struct hns3_rx_ptype {
+ u32 ptype:8;
+ u32 csum_level:2;
+ u32 ip_summed:2;
+ u32 l3_type:4;
+ u32 valid:1;
+};
+
struct ring_stats {
u64 sw_err_cnt;
u64 seg_pkt_cnt;
@@ -383,6 +408,12 @@ struct ring_stats {
u64 tx_tso_err;
u64 over_max_recursion;
u64 hw_limitation;
+ u64 tx_bounce;
+ u64 tx_spare_full;
+ u64 copy_bits_err;
+ u64 tx_sgl;
+ u64 skb2sgl_err;
+ u64 map_sg_err;
};
struct {
u64 rx_pkts;
@@ -396,10 +427,22 @@ struct ring_stats {
u64 csum_complete;
u64 rx_multicast;
u64 non_reuse_pg;
+ u64 frag_alloc_err;
+ u64 frag_alloc;
};
+ __le16 csum;
};
};
+struct hns3_tx_spare {
+ dma_addr_t dma;
+ void *buf;
+ u32 next_to_use;
+ u32 next_to_clean;
+ u32 last_to_clean;
+ u32 len;
+};
+
struct hns3_enet_ring {
struct hns3_desc *desc; /* dma map address space */
struct hns3_desc_cb *desc_cb;
@@ -422,18 +465,29 @@ struct hns3_enet_ring {
* next_to_use
*/
int next_to_clean;
- union {
- int last_to_use; /* last idx used by xmit */
- u32 pull_len; /* memcpy len for current rx packet */
- };
- u32 frag_num;
- void *va; /* first buffer address for current packet */
-
u32 flag; /* ring attribute */
int pending_buf;
- struct sk_buff *skb;
- struct sk_buff *tail_skb;
+ union {
+ /* for Tx ring */
+ struct {
+ u32 fd_qb_tx_sample;
+ int last_to_use; /* last idx used by xmit */
+ u32 tx_copybreak;
+ struct hns3_tx_spare *tx_spare;
+ };
+
+ /* for Rx ring */
+ struct {
+ u32 pull_len; /* memcpy len for current rx packet */
+ u32 rx_copybreak;
+ u32 frag_num;
+ /* first buffer address for current packet */
+ unsigned char *va;
+ struct sk_buff *skb;
+ struct sk_buff *tail_skb;
+ };
+ };
} ____cacheline_internodealigned_in_smp;
enum hns3_flow_level_range {
@@ -472,6 +526,7 @@ struct hns3_enet_ring_group {
u64 total_packets; /* total packets processed this group */
u16 count;
struct hns3_enet_coalesce coal;
+ struct dim dim;
};
struct hns3_enet_tqp_vector {
@@ -493,7 +548,7 @@ struct hns3_enet_tqp_vector {
char name[HNAE3_INT_NAME_LEN];
- unsigned long last_jiffies;
+ u64 event_cnt;
} ____cacheline_internodealigned_in_smp;
struct hns3_nic_priv {
@@ -516,6 +571,8 @@ struct hns3_nic_priv {
struct hns3_enet_coalesce tx_coal;
struct hns3_enet_coalesce rx_coal;
+ u32 tx_copybreak;
+ u32 rx_copybreak;
};
union l3_hdr_info {
@@ -631,7 +688,6 @@ void hns3_set_vector_coalesce_rx_ql(struct hns3_enet_tqp_vector *tqp_vector,
void hns3_set_vector_coalesce_tx_ql(struct hns3_enet_tqp_vector *tqp_vector,
u32 ql_value);
-void hns3_enable_vlan_filter(struct net_device *netdev, bool enable);
void hns3_request_update_promisc_mode(struct hnae3_handle *handle);
#ifdef CONFIG_HNS3_DCB
@@ -640,9 +696,10 @@ void hns3_dcbnl_setup(struct hnae3_handle *handle);
static inline void hns3_dcbnl_setup(struct hnae3_handle *handle) {}
#endif
-void hns3_dbg_init(struct hnae3_handle *handle);
+int hns3_dbg_init(struct hnae3_handle *handle);
void hns3_dbg_uninit(struct hnae3_handle *handle);
void hns3_dbg_register_debugfs(const char *debugfs_dir_name);
void hns3_dbg_unregister_debugfs(void);
void hns3_shinfo_pack(struct skb_shared_info *shinfo, __u32 *size);
+u16 hns3_get_max_available_channels(struct hnae3_handle *h);
#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
index c1ea403d2b56..82061ab6930f 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
@@ -46,6 +46,12 @@ static const struct hns3_stats hns3_txq_stats[] = {
HNS3_TQP_STAT("tso_err", tx_tso_err),
HNS3_TQP_STAT("over_max_recursion", over_max_recursion),
HNS3_TQP_STAT("hw_limitation", hw_limitation),
+ HNS3_TQP_STAT("bounce", tx_bounce),
+ HNS3_TQP_STAT("spare_full", tx_spare_full),
+ HNS3_TQP_STAT("copy_bits_err", copy_bits_err),
+ HNS3_TQP_STAT("sgl", tx_sgl),
+ HNS3_TQP_STAT("skb2sgl_err", skb2sgl_err),
+ HNS3_TQP_STAT("map_sg_err", map_sg_err),
};
#define HNS3_TXQ_STATS_COUNT ARRAY_SIZE(hns3_txq_stats)
@@ -65,6 +71,8 @@ static const struct hns3_stats hns3_rxq_stats[] = {
HNS3_TQP_STAT("csum_complete", csum_complete),
HNS3_TQP_STAT("multicast", rx_multicast),
HNS3_TQP_STAT("non_reuse_pg", non_reuse_pg),
+ HNS3_TQP_STAT("frag_alloc_err", frag_alloc_err),
+ HNS3_TQP_STAT("frag_alloc", frag_alloc),
};
#define HNS3_PRIV_FLAGS_LEN ARRAY_SIZE(hns3_priv_flags)
@@ -88,7 +96,6 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en)
{
struct hnae3_handle *h = hns3_get_handle(ndev);
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
- bool vlan_filter_enable;
int ret;
if (!h->ae_algo->ops->set_loopback ||
@@ -110,14 +117,11 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en)
if (ret || ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2)
return ret;
- if (en) {
+ if (en)
h->ae_algo->ops->set_promisc_mode(h, true, true);
- } else {
+ else
/* recover promisc mode before loopback test */
hns3_request_update_promisc_mode(h);
- vlan_filter_enable = ndev->flags & IFF_PROMISC ? false : true;
- hns3_enable_vlan_filter(ndev, vlan_filter_enable);
- }
return ret;
}
@@ -1596,12 +1600,77 @@ static int hns3_set_priv_flags(struct net_device *netdev, u32 pflags)
return 0;
}
+static int hns3_get_tunable(struct net_device *netdev,
+ const struct ethtool_tunable *tuna,
+ void *data)
+{
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ int ret = 0;
+
+ switch (tuna->id) {
+ case ETHTOOL_TX_COPYBREAK:
+ /* all the tx rings have the same tx_copybreak */
+ *(u32 *)data = priv->tx_copybreak;
+ break;
+ case ETHTOOL_RX_COPYBREAK:
+ *(u32 *)data = priv->rx_copybreak;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static int hns3_set_tunable(struct net_device *netdev,
+ const struct ethtool_tunable *tuna,
+ const void *data)
+{
+ struct hns3_nic_priv *priv = netdev_priv(netdev);
+ struct hnae3_handle *h = priv->ae_handle;
+ int i, ret = 0;
+
+ switch (tuna->id) {
+ case ETHTOOL_TX_COPYBREAK:
+ priv->tx_copybreak = *(u32 *)data;
+
+ for (i = 0; i < h->kinfo.num_tqps; i++)
+ priv->ring[i].tx_copybreak = priv->tx_copybreak;
+
+ break;
+ case ETHTOOL_RX_COPYBREAK:
+ priv->rx_copybreak = *(u32 *)data;
+
+ for (i = h->kinfo.num_tqps; i < h->kinfo.num_tqps * 2; i++)
+ priv->ring[i].rx_copybreak = priv->rx_copybreak;
+
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
#define HNS3_ETHTOOL_COALESCE (ETHTOOL_COALESCE_USECS | \
ETHTOOL_COALESCE_USE_ADAPTIVE | \
ETHTOOL_COALESCE_RX_USECS_HIGH | \
ETHTOOL_COALESCE_TX_USECS_HIGH | \
ETHTOOL_COALESCE_MAX_FRAMES)
+static int hns3_get_ts_info(struct net_device *netdev,
+ struct ethtool_ts_info *info)
+{
+ struct hnae3_handle *handle = hns3_get_handle(netdev);
+
+ if (handle->ae_algo->ops->get_ts_info)
+ return handle->ae_algo->ops->get_ts_info(handle, info);
+
+ return ethtool_op_get_ts_info(netdev, info);
+}
+
static const struct ethtool_ops hns3vf_ethtool_ops = {
.supported_coalesce_params = HNS3_ETHTOOL_COALESCE,
.get_drvinfo = hns3_get_drvinfo,
@@ -1628,6 +1697,8 @@ static const struct ethtool_ops hns3vf_ethtool_ops = {
.set_msglevel = hns3_set_msglevel,
.get_priv_flags = hns3_get_priv_flags,
.set_priv_flags = hns3_set_priv_flags,
+ .get_tunable = hns3_get_tunable,
+ .set_tunable = hns3_set_tunable,
};
static const struct ethtool_ops hns3_ethtool_ops = {
@@ -1666,6 +1737,9 @@ static const struct ethtool_ops hns3_ethtool_ops = {
.get_module_eeprom = hns3_get_module_eeprom,
.get_priv_flags = hns3_get_priv_flags,
.set_priv_flags = hns3_set_priv_flags,
+ .get_ts_info = hns3_get_ts_info,
+ .get_tunable = hns3_get_tunable,
+ .set_tunable = hns3_set_tunable,
};
void hns3_ethtool_set_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile b/drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile
index 6c28c8f6292c..a685392dbfe9 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/Makefile
@@ -7,6 +7,6 @@ ccflags-y := -I $(srctree)/drivers/net/ethernet/hisilicon/hns3
ccflags-y += -I $(srctree)/$(src)
obj-$(CONFIG_HNS3_HCLGE) += hclge.o
-hclge-objs = hclge_main.o hclge_cmd.o hclge_mdio.o hclge_tm.o hclge_mbx.o hclge_err.o hclge_debugfs.o
+hclge-objs = hclge_main.o hclge_cmd.o hclge_mdio.o hclge_tm.o hclge_mbx.o hclge_err.o hclge_debugfs.o hclge_ptp.o
hclge-$(CONFIG_HNS3_DCB) += hclge_dcb.o
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
index 76a482456f1f..887297e37cf3 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
@@ -178,7 +178,8 @@ static bool hclge_is_special_opcode(u16 opcode)
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};
+ HCLGE_QUERY_CLEAR_ALL_PF_MSIX_INT,
+ HCLGE_QUERY_ALL_ERR_INFO};
int i;
for (i = 0; i < ARRAY_SIZE(spec_opcode); i++) {
@@ -386,6 +387,14 @@ static void hclge_parse_capability(struct hclge_dev *hdev,
set_bit(HNAE3_DEV_SUPPORT_PAUSE_B, ae_dev->caps);
if (hnae3_get_bit(caps, HCLGE_CAP_PHY_IMP_B))
set_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, ae_dev->caps);
+ if (hnae3_get_bit(caps, HCLGE_CAP_RAS_IMP_B))
+ set_bit(HNAE3_DEV_SUPPORT_RAS_IMP_B, ae_dev->caps);
+ if (hnae3_get_bit(caps, HCLGE_CAP_RXD_ADV_LAYOUT_B))
+ set_bit(HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B, ae_dev->caps);
+ if (hnae3_get_bit(caps, HCLGE_CAP_PORT_VLAN_BYPASS_B)) {
+ set_bit(HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B, ae_dev->caps);
+ set_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps);
+ }
}
static __le32 hclge_build_api_caps(void)
@@ -469,7 +478,7 @@ static int hclge_firmware_compat_config(struct hclge_dev *hdev)
struct hclge_desc desc;
u32 compat = 0;
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_M7_COMPAT_CFG, false);
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_IMP_COMPAT_CFG, false);
req = (struct hclge_firmware_compat_cmd *)desc.data;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
index c6fc22e29581..18bde77ef944 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
@@ -130,6 +130,10 @@ enum hclge_opcode_type {
HCLGE_OPC_COMMON_LOOPBACK = 0x0315,
HCLGE_OPC_CONFIG_FEC_MODE = 0x031A,
+ /* PTP commands */
+ HCLGE_OPC_PTP_INT_EN = 0x0501,
+ HCLGE_OPC_PTP_MODE_CFG = 0x0507,
+
/* PFC/Pause commands */
HCLGE_OPC_CFG_MAC_PAUSE_EN = 0x0701,
HCLGE_OPC_CFG_PFC_PAUSE_EN = 0x0702,
@@ -236,6 +240,7 @@ enum hclge_opcode_type {
HCLGE_OPC_VLAN_FILTER_CTRL = 0x1100,
HCLGE_OPC_VLAN_FILTER_PF_CFG = 0x1101,
HCLGE_OPC_VLAN_FILTER_VF_CFG = 0x1102,
+ HCLGE_OPC_PORT_VLAN_BYPASS = 0x1103,
/* Flow Director commands */
HCLGE_OPC_FD_MODE_CTRL = 0x1200,
@@ -243,6 +248,7 @@ enum hclge_opcode_type {
HCLGE_OPC_FD_KEY_CONFIG = 0x1202,
HCLGE_OPC_FD_TCAM_OP = 0x1203,
HCLGE_OPC_FD_AD_OP = 0x1204,
+ HCLGE_OPC_FD_CNT_OP = 0x1205,
HCLGE_OPC_FD_USER_DEF_OP = 0x1207,
/* MDIO command */
@@ -267,10 +273,10 @@ 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,
- HCLGE_OPC_M7_COMPAT_CFG = 0x701A,
+ /* IMP stats command */
+ HCLGE_OPC_IMP_STATS_BD = 0x7012,
+ HCLGE_OPC_IMP_STATS_INFO = 0x7013,
+ HCLGE_OPC_IMP_COMPAT_CFG = 0x701A,
/* SFP command */
HCLGE_OPC_GET_SFP_EEPROM = 0x7100,
@@ -292,6 +298,8 @@ enum hclge_opcode_type {
HCLGE_QUERY_MSIX_INT_STS_BD_NUM = 0x1513,
HCLGE_QUERY_CLEAR_ALL_MPF_MSIX_INT = 0x1514,
HCLGE_QUERY_CLEAR_ALL_PF_MSIX_INT = 0x1515,
+ HCLGE_QUERY_ALL_ERR_BD_NUM = 0x1516,
+ HCLGE_QUERY_ALL_ERR_INFO = 0x1517,
HCLGE_CONFIG_ROCEE_RAS_INT_EN = 0x1580,
HCLGE_QUERY_CLEAR_ROCEE_RAS_INT = 0x1581,
HCLGE_ROCEE_PF_RAS_INT_CMD = 0x1584,
@@ -389,8 +397,11 @@ enum HCLGE_CAP_BITS {
HCLGE_CAP_HW_PAD_B,
HCLGE_CAP_STASH_B,
HCLGE_CAP_UDP_TUNNEL_CSUM_B,
+ HCLGE_CAP_RAS_IMP_B = 12,
HCLGE_CAP_FEC_B = 13,
HCLGE_CAP_PAUSE_B = 14,
+ HCLGE_CAP_RXD_ADV_LAYOUT_B = 15,
+ HCLGE_CAP_PORT_VLAN_BYPASS_B = 17,
};
enum HCLGE_API_CAP_BITS {
@@ -526,10 +537,14 @@ struct hclge_pf_res_cmd {
#define HCLGE_CFG_SPEED_ABILITY_M GENMASK(7, 0)
#define HCLGE_CFG_SPEED_ABILITY_EXT_S 10
#define HCLGE_CFG_SPEED_ABILITY_EXT_M GENMASK(15, 10)
+#define HCLGE_CFG_VLAN_FLTR_CAP_S 8
+#define HCLGE_CFG_VLAN_FLTR_CAP_M GENMASK(9, 8)
#define HCLGE_CFG_UMV_TBL_SPACE_S 16
#define HCLGE_CFG_UMV_TBL_SPACE_M GENMASK(31, 16)
#define HCLGE_CFG_PF_RSS_SIZE_S 0
#define HCLGE_CFG_PF_RSS_SIZE_M GENMASK(3, 0)
+#define HCLGE_CFG_TX_SPARE_BUF_SIZE_S 4
+#define HCLGE_CFG_TX_SPARE_BUF_SIZE_M GENMASK(15, 4)
#define HCLGE_CFG_CMD_CNT 4
@@ -810,6 +825,14 @@ struct hclge_vlan_filter_vf_cfg_cmd {
u8 vf_bitmap[HCLGE_MAX_VF_BYTES];
};
+#define HCLGE_INGRESS_BYPASS_B 0
+struct hclge_port_vlan_filter_bypass_cmd {
+ u8 bypass_state;
+ u8 rsv1[3];
+ u8 vf_id;
+ u8 rsv2[19];
+};
+
#define HCLGE_SWITCH_ANTI_SPOOF_B 0U
#define HCLGE_SWITCH_ALW_LPBK_B 1U
#define HCLGE_SWITCH_ALW_LCL_LPBK_B 2U
@@ -1087,6 +1110,14 @@ struct hclge_fd_ad_config_cmd {
u8 rsv2[8];
};
+struct hclge_fd_ad_cnt_read_cmd {
+ u8 rsv0[4];
+ __le16 index;
+ u8 rsv1[2];
+ __le64 cnt;
+ u8 rsv2[8];
+};
+
#define HCLGE_FD_USER_DEF_OFT_S 0
#define HCLGE_FD_USER_DEF_OFT_M GENMASK(14, 0)
#define HCLGE_FD_USER_DEF_EN_B 15
@@ -1100,7 +1131,7 @@ struct hclge_fd_user_def_cfg_cmd {
u8 rsv[12];
};
-struct hclge_get_m7_bd_cmd {
+struct hclge_get_imp_bd_cmd {
__le32 bd_num;
u8 rsv[20];
};
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
index 85d306459e36..288788186ecc 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
@@ -4,74 +4,110 @@
#include <linux/device.h>
#include "hclge_debugfs.h"
+#include "hclge_err.h"
#include "hclge_main.h"
#include "hclge_tm.h"
#include "hnae3.h"
+static const char * const state_str[] = { "off", "on" };
+static const char * const hclge_mac_state_str[] = {
+ "TO_ADD", "TO_DEL", "ACTIVE"
+};
+
static const struct hclge_dbg_reg_type_info hclge_dbg_reg_info[] = {
- { .reg_type = "bios common",
+ { .cmd = HNAE3_DBG_CMD_REG_BIOS_COMMON,
.dfx_msg = &hclge_dbg_bios_common_reg[0],
.reg_msg = { .msg_num = ARRAY_SIZE(hclge_dbg_bios_common_reg),
.offset = HCLGE_DBG_DFX_BIOS_OFFSET,
.cmd = HCLGE_OPC_DFX_BIOS_COMMON_REG } },
- { .reg_type = "ssu",
+ { .cmd = HNAE3_DBG_CMD_REG_SSU,
.dfx_msg = &hclge_dbg_ssu_reg_0[0],
.reg_msg = { .msg_num = ARRAY_SIZE(hclge_dbg_ssu_reg_0),
.offset = HCLGE_DBG_DFX_SSU_0_OFFSET,
.cmd = HCLGE_OPC_DFX_SSU_REG_0 } },
- { .reg_type = "ssu",
+ { .cmd = HNAE3_DBG_CMD_REG_SSU,
.dfx_msg = &hclge_dbg_ssu_reg_1[0],
.reg_msg = { .msg_num = ARRAY_SIZE(hclge_dbg_ssu_reg_1),
.offset = HCLGE_DBG_DFX_SSU_1_OFFSET,
.cmd = HCLGE_OPC_DFX_SSU_REG_1 } },
- { .reg_type = "ssu",
+ { .cmd = HNAE3_DBG_CMD_REG_SSU,
.dfx_msg = &hclge_dbg_ssu_reg_2[0],
.reg_msg = { .msg_num = ARRAY_SIZE(hclge_dbg_ssu_reg_2),
.offset = HCLGE_DBG_DFX_SSU_2_OFFSET,
.cmd = HCLGE_OPC_DFX_SSU_REG_2 } },
- { .reg_type = "igu egu",
+ { .cmd = HNAE3_DBG_CMD_REG_IGU_EGU,
.dfx_msg = &hclge_dbg_igu_egu_reg[0],
.reg_msg = { .msg_num = ARRAY_SIZE(hclge_dbg_igu_egu_reg),
.offset = HCLGE_DBG_DFX_IGU_OFFSET,
.cmd = HCLGE_OPC_DFX_IGU_EGU_REG } },
- { .reg_type = "rpu",
+ { .cmd = HNAE3_DBG_CMD_REG_RPU,
.dfx_msg = &hclge_dbg_rpu_reg_0[0],
.reg_msg = { .msg_num = ARRAY_SIZE(hclge_dbg_rpu_reg_0),
.offset = HCLGE_DBG_DFX_RPU_0_OFFSET,
.cmd = HCLGE_OPC_DFX_RPU_REG_0 } },
- { .reg_type = "rpu",
+ { .cmd = HNAE3_DBG_CMD_REG_RPU,
.dfx_msg = &hclge_dbg_rpu_reg_1[0],
.reg_msg = { .msg_num = ARRAY_SIZE(hclge_dbg_rpu_reg_1),
.offset = HCLGE_DBG_DFX_RPU_1_OFFSET,
.cmd = HCLGE_OPC_DFX_RPU_REG_1 } },
- { .reg_type = "ncsi",
+ { .cmd = HNAE3_DBG_CMD_REG_NCSI,
.dfx_msg = &hclge_dbg_ncsi_reg[0],
.reg_msg = { .msg_num = ARRAY_SIZE(hclge_dbg_ncsi_reg),
.offset = HCLGE_DBG_DFX_NCSI_OFFSET,
.cmd = HCLGE_OPC_DFX_NCSI_REG } },
- { .reg_type = "rtc",
+ { .cmd = HNAE3_DBG_CMD_REG_RTC,
.dfx_msg = &hclge_dbg_rtc_reg[0],
.reg_msg = { .msg_num = ARRAY_SIZE(hclge_dbg_rtc_reg),
.offset = HCLGE_DBG_DFX_RTC_OFFSET,
.cmd = HCLGE_OPC_DFX_RTC_REG } },
- { .reg_type = "ppp",
+ { .cmd = HNAE3_DBG_CMD_REG_PPP,
.dfx_msg = &hclge_dbg_ppp_reg[0],
.reg_msg = { .msg_num = ARRAY_SIZE(hclge_dbg_ppp_reg),
.offset = HCLGE_DBG_DFX_PPP_OFFSET,
.cmd = HCLGE_OPC_DFX_PPP_REG } },
- { .reg_type = "rcb",
+ { .cmd = HNAE3_DBG_CMD_REG_RCB,
.dfx_msg = &hclge_dbg_rcb_reg[0],
.reg_msg = { .msg_num = ARRAY_SIZE(hclge_dbg_rcb_reg),
.offset = HCLGE_DBG_DFX_RCB_OFFSET,
.cmd = HCLGE_OPC_DFX_RCB_REG } },
- { .reg_type = "tqp",
+ { .cmd = HNAE3_DBG_CMD_REG_TQP,
.dfx_msg = &hclge_dbg_tqp_reg[0],
.reg_msg = { .msg_num = ARRAY_SIZE(hclge_dbg_tqp_reg),
.offset = HCLGE_DBG_DFX_TQP_OFFSET,
.cmd = HCLGE_OPC_DFX_TQP_REG } },
};
-static int hclge_dbg_get_dfx_bd_num(struct hclge_dev *hdev, int offset)
+static void hclge_dbg_fill_content(char *content, u16 len,
+ const struct hclge_dbg_item *items,
+ const char **result, u16 size)
+{
+ char *pos = content;
+ u16 i;
+
+ memset(content, ' ', len);
+ for (i = 0; i < size; i++) {
+ if (result)
+ strncpy(pos, result[i], strlen(result[i]));
+ else
+ strncpy(pos, items[i].name, strlen(items[i].name));
+ pos += strlen(items[i].name) + items[i].interval;
+ }
+ *pos++ = '\n';
+ *pos++ = '\0';
+}
+
+static char *hclge_dbg_get_func_id_str(char *buf, u8 id)
+{
+ if (id)
+ sprintf(buf, "vf%u", id - 1);
+ else
+ sprintf(buf, "pf");
+
+ return buf;
+}
+
+static int hclge_dbg_get_dfx_bd_num(struct hclge_dev *hdev, int offset,
+ u32 *bd_num)
{
struct hclge_desc desc[HCLGE_GET_DFX_REG_TYPE_CNT];
int entries_per_desc;
@@ -81,13 +117,21 @@ static int hclge_dbg_get_dfx_bd_num(struct hclge_dev *hdev, int offset)
ret = hclge_query_bd_num_cmd_send(hdev, desc);
if (ret) {
dev_err(&hdev->pdev->dev,
- "get dfx bdnum fail, ret = %d\n", ret);
+ "failed to get dfx bd_num, offset = %d, ret = %d\n",
+ offset, ret);
return ret;
}
entries_per_desc = ARRAY_SIZE(desc[0].data);
index = offset % entries_per_desc;
- return le32_to_cpu(desc[offset / entries_per_desc].data[index]);
+
+ *bd_num = le32_to_cpu(desc[offset / entries_per_desc].data[index]);
+ if (!(*bd_num)) {
+ dev_err(&hdev->pdev->dev, "The value of dfx bd_num is 0!\n");
+ return -EINVAL;
+ }
+
+ return 0;
}
static int hclge_dbg_cmd_send(struct hclge_dev *hdev,
@@ -114,66 +158,108 @@ static int hclge_dbg_cmd_send(struct hclge_dev *hdev,
return ret;
}
-static void hclge_dbg_dump_reg_common(struct hclge_dev *hdev,
- const struct hclge_dbg_reg_type_info *reg_info,
- const char *cmd_buf)
+static int
+hclge_dbg_dump_reg_tqp(struct hclge_dev *hdev,
+ const struct hclge_dbg_reg_type_info *reg_info,
+ char *buf, int len, int *pos)
{
-#define IDX_OFFSET 1
-
- const char *s = &cmd_buf[strlen(reg_info->reg_type) + IDX_OFFSET];
const struct hclge_dbg_dfx_message *dfx_message = reg_info->dfx_msg;
const struct hclge_dbg_reg_common_msg *reg_msg = &reg_info->reg_msg;
struct hclge_desc *desc_src;
+ u32 index, entry, i, cnt;
+ int bd_num, min_num, ret;
struct hclge_desc *desc;
- int entries_per_desc;
- int bd_num, buf_len;
- int index = 0;
- int min_num;
- int ret, i;
- if (*s) {
- ret = kstrtouint(s, 0, &index);
- index = (ret != 0) ? 0 : index;
- }
+ ret = hclge_dbg_get_dfx_bd_num(hdev, reg_msg->offset, &bd_num);
+ if (ret)
+ return ret;
+
+ desc_src = kcalloc(bd_num, sizeof(struct hclge_desc), GFP_KERNEL);
+ if (!desc_src)
+ return -ENOMEM;
+
+ min_num = min_t(int, bd_num * HCLGE_DESC_DATA_LEN, reg_msg->msg_num);
+
+ for (i = 0, cnt = 0; i < min_num; i++, dfx_message++)
+ *pos += scnprintf(buf + *pos, len - *pos, "item%u = %s\n",
+ cnt++, dfx_message->message);
+
+ for (i = 0; i < cnt; i++)
+ *pos += scnprintf(buf + *pos, len - *pos, "item%u\t", i);
- bd_num = hclge_dbg_get_dfx_bd_num(hdev, reg_msg->offset);
- if (bd_num <= 0) {
- dev_err(&hdev->pdev->dev, "get cmd(%d) bd num(%d) failed\n",
- reg_msg->offset, bd_num);
- return;
+ *pos += scnprintf(buf + *pos, len - *pos, "\n");
+
+ for (index = 0; index < hdev->vport[0].alloc_tqps; index++) {
+ dfx_message = reg_info->dfx_msg;
+ desc = desc_src;
+ ret = hclge_dbg_cmd_send(hdev, desc, index, bd_num,
+ reg_msg->cmd);
+ if (ret)
+ break;
+
+ for (i = 0; i < min_num; i++, dfx_message++) {
+ entry = i % HCLGE_DESC_DATA_LEN;
+ if (i > 0 && !entry)
+ desc++;
+
+ *pos += scnprintf(buf + *pos, len - *pos, "%#x\t",
+ le32_to_cpu(desc->data[entry]));
+ }
+ *pos += scnprintf(buf + *pos, len - *pos, "\n");
}
- buf_len = sizeof(struct hclge_desc) * bd_num;
- desc_src = kzalloc(buf_len, GFP_KERNEL);
+ kfree(desc_src);
+ return ret;
+}
+
+static int
+hclge_dbg_dump_reg_common(struct hclge_dev *hdev,
+ const struct hclge_dbg_reg_type_info *reg_info,
+ char *buf, int len, int *pos)
+{
+ const struct hclge_dbg_reg_common_msg *reg_msg = &reg_info->reg_msg;
+ const struct hclge_dbg_dfx_message *dfx_message = reg_info->dfx_msg;
+ struct hclge_desc *desc_src;
+ int bd_num, min_num, ret;
+ struct hclge_desc *desc;
+ u32 entry, i;
+
+ ret = hclge_dbg_get_dfx_bd_num(hdev, reg_msg->offset, &bd_num);
+ if (ret)
+ return ret;
+
+ desc_src = kcalloc(bd_num, sizeof(struct hclge_desc), GFP_KERNEL);
if (!desc_src)
- return;
+ return -ENOMEM;
desc = desc_src;
- ret = hclge_dbg_cmd_send(hdev, desc, index, bd_num, reg_msg->cmd);
+
+ ret = hclge_dbg_cmd_send(hdev, desc, 0, bd_num, reg_msg->cmd);
if (ret) {
- kfree(desc_src);
- return;
+ kfree(desc);
+ return ret;
}
- entries_per_desc = ARRAY_SIZE(desc->data);
- min_num = min_t(int, bd_num * entries_per_desc, reg_msg->msg_num);
+ min_num = min_t(int, bd_num * HCLGE_DESC_DATA_LEN, reg_msg->msg_num);
- desc = desc_src;
- for (i = 0; i < min_num; i++) {
- if (i > 0 && (i % entries_per_desc) == 0)
+ for (i = 0; i < min_num; i++, dfx_message++) {
+ entry = i % HCLGE_DESC_DATA_LEN;
+ if (i > 0 && !entry)
desc++;
- if (dfx_message->flag)
- dev_info(&hdev->pdev->dev, "%s: 0x%x\n",
- dfx_message->message,
- le32_to_cpu(desc->data[i % entries_per_desc]));
+ if (!dfx_message->flag)
+ continue;
- dfx_message++;
+ *pos += scnprintf(buf + *pos, len - *pos, "%s: %#x\n",
+ dfx_message->message,
+ le32_to_cpu(desc->data[entry]));
}
kfree(desc_src);
+ return 0;
}
-static void hclge_dbg_dump_mac_enable_status(struct hclge_dev *hdev)
+static int hclge_dbg_dump_mac_enable_status(struct hclge_dev *hdev, char *buf,
+ int len, int *pos)
{
struct hclge_config_mac_mode_cmd *req;
struct hclge_desc desc;
@@ -186,43 +272,51 @@ static void hclge_dbg_dump_mac_enable_status(struct hclge_dev *hdev)
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to dump mac enable status, ret = %d\n", ret);
- return;
+ return ret;
}
req = (struct hclge_config_mac_mode_cmd *)desc.data;
loop_en = le32_to_cpu(req->txrx_pad_fcs_loop_en);
- dev_info(&hdev->pdev->dev, "config_mac_trans_en: %#x\n",
- hnae3_get_bit(loop_en, HCLGE_MAC_TX_EN_B));
- dev_info(&hdev->pdev->dev, "config_mac_rcv_en: %#x\n",
- hnae3_get_bit(loop_en, HCLGE_MAC_RX_EN_B));
- dev_info(&hdev->pdev->dev, "config_pad_trans_en: %#x\n",
- hnae3_get_bit(loop_en, HCLGE_MAC_PAD_TX_B));
- dev_info(&hdev->pdev->dev, "config_pad_rcv_en: %#x\n",
- hnae3_get_bit(loop_en, HCLGE_MAC_PAD_RX_B));
- dev_info(&hdev->pdev->dev, "config_1588_trans_en: %#x\n",
- hnae3_get_bit(loop_en, HCLGE_MAC_1588_TX_B));
- dev_info(&hdev->pdev->dev, "config_1588_rcv_en: %#x\n",
- hnae3_get_bit(loop_en, HCLGE_MAC_1588_RX_B));
- dev_info(&hdev->pdev->dev, "config_mac_app_loop_en: %#x\n",
- hnae3_get_bit(loop_en, HCLGE_MAC_APP_LP_B));
- dev_info(&hdev->pdev->dev, "config_mac_line_loop_en: %#x\n",
- hnae3_get_bit(loop_en, HCLGE_MAC_LINE_LP_B));
- dev_info(&hdev->pdev->dev, "config_mac_fcs_tx_en: %#x\n",
- hnae3_get_bit(loop_en, HCLGE_MAC_FCS_TX_B));
- dev_info(&hdev->pdev->dev, "config_mac_rx_oversize_truncate_en: %#x\n",
- hnae3_get_bit(loop_en, HCLGE_MAC_RX_OVERSIZE_TRUNCATE_B));
- dev_info(&hdev->pdev->dev, "config_mac_rx_fcs_strip_en: %#x\n",
- hnae3_get_bit(loop_en, HCLGE_MAC_RX_FCS_STRIP_B));
- dev_info(&hdev->pdev->dev, "config_mac_rx_fcs_en: %#x\n",
- hnae3_get_bit(loop_en, HCLGE_MAC_RX_FCS_B));
- dev_info(&hdev->pdev->dev, "config_mac_tx_under_min_err_en: %#x\n",
- hnae3_get_bit(loop_en, HCLGE_MAC_TX_UNDER_MIN_ERR_B));
- dev_info(&hdev->pdev->dev, "config_mac_tx_oversize_truncate_en: %#x\n",
- hnae3_get_bit(loop_en, HCLGE_MAC_TX_OVERSIZE_TRUNCATE_B));
-}
-
-static void hclge_dbg_dump_mac_frame_size(struct hclge_dev *hdev)
+ *pos += scnprintf(buf + *pos, len - *pos, "mac_trans_en: %#x\n",
+ hnae3_get_bit(loop_en, HCLGE_MAC_TX_EN_B));
+ *pos += scnprintf(buf + *pos, len - *pos, "mac_rcv_en: %#x\n",
+ hnae3_get_bit(loop_en, HCLGE_MAC_RX_EN_B));
+ *pos += scnprintf(buf + *pos, len - *pos, "pad_trans_en: %#x\n",
+ hnae3_get_bit(loop_en, HCLGE_MAC_PAD_TX_B));
+ *pos += scnprintf(buf + *pos, len - *pos, "pad_rcv_en: %#x\n",
+ hnae3_get_bit(loop_en, HCLGE_MAC_PAD_RX_B));
+ *pos += scnprintf(buf + *pos, len - *pos, "1588_trans_en: %#x\n",
+ hnae3_get_bit(loop_en, HCLGE_MAC_1588_TX_B));
+ *pos += scnprintf(buf + *pos, len - *pos, "1588_rcv_en: %#x\n",
+ hnae3_get_bit(loop_en, HCLGE_MAC_1588_RX_B));
+ *pos += scnprintf(buf + *pos, len - *pos, "mac_app_loop_en: %#x\n",
+ hnae3_get_bit(loop_en, HCLGE_MAC_APP_LP_B));
+ *pos += scnprintf(buf + *pos, len - *pos, "mac_line_loop_en: %#x\n",
+ hnae3_get_bit(loop_en, HCLGE_MAC_LINE_LP_B));
+ *pos += scnprintf(buf + *pos, len - *pos, "mac_fcs_tx_en: %#x\n",
+ hnae3_get_bit(loop_en, HCLGE_MAC_FCS_TX_B));
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "mac_rx_oversize_truncate_en: %#x\n",
+ hnae3_get_bit(loop_en,
+ HCLGE_MAC_RX_OVERSIZE_TRUNCATE_B));
+ *pos += scnprintf(buf + *pos, len - *pos, "mac_rx_fcs_strip_en: %#x\n",
+ hnae3_get_bit(loop_en, HCLGE_MAC_RX_FCS_STRIP_B));
+ *pos += scnprintf(buf + *pos, len - *pos, "mac_rx_fcs_en: %#x\n",
+ hnae3_get_bit(loop_en, HCLGE_MAC_RX_FCS_B));
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "mac_tx_under_min_err_en: %#x\n",
+ hnae3_get_bit(loop_en, HCLGE_MAC_TX_UNDER_MIN_ERR_B));
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "mac_tx_oversize_truncate_en: %#x\n",
+ hnae3_get_bit(loop_en,
+ HCLGE_MAC_TX_OVERSIZE_TRUNCATE_B));
+
+ return 0;
+}
+
+static int hclge_dbg_dump_mac_frame_size(struct hclge_dev *hdev, char *buf,
+ int len, int *pos)
{
struct hclge_config_max_frm_size_cmd *req;
struct hclge_desc desc;
@@ -234,17 +328,21 @@ static void hclge_dbg_dump_mac_frame_size(struct hclge_dev *hdev)
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to dump mac frame size, ret = %d\n", ret);
- return;
+ return ret;
}
req = (struct hclge_config_max_frm_size_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "max_frame_size: %u\n",
- le16_to_cpu(req->max_frm_size));
- dev_info(&hdev->pdev->dev, "min_frame_size: %u\n", req->min_frm_size);
+ *pos += scnprintf(buf + *pos, len - *pos, "max_frame_size: %u\n",
+ le16_to_cpu(req->max_frm_size));
+ *pos += scnprintf(buf + *pos, len - *pos, "min_frame_size: %u\n",
+ req->min_frm_size);
+
+ return 0;
}
-static void hclge_dbg_dump_mac_speed_duplex(struct hclge_dev *hdev)
+static int hclge_dbg_dump_mac_speed_duplex(struct hclge_dev *hdev, char *buf,
+ int len, int *pos)
{
#define HCLGE_MAC_SPEED_SHIFT 0
#define HCLGE_MAC_SPEED_MASK GENMASK(5, 0)
@@ -260,543 +358,540 @@ static void hclge_dbg_dump_mac_speed_duplex(struct hclge_dev *hdev)
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to dump mac speed duplex, ret = %d\n", ret);
- return;
+ return ret;
}
req = (struct hclge_config_mac_speed_dup_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "speed: %#lx\n",
- hnae3_get_field(req->speed_dup, HCLGE_MAC_SPEED_MASK,
- HCLGE_MAC_SPEED_SHIFT));
- dev_info(&hdev->pdev->dev, "duplex: %#x\n",
- hnae3_get_bit(req->speed_dup, HCLGE_MAC_DUPLEX_SHIFT));
+ *pos += scnprintf(buf + *pos, len - *pos, "speed: %#lx\n",
+ hnae3_get_field(req->speed_dup, HCLGE_MAC_SPEED_MASK,
+ HCLGE_MAC_SPEED_SHIFT));
+ *pos += scnprintf(buf + *pos, len - *pos, "duplex: %#x\n",
+ hnae3_get_bit(req->speed_dup,
+ HCLGE_MAC_DUPLEX_SHIFT));
+ return 0;
}
-static void hclge_dbg_dump_mac(struct hclge_dev *hdev)
+static int hclge_dbg_dump_mac(struct hclge_dev *hdev, char *buf, int len)
{
- hclge_dbg_dump_mac_enable_status(hdev);
+ int pos = 0;
+ int ret;
- hclge_dbg_dump_mac_frame_size(hdev);
+ ret = hclge_dbg_dump_mac_enable_status(hdev, buf, len, &pos);
+ if (ret)
+ return ret;
- hclge_dbg_dump_mac_speed_duplex(hdev);
+ ret = hclge_dbg_dump_mac_frame_size(hdev, buf, len, &pos);
+ if (ret)
+ return ret;
+
+ return hclge_dbg_dump_mac_speed_duplex(hdev, buf, len, &pos);
}
-static void hclge_dbg_dump_dcb(struct hclge_dev *hdev, const char *cmd_buf)
+static int hclge_dbg_dump_dcb_qset(struct hclge_dev *hdev, char *buf, int len,
+ int *pos)
{
- struct device *dev = &hdev->pdev->dev;
struct hclge_dbg_bitmap_cmd *bitmap;
- enum hclge_opcode_type cmd;
- int rq_id, pri_id, qset_id;
- int port_id, nq_id, pg_id;
- struct hclge_desc desc[2];
-
- int cnt, ret;
-
- cnt = sscanf(cmd_buf, "%i %i %i %i %i %i",
- &port_id, &pri_id, &pg_id, &rq_id, &nq_id, &qset_id);
- if (cnt != 6) {
- dev_err(&hdev->pdev->dev,
- "dump dcb: bad command parameter, cnt=%d\n", cnt);
- return;
- }
+ struct hclge_desc desc;
+ u16 qset_id, qset_num;
+ int ret;
- cmd = HCLGE_OPC_QSET_DFX_STS;
- ret = hclge_dbg_cmd_send(hdev, desc, qset_id, 1, cmd);
+ ret = hclge_tm_get_qset_num(hdev, &qset_num);
if (ret)
- goto err_dcb_cmd_send;
+ return ret;
- bitmap = (struct hclge_dbg_bitmap_cmd *)&desc[0].data[1];
- dev_info(dev, "roce_qset_mask: 0x%x\n", bitmap->bit0);
- dev_info(dev, "nic_qs_mask: 0x%x\n", bitmap->bit1);
- dev_info(dev, "qs_shaping_pass: 0x%x\n", bitmap->bit2);
- dev_info(dev, "qs_bp_sts: 0x%x\n", bitmap->bit3);
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "qset_id roce_qset_mask nic_qset_mask qset_shaping_pass qset_bp_status\n");
+ for (qset_id = 0; qset_id < qset_num; qset_id++) {
+ ret = hclge_dbg_cmd_send(hdev, &desc, qset_id, 1,
+ HCLGE_OPC_QSET_DFX_STS);
+ if (ret)
+ return ret;
- cmd = HCLGE_OPC_PRI_DFX_STS;
- ret = hclge_dbg_cmd_send(hdev, desc, pri_id, 1, cmd);
- if (ret)
- goto err_dcb_cmd_send;
+ bitmap = (struct hclge_dbg_bitmap_cmd *)&desc.data[1];
- bitmap = (struct hclge_dbg_bitmap_cmd *)&desc[0].data[1];
- dev_info(dev, "pri_mask: 0x%x\n", bitmap->bit0);
- dev_info(dev, "pri_cshaping_pass: 0x%x\n", bitmap->bit1);
- dev_info(dev, "pri_pshaping_pass: 0x%x\n", bitmap->bit2);
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "%04u %#x %#x %#x %#x\n",
+ qset_id, bitmap->bit0, bitmap->bit1,
+ bitmap->bit2, bitmap->bit3);
+ }
- cmd = HCLGE_OPC_PG_DFX_STS;
- ret = hclge_dbg_cmd_send(hdev, desc, pg_id, 1, cmd);
- if (ret)
- goto err_dcb_cmd_send;
+ return 0;
+}
- bitmap = (struct hclge_dbg_bitmap_cmd *)&desc[0].data[1];
- dev_info(dev, "pg_mask: 0x%x\n", bitmap->bit0);
- dev_info(dev, "pg_cshaping_pass: 0x%x\n", bitmap->bit1);
- dev_info(dev, "pg_pshaping_pass: 0x%x\n", bitmap->bit2);
+static int hclge_dbg_dump_dcb_pri(struct hclge_dev *hdev, char *buf, int len,
+ int *pos)
+{
+ struct hclge_dbg_bitmap_cmd *bitmap;
+ struct hclge_desc desc;
+ u8 pri_id, pri_num;
+ int ret;
- cmd = HCLGE_OPC_PORT_DFX_STS;
- ret = hclge_dbg_cmd_send(hdev, desc, port_id, 1, cmd);
+ ret = hclge_tm_get_pri_num(hdev, &pri_num);
if (ret)
- goto err_dcb_cmd_send;
-
- bitmap = (struct hclge_dbg_bitmap_cmd *)&desc[0].data[1];
- dev_info(dev, "port_mask: 0x%x\n", bitmap->bit0);
- dev_info(dev, "port_shaping_pass: 0x%x\n", bitmap->bit1);
+ return ret;
- cmd = HCLGE_OPC_SCH_NQ_CNT;
- ret = hclge_dbg_cmd_send(hdev, desc, nq_id, 1, cmd);
- if (ret)
- goto err_dcb_cmd_send;
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "pri_id pri_mask pri_cshaping_pass pri_pshaping_pass\n");
+ for (pri_id = 0; pri_id < pri_num; pri_id++) {
+ ret = hclge_dbg_cmd_send(hdev, &desc, pri_id, 1,
+ HCLGE_OPC_PRI_DFX_STS);
+ if (ret)
+ return ret;
- dev_info(dev, "sch_nq_cnt: 0x%x\n", le32_to_cpu(desc[0].data[1]));
+ bitmap = (struct hclge_dbg_bitmap_cmd *)&desc.data[1];
- cmd = HCLGE_OPC_SCH_RQ_CNT;
- ret = hclge_dbg_cmd_send(hdev, desc, nq_id, 1, cmd);
- if (ret)
- goto err_dcb_cmd_send;
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "%03u %#x %#x %#x\n",
+ pri_id, bitmap->bit0, bitmap->bit1,
+ bitmap->bit2);
+ }
- dev_info(dev, "sch_rq_cnt: 0x%x\n", le32_to_cpu(desc[0].data[1]));
+ return 0;
+}
- cmd = HCLGE_OPC_TM_INTERNAL_STS;
- ret = hclge_dbg_cmd_send(hdev, desc, 0, 2, cmd);
- if (ret)
- goto err_dcb_cmd_send;
-
- dev_info(dev, "pri_bp: 0x%x\n", le32_to_cpu(desc[0].data[1]));
- dev_info(dev, "fifo_dfx_info: 0x%x\n", le32_to_cpu(desc[0].data[2]));
- dev_info(dev, "sch_roce_fifo_afull_gap: 0x%x\n",
- le32_to_cpu(desc[0].data[3]));
- dev_info(dev, "tx_private_waterline: 0x%x\n",
- le32_to_cpu(desc[0].data[4]));
- dev_info(dev, "tm_bypass_en: 0x%x\n", le32_to_cpu(desc[0].data[5]));
- dev_info(dev, "SSU_TM_BYPASS_EN: 0x%x\n", le32_to_cpu(desc[1].data[0]));
- dev_info(dev, "SSU_RESERVE_CFG: 0x%x\n", le32_to_cpu(desc[1].data[1]));
-
- cmd = HCLGE_OPC_TM_INTERNAL_CNT;
- ret = hclge_dbg_cmd_send(hdev, desc, port_id, 1, cmd);
- if (ret)
- goto err_dcb_cmd_send;
+static int hclge_dbg_dump_dcb_pg(struct hclge_dev *hdev, char *buf, int len,
+ int *pos)
+{
+ struct hclge_dbg_bitmap_cmd *bitmap;
+ struct hclge_desc desc;
+ u8 pg_id;
+ int ret;
- dev_info(dev, "SCH_NIC_NUM: 0x%x\n", le32_to_cpu(desc[0].data[1]));
- dev_info(dev, "SCH_ROCE_NUM: 0x%x\n", le32_to_cpu(desc[0].data[2]));
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "pg_id pg_mask pg_cshaping_pass pg_pshaping_pass\n");
+ for (pg_id = 0; pg_id < hdev->tm_info.num_pg; pg_id++) {
+ ret = hclge_dbg_cmd_send(hdev, &desc, pg_id, 1,
+ HCLGE_OPC_PG_DFX_STS);
+ if (ret)
+ return ret;
- cmd = HCLGE_OPC_TM_INTERNAL_STS_1;
- ret = hclge_dbg_cmd_send(hdev, desc, port_id, 1, cmd);
- if (ret)
- goto err_dcb_cmd_send;
+ bitmap = (struct hclge_dbg_bitmap_cmd *)&desc.data[1];
- dev_info(dev, "TC_MAP_SEL: 0x%x\n", le32_to_cpu(desc[0].data[1]));
- dev_info(dev, "IGU_PFC_PRI_EN: 0x%x\n", le32_to_cpu(desc[0].data[2]));
- dev_info(dev, "MAC_PFC_PRI_EN: 0x%x\n", le32_to_cpu(desc[0].data[3]));
- dev_info(dev, "IGU_PRI_MAP_TC_CFG: 0x%x\n",
- le32_to_cpu(desc[0].data[4]));
- dev_info(dev, "IGU_TX_PRI_MAP_TC_CFG: 0x%x\n",
- le32_to_cpu(desc[0].data[5]));
- return;
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "%03u %#x %#x %#x\n",
+ pg_id, bitmap->bit0, bitmap->bit1,
+ bitmap->bit2);
+ }
-err_dcb_cmd_send:
- dev_err(&hdev->pdev->dev,
- "failed to dump dcb dfx, cmd = %#x, ret = %d\n",
- cmd, ret);
+ return 0;
}
-static void hclge_dbg_dump_reg_cmd(struct hclge_dev *hdev, const char *cmd_buf)
+static int hclge_dbg_dump_dcb_queue(struct hclge_dev *hdev, char *buf, int len,
+ int *pos)
{
- const struct hclge_dbg_reg_type_info *reg_info;
- bool has_dump = false;
- int i;
+ struct hclge_desc desc;
+ u16 nq_id;
+ int ret;
- for (i = 0; i < ARRAY_SIZE(hclge_dbg_reg_info); i++) {
- reg_info = &hclge_dbg_reg_info[i];
- if (!strncmp(cmd_buf, reg_info->reg_type,
- strlen(reg_info->reg_type))) {
- hclge_dbg_dump_reg_common(hdev, reg_info, cmd_buf);
- has_dump = true;
- }
- }
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "nq_id sch_nic_queue_cnt sch_roce_queue_cnt\n");
+ for (nq_id = 0; nq_id < hdev->num_tqps; nq_id++) {
+ ret = hclge_dbg_cmd_send(hdev, &desc, nq_id, 1,
+ HCLGE_OPC_SCH_NQ_CNT);
+ if (ret)
+ return ret;
- if (strncmp(cmd_buf, "mac", strlen("mac")) == 0) {
- hclge_dbg_dump_mac(hdev);
- has_dump = true;
- }
+ *pos += scnprintf(buf + *pos, len - *pos, "%04u %#x",
+ nq_id, le32_to_cpu(desc.data[1]));
- if (strncmp(cmd_buf, "dcb", 3) == 0) {
- hclge_dbg_dump_dcb(hdev, &cmd_buf[sizeof("dcb")]);
- has_dump = true;
- }
+ ret = hclge_dbg_cmd_send(hdev, &desc, nq_id, 1,
+ HCLGE_OPC_SCH_RQ_CNT);
+ if (ret)
+ return ret;
- if (!has_dump) {
- dev_info(&hdev->pdev->dev, "unknown command\n");
- return;
+ *pos += scnprintf(buf + *pos, len - *pos,
+ " %#x\n",
+ le32_to_cpu(desc.data[1]));
}
-}
-static void hclge_print_tc_info(struct hclge_dev *hdev, bool flag, int index)
-{
- if (flag)
- dev_info(&hdev->pdev->dev, "tc(%d): no sp mode weight: %u\n",
- index, hdev->tm_info.pg_info[0].tc_dwrr[index]);
- else
- dev_info(&hdev->pdev->dev, "tc(%d): sp mode\n", index);
+ return 0;
}
-static void hclge_dbg_dump_tc(struct hclge_dev *hdev)
+static int hclge_dbg_dump_dcb_port(struct hclge_dev *hdev, char *buf, int len,
+ int *pos)
{
- struct hclge_ets_tc_weight_cmd *ets_weight;
+ struct hclge_dbg_bitmap_cmd *bitmap;
struct hclge_desc desc;
- int i, ret;
-
- if (!hnae3_dev_dcb_supported(hdev)) {
- dev_info(&hdev->pdev->dev,
- "Only DCB-supported dev supports tc\n");
- return;
- }
-
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_ETS_TC_WEIGHT, true);
+ u8 port_id = 0;
+ int ret;
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret) {
- dev_err(&hdev->pdev->dev, "dump tc fail, ret = %d\n", ret);
- return;
- }
+ ret = hclge_dbg_cmd_send(hdev, &desc, port_id, 1,
+ HCLGE_OPC_PORT_DFX_STS);
+ if (ret)
+ return ret;
- ets_weight = (struct hclge_ets_tc_weight_cmd *)desc.data;
+ bitmap = (struct hclge_dbg_bitmap_cmd *)&desc.data[1];
- dev_info(&hdev->pdev->dev, "dump tc: %u tc enabled\n",
- hdev->tm_info.num_tc);
- dev_info(&hdev->pdev->dev, "weight_offset: %u\n",
- ets_weight->weight_offset);
+ *pos += scnprintf(buf + *pos, len - *pos, "port_mask: %#x\n",
+ bitmap->bit0);
+ *pos += scnprintf(buf + *pos, len - *pos, "port_shaping_pass: %#x\n",
+ bitmap->bit1);
- for (i = 0; i < HNAE3_MAX_TC; i++)
- hclge_print_tc_info(hdev, ets_weight->tc_weight[i], i);
+ return 0;
}
-static void hclge_dbg_dump_tm_pg(struct hclge_dev *hdev)
+static int hclge_dbg_dump_dcb_tm(struct hclge_dev *hdev, char *buf, int len,
+ int *pos)
{
- struct hclge_port_shapping_cmd *port_shap_cfg_cmd;
- struct hclge_bp_to_qs_map_cmd *bp_to_qs_map_cmd;
- struct hclge_pg_shapping_cmd *pg_shap_cfg_cmd;
- enum hclge_opcode_type cmd;
- struct hclge_desc desc;
+ struct hclge_desc desc[2];
+ u8 port_id = 0;
int ret;
- cmd = HCLGE_OPC_TM_PG_C_SHAPPING;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ ret = hclge_dbg_cmd_send(hdev, desc, port_id, 1,
+ HCLGE_OPC_TM_INTERNAL_CNT);
if (ret)
- goto err_tm_pg_cmd_send;
+ return ret;
- pg_shap_cfg_cmd = (struct hclge_pg_shapping_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "PG_C pg_id: %u\n", pg_shap_cfg_cmd->pg_id);
- dev_info(&hdev->pdev->dev, "PG_C pg_shapping: 0x%x\n",
- le32_to_cpu(pg_shap_cfg_cmd->pg_shapping_para));
+ *pos += scnprintf(buf + *pos, len - *pos, "SCH_NIC_NUM: %#x\n",
+ le32_to_cpu(desc[0].data[1]));
+ *pos += scnprintf(buf + *pos, len - *pos, "SCH_ROCE_NUM: %#x\n",
+ le32_to_cpu(desc[0].data[2]));
- cmd = HCLGE_OPC_TM_PG_P_SHAPPING;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ ret = hclge_dbg_cmd_send(hdev, desc, port_id, 2,
+ HCLGE_OPC_TM_INTERNAL_STS);
if (ret)
- goto err_tm_pg_cmd_send;
-
- pg_shap_cfg_cmd = (struct hclge_pg_shapping_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "PG_P pg_id: %u\n", pg_shap_cfg_cmd->pg_id);
- dev_info(&hdev->pdev->dev, "PG_P pg_shapping: 0x%x\n",
- le32_to_cpu(pg_shap_cfg_cmd->pg_shapping_para));
- dev_info(&hdev->pdev->dev, "PG_P flag: %#x\n", pg_shap_cfg_cmd->flag);
- dev_info(&hdev->pdev->dev, "PG_P pg_rate: %u(Mbps)\n",
- le32_to_cpu(pg_shap_cfg_cmd->pg_rate));
-
- cmd = HCLGE_OPC_TM_PORT_SHAPPING;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ return ret;
+
+ *pos += scnprintf(buf + *pos, len - *pos, "pri_bp: %#x\n",
+ le32_to_cpu(desc[0].data[1]));
+ *pos += scnprintf(buf + *pos, len - *pos, "fifo_dfx_info: %#x\n",
+ le32_to_cpu(desc[0].data[2]));
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "sch_roce_fifo_afull_gap: %#x\n",
+ le32_to_cpu(desc[0].data[3]));
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "tx_private_waterline: %#x\n",
+ le32_to_cpu(desc[0].data[4]));
+ *pos += scnprintf(buf + *pos, len - *pos, "tm_bypass_en: %#x\n",
+ le32_to_cpu(desc[0].data[5]));
+ *pos += scnprintf(buf + *pos, len - *pos, "SSU_TM_BYPASS_EN: %#x\n",
+ le32_to_cpu(desc[1].data[0]));
+ *pos += scnprintf(buf + *pos, len - *pos, "SSU_RESERVE_CFG: %#x\n",
+ le32_to_cpu(desc[1].data[1]));
+
+ if (hdev->hw.mac.media_type == HNAE3_MEDIA_TYPE_COPPER)
+ return 0;
+
+ ret = hclge_dbg_cmd_send(hdev, desc, port_id, 1,
+ HCLGE_OPC_TM_INTERNAL_STS_1);
if (ret)
- goto err_tm_pg_cmd_send;
+ return ret;
- port_shap_cfg_cmd = (struct hclge_port_shapping_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "PORT port_shapping: 0x%x\n",
- le32_to_cpu(port_shap_cfg_cmd->port_shapping_para));
- dev_info(&hdev->pdev->dev, "PORT flag: %#x\n", port_shap_cfg_cmd->flag);
- dev_info(&hdev->pdev->dev, "PORT port_rate: %u(Mbps)\n",
- le32_to_cpu(port_shap_cfg_cmd->port_rate));
+ *pos += scnprintf(buf + *pos, len - *pos, "TC_MAP_SEL: %#x\n",
+ le32_to_cpu(desc[0].data[1]));
+ *pos += scnprintf(buf + *pos, len - *pos, "IGU_PFC_PRI_EN: %#x\n",
+ le32_to_cpu(desc[0].data[2]));
+ *pos += scnprintf(buf + *pos, len - *pos, "MAC_PFC_PRI_EN: %#x\n",
+ le32_to_cpu(desc[0].data[3]));
+ *pos += scnprintf(buf + *pos, len - *pos, "IGU_PRI_MAP_TC_CFG: %#x\n",
+ le32_to_cpu(desc[0].data[4]));
+ *pos += scnprintf(buf + *pos, len - *pos,
+ "IGU_TX_PRI_MAP_TC_CFG: %#x\n",
+ le32_to_cpu(desc[0].data[5]));
- cmd = HCLGE_OPC_TM_PG_SCH_MODE_CFG;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ return 0;
+}
+
+static int hclge_dbg_dump_dcb(struct hclge_dev *hdev, char *buf, int len)
+{
+ int pos = 0;
+ int ret;
+
+ ret = hclge_dbg_dump_dcb_qset(hdev, buf, len, &pos);
if (ret)
- goto err_tm_pg_cmd_send;
+ return ret;
- dev_info(&hdev->pdev->dev, "PG_SCH pg_id: %u\n",
- le32_to_cpu(desc.data[0]));
+ ret = hclge_dbg_dump_dcb_pri(hdev, buf, len, &pos);
+ if (ret)
+ return ret;
- cmd = HCLGE_OPC_TM_PRI_SCH_MODE_CFG;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ ret = hclge_dbg_dump_dcb_pg(hdev, buf, len, &pos);
if (ret)
- goto err_tm_pg_cmd_send;
+ return ret;
- dev_info(&hdev->pdev->dev, "PRI_SCH pri_id: %u\n",
- le32_to_cpu(desc.data[0]));
+ ret = hclge_dbg_dump_dcb_queue(hdev, buf, len, &pos);
+ if (ret)
+ return ret;
- cmd = HCLGE_OPC_TM_QS_SCH_MODE_CFG;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ ret = hclge_dbg_dump_dcb_port(hdev, buf, len, &pos);
if (ret)
- goto err_tm_pg_cmd_send;
+ return ret;
- dev_info(&hdev->pdev->dev, "QS_SCH qs_id: %u\n",
- le32_to_cpu(desc.data[0]));
+ return hclge_dbg_dump_dcb_tm(hdev, buf, len, &pos);
+}
- if (!hnae3_dev_dcb_supported(hdev)) {
- dev_info(&hdev->pdev->dev,
- "Only DCB-supported dev supports tm mapping\n");
- return;
+static int hclge_dbg_dump_reg_cmd(struct hclge_dev *hdev,
+ enum hnae3_dbg_cmd cmd, char *buf, int len)
+{
+ const struct hclge_dbg_reg_type_info *reg_info;
+ int pos = 0, ret = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hclge_dbg_reg_info); i++) {
+ reg_info = &hclge_dbg_reg_info[i];
+ if (cmd == reg_info->cmd) {
+ if (cmd == HNAE3_DBG_CMD_REG_TQP)
+ return hclge_dbg_dump_reg_tqp(hdev, reg_info,
+ buf, len, &pos);
+
+ ret = hclge_dbg_dump_reg_common(hdev, reg_info, buf,
+ len, &pos);
+ if (ret)
+ break;
+ }
}
- cmd = HCLGE_OPC_TM_BP_TO_QSET_MAPPING;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- 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 tc_id: %u\n",
- bp_to_qs_map_cmd->tc_id);
- 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",
- le32_to_cpu(bp_to_qs_map_cmd->qs_bit_map));
- return;
-
-err_tm_pg_cmd_send:
- dev_err(&hdev->pdev->dev, "dump tm_pg fail(0x%x), ret = %d\n",
- cmd, ret);
-}
-
-static void hclge_dbg_dump_tm(struct hclge_dev *hdev)
-{
- struct hclge_priority_weight_cmd *priority_weight;
- struct hclge_pg_to_pri_link_cmd *pg_to_pri_map;
- struct hclge_qs_to_pri_link_cmd *qs_to_pri_map;
- struct hclge_nq_to_qs_link_cmd *nq_to_qs_map;
- struct hclge_pri_shapping_cmd *shap_cfg_cmd;
- struct hclge_pg_weight_cmd *pg_weight;
- struct hclge_qs_weight_cmd *qs_weight;
- enum hclge_opcode_type cmd;
+ return ret;
+}
+
+static int hclge_dbg_dump_tc(struct hclge_dev *hdev, char *buf, int len)
+{
+ struct hclge_ets_tc_weight_cmd *ets_weight;
struct hclge_desc desc;
+ char *sch_mode_str;
+ int pos = 0;
int ret;
+ u8 i;
- cmd = HCLGE_OPC_TM_PG_TO_PRI_LINK;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
+ if (!hnae3_dev_dcb_supported(hdev)) {
+ dev_err(&hdev->pdev->dev,
+ "Only DCB-supported dev supports tc\n");
+ return -EOPNOTSUPP;
+ }
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_ETS_TC_WEIGHT, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- goto err_tm_cmd_send;
+ if (ret) {
+ dev_err(&hdev->pdev->dev, "failed to get tc weight, ret = %d\n",
+ ret);
+ return ret;
+ }
- pg_to_pri_map = (struct hclge_pg_to_pri_link_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "dump tm\n");
- dev_info(&hdev->pdev->dev, "PG_TO_PRI gp_id: %u\n",
- pg_to_pri_map->pg_id);
- dev_info(&hdev->pdev->dev, "PG_TO_PRI map: 0x%x\n",
- pg_to_pri_map->pri_bit_map);
+ ets_weight = (struct hclge_ets_tc_weight_cmd *)desc.data;
- cmd = HCLGE_OPC_TM_QS_TO_PRI_LINK;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- goto err_tm_cmd_send;
-
- qs_to_pri_map = (struct hclge_qs_to_pri_link_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "QS_TO_PRI qs_id: %u\n",
- le16_to_cpu(qs_to_pri_map->qs_id));
- dev_info(&hdev->pdev->dev, "QS_TO_PRI priority: %u\n",
- qs_to_pri_map->priority);
- dev_info(&hdev->pdev->dev, "QS_TO_PRI link_vld: %u\n",
- qs_to_pri_map->link_vld);
-
- cmd = HCLGE_OPC_TM_NQ_TO_QS_LINK;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- goto err_tm_cmd_send;
+ pos += scnprintf(buf + pos, len - pos, "enabled tc number: %u\n",
+ hdev->tm_info.num_tc);
+ pos += scnprintf(buf + pos, len - pos, "weight_offset: %u\n",
+ ets_weight->weight_offset);
+
+ pos += scnprintf(buf + pos, len - pos, "TC MODE WEIGHT\n");
+ for (i = 0; i < HNAE3_MAX_TC; i++) {
+ sch_mode_str = ets_weight->tc_weight[i] ? "dwrr" : "sp";
+ pos += scnprintf(buf + pos, len - pos, "%u %4s %3u\n",
+ i, sch_mode_str,
+ hdev->tm_info.pg_info[0].tc_dwrr[i]);
+ }
- 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",
- le16_to_cpu(nq_to_qs_map->nq_id));
- dev_info(&hdev->pdev->dev, "NQ_TO_QS qset_id: 0x%x\n",
- le16_to_cpu(nq_to_qs_map->qset_id));
+ return 0;
+}
- cmd = HCLGE_OPC_TM_PG_WEIGHT;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- goto err_tm_cmd_send;
+static const struct hclge_dbg_item tm_pg_items[] = {
+ { "ID", 2 },
+ { "PRI_MAP", 2 },
+ { "MODE", 2 },
+ { "DWRR", 2 },
+ { "C_IR_B", 2 },
+ { "C_IR_U", 2 },
+ { "C_IR_S", 2 },
+ { "C_BS_B", 2 },
+ { "C_BS_S", 2 },
+ { "C_FLAG", 2 },
+ { "C_RATE(Mbps)", 2 },
+ { "P_IR_B", 2 },
+ { "P_IR_U", 2 },
+ { "P_IR_S", 2 },
+ { "P_BS_B", 2 },
+ { "P_BS_S", 2 },
+ { "P_FLAG", 2 },
+ { "P_RATE(Mbps)", 0 }
+};
- pg_weight = (struct hclge_pg_weight_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "PG pg_id: %u\n", pg_weight->pg_id);
- dev_info(&hdev->pdev->dev, "PG dwrr: %u\n", pg_weight->dwrr);
+static void hclge_dbg_fill_shaper_content(struct hclge_tm_shaper_para *para,
+ char **result, u8 *index)
+{
+ sprintf(result[(*index)++], "%3u", para->ir_b);
+ sprintf(result[(*index)++], "%3u", para->ir_u);
+ sprintf(result[(*index)++], "%3u", para->ir_s);
+ sprintf(result[(*index)++], "%3u", para->bs_b);
+ sprintf(result[(*index)++], "%3u", para->bs_s);
+ sprintf(result[(*index)++], "%3u", para->flag);
+ sprintf(result[(*index)++], "%6u", para->rate);
+}
- cmd = HCLGE_OPC_TM_QS_WEIGHT;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- goto err_tm_cmd_send;
+static int hclge_dbg_dump_tm_pg(struct hclge_dev *hdev, char *buf, int len)
+{
+ char data_str[ARRAY_SIZE(tm_pg_items)][HCLGE_DBG_DATA_STR_LEN];
+ struct hclge_tm_shaper_para c_shaper_para, p_shaper_para;
+ char *result[ARRAY_SIZE(tm_pg_items)], *sch_mode_str;
+ u8 pg_id, sch_mode, weight, pri_bit_map, i, j;
+ char content[HCLGE_DBG_TM_INFO_LEN];
+ int pos = 0;
+ int ret;
- qs_weight = (struct hclge_qs_weight_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "QS qs_id: %u\n",
- le16_to_cpu(qs_weight->qs_id));
- dev_info(&hdev->pdev->dev, "QS dwrr: %u\n", qs_weight->dwrr);
+ for (i = 0; i < ARRAY_SIZE(tm_pg_items); i++)
+ result[i] = &data_str[i][0];
- cmd = HCLGE_OPC_TM_PRI_WEIGHT;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- goto err_tm_cmd_send;
+ hclge_dbg_fill_content(content, sizeof(content), tm_pg_items,
+ NULL, ARRAY_SIZE(tm_pg_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
- priority_weight = (struct hclge_priority_weight_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "PRI pri_id: %u\n", priority_weight->pri_id);
- dev_info(&hdev->pdev->dev, "PRI dwrr: %u\n", priority_weight->dwrr);
+ for (pg_id = 0; pg_id < hdev->tm_info.num_pg; pg_id++) {
+ ret = hclge_tm_get_pg_to_pri_map(hdev, pg_id, &pri_bit_map);
+ if (ret)
+ return ret;
- cmd = HCLGE_OPC_TM_PRI_C_SHAPPING;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- goto err_tm_cmd_send;
-
- shap_cfg_cmd = (struct hclge_pri_shapping_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "PRI_C pri_id: %u\n", shap_cfg_cmd->pri_id);
- dev_info(&hdev->pdev->dev, "PRI_C pri_shapping: 0x%x\n",
- le32_to_cpu(shap_cfg_cmd->pri_shapping_para));
- dev_info(&hdev->pdev->dev, "PRI_C flag: %#x\n", shap_cfg_cmd->flag);
- dev_info(&hdev->pdev->dev, "PRI_C pri_rate: %u(Mbps)\n",
- le32_to_cpu(shap_cfg_cmd->pri_rate));
-
- cmd = HCLGE_OPC_TM_PRI_P_SHAPPING;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- goto err_tm_cmd_send;
+ ret = hclge_tm_get_pg_sch_mode(hdev, pg_id, &sch_mode);
+ if (ret)
+ return ret;
- shap_cfg_cmd = (struct hclge_pri_shapping_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "PRI_P pri_id: %u\n", shap_cfg_cmd->pri_id);
- dev_info(&hdev->pdev->dev, "PRI_P pri_shapping: 0x%x\n",
- le32_to_cpu(shap_cfg_cmd->pri_shapping_para));
- dev_info(&hdev->pdev->dev, "PRI_P flag: %#x\n", shap_cfg_cmd->flag);
- dev_info(&hdev->pdev->dev, "PRI_P pri_rate: %u(Mbps)\n",
- le32_to_cpu(shap_cfg_cmd->pri_rate));
+ ret = hclge_tm_get_pg_weight(hdev, pg_id, &weight);
+ if (ret)
+ return ret;
- hclge_dbg_dump_tm_pg(hdev);
+ ret = hclge_tm_get_pg_shaper(hdev, pg_id,
+ HCLGE_OPC_TM_PG_C_SHAPPING,
+ &c_shaper_para);
+ if (ret)
+ return ret;
+
+ ret = hclge_tm_get_pg_shaper(hdev, pg_id,
+ HCLGE_OPC_TM_PG_P_SHAPPING,
+ &p_shaper_para);
+ if (ret)
+ return ret;
- return;
+ sch_mode_str = sch_mode & HCLGE_TM_TX_SCHD_DWRR_MSK ? "dwrr" :
+ "sp";
+
+ j = 0;
+ sprintf(result[j++], "%02u", pg_id);
+ sprintf(result[j++], "0x%02x", pri_bit_map);
+ sprintf(result[j++], "%4s", sch_mode_str);
+ sprintf(result[j++], "%3u", weight);
+ hclge_dbg_fill_shaper_content(&c_shaper_para, result, &j);
+ hclge_dbg_fill_shaper_content(&p_shaper_para, result, &j);
+
+ hclge_dbg_fill_content(content, sizeof(content), tm_pg_items,
+ (const char **)result,
+ ARRAY_SIZE(tm_pg_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
+ }
-err_tm_cmd_send:
- dev_err(&hdev->pdev->dev, "dump tm fail(0x%x), ret = %d\n",
- cmd, ret);
+ return 0;
}
-static void hclge_dbg_dump_tm_map(struct hclge_dev *hdev,
- const char *cmd_buf)
+static int hclge_dbg_dump_tm_port(struct hclge_dev *hdev, char *buf, int len)
{
- struct hclge_bp_to_qs_map_cmd *bp_to_qs_map_cmd;
- struct hclge_nq_to_qs_link_cmd *nq_to_qs_map;
- u32 qset_mapping[HCLGE_BP_EXT_GRP_NUM];
- struct hclge_qs_to_pri_link_cmd *map;
- struct hclge_tqp_tx_queue_tc_cmd *tc;
- u16 group_id, queue_id, qset_id;
- enum hclge_opcode_type cmd;
- u8 grp_num, pri_id, tc_id;
- struct hclge_desc desc;
- u16 qs_id_l;
- u16 qs_id_h;
+ struct hclge_tm_shaper_para shaper_para;
+ int pos = 0;
int ret;
- u32 i;
- ret = kstrtou16(cmd_buf, 0, &queue_id);
- queue_id = (ret != 0) ? 0 : queue_id;
-
- cmd = HCLGE_OPC_TM_NQ_TO_QS_LINK;
- nq_to_qs_map = (struct hclge_nq_to_qs_link_cmd *)desc.data;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- nq_to_qs_map->nq_id = cpu_to_le16(queue_id);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ ret = hclge_tm_get_port_shaper(hdev, &shaper_para);
if (ret)
- goto err_tm_map_cmd_send;
- qset_id = le16_to_cpu(nq_to_qs_map->qset_id);
-
- /* convert qset_id to the following format, drop the vld bit
- * | qs_id_h | vld | qs_id_l |
- * qset_id: | 15 ~ 11 | 10 | 9 ~ 0 |
- * \ \ / /
- * \ \ / /
- * qset_id: | 15 | 14 ~ 10 | 9 ~ 0 |
- */
- qs_id_l = hnae3_get_field(qset_id, HCLGE_TM_QS_ID_L_MSK,
- HCLGE_TM_QS_ID_L_S);
- qs_id_h = hnae3_get_field(qset_id, HCLGE_TM_QS_ID_H_EXT_MSK,
- HCLGE_TM_QS_ID_H_EXT_S);
- qset_id = 0;
- hnae3_set_field(qset_id, HCLGE_TM_QS_ID_L_MSK, HCLGE_TM_QS_ID_L_S,
- qs_id_l);
- hnae3_set_field(qset_id, HCLGE_TM_QS_ID_H_MSK, HCLGE_TM_QS_ID_H_S,
- qs_id_h);
-
- cmd = HCLGE_OPC_TM_QS_TO_PRI_LINK;
- map = (struct hclge_qs_to_pri_link_cmd *)desc.data;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- map->qs_id = cpu_to_le16(qset_id);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- goto err_tm_map_cmd_send;
- pri_id = map->priority;
+ return ret;
- cmd = HCLGE_OPC_TQP_TX_QUEUE_TC;
- tc = (struct hclge_tqp_tx_queue_tc_cmd *)desc.data;
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- tc->queue_id = cpu_to_le16(queue_id);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- goto err_tm_map_cmd_send;
- tc_id = tc->tc_id & 0x7;
+ pos += scnprintf(buf + pos, len - pos,
+ "IR_B IR_U IR_S BS_B BS_S FLAG RATE(Mbps)\n");
+ pos += scnprintf(buf + pos, len - pos,
+ "%3u %3u %3u %3u %3u %1u %6u\n",
+ shaper_para.ir_b, shaper_para.ir_u, shaper_para.ir_s,
+ shaper_para.bs_b, shaper_para.bs_s, shaper_para.flag,
+ shaper_para.rate);
- dev_info(&hdev->pdev->dev, "queue_id | qset_id | pri_id | tc_id\n");
- dev_info(&hdev->pdev->dev, "%04u | %04u | %02u | %02u\n",
- queue_id, qset_id, pri_id, tc_id);
+ return 0;
+}
- if (!hnae3_dev_dcb_supported(hdev)) {
- dev_info(&hdev->pdev->dev,
- "Only DCB-supported dev supports tm mapping\n");
- return;
- }
+static int hclge_dbg_dump_tm_bp_qset_map(struct hclge_dev *hdev, u8 tc_id,
+ char *buf, int len)
+{
+ u32 qset_mapping[HCLGE_BP_EXT_GRP_NUM];
+ struct hclge_bp_to_qs_map_cmd *map;
+ struct hclge_desc desc;
+ int pos = 0;
+ u8 group_id;
+ u8 grp_num;
+ u16 i = 0;
+ int ret;
grp_num = hdev->num_tqps <= HCLGE_TQP_MAX_SIZE_DEV_V2 ?
HCLGE_BP_GRP_NUM : HCLGE_BP_EXT_GRP_NUM;
- cmd = HCLGE_OPC_TM_BP_TO_QSET_MAPPING;
- bp_to_qs_map_cmd = (struct hclge_bp_to_qs_map_cmd *)desc.data;
+ map = (struct hclge_bp_to_qs_map_cmd *)desc.data;
for (group_id = 0; group_id < grp_num; group_id++) {
- hclge_cmd_setup_basic_desc(&desc, cmd, true);
- bp_to_qs_map_cmd->tc_id = tc_id;
- bp_to_qs_map_cmd->qs_group_id = group_id;
+ hclge_cmd_setup_basic_desc(&desc,
+ HCLGE_OPC_TM_BP_TO_QSET_MAPPING,
+ true);
+ map->tc_id = tc_id;
+ map->qs_group_id = group_id;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
- goto err_tm_map_cmd_send;
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to get bp to qset map, ret = %d\n",
+ ret);
+ return ret;
+ }
- qset_mapping[group_id] =
- le32_to_cpu(bp_to_qs_map_cmd->qs_bit_map);
+ qset_mapping[group_id] = le32_to_cpu(map->qs_bit_map);
}
- dev_info(&hdev->pdev->dev, "index | tm bp qset maping:\n");
-
- i = 0;
+ pos += scnprintf(buf + pos, len - pos, "INDEX | TM BP QSET MAPPING:\n");
for (group_id = 0; group_id < grp_num / 8; group_id++) {
- dev_info(&hdev->pdev->dev,
+ pos += scnprintf(buf + pos, len - pos,
"%04d | %08x:%08x:%08x:%08x:%08x:%08x:%08x:%08x\n",
- group_id * 256, qset_mapping[(u32)(i + 7)],
- qset_mapping[(u32)(i + 6)], qset_mapping[(u32)(i + 5)],
- qset_mapping[(u32)(i + 4)], qset_mapping[(u32)(i + 3)],
- qset_mapping[(u32)(i + 2)], qset_mapping[(u32)(i + 1)],
+ group_id * 256, qset_mapping[i + 7],
+ qset_mapping[i + 6], qset_mapping[i + 5],
+ qset_mapping[i + 4], qset_mapping[i + 3],
+ qset_mapping[i + 2], qset_mapping[i + 1],
qset_mapping[i]);
i += 8;
}
- return;
+ return pos;
+}
+
+static int hclge_dbg_dump_tm_map(struct hclge_dev *hdev, char *buf, int len)
+{
+ u16 queue_id;
+ u16 qset_id;
+ u8 link_vld;
+ int pos = 0;
+ u8 pri_id;
+ u8 tc_id;
+ int ret;
+
+ for (queue_id = 0; queue_id < hdev->num_tqps; queue_id++) {
+ ret = hclge_tm_get_q_to_qs_map(hdev, queue_id, &qset_id);
+ if (ret)
+ return ret;
+
+ ret = hclge_tm_get_qset_map_pri(hdev, qset_id, &pri_id,
+ &link_vld);
+ if (ret)
+ return ret;
+
+ ret = hclge_tm_get_q_to_tc(hdev, queue_id, &tc_id);
+ if (ret)
+ return ret;
+
+ pos += scnprintf(buf + pos, len - pos,
+ "QUEUE_ID QSET_ID PRI_ID TC_ID\n");
+ pos += scnprintf(buf + pos, len - pos,
+ "%04u %4u %3u %2u\n",
+ queue_id, qset_id, pri_id, tc_id);
+
+ if (!hnae3_dev_dcb_supported(hdev))
+ continue;
+
+ ret = hclge_dbg_dump_tm_bp_qset_map(hdev, tc_id, buf + pos,
+ len - pos);
+ if (ret < 0)
+ return ret;
+ pos += ret;
+
+ pos += scnprintf(buf + pos, len - pos, "\n");
+ }
-err_tm_map_cmd_send:
- dev_err(&hdev->pdev->dev, "dump tqp map fail(0x%x), ret = %d\n",
- cmd, ret);
+ return 0;
}
static int hclge_dbg_dump_tm_nodes(struct hclge_dev *hdev, char *buf, int len)
@@ -833,8 +928,8 @@ static int hclge_dbg_dump_tm_nodes(struct hclge_dev *hdev, char *buf, int len)
static int hclge_dbg_dump_tm_pri(struct hclge_dev *hdev, char *buf, int len)
{
- struct hclge_pri_shaper_para c_shaper_para;
- struct hclge_pri_shaper_para p_shaper_para;
+ struct hclge_tm_shaper_para c_shaper_para;
+ struct hclge_tm_shaper_para p_shaper_para;
u8 pri_num, sch_mode, weight;
char *sch_mode_str;
int pos = 0;
@@ -896,19 +991,42 @@ static int hclge_dbg_dump_tm_pri(struct hclge_dev *hdev, char *buf, int len)
return 0;
}
+static const struct hclge_dbg_item tm_qset_items[] = {
+ { "ID", 4 },
+ { "MAP_PRI", 2 },
+ { "LINK_VLD", 2 },
+ { "MODE", 2 },
+ { "DWRR", 2 },
+ { "IR_B", 2 },
+ { "IR_U", 2 },
+ { "IR_S", 2 },
+ { "BS_B", 2 },
+ { "BS_S", 2 },
+ { "FLAG", 2 },
+ { "RATE(Mbps)", 0 }
+};
+
static int hclge_dbg_dump_tm_qset(struct hclge_dev *hdev, char *buf, int len)
{
+ char data_str[ARRAY_SIZE(tm_qset_items)][HCLGE_DBG_DATA_STR_LEN];
+ char *result[ARRAY_SIZE(tm_qset_items)], *sch_mode_str;
u8 priority, link_vld, sch_mode, weight;
- char *sch_mode_str;
+ struct hclge_tm_shaper_para shaper_para;
+ char content[HCLGE_DBG_TM_INFO_LEN];
+ u16 qset_num, i;
int ret, pos;
- u16 qset_num;
- u16 i;
+ u8 j;
ret = hclge_tm_get_qset_num(hdev, &qset_num);
if (ret)
return ret;
- pos = scnprintf(buf, len, "ID MAP_PRI LINK_VLD MODE DWRR\n");
+ for (i = 0; i < ARRAY_SIZE(tm_qset_items); i++)
+ result[i] = &data_str[i][0];
+
+ hclge_dbg_fill_content(content, sizeof(content), tm_qset_items,
+ NULL, ARRAY_SIZE(tm_qset_items));
+ pos = scnprintf(buf, len, "%s", content);
for (i = 0; i < qset_num; i++) {
ret = hclge_tm_get_qset_map_pri(hdev, i, &priority, &link_vld);
@@ -923,280 +1041,326 @@ static int hclge_dbg_dump_tm_qset(struct hclge_dev *hdev, char *buf, int len)
if (ret)
return ret;
+ ret = hclge_tm_get_qset_shaper(hdev, i, &shaper_para);
+ if (ret)
+ return ret;
+
sch_mode_str = sch_mode & HCLGE_TM_TX_SCHD_DWRR_MSK ? "dwrr" :
"sp";
- pos += scnprintf(buf + pos, len - pos,
- "%04u %4u %1u %4s %3u\n",
- i, priority, link_vld, sch_mode_str, weight);
+
+ j = 0;
+ sprintf(result[j++], "%04u", i);
+ sprintf(result[j++], "%4u", priority);
+ sprintf(result[j++], "%4u", link_vld);
+ sprintf(result[j++], "%4s", sch_mode_str);
+ sprintf(result[j++], "%3u", weight);
+ hclge_dbg_fill_shaper_content(&shaper_para, result, &j);
+
+ hclge_dbg_fill_content(content, sizeof(content), tm_qset_items,
+ (const char **)result,
+ ARRAY_SIZE(tm_qset_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
}
return 0;
}
-static void hclge_dbg_dump_qos_pause_cfg(struct hclge_dev *hdev)
+static int hclge_dbg_dump_qos_pause_cfg(struct hclge_dev *hdev, char *buf,
+ int len)
{
struct hclge_cfg_pause_param_cmd *pause_param;
struct hclge_desc desc;
+ int pos = 0;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_MAC_PARA, true);
-
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
- dev_err(&hdev->pdev->dev, "dump checksum fail, ret = %d\n",
- ret);
- return;
+ dev_err(&hdev->pdev->dev,
+ "failed to dump qos pause, ret = %d\n", ret);
+ return ret;
}
pause_param = (struct hclge_cfg_pause_param_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "dump qos pause cfg\n");
- dev_info(&hdev->pdev->dev, "pause_trans_gap: 0x%x\n",
- pause_param->pause_trans_gap);
- dev_info(&hdev->pdev->dev, "pause_trans_time: 0x%x\n",
- le16_to_cpu(pause_param->pause_trans_time));
+
+ pos += scnprintf(buf + pos, len - pos, "pause_trans_gap: 0x%x\n",
+ pause_param->pause_trans_gap);
+ pos += scnprintf(buf + pos, len - pos, "pause_trans_time: 0x%x\n",
+ le16_to_cpu(pause_param->pause_trans_time));
+ return 0;
}
-static void hclge_dbg_dump_qos_pri_map(struct hclge_dev *hdev)
+static int hclge_dbg_dump_qos_pri_map(struct hclge_dev *hdev, char *buf,
+ int len)
{
+#define HCLGE_DBG_TC_MASK 0x0F
+#define HCLGE_DBG_TC_BIT_WIDTH 4
+
struct hclge_qos_pri_map_cmd *pri_map;
struct hclge_desc desc;
+ int pos = 0;
+ u8 *pri_tc;
+ u8 tc, i;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PRI_TO_TC_MAPPING, true);
-
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
- "dump qos pri map fail, ret = %d\n", ret);
- return;
+ "failed to dump qos pri map, ret = %d\n", ret);
+ return ret;
}
pri_map = (struct hclge_qos_pri_map_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "dump qos pri map\n");
- dev_info(&hdev->pdev->dev, "vlan_to_pri: 0x%x\n", pri_map->vlan_pri);
- dev_info(&hdev->pdev->dev, "pri_0_to_tc: 0x%x\n", pri_map->pri0_tc);
- dev_info(&hdev->pdev->dev, "pri_1_to_tc: 0x%x\n", pri_map->pri1_tc);
- dev_info(&hdev->pdev->dev, "pri_2_to_tc: 0x%x\n", pri_map->pri2_tc);
- dev_info(&hdev->pdev->dev, "pri_3_to_tc: 0x%x\n", pri_map->pri3_tc);
- dev_info(&hdev->pdev->dev, "pri_4_to_tc: 0x%x\n", pri_map->pri4_tc);
- dev_info(&hdev->pdev->dev, "pri_5_to_tc: 0x%x\n", pri_map->pri5_tc);
- dev_info(&hdev->pdev->dev, "pri_6_to_tc: 0x%x\n", pri_map->pri6_tc);
- dev_info(&hdev->pdev->dev, "pri_7_to_tc: 0x%x\n", pri_map->pri7_tc);
+
+ pos += scnprintf(buf + pos, len - pos, "vlan_to_pri: 0x%x\n",
+ pri_map->vlan_pri);
+ pos += scnprintf(buf + pos, len - pos, "PRI TC\n");
+
+ pri_tc = (u8 *)pri_map;
+ for (i = 0; i < HNAE3_MAX_TC; i++) {
+ tc = pri_tc[i >> 1] >> ((i & 1) * HCLGE_DBG_TC_BIT_WIDTH);
+ tc &= HCLGE_DBG_TC_MASK;
+ pos += scnprintf(buf + pos, len - pos, "%u %u\n", i, tc);
+ }
+
+ return 0;
}
-static int hclge_dbg_dump_tx_buf_cfg(struct hclge_dev *hdev)
+static int hclge_dbg_dump_tx_buf_cfg(struct hclge_dev *hdev, char *buf, int len)
{
struct hclge_tx_buff_alloc_cmd *tx_buf_cmd;
struct hclge_desc desc;
+ int pos = 0;
int i, ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TX_BUFF_ALLOC, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to dump tx buf, ret = %d\n", ret);
return ret;
+ }
- dev_info(&hdev->pdev->dev, "dump qos buf cfg\n");
tx_buf_cmd = (struct hclge_tx_buff_alloc_cmd *)desc.data;
for (i = 0; i < HCLGE_MAX_TC_NUM; i++)
- dev_info(&hdev->pdev->dev, "tx_packet_buf_tc_%d: 0x%x\n", i,
- le16_to_cpu(tx_buf_cmd->tx_pkt_buff[i]));
+ pos += scnprintf(buf + pos, len - pos,
+ "tx_packet_buf_tc_%d: 0x%x\n", i,
+ le16_to_cpu(tx_buf_cmd->tx_pkt_buff[i]));
- return 0;
+ return pos;
}
-static int hclge_dbg_dump_rx_priv_buf_cfg(struct hclge_dev *hdev)
+static int hclge_dbg_dump_rx_priv_buf_cfg(struct hclge_dev *hdev, char *buf,
+ int len)
{
struct hclge_rx_priv_buff_cmd *rx_buf_cmd;
struct hclge_desc desc;
+ int pos = 0;
int i, ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RX_PRIV_BUFF_ALLOC, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to dump rx priv buf, ret = %d\n", ret);
return ret;
+ }
+
+ pos += scnprintf(buf + pos, len - pos, "\n");
- dev_info(&hdev->pdev->dev, "\n");
rx_buf_cmd = (struct hclge_rx_priv_buff_cmd *)desc.data;
for (i = 0; i < HCLGE_MAX_TC_NUM; i++)
- dev_info(&hdev->pdev->dev, "rx_packet_buf_tc_%d: 0x%x\n", i,
- le16_to_cpu(rx_buf_cmd->buf_num[i]));
+ pos += scnprintf(buf + pos, len - pos,
+ "rx_packet_buf_tc_%d: 0x%x\n", i,
+ le16_to_cpu(rx_buf_cmd->buf_num[i]));
- dev_info(&hdev->pdev->dev, "rx_share_buf: 0x%x\n",
- le16_to_cpu(rx_buf_cmd->shared_buf));
+ pos += scnprintf(buf + pos, len - pos, "rx_share_buf: 0x%x\n",
+ le16_to_cpu(rx_buf_cmd->shared_buf));
- return 0;
+ return pos;
}
-static int hclge_dbg_dump_rx_common_wl_cfg(struct hclge_dev *hdev)
+static int hclge_dbg_dump_rx_common_wl_cfg(struct hclge_dev *hdev, char *buf,
+ int len)
{
struct hclge_rx_com_wl *rx_com_wl;
struct hclge_desc desc;
+ int pos = 0;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RX_COM_WL_ALLOC, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to dump rx common wl, ret = %d\n", ret);
return ret;
+ }
rx_com_wl = (struct hclge_rx_com_wl *)desc.data;
- dev_info(&hdev->pdev->dev, "\n");
- dev_info(&hdev->pdev->dev, "rx_com_wl: high: 0x%x, low: 0x%x\n",
- le16_to_cpu(rx_com_wl->com_wl.high),
- le16_to_cpu(rx_com_wl->com_wl.low));
+ pos += scnprintf(buf + pos, len - pos, "\n");
+ pos += scnprintf(buf + pos, len - pos,
+ "rx_com_wl: high: 0x%x, low: 0x%x\n",
+ le16_to_cpu(rx_com_wl->com_wl.high),
+ le16_to_cpu(rx_com_wl->com_wl.low));
- return 0;
+ return pos;
}
-static int hclge_dbg_dump_rx_global_pkt_cnt(struct hclge_dev *hdev)
+static int hclge_dbg_dump_rx_global_pkt_cnt(struct hclge_dev *hdev, char *buf,
+ int len)
{
struct hclge_rx_com_wl *rx_packet_cnt;
struct hclge_desc desc;
+ int pos = 0;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RX_GBL_PKT_CNT, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret)
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to dump rx global pkt cnt, ret = %d\n", ret);
return ret;
+ }
rx_packet_cnt = (struct hclge_rx_com_wl *)desc.data;
- dev_info(&hdev->pdev->dev,
- "rx_global_packet_cnt: high: 0x%x, low: 0x%x\n",
- le16_to_cpu(rx_packet_cnt->com_wl.high),
- le16_to_cpu(rx_packet_cnt->com_wl.low));
+ pos += scnprintf(buf + pos, len - pos,
+ "rx_global_packet_cnt: high: 0x%x, low: 0x%x\n",
+ le16_to_cpu(rx_packet_cnt->com_wl.high),
+ le16_to_cpu(rx_packet_cnt->com_wl.low));
- return 0;
+ return pos;
}
-static int hclge_dbg_dump_rx_priv_wl_buf_cfg(struct hclge_dev *hdev)
+static int hclge_dbg_dump_rx_priv_wl_buf_cfg(struct hclge_dev *hdev, char *buf,
+ int len)
{
struct hclge_rx_priv_wl_buf *rx_priv_wl;
struct hclge_desc desc[2];
+ int pos = 0;
int i, ret;
hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_RX_PRIV_WL_ALLOC, true);
desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
hclge_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_RX_PRIV_WL_ALLOC, true);
ret = hclge_cmd_send(&hdev->hw, desc, 2);
- if (ret)
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to dump rx priv wl buf, ret = %d\n", ret);
return ret;
+ }
rx_priv_wl = (struct hclge_rx_priv_wl_buf *)desc[0].data;
for (i = 0; i < HCLGE_TC_NUM_ONE_DESC; i++)
- dev_info(&hdev->pdev->dev,
+ pos += scnprintf(buf + pos, len - pos,
"rx_priv_wl_tc_%d: high: 0x%x, low: 0x%x\n", i,
le16_to_cpu(rx_priv_wl->tc_wl[i].high),
le16_to_cpu(rx_priv_wl->tc_wl[i].low));
rx_priv_wl = (struct hclge_rx_priv_wl_buf *)desc[1].data;
for (i = 0; i < HCLGE_TC_NUM_ONE_DESC; i++)
- dev_info(&hdev->pdev->dev,
+ pos += scnprintf(buf + pos, len - pos,
"rx_priv_wl_tc_%d: high: 0x%x, low: 0x%x\n",
i + HCLGE_TC_NUM_ONE_DESC,
le16_to_cpu(rx_priv_wl->tc_wl[i].high),
le16_to_cpu(rx_priv_wl->tc_wl[i].low));
- return 0;
+ return pos;
}
-static int hclge_dbg_dump_rx_common_threshold_cfg(struct hclge_dev *hdev)
+static int hclge_dbg_dump_rx_common_threshold_cfg(struct hclge_dev *hdev,
+ char *buf, int len)
{
struct hclge_rx_com_thrd *rx_com_thrd;
struct hclge_desc desc[2];
+ int pos = 0;
int i, ret;
hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_RX_COM_THRD_ALLOC, true);
desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
hclge_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_RX_COM_THRD_ALLOC, true);
ret = hclge_cmd_send(&hdev->hw, desc, 2);
- if (ret)
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to dump rx common threshold, ret = %d\n", ret);
return ret;
+ }
- dev_info(&hdev->pdev->dev, "\n");
+ pos += scnprintf(buf + pos, len - pos, "\n");
rx_com_thrd = (struct hclge_rx_com_thrd *)desc[0].data;
for (i = 0; i < HCLGE_TC_NUM_ONE_DESC; i++)
- dev_info(&hdev->pdev->dev,
+ pos += scnprintf(buf + pos, len - pos,
"rx_com_thrd_tc_%d: high: 0x%x, low: 0x%x\n", i,
le16_to_cpu(rx_com_thrd->com_thrd[i].high),
le16_to_cpu(rx_com_thrd->com_thrd[i].low));
rx_com_thrd = (struct hclge_rx_com_thrd *)desc[1].data;
for (i = 0; i < HCLGE_TC_NUM_ONE_DESC; i++)
- dev_info(&hdev->pdev->dev,
+ pos += scnprintf(buf + pos, len - pos,
"rx_com_thrd_tc_%d: high: 0x%x, low: 0x%x\n",
i + HCLGE_TC_NUM_ONE_DESC,
le16_to_cpu(rx_com_thrd->com_thrd[i].high),
le16_to_cpu(rx_com_thrd->com_thrd[i].low));
- return 0;
+ return pos;
}
-static void hclge_dbg_dump_qos_buf_cfg(struct hclge_dev *hdev)
+static int hclge_dbg_dump_qos_buf_cfg(struct hclge_dev *hdev, char *buf,
+ int len)
{
- enum hclge_opcode_type cmd;
+ int pos = 0;
int ret;
- cmd = HCLGE_OPC_TX_BUFF_ALLOC;
- ret = hclge_dbg_dump_tx_buf_cfg(hdev);
- if (ret)
- goto err_qos_cmd_send;
-
- cmd = HCLGE_OPC_RX_PRIV_BUFF_ALLOC;
- ret = hclge_dbg_dump_rx_priv_buf_cfg(hdev);
- if (ret)
- goto err_qos_cmd_send;
+ ret = hclge_dbg_dump_tx_buf_cfg(hdev, buf + pos, len - pos);
+ if (ret < 0)
+ return ret;
+ pos += ret;
- cmd = HCLGE_OPC_RX_COM_WL_ALLOC;
- ret = hclge_dbg_dump_rx_common_wl_cfg(hdev);
- if (ret)
- goto err_qos_cmd_send;
+ ret = hclge_dbg_dump_rx_priv_buf_cfg(hdev, buf + pos, len - pos);
+ if (ret < 0)
+ return ret;
+ pos += ret;
- cmd = HCLGE_OPC_RX_GBL_PKT_CNT;
- ret = hclge_dbg_dump_rx_global_pkt_cnt(hdev);
- if (ret)
- goto err_qos_cmd_send;
+ ret = hclge_dbg_dump_rx_common_wl_cfg(hdev, buf + pos, len - pos);
+ if (ret < 0)
+ return ret;
+ pos += ret;
- dev_info(&hdev->pdev->dev, "\n");
- if (!hnae3_dev_dcb_supported(hdev)) {
- dev_info(&hdev->pdev->dev,
- "Only DCB-supported dev supports rx priv wl\n");
- return;
- }
+ ret = hclge_dbg_dump_rx_global_pkt_cnt(hdev, buf + pos, len - pos);
+ if (ret < 0)
+ return ret;
+ pos += ret;
- cmd = HCLGE_OPC_RX_PRIV_WL_ALLOC;
- ret = hclge_dbg_dump_rx_priv_wl_buf_cfg(hdev);
- if (ret)
- goto err_qos_cmd_send;
+ pos += scnprintf(buf + pos, len - pos, "\n");
+ if (!hnae3_dev_dcb_supported(hdev))
+ return 0;
- cmd = HCLGE_OPC_RX_COM_THRD_ALLOC;
- ret = hclge_dbg_dump_rx_common_threshold_cfg(hdev);
- if (ret)
- goto err_qos_cmd_send;
+ ret = hclge_dbg_dump_rx_priv_wl_buf_cfg(hdev, buf + pos, len - pos);
+ if (ret < 0)
+ return ret;
+ pos += ret;
- return;
+ ret = hclge_dbg_dump_rx_common_threshold_cfg(hdev, buf + pos,
+ len - pos);
+ if (ret < 0)
+ return ret;
-err_qos_cmd_send:
- dev_err(&hdev->pdev->dev,
- "dump qos buf cfg fail(0x%x), ret = %d\n", cmd, ret);
+ return 0;
}
-static void hclge_dbg_dump_mng_table(struct hclge_dev *hdev)
+static int hclge_dbg_dump_mng_table(struct hclge_dev *hdev, char *buf, int len)
{
struct hclge_mac_ethertype_idx_rd_cmd *req0;
- char printf_buf[HCLGE_DBG_BUF_LEN];
struct hclge_desc desc;
u32 msg_egress_port;
+ int pos = 0;
int ret, i;
- dev_info(&hdev->pdev->dev, "mng tab:\n");
- memset(printf_buf, 0, HCLGE_DBG_BUF_LEN);
- strncat(printf_buf,
- "entry|mac_addr |mask|ether|mask|vlan|mask",
- HCLGE_DBG_BUF_LEN - 1);
- strncat(printf_buf + strlen(printf_buf),
- "|i_map|i_dir|e_type|pf_id|vf_id|q_id|drop\n",
- HCLGE_DBG_BUF_LEN - strlen(printf_buf) - 1);
-
- dev_info(&hdev->pdev->dev, "%s", printf_buf);
+ pos += scnprintf(buf + pos, len - pos,
+ "entry mac_addr mask ether ");
+ pos += scnprintf(buf + pos, len - pos,
+ "mask vlan mask i_map i_dir e_type ");
+ pos += scnprintf(buf + pos, len - pos, "pf_id vf_id q_id drop\n");
for (i = 0; i < HCLGE_DBG_MNG_TBL_MAX; i++) {
hclge_cmd_setup_basic_desc(&desc, HCLGE_MAC_ETHERTYPE_IDX_RD,
@@ -1207,52 +1371,53 @@ static void hclge_dbg_dump_mng_table(struct hclge_dev *hdev)
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
- "call hclge_cmd_send fail, ret = %d\n", ret);
- return;
+ "failed to dump manage table, ret = %d\n", ret);
+ return ret;
}
if (!req0->resp_code)
continue;
- memset(printf_buf, 0, HCLGE_DBG_BUF_LEN);
- snprintf(printf_buf, HCLGE_DBG_BUF_LEN,
- "%02u |%02x:%02x:%02x:%02x:%02x:%02x|",
- le16_to_cpu(req0->index),
- req0->mac_addr[0], req0->mac_addr[1],
- req0->mac_addr[2], req0->mac_addr[3],
- req0->mac_addr[4], req0->mac_addr[5]);
-
- snprintf(printf_buf + strlen(printf_buf),
- HCLGE_DBG_BUF_LEN - strlen(printf_buf),
- "%x |%04x |%x |%04x|%x |%02x |%02x |",
- !!(req0->flags & HCLGE_DBG_MNG_MAC_MASK_B),
- le16_to_cpu(req0->ethter_type),
- !!(req0->flags & HCLGE_DBG_MNG_ETHER_MASK_B),
- le16_to_cpu(req0->vlan_tag) & HCLGE_DBG_MNG_VLAN_TAG,
- !!(req0->flags & HCLGE_DBG_MNG_VLAN_MASK_B),
- req0->i_port_bitmap, req0->i_port_direction);
+ pos += scnprintf(buf + pos, len - pos, "%02u %pM ",
+ le16_to_cpu(req0->index), req0->mac_addr);
+
+ pos += scnprintf(buf + pos, len - pos,
+ "%x %04x %x %04x ",
+ !!(req0->flags & HCLGE_DBG_MNG_MAC_MASK_B),
+ le16_to_cpu(req0->ethter_type),
+ !!(req0->flags & HCLGE_DBG_MNG_ETHER_MASK_B),
+ le16_to_cpu(req0->vlan_tag) &
+ HCLGE_DBG_MNG_VLAN_TAG);
+
+ pos += scnprintf(buf + pos, len - pos,
+ "%x %02x %02x ",
+ !!(req0->flags & HCLGE_DBG_MNG_VLAN_MASK_B),
+ req0->i_port_bitmap, req0->i_port_direction);
msg_egress_port = le16_to_cpu(req0->egress_port);
- snprintf(printf_buf + strlen(printf_buf),
- HCLGE_DBG_BUF_LEN - strlen(printf_buf),
- "%x |%x |%02x |%04x|%x\n",
- !!(msg_egress_port & HCLGE_DBG_MNG_E_TYPE_B),
- msg_egress_port & HCLGE_DBG_MNG_PF_ID,
- (msg_egress_port >> 3) & HCLGE_DBG_MNG_VF_ID,
- le16_to_cpu(req0->egress_queue),
- !!(msg_egress_port & HCLGE_DBG_MNG_DROP_B));
-
- dev_info(&hdev->pdev->dev, "%s", printf_buf);
+ pos += scnprintf(buf + pos, len - pos,
+ "%x %x %02x %04x %x\n",
+ !!(msg_egress_port & HCLGE_DBG_MNG_E_TYPE_B),
+ msg_egress_port & HCLGE_DBG_MNG_PF_ID,
+ (msg_egress_port >> 3) & HCLGE_DBG_MNG_VF_ID,
+ le16_to_cpu(req0->egress_queue),
+ !!(msg_egress_port & HCLGE_DBG_MNG_DROP_B));
}
+
+ return 0;
}
-static int hclge_dbg_fd_tcam_read(struct hclge_dev *hdev, u8 stage,
- bool sel_x, u32 loc)
+#define HCLGE_DBG_TCAM_BUF_SIZE 256
+
+static int hclge_dbg_fd_tcam_read(struct hclge_dev *hdev, bool sel_x,
+ char *tcam_buf,
+ struct hclge_dbg_tcam_msg tcam_msg)
{
struct hclge_fd_tcam_config_1_cmd *req1;
struct hclge_fd_tcam_config_2_cmd *req2;
struct hclge_fd_tcam_config_3_cmd *req3;
struct hclge_desc desc[3];
+ int pos = 0;
int ret, i;
u32 *req;
@@ -1266,31 +1431,35 @@ static int hclge_dbg_fd_tcam_read(struct hclge_dev *hdev, u8 stage,
req2 = (struct hclge_fd_tcam_config_2_cmd *)desc[1].data;
req3 = (struct hclge_fd_tcam_config_3_cmd *)desc[2].data;
- req1->stage = stage;
+ req1->stage = tcam_msg.stage;
req1->xy_sel = sel_x ? 1 : 0;
- req1->index = cpu_to_le32(loc);
+ req1->index = cpu_to_le32(tcam_msg.loc);
ret = hclge_cmd_send(&hdev->hw, desc, 3);
if (ret)
return ret;
- dev_info(&hdev->pdev->dev, " read result tcam key %s(%u):\n",
- sel_x ? "x" : "y", loc);
+ pos += scnprintf(tcam_buf + pos, HCLGE_DBG_TCAM_BUF_SIZE - pos,
+ "read result tcam key %s(%u):\n", sel_x ? "x" : "y",
+ tcam_msg.loc);
/* tcam_data0 ~ tcam_data1 */
req = (u32 *)req1->tcam_data;
for (i = 0; i < 2; i++)
- dev_info(&hdev->pdev->dev, "%08x\n", *req++);
+ pos += scnprintf(tcam_buf + pos, HCLGE_DBG_TCAM_BUF_SIZE - pos,
+ "%08x\n", *req++);
/* tcam_data2 ~ tcam_data7 */
req = (u32 *)req2->tcam_data;
for (i = 0; i < 6; i++)
- dev_info(&hdev->pdev->dev, "%08x\n", *req++);
+ pos += scnprintf(tcam_buf + pos, HCLGE_DBG_TCAM_BUF_SIZE - pos,
+ "%08x\n", *req++);
/* tcam_data8 ~ tcam_data12 */
req = (u32 *)req3->tcam_data;
for (i = 0; i < 5; i++)
- dev_info(&hdev->pdev->dev, "%08x\n", *req++);
+ pos += scnprintf(tcam_buf + pos, HCLGE_DBG_TCAM_BUF_SIZE - pos,
+ "%08x\n", *req++);
return ret;
}
@@ -1308,265 +1477,348 @@ static int hclge_dbg_get_rules_location(struct hclge_dev *hdev, u16 *rule_locs)
}
spin_unlock_bh(&hdev->fd_rule_lock);
- if (cnt != hdev->hclge_fd_rule_num)
+ if (cnt != hdev->hclge_fd_rule_num || cnt == 0)
return -EINVAL;
return cnt;
}
-static void hclge_dbg_fd_tcam(struct hclge_dev *hdev)
+static int hclge_dbg_dump_fd_tcam(struct hclge_dev *hdev, char *buf, int len)
{
+ u32 rule_num = hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1];
+ struct hclge_dbg_tcam_msg tcam_msg;
int i, ret, rule_cnt;
u16 *rule_locs;
+ char *tcam_buf;
+ int pos = 0;
if (!hnae3_dev_fd_supported(hdev)) {
dev_err(&hdev->pdev->dev,
"Only FD-supported dev supports dump fd tcam\n");
- return;
+ return -EOPNOTSUPP;
}
- if (!hdev->hclge_fd_rule_num ||
- !hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1])
- return;
+ if (!hdev->hclge_fd_rule_num || !rule_num)
+ return 0;
- rule_locs = kcalloc(hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1],
- sizeof(u16), GFP_KERNEL);
+ rule_locs = kcalloc(rule_num, sizeof(u16), GFP_KERNEL);
if (!rule_locs)
- return;
+ return -ENOMEM;
+
+ tcam_buf = kzalloc(HCLGE_DBG_TCAM_BUF_SIZE, GFP_KERNEL);
+ if (!tcam_buf) {
+ kfree(rule_locs);
+ return -ENOMEM;
+ }
rule_cnt = hclge_dbg_get_rules_location(hdev, rule_locs);
- if (rule_cnt <= 0) {
+ if (rule_cnt < 0) {
+ ret = rule_cnt;
dev_err(&hdev->pdev->dev,
- "failed to get rule number, ret = %d\n", rule_cnt);
- kfree(rule_locs);
- return;
+ "failed to get rule number, ret = %d\n", ret);
+ goto out;
}
+ ret = 0;
for (i = 0; i < rule_cnt; i++) {
- ret = hclge_dbg_fd_tcam_read(hdev, 0, true, rule_locs[i]);
+ tcam_msg.stage = HCLGE_FD_STAGE_1;
+ tcam_msg.loc = rule_locs[i];
+
+ ret = hclge_dbg_fd_tcam_read(hdev, true, tcam_buf, tcam_msg);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to get fd tcam key x, ret = %d\n", ret);
- kfree(rule_locs);
- return;
+ goto out;
}
- ret = hclge_dbg_fd_tcam_read(hdev, 0, false, rule_locs[i]);
+ pos += scnprintf(buf + pos, len - pos, "%s", tcam_buf);
+
+ ret = hclge_dbg_fd_tcam_read(hdev, false, tcam_buf, tcam_msg);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to get fd tcam key y, ret = %d\n", ret);
- kfree(rule_locs);
- return;
+ goto out;
}
+
+ pos += scnprintf(buf + pos, len - pos, "%s", tcam_buf);
}
+out:
+ kfree(tcam_buf);
kfree(rule_locs);
+ return ret;
}
-void hclge_dbg_dump_rst_info(struct hclge_dev *hdev)
-{
- dev_info(&hdev->pdev->dev, "PF reset count: %u\n",
- hdev->rst_stats.pf_rst_cnt);
- dev_info(&hdev->pdev->dev, "FLR reset count: %u\n",
- hdev->rst_stats.flr_rst_cnt);
- dev_info(&hdev->pdev->dev, "GLOBAL reset count: %u\n",
- hdev->rst_stats.global_rst_cnt);
- dev_info(&hdev->pdev->dev, "IMP reset count: %u\n",
- hdev->rst_stats.imp_rst_cnt);
- dev_info(&hdev->pdev->dev, "reset done count: %u\n",
- hdev->rst_stats.reset_done_cnt);
- dev_info(&hdev->pdev->dev, "HW reset done count: %u\n",
- hdev->rst_stats.hw_reset_done_cnt);
- dev_info(&hdev->pdev->dev, "reset count: %u\n",
- hdev->rst_stats.reset_cnt);
- dev_info(&hdev->pdev->dev, "reset fail count: %u\n",
- hdev->rst_stats.reset_fail_cnt);
- dev_info(&hdev->pdev->dev, "vector0 interrupt enable status: 0x%x\n",
- hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_REG_BASE));
- dev_info(&hdev->pdev->dev, "reset interrupt source: 0x%x\n",
- hclge_read_dev(&hdev->hw, HCLGE_MISC_RESET_STS_REG));
- dev_info(&hdev->pdev->dev, "reset interrupt status: 0x%x\n",
- hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS));
- dev_info(&hdev->pdev->dev, "hardware reset status: 0x%x\n",
- hclge_read_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG));
- dev_info(&hdev->pdev->dev, "handshake status: 0x%x\n",
- hclge_read_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG));
- dev_info(&hdev->pdev->dev, "function reset status: 0x%x\n",
- hclge_read_dev(&hdev->hw, HCLGE_FUN_RST_ING));
- dev_info(&hdev->pdev->dev, "hdev state: 0x%lx\n", hdev->state);
-}
-
-static void hclge_dbg_dump_serv_info(struct hclge_dev *hdev)
-{
- dev_info(&hdev->pdev->dev, "last_serv_processed: %lu\n",
- hdev->last_serv_processed);
- dev_info(&hdev->pdev->dev, "last_serv_cnt: %lu\n",
- hdev->serv_processed_cnt);
-}
-
-static void hclge_dbg_dump_interrupt(struct hclge_dev *hdev)
-{
- dev_info(&hdev->pdev->dev, "num_nic_msi: %u\n", hdev->num_nic_msi);
- dev_info(&hdev->pdev->dev, "num_roce_msi: %u\n", hdev->num_roce_msi);
- dev_info(&hdev->pdev->dev, "num_msi_used: %u\n", hdev->num_msi_used);
- dev_info(&hdev->pdev->dev, "num_msi_left: %u\n", hdev->num_msi_left);
-}
-
-static 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;
+static int hclge_dbg_dump_fd_counter(struct hclge_dev *hdev, char *buf, int len)
+{
+ u8 func_num = pci_num_vf(hdev->pdev) + 1; /* pf and enabled vf num */
+ struct hclge_fd_ad_cnt_read_cmd *req;
+ char str_id[HCLGE_DBG_ID_LEN];
struct hclge_desc desc;
- u32 bd_num, buf_len;
- int ret, i;
+ int pos = 0;
+ int ret;
+ u64 cnt;
+ u8 i;
+
+ pos += scnprintf(buf + pos, len - pos,
+ "func_id\thit_times\n");
+
+ for (i = 0; i < func_num; i++) {
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_CNT_OP, true);
+ req = (struct hclge_fd_ad_cnt_read_cmd *)desc.data;
+ req->index = cpu_to_le16(i);
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev, "failed to get fd counter, ret = %d\n",
+ ret);
+ return ret;
+ }
+ cnt = le64_to_cpu(req->cnt);
+ hclge_dbg_get_func_id_str(str_id, i);
+ pos += scnprintf(buf + pos, len - pos,
+ "%s\t%llu\n", str_id, cnt);
+ }
+
+ return 0;
+}
+
+int hclge_dbg_dump_rst_info(struct hclge_dev *hdev, char *buf, int len)
+{
+ int pos = 0;
+
+ pos += scnprintf(buf + pos, len - pos, "PF reset count: %u\n",
+ hdev->rst_stats.pf_rst_cnt);
+ pos += scnprintf(buf + pos, len - pos, "FLR reset count: %u\n",
+ hdev->rst_stats.flr_rst_cnt);
+ pos += scnprintf(buf + pos, len - pos, "GLOBAL reset count: %u\n",
+ hdev->rst_stats.global_rst_cnt);
+ pos += scnprintf(buf + pos, len - pos, "IMP reset count: %u\n",
+ hdev->rst_stats.imp_rst_cnt);
+ pos += scnprintf(buf + pos, len - pos, "reset done count: %u\n",
+ hdev->rst_stats.reset_done_cnt);
+ pos += scnprintf(buf + pos, len - pos, "HW reset done count: %u\n",
+ hdev->rst_stats.hw_reset_done_cnt);
+ pos += scnprintf(buf + pos, len - pos, "reset count: %u\n",
+ hdev->rst_stats.reset_cnt);
+ pos += scnprintf(buf + pos, len - pos, "reset fail count: %u\n",
+ hdev->rst_stats.reset_fail_cnt);
+ pos += scnprintf(buf + pos, len - pos,
+ "vector0 interrupt enable status: 0x%x\n",
+ hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_REG_BASE));
+ pos += scnprintf(buf + pos, len - pos, "reset interrupt source: 0x%x\n",
+ hclge_read_dev(&hdev->hw, HCLGE_MISC_RESET_STS_REG));
+ pos += scnprintf(buf + pos, len - pos, "reset interrupt status: 0x%x\n",
+ hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS));
+ pos += scnprintf(buf + pos, len - pos, "RAS interrupt status: 0x%x\n",
+ hclge_read_dev(&hdev->hw,
+ HCLGE_RAS_PF_OTHER_INT_STS_REG));
+ pos += scnprintf(buf + pos, len - pos, "hardware reset status: 0x%x\n",
+ hclge_read_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG));
+ pos += scnprintf(buf + pos, len - pos, "handshake status: 0x%x\n",
+ hclge_read_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG));
+ pos += scnprintf(buf + pos, len - pos, "function reset status: 0x%x\n",
+ hclge_read_dev(&hdev->hw, HCLGE_FUN_RST_ING));
+ pos += scnprintf(buf + pos, len - pos, "hdev state: 0x%lx\n",
+ hdev->state);
+
+ return 0;
+}
+
+static int hclge_dbg_dump_serv_info(struct hclge_dev *hdev, char *buf, int len)
+{
+ unsigned long rem_nsec;
+ int pos = 0;
+ u64 lc;
+
+ lc = local_clock();
+ rem_nsec = do_div(lc, HCLGE_BILLION_NANO_SECONDS);
+
+ pos += scnprintf(buf + pos, len - pos, "local_clock: [%5lu.%06lu]\n",
+ (unsigned long)lc, rem_nsec / 1000);
+ pos += scnprintf(buf + pos, len - pos, "delta: %u(ms)\n",
+ jiffies_to_msecs(jiffies - hdev->last_serv_processed));
+ pos += scnprintf(buf + pos, len - pos,
+ "last_service_task_processed: %lu(jiffies)\n",
+ hdev->last_serv_processed);
+ pos += scnprintf(buf + pos, len - pos, "last_service_task_cnt: %lu\n",
+ hdev->serv_processed_cnt);
+
+ return 0;
+}
+
+static int hclge_dbg_dump_interrupt(struct hclge_dev *hdev, char *buf, int len)
+{
+ int pos = 0;
+
+ pos += scnprintf(buf + pos, len - pos, "num_nic_msi: %u\n",
+ hdev->num_nic_msi);
+ pos += scnprintf(buf + pos, len - pos, "num_roce_msi: %u\n",
+ hdev->num_roce_msi);
+ pos += scnprintf(buf + pos, len - pos, "num_msi_used: %u\n",
+ hdev->num_msi_used);
+ pos += scnprintf(buf + pos, len - pos, "num_msi_left: %u\n",
+ hdev->num_msi_left);
+
+ return 0;
+}
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_M7_STATS_BD, true);
+static void hclge_dbg_imp_info_data_print(struct hclge_desc *desc_src,
+ char *buf, int len, u32 bd_num)
+{
+#define HCLGE_DBG_IMP_INFO_PRINT_OFFSET 0x2
+
+ struct hclge_desc *desc_index = desc_src;
+ u32 offset = 0;
+ int pos = 0;
+ u32 i, j;
- req = (struct hclge_get_m7_bd_cmd *)desc.data;
+ pos += scnprintf(buf + pos, len - pos, "offset | data\n");
+
+ for (i = 0; i < bd_num; i++) {
+ j = 0;
+ while (j < HCLGE_DESC_DATA_LEN - 1) {
+ pos += scnprintf(buf + pos, len - pos, "0x%04x | ",
+ offset);
+ pos += scnprintf(buf + pos, len - pos, "0x%08x ",
+ le32_to_cpu(desc_index->data[j++]));
+ pos += scnprintf(buf + pos, len - pos, "0x%08x\n",
+ le32_to_cpu(desc_index->data[j++]));
+ offset += sizeof(u32) * HCLGE_DBG_IMP_INFO_PRINT_OFFSET;
+ }
+ desc_index++;
+ }
+}
+
+static int
+hclge_dbg_get_imp_stats_info(struct hclge_dev *hdev, char *buf, int len)
+{
+ struct hclge_get_imp_bd_cmd *req;
+ struct hclge_desc *desc_src;
+ struct hclge_desc desc;
+ u32 bd_num;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_IMP_STATS_BD, true);
+
+ req = (struct hclge_get_imp_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",
+ "failed to get imp statistics bd number, ret = %d\n",
ret);
- return;
+ return ret;
}
bd_num = le32_to_cpu(req->bd_num);
- buf_len = sizeof(struct hclge_desc) * bd_num;
- desc_src = kzalloc(buf_len, GFP_KERNEL);
+ desc_src = kcalloc(bd_num, sizeof(struct hclge_desc), GFP_KERNEL);
if (!desc_src)
- return;
+ return -ENOMEM;
- desc_tmp = desc_src;
- ret = hclge_dbg_cmd_send(hdev, desc_tmp, 0, bd_num,
- HCLGE_OPC_M7_STATS_INFO);
+ ret = hclge_dbg_cmd_send(hdev, desc_src, 0, bd_num,
+ HCLGE_OPC_IMP_STATS_INFO);
if (ret) {
kfree(desc_src);
dev_err(&hdev->pdev->dev,
- "get firmware statistics failed, ret = %d\n", ret);
- return;
+ "failed to get imp statistics, ret = %d\n", ret);
+ return ret;
}
- 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++;
- }
+ hclge_dbg_imp_info_data_print(desc_src, buf, len, bd_num);
kfree(desc_src);
+
+ return 0;
}
#define HCLGE_CMD_NCL_CONFIG_BD_NUM 5
+#define HCLGE_MAX_NCL_CONFIG_LENGTH 16384
-static void hclge_ncl_config_data_print(struct hclge_dev *hdev,
- struct hclge_desc *desc, int *offset,
- int *length)
+static void hclge_ncl_config_data_print(struct hclge_desc *desc, int *index,
+ char *buf, int *len, int *pos)
{
#define HCLGE_CMD_DATA_NUM 6
- int i;
- int j;
+ int offset = HCLGE_MAX_NCL_CONFIG_LENGTH - *index;
+ int i, j;
for (i = 0; i < HCLGE_CMD_NCL_CONFIG_BD_NUM; i++) {
for (j = 0; j < HCLGE_CMD_DATA_NUM; j++) {
if (i == 0 && j == 0)
continue;
- dev_info(&hdev->pdev->dev, "0x%04x | 0x%08x\n",
- *offset,
- le32_to_cpu(desc[i].data[j]));
- *offset += sizeof(u32);
- *length -= sizeof(u32);
- if (*length <= 0)
+ *pos += scnprintf(buf + *pos, *len - *pos,
+ "0x%04x | 0x%08x\n", offset,
+ le32_to_cpu(desc[i].data[j]));
+
+ offset += sizeof(u32);
+ *index -= sizeof(u32);
+
+ if (*index <= 0)
return;
}
}
}
-/* 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,
- const char *cmd_buf)
+static int
+hclge_dbg_dump_ncl_config(struct hclge_dev *hdev, char *buf, int len)
{
-#define HCLGE_MAX_NCL_CONFIG_OFFSET 4096
#define HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD (20 + 24 * 4)
-#define HCLGE_NCL_CONFIG_PARAM_NUM 2
struct hclge_desc desc[HCLGE_CMD_NCL_CONFIG_BD_NUM];
int bd_num = HCLGE_CMD_NCL_CONFIG_BD_NUM;
- int offset;
- int length;
- int data0;
+ int index = HCLGE_MAX_NCL_CONFIG_LENGTH;
+ int pos = 0;
+ u32 data0;
int ret;
- ret = sscanf(cmd_buf, "%x %x", &offset, &length);
- if (ret != HCLGE_NCL_CONFIG_PARAM_NUM) {
- dev_err(&hdev->pdev->dev,
- "Too few parameters, num = %d.\n", ret);
- return;
- }
-
- if (offset < 0 || offset >= HCLGE_MAX_NCL_CONFIG_OFFSET ||
- length <= 0 || length > HCLGE_MAX_NCL_CONFIG_OFFSET - offset) {
- dev_err(&hdev->pdev->dev,
- "Invalid input, offset = %d, length = %d.\n",
- offset, length);
- return;
- }
+ pos += scnprintf(buf + pos, len - pos, "offset | data\n");
- dev_info(&hdev->pdev->dev, "offset | data\n");
-
- while (length > 0) {
- data0 = offset;
- if (length >= HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD)
+ while (index > 0) {
+ data0 = HCLGE_MAX_NCL_CONFIG_LENGTH - index;
+ if (index >= HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD)
data0 |= HCLGE_NCL_CONFIG_LENGTH_IN_EACH_CMD << 16;
else
- data0 |= length << 16;
+ data0 |= (u32)index << 16;
ret = hclge_dbg_cmd_send(hdev, desc, data0, bd_num,
HCLGE_OPC_QUERY_NCL_CONFIG);
if (ret)
- return;
+ return ret;
- hclge_ncl_config_data_print(hdev, desc, &offset, &length);
+ hclge_ncl_config_data_print(desc, &index, buf, &len, &pos);
}
+
+ return 0;
}
-static void hclge_dbg_dump_loopback(struct hclge_dev *hdev)
+static int hclge_dbg_dump_loopback(struct hclge_dev *hdev, char *buf, int len)
{
struct phy_device *phydev = hdev->hw.mac.phydev;
struct hclge_config_mac_mode_cmd *req_app;
struct hclge_common_lb_cmd *req_common;
struct hclge_desc desc;
u8 loopback_en;
+ int pos = 0;
int ret;
req_app = (struct hclge_config_mac_mode_cmd *)desc.data;
req_common = (struct hclge_common_lb_cmd *)desc.data;
- dev_info(&hdev->pdev->dev, "mac id: %u\n", hdev->hw.mac.mac_id);
+ pos += scnprintf(buf + pos, len - pos, "mac id: %u\n",
+ hdev->hw.mac.mac_id);
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_MAC_MODE, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to dump app loopback status, ret = %d\n", ret);
- return;
+ return ret;
}
loopback_en = hnae3_get_bit(le32_to_cpu(req_app->txrx_pad_fcs_loop_en),
HCLGE_MAC_APP_LP_B);
- dev_info(&hdev->pdev->dev, "app loopback: %s\n",
- loopback_en ? "on" : "off");
+ pos += scnprintf(buf + pos, len - pos, "app loopback: %s\n",
+ state_str[loopback_en]);
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_COMMON_LOOPBACK, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
@@ -1574,247 +1826,647 @@ static void hclge_dbg_dump_loopback(struct hclge_dev *hdev)
dev_err(&hdev->pdev->dev,
"failed to dump common loopback status, ret = %d\n",
ret);
- return;
+ return ret;
}
loopback_en = req_common->enable & HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B;
- dev_info(&hdev->pdev->dev, "serdes serial loopback: %s\n",
- loopback_en ? "on" : "off");
+ pos += scnprintf(buf + pos, len - pos, "serdes serial loopback: %s\n",
+ state_str[loopback_en]);
loopback_en = req_common->enable &
- HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B;
- dev_info(&hdev->pdev->dev, "serdes parallel loopback: %s\n",
- loopback_en ? "on" : "off");
+ HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B ? 1 : 0;
+ pos += scnprintf(buf + pos, len - pos, "serdes parallel loopback: %s\n",
+ state_str[loopback_en]);
if (phydev) {
- dev_info(&hdev->pdev->dev, "phy loopback: %s\n",
- phydev->loopback_enabled ? "on" : "off");
+ loopback_en = phydev->loopback_enabled;
+ pos += scnprintf(buf + pos, len - pos, "phy loopback: %s\n",
+ state_str[loopback_en]);
} else if (hnae3_dev_phy_imp_supported(hdev)) {
loopback_en = req_common->enable &
HCLGE_CMD_GE_PHY_INNER_LOOP_B;
- dev_info(&hdev->pdev->dev, "phy loopback: %s\n",
- loopback_en ? "on" : "off");
+ pos += scnprintf(buf + pos, len - pos, "phy loopback: %s\n",
+ state_str[loopback_en]);
}
+
+ return 0;
}
/* hclge_dbg_dump_mac_tnl_status: print message about mac tnl interrupt
* @hdev: pointer to struct hclge_dev
*/
-static void hclge_dbg_dump_mac_tnl_status(struct hclge_dev *hdev)
+static int
+hclge_dbg_dump_mac_tnl_status(struct hclge_dev *hdev, char *buf, int len)
{
-#define HCLGE_BILLION_NANO_SECONDS 1000000000
-
struct hclge_mac_tnl_stats stats;
unsigned long rem_nsec;
+ int pos = 0;
- dev_info(&hdev->pdev->dev, "Recently generated mac tnl interruption:\n");
+ pos += scnprintf(buf + pos, len - pos,
+ "Recently generated mac tnl interruption:\n");
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",
- (unsigned long)stats.time, rem_nsec / 1000,
- stats.status);
+
+ pos += scnprintf(buf + pos, len - pos,
+ "[%07lu.%03lu] status = 0x%x\n",
+ (unsigned long)stats.time, rem_nsec / 1000,
+ stats.status);
+ }
+
+ return 0;
+}
+
+
+static const struct hclge_dbg_item mac_list_items[] = {
+ { "FUNC_ID", 2 },
+ { "MAC_ADDR", 12 },
+ { "STATE", 2 },
+};
+
+static void hclge_dbg_dump_mac_list(struct hclge_dev *hdev, char *buf, int len,
+ bool is_unicast)
+{
+ char data_str[ARRAY_SIZE(mac_list_items)][HCLGE_DBG_DATA_STR_LEN];
+ char content[HCLGE_DBG_INFO_LEN], str_id[HCLGE_DBG_ID_LEN];
+ char *result[ARRAY_SIZE(mac_list_items)];
+ struct hclge_mac_node *mac_node, *tmp;
+ struct hclge_vport *vport;
+ struct list_head *list;
+ u32 func_id;
+ int pos = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mac_list_items); i++)
+ result[i] = &data_str[i][0];
+
+ pos += scnprintf(buf + pos, len - pos, "%s MAC_LIST:\n",
+ is_unicast ? "UC" : "MC");
+ hclge_dbg_fill_content(content, sizeof(content), mac_list_items,
+ NULL, ARRAY_SIZE(mac_list_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
+
+ for (func_id = 0; func_id < hdev->num_alloc_vport; func_id++) {
+ vport = &hdev->vport[func_id];
+ list = is_unicast ? &vport->uc_mac_list : &vport->mc_mac_list;
+ spin_lock_bh(&vport->mac_list_lock);
+ list_for_each_entry_safe(mac_node, tmp, list, node) {
+ i = 0;
+ result[i++] = hclge_dbg_get_func_id_str(str_id,
+ func_id);
+ sprintf(result[i++], "%pM", mac_node->mac_addr);
+ sprintf(result[i++], "%5s",
+ hclge_mac_state_str[mac_node->state]);
+ hclge_dbg_fill_content(content, sizeof(content),
+ mac_list_items,
+ (const char **)result,
+ ARRAY_SIZE(mac_list_items));
+ pos += scnprintf(buf + pos, len - pos, "%s", content);
+ }
+ spin_unlock_bh(&vport->mac_list_lock);
}
}
-static void hclge_dbg_dump_qs_shaper_single(struct hclge_dev *hdev, u16 qsid)
+static int hclge_dbg_dump_umv_info(struct hclge_dev *hdev, char *buf, int len)
{
- struct hclge_qs_shapping_cmd *shap_cfg_cmd;
- u8 ir_u, ir_b, ir_s, bs_b, bs_s;
+ u8 func_num = pci_num_vf(hdev->pdev) + 1;
+ struct hclge_vport *vport;
+ int pos = 0;
+ u8 i;
+
+ pos += scnprintf(buf, len, "num_alloc_vport : %u\n",
+ hdev->num_alloc_vport);
+ pos += scnprintf(buf + pos, len - pos, "max_umv_size : %u\n",
+ hdev->max_umv_size);
+ pos += scnprintf(buf + pos, len - pos, "wanted_umv_size : %u\n",
+ hdev->wanted_umv_size);
+ pos += scnprintf(buf + pos, len - pos, "priv_umv_size : %u\n",
+ hdev->priv_umv_size);
+
+ mutex_lock(&hdev->vport_lock);
+ pos += scnprintf(buf + pos, len - pos, "share_umv_size : %u\n",
+ hdev->share_umv_size);
+ for (i = 0; i < func_num; i++) {
+ vport = &hdev->vport[i];
+ pos += scnprintf(buf + pos, len - pos,
+ "vport(%u) used_umv_num : %u\n",
+ i, vport->used_umv_num);
+ }
+ mutex_unlock(&hdev->vport_lock);
+
+ return 0;
+}
+
+static int hclge_get_vlan_rx_offload_cfg(struct hclge_dev *hdev, u8 vf_id,
+ struct hclge_dbg_vlan_cfg *vlan_cfg)
+{
+ struct hclge_vport_vtag_rx_cfg_cmd *req;
struct hclge_desc desc;
- u32 shapping_para;
- u32 rate;
+ u16 bmap_index;
+ u8 rx_cfg;
int ret;
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QCN_SHAPPING_CFG, true);
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_VLAN_PORT_RX_CFG, true);
- shap_cfg_cmd = (struct hclge_qs_shapping_cmd *)desc.data;
- shap_cfg_cmd->qs_id = cpu_to_le16(qsid);
+ req = (struct hclge_vport_vtag_rx_cfg_cmd *)desc.data;
+ req->vf_offset = vf_id / HCLGE_VF_NUM_PER_CMD;
+ bmap_index = vf_id % HCLGE_VF_NUM_PER_CMD / HCLGE_VF_NUM_PER_BYTE;
+ req->vf_bitmap[bmap_index] = 1U << (vf_id % HCLGE_VF_NUM_PER_BYTE);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
- "qs%u failed to get tx_rate, ret=%d\n",
- qsid, ret);
- return;
+ "failed to get vport%u rxvlan cfg, ret = %d\n",
+ vf_id, ret);
+ return ret;
}
- shapping_para = le32_to_cpu(shap_cfg_cmd->qs_shapping_para);
- ir_b = hclge_tm_get_field(shapping_para, IR_B);
- ir_u = hclge_tm_get_field(shapping_para, IR_U);
- ir_s = hclge_tm_get_field(shapping_para, IR_S);
- bs_b = hclge_tm_get_field(shapping_para, BS_B);
- bs_s = hclge_tm_get_field(shapping_para, BS_S);
- rate = le32_to_cpu(shap_cfg_cmd->qs_rate);
+ rx_cfg = req->vport_vlan_cfg;
+ vlan_cfg->strip_tag1 = hnae3_get_bit(rx_cfg, HCLGE_REM_TAG1_EN_B);
+ vlan_cfg->strip_tag2 = hnae3_get_bit(rx_cfg, HCLGE_REM_TAG2_EN_B);
+ vlan_cfg->drop_tag1 = hnae3_get_bit(rx_cfg, HCLGE_DISCARD_TAG1_EN_B);
+ vlan_cfg->drop_tag2 = hnae3_get_bit(rx_cfg, HCLGE_DISCARD_TAG2_EN_B);
+ vlan_cfg->pri_only1 = hnae3_get_bit(rx_cfg, HCLGE_SHOW_TAG1_EN_B);
+ vlan_cfg->pri_only2 = hnae3_get_bit(rx_cfg, HCLGE_SHOW_TAG2_EN_B);
- dev_info(&hdev->pdev->dev,
- "qs%u ir_b:%u, ir_u:%u, ir_s:%u, bs_b:%u, bs_s:%u, flag:%#x, rate:%u(Mbps)\n",
- qsid, ir_b, ir_u, ir_s, bs_b, bs_s, shap_cfg_cmd->flag, rate);
+ return 0;
}
-static void hclge_dbg_dump_qs_shaper_all(struct hclge_dev *hdev)
+static int hclge_get_vlan_tx_offload_cfg(struct hclge_dev *hdev, u8 vf_id,
+ struct hclge_dbg_vlan_cfg *vlan_cfg)
{
- struct hnae3_knic_private_info *kinfo;
- struct hclge_vport *vport;
- int vport_id, i;
+ struct hclge_vport_vtag_tx_cfg_cmd *req;
+ struct hclge_desc desc;
+ u16 bmap_index;
+ u8 tx_cfg;
+ int ret;
- for (vport_id = 0; vport_id <= pci_num_vf(hdev->pdev); vport_id++) {
- vport = &hdev->vport[vport_id];
- kinfo = &vport->nic.kinfo;
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_VLAN_PORT_TX_CFG, true);
+ req = (struct hclge_vport_vtag_tx_cfg_cmd *)desc.data;
+ req->vf_offset = vf_id / HCLGE_VF_NUM_PER_CMD;
+ bmap_index = vf_id % HCLGE_VF_NUM_PER_CMD / HCLGE_VF_NUM_PER_BYTE;
+ req->vf_bitmap[bmap_index] = 1U << (vf_id % HCLGE_VF_NUM_PER_BYTE);
- dev_info(&hdev->pdev->dev, "qs cfg of vport%d:\n", vport_id);
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to get vport%u txvlan cfg, ret = %d\n",
+ vf_id, ret);
+ return ret;
+ }
- for (i = 0; i < kinfo->tc_info.num_tc; i++) {
- u16 qsid = vport->qs_offset + i;
+ tx_cfg = req->vport_vlan_cfg;
+ vlan_cfg->pvid = le16_to_cpu(req->def_vlan_tag1);
- hclge_dbg_dump_qs_shaper_single(hdev, qsid);
- }
- }
+ vlan_cfg->accept_tag1 = hnae3_get_bit(tx_cfg, HCLGE_ACCEPT_TAG1_B);
+ vlan_cfg->accept_tag2 = hnae3_get_bit(tx_cfg, HCLGE_ACCEPT_TAG2_B);
+ vlan_cfg->accept_untag1 = hnae3_get_bit(tx_cfg, HCLGE_ACCEPT_UNTAG1_B);
+ vlan_cfg->accept_untag2 = hnae3_get_bit(tx_cfg, HCLGE_ACCEPT_UNTAG2_B);
+ vlan_cfg->insert_tag1 = hnae3_get_bit(tx_cfg, HCLGE_PORT_INS_TAG1_EN_B);
+ vlan_cfg->insert_tag2 = hnae3_get_bit(tx_cfg, HCLGE_PORT_INS_TAG2_EN_B);
+ vlan_cfg->shift_tag = hnae3_get_bit(tx_cfg, HCLGE_TAG_SHIFT_MODE_EN_B);
+
+ return 0;
}
-static void hclge_dbg_dump_qs_shaper(struct hclge_dev *hdev,
- const char *cmd_buf)
+static int hclge_get_vlan_filter_config_cmd(struct hclge_dev *hdev,
+ u8 vlan_type, u8 vf_id,
+ struct hclge_desc *desc)
{
- u16 qsid;
+ struct hclge_vlan_filter_ctrl_cmd *req;
int ret;
- ret = kstrtou16(cmd_buf, 0, &qsid);
- if (ret) {
- hclge_dbg_dump_qs_shaper_all(hdev);
- return;
- }
+ hclge_cmd_setup_basic_desc(desc, HCLGE_OPC_VLAN_FILTER_CTRL, true);
+ req = (struct hclge_vlan_filter_ctrl_cmd *)desc->data;
+ req->vlan_type = vlan_type;
+ req->vf_id = vf_id;
- if (qsid >= hdev->ae_dev->dev_specs.max_qset_num) {
- dev_err(&hdev->pdev->dev, "qsid(%u) out of range[0-%u]\n",
- qsid, hdev->ae_dev->dev_specs.max_qset_num - 1);
- return;
- }
+ ret = hclge_cmd_send(&hdev->hw, desc, 1);
+ if (ret)
+ dev_err(&hdev->pdev->dev,
+ "failed to get vport%u vlan filter config, ret = %d.\n",
+ vf_id, ret);
- hclge_dbg_dump_qs_shaper_single(hdev, qsid);
+ return ret;
}
-static int hclge_dbg_dump_mac_list(struct hclge_dev *hdev, const char *cmd_buf,
- bool is_unicast)
+static int hclge_get_vlan_filter_state(struct hclge_dev *hdev, u8 vlan_type,
+ u8 vf_id, u8 *vlan_fe)
{
- struct hclge_mac_node *mac_node, *tmp;
- struct hclge_vport *vport;
- struct list_head *list;
- u32 func_id;
+ struct hclge_vlan_filter_ctrl_cmd *req;
+ struct hclge_desc desc;
+ int ret;
+
+ ret = hclge_get_vlan_filter_config_cmd(hdev, vlan_type, vf_id, &desc);
+ if (ret)
+ return ret;
+
+ req = (struct hclge_vlan_filter_ctrl_cmd *)desc.data;
+ *vlan_fe = req->vlan_fe;
+
+ return 0;
+}
+
+static int hclge_get_port_vlan_filter_bypass_state(struct hclge_dev *hdev,
+ u8 vf_id, u8 *bypass_en)
+{
+ struct hclge_port_vlan_filter_bypass_cmd *req;
+ struct hclge_desc desc;
int ret;
- ret = kstrtouint(cmd_buf, 0, &func_id);
- if (ret < 0) {
+ if (!test_bit(HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B, hdev->ae_dev->caps))
+ return 0;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PORT_VLAN_BYPASS, true);
+ req = (struct hclge_port_vlan_filter_bypass_cmd *)desc.data;
+ req->vf_id = vf_id;
+
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
dev_err(&hdev->pdev->dev,
- "dump mac list: bad command string, ret = %d\n", ret);
- return -EINVAL;
+ "failed to get vport%u port vlan filter bypass state, ret = %d.\n",
+ vf_id, ret);
+ return ret;
}
- if (func_id >= hdev->num_alloc_vport) {
- dev_err(&hdev->pdev->dev,
- "function id(%u) is out of range(0-%u)\n", func_id,
- hdev->num_alloc_vport - 1);
- return -EINVAL;
+ *bypass_en = hnae3_get_bit(req->bypass_state, HCLGE_INGRESS_BYPASS_B);
+
+ return 0;
+}
+
+static const struct hclge_dbg_item vlan_filter_items[] = {
+ { "FUNC_ID", 2 },
+ { "I_VF_VLAN_FILTER", 2 },
+ { "E_VF_VLAN_FILTER", 2 },
+ { "PORT_VLAN_FILTER_BYPASS", 0 }
+};
+
+static const struct hclge_dbg_item vlan_offload_items[] = {
+ { "FUNC_ID", 2 },
+ { "PVID", 4 },
+ { "ACCEPT_TAG1", 2 },
+ { "ACCEPT_TAG2", 2 },
+ { "ACCEPT_UNTAG1", 2 },
+ { "ACCEPT_UNTAG2", 2 },
+ { "INSERT_TAG1", 2 },
+ { "INSERT_TAG2", 2 },
+ { "SHIFT_TAG", 2 },
+ { "STRIP_TAG1", 2 },
+ { "STRIP_TAG2", 2 },
+ { "DROP_TAG1", 2 },
+ { "DROP_TAG2", 2 },
+ { "PRI_ONLY_TAG1", 2 },
+ { "PRI_ONLY_TAG2", 0 }
+};
+
+static int hclge_dbg_dump_vlan_filter_config(struct hclge_dev *hdev, char *buf,
+ int len, int *pos)
+{
+ char content[HCLGE_DBG_VLAN_FLTR_INFO_LEN], str_id[HCLGE_DBG_ID_LEN];
+ const char *result[ARRAY_SIZE(vlan_filter_items)];
+ u8 i, j, vlan_fe, bypass, ingress, egress;
+ u8 func_num = pci_num_vf(hdev->pdev) + 1; /* pf and enabled vf num */
+ int ret;
+
+ ret = hclge_get_vlan_filter_state(hdev, HCLGE_FILTER_TYPE_PORT, 0,
+ &vlan_fe);
+ if (ret)
+ return ret;
+ ingress = vlan_fe & HCLGE_FILTER_FE_NIC_INGRESS_B;
+ egress = vlan_fe & HCLGE_FILTER_FE_NIC_EGRESS_B ? 1 : 0;
+
+ *pos += scnprintf(buf, len, "I_PORT_VLAN_FILTER: %s\n",
+ state_str[ingress]);
+ *pos += scnprintf(buf + *pos, len - *pos, "E_PORT_VLAN_FILTER: %s\n",
+ state_str[egress]);
+
+ hclge_dbg_fill_content(content, sizeof(content), vlan_filter_items,
+ NULL, ARRAY_SIZE(vlan_filter_items));
+ *pos += scnprintf(buf + *pos, len - *pos, "%s", content);
+
+ for (i = 0; i < func_num; i++) {
+ ret = hclge_get_vlan_filter_state(hdev, HCLGE_FILTER_TYPE_VF, i,
+ &vlan_fe);
+ if (ret)
+ return ret;
+
+ ingress = vlan_fe & HCLGE_FILTER_FE_NIC_INGRESS_B;
+ egress = vlan_fe & HCLGE_FILTER_FE_NIC_EGRESS_B ? 1 : 0;
+ ret = hclge_get_port_vlan_filter_bypass_state(hdev, i, &bypass);
+ if (ret)
+ return ret;
+ j = 0;
+ result[j++] = hclge_dbg_get_func_id_str(str_id, i);
+ result[j++] = state_str[ingress];
+ result[j++] = state_str[egress];
+ result[j++] =
+ test_bit(HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B,
+ hdev->ae_dev->caps) ? state_str[bypass] : "NA";
+ hclge_dbg_fill_content(content, sizeof(content),
+ vlan_filter_items, result,
+ ARRAY_SIZE(vlan_filter_items));
+ *pos += scnprintf(buf + *pos, len - *pos, "%s", content);
}
+ *pos += scnprintf(buf + *pos, len - *pos, "\n");
+
+ return 0;
+}
- vport = &hdev->vport[func_id];
+static int hclge_dbg_dump_vlan_offload_config(struct hclge_dev *hdev, char *buf,
+ int len, int *pos)
+{
+ char str_id[HCLGE_DBG_ID_LEN], str_pvid[HCLGE_DBG_ID_LEN];
+ const char *result[ARRAY_SIZE(vlan_offload_items)];
+ char content[HCLGE_DBG_VLAN_OFFLOAD_INFO_LEN];
+ u8 func_num = pci_num_vf(hdev->pdev) + 1; /* pf and enabled vf num */
+ struct hclge_dbg_vlan_cfg vlan_cfg;
+ int ret;
+ u8 i, j;
- list = is_unicast ? &vport->uc_mac_list : &vport->mc_mac_list;
+ hclge_dbg_fill_content(content, sizeof(content), vlan_offload_items,
+ NULL, ARRAY_SIZE(vlan_offload_items));
+ *pos += scnprintf(buf + *pos, len - *pos, "%s", content);
- dev_info(&hdev->pdev->dev, "vport %u %s mac list:\n",
- func_id, is_unicast ? "uc" : "mc");
- dev_info(&hdev->pdev->dev, "mac address state\n");
+ for (i = 0; i < func_num; i++) {
+ ret = hclge_get_vlan_tx_offload_cfg(hdev, i, &vlan_cfg);
+ if (ret)
+ return ret;
- spin_lock_bh(&vport->mac_list_lock);
+ ret = hclge_get_vlan_rx_offload_cfg(hdev, i, &vlan_cfg);
+ if (ret)
+ return ret;
- list_for_each_entry_safe(mac_node, tmp, list, node) {
- dev_info(&hdev->pdev->dev, "%pM %d\n",
- mac_node->mac_addr, mac_node->state);
+ sprintf(str_pvid, "%u", vlan_cfg.pvid);
+ j = 0;
+ result[j++] = hclge_dbg_get_func_id_str(str_id, i);
+ result[j++] = str_pvid;
+ result[j++] = state_str[vlan_cfg.accept_tag1];
+ result[j++] = state_str[vlan_cfg.accept_tag2];
+ result[j++] = state_str[vlan_cfg.accept_untag1];
+ result[j++] = state_str[vlan_cfg.accept_untag2];
+ result[j++] = state_str[vlan_cfg.insert_tag1];
+ result[j++] = state_str[vlan_cfg.insert_tag2];
+ result[j++] = state_str[vlan_cfg.shift_tag];
+ result[j++] = state_str[vlan_cfg.strip_tag1];
+ result[j++] = state_str[vlan_cfg.strip_tag2];
+ result[j++] = state_str[vlan_cfg.drop_tag1];
+ result[j++] = state_str[vlan_cfg.drop_tag2];
+ result[j++] = state_str[vlan_cfg.pri_only1];
+ result[j++] = state_str[vlan_cfg.pri_only2];
+
+ hclge_dbg_fill_content(content, sizeof(content),
+ vlan_offload_items, result,
+ ARRAY_SIZE(vlan_offload_items));
+ *pos += scnprintf(buf + *pos, len - *pos, "%s", content);
}
- spin_unlock_bh(&vport->mac_list_lock);
+ return 0;
+}
+
+static int hclge_dbg_dump_vlan_config(struct hclge_dev *hdev, char *buf,
+ int len)
+{
+ int pos = 0;
+ int ret;
+
+ ret = hclge_dbg_dump_vlan_filter_config(hdev, buf, len, &pos);
+ if (ret)
+ return ret;
+
+ return hclge_dbg_dump_vlan_offload_config(hdev, buf, len, &pos);
+}
+
+static int hclge_dbg_dump_ptp_info(struct hclge_dev *hdev, char *buf, int len)
+{
+ struct hclge_ptp *ptp = hdev->ptp;
+ u32 sw_cfg = ptp->ptp_cfg;
+ unsigned int tx_start;
+ unsigned int last_rx;
+ int pos = 0;
+ u32 hw_cfg;
+ int ret;
+
+ pos += scnprintf(buf + pos, len - pos, "phc %s's debug info:\n",
+ ptp->info.name);
+ pos += scnprintf(buf + pos, len - pos, "ptp enable: %s\n",
+ test_bit(HCLGE_PTP_FLAG_EN, &ptp->flags) ?
+ "yes" : "no");
+ pos += scnprintf(buf + pos, len - pos, "ptp tx enable: %s\n",
+ test_bit(HCLGE_PTP_FLAG_TX_EN, &ptp->flags) ?
+ "yes" : "no");
+ pos += scnprintf(buf + pos, len - pos, "ptp rx enable: %s\n",
+ test_bit(HCLGE_PTP_FLAG_RX_EN, &ptp->flags) ?
+ "yes" : "no");
+
+ last_rx = jiffies_to_msecs(ptp->last_rx);
+ pos += scnprintf(buf + pos, len - pos, "last rx time: %lu.%lu\n",
+ last_rx / MSEC_PER_SEC, last_rx % MSEC_PER_SEC);
+ pos += scnprintf(buf + pos, len - pos, "rx count: %lu\n", ptp->rx_cnt);
+
+ tx_start = jiffies_to_msecs(ptp->tx_start);
+ pos += scnprintf(buf + pos, len - pos, "last tx start time: %lu.%lu\n",
+ tx_start / MSEC_PER_SEC, tx_start % MSEC_PER_SEC);
+ pos += scnprintf(buf + pos, len - pos, "tx count: %lu\n", ptp->tx_cnt);
+ pos += scnprintf(buf + pos, len - pos, "tx skipped count: %lu\n",
+ ptp->tx_skipped);
+ pos += scnprintf(buf + pos, len - pos, "tx timeout count: %lu\n",
+ ptp->tx_timeout);
+ pos += scnprintf(buf + pos, len - pos, "last tx seqid: %u\n",
+ ptp->last_tx_seqid);
+
+ ret = hclge_ptp_cfg_qry(hdev, &hw_cfg);
+ if (ret)
+ return ret;
+
+ pos += scnprintf(buf + pos, len - pos, "sw_cfg: %#x, hw_cfg: %#x\n",
+ sw_cfg, hw_cfg);
+
+ pos += scnprintf(buf + pos, len - pos, "tx type: %d, rx filter: %d\n",
+ ptp->ts_cfg.tx_type, ptp->ts_cfg.rx_filter);
return 0;
}
-int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf)
+static int hclge_dbg_dump_mac_uc(struct hclge_dev *hdev, char *buf, int len)
{
-#define DUMP_REG "dump reg"
-#define DUMP_TM_MAP "dump tm map"
-#define DUMP_LOOPBACK "dump loopback"
-#define DUMP_INTERRUPT "dump intr"
+ hclge_dbg_dump_mac_list(hdev, buf, len, true);
- struct hclge_vport *vport = hclge_get_vport(handle);
- struct hclge_dev *hdev = vport->back;
+ return 0;
+}
- if (strncmp(cmd_buf, "dump fd tcam", 12) == 0) {
- hclge_dbg_fd_tcam(hdev);
- } else if (strncmp(cmd_buf, "dump tc", 7) == 0) {
- hclge_dbg_dump_tc(hdev);
- } else if (strncmp(cmd_buf, DUMP_TM_MAP, strlen(DUMP_TM_MAP)) == 0) {
- hclge_dbg_dump_tm_map(hdev, &cmd_buf[sizeof(DUMP_TM_MAP)]);
- } else if (strncmp(cmd_buf, "dump tm", 7) == 0) {
- hclge_dbg_dump_tm(hdev);
- } else if (strncmp(cmd_buf, "dump qos pause cfg", 18) == 0) {
- hclge_dbg_dump_qos_pause_cfg(hdev);
- } else if (strncmp(cmd_buf, "dump qos pri map", 16) == 0) {
- hclge_dbg_dump_qos_pri_map(hdev);
- } else if (strncmp(cmd_buf, "dump qos buf cfg", 16) == 0) {
- hclge_dbg_dump_qos_buf_cfg(hdev);
- } else if (strncmp(cmd_buf, "dump mng tbl", 12) == 0) {
- hclge_dbg_dump_mng_table(hdev);
- } else if (strncmp(cmd_buf, DUMP_REG, strlen(DUMP_REG)) == 0) {
- hclge_dbg_dump_reg_cmd(hdev, &cmd_buf[sizeof(DUMP_REG)]);
- } else if (strncmp(cmd_buf, "dump reset info", 15) == 0) {
- hclge_dbg_dump_rst_info(hdev);
- } else if (strncmp(cmd_buf, "dump serv info", 14) == 0) {
- hclge_dbg_dump_serv_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")]);
- } else if (strncmp(cmd_buf, "dump mac tnl status", 19) == 0) {
- hclge_dbg_dump_mac_tnl_status(hdev);
- } else if (strncmp(cmd_buf, DUMP_LOOPBACK,
- strlen(DUMP_LOOPBACK)) == 0) {
- hclge_dbg_dump_loopback(hdev);
- } else if (strncmp(cmd_buf, "dump qs shaper", 14) == 0) {
- hclge_dbg_dump_qs_shaper(hdev,
- &cmd_buf[sizeof("dump qs shaper")]);
- } else if (strncmp(cmd_buf, "dump uc mac list", 16) == 0) {
- hclge_dbg_dump_mac_list(hdev,
- &cmd_buf[sizeof("dump uc mac list")],
- true);
- } else if (strncmp(cmd_buf, "dump mc mac list", 16) == 0) {
- hclge_dbg_dump_mac_list(hdev,
- &cmd_buf[sizeof("dump mc mac list")],
- false);
- } else if (strncmp(cmd_buf, DUMP_INTERRUPT,
- strlen(DUMP_INTERRUPT)) == 0) {
- hclge_dbg_dump_interrupt(hdev);
- } else {
- dev_info(&hdev->pdev->dev, "unknown command\n");
- return -EINVAL;
- }
+static int hclge_dbg_dump_mac_mc(struct hclge_dev *hdev, char *buf, int len)
+{
+ hclge_dbg_dump_mac_list(hdev, buf, len, false);
return 0;
}
-int hclge_dbg_read_cmd(struct hnae3_handle *handle, const char *cmd_buf,
+static const struct hclge_dbg_func hclge_dbg_cmd_func[] = {
+ {
+ .cmd = HNAE3_DBG_CMD_TM_NODES,
+ .dbg_dump = hclge_dbg_dump_tm_nodes,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_TM_PRI,
+ .dbg_dump = hclge_dbg_dump_tm_pri,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_TM_QSET,
+ .dbg_dump = hclge_dbg_dump_tm_qset,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_TM_MAP,
+ .dbg_dump = hclge_dbg_dump_tm_map,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_TM_PG,
+ .dbg_dump = hclge_dbg_dump_tm_pg,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_TM_PORT,
+ .dbg_dump = hclge_dbg_dump_tm_port,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_TC_SCH_INFO,
+ .dbg_dump = hclge_dbg_dump_tc,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_QOS_PAUSE_CFG,
+ .dbg_dump = hclge_dbg_dump_qos_pause_cfg,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_QOS_PRI_MAP,
+ .dbg_dump = hclge_dbg_dump_qos_pri_map,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_QOS_BUF_CFG,
+ .dbg_dump = hclge_dbg_dump_qos_buf_cfg,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_MAC_UC,
+ .dbg_dump = hclge_dbg_dump_mac_uc,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_MAC_MC,
+ .dbg_dump = hclge_dbg_dump_mac_mc,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_MNG_TBL,
+ .dbg_dump = hclge_dbg_dump_mng_table,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_LOOPBACK,
+ .dbg_dump = hclge_dbg_dump_loopback,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_PTP_INFO,
+ .dbg_dump = hclge_dbg_dump_ptp_info,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_INTERRUPT_INFO,
+ .dbg_dump = hclge_dbg_dump_interrupt,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_RESET_INFO,
+ .dbg_dump = hclge_dbg_dump_rst_info,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_IMP_INFO,
+ .dbg_dump = hclge_dbg_get_imp_stats_info,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_NCL_CONFIG,
+ .dbg_dump = hclge_dbg_dump_ncl_config,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_REG_BIOS_COMMON,
+ .dbg_dump_reg = hclge_dbg_dump_reg_cmd,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_REG_SSU,
+ .dbg_dump_reg = hclge_dbg_dump_reg_cmd,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_REG_IGU_EGU,
+ .dbg_dump_reg = hclge_dbg_dump_reg_cmd,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_REG_RPU,
+ .dbg_dump_reg = hclge_dbg_dump_reg_cmd,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_REG_NCSI,
+ .dbg_dump_reg = hclge_dbg_dump_reg_cmd,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_REG_RTC,
+ .dbg_dump_reg = hclge_dbg_dump_reg_cmd,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_REG_PPP,
+ .dbg_dump_reg = hclge_dbg_dump_reg_cmd,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_REG_RCB,
+ .dbg_dump_reg = hclge_dbg_dump_reg_cmd,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_REG_TQP,
+ .dbg_dump_reg = hclge_dbg_dump_reg_cmd,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_REG_MAC,
+ .dbg_dump = hclge_dbg_dump_mac,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_REG_DCB,
+ .dbg_dump = hclge_dbg_dump_dcb,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_FD_TCAM,
+ .dbg_dump = hclge_dbg_dump_fd_tcam,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_MAC_TNL_STATUS,
+ .dbg_dump = hclge_dbg_dump_mac_tnl_status,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_SERV_INFO,
+ .dbg_dump = hclge_dbg_dump_serv_info,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_VLAN_CONFIG,
+ .dbg_dump = hclge_dbg_dump_vlan_config,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_FD_COUNTER,
+ .dbg_dump = hclge_dbg_dump_fd_counter,
+ },
+ {
+ .cmd = HNAE3_DBG_CMD_UMV_INFO,
+ .dbg_dump = hclge_dbg_dump_umv_info,
+ },
+};
+
+int hclge_dbg_read_cmd(struct hnae3_handle *handle, enum hnae3_dbg_cmd cmd,
char *buf, int len)
{
struct hclge_vport *vport = hclge_get_vport(handle);
+ const struct hclge_dbg_func *cmd_func;
struct hclge_dev *hdev = vport->back;
+ u32 i;
- if (strncmp(cmd_buf, HNAE3_DBG_TM_NODES,
- strlen(HNAE3_DBG_TM_NODES)) == 0)
- return hclge_dbg_dump_tm_nodes(hdev, buf, len);
- else if (strncmp(cmd_buf, HNAE3_DBG_TM_PRI,
- strlen(HNAE3_DBG_TM_PRI)) == 0)
- return hclge_dbg_dump_tm_pri(hdev, buf, len);
- else if (strncmp(cmd_buf, HNAE3_DBG_TM_QSET,
- strlen(HNAE3_DBG_TM_QSET)) == 0)
- return hclge_dbg_dump_tm_qset(hdev, buf, len);
+ for (i = 0; i < ARRAY_SIZE(hclge_dbg_cmd_func); i++) {
+ if (cmd == hclge_dbg_cmd_func[i].cmd) {
+ cmd_func = &hclge_dbg_cmd_func[i];
+ if (cmd_func->dbg_dump)
+ return cmd_func->dbg_dump(hdev, buf, len);
+ else
+ return cmd_func->dbg_dump_reg(hdev, cmd, buf,
+ len);
+ }
+ }
+ dev_err(&hdev->pdev->dev, "invalid command(%d)\n", cmd);
return -EINVAL;
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h
index ca2ab6cf84d9..c526591a7240 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h
@@ -7,7 +7,6 @@
#include <linux/etherdevice.h>
#include "hclge_cmd.h"
-#define HCLGE_DBG_BUF_LEN 256
#define HCLGE_DBG_MNG_TBL_MAX 64
#define HCLGE_DBG_MNG_VLAN_MASK_B BIT(0)
@@ -70,6 +69,11 @@ struct hclge_dbg_reg_common_msg {
enum hclge_opcode_type cmd;
};
+struct hclge_dbg_tcam_msg {
+ u8 stage;
+ u32 loc;
+};
+
#define HCLGE_DBG_MAX_DFX_MSG_LEN 60
struct hclge_dbg_dfx_message {
int flag;
@@ -78,11 +82,18 @@ struct hclge_dbg_dfx_message {
#define HCLGE_DBG_MAC_REG_TYPE_LEN 32
struct hclge_dbg_reg_type_info {
- const char *reg_type;
+ enum hnae3_dbg_cmd cmd;
const struct hclge_dbg_dfx_message *dfx_msg;
struct hclge_dbg_reg_common_msg reg_msg;
};
+struct hclge_dbg_func {
+ enum hnae3_dbg_cmd cmd;
+ int (*dbg_dump)(struct hclge_dev *hdev, char *buf, int len);
+ int (*dbg_dump_reg)(struct hclge_dev *hdev, enum hnae3_dbg_cmd cmd,
+ char *buf, int len);
+};
+
static const struct hclge_dbg_dfx_message hclge_dbg_bios_common_reg[] = {
{false, "Reserved"},
{true, "BP_CPU_STATE"},
@@ -723,4 +734,36 @@ static const struct hclge_dbg_dfx_message hclge_dbg_tqp_reg[] = {
{true, "RCB_CFG_TX_RING_EBDNUM"},
};
+#define HCLGE_DBG_INFO_LEN 256
+#define HCLGE_DBG_VLAN_FLTR_INFO_LEN 256
+#define HCLGE_DBG_VLAN_OFFLOAD_INFO_LEN 512
+#define HCLGE_DBG_ID_LEN 16
+#define HCLGE_DBG_ITEM_NAME_LEN 32
+#define HCLGE_DBG_DATA_STR_LEN 32
+#define HCLGE_DBG_TM_INFO_LEN 256
+
+#define HCLGE_BILLION_NANO_SECONDS 1000000000
+
+struct hclge_dbg_item {
+ char name[HCLGE_DBG_ITEM_NAME_LEN];
+ u16 interval; /* blank numbers after the item */
+};
+
+struct hclge_dbg_vlan_cfg {
+ u16 pvid;
+ u8 accept_tag1;
+ u8 accept_tag2;
+ u8 accept_untag1;
+ u8 accept_untag2;
+ u8 insert_tag1;
+ u8 insert_tag2;
+ u8 shift_tag;
+ u8 strip_tag1;
+ u8 strip_tag2;
+ u8 drop_tag1;
+ u8 drop_tag2;
+ u8 pri_only1;
+ u8 pri_only2;
+};
+
#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
index 8223d699cd94..ec9a7f8bc3fe 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c
@@ -631,6 +631,134 @@ static const struct hclge_hw_error hclge_rocee_qmm_ovf_err_int[] = {
{ /* sentinel */ }
};
+static const struct hclge_hw_module_id hclge_hw_module_id_st[] = {
+ {
+ .module_id = MODULE_NONE,
+ .msg = "MODULE_NONE"
+ }, {
+ .module_id = MODULE_BIOS_COMMON,
+ .msg = "MODULE_BIOS_COMMON"
+ }, {
+ .module_id = MODULE_GE,
+ .msg = "MODULE_GE"
+ }, {
+ .module_id = MODULE_IGU_EGU,
+ .msg = "MODULE_IGU_EGU"
+ }, {
+ .module_id = MODULE_LGE,
+ .msg = "MODULE_LGE"
+ }, {
+ .module_id = MODULE_NCSI,
+ .msg = "MODULE_NCSI"
+ }, {
+ .module_id = MODULE_PPP,
+ .msg = "MODULE_PPP"
+ }, {
+ .module_id = MODULE_QCN,
+ .msg = "MODULE_QCN"
+ }, {
+ .module_id = MODULE_RCB_RX,
+ .msg = "MODULE_RCB_RX"
+ }, {
+ .module_id = MODULE_RTC,
+ .msg = "MODULE_RTC"
+ }, {
+ .module_id = MODULE_SSU,
+ .msg = "MODULE_SSU"
+ }, {
+ .module_id = MODULE_TM,
+ .msg = "MODULE_TM"
+ }, {
+ .module_id = MODULE_RCB_TX,
+ .msg = "MODULE_RCB_TX"
+ }, {
+ .module_id = MODULE_TXDMA,
+ .msg = "MODULE_TXDMA"
+ }, {
+ .module_id = MODULE_MASTER,
+ .msg = "MODULE_MASTER"
+ }, {
+ .module_id = MODULE_ROCEE_TOP,
+ .msg = "MODULE_ROCEE_TOP"
+ }, {
+ .module_id = MODULE_ROCEE_TIMER,
+ .msg = "MODULE_ROCEE_TIMER"
+ }, {
+ .module_id = MODULE_ROCEE_MDB,
+ .msg = "MODULE_ROCEE_MDB"
+ }, {
+ .module_id = MODULE_ROCEE_TSP,
+ .msg = "MODULE_ROCEE_TSP"
+ }, {
+ .module_id = MODULE_ROCEE_TRP,
+ .msg = "MODULE_ROCEE_TRP"
+ }, {
+ .module_id = MODULE_ROCEE_SCC,
+ .msg = "MODULE_ROCEE_SCC"
+ }, {
+ .module_id = MODULE_ROCEE_CAEP,
+ .msg = "MODULE_ROCEE_CAEP"
+ }, {
+ .module_id = MODULE_ROCEE_GEN_AC,
+ .msg = "MODULE_ROCEE_GEN_AC"
+ }, {
+ .module_id = MODULE_ROCEE_QMM,
+ .msg = "MODULE_ROCEE_QMM"
+ }, {
+ .module_id = MODULE_ROCEE_LSAN,
+ .msg = "MODULE_ROCEE_LSAN"
+ }
+};
+
+static const struct hclge_hw_type_id hclge_hw_type_id_st[] = {
+ {
+ .type_id = NONE_ERROR,
+ .msg = "none_error"
+ }, {
+ .type_id = FIFO_ERROR,
+ .msg = "fifo_error"
+ }, {
+ .type_id = MEMORY_ERROR,
+ .msg = "memory_error"
+ }, {
+ .type_id = POISON_ERROR,
+ .msg = "poison_error"
+ }, {
+ .type_id = MSIX_ECC_ERROR,
+ .msg = "msix_ecc_error"
+ }, {
+ .type_id = TQP_INT_ECC_ERROR,
+ .msg = "tqp_int_ecc_error"
+ }, {
+ .type_id = PF_ABNORMAL_INT_ERROR,
+ .msg = "pf_abnormal_int_error"
+ }, {
+ .type_id = MPF_ABNORMAL_INT_ERROR,
+ .msg = "mpf_abnormal_int_error"
+ }, {
+ .type_id = COMMON_ERROR,
+ .msg = "common_error"
+ }, {
+ .type_id = PORT_ERROR,
+ .msg = "port_error"
+ }, {
+ .type_id = ETS_ERROR,
+ .msg = "ets_error"
+ }, {
+ .type_id = NCSI_ERROR,
+ .msg = "ncsi_error"
+ }, {
+ .type_id = GLB_ERROR,
+ .msg = "glb_error"
+ }, {
+ .type_id = ROCEE_NORMAL_ERR,
+ .msg = "rocee_normal_error"
+ }, {
+ .type_id = ROCEE_OVF_ERR,
+ .msg = "rocee_ovf_error"
+ }
+};
+
static void hclge_log_error(struct device *dev, char *reg,
const struct hclge_hw_error *err,
u32 err_sts, unsigned long *reset_requests)
@@ -1611,11 +1739,27 @@ static const struct hclge_hw_blk hw_blk[] = {
{ /* sentinel */ }
};
+static void hclge_config_all_msix_error(struct hclge_dev *hdev, bool enable)
+{
+ u32 reg_val;
+
+ reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG);
+
+ if (enable)
+ reg_val |= BIT(HCLGE_VECTOR0_ALL_MSIX_ERR_B);
+ else
+ reg_val &= ~BIT(HCLGE_VECTOR0_ALL_MSIX_ERR_B);
+
+ hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG, reg_val);
+}
+
int hclge_config_nic_hw_error(struct hclge_dev *hdev, bool state)
{
const struct hclge_hw_blk *module = hw_blk;
int ret = 0;
+ hclge_config_all_msix_error(hdev, state);
+
while (module->name) {
if (module->config_err_int) {
ret = module->config_err_int(hdev, state);
@@ -1876,11 +2020,8 @@ static int hclge_handle_pf_msix_error(struct hclge_dev *hdev,
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 */
@@ -1903,16 +2044,45 @@ static int hclge_handle_all_hw_msix_error(struct hclge_dev *hdev,
if (ret)
goto msi_error;
+ ret = hclge_handle_mac_tnl(hdev);
+
+msi_error:
+ kfree(desc);
+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,
+ "failed to handle msix error during dev init\n");
+ return -EAGAIN;
+ }
+
+ return hclge_handle_all_hw_msix_error(hdev, reset_requests);
+}
+
+int hclge_handle_mac_tnl(struct hclge_dev *hdev)
+{
+ struct hclge_mac_tnl_stats mac_tnl_stats;
+ struct device *dev = &hdev->pdev->dev;
+ struct hclge_desc desc;
+ u32 status;
+ int ret;
+
/* query and clear mac tnl interruptions */
- hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_MAC_TNL_INT,
- true);
- ret = hclge_cmd_send(&hdev->hw, &desc[0], 1);
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_MAC_TNL_INT, true);
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
- dev_err(dev, "query mac tnl int cmd failed (%d)\n", ret);
- goto msi_error;
+ dev_err(dev, "failed to query mac tnl int, ret = %d.\n", ret);
+ return ret;
}
- status = le32_to_cpu(desc->data[0]);
+ status = le32_to_cpu(desc.data[0]);
if (status) {
/* When mac tnl interrupt occurs, we record current time and
* register status here in a fifo, then clear the status. So
@@ -1924,33 +2094,15 @@ static int hclge_handle_all_hw_msix_error(struct hclge_dev *hdev,
kfifo_put(&hdev->mac_tnl_log, mac_tnl_stats);
ret = hclge_clear_mac_tnl_int(hdev);
if (ret)
- dev_err(dev, "clear mac tnl int failed (%d)\n", ret);
+ dev_err(dev, "failed to clear mac tnl int, ret = %d.\n",
+ ret);
}
-msi_error:
- kfree(desc);
-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;
@@ -1999,3 +2151,207 @@ void hclge_handle_all_hns_hw_errors(struct hnae3_ae_dev *ae_dev)
msi_error:
kfree(desc);
}
+
+bool hclge_find_error_source(struct hclge_dev *hdev)
+{
+ u32 msix_src_flag, hw_err_src_flag;
+
+ msix_src_flag = hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS) &
+ HCLGE_VECTOR0_REG_MSIX_MASK;
+
+ hw_err_src_flag = hclge_read_dev(&hdev->hw,
+ HCLGE_RAS_PF_OTHER_INT_STS_REG) &
+ HCLGE_RAS_REG_ERR_MASK;
+
+ return msix_src_flag || hw_err_src_flag;
+}
+
+void hclge_handle_occurred_error(struct hclge_dev *hdev)
+{
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
+
+ if (hclge_find_error_source(hdev))
+ hclge_handle_error_info_log(ae_dev);
+}
+
+static void
+hclge_handle_error_type_reg_log(struct device *dev,
+ struct hclge_mod_err_info *mod_info,
+ struct hclge_type_reg_err_info *type_reg_info)
+{
+#define HCLGE_ERR_TYPE_MASK 0x7F
+#define HCLGE_ERR_TYPE_IS_RAS_OFFSET 7
+
+ u8 mod_id, total_module, type_id, total_type, i, is_ras;
+ u8 index_module = MODULE_NONE;
+ u8 index_type = NONE_ERROR;
+
+ mod_id = mod_info->mod_id;
+ type_id = type_reg_info->type_id & HCLGE_ERR_TYPE_MASK;
+ is_ras = type_reg_info->type_id >> HCLGE_ERR_TYPE_IS_RAS_OFFSET;
+
+ total_module = ARRAY_SIZE(hclge_hw_module_id_st);
+ total_type = ARRAY_SIZE(hclge_hw_type_id_st);
+
+ for (i = 0; i < total_module; i++) {
+ if (mod_id == hclge_hw_module_id_st[i].module_id) {
+ index_module = i;
+ break;
+ }
+ }
+
+ for (i = 0; i < total_type; i++) {
+ if (type_id == hclge_hw_type_id_st[i].type_id) {
+ index_type = i;
+ break;
+ }
+ }
+
+ if (index_module != MODULE_NONE && index_type != NONE_ERROR)
+ dev_err(dev,
+ "found %s %s, is %s error.\n",
+ hclge_hw_module_id_st[index_module].msg,
+ hclge_hw_type_id_st[index_type].msg,
+ is_ras ? "ras" : "msix");
+ else
+ dev_err(dev,
+ "unknown module[%u] or type[%u].\n", mod_id, type_id);
+
+ dev_err(dev, "reg_value:\n");
+ for (i = 0; i < type_reg_info->reg_num; i++)
+ dev_err(dev, "0x%08x\n", type_reg_info->hclge_reg[i]);
+}
+
+static void hclge_handle_error_module_log(struct hnae3_ae_dev *ae_dev,
+ const u32 *buf, u32 buf_size)
+{
+ struct hclge_type_reg_err_info *type_reg_info;
+ struct hclge_dev *hdev = ae_dev->priv;
+ struct device *dev = &hdev->pdev->dev;
+ struct hclge_mod_err_info *mod_info;
+ struct hclge_sum_err_info *sum_info;
+ u8 mod_num, err_num, i;
+ u32 offset = 0;
+
+ sum_info = (struct hclge_sum_err_info *)&buf[offset++];
+ if (sum_info->reset_type &&
+ sum_info->reset_type != HNAE3_NONE_RESET)
+ set_bit(sum_info->reset_type, &ae_dev->hw_err_reset_req);
+ mod_num = sum_info->mod_num;
+
+ while (mod_num--) {
+ if (offset >= buf_size) {
+ dev_err(dev, "The offset(%u) exceeds buf's size(%u).\n",
+ offset, buf_size);
+ return;
+ }
+ mod_info = (struct hclge_mod_err_info *)&buf[offset++];
+ err_num = mod_info->err_num;
+
+ for (i = 0; i < err_num; i++) {
+ if (offset >= buf_size) {
+ dev_err(dev,
+ "The offset(%u) exceeds buf size(%u).\n",
+ offset, buf_size);
+ return;
+ }
+
+ type_reg_info = (struct hclge_type_reg_err_info *)
+ &buf[offset++];
+ hclge_handle_error_type_reg_log(dev, mod_info,
+ type_reg_info);
+
+ offset += type_reg_info->reg_num;
+ }
+ }
+}
+
+static int hclge_query_all_err_bd_num(struct hclge_dev *hdev, u32 *bd_num)
+{
+ struct device *dev = &hdev->pdev->dev;
+ struct hclge_desc desc_bd;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc_bd, HCLGE_QUERY_ALL_ERR_BD_NUM, true);
+ ret = hclge_cmd_send(&hdev->hw, &desc_bd, 1);
+ if (ret) {
+ dev_err(dev, "failed to query error bd_num, ret = %d.\n", ret);
+ return ret;
+ }
+
+ *bd_num = le32_to_cpu(desc_bd.data[0]);
+ if (!(*bd_num)) {
+ dev_err(dev, "The value of bd_num is 0!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hclge_query_all_err_info(struct hclge_dev *hdev,
+ struct hclge_desc *desc, u32 bd_num)
+{
+ struct device *dev = &hdev->pdev->dev;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(desc, HCLGE_QUERY_ALL_ERR_INFO, true);
+ ret = hclge_cmd_send(&hdev->hw, desc, bd_num);
+ if (ret)
+ dev_err(dev, "failed to query error info, ret = %d.\n", ret);
+
+ return ret;
+}
+
+int hclge_handle_error_info_log(struct hnae3_ae_dev *ae_dev)
+{
+ u32 bd_num, desc_len, buf_len, buf_size, i;
+ struct hclge_dev *hdev = ae_dev->priv;
+ struct hclge_desc *desc;
+ __le32 *desc_data;
+ u32 *buf;
+ int ret;
+
+ ret = hclge_query_all_err_bd_num(hdev, &bd_num);
+ if (ret)
+ goto out;
+
+ desc_len = bd_num * sizeof(struct hclge_desc);
+ desc = kzalloc(desc_len, GFP_KERNEL);
+ if (!desc) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = hclge_query_all_err_info(hdev, desc, bd_num);
+ if (ret)
+ goto err_desc;
+
+ buf_len = bd_num * sizeof(struct hclge_desc) - HCLGE_DESC_NO_DATA_LEN;
+ buf_size = buf_len / sizeof(u32);
+
+ desc_data = kzalloc(buf_len, GFP_KERNEL);
+ if (!desc_data) {
+ ret = -ENOMEM;
+ goto err_desc;
+ }
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto err_buf_alloc;
+ }
+
+ memcpy(desc_data, &desc[0].data[0], buf_len);
+ for (i = 0; i < buf_size; i++)
+ buf[i] = le32_to_cpu(desc_data[i]);
+
+ hclge_handle_error_module_log(ae_dev, buf, buf_size);
+ kfree(buf);
+
+err_buf_alloc:
+ kfree(desc_data);
+err_desc:
+ kfree(desc);
+out:
+ return ret;
+}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h
index d647f3c84134..07987fb8332e 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h
@@ -15,6 +15,8 @@
#define HCLGE_RAS_PF_OTHER_INT_STS_REG 0x20B00
#define HCLGE_RAS_REG_NFE_MASK 0xFF00
#define HCLGE_RAS_REG_ROCEE_ERR_MASK 0x3000000
+#define HCLGE_RAS_REG_ERR_MASK \
+ (HCLGE_RAS_REG_NFE_MASK | HCLGE_RAS_REG_ROCEE_ERR_MASK)
#define HCLGE_VECTOR0_REG_MSIX_MASK 0x1FF00
@@ -107,6 +109,10 @@
#define HCLGE_ROCEE_OVF_ERR_INT_MASK 0x10000
#define HCLGE_ROCEE_OVF_ERR_TYPE_MASK 0x3F
+#define HCLGE_DESC_DATA_MAX 8
+#define HCLGE_REG_NUM_MAX 256
+#define HCLGE_DESC_NO_DATA_LEN 8
+
enum hclge_err_int_type {
HCLGE_ERR_INT_MSIX = 0,
HCLGE_ERR_INT_RAS_CE = 1,
@@ -114,6 +120,56 @@ enum hclge_err_int_type {
HCLGE_ERR_INT_RAS_FE = 3,
};
+enum hclge_mod_name_list {
+ MODULE_NONE = 0,
+ MODULE_BIOS_COMMON = 1,
+ MODULE_GE = 2,
+ MODULE_IGU_EGU = 3,
+ MODULE_LGE = 4,
+ MODULE_NCSI = 5,
+ MODULE_PPP = 6,
+ MODULE_QCN = 7,
+ MODULE_RCB_RX = 8,
+ MODULE_RTC = 9,
+ MODULE_SSU = 10,
+ MODULE_TM = 11,
+ MODULE_RCB_TX = 12,
+ MODULE_TXDMA = 13,
+ MODULE_MASTER = 14,
+ /* add new MODULE NAME for NIC here in order */
+ MODULE_ROCEE_TOP = 40,
+ MODULE_ROCEE_TIMER = 41,
+ MODULE_ROCEE_MDB = 42,
+ MODULE_ROCEE_TSP = 43,
+ MODULE_ROCEE_TRP = 44,
+ MODULE_ROCEE_SCC = 45,
+ MODULE_ROCEE_CAEP = 46,
+ MODULE_ROCEE_GEN_AC = 47,
+ MODULE_ROCEE_QMM = 48,
+ MODULE_ROCEE_LSAN = 49,
+ /* add new MODULE NAME for RoCEE here in order */
+};
+
+enum hclge_err_type_list {
+ NONE_ERROR = 0,
+ FIFO_ERROR = 1,
+ MEMORY_ERROR = 2,
+ POISON_ERROR = 3,
+ MSIX_ECC_ERROR = 4,
+ TQP_INT_ECC_ERROR = 5,
+ PF_ABNORMAL_INT_ERROR = 6,
+ MPF_ABNORMAL_INT_ERROR = 7,
+ COMMON_ERROR = 8,
+ PORT_ERROR = 9,
+ ETS_ERROR = 10,
+ NCSI_ERROR = 11,
+ GLB_ERROR = 12,
+ /* add new ERROR TYPE for NIC here in order */
+ ROCEE_NORMAL_ERR = 40,
+ ROCEE_OVF_ERR = 41,
+ /* add new ERROR TYPE for ROCEE here in order */
+};
+
struct hclge_hw_blk {
u32 msk;
const char *name;
@@ -126,11 +182,44 @@ struct hclge_hw_error {
enum hnae3_reset_type reset_level;
};
+struct hclge_hw_module_id {
+ enum hclge_mod_name_list module_id;
+ const char *msg;
+};
+
+struct hclge_hw_type_id {
+ enum hclge_err_type_list type_id;
+ const char *msg;
+};
+
+struct hclge_sum_err_info {
+ u8 reset_type;
+ u8 mod_num;
+ u8 rsv[2];
+};
+
+struct hclge_mod_err_info {
+ u8 mod_id;
+ u8 err_num;
+ u8 rsv[2];
+};
+
+struct hclge_type_reg_err_info {
+ u8 type_id;
+ u8 reg_num;
+ u8 rsv[2];
+ u32 hclge_reg[HCLGE_REG_NUM_MAX];
+};
+
int hclge_config_mac_tnl_int(struct hclge_dev *hdev, bool en);
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);
+bool hclge_find_error_source(struct hclge_dev *hdev);
+void hclge_handle_occurred_error(struct hclge_dev *hdev);
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);
+int hclge_handle_error_info_log(struct hnae3_ae_dev *ae_dev);
+int hclge_handle_mac_tnl(struct hclge_dev *hdev);
#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index 6304aed49f22..dd3354a57c62 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -1279,6 +1279,7 @@ static u32 hclge_get_max_speed(u16 speed_ability)
static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc)
{
+#define HCLGE_TX_SPARE_SIZE_UNIT 4096
#define SPEED_ABILITY_EXT_SHIFT 8
struct hclge_cfg_param_cmd *req;
@@ -1334,6 +1335,10 @@ static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc)
HCLGE_CFG_SPEED_ABILITY_EXT_S);
cfg->speed_ability |= speed_ability_ext << SPEED_ABILITY_EXT_SHIFT;
+ cfg->vlan_fliter_cap = hnae3_get_field(__le32_to_cpu(req->param[1]),
+ HCLGE_CFG_VLAN_FLTR_CAP_M,
+ HCLGE_CFG_VLAN_FLTR_CAP_S);
+
cfg->umv_space = hnae3_get_field(__le32_to_cpu(req->param[1]),
HCLGE_CFG_UMV_TBL_SPACE_M,
HCLGE_CFG_UMV_TBL_SPACE_S);
@@ -1354,6 +1359,15 @@ static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc)
cfg->pf_rss_size_max = cfg->pf_rss_size_max ?
1U << cfg->pf_rss_size_max :
cfg->vf_rss_size_max;
+
+ /* The unit of the tx spare buffer size queried from configuration
+ * file is HCLGE_TX_SPARE_SIZE_UNIT(4096) bytes, so a conversion is
+ * needed here.
+ */
+ cfg->tx_spare_buf_size = hnae3_get_field(__le32_to_cpu(req->param[2]),
+ HCLGE_CFG_TX_SPARE_BUF_SIZE_M,
+ HCLGE_CFG_TX_SPARE_BUF_SIZE_S);
+ cfg->tx_spare_buf_size *= HCLGE_TX_SPARE_SIZE_UNIT;
}
/* hclge_get_cfg: query the static parameter from flash
@@ -1513,6 +1527,7 @@ static void hclge_init_kdump_kernel_config(struct hclge_dev *hdev)
static int hclge_configure(struct hclge_dev *hdev)
{
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
struct hclge_cfg cfg;
unsigned int i;
int ret;
@@ -1534,6 +1549,9 @@ static int hclge_configure(struct hclge_dev *hdev)
hdev->tc_max = cfg.tc_num;
hdev->tm_info.hw_pfc_map = 0;
hdev->wanted_umv_size = cfg.umv_space;
+ hdev->tx_spare_buf_size = cfg.tx_spare_buf_size;
+ if (cfg.vlan_fliter_cap == HCLGE_VLAN_FLTR_CAN_MDF)
+ set_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps);
if (hnae3_dev_fd_supported(hdev)) {
hdev->fd_en = true;
@@ -1729,6 +1747,7 @@ static int hclge_knic_setup(struct hclge_vport *vport, u16 num_tqps,
kinfo->num_rx_desc = num_rx_desc;
kinfo->rx_buf_len = hdev->rx_buf_len;
+ kinfo->tx_spare_buf_size = hdev->tx_spare_buf_size;
kinfo->tqp = devm_kcalloc(&hdev->pdev->dev, num_tqps,
sizeof(struct hnae3_queue *), GFP_KERNEL);
@@ -1843,6 +1862,7 @@ static int hclge_alloc_vport(struct hclge_dev *hdev)
vport->mps = HCLGE_MAC_DEFAULT_FRAME;
vport->port_base_vlan_cfg.state = HNAE3_PORT_BASE_VLAN_DISABLE;
vport->rxvlan_cfg.rx_vlan_offload_en = true;
+ vport->req_vlan_fltr_en = true;
INIT_LIST_HEAD(&vport->vlan_list);
INIT_LIST_HEAD(&vport->uc_mac_list);
INIT_LIST_HEAD(&vport->mc_mac_list);
@@ -2835,6 +2855,14 @@ static void hclge_reset_task_schedule(struct hclge_dev *hdev)
hclge_wq, &hdev->service_task, 0);
}
+static void hclge_errhand_task_schedule(struct hclge_dev *hdev)
+{
+ if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) &&
+ !test_and_set_bit(HCLGE_STATE_ERR_SERVICE_SCHED, &hdev->state))
+ mod_delayed_work_on(cpumask_first(&hdev->affinity_mask),
+ hclge_wq, &hdev->service_task, 0);
+}
+
void hclge_task_schedule(struct hclge_dev *hdev, unsigned long delay_time)
{
if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) &&
@@ -3291,11 +3319,13 @@ static int hclge_set_vf_link_state(struct hnae3_handle *handle, int vf,
static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval)
{
- u32 cmdq_src_reg, msix_src_reg;
+ u32 cmdq_src_reg, msix_src_reg, hw_err_src_reg;
/* fetch the events from their corresponding regs */
cmdq_src_reg = hclge_read_dev(&hdev->hw, HCLGE_VECTOR0_CMDQ_SRC_REG);
msix_src_reg = hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS);
+ hw_err_src_reg = hclge_read_dev(&hdev->hw,
+ HCLGE_RAS_PF_OTHER_INT_STS_REG);
/* Assumption: If by any chance reset and mailbox events are reported
* together then we will only process reset event in this go and will
@@ -3323,10 +3353,15 @@ static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval)
return HCLGE_VECTOR0_EVENT_RST;
}
- /* check for vector0 msix event source */
- if (msix_src_reg & HCLGE_VECTOR0_REG_MSIX_MASK) {
- *clearval = msix_src_reg;
+ /* check for vector0 msix event and hardware error event source */
+ if (msix_src_reg & HCLGE_VECTOR0_REG_MSIX_MASK ||
+ hw_err_src_reg & HCLGE_RAS_REG_ERR_MASK)
return HCLGE_VECTOR0_EVENT_ERR;
+
+ /* check for vector0 ptp event source */
+ if (BIT(HCLGE_VECTOR0_REG_PTP_INT_B) & msix_src_reg) {
+ *clearval = msix_src_reg;
+ return HCLGE_VECTOR0_EVENT_PTP;
}
/* check for vector0 mailbox(=CMDQ RX) event source */
@@ -3338,9 +3373,8 @@ static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval)
/* print other vector0 event source */
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;
+ "INT status: CMDQ(%#x) HW errors(%#x) other(%#x)\n",
+ cmdq_src_reg, hw_err_src_reg, msix_src_reg);
return HCLGE_VECTOR0_EVENT_OTHER;
}
@@ -3349,6 +3383,7 @@ static void hclge_clear_event_cause(struct hclge_dev *hdev, u32 event_type,
u32 regclr)
{
switch (event_type) {
+ case HCLGE_VECTOR0_EVENT_PTP:
case HCLGE_VECTOR0_EVENT_RST:
hclge_write_dev(&hdev->hw, HCLGE_MISC_RESET_STS_REG, regclr);
break;
@@ -3377,6 +3412,7 @@ 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;
+ unsigned long flags;
u32 clearval = 0;
u32 event_cause;
@@ -3386,21 +3422,16 @@ static irqreturn_t hclge_misc_irq_handle(int irq, void *data)
/* vector 0 interrupt is shared with reset and mailbox source events.*/
switch (event_cause) {
case HCLGE_VECTOR0_EVENT_ERR:
- /* we do not know what type of reset is required now. This could
- * only be decided after we fetch the type of errors which
- * caused this event. Therefore, we will do below for now:
- * 1. Assert HNAE3_UNKNOWN_RESET type of reset. This means we
- * have defered type of reset to be used.
- * 2. Schedule the reset service task.
- * 3. When service task receives HNAE3_UNKNOWN_RESET type it
- * will fetch the correct type of reset. This would be done
- * by first decoding the types of errors.
- */
- set_bit(HNAE3_UNKNOWN_RESET, &hdev->reset_request);
- fallthrough;
+ hclge_errhand_task_schedule(hdev);
+ break;
case HCLGE_VECTOR0_EVENT_RST:
hclge_reset_task_schedule(hdev);
break;
+ case HCLGE_VECTOR0_EVENT_PTP:
+ spin_lock_irqsave(&hdev->ptp->lock, flags);
+ hclge_ptp_clean_tx_hwts(hdev);
+ spin_unlock_irqrestore(&hdev->ptp->lock, flags);
+ break;
case HCLGE_VECTOR0_EVENT_MBX:
/* If we are here then,
* 1. Either we are not handling any mbx task and we are not
@@ -3421,15 +3452,11 @@ static irqreturn_t hclge_misc_irq_handle(int irq, void *data)
hclge_clear_event_cause(hdev, event_cause, clearval);
- /* Enable interrupt if it is not cause by reset. And when
- * clearval equal to 0, it means interrupt status may be
- * cleared by hardware before driver reads status register.
- * For this case, vector0 interrupt also should be enabled.
- */
- if (!clearval ||
- event_cause == HCLGE_VECTOR0_EVENT_MBX) {
+ /* Enable interrupt if it is not caused by reset event or error event */
+ if (event_cause == HCLGE_VECTOR0_EVENT_PTP ||
+ event_cause == HCLGE_VECTOR0_EVENT_MBX ||
+ event_cause == HCLGE_VECTOR0_EVENT_OTHER)
hclge_enable_vector(&hdev->misc_vector, true);
- }
return IRQ_HANDLED;
}
@@ -3786,28 +3813,6 @@ static enum hnae3_reset_type hclge_get_reset_level(struct hnae3_ae_dev *ae_dev,
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)) {
- u32 msix_sts_reg = hclge_read_dev(&hdev->hw,
- HCLGE_MISC_VECTOR_INT_STS);
- /* we will intentionally ignore any errors from this function
- * as we will end up in *some* reset request in any case
- */
- if (hclge_handle_hw_msix_error(hdev, addr))
- dev_info(&hdev->pdev->dev, "received msix interrupt 0x%x\n",
- msix_sts_reg);
-
- clear_bit(HNAE3_UNKNOWN_RESET, addr);
- /* We defered the clearing of the error event which caused
- * interrupt since it was not posssible to do that in
- * interrupt context (and this is the reason we introduced
- * new UNKNOWN reset type). Now, the errors have been
- * handled and cleared in hardware we can safely enable
- * interrupts. This is an exception to the norm.
- */
- hclge_enable_vector(&hdev->misc_vector, true);
- }
-
/* return the highest priority reset level amongst all */
if (test_bit(HNAE3_IMP_RESET, addr)) {
rst_level = HNAE3_IMP_RESET;
@@ -3936,6 +3941,21 @@ static int hclge_reset_prepare_wait(struct hclge_dev *hdev)
return ret;
}
+static void hclge_show_rst_info(struct hclge_dev *hdev)
+{
+ char *buf;
+
+ buf = kzalloc(HCLGE_DBG_RESET_INFO_LEN, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ hclge_dbg_dump_rst_info(hdev, buf, HCLGE_DBG_RESET_INFO_LEN);
+
+ dev_info(&hdev->pdev->dev, "dump reset info:\n%s", buf);
+
+ kfree(buf);
+}
+
static bool hclge_reset_err_handle(struct hclge_dev *hdev)
{
#define MAX_RESET_FAIL_CNT 5
@@ -3966,7 +3986,7 @@ static bool hclge_reset_err_handle(struct hclge_dev *hdev)
dev_err(&hdev->pdev->dev, "Reset fail!\n");
- hclge_dbg_dump_rst_info(hdev);
+ hclge_show_rst_info(hdev);
set_bit(HCLGE_STATE_RST_FAIL, &hdev->state);
@@ -4241,6 +4261,68 @@ static void hclge_reset_subtask(struct hclge_dev *hdev)
hdev->reset_type = HNAE3_NONE_RESET;
}
+static void hclge_handle_err_reset_request(struct hclge_dev *hdev)
+{
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
+ enum hnae3_reset_type reset_type;
+
+ if (ae_dev->hw_err_reset_req) {
+ reset_type = hclge_get_reset_level(ae_dev,
+ &ae_dev->hw_err_reset_req);
+ hclge_set_def_reset_request(ae_dev, reset_type);
+ }
+
+ if (hdev->default_reset_request && ae_dev->ops->reset_event)
+ ae_dev->ops->reset_event(hdev->pdev, NULL);
+
+ /* enable interrupt after error handling complete */
+ hclge_enable_vector(&hdev->misc_vector, true);
+}
+
+static void hclge_handle_err_recovery(struct hclge_dev *hdev)
+{
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
+
+ ae_dev->hw_err_reset_req = 0;
+
+ if (hclge_find_error_source(hdev)) {
+ hclge_handle_error_info_log(ae_dev);
+ hclge_handle_mac_tnl(hdev);
+ }
+
+ hclge_handle_err_reset_request(hdev);
+}
+
+static void hclge_misc_err_recovery(struct hclge_dev *hdev)
+{
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
+ struct device *dev = &hdev->pdev->dev;
+ u32 msix_sts_reg;
+
+ msix_sts_reg = hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS);
+ if (msix_sts_reg & HCLGE_VECTOR0_REG_MSIX_MASK) {
+ if (hclge_handle_hw_msix_error
+ (hdev, &hdev->default_reset_request))
+ dev_info(dev, "received msix interrupt 0x%x\n",
+ msix_sts_reg);
+ }
+
+ hclge_handle_hw_ras_error(ae_dev);
+
+ hclge_handle_err_reset_request(hdev);
+}
+
+static void hclge_errhand_service_task(struct hclge_dev *hdev)
+{
+ if (!test_and_clear_bit(HCLGE_STATE_ERR_SERVICE_SCHED, &hdev->state))
+ return;
+
+ if (hnae3_dev_ras_imp_supported(hdev))
+ hclge_handle_err_recovery(hdev);
+ else
+ hclge_misc_err_recovery(hdev);
+}
+
static void hclge_reset_service_task(struct hclge_dev *hdev)
{
if (!test_and_clear_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state))
@@ -4319,19 +4401,43 @@ out:
hclge_task_schedule(hdev, delta);
}
+static void hclge_ptp_service_task(struct hclge_dev *hdev)
+{
+ unsigned long flags;
+
+ if (!test_bit(HCLGE_STATE_PTP_EN, &hdev->state) ||
+ !test_bit(HCLGE_STATE_PTP_TX_HANDLING, &hdev->state) ||
+ !time_is_before_jiffies(hdev->ptp->tx_start + HZ))
+ return;
+
+ /* to prevent concurrence with the irq handler */
+ spin_lock_irqsave(&hdev->ptp->lock, flags);
+
+ /* check HCLGE_STATE_PTP_TX_HANDLING here again, since the irq
+ * handler may handle it just before spin_lock_irqsave().
+ */
+ if (test_bit(HCLGE_STATE_PTP_TX_HANDLING, &hdev->state))
+ hclge_ptp_clean_tx_hwts(hdev);
+
+ spin_unlock_irqrestore(&hdev->ptp->lock, flags);
+}
+
static void hclge_service_task(struct work_struct *work)
{
struct hclge_dev *hdev =
container_of(work, struct hclge_dev, service_task.work);
+ hclge_errhand_service_task(hdev);
hclge_reset_service_task(hdev);
+ hclge_ptp_service_task(hdev);
hclge_mailbox_service_task(hdev);
hclge_periodic_service_task(hdev);
- /* Handle reset and mbx again in case periodical task delays the
- * handling by calling hclge_task_schedule() in
+ /* Handle error recovery, reset and mbx again in case periodical task
+ * delays the handling by calling hclge_task_schedule() in
* hclge_periodic_service_task().
*/
+ hclge_errhand_service_task(hdev);
hclge_reset_service_task(hdev);
hclge_mailbox_service_task(hdev);
}
@@ -5168,9 +5274,8 @@ static int hclge_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc,
static void hclge_request_update_promisc_mode(struct hnae3_handle *handle)
{
struct hclge_vport *vport = hclge_get_vport(handle);
- struct hclge_dev *hdev = vport->back;
- set_bit(HCLGE_STATE_PROMISC_CHANGED, &hdev->state);
+ set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state);
}
static void hclge_sync_fd_state(struct hclge_dev *hdev)
@@ -5895,8 +6000,14 @@ static int hclge_config_action(struct hclge_dev *hdev, u8 stage,
ad_data.queue_id = rule->queue_id;
}
- ad_data.use_counter = false;
- ad_data.counter_id = 0;
+ if (hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_1]) {
+ ad_data.use_counter = true;
+ ad_data.counter_id = rule->vf_id %
+ hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_1];
+ } else {
+ ad_data.use_counter = false;
+ ad_data.counter_id = 0;
+ }
ad_data.use_next_stage = false;
ad_data.next_input_key = 0;
@@ -8035,6 +8146,7 @@ int hclge_vport_start(struct hclge_vport *vport)
struct hclge_dev *hdev = vport->back;
set_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state);
+ set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state);
vport->last_active_jiffies = jiffies;
if (test_bit(vport->vport_id, hdev->vport_config_block)) {
@@ -8776,8 +8888,7 @@ static bool hclge_sync_from_add_list(struct list_head *add_list,
kfree(mac_node);
} else if (mac_node->state == HCLGE_MAC_ACTIVE) {
mac_node->state = HCLGE_MAC_TO_DEL;
- list_del(&mac_node->node);
- list_add_tail(&mac_node->node, mac_list);
+ list_move_tail(&mac_node->node, mac_list);
} else {
list_del(&mac_node->node);
kfree(mac_node);
@@ -8806,8 +8917,7 @@ static void hclge_sync_from_del_list(struct list_head *del_list,
list_del(&mac_node->node);
kfree(mac_node);
} else {
- list_del(&mac_node->node);
- list_add_tail(&mac_node->node, mac_list);
+ list_move_tail(&mac_node->node, mac_list);
}
}
}
@@ -8851,8 +8961,7 @@ static void hclge_sync_vport_mac_table(struct hclge_vport *vport,
list_for_each_entry_safe(mac_node, tmp, list, node) {
switch (mac_node->state) {
case HCLGE_MAC_TO_DEL:
- list_del(&mac_node->node);
- list_add_tail(&mac_node->node, &tmp_del_list);
+ list_move_tail(&mac_node->node, &tmp_del_list);
break;
case HCLGE_MAC_TO_ADD:
new_node = kzalloc(sizeof(*new_node), GFP_ATOMIC);
@@ -8934,8 +9043,7 @@ static void hclge_build_del_list(struct list_head *list,
switch (mac_cfg->state) {
case HCLGE_MAC_TO_DEL:
case HCLGE_MAC_ACTIVE:
- list_del(&mac_cfg->node);
- list_add_tail(&mac_cfg->node, tmp_del_list);
+ list_move_tail(&mac_cfg->node, tmp_del_list);
break;
case HCLGE_MAC_TO_ADD:
if (is_del_list) {
@@ -9030,8 +9138,7 @@ static void hclge_uninit_vport_mac_list(struct hclge_vport *vport,
switch (mac_node->state) {
case HCLGE_MAC_TO_DEL:
case HCLGE_MAC_ACTIVE:
- list_del(&mac_node->node);
- list_add_tail(&mac_node->node, &tmp_del_list);
+ list_move_tail(&mac_node->node, &tmp_del_list);
break;
case HCLGE_MAC_TO_ADD:
list_del(&mac_node->node);
@@ -9360,12 +9467,41 @@ static int hclge_do_ioctl(struct hnae3_handle *handle, struct ifreq *ifr,
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
- if (!hdev->hw.mac.phydev)
- return hclge_mii_ioctl(hdev, ifr, cmd);
+ switch (cmd) {
+ case SIOCGHWTSTAMP:
+ return hclge_ptp_get_cfg(hdev, ifr);
+ case SIOCSHWTSTAMP:
+ return hclge_ptp_set_cfg(hdev, ifr);
+ default:
+ if (!hdev->hw.mac.phydev)
+ return hclge_mii_ioctl(hdev, ifr, cmd);
+ }
return phy_mii_ioctl(hdev->hw.mac.phydev, ifr, cmd);
}
+static int hclge_set_port_vlan_filter_bypass(struct hclge_dev *hdev, u8 vf_id,
+ bool bypass_en)
+{
+ struct hclge_port_vlan_filter_bypass_cmd *req;
+ struct hclge_desc desc;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PORT_VLAN_BYPASS, false);
+ req = (struct hclge_port_vlan_filter_bypass_cmd *)desc.data;
+ req->vf_id = vf_id;
+ hnae3_set_bit(req->bypass_state, HCLGE_INGRESS_BYPASS_B,
+ bypass_en ? 1 : 0);
+
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret)
+ dev_err(&hdev->pdev->dev,
+ "failed to set vport%u port vlan filter bypass state, ret = %d.\n",
+ vf_id, ret);
+
+ return ret;
+}
+
static int hclge_set_vlan_filter_ctrl(struct hclge_dev *hdev, u8 vlan_type,
u8 fe_type, bool filter_en, u8 vf_id)
{
@@ -9399,37 +9535,99 @@ static int hclge_set_vlan_filter_ctrl(struct hclge_dev *hdev, u8 vlan_type,
return ret;
}
-#define HCLGE_FILTER_TYPE_VF 0
-#define HCLGE_FILTER_TYPE_PORT 1
-#define HCLGE_FILTER_FE_EGRESS_V1_B BIT(0)
-#define HCLGE_FILTER_FE_NIC_INGRESS_B BIT(0)
-#define HCLGE_FILTER_FE_NIC_EGRESS_B BIT(1)
-#define HCLGE_FILTER_FE_ROCE_INGRESS_B BIT(2)
-#define HCLGE_FILTER_FE_ROCE_EGRESS_B BIT(3)
-#define HCLGE_FILTER_FE_EGRESS (HCLGE_FILTER_FE_NIC_EGRESS_B \
- | HCLGE_FILTER_FE_ROCE_EGRESS_B)
-#define HCLGE_FILTER_FE_INGRESS (HCLGE_FILTER_FE_NIC_INGRESS_B \
- | HCLGE_FILTER_FE_ROCE_INGRESS_B)
+static int hclge_set_vport_vlan_filter(struct hclge_vport *vport, bool enable)
+{
+ struct hclge_dev *hdev = vport->back;
+ struct hnae3_ae_dev *ae_dev = hdev->ae_dev;
+ int ret;
+
+ if (hdev->ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2)
+ return hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
+ HCLGE_FILTER_FE_EGRESS_V1_B,
+ enable, vport->vport_id);
+
+ ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
+ HCLGE_FILTER_FE_EGRESS, enable,
+ vport->vport_id);
+ if (ret)
+ return ret;
+
+ if (test_bit(HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B, ae_dev->caps))
+ ret = hclge_set_port_vlan_filter_bypass(hdev, vport->vport_id,
+ !enable);
+ else if (!vport->vport_id)
+ ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT,
+ HCLGE_FILTER_FE_INGRESS,
+ enable, 0);
+
+ return ret;
+}
-static void hclge_enable_vlan_filter(struct hnae3_handle *handle, bool enable)
+static bool hclge_need_enable_vport_vlan_filter(struct hclge_vport *vport)
{
- struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hnae3_handle *handle = &vport->nic;
+ struct hclge_vport_vlan_cfg *vlan, *tmp;
struct hclge_dev *hdev = vport->back;
- if (hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2) {
- hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
- HCLGE_FILTER_FE_EGRESS, enable, 0);
- hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT,
- HCLGE_FILTER_FE_INGRESS, enable, 0);
- } else {
- hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
- HCLGE_FILTER_FE_EGRESS_V1_B, enable,
- 0);
+ if (vport->vport_id) {
+ if (vport->port_base_vlan_cfg.state !=
+ HNAE3_PORT_BASE_VLAN_DISABLE)
+ return true;
+
+ if (vport->vf_info.trusted && vport->vf_info.request_uc_en)
+ return false;
+ } else if (handle->netdev_flags & HNAE3_USER_UPE) {
+ return false;
}
- if (enable)
- handle->netdev_flags |= HNAE3_VLAN_FLTR;
- else
- handle->netdev_flags &= ~HNAE3_VLAN_FLTR;
+
+ if (!vport->req_vlan_fltr_en)
+ return false;
+
+ /* compatible with former device, always enable vlan filter */
+ if (!test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, hdev->ae_dev->caps))
+ return true;
+
+ list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node)
+ if (vlan->vlan_id != 0)
+ return true;
+
+ return false;
+}
+
+int hclge_enable_vport_vlan_filter(struct hclge_vport *vport, bool request_en)
+{
+ struct hclge_dev *hdev = vport->back;
+ bool need_en;
+ int ret;
+
+ mutex_lock(&hdev->vport_lock);
+
+ vport->req_vlan_fltr_en = request_en;
+
+ need_en = hclge_need_enable_vport_vlan_filter(vport);
+ if (need_en == vport->cur_vlan_fltr_en) {
+ mutex_unlock(&hdev->vport_lock);
+ return 0;
+ }
+
+ ret = hclge_set_vport_vlan_filter(vport, need_en);
+ if (ret) {
+ mutex_unlock(&hdev->vport_lock);
+ return ret;
+ }
+
+ vport->cur_vlan_fltr_en = need_en;
+
+ mutex_unlock(&hdev->vport_lock);
+
+ return 0;
+}
+
+static int hclge_enable_vlan_filter(struct hnae3_handle *handle, bool enable)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+
+ return hclge_enable_vport_vlan_filter(vport, enable);
}
static int hclge_set_vf_vlan_filter_cmd(struct hclge_dev *hdev, u16 vfid,
@@ -9709,7 +9907,7 @@ static int hclge_set_vlan_rx_offload_cfg(struct hclge_vport *vport)
static int hclge_vlan_offload_cfg(struct hclge_vport *vport,
u16 port_base_vlan_state,
- u16 vlan_tag)
+ u16 vlan_tag, u8 qos)
{
int ret;
@@ -9723,7 +9921,8 @@ static int hclge_vlan_offload_cfg(struct hclge_vport *vport,
vport->txvlan_cfg.accept_tag1 =
ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3;
vport->txvlan_cfg.insert_tag1_en = true;
- vport->txvlan_cfg.default_tag1 = vlan_tag;
+ vport->txvlan_cfg.default_tag1 = (qos << VLAN_PRIO_SHIFT) |
+ vlan_tag;
}
vport->txvlan_cfg.accept_untag1 = true;
@@ -9822,6 +10021,7 @@ static int hclge_init_vlan_config(struct hclge_dev *hdev)
vport->vport_id);
if (ret)
return ret;
+ vport->cur_vlan_fltr_en = true;
}
ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT,
@@ -9837,8 +10037,6 @@ static int hclge_init_vlan_config(struct hclge_dev *hdev)
return ret;
}
- handle->netdev_flags |= HNAE3_VLAN_FLTR;
-
hdev->vlan_type_cfg.rx_in_fst_vlan_type = HCLGE_DEF_VLAN_TYPE;
hdev->vlan_type_cfg.rx_in_sec_vlan_type = HCLGE_DEF_VLAN_TYPE;
hdev->vlan_type_cfg.rx_ot_fst_vlan_type = HCLGE_DEF_VLAN_TYPE;
@@ -9852,13 +10050,15 @@ static int hclge_init_vlan_config(struct hclge_dev *hdev)
for (i = 0; i < hdev->num_alloc_vport; i++) {
u16 vlan_tag;
+ u8 qos;
vport = &hdev->vport[i];
vlan_tag = vport->port_base_vlan_cfg.vlan_info.vlan_tag;
+ qos = vport->port_base_vlan_cfg.vlan_info.qos;
ret = hclge_vlan_offload_cfg(vport,
vport->port_base_vlan_cfg.state,
- vlan_tag);
+ vlan_tag, qos);
if (ret)
return ret;
}
@@ -10033,7 +10233,6 @@ static void hclge_restore_hw_table(struct hclge_dev *hdev)
hclge_restore_mac_table_common(vport);
hclge_restore_vport_vlan_table(vport);
- set_bit(HCLGE_STATE_PROMISC_CHANGED, &hdev->state);
set_bit(HCLGE_STATE_FD_USER_DEF_CHANGED, &hdev->state);
hclge_restore_fd_entries(handle);
}
@@ -10060,6 +10259,14 @@ int hclge_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable)
return hclge_set_vlan_rx_offload_cfg(vport);
}
+static void hclge_set_vport_vlan_fltr_change(struct hclge_vport *vport)
+{
+ struct hclge_dev *hdev = vport->back;
+
+ if (test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, hdev->ae_dev->caps))
+ set_bit(HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE, &vport->state);
+}
+
static int hclge_update_vlan_filter_entries(struct hclge_vport *vport,
u16 port_base_vlan_state,
struct hclge_vlan_info *new_info,
@@ -10070,6 +10277,10 @@ static int hclge_update_vlan_filter_entries(struct hclge_vport *vport,
if (port_base_vlan_state == HNAE3_PORT_BASE_VLAN_ENABLE) {
hclge_rm_vport_all_vlan_table(vport, false);
+ /* force clear VLAN 0 */
+ ret = hclge_set_vf_vlan_common(hdev, vport->vport_id, true, 0);
+ if (ret)
+ return ret;
return hclge_set_vlan_filter_hw(hdev,
htons(new_info->vlan_proto),
vport->vport_id,
@@ -10077,6 +10288,11 @@ static int hclge_update_vlan_filter_entries(struct hclge_vport *vport,
false);
}
+ /* force add VLAN 0 */
+ ret = hclge_set_vf_vlan_common(hdev, vport->vport_id, false, 0);
+ if (ret)
+ return ret;
+
ret = hclge_set_vlan_filter_hw(hdev, htons(old_info->vlan_proto),
vport->vport_id, old_info->vlan_tag,
true);
@@ -10086,6 +10302,18 @@ static int hclge_update_vlan_filter_entries(struct hclge_vport *vport,
return hclge_add_vport_all_vlan_table(vport);
}
+static bool hclge_need_update_vlan_filter(const struct hclge_vlan_info *new_cfg,
+ const struct hclge_vlan_info *old_cfg)
+{
+ if (new_cfg->vlan_tag != old_cfg->vlan_tag)
+ return true;
+
+ if (new_cfg->vlan_tag == 0 && (new_cfg->qos == 0 || old_cfg->qos == 0))
+ return true;
+
+ return false;
+}
+
int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state,
struct hclge_vlan_info *vlan_info)
{
@@ -10096,10 +10324,14 @@ int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state,
old_vlan_info = &vport->port_base_vlan_cfg.vlan_info;
- ret = hclge_vlan_offload_cfg(vport, state, vlan_info->vlan_tag);
+ ret = hclge_vlan_offload_cfg(vport, state, vlan_info->vlan_tag,
+ vlan_info->qos);
if (ret)
return ret;
+ if (!hclge_need_update_vlan_filter(vlan_info, old_vlan_info))
+ goto out;
+
if (state == HNAE3_PORT_BASE_VLAN_MODIFY) {
/* add new VLAN tag */
ret = hclge_set_vlan_filter_hw(hdev,
@@ -10111,15 +10343,23 @@ int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state,
return ret;
/* remove old VLAN tag */
- ret = hclge_set_vlan_filter_hw(hdev,
- htons(old_vlan_info->vlan_proto),
- vport->vport_id,
- old_vlan_info->vlan_tag,
- true);
- if (ret)
+ if (old_vlan_info->vlan_tag == 0)
+ ret = hclge_set_vf_vlan_common(hdev, vport->vport_id,
+ true, 0);
+ else
+ ret = hclge_set_vlan_filter_hw(hdev,
+ htons(ETH_P_8021Q),
+ vport->vport_id,
+ old_vlan_info->vlan_tag,
+ true);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to clear vport%u port base vlan %u, ret = %d.\n",
+ vport->vport_id, old_vlan_info->vlan_tag, ret);
return ret;
+ }
- goto update;
+ goto out;
}
ret = hclge_update_vlan_filter_entries(vport, state, vlan_info,
@@ -10127,38 +10367,38 @@ int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state,
if (ret)
return ret;
- /* update state only when disable/enable port based VLAN */
+out:
vport->port_base_vlan_cfg.state = state;
if (state == HNAE3_PORT_BASE_VLAN_DISABLE)
nic->port_base_vlan_state = HNAE3_PORT_BASE_VLAN_DISABLE;
else
nic->port_base_vlan_state = HNAE3_PORT_BASE_VLAN_ENABLE;
-update:
- vport->port_base_vlan_cfg.vlan_info.vlan_tag = vlan_info->vlan_tag;
- vport->port_base_vlan_cfg.vlan_info.qos = vlan_info->qos;
- vport->port_base_vlan_cfg.vlan_info.vlan_proto = vlan_info->vlan_proto;
+ vport->port_base_vlan_cfg.vlan_info = *vlan_info;
+ hclge_set_vport_vlan_fltr_change(vport);
return 0;
}
static u16 hclge_get_port_base_vlan_state(struct hclge_vport *vport,
enum hnae3_port_base_vlan_state state,
- u16 vlan)
+ u16 vlan, u8 qos)
{
if (state == HNAE3_PORT_BASE_VLAN_DISABLE) {
- if (!vlan)
- return HNAE3_PORT_BASE_VLAN_NOCHANGE;
- else
- return HNAE3_PORT_BASE_VLAN_ENABLE;
- } else {
- if (!vlan)
- return HNAE3_PORT_BASE_VLAN_DISABLE;
- else if (vport->port_base_vlan_cfg.vlan_info.vlan_tag == vlan)
+ if (!vlan && !qos)
return HNAE3_PORT_BASE_VLAN_NOCHANGE;
- else
- return HNAE3_PORT_BASE_VLAN_MODIFY;
+
+ return HNAE3_PORT_BASE_VLAN_ENABLE;
}
+
+ if (!vlan && !qos)
+ return HNAE3_PORT_BASE_VLAN_DISABLE;
+
+ if (vport->port_base_vlan_cfg.vlan_info.vlan_tag == vlan &&
+ vport->port_base_vlan_cfg.vlan_info.qos == qos)
+ return HNAE3_PORT_BASE_VLAN_NOCHANGE;
+
+ return HNAE3_PORT_BASE_VLAN_MODIFY;
}
static int hclge_set_vf_vlan_filter(struct hnae3_handle *handle, int vfid,
@@ -10186,7 +10426,7 @@ static int hclge_set_vf_vlan_filter(struct hnae3_handle *handle, int vfid,
state = hclge_get_port_base_vlan_state(vport,
vport->port_base_vlan_cfg.state,
- vlan);
+ vlan, qos);
if (state == HNAE3_PORT_BASE_VLAN_NOCHANGE)
return 0;
@@ -10209,8 +10449,7 @@ static int hclge_set_vf_vlan_filter(struct hnae3_handle *handle, int vfid,
test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state))
hclge_push_vf_port_base_vlan_info(&hdev->vport[0],
vport->vport_id, state,
- vlan, qos,
- ntohs(proto));
+ &vlan_info);
return 0;
}
@@ -10280,9 +10519,37 @@ int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto,
*/
set_bit(vlan_id, vport->vlan_del_fail_bmap);
}
+
+ hclge_set_vport_vlan_fltr_change(vport);
+
return ret;
}
+static void hclge_sync_vlan_fltr_state(struct hclge_dev *hdev)
+{
+ struct hclge_vport *vport;
+ int ret;
+ u16 i;
+
+ for (i = 0; i < hdev->num_alloc_vport; i++) {
+ vport = &hdev->vport[i];
+ if (!test_and_clear_bit(HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE,
+ &vport->state))
+ continue;
+
+ ret = hclge_enable_vport_vlan_filter(vport,
+ vport->req_vlan_fltr_en);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to sync vlan filter state for vport%u, ret = %d\n",
+ vport->vport_id, ret);
+ set_bit(HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE,
+ &vport->state);
+ return;
+ }
+ }
+}
+
static void hclge_sync_vlan_filter(struct hclge_dev *hdev)
{
#define HCLGE_MAX_SYNC_COUNT 60
@@ -10305,6 +10572,7 @@ static void hclge_sync_vlan_filter(struct hclge_dev *hdev)
clear_bit(vlan_id, vport->vlan_del_fail_bmap);
hclge_rm_vport_vlan_table(vport, vlan_id, false);
+ hclge_set_vport_vlan_fltr_change(vport);
sync_cnt++;
if (sync_cnt >= HCLGE_MAX_SYNC_COUNT)
@@ -10314,6 +10582,8 @@ static void hclge_sync_vlan_filter(struct hclge_dev *hdev)
VLAN_N_VID);
}
}
+
+ hclge_sync_vlan_fltr_state(hdev);
}
static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps)
@@ -10807,6 +11077,8 @@ static void hclge_info_show(struct hclge_dev *hdev)
hdev->flag & HCLGE_FLAG_DCB_ENABLE ? "enable" : "disable");
dev_info(dev, "MQPRIO %s\n",
hdev->flag & HCLGE_FLAG_MQPRIO_ENABLE ? "enable" : "disable");
+ dev_info(dev, "Default tx spare buffer size: %u\n",
+ hdev->tx_spare_buf_size);
dev_info(dev, "PF info end.\n");
}
@@ -11167,6 +11439,18 @@ static void hclge_clear_resetting_state(struct hclge_dev *hdev)
}
}
+static void hclge_init_rxd_adv_layout(struct hclge_dev *hdev)
+{
+ if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev))
+ hclge_write_dev(&hdev->hw, HCLGE_RXD_ADV_LAYOUT_EN_REG, 1);
+}
+
+static void hclge_uninit_rxd_adv_layout(struct hclge_dev *hdev)
+{
+ if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev))
+ hclge_write_dev(&hdev->hw, HCLGE_RXD_ADV_LAYOUT_EN_REG, 0);
+}
+
static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
{
struct pci_dev *pdev = ae_dev->pdev;
@@ -11309,6 +11593,10 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
goto err_mdiobus_unreg;
}
+ ret = hclge_ptp_init(hdev);
+ if (ret)
+ goto err_mdiobus_unreg;
+
INIT_KFIFO(hdev->mac_tnl_log);
hclge_dcb_ops_set(hdev);
@@ -11325,7 +11613,10 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
hclge_clear_resetting_state(hdev);
/* Log and clear the hw errors those already occurred */
- hclge_handle_all_hns_hw_errors(ae_dev);
+ if (hnae3_dev_ras_imp_supported(hdev))
+ hclge_handle_occurred_error(hdev);
+ else
+ 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
@@ -11339,6 +11630,8 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
mod_timer(&hdev->reset_timer, jiffies + HCLGE_RESET_INTERVAL);
}
+ hclge_init_rxd_adv_layout(hdev);
+
/* Enable MISC vector(vector0) */
hclge_enable_vector(&hdev->misc_vector, true);
@@ -11471,10 +11764,7 @@ static int hclge_set_vf_trust(struct hnae3_handle *handle, int vf, bool enable)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
- struct hnae3_ae_dev *ae_dev = hdev->ae_dev;
u32 new_trusted = enable ? 1 : 0;
- bool en_bc_pmc;
- int ret;
vport = hclge_get_vf_vport(hdev, vf);
if (!vport)
@@ -11483,18 +11773,9 @@ static int hclge_set_vf_trust(struct hnae3_handle *handle, int vf, bool enable)
if (vport->vf_info.trusted == new_trusted)
return 0;
- /* Disable promisc mode for VF if it is not trusted any more. */
- if (!enable && vport->vf_info.promisc_enable) {
- en_bc_pmc = ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2;
- ret = hclge_set_vport_promisc_mode(vport, false, false,
- en_bc_pmc);
- if (ret)
- return ret;
- vport->vf_info.promisc_enable = 0;
- hclge_inform_vf_promisc_info(vport);
- }
-
vport->vf_info.trusted = new_trusted;
+ set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state);
+ hclge_task_schedule(hdev, 0);
return 0;
}
@@ -11687,8 +11968,15 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev)
return ret;
}
+ ret = hclge_ptp_init(hdev);
+ if (ret)
+ return ret;
+
/* Log and clear the hw errors those already occurred */
- hclge_handle_all_hns_hw_errors(ae_dev);
+ if (hnae3_dev_ras_imp_supported(hdev))
+ hclge_handle_occurred_error(hdev);
+ else
+ hclge_handle_all_hns_hw_errors(ae_dev);
/* Re-enable the hw error interrupts because
* the interrupts get disabled on global reset.
@@ -11720,6 +12008,8 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev)
if (ret)
return ret;
+ hclge_init_rxd_adv_layout(hdev);
+
dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n",
HCLGE_DRIVER_NAME);
@@ -11735,6 +12025,8 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev)
hclge_clear_vf_vlan(hdev);
hclge_misc_affinity_teardown(hdev);
hclge_state_uninit(hdev);
+ hclge_ptp_uninit(hdev);
+ hclge_uninit_rxd_adv_layout(hdev);
hclge_uninit_mac_table(hdev);
hclge_del_all_fd_entries(hdev);
@@ -12385,21 +12677,50 @@ static void hclge_sync_promisc_mode(struct hclge_dev *hdev)
struct hnae3_handle *handle = &vport->nic;
u8 tmp_flags;
int ret;
+ u16 i;
if (vport->last_promisc_flags != vport->overflow_promisc_flags) {
- set_bit(HCLGE_STATE_PROMISC_CHANGED, &hdev->state);
+ set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state);
vport->last_promisc_flags = vport->overflow_promisc_flags;
}
- if (test_bit(HCLGE_STATE_PROMISC_CHANGED, &hdev->state)) {
+ if (test_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state)) {
tmp_flags = handle->netdev_flags | vport->last_promisc_flags;
ret = hclge_set_promisc_mode(handle, tmp_flags & HNAE3_UPE,
tmp_flags & HNAE3_MPE);
if (!ret) {
- clear_bit(HCLGE_STATE_PROMISC_CHANGED, &hdev->state);
- hclge_enable_vlan_filter(handle,
- tmp_flags & HNAE3_VLAN_FLTR);
+ clear_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE,
+ &vport->state);
+ set_bit(HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE,
+ &vport->state);
+ }
+ }
+
+ for (i = 1; i < hdev->num_alloc_vport; i++) {
+ bool uc_en = false;
+ bool mc_en = false;
+ bool bc_en;
+
+ vport = &hdev->vport[i];
+
+ if (!test_and_clear_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE,
+ &vport->state))
+ continue;
+
+ if (vport->vf_info.trusted) {
+ uc_en = vport->vf_info.request_uc_en > 0;
+ mc_en = vport->vf_info.request_mc_en > 0;
+ }
+ bc_en = vport->vf_info.request_bc_en > 0;
+
+ ret = hclge_cmd_set_promisc_mode(hdev, vport->vport_id, uc_en,
+ mc_en, bc_en);
+ if (ret) {
+ set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE,
+ &vport->state);
+ return;
}
+ hclge_set_vport_vlan_fltr_change(vport);
}
}
@@ -12578,7 +12899,6 @@ static const struct hnae3_ae_ops hclge_ops = {
.get_fd_all_rules = hclge_get_all_rules,
.enable_fd = hclge_enable_fd,
.add_arfs_entry = hclge_add_fd_entry_by_arfs,
- .dbg_run_cmd = hclge_dbg_run_cmd,
.dbg_read_cmd = hclge_dbg_read_cmd,
.handle_hw_ras_error = hclge_handle_hw_ras_error,
.get_hw_reset_stat = hclge_get_hw_reset_stat,
@@ -12602,6 +12922,9 @@ static const struct hnae3_ae_ops hclge_ops = {
.cls_flower_active = hclge_is_cls_flower_active,
.get_phy_link_ksettings = hclge_get_phy_link_ksettings,
.set_phy_link_ksettings = hclge_set_phy_link_ksettings,
+ .set_tx_hwts_info = hclge_ptp_set_tx_info,
+ .get_rx_hwts = hclge_ptp_get_rx_hwts,
+ .get_ts_info = hclge_ptp_get_ts_info,
};
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 ff1d47308c2d..3d3352491dba 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
@@ -10,6 +10,7 @@
#include <linux/kfifo.h>
#include "hclge_cmd.h"
+#include "hclge_ptp.h"
#include "hnae3.h"
#define HCLGE_MOD_VERSION "1.0"
@@ -53,6 +54,7 @@
/* bar registers for common func */
#define HCLGE_VECTOR0_OTER_EN_REG 0x20600
#define HCLGE_GRO_EN_REG 0x28000
+#define HCLGE_RXD_ADV_LAYOUT_EN_REG 0x28008
/* bar registers for rcb */
#define HCLGE_RING_RX_ADDR_L_REG 0x80000
@@ -147,6 +149,8 @@
#define HCLGE_MAX_QSET_NUM 1024
+#define HCLGE_DBG_RESET_INFO_LEN 1024
+
enum HLCGE_PORT_TYPE {
HOST_PORT,
NETWORK_PORT
@@ -175,6 +179,7 @@ enum HLCGE_PORT_TYPE {
#define HCLGE_FUN_RST_ING_B 0
/* Vector0 register bits define */
+#define HCLGE_VECTOR0_REG_PTP_INT_B 0
#define HCLGE_VECTOR0_GLOBALRESET_INT_B 5
#define HCLGE_VECTOR0_CORERESET_INT_B 6
#define HCLGE_VECTOR0_IMPRESET_INT_B 7
@@ -187,6 +192,7 @@ enum HLCGE_PORT_TYPE {
#define HCLGE_VECTOR0_IMP_RESET_INT_B 1
#define HCLGE_VECTOR0_IMP_CMDQ_ERR_B 4U
#define HCLGE_VECTOR0_IMP_RD_POISON_B 5U
+#define HCLGE_VECTOR0_ALL_MSIX_ERR_B 6U
#define HCLGE_MAC_DEFAULT_FRAME \
(ETH_HLEN + ETH_FCS_LEN + 2 * VLAN_HLEN + ETH_DATA_LEN)
@@ -218,14 +224,16 @@ enum HCLGE_DEV_STATE {
HCLGE_STATE_RST_HANDLING,
HCLGE_STATE_MBX_SERVICE_SCHED,
HCLGE_STATE_MBX_HANDLING,
+ HCLGE_STATE_ERR_SERVICE_SCHED,
HCLGE_STATE_STATISTICS_UPDATING,
HCLGE_STATE_CMD_DISABLE,
HCLGE_STATE_LINK_UPDATING,
- HCLGE_STATE_PROMISC_CHANGED,
HCLGE_STATE_RST_FAIL,
HCLGE_STATE_FD_TBL_CHANGED,
HCLGE_STATE_FD_CLEAR_ALL,
HCLGE_STATE_FD_USER_DEF_CHANGED,
+ HCLGE_STATE_PTP_EN,
+ HCLGE_STATE_PTP_TX_HANDLING,
HCLGE_STATE_MAX
};
@@ -233,6 +241,7 @@ enum hclge_evt_cause {
HCLGE_VECTOR0_EVENT_RST,
HCLGE_VECTOR0_EVENT_MBX,
HCLGE_VECTOR0_EVENT_ERR,
+ HCLGE_VECTOR0_EVENT_PTP,
HCLGE_VECTOR0_EVENT_OTHER,
};
@@ -319,6 +328,22 @@ enum hclge_fc_mode {
HCLGE_FC_DEFAULT
};
+#define HCLGE_FILTER_TYPE_VF 0
+#define HCLGE_FILTER_TYPE_PORT 1
+#define HCLGE_FILTER_FE_EGRESS_V1_B BIT(0)
+#define HCLGE_FILTER_FE_NIC_INGRESS_B BIT(0)
+#define HCLGE_FILTER_FE_NIC_EGRESS_B BIT(1)
+#define HCLGE_FILTER_FE_ROCE_INGRESS_B BIT(2)
+#define HCLGE_FILTER_FE_ROCE_EGRESS_B BIT(3)
+#define HCLGE_FILTER_FE_EGRESS (HCLGE_FILTER_FE_NIC_EGRESS_B \
+ | HCLGE_FILTER_FE_ROCE_EGRESS_B)
+#define HCLGE_FILTER_FE_INGRESS (HCLGE_FILTER_FE_NIC_INGRESS_B \
+ | HCLGE_FILTER_FE_ROCE_INGRESS_B)
+
+enum hclge_vlan_fltr_cap {
+ HCLGE_VLAN_FLTR_DEF,
+ HCLGE_VLAN_FLTR_CAN_MDF,
+};
enum hclge_link_fail_code {
HCLGE_LF_NORMAL,
HCLGE_LF_REF_CLOCK_LOST,
@@ -349,6 +374,7 @@ struct hclge_tc_info {
struct hclge_cfg {
u8 tc_num;
+ u8 vlan_fliter_cap;
u16 tqp_desc_num;
u16 rx_buf_len;
u16 vf_rss_size_max;
@@ -358,6 +384,7 @@ struct hclge_cfg {
u8 mac_addr[ETH_ALEN];
u8 default_speed;
u32 numa_node_map;
+ u32 tx_spare_buf_size;
u16 speed_ability;
u16 umv_space;
};
@@ -757,9 +784,14 @@ struct hclge_mac_tnl_stats {
struct hclge_vf_vlan_cfg {
u8 mbx_cmd;
u8 subcode;
- u8 is_kill;
- u16 vlan;
- u16 proto;
+ union {
+ struct {
+ u8 is_kill;
+ u16 vlan;
+ u16 proto;
+ };
+ u8 enable;
+ };
};
#pragma pack()
@@ -817,6 +849,7 @@ struct hclge_dev {
u16 alloc_rss_size; /* Allocated RSS task queue */
u16 vf_rss_size_max; /* HW defined VF max RSS task queue */
u16 pf_rss_size_max; /* HW defined PF max RSS task queue */
+ u32 tx_spare_buf_size; /* HW defined TX spare buffer size */
u16 fdir_pf_filter_count; /* Num of guaranteed filters for this PF */
u16 num_alloc_vport; /* Num vports this driver supports */
@@ -909,6 +942,7 @@ struct hclge_dev {
/* affinity mask and notify for misc interrupt */
cpumask_t affinity_mask;
struct irq_affinity_notify affinity_notify;
+ struct hclge_ptp *ptp;
};
/* VPort level vlan tag configuration for TX direction */
@@ -949,6 +983,8 @@ struct hclge_rss_tuple_cfg {
enum HCLGE_VPORT_STATE {
HCLGE_VPORT_STATE_ALIVE,
HCLGE_VPORT_STATE_MAC_TBL_CHANGE,
+ HCLGE_VPORT_STATE_PROMISC_CHANGE,
+ HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE,
HCLGE_VPORT_STATE_MAX
};
@@ -969,7 +1005,9 @@ struct hclge_vf_info {
u32 spoofchk;
u32 max_tx_rate;
u32 trusted;
- u16 promisc_enable;
+ u8 request_uc_en;
+ u8 request_mc_en;
+ u8 request_bc_en;
};
struct hclge_vport {
@@ -988,6 +1026,8 @@ struct hclge_vport {
u32 bw_limit; /* VSI BW Limit (0 = disabled) */
u8 dwrr;
+ bool req_vlan_fltr_en;
+ bool cur_vlan_fltr_en;
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;
@@ -1059,8 +1099,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, const char *cmd_buf);
-int hclge_dbg_read_cmd(struct hnae3_handle *handle, const char *cmd_buf,
+int hclge_dbg_read_cmd(struct hnae3_handle *handle, enum hnae3_dbg_cmd cmd,
char *buf, int len);
u16 hclge_covert_handle_qid_global(struct hnae3_handle *handle, u16 queue_id);
int hclge_notify_client(struct hclge_dev *hdev,
@@ -1080,14 +1119,15 @@ void hclge_restore_vport_vlan_table(struct hclge_vport *vport);
int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state,
struct hclge_vlan_info *vlan_info);
int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid,
- u16 state, u16 vlan_tag, u16 qos,
- u16 vlan_proto);
+ u16 state,
+ struct hclge_vlan_info *vlan_info);
void hclge_task_schedule(struct hclge_dev *hdev, unsigned long delay_time);
int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev,
struct hclge_desc *desc);
void hclge_report_hw_error(struct hclge_dev *hdev,
enum hnae3_hw_error_type type);
void hclge_inform_vf_promisc_info(struct hclge_vport *vport);
-void hclge_dbg_dump_rst_info(struct hclge_dev *hdev);
+int hclge_dbg_dump_rst_info(struct hclge_dev *hdev, char *buf, int len);
int hclge_push_vf_link_status(struct hclge_vport *vport);
+int hclge_enable_vport_vlan_filter(struct hclge_vport *vport, bool request_en);
#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
index f1c9f4ada348..e10a2c36b706 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
@@ -231,19 +231,15 @@ static int hclge_map_unmap_ring_to_vf_vector(struct hclge_vport *vport, bool en,
return ret;
}
-static int hclge_set_vf_promisc_mode(struct hclge_vport *vport,
- struct hclge_mbx_vf_to_pf_cmd *req)
+static void hclge_set_vf_promisc_mode(struct hclge_vport *vport,
+ struct hclge_mbx_vf_to_pf_cmd *req)
{
- bool en_bc = req->msg.en_bc ? true : false;
- bool en_uc = req->msg.en_uc ? true : false;
- bool en_mc = req->msg.en_mc ? true : false;
struct hnae3_handle *handle = &vport->nic;
- int ret;
+ struct hclge_dev *hdev = vport->back;
- if (!vport->vf_info.trusted) {
- en_uc = false;
- en_mc = false;
- }
+ vport->vf_info.request_uc_en = req->msg.en_uc;
+ vport->vf_info.request_mc_en = req->msg.en_mc;
+ vport->vf_info.request_bc_en = req->msg.en_bc;
if (req->msg.en_limit_promisc)
set_bit(HNAE3_PFLAG_LIMIT_PROMISC, &handle->priv_flags);
@@ -251,22 +247,8 @@ static int hclge_set_vf_promisc_mode(struct hclge_vport *vport,
clear_bit(HNAE3_PFLAG_LIMIT_PROMISC,
&handle->priv_flags);
- ret = hclge_set_vport_promisc_mode(vport, en_uc, en_mc, en_bc);
-
- vport->vf_info.promisc_enable = (en_uc || en_mc) ? 1 : 0;
-
- return ret;
-}
-
-void hclge_inform_vf_promisc_info(struct hclge_vport *vport)
-{
- u8 dest_vfid = (u8)vport->vport_id;
- u8 msg_data[2];
-
- memcpy(&msg_data[0], &vport->vf_info.promisc_enable, sizeof(u16));
-
- hclge_send_mbx_msg(vport, msg_data, sizeof(msg_data),
- HCLGE_MBX_PUSH_PROMISC_INFO, dest_vfid);
+ set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state);
+ hclge_task_schedule(hdev, 0);
}
static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport,
@@ -336,17 +318,17 @@ static int hclge_set_vf_mc_mac_addr(struct hclge_vport *vport,
}
int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid,
- u16 state, u16 vlan_tag, u16 qos,
- u16 vlan_proto)
+ u16 state,
+ struct hclge_vlan_info *vlan_info)
{
#define MSG_DATA_SIZE 8
u8 msg_data[MSG_DATA_SIZE];
memcpy(&msg_data[0], &state, sizeof(u16));
- memcpy(&msg_data[2], &vlan_proto, sizeof(u16));
- memcpy(&msg_data[4], &qos, sizeof(u16));
- memcpy(&msg_data[6], &vlan_tag, sizeof(u16));
+ memcpy(&msg_data[2], &vlan_info->vlan_proto, sizeof(u16));
+ memcpy(&msg_data[4], &vlan_info->qos, sizeof(u16));
+ memcpy(&msg_data[6], &vlan_info->vlan_tag, sizeof(u16));
return hclge_send_mbx_msg(vport, msg_data, sizeof(msg_data),
HCLGE_MBX_PUSH_VLAN_INFO, vfid);
@@ -359,49 +341,35 @@ static int hclge_set_vf_vlan_cfg(struct hclge_vport *vport,
#define HCLGE_MBX_VLAN_STATE_OFFSET 0
#define HCLGE_MBX_VLAN_INFO_OFFSET 2
+ struct hnae3_handle *handle = &vport->nic;
+ struct hclge_dev *hdev = vport->back;
struct hclge_vf_vlan_cfg *msg_cmd;
- int status = 0;
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 = !!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 (msg_cmd->subcode == HCLGE_MBX_VLAN_RX_OFF_CFG) {
- struct hnae3_handle *handle = &vport->nic;
- bool en = msg_cmd->is_kill ? true : false;
-
- status = hclge_en_hw_strip_rxvtag(handle, en);
- } else if (msg_cmd->subcode == HCLGE_MBX_PORT_BASE_VLAN_CFG) {
- struct hclge_vlan_info *vlan_info;
- u16 *state;
-
- state = (u16 *)&mbx_req->msg.data[HCLGE_MBX_VLAN_STATE_OFFSET];
- vlan_info = (struct hclge_vlan_info *)
- &mbx_req->msg.data[HCLGE_MBX_VLAN_INFO_OFFSET];
- status = hclge_update_port_base_vlan_cfg(vport, *state,
- vlan_info);
- } else if (msg_cmd->subcode == HCLGE_MBX_GET_PORT_BASE_VLAN_STATE) {
- struct hnae3_ae_dev *ae_dev = pci_get_drvdata(vport->nic.pdev);
+ switch (msg_cmd->subcode) {
+ case HCLGE_MBX_VLAN_FILTER:
+ return hclge_set_vlan_filter(handle,
+ cpu_to_be16(msg_cmd->proto),
+ msg_cmd->vlan, msg_cmd->is_kill);
+ case HCLGE_MBX_VLAN_RX_OFF_CFG:
+ return hclge_en_hw_strip_rxvtag(handle, msg_cmd->enable);
+ case HCLGE_MBX_GET_PORT_BASE_VLAN_STATE:
/* vf does not need to know about the port based VLAN state
* on device HNAE3_DEVICE_VERSION_V3. So always return disable
* on device HNAE3_DEVICE_VERSION_V3 if vf queries the port
* based VLAN state.
*/
resp_msg->data[0] =
- ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3 ?
+ hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3 ?
HNAE3_PORT_BASE_VLAN_DISABLE :
vport->port_base_vlan_cfg.state;
resp_msg->len = sizeof(u8);
+ return 0;
+ case HCLGE_MBX_ENABLE_VLAN_FILTER:
+ return hclge_enable_vport_vlan_filter(vport, msg_cmd->enable);
+ default:
+ return 0;
}
-
- return status;
}
static int hclge_set_vf_alive(struct hclge_vport *vport,
@@ -418,16 +386,23 @@ static int hclge_set_vf_alive(struct hclge_vport *vport,
return ret;
}
-static void hclge_get_vf_tcinfo(struct hclge_vport *vport,
- struct hclge_respond_to_vf_msg *resp_msg)
+static void hclge_get_basic_info(struct hclge_vport *vport,
+ struct hclge_respond_to_vf_msg *resp_msg)
{
struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
+ struct hnae3_ae_dev *ae_dev = vport->back->ae_dev;
+ struct hclge_basic_info *basic_info;
unsigned int i;
+ basic_info = (struct hclge_basic_info *)resp_msg->data;
for (i = 0; i < kinfo->tc_info.num_tc; i++)
- resp_msg->data[0] |= BIT(i);
+ basic_info->hw_tc_map |= BIT(i);
- resp_msg->len = sizeof(u8);
+ if (test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps))
+ hnae3_set_bit(basic_info->pf_caps,
+ HNAE3_PF_SUPPORT_VLAN_FLTR_MDF_B, 1);
+
+ resp_msg->len = HCLGE_MBX_MAX_RESP_DATA_SIZE;
}
static void hclge_get_vf_queue_info(struct hclge_vport *vport,
@@ -750,11 +725,7 @@ void hclge_mbx_handler(struct hclge_dev *hdev)
req);
break;
case HCLGE_MBX_SET_PROMISC_MODE:
- ret = hclge_set_vf_promisc_mode(vport, req);
- if (ret)
- dev_err(&hdev->pdev->dev,
- "PF fail(%d) to set VF promisc mode\n",
- ret);
+ hclge_set_vf_promisc_mode(vport, req);
break;
case HCLGE_MBX_SET_UNICAST:
ret = hclge_set_vf_uc_mac_addr(vport, req);
@@ -790,8 +761,8 @@ void hclge_mbx_handler(struct hclge_dev *hdev)
case HCLGE_MBX_GET_QDEPTH:
hclge_get_vf_queue_depth(vport, &resp_msg);
break;
- case HCLGE_MBX_GET_TCINFO:
- hclge_get_vf_tcinfo(vport, &resp_msg);
+ case HCLGE_MBX_GET_BASIC_INFO:
+ hclge_get_basic_info(vport, &resp_msg);
break;
case HCLGE_MBX_GET_LINK_STATUS:
ret = hclge_push_vf_link_status(vport);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c
new file mode 100644
index 000000000000..3b1f84502e36
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (c) 2021 Hisilicon Limited.
+
+#include <linux/skbuff.h>
+#include "hclge_main.h"
+#include "hnae3.h"
+
+static int hclge_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+ struct hclge_dev *hdev = hclge_ptp_get_hdev(ptp);
+ u64 adj_val, adj_base, diff;
+ unsigned long flags;
+ bool is_neg = false;
+ u32 quo, numerator;
+
+ if (ppb < 0) {
+ ppb = -ppb;
+ is_neg = true;
+ }
+
+ adj_base = HCLGE_PTP_CYCLE_ADJ_BASE * HCLGE_PTP_CYCLE_ADJ_UNIT;
+ adj_val = adj_base * ppb;
+ diff = div_u64(adj_val, 1000000000ULL);
+
+ if (is_neg)
+ adj_val = adj_base - diff;
+ else
+ adj_val = adj_base + diff;
+
+ /* This clock cycle is defined by three part: quotient, numerator
+ * and denominator. For example, 2.5ns, the quotient is 2,
+ * denominator is fixed to HCLGE_PTP_CYCLE_ADJ_UNIT, and numerator
+ * is 0.5 * HCLGE_PTP_CYCLE_ADJ_UNIT.
+ */
+ quo = div_u64_rem(adj_val, HCLGE_PTP_CYCLE_ADJ_UNIT, &numerator);
+
+ spin_lock_irqsave(&hdev->ptp->lock, flags);
+ writel(quo, hdev->ptp->io_base + HCLGE_PTP_CYCLE_QUO_REG);
+ writel(numerator, hdev->ptp->io_base + HCLGE_PTP_CYCLE_NUM_REG);
+ writel(HCLGE_PTP_CYCLE_ADJ_UNIT,
+ hdev->ptp->io_base + HCLGE_PTP_CYCLE_DEN_REG);
+ writel(HCLGE_PTP_CYCLE_ADJ_EN,
+ hdev->ptp->io_base + HCLGE_PTP_CYCLE_CFG_REG);
+ spin_unlock_irqrestore(&hdev->ptp->lock, flags);
+
+ return 0;
+}
+
+bool hclge_ptp_set_tx_info(struct hnae3_handle *handle, struct sk_buff *skb)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+ struct hclge_ptp *ptp = hdev->ptp;
+
+ if (!test_bit(HCLGE_PTP_FLAG_TX_EN, &ptp->flags) ||
+ test_and_set_bit(HCLGE_STATE_PTP_TX_HANDLING, &hdev->state)) {
+ ptp->tx_skipped++;
+ return false;
+ }
+
+ ptp->tx_start = jiffies;
+ ptp->tx_skb = skb_get(skb);
+ ptp->tx_cnt++;
+
+ return true;
+}
+
+void hclge_ptp_clean_tx_hwts(struct hclge_dev *hdev)
+{
+ struct sk_buff *skb = hdev->ptp->tx_skb;
+ struct skb_shared_hwtstamps hwts;
+ u32 hi, lo;
+ u64 ns;
+
+ ns = readl(hdev->ptp->io_base + HCLGE_PTP_TX_TS_NSEC_REG) &
+ HCLGE_PTP_TX_TS_NSEC_MASK;
+ lo = readl(hdev->ptp->io_base + HCLGE_PTP_TX_TS_SEC_L_REG);
+ hi = readl(hdev->ptp->io_base + HCLGE_PTP_TX_TS_SEC_H_REG) &
+ HCLGE_PTP_TX_TS_SEC_H_MASK;
+ hdev->ptp->last_tx_seqid = readl(hdev->ptp->io_base +
+ HCLGE_PTP_TX_TS_SEQID_REG);
+
+ if (skb) {
+ hdev->ptp->tx_skb = NULL;
+ hdev->ptp->tx_cleaned++;
+
+ ns += (((u64)hi) << 32 | lo) * NSEC_PER_SEC;
+ hwts.hwtstamp = ns_to_ktime(ns);
+ skb_tstamp_tx(skb, &hwts);
+ dev_kfree_skb_any(skb);
+ }
+
+ clear_bit(HCLGE_STATE_PTP_TX_HANDLING, &hdev->state);
+}
+
+void hclge_ptp_get_rx_hwts(struct hnae3_handle *handle, struct sk_buff *skb,
+ u32 nsec, u32 sec)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+ unsigned long flags;
+ u64 ns = nsec;
+ u32 sec_h;
+
+ if (!test_bit(HCLGE_PTP_FLAG_RX_EN, &hdev->ptp->flags))
+ return;
+
+ /* Since the BD does not have enough space for the higher 16 bits of
+ * second, and this part will not change frequently, so read it
+ * from register.
+ */
+ spin_lock_irqsave(&hdev->ptp->lock, flags);
+ sec_h = readl(hdev->ptp->io_base + HCLGE_PTP_CUR_TIME_SEC_H_REG);
+ spin_unlock_irqrestore(&hdev->ptp->lock, flags);
+
+ ns += (((u64)sec_h) << HCLGE_PTP_SEC_H_OFFSET | sec) * NSEC_PER_SEC;
+ skb_hwtstamps(skb)->hwtstamp = ns_to_ktime(ns);
+ hdev->ptp->last_rx = jiffies;
+ hdev->ptp->rx_cnt++;
+}
+
+static int hclge_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ struct hclge_dev *hdev = hclge_ptp_get_hdev(ptp);
+ unsigned long flags;
+ u32 hi, lo;
+ u64 ns;
+
+ spin_lock_irqsave(&hdev->ptp->lock, flags);
+ ns = readl(hdev->ptp->io_base + HCLGE_PTP_CUR_TIME_NSEC_REG);
+ hi = readl(hdev->ptp->io_base + HCLGE_PTP_CUR_TIME_SEC_H_REG);
+ lo = readl(hdev->ptp->io_base + HCLGE_PTP_CUR_TIME_SEC_L_REG);
+ spin_unlock_irqrestore(&hdev->ptp->lock, flags);
+
+ ns += (((u64)hi) << HCLGE_PTP_SEC_H_OFFSET | lo) * NSEC_PER_SEC;
+ *ts = ns_to_timespec64(ns);
+
+ return 0;
+}
+
+static int hclge_ptp_settime(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct hclge_dev *hdev = hclge_ptp_get_hdev(ptp);
+ unsigned long flags;
+
+ spin_lock_irqsave(&hdev->ptp->lock, flags);
+ writel(ts->tv_nsec, hdev->ptp->io_base + HCLGE_PTP_TIME_NSEC_REG);
+ writel(ts->tv_sec >> HCLGE_PTP_SEC_H_OFFSET,
+ hdev->ptp->io_base + HCLGE_PTP_TIME_SEC_H_REG);
+ writel(ts->tv_sec & HCLGE_PTP_SEC_L_MASK,
+ hdev->ptp->io_base + HCLGE_PTP_TIME_SEC_L_REG);
+ /* synchronize the time of phc */
+ writel(HCLGE_PTP_TIME_SYNC_EN,
+ hdev->ptp->io_base + HCLGE_PTP_TIME_SYNC_REG);
+ spin_unlock_irqrestore(&hdev->ptp->lock, flags);
+
+ return 0;
+}
+
+static int hclge_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct hclge_dev *hdev = hclge_ptp_get_hdev(ptp);
+ unsigned long flags;
+ bool is_neg = false;
+ u32 adj_val = 0;
+
+ if (delta < 0) {
+ adj_val |= HCLGE_PTP_TIME_NSEC_NEG;
+ delta = -delta;
+ is_neg = true;
+ }
+
+ if (delta > HCLGE_PTP_TIME_NSEC_MASK) {
+ struct timespec64 ts;
+ s64 ns;
+
+ hclge_ptp_gettimex(ptp, &ts, NULL);
+ ns = timespec64_to_ns(&ts);
+ ns = is_neg ? ns - delta : ns + delta;
+ ts = ns_to_timespec64(ns);
+ return hclge_ptp_settime(ptp, &ts);
+ }
+
+ adj_val |= delta & HCLGE_PTP_TIME_NSEC_MASK;
+
+ spin_lock_irqsave(&hdev->ptp->lock, flags);
+ writel(adj_val, hdev->ptp->io_base + HCLGE_PTP_TIME_NSEC_REG);
+ writel(HCLGE_PTP_TIME_ADJ_EN,
+ hdev->ptp->io_base + HCLGE_PTP_TIME_ADJ_REG);
+ spin_unlock_irqrestore(&hdev->ptp->lock, flags);
+
+ return 0;
+}
+
+int hclge_ptp_get_cfg(struct hclge_dev *hdev, struct ifreq *ifr)
+{
+ if (!test_bit(HCLGE_STATE_PTP_EN, &hdev->state))
+ return -EOPNOTSUPP;
+
+ return copy_to_user(ifr->ifr_data, &hdev->ptp->ts_cfg,
+ sizeof(struct hwtstamp_config)) ? -EFAULT : 0;
+}
+
+static int hclge_ptp_int_en(struct hclge_dev *hdev, bool en)
+{
+ struct hclge_ptp_int_cmd *req;
+ struct hclge_desc desc;
+ int ret;
+
+ req = (struct hclge_ptp_int_cmd *)desc.data;
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PTP_INT_EN, false);
+ req->int_en = en ? 1 : 0;
+
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret)
+ dev_err(&hdev->pdev->dev,
+ "failed to %s ptp interrupt, ret = %d\n",
+ en ? "enable" : "disable", ret);
+
+ return ret;
+}
+
+int hclge_ptp_cfg_qry(struct hclge_dev *hdev, u32 *cfg)
+{
+ struct hclge_ptp_cfg_cmd *req;
+ struct hclge_desc desc;
+ int ret;
+
+ req = (struct hclge_ptp_cfg_cmd *)desc.data;
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PTP_MODE_CFG, true);
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to query ptp config, ret = %d\n", ret);
+ return ret;
+ }
+
+ *cfg = le32_to_cpu(req->cfg);
+
+ return 0;
+}
+
+static int hclge_ptp_cfg(struct hclge_dev *hdev, u32 cfg)
+{
+ struct hclge_ptp_cfg_cmd *req;
+ struct hclge_desc desc;
+ int ret;
+
+ req = (struct hclge_ptp_cfg_cmd *)desc.data;
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PTP_MODE_CFG, false);
+ req->cfg = cpu_to_le32(cfg);
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret)
+ dev_err(&hdev->pdev->dev,
+ "failed to config ptp, ret = %d\n", ret);
+
+ return ret;
+}
+
+static int hclge_ptp_set_tx_mode(struct hwtstamp_config *cfg,
+ unsigned long *flags, u32 *ptp_cfg)
+{
+ switch (cfg->tx_type) {
+ case HWTSTAMP_TX_OFF:
+ clear_bit(HCLGE_PTP_FLAG_TX_EN, flags);
+ break;
+ case HWTSTAMP_TX_ON:
+ set_bit(HCLGE_PTP_FLAG_TX_EN, flags);
+ *ptp_cfg |= HCLGE_PTP_TX_EN_B;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
+static int hclge_ptp_set_rx_mode(struct hwtstamp_config *cfg,
+ unsigned long *flags, u32 *ptp_cfg)
+{
+ int rx_filter = cfg->rx_filter;
+
+ switch (cfg->rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ clear_bit(HCLGE_PTP_FLAG_RX_EN, flags);
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ set_bit(HCLGE_PTP_FLAG_RX_EN, flags);
+ *ptp_cfg |= HCLGE_PTP_RX_EN_B;
+ *ptp_cfg |= HCLGE_PTP_UDP_FULL_TYPE << HCLGE_PTP_UDP_EN_SHIFT;
+ rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ set_bit(HCLGE_PTP_FLAG_RX_EN, flags);
+ *ptp_cfg |= HCLGE_PTP_RX_EN_B;
+ *ptp_cfg |= HCLGE_PTP_UDP_FULL_TYPE << HCLGE_PTP_UDP_EN_SHIFT;
+ *ptp_cfg |= HCLGE_PTP_MSG1_V2_DEFAULT << HCLGE_PTP_MSG1_SHIFT;
+ *ptp_cfg |= HCLGE_PTP_MSG0_V2_EVENT << HCLGE_PTP_MSG0_SHIFT;
+ *ptp_cfg |= HCLGE_PTP_MSG_TYPE_V2 << HCLGE_PTP_MSG_TYPE_SHIFT;
+ rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+ break;
+ case HWTSTAMP_FILTER_ALL:
+ default:
+ return -ERANGE;
+ }
+
+ cfg->rx_filter = rx_filter;
+
+ return 0;
+}
+
+static int hclge_ptp_set_ts_mode(struct hclge_dev *hdev,
+ struct hwtstamp_config *cfg)
+{
+ unsigned long flags = hdev->ptp->flags;
+ u32 ptp_cfg = 0;
+ int ret;
+
+ if (test_bit(HCLGE_PTP_FLAG_EN, &hdev->ptp->flags))
+ ptp_cfg |= HCLGE_PTP_EN_B;
+
+ ret = hclge_ptp_set_tx_mode(cfg, &flags, &ptp_cfg);
+ if (ret)
+ return ret;
+
+ ret = hclge_ptp_set_rx_mode(cfg, &flags, &ptp_cfg);
+ if (ret)
+ return ret;
+
+ ret = hclge_ptp_cfg(hdev, ptp_cfg);
+ if (ret)
+ return ret;
+
+ hdev->ptp->flags = flags;
+ hdev->ptp->ptp_cfg = ptp_cfg;
+
+ return 0;
+}
+
+int hclge_ptp_set_cfg(struct hclge_dev *hdev, struct ifreq *ifr)
+{
+ struct hwtstamp_config cfg;
+ int ret;
+
+ if (!test_bit(HCLGE_STATE_PTP_EN, &hdev->state)) {
+ dev_err(&hdev->pdev->dev, "phc is unsupported\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+ return -EFAULT;
+
+ ret = hclge_ptp_set_ts_mode(hdev, &cfg);
+ if (ret)
+ return ret;
+
+ hdev->ptp->ts_cfg = cfg;
+
+ return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+}
+
+int hclge_ptp_get_ts_info(struct hnae3_handle *handle,
+ struct ethtool_ts_info *info)
+{
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+
+ if (!test_bit(HCLGE_STATE_PTP_EN, &hdev->state)) {
+ dev_err(&hdev->pdev->dev, "phc is unsupported\n");
+ return -EOPNOTSUPP;
+ }
+
+ info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE |
+ SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+
+ if (hdev->ptp->clock)
+ info->phc_index = ptp_clock_index(hdev->ptp->clock);
+ else
+ info->phc_index = -1;
+
+ info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
+
+ info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
+ BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+ BIT(HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+ BIT(HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ);
+
+ info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
+ BIT(HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+ BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) |
+ BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+ BIT(HWTSTAMP_FILTER_PTP_V2_SYNC) |
+ BIT(HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+ BIT(HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
+ BIT(HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ);
+
+ return 0;
+}
+
+static int hclge_ptp_create_clock(struct hclge_dev *hdev)
+{
+ struct hclge_ptp *ptp;
+
+ ptp = devm_kzalloc(&hdev->pdev->dev, sizeof(*ptp), GFP_KERNEL);
+ if (!ptp)
+ return -ENOMEM;
+
+ ptp->hdev = hdev;
+ snprintf(ptp->info.name, sizeof(ptp->info.name), "%s",
+ HCLGE_DRIVER_NAME);
+ ptp->info.owner = THIS_MODULE;
+ ptp->info.max_adj = HCLGE_PTP_CYCLE_ADJ_MAX;
+ ptp->info.n_ext_ts = 0;
+ ptp->info.pps = 0;
+ ptp->info.adjfreq = hclge_ptp_adjfreq;
+ ptp->info.adjtime = hclge_ptp_adjtime;
+ ptp->info.gettimex64 = hclge_ptp_gettimex;
+ ptp->info.settime64 = hclge_ptp_settime;
+
+ ptp->info.n_alarm = 0;
+ ptp->clock = ptp_clock_register(&ptp->info, &hdev->pdev->dev);
+ if (IS_ERR(ptp->clock)) {
+ dev_err(&hdev->pdev->dev,
+ "%d failed to register ptp clock, ret = %ld\n",
+ ptp->info.n_alarm, PTR_ERR(ptp->clock));
+ return -ENODEV;
+ } else if (!ptp->clock) {
+ dev_err(&hdev->pdev->dev, "failed to register ptp clock\n");
+ return -ENODEV;
+ }
+
+ spin_lock_init(&ptp->lock);
+ ptp->io_base = hdev->hw.io_base + HCLGE_PTP_REG_OFFSET;
+ ptp->ts_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
+ ptp->ts_cfg.tx_type = HWTSTAMP_TX_OFF;
+ hdev->ptp = ptp;
+
+ return 0;
+}
+
+static void hclge_ptp_destroy_clock(struct hclge_dev *hdev)
+{
+ ptp_clock_unregister(hdev->ptp->clock);
+ hdev->ptp->clock = NULL;
+ devm_kfree(&hdev->pdev->dev, hdev->ptp);
+ hdev->ptp = NULL;
+}
+
+int hclge_ptp_init(struct hclge_dev *hdev)
+{
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
+ struct timespec64 ts;
+ int ret;
+
+ if (!test_bit(HNAE3_DEV_SUPPORT_PTP_B, ae_dev->caps))
+ return 0;
+
+ if (!hdev->ptp) {
+ ret = hclge_ptp_create_clock(hdev);
+ if (ret)
+ return ret;
+ }
+
+ ret = hclge_ptp_int_en(hdev, true);
+ if (ret)
+ goto out;
+
+ set_bit(HCLGE_PTP_FLAG_EN, &hdev->ptp->flags);
+ ret = hclge_ptp_adjfreq(&hdev->ptp->info, 0);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to init freq, ret = %d\n", ret);
+ goto out;
+ }
+
+ ret = hclge_ptp_set_ts_mode(hdev, &hdev->ptp->ts_cfg);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to init ts mode, ret = %d\n", ret);
+ goto out;
+ }
+
+ ktime_get_real_ts64(&ts);
+ ret = hclge_ptp_settime(&hdev->ptp->info, &ts);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to init ts time, ret = %d\n", ret);
+ goto out;
+ }
+
+ set_bit(HCLGE_STATE_PTP_EN, &hdev->state);
+ dev_info(&hdev->pdev->dev, "phc initializes ok!\n");
+
+ return 0;
+
+out:
+ hclge_ptp_destroy_clock(hdev);
+
+ return ret;
+}
+
+void hclge_ptp_uninit(struct hclge_dev *hdev)
+{
+ struct hclge_ptp *ptp = hdev->ptp;
+
+ if (!ptp)
+ return;
+
+ hclge_ptp_int_en(hdev, false);
+ clear_bit(HCLGE_STATE_PTP_EN, &hdev->state);
+ clear_bit(HCLGE_PTP_FLAG_EN, &ptp->flags);
+ ptp->ts_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
+ ptp->ts_cfg.tx_type = HWTSTAMP_TX_OFF;
+
+ if (hclge_ptp_set_ts_mode(hdev, &ptp->ts_cfg))
+ dev_err(&hdev->pdev->dev, "failed to disable phc\n");
+
+ if (ptp->tx_skb) {
+ struct sk_buff *skb = ptp->tx_skb;
+
+ ptp->tx_skb = NULL;
+ dev_kfree_skb_any(skb);
+ }
+
+ hclge_ptp_destroy_clock(hdev);
+}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.h
new file mode 100644
index 000000000000..5a202b775471
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.h
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+// Copyright (c) 2021 Hisilicon Limited.
+
+#ifndef __HCLGE_PTP_H
+#define __HCLGE_PTP_H
+
+#include <linux/ptp_clock_kernel.h>
+#include <linux/net_tstamp.h>
+#include <linux/types.h>
+
+#define HCLGE_PTP_REG_OFFSET 0x29000
+
+#define HCLGE_PTP_TX_TS_SEQID_REG 0x0
+#define HCLGE_PTP_TX_TS_NSEC_REG 0x4
+#define HCLGE_PTP_TX_TS_NSEC_MASK GENMASK(29, 0)
+#define HCLGE_PTP_TX_TS_SEC_L_REG 0x8
+#define HCLGE_PTP_TX_TS_SEC_H_REG 0xC
+#define HCLGE_PTP_TX_TS_SEC_H_MASK GENMASK(15, 0)
+#define HCLGE_PTP_TX_TS_CNT_REG 0x30
+
+#define HCLGE_PTP_TIME_SEC_H_REG 0x50
+#define HCLGE_PTP_TIME_SEC_H_MASK GENMASK(15, 0)
+#define HCLGE_PTP_TIME_SEC_L_REG 0x54
+#define HCLGE_PTP_TIME_NSEC_REG 0x58
+#define HCLGE_PTP_TIME_NSEC_MASK GENMASK(29, 0)
+#define HCLGE_PTP_TIME_NSEC_NEG BIT(31)
+#define HCLGE_PTP_TIME_SYNC_REG 0x5C
+#define HCLGE_PTP_TIME_SYNC_EN BIT(0)
+#define HCLGE_PTP_TIME_ADJ_REG 0x60
+#define HCLGE_PTP_TIME_ADJ_EN BIT(0)
+#define HCLGE_PTP_CYCLE_QUO_REG 0x64
+#define HCLGE_PTP_CYCLE_DEN_REG 0x68
+#define HCLGE_PTP_CYCLE_NUM_REG 0x6C
+#define HCLGE_PTP_CYCLE_CFG_REG 0x70
+#define HCLGE_PTP_CYCLE_ADJ_EN BIT(0)
+#define HCLGE_PTP_CUR_TIME_SEC_H_REG 0x74
+#define HCLGE_PTP_CUR_TIME_SEC_L_REG 0x78
+#define HCLGE_PTP_CUR_TIME_NSEC_REG 0x7C
+
+#define HCLGE_PTP_CYCLE_ADJ_BASE 2
+#define HCLGE_PTP_CYCLE_ADJ_MAX 500000000
+#define HCLGE_PTP_CYCLE_ADJ_UNIT 100000000
+#define HCLGE_PTP_SEC_H_OFFSET 32u
+#define HCLGE_PTP_SEC_L_MASK GENMASK(31, 0)
+
+#define HCLGE_PTP_FLAG_EN 0
+#define HCLGE_PTP_FLAG_TX_EN 1
+#define HCLGE_PTP_FLAG_RX_EN 2
+
+struct hclge_ptp {
+ struct hclge_dev *hdev;
+ struct ptp_clock *clock;
+ struct sk_buff *tx_skb;
+ unsigned long flags;
+ void __iomem *io_base;
+ struct ptp_clock_info info;
+ struct hwtstamp_config ts_cfg;
+ spinlock_t lock; /* protects ptp registers */
+ u32 ptp_cfg;
+ u32 last_tx_seqid;
+ unsigned long tx_start;
+ unsigned long tx_cnt;
+ unsigned long tx_skipped;
+ unsigned long tx_cleaned;
+ unsigned long last_rx;
+ unsigned long rx_cnt;
+ unsigned long tx_timeout;
+};
+
+struct hclge_ptp_int_cmd {
+#define HCLGE_PTP_INT_EN_B BIT(0)
+
+ u8 int_en;
+ u8 rsvd[23];
+};
+
+enum hclge_ptp_udp_type {
+ HCLGE_PTP_UDP_NOT_TYPE,
+ HCLGE_PTP_UDP_P13F_TYPE,
+ HCLGE_PTP_UDP_P140_TYPE,
+ HCLGE_PTP_UDP_FULL_TYPE,
+};
+
+enum hclge_ptp_msg_type {
+ HCLGE_PTP_MSG_TYPE_V2_L2,
+ HCLGE_PTP_MSG_TYPE_V2,
+ HCLGE_PTP_MSG_TYPE_V2_EVENT,
+};
+
+enum hclge_ptp_msg0_type {
+ HCLGE_PTP_MSG0_V2_DELAY_REQ = 1,
+ HCLGE_PTP_MSG0_V2_PDELAY_REQ,
+ HCLGE_PTP_MSG0_V2_DELAY_RESP,
+ HCLGE_PTP_MSG0_V2_EVENT = 0xF,
+};
+
+#define HCLGE_PTP_MSG1_V2_DEFAULT 1
+
+struct hclge_ptp_cfg_cmd {
+#define HCLGE_PTP_EN_B BIT(0)
+#define HCLGE_PTP_TX_EN_B BIT(1)
+#define HCLGE_PTP_RX_EN_B BIT(2)
+#define HCLGE_PTP_UDP_EN_SHIFT 3
+#define HCLGE_PTP_UDP_EN_MASK GENMASK(4, 3)
+#define HCLGE_PTP_MSG_TYPE_SHIFT 8
+#define HCLGE_PTP_MSG_TYPE_MASK GENMASK(9, 8)
+#define HCLGE_PTP_MSG1_SHIFT 16
+#define HCLGE_PTP_MSG1_MASK GENMASK(19, 16)
+#define HCLGE_PTP_MSG0_SHIFT 24
+#define HCLGE_PTP_MSG0_MASK GENMASK(27, 24)
+
+ __le32 cfg;
+ u8 rsvd[20];
+};
+
+static inline struct hclge_dev *hclge_ptp_get_hdev(struct ptp_clock_info *info)
+{
+ struct hclge_ptp *ptp = container_of(info, struct hclge_ptp, info);
+
+ return ptp->hdev;
+}
+
+bool hclge_ptp_set_tx_info(struct hnae3_handle *handle, struct sk_buff *skb);
+void hclge_ptp_clean_tx_hwts(struct hclge_dev *dev);
+void hclge_ptp_get_rx_hwts(struct hnae3_handle *handle, struct sk_buff *skb,
+ u32 nsec, u32 sec);
+int hclge_ptp_get_cfg(struct hclge_dev *hdev, struct ifreq *ifr);
+int hclge_ptp_set_cfg(struct hclge_dev *hdev, struct ifreq *ifr);
+int hclge_ptp_init(struct hclge_dev *hdev);
+void hclge_ptp_uninit(struct hclge_dev *hdev);
+int hclge_ptp_get_ts_info(struct hnae3_handle *handle,
+ struct ethtool_ts_info *info);
+int hclge_ptp_cfg_qry(struct hclge_dev *hdev, u32 *cfg);
+#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
index ebb962bad451..78d5bf1ea561 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
@@ -1733,6 +1733,36 @@ int hclge_tm_get_qset_weight(struct hclge_dev *hdev, u16 qset_id, u8 *weight)
return 0;
}
+int hclge_tm_get_qset_shaper(struct hclge_dev *hdev, u16 qset_id,
+ struct hclge_tm_shaper_para *para)
+{
+ struct hclge_qs_shapping_cmd *shap_cfg_cmd;
+ struct hclge_desc desc;
+ u32 shapping_para;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QCN_SHAPPING_CFG, true);
+ shap_cfg_cmd = (struct hclge_qs_shapping_cmd *)desc.data;
+ shap_cfg_cmd->qs_id = cpu_to_le16(qset_id);
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to get qset %u shaper, ret = %d\n", qset_id,
+ ret);
+ return ret;
+ }
+
+ shapping_para = le32_to_cpu(shap_cfg_cmd->qs_shapping_para);
+ para->ir_b = hclge_tm_get_field(shapping_para, IR_B);
+ para->ir_u = hclge_tm_get_field(shapping_para, IR_U);
+ para->ir_s = hclge_tm_get_field(shapping_para, IR_S);
+ para->bs_b = hclge_tm_get_field(shapping_para, BS_B);
+ para->bs_s = hclge_tm_get_field(shapping_para, BS_S);
+ para->flag = shap_cfg_cmd->flag;
+ para->rate = le32_to_cpu(shap_cfg_cmd->qs_rate);
+ return 0;
+}
+
int hclge_tm_get_pri_sch_mode(struct hclge_dev *hdev, u8 pri_id, u8 *mode)
{
struct hclge_pri_sch_mode_cfg_cmd *pri_sch_mode;
@@ -1775,7 +1805,7 @@ int hclge_tm_get_pri_weight(struct hclge_dev *hdev, u8 pri_id, u8 *weight)
int hclge_tm_get_pri_shaper(struct hclge_dev *hdev, u8 pri_id,
enum hclge_opcode_type cmd,
- struct hclge_pri_shaper_para *para)
+ struct hclge_tm_shaper_para *para)
{
struct hclge_pri_shapping_cmd *shap_cfg_cmd;
struct hclge_desc desc;
@@ -1807,3 +1837,186 @@ int hclge_tm_get_pri_shaper(struct hclge_dev *hdev, u8 pri_id,
para->rate = le32_to_cpu(shap_cfg_cmd->pri_rate);
return 0;
}
+
+int hclge_tm_get_q_to_qs_map(struct hclge_dev *hdev, u16 q_id, u16 *qset_id)
+{
+ struct hclge_nq_to_qs_link_cmd *map;
+ struct hclge_desc desc;
+ u16 qs_id_l;
+ u16 qs_id_h;
+ int ret;
+
+ map = (struct hclge_nq_to_qs_link_cmd *)desc.data;
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_NQ_TO_QS_LINK, true);
+ map->nq_id = cpu_to_le16(q_id);
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to get queue to qset map, ret = %d\n", ret);
+ return ret;
+ }
+ *qset_id = le16_to_cpu(map->qset_id);
+
+ /* convert qset_id to the following format, drop the vld bit
+ * | qs_id_h | vld | qs_id_l |
+ * qset_id: | 15 ~ 11 | 10 | 9 ~ 0 |
+ * \ \ / /
+ * \ \ / /
+ * qset_id: | 15 | 14 ~ 10 | 9 ~ 0 |
+ */
+ qs_id_l = hnae3_get_field(*qset_id, HCLGE_TM_QS_ID_L_MSK,
+ HCLGE_TM_QS_ID_L_S);
+ qs_id_h = hnae3_get_field(*qset_id, HCLGE_TM_QS_ID_H_EXT_MSK,
+ HCLGE_TM_QS_ID_H_EXT_S);
+ *qset_id = 0;
+ hnae3_set_field(*qset_id, HCLGE_TM_QS_ID_L_MSK, HCLGE_TM_QS_ID_L_S,
+ qs_id_l);
+ hnae3_set_field(*qset_id, HCLGE_TM_QS_ID_H_MSK, HCLGE_TM_QS_ID_H_S,
+ qs_id_h);
+ return 0;
+}
+
+int hclge_tm_get_q_to_tc(struct hclge_dev *hdev, u16 q_id, u8 *tc_id)
+{
+#define HCLGE_TM_TC_MASK 0x7
+
+ struct hclge_tqp_tx_queue_tc_cmd *tc;
+ struct hclge_desc desc;
+ int ret;
+
+ tc = (struct hclge_tqp_tx_queue_tc_cmd *)desc.data;
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TQP_TX_QUEUE_TC, true);
+ tc->queue_id = cpu_to_le16(q_id);
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to get queue to tc map, ret = %d\n", ret);
+ return ret;
+ }
+
+ *tc_id = tc->tc_id & HCLGE_TM_TC_MASK;
+ return 0;
+}
+
+int hclge_tm_get_pg_to_pri_map(struct hclge_dev *hdev, u8 pg_id,
+ u8 *pri_bit_map)
+{
+ struct hclge_pg_to_pri_link_cmd *map;
+ struct hclge_desc desc;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PG_TO_PRI_LINK, true);
+ map = (struct hclge_pg_to_pri_link_cmd *)desc.data;
+ map->pg_id = pg_id;
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to get pg to pri map, ret = %d\n", ret);
+ return ret;
+ }
+
+ *pri_bit_map = map->pri_bit_map;
+ return 0;
+}
+
+int hclge_tm_get_pg_weight(struct hclge_dev *hdev, u8 pg_id, u8 *weight)
+{
+ struct hclge_pg_weight_cmd *pg_weight_cmd;
+ struct hclge_desc desc;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PG_WEIGHT, true);
+ pg_weight_cmd = (struct hclge_pg_weight_cmd *)desc.data;
+ pg_weight_cmd->pg_id = pg_id;
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to get pg weight, ret = %d\n", ret);
+ return ret;
+ }
+
+ *weight = pg_weight_cmd->dwrr;
+ return 0;
+}
+
+int hclge_tm_get_pg_sch_mode(struct hclge_dev *hdev, u8 pg_id, u8 *mode)
+{
+ struct hclge_desc desc;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PG_SCH_MODE_CFG, true);
+ desc.data[0] = cpu_to_le32(pg_id);
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to get pg sch mode, ret = %d\n", ret);
+ return ret;
+ }
+
+ *mode = (u8)le32_to_cpu(desc.data[1]);
+ return 0;
+}
+
+int hclge_tm_get_pg_shaper(struct hclge_dev *hdev, u8 pg_id,
+ enum hclge_opcode_type cmd,
+ struct hclge_tm_shaper_para *para)
+{
+ struct hclge_pg_shapping_cmd *shap_cfg_cmd;
+ struct hclge_desc desc;
+ u32 shapping_para;
+ int ret;
+
+ if (cmd != HCLGE_OPC_TM_PG_C_SHAPPING &&
+ cmd != HCLGE_OPC_TM_PG_P_SHAPPING)
+ return -EINVAL;
+
+ hclge_cmd_setup_basic_desc(&desc, cmd, true);
+ shap_cfg_cmd = (struct hclge_pg_shapping_cmd *)desc.data;
+ shap_cfg_cmd->pg_id = pg_id;
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to get pg shaper(%#x), ret = %d\n",
+ cmd, ret);
+ return ret;
+ }
+
+ shapping_para = le32_to_cpu(shap_cfg_cmd->pg_shapping_para);
+ para->ir_b = hclge_tm_get_field(shapping_para, IR_B);
+ para->ir_u = hclge_tm_get_field(shapping_para, IR_U);
+ para->ir_s = hclge_tm_get_field(shapping_para, IR_S);
+ para->bs_b = hclge_tm_get_field(shapping_para, BS_B);
+ para->bs_s = hclge_tm_get_field(shapping_para, BS_S);
+ para->flag = shap_cfg_cmd->flag;
+ para->rate = le32_to_cpu(shap_cfg_cmd->pg_rate);
+ return 0;
+}
+
+int hclge_tm_get_port_shaper(struct hclge_dev *hdev,
+ struct hclge_tm_shaper_para *para)
+{
+ struct hclge_port_shapping_cmd *port_shap_cfg_cmd;
+ struct hclge_desc desc;
+ u32 shapping_para;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PORT_SHAPPING, true);
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to get port shaper, ret = %d\n", ret);
+ return ret;
+ }
+
+ port_shap_cfg_cmd = (struct hclge_port_shapping_cmd *)desc.data;
+ shapping_para = le32_to_cpu(port_shap_cfg_cmd->port_shapping_para);
+ para->ir_b = hclge_tm_get_field(shapping_para, IR_B);
+ para->ir_u = hclge_tm_get_field(shapping_para, IR_U);
+ para->ir_s = hclge_tm_get_field(shapping_para, IR_S);
+ para->bs_b = hclge_tm_get_field(shapping_para, BS_B);
+ para->bs_s = hclge_tm_get_field(shapping_para, BS_S);
+ para->flag = port_shap_cfg_cmd->flag;
+ para->rate = le32_to_cpu(port_shap_cfg_cmd->port_rate);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
index b25d76023af0..2ee9b795f71d 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
@@ -199,14 +199,14 @@ struct hclge_tm_nodes_cmd {
__le16 queue_num;
};
-struct hclge_pri_shaper_para {
+struct hclge_tm_shaper_para {
+ u32 rate;
u8 ir_b;
u8 ir_u;
u8 ir_s;
u8 bs_b;
u8 bs_s;
u8 flag;
- u32 rate;
};
#define hclge_tm_set_field(dest, string, val) \
@@ -237,9 +237,22 @@ int hclge_tm_get_qset_map_pri(struct hclge_dev *hdev, u16 qset_id, u8 *priority,
u8 *link_vld);
int hclge_tm_get_qset_sch_mode(struct hclge_dev *hdev, u16 qset_id, u8 *mode);
int hclge_tm_get_qset_weight(struct hclge_dev *hdev, u16 qset_id, u8 *weight);
+int hclge_tm_get_qset_shaper(struct hclge_dev *hdev, u16 qset_id,
+ struct hclge_tm_shaper_para *para);
int hclge_tm_get_pri_sch_mode(struct hclge_dev *hdev, u8 pri_id, u8 *mode);
int hclge_tm_get_pri_weight(struct hclge_dev *hdev, u8 pri_id, u8 *weight);
int hclge_tm_get_pri_shaper(struct hclge_dev *hdev, u8 pri_id,
enum hclge_opcode_type cmd,
- struct hclge_pri_shaper_para *para);
+ struct hclge_tm_shaper_para *para);
+int hclge_tm_get_q_to_qs_map(struct hclge_dev *hdev, u16 q_id, u16 *qset_id);
+int hclge_tm_get_q_to_tc(struct hclge_dev *hdev, u16 q_id, u8 *tc_id);
+int hclge_tm_get_pg_to_pri_map(struct hclge_dev *hdev, u8 pg_id,
+ u8 *pri_bit_map);
+int hclge_tm_get_pg_weight(struct hclge_dev *hdev, u8 pg_id, u8 *weight);
+int hclge_tm_get_pg_sch_mode(struct hclge_dev *hdev, u8 pg_id, u8 *mode);
+int hclge_tm_get_pg_shaper(struct hclge_dev *hdev, u8 pg_id,
+ enum hclge_opcode_type cmd,
+ struct hclge_tm_shaper_para *para);
+int hclge_tm_get_port_shaper(struct hclge_dev *hdev,
+ struct hclge_tm_shaper_para *para);
#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c
index d8c5c5810b99..bd19a2d89f6c 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c
@@ -359,6 +359,8 @@ static void hclgevf_parse_capability(struct hclgevf_dev *hdev,
set_bit(HNAE3_DEV_SUPPORT_HW_TX_CSUM_B, ae_dev->caps);
if (hnae3_get_bit(caps, HCLGEVF_CAP_UDP_TUNNEL_CSUM_B))
set_bit(HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B, ae_dev->caps);
+ if (hnae3_get_bit(caps, HCLGEVF_CAP_RXD_ADV_LAYOUT_B))
+ set_bit(HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B, ae_dev->caps);
}
static __le32 hclgevf_build_api_caps(void)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h
index c6dc11b32aa7..202feb70dba5 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h
@@ -159,6 +159,7 @@ enum HCLGEVF_CAP_BITS {
HCLGEVF_CAP_HW_PAD_B,
HCLGEVF_CAP_STASH_B,
HCLGEVF_CAP_UDP_TUNNEL_CSUM_B,
+ HCLGEVF_CAP_RXD_ADV_LAYOUT_B = 15,
};
enum HCLGEVF_API_CAP_BITS {
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
index 0db51ef15ef6..52eaf82b7cd7 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
@@ -243,23 +243,31 @@ static void hclgevf_build_send_msg(struct hclge_vf_to_pf_msg *msg, u8 code,
}
}
-static int hclgevf_get_tc_info(struct hclgevf_dev *hdev)
+static int hclgevf_get_basic_info(struct hclgevf_dev *hdev)
{
+ struct hnae3_ae_dev *ae_dev = hdev->ae_dev;
+ u8 resp_msg[HCLGE_MBX_MAX_RESP_DATA_SIZE];
+ struct hclge_basic_info *basic_info;
struct hclge_vf_to_pf_msg send_msg;
- u8 resp_msg;
+ unsigned long caps;
int status;
- hclgevf_build_send_msg(&send_msg, HCLGE_MBX_GET_TCINFO, 0);
- status = hclgevf_send_mbx_msg(hdev, &send_msg, true, &resp_msg,
+ hclgevf_build_send_msg(&send_msg, HCLGE_MBX_GET_BASIC_INFO, 0);
+ status = hclgevf_send_mbx_msg(hdev, &send_msg, true, resp_msg,
sizeof(resp_msg));
if (status) {
dev_err(&hdev->pdev->dev,
- "VF request to get TC info from PF failed %d",
- status);
+ "failed to get basic info from pf, ret = %d", status);
return status;
}
- hdev->hw_tc_map = resp_msg;
+ basic_info = (struct hclge_basic_info *)resp_msg;
+
+ hdev->hw_tc_map = basic_info->hw_tc_map;
+ hdev->mbx_api_version = basic_info->mbx_api_version;
+ caps = basic_info->pf_caps;
+ if (test_bit(HNAE3_PF_SUPPORT_VLAN_FLTR_MDF_B, &caps))
+ set_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps);
return 0;
}
@@ -1528,8 +1536,7 @@ static void hclgevf_sync_from_add_list(struct list_head *add_list,
kfree(mac_node);
} else if (mac_node->state == HCLGEVF_MAC_ACTIVE) {
mac_node->state = HCLGEVF_MAC_TO_DEL;
- list_del(&mac_node->node);
- list_add_tail(&mac_node->node, mac_list);
+ list_move_tail(&mac_node->node, mac_list);
} else {
list_del(&mac_node->node);
kfree(mac_node);
@@ -1554,8 +1561,7 @@ static void hclgevf_sync_from_del_list(struct list_head *del_list,
list_del(&mac_node->node);
kfree(mac_node);
} else {
- list_del(&mac_node->node);
- list_add_tail(&mac_node->node, mac_list);
+ list_move_tail(&mac_node->node, mac_list);
}
}
}
@@ -1591,8 +1597,7 @@ static void hclgevf_sync_mac_list(struct hclgevf_dev *hdev,
list_for_each_entry_safe(mac_node, tmp, list, node) {
switch (mac_node->state) {
case HCLGEVF_MAC_TO_DEL:
- list_del(&mac_node->node);
- list_add_tail(&mac_node->node, &tmp_del_list);
+ list_move_tail(&mac_node->node, &tmp_del_list);
break;
case HCLGEVF_MAC_TO_ADD:
new_node = kzalloc(sizeof(*new_node), GFP_ATOMIC);
@@ -1642,6 +1647,22 @@ static void hclgevf_uninit_mac_list(struct hclgevf_dev *hdev)
spin_unlock_bh(&hdev->mac_table.mac_list_lock);
}
+static int hclgevf_enable_vlan_filter(struct hnae3_handle *handle, bool enable)
+{
+ struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
+ struct hnae3_ae_dev *ae_dev = hdev->ae_dev;
+ struct hclge_vf_to_pf_msg send_msg;
+
+ if (!test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps))
+ return -EOPNOTSUPP;
+
+ hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_VLAN,
+ HCLGE_MBX_ENABLE_VLAN_FILTER);
+ send_msg.data[0] = enable ? 1 : 0;
+
+ return hclgevf_send_mbx_msg(hdev, &send_msg, true, NULL, 0);
+}
+
static int hclgevf_set_vlan_filter(struct hnae3_handle *handle,
__be16 proto, u16 vlan_id,
bool is_kill)
@@ -2466,6 +2487,10 @@ static int hclgevf_configure(struct hclgevf_dev *hdev)
{
int ret;
+ ret = hclgevf_get_basic_info(hdev);
+ if (ret)
+ return ret;
+
/* get current port based vlan state from PF */
ret = hclgevf_get_port_base_vlan_filter_state(hdev);
if (ret)
@@ -2481,12 +2506,7 @@ static int hclgevf_configure(struct hclgevf_dev *hdev)
if (ret)
return ret;
- ret = hclgevf_get_pf_media_type(hdev);
- if (ret)
- return ret;
-
- /* get tc configuration from PF */
- return hclgevf_get_tc_info(hdev);
+ return hclgevf_get_pf_media_type(hdev);
}
static int hclgevf_alloc_hdev(struct hnae3_ae_dev *ae_dev)
@@ -3242,6 +3262,18 @@ static int hclgevf_clear_vport_list(struct hclgevf_dev *hdev)
return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0);
}
+static void hclgevf_init_rxd_adv_layout(struct hclgevf_dev *hdev)
+{
+ if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev))
+ hclgevf_write_dev(&hdev->hw, HCLGEVF_RXD_ADV_LAYOUT_EN_REG, 1);
+}
+
+static void hclgevf_uninit_rxd_adv_layout(struct hclgevf_dev *hdev)
+{
+ if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev))
+ hclgevf_write_dev(&hdev->hw, HCLGEVF_RXD_ADV_LAYOUT_EN_REG, 0);
+}
+
static int hclgevf_reset_hdev(struct hclgevf_dev *hdev)
{
struct pci_dev *pdev = hdev->pdev;
@@ -3279,6 +3311,8 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev)
set_bit(HCLGEVF_STATE_PROMISC_CHANGED, &hdev->state);
+ hclgevf_init_rxd_adv_layout(hdev);
+
dev_info(&hdev->pdev->dev, "Reset done\n");
return 0;
@@ -3379,6 +3413,8 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev)
goto err_config;
}
+ hclgevf_init_rxd_adv_layout(hdev);
+
hdev->last_reset_time = jiffies;
dev_info(&hdev->pdev->dev, "finished initializing %s driver\n",
HCLGEVF_DRIVER_NAME);
@@ -3405,6 +3441,7 @@ static void hclgevf_uninit_hdev(struct hclgevf_dev *hdev)
struct hclge_vf_to_pf_msg send_msg;
hclgevf_state_uninit(hdev);
+ hclgevf_uninit_rxd_adv_layout(hdev);
hclgevf_build_send_msg(&send_msg, HCLGE_MBX_VF_UNINIT, 0);
hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0);
@@ -3784,6 +3821,7 @@ static const struct hnae3_ae_ops hclgevf_ops = {
.get_tc_size = hclgevf_get_tc_size,
.get_fw_version = hclgevf_get_fw_version,
.set_vlan_filter = hclgevf_set_vlan_filter,
+ .enable_vlan_filter = hclgevf_enable_vlan_filter,
.enable_hw_strip_rxvtag = hclgevf_en_hw_strip_rxvtag,
.reset_event = hclgevf_reset_event,
.set_default_reset_request = hclgevf_set_def_reset_request,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
index 265c9b0b4728..d7d02848d674 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
@@ -47,6 +47,7 @@
/* bar registers for common func */
#define HCLGEVF_GRO_EN_REG 0x28000
+#define HCLGEVF_RXD_ADV_LAYOUT_EN_REG 0x28008
/* bar registers for rcb */
#define HCLGEVF_RING_RX_ADDR_L_REG 0x80000
@@ -284,6 +285,7 @@ struct hclgevf_dev {
struct semaphore reset_sem; /* protect reset process */
u32 fw_version;
+ u16 mbx_api_version;
u16 num_tqps; /* num task queue pairs of this VF */
u16 alloc_rss_size; /* allocated RSS task queue */
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
index dc024ef521c0..162d3c330dec 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
@@ -1663,7 +1663,6 @@ static void hinic_diag_test(struct net_device *netdev,
err = hinic_port_link_state(nic_dev, &link_state);
if (!err && link_state == HINIC_LINK_STATE_UP)
netif_carrier_on(netdev);
-
}
static int hinic_set_phys_id(struct net_device *netdev,
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c
index 5a6bbee819cd..307a6d4af993 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c
@@ -223,7 +223,7 @@ static void cmdq_prepare_wqe_ctrl(struct hinic_cmdq_wqe *wqe, int wrapped,
saved_data = CMDQ_WQE_HEADER(wqe)->saved_data;
saved_data = HINIC_SAVED_DATA_CLEAR(saved_data, ARM);
- if ((cmd == CMDQ_SET_ARM_CMD) && (mod == HINIC_MOD_COMM))
+ if (cmd == CMDQ_SET_ARM_CMD && mod == HINIC_MOD_COMM)
CMDQ_WQE_HEADER(wqe)->saved_data |=
HINIC_SAVED_DATA_SET(1, ARM);
else
@@ -594,7 +594,7 @@ static void cmdq_update_errcode(struct hinic_cmdq *cmdq, u16 prod_idx,
}
/**
- * cmdq_arm_ceq_handler - cmdq completion event handler for sync command
+ * cmdq_sync_cmd_handler - cmdq completion event handler for sync command
* @cmdq: the cmdq of the command
* @cons_idx: the consumer index to update the error code for
* @errcode: the error code
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
index 0c74f6674634..428108eb10d2 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
@@ -48,7 +48,7 @@ enum io_status {
};
/**
- * get_capability - convert device capabilities to NIC capabilities
+ * parse_capability - convert device capabilities to NIC capabilities
* @hwdev: the HW device to set and convert device capabilities for
* @dev_cap: device capabilities from FW
*
@@ -92,7 +92,7 @@ static int parse_capability(struct hinic_hwdev *hwdev,
}
/**
- * get_cap_from_fw - get device capabilities from FW
+ * get_capability - get device capabilities from FW
* @pfhwdev: the PF HW device to get capabilities for
*
* Return 0 - Success, negative - Failure
@@ -257,7 +257,7 @@ static int init_fw_ctxt(struct hinic_hwdev *hwdev)
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_FWCTXT_INIT,
&fw_ctxt, sizeof(fw_ctxt),
&fw_ctxt, &out_size);
- if (err || (out_size != sizeof(fw_ctxt)) || fw_ctxt.status) {
+ if (err || out_size != sizeof(fw_ctxt) || fw_ctxt.status) {
dev_err(&pdev->dev, "Failed to init FW ctxt, err: %d, status: 0x%x, out size: 0x%x\n",
err, fw_ctxt.status, out_size);
return -EIO;
@@ -346,7 +346,7 @@ static int wait_for_db_state(struct hinic_hwdev *hwdev)
}
/**
- * clear_io_resource - set the IO resources as not active in the NIC
+ * clear_io_resources - set the IO resources as not active in the NIC
* @hwdev: the NIC HW device
*
* Return 0 - Success, negative - Failure
@@ -424,7 +424,7 @@ static int get_base_qpn(struct hinic_hwdev *hwdev, u16 *base_qpn)
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_GLOBAL_QPN,
&cmd_base_qpn, sizeof(cmd_base_qpn),
&cmd_base_qpn, &out_size);
- if (err || (out_size != sizeof(cmd_base_qpn)) || cmd_base_qpn.status) {
+ if (err || out_size != sizeof(cmd_base_qpn) || cmd_base_qpn.status) {
dev_err(&pdev->dev, "Failed to get base qpn, err: %d, status: 0x%x, out size: 0x%x\n",
err, cmd_base_qpn.status, out_size);
return -EIO;
@@ -605,8 +605,8 @@ static void nic_mgmt_msg_handler(void *handle, u8 cmd, void *buf_in,
hwif = hwdev->hwif;
pdev = hwif->pdev;
- if ((cmd < HINIC_MGMT_MSG_CMD_BASE) ||
- (cmd >= HINIC_MGMT_MSG_CMD_MAX)) {
+ if (cmd < HINIC_MGMT_MSG_CMD_BASE ||
+ cmd >= HINIC_MGMT_MSG_CMD_MAX) {
dev_err(&pdev->dev, "unknown L2NIC event, cmd = %d\n", cmd);
return;
}
@@ -619,7 +619,7 @@ static void nic_mgmt_msg_handler(void *handle, u8 cmd, void *buf_in,
HINIC_CB_ENABLED,
HINIC_CB_ENABLED | HINIC_CB_RUNNING);
- if ((cb_state == HINIC_CB_ENABLED) && (nic_cb->handler))
+ if (cb_state == HINIC_CB_ENABLED && nic_cb->handler)
nic_cb->handler(nic_cb->handle, buf_in,
in_size, buf_out, out_size);
else
@@ -1090,7 +1090,7 @@ struct hinic_sq *hinic_hwdev_get_sq(struct hinic_hwdev *hwdev, int i)
}
/**
- * hinic_hwdev_get_sq - get RQ
+ * hinic_hwdev_get_rq - get RQ
* @hwdev: the NIC HW device
* @i: the position of the RQ
*
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
index 19942fef99d9..d3fc05a07fdb 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
@@ -254,8 +254,8 @@ static void aeq_irq_handler(struct hinic_eq *eq)
HINIC_EQE_ENABLED,
HINIC_EQE_ENABLED |
HINIC_EQE_RUNNING);
- if ((eqe_state == HINIC_EQE_ENABLED) &&
- (hwe_cb->hwe_handler))
+ if (eqe_state == HINIC_EQE_ENABLED &&
+ hwe_cb->hwe_handler)
hwe_cb->hwe_handler(hwe_cb->handle,
aeqe_curr->data, size);
else
@@ -299,7 +299,7 @@ static void ceq_event_handler(struct hinic_ceqs *ceqs, u32 ceqe)
HINIC_EQE_ENABLED,
HINIC_EQE_ENABLED | HINIC_EQE_RUNNING);
- if ((eqe_state == HINIC_EQE_ENABLED) && (ceq_cb->handler))
+ if (eqe_state == HINIC_EQE_ENABLED && ceq_cb->handler)
ceq_cb->handler(ceq_cb->handle, CEQE_DATA(ceqe));
else
dev_err(&pdev->dev, "Unhandled CEQ Event %d\n", event);
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c
index cab38ff0713c..0428faa68e80 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c
@@ -334,7 +334,7 @@ static void set_dma_attr(struct hinic_hwif *hwif, u32 entry_idx,
}
/**
- * dma_attr_table_init - initialize the default dma attributes
+ * dma_attr_init - initialize the default dma attributes
* @hwif: the HW interface of a pci function device
**/
static void dma_attr_init(struct hinic_hwif *hwif)
@@ -395,7 +395,7 @@ static void __print_selftest_reg(struct hinic_hwif *hwif)
/**
* hinic_init_hwif - initialize the hw interface
* @hwif: the HW interface of a pci function device
- * @pdev: the pci device for acessing PCI resources
+ * @pdev: the pci device for accessing PCI resources
*
* Return 0 - Success, negative - Failure
**/
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c
index 4ef4008e65bd..a6e43d686293 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c
@@ -137,7 +137,7 @@ static int write_sq_ctxts(struct hinic_func_to_io *func_to_io, u16 base_qpn,
err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC,
IO_CMD_MODIFY_QUEUE_CTXT, &cmdq_buf,
&out_param);
- if ((err) || (out_param != 0)) {
+ if (err || out_param != 0) {
dev_err(&pdev->dev, "Failed to set SQ ctxts\n");
err = -EFAULT;
}
@@ -181,7 +181,7 @@ static int write_rq_ctxts(struct hinic_func_to_io *func_to_io, u16 base_qpn,
err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC,
IO_CMD_MODIFY_QUEUE_CTXT, &cmdq_buf,
&out_param);
- if ((err) || (out_param != 0)) {
+ if (err || out_param != 0) {
dev_err(&pdev->dev, "Failed to set RQ ctxts\n");
err = -EFAULT;
}
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
index 817173f1fbb7..ebc77771f5da 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
@@ -294,7 +294,7 @@ static int msg_to_mgmt_sync(struct hinic_pf_to_mgmt *pf_to_mgmt,
goto unlock_sync_msg;
}
- if ((buf_out) && (recv_msg->msg_len <= MAX_PF_MGMT_BUF_SIZE)) {
+ if (buf_out && recv_msg->msg_len <= MAX_PF_MGMT_BUF_SIZE) {
memcpy(buf_out, recv_msg->msg, recv_msg->msg_len);
*out_size = recv_msg->msg_len;
}
@@ -411,7 +411,7 @@ static void recv_mgmt_msg_work_handler(struct work_struct *work)
HINIC_MGMT_CB_ENABLED,
HINIC_MGMT_CB_ENABLED | HINIC_MGMT_CB_RUNNING);
- if ((cb_state == HINIC_MGMT_CB_ENABLED) && (mgmt_cb->cb))
+ if (cb_state == HINIC_MGMT_CB_ENABLED && mgmt_cb->cb)
mgmt_cb->cb(mgmt_cb->handle, mgmt_work->cmd,
mgmt_work->msg, mgmt_work->msg_len,
buf_out, &out_size);
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c
index dcba4d009bad..336248aa2e48 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c
@@ -894,7 +894,7 @@ struct hinic_rq_wqe *hinic_rq_read_next_wqe(struct hinic_rq *rq,
}
/**
- * hinic_put_wqe - release the ci for new wqes
+ * hinic_rq_put_wqe - release the ci for new wqes
* @rq: recv queue
* @cons_idx: consumer index of the wqe
* @wqe_size: the size of the wqe
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c
index 5dc3743f8091..7f0f1aa3cedd 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c
@@ -89,6 +89,7 @@ static inline int WQE_PAGE_NUM(struct hinic_wq *wq, u16 idx)
return (((idx) >> ((wq)->wqebbs_per_page_shift))
& ((wq)->num_q_pages - 1));
}
+
/**
* queue_alloc_page - allocate page for Queue
* @hwif: HW interface for allocating DMA
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c b/drivers/net/ethernet/huawei/hinic/hinic_main.c
index 9a9b09401d01..405ee4d2d2b1 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_main.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c
@@ -172,7 +172,6 @@ static int create_txqs(struct hinic_dev *nic_dev)
"Failed to add SQ%d debug\n", i);
goto err_add_sq_dbg;
}
-
}
return 0;
@@ -233,7 +232,7 @@ static void free_txqs(struct hinic_dev *nic_dev)
}
/**
- * create_txqs - Create the Logical Rx Queues of specific NIC device
+ * create_rxqs - Create the Logical Rx Queues of specific NIC device
* @nic_dev: the specific NIC device
*
* Return 0 - Success, negative - Failure
@@ -289,7 +288,7 @@ err_init_rxq:
}
/**
- * free_txqs - Free the Logical Rx Queues of specific NIC device
+ * free_rxqs - Free the Logical Rx Queues of specific NIC device
* @nic_dev: the specific NIC device
**/
static void free_rxqs(struct hinic_dev *nic_dev)
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.c b/drivers/net/ethernet/huawei/hinic/hinic_port.c
index eb97f2d6b1ad..28ae6f1201a8 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_port.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_port.c
@@ -128,7 +128,7 @@ int hinic_port_get_mac(struct hinic_dev *nic_dev, u8 *addr)
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_MAC,
&port_mac_cmd, sizeof(port_mac_cmd),
&port_mac_cmd, &out_size);
- if (err || (out_size != sizeof(port_mac_cmd)) || port_mac_cmd.status) {
+ if (err || out_size != sizeof(port_mac_cmd) || port_mac_cmd.status) {
dev_err(&pdev->dev, "Failed to get mac, err: %d, status: 0x%x, out size: 0x%x\n",
err, port_mac_cmd.status, out_size);
return -EFAULT;
@@ -263,7 +263,7 @@ int hinic_port_link_state(struct hinic_dev *nic_dev,
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_LINK_STATE,
&link_cmd, sizeof(link_cmd),
&link_cmd, &out_size);
- if (err || (out_size != sizeof(link_cmd)) || link_cmd.status) {
+ if (err || out_size != sizeof(link_cmd) || link_cmd.status) {
dev_err(&pdev->dev, "Failed to get link state, err: %d, status: 0x%x, out size: 0x%x\n",
err, link_cmd.status, out_size);
return -EINVAL;
@@ -297,7 +297,7 @@ int hinic_port_set_state(struct hinic_dev *nic_dev, enum hinic_port_state state)
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_PORT_STATE,
&port_state, sizeof(port_state),
&port_state, &out_size);
- if (err || (out_size != sizeof(port_state)) || port_state.status) {
+ if (err || out_size != sizeof(port_state) || port_state.status) {
dev_err(&pdev->dev, "Failed to set port state, err: %d, status: 0x%x, out size: 0x%x\n",
err, port_state.status, out_size);
return -EFAULT;
@@ -329,7 +329,7 @@ int hinic_port_set_func_state(struct hinic_dev *nic_dev,
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_FUNC_STATE,
&func_state, sizeof(func_state),
&func_state, &out_size);
- if (err || (out_size != sizeof(func_state)) || func_state.status) {
+ if (err || out_size != sizeof(func_state) || func_state.status) {
dev_err(&pdev->dev, "Failed to set port func state, err: %d, status: 0x%x, out size: 0x%x\n",
err, func_state.status, out_size);
return -EFAULT;
@@ -359,7 +359,7 @@ int hinic_port_get_cap(struct hinic_dev *nic_dev,
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_CAP,
port_cap, sizeof(*port_cap),
port_cap, &out_size);
- if (err || (out_size != sizeof(*port_cap)) || port_cap->status) {
+ if (err || out_size != sizeof(*port_cap) || port_cap->status) {
dev_err(&pdev->dev,
"Failed to get port capabilities, err: %d, status: 0x%x, out size: 0x%x\n",
err, port_cap->status, out_size);
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_rx.c b/drivers/net/ethernet/huawei/hinic/hinic_rx.c
index cce08647b9b2..fed3b6bc0d76 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_rx.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_rx.c
@@ -118,6 +118,7 @@ static void rx_csum(struct hinic_rxq *rxq, u32 status,
skb->ip_summed = CHECKSUM_NONE;
}
}
+
/**
* rx_alloc_skb - allocate skb and map it to dma address
* @rxq: rx queue
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_tx.c b/drivers/net/ethernet/huawei/hinic/hinic_tx.c
index 710c4ff7bc0e..c5bdb0d374ef 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_tx.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_tx.c
@@ -660,7 +660,7 @@ static void tx_free_skb(struct hinic_dev *nic_dev, struct sk_buff *skb,
}
/**
- * free_all_rx_skbs - free all skbs in tx queue
+ * free_all_tx_skbs - free all skbs in tx queue
* @txq: tx queue
**/
static void free_all_tx_skbs(struct hinic_txq *txq)
@@ -717,7 +717,7 @@ static int free_tx_poll(struct napi_struct *napi, int budget)
/* Reading a WQEBB to get real WQE size and consumer index. */
sq_wqe = hinic_sq_read_wqebb(sq, &skb, &wqe_size, &sw_ci);
- if ((!sq_wqe) ||
+ if (!sq_wqe ||
(((hw_ci - sw_ci) & wq->mask) * wq->wqebb_size < wqe_size))
break;
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index ea55314b209d..d5df131b183c 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -2618,10 +2618,8 @@ static int ehea_restart_qps(struct net_device *dev)
u16 dummy16 = 0;
cb0 = (void *)get_zeroed_page(GFP_KERNEL);
- if (!cb0) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!cb0)
+ return -ENOMEM;
for (i = 0; i < (port->num_def_qps); i++) {
struct ehea_port_res *pr = &port->port_res[i];
@@ -2641,6 +2639,7 @@ static int ehea_restart_qps(struct net_device *dev)
cb0);
if (hret != H_SUCCESS) {
netdev_err(dev, "query_ehea_qp failed (1)\n");
+ ret = -EFAULT;
goto out;
}
@@ -2653,6 +2652,7 @@ static int ehea_restart_qps(struct net_device *dev)
&dummy64, &dummy16, &dummy16);
if (hret != H_SUCCESS) {
netdev_err(dev, "modify_ehea_qp failed (1)\n");
+ ret = -EFAULT;
goto out;
}
@@ -2661,6 +2661,7 @@ static int ehea_restart_qps(struct net_device *dev)
cb0);
if (hret != H_SUCCESS) {
netdev_err(dev, "query_ehea_qp failed (2)\n");
+ ret = -EFAULT;
goto out;
}
@@ -2867,14 +2868,14 @@ out:
return ret;
}
-static ssize_t ehea_show_port_id(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t log_port_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev);
return sprintf(buf, "%d", port->logical_port_id);
}
-static DEVICE_ATTR(log_port_id, 0444, ehea_show_port_id, NULL);
+static DEVICE_ATTR_RO(log_port_id);
static void logical_port_release(struct device *dev)
{
@@ -3113,7 +3114,7 @@ static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter,
return NULL;
}
-static ssize_t ehea_probe_port(struct device *dev,
+static ssize_t probe_port_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -3168,9 +3169,9 @@ static ssize_t ehea_probe_port(struct device *dev,
return (ssize_t) count;
}
-static ssize_t ehea_remove_port(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t remove_port_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct ehea_adapter *adapter = dev_get_drvdata(dev);
struct ehea_port *port;
@@ -3203,8 +3204,8 @@ static ssize_t ehea_remove_port(struct device *dev,
return (ssize_t) count;
}
-static DEVICE_ATTR(probe_port, 0200, NULL, ehea_probe_port);
-static DEVICE_ATTR(remove_port, 0200, NULL, ehea_remove_port);
+static DEVICE_ATTR_WO(probe_port);
+static DEVICE_ATTR_WO(remove_port);
static int ehea_create_device_sysfs(struct platform_device *dev)
{
diff --git a/drivers/net/ethernet/ibm/emac/emac.h b/drivers/net/ethernet/ibm/emac/emac.h
index aa9f651288d5..09d3ac374b2d 100644
--- a/drivers/net/ethernet/ibm/emac/emac.h
+++ b/drivers/net/ethernet/ibm/emac/emac.h
@@ -77,7 +77,7 @@ struct emac_regs {
struct {
u32 rsvd1;
u32 revid;
- u32 rsvd2[2];
+ u32 rsvd2[2];
u32 iaht1; /* Reset, R */
u32 iaht2; /* Reset, R */
u32 iaht3; /* Reset, R */
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 7fea9ae60f13..737ba85e409f 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1285,36 +1285,41 @@ static void ibmveth_rx_csum_helper(struct sk_buff *skb,
iph_proto = iph6->nexthdr;
}
- /* In OVS environment, when a flow is not cached, specifically for a
- * new TCP connection, the first packet information is passed up
+ /* When CSO is enabled the TCP checksum may have be set to NULL by
+ * the sender given that we zeroed out TCP checksum field in
+ * transmit path (refer ibmveth_start_xmit routine). In this case set
+ * up CHECKSUM_PARTIAL. If the packet is forwarded, the checksum will
+ * then be recalculated by the destination NIC (CSO must be enabled
+ * on the destination NIC).
+ *
+ * In an OVS environment, when a flow is not cached, specifically for a
+ * new TCP connection, the first packet information is passed up to
* the user space for finding a flow. During this process, OVS computes
* checksum on the first packet when CHECKSUM_PARTIAL flag is set.
*
- * Given that we zeroed out TCP checksum field in transmit path
- * (refer ibmveth_start_xmit routine) as we set "no checksum bit",
- * OVS computed checksum will be incorrect w/o TCP pseudo checksum
- * in the packet. This leads to OVS dropping the packet and hence
- * TCP retransmissions are seen.
- *
- * So, re-compute TCP pseudo header checksum.
+ * So, re-compute TCP pseudo header checksum when configured for
+ * trunk mode.
*/
- if (iph_proto == IPPROTO_TCP && adapter->is_active_trunk) {
+ if (iph_proto == IPPROTO_TCP) {
struct tcphdr *tcph = (struct tcphdr *)(skb->data + iphlen);
-
- tcphdrlen = skb->len - iphlen;
-
- /* Recompute TCP pseudo header checksum */
- if (skb_proto == ETH_P_IP)
- tcph->check = ~csum_tcpudp_magic(iph->saddr,
+ if (tcph->check == 0x0000) {
+ /* Recompute TCP pseudo header checksum */
+ if (adapter->is_active_trunk) {
+ tcphdrlen = skb->len - iphlen;
+ if (skb_proto == ETH_P_IP)
+ tcph->check =
+ ~csum_tcpudp_magic(iph->saddr,
iph->daddr, tcphdrlen, iph_proto, 0);
- else if (skb_proto == ETH_P_IPV6)
- tcph->check = ~csum_ipv6_magic(&iph6->saddr,
+ else if (skb_proto == ETH_P_IPV6)
+ tcph->check =
+ ~csum_ipv6_magic(&iph6->saddr,
&iph6->daddr, tcphdrlen, iph_proto, 0);
-
- /* Setup SKB fields for checksum offload */
- skb_partial_csum_set(skb, iphlen,
- offsetof(struct tcphdr, check));
- skb_reset_network_header(skb);
+ }
+ /* Setup SKB fields for checksum offload */
+ skb_partial_csum_set(skb, iphlen,
+ offsetof(struct tcphdr, check));
+ skb_reset_network_header(skb);
+ }
}
}
@@ -1799,8 +1804,7 @@ static ssize_t veth_pool_store(struct kobject *kobj, struct attribute *attr,
struct ibmveth_buff_pool *pool = container_of(kobj,
struct ibmveth_buff_pool,
kobj);
- struct net_device *netdev = dev_get_drvdata(
- container_of(kobj->parent, struct device, kobj));
+ struct net_device *netdev = dev_get_drvdata(kobj_to_dev(kobj->parent));
struct ibmveth_adapter *adapter = netdev_priv(netdev);
long value = simple_strtol(buf, NULL, 10);
long rc;
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index 5788bb956d73..ed77191d19f4 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -95,7 +95,7 @@ static union sub_crq *ibmvnic_next_scrq(struct ibmvnic_adapter *,
struct ibmvnic_sub_crq_queue *);
static int ibmvnic_poll(struct napi_struct *napi, int data);
static void send_query_map(struct ibmvnic_adapter *adapter);
-static int send_request_map(struct ibmvnic_adapter *, dma_addr_t, __be32, u8);
+static int send_request_map(struct ibmvnic_adapter *, dma_addr_t, u32, u8);
static int send_request_unmap(struct ibmvnic_adapter *, u8);
static int send_login(struct ibmvnic_adapter *adapter);
static void send_query_cap(struct ibmvnic_adapter *adapter);
@@ -106,6 +106,8 @@ static void release_crq_queue(struct ibmvnic_adapter *);
static int __ibmvnic_set_mac(struct net_device *, u8 *);
static int init_crq_queue(struct ibmvnic_adapter *adapter);
static int send_query_phys_parms(struct ibmvnic_adapter *adapter);
+static void ibmvnic_tx_scrq_clean_buffer(struct ibmvnic_adapter *adapter,
+ struct ibmvnic_sub_crq_queue *tx_scrq);
struct ibmvnic_stat {
char name[ETH_GSTRING_LEN];
@@ -141,6 +143,29 @@ static const struct ibmvnic_stat ibmvnic_stats[] = {
{"internal_mac_rx_errors", IBMVNIC_STAT_OFF(internal_mac_rx_errors)},
};
+static int send_crq_init_complete(struct ibmvnic_adapter *adapter)
+{
+ union ibmvnic_crq crq;
+
+ memset(&crq, 0, sizeof(crq));
+ crq.generic.first = IBMVNIC_CRQ_INIT_CMD;
+ crq.generic.cmd = IBMVNIC_CRQ_INIT_COMPLETE;
+
+ return ibmvnic_send_crq(adapter, &crq);
+}
+
+static int send_version_xchg(struct ibmvnic_adapter *adapter)
+{
+ union ibmvnic_crq crq;
+
+ memset(&crq, 0, sizeof(crq));
+ crq.version_exchange.first = IBMVNIC_CRQ_CMD;
+ crq.version_exchange.cmd = VERSION_EXCHANGE;
+ crq.version_exchange.version = cpu_to_be16(ibmvnic_version);
+
+ return ibmvnic_send_crq(adapter, &crq);
+}
+
static long h_reg_sub_crq(unsigned long unit_address, unsigned long token,
unsigned long length, unsigned long *number,
unsigned long *irq)
@@ -209,12 +234,11 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter,
mutex_lock(&adapter->fw_lock);
adapter->fw_done_rc = 0;
reinit_completion(&adapter->fw_done);
- rc = send_request_map(adapter, ltb->addr,
- ltb->size, ltb->map_id);
+
+ rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id);
if (rc) {
- dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
- mutex_unlock(&adapter->fw_lock);
- return rc;
+ dev_err(dev, "send_request_map failed, rc = %d\n", rc);
+ goto out;
}
rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
@@ -222,20 +246,23 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter,
dev_err(dev,
"Long term map request aborted or timed out,rc = %d\n",
rc);
- dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
- mutex_unlock(&adapter->fw_lock);
- return rc;
+ goto out;
}
if (adapter->fw_done_rc) {
dev_err(dev, "Couldn't map long term buffer,rc = %d\n",
adapter->fw_done_rc);
+ rc = -1;
+ goto out;
+ }
+ rc = 0;
+out:
+ if (rc) {
dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
- mutex_unlock(&adapter->fw_lock);
- return -1;
+ ltb->buff = NULL;
}
mutex_unlock(&adapter->fw_lock);
- return 0;
+ return rc;
}
static void free_long_term_buff(struct ibmvnic_adapter *adapter,
@@ -255,14 +282,44 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter,
adapter->reset_reason != VNIC_RESET_TIMEOUT)
send_request_unmap(adapter, ltb->map_id);
dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
+ ltb->buff = NULL;
+ ltb->map_id = 0;
}
-static int reset_long_term_buff(struct ibmvnic_long_term_buff *ltb)
+static int reset_long_term_buff(struct ibmvnic_adapter *adapter,
+ struct ibmvnic_long_term_buff *ltb)
{
- if (!ltb->buff)
- return -EINVAL;
+ struct device *dev = &adapter->vdev->dev;
+ int rc;
memset(ltb->buff, 0, ltb->size);
+
+ mutex_lock(&adapter->fw_lock);
+ adapter->fw_done_rc = 0;
+
+ reinit_completion(&adapter->fw_done);
+ rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id);
+ if (rc) {
+ mutex_unlock(&adapter->fw_lock);
+ return rc;
+ }
+
+ rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
+ if (rc) {
+ dev_info(dev,
+ "Reset failed, long term map request timed out or aborted\n");
+ mutex_unlock(&adapter->fw_lock);
+ return rc;
+ }
+
+ if (adapter->fw_done_rc) {
+ dev_info(dev,
+ "Reset failed, attempting to free and reallocate buffer\n");
+ free_long_term_buff(adapter, ltb);
+ mutex_unlock(&adapter->fw_lock);
+ return alloc_long_term_buff(adapter, ltb, ltb->size);
+ }
+ mutex_unlock(&adapter->fw_lock);
return 0;
}
@@ -298,7 +355,14 @@ static void replenish_rx_pool(struct ibmvnic_adapter *adapter,
rx_scrq = adapter->rx_scrq[pool->index];
ind_bufp = &rx_scrq->ind_buf;
- for (i = 0; i < count; ++i) {
+
+ /* netdev_skb_alloc() could have failed after we saved a few skbs
+ * in the indir_buf and we would not have sent them to VIOS yet.
+ * To account for them, start the loop at ind_bufp->index rather
+ * than 0. If we pushed all the skbs to VIOS, ind_bufp->index will
+ * be 0.
+ */
+ for (i = ind_bufp->index; i < count; ++i) {
skb = netdev_alloc_skb(adapter->netdev, pool->buff_size);
if (!skb) {
dev_err(dev, "Couldn't replenish rx buff\n");
@@ -484,7 +548,8 @@ static int reset_rx_pools(struct ibmvnic_adapter *adapter)
rx_pool->size *
rx_pool->buff_size);
} else {
- rc = reset_long_term_buff(&rx_pool->long_term_buff);
+ rc = reset_long_term_buff(adapter,
+ &rx_pool->long_term_buff);
}
if (rc)
@@ -607,11 +672,12 @@ static int init_rx_pools(struct net_device *netdev)
return 0;
}
-static int reset_one_tx_pool(struct ibmvnic_tx_pool *tx_pool)
+static int reset_one_tx_pool(struct ibmvnic_adapter *adapter,
+ struct ibmvnic_tx_pool *tx_pool)
{
int rc, i;
- rc = reset_long_term_buff(&tx_pool->long_term_buff);
+ rc = reset_long_term_buff(adapter, &tx_pool->long_term_buff);
if (rc)
return rc;
@@ -638,10 +704,11 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter)
tx_scrqs = adapter->num_active_tx_pools;
for (i = 0; i < tx_scrqs; i++) {
- rc = reset_one_tx_pool(&adapter->tso_pool[i]);
+ ibmvnic_tx_scrq_clean_buffer(adapter, adapter->tx_scrq[i]);
+ rc = reset_one_tx_pool(adapter, &adapter->tso_pool[i]);
if (rc)
return rc;
- rc = reset_one_tx_pool(&adapter->tx_pool[i]);
+ rc = reset_one_tx_pool(adapter, &adapter->tx_pool[i]);
if (rc)
return rc;
}
@@ -734,8 +801,11 @@ static int init_tx_pools(struct net_device *netdev)
adapter->tso_pool = kcalloc(tx_subcrqs,
sizeof(struct ibmvnic_tx_pool), GFP_KERNEL);
- if (!adapter->tso_pool)
+ if (!adapter->tso_pool) {
+ kfree(adapter->tx_pool);
+ adapter->tx_pool = NULL;
return -1;
+ }
adapter->num_active_tx_pools = tx_subcrqs;
@@ -846,9 +916,10 @@ static const char *adapter_state_to_string(enum vnic_state state)
return "REMOVING";
case VNIC_REMOVED:
return "REMOVED";
- default:
- return "UNKNOWN";
+ case VNIC_DOWN:
+ return "DOWN";
}
+ return "UNKNOWN";
}
static int ibmvnic_login(struct net_device *netdev)
@@ -1180,6 +1251,11 @@ static int __ibmvnic_open(struct net_device *netdev)
netif_tx_start_all_queues(netdev);
+ if (prev_state == VNIC_CLOSED) {
+ for (i = 0; i < adapter->req_rx_queues; i++)
+ napi_schedule(&adapter->napi[i]);
+ }
+
adapter->state = VNIC_OPEN;
return rc;
}
@@ -1502,7 +1578,8 @@ static int create_hdr_descs(u8 hdr_field, u8 *hdr_data, int len, int *hdr_len,
/**
* build_hdr_descs_arr - build a header descriptor array
- * @txbuff: tx buffer
+ * @skb: tx socket buffer
+ * @indir_arr: indirect array
* @num_entries: number of descriptors to be sent
* @hdr_field: bit field determining which headers will be sent
*
@@ -1583,7 +1660,8 @@ static void ibmvnic_tx_scrq_clean_buffer(struct ibmvnic_adapter *adapter,
ind_bufp->index = 0;
if (atomic_sub_return(entries, &tx_scrq->used) <=
(adapter->req_tx_entries_per_subcrq / 2) &&
- __netif_subqueue_stopped(adapter->netdev, queue_num)) {
+ __netif_subqueue_stopped(adapter->netdev, queue_num) &&
+ !test_bit(0, &adapter->resetting)) {
netif_wake_subqueue(adapter->netdev, queue_num);
netdev_dbg(adapter->netdev, "Started queue %d\n",
queue_num);
@@ -1676,7 +1754,6 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
tx_send_failed++;
tx_dropped++;
ret = NETDEV_TX_OK;
- ibmvnic_tx_scrq_flush(adapter, tx_scrq);
goto out;
}
@@ -1946,9 +2023,10 @@ static const char *reset_reason_to_string(enum ibmvnic_reset_reason reason)
return "TIMEOUT";
case VNIC_RESET_CHANGE_PARAM:
return "CHANGE_PARAM";
- default:
- return "UNKNOWN";
+ case VNIC_RESET_PASSIVE_INIT:
+ return "PASSIVE_INIT";
}
+ return "UNKNOWN";
}
/*
@@ -2085,10 +2163,10 @@ static int do_reset(struct ibmvnic_adapter *adapter,
goto out;
}
- /* If the adapter was in PROBE state prior to the reset,
+ /* If the adapter was in PROBE or DOWN state prior to the reset,
* exit here.
*/
- if (reset_state == VNIC_PROBED) {
+ if (reset_state == VNIC_PROBED || reset_state == VNIC_DOWN) {
rc = 0;
goto out;
}
@@ -2214,10 +2292,10 @@ static int do_hard_reset(struct ibmvnic_adapter *adapter,
if (rc)
goto out;
- /* If the adapter was in PROBE state prior to the reset,
+ /* If the adapter was in PROBE or DOWN state prior to the reset,
* exit here.
*/
- if (reset_state == VNIC_PROBED)
+ if (reset_state == VNIC_PROBED || reset_state == VNIC_DOWN)
goto out;
rc = ibmvnic_login(netdev);
@@ -2270,11 +2348,82 @@ static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter)
return rwi;
}
+/**
+ * do_passive_init - complete probing when partner device is detected.
+ * @adapter: ibmvnic_adapter struct
+ *
+ * If the ibmvnic device does not have a partner device to communicate with at boot
+ * and that partner device comes online at a later time, this function is called
+ * to complete the initialization process of ibmvnic device.
+ * Caller is expected to hold rtnl_lock().
+ *
+ * Returns non-zero if sub-CRQs are not initialized properly leaving the device
+ * in the down state.
+ * Returns 0 upon success and the device is in PROBED state.
+ */
+
+static int do_passive_init(struct ibmvnic_adapter *adapter)
+{
+ unsigned long timeout = msecs_to_jiffies(30000);
+ struct net_device *netdev = adapter->netdev;
+ struct device *dev = &adapter->vdev->dev;
+ int rc;
+
+ netdev_dbg(netdev, "Partner device found, probing.\n");
+
+ adapter->state = VNIC_PROBING;
+ reinit_completion(&adapter->init_done);
+ adapter->init_done_rc = 0;
+ adapter->crq.active = true;
+
+ rc = send_crq_init_complete(adapter);
+ if (rc)
+ goto out;
+
+ rc = send_version_xchg(adapter);
+ if (rc)
+ netdev_dbg(adapter->netdev, "send_version_xchg failed, rc=%d\n", rc);
+
+ if (!wait_for_completion_timeout(&adapter->init_done, timeout)) {
+ dev_err(dev, "Initialization sequence timed out\n");
+ rc = -ETIMEDOUT;
+ goto out;
+ }
+
+ rc = init_sub_crqs(adapter);
+ if (rc) {
+ dev_err(dev, "Initialization of sub crqs failed, rc=%d\n", rc);
+ goto out;
+ }
+
+ rc = init_sub_crq_irqs(adapter);
+ if (rc) {
+ dev_err(dev, "Failed to initialize sub crq irqs\n, rc=%d", rc);
+ goto init_failed;
+ }
+
+ netdev->mtu = adapter->req_mtu - ETH_HLEN;
+ netdev->min_mtu = adapter->min_mtu - ETH_HLEN;
+ netdev->max_mtu = adapter->max_mtu - ETH_HLEN;
+
+ adapter->state = VNIC_PROBED;
+ netdev_dbg(netdev, "Probed successfully. Waiting for signal from partner device.\n");
+
+ return 0;
+
+init_failed:
+ release_sub_crqs(adapter, 1);
+out:
+ adapter->state = VNIC_DOWN;
+ return rc;
+}
+
static void __ibmvnic_reset(struct work_struct *work)
{
- struct ibmvnic_rwi *rwi;
struct ibmvnic_adapter *adapter;
bool saved_state = false;
+ struct ibmvnic_rwi *tmprwi;
+ struct ibmvnic_rwi *rwi;
unsigned long flags;
u32 reset_state;
int rc = 0;
@@ -2306,7 +2455,13 @@ static void __ibmvnic_reset(struct work_struct *work)
}
spin_unlock_irqrestore(&adapter->state_lock, flags);
- if (adapter->force_reset_recovery) {
+ if (rwi->reset_reason == VNIC_RESET_PASSIVE_INIT) {
+ rtnl_lock();
+ rc = do_passive_init(adapter);
+ rtnl_unlock();
+ if (!rc)
+ netif_carrier_on(adapter->netdev);
+ } else if (adapter->force_reset_recovery) {
/* Since we are doing a hard reset now, clear the
* failover_pending flag so we don't ignore any
* future MOBILITY or other resets.
@@ -2335,7 +2490,7 @@ static void __ibmvnic_reset(struct work_struct *work)
} else {
rc = do_reset(adapter, rwi, reset_state);
}
- kfree(rwi);
+ tmprwi = rwi;
adapter->last_reset_time = jiffies;
if (rc)
@@ -2343,8 +2498,23 @@ static void __ibmvnic_reset(struct work_struct *work)
rwi = get_next_rwi(adapter);
+ /*
+ * If there is another reset queued, free the previous rwi
+ * and process the new reset even if previous reset failed
+ * (the previous reset could have failed because of a fail
+ * over for instance, so process the fail over).
+ *
+ * If there are no resets queued and the previous reset failed,
+ * the adapter would be in an undefined state. So retry the
+ * previous reset as a hard reset.
+ */
+ if (rwi)
+ kfree(tmprwi);
+ else if (rc)
+ rwi = tmprwi;
+
if (rwi && (rwi->reset_reason == VNIC_RESET_FAILOVER ||
- rwi->reset_reason == VNIC_RESET_MOBILITY))
+ rwi->reset_reason == VNIC_RESET_MOBILITY || rc))
adapter->force_reset_recovery = true;
}
@@ -2402,8 +2572,7 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
goto err;
}
- list_for_each(entry, &adapter->rwi_list) {
- tmp = list_entry(entry, struct ibmvnic_rwi, list);
+ list_for_each_entry(tmp, &adapter->rwi_list, list) {
if (tmp->reset_reason == reason) {
netdev_dbg(netdev, "Skipping matching reset, reason=%s\n",
reset_reason_to_string(reason));
@@ -3140,6 +3309,7 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter, bool do_h_free)
netdev_dbg(adapter->netdev, "Releasing tx_scrq[%d]\n",
i);
+ ibmvnic_tx_scrq_clean_buffer(adapter, adapter->tx_scrq[i]);
if (adapter->tx_scrq[i]->irq) {
free_irq(adapter->tx_scrq[i]->irq,
adapter->tx_scrq[i]);
@@ -3213,7 +3383,7 @@ static int enable_scrq_irq(struct ibmvnic_adapter *adapter,
/* H_EOI would fail with rc = H_FUNCTION when running
* in XIVE mode which is expected, but not an error.
*/
- if (rc && rc != H_FUNCTION)
+ if (rc && (rc != H_FUNCTION))
dev_err(dev, "H_EOI FAILED irq 0x%llx. rc=%ld\n",
val, rc);
}
@@ -3776,18 +3946,6 @@ static int ibmvnic_send_crq_init(struct ibmvnic_adapter *adapter)
return 0;
}
-static int send_version_xchg(struct ibmvnic_adapter *adapter)
-{
- union ibmvnic_crq crq;
-
- memset(&crq, 0, sizeof(crq));
- crq.version_exchange.first = IBMVNIC_CRQ_CMD;
- crq.version_exchange.cmd = VERSION_EXCHANGE;
- crq.version_exchange.version = cpu_to_be16(ibmvnic_version);
-
- return ibmvnic_send_crq(adapter, &crq);
-}
-
struct vnic_login_client_data {
u8 type;
__be16 len;
@@ -3820,21 +3978,21 @@ static void vnic_add_client_data(struct ibmvnic_adapter *adapter,
vlcd->type = 1;
len = strlen(os_name) + 1;
vlcd->len = cpu_to_be16(len);
- strncpy(vlcd->name, os_name, len);
+ strscpy(vlcd->name, os_name, len);
vlcd = (struct vnic_login_client_data *)(vlcd->name + len);
/* Type 2 - LPAR name */
vlcd->type = 2;
len = strlen(utsname()->nodename) + 1;
vlcd->len = cpu_to_be16(len);
- strncpy(vlcd->name, utsname()->nodename, len);
+ strscpy(vlcd->name, utsname()->nodename, len);
vlcd = (struct vnic_login_client_data *)(vlcd->name + len);
/* Type 3 - device name */
vlcd->type = 3;
len = strlen(adapter->netdev->name) + 1;
vlcd->len = cpu_to_be16(len);
- strncpy(vlcd->name, adapter->netdev->name, len);
+ strscpy(vlcd->name, adapter->netdev->name, len);
}
static int send_login(struct ibmvnic_adapter *adapter)
@@ -4301,7 +4459,7 @@ static void handle_vpd_rsp(union ibmvnic_crq *crq,
complete:
if (adapter->fw_version[0] == '\0')
- strncpy((char *)adapter->fw_version, "N/A", 3 * sizeof(char));
+ strscpy((char *)adapter->fw_version, "N/A", sizeof(adapter->fw_version));
complete(&adapter->fw_done);
}
@@ -4907,7 +5065,12 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
complete(&adapter->init_done);
adapter->init_done_rc = -EIO;
}
- rc = ibmvnic_reset(adapter, VNIC_RESET_FAILOVER);
+
+ if (adapter->state == VNIC_DOWN)
+ rc = ibmvnic_reset(adapter, VNIC_RESET_PASSIVE_INIT);
+ else
+ rc = ibmvnic_reset(adapter, VNIC_RESET_FAILOVER);
+
if (rc && rc != -EBUSY) {
/* We were unable to schedule the failover
* reset either because the adapter was still
@@ -5330,6 +5493,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
struct ibmvnic_adapter *adapter;
struct net_device *netdev;
unsigned char *mac_addr_p;
+ bool init_success;
int rc;
dev_dbg(&dev->dev, "entering ibmvnic_probe for UA 0x%x\n",
@@ -5376,6 +5540,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
init_completion(&adapter->stats_done);
clear_bit(0, &adapter->resetting);
+ init_success = false;
do {
rc = init_crq_queue(adapter);
if (rc) {
@@ -5385,10 +5550,16 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
}
rc = ibmvnic_reset_init(adapter, false);
- if (rc && rc != EAGAIN)
- goto ibmvnic_init_fail;
} while (rc == EAGAIN);
+ /* We are ignoring the error from ibmvnic_reset_init() assuming that the
+ * partner is not ready. CRQ is not active. When the partner becomes
+ * ready, we will do the passive init reset.
+ */
+
+ if (!rc)
+ init_success = true;
+
rc = init_stats_buffers(adapter);
if (rc)
goto ibmvnic_init_fail;
@@ -5397,10 +5568,6 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
if (rc)
goto ibmvnic_stats_fail;
- netdev->mtu = adapter->req_mtu - ETH_HLEN;
- netdev->min_mtu = adapter->min_mtu - ETH_HLEN;
- netdev->max_mtu = adapter->max_mtu - ETH_HLEN;
-
rc = device_create_file(&dev->dev, &dev_attr_failover);
if (rc)
goto ibmvnic_dev_file_err;
@@ -5413,7 +5580,14 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
}
dev_info(&dev->dev, "ibmvnic registered\n");
- adapter->state = VNIC_PROBED;
+ if (init_success) {
+ adapter->state = VNIC_PROBED;
+ netdev->mtu = adapter->req_mtu - ETH_HLEN;
+ netdev->min_mtu = adapter->min_mtu - ETH_HLEN;
+ netdev->max_mtu = adapter->max_mtu - ETH_HLEN;
+ } else {
+ adapter->state = VNIC_DOWN;
+ }
adapter->wait_for_reset = false;
adapter->last_reset_time = jiffies;
diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
index c1d39a748546..22df602323bc 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.h
+++ b/drivers/net/ethernet/ibm/ibmvnic.h
@@ -851,14 +851,16 @@ enum vnic_state {VNIC_PROBING = 1,
VNIC_CLOSING,
VNIC_CLOSED,
VNIC_REMOVING,
- VNIC_REMOVED};
+ VNIC_REMOVED,
+ VNIC_DOWN};
enum ibmvnic_reset_reason {VNIC_RESET_FAILOVER = 1,
VNIC_RESET_MOBILITY,
VNIC_RESET_FATAL,
VNIC_RESET_NON_FATAL,
VNIC_RESET_TIMEOUT,
- VNIC_RESET_CHANGE_PARAM};
+ VNIC_RESET_CHANGE_PARAM,
+ VNIC_RESET_PASSIVE_INIT};
struct ibmvnic_rwi {
enum ibmvnic_reset_reason reset_reason;
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index c1d155690341..82744a7501c7 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -241,6 +241,7 @@ config I40E
tristate "Intel(R) Ethernet Controller XL710 Family support"
imply PTP_1588_CLOCK
depends on PCI
+ select AUXILIARY_BUS
help
This driver supports Intel(R) Ethernet Controller XL710 Family of
devices. For more information on how to identify your adapter, go
@@ -294,9 +295,11 @@ config ICE
tristate "Intel(R) Ethernet Connection E800 Series Support"
default n
depends on PCI_MSI
+ select AUXILIARY_BUS
select DIMLIB
select NET_DEVLINK
select PLDMFW
+ imply PTP_1588_CLOCK
help
This driver supports Intel(R) Ethernet Connection E800 Series of
devices. For more information on how to identify your adapter, go
diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c
index f8d78af76d7d..1b0958bd24f6 100644
--- a/drivers/net/ethernet/intel/e100.c
+++ b/drivers/net/ethernet/intel/e100.c
@@ -1395,7 +1395,7 @@ static int e100_phy_check_without_mii(struct nic *nic)
u8 phy_type;
int without_mii;
- phy_type = (nic->eeprom[eeprom_phy_iface] >> 8) & 0x0f;
+ phy_type = (le16_to_cpu(nic->eeprom[eeprom_phy_iface]) >> 8) & 0x0f;
switch (phy_type) {
case NoSuchPhy: /* Non-MII PHY; UNTESTED! */
@@ -1515,7 +1515,7 @@ static int e100_phy_init(struct nic *nic)
mdio_write(netdev, nic->mii.phy_id, MII_BMCR, bmcr);
} else if ((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&
(mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) &&
- (nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) {
+ (le16_to_cpu(nic->eeprom[eeprom_cnfg_mdix]) & eeprom_mdix_enabled))) {
/* enable/disable MDI/MDI-X auto-switching. */
mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG,
nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH);
@@ -2269,9 +2269,9 @@ static int e100_asf(struct nic *nic)
{
/* ASF can be enabled from eeprom */
return (nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1057) &&
- (nic->eeprom[eeprom_config_asf] & eeprom_asf) &&
- !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) &&
- ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE);
+ (le16_to_cpu(nic->eeprom[eeprom_config_asf]) & eeprom_asf) &&
+ !(le16_to_cpu(nic->eeprom[eeprom_config_asf]) & eeprom_gcl) &&
+ ((le16_to_cpu(nic->eeprom[eeprom_smbus_addr]) & 0xFF) != 0xFE);
}
static int e100_up(struct nic *nic)
@@ -2926,7 +2926,7 @@ static int e100_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Wol magic packet can be enabled from eeprom */
if ((nic->mac >= mac_82558_D101_A4) &&
- (nic->eeprom[eeprom_id] & eeprom_id_wol)) {
+ (le16_to_cpu(nic->eeprom[eeprom_id]) & eeprom_id_wol)) {
nic->flags |= wol_magic;
device_set_wakeup_enable(&pdev->dev, true);
}
diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
index f976e9daa3d8..3c51ee94fa00 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
@@ -513,7 +513,7 @@ static int e1000_set_eeprom(struct net_device *netdev,
memcpy(ptr, bytes, eeprom->len);
for (i = 0; i < last_word - first_word + 1; i++)
- eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
+ cpu_to_le16s(&eeprom_buff[i]);
ret_val = e1000_write_eeprom(hw, first_word,
last_word - first_word + 1, eeprom_buff);
diff --git a/drivers/net/ethernet/intel/e1000/e1000_hw.c b/drivers/net/ethernet/intel/e1000/e1000_hw.c
index 19cf36360933..1042e79a1397 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_hw.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_hw.c
@@ -2522,7 +2522,7 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
* turn it on. For compatibility with a TBI link
* partner, we will store bad packets. Some
* frames have an additional byte on the end and
- * will look like CRC errors to to the hardware.
+ * will look like CRC errors to the hardware.
*/
if (!hw->tbi_compatibility_on) {
hw->tbi_compatibility_on = true;
@@ -2723,7 +2723,7 @@ static void e1000_shift_out_mdi_bits(struct e1000_hw *hw, u32 data, u16 count)
* e1000_shift_in_mdi_bits - Shifts data bits in from the PHY
* @hw: Struct containing variables accessed by shared code
*
- * Bits are shifted in in MSB to LSB order.
+ * Bits are shifted in MSB to LSB order.
*/
static u16 e1000_shift_in_mdi_bits(struct e1000_hw *hw)
{
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 042de276e632..c2a109126c27 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -5245,7 +5245,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
if (!test_and_set_bit(__E1000_DISABLED, &adapter->flags))
pci_disable_device(pdev);
- /* Request a slot slot reset. */
+ /* Request a slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
}
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 590ad110d383..cf7b3887da1d 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -4639,7 +4639,7 @@ static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw)
* @hw: pointer to the HW structure
*
* ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
- * register, so the the bus width is hard coded.
+ * register, so the bus width is hard coded.
**/
static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
{
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 88e9035b75cf..757a54c39eef 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -5223,18 +5223,20 @@ static void e1000_watchdog_task(struct work_struct *work)
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);
+ if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
pcim_state = er32(STATUS);
-
- /* Checking if MAC exited DMoff state */
- if (!(pcim_state & E1000_STATUS_PCIM_STATE))
- e1000_phy_hw_reset(&adapter->hw);
+ 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 */
@@ -7118,7 +7120,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
pci_disable_device(pdev);
- /* Request a slot slot reset. */
+ /* Request a slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
}
@@ -7662,6 +7664,7 @@ err_flashmap:
err_ioremap:
free_netdev(netdev);
err_alloc_etherdev:
+ pci_disable_pcie_error_reporting(pdev);
pci_release_mem_regions(pdev);
err_pci_reg:
err_dma:
diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c
index 1db35b2c7750..0f0efee5fc8e 100644
--- a/drivers/net/ethernet/intel/e1000e/phy.c
+++ b/drivers/net/ethernet/intel/e1000e/phy.c
@@ -2978,7 +2978,7 @@ static u32 e1000_get_phy_addr_for_hv_page(u32 page)
* @data: pointer to the data to be read or written
* @read: determines if operation is read or write
*
- * Reads the PHY register at offset and stores the retreived information
+ * Reads the PHY register at offset and stores the retrieved information
* in data. Assumes semaphore already acquired. Note that the procedure
* to access these regs uses the address port and data port to read/write.
* These accesses done with PHY address 2 and without using pages.
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
index 9e3103fae723..adfa2768f024 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
@@ -1370,7 +1370,6 @@ static irqreturn_t fm10k_msix_mbx_pf(int __always_unused irq, void *data)
struct fm10k_hw *hw = &interface->hw;
struct fm10k_mbx_info *mbx = &hw->mbx;
u32 eicr;
- s32 err = 0;
/* unmask any set bits related to this interrupt */
eicr = fm10k_read_reg(hw, FM10K_EICR);
@@ -1386,15 +1385,16 @@ static irqreturn_t fm10k_msix_mbx_pf(int __always_unused irq, void *data)
/* service mailboxes */
if (fm10k_mbx_trylock(interface)) {
- err = mbx->ops.process(hw, mbx);
+ s32 err = mbx->ops.process(hw, mbx);
+
+ if (err == FM10K_ERR_RESET_REQUESTED)
+ set_bit(FM10K_FLAG_RESET_REQUESTED, interface->flags);
+
/* handle VFLRE events */
fm10k_iov_event(interface);
fm10k_mbx_unlock(interface);
}
- if (err == FM10K_ERR_RESET_REQUESTED)
- set_bit(FM10K_FLAG_RESET_REQUESTED, interface->flags);
-
/* if switch toggled state we should reset GLORTs */
if (eicr & FM10K_EICR_SWITCHNOTREADY) {
/* force link down for at least 4 seconds */
@@ -2227,6 +2227,7 @@ err_sw_init:
err_ioremap:
free_netdev(netdev);
err_alloc_netdev:
+ pci_disable_pcie_error_reporting(pdev);
pci_release_mem_regions(pdev);
err_pci_reg:
err_dma:
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 85d3dd3a3339..b9417dc0007c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -870,6 +870,8 @@ struct i40e_netdev_priv {
struct i40e_vsi *vsi;
};
+extern struct ida i40e_client_ida;
+
/* struct that defines an interrupt vector */
struct i40e_q_vector {
struct i40e_vsi *vsi;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_client.c b/drivers/net/ethernet/intel/i40e/i40e_client.c
index 32f3facbed1a..ea2bb0140a6e 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_client.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_client.c
@@ -8,10 +8,9 @@
#include "i40e.h"
#include "i40e_prototype.h"
-static const char i40e_client_interface_version_str[] = I40E_CLIENT_VERSION_STR;
-static struct i40e_client *registered_client;
static LIST_HEAD(i40e_devices);
static DEFINE_MUTEX(i40e_device_mutex);
+DEFINE_IDA(i40e_client_ida);
static int i40e_client_virtchnl_send(struct i40e_info *ldev,
struct i40e_client *client,
@@ -275,6 +274,57 @@ void i40e_client_update_msix_info(struct i40e_pf *pf)
cdev->lan_info.msix_entries = &pf->msix_entries[pf->iwarp_base_vector];
}
+static void i40e_auxiliary_dev_release(struct device *dev)
+{
+ struct i40e_auxiliary_device *i40e_aux_dev =
+ container_of(dev, struct i40e_auxiliary_device, aux_dev.dev);
+
+ ida_free(&i40e_client_ida, i40e_aux_dev->aux_dev.id);
+ kfree(i40e_aux_dev);
+}
+
+static int i40e_register_auxiliary_dev(struct i40e_info *ldev, const char *name)
+{
+ struct i40e_auxiliary_device *i40e_aux_dev;
+ struct pci_dev *pdev = ldev->pcidev;
+ struct auxiliary_device *aux_dev;
+ int ret;
+
+ i40e_aux_dev = kzalloc(sizeof(*i40e_aux_dev), GFP_KERNEL);
+ if (!i40e_aux_dev)
+ return -ENOMEM;
+
+ i40e_aux_dev->ldev = ldev;
+
+ aux_dev = &i40e_aux_dev->aux_dev;
+ aux_dev->name = name;
+ aux_dev->dev.parent = &pdev->dev;
+ aux_dev->dev.release = i40e_auxiliary_dev_release;
+ ldev->aux_dev = aux_dev;
+
+ ret = ida_alloc(&i40e_client_ida, GFP_KERNEL);
+ if (ret < 0) {
+ kfree(i40e_aux_dev);
+ return ret;
+ }
+ aux_dev->id = ret;
+
+ ret = auxiliary_device_init(aux_dev);
+ if (ret < 0) {
+ ida_free(&i40e_client_ida, aux_dev->id);
+ kfree(i40e_aux_dev);
+ return ret;
+ }
+
+ ret = auxiliary_device_add(aux_dev);
+ if (ret) {
+ auxiliary_device_uninit(aux_dev);
+ return ret;
+ }
+
+ return ret;
+}
+
/**
* i40e_client_add_instance - add a client instance struct to the instance list
* @pf: pointer to the board struct
@@ -286,9 +336,6 @@ static void i40e_client_add_instance(struct i40e_pf *pf)
struct netdev_hw_addr *mac = NULL;
struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
- if (!registered_client || pf->cinst)
- return;
-
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return;
@@ -308,11 +355,8 @@ static void i40e_client_add_instance(struct i40e_pf *pf)
cdev->lan_info.fw_build = pf->hw.aq.fw_build;
set_bit(__I40E_CLIENT_INSTANCE_NONE, &cdev->state);
- if (i40e_client_get_params(vsi, &cdev->lan_info.params)) {
- kfree(cdev);
- cdev = NULL;
- return;
- }
+ if (i40e_client_get_params(vsi, &cdev->lan_info.params))
+ goto free_cdev;
mac = list_first_entry(&cdev->lan_info.netdev->dev_addrs.list,
struct netdev_hw_addr, list);
@@ -321,10 +365,19 @@ static void i40e_client_add_instance(struct i40e_pf *pf)
else
dev_err(&pf->pdev->dev, "MAC address list is empty!\n");
- cdev->client = registered_client;
pf->cinst = cdev;
- i40e_client_update_msix_info(pf);
+ cdev->lan_info.msix_count = pf->num_iwarp_msix;
+ cdev->lan_info.msix_entries = &pf->msix_entries[pf->iwarp_base_vector];
+
+ if (i40e_register_auxiliary_dev(&cdev->lan_info, "iwarp"))
+ goto free_cdev;
+
+ return;
+
+free_cdev:
+ kfree(cdev);
+ pf->cinst = NULL;
}
/**
@@ -345,7 +398,7 @@ void i40e_client_del_instance(struct i40e_pf *pf)
**/
void i40e_client_subtask(struct i40e_pf *pf)
{
- struct i40e_client *client = registered_client;
+ struct i40e_client *client;
struct i40e_client_instance *cdev;
struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
int ret = 0;
@@ -359,9 +412,11 @@ void i40e_client_subtask(struct i40e_pf *pf)
test_bit(__I40E_CONFIG_BUSY, pf->state))
return;
- if (!client || !cdev)
+ if (!cdev || !cdev->client)
return;
+ client = cdev->client;
+
/* Here we handle client opens. If the client is down, and
* the netdev is registered, then open the client.
*/
@@ -423,16 +478,8 @@ int i40e_lan_add_device(struct i40e_pf *pf)
pf->hw.pf_id, pf->hw.bus.bus_id,
pf->hw.bus.device, pf->hw.bus.func);
- /* If a client has already been registered, we need to add an instance
- * of it to our new LAN device.
- */
- if (registered_client)
- i40e_client_add_instance(pf);
+ i40e_client_add_instance(pf);
- /* Since in some cases register may have happened before a device gets
- * added, we can schedule a subtask to go initiate the clients if
- * they can be launched at probe time.
- */
set_bit(__I40E_CLIENT_SERVICE_REQUESTED, pf->state);
i40e_service_event_schedule(pf);
@@ -449,9 +496,13 @@ out:
**/
int i40e_lan_del_device(struct i40e_pf *pf)
{
+ struct auxiliary_device *aux_dev = pf->cinst->lan_info.aux_dev;
struct i40e_device *ldev, *tmp;
int ret = -ENODEV;
+ auxiliary_device_delete(aux_dev);
+ auxiliary_device_uninit(aux_dev);
+
/* First, remove any client instance. */
i40e_client_del_instance(pf);
@@ -472,69 +523,6 @@ int i40e_lan_del_device(struct i40e_pf *pf)
}
/**
- * i40e_client_release - release client specific resources
- * @client: pointer to the registered client
- *
- **/
-static void i40e_client_release(struct i40e_client *client)
-{
- struct i40e_client_instance *cdev;
- struct i40e_device *ldev;
- struct i40e_pf *pf;
-
- mutex_lock(&i40e_device_mutex);
- list_for_each_entry(ldev, &i40e_devices, list) {
- pf = ldev->pf;
- cdev = pf->cinst;
- if (!cdev)
- continue;
-
- while (test_and_set_bit(__I40E_SERVICE_SCHED,
- pf->state))
- usleep_range(500, 1000);
-
- if (test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
- if (client->ops && client->ops->close)
- client->ops->close(&cdev->lan_info, client,
- false);
- i40e_client_release_qvlist(&cdev->lan_info);
- clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
-
- dev_warn(&pf->pdev->dev,
- "Client %s instance for PF id %d closed\n",
- client->name, pf->hw.pf_id);
- }
- /* delete the client instance */
- i40e_client_del_instance(pf);
- dev_info(&pf->pdev->dev, "Deleted client instance of Client %s\n",
- client->name);
- clear_bit(__I40E_SERVICE_SCHED, pf->state);
- }
- mutex_unlock(&i40e_device_mutex);
-}
-
-/**
- * i40e_client_prepare - prepare client specific resources
- * @client: pointer to the registered client
- *
- **/
-static void i40e_client_prepare(struct i40e_client *client)
-{
- struct i40e_device *ldev;
- struct i40e_pf *pf;
-
- mutex_lock(&i40e_device_mutex);
- list_for_each_entry(ldev, &i40e_devices, list) {
- pf = ldev->pf;
- i40e_client_add_instance(pf);
- /* Start the client subtask */
- set_bit(__I40E_CLIENT_SERVICE_REQUESTED, pf->state);
- i40e_service_event_schedule(pf);
- }
- mutex_unlock(&i40e_device_mutex);
-}
-
-/**
* i40e_client_virtchnl_send - TBD
* @ldev: pointer to L2 context
* @client: Client pointer
@@ -579,7 +567,7 @@ static int i40e_client_setup_qvlist(struct i40e_info *ldev,
u32 v_idx, i, reg_idx, reg;
ldev->qvlist_info = kzalloc(struct_size(ldev->qvlist_info, qv_info,
- qvlist_info->num_vectors - 1), GFP_KERNEL);
+ qvlist_info->num_vectors), GFP_KERNEL);
if (!ldev->qvlist_info)
return -ENOMEM;
ldev->qvlist_info->num_vectors = qvlist_info->num_vectors;
@@ -732,81 +720,34 @@ static int i40e_client_update_vsi_ctxt(struct i40e_info *ldev,
return err;
}
-/**
- * i40e_register_client - Register a i40e client driver with the L2 driver
- * @client: pointer to the i40e_client struct
- *
- * Returns 0 on success or non-0 on error
- **/
-int i40e_register_client(struct i40e_client *client)
+void i40e_client_device_register(struct i40e_info *ldev, struct i40e_client *client)
{
- int ret = 0;
-
- if (!client) {
- ret = -EIO;
- goto out;
- }
-
- if (strlen(client->name) == 0) {
- pr_info("i40e: Failed to register client with no name\n");
- ret = -EIO;
- goto out;
- }
-
- if (registered_client) {
- pr_info("i40e: Client %s has already been registered!\n",
- client->name);
- ret = -EEXIST;
- goto out;
- }
-
- if ((client->version.major != I40E_CLIENT_VERSION_MAJOR) ||
- (client->version.minor != I40E_CLIENT_VERSION_MINOR)) {
- pr_info("i40e: Failed to register client %s due to mismatched client interface version\n",
- client->name);
- pr_info("Client is using version: %02d.%02d.%02d while LAN driver supports %s\n",
- client->version.major, client->version.minor,
- client->version.build,
- i40e_client_interface_version_str);
- ret = -EIO;
- goto out;
- }
-
- registered_client = client;
-
- i40e_client_prepare(client);
+ struct i40e_pf *pf = ldev->pf;
- pr_info("i40e: Registered client %s\n", client->name);
-out:
- return ret;
+ pf->cinst->client = client;
+ set_bit(__I40E_CLIENT_SERVICE_REQUESTED, pf->state);
+ i40e_service_event_schedule(pf);
}
-EXPORT_SYMBOL(i40e_register_client);
+EXPORT_SYMBOL_GPL(i40e_client_device_register);
-/**
- * i40e_unregister_client - Unregister a i40e client driver with the L2 driver
- * @client: pointer to the i40e_client struct
- *
- * Returns 0 on success or non-0 on error
- **/
-int i40e_unregister_client(struct i40e_client *client)
+void i40e_client_device_unregister(struct i40e_info *ldev)
{
- int ret = 0;
+ struct i40e_pf *pf = ldev->pf;
+ struct i40e_client_instance *cdev = pf->cinst;
- if (registered_client != client) {
- pr_info("i40e: Client %s has not been registered\n",
- client->name);
- ret = -ENODEV;
- goto out;
+ if (!cdev)
+ return;
+
+ while (test_and_set_bit(__I40E_SERVICE_SCHED, pf->state))
+ usleep_range(500, 1000);
+
+ if (test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
+ cdev->client->ops->close(&cdev->lan_info, cdev->client, false);
+ clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
+ i40e_client_release_qvlist(&cdev->lan_info);
}
- registered_client = NULL;
- /* When a unregister request comes through we would have to send
- * a close for each of the client instances that were opened.
- * client_release function is called to handle this.
- */
- i40e_client_release(client);
- pr_info("i40e: Unregistered client %s\n", client->name);
-out:
- return ret;
+ pf->cinst->client = NULL;
+ clear_bit(__I40E_SERVICE_SCHED, pf->state);
}
-EXPORT_SYMBOL(i40e_unregister_client);
+EXPORT_SYMBOL_GPL(i40e_client_device_unregister);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index 67cb0b47416a..b4d3fed0d2f2 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -552,9 +552,9 @@ i40e_status i40e_aq_set_rss_key(struct i40e_hw *hw,
* ENDIF
*/
-/* macro to make the table lines short */
+/* macro to make the table lines short, use explicit indexing with [PTYPE] */
#define I40E_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\
- { PTYPE, \
+ [PTYPE] = { \
1, \
I40E_RX_PTYPE_OUTER_##OUTER_IP, \
I40E_RX_PTYPE_OUTER_##OUTER_IP_VER, \
@@ -565,16 +565,15 @@ i40e_status i40e_aq_set_rss_key(struct i40e_hw *hw,
I40E_RX_PTYPE_INNER_PROT_##I, \
I40E_RX_PTYPE_PAYLOAD_LAYER_##PL }
-#define I40E_PTT_UNUSED_ENTRY(PTYPE) \
- { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+#define I40E_PTT_UNUSED_ENTRY(PTYPE) [PTYPE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
/* shorter macros makes the table fit but are terse */
#define I40E_RX_PTYPE_NOF I40E_RX_PTYPE_NOT_FRAG
#define I40E_RX_PTYPE_FRG I40E_RX_PTYPE_FRAG
#define I40E_RX_PTYPE_INNER_PROT_TS I40E_RX_PTYPE_INNER_PROT_TIMESYNC
-/* Lookup table mapping the HW PTYPE to the bit field for decoding */
-struct i40e_rx_ptype_decoded i40e_ptype_lookup[] = {
+/* Lookup table mapping in the 8-bit HW PTYPE to the bit field for decoding */
+struct i40e_rx_ptype_decoded i40e_ptype_lookup[BIT(8)] = {
/* L2 Packet types */
I40E_PTT_UNUSED_ENTRY(0),
I40E_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
@@ -780,118 +779,7 @@ struct i40e_rx_ptype_decoded i40e_ptype_lookup[] = {
I40E_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
/* unused entries */
- I40E_PTT_UNUSED_ENTRY(154),
- I40E_PTT_UNUSED_ENTRY(155),
- I40E_PTT_UNUSED_ENTRY(156),
- I40E_PTT_UNUSED_ENTRY(157),
- I40E_PTT_UNUSED_ENTRY(158),
- I40E_PTT_UNUSED_ENTRY(159),
-
- I40E_PTT_UNUSED_ENTRY(160),
- I40E_PTT_UNUSED_ENTRY(161),
- I40E_PTT_UNUSED_ENTRY(162),
- I40E_PTT_UNUSED_ENTRY(163),
- I40E_PTT_UNUSED_ENTRY(164),
- I40E_PTT_UNUSED_ENTRY(165),
- I40E_PTT_UNUSED_ENTRY(166),
- I40E_PTT_UNUSED_ENTRY(167),
- I40E_PTT_UNUSED_ENTRY(168),
- I40E_PTT_UNUSED_ENTRY(169),
-
- I40E_PTT_UNUSED_ENTRY(170),
- I40E_PTT_UNUSED_ENTRY(171),
- I40E_PTT_UNUSED_ENTRY(172),
- I40E_PTT_UNUSED_ENTRY(173),
- I40E_PTT_UNUSED_ENTRY(174),
- I40E_PTT_UNUSED_ENTRY(175),
- I40E_PTT_UNUSED_ENTRY(176),
- I40E_PTT_UNUSED_ENTRY(177),
- I40E_PTT_UNUSED_ENTRY(178),
- I40E_PTT_UNUSED_ENTRY(179),
-
- I40E_PTT_UNUSED_ENTRY(180),
- I40E_PTT_UNUSED_ENTRY(181),
- I40E_PTT_UNUSED_ENTRY(182),
- I40E_PTT_UNUSED_ENTRY(183),
- I40E_PTT_UNUSED_ENTRY(184),
- I40E_PTT_UNUSED_ENTRY(185),
- I40E_PTT_UNUSED_ENTRY(186),
- I40E_PTT_UNUSED_ENTRY(187),
- I40E_PTT_UNUSED_ENTRY(188),
- I40E_PTT_UNUSED_ENTRY(189),
-
- I40E_PTT_UNUSED_ENTRY(190),
- I40E_PTT_UNUSED_ENTRY(191),
- I40E_PTT_UNUSED_ENTRY(192),
- I40E_PTT_UNUSED_ENTRY(193),
- I40E_PTT_UNUSED_ENTRY(194),
- I40E_PTT_UNUSED_ENTRY(195),
- I40E_PTT_UNUSED_ENTRY(196),
- I40E_PTT_UNUSED_ENTRY(197),
- I40E_PTT_UNUSED_ENTRY(198),
- I40E_PTT_UNUSED_ENTRY(199),
-
- I40E_PTT_UNUSED_ENTRY(200),
- I40E_PTT_UNUSED_ENTRY(201),
- I40E_PTT_UNUSED_ENTRY(202),
- I40E_PTT_UNUSED_ENTRY(203),
- I40E_PTT_UNUSED_ENTRY(204),
- I40E_PTT_UNUSED_ENTRY(205),
- I40E_PTT_UNUSED_ENTRY(206),
- I40E_PTT_UNUSED_ENTRY(207),
- I40E_PTT_UNUSED_ENTRY(208),
- I40E_PTT_UNUSED_ENTRY(209),
-
- I40E_PTT_UNUSED_ENTRY(210),
- I40E_PTT_UNUSED_ENTRY(211),
- I40E_PTT_UNUSED_ENTRY(212),
- I40E_PTT_UNUSED_ENTRY(213),
- I40E_PTT_UNUSED_ENTRY(214),
- I40E_PTT_UNUSED_ENTRY(215),
- I40E_PTT_UNUSED_ENTRY(216),
- I40E_PTT_UNUSED_ENTRY(217),
- I40E_PTT_UNUSED_ENTRY(218),
- I40E_PTT_UNUSED_ENTRY(219),
-
- I40E_PTT_UNUSED_ENTRY(220),
- I40E_PTT_UNUSED_ENTRY(221),
- I40E_PTT_UNUSED_ENTRY(222),
- I40E_PTT_UNUSED_ENTRY(223),
- I40E_PTT_UNUSED_ENTRY(224),
- I40E_PTT_UNUSED_ENTRY(225),
- I40E_PTT_UNUSED_ENTRY(226),
- I40E_PTT_UNUSED_ENTRY(227),
- I40E_PTT_UNUSED_ENTRY(228),
- I40E_PTT_UNUSED_ENTRY(229),
-
- I40E_PTT_UNUSED_ENTRY(230),
- I40E_PTT_UNUSED_ENTRY(231),
- I40E_PTT_UNUSED_ENTRY(232),
- I40E_PTT_UNUSED_ENTRY(233),
- I40E_PTT_UNUSED_ENTRY(234),
- I40E_PTT_UNUSED_ENTRY(235),
- I40E_PTT_UNUSED_ENTRY(236),
- I40E_PTT_UNUSED_ENTRY(237),
- I40E_PTT_UNUSED_ENTRY(238),
- I40E_PTT_UNUSED_ENTRY(239),
-
- I40E_PTT_UNUSED_ENTRY(240),
- I40E_PTT_UNUSED_ENTRY(241),
- I40E_PTT_UNUSED_ENTRY(242),
- I40E_PTT_UNUSED_ENTRY(243),
- I40E_PTT_UNUSED_ENTRY(244),
- I40E_PTT_UNUSED_ENTRY(245),
- I40E_PTT_UNUSED_ENTRY(246),
- I40E_PTT_UNUSED_ENTRY(247),
- I40E_PTT_UNUSED_ENTRY(248),
- I40E_PTT_UNUSED_ENTRY(249),
-
- I40E_PTT_UNUSED_ENTRY(250),
- I40E_PTT_UNUSED_ENTRY(251),
- I40E_PTT_UNUSED_ENTRY(252),
- I40E_PTT_UNUSED_ENTRY(253),
- I40E_PTT_UNUSED_ENTRY(254),
- I40E_PTT_UNUSED_ENTRY(255)
+ [154 ... 255] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
/**
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index ccd5b9486ea9..3e822bad4851 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -1262,8 +1262,7 @@ static int i40e_set_link_ksettings(struct net_device *netdev,
if (ethtool_link_ksettings_test_link_mode(&safe_ks,
supported,
Autoneg) &&
- hw->phy.link_info.phy_type !=
- I40E_PHY_TYPE_10GBASE_T) {
+ hw->phy.media_type != I40E_MEDIA_TYPE_BASET) {
netdev_info(netdev, "Autoneg cannot be disabled on this phy\n");
err = -EINVAL;
goto done;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 704e474879c5..861e59a350bd 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -32,7 +32,7 @@ static void i40e_vsi_reinit_locked(struct i40e_vsi *vsi);
static void i40e_handle_reset_warning(struct i40e_pf *pf, bool lock_acquired);
static int i40e_add_vsi(struct i40e_vsi *vsi);
static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi);
-static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit);
+static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit, bool lock_acquired);
static int i40e_setup_misc_vector(struct i40e_pf *pf);
static void i40e_determine_queue_usage(struct i40e_pf *pf);
static int i40e_setup_pf_filter_control(struct i40e_pf *pf);
@@ -8703,6 +8703,8 @@ int i40e_vsi_open(struct i40e_vsi *vsi)
dev_driver_string(&pf->pdev->dev),
dev_name(&pf->pdev->dev));
err = i40e_vsi_request_irq(vsi, int_name);
+ if (err)
+ goto err_setup_rx;
} else {
err = -EINVAL;
@@ -10569,7 +10571,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
#endif /* CONFIG_I40E_DCB */
if (!lock_acquired)
rtnl_lock();
- ret = i40e_setup_pf_switch(pf, reinit);
+ ret = i40e_setup_pf_switch(pf, reinit, true);
if (ret)
goto end_unlock;
@@ -14627,10 +14629,11 @@ int i40e_fetch_switch_configuration(struct i40e_pf *pf, bool printconfig)
* i40e_setup_pf_switch - Setup the HW switch on startup or after reset
* @pf: board private structure
* @reinit: if the Main VSI needs to re-initialized.
+ * @lock_acquired: indicates whether or not the lock has been acquired
*
* Returns 0 on success, negative value on failure
**/
-static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
+static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit, bool lock_acquired)
{
u16 flags = 0;
int ret;
@@ -14732,9 +14735,15 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
i40e_ptp_init(pf);
+ if (!lock_acquired)
+ rtnl_lock();
+
/* repopulate tunnel port filters */
udp_tunnel_nic_reset_ntf(pf->vsi[pf->lan_vsi]->netdev);
+ if (!lock_acquired)
+ rtnl_unlock();
+
return ret;
}
@@ -15528,7 +15537,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
}
#endif
- err = i40e_setup_pf_switch(pf, false);
+ err = i40e_setup_pf_switch(pf, false, false);
if (err) {
dev_info(&pdev->dev, "setup_pf_switch failed: %d\n", err);
goto err_vsis;
@@ -16270,6 +16279,7 @@ static void __exit i40e_exit_module(void)
{
pci_unregister_driver(&i40e_driver);
destroy_workqueue(i40e_wq);
+ ida_destroy(&i40e_client_ida);
i40e_dbg_exit();
}
module_exit(i40e_exit_module);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
index f1f6fc3744e9..7b971b205d36 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
@@ -11,13 +11,14 @@
* operate with the nanosecond field directly without fear of overflow.
*
* Much like the 82599, the update period is dependent upon the link speed:
- * At 40Gb link or no link, the period is 1.6ns.
- * At 10Gb link, the period is multiplied by 2. (3.2ns)
+ * At 40Gb, 25Gb, or no link, the period is 1.6ns.
+ * At 10Gb or 5Gb link, the period is multiplied by 2. (3.2ns)
* At 1Gb link, the period is multiplied by 20. (32ns)
* 1588 functionality is not supported at 100Mbps.
*/
#define I40E_PTP_40GB_INCVAL 0x0199999999ULL
#define I40E_PTP_10GB_INCVAL_MULT 2
+#define I40E_PTP_5GB_INCVAL_MULT 2
#define I40E_PTP_1GB_INCVAL_MULT 20
#define I40E_PRTTSYN_CTL1_TSYNTYPE_V1 BIT(I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT)
@@ -465,6 +466,9 @@ void i40e_ptp_set_increment(struct i40e_pf *pf)
case I40E_LINK_SPEED_10GB:
mult = I40E_PTP_10GB_INCVAL_MULT;
break;
+ case I40E_LINK_SPEED_5GB:
+ mult = I40E_PTP_5GB_INCVAL_MULT;
+ break;
case I40E_LINK_SPEED_1GB:
mult = I40E_PTP_1GB_INCVAL_MULT;
break;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index b883ab809df3..38eb8151ee9a 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -2298,7 +2298,6 @@ static int i40e_run_xdp(struct i40e_ring *rx_ring, struct xdp_buff *xdp)
struct bpf_prog *xdp_prog;
u32 act;
- rcu_read_lock();
xdp_prog = READ_ONCE(rx_ring->xdp_prog);
if (!xdp_prog)
@@ -2334,7 +2333,6 @@ out_failure:
break;
}
xdp_out:
- rcu_read_unlock();
return result;
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
index c81109a63e90..36a4ca1ffb1a 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -804,7 +804,6 @@ enum i40e_rx_l2_ptype {
};
struct i40e_rx_ptype_decoded {
- u32 ptype:8;
u32 known:1;
u32 outer_ip:1;
u32 outer_ip_ver:1;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
index 68f177a86403..e7e778ca074c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
@@ -153,7 +153,6 @@ static int i40e_run_xdp_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp)
struct bpf_prog *xdp_prog;
u32 act;
- rcu_read_lock();
/* NB! xdp_prog will always be !NULL, due to the fact that
* this path is enabled by setting an XDP program.
*/
@@ -164,7 +163,6 @@ static int i40e_run_xdp_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp)
err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
if (err)
goto out_failure;
- rcu_read_unlock();
return I40E_XDP_REDIR;
}
@@ -188,7 +186,6 @@ out_failure:
result = I40E_XDP_CONSUMED;
break;
}
- rcu_read_unlock();
return result;
}
diff --git a/drivers/net/ethernet/intel/iavf/iavf_common.c b/drivers/net/ethernet/intel/iavf/iavf_common.c
index 8547fc8fdfd6..e9cc7f6ddc46 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_common.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_common.c
@@ -522,9 +522,9 @@ enum iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 vsi_id,
* ENDIF
*/
-/* macro to make the table lines short */
+/* macro to make the table lines short, use explicit indexing with [PTYPE] */
#define IAVF_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\
- { PTYPE, \
+ [PTYPE] = { \
1, \
IAVF_RX_PTYPE_OUTER_##OUTER_IP, \
IAVF_RX_PTYPE_OUTER_##OUTER_IP_VER, \
@@ -535,16 +535,15 @@ enum iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 vsi_id,
IAVF_RX_PTYPE_INNER_PROT_##I, \
IAVF_RX_PTYPE_PAYLOAD_LAYER_##PL }
-#define IAVF_PTT_UNUSED_ENTRY(PTYPE) \
- { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+#define IAVF_PTT_UNUSED_ENTRY(PTYPE) [PTYPE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
/* shorter macros makes the table fit but are terse */
#define IAVF_RX_PTYPE_NOF IAVF_RX_PTYPE_NOT_FRAG
#define IAVF_RX_PTYPE_FRG IAVF_RX_PTYPE_FRAG
#define IAVF_RX_PTYPE_INNER_PROT_TS IAVF_RX_PTYPE_INNER_PROT_TIMESYNC
-/* Lookup table mapping the HW PTYPE to the bit field for decoding */
-struct iavf_rx_ptype_decoded iavf_ptype_lookup[] = {
+/* Lookup table mapping the 8-bit HW PTYPE to the bit field for decoding */
+struct iavf_rx_ptype_decoded iavf_ptype_lookup[BIT(8)] = {
/* L2 Packet types */
IAVF_PTT_UNUSED_ENTRY(0),
IAVF_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
@@ -750,118 +749,7 @@ struct iavf_rx_ptype_decoded iavf_ptype_lookup[] = {
IAVF_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
/* unused entries */
- IAVF_PTT_UNUSED_ENTRY(154),
- IAVF_PTT_UNUSED_ENTRY(155),
- IAVF_PTT_UNUSED_ENTRY(156),
- IAVF_PTT_UNUSED_ENTRY(157),
- IAVF_PTT_UNUSED_ENTRY(158),
- IAVF_PTT_UNUSED_ENTRY(159),
-
- IAVF_PTT_UNUSED_ENTRY(160),
- IAVF_PTT_UNUSED_ENTRY(161),
- IAVF_PTT_UNUSED_ENTRY(162),
- IAVF_PTT_UNUSED_ENTRY(163),
- IAVF_PTT_UNUSED_ENTRY(164),
- IAVF_PTT_UNUSED_ENTRY(165),
- IAVF_PTT_UNUSED_ENTRY(166),
- IAVF_PTT_UNUSED_ENTRY(167),
- IAVF_PTT_UNUSED_ENTRY(168),
- IAVF_PTT_UNUSED_ENTRY(169),
-
- IAVF_PTT_UNUSED_ENTRY(170),
- IAVF_PTT_UNUSED_ENTRY(171),
- IAVF_PTT_UNUSED_ENTRY(172),
- IAVF_PTT_UNUSED_ENTRY(173),
- IAVF_PTT_UNUSED_ENTRY(174),
- IAVF_PTT_UNUSED_ENTRY(175),
- IAVF_PTT_UNUSED_ENTRY(176),
- IAVF_PTT_UNUSED_ENTRY(177),
- IAVF_PTT_UNUSED_ENTRY(178),
- IAVF_PTT_UNUSED_ENTRY(179),
-
- IAVF_PTT_UNUSED_ENTRY(180),
- IAVF_PTT_UNUSED_ENTRY(181),
- IAVF_PTT_UNUSED_ENTRY(182),
- IAVF_PTT_UNUSED_ENTRY(183),
- IAVF_PTT_UNUSED_ENTRY(184),
- IAVF_PTT_UNUSED_ENTRY(185),
- IAVF_PTT_UNUSED_ENTRY(186),
- IAVF_PTT_UNUSED_ENTRY(187),
- IAVF_PTT_UNUSED_ENTRY(188),
- IAVF_PTT_UNUSED_ENTRY(189),
-
- IAVF_PTT_UNUSED_ENTRY(190),
- IAVF_PTT_UNUSED_ENTRY(191),
- IAVF_PTT_UNUSED_ENTRY(192),
- IAVF_PTT_UNUSED_ENTRY(193),
- IAVF_PTT_UNUSED_ENTRY(194),
- IAVF_PTT_UNUSED_ENTRY(195),
- IAVF_PTT_UNUSED_ENTRY(196),
- IAVF_PTT_UNUSED_ENTRY(197),
- IAVF_PTT_UNUSED_ENTRY(198),
- IAVF_PTT_UNUSED_ENTRY(199),
-
- IAVF_PTT_UNUSED_ENTRY(200),
- IAVF_PTT_UNUSED_ENTRY(201),
- IAVF_PTT_UNUSED_ENTRY(202),
- IAVF_PTT_UNUSED_ENTRY(203),
- IAVF_PTT_UNUSED_ENTRY(204),
- IAVF_PTT_UNUSED_ENTRY(205),
- IAVF_PTT_UNUSED_ENTRY(206),
- IAVF_PTT_UNUSED_ENTRY(207),
- IAVF_PTT_UNUSED_ENTRY(208),
- IAVF_PTT_UNUSED_ENTRY(209),
-
- IAVF_PTT_UNUSED_ENTRY(210),
- IAVF_PTT_UNUSED_ENTRY(211),
- IAVF_PTT_UNUSED_ENTRY(212),
- IAVF_PTT_UNUSED_ENTRY(213),
- IAVF_PTT_UNUSED_ENTRY(214),
- IAVF_PTT_UNUSED_ENTRY(215),
- IAVF_PTT_UNUSED_ENTRY(216),
- IAVF_PTT_UNUSED_ENTRY(217),
- IAVF_PTT_UNUSED_ENTRY(218),
- IAVF_PTT_UNUSED_ENTRY(219),
-
- IAVF_PTT_UNUSED_ENTRY(220),
- IAVF_PTT_UNUSED_ENTRY(221),
- IAVF_PTT_UNUSED_ENTRY(222),
- IAVF_PTT_UNUSED_ENTRY(223),
- IAVF_PTT_UNUSED_ENTRY(224),
- IAVF_PTT_UNUSED_ENTRY(225),
- IAVF_PTT_UNUSED_ENTRY(226),
- IAVF_PTT_UNUSED_ENTRY(227),
- IAVF_PTT_UNUSED_ENTRY(228),
- IAVF_PTT_UNUSED_ENTRY(229),
-
- IAVF_PTT_UNUSED_ENTRY(230),
- IAVF_PTT_UNUSED_ENTRY(231),
- IAVF_PTT_UNUSED_ENTRY(232),
- IAVF_PTT_UNUSED_ENTRY(233),
- IAVF_PTT_UNUSED_ENTRY(234),
- IAVF_PTT_UNUSED_ENTRY(235),
- IAVF_PTT_UNUSED_ENTRY(236),
- IAVF_PTT_UNUSED_ENTRY(237),
- IAVF_PTT_UNUSED_ENTRY(238),
- IAVF_PTT_UNUSED_ENTRY(239),
-
- IAVF_PTT_UNUSED_ENTRY(240),
- IAVF_PTT_UNUSED_ENTRY(241),
- IAVF_PTT_UNUSED_ENTRY(242),
- IAVF_PTT_UNUSED_ENTRY(243),
- IAVF_PTT_UNUSED_ENTRY(244),
- IAVF_PTT_UNUSED_ENTRY(245),
- IAVF_PTT_UNUSED_ENTRY(246),
- IAVF_PTT_UNUSED_ENTRY(247),
- IAVF_PTT_UNUSED_ENTRY(248),
- IAVF_PTT_UNUSED_ENTRY(249),
-
- IAVF_PTT_UNUSED_ENTRY(250),
- IAVF_PTT_UNUSED_ENTRY(251),
- IAVF_PTT_UNUSED_ENTRY(252),
- IAVF_PTT_UNUSED_ENTRY(253),
- IAVF_PTT_UNUSED_ENTRY(254),
- IAVF_PTT_UNUSED_ENTRY(255)
+ [154 ... 255] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
/**
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index e612c24fa384..44bafedd09f2 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -3798,6 +3798,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_ioremap:
free_netdev(netdev);
err_alloc_etherdev:
+ pci_disable_pcie_error_reporting(pdev);
pci_release_regions(pdev);
err_pci_reg:
err_dma:
diff --git a/drivers/net/ethernet/intel/iavf/iavf_type.h b/drivers/net/ethernet/intel/iavf/iavf_type.h
index de9fda78b43a..9f1f523807c4 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_type.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_type.h
@@ -370,7 +370,6 @@ enum iavf_rx_l2_ptype {
};
struct iavf_rx_ptype_decoded {
- u32 ptype:8;
u32 known:1;
u32 outer_ip:1;
u32 outer_ip_ver:1;
diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile
index 07fe857e9e3a..4f538cdf42c1 100644
--- a/drivers/net/ethernet/intel/ice/Makefile
+++ b/drivers/net/ethernet/intel/ice/Makefile
@@ -22,12 +22,14 @@ ice-y := ice_main.o \
ice_ethtool_fdir.o \
ice_flex_pipe.o \
ice_flow.o \
+ ice_idc.o \
ice_devlink.o \
ice_fw_update.o \
ice_lag.o \
ice_ethtool.o
ice-$(CONFIG_PCI_IOV) += ice_virtchnl_allowlist.o
ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o ice_sriov.o ice_virtchnl_fdir.o
+ice-$(CONFIG_PTP_1588_CLOCK) += ice_ptp.o ice_ptp_hw.o
ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 2924c67567b8..a450343fbb92 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -34,6 +34,7 @@
#include <linux/if_bridge.h>
#include <linux/ctype.h>
#include <linux/bpf.h>
+#include <linux/auxiliary_bus.h>
#include <linux/avf/virtchnl.h>
#include <linux/cpu_rmap.h>
#include <linux/dim.h>
@@ -55,8 +56,10 @@
#include "ice_switch.h"
#include "ice_common.h"
#include "ice_sched.h"
+#include "ice_idc_int.h"
#include "ice_virtchnl_pf.h"
#include "ice_sriov.h"
+#include "ice_ptp.h"
#include "ice_fdir.h"
#include "ice_xsk.h"
#include "ice_arfs.h"
@@ -72,12 +75,15 @@
#define ICE_DFLT_TRAFFIC_CLASS BIT(0)
#define ICE_INT_NAME_STR_LEN (IFNAMSIZ + 16)
-#define ICE_AQ_LEN 64
+#define ICE_AQ_LEN 192
#define ICE_MBXSQ_LEN 64
+#define ICE_SBQ_LEN 64
#define ICE_MIN_LAN_TXRX_MSIX 1
#define ICE_MIN_LAN_OICR_MSIX 1
#define ICE_MIN_MSIX (ICE_MIN_LAN_TXRX_MSIX + ICE_MIN_LAN_OICR_MSIX)
#define ICE_FDIR_MSIX 2
+#define ICE_RDMA_NUM_AEQ_MSIX 4
+#define ICE_MIN_RDMA_MSIX 2
#define ICE_NO_VSI 0xffff
#define ICE_VSI_MAP_CONTIG 0
#define ICE_VSI_MAP_SCATTER 1
@@ -88,8 +94,9 @@
#define ICE_MAX_LG_RSS_QS 256
#define ICE_RES_VALID_BIT 0x8000
#define ICE_RES_MISC_VEC_ID (ICE_RES_VALID_BIT - 1)
+#define ICE_RES_RDMA_VEC_ID (ICE_RES_MISC_VEC_ID - 1)
/* All VF control VSIs share the same IRQ, so assign a unique ID for them */
-#define ICE_RES_VF_CTRL_VEC_ID (ICE_RES_MISC_VEC_ID - 1)
+#define ICE_RES_VF_CTRL_VEC_ID (ICE_RES_RDMA_VEC_ID - 1)
#define ICE_INVAL_Q_INDEX 0xffff
#define ICE_INVAL_VFID 256
@@ -203,9 +210,9 @@ enum ice_pf_state {
ICE_NEEDS_RESTART,
ICE_PREPARED_FOR_RESET, /* set by driver when prepared */
ICE_RESET_OICR_RECV, /* set by driver after rcv reset OICR */
- ICE_PFR_REQ, /* set by driver and peers */
- ICE_CORER_REQ, /* set by driver and peers */
- ICE_GLOBR_REQ, /* set by driver and peers */
+ ICE_PFR_REQ, /* set by driver */
+ ICE_CORER_REQ, /* set by driver */
+ ICE_GLOBR_REQ, /* set by driver */
ICE_CORER_RECV, /* set by OICR handler */
ICE_GLOBR_RECV, /* set by OICR handler */
ICE_EMPR_RECV, /* set by OICR handler */
@@ -222,6 +229,7 @@ enum ice_pf_state {
ICE_STATE_NOMINAL_CHECK_BITS,
ICE_ADMINQ_EVENT_PENDING,
ICE_MAILBOXQ_EVENT_PENDING,
+ ICE_SIDEBANDQ_EVENT_PENDING,
ICE_MDD_EVENT_PENDING,
ICE_VFLR_EVENT_PENDING,
ICE_FLTR_OVERFLOW_PROMISC,
@@ -332,6 +340,7 @@ struct ice_vsi {
u16 req_rxq; /* User requested Rx queues */
u16 num_rx_desc;
u16 num_tx_desc;
+ u16 qset_handle[ICE_MAX_TRAFFIC_CLASS];
struct ice_tc_cfg tc_cfg;
struct bpf_prog *xdp_prog;
struct ice_ring **xdp_rings; /* XDP ring array */
@@ -374,17 +383,22 @@ struct ice_q_vector {
enum ice_pf_flags {
ICE_FLAG_FLTR_SYNC,
+ ICE_FLAG_RDMA_ENA,
ICE_FLAG_RSS_ENA,
ICE_FLAG_SRIOV_ENA,
ICE_FLAG_SRIOV_CAPABLE,
ICE_FLAG_DCB_CAPABLE,
ICE_FLAG_DCB_ENA,
ICE_FLAG_FD_ENA,
+ ICE_FLAG_PTP_SUPPORTED, /* PTP is supported by NVM */
+ ICE_FLAG_PTP, /* PTP is enabled by software */
+ ICE_FLAG_AUX_ENA,
ICE_FLAG_ADV_FEATURES,
ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA,
ICE_FLAG_TOTAL_PORT_SHUTDOWN_ENA,
ICE_FLAG_NO_MEDIA,
ICE_FLAG_FW_LLDP_AGENT,
+ ICE_FLAG_MOD_POWER_UNSUPPORTED,
ICE_FLAG_ETHTOOL_CTXT, /* set when ethtool holds RTNL lock */
ICE_FLAG_LEGACY_RX,
ICE_FLAG_VF_TRUE_PROMISC_ENA,
@@ -440,12 +454,17 @@ struct ice_pf {
struct mutex sw_mutex; /* lock for protecting VSI alloc flow */
struct mutex tc_mutex; /* lock to protect TC changes */
u32 msg_enable;
+ struct ice_ptp ptp;
+ u16 num_rdma_msix; /* Total MSIX vectors for RDMA driver */
+ u16 rdma_base_vector;
/* spinlock to protect the AdminQ wait list */
spinlock_t aq_wait_lock;
struct hlist_head aq_wait_list;
wait_queue_head_t aq_wait_queue;
+ wait_queue_head_t reset_wait_queue;
+
u32 hw_csum_rx_error;
u16 oicr_idx; /* Other interrupt cause MSIX vector index */
u16 num_avail_sw_msix; /* remaining MSIX SW vectors left unclaimed */
@@ -472,6 +491,8 @@ struct ice_pf {
unsigned long tx_timeout_last_recovery;
u32 tx_timeout_recovery_level;
char int_name[ICE_INT_NAME_STR_LEN];
+ struct auxiliary_device *adev;
+ int aux_idx;
u32 sw_int_count;
__le64 nvm_phy_type_lo; /* NVM PHY type low */
@@ -638,6 +659,9 @@ int ice_get_rss_key(struct ice_vsi *vsi, u8 *seed);
void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size);
int ice_schedule_reset(struct ice_pf *pf, enum ice_reset_req reset);
void ice_print_link_msg(struct ice_vsi *vsi, bool isup);
+int ice_plug_aux_dev(struct ice_pf *pf);
+void ice_unplug_aux_dev(struct ice_pf *pf);
+int ice_init_rdma(struct ice_pf *pf);
const char *ice_stat_str(enum ice_status stat_err);
const char *ice_aq_str(enum ice_aq_err aq_err);
bool ice_is_wol_supported(struct ice_hw *hw);
@@ -662,4 +686,25 @@ int ice_open_internal(struct net_device *netdev);
int ice_stop(struct net_device *netdev);
void ice_service_task_schedule(struct ice_pf *pf);
+/**
+ * ice_set_rdma_cap - enable RDMA support
+ * @pf: PF struct
+ */
+static inline void ice_set_rdma_cap(struct ice_pf *pf)
+{
+ if (pf->hw.func_caps.common_cap.rdma && pf->num_rdma_msix) {
+ set_bit(ICE_FLAG_RDMA_ENA, pf->flags);
+ ice_plug_aux_dev(pf);
+ }
+}
+
+/**
+ * ice_clear_rdma_cap - disable RDMA support
+ * @pf: PF struct
+ */
+static inline void ice_clear_rdma_cap(struct ice_pf *pf)
+{
+ ice_unplug_aux_dev(pf);
+ clear_bit(ICE_FLAG_RDMA_ENA, pf->flags);
+}
#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 5cdfe406af84..21b4c7cd6f05 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -108,6 +108,7 @@ struct ice_aqc_list_caps_elem {
#define ICE_AQC_CAPS_TXQS 0x0042
#define ICE_AQC_CAPS_MSIX 0x0043
#define ICE_AQC_CAPS_FD 0x0045
+#define ICE_AQC_CAPS_1588 0x0046
#define ICE_AQC_CAPS_MAX_MTU 0x0047
#define ICE_AQC_CAPS_NVM_VER 0x0048
#define ICE_AQC_CAPS_PENDING_NVM_VER 0x0049
@@ -115,6 +116,7 @@ struct ice_aqc_list_caps_elem {
#define ICE_AQC_CAPS_PENDING_OROM_VER 0x004B
#define ICE_AQC_CAPS_NET_VER 0x004C
#define ICE_AQC_CAPS_PENDING_NET_VER 0x004D
+#define ICE_AQC_CAPS_RDMA 0x0051
#define ICE_AQC_CAPS_NVM_MGMT 0x0080
u8 major_ver;
@@ -1122,7 +1124,9 @@ struct ice_aqc_get_link_status_data {
#define ICE_AQ_LINK_TOPO_UNDRUTIL_PRT BIT(5)
#define ICE_AQ_LINK_TOPO_UNDRUTIL_MEDIA BIT(6)
#define ICE_AQ_LINK_TOPO_UNSUPP_MEDIA BIT(7)
- u8 reserved1;
+ u8 link_cfg_err;
+#define ICE_AQ_LINK_MODULE_POWER_UNSUPPORTED BIT(5)
+#define ICE_AQ_LINK_INVAL_MAX_POWER_LIMIT BIT(7)
u8 link_info;
#define ICE_AQ_LINK_UP BIT(0) /* Link Status */
#define ICE_AQ_LINK_FAULT BIT(1)
@@ -1165,7 +1169,7 @@ struct ice_aqc_get_link_status_data {
#define ICE_AQ_CFG_PACING_TYPE_FIXED ICE_AQ_CFG_PACING_TYPE_M
/* External Device Power Ability */
u8 power_desc;
-#define ICE_AQ_PWR_CLASS_M 0x3
+#define ICE_AQ_PWR_CLASS_M 0x3F
#define ICE_AQ_LINK_PWR_BASET_LOW_HIGH 0
#define ICE_AQ_LINK_PWR_BASET_HIGH 1
#define ICE_AQ_LINK_PWR_QSFP_CLASS_1 0
@@ -1608,6 +1612,15 @@ struct ice_aqc_get_set_rss_lut {
__le32 addr_low;
};
+/* Sideband Control Interface Commands */
+/* Neighbor Device Request (indirect 0x0C00); also used for the response. */
+struct ice_aqc_neigh_dev_req {
+ __le16 sb_data_len;
+ u8 reserved[6];
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
/* Add Tx LAN Queues (indirect 0x0C30) */
struct ice_aqc_add_txqs {
u8 num_qgrps;
@@ -1684,6 +1697,36 @@ struct ice_aqc_dis_txq_item {
__le16 q_id[];
} __packed;
+/* Add Tx RDMA Queue Set (indirect 0x0C33) */
+struct ice_aqc_add_rdma_qset {
+ u8 num_qset_grps;
+ u8 reserved[7];
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
+/* This is the descriptor of each Qset entry for the Add Tx RDMA Queue Set
+ * command (0x0C33). Only used within struct ice_aqc_add_rdma_qset.
+ */
+struct ice_aqc_add_tx_rdma_qset_entry {
+ __le16 tx_qset_id;
+ u8 rsvd[2];
+ __le32 qset_teid;
+ struct ice_aqc_txsched_elem info;
+};
+
+/* The format of the command buffer for Add Tx RDMA Queue Set(0x0C33)
+ * is an array of the following structs. Please note that the length of
+ * each struct ice_aqc_add_rdma_qset is variable due to the variable
+ * number of queues in each group!
+ */
+struct ice_aqc_add_rdma_qset_data {
+ __le32 parent_teid;
+ __le16 num_qsets;
+ u8 rsvd[2];
+ struct ice_aqc_add_tx_rdma_qset_entry rdma_qsets[];
+};
+
/* Configure Firmware Logging Command (indirect 0xFF09)
* Logging Information Read Response (indirect 0xFF10)
* Note: The 0xFF10 command has no input parameters.
@@ -1810,6 +1853,30 @@ struct ice_aqc_get_pkg_info_resp {
struct ice_aqc_get_pkg_info pkg_info[];
};
+/* Driver Shared Parameters (direct, 0x0C90) */
+struct ice_aqc_driver_shared_params {
+ u8 set_or_get_op;
+#define ICE_AQC_DRIVER_PARAM_OP_MASK BIT(0)
+#define ICE_AQC_DRIVER_PARAM_SET 0
+#define ICE_AQC_DRIVER_PARAM_GET 1
+ u8 param_indx;
+#define ICE_AQC_DRIVER_PARAM_MAX_IDX 15
+ u8 rsvd[2];
+ __le32 param_val;
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
+enum ice_aqc_driver_params {
+ /* OS clock index for PTP timer Domain 0 */
+ ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR0 = 0,
+ /* OS clock index for PTP timer Domain 1 */
+ ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR1,
+
+ /* Add new parameters above */
+ ICE_AQC_DRIVER_PARAM_MAX = 16,
+};
+
/* Lan Queue Overflow Event (direct, 0x1001) */
struct ice_aqc_event_lan_overflow {
__le32 prtdcb_ruptq;
@@ -1878,13 +1945,16 @@ struct ice_aq_desc {
struct ice_aqc_lldp_filter_ctrl lldp_filter_ctrl;
struct ice_aqc_get_set_rss_lut get_set_rss_lut;
struct ice_aqc_get_set_rss_key get_set_rss_key;
+ struct ice_aqc_neigh_dev_req neigh_dev;
struct ice_aqc_add_txqs add_txqs;
struct ice_aqc_dis_txqs dis_txqs;
+ struct ice_aqc_add_rdma_qset add_rdma_qset;
struct ice_aqc_add_get_update_free_vsi vsi_cmd;
struct ice_aqc_add_update_free_vsi_resp add_update_free_vsi_res;
struct ice_aqc_fw_logging fw_logging;
struct ice_aqc_get_clear_fw_log get_clear_fw_log;
struct ice_aqc_download_pkg download_pkg;
+ struct ice_aqc_driver_shared_params drv_shared_params;
struct ice_aqc_set_mac_lb set_mac_lb;
struct ice_aqc_alloc_free_res_cmd sw_res_ctrl;
struct ice_aqc_set_mac_cfg set_mac_cfg;
@@ -2025,15 +2095,21 @@ enum ice_adminq_opc {
ice_aqc_opc_get_rss_key = 0x0B04,
ice_aqc_opc_get_rss_lut = 0x0B05,
+ /* Sideband Control Interface commands */
+ ice_aqc_opc_neighbour_device_request = 0x0C00,
+
/* Tx queue handling commands/events */
ice_aqc_opc_add_txqs = 0x0C30,
ice_aqc_opc_dis_txqs = 0x0C31,
+ ice_aqc_opc_add_rdma_qset = 0x0C33,
/* package commands */
ice_aqc_opc_download_pkg = 0x0C40,
ice_aqc_opc_update_pkg = 0x0C42,
ice_aqc_opc_get_pkg_info_list = 0x0C43,
+ ice_aqc_opc_driver_shared_params = 0x0C90,
+
/* Standalone Commands/Events */
ice_aqc_opc_event_lan_overflow = 0x1001,
diff --git a/drivers/net/ethernet/intel/ice/ice_arfs.h b/drivers/net/ethernet/intel/ice/ice_arfs.h
index f39cd16403ed..80ed76f0cace 100644
--- a/drivers/net/ethernet/intel/ice/ice_arfs.h
+++ b/drivers/net/ethernet/intel/ice/ice_arfs.h
@@ -52,12 +52,12 @@ bool
ice_is_arfs_using_perfect_flow(struct ice_hw *hw,
enum ice_fltr_ptype flow_type);
#else
-#define ice_sync_arfs_fltrs(pf) do {} while (0)
-#define ice_init_arfs(vsi) do {} while (0)
-#define ice_clear_arfs(vsi) do {} while (0)
-#define ice_remove_arfs(pf) do {} while (0)
-#define ice_free_cpu_rx_rmap(vsi) do {} while (0)
-#define ice_rebuild_arfs(pf) do {} while (0)
+static inline void ice_clear_arfs(struct ice_vsi *vsi) { }
+static inline void ice_free_cpu_rx_rmap(struct ice_vsi *vsi) { }
+static inline void ice_init_arfs(struct ice_vsi *vsi) { }
+static inline void ice_sync_arfs_fltrs(struct ice_pf *pf) { }
+static inline void ice_remove_arfs(struct ice_pf *pf) { }
+static inline void ice_rebuild_arfs(struct ice_pf *pf) { }
static inline int ice_set_cpu_rx_rmap(struct ice_vsi __always_unused *vsi)
{
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index 5985a7e5ca8a..c36057efc7ae 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -287,6 +287,15 @@ ice_setup_tx_ctx(struct ice_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q)
/* make sure the context is associated with the right VSI */
tlan_ctx->src_vsi = ice_get_hw_vsi_num(hw, vsi->idx);
+ /* Restrict Tx timestamps to the PF VSI */
+ switch (vsi->type) {
+ case ICE_VSI_PF:
+ tlan_ctx->tsyn_ena = 1;
+ break;
+ default:
+ break;
+ }
+
tlan_ctx->tso_ena = ICE_TX_LEGACY;
tlan_ctx->tso_qnum = pf_q;
@@ -319,11 +328,9 @@ static unsigned int ice_rx_offset(struct ice_ring *rx_ring)
*
* Configure the Rx descriptor ring in RLAN context.
*/
-int ice_setup_rx_ctx(struct ice_ring *ring)
+static int ice_setup_rx_ctx(struct ice_ring *ring)
{
- struct device *dev = ice_pf_to_dev(ring->vsi->back);
int chain_len = ICE_MAX_CHAINED_RX_BUFS;
- u16 num_bufs = ICE_DESC_UNUSED(ring);
struct ice_vsi *vsi = ring->vsi;
u32 rxdid = ICE_RXDID_FLEX_NIC;
struct ice_rlan_ctx rlan_ctx;
@@ -339,48 +346,6 @@ int ice_setup_rx_ctx(struct ice_ring *ring)
/* clear the context structure first */
memset(&rlan_ctx, 0, sizeof(rlan_ctx));
- ring->rx_buf_len = vsi->rx_buf_len;
-
- if (ring->vsi->type == ICE_VSI_PF) {
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq))
- /* coverity[check_return] */
- xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
- ring->q_index, ring->q_vector->napi.napi_id);
-
- ring->xsk_pool = ice_xsk_pool(ring);
- if (ring->xsk_pool) {
- xdp_rxq_info_unreg_mem_model(&ring->xdp_rxq);
-
- ring->rx_buf_len =
- xsk_pool_get_rx_frame_size(ring->xsk_pool);
- /* For AF_XDP ZC, we disallow packets to span on
- * multiple buffers, thus letting us skip that
- * handling in the fast-path.
- */
- chain_len = 1;
- err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
- MEM_TYPE_XSK_BUFF_POOL,
- NULL);
- if (err)
- return err;
- xsk_pool_set_rxq_info(ring->xsk_pool, &ring->xdp_rxq);
-
- dev_info(dev, "Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx ring %d\n",
- ring->q_index);
- } else {
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq))
- /* coverity[check_return] */
- xdp_rxq_info_reg(&ring->xdp_rxq,
- ring->netdev,
- ring->q_index, ring->q_vector->napi.napi_id);
-
- err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
- MEM_TYPE_PAGE_SHARED,
- NULL);
- if (err)
- return err;
- }
- }
/* Receive Queue Base Address.
* Indicates the starting address of the descriptor queue defined in
* 128 Byte units.
@@ -415,6 +380,12 @@ int ice_setup_rx_ctx(struct ice_ring *ring)
*/
rlan_ctx.showiv = 0;
+ /* For AF_XDP ZC, we disallow packets to span on
+ * multiple buffers, thus letting us skip that
+ * handling in the fast-path.
+ */
+ if (ring->xsk_pool)
+ chain_len = 1;
/* Max packet size for this queue - must not be set to a larger value
* than 5 x DBUF
*/
@@ -431,14 +402,15 @@ int ice_setup_rx_ctx(struct ice_ring *ring)
* of same priority
*/
if (vsi->type != ICE_VSI_VF)
- ice_write_qrxflxp_cntxt(hw, pf_q, rxdid, 0x3);
+ ice_write_qrxflxp_cntxt(hw, pf_q, rxdid, 0x3, true);
else
- ice_write_qrxflxp_cntxt(hw, pf_q, ICE_RXDID_LEGACY_1, 0x3);
+ ice_write_qrxflxp_cntxt(hw, pf_q, ICE_RXDID_LEGACY_1, 0x3,
+ false);
/* Absolute queue number out of 2K needs to be passed */
err = ice_write_rxq_ctx(hw, &rlan_ctx, pf_q);
if (err) {
- dev_err(dev, "Failed to set LAN Rx queue context for absolute Rx queue %d error: %d\n",
+ dev_err(ice_pf_to_dev(vsi->back), "Failed to set LAN Rx queue context for absolute Rx queue %d error: %d\n",
pf_q, err);
return -EIO;
}
@@ -458,6 +430,66 @@ int ice_setup_rx_ctx(struct ice_ring *ring)
ring->tail = hw->hw_addr + QRX_TAIL(pf_q);
writel(0, ring->tail);
+ return 0;
+}
+
+/**
+ * ice_vsi_cfg_rxq - Configure an Rx queue
+ * @ring: the ring being configured
+ *
+ * Return 0 on success and a negative value on error.
+ */
+int ice_vsi_cfg_rxq(struct ice_ring *ring)
+{
+ struct device *dev = ice_pf_to_dev(ring->vsi->back);
+ u16 num_bufs = ICE_DESC_UNUSED(ring);
+ int err;
+
+ ring->rx_buf_len = ring->vsi->rx_buf_len;
+
+ if (ring->vsi->type == ICE_VSI_PF) {
+ if (!xdp_rxq_info_is_reg(&ring->xdp_rxq))
+ /* coverity[check_return] */
+ xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
+ ring->q_index, ring->q_vector->napi.napi_id);
+
+ ring->xsk_pool = ice_xsk_pool(ring);
+ if (ring->xsk_pool) {
+ xdp_rxq_info_unreg_mem_model(&ring->xdp_rxq);
+
+ ring->rx_buf_len =
+ xsk_pool_get_rx_frame_size(ring->xsk_pool);
+ err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
+ MEM_TYPE_XSK_BUFF_POOL,
+ NULL);
+ if (err)
+ return err;
+ xsk_pool_set_rxq_info(ring->xsk_pool, &ring->xdp_rxq);
+
+ dev_info(dev, "Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx ring %d\n",
+ ring->q_index);
+ } else {
+ if (!xdp_rxq_info_is_reg(&ring->xdp_rxq))
+ /* coverity[check_return] */
+ xdp_rxq_info_reg(&ring->xdp_rxq,
+ ring->netdev,
+ ring->q_index, ring->q_vector->napi.napi_id);
+
+ err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
+ MEM_TYPE_PAGE_SHARED,
+ NULL);
+ if (err)
+ return err;
+ }
+ }
+
+ err = ice_setup_rx_ctx(ring);
+ if (err) {
+ dev_err(dev, "ice_setup_rx_ctx failed for RxQ %d, err %d\n",
+ ring->q_index, err);
+ return err;
+ }
+
if (ring->xsk_pool) {
bool ok;
@@ -470,9 +502,13 @@ int ice_setup_rx_ctx(struct ice_ring *ring)
}
ok = ice_alloc_rx_bufs_zc(ring, num_bufs);
- if (!ok)
+ if (!ok) {
+ u16 pf_q = ring->vsi->rxq_map[ring->q_index];
+
dev_info(dev, "Failed to allocate some buffers on XSK buffer pool enabled Rx ring %d (pf_q %d)\n",
ring->q_index, pf_q);
+ }
+
return 0;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_base.h b/drivers/net/ethernet/intel/ice/ice_base.h
index 44efdb627043..20e1c29aa68a 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.h
+++ b/drivers/net/ethernet/intel/ice/ice_base.h
@@ -6,7 +6,7 @@
#include "ice.h"
-int ice_setup_rx_ctx(struct ice_ring *ring);
+int ice_vsi_cfg_rxq(struct ice_ring *ring);
int __ice_vsi_get_qs(struct ice_qs_cfg *qs_cfg);
int
ice_vsi_ctrl_one_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx, bool wait);
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index e93b1e40f627..2fb81e359cdf 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -2,6 +2,7 @@
/* Copyright (c) 2018, Intel Corporation. */
#include "ice_common.h"
+#include "ice_lib.h"
#include "ice_sched.h"
#include "ice_adminq_cmd.h"
#include "ice_flow.h"
@@ -58,6 +59,17 @@ static enum ice_status ice_set_mac_type(struct ice_hw *hw)
}
/**
+ * ice_is_e810
+ * @hw: pointer to the hardware structure
+ *
+ * returns true if the device is E810 based, false if not.
+ */
+bool ice_is_e810(struct ice_hw *hw)
+{
+ return hw->mac_type == ICE_MAC_E810;
+}
+
+/**
* ice_clear_pf_cfg - Clear PF configuration
* @hw: pointer to the hardware structure
*
@@ -424,6 +436,7 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse,
li->phy_type_high = le64_to_cpu(link_data.phy_type_high);
*hw_media_type = ice_get_media_type(pi);
li->link_info = link_data.link_info;
+ li->link_cfg_err = link_data.link_cfg_err;
li->an_info = link_data.an_info;
li->ext_info = link_data.ext_info;
li->max_frame_size = le16_to_cpu(link_data.max_frame_size);
@@ -454,6 +467,7 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse,
(unsigned long long)li->phy_type_high);
ice_debug(hw, ICE_DBG_LINK, " media_type = 0x%x\n", *hw_media_type);
ice_debug(hw, ICE_DBG_LINK, " link_info = 0x%x\n", li->link_info);
+ ice_debug(hw, ICE_DBG_LINK, " link_cfg_err = 0x%x\n", li->link_cfg_err);
ice_debug(hw, ICE_DBG_LINK, " an_info = 0x%x\n", li->an_info);
ice_debug(hw, ICE_DBG_LINK, " ext_info = 0x%x\n", li->ext_info);
ice_debug(hw, ICE_DBG_LINK, " fec_info = 0x%x\n", li->fec_info);
@@ -1062,7 +1076,8 @@ enum ice_status ice_check_reset(struct ice_hw *hw)
GLNVM_ULD_POR_DONE_1_M |\
GLNVM_ULD_PCIER_DONE_2_M)
- uld_mask = ICE_RESET_DONE_MASK;
+ uld_mask = ICE_RESET_DONE_MASK | (hw->func_caps.common_cap.rdma ?
+ GLNVM_ULD_PE_DONE_M : 0);
/* Device is Active; check Global Reset processes are done */
for (cnt = 0; cnt < ICE_PF_RESET_WAIT_COUNT; cnt++) {
@@ -1289,6 +1304,64 @@ const struct ice_ctx_ele ice_tlan_ctx_info[] = {
{ 0 }
};
+/* Sideband Queue command wrappers */
+
+/**
+ * ice_sbq_send_cmd - send Sideband Queue command to Sideband Queue
+ * @hw: pointer to the HW struct
+ * @desc: descriptor describing the command
+ * @buf: buffer to use for indirect commands (NULL for direct commands)
+ * @buf_size: size of buffer for indirect commands (0 for direct commands)
+ * @cd: pointer to command details structure
+ */
+static int
+ice_sbq_send_cmd(struct ice_hw *hw, struct ice_sbq_cmd_desc *desc,
+ void *buf, u16 buf_size, struct ice_sq_cd *cd)
+{
+ return ice_status_to_errno(ice_sq_send_cmd(hw, ice_get_sbq(hw),
+ (struct ice_aq_desc *)desc,
+ buf, buf_size, cd));
+}
+
+/**
+ * ice_sbq_rw_reg - Fill Sideband Queue command
+ * @hw: pointer to the HW struct
+ * @in: message info to be filled in descriptor
+ */
+int ice_sbq_rw_reg(struct ice_hw *hw, struct ice_sbq_msg_input *in)
+{
+ struct ice_sbq_cmd_desc desc = {0};
+ struct ice_sbq_msg_req msg = {0};
+ u16 msg_len;
+ int status;
+
+ msg_len = sizeof(msg);
+
+ msg.dest_dev = in->dest_dev;
+ msg.opcode = in->opcode;
+ msg.flags = ICE_SBQ_MSG_FLAGS;
+ msg.sbe_fbe = ICE_SBQ_MSG_SBE_FBE;
+ msg.msg_addr_low = cpu_to_le16(in->msg_addr_low);
+ msg.msg_addr_high = cpu_to_le32(in->msg_addr_high);
+
+ if (in->opcode)
+ msg.data = cpu_to_le32(in->data);
+ else
+ /* data read comes back in completion, so shorten the struct by
+ * sizeof(msg.data)
+ */
+ msg_len -= sizeof(msg.data);
+
+ desc.flags = cpu_to_le16(ICE_AQ_FLAG_RD);
+ desc.opcode = cpu_to_le16(ice_sbq_opc_neigh_dev_req);
+ desc.param0.cmd_len = cpu_to_le16(msg_len);
+ status = ice_sbq_send_cmd(hw, &desc, &msg, msg_len, NULL);
+ if (!status && !in->opcode)
+ in->data = le32_to_cpu
+ (((struct ice_sbq_msg_cmpl *)&msg)->data);
+ return status;
+}
+
/* FW Admin Queue command wrappers */
/* Software lock/mutex that is meant to be held while the Global Config Lock
@@ -1938,6 +2011,10 @@ ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps,
ice_debug(hw, ICE_DBG_INIT, "%s: nvm_unified_update = %d\n", prefix,
caps->nvm_unified_update);
break;
+ case ICE_AQC_CAPS_RDMA:
+ caps->rdma = (number == 1);
+ ice_debug(hw, ICE_DBG_INIT, "%s: rdma = %d\n", prefix, caps->rdma);
+ break;
case ICE_AQC_CAPS_MAX_MTU:
caps->max_mtu = number;
ice_debug(hw, ICE_DBG_INIT, "%s: max_mtu = %d\n",
@@ -1971,6 +2048,16 @@ ice_recalc_port_limited_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps)
caps->maxtc = 4;
ice_debug(hw, ICE_DBG_INIT, "reducing maxtc to %d (based on #ports)\n",
caps->maxtc);
+ if (caps->rdma) {
+ ice_debug(hw, ICE_DBG_INIT, "forcing RDMA off\n");
+ caps->rdma = 0;
+ }
+
+ /* print message only when processing device capabilities
+ * during initialization.
+ */
+ if (caps == &hw->dev_caps.common_cap)
+ dev_info(ice_hw_to_dev(hw), "RDMA functionality is not available with the current device configuration.\n");
}
}
@@ -2017,6 +2104,48 @@ ice_parse_vsi_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p,
}
/**
+ * ice_parse_1588_func_caps - Parse ICE_AQC_CAPS_1588 function caps
+ * @hw: pointer to the HW struct
+ * @func_p: pointer to function capabilities structure
+ * @cap: pointer to the capability element to parse
+ *
+ * Extract function capabilities for ICE_AQC_CAPS_1588.
+ */
+static void
+ice_parse_1588_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p,
+ struct ice_aqc_list_caps_elem *cap)
+{
+ struct ice_ts_func_info *info = &func_p->ts_func_info;
+ u32 number = le32_to_cpu(cap->number);
+
+ info->ena = ((number & ICE_TS_FUNC_ENA_M) != 0);
+ func_p->common_cap.ieee_1588 = info->ena;
+
+ info->src_tmr_owned = ((number & ICE_TS_SRC_TMR_OWND_M) != 0);
+ info->tmr_ena = ((number & ICE_TS_TMR_ENA_M) != 0);
+ info->tmr_index_owned = ((number & ICE_TS_TMR_IDX_OWND_M) != 0);
+ info->tmr_index_assoc = ((number & ICE_TS_TMR_IDX_ASSOC_M) != 0);
+
+ info->clk_freq = (number & ICE_TS_CLK_FREQ_M) >> ICE_TS_CLK_FREQ_S;
+ info->clk_src = ((number & ICE_TS_CLK_SRC_M) != 0);
+
+ ice_debug(hw, ICE_DBG_INIT, "func caps: ieee_1588 = %u\n",
+ func_p->common_cap.ieee_1588);
+ ice_debug(hw, ICE_DBG_INIT, "func caps: src_tmr_owned = %u\n",
+ info->src_tmr_owned);
+ ice_debug(hw, ICE_DBG_INIT, "func caps: tmr_ena = %u\n",
+ info->tmr_ena);
+ ice_debug(hw, ICE_DBG_INIT, "func caps: tmr_index_owned = %u\n",
+ info->tmr_index_owned);
+ ice_debug(hw, ICE_DBG_INIT, "func caps: tmr_index_assoc = %u\n",
+ info->tmr_index_assoc);
+ ice_debug(hw, ICE_DBG_INIT, "func caps: clk_freq = %u\n",
+ info->clk_freq);
+ ice_debug(hw, ICE_DBG_INIT, "func caps: clk_src = %u\n",
+ info->clk_src);
+}
+
+/**
* ice_parse_fdir_func_caps - Parse ICE_AQC_CAPS_FD function caps
* @hw: pointer to the HW struct
* @func_p: pointer to function capabilities structure
@@ -2082,6 +2211,9 @@ ice_parse_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p,
case ICE_AQC_CAPS_VSI:
ice_parse_vsi_func_caps(hw, func_p, &cap_resp[i]);
break;
+ case ICE_AQC_CAPS_1588:
+ ice_parse_1588_func_caps(hw, func_p, &cap_resp[i]);
+ break;
case ICE_AQC_CAPS_FD:
ice_parse_fdir_func_caps(hw, func_p);
break;
@@ -2155,6 +2287,57 @@ ice_parse_vsi_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
}
/**
+ * ice_parse_1588_dev_caps - Parse ICE_AQC_CAPS_1588 device caps
+ * @hw: pointer to the HW struct
+ * @dev_p: pointer to device capabilities structure
+ * @cap: capability element to parse
+ *
+ * Parse ICE_AQC_CAPS_1588 for device capabilities.
+ */
+static void
+ice_parse_1588_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
+ struct ice_aqc_list_caps_elem *cap)
+{
+ struct ice_ts_dev_info *info = &dev_p->ts_dev_info;
+ u32 logical_id = le32_to_cpu(cap->logical_id);
+ u32 phys_id = le32_to_cpu(cap->phys_id);
+ u32 number = le32_to_cpu(cap->number);
+
+ info->ena = ((number & ICE_TS_DEV_ENA_M) != 0);
+ dev_p->common_cap.ieee_1588 = info->ena;
+
+ info->tmr0_owner = number & ICE_TS_TMR0_OWNR_M;
+ info->tmr0_owned = ((number & ICE_TS_TMR0_OWND_M) != 0);
+ info->tmr0_ena = ((number & ICE_TS_TMR0_ENA_M) != 0);
+
+ info->tmr1_owner = (number & ICE_TS_TMR1_OWNR_M) >> ICE_TS_TMR1_OWNR_S;
+ info->tmr1_owned = ((number & ICE_TS_TMR1_OWND_M) != 0);
+ info->tmr1_ena = ((number & ICE_TS_TMR1_ENA_M) != 0);
+
+ info->ena_ports = logical_id;
+ info->tmr_own_map = phys_id;
+
+ ice_debug(hw, ICE_DBG_INIT, "dev caps: ieee_1588 = %u\n",
+ dev_p->common_cap.ieee_1588);
+ ice_debug(hw, ICE_DBG_INIT, "dev caps: tmr0_owner = %u\n",
+ info->tmr0_owner);
+ ice_debug(hw, ICE_DBG_INIT, "dev caps: tmr0_owned = %u\n",
+ info->tmr0_owned);
+ ice_debug(hw, ICE_DBG_INIT, "dev caps: tmr0_ena = %u\n",
+ info->tmr0_ena);
+ ice_debug(hw, ICE_DBG_INIT, "dev caps: tmr1_owner = %u\n",
+ info->tmr1_owner);
+ ice_debug(hw, ICE_DBG_INIT, "dev caps: tmr1_owned = %u\n",
+ info->tmr1_owned);
+ ice_debug(hw, ICE_DBG_INIT, "dev caps: tmr1_ena = %u\n",
+ info->tmr1_ena);
+ ice_debug(hw, ICE_DBG_INIT, "dev caps: ieee_1588 ena_ports = %u\n",
+ info->ena_ports);
+ ice_debug(hw, ICE_DBG_INIT, "dev caps: tmr_own_map = %u\n",
+ info->tmr_own_map);
+}
+
+/**
* ice_parse_fdir_dev_caps - Parse ICE_AQC_CAPS_FD device caps
* @hw: pointer to the HW struct
* @dev_p: pointer to device capabilities structure
@@ -2215,6 +2398,9 @@ ice_parse_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
case ICE_AQC_CAPS_VSI:
ice_parse_vsi_dev_caps(hw, dev_p, &cap_resp[i]);
break;
+ case ICE_AQC_CAPS_1588:
+ ice_parse_1588_dev_caps(hw, dev_p, &cap_resp[i]);
+ break;
case ICE_AQC_CAPS_FD:
ice_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]);
break;
@@ -3635,6 +3821,52 @@ do_aq:
return status;
}
+/**
+ * ice_aq_add_rdma_qsets
+ * @hw: pointer to the hardware structure
+ * @num_qset_grps: Number of RDMA Qset groups
+ * @qset_list: list of Qset groups to be added
+ * @buf_size: size of buffer for indirect command
+ * @cd: pointer to command details structure or NULL
+ *
+ * Add Tx RDMA Qsets (0x0C33)
+ */
+static int
+ice_aq_add_rdma_qsets(struct ice_hw *hw, u8 num_qset_grps,
+ struct ice_aqc_add_rdma_qset_data *qset_list,
+ u16 buf_size, struct ice_sq_cd *cd)
+{
+ struct ice_aqc_add_rdma_qset_data *list;
+ struct ice_aqc_add_rdma_qset *cmd;
+ struct ice_aq_desc desc;
+ u16 i, sum_size = 0;
+
+ cmd = &desc.params.add_rdma_qset;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_rdma_qset);
+
+ if (num_qset_grps > ICE_LAN_TXQ_MAX_QGRPS)
+ return -EINVAL;
+
+ for (i = 0, list = qset_list; i < num_qset_grps; i++) {
+ u16 num_qsets = le16_to_cpu(list->num_qsets);
+
+ sum_size += struct_size(list, rdma_qsets, num_qsets);
+ list = (struct ice_aqc_add_rdma_qset_data *)(list->rdma_qsets +
+ num_qsets);
+ }
+
+ if (buf_size != sum_size)
+ return -EINVAL;
+
+ desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
+
+ cmd->num_qset_grps = num_qset_grps;
+
+ return ice_status_to_errno(ice_aq_send_cmd(hw, &desc, qset_list,
+ buf_size, cd));
+}
+
/* End of FW Admin Queue command wrappers */
/**
@@ -4133,6 +4365,162 @@ ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_handle, u8 tc_bitmap,
}
/**
+ * ice_cfg_vsi_rdma - configure the VSI RDMA queues
+ * @pi: port information structure
+ * @vsi_handle: software VSI handle
+ * @tc_bitmap: TC bitmap
+ * @max_rdmaqs: max RDMA queues array per TC
+ *
+ * This function adds/updates the VSI RDMA queues per TC.
+ */
+int
+ice_cfg_vsi_rdma(struct ice_port_info *pi, u16 vsi_handle, u16 tc_bitmap,
+ u16 *max_rdmaqs)
+{
+ return ice_status_to_errno(ice_cfg_vsi_qs(pi, vsi_handle, tc_bitmap,
+ max_rdmaqs,
+ ICE_SCHED_NODE_OWNER_RDMA));
+}
+
+/**
+ * ice_ena_vsi_rdma_qset
+ * @pi: port information structure
+ * @vsi_handle: software VSI handle
+ * @tc: TC number
+ * @rdma_qset: pointer to RDMA Qset
+ * @num_qsets: number of RDMA Qsets
+ * @qset_teid: pointer to Qset node TEIDs
+ *
+ * This function adds RDMA Qset
+ */
+int
+ice_ena_vsi_rdma_qset(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
+ u16 *rdma_qset, u16 num_qsets, u32 *qset_teid)
+{
+ struct ice_aqc_txsched_elem_data node = { 0 };
+ struct ice_aqc_add_rdma_qset_data *buf;
+ struct ice_sched_node *parent;
+ enum ice_status status;
+ struct ice_hw *hw;
+ u16 i, buf_size;
+ int ret;
+
+ if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY)
+ return -EIO;
+ hw = pi->hw;
+
+ if (!ice_is_vsi_valid(hw, vsi_handle))
+ return -EINVAL;
+
+ buf_size = struct_size(buf, rdma_qsets, num_qsets);
+ buf = kzalloc(buf_size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ mutex_lock(&pi->sched_lock);
+
+ parent = ice_sched_get_free_qparent(pi, vsi_handle, tc,
+ ICE_SCHED_NODE_OWNER_RDMA);
+ if (!parent) {
+ ret = -EINVAL;
+ goto rdma_error_exit;
+ }
+ buf->parent_teid = parent->info.node_teid;
+ node.parent_teid = parent->info.node_teid;
+
+ buf->num_qsets = cpu_to_le16(num_qsets);
+ for (i = 0; i < num_qsets; i++) {
+ buf->rdma_qsets[i].tx_qset_id = cpu_to_le16(rdma_qset[i]);
+ buf->rdma_qsets[i].info.valid_sections =
+ ICE_AQC_ELEM_VALID_GENERIC | ICE_AQC_ELEM_VALID_CIR |
+ ICE_AQC_ELEM_VALID_EIR;
+ buf->rdma_qsets[i].info.generic = 0;
+ buf->rdma_qsets[i].info.cir_bw.bw_profile_idx =
+ cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID);
+ buf->rdma_qsets[i].info.cir_bw.bw_alloc =
+ cpu_to_le16(ICE_SCHED_DFLT_BW_WT);
+ buf->rdma_qsets[i].info.eir_bw.bw_profile_idx =
+ cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID);
+ buf->rdma_qsets[i].info.eir_bw.bw_alloc =
+ cpu_to_le16(ICE_SCHED_DFLT_BW_WT);
+ }
+ ret = ice_aq_add_rdma_qsets(hw, 1, buf, buf_size, NULL);
+ if (ret) {
+ ice_debug(hw, ICE_DBG_RDMA, "add RDMA qset failed\n");
+ goto rdma_error_exit;
+ }
+ node.data.elem_type = ICE_AQC_ELEM_TYPE_LEAF;
+ for (i = 0; i < num_qsets; i++) {
+ node.node_teid = buf->rdma_qsets[i].qset_teid;
+ status = ice_sched_add_node(pi, hw->num_tx_sched_layers - 1,
+ &node);
+ if (status) {
+ ret = ice_status_to_errno(status);
+ break;
+ }
+ qset_teid[i] = le32_to_cpu(node.node_teid);
+ }
+rdma_error_exit:
+ mutex_unlock(&pi->sched_lock);
+ kfree(buf);
+ return ret;
+}
+
+/**
+ * ice_dis_vsi_rdma_qset - free RDMA resources
+ * @pi: port_info struct
+ * @count: number of RDMA Qsets to free
+ * @qset_teid: TEID of Qset node
+ * @q_id: list of queue IDs being disabled
+ */
+int
+ice_dis_vsi_rdma_qset(struct ice_port_info *pi, u16 count, u32 *qset_teid,
+ u16 *q_id)
+{
+ struct ice_aqc_dis_txq_item *qg_list;
+ enum ice_status status = 0;
+ struct ice_hw *hw;
+ u16 qg_size;
+ int i;
+
+ if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY)
+ return -EIO;
+
+ hw = pi->hw;
+
+ qg_size = struct_size(qg_list, q_id, 1);
+ qg_list = kzalloc(qg_size, GFP_KERNEL);
+ if (!qg_list)
+ return -ENOMEM;
+
+ mutex_lock(&pi->sched_lock);
+
+ for (i = 0; i < count; i++) {
+ struct ice_sched_node *node;
+
+ node = ice_sched_find_node_by_teid(pi->root, qset_teid[i]);
+ if (!node)
+ continue;
+
+ qg_list->parent_teid = node->info.parent_teid;
+ qg_list->num_qs = 1;
+ qg_list->q_id[0] =
+ cpu_to_le16(q_id[i] |
+ ICE_AQC_Q_DIS_BUF_ELEM_TYPE_RDMA_QSET);
+
+ status = ice_aq_dis_lan_txq(hw, 1, qg_list, qg_size,
+ ICE_NO_RESET, 0, NULL);
+ if (status)
+ break;
+
+ ice_free_sched_node(pi, node);
+ }
+
+ mutex_unlock(&pi->sched_lock);
+ kfree(qg_list);
+ return ice_status_to_errno(status);
+}
+
+/**
* ice_replay_pre_init - replay pre initialization
* @hw: pointer to the HW struct
*
@@ -4304,6 +4692,81 @@ ice_sched_query_elem(struct ice_hw *hw, u32 node_teid,
}
/**
+ * ice_aq_set_driver_param - Set driver parameter to share via firmware
+ * @hw: pointer to the HW struct
+ * @idx: parameter index to set
+ * @value: the value to set the parameter to
+ * @cd: pointer to command details structure or NULL
+ *
+ * Set the value of one of the software defined parameters. All PFs connected
+ * to this device can read the value using ice_aq_get_driver_param.
+ *
+ * Note that firmware provides no synchronization or locking, and will not
+ * save the parameter value during a device reset. It is expected that
+ * a single PF will write the parameter value, while all other PFs will only
+ * read it.
+ */
+int
+ice_aq_set_driver_param(struct ice_hw *hw, enum ice_aqc_driver_params idx,
+ u32 value, struct ice_sq_cd *cd)
+{
+ struct ice_aqc_driver_shared_params *cmd;
+ struct ice_aq_desc desc;
+
+ if (idx >= ICE_AQC_DRIVER_PARAM_MAX)
+ return -EIO;
+
+ cmd = &desc.params.drv_shared_params;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_driver_shared_params);
+
+ cmd->set_or_get_op = ICE_AQC_DRIVER_PARAM_SET;
+ cmd->param_indx = idx;
+ cmd->param_val = cpu_to_le32(value);
+
+ return ice_status_to_errno(ice_aq_send_cmd(hw, &desc, NULL, 0, cd));
+}
+
+/**
+ * ice_aq_get_driver_param - Get driver parameter shared via firmware
+ * @hw: pointer to the HW struct
+ * @idx: parameter index to set
+ * @value: storage to return the shared parameter
+ * @cd: pointer to command details structure or NULL
+ *
+ * Get the value of one of the software defined parameters.
+ *
+ * Note that firmware provides no synchronization or locking. It is expected
+ * that only a single PF will write a given parameter.
+ */
+int
+ice_aq_get_driver_param(struct ice_hw *hw, enum ice_aqc_driver_params idx,
+ u32 *value, struct ice_sq_cd *cd)
+{
+ struct ice_aqc_driver_shared_params *cmd;
+ struct ice_aq_desc desc;
+ enum ice_status status;
+
+ if (idx >= ICE_AQC_DRIVER_PARAM_MAX)
+ return -EIO;
+
+ cmd = &desc.params.drv_shared_params;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_driver_shared_params);
+
+ cmd->set_or_get_op = ICE_AQC_DRIVER_PARAM_GET;
+ cmd->param_indx = idx;
+
+ status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
+ if (status)
+ return ice_status_to_errno(status);
+
+ *value = le32_to_cpu(cmd->param_val);
+
+ return 0;
+}
+
+/**
* ice_fw_supports_link_override
* @hw: pointer to the hardware structure
*
diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index 7a9d2dfb21a2..fb16070f02e2 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -40,6 +40,8 @@ enum ice_status
ice_aq_alloc_free_res(struct ice_hw *hw, u16 num_entries,
struct ice_aqc_alloc_free_res_elem *buf, u16 buf_size,
enum ice_adminq_opc opc, struct ice_sq_cd *cd);
+bool ice_is_sbq_supported(struct ice_hw *hw);
+struct ice_ctl_q_info *ice_get_sbq(struct ice_hw *hw);
enum ice_status
ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq,
struct ice_aq_desc *desc, void *buf, u16 buf_size,
@@ -97,6 +99,7 @@ ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high,
enum ice_status
ice_aq_manage_mac_write(struct ice_hw *hw, const u8 *mac_addr, u8 flags,
struct ice_sq_cd *cd);
+bool ice_is_e810(struct ice_hw *hw);
enum ice_status ice_clear_pf_cfg(struct ice_hw *hw);
enum ice_status
ice_aq_set_phy_cfg(struct ice_hw *hw, struct ice_port_info *pi,
@@ -147,6 +150,15 @@ ice_aq_sff_eeprom(struct ice_hw *hw, u16 lport, u8 bus_addr,
u16 mem_addr, u8 page, u8 set_page, u8 *data, u8 length,
bool write, struct ice_sq_cd *cd);
+int
+ice_cfg_vsi_rdma(struct ice_port_info *pi, u16 vsi_handle, u16 tc_bitmap,
+ u16 *max_rdmaqs);
+int
+ice_ena_vsi_rdma_qset(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
+ u16 *rdma_qset, u16 num_qsets, u32 *qset_teid);
+int
+ice_dis_vsi_rdma_qset(struct ice_port_info *pi, u16 count, u32 *qset_teid,
+ u16 *q_id);
enum ice_status
ice_dis_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_queues,
u16 *q_handle, u16 *q_ids, u32 *q_teids,
@@ -164,6 +176,7 @@ void ice_replay_post(struct ice_hw *hw);
void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf);
struct ice_q_ctx *
ice_get_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 q_handle);
+int ice_sbq_rw_reg(struct ice_hw *hw, struct ice_sbq_msg_input *in);
void
ice_stat_update40(struct ice_hw *hw, u32 reg, bool prev_stat_loaded,
u64 *prev_stat, u64 *cur_stat);
@@ -173,6 +186,12 @@ ice_stat_update32(struct ice_hw *hw, u32 reg, bool prev_stat_loaded,
enum ice_status
ice_sched_query_elem(struct ice_hw *hw, u32 node_teid,
struct ice_aqc_txsched_elem_data *buf);
+int
+ice_aq_set_driver_param(struct ice_hw *hw, enum ice_aqc_driver_params idx,
+ u32 value, struct ice_sq_cd *cd);
+int
+ice_aq_get_driver_param(struct ice_hw *hw, enum ice_aqc_driver_params idx,
+ u32 *value, struct ice_sq_cd *cd);
enum ice_status
ice_aq_set_lldp_mib(struct ice_hw *hw, u8 mib_type, void *buf, u16 buf_size,
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 87b33bdd4960..03bdb125be36 100644
--- a/drivers/net/ethernet/intel/ice/ice_controlq.c
+++ b/drivers/net/ethernet/intel/ice/ice_controlq.c
@@ -52,6 +52,19 @@ static void ice_mailbox_init_regs(struct ice_hw *hw)
}
/**
+ * ice_sb_init_regs - Initialize Sideband registers
+ * @hw: pointer to the hardware structure
+ *
+ * This assumes the alloc_sq and alloc_rq functions have already been called
+ */
+static void ice_sb_init_regs(struct ice_hw *hw)
+{
+ struct ice_ctl_q_info *cq = &hw->sbq;
+
+ ICE_CQ_INIT_REGS(cq, PF_SB);
+}
+
+/**
* ice_check_sq_alive
* @hw: pointer to the HW struct
* @cq: pointer to the specific Control queue
@@ -609,6 +622,10 @@ static enum ice_status ice_init_ctrlq(struct ice_hw *hw, enum ice_ctl_q q_type)
ice_adminq_init_regs(hw);
cq = &hw->adminq;
break;
+ case ICE_CTL_Q_SB:
+ ice_sb_init_regs(hw);
+ cq = &hw->sbq;
+ break;
case ICE_CTL_Q_MAILBOX:
ice_mailbox_init_regs(hw);
cq = &hw->mailboxq;
@@ -646,6 +663,32 @@ init_ctrlq_free_sq:
}
/**
+ * ice_is_sbq_supported - is the sideband queue supported
+ * @hw: pointer to the hardware structure
+ *
+ * Returns true if the sideband control queue interface is
+ * supported for the device, false otherwise
+ */
+bool ice_is_sbq_supported(struct ice_hw *hw)
+{
+ /* The device sideband queue is only supported on devices with the
+ * generic MAC type.
+ */
+ return hw->mac_type == ICE_MAC_GENERIC;
+}
+
+/**
+ * ice_get_sbq - returns the right control queue to use for sideband
+ * @hw: pointer to the hardware structure
+ */
+struct ice_ctl_q_info *ice_get_sbq(struct ice_hw *hw)
+{
+ if (ice_is_sbq_supported(hw))
+ return &hw->sbq;
+ return &hw->adminq;
+}
+
+/**
* ice_shutdown_ctrlq - shutdown routine for any control queue
* @hw: pointer to the hardware structure
* @q_type: specific Control queue type
@@ -662,6 +705,9 @@ static void ice_shutdown_ctrlq(struct ice_hw *hw, enum ice_ctl_q q_type)
if (ice_check_sq_alive(hw, cq))
ice_aq_q_shutdown(hw, true);
break;
+ case ICE_CTL_Q_SB:
+ cq = &hw->sbq;
+ break;
case ICE_CTL_Q_MAILBOX:
cq = &hw->mailboxq;
break;
@@ -685,6 +731,9 @@ void ice_shutdown_all_ctrlq(struct ice_hw *hw)
{
/* Shutdown FW admin queue */
ice_shutdown_ctrlq(hw, ICE_CTL_Q_ADMIN);
+ /* Shutdown PHY Sideband */
+ if (ice_is_sbq_supported(hw))
+ ice_shutdown_ctrlq(hw, ICE_CTL_Q_SB);
/* Shutdown PF-VF Mailbox */
ice_shutdown_ctrlq(hw, ICE_CTL_Q_MAILBOX);
}
@@ -724,6 +773,15 @@ enum ice_status ice_init_all_ctrlq(struct ice_hw *hw)
if (status)
return status;
+ /* sideband control queue (SBQ) interface is not supported on some
+ * devices. Initialize if supported, else fallback to the admin queue
+ * interface
+ */
+ if (ice_is_sbq_supported(hw)) {
+ status = ice_init_ctrlq(hw, ICE_CTL_Q_SB);
+ if (status)
+ return status;
+ }
/* Init Mailbox queue */
return ice_init_ctrlq(hw, ICE_CTL_Q_MAILBOX);
}
@@ -759,6 +817,8 @@ static void ice_init_ctrlq_locks(struct ice_ctl_q_info *cq)
enum ice_status ice_create_all_ctrlq(struct ice_hw *hw)
{
ice_init_ctrlq_locks(&hw->adminq);
+ if (ice_is_sbq_supported(hw))
+ ice_init_ctrlq_locks(&hw->sbq);
ice_init_ctrlq_locks(&hw->mailboxq);
return ice_init_all_ctrlq(hw);
@@ -791,6 +851,8 @@ void ice_destroy_all_ctrlq(struct ice_hw *hw)
ice_shutdown_all_ctrlq(hw);
ice_destroy_ctrlq_locks(&hw->adminq);
+ if (ice_is_sbq_supported(hw))
+ ice_destroy_ctrlq_locks(&hw->sbq);
ice_destroy_ctrlq_locks(&hw->mailboxq);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h
index fe75871e48ca..c07e9cc9fc6e 100644
--- a/drivers/net/ethernet/intel/ice/ice_controlq.h
+++ b/drivers/net/ethernet/intel/ice/ice_controlq.h
@@ -9,6 +9,7 @@
/* Maximum buffer lengths for all control queue types */
#define ICE_AQ_MAX_BUF_LEN 4096
#define ICE_MBXQ_MAX_BUF_LEN 4096
+#define ICE_SBQ_MAX_BUF_LEN 512
#define ICE_CTL_Q_DESC(R, i) \
(&(((struct ice_aq_desc *)((R).desc_buf.va))[i]))
@@ -29,6 +30,7 @@ enum ice_ctl_q {
ICE_CTL_Q_UNKNOWN = 0,
ICE_CTL_Q_ADMIN,
ICE_CTL_Q_MAILBOX,
+ ICE_CTL_Q_SB,
};
/* Control Queue timeout settings - max delay 1s */
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
index df02cffdf209..926cf748c5ec 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
@@ -275,6 +275,7 @@ 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 device *dev = ice_pf_to_dev(pf);
int ret = ICE_DCB_NO_HW_CHG;
+ struct iidc_event *event;
struct ice_vsi *pf_vsi;
curr_cfg = &pf->hw.port_info->qos_cfg.local_dcbx_cfg;
@@ -313,6 +314,17 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked)
goto free_cfg;
}
+ /* Notify AUX drivers about impending change to TCs */
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+ if (!event) {
+ ret = -ENOMEM;
+ goto free_cfg;
+ }
+
+ set_bit(IIDC_EVENT_BEFORE_TC_CHANGE, event->type);
+ ice_send_event_to_aux(pf, event);
+ kfree(event);
+
/* avoid race conditions by holding the lock while disabling and
* re-enabling the VSI
*/
@@ -640,6 +652,7 @@ static int ice_dcb_noncontig_cfg(struct ice_pf *pf)
void ice_pf_dcb_recfg(struct ice_pf *pf)
{
struct ice_dcbx_cfg *dcbcfg = &pf->hw.port_info->qos_cfg.local_dcbx_cfg;
+ struct iidc_event *event;
u8 tc_map = 0;
int v, ret;
@@ -675,6 +688,14 @@ void ice_pf_dcb_recfg(struct ice_pf *pf)
if (vsi->type == ICE_VSI_PF)
ice_dcbnl_set_all(vsi);
}
+ /* Notify the AUX drivers that TC change is finished */
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+ if (!event)
+ return;
+
+ set_bit(IIDC_EVENT_AFTER_TC_CHANGE, event->type);
+ ice_send_event_to_aux(pf, event);
+ kfree(event);
}
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h
index 35c21d9ae009..261b6e2ed7bc 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h
@@ -60,7 +60,7 @@ static inline bool ice_is_dcb_active(struct ice_pf *pf)
test_bit(ICE_FLAG_DCB_ENA, pf->flags));
}
#else
-#define ice_dcb_rebuild(pf) do {} while (0)
+static inline void ice_dcb_rebuild(struct ice_pf *pf) { }
static inline u8 ice_dcb_get_ena_tc(struct ice_dcbx_cfg __always_unused *dcbcfg)
{
@@ -113,11 +113,12 @@ ice_is_pfc_causing_hung_q(struct ice_pf __always_unused *pf,
return false;
}
-#define ice_update_dcb_stats(pf) do {} while (0)
-#define ice_pf_dcb_recfg(pf) do {} while (0)
-#define ice_vsi_cfg_dcb_rings(vsi) do {} while (0)
-#define ice_dcb_process_lldp_set_mib_change(pf, event) do {} while (0)
-#define ice_set_cgd_num(tlan_ctx, ring) do {} while (0)
-#define ice_vsi_cfg_netdev_tc(vsi, ena_tc) do {} while (0)
+static inline void ice_pf_dcb_recfg(struct ice_pf *pf) { }
+static inline void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi) { }
+static inline void ice_update_dcb_stats(struct ice_pf *pf) { }
+static inline void
+ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, struct ice_rq_event_info *event) { }
+static inline void ice_vsi_cfg_netdev_tc(struct ice_vsi *vsi, u8 ena_tc) { }
+static inline void ice_set_cgd_num(struct ice_tlan_ctx *tlan_ctx, struct ice_ring *ring) { }
#endif /* CONFIG_DCB */
#endif /* _ICE_DCB_LIB_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_nl.h b/drivers/net/ethernet/intel/ice/ice_dcb_nl.h
index 6c630a362293..eac2f34bdcdd 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb_nl.h
+++ b/drivers/net/ethernet/intel/ice/ice_dcb_nl.h
@@ -11,9 +11,10 @@ void
ice_dcbnl_flush_apps(struct ice_pf *pf, struct ice_dcbx_cfg *old_cfg,
struct ice_dcbx_cfg *new_cfg);
#else
-#define ice_dcbnl_setup(vsi) do {} while (0)
-#define ice_dcbnl_set_all(vsi) do {} while (0)
-#define ice_dcbnl_flush_apps(pf, old_cfg, new_cfg) do {} while (0)
+static inline void ice_dcbnl_setup(struct ice_vsi *vsi) { }
+static inline void ice_dcbnl_set_all(struct ice_vsi *vsi) { }
+static inline void
+ice_dcbnl_flush_apps(struct ice_pf *pf, struct ice_dcbx_cfg *old_cfg,
+ struct ice_dcbx_cfg *new_cfg) { }
#endif /* CONFIG_DCB */
-
#endif /* _ICE_DCB_NL_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.c b/drivers/net/ethernet/intel/ice/ice_devlink.c
index cf685eeea198..91b545ab8b8f 100644
--- a/drivers/net/ethernet/intel/ice/ice_devlink.c
+++ b/drivers/net/ethernet/intel/ice/ice_devlink.c
@@ -276,6 +276,12 @@ static int ice_devlink_info_get(struct devlink *devlink,
size_t i;
int err;
+ err = ice_wait_for_reset(pf, 10 * HZ);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "Device is busy resetting");
+ return err;
+ }
+
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
@@ -283,6 +289,9 @@ static int ice_devlink_info_get(struct devlink *devlink,
/* discover capabilities first */
status = ice_discover_dev_caps(hw, &ctx->dev_caps);
if (status) {
+ dev_dbg(dev, "Failed to discover device capabilities, status %s aq_err %s\n",
+ ice_stat_str(status), ice_aq_str(hw->adminq.sq_last_status));
+ NL_SET_ERR_MSG_MOD(extack, "Unable to discover device capabilities");
err = -EIO;
goto out_free_ctx;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 99301ad95290..d95a5daca114 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -3195,6 +3195,31 @@ ice_set_rxfh(struct net_device *netdev, const u32 *indir, const u8 *key,
return 0;
}
+static int
+ice_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
+{
+ struct ice_pf *pf = ice_netdev_to_pf(dev);
+
+ /* only report timestamping if PTP is enabled */
+ if (!test_bit(ICE_FLAG_PTP, pf->flags))
+ return ethtool_op_get_ts_info(dev, info);
+
+ info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE |
+ SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+
+ info->phc_index = ice_get_ptp_clock_index(pf);
+
+ info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
+
+ info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
+
+ return 0;
+}
+
/**
* ice_get_max_txq - return the maximum number of Tx queues for in a PF
* @pf: PF structure
@@ -3462,13 +3487,9 @@ static int
ice_get_rc_coalesce(struct ethtool_coalesce *ec, enum ice_container_type c_type,
struct ice_ring_container *rc)
{
- struct ice_pf *pf;
-
if (!rc->ring)
return -EINVAL;
- pf = rc->ring->vsi->back;
-
switch (c_type) {
case ICE_RX_CONTAINER:
ec->use_adaptive_rx_coalesce = ITR_IS_DYNAMIC(rc);
@@ -3480,7 +3501,7 @@ ice_get_rc_coalesce(struct ethtool_coalesce *ec, enum ice_container_type c_type,
ec->tx_coalesce_usecs = rc->itr_setting;
break;
default:
- dev_dbg(ice_pf_to_dev(pf), "Invalid c_type %d\n", c_type);
+ dev_dbg(ice_pf_to_dev(rc->ring->vsi->back), "Invalid c_type %d\n", c_type);
return -EINVAL;
}
@@ -3990,7 +4011,7 @@ static const struct ethtool_ops ice_ethtool_ops = {
.set_rxfh = ice_set_rxfh,
.get_channels = ice_get_channels,
.set_channels = ice_set_channels,
- .get_ts_info = ethtool_op_get_ts_info,
+ .get_ts_info = ice_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,
diff --git a/drivers/net/ethernet/intel/ice/ice_fw_update.c b/drivers/net/ethernet/intel/ice/ice_fw_update.c
index dcec0360ce55..f8601d5b0b19 100644
--- a/drivers/net/ethernet/intel/ice/ice_fw_update.c
+++ b/drivers/net/ethernet/intel/ice/ice_fw_update.c
@@ -702,6 +702,16 @@ int ice_flash_pldm_image(struct ice_pf *pf, const struct firmware *fw,
}
err = pldmfw_flash_image(&priv.context, fw);
+ if (err == -ENOENT) {
+ dev_err(dev, "Firmware image has no record matching this device\n");
+ NL_SET_ERR_MSG_MOD(extack, "Firmware image has no record matching this device");
+ } else if (err) {
+ /* Do not set a generic extended ACK message here. A more
+ * specific message may already have been set by one of our
+ * ops.
+ */
+ dev_err(dev, "Failed to flash PLDM image, err %d", err);
+ }
ice_release_nvm(hw);
diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
index 9b8300d4a267..76021d977b60 100644
--- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
+++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
@@ -52,6 +52,54 @@
#define PF_MBX_ATQLEN_ATQCRIT_M BIT(30)
#define PF_MBX_ATQLEN_ATQENABLE_M BIT(31)
#define PF_MBX_ATQT 0x0022E300
+#define PF_SB_ARQBAH 0x0022FF00
+#define PF_SB_ARQBAH_ARQBAH_S 0
+#define PF_SB_ARQBAH_ARQBAH_M ICE_M(0xFFFFFFFF, 0)
+#define PF_SB_ARQBAL 0x0022FE80
+#define PF_SB_ARQBAL_ARQBAL_LSB_S 0
+#define PF_SB_ARQBAL_ARQBAL_LSB_M ICE_M(0x3F, 0)
+#define PF_SB_ARQBAL_ARQBAL_S 6
+#define PF_SB_ARQBAL_ARQBAL_M ICE_M(0x3FFFFFF, 6)
+#define PF_SB_ARQH 0x00230000
+#define PF_SB_ARQH_ARQH_S 0
+#define PF_SB_ARQH_ARQH_M ICE_M(0x3FF, 0)
+#define PF_SB_ARQLEN 0x0022FF80
+#define PF_SB_ARQLEN_ARQLEN_S 0
+#define PF_SB_ARQLEN_ARQLEN_M ICE_M(0x3FF, 0)
+#define PF_SB_ARQLEN_ARQVFE_S 28
+#define PF_SB_ARQLEN_ARQVFE_M BIT(28)
+#define PF_SB_ARQLEN_ARQOVFL_S 29
+#define PF_SB_ARQLEN_ARQOVFL_M BIT(29)
+#define PF_SB_ARQLEN_ARQCRIT_S 30
+#define PF_SB_ARQLEN_ARQCRIT_M BIT(30)
+#define PF_SB_ARQLEN_ARQENABLE_S 31
+#define PF_SB_ARQLEN_ARQENABLE_M BIT(31)
+#define PF_SB_ARQT 0x00230080
+#define PF_SB_ARQT_ARQT_S 0
+#define PF_SB_ARQT_ARQT_M ICE_M(0x3FF, 0)
+#define PF_SB_ATQBAH 0x0022FC80
+#define PF_SB_ATQBAH_ATQBAH_S 0
+#define PF_SB_ATQBAH_ATQBAH_M ICE_M(0xFFFFFFFF, 0)
+#define PF_SB_ATQBAL 0x0022FC00
+#define PF_SB_ATQBAL_ATQBAL_S 6
+#define PF_SB_ATQBAL_ATQBAL_M ICE_M(0x3FFFFFF, 6)
+#define PF_SB_ATQH 0x0022FD80
+#define PF_SB_ATQH_ATQH_S 0
+#define PF_SB_ATQH_ATQH_M ICE_M(0x3FF, 0)
+#define PF_SB_ATQLEN 0x0022FD00
+#define PF_SB_ATQLEN_ATQLEN_S 0
+#define PF_SB_ATQLEN_ATQLEN_M ICE_M(0x3FF, 0)
+#define PF_SB_ATQLEN_ATQVFE_S 28
+#define PF_SB_ATQLEN_ATQVFE_M BIT(28)
+#define PF_SB_ATQLEN_ATQOVFL_S 29
+#define PF_SB_ATQLEN_ATQOVFL_M BIT(29)
+#define PF_SB_ATQLEN_ATQCRIT_S 30
+#define PF_SB_ATQLEN_ATQCRIT_M BIT(30)
+#define PF_SB_ATQLEN_ATQENABLE_S 31
+#define PF_SB_ATQLEN_ATQENABLE_M BIT(31)
+#define PF_SB_ATQT 0x0022FE00
+#define PF_SB_ATQT_ATQT_S 0
+#define PF_SB_ATQT_ATQT_M ICE_M(0x3FF, 0)
#define PRTDCB_GENC 0x00083000
#define PRTDCB_GENC_PFCLDA_S 16
#define PRTDCB_GENC_PFCLDA_M ICE_M(0xFFFF, 16)
@@ -90,6 +138,10 @@
#define GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_S 4
#define GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_M ICE_M(0x3, 4)
#define GLGEN_CLKSTAT_SRC 0x000B826C
+#define GLGEN_GPIO_CTL(_i) (0x000880C8 + ((_i) * 4))
+#define GLGEN_GPIO_CTL_PIN_DIR_M BIT(4)
+#define GLGEN_GPIO_CTL_PIN_FUNC_S 8
+#define GLGEN_GPIO_CTL_PIN_FUNC_M ICE_M(0xF, 8)
#define GLGEN_RSTAT 0x000B8188
#define GLGEN_RSTAT_DEVSTATE_M ICE_M(0x3, 0)
#define GLGEN_RSTCTL 0x000B8180
@@ -111,8 +163,6 @@
#define VPGEN_VFRSTAT_VFRD_M BIT(0)
#define VPGEN_VFRTRIG(_VF) (0x00090000 + ((_VF) * 4))
#define VPGEN_VFRTRIG_VFSWR_M BIT(0)
-#define PFHMC_ERRORDATA 0x00520500
-#define PFHMC_ERRORINFO 0x00520400
#define GLINT_CTL 0x0016CC54
#define GLINT_CTL_DIS_AUTOMASK_M BIT(0)
#define GLINT_CTL_ITR_GRAN_200_S 16
@@ -156,11 +206,14 @@
#define PFINT_MBX_CTL_ITR_INDX_M ICE_M(0x3, 11)
#define PFINT_MBX_CTL_CAUSE_ENA_M BIT(30)
#define PFINT_OICR 0x0016CA00
+#define PFINT_OICR_TSYN_TX_M BIT(11)
+#define PFINT_OICR_TSYN_EVNT_M BIT(12)
#define PFINT_OICR_ECC_ERR_M BIT(16)
#define PFINT_OICR_MAL_DETECT_M BIT(19)
#define PFINT_OICR_GRST_M BIT(20)
#define PFINT_OICR_PCI_EXCEPTION_M BIT(21)
#define PFINT_OICR_HMC_ERR_M BIT(26)
+#define PFINT_OICR_PE_PUSH_M BIT(27)
#define PFINT_OICR_PE_CRITERR_M BIT(28)
#define PFINT_OICR_VFLR_M BIT(29)
#define PFINT_OICR_SWINT_M BIT(31)
@@ -170,6 +223,9 @@
#define PFINT_OICR_CTL_ITR_INDX_M ICE_M(0x3, 11)
#define PFINT_OICR_CTL_CAUSE_ENA_M BIT(30)
#define PFINT_OICR_ENA 0x0016C900
+#define PFINT_SB_CTL 0x0016B600
+#define PFINT_SB_CTL_MSIX_INDX_M ICE_M(0x7FF, 0)
+#define PFINT_SB_CTL_CAUSE_ENA_M BIT(30)
#define QINT_RQCTL(_QRX) (0x00150000 + ((_QRX) * 4))
#define QINT_RQCTL_MSIX_INDX_S 0
#define QINT_RQCTL_MSIX_INDX_M ICE_M(0x7FF, 0)
@@ -383,6 +439,36 @@
#define GLV_UPRCL(_i) (0x003B2000 + ((_i) * 8))
#define GLV_UPTCL(_i) (0x0030A000 + ((_i) * 8))
#define PRTRPB_RDPC 0x000AC260
+#define GLTSYN_AUX_IN_0(_i) (0x000889D8 + ((_i) * 4))
+#define GLTSYN_AUX_IN_0_INT_ENA_M BIT(4)
+#define GLTSYN_AUX_OUT_0(_i) (0x00088998 + ((_i) * 4))
+#define GLTSYN_AUX_OUT_0_OUT_ENA_M BIT(0)
+#define GLTSYN_AUX_OUT_0_OUTMOD_M ICE_M(0x3, 1)
+#define GLTSYN_CLKO_0(_i) (0x000889B8 + ((_i) * 4))
+#define GLTSYN_CMD 0x00088810
+#define GLTSYN_CMD_SYNC 0x00088814
+#define GLTSYN_ENA(_i) (0x00088808 + ((_i) * 4))
+#define GLTSYN_ENA_TSYN_ENA_M BIT(0)
+#define GLTSYN_EVNT_H_0(_i) (0x00088970 + ((_i) * 4))
+#define GLTSYN_EVNT_L_0(_i) (0x00088968 + ((_i) * 4))
+#define GLTSYN_INCVAL_H(_i) (0x00088920 + ((_i) * 4))
+#define GLTSYN_INCVAL_L(_i) (0x00088918 + ((_i) * 4))
+#define GLTSYN_SHADJ_H(_i) (0x00088910 + ((_i) * 4))
+#define GLTSYN_SHADJ_L(_i) (0x00088908 + ((_i) * 4))
+#define GLTSYN_SHTIME_0(_i) (0x000888E0 + ((_i) * 4))
+#define GLTSYN_SHTIME_H(_i) (0x000888F0 + ((_i) * 4))
+#define GLTSYN_SHTIME_L(_i) (0x000888E8 + ((_i) * 4))
+#define GLTSYN_STAT(_i) (0x000888C0 + ((_i) * 4))
+#define GLTSYN_STAT_EVENT0_M BIT(0)
+#define GLTSYN_STAT_EVENT1_M BIT(1)
+#define GLTSYN_STAT_EVENT2_M BIT(2)
+#define GLTSYN_SYNC_DLAY 0x00088818
+#define GLTSYN_TGT_H_0(_i) (0x00088930 + ((_i) * 4))
+#define GLTSYN_TGT_L_0(_i) (0x00088928 + ((_i) * 4))
+#define GLTSYN_TIME_H(_i) (0x000888D8 + ((_i) * 4))
+#define GLTSYN_TIME_L(_i) (0x000888D0 + ((_i) * 4))
+#define PFTSYN_SEM 0x00088880
+#define PFTSYN_SEM_BUSY_M BIT(0)
#define VSIQF_FD_CNT(_VSI) (0x00464000 + ((_VSI) * 4))
#define VSIQF_FD_CNT_FD_GCNT_S 0
#define VSIQF_FD_CNT_FD_GCNT_M ICE_M(0x3FFF, 0)
diff --git a/drivers/net/ethernet/intel/ice/ice_idc.c b/drivers/net/ethernet/intel/ice/ice_idc.c
new file mode 100644
index 000000000000..1f2afdf6cd48
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_idc.c
@@ -0,0 +1,334 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2021, Intel Corporation. */
+
+/* Inter-Driver Communication */
+#include "ice.h"
+#include "ice_lib.h"
+#include "ice_dcb_lib.h"
+
+/**
+ * ice_get_auxiliary_drv - retrieve iidc_auxiliary_drv struct
+ * @pf: pointer to PF struct
+ *
+ * This function has to be called with a device_lock on the
+ * pf->adev.dev to avoid race conditions.
+ */
+static struct iidc_auxiliary_drv *ice_get_auxiliary_drv(struct ice_pf *pf)
+{
+ struct auxiliary_device *adev;
+
+ adev = pf->adev;
+ if (!adev || !adev->dev.driver)
+ return NULL;
+
+ return container_of(adev->dev.driver, struct iidc_auxiliary_drv,
+ adrv.driver);
+}
+
+/**
+ * ice_send_event_to_aux - send event to RDMA AUX driver
+ * @pf: pointer to PF struct
+ * @event: event struct
+ */
+void ice_send_event_to_aux(struct ice_pf *pf, struct iidc_event *event)
+{
+ struct iidc_auxiliary_drv *iadrv;
+
+ if (!pf->adev)
+ return;
+
+ device_lock(&pf->adev->dev);
+ iadrv = ice_get_auxiliary_drv(pf);
+ if (iadrv && iadrv->event_handler)
+ iadrv->event_handler(pf, event);
+ device_unlock(&pf->adev->dev);
+}
+
+/**
+ * ice_find_vsi - Find the VSI from VSI ID
+ * @pf: The PF pointer to search in
+ * @vsi_num: The VSI ID to search for
+ */
+static struct ice_vsi *ice_find_vsi(struct ice_pf *pf, u16 vsi_num)
+{
+ int i;
+
+ ice_for_each_vsi(pf, i)
+ if (pf->vsi[i] && pf->vsi[i]->vsi_num == vsi_num)
+ return pf->vsi[i];
+ return NULL;
+}
+
+/**
+ * ice_add_rdma_qset - Add Leaf Node for RDMA Qset
+ * @pf: PF struct
+ * @qset: Resource to be allocated
+ */
+int ice_add_rdma_qset(struct ice_pf *pf, struct iidc_rdma_qset_params *qset)
+{
+ u16 max_rdmaqs[ICE_MAX_TRAFFIC_CLASS];
+ struct ice_vsi *vsi;
+ struct device *dev;
+ u32 qset_teid;
+ u16 qs_handle;
+ int status;
+ int i;
+
+ if (WARN_ON(!pf || !qset))
+ return -EINVAL;
+
+ dev = ice_pf_to_dev(pf);
+
+ if (!test_bit(ICE_FLAG_RDMA_ENA, pf->flags))
+ return -EINVAL;
+
+ vsi = ice_get_main_vsi(pf);
+ if (!vsi) {
+ dev_err(dev, "RDMA QSet invalid VSI\n");
+ return -EINVAL;
+ }
+
+ ice_for_each_traffic_class(i)
+ max_rdmaqs[i] = 0;
+
+ max_rdmaqs[qset->tc]++;
+ qs_handle = qset->qs_handle;
+
+ status = ice_cfg_vsi_rdma(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc,
+ max_rdmaqs);
+ if (status) {
+ dev_err(dev, "Failed VSI RDMA Qset config\n");
+ return status;
+ }
+
+ status = ice_ena_vsi_rdma_qset(vsi->port_info, vsi->idx, qset->tc,
+ &qs_handle, 1, &qset_teid);
+ if (status) {
+ dev_err(dev, "Failed VSI RDMA Qset enable\n");
+ return status;
+ }
+ vsi->qset_handle[qset->tc] = qset->qs_handle;
+ qset->teid = qset_teid;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ice_add_rdma_qset);
+
+/**
+ * ice_del_rdma_qset - Delete leaf node for RDMA Qset
+ * @pf: PF struct
+ * @qset: Resource to be freed
+ */
+int ice_del_rdma_qset(struct ice_pf *pf, struct iidc_rdma_qset_params *qset)
+{
+ struct ice_vsi *vsi;
+ u32 teid;
+ u16 q_id;
+
+ if (WARN_ON(!pf || !qset))
+ return -EINVAL;
+
+ vsi = ice_find_vsi(pf, qset->vport_id);
+ if (!vsi) {
+ dev_err(ice_pf_to_dev(pf), "RDMA Invalid VSI\n");
+ return -EINVAL;
+ }
+
+ q_id = qset->qs_handle;
+ teid = qset->teid;
+
+ vsi->qset_handle[qset->tc] = 0;
+
+ return ice_dis_vsi_rdma_qset(vsi->port_info, 1, &teid, &q_id);
+}
+EXPORT_SYMBOL_GPL(ice_del_rdma_qset);
+
+/**
+ * ice_rdma_request_reset - accept request from RDMA to perform a reset
+ * @pf: struct for PF
+ * @reset_type: type of reset
+ */
+int ice_rdma_request_reset(struct ice_pf *pf, enum iidc_reset_type reset_type)
+{
+ enum ice_reset_req reset;
+
+ if (WARN_ON(!pf))
+ return -EINVAL;
+
+ switch (reset_type) {
+ case IIDC_PFR:
+ reset = ICE_RESET_PFR;
+ break;
+ case IIDC_CORER:
+ reset = ICE_RESET_CORER;
+ break;
+ case IIDC_GLOBR:
+ reset = ICE_RESET_GLOBR;
+ break;
+ default:
+ dev_err(ice_pf_to_dev(pf), "incorrect reset request\n");
+ return -EINVAL;
+ }
+
+ return ice_schedule_reset(pf, reset);
+}
+EXPORT_SYMBOL_GPL(ice_rdma_request_reset);
+
+/**
+ * ice_rdma_update_vsi_filter - update main VSI filters for RDMA
+ * @pf: pointer to struct for PF
+ * @vsi_id: VSI HW idx to update filter on
+ * @enable: bool whether to enable or disable filters
+ */
+int ice_rdma_update_vsi_filter(struct ice_pf *pf, u16 vsi_id, bool enable)
+{
+ struct ice_vsi *vsi;
+ int status;
+
+ if (WARN_ON(!pf))
+ return -EINVAL;
+
+ vsi = ice_find_vsi(pf, vsi_id);
+ if (!vsi)
+ return -EINVAL;
+
+ status = ice_cfg_rdma_fltr(&pf->hw, vsi->idx, enable);
+ if (status) {
+ dev_err(ice_pf_to_dev(pf), "Failed to %sable RDMA filtering\n",
+ enable ? "en" : "dis");
+ } else {
+ if (enable)
+ vsi->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
+ else
+ vsi->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
+ }
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(ice_rdma_update_vsi_filter);
+
+/**
+ * ice_get_qos_params - parse QoS params for RDMA consumption
+ * @pf: pointer to PF struct
+ * @qos: set of QoS values
+ */
+void ice_get_qos_params(struct ice_pf *pf, struct iidc_qos_params *qos)
+{
+ struct ice_dcbx_cfg *dcbx_cfg;
+ unsigned int i;
+ u32 up2tc;
+
+ dcbx_cfg = &pf->hw.port_info->qos_cfg.local_dcbx_cfg;
+ up2tc = rd32(&pf->hw, PRTDCB_TUP2TC);
+
+ qos->num_tc = ice_dcb_get_num_tc(dcbx_cfg);
+ for (i = 0; i < IIDC_MAX_USER_PRIORITY; i++)
+ qos->up2tc[i] = (up2tc >> (i * 3)) & 0x7;
+
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
+ qos->tc_info[i].rel_bw = dcbx_cfg->etscfg.tcbwtable[i];
+}
+EXPORT_SYMBOL_GPL(ice_get_qos_params);
+
+/**
+ * ice_reserve_rdma_qvector - Reserve vector resources for RDMA driver
+ * @pf: board private structure to initialize
+ */
+static int ice_reserve_rdma_qvector(struct ice_pf *pf)
+{
+ if (test_bit(ICE_FLAG_RDMA_ENA, pf->flags)) {
+ int index;
+
+ index = ice_get_res(pf, pf->irq_tracker, pf->num_rdma_msix,
+ ICE_RES_RDMA_VEC_ID);
+ if (index < 0)
+ return index;
+ pf->num_avail_sw_msix -= pf->num_rdma_msix;
+ pf->rdma_base_vector = (u16)index;
+ }
+ return 0;
+}
+
+/**
+ * ice_adev_release - function to be mapped to AUX dev's release op
+ * @dev: pointer to device to free
+ */
+static void ice_adev_release(struct device *dev)
+{
+ struct iidc_auxiliary_dev *iadev;
+
+ iadev = container_of(dev, struct iidc_auxiliary_dev, adev.dev);
+ kfree(iadev);
+}
+
+/**
+ * ice_plug_aux_dev - allocate and register AUX device
+ * @pf: pointer to pf struct
+ */
+int ice_plug_aux_dev(struct ice_pf *pf)
+{
+ struct iidc_auxiliary_dev *iadev;
+ struct auxiliary_device *adev;
+ int ret;
+
+ iadev = kzalloc(sizeof(*iadev), GFP_KERNEL);
+ if (!iadev)
+ return -ENOMEM;
+
+ adev = &iadev->adev;
+ pf->adev = adev;
+ iadev->pf = pf;
+
+ adev->id = pf->aux_idx;
+ adev->dev.release = ice_adev_release;
+ adev->dev.parent = &pf->pdev->dev;
+ adev->name = IIDC_RDMA_ROCE_NAME;
+
+ ret = auxiliary_device_init(adev);
+ if (ret) {
+ pf->adev = NULL;
+ kfree(iadev);
+ return ret;
+ }
+
+ ret = auxiliary_device_add(adev);
+ if (ret) {
+ pf->adev = NULL;
+ auxiliary_device_uninit(adev);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* ice_unplug_aux_dev - unregister and free AUX device
+ * @pf: pointer to pf struct
+ */
+void ice_unplug_aux_dev(struct ice_pf *pf)
+{
+ if (!pf->adev)
+ return;
+
+ auxiliary_device_delete(pf->adev);
+ auxiliary_device_uninit(pf->adev);
+ pf->adev = NULL;
+}
+
+/**
+ * ice_init_rdma - initializes PF for RDMA use
+ * @pf: ptr to ice_pf
+ */
+int ice_init_rdma(struct ice_pf *pf)
+{
+ struct device *dev = &pf->pdev->dev;
+ int ret;
+
+ /* Reserve vector resources */
+ ret = ice_reserve_rdma_qvector(pf);
+ if (ret < 0) {
+ dev_err(dev, "failed to reserve vectors for RDMA\n");
+ return ret;
+ }
+
+ return ice_plug_aux_dev(pf);
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_idc_int.h b/drivers/net/ethernet/intel/ice/ice_idc_int.h
new file mode 100644
index 000000000000..b7796b8aecbd
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_idc_int.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2021, Intel Corporation. */
+
+#ifndef _ICE_IDC_INT_H_
+#define _ICE_IDC_INT_H_
+
+#include <linux/net/intel/iidc.h>
+#include "ice.h"
+
+struct ice_pf;
+
+void ice_send_event_to_aux(struct ice_pf *pf, struct iidc_event *event);
+
+#endif /* !_ICE_IDC_INT_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c
index 4599fc3b4ed8..37c18c66b5c7 100644
--- a/drivers/net/ethernet/intel/ice/ice_lag.c
+++ b/drivers/net/ethernet/intel/ice/ice_lag.c
@@ -172,6 +172,7 @@ ice_lag_link(struct ice_lag *lag, struct netdev_notifier_changeupper_info *info)
}
ice_clear_sriov_cap(pf);
+ ice_clear_rdma_cap(pf);
lag->bonded = true;
lag->role = ICE_LAG_UNSET;
@@ -222,6 +223,7 @@ ice_lag_unlink(struct ice_lag *lag,
}
ice_set_sriov_cap(pf);
+ ice_set_rdma_cap(pf);
lag->bonded = false;
lag->role = ICE_LAG_NONE;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
index 21329ed3087e..80736e0ec0dc 100644
--- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
+++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
@@ -161,7 +161,6 @@ struct ice_fltr_desc {
#define ICE_FXD_FLTR_WB_QW1_FAIL_PROF_YES 0x1ULL
struct ice_rx_ptype_decoded {
- u32 ptype:10;
u32 known:1;
u32 outer_ip:1;
u32 outer_ip_ver:2;
@@ -606,9 +605,32 @@ struct ice_tlan_ctx {
u8 int_q_state; /* width not needed - internal - DO NOT WRITE!!! */
};
-/* macro to make the table lines short */
+/* The ice_ptype_lkup table is used to convert from the 10-bit ptype in the
+ * hardware to a bit-field that can be used by SW to more easily determine the
+ * packet type.
+ *
+ * Macros are used to shorten the table lines and make this table human
+ * readable.
+ *
+ * We store the PTYPE in the top byte of the bit field - this is just so that
+ * we can check that the table doesn't have a row missing, as the index into
+ * the table should be the PTYPE.
+ *
+ * Typical work flow:
+ *
+ * IF NOT ice_ptype_lkup[ptype].known
+ * THEN
+ * Packet is unknown
+ * ELSE IF ice_ptype_lkup[ptype].outer_ip == ICE_RX_PTYPE_OUTER_IP
+ * Use the rest of the fields to look at the tunnels, inner protocols, etc
+ * ELSE
+ * Use the enum ice_rx_l2_ptype to decode the packet type
+ * ENDIF
+ */
+
+/* macro to make the table lines short, use explicit indexing with [PTYPE] */
#define ICE_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\
- { PTYPE, \
+ [PTYPE] = { \
1, \
ICE_RX_PTYPE_OUTER_##OUTER_IP, \
ICE_RX_PTYPE_OUTER_##OUTER_IP_VER, \
@@ -619,18 +641,18 @@ struct ice_tlan_ctx {
ICE_RX_PTYPE_INNER_PROT_##I, \
ICE_RX_PTYPE_PAYLOAD_LAYER_##PL }
-#define ICE_PTT_UNUSED_ENTRY(PTYPE) { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+#define ICE_PTT_UNUSED_ENTRY(PTYPE) [PTYPE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
/* shorter macros makes the table fit but are terse */
#define ICE_RX_PTYPE_NOF ICE_RX_PTYPE_NOT_FRAG
#define ICE_RX_PTYPE_FRG ICE_RX_PTYPE_FRAG
-/* Lookup table mapping the HW PTYPE to the bit field for decoding */
-static const struct ice_rx_ptype_decoded ice_ptype_lkup[] = {
+/* Lookup table mapping in the 10-bit HW PTYPE to the bit field for decoding */
+static const struct ice_rx_ptype_decoded ice_ptype_lkup[BIT(10)] = {
/* L2 Packet types */
ICE_PTT_UNUSED_ENTRY(0),
ICE_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
- ICE_PTT(2, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),
+ ICE_PTT_UNUSED_ENTRY(2),
ICE_PTT_UNUSED_ENTRY(3),
ICE_PTT_UNUSED_ENTRY(4),
ICE_PTT_UNUSED_ENTRY(5),
@@ -744,7 +766,7 @@ static const struct ice_rx_ptype_decoded ice_ptype_lkup[] = {
/* Non Tunneled IPv6 */
ICE_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3),
ICE_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3),
- ICE_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP, PAY3),
+ ICE_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP, PAY4),
ICE_PTT_UNUSED_ENTRY(91),
ICE_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP, PAY4),
ICE_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4),
@@ -832,118 +854,7 @@ static const struct ice_rx_ptype_decoded ice_ptype_lkup[] = {
ICE_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
/* unused entries */
- ICE_PTT_UNUSED_ENTRY(154),
- ICE_PTT_UNUSED_ENTRY(155),
- ICE_PTT_UNUSED_ENTRY(156),
- ICE_PTT_UNUSED_ENTRY(157),
- ICE_PTT_UNUSED_ENTRY(158),
- ICE_PTT_UNUSED_ENTRY(159),
-
- ICE_PTT_UNUSED_ENTRY(160),
- ICE_PTT_UNUSED_ENTRY(161),
- ICE_PTT_UNUSED_ENTRY(162),
- ICE_PTT_UNUSED_ENTRY(163),
- ICE_PTT_UNUSED_ENTRY(164),
- ICE_PTT_UNUSED_ENTRY(165),
- ICE_PTT_UNUSED_ENTRY(166),
- ICE_PTT_UNUSED_ENTRY(167),
- ICE_PTT_UNUSED_ENTRY(168),
- ICE_PTT_UNUSED_ENTRY(169),
-
- ICE_PTT_UNUSED_ENTRY(170),
- ICE_PTT_UNUSED_ENTRY(171),
- ICE_PTT_UNUSED_ENTRY(172),
- ICE_PTT_UNUSED_ENTRY(173),
- ICE_PTT_UNUSED_ENTRY(174),
- ICE_PTT_UNUSED_ENTRY(175),
- ICE_PTT_UNUSED_ENTRY(176),
- ICE_PTT_UNUSED_ENTRY(177),
- ICE_PTT_UNUSED_ENTRY(178),
- ICE_PTT_UNUSED_ENTRY(179),
-
- ICE_PTT_UNUSED_ENTRY(180),
- ICE_PTT_UNUSED_ENTRY(181),
- ICE_PTT_UNUSED_ENTRY(182),
- ICE_PTT_UNUSED_ENTRY(183),
- ICE_PTT_UNUSED_ENTRY(184),
- ICE_PTT_UNUSED_ENTRY(185),
- ICE_PTT_UNUSED_ENTRY(186),
- ICE_PTT_UNUSED_ENTRY(187),
- ICE_PTT_UNUSED_ENTRY(188),
- ICE_PTT_UNUSED_ENTRY(189),
-
- ICE_PTT_UNUSED_ENTRY(190),
- ICE_PTT_UNUSED_ENTRY(191),
- ICE_PTT_UNUSED_ENTRY(192),
- ICE_PTT_UNUSED_ENTRY(193),
- ICE_PTT_UNUSED_ENTRY(194),
- ICE_PTT_UNUSED_ENTRY(195),
- ICE_PTT_UNUSED_ENTRY(196),
- ICE_PTT_UNUSED_ENTRY(197),
- ICE_PTT_UNUSED_ENTRY(198),
- ICE_PTT_UNUSED_ENTRY(199),
-
- ICE_PTT_UNUSED_ENTRY(200),
- ICE_PTT_UNUSED_ENTRY(201),
- ICE_PTT_UNUSED_ENTRY(202),
- ICE_PTT_UNUSED_ENTRY(203),
- ICE_PTT_UNUSED_ENTRY(204),
- ICE_PTT_UNUSED_ENTRY(205),
- ICE_PTT_UNUSED_ENTRY(206),
- ICE_PTT_UNUSED_ENTRY(207),
- ICE_PTT_UNUSED_ENTRY(208),
- ICE_PTT_UNUSED_ENTRY(209),
-
- ICE_PTT_UNUSED_ENTRY(210),
- ICE_PTT_UNUSED_ENTRY(211),
- ICE_PTT_UNUSED_ENTRY(212),
- ICE_PTT_UNUSED_ENTRY(213),
- ICE_PTT_UNUSED_ENTRY(214),
- ICE_PTT_UNUSED_ENTRY(215),
- ICE_PTT_UNUSED_ENTRY(216),
- ICE_PTT_UNUSED_ENTRY(217),
- ICE_PTT_UNUSED_ENTRY(218),
- ICE_PTT_UNUSED_ENTRY(219),
-
- ICE_PTT_UNUSED_ENTRY(220),
- ICE_PTT_UNUSED_ENTRY(221),
- ICE_PTT_UNUSED_ENTRY(222),
- ICE_PTT_UNUSED_ENTRY(223),
- ICE_PTT_UNUSED_ENTRY(224),
- ICE_PTT_UNUSED_ENTRY(225),
- ICE_PTT_UNUSED_ENTRY(226),
- ICE_PTT_UNUSED_ENTRY(227),
- ICE_PTT_UNUSED_ENTRY(228),
- ICE_PTT_UNUSED_ENTRY(229),
-
- ICE_PTT_UNUSED_ENTRY(230),
- ICE_PTT_UNUSED_ENTRY(231),
- ICE_PTT_UNUSED_ENTRY(232),
- ICE_PTT_UNUSED_ENTRY(233),
- ICE_PTT_UNUSED_ENTRY(234),
- ICE_PTT_UNUSED_ENTRY(235),
- ICE_PTT_UNUSED_ENTRY(236),
- ICE_PTT_UNUSED_ENTRY(237),
- ICE_PTT_UNUSED_ENTRY(238),
- ICE_PTT_UNUSED_ENTRY(239),
-
- ICE_PTT_UNUSED_ENTRY(240),
- ICE_PTT_UNUSED_ENTRY(241),
- ICE_PTT_UNUSED_ENTRY(242),
- ICE_PTT_UNUSED_ENTRY(243),
- ICE_PTT_UNUSED_ENTRY(244),
- ICE_PTT_UNUSED_ENTRY(245),
- ICE_PTT_UNUSED_ENTRY(246),
- ICE_PTT_UNUSED_ENTRY(247),
- ICE_PTT_UNUSED_ENTRY(248),
- ICE_PTT_UNUSED_ENTRY(249),
-
- ICE_PTT_UNUSED_ENTRY(250),
- ICE_PTT_UNUSED_ENTRY(251),
- ICE_PTT_UNUSED_ENTRY(252),
- ICE_PTT_UNUSED_ENTRY(253),
- ICE_PTT_UNUSED_ENTRY(254),
- ICE_PTT_UNUSED_ENTRY(255),
+ [154 ... 1023] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
static inline struct ice_rx_ptype_decoded ice_decode_rx_desc_ptype(u16 ptype)
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 27f9dac8719c..dde9802c6c72 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -169,12 +169,13 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id)
switch (vsi->type) {
case ICE_VSI_PF:
- vsi->alloc_txq = min3(pf->num_lan_msix,
- ice_get_avail_txq_count(pf),
- (u16)num_online_cpus());
if (vsi->req_txq) {
vsi->alloc_txq = vsi->req_txq;
vsi->num_txq = vsi->req_txq;
+ } else {
+ vsi->alloc_txq = min3(pf->num_lan_msix,
+ ice_get_avail_txq_count(pf),
+ (u16)num_online_cpus());
}
pf->num_lan_tx = vsi->alloc_txq;
@@ -183,12 +184,13 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id)
if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {
vsi->alloc_rxq = 1;
} else {
- vsi->alloc_rxq = min3(pf->num_lan_msix,
- ice_get_avail_rxq_count(pf),
- (u16)num_online_cpus());
if (vsi->req_rxq) {
vsi->alloc_rxq = vsi->req_rxq;
vsi->num_rxq = vsi->req_rxq;
+ } else {
+ vsi->alloc_rxq = min3(pf->num_lan_msix,
+ ice_get_avail_rxq_count(pf),
+ (u16)num_online_cpus());
}
}
@@ -629,6 +631,17 @@ bool ice_is_safe_mode(struct ice_pf *pf)
}
/**
+ * ice_is_aux_ena
+ * @pf: pointer to the PF struct
+ *
+ * returns true if AUX devices/drivers are supported, false otherwise
+ */
+bool ice_is_aux_ena(struct ice_pf *pf)
+{
+ return test_bit(ICE_FLAG_AUX_ENA, pf->flags);
+}
+
+/**
* ice_vsi_clean_rss_flow_fld - Delete RSS configuration
* @vsi: the VSI being cleaned up
*
@@ -1192,11 +1205,11 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi)
num_q_vectors = vsi->num_q_vectors;
/* reserve slots from OS requested IRQs */
if (vsi->type == ICE_VSI_CTRL && vsi->vf_id != ICE_INVAL_VFID) {
- struct ice_vf *vf;
int i;
ice_for_each_vf(pf, i) {
- vf = &pf->vf[i];
+ struct ice_vf *vf = &pf->vf[i];
+
if (i != vsi->vf_id && vf->ctrl_vsi_idx != ICE_NO_VSI) {
base = pf->vsi[vf->ctrl_vsi_idx]->base_vector;
break;
@@ -1285,6 +1298,7 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi)
ring->reg_idx = vsi->txq_map[i];
ring->ring_active = false;
ring->vsi = vsi;
+ ring->tx_tstamps = &pf->ptp.port.tx;
ring->dev = dev;
ring->count = vsi->num_tx_desc;
WRITE_ONCE(vsi->tx_rings[i], ring);
@@ -1662,9 +1676,11 @@ void ice_vsi_cfg_frame_size(struct ice_vsi *vsi)
* @pf_q: index of the Rx queue in the PF's queue space
* @rxdid: flexible descriptor RXDID
* @prio: priority for the RXDID for this queue
+ * @ena_ts: true to enable timestamp and false to disable timestamp
*/
void
-ice_write_qrxflxp_cntxt(struct ice_hw *hw, u16 pf_q, u32 rxdid, u32 prio)
+ice_write_qrxflxp_cntxt(struct ice_hw *hw, u16 pf_q, u32 rxdid, u32 prio,
+ bool ena_ts)
{
int regval = rd32(hw, QRXFLXP_CNTXT(pf_q));
@@ -1679,9 +1695,40 @@ ice_write_qrxflxp_cntxt(struct ice_hw *hw, u16 pf_q, u32 rxdid, u32 prio)
regval |= (prio << QRXFLXP_CNTXT_RXDID_PRIO_S) &
QRXFLXP_CNTXT_RXDID_PRIO_M;
+ if (ena_ts)
+ /* Enable TimeSync on this queue */
+ regval |= QRXFLXP_CNTXT_TS_M;
+
wr32(hw, QRXFLXP_CNTXT(pf_q), regval);
}
+int ice_vsi_cfg_single_rxq(struct ice_vsi *vsi, u16 q_idx)
+{
+ if (q_idx >= vsi->num_rxq)
+ return -EINVAL;
+
+ return ice_vsi_cfg_rxq(vsi->rx_rings[q_idx]);
+}
+
+int ice_vsi_cfg_single_txq(struct ice_vsi *vsi, struct ice_ring **tx_rings, u16 q_idx)
+{
+ struct ice_aqc_add_tx_qgrp *qg_buf;
+ int err;
+
+ if (q_idx >= vsi->alloc_txq || !tx_rings || !tx_rings[q_idx])
+ return -EINVAL;
+
+ qg_buf = kzalloc(struct_size(qg_buf, txqs, 1), GFP_KERNEL);
+ if (!qg_buf)
+ return -ENOMEM;
+
+ qg_buf->num_txqs = 1;
+
+ err = ice_vsi_cfg_txq(vsi, tx_rings[q_idx], qg_buf);
+ kfree(qg_buf);
+ return err;
+}
+
/**
* ice_vsi_cfg_rxqs - Configure the VSI for Rx
* @vsi: the VSI being configured
@@ -1699,15 +1746,11 @@ int ice_vsi_cfg_rxqs(struct ice_vsi *vsi)
ice_vsi_cfg_frame_size(vsi);
setup_rings:
/* set up individual rings */
- for (i = 0; i < vsi->num_rxq; i++) {
- int err;
+ ice_for_each_rxq(vsi, i) {
+ int err = ice_vsi_cfg_rxq(vsi->rx_rings[i]);
- err = ice_setup_rx_ctx(vsi->rx_rings[i]);
- if (err) {
- dev_err(ice_pf_to_dev(vsi->back), "ice_setup_rx_ctx failed for RxQ %d, err %d\n",
- i, err);
+ if (err)
return err;
- }
}
return 0;
@@ -2217,7 +2260,7 @@ void ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create)
}
if (status)
- dev_err(dev, "Fail %s %s LLDP rule on VSI %i error: %s\n",
+ dev_dbg(dev, "Fail %s %s LLDP rule on VSI %i error: %s\n",
create ? "adding" : "removing", tx ? "TX" : "RX",
vsi->vsi_num, ice_stat_str(status));
}
@@ -2832,11 +2875,11 @@ int ice_vsi_release(struct ice_vsi *vsi)
* cleared in the same manner.
*/
if (vsi->type == ICE_VSI_CTRL && vsi->vf_id != ICE_INVAL_VFID) {
- struct ice_vf *vf;
int i;
ice_for_each_vf(pf, i) {
- vf = &pf->vf[i];
+ struct ice_vf *vf = &pf->vf[i];
+
if (i != vsi->vf_id && vf->ctrl_vsi_idx != ICE_NO_VSI)
break;
}
@@ -3196,6 +3239,34 @@ bool ice_is_reset_in_progress(unsigned long *state)
test_bit(ICE_GLOBR_REQ, state);
}
+/**
+ * ice_wait_for_reset - Wait for driver to finish reset and rebuild
+ * @pf: pointer to the PF structure
+ * @timeout: length of time to wait, in jiffies
+ *
+ * Wait (sleep) for a short time until the driver finishes cleaning up from
+ * a device reset. The caller must be able to sleep. Use this to delay
+ * operations that could fail while the driver is cleaning up after a device
+ * reset.
+ *
+ * Returns 0 on success, -EBUSY if the reset is not finished within the
+ * timeout, and -ERESTARTSYS if the thread was interrupted.
+ */
+int ice_wait_for_reset(struct ice_pf *pf, unsigned long timeout)
+{
+ long ret;
+
+ ret = wait_event_interruptible_timeout(pf->reset_wait_queue,
+ !ice_is_reset_in_progress(pf->state),
+ timeout);
+ if (ret < 0)
+ return ret;
+ else if (!ret)
+ return -EBUSY;
+ else
+ return 0;
+}
+
#ifdef CONFIG_DCB
/**
* ice_vsi_update_q_map - update our copy of the VSI info with new queue map
@@ -3330,13 +3401,22 @@ int ice_status_to_errno(enum ice_status err)
case ICE_ERR_DOES_NOT_EXIST:
return -ENOENT;
case ICE_ERR_OUT_OF_RANGE:
- return -ENOTTY;
+ case ICE_ERR_AQ_ERROR:
+ case ICE_ERR_AQ_TIMEOUT:
+ case ICE_ERR_AQ_EMPTY:
+ case ICE_ERR_AQ_FW_CRITICAL:
+ return -EIO;
case ICE_ERR_PARAM:
+ case ICE_ERR_INVAL_SIZE:
return -EINVAL;
case ICE_ERR_NO_MEMORY:
return -ENOMEM;
case ICE_ERR_MAX_LIMIT:
return -EAGAIN;
+ case ICE_ERR_RESET_ONGOING:
+ return -EBUSY;
+ case ICE_ERR_AQ_FULL:
+ return -ENOSPC;
default:
return -EINVAL;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h
index 511c2316c40c..d5a28bf0fc2c 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_lib.h
@@ -12,6 +12,10 @@ bool ice_pf_state_is_nominal(struct ice_pf *pf);
void ice_update_eth_stats(struct ice_vsi *vsi);
+int ice_vsi_cfg_single_rxq(struct ice_vsi *vsi, u16 q_idx);
+
+int ice_vsi_cfg_single_txq(struct ice_vsi *vsi, struct ice_ring **tx_rings, u16 q_idx);
+
int ice_vsi_cfg_rxqs(struct ice_vsi *vsi);
int ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi);
@@ -73,9 +77,11 @@ ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id);
int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi);
bool ice_is_reset_in_progress(unsigned long *state);
+int ice_wait_for_reset(struct ice_pf *pf, unsigned long timeout);
void
-ice_write_qrxflxp_cntxt(struct ice_hw *hw, u16 pf_q, u32 rxdid, u32 prio);
+ice_write_qrxflxp_cntxt(struct ice_hw *hw, u16 pf_q, u32 rxdid, u32 prio,
+ bool ena_ts);
void ice_vsi_dis_irq(struct ice_vsi *vsi);
@@ -102,7 +108,7 @@ enum ice_status
ice_vsi_cfg_mac_fltr(struct ice_vsi *vsi, const u8 *macaddr, bool set);
bool ice_is_safe_mode(struct ice_pf *pf);
-
+bool ice_is_aux_ena(struct ice_pf *pf);
bool ice_is_dflt_vsi_in_use(struct ice_sw *sw);
bool ice_is_vsi_dflt_vsi(struct ice_sw *sw, struct ice_vsi *vsi);
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 0eb2307325d3..ef8d1815af56 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -13,6 +13,12 @@
#include "ice_dcb_lib.h"
#include "ice_dcb_nl.h"
#include "ice_devlink.h"
+/* Including ice_trace.h with CREATE_TRACE_POINTS defined will generate the
+ * ice tracepoint functions. This must be done exactly once across the
+ * ice driver.
+ */
+#define CREATE_TRACE_POINTS
+#include "ice_trace.h"
#define DRV_SUMMARY "Intel(R) Ethernet Connection E800 Series Linux Driver"
static const char ice_driver_string[] = DRV_SUMMARY;
@@ -35,6 +41,8 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all), hw debug_mask (0x8XXXX
MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
#endif /* !CONFIG_DYNAMIC_DEBUG */
+static DEFINE_IDA(ice_aux_ida);
+
static struct workqueue_struct *ice_wq;
static const struct net_device_ops ice_netdev_safe_mode_ops;
static const struct net_device_ops ice_netdev_ops;
@@ -454,6 +462,8 @@ ice_prepare_for_reset(struct ice_pf *pf)
if (test_bit(ICE_PREPARED_FOR_RESET, pf->state))
return;
+ ice_unplug_aux_dev(pf);
+
/* Notify VFs of impending reset */
if (ice_check_sq_alive(hw, &hw->mailboxq))
ice_vc_notify_reset(pf);
@@ -467,6 +477,9 @@ ice_prepare_for_reset(struct ice_pf *pf)
/* disable the VSIs and their queues that are not already DOWN */
ice_pf_dis_all_vsi(pf, false);
+ if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
+ ice_ptp_release(pf);
+
if (hw->port_info)
ice_sched_clear_port(hw->port_info);
@@ -499,6 +512,7 @@ static void ice_do_reset(struct ice_pf *pf, enum ice_reset_req reset_type)
clear_bit(ICE_PFR_REQ, pf->state);
clear_bit(ICE_CORER_REQ, pf->state);
clear_bit(ICE_GLOBR_REQ, pf->state);
+ wake_up(&pf->reset_wait_queue);
return;
}
@@ -511,6 +525,7 @@ static void ice_do_reset(struct ice_pf *pf, enum ice_reset_req reset_type)
ice_rebuild(pf, reset_type);
clear_bit(ICE_PREPARED_FOR_RESET, pf->state);
clear_bit(ICE_PFR_REQ, pf->state);
+ wake_up(&pf->reset_wait_queue);
ice_reset_all_vfs(pf, true);
}
}
@@ -561,6 +576,7 @@ static void ice_reset_subtask(struct ice_pf *pf)
clear_bit(ICE_PFR_REQ, pf->state);
clear_bit(ICE_CORER_REQ, pf->state);
clear_bit(ICE_GLOBR_REQ, pf->state);
+ wake_up(&pf->reset_wait_queue);
ice_reset_all_vfs(pf, true);
}
@@ -858,6 +874,38 @@ static void ice_set_dflt_mib(struct ice_pf *pf)
}
/**
+ * ice_check_module_power
+ * @pf: pointer to PF struct
+ * @link_cfg_err: bitmap from the link info structure
+ *
+ * check module power level returned by a previous call to aq_get_link_info
+ * and print error messages if module power level is not supported
+ */
+static void ice_check_module_power(struct ice_pf *pf, u8 link_cfg_err)
+{
+ /* if module power level is supported, clear the flag */
+ if (!(link_cfg_err & (ICE_AQ_LINK_INVAL_MAX_POWER_LIMIT |
+ ICE_AQ_LINK_MODULE_POWER_UNSUPPORTED))) {
+ clear_bit(ICE_FLAG_MOD_POWER_UNSUPPORTED, pf->flags);
+ return;
+ }
+
+ /* if ICE_FLAG_MOD_POWER_UNSUPPORTED was previously set and the
+ * above block didn't clear this bit, there's nothing to do
+ */
+ if (test_bit(ICE_FLAG_MOD_POWER_UNSUPPORTED, pf->flags))
+ return;
+
+ if (link_cfg_err & ICE_AQ_LINK_INVAL_MAX_POWER_LIMIT) {
+ dev_err(ice_pf_to_dev(pf), "The installed module is incompatible with the device's NVM image. Cannot start link\n");
+ set_bit(ICE_FLAG_MOD_POWER_UNSUPPORTED, pf->flags);
+ } else if (link_cfg_err & ICE_AQ_LINK_MODULE_POWER_UNSUPPORTED) {
+ dev_err(ice_pf_to_dev(pf), "The module's power requirements exceed the device's power supply. Cannot start link\n");
+ set_bit(ICE_FLAG_MOD_POWER_UNSUPPORTED, pf->flags);
+ }
+}
+
+/**
* ice_link_event - process the link event
* @pf: PF that the link event is associated with
* @pi: port_info for the port that the link event is associated with
@@ -892,6 +940,8 @@ ice_link_event(struct ice_pf *pf, struct ice_port_info *pi, bool link_up,
pi->lport, ice_stat_str(status),
ice_aq_str(pi->hw->adminq.sq_last_status));
+ ice_check_module_power(pf, pi->phy.link_info.link_cfg_err);
+
/* Check if the link state is up after updating link info, and treat
* this event as an UP event since the link is actually UP now.
*/
@@ -1190,6 +1240,10 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type)
cq = &hw->adminq;
qtype = "Admin";
break;
+ case ICE_CTL_Q_SB:
+ cq = &hw->sbq;
+ qtype = "Sideband";
+ break;
case ICE_CTL_Q_MAILBOX:
cq = &hw->mailboxq;
qtype = "Mailbox";
@@ -1364,6 +1418,34 @@ static void ice_clean_mailboxq_subtask(struct ice_pf *pf)
}
/**
+ * ice_clean_sbq_subtask - clean the Sideband Queue rings
+ * @pf: board private structure
+ */
+static void ice_clean_sbq_subtask(struct ice_pf *pf)
+{
+ struct ice_hw *hw = &pf->hw;
+
+ /* Nothing to do here if sideband queue is not supported */
+ if (!ice_is_sbq_supported(hw)) {
+ clear_bit(ICE_SIDEBANDQ_EVENT_PENDING, pf->state);
+ return;
+ }
+
+ if (!test_bit(ICE_SIDEBANDQ_EVENT_PENDING, pf->state))
+ return;
+
+ if (__ice_clean_ctrlq(pf, ICE_CTL_Q_SB))
+ return;
+
+ clear_bit(ICE_SIDEBANDQ_EVENT_PENDING, pf->state);
+
+ if (ice_ctrlq_pending(hw, &hw->sbq))
+ __ice_clean_ctrlq(pf, ICE_CTL_Q_SB);
+
+ ice_flush(hw);
+}
+
+/**
* ice_service_task_schedule - schedule the service task to wake up
* @pf: board private structure
*
@@ -2006,6 +2088,8 @@ static void ice_check_media_subtask(struct ice_pf *pf)
if (err)
return;
+ ice_check_module_power(pf, pi->phy.link_info.link_cfg_err);
+
if (pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE) {
if (!test_bit(ICE_PHY_INIT_COMPLETE, pf->state))
ice_init_phy_user_cfg(pi);
@@ -2063,6 +2147,7 @@ static void ice_service_task(struct work_struct *work)
ice_process_vflr_event(pf);
ice_clean_mailboxq_subtask(pf);
+ ice_clean_sbq_subtask(pf);
ice_sync_arfs_fltrs(pf);
ice_flush_fdir_ctx(pf);
@@ -2078,6 +2163,7 @@ static void ice_service_task(struct work_struct *work)
test_bit(ICE_VFLR_EVENT_PENDING, pf->state) ||
test_bit(ICE_MAILBOXQ_EVENT_PENDING, pf->state) ||
test_bit(ICE_FD_VF_FLUSH_CTX, pf->state) ||
+ test_bit(ICE_SIDEBANDQ_EVENT_PENDING, pf->state) ||
test_bit(ICE_ADMINQ_EVENT_PENDING, pf->state))
mod_timer(&pf->serv_tmr, jiffies);
}
@@ -2096,6 +2182,10 @@ static void ice_set_ctrlq_len(struct ice_hw *hw)
hw->mailboxq.num_sq_entries = ICE_MBXSQ_LEN;
hw->mailboxq.rq_buf_size = ICE_MBXQ_MAX_BUF_LEN;
hw->mailboxq.sq_buf_size = ICE_MBXQ_MAX_BUF_LEN;
+ hw->sbq.num_rq_entries = ICE_SBQ_LEN;
+ hw->sbq.num_sq_entries = ICE_SBQ_LEN;
+ hw->sbq.rq_buf_size = ICE_SBQ_MAX_BUF_LEN;
+ hw->sbq.sq_buf_size = ICE_SBQ_MAX_BUF_LEN;
}
/**
@@ -2118,6 +2208,8 @@ int ice_schedule_reset(struct ice_pf *pf, enum ice_reset_req reset)
return -EBUSY;
}
+ ice_unplug_aux_dev(pf);
+
switch (reset) {
case ICE_RESET_PFR:
set_bit(ICE_PFR_REQ, pf->state);
@@ -2622,6 +2714,7 @@ static void ice_ena_misc_vector(struct ice_pf *pf)
PFINT_OICR_PCI_EXCEPTION_M |
PFINT_OICR_VFLR_M |
PFINT_OICR_HMC_ERR_M |
+ PFINT_OICR_PE_PUSH_M |
PFINT_OICR_PE_CRITERR_M);
wr32(hw, PFINT_OICR_ENA, val);
@@ -2647,6 +2740,7 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
dev = ice_pf_to_dev(pf);
set_bit(ICE_ADMINQ_EVENT_PENDING, pf->state);
set_bit(ICE_MAILBOXQ_EVENT_PENDING, pf->state);
+ set_bit(ICE_SIDEBANDQ_EVENT_PENDING, pf->state);
oicr = rd32(hw, PFINT_OICR);
ena_mask = rd32(hw, PFINT_OICR_ENA);
@@ -2692,8 +2786,6 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
/* If a reset cycle isn't already in progress, we set a bit in
* pf->state so that the service task can start a reset/rebuild.
- * We also make note of which reset happened so that peer
- * devices/drivers can be informed.
*/
if (!test_and_set_bit(ICE_RESET_OICR_RECV, pf->state)) {
if (reset == ICE_RESET_CORER)
@@ -2720,11 +2812,36 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
}
}
- if (oicr & PFINT_OICR_HMC_ERR_M) {
- ena_mask &= ~PFINT_OICR_HMC_ERR_M;
- dev_dbg(dev, "HMC Error interrupt - info 0x%x, data 0x%x\n",
- rd32(hw, PFHMC_ERRORINFO),
- rd32(hw, PFHMC_ERRORDATA));
+ if (oicr & PFINT_OICR_TSYN_TX_M) {
+ ena_mask &= ~PFINT_OICR_TSYN_TX_M;
+ ice_ptp_process_ts(pf);
+ }
+
+ if (oicr & PFINT_OICR_TSYN_EVNT_M) {
+ u8 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
+ u32 gltsyn_stat = rd32(hw, GLTSYN_STAT(tmr_idx));
+
+ /* Save EVENTs from GTSYN register */
+ pf->ptp.ext_ts_irq |= gltsyn_stat & (GLTSYN_STAT_EVENT0_M |
+ GLTSYN_STAT_EVENT1_M |
+ GLTSYN_STAT_EVENT2_M);
+ ena_mask &= ~PFINT_OICR_TSYN_EVNT_M;
+ kthread_queue_work(pf->ptp.kworker, &pf->ptp.extts_work);
+ }
+
+#define ICE_AUX_CRIT_ERR (PFINT_OICR_PE_CRITERR_M | PFINT_OICR_HMC_ERR_M | PFINT_OICR_PE_PUSH_M)
+ if (oicr & ICE_AUX_CRIT_ERR) {
+ struct iidc_event *event;
+
+ ena_mask &= ~ICE_AUX_CRIT_ERR;
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+ if (event) {
+ set_bit(IIDC_EVENT_CRIT_ERR, event->type);
+ /* report the entire OICR value to AUX driver */
+ event->reg = oicr;
+ ice_send_event_to_aux(pf, event);
+ kfree(event);
+ }
}
/* Report any remaining unexpected interrupts */
@@ -2734,8 +2851,7 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
/* If a critical error is pending there is no choice but to
* reset the device.
*/
- if (oicr & (PFINT_OICR_PE_CRITERR_M |
- PFINT_OICR_PCI_EXCEPTION_M |
+ if (oicr & (PFINT_OICR_PCI_EXCEPTION_M |
PFINT_OICR_ECC_ERR_M)) {
set_bit(ICE_PFR_REQ, pf->state);
ice_service_task_schedule(pf);
@@ -2763,6 +2879,9 @@ static void ice_dis_ctrlq_interrupts(struct ice_hw *hw)
wr32(hw, PFINT_MBX_CTL,
rd32(hw, PFINT_MBX_CTL) & ~PFINT_MBX_CTL_CAUSE_ENA_M);
+ wr32(hw, PFINT_SB_CTL,
+ rd32(hw, PFINT_SB_CTL) & ~PFINT_SB_CTL_CAUSE_ENA_M);
+
/* disable Control queue Interrupt causes */
wr32(hw, PFINT_OICR_CTL,
rd32(hw, PFINT_OICR_CTL) & ~PFINT_OICR_CTL_CAUSE_ENA_M);
@@ -2817,6 +2936,11 @@ static void ice_ena_ctrlq_interrupts(struct ice_hw *hw, u16 reg_idx)
PFINT_MBX_CTL_CAUSE_ENA_M);
wr32(hw, PFINT_MBX_CTL, val);
+ /* This enables Sideband queue Interrupt causes */
+ val = ((reg_idx & PFINT_SB_CTL_MSIX_INDX_M) |
+ PFINT_SB_CTL_CAUSE_ENA_M);
+ wr32(hw, PFINT_SB_CTL, val);
+
ice_flush(hw);
}
@@ -2986,7 +3110,6 @@ static void ice_set_netdev_features(struct net_device *netdev)
*/
static int ice_cfg_netdev(struct ice_vsi *vsi)
{
- struct ice_pf *pf = vsi->back;
struct ice_netdev_priv *np;
struct net_device *netdev;
u8 mac_addr[ETH_ALEN];
@@ -3006,7 +3129,7 @@ static int ice_cfg_netdev(struct ice_vsi *vsi)
ice_set_ops(netdev);
if (vsi->type == ICE_VSI_PF) {
- SET_NETDEV_DEV(netdev, ice_pf_to_dev(pf));
+ SET_NETDEV_DEV(netdev, ice_pf_to_dev(vsi->back));
ether_addr_copy(mac_addr, vsi->port_info->mac.perm_addr);
ether_addr_copy(netdev->dev_addr, mac_addr);
ether_addr_copy(netdev->perm_addr, mac_addr);
@@ -3280,6 +3403,9 @@ static void ice_deinit_pf(struct ice_pf *pf)
bitmap_free(pf->avail_rxqs);
pf->avail_rxqs = NULL;
}
+
+ if (pf->ptp.clock)
+ ptp_clock_unregister(pf->ptp.clock);
}
/**
@@ -3290,6 +3416,12 @@ static void ice_set_pf_caps(struct ice_pf *pf)
{
struct ice_hw_func_caps *func_caps = &pf->hw.func_caps;
+ clear_bit(ICE_FLAG_RDMA_ENA, pf->flags);
+ clear_bit(ICE_FLAG_AUX_ENA, pf->flags);
+ if (func_caps->common_cap.rdma) {
+ set_bit(ICE_FLAG_RDMA_ENA, pf->flags);
+ set_bit(ICE_FLAG_AUX_ENA, pf->flags);
+ }
clear_bit(ICE_FLAG_DCB_CAPABLE, pf->flags);
if (func_caps->common_cap.dcb)
set_bit(ICE_FLAG_DCB_CAPABLE, pf->flags);
@@ -3320,6 +3452,10 @@ static void ice_set_pf_caps(struct ice_pf *pf)
func_caps->fd_fltr_best_effort);
}
+ clear_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags);
+ if (func_caps->common_cap.ieee_1588)
+ set_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags);
+
pf->max_pf_txqs = func_caps->common_cap.num_txq;
pf->max_pf_rxqs = func_caps->common_cap.num_rxq;
}
@@ -3339,6 +3475,8 @@ static int ice_init_pf(struct ice_pf *pf)
spin_lock_init(&pf->aq_wait_lock);
init_waitqueue_head(&pf->aq_wait_queue);
+ init_waitqueue_head(&pf->reset_wait_queue);
+
/* setup service timer and periodic service task */
timer_setup(&pf->serv_tmr, ice_service_timer, 0);
pf->serv_tmr_period = HZ;
@@ -3369,11 +3507,12 @@ static int ice_init_pf(struct ice_pf *pf)
*/
static int ice_ena_msix_range(struct ice_pf *pf)
{
- int v_left, v_actual, v_other, v_budget = 0;
+ int num_cpus, v_left, v_actual, v_other, v_budget = 0;
struct device *dev = ice_pf_to_dev(pf);
int needed, err, i;
v_left = pf->hw.func_caps.common_cap.num_msix_vectors;
+ num_cpus = num_online_cpus();
/* reserve for LAN miscellaneous handler */
needed = ICE_MIN_LAN_OICR_MSIX;
@@ -3395,13 +3534,23 @@ static int ice_ena_msix_range(struct ice_pf *pf)
v_other = v_budget;
/* reserve vectors for LAN traffic */
- needed = min_t(int, num_online_cpus(), v_left);
+ needed = num_cpus;
if (v_left < needed)
goto no_hw_vecs_left_err;
pf->num_lan_msix = needed;
v_budget += needed;
v_left -= needed;
+ /* reserve vectors for RDMA auxiliary driver */
+ if (test_bit(ICE_FLAG_RDMA_ENA, pf->flags)) {
+ needed = num_cpus + ICE_RDMA_NUM_AEQ_MSIX;
+ if (v_left < needed)
+ goto no_hw_vecs_left_err;
+ pf->num_rdma_msix = needed;
+ v_budget += needed;
+ v_left -= needed;
+ }
+
pf->msix_entries = devm_kcalloc(dev, v_budget,
sizeof(*pf->msix_entries), GFP_KERNEL);
if (!pf->msix_entries) {
@@ -3431,16 +3580,46 @@ static int ice_ena_msix_range(struct ice_pf *pf)
err = -ERANGE;
goto msix_err;
} else {
- int v_traffic = v_actual - v_other;
+ int v_remain = v_actual - v_other;
+ int v_rdma = 0, v_min_rdma = 0;
+
+ if (test_bit(ICE_FLAG_RDMA_ENA, pf->flags)) {
+ /* Need at least 1 interrupt in addition to
+ * AEQ MSIX
+ */
+ v_rdma = ICE_RDMA_NUM_AEQ_MSIX + 1;
+ v_min_rdma = ICE_MIN_RDMA_MSIX;
+ }
if (v_actual == ICE_MIN_MSIX ||
- v_traffic < ICE_MIN_LAN_TXRX_MSIX)
+ v_remain < ICE_MIN_LAN_TXRX_MSIX + v_min_rdma) {
+ dev_warn(dev, "Not enough MSI-X vectors to support RDMA.\n");
+ clear_bit(ICE_FLAG_RDMA_ENA, pf->flags);
+
+ pf->num_rdma_msix = 0;
pf->num_lan_msix = ICE_MIN_LAN_TXRX_MSIX;
- else
- pf->num_lan_msix = v_traffic;
+ } else if ((v_remain < ICE_MIN_LAN_TXRX_MSIX + v_rdma) ||
+ (v_remain - v_rdma < v_rdma)) {
+ /* Support minimum RDMA and give remaining
+ * vectors to LAN MSIX
+ */
+ pf->num_rdma_msix = v_min_rdma;
+ pf->num_lan_msix = v_remain - v_min_rdma;
+ } else {
+ /* Split remaining MSIX with RDMA after
+ * accounting for AEQ MSIX
+ */
+ pf->num_rdma_msix = (v_remain - ICE_RDMA_NUM_AEQ_MSIX) / 2 +
+ ICE_RDMA_NUM_AEQ_MSIX;
+ pf->num_lan_msix = v_remain - pf->num_rdma_msix;
+ }
dev_notice(dev, "Enabled %d MSI-X vectors for LAN traffic.\n",
pf->num_lan_msix);
+
+ if (test_bit(ICE_FLAG_RDMA_ENA, pf->flags))
+ dev_notice(dev, "Enabled %d MSI-X vectors for RDMA.\n",
+ pf->num_rdma_msix);
}
}
@@ -3455,6 +3634,7 @@ no_hw_vecs_left_err:
needed, v_left);
err = -ERANGE;
exit_err:
+ pf->num_rdma_msix = 0;
pf->num_lan_msix = 0;
return err;
}
@@ -4218,6 +4398,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
ice_init_link_dflt_override(pf->hw.port_info);
+ ice_check_module_power(pf, pf->hw.port_info->phy.link_info.link_cfg_err);
+
/* if media available, initialize PHY settings */
if (pf->hw.port_info->phy.link_info.link_info &
ICE_AQ_MEDIA_AVAILABLE) {
@@ -4256,6 +4438,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
}
/* initialize DDP driven features */
+ if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
+ ice_ptp_init(pf);
/* Note: Flow director init failure is non-fatal to load */
if (ice_init_fdir(pf))
@@ -4282,8 +4466,29 @@ probe_done:
/* ready to go, so clear down state bit */
clear_bit(ICE_DOWN, pf->state);
+ if (ice_is_aux_ena(pf)) {
+ pf->aux_idx = ida_alloc(&ice_aux_ida, GFP_KERNEL);
+ if (pf->aux_idx < 0) {
+ dev_err(dev, "Failed to allocate device ID for AUX driver\n");
+ err = -ENOMEM;
+ goto err_netdev_reg;
+ }
+
+ err = ice_init_rdma(pf);
+ if (err) {
+ dev_err(dev, "Failed to initialize RDMA: %d\n", err);
+ err = -EIO;
+ goto err_init_aux_unroll;
+ }
+ } else {
+ dev_warn(dev, "RDMA is not supported on this device\n");
+ }
+
return 0;
+err_init_aux_unroll:
+ pf->adev = NULL;
+ ida_free(&ice_aux_ida, pf->aux_idx);
err_netdev_reg:
err_send_version_unroll:
ice_vsi_release_all(pf);
@@ -4393,13 +4598,17 @@ static void ice_remove(struct pci_dev *pdev)
ice_free_vfs(pf);
}
- set_bit(ICE_DOWN, pf->state);
ice_service_task_stop(pf);
ice_aq_cancel_waiting_tasks(pf);
+ ice_unplug_aux_dev(pf);
+ ida_free(&ice_aux_ida, pf->aux_idx);
+ set_bit(ICE_DOWN, pf->state);
mutex_destroy(&(&pf->hw)->fdir_fltr_lock);
ice_deinit_lag(pf);
+ if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
+ ice_ptp_release(pf);
if (!ice_is_safe_mode(pf))
ice_remove_arfs(pf);
ice_setup_mc_magic_wake(pf);
@@ -4552,6 +4761,8 @@ static int __maybe_unused ice_suspend(struct device *dev)
*/
disabled = ice_service_task_stop(pf);
+ ice_unplug_aux_dev(pf);
+
/* Already suspended?, then there is nothing to do */
if (test_and_set_bit(ICE_SUSPENDED, pf->state)) {
if (!disabled)
@@ -5284,6 +5495,7 @@ static void ice_tx_dim_work(struct work_struct *work)
itr = tx_profile[dim->profile_ix].itr;
intrl = tx_profile[dim->profile_ix].intrl;
+ ice_trace(tx_dim_work, q_vector, dim);
ice_write_itr(rc, itr);
ice_write_intrl(q_vector, intrl);
@@ -5308,6 +5520,7 @@ static void ice_rx_dim_work(struct work_struct *work)
itr = rx_profile[dim->profile_ix].itr;
intrl = rx_profile[dim->profile_ix].intrl;
+ ice_trace(rx_dim_work, q_vector, dim);
ice_write_itr(rc, itr);
ice_write_intrl(q_vector, intrl);
@@ -5451,7 +5664,6 @@ ice_update_vsi_tx_ring_stats(struct ice_vsi *vsi, struct ice_ring **rings,
static void ice_update_vsi_ring_stats(struct ice_vsi *vsi)
{
struct rtnl_link_stats64 *vsi_stats = &vsi->net_stats;
- struct ice_ring *ring;
u64 pkts, bytes;
int i;
@@ -5475,7 +5687,8 @@ static void ice_update_vsi_ring_stats(struct ice_vsi *vsi)
/* update Rx rings counters */
ice_for_each_rxq(vsi, i) {
- ring = READ_ONCE(vsi->rx_rings[i]);
+ struct ice_ring *ring = READ_ONCE(vsi->rx_rings[i]);
+
ice_fetch_u64_stats_per_ring(ring, &pkts, &bytes);
vsi_stats->rx_packets += pkts;
vsi_stats->rx_bytes += bytes;
@@ -6142,6 +6355,12 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
ice_clear_pxe_mode(hw);
+ ret = ice_init_nvm(hw);
+ if (ret) {
+ dev_err(dev, "ice_init_nvm failed %s\n", ice_stat_str(ret));
+ goto err_init_ctrlq;
+ }
+
ret = ice_get_caps(hw);
if (ret) {
dev_err(dev, "ice_get_caps failed %s\n", ice_stat_str(ret));
@@ -6183,6 +6402,13 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
if (test_bit(ICE_FLAG_DCB_ENA, pf->flags))
ice_dcb_rebuild(pf);
+ /* If the PF previously had enabled PTP, PTP init needs to happen before
+ * the VSI rebuild. If not, this causes the PTP link status events to
+ * fail.
+ */
+ if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
+ ice_ptp_init(pf);
+
/* rebuild PF VSI */
err = ice_vsi_rebuild_by_type(pf, ICE_VSI_PF);
if (err) {
@@ -6222,6 +6448,8 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
/* if we get here, reset flow is successful */
clear_bit(ICE_RESET_FAILED, pf->state);
+
+ ice_plug_aux_dev(pf);
return;
err_vsi_rebuild:
@@ -6260,7 +6488,9 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu)
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi *vsi = np->vsi;
struct ice_pf *pf = vsi->back;
+ struct iidc_event *event;
u8 count = 0;
+ int err = 0;
if (new_mtu == (int)netdev->mtu) {
netdev_warn(netdev, "MTU is already %u\n", netdev->mtu);
@@ -6293,27 +6523,59 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu)
return -EBUSY;
}
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+ if (!event)
+ return -ENOMEM;
+
+ set_bit(IIDC_EVENT_BEFORE_MTU_CHANGE, event->type);
+ ice_send_event_to_aux(pf, event);
+ clear_bit(IIDC_EVENT_BEFORE_MTU_CHANGE, event->type);
+
netdev->mtu = (unsigned int)new_mtu;
/* if VSI is up, bring it down and then back up */
if (!test_and_set_bit(ICE_VSI_DOWN, vsi->state)) {
- int err;
-
err = ice_down(vsi);
if (err) {
netdev_err(netdev, "change MTU if_down err %d\n", err);
- return err;
+ goto event_after;
}
err = ice_up(vsi);
if (err) {
netdev_err(netdev, "change MTU if_up err %d\n", err);
- return err;
+ goto event_after;
}
}
netdev_dbg(netdev, "changed MTU to %d\n", new_mtu);
- return 0;
+event_after:
+ set_bit(IIDC_EVENT_AFTER_MTU_CHANGE, event->type);
+ ice_send_event_to_aux(pf, event);
+ kfree(event);
+
+ return err;
+}
+
+/**
+ * ice_do_ioctl - Access the hwtstamp interface
+ * @netdev: network interface device structure
+ * @ifr: interface request data
+ * @cmd: ioctl command
+ */
+static int ice_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_pf *pf = np->vsi->back;
+
+ switch (cmd) {
+ case SIOCGHWTSTAMP:
+ return ice_ptp_get_ts_config(pf, ifr);
+ case SIOCSHWTSTAMP:
+ return ice_ptp_set_ts_config(pf, ifr);
+ default:
+ return -EOPNOTSUPP;
+ }
}
/**
@@ -6832,6 +7094,8 @@ int ice_open_internal(struct net_device *netdev)
return -EIO;
}
+ ice_check_module_power(pf, pi->phy.link_info.link_cfg_err);
+
/* Set PHY if there is media, otherwise, turn off PHY */
if (pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE) {
clear_bit(ICE_FLAG_NO_MEDIA, pf->flags);
@@ -6965,6 +7229,7 @@ static const struct net_device_ops ice_netdev_ops = {
.ndo_change_mtu = ice_change_mtu,
.ndo_get_stats64 = ice_get_stats64,
.ndo_set_tx_maxrate = ice_set_tx_maxrate,
+ .ndo_do_ioctl = ice_do_ioctl,
.ndo_set_vf_spoofchk = ice_set_vf_spoofchk,
.ndo_set_vf_mac = ice_set_vf_mac,
.ndo_get_vf_config = ice_get_vf_cfg,
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
new file mode 100644
index 000000000000..5d5207b56ca9
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -0,0 +1,1558 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2021, Intel Corporation. */
+
+#include "ice.h"
+#include "ice_lib.h"
+
+#define E810_OUT_PROP_DELAY_NS 1
+
+/**
+ * ice_set_tx_tstamp - Enable or disable Tx timestamping
+ * @pf: The PF pointer to search in
+ * @on: bool value for whether timestamps are enabled or disabled
+ */
+static void ice_set_tx_tstamp(struct ice_pf *pf, bool on)
+{
+ struct ice_vsi *vsi;
+ u32 val;
+ u16 i;
+
+ vsi = ice_get_main_vsi(pf);
+ if (!vsi)
+ return;
+
+ /* Set the timestamp enable flag for all the Tx rings */
+ ice_for_each_rxq(vsi, i) {
+ if (!vsi->tx_rings[i])
+ continue;
+ vsi->tx_rings[i]->ptp_tx = on;
+ }
+
+ /* Configure the Tx timestamp interrupt */
+ val = rd32(&pf->hw, PFINT_OICR_ENA);
+ if (on)
+ val |= PFINT_OICR_TSYN_TX_M;
+ else
+ val &= ~PFINT_OICR_TSYN_TX_M;
+ wr32(&pf->hw, PFINT_OICR_ENA, val);
+}
+
+/**
+ * ice_set_rx_tstamp - Enable or disable Rx timestamping
+ * @pf: The PF pointer to search in
+ * @on: bool value for whether timestamps are enabled or disabled
+ */
+static void ice_set_rx_tstamp(struct ice_pf *pf, bool on)
+{
+ struct ice_vsi *vsi;
+ u16 i;
+
+ vsi = ice_get_main_vsi(pf);
+ if (!vsi)
+ return;
+
+ /* Set the timestamp flag for all the Rx rings */
+ ice_for_each_rxq(vsi, i) {
+ if (!vsi->rx_rings[i])
+ continue;
+ vsi->rx_rings[i]->ptp_rx = on;
+ }
+}
+
+/**
+ * ice_ptp_cfg_timestamp - Configure timestamp for init/deinit
+ * @pf: Board private structure
+ * @ena: bool value to enable or disable time stamp
+ *
+ * This function will configure timestamping during PTP initialization
+ * and deinitialization
+ */
+static void ice_ptp_cfg_timestamp(struct ice_pf *pf, bool ena)
+{
+ ice_set_tx_tstamp(pf, ena);
+ ice_set_rx_tstamp(pf, ena);
+
+ if (ena) {
+ pf->ptp.tstamp_config.rx_filter = HWTSTAMP_FILTER_ALL;
+ pf->ptp.tstamp_config.tx_type = HWTSTAMP_TX_ON;
+ } else {
+ pf->ptp.tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
+ pf->ptp.tstamp_config.tx_type = HWTSTAMP_TX_OFF;
+ }
+}
+
+/**
+ * ice_get_ptp_clock_index - Get the PTP clock index
+ * @pf: the PF pointer
+ *
+ * Determine the clock index of the PTP clock associated with this device. If
+ * this is the PF controlling the clock, just use the local access to the
+ * clock device pointer.
+ *
+ * Otherwise, read from the driver shared parameters to determine the clock
+ * index value.
+ *
+ * Returns: the index of the PTP clock associated with this device, or -1 if
+ * there is no associated clock.
+ */
+int ice_get_ptp_clock_index(struct ice_pf *pf)
+{
+ struct device *dev = ice_pf_to_dev(pf);
+ enum ice_aqc_driver_params param_idx;
+ struct ice_hw *hw = &pf->hw;
+ u8 tmr_idx;
+ u32 value;
+ int err;
+
+ /* Use the ptp_clock structure if we're the main PF */
+ if (pf->ptp.clock)
+ return ptp_clock_index(pf->ptp.clock);
+
+ tmr_idx = hw->func_caps.ts_func_info.tmr_index_assoc;
+ if (!tmr_idx)
+ param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR0;
+ else
+ param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR1;
+
+ err = ice_aq_get_driver_param(hw, param_idx, &value, NULL);
+ if (err) {
+ dev_err(dev, "Failed to read PTP clock index parameter, err %d aq_err %s\n",
+ err, ice_aq_str(hw->adminq.sq_last_status));
+ return -1;
+ }
+
+ /* The PTP clock index is an integer, and will be between 0 and
+ * INT_MAX. The highest bit of the driver shared parameter is used to
+ * indicate whether or not the currently stored clock index is valid.
+ */
+ if (!(value & PTP_SHARED_CLK_IDX_VALID))
+ return -1;
+
+ return value & ~PTP_SHARED_CLK_IDX_VALID;
+}
+
+/**
+ * ice_set_ptp_clock_index - Set the PTP clock index
+ * @pf: the PF pointer
+ *
+ * Set the PTP clock index for this device into the shared driver parameters,
+ * so that other PFs associated with this device can read it.
+ *
+ * If the PF is unable to store the clock index, it will log an error, but
+ * will continue operating PTP.
+ */
+static void ice_set_ptp_clock_index(struct ice_pf *pf)
+{
+ struct device *dev = ice_pf_to_dev(pf);
+ enum ice_aqc_driver_params param_idx;
+ struct ice_hw *hw = &pf->hw;
+ u8 tmr_idx;
+ u32 value;
+ int err;
+
+ if (!pf->ptp.clock)
+ return;
+
+ tmr_idx = hw->func_caps.ts_func_info.tmr_index_assoc;
+ if (!tmr_idx)
+ param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR0;
+ else
+ param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR1;
+
+ value = (u32)ptp_clock_index(pf->ptp.clock);
+ if (value > INT_MAX) {
+ dev_err(dev, "PTP Clock index is too large to store\n");
+ return;
+ }
+ value |= PTP_SHARED_CLK_IDX_VALID;
+
+ err = ice_aq_set_driver_param(hw, param_idx, value, NULL);
+ if (err) {
+ dev_err(dev, "Failed to set PTP clock index parameter, err %d aq_err %s\n",
+ err, ice_aq_str(hw->adminq.sq_last_status));
+ }
+}
+
+/**
+ * ice_clear_ptp_clock_index - Clear the PTP clock index
+ * @pf: the PF pointer
+ *
+ * Clear the PTP clock index for this device. Must be called when
+ * unregistering the PTP clock, in order to ensure other PFs stop reporting
+ * a clock object that no longer exists.
+ */
+static void ice_clear_ptp_clock_index(struct ice_pf *pf)
+{
+ struct device *dev = ice_pf_to_dev(pf);
+ enum ice_aqc_driver_params param_idx;
+ struct ice_hw *hw = &pf->hw;
+ u8 tmr_idx;
+ int err;
+
+ /* Do not clear the index if we don't own the timer */
+ if (!hw->func_caps.ts_func_info.src_tmr_owned)
+ return;
+
+ tmr_idx = hw->func_caps.ts_func_info.tmr_index_assoc;
+ if (!tmr_idx)
+ param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR0;
+ else
+ param_idx = ICE_AQC_DRIVER_PARAM_CLK_IDX_TMR1;
+
+ err = ice_aq_set_driver_param(hw, param_idx, 0, NULL);
+ if (err) {
+ dev_dbg(dev, "Failed to clear PTP clock index parameter, err %d aq_err %s\n",
+ err, ice_aq_str(hw->adminq.sq_last_status));
+ }
+}
+
+/**
+ * ice_ptp_read_src_clk_reg - Read the source clock register
+ * @pf: Board private structure
+ * @sts: Optional parameter for holding a pair of system timestamps from
+ * the system clock. Will be ignored if NULL is given.
+ */
+static u64
+ice_ptp_read_src_clk_reg(struct ice_pf *pf, struct ptp_system_timestamp *sts)
+{
+ struct ice_hw *hw = &pf->hw;
+ u32 hi, lo, lo2;
+ u8 tmr_idx;
+
+ tmr_idx = ice_get_ptp_src_clock_index(hw);
+ /* Read the system timestamp pre PHC read */
+ ptp_read_system_prets(sts);
+
+ lo = rd32(hw, GLTSYN_TIME_L(tmr_idx));
+
+ /* Read the system timestamp post PHC read */
+ ptp_read_system_postts(sts);
+
+ hi = rd32(hw, GLTSYN_TIME_H(tmr_idx));
+ lo2 = rd32(hw, GLTSYN_TIME_L(tmr_idx));
+
+ if (lo2 < lo) {
+ /* if TIME_L rolled over read TIME_L again and update
+ * system timestamps
+ */
+ ptp_read_system_prets(sts);
+ lo = rd32(hw, GLTSYN_TIME_L(tmr_idx));
+ ptp_read_system_postts(sts);
+ hi = rd32(hw, GLTSYN_TIME_H(tmr_idx));
+ }
+
+ return ((u64)hi << 32) | lo;
+}
+
+/**
+ * ice_ptp_update_cached_phctime - Update the cached PHC time values
+ * @pf: Board specific private structure
+ *
+ * This function updates the system time values which are cached in the PF
+ * structure and the Rx rings.
+ *
+ * This function must be called periodically to ensure that the cached value
+ * is never more than 2 seconds old. It must also be called whenever the PHC
+ * time has been changed.
+ */
+static void ice_ptp_update_cached_phctime(struct ice_pf *pf)
+{
+ u64 systime;
+ int i;
+
+ /* Read the current PHC time */
+ systime = ice_ptp_read_src_clk_reg(pf, NULL);
+
+ /* Update the cached PHC time stored in the PF structure */
+ WRITE_ONCE(pf->ptp.cached_phc_time, systime);
+
+ ice_for_each_vsi(pf, i) {
+ struct ice_vsi *vsi = pf->vsi[i];
+ int j;
+
+ if (!vsi)
+ continue;
+
+ if (vsi->type != ICE_VSI_PF)
+ continue;
+
+ ice_for_each_rxq(vsi, j) {
+ if (!vsi->rx_rings[j])
+ continue;
+ WRITE_ONCE(vsi->rx_rings[j]->cached_phctime, systime);
+ }
+ }
+}
+
+/**
+ * ice_ptp_extend_32b_ts - Convert a 32b nanoseconds timestamp to 64b
+ * @cached_phc_time: recently cached copy of PHC time
+ * @in_tstamp: Ingress/egress 32b nanoseconds timestamp value
+ *
+ * Hardware captures timestamps which contain only 32 bits of nominal
+ * nanoseconds, as opposed to the 64bit timestamps that the stack expects.
+ * Note that the captured timestamp values may be 40 bits, but the lower
+ * 8 bits are sub-nanoseconds and generally discarded.
+ *
+ * Extend the 32bit nanosecond timestamp using the following algorithm and
+ * assumptions:
+ *
+ * 1) have a recently cached copy of the PHC time
+ * 2) assume that the in_tstamp was captured 2^31 nanoseconds (~2.1
+ * seconds) before or after the PHC time was captured.
+ * 3) calculate the delta between the cached time and the timestamp
+ * 4) if the delta is smaller than 2^31 nanoseconds, then the timestamp was
+ * captured after the PHC time. In this case, the full timestamp is just
+ * the cached PHC time plus the delta.
+ * 5) otherwise, if the delta is larger than 2^31 nanoseconds, then the
+ * timestamp was captured *before* the PHC time, i.e. because the PHC
+ * cache was updated after the timestamp was captured by hardware. In this
+ * case, the full timestamp is the cached time minus the inverse delta.
+ *
+ * This algorithm works even if the PHC time was updated after a Tx timestamp
+ * was requested, but before the Tx timestamp event was reported from
+ * hardware.
+ *
+ * This calculation primarily relies on keeping the cached PHC time up to
+ * date. If the timestamp was captured more than 2^31 nanoseconds after the
+ * PHC time, it is possible that the lower 32bits of PHC time have
+ * overflowed more than once, and we might generate an incorrect timestamp.
+ *
+ * This is prevented by (a) periodically updating the cached PHC time once
+ * a second, and (b) discarding any Tx timestamp packet if it has waited for
+ * a timestamp for more than one second.
+ */
+static u64 ice_ptp_extend_32b_ts(u64 cached_phc_time, u32 in_tstamp)
+{
+ u32 delta, phc_time_lo;
+ u64 ns;
+
+ /* Extract the lower 32 bits of the PHC time */
+ phc_time_lo = (u32)cached_phc_time;
+
+ /* Calculate the delta between the lower 32bits of the cached PHC
+ * time and the in_tstamp value
+ */
+ delta = (in_tstamp - phc_time_lo);
+
+ /* Do not assume that the in_tstamp is always more recent than the
+ * cached PHC time. If the delta is large, it indicates that the
+ * in_tstamp was taken in the past, and should be converted
+ * forward.
+ */
+ if (delta > (U32_MAX / 2)) {
+ /* reverse the delta calculation here */
+ delta = (phc_time_lo - in_tstamp);
+ ns = cached_phc_time - delta;
+ } else {
+ ns = cached_phc_time + delta;
+ }
+
+ return ns;
+}
+
+/**
+ * ice_ptp_extend_40b_ts - Convert a 40b timestamp to 64b nanoseconds
+ * @pf: Board private structure
+ * @in_tstamp: Ingress/egress 40b timestamp value
+ *
+ * The Tx and Rx timestamps are 40 bits wide, including 32 bits of nominal
+ * nanoseconds, 7 bits of sub-nanoseconds, and a valid bit.
+ *
+ * *--------------------------------------------------------------*
+ * | 32 bits of nanoseconds | 7 high bits of sub ns underflow | v |
+ * *--------------------------------------------------------------*
+ *
+ * The low bit is an indicator of whether the timestamp is valid. The next
+ * 7 bits are a capture of the upper 7 bits of the sub-nanosecond underflow,
+ * and the remaining 32 bits are the lower 32 bits of the PHC timer.
+ *
+ * It is assumed that the caller verifies the timestamp is valid prior to
+ * calling this function.
+ *
+ * Extract the 32bit nominal nanoseconds and extend them. Use the cached PHC
+ * time stored in the device private PTP structure as the basis for timestamp
+ * extension.
+ *
+ * See ice_ptp_extend_32b_ts for a detailed explanation of the extension
+ * algorithm.
+ */
+static u64 ice_ptp_extend_40b_ts(struct ice_pf *pf, u64 in_tstamp)
+{
+ const u64 mask = GENMASK_ULL(31, 0);
+
+ return ice_ptp_extend_32b_ts(pf->ptp.cached_phc_time,
+ (in_tstamp >> 8) & mask);
+}
+
+/**
+ * ice_ptp_read_time - Read the time from the device
+ * @pf: Board private structure
+ * @ts: timespec structure to hold the current time value
+ * @sts: Optional parameter for holding a pair of system timestamps from
+ * the system clock. Will be ignored if NULL is given.
+ *
+ * This function reads the source clock registers and stores them in a timespec.
+ * However, since the registers are 64 bits of nanoseconds, we must convert the
+ * result to a timespec before we can return.
+ */
+static void
+ice_ptp_read_time(struct ice_pf *pf, struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ u64 time_ns = ice_ptp_read_src_clk_reg(pf, sts);
+
+ *ts = ns_to_timespec64(time_ns);
+}
+
+/**
+ * ice_ptp_write_init - Set PHC time to provided value
+ * @pf: Board private structure
+ * @ts: timespec structure that holds the new time value
+ *
+ * Set the PHC time to the specified time provided in the timespec.
+ */
+static int ice_ptp_write_init(struct ice_pf *pf, struct timespec64 *ts)
+{
+ u64 ns = timespec64_to_ns(ts);
+ struct ice_hw *hw = &pf->hw;
+
+ return ice_ptp_init_time(hw, ns);
+}
+
+/**
+ * ice_ptp_write_adj - Adjust PHC clock time atomically
+ * @pf: Board private structure
+ * @adj: Adjustment in nanoseconds
+ *
+ * Perform an atomic adjustment of the PHC time by the specified number of
+ * nanoseconds.
+ */
+static int ice_ptp_write_adj(struct ice_pf *pf, s32 adj)
+{
+ struct ice_hw *hw = &pf->hw;
+
+ return ice_ptp_adj_clock(hw, adj);
+}
+
+/**
+ * ice_ptp_adjfine - Adjust clock increment rate
+ * @info: the driver's PTP info structure
+ * @scaled_ppm: Parts per million with 16-bit fractional field
+ *
+ * Adjust the frequency of the clock by the indicated scaled ppm from the
+ * base frequency.
+ */
+static int ice_ptp_adjfine(struct ptp_clock_info *info, long scaled_ppm)
+{
+ struct ice_pf *pf = ptp_info_to_pf(info);
+ u64 freq, divisor = 1000000ULL;
+ struct ice_hw *hw = &pf->hw;
+ s64 incval, diff;
+ int neg_adj = 0;
+ int err;
+
+ incval = ICE_PTP_NOMINAL_INCVAL_E810;
+
+ if (scaled_ppm < 0) {
+ neg_adj = 1;
+ scaled_ppm = -scaled_ppm;
+ }
+
+ while ((u64)scaled_ppm > div_u64(U64_MAX, incval)) {
+ /* handle overflow by scaling down the scaled_ppm and
+ * the divisor, losing some precision
+ */
+ scaled_ppm >>= 2;
+ divisor >>= 2;
+ }
+
+ freq = (incval * (u64)scaled_ppm) >> 16;
+ diff = div_u64(freq, divisor);
+
+ if (neg_adj)
+ incval -= diff;
+ else
+ incval += diff;
+
+ err = ice_ptp_write_incval_locked(hw, incval);
+ if (err) {
+ dev_err(ice_pf_to_dev(pf), "PTP failed to set incval, err %d\n",
+ err);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * ice_ptp_extts_work - Workqueue task function
+ * @work: external timestamp work structure
+ *
+ * Service for PTP external clock event
+ */
+static void ice_ptp_extts_work(struct kthread_work *work)
+{
+ struct ice_ptp *ptp = container_of(work, struct ice_ptp, extts_work);
+ struct ice_pf *pf = container_of(ptp, struct ice_pf, ptp);
+ struct ptp_clock_event event;
+ struct ice_hw *hw = &pf->hw;
+ u8 chan, tmr_idx;
+ u32 hi, lo;
+
+ tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
+ /* Event time is captured by one of the two matched registers
+ * GLTSYN_EVNT_L: 32 LSB of sampled time event
+ * GLTSYN_EVNT_H: 32 MSB of sampled time event
+ * Event is defined in GLTSYN_EVNT_0 register
+ */
+ for (chan = 0; chan < GLTSYN_EVNT_H_IDX_MAX; chan++) {
+ /* Check if channel is enabled */
+ if (pf->ptp.ext_ts_irq & (1 << chan)) {
+ lo = rd32(hw, GLTSYN_EVNT_L(chan, tmr_idx));
+ hi = rd32(hw, GLTSYN_EVNT_H(chan, tmr_idx));
+ event.timestamp = (((u64)hi) << 32) | lo;
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = chan;
+
+ /* Fire event */
+ ptp_clock_event(pf->ptp.clock, &event);
+ pf->ptp.ext_ts_irq &= ~(1 << chan);
+ }
+ }
+}
+
+/**
+ * ice_ptp_cfg_extts - Configure EXTTS pin and channel
+ * @pf: Board private structure
+ * @ena: true to enable; false to disable
+ * @chan: GPIO channel (0-3)
+ * @gpio_pin: GPIO pin
+ * @extts_flags: request flags from the ptp_extts_request.flags
+ */
+static int
+ice_ptp_cfg_extts(struct ice_pf *pf, bool ena, unsigned int chan, u32 gpio_pin,
+ unsigned int extts_flags)
+{
+ u32 func, aux_reg, gpio_reg, irq_reg;
+ struct ice_hw *hw = &pf->hw;
+ u8 tmr_idx;
+
+ if (chan > (unsigned int)pf->ptp.info.n_ext_ts)
+ return -EINVAL;
+
+ tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
+
+ irq_reg = rd32(hw, PFINT_OICR_ENA);
+
+ if (ena) {
+ /* Enable the interrupt */
+ irq_reg |= PFINT_OICR_TSYN_EVNT_M;
+ aux_reg = GLTSYN_AUX_IN_0_INT_ENA_M;
+
+#define GLTSYN_AUX_IN_0_EVNTLVL_RISING_EDGE BIT(0)
+#define GLTSYN_AUX_IN_0_EVNTLVL_FALLING_EDGE BIT(1)
+
+ /* set event level to requested edge */
+ if (extts_flags & PTP_FALLING_EDGE)
+ aux_reg |= GLTSYN_AUX_IN_0_EVNTLVL_FALLING_EDGE;
+ if (extts_flags & PTP_RISING_EDGE)
+ aux_reg |= GLTSYN_AUX_IN_0_EVNTLVL_RISING_EDGE;
+
+ /* Write GPIO CTL reg.
+ * 0x1 is input sampled by EVENT register(channel)
+ * + num_in_channels * tmr_idx
+ */
+ func = 1 + chan + (tmr_idx * 3);
+ gpio_reg = ((func << GLGEN_GPIO_CTL_PIN_FUNC_S) &
+ GLGEN_GPIO_CTL_PIN_FUNC_M);
+ pf->ptp.ext_ts_chan |= (1 << chan);
+ } else {
+ /* clear the values we set to reset defaults */
+ aux_reg = 0;
+ gpio_reg = 0;
+ pf->ptp.ext_ts_chan &= ~(1 << chan);
+ if (!pf->ptp.ext_ts_chan)
+ irq_reg &= ~PFINT_OICR_TSYN_EVNT_M;
+ }
+
+ wr32(hw, PFINT_OICR_ENA, irq_reg);
+ wr32(hw, GLTSYN_AUX_IN(chan, tmr_idx), aux_reg);
+ wr32(hw, GLGEN_GPIO_CTL(gpio_pin), gpio_reg);
+
+ return 0;
+}
+
+/**
+ * ice_ptp_cfg_clkout - Configure clock to generate periodic wave
+ * @pf: Board private structure
+ * @chan: GPIO channel (0-3)
+ * @config: desired periodic clk configuration. NULL will disable channel
+ * @store: If set to true the values will be stored
+ *
+ * Configure the internal clock generator modules to generate the clock wave of
+ * specified period.
+ */
+static int ice_ptp_cfg_clkout(struct ice_pf *pf, unsigned int chan,
+ struct ice_perout_channel *config, bool store)
+{
+ u64 current_time, period, start_time, phase;
+ struct ice_hw *hw = &pf->hw;
+ u32 func, val, gpio_pin;
+ u8 tmr_idx;
+
+ tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
+
+ /* 0. Reset mode & out_en in AUX_OUT */
+ wr32(hw, GLTSYN_AUX_OUT(chan, tmr_idx), 0);
+
+ /* If we're disabling the output, clear out CLKO and TGT and keep
+ * output level low
+ */
+ if (!config || !config->ena) {
+ wr32(hw, GLTSYN_CLKO(chan, tmr_idx), 0);
+ wr32(hw, GLTSYN_TGT_L(chan, tmr_idx), 0);
+ wr32(hw, GLTSYN_TGT_H(chan, tmr_idx), 0);
+
+ val = GLGEN_GPIO_CTL_PIN_DIR_M;
+ gpio_pin = pf->ptp.perout_channels[chan].gpio_pin;
+ wr32(hw, GLGEN_GPIO_CTL(gpio_pin), val);
+
+ /* Store the value if requested */
+ if (store)
+ memset(&pf->ptp.perout_channels[chan], 0,
+ sizeof(struct ice_perout_channel));
+
+ return 0;
+ }
+ period = config->period;
+ start_time = config->start_time;
+ div64_u64_rem(start_time, period, &phase);
+ gpio_pin = config->gpio_pin;
+
+ /* 1. Write clkout with half of required period value */
+ if (period & 0x1) {
+ dev_err(ice_pf_to_dev(pf), "CLK Period must be an even value\n");
+ goto err;
+ }
+
+ period >>= 1;
+
+ /* For proper operation, the GLTSYN_CLKO must be larger than clock tick
+ */
+#define MIN_PULSE 3
+ if (period <= MIN_PULSE || period > U32_MAX) {
+ dev_err(ice_pf_to_dev(pf), "CLK Period must be > %d && < 2^33",
+ MIN_PULSE * 2);
+ goto err;
+ }
+
+ wr32(hw, GLTSYN_CLKO(chan, tmr_idx), lower_32_bits(period));
+
+ /* Allow time for programming before start_time is hit */
+ current_time = ice_ptp_read_src_clk_reg(pf, NULL);
+
+ /* if start time is in the past start the timer at the nearest second
+ * maintaining phase
+ */
+ if (start_time < current_time)
+ start_time = div64_u64(current_time + NSEC_PER_MSEC - 1,
+ NSEC_PER_SEC) * NSEC_PER_SEC + phase;
+
+ start_time -= E810_OUT_PROP_DELAY_NS;
+
+ /* 2. Write TARGET time */
+ wr32(hw, GLTSYN_TGT_L(chan, tmr_idx), lower_32_bits(start_time));
+ wr32(hw, GLTSYN_TGT_H(chan, tmr_idx), upper_32_bits(start_time));
+
+ /* 3. Write AUX_OUT register */
+ val = GLTSYN_AUX_OUT_0_OUT_ENA_M | GLTSYN_AUX_OUT_0_OUTMOD_M;
+ wr32(hw, GLTSYN_AUX_OUT(chan, tmr_idx), val);
+
+ /* 4. write GPIO CTL reg */
+ func = 8 + chan + (tmr_idx * 4);
+ val = GLGEN_GPIO_CTL_PIN_DIR_M |
+ ((func << GLGEN_GPIO_CTL_PIN_FUNC_S) & GLGEN_GPIO_CTL_PIN_FUNC_M);
+ wr32(hw, GLGEN_GPIO_CTL(gpio_pin), val);
+
+ /* Store the value if requested */
+ if (store) {
+ memcpy(&pf->ptp.perout_channels[chan], config,
+ sizeof(struct ice_perout_channel));
+ pf->ptp.perout_channels[chan].start_time = phase;
+ }
+
+ return 0;
+err:
+ dev_err(ice_pf_to_dev(pf), "PTP failed to cfg per_clk\n");
+ return -EFAULT;
+}
+
+/**
+ * ice_ptp_gpio_enable_e810 - Enable/disable ancillary features of PHC
+ * @info: the driver's PTP info structure
+ * @rq: The requested feature to change
+ * @on: Enable/disable flag
+ */
+static int
+ice_ptp_gpio_enable_e810(struct ptp_clock_info *info,
+ struct ptp_clock_request *rq, int on)
+{
+ struct ice_pf *pf = ptp_info_to_pf(info);
+ struct ice_perout_channel clk_cfg = {0};
+ unsigned int chan;
+ u32 gpio_pin;
+ int err;
+
+ switch (rq->type) {
+ case PTP_CLK_REQ_PEROUT:
+ chan = rq->perout.index;
+ if (chan == PPS_CLK_GEN_CHAN)
+ clk_cfg.gpio_pin = PPS_PIN_INDEX;
+ else
+ clk_cfg.gpio_pin = chan;
+
+ clk_cfg.period = ((rq->perout.period.sec * NSEC_PER_SEC) +
+ rq->perout.period.nsec);
+ clk_cfg.start_time = ((rq->perout.start.sec * NSEC_PER_SEC) +
+ rq->perout.start.nsec);
+ clk_cfg.ena = !!on;
+
+ err = ice_ptp_cfg_clkout(pf, chan, &clk_cfg, true);
+ break;
+ case PTP_CLK_REQ_EXTTS:
+ chan = rq->extts.index;
+ gpio_pin = chan;
+
+ err = ice_ptp_cfg_extts(pf, !!on, chan, gpio_pin,
+ rq->extts.flags);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return err;
+}
+
+/**
+ * ice_ptp_gettimex64 - Get the time of the clock
+ * @info: the driver's PTP info structure
+ * @ts: timespec64 structure to hold the current time value
+ * @sts: Optional parameter for holding a pair of system timestamps from
+ * the system clock. Will be ignored if NULL is given.
+ *
+ * Read the device clock and return the correct value on ns, after converting it
+ * into a timespec struct.
+ */
+static int
+ice_ptp_gettimex64(struct ptp_clock_info *info, struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ struct ice_pf *pf = ptp_info_to_pf(info);
+ struct ice_hw *hw = &pf->hw;
+
+ if (!ice_ptp_lock(hw)) {
+ dev_err(ice_pf_to_dev(pf), "PTP failed to get time\n");
+ return -EBUSY;
+ }
+
+ ice_ptp_read_time(pf, ts, sts);
+ ice_ptp_unlock(hw);
+
+ return 0;
+}
+
+/**
+ * ice_ptp_settime64 - Set the time of the clock
+ * @info: the driver's PTP info structure
+ * @ts: timespec64 structure that holds the new time value
+ *
+ * Set the device clock to the user input value. The conversion from timespec
+ * to ns happens in the write function.
+ */
+static int
+ice_ptp_settime64(struct ptp_clock_info *info, const struct timespec64 *ts)
+{
+ struct ice_pf *pf = ptp_info_to_pf(info);
+ struct timespec64 ts64 = *ts;
+ struct ice_hw *hw = &pf->hw;
+ int err;
+
+ if (!ice_ptp_lock(hw)) {
+ err = -EBUSY;
+ goto exit;
+ }
+
+ err = ice_ptp_write_init(pf, &ts64);
+ ice_ptp_unlock(hw);
+
+ if (!err)
+ ice_ptp_update_cached_phctime(pf);
+
+exit:
+ if (err) {
+ dev_err(ice_pf_to_dev(pf), "PTP failed to set time %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * ice_ptp_adjtime_nonatomic - Do a non-atomic clock adjustment
+ * @info: the driver's PTP info structure
+ * @delta: Offset in nanoseconds to adjust the time by
+ */
+static int ice_ptp_adjtime_nonatomic(struct ptp_clock_info *info, s64 delta)
+{
+ struct timespec64 now, then;
+
+ then = ns_to_timespec64(delta);
+ ice_ptp_gettimex64(info, &now, NULL);
+ now = timespec64_add(now, then);
+
+ return ice_ptp_settime64(info, (const struct timespec64 *)&now);
+}
+
+/**
+ * ice_ptp_adjtime - Adjust the time of the clock by the indicated delta
+ * @info: the driver's PTP info structure
+ * @delta: Offset in nanoseconds to adjust the time by
+ */
+static int ice_ptp_adjtime(struct ptp_clock_info *info, s64 delta)
+{
+ struct ice_pf *pf = ptp_info_to_pf(info);
+ struct ice_hw *hw = &pf->hw;
+ struct device *dev;
+ int err;
+
+ dev = ice_pf_to_dev(pf);
+
+ /* Hardware only supports atomic adjustments using signed 32-bit
+ * integers. For any adjustment outside this range, perform
+ * a non-atomic get->adjust->set flow.
+ */
+ if (delta > S32_MAX || delta < S32_MIN) {
+ dev_dbg(dev, "delta = %lld, adjtime non-atomic\n", delta);
+ return ice_ptp_adjtime_nonatomic(info, delta);
+ }
+
+ if (!ice_ptp_lock(hw)) {
+ dev_err(dev, "PTP failed to acquire semaphore in adjtime\n");
+ return -EBUSY;
+ }
+
+ err = ice_ptp_write_adj(pf, delta);
+
+ ice_ptp_unlock(hw);
+
+ if (err) {
+ dev_err(dev, "PTP failed to adjust time, err %d\n", err);
+ return err;
+ }
+
+ ice_ptp_update_cached_phctime(pf);
+
+ return 0;
+}
+
+/**
+ * ice_ptp_get_ts_config - ioctl interface to read the timestamping config
+ * @pf: Board private structure
+ * @ifr: ioctl data
+ *
+ * Copy the timestamping config to user buffer
+ */
+int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr)
+{
+ struct hwtstamp_config *config;
+
+ if (!test_bit(ICE_FLAG_PTP, pf->flags))
+ return -EIO;
+
+ config = &pf->ptp.tstamp_config;
+
+ return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
+ -EFAULT : 0;
+}
+
+/**
+ * ice_ptp_set_timestamp_mode - Setup driver for requested timestamp mode
+ * @pf: Board private structure
+ * @config: hwtstamp settings requested or saved
+ */
+static int
+ice_ptp_set_timestamp_mode(struct ice_pf *pf, struct hwtstamp_config *config)
+{
+ /* Reserved for future extensions. */
+ if (config->flags)
+ return -EINVAL;
+
+ switch (config->tx_type) {
+ case HWTSTAMP_TX_OFF:
+ ice_set_tx_tstamp(pf, false);
+ break;
+ case HWTSTAMP_TX_ON:
+ ice_set_tx_tstamp(pf, true);
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config->rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ ice_set_rx_tstamp(pf, false);
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_NTP_ALL:
+ case HWTSTAMP_FILTER_ALL:
+ config->rx_filter = HWTSTAMP_FILTER_ALL;
+ ice_set_rx_tstamp(pf, true);
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
+/**
+ * ice_ptp_set_ts_config - ioctl interface to control the timestamping
+ * @pf: Board private structure
+ * @ifr: ioctl data
+ *
+ * Get the user config and store it
+ */
+int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr)
+{
+ struct hwtstamp_config config;
+ int err;
+
+ if (!test_bit(ICE_FLAG_PTP, pf->flags))
+ return -EAGAIN;
+
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+ return -EFAULT;
+
+ err = ice_ptp_set_timestamp_mode(pf, &config);
+ if (err)
+ return err;
+
+ /* Save these settings for future reference */
+ pf->ptp.tstamp_config = config;
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
+}
+
+/**
+ * ice_ptp_rx_hwtstamp - Check for an Rx timestamp
+ * @rx_ring: Ring to get the VSI info
+ * @rx_desc: Receive descriptor
+ * @skb: Particular skb to send timestamp with
+ *
+ * The driver receives a notification in the receive descriptor with timestamp.
+ * The timestamp is in ns, so we must convert the result first.
+ */
+void
+ice_ptp_rx_hwtstamp(struct ice_ring *rx_ring,
+ union ice_32b_rx_flex_desc *rx_desc, struct sk_buff *skb)
+{
+ u32 ts_high;
+ u64 ts_ns;
+
+ /* Populate timesync data into skb */
+ if (rx_desc->wb.time_stamp_low & ICE_PTP_TS_VALID) {
+ struct skb_shared_hwtstamps *hwtstamps;
+
+ /* Use ice_ptp_extend_32b_ts directly, using the ring-specific
+ * cached PHC value, rather than accessing the PF. This also
+ * allows us to simply pass the upper 32bits of nanoseconds
+ * directly. Calling ice_ptp_extend_40b_ts is unnecessary as
+ * it would just discard these bits itself.
+ */
+ ts_high = le32_to_cpu(rx_desc->wb.flex_ts.ts_high);
+ ts_ns = ice_ptp_extend_32b_ts(rx_ring->cached_phctime, ts_high);
+
+ hwtstamps = skb_hwtstamps(skb);
+ memset(hwtstamps, 0, sizeof(*hwtstamps));
+ hwtstamps->hwtstamp = ns_to_ktime(ts_ns);
+ }
+}
+
+/**
+ * ice_ptp_setup_pins_e810 - Setup PTP pins in sysfs
+ * @info: PTP clock capabilities
+ */
+static void ice_ptp_setup_pins_e810(struct ptp_clock_info *info)
+{
+ info->n_per_out = E810_N_PER_OUT;
+ info->n_ext_ts = E810_N_EXT_TS;
+}
+
+/**
+ * ice_ptp_set_funcs_e810 - Set specialized functions for E810 support
+ * @pf: Board private structure
+ * @info: PTP info to fill
+ *
+ * Assign functions to the PTP capabiltiies structure for E810 devices.
+ * Functions which operate across all device families should be set directly
+ * in ice_ptp_set_caps. Only add functions here which are distinct for e810
+ * devices.
+ */
+static void
+ice_ptp_set_funcs_e810(struct ice_pf *pf, struct ptp_clock_info *info)
+{
+ info->enable = ice_ptp_gpio_enable_e810;
+
+ ice_ptp_setup_pins_e810(info);
+}
+
+/**
+ * ice_ptp_set_caps - Set PTP capabilities
+ * @pf: Board private structure
+ */
+static void ice_ptp_set_caps(struct ice_pf *pf)
+{
+ struct ptp_clock_info *info = &pf->ptp.info;
+ struct device *dev = ice_pf_to_dev(pf);
+
+ snprintf(info->name, sizeof(info->name) - 1, "%s-%s-clk",
+ dev_driver_string(dev), dev_name(dev));
+ info->owner = THIS_MODULE;
+ info->max_adj = 999999999;
+ info->adjtime = ice_ptp_adjtime;
+ info->adjfine = ice_ptp_adjfine;
+ info->gettimex64 = ice_ptp_gettimex64;
+ info->settime64 = ice_ptp_settime64;
+
+ ice_ptp_set_funcs_e810(pf, info);
+}
+
+/**
+ * ice_ptp_create_clock - Create PTP clock device for userspace
+ * @pf: Board private structure
+ *
+ * This function creates a new PTP clock device. It only creates one if we
+ * don't already have one. Will return error if it can't create one, but success
+ * if we already have a device. Should be used by ice_ptp_init to create clock
+ * initially, and prevent global resets from creating new clock devices.
+ */
+static long ice_ptp_create_clock(struct ice_pf *pf)
+{
+ struct ptp_clock_info *info;
+ struct ptp_clock *clock;
+ struct device *dev;
+
+ /* No need to create a clock device if we already have one */
+ if (pf->ptp.clock)
+ return 0;
+
+ ice_ptp_set_caps(pf);
+
+ info = &pf->ptp.info;
+ dev = ice_pf_to_dev(pf);
+
+ /* Allocate memory for kernel pins interface */
+ if (info->n_pins) {
+ info->pin_config = devm_kcalloc(dev, info->n_pins,
+ sizeof(*info->pin_config),
+ GFP_KERNEL);
+ if (!info->pin_config) {
+ info->n_pins = 0;
+ return -ENOMEM;
+ }
+ }
+
+ /* Attempt to register the clock before enabling the hardware. */
+ clock = ptp_clock_register(info, dev);
+ if (IS_ERR(clock))
+ return PTR_ERR(clock);
+
+ pf->ptp.clock = clock;
+
+ return 0;
+}
+
+/**
+ * ice_ptp_tx_tstamp_work - Process Tx timestamps for a port
+ * @work: pointer to the kthread_work struct
+ *
+ * Process timestamps captured by the PHY associated with this port. To do
+ * this, loop over each index with a waiting skb.
+ *
+ * If a given index has a valid timestamp, perform the following steps:
+ *
+ * 1) copy the timestamp out of the PHY register
+ * 4) clear the timestamp valid bit in the PHY register
+ * 5) unlock the index by clearing the associated in_use bit.
+ * 2) extend the 40b timestamp value to get a 64bit timestamp
+ * 3) send that timestamp to the stack
+ *
+ * After looping, if we still have waiting SKBs, then re-queue the work. This
+ * may cause us effectively poll even when not strictly necessary. We do this
+ * because it's possible a new timestamp was requested around the same time as
+ * the interrupt. In some cases hardware might not interrupt us again when the
+ * timestamp is captured.
+ *
+ * Note that we only take the tracking lock when clearing the bit and when
+ * checking if we need to re-queue this task. The only place where bits can be
+ * set is the hard xmit routine where an SKB has a request flag set. The only
+ * places where we clear bits are this work function, or the periodic cleanup
+ * thread. If the cleanup thread clears a bit we're processing we catch it
+ * when we lock to clear the bit and then grab the SKB pointer. If a Tx thread
+ * starts a new timestamp, we might not begin processing it right away but we
+ * will notice it at the end when we re-queue the work item. If a Tx thread
+ * starts a new timestamp just after this function exits without re-queuing,
+ * the interrupt when the timestamp finishes should trigger. Avoiding holding
+ * the lock for the entire function is important in order to ensure that Tx
+ * threads do not get blocked while waiting for the lock.
+ */
+static void ice_ptp_tx_tstamp_work(struct kthread_work *work)
+{
+ struct ice_ptp_port *ptp_port;
+ struct ice_ptp_tx *tx;
+ struct ice_pf *pf;
+ struct ice_hw *hw;
+ u8 idx;
+
+ tx = container_of(work, struct ice_ptp_tx, work);
+ if (!tx->init)
+ return;
+
+ ptp_port = container_of(tx, struct ice_ptp_port, tx);
+ pf = ptp_port_to_pf(ptp_port);
+ hw = &pf->hw;
+
+ for_each_set_bit(idx, tx->in_use, tx->len) {
+ struct skb_shared_hwtstamps shhwtstamps = {};
+ u8 phy_idx = idx + tx->quad_offset;
+ u64 raw_tstamp, tstamp;
+ struct sk_buff *skb;
+ int err;
+
+ err = ice_read_phy_tstamp(hw, tx->quad, phy_idx,
+ &raw_tstamp);
+ if (err)
+ continue;
+
+ /* Check if the timestamp is valid */
+ if (!(raw_tstamp & ICE_PTP_TS_VALID))
+ continue;
+
+ /* clear the timestamp register, so that it won't show valid
+ * again when re-used.
+ */
+ ice_clear_phy_tstamp(hw, tx->quad, phy_idx);
+
+ /* The timestamp is valid, so we'll go ahead and clear this
+ * index and then send the timestamp up to the stack.
+ */
+ spin_lock(&tx->lock);
+ clear_bit(idx, tx->in_use);
+ skb = tx->tstamps[idx].skb;
+ tx->tstamps[idx].skb = NULL;
+ spin_unlock(&tx->lock);
+
+ /* it's (unlikely but) possible we raced with the cleanup
+ * thread for discarding old timestamp requests.
+ */
+ if (!skb)
+ continue;
+
+ /* Extend the timestamp using cached PHC time */
+ tstamp = ice_ptp_extend_40b_ts(pf, raw_tstamp);
+ shhwtstamps.hwtstamp = ns_to_ktime(tstamp);
+
+ skb_tstamp_tx(skb, &shhwtstamps);
+ dev_kfree_skb_any(skb);
+ }
+
+ /* Check if we still have work to do. If so, re-queue this task to
+ * poll for remaining timestamps.
+ */
+ spin_lock(&tx->lock);
+ if (!bitmap_empty(tx->in_use, tx->len))
+ kthread_queue_work(pf->ptp.kworker, &tx->work);
+ spin_unlock(&tx->lock);
+}
+
+/**
+ * ice_ptp_request_ts - Request an available Tx timestamp index
+ * @tx: the PTP Tx timestamp tracker to request from
+ * @skb: the SKB to associate with this timestamp request
+ */
+s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb)
+{
+ u8 idx;
+
+ /* Check if this tracker is initialized */
+ if (!tx->init)
+ return -1;
+
+ spin_lock(&tx->lock);
+ /* Find and set the first available index */
+ idx = find_first_zero_bit(tx->in_use, tx->len);
+ if (idx < tx->len) {
+ /* We got a valid index that no other thread could have set. Store
+ * a reference to the skb and the start time to allow discarding old
+ * requests.
+ */
+ set_bit(idx, tx->in_use);
+ tx->tstamps[idx].start = jiffies;
+ tx->tstamps[idx].skb = skb_get(skb);
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ }
+
+ spin_unlock(&tx->lock);
+
+ /* return the appropriate PHY timestamp register index, -1 if no
+ * indexes were available.
+ */
+ if (idx >= tx->len)
+ return -1;
+ else
+ return idx + tx->quad_offset;
+}
+
+/**
+ * ice_ptp_process_ts - Spawn kthread work to handle timestamps
+ * @pf: Board private structure
+ *
+ * Queue work required to process the PTP Tx timestamps outside of interrupt
+ * context.
+ */
+void ice_ptp_process_ts(struct ice_pf *pf)
+{
+ if (pf->ptp.port.tx.init)
+ kthread_queue_work(pf->ptp.kworker, &pf->ptp.port.tx.work);
+}
+
+/**
+ * ice_ptp_alloc_tx_tracker - Initialize tracking for Tx timestamps
+ * @tx: Tx tracking structure to initialize
+ *
+ * Assumes that the length has already been initialized. Do not call directly,
+ * use the ice_ptp_init_tx_e822 or ice_ptp_init_tx_e810 instead.
+ */
+static int
+ice_ptp_alloc_tx_tracker(struct ice_ptp_tx *tx)
+{
+ tx->tstamps = kcalloc(tx->len, sizeof(*tx->tstamps), GFP_KERNEL);
+ if (!tx->tstamps)
+ return -ENOMEM;
+
+ tx->in_use = bitmap_zalloc(tx->len, GFP_KERNEL);
+ if (!tx->in_use) {
+ kfree(tx->tstamps);
+ tx->tstamps = NULL;
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&tx->lock);
+ kthread_init_work(&tx->work, ice_ptp_tx_tstamp_work);
+
+ tx->init = 1;
+
+ return 0;
+}
+
+/**
+ * ice_ptp_flush_tx_tracker - Flush any remaining timestamps from the tracker
+ * @pf: Board private structure
+ * @tx: the tracker to flush
+ */
+static void
+ice_ptp_flush_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
+{
+ u8 idx;
+
+ for (idx = 0; idx < tx->len; idx++) {
+ u8 phy_idx = idx + tx->quad_offset;
+
+ /* Clear any potential residual timestamp in the PHY block */
+ if (!pf->hw.reset_ongoing)
+ ice_clear_phy_tstamp(&pf->hw, tx->quad, phy_idx);
+
+ if (tx->tstamps[idx].skb) {
+ dev_kfree_skb_any(tx->tstamps[idx].skb);
+ tx->tstamps[idx].skb = NULL;
+ }
+ }
+}
+
+/**
+ * ice_ptp_release_tx_tracker - Release allocated memory for Tx tracker
+ * @pf: Board private structure
+ * @tx: Tx tracking structure to release
+ *
+ * Free memory associated with the Tx timestamp tracker.
+ */
+static void
+ice_ptp_release_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
+{
+ tx->init = 0;
+
+ kthread_cancel_work_sync(&tx->work);
+
+ ice_ptp_flush_tx_tracker(pf, tx);
+
+ kfree(tx->tstamps);
+ tx->tstamps = NULL;
+
+ kfree(tx->in_use);
+ tx->in_use = NULL;
+
+ tx->len = 0;
+}
+
+/**
+ * ice_ptp_init_tx_e810 - Initialize tracking for Tx timestamps
+ * @pf: Board private structure
+ * @tx: the Tx tracking structure to initialize
+ *
+ * Initialize the Tx timestamp tracker for this PF. For E810 devices, each
+ * port has its own block of timestamps, independent of the other ports.
+ */
+static int
+ice_ptp_init_tx_e810(struct ice_pf *pf, struct ice_ptp_tx *tx)
+{
+ tx->quad = pf->hw.port_info->lport;
+ tx->quad_offset = 0;
+ tx->len = INDEX_PER_QUAD;
+
+ return ice_ptp_alloc_tx_tracker(tx);
+}
+
+/**
+ * ice_ptp_tx_tstamp_cleanup - Cleanup old timestamp requests that got dropped
+ * @tx: PTP Tx tracker to clean up
+ *
+ * Loop through the Tx timestamp requests and see if any of them have been
+ * waiting for a long time. Discard any SKBs that have been waiting for more
+ * than 2 seconds. This is long enough to be reasonably sure that the
+ * timestamp will never be captured. This might happen if the packet gets
+ * discarded before it reaches the PHY timestamping block.
+ */
+static void ice_ptp_tx_tstamp_cleanup(struct ice_ptp_tx *tx)
+{
+ u8 idx;
+
+ if (!tx->init)
+ return;
+
+ for_each_set_bit(idx, tx->in_use, tx->len) {
+ struct sk_buff *skb;
+
+ /* Check if this SKB has been waiting for too long */
+ if (time_is_after_jiffies(tx->tstamps[idx].start + 2 * HZ))
+ continue;
+
+ spin_lock(&tx->lock);
+ skb = tx->tstamps[idx].skb;
+ tx->tstamps[idx].skb = NULL;
+ clear_bit(idx, tx->in_use);
+ spin_unlock(&tx->lock);
+
+ /* Free the SKB after we've cleared the bit */
+ dev_kfree_skb_any(skb);
+ }
+}
+
+static void ice_ptp_periodic_work(struct kthread_work *work)
+{
+ struct ice_ptp *ptp = container_of(work, struct ice_ptp, work.work);
+ struct ice_pf *pf = container_of(ptp, struct ice_pf, ptp);
+
+ if (!test_bit(ICE_FLAG_PTP, pf->flags))
+ return;
+
+ ice_ptp_update_cached_phctime(pf);
+
+ ice_ptp_tx_tstamp_cleanup(&pf->ptp.port.tx);
+
+ /* Run twice a second */
+ kthread_queue_delayed_work(ptp->kworker, &ptp->work,
+ msecs_to_jiffies(500));
+}
+
+/**
+ * ice_ptp_init_owner - Initialize PTP_1588_CLOCK device
+ * @pf: Board private structure
+ *
+ * Setup and initialize a PTP clock device that represents the device hardware
+ * clock. Save the clock index for other functions connected to the same
+ * hardware resource.
+ */
+static int ice_ptp_init_owner(struct ice_pf *pf)
+{
+ struct device *dev = ice_pf_to_dev(pf);
+ struct ice_hw *hw = &pf->hw;
+ struct timespec64 ts;
+ u8 src_idx;
+ int err;
+
+ wr32(hw, GLTSYN_SYNC_DLAY, 0);
+
+ /* Clear some HW residue and enable source clock */
+ src_idx = hw->func_caps.ts_func_info.tmr_index_owned;
+
+ /* Enable source clocks */
+ wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M);
+
+ /* Enable PHY time sync */
+ err = ice_ptp_init_phy_e810(hw);
+ if (err)
+ goto err_exit;
+
+ /* Clear event status indications for auxiliary pins */
+ (void)rd32(hw, GLTSYN_STAT(src_idx));
+
+ /* Acquire the global hardware lock */
+ if (!ice_ptp_lock(hw)) {
+ err = -EBUSY;
+ goto err_exit;
+ }
+
+ /* Write the increment time value to PHY and LAN */
+ err = ice_ptp_write_incval(hw, ICE_PTP_NOMINAL_INCVAL_E810);
+ if (err) {
+ ice_ptp_unlock(hw);
+ goto err_exit;
+ }
+
+ ts = ktime_to_timespec64(ktime_get_real());
+ /* Write the initial Time value to PHY and LAN */
+ err = ice_ptp_write_init(pf, &ts);
+ if (err) {
+ ice_ptp_unlock(hw);
+ goto err_exit;
+ }
+
+ /* Release the global hardware lock */
+ ice_ptp_unlock(hw);
+
+ /* Ensure we have a clock device */
+ err = ice_ptp_create_clock(pf);
+ if (err)
+ goto err_clk;
+
+ /* Store the PTP clock index for other PFs */
+ ice_set_ptp_clock_index(pf);
+
+ return 0;
+
+err_clk:
+ pf->ptp.clock = NULL;
+err_exit:
+ dev_err(dev, "PTP failed to register clock, err %d\n", err);
+
+ return err;
+}
+
+/**
+ * ice_ptp_init - Initialize the PTP support after device probe or reset
+ * @pf: Board private structure
+ *
+ * This function sets device up for PTP support. The first time it is run, it
+ * will create a clock device. It does not create a clock device if one
+ * already exists. It also reconfigures the device after a reset.
+ */
+void ice_ptp_init(struct ice_pf *pf)
+{
+ struct device *dev = ice_pf_to_dev(pf);
+ struct kthread_worker *kworker;
+ struct ice_hw *hw = &pf->hw;
+ int err;
+
+ /* PTP is currently only supported on E810 devices */
+ if (!ice_is_e810(hw))
+ return;
+
+ /* Check if this PF owns the source timer */
+ if (hw->func_caps.ts_func_info.src_tmr_owned) {
+ err = ice_ptp_init_owner(pf);
+ if (err)
+ return;
+ }
+
+ /* Disable timestamping for both Tx and Rx */
+ ice_ptp_cfg_timestamp(pf, false);
+
+ /* Initialize the PTP port Tx timestamp tracker */
+ ice_ptp_init_tx_e810(pf, &pf->ptp.port.tx);
+
+ /* Initialize work functions */
+ kthread_init_delayed_work(&pf->ptp.work, ice_ptp_periodic_work);
+ kthread_init_work(&pf->ptp.extts_work, ice_ptp_extts_work);
+
+ /* Allocate a kworker for handling work required for the ports
+ * connected to the PTP hardware clock.
+ */
+ kworker = kthread_create_worker(0, "ice-ptp-%s", dev_name(dev));
+ if (IS_ERR(kworker)) {
+ err = PTR_ERR(kworker);
+ goto err_kworker;
+ }
+ pf->ptp.kworker = kworker;
+
+ set_bit(ICE_FLAG_PTP, pf->flags);
+
+ /* Start periodic work going */
+ kthread_queue_delayed_work(pf->ptp.kworker, &pf->ptp.work, 0);
+
+ dev_info(dev, "PTP init successful\n");
+ return;
+
+err_kworker:
+ /* If we registered a PTP clock, release it */
+ if (pf->ptp.clock) {
+ ptp_clock_unregister(pf->ptp.clock);
+ pf->ptp.clock = NULL;
+ }
+ dev_err(dev, "PTP failed %d\n", err);
+}
+
+/**
+ * ice_ptp_release - Disable the driver/HW support and unregister the clock
+ * @pf: Board private structure
+ *
+ * This function handles the cleanup work required from the initialization by
+ * clearing out the important information and unregistering the clock
+ */
+void ice_ptp_release(struct ice_pf *pf)
+{
+ /* Disable timestamping for both Tx and Rx */
+ ice_ptp_cfg_timestamp(pf, false);
+
+ ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx);
+
+ clear_bit(ICE_FLAG_PTP, pf->flags);
+
+ kthread_cancel_delayed_work_sync(&pf->ptp.work);
+
+ if (pf->ptp.kworker) {
+ kthread_destroy_worker(pf->ptp.kworker);
+ pf->ptp.kworker = NULL;
+ }
+
+ if (!pf->ptp.clock)
+ return;
+
+ ice_clear_ptp_clock_index(pf);
+ ptp_clock_unregister(pf->ptp.clock);
+ pf->ptp.clock = NULL;
+
+ dev_info(ice_pf_to_dev(pf), "Removed PTP clock\n");
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h
new file mode 100644
index 000000000000..e1c787bd5b96
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.h
@@ -0,0 +1,204 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021, Intel Corporation. */
+
+#ifndef _ICE_PTP_H_
+#define _ICE_PTP_H_
+
+#include <linux/ptp_clock_kernel.h>
+#include <linux/kthread.h>
+
+#include "ice_ptp_hw.h"
+
+enum ice_ptp_pin {
+ GPIO_20 = 0,
+ GPIO_21,
+ GPIO_22,
+ GPIO_23,
+ NUM_ICE_PTP_PIN
+};
+
+struct ice_perout_channel {
+ bool ena;
+ u32 gpio_pin;
+ u64 period;
+ u64 start_time;
+};
+
+/* The ice hardware captures Tx hardware timestamps in the PHY. The timestamp
+ * is stored in a buffer of registers. Depending on the specific hardware,
+ * this buffer might be shared across multiple PHY ports.
+ *
+ * On transmit of a packet to be timestamped, software is responsible for
+ * selecting an open index. Hardware makes no attempt to lock or prevent
+ * re-use of an index for multiple packets.
+ *
+ * To handle this, timestamp indexes must be tracked by software to ensure
+ * that an index is not re-used for multiple transmitted packets. The
+ * structures and functions declared in this file track the available Tx
+ * register indexes, as well as provide storage for the SKB pointers.
+ *
+ * To allow multiple ports to access the shared register block independently,
+ * the blocks are split up so that indexes are assigned to each port based on
+ * hardware logical port number.
+ */
+
+/**
+ * struct ice_tx_tstamp - Tracking for a single Tx timestamp
+ * @skb: pointer to the SKB for this timestamp request
+ * @start: jiffies when the timestamp was first requested
+ *
+ * This structure tracks a single timestamp request. The SKB pointer is
+ * provided when initiating a request. The start time is used to ensure that
+ * we discard old requests that were not fulfilled within a 2 second time
+ * window.
+ */
+struct ice_tx_tstamp {
+ struct sk_buff *skb;
+ unsigned long start;
+};
+
+/**
+ * struct ice_ptp_tx - Tracking structure for all Tx timestamp requests on a port
+ * @work: work function to handle processing of Tx timestamps
+ * @lock: lock to prevent concurrent write to in_use bitmap
+ * @tstamps: array of len to store outstanding requests
+ * @in_use: bitmap of len to indicate which slots are in use
+ * @quad: which quad the timestamps are captured in
+ * @quad_offset: offset into timestamp block of the quad to get the real index
+ * @len: length of the tstamps and in_use fields.
+ * @init: if true, the tracker is initialized;
+ */
+struct ice_ptp_tx {
+ struct kthread_work work;
+ spinlock_t lock; /* lock protecting in_use bitmap */
+ struct ice_tx_tstamp *tstamps;
+ unsigned long *in_use;
+ u8 quad;
+ u8 quad_offset;
+ u8 len;
+ u8 init;
+};
+
+/* Quad and port information for initializing timestamp blocks */
+#define INDEX_PER_QUAD 64
+#define INDEX_PER_PORT (INDEX_PER_QUAD / ICE_PORTS_PER_QUAD)
+
+/**
+ * struct ice_ptp_port - data used to initialize an external port for PTP
+ *
+ * This structure contains PTP data related to the external ports. Currently
+ * it is used for tracking the Tx timestamps of a port. In the future this
+ * structure will also hold information for the E822 port initialization
+ * logic.
+ *
+ * @tx: Tx timestamp tracking for this port
+ */
+struct ice_ptp_port {
+ struct ice_ptp_tx tx;
+};
+
+#define GLTSYN_TGT_H_IDX_MAX 4
+
+/**
+ * struct ice_ptp - data used for integrating with CONFIG_PTP_1588_CLOCK
+ * @port: data for the PHY port initialization procedure
+ * @work: delayed work function for periodic tasks
+ * @extts_work: work function for handling external Tx timestamps
+ * @cached_phc_time: a cached copy of the PHC time for timestamp extension
+ * @ext_ts_chan: the external timestamp channel in use
+ * @ext_ts_irq: the external timestamp IRQ in use
+ * @kworker: kwork thread for handling periodic work
+ * @perout_channels: periodic output data
+ * @info: structure defining PTP hardware capabilities
+ * @clock: pointer to registered PTP clock device
+ * @tstamp_config: hardware timestamping configuration
+ */
+struct ice_ptp {
+ struct ice_ptp_port port;
+ struct kthread_delayed_work work;
+ struct kthread_work extts_work;
+ u64 cached_phc_time;
+ u8 ext_ts_chan;
+ u8 ext_ts_irq;
+ struct kthread_worker *kworker;
+ struct ice_perout_channel perout_channels[GLTSYN_TGT_H_IDX_MAX];
+ struct ptp_clock_info info;
+ struct ptp_clock *clock;
+ struct hwtstamp_config tstamp_config;
+};
+
+#define __ptp_port_to_ptp(p) \
+ container_of((p), struct ice_ptp, port)
+#define ptp_port_to_pf(p) \
+ container_of(__ptp_port_to_ptp((p)), struct ice_pf, ptp)
+
+#define __ptp_info_to_ptp(i) \
+ container_of((i), struct ice_ptp, info)
+#define ptp_info_to_pf(i) \
+ container_of(__ptp_info_to_ptp((i)), struct ice_pf, ptp)
+
+#define PTP_SHARED_CLK_IDX_VALID BIT(31)
+#define ICE_PTP_TS_VALID BIT(0)
+
+/* Per-channel register definitions */
+#define GLTSYN_AUX_OUT(_chan, _idx) (GLTSYN_AUX_OUT_0(_idx) + ((_chan) * 8))
+#define GLTSYN_AUX_IN(_chan, _idx) (GLTSYN_AUX_IN_0(_idx) + ((_chan) * 8))
+#define GLTSYN_CLKO(_chan, _idx) (GLTSYN_CLKO_0(_idx) + ((_chan) * 8))
+#define GLTSYN_TGT_L(_chan, _idx) (GLTSYN_TGT_L_0(_idx) + ((_chan) * 16))
+#define GLTSYN_TGT_H(_chan, _idx) (GLTSYN_TGT_H_0(_idx) + ((_chan) * 16))
+#define GLTSYN_EVNT_L(_chan, _idx) (GLTSYN_EVNT_L_0(_idx) + ((_chan) * 16))
+#define GLTSYN_EVNT_H(_chan, _idx) (GLTSYN_EVNT_H_0(_idx) + ((_chan) * 16))
+#define GLTSYN_EVNT_H_IDX_MAX 3
+
+/* Pin definitions for PTP PPS out */
+#define PPS_CLK_GEN_CHAN 3
+#define PPS_CLK_SRC_CHAN 2
+#define PPS_PIN_INDEX 5
+#define TIME_SYNC_PIN_INDEX 4
+#define E810_N_EXT_TS 3
+#define E810_N_PER_OUT 4
+
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+struct ice_pf;
+int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr);
+int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr);
+int ice_get_ptp_clock_index(struct ice_pf *pf);
+
+s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb);
+void ice_ptp_process_ts(struct ice_pf *pf);
+
+void
+ice_ptp_rx_hwtstamp(struct ice_ring *rx_ring,
+ union ice_32b_rx_flex_desc *rx_desc, struct sk_buff *skb);
+void ice_ptp_init(struct ice_pf *pf);
+void ice_ptp_release(struct ice_pf *pf);
+#else /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */
+static inline int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int ice_get_ptp_clock_index(struct ice_pf *pf)
+{
+ return -1;
+}
+
+static inline s8
+ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb)
+{
+ return -1;
+}
+
+static inline void ice_ptp_process_ts(struct ice_pf *pf) { }
+static inline void
+ice_ptp_rx_hwtstamp(struct ice_ring *rx_ring,
+ union ice_32b_rx_flex_desc *rx_desc, struct sk_buff *skb) { }
+static inline void ice_ptp_init(struct ice_pf *pf) { }
+static inline void ice_ptp_release(struct ice_pf *pf) { }
+#endif /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */
+#endif /* _ICE_PTP_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
new file mode 100644
index 000000000000..3eca0e4eab0b
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
@@ -0,0 +1,651 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2021, Intel Corporation. */
+
+#include "ice_common.h"
+#include "ice_ptp_hw.h"
+
+/* Low level functions for interacting with and managing the device clock used
+ * for the Precision Time Protocol.
+ *
+ * The ice hardware represents the current time using three registers:
+ *
+ * GLTSYN_TIME_H GLTSYN_TIME_L GLTSYN_TIME_R
+ * +---------------+ +---------------+ +---------------+
+ * | 32 bits | | 32 bits | | 32 bits |
+ * +---------------+ +---------------+ +---------------+
+ *
+ * The registers are incremented every clock tick using a 40bit increment
+ * value defined over two registers:
+ *
+ * GLTSYN_INCVAL_H GLTSYN_INCVAL_L
+ * +---------------+ +---------------+
+ * | 8 bit s | | 32 bits |
+ * +---------------+ +---------------+
+ *
+ * The increment value is added to the GLSTYN_TIME_R and GLSTYN_TIME_L
+ * registers every clock source tick. Depending on the specific device
+ * configuration, the clock source frequency could be one of a number of
+ * values.
+ *
+ * For E810 devices, the increment frequency is 812.5 MHz
+ *
+ * The hardware captures timestamps in the PHY for incoming packets, and for
+ * outgoing packets on request. To support this, the PHY maintains a timer
+ * that matches the lower 64 bits of the global source timer.
+ *
+ * In order to ensure that the PHY timers and the source timer are equivalent,
+ * shadow registers are used to prepare the desired initial values. A special
+ * sync command is issued to trigger copying from the shadow registers into
+ * the appropriate source and PHY registers simultaneously.
+ */
+
+/**
+ * ice_get_ptp_src_clock_index - determine source clock index
+ * @hw: pointer to HW struct
+ *
+ * Determine the source clock index currently in use, based on device
+ * capabilities reported during initialization.
+ */
+u8 ice_get_ptp_src_clock_index(struct ice_hw *hw)
+{
+ return hw->func_caps.ts_func_info.tmr_index_assoc;
+}
+
+/* E810 functions
+ *
+ * The following functions operate on the E810 series devices which use
+ * a separate external PHY.
+ */
+
+/**
+ * ice_read_phy_reg_e810 - Read register from external PHY on E810
+ * @hw: pointer to the HW struct
+ * @addr: the address to read from
+ * @val: On return, the value read from the PHY
+ *
+ * Read a register from the external PHY on the E810 device.
+ */
+static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val)
+{
+ struct ice_sbq_msg_input msg = {0};
+ int status;
+
+ msg.msg_addr_low = lower_16_bits(addr);
+ msg.msg_addr_high = upper_16_bits(addr);
+ msg.opcode = ice_sbq_msg_rd;
+ msg.dest_dev = rmn_0;
+
+ status = ice_sbq_rw_reg(hw, &msg);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, status %d\n",
+ status);
+ return status;
+ }
+
+ *val = msg.data;
+
+ return 0;
+}
+
+/**
+ * ice_write_phy_reg_e810 - Write register on external PHY on E810
+ * @hw: pointer to the HW struct
+ * @addr: the address to writem to
+ * @val: the value to write to the PHY
+ *
+ * Write a value to a register of the external PHY on the E810 device.
+ */
+static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val)
+{
+ struct ice_sbq_msg_input msg = {0};
+ int status;
+
+ msg.msg_addr_low = lower_16_bits(addr);
+ msg.msg_addr_high = upper_16_bits(addr);
+ msg.opcode = ice_sbq_msg_wr;
+ msg.dest_dev = rmn_0;
+ msg.data = val;
+
+ status = ice_sbq_rw_reg(hw, &msg);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, status %d\n",
+ status);
+ return status;
+ }
+
+ return 0;
+}
+
+/**
+ * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY
+ * @hw: pointer to the HW struct
+ * @lport: the lport to read from
+ * @idx: the timestamp index to read
+ * @tstamp: on return, the 40bit timestamp value
+ *
+ * Read a 40bit timestamp value out of the timestamp block of the external PHY
+ * on the E810 device.
+ */
+static int
+ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp)
+{
+ u32 lo_addr, hi_addr, lo, hi;
+ int status;
+
+ lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
+ hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
+
+ status = ice_read_phy_reg_e810(hw, lo_addr, &lo);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, status %d\n",
+ status);
+ return status;
+ }
+
+ status = ice_read_phy_reg_e810(hw, hi_addr, &hi);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, status %d\n",
+ status);
+ return status;
+ }
+
+ /* For E810 devices, the timestamp is reported with the lower 32 bits
+ * in the low register, and the upper 8 bits in the high register.
+ */
+ *tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M);
+
+ return 0;
+}
+
+/**
+ * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY
+ * @hw: pointer to the HW struct
+ * @lport: the lport to read from
+ * @idx: the timestamp index to reset
+ *
+ * Clear a timestamp, resetting its valid bit, from the timestamp block of the
+ * external PHY on the E810 device.
+ */
+static int ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx)
+{
+ u32 lo_addr, hi_addr;
+ int status;
+
+ lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
+ hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
+
+ status = ice_write_phy_reg_e810(hw, lo_addr, 0);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, status %d\n",
+ status);
+ return status;
+ }
+
+ status = ice_write_phy_reg_e810(hw, hi_addr, 0);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, status %d\n",
+ status);
+ return status;
+ }
+
+ return 0;
+}
+
+/**
+ * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY
+ * @hw: pointer to HW struct
+ *
+ * Enable the timesync PTP functionality for the external PHY connected to
+ * this function.
+ */
+int ice_ptp_init_phy_e810(struct ice_hw *hw)
+{
+ int status;
+ u8 tmr_idx;
+
+ tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
+ status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx),
+ GLTSYN_ENA_TSYN_ENA_M);
+ if (status)
+ ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n",
+ status);
+
+ return status;
+}
+
+/**
+ * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time
+ * @hw: Board private structure
+ * @time: Time to initialize the PHY port clock to
+ *
+ * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the
+ * initial clock time. The time will not actually be programmed until the
+ * driver issues an INIT_TIME command.
+ *
+ * The time value is the upper 32 bits of the PHY timer, usually in units of
+ * nominal nanoseconds.
+ */
+static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time)
+{
+ int status;
+ u8 tmr_idx;
+
+ tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
+ status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, status %d\n",
+ status);
+ return status;
+ }
+
+ status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, status %d\n",
+ status);
+ return status;
+ }
+
+ return 0;
+}
+
+/**
+ * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment
+ * @hw: pointer to HW struct
+ * @adj: adjustment value to program
+ *
+ * Prepare the PHY port for an atomic adjustment by programming the PHY
+ * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment
+ * is completed by issuing an ADJ_TIME sync command.
+ *
+ * The adjustment value only contains the portion used for the upper 32bits of
+ * the PHY timer, usually in units of nominal nanoseconds. Negative
+ * adjustments are supported using 2s complement arithmetic.
+ */
+static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj)
+{
+ int status;
+ u8 tmr_idx;
+
+ tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
+
+ /* Adjustments are represented as signed 2's complement values in
+ * nanoseconds. Sub-nanosecond adjustment is not supported.
+ */
+ status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), 0);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, status %d\n",
+ status);
+ return status;
+ }
+
+ status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), adj);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, status %d\n",
+ status);
+ return status;
+ }
+
+ return 0;
+}
+
+/**
+ * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change
+ * @hw: pointer to HW struct
+ * @incval: The new 40bit increment value to prepare
+ *
+ * Prepare the PHY port for a new increment value by programming the PHY
+ * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is
+ * completed by issuing an INIT_INCVAL command.
+ */
+static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval)
+{
+ u32 high, low;
+ int status;
+ u8 tmr_idx;
+
+ tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
+ low = lower_32_bits(incval);
+ high = upper_32_bits(incval);
+
+ status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, status %d\n",
+ status);
+ return status;
+ }
+
+ status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, status %d\n",
+ status);
+ return status;
+ }
+
+ return 0;
+}
+
+/**
+ * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command
+ * @hw: pointer to HW struct
+ * @cmd: Command to be sent to the port
+ *
+ * Prepare the external PHYs connected to this device for a timer sync
+ * command.
+ */
+static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
+{
+ u32 cmd_val, val;
+ int status;
+
+ switch (cmd) {
+ case INIT_TIME:
+ cmd_val = GLTSYN_CMD_INIT_TIME;
+ break;
+ case INIT_INCVAL:
+ cmd_val = GLTSYN_CMD_INIT_INCVAL;
+ break;
+ case ADJ_TIME:
+ cmd_val = GLTSYN_CMD_ADJ_TIME;
+ break;
+ case READ_TIME:
+ cmd_val = GLTSYN_CMD_READ_TIME;
+ break;
+ case ADJ_TIME_AT_TIME:
+ cmd_val = GLTSYN_CMD_ADJ_INIT_TIME;
+ break;
+ }
+
+ /* Read, modify, write */
+ status = ice_read_phy_reg_e810(hw, ETH_GLTSYN_CMD, &val);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, status %d\n", status);
+ return status;
+ }
+
+ /* Modify necessary bits only and perform write */
+ val &= ~TS_CMD_MASK_E810;
+ val |= cmd_val;
+
+ status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_CMD, val);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, status %d\n", status);
+ return status;
+ }
+
+ return 0;
+}
+
+/* Device agnostic functions
+ *
+ * The following functions implement useful behavior to hide the differences
+ * between E810 and other devices. They call the device-specific
+ * implementations where necessary.
+ *
+ * Currently, the driver only supports E810, but future work will enable
+ * support for E822-based devices.
+ */
+
+/**
+ * ice_ptp_lock - Acquire PTP global semaphore register lock
+ * @hw: pointer to the HW struct
+ *
+ * Acquire the global PTP hardware semaphore lock. Returns true if the lock
+ * was acquired, false otherwise.
+ *
+ * The PFTSYN_SEM register sets the busy bit on read, returning the previous
+ * value. If software sees the busy bit cleared, this means that this function
+ * acquired the lock (and the busy bit is now set). If software sees the busy
+ * bit set, it means that another function acquired the lock.
+ *
+ * Software must clear the busy bit with a write to release the lock for other
+ * functions when done.
+ */
+bool ice_ptp_lock(struct ice_hw *hw)
+{
+ u32 hw_lock;
+ int i;
+
+#define MAX_TRIES 5
+
+ for (i = 0; i < MAX_TRIES; i++) {
+ hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
+ hw_lock = hw_lock & PFTSYN_SEM_BUSY_M;
+ if (!hw_lock)
+ break;
+
+ /* Somebody is holding the lock */
+ usleep_range(10000, 20000);
+ }
+
+ return !hw_lock;
+}
+
+/**
+ * ice_ptp_unlock - Release PTP global semaphore register lock
+ * @hw: pointer to the HW struct
+ *
+ * Release the global PTP hardware semaphore lock. This is done by writing to
+ * the PFTSYN_SEM register.
+ */
+void ice_ptp_unlock(struct ice_hw *hw)
+{
+ wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0);
+}
+
+/**
+ * ice_ptp_src_cmd - Prepare source timer for a timer command
+ * @hw: pointer to HW structure
+ * @cmd: Timer command
+ *
+ * Prepare the source timer for an upcoming timer sync command.
+ */
+static void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
+{
+ u32 cmd_val;
+ u8 tmr_idx;
+
+ tmr_idx = ice_get_ptp_src_clock_index(hw);
+ cmd_val = tmr_idx << SEL_CPK_SRC;
+
+ switch (cmd) {
+ case INIT_TIME:
+ cmd_val |= GLTSYN_CMD_INIT_TIME;
+ break;
+ case INIT_INCVAL:
+ cmd_val |= GLTSYN_CMD_INIT_INCVAL;
+ break;
+ case ADJ_TIME:
+ cmd_val |= GLTSYN_CMD_ADJ_TIME;
+ break;
+ case ADJ_TIME_AT_TIME:
+ cmd_val |= GLTSYN_CMD_ADJ_INIT_TIME;
+ break;
+ case READ_TIME:
+ cmd_val |= GLTSYN_CMD_READ_TIME;
+ break;
+ }
+
+ wr32(hw, GLTSYN_CMD, cmd_val);
+}
+
+/**
+ * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command
+ * @hw: pointer to HW struct
+ * @cmd: the command to issue
+ *
+ * Prepare the source timer and PHY timers and then trigger the requested
+ * command. This causes the shadow registers previously written in preparation
+ * for the command to be synchronously applied to both the source and PHY
+ * timers.
+ */
+static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
+{
+ int status;
+
+ /* First, prepare the source timer */
+ ice_ptp_src_cmd(hw, cmd);
+
+ /* Next, prepare the ports */
+ status = ice_ptp_port_cmd_e810(hw, cmd);
+ if (status) {
+ ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, status %d\n",
+ cmd, status);
+ return status;
+ }
+
+ /* Write the sync command register to drive both source and PHY timer commands
+ * synchronously
+ */
+ wr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD);
+
+ return 0;
+}
+
+/**
+ * ice_ptp_init_time - Initialize device time to provided value
+ * @hw: pointer to HW struct
+ * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H)
+ *
+ * Initialize the device to the specified time provided. This requires a three
+ * step process:
+ *
+ * 1) write the new init time to the source timer shadow registers
+ * 2) write the new init time to the PHY timer shadow registers
+ * 3) issue an init_time timer command to synchronously switch both the source
+ * and port timers to the new init time value at the next clock cycle.
+ */
+int ice_ptp_init_time(struct ice_hw *hw, u64 time)
+{
+ int status;
+ u8 tmr_idx;
+
+ tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
+
+ /* Source timers */
+ wr32(hw, GLTSYN_SHTIME_L(tmr_idx), lower_32_bits(time));
+ wr32(hw, GLTSYN_SHTIME_H(tmr_idx), upper_32_bits(time));
+ wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0);
+
+ /* PHY timers */
+ /* Fill Rx and Tx ports and send msg to PHY */
+ status = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF);
+ if (status)
+ return status;
+
+ return ice_ptp_tmr_cmd(hw, INIT_TIME);
+}
+
+/**
+ * ice_ptp_write_incval - Program PHC with new increment value
+ * @hw: pointer to HW struct
+ * @incval: Source timer increment value per clock cycle
+ *
+ * Program the PHC with a new increment value. This requires a three-step
+ * process:
+ *
+ * 1) Write the increment value to the source timer shadow registers
+ * 2) Write the increment value to the PHY timer shadow registers
+ * 3) Issue an INIT_INCVAL timer command to synchronously switch both the
+ * source and port timers to the new increment value at the next clock
+ * cycle.
+ */
+int ice_ptp_write_incval(struct ice_hw *hw, u64 incval)
+{
+ int status;
+ u8 tmr_idx;
+
+ tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
+
+ /* Shadow Adjust */
+ wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval));
+ wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval));
+
+ status = ice_ptp_prep_phy_incval_e810(hw, incval);
+ if (status)
+ return status;
+
+ return ice_ptp_tmr_cmd(hw, INIT_INCVAL);
+}
+
+/**
+ * ice_ptp_write_incval_locked - Program new incval while holding semaphore
+ * @hw: pointer to HW struct
+ * @incval: Source timer increment value per clock cycle
+ *
+ * Program a new PHC incval while holding the PTP semaphore.
+ */
+int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval)
+{
+ int status;
+
+ if (!ice_ptp_lock(hw))
+ return -EBUSY;
+
+ status = ice_ptp_write_incval(hw, incval);
+
+ ice_ptp_unlock(hw);
+
+ return status;
+}
+
+/**
+ * ice_ptp_adj_clock - Adjust PHC clock time atomically
+ * @hw: pointer to HW struct
+ * @adj: Adjustment in nanoseconds
+ *
+ * Perform an atomic adjustment of the PHC time by the specified number of
+ * nanoseconds. This requires a three-step process:
+ *
+ * 1) Write the adjustment to the source timer shadow registers
+ * 2) Write the adjustment to the PHY timer shadow registers
+ * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to
+ * both the source and port timers at the next clock cycle.
+ */
+int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
+{
+ int status;
+ u8 tmr_idx;
+
+ tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
+
+ /* Write the desired clock adjustment into the GLTSYN_SHADJ register.
+ * For an ADJ_TIME command, this set of registers represents the value
+ * to add to the clock time. It supports subtraction by interpreting
+ * the value as a 2's complement integer.
+ */
+ wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0);
+ wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj);
+
+ status = ice_ptp_prep_phy_adj_e810(hw, adj);
+ if (status)
+ return status;
+
+ return ice_ptp_tmr_cmd(hw, ADJ_TIME);
+}
+
+/**
+ * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block
+ * @hw: pointer to the HW struct
+ * @block: the block to read from
+ * @idx: the timestamp index to read
+ * @tstamp: on return, the 40bit timestamp value
+ *
+ * Read a 40bit timestamp value out of the timestamp block.
+ */
+int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp)
+{
+ return ice_read_phy_tstamp_e810(hw, block, idx, tstamp);
+}
+
+/**
+ * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block
+ * @hw: pointer to the HW struct
+ * @block: the block to read from
+ * @idx: the timestamp index to reset
+ *
+ * Clear a timestamp, resetting its valid bit, from the timestamp block.
+ */
+int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx)
+{
+ return ice_clear_phy_tstamp_e810(hw, block, idx);
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
new file mode 100644
index 000000000000..55a414e87018
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021, Intel Corporation. */
+
+#ifndef _ICE_PTP_HW_H_
+#define _ICE_PTP_HW_H_
+
+enum ice_ptp_tmr_cmd {
+ INIT_TIME,
+ INIT_INCVAL,
+ ADJ_TIME,
+ ADJ_TIME_AT_TIME,
+ READ_TIME
+};
+
+/* Increment value to generate nanoseconds in the GLTSYN_TIME_L register for
+ * the E810 devices. Based off of a PLL with an 812.5 MHz frequency.
+ */
+#define ICE_PTP_NOMINAL_INCVAL_E810 0x13b13b13bULL
+
+/* Device agnostic functions */
+u8 ice_get_ptp_src_clock_index(struct ice_hw *hw);
+bool ice_ptp_lock(struct ice_hw *hw);
+void ice_ptp_unlock(struct ice_hw *hw);
+int ice_ptp_init_time(struct ice_hw *hw, u64 time);
+int ice_ptp_write_incval(struct ice_hw *hw, u64 incval);
+int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval);
+int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj);
+int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp);
+int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx);
+
+/* E810 family functions */
+int ice_ptp_init_phy_e810(struct ice_hw *hw);
+
+#define PFTSYN_SEM_BYTES 4
+
+/* PHY timer commands */
+#define SEL_CPK_SRC 8
+
+/* Time Sync command Definitions */
+#define GLTSYN_CMD_INIT_TIME BIT(0)
+#define GLTSYN_CMD_INIT_INCVAL BIT(1)
+#define GLTSYN_CMD_ADJ_TIME BIT(2)
+#define GLTSYN_CMD_ADJ_INIT_TIME (BIT(2) | BIT(3))
+#define GLTSYN_CMD_READ_TIME BIT(7)
+
+#define TS_CMD_MASK_E810 0xFF
+#define SYNC_EXEC_CMD 0x3
+
+/* E810 timesync enable register */
+#define ETH_GLTSYN_ENA(_i) (0x03000348 + ((_i) * 4))
+
+/* E810 shadow init time registers */
+#define ETH_GLTSYN_SHTIME_0(i) (0x03000368 + ((i) * 32))
+#define ETH_GLTSYN_SHTIME_L(i) (0x0300036C + ((i) * 32))
+
+/* E810 shadow time adjust registers */
+#define ETH_GLTSYN_SHADJ_L(_i) (0x03000378 + ((_i) * 32))
+#define ETH_GLTSYN_SHADJ_H(_i) (0x0300037C + ((_i) * 32))
+
+/* E810 timer command register */
+#define ETH_GLTSYN_CMD 0x03000344
+
+/* Source timer incval macros */
+#define INCVAL_HIGH_M 0xFF
+
+/* Timestamp block macros */
+#define TS_LOW_M 0xFFFFFFFF
+#define TS_HIGH_S 32
+
+#define BYTES_PER_IDX_ADDR_L_U 8
+
+/* External PHY timestamp address */
+#define TS_EXT(a, port, idx) ((a) + (0x1000 * (port)) + \
+ ((idx) * BYTES_PER_IDX_ADDR_L_U))
+
+#define LOW_TX_MEMORY_BANK_START 0x03090000
+#define HIGH_TX_MEMORY_BANK_START 0x03090004
+
+#endif /* _ICE_PTP_HW_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h b/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h
new file mode 100644
index 000000000000..ead75fe2bcda
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_sbq_cmd.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021, Intel Corporation. */
+
+#ifndef _ICE_SBQ_CMD_H_
+#define _ICE_SBQ_CMD_H_
+
+/* This header file defines the Sideband Queue commands, error codes and
+ * descriptor format. It is shared between Firmware and Software.
+ */
+
+/* Sideband Queue command structure and opcodes */
+enum ice_sbq_opc {
+ /* Sideband Queue commands */
+ ice_sbq_opc_neigh_dev_req = 0x0C00,
+ ice_sbq_opc_neigh_dev_ev = 0x0C01
+};
+
+/* Sideband Queue descriptor. Indirect command
+ * and non posted
+ */
+struct ice_sbq_cmd_desc {
+ __le16 flags;
+ __le16 opcode;
+ __le16 datalen;
+ __le16 cmd_retval;
+
+ /* Opaque message data */
+ __le32 cookie_high;
+ __le32 cookie_low;
+
+ union {
+ __le16 cmd_len;
+ __le16 cmpl_len;
+ } param0;
+
+ u8 reserved[6];
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
+struct ice_sbq_evt_desc {
+ __le16 flags;
+ __le16 opcode;
+ __le16 datalen;
+ __le16 cmd_retval;
+ u8 data[24];
+};
+
+enum ice_sbq_msg_dev {
+ rmn_0 = 0x02,
+ rmn_1 = 0x03,
+ rmn_2 = 0x04,
+ cgu = 0x06
+};
+
+enum ice_sbq_msg_opcode {
+ ice_sbq_msg_rd = 0x00,
+ ice_sbq_msg_wr = 0x01
+};
+
+#define ICE_SBQ_MSG_FLAGS 0x40
+#define ICE_SBQ_MSG_SBE_FBE 0x0F
+
+struct ice_sbq_msg_req {
+ u8 dest_dev;
+ u8 src_dev;
+ u8 opcode;
+ u8 flags;
+ u8 sbe_fbe;
+ u8 func_id;
+ __le16 msg_addr_low;
+ __le32 msg_addr_high;
+ __le32 data;
+};
+
+struct ice_sbq_msg_cmpl {
+ u8 dest_dev;
+ u8 src_dev;
+ u8 opcode;
+ u8 flags;
+ __le32 data;
+};
+
+/* Internal struct */
+struct ice_sbq_msg_input {
+ u8 dest_dev;
+ u8 opcode;
+ u16 msg_addr_low;
+ u32 msg_addr_high;
+ u32 data;
+};
+#endif /* _ICE_SBQ_CMD_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c
index 2f097637e405..9f07b6641705 100644
--- a/drivers/net/ethernet/intel/ice/ice_sched.c
+++ b/drivers/net/ethernet/intel/ice/ice_sched.c
@@ -596,6 +596,50 @@ ice_alloc_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs)
}
/**
+ * ice_alloc_rdma_q_ctx - allocate RDMA queue contexts for the given VSI and TC
+ * @hw: pointer to the HW struct
+ * @vsi_handle: VSI handle
+ * @tc: TC number
+ * @new_numqs: number of queues
+ */
+static enum ice_status
+ice_alloc_rdma_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs)
+{
+ struct ice_vsi_ctx *vsi_ctx;
+ struct ice_q_ctx *q_ctx;
+
+ vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
+ if (!vsi_ctx)
+ return ICE_ERR_PARAM;
+ /* allocate RDMA queue contexts */
+ if (!vsi_ctx->rdma_q_ctx[tc]) {
+ vsi_ctx->rdma_q_ctx[tc] = devm_kcalloc(ice_hw_to_dev(hw),
+ new_numqs,
+ sizeof(*q_ctx),
+ GFP_KERNEL);
+ if (!vsi_ctx->rdma_q_ctx[tc])
+ return ICE_ERR_NO_MEMORY;
+ vsi_ctx->num_rdma_q_entries[tc] = new_numqs;
+ return 0;
+ }
+ /* num queues are increased, update the queue contexts */
+ if (new_numqs > vsi_ctx->num_rdma_q_entries[tc]) {
+ u16 prev_num = vsi_ctx->num_rdma_q_entries[tc];
+
+ q_ctx = devm_kcalloc(ice_hw_to_dev(hw), new_numqs,
+ sizeof(*q_ctx), GFP_KERNEL);
+ if (!q_ctx)
+ return ICE_ERR_NO_MEMORY;
+ memcpy(q_ctx, vsi_ctx->rdma_q_ctx[tc],
+ prev_num * sizeof(*q_ctx));
+ devm_kfree(ice_hw_to_dev(hw), vsi_ctx->rdma_q_ctx[tc]);
+ vsi_ctx->rdma_q_ctx[tc] = q_ctx;
+ vsi_ctx->num_rdma_q_entries[tc] = new_numqs;
+ }
+ return 0;
+}
+
+/**
* ice_aq_rl_profile - performs a rate limiting task
* @hw: pointer to the HW struct
* @opcode: opcode for add, query, or remove profile(s)
@@ -1774,13 +1818,22 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle,
if (!vsi_ctx)
return ICE_ERR_PARAM;
- prev_numqs = vsi_ctx->sched.max_lanq[tc];
+ if (owner == ICE_SCHED_NODE_OWNER_LAN)
+ prev_numqs = vsi_ctx->sched.max_lanq[tc];
+ else
+ prev_numqs = vsi_ctx->sched.max_rdmaq[tc];
/* num queues are not changed or less than the previous number */
if (new_numqs <= prev_numqs)
return status;
- status = ice_alloc_lan_q_ctx(hw, vsi_handle, tc, new_numqs);
- if (status)
- return status;
+ if (owner == ICE_SCHED_NODE_OWNER_LAN) {
+ status = ice_alloc_lan_q_ctx(hw, vsi_handle, tc, new_numqs);
+ if (status)
+ return status;
+ } else {
+ status = ice_alloc_rdma_q_ctx(hw, vsi_handle, tc, new_numqs);
+ if (status)
+ return status;
+ }
if (new_numqs)
ice_sched_calc_vsi_child_nodes(hw, new_numqs, new_num_nodes);
@@ -1795,7 +1848,10 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle,
new_num_nodes, owner);
if (status)
return status;
- vsi_ctx->sched.max_lanq[tc] = new_numqs;
+ if (owner == ICE_SCHED_NODE_OWNER_LAN)
+ vsi_ctx->sched.max_lanq[tc] = new_numqs;
+ else
+ vsi_ctx->sched.max_rdmaq[tc] = new_numqs;
return 0;
}
@@ -1861,6 +1917,7 @@ ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 maxqs,
* recreate the child nodes all the time in these cases.
*/
vsi_ctx->sched.max_lanq[tc] = 0;
+ vsi_ctx->sched.max_rdmaq[tc] = 0;
}
/* update the VSI child nodes */
@@ -1990,6 +2047,8 @@ ice_sched_rm_vsi_cfg(struct ice_port_info *pi, u16 vsi_handle, u8 owner)
}
if (owner == ICE_SCHED_NODE_OWNER_LAN)
vsi_ctx->sched.max_lanq[i] = 0;
+ else
+ vsi_ctx->sched.max_rdmaq[i] = 0;
}
status = 0;
@@ -2686,8 +2745,8 @@ static enum ice_status
ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id,
u16 vsi_handle, unsigned long *tc_bitmap)
{
- struct ice_sched_agg_vsi_info *agg_vsi_info;
- struct ice_sched_agg_info *agg_info;
+ struct ice_sched_agg_vsi_info *agg_vsi_info, *old_agg_vsi_info = NULL;
+ struct ice_sched_agg_info *agg_info, *old_agg_info;
enum ice_status status = 0;
struct ice_hw *hw = pi->hw;
u8 tc;
@@ -2697,6 +2756,20 @@ ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id,
agg_info = ice_get_agg_info(hw, agg_id);
if (!agg_info)
return ICE_ERR_PARAM;
+ /* If the VSI is already part of another aggregator then update
+ * its VSI info list
+ */
+ old_agg_info = ice_get_vsi_agg_info(hw, vsi_handle);
+ if (old_agg_info && old_agg_info != agg_info) {
+ struct ice_sched_agg_vsi_info *vtmp;
+
+ list_for_each_entry_safe(old_agg_vsi_info, vtmp,
+ &old_agg_info->agg_vsi_list,
+ list_entry)
+ if (old_agg_vsi_info->vsi_handle == vsi_handle)
+ break;
+ }
+
/* check if entry already exist */
agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
if (!agg_vsi_info) {
@@ -2721,6 +2794,12 @@ ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id,
break;
set_bit(tc, agg_vsi_info->tc_bitmap);
+ if (old_agg_vsi_info)
+ clear_bit(tc, old_agg_vsi_info->tc_bitmap);
+ }
+ if (old_agg_vsi_info && !old_agg_vsi_info->tc_bitmap[0]) {
+ list_del(&old_agg_vsi_info->list_entry);
+ devm_kfree(ice_hw_to_dev(pi->hw), old_agg_vsi_info);
}
return status;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c
index 357d3073d814..3b6c1420aa7b 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.c
+++ b/drivers/net/ethernet/intel/ice/ice_switch.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2018, Intel Corporation. */
+#include "ice_lib.h"
#include "ice_switch.h"
#define ICE_ETH_DA_OFFSET 0
@@ -302,6 +303,10 @@ static void ice_clear_vsi_q_ctx(struct ice_hw *hw, u16 vsi_handle)
devm_kfree(ice_hw_to_dev(hw), vsi->lan_q_ctx[i]);
vsi->lan_q_ctx[i] = NULL;
}
+ if (vsi->rdma_q_ctx[i]) {
+ devm_kfree(ice_hw_to_dev(hw), vsi->rdma_q_ctx[i]);
+ vsi->rdma_q_ctx[i] = NULL;
+ }
}
}
@@ -423,6 +428,29 @@ ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
}
/**
+ * ice_cfg_rdma_fltr - enable/disable RDMA filtering on VSI
+ * @hw: pointer to HW struct
+ * @vsi_handle: VSI SW index
+ * @enable: boolean for enable/disable
+ */
+int
+ice_cfg_rdma_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable)
+{
+ struct ice_vsi_ctx *ctx;
+
+ ctx = ice_get_vsi_ctx(hw, vsi_handle);
+ if (!ctx)
+ return -EIO;
+
+ if (enable)
+ ctx->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
+ else
+ ctx->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
+
+ return ice_status_to_errno(ice_update_vsi(hw, vsi_handle, ctx, NULL));
+}
+
+/**
* ice_aq_alloc_free_vsi_list
* @hw: pointer to the HW struct
* @vsi_list_id: VSI list ID returned or used for lookup
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h
index 8b4f9d35c860..c5db8d56133f 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.h
+++ b/drivers/net/ethernet/intel/ice/ice_switch.h
@@ -26,6 +26,8 @@ struct ice_vsi_ctx {
u8 vf_num;
u16 num_lan_q_entries[ICE_MAX_TRAFFIC_CLASS];
struct ice_q_ctx *lan_q_ctx[ICE_MAX_TRAFFIC_CLASS];
+ u16 num_rdma_q_entries[ICE_MAX_TRAFFIC_CLASS];
+ struct ice_q_ctx *rdma_q_ctx[ICE_MAX_TRAFFIC_CLASS];
};
enum ice_sw_fwd_act_type {
@@ -223,6 +225,8 @@ enum ice_status
ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list);
enum ice_status
ice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list);
+int
+ice_cfg_rdma_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable);
void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle);
enum ice_status
ice_add_vlan(struct ice_hw *hw, struct list_head *m_list);
@@ -243,7 +247,6 @@ ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
enum ice_status ice_init_def_sw_recp(struct ice_hw *hw);
u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle);
-bool ice_is_vsi_valid(struct ice_hw *hw, u16 vsi_handle);
enum ice_status ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle);
void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw);
diff --git a/drivers/net/ethernet/intel/ice/ice_trace.h b/drivers/net/ethernet/intel/ice/ice_trace.h
new file mode 100644
index 000000000000..9bc0b8fdfc77
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_trace.h
@@ -0,0 +1,232 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021 Intel Corporation. */
+
+/* Modeled on trace-events-sample.h */
+
+/* The trace subsystem name for ice will be "ice".
+ *
+ * This file is named ice_trace.h.
+ *
+ * Since this include file's name is different from the trace
+ * subsystem name, we'll have to define TRACE_INCLUDE_FILE at the end
+ * of this file.
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM ice
+
+/* See trace-events-sample.h for a detailed description of why this
+ * guard clause is different from most normal include files.
+ */
+#if !defined(_ICE_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _ICE_TRACE_H_
+
+#include <linux/tracepoint.h>
+
+/* ice_trace() macro enables shared code to refer to trace points
+ * like:
+ *
+ * trace_ice_example(args...)
+ *
+ * ... as:
+ *
+ * ice_trace(example, args...)
+ *
+ * ... to resolve to the PF version of the tracepoint without
+ * ifdefs, and to allow tracepoints to be disabled entirely at build
+ * time.
+ *
+ * Trace point should always be referred to in the driver via this
+ * macro.
+ *
+ * Similarly, ice_trace_enabled(trace_name) wraps references to
+ * trace_ice_<trace_name>_enabled() functions.
+ * @trace_name: name of tracepoint
+ */
+#define _ICE_TRACE_NAME(trace_name) (trace_##ice##_##trace_name)
+#define ICE_TRACE_NAME(trace_name) _ICE_TRACE_NAME(trace_name)
+
+#define ice_trace(trace_name, args...) ICE_TRACE_NAME(trace_name)(args)
+
+#define ice_trace_enabled(trace_name) ICE_TRACE_NAME(trace_name##_enabled)()
+
+/* This is for events common to PF. Corresponding versions will be named
+ * trace_ice_*. The ice_trace() macro above will select the right trace point
+ * name for the driver.
+ */
+
+/* Begin tracepoints */
+
+/* Global tracepoints */
+
+/* Events related to DIM, q_vectors and ring containers */
+DECLARE_EVENT_CLASS(ice_rx_dim_template,
+ TP_PROTO(struct ice_q_vector *q_vector, struct dim *dim),
+ TP_ARGS(q_vector, dim),
+ TP_STRUCT__entry(__field(struct ice_q_vector *, q_vector)
+ __field(struct dim *, dim)
+ __string(devname, q_vector->rx.ring->netdev->name)),
+
+ TP_fast_assign(__entry->q_vector = q_vector;
+ __entry->dim = dim;
+ __assign_str(devname, q_vector->rx.ring->netdev->name);),
+
+ TP_printk("netdev: %s Rx-Q: %d dim-state: %d dim-profile: %d dim-tune: %d dim-st-right: %d dim-st-left: %d dim-tired: %d",
+ __get_str(devname),
+ __entry->q_vector->rx.ring->q_index,
+ __entry->dim->state,
+ __entry->dim->profile_ix,
+ __entry->dim->tune_state,
+ __entry->dim->steps_right,
+ __entry->dim->steps_left,
+ __entry->dim->tired)
+);
+
+DEFINE_EVENT(ice_rx_dim_template, ice_rx_dim_work,
+ TP_PROTO(struct ice_q_vector *q_vector, struct dim *dim),
+ TP_ARGS(q_vector, dim)
+);
+
+DECLARE_EVENT_CLASS(ice_tx_dim_template,
+ TP_PROTO(struct ice_q_vector *q_vector, struct dim *dim),
+ TP_ARGS(q_vector, dim),
+ TP_STRUCT__entry(__field(struct ice_q_vector *, q_vector)
+ __field(struct dim *, dim)
+ __string(devname, q_vector->tx.ring->netdev->name)),
+
+ TP_fast_assign(__entry->q_vector = q_vector;
+ __entry->dim = dim;
+ __assign_str(devname, q_vector->tx.ring->netdev->name);),
+
+ TP_printk("netdev: %s Tx-Q: %d dim-state: %d dim-profile: %d dim-tune: %d dim-st-right: %d dim-st-left: %d dim-tired: %d",
+ __get_str(devname),
+ __entry->q_vector->tx.ring->q_index,
+ __entry->dim->state,
+ __entry->dim->profile_ix,
+ __entry->dim->tune_state,
+ __entry->dim->steps_right,
+ __entry->dim->steps_left,
+ __entry->dim->tired)
+);
+
+DEFINE_EVENT(ice_tx_dim_template, ice_tx_dim_work,
+ TP_PROTO(struct ice_q_vector *q_vector, struct dim *dim),
+ TP_ARGS(q_vector, dim)
+);
+
+/* Events related to a vsi & ring */
+DECLARE_EVENT_CLASS(ice_tx_template,
+ TP_PROTO(struct ice_ring *ring, struct ice_tx_desc *desc,
+ struct ice_tx_buf *buf),
+
+ TP_ARGS(ring, desc, buf),
+ TP_STRUCT__entry(__field(void *, ring)
+ __field(void *, desc)
+ __field(void *, buf)
+ __string(devname, ring->netdev->name)),
+
+ TP_fast_assign(__entry->ring = ring;
+ __entry->desc = desc;
+ __entry->buf = buf;
+ __assign_str(devname, ring->netdev->name);),
+
+ TP_printk("netdev: %s ring: %pK desc: %pK buf %pK", __get_str(devname),
+ __entry->ring, __entry->desc, __entry->buf)
+);
+
+#define DEFINE_TX_TEMPLATE_OP_EVENT(name) \
+DEFINE_EVENT(ice_tx_template, name, \
+ TP_PROTO(struct ice_ring *ring, \
+ struct ice_tx_desc *desc, \
+ struct ice_tx_buf *buf), \
+ TP_ARGS(ring, desc, buf))
+
+DEFINE_TX_TEMPLATE_OP_EVENT(ice_clean_tx_irq);
+DEFINE_TX_TEMPLATE_OP_EVENT(ice_clean_tx_irq_unmap);
+DEFINE_TX_TEMPLATE_OP_EVENT(ice_clean_tx_irq_unmap_eop);
+
+DECLARE_EVENT_CLASS(ice_rx_template,
+ TP_PROTO(struct ice_ring *ring, union ice_32b_rx_flex_desc *desc),
+
+ TP_ARGS(ring, desc),
+
+ TP_STRUCT__entry(__field(void *, ring)
+ __field(void *, desc)
+ __string(devname, ring->netdev->name)),
+
+ TP_fast_assign(__entry->ring = ring;
+ __entry->desc = desc;
+ __assign_str(devname, ring->netdev->name);),
+
+ TP_printk("netdev: %s ring: %pK desc: %pK", __get_str(devname),
+ __entry->ring, __entry->desc)
+);
+DEFINE_EVENT(ice_rx_template, ice_clean_rx_irq,
+ TP_PROTO(struct ice_ring *ring, union ice_32b_rx_flex_desc *desc),
+ TP_ARGS(ring, desc)
+);
+
+DECLARE_EVENT_CLASS(ice_rx_indicate_template,
+ TP_PROTO(struct ice_ring *ring, union ice_32b_rx_flex_desc *desc,
+ struct sk_buff *skb),
+
+ TP_ARGS(ring, desc, skb),
+
+ TP_STRUCT__entry(__field(void *, ring)
+ __field(void *, desc)
+ __field(void *, skb)
+ __string(devname, ring->netdev->name)),
+
+ TP_fast_assign(__entry->ring = ring;
+ __entry->desc = desc;
+ __entry->skb = skb;
+ __assign_str(devname, ring->netdev->name);),
+
+ TP_printk("netdev: %s ring: %pK desc: %pK skb %pK", __get_str(devname),
+ __entry->ring, __entry->desc, __entry->skb)
+);
+
+DEFINE_EVENT(ice_rx_indicate_template, ice_clean_rx_irq_indicate,
+ TP_PROTO(struct ice_ring *ring, union ice_32b_rx_flex_desc *desc,
+ struct sk_buff *skb),
+ TP_ARGS(ring, desc, skb)
+);
+
+DECLARE_EVENT_CLASS(ice_xmit_template,
+ TP_PROTO(struct ice_ring *ring, struct sk_buff *skb),
+
+ TP_ARGS(ring, skb),
+
+ TP_STRUCT__entry(__field(void *, ring)
+ __field(void *, skb)
+ __string(devname, ring->netdev->name)),
+
+ TP_fast_assign(__entry->ring = ring;
+ __entry->skb = skb;
+ __assign_str(devname, ring->netdev->name);),
+
+ TP_printk("netdev: %s skb: %pK ring: %pK", __get_str(devname),
+ __entry->skb, __entry->ring)
+);
+
+#define DEFINE_XMIT_TEMPLATE_OP_EVENT(name) \
+DEFINE_EVENT(ice_xmit_template, name, \
+ TP_PROTO(struct ice_ring *ring, struct sk_buff *skb), \
+ TP_ARGS(ring, skb))
+
+DEFINE_XMIT_TEMPLATE_OP_EVENT(ice_xmit_frame_ring);
+DEFINE_XMIT_TEMPLATE_OP_EVENT(ice_xmit_frame_ring_drop);
+
+/* End tracepoints */
+
+#endif /* _ICE_TRACE_H_ */
+/* This must be outside ifdef _ICE_TRACE_H */
+
+/* This trace include file is not located in the .../include/trace
+ * with the kernel tracepoint definitions, because we're a loadable
+ * module.
+ */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE ../../drivers/net/ethernet/intel/ice/ice_trace
+#include <trace/define_trace.h>
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index 04748aa4c7c8..6ee8e0032d52 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -10,6 +10,7 @@
#include "ice_txrx_lib.h"
#include "ice_lib.h"
#include "ice.h"
+#include "ice_trace.h"
#include "ice_dcb_lib.h"
#include "ice_xsk.h"
@@ -224,6 +225,7 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
smp_rmb(); /* prevent any other reads prior to eop_desc */
+ ice_trace(clean_tx_irq, tx_ring, tx_desc, tx_buf);
/* if the descriptor isn't done, no work yet to do */
if (!(eop_desc->cmd_type_offset_bsz &
cpu_to_le64(ICE_TX_DESC_DTYPE_DESC_DONE)))
@@ -254,6 +256,7 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
/* unmap remaining buffers */
while (tx_desc != eop_desc) {
+ ice_trace(clean_tx_irq_unmap, tx_ring, tx_desc, tx_buf);
tx_buf++;
tx_desc++;
i++;
@@ -272,6 +275,7 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
dma_unmap_len_set(tx_buf, len, 0);
}
}
+ ice_trace(clean_tx_irq_unmap_eop, tx_ring, tx_desc, tx_buf);
/* move us one more past the eop_desc for start of next pkt */
tx_buf++;
@@ -1082,7 +1086,7 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
u16 stat_err_bits;
int rx_buf_pgcnt;
u16 vlan_tag = 0;
- u8 rx_ptype;
+ u16 rx_ptype;
/* get the Rx desc from Rx ring based on 'next_to_clean' */
rx_desc = ICE_RX_DESC(rx_ring, rx_ring->next_to_clean);
@@ -1102,6 +1106,7 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
*/
dma_rmb();
+ ice_trace(clean_rx_irq, rx_ring, rx_desc);
if (rx_desc->wb.rxdid == FDIR_DESC_RXDID || !rx_ring->netdev) {
struct ice_vsi *ctrl_vsi = rx_ring->vsi;
@@ -1135,15 +1140,11 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
xdp.frame_sz = ice_rx_frame_truesize(rx_ring, size);
#endif
- rcu_read_lock();
xdp_prog = READ_ONCE(rx_ring->xdp_prog);
- if (!xdp_prog) {
- rcu_read_unlock();
+ if (!xdp_prog)
goto construct_skb;
- }
xdp_res = ice_run_xdp(rx_ring, &xdp, xdp_prog);
- rcu_read_unlock();
if (!xdp_res)
goto construct_skb;
if (xdp_res & (ICE_XDP_TX | ICE_XDP_REDIR)) {
@@ -1207,6 +1208,7 @@ construct_skb:
ice_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype);
+ ice_trace(clean_rx_irq_indicate, rx_ring, rx_desc, skb);
/* send completed skb up the stack */
ice_receive_skb(rx_ring, skb, vlan_tag);
skb = NULL;
@@ -2137,6 +2139,41 @@ static bool ice_chk_linearize(struct sk_buff *skb, unsigned int count)
}
/**
+ * ice_tstamp - set up context descriptor for hardware timestamp
+ * @tx_ring: pointer to the Tx ring to send buffer on
+ * @skb: pointer to the SKB we're sending
+ * @first: Tx buffer
+ * @off: Tx offload parameters
+ */
+static void
+ice_tstamp(struct ice_ring *tx_ring, struct sk_buff *skb,
+ struct ice_tx_buf *first, struct ice_tx_offload_params *off)
+{
+ s8 idx;
+
+ /* only timestamp the outbound packet if the user has requested it */
+ if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)))
+ return;
+
+ if (!tx_ring->ptp_tx)
+ return;
+
+ /* Tx timestamps cannot be sampled when doing TSO */
+ if (first->tx_flags & ICE_TX_FLAGS_TSO)
+ return;
+
+ /* Grab an open timestamp slot */
+ idx = ice_ptp_request_ts(tx_ring->tx_tstamps, skb);
+ if (idx < 0)
+ return;
+
+ off->cd_qw1 |= (u64)(ICE_TX_DESC_DTYPE_CTX |
+ (ICE_TX_CTX_DESC_TSYN << ICE_TXD_CTX_QW1_CMD_S) |
+ ((u64)idx << ICE_TXD_CTX_QW1_TSO_LEN_S));
+ first->tx_flags |= ICE_TX_FLAGS_TSYN;
+}
+
+/**
* ice_xmit_frame_ring - Sends buffer on Tx ring
* @skb: send buffer
* @tx_ring: ring to send buffer on
@@ -2153,6 +2190,8 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_ring *tx_ring)
unsigned int count;
int tso, csum;
+ ice_trace(xmit_frame_ring, tx_ring, skb);
+
count = ice_xmit_desc_count(skb);
if (ice_chk_linearize(skb, count)) {
if (__skb_linearize(skb))
@@ -2205,6 +2244,8 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_ring *tx_ring)
ICE_TX_CTX_DESC_SWTCH_UPLINK <<
ICE_TXD_CTX_QW1_CMD_S);
+ ice_tstamp(tx_ring, skb, first, &offload);
+
if (offload.cd_qw1 & ICE_TX_DESC_DTYPE_CTX) {
struct ice_tx_ctx_desc *cdesc;
u16 i = tx_ring->next_to_use;
@@ -2225,6 +2266,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_ring *tx_ring)
return NETDEV_TX_OK;
out_drop:
+ ice_trace(xmit_frame_ring_drop, tx_ring, skb);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h
index c5a92ac787d6..1e46e80f3d6f 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h
@@ -118,6 +118,7 @@ static inline int ice_skb_pad(void)
* freed instead of returned like skb packets.
*/
#define ICE_TX_FLAGS_DUMMY_PKT BIT(3)
+#define ICE_TX_FLAGS_TSYN BIT(4)
#define ICE_TX_FLAGS_IPV4 BIT(5)
#define ICE_TX_FLAGS_IPV6 BIT(6)
#define ICE_TX_FLAGS_TUNNEL BIT(7)
@@ -311,6 +312,10 @@ struct ice_ring {
u32 txq_teid; /* Added Tx queue TEID */
u16 rx_buf_len;
u8 dcb_tc; /* Traffic class of ring */
+ struct ice_ptp_tx *tx_tstamps;
+ u64 cached_phctime;
+ u8 ptp_rx:1;
+ u8 ptp_tx:1;
} ____cacheline_internodealigned_in_smp;
static inline bool ice_ring_uses_build_skb(struct ice_ring *ring)
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
index 207f6ee3a7f6..171397dcf00a 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
@@ -38,10 +38,23 @@ void ice_release_rx_desc(struct ice_ring *rx_ring, u16 val)
* ice_ptype_to_htype - get a hash type
* @ptype: the ptype value from the descriptor
*
- * Returns a hash type to be used by skb_set_hash
+ * Returns appropriate hash type (such as PKT_HASH_TYPE_L2/L3/L4) to be used by
+ * skb_set_hash based on PTYPE as parsed by HW Rx pipeline and is part of
+ * Rx desc.
*/
-static enum pkt_hash_types ice_ptype_to_htype(u8 __always_unused ptype)
+static enum pkt_hash_types ice_ptype_to_htype(u16 ptype)
{
+ struct ice_rx_ptype_decoded decoded = ice_decode_rx_desc_ptype(ptype);
+
+ if (!decoded.known)
+ return PKT_HASH_TYPE_NONE;
+ if (decoded.payload_layer == ICE_RX_PTYPE_PAYLOAD_LAYER_PAY4)
+ return PKT_HASH_TYPE_L4;
+ if (decoded.payload_layer == ICE_RX_PTYPE_PAYLOAD_LAYER_PAY3)
+ return PKT_HASH_TYPE_L3;
+ if (decoded.outer_ip == ICE_RX_PTYPE_OUTER_L2)
+ return PKT_HASH_TYPE_L2;
+
return PKT_HASH_TYPE_NONE;
}
@@ -54,7 +67,7 @@ static enum pkt_hash_types ice_ptype_to_htype(u8 __always_unused ptype)
*/
static void
ice_rx_hash(struct ice_ring *rx_ring, union ice_32b_rx_flex_desc *rx_desc,
- struct sk_buff *skb, u8 rx_ptype)
+ struct sk_buff *skb, u16 rx_ptype)
{
struct ice_32b_rx_flex_desc_nic *nic_mdid;
u32 hash;
@@ -81,7 +94,7 @@ ice_rx_hash(struct ice_ring *rx_ring, union ice_32b_rx_flex_desc *rx_desc,
*/
static void
ice_rx_csum(struct ice_ring *ring, struct sk_buff *skb,
- union ice_32b_rx_flex_desc *rx_desc, u8 ptype)
+ union ice_32b_rx_flex_desc *rx_desc, u16 ptype)
{
struct ice_rx_ptype_decoded decoded;
u16 rx_status0, rx_status1;
@@ -167,7 +180,7 @@ checksum_fail:
void
ice_process_skb_fields(struct ice_ring *rx_ring,
union ice_32b_rx_flex_desc *rx_desc,
- struct sk_buff *skb, u8 ptype)
+ struct sk_buff *skb, u16 ptype)
{
ice_rx_hash(rx_ring, rx_desc, skb, ptype);
@@ -175,6 +188,9 @@ ice_process_skb_fields(struct ice_ring *rx_ring,
skb->protocol = eth_type_trans(skb, rx_ring->netdev);
ice_rx_csum(rx_ring, skb, rx_desc, ptype);
+
+ if (rx_ring->ptp_rx)
+ ice_ptp_rx_hwtstamp(rx_ring, rx_desc, skb);
}
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
index 58ff58f0f972..05ac30752902 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
@@ -53,7 +53,7 @@ void ice_release_rx_desc(struct ice_ring *rx_ring, u16 val);
void
ice_process_skb_fields(struct ice_ring *rx_ring,
union ice_32b_rx_flex_desc *rx_desc,
- struct sk_buff *skb, u8 ptype);
+ struct sk_buff *skb, u16 ptype);
void
ice_receive_skb(struct ice_ring *rx_ring, struct sk_buff *skb, u16 vlan_tag);
#endif /* !_ICE_TXRX_LIB_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h
index 4474dd6a7ba1..d33d1906103c 100644
--- a/drivers/net/ethernet/intel/ice/ice_type.h
+++ b/drivers/net/ethernet/intel/ice/ice_type.h
@@ -14,6 +14,7 @@
#include "ice_lan_tx_rx.h"
#include "ice_flex_type.h"
#include "ice_protocol_type.h"
+#include "ice_sbq_cmd.h"
static inline bool ice_is_tc_ena(unsigned long bitmap, u8 tc)
{
@@ -45,8 +46,10 @@ static inline u32 ice_round_to_num(u32 N, u32 R)
#define ICE_DBG_FLOW BIT_ULL(9)
#define ICE_DBG_SW BIT_ULL(13)
#define ICE_DBG_SCHED BIT_ULL(14)
+#define ICE_DBG_RDMA BIT_ULL(15)
#define ICE_DBG_PKG BIT_ULL(16)
#define ICE_DBG_RES BIT_ULL(17)
+#define ICE_DBG_PTP BIT_ULL(19)
#define ICE_DBG_AQ_MSG BIT_ULL(24)
#define ICE_DBG_AQ_DESC BIT_ULL(25)
#define ICE_DBG_AQ_DESC_BUF BIT_ULL(26)
@@ -63,7 +66,7 @@ enum ice_aq_res_ids {
/* FW update timeout definitions are in milliseconds */
#define ICE_NVM_TIMEOUT 180000
#define ICE_CHANGE_LOCK_TIMEOUT 1000
-#define ICE_GLOBAL_CFG_LOCK_TIMEOUT 3000
+#define ICE_GLOBAL_CFG_LOCK_TIMEOUT 5000
enum ice_aq_res_access_type {
ICE_RES_READ = 1,
@@ -146,6 +149,7 @@ struct ice_link_status {
u16 max_frame_size;
u16 link_speed;
u16 req_speeds;
+ u8 link_cfg_err;
u8 lse_ena; /* Link Status Event notification */
u8 link_info;
u8 an_info;
@@ -262,6 +266,8 @@ struct ice_hw_common_caps {
u8 rss_table_entry_width; /* RSS Entry width in bits */
u8 dcb;
+ u8 ieee_1588;
+ u8 rdma;
bool nvm_update_pending_nvm;
bool nvm_update_pending_orom;
@@ -273,6 +279,54 @@ struct ice_hw_common_caps {
#define ICE_NVM_MGMT_UNIFIED_UPD_SUPPORT BIT(3)
};
+/* IEEE 1588 TIME_SYNC specific info */
+/* Function specific definitions */
+#define ICE_TS_FUNC_ENA_M BIT(0)
+#define ICE_TS_SRC_TMR_OWND_M BIT(1)
+#define ICE_TS_TMR_ENA_M BIT(2)
+#define ICE_TS_TMR_IDX_OWND_S 4
+#define ICE_TS_TMR_IDX_OWND_M BIT(4)
+#define ICE_TS_CLK_FREQ_S 16
+#define ICE_TS_CLK_FREQ_M ICE_M(0x7, ICE_TS_CLK_FREQ_S)
+#define ICE_TS_CLK_SRC_S 20
+#define ICE_TS_CLK_SRC_M BIT(20)
+#define ICE_TS_TMR_IDX_ASSOC_S 24
+#define ICE_TS_TMR_IDX_ASSOC_M BIT(24)
+
+struct ice_ts_func_info {
+ /* Function specific info */
+ u32 clk_freq;
+ u8 clk_src;
+ u8 tmr_index_assoc;
+ u8 ena;
+ u8 tmr_index_owned;
+ u8 src_tmr_owned;
+ u8 tmr_ena;
+};
+
+/* Device specific definitions */
+#define ICE_TS_TMR0_OWNR_M 0x7
+#define ICE_TS_TMR0_OWND_M BIT(3)
+#define ICE_TS_TMR1_OWNR_S 4
+#define ICE_TS_TMR1_OWNR_M ICE_M(0x7, ICE_TS_TMR1_OWNR_S)
+#define ICE_TS_TMR1_OWND_M BIT(7)
+#define ICE_TS_DEV_ENA_M BIT(24)
+#define ICE_TS_TMR0_ENA_M BIT(25)
+#define ICE_TS_TMR1_ENA_M BIT(26)
+
+struct ice_ts_dev_info {
+ /* Device specific info */
+ u32 ena_ports;
+ u32 tmr_own_map;
+ u32 tmr0_owner;
+ u32 tmr1_owner;
+ u8 tmr0_owned;
+ u8 tmr1_owned;
+ u8 ena;
+ u8 tmr0_ena;
+ u8 tmr1_ena;
+};
+
/* Function specific capabilities */
struct ice_hw_func_caps {
struct ice_hw_common_caps common_cap;
@@ -281,6 +335,7 @@ struct ice_hw_func_caps {
u32 guar_num_vsi;
u32 fd_fltr_guar; /* Number of filters guaranteed */
u32 fd_fltr_best_effort; /* Number of best effort filters */
+ struct ice_ts_func_info ts_func_info;
};
/* Device wide capabilities */
@@ -289,6 +344,7 @@ struct ice_hw_dev_caps {
u32 num_vfs_exposed; /* Total number of VFs exposed */
u32 num_vsi_allocd_to_host; /* Excluding EMP VSI */
u32 num_flow_director_fltr; /* Number of FD filters available */
+ struct ice_ts_dev_info ts_dev_info;
u32 num_funcs;
};
@@ -440,6 +496,7 @@ struct ice_sched_node {
u8 tc_num;
u8 owner;
#define ICE_SCHED_NODE_OWNER_LAN 0
+#define ICE_SCHED_NODE_OWNER_RDMA 2
};
/* Access Macros for Tx Sched Elements data */
@@ -511,6 +568,7 @@ struct ice_sched_vsi_info {
struct ice_sched_node *ag_node[ICE_MAX_TRAFFIC_CLASS];
struct list_head list_entry;
u16 max_lanq[ICE_MAX_TRAFFIC_CLASS];
+ u16 max_rdmaq[ICE_MAX_TRAFFIC_CLASS];
};
/* driver defines the policy */
@@ -749,6 +807,7 @@ struct ice_hw {
/* Control Queue info */
struct ice_ctl_q_info adminq;
+ struct ice_ctl_q_info sbq;
struct ice_ctl_q_info mailboxq;
u8 api_branch; /* API branch version */
@@ -784,6 +843,14 @@ struct ice_hw {
u8 ucast_shared; /* true if VSIs can share unicast addr */
+#define ICE_PHY_PER_NAC 1
+#define ICE_MAX_QUAD 2
+#define ICE_NUM_QUAD_TYPE 2
+#define ICE_PORTS_PER_QUAD 4
+#define ICE_PHY_0_LAST_QUAD 1
+#define ICE_PORTS_PER_PHY 8
+#define ICE_NUM_EXTERNAL_PORTS ICE_PORTS_PER_PHY
+
/* Active package version (currently active) */
struct ice_pkg_ver active_pkg_ver;
u32 active_track_id;
diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
index 97a46c616aca..2826570dab51 100644
--- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
@@ -939,16 +939,18 @@ static int ice_vf_rebuild_host_mac_cfg(struct ice_vf *vf)
vf->num_mac++;
- if (is_valid_ether_addr(vf->dflt_lan_addr.addr)) {
- status = ice_fltr_add_mac(vsi, vf->dflt_lan_addr.addr,
+ if (is_valid_ether_addr(vf->hw_lan_addr.addr)) {
+ status = ice_fltr_add_mac(vsi, vf->hw_lan_addr.addr,
ICE_FWD_TO_VSI);
if (status) {
dev_err(dev, "failed to add default unicast MAC filter %pM for VF %u, error %s\n",
- &vf->dflt_lan_addr.addr[0], vf->vf_id,
+ &vf->hw_lan_addr.addr[0], vf->vf_id,
ice_stat_str(status));
return ice_status_to_errno(status);
}
vf->num_mac++;
+
+ ether_addr_copy(vf->dev_lan_addr.addr, vf->hw_lan_addr.addr);
}
return 0;
@@ -1687,7 +1689,6 @@ bool ice_reset_vf(struct ice_vf *vf, bool is_vflr)
else
promisc_m = ICE_UCAST_PROMISC_BITS;
- vsi = ice_get_vf_vsi(vf);
if (ice_vf_set_vsi_promisc(vf, vsi, promisc_m, true))
dev_err(dev, "disabling promiscuous mode failed\n");
}
@@ -2386,7 +2387,7 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg)
vfres->vsi_res[0].vsi_type = VIRTCHNL_VSI_SRIOV;
vfres->vsi_res[0].num_queue_pairs = vsi->num_txq;
ether_addr_copy(vfres->vsi_res[0].default_mac_addr,
- vf->dflt_lan_addr.addr);
+ vf->hw_lan_addr.addr);
/* match guest capabilities */
vf->driver_caps = vfres->vf_cap_flags;
@@ -3542,10 +3543,9 @@ static int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg)
struct virtchnl_vsi_queue_config_info *qci =
(struct virtchnl_vsi_queue_config_info *)msg;
struct virtchnl_queue_pair_info *qpi;
- u16 num_rxq = 0, num_txq = 0;
struct ice_pf *pf = vf->pf;
struct ice_vsi *vsi;
- int i;
+ int i, q_idx;
if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
@@ -3583,18 +3583,31 @@ static int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg)
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
+
+ q_idx = qpi->rxq.queue_id;
+
+ /* make sure selected "q_idx" is in valid range of queues
+ * for selected "vsi"
+ */
+ if (q_idx >= vsi->alloc_txq || q_idx >= vsi->alloc_rxq) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto error_param;
+ }
+
/* copy Tx queue info from VF into VSI */
if (qpi->txq.ring_len > 0) {
- num_txq++;
vsi->tx_rings[i]->dma = qpi->txq.dma_ring_addr;
vsi->tx_rings[i]->count = qpi->txq.ring_len;
+ if (ice_vsi_cfg_single_txq(vsi, vsi->tx_rings, q_idx)) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto error_param;
+ }
}
/* copy Rx queue info from VF into VSI */
if (qpi->rxq.ring_len > 0) {
u16 max_frame_size = ice_vc_get_max_frame_size(vf);
- num_rxq++;
vsi->rx_rings[i]->dma = qpi->rxq.dma_ring_addr;
vsi->rx_rings[i]->count = qpi->rxq.ring_len;
@@ -3611,27 +3624,20 @@ static int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg)
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
- }
- vsi->max_frame = qpi->rxq.max_pkt_size;
- /* add space for the port VLAN since the VF driver is not
- * expected to account for it in the MTU calculation
- */
- if (vf->port_vlan_info)
- vsi->max_frame += VLAN_HLEN;
- }
-
- /* VF can request to configure less than allocated queues or default
- * allocated queues. So update the VSI with new number
- */
- vsi->num_txq = num_txq;
- vsi->num_rxq = num_rxq;
- /* All queues of VF VSI are in TC 0 */
- vsi->tc_cfg.tc_info[0].qcount_tx = num_txq;
- vsi->tc_cfg.tc_info[0].qcount_rx = num_rxq;
+ vsi->max_frame = qpi->rxq.max_pkt_size;
+ /* add space for the port VLAN since the VF driver is not
+ * expected to account for it in the MTU calculation
+ */
+ if (vf->port_vlan_info)
+ vsi->max_frame += VLAN_HLEN;
- if (ice_vsi_cfg_lan_txqs(vsi) || ice_vsi_cfg_rxqs(vsi))
- v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR;
+ if (ice_vsi_cfg_single_rxq(vsi, q_idx)) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto error_param;
+ }
+ }
+ }
error_param:
/* send the response to the VF */
@@ -3667,19 +3673,95 @@ static bool ice_can_vf_change_mac(struct ice_vf *vf)
}
/**
+ * ice_vc_ether_addr_type - get type of virtchnl_ether_addr
+ * @vc_ether_addr: used to extract the type
+ */
+static u8
+ice_vc_ether_addr_type(struct virtchnl_ether_addr *vc_ether_addr)
+{
+ return (vc_ether_addr->type & VIRTCHNL_ETHER_ADDR_TYPE_MASK);
+}
+
+/**
+ * ice_is_vc_addr_legacy - check if the MAC address is from an older VF
+ * @vc_ether_addr: VIRTCHNL structure that contains MAC and type
+ */
+static bool
+ice_is_vc_addr_legacy(struct virtchnl_ether_addr *vc_ether_addr)
+{
+ u8 type = ice_vc_ether_addr_type(vc_ether_addr);
+
+ return (type == VIRTCHNL_ETHER_ADDR_LEGACY);
+}
+
+/**
+ * ice_is_vc_addr_primary - check if the MAC address is the VF's primary MAC
+ * @vc_ether_addr: VIRTCHNL structure that contains MAC and type
+ *
+ * This function should only be called when the MAC address in
+ * virtchnl_ether_addr is a valid unicast MAC
+ */
+static bool
+ice_is_vc_addr_primary(struct virtchnl_ether_addr __maybe_unused *vc_ether_addr)
+{
+ u8 type = ice_vc_ether_addr_type(vc_ether_addr);
+
+ return (type == VIRTCHNL_ETHER_ADDR_PRIMARY);
+}
+
+/**
+ * ice_vfhw_mac_add - update the VF's cached hardware MAC if allowed
+ * @vf: VF to update
+ * @vc_ether_addr: structure from VIRTCHNL with MAC to add
+ */
+static void
+ice_vfhw_mac_add(struct ice_vf *vf, struct virtchnl_ether_addr *vc_ether_addr)
+{
+ u8 *mac_addr = vc_ether_addr->addr;
+
+ if (!is_valid_ether_addr(mac_addr))
+ return;
+
+ /* only allow legacy VF drivers to set the device and hardware MAC if it
+ * is zero and allow new VF drivers to set the hardware MAC if the type
+ * was correctly specified over VIRTCHNL
+ */
+ if ((ice_is_vc_addr_legacy(vc_ether_addr) &&
+ is_zero_ether_addr(vf->hw_lan_addr.addr)) ||
+ ice_is_vc_addr_primary(vc_ether_addr)) {
+ ether_addr_copy(vf->dev_lan_addr.addr, mac_addr);
+ ether_addr_copy(vf->hw_lan_addr.addr, mac_addr);
+ }
+
+ /* hardware and device MACs are already set, but its possible that the
+ * VF driver sent the VIRTCHNL_OP_ADD_ETH_ADDR message before the
+ * VIRTCHNL_OP_DEL_ETH_ADDR when trying to update its MAC, so save it
+ * away for the legacy VF driver case as it will be updated in the
+ * delete flow for this case
+ */
+ if (ice_is_vc_addr_legacy(vc_ether_addr)) {
+ ether_addr_copy(vf->legacy_last_added_umac.addr,
+ mac_addr);
+ vf->legacy_last_added_umac.time_modified = jiffies;
+ }
+}
+
+/**
* ice_vc_add_mac_addr - attempt to add the MAC address passed in
* @vf: pointer to the VF info
* @vsi: pointer to the VF's VSI
- * @mac_addr: MAC address to add
+ * @vc_ether_addr: VIRTCHNL MAC address structure used to add MAC
*/
static int
-ice_vc_add_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi, u8 *mac_addr)
+ice_vc_add_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi,
+ struct virtchnl_ether_addr *vc_ether_addr)
{
struct device *dev = ice_pf_to_dev(vf->pf);
+ u8 *mac_addr = vc_ether_addr->addr;
enum ice_status status;
- /* default unicast MAC already added */
- if (ether_addr_equal(mac_addr, vf->dflt_lan_addr.addr))
+ /* device MAC already added */
+ if (ether_addr_equal(mac_addr, vf->dev_lan_addr.addr))
return 0;
if (is_unicast_ether_addr(mac_addr) && !ice_can_vf_change_mac(vf)) {
@@ -3698,12 +3780,7 @@ ice_vc_add_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi, u8 *mac_addr)
return -EIO;
}
- /* Set the default LAN address to the latest unicast MAC address added
- * by the VF. The default LAN address is reported by the PF via
- * ndo_get_vf_config.
- */
- if (is_unicast_ether_addr(mac_addr))
- ether_addr_copy(vf->dflt_lan_addr.addr, mac_addr);
+ ice_vfhw_mac_add(vf, vc_ether_addr);
vf->num_mac++;
@@ -3711,19 +3788,65 @@ ice_vc_add_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi, u8 *mac_addr)
}
/**
+ * ice_is_legacy_umac_expired - check if last added legacy unicast MAC expired
+ * @last_added_umac: structure used to check expiration
+ */
+static bool ice_is_legacy_umac_expired(struct ice_time_mac *last_added_umac)
+{
+#define ICE_LEGACY_VF_MAC_CHANGE_EXPIRE_TIME msecs_to_jiffies(3000)
+ return time_is_before_jiffies(last_added_umac->time_modified +
+ ICE_LEGACY_VF_MAC_CHANGE_EXPIRE_TIME);
+}
+
+/**
+ * ice_vfhw_mac_del - update the VF's cached hardware MAC if allowed
+ * @vf: VF to update
+ * @vc_ether_addr: structure from VIRTCHNL with MAC to delete
+ */
+static void
+ice_vfhw_mac_del(struct ice_vf *vf, struct virtchnl_ether_addr *vc_ether_addr)
+{
+ u8 *mac_addr = vc_ether_addr->addr;
+
+ if (!is_valid_ether_addr(mac_addr) ||
+ !ether_addr_equal(vf->dev_lan_addr.addr, mac_addr))
+ return;
+
+ /* allow the device MAC to be repopulated in the add flow and don't
+ * clear the hardware MAC (i.e. hw_lan_addr.addr) here as that is meant
+ * to be persistent on VM reboot and across driver unload/load, which
+ * won't work if we clear the hardware MAC here
+ */
+ eth_zero_addr(vf->dev_lan_addr.addr);
+
+ /* only update cached hardware MAC for legacy VF drivers on delete
+ * because we cannot guarantee order/type of MAC from the VF driver
+ */
+ if (ice_is_vc_addr_legacy(vc_ether_addr) &&
+ !ice_is_legacy_umac_expired(&vf->legacy_last_added_umac)) {
+ ether_addr_copy(vf->dev_lan_addr.addr,
+ vf->legacy_last_added_umac.addr);
+ ether_addr_copy(vf->hw_lan_addr.addr,
+ vf->legacy_last_added_umac.addr);
+ }
+}
+
+/**
* ice_vc_del_mac_addr - attempt to delete the MAC address passed in
* @vf: pointer to the VF info
* @vsi: pointer to the VF's VSI
- * @mac_addr: MAC address to delete
+ * @vc_ether_addr: VIRTCHNL MAC address structure used to delete MAC
*/
static int
-ice_vc_del_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi, u8 *mac_addr)
+ice_vc_del_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi,
+ struct virtchnl_ether_addr *vc_ether_addr)
{
struct device *dev = ice_pf_to_dev(vf->pf);
+ u8 *mac_addr = vc_ether_addr->addr;
enum ice_status status;
if (!ice_can_vf_change_mac(vf) &&
- ether_addr_equal(mac_addr, vf->dflt_lan_addr.addr))
+ ether_addr_equal(vf->dev_lan_addr.addr, mac_addr))
return 0;
status = ice_fltr_remove_mac(vsi, mac_addr, ICE_FWD_TO_VSI);
@@ -3737,8 +3860,7 @@ ice_vc_del_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi, u8 *mac_addr)
return -EIO;
}
- if (ether_addr_equal(mac_addr, vf->dflt_lan_addr.addr))
- eth_zero_addr(vf->dflt_lan_addr.addr);
+ ice_vfhw_mac_del(vf, vc_ether_addr);
vf->num_mac--;
@@ -3757,7 +3879,8 @@ static int
ice_vc_handle_mac_addr_msg(struct ice_vf *vf, u8 *msg, bool set)
{
int (*ice_vc_cfg_mac)
- (struct ice_vf *vf, struct ice_vsi *vsi, u8 *mac_addr);
+ (struct ice_vf *vf, struct ice_vsi *vsi,
+ struct virtchnl_ether_addr *virtchnl_ether_addr);
enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
struct virtchnl_ether_addr_list *al =
(struct virtchnl_ether_addr_list *)msg;
@@ -3806,7 +3929,7 @@ ice_vc_handle_mac_addr_msg(struct ice_vf *vf, u8 *msg, bool set)
is_zero_ether_addr(mac_addr))
continue;
- result = ice_vc_cfg_mac(vf, vsi, mac_addr);
+ result = ice_vc_cfg_mac(vf, vsi, &al->list[i]);
if (result == -EEXIST || result == -ENOENT) {
continue;
} else if (result) {
@@ -4444,7 +4567,7 @@ ice_get_vf_cfg(struct net_device *netdev, int vf_id, struct ifla_vf_info *ivi)
return -EBUSY;
ivi->vf = vf_id;
- ether_addr_copy(ivi->mac, vf->dflt_lan_addr.addr);
+ ether_addr_copy(ivi->mac, vf->hw_lan_addr.addr);
/* VF configuration for VLAN and applicable QoS */
ivi->vlan = vf->port_vlan_info & VLAN_VID_MASK;
@@ -4520,7 +4643,8 @@ int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
vf = &pf->vf[vf_id];
/* nothing left to do, unicast MAC already set */
- if (ether_addr_equal(vf->dflt_lan_addr.addr, mac))
+ if (ether_addr_equal(vf->dev_lan_addr.addr, mac) &&
+ ether_addr_equal(vf->hw_lan_addr.addr, mac))
return 0;
ret = ice_check_vf_ready_for_cfg(vf);
@@ -4536,7 +4660,8 @@ int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
/* VF is notified of its new MAC via the PF's response to the
* VIRTCHNL_OP_GET_VF_RESOURCES message after the VF has been reset
*/
- ether_addr_copy(vf->dflt_lan_addr.addr, mac);
+ ether_addr_copy(vf->dev_lan_addr.addr, mac);
+ ether_addr_copy(vf->hw_lan_addr.addr, mac);
if (is_zero_ether_addr(mac)) {
/* VF will send VIRTCHNL_OP_ADD_ETH_ADDR message with its MAC */
vf->pf_set_mac = false;
@@ -4689,7 +4814,7 @@ void ice_print_vf_rx_mdd_event(struct ice_vf *vf)
dev_info(dev, "%d Rx Malicious Driver Detection events detected on PF %d VF %d MAC %pM. mdd-auto-reset-vfs=%s\n",
vf->mdd_rx_events.count, pf->hw.pf_id, vf->vf_id,
- vf->dflt_lan_addr.addr,
+ vf->dev_lan_addr.addr,
test_bit(ICE_FLAG_MDD_AUTO_RESET_VF, pf->flags)
? "on" : "off");
}
@@ -4733,7 +4858,7 @@ void ice_print_vfs_mdd_events(struct ice_pf *pf)
dev_info(dev, "%d Tx Malicious Driver Detection events detected on PF %d VF %d MAC %pM.\n",
vf->mdd_tx_events.count, hw->pf_id, i,
- vf->dflt_lan_addr.addr);
+ vf->dev_lan_addr.addr);
}
}
}
@@ -4823,7 +4948,7 @@ ice_is_malicious_vf(struct ice_pf *pf, struct ice_rq_event_info *event,
if (pf_vsi)
dev_warn(dev, "VF MAC %pM on PF MAC %pM is generating asynchronous messages and may be overflowing the PF message queue. Please see the Adapter User Guide for more information\n",
- &vf->dflt_lan_addr.addr[0],
+ &vf->dev_lan_addr.addr[0],
pf_vsi->netdev->dev_addr);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
index d800ed83d6c3..842cb077df86 100644
--- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
+++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
@@ -58,6 +58,11 @@ enum ice_virtchnl_cap {
ICE_VIRTCHNL_VF_CAP_PRIVILEGE,
};
+struct ice_time_mac {
+ unsigned long time_modified;
+ u8 addr[ETH_ALEN];
+};
+
/* VF MDD events print structure */
struct ice_mdd_vf_events {
u16 count; /* total count of Rx|Tx events */
@@ -78,7 +83,9 @@ struct ice_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;
+ struct virtchnl_ether_addr dev_lan_addr;
+ struct virtchnl_ether_addr hw_lan_addr;
+ struct ice_time_mac legacy_last_added_umac;
DECLARE_BITMAP(txq_ena, ICE_MAX_RSS_QS_PER_VF);
DECLARE_BITMAP(rxq_ena, ICE_MAX_RSS_QS_PER_VF);
u16 port_vlan_info; /* Port VLAN ID and QoS */
@@ -151,16 +158,18 @@ ice_vc_send_msg_to_vf(struct ice_vf *vf, u32 v_opcode,
enum virtchnl_status_code v_retval, u8 *msg, u16 msglen);
bool ice_vc_isvalid_vsi_id(struct ice_vf *vf, u16 vsi_id);
#else /* CONFIG_PCI_IOV */
-#define ice_process_vflr_event(pf) do {} while (0)
-#define ice_free_vfs(pf) do {} while (0)
-#define ice_vc_process_vf_msg(pf, event) do {} while (0)
-#define ice_vc_notify_link_state(pf) do {} while (0)
-#define ice_vc_notify_reset(pf) do {} while (0)
-#define ice_set_vf_state_qs_dis(vf) do {} while (0)
-#define ice_vf_lan_overflow_event(pf, event) do {} while (0)
-#define ice_print_vfs_mdd_events(pf) do {} while (0)
-#define ice_print_vf_rx_mdd_event(vf) do {} while (0)
-#define ice_restore_all_vfs_msi_state(pdev) do {} while (0)
+static inline void ice_process_vflr_event(struct ice_pf *pf) { }
+static inline void ice_free_vfs(struct ice_pf *pf) { }
+static inline
+void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event) { }
+static inline void ice_vc_notify_link_state(struct ice_pf *pf) { }
+static inline void ice_vc_notify_reset(struct ice_pf *pf) { }
+static inline void ice_set_vf_state_qs_dis(struct ice_vf *vf) { }
+static inline
+void ice_vf_lan_overflow_event(struct ice_pf *pf, struct ice_rq_event_info *event) { }
+static inline void ice_print_vfs_mdd_events(struct ice_pf *pf) { }
+static inline void ice_print_vf_rx_mdd_event(struct ice_vf *vf) { }
+static inline void ice_restore_all_vfs_msi_state(struct pci_dev *pdev) { }
static inline bool
ice_is_malicious_vf(struct ice_pf __always_unused *pf,
diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c
index a1f89ea3c2bd..5a9f61deeb38 100644
--- a/drivers/net/ethernet/intel/ice/ice_xsk.c
+++ b/drivers/net/ethernet/intel/ice/ice_xsk.c
@@ -236,7 +236,7 @@ static int ice_qp_ena(struct ice_vsi *vsi, u16 q_idx)
xdp_ring->xsk_pool = ice_xsk_pool(xdp_ring);
}
- err = ice_setup_rx_ctx(rx_ring);
+ err = ice_vsi_cfg_rxq(rx_ring);
if (err)
goto free_buf;
@@ -466,7 +466,6 @@ ice_run_xdp_zc(struct ice_ring *rx_ring, struct xdp_buff *xdp)
struct ice_ring *xdp_ring;
u32 act;
- rcu_read_lock();
/* ZC patch is enabled only when XDP program is set,
* so here it can not be NULL
*/
@@ -478,7 +477,6 @@ ice_run_xdp_zc(struct ice_ring *rx_ring, struct xdp_buff *xdp)
err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
if (err)
goto out_failure;
- rcu_read_unlock();
return ICE_XDP_REDIR;
}
@@ -503,7 +501,6 @@ out_failure:
break;
}
- rcu_read_unlock();
return result;
}
@@ -528,7 +525,7 @@ int ice_clean_rx_irq_zc(struct ice_ring *rx_ring, int budget)
struct sk_buff *skb;
u16 stat_err_bits;
u16 vlan_tag = 0;
- u8 rx_ptype;
+ u16 rx_ptype;
rx_desc = ICE_RX_DESC(rx_ring, rx_ring->next_to_clean);
diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.h b/drivers/net/ethernet/intel/ice/ice_xsk.h
index fad783690134..ea208808623a 100644
--- a/drivers/net/ethernet/intel/ice/ice_xsk.h
+++ b/drivers/net/ethernet/intel/ice/ice_xsk.h
@@ -60,7 +60,7 @@ ice_xsk_wakeup(struct net_device __always_unused *netdev,
return -EOPNOTSUPP;
}
-#define ice_xsk_clean_rx_ring(rx_ring) do {} while (0)
-#define ice_xsk_clean_xdp_ring(xdp_ring) do {} while (0)
+static inline void ice_xsk_clean_rx_ring(struct ice_ring *rx_ring) { }
+static inline void ice_xsk_clean_xdp_ring(struct ice_ring *xdp_ring) { }
#endif /* CONFIG_XDP_SOCKETS */
#endif /* !_ICE_XSK_H_ */
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index 50863fd87d53..cbe92fd23a70 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -2756,6 +2756,7 @@ out:
return ret_val;
}
+#ifdef CONFIG_IGB_HWMON
static const u8 e1000_emc_temp_data[4] = {
E1000_EMC_INTERNAL_DATA,
E1000_EMC_DIODE1_DATA,
@@ -2769,7 +2770,6 @@ static const u8 e1000_emc_therm_limit[4] = {
E1000_EMC_DIODE3_THERM_LIMIT
};
-#ifdef CONFIG_IGB_HWMON
/**
* igb_get_thermal_sensor_data_generic - Gathers thermal sensor data
* @hw: pointer to hardware structure
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 7545da216d8b..636a1b1fb7e1 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -831,7 +831,7 @@ static int igb_set_eeprom(struct net_device *netdev,
memcpy(ptr, bytes, eeprom->len);
for (i = 0; i < last_word - first_word + 1; i++)
- eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
+ cpu_to_le16s(&eeprom_buff[i]);
ret_val = hw->nvm.ops.write(hw, first_word,
last_word - first_word + 1, eeprom_buff);
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index b2a042f825ff..171a7a629b20 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -356,7 +356,7 @@ static void igb_dump(struct igb_adapter *adapter)
struct igb_reg_info *reginfo;
struct igb_ring *tx_ring;
union e1000_adv_tx_desc *tx_desc;
- struct my_u0 { u64 a; u64 b; } *u0;
+ struct my_u0 { __le64 a; __le64 b; } *u0;
struct igb_ring *rx_ring;
union e1000_adv_rx_desc *rx_desc;
u32 staterr;
@@ -931,6 +931,7 @@ static void igb_configure_msix(struct igb_adapter *adapter)
**/
static int igb_request_msix(struct igb_adapter *adapter)
{
+ unsigned int num_q_vectors = adapter->num_q_vectors;
struct net_device *netdev = adapter->netdev;
int i, err = 0, vector = 0, free_vector = 0;
@@ -939,7 +940,13 @@ static int igb_request_msix(struct igb_adapter *adapter)
if (err)
goto err_out;
- for (i = 0; i < adapter->num_q_vectors; i++) {
+ if (num_q_vectors > MAX_Q_VECTORS) {
+ num_q_vectors = MAX_Q_VECTORS;
+ dev_warn(&adapter->pdev->dev,
+ "The number of queue vectors (%d) is higher than max allowed (%d)\n",
+ adapter->num_q_vectors, MAX_Q_VECTORS);
+ }
+ for (i = 0; i < num_q_vectors; i++) {
struct igb_q_vector *q_vector = adapter->q_vector[i];
vector++;
@@ -1678,14 +1685,15 @@ static bool is_any_txtime_enabled(struct igb_adapter *adapter)
**/
static void igb_config_tx_modes(struct igb_adapter *adapter, int queue)
{
- struct igb_ring *ring = adapter->tx_ring[queue];
struct net_device *netdev = adapter->netdev;
struct e1000_hw *hw = &adapter->hw;
+ struct igb_ring *ring;
u32 tqavcc, tqavctrl;
u16 value;
WARN_ON(hw->mac.type != e1000_i210);
WARN_ON(queue < 0 || queue > 1);
+ ring = adapter->tx_ring[queue];
/* If any of the Qav features is enabled, configure queues as SR and
* with HIGH PRIO. If none is, then configure them with LOW PRIO and
@@ -2643,7 +2651,8 @@ static int igb_parse_cls_flower(struct igb_adapter *adapter,
}
input->filter.match_flags |= IGB_FILTER_FLAG_VLAN_TCI;
- input->filter.vlan_tci = match.key->vlan_priority;
+ input->filter.vlan_tci =
+ (__force __be16)match.key->vlan_priority;
}
}
@@ -3614,6 +3623,7 @@ err_sw_init:
err_ioremap:
free_netdev(netdev);
err_alloc_etherdev:
+ pci_disable_pcie_error_reporting(pdev);
pci_release_mem_regions(pdev);
err_pci_reg:
err_dma:
@@ -4834,6 +4844,8 @@ static void igb_clean_tx_ring(struct igb_ring *tx_ring)
DMA_TO_DEVICE);
}
+ tx_buffer->next_to_watch = NULL;
+
/* move us one more past the eop_desc for start of next pkt */
tx_buffer++;
i++;
@@ -6275,12 +6287,12 @@ int igb_xmit_xdp_ring(struct igb_adapter *adapter,
cmd_type |= len | IGB_TXD_DCMD;
tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type);
- olinfo_status = cpu_to_le32(len << E1000_ADVTXD_PAYLEN_SHIFT);
+ olinfo_status = len << E1000_ADVTXD_PAYLEN_SHIFT;
/* 82575 requires a unique index per ring */
if (test_bit(IGB_RING_FLAG_TX_CTX_IDX, &tx_ring->flags))
olinfo_status |= tx_ring->reg_idx << 4;
- tx_desc->read.olinfo_status = olinfo_status;
+ tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
netdev_tx_sent_queue(txring_txq(tx_ring), tx_buffer->bytecount);
@@ -8380,7 +8392,6 @@ static struct sk_buff *igb_run_xdp(struct igb_adapter *adapter,
struct bpf_prog *xdp_prog;
u32 act;
- rcu_read_lock();
xdp_prog = READ_ONCE(rx_ring->xdp_prog);
if (!xdp_prog)
@@ -8415,7 +8426,6 @@ out_failure:
break;
}
xdp_out:
- rcu_read_unlock();
return ERR_PTR(-result);
}
@@ -8592,7 +8602,7 @@ static void igb_process_skb_fields(struct igb_ring *rx_ring,
if (igb_test_staterr(rx_desc, E1000_RXDEXT_STATERR_LB) &&
test_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &rx_ring->flags))
- vid = be16_to_cpu(rx_desc->wb.upper.vlan);
+ vid = be16_to_cpu((__force __be16)rx_desc->wb.upper.vlan);
else
vid = le16_to_cpu(rx_desc->wb.upper.vlan);
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index d68cd4466a54..0011b15e678c 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -1131,12 +1131,12 @@ static int igb_ptp_set_timestamp_mode(struct igb_adapter *adapter,
| E1000_FTQF_MASK); /* mask all inputs */
ftqf &= ~E1000_FTQF_MASK_PROTO_BP; /* enable protocol check */
- wr32(E1000_IMIR(3), htons(PTP_EV_PORT));
+ wr32(E1000_IMIR(3), (__force unsigned int)htons(PTP_EV_PORT));
wr32(E1000_IMIREXT(3),
(E1000_IMIREXT_SIZE_BP | E1000_IMIREXT_CTRL_BP));
if (hw->mac.type == e1000_82576) {
/* enable source port check */
- wr32(E1000_SPQF(3), htons(PTP_EV_PORT));
+ wr32(E1000_SPQF(3), (__force unsigned int)htons(PTP_EV_PORT));
ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP;
}
wr32(E1000_FTQF(3), ftqf);
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index fb3fbcb13331..1bbe9862a758 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -83,14 +83,14 @@ static int igbvf_desc_unused(struct igbvf_ring *ring)
static void igbvf_receive_skb(struct igbvf_adapter *adapter,
struct net_device *netdev,
struct sk_buff *skb,
- u32 status, u16 vlan)
+ u32 status, __le16 vlan)
{
u16 vid;
if (status & E1000_RXD_STAT_VP) {
if ((adapter->flags & IGBVF_FLAG_RX_LB_VLAN_BSWAP) &&
(status & E1000_RXDEXT_STATERR_LB))
- vid = be16_to_cpu(vlan) & E1000_RXD_SPC_VLAN_MASK;
+ vid = be16_to_cpu((__force __be16)vlan) & E1000_RXD_SPC_VLAN_MASK;
else
vid = le16_to_cpu(vlan) & E1000_RXD_SPC_VLAN_MASK;
if (test_bit(vid, adapter->active_vlans))
@@ -2056,7 +2056,7 @@ static int igbvf_tso(struct igbvf_ring *tx_ring,
/* remove payload length from inner checksum */
paylen = skb->len - l4_offset;
- csum_replace_by_diff(&l4.tcp->check, htonl(paylen));
+ csum_replace_by_diff(&l4.tcp->check, (__force __wsum)htonl(paylen));
/* MSS L4LEN IDX */
mss_l4len_idx = (*hdr_len - l4_offset) << E1000_ADVTXD_L4LEN_SHIFT;
diff --git a/drivers/net/ethernet/intel/igbvf/vf.h b/drivers/net/ethernet/intel/igbvf/vf.h
index c71b0d7dbcee..ba9bb3132d5d 100644
--- a/drivers/net/ethernet/intel/igbvf/vf.h
+++ b/drivers/net/ethernet/intel/igbvf/vf.h
@@ -35,31 +35,31 @@ struct e1000_hw;
/* Receive Descriptor - Advanced */
union e1000_adv_rx_desc {
struct {
- u64 pkt_addr; /* Packet buffer address */
- u64 hdr_addr; /* Header buffer address */
+ __le64 pkt_addr; /* Packet buffer address */
+ __le64 hdr_addr; /* Header buffer address */
} read;
struct {
struct {
union {
- u32 data;
+ __le32 data;
struct {
- u16 pkt_info; /* RSS/Packet type */
+ __le16 pkt_info; /* RSS/Packet type */
/* Split Header, hdr buffer length */
- u16 hdr_info;
+ __le16 hdr_info;
} hs_rss;
} lo_dword;
union {
- u32 rss; /* RSS Hash */
+ __le32 rss; /* RSS Hash */
struct {
- u16 ip_id; /* IP id */
- u16 csum; /* Packet Checksum */
+ __le16 ip_id; /* IP id */
+ __le16 csum; /* Packet Checksum */
} csum_ip;
} hi_dword;
} lower;
struct {
- u32 status_error; /* ext status/error */
- u16 length; /* Packet length */
- u16 vlan; /* VLAN tag */
+ __le32 status_error; /* ext status/error */
+ __le16 length; /* Packet length */
+ __le16 vlan; /* VLAN tag */
} upper;
} wb; /* writeback */
};
@@ -70,14 +70,14 @@ union e1000_adv_rx_desc {
/* Transmit Descriptor - Advanced */
union e1000_adv_tx_desc {
struct {
- u64 buffer_addr; /* Address of descriptor's data buf */
- u32 cmd_type_len;
- u32 olinfo_status;
+ __le64 buffer_addr; /* Address of descriptor's data buf */
+ __le32 cmd_type_len;
+ __le32 olinfo_status;
} read;
struct {
- u64 rsvd; /* Reserved */
- u32 nxtseq_seed;
- u32 status;
+ __le64 rsvd; /* Reserved */
+ __le32 nxtseq_seed;
+ __le32 status;
} wb;
};
@@ -94,10 +94,10 @@ union e1000_adv_tx_desc {
/* Context descriptors */
struct e1000_adv_tx_context_desc {
- u32 vlan_macip_lens;
- u32 seqnum_seed;
- u32 type_tucmd_mlhl;
- u32 mss_l4len_idx;
+ __le32 vlan_macip_lens;
+ __le32 seqnum_seed;
+ __le32 type_tucmd_mlhl;
+ __le32 mss_l4len_idx;
};
#define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index 25871351730b..5901ed9fb545 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -118,6 +118,7 @@ struct igc_ring {
};
struct xdp_rxq_info xdp_rxq;
+ struct xsk_buff_pool *xsk_pool;
} ____cacheline_internodealigned_in_smp;
/* Board specific private data structure */
@@ -255,6 +256,11 @@ bool igc_has_link(struct igc_adapter *adapter);
void igc_reset(struct igc_adapter *adapter);
int igc_set_spd_dplx(struct igc_adapter *adapter, u32 spd, u8 dplx);
void igc_update_stats(struct igc_adapter *adapter);
+void igc_disable_rx_ring(struct igc_ring *ring);
+void igc_enable_rx_ring(struct igc_ring *ring);
+void igc_disable_tx_ring(struct igc_ring *ring);
+void igc_enable_tx_ring(struct igc_ring *ring);
+int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags);
/* igc_dump declarations */
void igc_rings_dump(struct igc_adapter *adapter);
@@ -366,6 +372,7 @@ extern char igc_driver_name[];
/* VLAN info */
#define IGC_TX_FLAGS_VLAN_MASK 0xffff0000
+#define IGC_TX_FLAGS_VLAN_SHIFT 16
/* igc_test_staterr - tests bits within Rx descriptor status and error fields */
static inline __le32 igc_test_staterr(union igc_adv_rx_desc *rx_desc,
@@ -390,8 +397,6 @@ enum igc_tx_flags {
/* olinfo flags */
IGC_TX_FLAGS_IPV4 = 0x10,
IGC_TX_FLAGS_CSUM = 0x20,
-
- IGC_TX_FLAGS_XDP = 0x100,
};
enum igc_boards {
@@ -408,12 +413,19 @@ enum igc_boards {
#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IGC_MAX_DATA_PER_TXD)
#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
+enum igc_tx_buffer_type {
+ IGC_TX_BUFFER_TYPE_SKB,
+ IGC_TX_BUFFER_TYPE_XDP,
+ IGC_TX_BUFFER_TYPE_XSK,
+};
+
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer
*/
struct igc_tx_buffer {
union igc_adv_tx_desc *next_to_watch;
unsigned long time_stamp;
+ enum igc_tx_buffer_type type;
union {
struct sk_buff *skb;
struct xdp_frame *xdpf;
@@ -428,14 +440,19 @@ struct igc_tx_buffer {
};
struct igc_rx_buffer {
- dma_addr_t dma;
- struct page *page;
+ union {
+ struct {
+ dma_addr_t dma;
+ struct page *page;
#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
- __u32 page_offset;
+ __u32 page_offset;
#else
- __u16 page_offset;
+ __u16 page_offset;
#endif
- __u16 pagecnt_bias;
+ __u16 pagecnt_bias;
+ };
+ struct xdp_buff *xdp;
+ };
};
struct igc_q_vector {
@@ -521,7 +538,8 @@ enum igc_ring_flags_t {
IGC_RING_FLAG_RX_SCTP_CSUM,
IGC_RING_FLAG_RX_LB_VLAN_BSWAP,
IGC_RING_FLAG_TX_CTX_IDX,
- IGC_RING_FLAG_TX_DETECT_HANG
+ IGC_RING_FLAG_TX_DETECT_HANG,
+ IGC_RING_FLAG_AF_XDP_ZC,
};
#define ring_uses_large_buffer(ring) \
@@ -560,7 +578,7 @@ static inline s32 igc_read_phy_reg(struct igc_hw *hw, u32 offset, u16 *data)
if (hw->phy.ops.read_reg)
return hw->phy.ops.read_reg(hw, offset, data);
- return 0;
+ return -EOPNOTSUPP;
}
void igc_reinit_locked(struct igc_adapter *);
diff --git a/drivers/net/ethernet/intel/igc/igc_base.h b/drivers/net/ethernet/intel/igc/igc_base.h
index ea627ce52525..ce530f5fd7bd 100644
--- a/drivers/net/ethernet/intel/igc/igc_base.h
+++ b/drivers/net/ethernet/intel/igc/igc_base.h
@@ -78,9 +78,11 @@ union igc_adv_rx_desc {
/* Additional Transmit Descriptor Control definitions */
#define IGC_TXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Tx Queue */
+#define IGC_TXDCTL_SWFLUSH 0x04000000 /* Transmit Software Flush */
/* Additional Receive Descriptor Control definitions */
#define IGC_RXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Rx Queue */
+#define IGC_RXDCTL_SWFLUSH 0x04000000 /* Receive Software Flush */
/* SRRCTL bit definitions */
#define IGC_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */
diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h
index 0103dda32f39..c3a5a5518790 100644
--- a/drivers/net/ethernet/intel/igc/igc_defines.h
+++ b/drivers/net/ethernet/intel/igc/igc_defines.h
@@ -94,12 +94,13 @@
#define IGC_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
#define IGC_CTRL_FRCSPD 0x00000800 /* Force Speed */
#define IGC_CTRL_FRCDPX 0x00001000 /* Force Duplex */
+#define IGC_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
#define IGC_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
#define IGC_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
-#define IGC_CTRL_SDP0_DIR 0x00400000 /* SDP0 Data direction */
-#define IGC_CTRL_SDP1_DIR 0x00800000 /* SDP1 Data direction */
+#define IGC_CTRL_SDP0_DIR 0x00400000 /* SDP0 Data direction */
+#define IGC_CTRL_SDP1_DIR 0x00800000 /* SDP1 Data direction */
/* As per the EAS the maximum supported size is 9.5KB (9728 bytes) */
#define MAX_JUMBO_FRAME_SIZE 0x2600
@@ -128,7 +129,6 @@
#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
/* 1000BASE-T Control Register */
-#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */
#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
@@ -323,6 +323,9 @@
#define IGC_RXD_STAT_IXSM 0x04 /* Ignore checksum */
#define IGC_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */
#define IGC_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
+#define IGC_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
+
+#define IGC_RXDEXT_STATERR_LB 0x00040000
/* Advanced Receive Descriptor bit definitions */
#define IGC_RXDADV_STAT_TSIP 0x08000 /* timestamp in packet */
diff --git a/drivers/net/ethernet/intel/igc/igc_dump.c b/drivers/net/ethernet/intel/igc/igc_dump.c
index 495bed47ed0a..c09c95cc5f70 100644
--- a/drivers/net/ethernet/intel/igc/igc_dump.c
+++ b/drivers/net/ethernet/intel/igc/igc_dump.c
@@ -112,7 +112,7 @@ static void igc_regdump(struct igc_hw *hw, struct igc_reg_info *reginfo)
void igc_rings_dump(struct igc_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- struct my_u0 { u64 a; u64 b; } *u0;
+ struct my_u0 { __le64 a; __le64 b; } *u0;
union igc_adv_tx_desc *tx_desc;
union igc_adv_rx_desc *rx_desc;
struct igc_ring *tx_ring;
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
index 9722449d7633..fa4171860623 100644
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -554,7 +554,7 @@ static int igc_ethtool_set_eeprom(struct net_device *netdev,
memcpy(ptr, bytes, eeprom->len);
for (i = 0; i < last_word - first_word + 1; i++)
- eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
+ cpu_to_le16s(&eeprom_buff[i]);
ret_val = hw->nvm.ops.write(hw, first_word,
last_word - first_word + 1, eeprom_buff);
@@ -765,35 +765,22 @@ static void igc_ethtool_get_strings(struct net_device *netdev, u32 stringset,
IGC_TEST_LEN * ETH_GSTRING_LEN);
break;
case ETH_SS_STATS:
- for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++) {
- memcpy(p, igc_gstrings_stats[i].stat_string,
- ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
- for (i = 0; i < IGC_NETDEV_STATS_LEN; i++) {
- memcpy(p, igc_gstrings_net_stats[i].stat_string,
- ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++)
+ ethtool_sprintf(&p, igc_gstrings_stats[i].stat_string);
+ for (i = 0; i < IGC_NETDEV_STATS_LEN; i++)
+ ethtool_sprintf(&p,
+ igc_gstrings_net_stats[i].stat_string);
for (i = 0; i < adapter->num_tx_queues; i++) {
- sprintf(p, "tx_queue_%u_packets", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "tx_queue_%u_bytes", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "tx_queue_%u_restart", i);
- p += ETH_GSTRING_LEN;
+ ethtool_sprintf(&p, "tx_queue_%u_packets", i);
+ ethtool_sprintf(&p, "tx_queue_%u_bytes", i);
+ ethtool_sprintf(&p, "tx_queue_%u_restart", i);
}
for (i = 0; i < adapter->num_rx_queues; i++) {
- sprintf(p, "rx_queue_%u_packets", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "rx_queue_%u_bytes", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "rx_queue_%u_drops", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "rx_queue_%u_csum_err", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "rx_queue_%u_alloc_failed", i);
- p += ETH_GSTRING_LEN;
+ ethtool_sprintf(&p, "rx_queue_%u_packets", i);
+ ethtool_sprintf(&p, "rx_queue_%u_bytes", i);
+ ethtool_sprintf(&p, "rx_queue_%u_drops", i);
+ ethtool_sprintf(&p, "rx_queue_%u_csum_err", i);
+ ethtool_sprintf(&p, "rx_queue_%u_alloc_failed", i);
}
/* BUG_ON(p - data != IGC_STATS_LEN * ETH_GSTRING_LEN); */
break;
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index f1adf154ec4a..e29aadbc6744 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -11,7 +11,7 @@
#include <linux/pm_runtime.h>
#include <net/pkt_sched.h>
#include <linux/bpf_trace.h>
-
+#include <net/xdp_sock_drv.h>
#include <net/ipv6.h>
#include "igc.h"
@@ -111,6 +111,9 @@ void igc_reset(struct igc_adapter *adapter)
if (!netif_running(adapter->netdev))
igc_power_down_phy_copper_base(&adapter->hw);
+ /* Enable HW to recognize an 802.1Q VLAN Ethernet packet */
+ wr32(IGC_VET, ETH_P_8021Q);
+
/* Re-enable PTP, where applicable. */
igc_ptp_reset(adapter);
@@ -171,6 +174,14 @@ static void igc_get_hw_control(struct igc_adapter *adapter)
ctrl_ext | IGC_CTRL_EXT_DRV_LOAD);
}
+static void igc_unmap_tx_buffer(struct device *dev, struct igc_tx_buffer *buf)
+{
+ dma_unmap_single(dev, dma_unmap_addr(buf, dma),
+ dma_unmap_len(buf, len), DMA_TO_DEVICE);
+
+ dma_unmap_len_set(buf, len, 0);
+}
+
/**
* igc_clean_tx_ring - Free Tx Buffers
* @tx_ring: ring to be cleaned
@@ -179,20 +190,27 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring)
{
u16 i = tx_ring->next_to_clean;
struct igc_tx_buffer *tx_buffer = &tx_ring->tx_buffer_info[i];
+ u32 xsk_frames = 0;
while (i != tx_ring->next_to_use) {
union igc_adv_tx_desc *eop_desc, *tx_desc;
- if (tx_buffer->tx_flags & IGC_TX_FLAGS_XDP)
+ switch (tx_buffer->type) {
+ case IGC_TX_BUFFER_TYPE_XSK:
+ xsk_frames++;
+ break;
+ case IGC_TX_BUFFER_TYPE_XDP:
xdp_return_frame(tx_buffer->xdpf);
- else
+ igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
+ break;
+ case IGC_TX_BUFFER_TYPE_SKB:
dev_kfree_skb_any(tx_buffer->skb);
-
- /* unmap skb header data */
- dma_unmap_single(tx_ring->dev,
- dma_unmap_addr(tx_buffer, dma),
- dma_unmap_len(tx_buffer, len),
- DMA_TO_DEVICE);
+ igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
+ break;
+ default:
+ netdev_warn_once(tx_ring->netdev, "Unknown Tx buffer type\n");
+ break;
+ }
/* check for eop_desc to determine the end of the packet */
eop_desc = tx_buffer->next_to_watch;
@@ -211,12 +229,11 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring)
/* unmap any remaining paged data */
if (dma_unmap_len(tx_buffer, len))
- dma_unmap_page(tx_ring->dev,
- dma_unmap_addr(tx_buffer, dma),
- dma_unmap_len(tx_buffer, len),
- DMA_TO_DEVICE);
+ igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
}
+ tx_buffer->next_to_watch = NULL;
+
/* move us one more past the eop_desc for start of next pkt */
tx_buffer++;
i++;
@@ -226,6 +243,9 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring)
}
}
+ if (tx_ring->xsk_pool && xsk_frames)
+ xsk_tx_completed(tx_ring->xsk_pool, xsk_frames);
+
/* reset BQL for queue */
netdev_tx_reset_queue(txring_txq(tx_ring));
@@ -346,11 +366,7 @@ static int igc_setup_all_tx_resources(struct igc_adapter *adapter)
return err;
}
-/**
- * igc_clean_rx_ring - Free Rx Buffers per Queue
- * @rx_ring: ring to free buffers from
- */
-static void igc_clean_rx_ring(struct igc_ring *rx_ring)
+static void igc_clean_rx_ring_page_shared(struct igc_ring *rx_ring)
{
u16 i = rx_ring->next_to_clean;
@@ -383,12 +399,39 @@ static void igc_clean_rx_ring(struct igc_ring *rx_ring)
if (i == rx_ring->count)
i = 0;
}
+}
- clear_ring_uses_large_buffer(rx_ring);
+static void igc_clean_rx_ring_xsk_pool(struct igc_ring *ring)
+{
+ struct igc_rx_buffer *bi;
+ u16 i;
- rx_ring->next_to_alloc = 0;
- rx_ring->next_to_clean = 0;
- rx_ring->next_to_use = 0;
+ for (i = 0; i < ring->count; i++) {
+ bi = &ring->rx_buffer_info[i];
+ if (!bi->xdp)
+ continue;
+
+ xsk_buff_free(bi->xdp);
+ bi->xdp = NULL;
+ }
+}
+
+/**
+ * igc_clean_rx_ring - Free Rx Buffers per Queue
+ * @ring: ring to free buffers from
+ */
+static void igc_clean_rx_ring(struct igc_ring *ring)
+{
+ if (ring->xsk_pool)
+ igc_clean_rx_ring_xsk_pool(ring);
+ else
+ igc_clean_rx_ring_page_shared(ring);
+
+ clear_ring_uses_large_buffer(ring);
+
+ ring->next_to_alloc = 0;
+ ring->next_to_clean = 0;
+ ring->next_to_use = 0;
}
/**
@@ -414,7 +457,7 @@ void igc_free_rx_resources(struct igc_ring *rx_ring)
{
igc_clean_rx_ring(rx_ring);
- igc_xdp_unregister_rxq_info(rx_ring);
+ xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
vfree(rx_ring->rx_buffer_info);
rx_ring->rx_buffer_info = NULL;
@@ -453,11 +496,16 @@ int igc_setup_rx_resources(struct igc_ring *rx_ring)
{
struct net_device *ndev = rx_ring->netdev;
struct device *dev = rx_ring->dev;
+ u8 index = rx_ring->queue_index;
int size, desc_len, res;
- res = igc_xdp_register_rxq_info(rx_ring);
- if (res < 0)
+ res = xdp_rxq_info_reg(&rx_ring->xdp_rxq, ndev, index,
+ rx_ring->q_vector->napi.napi_id);
+ if (res < 0) {
+ netdev_err(ndev, "Failed to register xdp_rxq index %u\n",
+ index);
return res;
+ }
size = sizeof(struct igc_rx_buffer) * rx_ring->count;
rx_ring->rx_buffer_info = vzalloc(size);
@@ -483,7 +531,7 @@ int igc_setup_rx_resources(struct igc_ring *rx_ring)
return 0;
err:
- igc_xdp_unregister_rxq_info(rx_ring);
+ xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
vfree(rx_ring->rx_buffer_info);
rx_ring->rx_buffer_info = NULL;
netdev_err(ndev, "Unable to allocate memory for Rx descriptor ring\n");
@@ -515,9 +563,14 @@ static int igc_setup_all_rx_resources(struct igc_adapter *adapter)
return err;
}
-static bool igc_xdp_is_enabled(struct igc_adapter *adapter)
+static struct xsk_buff_pool *igc_get_xsk_pool(struct igc_adapter *adapter,
+ struct igc_ring *ring)
{
- return !!adapter->xdp_prog;
+ if (!igc_xdp_is_enabled(adapter) ||
+ !test_bit(IGC_RING_FLAG_AF_XDP_ZC, &ring->flags))
+ return NULL;
+
+ return xsk_get_pool_from_qid(ring->netdev, ring->queue_index);
}
/**
@@ -535,6 +588,20 @@ static void igc_configure_rx_ring(struct igc_adapter *adapter,
int reg_idx = ring->reg_idx;
u32 srrctl = 0, rxdctl = 0;
u64 rdba = ring->dma;
+ u32 buf_size;
+
+ xdp_rxq_info_unreg_mem_model(&ring->xdp_rxq);
+ ring->xsk_pool = igc_get_xsk_pool(adapter, ring);
+ if (ring->xsk_pool) {
+ WARN_ON(xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
+ MEM_TYPE_XSK_BUFF_POOL,
+ NULL));
+ xsk_pool_set_rxq_info(ring->xsk_pool, &ring->xdp_rxq);
+ } else {
+ WARN_ON(xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
+ MEM_TYPE_PAGE_SHARED,
+ NULL));
+ }
if (igc_xdp_is_enabled(adapter))
set_ring_uses_large_buffer(ring);
@@ -558,12 +625,15 @@ static void igc_configure_rx_ring(struct igc_adapter *adapter,
ring->next_to_clean = 0;
ring->next_to_use = 0;
- /* set descriptor configuration */
- srrctl = IGC_RX_HDR_LEN << IGC_SRRCTL_BSIZEHDRSIZE_SHIFT;
- if (ring_uses_large_buffer(ring))
- srrctl |= IGC_RXBUFFER_3072 >> IGC_SRRCTL_BSIZEPKT_SHIFT;
+ if (ring->xsk_pool)
+ buf_size = xsk_pool_get_rx_frame_size(ring->xsk_pool);
+ else if (ring_uses_large_buffer(ring))
+ buf_size = IGC_RXBUFFER_3072;
else
- srrctl |= IGC_RXBUFFER_2048 >> IGC_SRRCTL_BSIZEPKT_SHIFT;
+ buf_size = IGC_RXBUFFER_2048;
+
+ srrctl = IGC_RX_HDR_LEN << IGC_SRRCTL_BSIZEHDRSIZE_SHIFT;
+ srrctl |= buf_size >> IGC_SRRCTL_BSIZEPKT_SHIFT;
srrctl |= IGC_SRRCTL_DESCTYPE_ADV_ONEBUF;
wr32(IGC_SRRCTL(reg_idx), srrctl);
@@ -618,6 +688,8 @@ static void igc_configure_tx_ring(struct igc_adapter *adapter,
u64 tdba = ring->dma;
u32 txdctl = 0;
+ ring->xsk_pool = igc_get_xsk_pool(adapter, ring);
+
/* disable the queue */
wr32(IGC_TXDCTL(reg_idx), 0);
wrfl();
@@ -1055,13 +1127,17 @@ static inline int igc_maybe_stop_tx(struct igc_ring *tx_ring, const u16 size)
((u32)((_input) & (_flag)) * ((_result) / (_flag))) : \
((u32)((_input) & (_flag)) / ((_flag) / (_result))))
-static u32 igc_tx_cmd_type(u32 tx_flags)
+static u32 igc_tx_cmd_type(struct sk_buff *skb, u32 tx_flags)
{
/* set type for advanced descriptor with frame checksum insertion */
u32 cmd_type = IGC_ADVTXD_DTYP_DATA |
IGC_ADVTXD_DCMD_DEXT |
IGC_ADVTXD_DCMD_IFCS;
+ /* set HW vlan bit if vlan is present */
+ cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_VLAN,
+ IGC_ADVTXD_DCMD_VLE);
+
/* set segmentation bits for TSO */
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSO,
(IGC_ADVTXD_DCMD_TSE));
@@ -1070,6 +1146,9 @@ static u32 igc_tx_cmd_type(u32 tx_flags)
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP,
(IGC_ADVTXD_MAC_TSTAMP));
+ /* insert frame checksum */
+ cmd_type ^= IGC_SET_FLAG(skb->no_fcs, 1, IGC_ADVTXD_DCMD_IFCS);
+
return cmd_type;
}
@@ -1104,8 +1183,9 @@ static int igc_tx_map(struct igc_ring *tx_ring,
u16 i = tx_ring->next_to_use;
unsigned int data_len, size;
dma_addr_t dma;
- u32 cmd_type = igc_tx_cmd_type(tx_flags);
+ u32 cmd_type;
+ cmd_type = igc_tx_cmd_type(skb, tx_flags);
tx_desc = IGC_TX_DESC(tx_ring, i);
igc_tx_olinfo_status(tx_ring, tx_desc, tx_flags, skb->len - hdr_len);
@@ -1211,11 +1291,7 @@ dma_error:
/* clear dma mappings for failed tx_buffer_info map */
while (tx_buffer != first) {
if (dma_unmap_len(tx_buffer, len))
- dma_unmap_page(tx_ring->dev,
- dma_unmap_addr(tx_buffer, dma),
- dma_unmap_len(tx_buffer, len),
- DMA_TO_DEVICE);
- dma_unmap_len_set(tx_buffer, len, 0);
+ igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
if (i-- == 0)
i += tx_ring->count;
@@ -1223,11 +1299,7 @@ dma_error:
}
if (dma_unmap_len(tx_buffer, len))
- dma_unmap_single(tx_ring->dev,
- dma_unmap_addr(tx_buffer, dma),
- dma_unmap_len(tx_buffer, len),
- DMA_TO_DEVICE);
- dma_unmap_len_set(tx_buffer, len, 0);
+ igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
dev_kfree_skb_any(tx_buffer->skb);
tx_buffer->skb = NULL;
@@ -1359,6 +1431,7 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
/* record the location of the first descriptor for this packet */
first = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
+ first->type = IGC_TX_BUFFER_TYPE_SKB;
first->skb = skb;
first->bytecount = skb->len;
first->gso_segs = 1;
@@ -1383,6 +1456,11 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
}
}
+ if (skb_vlan_tag_present(skb)) {
+ tx_flags |= IGC_TX_FLAGS_VLAN;
+ tx_flags |= (skb_vlan_tag_get(skb) << IGC_TX_FLAGS_VLAN_SHIFT);
+ }
+
/* record initial flags and protocol */
first->tx_flags = tx_flags;
first->protocol = protocol;
@@ -1482,6 +1560,25 @@ static inline void igc_rx_hash(struct igc_ring *ring,
PKT_HASH_TYPE_L3);
}
+static void igc_rx_vlan(struct igc_ring *rx_ring,
+ union igc_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
+{
+ struct net_device *dev = rx_ring->netdev;
+ u16 vid;
+
+ if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
+ igc_test_staterr(rx_desc, IGC_RXD_STAT_VP)) {
+ if (igc_test_staterr(rx_desc, IGC_RXDEXT_STATERR_LB) &&
+ test_bit(IGC_RING_FLAG_RX_LB_VLAN_BSWAP, &rx_ring->flags))
+ vid = be16_to_cpu((__force __be16)rx_desc->wb.upper.vlan);
+ else
+ vid = le16_to_cpu(rx_desc->wb.upper.vlan);
+
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
+ }
+}
+
/**
* igc_process_skb_fields - Populate skb header fields from Rx descriptor
* @rx_ring: rx descriptor ring packet is being transacted on
@@ -1500,11 +1597,37 @@ static void igc_process_skb_fields(struct igc_ring *rx_ring,
igc_rx_checksum(rx_ring, rx_desc, skb);
+ igc_rx_vlan(rx_ring, rx_desc, skb);
+
skb_record_rx_queue(skb, rx_ring->queue_index);
skb->protocol = eth_type_trans(skb, rx_ring->netdev);
}
+static void igc_vlan_mode(struct net_device *netdev, netdev_features_t features)
+{
+ bool enable = !!(features & NETIF_F_HW_VLAN_CTAG_RX);
+ struct igc_adapter *adapter = netdev_priv(netdev);
+ struct igc_hw *hw = &adapter->hw;
+ u32 ctrl;
+
+ ctrl = rd32(IGC_CTRL);
+
+ if (enable) {
+ /* enable VLAN tag insert/strip */
+ ctrl |= IGC_CTRL_VME;
+ } else {
+ /* disable VLAN tag insert/strip */
+ ctrl &= ~IGC_CTRL_VME;
+ }
+ wr32(IGC_CTRL, ctrl);
+}
+
+static void igc_restore_vlan(struct igc_adapter *adapter)
+{
+ igc_vlan_mode(adapter->netdev, adapter->netdev->features);
+}
+
static struct igc_rx_buffer *igc_get_rx_buffer(struct igc_ring *rx_ring,
const unsigned int size,
int *rx_buffer_pgcnt)
@@ -1930,6 +2053,63 @@ static void igc_alloc_rx_buffers(struct igc_ring *rx_ring, u16 cleaned_count)
}
}
+static bool igc_alloc_rx_buffers_zc(struct igc_ring *ring, u16 count)
+{
+ union igc_adv_rx_desc *desc;
+ u16 i = ring->next_to_use;
+ struct igc_rx_buffer *bi;
+ dma_addr_t dma;
+ bool ok = true;
+
+ if (!count)
+ return ok;
+
+ desc = IGC_RX_DESC(ring, i);
+ bi = &ring->rx_buffer_info[i];
+ i -= ring->count;
+
+ do {
+ bi->xdp = xsk_buff_alloc(ring->xsk_pool);
+ if (!bi->xdp) {
+ ok = false;
+ break;
+ }
+
+ dma = xsk_buff_xdp_get_dma(bi->xdp);
+ desc->read.pkt_addr = cpu_to_le64(dma);
+
+ desc++;
+ bi++;
+ i++;
+ if (unlikely(!i)) {
+ desc = IGC_RX_DESC(ring, 0);
+ bi = ring->rx_buffer_info;
+ i -= ring->count;
+ }
+
+ /* Clear the length for the next_to_use descriptor. */
+ desc->wb.upper.length = 0;
+
+ count--;
+ } while (count);
+
+ i += ring->count;
+
+ if (ring->next_to_use != i) {
+ ring->next_to_use = i;
+
+ /* Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64).
+ */
+ wmb();
+ writel(i, ring->tail);
+ }
+
+ return ok;
+}
+
static int igc_xdp_init_tx_buffer(struct igc_tx_buffer *buffer,
struct xdp_frame *xdpf,
struct igc_ring *ring)
@@ -1942,8 +2122,8 @@ static int igc_xdp_init_tx_buffer(struct igc_tx_buffer *buffer,
return -ENOMEM;
}
+ buffer->type = IGC_TX_BUFFER_TYPE_XDP;
buffer->xdpf = xdpf;
- buffer->tx_flags = IGC_TX_FLAGS_XDP;
buffer->protocol = 0;
buffer->bytecount = xdpf->len;
buffer->gso_segs = 1;
@@ -2025,35 +2205,24 @@ static int igc_xdp_xmit_back(struct igc_adapter *adapter, struct xdp_buff *xdp)
return res;
}
-static struct sk_buff *igc_xdp_run_prog(struct igc_adapter *adapter,
- struct xdp_buff *xdp)
+/* This function assumes rcu_read_lock() is held by the caller. */
+static int __igc_xdp_run_prog(struct igc_adapter *adapter,
+ struct bpf_prog *prog,
+ struct xdp_buff *xdp)
{
- struct bpf_prog *prog;
- int res;
- u32 act;
-
- rcu_read_lock();
+ u32 act = bpf_prog_run_xdp(prog, xdp);
- prog = READ_ONCE(adapter->xdp_prog);
- if (!prog) {
- res = IGC_XDP_PASS;
- goto unlock;
- }
-
- act = bpf_prog_run_xdp(prog, xdp);
switch (act) {
case XDP_PASS:
- res = IGC_XDP_PASS;
- break;
+ return IGC_XDP_PASS;
case XDP_TX:
if (igc_xdp_xmit_back(adapter, xdp) < 0)
goto out_failure;
- res = IGC_XDP_TX;
- break;
+ return IGC_XDP_TX;
case XDP_REDIRECT:
if (xdp_do_redirect(adapter->netdev, xdp, prog) < 0)
goto out_failure;
- res = IGC_XDP_REDIRECT;
+ return IGC_XDP_REDIRECT;
break;
default:
bpf_warn_invalid_xdp_action(act);
@@ -2063,12 +2232,25 @@ out_failure:
trace_xdp_exception(adapter->netdev, prog, act);
fallthrough;
case XDP_DROP:
- res = IGC_XDP_CONSUMED;
- break;
+ return IGC_XDP_CONSUMED;
}
+}
-unlock:
- rcu_read_unlock();
+static struct sk_buff *igc_xdp_run_prog(struct igc_adapter *adapter,
+ struct xdp_buff *xdp)
+{
+ struct bpf_prog *prog;
+ int res;
+
+ prog = READ_ONCE(adapter->xdp_prog);
+ if (!prog) {
+ res = IGC_XDP_PASS;
+ goto out;
+ }
+
+ res = __igc_xdp_run_prog(adapter, prog, xdp);
+
+out:
return ERR_PTR(-res);
}
@@ -2102,6 +2284,20 @@ static void igc_finalize_xdp(struct igc_adapter *adapter, int status)
xdp_do_flush();
}
+static void igc_update_rx_stats(struct igc_q_vector *q_vector,
+ unsigned int packets, unsigned int bytes)
+{
+ struct igc_ring *ring = q_vector->rx.ring;
+
+ u64_stats_update_begin(&ring->rx_syncp);
+ ring->rx_stats.packets += packets;
+ ring->rx_stats.bytes += bytes;
+ u64_stats_update_end(&ring->rx_syncp);
+
+ q_vector->rx.total_packets += packets;
+ q_vector->rx.total_bytes += bytes;
+}
+
static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
{
unsigned int total_bytes = 0, total_packets = 0;
@@ -2150,12 +2346,9 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
}
if (!skb) {
- xdp.data = pktbuf + pkt_offset;
- xdp.data_end = xdp.data + size;
- xdp.data_hard_start = pktbuf - igc_rx_offset(rx_ring);
- xdp_set_data_meta_invalid(&xdp);
- xdp.frame_sz = truesize;
- xdp.rxq = &rx_ring->xdp_rxq;
+ xdp_init_buff(&xdp, truesize, &rx_ring->xdp_rxq);
+ xdp_prepare_buff(&xdp, pktbuf - igc_rx_offset(rx_ring),
+ igc_rx_offset(rx_ring) + pkt_offset, size, false);
skb = igc_xdp_run_prog(adapter, &xdp);
}
@@ -2225,12 +2418,7 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
/* place incomplete frames back on ring for completion */
rx_ring->skb = skb;
- u64_stats_update_begin(&rx_ring->rx_syncp);
- rx_ring->rx_stats.packets += total_packets;
- rx_ring->rx_stats.bytes += total_bytes;
- u64_stats_update_end(&rx_ring->rx_syncp);
- q_vector->rx.total_packets += total_packets;
- q_vector->rx.total_bytes += total_bytes;
+ igc_update_rx_stats(q_vector, total_packets, total_bytes);
if (cleaned_count)
igc_alloc_rx_buffers(rx_ring, cleaned_count);
@@ -2238,6 +2426,221 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
return total_packets;
}
+static struct sk_buff *igc_construct_skb_zc(struct igc_ring *ring,
+ struct xdp_buff *xdp)
+{
+ unsigned int metasize = xdp->data - xdp->data_meta;
+ unsigned int datasize = xdp->data_end - xdp->data;
+ unsigned int totalsize = metasize + datasize;
+ struct sk_buff *skb;
+
+ skb = __napi_alloc_skb(&ring->q_vector->napi,
+ xdp->data_end - xdp->data_hard_start,
+ GFP_ATOMIC | __GFP_NOWARN);
+ if (unlikely(!skb))
+ return NULL;
+
+ skb_reserve(skb, xdp->data_meta - xdp->data_hard_start);
+ memcpy(__skb_put(skb, totalsize), xdp->data_meta, totalsize);
+ if (metasize)
+ skb_metadata_set(skb, metasize);
+
+ return skb;
+}
+
+static void igc_dispatch_skb_zc(struct igc_q_vector *q_vector,
+ union igc_adv_rx_desc *desc,
+ struct xdp_buff *xdp,
+ ktime_t timestamp)
+{
+ struct igc_ring *ring = q_vector->rx.ring;
+ struct sk_buff *skb;
+
+ skb = igc_construct_skb_zc(ring, xdp);
+ if (!skb) {
+ ring->rx_stats.alloc_failed++;
+ return;
+ }
+
+ if (timestamp)
+ skb_hwtstamps(skb)->hwtstamp = timestamp;
+
+ if (igc_cleanup_headers(ring, desc, skb))
+ return;
+
+ igc_process_skb_fields(ring, desc, skb);
+ napi_gro_receive(&q_vector->napi, skb);
+}
+
+static int igc_clean_rx_irq_zc(struct igc_q_vector *q_vector, const int budget)
+{
+ struct igc_adapter *adapter = q_vector->adapter;
+ struct igc_ring *ring = q_vector->rx.ring;
+ u16 cleaned_count = igc_desc_unused(ring);
+ int total_bytes = 0, total_packets = 0;
+ u16 ntc = ring->next_to_clean;
+ struct bpf_prog *prog;
+ bool failure = false;
+ int xdp_status = 0;
+
+ rcu_read_lock();
+
+ prog = READ_ONCE(adapter->xdp_prog);
+
+ while (likely(total_packets < budget)) {
+ union igc_adv_rx_desc *desc;
+ struct igc_rx_buffer *bi;
+ ktime_t timestamp = 0;
+ unsigned int size;
+ int res;
+
+ desc = IGC_RX_DESC(ring, ntc);
+ size = le16_to_cpu(desc->wb.upper.length);
+ if (!size)
+ break;
+
+ /* This memory barrier is needed to keep us from reading
+ * any other fields out of the rx_desc until we know the
+ * descriptor has been written back
+ */
+ dma_rmb();
+
+ bi = &ring->rx_buffer_info[ntc];
+
+ if (igc_test_staterr(desc, IGC_RXDADV_STAT_TSIP)) {
+ timestamp = igc_ptp_rx_pktstamp(q_vector->adapter,
+ bi->xdp->data);
+
+ bi->xdp->data += IGC_TS_HDR_LEN;
+
+ /* HW timestamp has been copied into local variable. Metadata
+ * length when XDP program is called should be 0.
+ */
+ bi->xdp->data_meta += IGC_TS_HDR_LEN;
+ size -= IGC_TS_HDR_LEN;
+ }
+
+ bi->xdp->data_end = bi->xdp->data + size;
+ xsk_buff_dma_sync_for_cpu(bi->xdp, ring->xsk_pool);
+
+ res = __igc_xdp_run_prog(adapter, prog, bi->xdp);
+ switch (res) {
+ case IGC_XDP_PASS:
+ igc_dispatch_skb_zc(q_vector, desc, bi->xdp, timestamp);
+ fallthrough;
+ case IGC_XDP_CONSUMED:
+ xsk_buff_free(bi->xdp);
+ break;
+ case IGC_XDP_TX:
+ case IGC_XDP_REDIRECT:
+ xdp_status |= res;
+ break;
+ }
+
+ bi->xdp = NULL;
+ total_bytes += size;
+ total_packets++;
+ cleaned_count++;
+ ntc++;
+ if (ntc == ring->count)
+ ntc = 0;
+ }
+
+ ring->next_to_clean = ntc;
+ rcu_read_unlock();
+
+ if (cleaned_count >= IGC_RX_BUFFER_WRITE)
+ failure = !igc_alloc_rx_buffers_zc(ring, cleaned_count);
+
+ if (xdp_status)
+ igc_finalize_xdp(adapter, xdp_status);
+
+ igc_update_rx_stats(q_vector, total_packets, total_bytes);
+
+ if (xsk_uses_need_wakeup(ring->xsk_pool)) {
+ if (failure || ring->next_to_clean == ring->next_to_use)
+ xsk_set_rx_need_wakeup(ring->xsk_pool);
+ else
+ xsk_clear_rx_need_wakeup(ring->xsk_pool);
+ return total_packets;
+ }
+
+ return failure ? budget : total_packets;
+}
+
+static void igc_update_tx_stats(struct igc_q_vector *q_vector,
+ unsigned int packets, unsigned int bytes)
+{
+ struct igc_ring *ring = q_vector->tx.ring;
+
+ u64_stats_update_begin(&ring->tx_syncp);
+ ring->tx_stats.bytes += bytes;
+ ring->tx_stats.packets += packets;
+ u64_stats_update_end(&ring->tx_syncp);
+
+ q_vector->tx.total_bytes += bytes;
+ q_vector->tx.total_packets += packets;
+}
+
+static void igc_xdp_xmit_zc(struct igc_ring *ring)
+{
+ struct xsk_buff_pool *pool = ring->xsk_pool;
+ struct netdev_queue *nq = txring_txq(ring);
+ union igc_adv_tx_desc *tx_desc = NULL;
+ int cpu = smp_processor_id();
+ u16 ntu = ring->next_to_use;
+ struct xdp_desc xdp_desc;
+ u16 budget;
+
+ if (!netif_carrier_ok(ring->netdev))
+ return;
+
+ __netif_tx_lock(nq, cpu);
+
+ budget = igc_desc_unused(ring);
+
+ while (xsk_tx_peek_desc(pool, &xdp_desc) && budget--) {
+ u32 cmd_type, olinfo_status;
+ struct igc_tx_buffer *bi;
+ dma_addr_t dma;
+
+ cmd_type = IGC_ADVTXD_DTYP_DATA | IGC_ADVTXD_DCMD_DEXT |
+ IGC_ADVTXD_DCMD_IFCS | IGC_TXD_DCMD |
+ xdp_desc.len;
+ olinfo_status = xdp_desc.len << IGC_ADVTXD_PAYLEN_SHIFT;
+
+ dma = xsk_buff_raw_get_dma(pool, xdp_desc.addr);
+ xsk_buff_raw_dma_sync_for_device(pool, dma, xdp_desc.len);
+
+ tx_desc = IGC_TX_DESC(ring, ntu);
+ tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type);
+ tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
+ tx_desc->read.buffer_addr = cpu_to_le64(dma);
+
+ bi = &ring->tx_buffer_info[ntu];
+ bi->type = IGC_TX_BUFFER_TYPE_XSK;
+ bi->protocol = 0;
+ bi->bytecount = xdp_desc.len;
+ bi->gso_segs = 1;
+ bi->time_stamp = jiffies;
+ bi->next_to_watch = tx_desc;
+
+ netdev_tx_sent_queue(txring_txq(ring), xdp_desc.len);
+
+ ntu++;
+ if (ntu == ring->count)
+ ntu = 0;
+ }
+
+ ring->next_to_use = ntu;
+ if (tx_desc) {
+ igc_flush_tx_descriptors(ring);
+ xsk_tx_release(pool);
+ }
+
+ __netif_tx_unlock(nq);
+}
+
/**
* igc_clean_tx_irq - Reclaim resources after transmit completes
* @q_vector: pointer to q_vector containing needed info
@@ -2254,6 +2657,7 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
unsigned int i = tx_ring->next_to_clean;
struct igc_tx_buffer *tx_buffer;
union igc_adv_tx_desc *tx_desc;
+ u32 xsk_frames = 0;
if (test_bit(__IGC_DOWN, &adapter->state))
return true;
@@ -2283,19 +2687,22 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
total_bytes += tx_buffer->bytecount;
total_packets += tx_buffer->gso_segs;
- if (tx_buffer->tx_flags & IGC_TX_FLAGS_XDP)
+ switch (tx_buffer->type) {
+ case IGC_TX_BUFFER_TYPE_XSK:
+ xsk_frames++;
+ break;
+ case IGC_TX_BUFFER_TYPE_XDP:
xdp_return_frame(tx_buffer->xdpf);
- else
+ igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
+ break;
+ case IGC_TX_BUFFER_TYPE_SKB:
napi_consume_skb(tx_buffer->skb, napi_budget);
-
- /* unmap skb header data */
- dma_unmap_single(tx_ring->dev,
- dma_unmap_addr(tx_buffer, dma),
- dma_unmap_len(tx_buffer, len),
- DMA_TO_DEVICE);
-
- /* clear tx_buffer data */
- dma_unmap_len_set(tx_buffer, len, 0);
+ igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
+ break;
+ default:
+ netdev_warn_once(tx_ring->netdev, "Unknown Tx buffer type\n");
+ break;
+ }
/* clear last DMA location and unmap remaining buffers */
while (tx_desc != eop_desc) {
@@ -2309,13 +2716,8 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
}
/* unmap any remaining paged data */
- if (dma_unmap_len(tx_buffer, len)) {
- dma_unmap_page(tx_ring->dev,
- dma_unmap_addr(tx_buffer, dma),
- dma_unmap_len(tx_buffer, len),
- DMA_TO_DEVICE);
- dma_unmap_len_set(tx_buffer, len, 0);
- }
+ if (dma_unmap_len(tx_buffer, len))
+ igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
}
/* move us one more past the eop_desc for start of next pkt */
@@ -2340,12 +2742,16 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
i += tx_ring->count;
tx_ring->next_to_clean = i;
- u64_stats_update_begin(&tx_ring->tx_syncp);
- tx_ring->tx_stats.bytes += total_bytes;
- tx_ring->tx_stats.packets += total_packets;
- u64_stats_update_end(&tx_ring->tx_syncp);
- q_vector->tx.total_bytes += total_bytes;
- q_vector->tx.total_packets += total_packets;
+
+ igc_update_tx_stats(q_vector, total_packets, total_bytes);
+
+ if (tx_ring->xsk_pool) {
+ if (xsk_frames)
+ xsk_tx_completed(tx_ring->xsk_pool, xsk_frames);
+ if (xsk_uses_need_wakeup(tx_ring->xsk_pool))
+ xsk_set_tx_need_wakeup(tx_ring->xsk_pool);
+ igc_xdp_xmit_zc(tx_ring);
+ }
if (test_bit(IGC_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags)) {
struct igc_hw *hw = &adapter->hw;
@@ -2906,6 +3312,8 @@ static void igc_configure(struct igc_adapter *adapter)
igc_get_hw_control(adapter);
igc_set_rx_mode(netdev);
+ igc_restore_vlan(adapter);
+
igc_setup_tctl(adapter);
igc_setup_mrqc(adapter);
igc_setup_rctl(adapter);
@@ -2925,7 +3333,10 @@ static void igc_configure(struct igc_adapter *adapter)
for (i = 0; i < adapter->num_rx_queues; i++) {
struct igc_ring *ring = adapter->rx_ring[i];
- igc_alloc_rx_buffers(ring, igc_desc_unused(ring));
+ if (ring->xsk_pool)
+ igc_alloc_rx_buffers_zc(ring, igc_desc_unused(ring));
+ else
+ igc_alloc_rx_buffers(ring, igc_desc_unused(ring));
}
}
@@ -3540,14 +3951,17 @@ static int igc_poll(struct napi_struct *napi, int budget)
struct igc_q_vector *q_vector = container_of(napi,
struct igc_q_vector,
napi);
+ struct igc_ring *rx_ring = q_vector->rx.ring;
bool clean_complete = true;
int work_done = 0;
if (q_vector->tx.ring)
clean_complete = igc_clean_tx_irq(q_vector, budget);
- if (q_vector->rx.ring) {
- int cleaned = igc_clean_rx_irq(q_vector, budget);
+ if (rx_ring) {
+ int cleaned = rx_ring->xsk_pool ?
+ igc_clean_rx_irq_zc(q_vector, budget) :
+ igc_clean_rx_irq(q_vector, budget);
work_done += cleaned;
if (cleaned >= budget)
@@ -4199,6 +4613,9 @@ static int igc_set_features(struct net_device *netdev,
netdev_features_t changed = netdev->features ^ features;
struct igc_adapter *adapter = netdev_priv(netdev);
+ if (changed & NETIF_F_HW_VLAN_CTAG_RX)
+ igc_vlan_mode(netdev, features);
+
/* Add VLAN support */
if (!(changed & (NETIF_F_RXALL | NETIF_F_NTUPLE)))
return 0;
@@ -5185,6 +5602,9 @@ static int igc_bpf(struct net_device *dev, struct netdev_bpf *bpf)
switch (bpf->command) {
case XDP_SETUP_PROG:
return igc_xdp_set_prog(adapter, bpf->prog, bpf->extack);
+ case XDP_SETUP_XSK_POOL:
+ return igc_xdp_setup_pool(adapter, bpf->xsk.pool,
+ bpf->xsk.queue_id);
default:
return -EOPNOTSUPP;
}
@@ -5230,6 +5650,43 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames,
return num_frames - drops;
}
+static void igc_trigger_rxtxq_interrupt(struct igc_adapter *adapter,
+ struct igc_q_vector *q_vector)
+{
+ struct igc_hw *hw = &adapter->hw;
+ u32 eics = 0;
+
+ eics |= q_vector->eims_value;
+ wr32(IGC_EICS, eics);
+}
+
+int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
+{
+ struct igc_adapter *adapter = netdev_priv(dev);
+ struct igc_q_vector *q_vector;
+ struct igc_ring *ring;
+
+ if (test_bit(__IGC_DOWN, &adapter->state))
+ return -ENETDOWN;
+
+ if (!igc_xdp_is_enabled(adapter))
+ return -ENXIO;
+
+ if (queue_id >= adapter->num_rx_queues)
+ return -EINVAL;
+
+ ring = adapter->rx_ring[queue_id];
+
+ if (!ring->xsk_pool)
+ return -ENXIO;
+
+ q_vector = adapter->q_vector[queue_id];
+ if (!napi_if_scheduled_mark_missed(&q_vector->napi))
+ igc_trigger_rxtxq_interrupt(adapter, q_vector);
+
+ return 0;
+}
+
static const struct net_device_ops igc_netdev_ops = {
.ndo_open = igc_open,
.ndo_stop = igc_close,
@@ -5245,6 +5702,7 @@ static const struct net_device_ops igc_netdev_ops = {
.ndo_setup_tc = igc_setup_tc,
.ndo_bpf = igc_bpf,
.ndo_xdp_xmit = igc_xdp_xmit,
+ .ndo_xsk_wakeup = igc_xsk_wakeup,
};
/* PCIe configuration access */
@@ -5484,11 +5942,15 @@ static int igc_probe(struct pci_dev *pdev,
/* copy netdev features into list of user selectable features */
netdev->hw_features |= NETIF_F_NTUPLE;
+ netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
+ netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
netdev->hw_features |= netdev->features;
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
+ netdev->vlan_features |= netdev->features;
+
/* MTU range: 68 - 9216 */
netdev->min_mtu = ETH_MIN_MTU;
netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE;
@@ -5594,6 +6056,7 @@ err_sw_init:
err_ioremap:
free_netdev(netdev);
err_alloc_etherdev:
+ pci_disable_pcie_error_reporting(pdev);
pci_release_mem_regions(pdev);
err_pci_reg:
err_dma:
@@ -5997,6 +6460,61 @@ struct net_device *igc_get_hw_dev(struct igc_hw *hw)
return adapter->netdev;
}
+static void igc_disable_rx_ring_hw(struct igc_ring *ring)
+{
+ struct igc_hw *hw = &ring->q_vector->adapter->hw;
+ u8 idx = ring->reg_idx;
+ u32 rxdctl;
+
+ rxdctl = rd32(IGC_RXDCTL(idx));
+ rxdctl &= ~IGC_RXDCTL_QUEUE_ENABLE;
+ rxdctl |= IGC_RXDCTL_SWFLUSH;
+ wr32(IGC_RXDCTL(idx), rxdctl);
+}
+
+void igc_disable_rx_ring(struct igc_ring *ring)
+{
+ igc_disable_rx_ring_hw(ring);
+ igc_clean_rx_ring(ring);
+}
+
+void igc_enable_rx_ring(struct igc_ring *ring)
+{
+ struct igc_adapter *adapter = ring->q_vector->adapter;
+
+ igc_configure_rx_ring(adapter, ring);
+
+ if (ring->xsk_pool)
+ igc_alloc_rx_buffers_zc(ring, igc_desc_unused(ring));
+ else
+ igc_alloc_rx_buffers(ring, igc_desc_unused(ring));
+}
+
+static void igc_disable_tx_ring_hw(struct igc_ring *ring)
+{
+ struct igc_hw *hw = &ring->q_vector->adapter->hw;
+ u8 idx = ring->reg_idx;
+ u32 txdctl;
+
+ txdctl = rd32(IGC_TXDCTL(idx));
+ txdctl &= ~IGC_TXDCTL_QUEUE_ENABLE;
+ txdctl |= IGC_TXDCTL_SWFLUSH;
+ wr32(IGC_TXDCTL(idx), txdctl);
+}
+
+void igc_disable_tx_ring(struct igc_ring *ring)
+{
+ igc_disable_tx_ring_hw(ring);
+ igc_clean_tx_ring(ring);
+}
+
+void igc_enable_tx_ring(struct igc_ring *ring)
+{
+ struct igc_adapter *adapter = ring->q_vector->adapter;
+
+ igc_configure_tx_ring(adapter, ring);
+}
+
/**
* igc_init_module - Driver Registration Routine
*
diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h
index cc174853554b..0f82990567d9 100644
--- a/drivers/net/ethernet/intel/igc/igc_regs.h
+++ b/drivers/net/ethernet/intel/igc/igc_regs.h
@@ -10,8 +10,8 @@
#define IGC_EECD 0x00010 /* EEPROM/Flash Control - RW */
#define IGC_CTRL_EXT 0x00018 /* Extended Device Control - RW */
#define IGC_MDIC 0x00020 /* MDI Control - RW */
-#define IGC_MDICNFG 0x00E04 /* MDC/MDIO Configuration - RW */
#define IGC_CONNSW 0x00034 /* Copper/Fiber switch control - RW */
+#define IGC_VET 0x00038 /* VLAN Ether Type - RW */
#define IGC_I225_PHPM 0x00E14 /* I225 PHY Power Management */
#define IGC_GPHY_VERSION 0x0001E /* I225 gPHY Firmware Version */
diff --git a/drivers/net/ethernet/intel/igc/igc_xdp.c b/drivers/net/ethernet/intel/igc/igc_xdp.c
index 11133c4619bb..a8cf5374be47 100644
--- a/drivers/net/ethernet/intel/igc/igc_xdp.c
+++ b/drivers/net/ethernet/intel/igc/igc_xdp.c
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020, Intel Corporation. */
+#include <net/xdp_sock_drv.h>
+
#include "igc.h"
#include "igc_xdp.h"
@@ -32,29 +34,112 @@ int igc_xdp_set_prog(struct igc_adapter *adapter, struct bpf_prog *prog,
return 0;
}
-int igc_xdp_register_rxq_info(struct igc_ring *ring)
+static int igc_xdp_enable_pool(struct igc_adapter *adapter,
+ struct xsk_buff_pool *pool, u16 queue_id)
{
- struct net_device *dev = ring->netdev;
+ struct net_device *ndev = adapter->netdev;
+ struct device *dev = &adapter->pdev->dev;
+ struct igc_ring *rx_ring, *tx_ring;
+ struct napi_struct *napi;
+ bool needs_reset;
+ u32 frame_size;
int err;
- err = xdp_rxq_info_reg(&ring->xdp_rxq, dev, ring->queue_index, 0);
- if (err) {
- netdev_err(dev, "Failed to register xdp rxq info\n");
- return err;
+ if (queue_id >= adapter->num_rx_queues ||
+ queue_id >= adapter->num_tx_queues)
+ return -EINVAL;
+
+ frame_size = xsk_pool_get_rx_frame_size(pool);
+ if (frame_size < ETH_FRAME_LEN + VLAN_HLEN * 2) {
+ /* When XDP is enabled, the driver doesn't support frames that
+ * span over multiple buffers. To avoid that, we check if xsk
+ * frame size is big enough to fit the max ethernet frame size
+ * + vlan double tagging.
+ */
+ return -EOPNOTSUPP;
}
- err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq, MEM_TYPE_PAGE_SHARED,
- NULL);
+ err = xsk_pool_dma_map(pool, dev, IGC_RX_DMA_ATTR);
if (err) {
- netdev_err(dev, "Failed to register xdp rxq mem model\n");
- xdp_rxq_info_unreg(&ring->xdp_rxq);
+ netdev_err(ndev, "Failed to map xsk pool\n");
return err;
}
+ needs_reset = netif_running(adapter->netdev) && igc_xdp_is_enabled(adapter);
+
+ rx_ring = adapter->rx_ring[queue_id];
+ tx_ring = adapter->tx_ring[queue_id];
+ /* Rx and Tx rings share the same napi context. */
+ napi = &rx_ring->q_vector->napi;
+
+ if (needs_reset) {
+ igc_disable_rx_ring(rx_ring);
+ igc_disable_tx_ring(tx_ring);
+ napi_disable(napi);
+ }
+
+ set_bit(IGC_RING_FLAG_AF_XDP_ZC, &rx_ring->flags);
+ set_bit(IGC_RING_FLAG_AF_XDP_ZC, &tx_ring->flags);
+
+ if (needs_reset) {
+ napi_enable(napi);
+ igc_enable_rx_ring(rx_ring);
+ igc_enable_tx_ring(tx_ring);
+
+ err = igc_xsk_wakeup(ndev, queue_id, XDP_WAKEUP_RX);
+ if (err) {
+ xsk_pool_dma_unmap(pool, IGC_RX_DMA_ATTR);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int igc_xdp_disable_pool(struct igc_adapter *adapter, u16 queue_id)
+{
+ struct igc_ring *rx_ring, *tx_ring;
+ struct xsk_buff_pool *pool;
+ struct napi_struct *napi;
+ bool needs_reset;
+
+ if (queue_id >= adapter->num_rx_queues ||
+ queue_id >= adapter->num_tx_queues)
+ return -EINVAL;
+
+ pool = xsk_get_pool_from_qid(adapter->netdev, queue_id);
+ if (!pool)
+ return -EINVAL;
+
+ needs_reset = netif_running(adapter->netdev) && igc_xdp_is_enabled(adapter);
+
+ rx_ring = adapter->rx_ring[queue_id];
+ tx_ring = adapter->tx_ring[queue_id];
+ /* Rx and Tx rings share the same napi context. */
+ napi = &rx_ring->q_vector->napi;
+
+ if (needs_reset) {
+ igc_disable_rx_ring(rx_ring);
+ igc_disable_tx_ring(tx_ring);
+ napi_disable(napi);
+ }
+
+ xsk_pool_dma_unmap(pool, IGC_RX_DMA_ATTR);
+ clear_bit(IGC_RING_FLAG_AF_XDP_ZC, &rx_ring->flags);
+ clear_bit(IGC_RING_FLAG_AF_XDP_ZC, &tx_ring->flags);
+
+ if (needs_reset) {
+ napi_enable(napi);
+ igc_enable_rx_ring(rx_ring);
+ igc_enable_tx_ring(tx_ring);
+ }
+
return 0;
}
-void igc_xdp_unregister_rxq_info(struct igc_ring *ring)
+int igc_xdp_setup_pool(struct igc_adapter *adapter, struct xsk_buff_pool *pool,
+ u16 queue_id)
{
- xdp_rxq_info_unreg(&ring->xdp_rxq);
+ return pool ? igc_xdp_enable_pool(adapter, pool, queue_id) :
+ igc_xdp_disable_pool(adapter, queue_id);
}
diff --git a/drivers/net/ethernet/intel/igc/igc_xdp.h b/drivers/net/ethernet/intel/igc/igc_xdp.h
index cfecb515b718..a74e5487d199 100644
--- a/drivers/net/ethernet/intel/igc/igc_xdp.h
+++ b/drivers/net/ethernet/intel/igc/igc_xdp.h
@@ -6,8 +6,12 @@
int igc_xdp_set_prog(struct igc_adapter *adapter, struct bpf_prog *prog,
struct netlink_ext_ack *extack);
+int igc_xdp_setup_pool(struct igc_adapter *adapter, struct xsk_buff_pool *pool,
+ u16 queue_id);
-int igc_xdp_register_rxq_info(struct igc_ring *ring);
-void igc_xdp_unregister_rxq_info(struct igc_ring *ring);
+static inline bool igc_xdp_is_enabled(struct igc_adapter *adapter)
+{
+ return !!adapter->xdp_prog;
+}
#endif /* _IGC_XDP_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
index e324e42fab2d..58ea959a4482 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
@@ -1514,8 +1514,7 @@ static u32 ixgbe_get_fdirtcpm_82599(union ixgbe_atr_input *input_mask)
#define IXGBE_WRITE_REG_BE32(a, reg, value) \
IXGBE_WRITE_REG((a), (reg), IXGBE_STORE_AS_BE32(ntohl(value)))
-#define IXGBE_STORE_AS_BE16(_value) \
- ntohs(((u16)(_value) >> 8) | ((u16)(_value) << 8))
+#define IXGBE_STORE_AS_BE16(_value) __swab16(ntohs((_value)))
s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw,
union ixgbe_atr_input *input_mask)
@@ -1651,13 +1650,13 @@ s32 ixgbe_fdir_write_perfect_filter_82599(struct ixgbe_hw *hw,
IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRIPDA, input->formatted.dst_ip[0]);
/* record source and destination port (little-endian)*/
- fdirport = ntohs(input->formatted.dst_port);
+ fdirport = be16_to_cpu(input->formatted.dst_port);
fdirport <<= IXGBE_FDIRPORT_DESTINATION_SHIFT;
- fdirport |= ntohs(input->formatted.src_port);
+ fdirport |= be16_to_cpu(input->formatted.src_port);
IXGBE_WRITE_REG(hw, IXGBE_FDIRPORT, fdirport);
/* record vlan (little-endian) and flex_bytes(big-endian) */
- fdirvlan = IXGBE_STORE_AS_BE16((__force u16)input->formatted.flex_bytes);
+ fdirvlan = IXGBE_STORE_AS_BE16(input->formatted.flex_bytes);
fdirvlan <<= IXGBE_FDIRVLAN_FLEX_SHIFT;
fdirvlan |= ntohs(input->formatted.vlan_id);
IXGBE_WRITE_REG(hw, IXGBE_FDIRVLAN, fdirvlan);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
index 03ccbe6b66d2..e90b5047e695 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -3678,10 +3678,8 @@ s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, void *buffer,
bool return_data)
{
u32 hdr_size = sizeof(struct ixgbe_hic_hdr);
- union {
- struct ixgbe_hic_hdr hdr;
- u32 u32arr[1];
- } *bp = buffer;
+ struct ixgbe_hic_hdr *hdr = buffer;
+ u32 *u32arr = buffer;
u16 buf_len, dword_len;
s32 status;
u32 bi;
@@ -3707,12 +3705,12 @@ s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, void *buffer,
/* first pull in the header so we know the buffer length */
for (bi = 0; bi < dword_len; bi++) {
- bp->u32arr[bi] = IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, bi);
- le32_to_cpus(&bp->u32arr[bi]);
+ u32arr[bi] = IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, bi);
+ le32_to_cpus(&u32arr[bi]);
}
/* If there is any thing in data position pull it in */
- buf_len = bp->hdr.buf_len;
+ buf_len = hdr->buf_len;
if (!buf_len)
goto rel_out;
@@ -3727,8 +3725,8 @@ s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, void *buffer,
/* Pull in the rest of the buffer (bi is where we left off) */
for (; bi <= dword_len; bi++) {
- bp->u32arr[bi] = IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, bi);
- le32_to_cpus(&bp->u32arr[bi]);
+ u32arr[bi] = IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, bi);
+ le32_to_cpus(&u32arr[bi]);
}
rel_out:
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
index 54d47265a7ac..e596e1a9fc75 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
@@ -511,14 +511,14 @@ static int ixgbe_ipsec_check_mgmt_ip(struct xfrm_state *xs)
continue;
reg = IXGBE_READ_REG(hw, MIPAF_ARR(3, i));
- if (reg == xs->id.daddr.a4)
+ if (reg == (__force u32)xs->id.daddr.a4)
return 1;
}
}
if ((bmcipval & BMCIP_MASK) == BMCIP_V4) {
reg = IXGBE_READ_REG(hw, IXGBE_BMCIP(3));
- if (reg == xs->id.daddr.a4)
+ if (reg == (__force u32)xs->id.daddr.a4)
return 1;
}
@@ -533,7 +533,7 @@ static int ixgbe_ipsec_check_mgmt_ip(struct xfrm_state *xs)
for (j = 0; j < 4; j++) {
reg = IXGBE_READ_REG(hw, MIPAF_ARR(i, j));
- if (reg != xs->id.daddr.a6[j])
+ if (reg != (__force u32)xs->id.daddr.a6[j])
break;
}
if (j == 4) /* did we match all 4 words? */
@@ -543,7 +543,7 @@ static int ixgbe_ipsec_check_mgmt_ip(struct xfrm_state *xs)
if ((bmcipval & BMCIP_MASK) == BMCIP_V6) {
for (j = 0; j < 4; j++) {
reg = IXGBE_READ_REG(hw, IXGBE_BMCIP(j));
- if (reg != xs->id.daddr.a6[j])
+ if (reg != (__force u32)xs->id.daddr.a6[j])
break;
}
if (j == 4) /* did we match all 4 words? */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 2ac5b82676f3..913253f8ecb4 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -2199,7 +2199,6 @@ static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter,
struct xdp_frame *xdpf;
u32 act;
- rcu_read_lock();
xdp_prog = READ_ONCE(rx_ring->xdp_prog);
if (!xdp_prog)
@@ -2237,7 +2236,6 @@ out_failure:
break;
}
xdp_out:
- rcu_read_unlock();
return ERR_PTR(-result);
}
@@ -11069,6 +11067,7 @@ err_ioremap:
disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state);
free_netdev(netdev);
err_alloc_etherdev:
+ pci_disable_pcie_error_reporting(pdev);
pci_release_mem_regions(pdev);
err_pci_reg:
err_dma:
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
index f72d2978263b..96dd1a4f956a 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
@@ -100,7 +100,6 @@ static int ixgbe_run_xdp_zc(struct ixgbe_adapter *adapter,
struct xdp_frame *xdpf;
u32 act;
- rcu_read_lock();
xdp_prog = READ_ONCE(rx_ring->xdp_prog);
act = bpf_prog_run_xdp(xdp_prog, xdp);
@@ -108,7 +107,6 @@ static int ixgbe_run_xdp_zc(struct ixgbe_adapter *adapter,
err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
if (err)
goto out_failure;
- rcu_read_unlock();
return IXGBE_XDP_REDIR;
}
@@ -134,7 +132,6 @@ out_failure:
result = IXGBE_XDP_CONSUMED;
break;
}
- rcu_read_unlock();
return result;
}
diff --git a/drivers/net/ethernet/intel/ixgbevf/ipsec.c b/drivers/net/ethernet/intel/ixgbevf/ipsec.c
index caaea2c920a6..e3e4676af9e4 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ipsec.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ipsec.c
@@ -211,7 +211,7 @@ struct xfrm_state *ixgbevf_ipsec_find_rx_state(struct ixgbevf_ipsec *ipsec,
static int ixgbevf_ipsec_parse_proto_keys(struct xfrm_state *xs,
u32 *mykey, u32 *mysalt)
{
- struct net_device *dev = xs->xso.dev;
+ struct net_device *dev = xs->xso.real_dev;
unsigned char *key_data;
char *alg_name = NULL;
int key_len;
@@ -260,12 +260,15 @@ static int ixgbevf_ipsec_parse_proto_keys(struct xfrm_state *xs,
**/
static int ixgbevf_ipsec_add_sa(struct xfrm_state *xs)
{
- struct net_device *dev = xs->xso.dev;
- struct ixgbevf_adapter *adapter = netdev_priv(dev);
- struct ixgbevf_ipsec *ipsec = adapter->ipsec;
+ struct net_device *dev = xs->xso.real_dev;
+ struct ixgbevf_adapter *adapter;
+ struct ixgbevf_ipsec *ipsec;
u16 sa_idx;
int ret;
+ adapter = netdev_priv(dev);
+ ipsec = adapter->ipsec;
+
if (xs->id.proto != IPPROTO_ESP && xs->id.proto != IPPROTO_AH) {
netdev_err(dev, "Unsupported protocol 0x%04x for IPsec offload\n",
xs->id.proto);
@@ -383,11 +386,14 @@ static int ixgbevf_ipsec_add_sa(struct xfrm_state *xs)
**/
static void ixgbevf_ipsec_del_sa(struct xfrm_state *xs)
{
- struct net_device *dev = xs->xso.dev;
- struct ixgbevf_adapter *adapter = netdev_priv(dev);
- struct ixgbevf_ipsec *ipsec = adapter->ipsec;
+ struct net_device *dev = xs->xso.real_dev;
+ struct ixgbevf_adapter *adapter;
+ struct ixgbevf_ipsec *ipsec;
u16 sa_idx;
+ adapter = netdev_priv(dev);
+ ipsec = adapter->ipsec;
+
if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) {
sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_RX_INDEX;
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index 0e733cc15c58..c714e1ecd308 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -1054,7 +1054,6 @@ static struct sk_buff *ixgbevf_run_xdp(struct ixgbevf_adapter *adapter,
struct bpf_prog *xdp_prog;
u32 act;
- rcu_read_lock();
xdp_prog = READ_ONCE(rx_ring->xdp_prog);
if (!xdp_prog)
@@ -1082,7 +1081,6 @@ out_failure:
break;
}
xdp_out:
- rcu_read_unlock();
return ERR_PTR(-result);
}
@@ -3817,7 +3815,7 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring,
/* remove payload length from inner checksum */
paylen = skb->len - l4_offset;
- csum_replace_by_diff(&l4.tcp->check, htonl(paylen));
+ csum_replace_by_diff(&l4.tcp->check, (__force __wsum)htonl(paylen));
/* update gso size and bytecount with header size */
first->gso_segs = skb_shinfo(skb)->gso_segs;
diff --git a/drivers/net/ethernet/lantiq_xrx200.c b/drivers/net/ethernet/lantiq_xrx200.c
index 21ef2f128070..fb78f17d734f 100644
--- a/drivers/net/ethernet/lantiq_xrx200.c
+++ b/drivers/net/ethernet/lantiq_xrx200.c
@@ -437,7 +437,6 @@ static int xrx200_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
- struct resource *res;
struct xrx200_priv *priv;
struct net_device *net_dev;
int err;
@@ -457,13 +456,7 @@ static int xrx200_probe(struct platform_device *pdev)
net_dev->max_mtu = XRX200_DMA_DATA_LEN;
/* load the memory ranges */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "failed to get resources\n");
- return -ENOENT;
- }
-
- priv->pmac_reg = devm_ioremap_resource(dev, res);
+ priv->pmac_reg = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(priv->pmac_reg))
return PTR_ERR(priv->pmac_reg);
diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c
index d14762d93640..62a97c46fba0 100644
--- a/drivers/net/ethernet/marvell/mvmdio.c
+++ b/drivers/net/ethernet/marvell/mvmdio.c
@@ -17,6 +17,8 @@
* warranty of any kind, whether express or implied.
*/
+#include <linux/acpi.h>
+#include <linux/acpi_mdio.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -281,7 +283,7 @@ static int orion_mdio_probe(struct platform_device *pdev)
struct orion_mdio_dev *dev;
int i, ret;
- type = (enum orion_mdio_bus_type)of_device_get_match_data(&pdev->dev);
+ type = (enum orion_mdio_bus_type)device_get_match_data(&pdev->dev);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
@@ -369,7 +371,13 @@ static int orion_mdio_probe(struct platform_device *pdev)
goto out_mdio;
}
- ret = of_mdiobus_register(bus, pdev->dev.of_node);
+ /* For the platforms not supporting DT/ACPI fall-back
+ * to mdiobus_register via of_mdiobus_register.
+ */
+ if (is_acpi_node(pdev->dev.fwnode))
+ ret = acpi_mdiobus_register(bus, pdev->dev.fwnode);
+ else
+ ret = of_mdiobus_register(bus, pdev->dev.of_node);
if (ret < 0) {
dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
goto out_mdio;
@@ -421,12 +429,20 @@ static const struct of_device_id orion_mdio_match[] = {
};
MODULE_DEVICE_TABLE(of, orion_mdio_match);
+static const struct acpi_device_id orion_mdio_acpi_match[] = {
+ { "MRVL0100", BUS_TYPE_SMI },
+ { "MRVL0101", BUS_TYPE_XSMI },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, orion_mdio_acpi_match);
+
static struct platform_driver orion_mdio_driver = {
.probe = orion_mdio_probe,
.remove = orion_mdio_remove,
.driver = {
.name = "orion-mdio",
.of_match_table = orion_mdio_match,
+ .acpi_match_table = ACPI_PTR(orion_mdio_acpi_match),
},
};
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 7d5cd9bc6c99..76a7777c746d 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -1805,18 +1805,14 @@ static void mvneta_rx_error(struct mvneta_port *pp,
}
/* Handle RX checksum offload based on the descriptor's status */
-static void mvneta_rx_csum(struct mvneta_port *pp, u32 status,
- struct sk_buff *skb)
+static int mvneta_rx_csum(struct mvneta_port *pp, u32 status)
{
if ((pp->dev->features & NETIF_F_RXCSUM) &&
(status & MVNETA_RXD_L3_IP4) &&
- (status & MVNETA_RXD_L4_CSUM_OK)) {
- skb->csum = 0;
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- return;
- }
+ (status & MVNETA_RXD_L4_CSUM_OK))
+ return CHECKSUM_UNNECESSARY;
- skb->ip_summed = CHECKSUM_NONE;
+ return CHECKSUM_NONE;
}
/* Return tx queue pointer (find last set bit) according to <cause> returned
@@ -2303,24 +2299,24 @@ mvneta_swbm_add_rx_fragment(struct mvneta_port *pp,
skb_frag_off_set(frag, pp->rx_offset_correction);
skb_frag_size_set(frag, data_len);
__skb_frag_set_page(frag, page);
-
- /* last fragment */
- if (len == *size) {
- struct skb_shared_info *sinfo;
-
- sinfo = xdp_get_shared_info_from_buff(xdp);
- sinfo->nr_frags = xdp_sinfo->nr_frags;
- memcpy(sinfo->frags, xdp_sinfo->frags,
- sinfo->nr_frags * sizeof(skb_frag_t));
- }
} else {
page_pool_put_full_page(rxq->page_pool, page, true);
}
+
+ /* last fragment */
+ if (len == *size) {
+ struct skb_shared_info *sinfo;
+
+ sinfo = xdp_get_shared_info_from_buff(xdp);
+ sinfo->nr_frags = xdp_sinfo->nr_frags;
+ memcpy(sinfo->frags, xdp_sinfo->frags,
+ sinfo->nr_frags * sizeof(skb_frag_t));
+ }
*size -= len;
}
static struct sk_buff *
-mvneta_swbm_build_skb(struct mvneta_port *pp, struct mvneta_rx_queue *rxq,
+mvneta_swbm_build_skb(struct mvneta_port *pp, struct page_pool *pool,
struct xdp_buff *xdp, u32 desc_status)
{
struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
@@ -2331,11 +2327,11 @@ mvneta_swbm_build_skb(struct mvneta_port *pp, struct mvneta_rx_queue *rxq,
if (!skb)
return ERR_PTR(-ENOMEM);
- page_pool_release_page(rxq->page_pool, virt_to_page(xdp->data));
+ skb_mark_for_recycle(skb, virt_to_page(xdp->data), pool);
skb_reserve(skb, xdp->data - xdp->data_hard_start);
skb_put(skb, xdp->data_end - xdp->data);
- mvneta_rx_csum(pp, desc_status, skb);
+ skb->ip_summed = mvneta_rx_csum(pp, desc_status);
for (i = 0; i < num_frags; i++) {
skb_frag_t *frag = &sinfo->frags[i];
@@ -2343,7 +2339,10 @@ mvneta_swbm_build_skb(struct mvneta_port *pp, struct mvneta_rx_queue *rxq,
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
skb_frag_page(frag), skb_frag_off(frag),
skb_frag_size(frag), PAGE_SIZE);
- page_pool_release_page(rxq->page_pool, skb_frag_page(frag));
+ /* We don't need to reset pp_recycle here. It's already set, so
+ * just mark fragments for recycling.
+ */
+ page_pool_store_mem_info(skb_frag_page(frag), pool);
}
return skb;
@@ -2370,7 +2369,6 @@ static int mvneta_rx_swbm(struct napi_struct *napi,
/* Get number of received packets */
rx_todo = mvneta_rxq_busy_desc_num_get(pp, rxq);
- rcu_read_lock();
xdp_prog = READ_ONCE(pp->xdp_prog);
/* Fairness NAPI loop */
@@ -2425,7 +2423,7 @@ static int mvneta_rx_swbm(struct napi_struct *napi,
mvneta_run_xdp(pp, rxq, xdp_prog, &xdp_buf, frame_sz, &ps))
goto next;
- skb = mvneta_swbm_build_skb(pp, rxq, &xdp_buf, desc_status);
+ skb = mvneta_swbm_build_skb(pp, rxq->page_pool, &xdp_buf, desc_status);
if (IS_ERR(skb)) {
struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats);
@@ -2448,7 +2446,6 @@ next:
xdp_buf.data_hard_start = NULL;
sinfo.nr_frags = 0;
}
- rcu_read_unlock();
if (xdp_buf.data_hard_start)
mvneta_xdp_put_buff(pp, rxq, &xdp_buf, &sinfo, -1);
@@ -2532,7 +2529,7 @@ err_drop_frame:
rx_bytes);
skb->protocol = eth_type_trans(skb, dev);
- mvneta_rx_csum(pp, rx_status, skb);
+ skb->ip_summed = mvneta_rx_csum(pp, rx_status);
napi_gro_receive(napi, skb);
rcvd_pkts++;
@@ -2581,8 +2578,7 @@ err_drop_frame:
skb_put(skb, rx_bytes);
skb->protocol = eth_type_trans(skb, dev);
-
- mvneta_rx_csum(pp, rx_status, skb);
+ skb->ip_summed = mvneta_rx_csum(pp, rx_status);
napi_gro_receive(napi, skb);
}
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
index 4a61c90003b5..b9fbc9f000f2 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
@@ -1197,9 +1197,6 @@ struct mvpp2_port {
/* Firmware node associated to the port */
struct fwnode_handle *fwnode;
- /* Is a PHY always connected to the port */
- bool has_phy;
-
/* Per-port registers' base address */
void __iomem *base;
void __iomem *stats_base;
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index d39c7639cdba..3229bafa2a2c 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -3543,21 +3543,17 @@ static void mvpp2_rx_error(struct mvpp2_port *port,
}
/* Handle RX checksum offload */
-static void mvpp2_rx_csum(struct mvpp2_port *port, u32 status,
- struct sk_buff *skb)
+static int mvpp2_rx_csum(struct mvpp2_port *port, u32 status)
{
if (((status & MVPP2_RXD_L3_IP4) &&
!(status & MVPP2_RXD_IP4_HEADER_ERR)) ||
(status & MVPP2_RXD_L3_IP6))
if (((status & MVPP2_RXD_L4_UDP) ||
(status & MVPP2_RXD_L4_TCP)) &&
- (status & MVPP2_RXD_L4_CSUM_OK)) {
- skb->csum = 0;
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- return;
- }
+ (status & MVPP2_RXD_L4_CSUM_OK))
+ return CHECKSUM_UNNECESSARY;
- skb->ip_summed = CHECKSUM_NONE;
+ return CHECKSUM_NONE;
}
/* Allocate a new skb and add it to BM pool */
@@ -3784,9 +3780,9 @@ mvpp2_xdp_xmit(struct net_device *dev, int num_frame,
}
static int
-mvpp2_run_xdp(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq,
- struct bpf_prog *prog, struct xdp_buff *xdp,
- struct page_pool *pp, struct mvpp2_pcpu_stats *stats)
+mvpp2_run_xdp(struct mvpp2_port *port, struct bpf_prog *prog,
+ struct xdp_buff *xdp, struct page_pool *pp,
+ struct mvpp2_pcpu_stats *stats)
{
unsigned int len, sync, err;
struct page *page;
@@ -3881,8 +3877,6 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
int rx_done = 0;
u32 xdp_ret = 0;
- rcu_read_lock();
-
xdp_prog = READ_ONCE(port->xdp_prog);
/* Get number of received packets and clamp the to-do */
@@ -3900,15 +3894,19 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
phys_addr_t phys_addr;
u32 rx_status, timestamp;
int pool, rx_bytes, err, ret;
+ struct page *page;
void *data;
+ phys_addr = mvpp2_rxdesc_cookie_get(port, rx_desc);
+ data = (void *)phys_to_virt(phys_addr);
+ page = virt_to_page(data);
+ prefetch(page);
+
rx_done++;
rx_status = mvpp2_rxdesc_status_get(port, rx_desc);
rx_bytes = mvpp2_rxdesc_size_get(port, rx_desc);
rx_bytes -= MVPP2_MH_SIZE;
dma_addr = mvpp2_rxdesc_dma_addr_get(port, rx_desc);
- phys_addr = mvpp2_rxdesc_cookie_get(port, rx_desc);
- data = (void *)phys_to_virt(phys_addr);
pool = (rx_status & MVPP2_RXD_BM_POOL_ID_MASK) >>
MVPP2_RXD_BM_POOL_ID_OFFS;
@@ -3938,7 +3936,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
goto err_drop_frame;
/* Prefetch header */
- prefetch(data);
+ prefetch(data + MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM);
if (bm_pool->frag_size > PAGE_SIZE)
frag_size = 0;
@@ -3958,7 +3956,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM,
rx_bytes, false);
- ret = mvpp2_run_xdp(port, rxq, xdp_prog, &xdp, pp, &ps);
+ ret = mvpp2_run_xdp(port, xdp_prog, &xdp, pp, &ps);
if (ret) {
xdp_ret |= ret;
@@ -3997,7 +3995,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
}
if (pp)
- page_pool_release_page(pp, virt_to_page(data));
+ skb_mark_for_recycle(skb, page, pp);
else
dma_unmap_single_attrs(dev->dev.parent, dma_addr,
bm_pool->buf_size, DMA_FROM_DEVICE,
@@ -4008,8 +4006,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
skb_reserve(skb, MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM);
skb_put(skb, rx_bytes);
+ skb->ip_summed = mvpp2_rx_csum(port, rx_status);
skb->protocol = eth_type_trans(skb, dev);
- mvpp2_rx_csum(port, rx_status, skb);
napi_gro_receive(napi, skb);
continue;
@@ -4024,8 +4022,6 @@ err_drop_frame:
mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr);
}
- rcu_read_unlock();
-
if (xdp_ret & MVPP2_XDP_REDIR)
xdp_do_flush_map();
@@ -4789,9 +4785,8 @@ static int mvpp2_open(struct net_device *dev)
goto err_cleanup_txqs;
}
- /* Phylink isn't supported yet in ACPI mode */
- if (port->of_node) {
- err = phylink_of_phy_connect(port->phylink, port->of_node, 0);
+ if (port->phylink) {
+ err = phylink_fwnode_phy_connect(port->phylink, port->fwnode, 0);
if (err) {
netdev_err(port->dev, "could not attach PHY (%d)\n",
err);
@@ -6699,6 +6694,19 @@ static void mvpp2_acpi_start(struct mvpp2_port *port)
SPEED_UNKNOWN, DUPLEX_UNKNOWN, false, false);
}
+/* In order to ensure backward compatibility for ACPI, check if the port
+ * firmware node comprises the necessary description allowing to use phylink.
+ */
+static bool mvpp2_use_acpi_compat_mode(struct fwnode_handle *port_fwnode)
+{
+ if (!is_acpi_node(port_fwnode))
+ return false;
+
+ return (!fwnode_property_present(port_fwnode, "phy-handle") &&
+ !fwnode_property_present(port_fwnode, "managed") &&
+ !fwnode_get_named_child_node(port_fwnode, "fixed-link"));
+}
+
/* Ports initialization */
static int mvpp2_port_probe(struct platform_device *pdev,
struct fwnode_handle *port_fwnode,
@@ -6774,7 +6782,6 @@ static int mvpp2_port_probe(struct platform_device *pdev,
port = netdev_priv(dev);
port->dev = dev;
port->fwnode = port_fwnode;
- port->has_phy = !!of_find_property(port_node, "phy", NULL);
port->ntxqs = ntxqs;
port->nrxqs = nrxqs;
port->priv = priv;
@@ -6917,8 +6924,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
dev->max_mtu = MVPP2_BM_JUMBO_PKT_SIZE;
dev->dev.of_node = port_node;
- /* Phylink isn't used w/ ACPI as of now */
- if (port_node) {
+ if (!mvpp2_use_acpi_compat_mode(port_fwnode)) {
port->phylink_config.dev = &dev->dev;
port->phylink_config.type = PHYLINK_NETDEV;
@@ -6930,6 +6936,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
}
port->phylink = phylink;
} else {
+ dev_warn(&pdev->dev, "Use link irqs for port#%d. FW update required\n", port->id);
port->phylink = NULL;
}
@@ -7347,7 +7354,6 @@ static int mvpp2_get_sram(struct platform_device *pdev,
static int mvpp2_probe(struct platform_device *pdev)
{
- const struct acpi_device_id *acpi_id;
struct fwnode_handle *fwnode = pdev->dev.fwnode;
struct fwnode_handle *port_fwnode;
struct mvpp2 *priv;
@@ -7360,16 +7366,7 @@ static int mvpp2_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- if (has_acpi_companion(&pdev->dev)) {
- acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
- &pdev->dev);
- if (!acpi_id)
- return -EINVAL;
- priv->hw_version = (unsigned long)acpi_id->driver_data;
- } else {
- priv->hw_version =
- (unsigned long)of_device_get_match_data(&pdev->dev);
- }
+ priv->hw_version = (unsigned long)device_get_match_data(&pdev->dev);
/* multi queue mode isn't supported on PPV2.1, fallback to single
* mode
@@ -7387,6 +7384,10 @@ static int mvpp2_probe(struct platform_device *pdev)
return PTR_ERR(priv->lms_base);
} else {
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "Invalid resource\n");
+ return -EINVAL;
+ }
if (has_acpi_companion(&pdev->dev)) {
/* In case the MDIO memory region is declared in
* the ACPI, it can already appear as 'in-use'
@@ -7481,34 +7482,35 @@ static int mvpp2_probe(struct platform_device *pdev)
if (err < 0)
goto err_gop_clk;
- priv->mg_core_clk = devm_clk_get(&pdev->dev, "mg_core_clk");
+ priv->mg_core_clk = devm_clk_get_optional(&pdev->dev, "mg_core_clk");
if (IS_ERR(priv->mg_core_clk)) {
- priv->mg_core_clk = NULL;
- } else {
- err = clk_prepare_enable(priv->mg_core_clk);
- if (err < 0)
- goto err_mg_clk;
+ err = PTR_ERR(priv->mg_core_clk);
+ goto err_mg_clk;
}
+
+ err = clk_prepare_enable(priv->mg_core_clk);
+ if (err < 0)
+ goto err_mg_clk;
}
- priv->axi_clk = devm_clk_get(&pdev->dev, "axi_clk");
+ priv->axi_clk = devm_clk_get_optional(&pdev->dev, "axi_clk");
if (IS_ERR(priv->axi_clk)) {
err = PTR_ERR(priv->axi_clk);
- if (err == -EPROBE_DEFER)
- goto err_mg_core_clk;
- priv->axi_clk = NULL;
- } else {
- err = clk_prepare_enable(priv->axi_clk);
- if (err < 0)
- goto err_mg_core_clk;
+ goto err_mg_core_clk;
}
+ err = clk_prepare_enable(priv->axi_clk);
+ if (err < 0)
+ goto err_mg_core_clk;
+
/* Get system's tclk rate */
priv->tclk = clk_get_rate(priv->pp_clk);
- } else if (device_property_read_u32(&pdev->dev, "clock-frequency",
- &priv->tclk)) {
- dev_err(&pdev->dev, "missing clock-frequency value\n");
- return -EINVAL;
+ } else {
+ err = device_property_read_u32(&pdev->dev, "clock-frequency", &priv->tclk);
+ if (err) {
+ dev_err(&pdev->dev, "missing clock-frequency value\n");
+ return err;
+ }
}
if (priv->hw_version >= MVPP22) {
@@ -7588,6 +7590,8 @@ static int mvpp2_probe(struct platform_device *pdev)
return 0;
err_port_probe:
+ fwnode_handle_put(port_fwnode);
+
i = 0;
fwnode_for_each_available_child_node(fwnode, port_fwnode) {
if (priv->port_list[i])
@@ -7596,13 +7600,10 @@ err_port_probe:
}
err_axi_clk:
clk_disable_unprepare(priv->axi_clk);
-
err_mg_core_clk:
- if (priv->hw_version >= MVPP22)
- clk_disable_unprepare(priv->mg_core_clk);
+ clk_disable_unprepare(priv->mg_core_clk);
err_mg_clk:
- if (priv->hw_version >= MVPP22)
- clk_disable_unprepare(priv->mg_clk);
+ clk_disable_unprepare(priv->mg_clk);
err_gop_clk:
clk_disable_unprepare(priv->gop_clk);
err_pp_clk:
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
index 7cc7d72d761e..93575800ca92 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
@@ -394,9 +394,6 @@ static int mvpp2_prs_tcam_first_free(struct mvpp2 *priv, unsigned char start,
if (start > end)
swap(start, end);
- if (end >= MVPP2_PRS_TCAM_SRAM_SIZE)
- end = MVPP2_PRS_TCAM_SRAM_SIZE - 1;
-
for (tid = start; tid <= end; tid++) {
if (!priv->prs_shadow[tid].valid)
return tid;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
index fac6474ad694..9169849881bf 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
@@ -86,6 +86,22 @@ bool is_lmac_valid(struct cgx *cgx, int lmac_id)
return test_bit(lmac_id, &cgx->lmac_bmap);
}
+/* Helper function to get sequential index
+ * given the enabled LMAC of a CGX
+ */
+static int get_sequence_id_of_lmac(struct cgx *cgx, int lmac_id)
+{
+ int tmp, id = 0;
+
+ for_each_set_bit(tmp, &cgx->lmac_bmap, MAX_LMAC_PER_CGX) {
+ if (tmp == lmac_id)
+ break;
+ id++;
+ }
+
+ return id;
+}
+
struct mac_ops *get_mac_ops(void *cgxd)
{
if (!cgxd)
@@ -211,37 +227,257 @@ static u64 mac2u64 (u8 *mac_addr)
return mac;
}
+static void cfg2mac(u64 cfg, u8 *mac_addr)
+{
+ int i, index = 0;
+
+ for (i = ETH_ALEN - 1; i >= 0; i--, index++)
+ mac_addr[i] = (cfg >> (8 * index)) & 0xFF;
+}
+
int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr)
{
struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
+ struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev);
struct mac_ops *mac_ops;
+ int index, id;
u64 cfg;
+ /* access mac_ops to know csr_offset */
mac_ops = cgx_dev->mac_ops;
+
/* copy 6bytes from macaddr */
/* memcpy(&cfg, mac_addr, 6); */
cfg = mac2u64 (mac_addr);
- cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (lmac_id * 0x8)),
+ id = get_sequence_id_of_lmac(cgx_dev, lmac_id);
+
+ index = id * lmac->mac_to_index_bmap.max;
+
+ cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)),
cfg | CGX_DMAC_CAM_ADDR_ENABLE | ((u64)lmac_id << 49));
cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0);
- cfg |= CGX_DMAC_CTL0_CAM_ENABLE;
+ cfg |= (CGX_DMAC_CTL0_CAM_ENABLE | CGX_DMAC_BCAST_MODE |
+ CGX_DMAC_MCAST_MODE);
cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg);
return 0;
}
+u64 cgx_read_dmac_ctrl(void *cgxd, int lmac_id)
+{
+ struct mac_ops *mac_ops;
+ struct cgx *cgx = cgxd;
+
+ if (!cgxd || !is_lmac_valid(cgxd, lmac_id))
+ return 0;
+
+ cgx = cgxd;
+ /* Get mac_ops to know csr offset */
+ mac_ops = cgx->mac_ops;
+
+ return cgx_read(cgxd, lmac_id, CGXX_CMRX_RX_DMAC_CTL0);
+}
+
+u64 cgx_read_dmac_entry(void *cgxd, int index)
+{
+ struct mac_ops *mac_ops;
+ struct cgx *cgx;
+
+ if (!cgxd)
+ return 0;
+
+ cgx = cgxd;
+ mac_ops = cgx->mac_ops;
+ return cgx_read(cgx, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 8)));
+}
+
+int cgx_lmac_addr_add(u8 cgx_id, u8 lmac_id, u8 *mac_addr)
+{
+ struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
+ struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev);
+ struct mac_ops *mac_ops;
+ int index, idx;
+ u64 cfg = 0;
+ int id;
+
+ if (!lmac)
+ return -ENODEV;
+
+ mac_ops = cgx_dev->mac_ops;
+ /* Get available index where entry is to be installed */
+ idx = rvu_alloc_rsrc(&lmac->mac_to_index_bmap);
+ if (idx < 0)
+ return idx;
+
+ id = get_sequence_id_of_lmac(cgx_dev, lmac_id);
+
+ index = id * lmac->mac_to_index_bmap.max + idx;
+
+ cfg = mac2u64 (mac_addr);
+ cfg |= CGX_DMAC_CAM_ADDR_ENABLE;
+ cfg |= ((u64)lmac_id << 49);
+ cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), cfg);
+
+ cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0);
+ cfg |= (CGX_DMAC_BCAST_MODE | CGX_DMAC_CAM_ACCEPT);
+
+ if (is_multicast_ether_addr(mac_addr)) {
+ cfg &= ~GENMASK_ULL(2, 1);
+ cfg |= CGX_DMAC_MCAST_MODE_CAM;
+ lmac->mcast_filters_count++;
+ } else if (!lmac->mcast_filters_count) {
+ cfg |= CGX_DMAC_MCAST_MODE;
+ }
+
+ cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg);
+
+ return idx;
+}
+
+int cgx_lmac_addr_reset(u8 cgx_id, u8 lmac_id)
+{
+ struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
+ struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev);
+ struct mac_ops *mac_ops;
+ u8 index = 0, id;
+ u64 cfg;
+
+ if (!lmac)
+ return -ENODEV;
+
+ mac_ops = cgx_dev->mac_ops;
+ /* Restore index 0 to its default init value as done during
+ * cgx_lmac_init
+ */
+ set_bit(0, lmac->mac_to_index_bmap.bmap);
+
+ id = get_sequence_id_of_lmac(cgx_dev, lmac_id);
+
+ index = id * lmac->mac_to_index_bmap.max + index;
+ cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), 0);
+
+ /* Reset CGXX_CMRX_RX_DMAC_CTL0 register to default state */
+ cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0);
+ cfg &= ~CGX_DMAC_CAM_ACCEPT;
+ cfg |= (CGX_DMAC_BCAST_MODE | CGX_DMAC_MCAST_MODE);
+ cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg);
+
+ return 0;
+}
+
+/* Allows caller to change macaddress associated with index
+ * in dmac filter table including index 0 reserved for
+ * interface mac address
+ */
+int cgx_lmac_addr_update(u8 cgx_id, u8 lmac_id, u8 *mac_addr, u8 index)
+{
+ struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
+ struct mac_ops *mac_ops;
+ struct lmac *lmac;
+ u64 cfg;
+ int id;
+
+ lmac = lmac_pdata(lmac_id, cgx_dev);
+ if (!lmac)
+ return -ENODEV;
+
+ mac_ops = cgx_dev->mac_ops;
+ /* Validate the index */
+ if (index >= lmac->mac_to_index_bmap.max)
+ return -EINVAL;
+
+ /* ensure index is already set */
+ if (!test_bit(index, lmac->mac_to_index_bmap.bmap))
+ return -EINVAL;
+
+ id = get_sequence_id_of_lmac(cgx_dev, lmac_id);
+
+ index = id * lmac->mac_to_index_bmap.max + index;
+
+ cfg = cgx_read(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)));
+ cfg &= ~CGX_RX_DMAC_ADR_MASK;
+ cfg |= mac2u64 (mac_addr);
+
+ cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), cfg);
+ return 0;
+}
+
+int cgx_lmac_addr_del(u8 cgx_id, u8 lmac_id, u8 index)
+{
+ struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
+ struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev);
+ struct mac_ops *mac_ops;
+ u8 mac[ETH_ALEN];
+ u64 cfg;
+ int id;
+
+ if (!lmac)
+ return -ENODEV;
+
+ mac_ops = cgx_dev->mac_ops;
+ /* Validate the index */
+ if (index >= lmac->mac_to_index_bmap.max)
+ return -EINVAL;
+
+ /* Skip deletion for reserved index i.e. index 0 */
+ if (index == 0)
+ return 0;
+
+ rvu_free_rsrc(&lmac->mac_to_index_bmap, index);
+
+ id = get_sequence_id_of_lmac(cgx_dev, lmac_id);
+
+ index = id * lmac->mac_to_index_bmap.max + index;
+
+ /* Read MAC address to check whether it is ucast or mcast */
+ cfg = cgx_read(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)));
+
+ cfg2mac(cfg, mac);
+ if (is_multicast_ether_addr(mac))
+ lmac->mcast_filters_count--;
+
+ if (!lmac->mcast_filters_count) {
+ cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0);
+ cfg &= ~GENMASK_ULL(2, 1);
+ cfg |= CGX_DMAC_MCAST_MODE;
+ cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg);
+ }
+
+ cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), 0);
+
+ return 0;
+}
+
+int cgx_lmac_addr_max_entries_get(u8 cgx_id, u8 lmac_id)
+{
+ struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
+ struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev);
+
+ if (lmac)
+ return lmac->mac_to_index_bmap.max;
+
+ return 0;
+}
+
u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id)
{
struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
+ struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev);
struct mac_ops *mac_ops;
+ int index;
u64 cfg;
+ int id;
mac_ops = cgx_dev->mac_ops;
- cfg = cgx_read(cgx_dev, 0, CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8);
+ id = get_sequence_id_of_lmac(cgx_dev, lmac_id);
+
+ index = id * lmac->mac_to_index_bmap.max;
+
+ cfg = cgx_read(cgx_dev, 0, CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8);
return cfg & CGX_RX_DMAC_ADR_MASK;
}
@@ -297,35 +533,51 @@ int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable)
void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable)
{
struct cgx *cgx = cgx_get_pdata(cgx_id);
+ struct lmac *lmac = lmac_pdata(lmac_id, cgx);
+ u16 max_dmac = lmac->mac_to_index_bmap.max;
struct mac_ops *mac_ops;
+ int index, i;
u64 cfg = 0;
+ int id;
if (!cgx)
return;
+ id = get_sequence_id_of_lmac(cgx, lmac_id);
+
mac_ops = cgx->mac_ops;
if (enable) {
/* Enable promiscuous mode on LMAC */
cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0);
- cfg &= ~(CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE);
- cfg |= CGX_DMAC_BCAST_MODE;
+ cfg &= ~CGX_DMAC_CAM_ACCEPT;
+ cfg |= (CGX_DMAC_BCAST_MODE | CGX_DMAC_MCAST_MODE);
cgx_write(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg);
- cfg = cgx_read(cgx, 0,
- (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8));
- cfg &= ~CGX_DMAC_CAM_ADDR_ENABLE;
- cgx_write(cgx, 0,
- (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8), cfg);
+ for (i = 0; i < max_dmac; i++) {
+ index = id * max_dmac + i;
+ cfg = cgx_read(cgx, 0,
+ (CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8));
+ cfg &= ~CGX_DMAC_CAM_ADDR_ENABLE;
+ cgx_write(cgx, 0,
+ (CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8), cfg);
+ }
} else {
/* Disable promiscuous mode */
cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0);
cfg |= CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE;
cgx_write(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg);
- cfg = cgx_read(cgx, 0,
- (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8));
- cfg |= CGX_DMAC_CAM_ADDR_ENABLE;
- cgx_write(cgx, 0,
- (CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8), cfg);
+ for (i = 0; i < max_dmac; i++) {
+ index = id * max_dmac + i;
+ cfg = cgx_read(cgx, 0,
+ (CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8));
+ if ((cfg & CGX_RX_DMAC_ADR_MASK) != 0) {
+ cfg |= CGX_DMAC_CAM_ADDR_ENABLE;
+ cgx_write(cgx, 0,
+ (CGXX_CMRX_RX_DMAC_CAM0 +
+ index * 0x8),
+ cfg);
+ }
+ }
}
}
@@ -1234,6 +1486,15 @@ static int cgx_lmac_init(struct cgx *cgx)
}
lmac->cgx = cgx;
+ lmac->mac_to_index_bmap.max =
+ MAX_DMAC_ENTRIES_PER_CGX / cgx->lmac_count;
+ err = rvu_alloc_bitmap(&lmac->mac_to_index_bmap);
+ if (err)
+ return err;
+
+ /* Reserve first entry for default MAC address */
+ set_bit(0, lmac->mac_to_index_bmap.bmap);
+
init_waitqueue_head(&lmac->wq_cmd_cmplt);
mutex_init(&lmac->cmd_lock);
spin_lock_init(&lmac->event_cb_lock);
@@ -1274,6 +1535,7 @@ static int cgx_lmac_exit(struct cgx *cgx)
continue;
cgx->mac_ops->mac_pause_frm_config(cgx, lmac->lmac_id, false);
cgx_configure_interrupt(cgx, lmac, lmac->lmac_id, true);
+ kfree(lmac->mac_to_index_bmap.bmap);
kfree(lmac->name);
kfree(lmac);
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
index 12521262164a..237ba2b56210 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
@@ -23,6 +23,7 @@
#define CGX_ID_MASK 0x7
#define MAX_LMAC_PER_CGX 4
+#define MAX_DMAC_ENTRIES_PER_CGX 32
#define CGX_FIFO_LEN 65536 /* 64K for both Rx & Tx */
#define CGX_OFFSET(x) ((x) * MAX_LMAC_PER_CGX)
@@ -46,10 +47,12 @@
#define CGXX_CMRX_RX_DMAC_CTL0 (0x1F8 + mac_ops->csr_offset)
#define CGX_DMAC_CTL0_CAM_ENABLE BIT_ULL(3)
#define CGX_DMAC_CAM_ACCEPT BIT_ULL(3)
+#define CGX_DMAC_MCAST_MODE_CAM BIT_ULL(2)
#define CGX_DMAC_MCAST_MODE BIT_ULL(1)
#define CGX_DMAC_BCAST_MODE BIT_ULL(0)
#define CGXX_CMRX_RX_DMAC_CAM0 (0x200 + mac_ops->csr_offset)
#define CGX_DMAC_CAM_ADDR_ENABLE BIT_ULL(48)
+#define CGX_DMAC_CAM_ENTRY_LMACID GENMASK_ULL(50, 49)
#define CGXX_CMRX_RX_DMAC_CAM1 0x400
#define CGX_RX_DMAC_ADR_MASK GENMASK_ULL(47, 0)
#define CGXX_CMRX_TX_STAT0 0x700
@@ -139,7 +142,11 @@ int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat);
int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable);
int cgx_lmac_tx_enable(void *cgxd, int lmac_id, bool enable);
int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr);
+int cgx_lmac_addr_reset(u8 cgx_id, u8 lmac_id);
u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id);
+int cgx_lmac_addr_add(u8 cgx_id, u8 lmac_id, u8 *mac_addr);
+int cgx_lmac_addr_del(u8 cgx_id, u8 lmac_id, u8 index);
+int cgx_lmac_addr_max_entries_get(u8 cgx_id, u8 lmac_id);
void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable);
void cgx_lmac_enadis_rx_pause_fwding(void *cgxd, int lmac_id, bool enable);
int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable);
@@ -165,4 +172,7 @@ u8 cgx_get_lmacid(void *cgxd, u8 lmac_index);
unsigned long cgx_get_lmac_bmap(void *cgxd);
void cgx_lmac_write(int cgx_id, int lmac_id, u64 offset, u64 val);
u64 cgx_lmac_read(int cgx_id, int lmac_id, u64 offset);
+int cgx_lmac_addr_update(u8 cgx_id, u8 lmac_id, u8 *mac_addr, u8 index);
+u64 cgx_read_dmac_ctrl(void *cgxd, int lmac_id);
+u64 cgx_read_dmac_entry(void *cgxd, int index);
#endif /* CGX_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h
index e66109367487..47f5ed006a93 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/common.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h
@@ -197,6 +197,11 @@ enum nix_scheduler {
#define SDP_CHANNELS 256
+/* The mask is to extract lower 10-bits of channel number
+ * which CPT will pass to X2P.
+ */
+#define NIX_CHAN_CPT_X2P_MASK (0x3ffull)
+
/* NIX LSO format indices.
* As of now TSO is the only one using, so statically assigning indices.
*/
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/lmac_common.h b/drivers/net/ethernet/marvell/octeontx2/af/lmac_common.h
index 45706fd87120..a8b7b1c7a1d5 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/lmac_common.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/lmac_common.h
@@ -10,17 +10,19 @@
#include "rvu.h"
#include "cgx.h"
/**
- * struct lmac
+ * struct lmac - per lmac locks and properties
* @wq_cmd_cmplt: waitq to keep the process blocked until cmd completion
* @cmd_lock: Lock to serialize the command interface
* @resp: command response
* @link_info: link related information
+ * @mac_to_index_bmap: Mac address to CGX table index mapping
* @event_cb: callback for linkchange events
* @event_cb_lock: lock for serializing callback with unregister
- * @cmd_pend: flag set before new command is started
- * flag cleared after command response is received
* @cgx: parent cgx port
+ * @mcast_filters_count: Number of multicast filters installed
* @lmac_id: lmac port id
+ * @cmd_pend: flag set before new command is started
+ * flag cleared after command response is received
* @name: lmac port name
*/
struct lmac {
@@ -29,12 +31,14 @@ struct lmac {
struct mutex cmd_lock;
u64 resp;
struct cgx_link_user_info link_info;
+ struct rsrc_bmap mac_to_index_bmap;
struct cgx_event_cb event_cb;
/* lock for serializing callback with unregister */
spinlock_t event_cb_lock;
- bool cmd_pend;
struct cgx *cgx;
+ u8 mcast_filters_count;
u8 lmac_id;
+ bool cmd_pend;
char *name;
};
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index cedb2616c509..f5ec39de026a 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -134,6 +134,9 @@ M(MSIX_OFFSET, 0x005, msix_offset, msg_req, msix_offset_rsp) \
M(VF_FLR, 0x006, vf_flr, msg_req, msg_rsp) \
M(PTP_OP, 0x007, ptp_op, ptp_req, ptp_rsp) \
M(GET_HW_CAP, 0x008, get_hw_cap, msg_req, get_hw_cap_rsp) \
+M(LMTST_TBL_SETUP, 0x00a, lmtst_tbl_setup, lmtst_tbl_setup_req, \
+ msg_rsp) \
+M(SET_VF_PERM, 0x00b, set_vf_perm, set_vf_perm, msg_rsp) \
/* CGX mbox IDs (range 0x200 - 0x3FF) */ \
M(CGX_START_RXTX, 0x200, cgx_start_rxtx, msg_req, msg_rsp) \
M(CGX_STOP_RXTX, 0x201, cgx_stop_rxtx, msg_req, msg_rsp) \
@@ -162,7 +165,15 @@ M(CGX_SET_LINK_MODE, 0x214, cgx_set_link_mode, cgx_set_link_mode_req,\
M(CGX_FEATURES_GET, 0x215, cgx_features_get, msg_req, \
cgx_features_info_msg) \
M(RPM_STATS, 0x216, rpm_stats, msg_req, rpm_stats_rsp) \
- /* NPA mbox IDs (range 0x400 - 0x5FF) */ \
+M(CGX_MAC_ADDR_ADD, 0x217, cgx_mac_addr_add, cgx_mac_addr_add_req, \
+ cgx_mac_addr_add_rsp) \
+M(CGX_MAC_ADDR_DEL, 0x218, cgx_mac_addr_del, cgx_mac_addr_del_req, \
+ msg_rsp) \
+M(CGX_MAC_MAX_ENTRIES_GET, 0x219, cgx_mac_max_entries_get, msg_req, \
+ cgx_max_dmac_entries_get_rsp) \
+M(CGX_MAC_ADDR_RESET, 0x21A, cgx_mac_addr_reset, msg_req, msg_rsp) \
+M(CGX_MAC_ADDR_UPDATE, 0x21B, cgx_mac_addr_update, cgx_mac_addr_update_req, \
+ msg_rsp) \
/* NPA mbox IDs (range 0x400 - 0x5FF) */ \
M(NPA_LF_ALLOC, 0x400, npa_lf_alloc, \
npa_lf_alloc_req, npa_lf_alloc_rsp) \
@@ -259,7 +270,11 @@ M(NIX_BP_DISABLE, 0x8017, nix_bp_disable, nix_bp_cfg_req, msg_rsp) \
M(NIX_GET_MAC_ADDR, 0x8018, nix_get_mac_addr, msg_req, nix_get_mac_addr_rsp) \
M(NIX_CN10K_AQ_ENQ, 0x8019, nix_cn10k_aq_enq, nix_cn10k_aq_enq_req, \
nix_cn10k_aq_enq_rsp) \
-M(NIX_GET_HW_INFO, 0x801a, nix_get_hw_info, msg_req, nix_hw_info)
+M(NIX_GET_HW_INFO, 0x801c, nix_get_hw_info, msg_req, nix_hw_info) \
+M(NIX_BANDPROF_ALLOC, 0x801d, nix_bandprof_alloc, nix_bandprof_alloc_req, \
+ nix_bandprof_alloc_rsp) \
+M(NIX_BANDPROF_FREE, 0x801e, nix_bandprof_free, nix_bandprof_free_req, \
+ msg_rsp)
/* Messages initiated by AF (range 0xC00 - 0xDFF) */
#define MBOX_UP_CGX_MESSAGES \
@@ -396,6 +411,38 @@ struct cgx_mac_addr_set_or_get {
u8 mac_addr[ETH_ALEN];
};
+/* Structure for requesting the operation to
+ * add DMAC filter entry into CGX interface
+ */
+struct cgx_mac_addr_add_req {
+ struct mbox_msghdr hdr;
+ u8 mac_addr[ETH_ALEN];
+};
+
+/* Structure for response against the operation to
+ * add DMAC filter entry into CGX interface
+ */
+struct cgx_mac_addr_add_rsp {
+ struct mbox_msghdr hdr;
+ u8 index;
+};
+
+/* Structure for requesting the operation to
+ * delete DMAC filter entry from CGX interface
+ */
+struct cgx_mac_addr_del_req {
+ struct mbox_msghdr hdr;
+ u8 index;
+};
+
+/* Structure for response against the operation to
+ * get maximum supported DMAC filter entries
+ */
+struct cgx_max_dmac_entries_get_rsp {
+ struct mbox_msghdr hdr;
+ u8 max_dmac_filters;
+};
+
struct cgx_link_user_info {
uint64_t link_up:1;
uint64_t full_duplex:1;
@@ -494,6 +541,12 @@ struct cgx_set_link_mode_rsp {
int status;
};
+struct cgx_mac_addr_update_req {
+ struct mbox_msghdr hdr;
+ u8 mac_addr[ETH_ALEN];
+ u8 index;
+};
+
#define RVU_LMAC_FEAT_FC BIT_ULL(0) /* pause frames */
#define RVU_LMAC_FEAT_PTP BIT_ULL(1) /* precision time protocol */
#define RVU_MAC_VERSION BIT_ULL(2)
@@ -611,7 +664,12 @@ enum nix_af_status {
NIX_AF_INVAL_SSO_PF_FUNC = -420,
NIX_AF_ERR_TX_VTAG_NOSPC = -421,
NIX_AF_ERR_RX_VTAG_INUSE = -422,
- NIX_AF_ERR_NPC_KEY_NOT_SUPP = -423,
+ NIX_AF_ERR_PTP_CONFIG_FAIL = -423,
+ NIX_AF_ERR_NPC_KEY_NOT_SUPP = -424,
+ NIX_AF_ERR_INVALID_NIXBLK = -425,
+ NIX_AF_ERR_INVALID_BANDPROF = -426,
+ NIX_AF_ERR_IPOLICER_NOTSUPP = -427,
+ NIX_AF_ERR_BANDPROF_INVAL_REQ = -428,
};
/* For NIX RX vtag action */
@@ -680,6 +738,7 @@ struct nix_cn10k_aq_enq_req {
struct nix_cq_ctx_s cq;
struct nix_rsse_s rss;
struct nix_rx_mce_s mce;
+ struct nix_bandprof_s prof;
};
union {
struct nix_cn10k_rq_ctx_s rq_mask;
@@ -687,6 +746,7 @@ struct nix_cn10k_aq_enq_req {
struct nix_cq_ctx_s cq_mask;
struct nix_rsse_s rss_mask;
struct nix_rx_mce_s mce_mask;
+ struct nix_bandprof_s prof_mask;
};
};
@@ -698,6 +758,7 @@ struct nix_cn10k_aq_enq_rsp {
struct nix_cq_ctx_s cq;
struct nix_rsse_s rss;
struct nix_rx_mce_s mce;
+ struct nix_bandprof_s prof;
};
};
@@ -713,6 +774,7 @@ struct nix_aq_enq_req {
struct nix_cq_ctx_s cq;
struct nix_rsse_s rss;
struct nix_rx_mce_s mce;
+ u64 prof;
};
union {
struct nix_rq_ctx_s rq_mask;
@@ -720,6 +782,7 @@ struct nix_aq_enq_req {
struct nix_cq_ctx_s cq_mask;
struct nix_rsse_s rss_mask;
struct nix_rx_mce_s mce_mask;
+ u64 prof_mask;
};
};
@@ -731,6 +794,7 @@ struct nix_aq_enq_rsp {
struct nix_cq_ctx_s cq;
struct nix_rsse_s rss;
struct nix_rx_mce_s mce;
+ struct nix_bandprof_s prof;
};
};
@@ -913,6 +977,7 @@ struct nix_rx_mode {
#define NIX_RX_MODE_UCAST BIT(0)
#define NIX_RX_MODE_PROMISC BIT(1)
#define NIX_RX_MODE_ALLMULTI BIT(2)
+#define NIX_RX_MODE_USE_MCE BIT(3)
u16 mode;
};
@@ -971,6 +1036,31 @@ struct nix_hw_info {
u16 min_mtu;
};
+struct nix_bandprof_alloc_req {
+ struct mbox_msghdr hdr;
+ /* Count of profiles needed per layer */
+ u16 prof_count[BAND_PROF_NUM_LAYERS];
+};
+
+struct nix_bandprof_alloc_rsp {
+ struct mbox_msghdr hdr;
+ u16 prof_count[BAND_PROF_NUM_LAYERS];
+
+ /* There is no need to allocate morethan 1 bandwidth profile
+ * per RQ of a PF_FUNC's NIXLF. So limit the maximum
+ * profiles to 64 per PF_FUNC.
+ */
+#define MAX_BANDPROF_PER_PFFUNC 64
+ u16 prof_idx[BAND_PROF_NUM_LAYERS][MAX_BANDPROF_PER_PFFUNC];
+};
+
+struct nix_bandprof_free_req {
+ struct mbox_msghdr hdr;
+ u8 free_all;
+ u16 prof_count[BAND_PROF_NUM_LAYERS];
+ u16 prof_idx[BAND_PROF_NUM_LAYERS][MAX_BANDPROF_PER_PFFUNC];
+};
+
/* NPC mbox message structs */
#define NPC_MCAM_ENTRY_INVALID 0xFFFF
@@ -1228,6 +1318,22 @@ struct ptp_rsp {
u64 clk;
};
+struct set_vf_perm {
+ struct mbox_msghdr hdr;
+ u16 vf;
+#define RESET_VF_PERM BIT_ULL(0)
+#define VF_TRUSTED BIT_ULL(1)
+ u64 flags;
+};
+
+struct lmtst_tbl_setup_req {
+ struct mbox_msghdr hdr;
+ u16 base_pcifunc;
+ u8 use_local_lmt_region;
+ u64 lmt_iova;
+ u64 rsvd[4];
+};
+
/* CPT mailbox error codes
* Range 901 - 1000.
*/
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/npc.h
index 1e012e787260..19bad9a59c8f 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/npc.h
@@ -33,6 +33,10 @@ enum npc_kpu_la_ltype {
NPC_LT_LA_IH_2_ETHER,
NPC_LT_LA_HIGIG2_ETHER,
NPC_LT_LA_IH_NIX_HIGIG2_ETHER,
+ NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ NPC_LT_LA_CH_LEN_90B_ETHER,
+ NPC_LT_LA_CPT_HDR,
+ NPC_LT_LA_CUSTOM_L2_24B_ETHER,
NPC_LT_LA_CUSTOM0 = 0xE,
NPC_LT_LA_CUSTOM1 = 0xF,
};
@@ -42,7 +46,7 @@ enum npc_kpu_lb_ltype {
NPC_LT_LB_CTAG,
NPC_LT_LB_STAG_QINQ,
NPC_LT_LB_BTAG,
- NPC_LT_LB_ITAG,
+ NPC_LT_LB_PPPOE,
NPC_LT_LB_DSA,
NPC_LT_LB_DSA_VLAN,
NPC_LT_LB_EDSA,
@@ -50,6 +54,7 @@ enum npc_kpu_lb_ltype {
NPC_LT_LB_EXDSA,
NPC_LT_LB_EXDSA_VLAN,
NPC_LT_LB_FDSA,
+ NPC_LT_LB_VLAN_EXDSA,
NPC_LT_LB_CUSTOM0 = 0xE,
NPC_LT_LB_CUSTOM1 = 0xF,
};
@@ -65,6 +70,7 @@ enum npc_kpu_lc_ltype {
NPC_LT_LC_NSH,
NPC_LT_LC_PTP,
NPC_LT_LC_FCOE,
+ NPC_LT_LC_NGIO,
NPC_LT_LC_CUSTOM0 = 0xE,
NPC_LT_LC_CUSTOM1 = 0xF,
};
@@ -146,7 +152,14 @@ enum npc_kpu_lh_ltype {
* Ethernet interfaces, LBK interfaces, etc.
*/
enum npc_pkind_type {
- NPC_TX_DEF_PKIND = 63ULL, /* NIX-TX PKIND */
+ NPC_RX_VLAN_EXDSA_PKIND = 56ULL,
+ NPC_RX_CHLEN24B_PKIND = 57ULL,
+ NPC_RX_CPT_HDR_PKIND,
+ NPC_RX_CHLEN90B_PKIND,
+ NPC_TX_HIGIG_PKIND,
+ NPC_RX_HIGIG_PKIND,
+ NPC_RX_EDSA_PKIND,
+ NPC_TX_DEF_PKIND, /* NIX-TX PKIND */
};
/* list of known and supported fields in packet header and
@@ -213,7 +226,7 @@ struct npc_kpu_profile_cam {
u16 dp1_mask;
u16 dp2;
u16 dp2_mask;
-};
+} __packed;
struct npc_kpu_profile_action {
u8 errlev;
@@ -233,13 +246,13 @@ struct npc_kpu_profile_action {
u8 mask;
u8 right;
u8 shift;
-};
+} __packed;
struct npc_kpu_profile {
int cam_entries;
int action_entries;
- const struct npc_kpu_profile_cam *cam;
- const struct npc_kpu_profile_action *action;
+ struct npc_kpu_profile_cam *cam;
+ struct npc_kpu_profile_action *action;
};
/* NPC KPU register formats */
@@ -425,7 +438,19 @@ struct nix_tx_action {
/* NPC MCAM reserved entry index per nixlf */
#define NIXLF_UCAST_ENTRY 0
#define NIXLF_BCAST_ENTRY 1
-#define NIXLF_PROMISC_ENTRY 2
+#define NIXLF_ALLMULTI_ENTRY 2
+#define NIXLF_PROMISC_ENTRY 3
+
+struct npc_coalesced_kpu_prfl {
+#define NPC_SIGN 0x00666f727063706e
+#define NPC_PRFL_NAME "npc_prfls_array"
+#define NPC_NAME_LEN 32
+ __le64 signature; /* "npcprof\0" (8 bytes/ASCII characters) */
+ u8 name[NPC_NAME_LEN]; /* KPU Profile name */
+ u64 version; /* KPU firmware/profile version */
+ u8 num_prfl; /* No of NPC profiles. */
+ u16 prfl_sz[0];
+};
struct npc_mcam_kex {
/* MKEX Profle Header */
@@ -445,6 +470,15 @@ struct npc_mcam_kex {
u64 intf_ld_flags[NPC_MAX_INTF][NPC_MAX_LD][NPC_MAX_LFL];
} __packed;
+struct npc_kpu_fwdata {
+ int entries;
+ /* What follows is:
+ * struct npc_kpu_profile_cam[entries];
+ * struct npc_kpu_profile_action[entries];
+ */
+ u8 data[0];
+} __packed;
+
struct npc_lt_def {
u8 ltype_mask;
u8 ltype_match;
@@ -459,6 +493,29 @@ struct npc_lt_def_ipsec {
u8 spi_nz;
};
+struct npc_lt_def_apad {
+ u8 ltype_mask;
+ u8 ltype_match;
+ u8 lid;
+ u8 valid;
+} __packed;
+
+struct npc_lt_def_color {
+ u8 ltype_mask;
+ u8 ltype_match;
+ u8 lid;
+ u8 noffset;
+ u8 offset;
+} __packed;
+
+struct npc_lt_def_et {
+ u8 ltype_mask;
+ u8 ltype_match;
+ u8 lid;
+ u8 valid;
+ u8 offset;
+} __packed;
+
struct npc_lt_def_cfg {
struct npc_lt_def rx_ol2;
struct npc_lt_def rx_oip4;
@@ -476,7 +533,41 @@ struct npc_lt_def_cfg {
struct npc_lt_def pck_oip4;
struct npc_lt_def pck_oip6;
struct npc_lt_def pck_iip4;
-};
+ struct npc_lt_def_apad rx_apad0;
+ struct npc_lt_def_apad rx_apad1;
+ struct npc_lt_def_color ovlan;
+ struct npc_lt_def_color ivlan;
+ struct npc_lt_def_color rx_gen0_color;
+ struct npc_lt_def_color rx_gen1_color;
+ struct npc_lt_def_et rx_et[2];
+} __packed;
+
+/* Loadable KPU profile firmware data */
+struct npc_kpu_profile_fwdata {
+#define KPU_SIGN 0x00666f727075706b
+#define KPU_NAME_LEN 32
+/** Maximum number of custom KPU entries supported by the built-in profile. */
+#define KPU_MAX_CST_ENT 2
+ /* KPU Profle Header */
+ __le64 signature; /* "kpuprof\0" (8 bytes/ASCII characters) */
+ u8 name[KPU_NAME_LEN]; /* KPU Profile name */
+ __le64 version; /* KPU profile version */
+ u8 kpus;
+ u8 reserved[7];
+
+ /* Default MKEX profile to be used with this KPU profile. May be
+ * overridden with mkex_profile module parameter. Format is same as for
+ * the MKEX profile to streamline processing.
+ */
+ struct npc_mcam_kex mkex;
+ /* LTYPE values for specific HW offloaded protocols. */
+ struct npc_lt_def_cfg lt_def;
+ /* Dynamically sized data:
+ * Custom KPU CAM and ACTION configuration entries.
+ * struct npc_kpu_fwdata kpu[kpus];
+ */
+ u8 data[0];
+} __packed;
struct rvu_npc_mcam_rule {
struct flow_msg packet;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h b/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h
index 5c372d2c24a1..fee655cc7523 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h
@@ -11,7 +11,10 @@
#ifndef NPC_PROFILE_H
#define NPC_PROFILE_H
-#define NPC_KPU_PROFILE_VER 0x0000000100050000
+#define NPC_KPU_PROFILE_VER 0x0000000100060000
+#define NPC_KPU_VER_MAJ(ver) ((u16)(((ver) >> 32) & 0xFFFF))
+#define NPC_KPU_VER_MIN(ver) ((u16)(((ver) >> 16) & 0xFFFF))
+#define NPC_KPU_VER_PATCH(ver) ((u16)((ver) & 0xFFFF))
#define NPC_IH_W 0x8000
#define NPC_IH_UTAG 0x2000
@@ -20,6 +23,7 @@
#define NPC_ETYPE_IP6 0x86dd
#define NPC_ETYPE_ARP 0x0806
#define NPC_ETYPE_RARP 0x8035
+#define NPC_ETYPE_NGIO 0x8842
#define NPC_ETYPE_MPLSU 0x8847
#define NPC_ETYPE_MPLSM 0x8848
#define NPC_ETYPE_ETAG 0x893f
@@ -33,6 +37,10 @@
#define NPC_ETYPE_PPP 0x880b
#define NPC_ETYPE_NSH 0x894f
#define NPC_ETYPE_DSA 0xdada
+#define NPC_ETYPE_PPPOE 0x8864
+
+#define NPC_PPP_IP 0x0021
+#define NPC_PPP_IP6 0x0057
#define NPC_IPNH_HOP 0
#define NPC_IPNH_ICMP 1
@@ -142,14 +150,15 @@
#define NPC_DSA_EDSA 0x8000
#define NPC_DSA_FDSA 0xc000
-#define NPC_KEXOF_DMAC 8
-#define MKEX_SIGN 0x19bbfdbd15f /* strtoull of "mkexprof" with base:36 */
+#define NPC_KEXOF_DMAC 9
+#define MKEX_SIGN 0x19bbfdbd15f
#define KEX_LD_CFG(bytesm1, hdr_ofs, ena, flags_ena, key_ofs) \
(((bytesm1) << 16) | ((hdr_ofs) << 8) | ((ena) << 7) | \
((flags_ena) << 6) | ((key_ofs) & 0x3F))
/* Rx parse key extract nibble enable */
#define NPC_PARSE_NIBBLE_INTF_RX (NPC_PARSE_NIBBLE_CHAN | \
+ NPC_PARSE_NIBBLE_ERRCODE | \
NPC_PARSE_NIBBLE_LA_LTYPE | \
NPC_PARSE_NIBBLE_LB_LTYPE | \
NPC_PARSE_NIBBLE_LC_LTYPE | \
@@ -170,25 +179,31 @@ enum npc_kpu_parser_state {
NPC_S_KPU1_EXDSA,
NPC_S_KPU1_HIGIG2,
NPC_S_KPU1_IH_NIX_HIGIG2,
+ NPC_S_KPU1_CUSTOM_L2_90B,
+ NPC_S_KPU1_CPT_HDR,
+ NPC_S_KPU1_CUSTOM_L2_24B,
+ NPC_S_KPU1_VLAN_EXDSA,
NPC_S_KPU2_CTAG,
NPC_S_KPU2_CTAG2,
NPC_S_KPU2_SBTAG,
NPC_S_KPU2_QINQ,
NPC_S_KPU2_ETAG,
- NPC_S_KPU2_ITAG,
NPC_S_KPU2_PREHEADER,
NPC_S_KPU2_EXDSA,
+ NPC_S_KPU2_NGIO,
NPC_S_KPU3_CTAG,
NPC_S_KPU3_STAG,
NPC_S_KPU3_QINQ,
- NPC_S_KPU3_ITAG,
NPC_S_KPU3_CTAG_C,
NPC_S_KPU3_STAG_C,
NPC_S_KPU3_QINQ_C,
NPC_S_KPU3_DSA,
+ NPC_S_KPU3_VLAN_EXDSA,
NPC_S_KPU4_MPLS,
NPC_S_KPU4_NSH,
NPC_S_KPU4_FDSA,
+ NPC_S_KPU4_VLAN_EXDSA,
+ NPC_S_KPU4_PPPOE,
NPC_S_KPU5_IP,
NPC_S_KPU5_IP6,
NPC_S_KPU5_ARP,
@@ -198,13 +213,19 @@ enum npc_kpu_parser_state {
NPC_S_KPU5_MPLS,
NPC_S_KPU5_MPLS_PL,
NPC_S_KPU5_NSH,
+ NPC_S_KPU5_CPT_IP,
+ NPC_S_KPU5_CPT_IP6,
NPC_S_KPU6_IP6_EXT,
NPC_S_KPU6_IP6_HOP_DEST,
NPC_S_KPU6_IP6_ROUT,
NPC_S_KPU6_IP6_FRAG,
+ NPC_S_KPU6_IP6_CPT_FRAG,
+ NPC_S_KPU6_IP6_CPT_HOP_DEST,
+ NPC_S_KPU6_IP6_CPT_ROUT,
NPC_S_KPU7_IP6_EXT,
NPC_S_KPU7_IP6_ROUT,
NPC_S_KPU7_IP6_FRAG,
+ NPC_S_KPU7_CPT_IP6_FRAG,
NPC_S_KPU8_TCP,
NPC_S_KPU8_UDP,
NPC_S_KPU8_SCTP,
@@ -265,7 +286,6 @@ enum npc_kpu_la_lflag {
NPC_F_LA_L_UNK_ETYPE = 1,
NPC_F_LA_L_WITH_VLAN,
NPC_F_LA_L_WITH_ETAG,
- NPC_F_LA_L_WITH_ITAG,
NPC_F_LA_L_WITH_MPLS,
NPC_F_LA_L_WITH_NSH,
};
@@ -442,7 +462,28 @@ enum NPC_ERRLEV_E {
NPC_ERRLEV_ENUM_LAST = 16,
};
-static const struct npc_kpu_profile_action ikpu_action_entries[] = {
+#define NPC_KPU_NOP_CAM \
+ { \
+ NPC_S_NA, 0xff, \
+ 0x0000, \
+ 0x0000, \
+ 0x0000, \
+ 0x0000, \
+ 0x0000, \
+ 0x0000, \
+ }
+
+#define NPC_KPU_NOP_ACTION \
+ { \
+ NPC_ERRLEV_RE, NPC_EC_NOERR, \
+ 0, 0, 0, 0, 0, \
+ NPC_S_NA, 0, 0, \
+ NPC_LID_LA, NPC_LT_NA, \
+ 0, \
+ 0, 0, 0, 0, \
+ }
+
+static struct npc_kpu_profile_action ikpu_action_entries[] = {
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
12, 16, 20, 0, 0,
@@ -950,7 +991,7 @@ static const struct npc_kpu_profile_action ikpu_action_entries[] = {
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
12, 16, 20, 0, 0,
- NPC_S_KPU1_ETHER, 0, 0,
+ NPC_S_KPU1_VLAN_EXDSA, 0, 0,
NPC_LID_LA, NPC_LT_NA,
0,
0, 0, 0, 0,
@@ -958,8 +999,8 @@ static const struct npc_kpu_profile_action ikpu_action_entries[] = {
},
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
- 12, 16, 20, 0, 0,
- NPC_S_KPU1_ETHER, 0, 0,
+ 36, 40, 44, 0, 0,
+ NPC_S_KPU1_CUSTOM_L2_24B, 0, 0,
NPC_LID_LA, NPC_LT_NA,
0,
0, 0, 0, 0,
@@ -967,8 +1008,8 @@ static const struct npc_kpu_profile_action ikpu_action_entries[] = {
},
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
- 12, 16, 20, 0, 0,
- NPC_S_KPU1_ETHER, 0, 0,
+ 40, 54, 58, 0, 0,
+ NPC_S_KPU1_CPT_HDR, 0, 0,
NPC_LID_LA, NPC_LT_NA,
0,
0, 0, 0, 0,
@@ -976,8 +1017,8 @@ static const struct npc_kpu_profile_action ikpu_action_entries[] = {
},
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
- 12, 16, 20, 0, 0,
- NPC_S_KPU1_ETHER, 0, 0,
+ 102, 106, 110, 0, 0,
+ NPC_S_KPU1_CUSTOM_L2_90B, 0, 0,
NPC_LID_LA, NPC_LT_NA,
0,
0, 0, 0, 0,
@@ -1021,7 +1062,9 @@ static const struct npc_kpu_profile_action ikpu_action_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu1_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU1_ETHER, 0xff,
NPC_ETYPE_IP,
@@ -1080,6 +1123,15 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
NPC_S_KPU1_ETHER, 0xff,
NPC_ETYPE_CTAG,
0xffff,
+ NPC_ETYPE_NGIO,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_ETHER, 0xff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
NPC_ETYPE_CTAG,
0xffff,
0x0000,
@@ -1123,7 +1175,7 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
},
{
NPC_S_KPU1_ETHER, 0xff,
- NPC_ETYPE_ITAG,
+ NPC_ETYPE_MPLSU,
0xffff,
0x0000,
0x0000,
@@ -1132,7 +1184,7 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
},
{
NPC_S_KPU1_ETHER, 0xff,
- NPC_ETYPE_MPLSU,
+ NPC_ETYPE_MPLSM,
0xffff,
0x0000,
0x0000,
@@ -1141,7 +1193,7 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
},
{
NPC_S_KPU1_ETHER, 0xff,
- NPC_ETYPE_MPLSM,
+ NPC_ETYPE_NSH,
0xffff,
0x0000,
0x0000,
@@ -1150,7 +1202,7 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
},
{
NPC_S_KPU1_ETHER, 0xff,
- NPC_ETYPE_NSH,
+ NPC_ETYPE_DSA,
0xffff,
0x0000,
0x0000,
@@ -1159,7 +1211,7 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
},
{
NPC_S_KPU1_ETHER, 0xff,
- NPC_ETYPE_DSA,
+ NPC_ETYPE_PPPOE,
0xffff,
0x0000,
0x0000,
@@ -1294,15 +1346,6 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
},
{
NPC_S_KPU1_IH_NIX, 0xff,
- NPC_ETYPE_ITAG,
- 0xffff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU1_IH_NIX, 0xff,
NPC_ETYPE_MPLSU,
0xffff,
0x0000,
@@ -1339,8 +1382,8 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
},
{
NPC_S_KPU1_IH, 0xff,
- NPC_IH_W|NPC_IH_UTAG,
- NPC_IH_W|NPC_IH_UTAG,
+ NPC_IH_W | NPC_IH_UTAG,
+ NPC_IH_W | NPC_IH_UTAG,
0x0000,
0x0000,
0x0000,
@@ -1349,7 +1392,7 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
{
NPC_S_KPU1_IH, 0xff,
NPC_IH_W,
- NPC_IH_W|NPC_IH_UTAG,
+ NPC_IH_W | NPC_IH_UTAG,
0x0000,
0x0000,
0x0000,
@@ -1358,7 +1401,7 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
{
NPC_S_KPU1_IH, 0xff,
0x0000,
- NPC_IH_W|NPC_IH_UTAG,
+ NPC_IH_W | NPC_IH_UTAG,
0x0000,
0x0000,
0x0000,
@@ -1501,15 +1544,6 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
},
{
NPC_S_KPU1_HIGIG2, 0xff,
- NPC_ETYPE_ITAG,
- 0xffff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU1_HIGIG2, 0xff,
NPC_ETYPE_MPLSU,
0xffff,
0x0000,
@@ -1645,7 +1679,7 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
},
{
NPC_S_KPU1_IH_NIX_HIGIG2, 0xff,
- NPC_ETYPE_ITAG,
+ NPC_ETYPE_MPLSU,
0xffff,
0x0000,
0x0000,
@@ -1654,7 +1688,7 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
},
{
NPC_S_KPU1_IH_NIX_HIGIG2, 0xff,
- NPC_ETYPE_MPLSU,
+ NPC_ETYPE_MPLSM,
0xffff,
0x0000,
0x0000,
@@ -1663,7 +1697,7 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
},
{
NPC_S_KPU1_IH_NIX_HIGIG2, 0xff,
- NPC_ETYPE_MPLSM,
+ NPC_ETYPE_NSH,
0xffff,
0x0000,
0x0000,
@@ -1672,6 +1706,132 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
},
{
NPC_S_KPU1_IH_NIX_HIGIG2, 0xff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
+ NPC_ETYPE_IP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
+ NPC_ETYPE_IP6,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
+ NPC_ETYPE_ARP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
+ NPC_ETYPE_RARP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
+ NPC_ETYPE_PTP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
+ NPC_ETYPE_FCOE,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
+ NPC_ETYPE_SBTAG,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
+ NPC_ETYPE_QINQ,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
+ NPC_ETYPE_ETAG,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
+ NPC_ETYPE_MPLSU,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
+ NPC_ETYPE_MPLSM,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
NPC_ETYPE_NSH,
0xffff,
0x0000,
@@ -1680,7 +1840,88 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
0x0000,
},
{
- NPC_S_KPU1_IH_NIX_HIGIG2, 0xff,
+ NPC_S_KPU1_CUSTOM_L2_90B, 0xff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CPT_HDR, 0xff,
+ 0x0000,
+ 0xffff,
+ NPC_ETYPE_IP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CPT_HDR, 0xff,
+ 0x0000,
+ 0xffff,
+ NPC_ETYPE_IP6,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CPT_HDR, 0xff,
+ 0x0000,
+ 0xffff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CPT_HDR, 0xff,
+ 0x0000,
+ 0xffff,
+ NPC_ETYPE_QINQ,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CPT_HDR, 0xff,
+ 0x0000,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ NPC_ETYPE_IP,
+ 0xffff,
+ },
+ {
+ NPC_S_KPU1_CPT_HDR, 0xff,
+ 0x0000,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ NPC_ETYPE_IP6,
+ 0xffff,
+ },
+ {
+ NPC_S_KPU1_CPT_HDR, 0xff,
+ 0x0000,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ },
+ {
+ NPC_S_KPU1_CPT_HDR, 0xff,
+ 0x0000,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ NPC_ETYPE_QINQ,
+ 0xffff,
+ },
+ {
+ NPC_S_KPU1_CPT_HDR, 0xff,
0x0000,
0x0000,
0x0000,
@@ -1689,6 +1930,150 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
0x0000,
},
{
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ NPC_ETYPE_IP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ NPC_ETYPE_IP6,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ NPC_ETYPE_ARP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ NPC_ETYPE_RARP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ NPC_ETYPE_PTP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ NPC_ETYPE_FCOE,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ NPC_ETYPE_SBTAG,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ NPC_ETYPE_QINQ,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ NPC_ETYPE_ETAG,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ NPC_ETYPE_MPLSU,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ NPC_ETYPE_MPLSM,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ NPC_ETYPE_NSH,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_CUSTOM_L2_24B, 0xff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU1_VLAN_EXDSA, 0xff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
NPC_S_NA, 0X00,
0x0000,
0x0000,
@@ -1699,7 +2084,9 @@ static const struct npc_kpu_profile_cam kpu1_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu2_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu2_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU2_CTAG, 0xff,
NPC_ETYPE_IP,
@@ -1783,6 +2170,24 @@ static const struct npc_kpu_profile_cam kpu2_cam_entries[] = {
},
{
NPC_S_KPU2_CTAG, 0xff,
+ NPC_ETYPE_PPPOE,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ NPC_PPP_IP,
+ 0xffff,
+ },
+ {
+ NPC_S_KPU2_CTAG, 0xff,
+ NPC_ETYPE_PPPOE,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ NPC_PPP_IP6,
+ 0xffff,
+ },
+ {
+ NPC_S_KPU2_CTAG, 0xff,
0x0000,
0x0000,
0x0000,
@@ -2226,15 +2631,6 @@ static const struct npc_kpu_profile_cam kpu2_cam_entries[] = {
NPC_S_KPU2_ETAG, 0xff,
NPC_ETYPE_SBTAG,
0xffff,
- NPC_ETYPE_ITAG,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU2_ETAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
0x0000,
0x0000,
0x0000,
@@ -2313,159 +2709,6 @@ static const struct npc_kpu_profile_cam kpu2_cam_entries[] = {
0x0000,
},
{
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_IP,
- 0xffff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_IP6,
- 0xffff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_ARP,
- 0xffff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_RARP,
- 0xffff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- NPC_ETYPE_CTAG,
- 0xffff,
- NPC_ETYPE_IP,
- 0xffff,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- NPC_ETYPE_CTAG,
- 0xffff,
- NPC_ETYPE_IP6,
- 0xffff,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- NPC_ETYPE_CTAG,
- 0xffff,
- NPC_ETYPE_ARP,
- 0xffff,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- NPC_ETYPE_CTAG,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- NPC_ETYPE_IP,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- NPC_ETYPE_IP6,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- NPC_ETYPE_ARP,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_CTAG,
- 0xffff,
- NPC_ETYPE_IP,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_CTAG,
- 0xffff,
- NPC_ETYPE_IP6,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_CTAG,
- 0xffff,
- NPC_ETYPE_ARP,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- NPC_ETYPE_CTAG,
- 0xffff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU2_ITAG, 0xff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
NPC_S_KPU2_CTAG2, 0xff,
NPC_ETYPE_IP,
0xffff,
@@ -2817,6 +3060,15 @@ static const struct npc_kpu_profile_cam kpu2_cam_entries[] = {
0x0000,
},
{
+ NPC_S_KPU2_NGIO, 0xff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
NPC_S_NA, 0X00,
0x0000,
0x0000,
@@ -2827,7 +3079,9 @@ static const struct npc_kpu_profile_cam kpu2_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu3_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu3_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU3_CTAG, 0xff,
NPC_ETYPE_IP,
@@ -3243,159 +3497,6 @@ static const struct npc_kpu_profile_cam kpu3_cam_entries[] = {
0x0000,
},
{
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_IP,
- 0xffff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_IP6,
- 0xffff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_ARP,
- 0xffff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_RARP,
- 0xffff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- NPC_ETYPE_CTAG,
- 0xffff,
- NPC_ETYPE_IP,
- 0xffff,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- NPC_ETYPE_CTAG,
- 0xffff,
- NPC_ETYPE_IP6,
- 0xffff,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- NPC_ETYPE_CTAG,
- 0xffff,
- NPC_ETYPE_ARP,
- 0xffff,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- NPC_ETYPE_IP,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- NPC_ETYPE_IP6,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- NPC_ETYPE_ARP,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- NPC_ETYPE_CTAG,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_SBTAG,
- 0xffff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_CTAG,
- 0xffff,
- NPC_ETYPE_IP,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_CTAG,
- 0xffff,
- NPC_ETYPE_IP6,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_CTAG,
- 0xffff,
- NPC_ETYPE_ARP,
- 0xffff,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- NPC_ETYPE_CTAG,
- 0xffff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
- NPC_S_KPU3_ITAG, 0xff,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- 0x0000,
- },
- {
NPC_S_KPU3_CTAG_C, 0xff,
NPC_ETYPE_IP,
0xffff,
@@ -3936,6 +4037,15 @@ static const struct npc_kpu_profile_cam kpu3_cam_entries[] = {
0x0000,
},
{
+ NPC_S_KPU3_VLAN_EXDSA, 0xff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
NPC_S_NA, 0X00,
0x0000,
0x0000,
@@ -3946,7 +4056,9 @@ static const struct npc_kpu_profile_cam kpu3_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu4_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu4_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU4_MPLS, 0xff,
NPC_MPLS_S,
@@ -4084,6 +4196,78 @@ static const struct npc_kpu_profile_cam kpu4_cam_entries[] = {
},
{
NPC_S_KPU4_FDSA, 0xff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ NPC_ETYPE_IP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU4_FDSA, 0xff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ NPC_ETYPE_IP6,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU4_FDSA, 0xff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ NPC_ETYPE_ARP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU4_FDSA, 0xff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ NPC_ETYPE_RARP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU4_FDSA, 0xff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ NPC_ETYPE_PTP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU4_FDSA, 0xff,
+ NPC_ETYPE_CTAG,
+ 0xffff,
+ NPC_ETYPE_FCOE,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU4_FDSA, 0xff,
+ NPC_ETYPE_PPPOE,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ NPC_PPP_IP,
+ 0xffff,
+ },
+ {
+ NPC_S_KPU4_FDSA, 0xff,
+ NPC_ETYPE_PPPOE,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ NPC_PPP_IP6,
+ 0xffff,
+ },
+ {
+ NPC_S_KPU4_FDSA, 0xff,
0x0000,
NPC_DSA_FDSA,
0x0000,
@@ -4092,6 +4276,87 @@ static const struct npc_kpu_profile_cam kpu4_cam_entries[] = {
0x0000,
},
{
+ NPC_S_KPU4_VLAN_EXDSA, 0xff,
+ NPC_ETYPE_IP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU4_VLAN_EXDSA, 0xff,
+ NPC_ETYPE_IP6,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU4_VLAN_EXDSA, 0xff,
+ NPC_ETYPE_ARP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU4_VLAN_EXDSA, 0xff,
+ NPC_ETYPE_RARP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU4_VLAN_EXDSA, 0xff,
+ NPC_ETYPE_PTP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU4_VLAN_EXDSA, 0xff,
+ NPC_ETYPE_FCOE,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU4_VLAN_EXDSA, 0xff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU4_PPPOE, 0xff,
+ NPC_PPP_IP,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU4_PPPOE, 0xff,
+ NPC_PPP_IP6,
+ 0xffff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
NPC_S_NA, 0X00,
0x0000,
0x0000,
@@ -4102,7 +4367,9 @@ static const struct npc_kpu_profile_cam kpu4_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu5_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU5_IP, 0xff,
0x0000,
@@ -4125,116 +4392,116 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
NPC_S_KPU5_IP, 0xff,
NPC_IPNH_TCP,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
NPC_IPNH_UDP,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
NPC_IPNH_SCTP,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
NPC_IPNH_ICMP,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
NPC_IPNH_IGMP,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
NPC_IPNH_ESP,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
NPC_IPNH_AH,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
NPC_IPNH_GRE,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
NPC_IPNH_IP,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
NPC_IPNH_IP6,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
NPC_IPNH_MPLS,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
0x0000,
0x0000,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
0x0000,
0x0000,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
0x0000,
},
@@ -4245,7 +4512,7 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
NPC_IP_VER_4,
NPC_IP_VER_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
@@ -4254,7 +4521,7 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
NPC_IP_VER_4,
NPC_IP_VER_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
@@ -4263,7 +4530,7 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
NPC_IP_VER_4,
NPC_IP_VER_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
@@ -4272,7 +4539,7 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
NPC_IP_VER_4,
NPC_IP_VER_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
@@ -4281,7 +4548,7 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
NPC_IP_VER_4,
NPC_IP_VER_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
@@ -4290,7 +4557,7 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
NPC_IP_VER_4,
NPC_IP_VER_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
@@ -4299,7 +4566,7 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
NPC_IP_VER_4,
NPC_IP_VER_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
@@ -4308,7 +4575,7 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
NPC_IP_VER_4,
NPC_IP_VER_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
@@ -4317,7 +4584,7 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
NPC_IP_VER_4,
NPC_IP_VER_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
@@ -4326,7 +4593,7 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
NPC_IP_VER_4,
NPC_IP_VER_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
@@ -4335,7 +4602,7 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
NPC_IP_VER_4,
NPC_IP_VER_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
@@ -4344,7 +4611,7 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
NPC_IP_VER_4,
NPC_IP_VER_MASK,
0x0000,
- NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF,
+ NPC_IP_HDR_MF | NPC_IP_HDR_FRAGOFF,
},
{
NPC_S_KPU5_IP, 0xff,
@@ -4662,6 +4929,429 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
0x0000,
},
{
+ NPC_S_KPU5_CPT_IP, 0xff,
+ 0x0000,
+ NPC_IP_TTL_MASK,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0001,
+ NPC_IP_HDR_FRAGOFF,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_TCP,
+ 0x00ff,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_UDP,
+ 0x00ff,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_SCTP,
+ 0x00ff,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_ICMP,
+ 0x00ff,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_IGMP,
+ 0x00ff,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_ESP,
+ 0x00ff,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_AH,
+ 0x00ff,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_GRE,
+ 0x00ff,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_IP,
+ 0x00ff,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_IP6,
+ 0x00ff,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_MPLS,
+ 0x00ff,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ 0x0000,
+ 0x0000,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_TCP,
+ 0x00ff,
+ NPC_IP_VER_4,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_UDP,
+ 0x00ff,
+ NPC_IP_VER_4,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_SCTP,
+ 0x00ff,
+ NPC_IP_VER_4,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_ICMP,
+ 0x00ff,
+ NPC_IP_VER_4,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_IGMP,
+ 0x00ff,
+ NPC_IP_VER_4,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_ESP,
+ 0x00ff,
+ NPC_IP_VER_4,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_AH,
+ 0x00ff,
+ NPC_IP_VER_4,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_GRE,
+ 0x00ff,
+ NPC_IP_VER_4,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_IP,
+ 0x00ff,
+ NPC_IP_VER_4,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_IP6,
+ 0x00ff,
+ NPC_IP_VER_4,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ NPC_IPNH_MPLS,
+ 0x00ff,
+ NPC_IP_VER_4,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ 0x0000,
+ 0x0000,
+ NPC_IP_VER_4,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP, 0xff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ 0x0000,
+ NPC_IP6_HOP_MASK,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_TCP << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_UDP << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_SCTP << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_ICMP << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_ICMP6 << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_GRE << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_IP6 << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_MPLS << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_HOP << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_DEST << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_ROUT << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_FRAG << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_ESP << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_AH << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_MOBILITY << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_HOSTID << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ NPC_IPNH_SHIM6 << 8,
+ 0xff00,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ 0x0000,
+ 0x0000,
+ NPC_IP_VER_6,
+ NPC_IP_VER_MASK,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU5_CPT_IP6, 0xff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
NPC_S_NA, 0X00,
0x0000,
0x0000,
@@ -4672,7 +5362,9 @@ static const struct npc_kpu_profile_cam kpu5_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu6_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu6_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU6_IP6_EXT, 0xff,
0x0000,
@@ -5007,6 +5699,330 @@ static const struct npc_kpu_profile_cam kpu6_cam_entries[] = {
0x0000,
},
{
+ NPC_S_KPU6_IP6_CPT_FRAG, 0xff,
+ NPC_IPNH_TCP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_FRAG, 0xff,
+ NPC_IPNH_UDP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_FRAG, 0xff,
+ NPC_IPNH_SCTP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_FRAG, 0xff,
+ NPC_IPNH_ICMP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_FRAG, 0xff,
+ NPC_IPNH_ICMP6 << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_FRAG, 0xff,
+ NPC_IPNH_ESP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_FRAG, 0xff,
+ NPC_IPNH_AH << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_FRAG, 0xff,
+ NPC_IPNH_GRE << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_FRAG, 0xff,
+ NPC_IPNH_IP6 << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_FRAG, 0xff,
+ NPC_IPNH_MPLS << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_FRAG, 0xff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff,
+ NPC_IPNH_TCP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff,
+ NPC_IPNH_UDP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff,
+ NPC_IPNH_SCTP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff,
+ NPC_IPNH_ICMP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff,
+ NPC_IPNH_ICMP6 << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff,
+ NPC_IPNH_ESP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff,
+ NPC_IPNH_AH << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff,
+ NPC_IPNH_GRE << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff,
+ NPC_IPNH_IP6 << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff,
+ NPC_IPNH_MPLS << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff,
+ NPC_IPNH_ROUT << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff,
+ NPC_IPNH_FRAG << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_ROUT, 0xff,
+ NPC_IPNH_TCP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_ROUT, 0xff,
+ NPC_IPNH_UDP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_ROUT, 0xff,
+ NPC_IPNH_SCTP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_ROUT, 0xff,
+ NPC_IPNH_ICMP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_ROUT, 0xff,
+ NPC_IPNH_ICMP6 << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_ROUT, 0xff,
+ NPC_IPNH_ESP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_ROUT, 0xff,
+ NPC_IPNH_AH << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_ROUT, 0xff,
+ NPC_IPNH_GRE << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_ROUT, 0xff,
+ NPC_IPNH_IP6 << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_ROUT, 0xff,
+ NPC_IPNH_MPLS << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_ROUT, 0xff,
+ NPC_IPNH_FRAG << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU6_IP6_CPT_ROUT, 0xff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
NPC_S_NA, 0X00,
0x0000,
0x0000,
@@ -5017,7 +6033,9 @@ static const struct npc_kpu_profile_cam kpu6_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu7_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu7_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU7_IP6_EXT, 0xff,
0x0000,
@@ -5226,6 +6244,105 @@ static const struct npc_kpu_profile_cam kpu7_cam_entries[] = {
0x0000,
},
{
+ NPC_S_KPU7_CPT_IP6_FRAG, 0xff,
+ NPC_IPNH_TCP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU7_CPT_IP6_FRAG, 0xff,
+ NPC_IPNH_UDP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU7_CPT_IP6_FRAG, 0xff,
+ NPC_IPNH_SCTP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU7_CPT_IP6_FRAG, 0xff,
+ NPC_IPNH_ICMP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU7_CPT_IP6_FRAG, 0xff,
+ NPC_IPNH_ICMP6 << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU7_CPT_IP6_FRAG, 0xff,
+ NPC_IPNH_ESP << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU7_CPT_IP6_FRAG, 0xff,
+ NPC_IPNH_AH << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU7_CPT_IP6_FRAG, 0xff,
+ NPC_IPNH_GRE << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU7_CPT_IP6_FRAG, 0xff,
+ NPC_IPNH_IP6 << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU7_CPT_IP6_FRAG, 0xff,
+ NPC_IPNH_MPLS << 8,
+ 0xff00,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
+ NPC_S_KPU7_CPT_IP6_FRAG, 0xff,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ },
+ {
NPC_S_NA, 0X00,
0x0000,
0x0000,
@@ -5236,7 +6353,9 @@ static const struct npc_kpu_profile_cam kpu7_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu8_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU8_TCP, 0xff,
0x0000,
@@ -5259,8 +6378,8 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_TCP, 0xff,
0x0000,
0x0000,
- NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_FIN,
- NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_FIN,
+ NPC_TCP_FLAGS_RST | NPC_TCP_FLAGS_FIN,
+ NPC_TCP_FLAGS_RST | NPC_TCP_FLAGS_FIN,
0x0000,
0x0000,
},
@@ -5268,8 +6387,8 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_TCP, 0xff,
0x0000,
0x0000,
- NPC_TCP_FLAGS_URG|NPC_TCP_FLAGS_SYN,
- NPC_TCP_FLAGS_URG|NPC_TCP_FLAGS_SYN,
+ NPC_TCP_FLAGS_URG | NPC_TCP_FLAGS_SYN,
+ NPC_TCP_FLAGS_URG | NPC_TCP_FLAGS_SYN,
0x0000,
0x0000,
},
@@ -5277,8 +6396,8 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_TCP, 0xff,
0x0000,
0x0000,
- NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_SYN,
- NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_SYN,
+ NPC_TCP_FLAGS_RST | NPC_TCP_FLAGS_SYN,
+ NPC_TCP_FLAGS_RST | NPC_TCP_FLAGS_SYN,
0x0000,
0x0000,
},
@@ -5286,8 +6405,8 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_TCP, 0xff,
0x0000,
0x0000,
- NPC_TCP_FLAGS_SYN|NPC_TCP_FLAGS_FIN,
- NPC_TCP_FLAGS_SYN|NPC_TCP_FLAGS_FIN,
+ NPC_TCP_FLAGS_SYN | NPC_TCP_FLAGS_FIN,
+ NPC_TCP_FLAGS_SYN | NPC_TCP_FLAGS_FIN,
0x0000,
0x0000,
},
@@ -5565,7 +6684,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_MPLSU,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_KEY,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY,
0xffff,
0x0000,
0x0000,
@@ -5574,7 +6693,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_MPLSU,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_SEQ,
+ NPC_GRE_F_CSUM | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5583,7 +6702,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_MPLSU,
0xffff,
- NPC_GRE_F_KEY|NPC_GRE_F_SEQ,
+ NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5592,7 +6711,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_MPLSU,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_KEY|NPC_GRE_F_SEQ,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5637,7 +6756,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_MPLSM,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_KEY,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY,
0xffff,
0x0000,
0x0000,
@@ -5646,7 +6765,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_MPLSM,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_SEQ,
+ NPC_GRE_F_CSUM | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5655,7 +6774,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_MPLSM,
0xffff,
- NPC_GRE_F_KEY|NPC_GRE_F_SEQ,
+ NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5664,7 +6783,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_MPLSM,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_KEY|NPC_GRE_F_SEQ,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5709,7 +6828,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_NSH,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_KEY,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY,
0xffff,
0x0000,
0x0000,
@@ -5718,7 +6837,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_NSH,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_SEQ,
+ NPC_GRE_F_CSUM | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5727,7 +6846,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_NSH,
0xffff,
- NPC_GRE_F_KEY|NPC_GRE_F_SEQ,
+ NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5736,7 +6855,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_NSH,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_KEY|NPC_GRE_F_SEQ,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5781,7 +6900,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_IP,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_KEY,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY,
0xffff,
0x0000,
0x0000,
@@ -5790,7 +6909,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_IP,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_SEQ,
+ NPC_GRE_F_CSUM | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5799,7 +6918,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_IP,
0xffff,
- NPC_GRE_F_KEY|NPC_GRE_F_SEQ,
+ NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5808,7 +6927,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_IP,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_KEY|NPC_GRE_F_SEQ,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5853,7 +6972,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_IP6,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_KEY,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY,
0xffff,
0x0000,
0x0000,
@@ -5862,7 +6981,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_IP6,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_SEQ,
+ NPC_GRE_F_CSUM | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5871,7 +6990,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_IP6,
0xffff,
- NPC_GRE_F_KEY|NPC_GRE_F_SEQ,
+ NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5880,7 +6999,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_IP6,
0xffff,
- NPC_GRE_F_CSUM|NPC_GRE_F_KEY|NPC_GRE_F_SEQ,
+ NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ,
0xffff,
0x0000,
0x0000,
@@ -5916,7 +7035,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_PPP,
0xffff,
- NPC_GRE_F_KEY|NPC_GRE_VER_1,
+ NPC_GRE_F_KEY | NPC_GRE_VER_1,
0xffff,
0x0000,
0x0000,
@@ -5925,7 +7044,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_PPP,
0xffff,
- NPC_GRE_F_KEY|NPC_GRE_F_SEQ|NPC_GRE_VER_1,
+ NPC_GRE_F_KEY | NPC_GRE_F_SEQ | NPC_GRE_VER_1,
0xffff,
0x0000,
0x0000,
@@ -5934,7 +7053,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_PPP,
0xffff,
- NPC_GRE_F_KEY|NPC_GRE_F_ACK|NPC_GRE_VER_1,
+ NPC_GRE_F_KEY | NPC_GRE_F_ACK | NPC_GRE_VER_1,
0xffff,
0x0000,
0x0000,
@@ -5943,7 +7062,7 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
NPC_S_KPU8_GRE, 0xff,
NPC_ETYPE_PPP,
0xffff,
- NPC_GRE_F_KEY|NPC_GRE_F_SEQ|NPC_GRE_F_ACK|NPC_GRE_VER_1,
+ NPC_GRE_F_KEY | NPC_GRE_F_SEQ | NPC_GRE_F_ACK | NPC_GRE_VER_1,
0xffff,
0x0000,
0x0000,
@@ -5977,7 +7096,9 @@ static const struct npc_kpu_profile_cam kpu8_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu9_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu9_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU9_TU_MPLS_IN_GRE, 0xff,
NPC_MPLS_S,
@@ -6387,8 +7508,8 @@ static const struct npc_kpu_profile_cam kpu9_cam_entries[] = {
NPC_S_KPU9_GTPU, 0xff,
0x0000,
0x0000,
- 0x0000,
- 0x0000,
+ NPC_GTP_PT_GTP | NPC_GTP_VER1,
+ NPC_GTP_PT_MASK | NPC_GTP_VER_MASK,
0x0000,
0x0000,
},
@@ -6448,7 +7569,9 @@ static const struct npc_kpu_profile_cam kpu9_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu10_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu10_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU10_TU_MPLS, 0xff,
NPC_MPLS_S,
@@ -6613,7 +7736,9 @@ static const struct npc_kpu_profile_cam kpu10_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu11_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu11_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU11_TU_ETHER, 0xff,
NPC_ETYPE_IP,
@@ -6922,13 +8047,15 @@ static const struct npc_kpu_profile_cam kpu11_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu12_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu12_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU12_TU_IP, 0xff,
NPC_IPNH_TCP,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
0x0000,
},
@@ -6936,8 +8063,8 @@ static const struct npc_kpu_profile_cam kpu12_cam_entries[] = {
NPC_S_KPU12_TU_IP, 0xff,
NPC_IPNH_UDP,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
0x0000,
},
@@ -6945,8 +8072,8 @@ static const struct npc_kpu_profile_cam kpu12_cam_entries[] = {
NPC_S_KPU12_TU_IP, 0xff,
NPC_IPNH_SCTP,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
0x0000,
},
@@ -6954,8 +8081,8 @@ static const struct npc_kpu_profile_cam kpu12_cam_entries[] = {
NPC_S_KPU12_TU_IP, 0xff,
NPC_IPNH_ICMP,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
0x0000,
},
@@ -6963,8 +8090,8 @@ static const struct npc_kpu_profile_cam kpu12_cam_entries[] = {
NPC_S_KPU12_TU_IP, 0xff,
NPC_IPNH_IGMP,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
0x0000,
},
@@ -6972,8 +8099,8 @@ static const struct npc_kpu_profile_cam kpu12_cam_entries[] = {
NPC_S_KPU12_TU_IP, 0xff,
NPC_IPNH_ESP,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
0x0000,
},
@@ -6981,8 +8108,8 @@ static const struct npc_kpu_profile_cam kpu12_cam_entries[] = {
NPC_S_KPU12_TU_IP, 0xff,
NPC_IPNH_AH,
0x00ff,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
0x0000,
},
@@ -6990,8 +8117,8 @@ static const struct npc_kpu_profile_cam kpu12_cam_entries[] = {
NPC_S_KPU12_TU_IP, 0xff,
0x0000,
0x0000,
- NPC_IP_VER_4|NPC_IP_HDR_LEN_5,
- NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK,
+ NPC_IP_VER_4 | NPC_IP_HDR_LEN_5,
+ NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK,
0x0000,
0x0000,
},
@@ -7177,7 +8304,9 @@ static const struct npc_kpu_profile_cam kpu12_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu13_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu13_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU13_TU_IP6_EXT, 0xff,
0x0000,
@@ -7189,7 +8318,9 @@ static const struct npc_kpu_profile_cam kpu13_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu14_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu14_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU14_TU_IP6_EXT, 0xff,
0x0000,
@@ -7201,7 +8332,9 @@ static const struct npc_kpu_profile_cam kpu14_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu15_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu15_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU15_TU_TCP, 0xff,
0x0000,
@@ -7224,8 +8357,8 @@ static const struct npc_kpu_profile_cam kpu15_cam_entries[] = {
NPC_S_KPU15_TU_TCP, 0xff,
0x0000,
0x0000,
- NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_FIN,
- NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_FIN,
+ NPC_TCP_FLAGS_RST | NPC_TCP_FLAGS_FIN,
+ NPC_TCP_FLAGS_RST | NPC_TCP_FLAGS_FIN,
0x0000,
0x0000,
},
@@ -7233,8 +8366,8 @@ static const struct npc_kpu_profile_cam kpu15_cam_entries[] = {
NPC_S_KPU15_TU_TCP, 0xff,
0x0000,
0x0000,
- NPC_TCP_FLAGS_URG|NPC_TCP_FLAGS_SYN,
- NPC_TCP_FLAGS_URG|NPC_TCP_FLAGS_SYN,
+ NPC_TCP_FLAGS_URG | NPC_TCP_FLAGS_SYN,
+ NPC_TCP_FLAGS_URG | NPC_TCP_FLAGS_SYN,
0x0000,
0x0000,
},
@@ -7242,8 +8375,8 @@ static const struct npc_kpu_profile_cam kpu15_cam_entries[] = {
NPC_S_KPU15_TU_TCP, 0xff,
0x0000,
0x0000,
- NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_SYN,
- NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_SYN,
+ NPC_TCP_FLAGS_RST | NPC_TCP_FLAGS_SYN,
+ NPC_TCP_FLAGS_RST | NPC_TCP_FLAGS_SYN,
0x0000,
0x0000,
},
@@ -7251,8 +8384,8 @@ static const struct npc_kpu_profile_cam kpu15_cam_entries[] = {
NPC_S_KPU15_TU_TCP, 0xff,
0x0000,
0x0000,
- NPC_TCP_FLAGS_SYN|NPC_TCP_FLAGS_FIN,
- NPC_TCP_FLAGS_SYN|NPC_TCP_FLAGS_FIN,
+ NPC_TCP_FLAGS_SYN | NPC_TCP_FLAGS_FIN,
+ NPC_TCP_FLAGS_SYN | NPC_TCP_FLAGS_FIN,
0x0000,
0x0000,
},
@@ -7402,7 +8535,9 @@ static const struct npc_kpu_profile_cam kpu15_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_cam kpu16_cam_entries[] = {
+static struct npc_kpu_profile_cam kpu16_cam_entries[] = {
+ NPC_KPU_NOP_CAM,
+ NPC_KPU_NOP_CAM,
{
NPC_S_KPU16_TCP_DATA, 0xff,
0x0000,
@@ -7459,7 +8594,9 @@ static const struct npc_kpu_profile_cam kpu16_cam_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu1_action_entries[] = {
+static struct npc_kpu_profile_action kpu1_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
8, 0, 6, 3, 0,
@@ -7511,6 +8648,14 @@ static const struct npc_kpu_profile_action kpu1_action_entries[] = {
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
8, 12, 0, 0, 0,
+ NPC_S_KPU2_NGIO, 12, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 12, 0, 0, 0,
NPC_S_KPU2_CTAG2, 12, 1,
NPC_LID_LA, NPC_LT_LA_ETHER,
NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN,
@@ -7518,7 +8663,7 @@ static const struct npc_kpu_profile_action kpu1_action_entries[] = {
},
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
- 4, 8, 0, 0, 0,
+ 4, 8, 12, 0, 0,
NPC_S_KPU2_CTAG, 12, 1,
NPC_LID_LA, NPC_LT_LA_ETHER,
NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN,
@@ -7550,14 +8695,6 @@ static const struct npc_kpu_profile_action kpu1_action_entries[] = {
},
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
- 18, 22, 26, 0, 0,
- NPC_S_KPU2_ITAG, 12, 1,
- NPC_LID_LA, NPC_LT_LA_ETHER,
- NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_ITAG,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
2, 6, 10, 2, 0,
NPC_S_KPU4_MPLS, 14, 1,
NPC_LID_LA, NPC_LT_LA_ETHER,
@@ -7590,6 +8727,14 @@ static const struct npc_kpu_profile_action kpu1_action_entries[] = {
},
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 12, 0, 2, 0,
+ NPC_S_KPU4_PPPOE, 12, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
0, 0, 0, 0, 1,
NPC_S_NA, 0, 1,
NPC_LID_LA, NPC_LT_LA_8023,
@@ -7707,15 +8852,6 @@ static const struct npc_kpu_profile_action kpu1_action_entries[] = {
},
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
- 18, 22, 26, 0, 0,
- NPC_S_KPU2_ITAG, 20, 1,
- NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER,
- NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_TAG
- | NPC_F_LA_L_WITH_ITAG,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
2, 6, 10, 2, 0,
NPC_S_KPU4_MPLS, 22, 1,
NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER,
@@ -7788,7 +8924,7 @@ static const struct npc_kpu_profile_action kpu1_action_entries[] = {
},
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
- 4, 8, 16, 2, 0,
+ 4, 8, 12, 2, 0,
NPC_S_KPU4_FDSA, 12, 1,
NPC_LID_LA, NPC_LT_LA_ETHER,
0,
@@ -7897,15 +9033,6 @@ static const struct npc_kpu_profile_action kpu1_action_entries[] = {
},
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
- 18, 22, 26, 0, 0,
- NPC_S_KPU2_ITAG, 28, 1,
- NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER,
- NPC_F_LA_U_HAS_HIGIG2 | NPC_F_LA_U_HAS_TAG
- | NPC_F_LA_L_WITH_ITAG,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
2, 6, 10, 2, 0,
NPC_S_KPU4_MPLS, 30, 1,
NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER,
@@ -8031,15 +9158,6 @@ static const struct npc_kpu_profile_action kpu1_action_entries[] = {
},
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
- 18, 22, 26, 0, 0,
- NPC_S_KPU2_ITAG, 36, 1,
- NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER,
- NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2
- | NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_ITAG,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
2, 6, 10, 2, 0,
NPC_S_KPU4_MPLS, 38, 1,
NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER,
@@ -8075,6 +9193,326 @@ static const struct npc_kpu_profile_action kpu1_action_entries[] = {
0, 0, 0, 0,
},
{
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 0, 6, 3, 0,
+ NPC_S_KPU5_IP, 104, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 3, 0,
+ NPC_S_KPU5_IP6, 104, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 3, 0,
+ NPC_S_KPU5_ARP, 104, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 3, 0,
+ NPC_S_KPU5_RARP, 104, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 3, 0,
+ NPC_S_KPU5_PTP, 104, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 3, 0,
+ NPC_S_KPU5_FCOE, 104, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 12, 0, 0, 0,
+ NPC_S_KPU2_CTAG2, 102, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 4, 8, 0, 0, 0,
+ NPC_S_KPU2_CTAG, 102, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 4, 8, 22, 0, 0,
+ NPC_S_KPU2_SBTAG, 102, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 4, 8, 0, 0, 0,
+ NPC_S_KPU2_QINQ, 102, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 12, 26, 0, 0,
+ NPC_S_KPU2_ETAG, 102, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_ETAG,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 6, 10, 2, 0,
+ NPC_S_KPU4_MPLS, 104, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ NPC_F_LA_L_WITH_MPLS,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 6, 10, 2, 0,
+ NPC_S_KPU4_MPLS, 104, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ NPC_F_LA_L_WITH_MPLS,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 0, 0, 2, 0,
+ NPC_S_KPU4_NSH, 104, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ NPC_F_LA_L_WITH_NSH,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_90B_ETHER,
+ NPC_F_LA_L_UNK_ETYPE,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 0, 6, 3, 0,
+ NPC_S_KPU5_CPT_IP, 56, 1,
+ NPC_LID_LA, NPC_LT_LA_CPT_HDR,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 3, 0,
+ NPC_S_KPU5_CPT_IP6, 56, 1,
+ NPC_LID_LA, NPC_LT_LA_CPT_HDR,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 4, 8, 0, 0, 0,
+ NPC_S_KPU2_CTAG, 54, 1,
+ NPC_LID_LA, NPC_LT_LA_CPT_HDR,
+ NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 4, 8, 0, 0, 0,
+ NPC_S_KPU2_QINQ, 54, 1,
+ NPC_LID_LA, NPC_LT_LA_CPT_HDR,
+ NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 0, 6, 3, 0,
+ NPC_S_KPU5_CPT_IP, 60, 1,
+ NPC_LID_LA, NPC_LT_LA_CPT_HDR,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 3, 0,
+ NPC_S_KPU5_CPT_IP6, 60, 1,
+ NPC_LID_LA, NPC_LT_LA_CPT_HDR,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 4, 8, 0, 0, 0,
+ NPC_S_KPU2_CTAG, 58, 1,
+ NPC_LID_LA, NPC_LT_LA_CPT_HDR,
+ NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 4, 8, 0, 0, 0,
+ NPC_S_KPU2_QINQ, 58, 1,
+ NPC_LID_LA, NPC_LT_LA_CPT_HDR,
+ NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LA, NPC_LT_LA_CPT_HDR,
+ NPC_F_LA_L_UNK_ETYPE,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 0, 6, 3, 0,
+ NPC_S_KPU5_IP, 38, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 3, 0,
+ NPC_S_KPU5_IP6, 38, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 3, 0,
+ NPC_S_KPU5_ARP, 38, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 3, 0,
+ NPC_S_KPU5_RARP, 38, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 3, 0,
+ NPC_S_KPU5_PTP, 38, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 3, 0,
+ NPC_S_KPU5_FCOE, 38, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 12, 0, 0, 0,
+ NPC_S_KPU2_CTAG2, 36, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 4, 8, 0, 0, 0,
+ NPC_S_KPU2_CTAG, 36, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 4, 8, 22, 0, 0,
+ NPC_S_KPU2_SBTAG, 36, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 4, 8, 0, 0, 0,
+ NPC_S_KPU2_QINQ, 36, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 12, 26, 0, 0,
+ NPC_S_KPU2_ETAG, 36, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_ETAG,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 6, 10, 2, 0,
+ NPC_S_KPU4_MPLS, 38, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ NPC_F_LA_L_WITH_MPLS,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 6, 10, 2, 0,
+ NPC_S_KPU4_MPLS, 38, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ NPC_F_LA_L_WITH_MPLS,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 0, 0, 2, 0,
+ NPC_S_KPU4_NSH, 38, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ NPC_F_LA_L_WITH_NSH,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LA, NPC_LT_LA_CUSTOM_L2_24B_ETHER,
+ NPC_F_LA_L_UNK_ETYPE,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 12, 0, 0, 1, 0,
+ NPC_S_KPU3_VLAN_EXDSA, 12, 1,
+ NPC_LID_LA, NPC_LT_LA_ETHER,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
NPC_ERRLEV_LA, NPC_EC_L2_K1,
0, 0, 0, 0, 1,
NPC_S_NA, 0, 0,
@@ -8084,7 +9522,9 @@ static const struct npc_kpu_profile_action kpu1_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu2_action_entries[] = {
+static struct npc_kpu_profile_action kpu2_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
8, 0, 6, 2, 0,
@@ -8159,6 +9599,22 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
},
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 0, 6, 2, 0,
+ NPC_S_KPU5_IP, 14, 1,
+ NPC_LID_LB, NPC_LT_LB_PPPOE,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 2, 0,
+ NPC_S_KPU5_IP6, 14, 1,
+ NPC_LID_LB, NPC_LT_LB_PPPOE,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
0, 0, 0, 0, 1,
NPC_S_NA, 0, 1,
NPC_LID_LB, NPC_LT_LB_CTAG,
@@ -8170,7 +9626,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
8, 0, 6, 2, 0,
NPC_S_KPU5_IP, 10, 1,
NPC_LID_LB, NPC_LT_LB_STAG_QINQ,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG,
0, 0, 0, 0,
},
{
@@ -8178,7 +9634,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
6, 0, 0, 2, 0,
NPC_S_KPU5_IP6, 10, 1,
NPC_LID_LB, NPC_LT_LB_STAG_QINQ,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG,
0, 0, 0, 0,
},
{
@@ -8186,7 +9642,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
0, 0, 0, 2, 0,
NPC_S_KPU5_ARP, 10, 1,
NPC_LID_LB, NPC_LT_LB_STAG_QINQ,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG,
0, 0, 0, 0,
},
{
@@ -8194,7 +9650,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
0, 0, 0, 2, 0,
NPC_S_KPU5_RARP, 10, 1,
NPC_LID_LB, NPC_LT_LB_STAG_QINQ,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG,
0, 0, 0, 0,
},
{
@@ -8202,7 +9658,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
0, 0, 0, 2, 0,
NPC_S_KPU5_PTP, 10, 1,
NPC_LID_LB, NPC_LT_LB_STAG_QINQ,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG,
0, 0, 0, 0,
},
{
@@ -8210,7 +9666,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
0, 0, 0, 2, 0,
NPC_S_KPU5_FCOE, 10, 1,
NPC_LID_LB, NPC_LT_LB_STAG_QINQ,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG,
0, 0, 0, 0,
},
{
@@ -8218,7 +9674,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 6, 10, 1, 0,
NPC_S_KPU4_MPLS, 10, 1,
NPC_LID_LB, NPC_LT_LB_STAG_QINQ,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG,
0, 0, 0, 0,
},
{
@@ -8226,7 +9682,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 6, 10, 1, 0,
NPC_S_KPU4_MPLS, 10, 1,
NPC_LID_LB, NPC_LT_LB_STAG_QINQ,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG,
0, 0, 0, 0,
},
{
@@ -8234,7 +9690,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 0, 0, 1, 0,
NPC_S_KPU4_NSH, 10, 1,
NPC_LID_LB, NPC_LT_LB_STAG_QINQ,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG,
0, 0, 0, 0,
},
{
@@ -8242,7 +9698,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
0, 0, 0, 0, 1,
NPC_S_NA, 0, 1,
NPC_LID_LB, NPC_LT_LB_STAG_QINQ,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG_UNK,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG_UNK,
0, 0, 0, 0,
},
{
@@ -8250,7 +9706,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 6, 0, 0, 0,
NPC_S_KPU3_CTAG, 10, 1,
NPC_LID_LB, NPC_LT_LB_STAG_QINQ,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG_CTAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_STAG_CTAG,
0, 0, 0, 0,
},
{
@@ -8258,7 +9714,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 6, 0, 0, 0,
NPC_S_KPU3_STAG, 10, 1,
NPC_LID_LB, NPC_LT_LB_STAG_QINQ,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG_STAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_STAG_STAG,
0, 0, 0, 0,
},
{
@@ -8266,7 +9722,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
8, 0, 6, 2, 0,
NPC_S_KPU5_IP, 24, 1,
NPC_LID_LB, NPC_LT_LB_BTAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG,
0, 0, 0, 0,
},
{
@@ -8274,7 +9730,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
6, 0, 0, 2, 0,
NPC_S_KPU5_IP6, 24, 1,
NPC_LID_LB, NPC_LT_LB_BTAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG,
0, 0, 0, 0,
},
{
@@ -8282,7 +9738,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
0, 0, 0, 2, 0,
NPC_S_KPU5_ARP, 24, 1,
NPC_LID_LB, NPC_LT_LB_BTAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG,
0, 0, 0, 0,
},
{
@@ -8290,7 +9746,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
0, 0, 0, 2, 0,
NPC_S_KPU5_RARP, 24, 1,
NPC_LID_LB, NPC_LT_LB_BTAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG,
0, 0, 0, 0,
},
{
@@ -8298,7 +9754,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
0, 0, 0, 2, 0,
NPC_S_KPU5_PTP, 24, 1,
NPC_LID_LB, NPC_LT_LB_BTAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG,
0, 0, 0, 0,
},
{
@@ -8306,7 +9762,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
0, 0, 0, 2, 0,
NPC_S_KPU5_FCOE, 24, 1,
NPC_LID_LB, NPC_LT_LB_BTAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG,
0, 0, 0, 0,
},
{
@@ -8314,7 +9770,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 6, 10, 1, 0,
NPC_S_KPU4_MPLS, 24, 1,
NPC_LID_LB, NPC_LT_LB_BTAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG,
0, 0, 0, 0,
},
{
@@ -8322,7 +9778,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 6, 10, 1, 0,
NPC_S_KPU4_MPLS, 24, 1,
NPC_LID_LB, NPC_LT_LB_BTAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG,
0, 0, 0, 0,
},
{
@@ -8330,7 +9786,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 0, 0, 1, 0,
NPC_S_KPU4_NSH, 24, 1,
NPC_LID_LB, NPC_LT_LB_BTAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG,
0, 0, 0, 0,
},
{
@@ -8338,7 +9794,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 0, 0, 0, 0,
NPC_S_KPU3_STAG, 24, 1,
NPC_LID_LB, NPC_LT_LB_BTAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG_STAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG_STAG,
0, 0, 0, 0,
},
{
@@ -8346,7 +9802,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 0, 0, 0, 0,
NPC_S_KPU3_CTAG, 24, 1,
NPC_LID_LB, NPC_LT_LB_BTAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG_CTAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG_CTAG,
0, 0, 0, 0,
},
{
@@ -8354,7 +9810,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
0, 0, 0, 0, 1,
NPC_S_NA, 0, 1,
NPC_LID_LB, NPC_LT_LB_BTAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG_UNK,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG_UNK,
0, 0, 0, 0,
},
{
@@ -8546,15 +10002,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 0, 0, 0, 0,
NPC_S_KPU3_CTAG, 10, 1,
NPC_LID_LB, NPC_LT_LB_ETAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 16, 20, 24, 0, 0,
- NPC_S_KPU3_ITAG, 14, 1,
- NPC_LID_LB, NPC_LT_LB_ETAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_BTAG_ITAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG,
0, 0, 0, 0,
},
{
@@ -8562,7 +10010,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 6, 0, 0, 0,
NPC_S_KPU3_STAG, 10, 1,
NPC_LID_LB, NPC_LT_LB_ETAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_STAG,
0, 0, 0, 0,
},
{
@@ -8570,7 +10018,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 6, 0, 0, 0,
NPC_S_KPU3_QINQ, 10, 1,
NPC_LID_LB, NPC_LT_LB_ETAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_QINQ,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_QINQ,
0, 0, 0, 0,
},
{
@@ -8578,7 +10026,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
8, 0, 6, 2, 0,
NPC_S_KPU5_IP, 28, 1,
NPC_LID_LB, NPC_LT_LB_ETAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG,
0, 0, 0, 0,
},
{
@@ -8586,7 +10034,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
6, 0, 0, 2, 0,
NPC_S_KPU5_IP6, 28, 1,
NPC_LID_LB, NPC_LT_LB_ETAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG,
0, 0, 0, 0,
},
{
@@ -8594,7 +10042,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
0, 0, 0, 2, 0,
NPC_S_KPU5_ARP, 28, 1,
NPC_LID_LB, NPC_LT_LB_ETAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG,
0, 0, 0, 0,
},
{
@@ -8602,7 +10050,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 0, 0, 0, 0,
NPC_S_KPU3_STAG, 28, 1,
NPC_LID_LB, NPC_LT_LB_ETAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG_STAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG_STAG,
0, 0, 0, 0,
},
{
@@ -8610,7 +10058,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
2, 0, 0, 0, 0,
NPC_S_KPU3_CTAG, 28, 1,
NPC_LID_LB, NPC_LT_LB_ETAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG_CTAG,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG_CTAG,
0, 0, 0, 0,
},
{
@@ -8618,7 +10066,7 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
0, 0, 0, 0, 1,
NPC_S_NA, 0, 1,
NPC_LID_LB, NPC_LT_LB_ETAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG_UNK,
+ NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG_UNK,
0, 0, 0, 0,
},
{
@@ -8632,142 +10080,6 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
8, 0, 6, 2, 0,
- NPC_S_KPU5_IP, 20, 1,
- NPC_LID_LB, NPC_LT_LB_ITAG,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 6, 0, 0, 2, 0,
- NPC_S_KPU5_IP6, 20, 1,
- NPC_LID_LB, NPC_LT_LB_ITAG,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 0, 0, 0, 2, 0,
- NPC_S_KPU5_ARP, 20, 1,
- NPC_LID_LB, NPC_LT_LB_ITAG,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 0, 0, 0, 2, 0,
- NPC_S_KPU5_RARP, 20, 1,
- NPC_LID_LB, NPC_LT_LB_ITAG,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 8, 0, 6, 2, 0,
- NPC_S_KPU5_IP, 28, 1,
- NPC_LID_LB, NPC_LT_LB_ITAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG_CTAG,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 6, 0, 0, 2, 0,
- NPC_S_KPU5_IP6, 28, 1,
- NPC_LID_LB, NPC_LT_LB_ITAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG_CTAG,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 0, 0, 0, 2, 0,
- NPC_S_KPU5_ARP, 28, 1,
- NPC_LID_LB, NPC_LT_LB_ITAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG_CTAG,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK,
- 0, 0, 0, 0, 1,
- NPC_S_NA, 0, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 8, 0, 6, 2, 0,
- NPC_S_KPU5_IP, 24, 1,
- NPC_LID_LB, NPC_LT_LB_ITAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 6, 0, 0, 2, 0,
- NPC_S_KPU5_IP6, 24, 1,
- NPC_LID_LB, NPC_LT_LB_ITAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 0, 0, 0, 2, 0,
- NPC_S_KPU5_ARP, 24, 1,
- NPC_LID_LB, NPC_LT_LB_ITAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK,
- 0, 0, 0, 0, 1,
- NPC_S_NA, 0, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 8, 0, 6, 2, 0,
- NPC_S_KPU5_IP, 24, 1,
- NPC_LID_LB, NPC_LT_LB_ITAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 6, 0, 0, 2, 0,
- NPC_S_KPU5_IP6, 24, 1,
- NPC_LID_LB, NPC_LT_LB_ITAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 0, 0, 0, 2, 0,
- NPC_S_KPU5_ARP, 24, 1,
- NPC_LID_LB, NPC_LT_LB_ITAG,
- NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK,
- 0, 0, 0, 0, 1,
- NPC_S_NA, 0, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK,
- 0, 0, 0, 0, 1,
- NPC_S_NA, 0, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 8, 0, 6, 2, 0,
NPC_S_KPU5_IP, 10, 1,
NPC_LID_LB, NPC_LT_LB_STAG_QINQ,
0,
@@ -9078,6 +10390,14 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
0, 0, 0, 0,
},
{
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_NGIO,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
NPC_ERRLEV_LB, NPC_EC_L2_K3,
0, 0, 0, 0, 1,
NPC_S_NA, 0, 0,
@@ -9087,11 +10407,13 @@ static const struct npc_kpu_profile_action kpu2_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu3_action_entries[] = {
+static struct npc_kpu_profile_action kpu3_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
8, 0, 6, 1, 0,
- NPC_S_KPU5_IP, 4, 0,
+ NPC_S_KPU5_IP, 6, 0,
NPC_LID_LB, NPC_LT_NA,
0,
0, 0, 0, 0,
@@ -9099,7 +10421,7 @@ static const struct npc_kpu_profile_action kpu3_action_entries[] = {
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
6, 0, 0, 1, 0,
- NPC_S_KPU5_IP6, 4, 0,
+ NPC_S_KPU5_IP6, 6, 0,
NPC_LID_LB, NPC_LT_NA,
0,
0, 0, 0, 0,
@@ -9107,7 +10429,7 @@ static const struct npc_kpu_profile_action kpu3_action_entries[] = {
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
0, 0, 0, 1, 0,
- NPC_S_KPU5_ARP, 4, 0,
+ NPC_S_KPU5_ARP, 6, 0,
NPC_LID_LB, NPC_LT_NA,
0,
0, 0, 0, 0,
@@ -9115,7 +10437,7 @@ static const struct npc_kpu_profile_action kpu3_action_entries[] = {
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
0, 0, 0, 1, 0,
- NPC_S_KPU5_RARP, 4, 0,
+ NPC_S_KPU5_RARP, 6, 0,
NPC_LID_LB, NPC_LT_NA,
0,
0, 0, 0, 0,
@@ -9123,7 +10445,7 @@ static const struct npc_kpu_profile_action kpu3_action_entries[] = {
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
0, 0, 0, 1, 0,
- NPC_S_KPU5_PTP, 4, 0,
+ NPC_S_KPU5_PTP, 6, 0,
NPC_LID_LB, NPC_LT_NA,
0,
0, 0, 0, 0,
@@ -9131,7 +10453,7 @@ static const struct npc_kpu_profile_action kpu3_action_entries[] = {
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
0, 0, 0, 1, 0,
- NPC_S_KPU5_FCOE, 4, 0,
+ NPC_S_KPU5_FCOE, 6, 0,
NPC_LID_LB, NPC_LT_NA,
0,
0, 0, 0, 0,
@@ -9139,7 +10461,7 @@ static const struct npc_kpu_profile_action kpu3_action_entries[] = {
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
2, 6, 10, 0, 0,
- NPC_S_KPU4_MPLS, 4, 0,
+ NPC_S_KPU4_MPLS, 6, 0,
NPC_LID_LB, NPC_LT_NA,
0,
0, 0, 0, 0,
@@ -9147,7 +10469,7 @@ static const struct npc_kpu_profile_action kpu3_action_entries[] = {
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
2, 6, 10, 0, 0,
- NPC_S_KPU4_MPLS, 4, 0,
+ NPC_S_KPU4_MPLS, 6, 0,
NPC_LID_LB, NPC_LT_NA,
0,
0, 0, 0, 0,
@@ -9155,7 +10477,7 @@ static const struct npc_kpu_profile_action kpu3_action_entries[] = {
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
2, 0, 0, 0, 0,
- NPC_S_KPU4_NSH, 4, 0,
+ NPC_S_KPU4_NSH, 6, 0,
NPC_LID_LB, NPC_LT_NA,
0,
0, 0, 0, 0,
@@ -9458,142 +10780,6 @@ static const struct npc_kpu_profile_action kpu3_action_entries[] = {
},
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
- 8, 0, 6, 2, 0,
- NPC_S_KPU5_IP, 18, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 6, 0, 0, 2, 0,
- NPC_S_KPU5_IP6, 18, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 0, 0, 0, 2, 0,
- NPC_S_KPU5_ARP, 18, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 0, 0, 0, 2, 0,
- NPC_S_KPU5_RARP, 18, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 8, 0, 6, 1, 0,
- NPC_S_KPU5_IP, 26, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 6, 0, 0, 1, 0,
- NPC_S_KPU5_IP6, 26, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 0, 0, 0, 1, 0,
- NPC_S_KPU5_ARP, 26, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 8, 0, 6, 1, 0,
- NPC_S_KPU5_IP, 22, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 6, 0, 0, 1, 0,
- NPC_S_KPU5_IP6, 22, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 0, 0, 0, 1, 0,
- NPC_S_KPU5_ARP, 22, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK,
- 0, 0, 0, 0, 1,
- NPC_S_NA, 0, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK,
- 0, 0, 0, 0, 1,
- NPC_S_NA, 0, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 8, 0, 6, 1, 0,
- NPC_S_KPU5_IP, 22, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 6, 0, 0, 1, 0,
- NPC_S_KPU5_IP6, 22, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
- 0, 0, 0, 1, 0,
- NPC_S_KPU5_ARP, 22, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK,
- 0, 0, 0, 0, 1,
- NPC_S_NA, 0, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK,
- 0, 0, 0, 0, 1,
- NPC_S_NA, 0, 0,
- NPC_LID_LB, NPC_LT_NA,
- 0,
- 0, 0, 0, 0,
- },
- {
- NPC_ERRLEV_RE, NPC_EC_NOERR,
8, 0, 6, 1, 0,
NPC_S_KPU5_IP, 4, 1,
NPC_LID_LB, NPC_LT_LB_CTAG,
@@ -10073,6 +11259,14 @@ static const struct npc_kpu_profile_action kpu3_action_entries[] = {
0, 0, 0, 0,
},
{
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 0,
+ NPC_S_KPU4_VLAN_EXDSA, 12, 1,
+ NPC_LID_LB, NPC_LT_LB_VLAN_EXDSA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
NPC_ERRLEV_LB, NPC_EC_L2_K3,
0, 0, 0, 0, 1,
NPC_S_NA, 0, 0,
@@ -10082,7 +11276,9 @@ static const struct npc_kpu_profile_action kpu3_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu4_action_entries[] = {
+static struct npc_kpu_profile_action kpu4_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
0, 0, 0, 0, 0,
@@ -10205,6 +11401,70 @@ static const struct npc_kpu_profile_action kpu4_action_entries[] = {
},
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 0, 6, 0, 0,
+ NPC_S_KPU5_IP, 10, 1,
+ NPC_LID_LB, NPC_LT_LB_FDSA,
+ NPC_F_LB_L_FDSA,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 0, 0,
+ NPC_S_KPU5_IP6, 10, 1,
+ NPC_LID_LB, NPC_LT_LB_FDSA,
+ NPC_F_LB_L_FDSA,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 0,
+ NPC_S_KPU5_ARP, 10, 1,
+ NPC_LID_LB, NPC_LT_LB_FDSA,
+ NPC_F_LB_L_FDSA,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 0, 6, 0, 0,
+ NPC_S_KPU5_RARP, 10, 1,
+ NPC_LID_LB, NPC_LT_LB_FDSA,
+ NPC_F_LB_L_FDSA,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 0, 0,
+ NPC_S_KPU5_PTP, 10, 1,
+ NPC_LID_LB, NPC_LT_LB_FDSA,
+ NPC_F_LB_L_FDSA,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 0,
+ NPC_S_KPU5_FCOE, 10, 1,
+ NPC_LID_LB, NPC_LT_LB_FDSA,
+ NPC_F_LB_L_FDSA,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 0, 6, 0, 0,
+ NPC_S_KPU5_IP, 14, 1,
+ NPC_LID_LB, NPC_LT_LB_PPPOE,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 0, 0,
+ NPC_S_KPU5_IP6, 14, 1,
+ NPC_LID_LB, NPC_LT_LB_PPPOE,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
0, 0, 0, 0, 1,
NPC_S_NA, 0, 1,
NPC_LID_LB, NPC_LT_LB_FDSA,
@@ -10212,6 +11472,78 @@ static const struct npc_kpu_profile_action kpu4_action_entries[] = {
0, 0, 0, 0,
},
{
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 0, 6, 0, 0,
+ NPC_S_KPU5_IP, 2, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 0, 0,
+ NPC_S_KPU5_IP6, 2, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 0,
+ NPC_S_KPU5_ARP, 2, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 0, 6, 0, 0,
+ NPC_S_KPU5_RARP, 2, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 0, 0,
+ NPC_S_KPU5_PTP, 2, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 0,
+ NPC_S_KPU5_FCOE, 2, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 0, 6, 0, 0,
+ NPC_S_KPU5_IP, 10, 0,
+ NPC_LID_LB, NPC_LT_LB_PPPOE,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 0, 0,
+ NPC_S_KPU5_IP6, 10, 0,
+ NPC_LID_LB, NPC_LT_LB_PPPOE,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
NPC_ERRLEV_LB, NPC_EC_L2_K4,
0, 0, 0, 0, 1,
NPC_S_NA, 0, 0,
@@ -10221,7 +11553,9 @@ static const struct npc_kpu_profile_action kpu4_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu5_action_entries[] = {
+static struct npc_kpu_profile_action kpu5_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_LC, NPC_EC_IP_TTL_0,
0, 0, 0, 0, 1,
@@ -10719,6 +12053,382 @@ static const struct npc_kpu_profile_action kpu5_action_entries[] = {
0, 0, 0, 0,
},
{
+ NPC_ERRLEV_LC, NPC_EC_IP_TTL_0,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_LC, NPC_EC_IP_FRAG_OFFSET_1,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ NPC_F_LC_U_IP_FRAG,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 12, 0, 2, 0,
+ NPC_S_KPU8_TCP, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 0, 0, 2, 0,
+ NPC_S_KPU8_UDP, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU8_SCTP, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU8_ICMP, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU8_IGMP, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 3, 0,
+ NPC_S_KPU9_ESP, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU8_AH, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 0, 0, 2, 0,
+ NPC_S_KPU8_GRE, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 0, 6, 6, 0,
+ NPC_S_KPU12_TU_IP, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ NPC_F_LC_L_IP_IN_IP,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 6, 0,
+ NPC_S_KPU12_TU_IP6, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ NPC_F_LC_L_6TO4,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 6, 10, 3, 0,
+ NPC_S_KPU9_TU_MPLS_IN_IP, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ NPC_F_LC_L_MPLS_IN_IP,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ NPC_F_LC_U_UNK_PROTO,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 12, 0, 2, 0,
+ NPC_S_KPU8_TCP, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP_OPT,
+ 0,
+ 0, 0xf, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 8, 10, 2, 0,
+ NPC_S_KPU8_UDP, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP_OPT,
+ 0,
+ 0, 0xf, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU8_SCTP, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP_OPT,
+ 0,
+ 0, 0xf, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU8_ICMP, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP_OPT,
+ 0,
+ 0, 0xf, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU8_IGMP, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP_OPT,
+ 0,
+ 0, 0xf, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 3, 0,
+ NPC_S_KPU9_ESP, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP_OPT,
+ 0,
+ 0, 0xf, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU8_AH, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP_OPT,
+ 0,
+ 0, 0xf, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 0, 0, 2, 0,
+ NPC_S_KPU8_GRE, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP_OPT,
+ 0,
+ 0, 0xf, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 8, 0, 6, 6, 0,
+ NPC_S_KPU12_TU_IP, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP_OPT,
+ NPC_F_LC_L_IP_IN_IP,
+ 0, 0xf, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 6, 0,
+ NPC_S_KPU12_TU_IP6, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP_OPT,
+ NPC_F_LC_L_6TO4,
+ 0, 0xf, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 6, 10, 3, 0,
+ NPC_S_KPU9_TU_MPLS_IN_IP, 20, 1,
+ NPC_LID_LC, NPC_LT_LC_IP_OPT,
+ NPC_F_LC_L_MPLS_IN_IP,
+ 0, 0xf, 0, 2,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP_OPT,
+ NPC_F_LC_U_UNK_PROTO,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_LC, NPC_EC_IP_VER,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_LC, NPC_EC_IP6_HOP_0,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 12, 0, 2, 0,
+ NPC_S_KPU8_TCP, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 0, 0, 2, 0,
+ NPC_S_KPU8_UDP, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU8_SCTP, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU8_ICMP, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU8_ICMP6, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU8_GRE, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 6, 0,
+ NPC_S_KPU12_TU_IP6, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6,
+ NPC_F_LC_L_IP6_TUN_IP6,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 6, 10, 3, 0,
+ NPC_S_KPU9_TU_MPLS_IN_IP, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6,
+ NPC_F_LC_L_IP6_MPLS_IN_IP,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 0,
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6_EXT,
+ NPC_F_LC_L_EXT_HOP,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 0,
+ NPC_S_KPU6_IP6_CPT_HOP_DEST, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6_EXT,
+ NPC_F_LC_L_EXT_DEST,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 0,
+ NPC_S_KPU6_IP6_CPT_ROUT, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6_EXT,
+ NPC_F_LC_L_EXT_ROUT,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 2, 0, 0, 0,
+ NPC_S_KPU6_IP6_CPT_FRAG, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6_EXT,
+ NPC_F_LC_U_IP6_FRAG,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 3, 0,
+ NPC_S_KPU9_ESP, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6_EXT,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU8_AH, 40, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6_EXT,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6_EXT,
+ NPC_F_LC_L_EXT_MOBILITY,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6_EXT,
+ NPC_F_LC_L_EXT_HOSTID,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6_EXT,
+ NPC_F_LC_L_EXT_SHIM6,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6,
+ NPC_F_LC_U_UNK_PROTO,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_LC, NPC_EC_IP6_VER,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 1,
+ NPC_LID_LC, NPC_LT_LC_IP6,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
NPC_ERRLEV_LC, NPC_EC_UNK,
0, 0, 0, 0, 1,
NPC_S_NA, 0, 0,
@@ -10728,7 +12438,9 @@ static const struct npc_kpu_profile_action kpu5_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu6_action_entries[] = {
+static struct npc_kpu_profile_action kpu6_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
0, 0, 0, 0, 1,
@@ -11026,6 +12738,294 @@ static const struct npc_kpu_profile_action kpu6_action_entries[] = {
0, 0, 0, 0,
},
{
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 12, 0, 1, 0,
+ NPC_S_KPU8_TCP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 8, 10, 1, 0,
+ NPC_S_KPU8_UDP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_SCTP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_ICMP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_ICMP6, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU9_ESP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_AH, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_GRE, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 5, 0,
+ NPC_S_KPU12_TU_IP6, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 6, 10, 2, 0,
+ NPC_S_KPU9_TU_MPLS_IN_IP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 12, 0, 1, 0,
+ NPC_S_KPU8_TCP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 8, 10, 1, 0,
+ NPC_S_KPU8_UDP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_SCTP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_ICMP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_ICMP6, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU9_ESP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_AH, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_GRE, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 5, 0,
+ NPC_S_KPU12_TU_IP6, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 6, 10, 2, 0,
+ NPC_S_KPU9_TU_MPLS_IN_IP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 0,
+ NPC_S_KPU7_IP6_ROUT, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 2, 0, 0, 0,
+ NPC_S_KPU7_CPT_IP6_FRAG, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 12, 0, 1, 0,
+ NPC_S_KPU8_TCP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 8, 10, 1, 0,
+ NPC_S_KPU8_UDP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_SCTP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_ICMP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_ICMP6, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 2, 0,
+ NPC_S_KPU9_ESP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_AH, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU8_GRE, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 5, 0,
+ NPC_S_KPU12_TU_IP6, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 6, 10, 2, 0,
+ NPC_S_KPU9_TU_MPLS_IN_IP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 2, 0, 0, 0,
+ NPC_S_KPU7_CPT_IP6_FRAG, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 1, 0xff, 0, 3,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
NPC_ERRLEV_LC, NPC_EC_UNK,
0, 0, 0, 0, 1,
NPC_S_NA, 0, 0,
@@ -11035,7 +13035,9 @@ static const struct npc_kpu_profile_action kpu6_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu7_action_entries[] = {
+static struct npc_kpu_profile_action kpu7_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
0, 0, 0, 0, 1,
@@ -11221,6 +13223,94 @@ static const struct npc_kpu_profile_action kpu7_action_entries[] = {
0, 0, 0, 0,
},
{
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 12, 0, 0, 0,
+ NPC_S_KPU8_TCP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 8, 10, 0, 0,
+ NPC_S_KPU8_UDP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 0,
+ NPC_S_KPU8_SCTP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 0,
+ NPC_S_KPU8_ICMP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 0,
+ NPC_S_KPU8_ICMP6, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 1, 0,
+ NPC_S_KPU9_ESP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 0,
+ NPC_S_KPU8_AH, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 0,
+ NPC_S_KPU8_GRE, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 6, 0, 0, 4, 0,
+ NPC_S_KPU12_TU_IP6, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 2, 6, 10, 1, 0,
+ NPC_S_KPU9_TU_MPLS_IN_IP, 8, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
+ NPC_ERRLEV_RE, NPC_EC_NOERR,
+ 0, 0, 0, 0, 1,
+ NPC_S_NA, 0, 0,
+ NPC_LID_LC, NPC_LT_NA,
+ 0,
+ 0, 0, 0, 0,
+ },
+ {
NPC_ERRLEV_LC, NPC_EC_UNK,
0, 0, 0, 0, 1,
NPC_S_NA, 0, 0,
@@ -11230,7 +13320,9 @@ static const struct npc_kpu_profile_action kpu7_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu8_action_entries[] = {
+static struct npc_kpu_profile_action kpu8_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_LD, NPC_EC_TCP_FLAGS_FIN_ONLY,
0, 0, 0, 0, 1,
@@ -11889,7 +13981,9 @@ static const struct npc_kpu_profile_action kpu8_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu9_action_entries[] = {
+static struct npc_kpu_profile_action kpu9_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
0, 0, 0, 0, 0,
@@ -12252,10 +14346,10 @@ static const struct npc_kpu_profile_action kpu9_action_entries[] = {
},
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
- 0, 0, 0, 0, 1,
- NPC_S_NA, 0, 1,
+ 8, 0, 6, 2, 0,
+ NPC_S_KPU12_TU_IP, 8, 1,
NPC_LID_LE, NPC_LT_LE_GTPU,
- NPC_F_LE_L_GTPU_UNK,
+ 0,
0, 0, 0, 0,
},
{
@@ -12308,7 +14402,9 @@ static const struct npc_kpu_profile_action kpu9_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu10_action_entries[] = {
+static struct npc_kpu_profile_action kpu10_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
8, 0, 6, 1, 0,
@@ -12455,7 +14551,9 @@ static const struct npc_kpu_profile_action kpu10_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu11_action_entries[] = {
+static struct npc_kpu_profile_action kpu11_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
8, 0, 6, 0, 0,
@@ -12730,7 +14828,9 @@ static const struct npc_kpu_profile_action kpu11_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu12_action_entries[] = {
+static struct npc_kpu_profile_action kpu12_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
2, 12, 0, 2, 0,
@@ -12957,7 +15057,9 @@ static const struct npc_kpu_profile_action kpu12_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu13_action_entries[] = {
+static struct npc_kpu_profile_action kpu13_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
0, 0, 0, 0, 1,
@@ -12968,7 +15070,9 @@ static const struct npc_kpu_profile_action kpu13_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu14_action_entries[] = {
+static struct npc_kpu_profile_action kpu14_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
0, 0, 0, 0, 1,
@@ -12979,7 +15083,9 @@ static const struct npc_kpu_profile_action kpu14_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu15_action_entries[] = {
+static struct npc_kpu_profile_action kpu15_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_LG, NPC_EC_TCP_FLAGS_FIN_ONLY,
0, 0, 0, 0, 1,
@@ -13158,7 +15264,9 @@ static const struct npc_kpu_profile_action kpu15_action_entries[] = {
},
};
-static const struct npc_kpu_profile_action kpu16_action_entries[] = {
+static struct npc_kpu_profile_action kpu16_action_entries[] = {
+ NPC_KPU_NOP_ACTION,
+ NPC_KPU_NOP_ACTION,
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
0, 0, 0, 0, 1,
@@ -13209,7 +15317,7 @@ static const struct npc_kpu_profile_action kpu16_action_entries[] = {
},
};
-static const struct npc_kpu_profile npc_kpu_profiles[] = {
+static struct npc_kpu_profile npc_kpu_profiles[] = {
{
ARRAY_SIZE(kpu1_cam_entries),
ARRAY_SIZE(kpu1_action_entries),
@@ -13308,12 +15416,22 @@ static const struct npc_kpu_profile npc_kpu_profiles[] = {
},
};
-static const struct npc_lt_def_cfg npc_lt_defaults = {
+static struct npc_lt_def_cfg npc_lt_defaults = {
.rx_ol2 = {
.lid = NPC_LID_LA,
.ltype_match = NPC_LT_LA_ETHER,
.ltype_mask = 0x0F,
},
+ .ovlan = {
+ .lid = NPC_LID_LB,
+ .ltype_match = NPC_LT_LB_CTAG,
+ .ltype_mask = 0x0F,
+ },
+ .ivlan = {
+ .lid = NPC_LID_LB,
+ .ltype_match = NPC_LT_LB_STAG_QINQ,
+ .ltype_mask = 0x0F,
+ },
.rx_oip4 = {
.lid = NPC_LID_LC,
.ltype_match = NPC_LT_LC_IP,
@@ -13392,6 +15510,30 @@ static const struct npc_lt_def_cfg npc_lt_defaults = {
.ltype_match = NPC_LT_LG_TU_IP,
.ltype_mask = 0x0F,
},
+ .rx_apad0 = {
+ .valid = 0,
+ .lid = NPC_LID_LC,
+ .ltype_match = NPC_LT_LC_IP6,
+ .ltype_mask = 0x0F,
+ },
+ .rx_apad1 = {
+ .valid = 0,
+ .lid = NPC_LID_LC,
+ .ltype_match = NPC_LT_LC_IP6,
+ .ltype_mask = 0x0F,
+ },
+ .rx_et = {
+ {
+ .lid = NPC_LID_LB,
+ .ltype_match = NPC_LT_NA,
+ .ltype_mask = 0x0,
+ },
+ {
+ .lid = NPC_LID_LB,
+ .ltype_match = NPC_LT_NA,
+ .ltype_mask = 0x0,
+ },
+ },
};
static struct npc_mcam_kex npc_mkex_default = {
@@ -13399,7 +15541,7 @@ static struct npc_mcam_kex npc_mkex_default = {
.name = "default",
.kpu_version = NPC_KPU_PROFILE_VER,
.keyx_cfg = {
- /* nibble: LA..LE (ltype only) + channel */
+ /* nibble: LA..LE (ltype only) + Error code + Channel */
[NIX_INTF_RX] = ((u64)NPC_MCAM_KEY_X2 << 32) | NPC_PARSE_NIBBLE_INTF_RX,
/* nibble: LA..LE (ltype only) */
[NIX_INTF_TX] = ((u64)NPC_MCAM_KEY_X2 << 32) | NPC_PARSE_NIBBLE_INTF_TX,
@@ -13410,30 +15552,40 @@ static struct npc_mcam_kex npc_mkex_default = {
[NPC_LID_LA] = {
/* Layer A: Ethernet: */
[NPC_LT_LA_ETHER] = {
- /* DMAC: 6 bytes, KW1[47:0] */
+ /* DMAC: 6 bytes, KW1[55:8] */
KEX_LD_CFG(0x05, 0x0, 0x1, 0x0, NPC_KEXOF_DMAC),
- /* Ethertype: 2 bytes, KW0[47:32] */
- KEX_LD_CFG(0x01, 0xc, 0x1, 0x0, 0x4),
+ /* Ethertype: 2 bytes, KW0[55:40] */
+ KEX_LD_CFG(0x01, 0xc, 0x1, 0x0, 0x5),
+ },
+ /* Layer A: HiGig2: */
+ [NPC_LT_LA_HIGIG2_ETHER] = {
+ /* Classification: 2 bytes, KW1[23:8] */
+ KEX_LD_CFG(0x01, 0x8, 0x1, 0x0, NPC_KEXOF_DMAC),
+ /* VID: 2 bytes, KW1[39:24] */
+ KEX_LD_CFG(0x01, 0xc, 0x1, 0x0,
+ NPC_KEXOF_DMAC + 2),
},
},
[NPC_LID_LB] = {
/* Layer B: Single VLAN (CTAG) */
- /* CTAG VLAN[2..3] + Ethertype, 4 bytes, KW0[63:32] */
[NPC_LT_LB_CTAG] = {
- KEX_LD_CFG(0x03, 0x2, 0x1, 0x0, 0x4),
+ /* CTAG VLAN: 2 bytes, KW1[7:0], KW0[63:56] */
+ KEX_LD_CFG(0x01, 0x2, 0x1, 0x0, 0x7),
+ /* Ethertype: 2 bytes, KW0[55:40] */
+ KEX_LD_CFG(0x01, 0x4, 0x1, 0x0, 0x5),
},
/* Layer B: Stacked VLAN (STAG|QinQ) */
[NPC_LT_LB_STAG_QINQ] = {
- /* Outer VLAN: 2 bytes, KW0[63:48] */
- KEX_LD_CFG(0x01, 0x2, 0x1, 0x0, 0x6),
- /* Ethertype: 2 bytes, KW0[47:32] */
- KEX_LD_CFG(0x01, 0x8, 0x1, 0x0, 0x4),
+ /* Outer VLAN: 2 bytes, KW1[7:0], KW0[63:56] */
+ KEX_LD_CFG(0x01, 0x2, 0x1, 0x0, 0x7),
+ /* Ethertype: 2 bytes, KW0[55:40] */
+ KEX_LD_CFG(0x01, 0x8, 0x1, 0x0, 0x5),
},
[NPC_LT_LB_FDSA] = {
- /* SWITCH PORT: 1 byte, KW0[63:48] */
- KEX_LD_CFG(0x0, 0x1, 0x1, 0x0, 0x6),
- /* Ethertype: 2 bytes, KW0[47:32] */
- KEX_LD_CFG(0x01, 0x4, 0x1, 0x0, 0x4),
+ /* SWITCH PORT: 1 byte, KW0[63:56] */
+ KEX_LD_CFG(0x0, 0x1, 0x1, 0x0, 0x7),
+ /* Ethertype: 2 bytes, KW0[55:40] */
+ KEX_LD_CFG(0x01, 0x4, 0x1, 0x0, 0x5),
},
},
[NPC_LID_LC] = {
@@ -13477,6 +15629,13 @@ static struct npc_mcam_kex npc_mkex_default = {
/* DMAC: 6 bytes, KW1[63:16] */
KEX_LD_CFG(0x05, 0x8, 0x1, 0x0, 0xa),
},
+ /* Layer A: HiGig2: */
+ [NPC_LT_LA_IH_NIX_HIGIG2_ETHER] = {
+ /* PF_FUNC: 2B , KW0 [47:32] */
+ KEX_LD_CFG(0x01, 0x0, 0x1, 0x0, 0x4),
+ /* VID: 2 bytes, KW1[31:16] */
+ KEX_LD_CFG(0x01, 0x10, 0x1, 0x0, 0xa),
+ },
},
[NPC_LID_LB] = {
/* Layer B: Single VLAN (CTAG) */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
index ab24a5e8ee8a..10cddf1ac7b9 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
@@ -57,6 +57,10 @@ static char *mkex_profile; /* MKEX profile name */
module_param(mkex_profile, charp, 0000);
MODULE_PARM_DESC(mkex_profile, "MKEX profile name string");
+static char *kpu_profile; /* KPU profile name */
+module_param(kpu_profile, charp, 0000);
+MODULE_PARM_DESC(kpu_profile, "KPU profile name string");
+
static void rvu_setup_hw_capabilities(struct rvu *rvu)
{
struct rvu_hwinfo *hw = rvu->hw;
@@ -180,6 +184,14 @@ int rvu_rsrc_free_count(struct rsrc_bmap *rsrc)
return (rsrc->max - used);
}
+bool is_rsrc_free(struct rsrc_bmap *rsrc, int id)
+{
+ if (!rsrc->bmap)
+ return false;
+
+ return !test_bit(id, rsrc->bmap);
+}
+
int rvu_alloc_bitmap(struct rsrc_bmap *rsrc)
{
rsrc->bmap = kcalloc(BITS_TO_LONGS(rsrc->max),
@@ -1754,6 +1766,48 @@ int rvu_mbox_handler_get_hw_cap(struct rvu *rvu, struct msg_req *req,
return 0;
}
+int rvu_mbox_handler_set_vf_perm(struct rvu *rvu, struct set_vf_perm *req,
+ struct msg_rsp *rsp)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc = req->hdr.pcifunc;
+ struct rvu_pfvf *pfvf;
+ int blkaddr, nixlf;
+ u16 target;
+
+ /* Only PF can add VF permissions */
+ if ((pcifunc & RVU_PFVF_FUNC_MASK) || is_afvf(pcifunc))
+ return -EOPNOTSUPP;
+
+ target = (pcifunc & ~RVU_PFVF_FUNC_MASK) | (req->vf + 1);
+ pfvf = rvu_get_pfvf(rvu, target);
+
+ if (req->flags & RESET_VF_PERM) {
+ pfvf->flags &= RVU_CLEAR_VF_PERM;
+ } else if (test_bit(PF_SET_VF_TRUSTED, &pfvf->flags) ^
+ (req->flags & VF_TRUSTED)) {
+ change_bit(PF_SET_VF_TRUSTED, &pfvf->flags);
+ /* disable multicast and promisc entries */
+ if (!test_bit(PF_SET_VF_TRUSTED, &pfvf->flags)) {
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, target);
+ if (blkaddr < 0)
+ return 0;
+ nixlf = rvu_get_lf(rvu, &hw->block[blkaddr],
+ target, 0);
+ if (nixlf < 0)
+ return 0;
+ npc_enadis_default_mce_entry(rvu, target, nixlf,
+ NIXLF_ALLMULTI_ENTRY,
+ false);
+ npc_enadis_default_mce_entry(rvu, target, nixlf,
+ NIXLF_PROMISC_ENTRY,
+ false);
+ }
+ }
+
+ return 0;
+}
+
static int rvu_process_mbox_msg(struct otx2_mbox *mbox, int devid,
struct mbox_msghdr *req)
{
@@ -2279,6 +2333,7 @@ static void __rvu_flr_handler(struct rvu *rvu, u16 pcifunc)
rvu_blklf_teardown(rvu, pcifunc, BLKADDR_SSOW);
rvu_blklf_teardown(rvu, pcifunc, BLKADDR_SSO);
rvu_blklf_teardown(rvu, pcifunc, BLKADDR_NPA);
+ rvu_reset_lmt_map_tbl(rvu, pcifunc);
rvu_detach_rsrcs(rvu, NULL, pcifunc);
mutex_unlock(&rvu->flr_lock);
}
@@ -2842,6 +2897,8 @@ static void rvu_update_module_params(struct rvu *rvu)
strscpy(rvu->mkex_pfl_name,
mkex_profile ? mkex_profile : default_pfl_name, MKEX_NAME_LEN);
+ strscpy(rvu->kpu_pfl_name,
+ kpu_profile ? kpu_profile : default_pfl_name, KPU_NAME_LEN);
}
static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index c2cc4806d13c..10e58a5d5861 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -223,13 +223,17 @@ struct rvu_pfvf {
u16 maxlen;
u16 minlen;
- u8 pf_set_vf_cfg;
u8 mac_addr[ETH_ALEN]; /* MAC address of this PF/VF */
u8 default_mac[ETH_ALEN]; /* MAC address from FWdata */
- /* Broadcast pkt replication info */
+ /* Broadcast/Multicast/Promisc pkt replication info */
u16 bcast_mce_idx;
+ u16 mcast_mce_idx;
+ u16 promisc_mce_idx;
struct nix_mce_list bcast_mce_list;
+ struct nix_mce_list mcast_mce_list;
+ struct nix_mce_list promisc_mce_list;
+ bool use_mce_list;
struct rvu_npc_mcam_rule *def_ucast_rule;
@@ -239,8 +243,19 @@ struct rvu_pfvf {
u8 nix_blkaddr; /* BLKADDR_NIX0/1 assigned to this PF */
u8 nix_rx_intf; /* NIX0_RX/NIX1_RX interface to NPC */
u8 nix_tx_intf; /* NIX0_TX/NIX1_TX interface to NPC */
+ u64 lmt_base_addr; /* Preseving the pcifunc's lmtst base addr*/
+ unsigned long flags;
};
+enum rvu_pfvf_flags {
+ NIXLF_INITIALIZED = 0,
+ PF_SET_VF_MAC,
+ PF_SET_VF_CFG,
+ PF_SET_VF_TRUSTED,
+};
+
+#define RVU_CLEAR_VF_PERM ~GENMASK(PF_SET_VF_TRUSTED, PF_SET_VF_MAC)
+
struct nix_txsch {
struct rsrc_bmap schq;
u8 lvl;
@@ -282,6 +297,13 @@ struct nix_txvlan {
struct mutex rsrc_lock; /* Serialize resource alloc/free */
};
+struct nix_ipolicer {
+ struct rsrc_bmap band_prof;
+ u16 *pfvf_map;
+ u16 *match_id;
+ u16 *ref_count;
+};
+
struct nix_hw {
int blkaddr;
struct rvu *rvu;
@@ -291,6 +313,7 @@ struct nix_hw {
struct nix_mark_format mark_format;
struct nix_lso lso;
struct nix_txvlan txvlan;
+ struct nix_ipolicer *ipolicer;
};
/* RVU block's capabilities or functionality,
@@ -308,6 +331,7 @@ struct hw_cap {
bool nix_rx_multicast; /* Rx packet replication support */
bool per_pf_mbox_regs; /* PF mbox specified in per PF registers ? */
bool programmable_chans; /* Channels programmable ? */
+ bool ipolicer;
};
struct rvu_hwinfo {
@@ -386,6 +410,7 @@ struct npc_kpu_profile_adapter {
const struct npc_kpu_profile_action *ikpu; /* array[pkinds] */
const struct npc_kpu_profile *kpu; /* array[kpus] */
struct npc_mcam_kex *mkex;
+ bool custom;
size_t pkinds;
size_t kpus;
};
@@ -435,9 +460,13 @@ struct rvu {
struct mutex cgx_cfg_lock; /* serialize cgx configuration */
char mkex_pfl_name[MKEX_NAME_LEN]; /* Configured MKEX profile name */
+ char kpu_pfl_name[KPU_NAME_LEN]; /* Configured KPU profile name */
/* Firmware data */
struct rvu_fwdata *fwdata;
+ void *kpu_fwdata;
+ size_t kpu_fwdata_sz;
+ void __iomem *kpu_prfl_addr;
/* NPC KPU data */
struct npc_kpu_profile_adapter kpu;
@@ -543,11 +572,16 @@ static inline u16 rvu_nix_chan_cpt(struct rvu *rvu, u8 chan)
/* Function Prototypes
* RVU
*/
-static inline int is_afvf(u16 pcifunc)
+static inline bool is_afvf(u16 pcifunc)
{
return !(pcifunc & ~RVU_PFVF_FUNC_MASK);
}
+static inline bool is_vf(u16 pcifunc)
+{
+ return !!(pcifunc & RVU_PFVF_FUNC_MASK);
+}
+
/* check if PF_FUNC is AF */
static inline bool is_pffunc_af(u16 pcifunc)
{
@@ -563,6 +597,7 @@ static inline bool is_rvu_fwdata_valid(struct rvu *rvu)
int rvu_alloc_bitmap(struct rsrc_bmap *rsrc);
int rvu_alloc_rsrc(struct rsrc_bmap *rsrc);
void rvu_free_rsrc(struct rsrc_bmap *rsrc, int id);
+bool is_rsrc_free(struct rsrc_bmap *rsrc, int id);
int rvu_rsrc_free_count(struct rsrc_bmap *rsrc);
int rvu_alloc_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc);
bool rvu_rsrc_check_contig(struct rsrc_bmap *rsrc, int nrsrc);
@@ -603,6 +638,12 @@ static inline void rvu_get_cgx_lmac_id(u8 map, u8 *cgx_id, u8 *lmac_id)
*lmac_id = (map & 0xF);
}
+static inline bool is_cgx_vf(struct rvu *rvu, u16 pcifunc)
+{
+ return ((pcifunc & RVU_PFVF_FUNC_MASK) &&
+ is_pf_cgxmapped(rvu, rvu_get_pf(pcifunc)));
+}
+
#define M(_name, _id, fn_name, req, rsp) \
int rvu_mbox_handler_ ## fn_name(struct rvu *, struct req *, struct rsp *);
MBOX_MESSAGES
@@ -616,6 +657,8 @@ void rvu_cgx_enadis_rx_bp(struct rvu *rvu, int pf, bool enable);
int rvu_cgx_start_stop_io(struct rvu *rvu, u16 pcifunc, bool start);
int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, int index,
int rxtxflag, u64 *stat);
+void rvu_cgx_disable_dmac_entries(struct rvu *rvu, u16 pcifunc);
+
/* NPA APIs */
int rvu_npa_init(struct rvu *rvu);
void rvu_npa_freemem(struct rvu *rvu);
@@ -632,10 +675,22 @@ void rvu_nix_freemem(struct rvu *rvu);
int rvu_get_nixlf_count(struct rvu *rvu);
void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int npalf);
int nix_get_nixlf(struct rvu *rvu, u16 pcifunc, int *nixlf, int *nix_blkaddr);
-int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add);
+int nix_update_mce_list(struct rvu *rvu, u16 pcifunc,
+ struct nix_mce_list *mce_list,
+ int mce_idx, int mcam_index, bool add);
+void nix_get_mce_list(struct rvu *rvu, u16 pcifunc, int type,
+ struct nix_mce_list **mce_list, int *mce_idx);
struct nix_hw *get_nix_hw(struct rvu_hwinfo *hw, int blkaddr);
int rvu_get_next_nix_blkaddr(struct rvu *rvu, int blkaddr);
void rvu_nix_reset_mac(struct rvu_pfvf *pfvf, int pcifunc);
+int nix_get_struct_ptrs(struct rvu *rvu, u16 pcifunc,
+ struct nix_hw **nix_hw, int *blkaddr);
+int rvu_nix_setup_ratelimit_aggr(struct rvu *rvu, u16 pcifunc,
+ u16 rq_idx, u16 match_id);
+int nix_aq_context_read(struct rvu *rvu, struct nix_hw *nix_hw,
+ struct nix_cn10k_aq_enq_req *aq_req,
+ struct nix_cn10k_aq_enq_rsp *aq_rsp,
+ u16 pcifunc, u8 ctype, u32 qidx);
/* NPC APIs */
int rvu_npc_init(struct rvu *rvu);
@@ -646,13 +701,19 @@ int npc_config_ts_kpuaction(struct rvu *rvu, int pf, u16 pcifunc, bool en);
void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc,
int nixlf, u64 chan, u8 *mac_addr);
void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc,
- int nixlf, u64 chan, u8 chan_cnt,
- bool allmulti);
-void rvu_npc_disable_promisc_entry(struct rvu *rvu, u16 pcifunc, int nixlf);
-void rvu_npc_enable_promisc_entry(struct rvu *rvu, u16 pcifunc, int nixlf);
+ int nixlf, u64 chan, u8 chan_cnt);
+void rvu_npc_enable_promisc_entry(struct rvu *rvu, u16 pcifunc, int nixlf,
+ bool enable);
void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc,
int nixlf, u64 chan);
-void rvu_npc_enable_bcast_entry(struct rvu *rvu, u16 pcifunc, bool enable);
+void rvu_npc_enable_bcast_entry(struct rvu *rvu, u16 pcifunc, int nixlf,
+ bool enable);
+void rvu_npc_install_allmulti_entry(struct rvu *rvu, u16 pcifunc, int nixlf,
+ u64 chan);
+void rvu_npc_enable_allmulti_entry(struct rvu *rvu, u16 pcifunc, int nixlf,
+ bool enable);
+void npc_enadis_default_mce_entry(struct rvu *rvu, u16 pcifunc,
+ int nixlf, int type, bool enable);
void rvu_npc_disable_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf);
void rvu_npc_free_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf);
void rvu_npc_disable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf);
@@ -683,6 +744,7 @@ void npc_read_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
bool is_mac_feature_supported(struct rvu *rvu, int pf, int feature);
u32 rvu_cgx_get_fifolen(struct rvu *rvu);
void *rvu_first_cgx_pdata(struct rvu *rvu);
+int cgxlmac_to_pf(struct rvu *rvu, int cgx_id, int lmac_id);
int npc_get_nixlf_mcam_index(struct npc_mcam *mcam, u16 pcifunc, int nixlf,
int type);
@@ -696,6 +758,9 @@ int rvu_cpt_lf_teardown(struct rvu *rvu, u16 pcifunc, int lf, int slot);
int rvu_set_channels_base(struct rvu *rvu);
void rvu_program_channels(struct rvu *rvu);
+/* CN10K RVU - LMT*/
+void rvu_reset_lmt_map_tbl(struct rvu *rvu, u16 pcifunc);
+
#ifdef CONFIG_DEBUG_FS
void rvu_dbg_init(struct rvu *rvu);
void rvu_dbg_exit(struct rvu *rvu);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
index 6e2bf4fcd29c..6cc8fbb7190c 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
@@ -63,7 +63,7 @@ static u16 cgxlmac_to_pfmap(struct rvu *rvu, u8 cgx_id, u8 lmac_id)
return rvu->cgxlmac2pf_map[CGX_OFFSET(cgx_id) + lmac_id];
}
-static int cgxlmac_to_pf(struct rvu *rvu, int cgx_id, int lmac_id)
+int cgxlmac_to_pf(struct rvu *rvu, int cgx_id, int lmac_id)
{
unsigned long pfmap;
@@ -454,6 +454,31 @@ int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start)
return 0;
}
+void rvu_cgx_disable_dmac_entries(struct rvu *rvu, u16 pcifunc)
+{
+ int pf = rvu_get_pf(pcifunc);
+ int i = 0, lmac_count = 0;
+ u8 max_dmac_filters;
+ u8 cgx_id, lmac_id;
+ void *cgx_dev;
+
+ if (!is_cgx_config_permitted(rvu, pcifunc))
+ return;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ cgx_dev = cgx_get_pdata(cgx_id);
+ lmac_count = cgx_get_lmac_cnt(cgx_dev);
+ max_dmac_filters = MAX_DMAC_ENTRIES_PER_CGX / lmac_count;
+
+ for (i = 0; i < max_dmac_filters; i++)
+ cgx_lmac_addr_del(cgx_id, lmac_id, i);
+
+ /* As cgx_lmac_addr_del does not clear entry for index 0
+ * so it needs to be done explicitly
+ */
+ cgx_lmac_addr_reset(cgx_id, lmac_id);
+}
+
int rvu_mbox_handler_cgx_start_rxtx(struct rvu *rvu, struct msg_req *req,
struct msg_rsp *rsp)
{
@@ -557,6 +582,63 @@ int rvu_mbox_handler_cgx_mac_addr_set(struct rvu *rvu,
return 0;
}
+int rvu_mbox_handler_cgx_mac_addr_add(struct rvu *rvu,
+ struct cgx_mac_addr_add_req *req,
+ struct cgx_mac_addr_add_rsp *rsp)
+{
+ int pf = rvu_get_pf(req->hdr.pcifunc);
+ u8 cgx_id, lmac_id;
+ int rc = 0;
+
+ if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
+ return -EPERM;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ rc = cgx_lmac_addr_add(cgx_id, lmac_id, req->mac_addr);
+ if (rc >= 0) {
+ rsp->index = rc;
+ return 0;
+ }
+
+ return rc;
+}
+
+int rvu_mbox_handler_cgx_mac_addr_del(struct rvu *rvu,
+ struct cgx_mac_addr_del_req *req,
+ struct msg_rsp *rsp)
+{
+ int pf = rvu_get_pf(req->hdr.pcifunc);
+ u8 cgx_id, lmac_id;
+
+ if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
+ return -EPERM;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ return cgx_lmac_addr_del(cgx_id, lmac_id, req->index);
+}
+
+int rvu_mbox_handler_cgx_mac_max_entries_get(struct rvu *rvu,
+ struct msg_req *req,
+ struct cgx_max_dmac_entries_get_rsp
+ *rsp)
+{
+ int pf = rvu_get_pf(req->hdr.pcifunc);
+ u8 cgx_id, lmac_id;
+
+ /* If msg is received from PFs(which are not mapped to CGX LMACs)
+ * or VF then no entries are allocated for DMAC filters at CGX level.
+ * So returning zero.
+ */
+ if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc)) {
+ rsp->max_dmac_filters = 0;
+ return 0;
+ }
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ rsp->max_dmac_filters = cgx_lmac_addr_max_entries_get(cgx_id, lmac_id);
+ return 0;
+}
+
int rvu_mbox_handler_cgx_mac_addr_get(struct rvu *rvu,
struct cgx_mac_addr_set_or_get *req,
struct cgx_mac_addr_set_or_get *rsp)
@@ -953,3 +1035,30 @@ int rvu_mbox_handler_cgx_set_link_mode(struct rvu *rvu,
rsp->status = cgx_set_link_mode(cgxd, req->args, cgx_idx, lmac);
return 0;
}
+
+int rvu_mbox_handler_cgx_mac_addr_reset(struct rvu *rvu, struct msg_req *req,
+ struct msg_rsp *rsp)
+{
+ int pf = rvu_get_pf(req->hdr.pcifunc);
+ u8 cgx_id, lmac_id;
+
+ if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
+ return -EPERM;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ return cgx_lmac_addr_reset(cgx_id, lmac_id);
+}
+
+int rvu_mbox_handler_cgx_mac_addr_update(struct rvu *rvu,
+ struct cgx_mac_addr_update_req *req,
+ struct msg_rsp *rsp)
+{
+ int pf = rvu_get_pf(req->hdr.pcifunc);
+ u8 cgx_id, lmac_id;
+
+ if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
+ return -EPERM;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ return cgx_lmac_addr_update(cgx_id, lmac_id, req->mac_addr, req->index);
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c
index 7d9e71c6965f..8d48b64485c6 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c
@@ -10,6 +10,206 @@
#include "cgx.h"
#include "rvu_reg.h"
+/* RVU LMTST */
+#define LMT_TBL_OP_READ 0
+#define LMT_TBL_OP_WRITE 1
+#define LMT_MAP_TABLE_SIZE (128 * 1024)
+#define LMT_MAPTBL_ENTRY_SIZE 16
+
+/* Function to perform operations (read/write) on lmtst map table */
+static int lmtst_map_table_ops(struct rvu *rvu, u32 index, u64 *val,
+ int lmt_tbl_op)
+{
+ void __iomem *lmt_map_base;
+ u64 tbl_base;
+
+ tbl_base = rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_MAP_BASE);
+
+ lmt_map_base = ioremap_wc(tbl_base, LMT_MAP_TABLE_SIZE);
+ if (!lmt_map_base) {
+ dev_err(rvu->dev, "Failed to setup lmt map table mapping!!\n");
+ return -ENOMEM;
+ }
+
+ if (lmt_tbl_op == LMT_TBL_OP_READ) {
+ *val = readq(lmt_map_base + index);
+ } else {
+ writeq((*val), (lmt_map_base + index));
+ /* Flushing the AP interceptor cache to make APR_LMT_MAP_ENTRY_S
+ * changes effective. Write 1 for flush and read is being used as a
+ * barrier and sets up a data dependency. Write to 0 after a write
+ * to 1 to complete the flush.
+ */
+ rvu_write64(rvu, BLKADDR_APR, APR_AF_LMT_CTL, BIT_ULL(0));
+ rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_CTL);
+ rvu_write64(rvu, BLKADDR_APR, APR_AF_LMT_CTL, 0x00);
+ }
+
+ iounmap(lmt_map_base);
+ return 0;
+}
+
+static u32 rvu_get_lmtst_tbl_index(struct rvu *rvu, u16 pcifunc)
+{
+ return ((rvu_get_pf(pcifunc) * rvu->hw->total_vfs) +
+ (pcifunc & RVU_PFVF_FUNC_MASK)) * LMT_MAPTBL_ENTRY_SIZE;
+}
+
+static int rvu_get_lmtaddr(struct rvu *rvu, u16 pcifunc,
+ u64 iova, u64 *lmt_addr)
+{
+ u64 pa, val, pf;
+ int err;
+
+ if (!iova) {
+ dev_err(rvu->dev, "%s Requested Null address for transulation\n", __func__);
+ return -EINVAL;
+ }
+
+ rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_ADDR_REQ, iova);
+ pf = rvu_get_pf(pcifunc) & 0x1F;
+ val = BIT_ULL(63) | BIT_ULL(14) | BIT_ULL(13) | pf << 8 |
+ ((pcifunc & RVU_PFVF_FUNC_MASK) & 0xFF);
+ rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_TXN_REQ, val);
+
+ err = rvu_poll_reg(rvu, BLKADDR_RVUM, RVU_AF_SMMU_ADDR_RSP_STS, BIT_ULL(0), false);
+ if (err) {
+ dev_err(rvu->dev, "%s LMTLINE iova transulation failed\n", __func__);
+ return err;
+ }
+ val = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_ADDR_RSP_STS);
+ if (val & ~0x1ULL) {
+ dev_err(rvu->dev, "%s LMTLINE iova transulation failed err:%llx\n", __func__, val);
+ return -EIO;
+ }
+ /* PA[51:12] = RVU_AF_SMMU_TLN_FLIT1[60:21]
+ * PA[11:0] = IOVA[11:0]
+ */
+ pa = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_SMMU_TLN_FLIT1) >> 21;
+ pa &= GENMASK_ULL(39, 0);
+ *lmt_addr = (pa << 12) | (iova & 0xFFF);
+
+ return 0;
+}
+
+static int rvu_update_lmtaddr(struct rvu *rvu, u16 pcifunc, u64 lmt_addr)
+{
+ struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
+ u32 tbl_idx;
+ int err = 0;
+ u64 val;
+
+ /* Read the current lmt addr of pcifunc */
+ tbl_idx = rvu_get_lmtst_tbl_index(rvu, pcifunc);
+ err = lmtst_map_table_ops(rvu, tbl_idx, &val, LMT_TBL_OP_READ);
+ if (err) {
+ dev_err(rvu->dev,
+ "Failed to read LMT map table: index 0x%x err %d\n",
+ tbl_idx, err);
+ return err;
+ }
+
+ /* Storing the seondary's lmt base address as this needs to be
+ * reverted in FLR. Also making sure this default value doesn't
+ * get overwritten on multiple calls to this mailbox.
+ */
+ if (!pfvf->lmt_base_addr)
+ pfvf->lmt_base_addr = val;
+
+ /* Update the LMT table with new addr */
+ err = lmtst_map_table_ops(rvu, tbl_idx, &lmt_addr, LMT_TBL_OP_WRITE);
+ if (err) {
+ dev_err(rvu->dev,
+ "Failed to update LMT map table: index 0x%x err %d\n",
+ tbl_idx, err);
+ return err;
+ }
+ return 0;
+}
+
+int rvu_mbox_handler_lmtst_tbl_setup(struct rvu *rvu,
+ struct lmtst_tbl_setup_req *req,
+ struct msg_rsp *rsp)
+{
+ u64 lmt_addr, val;
+ u32 pri_tbl_idx;
+ int err = 0;
+
+ /* Check if PF_FUNC wants to use it's own local memory as LMTLINE
+ * region, if so, convert that IOVA to physical address and
+ * populate LMT table with that address
+ */
+ if (req->use_local_lmt_region) {
+ err = rvu_get_lmtaddr(rvu, req->hdr.pcifunc,
+ req->lmt_iova, &lmt_addr);
+ if (err < 0)
+ return err;
+
+ /* Update the lmt addr for this PFFUNC in the LMT table */
+ err = rvu_update_lmtaddr(rvu, req->hdr.pcifunc, lmt_addr);
+ if (err)
+ return err;
+ }
+
+ /* Reconfiguring lmtst map table in lmt region shared mode i.e. make
+ * multiple PF_FUNCs to share an LMTLINE region, so primary/base
+ * pcifunc (which is passed as an argument to mailbox) is the one
+ * whose lmt base address will be shared among other secondary
+ * pcifunc (will be the one who is calling this mailbox).
+ */
+ if (req->base_pcifunc) {
+ /* Calculating the LMT table index equivalent to primary
+ * pcifunc.
+ */
+ pri_tbl_idx = rvu_get_lmtst_tbl_index(rvu, req->base_pcifunc);
+
+ /* Read the base lmt addr of the primary pcifunc */
+ err = lmtst_map_table_ops(rvu, pri_tbl_idx, &val,
+ LMT_TBL_OP_READ);
+ if (err) {
+ dev_err(rvu->dev,
+ "Failed to read LMT map table: index 0x%x err %d\n",
+ pri_tbl_idx, err);
+ return err;
+ }
+
+ /* Update the base lmt addr of secondary with primary's base
+ * lmt addr.
+ */
+ err = rvu_update_lmtaddr(rvu, req->hdr.pcifunc, val);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/* Resetting the lmtst map table to original base addresses */
+void rvu_reset_lmt_map_tbl(struct rvu *rvu, u16 pcifunc)
+{
+ struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
+ u32 tbl_idx;
+ int err;
+
+ if (is_rvu_otx2(rvu))
+ return;
+
+ if (pfvf->lmt_base_addr) {
+ /* This corresponds to lmt map table index */
+ tbl_idx = rvu_get_lmtst_tbl_index(rvu, pcifunc);
+ /* Reverting back original lmt base addr for respective
+ * pcifunc.
+ */
+ err = lmtst_map_table_ops(rvu, tbl_idx, &pfvf->lmt_base_addr,
+ LMT_TBL_OP_WRITE);
+ if (err)
+ dev_err(rvu->dev,
+ "Failed to update LMT map table: index 0x%x err %d\n",
+ tbl_idx, err);
+ pfvf->lmt_base_addr = 0;
+ }
+}
+
int rvu_set_channels_base(struct rvu *rvu)
{
struct rvu_hwinfo *hw = rvu->hw;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
index 9bf8eaabf9ab..370d4ca1e5ed 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
@@ -1632,6 +1632,165 @@ static int rvu_dbg_nix_qsize_display(struct seq_file *filp, void *unused)
RVU_DEBUG_SEQ_FOPS(nix_qsize, nix_qsize_display, nix_qsize_write);
+static void print_band_prof_ctx(struct seq_file *m,
+ struct nix_bandprof_s *prof)
+{
+ char *str;
+
+ switch (prof->pc_mode) {
+ case NIX_RX_PC_MODE_VLAN:
+ str = "VLAN";
+ break;
+ case NIX_RX_PC_MODE_DSCP:
+ str = "DSCP";
+ break;
+ case NIX_RX_PC_MODE_GEN:
+ str = "Generic";
+ break;
+ case NIX_RX_PC_MODE_RSVD:
+ str = "Reserved";
+ break;
+ }
+ seq_printf(m, "W0: pc_mode\t\t%s\n", str);
+ str = (prof->icolor == 3) ? "Color blind" :
+ (prof->icolor == 0) ? "Green" :
+ (prof->icolor == 1) ? "Yellow" : "Red";
+ seq_printf(m, "W0: icolor\t\t%s\n", str);
+ seq_printf(m, "W0: tnl_ena\t\t%d\n", prof->tnl_ena);
+ seq_printf(m, "W0: peir_exponent\t%d\n", prof->peir_exponent);
+ seq_printf(m, "W0: pebs_exponent\t%d\n", prof->pebs_exponent);
+ seq_printf(m, "W0: cir_exponent\t%d\n", prof->cir_exponent);
+ seq_printf(m, "W0: cbs_exponent\t%d\n", prof->cbs_exponent);
+ seq_printf(m, "W0: peir_mantissa\t%d\n", prof->peir_mantissa);
+ seq_printf(m, "W0: pebs_mantissa\t%d\n", prof->pebs_mantissa);
+ seq_printf(m, "W0: cir_mantissa\t%d\n", prof->cir_mantissa);
+
+ seq_printf(m, "W1: cbs_mantissa\t%d\n", prof->cbs_mantissa);
+ str = (prof->lmode == 0) ? "byte" : "packet";
+ seq_printf(m, "W1: lmode\t\t%s\n", str);
+ seq_printf(m, "W1: l_select\t\t%d\n", prof->l_sellect);
+ seq_printf(m, "W1: rdiv\t\t%d\n", prof->rdiv);
+ seq_printf(m, "W1: adjust_exponent\t%d\n", prof->adjust_exponent);
+ seq_printf(m, "W1: adjust_mantissa\t%d\n", prof->adjust_mantissa);
+ str = (prof->gc_action == 0) ? "PASS" :
+ (prof->gc_action == 1) ? "DROP" : "RED";
+ seq_printf(m, "W1: gc_action\t\t%s\n", str);
+ str = (prof->yc_action == 0) ? "PASS" :
+ (prof->yc_action == 1) ? "DROP" : "RED";
+ seq_printf(m, "W1: yc_action\t\t%s\n", str);
+ str = (prof->rc_action == 0) ? "PASS" :
+ (prof->rc_action == 1) ? "DROP" : "RED";
+ seq_printf(m, "W1: rc_action\t\t%s\n", str);
+ seq_printf(m, "W1: meter_algo\t\t%d\n", prof->meter_algo);
+ seq_printf(m, "W1: band_prof_id\t%d\n", prof->band_prof_id);
+ seq_printf(m, "W1: hl_en\t\t%d\n", prof->hl_en);
+
+ seq_printf(m, "W2: ts\t\t\t%lld\n", (u64)prof->ts);
+ seq_printf(m, "W3: pe_accum\t\t%d\n", prof->pe_accum);
+ seq_printf(m, "W3: c_accum\t\t%d\n", prof->c_accum);
+ seq_printf(m, "W4: green_pkt_pass\t%lld\n",
+ (u64)prof->green_pkt_pass);
+ seq_printf(m, "W5: yellow_pkt_pass\t%lld\n",
+ (u64)prof->yellow_pkt_pass);
+ seq_printf(m, "W6: red_pkt_pass\t%lld\n", (u64)prof->red_pkt_pass);
+ seq_printf(m, "W7: green_octs_pass\t%lld\n",
+ (u64)prof->green_octs_pass);
+ seq_printf(m, "W8: yellow_octs_pass\t%lld\n",
+ (u64)prof->yellow_octs_pass);
+ seq_printf(m, "W9: red_octs_pass\t%lld\n", (u64)prof->red_octs_pass);
+ seq_printf(m, "W10: green_pkt_drop\t%lld\n",
+ (u64)prof->green_pkt_drop);
+ seq_printf(m, "W11: yellow_pkt_drop\t%lld\n",
+ (u64)prof->yellow_pkt_drop);
+ seq_printf(m, "W12: red_pkt_drop\t%lld\n", (u64)prof->red_pkt_drop);
+ seq_printf(m, "W13: green_octs_drop\t%lld\n",
+ (u64)prof->green_octs_drop);
+ seq_printf(m, "W14: yellow_octs_drop\t%lld\n",
+ (u64)prof->yellow_octs_drop);
+ seq_printf(m, "W15: red_octs_drop\t%lld\n", (u64)prof->red_octs_drop);
+ seq_puts(m, "==============================\n");
+}
+
+static int rvu_dbg_nix_band_prof_ctx_display(struct seq_file *m, void *unused)
+{
+ struct nix_hw *nix_hw = m->private;
+ struct nix_cn10k_aq_enq_req aq_req;
+ struct nix_cn10k_aq_enq_rsp aq_rsp;
+ struct rvu *rvu = nix_hw->rvu;
+ struct nix_ipolicer *ipolicer;
+ int layer, prof_idx, idx, rc;
+ u16 pcifunc;
+ char *str;
+
+ for (layer = 0; layer < BAND_PROF_NUM_LAYERS; layer++) {
+ if (layer == BAND_PROF_INVAL_LAYER)
+ continue;
+ str = (layer == BAND_PROF_LEAF_LAYER) ? "Leaf" :
+ (layer == BAND_PROF_MID_LAYER) ? "Mid" : "Top";
+
+ seq_printf(m, "\n%s bandwidth profiles\n", str);
+ seq_puts(m, "=======================\n");
+
+ ipolicer = &nix_hw->ipolicer[layer];
+
+ for (idx = 0; idx < ipolicer->band_prof.max; idx++) {
+ if (is_rsrc_free(&ipolicer->band_prof, idx))
+ continue;
+
+ prof_idx = (idx & 0x3FFF) | (layer << 14);
+ rc = nix_aq_context_read(rvu, nix_hw, &aq_req, &aq_rsp,
+ 0x00, NIX_AQ_CTYPE_BANDPROF,
+ prof_idx);
+ if (rc) {
+ dev_err(rvu->dev,
+ "%s: Failed to fetch context of %s profile %d, err %d\n",
+ __func__, str, idx, rc);
+ return 0;
+ }
+ seq_printf(m, "\n%s bandwidth profile:: %d\n", str, idx);
+ pcifunc = ipolicer->pfvf_map[idx];
+ if (!(pcifunc & RVU_PFVF_FUNC_MASK))
+ seq_printf(m, "Allocated to :: PF %d\n",
+ rvu_get_pf(pcifunc));
+ else
+ seq_printf(m, "Allocated to :: PF %d VF %d\n",
+ rvu_get_pf(pcifunc),
+ (pcifunc & RVU_PFVF_FUNC_MASK) - 1);
+ print_band_prof_ctx(m, &aq_rsp.prof);
+ }
+ }
+ return 0;
+}
+
+RVU_DEBUG_SEQ_FOPS(nix_band_prof_ctx, nix_band_prof_ctx_display, NULL);
+
+static int rvu_dbg_nix_band_prof_rsrc_display(struct seq_file *m, void *unused)
+{
+ struct nix_hw *nix_hw = m->private;
+ struct nix_ipolicer *ipolicer;
+ int layer;
+ char *str;
+
+ seq_puts(m, "\nBandwidth profile resource free count\n");
+ seq_puts(m, "=====================================\n");
+ for (layer = 0; layer < BAND_PROF_NUM_LAYERS; layer++) {
+ if (layer == BAND_PROF_INVAL_LAYER)
+ continue;
+ str = (layer == BAND_PROF_LEAF_LAYER) ? "Leaf" :
+ (layer == BAND_PROF_MID_LAYER) ? "Mid " : "Top ";
+
+ ipolicer = &nix_hw->ipolicer[layer];
+ seq_printf(m, "%s :: Max: %4d Free: %4d\n", str,
+ ipolicer->band_prof.max,
+ rvu_rsrc_free_count(&ipolicer->band_prof));
+ }
+ seq_puts(m, "=====================================\n");
+
+ return 0;
+}
+
+RVU_DEBUG_SEQ_FOPS(nix_band_prof_rsrc, nix_band_prof_rsrc_display, NULL);
+
static void rvu_dbg_nix_init(struct rvu *rvu, int blkaddr)
{
struct nix_hw *nix_hw;
@@ -1664,6 +1823,10 @@ static void rvu_dbg_nix_init(struct rvu *rvu, int blkaddr)
&rvu_dbg_nix_ndc_rx_hits_miss_fops);
debugfs_create_file("qsize", 0600, rvu->rvu_dbg.nix, rvu,
&rvu_dbg_nix_qsize_fops);
+ debugfs_create_file("ingress_policer_ctx", 0600, rvu->rvu_dbg.nix, nix_hw,
+ &rvu_dbg_nix_band_prof_ctx_fops);
+ debugfs_create_file("ingress_policer_rsrc", 0600, rvu->rvu_dbg.nix, nix_hw,
+ &rvu_dbg_nix_band_prof_rsrc_fops);
}
static void rvu_dbg_npa_init(struct rvu *rvu)
@@ -1808,10 +1971,9 @@ static int cgx_print_stats(struct seq_file *s, int lmac_id)
return err;
}
-static int rvu_dbg_cgx_stat_display(struct seq_file *filp, void *unused)
+static int rvu_dbg_derive_lmacid(struct seq_file *filp, int *lmac_id)
{
struct dentry *current_dir;
- int err, lmac_id;
char *buf;
current_dir = filp->file->f_path.dentry->d_parent;
@@ -1819,17 +1981,87 @@ static int rvu_dbg_cgx_stat_display(struct seq_file *filp, void *unused)
if (!buf)
return -EINVAL;
- err = kstrtoint(buf + 1, 10, &lmac_id);
- if (!err) {
- err = cgx_print_stats(filp, lmac_id);
- if (err)
- return err;
- }
+ return kstrtoint(buf + 1, 10, lmac_id);
+}
+
+static int rvu_dbg_cgx_stat_display(struct seq_file *filp, void *unused)
+{
+ int lmac_id, err;
+
+ err = rvu_dbg_derive_lmacid(filp, &lmac_id);
+ if (!err)
+ return cgx_print_stats(filp, lmac_id);
+
return err;
}
RVU_DEBUG_SEQ_FOPS(cgx_stat, cgx_stat_display, NULL);
+static int cgx_print_dmac_flt(struct seq_file *s, int lmac_id)
+{
+ struct pci_dev *pdev = NULL;
+ void *cgxd = s->private;
+ char *bcast, *mcast;
+ u16 index, domain;
+ u8 dmac[ETH_ALEN];
+ struct rvu *rvu;
+ u64 cfg, mac;
+ int pf;
+
+ rvu = pci_get_drvdata(pci_get_device(PCI_VENDOR_ID_CAVIUM,
+ PCI_DEVID_OCTEONTX2_RVU_AF, NULL));
+ if (!rvu)
+ return -ENODEV;
+
+ pf = cgxlmac_to_pf(rvu, cgx_get_cgxid(cgxd), lmac_id);
+ domain = 2;
+
+ pdev = pci_get_domain_bus_and_slot(domain, pf + 1, 0);
+ if (!pdev)
+ return 0;
+
+ cfg = cgx_read_dmac_ctrl(cgxd, lmac_id);
+ bcast = cfg & CGX_DMAC_BCAST_MODE ? "ACCEPT" : "REJECT";
+ mcast = cfg & CGX_DMAC_MCAST_MODE ? "ACCEPT" : "REJECT";
+
+ seq_puts(s,
+ "PCI dev RVUPF BROADCAST MULTICAST FILTER-MODE\n");
+ seq_printf(s, "%s PF%d %9s %9s",
+ dev_name(&pdev->dev), pf, bcast, mcast);
+ if (cfg & CGX_DMAC_CAM_ACCEPT)
+ seq_printf(s, "%12s\n\n", "UNICAST");
+ else
+ seq_printf(s, "%16s\n\n", "PROMISCUOUS");
+
+ seq_puts(s, "\nDMAC-INDEX ADDRESS\n");
+
+ for (index = 0 ; index < 32 ; index++) {
+ cfg = cgx_read_dmac_entry(cgxd, index);
+ /* Display enabled dmac entries associated with current lmac */
+ if (lmac_id == FIELD_GET(CGX_DMAC_CAM_ENTRY_LMACID, cfg) &&
+ FIELD_GET(CGX_DMAC_CAM_ADDR_ENABLE, cfg)) {
+ mac = FIELD_GET(CGX_RX_DMAC_ADR_MASK, cfg);
+ u64_to_ether_addr(mac, dmac);
+ seq_printf(s, "%7d %pM\n", index, dmac);
+ }
+ }
+
+ return 0;
+}
+
+static int rvu_dbg_cgx_dmac_flt_display(struct seq_file *filp, void *unused)
+{
+ int err, lmac_id;
+
+ err = rvu_dbg_derive_lmacid(filp, &lmac_id);
+ if (!err)
+ return cgx_print_dmac_flt(filp, lmac_id);
+
+ return err;
+}
+
+RVU_DEBUG_SEQ_FOPS(cgx_dmac_flt, cgx_dmac_flt_display, NULL);
+
static void rvu_dbg_cgx_init(struct rvu *rvu)
{
struct mac_ops *mac_ops;
@@ -1866,6 +2098,9 @@ static void rvu_dbg_cgx_init(struct rvu *rvu)
debugfs_create_file("stats", 0600, rvu->rvu_dbg.lmac,
cgx, &rvu_dbg_cgx_stat_fops);
+ debugfs_create_file("mac_filter", 0600,
+ rvu->rvu_dbg.lmac, cgx,
+ &rvu_dbg_cgx_dmac_flt_fops);
}
}
}
@@ -2132,6 +2367,7 @@ static int rvu_dbg_npc_mcam_show_rules(struct seq_file *s, void *unused)
struct rvu *rvu = s->private;
struct npc_mcam *mcam;
int pf, vf = -1;
+ bool enabled;
int blkaddr;
u16 target;
u64 hits;
@@ -2173,7 +2409,9 @@ static int rvu_dbg_npc_mcam_show_rules(struct seq_file *s, void *unused)
}
rvu_dbg_npc_mcam_show_action(s, iter);
- seq_printf(s, "\tenabled: %s\n", iter->enable ? "yes" : "no");
+
+ enabled = is_mcam_entry_enabled(rvu, mcam, blkaddr, iter->entry);
+ seq_printf(s, "\tenabled: %s\n", enabled ? "yes" : "no");
if (!iter->has_cntr)
continue;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index 0a8bd667cb11..aeae37704428 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -21,6 +21,16 @@
static void nix_free_tx_vtag_entries(struct rvu *rvu, u16 pcifunc);
static int rvu_nix_get_bpid(struct rvu *rvu, struct nix_bp_cfg_req *req,
int type, int chan_id);
+static int nix_update_mce_rule(struct rvu *rvu, u16 pcifunc,
+ int type, bool add);
+static int nix_setup_ipolicers(struct rvu *rvu,
+ struct nix_hw *nix_hw, int blkaddr);
+static void nix_ipolicer_freemem(struct nix_hw *nix_hw);
+static int nix_verify_bandprof(struct nix_cn10k_aq_enq_req *req,
+ struct nix_hw *nix_hw, u16 pcifunc);
+static int nix_free_all_bandprof(struct rvu *rvu, u16 pcifunc);
+static void nix_clear_ratelimit_aggr(struct rvu *rvu, struct nix_hw *nix_hw,
+ u32 leaf_prof);
enum mc_tbl_sz {
MC_TBL_SZ_256,
@@ -132,6 +142,22 @@ int nix_get_nixlf(struct rvu *rvu, u16 pcifunc, int *nixlf, int *nix_blkaddr)
return 0;
}
+int nix_get_struct_ptrs(struct rvu *rvu, u16 pcifunc,
+ struct nix_hw **nix_hw, int *blkaddr)
+{
+ struct rvu_pfvf *pfvf;
+
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+ *blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+ if (!pfvf->nixlf || *blkaddr < 0)
+ return NIX_AF_ERR_AF_LF_INVALID;
+
+ *nix_hw = get_nix_hw(rvu->hw, *blkaddr);
+ if (!*nix_hw)
+ return NIX_AF_ERR_INVALID_NIXBLK;
+ return 0;
+}
+
static void nix_mce_list_init(struct nix_mce_list *list, int max)
{
INIT_HLIST_HEAD(&list->head);
@@ -274,7 +300,7 @@ static int nix_interface_init(struct rvu *rvu, u16 pcifunc, int type, int nixlf)
pfvf->tx_chan_cnt = 1;
rvu_npc_install_promisc_entry(rvu, pcifunc, nixlf,
pfvf->rx_chan_base,
- pfvf->rx_chan_cnt, false);
+ pfvf->rx_chan_cnt);
break;
}
@@ -285,16 +311,17 @@ static int nix_interface_init(struct rvu *rvu, u16 pcifunc, int type, int nixlf)
pfvf->rx_chan_base, pfvf->mac_addr);
/* Add this PF_FUNC to bcast pkt replication list */
- err = nix_update_bcast_mce_list(rvu, pcifunc, true);
+ err = nix_update_mce_rule(rvu, pcifunc, NIXLF_BCAST_ENTRY, true);
if (err) {
dev_err(rvu->dev,
"Bcast list, failed to enable PF_FUNC 0x%x\n",
pcifunc);
return err;
}
-
+ /* Install MCAM rule matching Ethernet broadcast mac address */
rvu_npc_install_bcast_match_entry(rvu, pcifunc,
nixlf, pfvf->rx_chan_base);
+
pfvf->maxlen = NIC_HW_MIN_FRS;
pfvf->minlen = NIC_HW_MIN_FRS;
@@ -310,7 +337,7 @@ static void nix_interface_deinit(struct rvu *rvu, u16 pcifunc, u8 nixlf)
pfvf->minlen = 0;
/* Remove this PF_FUNC from bcast pkt replication list */
- err = nix_update_bcast_mce_list(rvu, pcifunc, false);
+ err = nix_update_mce_rule(rvu, pcifunc, NIXLF_BCAST_ENTRY, false);
if (err) {
dev_err(rvu->dev,
"Bcast list, failed to disable PF_FUNC 0x%x\n",
@@ -319,6 +346,9 @@ static void nix_interface_deinit(struct rvu *rvu, u16 pcifunc, u8 nixlf)
/* Free and disable any MCAM entries used by this NIX LF */
rvu_npc_disable_mcam_entries(rvu, pcifunc, nixlf);
+
+ /* Disable DMAC filters used */
+ rvu_cgx_disable_dmac_entries(rvu, pcifunc);
}
int rvu_mbox_handler_nix_bp_disable(struct rvu *rvu,
@@ -680,8 +710,11 @@ static int rvu_nix_blk_aq_enq_inst(struct rvu *rvu, struct nix_hw *nix_hw,
pfvf = rvu_get_pfvf(rvu, pcifunc);
nixlf = rvu_get_lf(rvu, block, pcifunc, 0);
- /* Skip NIXLF check for broadcast MCE entry init */
- if (!(!rsp && req->ctype == NIX_AQ_CTYPE_MCE)) {
+ /* Skip NIXLF check for broadcast MCE entry and bandwidth profile
+ * operations done by AF itself.
+ */
+ if (!((!rsp && req->ctype == NIX_AQ_CTYPE_MCE) ||
+ (req->ctype == NIX_AQ_CTYPE_BANDPROF && !pcifunc))) {
if (!pfvf->nixlf || nixlf < 0)
return NIX_AF_ERR_AF_LF_INVALID;
}
@@ -721,6 +754,11 @@ static int rvu_nix_blk_aq_enq_inst(struct rvu *rvu, struct nix_hw *nix_hw,
if (rsp)
rc = NIX_AF_ERR_AQ_ENQUEUE;
break;
+ case NIX_AQ_CTYPE_BANDPROF:
+ if (nix_verify_bandprof((struct nix_cn10k_aq_enq_req *)req,
+ nix_hw, pcifunc))
+ rc = NIX_AF_ERR_INVALID_BANDPROF;
+ break;
default:
rc = NIX_AF_ERR_AQ_ENQUEUE;
}
@@ -777,6 +815,9 @@ static int rvu_nix_blk_aq_enq_inst(struct rvu *rvu, struct nix_hw *nix_hw,
else if (req->ctype == NIX_AQ_CTYPE_MCE)
memcpy(mask, &req->mce_mask,
sizeof(struct nix_rx_mce_s));
+ else if (req->ctype == NIX_AQ_CTYPE_BANDPROF)
+ memcpy(mask, &req->prof_mask,
+ sizeof(struct nix_bandprof_s));
fallthrough;
case NIX_AQ_INSTOP_INIT:
if (req->ctype == NIX_AQ_CTYPE_RQ)
@@ -789,6 +830,8 @@ static int rvu_nix_blk_aq_enq_inst(struct rvu *rvu, struct nix_hw *nix_hw,
memcpy(ctx, &req->rss, sizeof(struct nix_rsse_s));
else if (req->ctype == NIX_AQ_CTYPE_MCE)
memcpy(ctx, &req->mce, sizeof(struct nix_rx_mce_s));
+ else if (req->ctype == NIX_AQ_CTYPE_BANDPROF)
+ memcpy(ctx, &req->prof, sizeof(struct nix_bandprof_s));
break;
case NIX_AQ_INSTOP_NOP:
case NIX_AQ_INSTOP_READ:
@@ -866,6 +909,9 @@ static int rvu_nix_blk_aq_enq_inst(struct rvu *rvu, struct nix_hw *nix_hw,
else if (req->ctype == NIX_AQ_CTYPE_MCE)
memcpy(&rsp->mce, ctx,
sizeof(struct nix_rx_mce_s));
+ else if (req->ctype == NIX_AQ_CTYPE_BANDPROF)
+ memcpy(&rsp->prof, ctx,
+ sizeof(struct nix_bandprof_s));
}
}
@@ -2203,8 +2249,8 @@ static int nix_blk_setup_mce(struct rvu *rvu, struct nix_hw *nix_hw,
aq_req.op = op;
aq_req.qidx = mce;
- /* Forward bcast pkts to RQ0, RSS not needed */
- aq_req.mce.op = 0;
+ /* Use RSS with RSS index 0 */
+ aq_req.mce.op = 1;
aq_req.mce.index = 0;
aq_req.mce.eol = eol;
aq_req.mce.pf_func = pcifunc;
@@ -2222,8 +2268,8 @@ static int nix_blk_setup_mce(struct rvu *rvu, struct nix_hw *nix_hw,
return 0;
}
-static int nix_update_mce_list(struct nix_mce_list *mce_list,
- u16 pcifunc, bool add)
+static int nix_update_mce_list_entry(struct nix_mce_list *mce_list,
+ u16 pcifunc, bool add)
{
struct mce *mce, *tail = NULL;
bool delete = false;
@@ -2234,6 +2280,9 @@ static int nix_update_mce_list(struct nix_mce_list *mce_list,
if (mce->pcifunc == pcifunc && !add) {
delete = true;
break;
+ } else if (mce->pcifunc == pcifunc && add) {
+ /* entry already exists */
+ return 0;
}
tail = mce;
}
@@ -2261,36 +2310,23 @@ static int nix_update_mce_list(struct nix_mce_list *mce_list,
return 0;
}
-int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add)
+int nix_update_mce_list(struct rvu *rvu, u16 pcifunc,
+ struct nix_mce_list *mce_list,
+ int mce_idx, int mcam_index, bool add)
{
- int err = 0, idx, next_idx, last_idx;
- struct nix_mce_list *mce_list;
+ int err = 0, idx, next_idx, last_idx, blkaddr, npc_blkaddr;
+ struct npc_mcam *mcam = &rvu->hw->mcam;
struct nix_mcast *mcast;
struct nix_hw *nix_hw;
- struct rvu_pfvf *pfvf;
struct mce *mce;
- int blkaddr;
-
- /* Broadcast pkt replication is not needed for AF's VFs, hence skip */
- if (is_afvf(pcifunc))
- return 0;
-
- blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
- if (blkaddr < 0)
- return 0;
- nix_hw = get_nix_hw(rvu->hw, blkaddr);
- if (!nix_hw)
- return 0;
-
- mcast = &nix_hw->mcast;
+ if (!mce_list)
+ return -EINVAL;
/* Get this PF/VF func's MCE index */
- pfvf = rvu_get_pfvf(rvu, pcifunc & ~RVU_PFVF_FUNC_MASK);
- idx = pfvf->bcast_mce_idx + (pcifunc & RVU_PFVF_FUNC_MASK);
+ idx = mce_idx + (pcifunc & RVU_PFVF_FUNC_MASK);
- mce_list = &pfvf->bcast_mce_list;
- if (idx > (pfvf->bcast_mce_idx + mce_list->max)) {
+ if (idx > (mce_idx + mce_list->max)) {
dev_err(rvu->dev,
"%s: Idx %d > max MCE idx %d, for PF%d bcast list\n",
__func__, idx, mce_list->max,
@@ -2298,20 +2334,26 @@ int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add)
return -EINVAL;
}
+ err = nix_get_struct_ptrs(rvu, pcifunc, &nix_hw, &blkaddr);
+ if (err)
+ return err;
+
+ mcast = &nix_hw->mcast;
mutex_lock(&mcast->mce_lock);
- err = nix_update_mce_list(mce_list, pcifunc, add);
+ err = nix_update_mce_list_entry(mce_list, pcifunc, add);
if (err)
goto end;
/* Disable MCAM entry in NPC */
if (!mce_list->count) {
- rvu_npc_enable_bcast_entry(rvu, pcifunc, false);
+ npc_blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ npc_enable_mcam_entry(rvu, mcam, npc_blkaddr, mcam_index, false);
goto end;
}
/* Dump the updated list to HW */
- idx = pfvf->bcast_mce_idx;
+ idx = mce_idx;
last_idx = idx + mce_list->count - 1;
hlist_for_each_entry(mce, &mce_list->head, node) {
if (idx > last_idx)
@@ -2332,7 +2374,71 @@ end:
return err;
}
-static int nix_setup_bcast_tables(struct rvu *rvu, struct nix_hw *nix_hw)
+void nix_get_mce_list(struct rvu *rvu, u16 pcifunc, int type,
+ struct nix_mce_list **mce_list, int *mce_idx)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ struct rvu_pfvf *pfvf;
+
+ if (!hw->cap.nix_rx_multicast ||
+ !is_pf_cgxmapped(rvu, rvu_get_pf(pcifunc & ~RVU_PFVF_FUNC_MASK))) {
+ *mce_list = NULL;
+ *mce_idx = 0;
+ return;
+ }
+
+ /* Get this PF/VF func's MCE index */
+ pfvf = rvu_get_pfvf(rvu, pcifunc & ~RVU_PFVF_FUNC_MASK);
+
+ if (type == NIXLF_BCAST_ENTRY) {
+ *mce_list = &pfvf->bcast_mce_list;
+ *mce_idx = pfvf->bcast_mce_idx;
+ } else if (type == NIXLF_ALLMULTI_ENTRY) {
+ *mce_list = &pfvf->mcast_mce_list;
+ *mce_idx = pfvf->mcast_mce_idx;
+ } else if (type == NIXLF_PROMISC_ENTRY) {
+ *mce_list = &pfvf->promisc_mce_list;
+ *mce_idx = pfvf->promisc_mce_idx;
+ } else {
+ *mce_list = NULL;
+ *mce_idx = 0;
+ }
+}
+
+static int nix_update_mce_rule(struct rvu *rvu, u16 pcifunc,
+ int type, bool add)
+{
+ int err = 0, nixlf, blkaddr, mcam_index, mce_idx;
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct rvu_hwinfo *hw = rvu->hw;
+ struct nix_mce_list *mce_list;
+
+ /* skip multicast pkt replication for AF's VFs */
+ if (is_afvf(pcifunc))
+ return 0;
+
+ if (!hw->cap.nix_rx_multicast)
+ return 0;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+ if (blkaddr < 0)
+ return -EINVAL;
+
+ nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0);
+ if (nixlf < 0)
+ return -EINVAL;
+
+ nix_get_mce_list(rvu, pcifunc, type, &mce_list, &mce_idx);
+
+ mcam_index = npc_get_nixlf_mcam_index(mcam,
+ pcifunc & ~RVU_PFVF_FUNC_MASK,
+ nixlf, type);
+ err = nix_update_mce_list(rvu, pcifunc, mce_list,
+ mce_idx, mcam_index, add);
+ return err;
+}
+
+static int nix_setup_mce_tables(struct rvu *rvu, struct nix_hw *nix_hw)
{
struct nix_mcast *mcast = &nix_hw->mcast;
int err, pf, numvfs, idx;
@@ -2355,11 +2461,18 @@ static int nix_setup_bcast_tables(struct rvu *rvu, struct nix_hw *nix_hw)
if (pfvf->nix_blkaddr != nix_hw->blkaddr)
continue;
- /* Save the start MCE */
+ /* save start idx of broadcast mce list */
pfvf->bcast_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1);
-
nix_mce_list_init(&pfvf->bcast_mce_list, numvfs + 1);
+ /* save start idx of multicast mce list */
+ pfvf->mcast_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1);
+ nix_mce_list_init(&pfvf->mcast_mce_list, numvfs + 1);
+
+ /* save the start idx of promisc mce list */
+ pfvf->promisc_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1);
+ nix_mce_list_init(&pfvf->promisc_mce_list, numvfs + 1);
+
for (idx = 0; idx < (numvfs + 1); idx++) {
/* idx-0 is for PF, followed by VFs */
pcifunc = (pf << RVU_PFVF_PF_SHIFT);
@@ -2375,6 +2488,22 @@ static int nix_setup_bcast_tables(struct rvu *rvu, struct nix_hw *nix_hw)
pcifunc, 0, true);
if (err)
return err;
+
+ /* add dummy entries to multicast mce list */
+ err = nix_blk_setup_mce(rvu, nix_hw,
+ pfvf->mcast_mce_idx + idx,
+ NIX_AQ_INSTOP_INIT,
+ pcifunc, 0, true);
+ if (err)
+ return err;
+
+ /* add dummy entries to promisc mce list */
+ err = nix_blk_setup_mce(rvu, nix_hw,
+ pfvf->promisc_mce_idx + idx,
+ NIX_AQ_INSTOP_INIT,
+ pcifunc, 0, true);
+ if (err)
+ return err;
}
}
return 0;
@@ -2421,7 +2550,7 @@ static int nix_setup_mcast(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr)
mutex_init(&mcast->mce_lock);
- return nix_setup_bcast_tables(rvu, nix_hw);
+ return nix_setup_mce_tables(rvu, nix_hw);
}
static int nix_setup_txvlan(struct rvu *rvu, struct nix_hw *nix_hw)
@@ -3035,15 +3164,22 @@ int rvu_mbox_handler_nix_set_mac_addr(struct rvu *rvu,
pfvf = rvu_get_pfvf(rvu, pcifunc);
- /* VF can't overwrite admin(PF) changes */
- if (from_vf && pfvf->pf_set_vf_cfg)
+ /* untrusted VF can't overwrite admin(PF) changes */
+ if (!test_bit(PF_SET_VF_TRUSTED, &pfvf->flags) &&
+ (from_vf && test_bit(PF_SET_VF_MAC, &pfvf->flags))) {
+ dev_warn(rvu->dev,
+ "MAC address set by admin(PF) cannot be overwritten by untrusted VF");
return -EPERM;
+ }
ether_addr_copy(pfvf->mac_addr, req->mac_addr);
rvu_npc_install_ucast_entry(rvu, pcifunc, nixlf,
pfvf->rx_chan_base, req->mac_addr);
+ if (test_bit(PF_SET_VF_TRUSTED, &pfvf->flags) && from_vf)
+ ether_addr_copy(pfvf->default_mac, req->mac_addr);
+
return 0;
}
@@ -3067,30 +3203,75 @@ int rvu_mbox_handler_nix_get_mac_addr(struct rvu *rvu,
int rvu_mbox_handler_nix_set_rx_mode(struct rvu *rvu, struct nix_rx_mode *req,
struct msg_rsp *rsp)
{
- bool allmulti = false, disable_promisc = false;
+ bool allmulti, promisc, nix_rx_multicast;
u16 pcifunc = req->hdr.pcifunc;
- int blkaddr, nixlf, err;
struct rvu_pfvf *pfvf;
+ int nixlf, err;
- err = nix_get_nixlf(rvu, pcifunc, &nixlf, &blkaddr);
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+ promisc = req->mode & NIX_RX_MODE_PROMISC ? true : false;
+ allmulti = req->mode & NIX_RX_MODE_ALLMULTI ? true : false;
+ pfvf->use_mce_list = req->mode & NIX_RX_MODE_USE_MCE ? true : false;
+
+ nix_rx_multicast = rvu->hw->cap.nix_rx_multicast & pfvf->use_mce_list;
+
+ if (is_vf(pcifunc) && !nix_rx_multicast &&
+ (promisc || allmulti)) {
+ dev_warn_ratelimited(rvu->dev,
+ "VF promisc/multicast not supported\n");
+ return 0;
+ }
+
+ /* untrusted VF can't configure promisc/allmulti */
+ if (is_vf(pcifunc) && !test_bit(PF_SET_VF_TRUSTED, &pfvf->flags) &&
+ (promisc || allmulti))
+ return 0;
+
+ err = nix_get_nixlf(rvu, pcifunc, &nixlf, NULL);
if (err)
return err;
- pfvf = rvu_get_pfvf(rvu, pcifunc);
+ if (nix_rx_multicast) {
+ /* add/del this PF_FUNC to/from mcast pkt replication list */
+ err = nix_update_mce_rule(rvu, pcifunc, NIXLF_ALLMULTI_ENTRY,
+ allmulti);
+ if (err) {
+ dev_err(rvu->dev,
+ "Failed to update pcifunc 0x%x to multicast list\n",
+ pcifunc);
+ return err;
+ }
- if (req->mode & NIX_RX_MODE_PROMISC)
- allmulti = false;
- else if (req->mode & NIX_RX_MODE_ALLMULTI)
- allmulti = true;
- else
- disable_promisc = true;
+ /* add/del this PF_FUNC to/from promisc pkt replication list */
+ err = nix_update_mce_rule(rvu, pcifunc, NIXLF_PROMISC_ENTRY,
+ promisc);
+ if (err) {
+ dev_err(rvu->dev,
+ "Failed to update pcifunc 0x%x to promisc list\n",
+ pcifunc);
+ return err;
+ }
+ }
- if (disable_promisc)
- rvu_npc_disable_promisc_entry(rvu, pcifunc, nixlf);
- else
+ /* install/uninstall allmulti entry */
+ if (allmulti) {
+ rvu_npc_install_allmulti_entry(rvu, pcifunc, nixlf,
+ pfvf->rx_chan_base);
+ } else {
+ if (!nix_rx_multicast)
+ rvu_npc_enable_allmulti_entry(rvu, pcifunc, nixlf, false);
+ }
+
+ /* install/uninstall promisc entry */
+ if (promisc) {
rvu_npc_install_promisc_entry(rvu, pcifunc, nixlf,
pfvf->rx_chan_base,
- pfvf->rx_chan_cnt, allmulti);
+ pfvf->rx_chan_cnt);
+ } else {
+ if (!nix_rx_multicast)
+ rvu_npc_enable_promisc_entry(rvu, pcifunc, nixlf, false);
+ }
+
return 0;
}
@@ -3470,6 +3651,10 @@ static int rvu_nix_block_init(struct rvu *rvu, struct nix_hw *nix_hw)
if (err)
return err;
+ err = nix_setup_ipolicers(rvu, nix_hw, blkaddr);
+ if (err)
+ return err;
+
err = nix_af_mark_format_setup(rvu, nix_hw, blkaddr);
if (err)
return err;
@@ -3523,6 +3708,40 @@ static int rvu_nix_block_init(struct rvu *rvu, struct nix_hw *nix_hw)
(ltdefs->rx_isctp.lid << 8) | (ltdefs->rx_isctp.ltype_match << 4) |
ltdefs->rx_isctp.ltype_mask);
+ if (!is_rvu_otx2(rvu)) {
+ /* Enable APAD calculation for other protocols
+ * matching APAD0 and APAD1 lt def registers.
+ */
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_CST_APAD0,
+ (ltdefs->rx_apad0.valid << 11) |
+ (ltdefs->rx_apad0.lid << 8) |
+ (ltdefs->rx_apad0.ltype_match << 4) |
+ ltdefs->rx_apad0.ltype_mask);
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_CST_APAD1,
+ (ltdefs->rx_apad1.valid << 11) |
+ (ltdefs->rx_apad1.lid << 8) |
+ (ltdefs->rx_apad1.ltype_match << 4) |
+ ltdefs->rx_apad1.ltype_mask);
+
+ /* Receive ethertype defination register defines layer
+ * information in NPC_RESULT_S to identify the Ethertype
+ * location in L2 header. Used for Ethertype overwriting
+ * in inline IPsec flow.
+ */
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_ET(0),
+ (ltdefs->rx_et[0].offset << 12) |
+ (ltdefs->rx_et[0].valid << 11) |
+ (ltdefs->rx_et[0].lid << 8) |
+ (ltdefs->rx_et[0].ltype_match << 4) |
+ ltdefs->rx_et[0].ltype_mask);
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_ET(1),
+ (ltdefs->rx_et[1].offset << 12) |
+ (ltdefs->rx_et[1].valid << 11) |
+ (ltdefs->rx_et[1].lid << 8) |
+ (ltdefs->rx_et[1].ltype_match << 4) |
+ ltdefs->rx_et[1].ltype_mask);
+ }
+
err = nix_rx_flowkey_alg_cfg(rvu, blkaddr);
if (err)
return err;
@@ -3584,6 +3803,8 @@ static void rvu_nix_block_freemem(struct rvu *rvu, int blkaddr,
kfree(txsch->schq.bmap);
}
+ nix_ipolicer_freemem(nix_hw);
+
vlan = &nix_hw->txvlan;
kfree(vlan->rsrc.bmap);
mutex_destroy(&vlan->rsrc_lock);
@@ -3614,6 +3835,7 @@ int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req,
struct msg_rsp *rsp)
{
u16 pcifunc = req->hdr.pcifunc;
+ struct rvu_pfvf *pfvf;
int nixlf, err;
err = nix_get_nixlf(rvu, pcifunc, &nixlf, NULL);
@@ -3624,6 +3846,9 @@ int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req,
npc_mcam_enable_flows(rvu, pcifunc);
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+ set_bit(NIXLF_INITIALIZED, &pfvf->flags);
+
return rvu_cgx_start_stop_io(rvu, pcifunc, true);
}
@@ -3631,6 +3856,7 @@ int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req,
struct msg_rsp *rsp)
{
u16 pcifunc = req->hdr.pcifunc;
+ struct rvu_pfvf *pfvf;
int nixlf, err;
err = nix_get_nixlf(rvu, pcifunc, &nixlf, NULL);
@@ -3639,6 +3865,9 @@ int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req,
rvu_npc_disable_mcam_entries(rvu, pcifunc, nixlf);
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+ clear_bit(NIXLF_INITIALIZED, &pfvf->flags);
+
return rvu_cgx_start_stop_io(rvu, pcifunc, false);
}
@@ -3657,6 +3886,8 @@ void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int nixlf)
nix_rx_sync(rvu, blkaddr);
nix_txschq_free(rvu, pcifunc);
+ clear_bit(NIXLF_INITIALIZED, &pfvf->flags);
+
rvu_cgx_start_stop_io(rvu, pcifunc, false);
if (pfvf->sq_ctx) {
@@ -3681,6 +3912,8 @@ void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int nixlf)
}
nix_ctx_free(rvu, pfvf);
+
+ nix_free_all_bandprof(rvu, pcifunc);
}
#define NIX_AF_LFX_TX_CFG_PTP_EN BIT_ULL(32)
@@ -3789,3 +4022,586 @@ void rvu_nix_reset_mac(struct rvu_pfvf *pfvf, int pcifunc)
if (from_vf)
ether_addr_copy(pfvf->mac_addr, pfvf->default_mac);
}
+
+/* NIX ingress policers or bandwidth profiles APIs */
+static void nix_config_rx_pkt_policer_precolor(struct rvu *rvu, int blkaddr)
+{
+ struct npc_lt_def_cfg defs, *ltdefs;
+
+ ltdefs = &defs;
+ memcpy(ltdefs, rvu->kpu.lt_def, sizeof(struct npc_lt_def_cfg));
+
+ /* Extract PCP and DEI fields from outer VLAN from byte offset
+ * 2 from the start of LB_PTR (ie TAG).
+ * VLAN0 is Outer VLAN and VLAN1 is Inner VLAN. Inner VLAN
+ * fields are considered when 'Tunnel enable' is set in profile.
+ */
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_VLAN0_PCP_DEI,
+ (2UL << 12) | (ltdefs->ovlan.lid << 8) |
+ (ltdefs->ovlan.ltype_match << 4) |
+ ltdefs->ovlan.ltype_mask);
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_VLAN1_PCP_DEI,
+ (2UL << 12) | (ltdefs->ivlan.lid << 8) |
+ (ltdefs->ivlan.ltype_match << 4) |
+ ltdefs->ivlan.ltype_mask);
+
+ /* DSCP field in outer and tunneled IPv4 packets */
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_OIP4_DSCP,
+ (1UL << 12) | (ltdefs->rx_oip4.lid << 8) |
+ (ltdefs->rx_oip4.ltype_match << 4) |
+ ltdefs->rx_oip4.ltype_mask);
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_IIP4_DSCP,
+ (1UL << 12) | (ltdefs->rx_iip4.lid << 8) |
+ (ltdefs->rx_iip4.ltype_match << 4) |
+ ltdefs->rx_iip4.ltype_mask);
+
+ /* DSCP field (traffic class) in outer and tunneled IPv6 packets */
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_OIP6_DSCP,
+ (1UL << 11) | (ltdefs->rx_oip6.lid << 8) |
+ (ltdefs->rx_oip6.ltype_match << 4) |
+ ltdefs->rx_oip6.ltype_mask);
+ rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_IIP6_DSCP,
+ (1UL << 11) | (ltdefs->rx_iip6.lid << 8) |
+ (ltdefs->rx_iip6.ltype_match << 4) |
+ ltdefs->rx_iip6.ltype_mask);
+}
+
+static int nix_init_policer_context(struct rvu *rvu, struct nix_hw *nix_hw,
+ int layer, int prof_idx)
+{
+ struct nix_cn10k_aq_enq_req aq_req;
+ int rc;
+
+ memset(&aq_req, 0, sizeof(struct nix_cn10k_aq_enq_req));
+
+ aq_req.qidx = (prof_idx & 0x3FFF) | (layer << 14);
+ aq_req.ctype = NIX_AQ_CTYPE_BANDPROF;
+ aq_req.op = NIX_AQ_INSTOP_INIT;
+
+ /* Context is all zeros, submit to AQ */
+ rc = rvu_nix_blk_aq_enq_inst(rvu, nix_hw,
+ (struct nix_aq_enq_req *)&aq_req, NULL);
+ if (rc)
+ dev_err(rvu->dev, "Failed to INIT bandwidth profile layer %d profile %d\n",
+ layer, prof_idx);
+ return rc;
+}
+
+static int nix_setup_ipolicers(struct rvu *rvu,
+ struct nix_hw *nix_hw, int blkaddr)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ struct nix_ipolicer *ipolicer;
+ int err, layer, prof_idx;
+ u64 cfg;
+
+ cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST);
+ if (!(cfg & BIT_ULL(61))) {
+ hw->cap.ipolicer = false;
+ return 0;
+ }
+
+ hw->cap.ipolicer = true;
+ nix_hw->ipolicer = devm_kcalloc(rvu->dev, BAND_PROF_NUM_LAYERS,
+ sizeof(*ipolicer), GFP_KERNEL);
+ if (!nix_hw->ipolicer)
+ return -ENOMEM;
+
+ cfg = rvu_read64(rvu, blkaddr, NIX_AF_PL_CONST);
+
+ for (layer = 0; layer < BAND_PROF_NUM_LAYERS; layer++) {
+ ipolicer = &nix_hw->ipolicer[layer];
+ switch (layer) {
+ case BAND_PROF_LEAF_LAYER:
+ ipolicer->band_prof.max = cfg & 0XFFFF;
+ break;
+ case BAND_PROF_MID_LAYER:
+ ipolicer->band_prof.max = (cfg >> 16) & 0XFFFF;
+ break;
+ case BAND_PROF_TOP_LAYER:
+ ipolicer->band_prof.max = (cfg >> 32) & 0XFFFF;
+ break;
+ }
+
+ if (!ipolicer->band_prof.max)
+ continue;
+
+ err = rvu_alloc_bitmap(&ipolicer->band_prof);
+ if (err)
+ return err;
+
+ ipolicer->pfvf_map = devm_kcalloc(rvu->dev,
+ ipolicer->band_prof.max,
+ sizeof(u16), GFP_KERNEL);
+ if (!ipolicer->pfvf_map)
+ return -ENOMEM;
+
+ ipolicer->match_id = devm_kcalloc(rvu->dev,
+ ipolicer->band_prof.max,
+ sizeof(u16), GFP_KERNEL);
+ if (!ipolicer->match_id)
+ return -ENOMEM;
+
+ for (prof_idx = 0;
+ prof_idx < ipolicer->band_prof.max; prof_idx++) {
+ /* Set AF as current owner for INIT ops to succeed */
+ ipolicer->pfvf_map[prof_idx] = 0x00;
+
+ /* There is no enable bit in the profile context,
+ * so no context disable. So let's INIT them here
+ * so that PF/VF later on have to just do WRITE to
+ * setup policer rates and config.
+ */
+ err = nix_init_policer_context(rvu, nix_hw,
+ layer, prof_idx);
+ if (err)
+ return err;
+ }
+
+ /* Allocate memory for maintaining ref_counts for MID level
+ * profiles, this will be needed for leaf layer profiles'
+ * aggregation.
+ */
+ if (layer != BAND_PROF_MID_LAYER)
+ continue;
+
+ ipolicer->ref_count = devm_kcalloc(rvu->dev,
+ ipolicer->band_prof.max,
+ sizeof(u16), GFP_KERNEL);
+ }
+
+ /* Set policer timeunit to 2us ie (19 + 1) * 100 nsec = 2us */
+ rvu_write64(rvu, blkaddr, NIX_AF_PL_TS, 19);
+
+ nix_config_rx_pkt_policer_precolor(rvu, blkaddr);
+
+ return 0;
+}
+
+static void nix_ipolicer_freemem(struct nix_hw *nix_hw)
+{
+ struct nix_ipolicer *ipolicer;
+ int layer;
+
+ for (layer = 0; layer < BAND_PROF_NUM_LAYERS; layer++) {
+ ipolicer = &nix_hw->ipolicer[layer];
+
+ if (!ipolicer->band_prof.max)
+ continue;
+
+ kfree(ipolicer->band_prof.bmap);
+ }
+}
+
+static int nix_verify_bandprof(struct nix_cn10k_aq_enq_req *req,
+ struct nix_hw *nix_hw, u16 pcifunc)
+{
+ struct nix_ipolicer *ipolicer;
+ int layer, hi_layer, prof_idx;
+
+ /* Bits [15:14] in profile index represent layer */
+ layer = (req->qidx >> 14) & 0x03;
+ prof_idx = req->qidx & 0x3FFF;
+
+ ipolicer = &nix_hw->ipolicer[layer];
+ if (prof_idx >= ipolicer->band_prof.max)
+ return -EINVAL;
+
+ /* Check if the profile is allocated to the requesting PCIFUNC or not
+ * with the exception of AF. AF is allowed to read and update contexts.
+ */
+ if (pcifunc && ipolicer->pfvf_map[prof_idx] != pcifunc)
+ return -EINVAL;
+
+ /* If this profile is linked to higher layer profile then check
+ * if that profile is also allocated to the requesting PCIFUNC
+ * or not.
+ */
+ if (!req->prof.hl_en)
+ return 0;
+
+ /* Leaf layer profile can link only to mid layer and
+ * mid layer to top layer.
+ */
+ if (layer == BAND_PROF_LEAF_LAYER)
+ hi_layer = BAND_PROF_MID_LAYER;
+ else if (layer == BAND_PROF_MID_LAYER)
+ hi_layer = BAND_PROF_TOP_LAYER;
+ else
+ return -EINVAL;
+
+ ipolicer = &nix_hw->ipolicer[hi_layer];
+ prof_idx = req->prof.band_prof_id;
+ if (prof_idx >= ipolicer->band_prof.max ||
+ ipolicer->pfvf_map[prof_idx] != pcifunc)
+ return -EINVAL;
+
+ return 0;
+}
+
+int rvu_mbox_handler_nix_bandprof_alloc(struct rvu *rvu,
+ struct nix_bandprof_alloc_req *req,
+ struct nix_bandprof_alloc_rsp *rsp)
+{
+ int blkaddr, layer, prof, idx, err;
+ u16 pcifunc = req->hdr.pcifunc;
+ struct nix_ipolicer *ipolicer;
+ struct nix_hw *nix_hw;
+
+ if (!rvu->hw->cap.ipolicer)
+ return NIX_AF_ERR_IPOLICER_NOTSUPP;
+
+ err = nix_get_struct_ptrs(rvu, pcifunc, &nix_hw, &blkaddr);
+ if (err)
+ return err;
+
+ mutex_lock(&rvu->rsrc_lock);
+ for (layer = 0; layer < BAND_PROF_NUM_LAYERS; layer++) {
+ if (layer == BAND_PROF_INVAL_LAYER)
+ continue;
+ if (!req->prof_count[layer])
+ continue;
+
+ ipolicer = &nix_hw->ipolicer[layer];
+ for (idx = 0; idx < req->prof_count[layer]; idx++) {
+ /* Allocate a max of 'MAX_BANDPROF_PER_PFFUNC' profiles */
+ if (idx == MAX_BANDPROF_PER_PFFUNC)
+ break;
+
+ prof = rvu_alloc_rsrc(&ipolicer->band_prof);
+ if (prof < 0)
+ break;
+ rsp->prof_count[layer]++;
+ rsp->prof_idx[layer][idx] = prof;
+ ipolicer->pfvf_map[prof] = pcifunc;
+ }
+ }
+ mutex_unlock(&rvu->rsrc_lock);
+ return 0;
+}
+
+static int nix_free_all_bandprof(struct rvu *rvu, u16 pcifunc)
+{
+ int blkaddr, layer, prof_idx, err;
+ struct nix_ipolicer *ipolicer;
+ struct nix_hw *nix_hw;
+
+ if (!rvu->hw->cap.ipolicer)
+ return NIX_AF_ERR_IPOLICER_NOTSUPP;
+
+ err = nix_get_struct_ptrs(rvu, pcifunc, &nix_hw, &blkaddr);
+ if (err)
+ return err;
+
+ mutex_lock(&rvu->rsrc_lock);
+ /* Free all the profiles allocated to the PCIFUNC */
+ for (layer = 0; layer < BAND_PROF_NUM_LAYERS; layer++) {
+ if (layer == BAND_PROF_INVAL_LAYER)
+ continue;
+ ipolicer = &nix_hw->ipolicer[layer];
+
+ for (prof_idx = 0; prof_idx < ipolicer->band_prof.max; prof_idx++) {
+ if (ipolicer->pfvf_map[prof_idx] != pcifunc)
+ continue;
+
+ /* Clear ratelimit aggregation, if any */
+ if (layer == BAND_PROF_LEAF_LAYER &&
+ ipolicer->match_id[prof_idx])
+ nix_clear_ratelimit_aggr(rvu, nix_hw, prof_idx);
+
+ ipolicer->pfvf_map[prof_idx] = 0x00;
+ ipolicer->match_id[prof_idx] = 0;
+ rvu_free_rsrc(&ipolicer->band_prof, prof_idx);
+ }
+ }
+ mutex_unlock(&rvu->rsrc_lock);
+ return 0;
+}
+
+int rvu_mbox_handler_nix_bandprof_free(struct rvu *rvu,
+ struct nix_bandprof_free_req *req,
+ struct msg_rsp *rsp)
+{
+ int blkaddr, layer, prof_idx, idx, err;
+ u16 pcifunc = req->hdr.pcifunc;
+ struct nix_ipolicer *ipolicer;
+ struct nix_hw *nix_hw;
+
+ if (req->free_all)
+ return nix_free_all_bandprof(rvu, pcifunc);
+
+ if (!rvu->hw->cap.ipolicer)
+ return NIX_AF_ERR_IPOLICER_NOTSUPP;
+
+ err = nix_get_struct_ptrs(rvu, pcifunc, &nix_hw, &blkaddr);
+ if (err)
+ return err;
+
+ mutex_lock(&rvu->rsrc_lock);
+ /* Free the requested profile indices */
+ for (layer = 0; layer < BAND_PROF_NUM_LAYERS; layer++) {
+ if (layer == BAND_PROF_INVAL_LAYER)
+ continue;
+ if (!req->prof_count[layer])
+ continue;
+
+ ipolicer = &nix_hw->ipolicer[layer];
+ for (idx = 0; idx < req->prof_count[layer]; idx++) {
+ prof_idx = req->prof_idx[layer][idx];
+ if (prof_idx >= ipolicer->band_prof.max ||
+ ipolicer->pfvf_map[prof_idx] != pcifunc)
+ continue;
+
+ /* Clear ratelimit aggregation, if any */
+ if (layer == BAND_PROF_LEAF_LAYER &&
+ ipolicer->match_id[prof_idx])
+ nix_clear_ratelimit_aggr(rvu, nix_hw, prof_idx);
+
+ ipolicer->pfvf_map[prof_idx] = 0x00;
+ ipolicer->match_id[prof_idx] = 0;
+ rvu_free_rsrc(&ipolicer->band_prof, prof_idx);
+ if (idx == MAX_BANDPROF_PER_PFFUNC)
+ break;
+ }
+ }
+ mutex_unlock(&rvu->rsrc_lock);
+ return 0;
+}
+
+int nix_aq_context_read(struct rvu *rvu, struct nix_hw *nix_hw,
+ struct nix_cn10k_aq_enq_req *aq_req,
+ struct nix_cn10k_aq_enq_rsp *aq_rsp,
+ u16 pcifunc, u8 ctype, u32 qidx)
+{
+ memset(aq_req, 0, sizeof(struct nix_cn10k_aq_enq_req));
+ aq_req->hdr.pcifunc = pcifunc;
+ aq_req->ctype = ctype;
+ aq_req->op = NIX_AQ_INSTOP_READ;
+ aq_req->qidx = qidx;
+
+ return rvu_nix_blk_aq_enq_inst(rvu, nix_hw,
+ (struct nix_aq_enq_req *)aq_req,
+ (struct nix_aq_enq_rsp *)aq_rsp);
+}
+
+static int nix_ipolicer_map_leaf_midprofs(struct rvu *rvu,
+ struct nix_hw *nix_hw,
+ struct nix_cn10k_aq_enq_req *aq_req,
+ struct nix_cn10k_aq_enq_rsp *aq_rsp,
+ u32 leaf_prof, u16 mid_prof)
+{
+ memset(aq_req, 0, sizeof(struct nix_cn10k_aq_enq_req));
+ aq_req->hdr.pcifunc = 0x00;
+ aq_req->ctype = NIX_AQ_CTYPE_BANDPROF;
+ aq_req->op = NIX_AQ_INSTOP_WRITE;
+ aq_req->qidx = leaf_prof;
+
+ aq_req->prof.band_prof_id = mid_prof;
+ aq_req->prof_mask.band_prof_id = GENMASK(6, 0);
+ aq_req->prof.hl_en = 1;
+ aq_req->prof_mask.hl_en = 1;
+
+ return rvu_nix_blk_aq_enq_inst(rvu, nix_hw,
+ (struct nix_aq_enq_req *)aq_req,
+ (struct nix_aq_enq_rsp *)aq_rsp);
+}
+
+int rvu_nix_setup_ratelimit_aggr(struct rvu *rvu, u16 pcifunc,
+ u16 rq_idx, u16 match_id)
+{
+ int leaf_prof, mid_prof, leaf_match;
+ struct nix_cn10k_aq_enq_req aq_req;
+ struct nix_cn10k_aq_enq_rsp aq_rsp;
+ struct nix_ipolicer *ipolicer;
+ struct nix_hw *nix_hw;
+ int blkaddr, idx, rc;
+
+ if (!rvu->hw->cap.ipolicer)
+ return 0;
+
+ rc = nix_get_struct_ptrs(rvu, pcifunc, &nix_hw, &blkaddr);
+ if (rc)
+ return rc;
+
+ /* Fetch the RQ's context to see if policing is enabled */
+ rc = nix_aq_context_read(rvu, nix_hw, &aq_req, &aq_rsp, pcifunc,
+ NIX_AQ_CTYPE_RQ, rq_idx);
+ if (rc) {
+ dev_err(rvu->dev,
+ "%s: Failed to fetch RQ%d context of PFFUNC 0x%x\n",
+ __func__, rq_idx, pcifunc);
+ return rc;
+ }
+
+ if (!aq_rsp.rq.policer_ena)
+ return 0;
+
+ /* Get the bandwidth profile ID mapped to this RQ */
+ leaf_prof = aq_rsp.rq.band_prof_id;
+
+ ipolicer = &nix_hw->ipolicer[BAND_PROF_LEAF_LAYER];
+ ipolicer->match_id[leaf_prof] = match_id;
+
+ /* Check if any other leaf profile is marked with same match_id */
+ for (idx = 0; idx < ipolicer->band_prof.max; idx++) {
+ if (idx == leaf_prof)
+ continue;
+ if (ipolicer->match_id[idx] != match_id)
+ continue;
+
+ leaf_match = idx;
+ break;
+ }
+
+ if (idx == ipolicer->band_prof.max)
+ return 0;
+
+ /* Fetch the matching profile's context to check if it's already
+ * mapped to a mid level profile.
+ */
+ rc = nix_aq_context_read(rvu, nix_hw, &aq_req, &aq_rsp, 0x00,
+ NIX_AQ_CTYPE_BANDPROF, leaf_match);
+ if (rc) {
+ dev_err(rvu->dev,
+ "%s: Failed to fetch context of leaf profile %d\n",
+ __func__, leaf_match);
+ return rc;
+ }
+
+ ipolicer = &nix_hw->ipolicer[BAND_PROF_MID_LAYER];
+ if (aq_rsp.prof.hl_en) {
+ /* Get Mid layer prof index and map leaf_prof index
+ * also such that flows that are being steered
+ * to different RQs and marked with same match_id
+ * are rate limited in a aggregate fashion
+ */
+ mid_prof = aq_rsp.prof.band_prof_id;
+ rc = nix_ipolicer_map_leaf_midprofs(rvu, nix_hw,
+ &aq_req, &aq_rsp,
+ leaf_prof, mid_prof);
+ if (rc) {
+ dev_err(rvu->dev,
+ "%s: Failed to map leaf(%d) and mid(%d) profiles\n",
+ __func__, leaf_prof, mid_prof);
+ goto exit;
+ }
+
+ mutex_lock(&rvu->rsrc_lock);
+ ipolicer->ref_count[mid_prof]++;
+ mutex_unlock(&rvu->rsrc_lock);
+ goto exit;
+ }
+
+ /* Allocate a mid layer profile and
+ * map both 'leaf_prof' and 'leaf_match' profiles to it.
+ */
+ mutex_lock(&rvu->rsrc_lock);
+ mid_prof = rvu_alloc_rsrc(&ipolicer->band_prof);
+ if (mid_prof < 0) {
+ dev_err(rvu->dev,
+ "%s: Unable to allocate mid layer profile\n", __func__);
+ mutex_unlock(&rvu->rsrc_lock);
+ goto exit;
+ }
+ mutex_unlock(&rvu->rsrc_lock);
+ ipolicer->pfvf_map[mid_prof] = 0x00;
+ ipolicer->ref_count[mid_prof] = 0;
+
+ /* Initialize mid layer profile same as 'leaf_prof' */
+ rc = nix_aq_context_read(rvu, nix_hw, &aq_req, &aq_rsp, 0x00,
+ NIX_AQ_CTYPE_BANDPROF, leaf_prof);
+ if (rc) {
+ dev_err(rvu->dev,
+ "%s: Failed to fetch context of leaf profile %d\n",
+ __func__, leaf_prof);
+ goto exit;
+ }
+
+ memset(&aq_req, 0, sizeof(struct nix_cn10k_aq_enq_req));
+ aq_req.hdr.pcifunc = 0x00;
+ aq_req.qidx = (mid_prof & 0x3FFF) | (BAND_PROF_MID_LAYER << 14);
+ aq_req.ctype = NIX_AQ_CTYPE_BANDPROF;
+ aq_req.op = NIX_AQ_INSTOP_WRITE;
+ memcpy(&aq_req.prof, &aq_rsp.prof, sizeof(struct nix_bandprof_s));
+ /* Clear higher layer enable bit in the mid profile, just in case */
+ aq_req.prof.hl_en = 0;
+ aq_req.prof_mask.hl_en = 1;
+
+ rc = rvu_nix_blk_aq_enq_inst(rvu, nix_hw,
+ (struct nix_aq_enq_req *)&aq_req, NULL);
+ if (rc) {
+ dev_err(rvu->dev,
+ "%s: Failed to INIT context of mid layer profile %d\n",
+ __func__, mid_prof);
+ goto exit;
+ }
+
+ /* Map both leaf profiles to this mid layer profile */
+ rc = nix_ipolicer_map_leaf_midprofs(rvu, nix_hw,
+ &aq_req, &aq_rsp,
+ leaf_prof, mid_prof);
+ if (rc) {
+ dev_err(rvu->dev,
+ "%s: Failed to map leaf(%d) and mid(%d) profiles\n",
+ __func__, leaf_prof, mid_prof);
+ goto exit;
+ }
+
+ mutex_lock(&rvu->rsrc_lock);
+ ipolicer->ref_count[mid_prof]++;
+ mutex_unlock(&rvu->rsrc_lock);
+
+ rc = nix_ipolicer_map_leaf_midprofs(rvu, nix_hw,
+ &aq_req, &aq_rsp,
+ leaf_match, mid_prof);
+ if (rc) {
+ dev_err(rvu->dev,
+ "%s: Failed to map leaf(%d) and mid(%d) profiles\n",
+ __func__, leaf_match, mid_prof);
+ ipolicer->ref_count[mid_prof]--;
+ goto exit;
+ }
+
+ mutex_lock(&rvu->rsrc_lock);
+ ipolicer->ref_count[mid_prof]++;
+ mutex_unlock(&rvu->rsrc_lock);
+
+exit:
+ return rc;
+}
+
+/* Called with mutex rsrc_lock */
+static void nix_clear_ratelimit_aggr(struct rvu *rvu, struct nix_hw *nix_hw,
+ u32 leaf_prof)
+{
+ struct nix_cn10k_aq_enq_req aq_req;
+ struct nix_cn10k_aq_enq_rsp aq_rsp;
+ struct nix_ipolicer *ipolicer;
+ u16 mid_prof;
+ int rc;
+
+ mutex_unlock(&rvu->rsrc_lock);
+
+ rc = nix_aq_context_read(rvu, nix_hw, &aq_req, &aq_rsp, 0x00,
+ NIX_AQ_CTYPE_BANDPROF, leaf_prof);
+
+ mutex_lock(&rvu->rsrc_lock);
+ if (rc) {
+ dev_err(rvu->dev,
+ "%s: Failed to fetch context of leaf profile %d\n",
+ __func__, leaf_prof);
+ return;
+ }
+
+ if (!aq_rsp.prof.hl_en)
+ return;
+
+ mid_prof = aq_rsp.prof.band_prof_id;
+ ipolicer = &nix_hw->ipolicer[BAND_PROF_MID_LAYER];
+ ipolicer->ref_count[mid_prof]--;
+ /* If ref_count is zero, free mid layer profile */
+ if (!ipolicer->ref_count[mid_prof]) {
+ ipolicer->pfvf_map[mid_prof] = 0x00;
+ rvu_free_rsrc(&ipolicer->band_prof, mid_prof);
+ }
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index 0bc4529691ec..3612e0a2cab3 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -19,7 +19,7 @@
#include "cgx.h"
#include "npc_profile.h"
-#define RSVD_MCAM_ENTRIES_PER_PF 2 /* Bcast & Promisc */
+#define RSVD_MCAM_ENTRIES_PER_PF 3 /* Broadcast, Promisc and AllMulticast */
#define RSVD_MCAM_ENTRIES_PER_NIXLF 1 /* Ucast for LFs */
#define NPC_PARSE_RESULT_DMAC_OFFSET 8
@@ -27,6 +27,8 @@
#define NPC_KEX_CHAN_MASK 0xFFFULL
#define NPC_KEX_PF_FUNC_MASK 0xFFFFULL
+#define ALIGN_8B_CEIL(__a) (((__a) + 7) & (-8))
+
static const char def_pfl_name[] = "default";
static void npc_mcam_free_all_entries(struct rvu *rvu, struct npc_mcam *mcam,
@@ -212,8 +214,10 @@ int npc_get_nixlf_mcam_index(struct npc_mcam *mcam,
*/
if (type == NIXLF_BCAST_ENTRY)
return index;
- else if (type == NIXLF_PROMISC_ENTRY)
+ else if (type == NIXLF_ALLMULTI_ENTRY)
return index + 1;
+ else if (type == NIXLF_PROMISC_ENTRY)
+ return index + 2;
}
return npc_get_ucast_mcam_index(mcam, pcifunc, nixlf);
@@ -411,37 +415,49 @@ static void npc_fill_entryword(struct mcam_entry *entry, int idx,
}
}
-static void npc_get_default_entry_action(struct rvu *rvu, struct npc_mcam *mcam,
- int blkaddr, int index,
- struct mcam_entry *entry)
+static u64 npc_get_default_entry_action(struct rvu *rvu, struct npc_mcam *mcam,
+ int blkaddr, u16 pf_func)
+{
+ int bank, nixlf, index;
+
+ /* get ucast entry rule entry index */
+ nix_get_nixlf(rvu, pf_func, &nixlf, NULL);
+ index = npc_get_nixlf_mcam_index(mcam, pf_func, nixlf,
+ NIXLF_UCAST_ENTRY);
+ bank = npc_get_bank(mcam, index);
+ index &= (mcam->banksize - 1);
+
+ return rvu_read64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_ACTION(index, bank));
+}
+
+static void npc_fixup_vf_rule(struct rvu *rvu, struct npc_mcam *mcam,
+ int blkaddr, int index, struct mcam_entry *entry,
+ bool *enable)
{
u16 owner, target_func;
struct rvu_pfvf *pfvf;
- int bank, nixlf;
u64 rx_action;
owner = mcam->entry2pfvf_map[index];
target_func = (entry->action >> 4) & 0xffff;
- /* return incase target is PF or LBK or rule owner is not PF */
+ /* do nothing when target is LBK/PF or owner is not PF */
if (is_afvf(target_func) || (owner & RVU_PFVF_FUNC_MASK) ||
!(target_func & RVU_PFVF_FUNC_MASK))
return;
+ /* save entry2target_pffunc */
pfvf = rvu_get_pfvf(rvu, target_func);
mcam->entry2target_pffunc[index] = target_func;
- /* return if nixlf is not attached or initialized */
- if (!is_nixlf_attached(rvu, target_func) || !pfvf->def_ucast_rule)
- return;
- /* get VF ucast entry rule */
- nix_get_nixlf(rvu, target_func, &nixlf, NULL);
- index = npc_get_nixlf_mcam_index(mcam, target_func,
- nixlf, NIXLF_UCAST_ENTRY);
- bank = npc_get_bank(mcam, index);
- index &= (mcam->banksize - 1);
+ /* don't enable rule when nixlf not attached or initialized */
+ if (!(is_nixlf_attached(rvu, target_func) &&
+ test_bit(NIXLF_INITIALIZED, &pfvf->flags)))
+ *enable = false;
- rx_action = rvu_read64(rvu, blkaddr,
- NPC_AF_MCAMEX_BANKX_ACTION(index, bank));
+ /* copy VF default entry action to the VF mcam entry */
+ rx_action = npc_get_default_entry_action(rvu, mcam, blkaddr,
+ target_func);
if (rx_action)
entry->action = rx_action;
}
@@ -493,10 +509,9 @@ static void npc_config_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
NPC_AF_MCAMEX_BANKX_CAMX_W1(index, bank, 0), cam0);
}
- /* copy VF default entry action to the VF mcam entry */
+ /* PF installing VF rule */
if (intf == NIX_INTF_RX && actindex < mcam->bmap_entries)
- npc_get_default_entry_action(rvu, mcam, blkaddr, actindex,
- entry);
+ npc_fixup_vf_rule(rvu, mcam, blkaddr, index, entry, &enable);
/* Set 'action' */
rvu_write64(rvu, blkaddr,
@@ -647,30 +662,32 @@ void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc,
}
void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc,
- int nixlf, u64 chan, u8 chan_cnt,
- bool allmulti)
+ int nixlf, u64 chan, u8 chan_cnt)
{
struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
struct npc_install_flow_req req = { 0 };
struct npc_install_flow_rsp rsp = { 0 };
struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct rvu_hwinfo *hw = rvu->hw;
int blkaddr, ucast_idx, index;
- u8 mac_addr[ETH_ALEN] = { 0 };
struct nix_rx_action action;
u64 relaxed_mask;
- /* Only PF or AF VF can add a promiscuous entry */
- if ((pcifunc & RVU_PFVF_FUNC_MASK) && !is_afvf(pcifunc))
+ if (!hw->cap.nix_rx_multicast && is_cgx_vf(rvu, pcifunc))
return;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
if (blkaddr < 0)
return;
- *(u64 *)&action = 0x00;
index = npc_get_nixlf_mcam_index(mcam, pcifunc,
nixlf, NIXLF_PROMISC_ENTRY);
+ if (is_cgx_vf(rvu, pcifunc))
+ index = npc_get_nixlf_mcam_index(mcam,
+ pcifunc & ~RVU_PFVF_FUNC_MASK,
+ nixlf, NIXLF_PROMISC_ENTRY);
+
/* If the corresponding PF's ucast action is RSS,
* use the same action for promisc also
*/
@@ -678,19 +695,20 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc,
nixlf, NIXLF_UCAST_ENTRY);
if (is_mcam_entry_enabled(rvu, mcam, blkaddr, ucast_idx))
*(u64 *)&action = npc_get_mcam_action(rvu, mcam,
- blkaddr, ucast_idx);
+ blkaddr, ucast_idx);
if (action.op != NIX_RX_ACTIONOP_RSS) {
*(u64 *)&action = 0x00;
action.op = NIX_RX_ACTIONOP_UCAST;
- action.pf_func = pcifunc;
}
- if (allmulti) {
- mac_addr[0] = 0x01; /* LSB bit of 1st byte in DMAC */
- ether_addr_copy(req.packet.dmac, mac_addr);
- ether_addr_copy(req.mask.dmac, mac_addr);
- req.features = BIT_ULL(NPC_DMAC);
+ /* RX_ACTION set to MCAST for CGX PF's */
+ if (hw->cap.nix_rx_multicast && pfvf->use_mce_list &&
+ is_pf_cgxmapped(rvu, rvu_get_pf(pcifunc))) {
+ *(u64 *)&action = 0x00;
+ action.op = NIX_RX_ACTIONOP_MCAST;
+ pfvf = rvu_get_pfvf(rvu, pcifunc & ~RVU_PFVF_FUNC_MASK);
+ action.index = pfvf->promisc_mce_idx;
}
req.chan_mask = 0xFFFU;
@@ -718,8 +736,8 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc,
rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp);
}
-static void npc_enadis_promisc_entry(struct rvu *rvu, u16 pcifunc,
- int nixlf, bool enable)
+void rvu_npc_enable_promisc_entry(struct rvu *rvu, u16 pcifunc,
+ int nixlf, bool enable)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
int blkaddr, index;
@@ -728,25 +746,14 @@ static void npc_enadis_promisc_entry(struct rvu *rvu, u16 pcifunc,
if (blkaddr < 0)
return;
- /* Only PF's have a promiscuous entry */
- if (pcifunc & RVU_PFVF_FUNC_MASK)
- return;
+ /* Get 'pcifunc' of PF device */
+ pcifunc = pcifunc & ~RVU_PFVF_FUNC_MASK;
index = npc_get_nixlf_mcam_index(mcam, pcifunc,
nixlf, NIXLF_PROMISC_ENTRY);
npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
}
-void rvu_npc_disable_promisc_entry(struct rvu *rvu, u16 pcifunc, int nixlf)
-{
- npc_enadis_promisc_entry(rvu, pcifunc, nixlf, false);
-}
-
-void rvu_npc_enable_promisc_entry(struct rvu *rvu, u16 pcifunc, int nixlf)
-{
- npc_enadis_promisc_entry(rvu, pcifunc, nixlf, true);
-}
-
void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc,
int nixlf, u64 chan)
{
@@ -756,8 +763,6 @@ void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc,
struct npc_mcam *mcam = &rvu->hw->mcam;
struct rvu_hwinfo *hw = rvu->hw;
int blkaddr, index;
- u32 req_index = 0;
- u8 op;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
if (blkaddr < 0)
@@ -770,7 +775,7 @@ void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc,
/* If pkt replication is not supported,
* then only PF is allowed to add a bcast match entry.
*/
- if (!hw->cap.nix_rx_multicast && pcifunc & RVU_PFVF_FUNC_MASK)
+ if (!hw->cap.nix_rx_multicast && is_vf(pcifunc))
return;
/* Get 'pcifunc' of PF device */
@@ -784,10 +789,10 @@ void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc,
* so install entry with UCAST action, so that PF
* receives all broadcast packets.
*/
- op = NIX_RX_ACTIONOP_UCAST;
+ req.op = NIX_RX_ACTIONOP_UCAST;
} else {
- op = NIX_RX_ACTIONOP_MCAST;
- req_index = pfvf->bcast_mce_idx;
+ req.op = NIX_RX_ACTIONOP_MCAST;
+ req.index = pfvf->bcast_mce_idx;
}
eth_broadcast_addr((u8 *)&req.packet.dmac);
@@ -796,15 +801,14 @@ void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc,
req.channel = chan;
req.intf = pfvf->nix_rx_intf;
req.entry = index;
- req.op = op;
req.hdr.pcifunc = 0; /* AF is requester */
req.vf = pcifunc;
- req.index = req_index;
rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp);
}
-void rvu_npc_enable_bcast_entry(struct rvu *rvu, u16 pcifunc, bool enable)
+void rvu_npc_enable_bcast_entry(struct rvu *rvu, u16 pcifunc, int nixlf,
+ bool enable)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
int blkaddr, index;
@@ -816,7 +820,104 @@ void rvu_npc_enable_bcast_entry(struct rvu *rvu, u16 pcifunc, bool enable)
/* Get 'pcifunc' of PF device */
pcifunc = pcifunc & ~RVU_PFVF_FUNC_MASK;
- index = npc_get_nixlf_mcam_index(mcam, pcifunc, 0, NIXLF_BCAST_ENTRY);
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf,
+ NIXLF_BCAST_ENTRY);
+ npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
+}
+
+void rvu_npc_install_allmulti_entry(struct rvu *rvu, u16 pcifunc, int nixlf,
+ u64 chan)
+{
+ struct npc_install_flow_req req = { 0 };
+ struct npc_install_flow_rsp rsp = { 0 };
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct rvu_hwinfo *hw = rvu->hw;
+ int blkaddr, ucast_idx, index;
+ u8 mac_addr[ETH_ALEN] = { 0 };
+ struct nix_rx_action action;
+ struct rvu_pfvf *pfvf;
+ u16 vf_func;
+
+ /* Only CGX PF/VF can add allmulticast entry */
+ if (is_afvf(pcifunc))
+ return;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return;
+
+ /* Get 'pcifunc' of PF device */
+ vf_func = pcifunc & RVU_PFVF_FUNC_MASK;
+ pcifunc = pcifunc & ~RVU_PFVF_FUNC_MASK;
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc,
+ nixlf, NIXLF_ALLMULTI_ENTRY);
+
+ /* If the corresponding PF's ucast action is RSS,
+ * use the same action for multicast entry also
+ */
+ ucast_idx = npc_get_nixlf_mcam_index(mcam, pcifunc,
+ nixlf, NIXLF_UCAST_ENTRY);
+ if (is_mcam_entry_enabled(rvu, mcam, blkaddr, ucast_idx))
+ *(u64 *)&action = npc_get_mcam_action(rvu, mcam,
+ blkaddr, ucast_idx);
+
+ if (action.op != NIX_RX_ACTIONOP_RSS) {
+ *(u64 *)&action = 0x00;
+ action.op = NIX_RX_ACTIONOP_UCAST;
+ action.pf_func = pcifunc;
+ }
+
+ /* RX_ACTION set to MCAST for CGX PF's */
+ if (hw->cap.nix_rx_multicast && pfvf->use_mce_list) {
+ *(u64 *)&action = 0x00;
+ action.op = NIX_RX_ACTIONOP_MCAST;
+ action.index = pfvf->mcast_mce_idx;
+ }
+
+ mac_addr[0] = 0x01; /* LSB bit of 1st byte in DMAC */
+ ether_addr_copy(req.packet.dmac, mac_addr);
+ ether_addr_copy(req.mask.dmac, mac_addr);
+ req.features = BIT_ULL(NPC_DMAC);
+
+ /* For cn10k the upper two bits of the channel number are
+ * cpt channel number. with masking out these bits in the
+ * mcam entry, same entry used for NIX will allow packets
+ * received from cpt for parsing.
+ */
+ if (!is_rvu_otx2(rvu))
+ req.chan_mask = NIX_CHAN_CPT_X2P_MASK;
+ else
+ req.chan_mask = 0xFFFU;
+
+ req.channel = chan;
+ req.intf = pfvf->nix_rx_intf;
+ req.entry = index;
+ req.op = action.op;
+ req.hdr.pcifunc = 0; /* AF is requester */
+ req.vf = pcifunc | vf_func;
+ req.index = action.index;
+ req.match_id = action.match_id;
+ req.flow_key_alg = action.flow_key_alg;
+
+ rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp);
+}
+
+void rvu_npc_enable_allmulti_entry(struct rvu *rvu, u16 pcifunc, int nixlf,
+ bool enable)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ int blkaddr, index;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return;
+
+ /* Get 'pcifunc' of PF device */
+ pcifunc = pcifunc & ~RVU_PFVF_FUNC_MASK;
+
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf,
+ NIXLF_ALLMULTI_ENTRY);
npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
}
@@ -858,6 +959,7 @@ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
int group, int alg_idx, int mcam_index)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct rvu_hwinfo *hw = rvu->hw;
struct nix_rx_action action;
int blkaddr, index, bank;
struct rvu_pfvf *pfvf;
@@ -913,7 +1015,8 @@ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
/* If PF's promiscuous entry is enabled,
* Set RSS action for that entry as well
*/
- if (is_mcam_entry_enabled(rvu, mcam, blkaddr, index)) {
+ if ((!hw->cap.nix_rx_multicast || !pfvf->use_mce_list) &&
+ is_mcam_entry_enabled(rvu, mcam, blkaddr, index)) {
bank = npc_get_bank(mcam, index);
index &= (mcam->banksize - 1);
@@ -923,12 +1026,47 @@ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
}
}
+void npc_enadis_default_mce_entry(struct rvu *rvu, u16 pcifunc,
+ int nixlf, int type, bool enable)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct rvu_hwinfo *hw = rvu->hw;
+ struct nix_mce_list *mce_list;
+ int index, blkaddr, mce_idx;
+ struct rvu_pfvf *pfvf;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return;
+
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc & ~RVU_PFVF_FUNC_MASK,
+ nixlf, type);
+
+ /* disable MCAM entry when packet replication is not supported by hw */
+ if (!hw->cap.nix_rx_multicast && !is_vf(pcifunc)) {
+ npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
+ return;
+ }
+
+ /* return incase mce list is not enabled */
+ pfvf = rvu_get_pfvf(rvu, pcifunc & ~RVU_PFVF_FUNC_MASK);
+ if (hw->cap.nix_rx_multicast && is_vf(pcifunc) &&
+ type != NIXLF_BCAST_ENTRY && !pfvf->use_mce_list)
+ return;
+
+ nix_get_mce_list(rvu, pcifunc, type, &mce_list, &mce_idx);
+
+ nix_update_mce_list(rvu, pcifunc, mce_list,
+ mce_idx, index, enable);
+ if (enable)
+ npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
+}
+
static void npc_enadis_default_entries(struct rvu *rvu, u16 pcifunc,
int nixlf, bool enable)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
- struct nix_rx_action action;
- int index, bank, blkaddr;
+ int index, blkaddr;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
if (blkaddr < 0)
@@ -939,48 +1077,33 @@ static void npc_enadis_default_entries(struct rvu *rvu, u16 pcifunc,
nixlf, NIXLF_UCAST_ENTRY);
npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
- /* For PF, ena/dis promisc and bcast MCAM match entries.
- * For VFs add/delete from bcast list when RX multicast
- * feature is present.
+ /* Nothing to do for VFs, on platforms where pkt replication
+ * is not supported
*/
- if (pcifunc & RVU_PFVF_FUNC_MASK && !rvu->hw->cap.nix_rx_multicast)
+ if ((pcifunc & RVU_PFVF_FUNC_MASK) && !rvu->hw->cap.nix_rx_multicast)
return;
- /* For bcast, enable/disable only if it's action is not
- * packet replication, incase if action is replication
- * then this PF/VF's nixlf is removed from bcast replication
- * list.
- */
- index = npc_get_nixlf_mcam_index(mcam, pcifunc & ~RVU_PFVF_FUNC_MASK,
- nixlf, NIXLF_BCAST_ENTRY);
- bank = npc_get_bank(mcam, index);
- *(u64 *)&action = rvu_read64(rvu, blkaddr,
- NPC_AF_MCAMEX_BANKX_ACTION(index & (mcam->banksize - 1), bank));
-
- /* VFs will not have BCAST entry */
- if (action.op != NIX_RX_ACTIONOP_MCAST &&
- !(pcifunc & RVU_PFVF_FUNC_MASK)) {
- npc_enable_mcam_entry(rvu, mcam,
- blkaddr, index, enable);
- } else {
- nix_update_bcast_mce_list(rvu, pcifunc, enable);
- /* Enable PF's BCAST entry for packet replication */
- rvu_npc_enable_bcast_entry(rvu, pcifunc, enable);
- }
-
- if (enable)
- rvu_npc_enable_promisc_entry(rvu, pcifunc, nixlf);
- else
- rvu_npc_disable_promisc_entry(rvu, pcifunc, nixlf);
+ /* add/delete pf_func to broadcast MCE list */
+ npc_enadis_default_mce_entry(rvu, pcifunc, nixlf,
+ NIXLF_BCAST_ENTRY, enable);
}
void rvu_npc_disable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf)
{
npc_enadis_default_entries(rvu, pcifunc, nixlf, false);
+
+ /* Delete multicast and promisc MCAM entries */
+ npc_enadis_default_mce_entry(rvu, pcifunc, nixlf,
+ NIXLF_ALLMULTI_ENTRY, false);
+ npc_enadis_default_mce_entry(rvu, pcifunc, nixlf,
+ NIXLF_PROMISC_ENTRY, false);
}
void rvu_npc_enable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf)
{
+ /* Enables only broadcast match entry. Promisc/Allmulti are enabled
+ * in set_rx_mode mbox handler.
+ */
npc_enadis_default_entries(rvu, pcifunc, nixlf, true);
}
@@ -1000,7 +1123,8 @@ void rvu_npc_disable_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf)
/* Disable MCAM entries directing traffic to this 'pcifunc' */
list_for_each_entry_safe(rule, tmp, &mcam->mcam_rules, list) {
if (is_npc_intf_rx(rule->intf) &&
- rule->rx_action.pf_func == pcifunc) {
+ rule->rx_action.pf_func == pcifunc &&
+ rule->rx_action.op != NIX_RX_ACTIONOP_MCAST) {
npc_enable_mcam_entry(rvu, mcam, blkaddr,
rule->entry, false);
rule->enable = false;
@@ -1134,6 +1258,30 @@ static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr,
}
}
+static int npc_fwdb_prfl_img_map(struct rvu *rvu, void __iomem **prfl_img_addr,
+ u64 *size)
+{
+ u64 prfl_addr, prfl_sz;
+
+ if (!rvu->fwdata)
+ return -EINVAL;
+
+ prfl_addr = rvu->fwdata->mcam_addr;
+ prfl_sz = rvu->fwdata->mcam_sz;
+
+ if (!prfl_addr || !prfl_sz)
+ return -EINVAL;
+
+ *prfl_img_addr = ioremap_wc(prfl_addr, prfl_sz);
+ if (!(*prfl_img_addr))
+ return -ENOMEM;
+
+ *size = prfl_sz;
+
+ return 0;
+}
+
+/* strtoull of "mkexprof" with base:36 */
#define MKEX_END_SIGN 0xdeadbeef
static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr,
@@ -1141,26 +1289,21 @@ static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr,
{
struct device *dev = &rvu->pdev->dev;
struct npc_mcam_kex *mcam_kex;
- void *mkex_prfl_addr = NULL;
- u64 prfl_addr, prfl_sz;
+ void __iomem *mkex_prfl_addr = NULL;
+ u64 prfl_sz;
+ int ret;
/* If user not selected mkex profile */
- if (!strncmp(mkex_profile, def_pfl_name, MKEX_NAME_LEN))
- goto program_mkex;
-
- if (!rvu->fwdata)
- goto program_mkex;
- prfl_addr = rvu->fwdata->mcam_addr;
- prfl_sz = rvu->fwdata->mcam_sz;
-
- if (!prfl_addr || !prfl_sz)
+ if (rvu->kpu_fwdata_sz ||
+ !strncmp(mkex_profile, def_pfl_name, MKEX_NAME_LEN))
goto program_mkex;
- mkex_prfl_addr = memremap(prfl_addr, prfl_sz, MEMREMAP_WC);
- if (!mkex_prfl_addr)
+ /* Setting up the mapping for mkex profile image */
+ ret = npc_fwdb_prfl_img_map(rvu, &mkex_prfl_addr, &prfl_sz);
+ if (ret < 0)
goto program_mkex;
- mcam_kex = (struct npc_mcam_kex *)mkex_prfl_addr;
+ mcam_kex = (struct npc_mcam_kex __force *)mkex_prfl_addr;
while (((s64)prfl_sz > 0) && (mcam_kex->mkex_sign != MKEX_END_SIGN)) {
/* Compare with mkex mod_param name string */
@@ -1186,7 +1329,7 @@ program_mkex:
/* Program selected mkex profile */
npc_program_mkex_profile(rvu, blkaddr, rvu->kpu.mkex);
if (mkex_prfl_addr)
- memunmap(mkex_prfl_addr);
+ iounmap(mkex_prfl_addr);
}
static void npc_config_kpuaction(struct rvu *rvu, int blkaddr,
@@ -1263,6 +1406,7 @@ static void npc_program_kpu_profile(struct rvu *rvu, int blkaddr, int kpu,
const struct npc_kpu_profile *profile)
{
int entry, num_entries, max_entries;
+ u64 entry_mask;
if (profile->cam_entries != profile->action_entries) {
dev_err(rvu->dev,
@@ -1286,8 +1430,12 @@ static void npc_program_kpu_profile(struct rvu *rvu, int blkaddr, int kpu,
/* Enable all programmed entries */
num_entries = min_t(int, profile->action_entries, profile->cam_entries);
+ entry_mask = enable_mask(num_entries);
+ /* Disable first KPU_MAX_CST_ENT entries for built-in profile */
+ if (!rvu->kpu.custom)
+ entry_mask |= GENMASK_ULL(KPU_MAX_CST_ENT - 1, 0);
rvu_write64(rvu, blkaddr,
- NPC_AF_KPUX_ENTRY_DISX(kpu, 0), enable_mask(num_entries));
+ NPC_AF_KPUX_ENTRY_DISX(kpu, 0), entry_mask);
if (num_entries > 64) {
rvu_write64(rvu, blkaddr,
NPC_AF_KPUX_ENTRY_DISX(kpu, 1),
@@ -1300,6 +1448,7 @@ static void npc_program_kpu_profile(struct rvu *rvu, int blkaddr, int kpu,
static int npc_prepare_default_kpu(struct npc_kpu_profile_adapter *profile)
{
+ profile->custom = 0;
profile->name = def_pfl_name;
profile->version = NPC_KPU_PROFILE_VER;
profile->ikpu = ikpu_action_entries;
@@ -1312,10 +1461,245 @@ static int npc_prepare_default_kpu(struct npc_kpu_profile_adapter *profile)
return 0;
}
+static int npc_apply_custom_kpu(struct rvu *rvu,
+ struct npc_kpu_profile_adapter *profile)
+{
+ size_t hdr_sz = sizeof(struct npc_kpu_profile_fwdata), offset = 0;
+ struct npc_kpu_profile_fwdata *fw = rvu->kpu_fwdata;
+ struct npc_kpu_profile_action *action;
+ struct npc_kpu_profile_cam *cam;
+ struct npc_kpu_fwdata *fw_kpu;
+ int entries;
+ u16 kpu, entry;
+
+ if (rvu->kpu_fwdata_sz < hdr_sz) {
+ dev_warn(rvu->dev, "Invalid KPU profile size\n");
+ return -EINVAL;
+ }
+ if (le64_to_cpu(fw->signature) != KPU_SIGN) {
+ dev_warn(rvu->dev, "Invalid KPU profile signature %llx\n",
+ fw->signature);
+ return -EINVAL;
+ }
+ /* Verify if the using known profile structure */
+ if (NPC_KPU_VER_MAJ(profile->version) >
+ NPC_KPU_VER_MAJ(NPC_KPU_PROFILE_VER)) {
+ dev_warn(rvu->dev, "Not supported Major version: %d > %d\n",
+ NPC_KPU_VER_MAJ(profile->version),
+ NPC_KPU_VER_MAJ(NPC_KPU_PROFILE_VER));
+ return -EINVAL;
+ }
+ /* Verify if profile is aligned with the required kernel changes */
+ if (NPC_KPU_VER_MIN(profile->version) <
+ NPC_KPU_VER_MIN(NPC_KPU_PROFILE_VER)) {
+ dev_warn(rvu->dev,
+ "Invalid KPU profile version: %d.%d.%d expected version <= %d.%d.%d\n",
+ NPC_KPU_VER_MAJ(profile->version),
+ NPC_KPU_VER_MIN(profile->version),
+ NPC_KPU_VER_PATCH(profile->version),
+ NPC_KPU_VER_MAJ(NPC_KPU_PROFILE_VER),
+ NPC_KPU_VER_MIN(NPC_KPU_PROFILE_VER),
+ NPC_KPU_VER_PATCH(NPC_KPU_PROFILE_VER));
+ return -EINVAL;
+ }
+ /* Verify if profile fits the HW */
+ if (fw->kpus > profile->kpus) {
+ dev_warn(rvu->dev, "Not enough KPUs: %d > %ld\n", fw->kpus,
+ profile->kpus);
+ return -EINVAL;
+ }
+
+ profile->custom = 1;
+ profile->name = fw->name;
+ profile->version = le64_to_cpu(fw->version);
+ profile->mkex = &fw->mkex;
+ profile->lt_def = &fw->lt_def;
+
+ for (kpu = 0; kpu < fw->kpus; kpu++) {
+ fw_kpu = (struct npc_kpu_fwdata *)(fw->data + offset);
+ if (fw_kpu->entries > KPU_MAX_CST_ENT)
+ dev_warn(rvu->dev,
+ "Too many custom entries on KPU%d: %d > %d\n",
+ kpu, fw_kpu->entries, KPU_MAX_CST_ENT);
+ entries = min(fw_kpu->entries, KPU_MAX_CST_ENT);
+ cam = (struct npc_kpu_profile_cam *)fw_kpu->data;
+ offset += sizeof(*fw_kpu) + fw_kpu->entries * sizeof(*cam);
+ action = (struct npc_kpu_profile_action *)(fw->data + offset);
+ offset += fw_kpu->entries * sizeof(*action);
+ if (rvu->kpu_fwdata_sz < hdr_sz + offset) {
+ dev_warn(rvu->dev,
+ "Profile size mismatch on KPU%i parsing.\n",
+ kpu + 1);
+ return -EINVAL;
+ }
+ for (entry = 0; entry < entries; entry++) {
+ profile->kpu[kpu].cam[entry] = cam[entry];
+ profile->kpu[kpu].action[entry] = action[entry];
+ }
+ }
+
+ return 0;
+}
+
+static int npc_load_kpu_prfl_img(struct rvu *rvu, void __iomem *prfl_addr,
+ u64 prfl_sz, const char *kpu_profile)
+{
+ struct npc_kpu_profile_fwdata *kpu_data = NULL;
+ int rc = -EINVAL;
+
+ kpu_data = (struct npc_kpu_profile_fwdata __force *)prfl_addr;
+ if (le64_to_cpu(kpu_data->signature) == KPU_SIGN &&
+ !strncmp(kpu_data->name, kpu_profile, KPU_NAME_LEN)) {
+ dev_info(rvu->dev, "Loading KPU profile from firmware db: %s\n",
+ kpu_profile);
+ rvu->kpu_fwdata = kpu_data;
+ rvu->kpu_fwdata_sz = prfl_sz;
+ rvu->kpu_prfl_addr = prfl_addr;
+ rc = 0;
+ }
+
+ return rc;
+}
+
+static int npc_fwdb_detect_load_prfl_img(struct rvu *rvu, uint64_t prfl_sz,
+ const char *kpu_profile)
+{
+ struct npc_coalesced_kpu_prfl *img_data = NULL;
+ int i = 0, rc = -EINVAL;
+ void __iomem *kpu_prfl_addr;
+ u16 offset;
+
+ img_data = (struct npc_coalesced_kpu_prfl __force *)rvu->kpu_prfl_addr;
+ if (le64_to_cpu(img_data->signature) == KPU_SIGN &&
+ !strncmp(img_data->name, kpu_profile, KPU_NAME_LEN)) {
+ /* Loaded profile is a single KPU profile. */
+ rc = npc_load_kpu_prfl_img(rvu, rvu->kpu_prfl_addr,
+ prfl_sz, kpu_profile);
+ goto done;
+ }
+
+ /* Loaded profile is coalesced image, offset of first KPU profile.*/
+ offset = offsetof(struct npc_coalesced_kpu_prfl, prfl_sz) +
+ (img_data->num_prfl * sizeof(uint16_t));
+ /* Check if mapped image is coalesced image. */
+ while (i < img_data->num_prfl) {
+ /* Profile image offsets are rounded up to next 8 multiple.*/
+ offset = ALIGN_8B_CEIL(offset);
+ kpu_prfl_addr = (void __iomem *)((uintptr_t)rvu->kpu_prfl_addr +
+ offset);
+ rc = npc_load_kpu_prfl_img(rvu, kpu_prfl_addr,
+ img_data->prfl_sz[i], kpu_profile);
+ if (!rc)
+ break;
+ /* Calculating offset of profile image based on profile size.*/
+ offset += img_data->prfl_sz[i];
+ i++;
+ }
+done:
+ return rc;
+}
+
+static int npc_load_kpu_profile_fwdb(struct rvu *rvu, const char *kpu_profile)
+{
+ int ret = -EINVAL;
+ u64 prfl_sz;
+
+ /* Setting up the mapping for NPC profile image */
+ ret = npc_fwdb_prfl_img_map(rvu, &rvu->kpu_prfl_addr, &prfl_sz);
+ if (ret < 0)
+ goto done;
+
+ /* Detect if profile is coalesced or single KPU profile and load */
+ ret = npc_fwdb_detect_load_prfl_img(rvu, prfl_sz, kpu_profile);
+ if (ret == 0)
+ goto done;
+
+ /* Cleaning up if KPU profile image from fwdata is not valid. */
+ if (rvu->kpu_prfl_addr) {
+ iounmap(rvu->kpu_prfl_addr);
+ rvu->kpu_prfl_addr = NULL;
+ rvu->kpu_fwdata_sz = 0;
+ rvu->kpu_fwdata = NULL;
+ }
+
+done:
+ return ret;
+}
+
static void npc_load_kpu_profile(struct rvu *rvu)
{
struct npc_kpu_profile_adapter *profile = &rvu->kpu;
+ const char *kpu_profile = rvu->kpu_pfl_name;
+ const struct firmware *fw = NULL;
+ bool retry_fwdb = false;
+
+ /* If user not specified profile customization */
+ if (!strncmp(kpu_profile, def_pfl_name, KPU_NAME_LEN))
+ goto revert_to_default;
+ /* First prepare default KPU, then we'll customize top entries. */
+ npc_prepare_default_kpu(profile);
+ /* Order of preceedence for load loading NPC profile (high to low)
+ * Firmware binary in filesystem.
+ * Firmware database method.
+ * Default KPU profile.
+ */
+ if (!request_firmware(&fw, kpu_profile, rvu->dev)) {
+ dev_info(rvu->dev, "Loading KPU profile from firmware: %s\n",
+ kpu_profile);
+ rvu->kpu_fwdata = kzalloc(fw->size, GFP_KERNEL);
+ if (rvu->kpu_fwdata) {
+ memcpy(rvu->kpu_fwdata, fw->data, fw->size);
+ rvu->kpu_fwdata_sz = fw->size;
+ }
+ release_firmware(fw);
+ retry_fwdb = true;
+ goto program_kpu;
+ }
+
+load_image_fwdb:
+ /* Loading the KPU profile using firmware database */
+ if (npc_load_kpu_profile_fwdb(rvu, kpu_profile))
+ goto revert_to_default;
+
+program_kpu:
+ /* Apply profile customization if firmware was loaded. */
+ if (!rvu->kpu_fwdata_sz || npc_apply_custom_kpu(rvu, profile)) {
+ /* If image from firmware filesystem fails to load or invalid
+ * retry with firmware database method.
+ */
+ if (rvu->kpu_fwdata || rvu->kpu_fwdata_sz) {
+ /* Loading image from firmware database failed. */
+ if (rvu->kpu_prfl_addr) {
+ iounmap(rvu->kpu_prfl_addr);
+ rvu->kpu_prfl_addr = NULL;
+ } else {
+ kfree(rvu->kpu_fwdata);
+ }
+ rvu->kpu_fwdata = NULL;
+ rvu->kpu_fwdata_sz = 0;
+ if (retry_fwdb) {
+ retry_fwdb = false;
+ goto load_image_fwdb;
+ }
+ }
+
+ dev_warn(rvu->dev,
+ "Can't load KPU profile %s. Using default.\n",
+ kpu_profile);
+ kfree(rvu->kpu_fwdata);
+ rvu->kpu_fwdata = NULL;
+ goto revert_to_default;
+ }
+
+ dev_info(rvu->dev, "Using custom profile '%s', version %d.%d.%d\n",
+ profile->name, NPC_KPU_VER_MAJ(profile->version),
+ NPC_KPU_VER_MIN(profile->version),
+ NPC_KPU_VER_PATCH(profile->version));
+
+ return;
+
+revert_to_default:
npc_prepare_default_kpu(profile);
}
@@ -1654,6 +2038,10 @@ void rvu_npc_freemem(struct rvu *rvu)
kfree(pkind->rsrc.bmap);
kfree(mcam->counters.bmap);
+ if (rvu->kpu_prfl_addr)
+ iounmap(rvu->kpu_prfl_addr);
+ else
+ kfree(rvu->kpu_fwdata);
mutex_destroy(&mcam->lock);
}
@@ -2149,8 +2537,11 @@ int rvu_mbox_handler_npc_mcam_alloc_entry(struct rvu *rvu,
rsp->free_count = 0;
/* Check if ref_entry is within range */
- if (req->priority && req->ref_entry >= mcam->bmap_entries)
+ if (req->priority && req->ref_entry >= mcam->bmap_entries) {
+ dev_err(rvu->dev, "%s: reference entry %d is out of range\n",
+ __func__, req->ref_entry);
return NPC_MCAM_INVALID_REQ;
+ }
/* ref_entry can't be '0' if requested priority is high.
* Can't be last entry if requested priority is low.
@@ -2163,8 +2554,12 @@ int rvu_mbox_handler_npc_mcam_alloc_entry(struct rvu *rvu,
/* Since list of allocated indices needs to be sent to requester,
* max number of non-contiguous entries per mbox msg is limited.
*/
- if (!req->contig && req->count > NPC_MAX_NONCONTIG_ENTRIES)
+ if (!req->contig && req->count > NPC_MAX_NONCONTIG_ENTRIES) {
+ dev_err(rvu->dev,
+ "%s: %d Non-contiguous MCAM entries requested is more than max (%d) allowed\n",
+ __func__, req->count, NPC_MAX_NONCONTIG_ENTRIES);
return NPC_MCAM_INVALID_REQ;
+ }
/* Alloc request from PFFUNC with no NIXLF attached should be denied */
if (!is_nixlf_attached(rvu, pcifunc))
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
index 7f35b62eea13..68633145a8b8 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
@@ -123,11 +123,8 @@ static bool npc_is_field_present(struct rvu *rvu, enum key_fields type, u8 intf)
static bool npc_is_same(struct npc_key_field *input,
struct npc_key_field *field)
{
- int ret;
-
- ret = memcmp(&input->layer_mdata, &field->layer_mdata,
- sizeof(struct npc_layer_mdata));
- return ret == 0;
+ return memcmp(&input->layer_mdata, &field->layer_mdata,
+ sizeof(struct npc_layer_mdata)) == 0;
}
static void npc_set_layer_mdata(struct npc_mcam *mcam, enum key_fields type,
@@ -1103,11 +1100,18 @@ find_rule:
if (pf_set_vfs_mac) {
ether_addr_copy(pfvf->default_mac, req->packet.dmac);
ether_addr_copy(pfvf->mac_addr, req->packet.dmac);
+ set_bit(PF_SET_VF_MAC, &pfvf->flags);
}
- if (pfvf->pf_set_vf_cfg && req->vtag0_type == NIX_AF_LFX_RX_VTAG_TYPE7)
+ if (test_bit(PF_SET_VF_CFG, &pfvf->flags) &&
+ req->vtag0_type == NIX_AF_LFX_RX_VTAG_TYPE7)
rule->vfvlan_cfg = true;
+ if (is_npc_intf_rx(req->intf) && req->match_id &&
+ (req->op == NIX_RX_ACTIONOP_UCAST || req->op == NIX_RX_ACTIONOP_RSS))
+ return rvu_nix_setup_ratelimit_aggr(rvu, req->hdr.pcifunc,
+ req->index, req->match_id);
+
return 0;
}
@@ -1167,7 +1171,7 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
/* PF installing for its VF */
if (req->hdr.pcifunc && !from_vf && req->vf)
- pfvf->pf_set_vf_cfg = 1;
+ set_bit(PF_SET_VF_CFG, &pfvf->flags);
/* update req destination mac addr */
if ((req->features & BIT_ULL(NPC_DMAC)) && is_npc_intf_rx(req->intf) &&
@@ -1177,9 +1181,12 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
}
err = nix_get_nixlf(rvu, target, &nixlf, NULL);
+ if (err && is_npc_intf_rx(req->intf) && !pf_set_vfs_mac)
+ return -EINVAL;
- /* If interface is uninitialized then do not enable entry */
- if (err || (!req->default_rule && !pfvf->def_ucast_rule))
+ /* don't enable rule when nixlf not attached or initialized */
+ if (!(is_nixlf_attached(rvu, target) &&
+ test_bit(NIXLF_INITIALIZED, &pfvf->flags)))
enable = false;
/* Packets reaching NPC in Tx path implies that a
@@ -1193,6 +1200,14 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
if (from_vf && !enable)
return -EINVAL;
+ /* PF sets VF mac & VF NIXLF is not attached, update the mac addr */
+ if (pf_set_vfs_mac && !enable) {
+ ether_addr_copy(pfvf->default_mac, req->packet.dmac);
+ ether_addr_copy(pfvf->mac_addr, req->packet.dmac);
+ set_bit(PF_SET_VF_MAC, &pfvf->flags);
+ return 0;
+ }
+
/* If message is from VF then its flow should not overlap with
* reserved unicast flow.
*/
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
index ac71c0f2f960..8b01ef6e2c99 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
@@ -49,6 +49,11 @@
#define RVU_AF_PFX_VF_BAR4_ADDR (0x5400 | (a) << 4)
#define RVU_AF_PFX_VF_BAR4_CFG (0x5600 | (a) << 4)
#define RVU_AF_PFX_LMTLINE_ADDR (0x5800 | (a) << 4)
+#define RVU_AF_SMMU_ADDR_REQ (0x6000)
+#define RVU_AF_SMMU_TXN_REQ (0x6008)
+#define RVU_AF_SMMU_ADDR_RSP_STS (0x6010)
+#define RVU_AF_SMMU_ADDR_TLN (0x6018)
+#define RVU_AF_SMMU_TLN_FLIT1 (0x6030)
/* Admin function's privileged PF/VF registers */
#define RVU_PRIV_CONST (0x8000000)
@@ -171,6 +176,7 @@
#define NIX_AF_SQ_CONST (0x0040)
#define NIX_AF_CQ_CONST (0x0048)
#define NIX_AF_RQ_CONST (0x0050)
+#define NIX_AF_PL_CONST (0x0058)
#define NIX_AF_PSE_CONST (0x0060)
#define NIX_AF_TL1_CONST (0x0070)
#define NIX_AF_TL2_CONST (0x0078)
@@ -181,6 +187,7 @@
#define NIX_AF_LSO_CFG (0x00A8)
#define NIX_AF_BLK_RST (0x00B0)
#define NIX_AF_TX_TSTMP_CFG (0x00C0)
+#define NIX_AF_PL_TS (0x00C8)
#define NIX_AF_RX_CFG (0x00D0)
#define NIX_AF_AVG_DELAY (0x00E0)
#define NIX_AF_CINT_DELAY (0x00F0)
@@ -208,19 +215,27 @@
#define NIX_AF_RVU_INT_ENA_W1S (0x01D0)
#define NIX_AF_RVU_INT_ENA_W1C (0x01D8)
#define NIX_AF_TCP_TIMER (0x01E0)
-#define NIX_AF_RX_WQE_TAG_CTL (0x01F0)
+#define NIX_AF_RX_DEF_ET(a) (0x01F0ull | (uint64_t)(a) << 3)
#define NIX_AF_RX_DEF_OL2 (0x0200)
#define NIX_AF_RX_DEF_OIP4 (0x0210)
#define NIX_AF_RX_DEF_IIP4 (0x0220)
+#define NIX_AF_RX_DEF_VLAN0_PCP_DEI (0x0228)
#define NIX_AF_RX_DEF_OIP6 (0x0230)
+#define NIX_AF_RX_DEF_VLAN1_PCP_DEI (0x0238)
#define NIX_AF_RX_DEF_IIP6 (0x0240)
#define NIX_AF_RX_DEF_OTCP (0x0250)
#define NIX_AF_RX_DEF_ITCP (0x0260)
#define NIX_AF_RX_DEF_OUDP (0x0270)
#define NIX_AF_RX_DEF_IUDP (0x0280)
#define NIX_AF_RX_DEF_OSCTP (0x0290)
+#define NIX_AF_RX_DEF_CST_APAD0 (0x0298)
#define NIX_AF_RX_DEF_ISCTP (0x02A0)
#define NIX_AF_RX_DEF_IPSECX (0x02B0)
+#define NIX_AF_RX_DEF_CST_APAD1 (0x02A8)
+#define NIX_AF_RX_DEF_IIP4_DSCP (0x02E0)
+#define NIX_AF_RX_DEF_OIP4_DSCP (0x02E8)
+#define NIX_AF_RX_DEF_IIP6_DSCP (0x02F0)
+#define NIX_AF_RX_DEF_OIP6_DSCP (0x02F8)
#define NIX_AF_RX_IPSEC_GEN_CFG (0x0300)
#define NIX_AF_RX_CPTX_INST_ADDR (0x0310)
#define NIX_AF_NDC_TX_SYNC (0x03F0)
@@ -682,4 +697,9 @@
#define LBK_LINK_CFG_ID_MASK GENMASK_ULL(11, 6)
#define LBK_LINK_CFG_BASE_MASK GENMASK_ULL(5, 0)
+/* APR */
+#define APR_AF_LMT_CFG (0x000ull)
+#define APR_AF_LMT_MAP_BASE (0x008ull)
+#define APR_AF_LMT_CTL (0x010ull)
+
#endif /* RVU_REG_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
index 5e5f45c7eab0..5bbe6727d11d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
@@ -35,7 +35,8 @@ enum rvu_block_addr_e {
BLKADDR_NDC_NPA0 = 0xeULL,
BLKADDR_NDC_NIX1_RX = 0x10ULL,
BLKADDR_NDC_NIX1_TX = 0x11ULL,
- BLK_COUNT = 0x12ULL,
+ BLKADDR_APR = 0x16ULL,
+ BLK_COUNT = 0x17ULL,
};
/* RVU Block Type Enumeration */
@@ -286,7 +287,7 @@ enum nix_aq_ctype {
NIX_AQ_CTYPE_MCE = 0x3,
NIX_AQ_CTYPE_RSS = 0x4,
NIX_AQ_CTYPE_DYNO = 0x5,
- NIX_AQ_CTYPE_BAND_PROF = 0x6,
+ NIX_AQ_CTYPE_BANDPROF = 0x6,
};
/* NIX admin queue instruction opcodes */
@@ -665,6 +666,89 @@ struct nix_rx_mce_s {
uint64_t next : 16;
};
+enum nix_band_prof_layers {
+ BAND_PROF_LEAF_LAYER = 0,
+ BAND_PROF_INVAL_LAYER = 1,
+ BAND_PROF_MID_LAYER = 2,
+ BAND_PROF_TOP_LAYER = 3,
+ BAND_PROF_NUM_LAYERS = 4,
+};
+
+enum NIX_RX_BAND_PROF_ACTIONRESULT_E {
+ NIX_RX_BAND_PROF_ACTIONRESULT_PASS = 0x0,
+ NIX_RX_BAND_PROF_ACTIONRESULT_DROP = 0x1,
+ NIX_RX_BAND_PROF_ACTIONRESULT_RED = 0x2,
+};
+
+enum nix_band_prof_pc_mode {
+ NIX_RX_PC_MODE_VLAN = 0,
+ NIX_RX_PC_MODE_DSCP = 1,
+ NIX_RX_PC_MODE_GEN = 2,
+ NIX_RX_PC_MODE_RSVD = 3,
+};
+
+/* NIX ingress policer bandwidth profile structure */
+struct nix_bandprof_s {
+ uint64_t pc_mode : 2; /* W0 */
+ uint64_t icolor : 2;
+ uint64_t tnl_ena : 1;
+ uint64_t reserved_5_7 : 3;
+ uint64_t peir_exponent : 5;
+ uint64_t reserved_13_15 : 3;
+ uint64_t pebs_exponent : 5;
+ uint64_t reserved_21_23 : 3;
+ uint64_t cir_exponent : 5;
+ uint64_t reserved_29_31 : 3;
+ uint64_t cbs_exponent : 5;
+ uint64_t reserved_37_39 : 3;
+ uint64_t peir_mantissa : 8;
+ uint64_t pebs_mantissa : 8;
+ uint64_t cir_mantissa : 8;
+ uint64_t cbs_mantissa : 8; /* W1 */
+ uint64_t lmode : 1;
+ uint64_t l_sellect : 3;
+ uint64_t rdiv : 4;
+ uint64_t adjust_exponent : 5;
+ uint64_t reserved_85_86 : 2;
+ uint64_t adjust_mantissa : 9;
+ uint64_t gc_action : 2;
+ uint64_t yc_action : 2;
+ uint64_t rc_action : 2;
+ uint64_t meter_algo : 2;
+ uint64_t band_prof_id : 7;
+ uint64_t reserved_111_118 : 8;
+ uint64_t hl_en : 1;
+ uint64_t reserved_120_127 : 8;
+ uint64_t ts : 48; /* W2 */
+ uint64_t reserved_176_191 : 16;
+ uint64_t pe_accum : 32; /* W3 */
+ uint64_t c_accum : 32;
+ uint64_t green_pkt_pass : 48; /* W4 */
+ uint64_t reserved_304_319 : 16;
+ uint64_t yellow_pkt_pass : 48; /* W5 */
+ uint64_t reserved_368_383 : 16;
+ uint64_t red_pkt_pass : 48; /* W6 */
+ uint64_t reserved_432_447 : 16;
+ uint64_t green_octs_pass : 48; /* W7 */
+ uint64_t reserved_496_511 : 16;
+ uint64_t yellow_octs_pass : 48; /* W8 */
+ uint64_t reserved_560_575 : 16;
+ uint64_t red_octs_pass : 48; /* W9 */
+ uint64_t reserved_624_639 : 16;
+ uint64_t green_pkt_drop : 48; /* W10 */
+ uint64_t reserved_688_703 : 16;
+ uint64_t yellow_pkt_drop : 48; /* W11 */
+ uint64_t reserved_752_767 : 16;
+ uint64_t red_pkt_drop : 48; /* W12 */
+ uint64_t reserved_816_831 : 16;
+ uint64_t green_octs_drop : 48; /* W13 */
+ uint64_t reserved_880_895 : 16;
+ uint64_t yellow_octs_drop : 48; /* W14 */
+ uint64_t reserved_944_959 : 16;
+ uint64_t red_octs_drop : 48; /* W15 */
+ uint64_t reserved_1008_1023 : 16;
+};
+
enum nix_lsoalg {
NIX_LSOALG_NOP,
NIX_LSOALG_ADD_SEGNUM,
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_trace.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_trace.h
index e6609068e81b..64aa7d350df1 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_trace.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_trace.h
@@ -21,7 +21,7 @@ TRACE_EVENT(otx2_msg_alloc,
__field(u16, id)
__field(u64, size)
),
- TP_fast_assign(__assign_str(dev, pci_name(pdev))
+ TP_fast_assign(__assign_str(dev, pci_name(pdev));
__entry->id = id;
__entry->size = size;
),
@@ -36,7 +36,7 @@ TRACE_EVENT(otx2_msg_send,
__field(u16, num_msgs)
__field(u64, msg_size)
),
- TP_fast_assign(__assign_str(dev, pci_name(pdev))
+ TP_fast_assign(__assign_str(dev, pci_name(pdev));
__entry->num_msgs = num_msgs;
__entry->msg_size = msg_size;
),
@@ -52,7 +52,7 @@ TRACE_EVENT(otx2_msg_check,
__field(u16, rspid)
__field(int, rc)
),
- TP_fast_assign(__assign_str(dev, pci_name(pdev))
+ TP_fast_assign(__assign_str(dev, pci_name(pdev));
__entry->reqid = reqid;
__entry->rspid = rspid;
__entry->rc = rc;
@@ -69,8 +69,8 @@ TRACE_EVENT(otx2_msg_interrupt,
__string(str, msg)
__field(u64, intr)
),
- TP_fast_assign(__assign_str(dev, pci_name(pdev))
- __assign_str(str, msg)
+ TP_fast_assign(__assign_str(dev, pci_name(pdev));
+ __assign_str(str, msg);
__entry->intr = intr;
),
TP_printk("[%s] mbox interrupt %s (0x%llx)\n", __get_str(dev),
@@ -84,7 +84,7 @@ TRACE_EVENT(otx2_msg_process,
__field(u16, id)
__field(int, err)
),
- TP_fast_assign(__assign_str(dev, pci_name(pdev))
+ TP_fast_assign(__assign_str(dev, pci_name(pdev));
__entry->id = id;
__entry->err = err;
),
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile b/drivers/net/ethernet/marvell/octeontx2/nic/Makefile
index 457c94793e63..3254b02205ca 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/Makefile
@@ -7,7 +7,7 @@ obj-$(CONFIG_OCTEONTX2_PF) += rvu_nicpf.o
obj-$(CONFIG_OCTEONTX2_VF) += rvu_nicvf.o
rvu_nicpf-y := otx2_pf.o otx2_common.o otx2_txrx.o otx2_ethtool.o \
- otx2_ptp.o otx2_flows.o otx2_tc.o cn10k.o
+ otx2_ptp.o otx2_flows.o otx2_tc.o cn10k.o otx2_dmac_flt.o
rvu_nicvf-y := otx2_vf.o
ccflags-y += -I$(srctree)/drivers/net/ethernet/marvell/octeontx2/af
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c
index 9ec0313f13fc..184de9466286 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c
@@ -22,69 +22,52 @@ static struct dev_hw_ops cn10k_hw_ops = {
.refill_pool_ptrs = cn10k_refill_pool_ptrs,
};
-int cn10k_pf_lmtst_init(struct otx2_nic *pf)
+int cn10k_lmtst_init(struct otx2_nic *pfvf)
{
- int size, num_lines;
- u64 base;
- if (!test_bit(CN10K_LMTST, &pf->hw.cap_flag)) {
- pf->hw_ops = &otx2_hw_ops;
+ struct lmtst_tbl_setup_req *req;
+ int qcount, err;
+
+ if (!test_bit(CN10K_LMTST, &pfvf->hw.cap_flag)) {
+ pfvf->hw_ops = &otx2_hw_ops;
return 0;
}
- pf->hw_ops = &cn10k_hw_ops;
- base = pci_resource_start(pf->pdev, PCI_MBOX_BAR_NUM) +
- (MBOX_SIZE * (pf->total_vfs + 1));
-
- size = pci_resource_len(pf->pdev, PCI_MBOX_BAR_NUM) -
- (MBOX_SIZE * (pf->total_vfs + 1));
-
- pf->hw.lmt_base = ioremap(base, size);
+ pfvf->hw_ops = &cn10k_hw_ops;
+ qcount = pfvf->hw.max_queues;
+ /* LMTST lines allocation
+ * qcount = num_online_cpus();
+ * NPA = TX + RX + XDP.
+ * NIX = TX * 32 (For Burst SQE flush).
+ */
+ pfvf->tot_lmt_lines = (qcount * 3) + (qcount * 32);
+ pfvf->npa_lmt_lines = qcount * 3;
+ pfvf->nix_lmt_size = LMT_BURST_SIZE * LMT_LINE_SIZE;
- if (!pf->hw.lmt_base) {
- dev_err(pf->dev, "Unable to map PF LMTST region\n");
+ mutex_lock(&pfvf->mbox.lock);
+ req = otx2_mbox_alloc_msg_lmtst_tbl_setup(&pfvf->mbox);
+ if (!req) {
+ mutex_unlock(&pfvf->mbox.lock);
return -ENOMEM;
}
- /* FIXME: Get the num of LMTST lines from LMT table */
- pf->tot_lmt_lines = size / LMT_LINE_SIZE;
- num_lines = (pf->tot_lmt_lines - NIX_LMTID_BASE) /
- pf->hw.tx_queues;
- /* Number of LMT lines per SQ queues */
- pf->nix_lmt_lines = num_lines > 32 ? 32 : num_lines;
-
- pf->nix_lmt_size = pf->nix_lmt_lines * LMT_LINE_SIZE;
- return 0;
-}
-
-int cn10k_vf_lmtst_init(struct otx2_nic *vf)
-{
- int size, num_lines;
+ req->use_local_lmt_region = true;
- if (!test_bit(CN10K_LMTST, &vf->hw.cap_flag)) {
- vf->hw_ops = &otx2_hw_ops;
- return 0;
+ err = qmem_alloc(pfvf->dev, &pfvf->dync_lmt, pfvf->tot_lmt_lines,
+ LMT_LINE_SIZE);
+ if (err) {
+ mutex_unlock(&pfvf->mbox.lock);
+ return err;
}
+ pfvf->hw.lmt_base = (u64 *)pfvf->dync_lmt->base;
+ req->lmt_iova = (u64)pfvf->dync_lmt->iova;
- vf->hw_ops = &cn10k_hw_ops;
- size = pci_resource_len(vf->pdev, PCI_MBOX_BAR_NUM);
- vf->hw.lmt_base = ioremap_wc(pci_resource_start(vf->pdev,
- PCI_MBOX_BAR_NUM),
- size);
- if (!vf->hw.lmt_base) {
- dev_err(vf->dev, "Unable to map VF LMTST region\n");
- return -ENOMEM;
- }
+ err = otx2_sync_mbox_msg(&pfvf->mbox);
+ mutex_unlock(&pfvf->mbox.lock);
- vf->tot_lmt_lines = size / LMT_LINE_SIZE;
- /* LMTST lines per SQ */
- num_lines = (vf->tot_lmt_lines - NIX_LMTID_BASE) /
- vf->hw.tx_queues;
- vf->nix_lmt_lines = num_lines > 32 ? 32 : num_lines;
- vf->nix_lmt_size = vf->nix_lmt_lines * LMT_LINE_SIZE;
return 0;
}
-EXPORT_SYMBOL(cn10k_vf_lmtst_init);
+EXPORT_SYMBOL(cn10k_lmtst_init);
int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura)
{
@@ -93,9 +76,11 @@ int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura)
struct otx2_snd_queue *sq;
sq = &pfvf->qset.sq[qidx];
- sq->lmt_addr = (__force u64 *)((u64)pfvf->hw.nix_lmt_base +
+ sq->lmt_addr = (u64 *)((u64)pfvf->hw.nix_lmt_base +
(qidx * pfvf->nix_lmt_size));
+ sq->lmt_id = pfvf->npa_lmt_lines + (qidx * LMT_BURST_SIZE);
+
/* Get memory to put this msg */
aq = otx2_mbox_alloc_msg_nix_cn10k_aq_enq(&pfvf->mbox);
if (!aq)
@@ -158,15 +143,13 @@ void cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq)
void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx)
{
- struct otx2_nic *pfvf = dev;
- int lmt_id = NIX_LMTID_BASE + (qidx * pfvf->nix_lmt_lines);
u64 val = 0, tar_addr = 0;
/* FIXME: val[0:10] LMT_ID.
* [12:15] no of LMTST - 1 in the burst.
* [19:63] data size of each LMTST in the burst except first.
*/
- val = (lmt_id & 0x7FF);
+ val = (sq->lmt_id & 0x7FF);
/* Target address for LMTST flush tells HW how many 128bit
* words are present.
* tar_addr[6:4] size of first LMTST - 1 in units of 128b.
@@ -179,3 +162,326 @@ void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx)
sq->head++;
sq->head &= (sq->sqe_cnt - 1);
}
+
+int cn10k_free_all_ipolicers(struct otx2_nic *pfvf)
+{
+ struct nix_bandprof_free_req *req;
+ int rc;
+
+ if (is_dev_otx2(pfvf->pdev))
+ return 0;
+
+ mutex_lock(&pfvf->mbox.lock);
+
+ req = otx2_mbox_alloc_msg_nix_bandprof_free(&pfvf->mbox);
+ if (!req) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* Free all bandwidth profiles allocated */
+ req->free_all = true;
+
+ rc = otx2_sync_mbox_msg(&pfvf->mbox);
+out:
+ mutex_unlock(&pfvf->mbox.lock);
+ return rc;
+}
+
+int cn10k_alloc_leaf_profile(struct otx2_nic *pfvf, u16 *leaf)
+{
+ struct nix_bandprof_alloc_req *req;
+ struct nix_bandprof_alloc_rsp *rsp;
+ int rc;
+
+ req = otx2_mbox_alloc_msg_nix_bandprof_alloc(&pfvf->mbox);
+ if (!req)
+ return -ENOMEM;
+
+ req->prof_count[BAND_PROF_LEAF_LAYER] = 1;
+
+ rc = otx2_sync_mbox_msg(&pfvf->mbox);
+ if (rc)
+ goto out;
+
+ rsp = (struct nix_bandprof_alloc_rsp *)
+ otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr);
+ if (!rsp->prof_count[BAND_PROF_LEAF_LAYER]) {
+ rc = -EIO;
+ goto out;
+ }
+
+ *leaf = rsp->prof_idx[BAND_PROF_LEAF_LAYER][0];
+out:
+ if (rc) {
+ dev_warn(pfvf->dev,
+ "Failed to allocate ingress bandwidth policer\n");
+ }
+
+ return rc;
+}
+
+int cn10k_alloc_matchall_ipolicer(struct otx2_nic *pfvf)
+{
+ struct otx2_hw *hw = &pfvf->hw;
+ int ret;
+
+ mutex_lock(&pfvf->mbox.lock);
+
+ ret = cn10k_alloc_leaf_profile(pfvf, &hw->matchall_ipolicer);
+
+ mutex_unlock(&pfvf->mbox.lock);
+
+ return ret;
+}
+
+#define POLICER_TIMESTAMP 1 /* 1 second */
+#define MAX_RATE_EXP 22 /* Valid rate exponent range: 0 - 22 */
+
+static void cn10k_get_ingress_burst_cfg(u32 burst, u32 *burst_exp,
+ u32 *burst_mantissa)
+{
+ int tmp;
+
+ /* Burst is calculated as
+ * (1+[BURST_MANTISSA]/256)*2^[BURST_EXPONENT]
+ * This is the upper limit on number tokens (bytes) that
+ * can be accumulated in the bucket.
+ */
+ *burst_exp = ilog2(burst);
+ if (burst < 256) {
+ /* No float: can't express mantissa in this case */
+ *burst_mantissa = 0;
+ return;
+ }
+
+ if (*burst_exp > MAX_RATE_EXP)
+ *burst_exp = MAX_RATE_EXP;
+
+ /* Calculate mantissa
+ * Find remaining bytes 'burst - 2^burst_exp'
+ * mantissa = (remaining bytes) / 2^ (burst_exp - 8)
+ */
+ tmp = burst - rounddown_pow_of_two(burst);
+ *burst_mantissa = tmp / (1UL << (*burst_exp - 8));
+}
+
+static void cn10k_get_ingress_rate_cfg(u64 rate, u32 *rate_exp,
+ u32 *rate_mantissa, u32 *rdiv)
+{
+ u32 div = 0;
+ u32 exp = 0;
+ u64 tmp;
+
+ /* Figure out mantissa, exponent and divider from given max pkt rate
+ *
+ * To achieve desired rate HW adds
+ * (1+[RATE_MANTISSA]/256)*2^[RATE_EXPONENT] tokens (bytes) at every
+ * policer timeunit * 2^rdiv ie 2 * 2^rdiv usecs, to the token bucket.
+ * Here policer timeunit is 2 usecs and rate is in bits per sec.
+ * Since floating point cannot be used below algorithm uses 1000000
+ * scale factor to support rates upto 100Gbps.
+ */
+ tmp = rate * 32 * 2;
+ if (tmp < 256000000) {
+ while (tmp < 256000000) {
+ tmp = tmp * 2;
+ div++;
+ }
+ } else {
+ for (exp = 0; tmp >= 512000000 && exp <= MAX_RATE_EXP; exp++)
+ tmp = tmp / 2;
+
+ if (exp > MAX_RATE_EXP)
+ exp = MAX_RATE_EXP;
+ }
+
+ *rate_mantissa = (tmp - 256000000) / 1000000;
+ *rate_exp = exp;
+ *rdiv = div;
+}
+
+int cn10k_map_unmap_rq_policer(struct otx2_nic *pfvf, int rq_idx,
+ u16 policer, bool map)
+{
+ struct nix_cn10k_aq_enq_req *aq;
+
+ aq = otx2_mbox_alloc_msg_nix_cn10k_aq_enq(&pfvf->mbox);
+ if (!aq)
+ return -ENOMEM;
+
+ /* Enable policing and set the bandwidth profile (policer) index */
+ if (map)
+ aq->rq.policer_ena = 1;
+ else
+ aq->rq.policer_ena = 0;
+ aq->rq_mask.policer_ena = 1;
+
+ aq->rq.band_prof_id = policer;
+ aq->rq_mask.band_prof_id = GENMASK(9, 0);
+
+ /* Fill AQ info */
+ aq->qidx = rq_idx;
+ aq->ctype = NIX_AQ_CTYPE_RQ;
+ aq->op = NIX_AQ_INSTOP_WRITE;
+
+ return otx2_sync_mbox_msg(&pfvf->mbox);
+}
+
+int cn10k_free_leaf_profile(struct otx2_nic *pfvf, u16 leaf)
+{
+ struct nix_bandprof_free_req *req;
+
+ req = otx2_mbox_alloc_msg_nix_bandprof_free(&pfvf->mbox);
+ if (!req)
+ return -ENOMEM;
+
+ req->prof_count[BAND_PROF_LEAF_LAYER] = 1;
+ req->prof_idx[BAND_PROF_LEAF_LAYER][0] = leaf;
+
+ return otx2_sync_mbox_msg(&pfvf->mbox);
+}
+
+int cn10k_free_matchall_ipolicer(struct otx2_nic *pfvf)
+{
+ struct otx2_hw *hw = &pfvf->hw;
+ int qidx, rc;
+
+ mutex_lock(&pfvf->mbox.lock);
+
+ /* Remove RQ's policer mapping */
+ for (qidx = 0; qidx < hw->rx_queues; qidx++)
+ cn10k_map_unmap_rq_policer(pfvf, qidx,
+ hw->matchall_ipolicer, false);
+
+ rc = cn10k_free_leaf_profile(pfvf, hw->matchall_ipolicer);
+
+ mutex_unlock(&pfvf->mbox.lock);
+ return rc;
+}
+
+int cn10k_set_ipolicer_rate(struct otx2_nic *pfvf, u16 profile,
+ u32 burst, u64 rate, bool pps)
+{
+ struct nix_cn10k_aq_enq_req *aq;
+ u32 burst_exp, burst_mantissa;
+ u32 rate_exp, rate_mantissa;
+ u32 rdiv;
+
+ /* Get exponent and mantissa values for the desired rate */
+ cn10k_get_ingress_burst_cfg(burst, &burst_exp, &burst_mantissa);
+ cn10k_get_ingress_rate_cfg(rate, &rate_exp, &rate_mantissa, &rdiv);
+
+ /* Init bandwidth profile */
+ aq = otx2_mbox_alloc_msg_nix_cn10k_aq_enq(&pfvf->mbox);
+ if (!aq)
+ return -ENOMEM;
+
+ /* Set initial color mode to blind */
+ aq->prof.icolor = 0x03;
+ aq->prof_mask.icolor = 0x03;
+
+ /* Set rate and burst values */
+ aq->prof.cir_exponent = rate_exp;
+ aq->prof_mask.cir_exponent = 0x1F;
+
+ aq->prof.cir_mantissa = rate_mantissa;
+ aq->prof_mask.cir_mantissa = 0xFF;
+
+ aq->prof.cbs_exponent = burst_exp;
+ aq->prof_mask.cbs_exponent = 0x1F;
+
+ aq->prof.cbs_mantissa = burst_mantissa;
+ aq->prof_mask.cbs_mantissa = 0xFF;
+
+ aq->prof.rdiv = rdiv;
+ aq->prof_mask.rdiv = 0xF;
+
+ if (pps) {
+ /* The amount of decremented tokens is calculated according to
+ * the following equation:
+ * max([ LMODE ? 0 : (packet_length - LXPTR)] +
+ * ([ADJUST_MANTISSA]/256 - 1) * 2^[ADJUST_EXPONENT],
+ * 1/256)
+ * if LMODE is 1 then rate limiting will be based on
+ * PPS otherwise bps.
+ * The aim of the ADJUST value is to specify a token cost per
+ * packet in contrary to the packet length that specifies a
+ * cost per byte. To rate limit based on PPS adjust mantissa
+ * is set as 384 and exponent as 1 so that number of tokens
+ * decremented becomes 1 i.e, 1 token per packeet.
+ */
+ aq->prof.adjust_exponent = 1;
+ aq->prof_mask.adjust_exponent = 0x1F;
+
+ aq->prof.adjust_mantissa = 384;
+ aq->prof_mask.adjust_mantissa = 0x1FF;
+
+ aq->prof.lmode = 0x1;
+ aq->prof_mask.lmode = 0x1;
+ }
+
+ /* Two rate three color marker
+ * With PEIR/EIR set to zero, color will be either green or red
+ */
+ aq->prof.meter_algo = 2;
+ aq->prof_mask.meter_algo = 0x3;
+
+ aq->prof.rc_action = NIX_RX_BAND_PROF_ACTIONRESULT_DROP;
+ aq->prof_mask.rc_action = 0x3;
+
+ aq->prof.yc_action = NIX_RX_BAND_PROF_ACTIONRESULT_PASS;
+ aq->prof_mask.yc_action = 0x3;
+
+ aq->prof.gc_action = NIX_RX_BAND_PROF_ACTIONRESULT_PASS;
+ aq->prof_mask.gc_action = 0x3;
+
+ /* Setting exponent value as 24 and mantissa as 0 configures
+ * the bucket with zero values making bucket unused. Peak
+ * information rate and Excess information rate buckets are
+ * unused here.
+ */
+ aq->prof.peir_exponent = 24;
+ aq->prof_mask.peir_exponent = 0x1F;
+
+ aq->prof.peir_mantissa = 0;
+ aq->prof_mask.peir_mantissa = 0xFF;
+
+ aq->prof.pebs_exponent = 24;
+ aq->prof_mask.pebs_exponent = 0x1F;
+
+ aq->prof.pebs_mantissa = 0;
+ aq->prof_mask.pebs_mantissa = 0xFF;
+
+ /* Fill AQ info */
+ aq->qidx = profile;
+ aq->ctype = NIX_AQ_CTYPE_BANDPROF;
+ aq->op = NIX_AQ_INSTOP_WRITE;
+
+ return otx2_sync_mbox_msg(&pfvf->mbox);
+}
+
+int cn10k_set_matchall_ipolicer_rate(struct otx2_nic *pfvf,
+ u32 burst, u64 rate)
+{
+ struct otx2_hw *hw = &pfvf->hw;
+ int qidx, rc;
+
+ mutex_lock(&pfvf->mbox.lock);
+
+ rc = cn10k_set_ipolicer_rate(pfvf, hw->matchall_ipolicer, burst,
+ rate, false);
+ if (rc)
+ goto out;
+
+ for (qidx = 0; qidx < hw->rx_queues; qidx++) {
+ rc = cn10k_map_unmap_rq_policer(pfvf, qidx,
+ hw->matchall_ipolicer, true);
+ if (rc)
+ break;
+ }
+
+out:
+ mutex_unlock(&pfvf->mbox.lock);
+ return rc;
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h
index e0bc595cbb78..1a1ae334477d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h
@@ -12,6 +12,16 @@
void cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq);
void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx);
int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura);
-int cn10k_pf_lmtst_init(struct otx2_nic *pf);
-int cn10k_vf_lmtst_init(struct otx2_nic *vf);
+int cn10k_lmtst_init(struct otx2_nic *pfvf);
+int cn10k_free_all_ipolicers(struct otx2_nic *pfvf);
+int cn10k_alloc_matchall_ipolicer(struct otx2_nic *pfvf);
+int cn10k_free_matchall_ipolicer(struct otx2_nic *pfvf);
+int cn10k_set_matchall_ipolicer_rate(struct otx2_nic *pfvf,
+ u32 burst, u64 rate);
+int cn10k_map_unmap_rq_policer(struct otx2_nic *pfvf, int rq_idx,
+ u16 policer, bool map);
+int cn10k_alloc_leaf_profile(struct otx2_nic *pfvf, u16 *leaf);
+int cn10k_set_ipolicer_rate(struct otx2_nic *pfvf, u16 profile,
+ u32 burst, u64 rate, bool pps);
+int cn10k_free_leaf_profile(struct otx2_nic *pfvf, u16 leaf);
#endif /* CN10K_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
index cf7875d51d87..7cccd802c4ed 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
@@ -210,6 +210,9 @@ int otx2_set_mac_address(struct net_device *netdev, void *p)
/* update dmac field in vlan offload rule */
if (pfvf->flags & OTX2_FLAG_RX_VLAN_SUPPORT)
otx2_install_rxvlan_offload_flow(pfvf);
+ /* update dmac address in ntuple and DMAC filter list */
+ if (pfvf->flags & OTX2_FLAG_DMACFLTR_SUPPORT)
+ otx2_dmacflt_update_pfmac_flow(pfvf);
} else {
return -EPERM;
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
index 45730d0d92f2..8fd58cd07f50 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
@@ -180,6 +180,7 @@ struct otx2_hw {
/* NIX */
u16 txschq_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC];
+ u16 matchall_ipolicer;
/* HW settings, coalescing etc */
u16 rx_chan_base;
@@ -217,12 +218,17 @@ struct otx2_hw {
unsigned long cap_flag;
#define LMT_LINE_SIZE 128
-#define NIX_LMTID_BASE 72 /* RX + TX + XDP */
- void __iomem *lmt_base;
+#define LMT_BURST_SIZE 32 /* 32 LMTST lines for burst SQE flush */
+ u64 *lmt_base;
u64 *npa_lmt_base;
u64 *nix_lmt_base;
};
+enum vfperm {
+ OTX2_RESET_VF_PERM,
+ OTX2_TRUSTED_VF,
+};
+
struct otx2_vf_config {
struct otx2_nic *pf;
struct delayed_work link_event_work;
@@ -230,6 +236,7 @@ struct otx2_vf_config {
u8 mac[ETH_ALEN];
u16 vlan;
int tx_vtag_idx;
+ bool trusted;
};
struct flr_work {
@@ -261,24 +268,29 @@ struct otx2_mac_table {
struct otx2_flow_config {
u16 entry[NPC_MAX_NONCONTIG_ENTRIES];
- u32 nr_flows;
-#define OTX2_MAX_NTUPLE_FLOWS 32
-#define OTX2_MAX_UNICAST_FLOWS 8
-#define OTX2_MAX_VLAN_FLOWS 1
-#define OTX2_MAX_TC_FLOWS OTX2_MAX_NTUPLE_FLOWS
-#define OTX2_MCAM_COUNT (OTX2_MAX_NTUPLE_FLOWS + \
+ u16 *flow_ent;
+ u16 *def_ent;
+ u16 nr_flows;
+#define OTX2_DEFAULT_FLOWCOUNT 16
+#define OTX2_MAX_UNICAST_FLOWS 8
+#define OTX2_MAX_VLAN_FLOWS 1
+#define OTX2_MAX_TC_FLOWS OTX2_DEFAULT_FLOWCOUNT
+#define OTX2_MCAM_COUNT (OTX2_DEFAULT_FLOWCOUNT + \
OTX2_MAX_UNICAST_FLOWS + \
OTX2_MAX_VLAN_FLOWS)
- u32 ntuple_offset;
- u32 unicast_offset;
- u32 rx_vlan_offset;
- u32 vf_vlan_offset;
-#define OTX2_PER_VF_VLAN_FLOWS 2 /* rx+tx per VF */
+ u16 ntuple_offset;
+ u16 unicast_offset;
+ u16 rx_vlan_offset;
+ u16 vf_vlan_offset;
+#define OTX2_PER_VF_VLAN_FLOWS 2 /* Rx + Tx per VF */
#define OTX2_VF_VLAN_RX_INDEX 0
#define OTX2_VF_VLAN_TX_INDEX 1
- u32 tc_flower_offset;
- u32 ntuple_max_flows;
- u32 tc_max_flows;
+ u16 tc_flower_offset;
+ u16 ntuple_max_flows;
+ u16 tc_max_flows;
+ u8 dmacflt_max_flows;
+ u8 *bmap_to_dmacindex;
+ unsigned long dmacflt_bmap;
struct list_head flow_list;
};
@@ -319,6 +331,8 @@ struct otx2_nic {
#define OTX2_FLAG_TX_PAUSE_ENABLED BIT_ULL(10)
#define OTX2_FLAG_TC_FLOWER_SUPPORT BIT_ULL(11)
#define OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED BIT_ULL(12)
+#define OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED BIT_ULL(13)
+#define OTX2_FLAG_DMACFLTR_SUPPORT BIT_ULL(14)
u64 flags;
struct otx2_qset qset;
@@ -353,8 +367,9 @@ struct otx2_nic {
/* Block address of NIX either BLKADDR_NIX0 or BLKADDR_NIX1 */
int nix_blkaddr;
/* LMTST Lines info */
+ struct qmem *dync_lmt;
u16 tot_lmt_lines;
- u16 nix_lmt_lines;
+ u16 npa_lmt_lines;
u32 nix_lmt_size;
struct otx2_ptp *ptp;
@@ -362,6 +377,7 @@ struct otx2_nic {
struct otx2_flow_config *flow_cfg;
struct otx2_tc_info tc_info;
+ unsigned long rq_bmap;
};
static inline bool is_otx2_lbkvf(struct pci_dev *pdev)
@@ -822,4 +838,11 @@ int otx2_init_tc(struct otx2_nic *nic);
void otx2_shutdown_tc(struct otx2_nic *nic);
int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type,
void *type_data);
+/* CGX/RPM DMAC filters support */
+int otx2_dmacflt_get_max_cnt(struct otx2_nic *pf);
+int otx2_dmacflt_add(struct otx2_nic *pf, const u8 *mac, u8 bit_pos);
+int otx2_dmacflt_remove(struct otx2_nic *pf, const u8 *mac, u8 bit_pos);
+int otx2_dmacflt_update(struct otx2_nic *pf, u8 *mac, u8 bit_pos);
+void otx2_dmacflt_reinstall_flows(struct otx2_nic *pf);
+void otx2_dmacflt_update_pfmac_flow(struct otx2_nic *pfvf);
#endif /* OTX2_COMMON_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dmac_flt.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dmac_flt.c
new file mode 100644
index 000000000000..383a6b5cb698
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dmac_flt.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell OcteonTx2 RVU Physcial Function ethernet driver
+ *
+ * Copyright (C) 2021 Marvell.
+ */
+
+#include "otx2_common.h"
+
+static int otx2_dmacflt_do_add(struct otx2_nic *pf, const u8 *mac,
+ u8 *dmac_index)
+{
+ struct cgx_mac_addr_add_req *req;
+ struct cgx_mac_addr_add_rsp *rsp;
+ int err;
+
+ mutex_lock(&pf->mbox.lock);
+
+ req = otx2_mbox_alloc_msg_cgx_mac_addr_add(&pf->mbox);
+ if (!req) {
+ mutex_unlock(&pf->mbox.lock);
+ return -ENOMEM;
+ }
+
+ ether_addr_copy(req->mac_addr, mac);
+ err = otx2_sync_mbox_msg(&pf->mbox);
+
+ if (!err) {
+ rsp = (struct cgx_mac_addr_add_rsp *)
+ otx2_mbox_get_rsp(&pf->mbox.mbox, 0, &req->hdr);
+ *dmac_index = rsp->index;
+ }
+
+ mutex_unlock(&pf->mbox.lock);
+ return err;
+}
+
+static int otx2_dmacflt_add_pfmac(struct otx2_nic *pf)
+{
+ struct cgx_mac_addr_set_or_get *req;
+ int err;
+
+ mutex_lock(&pf->mbox.lock);
+
+ req = otx2_mbox_alloc_msg_cgx_mac_addr_set(&pf->mbox);
+ if (!req) {
+ mutex_unlock(&pf->mbox.lock);
+ return -ENOMEM;
+ }
+
+ ether_addr_copy(req->mac_addr, pf->netdev->dev_addr);
+ err = otx2_sync_mbox_msg(&pf->mbox);
+
+ mutex_unlock(&pf->mbox.lock);
+ return err;
+}
+
+int otx2_dmacflt_add(struct otx2_nic *pf, const u8 *mac, u8 bit_pos)
+{
+ u8 *dmacindex;
+
+ /* Store dmacindex returned by CGX/RPM driver which will
+ * be used for macaddr update/remove
+ */
+ dmacindex = &pf->flow_cfg->bmap_to_dmacindex[bit_pos];
+
+ if (ether_addr_equal(mac, pf->netdev->dev_addr))
+ return otx2_dmacflt_add_pfmac(pf);
+ else
+ return otx2_dmacflt_do_add(pf, mac, dmacindex);
+}
+
+static int otx2_dmacflt_do_remove(struct otx2_nic *pfvf, const u8 *mac,
+ u8 dmac_index)
+{
+ struct cgx_mac_addr_del_req *req;
+ int err;
+
+ mutex_lock(&pfvf->mbox.lock);
+ req = otx2_mbox_alloc_msg_cgx_mac_addr_del(&pfvf->mbox);
+ if (!req) {
+ mutex_unlock(&pfvf->mbox.lock);
+ return -ENOMEM;
+ }
+
+ req->index = dmac_index;
+
+ err = otx2_sync_mbox_msg(&pfvf->mbox);
+ mutex_unlock(&pfvf->mbox.lock);
+
+ return err;
+}
+
+static int otx2_dmacflt_remove_pfmac(struct otx2_nic *pf)
+{
+ struct msg_req *req;
+ int err;
+
+ mutex_lock(&pf->mbox.lock);
+ req = otx2_mbox_alloc_msg_cgx_mac_addr_reset(&pf->mbox);
+ if (!req) {
+ mutex_unlock(&pf->mbox.lock);
+ return -ENOMEM;
+ }
+
+ err = otx2_sync_mbox_msg(&pf->mbox);
+
+ mutex_unlock(&pf->mbox.lock);
+ return err;
+}
+
+int otx2_dmacflt_remove(struct otx2_nic *pf, const u8 *mac,
+ u8 bit_pos)
+{
+ u8 dmacindex = pf->flow_cfg->bmap_to_dmacindex[bit_pos];
+
+ if (ether_addr_equal(mac, pf->netdev->dev_addr))
+ return otx2_dmacflt_remove_pfmac(pf);
+ else
+ return otx2_dmacflt_do_remove(pf, mac, dmacindex);
+}
+
+/* CGX/RPM blocks support max unicast entries of 32.
+ * on typical configuration MAC block associated
+ * with 4 lmacs, each lmac will have 8 dmac entries
+ */
+int otx2_dmacflt_get_max_cnt(struct otx2_nic *pf)
+{
+ struct cgx_max_dmac_entries_get_rsp *rsp;
+ struct msg_req *msg;
+ int err;
+
+ mutex_lock(&pf->mbox.lock);
+ msg = otx2_mbox_alloc_msg_cgx_mac_max_entries_get(&pf->mbox);
+
+ if (!msg) {
+ mutex_unlock(&pf->mbox.lock);
+ return -ENOMEM;
+ }
+
+ err = otx2_sync_mbox_msg(&pf->mbox);
+ if (err)
+ goto out;
+
+ rsp = (struct cgx_max_dmac_entries_get_rsp *)
+ otx2_mbox_get_rsp(&pf->mbox.mbox, 0, &msg->hdr);
+ pf->flow_cfg->dmacflt_max_flows = rsp->max_dmac_filters;
+
+out:
+ mutex_unlock(&pf->mbox.lock);
+ return err;
+}
+
+int otx2_dmacflt_update(struct otx2_nic *pf, u8 *mac, u8 bit_pos)
+{
+ struct cgx_mac_addr_update_req *req;
+ int rc;
+
+ mutex_lock(&pf->mbox.lock);
+
+ req = otx2_mbox_alloc_msg_cgx_mac_addr_update(&pf->mbox);
+
+ if (!req) {
+ mutex_unlock(&pf->mbox.lock);
+ return -ENOMEM;
+ }
+
+ ether_addr_copy(req->mac_addr, mac);
+ req->index = pf->flow_cfg->bmap_to_dmacindex[bit_pos];
+ rc = otx2_sync_mbox_msg(&pf->mbox);
+
+ mutex_unlock(&pf->mbox.lock);
+ return rc;
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
index 9d9a2e438acf..8df748e0677b 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
@@ -286,6 +286,12 @@ static int otx2_set_channels(struct net_device *dev,
if (!channel->rx_count || !channel->tx_count)
return -EINVAL;
+ if (bitmap_weight(&pfvf->rq_bmap, pfvf->hw.rx_queues) > 1) {
+ netdev_err(dev,
+ "Receive queues are in use by TC police action\n");
+ return -EINVAL;
+ }
+
if (if_up)
dev->netdev_ops->ndo_stop(dev);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
index 0b4fa92ba821..4d9de525802d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
@@ -18,15 +18,133 @@ struct otx2_flow {
bool is_vf;
u8 rss_ctx_id;
int vf;
+ bool dmac_filter;
};
+enum dmac_req {
+ DMAC_ADDR_UPDATE,
+ DMAC_ADDR_DEL
+};
+
+static void otx2_clear_ntuple_flow_info(struct otx2_nic *pfvf, struct otx2_flow_config *flow_cfg)
+{
+ devm_kfree(pfvf->dev, flow_cfg->flow_ent);
+ flow_cfg->flow_ent = NULL;
+ flow_cfg->ntuple_max_flows = 0;
+ flow_cfg->tc_max_flows = 0;
+}
+
+static int otx2_free_ntuple_mcam_entries(struct otx2_nic *pfvf)
+{
+ struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
+ struct npc_mcam_free_entry_req *req;
+ int ent, err;
+
+ if (!flow_cfg->ntuple_max_flows)
+ return 0;
+
+ mutex_lock(&pfvf->mbox.lock);
+ for (ent = 0; ent < flow_cfg->ntuple_max_flows; ent++) {
+ req = otx2_mbox_alloc_msg_npc_mcam_free_entry(&pfvf->mbox);
+ if (!req)
+ break;
+
+ req->entry = flow_cfg->flow_ent[ent];
+
+ /* Send message to AF to free MCAM entries */
+ err = otx2_sync_mbox_msg(&pfvf->mbox);
+ if (err)
+ break;
+ }
+ mutex_unlock(&pfvf->mbox.lock);
+ otx2_clear_ntuple_flow_info(pfvf, flow_cfg);
+ return 0;
+}
+
+static int otx2_alloc_ntuple_mcam_entries(struct otx2_nic *pfvf, u16 count)
+{
+ struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
+ struct npc_mcam_alloc_entry_req *req;
+ struct npc_mcam_alloc_entry_rsp *rsp;
+ int ent, allocated = 0;
+
+ /* Free current ones and allocate new ones with requested count */
+ otx2_free_ntuple_mcam_entries(pfvf);
+
+ if (!count)
+ return 0;
+
+ flow_cfg->flow_ent = devm_kmalloc_array(pfvf->dev, count,
+ sizeof(u16), GFP_KERNEL);
+ if (!flow_cfg->flow_ent)
+ return -ENOMEM;
+
+ mutex_lock(&pfvf->mbox.lock);
+
+ /* In a single request a max of NPC_MAX_NONCONTIG_ENTRIES MCAM entries
+ * can only be allocated.
+ */
+ while (allocated < count) {
+ req = otx2_mbox_alloc_msg_npc_mcam_alloc_entry(&pfvf->mbox);
+ if (!req)
+ goto exit;
+
+ req->contig = false;
+ req->count = (count - allocated) > NPC_MAX_NONCONTIG_ENTRIES ?
+ NPC_MAX_NONCONTIG_ENTRIES : count - allocated;
+ req->priority = NPC_MCAM_HIGHER_PRIO;
+ req->ref_entry = flow_cfg->def_ent[0];
+
+ /* Send message to AF */
+ if (otx2_sync_mbox_msg(&pfvf->mbox))
+ goto exit;
+
+ rsp = (struct npc_mcam_alloc_entry_rsp *)otx2_mbox_get_rsp
+ (&pfvf->mbox.mbox, 0, &req->hdr);
+
+ for (ent = 0; ent < rsp->count; ent++)
+ flow_cfg->flow_ent[ent + allocated] = rsp->entry_list[ent];
+
+ allocated += rsp->count;
+
+ /* If this request is not fulfilled, no need to send
+ * further requests.
+ */
+ if (rsp->count != req->count)
+ break;
+ }
+
+exit:
+ mutex_unlock(&pfvf->mbox.lock);
+
+ flow_cfg->ntuple_offset = 0;
+ flow_cfg->ntuple_max_flows = allocated;
+ flow_cfg->tc_max_flows = allocated;
+
+ if (allocated != count)
+ netdev_info(pfvf->netdev,
+ "Unable to allocate %d MCAM entries for ntuple, got %d\n",
+ count, allocated);
+
+ return allocated;
+}
+
int otx2_alloc_mcam_entries(struct otx2_nic *pfvf)
{
struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
struct npc_mcam_alloc_entry_req *req;
struct npc_mcam_alloc_entry_rsp *rsp;
int vf_vlan_max_flows;
- int i;
+ int ent, count;
+
+ vf_vlan_max_flows = pfvf->total_vfs * OTX2_PER_VF_VLAN_FLOWS;
+ count = OTX2_MAX_UNICAST_FLOWS +
+ OTX2_MAX_VLAN_FLOWS + vf_vlan_max_flows;
+
+ flow_cfg->def_ent = devm_kmalloc_array(pfvf->dev, count,
+ sizeof(u16), GFP_KERNEL);
+ if (!flow_cfg->def_ent)
+ return -ENOMEM;
mutex_lock(&pfvf->mbox.lock);
@@ -36,9 +154,8 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf)
return -ENOMEM;
}
- vf_vlan_max_flows = pfvf->total_vfs * OTX2_PER_VF_VLAN_FLOWS;
req->contig = false;
- req->count = OTX2_MCAM_COUNT + vf_vlan_max_flows;
+ req->count = count;
/* Send message to AF */
if (otx2_sync_mbox_msg(&pfvf->mbox)) {
@@ -51,37 +168,36 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf)
if (rsp->count != req->count) {
netdev_info(pfvf->netdev,
- "Unable to allocate %d MCAM entries, got %d\n",
- req->count, rsp->count);
- /* support only ntuples here */
- flow_cfg->ntuple_max_flows = rsp->count;
- flow_cfg->ntuple_offset = 0;
- pfvf->flags |= OTX2_FLAG_NTUPLE_SUPPORT;
- flow_cfg->tc_max_flows = flow_cfg->ntuple_max_flows;
- pfvf->flags |= OTX2_FLAG_TC_FLOWER_SUPPORT;
- } else {
- flow_cfg->vf_vlan_offset = 0;
- flow_cfg->ntuple_offset = flow_cfg->vf_vlan_offset +
- vf_vlan_max_flows;
- flow_cfg->tc_flower_offset = flow_cfg->ntuple_offset;
- flow_cfg->unicast_offset = flow_cfg->ntuple_offset +
- OTX2_MAX_NTUPLE_FLOWS;
- flow_cfg->rx_vlan_offset = flow_cfg->unicast_offset +
- OTX2_MAX_UNICAST_FLOWS;
- pfvf->flags |= OTX2_FLAG_NTUPLE_SUPPORT;
- pfvf->flags |= OTX2_FLAG_UCAST_FLTR_SUPPORT;
- pfvf->flags |= OTX2_FLAG_RX_VLAN_SUPPORT;
- pfvf->flags |= OTX2_FLAG_VF_VLAN_SUPPORT;
- pfvf->flags |= OTX2_FLAG_TC_FLOWER_SUPPORT;
- }
-
- for (i = 0; i < rsp->count; i++)
- flow_cfg->entry[i] = rsp->entry_list[i];
+ "Unable to allocate MCAM entries for ucast, vlan and vf_vlan\n");
+ mutex_unlock(&pfvf->mbox.lock);
+ devm_kfree(pfvf->dev, flow_cfg->def_ent);
+ return 0;
+ }
- pfvf->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;
+ for (ent = 0; ent < rsp->count; ent++)
+ flow_cfg->def_ent[ent] = rsp->entry_list[ent];
+
+ flow_cfg->vf_vlan_offset = 0;
+ flow_cfg->unicast_offset = vf_vlan_max_flows;
+ flow_cfg->rx_vlan_offset = flow_cfg->unicast_offset +
+ OTX2_MAX_UNICAST_FLOWS;
+ pfvf->flags |= OTX2_FLAG_UCAST_FLTR_SUPPORT;
+ pfvf->flags |= OTX2_FLAG_RX_VLAN_SUPPORT;
+ pfvf->flags |= OTX2_FLAG_VF_VLAN_SUPPORT;
+ pfvf->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;
mutex_unlock(&pfvf->mbox.lock);
+ /* Allocate entries for Ntuple filters */
+ count = otx2_alloc_ntuple_mcam_entries(pfvf, OTX2_DEFAULT_FLOWCOUNT);
+ if (count <= 0) {
+ otx2_clear_ntuple_flow_info(pfvf, flow_cfg);
+ return 0;
+ }
+
+ pfvf->flags |= OTX2_FLAG_NTUPLE_SUPPORT;
+ pfvf->flags |= OTX2_FLAG_TC_FLOWER_SUPPORT;
+
return 0;
}
@@ -96,18 +212,35 @@ int otx2_mcam_flow_init(struct otx2_nic *pf)
INIT_LIST_HEAD(&pf->flow_cfg->flow_list);
- pf->flow_cfg->ntuple_max_flows = OTX2_MAX_NTUPLE_FLOWS;
- pf->flow_cfg->tc_max_flows = pf->flow_cfg->ntuple_max_flows;
-
err = otx2_alloc_mcam_entries(pf);
if (err)
return err;
+ /* Check if MCAM entries are allocate or not */
+ if (!(pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT))
+ return 0;
+
pf->mac_table = devm_kzalloc(pf->dev, sizeof(struct otx2_mac_table)
* OTX2_MAX_UNICAST_FLOWS, GFP_KERNEL);
if (!pf->mac_table)
return -ENOMEM;
+ otx2_dmacflt_get_max_cnt(pf);
+
+ /* DMAC filters are not allocated */
+ if (!pf->flow_cfg->dmacflt_max_flows)
+ return 0;
+
+ pf->flow_cfg->bmap_to_dmacindex =
+ devm_kzalloc(pf->dev, sizeof(u8) *
+ pf->flow_cfg->dmacflt_max_flows,
+ GFP_KERNEL);
+
+ if (!pf->flow_cfg->bmap_to_dmacindex)
+ return -ENOMEM;
+
+ pf->flags |= OTX2_FLAG_DMACFLTR_SUPPORT;
+
return 0;
}
@@ -146,7 +279,7 @@ static int otx2_do_add_macfilter(struct otx2_nic *pf, const u8 *mac)
ether_addr_copy(pf->mac_table[i].addr, mac);
pf->mac_table[i].inuse = true;
pf->mac_table[i].mcam_entry =
- flow_cfg->entry[i + flow_cfg->unicast_offset];
+ flow_cfg->def_ent[i + flow_cfg->unicast_offset];
req->entry = pf->mac_table[i].mcam_entry;
break;
}
@@ -169,6 +302,12 @@ int otx2_add_macfilter(struct net_device *netdev, const u8 *mac)
{
struct otx2_nic *pf = netdev_priv(netdev);
+ if (bitmap_weight(&pf->flow_cfg->dmacflt_bmap,
+ pf->flow_cfg->dmacflt_max_flows))
+ netdev_warn(netdev,
+ "Add %pM to CGX/RPM DMAC filters list as well\n",
+ mac);
+
return otx2_do_add_macfilter(pf, mac);
}
@@ -240,12 +379,22 @@ static void otx2_add_flow_to_list(struct otx2_nic *pfvf, struct otx2_flow *flow)
list_add(&flow->list, head);
}
+static int otx2_get_maxflows(struct otx2_flow_config *flow_cfg)
+{
+ if (flow_cfg->nr_flows == flow_cfg->ntuple_max_flows ||
+ bitmap_weight(&flow_cfg->dmacflt_bmap,
+ flow_cfg->dmacflt_max_flows))
+ return flow_cfg->ntuple_max_flows + flow_cfg->dmacflt_max_flows;
+ else
+ return flow_cfg->ntuple_max_flows;
+}
+
int otx2_get_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc,
u32 location)
{
struct otx2_flow *iter;
- if (location >= pfvf->flow_cfg->ntuple_max_flows)
+ if (location >= otx2_get_maxflows(pfvf->flow_cfg))
return -EINVAL;
list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
@@ -267,7 +416,7 @@ int otx2_get_all_flows(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc,
int idx = 0;
int err = 0;
- nfc->data = pfvf->flow_cfg->ntuple_max_flows;
+ nfc->data = otx2_get_maxflows(pfvf->flow_cfg);
while ((!err || err == -ENOENT) && idx < rule_cnt) {
err = otx2_get_flow(pfvf, nfc, location);
if (!err)
@@ -551,6 +700,7 @@ static int otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp,
req->features |= BIT_ULL(NPC_IPPROTO_AH);
else
req->features |= BIT_ULL(NPC_IPPROTO_ESP);
+ break;
default:
break;
}
@@ -648,6 +798,32 @@ int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
return 0;
}
+static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf,
+ struct ethtool_rx_flow_spec *fsp)
+{
+ struct ethhdr *eth_mask = &fsp->m_u.ether_spec;
+ struct ethhdr *eth_hdr = &fsp->h_u.ether_spec;
+ u64 ring_cookie = fsp->ring_cookie;
+ u32 flow_type;
+
+ if (!(pfvf->flags & OTX2_FLAG_DMACFLTR_SUPPORT))
+ return false;
+
+ flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
+
+ /* CGX/RPM block dmac filtering configured for white listing
+ * check for action other than DROP
+ */
+ if (flow_type == ETHER_FLOW && ring_cookie != RX_CLS_FLOW_DISC &&
+ !ethtool_get_flow_spec_ring_vf(ring_cookie)) {
+ if (is_zero_ether_addr(eth_mask->h_dest) &&
+ is_valid_ether_addr(eth_hdr->h_dest))
+ return true;
+ }
+
+ return false;
+}
+
static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
{
u64 ring_cookie = flow->flow_spec.ring_cookie;
@@ -706,14 +882,46 @@ static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
return err;
}
+static int otx2_add_flow_with_pfmac(struct otx2_nic *pfvf,
+ struct otx2_flow *flow)
+{
+ struct otx2_flow *pf_mac;
+ struct ethhdr *eth_hdr;
+
+ pf_mac = kzalloc(sizeof(*pf_mac), GFP_KERNEL);
+ if (!pf_mac)
+ return -ENOMEM;
+
+ pf_mac->entry = 0;
+ pf_mac->dmac_filter = true;
+ pf_mac->location = pfvf->flow_cfg->ntuple_max_flows;
+ memcpy(&pf_mac->flow_spec, &flow->flow_spec,
+ sizeof(struct ethtool_rx_flow_spec));
+ pf_mac->flow_spec.location = pf_mac->location;
+
+ /* Copy PF mac address */
+ eth_hdr = &pf_mac->flow_spec.h_u.ether_spec;
+ ether_addr_copy(eth_hdr->h_dest, pfvf->netdev->dev_addr);
+
+ /* Install DMAC filter with PF mac address */
+ otx2_dmacflt_add(pfvf, eth_hdr->h_dest, 0);
+
+ otx2_add_flow_to_list(pfvf, pf_mac);
+ pfvf->flow_cfg->nr_flows++;
+ set_bit(0, &pfvf->flow_cfg->dmacflt_bmap);
+
+ return 0;
+}
+
int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc)
{
struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
struct ethtool_rx_flow_spec *fsp = &nfc->fs;
struct otx2_flow *flow;
+ struct ethhdr *eth_hdr;
bool new = false;
+ int err = 0;
u32 ring;
- int err;
ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT))
@@ -722,17 +930,15 @@ int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc)
if (ring >= pfvf->hw.rx_queues && fsp->ring_cookie != RX_CLS_FLOW_DISC)
return -EINVAL;
- if (fsp->location >= flow_cfg->ntuple_max_flows)
+ if (fsp->location >= otx2_get_maxflows(flow_cfg))
return -EINVAL;
flow = otx2_find_flow(pfvf, fsp->location);
if (!flow) {
- flow = kzalloc(sizeof(*flow), GFP_ATOMIC);
+ flow = kzalloc(sizeof(*flow), GFP_KERNEL);
if (!flow)
return -ENOMEM;
flow->location = fsp->location;
- flow->entry = flow_cfg->entry[flow_cfg->ntuple_offset +
- flow->location];
new = true;
}
/* struct copy */
@@ -741,7 +947,54 @@ int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc)
if (fsp->flow_type & FLOW_RSS)
flow->rss_ctx_id = nfc->rss_context;
- err = otx2_add_flow_msg(pfvf, flow);
+ if (otx2_is_flow_rule_dmacfilter(pfvf, &flow->flow_spec)) {
+ eth_hdr = &flow->flow_spec.h_u.ether_spec;
+
+ /* Sync dmac filter table with updated fields */
+ if (flow->dmac_filter)
+ return otx2_dmacflt_update(pfvf, eth_hdr->h_dest,
+ flow->entry);
+
+ if (bitmap_full(&flow_cfg->dmacflt_bmap,
+ flow_cfg->dmacflt_max_flows)) {
+ netdev_warn(pfvf->netdev,
+ "Can't insert the rule %d as max allowed dmac filters are %d\n",
+ flow->location +
+ flow_cfg->dmacflt_max_flows,
+ flow_cfg->dmacflt_max_flows);
+ err = -EINVAL;
+ if (new)
+ kfree(flow);
+ return err;
+ }
+
+ /* Install PF mac address to DMAC filter list */
+ if (!test_bit(0, &flow_cfg->dmacflt_bmap))
+ otx2_add_flow_with_pfmac(pfvf, flow);
+
+ flow->dmac_filter = true;
+ flow->entry = find_first_zero_bit(&flow_cfg->dmacflt_bmap,
+ flow_cfg->dmacflt_max_flows);
+ fsp->location = flow_cfg->ntuple_max_flows + flow->entry;
+ flow->flow_spec.location = fsp->location;
+ flow->location = fsp->location;
+
+ set_bit(flow->entry, &flow_cfg->dmacflt_bmap);
+ otx2_dmacflt_add(pfvf, eth_hdr->h_dest, flow->entry);
+
+ } else {
+ if (flow->location >= pfvf->flow_cfg->ntuple_max_flows) {
+ netdev_warn(pfvf->netdev,
+ "Can't insert non dmac ntuple rule at %d, allowed range %d-0\n",
+ flow->location,
+ flow_cfg->ntuple_max_flows - 1);
+ err = -EINVAL;
+ } else {
+ flow->entry = flow_cfg->flow_ent[flow->location];
+ err = otx2_add_flow_msg(pfvf, flow);
+ }
+ }
+
if (err) {
if (new)
kfree(flow);
@@ -779,20 +1032,70 @@ static int otx2_remove_flow_msg(struct otx2_nic *pfvf, u16 entry, bool all)
return err;
}
+static void otx2_update_rem_pfmac(struct otx2_nic *pfvf, int req)
+{
+ struct otx2_flow *iter;
+ struct ethhdr *eth_hdr;
+ bool found = false;
+
+ list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
+ if (iter->dmac_filter && iter->entry == 0) {
+ eth_hdr = &iter->flow_spec.h_u.ether_spec;
+ if (req == DMAC_ADDR_DEL) {
+ otx2_dmacflt_remove(pfvf, eth_hdr->h_dest,
+ 0);
+ clear_bit(0, &pfvf->flow_cfg->dmacflt_bmap);
+ found = true;
+ } else {
+ ether_addr_copy(eth_hdr->h_dest,
+ pfvf->netdev->dev_addr);
+ otx2_dmacflt_update(pfvf, eth_hdr->h_dest, 0);
+ }
+ break;
+ }
+ }
+
+ if (found) {
+ list_del(&iter->list);
+ kfree(iter);
+ pfvf->flow_cfg->nr_flows--;
+ }
+}
+
int otx2_remove_flow(struct otx2_nic *pfvf, u32 location)
{
struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
struct otx2_flow *flow;
int err;
- if (location >= flow_cfg->ntuple_max_flows)
+ if (location >= otx2_get_maxflows(flow_cfg))
return -EINVAL;
flow = otx2_find_flow(pfvf, location);
if (!flow)
return -ENOENT;
- err = otx2_remove_flow_msg(pfvf, flow->entry, false);
+ if (flow->dmac_filter) {
+ struct ethhdr *eth_hdr = &flow->flow_spec.h_u.ether_spec;
+
+ /* user not allowed to remove dmac filter with interface mac */
+ if (ether_addr_equal(pfvf->netdev->dev_addr, eth_hdr->h_dest))
+ return -EPERM;
+
+ err = otx2_dmacflt_remove(pfvf, eth_hdr->h_dest,
+ flow->entry);
+ clear_bit(flow->entry, &flow_cfg->dmacflt_bmap);
+ /* If all dmac filters are removed delete macfilter with
+ * interface mac address and configure CGX/RPM block in
+ * promiscuous mode
+ */
+ if (bitmap_weight(&flow_cfg->dmacflt_bmap,
+ flow_cfg->dmacflt_max_flows) == 1)
+ otx2_update_rem_pfmac(pfvf, DMAC_ADDR_DEL);
+ } else {
+ err = otx2_remove_flow_msg(pfvf, flow->entry, false);
+ }
+
if (err)
return err;
@@ -836,9 +1139,8 @@ int otx2_destroy_ntuple_flows(struct otx2_nic *pfvf)
return -ENOMEM;
}
- req->start = flow_cfg->entry[flow_cfg->ntuple_offset];
- req->end = flow_cfg->entry[flow_cfg->ntuple_offset +
- flow_cfg->ntuple_max_flows - 1];
+ req->start = flow_cfg->flow_ent[0];
+ req->end = flow_cfg->flow_ent[flow_cfg->ntuple_max_flows - 1];
err = otx2_sync_mbox_msg(&pfvf->mbox);
mutex_unlock(&pfvf->mbox.lock);
@@ -905,7 +1207,7 @@ int otx2_install_rxvlan_offload_flow(struct otx2_nic *pfvf)
return -ENOMEM;
}
- req->entry = flow_cfg->entry[flow_cfg->rx_vlan_offset];
+ req->entry = flow_cfg->def_ent[flow_cfg->rx_vlan_offset];
req->intf = NIX_INTF_RX;
ether_addr_copy(req->packet.dmac, pfvf->netdev->dev_addr);
eth_broadcast_addr((u8 *)&req->mask.dmac);
@@ -934,7 +1236,7 @@ static int otx2_delete_rxvlan_offload_flow(struct otx2_nic *pfvf)
return -ENOMEM;
}
- req->entry = flow_cfg->entry[flow_cfg->rx_vlan_offset];
+ req->entry = flow_cfg->def_ent[flow_cfg->rx_vlan_offset];
/* Send message to AF */
err = otx2_sync_mbox_msg(&pfvf->mbox);
mutex_unlock(&pfvf->mbox.lock);
@@ -990,3 +1292,22 @@ int otx2_enable_rxvlan(struct otx2_nic *pf, bool enable)
mutex_unlock(&pf->mbox.lock);
return rsp_hdr->rc;
}
+
+void otx2_dmacflt_reinstall_flows(struct otx2_nic *pf)
+{
+ struct otx2_flow *iter;
+ struct ethhdr *eth_hdr;
+
+ list_for_each_entry(iter, &pf->flow_cfg->flow_list, list) {
+ if (iter->dmac_filter) {
+ eth_hdr = &iter->flow_spec.h_u.ether_spec;
+ otx2_dmacflt_add(pf, eth_hdr->h_dest,
+ iter->entry);
+ }
+ }
+}
+
+void otx2_dmacflt_update_pfmac_flow(struct otx2_nic *pfvf)
+{
+ otx2_update_rem_pfmac(pfvf, DMAC_ADDR_UPDATE);
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index 03004fdac0c6..f300b807a85b 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -39,6 +39,8 @@ MODULE_DESCRIPTION(DRV_STRING);
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(pci, otx2_pf_id_table);
+static void otx2_vf_link_event_task(struct work_struct *work);
+
enum {
TYPE_PFAF,
TYPE_PFVF,
@@ -1108,6 +1110,11 @@ static int otx2_cgx_config_loopback(struct otx2_nic *pf, bool enable)
struct msg_req *msg;
int err;
+ if (enable && bitmap_weight(&pf->flow_cfg->dmacflt_bmap,
+ pf->flow_cfg->dmacflt_max_flows))
+ netdev_warn(pf->netdev,
+ "CGX/RPM internal loopback might not work as DMAC filters are active\n");
+
mutex_lock(&pf->mbox.lock);
if (enable)
msg = otx2_mbox_alloc_msg_cgx_intlbk_enable(&pf->mbox);
@@ -1459,6 +1466,9 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
otx2_free_cq_res(pf);
+ /* Free all ingress bandwidth profiles allocated */
+ cn10k_free_all_ipolicers(pf);
+
mutex_lock(&mbox->lock);
/* Reset NIX LF */
free_req = otx2_mbox_alloc_msg_nix_lf_free(mbox);
@@ -1528,10 +1538,10 @@ int otx2_open(struct net_device *netdev)
if (test_bit(CN10K_LMTST, &pf->hw.cap_flag)) {
/* Reserve LMT lines for NPA AURA batch free */
- pf->hw.npa_lmt_base = (__force u64 *)pf->hw.lmt_base;
+ pf->hw.npa_lmt_base = pf->hw.lmt_base;
/* Reserve LMT lines for NIX TX */
- pf->hw.nix_lmt_base = (__force u64 *)((u64)pf->hw.npa_lmt_base +
- (NIX_LMTID_BASE * LMT_LINE_SIZE));
+ pf->hw.nix_lmt_base = (u64 *)((u64)pf->hw.npa_lmt_base +
+ (pf->npa_lmt_lines * LMT_LINE_SIZE));
}
err = otx2_init_hw_resources(pf);
@@ -1639,6 +1649,10 @@ int otx2_open(struct net_device *netdev)
/* Restore pause frame settings */
otx2_config_pause_frm(pf);
+ /* Install DMAC Filters */
+ if (pf->flags & OTX2_FLAG_DMACFLTR_SUPPORT)
+ otx2_dmacflt_reinstall_flows(pf);
+
err = otx2_rxtx_enable(pf, true);
if (err)
goto err_tx_stop_queues;
@@ -1820,9 +1834,11 @@ static void otx2_do_set_rx_mode(struct work_struct *work)
if (promisc)
req->mode |= NIX_RX_MODE_PROMISC;
- else if (netdev->flags & (IFF_ALLMULTI | IFF_MULTICAST))
+ if (netdev->flags & (IFF_ALLMULTI | IFF_MULTICAST))
req->mode |= NIX_RX_MODE_ALLMULTI;
+ req->mode |= NIX_RX_MODE_USE_MCE;
+
otx2_sync_mbox_msg(&pf->mbox);
mutex_unlock(&pf->mbox.lock);
}
@@ -2044,7 +2060,7 @@ static int otx2_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
if (!netif_running(netdev))
return -EAGAIN;
- if (vf >= pci_num_vf(pdev))
+ if (vf >= pf->total_vfs)
return -EINVAL;
if (!is_valid_ether_addr(mac))
@@ -2055,7 +2071,8 @@ static int otx2_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
ret = otx2_do_set_vf_mac(pf, vf, mac);
if (ret == 0)
- dev_info(&pdev->dev, "Reload VF driver to apply the changes\n");
+ dev_info(&pdev->dev,
+ "Load/Reload VF driver\n");
return ret;
}
@@ -2104,7 +2121,7 @@ static int otx2_do_set_vf_vlan(struct otx2_nic *pf, int vf, u16 vlan, u8 qos,
}
idx = ((vf * OTX2_PER_VF_VLAN_FLOWS) + OTX2_VF_VLAN_RX_INDEX);
del_req->entry =
- flow_cfg->entry[flow_cfg->vf_vlan_offset + idx];
+ flow_cfg->def_ent[flow_cfg->vf_vlan_offset + idx];
err = otx2_sync_mbox_msg(&pf->mbox);
if (err)
goto out;
@@ -2117,7 +2134,7 @@ static int otx2_do_set_vf_vlan(struct otx2_nic *pf, int vf, u16 vlan, u8 qos,
}
idx = ((vf * OTX2_PER_VF_VLAN_FLOWS) + OTX2_VF_VLAN_TX_INDEX);
del_req->entry =
- flow_cfg->entry[flow_cfg->vf_vlan_offset + idx];
+ flow_cfg->def_ent[flow_cfg->vf_vlan_offset + idx];
err = otx2_sync_mbox_msg(&pf->mbox);
goto out;
@@ -2131,7 +2148,7 @@ static int otx2_do_set_vf_vlan(struct otx2_nic *pf, int vf, u16 vlan, u8 qos,
}
idx = ((vf * OTX2_PER_VF_VLAN_FLOWS) + OTX2_VF_VLAN_RX_INDEX);
- req->entry = flow_cfg->entry[flow_cfg->vf_vlan_offset + idx];
+ req->entry = flow_cfg->def_ent[flow_cfg->vf_vlan_offset + idx];
req->packet.vlan_tci = htons(vlan);
req->mask.vlan_tci = htons(VLAN_VID_MASK);
/* af fills the destination mac addr */
@@ -2182,7 +2199,7 @@ static int otx2_do_set_vf_vlan(struct otx2_nic *pf, int vf, u16 vlan, u8 qos,
eth_zero_addr((u8 *)&req->mask.dmac);
idx = ((vf * OTX2_PER_VF_VLAN_FLOWS) + OTX2_VF_VLAN_TX_INDEX);
- req->entry = flow_cfg->entry[flow_cfg->vf_vlan_offset + idx];
+ req->entry = flow_cfg->def_ent[flow_cfg->vf_vlan_offset + idx];
req->features = BIT_ULL(NPC_DMAC);
req->channel = pf->hw.tx_chan_base;
req->intf = NIX_INTF_TX;
@@ -2241,10 +2258,63 @@ static int otx2_get_vf_config(struct net_device *netdev, int vf,
ivi->vf = vf;
ether_addr_copy(ivi->mac, config->mac);
ivi->vlan = config->vlan;
+ ivi->trusted = config->trusted;
return 0;
}
+static int otx2_set_vf_permissions(struct otx2_nic *pf, int vf,
+ int req_perm)
+{
+ struct set_vf_perm *req;
+ int rc;
+
+ mutex_lock(&pf->mbox.lock);
+ req = otx2_mbox_alloc_msg_set_vf_perm(&pf->mbox);
+ if (!req) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* Let AF reset VF permissions as sriov is disabled */
+ if (req_perm == OTX2_RESET_VF_PERM) {
+ req->flags |= RESET_VF_PERM;
+ } else if (req_perm == OTX2_TRUSTED_VF) {
+ if (pf->vf_configs[vf].trusted)
+ req->flags |= VF_TRUSTED;
+ }
+
+ req->vf = vf;
+ rc = otx2_sync_mbox_msg(&pf->mbox);
+out:
+ mutex_unlock(&pf->mbox.lock);
+ return rc;
+}
+
+static int otx2_ndo_set_vf_trust(struct net_device *netdev, int vf,
+ bool enable)
+{
+ struct otx2_nic *pf = netdev_priv(netdev);
+ struct pci_dev *pdev = pf->pdev;
+ int rc;
+
+ if (vf >= pci_num_vf(pdev))
+ return -EINVAL;
+
+ if (pf->vf_configs[vf].trusted == enable)
+ return 0;
+
+ pf->vf_configs[vf].trusted = enable;
+ rc = otx2_set_vf_permissions(pf, vf, OTX2_TRUSTED_VF);
+
+ if (rc)
+ pf->vf_configs[vf].trusted = !enable;
+ else
+ netdev_info(pf->netdev, "VF %d is %strusted\n",
+ vf, enable ? "" : "not ");
+ return rc;
+}
+
static const struct net_device_ops otx2_netdev_ops = {
.ndo_open = otx2_open,
.ndo_stop = otx2_stop,
@@ -2261,6 +2331,7 @@ static const struct net_device_ops otx2_netdev_ops = {
.ndo_set_vf_vlan = otx2_set_vf_vlan,
.ndo_get_vf_config = otx2_get_vf_config,
.ndo_setup_tc = otx2_setup_tc,
+ .ndo_set_vf_trust = otx2_ndo_set_vf_trust,
};
static int otx2_wq_init(struct otx2_nic *pf)
@@ -2315,6 +2386,40 @@ static int otx2_realloc_msix_vectors(struct otx2_nic *pf)
return otx2_register_mbox_intr(pf, false);
}
+static int otx2_sriov_vfcfg_init(struct otx2_nic *pf)
+{
+ int i;
+
+ pf->vf_configs = devm_kcalloc(pf->dev, pf->total_vfs,
+ sizeof(struct otx2_vf_config),
+ GFP_KERNEL);
+ if (!pf->vf_configs)
+ return -ENOMEM;
+
+ for (i = 0; i < pf->total_vfs; i++) {
+ pf->vf_configs[i].pf = pf;
+ pf->vf_configs[i].intf_down = true;
+ pf->vf_configs[i].trusted = false;
+ INIT_DELAYED_WORK(&pf->vf_configs[i].link_event_work,
+ otx2_vf_link_event_task);
+ }
+
+ return 0;
+}
+
+static void otx2_sriov_vfcfg_cleanup(struct otx2_nic *pf)
+{
+ int i;
+
+ if (!pf->vf_configs)
+ return;
+
+ for (i = 0; i < pf->total_vfs; i++) {
+ cancel_delayed_work_sync(&pf->vf_configs[i].link_event_work);
+ otx2_set_vf_permissions(pf, i, OTX2_RESET_VF_PERM);
+ }
+}
+
static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct device *dev = &pdev->dev;
@@ -2430,7 +2535,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (err)
goto err_detach_rsrc;
- err = cn10k_pf_lmtst_init(pf);
+ err = cn10k_lmtst_init(pf);
if (err)
goto err_detach_rsrc;
@@ -2509,6 +2614,11 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (err)
goto err_mcam_flow_del;
+ /* Initialize SR-IOV resources */
+ err = otx2_sriov_vfcfg_init(pf);
+ if (err)
+ goto err_pf_sriov_init;
+
/* Enable link notifications */
otx2_cgx_config_linkevents(pf, true);
@@ -2518,6 +2628,8 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
+err_pf_sriov_init:
+ otx2_shutdown_tc(pf);
err_mcam_flow_del:
otx2_mcam_flow_del(pf);
err_unreg_netdev:
@@ -2527,8 +2639,8 @@ err_del_mcam_entries:
err_ptp_destroy:
otx2_ptp_destroy(pf);
err_detach_rsrc:
- if (hw->lmt_base)
- iounmap(hw->lmt_base);
+ if (test_bit(CN10K_LMTST, &pf->hw.cap_flag))
+ qmem_free(pf->dev, pf->dync_lmt);
otx2_detach_resources(&pf->mbox);
err_disable_mbox_intr:
otx2_disable_mbox_intr(pf);
@@ -2576,7 +2688,7 @@ static int otx2_sriov_enable(struct pci_dev *pdev, int numvfs)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct otx2_nic *pf = netdev_priv(netdev);
- int ret, i;
+ int ret;
/* Init PF <=> VF mailbox stuff */
ret = otx2_pfvf_mbox_init(pf, numvfs);
@@ -2587,23 +2699,9 @@ static int otx2_sriov_enable(struct pci_dev *pdev, int numvfs)
if (ret)
goto free_mbox;
- pf->vf_configs = kcalloc(numvfs, sizeof(struct otx2_vf_config),
- GFP_KERNEL);
- if (!pf->vf_configs) {
- ret = -ENOMEM;
- goto free_intr;
- }
-
- for (i = 0; i < numvfs; i++) {
- pf->vf_configs[i].pf = pf;
- pf->vf_configs[i].intf_down = true;
- INIT_DELAYED_WORK(&pf->vf_configs[i].link_event_work,
- otx2_vf_link_event_task);
- }
-
ret = otx2_pf_flr_init(pf, numvfs);
if (ret)
- goto free_configs;
+ goto free_intr;
ret = otx2_register_flr_me_intr(pf, numvfs);
if (ret)
@@ -2618,8 +2716,6 @@ free_flr_intr:
otx2_disable_flr_me_intr(pf);
free_flr:
otx2_flr_wq_destroy(pf);
-free_configs:
- kfree(pf->vf_configs);
free_intr:
otx2_disable_pfvf_mbox_intr(pf, numvfs);
free_mbox:
@@ -2632,17 +2728,12 @@ static int otx2_sriov_disable(struct pci_dev *pdev)
struct net_device *netdev = pci_get_drvdata(pdev);
struct otx2_nic *pf = netdev_priv(netdev);
int numvfs = pci_num_vf(pdev);
- int i;
if (!numvfs)
return 0;
pci_disable_sriov(pdev);
- for (i = 0; i < pci_num_vf(pdev); i++)
- cancel_delayed_work_sync(&pf->vf_configs[i].link_event_work);
- kfree(pf->vf_configs);
-
otx2_disable_flr_me_intr(pf);
otx2_flr_wq_destroy(pf);
otx2_disable_pfvf_mbox_intr(pf, numvfs);
@@ -2682,6 +2773,7 @@ static void otx2_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
otx2_sriov_disable(pf->pdev);
+ otx2_sriov_vfcfg_cleanup(pf);
if (pf->otx2_wq)
destroy_workqueue(pf->otx2_wq);
@@ -2689,9 +2781,8 @@ static void otx2_remove(struct pci_dev *pdev)
otx2_mcam_flow_del(pf);
otx2_shutdown_tc(pf);
otx2_detach_resources(&pf->mbox);
- if (pf->hw.lmt_base)
- iounmap(pf->hw.lmt_base);
-
+ if (test_bit(CN10K_LMTST, &pf->hw.cap_flag))
+ qmem_free(pf->dev, pf->dync_lmt);
otx2_disable_mbox_intr(pf);
otx2_pfaf_mbox_destroy(pf);
pci_free_irq_vectors(pf->pdev);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
index 51157b283f6f..972b202b9884 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
@@ -15,6 +15,7 @@
#include <net/tc_act/tc_vlan.h>
#include <net/ipv6.h>
+#include "cn10k.h"
#include "otx2_common.h"
/* Egress rate limiting definitions */
@@ -41,11 +42,14 @@ struct otx2_tc_flow_stats {
struct otx2_tc_flow {
struct rhash_head node;
unsigned long cookie;
- u16 entry;
unsigned int bitpos;
struct rcu_head rcu;
struct otx2_tc_flow_stats stats;
spinlock_t lock; /* lock for stats */
+ u16 rq;
+ u16 entry;
+ u16 leaf_profile;
+ bool is_act_police;
};
static void otx2_get_egress_burst_cfg(u32 burst, u32 *burst_exp,
@@ -220,17 +224,76 @@ static int otx2_tc_egress_matchall_delete(struct otx2_nic *nic,
return err;
}
+static int otx2_tc_act_set_police(struct otx2_nic *nic,
+ struct otx2_tc_flow *node,
+ struct flow_cls_offload *f,
+ u64 rate, u32 burst, u32 mark,
+ struct npc_install_flow_req *req, bool pps)
+{
+ struct netlink_ext_ack *extack = f->common.extack;
+ struct otx2_hw *hw = &nic->hw;
+ int rq_idx, rc;
+
+ rq_idx = find_first_zero_bit(&nic->rq_bmap, hw->rx_queues);
+ if (rq_idx >= hw->rx_queues) {
+ NL_SET_ERR_MSG_MOD(extack, "Police action rules exceeded");
+ return -EINVAL;
+ }
+
+ mutex_lock(&nic->mbox.lock);
+
+ rc = cn10k_alloc_leaf_profile(nic, &node->leaf_profile);
+ if (rc) {
+ mutex_unlock(&nic->mbox.lock);
+ return rc;
+ }
+
+ rc = cn10k_set_ipolicer_rate(nic, node->leaf_profile, burst, rate, pps);
+ if (rc)
+ goto free_leaf;
+
+ rc = cn10k_map_unmap_rq_policer(nic, rq_idx, node->leaf_profile, true);
+ if (rc)
+ goto free_leaf;
+
+ mutex_unlock(&nic->mbox.lock);
+
+ req->match_id = mark & 0xFFFFULL;
+ req->index = rq_idx;
+ req->op = NIX_RX_ACTIONOP_UCAST;
+ set_bit(rq_idx, &nic->rq_bmap);
+ node->is_act_police = true;
+ node->rq = rq_idx;
+
+ return 0;
+
+free_leaf:
+ if (cn10k_free_leaf_profile(nic, node->leaf_profile))
+ netdev_err(nic->netdev,
+ "Unable to free leaf bandwidth profile(%d)\n",
+ node->leaf_profile);
+ mutex_unlock(&nic->mbox.lock);
+ return rc;
+}
+
static int otx2_tc_parse_actions(struct otx2_nic *nic,
struct flow_action *flow_action,
- struct npc_install_flow_req *req)
+ struct npc_install_flow_req *req,
+ struct flow_cls_offload *f,
+ struct otx2_tc_flow *node)
{
+ struct netlink_ext_ack *extack = f->common.extack;
struct flow_action_entry *act;
struct net_device *target;
struct otx2_nic *priv;
+ u32 burst, mark = 0;
+ u8 nr_police = 0;
+ bool pps = false;
+ u64 rate;
int i;
if (!flow_action_has_entries(flow_action)) {
- netdev_info(nic->netdev, "no tc actions specified");
+ NL_SET_ERR_MSG_MOD(extack, "no tc actions specified");
return -EINVAL;
}
@@ -247,8 +310,8 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic,
priv = netdev_priv(target);
/* npc_install_flow_req doesn't support passing a target pcifunc */
if (rvu_get_pf(nic->pcifunc) != rvu_get_pf(priv->pcifunc)) {
- netdev_info(nic->netdev,
- "can't redirect to other pf/vf\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "can't redirect to other pf/vf");
return -EOPNOTSUPP;
}
req->vf = priv->pcifunc & RVU_PFVF_FUNC_MASK;
@@ -259,18 +322,55 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic,
/* use RX_VTAG_TYPE7 which is initialized to strip vlan tag */
req->vtag0_type = NIX_AF_LFX_RX_VTAG_TYPE7;
break;
+ case FLOW_ACTION_POLICE:
+ /* Ingress ratelimiting is not supported on OcteonTx2 */
+ if (is_dev_otx2(nic->pdev)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Ingress policing not supported on this platform");
+ return -EOPNOTSUPP;
+ }
+
+ if (act->police.rate_bytes_ps > 0) {
+ rate = act->police.rate_bytes_ps * 8;
+ burst = act->police.burst;
+ } else if (act->police.rate_pkt_ps > 0) {
+ /* The algorithm used to calculate rate
+ * mantissa, exponent values for a given token
+ * rate (token can be byte or packet) requires
+ * token rate to be mutiplied by 8.
+ */
+ rate = act->police.rate_pkt_ps * 8;
+ burst = act->police.burst_pkt;
+ pps = true;
+ }
+ nr_police++;
+ break;
+ case FLOW_ACTION_MARK:
+ mark = act->mark;
+ break;
default:
return -EOPNOTSUPP;
}
}
+ if (nr_police > 1) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "rate limit police offload requires a single action");
+ return -EOPNOTSUPP;
+ }
+
+ if (nr_police)
+ return otx2_tc_act_set_police(nic, node, f, rate, burst,
+ mark, req, pps);
+
return 0;
}
-static int otx2_tc_prepare_flow(struct otx2_nic *nic,
+static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
struct flow_cls_offload *f,
struct npc_install_flow_req *req)
{
+ struct netlink_ext_ack *extack = f->common.extack;
struct flow_msg *flow_spec = &req->packet;
struct flow_msg *flow_mask = &req->mask;
struct flow_dissector *dissector;
@@ -335,7 +435,7 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic,
flow_rule_match_eth_addrs(rule, &match);
if (!is_zero_ether_addr(match.mask->src)) {
- netdev_err(nic->netdev, "src mac match not supported\n");
+ NL_SET_ERR_MSG_MOD(extack, "src mac match not supported");
return -EOPNOTSUPP;
}
@@ -353,11 +453,11 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic,
flow_rule_match_ip(rule, &match);
if ((ntohs(flow_spec->etype) != ETH_P_IP) &&
match.mask->tos) {
- netdev_err(nic->netdev, "tos not supported\n");
+ NL_SET_ERR_MSG_MOD(extack, "tos not supported");
return -EOPNOTSUPP;
}
if (match.mask->ttl) {
- netdev_err(nic->netdev, "ttl not supported\n");
+ NL_SET_ERR_MSG_MOD(extack, "ttl not supported");
return -EOPNOTSUPP;
}
flow_spec->tos = match.key->tos;
@@ -413,8 +513,8 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic,
if (ipv6_addr_loopback(&match.key->dst) ||
ipv6_addr_loopback(&match.key->src)) {
- netdev_err(nic->netdev,
- "Flow matching on IPv6 loopback addr is not supported\n");
+ NL_SET_ERR_MSG_MOD(extack,
+ "Flow matching IPv6 loopback addr not supported");
return -EOPNOTSUPP;
}
@@ -463,7 +563,7 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic,
req->features |= BIT_ULL(NPC_SPORT_SCTP);
}
- return otx2_tc_parse_actions(nic, &rule->action, req);
+ return otx2_tc_parse_actions(nic, &rule->action, req, f, node);
}
static int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry)
@@ -498,6 +598,7 @@ static int otx2_tc_del_flow(struct otx2_nic *nic,
{
struct otx2_tc_info *tc_info = &nic->tc_info;
struct otx2_tc_flow *flow_node;
+ int err;
flow_node = rhashtable_lookup_fast(&tc_info->flow_table,
&tc_flow_cmd->cookie,
@@ -508,6 +609,27 @@ static int otx2_tc_del_flow(struct otx2_nic *nic,
return -EINVAL;
}
+ if (flow_node->is_act_police) {
+ mutex_lock(&nic->mbox.lock);
+
+ err = cn10k_map_unmap_rq_policer(nic, flow_node->rq,
+ flow_node->leaf_profile, false);
+ if (err)
+ netdev_err(nic->netdev,
+ "Unmapping RQ %d & profile %d failed\n",
+ flow_node->rq, flow_node->leaf_profile);
+
+ err = cn10k_free_leaf_profile(nic, flow_node->leaf_profile);
+ if (err)
+ netdev_err(nic->netdev,
+ "Unable to free leaf bandwidth profile(%d)\n",
+ flow_node->leaf_profile);
+
+ __clear_bit(flow_node->rq, &nic->rq_bmap);
+
+ mutex_unlock(&nic->mbox.lock);
+ }
+
otx2_del_mcam_flow_entry(nic, flow_node->entry);
WARN_ON(rhashtable_remove_fast(&nic->tc_info.flow_table,
@@ -524,14 +646,21 @@ static int otx2_tc_del_flow(struct otx2_nic *nic,
static int otx2_tc_add_flow(struct otx2_nic *nic,
struct flow_cls_offload *tc_flow_cmd)
{
+ struct netlink_ext_ack *extack = tc_flow_cmd->common.extack;
struct otx2_tc_info *tc_info = &nic->tc_info;
struct otx2_tc_flow *new_node, *old_node;
- struct npc_install_flow_req *req;
- int rc;
+ struct npc_install_flow_req *req, dummy;
+ int rc, err;
if (!(nic->flags & OTX2_FLAG_TC_FLOWER_SUPPORT))
return -ENOMEM;
+ if (bitmap_full(tc_info->tc_entries_bitmap, nic->flow_cfg->tc_max_flows)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Not enough MCAM space to add the flow");
+ return -ENOMEM;
+ }
+
/* allocate memory for the new flow and it's node */
new_node = kzalloc(sizeof(*new_node), GFP_KERNEL);
if (!new_node)
@@ -539,17 +668,11 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
spin_lock_init(&new_node->lock);
new_node->cookie = tc_flow_cmd->cookie;
- mutex_lock(&nic->mbox.lock);
- req = otx2_mbox_alloc_msg_npc_install_flow(&nic->mbox);
- if (!req) {
- mutex_unlock(&nic->mbox.lock);
- return -ENOMEM;
- }
+ memset(&dummy, 0, sizeof(struct npc_install_flow_req));
- rc = otx2_tc_prepare_flow(nic, tc_flow_cmd, req);
+ rc = otx2_tc_prepare_flow(nic, new_node, tc_flow_cmd, &dummy);
if (rc) {
- otx2_mbox_reset(&nic->mbox.mbox, 0);
- mutex_unlock(&nic->mbox.lock);
+ kfree_rcu(new_node, rcu);
return rc;
}
@@ -560,18 +683,22 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
if (old_node)
otx2_tc_del_flow(nic, tc_flow_cmd);
- if (bitmap_full(tc_info->tc_entries_bitmap, nic->flow_cfg->tc_max_flows)) {
- netdev_err(nic->netdev, "Not enough MCAM space to add the flow\n");
- otx2_mbox_reset(&nic->mbox.mbox, 0);
+ mutex_lock(&nic->mbox.lock);
+ req = otx2_mbox_alloc_msg_npc_install_flow(&nic->mbox);
+ if (!req) {
mutex_unlock(&nic->mbox.lock);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto free_leaf;
}
+ memcpy(&dummy.hdr, &req->hdr, sizeof(struct mbox_msghdr));
+ memcpy(req, &dummy, sizeof(struct npc_install_flow_req));
+
new_node->bitpos = find_first_zero_bit(tc_info->tc_entries_bitmap,
nic->flow_cfg->tc_max_flows);
req->channel = nic->hw.rx_chan_base;
- req->entry = nic->flow_cfg->entry[nic->flow_cfg->tc_flower_offset +
- nic->flow_cfg->tc_max_flows - new_node->bitpos];
+ req->entry = nic->flow_cfg->flow_ent[nic->flow_cfg->tc_flower_offset +
+ nic->flow_cfg->tc_max_flows - new_node->bitpos];
req->intf = NIX_INTF_RX;
req->set_cntr = 1;
new_node->entry = req->entry;
@@ -579,9 +706,10 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
/* Send message to AF */
rc = otx2_sync_mbox_msg(&nic->mbox);
if (rc) {
- netdev_err(nic->netdev, "Failed to install MCAM flow entry\n");
+ NL_SET_ERR_MSG_MOD(extack, "Failed to install MCAM flow entry");
mutex_unlock(&nic->mbox.lock);
- goto out;
+ kfree_rcu(new_node, rcu);
+ goto free_leaf;
}
mutex_unlock(&nic->mbox.lock);
@@ -591,12 +719,35 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
if (rc) {
otx2_del_mcam_flow_entry(nic, req->entry);
kfree_rcu(new_node, rcu);
- goto out;
+ goto free_leaf;
}
set_bit(new_node->bitpos, tc_info->tc_entries_bitmap);
tc_info->num_entries++;
-out:
+
+ return 0;
+
+free_leaf:
+ if (new_node->is_act_police) {
+ mutex_lock(&nic->mbox.lock);
+
+ err = cn10k_map_unmap_rq_policer(nic, new_node->rq,
+ new_node->leaf_profile, false);
+ if (err)
+ netdev_err(nic->netdev,
+ "Unmapping RQ %d & profile %d failed\n",
+ new_node->rq, new_node->leaf_profile);
+ err = cn10k_free_leaf_profile(nic, new_node->leaf_profile);
+ if (err)
+ netdev_err(nic->netdev,
+ "Unable to free leaf bandwidth profile(%d)\n",
+ new_node->leaf_profile);
+
+ __clear_bit(new_node->rq, &nic->rq_bmap);
+
+ mutex_unlock(&nic->mbox.lock);
+ }
+
return rc;
}
@@ -675,6 +826,87 @@ static int otx2_setup_tc_cls_flower(struct otx2_nic *nic,
}
}
+static int otx2_tc_ingress_matchall_install(struct otx2_nic *nic,
+ struct tc_cls_matchall_offload *cls)
+{
+ struct netlink_ext_ack *extack = cls->common.extack;
+ struct flow_action *actions = &cls->rule->action;
+ struct flow_action_entry *entry;
+ u64 rate;
+ int err;
+
+ err = otx2_tc_validate_flow(nic, actions, extack);
+ if (err)
+ return err;
+
+ if (nic->flags & OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Only one ingress MATCHALL ratelimitter can be offloaded");
+ return -ENOMEM;
+ }
+
+ entry = &cls->rule->action.entries[0];
+ switch (entry->id) {
+ case FLOW_ACTION_POLICE:
+ /* Ingress ratelimiting is not supported on OcteonTx2 */
+ if (is_dev_otx2(nic->pdev)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Ingress policing not supported on this platform");
+ return -EOPNOTSUPP;
+ }
+
+ err = cn10k_alloc_matchall_ipolicer(nic);
+ if (err)
+ return err;
+
+ /* Convert to bits per second */
+ rate = entry->police.rate_bytes_ps * 8;
+ err = cn10k_set_matchall_ipolicer_rate(nic, entry->police.burst, rate);
+ if (err)
+ return err;
+ nic->flags |= OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED;
+ break;
+ default:
+ NL_SET_ERR_MSG_MOD(extack,
+ "Only police action supported with Ingress MATCHALL offload");
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int otx2_tc_ingress_matchall_delete(struct otx2_nic *nic,
+ struct tc_cls_matchall_offload *cls)
+{
+ struct netlink_ext_ack *extack = cls->common.extack;
+ int err;
+
+ if (nic->flags & OTX2_FLAG_INTF_DOWN) {
+ NL_SET_ERR_MSG_MOD(extack, "Interface not initialized");
+ return -EINVAL;
+ }
+
+ err = cn10k_free_matchall_ipolicer(nic);
+ nic->flags &= ~OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED;
+ return err;
+}
+
+static int otx2_setup_tc_ingress_matchall(struct otx2_nic *nic,
+ struct tc_cls_matchall_offload *cls_matchall)
+{
+ switch (cls_matchall->command) {
+ case TC_CLSMATCHALL_REPLACE:
+ return otx2_tc_ingress_matchall_install(nic, cls_matchall);
+ case TC_CLSMATCHALL_DESTROY:
+ return otx2_tc_ingress_matchall_delete(nic, cls_matchall);
+ case TC_CLSMATCHALL_STATS:
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
static int otx2_setup_tc_block_ingress_cb(enum tc_setup_type type,
void *type_data, void *cb_priv)
{
@@ -686,6 +918,8 @@ static int otx2_setup_tc_block_ingress_cb(enum tc_setup_type type,
switch (type) {
case TC_SETUP_CLSFLOWER:
return otx2_setup_tc_cls_flower(nic, type_data);
+ case TC_SETUP_CLSMATCHALL:
+ return otx2_setup_tc_ingress_matchall(nic, type_data);
default:
break;
}
@@ -775,6 +1009,9 @@ int otx2_init_tc(struct otx2_nic *nic)
{
struct otx2_tc_info *tc = &nic->tc_info;
+ /* Exclude receive queue 0 being used for police action */
+ set_bit(0, &nic->rq_bmap);
+
tc->flow_ht_params = tc_flow_ht_params;
return rhashtable_init(&tc->flow_table, &tc->flow_ht_params);
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h
index 52486c1f0973..2f144e2cf436 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h
@@ -83,6 +83,7 @@ struct otx2_snd_queue {
u16 num_sqbs;
u16 sqe_thresh;
u8 sqe_per_sqb;
+ u32 lmt_id;
u64 io_addr;
u64 *aura_fc_addr;
u64 *lmt_addr;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
index 085be90a03eb..a8bee5aefec1 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
@@ -395,6 +395,42 @@ static netdev_tx_t otx2vf_xmit(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_OK;
}
+static void otx2vf_set_rx_mode(struct net_device *netdev)
+{
+ struct otx2_nic *vf = netdev_priv(netdev);
+
+ queue_work(vf->otx2_wq, &vf->rx_mode_work);
+}
+
+static void otx2vf_do_set_rx_mode(struct work_struct *work)
+{
+ struct otx2_nic *vf = container_of(work, struct otx2_nic, rx_mode_work);
+ struct net_device *netdev = vf->netdev;
+ unsigned int flags = netdev->flags;
+ struct nix_rx_mode *req;
+
+ mutex_lock(&vf->mbox.lock);
+
+ req = otx2_mbox_alloc_msg_nix_set_rx_mode(&vf->mbox);
+ if (!req) {
+ mutex_unlock(&vf->mbox.lock);
+ return;
+ }
+
+ req->mode = NIX_RX_MODE_UCAST;
+
+ if (flags & IFF_PROMISC)
+ req->mode |= NIX_RX_MODE_PROMISC;
+ if (flags & (IFF_ALLMULTI | IFF_MULTICAST))
+ req->mode |= NIX_RX_MODE_ALLMULTI;
+
+ req->mode |= NIX_RX_MODE_USE_MCE;
+
+ otx2_sync_mbox_msg(&vf->mbox);
+
+ mutex_unlock(&vf->mbox.lock);
+}
+
static int otx2vf_change_mtu(struct net_device *netdev, int new_mtu)
{
bool if_up = netif_running(netdev);
@@ -432,12 +468,24 @@ static const struct net_device_ops otx2vf_netdev_ops = {
.ndo_open = otx2vf_open,
.ndo_stop = otx2vf_stop,
.ndo_start_xmit = otx2vf_xmit,
+ .ndo_set_rx_mode = otx2vf_set_rx_mode,
.ndo_set_mac_address = otx2_set_mac_address,
.ndo_change_mtu = otx2vf_change_mtu,
.ndo_get_stats64 = otx2_get_stats64,
.ndo_tx_timeout = otx2_tx_timeout,
};
+static int otx2_wq_init(struct otx2_nic *vf)
+{
+ vf->otx2_wq = create_singlethread_workqueue("otx2vf_wq");
+ if (!vf->otx2_wq)
+ return -ENOMEM;
+
+ INIT_WORK(&vf->rx_mode_work, otx2vf_do_set_rx_mode);
+ INIT_WORK(&vf->reset_task, otx2vf_reset_task);
+ return 0;
+}
+
static int otx2vf_realloc_msix_vectors(struct otx2_nic *vf)
{
struct otx2_hw *hw = &vf->hw;
@@ -561,7 +609,7 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (err)
goto err_detach_rsrc;
- err = cn10k_vf_lmtst_init(vf);
+ err = cn10k_lmtst_init(vf);
if (err)
goto err_detach_rsrc;
@@ -588,8 +636,6 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
netdev->min_mtu = OTX2_MIN_MTU;
netdev->max_mtu = otx2_get_max_mtu(vf);
- INIT_WORK(&vf->reset_task, otx2vf_reset_task);
-
/* To distinguish, for LBK VFs set netdev name explicitly */
if (is_otx2_lbkvf(vf->pdev)) {
int n;
@@ -606,6 +652,10 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_detach_rsrc;
}
+ err = otx2_wq_init(vf);
+ if (err)
+ goto err_unreg_netdev;
+
otx2vf_set_ethtool_ops(netdev);
/* Enable pause frames by default */
@@ -614,9 +664,11 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
+err_unreg_netdev:
+ unregister_netdev(netdev);
err_detach_rsrc:
- if (hw->lmt_base)
- iounmap(hw->lmt_base);
+ if (test_bit(CN10K_LMTST, &vf->hw.cap_flag))
+ qmem_free(vf->dev, vf->dync_lmt);
otx2_detach_resources(&vf->mbox);
err_disable_mbox_intr:
otx2vf_disable_mbox_intr(vf);
@@ -644,12 +696,12 @@ static void otx2vf_remove(struct pci_dev *pdev)
cancel_work_sync(&vf->reset_task);
unregister_netdev(netdev);
+ if (vf->otx2_wq)
+ destroy_workqueue(vf->otx2_wq);
otx2vf_disable_mbox_intr(vf);
otx2_detach_resources(&vf->mbox);
-
- if (vf->hw.lmt_base)
- iounmap(vf->hw.lmt_base);
-
+ if (test_bit(CN10K_LMTST, &vf->hw.cap_flag))
+ qmem_free(vf->dev, vf->dync_lmt);
otx2vf_vfaf_mbox_destroy(vf);
pci_free_irq_vectors(vf->pdev);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/ethernet/marvell/prestera/Makefile b/drivers/net/ethernet/marvell/prestera/Makefile
index 93129e32ebc5..0609df8b913d 100644
--- a/drivers/net/ethernet/marvell/prestera/Makefile
+++ b/drivers/net/ethernet/marvell/prestera/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_PRESTERA) += prestera.o
prestera-objs := prestera_main.o prestera_hw.o prestera_dsa.o \
prestera_rxtx.o prestera_devlink.o prestera_ethtool.o \
- prestera_switchdev.o
+ prestera_switchdev.o prestera_acl.o prestera_flow.o \
+ prestera_flower.o prestera_span.o
obj-$(CONFIG_PRESTERA_PCI) += prestera_pci.o
diff --git a/drivers/net/ethernet/marvell/prestera/prestera.h b/drivers/net/ethernet/marvell/prestera/prestera.h
index 55aa4bf8a27c..f18fe664b373 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera.h
+++ b/drivers/net/ethernet/marvell/prestera/prestera.h
@@ -60,10 +60,22 @@ struct prestera_port_caps {
u8 transceiver;
};
+struct prestera_lag {
+ struct net_device *dev;
+ struct list_head members;
+ u16 member_count;
+ u16 lag_id;
+};
+
+struct prestera_flow_block;
+
struct prestera_port {
struct net_device *dev;
struct prestera_switch *sw;
+ struct prestera_flow_block *flow_block;
struct devlink_port dl_port;
+ struct list_head lag_member;
+ struct prestera_lag *lag;
u32 id;
u32 hw_id;
u32 dev_id;
@@ -127,6 +139,12 @@ struct prestera_port_event {
} data;
};
+enum prestera_fdb_entry_type {
+ PRESTERA_FDB_ENTRY_TYPE_REG_PORT,
+ PRESTERA_FDB_ENTRY_TYPE_LAG,
+ PRESTERA_FDB_ENTRY_TYPE_MAX
+};
+
enum prestera_fdb_event_id {
PRESTERA_FDB_EVENT_UNSPEC,
PRESTERA_FDB_EVENT_LEARNED,
@@ -134,7 +152,11 @@ enum prestera_fdb_event_id {
};
struct prestera_fdb_event {
- u32 port_id;
+ enum prestera_fdb_entry_type type;
+ union {
+ u32 port_id;
+ u16 lag_id;
+ } dest;
u32 vid;
union {
u8 mac[ETH_ALEN];
@@ -150,14 +172,20 @@ struct prestera_event {
};
struct prestera_switchdev;
+struct prestera_span;
struct prestera_rxtx;
+struct prestera_trap_data;
+struct prestera_acl;
struct prestera_switch {
struct prestera_device *dev;
struct prestera_switchdev *swdev;
struct prestera_rxtx *rxtx;
+ struct prestera_acl *acl;
+ struct prestera_span *span;
struct list_head event_handlers;
struct notifier_block netdev_nb;
+ struct prestera_trap_data *trap_data;
char base_mac[ETH_ALEN];
struct list_head port_list;
rwlock_t port_list_lock;
@@ -165,6 +193,9 @@ struct prestera_switch {
u32 mtu_min;
u32 mtu_max;
u8 id;
+ struct prestera_lag *lags;
+ u8 lag_member_max;
+ u8 lag_max;
};
struct prestera_rxtx_params {
@@ -203,4 +234,10 @@ int prestera_port_pvid_set(struct prestera_port *port, u16 vid);
bool prestera_netdev_check(const struct net_device *dev);
+bool prestera_port_is_lag_member(const struct prestera_port *port);
+
+struct prestera_lag *prestera_lag_by_id(struct prestera_switch *sw, u16 id);
+
+u16 prestera_port_lag_id(const struct prestera_port *port);
+
#endif /* _PRESTERA_H_ */
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_acl.c b/drivers/net/ethernet/marvell/prestera/prestera_acl.c
new file mode 100644
index 000000000000..83c75ffb1a1c
--- /dev/null
+++ b/drivers/net/ethernet/marvell/prestera/prestera_acl.c
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/* Copyright (c) 2020 Marvell International Ltd. All rights reserved */
+
+#include <linux/rhashtable.h>
+
+#include "prestera.h"
+#include "prestera_hw.h"
+#include "prestera_acl.h"
+#include "prestera_span.h"
+
+struct prestera_acl {
+ struct prestera_switch *sw;
+ struct list_head rules;
+};
+
+struct prestera_acl_ruleset {
+ struct rhashtable rule_ht;
+ struct prestera_switch *sw;
+ u16 id;
+};
+
+struct prestera_acl_rule {
+ struct rhash_head ht_node;
+ struct list_head list;
+ struct list_head match_list;
+ struct list_head action_list;
+ struct prestera_flow_block *block;
+ unsigned long cookie;
+ u32 priority;
+ u8 n_actions;
+ u8 n_matches;
+ u32 id;
+};
+
+static const struct rhashtable_params prestera_acl_rule_ht_params = {
+ .key_len = sizeof(unsigned long),
+ .key_offset = offsetof(struct prestera_acl_rule, cookie),
+ .head_offset = offsetof(struct prestera_acl_rule, ht_node),
+ .automatic_shrinking = true,
+};
+
+static struct prestera_acl_ruleset *
+prestera_acl_ruleset_create(struct prestera_switch *sw)
+{
+ struct prestera_acl_ruleset *ruleset;
+ int err;
+
+ ruleset = kzalloc(sizeof(*ruleset), GFP_KERNEL);
+ if (!ruleset)
+ return ERR_PTR(-ENOMEM);
+
+ err = rhashtable_init(&ruleset->rule_ht, &prestera_acl_rule_ht_params);
+ if (err)
+ goto err_rhashtable_init;
+
+ err = prestera_hw_acl_ruleset_create(sw, &ruleset->id);
+ if (err)
+ goto err_ruleset_create;
+
+ ruleset->sw = sw;
+
+ return ruleset;
+
+err_ruleset_create:
+ rhashtable_destroy(&ruleset->rule_ht);
+err_rhashtable_init:
+ kfree(ruleset);
+ return ERR_PTR(err);
+}
+
+static void prestera_acl_ruleset_destroy(struct prestera_acl_ruleset *ruleset)
+{
+ prestera_hw_acl_ruleset_del(ruleset->sw, ruleset->id);
+ rhashtable_destroy(&ruleset->rule_ht);
+ kfree(ruleset);
+}
+
+struct prestera_flow_block *
+prestera_acl_block_create(struct prestera_switch *sw, struct net *net)
+{
+ struct prestera_flow_block *block;
+
+ block = kzalloc(sizeof(*block), GFP_KERNEL);
+ if (!block)
+ return NULL;
+ INIT_LIST_HEAD(&block->binding_list);
+ block->net = net;
+ block->sw = sw;
+
+ block->ruleset = prestera_acl_ruleset_create(sw);
+ if (IS_ERR(block->ruleset)) {
+ kfree(block);
+ return NULL;
+ }
+
+ return block;
+}
+
+void prestera_acl_block_destroy(struct prestera_flow_block *block)
+{
+ prestera_acl_ruleset_destroy(block->ruleset);
+ WARN_ON(!list_empty(&block->binding_list));
+ kfree(block);
+}
+
+static struct prestera_flow_block_binding *
+prestera_acl_block_lookup(struct prestera_flow_block *block,
+ struct prestera_port *port)
+{
+ struct prestera_flow_block_binding *binding;
+
+ list_for_each_entry(binding, &block->binding_list, list)
+ if (binding->port == port)
+ return binding;
+
+ return NULL;
+}
+
+int prestera_acl_block_bind(struct prestera_flow_block *block,
+ struct prestera_port *port)
+{
+ struct prestera_flow_block_binding *binding;
+ int err;
+
+ if (WARN_ON(prestera_acl_block_lookup(block, port)))
+ return -EEXIST;
+
+ binding = kzalloc(sizeof(*binding), GFP_KERNEL);
+ if (!binding)
+ return -ENOMEM;
+ binding->span_id = PRESTERA_SPAN_INVALID_ID;
+ binding->port = port;
+
+ err = prestera_hw_acl_port_bind(port, block->ruleset->id);
+ if (err)
+ goto err_rules_bind;
+
+ list_add(&binding->list, &block->binding_list);
+ return 0;
+
+err_rules_bind:
+ kfree(binding);
+ return err;
+}
+
+int prestera_acl_block_unbind(struct prestera_flow_block *block,
+ struct prestera_port *port)
+{
+ struct prestera_flow_block_binding *binding;
+
+ binding = prestera_acl_block_lookup(block, port);
+ if (!binding)
+ return -ENOENT;
+
+ list_del(&binding->list);
+
+ prestera_hw_acl_port_unbind(port, block->ruleset->id);
+
+ kfree(binding);
+ return 0;
+}
+
+struct prestera_acl_ruleset *
+prestera_acl_block_ruleset_get(struct prestera_flow_block *block)
+{
+ return block->ruleset;
+}
+
+u16 prestera_acl_rule_ruleset_id_get(const struct prestera_acl_rule *rule)
+{
+ return rule->block->ruleset->id;
+}
+
+struct net *prestera_acl_block_net(struct prestera_flow_block *block)
+{
+ return block->net;
+}
+
+struct prestera_switch *prestera_acl_block_sw(struct prestera_flow_block *block)
+{
+ return block->sw;
+}
+
+struct prestera_acl_rule *
+prestera_acl_rule_lookup(struct prestera_acl_ruleset *ruleset,
+ unsigned long cookie)
+{
+ return rhashtable_lookup_fast(&ruleset->rule_ht, &cookie,
+ prestera_acl_rule_ht_params);
+}
+
+struct prestera_acl_rule *
+prestera_acl_rule_create(struct prestera_flow_block *block,
+ unsigned long cookie)
+{
+ struct prestera_acl_rule *rule;
+
+ rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+ if (!rule)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&rule->match_list);
+ INIT_LIST_HEAD(&rule->action_list);
+ rule->cookie = cookie;
+ rule->block = block;
+
+ return rule;
+}
+
+struct list_head *
+prestera_acl_rule_match_list_get(struct prestera_acl_rule *rule)
+{
+ return &rule->match_list;
+}
+
+struct list_head *
+prestera_acl_rule_action_list_get(struct prestera_acl_rule *rule)
+{
+ return &rule->action_list;
+}
+
+int prestera_acl_rule_action_add(struct prestera_acl_rule *rule,
+ struct prestera_acl_rule_action_entry *entry)
+{
+ struct prestera_acl_rule_action_entry *a_entry;
+
+ a_entry = kmalloc(sizeof(*a_entry), GFP_KERNEL);
+ if (!a_entry)
+ return -ENOMEM;
+
+ memcpy(a_entry, entry, sizeof(*entry));
+ list_add(&a_entry->list, &rule->action_list);
+
+ rule->n_actions++;
+ return 0;
+}
+
+u8 prestera_acl_rule_action_len(struct prestera_acl_rule *rule)
+{
+ return rule->n_actions;
+}
+
+u32 prestera_acl_rule_priority_get(struct prestera_acl_rule *rule)
+{
+ return rule->priority;
+}
+
+void prestera_acl_rule_priority_set(struct prestera_acl_rule *rule,
+ u32 priority)
+{
+ rule->priority = priority;
+}
+
+int prestera_acl_rule_match_add(struct prestera_acl_rule *rule,
+ struct prestera_acl_rule_match_entry *entry)
+{
+ struct prestera_acl_rule_match_entry *m_entry;
+
+ m_entry = kmalloc(sizeof(*m_entry), GFP_KERNEL);
+ if (!m_entry)
+ return -ENOMEM;
+
+ memcpy(m_entry, entry, sizeof(*entry));
+ list_add(&m_entry->list, &rule->match_list);
+
+ rule->n_matches++;
+ return 0;
+}
+
+u8 prestera_acl_rule_match_len(struct prestera_acl_rule *rule)
+{
+ return rule->n_matches;
+}
+
+void prestera_acl_rule_destroy(struct prestera_acl_rule *rule)
+{
+ struct prestera_acl_rule_action_entry *a_entry;
+ struct prestera_acl_rule_match_entry *m_entry;
+ struct list_head *pos, *n;
+
+ list_for_each_safe(pos, n, &rule->match_list) {
+ m_entry = list_entry(pos, typeof(*m_entry), list);
+ list_del(pos);
+ kfree(m_entry);
+ }
+
+ list_for_each_safe(pos, n, &rule->action_list) {
+ a_entry = list_entry(pos, typeof(*a_entry), list);
+ list_del(pos);
+ kfree(a_entry);
+ }
+
+ kfree(rule);
+}
+
+int prestera_acl_rule_add(struct prestera_switch *sw,
+ struct prestera_acl_rule *rule)
+{
+ u32 rule_id;
+ int err;
+
+ /* try to add rule to hash table first */
+ err = rhashtable_insert_fast(&rule->block->ruleset->rule_ht,
+ &rule->ht_node,
+ prestera_acl_rule_ht_params);
+ if (err)
+ return err;
+
+ /* add rule to hw */
+ err = prestera_hw_acl_rule_add(sw, rule, &rule_id);
+ if (err)
+ goto err_rule_add;
+
+ rule->id = rule_id;
+
+ list_add_tail(&rule->list, &sw->acl->rules);
+
+ return 0;
+
+err_rule_add:
+ rhashtable_remove_fast(&rule->block->ruleset->rule_ht, &rule->ht_node,
+ prestera_acl_rule_ht_params);
+ return err;
+}
+
+void prestera_acl_rule_del(struct prestera_switch *sw,
+ struct prestera_acl_rule *rule)
+{
+ rhashtable_remove_fast(&rule->block->ruleset->rule_ht, &rule->ht_node,
+ prestera_acl_rule_ht_params);
+ list_del(&rule->list);
+ prestera_hw_acl_rule_del(sw, rule->id);
+}
+
+int prestera_acl_rule_get_stats(struct prestera_switch *sw,
+ struct prestera_acl_rule *rule,
+ u64 *packets, u64 *bytes, u64 *last_use)
+{
+ u64 current_packets;
+ u64 current_bytes;
+ int err;
+
+ err = prestera_hw_acl_rule_stats_get(sw, rule->id, &current_packets,
+ &current_bytes);
+ if (err)
+ return err;
+
+ *packets = current_packets;
+ *bytes = current_bytes;
+ *last_use = jiffies;
+
+ return 0;
+}
+
+int prestera_acl_init(struct prestera_switch *sw)
+{
+ struct prestera_acl *acl;
+
+ acl = kzalloc(sizeof(*acl), GFP_KERNEL);
+ if (!acl)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&acl->rules);
+ sw->acl = acl;
+ acl->sw = sw;
+
+ return 0;
+}
+
+void prestera_acl_fini(struct prestera_switch *sw)
+{
+ struct prestera_acl *acl = sw->acl;
+
+ WARN_ON(!list_empty(&acl->rules));
+ kfree(acl);
+}
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_acl.h b/drivers/net/ethernet/marvell/prestera/prestera_acl.h
new file mode 100644
index 000000000000..39b7869be659
--- /dev/null
+++ b/drivers/net/ethernet/marvell/prestera/prestera_acl.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
+/* Copyright (c) 2020 Marvell International Ltd. All rights reserved. */
+
+#ifndef _PRESTERA_ACL_H_
+#define _PRESTERA_ACL_H_
+
+enum prestera_acl_rule_match_entry_type {
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_TYPE = 1,
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_DMAC,
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_SMAC,
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_PROTO,
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_PORT,
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_SRC,
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_DST,
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_SRC,
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_DST,
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_RANGE_SRC,
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_RANGE_DST,
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_ID,
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_TPID,
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_TYPE,
+ PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_CODE
+};
+
+enum prestera_acl_rule_action {
+ PRESTERA_ACL_RULE_ACTION_ACCEPT,
+ PRESTERA_ACL_RULE_ACTION_DROP,
+ PRESTERA_ACL_RULE_ACTION_TRAP
+};
+
+struct prestera_switch;
+struct prestera_port;
+struct prestera_acl_rule;
+struct prestera_acl_ruleset;
+
+struct prestera_flow_block_binding {
+ struct list_head list;
+ struct prestera_port *port;
+ int span_id;
+};
+
+struct prestera_flow_block {
+ struct list_head binding_list;
+ struct prestera_switch *sw;
+ struct net *net;
+ struct prestera_acl_ruleset *ruleset;
+ struct flow_block_cb *block_cb;
+};
+
+struct prestera_acl_rule_action_entry {
+ struct list_head list;
+ enum prestera_acl_rule_action id;
+};
+
+struct prestera_acl_rule_match_entry {
+ struct list_head list;
+ enum prestera_acl_rule_match_entry_type type;
+ union {
+ struct {
+ u8 key;
+ u8 mask;
+ } u8;
+ struct {
+ u16 key;
+ u16 mask;
+ } u16;
+ struct {
+ u32 key;
+ u32 mask;
+ } u32;
+ struct {
+ u64 key;
+ u64 mask;
+ } u64;
+ struct {
+ u8 key[ETH_ALEN];
+ u8 mask[ETH_ALEN];
+ } mac;
+ } keymask;
+};
+
+int prestera_acl_init(struct prestera_switch *sw);
+void prestera_acl_fini(struct prestera_switch *sw);
+struct prestera_flow_block *
+prestera_acl_block_create(struct prestera_switch *sw, struct net *net);
+void prestera_acl_block_destroy(struct prestera_flow_block *block);
+struct net *prestera_acl_block_net(struct prestera_flow_block *block);
+struct prestera_switch *prestera_acl_block_sw(struct prestera_flow_block *block);
+int prestera_acl_block_bind(struct prestera_flow_block *block,
+ struct prestera_port *port);
+int prestera_acl_block_unbind(struct prestera_flow_block *block,
+ struct prestera_port *port);
+struct prestera_acl_ruleset *
+prestera_acl_block_ruleset_get(struct prestera_flow_block *block);
+struct prestera_acl_rule *
+prestera_acl_rule_create(struct prestera_flow_block *block,
+ unsigned long cookie);
+u32 prestera_acl_rule_priority_get(struct prestera_acl_rule *rule);
+void prestera_acl_rule_priority_set(struct prestera_acl_rule *rule,
+ u32 priority);
+u16 prestera_acl_rule_ruleset_id_get(const struct prestera_acl_rule *rule);
+struct list_head *
+prestera_acl_rule_action_list_get(struct prestera_acl_rule *rule);
+u8 prestera_acl_rule_action_len(struct prestera_acl_rule *rule);
+u8 prestera_acl_rule_match_len(struct prestera_acl_rule *rule);
+int prestera_acl_rule_action_add(struct prestera_acl_rule *rule,
+ struct prestera_acl_rule_action_entry *entry);
+struct list_head *
+prestera_acl_rule_match_list_get(struct prestera_acl_rule *rule);
+int prestera_acl_rule_match_add(struct prestera_acl_rule *rule,
+ struct prestera_acl_rule_match_entry *entry);
+void prestera_acl_rule_destroy(struct prestera_acl_rule *rule);
+struct prestera_acl_rule *
+prestera_acl_rule_lookup(struct prestera_acl_ruleset *ruleset,
+ unsigned long cookie);
+int prestera_acl_rule_add(struct prestera_switch *sw,
+ struct prestera_acl_rule *rule);
+void prestera_acl_rule_del(struct prestera_switch *sw,
+ struct prestera_acl_rule *rule);
+int prestera_acl_rule_get_stats(struct prestera_switch *sw,
+ struct prestera_acl_rule *rule,
+ u64 *packets, u64 *bytes, u64 *last_use);
+
+#endif /* _PRESTERA_ACL_H_ */
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_devlink.c b/drivers/net/ethernet/marvell/prestera/prestera_devlink.c
index 94c185a0e2b8..d12e21db9fd6 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_devlink.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_devlink.c
@@ -4,6 +4,352 @@
#include <net/devlink.h>
#include "prestera_devlink.h"
+#include "prestera_hw.h"
+
+/* All driver-specific traps must be documented in
+ * Documentation/networking/devlink/prestera.rst
+ */
+enum {
+ DEVLINK_PRESTERA_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX,
+ DEVLINK_PRESTERA_TRAP_ID_ARP_BC,
+ DEVLINK_PRESTERA_TRAP_ID_IS_IS,
+ DEVLINK_PRESTERA_TRAP_ID_OSPF,
+ DEVLINK_PRESTERA_TRAP_ID_IP_BC_MAC,
+ DEVLINK_PRESTERA_TRAP_ID_ROUTER_MC,
+ DEVLINK_PRESTERA_TRAP_ID_VRRP,
+ DEVLINK_PRESTERA_TRAP_ID_DHCP,
+ DEVLINK_PRESTERA_TRAP_ID_MAC_TO_ME,
+ DEVLINK_PRESTERA_TRAP_ID_IPV4_OPTIONS,
+ DEVLINK_PRESTERA_TRAP_ID_IP_DEFAULT_ROUTE,
+ DEVLINK_PRESTERA_TRAP_ID_IP_TO_ME,
+ DEVLINK_PRESTERA_TRAP_ID_IPV4_ICMP_REDIRECT,
+ DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_0,
+ DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_1,
+ DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_2,
+ DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_3,
+ DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_4,
+ DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_5,
+ DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_6,
+ DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_7,
+ DEVLINK_PRESTERA_TRAP_ID_BGP,
+ DEVLINK_PRESTERA_TRAP_ID_SSH,
+ DEVLINK_PRESTERA_TRAP_ID_TELNET,
+ DEVLINK_PRESTERA_TRAP_ID_ICMP,
+ DEVLINK_PRESTERA_TRAP_ID_MET_RED,
+ DEVLINK_PRESTERA_TRAP_ID_IP_SIP_IS_ZERO,
+ DEVLINK_PRESTERA_TRAP_ID_IP_UC_DIP_DA_MISMATCH,
+ DEVLINK_PRESTERA_TRAP_ID_ILLEGAL_IPV4_HDR,
+ DEVLINK_PRESTERA_TRAP_ID_ILLEGAL_IP_ADDR,
+ DEVLINK_PRESTERA_TRAP_ID_INVALID_SA,
+ DEVLINK_PRESTERA_TRAP_ID_LOCAL_PORT,
+ DEVLINK_PRESTERA_TRAP_ID_PORT_NO_VLAN,
+ DEVLINK_PRESTERA_TRAP_ID_RXDMA_DROP,
+};
+
+#define DEVLINK_PRESTERA_TRAP_NAME_ARP_BC \
+ "arp_bc"
+#define DEVLINK_PRESTERA_TRAP_NAME_IS_IS \
+ "is_is"
+#define DEVLINK_PRESTERA_TRAP_NAME_OSPF \
+ "ospf"
+#define DEVLINK_PRESTERA_TRAP_NAME_IP_BC_MAC \
+ "ip_bc_mac"
+#define DEVLINK_PRESTERA_TRAP_NAME_ROUTER_MC \
+ "router_mc"
+#define DEVLINK_PRESTERA_TRAP_NAME_VRRP \
+ "vrrp"
+#define DEVLINK_PRESTERA_TRAP_NAME_DHCP \
+ "dhcp"
+#define DEVLINK_PRESTERA_TRAP_NAME_MAC_TO_ME \
+ "mac_to_me"
+#define DEVLINK_PRESTERA_TRAP_NAME_IPV4_OPTIONS \
+ "ipv4_options"
+#define DEVLINK_PRESTERA_TRAP_NAME_IP_DEFAULT_ROUTE \
+ "ip_default_route"
+#define DEVLINK_PRESTERA_TRAP_NAME_IP_TO_ME \
+ "ip_to_me"
+#define DEVLINK_PRESTERA_TRAP_NAME_IPV4_ICMP_REDIRECT \
+ "ipv4_icmp_redirect"
+#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_0 \
+ "acl_code_0"
+#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_1 \
+ "acl_code_1"
+#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_2 \
+ "acl_code_2"
+#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_3 \
+ "acl_code_3"
+#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_4 \
+ "acl_code_4"
+#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_5 \
+ "acl_code_5"
+#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_6 \
+ "acl_code_6"
+#define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_7 \
+ "acl_code_7"
+#define DEVLINK_PRESTERA_TRAP_NAME_BGP \
+ "bgp"
+#define DEVLINK_PRESTERA_TRAP_NAME_SSH \
+ "ssh"
+#define DEVLINK_PRESTERA_TRAP_NAME_TELNET \
+ "telnet"
+#define DEVLINK_PRESTERA_TRAP_NAME_ICMP \
+ "icmp"
+#define DEVLINK_PRESTERA_TRAP_NAME_RXDMA_DROP \
+ "rxdma_drop"
+#define DEVLINK_PRESTERA_TRAP_NAME_PORT_NO_VLAN \
+ "port_no_vlan"
+#define DEVLINK_PRESTERA_TRAP_NAME_LOCAL_PORT \
+ "local_port"
+#define DEVLINK_PRESTERA_TRAP_NAME_INVALID_SA \
+ "invalid_sa"
+#define DEVLINK_PRESTERA_TRAP_NAME_ILLEGAL_IP_ADDR \
+ "illegal_ip_addr"
+#define DEVLINK_PRESTERA_TRAP_NAME_ILLEGAL_IPV4_HDR \
+ "illegal_ipv4_hdr"
+#define DEVLINK_PRESTERA_TRAP_NAME_IP_UC_DIP_DA_MISMATCH \
+ "ip_uc_dip_da_mismatch"
+#define DEVLINK_PRESTERA_TRAP_NAME_IP_SIP_IS_ZERO \
+ "ip_sip_is_zero"
+#define DEVLINK_PRESTERA_TRAP_NAME_MET_RED \
+ "met_red"
+
+struct prestera_trap {
+ struct devlink_trap trap;
+ u8 cpu_code;
+};
+
+struct prestera_trap_item {
+ enum devlink_trap_action action;
+ void *trap_ctx;
+};
+
+struct prestera_trap_data {
+ struct prestera_switch *sw;
+ struct prestera_trap_item *trap_items_arr;
+ u32 traps_count;
+};
+
+#define PRESTERA_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT
+
+#define PRESTERA_TRAP_CONTROL(_id, _group_id, _action) \
+ DEVLINK_TRAP_GENERIC(CONTROL, _action, _id, \
+ DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
+ PRESTERA_TRAP_METADATA)
+
+#define PRESTERA_TRAP_DRIVER_CONTROL(_id, _group_id) \
+ DEVLINK_TRAP_DRIVER(CONTROL, TRAP, DEVLINK_PRESTERA_TRAP_ID_##_id, \
+ DEVLINK_PRESTERA_TRAP_NAME_##_id, \
+ DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
+ PRESTERA_TRAP_METADATA)
+
+#define PRESTERA_TRAP_EXCEPTION(_id, _group_id) \
+ DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \
+ DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
+ PRESTERA_TRAP_METADATA)
+
+#define PRESTERA_TRAP_DRIVER_EXCEPTION(_id, _group_id) \
+ DEVLINK_TRAP_DRIVER(EXCEPTION, TRAP, DEVLINK_PRESTERA_TRAP_ID_##_id, \
+ DEVLINK_PRESTERA_TRAP_NAME_##_id, \
+ DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
+ PRESTERA_TRAP_METADATA)
+
+#define PRESTERA_TRAP_DRIVER_DROP(_id, _group_id) \
+ DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_PRESTERA_TRAP_ID_##_id, \
+ DEVLINK_PRESTERA_TRAP_NAME_##_id, \
+ DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
+ PRESTERA_TRAP_METADATA)
+
+static const struct devlink_trap_group prestera_trap_groups_arr[] = {
+ /* No policer is associated with following groups (policerid == 0)*/
+ DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(NEIGH_DISCOVERY, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(ACL_TRAP, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(OSPF, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(STP, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(LACP, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(LLDP, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(VRRP, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(DHCP, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(BGP, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(LOCAL_DELIVERY, 0),
+ DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 0),
+};
+
+/* Initialize trap list, as well as associate CPU code with them. */
+static struct prestera_trap prestera_trap_items_arr[] = {
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(ARP_BC, NEIGH_DISCOVERY),
+ .cpu_code = 5,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(IS_IS, LOCAL_DELIVERY),
+ .cpu_code = 13,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(OSPF, OSPF),
+ .cpu_code = 16,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(IP_BC_MAC, LOCAL_DELIVERY),
+ .cpu_code = 19,
+ },
+ {
+ .trap = PRESTERA_TRAP_CONTROL(STP, STP, TRAP),
+ .cpu_code = 26,
+ },
+ {
+ .trap = PRESTERA_TRAP_CONTROL(LACP, LACP, TRAP),
+ .cpu_code = 27,
+ },
+ {
+ .trap = PRESTERA_TRAP_CONTROL(LLDP, LLDP, TRAP),
+ .cpu_code = 28,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(ROUTER_MC, LOCAL_DELIVERY),
+ .cpu_code = 29,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(VRRP, VRRP),
+ .cpu_code = 30,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(DHCP, DHCP),
+ .cpu_code = 33,
+ },
+ {
+ .trap = PRESTERA_TRAP_EXCEPTION(MTU_ERROR, L3_EXCEPTIONS),
+ .cpu_code = 63,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(MAC_TO_ME, LOCAL_DELIVERY),
+ .cpu_code = 65,
+ },
+ {
+ .trap = PRESTERA_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS),
+ .cpu_code = 133,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_EXCEPTION(IPV4_OPTIONS,
+ L3_EXCEPTIONS),
+ .cpu_code = 141,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(IP_DEFAULT_ROUTE,
+ LOCAL_DELIVERY),
+ .cpu_code = 160,
+ },
+ {
+ .trap = PRESTERA_TRAP_CONTROL(LOCAL_ROUTE, LOCAL_DELIVERY,
+ TRAP),
+ .cpu_code = 161,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_EXCEPTION(IPV4_ICMP_REDIRECT,
+ L3_EXCEPTIONS),
+ .cpu_code = 180,
+ },
+ {
+ .trap = PRESTERA_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY,
+ TRAP),
+ .cpu_code = 188,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_0, ACL_TRAP),
+ .cpu_code = 192,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_1, ACL_TRAP),
+ .cpu_code = 193,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_2, ACL_TRAP),
+ .cpu_code = 194,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_3, ACL_TRAP),
+ .cpu_code = 195,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_4, ACL_TRAP),
+ .cpu_code = 196,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_5, ACL_TRAP),
+ .cpu_code = 197,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_6, ACL_TRAP),
+ .cpu_code = 198,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_7, ACL_TRAP),
+ .cpu_code = 199,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(BGP, BGP),
+ .cpu_code = 206,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(SSH, LOCAL_DELIVERY),
+ .cpu_code = 207,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(TELNET, LOCAL_DELIVERY),
+ .cpu_code = 208,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_CONTROL(ICMP, LOCAL_DELIVERY),
+ .cpu_code = 209,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_DROP(RXDMA_DROP, BUFFER_DROPS),
+ .cpu_code = 37,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_DROP(PORT_NO_VLAN, L2_DROPS),
+ .cpu_code = 39,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_DROP(LOCAL_PORT, L2_DROPS),
+ .cpu_code = 56,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_DROP(INVALID_SA, L2_DROPS),
+ .cpu_code = 60,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_DROP(ILLEGAL_IP_ADDR, L3_DROPS),
+ .cpu_code = 136,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_DROP(ILLEGAL_IPV4_HDR, L3_DROPS),
+ .cpu_code = 137,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_DROP(IP_UC_DIP_DA_MISMATCH,
+ L3_DROPS),
+ .cpu_code = 138,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_DROP(IP_SIP_IS_ZERO, L3_DROPS),
+ .cpu_code = 145,
+ },
+ {
+ .trap = PRESTERA_TRAP_DRIVER_DROP(MET_RED, BUFFER_DROPS),
+ .cpu_code = 185,
+ },
+};
+
+static void prestera_devlink_traps_fini(struct prestera_switch *sw);
+
+static int prestera_drop_counter_get(struct devlink *devlink,
+ const struct devlink_trap *trap,
+ u64 *p_drops);
static int prestera_dl_info_get(struct devlink *dl,
struct devlink_info_req *req,
@@ -27,8 +373,21 @@ static int prestera_dl_info_get(struct devlink *dl,
buf);
}
+static int prestera_trap_init(struct devlink *devlink,
+ const struct devlink_trap *trap, void *trap_ctx);
+
+static int prestera_trap_action_set(struct devlink *devlink,
+ const struct devlink_trap *trap,
+ enum devlink_trap_action action,
+ struct netlink_ext_ack *extack);
+
+static int prestera_devlink_traps_register(struct prestera_switch *sw);
+
static const struct devlink_ops prestera_dl_ops = {
.info_get = prestera_dl_info_get,
+ .trap_init = prestera_trap_init,
+ .trap_action_set = prestera_trap_action_set,
+ .trap_drop_counter_get = prestera_drop_counter_get,
};
struct prestera_switch *prestera_devlink_alloc(void)
@@ -53,17 +412,32 @@ int prestera_devlink_register(struct prestera_switch *sw)
int err;
err = devlink_register(dl, sw->dev->dev);
- if (err)
+ if (err) {
dev_err(prestera_dev(sw), "devlink_register failed: %d\n", err);
+ return err;
+ }
- return err;
+ err = prestera_devlink_traps_register(sw);
+ if (err) {
+ devlink_unregister(dl);
+ dev_err(sw->dev->dev, "devlink_traps_register failed: %d\n",
+ err);
+ return err;
+ }
+
+ return 0;
}
void prestera_devlink_unregister(struct prestera_switch *sw)
{
+ struct prestera_trap_data *trap_data = sw->trap_data;
struct devlink *dl = priv_to_devlink(sw);
+ prestera_devlink_traps_fini(sw);
devlink_unregister(dl);
+
+ kfree(trap_data->trap_items_arr);
+ kfree(trap_data);
}
int prestera_devlink_port_register(struct prestera_port *port)
@@ -110,3 +484,155 @@ struct devlink_port *prestera_devlink_get_port(struct net_device *dev)
return &port->dl_port;
}
+
+static int prestera_devlink_traps_register(struct prestera_switch *sw)
+{
+ const u32 groups_count = ARRAY_SIZE(prestera_trap_groups_arr);
+ const u32 traps_count = ARRAY_SIZE(prestera_trap_items_arr);
+ struct devlink *devlink = priv_to_devlink(sw);
+ struct prestera_trap_data *trap_data;
+ struct prestera_trap *prestera_trap;
+ int err, i;
+
+ trap_data = kzalloc(sizeof(*trap_data), GFP_KERNEL);
+ if (!trap_data)
+ return -ENOMEM;
+
+ trap_data->trap_items_arr = kcalloc(traps_count,
+ sizeof(struct prestera_trap_item),
+ GFP_KERNEL);
+ if (!trap_data->trap_items_arr) {
+ err = -ENOMEM;
+ goto err_trap_items_alloc;
+ }
+
+ trap_data->sw = sw;
+ trap_data->traps_count = traps_count;
+ sw->trap_data = trap_data;
+
+ err = devlink_trap_groups_register(devlink, prestera_trap_groups_arr,
+ groups_count);
+ if (err)
+ goto err_groups_register;
+
+ for (i = 0; i < traps_count; i++) {
+ prestera_trap = &prestera_trap_items_arr[i];
+ err = devlink_traps_register(devlink, &prestera_trap->trap, 1,
+ sw);
+ if (err)
+ goto err_trap_register;
+ }
+
+ return 0;
+
+err_trap_register:
+ for (i--; i >= 0; i--) {
+ prestera_trap = &prestera_trap_items_arr[i];
+ devlink_traps_unregister(devlink, &prestera_trap->trap, 1);
+ }
+err_groups_register:
+ kfree(trap_data->trap_items_arr);
+err_trap_items_alloc:
+ kfree(trap_data);
+ return err;
+}
+
+static struct prestera_trap_item *
+prestera_get_trap_item_by_cpu_code(struct prestera_switch *sw, u8 cpu_code)
+{
+ struct prestera_trap_data *trap_data = sw->trap_data;
+ struct prestera_trap *prestera_trap;
+ int i;
+
+ for (i = 0; i < trap_data->traps_count; i++) {
+ prestera_trap = &prestera_trap_items_arr[i];
+ if (cpu_code == prestera_trap->cpu_code)
+ return &trap_data->trap_items_arr[i];
+ }
+
+ return NULL;
+}
+
+void prestera_devlink_trap_report(struct prestera_port *port,
+ struct sk_buff *skb, u8 cpu_code)
+{
+ struct prestera_trap_item *trap_item;
+ struct devlink *devlink;
+
+ devlink = port->dl_port.devlink;
+
+ trap_item = prestera_get_trap_item_by_cpu_code(port->sw, cpu_code);
+ if (unlikely(!trap_item))
+ return;
+
+ devlink_trap_report(devlink, skb, trap_item->trap_ctx,
+ &port->dl_port, NULL);
+}
+
+static struct prestera_trap_item *
+prestera_devlink_trap_item_lookup(struct prestera_switch *sw, u16 trap_id)
+{
+ struct prestera_trap_data *trap_data = sw->trap_data;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(prestera_trap_items_arr); i++) {
+ if (prestera_trap_items_arr[i].trap.id == trap_id)
+ return &trap_data->trap_items_arr[i];
+ }
+
+ return NULL;
+}
+
+static int prestera_trap_init(struct devlink *devlink,
+ const struct devlink_trap *trap, void *trap_ctx)
+{
+ struct prestera_switch *sw = devlink_priv(devlink);
+ struct prestera_trap_item *trap_item;
+
+ trap_item = prestera_devlink_trap_item_lookup(sw, trap->id);
+ if (WARN_ON(!trap_item))
+ return -EINVAL;
+
+ trap_item->trap_ctx = trap_ctx;
+ trap_item->action = trap->init_action;
+
+ return 0;
+}
+
+static int prestera_trap_action_set(struct devlink *devlink,
+ const struct devlink_trap *trap,
+ enum devlink_trap_action action,
+ struct netlink_ext_ack *extack)
+{
+ /* Currently, driver does not support trap action altering */
+ return -EOPNOTSUPP;
+}
+
+static int prestera_drop_counter_get(struct devlink *devlink,
+ const struct devlink_trap *trap,
+ u64 *p_drops)
+{
+ struct prestera_switch *sw = devlink_priv(devlink);
+ enum prestera_hw_cpu_code_cnt_t cpu_code_type =
+ PRESTERA_HW_CPU_CODE_CNT_TYPE_DROP;
+ struct prestera_trap *prestera_trap =
+ container_of(trap, struct prestera_trap, trap);
+
+ return prestera_hw_cpu_code_counters_get(sw, prestera_trap->cpu_code,
+ cpu_code_type, p_drops);
+}
+
+static void prestera_devlink_traps_fini(struct prestera_switch *sw)
+{
+ struct devlink *dl = priv_to_devlink(sw);
+ const struct devlink_trap *trap;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(prestera_trap_items_arr); ++i) {
+ trap = &prestera_trap_items_arr[i].trap;
+ devlink_traps_unregister(dl, trap, 1);
+ }
+
+ devlink_trap_groups_unregister(dl, prestera_trap_groups_arr,
+ ARRAY_SIZE(prestera_trap_groups_arr));
+}
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_devlink.h b/drivers/net/ethernet/marvell/prestera/prestera_devlink.h
index 51bee9f75415..5d73aa9db897 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_devlink.h
+++ b/drivers/net/ethernet/marvell/prestera/prestera_devlink.h
@@ -20,4 +20,7 @@ void prestera_devlink_port_clear(struct prestera_port *port);
struct devlink_port *prestera_devlink_get_port(struct net_device *dev);
+void prestera_devlink_trap_report(struct prestera_port *port,
+ struct sk_buff *skb, u8 cpu_code);
+
#endif /* _PRESTERA_DEVLINK_H_ */
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_dsa.c b/drivers/net/ethernet/marvell/prestera/prestera_dsa.c
index a5e01c7a307b..b7e89c0ca5c0 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_dsa.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_dsa.c
@@ -19,6 +19,7 @@
#define PRESTERA_DSA_W1_EXT_BIT BIT(31)
#define PRESTERA_DSA_W1_CFI_BIT BIT(30)
#define PRESTERA_DSA_W1_PORT_NUM GENMASK(11, 10)
+#define PRESTERA_DSA_W1_MASK_CPU_CODE GENMASK(7, 0)
#define PRESTERA_DSA_W2_EXT_BIT BIT(31)
#define PRESTERA_DSA_W2_PORT_NUM BIT(20)
@@ -74,6 +75,8 @@ int prestera_dsa_parse(struct prestera_dsa *dsa, const u8 *dsa_buf)
(FIELD_GET(PRESTERA_DSA_W1_PORT_NUM, words[1]) << 5) |
(FIELD_GET(PRESTERA_DSA_W2_PORT_NUM, words[2]) << 7);
+ dsa->cpu_code = FIELD_GET(PRESTERA_DSA_W1_MASK_CPU_CODE, words[1]);
+
return 0;
}
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_dsa.h b/drivers/net/ethernet/marvell/prestera/prestera_dsa.h
index 67018629bdd2..c99342f475cf 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_dsa.h
+++ b/drivers/net/ethernet/marvell/prestera/prestera_dsa.h
@@ -27,6 +27,7 @@ struct prestera_dsa {
struct prestera_dsa_vlan vlan;
u32 hw_dev_num;
u32 port_num;
+ u8 cpu_code;
};
int prestera_dsa_parse(struct prestera_dsa *dsa, const u8 *dsa_buf);
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_flow.c b/drivers/net/ethernet/marvell/prestera/prestera_flow.c
new file mode 100644
index 000000000000..c9891e968259
--- /dev/null
+++ b/drivers/net/ethernet/marvell/prestera/prestera_flow.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/* Copyright (c) 2020 Marvell International Ltd. All rights reserved */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+#include "prestera.h"
+#include "prestera_acl.h"
+#include "prestera_flow.h"
+#include "prestera_span.h"
+#include "prestera_flower.h"
+
+static LIST_HEAD(prestera_block_cb_list);
+
+static int prestera_flow_block_mall_cb(struct prestera_flow_block *block,
+ struct tc_cls_matchall_offload *f)
+{
+ switch (f->command) {
+ case TC_CLSMATCHALL_REPLACE:
+ return prestera_span_replace(block, f);
+ case TC_CLSMATCHALL_DESTROY:
+ prestera_span_destroy(block);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int prestera_flow_block_flower_cb(struct prestera_flow_block *block,
+ struct flow_cls_offload *f)
+{
+ if (f->common.chain_index != 0)
+ return -EOPNOTSUPP;
+
+ switch (f->command) {
+ case FLOW_CLS_REPLACE:
+ return prestera_flower_replace(block, f);
+ case FLOW_CLS_DESTROY:
+ prestera_flower_destroy(block, f);
+ return 0;
+ case FLOW_CLS_STATS:
+ return prestera_flower_stats(block, f);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int prestera_flow_block_cb(enum tc_setup_type type,
+ void *type_data, void *cb_priv)
+{
+ struct prestera_flow_block *block = cb_priv;
+
+ switch (type) {
+ case TC_SETUP_CLSFLOWER:
+ return prestera_flow_block_flower_cb(block, type_data);
+ case TC_SETUP_CLSMATCHALL:
+ return prestera_flow_block_mall_cb(block, type_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void prestera_flow_block_release(void *cb_priv)
+{
+ struct prestera_flow_block *block = cb_priv;
+
+ prestera_acl_block_destroy(block);
+}
+
+static struct prestera_flow_block *
+prestera_flow_block_get(struct prestera_switch *sw,
+ struct flow_block_offload *f,
+ bool *register_block)
+{
+ struct prestera_flow_block *block;
+ struct flow_block_cb *block_cb;
+
+ block_cb = flow_block_cb_lookup(f->block,
+ prestera_flow_block_cb, sw);
+ if (!block_cb) {
+ block = prestera_acl_block_create(sw, f->net);
+ if (!block)
+ return ERR_PTR(-ENOMEM);
+
+ block_cb = flow_block_cb_alloc(prestera_flow_block_cb,
+ sw, block,
+ prestera_flow_block_release);
+ if (IS_ERR(block_cb)) {
+ prestera_acl_block_destroy(block);
+ return ERR_CAST(block_cb);
+ }
+
+ block->block_cb = block_cb;
+ *register_block = true;
+ } else {
+ block = flow_block_cb_priv(block_cb);
+ *register_block = false;
+ }
+
+ flow_block_cb_incref(block_cb);
+
+ return block;
+}
+
+static void prestera_flow_block_put(struct prestera_flow_block *block)
+{
+ struct flow_block_cb *block_cb = block->block_cb;
+
+ if (flow_block_cb_decref(block_cb))
+ return;
+
+ flow_block_cb_free(block_cb);
+ prestera_acl_block_destroy(block);
+}
+
+static int prestera_setup_flow_block_bind(struct prestera_port *port,
+ struct flow_block_offload *f)
+{
+ struct prestera_switch *sw = port->sw;
+ struct prestera_flow_block *block;
+ struct flow_block_cb *block_cb;
+ bool register_block;
+ int err;
+
+ block = prestera_flow_block_get(sw, f, &register_block);
+ if (IS_ERR(block))
+ return PTR_ERR(block);
+
+ block_cb = block->block_cb;
+
+ err = prestera_acl_block_bind(block, port);
+ if (err)
+ goto err_block_bind;
+
+ if (register_block) {
+ flow_block_cb_add(block_cb, f);
+ list_add_tail(&block_cb->driver_list, &prestera_block_cb_list);
+ }
+
+ port->flow_block = block;
+ return 0;
+
+err_block_bind:
+ prestera_flow_block_put(block);
+
+ return err;
+}
+
+static void prestera_setup_flow_block_unbind(struct prestera_port *port,
+ struct flow_block_offload *f)
+{
+ struct prestera_switch *sw = port->sw;
+ struct prestera_flow_block *block;
+ struct flow_block_cb *block_cb;
+ int err;
+
+ block_cb = flow_block_cb_lookup(f->block, prestera_flow_block_cb, sw);
+ if (!block_cb)
+ return;
+
+ block = flow_block_cb_priv(block_cb);
+
+ prestera_span_destroy(block);
+
+ err = prestera_acl_block_unbind(block, port);
+ if (err)
+ goto error;
+
+ if (!flow_block_cb_decref(block_cb)) {
+ flow_block_cb_remove(block_cb, f);
+ list_del(&block_cb->driver_list);
+ }
+error:
+ port->flow_block = NULL;
+}
+
+int prestera_flow_block_setup(struct prestera_port *port,
+ struct flow_block_offload *f)
+{
+ if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+ return -EOPNOTSUPP;
+
+ f->driver_block_list = &prestera_block_cb_list;
+
+ switch (f->command) {
+ case FLOW_BLOCK_BIND:
+ return prestera_setup_flow_block_bind(port, f);
+ case FLOW_BLOCK_UNBIND:
+ prestera_setup_flow_block_unbind(port, f);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_flow.h b/drivers/net/ethernet/marvell/prestera/prestera_flow.h
new file mode 100644
index 000000000000..467c7038cace
--- /dev/null
+++ b/drivers/net/ethernet/marvell/prestera/prestera_flow.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
+/* Copyright (c) 2020 Marvell International Ltd. All rights reserved. */
+
+#ifndef _PRESTERA_FLOW_H_
+#define _PRESTERA_FLOW_H_
+
+#include <net/flow_offload.h>
+
+struct prestera_port;
+
+int prestera_flow_block_setup(struct prestera_port *port,
+ struct flow_block_offload *f);
+
+#endif /* _PRESTERA_FLOW_H_ */
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_flower.c b/drivers/net/ethernet/marvell/prestera/prestera_flower.c
new file mode 100644
index 000000000000..e571ba09ec08
--- /dev/null
+++ b/drivers/net/ethernet/marvell/prestera/prestera_flower.c
@@ -0,0 +1,359 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/* Copyright (c) 2020 Marvell International Ltd. All rights reserved */
+
+#include "prestera.h"
+#include "prestera_acl.h"
+#include "prestera_flower.h"
+
+static int prestera_flower_parse_actions(struct prestera_flow_block *block,
+ struct prestera_acl_rule *rule,
+ struct flow_action *flow_action,
+ struct netlink_ext_ack *extack)
+{
+ struct prestera_acl_rule_action_entry a_entry;
+ const struct flow_action_entry *act;
+ int err, i;
+
+ if (!flow_action_has_entries(flow_action))
+ return 0;
+
+ flow_action_for_each(i, act, flow_action) {
+ memset(&a_entry, 0, sizeof(a_entry));
+
+ switch (act->id) {
+ case FLOW_ACTION_ACCEPT:
+ a_entry.id = PRESTERA_ACL_RULE_ACTION_ACCEPT;
+ break;
+ case FLOW_ACTION_DROP:
+ a_entry.id = PRESTERA_ACL_RULE_ACTION_DROP;
+ break;
+ case FLOW_ACTION_TRAP:
+ a_entry.id = PRESTERA_ACL_RULE_ACTION_TRAP;
+ break;
+ default:
+ NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
+ pr_err("Unsupported action\n");
+ return -EOPNOTSUPP;
+ }
+
+ err = prestera_acl_rule_action_add(rule, &a_entry);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int prestera_flower_parse_meta(struct prestera_acl_rule *rule,
+ struct flow_cls_offload *f,
+ struct prestera_flow_block *block)
+{
+ struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
+ struct prestera_acl_rule_match_entry m_entry = {0};
+ struct net_device *ingress_dev;
+ struct flow_match_meta match;
+ struct prestera_port *port;
+
+ flow_rule_match_meta(f_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(prestera_acl_block_net(block),
+ 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 (!prestera_netdev_check(ingress_dev)) {
+ NL_SET_ERR_MSG_MOD(f->common.extack,
+ "Can't match on switchdev ingress port");
+ return -EINVAL;
+ }
+ port = netdev_priv(ingress_dev);
+
+ m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_PORT;
+ m_entry.keymask.u64.key = port->hw_id | ((u64)port->dev_id << 32);
+ m_entry.keymask.u64.mask = ~(u64)0;
+
+ return prestera_acl_rule_match_add(rule, &m_entry);
+}
+
+static int prestera_flower_parse(struct prestera_flow_block *block,
+ struct prestera_acl_rule *rule,
+ struct flow_cls_offload *f)
+{
+ struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
+ struct flow_dissector *dissector = f_rule->match.dissector;
+ struct prestera_acl_rule_match_entry m_entry;
+ u16 n_proto_mask = 0;
+ u16 n_proto_key = 0;
+ u16 addr_type = 0;
+ u8 ip_proto = 0;
+ int err;
+
+ if (dissector->used_keys &
+ ~(BIT(FLOW_DISSECTOR_KEY_META) |
+ BIT(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT(FLOW_DISSECTOR_KEY_ICMP) |
+ BIT(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT(FLOW_DISSECTOR_KEY_VLAN))) {
+ NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported key");
+ return -EOPNOTSUPP;
+ }
+
+ prestera_acl_rule_priority_set(rule, f->common.prio);
+
+ if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_META)) {
+ err = prestera_flower_parse_meta(rule, f, block);
+ if (err)
+ return err;
+ }
+
+ if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_CONTROL)) {
+ struct flow_match_control match;
+
+ flow_rule_match_control(f_rule, &match);
+ addr_type = match.key->addr_type;
+ }
+
+ if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_BASIC)) {
+ struct flow_match_basic match;
+
+ flow_rule_match_basic(f_rule, &match);
+ n_proto_key = ntohs(match.key->n_proto);
+ n_proto_mask = ntohs(match.mask->n_proto);
+
+ if (n_proto_key == ETH_P_ALL) {
+ n_proto_key = 0;
+ n_proto_mask = 0;
+ }
+
+ /* add eth type key,mask */
+ memset(&m_entry, 0, sizeof(m_entry));
+ m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_TYPE;
+ m_entry.keymask.u16.key = n_proto_key;
+ m_entry.keymask.u16.mask = n_proto_mask;
+ err = prestera_acl_rule_match_add(rule, &m_entry);
+ if (err)
+ return err;
+
+ /* add ip proto key,mask */
+ memset(&m_entry, 0, sizeof(m_entry));
+ m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_PROTO;
+ m_entry.keymask.u8.key = match.key->ip_proto;
+ m_entry.keymask.u8.mask = match.mask->ip_proto;
+ err = prestera_acl_rule_match_add(rule, &m_entry);
+ if (err)
+ return err;
+
+ ip_proto = match.key->ip_proto;
+ }
+
+ if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
+ struct flow_match_eth_addrs match;
+
+ flow_rule_match_eth_addrs(f_rule, &match);
+
+ /* add ethernet dst key,mask */
+ memset(&m_entry, 0, sizeof(m_entry));
+ m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_DMAC;
+ memcpy(&m_entry.keymask.mac.key,
+ &match.key->dst, sizeof(match.key->dst));
+ memcpy(&m_entry.keymask.mac.mask,
+ &match.mask->dst, sizeof(match.mask->dst));
+ err = prestera_acl_rule_match_add(rule, &m_entry);
+ if (err)
+ return err;
+
+ /* add ethernet src key,mask */
+ memset(&m_entry, 0, sizeof(m_entry));
+ m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_SMAC;
+ memcpy(&m_entry.keymask.mac.key,
+ &match.key->src, sizeof(match.key->src));
+ memcpy(&m_entry.keymask.mac.mask,
+ &match.mask->src, sizeof(match.mask->src));
+ err = prestera_acl_rule_match_add(rule, &m_entry);
+ if (err)
+ return err;
+ }
+
+ if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
+ struct flow_match_ipv4_addrs match;
+
+ flow_rule_match_ipv4_addrs(f_rule, &match);
+
+ memset(&m_entry, 0, sizeof(m_entry));
+ m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_SRC;
+ memcpy(&m_entry.keymask.u32.key,
+ &match.key->src, sizeof(match.key->src));
+ memcpy(&m_entry.keymask.u32.mask,
+ &match.mask->src, sizeof(match.mask->src));
+ err = prestera_acl_rule_match_add(rule, &m_entry);
+ if (err)
+ return err;
+
+ memset(&m_entry, 0, sizeof(m_entry));
+ m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_DST;
+ memcpy(&m_entry.keymask.u32.key,
+ &match.key->dst, sizeof(match.key->dst));
+ memcpy(&m_entry.keymask.u32.mask,
+ &match.mask->dst, sizeof(match.mask->dst));
+ err = prestera_acl_rule_match_add(rule, &m_entry);
+ if (err)
+ return err;
+ }
+
+ if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_PORTS)) {
+ struct flow_match_ports match;
+
+ if (ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP) {
+ NL_SET_ERR_MSG_MOD
+ (f->common.extack,
+ "Only UDP and TCP keys are supported");
+ return -EINVAL;
+ }
+
+ flow_rule_match_ports(f_rule, &match);
+
+ memset(&m_entry, 0, sizeof(m_entry));
+ m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_SRC;
+ m_entry.keymask.u16.key = ntohs(match.key->src);
+ m_entry.keymask.u16.mask = ntohs(match.mask->src);
+ err = prestera_acl_rule_match_add(rule, &m_entry);
+ if (err)
+ return err;
+
+ memset(&m_entry, 0, sizeof(m_entry));
+ m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_DST;
+ m_entry.keymask.u16.key = ntohs(match.key->dst);
+ m_entry.keymask.u16.mask = ntohs(match.mask->dst);
+ err = prestera_acl_rule_match_add(rule, &m_entry);
+ if (err)
+ return err;
+ }
+
+ if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_VLAN)) {
+ struct flow_match_vlan match;
+
+ flow_rule_match_vlan(f_rule, &match);
+
+ if (match.mask->vlan_id != 0) {
+ memset(&m_entry, 0, sizeof(m_entry));
+ m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_ID;
+ m_entry.keymask.u16.key = match.key->vlan_id;
+ m_entry.keymask.u16.mask = match.mask->vlan_id;
+ err = prestera_acl_rule_match_add(rule, &m_entry);
+ if (err)
+ return err;
+ }
+
+ memset(&m_entry, 0, sizeof(m_entry));
+ m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_TPID;
+ m_entry.keymask.u16.key = ntohs(match.key->vlan_tpid);
+ m_entry.keymask.u16.mask = ntohs(match.mask->vlan_tpid);
+ err = prestera_acl_rule_match_add(rule, &m_entry);
+ if (err)
+ return err;
+ }
+
+ if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ICMP)) {
+ struct flow_match_icmp match;
+
+ flow_rule_match_icmp(f_rule, &match);
+
+ memset(&m_entry, 0, sizeof(m_entry));
+ m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_TYPE;
+ m_entry.keymask.u8.key = match.key->type;
+ m_entry.keymask.u8.mask = match.mask->type;
+ err = prestera_acl_rule_match_add(rule, &m_entry);
+ if (err)
+ return err;
+
+ memset(&m_entry, 0, sizeof(m_entry));
+ m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_CODE;
+ m_entry.keymask.u8.key = match.key->code;
+ m_entry.keymask.u8.mask = match.mask->code;
+ err = prestera_acl_rule_match_add(rule, &m_entry);
+ if (err)
+ return err;
+ }
+
+ return prestera_flower_parse_actions(block, rule,
+ &f->rule->action,
+ f->common.extack);
+}
+
+int prestera_flower_replace(struct prestera_flow_block *block,
+ struct flow_cls_offload *f)
+{
+ struct prestera_switch *sw = prestera_acl_block_sw(block);
+ struct prestera_acl_rule *rule;
+ int err;
+
+ rule = prestera_acl_rule_create(block, f->cookie);
+ if (IS_ERR(rule))
+ return PTR_ERR(rule);
+
+ err = prestera_flower_parse(block, rule, f);
+ if (err)
+ goto err_flower_parse;
+
+ err = prestera_acl_rule_add(sw, rule);
+ if (err)
+ goto err_rule_add;
+
+ return 0;
+
+err_rule_add:
+err_flower_parse:
+ prestera_acl_rule_destroy(rule);
+ return err;
+}
+
+void prestera_flower_destroy(struct prestera_flow_block *block,
+ struct flow_cls_offload *f)
+{
+ struct prestera_acl_rule *rule;
+ struct prestera_switch *sw;
+
+ rule = prestera_acl_rule_lookup(prestera_acl_block_ruleset_get(block),
+ f->cookie);
+ if (rule) {
+ sw = prestera_acl_block_sw(block);
+ prestera_acl_rule_del(sw, rule);
+ prestera_acl_rule_destroy(rule);
+ }
+}
+
+int prestera_flower_stats(struct prestera_flow_block *block,
+ struct flow_cls_offload *f)
+{
+ struct prestera_switch *sw = prestera_acl_block_sw(block);
+ struct prestera_acl_rule *rule;
+ u64 packets;
+ u64 lastuse;
+ u64 bytes;
+ int err;
+
+ rule = prestera_acl_rule_lookup(prestera_acl_block_ruleset_get(block),
+ f->cookie);
+ if (!rule)
+ return -EINVAL;
+
+ err = prestera_acl_rule_get_stats(sw, rule, &packets, &bytes, &lastuse);
+ if (err)
+ return err;
+
+ flow_stats_update(&f->stats, bytes, packets, 0, lastuse,
+ FLOW_ACTION_HW_STATS_IMMEDIATE);
+ return 0;
+}
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_flower.h b/drivers/net/ethernet/marvell/prestera/prestera_flower.h
new file mode 100644
index 000000000000..91e045eec58b
--- /dev/null
+++ b/drivers/net/ethernet/marvell/prestera/prestera_flower.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
+/* Copyright (c) 2020 Marvell International Ltd. All rights reserved. */
+
+#ifndef _PRESTERA_FLOWER_H_
+#define _PRESTERA_FLOWER_H_
+
+#include <net/pkt_cls.h>
+
+struct prestera_flow_block;
+
+int prestera_flower_replace(struct prestera_flow_block *block,
+ struct flow_cls_offload *f);
+void prestera_flower_destroy(struct prestera_flow_block *block,
+ struct flow_cls_offload *f);
+int prestera_flower_stats(struct prestera_flow_block *block,
+ struct flow_cls_offload *f);
+
+#endif /* _PRESTERA_FLOWER_H_ */
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.c b/drivers/net/ethernet/marvell/prestera/prestera_hw.c
index 0424718d5998..c1297859e471 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_hw.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.c
@@ -2,11 +2,13 @@
/* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */
#include <linux/etherdevice.h>
+#include <linux/if_bridge.h>
#include <linux/ethtool.h>
#include <linux/list.h>
#include "prestera.h"
#include "prestera_hw.h"
+#include "prestera_acl.h"
#define PRESTERA_SWITCH_INIT_TIMEOUT_MS (30 * 1000)
@@ -36,11 +38,31 @@ enum prestera_cmd_type_t {
PRESTERA_CMD_TYPE_BRIDGE_PORT_ADD = 0x402,
PRESTERA_CMD_TYPE_BRIDGE_PORT_DELETE = 0x403,
+ PRESTERA_CMD_TYPE_ACL_RULE_ADD = 0x500,
+ PRESTERA_CMD_TYPE_ACL_RULE_DELETE = 0x501,
+ PRESTERA_CMD_TYPE_ACL_RULE_STATS_GET = 0x510,
+ PRESTERA_CMD_TYPE_ACL_RULESET_CREATE = 0x520,
+ PRESTERA_CMD_TYPE_ACL_RULESET_DELETE = 0x521,
+ PRESTERA_CMD_TYPE_ACL_PORT_BIND = 0x530,
+ PRESTERA_CMD_TYPE_ACL_PORT_UNBIND = 0x531,
+
PRESTERA_CMD_TYPE_RXTX_INIT = 0x800,
PRESTERA_CMD_TYPE_RXTX_PORT_INIT = 0x801,
+ PRESTERA_CMD_TYPE_LAG_MEMBER_ADD = 0x900,
+ PRESTERA_CMD_TYPE_LAG_MEMBER_DELETE = 0x901,
+ PRESTERA_CMD_TYPE_LAG_MEMBER_ENABLE = 0x902,
+ PRESTERA_CMD_TYPE_LAG_MEMBER_DISABLE = 0x903,
+
PRESTERA_CMD_TYPE_STP_PORT_SET = 0x1000,
+ PRESTERA_CMD_TYPE_SPAN_GET = 0x1100,
+ PRESTERA_CMD_TYPE_SPAN_BIND = 0x1101,
+ PRESTERA_CMD_TYPE_SPAN_UNBIND = 0x1102,
+ PRESTERA_CMD_TYPE_SPAN_RELEASE = 0x1103,
+
+ PRESTERA_CMD_TYPE_CPU_CODE_COUNTERS_GET = 0x2000,
+
PRESTERA_CMD_TYPE_ACK = 0x10000,
PRESTERA_CMD_TYPE_MAX
};
@@ -86,6 +108,11 @@ enum {
};
enum {
+ PRESTERA_PORT_FLOOD_TYPE_UC = 0,
+ PRESTERA_PORT_FLOOD_TYPE_MC = 1,
+};
+
+enum {
PRESTERA_PORT_GOOD_OCTETS_RCV_CNT,
PRESTERA_PORT_BAD_OCTETS_RCV_CNT,
PRESTERA_PORT_MAC_TRANSMIT_ERR_CNT,
@@ -127,6 +154,12 @@ enum {
PRESTERA_FC_SYMM_ASYMM,
};
+enum {
+ PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT = 0,
+ PRESTERA_HW_FDB_ENTRY_TYPE_LAG = 1,
+ PRESTERA_HW_FDB_ENTRY_TYPE_MAX = 2,
+};
+
struct prestera_fw_event_handler {
struct list_head list;
struct rcu_head rcu;
@@ -168,6 +201,8 @@ struct prestera_msg_switch_init_resp {
u32 port_count;
u32 mtu_max;
u8 switch_id;
+ u8 lag_max;
+ u8 lag_member_max;
};
struct prestera_msg_port_autoneg_param {
@@ -188,6 +223,11 @@ struct prestera_msg_port_mdix_param {
u8 admin_mode;
};
+struct prestera_msg_port_flood_param {
+ u8 type;
+ u8 enable;
+};
+
union prestera_msg_port_param {
u8 admin_state;
u8 oper_state;
@@ -205,6 +245,7 @@ union prestera_msg_port_param {
struct prestera_msg_port_mdix_param mdix;
struct prestera_msg_port_autoneg_param autoneg;
struct prestera_msg_port_cap_param cap;
+ struct prestera_msg_port_flood_param flood_ext;
};
struct prestera_msg_port_attr_req {
@@ -249,8 +290,13 @@ struct prestera_msg_vlan_req {
struct prestera_msg_fdb_req {
struct prestera_msg_cmd cmd;
u8 dest_type;
- u32 port;
- u32 dev;
+ union {
+ struct {
+ u32 port;
+ u32 dev;
+ };
+ u16 lag_id;
+ } dest;
u8 mac[ETH_ALEN];
u16 vid;
u8 dynamic;
@@ -269,6 +315,85 @@ struct prestera_msg_bridge_resp {
u16 bridge;
};
+struct prestera_msg_acl_action {
+ u32 id;
+};
+
+struct prestera_msg_acl_match {
+ u32 type;
+ union {
+ struct {
+ u8 key;
+ u8 mask;
+ } u8;
+ struct {
+ u16 key;
+ u16 mask;
+ } u16;
+ struct {
+ u32 key;
+ u32 mask;
+ } u32;
+ struct {
+ u64 key;
+ u64 mask;
+ } u64;
+ struct {
+ u8 key[ETH_ALEN];
+ u8 mask[ETH_ALEN];
+ } mac;
+ } __packed keymask;
+};
+
+struct prestera_msg_acl_rule_req {
+ struct prestera_msg_cmd cmd;
+ u32 id;
+ u32 priority;
+ u16 ruleset_id;
+ u8 n_actions;
+ u8 n_matches;
+};
+
+struct prestera_msg_acl_rule_resp {
+ struct prestera_msg_ret ret;
+ u32 id;
+};
+
+struct prestera_msg_acl_rule_stats_resp {
+ struct prestera_msg_ret ret;
+ u64 packets;
+ u64 bytes;
+};
+
+struct prestera_msg_acl_ruleset_bind_req {
+ struct prestera_msg_cmd cmd;
+ u32 port;
+ u32 dev;
+ u16 ruleset_id;
+};
+
+struct prestera_msg_acl_ruleset_req {
+ struct prestera_msg_cmd cmd;
+ u16 id;
+};
+
+struct prestera_msg_acl_ruleset_resp {
+ struct prestera_msg_ret ret;
+ u16 id;
+};
+
+struct prestera_msg_span_req {
+ struct prestera_msg_cmd cmd;
+ u32 port;
+ u32 dev;
+ u8 id;
+} __packed __aligned(4);
+
+struct prestera_msg_span_resp {
+ struct prestera_msg_ret ret;
+ u8 id;
+} __packed __aligned(4);
+
struct prestera_msg_stp_req {
struct prestera_msg_cmd cmd;
u32 port;
@@ -293,6 +418,24 @@ struct prestera_msg_rxtx_port_req {
u32 dev;
};
+struct prestera_msg_lag_req {
+ struct prestera_msg_cmd cmd;
+ u32 port;
+ u32 dev;
+ u16 lag_id;
+};
+
+struct prestera_msg_cpu_code_counter_req {
+ struct prestera_msg_cmd cmd;
+ u8 counter_type;
+ u8 code;
+};
+
+struct mvsw_msg_cpu_code_counter_ret {
+ struct prestera_msg_ret ret;
+ u64 packet_count;
+};
+
struct prestera_msg_event {
u16 type;
u16 id;
@@ -315,7 +458,10 @@ union prestera_msg_event_fdb_param {
struct prestera_msg_event_fdb {
struct prestera_msg_event id;
u8 dest_type;
- u32 port_id;
+ union {
+ u32 port_id;
+ u16 lag_id;
+ } dest;
u32 vid;
union prestera_msg_event_fdb_param param;
};
@@ -386,7 +532,19 @@ static int prestera_fw_parse_fdb_evt(void *msg, struct prestera_event *evt)
{
struct prestera_msg_event_fdb *hw_evt = msg;
- evt->fdb_evt.port_id = hw_evt->port_id;
+ switch (hw_evt->dest_type) {
+ case PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT:
+ evt->fdb_evt.type = PRESTERA_FDB_ENTRY_TYPE_REG_PORT;
+ evt->fdb_evt.dest.port_id = hw_evt->dest.port_id;
+ break;
+ case PRESTERA_HW_FDB_ENTRY_TYPE_LAG:
+ evt->fdb_evt.type = PRESTERA_FDB_ENTRY_TYPE_LAG;
+ evt->fdb_evt.dest.lag_id = hw_evt->dest.lag_id;
+ break;
+ default:
+ return -EINVAL;
+ }
+
evt->fdb_evt.vid = hw_evt->vid;
ether_addr_copy(evt->fdb_evt.data.mac, hw_evt->param.mac);
@@ -531,6 +689,8 @@ int prestera_hw_switch_init(struct prestera_switch *sw)
sw->mtu_min = PRESTERA_MIN_MTU;
sw->mtu_max = resp.mtu_max;
sw->id = resp.switch_id;
+ sw->lag_member_max = resp.lag_member_max;
+ sw->lag_max = resp.lag_max;
return 0;
}
@@ -696,6 +856,274 @@ int prestera_hw_port_remote_fc_get(const struct prestera_port *port,
return 0;
}
+int prestera_hw_acl_ruleset_create(struct prestera_switch *sw, u16 *ruleset_id)
+{
+ struct prestera_msg_acl_ruleset_resp resp;
+ struct prestera_msg_acl_ruleset_req req;
+ int err;
+
+ err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_ACL_RULESET_CREATE,
+ &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
+ if (err)
+ return err;
+
+ *ruleset_id = resp.id;
+
+ return 0;
+}
+
+int prestera_hw_acl_ruleset_del(struct prestera_switch *sw, u16 ruleset_id)
+{
+ struct prestera_msg_acl_ruleset_req req = {
+ .id = ruleset_id,
+ };
+
+ return prestera_cmd(sw, PRESTERA_CMD_TYPE_ACL_RULESET_DELETE,
+ &req.cmd, sizeof(req));
+}
+
+static int prestera_hw_acl_actions_put(struct prestera_msg_acl_action *action,
+ struct prestera_acl_rule *rule)
+{
+ struct list_head *a_list = prestera_acl_rule_action_list_get(rule);
+ struct prestera_acl_rule_action_entry *a_entry;
+ int i = 0;
+
+ list_for_each_entry(a_entry, a_list, list) {
+ action[i].id = a_entry->id;
+
+ switch (a_entry->id) {
+ case PRESTERA_ACL_RULE_ACTION_ACCEPT:
+ case PRESTERA_ACL_RULE_ACTION_DROP:
+ case PRESTERA_ACL_RULE_ACTION_TRAP:
+ /* just rule action id, no specific data */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ i++;
+ }
+
+ return 0;
+}
+
+static int prestera_hw_acl_matches_put(struct prestera_msg_acl_match *match,
+ struct prestera_acl_rule *rule)
+{
+ struct list_head *m_list = prestera_acl_rule_match_list_get(rule);
+ struct prestera_acl_rule_match_entry *m_entry;
+ int i = 0;
+
+ list_for_each_entry(m_entry, m_list, list) {
+ match[i].type = m_entry->type;
+
+ switch (m_entry->type) {
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_TYPE:
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_SRC:
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_DST:
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_ID:
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_TPID:
+ match[i].keymask.u16.key = m_entry->keymask.u16.key;
+ match[i].keymask.u16.mask = m_entry->keymask.u16.mask;
+ break;
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_TYPE:
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_CODE:
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_PROTO:
+ match[i].keymask.u8.key = m_entry->keymask.u8.key;
+ match[i].keymask.u8.mask = m_entry->keymask.u8.mask;
+ break;
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_SMAC:
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_DMAC:
+ memcpy(match[i].keymask.mac.key,
+ m_entry->keymask.mac.key,
+ sizeof(match[i].keymask.mac.key));
+ memcpy(match[i].keymask.mac.mask,
+ m_entry->keymask.mac.mask,
+ sizeof(match[i].keymask.mac.mask));
+ break;
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_SRC:
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_DST:
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_RANGE_SRC:
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_RANGE_DST:
+ match[i].keymask.u32.key = m_entry->keymask.u32.key;
+ match[i].keymask.u32.mask = m_entry->keymask.u32.mask;
+ break;
+ case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_PORT:
+ match[i].keymask.u64.key = m_entry->keymask.u64.key;
+ match[i].keymask.u64.mask = m_entry->keymask.u64.mask;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ i++;
+ }
+
+ return 0;
+}
+
+int prestera_hw_acl_rule_add(struct prestera_switch *sw,
+ struct prestera_acl_rule *rule,
+ u32 *rule_id)
+{
+ struct prestera_msg_acl_action *actions;
+ struct prestera_msg_acl_match *matches;
+ struct prestera_msg_acl_rule_resp resp;
+ struct prestera_msg_acl_rule_req *req;
+ u8 n_actions;
+ u8 n_matches;
+ void *buff;
+ u32 size;
+ int err;
+
+ n_actions = prestera_acl_rule_action_len(rule);
+ n_matches = prestera_acl_rule_match_len(rule);
+
+ size = sizeof(*req) + sizeof(*actions) * n_actions +
+ sizeof(*matches) * n_matches;
+
+ buff = kzalloc(size, GFP_KERNEL);
+ if (!buff)
+ return -ENOMEM;
+
+ req = buff;
+ actions = buff + sizeof(*req);
+ matches = buff + sizeof(*req) + sizeof(*actions) * n_actions;
+
+ /* put acl actions into the message */
+ err = prestera_hw_acl_actions_put(actions, rule);
+ if (err)
+ goto free_buff;
+
+ /* put acl matches into the message */
+ err = prestera_hw_acl_matches_put(matches, rule);
+ if (err)
+ goto free_buff;
+
+ req->ruleset_id = prestera_acl_rule_ruleset_id_get(rule);
+ req->priority = prestera_acl_rule_priority_get(rule);
+ req->n_actions = prestera_acl_rule_action_len(rule);
+ req->n_matches = prestera_acl_rule_match_len(rule);
+
+ err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_ACL_RULE_ADD,
+ &req->cmd, size, &resp.ret, sizeof(resp));
+ if (err)
+ goto free_buff;
+
+ *rule_id = resp.id;
+free_buff:
+ kfree(buff);
+ return err;
+}
+
+int prestera_hw_acl_rule_del(struct prestera_switch *sw, u32 rule_id)
+{
+ struct prestera_msg_acl_rule_req req = {
+ .id = rule_id
+ };
+
+ return prestera_cmd(sw, PRESTERA_CMD_TYPE_ACL_RULE_DELETE,
+ &req.cmd, sizeof(req));
+}
+
+int prestera_hw_acl_rule_stats_get(struct prestera_switch *sw, u32 rule_id,
+ u64 *packets, u64 *bytes)
+{
+ struct prestera_msg_acl_rule_stats_resp resp;
+ struct prestera_msg_acl_rule_req req = {
+ .id = rule_id
+ };
+ int err;
+
+ err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_ACL_RULE_STATS_GET,
+ &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
+ if (err)
+ return err;
+
+ *packets = resp.packets;
+ *bytes = resp.bytes;
+
+ return 0;
+}
+
+int prestera_hw_acl_port_bind(const struct prestera_port *port, u16 ruleset_id)
+{
+ struct prestera_msg_acl_ruleset_bind_req req = {
+ .port = port->hw_id,
+ .dev = port->dev_id,
+ .ruleset_id = ruleset_id,
+ };
+
+ return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_ACL_PORT_BIND,
+ &req.cmd, sizeof(req));
+}
+
+int prestera_hw_acl_port_unbind(const struct prestera_port *port,
+ u16 ruleset_id)
+{
+ struct prestera_msg_acl_ruleset_bind_req req = {
+ .port = port->hw_id,
+ .dev = port->dev_id,
+ .ruleset_id = ruleset_id,
+ };
+
+ return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_ACL_PORT_UNBIND,
+ &req.cmd, sizeof(req));
+}
+
+int prestera_hw_span_get(const struct prestera_port *port, u8 *span_id)
+{
+ struct prestera_msg_span_resp resp;
+ struct prestera_msg_span_req req = {
+ .port = port->hw_id,
+ .dev = port->dev_id,
+ };
+ int err;
+
+ err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_SPAN_GET,
+ &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
+ if (err)
+ return err;
+
+ *span_id = resp.id;
+
+ return 0;
+}
+
+int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id)
+{
+ struct prestera_msg_span_req req = {
+ .port = port->hw_id,
+ .dev = port->dev_id,
+ .id = span_id,
+ };
+
+ return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_SPAN_BIND,
+ &req.cmd, sizeof(req));
+}
+
+int prestera_hw_span_unbind(const struct prestera_port *port)
+{
+ struct prestera_msg_span_req req = {
+ .port = port->hw_id,
+ .dev = port->dev_id,
+ };
+
+ return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_SPAN_UNBIND,
+ &req.cmd, sizeof(req));
+}
+
+int prestera_hw_span_release(struct prestera_switch *sw, u8 span_id)
+{
+ struct prestera_msg_span_req req = {
+ .id = span_id
+ };
+
+ return prestera_cmd(sw, PRESTERA_CMD_TYPE_SPAN_RELEASE,
+ &req.cmd, sizeof(req));
+}
+
int prestera_hw_port_type_get(const struct prestera_port *port, u8 *type)
{
struct prestera_msg_port_attr_req req = {
@@ -988,7 +1416,43 @@ int prestera_hw_port_learning_set(struct prestera_port *port, bool enable)
&req.cmd, sizeof(req));
}
-int prestera_hw_port_flood_set(struct prestera_port *port, bool flood)
+static int prestera_hw_port_uc_flood_set(struct prestera_port *port, bool flood)
+{
+ struct prestera_msg_port_attr_req req = {
+ .attr = PRESTERA_CMD_PORT_ATTR_FLOOD,
+ .port = port->hw_id,
+ .dev = port->dev_id,
+ .param = {
+ .flood_ext = {
+ .type = PRESTERA_PORT_FLOOD_TYPE_UC,
+ .enable = flood,
+ }
+ }
+ };
+
+ return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
+ &req.cmd, sizeof(req));
+}
+
+static int prestera_hw_port_mc_flood_set(struct prestera_port *port, bool flood)
+{
+ struct prestera_msg_port_attr_req req = {
+ .attr = PRESTERA_CMD_PORT_ATTR_FLOOD,
+ .port = port->hw_id,
+ .dev = port->dev_id,
+ .param = {
+ .flood_ext = {
+ .type = PRESTERA_PORT_FLOOD_TYPE_MC,
+ .enable = flood,
+ }
+ }
+ };
+
+ return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
+ &req.cmd, sizeof(req));
+}
+
+static int prestera_hw_port_flood_set_v2(struct prestera_port *port, bool flood)
{
struct prestera_msg_port_attr_req req = {
.attr = PRESTERA_CMD_PORT_ATTR_FLOOD,
@@ -1003,6 +1467,41 @@ int prestera_hw_port_flood_set(struct prestera_port *port, bool flood)
&req.cmd, sizeof(req));
}
+int prestera_hw_port_flood_set(struct prestera_port *port, unsigned long mask,
+ unsigned long val)
+{
+ int err;
+
+ if (port->sw->dev->fw_rev.maj <= 2) {
+ if (!(mask & BR_FLOOD))
+ return 0;
+
+ return prestera_hw_port_flood_set_v2(port, val & BR_FLOOD);
+ }
+
+ if (mask & BR_FLOOD) {
+ err = prestera_hw_port_uc_flood_set(port, val & BR_FLOOD);
+ if (err)
+ goto err_uc_flood;
+ }
+
+ if (mask & BR_MCAST_FLOOD) {
+ err = prestera_hw_port_mc_flood_set(port, val & BR_MCAST_FLOOD);
+ if (err)
+ goto err_mc_flood;
+ }
+
+ return 0;
+
+err_mc_flood:
+ prestera_hw_port_mc_flood_set(port, 0);
+err_uc_flood:
+ if (mask & BR_FLOOD)
+ prestera_hw_port_uc_flood_set(port, 0);
+
+ return err;
+}
+
int prestera_hw_vlan_create(struct prestera_switch *sw, u16 vid)
{
struct prestera_msg_vlan_req req = {
@@ -1067,8 +1566,10 @@ int prestera_hw_fdb_add(struct prestera_port *port, const unsigned char *mac,
u16 vid, bool dynamic)
{
struct prestera_msg_fdb_req req = {
- .port = port->hw_id,
- .dev = port->dev_id,
+ .dest = {
+ .dev = port->dev_id,
+ .port = port->hw_id,
+ },
.vid = vid,
.dynamic = dynamic,
};
@@ -1083,8 +1584,10 @@ int prestera_hw_fdb_del(struct prestera_port *port, const unsigned char *mac,
u16 vid)
{
struct prestera_msg_fdb_req req = {
- .port = port->hw_id,
- .dev = port->dev_id,
+ .dest = {
+ .dev = port->dev_id,
+ .port = port->hw_id,
+ },
.vid = vid,
};
@@ -1094,11 +1597,48 @@ int prestera_hw_fdb_del(struct prestera_port *port, const unsigned char *mac,
&req.cmd, sizeof(req));
}
+int prestera_hw_lag_fdb_add(struct prestera_switch *sw, u16 lag_id,
+ const unsigned char *mac, u16 vid, bool dynamic)
+{
+ struct prestera_msg_fdb_req req = {
+ .dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
+ .dest = {
+ .lag_id = lag_id,
+ },
+ .vid = vid,
+ .dynamic = dynamic,
+ };
+
+ ether_addr_copy(req.mac, mac);
+
+ return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_ADD,
+ &req.cmd, sizeof(req));
+}
+
+int prestera_hw_lag_fdb_del(struct prestera_switch *sw, u16 lag_id,
+ const unsigned char *mac, u16 vid)
+{
+ struct prestera_msg_fdb_req req = {
+ .dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
+ .dest = {
+ .lag_id = lag_id,
+ },
+ .vid = vid,
+ };
+
+ ether_addr_copy(req.mac, mac);
+
+ return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_DELETE,
+ &req.cmd, sizeof(req));
+}
+
int prestera_hw_fdb_flush_port(struct prestera_port *port, u32 mode)
{
struct prestera_msg_fdb_req req = {
- .port = port->hw_id,
- .dev = port->dev_id,
+ .dest = {
+ .dev = port->dev_id,
+ .port = port->hw_id,
+ },
.flush_mode = mode,
};
@@ -1121,8 +1661,10 @@ int prestera_hw_fdb_flush_port_vlan(struct prestera_port *port, u16 vid,
u32 mode)
{
struct prestera_msg_fdb_req req = {
- .port = port->hw_id,
- .dev = port->dev_id,
+ .dest = {
+ .dev = port->dev_id,
+ .port = port->hw_id,
+ },
.vid = vid,
.flush_mode = mode,
};
@@ -1131,6 +1673,37 @@ int prestera_hw_fdb_flush_port_vlan(struct prestera_port *port, u16 vid,
&req.cmd, sizeof(req));
}
+int prestera_hw_fdb_flush_lag(struct prestera_switch *sw, u16 lag_id,
+ u32 mode)
+{
+ struct prestera_msg_fdb_req req = {
+ .dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
+ .dest = {
+ .lag_id = lag_id,
+ },
+ .flush_mode = mode,
+ };
+
+ return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_FLUSH_PORT,
+ &req.cmd, sizeof(req));
+}
+
+int prestera_hw_fdb_flush_lag_vlan(struct prestera_switch *sw,
+ u16 lag_id, u16 vid, u32 mode)
+{
+ struct prestera_msg_fdb_req req = {
+ .dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
+ .dest = {
+ .lag_id = lag_id,
+ },
+ .vid = vid,
+ .flush_mode = mode,
+ };
+
+ return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_FLUSH_PORT_VLAN,
+ &req.cmd, sizeof(req));
+}
+
int prestera_hw_bridge_create(struct prestera_switch *sw, u16 *bridge_id)
{
struct prestera_msg_bridge_resp resp;
@@ -1212,6 +1785,68 @@ int prestera_hw_rxtx_port_init(struct prestera_port *port)
&req.cmd, sizeof(req));
}
+int prestera_hw_lag_member_add(struct prestera_port *port, u16 lag_id)
+{
+ struct prestera_msg_lag_req req = {
+ .port = port->hw_id,
+ .dev = port->dev_id,
+ .lag_id = lag_id,
+ };
+
+ return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_LAG_MEMBER_ADD,
+ &req.cmd, sizeof(req));
+}
+
+int prestera_hw_lag_member_del(struct prestera_port *port, u16 lag_id)
+{
+ struct prestera_msg_lag_req req = {
+ .port = port->hw_id,
+ .dev = port->dev_id,
+ .lag_id = lag_id,
+ };
+
+ return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_LAG_MEMBER_DELETE,
+ &req.cmd, sizeof(req));
+}
+
+int prestera_hw_lag_member_enable(struct prestera_port *port, u16 lag_id,
+ bool enable)
+{
+ struct prestera_msg_lag_req req = {
+ .port = port->hw_id,
+ .dev = port->dev_id,
+ .lag_id = lag_id,
+ };
+ u32 cmd;
+
+ cmd = enable ? PRESTERA_CMD_TYPE_LAG_MEMBER_ENABLE :
+ PRESTERA_CMD_TYPE_LAG_MEMBER_DISABLE;
+
+ return prestera_cmd(port->sw, cmd, &req.cmd, sizeof(req));
+}
+
+int
+prestera_hw_cpu_code_counters_get(struct prestera_switch *sw, u8 code,
+ enum prestera_hw_cpu_code_cnt_t counter_type,
+ u64 *packet_count)
+{
+ struct prestera_msg_cpu_code_counter_req req = {
+ .counter_type = counter_type,
+ .code = code,
+ };
+ struct mvsw_msg_cpu_code_counter_ret resp;
+ int err;
+
+ err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_CPU_CODE_COUNTERS_GET,
+ &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
+ if (err)
+ return err;
+
+ *packet_count = resp.packet_count;
+
+ return 0;
+}
+
int prestera_hw_event_handler_register(struct prestera_switch *sw,
enum prestera_event_type type,
prestera_event_cb_t fn,
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.h b/drivers/net/ethernet/marvell/prestera/prestera_hw.h
index b2b5ac95b4e3..546d5fd8240d 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_hw.h
+++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.h
@@ -89,12 +89,18 @@ enum {
PRESTERA_STP_FORWARD,
};
+enum prestera_hw_cpu_code_cnt_t {
+ PRESTERA_HW_CPU_CODE_CNT_TYPE_DROP = 0,
+ PRESTERA_HW_CPU_CODE_CNT_TYPE_TRAP = 1,
+};
+
struct prestera_switch;
struct prestera_port;
struct prestera_port_stats;
struct prestera_port_caps;
enum prestera_event_type;
struct prestera_event;
+struct prestera_acl_rule;
typedef void (*prestera_event_cb_t)
(struct prestera_switch *sw, struct prestera_event *evt, void *arg);
@@ -138,7 +144,8 @@ int prestera_hw_port_mdix_get(const struct prestera_port *port, u8 *status,
int prestera_hw_port_mdix_set(const struct prestera_port *port, u8 mode);
int prestera_hw_port_speed_get(const struct prestera_port *port, u32 *speed);
int prestera_hw_port_learning_set(struct prestera_port *port, bool enable);
-int prestera_hw_port_flood_set(struct prestera_port *port, bool flood);
+int prestera_hw_port_flood_set(struct prestera_port *port, unsigned long mask,
+ unsigned long val);
int prestera_hw_port_accept_frm_type(struct prestera_port *port,
enum prestera_accept_frm_type type);
/* Vlan API */
@@ -165,6 +172,28 @@ int prestera_hw_bridge_delete(struct prestera_switch *sw, u16 bridge_id);
int prestera_hw_bridge_port_add(struct prestera_port *port, u16 bridge_id);
int prestera_hw_bridge_port_delete(struct prestera_port *port, u16 bridge_id);
+/* ACL API */
+int prestera_hw_acl_ruleset_create(struct prestera_switch *sw,
+ u16 *ruleset_id);
+int prestera_hw_acl_ruleset_del(struct prestera_switch *sw,
+ u16 ruleset_id);
+int prestera_hw_acl_rule_add(struct prestera_switch *sw,
+ struct prestera_acl_rule *rule,
+ u32 *rule_id);
+int prestera_hw_acl_rule_del(struct prestera_switch *sw, u32 rule_id);
+int prestera_hw_acl_rule_stats_get(struct prestera_switch *sw,
+ u32 rule_id, u64 *packets, u64 *bytes);
+int prestera_hw_acl_port_bind(const struct prestera_port *port,
+ u16 ruleset_id);
+int prestera_hw_acl_port_unbind(const struct prestera_port *port,
+ u16 ruleset_id);
+
+/* SPAN API */
+int prestera_hw_span_get(const struct prestera_port *port, u8 *span_id);
+int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id);
+int prestera_hw_span_unbind(const struct prestera_port *port);
+int prestera_hw_span_release(struct prestera_switch *sw, u8 span_id);
+
/* Event handlers */
int prestera_hw_event_handler_register(struct prestera_switch *sw,
enum prestera_event_type type,
@@ -179,4 +208,24 @@ int prestera_hw_rxtx_init(struct prestera_switch *sw,
struct prestera_rxtx_params *params);
int prestera_hw_rxtx_port_init(struct prestera_port *port);
+/* LAG API */
+int prestera_hw_lag_member_add(struct prestera_port *port, u16 lag_id);
+int prestera_hw_lag_member_del(struct prestera_port *port, u16 lag_id);
+int prestera_hw_lag_member_enable(struct prestera_port *port, u16 lag_id,
+ bool enable);
+int prestera_hw_lag_fdb_add(struct prestera_switch *sw, u16 lag_id,
+ const unsigned char *mac, u16 vid, bool dynamic);
+int prestera_hw_lag_fdb_del(struct prestera_switch *sw, u16 lag_id,
+ const unsigned char *mac, u16 vid);
+int prestera_hw_fdb_flush_lag(struct prestera_switch *sw, u16 lag_id,
+ u32 mode);
+int prestera_hw_fdb_flush_lag_vlan(struct prestera_switch *sw,
+ u16 lag_id, u16 vid, u32 mode);
+
+/* HW trap/drop counters API */
+int
+prestera_hw_cpu_code_counters_get(struct prestera_switch *sw, u8 code,
+ enum prestera_hw_cpu_code_cnt_t counter_type,
+ u64 *packet_count);
+
#endif /* _PRESTERA_HW_H_ */
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_main.c b/drivers/net/ethernet/marvell/prestera/prestera_main.c
index 2768c78528a5..226f4ff29f6e 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_main.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_main.c
@@ -8,9 +8,13 @@
#include <linux/netdev_features.h>
#include <linux/of.h>
#include <linux/of_net.h>
+#include <linux/if_vlan.h>
#include "prestera.h"
#include "prestera_hw.h"
+#include "prestera_acl.h"
+#include "prestera_flow.h"
+#include "prestera_span.h"
#include "prestera_rxtx.h"
#include "prestera_devlink.h"
#include "prestera_ethtool.h"
@@ -199,10 +203,25 @@ static void prestera_port_stats_update(struct work_struct *work)
msecs_to_jiffies(PRESTERA_STATS_DELAY_MS));
}
+static int prestera_port_setup_tc(struct net_device *dev,
+ enum tc_setup_type type,
+ void *type_data)
+{
+ struct prestera_port *port = netdev_priv(dev);
+
+ switch (type) {
+ case TC_SETUP_BLOCK:
+ return prestera_flow_block_setup(port, type_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static const struct net_device_ops prestera_netdev_ops = {
.ndo_open = prestera_port_open,
.ndo_stop = prestera_port_close,
.ndo_start_xmit = prestera_port_xmit,
+ .ndo_setup_tc = prestera_port_setup_tc,
.ndo_change_mtu = prestera_port_change_mtu,
.ndo_get_stats64 = prestera_port_get_stats64,
.ndo_set_mac_address = prestera_port_set_mac_address,
@@ -281,6 +300,7 @@ static int prestera_port_create(struct prestera_switch *sw, u32 id)
INIT_LIST_HEAD(&port->vlans_list);
port->pvid = PRESTERA_DEFAULT_VID;
+ port->lag = NULL;
port->dev = dev;
port->id = id;
port->sw = sw;
@@ -296,7 +316,7 @@ static int prestera_port_create(struct prestera_switch *sw, u32 id)
if (err)
goto err_dl_port_register;
- dev->features |= NETIF_F_NETNS_LOCAL;
+ dev->features |= NETIF_F_NETNS_LOCAL | NETIF_F_HW_TC;
dev->netdev_ops = &prestera_netdev_ops;
dev->ethtool_ops = &prestera_ethtool_ops;
@@ -472,6 +492,149 @@ static int prestera_switch_set_base_mac_addr(struct prestera_switch *sw)
return prestera_hw_switch_mac_set(sw, sw->base_mac);
}
+struct prestera_lag *prestera_lag_by_id(struct prestera_switch *sw, u16 id)
+{
+ return id < sw->lag_max ? &sw->lags[id] : NULL;
+}
+
+static struct prestera_lag *prestera_lag_by_dev(struct prestera_switch *sw,
+ struct net_device *dev)
+{
+ struct prestera_lag *lag;
+ u16 id;
+
+ for (id = 0; id < sw->lag_max; id++) {
+ lag = &sw->lags[id];
+ if (lag->dev == dev)
+ return lag;
+ }
+
+ return NULL;
+}
+
+static struct prestera_lag *prestera_lag_create(struct prestera_switch *sw,
+ struct net_device *lag_dev)
+{
+ struct prestera_lag *lag = NULL;
+ u16 id;
+
+ for (id = 0; id < sw->lag_max; id++) {
+ lag = &sw->lags[id];
+ if (!lag->dev)
+ break;
+ }
+ if (lag) {
+ INIT_LIST_HEAD(&lag->members);
+ lag->dev = lag_dev;
+ }
+
+ return lag;
+}
+
+static void prestera_lag_destroy(struct prestera_switch *sw,
+ struct prestera_lag *lag)
+{
+ WARN_ON(!list_empty(&lag->members));
+ lag->member_count = 0;
+ lag->dev = NULL;
+}
+
+static int prestera_lag_port_add(struct prestera_port *port,
+ struct net_device *lag_dev)
+{
+ struct prestera_switch *sw = port->sw;
+ struct prestera_lag *lag;
+ int err;
+
+ lag = prestera_lag_by_dev(sw, lag_dev);
+ if (!lag) {
+ lag = prestera_lag_create(sw, lag_dev);
+ if (!lag)
+ return -ENOSPC;
+ }
+
+ if (lag->member_count >= sw->lag_member_max)
+ return -ENOSPC;
+
+ err = prestera_hw_lag_member_add(port, lag->lag_id);
+ if (err) {
+ if (!lag->member_count)
+ prestera_lag_destroy(sw, lag);
+ return err;
+ }
+
+ list_add(&port->lag_member, &lag->members);
+ lag->member_count++;
+ port->lag = lag;
+
+ return 0;
+}
+
+static int prestera_lag_port_del(struct prestera_port *port)
+{
+ struct prestera_switch *sw = port->sw;
+ struct prestera_lag *lag = port->lag;
+ int err;
+
+ if (!lag || !lag->member_count)
+ return -EINVAL;
+
+ err = prestera_hw_lag_member_del(port, lag->lag_id);
+ if (err)
+ return err;
+
+ list_del(&port->lag_member);
+ lag->member_count--;
+ port->lag = NULL;
+
+ if (netif_is_bridge_port(lag->dev)) {
+ struct net_device *br_dev;
+
+ br_dev = netdev_master_upper_dev_get(lag->dev);
+
+ prestera_bridge_port_leave(br_dev, port);
+ }
+
+ if (!lag->member_count)
+ prestera_lag_destroy(sw, lag);
+
+ return 0;
+}
+
+bool prestera_port_is_lag_member(const struct prestera_port *port)
+{
+ return !!port->lag;
+}
+
+u16 prestera_port_lag_id(const struct prestera_port *port)
+{
+ return port->lag->lag_id;
+}
+
+static int prestera_lag_init(struct prestera_switch *sw)
+{
+ u16 id;
+
+ sw->lags = kcalloc(sw->lag_max, sizeof(*sw->lags), GFP_KERNEL);
+ if (!sw->lags)
+ return -ENOMEM;
+
+ for (id = 0; id < sw->lag_max; id++)
+ sw->lags[id].lag_id = id;
+
+ return 0;
+}
+
+static void prestera_lag_fini(struct prestera_switch *sw)
+{
+ u8 idx;
+
+ for (idx = 0; idx < sw->lag_max; idx++)
+ WARN_ON(sw->lags[idx].member_count);
+
+ kfree(sw->lags);
+}
+
bool prestera_netdev_check(const struct net_device *dev)
{
return dev->netdev_ops == &prestera_netdev_ops;
@@ -505,16 +668,119 @@ struct prestera_port *prestera_port_dev_lower_find(struct net_device *dev)
return port;
}
-static int prestera_netdev_port_event(struct net_device *dev,
+static int prestera_netdev_port_lower_event(struct net_device *dev,
+ unsigned long event, void *ptr)
+{
+ struct netdev_notifier_changelowerstate_info *info = ptr;
+ struct netdev_lag_lower_state_info *lower_state_info;
+ struct prestera_port *port = netdev_priv(dev);
+ bool enabled;
+
+ if (!netif_is_lag_port(dev))
+ return 0;
+ if (!prestera_port_is_lag_member(port))
+ return 0;
+
+ lower_state_info = info->lower_state_info;
+ enabled = lower_state_info->link_up && lower_state_info->tx_enabled;
+
+ return prestera_hw_lag_member_enable(port, port->lag->lag_id, enabled);
+}
+
+static bool prestera_lag_master_check(struct net_device *lag_dev,
+ struct netdev_lag_upper_info *info,
+ struct netlink_ext_ack *ext_ack)
+{
+ if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) {
+ NL_SET_ERR_MSG_MOD(ext_ack, "Unsupported LAG Tx type");
+ return false;
+ }
+
+ return true;
+}
+
+static int prestera_netdev_port_event(struct net_device *lower,
+ struct net_device *dev,
unsigned long event, void *ptr)
{
+ struct netdev_notifier_changeupper_info *info = ptr;
+ struct prestera_port *port = netdev_priv(dev);
+ struct netlink_ext_ack *extack;
+ struct net_device *upper;
+
+ extack = netdev_notifier_info_to_extack(&info->info);
+ upper = info->upper_dev;
+
switch (event) {
case NETDEV_PRECHANGEUPPER:
+ if (!netif_is_bridge_master(upper) &&
+ !netif_is_lag_master(upper)) {
+ NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
+ return -EINVAL;
+ }
+
+ if (!info->linking)
+ break;
+
+ if (netdev_has_any_upper_dev(upper)) {
+ NL_SET_ERR_MSG_MOD(extack, "Upper device is already enslaved");
+ return -EINVAL;
+ }
+
+ if (netif_is_lag_master(upper) &&
+ !prestera_lag_master_check(upper, info->upper_info, extack))
+ return -EOPNOTSUPP;
+ if (netif_is_lag_master(upper) && vlan_uses_dev(dev)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Master device is a LAG master and port has a VLAN");
+ return -EINVAL;
+ }
+ if (netif_is_lag_port(dev) && is_vlan_dev(upper) &&
+ !netif_is_lag_master(vlan_dev_real_dev(upper))) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Can not put a VLAN on a LAG port");
+ return -EINVAL;
+ }
+ break;
+
case NETDEV_CHANGEUPPER:
- return prestera_bridge_port_event(dev, event, ptr);
- default:
- return 0;
+ if (netif_is_bridge_master(upper)) {
+ if (info->linking)
+ return prestera_bridge_port_join(upper, port);
+ else
+ prestera_bridge_port_leave(upper, port);
+ } else if (netif_is_lag_master(upper)) {
+ if (info->linking)
+ return prestera_lag_port_add(port, upper);
+ else
+ prestera_lag_port_del(port);
+ }
+ break;
+
+ case NETDEV_CHANGELOWERSTATE:
+ return prestera_netdev_port_lower_event(dev, event, ptr);
}
+
+ return 0;
+}
+
+static int prestera_netdevice_lag_event(struct net_device *lag_dev,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev;
+ struct list_head *iter;
+ int err;
+
+ netdev_for_each_lower_dev(lag_dev, dev, iter) {
+ if (prestera_netdev_check(dev)) {
+ err = prestera_netdev_port_event(lag_dev, dev, event,
+ ptr);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
}
static int prestera_netdev_event_handler(struct notifier_block *nb,
@@ -524,7 +790,9 @@ static int prestera_netdev_event_handler(struct notifier_block *nb,
int err = 0;
if (prestera_netdev_check(dev))
- err = prestera_netdev_port_event(dev, event, ptr);
+ err = prestera_netdev_port_event(dev, dev, event, ptr);
+ else if (netif_is_lag_master(dev))
+ err = prestera_netdevice_lag_event(dev, event, ptr);
return notifier_from_errno(err);
}
@@ -574,10 +842,22 @@ static int prestera_switch_init(struct prestera_switch *sw)
if (err)
goto err_handlers_register;
+ err = prestera_acl_init(sw);
+ if (err)
+ goto err_acl_init;
+
+ err = prestera_span_init(sw);
+ if (err)
+ goto err_span_init;
+
err = prestera_devlink_register(sw);
if (err)
goto err_dl_register;
+ err = prestera_lag_init(sw);
+ if (err)
+ goto err_lag_init;
+
err = prestera_create_ports(sw);
if (err)
goto err_ports_create;
@@ -585,8 +865,14 @@ static int prestera_switch_init(struct prestera_switch *sw)
return 0;
err_ports_create:
+ prestera_lag_fini(sw);
+err_lag_init:
prestera_devlink_unregister(sw);
err_dl_register:
+ prestera_span_fini(sw);
+err_span_init:
+ prestera_acl_fini(sw);
+err_acl_init:
prestera_event_handlers_unregister(sw);
err_handlers_register:
prestera_rxtx_switch_fini(sw);
@@ -602,7 +888,10 @@ err_swdev_register:
static void prestera_switch_fini(struct prestera_switch *sw)
{
prestera_destroy_ports(sw);
+ prestera_lag_fini(sw);
prestera_devlink_unregister(sw);
+ prestera_span_fini(sw);
+ prestera_acl_fini(sw);
prestera_event_handlers_unregister(sw);
prestera_rxtx_switch_fini(sw);
prestera_switchdev_fini(sw);
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_pci.c b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
index 298110119272..a250d394da38 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_pci.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */
+#include <linux/bitfield.h>
#include <linux/circ_buf.h>
#include <linux/device.h>
#include <linux/firmware.h>
@@ -13,9 +14,12 @@
#define PRESTERA_MSG_MAX_SIZE 1500
-#define PRESTERA_SUPP_FW_MAJ_VER 2
+#define PRESTERA_SUPP_FW_MAJ_VER 3
#define PRESTERA_SUPP_FW_MIN_VER 0
+#define PRESTERA_PREV_FW_MAJ_VER 2
+#define PRESTERA_PREV_FW_MIN_VER 0
+
#define PRESTERA_FW_PATH_FMT "mrvl/prestera/mvsw_prestera_fw-v%u.%u.img"
#define PRESTERA_FW_HDR_MAGIC 0x351D9D06
@@ -144,6 +148,11 @@ struct prestera_fw_regs {
/* PRESTERA_CMD_RCV_CTL_REG flags */
#define PRESTERA_CMD_F_REPL_SENT BIT(0)
+#define PRESTERA_FW_EVT_CTL_STATUS_MASK GENMASK(1, 0)
+
+#define PRESTERA_FW_EVT_CTL_STATUS_ON 0
+#define PRESTERA_FW_EVT_CTL_STATUS_OFF 1
+
#define PRESTERA_EVTQ_REG_OFFSET(q, f) \
(PRESTERA_FW_REG_OFFSET(evtq_list) + \
(q) * sizeof(struct prestera_fw_evtq_regs) + \
@@ -166,6 +175,8 @@ struct prestera_fw_evtq {
};
struct prestera_fw {
+ struct prestera_fw_rev rev_supp;
+ const struct firmware *bin;
struct workqueue_struct *wq;
struct prestera_device dev;
u8 __iomem *ldr_regs;
@@ -260,6 +271,15 @@ static u8 prestera_fw_evtq_pick(struct prestera_fw *fw)
return PRESTERA_EVT_QNUM_MAX;
}
+static void prestera_fw_evt_ctl_status_set(struct prestera_fw *fw, u32 val)
+{
+ u32 status = prestera_fw_read(fw, PRESTERA_FW_STATUS_REG);
+
+ u32p_replace_bits(&status, val, PRESTERA_FW_EVT_CTL_STATUS_MASK);
+
+ prestera_fw_write(fw, PRESTERA_FW_STATUS_REG, status);
+}
+
static void prestera_fw_evt_work_fn(struct work_struct *work)
{
struct prestera_fw *fw;
@@ -269,6 +289,8 @@ static void prestera_fw_evt_work_fn(struct work_struct *work)
fw = container_of(work, struct prestera_fw, evt_work);
msg = fw->evt_msg;
+ prestera_fw_evt_ctl_status_set(fw, PRESTERA_FW_EVT_CTL_STATUS_OFF);
+
while ((qid = prestera_fw_evtq_pick(fw)) < PRESTERA_EVT_QNUM_MAX) {
u32 idx;
u32 len;
@@ -288,6 +310,8 @@ static void prestera_fw_evt_work_fn(struct work_struct *work)
if (fw->dev.recv_msg)
fw->dev.recv_msg(&fw->dev, msg, len);
}
+
+ prestera_fw_evt_ctl_status_set(fw, PRESTERA_FW_EVT_CTL_STATUS_ON);
}
static int prestera_fw_wait_reg32(struct prestera_fw *fw, u32 reg, u32 cmp,
@@ -576,25 +600,24 @@ static void prestera_fw_rev_parse(const struct prestera_fw_header *hdr,
static int prestera_fw_rev_check(struct prestera_fw *fw)
{
struct prestera_fw_rev *rev = &fw->dev.fw_rev;
- u16 maj_supp = PRESTERA_SUPP_FW_MAJ_VER;
- u16 min_supp = PRESTERA_SUPP_FW_MIN_VER;
- if (rev->maj == maj_supp && rev->min >= min_supp)
+ if (rev->maj == fw->rev_supp.maj && rev->min >= fw->rev_supp.min)
return 0;
dev_err(fw->dev.dev, "Driver supports FW version only '%u.%u.x'",
- PRESTERA_SUPP_FW_MAJ_VER, PRESTERA_SUPP_FW_MIN_VER);
+ fw->rev_supp.maj, fw->rev_supp.min);
return -EINVAL;
}
-static int prestera_fw_hdr_parse(struct prestera_fw *fw,
- const struct firmware *img)
+static int prestera_fw_hdr_parse(struct prestera_fw *fw)
{
- struct prestera_fw_header *hdr = (struct prestera_fw_header *)img->data;
struct prestera_fw_rev *rev = &fw->dev.fw_rev;
+ struct prestera_fw_header *hdr;
u32 magic;
+ hdr = (struct prestera_fw_header *)fw->bin->data;
+
magic = be32_to_cpu(hdr->magic_number);
if (magic != PRESTERA_FW_HDR_MAGIC) {
dev_err(fw->dev.dev, "FW img hdr magic is invalid");
@@ -609,11 +632,52 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw,
return prestera_fw_rev_check(fw);
}
+static int prestera_fw_get(struct prestera_fw *fw)
+{
+ int ver_maj = PRESTERA_SUPP_FW_MAJ_VER;
+ int ver_min = PRESTERA_SUPP_FW_MIN_VER;
+ char fw_path[128];
+ int err;
+
+pick_fw_ver:
+ snprintf(fw_path, sizeof(fw_path), PRESTERA_FW_PATH_FMT,
+ ver_maj, ver_min);
+
+ err = request_firmware_direct(&fw->bin, fw_path, fw->dev.dev);
+ if (err) {
+ if (ver_maj == PRESTERA_SUPP_FW_MAJ_VER) {
+ ver_maj = PRESTERA_PREV_FW_MAJ_VER;
+ ver_min = PRESTERA_PREV_FW_MIN_VER;
+
+ dev_warn(fw->dev.dev,
+ "missing latest %s firmware, fall-back to previous %u.%u version\n",
+ fw_path, ver_maj, ver_min);
+
+ goto pick_fw_ver;
+ } else {
+ dev_err(fw->dev.dev, "failed to request previous firmware: %s\n",
+ fw_path);
+ return err;
+ }
+ }
+
+ dev_info(fw->dev.dev, "Loading %s ...", fw_path);
+
+ fw->rev_supp.maj = ver_maj;
+ fw->rev_supp.min = ver_min;
+ fw->rev_supp.sub = 0;
+
+ return 0;
+}
+
+static void prestera_fw_put(struct prestera_fw *fw)
+{
+ release_firmware(fw->bin);
+}
+
static int prestera_fw_load(struct prestera_fw *fw)
{
size_t hlen = sizeof(struct prestera_fw_header);
- const struct firmware *f;
- char fw_path[128];
int err;
err = prestera_ldr_wait_reg32(fw, PRESTERA_LDR_READY_REG,
@@ -632,30 +696,24 @@ static int prestera_fw_load(struct prestera_fw *fw)
fw->ldr_wr_idx = 0;
- snprintf(fw_path, sizeof(fw_path), PRESTERA_FW_PATH_FMT,
- PRESTERA_SUPP_FW_MAJ_VER, PRESTERA_SUPP_FW_MIN_VER);
-
- err = request_firmware_direct(&f, fw_path, fw->dev.dev);
- if (err) {
- dev_err(fw->dev.dev, "failed to request firmware file\n");
+ err = prestera_fw_get(fw);
+ if (err)
return err;
- }
- err = prestera_fw_hdr_parse(fw, f);
+ err = prestera_fw_hdr_parse(fw);
if (err) {
dev_err(fw->dev.dev, "FW image header is invalid\n");
goto out_release;
}
- prestera_ldr_write(fw, PRESTERA_LDR_IMG_SIZE_REG, f->size - hlen);
+ prestera_ldr_write(fw, PRESTERA_LDR_IMG_SIZE_REG, fw->bin->size - hlen);
prestera_ldr_write(fw, PRESTERA_LDR_CTL_REG, PRESTERA_LDR_CTL_DL_START);
- dev_info(fw->dev.dev, "Loading %s ...", fw_path);
-
- err = prestera_ldr_fw_send(fw, f->data + hlen, f->size - hlen);
+ err = prestera_ldr_fw_send(fw, fw->bin->data + hlen,
+ fw->bin->size - hlen);
out_release:
- release_firmware(f);
+ prestera_fw_put(fw);
return err;
}
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c b/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c
index 2a13c318048c..73d2eba5262f 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c
@@ -14,6 +14,7 @@
#include "prestera.h"
#include "prestera_hw.h"
#include "prestera_rxtx.h"
+#include "prestera_devlink.h"
#define PRESTERA_SDMA_WAIT_MUL 10
@@ -214,9 +215,10 @@ static struct sk_buff *prestera_sdma_rx_skb_get(struct prestera_sdma *sdma,
static int prestera_rxtx_process_skb(struct prestera_sdma *sdma,
struct sk_buff *skb)
{
- const struct prestera_port *port;
+ struct prestera_port *port;
struct prestera_dsa dsa;
u32 hw_port, dev_id;
+ u8 cpu_code;
int err;
skb_pull(skb, ETH_HLEN);
@@ -259,6 +261,9 @@ static int prestera_rxtx_process_skb(struct prestera_sdma *sdma,
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tci);
}
+ cpu_code = dsa.cpu_code;
+ prestera_devlink_trap_report(port, skb, cpu_code);
+
return 0;
}
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_span.c b/drivers/net/ethernet/marvell/prestera/prestera_span.c
new file mode 100644
index 000000000000..3cafca827bb7
--- /dev/null
+++ b/drivers/net/ethernet/marvell/prestera/prestera_span.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/* Copyright (c) 2020 Marvell International Ltd. All rights reserved */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+#include "prestera.h"
+#include "prestera_hw.h"
+#include "prestera_acl.h"
+#include "prestera_span.h"
+
+struct prestera_span_entry {
+ struct list_head list;
+ struct prestera_port *port;
+ refcount_t ref_count;
+ u8 id;
+};
+
+struct prestera_span {
+ struct prestera_switch *sw;
+ struct list_head entries;
+};
+
+static struct prestera_span_entry *
+prestera_span_entry_create(struct prestera_port *port, u8 span_id)
+{
+ struct prestera_span_entry *entry;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return ERR_PTR(-ENOMEM);
+
+ refcount_set(&entry->ref_count, 1);
+ entry->port = port;
+ entry->id = span_id;
+ list_add_tail(&entry->list, &port->sw->span->entries);
+
+ return entry;
+}
+
+static void prestera_span_entry_del(struct prestera_span_entry *entry)
+{
+ list_del(&entry->list);
+ kfree(entry);
+}
+
+static struct prestera_span_entry *
+prestera_span_entry_find_by_id(struct prestera_span *span, u8 span_id)
+{
+ struct prestera_span_entry *entry;
+
+ list_for_each_entry(entry, &span->entries, list) {
+ if (entry->id == span_id)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static struct prestera_span_entry *
+prestera_span_entry_find_by_port(struct prestera_span *span,
+ struct prestera_port *port)
+{
+ struct prestera_span_entry *entry;
+
+ list_for_each_entry(entry, &span->entries, list) {
+ if (entry->port == port)
+ return entry;
+ }
+
+ return NULL;
+}
+
+static int prestera_span_get(struct prestera_port *port, u8 *span_id)
+{
+ u8 new_span_id;
+ struct prestera_switch *sw = port->sw;
+ struct prestera_span_entry *entry;
+ int err;
+
+ entry = prestera_span_entry_find_by_port(sw->span, port);
+ if (entry) {
+ refcount_inc(&entry->ref_count);
+ *span_id = entry->id;
+ return 0;
+ }
+
+ err = prestera_hw_span_get(port, &new_span_id);
+ if (err)
+ return err;
+
+ entry = prestera_span_entry_create(port, new_span_id);
+ if (IS_ERR(entry)) {
+ prestera_hw_span_release(sw, new_span_id);
+ return PTR_ERR(entry);
+ }
+
+ *span_id = new_span_id;
+ return 0;
+}
+
+static int prestera_span_put(struct prestera_switch *sw, u8 span_id)
+{
+ struct prestera_span_entry *entry;
+ int err;
+
+ entry = prestera_span_entry_find_by_id(sw->span, span_id);
+ if (!entry)
+ return false;
+
+ if (!refcount_dec_and_test(&entry->ref_count))
+ return 0;
+
+ err = prestera_hw_span_release(sw, span_id);
+ if (err)
+ return err;
+
+ prestera_span_entry_del(entry);
+ return 0;
+}
+
+static int prestera_span_rule_add(struct prestera_flow_block_binding *binding,
+ struct prestera_port *to_port)
+{
+ struct prestera_switch *sw = binding->port->sw;
+ u8 span_id;
+ int err;
+
+ if (binding->span_id != PRESTERA_SPAN_INVALID_ID)
+ /* port already in mirroring */
+ return -EEXIST;
+
+ err = prestera_span_get(to_port, &span_id);
+ if (err)
+ return err;
+
+ err = prestera_hw_span_bind(binding->port, span_id);
+ if (err) {
+ prestera_span_put(sw, span_id);
+ return err;
+ }
+
+ binding->span_id = span_id;
+ return 0;
+}
+
+static int prestera_span_rule_del(struct prestera_flow_block_binding *binding)
+{
+ int err;
+
+ err = prestera_hw_span_unbind(binding->port);
+ if (err)
+ return err;
+
+ err = prestera_span_put(binding->port->sw, binding->span_id);
+ if (err)
+ return err;
+
+ binding->span_id = PRESTERA_SPAN_INVALID_ID;
+ return 0;
+}
+
+int prestera_span_replace(struct prestera_flow_block *block,
+ struct tc_cls_matchall_offload *f)
+{
+ struct prestera_flow_block_binding *binding;
+ __be16 protocol = f->common.protocol;
+ struct flow_action_entry *act;
+ struct prestera_port *port;
+ int err;
+
+ if (!flow_offload_has_one_action(&f->rule->action)) {
+ NL_SET_ERR_MSG(f->common.extack,
+ "Only singular actions are supported");
+ return -EOPNOTSUPP;
+ }
+
+ act = &f->rule->action.entries[0];
+
+ if (!prestera_netdev_check(act->dev)) {
+ NL_SET_ERR_MSG(f->common.extack,
+ "Only Marvell Prestera port is supported");
+ return -EINVAL;
+ }
+ if (!tc_cls_can_offload_and_chain0(act->dev, &f->common))
+ return -EOPNOTSUPP;
+ if (act->id != FLOW_ACTION_MIRRED)
+ return -EOPNOTSUPP;
+ if (protocol != htons(ETH_P_ALL))
+ return -EOPNOTSUPP;
+
+ port = netdev_priv(act->dev);
+
+ list_for_each_entry(binding, &block->binding_list, list) {
+ err = prestera_span_rule_add(binding, port);
+ if (err)
+ goto rollback;
+ }
+
+ return 0;
+
+rollback:
+ list_for_each_entry_continue_reverse(binding,
+ &block->binding_list, list)
+ prestera_span_rule_del(binding);
+ return err;
+}
+
+void prestera_span_destroy(struct prestera_flow_block *block)
+{
+ struct prestera_flow_block_binding *binding;
+
+ list_for_each_entry(binding, &block->binding_list, list)
+ prestera_span_rule_del(binding);
+}
+
+int prestera_span_init(struct prestera_switch *sw)
+{
+ struct prestera_span *span;
+
+ span = kzalloc(sizeof(*span), GFP_KERNEL);
+ if (!span)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&span->entries);
+
+ sw->span = span;
+ span->sw = sw;
+
+ return 0;
+}
+
+void prestera_span_fini(struct prestera_switch *sw)
+{
+ struct prestera_span *span = sw->span;
+
+ WARN_ON(!list_empty(&span->entries));
+ kfree(span);
+}
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_span.h b/drivers/net/ethernet/marvell/prestera/prestera_span.h
new file mode 100644
index 000000000000..f0644521f78a
--- /dev/null
+++ b/drivers/net/ethernet/marvell/prestera/prestera_span.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
+/* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved. */
+
+#ifndef _PRESTERA_SPAN_H_
+#define _PRESTERA_SPAN_H_
+
+#include <net/pkt_cls.h>
+
+#define PRESTERA_SPAN_INVALID_ID -1
+
+struct prestera_switch;
+struct prestera_flow_block;
+
+int prestera_span_init(struct prestera_switch *sw);
+void prestera_span_fini(struct prestera_switch *sw);
+int prestera_span_replace(struct prestera_flow_block *block,
+ struct tc_cls_matchall_offload *f);
+void prestera_span_destroy(struct prestera_flow_block *block);
+
+#endif /* _PRESTERA_SPAN_H_ */
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c b/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c
index cb564890a3dc..0b3e8f2db294 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c
@@ -180,6 +180,45 @@ err_port_vlan_alloc:
return ERR_PTR(err);
}
+static int prestera_fdb_add(struct prestera_port *port,
+ const unsigned char *mac, u16 vid, bool dynamic)
+{
+ if (prestera_port_is_lag_member(port))
+ return prestera_hw_lag_fdb_add(port->sw, prestera_port_lag_id(port),
+ mac, vid, dynamic);
+
+ return prestera_hw_fdb_add(port, mac, vid, dynamic);
+}
+
+static int prestera_fdb_del(struct prestera_port *port,
+ const unsigned char *mac, u16 vid)
+{
+ if (prestera_port_is_lag_member(port))
+ return prestera_hw_lag_fdb_del(port->sw, prestera_port_lag_id(port),
+ mac, vid);
+ else
+ return prestera_hw_fdb_del(port, mac, vid);
+}
+
+static int prestera_fdb_flush_port_vlan(struct prestera_port *port, u16 vid,
+ u32 mode)
+{
+ if (prestera_port_is_lag_member(port))
+ return prestera_hw_fdb_flush_lag_vlan(port->sw, prestera_port_lag_id(port),
+ vid, mode);
+ else
+ return prestera_hw_fdb_flush_port_vlan(port, vid, mode);
+}
+
+static int prestera_fdb_flush_port(struct prestera_port *port, u32 mode)
+{
+ if (prestera_port_is_lag_member(port))
+ return prestera_hw_fdb_flush_lag(port->sw, prestera_port_lag_id(port),
+ mode);
+ else
+ return prestera_hw_fdb_flush_port(port, mode);
+}
+
static void
prestera_port_vlan_bridge_leave(struct prestera_port_vlan *port_vlan)
{
@@ -199,11 +238,11 @@ prestera_port_vlan_bridge_leave(struct prestera_port_vlan *port_vlan)
last_port = port_count == 1;
if (last_vlan)
- prestera_hw_fdb_flush_port(port, fdb_flush_mode);
+ prestera_fdb_flush_port(port, fdb_flush_mode);
else if (last_port)
prestera_hw_fdb_flush_vlan(port->sw, vid, fdb_flush_mode);
else
- prestera_hw_fdb_flush_port_vlan(port, vid, fdb_flush_mode);
+ prestera_fdb_flush_port_vlan(port, vid, fdb_flush_mode);
list_del(&port_vlan->br_vlan_head);
prestera_bridge_vlan_put(br_vlan);
@@ -312,11 +351,29 @@ __prestera_bridge_port_by_dev(struct prestera_bridge *bridge,
return NULL;
}
+static int prestera_match_upper_bridge_dev(struct net_device *dev,
+ struct netdev_nested_priv *priv)
+{
+ if (netif_is_bridge_master(dev))
+ priv->data = dev;
+
+ return 0;
+}
+
+static struct net_device *prestera_get_upper_bridge_dev(struct net_device *dev)
+{
+ struct netdev_nested_priv priv = { };
+
+ netdev_walk_all_upper_dev_rcu(dev, prestera_match_upper_bridge_dev,
+ &priv);
+ return priv.data;
+}
+
static struct prestera_bridge_port *
prestera_bridge_port_by_dev(struct prestera_switchdev *swdev,
struct net_device *dev)
{
- struct net_device *br_dev = netdev_master_upper_dev_get(dev);
+ struct net_device *br_dev = prestera_get_upper_bridge_dev(dev);
struct prestera_bridge *bridge;
if (!br_dev)
@@ -404,7 +461,8 @@ prestera_bridge_1d_port_join(struct prestera_bridge_port *br_port)
if (err)
return err;
- err = prestera_hw_port_flood_set(port, br_port->flags & BR_FLOOD);
+ err = prestera_hw_port_flood_set(port, BR_FLOOD | BR_MCAST_FLOOD,
+ br_port->flags);
if (err)
goto err_port_flood_set;
@@ -415,24 +473,23 @@ prestera_bridge_1d_port_join(struct prestera_bridge_port *br_port)
return 0;
err_port_learning_set:
- prestera_hw_port_flood_set(port, false);
err_port_flood_set:
prestera_hw_bridge_port_delete(port, bridge->bridge_id);
return err;
}
-static int prestera_port_bridge_join(struct prestera_port *port,
- struct net_device *upper)
+int prestera_bridge_port_join(struct net_device *br_dev,
+ struct prestera_port *port)
{
struct prestera_switchdev *swdev = port->sw->swdev;
struct prestera_bridge_port *br_port;
struct prestera_bridge *bridge;
int err;
- bridge = prestera_bridge_by_dev(swdev, upper);
+ bridge = prestera_bridge_by_dev(swdev, br_dev);
if (!bridge) {
- bridge = prestera_bridge_create(swdev, upper);
+ bridge = prestera_bridge_create(swdev, br_dev);
if (IS_ERR(bridge))
return PTR_ERR(bridge);
}
@@ -505,14 +562,14 @@ static int prestera_port_vid_stp_set(struct prestera_port *port, u16 vid,
return prestera_hw_vlan_port_stp_set(port, vid, hw_state);
}
-static void prestera_port_bridge_leave(struct prestera_port *port,
- struct net_device *upper)
+void prestera_bridge_port_leave(struct net_device *br_dev,
+ struct prestera_port *port)
{
struct prestera_switchdev *swdev = port->sw->swdev;
struct prestera_bridge_port *br_port;
struct prestera_bridge *bridge;
- bridge = prestera_bridge_by_dev(swdev, upper);
+ bridge = prestera_bridge_by_dev(swdev, br_dev);
if (!bridge)
return;
@@ -528,57 +585,11 @@ static void prestera_port_bridge_leave(struct prestera_port *port,
prestera_bridge_1d_port_leave(br_port);
prestera_hw_port_learning_set(port, false);
- prestera_hw_port_flood_set(port, false);
+ prestera_hw_port_flood_set(port, BR_FLOOD | BR_MCAST_FLOOD, 0);
prestera_port_vid_stp_set(port, PRESTERA_VID_ALL, BR_STATE_FORWARDING);
prestera_bridge_port_put(br_port);
}
-int prestera_bridge_port_event(struct net_device *dev, unsigned long event,
- void *ptr)
-{
- struct netdev_notifier_changeupper_info *info = ptr;
- struct netlink_ext_ack *extack;
- struct prestera_port *port;
- struct net_device *upper;
- int err;
-
- extack = netdev_notifier_info_to_extack(&info->info);
- port = netdev_priv(dev);
- upper = info->upper_dev;
-
- switch (event) {
- case NETDEV_PRECHANGEUPPER:
- if (!netif_is_bridge_master(upper)) {
- NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
- return -EINVAL;
- }
-
- if (!info->linking)
- break;
-
- if (netdev_has_any_upper_dev(upper)) {
- NL_SET_ERR_MSG_MOD(extack, "Upper device is already enslaved");
- return -EINVAL;
- }
- break;
-
- case NETDEV_CHANGEUPPER:
- if (!netif_is_bridge_master(upper))
- break;
-
- if (info->linking) {
- err = prestera_port_bridge_join(port, upper);
- if (err)
- return err;
- } else {
- prestera_port_bridge_leave(port, upper);
- }
- break;
- }
-
- return 0;
-}
-
static int prestera_port_attr_br_flags_set(struct prestera_port *port,
struct net_device *dev,
struct switchdev_brport_flags flags)
@@ -590,11 +601,9 @@ static int prestera_port_attr_br_flags_set(struct prestera_port *port,
if (!br_port)
return 0;
- if (flags.mask & BR_FLOOD) {
- err = prestera_hw_port_flood_set(port, flags.val & BR_FLOOD);
- if (err)
- return err;
- }
+ err = prestera_hw_port_flood_set(port, flags.mask, flags.val);
+ if (err)
+ return err;
if (flags.mask & BR_LEARNING) {
err = prestera_hw_port_learning_set(port,
@@ -699,7 +708,7 @@ err_port_stp_set:
return err;
}
-static int prestera_port_obj_attr_set(struct net_device *dev,
+static int prestera_port_obj_attr_set(struct net_device *dev, const void *ctx,
const struct switchdev_attr *attr,
struct netlink_ext_ack *extack)
{
@@ -771,9 +780,9 @@ static int prestera_port_fdb_set(struct prestera_port *port,
vid = bridge->bridge_id;
if (adding)
- err = prestera_hw_fdb_add(port, fdb_info->addr, vid, false);
+ err = prestera_fdb_add(port, fdb_info->addr, vid, false);
else
- err = prestera_hw_fdb_del(port, fdb_info->addr, vid);
+ err = prestera_fdb_del(port, fdb_info->addr, vid);
return err;
}
@@ -901,7 +910,8 @@ prestera_port_vlan_bridge_join(struct prestera_port_vlan *port_vlan,
if (port_vlan->br_port)
return 0;
- err = prestera_hw_port_flood_set(port, br_port->flags & BR_FLOOD);
+ err = prestera_hw_port_flood_set(port, BR_FLOOD | BR_MCAST_FLOOD,
+ br_port->flags);
if (err)
return err;
@@ -1009,15 +1019,15 @@ static int prestera_port_vlans_add(struct prestera_port *port,
{
bool flag_untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
- struct net_device *dev = vlan->obj.orig_dev;
+ struct net_device *orig_dev = vlan->obj.orig_dev;
struct prestera_bridge_port *br_port;
struct prestera_switch *sw = port->sw;
struct prestera_bridge *bridge;
- if (netif_is_bridge_master(dev))
+ if (netif_is_bridge_master(orig_dev))
return 0;
- br_port = prestera_bridge_port_by_dev(sw->swdev, dev);
+ br_port = prestera_bridge_port_by_dev(sw->swdev, port->dev);
if (WARN_ON(!br_port))
return -EINVAL;
@@ -1030,7 +1040,7 @@ static int prestera_port_vlans_add(struct prestera_port *port,
flag_pvid, extack);
}
-static int prestera_port_obj_add(struct net_device *dev,
+static int prestera_port_obj_add(struct net_device *dev, const void *ctx,
const struct switchdev_obj *obj,
struct netlink_ext_ack *extack)
{
@@ -1049,14 +1059,14 @@ static int prestera_port_obj_add(struct net_device *dev,
static int prestera_port_vlans_del(struct prestera_port *port,
const struct switchdev_obj_port_vlan *vlan)
{
- struct net_device *dev = vlan->obj.orig_dev;
+ struct net_device *orig_dev = vlan->obj.orig_dev;
struct prestera_bridge_port *br_port;
struct prestera_switch *sw = port->sw;
- if (netif_is_bridge_master(dev))
+ if (netif_is_bridge_master(orig_dev))
return -EOPNOTSUPP;
- br_port = prestera_bridge_port_by_dev(sw->swdev, dev);
+ br_port = prestera_bridge_port_by_dev(sw->swdev, port->dev);
if (WARN_ON(!br_port))
return -EINVAL;
@@ -1068,7 +1078,7 @@ static int prestera_port_vlans_del(struct prestera_port *port,
return 0;
}
-static int prestera_port_obj_del(struct net_device *dev,
+static int prestera_port_obj_del(struct net_device *dev, const void *ctx,
const struct switchdev_obj *obj)
{
struct prestera_port *port = netdev_priv(dev);
@@ -1114,10 +1124,26 @@ static void prestera_fdb_event(struct prestera_switch *sw,
struct prestera_event *evt, void *arg)
{
struct switchdev_notifier_fdb_info info;
+ struct net_device *dev = NULL;
struct prestera_port *port;
+ struct prestera_lag *lag;
- port = prestera_find_port(sw, evt->fdb_evt.port_id);
- if (!port)
+ switch (evt->fdb_evt.type) {
+ case PRESTERA_FDB_ENTRY_TYPE_REG_PORT:
+ port = prestera_find_port(sw, evt->fdb_evt.dest.port_id);
+ if (port)
+ dev = port->dev;
+ break;
+ case PRESTERA_FDB_ENTRY_TYPE_LAG:
+ lag = prestera_lag_by_id(sw, evt->fdb_evt.dest.lag_id);
+ if (lag)
+ dev = lag->dev;
+ break;
+ default:
+ return;
+ }
+
+ if (!dev)
return;
info.addr = evt->fdb_evt.data.mac;
@@ -1129,11 +1155,11 @@ static void prestera_fdb_event(struct prestera_switch *sw,
switch (evt->id) {
case PRESTERA_FDB_EVENT_LEARNED:
call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE,
- port->dev, &info.info, NULL);
+ dev, &info.info, NULL);
break;
case PRESTERA_FDB_EVENT_AGED:
call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
- port->dev, &info.info, NULL);
+ dev, &info.info, NULL);
break;
}
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_switchdev.h b/drivers/net/ethernet/marvell/prestera/prestera_switchdev.h
index 606e21d2355b..a91bc35d235f 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_switchdev.h
+++ b/drivers/net/ethernet/marvell/prestera/prestera_switchdev.h
@@ -7,7 +7,10 @@
int prestera_switchdev_init(struct prestera_switch *sw);
void prestera_switchdev_fini(struct prestera_switch *sw);
-int prestera_bridge_port_event(struct net_device *dev, unsigned long event,
- void *ptr);
+int prestera_bridge_port_join(struct net_device *br_dev,
+ struct prestera_port *port);
+
+void prestera_bridge_port_leave(struct net_device *br_dev,
+ struct prestera_port *port);
#endif /* _PRESTERA_SWITCHDEV_H_ */
diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c
index e967867828d8..9b48ae4bac39 100644
--- a/drivers/net/ethernet/marvell/pxa168_eth.c
+++ b/drivers/net/ethernet/marvell/pxa168_eth.c
@@ -1528,6 +1528,7 @@ static int pxa168_eth_remove(struct platform_device *pdev)
struct net_device *dev = platform_get_drvdata(pdev);
struct pxa168_eth_private *pep = netdev_priv(dev);
+ cancel_work_sync(&pep->tx_timeout_task);
if (pep->htpr) {
dma_free_coherent(pep->dev->dev.parent, HASH_ADDR_TABLE_SIZE,
pep->htpr, pep->htpr_dma);
@@ -1539,7 +1540,6 @@ static int pxa168_eth_remove(struct platform_device *pdev)
clk_disable_unprepare(pep->clk);
mdiobus_unregister(pep->smi_bus);
mdiobus_free(pep->smi_bus);
- cancel_work_sync(&pep->tx_timeout_task);
unregister_netdev(dev);
free_netdev(dev);
return 0;
diff --git a/drivers/net/ethernet/marvell/skge.h b/drivers/net/ethernet/marvell/skge.h
index 6928abcec0a3..f72217348eb4 100644
--- a/drivers/net/ethernet/marvell/skge.h
+++ b/drivers/net/ethernet/marvell/skge.h
@@ -263,7 +263,7 @@ enum {
CHIP_ID_YUKON_LP = 0xb2, /* Chip ID for YUKON-LP */
CHIP_ID_YUKON_XL = 0xb3, /* Chip ID for YUKON-2 XL */
CHIP_ID_YUKON_EC = 0xb6, /* Chip ID for YUKON-2 EC */
- CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */
+ CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */
CHIP_REV_YU_LITE_A1 = 3, /* Chip Rev. for YUKON-Lite A1,A2 */
CHIP_REV_YU_LITE_A3 = 7, /* Chip Rev. for YUKON-Lite A3 */
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 222c32367b2c..8b8bff59c8fe 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -471,7 +471,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
adv |= fiber_fc_adv[sky2->flow_mode];
} else {
reg |= GM_GPCR_AU_FCT_DIS;
- reg |= gm_fc_disable[sky2->flow_mode];
+ reg |= gm_fc_disable[sky2->flow_mode];
/* Forward pause packets to GMAC? */
if (sky2->flow_mode & FC_RX)
@@ -1656,16 +1656,16 @@ static void sky2_hw_up(struct sky2_port *sky2)
tx_init(sky2);
/*
- * On dual port PCI-X card, there is an problem where status
+ * On dual port PCI-X card, there is an problem where status
* can be received out of order due to split transactions
*/
if (otherdev && netif_running(otherdev) &&
- (cap = pci_find_capability(hw->pdev, PCI_CAP_ID_PCIX))) {
- u16 cmd;
+ (cap = pci_find_capability(hw->pdev, PCI_CAP_ID_PCIX))) {
+ u16 cmd;
cmd = sky2_pci_read16(hw, cap + PCI_X_CMD);
- cmd &= ~PCI_X_CMD_MAX_SPLIT;
- sky2_pci_write16(hw, cap + PCI_X_CMD, cmd);
+ cmd &= ~PCI_X_CMD_MAX_SPLIT;
+ sky2_pci_write16(hw, cap + PCI_X_CMD, cmd);
}
sky2_mac_init(hw, port);
@@ -1836,8 +1836,8 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
u16 mss;
u8 ctrl;
- if (unlikely(tx_avail(sky2) < tx_le_req(skb)))
- return NETDEV_TX_BUSY;
+ if (unlikely(tx_avail(sky2) < tx_le_req(skb)))
+ return NETDEV_TX_BUSY;
len = skb_headlen(skb);
mapping = dma_map_single(&hw->pdev->dev, skb->data, len,
@@ -1866,9 +1866,9 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
if (!(hw->flags & SKY2_HW_NEW_LE))
mss += ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
- if (mss != sky2->tx_last_mss) {
+ if (mss != sky2->tx_last_mss) {
le = get_tx_le(sky2, &slot);
- le->addr = cpu_to_le32(mss);
+ le->addr = cpu_to_le32(mss);
if (hw->flags & SKY2_HW_NEW_LE)
le->opcode = OP_MSS | HW_OWNER;
@@ -1895,8 +1895,8 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
/* Handle TCP checksum offload */
if (skb->ip_summed == CHECKSUM_PARTIAL) {
/* On Yukon EX (some versions) encoding change. */
- if (hw->flags & SKY2_HW_AUTO_TX_SUM)
- ctrl |= CALSUM; /* auto checksum */
+ if (hw->flags & SKY2_HW_AUTO_TX_SUM)
+ ctrl |= CALSUM; /* auto checksum */
else {
const unsigned offset = skb_transport_offset(skb);
u32 tcpsum;
@@ -2503,7 +2503,7 @@ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
if (length == 0) {
/* don't need this page */
- __skb_frag_unref(frag);
+ __skb_frag_unref(frag, false);
--skb_shinfo(skb)->nr_frags;
} else {
size = min(length, (unsigned) PAGE_SIZE);
@@ -2557,7 +2557,7 @@ nobuf:
static struct sk_buff *sky2_receive(struct net_device *dev,
u16 length, u32 status)
{
- struct sky2_port *sky2 = netdev_priv(dev);
+ struct sky2_port *sky2 = netdev_priv(dev);
struct rx_ring_info *re = sky2->rx_ring + sky2->rx_next;
struct sk_buff *skb = NULL;
u16 count = (status & GMR_FS_LEN) >> 16;
@@ -5063,11 +5063,11 @@ static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!disable_msi && pci_enable_msi(pdev) == 0) {
err = sky2_test_msi(hw);
if (err) {
- pci_disable_msi(pdev);
+ pci_disable_msi(pdev);
if (err != -EOPNOTSUPP)
goto err_out_free_netdev;
}
- }
+ }
netif_napi_add(dev, &hw->napi, sky2_poll, NAPI_WEIGHT);
diff --git a/drivers/net/ethernet/marvell/sky2.h b/drivers/net/ethernet/marvell/sky2.h
index b2dddd8a246c..ddec1627f1a7 100644
--- a/drivers/net/ethernet/marvell/sky2.h
+++ b/drivers/net/ethernet/marvell/sky2.h
@@ -538,8 +538,8 @@ enum {
CHIP_ID_YUKON_EC_U = 0xb4, /* YUKON-2 EC Ultra */
CHIP_ID_YUKON_EX = 0xb5, /* YUKON-2 Extreme */
CHIP_ID_YUKON_EC = 0xb6, /* YUKON-2 EC */
- CHIP_ID_YUKON_FE = 0xb7, /* YUKON-2 FE */
- CHIP_ID_YUKON_FE_P = 0xb8, /* YUKON-2 FE+ */
+ CHIP_ID_YUKON_FE = 0xb7, /* YUKON-2 FE */
+ CHIP_ID_YUKON_FE_P = 0xb8, /* YUKON-2 FE+ */
CHIP_ID_YUKON_SUPR = 0xb9, /* YUKON-2 Supreme */
CHIP_ID_YUKON_UL_2 = 0xba, /* YUKON-2 Ultra 2 */
CHIP_ID_YUKON_OPT = 0xbc, /* YUKON-2 Optima */
@@ -2262,8 +2262,8 @@ struct sky2_port {
#define SKY2_FLAG_AUTO_SPEED 0x0002
#define SKY2_FLAG_AUTO_PAUSE 0x0004
- enum flow_control flow_mode;
- enum flow_control flow_status;
+ enum flow_control flow_mode;
+ enum flow_control flow_status;
#ifdef CONFIG_SKY2_DEBUG
struct dentry *debugfs;
diff --git a/drivers/net/ethernet/mellanox/Kconfig b/drivers/net/ethernet/mellanox/Kconfig
index ff6613a5cdd3..b4f66eb9ddb9 100644
--- a/drivers/net/ethernet/mellanox/Kconfig
+++ b/drivers/net/ethernet/mellanox/Kconfig
@@ -22,5 +22,6 @@ source "drivers/net/ethernet/mellanox/mlx4/Kconfig"
source "drivers/net/ethernet/mellanox/mlx5/core/Kconfig"
source "drivers/net/ethernet/mellanox/mlxsw/Kconfig"
source "drivers/net/ethernet/mellanox/mlxfw/Kconfig"
+source "drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig"
endif # NET_VENDOR_MELLANOX
diff --git a/drivers/net/ethernet/mellanox/Makefile b/drivers/net/ethernet/mellanox/Makefile
index 79773ac331ee..d4b5f547a727 100644
--- a/drivers/net/ethernet/mellanox/Makefile
+++ b/drivers/net/ethernet/mellanox/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_MLX4_CORE) += mlx4/
obj-$(CONFIG_MLX5_CORE) += mlx5/core/
obj-$(CONFIG_MLXSW_CORE) += mlxsw/
obj-$(CONFIG_MLXFW) += mlxfw/
+obj-$(CONFIG_MLXBF_GIGE) += mlxbf_gige/
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index e35e4d7ef4d1..442991d91c15 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -526,7 +526,7 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv,
fail:
while (nr > 0) {
nr--;
- __skb_frag_unref(skb_shinfo(skb)->frags + nr);
+ __skb_frag_unref(skb_shinfo(skb)->frags + nr, false);
}
return 0;
}
@@ -679,9 +679,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
ring = priv->rx_ring[cq_ring];
- /* Protect accesses to: ring->xdp_prog, priv->mac_hash list */
- rcu_read_lock();
- xdp_prog = rcu_dereference(ring->xdp_prog);
+ xdp_prog = rcu_dereference_bh(ring->xdp_prog);
xdp_init_buff(&xdp, priv->frag_info[0].frag_stride, &ring->xdp_rxq);
doorbell_pending = false;
@@ -744,7 +742,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
/* Drop the packet, since HW loopback-ed it */
mac_hash = ethh->h_source[MLX4_EN_MAC_HASH_IDX];
bucket = &priv->mac_hash[mac_hash];
- hlist_for_each_entry_rcu(entry, bucket, hlist) {
+ hlist_for_each_entry_rcu_bh(entry, bucket, hlist) {
if (ether_addr_equal_64bits(entry->mac,
ethh->h_source))
goto next;
@@ -899,8 +897,6 @@ next:
break;
}
- rcu_read_unlock();
-
if (likely(polled)) {
if (doorbell_pending) {
priv->tx_cq[TX_XDP][cq_ring]->xdp_busy = true;
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index a99e71bc7b3c..771b92019af1 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -2660,6 +2660,7 @@ int mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave,
case RES_XRCD:
err = xrcdn_free_res(dev, slave, vhcr->op_modifier, alop,
vhcr->in_param, &vhcr->out_param);
+ break;
default:
break;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
index 461a43f338e6..e1a5a79e27c7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
@@ -12,7 +12,6 @@ config MLX5_CORE
depends on MLXFW || !MLXFW
depends on PTP_1588_CLOCK || !PTP_1588_CLOCK
depends on PCI_HYPERV_INTERFACE || !PCI_HYPERV_INTERFACE
- default n
help
Core driver for low level functionality of the ConnectX-4 and
Connect-IB cards by Mellanox Technologies.
@@ -36,7 +35,6 @@ config MLX5_CORE_EN
depends on NETDEVICES && ETHERNET && INET && PCI && MLX5_CORE
select PAGE_POOL
select DIMLIB
- default n
help
Ethernet support in Mellanox Technologies ConnectX-4 NIC.
@@ -79,6 +77,16 @@ config MLX5_ESWITCH
Legacy SRIOV mode (L2 mac vlan steering based).
Switchdev mode (eswitch offloads).
+config MLX5_BRIDGE
+ bool
+ depends on MLX5_ESWITCH && BRIDGE
+ default y
+ help
+ mlx5 ConnectX offloads support for Ethernet Bridging (BRIDGE).
+ Enable adding representors of mlx5 uplink and VF ports to Bridge and
+ offloading rules for traffic between such ports. Supports VLANs (trunk and
+ access modes).
+
config MLX5_CLS_ACT
bool "MLX5 TC classifier action support"
depends on MLX5_ESWITCH && NET_CLS_ACT
@@ -131,7 +139,6 @@ config MLX5_CORE_EN_DCB
config MLX5_CORE_IPOIB
bool "Mellanox 5th generation network adapters (connectX series) IPoIB offloads support"
depends on MLX5_CORE_EN
- default n
help
MLX5 IPoIB offloads & acceleration support.
@@ -139,7 +146,6 @@ 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
@@ -153,7 +159,6 @@ config MLX5_IPSEC
depends on XFRM_OFFLOAD
depends on INET_ESP_OFFLOAD || INET6_ESP_OFFLOAD
select MLX5_ACCEL
- default n
help
Build IPsec support for the Connect-X family of network cards by Mellanox
Technologies.
@@ -166,7 +171,6 @@ config MLX5_EN_IPSEC
depends on XFRM_OFFLOAD
depends on INET_ESP_OFFLOAD || INET6_ESP_OFFLOAD
depends on MLX5_FPGA_IPSEC || MLX5_IPSEC
- default n
help
Build support for IPsec cryptography-offload acceleration in the NIC.
Note: Support for hardware with this capability needs to be selected
@@ -179,7 +183,6 @@ config MLX5_FPGA_TLS
depends on MLX5_CORE_EN
depends on MLX5_FPGA
select MLX5_EN_TLS
- 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
@@ -194,7 +197,6 @@ config MLX5_TLS
depends on MLX5_CORE_EN
select MLX5_ACCEL
select MLX5_EN_TLS
- default n
help
Build TLS support for the Connect-X family of network cards by Mellanox
Technologies.
@@ -217,7 +219,6 @@ config MLX5_SW_STEERING
config MLX5_SF
bool "Mellanox Technologies subfunction device support using auxiliary device"
depends on MLX5_CORE && MLX5_CORE_EN
- default n
help
Build support for subfuction device in the NIC. A Mellanox subfunction
device can support RDMA, netdevice and vdpa device.
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index a1223e904190..b5072a3a2585 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -14,7 +14,7 @@ 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 port.o mr.o pd.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 \
+ fs_counters.o fs_ft_pool.o rl.o lag.o dev.o events.o wq.o lib/gid.o \
lib/devcom.o lib/pci_vsc.o lib/dm.o diag/fs_tracepoint.o \
diag/fw_tracer.o diag/crdump.o devlink.o diag/rsc_dump.o \
fw_reset.o qos.o
@@ -56,6 +56,7 @@ mlx5_core-$(CONFIG_MLX5_ESWITCH) += esw/acl/helper.o \
esw/acl/ingress_lgcy.o esw/acl/ingress_ofld.o \
esw/devlink_port.o esw/vporttbl.o
mlx5_core-$(CONFIG_MLX5_TC_SAMPLE) += esw/sample.o
+mlx5_core-$(CONFIG_MLX5_BRIDGE) += esw/bridge.o en/rep/bridge.o
mlx5_core-$(CONFIG_MLX5_MPFS) += lib/mpfs.o
mlx5_core-$(CONFIG_VXLAN) += lib/vxlan.o
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
index 44c458443428..d791d351b489 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
@@ -63,6 +63,11 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
err = devlink_info_version_running_put(req, "fw.version", version_str);
if (err)
return err;
+ err = devlink_info_version_running_put(req,
+ DEVLINK_INFO_VERSION_GENERIC_FW,
+ version_str);
+ if (err)
+ return err;
/* no pending version, return running (stored) version */
if (stored_fw == 0)
@@ -74,8 +79,9 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
err = devlink_info_version_stored_put(req, "fw.version", version_str);
if (err)
return err;
-
- return 0;
+ return devlink_info_version_stored_put(req,
+ DEVLINK_INFO_VERSION_GENERIC_FW,
+ version_str);
}
static int mlx5_devlink_reload_fw_activate(struct devlink *devlink, struct netlink_ext_ack *extack)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index b636d63358d2..b1b51bbba054 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -974,7 +974,6 @@ int mlx5e_open_rq(struct mlx5e_params *params, struct mlx5e_rq_param *param,
struct mlx5e_xsk_param *xsk, int node,
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);
int mlx5e_create_rq(struct mlx5e_rq *rq, struct mlx5e_rq_param *param);
void mlx5e_destroy_rq(struct mlx5e_rq *rq);
@@ -1163,6 +1162,13 @@ mlx5e_calc_max_nch(struct mlx5e_priv *priv, const struct mlx5e_profile *profile)
return priv->netdev->num_rx_queues / max_t(u8, profile->rq_groups, 1);
}
+static inline bool
+mlx5e_tx_mpwqe_supported(struct mlx5_core_dev *mdev)
+{
+ return !is_kdump_kernel() &&
+ MLX5_CAP_ETH(mdev, enhanced_multi_pkt_send_wqe);
+}
+
int mlx5e_priv_init(struct mlx5e_priv *priv,
struct net_device *netdev,
struct mlx5_core_dev *mdev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
index f410c1268422..150c8e82c738 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
@@ -201,7 +201,7 @@ int mlx5e_validate_params(struct mlx5_core_dev *mdev, struct mlx5e_params *param
static struct dim_cq_moder mlx5e_get_def_tx_moderation(u8 cq_period_mode)
{
- struct 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;
@@ -214,7 +214,7 @@ static struct dim_cq_moder mlx5e_get_def_tx_moderation(u8 cq_period_mode)
static struct dim_cq_moder mlx5e_get_def_rx_moderation(u8 cq_period_mode)
{
- struct 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;
@@ -614,7 +614,7 @@ static u8 mlx5e_build_icosq_log_wq_sz(struct mlx5e_params *params,
static u8 mlx5e_build_async_icosq_log_wq_sz(struct mlx5_core_dev *mdev)
{
- if (mlx5_accel_is_ktls_rx(mdev))
+ if (mlx5e_accel_is_ktls_rx(mdev))
return MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE;
return MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE;
@@ -643,7 +643,7 @@ static void mlx5e_build_async_icosq_param(struct mlx5_core_dev *mdev,
mlx5e_build_sq_param_common(mdev, param);
param->stop_room = mlx5e_stop_room_for_wqe(1); /* for XSK NOP */
- param->is_tls = mlx5_accel_is_ktls_rx(mdev);
+ param->is_tls = mlx5e_accel_is_ktls_rx(mdev);
if (param->is_tls)
param->stop_room += mlx5e_stop_room_for_wqe(1); /* for TLS RX resync NOP */
MLX5_SET(sqc, sqc, reg_umr, MLX5_CAP_ETH(mdev, reg_umr_sq));
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c
new file mode 100644
index 000000000000..3c0032c9647c
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c
@@ -0,0 +1,427 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2021 Mellanox Technologies. */
+
+#include <linux/netdevice.h>
+#include <linux/if_bridge.h>
+#include <net/netevent.h>
+#include <net/switchdev.h>
+#include "bridge.h"
+#include "esw/bridge.h"
+#include "en_rep.h"
+
+#define MLX5_ESW_BRIDGE_UPDATE_INTERVAL 1000
+
+struct mlx5_bridge_switchdev_fdb_work {
+ struct work_struct work;
+ struct switchdev_notifier_fdb_info fdb_info;
+ struct net_device *dev;
+ bool add;
+};
+
+static int mlx5_esw_bridge_port_changeupper(struct notifier_block *nb, void *ptr)
+{
+ struct mlx5_esw_bridge_offloads *br_offloads = container_of(nb,
+ struct mlx5_esw_bridge_offloads,
+ netdev_nb);
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct netdev_notifier_changeupper_info *info = ptr;
+ struct netlink_ext_ack *extack;
+ struct mlx5e_rep_priv *rpriv;
+ struct mlx5_eswitch *esw;
+ struct mlx5_vport *vport;
+ struct net_device *upper;
+ struct mlx5e_priv *priv;
+ u16 vport_num;
+
+ if (!mlx5e_eswitch_rep(dev))
+ return 0;
+
+ upper = info->upper_dev;
+ if (!netif_is_bridge_master(upper))
+ return 0;
+
+ esw = br_offloads->esw;
+ priv = netdev_priv(dev);
+ if (esw != priv->mdev->priv.eswitch)
+ return 0;
+
+ rpriv = priv->ppriv;
+ vport_num = rpriv->rep->vport;
+ vport = mlx5_eswitch_get_vport(esw, vport_num);
+ if (IS_ERR(vport))
+ return PTR_ERR(vport);
+
+ extack = netdev_notifier_info_to_extack(&info->info);
+
+ return info->linking ?
+ mlx5_esw_bridge_vport_link(upper->ifindex, br_offloads, vport, extack) :
+ mlx5_esw_bridge_vport_unlink(upper->ifindex, br_offloads, vport, extack);
+}
+
+static int mlx5_esw_bridge_switchdev_port_event(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ int err = 0;
+
+ switch (event) {
+ case NETDEV_PRECHANGEUPPER:
+ break;
+
+ case NETDEV_CHANGEUPPER:
+ err = mlx5_esw_bridge_port_changeupper(nb, ptr);
+ break;
+ }
+
+ return notifier_from_errno(err);
+}
+
+static int mlx5_esw_bridge_port_obj_add(struct net_device *dev,
+ const void *ctx,
+ const struct switchdev_obj *obj,
+ struct netlink_ext_ack *extack)
+{
+ const struct switchdev_obj_port_vlan *vlan;
+ struct mlx5e_rep_priv *rpriv;
+ struct mlx5_eswitch *esw;
+ struct mlx5_vport *vport;
+ struct mlx5e_priv *priv;
+ u16 vport_num;
+ int err = 0;
+
+ priv = netdev_priv(dev);
+ rpriv = priv->ppriv;
+ vport_num = rpriv->rep->vport;
+ esw = priv->mdev->priv.eswitch;
+ vport = mlx5_eswitch_get_vport(esw, vport_num);
+ if (IS_ERR(vport))
+ return PTR_ERR(vport);
+
+ switch (obj->id) {
+ case SWITCHDEV_OBJ_ID_PORT_VLAN:
+ vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
+ err = mlx5_esw_bridge_port_vlan_add(vlan->vid, vlan->flags, esw, vport, extack);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return err;
+}
+
+static int mlx5_esw_bridge_port_obj_del(struct net_device *dev,
+ const void *ctx,
+ const struct switchdev_obj *obj)
+{
+ const struct switchdev_obj_port_vlan *vlan;
+ struct mlx5e_rep_priv *rpriv;
+ struct mlx5_eswitch *esw;
+ struct mlx5_vport *vport;
+ struct mlx5e_priv *priv;
+ u16 vport_num;
+
+ priv = netdev_priv(dev);
+ rpriv = priv->ppriv;
+ vport_num = rpriv->rep->vport;
+ esw = priv->mdev->priv.eswitch;
+ vport = mlx5_eswitch_get_vport(esw, vport_num);
+ if (IS_ERR(vport))
+ return PTR_ERR(vport);
+
+ switch (obj->id) {
+ case SWITCHDEV_OBJ_ID_PORT_VLAN:
+ vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
+ mlx5_esw_bridge_port_vlan_del(vlan->vid, esw, vport);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int mlx5_esw_bridge_port_obj_attr_set(struct net_device *dev,
+ const void *ctx,
+ const struct switchdev_attr *attr,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx5e_rep_priv *rpriv;
+ struct mlx5_eswitch *esw;
+ struct mlx5_vport *vport;
+ struct mlx5e_priv *priv;
+ u16 vport_num;
+ int err = 0;
+
+ priv = netdev_priv(dev);
+ rpriv = priv->ppriv;
+ vport_num = rpriv->rep->vport;
+ esw = priv->mdev->priv.eswitch;
+ vport = mlx5_eswitch_get_vport(esw, vport_num);
+ if (IS_ERR(vport))
+ return PTR_ERR(vport);
+
+ switch (attr->id) {
+ case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
+ if (attr->u.brport_flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD)) {
+ NL_SET_ERR_MSG_MOD(extack, "Flag is not supported");
+ err = -EINVAL;
+ }
+ break;
+ case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
+ break;
+ case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
+ err = mlx5_esw_bridge_ageing_time_set(attr->u.ageing_time, esw, vport);
+ break;
+ case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
+ err = mlx5_esw_bridge_vlan_filtering_set(attr->u.vlan_filtering, esw, vport);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ }
+
+ return err;
+}
+
+static int mlx5_esw_bridge_event_blocking(struct notifier_block *unused,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+ int err;
+
+ switch (event) {
+ case SWITCHDEV_PORT_OBJ_ADD:
+ err = switchdev_handle_port_obj_add(dev, ptr,
+ mlx5e_eswitch_rep,
+ mlx5_esw_bridge_port_obj_add);
+ break;
+ case SWITCHDEV_PORT_OBJ_DEL:
+ err = switchdev_handle_port_obj_del(dev, ptr,
+ mlx5e_eswitch_rep,
+ mlx5_esw_bridge_port_obj_del);
+ break;
+ case SWITCHDEV_PORT_ATTR_SET:
+ err = switchdev_handle_port_attr_set(dev, ptr,
+ mlx5e_eswitch_rep,
+ mlx5_esw_bridge_port_obj_attr_set);
+ break;
+ default:
+ err = 0;
+ }
+
+ return notifier_from_errno(err);
+}
+
+static void
+mlx5_esw_bridge_cleanup_switchdev_fdb_work(struct mlx5_bridge_switchdev_fdb_work *fdb_work)
+{
+ dev_put(fdb_work->dev);
+ kfree(fdb_work->fdb_info.addr);
+ kfree(fdb_work);
+}
+
+static void mlx5_esw_bridge_switchdev_fdb_event_work(struct work_struct *work)
+{
+ struct mlx5_bridge_switchdev_fdb_work *fdb_work =
+ container_of(work, struct mlx5_bridge_switchdev_fdb_work, work);
+ struct switchdev_notifier_fdb_info *fdb_info =
+ &fdb_work->fdb_info;
+ struct net_device *dev = fdb_work->dev;
+ struct mlx5e_rep_priv *rpriv;
+ struct mlx5_eswitch *esw;
+ struct mlx5_vport *vport;
+ struct mlx5e_priv *priv;
+ u16 vport_num;
+
+ rtnl_lock();
+
+ priv = netdev_priv(dev);
+ rpriv = priv->ppriv;
+ vport_num = rpriv->rep->vport;
+ esw = priv->mdev->priv.eswitch;
+ vport = mlx5_eswitch_get_vport(esw, vport_num);
+ if (IS_ERR(vport))
+ goto out;
+
+ if (fdb_work->add)
+ mlx5_esw_bridge_fdb_create(dev, esw, vport, fdb_info);
+ else
+ mlx5_esw_bridge_fdb_remove(dev, esw, vport, fdb_info);
+
+out:
+ rtnl_unlock();
+ mlx5_esw_bridge_cleanup_switchdev_fdb_work(fdb_work);
+}
+
+static struct mlx5_bridge_switchdev_fdb_work *
+mlx5_esw_bridge_init_switchdev_fdb_work(struct net_device *dev, bool add,
+ struct switchdev_notifier_fdb_info *fdb_info)
+{
+ struct mlx5_bridge_switchdev_fdb_work *work;
+ u8 *addr;
+
+ work = kzalloc(sizeof(*work), GFP_ATOMIC);
+ if (!work)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_WORK(&work->work, mlx5_esw_bridge_switchdev_fdb_event_work);
+ memcpy(&work->fdb_info, fdb_info, sizeof(work->fdb_info));
+
+ addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
+ if (!addr) {
+ kfree(work);
+ return ERR_PTR(-ENOMEM);
+ }
+ ether_addr_copy(addr, fdb_info->addr);
+ work->fdb_info.addr = addr;
+
+ dev_hold(dev);
+ work->dev = dev;
+ work->add = add;
+ return work;
+}
+
+static int mlx5_esw_bridge_switchdev_event(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct mlx5_esw_bridge_offloads *br_offloads = container_of(nb,
+ struct mlx5_esw_bridge_offloads,
+ nb);
+ struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+ struct switchdev_notifier_fdb_info *fdb_info;
+ struct mlx5_bridge_switchdev_fdb_work *work;
+ struct switchdev_notifier_info *info = ptr;
+ struct net_device *upper;
+ struct mlx5e_priv *priv;
+
+ if (!mlx5e_eswitch_rep(dev))
+ return NOTIFY_DONE;
+ priv = netdev_priv(dev);
+ if (priv->mdev->priv.eswitch != br_offloads->esw)
+ return NOTIFY_DONE;
+
+ if (event == SWITCHDEV_PORT_ATTR_SET) {
+ int err = switchdev_handle_port_attr_set(dev, ptr,
+ mlx5e_eswitch_rep,
+ mlx5_esw_bridge_port_obj_attr_set);
+ return notifier_from_errno(err);
+ }
+
+ upper = netdev_master_upper_dev_get_rcu(dev);
+ if (!upper)
+ return NOTIFY_DONE;
+ if (!netif_is_bridge_master(upper))
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case SWITCHDEV_FDB_ADD_TO_DEVICE:
+ case SWITCHDEV_FDB_DEL_TO_DEVICE:
+ fdb_info = container_of(info,
+ struct switchdev_notifier_fdb_info,
+ info);
+
+ work = mlx5_esw_bridge_init_switchdev_fdb_work(dev,
+ event == SWITCHDEV_FDB_ADD_TO_DEVICE,
+ fdb_info);
+ if (IS_ERR(work)) {
+ WARN_ONCE(1, "Failed to init switchdev work, err=%ld",
+ PTR_ERR(work));
+ return notifier_from_errno(PTR_ERR(work));
+ }
+
+ queue_work(br_offloads->wq, &work->work);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static void mlx5_esw_bridge_update_work(struct work_struct *work)
+{
+ struct mlx5_esw_bridge_offloads *br_offloads = container_of(work,
+ struct mlx5_esw_bridge_offloads,
+ update_work.work);
+
+ rtnl_lock();
+ mlx5_esw_bridge_update(br_offloads);
+ rtnl_unlock();
+
+ queue_delayed_work(br_offloads->wq, &br_offloads->update_work,
+ msecs_to_jiffies(MLX5_ESW_BRIDGE_UPDATE_INTERVAL));
+}
+
+void mlx5e_rep_bridge_init(struct mlx5e_priv *priv)
+{
+ struct mlx5_esw_bridge_offloads *br_offloads;
+ struct mlx5_core_dev *mdev = priv->mdev;
+ struct mlx5_eswitch *esw =
+ mdev->priv.eswitch;
+ int err;
+
+ rtnl_lock();
+ br_offloads = mlx5_esw_bridge_init(esw);
+ rtnl_unlock();
+ if (IS_ERR(br_offloads)) {
+ esw_warn(mdev, "Failed to init esw bridge (err=%ld)\n", PTR_ERR(br_offloads));
+ return;
+ }
+
+ br_offloads->wq = alloc_ordered_workqueue("mlx5_bridge_wq", 0);
+ if (!br_offloads->wq) {
+ esw_warn(mdev, "Failed to allocate bridge offloads workqueue\n");
+ goto err_alloc_wq;
+ }
+ INIT_DELAYED_WORK(&br_offloads->update_work, mlx5_esw_bridge_update_work);
+ queue_delayed_work(br_offloads->wq, &br_offloads->update_work,
+ msecs_to_jiffies(MLX5_ESW_BRIDGE_UPDATE_INTERVAL));
+
+ br_offloads->nb.notifier_call = mlx5_esw_bridge_switchdev_event;
+ err = register_switchdev_notifier(&br_offloads->nb);
+ if (err) {
+ esw_warn(mdev, "Failed to register switchdev notifier (err=%d)\n", err);
+ goto err_register_swdev;
+ }
+
+ br_offloads->nb_blk.notifier_call = mlx5_esw_bridge_event_blocking;
+ err = register_switchdev_blocking_notifier(&br_offloads->nb_blk);
+ if (err) {
+ esw_warn(mdev, "Failed to register blocking switchdev notifier (err=%d)\n", err);
+ goto err_register_swdev_blk;
+ }
+
+ br_offloads->netdev_nb.notifier_call = mlx5_esw_bridge_switchdev_port_event;
+ err = register_netdevice_notifier(&br_offloads->netdev_nb);
+ if (err) {
+ esw_warn(mdev, "Failed to register bridge offloads netdevice notifier (err=%d)\n",
+ err);
+ goto err_register_netdev;
+ }
+ return;
+
+err_register_netdev:
+ unregister_switchdev_blocking_notifier(&br_offloads->nb_blk);
+err_register_swdev_blk:
+ unregister_switchdev_notifier(&br_offloads->nb);
+err_register_swdev:
+ destroy_workqueue(br_offloads->wq);
+err_alloc_wq:
+ mlx5_esw_bridge_cleanup(esw);
+}
+
+void mlx5e_rep_bridge_cleanup(struct mlx5e_priv *priv)
+{
+ struct mlx5_esw_bridge_offloads *br_offloads;
+ struct mlx5_core_dev *mdev = priv->mdev;
+ struct mlx5_eswitch *esw =
+ mdev->priv.eswitch;
+
+ br_offloads = esw->br_offloads;
+ if (!br_offloads)
+ return;
+
+ unregister_netdevice_notifier(&br_offloads->netdev_nb);
+ unregister_switchdev_blocking_notifier(&br_offloads->nb_blk);
+ unregister_switchdev_notifier(&br_offloads->nb);
+ cancel_delayed_work(&br_offloads->update_work);
+ destroy_workqueue(br_offloads->wq);
+ rtnl_lock();
+ mlx5_esw_bridge_cleanup(esw);
+ rtnl_unlock();
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.h b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.h
new file mode 100644
index 000000000000..fbeb64242831
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2021 Mellanox Technologies. */
+
+#ifndef __MLX5_EN_REP_BRIDGE__
+#define __MLX5_EN_REP_BRIDGE__
+
+#include "en.h"
+
+#if IS_ENABLED(CONFIG_MLX5_BRIDGE)
+
+void mlx5e_rep_bridge_init(struct mlx5e_priv *priv);
+void mlx5e_rep_bridge_cleanup(struct mlx5e_priv *priv);
+
+#else /* CONFIG_MLX5_BRIDGE */
+
+static inline void mlx5e_rep_bridge_init(struct mlx5e_priv *priv) {}
+static inline void mlx5e_rep_bridge_cleanup(struct mlx5e_priv *priv) {}
+
+#endif /* CONFIG_MLX5_BRIDGE */
+
+#endif /* __MLX5_EN_REP_BRIDGE__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
index 85eaadc989df..059799e4f483 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
@@ -613,7 +613,7 @@ static bool mlx5e_restore_skb(struct sk_buff *skb, u32 chain, u32 reg_c1,
struct mlx5e_tc_update_priv *tc_priv)
{
struct mlx5e_priv *priv = netdev_priv(skb->dev);
- u32 tunnel_id = reg_c1 >> ESW_TUN_OFFSET;
+ u32 tunnel_id = (reg_c1 >> ESW_TUN_OFFSET) & TUNNEL_ID_MASK;
if (chain) {
struct mlx5_rep_uplink_priv *uplink_priv;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
index 5da5e5323a44..91e7a01e32be 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
@@ -23,7 +23,7 @@
#include "en_tc.h"
#include "en_rep.h"
-#define MLX5_CT_ZONE_BITS (mlx5e_tc_attr_to_reg_mappings[ZONE_TO_REG].mlen * 8)
+#define MLX5_CT_ZONE_BITS (mlx5e_tc_attr_to_reg_mappings[ZONE_TO_REG].mlen)
#define MLX5_CT_ZONE_MASK GENMASK(MLX5_CT_ZONE_BITS - 1, 0)
#define MLX5_CT_STATE_ESTABLISHED_BIT BIT(1)
#define MLX5_CT_STATE_TRK_BIT BIT(2)
@@ -32,11 +32,11 @@
#define MLX5_CT_STATE_RELATED_BIT BIT(5)
#define MLX5_CT_STATE_INVALID_BIT BIT(6)
-#define MLX5_FTE_ID_BITS (mlx5e_tc_attr_to_reg_mappings[FTEID_TO_REG].mlen * 8)
+#define MLX5_FTE_ID_BITS (mlx5e_tc_attr_to_reg_mappings[FTEID_TO_REG].mlen)
#define MLX5_FTE_ID_MAX GENMASK(MLX5_FTE_ID_BITS - 1, 0)
#define MLX5_FTE_ID_MASK MLX5_FTE_ID_MAX
-#define MLX5_CT_LABELS_BITS (mlx5e_tc_attr_to_reg_mappings[LABELS_TO_REG].mlen * 8)
+#define MLX5_CT_LABELS_BITS (mlx5e_tc_attr_to_reg_mappings[LABELS_TO_REG].mlen)
#define MLX5_CT_LABELS_MASK GENMASK(MLX5_CT_LABELS_BITS - 1, 0)
#define ct_dbg(fmt, args...)\
@@ -150,6 +150,11 @@ struct mlx5_ct_entry {
unsigned long flags;
};
+static void
+mlx5_tc_ct_entry_destroy_mod_hdr(struct mlx5_tc_ct_priv *ct_priv,
+ struct mlx5_flow_attr *attr,
+ struct mlx5e_mod_hdr_handle *mh);
+
static const struct rhashtable_params cts_ht_params = {
.head_offset = offsetof(struct mlx5_ct_entry, node),
.key_offset = offsetof(struct mlx5_ct_entry, cookie),
@@ -458,8 +463,7 @@ mlx5_tc_ct_entry_del_rule(struct mlx5_tc_ct_priv *ct_priv,
ct_dbg("Deleting ct entry rule in zone %d", entry->tuple.zone);
mlx5_tc_rule_delete(netdev_priv(ct_priv->netdev), zone_rule->rule, attr);
- mlx5e_mod_hdr_detach(ct_priv->dev,
- ct_priv->mod_hdr_tbl, zone_rule->mh);
+ mlx5_tc_ct_entry_destroy_mod_hdr(ct_priv, zone_rule->attr, zone_rule->mh);
mlx5_put_label_mapping(ct_priv, attr->ct_attr.ct_labels_id);
kfree(attr);
}
@@ -686,15 +690,27 @@ mlx5_tc_ct_entry_create_mod_hdr(struct mlx5_tc_ct_priv *ct_priv,
if (err)
goto err_mapping;
- *mh = mlx5e_mod_hdr_attach(ct_priv->dev,
- ct_priv->mod_hdr_tbl,
- ct_priv->ns_type,
- &mod_acts);
- if (IS_ERR(*mh)) {
- err = PTR_ERR(*mh);
- goto err_mapping;
+ if (nat) {
+ attr->modify_hdr = mlx5_modify_header_alloc(ct_priv->dev, ct_priv->ns_type,
+ mod_acts.num_actions,
+ mod_acts.actions);
+ if (IS_ERR(attr->modify_hdr)) {
+ err = PTR_ERR(attr->modify_hdr);
+ goto err_mapping;
+ }
+
+ *mh = NULL;
+ } else {
+ *mh = mlx5e_mod_hdr_attach(ct_priv->dev,
+ ct_priv->mod_hdr_tbl,
+ ct_priv->ns_type,
+ &mod_acts);
+ if (IS_ERR(*mh)) {
+ err = PTR_ERR(*mh);
+ goto err_mapping;
+ }
+ attr->modify_hdr = mlx5e_mod_hdr_get(*mh);
}
- attr->modify_hdr = mlx5e_mod_hdr_get(*mh);
dealloc_mod_hdr_actions(&mod_acts);
return 0;
@@ -705,6 +721,17 @@ err_mapping:
return err;
}
+static void
+mlx5_tc_ct_entry_destroy_mod_hdr(struct mlx5_tc_ct_priv *ct_priv,
+ struct mlx5_flow_attr *attr,
+ struct mlx5e_mod_hdr_handle *mh)
+{
+ if (mh)
+ mlx5e_mod_hdr_detach(ct_priv->dev, ct_priv->mod_hdr_tbl, mh);
+ else
+ mlx5_modify_header_dealloc(ct_priv->dev, attr->modify_hdr);
+}
+
static int
mlx5_tc_ct_entry_add_rule(struct mlx5_tc_ct_priv *ct_priv,
struct flow_rule *flow_rule,
@@ -767,8 +794,7 @@ mlx5_tc_ct_entry_add_rule(struct mlx5_tc_ct_priv *ct_priv,
return 0;
err_rule:
- mlx5e_mod_hdr_detach(ct_priv->dev,
- ct_priv->mod_hdr_tbl, zone_rule->mh);
+ mlx5_tc_ct_entry_destroy_mod_hdr(ct_priv, zone_rule->attr, zone_rule->mh);
mlx5_put_label_mapping(ct_priv, attr->ct_attr.ct_labels_id);
err_mod_hdr:
kfree(attr);
@@ -918,7 +944,7 @@ mlx5_tc_ct_shared_counter_get(struct mlx5_tc_ct_priv *ct_priv,
}
if (rev_entry && refcount_inc_not_zero(&rev_entry->counter->refcount)) {
- ct_dbg("Using shared counter entry=0x%p rev=0x%p\n", entry, rev_entry);
+ ct_dbg("Using shared counter entry=0x%p rev=0x%p", entry, rev_entry);
shared_counter = rev_entry->counter;
spin_unlock_bh(&ct_priv->ht_lock);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.h
index 69e618d17071..644cf1641cde 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.h
@@ -33,15 +33,15 @@ struct mlx5_ct_attr {
#define zone_to_reg_ct {\
.mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_2,\
.moffset = 0,\
- .mlen = 2,\
+ .mlen = 16,\
.soffset = MLX5_BYTE_OFF(fte_match_param,\
- misc_parameters_2.metadata_reg_c_2) + 2,\
+ misc_parameters_2.metadata_reg_c_2),\
}
#define ctstate_to_reg_ct {\
.mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_2,\
- .moffset = 2,\
- .mlen = 2,\
+ .moffset = 16,\
+ .mlen = 16,\
.soffset = MLX5_BYTE_OFF(fte_match_param,\
misc_parameters_2.metadata_reg_c_2),\
}
@@ -49,7 +49,7 @@ struct mlx5_ct_attr {
#define mark_to_reg_ct {\
.mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_3,\
.moffset = 0,\
- .mlen = 4,\
+ .mlen = 32,\
.soffset = MLX5_BYTE_OFF(fte_match_param,\
misc_parameters_2.metadata_reg_c_3),\
}
@@ -57,7 +57,7 @@ struct mlx5_ct_attr {
#define labels_to_reg_ct {\
.mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_4,\
.moffset = 0,\
- .mlen = 4,\
+ .mlen = 32,\
.soffset = MLX5_BYTE_OFF(fte_match_param,\
misc_parameters_2.metadata_reg_c_4),\
}
@@ -65,7 +65,7 @@ struct mlx5_ct_attr {
#define fteid_to_reg_ct {\
.mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_5,\
.moffset = 0,\
- .mlen = 4,\
+ .mlen = 32,\
.soffset = MLX5_BYTE_OFF(fte_match_param,\
misc_parameters_2.metadata_reg_c_5),\
}
@@ -73,20 +73,19 @@ struct mlx5_ct_attr {
#define zone_restore_to_reg_ct {\
.mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_1,\
.moffset = 0,\
- .mlen = (ESW_ZONE_ID_BITS / 8),\
+ .mlen = ESW_ZONE_ID_BITS,\
.soffset = MLX5_BYTE_OFF(fte_match_param,\
- misc_parameters_2.metadata_reg_c_1) + 3,\
+ misc_parameters_2.metadata_reg_c_1),\
}
#define nic_zone_restore_to_reg_ct {\
.mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_B,\
- .moffset = 2,\
- .mlen = (ESW_ZONE_ID_BITS / 8),\
+ .moffset = 16,\
+ .mlen = ESW_ZONE_ID_BITS,\
}
#define REG_MAPPING_MLEN(reg) (mlx5e_tc_attr_to_reg_mappings[reg].mlen)
#define REG_MAPPING_MOFFSET(reg) (mlx5e_tc_attr_to_reg_mappings[reg].moffset)
-#define REG_MAPPING_SHIFT(reg) (REG_MAPPING_MOFFSET(reg) * 8)
#if IS_ENABLED(CONFIG_MLX5_TC_CT)
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 172e0474f2e6..8f79f04eccd6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
@@ -212,6 +212,7 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv,
{
int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
const struct ip_tunnel_key *tun_key = &e->tun_info->key;
+ struct mlx5_pkt_reformat_params reformat_params;
struct mlx5e_neigh m_neigh = {};
TC_TUN_ROUTE_ATTR_INIT(attr);
int ipv4_encap_size;
@@ -295,9 +296,12 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv,
*/
goto release_neigh;
}
- e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev,
- e->reformat_type,
- ipv4_encap_size, encap_header,
+
+ memset(&reformat_params, 0, sizeof(reformat_params));
+ reformat_params.type = e->reformat_type;
+ reformat_params.size = ipv4_encap_size;
+ reformat_params.data = encap_header;
+ e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev, &reformat_params,
MLX5_FLOW_NAMESPACE_FDB);
if (IS_ERR(e->pkt_reformat)) {
err = PTR_ERR(e->pkt_reformat);
@@ -324,6 +328,7 @@ int mlx5e_tc_tun_update_header_ipv4(struct mlx5e_priv *priv,
{
int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
const struct ip_tunnel_key *tun_key = &e->tun_info->key;
+ struct mlx5_pkt_reformat_params reformat_params;
TC_TUN_ROUTE_ATTR_INIT(attr);
int ipv4_encap_size;
char *encap_header;
@@ -396,9 +401,12 @@ int mlx5e_tc_tun_update_header_ipv4(struct mlx5e_priv *priv,
*/
goto release_neigh;
}
- e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev,
- e->reformat_type,
- ipv4_encap_size, encap_header,
+
+ memset(&reformat_params, 0, sizeof(reformat_params));
+ reformat_params.type = e->reformat_type;
+ reformat_params.size = ipv4_encap_size;
+ reformat_params.data = encap_header;
+ e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev, &reformat_params,
MLX5_FLOW_NAMESPACE_FDB);
if (IS_ERR(e->pkt_reformat)) {
err = PTR_ERR(e->pkt_reformat);
@@ -471,6 +479,7 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv,
{
int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
const struct ip_tunnel_key *tun_key = &e->tun_info->key;
+ struct mlx5_pkt_reformat_params reformat_params;
struct mlx5e_neigh m_neigh = {};
TC_TUN_ROUTE_ATTR_INIT(attr);
struct ipv6hdr *ip6h;
@@ -553,9 +562,11 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv,
goto release_neigh;
}
- e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev,
- e->reformat_type,
- ipv6_encap_size, encap_header,
+ memset(&reformat_params, 0, sizeof(reformat_params));
+ reformat_params.type = e->reformat_type;
+ reformat_params.size = ipv6_encap_size;
+ reformat_params.data = encap_header;
+ e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev, &reformat_params,
MLX5_FLOW_NAMESPACE_FDB);
if (IS_ERR(e->pkt_reformat)) {
err = PTR_ERR(e->pkt_reformat);
@@ -582,6 +593,7 @@ int mlx5e_tc_tun_update_header_ipv6(struct mlx5e_priv *priv,
{
int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
const struct ip_tunnel_key *tun_key = &e->tun_info->key;
+ struct mlx5_pkt_reformat_params reformat_params;
TC_TUN_ROUTE_ATTR_INIT(attr);
struct ipv6hdr *ip6h;
int ipv6_encap_size;
@@ -654,9 +666,11 @@ int mlx5e_tc_tun_update_header_ipv6(struct mlx5e_priv *priv,
goto release_neigh;
}
- e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev,
- e->reformat_type,
- ipv6_encap_size, encap_header,
+ memset(&reformat_params, 0, sizeof(reformat_params));
+ reformat_params.type = e->reformat_type;
+ reformat_params.size = ipv6_encap_size;
+ reformat_params.data = encap_header;
+ e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev, &reformat_params,
MLX5_FLOW_NAMESPACE_FDB);
if (IS_ERR(e->pkt_reformat)) {
err = PTR_ERR(e->pkt_reformat);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
index 490131e06efb..2e846b741280 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
@@ -120,6 +120,7 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
struct list_head *flow_list)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+ struct mlx5_pkt_reformat_params reformat_params;
struct mlx5_esw_flow_attr *esw_attr;
struct mlx5_flow_handle *rule;
struct mlx5_flow_attr *attr;
@@ -130,9 +131,12 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
if (e->flags & MLX5_ENCAP_ENTRY_NO_ROUTE)
return;
+ memset(&reformat_params, 0, sizeof(reformat_params));
+ reformat_params.type = e->reformat_type;
+ reformat_params.size = e->encap_size;
+ reformat_params.data = e->encap_header;
e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev,
- e->reformat_type,
- e->encap_size, e->encap_header,
+ &reformat_params,
MLX5_FLOW_NAMESPACE_FDB);
if (IS_ERR(e->pkt_reformat)) {
mlx5_core_warn(priv->mdev, "Failed to offload cached encapsulation header, %lu\n",
@@ -839,6 +843,7 @@ int mlx5e_attach_decap(struct mlx5e_priv *priv,
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5_esw_flow_attr *attr = flow->attr->esw_attr;
+ struct mlx5_pkt_reformat_params reformat_params;
struct mlx5e_tc_flow_parse_attr *parse_attr;
struct mlx5e_decap_entry *d;
struct mlx5e_decap_key key;
@@ -880,10 +885,12 @@ int mlx5e_attach_decap(struct mlx5e_priv *priv,
hash_add_rcu(esw->offloads.decap_tbl, &d->hlist, hash_key);
mutex_unlock(&esw->offloads.decap_tbl_lock);
+ memset(&reformat_params, 0, sizeof(reformat_params));
+ reformat_params.type = MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
+ reformat_params.size = sizeof(parse_attr->eth);
+ reformat_params.data = &parse_attr->eth;
d->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev,
- MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2,
- sizeof(parse_attr->eth),
- &parse_attr->eth,
+ &reformat_params,
MLX5_FLOW_NAMESPACE_FDB);
if (IS_ERR(d->pkt_reformat)) {
err = PTR_ERR(d->pkt_reformat);
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 00af0b831a28..d964665eaa63 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
@@ -162,7 +162,7 @@ static inline unsigned int mlx5e_accel_tx_ids_len(struct mlx5e_txqsq *sq,
/* Part of the eseg touched by TX offloads */
#define MLX5E_ACCEL_ESEG_LEN offsetof(struct mlx5_wqe_eth_seg, mss)
-static inline bool mlx5e_accel_tx_eseg(struct mlx5e_priv *priv,
+static inline void mlx5e_accel_tx_eseg(struct mlx5e_priv *priv,
struct sk_buff *skb,
struct mlx5_wqe_eth_seg *eseg, u16 ihs)
{
@@ -175,8 +175,6 @@ static inline bool mlx5e_accel_tx_eseg(struct mlx5e_priv *priv,
if (skb->encapsulation && skb->ip_summed == CHECKSUM_PARTIAL)
mlx5e_tx_tunnel_accel(skb, eseg, ihs);
#endif
-
- return true;
}
static inline void mlx5e_accel_tx_finish(struct mlx5e_txqsq *sq,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
index 26f7fab109d9..7cab08a2f715 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
@@ -428,7 +428,6 @@ int mlx5e_ipsec_init(struct mlx5e_priv *priv)
spin_lock_init(&ipsec->sadb_rx_lock);
ida_init(&ipsec->halloc);
ipsec->en_priv = priv;
- ipsec->en_priv->ipsec = ipsec;
ipsec->no_trailer = !!(mlx5_accel_ipsec_device_caps(priv->mdev) &
MLX5_ACCEL_IPSEC_CAP_RX_NO_TRAILER);
ipsec->wq = alloc_ordered_workqueue("mlx5e_ipsec: %s", 0,
@@ -438,6 +437,7 @@ int mlx5e_ipsec_init(struct mlx5e_priv *priv)
return -ENOMEM;
}
+ priv->ipsec = ipsec;
mlx5e_accel_ipsec_fs_init(priv);
netdev_dbg(priv->netdev, "IPSec attached to netdevice\n");
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
index a97e8d205094..33de8f0092a6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
@@ -136,8 +136,6 @@ static void mlx5e_ipsec_set_swp(struct sk_buff *skb,
struct mlx5_wqe_eth_seg *eseg, u8 mode,
struct xfrm_offload *xo)
{
- struct mlx5e_swp_spec swp_spec = {};
-
/* Tunnel Mode:
* SWP: OutL3 InL3 InL4
* Pkt: MAC IP ESP IP L4
@@ -146,23 +144,58 @@ static void mlx5e_ipsec_set_swp(struct sk_buff *skb,
* SWP: OutL3 InL4
* InL3
* Pkt: MAC IP ESP L4
+ *
+ * Tunnel(VXLAN TCP/UDP) over Transport Mode
+ * SWP: OutL3 InL3 InL4
+ * Pkt: MAC IP ESP UDP VXLAN IP L4
*/
- swp_spec.l3_proto = skb->protocol;
- swp_spec.is_tun = mode == XFRM_MODE_TUNNEL;
- if (swp_spec.is_tun) {
- if (xo->proto == IPPROTO_IPV6) {
- swp_spec.tun_l3_proto = htons(ETH_P_IPV6);
- swp_spec.tun_l4_proto = inner_ipv6_hdr(skb)->nexthdr;
- } else {
- swp_spec.tun_l3_proto = htons(ETH_P_IP);
- swp_spec.tun_l4_proto = inner_ip_hdr(skb)->protocol;
- }
- } else {
- swp_spec.tun_l3_proto = skb->protocol;
- swp_spec.tun_l4_proto = xo->proto;
+
+ /* Shared settings */
+ eseg->swp_outer_l3_offset = skb_network_offset(skb) / 2;
+ if (skb->protocol == htons(ETH_P_IPV6))
+ eseg->swp_flags |= MLX5_ETH_WQE_SWP_OUTER_L3_IPV6;
+
+ /* Tunnel mode */
+ if (mode == XFRM_MODE_TUNNEL) {
+ eseg->swp_inner_l3_offset = skb_inner_network_offset(skb) / 2;
+ eseg->swp_inner_l4_offset = skb_inner_transport_offset(skb) / 2;
+ if (xo->proto == IPPROTO_IPV6)
+ eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
+ if (inner_ip_hdr(skb)->protocol == IPPROTO_UDP)
+ eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP;
+ return;
+ }
+
+ /* Transport mode */
+ if (mode != XFRM_MODE_TRANSPORT)
+ return;
+
+ if (!xo->inner_ipproto) {
+ eseg->swp_inner_l3_offset = skb_network_offset(skb) / 2;
+ eseg->swp_inner_l4_offset = skb_inner_transport_offset(skb) / 2;
+ if (skb->protocol == htons(ETH_P_IPV6))
+ eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
+ if (xo->proto == IPPROTO_UDP)
+ eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP;
+ return;
+ }
+
+ /* Tunnel(VXLAN TCP/UDP) over Transport Mode */
+ switch (xo->inner_ipproto) {
+ case IPPROTO_UDP:
+ eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP;
+ fallthrough;
+ case IPPROTO_TCP:
+ eseg->swp_inner_l3_offset = skb_inner_network_offset(skb) / 2;
+ eseg->swp_inner_l4_offset = (skb->csum_start + skb->head - skb->data) / 2;
+ if (skb->protocol == htons(ETH_P_IPV6))
+ eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
+ break;
+ default:
+ break;
}
- mlx5e_set_eseg_swp(skb, eseg, &swp_spec);
+ return;
}
void mlx5e_ipsec_set_iv_esn(struct sk_buff *skb, struct xfrm_state *x,
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 3e80742a3caf..5120a59361e6 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
@@ -93,18 +93,38 @@ static inline bool mlx5e_ipsec_eseg_meta(struct mlx5_wqe_eth_seg *eseg)
void mlx5e_ipsec_tx_build_eseg(struct mlx5e_priv *priv, struct sk_buff *skb,
struct mlx5_wqe_eth_seg *eseg);
-static inline bool mlx5e_ipsec_feature_check(struct sk_buff *skb, struct net_device *netdev,
- netdev_features_t features)
+static inline netdev_features_t
+mlx5e_ipsec_feature_check(struct sk_buff *skb, netdev_features_t features)
{
+ struct xfrm_offload *xo = xfrm_offload(skb);
struct sec_path *sp = skb_sec_path(skb);
- if (sp && sp->len) {
+ if (sp && sp->len && xo) {
struct xfrm_state *x = sp->xvec[0];
- if (x && x->xso.offload_handle)
- return true;
+ if (!x || !x->xso.offload_handle)
+ goto out_disable;
+
+ if (xo->inner_ipproto) {
+ /* Cannot support tunnel packet over IPsec tunnel mode
+ * because we cannot offload three IP header csum
+ */
+ if (x->props.mode == XFRM_MODE_TUNNEL)
+ goto out_disable;
+
+ /* Only support UDP or TCP L4 checksum */
+ if (xo->inner_ipproto != IPPROTO_UDP &&
+ xo->inner_ipproto != IPPROTO_TCP)
+ goto out_disable;
+ }
+
+ return features;
+
}
- return false;
+
+ /* Disable CSUM and GSO for software IPsec */
+out_disable:
+ return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
}
#else
@@ -120,8 +140,9 @@ static inline bool mlx5e_ipsec_eseg_meta(struct mlx5_wqe_eth_seg *eseg)
}
static inline bool mlx5_ipsec_is_rx_flow(struct mlx5_cqe64 *cqe) { return false; }
-static inline bool mlx5e_ipsec_feature_check(struct sk_buff *skb, struct net_device *netdev,
- netdev_features_t features) { return false; }
+static inline netdev_features_t
+mlx5e_ipsec_feature_check(struct sk_buff *skb, netdev_features_t features)
+{ return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); }
#endif /* CONFIG_MLX5_EN_IPSEC */
#endif /* __MLX5E_IPSEC_RXTX_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c
index 95293ee0d38d..d93aadbf10da 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.c
@@ -59,12 +59,15 @@ void mlx5e_ktls_build_netdev(struct mlx5e_priv *priv)
struct net_device *netdev = priv->netdev;
struct mlx5_core_dev *mdev = priv->mdev;
- if (mlx5_accel_is_ktls_tx(mdev)) {
+ if (!mlx5e_accel_is_ktls_tx(mdev) && !mlx5e_accel_is_ktls_rx(mdev))
+ return;
+
+ if (mlx5e_accel_is_ktls_tx(mdev)) {
netdev->hw_features |= NETIF_F_HW_TLS_TX;
netdev->features |= NETIF_F_HW_TLS_TX;
}
- if (mlx5_accel_is_ktls_rx(mdev))
+ if (mlx5e_accel_is_ktls_rx(mdev))
netdev->hw_features |= NETIF_F_HW_TLS_RX;
netdev->tlsdev_ops = &mlx5e_ktls_ops;
@@ -89,7 +92,7 @@ int mlx5e_ktls_init_rx(struct mlx5e_priv *priv)
{
int err;
- if (!mlx5_accel_is_ktls_rx(priv->mdev))
+ if (!mlx5e_accel_is_ktls_rx(priv->mdev))
return 0;
priv->tls->rx_wq = create_singlethread_workqueue("mlx5e_tls_rx");
@@ -109,7 +112,7 @@ int mlx5e_ktls_init_rx(struct mlx5e_priv *priv)
void mlx5e_ktls_cleanup_rx(struct mlx5e_priv *priv)
{
- if (!mlx5_accel_is_ktls_rx(priv->mdev))
+ if (!mlx5e_accel_is_ktls_rx(priv->mdev))
return;
if (priv->netdev->features & NETIF_F_HW_TLS_RX)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h
index aaa579bf9a39..5833deb2354c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h
@@ -15,6 +15,25 @@ int mlx5e_ktls_set_feature_rx(struct net_device *netdev, bool enable);
struct mlx5e_ktls_resync_resp *
mlx5e_ktls_rx_resync_create_resp_list(void);
void mlx5e_ktls_rx_resync_destroy_resp_list(struct mlx5e_ktls_resync_resp *resp_list);
+
+static inline bool mlx5e_accel_is_ktls_tx(struct mlx5_core_dev *mdev)
+{
+ return !is_kdump_kernel() &&
+ mlx5_accel_is_ktls_tx(mdev);
+}
+
+static inline bool mlx5e_accel_is_ktls_rx(struct mlx5_core_dev *mdev)
+{
+ return !is_kdump_kernel() &&
+ mlx5_accel_is_ktls_rx(mdev);
+}
+
+static inline bool mlx5e_accel_is_ktls_device(struct mlx5_core_dev *mdev)
+{
+ return !is_kdump_kernel() &&
+ mlx5_accel_is_ktls_device(mdev);
+}
+
#else
static inline void mlx5e_ktls_build_netdev(struct mlx5e_priv *priv)
@@ -44,6 +63,11 @@ mlx5e_ktls_rx_resync_create_resp_list(void)
static inline void
mlx5e_ktls_rx_resync_destroy_resp_list(struct mlx5e_ktls_resync_resp *resp_list) {}
+
+static inline bool mlx5e_accel_is_ktls_tx(struct mlx5_core_dev *mdev) { return false; }
+static inline bool mlx5e_accel_is_ktls_rx(struct mlx5_core_dev *mdev) { return false; }
+static inline bool mlx5e_accel_is_ktls_device(struct mlx5_core_dev *mdev) { return false; }
+
#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
index 51bdf71073f3..9ad3459fb63a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
@@ -23,10 +23,13 @@ mlx5e_ktls_dumps_num_wqes(struct mlx5e_params *params, unsigned int nfrags,
return nfrags + DIV_ROUND_UP(sync_len, MLX5E_SW2HW_MTU(params, params->sw_mtu));
}
-u16 mlx5e_ktls_get_stop_room(struct mlx5e_params *params)
+u16 mlx5e_ktls_get_stop_room(struct mlx5_core_dev *mdev, struct mlx5e_params *params)
{
u16 num_dumps, stop_room = 0;
+ if (!mlx5e_accel_is_ktls_tx(mdev))
+ return 0;
+
num_dumps = mlx5e_ktls_dumps_num_wqes(params, MAX_SKB_FRAGS, TLS_MAX_PAYLOAD_SIZE);
stop_room += mlx5e_stop_room_for_wqe(MLX5E_TLS_SET_STATIC_PARAMS_WQEBBS);
@@ -135,6 +138,7 @@ void mlx5e_ktls_del_tx(struct net_device *netdev, struct tls_context *tls_ctx)
priv = netdev_priv(netdev);
mdev = priv->mdev;
+ atomic64_inc(&priv_tx->sw_stats->tx_tls_del);
mlx5e_destroy_tis(mdev, priv_tx->tisn);
mlx5_ktls_destroy_key(mdev, priv_tx->key_id);
kfree(priv_tx);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_txrx.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_txrx.h
index 8f79335057dc..08c9d5134479 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_txrx.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_txrx.h
@@ -14,7 +14,7 @@ struct mlx5e_accel_tx_tls_state {
u32 tls_tisn;
};
-u16 mlx5e_ktls_get_stop_room(struct mlx5e_params *params);
+u16 mlx5e_ktls_get_stop_room(struct mlx5_core_dev *mdev, struct mlx5e_params *params);
bool mlx5e_ktls_handle_tx_skb(struct tls_context *tls_ctx, struct mlx5e_txqsq *sq,
struct sk_buff *skb, int datalen,
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 d6b21b899dbc..b8fc863aa68d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.c
@@ -192,13 +192,13 @@ 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)) {
+ if (mlx5e_accel_is_ktls_device(priv->mdev)) {
mlx5e_ktls_build_netdev(priv);
return;
}
/* FPGA */
- if (!mlx5_accel_is_tls_device(priv->mdev))
+ if (!mlx5e_accel_is_tls_device(priv->mdev))
return;
caps = mlx5_accel_tls_device_caps(priv->mdev);
@@ -224,7 +224,7 @@ int mlx5e_tls_init(struct mlx5e_priv *priv)
{
struct mlx5e_tls *tls;
- if (!mlx5_accel_is_tls_device(priv->mdev))
+ if (!mlx5e_accel_is_tls_device(priv->mdev))
return 0;
tls = kzalloc(sizeof(*tls), GFP_KERNEL);
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 4c9274d390da..62ecf14bf86a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls.h
@@ -42,6 +42,7 @@
struct mlx5e_tls_sw_stats {
atomic64_t tx_tls_ctx;
+ atomic64_t tx_tls_del;
atomic64_t tx_tls_drop_metadata;
atomic64_t tx_tls_drop_resync_alloc;
atomic64_t tx_tls_drop_no_sync_data;
@@ -103,11 +104,18 @@ int mlx5e_tls_get_count(struct mlx5e_priv *priv);
int mlx5e_tls_get_strings(struct mlx5e_priv *priv, uint8_t *data);
int mlx5e_tls_get_stats(struct mlx5e_priv *priv, u64 *data);
+static inline bool mlx5e_accel_is_tls_device(struct mlx5_core_dev *mdev)
+{
+ return !is_kdump_kernel() &&
+ mlx5_accel_is_tls_device(mdev);
+}
+
#else
static inline void mlx5e_tls_build_netdev(struct mlx5e_priv *priv)
{
- if (mlx5_accel_is_ktls_device(priv->mdev))
+ if (!is_kdump_kernel() &&
+ mlx5_accel_is_ktls_device(priv->mdev))
mlx5e_ktls_build_netdev(priv);
}
@@ -117,6 +125,7 @@ static inline void mlx5e_tls_cleanup(struct mlx5e_priv *priv) { }
static inline int mlx5e_tls_get_count(struct mlx5e_priv *priv) { return 0; }
static inline int mlx5e_tls_get_strings(struct mlx5e_priv *priv, uint8_t *data) { return 0; }
static inline int mlx5e_tls_get_stats(struct mlx5e_priv *priv, u64 *data) { return 0; }
+static inline bool mlx5e_accel_is_tls_device(struct mlx5_core_dev *mdev) { return false; }
#endif
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 82dc09aaa7fc..7a700f913582 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
@@ -273,7 +273,7 @@ bool mlx5e_tls_handle_tx_skb(struct net_device *netdev, struct mlx5e_txqsq *sq,
if (WARN_ON_ONCE(tls_ctx->netdev != netdev))
goto err_out;
- if (mlx5_accel_is_ktls_tx(sq->mdev))
+ if (mlx5e_accel_is_ktls_tx(sq->mdev))
return mlx5e_ktls_handle_tx_skb(tls_ctx, sq, skb, datalen, state);
/* FPGA */
@@ -378,11 +378,11 @@ void mlx5e_tls_handle_rx_skb_metadata(struct mlx5e_rq *rq, struct sk_buff *skb,
u16 mlx5e_tls_get_stop_room(struct mlx5_core_dev *mdev, struct mlx5e_params *params)
{
- if (!mlx5_accel_is_tls_device(mdev))
+ if (!mlx5e_accel_is_tls_device(mdev))
return 0;
- if (mlx5_accel_is_ktls_device(mdev))
- return mlx5e_ktls_get_stop_room(params);
+ if (mlx5e_accel_is_ktls_device(mdev))
+ return mlx5e_ktls_get_stop_room(mdev, params);
/* FPGA */
/* Resync SKB. */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_stats.c
index 29463bdb7715..56e7b2aee85f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/tls_stats.c
@@ -47,6 +47,7 @@ static const struct counter_desc mlx5e_tls_sw_stats_desc[] = {
static const struct counter_desc mlx5e_ktls_sw_stats_desc[] = {
{ MLX5E_DECLARE_STAT(struct mlx5e_tls_sw_stats, tx_tls_ctx) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_tls_sw_stats, tx_tls_del) },
{ MLX5E_DECLARE_STAT(struct mlx5e_tls_sw_stats, rx_tls_ctx) },
{ MLX5E_DECLARE_STAT(struct mlx5e_tls_sw_stats, rx_tls_del) },
};
@@ -58,7 +59,7 @@ static const struct counter_desc *get_tls_atomic_stats(struct mlx5e_priv *priv)
{
if (!priv->tls)
return NULL;
- if (mlx5_accel_is_ktls_device(priv->mdev))
+ if (mlx5e_accel_is_ktls_device(priv->mdev))
return mlx5e_ktls_sw_stats_desc;
return mlx5e_tls_sw_stats_desc;
}
@@ -67,7 +68,7 @@ int mlx5e_tls_get_count(struct mlx5e_priv *priv)
{
if (!priv->tls)
return 0;
- if (mlx5_accel_is_ktls_device(priv->mdev))
+ if (mlx5e_accel_is_ktls_device(priv->mdev))
return ARRAY_SIZE(mlx5e_ktls_sw_stats_desc);
return ARRAY_SIZE(mlx5e_tls_sw_stats_desc);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index d6513aef5cd4..bd72572e03d1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -1992,7 +1992,7 @@ static int set_pflag_tx_mpwqe_common(struct net_device *netdev, u32 flag, bool e
struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5e_params new_params;
- if (enable && !MLX5_CAP_ETH(mdev, enhanced_multi_pkt_send_wqe))
+ if (enable && !mlx5e_tx_mpwqe_supported(mdev))
return -EOPNOTSUPP;
new_params = priv->channels.params;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index d26b8ed51195..d09e65557e75 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -91,12 +91,16 @@ void mlx5e_update_carrier(struct mlx5e_priv *priv)
{
struct mlx5_core_dev *mdev = priv->mdev;
u8 port_state;
+ bool up;
port_state = mlx5_query_vport_state(mdev,
MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT,
0);
- if (port_state == VPORT_STATE_UP) {
+ up = port_state == VPORT_STATE_UP;
+ if (up == netif_carrier_ok(priv->netdev))
+ netif_carrier_event(priv->netdev);
+ if (up) {
netdev_info(priv->netdev, "Link up\n");
netif_carrier_on(priv->netdev);
} else {
@@ -644,8 +648,8 @@ int mlx5e_create_rq(struct mlx5e_rq *rq, struct mlx5e_rq_param *param)
return -ENOMEM;
ts_format = mlx5_is_real_time_rq(mdev) ?
- MLX5_RQC_TIMESTAMP_FORMAT_REAL_TIME :
- MLX5_RQC_TIMESTAMP_FORMAT_FREE_RUNNING;
+ MLX5_TIMESTAMP_FORMAT_REAL_TIME :
+ MLX5_TIMESTAMP_FORMAT_FREE_RUNNING;
rqc = MLX5_ADDR_OF(create_rq_in, in, ctx);
wq = MLX5_ADDR_OF(rqc, rqc, wq);
@@ -853,7 +857,7 @@ int mlx5e_open_rq(struct mlx5e_params *params, struct mlx5e_rq_param *param,
if (err)
goto err_destroy_rq;
- if (mlx5e_is_tls_on(rq->priv) && !mlx5_accel_is_ktls_device(mdev))
+ if (mlx5e_is_tls_on(rq->priv) && !mlx5e_accel_is_ktls_device(mdev))
__set_bit(MLX5E_RQ_STATE_FPGA_TLS, &rq->state); /* must be FPGA */
if (MLX5_CAP_ETH(mdev, cqe_checksum_full))
@@ -1188,8 +1192,8 @@ static int mlx5e_create_sq(struct mlx5_core_dev *mdev,
return -ENOMEM;
ts_format = mlx5_is_real_time_sq(mdev) ?
- MLX5_SQC_TIMESTAMP_FORMAT_REAL_TIME :
- MLX5_SQC_TIMESTAMP_FORMAT_FREE_RUNNING;
+ MLX5_TIMESTAMP_FORMAT_REAL_TIME :
+ MLX5_TIMESTAMP_FORMAT_FREE_RUNNING;
sqc = MLX5_ADDR_OF(create_sq_in, in, ctx);
wq = MLX5_ADDR_OF(sqc, sqc, wq);
@@ -4327,6 +4331,11 @@ static netdev_features_t mlx5e_tunnel_features_check(struct mlx5e_priv *priv,
if (port == GENEVE_UDP_PORT && mlx5_geneve_tx_allowed(priv->mdev))
return features;
#endif
+ break;
+#ifdef CONFIG_MLX5_EN_IPSEC
+ case IPPROTO_ESP:
+ return mlx5e_ipsec_feature_check(skb, features);
+#endif
}
out:
@@ -4343,9 +4352,6 @@ netdev_features_t mlx5e_features_check(struct sk_buff *skb,
features = vlan_features_check(skb, features);
features = vxlan_features_check(skb, features);
- if (mlx5e_ipsec_feature_check(skb, netdev, features))
- return features;
-
/* Validate if the tunneled packet is being offloaded by HW */
if (skb->encapsulation &&
(features & NETIF_F_CSUM_MASK || features & NETIF_F_GSO_MASK))
@@ -4661,12 +4667,10 @@ void mlx5e_build_nic_params(struct mlx5e_priv *priv, struct mlx5e_xsk *xsk, u16
params->log_sq_size = is_kdump_kernel() ?
MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE :
MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE;
- MLX5E_SET_PFLAG(params, MLX5E_PFLAG_SKB_TX_MPWQE,
- MLX5_CAP_ETH(mdev, enhanced_multi_pkt_send_wqe));
+ MLX5E_SET_PFLAG(params, MLX5E_PFLAG_SKB_TX_MPWQE, mlx5e_tx_mpwqe_supported(mdev));
/* XDP SQ */
- MLX5E_SET_PFLAG(params, MLX5E_PFLAG_XDP_TX_MPWQE,
- MLX5_CAP_ETH(mdev, enhanced_multi_pkt_send_wqe));
+ MLX5E_SET_PFLAG(params, MLX5E_PFLAG_XDP_TX_MPWQE, mlx5e_tx_mpwqe_supported(mdev));
/* set CQE compression */
params->rx_cqe_compress_def = false;
@@ -5103,7 +5107,7 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv)
mlx5e_set_netdev_mtu_boundaries(priv);
mlx5e_set_dev_port_mtu(priv);
- mlx5_lag_add(mdev, netdev);
+ mlx5_lag_add_netdev(mdev, netdev);
mlx5e_enable_async_events(priv);
mlx5e_enable_blocking_events(priv);
@@ -5151,7 +5155,7 @@ static void mlx5e_nic_disable(struct mlx5e_priv *priv)
priv->en_trap = NULL;
}
mlx5e_disable_async_events(priv);
- mlx5_lag_remove(mdev);
+ mlx5_lag_remove_netdev(mdev, priv->netdev);
mlx5_vxlan_reset_to_default(mdev->vxlan);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 34eb1118670f..bf94bcb6fa5d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -45,11 +45,13 @@
#include "en_tc.h"
#include "en/rep/tc.h"
#include "en/rep/neigh.h"
+#include "en/rep/bridge.h"
#include "en/devlink.h"
#include "fs_core.h"
#include "lib/mlx5.h"
#define CREATE_TRACE_POINTS
#include "diag/en_rep_tracepoint.h"
+#include "en_accel/ipsec.h"
#define MLX5E_REP_PARAMS_DEF_LOG_SQ_SIZE \
max(0x7, MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)
@@ -536,13 +538,13 @@ static const struct net_device_ops mlx5e_netdev_ops_rep = {
.ndo_change_carrier = mlx5e_rep_change_carrier,
};
-bool mlx5e_eswitch_uplink_rep(struct net_device *netdev)
+bool mlx5e_eswitch_uplink_rep(const struct net_device *netdev)
{
return netdev->netdev_ops == &mlx5e_netdev_ops &&
mlx5e_is_uplink_rep(netdev_priv(netdev));
}
-bool mlx5e_eswitch_vf_rep(struct net_device *netdev)
+bool mlx5e_eswitch_vf_rep(const struct net_device *netdev)
{
return netdev->netdev_ops == &mlx5e_netdev_ops_rep;
}
@@ -629,6 +631,11 @@ static int mlx5e_init_ul_rep(struct mlx5_core_dev *mdev,
struct net_device *netdev)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
+ int err;
+
+ err = mlx5e_ipsec_init(priv);
+ if (err)
+ mlx5_core_err(mdev, "Uplink rep IPsec initialization failed, %d\n", err);
mlx5e_vxlan_set_netdev_info(priv);
return mlx5e_init_rep(mdev, netdev);
@@ -636,6 +643,7 @@ static int mlx5e_init_ul_rep(struct mlx5_core_dev *mdev,
static void mlx5e_cleanup_rep(struct mlx5e_priv *priv)
{
+ mlx5e_ipsec_cleanup(priv);
}
static int mlx5e_create_rep_ttc_table(struct mlx5e_priv *priv)
@@ -975,12 +983,13 @@ static void mlx5e_uplink_rep_enable(struct mlx5e_priv *priv)
if (MLX5_CAP_GEN(mdev, uplink_follow))
mlx5_modify_vport_admin_state(mdev, MLX5_VPORT_STATE_OP_MOD_UPLINK,
0, 0, MLX5_VPORT_ADMIN_STATE_AUTO);
- mlx5_lag_add(mdev, netdev);
+ mlx5_lag_add_netdev(mdev, netdev);
priv->events_nb.notifier_call = uplink_rep_async_event;
mlx5_notifier_register(mdev, &priv->events_nb);
mlx5e_dcbnl_initialize(priv);
mlx5e_dcbnl_init_app(priv);
mlx5e_rep_neigh_init(rpriv);
+ mlx5e_rep_bridge_init(priv);
netdev->wanted_features |= NETIF_F_HW_TC;
@@ -1002,11 +1011,12 @@ static void mlx5e_uplink_rep_disable(struct mlx5e_priv *priv)
netif_device_detach(priv->netdev);
rtnl_unlock();
+ mlx5e_rep_bridge_cleanup(priv);
mlx5e_rep_neigh_cleanup(rpriv);
mlx5e_dcbnl_delete_app(priv);
mlx5_notifier_unregister(mdev, &priv->events_nb);
mlx5e_rep_tc_disable(priv);
- mlx5_lag_remove(mdev);
+ mlx5_lag_remove_netdev(mdev, priv->netdev);
}
static MLX5E_DEFINE_STATS_GRP(sw_rep, 0);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
index 22585015c7a7..47a2dfb7792a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
@@ -231,9 +231,9 @@ void mlx5e_remove_sqs_fwd_rules(struct mlx5e_priv *priv);
void mlx5e_rep_queue_neigh_stats_work(struct mlx5e_priv *priv);
-bool mlx5e_eswitch_vf_rep(struct net_device *netdev);
-bool mlx5e_eswitch_uplink_rep(struct net_device *netdev);
-static inline bool mlx5e_eswitch_rep(struct net_device *netdev)
+bool mlx5e_eswitch_vf_rep(const struct net_device *netdev);
+bool mlx5e_eswitch_uplink_rep(const struct net_device *netdev);
+static inline bool mlx5e_eswitch_rep(const struct net_device *netdev)
{
return mlx5e_eswitch_vf_rep(netdev) ||
mlx5e_eswitch_uplink_rep(netdev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index f90894eea9e0..3c65fd0bcf31 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -579,6 +579,9 @@ INDIRECT_CALLABLE_SCOPE bool mlx5e_post_rx_wqes(struct mlx5e_rq *rq)
if (mlx5_wq_cyc_missing(wq) < wqe_bulk)
return false;
+ if (rq->page_pool)
+ page_pool_nid_changed(rq->page_pool, numa_mem_id());
+
do {
u16 head = mlx5_wq_cyc_get_head(wq);
@@ -734,6 +737,9 @@ INDIRECT_CALLABLE_SCOPE bool mlx5e_post_rx_mpwqes(struct mlx5e_rq *rq)
if (likely(missing < UMR_WQE_BULK))
return false;
+ if (rq->page_pool)
+ page_pool_nid_changed(rq->page_pool, numa_mem_id());
+
head = rq->mpwqe.actual_wq_head;
i = missing;
do {
@@ -1310,7 +1316,8 @@ static void mlx5e_handle_rx_cqe_rep(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
if (rep->vlan && skb_vlan_tag_present(skb))
skb_vlan_pop(skb);
- if (!mlx5e_rep_tc_update_skb(cqe, skb, &tc_priv)) {
+ if (unlikely(!mlx5_ipsec_is_rx_flow(cqe) &&
+ !mlx5e_rep_tc_update_skb(cqe, skb, &tc_priv))) {
dev_kfree_skb_any(skb);
goto free_wqe;
}
@@ -1367,7 +1374,8 @@ static void mlx5e_handle_rx_cqe_mpwrq_rep(struct mlx5e_rq *rq, struct mlx5_cqe64
mlx5e_complete_rx_cqe(rq, cqe, cqe_bcnt, skb);
- if (!mlx5e_rep_tc_update_skb(cqe, skb, &tc_priv)) {
+ if (unlikely(!mlx5_ipsec_is_rx_flow(cqe) &&
+ !mlx5e_rep_tc_update_skb(cqe, skb, &tc_priv))) {
dev_kfree_skb_any(skb);
goto mpwrq_cqe_out;
}
@@ -1553,12 +1561,9 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
return 0;
- if (rq->page_pool)
- page_pool_nid_changed(rq->page_pool, numa_mem_id());
-
if (rq->cqd.left) {
work_done += mlx5e_decompress_cqes_cont(rq, cqwq, 0, budget);
- if (rq->cqd.left || work_done >= budget)
+ if (work_done >= budget)
goto out;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index d4b0f270b6bb..629a61e8022f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -83,17 +83,17 @@ struct mlx5e_tc_attr_to_reg_mapping mlx5e_tc_attr_to_reg_mappings[] = {
[CHAIN_TO_REG] = {
.mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_0,
.moffset = 0,
- .mlen = 2,
+ .mlen = 16,
},
[VPORT_TO_REG] = {
.mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_0,
- .moffset = 2,
- .mlen = 2,
+ .moffset = 16,
+ .mlen = 16,
},
[TUNNEL_TO_REG] = {
.mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_1,
- .moffset = 1,
- .mlen = ((ESW_TUN_OPTS_BITS + ESW_TUN_ID_BITS) / 8),
+ .moffset = 8,
+ .mlen = ESW_TUN_OPTS_BITS + ESW_TUN_ID_BITS,
.soffset = MLX5_BYTE_OFF(fte_match_param,
misc_parameters_2.metadata_reg_c_1),
},
@@ -110,7 +110,7 @@ struct mlx5e_tc_attr_to_reg_mapping mlx5e_tc_attr_to_reg_mappings[] = {
[NIC_CHAIN_TO_REG] = {
.mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_B,
.moffset = 0,
- .mlen = 2,
+ .mlen = 16,
},
[NIC_ZONE_RESTORE_TO_REG] = nic_zone_restore_to_reg_ct,
};
@@ -128,23 +128,46 @@ static void mlx5e_put_flow_tunnel_id(struct mlx5e_tc_flow *flow);
void
mlx5e_tc_match_to_reg_match(struct mlx5_flow_spec *spec,
enum mlx5e_tc_attr_to_reg type,
- u32 data,
+ u32 val,
u32 mask)
{
+ void *headers_c = spec->match_criteria, *headers_v = spec->match_value, *fmask, *fval;
int soffset = mlx5e_tc_attr_to_reg_mappings[type].soffset;
+ int moffset = mlx5e_tc_attr_to_reg_mappings[type].moffset;
int match_len = mlx5e_tc_attr_to_reg_mappings[type].mlen;
- void *headers_c = spec->match_criteria;
- void *headers_v = spec->match_value;
- void *fmask, *fval;
+ u32 max_mask = GENMASK(match_len - 1, 0);
+ __be32 curr_mask_be, curr_val_be;
+ u32 curr_mask, curr_val;
fmask = headers_c + soffset;
fval = headers_v + soffset;
- mask = (__force u32)(cpu_to_be32(mask)) >> (32 - (match_len * 8));
- data = (__force u32)(cpu_to_be32(data)) >> (32 - (match_len * 8));
+ memcpy(&curr_mask_be, fmask, 4);
+ memcpy(&curr_val_be, fval, 4);
+
+ curr_mask = be32_to_cpu(curr_mask_be);
+ curr_val = be32_to_cpu(curr_val_be);
+
+ //move to correct offset
+ WARN_ON(mask > max_mask);
+ mask <<= moffset;
+ val <<= moffset;
+ max_mask <<= moffset;
+
+ //zero val and mask
+ curr_mask &= ~max_mask;
+ curr_val &= ~max_mask;
- memcpy(fmask, &mask, match_len);
- memcpy(fval, &data, match_len);
+ //add current to mask
+ curr_mask |= mask;
+ curr_val |= val;
+
+ //back to be32 and write
+ curr_mask_be = cpu_to_be32(curr_mask);
+ curr_val_be = cpu_to_be32(curr_val);
+
+ memcpy(fmask, &curr_mask_be, 4);
+ memcpy(fval, &curr_val_be, 4);
spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
}
@@ -152,23 +175,28 @@ mlx5e_tc_match_to_reg_match(struct mlx5_flow_spec *spec,
void
mlx5e_tc_match_to_reg_get_match(struct mlx5_flow_spec *spec,
enum mlx5e_tc_attr_to_reg type,
- u32 *data,
+ u32 *val,
u32 *mask)
{
+ void *headers_c = spec->match_criteria, *headers_v = spec->match_value, *fmask, *fval;
int soffset = mlx5e_tc_attr_to_reg_mappings[type].soffset;
+ int moffset = mlx5e_tc_attr_to_reg_mappings[type].moffset;
int match_len = mlx5e_tc_attr_to_reg_mappings[type].mlen;
- void *headers_c = spec->match_criteria;
- void *headers_v = spec->match_value;
- void *fmask, *fval;
+ u32 max_mask = GENMASK(match_len - 1, 0);
+ __be32 curr_mask_be, curr_val_be;
+ u32 curr_mask, curr_val;
fmask = headers_c + soffset;
fval = headers_v + soffset;
- memcpy(mask, fmask, match_len);
- memcpy(data, fval, match_len);
+ memcpy(&curr_mask_be, fmask, 4);
+ memcpy(&curr_val_be, fval, 4);
+
+ curr_mask = be32_to_cpu(curr_mask_be);
+ curr_val = be32_to_cpu(curr_val_be);
- *mask = be32_to_cpu((__force __be32)(*mask << (32 - (match_len * 8))));
- *data = be32_to_cpu((__force __be32)(*data << (32 - (match_len * 8))));
+ *mask = (curr_mask >> moffset) & max_mask;
+ *val = (curr_val >> moffset) & max_mask;
}
int
@@ -192,13 +220,13 @@ mlx5e_tc_match_to_reg_set_and_get_id(struct mlx5_core_dev *mdev,
(mod_hdr_acts->num_actions * MLX5_MH_ACT_SZ);
/* Firmware has 5bit length field and 0 means 32bits */
- if (mlen == 4)
+ if (mlen == 32)
mlen = 0;
MLX5_SET(set_action_in, modact, action_type, MLX5_ACTION_TYPE_SET);
MLX5_SET(set_action_in, modact, field, mfield);
- MLX5_SET(set_action_in, modact, offset, moffset * 8);
- MLX5_SET(set_action_in, modact, length, mlen * 8);
+ MLX5_SET(set_action_in, modact, offset, moffset);
+ MLX5_SET(set_action_in, modact, length, mlen);
MLX5_SET(set_action_in, modact, data, data);
err = mod_hdr_acts->num_actions;
mod_hdr_acts->num_actions++;
@@ -296,13 +324,13 @@ void mlx5e_tc_match_to_reg_mod_hdr_change(struct mlx5_core_dev *mdev,
modact = mod_hdr_acts->actions + (act_id * MLX5_MH_ACT_SZ);
/* Firmware has 5bit length field and 0 means 32bits */
- if (mlen == 4)
+ if (mlen == 32)
mlen = 0;
MLX5_SET(set_action_in, modact, action_type, MLX5_ACTION_TYPE_SET);
MLX5_SET(set_action_in, modact, field, mfield);
- MLX5_SET(set_action_in, modact, offset, moffset * 8);
- MLX5_SET(set_action_in, modact, length, mlen * 8);
+ MLX5_SET(set_action_in, modact, offset, moffset);
+ MLX5_SET(set_action_in, modact, length, mlen);
MLX5_SET(set_action_in, modact, data, data);
}
@@ -818,7 +846,7 @@ static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv,
hash_hairpin_info(peer_id, match_prio));
mutex_unlock(&priv->fs.tc.hairpin_tbl_lock);
- params.log_data_size = 15;
+ params.log_data_size = 16;
params.log_data_size = min_t(u8, params.log_data_size,
MLX5_CAP_GEN(priv->mdev, log_max_hairpin_wq_data_sz));
params.log_data_size = max_t(u8, params.log_data_size,
@@ -5105,7 +5133,7 @@ bool mlx5e_tc_update_skb(struct mlx5_cqe64 *cqe,
tc_skb_ext->chain = chain;
- zone_restore_id = (reg_b >> REG_MAPPING_SHIFT(NIC_ZONE_RESTORE_TO_REG)) &
+ zone_restore_id = (reg_b >> REG_MAPPING_MOFFSET(NIC_ZONE_RESTORE_TO_REG)) &
ESW_ZONE_ID_MASK;
if (!mlx5e_tc_ct_restore_flow(tc->ct, skb,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
index 17027536efba..f7cbeb0b66d2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
@@ -129,7 +129,7 @@ struct tunnel_match_enc_opts {
*/
#define TUNNEL_INFO_BITS 12
#define TUNNEL_INFO_BITS_MASK GENMASK(TUNNEL_INFO_BITS - 1, 0)
-#define ENC_OPTS_BITS 12
+#define ENC_OPTS_BITS 11
#define ENC_OPTS_BITS_MASK GENMASK(ENC_OPTS_BITS - 1, 0)
#define TUNNEL_ID_BITS (TUNNEL_INFO_BITS + ENC_OPTS_BITS)
#define TUNNEL_ID_MASK GENMASK(TUNNEL_ID_BITS - 1, 0)
@@ -201,10 +201,10 @@ enum mlx5e_tc_attr_to_reg {
struct mlx5e_tc_attr_to_reg_mapping {
int mfield; /* rewrite field */
- int moffset; /* offset of mfield */
- int mlen; /* bytes to rewrite/match */
+ int moffset; /* bit offset of mfield */
+ int mlen; /* bits to rewrite/match */
- int soffset; /* offset of spec for match */
+ int soffset; /* byte offset of spec for match */
};
extern struct mlx5e_tc_attr_to_reg_mapping mlx5e_tc_attr_to_reg_mappings[];
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
index 320fe0cda917..c63d78eda606 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -687,16 +687,12 @@ void mlx5e_tx_mpwqe_ensure_complete(struct mlx5e_txqsq *sq)
mlx5e_tx_mpwqe_session_complete(sq);
}
-static bool mlx5e_txwqe_build_eseg(struct mlx5e_priv *priv, struct mlx5e_txqsq *sq,
+static void mlx5e_txwqe_build_eseg(struct mlx5e_priv *priv, struct mlx5e_txqsq *sq,
struct sk_buff *skb, struct mlx5e_accel_tx_state *accel,
struct mlx5_wqe_eth_seg *eseg, u16 ihs)
{
- if (unlikely(!mlx5e_accel_tx_eseg(priv, skb, eseg, ihs)))
- return false;
-
+ mlx5e_accel_tx_eseg(priv, skb, eseg, ihs);
mlx5e_txwqe_build_eseg_csum(sq, skb, accel, eseg);
-
- return true;
}
netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -725,10 +721,7 @@ netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev)
if (mlx5e_tx_skb_supports_mpwqe(skb, &attr)) {
struct mlx5_wqe_eth_seg eseg = {};
- if (unlikely(!mlx5e_txwqe_build_eseg(priv, sq, skb, &accel, &eseg,
- attr.ihs)))
- return NETDEV_TX_OK;
-
+ mlx5e_txwqe_build_eseg(priv, sq, skb, &accel, &eseg, attr.ihs);
mlx5e_sq_xmit_mpwqe(sq, skb, &eseg, netdev_xmit_more());
return NETDEV_TX_OK;
}
@@ -743,9 +736,7 @@ netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev)
/* May update the WQE, but may not post other WQEs. */
mlx5e_accel_tx_finish(sq, wqe, &accel,
(struct mlx5_wqe_inline_seg *)(wqe->data + wqe_attr.ds_cnt_inl));
- if (unlikely(!mlx5e_txwqe_build_eseg(priv, sq, skb, &accel, &wqe->eth, attr.ihs)))
- return NETDEV_TX_OK;
-
+ mlx5e_txwqe_build_eseg(priv, sq, skb, &accel, &wqe->eth, attr.ihs);
mlx5e_sq_xmit_wqe(sq, skb, &attr, &wqe_attr, wqe, pi, netdev_xmit_more());
return NETDEV_TX_OK;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index 940333410267..6e074cc457de 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -1,33 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
- * Copyright (c) 2013-2015, Mellanox Technologies. 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.
+ * Copyright (c) 2013-2021, Mellanox Technologies inc. All rights reserved.
*/
#include <linux/interrupt.h>
@@ -45,6 +18,7 @@
#include "eswitch.h"
#include "lib/clock.h"
#include "diag/fw_tracer.h"
+#include "mlx5_irq.h"
enum {
MLX5_EQE_OWNER_INIT_VAL = 0x1,
@@ -84,6 +58,9 @@ struct mlx5_eq_table {
struct mutex lock; /* sync async eqs creations */
int num_comp_eqs;
struct mlx5_irq_table *irq_table;
+#ifdef CONFIG_RFS_ACCEL
+ struct cpu_rmap *rmap;
+#endif
};
#define MLX5_ASYNC_EVENT_MASK ((1ull << MLX5_EVENT_TYPE_PATH_MIG) | \
@@ -288,7 +265,7 @@ create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
u32 out[MLX5_ST_SZ_DW(create_eq_out)] = {0};
u8 log_eq_stride = ilog2(MLX5_EQE_SIZE);
struct mlx5_priv *priv = &dev->priv;
- u8 vecidx = param->irq_index;
+ u16 vecidx = param->irq_index;
__be64 *pas;
void *eqc;
int inlen;
@@ -311,13 +288,20 @@ create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
mlx5_init_fbc(eq->frag_buf.frags, log_eq_stride, log_eq_size, &eq->fbc);
init_eq_buf(eq);
+ eq->irq = mlx5_irq_request(dev, vecidx, param->affinity);
+ if (IS_ERR(eq->irq)) {
+ err = PTR_ERR(eq->irq);
+ goto err_buf;
+ }
+
+ vecidx = mlx5_irq_get_index(eq->irq);
inlen = MLX5_ST_SZ_BYTES(create_eq_in) +
MLX5_FLD_SZ_BYTES(create_eq_in, pas[0]) * eq->frag_buf.npages;
in = kvzalloc(inlen, GFP_KERNEL);
if (!in) {
err = -ENOMEM;
- goto err_buf;
+ goto err_irq;
}
pas = (__be64 *)MLX5_ADDR_OF(create_eq_in, in, pas);
@@ -361,6 +345,8 @@ err_eq:
err_in:
kvfree(in);
+err_irq:
+ mlx5_irq_release(eq->irq);
err_buf:
mlx5_frag_buf_free(dev, &eq->frag_buf);
return err;
@@ -379,10 +365,9 @@ err_buf:
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;
int err;
- err = mlx5_irq_attach_nb(eq_table->irq_table, eq->vecidx, nb);
+ err = mlx5_irq_attach_nb(eq->irq, nb);
if (!err)
eq_update_ci(eq, 1);
@@ -401,9 +386,7 @@ EXPORT_SYMBOL(mlx5_eq_enable);
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);
+ mlx5_irq_detach_nb(eq->irq, nb);
}
EXPORT_SYMBOL(mlx5_eq_disable);
@@ -417,10 +400,9 @@ static int destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
if (err)
mlx5_core_warn(dev, "failed to destroy a previously created eq: eqn %d\n",
eq->eqn);
- synchronize_irq(eq->irqn);
+ mlx5_irq_release(eq->irq);
mlx5_frag_buf_free(dev, &eq->frag_buf);
-
return err;
}
@@ -492,14 +474,7 @@ static int create_async_eq(struct mlx5_core_dev *dev,
int err;
mutex_lock(&eq_table->lock);
- /* Async EQs must share irq index 0 */
- if (param->irq_index != 0) {
- err = -EINVAL;
- goto unlock;
- }
-
err = create_map_eq(dev, eq, param);
-unlock:
mutex_unlock(&eq_table->lock);
return err;
}
@@ -618,8 +593,11 @@ setup_async_eq(struct mlx5_core_dev *dev, struct mlx5_eq_async *eq,
eq->irq_nb.notifier_call = mlx5_eq_async_int;
spin_lock_init(&eq->lock);
+ if (!zalloc_cpumask_var(&param->affinity, GFP_KERNEL))
+ return -ENOMEM;
err = create_async_eq(dev, &eq->core, param);
+ free_cpumask_var(param->affinity);
if (err) {
mlx5_core_warn(dev, "failed to create %s EQ %d\n", name, err);
return err;
@@ -654,7 +632,6 @@ static int create_async_eqs(struct mlx5_core_dev *dev)
mlx5_eq_notifier_register(dev, &table->cq_err_nb);
param = (struct mlx5_eq_param) {
- .irq_index = 0,
.nent = MLX5_NUM_CMD_EQE,
.mask[0] = 1ull << MLX5_EVENT_TYPE_CMD,
};
@@ -667,7 +644,6 @@ static int create_async_eqs(struct mlx5_core_dev *dev)
mlx5_cmd_allowed_opcode(dev, CMD_ALLOWED_OPCODE_ALL);
param = (struct mlx5_eq_param) {
- .irq_index = 0,
.nent = MLX5_NUM_ASYNC_EQE,
};
@@ -677,7 +653,6 @@ static int create_async_eqs(struct mlx5_core_dev *dev)
goto err2;
param = (struct mlx5_eq_param) {
- .irq_index = 0,
.nent = /* TODO: sriov max_vf + */ 1,
.mask[0] = 1ull << MLX5_EVENT_TYPE_PAGE_REQUEST,
};
@@ -737,6 +712,9 @@ mlx5_eq_create_generic(struct mlx5_core_dev *dev,
struct mlx5_eq *eq = kvzalloc(sizeof(*eq), GFP_KERNEL);
int err;
+ if (!cpumask_available(param->affinity))
+ return ERR_PTR(-EINVAL);
+
if (!eq)
return ERR_PTR(-ENOMEM);
@@ -847,16 +825,21 @@ static int create_comp_eqs(struct mlx5_core_dev *dev)
.irq_index = vecidx,
.nent = nent,
};
- err = create_map_eq(dev, &eq->core, &param);
- if (err) {
- kfree(eq);
- goto clean;
+
+ if (!zalloc_cpumask_var(&param.affinity, GFP_KERNEL)) {
+ err = -ENOMEM;
+ goto clean_eq;
}
+ cpumask_set_cpu(cpumask_local_spread(i, dev->priv.numa_node),
+ param.affinity);
+ err = create_map_eq(dev, &eq->core, &param);
+ free_cpumask_var(param.affinity);
+ if (err)
+ goto clean_eq;
err = mlx5_eq_enable(dev, &eq->core, &eq->irq_nb);
if (err) {
destroy_unmap_eq(dev, &eq->core);
- kfree(eq);
- goto clean;
+ goto clean_eq;
}
mlx5_core_dbg(dev, "allocated completion EQN %d\n", eq->core.eqn);
@@ -865,7 +848,8 @@ static int create_comp_eqs(struct mlx5_core_dev *dev)
}
return 0;
-
+clean_eq:
+ kfree(eq);
clean:
destroy_comp_eqs(dev);
return err;
@@ -901,17 +885,23 @@ EXPORT_SYMBOL(mlx5_comp_vectors_count);
struct cpumask *
mlx5_comp_irq_get_affinity_mask(struct mlx5_core_dev *dev, int vector)
{
- int vecidx = vector + MLX5_IRQ_VEC_COMP_BASE;
+ struct mlx5_eq_table *table = dev->priv.eq_table;
+ struct mlx5_eq_comp *eq, *n;
+ int i = 0;
- return mlx5_irq_get_affinity_mask(dev->priv.eq_table->irq_table,
- vecidx);
+ list_for_each_entry_safe(eq, n, &table->comp_eqs_list, list) {
+ if (i++ == vector)
+ break;
+ }
+
+ return mlx5_irq_get_affinity_mask(eq->core.irq);
}
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 mlx5_irq_get_rmap(dev->priv.eq_table->irq_table);
+ return dev->priv.eq_table->rmap;
}
#endif
@@ -928,12 +918,57 @@ struct mlx5_eq_comp *mlx5_eqn2comp_eq(struct mlx5_core_dev *dev, int eqn)
return ERR_PTR(-ENOENT);
}
+static void clear_rmap(struct mlx5_core_dev *dev)
+{
+#ifdef CONFIG_RFS_ACCEL
+ struct mlx5_eq_table *eq_table = dev->priv.eq_table;
+
+ free_irq_cpu_rmap(eq_table->rmap);
+#endif
+}
+
+static int set_rmap(struct mlx5_core_dev *mdev)
+{
+ int err = 0;
+#ifdef CONFIG_RFS_ACCEL
+ struct mlx5_eq_table *eq_table = mdev->priv.eq_table;
+ int vecidx;
+
+ eq_table->rmap = alloc_irq_cpu_rmap(eq_table->num_comp_eqs);
+ if (!eq_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 < eq_table->num_comp_eqs + MLX5_IRQ_VEC_COMP_BASE;
+ vecidx++) {
+ err = irq_cpu_rmap_add(eq_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:
+ clear_rmap(mdev);
+err_out:
+#endif
+ return err;
+}
+
/* This function should only be called after mlx5_cmd_force_teardown_hca */
void mlx5_core_eq_free_irqs(struct mlx5_core_dev *dev)
{
struct mlx5_eq_table *table = dev->priv.eq_table;
mutex_lock(&table->lock); /* sync with create/destroy_async_eq */
+ if (!mlx5_core_is_sf(dev))
+ clear_rmap(dev);
mlx5_irq_table_destroy(dev);
mutex_unlock(&table->lock);
}
@@ -950,12 +985,19 @@ int mlx5_eq_table_create(struct mlx5_core_dev *dev)
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 max_eqs_sf;
int err;
eq_table->num_comp_eqs =
min_t(int,
- mlx5_irq_get_num_comp(eq_table->irq_table),
+ mlx5_irq_table_get_num_comp(eq_table->irq_table),
num_eqs - MLX5_MAX_ASYNC_EQS);
+ if (mlx5_core_is_sf(dev)) {
+ max_eqs_sf = min_t(int, MLX5_COMP_EQS_PER_SF,
+ mlx5_irq_table_get_sfs_vec(eq_table->irq_table));
+ eq_table->num_comp_eqs = min_t(int, eq_table->num_comp_eqs,
+ max_eqs_sf);
+ }
err = create_async_eqs(dev);
if (err) {
@@ -963,6 +1005,18 @@ int mlx5_eq_table_create(struct mlx5_core_dev *dev)
goto err_async_eqs;
}
+ if (!mlx5_core_is_sf(dev)) {
+ /* rmap is a mapping between irq number and queue number.
+ * each irq can be assign only to a single rmap.
+ * since SFs share IRQs, rmap mapping cannot function correctly
+ * for irqs that are shared for different core/netdev RX rings.
+ * Hence we don't allow netdev rmap for SFs
+ */
+ err = set_rmap(dev);
+ if (err)
+ goto err_rmap;
+ }
+
err = create_comp_eqs(dev);
if (err) {
mlx5_core_err(dev, "Failed to create completion EQs\n");
@@ -971,6 +1025,9 @@ int mlx5_eq_table_create(struct mlx5_core_dev *dev)
return 0;
err_comp_eqs:
+ if (!mlx5_core_is_sf(dev))
+ clear_rmap(dev);
+err_rmap:
destroy_async_eqs(dev);
err_async_eqs:
return err;
@@ -978,6 +1035,8 @@ err_async_eqs:
void mlx5_eq_table_destroy(struct mlx5_core_dev *dev)
{
+ if (!mlx5_core_is_sf(dev))
+ clear_rmap(dev);
destroy_comp_eqs(dev);
destroy_async_eqs(dev);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c
new file mode 100644
index 000000000000..a6e1d4f78268
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c
@@ -0,0 +1,1299 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2021 Mellanox Technologies. */
+
+#include <linux/list.h>
+#include <linux/notifier.h>
+#include <net/netevent.h>
+#include <net/switchdev.h>
+#include "bridge.h"
+#include "eswitch.h"
+#include "bridge_priv.h"
+#define CREATE_TRACE_POINTS
+#include "diag/bridge_tracepoint.h"
+
+#define MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE 64000
+#define MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_FROM 0
+#define MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_TO (MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE / 4 - 1)
+#define MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_FROM \
+ (MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_TO + 1)
+#define MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_TO \
+ (MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE / 2 - 1)
+#define MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_FROM \
+ (MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_TO + 1)
+#define MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_TO (MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE - 1)
+
+#define MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE 64000
+#define MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_FROM 0
+#define MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_TO (MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE / 2 - 1)
+#define MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_FROM \
+ (MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_TO + 1)
+#define MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_TO (MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE - 1)
+
+#define MLX5_ESW_BRIDGE_SKIP_TABLE_SIZE 0
+
+enum {
+ MLX5_ESW_BRIDGE_LEVEL_INGRESS_TABLE,
+ MLX5_ESW_BRIDGE_LEVEL_EGRESS_TABLE,
+ MLX5_ESW_BRIDGE_LEVEL_SKIP_TABLE,
+};
+
+static const struct rhashtable_params fdb_ht_params = {
+ .key_offset = offsetof(struct mlx5_esw_bridge_fdb_entry, key),
+ .key_len = sizeof(struct mlx5_esw_bridge_fdb_key),
+ .head_offset = offsetof(struct mlx5_esw_bridge_fdb_entry, ht_node),
+ .automatic_shrinking = true,
+};
+
+enum {
+ MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG = BIT(0),
+};
+
+struct mlx5_esw_bridge {
+ int ifindex;
+ int refcnt;
+ struct list_head list;
+ struct mlx5_esw_bridge_offloads *br_offloads;
+
+ struct list_head fdb_list;
+ struct rhashtable fdb_ht;
+ struct xarray vports;
+
+ struct mlx5_flow_table *egress_ft;
+ struct mlx5_flow_group *egress_vlan_fg;
+ struct mlx5_flow_group *egress_mac_fg;
+ unsigned long ageing_time;
+ u32 flags;
+};
+
+static void
+mlx5_esw_bridge_fdb_offload_notify(struct net_device *dev, const unsigned char *addr, u16 vid,
+ unsigned long val)
+{
+ struct switchdev_notifier_fdb_info send_info;
+
+ send_info.addr = addr;
+ send_info.vid = vid;
+ send_info.offloaded = true;
+ call_switchdev_notifiers(val, dev, &send_info.info, NULL);
+}
+
+static struct mlx5_flow_table *
+mlx5_esw_bridge_table_create(int max_fte, u32 level, struct mlx5_eswitch *esw)
+{
+ struct mlx5_flow_table_attr ft_attr = {};
+ struct mlx5_core_dev *dev = esw->dev;
+ struct mlx5_flow_namespace *ns;
+ struct mlx5_flow_table *fdb;
+
+ ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
+ if (!ns) {
+ esw_warn(dev, "Failed to get FDB namespace\n");
+ return ERR_PTR(-ENOENT);
+ }
+
+ ft_attr.flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
+ ft_attr.max_fte = max_fte;
+ ft_attr.level = level;
+ ft_attr.prio = FDB_BR_OFFLOAD;
+ fdb = mlx5_create_flow_table(ns, &ft_attr);
+ if (IS_ERR(fdb))
+ esw_warn(dev, "Failed to create bridge FDB Table (err=%ld)\n", PTR_ERR(fdb));
+
+ return fdb;
+}
+
+static struct mlx5_flow_group *
+mlx5_esw_bridge_ingress_vlan_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *ingress_ft)
+{
+ int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+ struct mlx5_flow_group *fg;
+ u32 *in, *match;
+
+ in = kvzalloc(inlen, GFP_KERNEL);
+ if (!in)
+ return ERR_PTR(-ENOMEM);
+
+ MLX5_SET(create_flow_group_in, in, match_criteria_enable,
+ MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2);
+ match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
+
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_47_16);
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_15_0);
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag);
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.first_vid);
+
+ MLX5_SET(fte_match_param, match, misc_parameters_2.metadata_reg_c_0,
+ mlx5_eswitch_get_vport_metadata_mask());
+
+ MLX5_SET(create_flow_group_in, in, start_flow_index,
+ MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_FROM);
+ MLX5_SET(create_flow_group_in, in, end_flow_index,
+ MLX5_ESW_BRIDGE_INGRESS_TABLE_VLAN_GRP_IDX_TO);
+
+ fg = mlx5_create_flow_group(ingress_ft, in);
+ kvfree(in);
+ if (IS_ERR(fg))
+ esw_warn(esw->dev,
+ "Failed to create VLAN flow group for bridge ingress table (err=%ld)\n",
+ PTR_ERR(fg));
+
+ return fg;
+}
+
+static struct mlx5_flow_group *
+mlx5_esw_bridge_ingress_filter_fg_create(struct mlx5_eswitch *esw,
+ struct mlx5_flow_table *ingress_ft)
+{
+ int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+ struct mlx5_flow_group *fg;
+ u32 *in, *match;
+
+ in = kvzalloc(inlen, GFP_KERNEL);
+ if (!in)
+ return ERR_PTR(-ENOMEM);
+
+ MLX5_SET(create_flow_group_in, in, match_criteria_enable,
+ MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2);
+ match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
+
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_47_16);
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_15_0);
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag);
+
+ MLX5_SET(fte_match_param, match, misc_parameters_2.metadata_reg_c_0,
+ mlx5_eswitch_get_vport_metadata_mask());
+
+ MLX5_SET(create_flow_group_in, in, start_flow_index,
+ MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_FROM);
+ MLX5_SET(create_flow_group_in, in, end_flow_index,
+ MLX5_ESW_BRIDGE_INGRESS_TABLE_FILTER_GRP_IDX_TO);
+
+ fg = mlx5_create_flow_group(ingress_ft, in);
+ if (IS_ERR(fg))
+ esw_warn(esw->dev,
+ "Failed to create bridge ingress table VLAN filter flow group (err=%ld)\n",
+ PTR_ERR(fg));
+
+ kvfree(in);
+ return fg;
+}
+
+static struct mlx5_flow_group *
+mlx5_esw_bridge_ingress_mac_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *ingress_ft)
+{
+ int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+ struct mlx5_flow_group *fg;
+ u32 *in, *match;
+
+ in = kvzalloc(inlen, GFP_KERNEL);
+ if (!in)
+ return ERR_PTR(-ENOMEM);
+
+ MLX5_SET(create_flow_group_in, in, match_criteria_enable,
+ MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2);
+ match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
+
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_47_16);
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.smac_15_0);
+
+ MLX5_SET(fte_match_param, match, misc_parameters_2.metadata_reg_c_0,
+ mlx5_eswitch_get_vport_metadata_mask());
+
+ MLX5_SET(create_flow_group_in, in, start_flow_index,
+ MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_FROM);
+ MLX5_SET(create_flow_group_in, in, end_flow_index,
+ MLX5_ESW_BRIDGE_INGRESS_TABLE_MAC_GRP_IDX_TO);
+
+ fg = mlx5_create_flow_group(ingress_ft, in);
+ if (IS_ERR(fg))
+ esw_warn(esw->dev,
+ "Failed to create MAC flow group for bridge ingress table (err=%ld)\n",
+ PTR_ERR(fg));
+
+ kvfree(in);
+ return fg;
+}
+
+static struct mlx5_flow_group *
+mlx5_esw_bridge_egress_vlan_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *egress_ft)
+{
+ int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+ struct mlx5_flow_group *fg;
+ u32 *in, *match;
+
+ in = kvzalloc(inlen, GFP_KERNEL);
+ if (!in)
+ return ERR_PTR(-ENOMEM);
+
+ MLX5_SET(create_flow_group_in, in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
+ match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
+
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.dmac_47_16);
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.dmac_15_0);
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.cvlan_tag);
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.first_vid);
+
+ MLX5_SET(create_flow_group_in, in, start_flow_index,
+ MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_FROM);
+ MLX5_SET(create_flow_group_in, in, end_flow_index,
+ MLX5_ESW_BRIDGE_EGRESS_TABLE_VLAN_GRP_IDX_TO);
+
+ fg = mlx5_create_flow_group(egress_ft, in);
+ if (IS_ERR(fg))
+ esw_warn(esw->dev,
+ "Failed to create VLAN flow group for bridge egress table (err=%ld)\n",
+ PTR_ERR(fg));
+ kvfree(in);
+ return fg;
+}
+
+static struct mlx5_flow_group *
+mlx5_esw_bridge_egress_mac_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *egress_ft)
+{
+ int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+ struct mlx5_flow_group *fg;
+ u32 *in, *match;
+
+ in = kvzalloc(inlen, GFP_KERNEL);
+ if (!in)
+ return ERR_PTR(-ENOMEM);
+
+ MLX5_SET(create_flow_group_in, in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
+ match = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
+
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.dmac_47_16);
+ MLX5_SET_TO_ONES(fte_match_param, match, outer_headers.dmac_15_0);
+
+ MLX5_SET(create_flow_group_in, in, start_flow_index,
+ MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_FROM);
+ MLX5_SET(create_flow_group_in, in, end_flow_index,
+ MLX5_ESW_BRIDGE_EGRESS_TABLE_MAC_GRP_IDX_TO);
+
+ fg = mlx5_create_flow_group(egress_ft, in);
+ if (IS_ERR(fg))
+ esw_warn(esw->dev,
+ "Failed to create bridge egress table MAC flow group (err=%ld)\n",
+ PTR_ERR(fg));
+ kvfree(in);
+ return fg;
+}
+
+static int
+mlx5_esw_bridge_ingress_table_init(struct mlx5_esw_bridge_offloads *br_offloads)
+{
+ struct mlx5_flow_group *mac_fg, *filter_fg, *vlan_fg;
+ struct mlx5_flow_table *ingress_ft, *skip_ft;
+ int err;
+
+ if (!mlx5_eswitch_vport_match_metadata_enabled(br_offloads->esw))
+ return -EOPNOTSUPP;
+
+ ingress_ft = mlx5_esw_bridge_table_create(MLX5_ESW_BRIDGE_INGRESS_TABLE_SIZE,
+ MLX5_ESW_BRIDGE_LEVEL_INGRESS_TABLE,
+ br_offloads->esw);
+ if (IS_ERR(ingress_ft))
+ return PTR_ERR(ingress_ft);
+
+ skip_ft = mlx5_esw_bridge_table_create(MLX5_ESW_BRIDGE_SKIP_TABLE_SIZE,
+ MLX5_ESW_BRIDGE_LEVEL_SKIP_TABLE,
+ br_offloads->esw);
+ if (IS_ERR(skip_ft)) {
+ err = PTR_ERR(skip_ft);
+ goto err_skip_tbl;
+ }
+
+ vlan_fg = mlx5_esw_bridge_ingress_vlan_fg_create(br_offloads->esw, ingress_ft);
+ if (IS_ERR(vlan_fg)) {
+ err = PTR_ERR(vlan_fg);
+ goto err_vlan_fg;
+ }
+
+ filter_fg = mlx5_esw_bridge_ingress_filter_fg_create(br_offloads->esw, ingress_ft);
+ if (IS_ERR(filter_fg)) {
+ err = PTR_ERR(filter_fg);
+ goto err_filter_fg;
+ }
+
+ mac_fg = mlx5_esw_bridge_ingress_mac_fg_create(br_offloads->esw, ingress_ft);
+ if (IS_ERR(mac_fg)) {
+ err = PTR_ERR(mac_fg);
+ goto err_mac_fg;
+ }
+
+ br_offloads->ingress_ft = ingress_ft;
+ br_offloads->skip_ft = skip_ft;
+ br_offloads->ingress_vlan_fg = vlan_fg;
+ br_offloads->ingress_filter_fg = filter_fg;
+ br_offloads->ingress_mac_fg = mac_fg;
+ return 0;
+
+err_mac_fg:
+ mlx5_destroy_flow_group(filter_fg);
+err_filter_fg:
+ mlx5_destroy_flow_group(vlan_fg);
+err_vlan_fg:
+ mlx5_destroy_flow_table(skip_ft);
+err_skip_tbl:
+ mlx5_destroy_flow_table(ingress_ft);
+ return err;
+}
+
+static void
+mlx5_esw_bridge_ingress_table_cleanup(struct mlx5_esw_bridge_offloads *br_offloads)
+{
+ mlx5_destroy_flow_group(br_offloads->ingress_mac_fg);
+ br_offloads->ingress_mac_fg = NULL;
+ mlx5_destroy_flow_group(br_offloads->ingress_filter_fg);
+ br_offloads->ingress_filter_fg = NULL;
+ mlx5_destroy_flow_group(br_offloads->ingress_vlan_fg);
+ br_offloads->ingress_vlan_fg = NULL;
+ mlx5_destroy_flow_table(br_offloads->skip_ft);
+ br_offloads->skip_ft = NULL;
+ mlx5_destroy_flow_table(br_offloads->ingress_ft);
+ br_offloads->ingress_ft = NULL;
+}
+
+static int
+mlx5_esw_bridge_egress_table_init(struct mlx5_esw_bridge_offloads *br_offloads,
+ struct mlx5_esw_bridge *bridge)
+{
+ struct mlx5_flow_group *mac_fg, *vlan_fg;
+ struct mlx5_flow_table *egress_ft;
+ int err;
+
+ egress_ft = mlx5_esw_bridge_table_create(MLX5_ESW_BRIDGE_EGRESS_TABLE_SIZE,
+ MLX5_ESW_BRIDGE_LEVEL_EGRESS_TABLE,
+ br_offloads->esw);
+ if (IS_ERR(egress_ft))
+ return PTR_ERR(egress_ft);
+
+ vlan_fg = mlx5_esw_bridge_egress_vlan_fg_create(br_offloads->esw, egress_ft);
+ if (IS_ERR(vlan_fg)) {
+ err = PTR_ERR(vlan_fg);
+ goto err_vlan_fg;
+ }
+
+ mac_fg = mlx5_esw_bridge_egress_mac_fg_create(br_offloads->esw, egress_ft);
+ if (IS_ERR(mac_fg)) {
+ err = PTR_ERR(mac_fg);
+ goto err_mac_fg;
+ }
+
+ bridge->egress_ft = egress_ft;
+ bridge->egress_vlan_fg = vlan_fg;
+ bridge->egress_mac_fg = mac_fg;
+ return 0;
+
+err_mac_fg:
+ mlx5_destroy_flow_group(vlan_fg);
+err_vlan_fg:
+ mlx5_destroy_flow_table(egress_ft);
+ return err;
+}
+
+static void
+mlx5_esw_bridge_egress_table_cleanup(struct mlx5_esw_bridge *bridge)
+{
+ mlx5_destroy_flow_group(bridge->egress_mac_fg);
+ mlx5_destroy_flow_group(bridge->egress_vlan_fg);
+ mlx5_destroy_flow_table(bridge->egress_ft);
+}
+
+static struct mlx5_flow_handle *
+mlx5_esw_bridge_ingress_flow_create(u16 vport_num, const unsigned char *addr,
+ struct mlx5_esw_bridge_vlan *vlan, u32 counter_id,
+ struct mlx5_esw_bridge *bridge)
+{
+ struct mlx5_esw_bridge_offloads *br_offloads = bridge->br_offloads;
+ struct mlx5_flow_act flow_act = {
+ .action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_COUNT,
+ .flags = FLOW_ACT_NO_APPEND,
+ };
+ struct mlx5_flow_destination dests[2] = {};
+ struct mlx5_flow_spec *rule_spec;
+ struct mlx5_flow_handle *handle;
+ u8 *smac_v, *smac_c;
+
+ rule_spec = kvzalloc(sizeof(*rule_spec), GFP_KERNEL);
+ if (!rule_spec)
+ return ERR_PTR(-ENOMEM);
+
+ rule_spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2;
+
+ smac_v = MLX5_ADDR_OF(fte_match_param, rule_spec->match_value,
+ outer_headers.smac_47_16);
+ ether_addr_copy(smac_v, addr);
+ smac_c = MLX5_ADDR_OF(fte_match_param, rule_spec->match_criteria,
+ outer_headers.smac_47_16);
+ eth_broadcast_addr(smac_c);
+
+ MLX5_SET(fte_match_param, rule_spec->match_criteria,
+ misc_parameters_2.metadata_reg_c_0, mlx5_eswitch_get_vport_metadata_mask());
+ MLX5_SET(fte_match_param, rule_spec->match_value, misc_parameters_2.metadata_reg_c_0,
+ mlx5_eswitch_get_vport_metadata_for_match(br_offloads->esw, vport_num));
+
+ if (vlan && vlan->pkt_reformat_push) {
+ flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
+ flow_act.pkt_reformat = vlan->pkt_reformat_push;
+ } else if (vlan) {
+ MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
+ outer_headers.cvlan_tag);
+ MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
+ outer_headers.cvlan_tag);
+ MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
+ outer_headers.first_vid);
+ MLX5_SET(fte_match_param, rule_spec->match_value, outer_headers.first_vid,
+ vlan->vid);
+ }
+
+ dests[0].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+ dests[0].ft = bridge->egress_ft;
+ dests[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
+ dests[1].counter_id = counter_id;
+
+ handle = mlx5_add_flow_rules(br_offloads->ingress_ft, rule_spec, &flow_act, dests,
+ ARRAY_SIZE(dests));
+
+ kvfree(rule_spec);
+ return handle;
+}
+
+static struct mlx5_flow_handle *
+mlx5_esw_bridge_ingress_filter_flow_create(u16 vport_num, const unsigned char *addr,
+ struct mlx5_esw_bridge *bridge)
+{
+ struct mlx5_esw_bridge_offloads *br_offloads = bridge->br_offloads;
+ struct mlx5_flow_destination dest = {
+ .type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE,
+ .ft = br_offloads->skip_ft,
+ };
+ struct mlx5_flow_act flow_act = {
+ .action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
+ .flags = FLOW_ACT_NO_APPEND,
+ };
+ struct mlx5_flow_spec *rule_spec;
+ struct mlx5_flow_handle *handle;
+ u8 *smac_v, *smac_c;
+
+ rule_spec = kvzalloc(sizeof(*rule_spec), GFP_KERNEL);
+ if (!rule_spec)
+ return ERR_PTR(-ENOMEM);
+
+ rule_spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS_2;
+
+ smac_v = MLX5_ADDR_OF(fte_match_param, rule_spec->match_value,
+ outer_headers.smac_47_16);
+ ether_addr_copy(smac_v, addr);
+ smac_c = MLX5_ADDR_OF(fte_match_param, rule_spec->match_criteria,
+ outer_headers.smac_47_16);
+ eth_broadcast_addr(smac_c);
+
+ MLX5_SET(fte_match_param, rule_spec->match_criteria,
+ misc_parameters_2.metadata_reg_c_0, mlx5_eswitch_get_vport_metadata_mask());
+ MLX5_SET(fte_match_param, rule_spec->match_value, misc_parameters_2.metadata_reg_c_0,
+ mlx5_eswitch_get_vport_metadata_for_match(br_offloads->esw, vport_num));
+
+ MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
+ outer_headers.cvlan_tag);
+ MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
+ outer_headers.cvlan_tag);
+
+ handle = mlx5_add_flow_rules(br_offloads->ingress_ft, rule_spec, &flow_act, &dest, 1);
+
+ kvfree(rule_spec);
+ return handle;
+}
+
+static struct mlx5_flow_handle *
+mlx5_esw_bridge_egress_flow_create(u16 vport_num, const unsigned char *addr,
+ struct mlx5_esw_bridge_vlan *vlan,
+ struct mlx5_esw_bridge *bridge)
+{
+ struct mlx5_flow_destination dest = {
+ .type = MLX5_FLOW_DESTINATION_TYPE_VPORT,
+ .vport.num = vport_num,
+ };
+ struct mlx5_flow_act flow_act = {
+ .action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
+ .flags = FLOW_ACT_NO_APPEND,
+ };
+ struct mlx5_flow_spec *rule_spec;
+ struct mlx5_flow_handle *handle;
+ u8 *dmac_v, *dmac_c;
+
+ rule_spec = kvzalloc(sizeof(*rule_spec), GFP_KERNEL);
+ if (!rule_spec)
+ return ERR_PTR(-ENOMEM);
+
+ rule_spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+
+ dmac_v = MLX5_ADDR_OF(fte_match_param, rule_spec->match_value,
+ outer_headers.dmac_47_16);
+ ether_addr_copy(dmac_v, addr);
+ dmac_c = MLX5_ADDR_OF(fte_match_param, rule_spec->match_criteria,
+ outer_headers.dmac_47_16);
+ eth_broadcast_addr(dmac_c);
+
+ if (vlan) {
+ if (vlan->pkt_reformat_pop) {
+ flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
+ flow_act.pkt_reformat = vlan->pkt_reformat_pop;
+ }
+
+ MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
+ outer_headers.cvlan_tag);
+ MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_value,
+ outer_headers.cvlan_tag);
+ MLX5_SET_TO_ONES(fte_match_param, rule_spec->match_criteria,
+ outer_headers.first_vid);
+ MLX5_SET(fte_match_param, rule_spec->match_value, outer_headers.first_vid,
+ vlan->vid);
+ }
+
+ handle = mlx5_add_flow_rules(bridge->egress_ft, rule_spec, &flow_act, &dest, 1);
+
+ kvfree(rule_spec);
+ return handle;
+}
+
+static struct mlx5_esw_bridge *mlx5_esw_bridge_create(int ifindex,
+ struct mlx5_esw_bridge_offloads *br_offloads)
+{
+ struct mlx5_esw_bridge *bridge;
+ int err;
+
+ bridge = kvzalloc(sizeof(*bridge), GFP_KERNEL);
+ if (!bridge)
+ return ERR_PTR(-ENOMEM);
+
+ bridge->br_offloads = br_offloads;
+ err = mlx5_esw_bridge_egress_table_init(br_offloads, bridge);
+ if (err)
+ goto err_egress_tbl;
+
+ err = rhashtable_init(&bridge->fdb_ht, &fdb_ht_params);
+ if (err)
+ goto err_fdb_ht;
+
+ INIT_LIST_HEAD(&bridge->fdb_list);
+ xa_init(&bridge->vports);
+ bridge->ifindex = ifindex;
+ bridge->refcnt = 1;
+ bridge->ageing_time = BR_DEFAULT_AGEING_TIME;
+ list_add(&bridge->list, &br_offloads->bridges);
+
+ return bridge;
+
+err_fdb_ht:
+ mlx5_esw_bridge_egress_table_cleanup(bridge);
+err_egress_tbl:
+ kvfree(bridge);
+ return ERR_PTR(err);
+}
+
+static void mlx5_esw_bridge_get(struct mlx5_esw_bridge *bridge)
+{
+ bridge->refcnt++;
+}
+
+static void mlx5_esw_bridge_put(struct mlx5_esw_bridge_offloads *br_offloads,
+ struct mlx5_esw_bridge *bridge)
+{
+ if (--bridge->refcnt)
+ return;
+
+ mlx5_esw_bridge_egress_table_cleanup(bridge);
+ WARN_ON(!xa_empty(&bridge->vports));
+ list_del(&bridge->list);
+ rhashtable_destroy(&bridge->fdb_ht);
+ kvfree(bridge);
+
+ if (list_empty(&br_offloads->bridges))
+ mlx5_esw_bridge_ingress_table_cleanup(br_offloads);
+}
+
+static struct mlx5_esw_bridge *
+mlx5_esw_bridge_lookup(int ifindex, struct mlx5_esw_bridge_offloads *br_offloads)
+{
+ struct mlx5_esw_bridge *bridge;
+
+ ASSERT_RTNL();
+
+ list_for_each_entry(bridge, &br_offloads->bridges, list) {
+ if (bridge->ifindex == ifindex) {
+ mlx5_esw_bridge_get(bridge);
+ return bridge;
+ }
+ }
+
+ if (!br_offloads->ingress_ft) {
+ int err = mlx5_esw_bridge_ingress_table_init(br_offloads);
+
+ if (err)
+ return ERR_PTR(err);
+ }
+
+ bridge = mlx5_esw_bridge_create(ifindex, br_offloads);
+ if (IS_ERR(bridge) && list_empty(&br_offloads->bridges))
+ mlx5_esw_bridge_ingress_table_cleanup(br_offloads);
+ return bridge;
+}
+
+static int mlx5_esw_bridge_port_insert(struct mlx5_esw_bridge_port *port,
+ struct mlx5_esw_bridge *bridge)
+{
+ return xa_insert(&bridge->vports, port->vport_num, port, GFP_KERNEL);
+}
+
+static struct mlx5_esw_bridge_port *
+mlx5_esw_bridge_port_lookup(u16 vport_num, struct mlx5_esw_bridge *bridge)
+{
+ return xa_load(&bridge->vports, vport_num);
+}
+
+static void mlx5_esw_bridge_port_erase(struct mlx5_esw_bridge_port *port,
+ struct mlx5_esw_bridge *bridge)
+{
+ xa_erase(&bridge->vports, port->vport_num);
+}
+
+static void mlx5_esw_bridge_fdb_entry_refresh(unsigned long lastuse,
+ struct mlx5_esw_bridge_fdb_entry *entry)
+{
+ trace_mlx5_esw_bridge_fdb_entry_refresh(entry);
+
+ entry->lastuse = lastuse;
+ mlx5_esw_bridge_fdb_offload_notify(entry->dev, entry->key.addr,
+ entry->key.vid,
+ SWITCHDEV_FDB_ADD_TO_BRIDGE);
+}
+
+static void
+mlx5_esw_bridge_fdb_entry_cleanup(struct mlx5_esw_bridge_fdb_entry *entry,
+ struct mlx5_esw_bridge *bridge)
+{
+ trace_mlx5_esw_bridge_fdb_entry_cleanup(entry);
+
+ rhashtable_remove_fast(&bridge->fdb_ht, &entry->ht_node, fdb_ht_params);
+ mlx5_del_flow_rules(entry->egress_handle);
+ if (entry->filter_handle)
+ mlx5_del_flow_rules(entry->filter_handle);
+ mlx5_del_flow_rules(entry->ingress_handle);
+ mlx5_fc_destroy(bridge->br_offloads->esw->dev, entry->ingress_counter);
+ list_del(&entry->vlan_list);
+ list_del(&entry->list);
+ kvfree(entry);
+}
+
+static void mlx5_esw_bridge_fdb_flush(struct mlx5_esw_bridge *bridge)
+{
+ struct mlx5_esw_bridge_fdb_entry *entry, *tmp;
+
+ list_for_each_entry_safe(entry, tmp, &bridge->fdb_list, list) {
+ if (!(entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER))
+ mlx5_esw_bridge_fdb_offload_notify(entry->dev, entry->key.addr,
+ entry->key.vid,
+ SWITCHDEV_FDB_DEL_TO_BRIDGE);
+ mlx5_esw_bridge_fdb_entry_cleanup(entry, bridge);
+ }
+}
+
+static struct mlx5_esw_bridge_vlan *
+mlx5_esw_bridge_vlan_lookup(u16 vid, struct mlx5_esw_bridge_port *port)
+{
+ return xa_load(&port->vlans, vid);
+}
+
+static int
+mlx5_esw_bridge_vlan_push_create(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw)
+{
+ struct {
+ __be16 h_vlan_proto;
+ __be16 h_vlan_TCI;
+ } vlan_hdr = { htons(ETH_P_8021Q), htons(vlan->vid) };
+ struct mlx5_pkt_reformat_params reformat_params = {};
+ struct mlx5_pkt_reformat *pkt_reformat;
+
+ if (!BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, reformat_insert)) ||
+ MLX5_CAP_GEN_2(esw->dev, max_reformat_insert_size) < sizeof(vlan_hdr) ||
+ MLX5_CAP_GEN_2(esw->dev, max_reformat_insert_offset) <
+ offsetof(struct vlan_ethhdr, h_vlan_proto)) {
+ esw_warn(esw->dev, "Packet reformat INSERT_HEADER is not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ reformat_params.type = MLX5_REFORMAT_TYPE_INSERT_HDR;
+ reformat_params.param_0 = MLX5_REFORMAT_CONTEXT_ANCHOR_MAC_START;
+ reformat_params.param_1 = offsetof(struct vlan_ethhdr, h_vlan_proto);
+ reformat_params.size = sizeof(vlan_hdr);
+ reformat_params.data = &vlan_hdr;
+ pkt_reformat = mlx5_packet_reformat_alloc(esw->dev,
+ &reformat_params,
+ MLX5_FLOW_NAMESPACE_FDB);
+ if (IS_ERR(pkt_reformat)) {
+ esw_warn(esw->dev, "Failed to alloc packet reformat INSERT_HEADER (err=%ld)\n",
+ PTR_ERR(pkt_reformat));
+ return PTR_ERR(pkt_reformat);
+ }
+
+ vlan->pkt_reformat_push = pkt_reformat;
+ return 0;
+}
+
+static void
+mlx5_esw_bridge_vlan_push_cleanup(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw)
+{
+ mlx5_packet_reformat_dealloc(esw->dev, vlan->pkt_reformat_push);
+ vlan->pkt_reformat_push = NULL;
+}
+
+static int
+mlx5_esw_bridge_vlan_pop_create(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw)
+{
+ struct mlx5_pkt_reformat_params reformat_params = {};
+ struct mlx5_pkt_reformat *pkt_reformat;
+
+ if (!BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, reformat_remove)) ||
+ MLX5_CAP_GEN_2(esw->dev, max_reformat_remove_size) < sizeof(struct vlan_hdr) ||
+ MLX5_CAP_GEN_2(esw->dev, max_reformat_remove_offset) <
+ offsetof(struct vlan_ethhdr, h_vlan_proto)) {
+ esw_warn(esw->dev, "Packet reformat REMOVE_HEADER is not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ reformat_params.type = MLX5_REFORMAT_TYPE_REMOVE_HDR;
+ reformat_params.param_0 = MLX5_REFORMAT_CONTEXT_ANCHOR_MAC_START;
+ reformat_params.param_1 = offsetof(struct vlan_ethhdr, h_vlan_proto);
+ reformat_params.size = sizeof(struct vlan_hdr);
+ pkt_reformat = mlx5_packet_reformat_alloc(esw->dev,
+ &reformat_params,
+ MLX5_FLOW_NAMESPACE_FDB);
+ if (IS_ERR(pkt_reformat)) {
+ esw_warn(esw->dev, "Failed to alloc packet reformat REMOVE_HEADER (err=%ld)\n",
+ PTR_ERR(pkt_reformat));
+ return PTR_ERR(pkt_reformat);
+ }
+
+ vlan->pkt_reformat_pop = pkt_reformat;
+ return 0;
+}
+
+static void
+mlx5_esw_bridge_vlan_pop_cleanup(struct mlx5_esw_bridge_vlan *vlan, struct mlx5_eswitch *esw)
+{
+ mlx5_packet_reformat_dealloc(esw->dev, vlan->pkt_reformat_pop);
+ vlan->pkt_reformat_pop = NULL;
+}
+
+static struct mlx5_esw_bridge_vlan *
+mlx5_esw_bridge_vlan_create(u16 vid, u16 flags, struct mlx5_esw_bridge_port *port,
+ struct mlx5_eswitch *esw)
+{
+ struct mlx5_esw_bridge_vlan *vlan;
+ int err;
+
+ vlan = kvzalloc(sizeof(*vlan), GFP_KERNEL);
+ if (!vlan)
+ return ERR_PTR(-ENOMEM);
+
+ vlan->vid = vid;
+ vlan->flags = flags;
+ INIT_LIST_HEAD(&vlan->fdb_list);
+
+ if (flags & BRIDGE_VLAN_INFO_PVID) {
+ err = mlx5_esw_bridge_vlan_push_create(vlan, esw);
+ if (err)
+ goto err_vlan_push;
+ }
+ if (flags & BRIDGE_VLAN_INFO_UNTAGGED) {
+ err = mlx5_esw_bridge_vlan_pop_create(vlan, esw);
+ if (err)
+ goto err_vlan_pop;
+ }
+
+ err = xa_insert(&port->vlans, vid, vlan, GFP_KERNEL);
+ if (err)
+ goto err_xa_insert;
+
+ trace_mlx5_esw_bridge_vlan_create(vlan);
+ return vlan;
+
+err_xa_insert:
+ if (vlan->pkt_reformat_pop)
+ mlx5_esw_bridge_vlan_pop_cleanup(vlan, esw);
+err_vlan_pop:
+ if (vlan->pkt_reformat_push)
+ mlx5_esw_bridge_vlan_push_cleanup(vlan, esw);
+err_vlan_push:
+ kvfree(vlan);
+ return ERR_PTR(err);
+}
+
+static void mlx5_esw_bridge_vlan_erase(struct mlx5_esw_bridge_port *port,
+ struct mlx5_esw_bridge_vlan *vlan)
+{
+ xa_erase(&port->vlans, vlan->vid);
+}
+
+static void mlx5_esw_bridge_vlan_flush(struct mlx5_esw_bridge_vlan *vlan,
+ struct mlx5_esw_bridge *bridge)
+{
+ struct mlx5_esw_bridge_fdb_entry *entry, *tmp;
+
+ list_for_each_entry_safe(entry, tmp, &vlan->fdb_list, vlan_list) {
+ if (!(entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER))
+ mlx5_esw_bridge_fdb_offload_notify(entry->dev, entry->key.addr,
+ entry->key.vid,
+ SWITCHDEV_FDB_DEL_TO_BRIDGE);
+ mlx5_esw_bridge_fdb_entry_cleanup(entry, bridge);
+ }
+
+ if (vlan->pkt_reformat_pop)
+ mlx5_esw_bridge_vlan_pop_cleanup(vlan, bridge->br_offloads->esw);
+ if (vlan->pkt_reformat_push)
+ mlx5_esw_bridge_vlan_push_cleanup(vlan, bridge->br_offloads->esw);
+}
+
+static void mlx5_esw_bridge_vlan_cleanup(struct mlx5_esw_bridge_port *port,
+ struct mlx5_esw_bridge_vlan *vlan,
+ struct mlx5_esw_bridge *bridge)
+{
+ trace_mlx5_esw_bridge_vlan_cleanup(vlan);
+ mlx5_esw_bridge_vlan_flush(vlan, bridge);
+ mlx5_esw_bridge_vlan_erase(port, vlan);
+ kvfree(vlan);
+}
+
+static void mlx5_esw_bridge_port_vlans_flush(struct mlx5_esw_bridge_port *port,
+ struct mlx5_esw_bridge *bridge)
+{
+ struct mlx5_esw_bridge_vlan *vlan;
+ unsigned long index;
+
+ xa_for_each(&port->vlans, index, vlan)
+ mlx5_esw_bridge_vlan_cleanup(port, vlan, bridge);
+}
+
+static struct mlx5_esw_bridge_vlan *
+mlx5_esw_bridge_port_vlan_lookup(u16 vid, u16 vport_num, struct mlx5_esw_bridge *bridge,
+ struct mlx5_eswitch *esw)
+{
+ struct mlx5_esw_bridge_port *port;
+ struct mlx5_esw_bridge_vlan *vlan;
+
+ port = mlx5_esw_bridge_port_lookup(vport_num, bridge);
+ if (!port) {
+ /* FDB is added asynchronously on wq while port might have been deleted
+ * concurrently. Report on 'info' logging level and skip the FDB offload.
+ */
+ esw_info(esw->dev, "Failed to lookup bridge port (vport=%u)\n", vport_num);
+ return ERR_PTR(-EINVAL);
+ }
+
+ vlan = mlx5_esw_bridge_vlan_lookup(vid, port);
+ if (!vlan) {
+ /* FDB is added asynchronously on wq while vlan might have been deleted
+ * concurrently. Report on 'info' logging level and skip the FDB offload.
+ */
+ esw_info(esw->dev, "Failed to lookup bridge port vlan metadata (vport=%u)\n",
+ vport_num);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return vlan;
+}
+
+static struct mlx5_esw_bridge_fdb_entry *
+mlx5_esw_bridge_fdb_entry_init(struct net_device *dev, u16 vport_num, const unsigned char *addr,
+ u16 vid, bool added_by_user, struct mlx5_eswitch *esw,
+ struct mlx5_esw_bridge *bridge)
+{
+ struct mlx5_esw_bridge_vlan *vlan = NULL;
+ struct mlx5_esw_bridge_fdb_entry *entry;
+ struct mlx5_flow_handle *handle;
+ struct mlx5_fc *counter;
+ struct mlx5e_priv *priv;
+ int err;
+
+ if (bridge->flags & MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG && vid) {
+ vlan = mlx5_esw_bridge_port_vlan_lookup(vid, vport_num, bridge, esw);
+ if (IS_ERR(vlan))
+ return ERR_CAST(vlan);
+ }
+
+ priv = netdev_priv(dev);
+ entry = kvzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return ERR_PTR(-ENOMEM);
+
+ ether_addr_copy(entry->key.addr, addr);
+ entry->key.vid = vid;
+ entry->dev = dev;
+ entry->vport_num = vport_num;
+ entry->lastuse = jiffies;
+ if (added_by_user)
+ entry->flags |= MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER;
+
+ counter = mlx5_fc_create(priv->mdev, true);
+ if (IS_ERR(counter)) {
+ err = PTR_ERR(counter);
+ goto err_ingress_fc_create;
+ }
+ entry->ingress_counter = counter;
+
+ handle = mlx5_esw_bridge_ingress_flow_create(vport_num, addr, vlan, mlx5_fc_id(counter),
+ bridge);
+ if (IS_ERR(handle)) {
+ err = PTR_ERR(handle);
+ esw_warn(esw->dev, "Failed to create ingress flow(vport=%u,err=%d)\n",
+ vport_num, err);
+ goto err_ingress_flow_create;
+ }
+ entry->ingress_handle = handle;
+
+ if (bridge->flags & MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG) {
+ handle = mlx5_esw_bridge_ingress_filter_flow_create(vport_num, addr, bridge);
+ if (IS_ERR(handle)) {
+ err = PTR_ERR(handle);
+ esw_warn(esw->dev, "Failed to create ingress filter(vport=%u,err=%d)\n",
+ vport_num, err);
+ goto err_ingress_filter_flow_create;
+ }
+ entry->filter_handle = handle;
+ }
+
+ handle = mlx5_esw_bridge_egress_flow_create(vport_num, addr, vlan, bridge);
+ if (IS_ERR(handle)) {
+ err = PTR_ERR(handle);
+ esw_warn(esw->dev, "Failed to create egress flow(vport=%u,err=%d)\n",
+ vport_num, err);
+ goto err_egress_flow_create;
+ }
+ entry->egress_handle = handle;
+
+ err = rhashtable_insert_fast(&bridge->fdb_ht, &entry->ht_node, fdb_ht_params);
+ if (err) {
+ esw_warn(esw->dev, "Failed to insert FDB flow(vport=%u,err=%d)\n", vport_num, err);
+ goto err_ht_init;
+ }
+
+ if (vlan)
+ list_add(&entry->vlan_list, &vlan->fdb_list);
+ else
+ INIT_LIST_HEAD(&entry->vlan_list);
+ list_add(&entry->list, &bridge->fdb_list);
+
+ trace_mlx5_esw_bridge_fdb_entry_init(entry);
+ return entry;
+
+err_ht_init:
+ mlx5_del_flow_rules(entry->egress_handle);
+err_egress_flow_create:
+ if (entry->filter_handle)
+ mlx5_del_flow_rules(entry->filter_handle);
+err_ingress_filter_flow_create:
+ mlx5_del_flow_rules(entry->ingress_handle);
+err_ingress_flow_create:
+ mlx5_fc_destroy(priv->mdev, entry->ingress_counter);
+err_ingress_fc_create:
+ kvfree(entry);
+ return ERR_PTR(err);
+}
+
+int mlx5_esw_bridge_ageing_time_set(unsigned long ageing_time, struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport)
+{
+ if (!vport->bridge)
+ return -EINVAL;
+
+ vport->bridge->ageing_time = ageing_time;
+ return 0;
+}
+
+int mlx5_esw_bridge_vlan_filtering_set(bool enable, struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport)
+{
+ struct mlx5_esw_bridge *bridge;
+ bool filtering;
+
+ if (!vport->bridge)
+ return -EINVAL;
+
+ bridge = vport->bridge;
+ filtering = bridge->flags & MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG;
+ if (filtering == enable)
+ return 0;
+
+ mlx5_esw_bridge_fdb_flush(bridge);
+ if (enable)
+ bridge->flags |= MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG;
+ else
+ bridge->flags &= ~MLX5_ESW_BRIDGE_VLAN_FILTERING_FLAG;
+
+ return 0;
+}
+
+static int mlx5_esw_bridge_vport_init(struct mlx5_esw_bridge_offloads *br_offloads,
+ struct mlx5_esw_bridge *bridge,
+ struct mlx5_vport *vport)
+{
+ struct mlx5_eswitch *esw = br_offloads->esw;
+ struct mlx5_esw_bridge_port *port;
+ int err;
+
+ port = kvzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port) {
+ err = -ENOMEM;
+ goto err_port_alloc;
+ }
+
+ port->vport_num = vport->vport;
+ xa_init(&port->vlans);
+ err = mlx5_esw_bridge_port_insert(port, bridge);
+ if (err) {
+ esw_warn(esw->dev, "Failed to insert port metadata (vport=%u,err=%d)\n",
+ vport->vport, err);
+ goto err_port_insert;
+ }
+ trace_mlx5_esw_bridge_vport_init(port);
+
+ vport->bridge = bridge;
+ return 0;
+
+err_port_insert:
+ kvfree(port);
+err_port_alloc:
+ mlx5_esw_bridge_put(br_offloads, bridge);
+ return err;
+}
+
+static int mlx5_esw_bridge_vport_cleanup(struct mlx5_esw_bridge_offloads *br_offloads,
+ struct mlx5_vport *vport)
+{
+ struct mlx5_esw_bridge *bridge = vport->bridge;
+ struct mlx5_esw_bridge_fdb_entry *entry, *tmp;
+ struct mlx5_esw_bridge_port *port;
+
+ list_for_each_entry_safe(entry, tmp, &bridge->fdb_list, list)
+ if (entry->vport_num == vport->vport)
+ mlx5_esw_bridge_fdb_entry_cleanup(entry, bridge);
+
+ port = mlx5_esw_bridge_port_lookup(vport->vport, bridge);
+ if (!port) {
+ WARN(1, "Vport %u metadata not found on bridge", vport->vport);
+ return -EINVAL;
+ }
+
+ trace_mlx5_esw_bridge_vport_cleanup(port);
+ mlx5_esw_bridge_port_vlans_flush(port, bridge);
+ mlx5_esw_bridge_port_erase(port, bridge);
+ kvfree(port);
+ mlx5_esw_bridge_put(br_offloads, bridge);
+ vport->bridge = NULL;
+ return 0;
+}
+
+int mlx5_esw_bridge_vport_link(int ifindex, struct mlx5_esw_bridge_offloads *br_offloads,
+ struct mlx5_vport *vport, struct netlink_ext_ack *extack)
+{
+ struct mlx5_esw_bridge *bridge;
+ int err;
+
+ WARN_ON(vport->bridge);
+
+ bridge = mlx5_esw_bridge_lookup(ifindex, br_offloads);
+ if (IS_ERR(bridge)) {
+ NL_SET_ERR_MSG_MOD(extack, "Error checking for existing bridge with same ifindex");
+ return PTR_ERR(bridge);
+ }
+
+ err = mlx5_esw_bridge_vport_init(br_offloads, bridge, vport);
+ if (err)
+ NL_SET_ERR_MSG_MOD(extack, "Error initializing port");
+ return err;
+}
+
+int mlx5_esw_bridge_vport_unlink(int ifindex, struct mlx5_esw_bridge_offloads *br_offloads,
+ struct mlx5_vport *vport, struct netlink_ext_ack *extack)
+{
+ struct mlx5_esw_bridge *bridge = vport->bridge;
+ int err;
+
+ if (!bridge) {
+ NL_SET_ERR_MSG_MOD(extack, "Port is not attached to any bridge");
+ return -EINVAL;
+ }
+ if (bridge->ifindex != ifindex) {
+ NL_SET_ERR_MSG_MOD(extack, "Port is attached to another bridge");
+ return -EINVAL;
+ }
+
+ err = mlx5_esw_bridge_vport_cleanup(br_offloads, vport);
+ if (err)
+ NL_SET_ERR_MSG_MOD(extack, "Port cleanup failed");
+ return err;
+}
+
+int mlx5_esw_bridge_port_vlan_add(u16 vid, u16 flags, struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport, struct netlink_ext_ack *extack)
+{
+ struct mlx5_esw_bridge_port *port;
+ struct mlx5_esw_bridge_vlan *vlan;
+
+ port = mlx5_esw_bridge_port_lookup(vport->vport, vport->bridge);
+ if (!port)
+ return -EINVAL;
+
+ vlan = mlx5_esw_bridge_vlan_lookup(vid, port);
+ if (vlan) {
+ if (vlan->flags == flags)
+ return 0;
+ mlx5_esw_bridge_vlan_cleanup(port, vlan, vport->bridge);
+ }
+
+ vlan = mlx5_esw_bridge_vlan_create(vid, flags, port, esw);
+ if (IS_ERR(vlan)) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to create VLAN entry");
+ return PTR_ERR(vlan);
+ }
+ return 0;
+}
+
+void mlx5_esw_bridge_port_vlan_del(u16 vid, struct mlx5_eswitch *esw, struct mlx5_vport *vport)
+{
+ struct mlx5_esw_bridge_port *port;
+ struct mlx5_esw_bridge_vlan *vlan;
+
+ port = mlx5_esw_bridge_port_lookup(vport->vport, vport->bridge);
+ if (!port)
+ return;
+
+ vlan = mlx5_esw_bridge_vlan_lookup(vid, port);
+ if (!vlan)
+ return;
+ mlx5_esw_bridge_vlan_cleanup(port, vlan, vport->bridge);
+}
+
+void mlx5_esw_bridge_fdb_create(struct net_device *dev, struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport,
+ struct switchdev_notifier_fdb_info *fdb_info)
+{
+ struct mlx5_esw_bridge *bridge = vport->bridge;
+ struct mlx5_esw_bridge_fdb_entry *entry;
+ u16 vport_num = vport->vport;
+
+ if (!bridge) {
+ esw_info(esw->dev, "Vport is not assigned to bridge (vport=%u)\n", vport_num);
+ return;
+ }
+
+ entry = mlx5_esw_bridge_fdb_entry_init(dev, vport_num, fdb_info->addr, fdb_info->vid,
+ fdb_info->added_by_user, esw, bridge);
+ if (IS_ERR(entry))
+ return;
+
+ if (entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER)
+ mlx5_esw_bridge_fdb_offload_notify(dev, entry->key.addr, entry->key.vid,
+ SWITCHDEV_FDB_OFFLOADED);
+ else
+ /* Take over dynamic entries to prevent kernel bridge from aging them out. */
+ mlx5_esw_bridge_fdb_offload_notify(dev, entry->key.addr, entry->key.vid,
+ SWITCHDEV_FDB_ADD_TO_BRIDGE);
+}
+
+void mlx5_esw_bridge_fdb_remove(struct net_device *dev, struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport,
+ struct switchdev_notifier_fdb_info *fdb_info)
+{
+ struct mlx5_esw_bridge *bridge = vport->bridge;
+ struct mlx5_esw_bridge_fdb_entry *entry;
+ struct mlx5_esw_bridge_fdb_key key;
+ u16 vport_num = vport->vport;
+
+ if (!bridge) {
+ esw_warn(esw->dev, "Vport is not assigned to bridge (vport=%u)\n", vport_num);
+ return;
+ }
+
+ ether_addr_copy(key.addr, fdb_info->addr);
+ key.vid = fdb_info->vid;
+ entry = rhashtable_lookup_fast(&bridge->fdb_ht, &key, fdb_ht_params);
+ if (!entry) {
+ esw_warn(esw->dev,
+ "FDB entry with specified key not found (MAC=%pM,vid=%u,vport=%u)\n",
+ key.addr, key.vid, vport_num);
+ return;
+ }
+
+ if (!(entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER))
+ mlx5_esw_bridge_fdb_offload_notify(dev, entry->key.addr, entry->key.vid,
+ SWITCHDEV_FDB_DEL_TO_BRIDGE);
+ mlx5_esw_bridge_fdb_entry_cleanup(entry, bridge);
+}
+
+void mlx5_esw_bridge_update(struct mlx5_esw_bridge_offloads *br_offloads)
+{
+ struct mlx5_esw_bridge_fdb_entry *entry, *tmp;
+ struct mlx5_esw_bridge *bridge;
+
+ list_for_each_entry(bridge, &br_offloads->bridges, list) {
+ list_for_each_entry_safe(entry, tmp, &bridge->fdb_list, list) {
+ unsigned long lastuse =
+ (unsigned long)mlx5_fc_query_lastuse(entry->ingress_counter);
+
+ if (entry->flags & MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER)
+ continue;
+
+ if (time_after(lastuse, entry->lastuse)) {
+ mlx5_esw_bridge_fdb_entry_refresh(lastuse, entry);
+ } else if (time_is_before_jiffies(entry->lastuse + bridge->ageing_time)) {
+ mlx5_esw_bridge_fdb_offload_notify(entry->dev, entry->key.addr,
+ entry->key.vid,
+ SWITCHDEV_FDB_DEL_TO_BRIDGE);
+ mlx5_esw_bridge_fdb_entry_cleanup(entry, bridge);
+ }
+ }
+ }
+}
+
+static void mlx5_esw_bridge_flush(struct mlx5_esw_bridge_offloads *br_offloads)
+{
+ struct mlx5_eswitch *esw = br_offloads->esw;
+ struct mlx5_vport *vport;
+ unsigned long i;
+
+ mlx5_esw_for_each_vport(esw, i, vport)
+ if (vport->bridge)
+ mlx5_esw_bridge_vport_cleanup(br_offloads, vport);
+
+ WARN_ONCE(!list_empty(&br_offloads->bridges),
+ "Cleaning up bridge offloads while still having bridges attached\n");
+}
+
+struct mlx5_esw_bridge_offloads *mlx5_esw_bridge_init(struct mlx5_eswitch *esw)
+{
+ struct mlx5_esw_bridge_offloads *br_offloads;
+
+ br_offloads = kvzalloc(sizeof(*br_offloads), GFP_KERNEL);
+ if (!br_offloads)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&br_offloads->bridges);
+ br_offloads->esw = esw;
+ esw->br_offloads = br_offloads;
+
+ return br_offloads;
+}
+
+void mlx5_esw_bridge_cleanup(struct mlx5_eswitch *esw)
+{
+ struct mlx5_esw_bridge_offloads *br_offloads = esw->br_offloads;
+
+ if (!br_offloads)
+ return;
+
+ mlx5_esw_bridge_flush(br_offloads);
+
+ esw->br_offloads = NULL;
+ kvfree(br_offloads);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h
new file mode 100644
index 000000000000..d826942b27fc
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2021 Mellanox Technologies. */
+
+#ifndef __MLX5_ESW_BRIDGE_H__
+#define __MLX5_ESW_BRIDGE_H__
+
+#include <linux/notifier.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include "eswitch.h"
+
+struct mlx5_flow_table;
+struct mlx5_flow_group;
+
+struct mlx5_esw_bridge_offloads {
+ struct mlx5_eswitch *esw;
+ struct list_head bridges;
+ struct notifier_block netdev_nb;
+ struct notifier_block nb_blk;
+ struct notifier_block nb;
+ struct workqueue_struct *wq;
+ struct delayed_work update_work;
+
+ struct mlx5_flow_table *ingress_ft;
+ struct mlx5_flow_group *ingress_vlan_fg;
+ struct mlx5_flow_group *ingress_filter_fg;
+ struct mlx5_flow_group *ingress_mac_fg;
+
+ struct mlx5_flow_table *skip_ft;
+};
+
+struct mlx5_esw_bridge_offloads *mlx5_esw_bridge_init(struct mlx5_eswitch *esw);
+void mlx5_esw_bridge_cleanup(struct mlx5_eswitch *esw);
+int mlx5_esw_bridge_vport_link(int ifindex, struct mlx5_esw_bridge_offloads *br_offloads,
+ struct mlx5_vport *vport, struct netlink_ext_ack *extack);
+int mlx5_esw_bridge_vport_unlink(int ifindex, struct mlx5_esw_bridge_offloads *br_offloads,
+ struct mlx5_vport *vport, struct netlink_ext_ack *extack);
+void mlx5_esw_bridge_fdb_create(struct net_device *dev, struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport,
+ struct switchdev_notifier_fdb_info *fdb_info);
+void mlx5_esw_bridge_fdb_remove(struct net_device *dev, struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport,
+ struct switchdev_notifier_fdb_info *fdb_info);
+void mlx5_esw_bridge_update(struct mlx5_esw_bridge_offloads *br_offloads);
+int mlx5_esw_bridge_ageing_time_set(unsigned long ageing_time, struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport);
+int mlx5_esw_bridge_vlan_filtering_set(bool enable, struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport);
+int mlx5_esw_bridge_port_vlan_add(u16 vid, u16 flags, struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport, struct netlink_ext_ack *extack);
+void mlx5_esw_bridge_port_vlan_del(u16 vid, struct mlx5_eswitch *esw, struct mlx5_vport *vport);
+
+#endif /* __MLX5_ESW_BRIDGE_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_priv.h b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_priv.h
new file mode 100644
index 000000000000..d9ab2e8bc2cb
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_priv.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2021 Mellanox Technologies. */
+
+#ifndef _MLX5_ESW_BRIDGE_PRIVATE_
+#define _MLX5_ESW_BRIDGE_PRIVATE_
+
+#include <linux/netdevice.h>
+#include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
+#include <linux/if_ether.h>
+#include <linux/rhashtable.h>
+#include <linux/xarray.h>
+#include "fs_core.h"
+
+struct mlx5_esw_bridge_fdb_key {
+ unsigned char addr[ETH_ALEN];
+ u16 vid;
+};
+
+enum {
+ MLX5_ESW_BRIDGE_FLAG_ADDED_BY_USER = BIT(0),
+};
+
+struct mlx5_esw_bridge_fdb_entry {
+ struct mlx5_esw_bridge_fdb_key key;
+ struct rhash_head ht_node;
+ struct net_device *dev;
+ struct list_head list;
+ struct list_head vlan_list;
+ u16 vport_num;
+ u16 flags;
+
+ struct mlx5_flow_handle *ingress_handle;
+ struct mlx5_fc *ingress_counter;
+ unsigned long lastuse;
+ struct mlx5_flow_handle *egress_handle;
+ struct mlx5_flow_handle *filter_handle;
+};
+
+struct mlx5_esw_bridge_vlan {
+ u16 vid;
+ u16 flags;
+ struct list_head fdb_list;
+ struct mlx5_pkt_reformat *pkt_reformat_push;
+ struct mlx5_pkt_reformat *pkt_reformat_pop;
+};
+
+struct mlx5_esw_bridge_port {
+ u16 vport_num;
+ struct xarray vlans;
+};
+
+#endif /* _MLX5_ESW_BRIDGE_PRIVATE_ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/diag/bridge_tracepoint.h b/drivers/net/ethernet/mellanox/mlx5/core/esw/diag/bridge_tracepoint.h
new file mode 100644
index 000000000000..227964b7d3b9
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/diag/bridge_tracepoint.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2021 Mellanox Technologies. */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mlx5
+
+#if !defined(_MLX5_ESW_BRIDGE_TRACEPOINT_) || defined(TRACE_HEADER_MULTI_READ)
+#define _MLX5_ESW_BRIDGE_TRACEPOINT_
+
+#include <linux/tracepoint.h>
+#include "../bridge_priv.h"
+
+DECLARE_EVENT_CLASS(mlx5_esw_bridge_fdb_template,
+ TP_PROTO(const struct mlx5_esw_bridge_fdb_entry *fdb),
+ TP_ARGS(fdb),
+ TP_STRUCT__entry(
+ __array(char, dev_name, IFNAMSIZ)
+ __array(unsigned char, addr, ETH_ALEN)
+ __field(u16, vid)
+ __field(u16, flags)
+ __field(unsigned int, used)
+ ),
+ TP_fast_assign(
+ strncpy(__entry->dev_name,
+ netdev_name(fdb->dev),
+ IFNAMSIZ);
+ memcpy(__entry->addr, fdb->key.addr, ETH_ALEN);
+ __entry->vid = fdb->key.vid;
+ __entry->flags = fdb->flags;
+ __entry->used = jiffies_to_msecs(jiffies - fdb->lastuse)
+ ),
+ TP_printk("net_device=%s addr=%pM vid=%hu flags=%hx used=%u",
+ __entry->dev_name,
+ __entry->addr,
+ __entry->vid,
+ __entry->flags,
+ __entry->used / 1000)
+ );
+
+DEFINE_EVENT(mlx5_esw_bridge_fdb_template,
+ mlx5_esw_bridge_fdb_entry_init,
+ TP_PROTO(const struct mlx5_esw_bridge_fdb_entry *fdb),
+ TP_ARGS(fdb)
+ );
+DEFINE_EVENT(mlx5_esw_bridge_fdb_template,
+ mlx5_esw_bridge_fdb_entry_refresh,
+ TP_PROTO(const struct mlx5_esw_bridge_fdb_entry *fdb),
+ TP_ARGS(fdb)
+ );
+DEFINE_EVENT(mlx5_esw_bridge_fdb_template,
+ mlx5_esw_bridge_fdb_entry_cleanup,
+ TP_PROTO(const struct mlx5_esw_bridge_fdb_entry *fdb),
+ TP_ARGS(fdb)
+ );
+
+DECLARE_EVENT_CLASS(mlx5_esw_bridge_vlan_template,
+ TP_PROTO(const struct mlx5_esw_bridge_vlan *vlan),
+ TP_ARGS(vlan),
+ TP_STRUCT__entry(
+ __field(u16, vid)
+ __field(u16, flags)
+ ),
+ TP_fast_assign(
+ __entry->vid = vlan->vid;
+ __entry->flags = vlan->flags;
+ ),
+ TP_printk("vid=%hu flags=%hx",
+ __entry->vid,
+ __entry->flags)
+ );
+
+DEFINE_EVENT(mlx5_esw_bridge_vlan_template,
+ mlx5_esw_bridge_vlan_create,
+ TP_PROTO(const struct mlx5_esw_bridge_vlan *vlan),
+ TP_ARGS(vlan)
+ );
+DEFINE_EVENT(mlx5_esw_bridge_vlan_template,
+ mlx5_esw_bridge_vlan_cleanup,
+ TP_PROTO(const struct mlx5_esw_bridge_vlan *vlan),
+ TP_ARGS(vlan)
+ );
+
+DECLARE_EVENT_CLASS(mlx5_esw_bridge_port_template,
+ TP_PROTO(const struct mlx5_esw_bridge_port *port),
+ TP_ARGS(port),
+ TP_STRUCT__entry(
+ __field(u16, vport_num)
+ ),
+ TP_fast_assign(
+ __entry->vport_num = port->vport_num;
+ ),
+ TP_printk("vport_num=%hu", __entry->vport_num)
+ );
+
+DEFINE_EVENT(mlx5_esw_bridge_port_template,
+ mlx5_esw_bridge_vport_init,
+ TP_PROTO(const struct mlx5_esw_bridge_port *port),
+ TP_ARGS(port)
+ );
+DEFINE_EVENT(mlx5_esw_bridge_port_template,
+ mlx5_esw_bridge_vport_cleanup,
+ TP_PROTO(const struct mlx5_esw_bridge_port *port),
+ TP_ARGS(port)
+ );
+
+#endif
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH esw/diag
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE bridge_tracepoint
+#include <trace/define_trace.h>
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index 64ccb2bc0b58..48cac5bf606d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -150,6 +150,8 @@ enum mlx5_eswitch_vport_event {
MLX5_VPORT_PROMISC_CHANGE = BIT(3),
};
+struct mlx5_esw_bridge;
+
struct mlx5_vport {
struct mlx5_core_dev *dev;
struct hlist_head uc_list[MLX5_L2_ADDR_HASH_SIZE];
@@ -178,6 +180,7 @@ struct mlx5_vport {
enum mlx5_eswitch_vport_event enabled_events;
int index;
struct devlink_port *dl_port;
+ struct mlx5_esw_bridge *bridge;
};
struct mlx5_esw_indir_table;
@@ -196,6 +199,7 @@ struct mlx5_eswitch_fdb {
struct offloads_fdb {
struct mlx5_flow_namespace *ns;
+ struct mlx5_flow_table *tc_miss_table;
struct mlx5_flow_table *slow_fdb;
struct mlx5_flow_group *send_to_vport_grp;
struct mlx5_flow_group *send_to_vport_meta_grp;
@@ -270,6 +274,8 @@ enum {
MLX5_ESWITCH_REG_C1_LOOPBACK_ENABLED = BIT(1),
};
+struct mlx5_esw_bridge_offloads;
+
struct mlx5_eswitch {
struct mlx5_core_dev *dev;
struct mlx5_nb nb;
@@ -299,6 +305,7 @@ struct mlx5_eswitch {
u32 root_tsar_id;
} qos;
+ struct mlx5_esw_bridge_offloads *br_offloads;
struct mlx5_esw_offload offloads;
int mode;
u16 manager_vport;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index d18a28a6e9a6..7579f3402776 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -1634,7 +1634,21 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw)
}
esw->fdb_table.offloads.slow_fdb = fdb;
- err = esw_chains_create(esw, fdb);
+ /* Create empty TC-miss managed table. This allows plugging in following
+ * priorities without directly exposing their level 0 table to
+ * eswitch_offloads and passing it as miss_fdb to following call to
+ * esw_chains_create().
+ */
+ memset(&ft_attr, 0, sizeof(ft_attr));
+ ft_attr.prio = FDB_TC_MISS;
+ esw->fdb_table.offloads.tc_miss_table = mlx5_create_flow_table(root_ns, &ft_attr);
+ if (IS_ERR(esw->fdb_table.offloads.tc_miss_table)) {
+ err = PTR_ERR(esw->fdb_table.offloads.tc_miss_table);
+ esw_warn(dev, "Failed to create TC miss FDB Table err %d\n", err);
+ goto tc_miss_table_err;
+ }
+
+ err = esw_chains_create(esw, esw->fdb_table.offloads.tc_miss_table);
if (err) {
esw_warn(dev, "Failed to open fdb chains err(%d)\n", err);
goto fdb_chains_err;
@@ -1779,6 +1793,8 @@ send_vport_meta_err:
send_vport_err:
esw_chains_destroy(esw, esw_chains(esw));
fdb_chains_err:
+ mlx5_destroy_flow_table(esw->fdb_table.offloads.tc_miss_table);
+tc_miss_table_err:
mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
slow_fdb_err:
/* Holds true only as long as DMFS is the default */
@@ -1806,6 +1822,7 @@ static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
esw_chains_destroy(esw, esw_chains(esw));
+ mlx5_destroy_flow_table(esw->fdb_table.offloads.tc_miss_table);
mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
/* Holds true only as long as DMFS is the default */
mlx5_flow_namespace_set_mode(esw->fdb_table.offloads.ns,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
index 8e06731d3cb3..896a6c3dbdb7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
@@ -36,6 +36,7 @@
#include "fs_core.h"
#include "fs_cmd.h"
+#include "fs_ft_pool.h"
#include "mlx5_core.h"
#include "eswitch.h"
@@ -49,9 +50,11 @@ static int mlx5_cmd_stub_update_root_ft(struct mlx5_flow_root_namespace *ns,
static int mlx5_cmd_stub_create_flow_table(struct mlx5_flow_root_namespace *ns,
struct mlx5_flow_table *ft,
- unsigned int log_size,
+ unsigned int size,
struct mlx5_flow_table *next_ft)
{
+ ft->max_fte = size ? roundup_pow_of_two(size) : 1;
+
return 0;
}
@@ -108,9 +111,7 @@ static int mlx5_cmd_stub_delete_fte(struct mlx5_flow_root_namespace *ns,
}
static int mlx5_cmd_stub_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns,
- int reformat_type,
- size_t size,
- void *reformat_data,
+ struct mlx5_pkt_reformat_params *params,
enum mlx5_flow_namespace_type namespace,
struct mlx5_pkt_reformat *pkt_reformat)
{
@@ -181,7 +182,7 @@ static int mlx5_cmd_update_root_ft(struct mlx5_flow_root_namespace *ns,
static int mlx5_cmd_create_flow_table(struct mlx5_flow_root_namespace *ns,
struct mlx5_flow_table *ft,
- unsigned int log_size,
+ unsigned int size,
struct mlx5_flow_table *next_ft)
{
int en_encap = !!(ft->flags & MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT);
@@ -192,12 +193,18 @@ static int mlx5_cmd_create_flow_table(struct mlx5_flow_root_namespace *ns,
struct mlx5_core_dev *dev = ns->dev;
int err;
+ if (size != POOL_NEXT_SIZE)
+ size = roundup_pow_of_two(size);
+ size = mlx5_ft_pool_get_avail_sz(dev, ft->type, size);
+ if (!size)
+ return -ENOSPC;
+
MLX5_SET(create_flow_table_in, in, opcode,
MLX5_CMD_OP_CREATE_FLOW_TABLE);
MLX5_SET(create_flow_table_in, in, table_type, ft->type);
MLX5_SET(create_flow_table_in, in, flow_table_context.level, ft->level);
- MLX5_SET(create_flow_table_in, in, flow_table_context.log_size, log_size);
+ MLX5_SET(create_flow_table_in, in, flow_table_context.log_size, size ? ilog2(size) : 0);
MLX5_SET(create_flow_table_in, in, vport_number, ft->vport);
MLX5_SET(create_flow_table_in, in, other_vport,
!!(ft->flags & MLX5_FLOW_TABLE_OTHER_VPORT));
@@ -234,9 +241,14 @@ static int mlx5_cmd_create_flow_table(struct mlx5_flow_root_namespace *ns,
}
err = mlx5_cmd_exec_inout(dev, create_flow_table, in, out);
- if (!err)
+ if (!err) {
ft->id = MLX5_GET(create_flow_table_out, out,
table_id);
+ ft->max_fte = size;
+ } else {
+ mlx5_ft_pool_put_sz(ns->dev, size);
+ }
+
return err;
}
@@ -245,6 +257,7 @@ static int mlx5_cmd_destroy_flow_table(struct mlx5_flow_root_namespace *ns,
{
u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)] = {};
struct mlx5_core_dev *dev = ns->dev;
+ int err;
MLX5_SET(destroy_flow_table_in, in, opcode,
MLX5_CMD_OP_DESTROY_FLOW_TABLE);
@@ -254,7 +267,11 @@ static int mlx5_cmd_destroy_flow_table(struct mlx5_flow_root_namespace *ns,
MLX5_SET(destroy_flow_table_in, in, other_vport,
!!(ft->flags & MLX5_FLOW_TABLE_OTHER_VPORT));
- return mlx5_cmd_exec_in(dev, destroy_flow_table, in);
+ err = mlx5_cmd_exec_in(dev, destroy_flow_table, in);
+ if (!err)
+ mlx5_ft_pool_put_sz(ns->dev, ft->max_fte);
+
+ return err;
}
static int mlx5_cmd_modify_flow_table(struct mlx5_flow_root_namespace *ns,
@@ -682,9 +699,7 @@ int mlx5_cmd_fc_bulk_query(struct mlx5_core_dev *dev, u32 base_id, int bulk_len,
}
static int mlx5_cmd_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns,
- int reformat_type,
- size_t size,
- void *reformat_data,
+ struct mlx5_pkt_reformat_params *params,
enum mlx5_flow_namespace_type namespace,
struct mlx5_pkt_reformat *pkt_reformat)
{
@@ -702,14 +717,14 @@ static int mlx5_cmd_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns,
else
max_encap_size = MLX5_CAP_FLOWTABLE(dev, max_encap_header_size);
- if (size > max_encap_size) {
+ if (params->size > max_encap_size) {
mlx5_core_warn(dev, "encap size %zd too big, max supported is %d\n",
- size, max_encap_size);
+ params->size, max_encap_size);
return -EINVAL;
}
- in = kzalloc(MLX5_ST_SZ_BYTES(alloc_packet_reformat_context_in) + size,
- GFP_KERNEL);
+ in = kzalloc(MLX5_ST_SZ_BYTES(alloc_packet_reformat_context_in) +
+ params->size, GFP_KERNEL);
if (!in)
return -ENOMEM;
@@ -718,15 +733,20 @@ static int mlx5_cmd_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns,
reformat = MLX5_ADDR_OF(packet_reformat_context_in,
packet_reformat_context_in,
reformat_data);
- inlen = reformat - (void *)in + size;
+ inlen = reformat - (void *)in + params->size;
MLX5_SET(alloc_packet_reformat_context_in, in, opcode,
MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT);
MLX5_SET(packet_reformat_context_in, packet_reformat_context_in,
- reformat_data_size, size);
+ reformat_data_size, params->size);
+ MLX5_SET(packet_reformat_context_in, packet_reformat_context_in,
+ reformat_type, params->type);
+ MLX5_SET(packet_reformat_context_in, packet_reformat_context_in,
+ reformat_param_0, params->param_0);
MLX5_SET(packet_reformat_context_in, packet_reformat_context_in,
- reformat_type, reformat_type);
- memcpy(reformat, reformat_data, size);
+ reformat_param_1, params->param_1);
+ if (params->data && params->size)
+ memcpy(reformat, params->data, params->size);
err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h
index d62de642eca9..5ecd33cdc087 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h
@@ -38,7 +38,7 @@
struct mlx5_flow_cmds {
int (*create_flow_table)(struct mlx5_flow_root_namespace *ns,
struct mlx5_flow_table *ft,
- unsigned int log_size,
+ unsigned int size,
struct mlx5_flow_table *next_ft);
int (*destroy_flow_table)(struct mlx5_flow_root_namespace *ns,
struct mlx5_flow_table *ft);
@@ -77,9 +77,7 @@ struct mlx5_flow_cmds {
bool disconnect);
int (*packet_reformat_alloc)(struct mlx5_flow_root_namespace *ns,
- int reformat_type,
- size_t size,
- void *reformat_data,
+ struct mlx5_pkt_reformat_params *params,
enum mlx5_flow_namespace_type namespace,
struct mlx5_pkt_reformat *pkt_reformat);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
index f74d2c834037..d7bf0a3e4a52 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
@@ -38,6 +38,7 @@
#include "mlx5_core.h"
#include "fs_core.h"
#include "fs_cmd.h"
+#include "fs_ft_pool.h"
#include "diag/fs_tracepoint.h"
#include "accel/ipsec.h"
#include "fpga/ipsec.h"
@@ -752,7 +753,7 @@ static struct mlx5_flow_group *alloc_insert_flow_group(struct mlx5_flow_table *f
return fg;
}
-static struct mlx5_flow_table *alloc_flow_table(int level, u16 vport, int max_fte,
+static struct mlx5_flow_table *alloc_flow_table(int level, u16 vport,
enum fs_flow_table_type table_type,
enum fs_flow_table_op_mod op_mod,
u32 flags)
@@ -775,7 +776,6 @@ static struct mlx5_flow_table *alloc_flow_table(int level, u16 vport, int max_ft
ft->op_mod = op_mod;
ft->type = table_type;
ft->vport = vport;
- ft->max_fte = max_fte;
ft->flags = flags;
INIT_LIST_HEAD(&ft->fwd_rules);
mutex_init(&ft->lock);
@@ -1070,7 +1070,6 @@ static struct mlx5_flow_table *__mlx5_create_flow_table(struct mlx5_flow_namespa
struct mlx5_flow_table *next_ft;
struct fs_prio *fs_prio = NULL;
struct mlx5_flow_table *ft;
- int log_table_sz;
int err;
if (!root) {
@@ -1101,7 +1100,6 @@ static struct mlx5_flow_table *__mlx5_create_flow_table(struct mlx5_flow_namespa
*/
ft = alloc_flow_table(ft_attr->level,
vport,
- ft_attr->max_fte ? roundup_pow_of_two(ft_attr->max_fte) : 0,
root->table_type,
op_mod, ft_attr->flags);
if (IS_ERR(ft)) {
@@ -1110,12 +1108,11 @@ static struct mlx5_flow_table *__mlx5_create_flow_table(struct mlx5_flow_namespa
}
tree_init_node(&ft->node, del_hw_flow_table, del_sw_flow_table);
- log_table_sz = ft->max_fte ? ilog2(ft->max_fte) : 0;
next_ft = unmanaged ? ft_attr->next_ft :
find_next_chained_ft(fs_prio);
ft->def_miss_action = ns->def_miss_action;
ft->ns = ns;
- err = root->cmds->create_flow_table(root, ft, log_table_sz, next_ft);
+ err = root->cmds->create_flow_table(root, ft, ft_attr->max_fte, next_ft);
if (err)
goto free_ft;
@@ -1170,28 +1167,36 @@ mlx5_create_lag_demux_flow_table(struct mlx5_flow_namespace *ns,
ft_attr.level = level;
ft_attr.prio = prio;
+ ft_attr.max_fte = 1;
+
return __mlx5_create_flow_table(ns, &ft_attr, FS_FT_OP_MOD_LAG_DEMUX, 0);
}
EXPORT_SYMBOL(mlx5_create_lag_demux_flow_table);
+#define MAX_FLOW_GROUP_SIZE BIT(24)
struct mlx5_flow_table*
mlx5_create_auto_grouped_flow_table(struct mlx5_flow_namespace *ns,
struct mlx5_flow_table_attr *ft_attr)
{
int num_reserved_entries = ft_attr->autogroup.num_reserved_entries;
- int autogroups_max_fte = ft_attr->max_fte - num_reserved_entries;
int max_num_groups = ft_attr->autogroup.max_num_groups;
struct mlx5_flow_table *ft;
-
- if (max_num_groups > autogroups_max_fte)
- return ERR_PTR(-EINVAL);
- if (num_reserved_entries > ft_attr->max_fte)
- return ERR_PTR(-EINVAL);
+ int autogroups_max_fte;
ft = mlx5_create_flow_table(ns, ft_attr);
if (IS_ERR(ft))
return ft;
+ autogroups_max_fte = ft->max_fte - num_reserved_entries;
+ if (max_num_groups > autogroups_max_fte)
+ goto err_validate;
+ if (num_reserved_entries > ft->max_fte)
+ goto err_validate;
+
+ /* Align the number of groups according to the largest group size */
+ if (autogroups_max_fte / (max_num_groups + 1) > MAX_FLOW_GROUP_SIZE)
+ max_num_groups = (autogroups_max_fte / MAX_FLOW_GROUP_SIZE) - 1;
+
ft->autogroup.active = true;
ft->autogroup.required_groups = max_num_groups;
ft->autogroup.max_fte = autogroups_max_fte;
@@ -1199,6 +1204,10 @@ mlx5_create_auto_grouped_flow_table(struct mlx5_flow_namespace *ns,
ft->autogroup.group_size = autogroups_max_fte / (max_num_groups + 1);
return ft;
+
+err_validate:
+ mlx5_destroy_flow_table(ft);
+ return ERR_PTR(-ENOSPC);
}
EXPORT_SYMBOL(mlx5_create_auto_grouped_flow_table);
@@ -1495,7 +1504,9 @@ static bool mlx5_flow_dests_cmp(struct mlx5_flow_destination *d1,
(d1->type == MLX5_FLOW_DESTINATION_TYPE_TIR &&
d1->tir_num == d2->tir_num) ||
(d1->type == MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM &&
- d1->ft_num == d2->ft_num))
+ d1->ft_num == d2->ft_num) ||
+ (d1->type == MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER &&
+ d1->sampler_id == d2->sampler_id))
return true;
}
@@ -2592,6 +2603,7 @@ void mlx5_cleanup_fs(struct mlx5_core_dev *dev)
mlx5_cleanup_fc_stats(dev);
kmem_cache_destroy(steering->ftes_cache);
kmem_cache_destroy(steering->fgs_cache);
+ mlx5_ft_pool_destroy(dev);
kfree(steering);
}
@@ -2770,6 +2782,18 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering)
if (err)
goto out_err;
+ maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, FDB_TC_MISS, 1);
+ if (IS_ERR(maj_prio)) {
+ err = PTR_ERR(maj_prio);
+ goto out_err;
+ }
+
+ maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, FDB_BR_OFFLOAD, 3);
+ if (IS_ERR(maj_prio)) {
+ err = PTR_ERR(maj_prio);
+ goto out_err;
+ }
+
maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, FDB_SLOW_PATH, 1);
if (IS_ERR(maj_prio)) {
err = PTR_ERR(maj_prio);
@@ -2942,9 +2966,16 @@ int mlx5_init_fs(struct mlx5_core_dev *dev)
if (err)
return err;
+ err = mlx5_ft_pool_init(dev);
+ if (err)
+ return err;
+
steering = kzalloc(sizeof(*steering), GFP_KERNEL);
- if (!steering)
- return -ENOMEM;
+ if (!steering) {
+ err = -ENOMEM;
+ goto err;
+ }
+
steering->dev = dev;
dev->priv.steering = steering;
@@ -3151,9 +3182,7 @@ void mlx5_modify_header_dealloc(struct mlx5_core_dev *dev,
EXPORT_SYMBOL(mlx5_modify_header_dealloc);
struct mlx5_pkt_reformat *mlx5_packet_reformat_alloc(struct mlx5_core_dev *dev,
- int reformat_type,
- size_t size,
- void *reformat_data,
+ struct mlx5_pkt_reformat_params *params,
enum mlx5_flow_namespace_type ns_type)
{
struct mlx5_pkt_reformat *pkt_reformat;
@@ -3169,9 +3198,8 @@ struct mlx5_pkt_reformat *mlx5_packet_reformat_alloc(struct mlx5_core_dev *dev,
return ERR_PTR(-ENOMEM);
pkt_reformat->ns_type = ns_type;
- pkt_reformat->reformat_type = reformat_type;
- err = root->cmds->packet_reformat_alloc(root, reformat_type, size,
- reformat_data, ns_type,
+ pkt_reformat->reformat_type = params->type;
+ err = root->cmds->packet_reformat_alloc(root, params, ns_type,
pkt_reformat);
if (err) {
kfree(pkt_reformat);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
index e577a2c424af..7317cdeab661 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
@@ -331,6 +331,7 @@ void mlx5_fs_ingress_acls_cleanup(struct mlx5_core_dev *dev);
#define MLX5_CAP_FLOWTABLE_TYPE(mdev, cap, type) ( \
(type == FS_FT_NIC_RX) ? MLX5_CAP_FLOWTABLE_NIC_RX(mdev, cap) : \
+ (type == FS_FT_NIC_TX) ? MLX5_CAP_FLOWTABLE_NIC_TX(mdev, cap) : \
(type == FS_FT_ESW_EGRESS_ACL) ? MLX5_CAP_ESW_EGRESS_ACL(mdev, cap) : \
(type == FS_FT_ESW_INGRESS_ACL) ? MLX5_CAP_ESW_INGRESS_ACL(mdev, cap) : \
(type == FS_FT_FDB) ? MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, cap) : \
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c
new file mode 100644
index 000000000000..c14590acc772
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2021 Mellanox Technologies. */
+
+#include "fs_ft_pool.h"
+
+/* Firmware currently has 4 pool of 4 sizes that it supports (FT_POOLS),
+ * and a virtual memory region of 16M (MLX5_FT_SIZE), this region is duplicated
+ * for each flow table pool. We can allocate up to 16M of each pool,
+ * and we keep track of how much we used via mlx5_ft_pool_get_avail_sz.
+ * Firmware doesn't report any of this for now.
+ * ESW_POOL is expected to be sorted from large to small and match firmware
+ * pools.
+ */
+#define FT_SIZE (16 * 1024 * 1024)
+static const unsigned int FT_POOLS[] = { 4 * 1024 * 1024,
+ 1 * 1024 * 1024,
+ 64 * 1024,
+ 128,
+ 1 /* size for termination tables */ };
+struct mlx5_ft_pool {
+ int ft_left[ARRAY_SIZE(FT_POOLS)];
+};
+
+int mlx5_ft_pool_init(struct mlx5_core_dev *dev)
+{
+ struct mlx5_ft_pool *ft_pool;
+ int i;
+
+ ft_pool = kzalloc(sizeof(*ft_pool), GFP_KERNEL);
+ if (!ft_pool)
+ return -ENOMEM;
+
+ for (i = ARRAY_SIZE(FT_POOLS) - 1; i >= 0; i--)
+ ft_pool->ft_left[i] = FT_SIZE / FT_POOLS[i];
+
+ dev->priv.ft_pool = ft_pool;
+ return 0;
+}
+
+void mlx5_ft_pool_destroy(struct mlx5_core_dev *dev)
+{
+ kfree(dev->priv.ft_pool);
+}
+
+int
+mlx5_ft_pool_get_avail_sz(struct mlx5_core_dev *dev, enum fs_flow_table_type table_type,
+ int desired_size)
+{
+ u32 max_ft_size = 1 << MLX5_CAP_FLOWTABLE_TYPE(dev, log_max_ft_size, table_type);
+ int i, found_i = -1;
+
+ for (i = ARRAY_SIZE(FT_POOLS) - 1; i >= 0; i--) {
+ if (dev->priv.ft_pool->ft_left[i] && FT_POOLS[i] >= desired_size &&
+ FT_POOLS[i] <= max_ft_size) {
+ found_i = i;
+ if (desired_size != POOL_NEXT_SIZE)
+ break;
+ }
+ }
+
+ if (found_i != -1) {
+ --dev->priv.ft_pool->ft_left[found_i];
+ return FT_POOLS[found_i];
+ }
+
+ return 0;
+}
+
+void
+mlx5_ft_pool_put_sz(struct mlx5_core_dev *dev, int sz)
+{
+ int i;
+
+ if (!sz)
+ return;
+
+ for (i = ARRAY_SIZE(FT_POOLS) - 1; i >= 0; i--) {
+ if (sz == FT_POOLS[i]) {
+ ++dev->priv.ft_pool->ft_left[i];
+ return;
+ }
+ }
+
+ WARN_ONCE(1, "Couldn't find size %d in flow table size pool", sz);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h
new file mode 100644
index 000000000000..25f4274b372b
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_ft_pool.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2021 Mellanox Technologies. */
+
+#ifndef __MLX5_FS_FT_POOL_H__
+#define __MLX5_FS_FT_POOL_H__
+
+#include <linux/mlx5/driver.h>
+#include "fs_core.h"
+
+#define POOL_NEXT_SIZE 0
+
+int mlx5_ft_pool_init(struct mlx5_core_dev *dev);
+void mlx5_ft_pool_destroy(struct mlx5_core_dev *dev);
+
+int
+mlx5_ft_pool_get_avail_sz(struct mlx5_core_dev *dev, enum fs_flow_table_type table_type,
+ int desired_size);
+void
+mlx5_ft_pool_put_sz(struct mlx5_core_dev *dev, int sz);
+
+#endif /* __MLX5_FS_FT_POOL_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
index 02558ac2ace6..016d26f809a5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
@@ -148,6 +148,12 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
if (err)
return err;
+ if (MLX5_CAP_GEN(dev, hca_cap_2)) {
+ err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL_2);
+ if (err)
+ return err;
+ }
+
if (MLX5_CAP_GEN(dev, eth_net_offloads)) {
err = mlx5_core_get_caps(dev, MLX5_CAP_ETHERNET_OFFLOADS);
if (err)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
index 97d96fc38a65..0e487ec57d5c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
@@ -150,6 +150,7 @@ enum mlx5_ptys_rate {
MLX5_PTYS_RATE_FDR = 1 << 4,
MLX5_PTYS_RATE_EDR = 1 << 5,
MLX5_PTYS_RATE_HDR = 1 << 6,
+ MLX5_PTYS_RATE_NDR = 1 << 7,
};
static inline int mlx5_ptys_rate_enum_to_int(enum mlx5_ptys_rate rate)
@@ -162,6 +163,7 @@ static inline int mlx5_ptys_rate_enum_to_int(enum mlx5_ptys_rate rate)
case MLX5_PTYS_RATE_FDR: return 14000;
case MLX5_PTYS_RATE_EDR: return 25000;
case MLX5_PTYS_RATE_HDR: return 50000;
+ case MLX5_PTYS_RATE_NDR: return 100000;
default: return -1;
}
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag.c
index b8748390335f..5c043c5cc403 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag.c
@@ -93,6 +93,64 @@ int mlx5_cmd_destroy_vport_lag(struct mlx5_core_dev *dev)
}
EXPORT_SYMBOL(mlx5_cmd_destroy_vport_lag);
+static int mlx5_lag_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr);
+static void mlx5_do_bond_work(struct work_struct *work);
+
+static void mlx5_ldev_free(struct kref *ref)
+{
+ struct mlx5_lag *ldev = container_of(ref, struct mlx5_lag, ref);
+
+ if (ldev->nb.notifier_call)
+ unregister_netdevice_notifier_net(&init_net, &ldev->nb);
+ mlx5_lag_mp_cleanup(ldev);
+ cancel_delayed_work_sync(&ldev->bond_work);
+ destroy_workqueue(ldev->wq);
+ kfree(ldev);
+}
+
+static void mlx5_ldev_put(struct mlx5_lag *ldev)
+{
+ kref_put(&ldev->ref, mlx5_ldev_free);
+}
+
+static void mlx5_ldev_get(struct mlx5_lag *ldev)
+{
+ kref_get(&ldev->ref);
+}
+
+static struct mlx5_lag *mlx5_lag_dev_alloc(struct mlx5_core_dev *dev)
+{
+ struct mlx5_lag *ldev;
+ int err;
+
+ ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
+ if (!ldev)
+ return NULL;
+
+ ldev->wq = create_singlethread_workqueue("mlx5_lag");
+ if (!ldev->wq) {
+ kfree(ldev);
+ return NULL;
+ }
+
+ kref_init(&ldev->ref);
+ INIT_DELAYED_WORK(&ldev->bond_work, mlx5_do_bond_work);
+
+ ldev->nb.notifier_call = mlx5_lag_netdev_event;
+ if (register_netdevice_notifier_net(&init_net, &ldev->nb)) {
+ ldev->nb.notifier_call = NULL;
+ mlx5_core_err(dev, "Failed to register LAG netdev notifier\n");
+ }
+
+ err = mlx5_lag_mp_init(ldev);
+ if (err)
+ mlx5_core_err(dev, "Failed to init multipath lag err=%d\n",
+ err);
+
+ return ldev;
+}
+
int mlx5_lag_dev_get_netdev_idx(struct mlx5_lag *ldev,
struct net_device *ndev)
{
@@ -118,17 +176,24 @@ static bool __mlx5_lag_is_sriov(struct mlx5_lag *ldev)
static void mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker,
u8 *port1, u8 *port2)
{
+ bool p1en;
+ bool p2en;
+
+ p1en = tracker->netdev_state[MLX5_LAG_P1].tx_enabled &&
+ tracker->netdev_state[MLX5_LAG_P1].link_up;
+
+ p2en = tracker->netdev_state[MLX5_LAG_P2].tx_enabled &&
+ tracker->netdev_state[MLX5_LAG_P2].link_up;
+
*port1 = 1;
*port2 = 2;
- if (!tracker->netdev_state[MLX5_LAG_P1].tx_enabled ||
- !tracker->netdev_state[MLX5_LAG_P1].link_up) {
- *port1 = 2;
+ if ((!p1en && !p2en) || (p1en && p2en))
return;
- }
- if (!tracker->netdev_state[MLX5_LAG_P2].tx_enabled ||
- !tracker->netdev_state[MLX5_LAG_P2].link_up)
+ if (p1en)
*port2 = 1;
+ else
+ *port1 = 2;
}
void mlx5_modify_lag(struct mlx5_lag *ldev,
@@ -251,6 +316,10 @@ static void mlx5_lag_add_devices(struct mlx5_lag *ldev)
if (!ldev->pf[i].dev)
continue;
+ if (ldev->pf[i].dev->priv.flags &
+ MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)
+ continue;
+
ldev->pf[i].dev->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
mlx5_rescan_drivers_locked(ldev->pf[i].dev);
}
@@ -269,6 +338,31 @@ static void mlx5_lag_remove_devices(struct mlx5_lag *ldev)
}
}
+static void mlx5_disable_lag(struct mlx5_lag *ldev)
+{
+ struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev;
+ struct mlx5_core_dev *dev1 = ldev->pf[MLX5_LAG_P2].dev;
+ bool roce_lag;
+ int err;
+
+ roce_lag = __mlx5_lag_is_roce(ldev);
+
+ if (roce_lag) {
+ if (!(dev0->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)) {
+ dev0->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
+ mlx5_rescan_drivers_locked(dev0);
+ }
+ mlx5_nic_vport_disable_roce(dev1);
+ }
+
+ err = mlx5_deactivate_lag(ldev);
+ if (err)
+ return;
+
+ if (roce_lag)
+ mlx5_lag_add_devices(ldev);
+}
+
static void mlx5_do_bond(struct mlx5_lag *ldev)
{
struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev;
@@ -280,9 +374,7 @@ static void mlx5_do_bond(struct mlx5_lag *ldev)
if (!mlx5_lag_is_ready(ldev))
return;
- spin_lock(&lag_lock);
tracker = ldev->tracker;
- spin_unlock(&lag_lock);
do_bond = tracker.is_bonded && mlx5_lag_check_prereq(ldev);
@@ -291,8 +383,9 @@ static void mlx5_do_bond(struct mlx5_lag *ldev)
!mlx5_sriov_is_enabled(dev1);
#ifdef CONFIG_MLX5_ESWITCH
- roce_lag &= dev0->priv.eswitch->mode == MLX5_ESWITCH_NONE &&
- dev1->priv.eswitch->mode == MLX5_ESWITCH_NONE;
+ roce_lag = roce_lag &&
+ dev0->priv.eswitch->mode == MLX5_ESWITCH_NONE &&
+ dev1->priv.eswitch->mode == MLX5_ESWITCH_NONE;
#endif
if (roce_lag)
@@ -316,20 +409,7 @@ static void mlx5_do_bond(struct mlx5_lag *ldev)
} else if (do_bond && __mlx5_lag_is_active(ldev)) {
mlx5_modify_lag(ldev, &tracker);
} else if (!do_bond && __mlx5_lag_is_active(ldev)) {
- roce_lag = __mlx5_lag_is_roce(ldev);
-
- if (roce_lag) {
- dev0->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
- mlx5_rescan_drivers_locked(dev0);
- mlx5_nic_vport_disable_roce(dev1);
- }
-
- err = mlx5_deactivate_lag(ldev);
- if (err)
- return;
-
- if (roce_lag)
- mlx5_lag_add_devices(ldev);
+ mlx5_disable_lag(ldev);
}
}
@@ -481,9 +561,7 @@ static int mlx5_lag_netdev_event(struct notifier_block *this,
break;
}
- spin_lock(&lag_lock);
ldev->tracker = tracker;
- spin_unlock(&lag_lock);
if (changed)
mlx5_queue_bond_work(ldev, 0);
@@ -491,55 +569,52 @@ static int mlx5_lag_netdev_event(struct notifier_block *this,
return NOTIFY_DONE;
}
-static struct mlx5_lag *mlx5_lag_dev_alloc(void)
+static void mlx5_ldev_add_netdev(struct mlx5_lag *ldev,
+ struct mlx5_core_dev *dev,
+ struct net_device *netdev)
{
- struct mlx5_lag *ldev;
-
- ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
- if (!ldev)
- return NULL;
-
- ldev->wq = create_singlethread_workqueue("mlx5_lag");
- if (!ldev->wq) {
- kfree(ldev);
- return NULL;
- }
+ unsigned int fn = PCI_FUNC(dev->pdev->devfn);
- INIT_DELAYED_WORK(&ldev->bond_work, mlx5_do_bond_work);
+ if (fn >= MLX5_MAX_PORTS)
+ return;
- return ldev;
+ spin_lock(&lag_lock);
+ ldev->pf[fn].netdev = netdev;
+ ldev->tracker.netdev_state[fn].link_up = 0;
+ ldev->tracker.netdev_state[fn].tx_enabled = 0;
+ spin_unlock(&lag_lock);
}
-static void mlx5_lag_dev_free(struct mlx5_lag *ldev)
+static void mlx5_ldev_remove_netdev(struct mlx5_lag *ldev,
+ struct net_device *netdev)
{
- destroy_workqueue(ldev->wq);
- kfree(ldev);
+ int i;
+
+ spin_lock(&lag_lock);
+ for (i = 0; i < MLX5_MAX_PORTS; i++) {
+ if (ldev->pf[i].netdev == netdev) {
+ ldev->pf[i].netdev = NULL;
+ break;
+ }
+ }
+ spin_unlock(&lag_lock);
}
-static int mlx5_lag_dev_add_pf(struct mlx5_lag *ldev,
- struct mlx5_core_dev *dev,
- struct net_device *netdev)
+static void mlx5_ldev_add_mdev(struct mlx5_lag *ldev,
+ struct mlx5_core_dev *dev)
{
unsigned int fn = PCI_FUNC(dev->pdev->devfn);
if (fn >= MLX5_MAX_PORTS)
- return -EPERM;
-
- spin_lock(&lag_lock);
- ldev->pf[fn].dev = dev;
- ldev->pf[fn].netdev = netdev;
- ldev->tracker.netdev_state[fn].link_up = 0;
- ldev->tracker.netdev_state[fn].tx_enabled = 0;
+ return;
+ ldev->pf[fn].dev = dev;
dev->priv.lag = ldev;
-
- spin_unlock(&lag_lock);
-
- return fn;
}
-static void mlx5_lag_dev_remove_pf(struct mlx5_lag *ldev,
- struct mlx5_core_dev *dev)
+/* Must be called with intf_mutex held */
+static void mlx5_ldev_remove_mdev(struct mlx5_lag *ldev,
+ struct mlx5_core_dev *dev)
{
int i;
@@ -550,19 +625,15 @@ static void mlx5_lag_dev_remove_pf(struct mlx5_lag *ldev,
if (i == MLX5_MAX_PORTS)
return;
- spin_lock(&lag_lock);
- memset(&ldev->pf[i], 0, sizeof(*ldev->pf));
-
+ ldev->pf[i].dev = NULL;
dev->priv.lag = NULL;
- spin_unlock(&lag_lock);
}
/* Must be called with intf_mutex held */
-void mlx5_lag_add(struct mlx5_core_dev *dev, struct net_device *netdev)
+static void __mlx5_lag_dev_add_mdev(struct mlx5_core_dev *dev)
{
struct mlx5_lag *ldev = NULL;
struct mlx5_core_dev *tmp_dev;
- int i, err;
if (!MLX5_CAP_GEN(dev, vport_group_manager) ||
!MLX5_CAP_GEN(dev, lag_master) ||
@@ -574,67 +645,77 @@ void mlx5_lag_add(struct mlx5_core_dev *dev, struct net_device *netdev)
ldev = tmp_dev->priv.lag;
if (!ldev) {
- ldev = mlx5_lag_dev_alloc();
+ ldev = mlx5_lag_dev_alloc(dev);
if (!ldev) {
mlx5_core_err(dev, "Failed to alloc lag dev\n");
return;
}
+ } else {
+ mlx5_ldev_get(ldev);
}
- if (mlx5_lag_dev_add_pf(ldev, dev, netdev) < 0)
- return;
+ mlx5_ldev_add_mdev(ldev, dev);
- for (i = 0; i < MLX5_MAX_PORTS; i++)
- if (!ldev->pf[i].dev)
- break;
+ return;
+}
- if (i >= MLX5_MAX_PORTS)
- ldev->flags |= MLX5_LAG_FLAG_READY;
+void mlx5_lag_remove_mdev(struct mlx5_core_dev *dev)
+{
+ struct mlx5_lag *ldev;
- if (!ldev->nb.notifier_call) {
- ldev->nb.notifier_call = mlx5_lag_netdev_event;
- if (register_netdevice_notifier_net(&init_net, &ldev->nb)) {
- ldev->nb.notifier_call = NULL;
- mlx5_core_err(dev, "Failed to register LAG netdev notifier\n");
- }
- }
+ ldev = mlx5_lag_dev(dev);
+ if (!ldev)
+ return;
- err = mlx5_lag_mp_init(ldev);
- if (err)
- mlx5_core_err(dev, "Failed to init multipath lag err=%d\n",
- err);
+ mlx5_dev_list_lock();
+ mlx5_ldev_remove_mdev(ldev, dev);
+ mlx5_dev_list_unlock();
+ mlx5_ldev_put(ldev);
+}
+
+void mlx5_lag_add_mdev(struct mlx5_core_dev *dev)
+{
+ mlx5_dev_list_lock();
+ __mlx5_lag_dev_add_mdev(dev);
+ mlx5_dev_list_unlock();
}
/* Must be called with intf_mutex held */
-void mlx5_lag_remove(struct mlx5_core_dev *dev)
+void mlx5_lag_remove_netdev(struct mlx5_core_dev *dev,
+ struct net_device *netdev)
{
struct mlx5_lag *ldev;
- int i;
- ldev = mlx5_lag_dev_get(dev);
+ ldev = mlx5_lag_dev(dev);
if (!ldev)
return;
if (__mlx5_lag_is_active(ldev))
- mlx5_deactivate_lag(ldev);
-
- mlx5_lag_dev_remove_pf(ldev, dev);
+ mlx5_disable_lag(ldev);
+ mlx5_ldev_remove_netdev(ldev, netdev);
ldev->flags &= ~MLX5_LAG_FLAG_READY;
+}
+
+/* Must be called with intf_mutex held */
+void mlx5_lag_add_netdev(struct mlx5_core_dev *dev,
+ struct net_device *netdev)
+{
+ struct mlx5_lag *ldev;
+ int i;
+
+ ldev = mlx5_lag_dev(dev);
+ if (!ldev)
+ return;
+
+ mlx5_ldev_add_netdev(ldev, dev, netdev);
for (i = 0; i < MLX5_MAX_PORTS; i++)
- if (ldev->pf[i].dev)
+ if (!ldev->pf[i].dev)
break;
- if (i == MLX5_MAX_PORTS) {
- if (ldev->nb.notifier_call) {
- unregister_netdevice_notifier_net(&init_net, &ldev->nb);
- ldev->nb.notifier_call = NULL;
- }
- mlx5_lag_mp_cleanup(ldev);
- cancel_delayed_work_sync(&ldev->bond_work);
- mlx5_lag_dev_free(ldev);
- }
+ if (i >= MLX5_MAX_PORTS)
+ ldev->flags |= MLX5_LAG_FLAG_READY;
}
bool mlx5_lag_is_roce(struct mlx5_core_dev *dev)
@@ -643,7 +724,7 @@ bool mlx5_lag_is_roce(struct mlx5_core_dev *dev)
bool res;
spin_lock(&lag_lock);
- ldev = mlx5_lag_dev_get(dev);
+ ldev = mlx5_lag_dev(dev);
res = ldev && __mlx5_lag_is_roce(ldev);
spin_unlock(&lag_lock);
@@ -657,7 +738,7 @@ bool mlx5_lag_is_active(struct mlx5_core_dev *dev)
bool res;
spin_lock(&lag_lock);
- ldev = mlx5_lag_dev_get(dev);
+ ldev = mlx5_lag_dev(dev);
res = ldev && __mlx5_lag_is_active(ldev);
spin_unlock(&lag_lock);
@@ -671,7 +752,7 @@ bool mlx5_lag_is_sriov(struct mlx5_core_dev *dev)
bool res;
spin_lock(&lag_lock);
- ldev = mlx5_lag_dev_get(dev);
+ ldev = mlx5_lag_dev(dev);
res = ldev && __mlx5_lag_is_sriov(ldev);
spin_unlock(&lag_lock);
@@ -684,7 +765,7 @@ void mlx5_lag_update(struct mlx5_core_dev *dev)
struct mlx5_lag *ldev;
mlx5_dev_list_lock();
- ldev = mlx5_lag_dev_get(dev);
+ ldev = mlx5_lag_dev(dev);
if (!ldev)
goto unlock;
@@ -700,7 +781,7 @@ struct net_device *mlx5_lag_get_roce_netdev(struct mlx5_core_dev *dev)
struct mlx5_lag *ldev;
spin_lock(&lag_lock);
- ldev = mlx5_lag_dev_get(dev);
+ ldev = mlx5_lag_dev(dev);
if (!(ldev && __mlx5_lag_is_roce(ldev)))
goto unlock;
@@ -729,7 +810,7 @@ u8 mlx5_lag_get_slave_port(struct mlx5_core_dev *dev,
u8 port = 0;
spin_lock(&lag_lock);
- ldev = mlx5_lag_dev_get(dev);
+ ldev = mlx5_lag_dev(dev);
if (!(ldev && __mlx5_lag_is_roce(ldev)))
goto unlock;
@@ -765,7 +846,7 @@ int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev,
memset(values, 0, sizeof(*values) * num_counters);
spin_lock(&lag_lock);
- ldev = mlx5_lag_dev_get(dev);
+ ldev = mlx5_lag_dev(dev);
if (ldev && __mlx5_lag_is_active(ldev)) {
num_ports = MLX5_MAX_PORTS;
mdev[MLX5_LAG_P1] = ldev->pf[MLX5_LAG_P1].dev;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag.h
index 8d8cf2d0bc6d..191392c37558 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag.h
@@ -40,6 +40,7 @@ struct lag_tracker {
struct mlx5_lag {
u8 flags;
u8 v2p_map[MLX5_MAX_PORTS];
+ struct kref ref;
struct lag_func pf[MLX5_MAX_PORTS];
struct lag_tracker tracker;
struct workqueue_struct *wq;
@@ -49,7 +50,7 @@ struct mlx5_lag {
};
static inline struct mlx5_lag *
-mlx5_lag_dev_get(struct mlx5_core_dev *dev)
+mlx5_lag_dev(struct mlx5_core_dev *dev)
{
return dev->priv.lag;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c
index fd6196b5e163..c4bf8b679541 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c
@@ -28,7 +28,7 @@ bool mlx5_lag_is_multipath(struct mlx5_core_dev *dev)
struct mlx5_lag *ldev;
bool res;
- ldev = mlx5_lag_dev_get(dev);
+ ldev = mlx5_lag_dev(dev);
res = ldev && __mlx5_lag_is_multipath(ldev);
return res;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h
index ceae6bc378e0..bd95b9f8d143 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h
@@ -37,16 +37,18 @@ static inline bool mlx5_is_real_time_rq(struct mlx5_core_dev *mdev)
{
u8 rq_ts_format_cap = MLX5_CAP_GEN(mdev, rq_ts_format);
- return (rq_ts_format_cap == MLX5_RQ_TIMESTAMP_FORMAT_CAP_REAL_TIME ||
- rq_ts_format_cap == MLX5_RQ_TIMESTAMP_FORMAT_CAP_FREE_RUNNING_AND_REAL_TIME);
+ return (rq_ts_format_cap == MLX5_TIMESTAMP_FORMAT_CAP_REAL_TIME ||
+ rq_ts_format_cap ==
+ MLX5_TIMESTAMP_FORMAT_CAP_FREE_RUNNING_AND_REAL_TIME);
}
static inline bool mlx5_is_real_time_sq(struct mlx5_core_dev *mdev)
{
u8 sq_ts_format_cap = MLX5_CAP_GEN(mdev, sq_ts_format);
- return (sq_ts_format_cap == MLX5_SQ_TIMESTAMP_FORMAT_CAP_REAL_TIME ||
- sq_ts_format_cap == MLX5_SQ_TIMESTAMP_FORMAT_CAP_FREE_RUNNING_AND_REAL_TIME);
+ return (sq_ts_format_cap == MLX5_TIMESTAMP_FORMAT_CAP_REAL_TIME ||
+ sq_ts_format_cap ==
+ MLX5_TIMESTAMP_FORMAT_CAP_FREE_RUNNING_AND_REAL_TIME);
}
typedef ktime_t (*cqe_ts_to_ns)(struct mlx5_clock *, u64);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
index f607a3858ef5..624cedebb510 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
-/* Copyright (c) 2018 Mellanox Technologies */
+/* Copyright (c) 2018-2021, Mellanox Technologies inc. All rights reserved. */
#ifndef __LIB_MLX5_EQ_H__
#define __LIB_MLX5_EQ_H__
@@ -32,6 +32,7 @@ struct mlx5_eq {
unsigned int irqn;
u8 eqn;
struct mlx5_rsc_debug *dbg;
+ struct mlx5_irq *irq;
};
struct mlx5_eq_async {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c
index 20a4047f2737..97e5845b4cfd 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c
@@ -6,6 +6,7 @@
#include <linux/mlx5/fs.h>
#include "lib/fs_chains.h"
+#include "fs_ft_pool.h"
#include "en/mapping.h"
#include "fs_core.h"
#include "en_tc.h"
@@ -13,25 +14,10 @@
#define chains_lock(chains) ((chains)->lock)
#define chains_ht(chains) ((chains)->chains_ht)
#define prios_ht(chains) ((chains)->prios_ht)
-#define ft_pool_left(chains) ((chains)->ft_left)
#define tc_default_ft(chains) ((chains)->tc_default_ft)
#define tc_end_ft(chains) ((chains)->tc_end_ft)
#define ns_to_chains_fs_prio(ns) ((ns) == MLX5_FLOW_NAMESPACE_FDB ? \
FDB_TC_OFFLOAD : MLX5E_TC_PRIO)
-
-/* Firmware currently has 4 pool of 4 sizes that it supports (FT_POOLS),
- * and a virtual memory region of 16M (MLX5_FT_SIZE), this region is duplicated
- * for each flow table pool. We can allocate up to 16M of each pool,
- * and we keep track of how much we used via get_next_avail_sz_from_pool.
- * Firmware doesn't report any of this for now.
- * ESW_POOL is expected to be sorted from large to small and match firmware
- * pools.
- */
-#define FT_SIZE (16 * 1024 * 1024)
-static const unsigned int FT_POOLS[] = { 4 * 1024 * 1024,
- 1 * 1024 * 1024,
- 64 * 1024,
- 128 };
#define FT_TBL_SZ (64 * 1024)
struct mlx5_fs_chains {
@@ -49,8 +35,6 @@ struct mlx5_fs_chains {
enum mlx5_flow_namespace_type ns;
u32 group_num;
u32 flags;
-
- int ft_left[ARRAY_SIZE(FT_POOLS)];
};
struct fs_chain {
@@ -160,54 +144,6 @@ mlx5_chains_set_end_ft(struct mlx5_fs_chains *chains,
tc_end_ft(chains) = ft;
}
-#define POOL_NEXT_SIZE 0
-static int
-mlx5_chains_get_avail_sz_from_pool(struct mlx5_fs_chains *chains,
- int desired_size)
-{
- int i, found_i = -1;
-
- for (i = ARRAY_SIZE(FT_POOLS) - 1; i >= 0; i--) {
- if (ft_pool_left(chains)[i] && FT_POOLS[i] > desired_size) {
- found_i = i;
- if (desired_size != POOL_NEXT_SIZE)
- break;
- }
- }
-
- if (found_i != -1) {
- --ft_pool_left(chains)[found_i];
- return FT_POOLS[found_i];
- }
-
- return 0;
-}
-
-static void
-mlx5_chains_put_sz_to_pool(struct mlx5_fs_chains *chains, int sz)
-{
- int i;
-
- for (i = ARRAY_SIZE(FT_POOLS) - 1; i >= 0; i--) {
- if (sz == FT_POOLS[i]) {
- ++ft_pool_left(chains)[i];
- return;
- }
- }
-
- WARN_ONCE(1, "Couldn't find size %d in flow table size pool", sz);
-}
-
-static void
-mlx5_chains_init_sz_pool(struct mlx5_fs_chains *chains, u32 ft_max)
-{
- int i;
-
- for (i = ARRAY_SIZE(FT_POOLS) - 1; i >= 0; i--)
- ft_pool_left(chains)[i] =
- FT_POOLS[i] <= ft_max ? FT_SIZE / FT_POOLS[i] : 0;
-}
-
static struct mlx5_flow_table *
mlx5_chains_create_table(struct mlx5_fs_chains *chains,
u32 chain, u32 prio, u32 level)
@@ -221,11 +157,7 @@ mlx5_chains_create_table(struct mlx5_fs_chains *chains,
ft_attr.flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
- sz = (chain == mlx5_chains_get_nf_ft_chain(chains)) ?
- mlx5_chains_get_avail_sz_from_pool(chains, FT_TBL_SZ) :
- mlx5_chains_get_avail_sz_from_pool(chains, POOL_NEXT_SIZE);
- if (!sz)
- return ERR_PTR(-ENOSPC);
+ sz = (chain == mlx5_chains_get_nf_ft_chain(chains)) ? FT_TBL_SZ : POOL_NEXT_SIZE;
ft_attr.max_fte = sz;
/* We use tc_default_ft(chains) as the table's next_ft till
@@ -266,21 +198,12 @@ mlx5_chains_create_table(struct mlx5_fs_chains *chains,
if (IS_ERR(ft)) {
mlx5_core_warn(chains->dev, "Failed to create chains table err %d (chain: %d, prio: %d, level: %d, size: %d)\n",
(int)PTR_ERR(ft), chain, prio, level, sz);
- mlx5_chains_put_sz_to_pool(chains, sz);
return ft;
}
return ft;
}
-static void
-mlx5_chains_destroy_table(struct mlx5_fs_chains *chains,
- struct mlx5_flow_table *ft)
-{
- mlx5_chains_put_sz_to_pool(chains, ft->max_fte);
- mlx5_destroy_flow_table(ft);
-}
-
static int
create_chain_restore(struct fs_chain *chain)
{
@@ -336,9 +259,10 @@ create_chain_restore(struct fs_chain *chain)
MLX5_SET(set_action_in, modact, field,
mlx5e_tc_attr_to_reg_mappings[chain_to_reg].mfield);
MLX5_SET(set_action_in, modact, offset,
- mlx5e_tc_attr_to_reg_mappings[chain_to_reg].moffset * 8);
+ mlx5e_tc_attr_to_reg_mappings[chain_to_reg].moffset);
MLX5_SET(set_action_in, modact, length,
- mlx5e_tc_attr_to_reg_mappings[chain_to_reg].mlen * 8);
+ mlx5e_tc_attr_to_reg_mappings[chain_to_reg].mlen == 32 ?
+ 0 : mlx5e_tc_attr_to_reg_mappings[chain_to_reg].mlen);
MLX5_SET(set_action_in, modact, data, chain->id);
mod_hdr = mlx5_modify_header_alloc(chains->dev, chains->ns,
1, modact);
@@ -636,7 +560,7 @@ err_insert:
err_miss_rule:
mlx5_destroy_flow_group(miss_group);
err_group:
- mlx5_chains_destroy_table(chains, ft);
+ mlx5_destroy_flow_table(ft);
err_create:
err_alloc:
kvfree(prio_s);
@@ -659,7 +583,7 @@ mlx5_chains_destroy_prio(struct mlx5_fs_chains *chains,
prio_params);
mlx5_del_flow_rules(prio->miss_rule);
mlx5_destroy_flow_group(prio->miss_group);
- mlx5_chains_destroy_table(chains, prio->ft);
+ mlx5_destroy_flow_table(prio->ft);
mlx5_chains_put_chain(chain);
kvfree(prio);
}
@@ -784,7 +708,7 @@ void
mlx5_chains_destroy_global_table(struct mlx5_fs_chains *chains,
struct mlx5_flow_table *ft)
{
- mlx5_chains_destroy_table(chains, ft);
+ mlx5_destroy_flow_table(ft);
}
static struct mlx5_fs_chains *
@@ -816,8 +740,6 @@ mlx5_chains_init(struct mlx5_core_dev *dev, struct mlx5_chains_attr *attr)
mlx5_chains_get_chain_range(chains_priv),
mlx5_chains_get_prio_range(chains_priv));
- mlx5_chains_init_sz_pool(chains_priv, attr->max_ft_sz);
-
err = rhashtable_init(&chains_ht(chains_priv), &chain_params);
if (err)
goto init_chains_ht_err;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/sf.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/sf.h
new file mode 100644
index 000000000000..84e5683861be
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/sf.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2021 Mellanox Technologies Ltd */
+
+#ifndef __LIB_MLX5_SF_H__
+#define __LIB_MLX5_SF_H__
+
+#include <linux/mlx5/driver.h>
+
+static inline u16 mlx5_sf_start_function_id(const struct mlx5_core_dev *dev)
+{
+ return MLX5_CAP_GEN(dev, sf_base_id);
+}
+
+#ifdef CONFIG_MLX5_SF
+
+static inline bool mlx5_sf_supported(const struct mlx5_core_dev *dev)
+{
+ return MLX5_CAP_GEN(dev, sf);
+}
+
+static inline u16 mlx5_sf_max_functions(const struct mlx5_core_dev *dev)
+{
+ if (!mlx5_sf_supported(dev))
+ return 0;
+ if (MLX5_CAP_GEN(dev, max_num_sf))
+ return MLX5_CAP_GEN(dev, max_num_sf);
+ else
+ return 1 << MLX5_CAP_GEN(dev, log_max_sf);
+}
+
+#else
+
+static inline bool mlx5_sf_supported(const struct mlx5_core_dev *dev)
+{
+ return false;
+}
+
+static inline u16 mlx5_sf_max_functions(const struct mlx5_core_dev *dev)
+{
+ return 0;
+}
+
+#endif
+
+#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 0d0f63a27aba..eb1b316560a8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -76,6 +76,7 @@
#include "sf/vhca_event.h"
#include "sf/dev/dev.h"
#include "sf/sf.h"
+#include "mlx5_irq.h"
MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
MODULE_DESCRIPTION("Mellanox 5th generation network adapters (ConnectX series) core driver");
@@ -1185,6 +1186,7 @@ static int mlx5_load(struct mlx5_core_dev *dev)
}
mlx5_sf_dev_table_create(dev);
+ mlx5_lag_add_mdev(dev);
return 0;
@@ -1220,6 +1222,7 @@ err_irq_table:
static void mlx5_unload(struct mlx5_core_dev *dev)
{
+ mlx5_lag_remove_mdev(dev);
mlx5_sf_dev_table_destroy(dev);
mlx5_sriov_detach(dev);
mlx5_ec_cleanup(dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index a22b706eebd3..343807ac2036 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -164,27 +164,10 @@ int mlx5_query_mcam_reg(struct mlx5_core_dev *dev, u32 *mcap, u8 feature_group,
int mlx5_query_qcam_reg(struct mlx5_core_dev *mdev, u32 *qcam,
u8 feature_group, u8 access_reg_group);
-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);
-
-int mlx5_set_msix_vec_count(struct mlx5_core_dev *dev, int devfn,
- int msix_vec_count);
-int mlx5_get_default_msix_vec_count(struct mlx5_core_dev *dev, int num_vfs);
-
-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);
-struct mlx5_irq_table *mlx5_irq_table_get(struct mlx5_core_dev *dev);
+void mlx5_lag_add_netdev(struct mlx5_core_dev *dev, struct net_device *netdev);
+void mlx5_lag_remove_netdev(struct mlx5_core_dev *dev, struct net_device *netdev);
+void mlx5_lag_add_mdev(struct mlx5_core_dev *dev);
+void mlx5_lag_remove_mdev(struct mlx5_core_dev *dev);
int mlx5_events_init(struct mlx5_core_dev *dev);
void mlx5_events_cleanup(struct mlx5_core_dev *dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_irq.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_irq.h
new file mode 100644
index 000000000000..abd024173c42
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_irq.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2021 Mellanox Technologies. */
+
+#ifndef __MLX5_IRQ_H__
+#define __MLX5_IRQ_H__
+
+#include <linux/mlx5/driver.h>
+
+#define MLX5_COMP_EQS_PER_SF 8
+
+#define MLX5_IRQ_EQ_CTRL (0)
+
+struct mlx5_irq;
+
+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_table_get_num_comp(struct mlx5_irq_table *table);
+int mlx5_irq_table_get_sfs_vec(struct mlx5_irq_table *table);
+struct mlx5_irq_table *mlx5_irq_table_get(struct mlx5_core_dev *dev);
+
+int mlx5_set_msix_vec_count(struct mlx5_core_dev *dev, int devfn,
+ int msix_vec_count);
+int mlx5_get_default_msix_vec_count(struct mlx5_core_dev *dev, int num_vfs);
+
+struct mlx5_irq *mlx5_irq_request(struct mlx5_core_dev *dev, u16 vecidx,
+ struct cpumask *affinity);
+void mlx5_irq_release(struct mlx5_irq *irq);
+int mlx5_irq_attach_nb(struct mlx5_irq *irq, struct notifier_block *nb);
+int mlx5_irq_detach_nb(struct mlx5_irq *irq, struct notifier_block *nb);
+struct cpumask *mlx5_irq_get_affinity_mask(struct mlx5_irq *irq);
+int mlx5_irq_get_index(struct mlx5_irq *irq);
+
+#endif /* __MLX5_IRQ_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
index c3373fb1cd7f..b25f764daa08 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
@@ -6,60 +6,52 @@
#include <linux/module.h>
#include <linux/mlx5/driver.h>
#include "mlx5_core.h"
+#include "mlx5_irq.h"
+#include "lib/sf.h"
#ifdef CONFIG_RFS_ACCEL
#include <linux/cpu_rmap.h>
#endif
#define MLX5_MAX_IRQ_NAME (32)
+/* max irq_index is 255. three chars */
+#define MLX5_MAX_IRQ_IDX_CHARS (3)
+
+#define MLX5_SFS_PER_CTRL_IRQ 64
+#define MLX5_IRQ_CTRL_SF_MAX 8
+/* min num of vectores for SFs to be enabled */
+#define MLX5_IRQ_VEC_COMP_BASE_SF 2
+
+#define MLX5_EQ_SHARE_IRQ_MAX_COMP (8)
+#define MLX5_EQ_SHARE_IRQ_MAX_CTRL (UINT_MAX)
+#define MLX5_EQ_SHARE_IRQ_MIN_COMP (1)
+#define MLX5_EQ_SHARE_IRQ_MIN_CTRL (4)
+#define MLX5_EQ_REFS_PER_IRQ (2)
struct mlx5_irq {
+ u32 index;
struct atomic_notifier_head nh;
cpumask_var_t mask;
char name[MLX5_MAX_IRQ_NAME];
+ struct kref kref;
+ int irqn;
+ struct mlx5_irq_pool *pool;
};
-struct mlx5_irq_table {
- struct mlx5_irq *irq;
- int nvec;
-#ifdef CONFIG_RFS_ACCEL
- struct cpu_rmap *rmap;
-#endif
+struct mlx5_irq_pool {
+ char name[MLX5_MAX_IRQ_NAME - MLX5_MAX_IRQ_IDX_CHARS];
+ struct xa_limit xa_num_irqs;
+ struct mutex lock; /* sync IRQs creations */
+ struct xarray irqs;
+ u32 max_threshold;
+ u32 min_threshold;
+ struct mlx5_core_dev *dev;
};
-int mlx5_irq_table_init(struct mlx5_core_dev *dev)
-{
- struct mlx5_irq_table *irq_table;
-
- if (mlx5_core_is_sf(dev))
- return 0;
-
- 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)
-{
- if (mlx5_core_is_sf(dev))
- return;
-
- 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];
-}
+struct mlx5_irq_table {
+ struct mlx5_irq_pool *pf_pool;
+ struct mlx5_irq_pool *sf_ctrl_pool;
+ struct mlx5_irq_pool *sf_comp_pool;
+};
/**
* mlx5_get_default_msix_vec_count - Get the default number of MSI-X vectors
@@ -146,34 +138,46 @@ out:
return ret;
}
-int mlx5_irq_attach_nb(struct mlx5_irq_table *irq_table, int vecidx,
- struct notifier_block *nb)
+static void irq_release(struct kref *kref)
{
- struct mlx5_irq *irq;
+ struct mlx5_irq *irq = container_of(kref, struct mlx5_irq, kref);
+ struct mlx5_irq_pool *pool = irq->pool;
- irq = &irq_table->irq[vecidx];
- return atomic_notifier_chain_register(&irq->nh, nb);
+ xa_erase(&pool->irqs, irq->index);
+ /* 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_set_affinity_hint(irq->irqn, NULL);
+ free_cpumask_var(irq->mask);
+ free_irq(irq->irqn, &irq->nh);
+ kfree(irq);
}
-int mlx5_irq_detach_nb(struct mlx5_irq_table *irq_table, int vecidx,
- struct notifier_block *nb)
+static void irq_put(struct mlx5_irq *irq)
{
- struct mlx5_irq *irq;
+ struct mlx5_irq_pool *pool = irq->pool;
- irq = &irq_table->irq[vecidx];
- return atomic_notifier_chain_unregister(&irq->nh, nb);
+ mutex_lock(&pool->lock);
+ kref_put(&irq->kref, irq_release);
+ mutex_unlock(&pool->lock);
}
-static irqreturn_t mlx5_irq_int_handler(int irq, void *nh)
+static irqreturn_t irq_int_handler(int irq, void *nh)
{
atomic_notifier_call_chain(nh, 0, NULL);
return IRQ_HANDLED;
}
+static void irq_sf_set_name(struct mlx5_irq_pool *pool, char *name, int vecidx)
+{
+ snprintf(name, MLX5_MAX_IRQ_NAME, "%s%d", pool->name, vecidx);
+}
+
static void irq_set_name(char *name, int vecidx)
{
if (vecidx == 0) {
- snprintf(name, MLX5_MAX_IRQ_NAME, "mlx5_async");
+ snprintf(name, MLX5_MAX_IRQ_NAME, "mlx5_async%d", vecidx);
return;
}
@@ -181,251 +185,431 @@ static void irq_set_name(char *name, int vecidx)
vecidx - MLX5_IRQ_VEC_COMP_BASE);
}
-static int request_irqs(struct mlx5_core_dev *dev, int nvec)
+static struct mlx5_irq *irq_request(struct mlx5_irq_pool *pool, int i)
{
+ struct mlx5_core_dev *dev = pool->dev;
char name[MLX5_MAX_IRQ_NAME];
+ struct mlx5_irq *irq;
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 = kzalloc(sizeof(*irq), GFP_KERNEL);
+ if (!irq)
+ return ERR_PTR(-ENOMEM);
+ irq->irqn = pci_irq_vector(dev->pdev, i);
+ if (!pool->name[0])
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;
- }
+ else
+ irq_sf_set_name(pool, 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(irq->irqn, irq_int_handler, 0, irq->name,
+ &irq->nh);
+ if (err) {
+ mlx5_core_err(dev, "Failed to request irq. err = %d\n", err);
+ goto err_req_irq;
}
- return 0;
+ if (!zalloc_cpumask_var(&irq->mask, GFP_KERNEL)) {
+ mlx5_core_warn(dev, "zalloc_cpumask_var failed\n");
+ err = -ENOMEM;
+ goto err_cpumask;
+ }
+ kref_init(&irq->kref);
+ irq->index = i;
+ err = xa_err(xa_store(&pool->irqs, irq->index, irq, GFP_KERNEL));
+ if (err) {
+ mlx5_core_err(dev, "Failed to alloc xa entry for irq(%u). err = %d\n",
+ irq->index, err);
+ goto err_xa;
+ }
+ irq->pool = pool;
+ return irq;
+err_xa:
+ free_cpumask_var(irq->mask);
+err_cpumask:
+ free_irq(irq->irqn, &irq->nh);
+err_req_irq:
+ kfree(irq);
+ return ERR_PTR(err);
+}
-err_request_irq:
- while (i--) {
- struct mlx5_irq *irq = mlx5_irq_get(dev, i);
- int irqn = pci_irq_vector(dev->pdev, i);
+int mlx5_irq_attach_nb(struct mlx5_irq *irq, struct notifier_block *nb)
+{
+ int err;
- free_irq(irqn, &irq->nh);
- }
- return err;
+ err = kref_get_unless_zero(&irq->kref);
+ if (WARN_ON_ONCE(!err))
+ /* Something very bad happens here, we are enabling EQ
+ * on non-existing IRQ.
+ */
+ return -ENOENT;
+ err = atomic_notifier_chain_register(&irq->nh, nb);
+ if (err)
+ irq_put(irq);
+ return err;
}
-static void irq_clear_rmap(struct mlx5_core_dev *dev)
+int mlx5_irq_detach_nb(struct mlx5_irq *irq, struct notifier_block *nb)
{
-#ifdef CONFIG_RFS_ACCEL
- struct mlx5_irq_table *irq_table = dev->priv.irq_table;
+ irq_put(irq);
+ return atomic_notifier_chain_unregister(&irq->nh, nb);
+}
- free_irq_cpu_rmap(irq_table->rmap);
-#endif
+struct cpumask *mlx5_irq_get_affinity_mask(struct mlx5_irq *irq)
+{
+ return irq->mask;
}
-static int irq_set_rmap(struct mlx5_core_dev *mdev)
+int mlx5_irq_get_index(struct mlx5_irq *irq)
{
- int err = 0;
-#ifdef CONFIG_RFS_ACCEL
- struct mlx5_irq_table *irq_table = mdev->priv.irq_table;
- int num_affinity_vec;
- int vecidx;
+ return irq->index;
+}
- 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;
+/* irq_pool API */
+
+/* creating an irq from irq_pool */
+static struct mlx5_irq *irq_pool_create_irq(struct mlx5_irq_pool *pool,
+ struct cpumask *affinity)
+{
+ struct mlx5_irq *irq;
+ u32 irq_index;
+ int err;
+
+ err = xa_alloc(&pool->irqs, &irq_index, NULL, pool->xa_num_irqs,
+ GFP_KERNEL);
+ if (err)
+ return ERR_PTR(err);
+ irq = irq_request(pool, irq_index);
+ if (IS_ERR(irq))
+ return irq;
+ cpumask_copy(irq->mask, affinity);
+ irq_set_affinity_hint(irq->irqn, irq->mask);
+ return irq;
+}
+
+/* looking for the irq with the smallest refcount and the same affinity */
+static struct mlx5_irq *irq_pool_find_least_loaded(struct mlx5_irq_pool *pool,
+ struct cpumask *affinity)
+{
+ int start = pool->xa_num_irqs.min;
+ int end = pool->xa_num_irqs.max;
+ struct mlx5_irq *irq = NULL;
+ struct mlx5_irq *iter;
+ unsigned long index;
+
+ lockdep_assert_held(&pool->lock);
+ xa_for_each_range(&pool->irqs, index, iter, start, end) {
+ if (!cpumask_equal(iter->mask, affinity))
+ continue;
+ if (kref_read(&iter->kref) < pool->min_threshold)
+ return iter;
+ if (!irq || kref_read(&iter->kref) <
+ kref_read(&irq->kref))
+ irq = iter;
}
+ return irq;
+}
+
+/* requesting an irq from a given pool according to given affinity */
+static struct mlx5_irq *irq_pool_request_affinity(struct mlx5_irq_pool *pool,
+ struct cpumask *affinity)
+{
+ struct mlx5_irq *least_loaded_irq, *new_irq;
- 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;
+ mutex_lock(&pool->lock);
+ least_loaded_irq = irq_pool_find_least_loaded(pool, affinity);
+ if (least_loaded_irq &&
+ kref_read(&least_loaded_irq->kref) < pool->min_threshold)
+ goto out;
+ new_irq = irq_pool_create_irq(pool, affinity);
+ if (IS_ERR(new_irq)) {
+ if (!least_loaded_irq) {
+ mlx5_core_err(pool->dev, "Didn't find IRQ for cpu = %u\n",
+ cpumask_first(affinity));
+ mutex_unlock(&pool->lock);
+ return new_irq;
}
+ /* We failed to create a new IRQ for the requested affinity,
+ * sharing existing IRQ.
+ */
+ goto out;
}
- return 0;
+ least_loaded_irq = new_irq;
+ goto unlock;
+out:
+ kref_get(&least_loaded_irq->kref);
+ if (kref_read(&least_loaded_irq->kref) > pool->max_threshold)
+ mlx5_core_dbg(pool->dev, "IRQ %u overloaded, pool_name: %s, %u EQs on this irq\n",
+ least_loaded_irq->irqn, pool->name,
+ kref_read(&least_loaded_irq->kref) / MLX5_EQ_REFS_PER_IRQ);
+unlock:
+ mutex_unlock(&pool->lock);
+ return least_loaded_irq;
+}
-err_irq_cpu_rmap_add:
- irq_clear_rmap(mdev);
-err_out:
-#endif
- return err;
+/* requesting an irq from a given pool according to given index */
+static struct mlx5_irq *
+irq_pool_request_vector(struct mlx5_irq_pool *pool, int vecidx,
+ struct cpumask *affinity)
+{
+ struct mlx5_irq *irq;
+
+ mutex_lock(&pool->lock);
+ irq = xa_load(&pool->irqs, vecidx);
+ if (irq) {
+ kref_get(&irq->kref);
+ goto unlock;
+ }
+ irq = irq_request(pool, vecidx);
+ if (IS_ERR(irq) || !affinity)
+ goto unlock;
+ cpumask_copy(irq->mask, affinity);
+ irq_set_affinity_hint(irq->irqn, irq->mask);
+unlock:
+ mutex_unlock(&pool->lock);
+ return irq;
}
-/* Completion IRQ vectors */
+static struct mlx5_irq_pool *find_sf_irq_pool(struct mlx5_irq_table *irq_table,
+ int i, struct cpumask *affinity)
+{
+ if (cpumask_empty(affinity) && i == MLX5_IRQ_EQ_CTRL)
+ return irq_table->sf_ctrl_pool;
+ return irq_table->sf_comp_pool;
+}
-static int set_comp_irq_affinity_hint(struct mlx5_core_dev *mdev, int i)
+/**
+ * mlx5_irq_release - release an IRQ back to the system.
+ * @irq: irq to be released.
+ */
+void mlx5_irq_release(struct mlx5_irq *irq)
{
- int vecidx = MLX5_IRQ_VEC_COMP_BASE + i;
+ synchronize_irq(irq->irqn);
+ irq_put(irq);
+}
+
+/**
+ * mlx5_irq_request - request an IRQ for mlx5 device.
+ * @dev: mlx5 device that requesting the IRQ.
+ * @vecidx: vector index of the IRQ. This argument is ignore if affinity is
+ * provided.
+ * @affinity: cpumask requested for this IRQ.
+ *
+ * This function returns a pointer to IRQ, or ERR_PTR in case of error.
+ */
+struct mlx5_irq *mlx5_irq_request(struct mlx5_core_dev *dev, u16 vecidx,
+ struct cpumask *affinity)
+{
+ struct mlx5_irq_table *irq_table = mlx5_irq_table_get(dev);
+ struct mlx5_irq_pool *pool;
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;
+ if (mlx5_core_is_sf(dev)) {
+ pool = find_sf_irq_pool(irq_table, vecidx, affinity);
+ if (!pool)
+ /* we don't have IRQs for SFs, using the PF IRQs */
+ goto pf_irq;
+ if (cpumask_empty(affinity) && !strcmp(pool->name, "mlx5_sf_comp"))
+ /* In case an SF user request IRQ with vecidx */
+ irq = irq_pool_request_vector(pool, vecidx, NULL);
+ else
+ irq = irq_pool_request_affinity(pool, affinity);
+ goto out;
}
+pf_irq:
+ pool = irq_table->pf_pool;
+ irq = irq_pool_request_vector(pool, vecidx, affinity);
+out:
+ if (IS_ERR(irq))
+ return irq;
+ mlx5_core_dbg(dev, "irq %u mapped to cpu %*pbl, %u EQs on this irq\n",
+ irq->irqn, cpumask_pr_args(affinity),
+ kref_read(&irq->kref) / MLX5_EQ_REFS_PER_IRQ);
+ return irq;
+}
- 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 struct mlx5_irq_pool *
+irq_pool_alloc(struct mlx5_core_dev *dev, int start, int size, char *name,
+ u32 min_threshold, u32 max_threshold)
+{
+ struct mlx5_irq_pool *pool = kvzalloc(sizeof(*pool), GFP_KERNEL);
+
+ if (!pool)
+ return ERR_PTR(-ENOMEM);
+ pool->dev = dev;
+ xa_init_flags(&pool->irqs, XA_FLAGS_ALLOC);
+ pool->xa_num_irqs.min = start;
+ pool->xa_num_irqs.max = start + size - 1;
+ if (name)
+ snprintf(pool->name, MLX5_MAX_IRQ_NAME - MLX5_MAX_IRQ_IDX_CHARS,
+ name);
+ pool->min_threshold = min_threshold * MLX5_EQ_REFS_PER_IRQ;
+ pool->max_threshold = max_threshold * MLX5_EQ_REFS_PER_IRQ;
+ mutex_init(&pool->lock);
+ mlx5_core_dbg(dev, "pool->name = %s, pool->size = %d, pool->start = %d",
+ name, size, start);
+ return pool;
}
-static void clear_comp_irq_affinity_hint(struct mlx5_core_dev *mdev, int i)
+static void irq_pool_free(struct mlx5_irq_pool *pool)
{
- int vecidx = MLX5_IRQ_VEC_COMP_BASE + i;
struct mlx5_irq *irq;
- int irqn;
+ unsigned long index;
- irq = mlx5_irq_get(mdev, vecidx);
- irqn = pci_irq_vector(mdev->pdev, vecidx);
- irq_set_affinity_hint(irqn, NULL);
- free_cpumask_var(irq->mask);
+ xa_for_each(&pool->irqs, index, irq)
+ irq_release(&irq->kref);
+ xa_destroy(&pool->irqs);
+ kvfree(pool);
}
-static int set_comp_irq_affinity_hints(struct mlx5_core_dev *mdev)
+static int irq_pools_init(struct mlx5_core_dev *dev, int sf_vec, int pf_vec)
{
- int nvec = mlx5_irq_get_num_comp(mdev->priv.irq_table);
+ struct mlx5_irq_table *table = dev->priv.irq_table;
+ int num_sf_ctrl_by_msix;
+ int num_sf_ctrl_by_sfs;
+ int num_sf_ctrl;
int err;
- int i;
- for (i = 0; i < nvec; i++) {
- err = set_comp_irq_affinity_hint(mdev, i);
- if (err)
- goto err_out;
+ /* init pf_pool */
+ table->pf_pool = irq_pool_alloc(dev, 0, pf_vec, NULL,
+ MLX5_EQ_SHARE_IRQ_MIN_COMP,
+ MLX5_EQ_SHARE_IRQ_MAX_COMP);
+ if (IS_ERR(table->pf_pool))
+ return PTR_ERR(table->pf_pool);
+ if (!mlx5_sf_max_functions(dev))
+ return 0;
+ if (sf_vec < MLX5_IRQ_VEC_COMP_BASE_SF) {
+ mlx5_core_err(dev, "Not enough IRQs for SFs. SF may run at lower performance\n");
+ return 0;
}
+ /* init sf_ctrl_pool */
+ num_sf_ctrl_by_msix = DIV_ROUND_UP(sf_vec, MLX5_COMP_EQS_PER_SF);
+ num_sf_ctrl_by_sfs = DIV_ROUND_UP(mlx5_sf_max_functions(dev),
+ MLX5_SFS_PER_CTRL_IRQ);
+ num_sf_ctrl = min_t(int, num_sf_ctrl_by_msix, num_sf_ctrl_by_sfs);
+ num_sf_ctrl = min_t(int, MLX5_IRQ_CTRL_SF_MAX, num_sf_ctrl);
+ table->sf_ctrl_pool = irq_pool_alloc(dev, pf_vec, num_sf_ctrl,
+ "mlx5_sf_ctrl",
+ MLX5_EQ_SHARE_IRQ_MIN_CTRL,
+ MLX5_EQ_SHARE_IRQ_MAX_CTRL);
+ if (IS_ERR(table->sf_ctrl_pool)) {
+ err = PTR_ERR(table->sf_ctrl_pool);
+ goto err_pf;
+ }
+ /* init sf_comp_pool */
+ table->sf_comp_pool = irq_pool_alloc(dev, pf_vec + num_sf_ctrl,
+ sf_vec - num_sf_ctrl, "mlx5_sf_comp",
+ MLX5_EQ_SHARE_IRQ_MIN_COMP,
+ MLX5_EQ_SHARE_IRQ_MAX_COMP);
+ if (IS_ERR(table->sf_comp_pool)) {
+ err = PTR_ERR(table->sf_comp_pool);
+ goto err_sf_ctrl;
+ }
return 0;
-
-err_out:
- for (i--; i >= 0; i--)
- clear_comp_irq_affinity_hint(mdev, i);
-
+err_sf_ctrl:
+ irq_pool_free(table->sf_ctrl_pool);
+err_pf:
+ irq_pool_free(table->pf_pool);
return err;
}
-static void clear_comp_irqs_affinity_hints(struct mlx5_core_dev *mdev)
+static void irq_pools_destroy(struct mlx5_irq_table *table)
{
- 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);
+ if (table->sf_ctrl_pool) {
+ irq_pool_free(table->sf_comp_pool);
+ irq_pool_free(table->sf_ctrl_pool);
+ }
+ irq_pool_free(table->pf_pool);
}
-struct cpumask *
-mlx5_irq_get_affinity_mask(struct mlx5_irq_table *irq_table, int vecidx)
+/* irq_table API */
+
+int mlx5_irq_table_init(struct mlx5_core_dev *dev)
{
- return irq_table->irq[vecidx].mask;
+ struct mlx5_irq_table *irq_table;
+
+ if (mlx5_core_is_sf(dev))
+ return 0;
+
+ irq_table = kvzalloc(sizeof(*irq_table), GFP_KERNEL);
+ if (!irq_table)
+ return -ENOMEM;
+
+ dev->priv.irq_table = irq_table;
+ return 0;
}
-#ifdef CONFIG_RFS_ACCEL
-struct cpu_rmap *mlx5_irq_get_rmap(struct mlx5_irq_table *irq_table)
+void mlx5_irq_table_cleanup(struct mlx5_core_dev *dev)
{
- return irq_table->rmap;
+ if (mlx5_core_is_sf(dev))
+ return;
+
+ kvfree(dev->priv.irq_table);
}
-#endif
-static void unrequest_irqs(struct mlx5_core_dev *dev)
+int mlx5_irq_table_get_num_comp(struct mlx5_irq_table *table)
{
- 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);
+ return table->pf_pool->xa_num_irqs.max - table->pf_pool->xa_num_irqs.min;
}
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 total_vec;
+ int pf_vec;
int err;
if (mlx5_core_is_sf(dev))
return 0;
- 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)
+ pf_vec = MLX5_CAP_GEN(dev, num_ports) * num_online_cpus() +
+ MLX5_IRQ_VEC_COMP_BASE;
+ pf_vec = min_t(int, pf_vec, num_eqs);
+ if (pf_vec <= MLX5_IRQ_VEC_COMP_BASE)
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;
+ total_vec = pf_vec;
+ if (mlx5_sf_max_functions(dev))
+ total_vec += MLX5_IRQ_CTRL_SF_MAX +
+ MLX5_COMP_EQS_PER_SF * mlx5_sf_max_functions(dev);
- err = irq_set_rmap(dev);
- if (err)
- goto err_set_rmap;
+ total_vec = pci_alloc_irq_vectors(dev->pdev, MLX5_IRQ_VEC_COMP_BASE + 1,
+ total_vec, PCI_IRQ_MSIX);
+ if (total_vec < 0)
+ return total_vec;
+ pf_vec = min(pf_vec, total_vec);
- err = request_irqs(dev, nvec);
+ err = irq_pools_init(dev, total_vec - pf_vec, pf_vec);
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;
+ pci_free_irq_vectors(dev->pdev);
-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;
if (mlx5_core_is_sf(dev))
return;
- /* 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.
+ /* There are cases where IRQs still will be in used when we reaching
+ * to here. Hence, making sure all the irqs are realeased.
*/
- 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);
+ irq_pools_destroy(table);
pci_free_irq_vectors(dev->pdev);
- kfree(table->irq);
+}
+
+int mlx5_irq_table_get_sfs_vec(struct mlx5_irq_table *table)
+{
+ if (table->sf_comp_pool)
+ return table->sf_comp_pool->xa_num_irqs.max -
+ table->sf_comp_pool->xa_num_irqs.min + 1;
+ else
+ return mlx5_irq_table_get_num_comp(table);
}
struct mlx5_irq_table *mlx5_irq_table_get(struct mlx5_core_dev *dev)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c
index ef5f892aafad..d9c69123c1ab 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c
@@ -6,7 +6,6 @@
#include "sf.h"
#include "mlx5_ifc_vhca_event.h"
#include "ecpf.h"
-#include "vhca_event.h"
#include "mlx5_core.h"
#include "eswitch.h"
@@ -74,26 +73,29 @@ static int mlx5_sf_hw_table_id_alloc(struct mlx5_sf_hw_table *table, u32 control
u32 usr_sfnum)
{
struct mlx5_sf_hwc_table *hwc;
+ int free_idx = -1;
int i;
hwc = mlx5_sf_controller_to_hwc(table->dev, controller);
if (!hwc->sfs)
return -ENOSPC;
- /* Check if sf with same sfnum already exists or not. */
for (i = 0; i < hwc->max_fn; i++) {
+ if (!hwc->sfs[i].allocated && free_idx == -1) {
+ free_idx = i;
+ continue;
+ }
+
if (hwc->sfs[i].allocated && hwc->sfs[i].usr_sfnum == usr_sfnum)
return -EEXIST;
}
- /* Find the free entry and allocate the entry from the array */
- for (i = 0; i < hwc->max_fn; i++) {
- if (!hwc->sfs[i].allocated) {
- hwc->sfs[i].usr_sfnum = usr_sfnum;
- hwc->sfs[i].allocated = true;
- return i;
- }
- }
- return -ENOSPC;
+
+ if (free_idx == -1)
+ return -ENOSPC;
+
+ hwc->sfs[free_idx].usr_sfnum = usr_sfnum;
+ hwc->sfs[free_idx].allocated = true;
+ return free_idx;
}
static void mlx5_sf_hw_table_id_free(struct mlx5_sf_hw_table *table, u32 controller, int id)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h
index 0b6aea1e6a94..81ce13b19ee8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h
@@ -5,42 +5,7 @@
#define __MLX5_SF_H__
#include <linux/mlx5/driver.h>
-
-static inline u16 mlx5_sf_start_function_id(const struct mlx5_core_dev *dev)
-{
- return MLX5_CAP_GEN(dev, sf_base_id);
-}
-
-#ifdef CONFIG_MLX5_SF
-
-static inline bool mlx5_sf_supported(const struct mlx5_core_dev *dev)
-{
- return MLX5_CAP_GEN(dev, sf);
-}
-
-static inline u16 mlx5_sf_max_functions(const struct mlx5_core_dev *dev)
-{
- if (!mlx5_sf_supported(dev))
- return 0;
- if (MLX5_CAP_GEN(dev, max_num_sf))
- return MLX5_CAP_GEN(dev, max_num_sf);
- else
- return 1 << MLX5_CAP_GEN(dev, log_max_sf);
-}
-
-#else
-
-static inline bool mlx5_sf_supported(const struct mlx5_core_dev *dev)
-{
- return false;
-}
-
-static inline u16 mlx5_sf_max_functions(const struct mlx5_core_dev *dev)
-{
- return 0;
-}
-
-#endif
+#include "lib/sf.h"
#ifdef CONFIG_MLX5_SF_MANAGER
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
index 2338989d4403..e8185b69ac6c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
@@ -34,6 +34,7 @@
#include <linux/mlx5/driver.h>
#include <linux/mlx5/vport.h>
#include "mlx5_core.h"
+#include "mlx5_irq.h"
#include "eswitch.h"
static int sriov_restore_guids(struct mlx5_core_dev *dev, int vf)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c
index 949879cf2092..6475ba35cf6b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c
@@ -2,6 +2,7 @@
/* Copyright (c) 2019 Mellanox Technologies. */
#include "dr_types.h"
+#include "dr_ste.h"
enum dr_action_domain {
DR_ACTION_DOMAIN_NIC_INGRESS,
@@ -14,7 +15,8 @@ enum dr_action_domain {
enum dr_action_valid_state {
DR_ACTION_STATE_ERR,
DR_ACTION_STATE_NO_ACTION,
- DR_ACTION_STATE_REFORMAT,
+ DR_ACTION_STATE_ENCAP,
+ DR_ACTION_STATE_DECAP,
DR_ACTION_STATE_MODIFY_HDR,
DR_ACTION_STATE_MODIFY_VLAN,
DR_ACTION_STATE_NON_TERM,
@@ -29,46 +31,74 @@ next_action_state[DR_ACTION_DOMAIN_MAX][DR_ACTION_STATE_MAX][DR_ACTION_TYP_MAX]
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_TAG] = DR_ACTION_STATE_NON_TERM,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
- [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_REFORMAT,
- [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP,
+ [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
[DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
[DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
},
- [DR_ACTION_STATE_REFORMAT] = {
+ [DR_ACTION_STATE_DECAP] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
- [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_REFORMAT,
- [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_DECAP,
+ [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_DECAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
[DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
[DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
},
+ [DR_ACTION_STATE_ENCAP] = {
+ [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP,
+ },
[DR_ACTION_STATE_MODIFY_HDR] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_TAG] = DR_ACTION_STATE_MODIFY_HDR,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
},
[DR_ACTION_STATE_MODIFY_VLAN] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_TAG] = DR_ACTION_STATE_MODIFY_VLAN,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_VLAN,
[DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
[DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
},
[DR_ACTION_STATE_NON_TERM] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_TAG] = DR_ACTION_STATE_NON_TERM,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
- [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_REFORMAT,
- [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP,
+ [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
[DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
[DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
},
@@ -80,39 +110,48 @@ next_action_state[DR_ACTION_DOMAIN_MAX][DR_ACTION_STATE_MAX][DR_ACTION_TYP_MAX]
[DR_ACTION_STATE_NO_ACTION] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
- [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
- [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
[DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
[DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
},
- [DR_ACTION_STATE_REFORMAT] = {
+ [DR_ACTION_STATE_ENCAP] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
- [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP,
},
[DR_ACTION_STATE_MODIFY_HDR] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR,
- [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
- [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
[DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
},
[DR_ACTION_STATE_MODIFY_VLAN] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_VLAN,
[DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
- [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
- [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
},
[DR_ACTION_STATE_NON_TERM] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
- [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
- [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
[DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
[DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
},
@@ -124,41 +163,69 @@ next_action_state[DR_ACTION_DOMAIN_MAX][DR_ACTION_STATE_MAX][DR_ACTION_TYP_MAX]
[DR_ACTION_STATE_NO_ACTION] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
- [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_REFORMAT,
- [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP,
+ [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
[DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
[DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
[DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
},
- [DR_ACTION_STATE_REFORMAT] = {
+ [DR_ACTION_STATE_DECAP] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
- [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_DECAP,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
[DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
[DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
+ },
+ [DR_ACTION_STATE_ENCAP] = {
+ [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP,
},
[DR_ACTION_STATE_MODIFY_HDR] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR,
[DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
},
[DR_ACTION_STATE_MODIFY_VLAN] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_VLAN,
[DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
},
[DR_ACTION_STATE_NON_TERM] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
- [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_REFORMAT,
- [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP,
+ [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
[DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
[DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
[DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
@@ -171,44 +238,53 @@ next_action_state[DR_ACTION_DOMAIN_MAX][DR_ACTION_STATE_MAX][DR_ACTION_TYP_MAX]
[DR_ACTION_STATE_NO_ACTION] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
[DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
- [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
- [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
[DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
[DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
},
- [DR_ACTION_STATE_REFORMAT] = {
+ [DR_ACTION_STATE_ENCAP] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
- [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
},
[DR_ACTION_STATE_MODIFY_HDR] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR,
- [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
- [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
[DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
[DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
},
[DR_ACTION_STATE_MODIFY_VLAN] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_VLAN,
- [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
- [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
[DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
},
[DR_ACTION_STATE_NON_TERM] = {
[DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
+ [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM,
[DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
[DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
- [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
- [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
+ [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP,
+ [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP,
[DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
[DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
},
@@ -235,6 +311,9 @@ dr_action_reformat_to_action_type(enum mlx5dr_action_reformat_type reformat_type
case DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L3:
*action_type = DR_ACTION_TYP_L2_TO_TNL_L3;
break;
+ case DR_ACTION_REFORMAT_TYP_INSERT_HDR:
+ *action_type = DR_ACTION_TYP_INSERT_HDR;
+ break;
default:
return -EINVAL;
}
@@ -454,8 +533,17 @@ int mlx5dr_actions_build_ste_arr(struct mlx5dr_matcher *matcher,
break;
case DR_ACTION_TYP_L2_TO_TNL_L2:
case DR_ACTION_TYP_L2_TO_TNL_L3:
- attr.reformat_size = action->reformat->reformat_size;
- attr.reformat_id = action->reformat->reformat_id;
+ if (rx_rule &&
+ !(dmn->ste_ctx->actions_caps & DR_STE_CTX_ACTION_CAP_RX_ENCAP)) {
+ mlx5dr_info(dmn, "Device doesn't support Encap on RX\n");
+ goto out_invalid_arg;
+ }
+ attr.reformat.size = action->reformat->size;
+ attr.reformat.id = action->reformat->id;
+ break;
+ case DR_ACTION_TYP_SAMPLER:
+ attr.final_icm_addr = rx_rule ? action->sampler->rx_icm_addr :
+ action->sampler->tx_icm_addr;
break;
case DR_ACTION_TYP_VPORT:
attr.hit_gvmi = action->vport->caps->vhca_gvmi;
@@ -481,6 +569,12 @@ int mlx5dr_actions_build_ste_arr(struct mlx5dr_matcher *matcher,
attr.vlans.headers[attr.vlans.count++] = action->push_vlan->vlan_hdr;
break;
+ case DR_ACTION_TYP_INSERT_HDR:
+ attr.reformat.size = action->reformat->size;
+ attr.reformat.id = action->reformat->id;
+ attr.reformat.param_0 = action->reformat->param_0;
+ attr.reformat.param_1 = action->reformat->param_1;
+ break;
default:
goto out_invalid_arg;
}
@@ -543,6 +637,8 @@ static unsigned int action_size[DR_ACTION_TYP_MAX] = {
[DR_ACTION_TYP_MODIFY_HDR] = sizeof(struct mlx5dr_action_rewrite),
[DR_ACTION_TYP_VPORT] = sizeof(struct mlx5dr_action_vport),
[DR_ACTION_TYP_PUSH_VLAN] = sizeof(struct mlx5dr_action_push_vlan),
+ [DR_ACTION_TYP_INSERT_HDR] = sizeof(struct mlx5dr_action_reformat),
+ [DR_ACTION_TYP_SAMPLER] = sizeof(struct mlx5dr_action_sampler),
};
static struct mlx5dr_action *
@@ -651,7 +747,7 @@ mlx5dr_action_create_mult_dest_tbl(struct mlx5dr_domain *dmn,
if (reformat_action) {
reformat_req = true;
hw_dests[i].vport.reformat_id =
- reformat_action->reformat->reformat_id;
+ reformat_action->reformat->id;
ref_actions[num_of_ref++] = reformat_action;
hw_dests[i].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
}
@@ -755,14 +851,43 @@ struct mlx5dr_action *mlx5dr_action_create_tag(u32 tag_value)
return action;
}
+struct mlx5dr_action *
+mlx5dr_action_create_flow_sampler(struct mlx5dr_domain *dmn, u32 sampler_id)
+{
+ struct mlx5dr_action *action;
+ u64 icm_rx, icm_tx;
+ int ret;
+
+ ret = mlx5dr_cmd_query_flow_sampler(dmn->mdev, sampler_id,
+ &icm_rx, &icm_tx);
+ if (ret)
+ return NULL;
+
+ action = dr_action_create_generic(DR_ACTION_TYP_SAMPLER);
+ if (!action)
+ return NULL;
+
+ action->sampler->dmn = dmn;
+ action->sampler->sampler_id = sampler_id;
+ action->sampler->rx_icm_addr = icm_rx;
+ action->sampler->tx_icm_addr = icm_tx;
+
+ refcount_inc(&dmn->refcount);
+ return action;
+}
+
static int
dr_action_verify_reformat_params(enum mlx5dr_action_type reformat_type,
struct mlx5dr_domain *dmn,
+ u8 reformat_param_0,
+ u8 reformat_param_1,
size_t data_sz,
void *data)
{
- if ((!data && data_sz) || (data && !data_sz) || reformat_type >
- DR_ACTION_TYP_L2_TO_TNL_L3) {
+ if ((!data && data_sz) || (data && !data_sz) ||
+ ((reformat_param_0 || reformat_param_1) &&
+ reformat_type != DR_ACTION_TYP_INSERT_HDR) ||
+ reformat_type > DR_ACTION_TYP_INSERT_HDR) {
mlx5dr_dbg(dmn, "Invalid reformat parameter!\n");
goto out_err;
}
@@ -794,6 +919,7 @@ out_err:
static int
dr_action_create_reformat_action(struct mlx5dr_domain *dmn,
+ u8 reformat_param_0, u8 reformat_param_1,
size_t data_sz, void *data,
struct mlx5dr_action *action)
{
@@ -811,13 +937,14 @@ dr_action_create_reformat_action(struct mlx5dr_domain *dmn,
else
rt = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
- ret = mlx5dr_cmd_create_reformat_ctx(dmn->mdev, rt, data_sz, data,
+ ret = mlx5dr_cmd_create_reformat_ctx(dmn->mdev, rt, 0, 0,
+ data_sz, data,
&reformat_id);
if (ret)
return ret;
- action->reformat->reformat_id = reformat_id;
- action->reformat->reformat_size = data_sz;
+ action->reformat->id = reformat_id;
+ action->reformat->size = data_sz;
return 0;
}
case DR_ACTION_TYP_TNL_L2_TO_L2:
@@ -859,6 +986,23 @@ dr_action_create_reformat_action(struct mlx5dr_domain *dmn,
}
return 0;
}
+ case DR_ACTION_TYP_INSERT_HDR:
+ {
+ ret = mlx5dr_cmd_create_reformat_ctx(dmn->mdev,
+ MLX5_REFORMAT_TYPE_INSERT_HDR,
+ reformat_param_0,
+ reformat_param_1,
+ data_sz, data,
+ &reformat_id);
+ if (ret)
+ return ret;
+
+ action->reformat->id = reformat_id;
+ action->reformat->size = data_sz;
+ action->reformat->param_0 = reformat_param_0;
+ action->reformat->param_1 = reformat_param_1;
+ return 0;
+ }
default:
mlx5dr_info(dmn, "Reformat type is not supported %d\n", action->action_type);
return -EINVAL;
@@ -896,6 +1040,8 @@ struct mlx5dr_action *mlx5dr_action_create_push_vlan(struct mlx5dr_domain *dmn,
struct mlx5dr_action *
mlx5dr_action_create_packet_reformat(struct mlx5dr_domain *dmn,
enum mlx5dr_action_reformat_type reformat_type,
+ u8 reformat_param_0,
+ u8 reformat_param_1,
size_t data_sz,
void *data)
{
@@ -912,7 +1058,9 @@ mlx5dr_action_create_packet_reformat(struct mlx5dr_domain *dmn,
goto dec_ref;
}
- ret = dr_action_verify_reformat_params(action_type, dmn, data_sz, data);
+ ret = dr_action_verify_reformat_params(action_type, dmn,
+ reformat_param_0, reformat_param_1,
+ data_sz, data);
if (ret)
goto dec_ref;
@@ -923,6 +1071,8 @@ mlx5dr_action_create_packet_reformat(struct mlx5dr_domain *dmn,
action->reformat->dmn = dmn;
ret = dr_action_create_reformat_action(dmn,
+ reformat_param_0,
+ reformat_param_1,
data_sz,
data,
action);
@@ -1516,8 +1666,9 @@ int mlx5dr_action_destroy(struct mlx5dr_action *action)
break;
case DR_ACTION_TYP_L2_TO_TNL_L2:
case DR_ACTION_TYP_L2_TO_TNL_L3:
+ case DR_ACTION_TYP_INSERT_HDR:
mlx5dr_cmd_destroy_reformat_ctx((action->reformat->dmn)->mdev,
- action->reformat->reformat_id);
+ action->reformat->id);
refcount_dec(&action->reformat->dmn->refcount);
break;
case DR_ACTION_TYP_MODIFY_HDR:
@@ -1525,6 +1676,9 @@ int mlx5dr_action_destroy(struct mlx5dr_action *action)
kfree(action->rewrite->data);
refcount_dec(&action->rewrite->dmn->refcount);
break;
+ case DR_ACTION_TYP_SAMPLER:
+ refcount_dec(&action->sampler->dmn->refcount);
+ break;
default:
break;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c
index 5970cb8fc0c0..54e1f5438bbe 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c
@@ -228,6 +228,36 @@ int mlx5dr_cmd_query_flow_table(struct mlx5_core_dev *dev,
return 0;
}
+int mlx5dr_cmd_query_flow_sampler(struct mlx5_core_dev *dev,
+ u32 sampler_id,
+ u64 *rx_icm_addr,
+ u64 *tx_icm_addr)
+{
+ u32 out[MLX5_ST_SZ_DW(query_sampler_obj_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
+ void *attr;
+ int ret;
+
+ MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
+ MLX5_CMD_OP_QUERY_GENERAL_OBJECT);
+ MLX5_SET(general_obj_in_cmd_hdr, in, obj_type,
+ MLX5_GENERAL_OBJECT_TYPES_SAMPLER);
+ MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, sampler_id);
+
+ ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+ if (ret)
+ return ret;
+
+ attr = MLX5_ADDR_OF(query_sampler_obj_out, out, sampler_object);
+
+ *rx_icm_addr = MLX5_GET64(sampler_obj, attr,
+ sw_steering_icm_address_rx);
+ *tx_icm_addr = MLX5_GET64(sampler_obj, attr,
+ sw_steering_icm_address_tx);
+
+ return 0;
+}
+
int mlx5dr_cmd_sync_steering(struct mlx5_core_dev *mdev)
{
u32 in[MLX5_ST_SZ_DW(sync_steering_in)] = {};
@@ -460,6 +490,8 @@ int mlx5dr_cmd_destroy_flow_table(struct mlx5_core_dev *mdev,
int mlx5dr_cmd_create_reformat_ctx(struct mlx5_core_dev *mdev,
enum mlx5_reformat_ctx_type rt,
+ u8 reformat_param_0,
+ u8 reformat_param_1,
size_t reformat_size,
void *reformat_data,
u32 *reformat_id)
@@ -486,8 +518,11 @@ int mlx5dr_cmd_create_reformat_ctx(struct mlx5_core_dev *mdev,
pdata = MLX5_ADDR_OF(packet_reformat_context_in, prctx, reformat_data);
MLX5_SET(packet_reformat_context_in, prctx, reformat_type, rt);
+ MLX5_SET(packet_reformat_context_in, prctx, reformat_param_0, reformat_param_0);
+ MLX5_SET(packet_reformat_context_in, prctx, reformat_param_1, reformat_param_1);
MLX5_SET(packet_reformat_context_in, prctx, reformat_data_size, reformat_size);
- memcpy(pdata, reformat_data, reformat_size);
+ if (reformat_data && reformat_size)
+ memcpy(pdata, reformat_data, reformat_size);
err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out));
if (err)
@@ -706,6 +741,9 @@ int mlx5dr_cmd_set_fte(struct mlx5_core_dev *dev,
fte->dest_arr[i].vport.reformat_id);
}
break;
+ case MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER:
+ id = fte->dest_arr[i].sampler_id;
+ break;
default:
id = fte->dest_arr[i].tir_num;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.h
index 992b591bf0c5..12a8bbbf944b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.h
@@ -156,6 +156,7 @@ struct mlx5dr_ste_ctx {
u16 (*get_byte_mask)(u8 *hw_ste_p);
/* Actions */
+ u32 actions_caps;
void (*set_actions_rx)(struct mlx5dr_domain *dmn,
u8 *action_type_set,
u8 *hw_ste_arr,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c
index 0757a4e8540e..f1950e4968da 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c
@@ -437,8 +437,8 @@ dr_ste_v0_set_actions_tx(struct mlx5dr_domain *dmn,
attr->gvmi);
dr_ste_v0_set_tx_encap(last_ste,
- attr->reformat_id,
- attr->reformat_size,
+ attr->reformat.id,
+ attr->reformat.size,
action_type_set[DR_ACTION_TYP_L2_TO_TNL_L3]);
/* Whenever prio_tag_required enabled, we can be sure that the
* previous table (ACL) already push vlan to our packet,
@@ -1893,6 +1893,7 @@ struct mlx5dr_ste_ctx ste_ctx_v0 = {
.get_byte_mask = &dr_ste_v0_get_byte_mask,
/* Actions */
+ .actions_caps = DR_STE_CTX_ACTION_CAP_NONE,
.set_actions_rx = &dr_ste_v0_set_actions_rx,
.set_actions_tx = &dr_ste_v0_set_actions_tx,
.modify_field_arr_sz = ARRAY_SIZE(dr_ste_v0_action_modify_field_arr),
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c
index 7466f016375c..4aaca8eb7597 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c
@@ -116,6 +116,8 @@ enum {
DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_3 = 0x4f,
DR_STE_V1_ACTION_MDFY_FLD_TCP_MISC_0 = 0x5e,
DR_STE_V1_ACTION_MDFY_FLD_TCP_MISC_1 = 0x5f,
+ DR_STE_V1_ACTION_MDFY_FLD_CFG_HDR_0_0 = 0x6f,
+ DR_STE_V1_ACTION_MDFY_FLD_CFG_HDR_0_1 = 0x70,
DR_STE_V1_ACTION_MDFY_FLD_METADATA_2_CQE = 0x7b,
DR_STE_V1_ACTION_MDFY_FLD_GNRL_PURPOSE = 0x7c,
DR_STE_V1_ACTION_MDFY_FLD_REGISTER_2 = 0x8c,
@@ -246,6 +248,12 @@ static const struct mlx5dr_ste_action_modify_field dr_ste_v1_action_modify_field
[MLX5_ACTION_IN_FIELD_OUT_FIRST_VID] = {
.hw_field = DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_2, .start = 0, .end = 15,
},
+ [MLX5_ACTION_IN_FIELD_OUT_EMD_31_0] = {
+ .hw_field = DR_STE_V1_ACTION_MDFY_FLD_CFG_HDR_0_1, .start = 0, .end = 31,
+ },
+ [MLX5_ACTION_IN_FIELD_OUT_EMD_47_32] = {
+ .hw_field = DR_STE_V1_ACTION_MDFY_FLD_CFG_HDR_0_0, .start = 0, .end = 15,
+ },
};
static void dr_ste_v1_set_entry_type(u8 *hw_ste_p, u8 entry_type)
@@ -361,8 +369,8 @@ static void dr_ste_v1_set_reparse(u8 *hw_ste_p)
MLX5_SET(ste_match_bwc_v1, hw_ste_p, reparse, 1);
}
-static void dr_ste_v1_set_tx_encap(u8 *hw_ste_p, u8 *d_action,
- u32 reformat_id, int size)
+static void dr_ste_v1_set_encap(u8 *hw_ste_p, u8 *d_action,
+ u32 reformat_id, int size)
{
MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, action_id,
DR_STE_V1_ACTION_ID_INSERT_POINTER);
@@ -374,6 +382,26 @@ static void dr_ste_v1_set_tx_encap(u8 *hw_ste_p, u8 *d_action,
dr_ste_v1_set_reparse(hw_ste_p);
}
+static void dr_ste_v1_set_insert_hdr(u8 *hw_ste_p, u8 *d_action,
+ u32 reformat_id,
+ u8 anchor, u8 offset,
+ int size)
+{
+ MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action,
+ action_id, DR_STE_V1_ACTION_ID_INSERT_POINTER);
+ MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, start_anchor, anchor);
+
+ /* The hardware expects here size and offset in words (2 byte) */
+ MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, size, size / 2);
+ MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, start_offset, offset / 2);
+
+ MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, pointer, reformat_id);
+ MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, attributes,
+ DR_STE_V1_ACTION_INSERT_PTR_ATTR_NONE);
+
+ dr_ste_v1_set_reparse(hw_ste_p);
+}
+
static void dr_ste_v1_set_tx_push_vlan(u8 *hw_ste_p, u8 *d_action,
u32 vlan_hdr)
{
@@ -401,11 +429,11 @@ static void dr_ste_v1_set_rx_pop_vlan(u8 *hw_ste_p, u8 *s_action, u8 vlans_num)
dr_ste_v1_set_reparse(hw_ste_p);
}
-static void dr_ste_v1_set_tx_encap_l3(u8 *hw_ste_p,
- u8 *frst_s_action,
- u8 *scnd_d_action,
- u32 reformat_id,
- int size)
+static void dr_ste_v1_set_encap_l3(u8 *hw_ste_p,
+ u8 *frst_s_action,
+ u8 *scnd_d_action,
+ u32 reformat_id,
+ int size)
{
/* Remove L2 headers */
MLX5_SET(ste_single_action_remove_header_v1, frst_s_action, action_id,
@@ -519,9 +547,9 @@ static void dr_ste_v1_set_actions_tx(struct mlx5dr_domain *dmn,
action_sz = DR_STE_ACTION_TRIPLE_SZ;
allow_encap = true;
}
- dr_ste_v1_set_tx_encap(last_ste, action,
- attr->reformat_id,
- attr->reformat_size);
+ dr_ste_v1_set_encap(last_ste, action,
+ attr->reformat.id,
+ attr->reformat.size);
action_sz -= DR_STE_ACTION_DOUBLE_SZ;
action += DR_STE_ACTION_DOUBLE_SZ;
} else if (action_type_set[DR_ACTION_TYP_L2_TO_TNL_L3]) {
@@ -532,12 +560,25 @@ static void dr_ste_v1_set_actions_tx(struct mlx5dr_domain *dmn,
action_sz = DR_STE_ACTION_TRIPLE_SZ;
d_action = action + DR_STE_ACTION_SINGLE_SZ;
- dr_ste_v1_set_tx_encap_l3(last_ste,
- action, d_action,
- attr->reformat_id,
- attr->reformat_size);
+ dr_ste_v1_set_encap_l3(last_ste,
+ action, d_action,
+ attr->reformat.id,
+ attr->reformat.size);
action_sz -= DR_STE_ACTION_TRIPLE_SZ;
action += DR_STE_ACTION_TRIPLE_SZ;
+ } else if (action_type_set[DR_ACTION_TYP_INSERT_HDR]) {
+ if (!allow_encap || action_sz < DR_STE_ACTION_DOUBLE_SZ) {
+ dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi);
+ action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action);
+ action_sz = DR_STE_ACTION_TRIPLE_SZ;
+ }
+ dr_ste_v1_set_insert_hdr(last_ste, action,
+ attr->reformat.id,
+ attr->reformat.param_0,
+ attr->reformat.param_1,
+ attr->reformat.size);
+ action_sz -= DR_STE_ACTION_DOUBLE_SZ;
+ action += DR_STE_ACTION_DOUBLE_SZ;
}
dr_ste_v1_set_hit_gvmi(last_ste, attr->hit_gvmi);
@@ -616,7 +657,9 @@ static void dr_ste_v1_set_actions_rx(struct mlx5dr_domain *dmn,
}
if (action_type_set[DR_ACTION_TYP_CTR]) {
- /* Counter action set after decap to exclude decaped header */
+ /* Counter action set after decap and before insert_hdr
+ * to exclude decaped / encaped header respectively.
+ */
if (!allow_ctr) {
dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi);
action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action);
@@ -627,6 +670,52 @@ static void dr_ste_v1_set_actions_rx(struct mlx5dr_domain *dmn,
dr_ste_v1_set_counter_id(last_ste, attr->ctr_id);
}
+ if (action_type_set[DR_ACTION_TYP_L2_TO_TNL_L2]) {
+ if (action_sz < DR_STE_ACTION_DOUBLE_SZ) {
+ dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi);
+ action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action);
+ action_sz = DR_STE_ACTION_TRIPLE_SZ;
+ }
+ dr_ste_v1_set_encap(last_ste, action,
+ attr->reformat.id,
+ attr->reformat.size);
+ action_sz -= DR_STE_ACTION_DOUBLE_SZ;
+ action += DR_STE_ACTION_DOUBLE_SZ;
+ allow_modify_hdr = false;
+ } else if (action_type_set[DR_ACTION_TYP_L2_TO_TNL_L3]) {
+ u8 *d_action;
+
+ if (action_sz < DR_STE_ACTION_TRIPLE_SZ) {
+ dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi);
+ action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action);
+ action_sz = DR_STE_ACTION_TRIPLE_SZ;
+ }
+
+ d_action = action + DR_STE_ACTION_SINGLE_SZ;
+
+ dr_ste_v1_set_encap_l3(last_ste,
+ action, d_action,
+ attr->reformat.id,
+ attr->reformat.size);
+ action_sz -= DR_STE_ACTION_TRIPLE_SZ;
+ allow_modify_hdr = false;
+ } else if (action_type_set[DR_ACTION_TYP_INSERT_HDR]) {
+ /* Modify header, decap, and encap must use different STEs */
+ if (!allow_modify_hdr || action_sz < DR_STE_ACTION_DOUBLE_SZ) {
+ dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi);
+ action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action);
+ action_sz = DR_STE_ACTION_TRIPLE_SZ;
+ }
+ dr_ste_v1_set_insert_hdr(last_ste, action,
+ attr->reformat.id,
+ attr->reformat.param_0,
+ attr->reformat.param_1,
+ attr->reformat.size);
+ action_sz -= DR_STE_ACTION_DOUBLE_SZ;
+ action += DR_STE_ACTION_DOUBLE_SZ;
+ allow_modify_hdr = false;
+ }
+
dr_ste_v1_set_hit_gvmi(last_ste, attr->hit_gvmi);
dr_ste_v1_set_hit_addr(last_ste, attr->final_icm_addr, 1);
}
@@ -1871,6 +1960,7 @@ struct mlx5dr_ste_ctx ste_ctx_v1 = {
.set_byte_mask = &dr_ste_v1_set_byte_mask,
.get_byte_mask = &dr_ste_v1_get_byte_mask,
/* Actions */
+ .actions_caps = DR_STE_CTX_ACTION_CAP_RX_ENCAP,
.set_actions_rx = &dr_ste_v1_set_actions_rx,
.set_actions_tx = &dr_ste_v1_set_actions_tx,
.modify_field_arr_sz = ARRAY_SIZE(dr_ste_v1_action_modify_field_arr),
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h
index 67460c42a99b..f5e93fa87aff 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h
@@ -89,6 +89,11 @@ enum {
DR_STE_SIZE_REDUCED = DR_STE_SIZE - DR_STE_SIZE_MASK,
};
+enum mlx5dr_ste_ctx_action_cap {
+ DR_STE_CTX_ACTION_CAP_NONE = 0,
+ DR_STE_CTX_ACTION_CAP_RX_ENCAP = 1 << 0,
+};
+
enum {
DR_MODIFY_ACTION_SIZE = 8,
};
@@ -118,6 +123,8 @@ enum mlx5dr_action_type {
DR_ACTION_TYP_VPORT,
DR_ACTION_TYP_POP_VLAN,
DR_ACTION_TYP_PUSH_VLAN,
+ DR_ACTION_TYP_INSERT_HDR,
+ DR_ACTION_TYP_SAMPLER,
DR_ACTION_TYP_MAX,
};
@@ -261,8 +268,12 @@ struct mlx5dr_ste_actions_attr {
u32 ctr_id;
u16 gvmi;
u16 hit_gvmi;
- u32 reformat_id;
- u32 reformat_size;
+ struct {
+ u32 id;
+ u32 size;
+ u8 param_0;
+ u8 param_1;
+ } reformat;
struct {
int count;
u32 headers[MLX5DR_MAX_VLANS];
@@ -903,8 +914,17 @@ struct mlx5dr_action_rewrite {
struct mlx5dr_action_reformat {
struct mlx5dr_domain *dmn;
- u32 reformat_id;
- u32 reformat_size;
+ u32 id;
+ u32 size;
+ u8 param_0;
+ u8 param_1;
+};
+
+struct mlx5dr_action_sampler {
+ struct mlx5dr_domain *dmn;
+ u64 rx_icm_addr;
+ u64 tx_icm_addr;
+ u32 sampler_id;
};
struct mlx5dr_action_dest_tbl {
@@ -950,6 +970,7 @@ struct mlx5dr_action {
void *data;
struct mlx5dr_action_rewrite *rewrite;
struct mlx5dr_action_reformat *reformat;
+ struct mlx5dr_action_sampler *sampler;
struct mlx5dr_action_dest_tbl *dest_tbl;
struct mlx5dr_action_ctr *ctr;
struct mlx5dr_action_vport *vport;
@@ -1104,6 +1125,10 @@ int mlx5dr_cmd_query_gvmi(struct mlx5_core_dev *mdev,
bool other_vport, u16 vport_number, u16 *gvmi);
int mlx5dr_cmd_query_esw_caps(struct mlx5_core_dev *mdev,
struct mlx5dr_esw_caps *caps);
+int mlx5dr_cmd_query_flow_sampler(struct mlx5_core_dev *dev,
+ u32 sampler_id,
+ u64 *rx_icm_addr,
+ u64 *tx_icm_addr);
int mlx5dr_cmd_sync_steering(struct mlx5_core_dev *mdev);
int mlx5dr_cmd_set_fte_modify_and_vport(struct mlx5_core_dev *mdev,
u32 table_type,
@@ -1142,6 +1167,8 @@ int mlx5dr_cmd_query_flow_table(struct mlx5_core_dev *dev,
struct mlx5dr_cmd_query_flow_table_details *output);
int mlx5dr_cmd_create_reformat_ctx(struct mlx5_core_dev *mdev,
enum mlx5_reformat_ctx_type rt,
+ u8 reformat_param_0,
+ u8 reformat_param_1,
size_t reformat_size,
void *reformat_data,
u32 *reformat_id);
@@ -1252,7 +1279,6 @@ struct mlx5dr_send_ring {
u32 tx_head;
void *buf;
u32 buf_size;
- struct ib_wc wc[MAX_SEND_CQE];
u8 sync_buff[MIN_READ_SYNC];
struct mlx5dr_mr *sync_mr;
spinlock_t lock; /* Protect the data path of the send ring */
@@ -1290,6 +1316,7 @@ struct mlx5dr_cmd_flow_destination_hw_info {
u32 ft_num;
u32 ft_id;
u32 counter_id;
+ u32 sampler_id;
struct {
u16 num;
u16 vhca_id;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c
index 96c39a17d026..d5926dd7e972 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c
@@ -62,7 +62,7 @@ static int set_miss_action(struct mlx5_flow_root_namespace *ns,
static int mlx5_cmd_dr_create_flow_table(struct mlx5_flow_root_namespace *ns,
struct mlx5_flow_table *ft,
- unsigned int log_size,
+ unsigned int size,
struct mlx5_flow_table *next_ft)
{
struct mlx5dr_table *tbl;
@@ -71,7 +71,7 @@ static int mlx5_cmd_dr_create_flow_table(struct mlx5_flow_root_namespace *ns,
if (mlx5_dr_is_fw_table(ft->flags))
return mlx5_fs_cmd_get_fw_cmds()->create_flow_table(ns, ft,
- log_size,
+ size,
next_ft);
flags = ft->flags;
/* turn off encap/decap if not supported for sw-str by fw */
@@ -97,6 +97,8 @@ static int mlx5_cmd_dr_create_flow_table(struct mlx5_flow_root_namespace *ns,
}
}
+ ft->max_fte = INT_MAX;
+
return 0;
}
@@ -287,7 +289,8 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
DR_ACTION_REFORMAT_TYP_TNL_L2_TO_L2;
tmp_action = mlx5dr_action_create_packet_reformat(domain,
- decap_type, 0,
+ decap_type,
+ 0, 0, 0,
NULL);
if (!tmp_action) {
err = -ENOMEM;
@@ -384,7 +387,7 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
list_for_each_entry(dst, &fte->node.children, node.list) {
enum mlx5_flow_destination_type type = dst->dest_attr.type;
- u32 ft_id;
+ u32 id;
if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX ||
num_term_actions >= MLX5_FLOW_CONTEXT_ACTION_MAX) {
@@ -422,9 +425,20 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
num_term_actions++;
break;
case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM:
- ft_id = dst->dest_attr.ft_num;
+ id = dst->dest_attr.ft_num;
tmp_action = mlx5dr_action_create_dest_table_num(domain,
- ft_id);
+ id);
+ if (!tmp_action) {
+ err = -ENOMEM;
+ goto free_actions;
+ }
+ fs_dr_actions[fs_dr_num_actions++] = tmp_action;
+ term_actions[num_term_actions++].dest = tmp_action;
+ break;
+ case MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER:
+ id = dst->dest_attr.sampler_id;
+ tmp_action = mlx5dr_action_create_flow_sampler(domain,
+ id);
if (!tmp_action) {
err = -ENOMEM;
goto free_actions;
@@ -520,9 +534,7 @@ out_err:
}
static int mlx5_cmd_dr_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns,
- int reformat_type,
- size_t size,
- void *reformat_data,
+ struct mlx5_pkt_reformat_params *params,
enum mlx5_flow_namespace_type namespace,
struct mlx5_pkt_reformat *pkt_reformat)
{
@@ -530,7 +542,7 @@ static int mlx5_cmd_dr_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns
struct mlx5dr_action *action;
int dr_reformat;
- switch (reformat_type) {
+ switch (params->type) {
case MLX5_REFORMAT_TYPE_L2_TO_VXLAN:
case MLX5_REFORMAT_TYPE_L2_TO_NVGRE:
case MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL:
@@ -542,16 +554,21 @@ static int mlx5_cmd_dr_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns
case MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL:
dr_reformat = DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L3;
break;
+ case MLX5_REFORMAT_TYPE_INSERT_HDR:
+ dr_reformat = DR_ACTION_REFORMAT_TYP_INSERT_HDR;
+ break;
default:
mlx5_core_err(ns->dev, "Packet-reformat not supported(%d)\n",
- reformat_type);
+ params->type);
return -EOPNOTSUPP;
}
action = mlx5dr_action_create_packet_reformat(dr_domain,
dr_reformat,
- size,
- reformat_data);
+ params->param_0,
+ params->param_1,
+ params->size,
+ params->data);
if (!action) {
mlx5_core_err(ns->dev, "Failed allocating packet-reformat action\n");
return -EINVAL;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h
index 9737565cd8d4..bbfe101d4e57 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h
@@ -26,6 +26,7 @@ enum mlx5dr_action_reformat_type {
DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L2,
DR_ACTION_REFORMAT_TYP_TNL_L3_TO_L2,
DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L3,
+ DR_ACTION_REFORMAT_TYP_INSERT_HDR,
};
struct mlx5dr_match_parameters {
@@ -100,11 +101,16 @@ struct mlx5dr_action *mlx5dr_action_create_drop(void);
struct mlx5dr_action *mlx5dr_action_create_tag(u32 tag_value);
struct mlx5dr_action *
+mlx5dr_action_create_flow_sampler(struct mlx5dr_domain *dmn, u32 sampler_id);
+
+struct mlx5dr_action *
mlx5dr_action_create_flow_counter(u32 counter_id);
struct mlx5dr_action *
mlx5dr_action_create_packet_reformat(struct mlx5dr_domain *dmn,
enum mlx5dr_action_reformat_type reformat_type,
+ u8 reformat_param_0,
+ u8 reformat_param_1,
size_t data_sz,
void *data);
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig
new file mode 100644
index 000000000000..4cdebafaf222
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+#
+# Mellanox GigE driver configuration
+#
+
+config MLXBF_GIGE
+ tristate "Mellanox Technologies BlueField Gigabit Ethernet support"
+ depends on (ARM64 && ACPI) || COMPILE_TEST
+ select PHYLIB
+ help
+ The second generation BlueField SoC from Mellanox Technologies
+ supports an out-of-band Gigabit Ethernet management port to the
+ Arm subsystem.
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile
new file mode 100644
index 000000000000..e57c1375f236
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+
+obj-$(CONFIG_MLXBF_GIGE) += mlxbf_gige.o
+
+mlxbf_gige-y := mlxbf_gige_ethtool.o \
+ mlxbf_gige_gpio.o \
+ mlxbf_gige_intr.o \
+ mlxbf_gige_main.o \
+ mlxbf_gige_mdio.o \
+ mlxbf_gige_rx.o \
+ mlxbf_gige_tx.o
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
new file mode 100644
index 000000000000..e3509e69ed1c
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
@@ -0,0 +1,190 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */
+
+/* Header file for Gigabit Ethernet driver for Mellanox BlueField SoC
+ * - this file contains software data structures and any chip-specific
+ * data structures (e.g. TX WQE format) that are memory resident.
+ *
+ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES
+ */
+
+#ifndef __MLXBF_GIGE_H__
+#define __MLXBF_GIGE_H__
+
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/irqreturn.h>
+#include <linux/netdevice.h>
+#include <linux/irq.h>
+
+/* The silicon design supports a maximum RX ring size of
+ * 32K entries. Based on current testing this maximum size
+ * is not required to be supported. Instead the RX ring
+ * will be capped at a realistic value of 1024 entries.
+ */
+#define MLXBF_GIGE_MIN_RXQ_SZ 32
+#define MLXBF_GIGE_MAX_RXQ_SZ 1024
+#define MLXBF_GIGE_DEFAULT_RXQ_SZ 128
+
+#define MLXBF_GIGE_MIN_TXQ_SZ 4
+#define MLXBF_GIGE_MAX_TXQ_SZ 256
+#define MLXBF_GIGE_DEFAULT_TXQ_SZ 128
+
+#define MLXBF_GIGE_DEFAULT_BUF_SZ 2048
+
+#define MLXBF_GIGE_DMA_PAGE_SZ 4096
+#define MLXBF_GIGE_DMA_PAGE_SHIFT 12
+
+/* There are four individual MAC RX filters. Currently
+ * two of them are being used: one for the broadcast MAC
+ * (index 0) and one for local MAC (index 1)
+ */
+#define MLXBF_GIGE_BCAST_MAC_FILTER_IDX 0
+#define MLXBF_GIGE_LOCAL_MAC_FILTER_IDX 1
+
+/* Define for broadcast MAC literal */
+#define BCAST_MAC_ADDR 0xFFFFFFFFFFFF
+
+/* There are three individual interrupts:
+ * 1) Errors, "OOB" interrupt line
+ * 2) Receive Packet, "OOB_LLU" interrupt line
+ * 3) LLU and PLU Events, "OOB_PLU" interrupt line
+ */
+#define MLXBF_GIGE_ERROR_INTR_IDX 0
+#define MLXBF_GIGE_RECEIVE_PKT_INTR_IDX 1
+#define MLXBF_GIGE_LLU_PLU_INTR_IDX 2
+#define MLXBF_GIGE_PHY_INT_N 3
+
+#define MLXBF_GIGE_MDIO_DEFAULT_PHY_ADDR 0x3
+
+#define MLXBF_GIGE_DEFAULT_PHY_INT_GPIO 12
+
+struct mlxbf_gige_stats {
+ u64 hw_access_errors;
+ u64 tx_invalid_checksums;
+ u64 tx_small_frames;
+ u64 tx_index_errors;
+ u64 sw_config_errors;
+ u64 sw_access_errors;
+ u64 rx_truncate_errors;
+ u64 rx_mac_errors;
+ u64 rx_din_dropped_pkts;
+ u64 tx_fifo_full;
+ u64 rx_filter_passed_pkts;
+ u64 rx_filter_discard_pkts;
+};
+
+struct mlxbf_gige {
+ void __iomem *base;
+ void __iomem *llu_base;
+ void __iomem *plu_base;
+ struct device *dev;
+ struct net_device *netdev;
+ struct platform_device *pdev;
+ void __iomem *mdio_io;
+ struct mii_bus *mdiobus;
+ void __iomem *gpio_io;
+ struct irq_domain *irqdomain;
+ u32 phy_int_gpio_mask;
+ spinlock_t lock; /* for packet processing indices */
+ spinlock_t gpio_lock; /* for GPIO bus access */
+ u16 rx_q_entries;
+ u16 tx_q_entries;
+ u64 *tx_wqe_base;
+ dma_addr_t tx_wqe_base_dma;
+ u64 *tx_wqe_next;
+ u64 *tx_cc;
+ dma_addr_t tx_cc_dma;
+ dma_addr_t *rx_wqe_base;
+ dma_addr_t rx_wqe_base_dma;
+ u64 *rx_cqe_base;
+ dma_addr_t rx_cqe_base_dma;
+ u16 tx_pi;
+ u16 prev_tx_ci;
+ u64 error_intr_count;
+ u64 rx_intr_count;
+ u64 llu_plu_intr_count;
+ struct sk_buff *rx_skb[MLXBF_GIGE_MAX_RXQ_SZ];
+ struct sk_buff *tx_skb[MLXBF_GIGE_MAX_TXQ_SZ];
+ int error_irq;
+ int rx_irq;
+ int llu_plu_irq;
+ int phy_irq;
+ int hw_phy_irq;
+ bool promisc_enabled;
+ u8 valid_polarity;
+ struct napi_struct napi;
+ struct mlxbf_gige_stats stats;
+};
+
+/* Rx Work Queue Element definitions */
+#define MLXBF_GIGE_RX_WQE_SZ 8
+
+/* Rx Completion Queue Element definitions */
+#define MLXBF_GIGE_RX_CQE_SZ 8
+#define MLXBF_GIGE_RX_CQE_PKT_LEN_MASK GENMASK(10, 0)
+#define MLXBF_GIGE_RX_CQE_VALID_MASK GENMASK(11, 11)
+#define MLXBF_GIGE_RX_CQE_PKT_STATUS_MASK GENMASK(15, 12)
+#define MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR GENMASK(12, 12)
+#define MLXBF_GIGE_RX_CQE_PKT_STATUS_TRUNCATED GENMASK(13, 13)
+#define MLXBF_GIGE_RX_CQE_CHKSUM_MASK GENMASK(31, 16)
+
+/* Tx Work Queue Element definitions */
+#define MLXBF_GIGE_TX_WQE_SZ_QWORDS 2
+#define MLXBF_GIGE_TX_WQE_SZ 16
+#define MLXBF_GIGE_TX_WQE_PKT_LEN_MASK GENMASK(10, 0)
+#define MLXBF_GIGE_TX_WQE_UPDATE_MASK GENMASK(31, 31)
+#define MLXBF_GIGE_TX_WQE_CHKSUM_LEN_MASK GENMASK(42, 32)
+#define MLXBF_GIGE_TX_WQE_CHKSUM_START_MASK GENMASK(55, 48)
+#define MLXBF_GIGE_TX_WQE_CHKSUM_OFFSET_MASK GENMASK(63, 56)
+
+/* Macro to return packet length of specified TX WQE */
+#define MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr) \
+ (*((tx_wqe_addr) + 1) & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK)
+
+/* Tx Completion Count */
+#define MLXBF_GIGE_TX_CC_SZ 8
+
+/* List of resources in ACPI table */
+enum mlxbf_gige_res {
+ MLXBF_GIGE_RES_MAC,
+ MLXBF_GIGE_RES_MDIO9,
+ MLXBF_GIGE_RES_GPIO0,
+ MLXBF_GIGE_RES_LLU,
+ MLXBF_GIGE_RES_PLU
+};
+
+/* Version of register data returned by mlxbf_gige_get_regs() */
+#define MLXBF_GIGE_REGS_VERSION 1
+
+int mlxbf_gige_mdio_probe(struct platform_device *pdev,
+ struct mlxbf_gige *priv);
+void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv);
+irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id);
+void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv);
+
+void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv,
+ unsigned int index, u64 dmac);
+void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv,
+ unsigned int index, u64 *dmac);
+void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv);
+void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv);
+int mlxbf_gige_rx_init(struct mlxbf_gige *priv);
+void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv);
+int mlxbf_gige_tx_init(struct mlxbf_gige *priv);
+void mlxbf_gige_tx_deinit(struct mlxbf_gige *priv);
+bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv);
+netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb,
+ struct net_device *netdev);
+struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv,
+ unsigned int map_len,
+ dma_addr_t *buf_dma,
+ enum dma_data_direction dir);
+int mlxbf_gige_request_irqs(struct mlxbf_gige *priv);
+void mlxbf_gige_free_irqs(struct mlxbf_gige *priv);
+int mlxbf_gige_poll(struct napi_struct *napi, int budget);
+extern const struct ethtool_ops mlxbf_gige_ethtool_ops;
+void mlxbf_gige_update_tx_wqe_next(struct mlxbf_gige *priv);
+
+int mlxbf_gige_gpio_init(struct platform_device *pdev, struct mlxbf_gige *priv);
+void mlxbf_gige_gpio_free(struct mlxbf_gige *priv);
+
+#endif /* !defined(__MLXBF_GIGE_H__) */
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c
new file mode 100644
index 000000000000..92b798f8e73a
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+
+/* Ethtool support for Mellanox Gigabit Ethernet driver
+ *
+ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES
+ */
+
+#include <linux/phy.h>
+
+#include "mlxbf_gige.h"
+#include "mlxbf_gige_regs.h"
+
+/* Start of struct ethtool_ops functions */
+static int mlxbf_gige_get_regs_len(struct net_device *netdev)
+{
+ return MLXBF_GIGE_MMIO_REG_SZ;
+}
+
+static void mlxbf_gige_get_regs(struct net_device *netdev,
+ struct ethtool_regs *regs, void *p)
+{
+ struct mlxbf_gige *priv = netdev_priv(netdev);
+
+ regs->version = MLXBF_GIGE_REGS_VERSION;
+
+ /* Read entire MMIO register space and store results
+ * into the provided buffer. Each 64-bit word is converted
+ * to big-endian to make the output more readable.
+ *
+ * NOTE: by design, a read to an offset without an existing
+ * register will be acknowledged and return zero.
+ */
+ memcpy_fromio(p, priv->base, MLXBF_GIGE_MMIO_REG_SZ);
+}
+
+static void mlxbf_gige_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ering)
+{
+ struct mlxbf_gige *priv = netdev_priv(netdev);
+
+ ering->rx_max_pending = MLXBF_GIGE_MAX_RXQ_SZ;
+ ering->tx_max_pending = MLXBF_GIGE_MAX_TXQ_SZ;
+ ering->rx_pending = priv->rx_q_entries;
+ ering->tx_pending = priv->tx_q_entries;
+}
+
+static const struct {
+ const char string[ETH_GSTRING_LEN];
+} mlxbf_gige_ethtool_stats_keys[] = {
+ { "hw_access_errors" },
+ { "tx_invalid_checksums" },
+ { "tx_small_frames" },
+ { "tx_index_errors" },
+ { "sw_config_errors" },
+ { "sw_access_errors" },
+ { "rx_truncate_errors" },
+ { "rx_mac_errors" },
+ { "rx_din_dropped_pkts" },
+ { "tx_fifo_full" },
+ { "rx_filter_passed_pkts" },
+ { "rx_filter_discard_pkts" },
+};
+
+static int mlxbf_gige_get_sset_count(struct net_device *netdev, int stringset)
+{
+ if (stringset != ETH_SS_STATS)
+ return -EOPNOTSUPP;
+ return ARRAY_SIZE(mlxbf_gige_ethtool_stats_keys);
+}
+
+static void mlxbf_gige_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *buf)
+{
+ if (stringset != ETH_SS_STATS)
+ return;
+ memcpy(buf, &mlxbf_gige_ethtool_stats_keys,
+ sizeof(mlxbf_gige_ethtool_stats_keys));
+}
+
+static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *estats,
+ u64 *data)
+{
+ struct mlxbf_gige *priv = netdev_priv(netdev);
+
+ /* Fill data array with interface statistics
+ *
+ * NOTE: the data writes must be in
+ * sync with the strings shown in
+ * the mlxbf_gige_ethtool_stats_keys[] array
+ *
+ * NOTE2: certain statistics below are zeroed upon
+ * port disable, so the calculation below
+ * must include the "cached" value of the stat
+ * plus the value read directly from hardware.
+ * Cached statistics are currently:
+ * rx_din_dropped_pkts
+ * rx_filter_passed_pkts
+ * rx_filter_discard_pkts
+ */
+ *data++ = priv->stats.hw_access_errors;
+ *data++ = priv->stats.tx_invalid_checksums;
+ *data++ = priv->stats.tx_small_frames;
+ *data++ = priv->stats.tx_index_errors;
+ *data++ = priv->stats.sw_config_errors;
+ *data++ = priv->stats.sw_access_errors;
+ *data++ = priv->stats.rx_truncate_errors;
+ *data++ = priv->stats.rx_mac_errors;
+ *data++ = (priv->stats.rx_din_dropped_pkts +
+ readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER));
+ *data++ = priv->stats.tx_fifo_full;
+ *data++ = (priv->stats.rx_filter_passed_pkts +
+ readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL));
+ *data++ = (priv->stats.rx_filter_discard_pkts +
+ readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL));
+}
+
+static void mlxbf_gige_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ pause->autoneg = AUTONEG_DISABLE;
+ pause->rx_pause = 1;
+ pause->tx_pause = 1;
+}
+
+const struct ethtool_ops mlxbf_gige_ethtool_ops = {
+ .get_link = ethtool_op_get_link,
+ .get_ringparam = mlxbf_gige_get_ringparam,
+ .get_regs_len = mlxbf_gige_get_regs_len,
+ .get_regs = mlxbf_gige_get_regs,
+ .get_strings = mlxbf_gige_get_strings,
+ .get_sset_count = mlxbf_gige_get_sset_count,
+ .get_ethtool_stats = mlxbf_gige_get_ethtool_stats,
+ .nway_reset = phy_ethtool_nway_reset,
+ .get_pauseparam = mlxbf_gige_get_pauseparam,
+ .get_link_ksettings = phy_ethtool_get_link_ksettings,
+};
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c
new file mode 100644
index 000000000000..a8d966db5715
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+
+/* Initialize and handle GPIO interrupt triggered by INT_N PHY signal.
+ * This GPIO interrupt triggers the PHY state machine to bring the link
+ * up/down.
+ *
+ * Copyright (C) 2021 NVIDIA CORPORATION & AFFILIATES
+ */
+
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irqreturn.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#include "mlxbf_gige.h"
+#include "mlxbf_gige_regs.h"
+
+#define MLXBF_GIGE_GPIO_CAUSE_FALL_EN 0x48
+#define MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x80
+#define MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0 0x94
+#define MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE 0x98
+
+static void mlxbf_gige_gpio_enable(struct mlxbf_gige *priv)
+{
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&priv->gpio_lock, flags);
+ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE);
+ val |= priv->phy_int_gpio_mask;
+ writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE);
+
+ /* The INT_N interrupt level is active low.
+ * So enable cause fall bit to detect when GPIO
+ * state goes low.
+ */
+ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN);
+ val |= priv->phy_int_gpio_mask;
+ writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN);
+
+ /* Enable PHY interrupt by setting the priority level */
+ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0);
+ val |= priv->phy_int_gpio_mask;
+ writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0);
+ spin_unlock_irqrestore(&priv->gpio_lock, flags);
+}
+
+static void mlxbf_gige_gpio_disable(struct mlxbf_gige *priv)
+{
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&priv->gpio_lock, flags);
+ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0);
+ val &= ~priv->phy_int_gpio_mask;
+ writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0);
+ spin_unlock_irqrestore(&priv->gpio_lock, flags);
+}
+
+static irqreturn_t mlxbf_gige_gpio_handler(int irq, void *ptr)
+{
+ struct mlxbf_gige *priv;
+ u32 val;
+
+ priv = ptr;
+
+ /* Check if this interrupt is from PHY device.
+ * Return if it is not.
+ */
+ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0);
+ if (!(val & priv->phy_int_gpio_mask))
+ return IRQ_NONE;
+
+ /* Clear interrupt when done, otherwise, no further interrupt
+ * will be triggered.
+ */
+ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE);
+ val |= priv->phy_int_gpio_mask;
+ writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE);
+
+ generic_handle_irq(priv->phy_irq);
+
+ return IRQ_HANDLED;
+}
+
+static void mlxbf_gige_gpio_mask(struct irq_data *irqd)
+{
+ struct mlxbf_gige *priv = irq_data_get_irq_chip_data(irqd);
+
+ mlxbf_gige_gpio_disable(priv);
+}
+
+static void mlxbf_gige_gpio_unmask(struct irq_data *irqd)
+{
+ struct mlxbf_gige *priv = irq_data_get_irq_chip_data(irqd);
+
+ mlxbf_gige_gpio_enable(priv);
+}
+
+static struct irq_chip mlxbf_gige_gpio_chip = {
+ .name = "mlxbf_gige_phy",
+ .irq_mask = mlxbf_gige_gpio_mask,
+ .irq_unmask = mlxbf_gige_gpio_unmask,
+};
+
+static int mlxbf_gige_gpio_domain_map(struct irq_domain *d,
+ unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ irq_set_chip_data(irq, d->host_data);
+ irq_set_chip_and_handler(irq, &mlxbf_gige_gpio_chip, handle_simple_irq);
+ irq_set_noprobe(irq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops mlxbf_gige_gpio_domain_ops = {
+ .map = mlxbf_gige_gpio_domain_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+#ifdef CONFIG_ACPI
+static int mlxbf_gige_gpio_resources(struct acpi_resource *ares,
+ void *data)
+{
+ struct acpi_resource_gpio *gpio;
+ u32 *phy_int_gpio = data;
+
+ if (ares->type == ACPI_RESOURCE_TYPE_GPIO) {
+ gpio = &ares->data.gpio;
+ *phy_int_gpio = gpio->pin_table[0];
+ }
+
+ return 1;
+}
+#endif
+
+void mlxbf_gige_gpio_free(struct mlxbf_gige *priv)
+{
+ irq_dispose_mapping(priv->phy_irq);
+ irq_domain_remove(priv->irqdomain);
+}
+
+int mlxbf_gige_gpio_init(struct platform_device *pdev,
+ struct mlxbf_gige *priv)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ u32 phy_int_gpio = 0;
+ int ret;
+
+ LIST_HEAD(resources);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_GPIO0);
+ if (!res)
+ return -ENODEV;
+
+ priv->gpio_io = devm_ioremap(dev, res->start, resource_size(res));
+ if (!priv->gpio_io)
+ return -ENOMEM;
+
+#ifdef CONFIG_ACPI
+ ret = acpi_dev_get_resources(ACPI_COMPANION(dev),
+ &resources, mlxbf_gige_gpio_resources,
+ &phy_int_gpio);
+ acpi_dev_free_resource_list(&resources);
+ if (ret < 0 || !phy_int_gpio) {
+ dev_err(dev, "Error retrieving the gpio phy pin");
+ return -EINVAL;
+ }
+#endif
+
+ priv->phy_int_gpio_mask = BIT(phy_int_gpio);
+
+ mlxbf_gige_gpio_disable(priv);
+
+ priv->hw_phy_irq = platform_get_irq(pdev, MLXBF_GIGE_PHY_INT_N);
+
+ priv->irqdomain = irq_domain_add_simple(NULL, 1, 0,
+ &mlxbf_gige_gpio_domain_ops,
+ priv);
+ if (!priv->irqdomain) {
+ dev_err(dev, "Failed to add IRQ domain\n");
+ return -ENOMEM;
+ }
+
+ priv->phy_irq = irq_create_mapping(priv->irqdomain, 0);
+ if (!priv->phy_irq) {
+ irq_domain_remove(priv->irqdomain);
+ priv->irqdomain = NULL;
+ dev_err(dev, "Error mapping PHY IRQ\n");
+ return -EINVAL;
+ }
+
+ ret = devm_request_irq(dev, priv->hw_phy_irq, mlxbf_gige_gpio_handler,
+ IRQF_ONESHOT | IRQF_SHARED, "mlxbf_gige_phy", priv);
+ if (ret) {
+ dev_err(dev, "Failed to request PHY IRQ");
+ mlxbf_gige_gpio_free(priv);
+ return ret;
+ }
+
+ return ret;
+}
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c
new file mode 100644
index 000000000000..c38795be04a2
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+
+/* Interrupt related logic for Mellanox Gigabit Ethernet driver
+ *
+ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES
+ */
+
+#include <linux/interrupt.h>
+
+#include "mlxbf_gige.h"
+#include "mlxbf_gige_regs.h"
+
+static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id)
+{
+ struct mlxbf_gige *priv;
+ u64 int_status;
+
+ priv = dev_id;
+
+ priv->error_intr_count++;
+
+ int_status = readq(priv->base + MLXBF_GIGE_INT_STATUS);
+
+ if (int_status & MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR)
+ priv->stats.hw_access_errors++;
+
+ if (int_status & MLXBF_GIGE_INT_STATUS_TX_CHECKSUM_INPUTS) {
+ priv->stats.tx_invalid_checksums++;
+ /* This error condition is latched into MLXBF_GIGE_INT_STATUS
+ * when the GigE silicon operates on the offending
+ * TX WQE. The write to MLXBF_GIGE_INT_STATUS at the bottom
+ * of this routine clears this error condition.
+ */
+ }
+
+ if (int_status & MLXBF_GIGE_INT_STATUS_TX_SMALL_FRAME_SIZE) {
+ priv->stats.tx_small_frames++;
+ /* This condition happens when the networking stack invokes
+ * this driver's "start_xmit()" method with a packet whose
+ * size < 60 bytes. The GigE silicon will automatically pad
+ * this small frame up to a minimum-sized frame before it is
+ * sent. The "tx_small_frame" condition is latched into the
+ * MLXBF_GIGE_INT_STATUS register when the GigE silicon
+ * operates on the offending TX WQE. The write to
+ * MLXBF_GIGE_INT_STATUS at the bottom of this routine
+ * clears this condition.
+ */
+ }
+
+ if (int_status & MLXBF_GIGE_INT_STATUS_TX_PI_CI_EXCEED_WQ_SIZE)
+ priv->stats.tx_index_errors++;
+
+ if (int_status & MLXBF_GIGE_INT_STATUS_SW_CONFIG_ERROR)
+ priv->stats.sw_config_errors++;
+
+ if (int_status & MLXBF_GIGE_INT_STATUS_SW_ACCESS_ERROR)
+ priv->stats.sw_access_errors++;
+
+ /* Clear all error interrupts by writing '1' back to
+ * all the asserted bits in INT_STATUS. Do not write
+ * '1' back to 'receive packet' bit, since that is
+ * managed separately.
+ */
+
+ int_status &= ~MLXBF_GIGE_INT_STATUS_RX_RECEIVE_PACKET;
+
+ writeq(int_status, priv->base + MLXBF_GIGE_INT_STATUS);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mlxbf_gige_rx_intr(int irq, void *dev_id)
+{
+ struct mlxbf_gige *priv;
+
+ priv = dev_id;
+
+ priv->rx_intr_count++;
+
+ /* NOTE: GigE silicon automatically disables "packet rx" interrupt by
+ * setting MLXBF_GIGE_INT_MASK bit0 upon triggering the interrupt
+ * to the ARM cores. Software needs to re-enable "packet rx"
+ * interrupts by clearing MLXBF_GIGE_INT_MASK bit0.
+ */
+
+ napi_schedule(&priv->napi);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mlxbf_gige_llu_plu_intr(int irq, void *dev_id)
+{
+ struct mlxbf_gige *priv;
+
+ priv = dev_id;
+ priv->llu_plu_intr_count++;
+
+ return IRQ_HANDLED;
+}
+
+int mlxbf_gige_request_irqs(struct mlxbf_gige *priv)
+{
+ int err;
+
+ err = request_irq(priv->error_irq, mlxbf_gige_error_intr, 0,
+ "mlxbf_gige_error", priv);
+ if (err) {
+ dev_err(priv->dev, "Request error_irq failure\n");
+ return err;
+ }
+
+ err = request_irq(priv->rx_irq, mlxbf_gige_rx_intr, 0,
+ "mlxbf_gige_rx", priv);
+ if (err) {
+ dev_err(priv->dev, "Request rx_irq failure\n");
+ goto free_error_irq;
+ }
+
+ err = request_irq(priv->llu_plu_irq, mlxbf_gige_llu_plu_intr, 0,
+ "mlxbf_gige_llu_plu", priv);
+ if (err) {
+ dev_err(priv->dev, "Request llu_plu_irq failure\n");
+ goto free_rx_irq;
+ }
+
+ return 0;
+
+free_rx_irq:
+ free_irq(priv->rx_irq, priv);
+
+free_error_irq:
+ free_irq(priv->error_irq, priv);
+
+ return err;
+}
+
+void mlxbf_gige_free_irqs(struct mlxbf_gige *priv)
+{
+ free_irq(priv->error_irq, priv);
+ free_irq(priv->rx_irq, priv);
+ free_irq(priv->llu_plu_irq, priv);
+}
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
new file mode 100644
index 000000000000..a0a059e0154f
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
@@ -0,0 +1,452 @@
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+
+/* Gigabit Ethernet driver for Mellanox BlueField SoC
+ *
+ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/skbuff.h>
+
+#include "mlxbf_gige.h"
+#include "mlxbf_gige_regs.h"
+
+#define DRV_NAME "mlxbf_gige"
+
+/* Allocate SKB whose payload pointer aligns with the Bluefield
+ * hardware DMA limitation, i.e. DMA operation can't cross
+ * a 4KB boundary. A maximum packet size of 2KB is assumed in the
+ * alignment formula. The alignment logic overallocates an SKB,
+ * and then adjusts the headroom so that the SKB data pointer is
+ * naturally aligned to a 2KB boundary.
+ */
+struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv,
+ unsigned int map_len,
+ dma_addr_t *buf_dma,
+ enum dma_data_direction dir)
+{
+ struct sk_buff *skb;
+ u64 addr, offset;
+
+ /* Overallocate the SKB so that any headroom adjustment (to
+ * provide 2KB natural alignment) does not exceed payload area
+ */
+ skb = netdev_alloc_skb(priv->netdev, MLXBF_GIGE_DEFAULT_BUF_SZ * 2);
+ if (!skb)
+ return NULL;
+
+ /* Adjust the headroom so that skb->data is naturally aligned to
+ * a 2KB boundary, which is the maximum packet size supported.
+ */
+ addr = (long)skb->data;
+ offset = (addr + MLXBF_GIGE_DEFAULT_BUF_SZ - 1) &
+ ~(MLXBF_GIGE_DEFAULT_BUF_SZ - 1);
+ offset -= addr;
+ if (offset)
+ skb_reserve(skb, offset);
+
+ /* Return streaming DMA mapping to caller */
+ *buf_dma = dma_map_single(priv->dev, skb->data, map_len, dir);
+ if (dma_mapping_error(priv->dev, *buf_dma)) {
+ dev_kfree_skb(skb);
+ *buf_dma = (dma_addr_t)0;
+ return NULL;
+ }
+
+ return skb;
+}
+
+static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv)
+{
+ u8 mac[ETH_ALEN];
+ u64 local_mac;
+
+ memset(mac, 0, ETH_ALEN);
+ mlxbf_gige_get_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX,
+ &local_mac);
+ u64_to_ether_addr(local_mac, mac);
+
+ if (is_valid_ether_addr(mac)) {
+ ether_addr_copy(priv->netdev->dev_addr, mac);
+ } else {
+ /* Provide a random MAC if for some reason the device has
+ * not been configured with a valid MAC address already.
+ */
+ eth_hw_addr_random(priv->netdev);
+ }
+
+ local_mac = ether_addr_to_u64(priv->netdev->dev_addr);
+ mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX,
+ local_mac);
+}
+
+static void mlxbf_gige_cache_stats(struct mlxbf_gige *priv)
+{
+ struct mlxbf_gige_stats *p;
+
+ /* Cache stats that will be cleared by clean port operation */
+ p = &priv->stats;
+ p->rx_din_dropped_pkts += readq(priv->base +
+ MLXBF_GIGE_RX_DIN_DROP_COUNTER);
+ p->rx_filter_passed_pkts += readq(priv->base +
+ MLXBF_GIGE_RX_PASS_COUNTER_ALL);
+ p->rx_filter_discard_pkts += readq(priv->base +
+ MLXBF_GIGE_RX_DISC_COUNTER_ALL);
+}
+
+static int mlxbf_gige_clean_port(struct mlxbf_gige *priv)
+{
+ u64 control;
+ u64 temp;
+ int err;
+
+ /* Set the CLEAN_PORT_EN bit to trigger SW reset */
+ control = readq(priv->base + MLXBF_GIGE_CONTROL);
+ control |= MLXBF_GIGE_CONTROL_CLEAN_PORT_EN;
+ writeq(control, priv->base + MLXBF_GIGE_CONTROL);
+
+ /* Ensure completion of "clean port" write before polling status */
+ mb();
+
+ err = readq_poll_timeout_atomic(priv->base + MLXBF_GIGE_STATUS, temp,
+ (temp & MLXBF_GIGE_STATUS_READY),
+ 100, 100000);
+
+ /* Clear the CLEAN_PORT_EN bit at end of this loop */
+ control = readq(priv->base + MLXBF_GIGE_CONTROL);
+ control &= ~MLXBF_GIGE_CONTROL_CLEAN_PORT_EN;
+ writeq(control, priv->base + MLXBF_GIGE_CONTROL);
+
+ return err;
+}
+
+static int mlxbf_gige_open(struct net_device *netdev)
+{
+ struct mlxbf_gige *priv = netdev_priv(netdev);
+ struct phy_device *phydev = netdev->phydev;
+ u64 int_en;
+ int err;
+
+ err = mlxbf_gige_request_irqs(priv);
+ if (err)
+ return err;
+ mlxbf_gige_cache_stats(priv);
+ err = mlxbf_gige_clean_port(priv);
+ if (err)
+ goto free_irqs;
+ err = mlxbf_gige_rx_init(priv);
+ if (err)
+ goto free_irqs;
+ err = mlxbf_gige_tx_init(priv);
+ if (err)
+ goto rx_deinit;
+
+ phy_start(phydev);
+
+ netif_napi_add(netdev, &priv->napi, mlxbf_gige_poll, NAPI_POLL_WEIGHT);
+ napi_enable(&priv->napi);
+ netif_start_queue(netdev);
+
+ /* Set bits in INT_EN that we care about */
+ int_en = MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR |
+ MLXBF_GIGE_INT_EN_TX_CHECKSUM_INPUTS |
+ MLXBF_GIGE_INT_EN_TX_SMALL_FRAME_SIZE |
+ MLXBF_GIGE_INT_EN_TX_PI_CI_EXCEED_WQ_SIZE |
+ MLXBF_GIGE_INT_EN_SW_CONFIG_ERROR |
+ MLXBF_GIGE_INT_EN_SW_ACCESS_ERROR |
+ MLXBF_GIGE_INT_EN_RX_RECEIVE_PACKET;
+
+ /* Ensure completion of all initialization before enabling interrupts */
+ mb();
+
+ writeq(int_en, priv->base + MLXBF_GIGE_INT_EN);
+
+ return 0;
+
+rx_deinit:
+ mlxbf_gige_rx_deinit(priv);
+
+free_irqs:
+ mlxbf_gige_free_irqs(priv);
+ return err;
+}
+
+static int mlxbf_gige_stop(struct net_device *netdev)
+{
+ struct mlxbf_gige *priv = netdev_priv(netdev);
+
+ writeq(0, priv->base + MLXBF_GIGE_INT_EN);
+ netif_stop_queue(netdev);
+ napi_disable(&priv->napi);
+ netif_napi_del(&priv->napi);
+ mlxbf_gige_free_irqs(priv);
+
+ phy_stop(netdev->phydev);
+
+ mlxbf_gige_rx_deinit(priv);
+ mlxbf_gige_tx_deinit(priv);
+ mlxbf_gige_cache_stats(priv);
+ mlxbf_gige_clean_port(priv);
+
+ return 0;
+}
+
+static int mlxbf_gige_do_ioctl(struct net_device *netdev,
+ struct ifreq *ifr, int cmd)
+{
+ if (!(netif_running(netdev)))
+ return -EINVAL;
+
+ return phy_mii_ioctl(netdev->phydev, ifr, cmd);
+}
+
+static void mlxbf_gige_set_rx_mode(struct net_device *netdev)
+{
+ struct mlxbf_gige *priv = netdev_priv(netdev);
+ bool new_promisc_enabled;
+
+ new_promisc_enabled = netdev->flags & IFF_PROMISC;
+
+ /* Only write to the hardware registers if the new setting
+ * of promiscuous mode is different from the current one.
+ */
+ if (new_promisc_enabled != priv->promisc_enabled) {
+ priv->promisc_enabled = new_promisc_enabled;
+
+ if (new_promisc_enabled)
+ mlxbf_gige_enable_promisc(priv);
+ else
+ mlxbf_gige_disable_promisc(priv);
+ }
+}
+
+static void mlxbf_gige_get_stats64(struct net_device *netdev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct mlxbf_gige *priv = netdev_priv(netdev);
+
+ netdev_stats_to_stats64(stats, &netdev->stats);
+
+ stats->rx_length_errors = priv->stats.rx_truncate_errors;
+ stats->rx_fifo_errors = priv->stats.rx_din_dropped_pkts +
+ readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER);
+ stats->rx_crc_errors = priv->stats.rx_mac_errors;
+ stats->rx_errors = stats->rx_length_errors +
+ stats->rx_fifo_errors +
+ stats->rx_crc_errors;
+
+ stats->tx_fifo_errors = priv->stats.tx_fifo_full;
+ stats->tx_errors = stats->tx_fifo_errors;
+}
+
+static const struct net_device_ops mlxbf_gige_netdev_ops = {
+ .ndo_open = mlxbf_gige_open,
+ .ndo_stop = mlxbf_gige_stop,
+ .ndo_start_xmit = mlxbf_gige_start_xmit,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_do_ioctl = mlxbf_gige_do_ioctl,
+ .ndo_set_rx_mode = mlxbf_gige_set_rx_mode,
+ .ndo_get_stats64 = mlxbf_gige_get_stats64,
+};
+
+static void mlxbf_gige_adjust_link(struct net_device *netdev)
+{
+ struct phy_device *phydev = netdev->phydev;
+
+ phy_print_status(phydev);
+}
+
+static int mlxbf_gige_probe(struct platform_device *pdev)
+{
+ struct phy_device *phydev;
+ struct net_device *netdev;
+ struct resource *mac_res;
+ struct resource *llu_res;
+ struct resource *plu_res;
+ struct mlxbf_gige *priv;
+ void __iomem *llu_base;
+ void __iomem *plu_base;
+ void __iomem *base;
+ u64 control;
+ int addr;
+ int err;
+
+ mac_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MAC);
+ if (!mac_res)
+ return -ENXIO;
+
+ base = devm_ioremap_resource(&pdev->dev, mac_res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ llu_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_LLU);
+ if (!llu_res)
+ return -ENXIO;
+
+ llu_base = devm_ioremap_resource(&pdev->dev, llu_res);
+ if (IS_ERR(llu_base))
+ return PTR_ERR(llu_base);
+
+ plu_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_PLU);
+ if (!plu_res)
+ return -ENXIO;
+
+ plu_base = devm_ioremap_resource(&pdev->dev, plu_res);
+ if (IS_ERR(plu_base))
+ return PTR_ERR(plu_base);
+
+ /* Perform general init of GigE block */
+ control = readq(base + MLXBF_GIGE_CONTROL);
+ control |= MLXBF_GIGE_CONTROL_PORT_EN;
+ writeq(control, base + MLXBF_GIGE_CONTROL);
+
+ netdev = devm_alloc_etherdev(&pdev->dev, sizeof(*priv));
+ if (!netdev)
+ return -ENOMEM;
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+ netdev->netdev_ops = &mlxbf_gige_netdev_ops;
+ netdev->ethtool_ops = &mlxbf_gige_ethtool_ops;
+ priv = netdev_priv(netdev);
+ priv->netdev = netdev;
+
+ platform_set_drvdata(pdev, priv);
+ priv->dev = &pdev->dev;
+ priv->pdev = pdev;
+
+ spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->gpio_lock);
+
+ /* Attach MDIO device */
+ err = mlxbf_gige_mdio_probe(pdev, priv);
+ if (err)
+ return err;
+
+ err = mlxbf_gige_gpio_init(pdev, priv);
+ if (err) {
+ dev_err(&pdev->dev, "PHY IRQ initialization failed\n");
+ mlxbf_gige_mdio_remove(priv);
+ return -ENODEV;
+ }
+
+ priv->base = base;
+ priv->llu_base = llu_base;
+ priv->plu_base = plu_base;
+
+ priv->rx_q_entries = MLXBF_GIGE_DEFAULT_RXQ_SZ;
+ priv->tx_q_entries = MLXBF_GIGE_DEFAULT_TXQ_SZ;
+
+ /* Write initial MAC address to hardware */
+ mlxbf_gige_initial_mac(priv);
+
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (err) {
+ dev_err(&pdev->dev, "DMA configuration failed: 0x%x\n", err);
+ goto out;
+ }
+
+ priv->error_irq = platform_get_irq(pdev, MLXBF_GIGE_ERROR_INTR_IDX);
+ priv->rx_irq = platform_get_irq(pdev, MLXBF_GIGE_RECEIVE_PKT_INTR_IDX);
+ priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX);
+
+ phydev = phy_find_first(priv->mdiobus);
+ if (!phydev) {
+ err = -ENODEV;
+ goto out;
+ }
+
+ addr = phydev->mdio.addr;
+ priv->mdiobus->irq[addr] = priv->phy_irq;
+ phydev->irq = priv->phy_irq;
+
+ err = phy_connect_direct(netdev, phydev,
+ mlxbf_gige_adjust_link,
+ PHY_INTERFACE_MODE_GMII);
+ if (err) {
+ dev_err(&pdev->dev, "Could not attach to PHY\n");
+ goto out;
+ }
+
+ /* MAC only supports 1000T full duplex mode */
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT);
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT);
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
+
+ /* Only symmetric pause with flow control enabled is supported so no
+ * need to negotiate pause.
+ */
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising);
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising);
+
+ /* Display information about attached PHY device */
+ phy_attached_info(phydev);
+
+ err = register_netdev(netdev);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to register netdev\n");
+ phy_disconnect(phydev);
+ goto out;
+ }
+
+ return 0;
+
+out:
+ mlxbf_gige_gpio_free(priv);
+ mlxbf_gige_mdio_remove(priv);
+ return err;
+}
+
+static int mlxbf_gige_remove(struct platform_device *pdev)
+{
+ struct mlxbf_gige *priv = platform_get_drvdata(pdev);
+
+ unregister_netdev(priv->netdev);
+ phy_disconnect(priv->netdev->phydev);
+ mlxbf_gige_gpio_free(priv);
+ mlxbf_gige_mdio_remove(priv);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static void mlxbf_gige_shutdown(struct platform_device *pdev)
+{
+ struct mlxbf_gige *priv = platform_get_drvdata(pdev);
+
+ writeq(0, priv->base + MLXBF_GIGE_INT_EN);
+ mlxbf_gige_clean_port(priv);
+}
+
+static const struct acpi_device_id __maybe_unused mlxbf_gige_acpi_match[] = {
+ { "MLNXBF17", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, mlxbf_gige_acpi_match);
+
+static struct platform_driver mlxbf_gige_driver = {
+ .probe = mlxbf_gige_probe,
+ .remove = mlxbf_gige_remove,
+ .shutdown = mlxbf_gige_shutdown,
+ .driver = {
+ .name = DRV_NAME,
+ .acpi_match_table = ACPI_PTR(mlxbf_gige_acpi_match),
+ },
+};
+
+module_platform_driver(mlxbf_gige_driver);
+
+MODULE_DESCRIPTION("Mellanox BlueField SoC Gigabit Ethernet Driver");
+MODULE_AUTHOR("David Thompson <davthompson@nvidia.com>");
+MODULE_AUTHOR("Asmaa Mnebhi <asmaa@nvidia.com>");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
new file mode 100644
index 000000000000..e32dd34fdcc0
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+
+/* MDIO support for Mellanox Gigabit Ethernet driver
+ *
+ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES
+ */
+
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/irqreturn.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#include "mlxbf_gige.h"
+
+#define MLXBF_GIGE_MDIO_GW_OFFSET 0x0
+#define MLXBF_GIGE_MDIO_CFG_OFFSET 0x4
+
+/* Support clause 22 */
+#define MLXBF_GIGE_MDIO_CL22_ST1 0x1
+#define MLXBF_GIGE_MDIO_CL22_WRITE 0x1
+#define MLXBF_GIGE_MDIO_CL22_READ 0x2
+
+/* Busy bit is set by software and cleared by hardware */
+#define MLXBF_GIGE_MDIO_SET_BUSY 0x1
+
+/* MDIO GW register bits */
+#define MLXBF_GIGE_MDIO_GW_AD_MASK GENMASK(15, 0)
+#define MLXBF_GIGE_MDIO_GW_DEVAD_MASK GENMASK(20, 16)
+#define MLXBF_GIGE_MDIO_GW_PARTAD_MASK GENMASK(25, 21)
+#define MLXBF_GIGE_MDIO_GW_OPCODE_MASK GENMASK(27, 26)
+#define MLXBF_GIGE_MDIO_GW_ST1_MASK GENMASK(28, 28)
+#define MLXBF_GIGE_MDIO_GW_BUSY_MASK GENMASK(30, 30)
+
+/* MDIO config register bits */
+#define MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK GENMASK(1, 0)
+#define MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK GENMASK(2, 2)
+#define MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK GENMASK(4, 4)
+#define MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK GENMASK(15, 8)
+#define MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK GENMASK(23, 16)
+#define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK GENMASK(31, 24)
+
+/* Formula for encoding the MDIO period. The encoded value is
+ * passed to the MDIO config register.
+ *
+ * mdc_clk = 2*(val + 1)*i1clk
+ *
+ * 400 ns = 2*(val + 1)*(((1/430)*1000) ns)
+ *
+ * val = (((400 * 430 / 1000) / 2) - 1)
+ */
+#define MLXBF_GIGE_I1CLK_MHZ 430
+#define MLXBF_GIGE_MDC_CLK_NS 400
+
+#define MLXBF_GIGE_MDIO_PERIOD (((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1)
+
+#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \
+ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \
+ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \
+ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, \
+ MLXBF_GIGE_MDIO_PERIOD) | \
+ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \
+ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13))
+
+static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add,
+ int phy_reg, u32 opcode)
+{
+ u32 gw_reg = 0;
+
+ gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_AD_MASK, data);
+ gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_DEVAD_MASK, phy_reg);
+ gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_PARTAD_MASK, phy_add);
+ gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_OPCODE_MASK, opcode);
+ gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_ST1_MASK,
+ MLXBF_GIGE_MDIO_CL22_ST1);
+ gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_BUSY_MASK,
+ MLXBF_GIGE_MDIO_SET_BUSY);
+
+ return gw_reg;
+}
+
+static int mlxbf_gige_mdio_read(struct mii_bus *bus, int phy_add, int phy_reg)
+{
+ struct mlxbf_gige *priv = bus->priv;
+ u32 cmd;
+ int ret;
+ u32 val;
+
+ if (phy_reg & MII_ADDR_C45)
+ return -EOPNOTSUPP;
+
+ /* Send mdio read request */
+ cmd = mlxbf_gige_mdio_create_cmd(0, phy_add, phy_reg, MLXBF_GIGE_MDIO_CL22_READ);
+
+ writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
+
+ ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET,
+ val, !(val & MLXBF_GIGE_MDIO_GW_BUSY_MASK), 100, 1000000);
+
+ if (ret) {
+ writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
+ return ret;
+ }
+
+ ret = readl(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
+ /* Only return ad bits of the gw register */
+ ret &= MLXBF_GIGE_MDIO_GW_AD_MASK;
+
+ return ret;
+}
+
+static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add,
+ int phy_reg, u16 val)
+{
+ struct mlxbf_gige *priv = bus->priv;
+ u32 cmd;
+ int ret;
+ u32 temp;
+
+ if (phy_reg & MII_ADDR_C45)
+ return -EOPNOTSUPP;
+
+ /* Send mdio write request */
+ cmd = mlxbf_gige_mdio_create_cmd(val, phy_add, phy_reg,
+ MLXBF_GIGE_MDIO_CL22_WRITE);
+ writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
+
+ /* If the poll timed out, drop the request */
+ ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET,
+ temp, !(temp & MLXBF_GIGE_MDIO_GW_BUSY_MASK), 100, 1000000);
+
+ return ret;
+}
+
+int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MDIO9);
+ if (!res)
+ return -ENODEV;
+
+ priv->mdio_io = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->mdio_io))
+ return PTR_ERR(priv->mdio_io);
+
+ /* Configure mdio parameters */
+ writel(MLXBF_GIGE_MDIO_CFG_VAL,
+ priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET);
+
+ priv->mdiobus = devm_mdiobus_alloc(dev);
+ if (!priv->mdiobus) {
+ dev_err(dev, "Failed to alloc MDIO bus\n");
+ return -ENOMEM;
+ }
+
+ priv->mdiobus->name = "mlxbf-mdio";
+ priv->mdiobus->read = mlxbf_gige_mdio_read;
+ priv->mdiobus->write = mlxbf_gige_mdio_write;
+ priv->mdiobus->parent = dev;
+ priv->mdiobus->priv = priv;
+ snprintf(priv->mdiobus->id, MII_BUS_ID_SIZE, "%s",
+ dev_name(dev));
+
+ ret = mdiobus_register(priv->mdiobus);
+ if (ret)
+ dev_err(dev, "Failed to register MDIO bus\n");
+
+ return ret;
+}
+
+void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv)
+{
+ mdiobus_unregister(priv->mdiobus);
+}
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
new file mode 100644
index 000000000000..5fb33c9294bf
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */
+
+/* Header file for Mellanox BlueField GigE register defines
+ *
+ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES
+ */
+
+#ifndef __MLXBF_GIGE_REGS_H__
+#define __MLXBF_GIGE_REGS_H__
+
+#define MLXBF_GIGE_STATUS 0x0010
+#define MLXBF_GIGE_STATUS_READY BIT(0)
+#define MLXBF_GIGE_INT_STATUS 0x0028
+#define MLXBF_GIGE_INT_STATUS_RX_RECEIVE_PACKET BIT(0)
+#define MLXBF_GIGE_INT_STATUS_RX_MAC_ERROR BIT(1)
+#define MLXBF_GIGE_INT_STATUS_RX_TRN_ERROR BIT(2)
+#define MLXBF_GIGE_INT_STATUS_SW_ACCESS_ERROR BIT(3)
+#define MLXBF_GIGE_INT_STATUS_SW_CONFIG_ERROR BIT(4)
+#define MLXBF_GIGE_INT_STATUS_TX_PI_CI_EXCEED_WQ_SIZE BIT(5)
+#define MLXBF_GIGE_INT_STATUS_TX_SMALL_FRAME_SIZE BIT(6)
+#define MLXBF_GIGE_INT_STATUS_TX_CHECKSUM_INPUTS BIT(7)
+#define MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR BIT(8)
+#define MLXBF_GIGE_INT_EN 0x0030
+#define MLXBF_GIGE_INT_EN_RX_RECEIVE_PACKET BIT(0)
+#define MLXBF_GIGE_INT_EN_RX_MAC_ERROR BIT(1)
+#define MLXBF_GIGE_INT_EN_RX_TRN_ERROR BIT(2)
+#define MLXBF_GIGE_INT_EN_SW_ACCESS_ERROR BIT(3)
+#define MLXBF_GIGE_INT_EN_SW_CONFIG_ERROR BIT(4)
+#define MLXBF_GIGE_INT_EN_TX_PI_CI_EXCEED_WQ_SIZE BIT(5)
+#define MLXBF_GIGE_INT_EN_TX_SMALL_FRAME_SIZE BIT(6)
+#define MLXBF_GIGE_INT_EN_TX_CHECKSUM_INPUTS BIT(7)
+#define MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR BIT(8)
+#define MLXBF_GIGE_INT_MASK 0x0038
+#define MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET BIT(0)
+#define MLXBF_GIGE_CONTROL 0x0040
+#define MLXBF_GIGE_CONTROL_PORT_EN BIT(0)
+#define MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN BIT(1)
+#define MLXBF_GIGE_CONTROL_EN_SPECIFIC_MAC BIT(4)
+#define MLXBF_GIGE_CONTROL_CLEAN_PORT_EN BIT(31)
+#define MLXBF_GIGE_RX_WQ_BASE 0x0200
+#define MLXBF_GIGE_RX_WQE_SIZE_LOG2 0x0208
+#define MLXBF_GIGE_RX_WQE_SIZE_LOG2_RESET_VAL 7
+#define MLXBF_GIGE_RX_CQ_BASE 0x0210
+#define MLXBF_GIGE_TX_WQ_BASE 0x0218
+#define MLXBF_GIGE_TX_WQ_SIZE_LOG2 0x0220
+#define MLXBF_GIGE_TX_WQ_SIZE_LOG2_RESET_VAL 7
+#define MLXBF_GIGE_TX_CI_UPDATE_ADDRESS 0x0228
+#define MLXBF_GIGE_RX_WQE_PI 0x0230
+#define MLXBF_GIGE_TX_PRODUCER_INDEX 0x0238
+#define MLXBF_GIGE_RX_MAC_FILTER 0x0240
+#define MLXBF_GIGE_RX_MAC_FILTER_STRIDE 0x0008
+#define MLXBF_GIGE_RX_DIN_DROP_COUNTER 0x0260
+#define MLXBF_GIGE_TX_CONSUMER_INDEX 0x0310
+#define MLXBF_GIGE_TX_CONTROL 0x0318
+#define MLXBF_GIGE_TX_CONTROL_GRACEFUL_STOP BIT(0)
+#define MLXBF_GIGE_TX_STATUS 0x0388
+#define MLXBF_GIGE_TX_STATUS_DATA_FIFO_FULL BIT(1)
+#define MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START 0x0520
+#define MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END 0x0528
+#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC 0x0540
+#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC_EN BIT(0)
+#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS 0x0548
+#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS_EN BIT(0)
+#define MLXBF_GIGE_RX_PASS_COUNTER_ALL 0x0550
+#define MLXBF_GIGE_RX_DISC_COUNTER_ALL 0x0560
+#define MLXBF_GIGE_RX 0x0578
+#define MLXBF_GIGE_RX_STRIP_CRC_EN BIT(1)
+#define MLXBF_GIGE_RX_DMA 0x0580
+#define MLXBF_GIGE_RX_DMA_EN BIT(0)
+#define MLXBF_GIGE_RX_CQE_PACKET_CI 0x05b0
+#define MLXBF_GIGE_MAC_CFG 0x05e8
+
+/* NOTE: MLXBF_GIGE_MAC_CFG is the last defined register offset,
+ * so use that plus size of single register to derive total size
+ */
+#define MLXBF_GIGE_MMIO_REG_SZ (MLXBF_GIGE_MAC_CFG + 8)
+
+#endif /* !defined(__MLXBF_GIGE_REGS_H__) */
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c
new file mode 100644
index 000000000000..afa3b92a6905
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+
+/* Packet receive logic for Mellanox Gigabit Ethernet driver
+ *
+ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "mlxbf_gige.h"
+#include "mlxbf_gige_regs.h"
+
+void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv,
+ unsigned int index, u64 dmac)
+{
+ void __iomem *base = priv->base;
+ u64 control;
+
+ /* Write destination MAC to specified MAC RX filter */
+ writeq(dmac, base + MLXBF_GIGE_RX_MAC_FILTER +
+ (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE));
+
+ /* Enable MAC receive filter mask for specified index */
+ control = readq(base + MLXBF_GIGE_CONTROL);
+ control |= (MLXBF_GIGE_CONTROL_EN_SPECIFIC_MAC << index);
+ writeq(control, base + MLXBF_GIGE_CONTROL);
+}
+
+void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv,
+ unsigned int index, u64 *dmac)
+{
+ void __iomem *base = priv->base;
+
+ /* Read destination MAC from specified MAC RX filter */
+ *dmac = readq(base + MLXBF_GIGE_RX_MAC_FILTER +
+ (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE));
+}
+
+void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv)
+{
+ void __iomem *base = priv->base;
+ u64 control;
+ u64 end_mac;
+
+ /* Enable MAC_ID_RANGE match functionality */
+ control = readq(base + MLXBF_GIGE_CONTROL);
+ control |= MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN;
+ writeq(control, base + MLXBF_GIGE_CONTROL);
+
+ /* Set start of destination MAC range check to 0 */
+ writeq(0, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START);
+
+ /* Set end of destination MAC range check to all FFs */
+ end_mac = BCAST_MAC_ADDR;
+ writeq(end_mac, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END);
+}
+
+void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv)
+{
+ void __iomem *base = priv->base;
+ u64 control;
+
+ /* Disable MAC_ID_RANGE match functionality */
+ control = readq(base + MLXBF_GIGE_CONTROL);
+ control &= ~MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN;
+ writeq(control, base + MLXBF_GIGE_CONTROL);
+
+ /* NOTE: no need to change DMAC_RANGE_START or END;
+ * those values are ignored since MAC_ID_RANGE_EN=0
+ */
+}
+
+/* Receive Initialization
+ * 1) Configures RX MAC filters via MMIO registers
+ * 2) Allocates RX WQE array using coherent DMA mapping
+ * 3) Initializes each element of RX WQE array with a receive
+ * buffer pointer (also using coherent DMA mapping)
+ * 4) Allocates RX CQE array using coherent DMA mapping
+ * 5) Completes other misc receive initialization
+ */
+int mlxbf_gige_rx_init(struct mlxbf_gige *priv)
+{
+ size_t wq_size, cq_size;
+ dma_addr_t *rx_wqe_ptr;
+ dma_addr_t rx_buf_dma;
+ u64 data;
+ int i, j;
+
+ /* Configure MAC RX filter #0 to allow RX of broadcast pkts */
+ mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_BCAST_MAC_FILTER_IDX,
+ BCAST_MAC_ADDR);
+
+ wq_size = MLXBF_GIGE_RX_WQE_SZ * priv->rx_q_entries;
+ priv->rx_wqe_base = dma_alloc_coherent(priv->dev, wq_size,
+ &priv->rx_wqe_base_dma,
+ GFP_KERNEL);
+ if (!priv->rx_wqe_base)
+ return -ENOMEM;
+
+ /* Initialize 'rx_wqe_ptr' to point to first RX WQE in array
+ * Each RX WQE is simply a receive buffer pointer, so walk
+ * the entire array, allocating a 2KB buffer for each element
+ */
+ rx_wqe_ptr = priv->rx_wqe_base;
+
+ for (i = 0; i < priv->rx_q_entries; i++) {
+ priv->rx_skb[i] = mlxbf_gige_alloc_skb(priv, MLXBF_GIGE_DEFAULT_BUF_SZ,
+ &rx_buf_dma, DMA_FROM_DEVICE);
+ if (!priv->rx_skb[i])
+ goto free_wqe_and_skb;
+ *rx_wqe_ptr++ = rx_buf_dma;
+ }
+
+ /* Write RX WQE base address into MMIO reg */
+ writeq(priv->rx_wqe_base_dma, priv->base + MLXBF_GIGE_RX_WQ_BASE);
+
+ cq_size = MLXBF_GIGE_RX_CQE_SZ * priv->rx_q_entries;
+ priv->rx_cqe_base = dma_alloc_coherent(priv->dev, cq_size,
+ &priv->rx_cqe_base_dma,
+ GFP_KERNEL);
+ if (!priv->rx_cqe_base)
+ goto free_wqe_and_skb;
+
+ for (i = 0; i < priv->rx_q_entries; i++)
+ priv->rx_cqe_base[i] |= MLXBF_GIGE_RX_CQE_VALID_MASK;
+
+ /* Write RX CQE base address into MMIO reg */
+ writeq(priv->rx_cqe_base_dma, priv->base + MLXBF_GIGE_RX_CQ_BASE);
+
+ /* Write RX_WQE_PI with current number of replenished buffers */
+ writeq(priv->rx_q_entries, priv->base + MLXBF_GIGE_RX_WQE_PI);
+
+ /* Enable removal of CRC during RX */
+ data = readq(priv->base + MLXBF_GIGE_RX);
+ data |= MLXBF_GIGE_RX_STRIP_CRC_EN;
+ writeq(data, priv->base + MLXBF_GIGE_RX);
+
+ /* Enable RX MAC filter pass and discard counters */
+ writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC_EN,
+ priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC);
+ writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS_EN,
+ priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS);
+
+ /* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to
+ * indicate readiness to receive interrupts
+ */
+ data = readq(priv->base + MLXBF_GIGE_INT_MASK);
+ data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET;
+ writeq(data, priv->base + MLXBF_GIGE_INT_MASK);
+
+ /* Enable RX DMA to write new packets to memory */
+ data = readq(priv->base + MLXBF_GIGE_RX_DMA);
+ data |= MLXBF_GIGE_RX_DMA_EN;
+ writeq(data, priv->base + MLXBF_GIGE_RX_DMA);
+
+ writeq(ilog2(priv->rx_q_entries),
+ priv->base + MLXBF_GIGE_RX_WQE_SIZE_LOG2);
+
+ return 0;
+
+free_wqe_and_skb:
+ rx_wqe_ptr = priv->rx_wqe_base;
+ for (j = 0; j < i; j++) {
+ dma_unmap_single(priv->dev, *rx_wqe_ptr,
+ MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE);
+ dev_kfree_skb(priv->rx_skb[j]);
+ rx_wqe_ptr++;
+ }
+ dma_free_coherent(priv->dev, wq_size,
+ priv->rx_wqe_base, priv->rx_wqe_base_dma);
+ return -ENOMEM;
+}
+
+/* Receive Deinitialization
+ * This routine will free allocations done by mlxbf_gige_rx_init(),
+ * namely the RX WQE and RX CQE arrays, as well as all RX buffers
+ */
+void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv)
+{
+ dma_addr_t *rx_wqe_ptr;
+ size_t size;
+ u64 data;
+ int i;
+
+ /* Disable RX DMA to prevent packet transfers to memory */
+ data = readq(priv->base + MLXBF_GIGE_RX_DMA);
+ data &= ~MLXBF_GIGE_RX_DMA_EN;
+ writeq(data, priv->base + MLXBF_GIGE_RX_DMA);
+
+ rx_wqe_ptr = priv->rx_wqe_base;
+
+ for (i = 0; i < priv->rx_q_entries; i++) {
+ dma_unmap_single(priv->dev, *rx_wqe_ptr, MLXBF_GIGE_DEFAULT_BUF_SZ,
+ DMA_FROM_DEVICE);
+ dev_kfree_skb(priv->rx_skb[i]);
+ rx_wqe_ptr++;
+ }
+
+ size = MLXBF_GIGE_RX_WQE_SZ * priv->rx_q_entries;
+ dma_free_coherent(priv->dev, size,
+ priv->rx_wqe_base, priv->rx_wqe_base_dma);
+
+ size = MLXBF_GIGE_RX_CQE_SZ * priv->rx_q_entries;
+ dma_free_coherent(priv->dev, size,
+ priv->rx_cqe_base, priv->rx_cqe_base_dma);
+
+ priv->rx_wqe_base = NULL;
+ priv->rx_wqe_base_dma = 0;
+ priv->rx_cqe_base = NULL;
+ priv->rx_cqe_base_dma = 0;
+ writeq(0, priv->base + MLXBF_GIGE_RX_WQ_BASE);
+ writeq(0, priv->base + MLXBF_GIGE_RX_CQ_BASE);
+}
+
+static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts)
+{
+ struct net_device *netdev = priv->netdev;
+ struct sk_buff *skb = NULL, *rx_skb;
+ u16 rx_pi_rem, rx_ci_rem;
+ dma_addr_t *rx_wqe_addr;
+ dma_addr_t rx_buf_dma;
+ u64 *rx_cqe_addr;
+ u64 datalen;
+ u64 rx_cqe;
+ u16 rx_ci;
+ u16 rx_pi;
+
+ /* Index into RX buffer array is rx_pi w/wrap based on RX_CQE_SIZE */
+ rx_pi = readq(priv->base + MLXBF_GIGE_RX_WQE_PI);
+ rx_pi_rem = rx_pi % priv->rx_q_entries;
+
+ rx_wqe_addr = priv->rx_wqe_base + rx_pi_rem;
+ rx_cqe_addr = priv->rx_cqe_base + rx_pi_rem;
+ rx_cqe = *rx_cqe_addr;
+
+ if ((!!(rx_cqe & MLXBF_GIGE_RX_CQE_VALID_MASK)) != priv->valid_polarity)
+ return false;
+
+ if ((rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MASK) == 0) {
+ /* Packet is OK, increment stats */
+ datalen = rx_cqe & MLXBF_GIGE_RX_CQE_PKT_LEN_MASK;
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += datalen;
+
+ skb = priv->rx_skb[rx_pi_rem];
+
+ skb_put(skb, datalen);
+
+ skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */
+
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ /* Alloc another RX SKB for this same index */
+ rx_skb = mlxbf_gige_alloc_skb(priv, MLXBF_GIGE_DEFAULT_BUF_SZ,
+ &rx_buf_dma, DMA_FROM_DEVICE);
+ if (!rx_skb)
+ return false;
+ priv->rx_skb[rx_pi_rem] = rx_skb;
+ dma_unmap_single(priv->dev, *rx_wqe_addr,
+ MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE);
+ *rx_wqe_addr = rx_buf_dma;
+ } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR) {
+ priv->stats.rx_mac_errors++;
+ } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_TRUNCATED) {
+ priv->stats.rx_truncate_errors++;
+ }
+
+ /* Let hardware know we've replenished one buffer */
+ rx_pi++;
+
+ /* Ensure completion of all writes before notifying HW of replenish */
+ wmb();
+ writeq(rx_pi, priv->base + MLXBF_GIGE_RX_WQE_PI);
+
+ (*rx_pkts)++;
+
+ rx_pi_rem = rx_pi % priv->rx_q_entries;
+ if (rx_pi_rem == 0)
+ priv->valid_polarity ^= 1;
+ rx_ci = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI);
+ rx_ci_rem = rx_ci % priv->rx_q_entries;
+
+ if (skb)
+ netif_receive_skb(skb);
+
+ return rx_pi_rem != rx_ci_rem;
+}
+
+/* Driver poll() function called by NAPI infrastructure */
+int mlxbf_gige_poll(struct napi_struct *napi, int budget)
+{
+ struct mlxbf_gige *priv;
+ bool remaining_pkts;
+ int work_done = 0;
+ u64 data;
+
+ priv = container_of(napi, struct mlxbf_gige, napi);
+
+ mlxbf_gige_handle_tx_complete(priv);
+
+ do {
+ remaining_pkts = mlxbf_gige_rx_packet(priv, &work_done);
+ } while (remaining_pkts && work_done < budget);
+
+ /* If amount of work done < budget, turn off NAPI polling
+ * via napi_complete_done(napi, work_done) and then
+ * re-enable interrupts.
+ */
+ if (work_done < budget && napi_complete_done(napi, work_done)) {
+ /* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to
+ * indicate receive readiness
+ */
+ data = readq(priv->base + MLXBF_GIGE_INT_MASK);
+ data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET;
+ writeq(data, priv->base + MLXBF_GIGE_INT_MASK);
+ }
+
+ return work_done;
+}
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c
new file mode 100644
index 000000000000..04982e888c63
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+
+/* Packet transmit logic for Mellanox Gigabit Ethernet driver
+ *
+ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES
+ */
+
+#include <linux/skbuff.h>
+
+#include "mlxbf_gige.h"
+#include "mlxbf_gige_regs.h"
+
+/* Transmit Initialization
+ * 1) Allocates TX WQE array using coherent DMA mapping
+ * 2) Allocates TX completion counter using coherent DMA mapping
+ */
+int mlxbf_gige_tx_init(struct mlxbf_gige *priv)
+{
+ size_t size;
+
+ size = MLXBF_GIGE_TX_WQE_SZ * priv->tx_q_entries;
+ priv->tx_wqe_base = dma_alloc_coherent(priv->dev, size,
+ &priv->tx_wqe_base_dma,
+ GFP_KERNEL);
+ if (!priv->tx_wqe_base)
+ return -ENOMEM;
+
+ priv->tx_wqe_next = priv->tx_wqe_base;
+
+ /* Write TX WQE base address into MMIO reg */
+ writeq(priv->tx_wqe_base_dma, priv->base + MLXBF_GIGE_TX_WQ_BASE);
+
+ /* Allocate address for TX completion count */
+ priv->tx_cc = dma_alloc_coherent(priv->dev, MLXBF_GIGE_TX_CC_SZ,
+ &priv->tx_cc_dma, GFP_KERNEL);
+ if (!priv->tx_cc) {
+ dma_free_coherent(priv->dev, size,
+ priv->tx_wqe_base, priv->tx_wqe_base_dma);
+ return -ENOMEM;
+ }
+
+ /* Write TX CC base address into MMIO reg */
+ writeq(priv->tx_cc_dma, priv->base + MLXBF_GIGE_TX_CI_UPDATE_ADDRESS);
+
+ writeq(ilog2(priv->tx_q_entries),
+ priv->base + MLXBF_GIGE_TX_WQ_SIZE_LOG2);
+
+ priv->prev_tx_ci = 0;
+ priv->tx_pi = 0;
+
+ return 0;
+}
+
+/* Transmit Deinitialization
+ * This routine will free allocations done by mlxbf_gige_tx_init(),
+ * namely the TX WQE array and the TX completion counter
+ */
+void mlxbf_gige_tx_deinit(struct mlxbf_gige *priv)
+{
+ u64 *tx_wqe_addr;
+ size_t size;
+ int i;
+
+ tx_wqe_addr = priv->tx_wqe_base;
+
+ for (i = 0; i < priv->tx_q_entries; i++) {
+ if (priv->tx_skb[i]) {
+ dma_unmap_single(priv->dev, *tx_wqe_addr,
+ priv->tx_skb[i]->len, DMA_TO_DEVICE);
+ dev_kfree_skb(priv->tx_skb[i]);
+ priv->tx_skb[i] = NULL;
+ }
+ tx_wqe_addr += 2;
+ }
+
+ size = MLXBF_GIGE_TX_WQE_SZ * priv->tx_q_entries;
+ dma_free_coherent(priv->dev, size,
+ priv->tx_wqe_base, priv->tx_wqe_base_dma);
+
+ dma_free_coherent(priv->dev, MLXBF_GIGE_TX_CC_SZ,
+ priv->tx_cc, priv->tx_cc_dma);
+
+ priv->tx_wqe_base = NULL;
+ priv->tx_wqe_base_dma = 0;
+ priv->tx_cc = NULL;
+ priv->tx_cc_dma = 0;
+ priv->tx_wqe_next = NULL;
+ writeq(0, priv->base + MLXBF_GIGE_TX_WQ_BASE);
+ writeq(0, priv->base + MLXBF_GIGE_TX_CI_UPDATE_ADDRESS);
+}
+
+/* Function that returns status of TX ring:
+ * 0: TX ring is full, i.e. there are no
+ * available un-used entries in TX ring.
+ * non-null: TX ring is not full, i.e. there are
+ * some available entries in TX ring.
+ * The non-null value is a measure of
+ * how many TX entries are available, but
+ * it is not the exact number of available
+ * entries (see below).
+ *
+ * The algorithm makes the assumption that if
+ * (prev_tx_ci == tx_pi) then the TX ring is empty.
+ * An empty ring actually has (tx_q_entries-1)
+ * entries, which allows the algorithm to differentiate
+ * the case of an empty ring vs. a full ring.
+ */
+static u16 mlxbf_gige_tx_buffs_avail(struct mlxbf_gige *priv)
+{
+ unsigned long flags;
+ u16 avail;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->prev_tx_ci == priv->tx_pi)
+ avail = priv->tx_q_entries - 1;
+ else
+ avail = ((priv->tx_q_entries + priv->prev_tx_ci - priv->tx_pi)
+ % priv->tx_q_entries) - 1;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return avail;
+}
+
+bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv)
+{
+ struct net_device_stats *stats;
+ u16 tx_wqe_index;
+ u64 *tx_wqe_addr;
+ u64 tx_status;
+ u16 tx_ci;
+
+ tx_status = readq(priv->base + MLXBF_GIGE_TX_STATUS);
+ if (tx_status & MLXBF_GIGE_TX_STATUS_DATA_FIFO_FULL)
+ priv->stats.tx_fifo_full++;
+ tx_ci = readq(priv->base + MLXBF_GIGE_TX_CONSUMER_INDEX);
+ stats = &priv->netdev->stats;
+
+ /* Transmit completion logic needs to loop until the completion
+ * index (in SW) equals TX consumer index (from HW). These
+ * parameters are unsigned 16-bit values and the wrap case needs
+ * to be supported, that is TX consumer index wrapped from 0xFFFF
+ * to 0 while TX completion index is still < 0xFFFF.
+ */
+ for (; priv->prev_tx_ci != tx_ci; priv->prev_tx_ci++) {
+ tx_wqe_index = priv->prev_tx_ci % priv->tx_q_entries;
+ /* Each TX WQE is 16 bytes. The 8 MSB store the 2KB TX
+ * buffer address and the 8 LSB contain information
+ * about the TX WQE.
+ */
+ tx_wqe_addr = priv->tx_wqe_base +
+ (tx_wqe_index * MLXBF_GIGE_TX_WQE_SZ_QWORDS);
+
+ stats->tx_packets++;
+ stats->tx_bytes += MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr);
+
+ dma_unmap_single(priv->dev, *tx_wqe_addr,
+ priv->tx_skb[tx_wqe_index]->len, DMA_TO_DEVICE);
+ dev_consume_skb_any(priv->tx_skb[tx_wqe_index]);
+ priv->tx_skb[tx_wqe_index] = NULL;
+
+ /* Ensure completion of updates across all cores */
+ mb();
+ }
+
+ /* Since the TX ring was likely just drained, check if TX queue
+ * had previously been stopped and now that there are TX buffers
+ * available the TX queue can be awakened.
+ */
+ if (netif_queue_stopped(priv->netdev) &&
+ mlxbf_gige_tx_buffs_avail(priv))
+ netif_wake_queue(priv->netdev);
+
+ return true;
+}
+
+/* Function to advance the tx_wqe_next pointer to next TX WQE */
+void mlxbf_gige_update_tx_wqe_next(struct mlxbf_gige *priv)
+{
+ /* Advance tx_wqe_next pointer */
+ priv->tx_wqe_next += MLXBF_GIGE_TX_WQE_SZ_QWORDS;
+
+ /* Check if 'next' pointer is beyond end of TX ring */
+ /* If so, set 'next' back to 'base' pointer of ring */
+ if (priv->tx_wqe_next == (priv->tx_wqe_base +
+ (priv->tx_q_entries * MLXBF_GIGE_TX_WQE_SZ_QWORDS)))
+ priv->tx_wqe_next = priv->tx_wqe_base;
+}
+
+netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ struct mlxbf_gige *priv = netdev_priv(netdev);
+ long buff_addr, start_dma_page, end_dma_page;
+ struct sk_buff *tx_skb;
+ dma_addr_t tx_buf_dma;
+ unsigned long flags;
+ u64 *tx_wqe_addr;
+ u64 word2;
+
+ /* If needed, linearize TX SKB as hardware DMA expects this */
+ if (skb->len > MLXBF_GIGE_DEFAULT_BUF_SZ || skb_linearize(skb)) {
+ dev_kfree_skb(skb);
+ netdev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+
+ buff_addr = (long)skb->data;
+ start_dma_page = buff_addr >> MLXBF_GIGE_DMA_PAGE_SHIFT;
+ end_dma_page = (buff_addr + skb->len - 1) >> MLXBF_GIGE_DMA_PAGE_SHIFT;
+
+ /* Verify that payload pointer and data length of SKB to be
+ * transmitted does not violate the hardware DMA limitation.
+ */
+ if (start_dma_page != end_dma_page) {
+ /* DMA operation would fail as-is, alloc new aligned SKB */
+ tx_skb = mlxbf_gige_alloc_skb(priv, skb->len,
+ &tx_buf_dma, DMA_TO_DEVICE);
+ if (!tx_skb) {
+ /* Free original skb, could not alloc new aligned SKB */
+ dev_kfree_skb(skb);
+ netdev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+
+ skb_put_data(tx_skb, skb->data, skb->len);
+
+ /* Free the original SKB */
+ dev_kfree_skb(skb);
+ } else {
+ tx_skb = skb;
+ tx_buf_dma = dma_map_single(priv->dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
+ if (dma_mapping_error(priv->dev, tx_buf_dma)) {
+ dev_kfree_skb(skb);
+ netdev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+ }
+
+ /* Get address of TX WQE */
+ tx_wqe_addr = priv->tx_wqe_next;
+
+ mlxbf_gige_update_tx_wqe_next(priv);
+
+ /* Put PA of buffer address into first 64-bit word of TX WQE */
+ *tx_wqe_addr = tx_buf_dma;
+
+ /* Set TX WQE pkt_len appropriately
+ * NOTE: GigE silicon will automatically pad up to
+ * minimum packet length if needed.
+ */
+ word2 = tx_skb->len & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK;
+
+ /* Write entire 2nd word of TX WQE */
+ *(tx_wqe_addr + 1) = word2;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->tx_skb[priv->tx_pi % priv->tx_q_entries] = tx_skb;
+ priv->tx_pi++;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (!netdev_xmit_more()) {
+ /* Create memory barrier before write to TX PI */
+ wmb();
+ writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX);
+ }
+
+ /* Check if the last TX entry was just used */
+ if (!mlxbf_gige_tx_buffs_avail(priv)) {
+ /* TX ring is full, inform stack */
+ netif_stop_queue(netdev);
+
+ /* Since there is no separate "TX complete" interrupt, need
+ * to explicitly schedule NAPI poll. This will trigger logic
+ * which processes TX completions, and will hopefully drain
+ * the TX ring allowing the TX queue to be awakened.
+ */
+ napi_schedule(&priv->napi);
+ }
+
+ return NETDEV_TX_OK;
+}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig
index a619d90559f7..12871c8dc7c1 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig
@@ -49,28 +49,6 @@ config MLXSW_I2C
To compile this driver as a module, choose M here: the
module will be called mlxsw_i2c.
-config MLXSW_SWITCHIB
- tristate "Mellanox Technologies SwitchIB and SwitchIB-2 support"
- depends on MLXSW_CORE && MLXSW_PCI && NET_SWITCHDEV
- default m
- help
- This driver supports Mellanox Technologies SwitchIB and SwitchIB-2
- Infiniband Switch ASICs.
-
- To compile this driver as a module, choose M here: the
- module will be called mlxsw_switchib.
-
-config MLXSW_SWITCHX2
- tristate "Mellanox Technologies SwitchX-2 support"
- depends on MLXSW_CORE && MLXSW_PCI && NET_SWITCHDEV
- default m
- help
- This driver supports Mellanox Technologies SwitchX-2 Ethernet
- Switch ASICs.
-
- To compile this driver as a module, choose M here: the
- module will be called mlxsw_switchx2.
-
config MLXSW_SPECTRUM
tristate "Mellanox Technologies Spectrum family support"
depends on MLXSW_CORE && MLXSW_PCI && NET_SWITCHDEV && VLAN_8021Q
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile
index f545fd2c5896..196adeb33495 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Makefile
+++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile
@@ -8,10 +8,6 @@ obj-$(CONFIG_MLXSW_PCI) += mlxsw_pci.o
mlxsw_pci-objs := pci.o
obj-$(CONFIG_MLXSW_I2C) += mlxsw_i2c.o
mlxsw_i2c-objs := i2c.o
-obj-$(CONFIG_MLXSW_SWITCHIB) += mlxsw_switchib.o
-mlxsw_switchib-objs := switchib.o
-obj-$(CONFIG_MLXSW_SWITCHX2) += mlxsw_switchx2.o
-mlxsw_switchx2-objs := switchx2.o
obj-$(CONFIG_MLXSW_SPECTRUM) += mlxsw_spectrum.o
mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \
spectrum_switchdev.o spectrum_router.o \
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
index 7e9a7cb31720..e775f08fb464 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c
@@ -630,7 +630,7 @@ static int mlxsw_emad_transmit(struct mlxsw_core *mlxsw_core,
struct sk_buff *skb;
int err;
- skb = skb_copy(trans->tx_skb, GFP_KERNEL);
+ skb = skb_clone(trans->tx_skb, GFP_KERNEL);
if (!skb)
return -ENOMEM;
@@ -1444,7 +1444,9 @@ mlxsw_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
if (err)
return err;
- err = devlink_info_version_fixed_put(req, "fw.psid", fw_info_psid);
+ err = devlink_info_version_fixed_put(req,
+ DEVLINK_INFO_VERSION_GENERIC_FW_PSID,
+ fw_info_psid);
if (err)
return err;
@@ -1453,7 +1455,9 @@ mlxsw_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
if (err)
return err;
- return 0;
+ return devlink_info_version_running_put(req,
+ DEVLINK_INFO_VERSION_GENERIC_FW,
+ buf);
}
static int
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c
index dd26865bd587..3713c45cfa1e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c
@@ -3,6 +3,7 @@
#include <linux/kernel.h>
#include <linux/err.h>
+#include <linux/ethtool.h>
#include <linux/sfp.h>
#include "core.h"
@@ -25,8 +26,8 @@ struct mlxsw_env {
static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id,
bool *qsfp, bool *cmis)
{
- char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE];
char mcia_pl[MLXSW_REG_MCIA_LEN];
+ char *eeprom_tmp;
u8 ident;
int err;
@@ -35,7 +36,7 @@ static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id,
err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
if (err)
return err;
- mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp);
+ eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
ident = eeprom_tmp[0];
*cmis = false;
switch (ident) {
@@ -63,8 +64,8 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module,
u16 offset, u16 size, void *data,
bool qsfp, unsigned int *p_read_size)
{
- char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE];
char mcia_pl[MLXSW_REG_MCIA_LEN];
+ char *eeprom_tmp;
u16 i2c_addr;
u8 page = 0;
int status;
@@ -115,7 +116,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module,
if (status)
return -EIO;
- mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp);
+ eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
memcpy(data, eeprom_tmp, size);
*p_read_size = size;
@@ -125,14 +126,14 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module,
int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module,
int off, int *temp)
{
- char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE];
+ unsigned int module_temp, module_crit, module_emerg;
union {
u8 buf[MLXSW_REG_MCIA_TH_ITEM_SIZE];
u16 temp;
} temp_thresh;
char mcia_pl[MLXSW_REG_MCIA_LEN] = {0};
char mtmp_pl[MLXSW_REG_MTMP_LEN];
- unsigned int module_temp;
+ char *eeprom_tmp;
bool qsfp, cmis;
int page;
int err;
@@ -142,12 +143,21 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module,
err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl);
if (err)
return err;
- mlxsw_reg_mtmp_unpack(mtmp_pl, &module_temp, NULL, NULL);
+ mlxsw_reg_mtmp_unpack(mtmp_pl, &module_temp, NULL, &module_crit,
+ &module_emerg, NULL);
if (!module_temp) {
*temp = 0;
return 0;
}
+ /* Validate if threshold reading is available through MTMP register,
+ * otherwise fallback to read through MCIA.
+ */
+ if (module_emerg) {
+ *temp = off == SFP_TEMP_HIGH_WARN ? module_crit : module_emerg;
+ return 0;
+ }
+
/* Read Free Side Device Temperature Thresholds from page 03h
* (MSB at lower byte address).
* Bytes:
@@ -185,7 +195,7 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module,
if (err)
return err;
- mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp);
+ eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
memcpy(temp_thresh.buf, eeprom_tmp, MLXSW_REG_MCIA_TH_ITEM_SIZE);
*temp = temp_thresh.temp * 1000;
@@ -306,6 +316,79 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev,
}
EXPORT_SYMBOL(mlxsw_env_get_module_eeprom);
+static int mlxsw_env_mcia_status_process(const char *mcia_pl,
+ struct netlink_ext_ack *extack)
+{
+ u8 status = mlxsw_reg_mcia_status_get(mcia_pl);
+
+ switch (status) {
+ case MLXSW_REG_MCIA_STATUS_GOOD:
+ return 0;
+ case MLXSW_REG_MCIA_STATUS_NO_EEPROM_MODULE:
+ NL_SET_ERR_MSG_MOD(extack, "No response from module's EEPROM");
+ return -EIO;
+ case MLXSW_REG_MCIA_STATUS_MODULE_NOT_SUPPORTED:
+ NL_SET_ERR_MSG_MOD(extack, "Module type not supported by the device");
+ return -EOPNOTSUPP;
+ case MLXSW_REG_MCIA_STATUS_MODULE_NOT_CONNECTED:
+ NL_SET_ERR_MSG_MOD(extack, "No module present indication");
+ return -EIO;
+ case MLXSW_REG_MCIA_STATUS_I2C_ERROR:
+ NL_SET_ERR_MSG_MOD(extack, "Error occurred while trying to access module's EEPROM using I2C");
+ return -EIO;
+ case MLXSW_REG_MCIA_STATUS_MODULE_DISABLED:
+ NL_SET_ERR_MSG_MOD(extack, "Module is disabled");
+ return -EIO;
+ default:
+ NL_SET_ERR_MSG_MOD(extack, "Unknown error");
+ return -EIO;
+ }
+}
+
+int
+mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
+ const struct ethtool_module_eeprom *page,
+ struct netlink_ext_ack *extack)
+{
+ u32 bytes_read = 0;
+ u16 device_addr;
+
+ /* Offset cannot be larger than 2 * ETH_MODULE_EEPROM_PAGE_LEN */
+ device_addr = page->offset;
+
+ while (bytes_read < page->length) {
+ char mcia_pl[MLXSW_REG_MCIA_LEN];
+ char *eeprom_tmp;
+ u8 size;
+ int err;
+
+ size = min_t(u8, page->length - bytes_read,
+ MLXSW_REG_MCIA_EEPROM_SIZE);
+
+ mlxsw_reg_mcia_pack(mcia_pl, module, 0, page->page,
+ device_addr + bytes_read, size,
+ page->i2c_address);
+ mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank);
+
+ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to access module's EEPROM");
+ return err;
+ }
+
+ err = mlxsw_env_mcia_status_process(mcia_pl, extack);
+ if (err)
+ return err;
+
+ eeprom_tmp = mlxsw_reg_mcia_eeprom_data(mcia_pl);
+ memcpy(page->data + bytes_read, eeprom_tmp, size);
+ bytes_read += size;
+ }
+
+ return bytes_read;
+}
+EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page);
+
static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core,
u8 module,
bool *p_has_temp_sensor)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.h b/drivers/net/ethernet/mellanox/mlxsw/core_env.h
index 2b23f8a87862..0bf5bd0f8a7e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.h
@@ -4,6 +4,8 @@
#ifndef _MLXSW_CORE_ENV_H
#define _MLXSW_CORE_ENV_H
+#include <linux/ethtool.h>
+
struct ethtool_modinfo;
struct ethtool_eeprom;
@@ -18,6 +20,11 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev,
struct ethtool_eeprom *ee, u8 *data);
int
+mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
+ const struct ethtool_module_eeprom *page,
+ struct netlink_ext_ack *extack);
+
+int
mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module,
u64 *p_counter);
int mlxsw_env_init(struct mlxsw_core *core, struct mlxsw_env **p_env);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
index 2196c946698a..d41afdfbd085 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
@@ -72,7 +72,7 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev,
dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n");
return err;
}
- mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
+ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL);
return sprintf(buf, "%d\n", temp);
}
@@ -95,7 +95,7 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev,
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);
+ mlxsw_reg_mtmp_unpack(mtmp_pl, NULL, &temp_max, NULL, NULL, NULL);
return sprintf(buf, "%d\n", temp_max);
}
@@ -239,7 +239,7 @@ static int mlxsw_hwmon_module_temp_get(struct device *dev,
dev_err(dev, "Failed to query module temperature\n");
return err;
}
- mlxsw_reg_mtmp_unpack(mtmp_pl, p_temp, NULL, NULL);
+ mlxsw_reg_mtmp_unpack(mtmp_pl, p_temp, NULL, NULL, NULL, NULL);
return 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
index 85f0ce285146..0998dcc9cac0 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -149,22 +149,27 @@ mlxsw_thermal_module_trips_reset(struct mlxsw_thermal_module *tz)
static int
mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core,
- struct mlxsw_thermal_module *tz)
+ struct mlxsw_thermal_module *tz,
+ int crit_temp, int emerg_temp)
{
- int crit_temp, emerg_temp;
int err;
- err = mlxsw_env_module_temp_thresholds_get(core, tz->module,
- SFP_TEMP_HIGH_WARN,
- &crit_temp);
- if (err)
- return err;
+ /* Do not try to query temperature thresholds directly from the module's
+ * EEPROM if we got valid thresholds from MTMP.
+ */
+ if (!emerg_temp || !crit_temp) {
+ err = mlxsw_env_module_temp_thresholds_get(core, tz->module,
+ SFP_TEMP_HIGH_WARN,
+ &crit_temp);
+ if (err)
+ return err;
- err = mlxsw_env_module_temp_thresholds_get(core, tz->module,
- SFP_TEMP_HIGH_ALARM,
- &emerg_temp);
- if (err)
- return err;
+ err = mlxsw_env_module_temp_thresholds_get(core, tz->module,
+ SFP_TEMP_HIGH_ALARM,
+ &emerg_temp);
+ if (err)
+ return err;
+ }
if (crit_temp > emerg_temp) {
dev_warn(dev, "%s : Critical threshold %d is above emergency threshold %d\n",
@@ -281,7 +286,7 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
dev_err(dev, "Failed to query temp sensor\n");
return err;
}
- mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
+ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL);
if (temp > 0)
mlxsw_thermal_tz_score_update(thermal, tzdev, thermal->trips,
temp);
@@ -420,36 +425,57 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
return err;
}
-static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev,
- int *p_temp)
+static void
+mlxsw_thermal_module_temp_and_thresholds_get(struct mlxsw_core *core,
+ u16 sensor_index, int *p_temp,
+ int *p_crit_temp,
+ int *p_emerg_temp)
{
- struct mlxsw_thermal_module *tz = tzdev->devdata;
- struct mlxsw_thermal *thermal = tz->parent;
- struct device *dev = thermal->bus_info->dev;
char mtmp_pl[MLXSW_REG_MTMP_LEN];
- int temp;
int err;
- /* Read module temperature. */
- 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);
+ /* Read module temperature and thresholds. */
+ mlxsw_reg_mtmp_pack(mtmp_pl, sensor_index, false, false);
+ err = mlxsw_reg_query(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.
+ /* Set temperature and thresholds to zero to avoid passing
+ * uninitialized data back to the caller.
*/
- temp = 0;
- *p_temp = (int) temp;
- return 0;
+ *p_temp = 0;
+ *p_crit_temp = 0;
+ *p_emerg_temp = 0;
+
+ return;
}
- mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
+ mlxsw_reg_mtmp_unpack(mtmp_pl, p_temp, NULL, p_crit_temp, p_emerg_temp,
+ NULL);
+}
+
+static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev,
+ int *p_temp)
+{
+ struct mlxsw_thermal_module *tz = tzdev->devdata;
+ struct mlxsw_thermal *thermal = tz->parent;
+ int temp, crit_temp, emerg_temp;
+ struct device *dev;
+ u16 sensor_index;
+ int err;
+
+ dev = thermal->bus_info->dev;
+ sensor_index = MLXSW_REG_MTMP_MODULE_INDEX_MIN + tz->module;
+
+ /* Read module temperature and thresholds. */
+ mlxsw_thermal_module_temp_and_thresholds_get(thermal->core,
+ sensor_index, &temp,
+ &crit_temp, &emerg_temp);
*p_temp = temp;
if (!temp)
return 0;
/* Update trip points. */
- err = mlxsw_thermal_module_trips_update(dev, thermal->core, tz);
+ err = mlxsw_thermal_module_trips_update(dev, thermal->core, tz,
+ crit_temp, emerg_temp);
if (!err && temp > 0)
mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
@@ -560,7 +586,7 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
if (err)
return err;
- mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
+ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL, NULL, NULL);
if (temp > 0)
mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp);
@@ -717,7 +743,10 @@ mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core,
struct mlxsw_thermal *thermal, u8 module)
{
struct mlxsw_thermal_module *module_tz;
+ int dummy_temp, crit_temp, emerg_temp;
+ u16 sensor_index;
+ sensor_index = MLXSW_REG_MTMP_MODULE_INDEX_MIN + module;
module_tz = &thermal->tz_module_arr[module];
/* Skip if parent is already set (case of port split). */
if (module_tz->parent)
@@ -728,8 +757,12 @@ mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core,
sizeof(thermal->trips));
/* Initialize all trip point. */
mlxsw_thermal_module_trips_reset(module_tz);
+ /* Read module temperature and thresholds. */
+ mlxsw_thermal_module_temp_and_thresholds_get(core, sensor_index, &dummy_temp,
+ &crit_temp, &emerg_temp);
/* Update trip point according to the module data. */
- return mlxsw_thermal_module_trips_update(dev, core, module_tz);
+ return mlxsw_thermal_module_trips_update(dev, core, module_tz,
+ crit_temp, emerg_temp);
}
static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/ib.h b/drivers/net/ethernet/mellanox/mlxsw/ib.h
deleted file mode 100644
index 2d0cb0f5eb85..000000000000
--- a/drivers/net/ethernet/mellanox/mlxsw/ib.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
-/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
-
-#ifndef _MLXSW_IB_H
-#define _MLXSW_IB_H
-
-#define MLXSW_IB_DEFAULT_MTU 4096
-
-#endif /* _MLXSW_IB_H */
diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c
index b34c44723f8b..d9d56c44e994 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c
@@ -112,10 +112,23 @@ mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee,
ee, data);
}
+static int
+mlxsw_m_get_module_eeprom_by_page(struct net_device *netdev,
+ const struct ethtool_module_eeprom *page,
+ struct netlink_ext_ack *extack)
+{
+ struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
+ struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
+
+ return mlxsw_env_get_module_eeprom_by_page(core, mlxsw_m_port->module,
+ page, extack);
+}
+
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,
+ .get_module_eeprom_by_page = mlxsw_m_get_module_eeprom_by_page,
};
static int
@@ -234,6 +247,7 @@ static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 local_port)
static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port,
u8 *last_module)
{
+ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core);
u8 module, width;
int err;
@@ -249,6 +263,9 @@ static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port,
if (module == *last_module)
return 0;
*last_module = module;
+
+ if (WARN_ON_ONCE(module >= max_ports))
+ return -EINVAL;
mlxsw_m->module_to_port[module] = ++mlxsw_m->max_ports;
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c
index 8e8456811384..13b0259f7ea6 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c
@@ -1426,11 +1426,6 @@ static int mlxsw_pci_sys_ready_wait(struct mlxsw_pci *mlxsw_pci,
unsigned long end;
u32 val;
- if (id->device == PCI_DEVICE_ID_MELLANOX_SWITCHX2) {
- msleep(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS);
- return 0;
- }
-
/* We must wait for the HW to become responsive. */
msleep(MLXSW_PCI_SW_RESET_WAIT_MSECS);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.h b/drivers/net/ethernet/mellanox/mlxsw/pci.h
index 5b1323645a5d..9899c1a2ea8f 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.h
@@ -6,12 +6,9 @@
#include <linux/pci.h>
-#define PCI_DEVICE_ID_MELLANOX_SWITCHX2 0xc738
#define PCI_DEVICE_ID_MELLANOX_SPECTRUM 0xcb84
#define PCI_DEVICE_ID_MELLANOX_SPECTRUM2 0xcf6c
#define PCI_DEVICE_ID_MELLANOX_SPECTRUM3 0xcf70
-#define PCI_DEVICE_ID_MELLANOX_SWITCHIB 0xcb20
-#define PCI_DEVICE_ID_MELLANOX_SWITCHIB2 0xcf08
#if IS_ENABLED(CONFIG_MLXSW_PCI)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h
index 2bc5a9003c6d..6fbda6ebd590 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -8305,6 +8305,8 @@ enum {
MLXSW_REG_RECR2_TCP_UDP_EN_IPV4 = 7,
/* Enable TCP/UDP header fields if packet is IPv6 */
MLXSW_REG_RECR2_TCP_UDP_EN_IPV6 = 8,
+
+ __MLXSW_REG_RECR2_HEADER_CNT,
};
/* reg_recr2_outer_header_enables
@@ -8339,6 +8341,8 @@ enum {
MLXSW_REG_RECR2_TCP_UDP_SPORT = 74,
/* TCP/UDP Destination Port */
MLXSW_REG_RECR2_TCP_UDP_DPORT = 75,
+
+ __MLXSW_REG_RECR2_FIELD_CNT,
};
/* reg_recr2_outer_header_fields_enable
@@ -8347,47 +8351,47 @@ enum {
*/
MLXSW_ITEM_BIT_ARRAY(reg, recr2, outer_header_fields_enable, 0x14, 0x14, 1);
-static inline void mlxsw_reg_recr2_ipv4_sip_enable(char *payload)
-{
- int i;
-
- for (i = MLXSW_REG_RECR2_IPV4_SIP0; i <= MLXSW_REG_RECR2_IPV4_SIP3; i++)
- mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i,
- true);
-}
-
-static inline void mlxsw_reg_recr2_ipv4_dip_enable(char *payload)
-{
- int i;
-
- for (i = MLXSW_REG_RECR2_IPV4_DIP0; i <= MLXSW_REG_RECR2_IPV4_DIP3; i++)
- mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i,
- true);
-}
-
-static inline void mlxsw_reg_recr2_ipv6_sip_enable(char *payload)
-{
- int i = MLXSW_REG_RECR2_IPV6_SIP0_7;
-
- mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i, true);
-
- i = MLXSW_REG_RECR2_IPV6_SIP8;
- for (; i <= MLXSW_REG_RECR2_IPV6_SIP15; i++)
- mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i,
- true);
-}
-
-static inline void mlxsw_reg_recr2_ipv6_dip_enable(char *payload)
-{
- int i = MLXSW_REG_RECR2_IPV6_DIP0_7;
-
- mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i, true);
+/* reg_recr2_inner_header_enables
+ * Bit mask where each bit enables a specific inner layer to be included in the
+ * hash calculation. Same values as reg_recr2_outer_header_enables.
+ * Access: RW
+ */
+MLXSW_ITEM_BIT_ARRAY(reg, recr2, inner_header_enables, 0x2C, 0x04, 1);
- i = MLXSW_REG_RECR2_IPV6_DIP8;
- for (; i <= MLXSW_REG_RECR2_IPV6_DIP15; i++)
- mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i,
- true);
-}
+enum {
+ /* Inner IPv4 Source IP */
+ MLXSW_REG_RECR2_INNER_IPV4_SIP0 = 3,
+ MLXSW_REG_RECR2_INNER_IPV4_SIP3 = 6,
+ /* Inner IPv4 Destination IP */
+ MLXSW_REG_RECR2_INNER_IPV4_DIP0 = 7,
+ MLXSW_REG_RECR2_INNER_IPV4_DIP3 = 10,
+ /* Inner IP Protocol */
+ MLXSW_REG_RECR2_INNER_IPV4_PROTOCOL = 11,
+ /* Inner IPv6 Source IP */
+ MLXSW_REG_RECR2_INNER_IPV6_SIP0_7 = 12,
+ MLXSW_REG_RECR2_INNER_IPV6_SIP8 = 20,
+ MLXSW_REG_RECR2_INNER_IPV6_SIP15 = 27,
+ /* Inner IPv6 Destination IP */
+ MLXSW_REG_RECR2_INNER_IPV6_DIP0_7 = 28,
+ MLXSW_REG_RECR2_INNER_IPV6_DIP8 = 36,
+ MLXSW_REG_RECR2_INNER_IPV6_DIP15 = 43,
+ /* Inner IPv6 Next Header */
+ MLXSW_REG_RECR2_INNER_IPV6_NEXT_HEADER = 44,
+ /* Inner IPv6 Flow Label */
+ MLXSW_REG_RECR2_INNER_IPV6_FLOW_LABEL = 45,
+ /* Inner TCP/UDP Source Port */
+ MLXSW_REG_RECR2_INNER_TCP_UDP_SPORT = 46,
+ /* Inner TCP/UDP Destination Port */
+ MLXSW_REG_RECR2_INNER_TCP_UDP_DPORT = 47,
+
+ __MLXSW_REG_RECR2_INNER_FIELD_CNT,
+};
+
+/* reg_recr2_inner_header_fields_enable
+ * Inner packet fields to enable for ECMP hash subject to inner_header_enables.
+ * Access: RW
+ */
+MLXSW_ITEM_BIT_ARRAY(reg, recr2, inner_header_fields_enable, 0x30, 0x08, 1);
static inline void mlxsw_reg_recr2_pack(char *payload, u32 seed)
{
@@ -9459,6 +9463,14 @@ MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 12);
((s16)((GENMASK(15, 0) + (v_) + 1) \
* 125)); })
+/* reg_mtmp_max_operational_temperature
+ * The highest temperature in the nominal operational range. Reading is in
+ * 0.125 Celsius degrees units.
+ * In case of module this is SFF critical temperature threshold.
+ * Access: RO
+ */
+MLXSW_ITEM32(reg, mtmp, max_operational_temperature, 0x04, 16, 16);
+
/* reg_mtmp_temperature
* Temperature reading from the sensor. Reading is in 0.125 Celsius
* degrees units.
@@ -9537,7 +9549,9 @@ static inline void mlxsw_reg_mtmp_pack(char *payload, u16 sensor_index,
}
static inline void mlxsw_reg_mtmp_unpack(char *payload, int *p_temp,
- int *p_max_temp, char *sensor_name)
+ int *p_max_temp, int *p_temp_hi,
+ int *p_max_oper_temp,
+ char *sensor_name)
{
s16 temp;
@@ -9549,6 +9563,14 @@ static inline void mlxsw_reg_mtmp_unpack(char *payload, int *p_temp,
temp = mlxsw_reg_mtmp_max_temperature_get(payload);
*p_max_temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp);
}
+ if (p_temp_hi) {
+ temp = mlxsw_reg_mtmp_temperature_threshold_hi_get(payload);
+ *p_temp_hi = MLXSW_REG_MTMP_TEMP_TO_MC(temp);
+ }
+ if (p_max_oper_temp) {
+ temp = mlxsw_reg_mtmp_max_operational_temperature_get(payload);
+ *p_max_oper_temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp);
+ }
if (sensor_name)
mlxsw_reg_mtmp_sensor_name_memcpy_from(payload, sensor_name);
}
@@ -9668,6 +9690,20 @@ MLXSW_ITEM32(reg, mcia, l, 0x00, 31, 1);
*/
MLXSW_ITEM32(reg, mcia, module, 0x00, 16, 8);
+enum {
+ MLXSW_REG_MCIA_STATUS_GOOD = 0,
+ /* No response from module's EEPROM. */
+ MLXSW_REG_MCIA_STATUS_NO_EEPROM_MODULE = 1,
+ /* Module type not supported by the device. */
+ MLXSW_REG_MCIA_STATUS_MODULE_NOT_SUPPORTED = 2,
+ /* No module present indication. */
+ MLXSW_REG_MCIA_STATUS_MODULE_NOT_CONNECTED = 3,
+ /* Error occurred while trying to access module's EEPROM using I2C. */
+ MLXSW_REG_MCIA_STATUS_I2C_ERROR = 9,
+ /* Module is disabled. */
+ MLXSW_REG_MCIA_STATUS_MODULE_DISABLED = 16,
+};
+
/* reg_mcia_status
* Module status.
* Access: RO
@@ -9692,6 +9728,12 @@ MLXSW_ITEM32(reg, mcia, page_number, 0x04, 16, 8);
*/
MLXSW_ITEM32(reg, mcia, device_address, 0x04, 0, 16);
+/* reg_mcia_bank_number
+ * Bank number.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, mcia, bank_number, 0x08, 16, 8);
+
/* reg_mcia_size
* Number of bytes to read/write (up to 48 bytes).
* Access: RW
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index bca0354482cb..88699e678544 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -2125,9 +2125,14 @@ static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
struct mlxsw_sp *mlxsw_sp = priv;
struct mlxsw_sp_port *mlxsw_sp_port;
enum mlxsw_reg_pude_oper_status status;
+ unsigned int max_ports;
u8 local_port;
+ max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
local_port = mlxsw_reg_pude_local_port_get(pude_pl);
+
+ if (WARN_ON_ONCE(local_port >= max_ports))
+ return;
mlxsw_sp_port = mlxsw_sp->ports[local_port];
if (!mlxsw_sp_port)
return;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
index 37ff29a1686e..9de160e740b2 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
@@ -364,7 +364,7 @@ static u16 mlxsw_sp_hdroom_buf_delay_get(const struct mlxsw_sp *mlxsw_sp,
static u32 mlxsw_sp_hdroom_int_buf_size_get(struct mlxsw_sp *mlxsw_sp, int mtu, u32 speed)
{
- u32 buffsize = mlxsw_sp->sb_ops->int_buf_size_get(speed, mtu);
+ u32 buffsize = mlxsw_sp->sb_ops->int_buf_size_get(mtu, speed);
return mlxsw_sp_bytes_cells(mlxsw_sp, buffsize) + 1;
}
@@ -388,8 +388,8 @@ void mlxsw_sp_hdroom_bufs_reset_sizes(struct mlxsw_sp_port *mlxsw_sp_port,
int i;
/* Internal buffer. */
- reserve_cells = mlxsw_sp_hdroom_int_buf_size_get(mlxsw_sp, mlxsw_sp_port->max_speed,
- mlxsw_sp_port->max_mtu);
+ reserve_cells = mlxsw_sp_hdroom_int_buf_size_get(mlxsw_sp, mlxsw_sp_port->max_mtu,
+ mlxsw_sp_port->max_speed);
reserve_cells = mlxsw_sp_port_headroom_8x_adjust(mlxsw_sp_port, reserve_cells);
hdroom->int_buf.reserve_cells = reserve_cells;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c
index c8061beed6db..267590a0eee7 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c
@@ -1051,6 +1051,19 @@ static int mlxsw_sp_get_module_eeprom(struct net_device *netdev,
}
static int
+mlxsw_sp_get_module_eeprom_by_page(struct net_device *dev,
+ const struct ethtool_module_eeprom *page,
+ struct netlink_ext_ack *extack)
+{
+ struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ u8 module = mlxsw_sp_port->mapping.module;
+
+ return mlxsw_env_get_module_eeprom_by_page(mlxsw_sp->core, module, page,
+ extack);
+}
+
+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);
@@ -1199,6 +1212,7 @@ const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
.set_link_ksettings = mlxsw_sp_port_set_link_ksettings,
.get_module_info = mlxsw_sp_get_module_info,
.get_module_eeprom = mlxsw_sp_get_module_eeprom,
+ .get_module_eeprom_by_page = mlxsw_sp_get_module_eeprom_by_page,
.get_ts_info = mlxsw_sp_get_ts_info,
.get_eth_phy_stats = mlxsw_sp_get_eth_phy_stats,
.get_eth_mac_stats = mlxsw_sp_get_eth_mac_stats,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
index d6e9ecb14681..bfef65d1587c 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
@@ -568,10 +568,13 @@ void mlxsw_sp1_ptp_got_timestamp(struct mlxsw_sp *mlxsw_sp, bool ingress,
u8 domain_number, u16 sequence_id,
u64 timestamp)
{
+ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
struct mlxsw_sp_port *mlxsw_sp_port;
struct mlxsw_sp1_ptp_key key;
u8 types;
+ if (WARN_ON_ONCE(local_port >= max_ports))
+ return;
mlxsw_sp_port = mlxsw_sp->ports[local_port];
if (!mlxsw_sp_port)
return;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 41259c0004d1..7e221ef01437 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -2282,6 +2282,7 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
char *rauhtd_pl,
int ent_index)
{
+ u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
struct net_device *dev;
struct neighbour *n;
__be32 dipn;
@@ -2290,6 +2291,8 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
mlxsw_reg_rauhtd_ent_ipv4_unpack(rauhtd_pl, ent_index, &rif, &dip);
+ if (WARN_ON_ONCE(rif >= max_rifs))
+ return;
if (!mlxsw_sp->router->rifs[rif]) {
dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n");
return;
@@ -3841,8 +3844,8 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
bool offload_change = false;
u32 adj_index;
bool old_adj_index_valid;
- int i, err2, err = 0;
u32 old_adj_index;
+ int i, err2, err;
if (!nhgi->gateway)
return mlxsw_sp_nexthop_fib_entries_update(mlxsw_sp, nh_grp);
@@ -3872,11 +3875,13 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
return 0;
}
mlxsw_sp_nexthop_group_normalize(nhgi);
- if (!nhgi->sum_norm_weight)
+ if (!nhgi->sum_norm_weight) {
/* No neigh of this group is connected so we just set
* the trap and let everthing flow through kernel.
*/
+ err = 0;
goto set_trap;
+ }
ecmp_size = nhgi->sum_norm_weight;
err = mlxsw_sp_fix_adj_grp_size(mlxsw_sp, &ecmp_size);
@@ -4307,9 +4312,6 @@ static void mlxsw_sp_nexthop4_event(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_nexthop_key key;
struct mlxsw_sp_nexthop *nh;
- if (mlxsw_sp->router->aborted)
- return;
-
key.fib_nh = fib_nh;
nh = mlxsw_sp_nexthop_lookup(mlxsw_sp, key);
if (!nh)
@@ -5405,7 +5407,6 @@ mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group *nh_grp,
ipv6_addr_equal((const struct in6_addr *) &nh->gw_addr,
&rt->fib6_nh->fib_nh_gw6))
return nh;
- continue;
}
return NULL;
@@ -6417,9 +6418,6 @@ mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_node *fib_node;
int err;
- if (mlxsw_sp->router->aborted)
- return 0;
-
if (fen_info->fi->nh &&
!mlxsw_sp_nexthop_obj_group_lookup(mlxsw_sp, fen_info->fi->nh->id))
return 0;
@@ -6480,9 +6478,6 @@ static int mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_node *fib_node;
int err;
- if (mlxsw_sp->router->aborted)
- return 0;
-
fib4_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info);
if (!fib4_entry)
return 0;
@@ -7065,9 +7060,6 @@ static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp,
struct fib6_info *rt = rt_arr[0];
int err;
- if (mlxsw_sp->router->aborted)
- return 0;
-
if (rt->fib6_src.plen)
return -EINVAL;
@@ -7131,9 +7123,6 @@ static int mlxsw_sp_router_fib6_append(struct mlxsw_sp *mlxsw_sp,
struct fib6_info *rt = rt_arr[0];
int err;
- if (mlxsw_sp->router->aborted)
- return 0;
-
if (rt->fib6_src.plen)
return -EINVAL;
@@ -7175,9 +7164,6 @@ static int mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp,
struct fib6_info *rt = rt_arr[0];
int err;
- if (mlxsw_sp->router->aborted)
- return 0;
-
if (mlxsw_sp_fib6_rt_should_ignore(rt))
return 0;
@@ -7206,55 +7192,6 @@ static int mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp,
return err;
}
-static int __mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp,
- enum mlxsw_sp_l3proto proto,
- u8 tree_id)
-{
- const struct mlxsw_sp_router_ll_ops *ll_ops = mlxsw_sp->router->proto_ll_ops[proto];
- enum mlxsw_reg_ralxx_protocol ralxx_proto =
- (enum mlxsw_reg_ralxx_protocol) proto;
- struct mlxsw_sp_fib_entry_priv *priv;
- char xralta_pl[MLXSW_REG_XRALTA_LEN];
- char xralst_pl[MLXSW_REG_XRALST_LEN];
- int i, err;
-
- mlxsw_reg_xralta_pack(xralta_pl, true, ralxx_proto, tree_id);
- err = ll_ops->ralta_write(mlxsw_sp, xralta_pl);
- if (err)
- return err;
-
- mlxsw_reg_xralst_pack(xralst_pl, 0xff, tree_id);
- err = ll_ops->ralst_write(mlxsw_sp, xralst_pl);
- if (err)
- return err;
-
- for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
- struct mlxsw_sp_fib_entry_op_ctx *op_ctx = mlxsw_sp->router->ll_op_ctx;
- struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
- char xraltb_pl[MLXSW_REG_XRALTB_LEN];
-
- mlxsw_sp_fib_entry_op_ctx_clear(op_ctx);
- mlxsw_reg_xraltb_pack(xraltb_pl, vr->id, ralxx_proto, tree_id);
- err = ll_ops->raltb_write(mlxsw_sp, xraltb_pl);
- if (err)
- return err;
-
- priv = mlxsw_sp_fib_entry_priv_create(ll_ops);
- if (IS_ERR(priv))
- return PTR_ERR(priv);
-
- ll_ops->fib_entry_pack(op_ctx, proto, MLXSW_SP_FIB_ENTRY_OP_WRITE,
- vr->id, 0, NULL, priv);
- ll_ops->fib_entry_act_ip2me_pack(op_ctx);
- err = ll_ops->fib_entry_commit(mlxsw_sp, op_ctx, NULL);
- mlxsw_sp_fib_entry_priv_put(priv);
- if (err)
- return err;
- }
-
- return 0;
-}
-
static struct mlxsw_sp_mr_table *
mlxsw_sp_router_fibmr_family_to_table(struct mlxsw_sp_vr *vr, int family)
{
@@ -7271,9 +7208,6 @@ static int mlxsw_sp_router_fibmr_add(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_mr_table *mrt;
struct mlxsw_sp_vr *vr;
- if (mlxsw_sp->router->aborted)
- return 0;
-
vr = mlxsw_sp_vr_get(mlxsw_sp, men_info->tb_id, NULL);
if (IS_ERR(vr))
return PTR_ERR(vr);
@@ -7288,9 +7222,6 @@ static void mlxsw_sp_router_fibmr_del(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_mr_table *mrt;
struct mlxsw_sp_vr *vr;
- if (mlxsw_sp->router->aborted)
- return;
-
vr = mlxsw_sp_vr_find(mlxsw_sp, men_info->tb_id);
if (WARN_ON(!vr))
return;
@@ -7308,9 +7239,6 @@ mlxsw_sp_router_fibmr_vif_add(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *rif;
struct mlxsw_sp_vr *vr;
- if (mlxsw_sp->router->aborted)
- return 0;
-
vr = mlxsw_sp_vr_get(mlxsw_sp, ven_info->tb_id, NULL);
if (IS_ERR(vr))
return PTR_ERR(vr);
@@ -7329,9 +7257,6 @@ mlxsw_sp_router_fibmr_vif_del(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_mr_table *mrt;
struct mlxsw_sp_vr *vr;
- if (mlxsw_sp->router->aborted)
- return;
-
vr = mlxsw_sp_vr_find(mlxsw_sp, ven_info->tb_id);
if (WARN_ON(!vr))
return;
@@ -7341,25 +7266,6 @@ mlxsw_sp_router_fibmr_vif_del(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_vr_put(mlxsw_sp, vr);
}
-static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp)
-{
- enum mlxsw_sp_l3proto proto = MLXSW_SP_L3_PROTO_IPV4;
- int err;
-
- err = __mlxsw_sp_router_set_abort_trap(mlxsw_sp, proto,
- MLXSW_SP_LPM_TREE_MIN);
- if (err)
- return err;
-
- /* The multicast router code does not need an abort trap as by default,
- * packets that don't match any routes are trapped to the CPU.
- */
-
- proto = MLXSW_SP_L3_PROTO_IPV6;
- return __mlxsw_sp_router_set_abort_trap(mlxsw_sp, proto,
- MLXSW_SP_LPM_TREE_MIN + 1);
-}
-
static void mlxsw_sp_fib4_node_flush(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_node *fib_node)
{
@@ -7446,20 +7352,6 @@ static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp)
mlxsw_sp->router->adj_discard_index_valid = false;
}
-static void mlxsw_sp_router_fib_abort(struct mlxsw_sp *mlxsw_sp)
-{
- int err;
-
- if (mlxsw_sp->router->aborted)
- return;
- dev_warn(mlxsw_sp->bus_info->dev, "FIB abort triggered. Note that FIB entries are no longer being offloaded to this device.\n");
- mlxsw_sp_router_fib_flush(mlxsw_sp);
- mlxsw_sp->router->aborted = true;
- err = mlxsw_sp_router_set_abort_trap(mlxsw_sp);
- if (err)
- dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n");
-}
-
struct mlxsw_sp_fib6_event {
struct fib6_info **rt_arr;
unsigned int nrt6;
@@ -7541,7 +7433,7 @@ static void mlxsw_sp_router_fib4_event_process(struct mlxsw_sp *mlxsw_sp,
err = mlxsw_sp_router_fib4_replace(mlxsw_sp, op_ctx, &fib_event->fen_info);
if (err) {
mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
- mlxsw_sp_router_fib_abort(mlxsw_sp);
+ dev_warn(mlxsw_sp->bus_info->dev, "FIB replace failed.\n");
mlxsw_sp_fib4_offload_failed_flag_set(mlxsw_sp,
&fib_event->fen_info);
}
@@ -7576,7 +7468,7 @@ static void mlxsw_sp_router_fib6_event_process(struct mlxsw_sp *mlxsw_sp,
fib_event->fib6_event.nrt6);
if (err) {
mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
- mlxsw_sp_router_fib_abort(mlxsw_sp);
+ dev_warn(mlxsw_sp->bus_info->dev, "FIB replace failed.\n");
mlxsw_sp_fib6_offload_failed_flag_set(mlxsw_sp,
fib6_event->rt_arr,
fib6_event->nrt6);
@@ -7588,7 +7480,7 @@ static void mlxsw_sp_router_fib6_event_process(struct mlxsw_sp *mlxsw_sp,
fib_event->fib6_event.nrt6);
if (err) {
mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
- mlxsw_sp_router_fib_abort(mlxsw_sp);
+ dev_warn(mlxsw_sp->bus_info->dev, "FIB append failed.\n");
mlxsw_sp_fib6_offload_failed_flag_set(mlxsw_sp,
fib6_event->rt_arr,
fib6_event->nrt6);
@@ -7620,7 +7512,7 @@ static void mlxsw_sp_router_fibmr_event_process(struct mlxsw_sp *mlxsw_sp,
err = mlxsw_sp_router_fibmr_add(mlxsw_sp, &fib_event->men_info, replace);
if (err)
- mlxsw_sp_router_fib_abort(mlxsw_sp);
+ dev_warn(mlxsw_sp->bus_info->dev, "MR entry add failed.\n");
mr_cache_put(fib_event->men_info.mfc);
break;
case FIB_EVENT_ENTRY_DEL:
@@ -7631,7 +7523,7 @@ static void mlxsw_sp_router_fibmr_event_process(struct mlxsw_sp *mlxsw_sp,
err = mlxsw_sp_router_fibmr_vif_add(mlxsw_sp,
&fib_event->ven_info);
if (err)
- mlxsw_sp_router_fib_abort(mlxsw_sp);
+ dev_warn(mlxsw_sp->bus_info->dev, "MR VIF add failed.\n");
dev_put(fib_event->ven_info.dev);
break;
case FIB_EVENT_VIF_DEL:
@@ -7795,9 +7687,6 @@ static int mlxsw_sp_router_fib_rule_event(unsigned long event,
if (event == FIB_EVENT_RULE_DEL)
return 0;
- if (mlxsw_sp->router->aborted)
- return 0;
-
fr_info = container_of(info, struct fib_rule_notifier_info, info);
rule = fr_info->rule;
@@ -7855,10 +7744,6 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
case FIB_EVENT_ENTRY_ADD:
case FIB_EVENT_ENTRY_REPLACE:
case FIB_EVENT_ENTRY_APPEND:
- if (router->aborted) {
- NL_SET_ERR_MSG_MOD(info->extack, "FIB offload was aborted. Not configuring route");
- return notifier_from_errno(-EINVAL);
- }
if (info->family == AF_INET) {
struct fib_entry_notifier_info *fen_info = ptr;
@@ -9594,66 +9479,229 @@ static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb)
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH
-static void mlxsw_sp_mp_hash_header_set(char *recr2_pl, int header)
+struct mlxsw_sp_mp_hash_config {
+ DECLARE_BITMAP(headers, __MLXSW_REG_RECR2_HEADER_CNT);
+ DECLARE_BITMAP(fields, __MLXSW_REG_RECR2_FIELD_CNT);
+ DECLARE_BITMAP(inner_headers, __MLXSW_REG_RECR2_HEADER_CNT);
+ DECLARE_BITMAP(inner_fields, __MLXSW_REG_RECR2_INNER_FIELD_CNT);
+};
+
+#define MLXSW_SP_MP_HASH_HEADER_SET(_headers, _header) \
+ bitmap_set(_headers, MLXSW_REG_RECR2_##_header, 1)
+
+#define MLXSW_SP_MP_HASH_FIELD_SET(_fields, _field) \
+ bitmap_set(_fields, MLXSW_REG_RECR2_##_field, 1)
+
+#define MLXSW_SP_MP_HASH_FIELD_RANGE_SET(_fields, _field, _nr) \
+ bitmap_set(_fields, MLXSW_REG_RECR2_##_field, _nr)
+
+static void mlxsw_sp_mp_hash_inner_l3(struct mlxsw_sp_mp_hash_config *config)
{
- mlxsw_reg_recr2_outer_header_enables_set(recr2_pl, header, true);
+ unsigned long *inner_headers = config->inner_headers;
+ unsigned long *inner_fields = config->inner_fields;
+
+ /* IPv4 inner */
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV4_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV4_EN_TCP_UDP);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV4_SIP0, 4);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV4_DIP0, 4);
+ /* IPv6 inner */
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV6_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV6_EN_TCP_UDP);
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_SIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV6_SIP8, 8);
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_DIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV6_DIP8, 8);
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_NEXT_HEADER);
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_FLOW_LABEL);
}
-static void mlxsw_sp_mp_hash_field_set(char *recr2_pl, int field)
+static void mlxsw_sp_mp4_hash_outer_addr(struct mlxsw_sp_mp_hash_config *config)
{
- mlxsw_reg_recr2_outer_header_fields_enable_set(recr2_pl, field, true);
+ unsigned long *headers = config->headers;
+ unsigned long *fields = config->fields;
+
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_TCP_UDP);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_SIP0, 4);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_DIP0, 4);
}
-static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp, char *recr2_pl)
+static void
+mlxsw_sp_mp_hash_inner_custom(struct mlxsw_sp_mp_hash_config *config,
+ u32 hash_fields)
+{
+ unsigned long *inner_headers = config->inner_headers;
+ unsigned long *inner_fields = config->inner_fields;
+
+ /* IPv4 Inner */
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV4_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV4_EN_TCP_UDP);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_IP)
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV4_SIP0, 4);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_IP)
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV4_DIP0, 4);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_IP_PROTO)
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV4_PROTOCOL);
+ /* IPv6 inner */
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV6_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, IPV6_EN_TCP_UDP);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_IP) {
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_SIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV6_SIP8, 8);
+ }
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_IP) {
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_DIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(inner_fields, INNER_IPV6_DIP8, 8);
+ }
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_IP_PROTO)
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_NEXT_HEADER);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_FLOWLABEL)
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_IPV6_FLOW_LABEL);
+ /* L4 inner */
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, TCP_UDP_EN_IPV4);
+ MLXSW_SP_MP_HASH_HEADER_SET(inner_headers, TCP_UDP_EN_IPV6);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_SRC_PORT)
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_TCP_UDP_SPORT);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_INNER_DST_PORT)
+ MLXSW_SP_MP_HASH_FIELD_SET(inner_fields, INNER_TCP_UDP_DPORT);
+}
+
+static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_mp_hash_config *config)
{
struct net *net = mlxsw_sp_net(mlxsw_sp);
- bool only_l3 = !net->ipv4.sysctl_fib_multipath_hash_policy;
-
- mlxsw_sp_mp_hash_header_set(recr2_pl,
- MLXSW_REG_RECR2_IPV4_EN_NOT_TCP_NOT_UDP);
- mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV4_EN_TCP_UDP);
- mlxsw_reg_recr2_ipv4_sip_enable(recr2_pl);
- mlxsw_reg_recr2_ipv4_dip_enable(recr2_pl);
- if (only_l3)
- return;
- mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_EN_IPV4);
- mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_IPV4_PROTOCOL);
- mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_SPORT);
- mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_DPORT);
+ unsigned long *headers = config->headers;
+ unsigned long *fields = config->fields;
+ u32 hash_fields;
+
+ switch (net->ipv4.sysctl_fib_multipath_hash_policy) {
+ case 0:
+ mlxsw_sp_mp4_hash_outer_addr(config);
+ break;
+ case 1:
+ mlxsw_sp_mp4_hash_outer_addr(config);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, TCP_UDP_EN_IPV4);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV4_PROTOCOL);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_SPORT);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_DPORT);
+ break;
+ case 2:
+ /* Outer */
+ mlxsw_sp_mp4_hash_outer_addr(config);
+ /* Inner */
+ mlxsw_sp_mp_hash_inner_l3(config);
+ break;
+ case 3:
+ hash_fields = net->ipv4.sysctl_fib_multipath_hash_fields;
+ /* Outer */
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_TCP_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, TCP_UDP_EN_IPV4);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_IP)
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_SIP0, 4);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_IP)
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV4_DIP0, 4);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_IP_PROTO)
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV4_PROTOCOL);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_PORT)
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_SPORT);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_PORT)
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_DPORT);
+ /* Inner */
+ mlxsw_sp_mp_hash_inner_custom(config, hash_fields);
+ break;
+ }
}
-static void mlxsw_sp_mp6_hash_init(struct mlxsw_sp *mlxsw_sp, char *recr2_pl)
+static void mlxsw_sp_mp6_hash_outer_addr(struct mlxsw_sp_mp_hash_config *config)
{
- bool only_l3 = !ip6_multipath_hash_policy(mlxsw_sp_net(mlxsw_sp));
+ unsigned long *headers = config->headers;
+ unsigned long *fields = config->fields;
- mlxsw_sp_mp_hash_header_set(recr2_pl,
- MLXSW_REG_RECR2_IPV6_EN_NOT_TCP_NOT_UDP);
- mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV6_EN_TCP_UDP);
- mlxsw_reg_recr2_ipv6_sip_enable(recr2_pl);
- mlxsw_reg_recr2_ipv6_dip_enable(recr2_pl);
- mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_IPV6_NEXT_HEADER);
- if (only_l3) {
- mlxsw_sp_mp_hash_field_set(recr2_pl,
- MLXSW_REG_RECR2_IPV6_FLOW_LABEL);
- } else {
- mlxsw_sp_mp_hash_header_set(recr2_pl,
- MLXSW_REG_RECR2_TCP_UDP_EN_IPV6);
- mlxsw_sp_mp_hash_field_set(recr2_pl,
- MLXSW_REG_RECR2_TCP_UDP_SPORT);
- mlxsw_sp_mp_hash_field_set(recr2_pl,
- MLXSW_REG_RECR2_TCP_UDP_DPORT);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_TCP_UDP);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_SIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_SIP8, 8);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_DIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_DIP8, 8);
+}
+
+static void mlxsw_sp_mp6_hash_init(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_mp_hash_config *config)
+{
+ u32 hash_fields = ip6_multipath_hash_fields(mlxsw_sp_net(mlxsw_sp));
+ unsigned long *headers = config->headers;
+ unsigned long *fields = config->fields;
+
+ switch (ip6_multipath_hash_policy(mlxsw_sp_net(mlxsw_sp))) {
+ case 0:
+ mlxsw_sp_mp6_hash_outer_addr(config);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_NEXT_HEADER);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_FLOW_LABEL);
+ break;
+ case 1:
+ mlxsw_sp_mp6_hash_outer_addr(config);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, TCP_UDP_EN_IPV6);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_NEXT_HEADER);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_SPORT);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_DPORT);
+ break;
+ case 2:
+ /* Outer */
+ mlxsw_sp_mp6_hash_outer_addr(config);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_NEXT_HEADER);
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_FLOW_LABEL);
+ /* Inner */
+ mlxsw_sp_mp_hash_inner_l3(config);
+ break;
+ case 3:
+ /* Outer */
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_NOT_TCP_NOT_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV6_EN_TCP_UDP);
+ MLXSW_SP_MP_HASH_HEADER_SET(headers, TCP_UDP_EN_IPV6);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_IP) {
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_SIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_SIP8, 8);
+ }
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_IP) {
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_DIP0_7);
+ MLXSW_SP_MP_HASH_FIELD_RANGE_SET(fields, IPV6_DIP8, 8);
+ }
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_IP_PROTO)
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_NEXT_HEADER);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_FLOWLABEL)
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, IPV6_FLOW_LABEL);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_SRC_PORT)
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_SPORT);
+ if (hash_fields & FIB_MULTIPATH_HASH_FIELD_DST_PORT)
+ MLXSW_SP_MP_HASH_FIELD_SET(fields, TCP_UDP_DPORT);
+ /* Inner */
+ mlxsw_sp_mp_hash_inner_custom(config, hash_fields);
+ break;
}
}
static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp)
{
+ struct mlxsw_sp_mp_hash_config config = {};
char recr2_pl[MLXSW_REG_RECR2_LEN];
+ unsigned long bit;
u32 seed;
seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 0);
mlxsw_reg_recr2_pack(recr2_pl, seed);
- mlxsw_sp_mp4_hash_init(mlxsw_sp, recr2_pl);
- mlxsw_sp_mp6_hash_init(mlxsw_sp, recr2_pl);
+ mlxsw_sp_mp4_hash_init(mlxsw_sp, &config);
+ mlxsw_sp_mp6_hash_init(mlxsw_sp, &config);
+
+ for_each_set_bit(bit, config.headers, __MLXSW_REG_RECR2_HEADER_CNT)
+ mlxsw_reg_recr2_outer_header_enables_set(recr2_pl, bit, 1);
+ for_each_set_bit(bit, config.fields, __MLXSW_REG_RECR2_FIELD_CNT)
+ mlxsw_reg_recr2_outer_header_fields_enable_set(recr2_pl, bit, 1);
+ for_each_set_bit(bit, config.inner_headers, __MLXSW_REG_RECR2_HEADER_CNT)
+ mlxsw_reg_recr2_inner_header_enables_set(recr2_pl, bit, 1);
+ for_each_set_bit(bit, config.inner_fields, __MLXSW_REG_RECR2_INNER_FIELD_CNT)
+ mlxsw_reg_recr2_inner_header_fields_enable_set(recr2_pl, bit, 1);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(recr2), recr2_pl);
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h
index be7708a375e1..c5d7007f9173 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h
@@ -58,7 +58,6 @@ struct mlxsw_sp_router {
#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */
struct list_head nexthop_neighs_list;
struct list_head ipip_list;
- bool aborted;
struct notifier_block nexthop_nb;
struct notifier_block fib_nb;
struct notifier_block netevent_nb;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index eeccd586e781..c5ef9aa64efe 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -898,7 +898,7 @@ mlxsw_sp_port_attr_br_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port,
return 0;
}
-static int mlxsw_sp_port_attr_set(struct net_device *dev,
+static int mlxsw_sp_port_attr_set(struct net_device *dev, const void *ctx,
const struct switchdev_attr *attr,
struct netlink_ext_ack *extack)
{
@@ -1766,7 +1766,7 @@ mlxsw_sp_port_mrouter_update_mdb(struct mlxsw_sp_port *mlxsw_sp_port,
}
}
-static int mlxsw_sp_port_obj_add(struct net_device *dev,
+static int mlxsw_sp_port_obj_add(struct net_device *dev, const void *ctx,
const struct switchdev_obj *obj,
struct netlink_ext_ack *extack)
{
@@ -1916,7 +1916,7 @@ mlxsw_sp_bridge_port_mdb_flush(struct mlxsw_sp_port *mlxsw_sp_port,
}
}
-static int mlxsw_sp_port_obj_del(struct net_device *dev,
+static int mlxsw_sp_port_obj_del(struct net_device *dev, const void *ctx,
const struct switchdev_obj *obj)
{
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
@@ -2520,6 +2520,7 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
char *sfn_pl, int rec_index,
bool adding)
{
+ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
struct mlxsw_sp_bridge_device *bridge_device;
struct mlxsw_sp_bridge_port *bridge_port;
@@ -2532,6 +2533,9 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
int err;
mlxsw_reg_sfn_mac_unpack(sfn_pl, rec_index, mac, &fid, &local_port);
+
+ if (WARN_ON_ONCE(local_port >= max_ports))
+ return;
mlxsw_sp_port = mlxsw_sp->ports[local_port];
if (!mlxsw_sp_port) {
dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect local port in FDB notification\n");
diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchib.c b/drivers/net/ethernet/mellanox/mlxsw/switchib.c
deleted file mode 100644
index 1e561132eb1e..000000000000
--- a/drivers/net/ethernet/mellanox/mlxsw/switchib.c
+++ /dev/null
@@ -1,595 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
-/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/skbuff.h>
-#include <linux/if_vlan.h>
-#include <net/switchdev.h>
-
-#include "pci.h"
-#include "core.h"
-#include "reg.h"
-#include "port.h"
-#include "trap.h"
-#include "txheader.h"
-#include "ib.h"
-
-static const char mlxsw_sib_driver_name[] = "mlxsw_switchib";
-static const char mlxsw_sib2_driver_name[] = "mlxsw_switchib2";
-
-struct mlxsw_sib_port;
-
-struct mlxsw_sib {
- struct mlxsw_sib_port **ports;
- struct mlxsw_core *core;
- const struct mlxsw_bus_info *bus_info;
- u8 hw_id[ETH_ALEN];
-};
-
-struct mlxsw_sib_port {
- struct mlxsw_sib *mlxsw_sib;
- u8 local_port;
- struct {
- u8 module;
- } mapping;
-};
-
-/* tx_v1_hdr_version
- * Tx header version.
- * Must be set to 1.
- */
-MLXSW_ITEM32(tx_v1, hdr, version, 0x00, 28, 4);
-
-/* tx_v1_hdr_ctl
- * Packet control type.
- * 0 - Ethernet control (e.g. EMADs, LACP)
- * 1 - Ethernet data
- */
-MLXSW_ITEM32(tx_v1, hdr, ctl, 0x00, 26, 2);
-
-/* tx_v1_hdr_proto
- * Packet protocol type. Must be set to 1 (Ethernet).
- */
-MLXSW_ITEM32(tx_v1, hdr, proto, 0x00, 21, 3);
-
-/* tx_v1_hdr_swid
- * Switch partition ID. Must be set to 0.
- */
-MLXSW_ITEM32(tx_v1, hdr, swid, 0x00, 12, 3);
-
-/* tx_v1_hdr_control_tclass
- * Indicates if the packet should use the control TClass and not one
- * of the data TClasses.
- */
-MLXSW_ITEM32(tx_v1, hdr, control_tclass, 0x00, 6, 1);
-
-/* tx_v1_hdr_port_mid
- * Destination local port for unicast packets.
- * Destination multicast ID for multicast packets.
- *
- * Control packets are directed to a specific egress port, while data
- * packets are transmitted through the CPU port (0) into the switch partition,
- * where forwarding rules are applied.
- */
-MLXSW_ITEM32(tx_v1, hdr, port_mid, 0x04, 16, 16);
-
-/* tx_v1_hdr_type
- * 0 - Data packets
- * 6 - Control packets
- */
-MLXSW_ITEM32(tx_v1, hdr, type, 0x0C, 0, 4);
-
-static void
-mlxsw_sib_tx_v1_hdr_construct(struct sk_buff *skb,
- const struct mlxsw_tx_info *tx_info)
-{
- char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN);
-
- memset(txhdr, 0, MLXSW_TXHDR_LEN);
-
- mlxsw_tx_v1_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_1);
- mlxsw_tx_v1_hdr_ctl_set(txhdr, MLXSW_TXHDR_ETH_CTL);
- mlxsw_tx_v1_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH);
- mlxsw_tx_v1_hdr_swid_set(txhdr, 0);
- mlxsw_tx_v1_hdr_control_tclass_set(txhdr, 1);
- mlxsw_tx_v1_hdr_port_mid_set(txhdr, tx_info->local_port);
- mlxsw_tx_v1_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL);
-}
-
-static int mlxsw_sib_hw_id_get(struct mlxsw_sib *mlxsw_sib)
-{
- char spad_pl[MLXSW_REG_SPAD_LEN] = {0};
- int err;
-
- err = mlxsw_reg_query(mlxsw_sib->core, MLXSW_REG(spad), spad_pl);
- if (err)
- return err;
- mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_sib->hw_id);
- return 0;
-}
-
-static int
-mlxsw_sib_port_admin_status_set(struct mlxsw_sib_port *mlxsw_sib_port,
- bool is_up)
-{
- struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
- char paos_pl[MLXSW_REG_PAOS_LEN];
-
- mlxsw_reg_paos_pack(paos_pl, mlxsw_sib_port->local_port,
- is_up ? MLXSW_PORT_ADMIN_STATUS_UP :
- MLXSW_PORT_ADMIN_STATUS_DOWN);
- return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(paos), paos_pl);
-}
-
-static int mlxsw_sib_port_mtu_set(struct mlxsw_sib_port *mlxsw_sib_port,
- u16 mtu)
-{
- struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
- char pmtu_pl[MLXSW_REG_PMTU_LEN];
- int max_mtu;
- int err;
-
- mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sib_port->local_port, 0);
- err = mlxsw_reg_query(mlxsw_sib->core, MLXSW_REG(pmtu), pmtu_pl);
- if (err)
- return err;
- max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl);
-
- if (mtu > max_mtu)
- return -EINVAL;
-
- mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sib_port->local_port, mtu);
- return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(pmtu), pmtu_pl);
-}
-
-static int mlxsw_sib_port_set(struct mlxsw_sib_port *mlxsw_sib_port, u8 port)
-{
- struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
- char plib_pl[MLXSW_REG_PLIB_LEN] = {0};
- int err;
-
- mlxsw_reg_plib_local_port_set(plib_pl, mlxsw_sib_port->local_port);
- mlxsw_reg_plib_ib_port_set(plib_pl, port);
- err = mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(plib), plib_pl);
- return err;
-}
-
-static int mlxsw_sib_port_swid_set(struct mlxsw_sib_port *mlxsw_sib_port,
- u8 swid)
-{
- struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
- char pspa_pl[MLXSW_REG_PSPA_LEN];
-
- mlxsw_reg_pspa_pack(pspa_pl, swid, mlxsw_sib_port->local_port);
- return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(pspa), pspa_pl);
-}
-
-static int mlxsw_sib_port_module_info_get(struct mlxsw_sib *mlxsw_sib,
- u8 local_port, u8 *p_module,
- u8 *p_width)
-{
- char pmlp_pl[MLXSW_REG_PMLP_LEN];
- int err;
-
- mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
- err = mlxsw_reg_query(mlxsw_sib->core, MLXSW_REG(pmlp), pmlp_pl);
- if (err)
- return err;
- *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
- *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl);
- return 0;
-}
-
-static int mlxsw_sib_port_speed_set(struct mlxsw_sib_port *mlxsw_sib_port,
- u16 speed, u16 width)
-{
- struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
- char ptys_pl[MLXSW_REG_PTYS_LEN];
-
- mlxsw_reg_ptys_ib_pack(ptys_pl, mlxsw_sib_port->local_port, speed,
- width);
- return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(ptys), ptys_pl);
-}
-
-static bool mlxsw_sib_port_created(struct mlxsw_sib *mlxsw_sib, u8 local_port)
-{
- return mlxsw_sib->ports[local_port] != NULL;
-}
-
-static int __mlxsw_sib_port_create(struct mlxsw_sib *mlxsw_sib, u8 local_port,
- u8 module, u8 width)
-{
- struct mlxsw_sib_port *mlxsw_sib_port;
- int err;
-
- mlxsw_sib_port = kzalloc(sizeof(*mlxsw_sib_port), GFP_KERNEL);
- if (!mlxsw_sib_port)
- return -ENOMEM;
- mlxsw_sib_port->mlxsw_sib = mlxsw_sib;
- mlxsw_sib_port->local_port = local_port;
- mlxsw_sib_port->mapping.module = module;
-
- err = mlxsw_sib_port_swid_set(mlxsw_sib_port, 0);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set SWID\n",
- mlxsw_sib_port->local_port);
- goto err_port_swid_set;
- }
-
- /* Expose the IB port number as it's front panel name */
- err = mlxsw_sib_port_set(mlxsw_sib_port, module + 1);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set IB port\n",
- mlxsw_sib_port->local_port);
- goto err_port_ib_set;
- }
-
- /* Supports all speeds from SDR to FDR (bitmask) and support bus width
- * of 1x, 2x and 4x (3 bits bitmask)
- */
- err = mlxsw_sib_port_speed_set(mlxsw_sib_port,
- MLXSW_REG_PTYS_IB_SPEED_EDR - 1,
- BIT(3) - 1);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set speed\n",
- mlxsw_sib_port->local_port);
- goto err_port_speed_set;
- }
-
- /* Change to the maximum MTU the device supports, the SMA will take
- * care of the active MTU
- */
- err = mlxsw_sib_port_mtu_set(mlxsw_sib_port, MLXSW_IB_DEFAULT_MTU);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set MTU\n",
- mlxsw_sib_port->local_port);
- goto err_port_mtu_set;
- }
-
- err = mlxsw_sib_port_admin_status_set(mlxsw_sib_port, true);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to change admin state to UP\n",
- mlxsw_sib_port->local_port);
- goto err_port_admin_set;
- }
-
- mlxsw_core_port_ib_set(mlxsw_sib->core, mlxsw_sib_port->local_port,
- mlxsw_sib_port);
- mlxsw_sib->ports[local_port] = mlxsw_sib_port;
- return 0;
-
-err_port_admin_set:
-err_port_mtu_set:
-err_port_speed_set:
-err_port_ib_set:
- mlxsw_sib_port_swid_set(mlxsw_sib_port, MLXSW_PORT_SWID_DISABLED_PORT);
-err_port_swid_set:
- kfree(mlxsw_sib_port);
- return err;
-}
-
-static int mlxsw_sib_port_create(struct mlxsw_sib *mlxsw_sib, u8 local_port,
- u8 module, u8 width)
-{
- int err;
-
- err = mlxsw_core_port_init(mlxsw_sib->core, local_port,
- module + 1, false, 0, false, 0,
- mlxsw_sib->hw_id, sizeof(mlxsw_sib->hw_id));
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to init core port\n",
- local_port);
- return err;
- }
- err = __mlxsw_sib_port_create(mlxsw_sib, local_port, module, width);
- if (err)
- goto err_port_create;
-
- return 0;
-
-err_port_create:
- mlxsw_core_port_fini(mlxsw_sib->core, local_port);
- return err;
-}
-
-static void __mlxsw_sib_port_remove(struct mlxsw_sib *mlxsw_sib, u8 local_port)
-{
- struct mlxsw_sib_port *mlxsw_sib_port = mlxsw_sib->ports[local_port];
-
- mlxsw_core_port_clear(mlxsw_sib->core, local_port, mlxsw_sib);
- mlxsw_sib->ports[local_port] = NULL;
- mlxsw_sib_port_admin_status_set(mlxsw_sib_port, false);
- mlxsw_sib_port_swid_set(mlxsw_sib_port, MLXSW_PORT_SWID_DISABLED_PORT);
- kfree(mlxsw_sib_port);
-}
-
-static void mlxsw_sib_port_remove(struct mlxsw_sib *mlxsw_sib, u8 local_port)
-{
- __mlxsw_sib_port_remove(mlxsw_sib, local_port);
- mlxsw_core_port_fini(mlxsw_sib->core, local_port);
-}
-
-static void mlxsw_sib_ports_remove(struct mlxsw_sib *mlxsw_sib)
-{
- int i;
-
- for (i = 1; i < MLXSW_PORT_MAX_IB_PORTS; i++)
- if (mlxsw_sib_port_created(mlxsw_sib, i))
- mlxsw_sib_port_remove(mlxsw_sib, i);
- kfree(mlxsw_sib->ports);
-}
-
-static int mlxsw_sib_ports_create(struct mlxsw_sib *mlxsw_sib)
-{
- size_t alloc_size;
- u8 module, width;
- int i;
- int err;
-
- alloc_size = sizeof(struct mlxsw_sib_port *) * MLXSW_PORT_MAX_IB_PORTS;
- mlxsw_sib->ports = kzalloc(alloc_size, GFP_KERNEL);
- if (!mlxsw_sib->ports)
- return -ENOMEM;
-
- for (i = 1; i < MLXSW_PORT_MAX_IB_PORTS; i++) {
- err = mlxsw_sib_port_module_info_get(mlxsw_sib, i, &module,
- &width);
- if (err)
- goto err_port_module_info_get;
- if (!width)
- continue;
- err = mlxsw_sib_port_create(mlxsw_sib, i, module, width);
- if (err)
- goto err_port_create;
- }
- return 0;
-
-err_port_create:
-err_port_module_info_get:
- for (i--; i >= 1; i--)
- if (mlxsw_sib_port_created(mlxsw_sib, i))
- mlxsw_sib_port_remove(mlxsw_sib, i);
- kfree(mlxsw_sib->ports);
- return err;
-}
-
-static void
-mlxsw_sib_pude_ib_event_func(struct mlxsw_sib_port *mlxsw_sib_port,
- enum mlxsw_reg_pude_oper_status status)
-{
- if (status == MLXSW_PORT_OPER_STATUS_UP)
- pr_info("ib link for port %d - up\n",
- mlxsw_sib_port->mapping.module + 1);
- else
- pr_info("ib link for port %d - down\n",
- mlxsw_sib_port->mapping.module + 1);
-}
-
-static void mlxsw_sib_pude_event_func(const struct mlxsw_reg_info *reg,
- char *pude_pl, void *priv)
-{
- struct mlxsw_sib *mlxsw_sib = priv;
- struct mlxsw_sib_port *mlxsw_sib_port;
- enum mlxsw_reg_pude_oper_status status;
- u8 local_port;
-
- local_port = mlxsw_reg_pude_local_port_get(pude_pl);
- mlxsw_sib_port = mlxsw_sib->ports[local_port];
- if (!mlxsw_sib_port) {
- dev_warn(mlxsw_sib->bus_info->dev, "Port %d: Link event received for non-existent port\n",
- local_port);
- return;
- }
-
- status = mlxsw_reg_pude_oper_status_get(pude_pl);
- mlxsw_sib_pude_ib_event_func(mlxsw_sib_port, status);
-}
-
-static const struct mlxsw_listener mlxsw_sib_listener[] = {
- MLXSW_EVENTL(mlxsw_sib_pude_event_func, PUDE, EMAD),
-};
-
-static int mlxsw_sib_taps_init(struct mlxsw_sib *mlxsw_sib)
-{
- int i;
- int err;
-
- for (i = 0; i < ARRAY_SIZE(mlxsw_sib_listener); i++) {
- err = mlxsw_core_trap_register(mlxsw_sib->core,
- &mlxsw_sib_listener[i],
- mlxsw_sib);
- if (err)
- goto err_rx_listener_register;
- }
-
- return 0;
-
-err_rx_listener_register:
- for (i--; i >= 0; i--) {
- mlxsw_core_trap_unregister(mlxsw_sib->core,
- &mlxsw_sib_listener[i],
- mlxsw_sib);
- }
-
- return err;
-}
-
-static void mlxsw_sib_traps_fini(struct mlxsw_sib *mlxsw_sib)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mlxsw_sib_listener); i++) {
- mlxsw_core_trap_unregister(mlxsw_sib->core,
- &mlxsw_sib_listener[i], mlxsw_sib);
- }
-}
-
-static int mlxsw_sib_basic_trap_groups_set(struct mlxsw_core *mlxsw_core)
-{
- char htgt_pl[MLXSW_REG_HTGT_LEN];
-
- mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_EMAD,
- MLXSW_REG_HTGT_INVALID_POLICER,
- MLXSW_REG_HTGT_DEFAULT_PRIORITY,
- MLXSW_REG_HTGT_DEFAULT_TC);
- mlxsw_reg_htgt_swid_set(htgt_pl, MLXSW_PORT_SWID_ALL_SWIDS);
- mlxsw_reg_htgt_local_path_rdq_set(htgt_pl,
- MLXSW_REG_HTGT_LOCAL_PATH_RDQ_SIB_EMAD);
- return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
-}
-
-static int mlxsw_sib_init(struct mlxsw_core *mlxsw_core,
- const struct mlxsw_bus_info *mlxsw_bus_info,
- struct netlink_ext_ack *extack)
-{
- struct mlxsw_sib *mlxsw_sib = mlxsw_core_driver_priv(mlxsw_core);
- int err;
-
- mlxsw_sib->core = mlxsw_core;
- mlxsw_sib->bus_info = mlxsw_bus_info;
-
- err = mlxsw_sib_hw_id_get(mlxsw_sib);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Failed to get switch HW ID\n");
- return err;
- }
-
- err = mlxsw_sib_ports_create(mlxsw_sib);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Failed to create ports\n");
- return err;
- }
-
- err = mlxsw_sib_taps_init(mlxsw_sib);
- if (err) {
- dev_err(mlxsw_sib->bus_info->dev, "Failed to set traps\n");
- goto err_traps_init_err;
- }
-
- return 0;
-
-err_traps_init_err:
- mlxsw_sib_ports_remove(mlxsw_sib);
- return err;
-}
-
-static void mlxsw_sib_fini(struct mlxsw_core *mlxsw_core)
-{
- struct mlxsw_sib *mlxsw_sib = mlxsw_core_driver_priv(mlxsw_core);
-
- mlxsw_sib_traps_fini(mlxsw_sib);
- mlxsw_sib_ports_remove(mlxsw_sib);
-}
-
-static const struct mlxsw_config_profile mlxsw_sib_config_profile = {
- .used_max_system_port = 1,
- .max_system_port = 48000,
- .used_max_ib_mc = 1,
- .max_ib_mc = 27,
- .used_max_pkey = 1,
- .max_pkey = 32,
- .swid_config = {
- {
- .used_type = 1,
- .type = MLXSW_PORT_SWID_TYPE_IB,
- }
- },
-};
-
-static struct mlxsw_driver mlxsw_sib_driver = {
- .kind = mlxsw_sib_driver_name,
- .priv_size = sizeof(struct mlxsw_sib),
- .init = mlxsw_sib_init,
- .fini = mlxsw_sib_fini,
- .basic_trap_groups_set = mlxsw_sib_basic_trap_groups_set,
- .txhdr_construct = mlxsw_sib_tx_v1_hdr_construct,
- .txhdr_len = MLXSW_TXHDR_LEN,
- .profile = &mlxsw_sib_config_profile,
-};
-
-static struct mlxsw_driver mlxsw_sib2_driver = {
- .kind = mlxsw_sib2_driver_name,
- .priv_size = sizeof(struct mlxsw_sib),
- .init = mlxsw_sib_init,
- .fini = mlxsw_sib_fini,
- .basic_trap_groups_set = mlxsw_sib_basic_trap_groups_set,
- .txhdr_construct = mlxsw_sib_tx_v1_hdr_construct,
- .txhdr_len = MLXSW_TXHDR_LEN,
- .profile = &mlxsw_sib_config_profile,
-};
-
-static const struct pci_device_id mlxsw_sib_pci_id_table[] = {
- {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SWITCHIB), 0},
- {0, },
-};
-
-static struct pci_driver mlxsw_sib_pci_driver = {
- .name = mlxsw_sib_driver_name,
- .id_table = mlxsw_sib_pci_id_table,
-};
-
-static const struct pci_device_id mlxsw_sib2_pci_id_table[] = {
- {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SWITCHIB2), 0},
- {0, },
-};
-
-static struct pci_driver mlxsw_sib2_pci_driver = {
- .name = mlxsw_sib2_driver_name,
- .id_table = mlxsw_sib2_pci_id_table,
-};
-
-static int __init mlxsw_sib_module_init(void)
-{
- int err;
-
- err = mlxsw_core_driver_register(&mlxsw_sib_driver);
- if (err)
- return err;
-
- err = mlxsw_core_driver_register(&mlxsw_sib2_driver);
- if (err)
- goto err_sib2_driver_register;
-
- err = mlxsw_pci_driver_register(&mlxsw_sib_pci_driver);
- if (err)
- goto err_sib_pci_driver_register;
-
- err = mlxsw_pci_driver_register(&mlxsw_sib2_pci_driver);
- if (err)
- goto err_sib2_pci_driver_register;
-
- return 0;
-
-err_sib2_pci_driver_register:
- mlxsw_pci_driver_unregister(&mlxsw_sib_pci_driver);
-err_sib_pci_driver_register:
- mlxsw_core_driver_unregister(&mlxsw_sib2_driver);
-err_sib2_driver_register:
- mlxsw_core_driver_unregister(&mlxsw_sib_driver);
- return err;
-}
-
-static void __exit mlxsw_sib_module_exit(void)
-{
- mlxsw_pci_driver_unregister(&mlxsw_sib2_pci_driver);
- mlxsw_pci_driver_unregister(&mlxsw_sib_pci_driver);
- mlxsw_core_driver_unregister(&mlxsw_sib2_driver);
- mlxsw_core_driver_unregister(&mlxsw_sib_driver);
-}
-
-module_init(mlxsw_sib_module_init);
-module_exit(mlxsw_sib_module_exit);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Elad Raz <eladr@@mellanox.com>");
-MODULE_DESCRIPTION("Mellanox SwitchIB and SwitchIB-2 driver");
-MODULE_ALIAS("mlxsw_switchib2");
-MODULE_DEVICE_TABLE(pci, mlxsw_sib_pci_id_table);
-MODULE_DEVICE_TABLE(pci, mlxsw_sib2_pci_id_table);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
deleted file mode 100644
index 131b2a53d261..000000000000
--- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
+++ /dev/null
@@ -1,1691 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
-/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/skbuff.h>
-#include <linux/if_vlan.h>
-
-#include "pci.h"
-#include "core.h"
-#include "reg.h"
-#include "port.h"
-#include "trap.h"
-#include "txheader.h"
-#include "ib.h"
-
-static const char mlxsw_sx_driver_name[] = "mlxsw_switchx2";
-static const char mlxsw_sx_driver_version[] = "1.0";
-
-struct mlxsw_sx_port;
-
-struct mlxsw_sx {
- struct mlxsw_sx_port **ports;
- struct mlxsw_core *core;
- const struct mlxsw_bus_info *bus_info;
- u8 hw_id[ETH_ALEN];
-};
-
-struct mlxsw_sx_port_pcpu_stats {
- u64 rx_packets;
- u64 rx_bytes;
- u64 tx_packets;
- u64 tx_bytes;
- struct u64_stats_sync syncp;
- u32 tx_dropped;
-};
-
-struct mlxsw_sx_port {
- struct net_device *dev;
- struct mlxsw_sx_port_pcpu_stats __percpu *pcpu_stats;
- struct mlxsw_sx *mlxsw_sx;
- u8 local_port;
- struct {
- u8 module;
- } mapping;
-};
-
-/* tx_hdr_version
- * Tx header version.
- * Must be set to 0.
- */
-MLXSW_ITEM32(tx, hdr, version, 0x00, 28, 4);
-
-/* tx_hdr_ctl
- * Packet control type.
- * 0 - Ethernet control (e.g. EMADs, LACP)
- * 1 - Ethernet data
- */
-MLXSW_ITEM32(tx, hdr, ctl, 0x00, 26, 2);
-
-/* tx_hdr_proto
- * Packet protocol type. Must be set to 1 (Ethernet).
- */
-MLXSW_ITEM32(tx, hdr, proto, 0x00, 21, 3);
-
-/* tx_hdr_etclass
- * Egress TClass to be used on the egress device on the egress port.
- * The MSB is specified in the 'ctclass3' field.
- * Range is 0-15, where 15 is the highest priority.
- */
-MLXSW_ITEM32(tx, hdr, etclass, 0x00, 18, 3);
-
-/* tx_hdr_swid
- * Switch partition ID.
- */
-MLXSW_ITEM32(tx, hdr, swid, 0x00, 12, 3);
-
-/* tx_hdr_port_mid
- * Destination local port for unicast packets.
- * Destination multicast ID for multicast packets.
- *
- * Control packets are directed to a specific egress port, while data
- * packets are transmitted through the CPU port (0) into the switch partition,
- * where forwarding rules are applied.
- */
-MLXSW_ITEM32(tx, hdr, port_mid, 0x04, 16, 16);
-
-/* tx_hdr_ctclass3
- * See field 'etclass'.
- */
-MLXSW_ITEM32(tx, hdr, ctclass3, 0x04, 14, 1);
-
-/* tx_hdr_rdq
- * RDQ for control packets sent to remote CPU.
- * Must be set to 0x1F for EMADs, otherwise 0.
- */
-MLXSW_ITEM32(tx, hdr, rdq, 0x04, 9, 5);
-
-/* tx_hdr_cpu_sig
- * Signature control for packets going to CPU. Must be set to 0.
- */
-MLXSW_ITEM32(tx, hdr, cpu_sig, 0x04, 0, 9);
-
-/* tx_hdr_sig
- * Stacking protocl signature. Must be set to 0xE0E0.
- */
-MLXSW_ITEM32(tx, hdr, sig, 0x0C, 16, 16);
-
-/* tx_hdr_stclass
- * Stacking TClass.
- */
-MLXSW_ITEM32(tx, hdr, stclass, 0x0C, 13, 3);
-
-/* tx_hdr_emad
- * EMAD bit. Must be set for EMADs.
- */
-MLXSW_ITEM32(tx, hdr, emad, 0x0C, 5, 1);
-
-/* tx_hdr_type
- * 0 - Data packets
- * 6 - Control packets
- */
-MLXSW_ITEM32(tx, hdr, type, 0x0C, 0, 4);
-
-static void mlxsw_sx_txhdr_construct(struct sk_buff *skb,
- const struct mlxsw_tx_info *tx_info)
-{
- char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN);
- bool is_emad = tx_info->is_emad;
-
- memset(txhdr, 0, MLXSW_TXHDR_LEN);
-
- /* We currently set default values for the egress tclass (QoS). */
- mlxsw_tx_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_0);
- mlxsw_tx_hdr_ctl_set(txhdr, MLXSW_TXHDR_ETH_CTL);
- mlxsw_tx_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH);
- mlxsw_tx_hdr_etclass_set(txhdr, is_emad ? MLXSW_TXHDR_ETCLASS_6 :
- MLXSW_TXHDR_ETCLASS_5);
- mlxsw_tx_hdr_swid_set(txhdr, 0);
- mlxsw_tx_hdr_port_mid_set(txhdr, tx_info->local_port);
- mlxsw_tx_hdr_ctclass3_set(txhdr, MLXSW_TXHDR_CTCLASS3);
- mlxsw_tx_hdr_rdq_set(txhdr, is_emad ? MLXSW_TXHDR_RDQ_EMAD :
- MLXSW_TXHDR_RDQ_OTHER);
- mlxsw_tx_hdr_cpu_sig_set(txhdr, MLXSW_TXHDR_CPU_SIG);
- mlxsw_tx_hdr_sig_set(txhdr, MLXSW_TXHDR_SIG);
- mlxsw_tx_hdr_stclass_set(txhdr, MLXSW_TXHDR_STCLASS_NONE);
- mlxsw_tx_hdr_emad_set(txhdr, is_emad ? MLXSW_TXHDR_EMAD :
- MLXSW_TXHDR_NOT_EMAD);
- mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL);
-}
-
-static int mlxsw_sx_port_admin_status_set(struct mlxsw_sx_port *mlxsw_sx_port,
- bool is_up)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char paos_pl[MLXSW_REG_PAOS_LEN];
-
- mlxsw_reg_paos_pack(paos_pl, mlxsw_sx_port->local_port,
- is_up ? MLXSW_PORT_ADMIN_STATUS_UP :
- MLXSW_PORT_ADMIN_STATUS_DOWN);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(paos), paos_pl);
-}
-
-static int mlxsw_sx_port_oper_status_get(struct mlxsw_sx_port *mlxsw_sx_port,
- bool *p_is_up)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char paos_pl[MLXSW_REG_PAOS_LEN];
- u8 oper_status;
- int err;
-
- mlxsw_reg_paos_pack(paos_pl, mlxsw_sx_port->local_port, 0);
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(paos), paos_pl);
- if (err)
- return err;
- oper_status = mlxsw_reg_paos_oper_status_get(paos_pl);
- *p_is_up = oper_status == MLXSW_PORT_ADMIN_STATUS_UP;
- return 0;
-}
-
-static int __mlxsw_sx_port_mtu_set(struct mlxsw_sx_port *mlxsw_sx_port,
- u16 mtu)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char pmtu_pl[MLXSW_REG_PMTU_LEN];
- int max_mtu;
- int err;
-
- mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sx_port->local_port, 0);
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(pmtu), pmtu_pl);
- if (err)
- return err;
- max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl);
-
- if (mtu > max_mtu)
- return -EINVAL;
-
- mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sx_port->local_port, mtu);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(pmtu), pmtu_pl);
-}
-
-static int mlxsw_sx_port_mtu_eth_set(struct mlxsw_sx_port *mlxsw_sx_port,
- u16 mtu)
-{
- mtu += MLXSW_TXHDR_LEN + ETH_HLEN;
- return __mlxsw_sx_port_mtu_set(mlxsw_sx_port, mtu);
-}
-
-static int mlxsw_sx_port_mtu_ib_set(struct mlxsw_sx_port *mlxsw_sx_port,
- u16 mtu)
-{
- return __mlxsw_sx_port_mtu_set(mlxsw_sx_port, mtu);
-}
-
-static int mlxsw_sx_port_ib_port_set(struct mlxsw_sx_port *mlxsw_sx_port,
- u8 ib_port)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char plib_pl[MLXSW_REG_PLIB_LEN] = {0};
- int err;
-
- mlxsw_reg_plib_local_port_set(plib_pl, mlxsw_sx_port->local_port);
- mlxsw_reg_plib_ib_port_set(plib_pl, ib_port);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(plib), plib_pl);
- return err;
-}
-
-static int mlxsw_sx_port_swid_set(struct mlxsw_sx_port *mlxsw_sx_port, u8 swid)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char pspa_pl[MLXSW_REG_PSPA_LEN];
-
- mlxsw_reg_pspa_pack(pspa_pl, swid, mlxsw_sx_port->local_port);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(pspa), pspa_pl);
-}
-
-static int
-mlxsw_sx_port_system_port_mapping_set(struct mlxsw_sx_port *mlxsw_sx_port)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char sspr_pl[MLXSW_REG_SSPR_LEN];
-
- mlxsw_reg_sspr_pack(sspr_pl, mlxsw_sx_port->local_port);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sspr), sspr_pl);
-}
-
-static int mlxsw_sx_port_module_info_get(struct mlxsw_sx *mlxsw_sx,
- u8 local_port, u8 *p_module,
- u8 *p_width)
-{
- char pmlp_pl[MLXSW_REG_PMLP_LEN];
- int err;
-
- mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(pmlp), pmlp_pl);
- if (err)
- return err;
- *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
- *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl);
- return 0;
-}
-
-static int mlxsw_sx_port_open(struct net_device *dev)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- int err;
-
- err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, true);
- if (err)
- return err;
- netif_start_queue(dev);
- return 0;
-}
-
-static int mlxsw_sx_port_stop(struct net_device *dev)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
-
- netif_stop_queue(dev);
- return mlxsw_sx_port_admin_status_set(mlxsw_sx_port, false);
-}
-
-static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- struct mlxsw_sx_port_pcpu_stats *pcpu_stats;
- const struct mlxsw_tx_info tx_info = {
- .local_port = mlxsw_sx_port->local_port,
- .is_emad = false,
- };
- u64 len;
- int err;
-
- if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {
- this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped);
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
- }
-
- memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb));
-
- if (mlxsw_core_skb_transmit_busy(mlxsw_sx->core, &tx_info))
- return NETDEV_TX_BUSY;
-
- mlxsw_sx_txhdr_construct(skb, &tx_info);
- /* TX header is consumed by HW on the way so we shouldn't count its
- * bytes as being sent.
- */
- len = skb->len - MLXSW_TXHDR_LEN;
- /* Due to a race we might fail here because of a full queue. In that
- * unlikely case we simply drop the packet.
- */
- err = mlxsw_core_skb_transmit(mlxsw_sx->core, skb, &tx_info);
-
- if (!err) {
- pcpu_stats = this_cpu_ptr(mlxsw_sx_port->pcpu_stats);
- u64_stats_update_begin(&pcpu_stats->syncp);
- pcpu_stats->tx_packets++;
- pcpu_stats->tx_bytes += len;
- u64_stats_update_end(&pcpu_stats->syncp);
- } else {
- this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped);
- dev_kfree_skb_any(skb);
- }
- return NETDEV_TX_OK;
-}
-
-static int mlxsw_sx_port_change_mtu(struct net_device *dev, int mtu)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- int err;
-
- err = mlxsw_sx_port_mtu_eth_set(mlxsw_sx_port, mtu);
- if (err)
- return err;
- dev->mtu = mtu;
- return 0;
-}
-
-static void
-mlxsw_sx_port_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *stats)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- struct mlxsw_sx_port_pcpu_stats *p;
- u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
- u32 tx_dropped = 0;
- unsigned int start;
- int i;
-
- for_each_possible_cpu(i) {
- p = per_cpu_ptr(mlxsw_sx_port->pcpu_stats, i);
- do {
- start = u64_stats_fetch_begin_irq(&p->syncp);
- rx_packets = p->rx_packets;
- rx_bytes = p->rx_bytes;
- tx_packets = p->tx_packets;
- tx_bytes = p->tx_bytes;
- } while (u64_stats_fetch_retry_irq(&p->syncp, start));
-
- stats->rx_packets += rx_packets;
- stats->rx_bytes += rx_bytes;
- stats->tx_packets += tx_packets;
- stats->tx_bytes += tx_bytes;
- /* tx_dropped is u32, updated without syncp protection. */
- tx_dropped += p->tx_dropped;
- }
- stats->tx_dropped = tx_dropped;
-}
-
-static struct devlink_port *
-mlxsw_sx_port_get_devlink_port(struct net_device *dev)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
-
- return mlxsw_core_port_devlink_port_get(mlxsw_sx->core,
- mlxsw_sx_port->local_port);
-}
-
-static const struct net_device_ops mlxsw_sx_port_netdev_ops = {
- .ndo_open = mlxsw_sx_port_open,
- .ndo_stop = mlxsw_sx_port_stop,
- .ndo_start_xmit = mlxsw_sx_port_xmit,
- .ndo_change_mtu = mlxsw_sx_port_change_mtu,
- .ndo_get_stats64 = mlxsw_sx_port_get_stats64,
- .ndo_get_devlink_port = mlxsw_sx_port_get_devlink_port,
-};
-
-static void mlxsw_sx_port_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *drvinfo)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
-
- strlcpy(drvinfo->driver, mlxsw_sx_driver_name, sizeof(drvinfo->driver));
- strlcpy(drvinfo->version, mlxsw_sx_driver_version,
- sizeof(drvinfo->version));
- snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
- "%d.%d.%d",
- mlxsw_sx->bus_info->fw_rev.major,
- mlxsw_sx->bus_info->fw_rev.minor,
- mlxsw_sx->bus_info->fw_rev.subminor);
- strlcpy(drvinfo->bus_info, mlxsw_sx->bus_info->device_name,
- sizeof(drvinfo->bus_info));
-}
-
-struct mlxsw_sx_port_hw_stats {
- char str[ETH_GSTRING_LEN];
- u64 (*getter)(const char *payload);
-};
-
-static const struct mlxsw_sx_port_hw_stats mlxsw_sx_port_hw_stats[] = {
- {
- .str = "a_frames_transmitted_ok",
- .getter = mlxsw_reg_ppcnt_a_frames_transmitted_ok_get,
- },
- {
- .str = "a_frames_received_ok",
- .getter = mlxsw_reg_ppcnt_a_frames_received_ok_get,
- },
- {
- .str = "a_frame_check_sequence_errors",
- .getter = mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get,
- },
- {
- .str = "a_alignment_errors",
- .getter = mlxsw_reg_ppcnt_a_alignment_errors_get,
- },
- {
- .str = "a_octets_transmitted_ok",
- .getter = mlxsw_reg_ppcnt_a_octets_transmitted_ok_get,
- },
- {
- .str = "a_octets_received_ok",
- .getter = mlxsw_reg_ppcnt_a_octets_received_ok_get,
- },
- {
- .str = "a_multicast_frames_xmitted_ok",
- .getter = mlxsw_reg_ppcnt_a_multicast_frames_xmitted_ok_get,
- },
- {
- .str = "a_broadcast_frames_xmitted_ok",
- .getter = mlxsw_reg_ppcnt_a_broadcast_frames_xmitted_ok_get,
- },
- {
- .str = "a_multicast_frames_received_ok",
- .getter = mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get,
- },
- {
- .str = "a_broadcast_frames_received_ok",
- .getter = mlxsw_reg_ppcnt_a_broadcast_frames_received_ok_get,
- },
- {
- .str = "a_in_range_length_errors",
- .getter = mlxsw_reg_ppcnt_a_in_range_length_errors_get,
- },
- {
- .str = "a_out_of_range_length_field",
- .getter = mlxsw_reg_ppcnt_a_out_of_range_length_field_get,
- },
- {
- .str = "a_frame_too_long_errors",
- .getter = mlxsw_reg_ppcnt_a_frame_too_long_errors_get,
- },
- {
- .str = "a_symbol_error_during_carrier",
- .getter = mlxsw_reg_ppcnt_a_symbol_error_during_carrier_get,
- },
- {
- .str = "a_mac_control_frames_transmitted",
- .getter = mlxsw_reg_ppcnt_a_mac_control_frames_transmitted_get,
- },
- {
- .str = "a_mac_control_frames_received",
- .getter = mlxsw_reg_ppcnt_a_mac_control_frames_received_get,
- },
- {
- .str = "a_unsupported_opcodes_received",
- .getter = mlxsw_reg_ppcnt_a_unsupported_opcodes_received_get,
- },
- {
- .str = "a_pause_mac_ctrl_frames_received",
- .getter = mlxsw_reg_ppcnt_a_pause_mac_ctrl_frames_received_get,
- },
- {
- .str = "a_pause_mac_ctrl_frames_xmitted",
- .getter = mlxsw_reg_ppcnt_a_pause_mac_ctrl_frames_transmitted_get,
- },
-};
-
-#define MLXSW_SX_PORT_HW_STATS_LEN ARRAY_SIZE(mlxsw_sx_port_hw_stats)
-
-static void mlxsw_sx_port_get_strings(struct net_device *dev,
- u32 stringset, u8 *data)
-{
- u8 *p = data;
- int i;
-
- switch (stringset) {
- case ETH_SS_STATS:
- for (i = 0; i < MLXSW_SX_PORT_HW_STATS_LEN; i++) {
- memcpy(p, mlxsw_sx_port_hw_stats[i].str,
- ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
- break;
- }
-}
-
-static void mlxsw_sx_port_get_stats(struct net_device *dev,
- struct ethtool_stats *stats, u64 *data)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
- int i;
- int err;
-
- mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sx_port->local_port,
- MLXSW_REG_PPCNT_IEEE_8023_CNT, 0);
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(ppcnt), ppcnt_pl);
- for (i = 0; i < MLXSW_SX_PORT_HW_STATS_LEN; i++)
- data[i] = !err ? mlxsw_sx_port_hw_stats[i].getter(ppcnt_pl) : 0;
-}
-
-static int mlxsw_sx_port_get_sset_count(struct net_device *dev, int sset)
-{
- switch (sset) {
- case ETH_SS_STATS:
- return MLXSW_SX_PORT_HW_STATS_LEN;
- default:
- return -EOPNOTSUPP;
- }
-}
-
-struct mlxsw_sx_port_link_mode {
- u32 mask;
- u32 supported;
- u32 advertised;
- u32 speed;
-};
-
-static const struct mlxsw_sx_port_link_mode mlxsw_sx_port_link_mode[] = {
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_SGMII |
- MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX,
- .supported = SUPPORTED_1000baseKX_Full,
- .advertised = ADVERTISED_1000baseKX_Full,
- .speed = 1000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CX4 |
- MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4,
- .supported = SUPPORTED_10000baseKX4_Full,
- .advertised = ADVERTISED_10000baseKX4_Full,
- .speed = 10000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |
- MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |
- MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |
- MLXSW_REG_PTYS_ETH_SPEED_10GBASE_ER_LR,
- .supported = SUPPORTED_10000baseKR_Full,
- .advertised = ADVERTISED_10000baseKR_Full,
- .speed = 10000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4,
- .supported = SUPPORTED_40000baseCR4_Full,
- .advertised = ADVERTISED_40000baseCR4_Full,
- .speed = 40000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4,
- .supported = SUPPORTED_40000baseKR4_Full,
- .advertised = ADVERTISED_40000baseKR4_Full,
- .speed = 40000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4,
- .supported = SUPPORTED_40000baseSR4_Full,
- .advertised = ADVERTISED_40000baseSR4_Full,
- .speed = 40000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_LR4_ER4,
- .supported = SUPPORTED_40000baseLR4_Full,
- .advertised = ADVERTISED_40000baseLR4_Full,
- .speed = 40000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR |
- MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR |
- MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR,
- .speed = 25000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR4 |
- MLXSW_REG_PTYS_ETH_SPEED_50GBASE_CR2 |
- MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR2,
- .speed = 50000,
- },
- {
- .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4,
- .speed = 100000,
- },
-};
-
-#define MLXSW_SX_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sx_port_link_mode)
-#define MLXSW_SX_PORT_BASE_SPEED 10000 /* Mb/s */
-
-static u32 mlxsw_sx_from_ptys_supported_port(u32 ptys_eth_proto)
-{
- if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |
- MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |
- MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 |
- MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 |
- MLXSW_REG_PTYS_ETH_SPEED_SGMII))
- return SUPPORTED_FIBRE;
-
- if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |
- MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 |
- MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 |
- MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX))
- return SUPPORTED_Backplane;
- return 0;
-}
-
-static u32 mlxsw_sx_from_ptys_supported_link(u32 ptys_eth_proto)
-{
- u32 modes = 0;
- int i;
-
- for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) {
- if (ptys_eth_proto & mlxsw_sx_port_link_mode[i].mask)
- modes |= mlxsw_sx_port_link_mode[i].supported;
- }
- return modes;
-}
-
-static u32 mlxsw_sx_from_ptys_advert_link(u32 ptys_eth_proto)
-{
- u32 modes = 0;
- int i;
-
- for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) {
- if (ptys_eth_proto & mlxsw_sx_port_link_mode[i].mask)
- modes |= mlxsw_sx_port_link_mode[i].advertised;
- }
- return modes;
-}
-
-static void mlxsw_sx_from_ptys_speed_duplex(bool carrier_ok, u32 ptys_eth_proto,
- struct ethtool_link_ksettings *cmd)
-{
- u32 speed = SPEED_UNKNOWN;
- u8 duplex = DUPLEX_UNKNOWN;
- int i;
-
- if (!carrier_ok)
- goto out;
-
- for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) {
- if (ptys_eth_proto & mlxsw_sx_port_link_mode[i].mask) {
- speed = mlxsw_sx_port_link_mode[i].speed;
- duplex = DUPLEX_FULL;
- break;
- }
- }
-out:
- cmd->base.speed = speed;
- cmd->base.duplex = duplex;
-}
-
-static u8 mlxsw_sx_port_connector_port(u32 ptys_eth_proto)
-{
- if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR |
- MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 |
- MLXSW_REG_PTYS_ETH_SPEED_SGMII))
- return PORT_FIBRE;
-
- if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR |
- MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4))
- return PORT_DA;
-
- if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR |
- MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 |
- MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 |
- MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4))
- return PORT_NONE;
-
- return PORT_OTHER;
-}
-
-static int
-mlxsw_sx_port_get_link_ksettings(struct net_device *dev,
- struct ethtool_link_ksettings *cmd)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char ptys_pl[MLXSW_REG_PTYS_LEN];
- u32 eth_proto_cap;
- u32 eth_proto_admin;
- u32 eth_proto_oper;
- u32 supported, advertising, lp_advertising;
- int err;
-
- mlxsw_reg_ptys_eth_pack(ptys_pl, mlxsw_sx_port->local_port, 0, false);
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl);
- if (err) {
- netdev_err(dev, "Failed to get proto");
- return err;
- }
- mlxsw_reg_ptys_eth_unpack(ptys_pl, &eth_proto_cap,
- &eth_proto_admin, &eth_proto_oper);
-
- supported = mlxsw_sx_from_ptys_supported_port(eth_proto_cap) |
- mlxsw_sx_from_ptys_supported_link(eth_proto_cap) |
- SUPPORTED_Pause | SUPPORTED_Asym_Pause;
- advertising = mlxsw_sx_from_ptys_advert_link(eth_proto_admin);
- mlxsw_sx_from_ptys_speed_duplex(netif_carrier_ok(dev),
- eth_proto_oper, cmd);
-
- eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap;
- cmd->base.port = mlxsw_sx_port_connector_port(eth_proto_oper);
- lp_advertising = mlxsw_sx_from_ptys_advert_link(eth_proto_oper);
-
- ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
- supported);
- ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
- advertising);
- ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
- lp_advertising);
-
- return 0;
-}
-
-static u32 mlxsw_sx_to_ptys_advert_link(u32 advertising)
-{
- u32 ptys_proto = 0;
- int i;
-
- for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) {
- if (advertising & mlxsw_sx_port_link_mode[i].advertised)
- ptys_proto |= mlxsw_sx_port_link_mode[i].mask;
- }
- return ptys_proto;
-}
-
-static u32 mlxsw_sx_to_ptys_speed(u32 speed)
-{
- u32 ptys_proto = 0;
- int i;
-
- for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) {
- if (speed == mlxsw_sx_port_link_mode[i].speed)
- ptys_proto |= mlxsw_sx_port_link_mode[i].mask;
- }
- return ptys_proto;
-}
-
-static u32 mlxsw_sx_to_ptys_upper_speed(u32 upper_speed)
-{
- u32 ptys_proto = 0;
- int i;
-
- for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) {
- if (mlxsw_sx_port_link_mode[i].speed <= upper_speed)
- ptys_proto |= mlxsw_sx_port_link_mode[i].mask;
- }
- return ptys_proto;
-}
-
-static int
-mlxsw_sx_port_set_link_ksettings(struct net_device *dev,
- const struct ethtool_link_ksettings *cmd)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char ptys_pl[MLXSW_REG_PTYS_LEN];
- u32 speed;
- u32 eth_proto_new;
- u32 eth_proto_cap;
- u32 eth_proto_admin;
- u32 advertising;
- bool is_up;
- int err;
-
- speed = cmd->base.speed;
-
- ethtool_convert_link_mode_to_legacy_u32(&advertising,
- cmd->link_modes.advertising);
-
- eth_proto_new = cmd->base.autoneg == AUTONEG_ENABLE ?
- mlxsw_sx_to_ptys_advert_link(advertising) :
- mlxsw_sx_to_ptys_speed(speed);
-
- mlxsw_reg_ptys_eth_pack(ptys_pl, mlxsw_sx_port->local_port, 0, false);
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl);
- if (err) {
- netdev_err(dev, "Failed to get proto");
- return err;
- }
- mlxsw_reg_ptys_eth_unpack(ptys_pl, &eth_proto_cap, &eth_proto_admin,
- NULL);
-
- eth_proto_new = eth_proto_new & eth_proto_cap;
- if (!eth_proto_new) {
- netdev_err(dev, "Not supported proto admin requested");
- return -EINVAL;
- }
- if (eth_proto_new == eth_proto_admin)
- return 0;
-
- mlxsw_reg_ptys_eth_pack(ptys_pl, mlxsw_sx_port->local_port,
- eth_proto_new, true);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl);
- if (err) {
- netdev_err(dev, "Failed to set proto admin");
- return err;
- }
-
- err = mlxsw_sx_port_oper_status_get(mlxsw_sx_port, &is_up);
- if (err) {
- netdev_err(dev, "Failed to get oper status");
- return err;
- }
- if (!is_up)
- return 0;
-
- err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, false);
- if (err) {
- netdev_err(dev, "Failed to set admin status");
- return err;
- }
-
- err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, true);
- if (err) {
- netdev_err(dev, "Failed to set admin status");
- return err;
- }
-
- return 0;
-}
-
-static const struct ethtool_ops mlxsw_sx_port_ethtool_ops = {
- .get_drvinfo = mlxsw_sx_port_get_drvinfo,
- .get_link = ethtool_op_get_link,
- .get_strings = mlxsw_sx_port_get_strings,
- .get_ethtool_stats = mlxsw_sx_port_get_stats,
- .get_sset_count = mlxsw_sx_port_get_sset_count,
- .get_link_ksettings = mlxsw_sx_port_get_link_ksettings,
- .set_link_ksettings = mlxsw_sx_port_set_link_ksettings,
-};
-
-static int mlxsw_sx_hw_id_get(struct mlxsw_sx *mlxsw_sx)
-{
- char spad_pl[MLXSW_REG_SPAD_LEN] = {0};
- int err;
-
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(spad), spad_pl);
- if (err)
- return err;
- mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_sx->hw_id);
- return 0;
-}
-
-static int mlxsw_sx_port_dev_addr_get(struct mlxsw_sx_port *mlxsw_sx_port)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- struct net_device *dev = mlxsw_sx_port->dev;
- char ppad_pl[MLXSW_REG_PPAD_LEN];
- int err;
-
- mlxsw_reg_ppad_pack(ppad_pl, false, 0);
- err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(ppad), ppad_pl);
- if (err)
- return err;
- mlxsw_reg_ppad_mac_memcpy_from(ppad_pl, dev->dev_addr);
- /* The last byte value in base mac address is guaranteed
- * to be such it does not overflow when adding local_port
- * value.
- */
- dev->dev_addr[ETH_ALEN - 1] += mlxsw_sx_port->local_port;
- return 0;
-}
-
-static int mlxsw_sx_port_stp_state_set(struct mlxsw_sx_port *mlxsw_sx_port,
- u16 vid, enum mlxsw_reg_spms_state state)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char *spms_pl;
- int err;
-
- spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL);
- if (!spms_pl)
- return -ENOMEM;
- mlxsw_reg_spms_pack(spms_pl, mlxsw_sx_port->local_port);
- mlxsw_reg_spms_vid_pack(spms_pl, vid, state);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(spms), spms_pl);
- kfree(spms_pl);
- return err;
-}
-
-static int mlxsw_sx_port_ib_speed_set(struct mlxsw_sx_port *mlxsw_sx_port,
- u16 speed, u16 width)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char ptys_pl[MLXSW_REG_PTYS_LEN];
-
- mlxsw_reg_ptys_ib_pack(ptys_pl, mlxsw_sx_port->local_port, speed,
- width);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl);
-}
-
-static int
-mlxsw_sx_port_speed_by_width_set(struct mlxsw_sx_port *mlxsw_sx_port, u8 width)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- u32 upper_speed = MLXSW_SX_PORT_BASE_SPEED * width;
- char ptys_pl[MLXSW_REG_PTYS_LEN];
- u32 eth_proto_admin;
-
- eth_proto_admin = mlxsw_sx_to_ptys_upper_speed(upper_speed);
- mlxsw_reg_ptys_eth_pack(ptys_pl, mlxsw_sx_port->local_port,
- eth_proto_admin, true);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl);
-}
-
-static int
-mlxsw_sx_port_mac_learning_mode_set(struct mlxsw_sx_port *mlxsw_sx_port,
- enum mlxsw_reg_spmlr_learn_mode mode)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
- char spmlr_pl[MLXSW_REG_SPMLR_LEN];
-
- mlxsw_reg_spmlr_pack(spmlr_pl, mlxsw_sx_port->local_port, mode);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(spmlr), spmlr_pl);
-}
-
-static int __mlxsw_sx_port_eth_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
- u8 module, u8 width)
-{
- struct mlxsw_sx_port *mlxsw_sx_port;
- struct net_device *dev;
- int err;
-
- dev = alloc_etherdev(sizeof(struct mlxsw_sx_port));
- if (!dev)
- return -ENOMEM;
- SET_NETDEV_DEV(dev, mlxsw_sx->bus_info->dev);
- dev_net_set(dev, mlxsw_core_net(mlxsw_sx->core));
- mlxsw_sx_port = netdev_priv(dev);
- mlxsw_sx_port->dev = dev;
- mlxsw_sx_port->mlxsw_sx = mlxsw_sx;
- mlxsw_sx_port->local_port = local_port;
- mlxsw_sx_port->mapping.module = module;
-
- mlxsw_sx_port->pcpu_stats =
- netdev_alloc_pcpu_stats(struct mlxsw_sx_port_pcpu_stats);
- if (!mlxsw_sx_port->pcpu_stats) {
- err = -ENOMEM;
- goto err_alloc_stats;
- }
-
- dev->netdev_ops = &mlxsw_sx_port_netdev_ops;
- dev->ethtool_ops = &mlxsw_sx_port_ethtool_ops;
-
- err = mlxsw_sx_port_dev_addr_get(mlxsw_sx_port);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Unable to get port mac address\n",
- mlxsw_sx_port->local_port);
- goto err_dev_addr_get;
- }
-
- netif_carrier_off(dev);
-
- dev->features |= NETIF_F_NETNS_LOCAL | NETIF_F_LLTX | NETIF_F_SG |
- NETIF_F_VLAN_CHALLENGED;
-
- dev->min_mtu = 0;
- dev->max_mtu = ETH_MAX_MTU;
-
- /* Each packet needs to have a Tx header (metadata) on top all other
- * headers.
- */
- dev->needed_headroom = MLXSW_TXHDR_LEN;
-
- err = mlxsw_sx_port_system_port_mapping_set(mlxsw_sx_port);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set system port mapping\n",
- mlxsw_sx_port->local_port);
- goto err_port_system_port_mapping_set;
- }
-
- err = mlxsw_sx_port_swid_set(mlxsw_sx_port, 0);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set SWID\n",
- mlxsw_sx_port->local_port);
- goto err_port_swid_set;
- }
-
- err = mlxsw_sx_port_speed_by_width_set(mlxsw_sx_port, width);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set speed\n",
- mlxsw_sx_port->local_port);
- goto err_port_speed_set;
- }
-
- err = mlxsw_sx_port_mtu_eth_set(mlxsw_sx_port, ETH_DATA_LEN);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set MTU\n",
- mlxsw_sx_port->local_port);
- goto err_port_mtu_set;
- }
-
- err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, false);
- if (err)
- goto err_port_admin_status_set;
-
- err = mlxsw_sx_port_stp_state_set(mlxsw_sx_port,
- MLXSW_PORT_DEFAULT_VID,
- MLXSW_REG_SPMS_STATE_FORWARDING);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set STP state\n",
- mlxsw_sx_port->local_port);
- goto err_port_stp_state_set;
- }
-
- err = mlxsw_sx_port_mac_learning_mode_set(mlxsw_sx_port,
- MLXSW_REG_SPMLR_LEARN_MODE_DISABLE);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set MAC learning mode\n",
- mlxsw_sx_port->local_port);
- goto err_port_mac_learning_mode_set;
- }
-
- err = register_netdev(dev);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to register netdev\n",
- mlxsw_sx_port->local_port);
- goto err_register_netdev;
- }
-
- mlxsw_core_port_eth_set(mlxsw_sx->core, mlxsw_sx_port->local_port,
- mlxsw_sx_port, dev);
- mlxsw_sx->ports[local_port] = mlxsw_sx_port;
- return 0;
-
-err_register_netdev:
-err_port_mac_learning_mode_set:
-err_port_stp_state_set:
-err_port_admin_status_set:
-err_port_mtu_set:
-err_port_speed_set:
- mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
-err_port_swid_set:
-err_port_system_port_mapping_set:
-err_dev_addr_get:
- free_percpu(mlxsw_sx_port->pcpu_stats);
-err_alloc_stats:
- free_netdev(dev);
- return err;
-}
-
-static int mlxsw_sx_port_eth_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
- u8 module, u8 width)
-{
- int err;
-
- err = mlxsw_core_port_init(mlxsw_sx->core, local_port,
- module + 1, false, 0, false, 0,
- mlxsw_sx->hw_id, sizeof(mlxsw_sx->hw_id));
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to init core port\n",
- local_port);
- return err;
- }
- err = __mlxsw_sx_port_eth_create(mlxsw_sx, local_port, module, width);
- if (err)
- goto err_port_create;
-
- return 0;
-
-err_port_create:
- mlxsw_core_port_fini(mlxsw_sx->core, local_port);
- return err;
-}
-
-static void __mlxsw_sx_port_eth_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = mlxsw_sx->ports[local_port];
-
- mlxsw_core_port_clear(mlxsw_sx->core, local_port, mlxsw_sx);
- unregister_netdev(mlxsw_sx_port->dev); /* This calls ndo_stop */
- mlxsw_sx->ports[local_port] = NULL;
- mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
- free_percpu(mlxsw_sx_port->pcpu_stats);
- free_netdev(mlxsw_sx_port->dev);
-}
-
-static bool mlxsw_sx_port_created(struct mlxsw_sx *mlxsw_sx, u8 local_port)
-{
- return mlxsw_sx->ports[local_port] != NULL;
-}
-
-static int __mlxsw_sx_port_ib_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
- u8 module, u8 width)
-{
- struct mlxsw_sx_port *mlxsw_sx_port;
- int err;
-
- mlxsw_sx_port = kzalloc(sizeof(*mlxsw_sx_port), GFP_KERNEL);
- if (!mlxsw_sx_port)
- return -ENOMEM;
- mlxsw_sx_port->mlxsw_sx = mlxsw_sx;
- mlxsw_sx_port->local_port = local_port;
- mlxsw_sx_port->mapping.module = module;
-
- err = mlxsw_sx_port_system_port_mapping_set(mlxsw_sx_port);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set system port mapping\n",
- mlxsw_sx_port->local_port);
- goto err_port_system_port_mapping_set;
- }
-
- /* Adding port to Infiniband swid (1) */
- err = mlxsw_sx_port_swid_set(mlxsw_sx_port, 1);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set SWID\n",
- mlxsw_sx_port->local_port);
- goto err_port_swid_set;
- }
-
- /* Expose the IB port number as it's front panel name */
- err = mlxsw_sx_port_ib_port_set(mlxsw_sx_port, module + 1);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set IB port\n",
- mlxsw_sx_port->local_port);
- goto err_port_ib_set;
- }
-
- /* Supports all speeds from SDR to FDR (bitmask) and support bus width
- * of 1x, 2x and 4x (3 bits bitmask)
- */
- err = mlxsw_sx_port_ib_speed_set(mlxsw_sx_port,
- MLXSW_REG_PTYS_IB_SPEED_EDR - 1,
- BIT(3) - 1);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set speed\n",
- mlxsw_sx_port->local_port);
- goto err_port_speed_set;
- }
-
- /* Change to the maximum MTU the device supports, the SMA will take
- * care of the active MTU
- */
- err = mlxsw_sx_port_mtu_ib_set(mlxsw_sx_port, MLXSW_IB_DEFAULT_MTU);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set MTU\n",
- mlxsw_sx_port->local_port);
- goto err_port_mtu_set;
- }
-
- err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, true);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to change admin state to UP\n",
- mlxsw_sx_port->local_port);
- goto err_port_admin_set;
- }
-
- mlxsw_core_port_ib_set(mlxsw_sx->core, mlxsw_sx_port->local_port,
- mlxsw_sx_port);
- mlxsw_sx->ports[local_port] = mlxsw_sx_port;
- return 0;
-
-err_port_admin_set:
-err_port_mtu_set:
-err_port_speed_set:
-err_port_ib_set:
- mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
-err_port_swid_set:
-err_port_system_port_mapping_set:
- kfree(mlxsw_sx_port);
- return err;
-}
-
-static void __mlxsw_sx_port_ib_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
-{
- struct mlxsw_sx_port *mlxsw_sx_port = mlxsw_sx->ports[local_port];
-
- mlxsw_core_port_clear(mlxsw_sx->core, local_port, mlxsw_sx);
- mlxsw_sx->ports[local_port] = NULL;
- mlxsw_sx_port_admin_status_set(mlxsw_sx_port, false);
- mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
- kfree(mlxsw_sx_port);
-}
-
-static void __mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
-{
- enum devlink_port_type port_type =
- mlxsw_core_port_type_get(mlxsw_sx->core, local_port);
-
- if (port_type == DEVLINK_PORT_TYPE_ETH)
- __mlxsw_sx_port_eth_remove(mlxsw_sx, local_port);
- else if (port_type == DEVLINK_PORT_TYPE_IB)
- __mlxsw_sx_port_ib_remove(mlxsw_sx, local_port);
-}
-
-static void mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
-{
- __mlxsw_sx_port_remove(mlxsw_sx, local_port);
- mlxsw_core_port_fini(mlxsw_sx->core, local_port);
-}
-
-static void mlxsw_sx_ports_remove(struct mlxsw_sx *mlxsw_sx)
-{
- int i;
-
- for (i = 1; i < mlxsw_core_max_ports(mlxsw_sx->core); i++)
- if (mlxsw_sx_port_created(mlxsw_sx, i))
- mlxsw_sx_port_remove(mlxsw_sx, i);
- kfree(mlxsw_sx->ports);
- mlxsw_sx->ports = NULL;
-}
-
-static int mlxsw_sx_ports_create(struct mlxsw_sx *mlxsw_sx)
-{
- unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sx->core);
- size_t alloc_size;
- u8 module, width;
- int i;
- int err;
-
- alloc_size = sizeof(struct mlxsw_sx_port *) * max_ports;
- mlxsw_sx->ports = kzalloc(alloc_size, GFP_KERNEL);
- if (!mlxsw_sx->ports)
- return -ENOMEM;
-
- for (i = 1; i < max_ports; i++) {
- err = mlxsw_sx_port_module_info_get(mlxsw_sx, i, &module,
- &width);
- if (err)
- goto err_port_module_info_get;
- if (!width)
- continue;
- err = mlxsw_sx_port_eth_create(mlxsw_sx, i, module, width);
- if (err)
- goto err_port_create;
- }
- return 0;
-
-err_port_create:
-err_port_module_info_get:
- for (i--; i >= 1; i--)
- if (mlxsw_sx_port_created(mlxsw_sx, i))
- mlxsw_sx_port_remove(mlxsw_sx, i);
- kfree(mlxsw_sx->ports);
- mlxsw_sx->ports = NULL;
- return err;
-}
-
-static void mlxsw_sx_pude_eth_event_func(struct mlxsw_sx_port *mlxsw_sx_port,
- enum mlxsw_reg_pude_oper_status status)
-{
- if (status == MLXSW_PORT_OPER_STATUS_UP) {
- netdev_info(mlxsw_sx_port->dev, "link up\n");
- netif_carrier_on(mlxsw_sx_port->dev);
- } else {
- netdev_info(mlxsw_sx_port->dev, "link down\n");
- netif_carrier_off(mlxsw_sx_port->dev);
- }
-}
-
-static void mlxsw_sx_pude_ib_event_func(struct mlxsw_sx_port *mlxsw_sx_port,
- enum mlxsw_reg_pude_oper_status status)
-{
- if (status == MLXSW_PORT_OPER_STATUS_UP)
- pr_info("ib link for port %d - up\n",
- mlxsw_sx_port->mapping.module + 1);
- else
- pr_info("ib link for port %d - down\n",
- mlxsw_sx_port->mapping.module + 1);
-}
-
-static void mlxsw_sx_pude_event_func(const struct mlxsw_reg_info *reg,
- char *pude_pl, void *priv)
-{
- struct mlxsw_sx *mlxsw_sx = priv;
- struct mlxsw_sx_port *mlxsw_sx_port;
- enum mlxsw_reg_pude_oper_status status;
- enum devlink_port_type port_type;
- u8 local_port;
-
- local_port = mlxsw_reg_pude_local_port_get(pude_pl);
- mlxsw_sx_port = mlxsw_sx->ports[local_port];
- if (!mlxsw_sx_port) {
- dev_warn(mlxsw_sx->bus_info->dev, "Port %d: Link event received for non-existent port\n",
- local_port);
- return;
- }
-
- status = mlxsw_reg_pude_oper_status_get(pude_pl);
- port_type = mlxsw_core_port_type_get(mlxsw_sx->core, local_port);
- if (port_type == DEVLINK_PORT_TYPE_ETH)
- mlxsw_sx_pude_eth_event_func(mlxsw_sx_port, status);
- else if (port_type == DEVLINK_PORT_TYPE_IB)
- mlxsw_sx_pude_ib_event_func(mlxsw_sx_port, status);
-}
-
-static void mlxsw_sx_rx_listener_func(struct sk_buff *skb, u8 local_port,
- void *priv)
-{
- struct mlxsw_sx *mlxsw_sx = priv;
- struct mlxsw_sx_port *mlxsw_sx_port = mlxsw_sx->ports[local_port];
- struct mlxsw_sx_port_pcpu_stats *pcpu_stats;
-
- if (unlikely(!mlxsw_sx_port)) {
- dev_warn_ratelimited(mlxsw_sx->bus_info->dev, "Port %d: skb received for non-existent port\n",
- local_port);
- return;
- }
-
- skb->dev = mlxsw_sx_port->dev;
-
- pcpu_stats = this_cpu_ptr(mlxsw_sx_port->pcpu_stats);
- u64_stats_update_begin(&pcpu_stats->syncp);
- pcpu_stats->rx_packets++;
- pcpu_stats->rx_bytes += skb->len;
- u64_stats_update_end(&pcpu_stats->syncp);
-
- skb->protocol = eth_type_trans(skb, skb->dev);
- netif_receive_skb(skb);
-}
-
-static int mlxsw_sx_port_type_set(struct mlxsw_core *mlxsw_core, u8 local_port,
- enum devlink_port_type new_type)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_core_driver_priv(mlxsw_core);
- u8 module, width;
- int err;
-
- if (!mlxsw_sx->ports || !mlxsw_sx->ports[local_port]) {
- dev_err(mlxsw_sx->bus_info->dev, "Port number \"%d\" does not exist\n",
- local_port);
- return -EINVAL;
- }
-
- if (new_type == DEVLINK_PORT_TYPE_AUTO)
- return -EOPNOTSUPP;
-
- __mlxsw_sx_port_remove(mlxsw_sx, local_port);
- err = mlxsw_sx_port_module_info_get(mlxsw_sx, local_port, &module,
- &width);
- if (err)
- goto err_port_module_info_get;
-
- if (new_type == DEVLINK_PORT_TYPE_ETH)
- err = __mlxsw_sx_port_eth_create(mlxsw_sx, local_port, module,
- width);
- else if (new_type == DEVLINK_PORT_TYPE_IB)
- err = __mlxsw_sx_port_ib_create(mlxsw_sx, local_port, module,
- width);
-
-err_port_module_info_get:
- return err;
-}
-
-enum {
- MLXSW_REG_HTGT_TRAP_GROUP_SX2_RX = 1,
- MLXSW_REG_HTGT_TRAP_GROUP_SX2_CTRL = 2,
-};
-
-#define MLXSW_SX_RXL(_trap_id) \
- MLXSW_RXL(mlxsw_sx_rx_listener_func, _trap_id, TRAP_TO_CPU, \
- false, SX2_RX, FORWARD)
-
-static const struct mlxsw_listener mlxsw_sx_listener[] = {
- MLXSW_EVENTL(mlxsw_sx_pude_event_func, PUDE, EMAD),
- MLXSW_SX_RXL(FDB_MC),
- MLXSW_SX_RXL(STP),
- MLXSW_SX_RXL(LACP),
- MLXSW_SX_RXL(EAPOL),
- MLXSW_SX_RXL(LLDP),
- MLXSW_SX_RXL(MMRP),
- MLXSW_SX_RXL(MVRP),
- MLXSW_SX_RXL(RPVST),
- MLXSW_SX_RXL(DHCP),
- MLXSW_SX_RXL(IGMP_QUERY),
- MLXSW_SX_RXL(IGMP_V1_REPORT),
- MLXSW_SX_RXL(IGMP_V2_REPORT),
- MLXSW_SX_RXL(IGMP_V2_LEAVE),
- MLXSW_SX_RXL(IGMP_V3_REPORT),
-};
-
-static int mlxsw_sx_traps_init(struct mlxsw_sx *mlxsw_sx)
-{
- char htgt_pl[MLXSW_REG_HTGT_LEN];
- int i;
- int err;
-
- mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SX2_RX,
- MLXSW_REG_HTGT_INVALID_POLICER,
- MLXSW_REG_HTGT_DEFAULT_PRIORITY,
- MLXSW_REG_HTGT_DEFAULT_TC);
- mlxsw_reg_htgt_local_path_rdq_set(htgt_pl,
- MLXSW_REG_HTGT_LOCAL_PATH_RDQ_SX2_RX);
-
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(htgt), htgt_pl);
- if (err)
- return err;
-
- mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SX2_CTRL,
- MLXSW_REG_HTGT_INVALID_POLICER,
- MLXSW_REG_HTGT_DEFAULT_PRIORITY,
- MLXSW_REG_HTGT_DEFAULT_TC);
- mlxsw_reg_htgt_local_path_rdq_set(htgt_pl,
- MLXSW_REG_HTGT_LOCAL_PATH_RDQ_SX2_CTRL);
-
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(htgt), htgt_pl);
- if (err)
- return err;
-
- for (i = 0; i < ARRAY_SIZE(mlxsw_sx_listener); i++) {
- err = mlxsw_core_trap_register(mlxsw_sx->core,
- &mlxsw_sx_listener[i],
- mlxsw_sx);
- if (err)
- goto err_listener_register;
-
- }
- return 0;
-
-err_listener_register:
- for (i--; i >= 0; i--) {
- mlxsw_core_trap_unregister(mlxsw_sx->core,
- &mlxsw_sx_listener[i],
- mlxsw_sx);
- }
- return err;
-}
-
-static void mlxsw_sx_traps_fini(struct mlxsw_sx *mlxsw_sx)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mlxsw_sx_listener); i++) {
- mlxsw_core_trap_unregister(mlxsw_sx->core,
- &mlxsw_sx_listener[i],
- mlxsw_sx);
- }
-}
-
-static int mlxsw_sx_flood_init(struct mlxsw_sx *mlxsw_sx)
-{
- char sfgc_pl[MLXSW_REG_SFGC_LEN];
- char sgcr_pl[MLXSW_REG_SGCR_LEN];
- char *sftr_pl;
- int err;
-
- /* Configure a flooding table, which includes only CPU port. */
- sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
- if (!sftr_pl)
- return -ENOMEM;
- mlxsw_reg_sftr_pack(sftr_pl, 0, 0, MLXSW_REG_SFGC_TABLE_TYPE_SINGLE, 0,
- MLXSW_PORT_CPU_PORT, true);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sftr), sftr_pl);
- kfree(sftr_pl);
- if (err)
- return err;
-
- /* Flood different packet types using the flooding table. */
- mlxsw_reg_sfgc_pack(sfgc_pl,
- MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST,
- MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
- MLXSW_REG_SFGC_TABLE_TYPE_SINGLE,
- 0);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl);
- if (err)
- return err;
-
- mlxsw_reg_sfgc_pack(sfgc_pl,
- MLXSW_REG_SFGC_TYPE_BROADCAST,
- MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
- MLXSW_REG_SFGC_TABLE_TYPE_SINGLE,
- 0);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl);
- if (err)
- return err;
-
- mlxsw_reg_sfgc_pack(sfgc_pl,
- MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP,
- MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
- MLXSW_REG_SFGC_TABLE_TYPE_SINGLE,
- 0);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl);
- if (err)
- return err;
-
- mlxsw_reg_sfgc_pack(sfgc_pl,
- MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6,
- MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
- MLXSW_REG_SFGC_TABLE_TYPE_SINGLE,
- 0);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl);
- if (err)
- return err;
-
- mlxsw_reg_sfgc_pack(sfgc_pl,
- MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4,
- MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
- MLXSW_REG_SFGC_TABLE_TYPE_SINGLE,
- 0);
- err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl);
- if (err)
- return err;
-
- mlxsw_reg_sgcr_pack(sgcr_pl, true);
- return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sgcr), sgcr_pl);
-}
-
-static int mlxsw_sx_basic_trap_groups_set(struct mlxsw_core *mlxsw_core)
-{
- char htgt_pl[MLXSW_REG_HTGT_LEN];
-
- mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_EMAD,
- MLXSW_REG_HTGT_INVALID_POLICER,
- MLXSW_REG_HTGT_DEFAULT_PRIORITY,
- MLXSW_REG_HTGT_DEFAULT_TC);
- mlxsw_reg_htgt_swid_set(htgt_pl, MLXSW_PORT_SWID_ALL_SWIDS);
- mlxsw_reg_htgt_local_path_rdq_set(htgt_pl,
- MLXSW_REG_HTGT_LOCAL_PATH_RDQ_SX2_EMAD);
- return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
-}
-
-static int mlxsw_sx_init(struct mlxsw_core *mlxsw_core,
- const struct mlxsw_bus_info *mlxsw_bus_info,
- struct netlink_ext_ack *extack)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_core_driver_priv(mlxsw_core);
- int err;
-
- mlxsw_sx->core = mlxsw_core;
- mlxsw_sx->bus_info = mlxsw_bus_info;
-
- err = mlxsw_sx_hw_id_get(mlxsw_sx);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Failed to get switch HW ID\n");
- return err;
- }
-
- err = mlxsw_sx_ports_create(mlxsw_sx);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Failed to create ports\n");
- return err;
- }
-
- err = mlxsw_sx_traps_init(mlxsw_sx);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Failed to set traps\n");
- goto err_listener_register;
- }
-
- err = mlxsw_sx_flood_init(mlxsw_sx);
- if (err) {
- dev_err(mlxsw_sx->bus_info->dev, "Failed to initialize flood tables\n");
- goto err_flood_init;
- }
-
- return 0;
-
-err_flood_init:
- mlxsw_sx_traps_fini(mlxsw_sx);
-err_listener_register:
- mlxsw_sx_ports_remove(mlxsw_sx);
- return err;
-}
-
-static void mlxsw_sx_fini(struct mlxsw_core *mlxsw_core)
-{
- struct mlxsw_sx *mlxsw_sx = mlxsw_core_driver_priv(mlxsw_core);
-
- mlxsw_sx_traps_fini(mlxsw_sx);
- mlxsw_sx_ports_remove(mlxsw_sx);
-}
-
-static const struct mlxsw_config_profile mlxsw_sx_config_profile = {
- .used_max_vepa_channels = 1,
- .max_vepa_channels = 0,
- .used_max_mid = 1,
- .max_mid = 7000,
- .used_max_pgt = 1,
- .max_pgt = 0,
- .used_max_system_port = 1,
- .max_system_port = 48000,
- .used_max_vlan_groups = 1,
- .max_vlan_groups = 127,
- .used_max_regions = 1,
- .max_regions = 400,
- .used_flood_tables = 1,
- .max_flood_tables = 2,
- .max_vid_flood_tables = 1,
- .used_flood_mode = 1,
- .flood_mode = 3,
- .used_max_ib_mc = 1,
- .max_ib_mc = 6,
- .used_max_pkey = 1,
- .max_pkey = 0,
- .swid_config = {
- {
- .used_type = 1,
- .type = MLXSW_PORT_SWID_TYPE_ETH,
- },
- {
- .used_type = 1,
- .type = MLXSW_PORT_SWID_TYPE_IB,
- }
- },
-};
-
-static struct mlxsw_driver mlxsw_sx_driver = {
- .kind = mlxsw_sx_driver_name,
- .priv_size = sizeof(struct mlxsw_sx),
- .init = mlxsw_sx_init,
- .fini = mlxsw_sx_fini,
- .basic_trap_groups_set = mlxsw_sx_basic_trap_groups_set,
- .txhdr_construct = mlxsw_sx_txhdr_construct,
- .txhdr_len = MLXSW_TXHDR_LEN,
- .profile = &mlxsw_sx_config_profile,
- .port_type_set = mlxsw_sx_port_type_set,
-};
-
-static const struct pci_device_id mlxsw_sx_pci_id_table[] = {
- {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SWITCHX2), 0},
- {0, },
-};
-
-static struct pci_driver mlxsw_sx_pci_driver = {
- .name = mlxsw_sx_driver_name,
- .id_table = mlxsw_sx_pci_id_table,
-};
-
-static int __init mlxsw_sx_module_init(void)
-{
- int err;
-
- err = mlxsw_core_driver_register(&mlxsw_sx_driver);
- if (err)
- return err;
-
- err = mlxsw_pci_driver_register(&mlxsw_sx_pci_driver);
- if (err)
- goto err_pci_driver_register;
-
- return 0;
-
-err_pci_driver_register:
- mlxsw_core_driver_unregister(&mlxsw_sx_driver);
- return err;
-}
-
-static void __exit mlxsw_sx_module_exit(void)
-{
- mlxsw_pci_driver_unregister(&mlxsw_sx_pci_driver);
- mlxsw_core_driver_unregister(&mlxsw_sx_driver);
-}
-
-module_init(mlxsw_sx_module_init);
-module_exit(mlxsw_sx_module_exit);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
-MODULE_DESCRIPTION("Mellanox SwitchX-2 driver");
-MODULE_DEVICE_TABLE(pci, mlxsw_sx_pci_id_table);
diff --git a/drivers/net/ethernet/micrel/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c
index caa251d0e381..b27713906d3a 100644
--- a/drivers/net/ethernet/micrel/ks8842.c
+++ b/drivers/net/ethernet/micrel/ks8842.c
@@ -1135,6 +1135,10 @@ static int ks8842_probe(struct platform_device *pdev)
unsigned i;
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iomem) {
+ dev_err(&pdev->dev, "Invalid resource\n");
+ return -EINVAL;
+ }
if (!request_mem_region(iomem->start, resource_size(iomem), DRV_NAME))
goto err_mem_region;
diff --git a/drivers/net/ethernet/micrel/ks8851_common.c b/drivers/net/ethernet/micrel/ks8851_common.c
index 13eef6e9bd2d..831518466de2 100644
--- a/drivers/net/ethernet/micrel/ks8851_common.c
+++ b/drivers/net/ethernet/micrel/ks8851_common.c
@@ -1022,30 +1022,23 @@ static int ks8851_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
*
* Read and check the TX/RX memory selftest information.
*/
-static int ks8851_read_selftest(struct ks8851_net *ks)
+static void ks8851_read_selftest(struct ks8851_net *ks)
{
unsigned both_done = MBIR_TXMBF | MBIR_RXMBF;
- int ret = 0;
unsigned rd;
rd = ks8851_rdreg16(ks, KS_MBIR);
if ((rd & both_done) != both_done) {
netdev_warn(ks->netdev, "Memory selftest not finished\n");
- return 0;
+ return;
}
- if (rd & MBIR_TXMBFA) {
+ if (rd & MBIR_TXMBFA)
netdev_err(ks->netdev, "TX memory selftest fail\n");
- ret |= 1;
- }
- if (rd & MBIR_RXMBFA) {
+ if (rd & MBIR_RXMBFA)
netdev_err(ks->netdev, "RX memory selftest fail\n");
- ret |= 2;
- }
-
- return 0;
}
/* driver bus management functions */
diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c
index 9ed264ed7070..7945eb5e2fe8 100644
--- a/drivers/net/ethernet/micrel/ksz884x.c
+++ b/drivers/net/ethernet/micrel/ksz884x.c
@@ -25,6 +25,7 @@
#include <linux/crc32.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/micrel_phy.h>
/* DMA Registers */
@@ -271,84 +272,15 @@
#define KS884X_PHY_CTRL_OFFSET 0x00
-/* Mode Control Register */
-#define PHY_REG_CTRL 0
-
-#define PHY_RESET 0x8000
-#define PHY_LOOPBACK 0x4000
-#define PHY_SPEED_100MBIT 0x2000
-#define PHY_AUTO_NEG_ENABLE 0x1000
-#define PHY_POWER_DOWN 0x0800
-#define PHY_MII_DISABLE 0x0400
-#define PHY_AUTO_NEG_RESTART 0x0200
-#define PHY_FULL_DUPLEX 0x0100
-#define PHY_COLLISION_TEST 0x0080
-#define PHY_HP_MDIX 0x0020
-#define PHY_FORCE_MDIX 0x0010
-#define PHY_AUTO_MDIX_DISABLE 0x0008
-#define PHY_REMOTE_FAULT_DISABLE 0x0004
-#define PHY_TRANSMIT_DISABLE 0x0002
-#define PHY_LED_DISABLE 0x0001
-
#define KS884X_PHY_STATUS_OFFSET 0x02
-/* Mode Status Register */
-#define PHY_REG_STATUS 1
-
-#define PHY_100BT4_CAPABLE 0x8000
-#define PHY_100BTX_FD_CAPABLE 0x4000
-#define PHY_100BTX_CAPABLE 0x2000
-#define PHY_10BT_FD_CAPABLE 0x1000
-#define PHY_10BT_CAPABLE 0x0800
-#define PHY_MII_SUPPRESS_CAPABLE 0x0040
-#define PHY_AUTO_NEG_ACKNOWLEDGE 0x0020
-#define PHY_REMOTE_FAULT 0x0010
-#define PHY_AUTO_NEG_CAPABLE 0x0008
-#define PHY_LINK_STATUS 0x0004
-#define PHY_JABBER_DETECT 0x0002
-#define PHY_EXTENDED_CAPABILITY 0x0001
-
#define KS884X_PHY_ID_1_OFFSET 0x04
#define KS884X_PHY_ID_2_OFFSET 0x06
-/* PHY Identifier Registers */
-#define PHY_REG_ID_1 2
-#define PHY_REG_ID_2 3
-
#define KS884X_PHY_AUTO_NEG_OFFSET 0x08
-/* Auto-Negotiation Advertisement Register */
-#define PHY_REG_AUTO_NEGOTIATION 4
-
-#define PHY_AUTO_NEG_NEXT_PAGE 0x8000
-#define PHY_AUTO_NEG_REMOTE_FAULT 0x2000
-/* Not supported. */
-#define PHY_AUTO_NEG_ASYM_PAUSE 0x0800
-#define PHY_AUTO_NEG_SYM_PAUSE 0x0400
-#define PHY_AUTO_NEG_100BT4 0x0200
-#define PHY_AUTO_NEG_100BTX_FD 0x0100
-#define PHY_AUTO_NEG_100BTX 0x0080
-#define PHY_AUTO_NEG_10BT_FD 0x0040
-#define PHY_AUTO_NEG_10BT 0x0020
-#define PHY_AUTO_NEG_SELECTOR 0x001F
-#define PHY_AUTO_NEG_802_3 0x0001
-
-#define PHY_AUTO_NEG_PAUSE (PHY_AUTO_NEG_SYM_PAUSE | PHY_AUTO_NEG_ASYM_PAUSE)
-
#define KS884X_PHY_REMOTE_CAP_OFFSET 0x0A
-/* Auto-Negotiation Link Partner Ability Register */
-#define PHY_REG_REMOTE_CAPABILITY 5
-
-#define PHY_REMOTE_NEXT_PAGE 0x8000
-#define PHY_REMOTE_ACKNOWLEDGE 0x4000
-#define PHY_REMOTE_REMOTE_FAULT 0x2000
-#define PHY_REMOTE_SYM_PAUSE 0x0400
-#define PHY_REMOTE_100BTX_FD 0x0100
-#define PHY_REMOTE_100BTX 0x0080
-#define PHY_REMOTE_10BT_FD 0x0040
-#define PHY_REMOTE_10BT 0x0020
-
/* P1VCT */
#define KS884X_P1VCT_P 0x04F0
#define KS884X_P1PHYCTRL_P 0x04F2
@@ -2153,7 +2085,7 @@ static void sw_cfg_broad_storm(struct ksz_hw *hw, u8 percent)
}
/**
- * sw_get_board_storm - get broadcast storm threshold
+ * sw_get_broad_storm - get broadcast storm threshold
* @hw: The hardware instance.
* @percent: Buffer to store the broadcast storm threshold percentage.
*
@@ -2886,15 +2818,6 @@ static void sw_block_addr(struct ksz_hw *hw)
}
}
-#define PHY_LINK_SUPPORT \
- (PHY_AUTO_NEG_ASYM_PAUSE | \
- PHY_AUTO_NEG_SYM_PAUSE | \
- PHY_AUTO_NEG_100BT4 | \
- PHY_AUTO_NEG_100BTX_FD | \
- PHY_AUTO_NEG_100BTX | \
- PHY_AUTO_NEG_10BT_FD | \
- PHY_AUTO_NEG_10BT)
-
static inline void hw_r_phy_ctrl(struct ksz_hw *hw, int phy, u16 *data)
{
*data = readw(hw->io + phy + KS884X_PHY_CTRL_OFFSET);
@@ -2973,7 +2896,7 @@ static void hw_r_phy(struct ksz_hw *hw, int port, u16 reg, u16 *val)
}
/**
- * port_w_phy - write data to PHY register
+ * hw_w_phy - write data to PHY register
* @hw: The hardware instance.
* @port: Port to write.
* @reg: PHY register to write.
@@ -3238,16 +3161,18 @@ static void determine_flow_ctrl(struct ksz_hw *hw, struct ksz_port *port,
rx = tx = 0;
if (port->force_link)
rx = tx = 1;
- if (remote & PHY_AUTO_NEG_SYM_PAUSE) {
- if (local & PHY_AUTO_NEG_SYM_PAUSE) {
+ if (remote & LPA_PAUSE_CAP) {
+ if (local & ADVERTISE_PAUSE_CAP) {
rx = tx = 1;
- } else if ((remote & PHY_AUTO_NEG_ASYM_PAUSE) &&
- (local & PHY_AUTO_NEG_PAUSE) ==
- PHY_AUTO_NEG_ASYM_PAUSE) {
+ } else if ((remote & LPA_PAUSE_ASYM) &&
+ (local &
+ (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) ==
+ ADVERTISE_PAUSE_ASYM) {
tx = 1;
}
- } else if (remote & PHY_AUTO_NEG_ASYM_PAUSE) {
- if ((local & PHY_AUTO_NEG_PAUSE) == PHY_AUTO_NEG_PAUSE)
+ } else if (remote & LPA_PAUSE_ASYM) {
+ if ((local & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM))
+ == (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM))
rx = 1;
}
if (!hw->ksz_switch)
@@ -3428,16 +3353,16 @@ static void port_force_link_speed(struct ksz_port *port)
phy = KS884X_PHY_1_CTRL_OFFSET + p * PHY_CTRL_INTERVAL;
hw_r_phy_ctrl(hw, phy, &data);
- data &= ~PHY_AUTO_NEG_ENABLE;
+ data &= ~BMCR_ANENABLE;
if (10 == port->speed)
- data &= ~PHY_SPEED_100MBIT;
+ data &= ~BMCR_SPEED100;
else if (100 == port->speed)
- data |= PHY_SPEED_100MBIT;
+ data |= BMCR_SPEED100;
if (1 == port->duplex)
- data &= ~PHY_FULL_DUPLEX;
+ data &= ~BMCR_FULLDPLX;
else if (2 == port->duplex)
- data |= PHY_FULL_DUPLEX;
+ data |= BMCR_FULLDPLX;
hw_w_phy_ctrl(hw, phy, data);
}
}
@@ -4782,7 +4707,7 @@ static void transmit_cleanup(struct dev_info *hw_priv, int normal)
}
/**
- * transmit_done - transmit done processing
+ * tx_done - transmit done processing
* @hw_priv: Network device.
*
* This routine is called when the transmit interrupt is triggered, indicating
diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
index d0f6dfe0dcf3..d54aa164c4e9 100644
--- a/drivers/net/ethernet/microchip/Kconfig
+++ b/drivers/net/ethernet/microchip/Kconfig
@@ -54,4 +54,6 @@ config LAN743X
To compile this driver as a module, choose M here. The module will be
called lan743x.
+source "drivers/net/ethernet/microchip/sparx5/Kconfig"
+
endif # NET_VENDOR_MICROCHIP
diff --git a/drivers/net/ethernet/microchip/Makefile b/drivers/net/ethernet/microchip/Makefile
index da603540ca57..c77dc0379bfd 100644
--- a/drivers/net/ethernet/microchip/Makefile
+++ b/drivers/net/ethernet/microchip/Makefile
@@ -8,3 +8,5 @@ obj-$(CONFIG_ENCX24J600) += encx24j600.o encx24j600-regmap.o
obj-$(CONFIG_LAN743X) += lan743x.o
lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o
+
+obj-$(CONFIG_SPARX5_SWITCH) += sparx5/
diff --git a/drivers/net/ethernet/microchip/sparx5/Kconfig b/drivers/net/ethernet/microchip/sparx5/Kconfig
new file mode 100644
index 000000000000..ac403d43c74c
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/Kconfig
@@ -0,0 +1,10 @@
+config SPARX5_SWITCH
+ tristate "Sparx5 switch driver"
+ depends on NET_SWITCHDEV
+ depends on HAS_IOMEM
+ depends on OF
+ select PHYLINK
+ select PHY_SPARX5_SERDES
+ select RESET_CONTROLLER
+ help
+ This driver supports the Sparx5 network switch device.
diff --git a/drivers/net/ethernet/microchip/sparx5/Makefile b/drivers/net/ethernet/microchip/sparx5/Makefile
new file mode 100644
index 000000000000..faa8f07a6b75
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the Microchip Sparx5 network device drivers.
+#
+
+obj-$(CONFIG_SPARX5_SWITCH) += sparx5-switch.o
+
+sparx5-switch-objs := sparx5_main.o sparx5_packet.o \
+ sparx5_netdev.o sparx5_phylink.o sparx5_port.o sparx5_mactable.o sparx5_vlan.o \
+ sparx5_switchdev.o sparx5_calendar.o sparx5_ethtool.o
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c b/drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c
new file mode 100644
index 000000000000..76a8bb596aec
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c
@@ -0,0 +1,596 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+
+#include "sparx5_main_regs.h"
+#include "sparx5_main.h"
+
+/* QSYS calendar information */
+#define SPX5_PORTS_PER_CALREG 10 /* Ports mapped in a calendar register */
+#define SPX5_CALBITS_PER_PORT 3 /* Bit per port in calendar register */
+
+/* DSM calendar information */
+#define SPX5_DSM_CAL_LEN 64
+#define SPX5_DSM_CAL_EMPTY 0xFFFF
+#define SPX5_DSM_CAL_MAX_DEVS_PER_TAXI 13
+#define SPX5_DSM_CAL_TAXIS 8
+#define SPX5_DSM_CAL_BW_LOSS 553
+
+#define SPX5_TAXI_PORT_MAX 70
+
+#define SPEED_12500 12500
+
+/* Maps from taxis to port numbers */
+static u32 sparx5_taxi_ports[SPX5_DSM_CAL_TAXIS][SPX5_DSM_CAL_MAX_DEVS_PER_TAXI] = {
+ {57, 12, 0, 1, 2, 16, 17, 18, 19, 20, 21, 22, 23},
+ {58, 13, 3, 4, 5, 24, 25, 26, 27, 28, 29, 30, 31},
+ {59, 14, 6, 7, 8, 32, 33, 34, 35, 36, 37, 38, 39},
+ {60, 15, 9, 10, 11, 40, 41, 42, 43, 44, 45, 46, 47},
+ {61, 48, 49, 50, 99, 99, 99, 99, 99, 99, 99, 99, 99},
+ {62, 51, 52, 53, 99, 99, 99, 99, 99, 99, 99, 99, 99},
+ {56, 63, 54, 55, 99, 99, 99, 99, 99, 99, 99, 99, 99},
+ {64, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99},
+};
+
+struct sparx5_calendar_data {
+ u32 schedule[SPX5_DSM_CAL_LEN];
+ u32 avg_dist[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI];
+ u32 taxi_ports[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI];
+ u32 taxi_speeds[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI];
+ u32 dev_slots[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI];
+ u32 new_slots[SPX5_DSM_CAL_LEN];
+ u32 temp_sched[SPX5_DSM_CAL_LEN];
+ u32 indices[SPX5_DSM_CAL_LEN];
+ u32 short_list[SPX5_DSM_CAL_LEN];
+ u32 long_list[SPX5_DSM_CAL_LEN];
+};
+
+static u32 sparx5_target_bandwidth(struct sparx5 *sparx5)
+{
+ switch (sparx5->target_ct) {
+ case SPX5_TARGET_CT_7546:
+ case SPX5_TARGET_CT_7546TSN:
+ return 65000;
+ case SPX5_TARGET_CT_7549:
+ case SPX5_TARGET_CT_7549TSN:
+ return 91000;
+ case SPX5_TARGET_CT_7552:
+ case SPX5_TARGET_CT_7552TSN:
+ return 129000;
+ case SPX5_TARGET_CT_7556:
+ case SPX5_TARGET_CT_7556TSN:
+ return 161000;
+ case SPX5_TARGET_CT_7558:
+ case SPX5_TARGET_CT_7558TSN:
+ return 201000;
+ default:
+ return 0;
+ }
+}
+
+/* This is used in calendar configuration */
+enum sparx5_cal_bw {
+ SPX5_CAL_SPEED_NONE = 0,
+ SPX5_CAL_SPEED_1G = 1,
+ SPX5_CAL_SPEED_2G5 = 2,
+ SPX5_CAL_SPEED_5G = 3,
+ SPX5_CAL_SPEED_10G = 4,
+ SPX5_CAL_SPEED_25G = 5,
+ SPX5_CAL_SPEED_0G5 = 6,
+ SPX5_CAL_SPEED_12G5 = 7
+};
+
+static u32 sparx5_clk_to_bandwidth(enum sparx5_core_clockfreq cclock)
+{
+ switch (cclock) {
+ case SPX5_CORE_CLOCK_250MHZ: return 83000; /* 250000 / 3 */
+ case SPX5_CORE_CLOCK_500MHZ: return 166000; /* 500000 / 3 */
+ case SPX5_CORE_CLOCK_625MHZ: return 208000; /* 625000 / 3 */
+ default: return 0;
+ }
+ return 0;
+}
+
+static u32 sparx5_cal_speed_to_value(enum sparx5_cal_bw speed)
+{
+ switch (speed) {
+ case SPX5_CAL_SPEED_1G: return 1000;
+ case SPX5_CAL_SPEED_2G5: return 2500;
+ case SPX5_CAL_SPEED_5G: return 5000;
+ case SPX5_CAL_SPEED_10G: return 10000;
+ case SPX5_CAL_SPEED_25G: return 25000;
+ case SPX5_CAL_SPEED_0G5: return 500;
+ case SPX5_CAL_SPEED_12G5: return 12500;
+ default: return 0;
+ }
+}
+
+static u32 sparx5_bandwidth_to_calendar(u32 bw)
+{
+ switch (bw) {
+ case SPEED_10: return SPX5_CAL_SPEED_0G5;
+ case SPEED_100: return SPX5_CAL_SPEED_0G5;
+ case SPEED_1000: return SPX5_CAL_SPEED_1G;
+ case SPEED_2500: return SPX5_CAL_SPEED_2G5;
+ case SPEED_5000: return SPX5_CAL_SPEED_5G;
+ case SPEED_10000: return SPX5_CAL_SPEED_10G;
+ case SPEED_12500: return SPX5_CAL_SPEED_12G5;
+ case SPEED_25000: return SPX5_CAL_SPEED_25G;
+ case SPEED_UNKNOWN: return SPX5_CAL_SPEED_1G;
+ default: return SPX5_CAL_SPEED_NONE;
+ }
+}
+
+static enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5,
+ u32 portno)
+{
+ struct sparx5_port *port;
+
+ if (portno >= SPX5_PORTS) {
+ /* Internal ports */
+ if (portno == SPX5_PORT_CPU_0 || portno == SPX5_PORT_CPU_1) {
+ /* Equals 1.25G */
+ return SPX5_CAL_SPEED_2G5;
+ } else if (portno == SPX5_PORT_VD0) {
+ /* IPMC only idle BW */
+ return SPX5_CAL_SPEED_NONE;
+ } else if (portno == SPX5_PORT_VD1) {
+ /* OAM only idle BW */
+ return SPX5_CAL_SPEED_NONE;
+ } else if (portno == SPX5_PORT_VD2) {
+ /* IPinIP gets only idle BW */
+ return SPX5_CAL_SPEED_NONE;
+ }
+ /* not in port map */
+ return SPX5_CAL_SPEED_NONE;
+ }
+ /* Front ports - may be used */
+ port = sparx5->ports[portno];
+ if (!port)
+ return SPX5_CAL_SPEED_NONE;
+ return sparx5_bandwidth_to_calendar(port->conf.bandwidth);
+}
+
+/* Auto configure the QSYS calendar based on port configuration */
+int sparx5_config_auto_calendar(struct sparx5 *sparx5)
+{
+ u32 cal[7], value, idx, portno;
+ u32 max_core_bw;
+ u32 total_bw = 0, used_port_bw = 0;
+ int err = 0;
+ enum sparx5_cal_bw spd;
+
+ memset(cal, 0, sizeof(cal));
+
+ max_core_bw = sparx5_clk_to_bandwidth(sparx5->coreclock);
+ if (max_core_bw == 0) {
+ dev_err(sparx5->dev, "Core clock not supported");
+ return -EINVAL;
+ }
+
+ /* Setup the calendar with the bandwidth to each port */
+ for (portno = 0; portno < SPX5_PORTS_ALL; portno++) {
+ u64 reg, offset, this_bw;
+
+ spd = sparx5_get_port_cal_speed(sparx5, portno);
+ if (spd == SPX5_CAL_SPEED_NONE)
+ continue;
+
+ this_bw = sparx5_cal_speed_to_value(spd);
+ if (portno < SPX5_PORTS)
+ used_port_bw += this_bw;
+ else
+ /* Internal ports are granted half the value */
+ this_bw = this_bw / 2;
+ total_bw += this_bw;
+ reg = portno;
+ offset = do_div(reg, SPX5_PORTS_PER_CALREG);
+ cal[reg] |= spd << (offset * SPX5_CALBITS_PER_PORT);
+ }
+
+ if (used_port_bw > sparx5_target_bandwidth(sparx5)) {
+ dev_err(sparx5->dev,
+ "Port BW %u above target BW %u\n",
+ used_port_bw, sparx5_target_bandwidth(sparx5));
+ return -EINVAL;
+ }
+
+ if (total_bw > max_core_bw) {
+ dev_err(sparx5->dev,
+ "Total BW %u above switch core BW %u\n",
+ total_bw, max_core_bw);
+ return -EINVAL;
+ }
+
+ /* Halt the calendar while changing it */
+ spx5_rmw(QSYS_CAL_CTRL_CAL_MODE_SET(10),
+ QSYS_CAL_CTRL_CAL_MODE,
+ sparx5, QSYS_CAL_CTRL);
+
+ /* Assign port bandwidth to auto calendar */
+ for (idx = 0; idx < ARRAY_SIZE(cal); idx++)
+ spx5_wr(cal[idx], sparx5, QSYS_CAL_AUTO(idx));
+
+ /* Increase grant rate of all ports to account for
+ * core clock ppm deviations
+ */
+ spx5_rmw(QSYS_CAL_CTRL_CAL_AUTO_GRANT_RATE_SET(671), /* 672->671 */
+ QSYS_CAL_CTRL_CAL_AUTO_GRANT_RATE,
+ sparx5,
+ QSYS_CAL_CTRL);
+
+ /* Grant idle usage to VD 0-2 */
+ for (idx = 2; idx < 5; idx++)
+ spx5_wr(HSCH_OUTB_SHARE_ENA_OUTB_SHARE_ENA_SET(12),
+ sparx5,
+ HSCH_OUTB_SHARE_ENA(idx));
+
+ /* Enable Auto mode */
+ spx5_rmw(QSYS_CAL_CTRL_CAL_MODE_SET(8),
+ QSYS_CAL_CTRL_CAL_MODE,
+ sparx5, QSYS_CAL_CTRL);
+
+ /* Verify successful calendar config */
+ value = spx5_rd(sparx5, QSYS_CAL_CTRL);
+ if (QSYS_CAL_CTRL_CAL_AUTO_ERROR_GET(value)) {
+ dev_err(sparx5->dev, "QSYS calendar error\n");
+ err = -EINVAL;
+ }
+ return err;
+}
+
+static u32 sparx5_dsm_exb_gcd(u32 a, u32 b)
+{
+ if (b == 0)
+ return a;
+ return sparx5_dsm_exb_gcd(b, a % b);
+}
+
+static u32 sparx5_dsm_cal_len(u32 *cal)
+{
+ u32 idx = 0, len = 0;
+
+ while (idx < SPX5_DSM_CAL_LEN) {
+ if (cal[idx] != SPX5_DSM_CAL_EMPTY)
+ len++;
+ idx++;
+ }
+ return len;
+}
+
+static u32 sparx5_dsm_cp_cal(u32 *sched)
+{
+ u32 idx = 0, tmp;
+
+ while (idx < SPX5_DSM_CAL_LEN) {
+ if (sched[idx] != SPX5_DSM_CAL_EMPTY) {
+ tmp = sched[idx];
+ sched[idx] = SPX5_DSM_CAL_EMPTY;
+ return tmp;
+ }
+ idx++;
+ }
+ return SPX5_DSM_CAL_EMPTY;
+}
+
+static int sparx5_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi,
+ struct sparx5_calendar_data *data)
+{
+ bool slow_mode;
+ u32 gcd, idx, sum, min, factor;
+ u32 num_of_slots, slot_spd, empty_slots;
+ u32 taxi_bw, clk_period_ps;
+
+ clk_period_ps = sparx5_clk_period(sparx5->coreclock);
+ taxi_bw = 128 * 1000000 / clk_period_ps;
+ slow_mode = !!(clk_period_ps > 2000);
+ memcpy(data->taxi_ports, &sparx5_taxi_ports[taxi],
+ sizeof(data->taxi_ports));
+
+ for (idx = 0; idx < SPX5_DSM_CAL_LEN; idx++) {
+ data->new_slots[idx] = SPX5_DSM_CAL_EMPTY;
+ data->schedule[idx] = SPX5_DSM_CAL_EMPTY;
+ data->temp_sched[idx] = SPX5_DSM_CAL_EMPTY;
+ }
+ /* Default empty calendar */
+ data->schedule[0] = SPX5_DSM_CAL_MAX_DEVS_PER_TAXI;
+
+ /* Map ports to taxi positions */
+ for (idx = 0; idx < SPX5_DSM_CAL_MAX_DEVS_PER_TAXI; idx++) {
+ u32 portno = data->taxi_ports[idx];
+
+ if (portno < SPX5_TAXI_PORT_MAX) {
+ data->taxi_speeds[idx] = sparx5_cal_speed_to_value
+ (sparx5_get_port_cal_speed(sparx5, portno));
+ } else {
+ data->taxi_speeds[idx] = 0;
+ }
+ }
+
+ sum = 0;
+ min = 25000;
+ for (idx = 0; idx < ARRAY_SIZE(data->taxi_speeds); idx++) {
+ u32 jdx;
+
+ sum += data->taxi_speeds[idx];
+ if (data->taxi_speeds[idx] && data->taxi_speeds[idx] < min)
+ min = data->taxi_speeds[idx];
+ gcd = min;
+ for (jdx = 0; jdx < ARRAY_SIZE(data->taxi_speeds); jdx++)
+ gcd = sparx5_dsm_exb_gcd(gcd, data->taxi_speeds[jdx]);
+ }
+ if (sum == 0) /* Empty calendar */
+ return 0;
+ /* Make room for overhead traffic */
+ factor = 100 * 100 * 1000 / (100 * 100 - SPX5_DSM_CAL_BW_LOSS);
+
+ if (sum * factor > (taxi_bw * 1000)) {
+ dev_err(sparx5->dev,
+ "Taxi %u, Requested BW %u above available BW %u\n",
+ taxi, sum, taxi_bw);
+ return -EINVAL;
+ }
+ for (idx = 0; idx < 4; idx++) {
+ u32 raw_spd;
+
+ if (idx == 0)
+ raw_spd = gcd / 5;
+ else if (idx == 1)
+ raw_spd = gcd / 2;
+ else if (idx == 2)
+ raw_spd = gcd;
+ else
+ raw_spd = min;
+ slot_spd = raw_spd * factor / 1000;
+ num_of_slots = taxi_bw / slot_spd;
+ if (num_of_slots <= 64)
+ break;
+ }
+
+ num_of_slots = num_of_slots > 64 ? 64 : num_of_slots;
+ slot_spd = taxi_bw / num_of_slots;
+
+ sum = 0;
+ for (idx = 0; idx < ARRAY_SIZE(data->taxi_speeds); idx++) {
+ u32 spd = data->taxi_speeds[idx];
+ u32 adjusted_speed = data->taxi_speeds[idx] * factor / 1000;
+
+ if (adjusted_speed > 0) {
+ data->avg_dist[idx] = (128 * 1000000 * 10) /
+ (adjusted_speed * clk_period_ps);
+ } else {
+ data->avg_dist[idx] = -1;
+ }
+ data->dev_slots[idx] = ((spd * factor / slot_spd) + 999) / 1000;
+ if (spd != 25000 && (spd != 10000 || !slow_mode)) {
+ if (num_of_slots < (5 * data->dev_slots[idx])) {
+ dev_err(sparx5->dev,
+ "Taxi %u, speed %u, Low slot sep.\n",
+ taxi, spd);
+ return -EINVAL;
+ }
+ }
+ sum += data->dev_slots[idx];
+ if (sum > num_of_slots) {
+ dev_err(sparx5->dev,
+ "Taxi %u with overhead factor %u\n",
+ taxi, factor);
+ return -EINVAL;
+ }
+ }
+
+ empty_slots = num_of_slots - sum;
+
+ for (idx = 0; idx < empty_slots; idx++)
+ data->schedule[idx] = SPX5_DSM_CAL_MAX_DEVS_PER_TAXI;
+
+ for (idx = 1; idx < num_of_slots; idx++) {
+ u32 indices_len = 0;
+ u32 slot, jdx, kdx, ts;
+ s32 cnt;
+ u32 num_of_old_slots, num_of_new_slots, tgt_score;
+
+ for (slot = 0; slot < ARRAY_SIZE(data->dev_slots); slot++) {
+ if (data->dev_slots[slot] == idx) {
+ data->indices[indices_len] = slot;
+ indices_len++;
+ }
+ }
+ if (indices_len == 0)
+ continue;
+ kdx = 0;
+ for (slot = 0; slot < idx; slot++) {
+ for (jdx = 0; jdx < indices_len; jdx++, kdx++)
+ data->new_slots[kdx] = data->indices[jdx];
+ }
+
+ for (slot = 0; slot < SPX5_DSM_CAL_LEN; slot++) {
+ if (data->schedule[slot] == SPX5_DSM_CAL_EMPTY)
+ break;
+ }
+
+ num_of_old_slots = slot;
+ num_of_new_slots = kdx;
+ cnt = 0;
+ ts = 0;
+
+ if (num_of_new_slots > num_of_old_slots) {
+ memcpy(data->short_list, data->schedule,
+ sizeof(data->short_list));
+ memcpy(data->long_list, data->new_slots,
+ sizeof(data->long_list));
+ tgt_score = 100000 * num_of_old_slots /
+ num_of_new_slots;
+ } else {
+ memcpy(data->short_list, data->new_slots,
+ sizeof(data->short_list));
+ memcpy(data->long_list, data->schedule,
+ sizeof(data->long_list));
+ tgt_score = 100000 * num_of_new_slots /
+ num_of_old_slots;
+ }
+
+ while (sparx5_dsm_cal_len(data->short_list) > 0 ||
+ sparx5_dsm_cal_len(data->long_list) > 0) {
+ u32 act = 0;
+
+ if (sparx5_dsm_cal_len(data->short_list) > 0) {
+ data->temp_sched[ts] =
+ sparx5_dsm_cp_cal(data->short_list);
+ ts++;
+ cnt += 100000;
+ act = 1;
+ }
+ while (sparx5_dsm_cal_len(data->long_list) > 0 &&
+ cnt > 0) {
+ data->temp_sched[ts] =
+ sparx5_dsm_cp_cal(data->long_list);
+ ts++;
+ cnt -= tgt_score;
+ act = 1;
+ }
+ if (act == 0) {
+ dev_err(sparx5->dev,
+ "Error in DSM calendar calculation\n");
+ return -EINVAL;
+ }
+ }
+
+ for (slot = 0; slot < SPX5_DSM_CAL_LEN; slot++) {
+ if (data->temp_sched[slot] == SPX5_DSM_CAL_EMPTY)
+ break;
+ }
+ for (slot = 0; slot < SPX5_DSM_CAL_LEN; slot++) {
+ data->schedule[slot] = data->temp_sched[slot];
+ data->temp_sched[slot] = SPX5_DSM_CAL_EMPTY;
+ data->new_slots[slot] = SPX5_DSM_CAL_EMPTY;
+ }
+ }
+ return 0;
+}
+
+static int sparx5_dsm_calendar_check(struct sparx5 *sparx5,
+ struct sparx5_calendar_data *data)
+{
+ u32 num_of_slots, idx, port;
+ int cnt, max_dist;
+ u32 slot_indices[SPX5_DSM_CAL_LEN], distances[SPX5_DSM_CAL_LEN];
+ u32 cal_length = sparx5_dsm_cal_len(data->schedule);
+
+ for (port = 0; port < SPX5_DSM_CAL_MAX_DEVS_PER_TAXI; port++) {
+ num_of_slots = 0;
+ max_dist = data->avg_dist[port];
+ for (idx = 0; idx < SPX5_DSM_CAL_LEN; idx++) {
+ slot_indices[idx] = SPX5_DSM_CAL_EMPTY;
+ distances[idx] = SPX5_DSM_CAL_EMPTY;
+ }
+
+ for (idx = 0; idx < cal_length; idx++) {
+ if (data->schedule[idx] == port) {
+ slot_indices[num_of_slots] = idx;
+ num_of_slots++;
+ }
+ }
+
+ slot_indices[num_of_slots] = slot_indices[0] + cal_length;
+
+ for (idx = 0; idx < num_of_slots; idx++) {
+ distances[idx] = (slot_indices[idx + 1] -
+ slot_indices[idx]) * 10;
+ }
+
+ for (idx = 0; idx < num_of_slots; idx++) {
+ u32 jdx, kdx;
+
+ cnt = distances[idx] - max_dist;
+ if (cnt < 0)
+ cnt = -cnt;
+ kdx = 0;
+ for (jdx = (idx + 1) % num_of_slots;
+ jdx != idx;
+ jdx = (jdx + 1) % num_of_slots, kdx++) {
+ cnt = cnt + distances[jdx] - max_dist;
+ if (cnt < 0)
+ cnt = -cnt;
+ if (cnt > max_dist)
+ goto check_err;
+ }
+ }
+ }
+ return 0;
+check_err:
+ dev_err(sparx5->dev,
+ "Port %u: distance %u above limit %d\n",
+ port, cnt, max_dist);
+ return -EINVAL;
+}
+
+static int sparx5_dsm_calendar_update(struct sparx5 *sparx5, u32 taxi,
+ struct sparx5_calendar_data *data)
+{
+ u32 idx;
+ u32 cal_len = sparx5_dsm_cal_len(data->schedule), len;
+
+ spx5_wr(DSM_TAXI_CAL_CFG_CAL_PGM_ENA_SET(1),
+ sparx5,
+ DSM_TAXI_CAL_CFG(taxi));
+ for (idx = 0; idx < cal_len; idx++) {
+ spx5_rmw(DSM_TAXI_CAL_CFG_CAL_IDX_SET(idx),
+ DSM_TAXI_CAL_CFG_CAL_IDX,
+ sparx5,
+ DSM_TAXI_CAL_CFG(taxi));
+ spx5_rmw(DSM_TAXI_CAL_CFG_CAL_PGM_VAL_SET(data->schedule[idx]),
+ DSM_TAXI_CAL_CFG_CAL_PGM_VAL,
+ sparx5,
+ DSM_TAXI_CAL_CFG(taxi));
+ }
+ spx5_wr(DSM_TAXI_CAL_CFG_CAL_PGM_ENA_SET(0),
+ sparx5,
+ DSM_TAXI_CAL_CFG(taxi));
+ len = DSM_TAXI_CAL_CFG_CAL_CUR_LEN_GET(spx5_rd(sparx5,
+ DSM_TAXI_CAL_CFG(taxi)));
+ if (len != cal_len - 1)
+ goto update_err;
+ return 0;
+update_err:
+ dev_err(sparx5->dev, "Incorrect calendar length: %u\n", len);
+ return -EINVAL;
+}
+
+/* Configure the DSM calendar based on port configuration */
+int sparx5_config_dsm_calendar(struct sparx5 *sparx5)
+{
+ int taxi;
+ struct sparx5_calendar_data *data;
+ int err = 0;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ for (taxi = 0; taxi < SPX5_DSM_CAL_TAXIS; ++taxi) {
+ err = sparx5_dsm_calendar_calc(sparx5, taxi, data);
+ if (err) {
+ dev_err(sparx5->dev, "DSM calendar calculation failed\n");
+ goto cal_out;
+ }
+ err = sparx5_dsm_calendar_check(sparx5, data);
+ if (err) {
+ dev_err(sparx5->dev, "DSM calendar check failed\n");
+ goto cal_out;
+ }
+ err = sparx5_dsm_calendar_update(sparx5, taxi, data);
+ if (err) {
+ dev_err(sparx5->dev, "DSM calendar update failed\n");
+ goto cal_out;
+ }
+ }
+cal_out:
+ kfree(data);
+ return err;
+}
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c
new file mode 100644
index 000000000000..59783fc46a7b
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c
@@ -0,0 +1,1227 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include <linux/ethtool.h>
+
+#include "sparx5_main_regs.h"
+#include "sparx5_main.h"
+#include "sparx5_port.h"
+
+/* Index of ANA_AC port counters */
+#define SPX5_PORT_POLICER_DROPS 0
+
+/* Add a potentially wrapping 32 bit value to a 64 bit counter */
+static void sparx5_update_counter(u64 *cnt, u32 val)
+{
+ if (val < (*cnt & U32_MAX))
+ *cnt += (u64)1 << 32; /* value has wrapped */
+ *cnt = (*cnt & ~(u64)U32_MAX) + val;
+}
+
+enum sparx5_stats_entry {
+ spx5_stats_rx_symbol_err_cnt = 0,
+ spx5_stats_pmac_rx_symbol_err_cnt = 1,
+ spx5_stats_tx_uc_cnt = 2,
+ spx5_stats_pmac_tx_uc_cnt = 3,
+ spx5_stats_tx_mc_cnt = 4,
+ spx5_stats_tx_bc_cnt = 5,
+ spx5_stats_tx_backoff1_cnt = 6,
+ spx5_stats_tx_multi_coll_cnt = 7,
+ spx5_stats_rx_uc_cnt = 8,
+ spx5_stats_pmac_rx_uc_cnt = 9,
+ spx5_stats_rx_mc_cnt = 10,
+ spx5_stats_rx_bc_cnt = 11,
+ spx5_stats_rx_crc_err_cnt = 12,
+ spx5_stats_pmac_rx_crc_err_cnt = 13,
+ spx5_stats_rx_alignment_lost_cnt = 14,
+ spx5_stats_pmac_rx_alignment_lost_cnt = 15,
+ spx5_stats_tx_ok_bytes_cnt = 16,
+ spx5_stats_pmac_tx_ok_bytes_cnt = 17,
+ spx5_stats_tx_defer_cnt = 18,
+ spx5_stats_tx_late_coll_cnt = 19,
+ spx5_stats_tx_xcoll_cnt = 20,
+ spx5_stats_tx_csense_cnt = 21,
+ spx5_stats_rx_ok_bytes_cnt = 22,
+ spx5_stats_pmac_rx_ok_bytes_cnt = 23,
+ spx5_stats_pmac_tx_mc_cnt = 24,
+ spx5_stats_pmac_tx_bc_cnt = 25,
+ spx5_stats_tx_xdefer_cnt = 26,
+ spx5_stats_pmac_rx_mc_cnt = 27,
+ spx5_stats_pmac_rx_bc_cnt = 28,
+ spx5_stats_rx_in_range_len_err_cnt = 29,
+ spx5_stats_pmac_rx_in_range_len_err_cnt = 30,
+ spx5_stats_rx_out_of_range_len_err_cnt = 31,
+ spx5_stats_pmac_rx_out_of_range_len_err_cnt = 32,
+ spx5_stats_rx_oversize_cnt = 33,
+ spx5_stats_pmac_rx_oversize_cnt = 34,
+ spx5_stats_tx_pause_cnt = 35,
+ spx5_stats_pmac_tx_pause_cnt = 36,
+ spx5_stats_rx_pause_cnt = 37,
+ spx5_stats_pmac_rx_pause_cnt = 38,
+ spx5_stats_rx_unsup_opcode_cnt = 39,
+ spx5_stats_pmac_rx_unsup_opcode_cnt = 40,
+ spx5_stats_rx_undersize_cnt = 41,
+ spx5_stats_pmac_rx_undersize_cnt = 42,
+ spx5_stats_rx_fragments_cnt = 43,
+ spx5_stats_pmac_rx_fragments_cnt = 44,
+ spx5_stats_rx_jabbers_cnt = 45,
+ spx5_stats_pmac_rx_jabbers_cnt = 46,
+ spx5_stats_rx_size64_cnt = 47,
+ spx5_stats_pmac_rx_size64_cnt = 48,
+ spx5_stats_rx_size65to127_cnt = 49,
+ spx5_stats_pmac_rx_size65to127_cnt = 50,
+ spx5_stats_rx_size128to255_cnt = 51,
+ spx5_stats_pmac_rx_size128to255_cnt = 52,
+ spx5_stats_rx_size256to511_cnt = 53,
+ spx5_stats_pmac_rx_size256to511_cnt = 54,
+ spx5_stats_rx_size512to1023_cnt = 55,
+ spx5_stats_pmac_rx_size512to1023_cnt = 56,
+ spx5_stats_rx_size1024to1518_cnt = 57,
+ spx5_stats_pmac_rx_size1024to1518_cnt = 58,
+ spx5_stats_rx_size1519tomax_cnt = 59,
+ spx5_stats_pmac_rx_size1519tomax_cnt = 60,
+ spx5_stats_tx_size64_cnt = 61,
+ spx5_stats_pmac_tx_size64_cnt = 62,
+ spx5_stats_tx_size65to127_cnt = 63,
+ spx5_stats_pmac_tx_size65to127_cnt = 64,
+ spx5_stats_tx_size128to255_cnt = 65,
+ spx5_stats_pmac_tx_size128to255_cnt = 66,
+ spx5_stats_tx_size256to511_cnt = 67,
+ spx5_stats_pmac_tx_size256to511_cnt = 68,
+ spx5_stats_tx_size512to1023_cnt = 69,
+ spx5_stats_pmac_tx_size512to1023_cnt = 70,
+ spx5_stats_tx_size1024to1518_cnt = 71,
+ spx5_stats_pmac_tx_size1024to1518_cnt = 72,
+ spx5_stats_tx_size1519tomax_cnt = 73,
+ spx5_stats_pmac_tx_size1519tomax_cnt = 74,
+ spx5_stats_mm_rx_assembly_err_cnt = 75,
+ spx5_stats_mm_rx_assembly_ok_cnt = 76,
+ spx5_stats_mm_rx_merge_frag_cnt = 77,
+ spx5_stats_mm_rx_smd_err_cnt = 78,
+ spx5_stats_mm_tx_pfragment_cnt = 79,
+ spx5_stats_rx_bad_bytes_cnt = 80,
+ spx5_stats_pmac_rx_bad_bytes_cnt = 81,
+ spx5_stats_rx_in_bytes_cnt = 82,
+ spx5_stats_rx_ipg_shrink_cnt = 83,
+ spx5_stats_rx_sync_lost_err_cnt = 84,
+ spx5_stats_rx_tagged_frms_cnt = 85,
+ spx5_stats_rx_untagged_frms_cnt = 86,
+ spx5_stats_tx_out_bytes_cnt = 87,
+ spx5_stats_tx_tagged_frms_cnt = 88,
+ spx5_stats_tx_untagged_frms_cnt = 89,
+ spx5_stats_rx_hih_cksm_err_cnt = 90,
+ spx5_stats_pmac_rx_hih_cksm_err_cnt = 91,
+ spx5_stats_rx_xgmii_prot_err_cnt = 92,
+ spx5_stats_pmac_rx_xgmii_prot_err_cnt = 93,
+ spx5_stats_ana_ac_port_stat_lsb_cnt = 94,
+ spx5_stats_green_p0_rx_fwd = 95,
+ spx5_stats_green_p0_rx_port_drop = 111,
+ spx5_stats_green_p0_tx_port = 127,
+ spx5_stats_rx_local_drop = 143,
+ spx5_stats_tx_local_drop = 144,
+ spx5_stats_count = 145,
+};
+
+static const char *const sparx5_stats_layout[] = {
+ "mm_rx_assembly_err_cnt",
+ "mm_rx_assembly_ok_cnt",
+ "mm_rx_merge_frag_cnt",
+ "mm_rx_smd_err_cnt",
+ "mm_tx_pfragment_cnt",
+ "rx_bad_bytes_cnt",
+ "pmac_rx_bad_bytes_cnt",
+ "rx_in_bytes_cnt",
+ "rx_ipg_shrink_cnt",
+ "rx_sync_lost_err_cnt",
+ "rx_tagged_frms_cnt",
+ "rx_untagged_frms_cnt",
+ "tx_out_bytes_cnt",
+ "tx_tagged_frms_cnt",
+ "tx_untagged_frms_cnt",
+ "rx_hih_cksm_err_cnt",
+ "pmac_rx_hih_cksm_err_cnt",
+ "rx_xgmii_prot_err_cnt",
+ "pmac_rx_xgmii_prot_err_cnt",
+ "rx_port_policer_drop",
+ "rx_fwd_green_p0",
+ "rx_fwd_green_p1",
+ "rx_fwd_green_p2",
+ "rx_fwd_green_p3",
+ "rx_fwd_green_p4",
+ "rx_fwd_green_p5",
+ "rx_fwd_green_p6",
+ "rx_fwd_green_p7",
+ "rx_fwd_yellow_p0",
+ "rx_fwd_yellow_p1",
+ "rx_fwd_yellow_p2",
+ "rx_fwd_yellow_p3",
+ "rx_fwd_yellow_p4",
+ "rx_fwd_yellow_p5",
+ "rx_fwd_yellow_p6",
+ "rx_fwd_yellow_p7",
+ "rx_port_drop_green_p0",
+ "rx_port_drop_green_p1",
+ "rx_port_drop_green_p2",
+ "rx_port_drop_green_p3",
+ "rx_port_drop_green_p4",
+ "rx_port_drop_green_p5",
+ "rx_port_drop_green_p6",
+ "rx_port_drop_green_p7",
+ "rx_port_drop_yellow_p0",
+ "rx_port_drop_yellow_p1",
+ "rx_port_drop_yellow_p2",
+ "rx_port_drop_yellow_p3",
+ "rx_port_drop_yellow_p4",
+ "rx_port_drop_yellow_p5",
+ "rx_port_drop_yellow_p6",
+ "rx_port_drop_yellow_p7",
+ "tx_port_green_p0",
+ "tx_port_green_p1",
+ "tx_port_green_p2",
+ "tx_port_green_p3",
+ "tx_port_green_p4",
+ "tx_port_green_p5",
+ "tx_port_green_p6",
+ "tx_port_green_p7",
+ "tx_port_yellow_p0",
+ "tx_port_yellow_p1",
+ "tx_port_yellow_p2",
+ "tx_port_yellow_p3",
+ "tx_port_yellow_p4",
+ "tx_port_yellow_p5",
+ "tx_port_yellow_p6",
+ "tx_port_yellow_p7",
+ "rx_local_drop",
+ "tx_local_drop",
+};
+
+static void sparx5_get_queue_sys_stats(struct sparx5 *sparx5, int portno)
+{
+ u64 *portstats;
+ u64 *stats;
+ u32 addr;
+ int idx;
+
+ portstats = &sparx5->stats[portno * sparx5->num_stats];
+ mutex_lock(&sparx5->queue_stats_lock);
+ spx5_wr(XQS_STAT_CFG_STAT_VIEW_SET(portno), sparx5, XQS_STAT_CFG);
+ addr = 0;
+ stats = &portstats[spx5_stats_green_p0_rx_fwd];
+ for (idx = 0; idx < 2 * SPX5_PRIOS; ++idx, ++addr, ++stats)
+ sparx5_update_counter(stats, spx5_rd(sparx5, XQS_CNT(addr)));
+ addr = 16;
+ stats = &portstats[spx5_stats_green_p0_rx_port_drop];
+ for (idx = 0; idx < 2 * SPX5_PRIOS; ++idx, ++addr, ++stats)
+ sparx5_update_counter(stats, spx5_rd(sparx5, XQS_CNT(addr)));
+ addr = 256;
+ stats = &portstats[spx5_stats_green_p0_tx_port];
+ for (idx = 0; idx < 2 * SPX5_PRIOS; ++idx, ++addr, ++stats)
+ sparx5_update_counter(stats, spx5_rd(sparx5, XQS_CNT(addr)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_local_drop],
+ spx5_rd(sparx5, XQS_CNT(32)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_local_drop],
+ spx5_rd(sparx5, XQS_CNT(272)));
+ mutex_unlock(&sparx5->queue_stats_lock);
+}
+
+static void sparx5_get_ana_ac_stats_stats(struct sparx5 *sparx5, int portno)
+{
+ u64 *portstats = &sparx5->stats[portno * sparx5->num_stats];
+
+ sparx5_update_counter(&portstats[spx5_stats_ana_ac_port_stat_lsb_cnt],
+ spx5_rd(sparx5, ANA_AC_PORT_STAT_LSB_CNT(portno,
+ SPX5_PORT_POLICER_DROPS)));
+}
+
+static void sparx5_get_dev_phy_stats(u64 *portstats, void __iomem *inst, u32
+ tinst)
+{
+ sparx5_update_counter(&portstats[spx5_stats_rx_symbol_err_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_SYMBOL_ERR_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_symbol_err_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_SYMBOL_ERR_CNT(tinst)));
+}
+
+static void sparx5_get_dev_mac_stats(u64 *portstats, void __iomem *inst, u32
+ tinst)
+{
+ sparx5_update_counter(&portstats[spx5_stats_tx_uc_cnt],
+ spx5_inst_rd(inst, DEV5G_TX_UC_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_uc_cnt],
+ spx5_inst_rd(inst, DEV5G_PMAC_TX_UC_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_mc_cnt],
+ spx5_inst_rd(inst, DEV5G_TX_MC_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_bc_cnt],
+ spx5_inst_rd(inst, DEV5G_TX_BC_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_uc_cnt],
+ spx5_inst_rd(inst, DEV5G_RX_UC_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_uc_cnt],
+ spx5_inst_rd(inst, DEV5G_PMAC_RX_UC_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_mc_cnt],
+ spx5_inst_rd(inst, DEV5G_RX_MC_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_bc_cnt],
+ spx5_inst_rd(inst, DEV5G_RX_BC_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_crc_err_cnt],
+ spx5_inst_rd(inst, DEV5G_RX_CRC_ERR_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_crc_err_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_CRC_ERR_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_alignment_lost_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_ALIGNMENT_LOST_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_alignment_lost_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_ALIGNMENT_LOST_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_ok_bytes_cnt],
+ spx5_inst_rd(inst, DEV5G_TX_OK_BYTES_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_ok_bytes_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_TX_OK_BYTES_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_ok_bytes_cnt],
+ spx5_inst_rd(inst, DEV5G_RX_OK_BYTES_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_ok_bytes_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_OK_BYTES_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_mc_cnt],
+ spx5_inst_rd(inst, DEV5G_PMAC_TX_MC_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_bc_cnt],
+ spx5_inst_rd(inst, DEV5G_PMAC_TX_BC_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_mc_cnt],
+ spx5_inst_rd(inst, DEV5G_PMAC_RX_MC_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_bc_cnt],
+ spx5_inst_rd(inst, DEV5G_PMAC_RX_BC_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_in_range_len_err_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_IN_RANGE_LEN_ERR_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_in_range_len_err_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_IN_RANGE_LEN_ERR_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_out_of_range_len_err_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_OUT_OF_RANGE_LEN_ERR_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_out_of_range_len_err_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_oversize_cnt],
+ spx5_inst_rd(inst, DEV5G_RX_OVERSIZE_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_oversize_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_OVERSIZE_CNT(tinst)));
+}
+
+static void sparx5_get_dev_mac_ctrl_stats(u64 *portstats, void __iomem *inst,
+ u32 tinst)
+{
+ sparx5_update_counter(&portstats[spx5_stats_tx_pause_cnt],
+ spx5_inst_rd(inst, DEV5G_TX_PAUSE_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_pause_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_TX_PAUSE_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_pause_cnt],
+ spx5_inst_rd(inst, DEV5G_RX_PAUSE_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_pause_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_PAUSE_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_unsup_opcode_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_UNSUP_OPCODE_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_unsup_opcode_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_UNSUP_OPCODE_CNT(tinst)));
+}
+
+static void sparx5_get_dev_rmon_stats(u64 *portstats, void __iomem *inst, u32
+ tinst)
+{
+ sparx5_update_counter(&portstats[spx5_stats_rx_undersize_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_UNDERSIZE_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_undersize_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_UNDERSIZE_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_oversize_cnt],
+ spx5_inst_rd(inst, DEV5G_RX_OVERSIZE_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_oversize_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_OVERSIZE_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_fragments_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_FRAGMENTS_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_fragments_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_FRAGMENTS_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_jabbers_cnt],
+ spx5_inst_rd(inst, DEV5G_RX_JABBERS_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_jabbers_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_JABBERS_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_size64_cnt],
+ spx5_inst_rd(inst, DEV5G_RX_SIZE64_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size64_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_SIZE64_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_size65to127_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_SIZE65TO127_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size65to127_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_SIZE65TO127_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_size128to255_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_SIZE128TO255_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size128to255_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_SIZE128TO255_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_size256to511_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_SIZE256TO511_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size256to511_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_SIZE256TO511_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_size512to1023_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_SIZE512TO1023_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size512to1023_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_SIZE512TO1023_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_size1024to1518_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_SIZE1024TO1518_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size1024to1518_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_SIZE1024TO1518_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_size1519tomax_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_SIZE1519TOMAX_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size1519tomax_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_SIZE1519TOMAX_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_size64_cnt],
+ spx5_inst_rd(inst, DEV5G_TX_SIZE64_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size64_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_TX_SIZE64_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_size65to127_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_TX_SIZE65TO127_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size65to127_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_TX_SIZE65TO127_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_size128to255_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_TX_SIZE128TO255_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size128to255_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_TX_SIZE128TO255_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_size256to511_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_TX_SIZE256TO511_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size256to511_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_TX_SIZE256TO511_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_size512to1023_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_TX_SIZE512TO1023_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size512to1023_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_TX_SIZE512TO1023_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_size1024to1518_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_TX_SIZE1024TO1518_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size1024to1518_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_TX_SIZE1024TO1518_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_size1519tomax_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_TX_SIZE1519TOMAX_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size1519tomax_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_TX_SIZE1519TOMAX_CNT(tinst)));
+}
+
+static void sparx5_get_dev_misc_stats(u64 *portstats, void __iomem *inst, u32
+ tinst)
+{
+ sparx5_update_counter(&portstats[spx5_stats_mm_rx_assembly_err_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_MM_RX_ASSEMBLY_ERR_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_mm_rx_assembly_ok_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_MM_RX_ASSEMBLY_OK_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_mm_rx_merge_frag_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_MM_RX_MERGE_FRAG_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_mm_rx_smd_err_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_MM_RX_SMD_ERR_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_mm_tx_pfragment_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_MM_TX_PFRAGMENT_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_bad_bytes_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_BAD_BYTES_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_bad_bytes_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_BAD_BYTES_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_in_bytes_cnt],
+ spx5_inst_rd(inst, DEV5G_RX_IN_BYTES_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_ipg_shrink_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_IPG_SHRINK_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_tagged_frms_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_TAGGED_FRMS_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_untagged_frms_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_UNTAGGED_FRMS_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_out_bytes_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_TX_OUT_BYTES_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_tagged_frms_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_TX_TAGGED_FRMS_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_untagged_frms_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_TX_UNTAGGED_FRMS_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_hih_cksm_err_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_HIH_CKSM_ERR_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_hih_cksm_err_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_HIH_CKSM_ERR_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_xgmii_prot_err_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_RX_XGMII_PROT_ERR_CNT(tinst)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_xgmii_prot_err_cnt],
+ spx5_inst_rd(inst,
+ DEV5G_PMAC_RX_XGMII_PROT_ERR_CNT(tinst)));
+}
+
+static void sparx5_get_device_stats(struct sparx5 *sparx5, int portno)
+{
+ u64 *portstats = &sparx5->stats[portno * sparx5->num_stats];
+ u32 tinst = sparx5_port_dev_index(portno);
+ u32 dev = sparx5_to_high_dev(portno);
+ void __iomem *inst;
+
+ inst = spx5_inst_get(sparx5, dev, tinst);
+ sparx5_get_dev_phy_stats(portstats, inst, tinst);
+ sparx5_get_dev_mac_stats(portstats, inst, tinst);
+ sparx5_get_dev_mac_ctrl_stats(portstats, inst, tinst);
+ sparx5_get_dev_rmon_stats(portstats, inst, tinst);
+ sparx5_get_dev_misc_stats(portstats, inst, tinst);
+}
+
+static void sparx5_get_asm_phy_stats(u64 *portstats, void __iomem *inst, int
+ portno)
+{
+ sparx5_update_counter(&portstats[spx5_stats_rx_symbol_err_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_SYMBOL_ERR_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_symbol_err_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_SYMBOL_ERR_CNT(portno)));
+}
+
+static void sparx5_get_asm_mac_stats(u64 *portstats, void __iomem *inst, int
+ portno)
+{
+ sparx5_update_counter(&portstats[spx5_stats_tx_uc_cnt],
+ spx5_inst_rd(inst, ASM_TX_UC_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_uc_cnt],
+ spx5_inst_rd(inst, ASM_PMAC_TX_UC_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_mc_cnt],
+ spx5_inst_rd(inst, ASM_TX_MC_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_bc_cnt],
+ spx5_inst_rd(inst, ASM_TX_BC_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_backoff1_cnt],
+ spx5_inst_rd(inst, ASM_TX_BACKOFF1_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_multi_coll_cnt],
+ spx5_inst_rd(inst,
+ ASM_TX_MULTI_COLL_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_uc_cnt],
+ spx5_inst_rd(inst, ASM_RX_UC_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_uc_cnt],
+ spx5_inst_rd(inst, ASM_PMAC_RX_UC_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_mc_cnt],
+ spx5_inst_rd(inst, ASM_RX_MC_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_bc_cnt],
+ spx5_inst_rd(inst, ASM_RX_BC_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_crc_err_cnt],
+ spx5_inst_rd(inst, ASM_RX_CRC_ERR_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_crc_err_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_CRC_ERR_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_alignment_lost_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_ALIGNMENT_LOST_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_alignment_lost_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_ALIGNMENT_LOST_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_ok_bytes_cnt],
+ spx5_inst_rd(inst, ASM_TX_OK_BYTES_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_ok_bytes_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_TX_OK_BYTES_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_defer_cnt],
+ spx5_inst_rd(inst, ASM_TX_DEFER_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_late_coll_cnt],
+ spx5_inst_rd(inst, ASM_TX_LATE_COLL_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_xcoll_cnt],
+ spx5_inst_rd(inst, ASM_TX_XCOLL_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_csense_cnt],
+ spx5_inst_rd(inst, ASM_TX_CSENSE_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_ok_bytes_cnt],
+ spx5_inst_rd(inst, ASM_RX_OK_BYTES_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_ok_bytes_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_OK_BYTES_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_mc_cnt],
+ spx5_inst_rd(inst, ASM_PMAC_TX_MC_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_bc_cnt],
+ spx5_inst_rd(inst, ASM_PMAC_TX_BC_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_xdefer_cnt],
+ spx5_inst_rd(inst, ASM_TX_XDEFER_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_mc_cnt],
+ spx5_inst_rd(inst, ASM_PMAC_RX_MC_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_bc_cnt],
+ spx5_inst_rd(inst, ASM_PMAC_RX_BC_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_in_range_len_err_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_IN_RANGE_LEN_ERR_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_in_range_len_err_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_IN_RANGE_LEN_ERR_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_out_of_range_len_err_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_OUT_OF_RANGE_LEN_ERR_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_out_of_range_len_err_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_oversize_cnt],
+ spx5_inst_rd(inst, ASM_RX_OVERSIZE_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_oversize_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_OVERSIZE_CNT(portno)));
+}
+
+static void sparx5_get_asm_mac_ctrl_stats(u64 *portstats, void __iomem *inst,
+ int portno)
+{
+ sparx5_update_counter(&portstats[spx5_stats_tx_pause_cnt],
+ spx5_inst_rd(inst, ASM_TX_PAUSE_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_pause_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_TX_PAUSE_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_pause_cnt],
+ spx5_inst_rd(inst, ASM_RX_PAUSE_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_pause_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_PAUSE_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_unsup_opcode_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_UNSUP_OPCODE_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_unsup_opcode_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_UNSUP_OPCODE_CNT(portno)));
+}
+
+static void sparx5_get_asm_rmon_stats(u64 *portstats, void __iomem *inst, int
+ portno)
+{
+ sparx5_update_counter(&portstats[spx5_stats_rx_undersize_cnt],
+ spx5_inst_rd(inst, ASM_RX_UNDERSIZE_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_undersize_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_UNDERSIZE_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_oversize_cnt],
+ spx5_inst_rd(inst, ASM_RX_OVERSIZE_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_oversize_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_OVERSIZE_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_fragments_cnt],
+ spx5_inst_rd(inst, ASM_RX_FRAGMENTS_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_fragments_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_FRAGMENTS_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_jabbers_cnt],
+ spx5_inst_rd(inst, ASM_RX_JABBERS_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_jabbers_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_JABBERS_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_size64_cnt],
+ spx5_inst_rd(inst, ASM_RX_SIZE64_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size64_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_SIZE64_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_size65to127_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_SIZE65TO127_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size65to127_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_SIZE65TO127_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_size128to255_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_SIZE128TO255_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size128to255_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_SIZE128TO255_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_size256to511_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_SIZE256TO511_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size256to511_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_SIZE256TO511_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_size512to1023_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_SIZE512TO1023_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size512to1023_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_SIZE512TO1023_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_size1024to1518_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_SIZE1024TO1518_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size1024to1518_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_SIZE1024TO1518_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_size1519tomax_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_SIZE1519TOMAX_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size1519tomax_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_SIZE1519TOMAX_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_size64_cnt],
+ spx5_inst_rd(inst, ASM_TX_SIZE64_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size64_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_TX_SIZE64_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_size65to127_cnt],
+ spx5_inst_rd(inst,
+ ASM_TX_SIZE65TO127_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size65to127_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_TX_SIZE65TO127_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_size128to255_cnt],
+ spx5_inst_rd(inst,
+ ASM_TX_SIZE128TO255_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size128to255_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_TX_SIZE128TO255_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_size256to511_cnt],
+ spx5_inst_rd(inst,
+ ASM_TX_SIZE256TO511_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size256to511_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_TX_SIZE256TO511_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_size512to1023_cnt],
+ spx5_inst_rd(inst,
+ ASM_TX_SIZE512TO1023_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size512to1023_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_TX_SIZE512TO1023_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_size1024to1518_cnt],
+ spx5_inst_rd(inst,
+ ASM_TX_SIZE1024TO1518_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size1024to1518_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_TX_SIZE1024TO1518_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_size1519tomax_cnt],
+ spx5_inst_rd(inst,
+ ASM_TX_SIZE1519TOMAX_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size1519tomax_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_TX_SIZE1519TOMAX_CNT(portno)));
+}
+
+static void sparx5_get_asm_misc_stats(u64 *portstats, void __iomem *inst, int
+ portno)
+{
+ sparx5_update_counter(&portstats[spx5_stats_mm_rx_assembly_err_cnt],
+ spx5_inst_rd(inst,
+ ASM_MM_RX_ASSEMBLY_ERR_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_mm_rx_assembly_ok_cnt],
+ spx5_inst_rd(inst,
+ ASM_MM_RX_ASSEMBLY_OK_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_mm_rx_merge_frag_cnt],
+ spx5_inst_rd(inst,
+ ASM_MM_RX_MERGE_FRAG_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_mm_rx_smd_err_cnt],
+ spx5_inst_rd(inst,
+ ASM_MM_RX_SMD_ERR_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_mm_tx_pfragment_cnt],
+ spx5_inst_rd(inst,
+ ASM_MM_TX_PFRAGMENT_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_bad_bytes_cnt],
+ spx5_inst_rd(inst, ASM_RX_BAD_BYTES_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_pmac_rx_bad_bytes_cnt],
+ spx5_inst_rd(inst,
+ ASM_PMAC_RX_BAD_BYTES_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_in_bytes_cnt],
+ spx5_inst_rd(inst, ASM_RX_IN_BYTES_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_ipg_shrink_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_IPG_SHRINK_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_sync_lost_err_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_SYNC_LOST_ERR_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_tagged_frms_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_TAGGED_FRMS_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_rx_untagged_frms_cnt],
+ spx5_inst_rd(inst,
+ ASM_RX_UNTAGGED_FRMS_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_out_bytes_cnt],
+ spx5_inst_rd(inst, ASM_TX_OUT_BYTES_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_tagged_frms_cnt],
+ spx5_inst_rd(inst,
+ ASM_TX_TAGGED_FRMS_CNT(portno)));
+ sparx5_update_counter(&portstats[spx5_stats_tx_untagged_frms_cnt],
+ spx5_inst_rd(inst,
+ ASM_TX_UNTAGGED_FRMS_CNT(portno)));
+}
+
+static void sparx5_get_asm_stats(struct sparx5 *sparx5, int portno)
+{
+ u64 *portstats = &sparx5->stats[portno * sparx5->num_stats];
+ void __iomem *inst = spx5_inst_get(sparx5, TARGET_ASM, 0);
+
+ sparx5_get_asm_phy_stats(portstats, inst, portno);
+ sparx5_get_asm_mac_stats(portstats, inst, portno);
+ sparx5_get_asm_mac_ctrl_stats(portstats, inst, portno);
+ sparx5_get_asm_rmon_stats(portstats, inst, portno);
+ sparx5_get_asm_misc_stats(portstats, inst, portno);
+}
+
+static const struct ethtool_rmon_hist_range sparx5_rmon_ranges[] = {
+ { 0, 64 },
+ { 65, 127 },
+ { 128, 255 },
+ { 256, 511 },
+ { 512, 1023 },
+ { 1024, 1518 },
+ { 1519, 10239 },
+ {}
+};
+
+static void sparx5_get_eth_phy_stats(struct net_device *ndev,
+ struct ethtool_eth_phy_stats *phy_stats)
+{
+ struct sparx5_port *port = netdev_priv(ndev);
+ struct sparx5 *sparx5 = port->sparx5;
+ int portno = port->portno;
+ void __iomem *inst;
+ u64 *portstats;
+
+ portstats = &sparx5->stats[portno * sparx5->num_stats];
+ if (sparx5_is_baser(port->conf.portmode)) {
+ u32 tinst = sparx5_port_dev_index(portno);
+ u32 dev = sparx5_to_high_dev(portno);
+
+ inst = spx5_inst_get(sparx5, dev, tinst);
+ sparx5_get_dev_phy_stats(portstats, inst, tinst);
+ } else {
+ inst = spx5_inst_get(sparx5, TARGET_ASM, 0);
+ sparx5_get_asm_phy_stats(portstats, inst, portno);
+ }
+ phy_stats->SymbolErrorDuringCarrier =
+ portstats[spx5_stats_rx_symbol_err_cnt] +
+ portstats[spx5_stats_pmac_rx_symbol_err_cnt];
+}
+
+static void sparx5_get_eth_mac_stats(struct net_device *ndev,
+ struct ethtool_eth_mac_stats *mac_stats)
+{
+ struct sparx5_port *port = netdev_priv(ndev);
+ struct sparx5 *sparx5 = port->sparx5;
+ int portno = port->portno;
+ void __iomem *inst;
+ u64 *portstats;
+
+ portstats = &sparx5->stats[portno * sparx5->num_stats];
+ if (sparx5_is_baser(port->conf.portmode)) {
+ u32 tinst = sparx5_port_dev_index(portno);
+ u32 dev = sparx5_to_high_dev(portno);
+
+ inst = spx5_inst_get(sparx5, dev, tinst);
+ sparx5_get_dev_mac_stats(portstats, inst, tinst);
+ } else {
+ inst = spx5_inst_get(sparx5, TARGET_ASM, 0);
+ sparx5_get_asm_mac_stats(portstats, inst, portno);
+ }
+ mac_stats->FramesTransmittedOK = portstats[spx5_stats_tx_uc_cnt] +
+ portstats[spx5_stats_pmac_tx_uc_cnt] +
+ portstats[spx5_stats_tx_mc_cnt] +
+ portstats[spx5_stats_tx_bc_cnt];
+ mac_stats->SingleCollisionFrames =
+ portstats[spx5_stats_tx_backoff1_cnt];
+ mac_stats->MultipleCollisionFrames =
+ portstats[spx5_stats_tx_multi_coll_cnt];
+ mac_stats->FramesReceivedOK = portstats[spx5_stats_rx_uc_cnt] +
+ portstats[spx5_stats_pmac_rx_uc_cnt] +
+ portstats[spx5_stats_rx_mc_cnt] +
+ portstats[spx5_stats_rx_bc_cnt];
+ mac_stats->FrameCheckSequenceErrors =
+ portstats[spx5_stats_rx_crc_err_cnt] +
+ portstats[spx5_stats_pmac_rx_crc_err_cnt];
+ mac_stats->AlignmentErrors = portstats[spx5_stats_rx_alignment_lost_cnt]
+ + portstats[spx5_stats_pmac_rx_alignment_lost_cnt];
+ mac_stats->OctetsTransmittedOK = portstats[spx5_stats_tx_ok_bytes_cnt] +
+ portstats[spx5_stats_pmac_tx_ok_bytes_cnt];
+ mac_stats->FramesWithDeferredXmissions =
+ portstats[spx5_stats_tx_defer_cnt];
+ mac_stats->LateCollisions =
+ portstats[spx5_stats_tx_late_coll_cnt];
+ mac_stats->FramesAbortedDueToXSColls =
+ portstats[spx5_stats_tx_xcoll_cnt];
+ mac_stats->CarrierSenseErrors = portstats[spx5_stats_tx_csense_cnt];
+ mac_stats->OctetsReceivedOK = portstats[spx5_stats_rx_ok_bytes_cnt] +
+ portstats[spx5_stats_pmac_rx_ok_bytes_cnt];
+ mac_stats->MulticastFramesXmittedOK = portstats[spx5_stats_tx_mc_cnt] +
+ portstats[spx5_stats_pmac_tx_mc_cnt];
+ mac_stats->BroadcastFramesXmittedOK = portstats[spx5_stats_tx_bc_cnt] +
+ portstats[spx5_stats_pmac_tx_bc_cnt];
+ mac_stats->FramesWithExcessiveDeferral =
+ portstats[spx5_stats_tx_xdefer_cnt];
+ mac_stats->MulticastFramesReceivedOK = portstats[spx5_stats_rx_mc_cnt] +
+ portstats[spx5_stats_pmac_rx_mc_cnt];
+ mac_stats->BroadcastFramesReceivedOK = portstats[spx5_stats_rx_bc_cnt] +
+ portstats[spx5_stats_pmac_rx_bc_cnt];
+ mac_stats->InRangeLengthErrors =
+ portstats[spx5_stats_rx_in_range_len_err_cnt] +
+ portstats[spx5_stats_pmac_rx_in_range_len_err_cnt];
+ mac_stats->OutOfRangeLengthField =
+ portstats[spx5_stats_rx_out_of_range_len_err_cnt] +
+ portstats[spx5_stats_pmac_rx_out_of_range_len_err_cnt];
+ mac_stats->FrameTooLongErrors = portstats[spx5_stats_rx_oversize_cnt] +
+ portstats[spx5_stats_pmac_rx_oversize_cnt];
+}
+
+static void sparx5_get_eth_mac_ctrl_stats(struct net_device *ndev,
+ struct ethtool_eth_ctrl_stats *mac_ctrl_stats)
+{
+ struct sparx5_port *port = netdev_priv(ndev);
+ struct sparx5 *sparx5 = port->sparx5;
+ int portno = port->portno;
+ void __iomem *inst;
+ u64 *portstats;
+
+ portstats = &sparx5->stats[portno * sparx5->num_stats];
+ if (sparx5_is_baser(port->conf.portmode)) {
+ u32 tinst = sparx5_port_dev_index(portno);
+ u32 dev = sparx5_to_high_dev(portno);
+
+ inst = spx5_inst_get(sparx5, dev, tinst);
+ sparx5_get_dev_mac_ctrl_stats(portstats, inst, tinst);
+ } else {
+ inst = spx5_inst_get(sparx5, TARGET_ASM, 0);
+ sparx5_get_asm_mac_ctrl_stats(portstats, inst, portno);
+ }
+ mac_ctrl_stats->MACControlFramesTransmitted =
+ portstats[spx5_stats_tx_pause_cnt] +
+ portstats[spx5_stats_pmac_tx_pause_cnt];
+ mac_ctrl_stats->MACControlFramesReceived =
+ portstats[spx5_stats_rx_pause_cnt] +
+ portstats[spx5_stats_pmac_rx_pause_cnt];
+ mac_ctrl_stats->UnsupportedOpcodesReceived =
+ portstats[spx5_stats_rx_unsup_opcode_cnt] +
+ portstats[spx5_stats_pmac_rx_unsup_opcode_cnt];
+}
+
+static void sparx5_get_eth_rmon_stats(struct net_device *ndev,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges)
+{
+ struct sparx5_port *port = netdev_priv(ndev);
+ struct sparx5 *sparx5 = port->sparx5;
+ int portno = port->portno;
+ void __iomem *inst;
+ u64 *portstats;
+
+ portstats = &sparx5->stats[portno * sparx5->num_stats];
+ if (sparx5_is_baser(port->conf.portmode)) {
+ u32 tinst = sparx5_port_dev_index(portno);
+ u32 dev = sparx5_to_high_dev(portno);
+
+ inst = spx5_inst_get(sparx5, dev, tinst);
+ sparx5_get_dev_rmon_stats(portstats, inst, tinst);
+ } else {
+ inst = spx5_inst_get(sparx5, TARGET_ASM, 0);
+ sparx5_get_asm_rmon_stats(portstats, inst, portno);
+ }
+ rmon_stats->undersize_pkts = portstats[spx5_stats_rx_undersize_cnt] +
+ portstats[spx5_stats_pmac_rx_undersize_cnt];
+ rmon_stats->oversize_pkts = portstats[spx5_stats_rx_oversize_cnt] +
+ portstats[spx5_stats_pmac_rx_oversize_cnt];
+ rmon_stats->fragments = portstats[spx5_stats_rx_fragments_cnt] +
+ portstats[spx5_stats_pmac_rx_fragments_cnt];
+ rmon_stats->jabbers = portstats[spx5_stats_rx_jabbers_cnt] +
+ portstats[spx5_stats_pmac_rx_jabbers_cnt];
+ rmon_stats->hist[0] = portstats[spx5_stats_rx_size64_cnt] +
+ portstats[spx5_stats_pmac_rx_size64_cnt];
+ rmon_stats->hist[1] = portstats[spx5_stats_rx_size65to127_cnt] +
+ portstats[spx5_stats_pmac_rx_size65to127_cnt];
+ rmon_stats->hist[2] = portstats[spx5_stats_rx_size128to255_cnt] +
+ portstats[spx5_stats_pmac_rx_size128to255_cnt];
+ rmon_stats->hist[3] = portstats[spx5_stats_rx_size256to511_cnt] +
+ portstats[spx5_stats_pmac_rx_size256to511_cnt];
+ rmon_stats->hist[4] = portstats[spx5_stats_rx_size512to1023_cnt] +
+ portstats[spx5_stats_pmac_rx_size512to1023_cnt];
+ rmon_stats->hist[5] = portstats[spx5_stats_rx_size1024to1518_cnt] +
+ portstats[spx5_stats_pmac_rx_size1024to1518_cnt];
+ rmon_stats->hist[6] = portstats[spx5_stats_rx_size1519tomax_cnt] +
+ portstats[spx5_stats_pmac_rx_size1519tomax_cnt];
+ rmon_stats->hist_tx[0] = portstats[spx5_stats_tx_size64_cnt] +
+ portstats[spx5_stats_pmac_tx_size64_cnt];
+ rmon_stats->hist_tx[1] = portstats[spx5_stats_tx_size65to127_cnt] +
+ portstats[spx5_stats_pmac_tx_size65to127_cnt];
+ rmon_stats->hist_tx[2] = portstats[spx5_stats_tx_size128to255_cnt] +
+ portstats[spx5_stats_pmac_tx_size128to255_cnt];
+ rmon_stats->hist_tx[3] = portstats[spx5_stats_tx_size256to511_cnt] +
+ portstats[spx5_stats_pmac_tx_size256to511_cnt];
+ rmon_stats->hist_tx[4] = portstats[spx5_stats_tx_size512to1023_cnt] +
+ portstats[spx5_stats_pmac_tx_size512to1023_cnt];
+ rmon_stats->hist_tx[5] = portstats[spx5_stats_tx_size1024to1518_cnt] +
+ portstats[spx5_stats_pmac_tx_size1024to1518_cnt];
+ rmon_stats->hist_tx[6] = portstats[spx5_stats_tx_size1519tomax_cnt] +
+ portstats[spx5_stats_pmac_tx_size1519tomax_cnt];
+ *ranges = sparx5_rmon_ranges;
+}
+
+static int sparx5_get_sset_count(struct net_device *ndev, int sset)
+{
+ struct sparx5_port *port = netdev_priv(ndev);
+ struct sparx5 *sparx5 = port->sparx5;
+
+ if (sset != ETH_SS_STATS)
+ return -EOPNOTSUPP;
+ return sparx5->num_ethtool_stats;
+}
+
+static void sparx5_get_sset_strings(struct net_device *ndev, u32 sset, u8 *data)
+{
+ struct sparx5_port *port = netdev_priv(ndev);
+ struct sparx5 *sparx5 = port->sparx5;
+ int idx;
+
+ if (sset != ETH_SS_STATS)
+ return;
+
+ for (idx = 0; idx < sparx5->num_ethtool_stats; idx++)
+ strncpy(data + idx * ETH_GSTRING_LEN,
+ sparx5->stats_layout[idx], ETH_GSTRING_LEN);
+}
+
+static void sparx5_get_sset_data(struct net_device *ndev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct sparx5_port *port = netdev_priv(ndev);
+ struct sparx5 *sparx5 = port->sparx5;
+ int portno = port->portno;
+ void __iomem *inst;
+ u64 *portstats;
+ int idx;
+
+ portstats = &sparx5->stats[portno * sparx5->num_stats];
+ if (sparx5_is_baser(port->conf.portmode)) {
+ u32 tinst = sparx5_port_dev_index(portno);
+ u32 dev = sparx5_to_high_dev(portno);
+
+ inst = spx5_inst_get(sparx5, dev, tinst);
+ sparx5_get_dev_misc_stats(portstats, inst, tinst);
+ } else {
+ inst = spx5_inst_get(sparx5, TARGET_ASM, 0);
+ sparx5_get_asm_misc_stats(portstats, inst, portno);
+ }
+ sparx5_get_ana_ac_stats_stats(sparx5, portno);
+ sparx5_get_queue_sys_stats(sparx5, portno);
+ /* Copy port counters to the ethtool buffer */
+ for (idx = spx5_stats_mm_rx_assembly_err_cnt;
+ idx < spx5_stats_mm_rx_assembly_err_cnt +
+ sparx5->num_ethtool_stats; idx++)
+ *data++ = portstats[idx];
+}
+
+void sparx5_get_stats64(struct net_device *ndev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct sparx5_port *port = netdev_priv(ndev);
+ struct sparx5 *sparx5 = port->sparx5;
+ u64 *portstats;
+ int idx;
+
+ if (!sparx5->stats)
+ return; /* Not initialized yet */
+
+ portstats = &sparx5->stats[port->portno * sparx5->num_stats];
+
+ stats->rx_packets = portstats[spx5_stats_rx_uc_cnt] +
+ portstats[spx5_stats_pmac_rx_uc_cnt] +
+ portstats[spx5_stats_rx_mc_cnt] +
+ portstats[spx5_stats_rx_bc_cnt];
+ stats->tx_packets = portstats[spx5_stats_tx_uc_cnt] +
+ portstats[spx5_stats_pmac_tx_uc_cnt] +
+ portstats[spx5_stats_tx_mc_cnt] +
+ portstats[spx5_stats_tx_bc_cnt];
+ stats->rx_bytes = portstats[spx5_stats_rx_ok_bytes_cnt] +
+ portstats[spx5_stats_pmac_rx_ok_bytes_cnt];
+ stats->tx_bytes = portstats[spx5_stats_tx_ok_bytes_cnt] +
+ portstats[spx5_stats_pmac_tx_ok_bytes_cnt];
+ stats->rx_errors = portstats[spx5_stats_rx_in_range_len_err_cnt] +
+ portstats[spx5_stats_pmac_rx_in_range_len_err_cnt] +
+ portstats[spx5_stats_rx_out_of_range_len_err_cnt] +
+ portstats[spx5_stats_pmac_rx_out_of_range_len_err_cnt] +
+ portstats[spx5_stats_rx_oversize_cnt] +
+ portstats[spx5_stats_pmac_rx_oversize_cnt] +
+ portstats[spx5_stats_rx_crc_err_cnt] +
+ portstats[spx5_stats_pmac_rx_crc_err_cnt] +
+ portstats[spx5_stats_rx_alignment_lost_cnt] +
+ portstats[spx5_stats_pmac_rx_alignment_lost_cnt];
+ stats->tx_errors = portstats[spx5_stats_tx_xcoll_cnt] +
+ portstats[spx5_stats_tx_csense_cnt] +
+ portstats[spx5_stats_tx_late_coll_cnt];
+ stats->multicast = portstats[spx5_stats_rx_mc_cnt] +
+ portstats[spx5_stats_pmac_rx_mc_cnt];
+ stats->collisions = portstats[spx5_stats_tx_late_coll_cnt] +
+ portstats[spx5_stats_tx_xcoll_cnt] +
+ portstats[spx5_stats_tx_backoff1_cnt];
+ stats->rx_length_errors = portstats[spx5_stats_rx_in_range_len_err_cnt] +
+ portstats[spx5_stats_pmac_rx_in_range_len_err_cnt] +
+ portstats[spx5_stats_rx_out_of_range_len_err_cnt] +
+ portstats[spx5_stats_pmac_rx_out_of_range_len_err_cnt] +
+ portstats[spx5_stats_rx_oversize_cnt] +
+ portstats[spx5_stats_pmac_rx_oversize_cnt];
+ stats->rx_crc_errors = portstats[spx5_stats_rx_crc_err_cnt] +
+ portstats[spx5_stats_pmac_rx_crc_err_cnt];
+ stats->rx_frame_errors = portstats[spx5_stats_rx_alignment_lost_cnt] +
+ portstats[spx5_stats_pmac_rx_alignment_lost_cnt];
+ stats->tx_aborted_errors = portstats[spx5_stats_tx_xcoll_cnt];
+ stats->tx_carrier_errors = portstats[spx5_stats_tx_csense_cnt];
+ stats->tx_window_errors = portstats[spx5_stats_tx_late_coll_cnt];
+ stats->rx_dropped = portstats[spx5_stats_ana_ac_port_stat_lsb_cnt];
+ for (idx = 0; idx < 2 * SPX5_PRIOS; ++idx, ++stats)
+ stats->rx_dropped += portstats[spx5_stats_green_p0_rx_port_drop
+ + idx];
+ stats->tx_dropped = portstats[spx5_stats_tx_local_drop];
+}
+
+static void sparx5_update_port_stats(struct sparx5 *sparx5, int portno)
+{
+ if (sparx5_is_baser(sparx5->ports[portno]->conf.portmode))
+ sparx5_get_device_stats(sparx5, portno);
+ else
+ sparx5_get_asm_stats(sparx5, portno);
+ sparx5_get_ana_ac_stats_stats(sparx5, portno);
+ sparx5_get_queue_sys_stats(sparx5, portno);
+}
+
+static void sparx5_update_stats(struct sparx5 *sparx5)
+{
+ int idx;
+
+ for (idx = 0; idx < SPX5_PORTS; idx++)
+ if (sparx5->ports[idx])
+ sparx5_update_port_stats(sparx5, idx);
+}
+
+static void sparx5_check_stats_work(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct sparx5 *sparx5 = container_of(dwork,
+ struct sparx5,
+ stats_work);
+
+ sparx5_update_stats(sparx5);
+
+ queue_delayed_work(sparx5->stats_queue, &sparx5->stats_work,
+ SPX5_STATS_CHECK_DELAY);
+}
+
+static int sparx5_get_link_settings(struct net_device *ndev,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct sparx5_port *port = netdev_priv(ndev);
+
+ return phylink_ethtool_ksettings_get(port->phylink, cmd);
+}
+
+static int sparx5_set_link_settings(struct net_device *ndev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct sparx5_port *port = netdev_priv(ndev);
+
+ return phylink_ethtool_ksettings_set(port->phylink, cmd);
+}
+
+static void sparx5_config_stats(struct sparx5 *sparx5)
+{
+ /* Enable global events for port policer drops */
+ spx5_rmw(ANA_AC_PORT_SGE_CFG_MASK_SET(0xf0f0),
+ ANA_AC_PORT_SGE_CFG_MASK,
+ sparx5,
+ ANA_AC_PORT_SGE_CFG(SPX5_PORT_POLICER_DROPS));
+}
+
+static void sparx5_config_port_stats(struct sparx5 *sparx5, int portno)
+{
+ /* Clear Queue System counters */
+ spx5_wr(XQS_STAT_CFG_STAT_VIEW_SET(portno) |
+ XQS_STAT_CFG_STAT_CLEAR_SHOT_SET(3), sparx5,
+ XQS_STAT_CFG);
+
+ /* Use counter for port policer drop count */
+ spx5_rmw(ANA_AC_PORT_STAT_CFG_CFG_CNT_FRM_TYPE_SET(1) |
+ ANA_AC_PORT_STAT_CFG_CFG_CNT_BYTE_SET(0) |
+ ANA_AC_PORT_STAT_CFG_CFG_PRIO_MASK_SET(0xff),
+ ANA_AC_PORT_STAT_CFG_CFG_CNT_FRM_TYPE |
+ ANA_AC_PORT_STAT_CFG_CFG_CNT_BYTE |
+ ANA_AC_PORT_STAT_CFG_CFG_PRIO_MASK,
+ sparx5, ANA_AC_PORT_STAT_CFG(portno, SPX5_PORT_POLICER_DROPS));
+}
+
+const struct ethtool_ops sparx5_ethtool_ops = {
+ .get_sset_count = sparx5_get_sset_count,
+ .get_strings = sparx5_get_sset_strings,
+ .get_ethtool_stats = sparx5_get_sset_data,
+ .get_link_ksettings = sparx5_get_link_settings,
+ .set_link_ksettings = sparx5_set_link_settings,
+ .get_link = ethtool_op_get_link,
+ .get_eth_phy_stats = sparx5_get_eth_phy_stats,
+ .get_eth_mac_stats = sparx5_get_eth_mac_stats,
+ .get_eth_ctrl_stats = sparx5_get_eth_mac_ctrl_stats,
+ .get_rmon_stats = sparx5_get_eth_rmon_stats,
+};
+
+int sparx_stats_init(struct sparx5 *sparx5)
+{
+ char queue_name[32];
+ int portno;
+
+ sparx5->stats_layout = sparx5_stats_layout;
+ sparx5->num_stats = spx5_stats_count;
+ sparx5->num_ethtool_stats = ARRAY_SIZE(sparx5_stats_layout);
+ sparx5->stats = devm_kcalloc(sparx5->dev,
+ SPX5_PORTS_ALL * sparx5->num_stats,
+ sizeof(u64), GFP_KERNEL);
+ if (!sparx5->stats)
+ return -ENOMEM;
+
+ mutex_init(&sparx5->queue_stats_lock);
+ sparx5_config_stats(sparx5);
+ for (portno = 0; portno < SPX5_PORTS; portno++)
+ if (sparx5->ports[portno])
+ sparx5_config_port_stats(sparx5, portno);
+
+ snprintf(queue_name, sizeof(queue_name), "%s-stats",
+ dev_name(sparx5->dev));
+ sparx5->stats_queue = create_singlethread_workqueue(queue_name);
+ INIT_DELAYED_WORK(&sparx5->stats_work, sparx5_check_stats_work);
+ queue_delayed_work(sparx5->stats_queue, &sparx5->stats_work,
+ SPX5_STATS_CHECK_DELAY);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c b/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c
new file mode 100644
index 000000000000..0443f66b5550
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include <net/switchdev.h>
+#include <linux/if_bridge.h>
+#include <linux/iopoll.h>
+
+#include "sparx5_main_regs.h"
+#include "sparx5_main.h"
+
+/* Commands for Mac Table Command register */
+#define MAC_CMD_LEARN 0 /* Insert (Learn) 1 entry */
+#define MAC_CMD_UNLEARN 1 /* Unlearn (Forget) 1 entry */
+#define MAC_CMD_LOOKUP 2 /* Look up 1 entry */
+#define MAC_CMD_READ 3 /* Read entry at Mac Table Index */
+#define MAC_CMD_WRITE 4 /* Write entry at Mac Table Index */
+#define MAC_CMD_SCAN 5 /* Scan (Age or find next) */
+#define MAC_CMD_FIND_SMALLEST 6 /* Get next entry */
+#define MAC_CMD_CLEAR_ALL 7 /* Delete all entries in table */
+
+/* Commands for MAC_ENTRY_ADDR_TYPE */
+#define MAC_ENTRY_ADDR_TYPE_UPSID_PN 0
+#define MAC_ENTRY_ADDR_TYPE_UPSID_CPU_OR_INT 1
+#define MAC_ENTRY_ADDR_TYPE_GLAG 2
+#define MAC_ENTRY_ADDR_TYPE_MC_IDX 3
+
+#define TABLE_UPDATE_SLEEP_US 10
+#define TABLE_UPDATE_TIMEOUT_US 100000
+
+struct sparx5_mact_entry {
+ struct list_head list;
+ unsigned char mac[ETH_ALEN];
+ u32 flags;
+#define MAC_ENT_ALIVE BIT(0)
+#define MAC_ENT_MOVED BIT(1)
+#define MAC_ENT_LOCK BIT(2)
+ u16 vid;
+ u16 port;
+};
+
+static int sparx5_mact_get_status(struct sparx5 *sparx5)
+{
+ return spx5_rd(sparx5, LRN_COMMON_ACCESS_CTRL);
+}
+
+static int sparx5_mact_wait_for_completion(struct sparx5 *sparx5)
+{
+ u32 val;
+
+ return readx_poll_timeout(sparx5_mact_get_status,
+ sparx5, val,
+ LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT_GET(val) == 0,
+ TABLE_UPDATE_SLEEP_US, TABLE_UPDATE_TIMEOUT_US);
+}
+
+static void sparx5_mact_select(struct sparx5 *sparx5,
+ const unsigned char mac[ETH_ALEN],
+ u16 vid)
+{
+ u32 macl = 0, mach = 0;
+
+ /* Set the MAC address to handle and the vlan associated in a format
+ * understood by the hardware.
+ */
+ mach |= vid << 16;
+ mach |= mac[0] << 8;
+ mach |= mac[1] << 0;
+ macl |= mac[2] << 24;
+ macl |= mac[3] << 16;
+ macl |= mac[4] << 8;
+ macl |= mac[5] << 0;
+
+ spx5_wr(mach, sparx5, LRN_MAC_ACCESS_CFG_0);
+ spx5_wr(macl, sparx5, LRN_MAC_ACCESS_CFG_1);
+}
+
+int sparx5_mact_learn(struct sparx5 *sparx5, int pgid,
+ const unsigned char mac[ETH_ALEN], u16 vid)
+{
+ int addr, type, ret;
+
+ if (pgid < SPX5_PORTS) {
+ type = MAC_ENTRY_ADDR_TYPE_UPSID_PN;
+ addr = pgid % 32;
+ addr += (pgid / 32) << 5; /* Add upsid */
+ } else {
+ type = MAC_ENTRY_ADDR_TYPE_MC_IDX;
+ addr = pgid - SPX5_PORTS;
+ }
+
+ mutex_lock(&sparx5->lock);
+
+ sparx5_mact_select(sparx5, mac, vid);
+
+ /* MAC entry properties */
+ spx5_wr(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_SET(addr) |
+ LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_TYPE_SET(type) |
+ LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_VLD_SET(1) |
+ LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_LOCKED_SET(1),
+ sparx5, LRN_MAC_ACCESS_CFG_2);
+ spx5_wr(0, sparx5, LRN_MAC_ACCESS_CFG_3);
+
+ /* Insert/learn new entry */
+ spx5_wr(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_CMD_SET(MAC_CMD_LEARN) |
+ LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT_SET(1),
+ sparx5, LRN_COMMON_ACCESS_CTRL);
+
+ ret = sparx5_mact_wait_for_completion(sparx5);
+
+ mutex_unlock(&sparx5->lock);
+
+ return ret;
+}
+
+int sparx5_mc_unsync(struct net_device *dev, const unsigned char *addr)
+{
+ struct sparx5_port *port = netdev_priv(dev);
+ struct sparx5 *sparx5 = port->sparx5;
+
+ return sparx5_mact_forget(sparx5, addr, port->pvid);
+}
+
+int sparx5_mc_sync(struct net_device *dev, const unsigned char *addr)
+{
+ struct sparx5_port *port = netdev_priv(dev);
+ struct sparx5 *sparx5 = port->sparx5;
+
+ return sparx5_mact_learn(sparx5, PGID_CPU, addr, port->pvid);
+}
+
+static int sparx5_mact_get(struct sparx5 *sparx5,
+ unsigned char mac[ETH_ALEN],
+ u16 *vid, u32 *pcfg2)
+{
+ u32 mach, macl, cfg2;
+ int ret = -ENOENT;
+
+ cfg2 = spx5_rd(sparx5, LRN_MAC_ACCESS_CFG_2);
+ if (LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_VLD_GET(cfg2)) {
+ mach = spx5_rd(sparx5, LRN_MAC_ACCESS_CFG_0);
+ macl = spx5_rd(sparx5, LRN_MAC_ACCESS_CFG_1);
+ mac[0] = ((mach >> 8) & 0xff);
+ mac[1] = ((mach >> 0) & 0xff);
+ mac[2] = ((macl >> 24) & 0xff);
+ mac[3] = ((macl >> 16) & 0xff);
+ mac[4] = ((macl >> 8) & 0xff);
+ mac[5] = ((macl >> 0) & 0xff);
+ *vid = mach >> 16;
+ *pcfg2 = cfg2;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+bool sparx5_mact_getnext(struct sparx5 *sparx5,
+ unsigned char mac[ETH_ALEN], u16 *vid, u32 *pcfg2)
+{
+ u32 cfg2;
+ int ret;
+
+ mutex_lock(&sparx5->lock);
+
+ sparx5_mact_select(sparx5, mac, *vid);
+
+ spx5_wr(LRN_SCAN_NEXT_CFG_SCAN_NEXT_IGNORE_LOCKED_ENA_SET(1) |
+ LRN_SCAN_NEXT_CFG_SCAN_NEXT_UNTIL_FOUND_ENA_SET(1),
+ sparx5, LRN_SCAN_NEXT_CFG);
+ spx5_wr(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_CMD_SET
+ (MAC_CMD_FIND_SMALLEST) |
+ LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT_SET(1),
+ sparx5, LRN_COMMON_ACCESS_CTRL);
+
+ ret = sparx5_mact_wait_for_completion(sparx5);
+ if (ret == 0) {
+ ret = sparx5_mact_get(sparx5, mac, vid, &cfg2);
+ if (ret == 0)
+ *pcfg2 = cfg2;
+ }
+
+ mutex_unlock(&sparx5->lock);
+
+ return ret == 0;
+}
+
+static int sparx5_mact_lookup(struct sparx5 *sparx5,
+ const unsigned char mac[ETH_ALEN],
+ u16 vid)
+{
+ int ret;
+
+ mutex_lock(&sparx5->lock);
+
+ sparx5_mact_select(sparx5, mac, vid);
+
+ /* Issue a lookup command */
+ spx5_wr(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_CMD_SET(MAC_CMD_LOOKUP) |
+ LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT_SET(1),
+ sparx5, LRN_COMMON_ACCESS_CTRL);
+
+ ret = sparx5_mact_wait_for_completion(sparx5);
+ if (ret)
+ goto out;
+
+ ret = LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_VLD_GET
+ (spx5_rd(sparx5, LRN_MAC_ACCESS_CFG_2));
+
+out:
+ mutex_unlock(&sparx5->lock);
+
+ return ret;
+}
+
+int sparx5_mact_forget(struct sparx5 *sparx5,
+ const unsigned char mac[ETH_ALEN], u16 vid)
+{
+ int ret;
+
+ mutex_lock(&sparx5->lock);
+
+ sparx5_mact_select(sparx5, mac, vid);
+
+ /* Issue an unlearn command */
+ spx5_wr(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_CMD_SET(MAC_CMD_UNLEARN) |
+ LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT_SET(1),
+ sparx5, LRN_COMMON_ACCESS_CTRL);
+
+ ret = sparx5_mact_wait_for_completion(sparx5);
+
+ mutex_unlock(&sparx5->lock);
+
+ return ret;
+}
+
+static struct sparx5_mact_entry *alloc_mact_entry(struct sparx5 *sparx5,
+ const unsigned char *mac,
+ u16 vid, u16 port_index)
+{
+ struct sparx5_mact_entry *mact_entry;
+
+ mact_entry = devm_kzalloc(sparx5->dev,
+ sizeof(*mact_entry), GFP_ATOMIC);
+ if (!mact_entry)
+ return NULL;
+
+ memcpy(mact_entry->mac, mac, ETH_ALEN);
+ mact_entry->vid = vid;
+ mact_entry->port = port_index;
+ return mact_entry;
+}
+
+static struct sparx5_mact_entry *find_mact_entry(struct sparx5 *sparx5,
+ const unsigned char *mac,
+ u16 vid, u16 port_index)
+{
+ struct sparx5_mact_entry *mact_entry;
+ struct sparx5_mact_entry *res = NULL;
+
+ mutex_lock(&sparx5->mact_lock);
+ list_for_each_entry(mact_entry, &sparx5->mact_entries, list) {
+ if (mact_entry->vid == vid &&
+ ether_addr_equal(mac, mact_entry->mac) &&
+ mact_entry->port == port_index) {
+ res = mact_entry;
+ break;
+ }
+ }
+ mutex_unlock(&sparx5->mact_lock);
+
+ return res;
+}
+
+static void sparx5_fdb_call_notifiers(enum switchdev_notifier_type type,
+ const char *mac, u16 vid,
+ struct net_device *dev, bool offloaded)
+{
+ struct switchdev_notifier_fdb_info info;
+
+ info.addr = mac;
+ info.vid = vid;
+ info.offloaded = offloaded;
+ call_switchdev_notifiers(type, dev, &info.info, NULL);
+}
+
+int sparx5_add_mact_entry(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ const unsigned char *addr, u16 vid)
+{
+ struct sparx5_mact_entry *mact_entry;
+ int ret;
+
+ ret = sparx5_mact_lookup(sparx5, addr, vid);
+ if (ret)
+ return 0;
+
+ /* In case the entry already exists, don't add it again to SW,
+ * just update HW, but we need to look in the actual HW because
+ * it is possible for an entry to be learn by HW and before the
+ * mact thread to start the frame will reach CPU and the CPU will
+ * add the entry but without the extern_learn flag.
+ */
+ mact_entry = find_mact_entry(sparx5, addr, vid, port->portno);
+ if (mact_entry)
+ goto update_hw;
+
+ /* Add the entry in SW MAC table not to get the notification when
+ * SW is pulling again
+ */
+ mact_entry = alloc_mact_entry(sparx5, addr, vid, port->portno);
+ if (!mact_entry)
+ return -ENOMEM;
+
+ mutex_lock(&sparx5->mact_lock);
+ list_add_tail(&mact_entry->list, &sparx5->mact_entries);
+ mutex_unlock(&sparx5->mact_lock);
+
+update_hw:
+ ret = sparx5_mact_learn(sparx5, port->portno, addr, vid);
+
+ /* New entry? */
+ if (mact_entry->flags == 0) {
+ mact_entry->flags |= MAC_ENT_LOCK; /* Don't age this */
+ sparx5_fdb_call_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, addr, vid,
+ port->ndev, true);
+ }
+
+ return ret;
+}
+
+int sparx5_del_mact_entry(struct sparx5 *sparx5,
+ const unsigned char *addr,
+ u16 vid)
+{
+ struct sparx5_mact_entry *mact_entry, *tmp;
+
+ /* Delete the entry in SW MAC table not to get the notification when
+ * SW is pulling again
+ */
+ mutex_lock(&sparx5->mact_lock);
+ list_for_each_entry_safe(mact_entry, tmp, &sparx5->mact_entries,
+ list) {
+ if ((vid == 0 || mact_entry->vid == vid) &&
+ ether_addr_equal(addr, mact_entry->mac)) {
+ list_del(&mact_entry->list);
+ devm_kfree(sparx5->dev, mact_entry);
+
+ sparx5_mact_forget(sparx5, addr, mact_entry->vid);
+ }
+ }
+ mutex_unlock(&sparx5->mact_lock);
+
+ return 0;
+}
+
+static void sparx5_mact_handle_entry(struct sparx5 *sparx5,
+ unsigned char mac[ETH_ALEN],
+ u16 vid, u32 cfg2)
+{
+ struct sparx5_mact_entry *mact_entry;
+ bool found = false;
+ u16 port;
+
+ if (LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_TYPE_GET(cfg2) !=
+ MAC_ENTRY_ADDR_TYPE_UPSID_PN)
+ return;
+
+ port = LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_GET(cfg2);
+ if (port >= SPX5_PORTS)
+ return;
+
+ if (!test_bit(port, sparx5->bridge_mask))
+ return;
+
+ mutex_lock(&sparx5->mact_lock);
+ list_for_each_entry(mact_entry, &sparx5->mact_entries, list) {
+ if (mact_entry->vid == vid &&
+ ether_addr_equal(mac, mact_entry->mac)) {
+ found = true;
+ mact_entry->flags |= MAC_ENT_ALIVE;
+ if (mact_entry->port != port) {
+ dev_warn(sparx5->dev, "Entry move: %d -> %d\n",
+ mact_entry->port, port);
+ mact_entry->port = port;
+ mact_entry->flags |= MAC_ENT_MOVED;
+ }
+ /* Entry handled */
+ break;
+ }
+ }
+ mutex_unlock(&sparx5->mact_lock);
+
+ if (found && !(mact_entry->flags & MAC_ENT_MOVED))
+ /* Present, not moved */
+ return;
+
+ if (!found) {
+ /* Entry not found - now add */
+ mact_entry = alloc_mact_entry(sparx5, mac, vid, port);
+ if (!mact_entry)
+ return;
+
+ mact_entry->flags |= MAC_ENT_ALIVE;
+ mutex_lock(&sparx5->mact_lock);
+ list_add_tail(&mact_entry->list, &sparx5->mact_entries);
+ mutex_unlock(&sparx5->mact_lock);
+ }
+
+ /* New or moved entry - notify bridge */
+ sparx5_fdb_call_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE,
+ mac, vid, sparx5->ports[port]->ndev,
+ true);
+}
+
+void sparx5_mact_pull_work(struct work_struct *work)
+{
+ struct delayed_work *del_work = to_delayed_work(work);
+ struct sparx5 *sparx5 = container_of(del_work, struct sparx5,
+ mact_work);
+ struct sparx5_mact_entry *mact_entry, *tmp;
+ unsigned char mac[ETH_ALEN];
+ u32 cfg2;
+ u16 vid;
+ int ret;
+
+ /* Reset MAC entry flags */
+ mutex_lock(&sparx5->mact_lock);
+ list_for_each_entry(mact_entry, &sparx5->mact_entries, list)
+ mact_entry->flags &= MAC_ENT_LOCK;
+ mutex_unlock(&sparx5->mact_lock);
+
+ /* MAIN mac address processing loop */
+ vid = 0;
+ memset(mac, 0, sizeof(mac));
+ do {
+ mutex_lock(&sparx5->lock);
+ sparx5_mact_select(sparx5, mac, vid);
+ spx5_wr(LRN_SCAN_NEXT_CFG_SCAN_NEXT_UNTIL_FOUND_ENA_SET(1),
+ sparx5, LRN_SCAN_NEXT_CFG);
+ spx5_wr(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_CMD_SET
+ (MAC_CMD_FIND_SMALLEST) |
+ LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT_SET(1),
+ sparx5, LRN_COMMON_ACCESS_CTRL);
+ ret = sparx5_mact_wait_for_completion(sparx5);
+ if (ret == 0)
+ ret = sparx5_mact_get(sparx5, mac, &vid, &cfg2);
+ mutex_unlock(&sparx5->lock);
+ if (ret == 0)
+ sparx5_mact_handle_entry(sparx5, mac, vid, cfg2);
+ } while (ret == 0);
+
+ mutex_lock(&sparx5->mact_lock);
+ list_for_each_entry_safe(mact_entry, tmp, &sparx5->mact_entries,
+ list) {
+ /* If the entry is in HW or permanent, then skip */
+ if (mact_entry->flags & (MAC_ENT_ALIVE | MAC_ENT_LOCK))
+ continue;
+
+ sparx5_fdb_call_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
+ mact_entry->mac, mact_entry->vid,
+ sparx5->ports[mact_entry->port]->ndev,
+ true);
+
+ list_del(&mact_entry->list);
+ devm_kfree(sparx5->dev, mact_entry);
+ }
+ mutex_unlock(&sparx5->mact_lock);
+
+ queue_delayed_work(sparx5->mact_queue, &sparx5->mact_work,
+ SPX5_MACT_PULL_DELAY);
+}
+
+void sparx5_set_ageing(struct sparx5 *sparx5, int msecs)
+{
+ int value = max(1, msecs / 10); /* unit 10 ms */
+
+ spx5_rmw(LRN_AUTOAGE_CFG_UNIT_SIZE_SET(2) | /* 10 ms */
+ LRN_AUTOAGE_CFG_PERIOD_VAL_SET(value / 2), /* one bit ageing */
+ LRN_AUTOAGE_CFG_UNIT_SIZE |
+ LRN_AUTOAGE_CFG_PERIOD_VAL,
+ sparx5,
+ LRN_AUTOAGE_CFG(0));
+}
+
+void sparx5_mact_init(struct sparx5 *sparx5)
+{
+ mutex_init(&sparx5->lock);
+
+ /* Flush MAC table */
+ spx5_wr(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_CMD_SET(MAC_CMD_CLEAR_ALL) |
+ LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT_SET(1),
+ sparx5, LRN_COMMON_ACCESS_CTRL);
+
+ if (sparx5_mact_wait_for_completion(sparx5) != 0)
+ dev_warn(sparx5->dev, "MAC flush error\n");
+
+ sparx5_set_ageing(sparx5, BR_DEFAULT_AGEING_TIME / HZ * 1000);
+}
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
new file mode 100644
index 000000000000..f666133a15de
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
@@ -0,0 +1,853 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
+ *
+ * The Sparx5 Chip Register Model can be browsed at this location:
+ * https://github.com/microchip-ung/sparx-5_reginfo
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
+#include <net/switchdev.h>
+#include <linux/etherdevice.h>
+#include <linux/io.h>
+#include <linux/printk.h>
+#include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <linux/reset.h>
+
+#include "sparx5_main_regs.h"
+#include "sparx5_main.h"
+#include "sparx5_port.h"
+
+#define QLIM_WM(fraction) \
+ ((SPX5_BUFFER_MEMORY / SPX5_BUFFER_CELL_SZ - 100) * (fraction) / 100)
+#define IO_RANGES 3
+
+struct initial_port_config {
+ u32 portno;
+ struct device_node *node;
+ struct sparx5_port_config conf;
+ struct phy *serdes;
+};
+
+struct sparx5_ram_config {
+ void __iomem *init_reg;
+ u32 init_val;
+};
+
+struct sparx5_main_io_resource {
+ enum sparx5_target id;
+ phys_addr_t offset;
+ int range;
+};
+
+static const struct sparx5_main_io_resource sparx5_main_iomap[] = {
+ { TARGET_CPU, 0, 0 }, /* 0x600000000 */
+ { TARGET_FDMA, 0x80000, 0 }, /* 0x600080000 */
+ { TARGET_PCEP, 0x400000, 0 }, /* 0x600400000 */
+ { TARGET_DEV2G5, 0x10004000, 1 }, /* 0x610004000 */
+ { TARGET_DEV5G, 0x10008000, 1 }, /* 0x610008000 */
+ { TARGET_PCS5G_BR, 0x1000c000, 1 }, /* 0x61000c000 */
+ { TARGET_DEV2G5 + 1, 0x10010000, 1 }, /* 0x610010000 */
+ { TARGET_DEV5G + 1, 0x10014000, 1 }, /* 0x610014000 */
+ { TARGET_PCS5G_BR + 1, 0x10018000, 1 }, /* 0x610018000 */
+ { TARGET_DEV2G5 + 2, 0x1001c000, 1 }, /* 0x61001c000 */
+ { TARGET_DEV5G + 2, 0x10020000, 1 }, /* 0x610020000 */
+ { TARGET_PCS5G_BR + 2, 0x10024000, 1 }, /* 0x610024000 */
+ { TARGET_DEV2G5 + 6, 0x10028000, 1 }, /* 0x610028000 */
+ { TARGET_DEV5G + 6, 0x1002c000, 1 }, /* 0x61002c000 */
+ { TARGET_PCS5G_BR + 6, 0x10030000, 1 }, /* 0x610030000 */
+ { TARGET_DEV2G5 + 7, 0x10034000, 1 }, /* 0x610034000 */
+ { TARGET_DEV5G + 7, 0x10038000, 1 }, /* 0x610038000 */
+ { TARGET_PCS5G_BR + 7, 0x1003c000, 1 }, /* 0x61003c000 */
+ { TARGET_DEV2G5 + 8, 0x10040000, 1 }, /* 0x610040000 */
+ { TARGET_DEV5G + 8, 0x10044000, 1 }, /* 0x610044000 */
+ { TARGET_PCS5G_BR + 8, 0x10048000, 1 }, /* 0x610048000 */
+ { TARGET_DEV2G5 + 9, 0x1004c000, 1 }, /* 0x61004c000 */
+ { TARGET_DEV5G + 9, 0x10050000, 1 }, /* 0x610050000 */
+ { TARGET_PCS5G_BR + 9, 0x10054000, 1 }, /* 0x610054000 */
+ { TARGET_DEV2G5 + 10, 0x10058000, 1 }, /* 0x610058000 */
+ { TARGET_DEV5G + 10, 0x1005c000, 1 }, /* 0x61005c000 */
+ { TARGET_PCS5G_BR + 10, 0x10060000, 1 }, /* 0x610060000 */
+ { TARGET_DEV2G5 + 11, 0x10064000, 1 }, /* 0x610064000 */
+ { TARGET_DEV5G + 11, 0x10068000, 1 }, /* 0x610068000 */
+ { TARGET_PCS5G_BR + 11, 0x1006c000, 1 }, /* 0x61006c000 */
+ { TARGET_DEV2G5 + 12, 0x10070000, 1 }, /* 0x610070000 */
+ { TARGET_DEV10G, 0x10074000, 1 }, /* 0x610074000 */
+ { TARGET_PCS10G_BR, 0x10078000, 1 }, /* 0x610078000 */
+ { TARGET_DEV2G5 + 14, 0x1007c000, 1 }, /* 0x61007c000 */
+ { TARGET_DEV10G + 2, 0x10080000, 1 }, /* 0x610080000 */
+ { TARGET_PCS10G_BR + 2, 0x10084000, 1 }, /* 0x610084000 */
+ { TARGET_DEV2G5 + 15, 0x10088000, 1 }, /* 0x610088000 */
+ { TARGET_DEV10G + 3, 0x1008c000, 1 }, /* 0x61008c000 */
+ { TARGET_PCS10G_BR + 3, 0x10090000, 1 }, /* 0x610090000 */
+ { TARGET_DEV2G5 + 16, 0x10094000, 1 }, /* 0x610094000 */
+ { TARGET_DEV2G5 + 17, 0x10098000, 1 }, /* 0x610098000 */
+ { TARGET_DEV2G5 + 18, 0x1009c000, 1 }, /* 0x61009c000 */
+ { TARGET_DEV2G5 + 19, 0x100a0000, 1 }, /* 0x6100a0000 */
+ { TARGET_DEV2G5 + 20, 0x100a4000, 1 }, /* 0x6100a4000 */
+ { TARGET_DEV2G5 + 21, 0x100a8000, 1 }, /* 0x6100a8000 */
+ { TARGET_DEV2G5 + 22, 0x100ac000, 1 }, /* 0x6100ac000 */
+ { TARGET_DEV2G5 + 23, 0x100b0000, 1 }, /* 0x6100b0000 */
+ { TARGET_DEV2G5 + 32, 0x100b4000, 1 }, /* 0x6100b4000 */
+ { TARGET_DEV2G5 + 33, 0x100b8000, 1 }, /* 0x6100b8000 */
+ { TARGET_DEV2G5 + 34, 0x100bc000, 1 }, /* 0x6100bc000 */
+ { TARGET_DEV2G5 + 35, 0x100c0000, 1 }, /* 0x6100c0000 */
+ { TARGET_DEV2G5 + 36, 0x100c4000, 1 }, /* 0x6100c4000 */
+ { TARGET_DEV2G5 + 37, 0x100c8000, 1 }, /* 0x6100c8000 */
+ { TARGET_DEV2G5 + 38, 0x100cc000, 1 }, /* 0x6100cc000 */
+ { TARGET_DEV2G5 + 39, 0x100d0000, 1 }, /* 0x6100d0000 */
+ { TARGET_DEV2G5 + 40, 0x100d4000, 1 }, /* 0x6100d4000 */
+ { TARGET_DEV2G5 + 41, 0x100d8000, 1 }, /* 0x6100d8000 */
+ { TARGET_DEV2G5 + 42, 0x100dc000, 1 }, /* 0x6100dc000 */
+ { TARGET_DEV2G5 + 43, 0x100e0000, 1 }, /* 0x6100e0000 */
+ { TARGET_DEV2G5 + 44, 0x100e4000, 1 }, /* 0x6100e4000 */
+ { TARGET_DEV2G5 + 45, 0x100e8000, 1 }, /* 0x6100e8000 */
+ { TARGET_DEV2G5 + 46, 0x100ec000, 1 }, /* 0x6100ec000 */
+ { TARGET_DEV2G5 + 47, 0x100f0000, 1 }, /* 0x6100f0000 */
+ { TARGET_DEV2G5 + 57, 0x100f4000, 1 }, /* 0x6100f4000 */
+ { TARGET_DEV25G + 1, 0x100f8000, 1 }, /* 0x6100f8000 */
+ { TARGET_PCS25G_BR + 1, 0x100fc000, 1 }, /* 0x6100fc000 */
+ { TARGET_DEV2G5 + 59, 0x10104000, 1 }, /* 0x610104000 */
+ { TARGET_DEV25G + 3, 0x10108000, 1 }, /* 0x610108000 */
+ { TARGET_PCS25G_BR + 3, 0x1010c000, 1 }, /* 0x61010c000 */
+ { TARGET_DEV2G5 + 60, 0x10114000, 1 }, /* 0x610114000 */
+ { TARGET_DEV25G + 4, 0x10118000, 1 }, /* 0x610118000 */
+ { TARGET_PCS25G_BR + 4, 0x1011c000, 1 }, /* 0x61011c000 */
+ { TARGET_DEV2G5 + 64, 0x10124000, 1 }, /* 0x610124000 */
+ { TARGET_DEV5G + 12, 0x10128000, 1 }, /* 0x610128000 */
+ { TARGET_PCS5G_BR + 12, 0x1012c000, 1 }, /* 0x61012c000 */
+ { TARGET_PORT_CONF, 0x10130000, 1 }, /* 0x610130000 */
+ { TARGET_DEV2G5 + 3, 0x10404000, 1 }, /* 0x610404000 */
+ { TARGET_DEV5G + 3, 0x10408000, 1 }, /* 0x610408000 */
+ { TARGET_PCS5G_BR + 3, 0x1040c000, 1 }, /* 0x61040c000 */
+ { TARGET_DEV2G5 + 4, 0x10410000, 1 }, /* 0x610410000 */
+ { TARGET_DEV5G + 4, 0x10414000, 1 }, /* 0x610414000 */
+ { TARGET_PCS5G_BR + 4, 0x10418000, 1 }, /* 0x610418000 */
+ { TARGET_DEV2G5 + 5, 0x1041c000, 1 }, /* 0x61041c000 */
+ { TARGET_DEV5G + 5, 0x10420000, 1 }, /* 0x610420000 */
+ { TARGET_PCS5G_BR + 5, 0x10424000, 1 }, /* 0x610424000 */
+ { TARGET_DEV2G5 + 13, 0x10428000, 1 }, /* 0x610428000 */
+ { TARGET_DEV10G + 1, 0x1042c000, 1 }, /* 0x61042c000 */
+ { TARGET_PCS10G_BR + 1, 0x10430000, 1 }, /* 0x610430000 */
+ { TARGET_DEV2G5 + 24, 0x10434000, 1 }, /* 0x610434000 */
+ { TARGET_DEV2G5 + 25, 0x10438000, 1 }, /* 0x610438000 */
+ { TARGET_DEV2G5 + 26, 0x1043c000, 1 }, /* 0x61043c000 */
+ { TARGET_DEV2G5 + 27, 0x10440000, 1 }, /* 0x610440000 */
+ { TARGET_DEV2G5 + 28, 0x10444000, 1 }, /* 0x610444000 */
+ { TARGET_DEV2G5 + 29, 0x10448000, 1 }, /* 0x610448000 */
+ { TARGET_DEV2G5 + 30, 0x1044c000, 1 }, /* 0x61044c000 */
+ { TARGET_DEV2G5 + 31, 0x10450000, 1 }, /* 0x610450000 */
+ { TARGET_DEV2G5 + 48, 0x10454000, 1 }, /* 0x610454000 */
+ { TARGET_DEV10G + 4, 0x10458000, 1 }, /* 0x610458000 */
+ { TARGET_PCS10G_BR + 4, 0x1045c000, 1 }, /* 0x61045c000 */
+ { TARGET_DEV2G5 + 49, 0x10460000, 1 }, /* 0x610460000 */
+ { TARGET_DEV10G + 5, 0x10464000, 1 }, /* 0x610464000 */
+ { TARGET_PCS10G_BR + 5, 0x10468000, 1 }, /* 0x610468000 */
+ { TARGET_DEV2G5 + 50, 0x1046c000, 1 }, /* 0x61046c000 */
+ { TARGET_DEV10G + 6, 0x10470000, 1 }, /* 0x610470000 */
+ { TARGET_PCS10G_BR + 6, 0x10474000, 1 }, /* 0x610474000 */
+ { TARGET_DEV2G5 + 51, 0x10478000, 1 }, /* 0x610478000 */
+ { TARGET_DEV10G + 7, 0x1047c000, 1 }, /* 0x61047c000 */
+ { TARGET_PCS10G_BR + 7, 0x10480000, 1 }, /* 0x610480000 */
+ { TARGET_DEV2G5 + 52, 0x10484000, 1 }, /* 0x610484000 */
+ { TARGET_DEV10G + 8, 0x10488000, 1 }, /* 0x610488000 */
+ { TARGET_PCS10G_BR + 8, 0x1048c000, 1 }, /* 0x61048c000 */
+ { TARGET_DEV2G5 + 53, 0x10490000, 1 }, /* 0x610490000 */
+ { TARGET_DEV10G + 9, 0x10494000, 1 }, /* 0x610494000 */
+ { TARGET_PCS10G_BR + 9, 0x10498000, 1 }, /* 0x610498000 */
+ { TARGET_DEV2G5 + 54, 0x1049c000, 1 }, /* 0x61049c000 */
+ { TARGET_DEV10G + 10, 0x104a0000, 1 }, /* 0x6104a0000 */
+ { TARGET_PCS10G_BR + 10, 0x104a4000, 1 }, /* 0x6104a4000 */
+ { TARGET_DEV2G5 + 55, 0x104a8000, 1 }, /* 0x6104a8000 */
+ { TARGET_DEV10G + 11, 0x104ac000, 1 }, /* 0x6104ac000 */
+ { TARGET_PCS10G_BR + 11, 0x104b0000, 1 }, /* 0x6104b0000 */
+ { TARGET_DEV2G5 + 56, 0x104b4000, 1 }, /* 0x6104b4000 */
+ { TARGET_DEV25G, 0x104b8000, 1 }, /* 0x6104b8000 */
+ { TARGET_PCS25G_BR, 0x104bc000, 1 }, /* 0x6104bc000 */
+ { TARGET_DEV2G5 + 58, 0x104c4000, 1 }, /* 0x6104c4000 */
+ { TARGET_DEV25G + 2, 0x104c8000, 1 }, /* 0x6104c8000 */
+ { TARGET_PCS25G_BR + 2, 0x104cc000, 1 }, /* 0x6104cc000 */
+ { TARGET_DEV2G5 + 61, 0x104d4000, 1 }, /* 0x6104d4000 */
+ { TARGET_DEV25G + 5, 0x104d8000, 1 }, /* 0x6104d8000 */
+ { TARGET_PCS25G_BR + 5, 0x104dc000, 1 }, /* 0x6104dc000 */
+ { TARGET_DEV2G5 + 62, 0x104e4000, 1 }, /* 0x6104e4000 */
+ { TARGET_DEV25G + 6, 0x104e8000, 1 }, /* 0x6104e8000 */
+ { TARGET_PCS25G_BR + 6, 0x104ec000, 1 }, /* 0x6104ec000 */
+ { TARGET_DEV2G5 + 63, 0x104f4000, 1 }, /* 0x6104f4000 */
+ { TARGET_DEV25G + 7, 0x104f8000, 1 }, /* 0x6104f8000 */
+ { TARGET_PCS25G_BR + 7, 0x104fc000, 1 }, /* 0x6104fc000 */
+ { TARGET_DSM, 0x10504000, 1 }, /* 0x610504000 */
+ { TARGET_ASM, 0x10600000, 1 }, /* 0x610600000 */
+ { TARGET_GCB, 0x11010000, 2 }, /* 0x611010000 */
+ { TARGET_QS, 0x11030000, 2 }, /* 0x611030000 */
+ { TARGET_ANA_ACL, 0x11050000, 2 }, /* 0x611050000 */
+ { TARGET_LRN, 0x11060000, 2 }, /* 0x611060000 */
+ { TARGET_VCAP_SUPER, 0x11080000, 2 }, /* 0x611080000 */
+ { TARGET_QSYS, 0x110a0000, 2 }, /* 0x6110a0000 */
+ { TARGET_QFWD, 0x110b0000, 2 }, /* 0x6110b0000 */
+ { TARGET_XQS, 0x110c0000, 2 }, /* 0x6110c0000 */
+ { TARGET_CLKGEN, 0x11100000, 2 }, /* 0x611100000 */
+ { TARGET_ANA_AC_POL, 0x11200000, 2 }, /* 0x611200000 */
+ { TARGET_QRES, 0x11280000, 2 }, /* 0x611280000 */
+ { TARGET_EACL, 0x112c0000, 2 }, /* 0x6112c0000 */
+ { TARGET_ANA_CL, 0x11400000, 2 }, /* 0x611400000 */
+ { TARGET_ANA_L3, 0x11480000, 2 }, /* 0x611480000 */
+ { TARGET_HSCH, 0x11580000, 2 }, /* 0x611580000 */
+ { TARGET_REW, 0x11600000, 2 }, /* 0x611600000 */
+ { TARGET_ANA_L2, 0x11800000, 2 }, /* 0x611800000 */
+ { TARGET_ANA_AC, 0x11900000, 2 }, /* 0x611900000 */
+ { TARGET_VOP, 0x11a00000, 2 }, /* 0x611a00000 */
+};
+
+static int sparx5_create_targets(struct sparx5 *sparx5)
+{
+ struct resource *iores[IO_RANGES];
+ void __iomem *iomem[IO_RANGES];
+ void __iomem *begin[IO_RANGES];
+ int range_id[IO_RANGES];
+ int idx, jdx;
+
+ for (idx = 0, jdx = 0; jdx < ARRAY_SIZE(sparx5_main_iomap); jdx++) {
+ const struct sparx5_main_io_resource *iomap = &sparx5_main_iomap[jdx];
+
+ if (idx == iomap->range) {
+ range_id[idx] = jdx;
+ idx++;
+ }
+ }
+ for (idx = 0; idx < IO_RANGES; idx++) {
+ iores[idx] = platform_get_resource(sparx5->pdev, IORESOURCE_MEM,
+ idx);
+ if (!iores[idx]) {
+ dev_err(sparx5->dev, "Invalid resource\n");
+ return -EINVAL;
+ }
+ iomem[idx] = devm_ioremap(sparx5->dev,
+ iores[idx]->start,
+ iores[idx]->end - iores[idx]->start
+ + 1);
+ if (!iomem[idx]) {
+ dev_err(sparx5->dev, "Unable to get switch registers: %s\n",
+ iores[idx]->name);
+ return -ENOMEM;
+ }
+ begin[idx] = iomem[idx] - sparx5_main_iomap[range_id[idx]].offset;
+ }
+ for (jdx = 0; jdx < ARRAY_SIZE(sparx5_main_iomap); jdx++) {
+ const struct sparx5_main_io_resource *iomap = &sparx5_main_iomap[jdx];
+
+ sparx5->regs[iomap->id] = begin[iomap->range] + iomap->offset;
+ }
+ return 0;
+}
+
+static int sparx5_create_port(struct sparx5 *sparx5,
+ struct initial_port_config *config)
+{
+ struct sparx5_port *spx5_port;
+ struct net_device *ndev;
+ struct phylink *phylink;
+ int err;
+
+ ndev = sparx5_create_netdev(sparx5, config->portno);
+ if (IS_ERR(ndev)) {
+ dev_err(sparx5->dev, "Could not create net device: %02u\n",
+ config->portno);
+ return PTR_ERR(ndev);
+ }
+ spx5_port = netdev_priv(ndev);
+ spx5_port->of_node = config->node;
+ spx5_port->serdes = config->serdes;
+ spx5_port->pvid = NULL_VID;
+ spx5_port->signd_internal = true;
+ spx5_port->signd_active_high = true;
+ spx5_port->signd_enable = true;
+ spx5_port->max_vlan_tags = SPX5_PORT_MAX_TAGS_NONE;
+ spx5_port->vlan_type = SPX5_VLAN_PORT_TYPE_UNAWARE;
+ spx5_port->custom_etype = 0x8880; /* Vitesse */
+ spx5_port->phylink_pcs.poll = true;
+ spx5_port->phylink_pcs.ops = &sparx5_phylink_pcs_ops;
+ sparx5->ports[config->portno] = spx5_port;
+
+ err = sparx5_port_init(sparx5, spx5_port, &config->conf);
+ if (err) {
+ dev_err(sparx5->dev, "port init failed\n");
+ return err;
+ }
+ spx5_port->conf = config->conf;
+
+ /* Setup VLAN */
+ sparx5_vlan_port_setup(sparx5, spx5_port->portno);
+
+ /* Create a phylink for PHY management. Also handles SFPs */
+ spx5_port->phylink_config.dev = &spx5_port->ndev->dev;
+ spx5_port->phylink_config.type = PHYLINK_NETDEV;
+ spx5_port->phylink_config.pcs_poll = true;
+
+ phylink = phylink_create(&spx5_port->phylink_config,
+ of_fwnode_handle(config->node),
+ config->conf.phy_mode,
+ &sparx5_phylink_mac_ops);
+ if (IS_ERR(phylink))
+ return PTR_ERR(phylink);
+
+ spx5_port->phylink = phylink;
+ phylink_set_pcs(phylink, &spx5_port->phylink_pcs);
+
+ return 0;
+}
+
+static int sparx5_init_ram(struct sparx5 *s5)
+{
+ const struct sparx5_ram_config spx5_ram_cfg[] = {
+ {spx5_reg_get(s5, ANA_AC_STAT_RESET), ANA_AC_STAT_RESET_RESET},
+ {spx5_reg_get(s5, ASM_STAT_CFG), ASM_STAT_CFG_STAT_CNT_CLR_SHOT},
+ {spx5_reg_get(s5, QSYS_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
+ {spx5_reg_get(s5, REW_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
+ {spx5_reg_get(s5, VOP_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
+ {spx5_reg_get(s5, ANA_AC_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
+ {spx5_reg_get(s5, ASM_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
+ {spx5_reg_get(s5, EACL_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
+ {spx5_reg_get(s5, VCAP_SUPER_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
+ {spx5_reg_get(s5, DSM_RAM_INIT), QSYS_RAM_INIT_RAM_INIT}
+ };
+ const struct sparx5_ram_config *cfg;
+ u32 value, pending, jdx, idx;
+
+ for (jdx = 0; jdx < 10; jdx++) {
+ pending = ARRAY_SIZE(spx5_ram_cfg);
+ for (idx = 0; idx < ARRAY_SIZE(spx5_ram_cfg); idx++) {
+ cfg = &spx5_ram_cfg[idx];
+ if (jdx == 0) {
+ writel(cfg->init_val, cfg->init_reg);
+ } else {
+ value = readl(cfg->init_reg);
+ if ((value & cfg->init_val) != cfg->init_val)
+ pending--;
+ }
+ }
+ if (!pending)
+ break;
+ usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
+ }
+
+ if (pending > 0) {
+ /* Still initializing, should be complete in
+ * less than 1ms
+ */
+ dev_err(s5->dev, "Memory initialization error\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int sparx5_init_switchcore(struct sparx5 *sparx5)
+{
+ u32 value;
+ int err = 0;
+
+ spx5_rmw(EACL_POL_EACL_CFG_EACL_FORCE_INIT_SET(1),
+ EACL_POL_EACL_CFG_EACL_FORCE_INIT,
+ sparx5,
+ EACL_POL_EACL_CFG);
+
+ spx5_rmw(EACL_POL_EACL_CFG_EACL_FORCE_INIT_SET(0),
+ EACL_POL_EACL_CFG_EACL_FORCE_INIT,
+ sparx5,
+ EACL_POL_EACL_CFG);
+
+ /* Initialize memories, if not done already */
+ value = spx5_rd(sparx5, HSCH_RESET_CFG);
+ if (!(value & HSCH_RESET_CFG_CORE_ENA)) {
+ err = sparx5_init_ram(sparx5);
+ if (err)
+ return err;
+ }
+
+ /* Reset counters */
+ spx5_wr(ANA_AC_STAT_RESET_RESET_SET(1), sparx5, ANA_AC_STAT_RESET);
+ spx5_wr(ASM_STAT_CFG_STAT_CNT_CLR_SHOT_SET(1), sparx5, ASM_STAT_CFG);
+
+ /* Enable switch-core and queue system */
+ spx5_wr(HSCH_RESET_CFG_CORE_ENA_SET(1), sparx5, HSCH_RESET_CFG);
+
+ return 0;
+}
+
+static int sparx5_init_coreclock(struct sparx5 *sparx5)
+{
+ enum sparx5_core_clockfreq freq = sparx5->coreclock;
+ u32 clk_div, clk_period, pol_upd_int, idx;
+
+ /* Verify if core clock frequency is supported on target.
+ * If 'VTSS_CORE_CLOCK_DEFAULT' then the highest supported
+ * freq. is used
+ */
+ switch (sparx5->target_ct) {
+ case SPX5_TARGET_CT_7546:
+ if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
+ freq = SPX5_CORE_CLOCK_250MHZ;
+ else if (sparx5->coreclock != SPX5_CORE_CLOCK_250MHZ)
+ freq = 0; /* Not supported */
+ break;
+ case SPX5_TARGET_CT_7549:
+ case SPX5_TARGET_CT_7552:
+ case SPX5_TARGET_CT_7556:
+ if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
+ freq = SPX5_CORE_CLOCK_500MHZ;
+ else if (sparx5->coreclock != SPX5_CORE_CLOCK_500MHZ)
+ freq = 0; /* Not supported */
+ break;
+ case SPX5_TARGET_CT_7558:
+ case SPX5_TARGET_CT_7558TSN:
+ if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
+ freq = SPX5_CORE_CLOCK_625MHZ;
+ else if (sparx5->coreclock != SPX5_CORE_CLOCK_625MHZ)
+ freq = 0; /* Not supported */
+ break;
+ case SPX5_TARGET_CT_7546TSN:
+ if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
+ freq = SPX5_CORE_CLOCK_625MHZ;
+ break;
+ case SPX5_TARGET_CT_7549TSN:
+ case SPX5_TARGET_CT_7552TSN:
+ case SPX5_TARGET_CT_7556TSN:
+ if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
+ freq = SPX5_CORE_CLOCK_625MHZ;
+ else if (sparx5->coreclock == SPX5_CORE_CLOCK_250MHZ)
+ freq = 0; /* Not supported */
+ break;
+ default:
+ dev_err(sparx5->dev, "Target (%#04x) not supported\n",
+ sparx5->target_ct);
+ return -ENODEV;
+ }
+
+ switch (freq) {
+ case SPX5_CORE_CLOCK_250MHZ:
+ clk_div = 10;
+ pol_upd_int = 312;
+ break;
+ case SPX5_CORE_CLOCK_500MHZ:
+ clk_div = 5;
+ pol_upd_int = 624;
+ break;
+ case SPX5_CORE_CLOCK_625MHZ:
+ clk_div = 4;
+ pol_upd_int = 780;
+ break;
+ default:
+ dev_err(sparx5->dev, "%d coreclock not supported on (%#04x)\n",
+ sparx5->coreclock, sparx5->target_ct);
+ return -EINVAL;
+ }
+
+ /* Update state with chosen frequency */
+ sparx5->coreclock = freq;
+
+ /* Configure the LCPLL */
+ spx5_rmw(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV_SET(clk_div) |
+ CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV_SET(0) |
+ CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR_SET(0) |
+ CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL_SET(0) |
+ CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA_SET(0) |
+ CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA_SET(1),
+ CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV |
+ CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV |
+ CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR |
+ CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL |
+ CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA |
+ CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA,
+ sparx5,
+ CLKGEN_LCPLL1_CORE_CLK_CFG);
+
+ clk_period = sparx5_clk_period(freq);
+
+ spx5_rmw(HSCH_SYS_CLK_PER_SYS_CLK_PER_100PS_SET(clk_period / 100),
+ HSCH_SYS_CLK_PER_SYS_CLK_PER_100PS,
+ sparx5,
+ HSCH_SYS_CLK_PER);
+
+ spx5_rmw(ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS_SET(clk_period / 100),
+ ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS,
+ sparx5,
+ ANA_AC_POL_BDLB_DLB_CTRL);
+
+ spx5_rmw(ANA_AC_POL_SLB_DLB_CTRL_CLK_PERIOD_01NS_SET(clk_period / 100),
+ ANA_AC_POL_SLB_DLB_CTRL_CLK_PERIOD_01NS,
+ sparx5,
+ ANA_AC_POL_SLB_DLB_CTRL);
+
+ spx5_rmw(LRN_AUTOAGE_CFG_1_CLK_PERIOD_01NS_SET(clk_period / 100),
+ LRN_AUTOAGE_CFG_1_CLK_PERIOD_01NS,
+ sparx5,
+ LRN_AUTOAGE_CFG_1);
+
+ for (idx = 0; idx < 3; idx++)
+ spx5_rmw(GCB_SIO_CLOCK_SYS_CLK_PERIOD_SET(clk_period / 100),
+ GCB_SIO_CLOCK_SYS_CLK_PERIOD,
+ sparx5,
+ GCB_SIO_CLOCK(idx));
+
+ spx5_rmw(HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY_SET
+ ((256 * 1000) / clk_period),
+ HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY,
+ sparx5,
+ HSCH_TAS_STATEMACHINE_CFG);
+
+ spx5_rmw(ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT_SET(pol_upd_int),
+ ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT,
+ sparx5,
+ ANA_AC_POL_POL_UPD_INT_CFG);
+
+ return 0;
+}
+
+static int sparx5_qlim_set(struct sparx5 *sparx5)
+{
+ u32 res, dp, prio;
+
+ for (res = 0; res < 2; res++) {
+ for (prio = 0; prio < 8; prio++)
+ spx5_wr(0xFFF, sparx5,
+ QRES_RES_CFG(prio + 630 + res * 1024));
+
+ for (dp = 0; dp < 4; dp++)
+ spx5_wr(0xFFF, sparx5,
+ QRES_RES_CFG(dp + 638 + res * 1024));
+ }
+
+ /* Set 80,90,95,100% of memory size for top watermarks */
+ spx5_wr(QLIM_WM(80), sparx5, XQS_QLIMIT_SHR_QLIM_CFG(0));
+ spx5_wr(QLIM_WM(90), sparx5, XQS_QLIMIT_SHR_CTOP_CFG(0));
+ spx5_wr(QLIM_WM(95), sparx5, XQS_QLIMIT_SHR_ATOP_CFG(0));
+ spx5_wr(QLIM_WM(100), sparx5, XQS_QLIMIT_SHR_TOP_CFG(0));
+
+ return 0;
+}
+
+/* Some boards needs to map the SGPIO for signal detect explicitly to the
+ * port module
+ */
+static void sparx5_board_init(struct sparx5 *sparx5)
+{
+ int idx;
+
+ if (!sparx5->sd_sgpio_remapping)
+ return;
+
+ /* Enable SGPIO Signal Detect remapping */
+ spx5_rmw(GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL,
+ GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL,
+ sparx5,
+ GCB_HW_SGPIO_SD_CFG);
+
+ /* Refer to LOS SGPIO */
+ for (idx = 0; idx < SPX5_PORTS; idx++)
+ if (sparx5->ports[idx])
+ if (sparx5->ports[idx]->conf.sd_sgpio != ~0)
+ spx5_wr(sparx5->ports[idx]->conf.sd_sgpio,
+ sparx5,
+ GCB_HW_SGPIO_TO_SD_MAP_CFG(idx));
+}
+
+static int sparx5_start(struct sparx5 *sparx5)
+{
+ u8 broadcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ char queue_name[32];
+ u32 idx;
+ int err;
+
+ /* Setup own UPSIDs */
+ for (idx = 0; idx < 3; idx++) {
+ spx5_wr(idx, sparx5, ANA_AC_OWN_UPSID(idx));
+ spx5_wr(idx, sparx5, ANA_CL_OWN_UPSID(idx));
+ spx5_wr(idx, sparx5, ANA_L2_OWN_UPSID(idx));
+ spx5_wr(idx, sparx5, REW_OWN_UPSID(idx));
+ }
+
+ /* Enable CPU ports */
+ for (idx = SPX5_PORTS; idx < SPX5_PORTS_ALL; idx++)
+ spx5_rmw(QFWD_SWITCH_PORT_MODE_PORT_ENA_SET(1),
+ QFWD_SWITCH_PORT_MODE_PORT_ENA,
+ sparx5,
+ QFWD_SWITCH_PORT_MODE(idx));
+
+ /* Init masks */
+ sparx5_update_fwd(sparx5);
+
+ /* CPU copy CPU pgids */
+ spx5_wr(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1),
+ sparx5, ANA_AC_PGID_MISC_CFG(PGID_CPU));
+ spx5_wr(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1),
+ sparx5, ANA_AC_PGID_MISC_CFG(PGID_BCAST));
+
+ /* Recalc injected frame FCS */
+ for (idx = SPX5_PORT_CPU_0; idx <= SPX5_PORT_CPU_1; idx++)
+ spx5_rmw(ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA_SET(1),
+ ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA,
+ sparx5, ANA_CL_FILTER_CTRL(idx));
+
+ /* Init MAC table, ageing */
+ sparx5_mact_init(sparx5);
+
+ /* Setup VLANs */
+ sparx5_vlan_init(sparx5);
+
+ /* Add host mode BC address (points only to CPU) */
+ sparx5_mact_learn(sparx5, PGID_CPU, broadcast, NULL_VID);
+
+ /* Enable queue limitation watermarks */
+ sparx5_qlim_set(sparx5);
+
+ err = sparx5_config_auto_calendar(sparx5);
+ if (err)
+ return err;
+
+ err = sparx5_config_dsm_calendar(sparx5);
+ if (err)
+ return err;
+
+ /* Init stats */
+ err = sparx_stats_init(sparx5);
+ if (err)
+ return err;
+
+ /* Init mact_sw struct */
+ mutex_init(&sparx5->mact_lock);
+ INIT_LIST_HEAD(&sparx5->mact_entries);
+ snprintf(queue_name, sizeof(queue_name), "%s-mact",
+ dev_name(sparx5->dev));
+ sparx5->mact_queue = create_singlethread_workqueue(queue_name);
+ INIT_DELAYED_WORK(&sparx5->mact_work, sparx5_mact_pull_work);
+ queue_delayed_work(sparx5->mact_queue, &sparx5->mact_work,
+ SPX5_MACT_PULL_DELAY);
+
+ err = sparx5_register_netdevs(sparx5);
+ if (err)
+ return err;
+
+ sparx5_board_init(sparx5);
+ err = sparx5_register_notifier_blocks(sparx5);
+
+ /* Start register based INJ/XTR */
+ err = -ENXIO;
+ if (err && sparx5->xtr_irq >= 0) {
+ err = devm_request_irq(sparx5->dev, sparx5->xtr_irq,
+ sparx5_xtr_handler, IRQF_SHARED,
+ "sparx5-xtr", sparx5);
+ if (!err)
+ err = sparx5_manual_injection_mode(sparx5);
+ if (err)
+ sparx5->xtr_irq = -ENXIO;
+ } else {
+ sparx5->xtr_irq = -ENXIO;
+ }
+ return err;
+}
+
+static void sparx5_cleanup_ports(struct sparx5 *sparx5)
+{
+ sparx5_unregister_netdevs(sparx5);
+ sparx5_destroy_netdevs(sparx5);
+}
+
+static int mchp_sparx5_probe(struct platform_device *pdev)
+{
+ struct initial_port_config *configs, *config;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *ports, *portnp;
+ struct reset_control *reset;
+ struct sparx5 *sparx5;
+ int idx = 0, err = 0;
+
+ if (!np && !pdev->dev.platform_data)
+ return -ENODEV;
+
+ sparx5 = devm_kzalloc(&pdev->dev, sizeof(*sparx5), GFP_KERNEL);
+ if (!sparx5)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, sparx5);
+ sparx5->pdev = pdev;
+ sparx5->dev = &pdev->dev;
+
+ /* Do switch core reset if available */
+ reset = devm_reset_control_get_optional_shared(&pdev->dev, "switch");
+ if (IS_ERR(reset))
+ return dev_err_probe(&pdev->dev, PTR_ERR(reset),
+ "Failed to get switch reset controller.\n");
+ reset_control_reset(reset);
+
+ /* Default values, some from DT */
+ sparx5->coreclock = SPX5_CORE_CLOCK_DEFAULT;
+
+ ports = of_get_child_by_name(np, "ethernet-ports");
+ if (!ports) {
+ dev_err(sparx5->dev, "no ethernet-ports child node found\n");
+ return -ENODEV;
+ }
+ sparx5->port_count = of_get_child_count(ports);
+
+ configs = kcalloc(sparx5->port_count,
+ sizeof(struct initial_port_config), GFP_KERNEL);
+ if (!configs) {
+ err = -ENOMEM;
+ goto cleanup_pnode;
+ }
+
+ for_each_available_child_of_node(ports, portnp) {
+ struct sparx5_port_config *conf;
+ struct phy *serdes;
+ u32 portno;
+
+ err = of_property_read_u32(portnp, "reg", &portno);
+ if (err) {
+ dev_err(sparx5->dev, "port reg property error\n");
+ continue;
+ }
+ config = &configs[idx];
+ conf = &config->conf;
+ conf->speed = SPEED_UNKNOWN;
+ conf->bandwidth = SPEED_UNKNOWN;
+ err = of_get_phy_mode(portnp, &conf->phy_mode);
+ if (err) {
+ dev_err(sparx5->dev, "port %u: missing phy-mode\n",
+ portno);
+ continue;
+ }
+ err = of_property_read_u32(portnp, "microchip,bandwidth",
+ &conf->bandwidth);
+ if (err) {
+ dev_err(sparx5->dev, "port %u: missing bandwidth\n",
+ portno);
+ continue;
+ }
+ err = of_property_read_u32(portnp, "microchip,sd-sgpio", &conf->sd_sgpio);
+ if (err)
+ conf->sd_sgpio = ~0;
+ else
+ sparx5->sd_sgpio_remapping = true;
+ serdes = devm_of_phy_get(sparx5->dev, portnp, NULL);
+ if (IS_ERR(serdes)) {
+ err = dev_err_probe(sparx5->dev, PTR_ERR(serdes),
+ "port %u: missing serdes\n",
+ portno);
+ goto cleanup_config;
+ }
+ config->portno = portno;
+ config->node = portnp;
+ config->serdes = serdes;
+
+ conf->media = PHY_MEDIA_DAC;
+ conf->serdes_reset = true;
+ conf->portmode = conf->phy_mode;
+ conf->power_down = true;
+ idx++;
+ }
+
+ err = sparx5_create_targets(sparx5);
+ if (err)
+ goto cleanup_config;
+
+ if (!of_get_mac_address(np, sparx5->base_mac)) {
+ dev_info(sparx5->dev, "MAC addr was not set, use random MAC\n");
+ eth_random_addr(sparx5->base_mac);
+ sparx5->base_mac[5] = 0;
+ }
+
+ sparx5->xtr_irq = platform_get_irq_byname(sparx5->pdev, "xtr");
+
+ /* Read chip ID to check CPU interface */
+ sparx5->chip_id = spx5_rd(sparx5, GCB_CHIP_ID);
+
+ sparx5->target_ct = (enum spx5_target_chiptype)
+ GCB_CHIP_ID_PART_ID_GET(sparx5->chip_id);
+
+ /* Initialize Switchcore and internal RAMs */
+ err = sparx5_init_switchcore(sparx5);
+ if (err) {
+ dev_err(sparx5->dev, "Switchcore initialization error\n");
+ goto cleanup_config;
+ }
+
+ /* Initialize the LC-PLL (core clock) and set affected registers */
+ err = sparx5_init_coreclock(sparx5);
+ if (err) {
+ dev_err(sparx5->dev, "LC-PLL initialization error\n");
+ goto cleanup_config;
+ }
+
+ for (idx = 0; idx < sparx5->port_count; ++idx) {
+ config = &configs[idx];
+ if (!config->node)
+ continue;
+
+ err = sparx5_create_port(sparx5, config);
+ if (err) {
+ dev_err(sparx5->dev, "port create error\n");
+ goto cleanup_ports;
+ }
+ }
+
+ err = sparx5_start(sparx5);
+ if (err) {
+ dev_err(sparx5->dev, "Start failed\n");
+ goto cleanup_ports;
+ }
+ goto cleanup_config;
+
+cleanup_ports:
+ sparx5_cleanup_ports(sparx5);
+cleanup_config:
+ kfree(configs);
+cleanup_pnode:
+ of_node_put(ports);
+ return err;
+}
+
+static int mchp_sparx5_remove(struct platform_device *pdev)
+{
+ struct sparx5 *sparx5 = platform_get_drvdata(pdev);
+
+ if (sparx5->xtr_irq) {
+ disable_irq(sparx5->xtr_irq);
+ sparx5->xtr_irq = -ENXIO;
+ }
+ sparx5_cleanup_ports(sparx5);
+ /* Unregister netdevs */
+ sparx5_unregister_notifier_blocks(sparx5);
+
+ return 0;
+}
+
+static const struct of_device_id mchp_sparx5_match[] = {
+ { .compatible = "microchip,sparx5-switch" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mchp_sparx5_match);
+
+static struct platform_driver mchp_sparx5_driver = {
+ .probe = mchp_sparx5_probe,
+ .remove = mchp_sparx5_remove,
+ .driver = {
+ .name = "sparx5-switch",
+ .of_match_table = mchp_sparx5_match,
+ },
+};
+
+module_platform_driver(mchp_sparx5_driver);
+
+MODULE_DESCRIPTION("Microchip Sparx5 switch driver");
+MODULE_AUTHOR("Steen Hegelund <steen.hegelund@microchip.com>");
+MODULE_LICENSE("Dual MIT/GPL");
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
new file mode 100644
index 000000000000..4d5f44c3a421
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
@@ -0,0 +1,375 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#ifndef __SPARX5_MAIN_H__
+#define __SPARX5_MAIN_H__
+
+#include <linux/types.h>
+#include <linux/phy/phy.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/if_vlan.h>
+#include <linux/bitmap.h>
+#include <linux/phylink.h>
+#include <linux/hrtimer.h>
+
+/* Target chip type */
+enum spx5_target_chiptype {
+ SPX5_TARGET_CT_7546 = 0x7546, /* SparX-5-64 Enterprise */
+ SPX5_TARGET_CT_7549 = 0x7549, /* SparX-5-90 Enterprise */
+ SPX5_TARGET_CT_7552 = 0x7552, /* SparX-5-128 Enterprise */
+ SPX5_TARGET_CT_7556 = 0x7556, /* SparX-5-160 Enterprise */
+ SPX5_TARGET_CT_7558 = 0x7558, /* SparX-5-200 Enterprise */
+ SPX5_TARGET_CT_7546TSN = 0x47546, /* SparX-5-64i Industrial */
+ SPX5_TARGET_CT_7549TSN = 0x47549, /* SparX-5-90i Industrial */
+ SPX5_TARGET_CT_7552TSN = 0x47552, /* SparX-5-128i Industrial */
+ SPX5_TARGET_CT_7556TSN = 0x47556, /* SparX-5-160i Industrial */
+ SPX5_TARGET_CT_7558TSN = 0x47558, /* SparX-5-200i Industrial */
+};
+
+enum sparx5_port_max_tags {
+ SPX5_PORT_MAX_TAGS_NONE, /* No extra tags allowed */
+ SPX5_PORT_MAX_TAGS_ONE, /* Single tag allowed */
+ SPX5_PORT_MAX_TAGS_TWO /* Single and double tag allowed */
+};
+
+enum sparx5_vlan_port_type {
+ SPX5_VLAN_PORT_TYPE_UNAWARE, /* VLAN unaware port */
+ SPX5_VLAN_PORT_TYPE_C, /* C-port */
+ SPX5_VLAN_PORT_TYPE_S, /* S-port */
+ SPX5_VLAN_PORT_TYPE_S_CUSTOM /* S-port using custom type */
+};
+
+#define SPX5_PORTS 65
+#define SPX5_PORT_CPU (SPX5_PORTS) /* Next port is CPU port */
+#define SPX5_PORT_CPU_0 (SPX5_PORT_CPU + 0) /* CPU Port 65 */
+#define SPX5_PORT_CPU_1 (SPX5_PORT_CPU + 1) /* CPU Port 66 */
+#define SPX5_PORT_VD0 (SPX5_PORT_CPU + 2) /* VD0/Port 67 used for IPMC */
+#define SPX5_PORT_VD1 (SPX5_PORT_CPU + 3) /* VD1/Port 68 used for AFI/OAM */
+#define SPX5_PORT_VD2 (SPX5_PORT_CPU + 4) /* VD2/Port 69 used for IPinIP*/
+#define SPX5_PORTS_ALL (SPX5_PORT_CPU + 5) /* Total number of ports */
+
+#define PGID_BASE SPX5_PORTS /* Starts after port PGIDs */
+#define PGID_UC_FLOOD (PGID_BASE + 0)
+#define PGID_MC_FLOOD (PGID_BASE + 1)
+#define PGID_IPV4_MC_DATA (PGID_BASE + 2)
+#define PGID_IPV4_MC_CTRL (PGID_BASE + 3)
+#define PGID_IPV6_MC_DATA (PGID_BASE + 4)
+#define PGID_IPV6_MC_CTRL (PGID_BASE + 5)
+#define PGID_BCAST (PGID_BASE + 6)
+#define PGID_CPU (PGID_BASE + 7)
+
+#define IFH_LEN 9 /* 36 bytes */
+#define NULL_VID 0
+#define SPX5_MACT_PULL_DELAY (2 * HZ)
+#define SPX5_STATS_CHECK_DELAY (1 * HZ)
+#define SPX5_PRIOS 8 /* Number of priority queues */
+#define SPX5_BUFFER_CELL_SZ 184 /* Cell size */
+#define SPX5_BUFFER_MEMORY 4194280 /* 22795 words * 184 bytes */
+
+#define XTR_QUEUE 0
+#define INJ_QUEUE 0
+
+struct sparx5;
+
+struct sparx5_port_config {
+ phy_interface_t portmode;
+ u32 bandwidth;
+ int speed;
+ int duplex;
+ enum phy_media media;
+ bool inband;
+ bool power_down;
+ bool autoneg;
+ bool serdes_reset;
+ u32 pause;
+ u32 pause_adv;
+ phy_interface_t phy_mode;
+ u32 sd_sgpio;
+};
+
+struct sparx5_port {
+ struct net_device *ndev;
+ struct sparx5 *sparx5;
+ struct device_node *of_node;
+ struct phy *serdes;
+ struct sparx5_port_config conf;
+ struct phylink_config phylink_config;
+ struct phylink *phylink;
+ struct phylink_pcs phylink_pcs;
+ u16 portno;
+ /* Ingress default VLAN (pvid) */
+ u16 pvid;
+ /* Egress default VLAN (vid) */
+ u16 vid;
+ bool signd_internal;
+ bool signd_active_high;
+ bool signd_enable;
+ bool flow_control;
+ enum sparx5_port_max_tags max_vlan_tags;
+ enum sparx5_vlan_port_type vlan_type;
+ u32 custom_etype;
+ u32 ifh[IFH_LEN];
+ bool vlan_aware;
+ struct hrtimer inj_timer;
+};
+
+enum sparx5_core_clockfreq {
+ SPX5_CORE_CLOCK_DEFAULT, /* Defaults to the highest supported frequency */
+ SPX5_CORE_CLOCK_250MHZ, /* 250MHZ core clock frequency */
+ SPX5_CORE_CLOCK_500MHZ, /* 500MHZ core clock frequency */
+ SPX5_CORE_CLOCK_625MHZ, /* 625MHZ core clock frequency */
+};
+
+struct sparx5 {
+ struct platform_device *pdev;
+ struct device *dev;
+ u32 chip_id;
+ enum spx5_target_chiptype target_ct;
+ void __iomem *regs[NUM_TARGETS];
+ int port_count;
+ struct mutex lock; /* MAC reg lock */
+ /* port structures are in net device */
+ struct sparx5_port *ports[SPX5_PORTS];
+ enum sparx5_core_clockfreq coreclock;
+ /* Statistics */
+ u32 num_stats;
+ u32 num_ethtool_stats;
+ const char * const *stats_layout;
+ u64 *stats;
+ /* Workqueue for reading stats */
+ struct mutex queue_stats_lock;
+ struct delayed_work stats_work;
+ struct workqueue_struct *stats_queue;
+ /* Notifiers */
+ struct notifier_block netdevice_nb;
+ struct notifier_block switchdev_nb;
+ struct notifier_block switchdev_blocking_nb;
+ /* Switch state */
+ u8 base_mac[ETH_ALEN];
+ /* Associated bridge device (when bridged) */
+ struct net_device *hw_bridge_dev;
+ /* Bridged interfaces */
+ DECLARE_BITMAP(bridge_mask, SPX5_PORTS);
+ DECLARE_BITMAP(bridge_fwd_mask, SPX5_PORTS);
+ DECLARE_BITMAP(bridge_lrn_mask, SPX5_PORTS);
+ DECLARE_BITMAP(vlan_mask[VLAN_N_VID], SPX5_PORTS);
+ /* SW MAC table */
+ struct list_head mact_entries;
+ /* mac table list (mact_entries) mutex */
+ struct mutex mact_lock;
+ struct delayed_work mact_work;
+ struct workqueue_struct *mact_queue;
+ /* Board specifics */
+ bool sd_sgpio_remapping;
+ /* Register based inj/xtr */
+ int xtr_irq;
+};
+
+/* sparx5_switchdev.c */
+int sparx5_register_notifier_blocks(struct sparx5 *sparx5);
+void sparx5_unregister_notifier_blocks(struct sparx5 *sparx5);
+
+/* sparx5_packet.c */
+irqreturn_t sparx5_xtr_handler(int irq, void *_priv);
+int sparx5_port_xmit_impl(struct sk_buff *skb, struct net_device *dev);
+int sparx5_manual_injection_mode(struct sparx5 *sparx5);
+void sparx5_port_inj_timer_setup(struct sparx5_port *port);
+
+/* sparx5_mactable.c */
+void sparx5_mact_pull_work(struct work_struct *work);
+int sparx5_mact_learn(struct sparx5 *sparx5, int port,
+ const unsigned char mac[ETH_ALEN], u16 vid);
+bool sparx5_mact_getnext(struct sparx5 *sparx5,
+ unsigned char mac[ETH_ALEN], u16 *vid, u32 *pcfg2);
+int sparx5_mact_forget(struct sparx5 *sparx5,
+ const unsigned char mac[ETH_ALEN], u16 vid);
+int sparx5_add_mact_entry(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ const unsigned char *addr, u16 vid);
+int sparx5_del_mact_entry(struct sparx5 *sparx5,
+ const unsigned char *addr,
+ u16 vid);
+int sparx5_mc_sync(struct net_device *dev, const unsigned char *addr);
+int sparx5_mc_unsync(struct net_device *dev, const unsigned char *addr);
+void sparx5_set_ageing(struct sparx5 *sparx5, int msecs);
+void sparx5_mact_init(struct sparx5 *sparx5);
+
+/* sparx5_vlan.c */
+void sparx5_pgid_update_mask(struct sparx5_port *port, int pgid, bool enable);
+void sparx5_update_fwd(struct sparx5 *sparx5);
+void sparx5_vlan_init(struct sparx5 *sparx5);
+void sparx5_vlan_port_setup(struct sparx5 *sparx5, int portno);
+int sparx5_vlan_vid_add(struct sparx5_port *port, u16 vid, bool pvid,
+ bool untagged);
+int sparx5_vlan_vid_del(struct sparx5_port *port, u16 vid);
+void sparx5_vlan_port_apply(struct sparx5 *sparx5, struct sparx5_port *port);
+
+/* sparx5_calendar.c */
+int sparx5_config_auto_calendar(struct sparx5 *sparx5);
+int sparx5_config_dsm_calendar(struct sparx5 *sparx5);
+
+/* sparx5_ethtool.c */
+void sparx5_get_stats64(struct net_device *ndev, struct rtnl_link_stats64 *stats);
+int sparx_stats_init(struct sparx5 *sparx5);
+
+/* sparx5_netdev.c */
+bool sparx5_netdevice_check(const struct net_device *dev);
+struct net_device *sparx5_create_netdev(struct sparx5 *sparx5, u32 portno);
+int sparx5_register_netdevs(struct sparx5 *sparx5);
+void sparx5_destroy_netdevs(struct sparx5 *sparx5);
+void sparx5_unregister_netdevs(struct sparx5 *sparx5);
+
+/* Clock period in picoseconds */
+static inline u32 sparx5_clk_period(enum sparx5_core_clockfreq cclock)
+{
+ switch (cclock) {
+ case SPX5_CORE_CLOCK_250MHZ:
+ return 4000;
+ case SPX5_CORE_CLOCK_500MHZ:
+ return 2000;
+ case SPX5_CORE_CLOCK_625MHZ:
+ default:
+ return 1600;
+ }
+}
+
+static inline bool sparx5_is_baser(phy_interface_t interface)
+{
+ return interface == PHY_INTERFACE_MODE_5GBASER ||
+ interface == PHY_INTERFACE_MODE_10GBASER ||
+ interface == PHY_INTERFACE_MODE_25GBASER;
+}
+
+extern const struct phylink_mac_ops sparx5_phylink_mac_ops;
+extern const struct phylink_pcs_ops sparx5_phylink_pcs_ops;
+extern const struct ethtool_ops sparx5_ethtool_ops;
+
+/* Calculate raw offset */
+static inline __pure int spx5_offset(int id, int tinst, int tcnt,
+ int gbase, int ginst,
+ int gcnt, int gwidth,
+ int raddr, int rinst,
+ int rcnt, int rwidth)
+{
+ WARN_ON((tinst) >= tcnt);
+ WARN_ON((ginst) >= gcnt);
+ WARN_ON((rinst) >= rcnt);
+ return gbase + ((ginst) * gwidth) +
+ raddr + ((rinst) * rwidth);
+}
+
+/* Read, Write and modify registers content.
+ * The register definition macros start at the id
+ */
+static inline void __iomem *spx5_addr(void __iomem *base[],
+ int id, int tinst, int tcnt,
+ int gbase, int ginst,
+ int gcnt, int gwidth,
+ int raddr, int rinst,
+ int rcnt, int rwidth)
+{
+ WARN_ON((tinst) >= tcnt);
+ WARN_ON((ginst) >= gcnt);
+ WARN_ON((rinst) >= rcnt);
+ return base[id + (tinst)] +
+ gbase + ((ginst) * gwidth) +
+ raddr + ((rinst) * rwidth);
+}
+
+static inline void __iomem *spx5_inst_addr(void __iomem *base,
+ int gbase, int ginst,
+ int gcnt, int gwidth,
+ int raddr, int rinst,
+ int rcnt, int rwidth)
+{
+ WARN_ON((ginst) >= gcnt);
+ WARN_ON((rinst) >= rcnt);
+ return base +
+ gbase + ((ginst) * gwidth) +
+ raddr + ((rinst) * rwidth);
+}
+
+static inline u32 spx5_rd(struct sparx5 *sparx5, int id, int tinst, int tcnt,
+ int gbase, int ginst, int gcnt, int gwidth,
+ int raddr, int rinst, int rcnt, int rwidth)
+{
+ return readl(spx5_addr(sparx5->regs, id, tinst, tcnt, gbase, ginst,
+ gcnt, gwidth, raddr, rinst, rcnt, rwidth));
+}
+
+static inline u32 spx5_inst_rd(void __iomem *iomem, int id, int tinst, int tcnt,
+ int gbase, int ginst, int gcnt, int gwidth,
+ int raddr, int rinst, int rcnt, int rwidth)
+{
+ return readl(spx5_inst_addr(iomem, gbase, ginst,
+ gcnt, gwidth, raddr, rinst, rcnt, rwidth));
+}
+
+static inline void spx5_wr(u32 val, struct sparx5 *sparx5,
+ int id, int tinst, int tcnt,
+ int gbase, int ginst, int gcnt, int gwidth,
+ int raddr, int rinst, int rcnt, int rwidth)
+{
+ writel(val, spx5_addr(sparx5->regs, id, tinst, tcnt,
+ gbase, ginst, gcnt, gwidth,
+ raddr, rinst, rcnt, rwidth));
+}
+
+static inline void spx5_inst_wr(u32 val, void __iomem *iomem,
+ int id, int tinst, int tcnt,
+ int gbase, int ginst, int gcnt, int gwidth,
+ int raddr, int rinst, int rcnt, int rwidth)
+{
+ writel(val, spx5_inst_addr(iomem,
+ gbase, ginst, gcnt, gwidth,
+ raddr, rinst, rcnt, rwidth));
+}
+
+static inline void spx5_rmw(u32 val, u32 mask, struct sparx5 *sparx5,
+ int id, int tinst, int tcnt,
+ int gbase, int ginst, int gcnt, int gwidth,
+ int raddr, int rinst, int rcnt, int rwidth)
+{
+ u32 nval;
+
+ nval = readl(spx5_addr(sparx5->regs, id, tinst, tcnt, gbase, ginst,
+ gcnt, gwidth, raddr, rinst, rcnt, rwidth));
+ nval = (nval & ~mask) | (val & mask);
+ writel(nval, spx5_addr(sparx5->regs, id, tinst, tcnt, gbase, ginst,
+ gcnt, gwidth, raddr, rinst, rcnt, rwidth));
+}
+
+static inline void spx5_inst_rmw(u32 val, u32 mask, void __iomem *iomem,
+ int id, int tinst, int tcnt,
+ int gbase, int ginst, int gcnt, int gwidth,
+ int raddr, int rinst, int rcnt, int rwidth)
+{
+ u32 nval;
+
+ nval = readl(spx5_inst_addr(iomem, gbase, ginst, gcnt, gwidth, raddr,
+ rinst, rcnt, rwidth));
+ nval = (nval & ~mask) | (val & mask);
+ writel(nval, spx5_inst_addr(iomem, gbase, ginst, gcnt, gwidth, raddr,
+ rinst, rcnt, rwidth));
+}
+
+static inline void __iomem *spx5_inst_get(struct sparx5 *sparx5, int id, int tinst)
+{
+ return sparx5->regs[id + tinst];
+}
+
+static inline void __iomem *spx5_reg_get(struct sparx5 *sparx5,
+ int id, int tinst, int tcnt,
+ int gbase, int ginst, int gcnt, int gwidth,
+ int raddr, int rinst, int rcnt, int rwidth)
+{
+ return spx5_addr(sparx5->regs, id, tinst, tcnt,
+ gbase, ginst, gcnt, gwidth,
+ raddr, rinst, rcnt, rwidth);
+}
+
+#endif /* __SPARX5_MAIN_H__ */
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h
new file mode 100644
index 000000000000..5ab2373a7178
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h
@@ -0,0 +1,4642 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ * Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2021 Microchip Technology Inc.
+ */
+
+/* This file is autogenerated by cml-utils 2021-05-06 13:06:37 +0200.
+ * Commit ID: 9ae4ec441e25e4b9003f4e514df5cb12a36b84d3
+ */
+
+#ifndef _SPARX5_MAIN_REGS_H_
+#define _SPARX5_MAIN_REGS_H_
+
+#include <linux/bitfield.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+
+enum sparx5_target {
+ TARGET_ANA_AC = 1,
+ TARGET_ANA_ACL = 2,
+ TARGET_ANA_AC_POL = 4,
+ TARGET_ANA_CL = 6,
+ TARGET_ANA_L2 = 7,
+ TARGET_ANA_L3 = 8,
+ TARGET_ASM = 9,
+ TARGET_CLKGEN = 11,
+ TARGET_CPU = 12,
+ TARGET_DEV10G = 17,
+ TARGET_DEV25G = 29,
+ TARGET_DEV2G5 = 37,
+ TARGET_DEV5G = 102,
+ TARGET_DSM = 115,
+ TARGET_EACL = 116,
+ TARGET_FDMA = 117,
+ TARGET_GCB = 118,
+ TARGET_HSCH = 119,
+ TARGET_LRN = 122,
+ TARGET_PCEP = 129,
+ TARGET_PCS10G_BR = 132,
+ TARGET_PCS25G_BR = 144,
+ TARGET_PCS5G_BR = 160,
+ TARGET_PORT_CONF = 173,
+ TARGET_QFWD = 175,
+ TARGET_QRES = 176,
+ TARGET_QS = 177,
+ TARGET_QSYS = 178,
+ TARGET_REW = 179,
+ TARGET_VCAP_SUPER = 326,
+ TARGET_VOP = 327,
+ TARGET_XQS = 331,
+ NUM_TARGETS = 332
+};
+
+#define __REG(...) __VA_ARGS__
+
+/* ANA_AC:RAM_CTRL:RAM_INIT */
+#define ANA_AC_RAM_INIT __REG(TARGET_ANA_AC, 0, 1, 839108, 0, 1, 4, 0, 0, 1, 4)
+
+#define ANA_AC_RAM_INIT_RAM_INIT BIT(1)
+#define ANA_AC_RAM_INIT_RAM_INIT_SET(x)\
+ FIELD_PREP(ANA_AC_RAM_INIT_RAM_INIT, x)
+#define ANA_AC_RAM_INIT_RAM_INIT_GET(x)\
+ FIELD_GET(ANA_AC_RAM_INIT_RAM_INIT, x)
+
+#define ANA_AC_RAM_INIT_RAM_CFG_HOOK BIT(0)
+#define ANA_AC_RAM_INIT_RAM_CFG_HOOK_SET(x)\
+ FIELD_PREP(ANA_AC_RAM_INIT_RAM_CFG_HOOK, x)
+#define ANA_AC_RAM_INIT_RAM_CFG_HOOK_GET(x)\
+ FIELD_GET(ANA_AC_RAM_INIT_RAM_CFG_HOOK, x)
+
+/* ANA_AC:PS_COMMON:OWN_UPSID */
+#define ANA_AC_OWN_UPSID(r) __REG(TARGET_ANA_AC, 0, 1, 894472, 0, 1, 352, 52, r, 3, 4)
+
+#define ANA_AC_OWN_UPSID_OWN_UPSID GENMASK(4, 0)
+#define ANA_AC_OWN_UPSID_OWN_UPSID_SET(x)\
+ FIELD_PREP(ANA_AC_OWN_UPSID_OWN_UPSID, x)
+#define ANA_AC_OWN_UPSID_OWN_UPSID_GET(x)\
+ FIELD_GET(ANA_AC_OWN_UPSID_OWN_UPSID, x)
+
+/* ANA_AC:SRC:SRC_CFG */
+#define ANA_AC_SRC_CFG(g) __REG(TARGET_ANA_AC, 0, 1, 849920, g, 102, 16, 0, 0, 1, 4)
+
+/* ANA_AC:SRC:SRC_CFG1 */
+#define ANA_AC_SRC_CFG1(g) __REG(TARGET_ANA_AC, 0, 1, 849920, g, 102, 16, 4, 0, 1, 4)
+
+/* ANA_AC:SRC:SRC_CFG2 */
+#define ANA_AC_SRC_CFG2(g) __REG(TARGET_ANA_AC, 0, 1, 849920, g, 102, 16, 8, 0, 1, 4)
+
+#define ANA_AC_SRC_CFG2_PORT_MASK2 BIT(0)
+#define ANA_AC_SRC_CFG2_PORT_MASK2_SET(x)\
+ FIELD_PREP(ANA_AC_SRC_CFG2_PORT_MASK2, x)
+#define ANA_AC_SRC_CFG2_PORT_MASK2_GET(x)\
+ FIELD_GET(ANA_AC_SRC_CFG2_PORT_MASK2, x)
+
+/* ANA_AC:PGID:PGID_CFG */
+#define ANA_AC_PGID_CFG(g) __REG(TARGET_ANA_AC, 0, 1, 786432, g, 3290, 16, 0, 0, 1, 4)
+
+/* ANA_AC:PGID:PGID_CFG1 */
+#define ANA_AC_PGID_CFG1(g) __REG(TARGET_ANA_AC, 0, 1, 786432, g, 3290, 16, 4, 0, 1, 4)
+
+/* ANA_AC:PGID:PGID_CFG2 */
+#define ANA_AC_PGID_CFG2(g) __REG(TARGET_ANA_AC, 0, 1, 786432, g, 3290, 16, 8, 0, 1, 4)
+
+#define ANA_AC_PGID_CFG2_PORT_MASK2 BIT(0)
+#define ANA_AC_PGID_CFG2_PORT_MASK2_SET(x)\
+ FIELD_PREP(ANA_AC_PGID_CFG2_PORT_MASK2, x)
+#define ANA_AC_PGID_CFG2_PORT_MASK2_GET(x)\
+ FIELD_GET(ANA_AC_PGID_CFG2_PORT_MASK2, x)
+
+/* ANA_AC:PGID:PGID_MISC_CFG */
+#define ANA_AC_PGID_MISC_CFG(g) __REG(TARGET_ANA_AC, 0, 1, 786432, g, 3290, 16, 12, 0, 1, 4)
+
+#define ANA_AC_PGID_MISC_CFG_PGID_CPU_QU GENMASK(6, 4)
+#define ANA_AC_PGID_MISC_CFG_PGID_CPU_QU_SET(x)\
+ FIELD_PREP(ANA_AC_PGID_MISC_CFG_PGID_CPU_QU, x)
+#define ANA_AC_PGID_MISC_CFG_PGID_CPU_QU_GET(x)\
+ FIELD_GET(ANA_AC_PGID_MISC_CFG_PGID_CPU_QU, x)
+
+#define ANA_AC_PGID_MISC_CFG_STACK_TYPE_ENA BIT(1)
+#define ANA_AC_PGID_MISC_CFG_STACK_TYPE_ENA_SET(x)\
+ FIELD_PREP(ANA_AC_PGID_MISC_CFG_STACK_TYPE_ENA, x)
+#define ANA_AC_PGID_MISC_CFG_STACK_TYPE_ENA_GET(x)\
+ FIELD_GET(ANA_AC_PGID_MISC_CFG_STACK_TYPE_ENA, x)
+
+#define ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA BIT(0)
+#define ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(x)\
+ FIELD_PREP(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA, x)
+#define ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_GET(x)\
+ FIELD_GET(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA, x)
+
+/* ANA_AC:STAT_GLOBAL_CFG_PORT:STAT_GLOBAL_EVENT_MASK */
+#define ANA_AC_PORT_SGE_CFG(r) __REG(TARGET_ANA_AC, 0, 1, 851552, 0, 1, 20, 0, r, 4, 4)
+
+#define ANA_AC_PORT_SGE_CFG_MASK GENMASK(15, 0)
+#define ANA_AC_PORT_SGE_CFG_MASK_SET(x)\
+ FIELD_PREP(ANA_AC_PORT_SGE_CFG_MASK, x)
+#define ANA_AC_PORT_SGE_CFG_MASK_GET(x)\
+ FIELD_GET(ANA_AC_PORT_SGE_CFG_MASK, x)
+
+/* ANA_AC:STAT_GLOBAL_CFG_PORT:STAT_RESET */
+#define ANA_AC_STAT_RESET __REG(TARGET_ANA_AC, 0, 1, 851552, 0, 1, 20, 16, 0, 1, 4)
+
+#define ANA_AC_STAT_RESET_RESET BIT(0)
+#define ANA_AC_STAT_RESET_RESET_SET(x)\
+ FIELD_PREP(ANA_AC_STAT_RESET_RESET, x)
+#define ANA_AC_STAT_RESET_RESET_GET(x)\
+ FIELD_GET(ANA_AC_STAT_RESET_RESET, x)
+
+/* ANA_AC:STAT_CNT_CFG_PORT:STAT_CFG */
+#define ANA_AC_PORT_STAT_CFG(g, r) __REG(TARGET_ANA_AC, 0, 1, 843776, g, 70, 64, 4, r, 4, 4)
+
+#define ANA_AC_PORT_STAT_CFG_CFG_PRIO_MASK GENMASK(11, 4)
+#define ANA_AC_PORT_STAT_CFG_CFG_PRIO_MASK_SET(x)\
+ FIELD_PREP(ANA_AC_PORT_STAT_CFG_CFG_PRIO_MASK, x)
+#define ANA_AC_PORT_STAT_CFG_CFG_PRIO_MASK_GET(x)\
+ FIELD_GET(ANA_AC_PORT_STAT_CFG_CFG_PRIO_MASK, x)
+
+#define ANA_AC_PORT_STAT_CFG_CFG_CNT_FRM_TYPE GENMASK(3, 1)
+#define ANA_AC_PORT_STAT_CFG_CFG_CNT_FRM_TYPE_SET(x)\
+ FIELD_PREP(ANA_AC_PORT_STAT_CFG_CFG_CNT_FRM_TYPE, x)
+#define ANA_AC_PORT_STAT_CFG_CFG_CNT_FRM_TYPE_GET(x)\
+ FIELD_GET(ANA_AC_PORT_STAT_CFG_CFG_CNT_FRM_TYPE, x)
+
+#define ANA_AC_PORT_STAT_CFG_CFG_CNT_BYTE BIT(0)
+#define ANA_AC_PORT_STAT_CFG_CFG_CNT_BYTE_SET(x)\
+ FIELD_PREP(ANA_AC_PORT_STAT_CFG_CFG_CNT_BYTE, x)
+#define ANA_AC_PORT_STAT_CFG_CFG_CNT_BYTE_GET(x)\
+ FIELD_GET(ANA_AC_PORT_STAT_CFG_CFG_CNT_BYTE, x)
+
+/* ANA_AC:STAT_CNT_CFG_PORT:STAT_LSB_CNT */
+#define ANA_AC_PORT_STAT_LSB_CNT(g, r) __REG(TARGET_ANA_AC, 0, 1, 843776, g, 70, 64, 20, r, 4, 4)
+
+/* ANA_ACL:COMMON:OWN_UPSID */
+#define ANA_ACL_OWN_UPSID(r) __REG(TARGET_ANA_ACL, 0, 1, 32768, 0, 1, 592, 580, r, 3, 4)
+
+#define ANA_ACL_OWN_UPSID_OWN_UPSID GENMASK(4, 0)
+#define ANA_ACL_OWN_UPSID_OWN_UPSID_SET(x)\
+ FIELD_PREP(ANA_ACL_OWN_UPSID_OWN_UPSID, x)
+#define ANA_ACL_OWN_UPSID_OWN_UPSID_GET(x)\
+ FIELD_GET(ANA_ACL_OWN_UPSID_OWN_UPSID, x)
+
+/* ANA_AC_POL:POL_ALL_CFG:POL_UPD_INT_CFG */
+#define ANA_AC_POL_POL_UPD_INT_CFG __REG(TARGET_ANA_AC_POL, 0, 1, 75968, 0, 1, 1160, 1148, 0, 1, 4)
+
+#define ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT GENMASK(9, 0)
+#define ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT_SET(x)\
+ FIELD_PREP(ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT, x)
+#define ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT_GET(x)\
+ FIELD_GET(ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT, x)
+
+/* ANA_AC_POL:COMMON_BDLB:DLB_CTRL */
+#define ANA_AC_POL_BDLB_DLB_CTRL __REG(TARGET_ANA_AC_POL, 0, 1, 79048, 0, 1, 8, 0, 0, 1, 4)
+
+#define ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS GENMASK(26, 19)
+#define ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS_SET(x)\
+ FIELD_PREP(ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS, x)
+#define ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS_GET(x)\
+ FIELD_GET(ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS, x)
+
+#define ANA_AC_POL_BDLB_DLB_CTRL_BASE_TICK_CNT GENMASK(18, 4)
+#define ANA_AC_POL_BDLB_DLB_CTRL_BASE_TICK_CNT_SET(x)\
+ FIELD_PREP(ANA_AC_POL_BDLB_DLB_CTRL_BASE_TICK_CNT, x)
+#define ANA_AC_POL_BDLB_DLB_CTRL_BASE_TICK_CNT_GET(x)\
+ FIELD_GET(ANA_AC_POL_BDLB_DLB_CTRL_BASE_TICK_CNT, x)
+
+#define ANA_AC_POL_BDLB_DLB_CTRL_LEAK_ENA BIT(1)
+#define ANA_AC_POL_BDLB_DLB_CTRL_LEAK_ENA_SET(x)\
+ FIELD_PREP(ANA_AC_POL_BDLB_DLB_CTRL_LEAK_ENA, x)
+#define ANA_AC_POL_BDLB_DLB_CTRL_LEAK_ENA_GET(x)\
+ FIELD_GET(ANA_AC_POL_BDLB_DLB_CTRL_LEAK_ENA, x)
+
+#define ANA_AC_POL_BDLB_DLB_CTRL_DLB_ADD_ENA BIT(0)
+#define ANA_AC_POL_BDLB_DLB_CTRL_DLB_ADD_ENA_SET(x)\
+ FIELD_PREP(ANA_AC_POL_BDLB_DLB_CTRL_DLB_ADD_ENA, x)
+#define ANA_AC_POL_BDLB_DLB_CTRL_DLB_ADD_ENA_GET(x)\
+ FIELD_GET(ANA_AC_POL_BDLB_DLB_CTRL_DLB_ADD_ENA, x)
+
+/* ANA_AC_POL:COMMON_BUM_SLB:DLB_CTRL */
+#define ANA_AC_POL_SLB_DLB_CTRL __REG(TARGET_ANA_AC_POL, 0, 1, 79056, 0, 1, 20, 0, 0, 1, 4)
+
+#define ANA_AC_POL_SLB_DLB_CTRL_CLK_PERIOD_01NS GENMASK(26, 19)
+#define ANA_AC_POL_SLB_DLB_CTRL_CLK_PERIOD_01NS_SET(x)\
+ FIELD_PREP(ANA_AC_POL_SLB_DLB_CTRL_CLK_PERIOD_01NS, x)
+#define ANA_AC_POL_SLB_DLB_CTRL_CLK_PERIOD_01NS_GET(x)\
+ FIELD_GET(ANA_AC_POL_SLB_DLB_CTRL_CLK_PERIOD_01NS, x)
+
+#define ANA_AC_POL_SLB_DLB_CTRL_BASE_TICK_CNT GENMASK(18, 4)
+#define ANA_AC_POL_SLB_DLB_CTRL_BASE_TICK_CNT_SET(x)\
+ FIELD_PREP(ANA_AC_POL_SLB_DLB_CTRL_BASE_TICK_CNT, x)
+#define ANA_AC_POL_SLB_DLB_CTRL_BASE_TICK_CNT_GET(x)\
+ FIELD_GET(ANA_AC_POL_SLB_DLB_CTRL_BASE_TICK_CNT, x)
+
+#define ANA_AC_POL_SLB_DLB_CTRL_LEAK_ENA BIT(1)
+#define ANA_AC_POL_SLB_DLB_CTRL_LEAK_ENA_SET(x)\
+ FIELD_PREP(ANA_AC_POL_SLB_DLB_CTRL_LEAK_ENA, x)
+#define ANA_AC_POL_SLB_DLB_CTRL_LEAK_ENA_GET(x)\
+ FIELD_GET(ANA_AC_POL_SLB_DLB_CTRL_LEAK_ENA, x)
+
+#define ANA_AC_POL_SLB_DLB_CTRL_DLB_ADD_ENA BIT(0)
+#define ANA_AC_POL_SLB_DLB_CTRL_DLB_ADD_ENA_SET(x)\
+ FIELD_PREP(ANA_AC_POL_SLB_DLB_CTRL_DLB_ADD_ENA, x)
+#define ANA_AC_POL_SLB_DLB_CTRL_DLB_ADD_ENA_GET(x)\
+ FIELD_GET(ANA_AC_POL_SLB_DLB_CTRL_DLB_ADD_ENA, x)
+
+/* ANA_CL:PORT:FILTER_CTRL */
+#define ANA_CL_FILTER_CTRL(g) __REG(TARGET_ANA_CL, 0, 1, 131072, g, 70, 512, 4, 0, 1, 4)
+
+#define ANA_CL_FILTER_CTRL_FILTER_SMAC_MC_DIS BIT(2)
+#define ANA_CL_FILTER_CTRL_FILTER_SMAC_MC_DIS_SET(x)\
+ FIELD_PREP(ANA_CL_FILTER_CTRL_FILTER_SMAC_MC_DIS, x)
+#define ANA_CL_FILTER_CTRL_FILTER_SMAC_MC_DIS_GET(x)\
+ FIELD_GET(ANA_CL_FILTER_CTRL_FILTER_SMAC_MC_DIS, x)
+
+#define ANA_CL_FILTER_CTRL_FILTER_NULL_MAC_DIS BIT(1)
+#define ANA_CL_FILTER_CTRL_FILTER_NULL_MAC_DIS_SET(x)\
+ FIELD_PREP(ANA_CL_FILTER_CTRL_FILTER_NULL_MAC_DIS, x)
+#define ANA_CL_FILTER_CTRL_FILTER_NULL_MAC_DIS_GET(x)\
+ FIELD_GET(ANA_CL_FILTER_CTRL_FILTER_NULL_MAC_DIS, x)
+
+#define ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA BIT(0)
+#define ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA_SET(x)\
+ FIELD_PREP(ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA, x)
+#define ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA_GET(x)\
+ FIELD_GET(ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA, x)
+
+/* ANA_CL:PORT:VLAN_FILTER_CTRL */
+#define ANA_CL_VLAN_FILTER_CTRL(g, r) __REG(TARGET_ANA_CL, 0, 1, 131072, g, 70, 512, 8, r, 3, 4)
+
+#define ANA_CL_VLAN_FILTER_CTRL_TAG_REQUIRED_ENA BIT(10)
+#define ANA_CL_VLAN_FILTER_CTRL_TAG_REQUIRED_ENA_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_FILTER_CTRL_TAG_REQUIRED_ENA, x)
+#define ANA_CL_VLAN_FILTER_CTRL_TAG_REQUIRED_ENA_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_FILTER_CTRL_TAG_REQUIRED_ENA, x)
+
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_CTAG_DIS BIT(9)
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_CTAG_DIS_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_FILTER_CTRL_PRIO_CTAG_DIS, x)
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_CTAG_DIS_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_FILTER_CTRL_PRIO_CTAG_DIS, x)
+
+#define ANA_CL_VLAN_FILTER_CTRL_CTAG_DIS BIT(8)
+#define ANA_CL_VLAN_FILTER_CTRL_CTAG_DIS_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_FILTER_CTRL_CTAG_DIS, x)
+#define ANA_CL_VLAN_FILTER_CTRL_CTAG_DIS_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_FILTER_CTRL_CTAG_DIS, x)
+
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_STAG_DIS BIT(7)
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_STAG_DIS_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_FILTER_CTRL_PRIO_STAG_DIS, x)
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_STAG_DIS_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_FILTER_CTRL_PRIO_STAG_DIS, x)
+
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST1_STAG_DIS BIT(6)
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST1_STAG_DIS_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST1_STAG_DIS, x)
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST1_STAG_DIS_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST1_STAG_DIS, x)
+
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST2_STAG_DIS BIT(5)
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST2_STAG_DIS_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST2_STAG_DIS, x)
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST2_STAG_DIS_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST2_STAG_DIS, x)
+
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST3_STAG_DIS BIT(4)
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST3_STAG_DIS_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST3_STAG_DIS, x)
+#define ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST3_STAG_DIS_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_FILTER_CTRL_PRIO_CUST3_STAG_DIS, x)
+
+#define ANA_CL_VLAN_FILTER_CTRL_STAG_DIS BIT(3)
+#define ANA_CL_VLAN_FILTER_CTRL_STAG_DIS_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_FILTER_CTRL_STAG_DIS, x)
+#define ANA_CL_VLAN_FILTER_CTRL_STAG_DIS_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_FILTER_CTRL_STAG_DIS, x)
+
+#define ANA_CL_VLAN_FILTER_CTRL_CUST1_STAG_DIS BIT(2)
+#define ANA_CL_VLAN_FILTER_CTRL_CUST1_STAG_DIS_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_FILTER_CTRL_CUST1_STAG_DIS, x)
+#define ANA_CL_VLAN_FILTER_CTRL_CUST1_STAG_DIS_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_FILTER_CTRL_CUST1_STAG_DIS, x)
+
+#define ANA_CL_VLAN_FILTER_CTRL_CUST2_STAG_DIS BIT(1)
+#define ANA_CL_VLAN_FILTER_CTRL_CUST2_STAG_DIS_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_FILTER_CTRL_CUST2_STAG_DIS, x)
+#define ANA_CL_VLAN_FILTER_CTRL_CUST2_STAG_DIS_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_FILTER_CTRL_CUST2_STAG_DIS, x)
+
+#define ANA_CL_VLAN_FILTER_CTRL_CUST3_STAG_DIS BIT(0)
+#define ANA_CL_VLAN_FILTER_CTRL_CUST3_STAG_DIS_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_FILTER_CTRL_CUST3_STAG_DIS, x)
+#define ANA_CL_VLAN_FILTER_CTRL_CUST3_STAG_DIS_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_FILTER_CTRL_CUST3_STAG_DIS, x)
+
+/* ANA_CL:PORT:ETAG_FILTER_CTRL */
+#define ANA_CL_ETAG_FILTER_CTRL(g) __REG(TARGET_ANA_CL, 0, 1, 131072, g, 70, 512, 20, 0, 1, 4)
+
+#define ANA_CL_ETAG_FILTER_CTRL_ETAG_REQUIRED_ENA BIT(1)
+#define ANA_CL_ETAG_FILTER_CTRL_ETAG_REQUIRED_ENA_SET(x)\
+ FIELD_PREP(ANA_CL_ETAG_FILTER_CTRL_ETAG_REQUIRED_ENA, x)
+#define ANA_CL_ETAG_FILTER_CTRL_ETAG_REQUIRED_ENA_GET(x)\
+ FIELD_GET(ANA_CL_ETAG_FILTER_CTRL_ETAG_REQUIRED_ENA, x)
+
+#define ANA_CL_ETAG_FILTER_CTRL_ETAG_DIS BIT(0)
+#define ANA_CL_ETAG_FILTER_CTRL_ETAG_DIS_SET(x)\
+ FIELD_PREP(ANA_CL_ETAG_FILTER_CTRL_ETAG_DIS, x)
+#define ANA_CL_ETAG_FILTER_CTRL_ETAG_DIS_GET(x)\
+ FIELD_GET(ANA_CL_ETAG_FILTER_CTRL_ETAG_DIS, x)
+
+/* ANA_CL:PORT:VLAN_CTRL */
+#define ANA_CL_VLAN_CTRL(g) __REG(TARGET_ANA_CL, 0, 1, 131072, g, 70, 512, 32, 0, 1, 4)
+
+#define ANA_CL_VLAN_CTRL_PORT_VOE_TPID_AWARE_DIS GENMASK(30, 26)
+#define ANA_CL_VLAN_CTRL_PORT_VOE_TPID_AWARE_DIS_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_CTRL_PORT_VOE_TPID_AWARE_DIS, x)
+#define ANA_CL_VLAN_CTRL_PORT_VOE_TPID_AWARE_DIS_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_CTRL_PORT_VOE_TPID_AWARE_DIS, x)
+
+#define ANA_CL_VLAN_CTRL_PORT_VOE_DEFAULT_PCP GENMASK(25, 23)
+#define ANA_CL_VLAN_CTRL_PORT_VOE_DEFAULT_PCP_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_CTRL_PORT_VOE_DEFAULT_PCP, x)
+#define ANA_CL_VLAN_CTRL_PORT_VOE_DEFAULT_PCP_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_CTRL_PORT_VOE_DEFAULT_PCP, x)
+
+#define ANA_CL_VLAN_CTRL_PORT_VOE_DEFAULT_DEI BIT(22)
+#define ANA_CL_VLAN_CTRL_PORT_VOE_DEFAULT_DEI_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_CTRL_PORT_VOE_DEFAULT_DEI, x)
+#define ANA_CL_VLAN_CTRL_PORT_VOE_DEFAULT_DEI_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_CTRL_PORT_VOE_DEFAULT_DEI, x)
+
+#define ANA_CL_VLAN_CTRL_VLAN_PCP_DEI_TRANS_ENA BIT(21)
+#define ANA_CL_VLAN_CTRL_VLAN_PCP_DEI_TRANS_ENA_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_CTRL_VLAN_PCP_DEI_TRANS_ENA, x)
+#define ANA_CL_VLAN_CTRL_VLAN_PCP_DEI_TRANS_ENA_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_CTRL_VLAN_PCP_DEI_TRANS_ENA, x)
+
+#define ANA_CL_VLAN_CTRL_VLAN_TAG_SEL BIT(20)
+#define ANA_CL_VLAN_CTRL_VLAN_TAG_SEL_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_CTRL_VLAN_TAG_SEL, x)
+#define ANA_CL_VLAN_CTRL_VLAN_TAG_SEL_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_CTRL_VLAN_TAG_SEL, x)
+
+#define ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA BIT(19)
+#define ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA, x)
+#define ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA, x)
+
+#define ANA_CL_VLAN_CTRL_VLAN_POP_CNT GENMASK(18, 17)
+#define ANA_CL_VLAN_CTRL_VLAN_POP_CNT_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_CTRL_VLAN_POP_CNT, x)
+#define ANA_CL_VLAN_CTRL_VLAN_POP_CNT_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_CTRL_VLAN_POP_CNT, x)
+
+#define ANA_CL_VLAN_CTRL_PORT_TAG_TYPE BIT(16)
+#define ANA_CL_VLAN_CTRL_PORT_TAG_TYPE_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_CTRL_PORT_TAG_TYPE, x)
+#define ANA_CL_VLAN_CTRL_PORT_TAG_TYPE_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_CTRL_PORT_TAG_TYPE, x)
+
+#define ANA_CL_VLAN_CTRL_PORT_PCP GENMASK(15, 13)
+#define ANA_CL_VLAN_CTRL_PORT_PCP_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_CTRL_PORT_PCP, x)
+#define ANA_CL_VLAN_CTRL_PORT_PCP_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_CTRL_PORT_PCP, x)
+
+#define ANA_CL_VLAN_CTRL_PORT_DEI BIT(12)
+#define ANA_CL_VLAN_CTRL_PORT_DEI_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_CTRL_PORT_DEI, x)
+#define ANA_CL_VLAN_CTRL_PORT_DEI_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_CTRL_PORT_DEI, x)
+
+#define ANA_CL_VLAN_CTRL_PORT_VID GENMASK(11, 0)
+#define ANA_CL_VLAN_CTRL_PORT_VID_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_CTRL_PORT_VID, x)
+#define ANA_CL_VLAN_CTRL_PORT_VID_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_CTRL_PORT_VID, x)
+
+/* ANA_CL:PORT:VLAN_CTRL_2 */
+#define ANA_CL_VLAN_CTRL_2(g) __REG(TARGET_ANA_CL, 0, 1, 131072, g, 70, 512, 36, 0, 1, 4)
+
+#define ANA_CL_VLAN_CTRL_2_VLAN_PUSH_CNT GENMASK(1, 0)
+#define ANA_CL_VLAN_CTRL_2_VLAN_PUSH_CNT_SET(x)\
+ FIELD_PREP(ANA_CL_VLAN_CTRL_2_VLAN_PUSH_CNT, x)
+#define ANA_CL_VLAN_CTRL_2_VLAN_PUSH_CNT_GET(x)\
+ FIELD_GET(ANA_CL_VLAN_CTRL_2_VLAN_PUSH_CNT, x)
+
+/* ANA_CL:PORT:CAPTURE_BPDU_CFG */
+#define ANA_CL_CAPTURE_BPDU_CFG(g) __REG(TARGET_ANA_CL, 0, 1, 131072, g, 70, 512, 196, 0, 1, 4)
+
+/* ANA_CL:COMMON:OWN_UPSID */
+#define ANA_CL_OWN_UPSID(r) __REG(TARGET_ANA_CL, 0, 1, 166912, 0, 1, 756, 0, r, 3, 4)
+
+#define ANA_CL_OWN_UPSID_OWN_UPSID GENMASK(4, 0)
+#define ANA_CL_OWN_UPSID_OWN_UPSID_SET(x)\
+ FIELD_PREP(ANA_CL_OWN_UPSID_OWN_UPSID, x)
+#define ANA_CL_OWN_UPSID_OWN_UPSID_GET(x)\
+ FIELD_GET(ANA_CL_OWN_UPSID_OWN_UPSID, x)
+
+/* ANA_L2:COMMON:AUTO_LRN_CFG */
+#define ANA_L2_AUTO_LRN_CFG __REG(TARGET_ANA_L2, 0, 1, 566024, 0, 1, 700, 24, 0, 1, 4)
+
+/* ANA_L2:COMMON:AUTO_LRN_CFG1 */
+#define ANA_L2_AUTO_LRN_CFG1 __REG(TARGET_ANA_L2, 0, 1, 566024, 0, 1, 700, 28, 0, 1, 4)
+
+/* ANA_L2:COMMON:AUTO_LRN_CFG2 */
+#define ANA_L2_AUTO_LRN_CFG2 __REG(TARGET_ANA_L2, 0, 1, 566024, 0, 1, 700, 32, 0, 1, 4)
+
+#define ANA_L2_AUTO_LRN_CFG2_AUTO_LRN_ENA2 BIT(0)
+#define ANA_L2_AUTO_LRN_CFG2_AUTO_LRN_ENA2_SET(x)\
+ FIELD_PREP(ANA_L2_AUTO_LRN_CFG2_AUTO_LRN_ENA2, x)
+#define ANA_L2_AUTO_LRN_CFG2_AUTO_LRN_ENA2_GET(x)\
+ FIELD_GET(ANA_L2_AUTO_LRN_CFG2_AUTO_LRN_ENA2, x)
+
+/* ANA_L2:COMMON:OWN_UPSID */
+#define ANA_L2_OWN_UPSID(r) __REG(TARGET_ANA_L2, 0, 1, 566024, 0, 1, 700, 672, r, 3, 4)
+
+#define ANA_L2_OWN_UPSID_OWN_UPSID GENMASK(4, 0)
+#define ANA_L2_OWN_UPSID_OWN_UPSID_SET(x)\
+ FIELD_PREP(ANA_L2_OWN_UPSID_OWN_UPSID, x)
+#define ANA_L2_OWN_UPSID_OWN_UPSID_GET(x)\
+ FIELD_GET(ANA_L2_OWN_UPSID_OWN_UPSID, x)
+
+/* ANA_L3:COMMON:VLAN_CTRL */
+#define ANA_L3_VLAN_CTRL __REG(TARGET_ANA_L3, 0, 1, 493632, 0, 1, 184, 4, 0, 1, 4)
+
+#define ANA_L3_VLAN_CTRL_VLAN_ENA BIT(0)
+#define ANA_L3_VLAN_CTRL_VLAN_ENA_SET(x)\
+ FIELD_PREP(ANA_L3_VLAN_CTRL_VLAN_ENA, x)
+#define ANA_L3_VLAN_CTRL_VLAN_ENA_GET(x)\
+ FIELD_GET(ANA_L3_VLAN_CTRL_VLAN_ENA, x)
+
+/* ANA_L3:VLAN:VLAN_CFG */
+#define ANA_L3_VLAN_CFG(g) __REG(TARGET_ANA_L3, 0, 1, 0, g, 5120, 64, 8, 0, 1, 4)
+
+#define ANA_L3_VLAN_CFG_VLAN_MSTP_PTR GENMASK(30, 24)
+#define ANA_L3_VLAN_CFG_VLAN_MSTP_PTR_SET(x)\
+ FIELD_PREP(ANA_L3_VLAN_CFG_VLAN_MSTP_PTR, x)
+#define ANA_L3_VLAN_CFG_VLAN_MSTP_PTR_GET(x)\
+ FIELD_GET(ANA_L3_VLAN_CFG_VLAN_MSTP_PTR, x)
+
+#define ANA_L3_VLAN_CFG_VLAN_FID GENMASK(20, 8)
+#define ANA_L3_VLAN_CFG_VLAN_FID_SET(x)\
+ FIELD_PREP(ANA_L3_VLAN_CFG_VLAN_FID, x)
+#define ANA_L3_VLAN_CFG_VLAN_FID_GET(x)\
+ FIELD_GET(ANA_L3_VLAN_CFG_VLAN_FID, x)
+
+#define ANA_L3_VLAN_CFG_VLAN_IGR_FILTER_ENA BIT(6)
+#define ANA_L3_VLAN_CFG_VLAN_IGR_FILTER_ENA_SET(x)\
+ FIELD_PREP(ANA_L3_VLAN_CFG_VLAN_IGR_FILTER_ENA, x)
+#define ANA_L3_VLAN_CFG_VLAN_IGR_FILTER_ENA_GET(x)\
+ FIELD_GET(ANA_L3_VLAN_CFG_VLAN_IGR_FILTER_ENA, x)
+
+#define ANA_L3_VLAN_CFG_VLAN_SEC_FWD_ENA BIT(5)
+#define ANA_L3_VLAN_CFG_VLAN_SEC_FWD_ENA_SET(x)\
+ FIELD_PREP(ANA_L3_VLAN_CFG_VLAN_SEC_FWD_ENA, x)
+#define ANA_L3_VLAN_CFG_VLAN_SEC_FWD_ENA_GET(x)\
+ FIELD_GET(ANA_L3_VLAN_CFG_VLAN_SEC_FWD_ENA, x)
+
+#define ANA_L3_VLAN_CFG_VLAN_FLOOD_DIS BIT(4)
+#define ANA_L3_VLAN_CFG_VLAN_FLOOD_DIS_SET(x)\
+ FIELD_PREP(ANA_L3_VLAN_CFG_VLAN_FLOOD_DIS, x)
+#define ANA_L3_VLAN_CFG_VLAN_FLOOD_DIS_GET(x)\
+ FIELD_GET(ANA_L3_VLAN_CFG_VLAN_FLOOD_DIS, x)
+
+#define ANA_L3_VLAN_CFG_VLAN_LRN_DIS BIT(3)
+#define ANA_L3_VLAN_CFG_VLAN_LRN_DIS_SET(x)\
+ FIELD_PREP(ANA_L3_VLAN_CFG_VLAN_LRN_DIS, x)
+#define ANA_L3_VLAN_CFG_VLAN_LRN_DIS_GET(x)\
+ FIELD_GET(ANA_L3_VLAN_CFG_VLAN_LRN_DIS, x)
+
+#define ANA_L3_VLAN_CFG_VLAN_RLEG_ENA BIT(2)
+#define ANA_L3_VLAN_CFG_VLAN_RLEG_ENA_SET(x)\
+ FIELD_PREP(ANA_L3_VLAN_CFG_VLAN_RLEG_ENA, x)
+#define ANA_L3_VLAN_CFG_VLAN_RLEG_ENA_GET(x)\
+ FIELD_GET(ANA_L3_VLAN_CFG_VLAN_RLEG_ENA, x)
+
+#define ANA_L3_VLAN_CFG_VLAN_PRIVATE_ENA BIT(1)
+#define ANA_L3_VLAN_CFG_VLAN_PRIVATE_ENA_SET(x)\
+ FIELD_PREP(ANA_L3_VLAN_CFG_VLAN_PRIVATE_ENA, x)
+#define ANA_L3_VLAN_CFG_VLAN_PRIVATE_ENA_GET(x)\
+ FIELD_GET(ANA_L3_VLAN_CFG_VLAN_PRIVATE_ENA, x)
+
+#define ANA_L3_VLAN_CFG_VLAN_MIRROR_ENA BIT(0)
+#define ANA_L3_VLAN_CFG_VLAN_MIRROR_ENA_SET(x)\
+ FIELD_PREP(ANA_L3_VLAN_CFG_VLAN_MIRROR_ENA, x)
+#define ANA_L3_VLAN_CFG_VLAN_MIRROR_ENA_GET(x)\
+ FIELD_GET(ANA_L3_VLAN_CFG_VLAN_MIRROR_ENA, x)
+
+/* ANA_L3:VLAN:VLAN_MASK_CFG */
+#define ANA_L3_VLAN_MASK_CFG(g) __REG(TARGET_ANA_L3, 0, 1, 0, g, 5120, 64, 16, 0, 1, 4)
+
+/* ANA_L3:VLAN:VLAN_MASK_CFG1 */
+#define ANA_L3_VLAN_MASK_CFG1(g) __REG(TARGET_ANA_L3, 0, 1, 0, g, 5120, 64, 20, 0, 1, 4)
+
+/* ANA_L3:VLAN:VLAN_MASK_CFG2 */
+#define ANA_L3_VLAN_MASK_CFG2(g) __REG(TARGET_ANA_L3, 0, 1, 0, g, 5120, 64, 24, 0, 1, 4)
+
+#define ANA_L3_VLAN_MASK_CFG2_VLAN_PORT_MASK2 BIT(0)
+#define ANA_L3_VLAN_MASK_CFG2_VLAN_PORT_MASK2_SET(x)\
+ FIELD_PREP(ANA_L3_VLAN_MASK_CFG2_VLAN_PORT_MASK2, x)
+#define ANA_L3_VLAN_MASK_CFG2_VLAN_PORT_MASK2_GET(x)\
+ FIELD_GET(ANA_L3_VLAN_MASK_CFG2_VLAN_PORT_MASK2, x)
+
+/* ASM:DEV_STATISTICS:RX_IN_BYTES_CNT */
+#define ASM_RX_IN_BYTES_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 0, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_SYMBOL_ERR_CNT */
+#define ASM_RX_SYMBOL_ERR_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 4, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_PAUSE_CNT */
+#define ASM_RX_PAUSE_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 8, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_UNSUP_OPCODE_CNT */
+#define ASM_RX_UNSUP_OPCODE_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 12, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_OK_BYTES_CNT */
+#define ASM_RX_OK_BYTES_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 16, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_BAD_BYTES_CNT */
+#define ASM_RX_BAD_BYTES_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 20, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_UC_CNT */
+#define ASM_RX_UC_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 24, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_MC_CNT */
+#define ASM_RX_MC_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 28, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_BC_CNT */
+#define ASM_RX_BC_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 32, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_CRC_ERR_CNT */
+#define ASM_RX_CRC_ERR_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 36, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_UNDERSIZE_CNT */
+#define ASM_RX_UNDERSIZE_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 40, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_FRAGMENTS_CNT */
+#define ASM_RX_FRAGMENTS_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 44, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_IN_RANGE_LEN_ERR_CNT */
+#define ASM_RX_IN_RANGE_LEN_ERR_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 48, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_OUT_OF_RANGE_LEN_ERR_CNT */
+#define ASM_RX_OUT_OF_RANGE_LEN_ERR_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 52, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_OVERSIZE_CNT */
+#define ASM_RX_OVERSIZE_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 56, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_JABBERS_CNT */
+#define ASM_RX_JABBERS_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 60, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_SIZE64_CNT */
+#define ASM_RX_SIZE64_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 64, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_SIZE65TO127_CNT */
+#define ASM_RX_SIZE65TO127_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 68, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_SIZE128TO255_CNT */
+#define ASM_RX_SIZE128TO255_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 72, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_SIZE256TO511_CNT */
+#define ASM_RX_SIZE256TO511_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 76, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_SIZE512TO1023_CNT */
+#define ASM_RX_SIZE512TO1023_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 80, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_SIZE1024TO1518_CNT */
+#define ASM_RX_SIZE1024TO1518_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 84, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_SIZE1519TOMAX_CNT */
+#define ASM_RX_SIZE1519TOMAX_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 88, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_IPG_SHRINK_CNT */
+#define ASM_RX_IPG_SHRINK_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 92, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_OUT_BYTES_CNT */
+#define ASM_TX_OUT_BYTES_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 96, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_PAUSE_CNT */
+#define ASM_TX_PAUSE_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 100, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_OK_BYTES_CNT */
+#define ASM_TX_OK_BYTES_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 104, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_UC_CNT */
+#define ASM_TX_UC_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 108, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_MC_CNT */
+#define ASM_TX_MC_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 112, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_BC_CNT */
+#define ASM_TX_BC_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 116, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_SIZE64_CNT */
+#define ASM_TX_SIZE64_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 120, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_SIZE65TO127_CNT */
+#define ASM_TX_SIZE65TO127_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 124, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_SIZE128TO255_CNT */
+#define ASM_TX_SIZE128TO255_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 128, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_SIZE256TO511_CNT */
+#define ASM_TX_SIZE256TO511_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 132, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_SIZE512TO1023_CNT */
+#define ASM_TX_SIZE512TO1023_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 136, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_SIZE1024TO1518_CNT */
+#define ASM_TX_SIZE1024TO1518_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 140, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_SIZE1519TOMAX_CNT */
+#define ASM_TX_SIZE1519TOMAX_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 144, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_ALIGNMENT_LOST_CNT */
+#define ASM_RX_ALIGNMENT_LOST_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 148, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_TAGGED_FRMS_CNT */
+#define ASM_RX_TAGGED_FRMS_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 152, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_UNTAGGED_FRMS_CNT */
+#define ASM_RX_UNTAGGED_FRMS_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 156, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_TAGGED_FRMS_CNT */
+#define ASM_TX_TAGGED_FRMS_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 160, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_UNTAGGED_FRMS_CNT */
+#define ASM_TX_UNTAGGED_FRMS_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 164, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_SYMBOL_ERR_CNT */
+#define ASM_PMAC_RX_SYMBOL_ERR_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 168, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_PAUSE_CNT */
+#define ASM_PMAC_RX_PAUSE_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 172, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_UNSUP_OPCODE_CNT */
+#define ASM_PMAC_RX_UNSUP_OPCODE_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 176, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_OK_BYTES_CNT */
+#define ASM_PMAC_RX_OK_BYTES_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 180, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_BAD_BYTES_CNT */
+#define ASM_PMAC_RX_BAD_BYTES_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 184, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_UC_CNT */
+#define ASM_PMAC_RX_UC_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 188, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_MC_CNT */
+#define ASM_PMAC_RX_MC_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 192, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_BC_CNT */
+#define ASM_PMAC_RX_BC_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 196, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_CRC_ERR_CNT */
+#define ASM_PMAC_RX_CRC_ERR_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 200, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_UNDERSIZE_CNT */
+#define ASM_PMAC_RX_UNDERSIZE_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 204, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_FRAGMENTS_CNT */
+#define ASM_PMAC_RX_FRAGMENTS_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 208, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_IN_RANGE_LEN_ERR_CNT */
+#define ASM_PMAC_RX_IN_RANGE_LEN_ERR_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 212, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT */
+#define ASM_PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 216, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_OVERSIZE_CNT */
+#define ASM_PMAC_RX_OVERSIZE_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 220, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_JABBERS_CNT */
+#define ASM_PMAC_RX_JABBERS_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 224, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_SIZE64_CNT */
+#define ASM_PMAC_RX_SIZE64_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 228, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_SIZE65TO127_CNT */
+#define ASM_PMAC_RX_SIZE65TO127_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 232, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_SIZE128TO255_CNT */
+#define ASM_PMAC_RX_SIZE128TO255_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 236, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_SIZE256TO511_CNT */
+#define ASM_PMAC_RX_SIZE256TO511_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 240, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_SIZE512TO1023_CNT */
+#define ASM_PMAC_RX_SIZE512TO1023_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 244, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_SIZE1024TO1518_CNT */
+#define ASM_PMAC_RX_SIZE1024TO1518_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 248, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_SIZE1519TOMAX_CNT */
+#define ASM_PMAC_RX_SIZE1519TOMAX_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 252, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_TX_PAUSE_CNT */
+#define ASM_PMAC_TX_PAUSE_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 256, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_TX_OK_BYTES_CNT */
+#define ASM_PMAC_TX_OK_BYTES_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 260, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_TX_UC_CNT */
+#define ASM_PMAC_TX_UC_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 264, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_TX_MC_CNT */
+#define ASM_PMAC_TX_MC_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 268, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_TX_BC_CNT */
+#define ASM_PMAC_TX_BC_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 272, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_TX_SIZE64_CNT */
+#define ASM_PMAC_TX_SIZE64_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 276, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_TX_SIZE65TO127_CNT */
+#define ASM_PMAC_TX_SIZE65TO127_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 280, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_TX_SIZE128TO255_CNT */
+#define ASM_PMAC_TX_SIZE128TO255_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 284, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_TX_SIZE256TO511_CNT */
+#define ASM_PMAC_TX_SIZE256TO511_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 288, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_TX_SIZE512TO1023_CNT */
+#define ASM_PMAC_TX_SIZE512TO1023_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 292, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_TX_SIZE1024TO1518_CNT */
+#define ASM_PMAC_TX_SIZE1024TO1518_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 296, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_TX_SIZE1519TOMAX_CNT */
+#define ASM_PMAC_TX_SIZE1519TOMAX_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 300, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_ALIGNMENT_LOST_CNT */
+#define ASM_PMAC_RX_ALIGNMENT_LOST_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 304, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:MM_RX_ASSEMBLY_ERR_CNT */
+#define ASM_MM_RX_ASSEMBLY_ERR_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 308, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:MM_RX_SMD_ERR_CNT */
+#define ASM_MM_RX_SMD_ERR_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 312, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:MM_RX_ASSEMBLY_OK_CNT */
+#define ASM_MM_RX_ASSEMBLY_OK_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 316, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:MM_RX_MERGE_FRAG_CNT */
+#define ASM_MM_RX_MERGE_FRAG_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 320, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:MM_TX_PFRAGMENT_CNT */
+#define ASM_MM_TX_PFRAGMENT_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 324, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_MULTI_COLL_CNT */
+#define ASM_TX_MULTI_COLL_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 328, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_LATE_COLL_CNT */
+#define ASM_TX_LATE_COLL_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 332, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_XCOLL_CNT */
+#define ASM_TX_XCOLL_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 336, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_DEFER_CNT */
+#define ASM_TX_DEFER_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 340, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_XDEFER_CNT */
+#define ASM_TX_XDEFER_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 344, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_BACKOFF1_CNT */
+#define ASM_TX_BACKOFF1_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 348, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:TX_CSENSE_CNT */
+#define ASM_TX_CSENSE_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 352, 0, 1, 4)
+
+/* ASM:DEV_STATISTICS:RX_IN_BYTES_MSB_CNT */
+#define ASM_RX_IN_BYTES_MSB_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 356, 0, 1, 4)
+
+#define ASM_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT GENMASK(3, 0)
+#define ASM_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(ASM_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT, x)
+#define ASM_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(ASM_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT, x)
+
+/* ASM:DEV_STATISTICS:RX_OK_BYTES_MSB_CNT */
+#define ASM_RX_OK_BYTES_MSB_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 360, 0, 1, 4)
+
+#define ASM_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT GENMASK(3, 0)
+#define ASM_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(ASM_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT, x)
+#define ASM_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(ASM_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT, x)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_OK_BYTES_MSB_CNT */
+#define ASM_PMAC_RX_OK_BYTES_MSB_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 364, 0, 1, 4)
+
+#define ASM_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT GENMASK(3, 0)
+#define ASM_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(ASM_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT, x)
+#define ASM_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(ASM_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT, x)
+
+/* ASM:DEV_STATISTICS:RX_BAD_BYTES_MSB_CNT */
+#define ASM_RX_BAD_BYTES_MSB_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 368, 0, 1, 4)
+
+#define ASM_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT GENMASK(3, 0)
+#define ASM_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(ASM_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT, x)
+#define ASM_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(ASM_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT, x)
+
+/* ASM:DEV_STATISTICS:PMAC_RX_BAD_BYTES_MSB_CNT */
+#define ASM_PMAC_RX_BAD_BYTES_MSB_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 372, 0, 1, 4)
+
+#define ASM_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT GENMASK(3, 0)
+#define ASM_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(ASM_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT, x)
+#define ASM_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(ASM_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT, x)
+
+/* ASM:DEV_STATISTICS:TX_OUT_BYTES_MSB_CNT */
+#define ASM_TX_OUT_BYTES_MSB_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 376, 0, 1, 4)
+
+#define ASM_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT GENMASK(3, 0)
+#define ASM_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(ASM_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT, x)
+#define ASM_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(ASM_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT, x)
+
+/* ASM:DEV_STATISTICS:TX_OK_BYTES_MSB_CNT */
+#define ASM_TX_OK_BYTES_MSB_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 380, 0, 1, 4)
+
+#define ASM_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT GENMASK(3, 0)
+#define ASM_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(ASM_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT, x)
+#define ASM_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(ASM_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT, x)
+
+/* ASM:DEV_STATISTICS:PMAC_TX_OK_BYTES_MSB_CNT */
+#define ASM_PMAC_TX_OK_BYTES_MSB_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 384, 0, 1, 4)
+
+#define ASM_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT GENMASK(3, 0)
+#define ASM_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(ASM_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT, x)
+#define ASM_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(ASM_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT, x)
+
+/* ASM:DEV_STATISTICS:RX_SYNC_LOST_ERR_CNT */
+#define ASM_RX_SYNC_LOST_ERR_CNT(g) __REG(TARGET_ASM, 0, 1, 0, g, 65, 512, 388, 0, 1, 4)
+
+/* ASM:CFG:STAT_CFG */
+#define ASM_STAT_CFG __REG(TARGET_ASM, 0, 1, 33280, 0, 1, 1088, 0, 0, 1, 4)
+
+#define ASM_STAT_CFG_STAT_CNT_CLR_SHOT BIT(0)
+#define ASM_STAT_CFG_STAT_CNT_CLR_SHOT_SET(x)\
+ FIELD_PREP(ASM_STAT_CFG_STAT_CNT_CLR_SHOT, x)
+#define ASM_STAT_CFG_STAT_CNT_CLR_SHOT_GET(x)\
+ FIELD_GET(ASM_STAT_CFG_STAT_CNT_CLR_SHOT, x)
+
+/* ASM:CFG:PORT_CFG */
+#define ASM_PORT_CFG(r) __REG(TARGET_ASM, 0, 1, 33280, 0, 1, 1088, 540, r, 67, 4)
+
+#define ASM_PORT_CFG_CSC_STAT_DIS BIT(12)
+#define ASM_PORT_CFG_CSC_STAT_DIS_SET(x)\
+ FIELD_PREP(ASM_PORT_CFG_CSC_STAT_DIS, x)
+#define ASM_PORT_CFG_CSC_STAT_DIS_GET(x)\
+ FIELD_GET(ASM_PORT_CFG_CSC_STAT_DIS, x)
+
+#define ASM_PORT_CFG_HIH_AFTER_PREAMBLE_ENA BIT(11)
+#define ASM_PORT_CFG_HIH_AFTER_PREAMBLE_ENA_SET(x)\
+ FIELD_PREP(ASM_PORT_CFG_HIH_AFTER_PREAMBLE_ENA, x)
+#define ASM_PORT_CFG_HIH_AFTER_PREAMBLE_ENA_GET(x)\
+ FIELD_GET(ASM_PORT_CFG_HIH_AFTER_PREAMBLE_ENA, x)
+
+#define ASM_PORT_CFG_IGN_TAXI_ABORT_ENA BIT(10)
+#define ASM_PORT_CFG_IGN_TAXI_ABORT_ENA_SET(x)\
+ FIELD_PREP(ASM_PORT_CFG_IGN_TAXI_ABORT_ENA, x)
+#define ASM_PORT_CFG_IGN_TAXI_ABORT_ENA_GET(x)\
+ FIELD_GET(ASM_PORT_CFG_IGN_TAXI_ABORT_ENA, x)
+
+#define ASM_PORT_CFG_NO_PREAMBLE_ENA BIT(9)
+#define ASM_PORT_CFG_NO_PREAMBLE_ENA_SET(x)\
+ FIELD_PREP(ASM_PORT_CFG_NO_PREAMBLE_ENA, x)
+#define ASM_PORT_CFG_NO_PREAMBLE_ENA_GET(x)\
+ FIELD_GET(ASM_PORT_CFG_NO_PREAMBLE_ENA, x)
+
+#define ASM_PORT_CFG_SKIP_PREAMBLE_ENA BIT(8)
+#define ASM_PORT_CFG_SKIP_PREAMBLE_ENA_SET(x)\
+ FIELD_PREP(ASM_PORT_CFG_SKIP_PREAMBLE_ENA, x)
+#define ASM_PORT_CFG_SKIP_PREAMBLE_ENA_GET(x)\
+ FIELD_GET(ASM_PORT_CFG_SKIP_PREAMBLE_ENA, x)
+
+#define ASM_PORT_CFG_FRM_AGING_DIS BIT(7)
+#define ASM_PORT_CFG_FRM_AGING_DIS_SET(x)\
+ FIELD_PREP(ASM_PORT_CFG_FRM_AGING_DIS, x)
+#define ASM_PORT_CFG_FRM_AGING_DIS_GET(x)\
+ FIELD_GET(ASM_PORT_CFG_FRM_AGING_DIS, x)
+
+#define ASM_PORT_CFG_PAD_ENA BIT(6)
+#define ASM_PORT_CFG_PAD_ENA_SET(x)\
+ FIELD_PREP(ASM_PORT_CFG_PAD_ENA, x)
+#define ASM_PORT_CFG_PAD_ENA_GET(x)\
+ FIELD_GET(ASM_PORT_CFG_PAD_ENA, x)
+
+#define ASM_PORT_CFG_INJ_DISCARD_CFG GENMASK(5, 4)
+#define ASM_PORT_CFG_INJ_DISCARD_CFG_SET(x)\
+ FIELD_PREP(ASM_PORT_CFG_INJ_DISCARD_CFG, x)
+#define ASM_PORT_CFG_INJ_DISCARD_CFG_GET(x)\
+ FIELD_GET(ASM_PORT_CFG_INJ_DISCARD_CFG, x)
+
+#define ASM_PORT_CFG_INJ_FORMAT_CFG GENMASK(3, 2)
+#define ASM_PORT_CFG_INJ_FORMAT_CFG_SET(x)\
+ FIELD_PREP(ASM_PORT_CFG_INJ_FORMAT_CFG, x)
+#define ASM_PORT_CFG_INJ_FORMAT_CFG_GET(x)\
+ FIELD_GET(ASM_PORT_CFG_INJ_FORMAT_CFG, x)
+
+#define ASM_PORT_CFG_VSTAX2_AWR_ENA BIT(1)
+#define ASM_PORT_CFG_VSTAX2_AWR_ENA_SET(x)\
+ FIELD_PREP(ASM_PORT_CFG_VSTAX2_AWR_ENA, x)
+#define ASM_PORT_CFG_VSTAX2_AWR_ENA_GET(x)\
+ FIELD_GET(ASM_PORT_CFG_VSTAX2_AWR_ENA, x)
+
+#define ASM_PORT_CFG_PFRM_FLUSH BIT(0)
+#define ASM_PORT_CFG_PFRM_FLUSH_SET(x)\
+ FIELD_PREP(ASM_PORT_CFG_PFRM_FLUSH, x)
+#define ASM_PORT_CFG_PFRM_FLUSH_GET(x)\
+ FIELD_GET(ASM_PORT_CFG_PFRM_FLUSH, x)
+
+/* ASM:RAM_CTRL:RAM_INIT */
+#define ASM_RAM_INIT __REG(TARGET_ASM, 0, 1, 34832, 0, 1, 4, 0, 0, 1, 4)
+
+#define ASM_RAM_INIT_RAM_INIT BIT(1)
+#define ASM_RAM_INIT_RAM_INIT_SET(x)\
+ FIELD_PREP(ASM_RAM_INIT_RAM_INIT, x)
+#define ASM_RAM_INIT_RAM_INIT_GET(x)\
+ FIELD_GET(ASM_RAM_INIT_RAM_INIT, x)
+
+#define ASM_RAM_INIT_RAM_CFG_HOOK BIT(0)
+#define ASM_RAM_INIT_RAM_CFG_HOOK_SET(x)\
+ FIELD_PREP(ASM_RAM_INIT_RAM_CFG_HOOK, x)
+#define ASM_RAM_INIT_RAM_CFG_HOOK_GET(x)\
+ FIELD_GET(ASM_RAM_INIT_RAM_CFG_HOOK, x)
+
+/* CLKGEN:LCPLL1:LCPLL1_CORE_CLK_CFG */
+#define CLKGEN_LCPLL1_CORE_CLK_CFG __REG(TARGET_CLKGEN, 0, 1, 12, 0, 1, 36, 0, 0, 1, 4)
+
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV GENMASK(7, 0)
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV_SET(x)\
+ FIELD_PREP(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV, x)
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV_GET(x)\
+ FIELD_GET(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV, x)
+
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV GENMASK(10, 8)
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV_SET(x)\
+ FIELD_PREP(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV, x)
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV_GET(x)\
+ FIELD_GET(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV, x)
+
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR BIT(11)
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR_SET(x)\
+ FIELD_PREP(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR, x)
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR_GET(x)\
+ FIELD_GET(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR, x)
+
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL GENMASK(13, 12)
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL_SET(x)\
+ FIELD_PREP(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL, x)
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL_GET(x)\
+ FIELD_GET(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL, x)
+
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA BIT(14)
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA_SET(x)\
+ FIELD_PREP(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA, x)
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA_GET(x)\
+ FIELD_GET(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA, x)
+
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA BIT(15)
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA_SET(x)\
+ FIELD_PREP(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA, x)
+#define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA_GET(x)\
+ FIELD_GET(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA, x)
+
+/* CPU:CPU_REGS:PROC_CTRL */
+#define CPU_PROC_CTRL __REG(TARGET_CPU, 0, 1, 0, 0, 1, 204, 176, 0, 1, 4)
+
+#define CPU_PROC_CTRL_AARCH64_MODE_ENA BIT(12)
+#define CPU_PROC_CTRL_AARCH64_MODE_ENA_SET(x)\
+ FIELD_PREP(CPU_PROC_CTRL_AARCH64_MODE_ENA, x)
+#define CPU_PROC_CTRL_AARCH64_MODE_ENA_GET(x)\
+ FIELD_GET(CPU_PROC_CTRL_AARCH64_MODE_ENA, x)
+
+#define CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS BIT(11)
+#define CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS_SET(x)\
+ FIELD_PREP(CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS, x)
+#define CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS_GET(x)\
+ FIELD_GET(CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS, x)
+
+#define CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS BIT(10)
+#define CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS_SET(x)\
+ FIELD_PREP(CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS, x)
+#define CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS_GET(x)\
+ FIELD_GET(CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS, x)
+
+#define CPU_PROC_CTRL_BE_EXCEP_MODE BIT(9)
+#define CPU_PROC_CTRL_BE_EXCEP_MODE_SET(x)\
+ FIELD_PREP(CPU_PROC_CTRL_BE_EXCEP_MODE, x)
+#define CPU_PROC_CTRL_BE_EXCEP_MODE_GET(x)\
+ FIELD_GET(CPU_PROC_CTRL_BE_EXCEP_MODE, x)
+
+#define CPU_PROC_CTRL_VINITHI BIT(8)
+#define CPU_PROC_CTRL_VINITHI_SET(x)\
+ FIELD_PREP(CPU_PROC_CTRL_VINITHI, x)
+#define CPU_PROC_CTRL_VINITHI_GET(x)\
+ FIELD_GET(CPU_PROC_CTRL_VINITHI, x)
+
+#define CPU_PROC_CTRL_CFGTE BIT(7)
+#define CPU_PROC_CTRL_CFGTE_SET(x)\
+ FIELD_PREP(CPU_PROC_CTRL_CFGTE, x)
+#define CPU_PROC_CTRL_CFGTE_GET(x)\
+ FIELD_GET(CPU_PROC_CTRL_CFGTE, x)
+
+#define CPU_PROC_CTRL_CP15S_DISABLE BIT(6)
+#define CPU_PROC_CTRL_CP15S_DISABLE_SET(x)\
+ FIELD_PREP(CPU_PROC_CTRL_CP15S_DISABLE, x)
+#define CPU_PROC_CTRL_CP15S_DISABLE_GET(x)\
+ FIELD_GET(CPU_PROC_CTRL_CP15S_DISABLE, x)
+
+#define CPU_PROC_CTRL_PROC_CRYPTO_DISABLE BIT(5)
+#define CPU_PROC_CTRL_PROC_CRYPTO_DISABLE_SET(x)\
+ FIELD_PREP(CPU_PROC_CTRL_PROC_CRYPTO_DISABLE, x)
+#define CPU_PROC_CTRL_PROC_CRYPTO_DISABLE_GET(x)\
+ FIELD_GET(CPU_PROC_CTRL_PROC_CRYPTO_DISABLE, x)
+
+#define CPU_PROC_CTRL_ACP_CACHE_FORCE_ENA BIT(4)
+#define CPU_PROC_CTRL_ACP_CACHE_FORCE_ENA_SET(x)\
+ FIELD_PREP(CPU_PROC_CTRL_ACP_CACHE_FORCE_ENA, x)
+#define CPU_PROC_CTRL_ACP_CACHE_FORCE_ENA_GET(x)\
+ FIELD_GET(CPU_PROC_CTRL_ACP_CACHE_FORCE_ENA, x)
+
+#define CPU_PROC_CTRL_ACP_AWCACHE BIT(3)
+#define CPU_PROC_CTRL_ACP_AWCACHE_SET(x)\
+ FIELD_PREP(CPU_PROC_CTRL_ACP_AWCACHE, x)
+#define CPU_PROC_CTRL_ACP_AWCACHE_GET(x)\
+ FIELD_GET(CPU_PROC_CTRL_ACP_AWCACHE, x)
+
+#define CPU_PROC_CTRL_ACP_ARCACHE BIT(2)
+#define CPU_PROC_CTRL_ACP_ARCACHE_SET(x)\
+ FIELD_PREP(CPU_PROC_CTRL_ACP_ARCACHE, x)
+#define CPU_PROC_CTRL_ACP_ARCACHE_GET(x)\
+ FIELD_GET(CPU_PROC_CTRL_ACP_ARCACHE, x)
+
+#define CPU_PROC_CTRL_L2_FLUSH_REQ BIT(1)
+#define CPU_PROC_CTRL_L2_FLUSH_REQ_SET(x)\
+ FIELD_PREP(CPU_PROC_CTRL_L2_FLUSH_REQ, x)
+#define CPU_PROC_CTRL_L2_FLUSH_REQ_GET(x)\
+ FIELD_GET(CPU_PROC_CTRL_L2_FLUSH_REQ, x)
+
+#define CPU_PROC_CTRL_ACP_DISABLE BIT(0)
+#define CPU_PROC_CTRL_ACP_DISABLE_SET(x)\
+ FIELD_PREP(CPU_PROC_CTRL_ACP_DISABLE, x)
+#define CPU_PROC_CTRL_ACP_DISABLE_GET(x)\
+ FIELD_GET(CPU_PROC_CTRL_ACP_DISABLE, x)
+
+/* DEV10G:MAC_CFG_STATUS:MAC_ENA_CFG */
+#define DEV10G_MAC_ENA_CFG(t) __REG(TARGET_DEV10G, t, 12, 0, 0, 1, 60, 0, 0, 1, 4)
+
+#define DEV10G_MAC_ENA_CFG_RX_ENA BIT(4)
+#define DEV10G_MAC_ENA_CFG_RX_ENA_SET(x)\
+ FIELD_PREP(DEV10G_MAC_ENA_CFG_RX_ENA, x)
+#define DEV10G_MAC_ENA_CFG_RX_ENA_GET(x)\
+ FIELD_GET(DEV10G_MAC_ENA_CFG_RX_ENA, x)
+
+#define DEV10G_MAC_ENA_CFG_TX_ENA BIT(0)
+#define DEV10G_MAC_ENA_CFG_TX_ENA_SET(x)\
+ FIELD_PREP(DEV10G_MAC_ENA_CFG_TX_ENA, x)
+#define DEV10G_MAC_ENA_CFG_TX_ENA_GET(x)\
+ FIELD_GET(DEV10G_MAC_ENA_CFG_TX_ENA, x)
+
+/* DEV10G:MAC_CFG_STATUS:MAC_MAXLEN_CFG */
+#define DEV10G_MAC_MAXLEN_CFG(t) __REG(TARGET_DEV10G, t, 12, 0, 0, 1, 60, 8, 0, 1, 4)
+
+#define DEV10G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK BIT(16)
+#define DEV10G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK_SET(x)\
+ FIELD_PREP(DEV10G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK, x)
+#define DEV10G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK_GET(x)\
+ FIELD_GET(DEV10G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK, x)
+
+#define DEV10G_MAC_MAXLEN_CFG_MAX_LEN GENMASK(15, 0)
+#define DEV10G_MAC_MAXLEN_CFG_MAX_LEN_SET(x)\
+ FIELD_PREP(DEV10G_MAC_MAXLEN_CFG_MAX_LEN, x)
+#define DEV10G_MAC_MAXLEN_CFG_MAX_LEN_GET(x)\
+ FIELD_GET(DEV10G_MAC_MAXLEN_CFG_MAX_LEN, x)
+
+/* DEV10G:MAC_CFG_STATUS:MAC_NUM_TAGS_CFG */
+#define DEV10G_MAC_NUM_TAGS_CFG(t) __REG(TARGET_DEV10G, t, 12, 0, 0, 1, 60, 12, 0, 1, 4)
+
+#define DEV10G_MAC_NUM_TAGS_CFG_NUM_TAGS GENMASK(1, 0)
+#define DEV10G_MAC_NUM_TAGS_CFG_NUM_TAGS_SET(x)\
+ FIELD_PREP(DEV10G_MAC_NUM_TAGS_CFG_NUM_TAGS, x)
+#define DEV10G_MAC_NUM_TAGS_CFG_NUM_TAGS_GET(x)\
+ FIELD_GET(DEV10G_MAC_NUM_TAGS_CFG_NUM_TAGS, x)
+
+/* DEV10G:MAC_CFG_STATUS:MAC_TAGS_CFG */
+#define DEV10G_MAC_TAGS_CFG(t, r) __REG(TARGET_DEV10G, t, 12, 0, 0, 1, 60, 16, r, 3, 4)
+
+#define DEV10G_MAC_TAGS_CFG_TAG_ID GENMASK(31, 16)
+#define DEV10G_MAC_TAGS_CFG_TAG_ID_SET(x)\
+ FIELD_PREP(DEV10G_MAC_TAGS_CFG_TAG_ID, x)
+#define DEV10G_MAC_TAGS_CFG_TAG_ID_GET(x)\
+ FIELD_GET(DEV10G_MAC_TAGS_CFG_TAG_ID, x)
+
+#define DEV10G_MAC_TAGS_CFG_TAG_ENA BIT(4)
+#define DEV10G_MAC_TAGS_CFG_TAG_ENA_SET(x)\
+ FIELD_PREP(DEV10G_MAC_TAGS_CFG_TAG_ENA, x)
+#define DEV10G_MAC_TAGS_CFG_TAG_ENA_GET(x)\
+ FIELD_GET(DEV10G_MAC_TAGS_CFG_TAG_ENA, x)
+
+/* DEV10G:MAC_CFG_STATUS:MAC_ADV_CHK_CFG */
+#define DEV10G_MAC_ADV_CHK_CFG(t) __REG(TARGET_DEV10G, t, 12, 0, 0, 1, 60, 28, 0, 1, 4)
+
+#define DEV10G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA BIT(24)
+#define DEV10G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA_SET(x)\
+ FIELD_PREP(DEV10G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA, x)
+#define DEV10G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA_GET(x)\
+ FIELD_GET(DEV10G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA, x)
+
+#define DEV10G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA BIT(20)
+#define DEV10G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA_SET(x)\
+ FIELD_PREP(DEV10G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA, x)
+#define DEV10G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA_GET(x)\
+ FIELD_GET(DEV10G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA, x)
+
+#define DEV10G_MAC_ADV_CHK_CFG_SFD_CHK_ENA BIT(16)
+#define DEV10G_MAC_ADV_CHK_CFG_SFD_CHK_ENA_SET(x)\
+ FIELD_PREP(DEV10G_MAC_ADV_CHK_CFG_SFD_CHK_ENA, x)
+#define DEV10G_MAC_ADV_CHK_CFG_SFD_CHK_ENA_GET(x)\
+ FIELD_GET(DEV10G_MAC_ADV_CHK_CFG_SFD_CHK_ENA, x)
+
+#define DEV10G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS BIT(12)
+#define DEV10G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS_SET(x)\
+ FIELD_PREP(DEV10G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS, x)
+#define DEV10G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS_GET(x)\
+ FIELD_GET(DEV10G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS, x)
+
+#define DEV10G_MAC_ADV_CHK_CFG_PRM_CHK_ENA BIT(8)
+#define DEV10G_MAC_ADV_CHK_CFG_PRM_CHK_ENA_SET(x)\
+ FIELD_PREP(DEV10G_MAC_ADV_CHK_CFG_PRM_CHK_ENA, x)
+#define DEV10G_MAC_ADV_CHK_CFG_PRM_CHK_ENA_GET(x)\
+ FIELD_GET(DEV10G_MAC_ADV_CHK_CFG_PRM_CHK_ENA, x)
+
+#define DEV10G_MAC_ADV_CHK_CFG_OOR_ERR_ENA BIT(4)
+#define DEV10G_MAC_ADV_CHK_CFG_OOR_ERR_ENA_SET(x)\
+ FIELD_PREP(DEV10G_MAC_ADV_CHK_CFG_OOR_ERR_ENA, x)
+#define DEV10G_MAC_ADV_CHK_CFG_OOR_ERR_ENA_GET(x)\
+ FIELD_GET(DEV10G_MAC_ADV_CHK_CFG_OOR_ERR_ENA, x)
+
+#define DEV10G_MAC_ADV_CHK_CFG_INR_ERR_ENA BIT(0)
+#define DEV10G_MAC_ADV_CHK_CFG_INR_ERR_ENA_SET(x)\
+ FIELD_PREP(DEV10G_MAC_ADV_CHK_CFG_INR_ERR_ENA, x)
+#define DEV10G_MAC_ADV_CHK_CFG_INR_ERR_ENA_GET(x)\
+ FIELD_GET(DEV10G_MAC_ADV_CHK_CFG_INR_ERR_ENA, x)
+
+/* DEV10G:MAC_CFG_STATUS:MAC_TX_MONITOR_STICKY */
+#define DEV10G_MAC_TX_MONITOR_STICKY(t) __REG(TARGET_DEV10G, t, 12, 0, 0, 1, 60, 48, 0, 1, 4)
+
+#define DEV10G_MAC_TX_MONITOR_STICKY_LOCAL_ERR_STATE_STICKY BIT(4)
+#define DEV10G_MAC_TX_MONITOR_STICKY_LOCAL_ERR_STATE_STICKY_SET(x)\
+ FIELD_PREP(DEV10G_MAC_TX_MONITOR_STICKY_LOCAL_ERR_STATE_STICKY, x)
+#define DEV10G_MAC_TX_MONITOR_STICKY_LOCAL_ERR_STATE_STICKY_GET(x)\
+ FIELD_GET(DEV10G_MAC_TX_MONITOR_STICKY_LOCAL_ERR_STATE_STICKY, x)
+
+#define DEV10G_MAC_TX_MONITOR_STICKY_REMOTE_ERR_STATE_STICKY BIT(3)
+#define DEV10G_MAC_TX_MONITOR_STICKY_REMOTE_ERR_STATE_STICKY_SET(x)\
+ FIELD_PREP(DEV10G_MAC_TX_MONITOR_STICKY_REMOTE_ERR_STATE_STICKY, x)
+#define DEV10G_MAC_TX_MONITOR_STICKY_REMOTE_ERR_STATE_STICKY_GET(x)\
+ FIELD_GET(DEV10G_MAC_TX_MONITOR_STICKY_REMOTE_ERR_STATE_STICKY, x)
+
+#define DEV10G_MAC_TX_MONITOR_STICKY_LINK_INTERRUPTION_STATE_STICKY BIT(2)
+#define DEV10G_MAC_TX_MONITOR_STICKY_LINK_INTERRUPTION_STATE_STICKY_SET(x)\
+ FIELD_PREP(DEV10G_MAC_TX_MONITOR_STICKY_LINK_INTERRUPTION_STATE_STICKY, x)
+#define DEV10G_MAC_TX_MONITOR_STICKY_LINK_INTERRUPTION_STATE_STICKY_GET(x)\
+ FIELD_GET(DEV10G_MAC_TX_MONITOR_STICKY_LINK_INTERRUPTION_STATE_STICKY, x)
+
+#define DEV10G_MAC_TX_MONITOR_STICKY_IDLE_STATE_STICKY BIT(1)
+#define DEV10G_MAC_TX_MONITOR_STICKY_IDLE_STATE_STICKY_SET(x)\
+ FIELD_PREP(DEV10G_MAC_TX_MONITOR_STICKY_IDLE_STATE_STICKY, x)
+#define DEV10G_MAC_TX_MONITOR_STICKY_IDLE_STATE_STICKY_GET(x)\
+ FIELD_GET(DEV10G_MAC_TX_MONITOR_STICKY_IDLE_STATE_STICKY, x)
+
+#define DEV10G_MAC_TX_MONITOR_STICKY_DIS_STATE_STICKY BIT(0)
+#define DEV10G_MAC_TX_MONITOR_STICKY_DIS_STATE_STICKY_SET(x)\
+ FIELD_PREP(DEV10G_MAC_TX_MONITOR_STICKY_DIS_STATE_STICKY, x)
+#define DEV10G_MAC_TX_MONITOR_STICKY_DIS_STATE_STICKY_GET(x)\
+ FIELD_GET(DEV10G_MAC_TX_MONITOR_STICKY_DIS_STATE_STICKY, x)
+
+/* DEV10G:DEV_CFG_STATUS:DEV_RST_CTRL */
+#define DEV10G_DEV_RST_CTRL(t) __REG(TARGET_DEV10G, t, 12, 436, 0, 1, 52, 0, 0, 1, 4)
+
+#define DEV10G_DEV_RST_CTRL_PARDET_MODE_ENA BIT(28)
+#define DEV10G_DEV_RST_CTRL_PARDET_MODE_ENA_SET(x)\
+ FIELD_PREP(DEV10G_DEV_RST_CTRL_PARDET_MODE_ENA, x)
+#define DEV10G_DEV_RST_CTRL_PARDET_MODE_ENA_GET(x)\
+ FIELD_GET(DEV10G_DEV_RST_CTRL_PARDET_MODE_ENA, x)
+
+#define DEV10G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS BIT(27)
+#define DEV10G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS_SET(x)\
+ FIELD_PREP(DEV10G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS, x)
+#define DEV10G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS_GET(x)\
+ FIELD_GET(DEV10G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS, x)
+
+#define DEV10G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS GENMASK(26, 25)
+#define DEV10G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS_SET(x)\
+ FIELD_PREP(DEV10G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS, x)
+#define DEV10G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS_GET(x)\
+ FIELD_GET(DEV10G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS, x)
+
+#define DEV10G_DEV_RST_CTRL_SERDES_SPEED_SEL GENMASK(24, 23)
+#define DEV10G_DEV_RST_CTRL_SERDES_SPEED_SEL_SET(x)\
+ FIELD_PREP(DEV10G_DEV_RST_CTRL_SERDES_SPEED_SEL, x)
+#define DEV10G_DEV_RST_CTRL_SERDES_SPEED_SEL_GET(x)\
+ FIELD_GET(DEV10G_DEV_RST_CTRL_SERDES_SPEED_SEL, x)
+
+#define DEV10G_DEV_RST_CTRL_SPEED_SEL GENMASK(22, 20)
+#define DEV10G_DEV_RST_CTRL_SPEED_SEL_SET(x)\
+ FIELD_PREP(DEV10G_DEV_RST_CTRL_SPEED_SEL, x)
+#define DEV10G_DEV_RST_CTRL_SPEED_SEL_GET(x)\
+ FIELD_GET(DEV10G_DEV_RST_CTRL_SPEED_SEL, x)
+
+#define DEV10G_DEV_RST_CTRL_PCS_TX_RST BIT(12)
+#define DEV10G_DEV_RST_CTRL_PCS_TX_RST_SET(x)\
+ FIELD_PREP(DEV10G_DEV_RST_CTRL_PCS_TX_RST, x)
+#define DEV10G_DEV_RST_CTRL_PCS_TX_RST_GET(x)\
+ FIELD_GET(DEV10G_DEV_RST_CTRL_PCS_TX_RST, x)
+
+#define DEV10G_DEV_RST_CTRL_PCS_RX_RST BIT(8)
+#define DEV10G_DEV_RST_CTRL_PCS_RX_RST_SET(x)\
+ FIELD_PREP(DEV10G_DEV_RST_CTRL_PCS_RX_RST, x)
+#define DEV10G_DEV_RST_CTRL_PCS_RX_RST_GET(x)\
+ FIELD_GET(DEV10G_DEV_RST_CTRL_PCS_RX_RST, x)
+
+#define DEV10G_DEV_RST_CTRL_MAC_TX_RST BIT(4)
+#define DEV10G_DEV_RST_CTRL_MAC_TX_RST_SET(x)\
+ FIELD_PREP(DEV10G_DEV_RST_CTRL_MAC_TX_RST, x)
+#define DEV10G_DEV_RST_CTRL_MAC_TX_RST_GET(x)\
+ FIELD_GET(DEV10G_DEV_RST_CTRL_MAC_TX_RST, x)
+
+#define DEV10G_DEV_RST_CTRL_MAC_RX_RST BIT(0)
+#define DEV10G_DEV_RST_CTRL_MAC_RX_RST_SET(x)\
+ FIELD_PREP(DEV10G_DEV_RST_CTRL_MAC_RX_RST, x)
+#define DEV10G_DEV_RST_CTRL_MAC_RX_RST_GET(x)\
+ FIELD_GET(DEV10G_DEV_RST_CTRL_MAC_RX_RST, x)
+
+/* DEV10G:PCS25G_CFG_STATUS:PCS25G_CFG */
+#define DEV10G_PCS25G_CFG(t) __REG(TARGET_DEV10G, t, 12, 488, 0, 1, 32, 0, 0, 1, 4)
+
+#define DEV10G_PCS25G_CFG_PCS25G_ENA BIT(0)
+#define DEV10G_PCS25G_CFG_PCS25G_ENA_SET(x)\
+ FIELD_PREP(DEV10G_PCS25G_CFG_PCS25G_ENA, x)
+#define DEV10G_PCS25G_CFG_PCS25G_ENA_GET(x)\
+ FIELD_GET(DEV10G_PCS25G_CFG_PCS25G_ENA, x)
+
+/* DEV10G:MAC_CFG_STATUS:MAC_ENA_CFG */
+#define DEV25G_MAC_ENA_CFG(t) __REG(TARGET_DEV25G, t, 8, 0, 0, 1, 60, 0, 0, 1, 4)
+
+#define DEV25G_MAC_ENA_CFG_RX_ENA BIT(4)
+#define DEV25G_MAC_ENA_CFG_RX_ENA_SET(x)\
+ FIELD_PREP(DEV25G_MAC_ENA_CFG_RX_ENA, x)
+#define DEV25G_MAC_ENA_CFG_RX_ENA_GET(x)\
+ FIELD_GET(DEV25G_MAC_ENA_CFG_RX_ENA, x)
+
+#define DEV25G_MAC_ENA_CFG_TX_ENA BIT(0)
+#define DEV25G_MAC_ENA_CFG_TX_ENA_SET(x)\
+ FIELD_PREP(DEV25G_MAC_ENA_CFG_TX_ENA, x)
+#define DEV25G_MAC_ENA_CFG_TX_ENA_GET(x)\
+ FIELD_GET(DEV25G_MAC_ENA_CFG_TX_ENA, x)
+
+/* DEV10G:MAC_CFG_STATUS:MAC_MAXLEN_CFG */
+#define DEV25G_MAC_MAXLEN_CFG(t) __REG(TARGET_DEV25G, t, 8, 0, 0, 1, 60, 8, 0, 1, 4)
+
+#define DEV25G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK BIT(16)
+#define DEV25G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK_SET(x)\
+ FIELD_PREP(DEV25G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK, x)
+#define DEV25G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK_GET(x)\
+ FIELD_GET(DEV25G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK, x)
+
+#define DEV25G_MAC_MAXLEN_CFG_MAX_LEN GENMASK(15, 0)
+#define DEV25G_MAC_MAXLEN_CFG_MAX_LEN_SET(x)\
+ FIELD_PREP(DEV25G_MAC_MAXLEN_CFG_MAX_LEN, x)
+#define DEV25G_MAC_MAXLEN_CFG_MAX_LEN_GET(x)\
+ FIELD_GET(DEV25G_MAC_MAXLEN_CFG_MAX_LEN, x)
+
+/* DEV10G:MAC_CFG_STATUS:MAC_ADV_CHK_CFG */
+#define DEV25G_MAC_ADV_CHK_CFG(t) __REG(TARGET_DEV25G, t, 8, 0, 0, 1, 60, 28, 0, 1, 4)
+
+#define DEV25G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA BIT(24)
+#define DEV25G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA_SET(x)\
+ FIELD_PREP(DEV25G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA, x)
+#define DEV25G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA_GET(x)\
+ FIELD_GET(DEV25G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA, x)
+
+#define DEV25G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA BIT(20)
+#define DEV25G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA_SET(x)\
+ FIELD_PREP(DEV25G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA, x)
+#define DEV25G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA_GET(x)\
+ FIELD_GET(DEV25G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA, x)
+
+#define DEV25G_MAC_ADV_CHK_CFG_SFD_CHK_ENA BIT(16)
+#define DEV25G_MAC_ADV_CHK_CFG_SFD_CHK_ENA_SET(x)\
+ FIELD_PREP(DEV25G_MAC_ADV_CHK_CFG_SFD_CHK_ENA, x)
+#define DEV25G_MAC_ADV_CHK_CFG_SFD_CHK_ENA_GET(x)\
+ FIELD_GET(DEV25G_MAC_ADV_CHK_CFG_SFD_CHK_ENA, x)
+
+#define DEV25G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS BIT(12)
+#define DEV25G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS_SET(x)\
+ FIELD_PREP(DEV25G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS, x)
+#define DEV25G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS_GET(x)\
+ FIELD_GET(DEV25G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS, x)
+
+#define DEV25G_MAC_ADV_CHK_CFG_PRM_CHK_ENA BIT(8)
+#define DEV25G_MAC_ADV_CHK_CFG_PRM_CHK_ENA_SET(x)\
+ FIELD_PREP(DEV25G_MAC_ADV_CHK_CFG_PRM_CHK_ENA, x)
+#define DEV25G_MAC_ADV_CHK_CFG_PRM_CHK_ENA_GET(x)\
+ FIELD_GET(DEV25G_MAC_ADV_CHK_CFG_PRM_CHK_ENA, x)
+
+#define DEV25G_MAC_ADV_CHK_CFG_OOR_ERR_ENA BIT(4)
+#define DEV25G_MAC_ADV_CHK_CFG_OOR_ERR_ENA_SET(x)\
+ FIELD_PREP(DEV25G_MAC_ADV_CHK_CFG_OOR_ERR_ENA, x)
+#define DEV25G_MAC_ADV_CHK_CFG_OOR_ERR_ENA_GET(x)\
+ FIELD_GET(DEV25G_MAC_ADV_CHK_CFG_OOR_ERR_ENA, x)
+
+#define DEV25G_MAC_ADV_CHK_CFG_INR_ERR_ENA BIT(0)
+#define DEV25G_MAC_ADV_CHK_CFG_INR_ERR_ENA_SET(x)\
+ FIELD_PREP(DEV25G_MAC_ADV_CHK_CFG_INR_ERR_ENA, x)
+#define DEV25G_MAC_ADV_CHK_CFG_INR_ERR_ENA_GET(x)\
+ FIELD_GET(DEV25G_MAC_ADV_CHK_CFG_INR_ERR_ENA, x)
+
+/* DEV10G:DEV_CFG_STATUS:DEV_RST_CTRL */
+#define DEV25G_DEV_RST_CTRL(t) __REG(TARGET_DEV25G, t, 8, 436, 0, 1, 52, 0, 0, 1, 4)
+
+#define DEV25G_DEV_RST_CTRL_PARDET_MODE_ENA BIT(28)
+#define DEV25G_DEV_RST_CTRL_PARDET_MODE_ENA_SET(x)\
+ FIELD_PREP(DEV25G_DEV_RST_CTRL_PARDET_MODE_ENA, x)
+#define DEV25G_DEV_RST_CTRL_PARDET_MODE_ENA_GET(x)\
+ FIELD_GET(DEV25G_DEV_RST_CTRL_PARDET_MODE_ENA, x)
+
+#define DEV25G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS BIT(27)
+#define DEV25G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS_SET(x)\
+ FIELD_PREP(DEV25G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS, x)
+#define DEV25G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS_GET(x)\
+ FIELD_GET(DEV25G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS, x)
+
+#define DEV25G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS GENMASK(26, 25)
+#define DEV25G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS_SET(x)\
+ FIELD_PREP(DEV25G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS, x)
+#define DEV25G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS_GET(x)\
+ FIELD_GET(DEV25G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS, x)
+
+#define DEV25G_DEV_RST_CTRL_SERDES_SPEED_SEL GENMASK(24, 23)
+#define DEV25G_DEV_RST_CTRL_SERDES_SPEED_SEL_SET(x)\
+ FIELD_PREP(DEV25G_DEV_RST_CTRL_SERDES_SPEED_SEL, x)
+#define DEV25G_DEV_RST_CTRL_SERDES_SPEED_SEL_GET(x)\
+ FIELD_GET(DEV25G_DEV_RST_CTRL_SERDES_SPEED_SEL, x)
+
+#define DEV25G_DEV_RST_CTRL_SPEED_SEL GENMASK(22, 20)
+#define DEV25G_DEV_RST_CTRL_SPEED_SEL_SET(x)\
+ FIELD_PREP(DEV25G_DEV_RST_CTRL_SPEED_SEL, x)
+#define DEV25G_DEV_RST_CTRL_SPEED_SEL_GET(x)\
+ FIELD_GET(DEV25G_DEV_RST_CTRL_SPEED_SEL, x)
+
+#define DEV25G_DEV_RST_CTRL_PCS_TX_RST BIT(12)
+#define DEV25G_DEV_RST_CTRL_PCS_TX_RST_SET(x)\
+ FIELD_PREP(DEV25G_DEV_RST_CTRL_PCS_TX_RST, x)
+#define DEV25G_DEV_RST_CTRL_PCS_TX_RST_GET(x)\
+ FIELD_GET(DEV25G_DEV_RST_CTRL_PCS_TX_RST, x)
+
+#define DEV25G_DEV_RST_CTRL_PCS_RX_RST BIT(8)
+#define DEV25G_DEV_RST_CTRL_PCS_RX_RST_SET(x)\
+ FIELD_PREP(DEV25G_DEV_RST_CTRL_PCS_RX_RST, x)
+#define DEV25G_DEV_RST_CTRL_PCS_RX_RST_GET(x)\
+ FIELD_GET(DEV25G_DEV_RST_CTRL_PCS_RX_RST, x)
+
+#define DEV25G_DEV_RST_CTRL_MAC_TX_RST BIT(4)
+#define DEV25G_DEV_RST_CTRL_MAC_TX_RST_SET(x)\
+ FIELD_PREP(DEV25G_DEV_RST_CTRL_MAC_TX_RST, x)
+#define DEV25G_DEV_RST_CTRL_MAC_TX_RST_GET(x)\
+ FIELD_GET(DEV25G_DEV_RST_CTRL_MAC_TX_RST, x)
+
+#define DEV25G_DEV_RST_CTRL_MAC_RX_RST BIT(0)
+#define DEV25G_DEV_RST_CTRL_MAC_RX_RST_SET(x)\
+ FIELD_PREP(DEV25G_DEV_RST_CTRL_MAC_RX_RST, x)
+#define DEV25G_DEV_RST_CTRL_MAC_RX_RST_GET(x)\
+ FIELD_GET(DEV25G_DEV_RST_CTRL_MAC_RX_RST, x)
+
+/* DEV10G:PCS25G_CFG_STATUS:PCS25G_CFG */
+#define DEV25G_PCS25G_CFG(t) __REG(TARGET_DEV25G, t, 8, 488, 0, 1, 32, 0, 0, 1, 4)
+
+#define DEV25G_PCS25G_CFG_PCS25G_ENA BIT(0)
+#define DEV25G_PCS25G_CFG_PCS25G_ENA_SET(x)\
+ FIELD_PREP(DEV25G_PCS25G_CFG_PCS25G_ENA, x)
+#define DEV25G_PCS25G_CFG_PCS25G_ENA_GET(x)\
+ FIELD_GET(DEV25G_PCS25G_CFG_PCS25G_ENA, x)
+
+/* DEV10G:PCS25G_CFG_STATUS:PCS25G_SD_CFG */
+#define DEV25G_PCS25G_SD_CFG(t) __REG(TARGET_DEV25G, t, 8, 488, 0, 1, 32, 4, 0, 1, 4)
+
+#define DEV25G_PCS25G_SD_CFG_SD_SEL BIT(8)
+#define DEV25G_PCS25G_SD_CFG_SD_SEL_SET(x)\
+ FIELD_PREP(DEV25G_PCS25G_SD_CFG_SD_SEL, x)
+#define DEV25G_PCS25G_SD_CFG_SD_SEL_GET(x)\
+ FIELD_GET(DEV25G_PCS25G_SD_CFG_SD_SEL, x)
+
+#define DEV25G_PCS25G_SD_CFG_SD_POL BIT(4)
+#define DEV25G_PCS25G_SD_CFG_SD_POL_SET(x)\
+ FIELD_PREP(DEV25G_PCS25G_SD_CFG_SD_POL, x)
+#define DEV25G_PCS25G_SD_CFG_SD_POL_GET(x)\
+ FIELD_GET(DEV25G_PCS25G_SD_CFG_SD_POL, x)
+
+#define DEV25G_PCS25G_SD_CFG_SD_ENA BIT(0)
+#define DEV25G_PCS25G_SD_CFG_SD_ENA_SET(x)\
+ FIELD_PREP(DEV25G_PCS25G_SD_CFG_SD_ENA, x)
+#define DEV25G_PCS25G_SD_CFG_SD_ENA_GET(x)\
+ FIELD_GET(DEV25G_PCS25G_SD_CFG_SD_ENA, x)
+
+/* DEV1G:DEV_CFG_STATUS:DEV_RST_CTRL */
+#define DEV2G5_DEV_RST_CTRL(t) __REG(TARGET_DEV2G5, t, 65, 0, 0, 1, 36, 0, 0, 1, 4)
+
+#define DEV2G5_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS BIT(23)
+#define DEV2G5_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS_SET(x)\
+ FIELD_PREP(DEV2G5_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS, x)
+#define DEV2G5_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS_GET(x)\
+ FIELD_GET(DEV2G5_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS, x)
+
+#define DEV2G5_DEV_RST_CTRL_SPEED_SEL GENMASK(22, 20)
+#define DEV2G5_DEV_RST_CTRL_SPEED_SEL_SET(x)\
+ FIELD_PREP(DEV2G5_DEV_RST_CTRL_SPEED_SEL, x)
+#define DEV2G5_DEV_RST_CTRL_SPEED_SEL_GET(x)\
+ FIELD_GET(DEV2G5_DEV_RST_CTRL_SPEED_SEL, x)
+
+#define DEV2G5_DEV_RST_CTRL_USX_PCS_TX_RST BIT(17)
+#define DEV2G5_DEV_RST_CTRL_USX_PCS_TX_RST_SET(x)\
+ FIELD_PREP(DEV2G5_DEV_RST_CTRL_USX_PCS_TX_RST, x)
+#define DEV2G5_DEV_RST_CTRL_USX_PCS_TX_RST_GET(x)\
+ FIELD_GET(DEV2G5_DEV_RST_CTRL_USX_PCS_TX_RST, x)
+
+#define DEV2G5_DEV_RST_CTRL_USX_PCS_RX_RST BIT(16)
+#define DEV2G5_DEV_RST_CTRL_USX_PCS_RX_RST_SET(x)\
+ FIELD_PREP(DEV2G5_DEV_RST_CTRL_USX_PCS_RX_RST, x)
+#define DEV2G5_DEV_RST_CTRL_USX_PCS_RX_RST_GET(x)\
+ FIELD_GET(DEV2G5_DEV_RST_CTRL_USX_PCS_RX_RST, x)
+
+#define DEV2G5_DEV_RST_CTRL_PCS_TX_RST BIT(12)
+#define DEV2G5_DEV_RST_CTRL_PCS_TX_RST_SET(x)\
+ FIELD_PREP(DEV2G5_DEV_RST_CTRL_PCS_TX_RST, x)
+#define DEV2G5_DEV_RST_CTRL_PCS_TX_RST_GET(x)\
+ FIELD_GET(DEV2G5_DEV_RST_CTRL_PCS_TX_RST, x)
+
+#define DEV2G5_DEV_RST_CTRL_PCS_RX_RST BIT(8)
+#define DEV2G5_DEV_RST_CTRL_PCS_RX_RST_SET(x)\
+ FIELD_PREP(DEV2G5_DEV_RST_CTRL_PCS_RX_RST, x)
+#define DEV2G5_DEV_RST_CTRL_PCS_RX_RST_GET(x)\
+ FIELD_GET(DEV2G5_DEV_RST_CTRL_PCS_RX_RST, x)
+
+#define DEV2G5_DEV_RST_CTRL_MAC_TX_RST BIT(4)
+#define DEV2G5_DEV_RST_CTRL_MAC_TX_RST_SET(x)\
+ FIELD_PREP(DEV2G5_DEV_RST_CTRL_MAC_TX_RST, x)
+#define DEV2G5_DEV_RST_CTRL_MAC_TX_RST_GET(x)\
+ FIELD_GET(DEV2G5_DEV_RST_CTRL_MAC_TX_RST, x)
+
+#define DEV2G5_DEV_RST_CTRL_MAC_RX_RST BIT(0)
+#define DEV2G5_DEV_RST_CTRL_MAC_RX_RST_SET(x)\
+ FIELD_PREP(DEV2G5_DEV_RST_CTRL_MAC_RX_RST, x)
+#define DEV2G5_DEV_RST_CTRL_MAC_RX_RST_GET(x)\
+ FIELD_GET(DEV2G5_DEV_RST_CTRL_MAC_RX_RST, x)
+
+/* DEV1G:MAC_CFG_STATUS:MAC_ENA_CFG */
+#define DEV2G5_MAC_ENA_CFG(t) __REG(TARGET_DEV2G5, t, 65, 52, 0, 1, 36, 0, 0, 1, 4)
+
+#define DEV2G5_MAC_ENA_CFG_RX_ENA BIT(4)
+#define DEV2G5_MAC_ENA_CFG_RX_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_ENA_CFG_RX_ENA, x)
+#define DEV2G5_MAC_ENA_CFG_RX_ENA_GET(x)\
+ FIELD_GET(DEV2G5_MAC_ENA_CFG_RX_ENA, x)
+
+#define DEV2G5_MAC_ENA_CFG_TX_ENA BIT(0)
+#define DEV2G5_MAC_ENA_CFG_TX_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_ENA_CFG_TX_ENA, x)
+#define DEV2G5_MAC_ENA_CFG_TX_ENA_GET(x)\
+ FIELD_GET(DEV2G5_MAC_ENA_CFG_TX_ENA, x)
+
+/* DEV1G:MAC_CFG_STATUS:MAC_MODE_CFG */
+#define DEV2G5_MAC_MODE_CFG(t) __REG(TARGET_DEV2G5, t, 65, 52, 0, 1, 36, 4, 0, 1, 4)
+
+#define DEV2G5_MAC_MODE_CFG_FC_WORD_SYNC_ENA BIT(8)
+#define DEV2G5_MAC_MODE_CFG_FC_WORD_SYNC_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_MODE_CFG_FC_WORD_SYNC_ENA, x)
+#define DEV2G5_MAC_MODE_CFG_FC_WORD_SYNC_ENA_GET(x)\
+ FIELD_GET(DEV2G5_MAC_MODE_CFG_FC_WORD_SYNC_ENA, x)
+
+#define DEV2G5_MAC_MODE_CFG_GIGA_MODE_ENA BIT(4)
+#define DEV2G5_MAC_MODE_CFG_GIGA_MODE_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_MODE_CFG_GIGA_MODE_ENA, x)
+#define DEV2G5_MAC_MODE_CFG_GIGA_MODE_ENA_GET(x)\
+ FIELD_GET(DEV2G5_MAC_MODE_CFG_GIGA_MODE_ENA, x)
+
+#define DEV2G5_MAC_MODE_CFG_FDX_ENA BIT(0)
+#define DEV2G5_MAC_MODE_CFG_FDX_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_MODE_CFG_FDX_ENA, x)
+#define DEV2G5_MAC_MODE_CFG_FDX_ENA_GET(x)\
+ FIELD_GET(DEV2G5_MAC_MODE_CFG_FDX_ENA, x)
+
+/* DEV1G:MAC_CFG_STATUS:MAC_MAXLEN_CFG */
+#define DEV2G5_MAC_MAXLEN_CFG(t) __REG(TARGET_DEV2G5, t, 65, 52, 0, 1, 36, 8, 0, 1, 4)
+
+#define DEV2G5_MAC_MAXLEN_CFG_MAX_LEN GENMASK(15, 0)
+#define DEV2G5_MAC_MAXLEN_CFG_MAX_LEN_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_MAXLEN_CFG_MAX_LEN, x)
+#define DEV2G5_MAC_MAXLEN_CFG_MAX_LEN_GET(x)\
+ FIELD_GET(DEV2G5_MAC_MAXLEN_CFG_MAX_LEN, x)
+
+/* DEV1G:MAC_CFG_STATUS:MAC_TAGS_CFG */
+#define DEV2G5_MAC_TAGS_CFG(t) __REG(TARGET_DEV2G5, t, 65, 52, 0, 1, 36, 12, 0, 1, 4)
+
+#define DEV2G5_MAC_TAGS_CFG_TAG_ID GENMASK(31, 16)
+#define DEV2G5_MAC_TAGS_CFG_TAG_ID_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_TAGS_CFG_TAG_ID, x)
+#define DEV2G5_MAC_TAGS_CFG_TAG_ID_GET(x)\
+ FIELD_GET(DEV2G5_MAC_TAGS_CFG_TAG_ID, x)
+
+#define DEV2G5_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA BIT(3)
+#define DEV2G5_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA, x)
+#define DEV2G5_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA_GET(x)\
+ FIELD_GET(DEV2G5_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA, x)
+
+#define DEV2G5_MAC_TAGS_CFG_PB_ENA GENMASK(2, 1)
+#define DEV2G5_MAC_TAGS_CFG_PB_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_TAGS_CFG_PB_ENA, x)
+#define DEV2G5_MAC_TAGS_CFG_PB_ENA_GET(x)\
+ FIELD_GET(DEV2G5_MAC_TAGS_CFG_PB_ENA, x)
+
+#define DEV2G5_MAC_TAGS_CFG_VLAN_AWR_ENA BIT(0)
+#define DEV2G5_MAC_TAGS_CFG_VLAN_AWR_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_TAGS_CFG_VLAN_AWR_ENA, x)
+#define DEV2G5_MAC_TAGS_CFG_VLAN_AWR_ENA_GET(x)\
+ FIELD_GET(DEV2G5_MAC_TAGS_CFG_VLAN_AWR_ENA, x)
+
+/* DEV1G:MAC_CFG_STATUS:MAC_TAGS_CFG2 */
+#define DEV2G5_MAC_TAGS_CFG2(t) __REG(TARGET_DEV2G5, t, 65, 52, 0, 1, 36, 16, 0, 1, 4)
+
+#define DEV2G5_MAC_TAGS_CFG2_TAG_ID3 GENMASK(31, 16)
+#define DEV2G5_MAC_TAGS_CFG2_TAG_ID3_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_TAGS_CFG2_TAG_ID3, x)
+#define DEV2G5_MAC_TAGS_CFG2_TAG_ID3_GET(x)\
+ FIELD_GET(DEV2G5_MAC_TAGS_CFG2_TAG_ID3, x)
+
+#define DEV2G5_MAC_TAGS_CFG2_TAG_ID2 GENMASK(15, 0)
+#define DEV2G5_MAC_TAGS_CFG2_TAG_ID2_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_TAGS_CFG2_TAG_ID2, x)
+#define DEV2G5_MAC_TAGS_CFG2_TAG_ID2_GET(x)\
+ FIELD_GET(DEV2G5_MAC_TAGS_CFG2_TAG_ID2, x)
+
+/* DEV1G:MAC_CFG_STATUS:MAC_ADV_CHK_CFG */
+#define DEV2G5_MAC_ADV_CHK_CFG(t) __REG(TARGET_DEV2G5, t, 65, 52, 0, 1, 36, 20, 0, 1, 4)
+
+#define DEV2G5_MAC_ADV_CHK_CFG_LEN_DROP_ENA BIT(0)
+#define DEV2G5_MAC_ADV_CHK_CFG_LEN_DROP_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_ADV_CHK_CFG_LEN_DROP_ENA, x)
+#define DEV2G5_MAC_ADV_CHK_CFG_LEN_DROP_ENA_GET(x)\
+ FIELD_GET(DEV2G5_MAC_ADV_CHK_CFG_LEN_DROP_ENA, x)
+
+/* DEV1G:MAC_CFG_STATUS:MAC_IFG_CFG */
+#define DEV2G5_MAC_IFG_CFG(t) __REG(TARGET_DEV2G5, t, 65, 52, 0, 1, 36, 24, 0, 1, 4)
+
+#define DEV2G5_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK BIT(17)
+#define DEV2G5_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK, x)
+#define DEV2G5_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK_GET(x)\
+ FIELD_GET(DEV2G5_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK, x)
+
+#define DEV2G5_MAC_IFG_CFG_TX_IFG GENMASK(12, 8)
+#define DEV2G5_MAC_IFG_CFG_TX_IFG_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_IFG_CFG_TX_IFG, x)
+#define DEV2G5_MAC_IFG_CFG_TX_IFG_GET(x)\
+ FIELD_GET(DEV2G5_MAC_IFG_CFG_TX_IFG, x)
+
+#define DEV2G5_MAC_IFG_CFG_RX_IFG2 GENMASK(7, 4)
+#define DEV2G5_MAC_IFG_CFG_RX_IFG2_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_IFG_CFG_RX_IFG2, x)
+#define DEV2G5_MAC_IFG_CFG_RX_IFG2_GET(x)\
+ FIELD_GET(DEV2G5_MAC_IFG_CFG_RX_IFG2, x)
+
+#define DEV2G5_MAC_IFG_CFG_RX_IFG1 GENMASK(3, 0)
+#define DEV2G5_MAC_IFG_CFG_RX_IFG1_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_IFG_CFG_RX_IFG1, x)
+#define DEV2G5_MAC_IFG_CFG_RX_IFG1_GET(x)\
+ FIELD_GET(DEV2G5_MAC_IFG_CFG_RX_IFG1, x)
+
+/* DEV1G:MAC_CFG_STATUS:MAC_HDX_CFG */
+#define DEV2G5_MAC_HDX_CFG(t) __REG(TARGET_DEV2G5, t, 65, 52, 0, 1, 36, 28, 0, 1, 4)
+
+#define DEV2G5_MAC_HDX_CFG_BYPASS_COL_SYNC BIT(26)
+#define DEV2G5_MAC_HDX_CFG_BYPASS_COL_SYNC_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_HDX_CFG_BYPASS_COL_SYNC, x)
+#define DEV2G5_MAC_HDX_CFG_BYPASS_COL_SYNC_GET(x)\
+ FIELD_GET(DEV2G5_MAC_HDX_CFG_BYPASS_COL_SYNC, x)
+
+#define DEV2G5_MAC_HDX_CFG_SEED GENMASK(23, 16)
+#define DEV2G5_MAC_HDX_CFG_SEED_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_HDX_CFG_SEED, x)
+#define DEV2G5_MAC_HDX_CFG_SEED_GET(x)\
+ FIELD_GET(DEV2G5_MAC_HDX_CFG_SEED, x)
+
+#define DEV2G5_MAC_HDX_CFG_SEED_LOAD BIT(12)
+#define DEV2G5_MAC_HDX_CFG_SEED_LOAD_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_HDX_CFG_SEED_LOAD, x)
+#define DEV2G5_MAC_HDX_CFG_SEED_LOAD_GET(x)\
+ FIELD_GET(DEV2G5_MAC_HDX_CFG_SEED_LOAD, x)
+
+#define DEV2G5_MAC_HDX_CFG_RETRY_AFTER_EXC_COL_ENA BIT(8)
+#define DEV2G5_MAC_HDX_CFG_RETRY_AFTER_EXC_COL_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_HDX_CFG_RETRY_AFTER_EXC_COL_ENA, x)
+#define DEV2G5_MAC_HDX_CFG_RETRY_AFTER_EXC_COL_ENA_GET(x)\
+ FIELD_GET(DEV2G5_MAC_HDX_CFG_RETRY_AFTER_EXC_COL_ENA, x)
+
+#define DEV2G5_MAC_HDX_CFG_LATE_COL_POS GENMASK(6, 0)
+#define DEV2G5_MAC_HDX_CFG_LATE_COL_POS_SET(x)\
+ FIELD_PREP(DEV2G5_MAC_HDX_CFG_LATE_COL_POS, x)
+#define DEV2G5_MAC_HDX_CFG_LATE_COL_POS_GET(x)\
+ FIELD_GET(DEV2G5_MAC_HDX_CFG_LATE_COL_POS, x)
+
+/* DEV1G:PCS1G_CFG_STATUS:PCS1G_CFG */
+#define DEV2G5_PCS1G_CFG(t) __REG(TARGET_DEV2G5, t, 65, 88, 0, 1, 68, 0, 0, 1, 4)
+
+#define DEV2G5_PCS1G_CFG_LINK_STATUS_TYPE BIT(4)
+#define DEV2G5_PCS1G_CFG_LINK_STATUS_TYPE_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_CFG_LINK_STATUS_TYPE, x)
+#define DEV2G5_PCS1G_CFG_LINK_STATUS_TYPE_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_CFG_LINK_STATUS_TYPE, x)
+
+#define DEV2G5_PCS1G_CFG_AN_LINK_CTRL_ENA BIT(1)
+#define DEV2G5_PCS1G_CFG_AN_LINK_CTRL_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_CFG_AN_LINK_CTRL_ENA, x)
+#define DEV2G5_PCS1G_CFG_AN_LINK_CTRL_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_CFG_AN_LINK_CTRL_ENA, x)
+
+#define DEV2G5_PCS1G_CFG_PCS_ENA BIT(0)
+#define DEV2G5_PCS1G_CFG_PCS_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_CFG_PCS_ENA, x)
+#define DEV2G5_PCS1G_CFG_PCS_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_CFG_PCS_ENA, x)
+
+/* DEV1G:PCS1G_CFG_STATUS:PCS1G_MODE_CFG */
+#define DEV2G5_PCS1G_MODE_CFG(t) __REG(TARGET_DEV2G5, t, 65, 88, 0, 1, 68, 4, 0, 1, 4)
+
+#define DEV2G5_PCS1G_MODE_CFG_UNIDIR_MODE_ENA BIT(4)
+#define DEV2G5_PCS1G_MODE_CFG_UNIDIR_MODE_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_MODE_CFG_UNIDIR_MODE_ENA, x)
+#define DEV2G5_PCS1G_MODE_CFG_UNIDIR_MODE_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_MODE_CFG_UNIDIR_MODE_ENA, x)
+
+#define DEV2G5_PCS1G_MODE_CFG_SAVE_PREAMBLE_ENA BIT(1)
+#define DEV2G5_PCS1G_MODE_CFG_SAVE_PREAMBLE_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_MODE_CFG_SAVE_PREAMBLE_ENA, x)
+#define DEV2G5_PCS1G_MODE_CFG_SAVE_PREAMBLE_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_MODE_CFG_SAVE_PREAMBLE_ENA, x)
+
+#define DEV2G5_PCS1G_MODE_CFG_SGMII_MODE_ENA BIT(0)
+#define DEV2G5_PCS1G_MODE_CFG_SGMII_MODE_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_MODE_CFG_SGMII_MODE_ENA, x)
+#define DEV2G5_PCS1G_MODE_CFG_SGMII_MODE_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_MODE_CFG_SGMII_MODE_ENA, x)
+
+/* DEV1G:PCS1G_CFG_STATUS:PCS1G_SD_CFG */
+#define DEV2G5_PCS1G_SD_CFG(t) __REG(TARGET_DEV2G5, t, 65, 88, 0, 1, 68, 8, 0, 1, 4)
+
+#define DEV2G5_PCS1G_SD_CFG_SD_SEL BIT(8)
+#define DEV2G5_PCS1G_SD_CFG_SD_SEL_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_SD_CFG_SD_SEL, x)
+#define DEV2G5_PCS1G_SD_CFG_SD_SEL_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_SD_CFG_SD_SEL, x)
+
+#define DEV2G5_PCS1G_SD_CFG_SD_POL BIT(4)
+#define DEV2G5_PCS1G_SD_CFG_SD_POL_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_SD_CFG_SD_POL, x)
+#define DEV2G5_PCS1G_SD_CFG_SD_POL_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_SD_CFG_SD_POL, x)
+
+#define DEV2G5_PCS1G_SD_CFG_SD_ENA BIT(0)
+#define DEV2G5_PCS1G_SD_CFG_SD_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_SD_CFG_SD_ENA, x)
+#define DEV2G5_PCS1G_SD_CFG_SD_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_SD_CFG_SD_ENA, x)
+
+/* DEV1G:PCS1G_CFG_STATUS:PCS1G_ANEG_CFG */
+#define DEV2G5_PCS1G_ANEG_CFG(t) __REG(TARGET_DEV2G5, t, 65, 88, 0, 1, 68, 12, 0, 1, 4)
+
+#define DEV2G5_PCS1G_ANEG_CFG_ADV_ABILITY GENMASK(31, 16)
+#define DEV2G5_PCS1G_ANEG_CFG_ADV_ABILITY_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_ANEG_CFG_ADV_ABILITY, x)
+#define DEV2G5_PCS1G_ANEG_CFG_ADV_ABILITY_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_ANEG_CFG_ADV_ABILITY, x)
+
+#define DEV2G5_PCS1G_ANEG_CFG_SW_RESOLVE_ENA BIT(8)
+#define DEV2G5_PCS1G_ANEG_CFG_SW_RESOLVE_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_ANEG_CFG_SW_RESOLVE_ENA, x)
+#define DEV2G5_PCS1G_ANEG_CFG_SW_RESOLVE_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_ANEG_CFG_SW_RESOLVE_ENA, x)
+
+#define DEV2G5_PCS1G_ANEG_CFG_ANEG_RESTART_ONE_SHOT BIT(1)
+#define DEV2G5_PCS1G_ANEG_CFG_ANEG_RESTART_ONE_SHOT_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_ANEG_CFG_ANEG_RESTART_ONE_SHOT, x)
+#define DEV2G5_PCS1G_ANEG_CFG_ANEG_RESTART_ONE_SHOT_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_ANEG_CFG_ANEG_RESTART_ONE_SHOT, x)
+
+#define DEV2G5_PCS1G_ANEG_CFG_ANEG_ENA BIT(0)
+#define DEV2G5_PCS1G_ANEG_CFG_ANEG_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_ANEG_CFG_ANEG_ENA, x)
+#define DEV2G5_PCS1G_ANEG_CFG_ANEG_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_ANEG_CFG_ANEG_ENA, x)
+
+/* DEV1G:PCS1G_CFG_STATUS:PCS1G_LB_CFG */
+#define DEV2G5_PCS1G_LB_CFG(t) __REG(TARGET_DEV2G5, t, 65, 88, 0, 1, 68, 20, 0, 1, 4)
+
+#define DEV2G5_PCS1G_LB_CFG_RA_ENA BIT(4)
+#define DEV2G5_PCS1G_LB_CFG_RA_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_LB_CFG_RA_ENA, x)
+#define DEV2G5_PCS1G_LB_CFG_RA_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_LB_CFG_RA_ENA, x)
+
+#define DEV2G5_PCS1G_LB_CFG_GMII_PHY_LB_ENA BIT(1)
+#define DEV2G5_PCS1G_LB_CFG_GMII_PHY_LB_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_LB_CFG_GMII_PHY_LB_ENA, x)
+#define DEV2G5_PCS1G_LB_CFG_GMII_PHY_LB_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_LB_CFG_GMII_PHY_LB_ENA, x)
+
+#define DEV2G5_PCS1G_LB_CFG_TBI_HOST_LB_ENA BIT(0)
+#define DEV2G5_PCS1G_LB_CFG_TBI_HOST_LB_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_LB_CFG_TBI_HOST_LB_ENA, x)
+#define DEV2G5_PCS1G_LB_CFG_TBI_HOST_LB_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_LB_CFG_TBI_HOST_LB_ENA, x)
+
+/* DEV1G:PCS1G_CFG_STATUS:PCS1G_ANEG_STATUS */
+#define DEV2G5_PCS1G_ANEG_STATUS(t) __REG(TARGET_DEV2G5, t, 65, 88, 0, 1, 68, 32, 0, 1, 4)
+
+#define DEV2G5_PCS1G_ANEG_STATUS_LP_ADV_ABILITY GENMASK(31, 16)
+#define DEV2G5_PCS1G_ANEG_STATUS_LP_ADV_ABILITY_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_ANEG_STATUS_LP_ADV_ABILITY, x)
+#define DEV2G5_PCS1G_ANEG_STATUS_LP_ADV_ABILITY_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_ANEG_STATUS_LP_ADV_ABILITY, x)
+
+#define DEV2G5_PCS1G_ANEG_STATUS_PR BIT(4)
+#define DEV2G5_PCS1G_ANEG_STATUS_PR_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_ANEG_STATUS_PR, x)
+#define DEV2G5_PCS1G_ANEG_STATUS_PR_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_ANEG_STATUS_PR, x)
+
+#define DEV2G5_PCS1G_ANEG_STATUS_PAGE_RX_STICKY BIT(3)
+#define DEV2G5_PCS1G_ANEG_STATUS_PAGE_RX_STICKY_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_ANEG_STATUS_PAGE_RX_STICKY, x)
+#define DEV2G5_PCS1G_ANEG_STATUS_PAGE_RX_STICKY_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_ANEG_STATUS_PAGE_RX_STICKY, x)
+
+#define DEV2G5_PCS1G_ANEG_STATUS_ANEG_COMPLETE BIT(0)
+#define DEV2G5_PCS1G_ANEG_STATUS_ANEG_COMPLETE_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_ANEG_STATUS_ANEG_COMPLETE, x)
+#define DEV2G5_PCS1G_ANEG_STATUS_ANEG_COMPLETE_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_ANEG_STATUS_ANEG_COMPLETE, x)
+
+/* DEV1G:PCS1G_CFG_STATUS:PCS1G_LINK_STATUS */
+#define DEV2G5_PCS1G_LINK_STATUS(t) __REG(TARGET_DEV2G5, t, 65, 88, 0, 1, 68, 40, 0, 1, 4)
+
+#define DEV2G5_PCS1G_LINK_STATUS_DELAY_VAR GENMASK(15, 12)
+#define DEV2G5_PCS1G_LINK_STATUS_DELAY_VAR_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_LINK_STATUS_DELAY_VAR, x)
+#define DEV2G5_PCS1G_LINK_STATUS_DELAY_VAR_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_LINK_STATUS_DELAY_VAR, x)
+
+#define DEV2G5_PCS1G_LINK_STATUS_SIGNAL_DETECT BIT(8)
+#define DEV2G5_PCS1G_LINK_STATUS_SIGNAL_DETECT_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_LINK_STATUS_SIGNAL_DETECT, x)
+#define DEV2G5_PCS1G_LINK_STATUS_SIGNAL_DETECT_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_LINK_STATUS_SIGNAL_DETECT, x)
+
+#define DEV2G5_PCS1G_LINK_STATUS_LINK_STATUS BIT(4)
+#define DEV2G5_PCS1G_LINK_STATUS_LINK_STATUS_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_LINK_STATUS_LINK_STATUS, x)
+#define DEV2G5_PCS1G_LINK_STATUS_LINK_STATUS_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_LINK_STATUS_LINK_STATUS, x)
+
+#define DEV2G5_PCS1G_LINK_STATUS_SYNC_STATUS BIT(0)
+#define DEV2G5_PCS1G_LINK_STATUS_SYNC_STATUS_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_LINK_STATUS_SYNC_STATUS, x)
+#define DEV2G5_PCS1G_LINK_STATUS_SYNC_STATUS_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_LINK_STATUS_SYNC_STATUS, x)
+
+/* DEV1G:PCS1G_CFG_STATUS:PCS1G_STICKY */
+#define DEV2G5_PCS1G_STICKY(t) __REG(TARGET_DEV2G5, t, 65, 88, 0, 1, 68, 48, 0, 1, 4)
+
+#define DEV2G5_PCS1G_STICKY_LINK_DOWN_STICKY BIT(4)
+#define DEV2G5_PCS1G_STICKY_LINK_DOWN_STICKY_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_STICKY_LINK_DOWN_STICKY, x)
+#define DEV2G5_PCS1G_STICKY_LINK_DOWN_STICKY_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_STICKY_LINK_DOWN_STICKY, x)
+
+#define DEV2G5_PCS1G_STICKY_OUT_OF_SYNC_STICKY BIT(0)
+#define DEV2G5_PCS1G_STICKY_OUT_OF_SYNC_STICKY_SET(x)\
+ FIELD_PREP(DEV2G5_PCS1G_STICKY_OUT_OF_SYNC_STICKY, x)
+#define DEV2G5_PCS1G_STICKY_OUT_OF_SYNC_STICKY_GET(x)\
+ FIELD_GET(DEV2G5_PCS1G_STICKY_OUT_OF_SYNC_STICKY, x)
+
+/* DEV1G:PCS_FX100_CONFIGURATION:PCS_FX100_CFG */
+#define DEV2G5_PCS_FX100_CFG(t) __REG(TARGET_DEV2G5, t, 65, 164, 0, 1, 4, 0, 0, 1, 4)
+
+#define DEV2G5_PCS_FX100_CFG_SD_SEL BIT(26)
+#define DEV2G5_PCS_FX100_CFG_SD_SEL_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_CFG_SD_SEL, x)
+#define DEV2G5_PCS_FX100_CFG_SD_SEL_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_CFG_SD_SEL, x)
+
+#define DEV2G5_PCS_FX100_CFG_SD_POL BIT(25)
+#define DEV2G5_PCS_FX100_CFG_SD_POL_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_CFG_SD_POL, x)
+#define DEV2G5_PCS_FX100_CFG_SD_POL_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_CFG_SD_POL, x)
+
+#define DEV2G5_PCS_FX100_CFG_SD_ENA BIT(24)
+#define DEV2G5_PCS_FX100_CFG_SD_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_CFG_SD_ENA, x)
+#define DEV2G5_PCS_FX100_CFG_SD_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_CFG_SD_ENA, x)
+
+#define DEV2G5_PCS_FX100_CFG_LOOPBACK_ENA BIT(20)
+#define DEV2G5_PCS_FX100_CFG_LOOPBACK_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_CFG_LOOPBACK_ENA, x)
+#define DEV2G5_PCS_FX100_CFG_LOOPBACK_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_CFG_LOOPBACK_ENA, x)
+
+#define DEV2G5_PCS_FX100_CFG_SWAP_MII_ENA BIT(16)
+#define DEV2G5_PCS_FX100_CFG_SWAP_MII_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_CFG_SWAP_MII_ENA, x)
+#define DEV2G5_PCS_FX100_CFG_SWAP_MII_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_CFG_SWAP_MII_ENA, x)
+
+#define DEV2G5_PCS_FX100_CFG_RXBITSEL GENMASK(15, 12)
+#define DEV2G5_PCS_FX100_CFG_RXBITSEL_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_CFG_RXBITSEL, x)
+#define DEV2G5_PCS_FX100_CFG_RXBITSEL_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_CFG_RXBITSEL, x)
+
+#define DEV2G5_PCS_FX100_CFG_SIGDET_CFG GENMASK(10, 9)
+#define DEV2G5_PCS_FX100_CFG_SIGDET_CFG_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_CFG_SIGDET_CFG, x)
+#define DEV2G5_PCS_FX100_CFG_SIGDET_CFG_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_CFG_SIGDET_CFG, x)
+
+#define DEV2G5_PCS_FX100_CFG_LINKHYST_TM_ENA BIT(8)
+#define DEV2G5_PCS_FX100_CFG_LINKHYST_TM_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_CFG_LINKHYST_TM_ENA, x)
+#define DEV2G5_PCS_FX100_CFG_LINKHYST_TM_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_CFG_LINKHYST_TM_ENA, x)
+
+#define DEV2G5_PCS_FX100_CFG_LINKHYSTTIMER GENMASK(7, 4)
+#define DEV2G5_PCS_FX100_CFG_LINKHYSTTIMER_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_CFG_LINKHYSTTIMER, x)
+#define DEV2G5_PCS_FX100_CFG_LINKHYSTTIMER_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_CFG_LINKHYSTTIMER, x)
+
+#define DEV2G5_PCS_FX100_CFG_UNIDIR_MODE_ENA BIT(3)
+#define DEV2G5_PCS_FX100_CFG_UNIDIR_MODE_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_CFG_UNIDIR_MODE_ENA, x)
+#define DEV2G5_PCS_FX100_CFG_UNIDIR_MODE_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_CFG_UNIDIR_MODE_ENA, x)
+
+#define DEV2G5_PCS_FX100_CFG_FEFCHK_ENA BIT(2)
+#define DEV2G5_PCS_FX100_CFG_FEFCHK_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_CFG_FEFCHK_ENA, x)
+#define DEV2G5_PCS_FX100_CFG_FEFCHK_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_CFG_FEFCHK_ENA, x)
+
+#define DEV2G5_PCS_FX100_CFG_FEFGEN_ENA BIT(1)
+#define DEV2G5_PCS_FX100_CFG_FEFGEN_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_CFG_FEFGEN_ENA, x)
+#define DEV2G5_PCS_FX100_CFG_FEFGEN_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_CFG_FEFGEN_ENA, x)
+
+#define DEV2G5_PCS_FX100_CFG_PCS_ENA BIT(0)
+#define DEV2G5_PCS_FX100_CFG_PCS_ENA_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_CFG_PCS_ENA, x)
+#define DEV2G5_PCS_FX100_CFG_PCS_ENA_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_CFG_PCS_ENA, x)
+
+/* DEV1G:PCS_FX100_STATUS:PCS_FX100_STATUS */
+#define DEV2G5_PCS_FX100_STATUS(t) __REG(TARGET_DEV2G5, t, 65, 168, 0, 1, 4, 0, 0, 1, 4)
+
+#define DEV2G5_PCS_FX100_STATUS_EDGE_POS_PTP GENMASK(11, 8)
+#define DEV2G5_PCS_FX100_STATUS_EDGE_POS_PTP_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_STATUS_EDGE_POS_PTP, x)
+#define DEV2G5_PCS_FX100_STATUS_EDGE_POS_PTP_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_STATUS_EDGE_POS_PTP, x)
+
+#define DEV2G5_PCS_FX100_STATUS_PCS_ERROR_STICKY BIT(7)
+#define DEV2G5_PCS_FX100_STATUS_PCS_ERROR_STICKY_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_STATUS_PCS_ERROR_STICKY, x)
+#define DEV2G5_PCS_FX100_STATUS_PCS_ERROR_STICKY_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_STATUS_PCS_ERROR_STICKY, x)
+
+#define DEV2G5_PCS_FX100_STATUS_FEF_FOUND_STICKY BIT(6)
+#define DEV2G5_PCS_FX100_STATUS_FEF_FOUND_STICKY_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_STATUS_FEF_FOUND_STICKY, x)
+#define DEV2G5_PCS_FX100_STATUS_FEF_FOUND_STICKY_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_STATUS_FEF_FOUND_STICKY, x)
+
+#define DEV2G5_PCS_FX100_STATUS_SSD_ERROR_STICKY BIT(5)
+#define DEV2G5_PCS_FX100_STATUS_SSD_ERROR_STICKY_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_STATUS_SSD_ERROR_STICKY, x)
+#define DEV2G5_PCS_FX100_STATUS_SSD_ERROR_STICKY_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_STATUS_SSD_ERROR_STICKY, x)
+
+#define DEV2G5_PCS_FX100_STATUS_SYNC_LOST_STICKY BIT(4)
+#define DEV2G5_PCS_FX100_STATUS_SYNC_LOST_STICKY_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_STATUS_SYNC_LOST_STICKY, x)
+#define DEV2G5_PCS_FX100_STATUS_SYNC_LOST_STICKY_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_STATUS_SYNC_LOST_STICKY, x)
+
+#define DEV2G5_PCS_FX100_STATUS_FEF_STATUS BIT(2)
+#define DEV2G5_PCS_FX100_STATUS_FEF_STATUS_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_STATUS_FEF_STATUS, x)
+#define DEV2G5_PCS_FX100_STATUS_FEF_STATUS_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_STATUS_FEF_STATUS, x)
+
+#define DEV2G5_PCS_FX100_STATUS_SIGNAL_DETECT BIT(1)
+#define DEV2G5_PCS_FX100_STATUS_SIGNAL_DETECT_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_STATUS_SIGNAL_DETECT, x)
+#define DEV2G5_PCS_FX100_STATUS_SIGNAL_DETECT_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_STATUS_SIGNAL_DETECT, x)
+
+#define DEV2G5_PCS_FX100_STATUS_SYNC_STATUS BIT(0)
+#define DEV2G5_PCS_FX100_STATUS_SYNC_STATUS_SET(x)\
+ FIELD_PREP(DEV2G5_PCS_FX100_STATUS_SYNC_STATUS, x)
+#define DEV2G5_PCS_FX100_STATUS_SYNC_STATUS_GET(x)\
+ FIELD_GET(DEV2G5_PCS_FX100_STATUS_SYNC_STATUS, x)
+
+/* DEV10G:MAC_CFG_STATUS:MAC_ENA_CFG */
+#define DEV5G_MAC_ENA_CFG(t) __REG(TARGET_DEV5G, t, 13, 0, 0, 1, 60, 0, 0, 1, 4)
+
+#define DEV5G_MAC_ENA_CFG_RX_ENA BIT(4)
+#define DEV5G_MAC_ENA_CFG_RX_ENA_SET(x)\
+ FIELD_PREP(DEV5G_MAC_ENA_CFG_RX_ENA, x)
+#define DEV5G_MAC_ENA_CFG_RX_ENA_GET(x)\
+ FIELD_GET(DEV5G_MAC_ENA_CFG_RX_ENA, x)
+
+#define DEV5G_MAC_ENA_CFG_TX_ENA BIT(0)
+#define DEV5G_MAC_ENA_CFG_TX_ENA_SET(x)\
+ FIELD_PREP(DEV5G_MAC_ENA_CFG_TX_ENA, x)
+#define DEV5G_MAC_ENA_CFG_TX_ENA_GET(x)\
+ FIELD_GET(DEV5G_MAC_ENA_CFG_TX_ENA, x)
+
+/* DEV10G:MAC_CFG_STATUS:MAC_MAXLEN_CFG */
+#define DEV5G_MAC_MAXLEN_CFG(t) __REG(TARGET_DEV5G, t, 13, 0, 0, 1, 60, 8, 0, 1, 4)
+
+#define DEV5G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK BIT(16)
+#define DEV5G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK_SET(x)\
+ FIELD_PREP(DEV5G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK, x)
+#define DEV5G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK_GET(x)\
+ FIELD_GET(DEV5G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK, x)
+
+#define DEV5G_MAC_MAXLEN_CFG_MAX_LEN GENMASK(15, 0)
+#define DEV5G_MAC_MAXLEN_CFG_MAX_LEN_SET(x)\
+ FIELD_PREP(DEV5G_MAC_MAXLEN_CFG_MAX_LEN, x)
+#define DEV5G_MAC_MAXLEN_CFG_MAX_LEN_GET(x)\
+ FIELD_GET(DEV5G_MAC_MAXLEN_CFG_MAX_LEN, x)
+
+/* DEV10G:MAC_CFG_STATUS:MAC_ADV_CHK_CFG */
+#define DEV5G_MAC_ADV_CHK_CFG(t) __REG(TARGET_DEV5G, t, 13, 0, 0, 1, 60, 28, 0, 1, 4)
+
+#define DEV5G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA BIT(24)
+#define DEV5G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA_SET(x)\
+ FIELD_PREP(DEV5G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA, x)
+#define DEV5G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA_GET(x)\
+ FIELD_GET(DEV5G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA, x)
+
+#define DEV5G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA BIT(20)
+#define DEV5G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA_SET(x)\
+ FIELD_PREP(DEV5G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA, x)
+#define DEV5G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA_GET(x)\
+ FIELD_GET(DEV5G_MAC_ADV_CHK_CFG_EXT_SOP_CHK_ENA, x)
+
+#define DEV5G_MAC_ADV_CHK_CFG_SFD_CHK_ENA BIT(16)
+#define DEV5G_MAC_ADV_CHK_CFG_SFD_CHK_ENA_SET(x)\
+ FIELD_PREP(DEV5G_MAC_ADV_CHK_CFG_SFD_CHK_ENA, x)
+#define DEV5G_MAC_ADV_CHK_CFG_SFD_CHK_ENA_GET(x)\
+ FIELD_GET(DEV5G_MAC_ADV_CHK_CFG_SFD_CHK_ENA, x)
+
+#define DEV5G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS BIT(12)
+#define DEV5G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS_SET(x)\
+ FIELD_PREP(DEV5G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS, x)
+#define DEV5G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS_GET(x)\
+ FIELD_GET(DEV5G_MAC_ADV_CHK_CFG_PRM_SHK_CHK_DIS, x)
+
+#define DEV5G_MAC_ADV_CHK_CFG_PRM_CHK_ENA BIT(8)
+#define DEV5G_MAC_ADV_CHK_CFG_PRM_CHK_ENA_SET(x)\
+ FIELD_PREP(DEV5G_MAC_ADV_CHK_CFG_PRM_CHK_ENA, x)
+#define DEV5G_MAC_ADV_CHK_CFG_PRM_CHK_ENA_GET(x)\
+ FIELD_GET(DEV5G_MAC_ADV_CHK_CFG_PRM_CHK_ENA, x)
+
+#define DEV5G_MAC_ADV_CHK_CFG_OOR_ERR_ENA BIT(4)
+#define DEV5G_MAC_ADV_CHK_CFG_OOR_ERR_ENA_SET(x)\
+ FIELD_PREP(DEV5G_MAC_ADV_CHK_CFG_OOR_ERR_ENA, x)
+#define DEV5G_MAC_ADV_CHK_CFG_OOR_ERR_ENA_GET(x)\
+ FIELD_GET(DEV5G_MAC_ADV_CHK_CFG_OOR_ERR_ENA, x)
+
+#define DEV5G_MAC_ADV_CHK_CFG_INR_ERR_ENA BIT(0)
+#define DEV5G_MAC_ADV_CHK_CFG_INR_ERR_ENA_SET(x)\
+ FIELD_PREP(DEV5G_MAC_ADV_CHK_CFG_INR_ERR_ENA, x)
+#define DEV5G_MAC_ADV_CHK_CFG_INR_ERR_ENA_GET(x)\
+ FIELD_GET(DEV5G_MAC_ADV_CHK_CFG_INR_ERR_ENA, x)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_SYMBOL_ERR_CNT */
+#define DEV5G_RX_SYMBOL_ERR_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 0, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_PAUSE_CNT */
+#define DEV5G_RX_PAUSE_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 4, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_UNSUP_OPCODE_CNT */
+#define DEV5G_RX_UNSUP_OPCODE_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 8, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_UC_CNT */
+#define DEV5G_RX_UC_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 12, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_MC_CNT */
+#define DEV5G_RX_MC_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 16, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_BC_CNT */
+#define DEV5G_RX_BC_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 20, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_CRC_ERR_CNT */
+#define DEV5G_RX_CRC_ERR_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 24, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_UNDERSIZE_CNT */
+#define DEV5G_RX_UNDERSIZE_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 28, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_FRAGMENTS_CNT */
+#define DEV5G_RX_FRAGMENTS_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 32, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_IN_RANGE_LEN_ERR_CNT */
+#define DEV5G_RX_IN_RANGE_LEN_ERR_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 36, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_OUT_OF_RANGE_LEN_ERR_CNT */
+#define DEV5G_RX_OUT_OF_RANGE_LEN_ERR_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 40, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_OVERSIZE_CNT */
+#define DEV5G_RX_OVERSIZE_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 44, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_JABBERS_CNT */
+#define DEV5G_RX_JABBERS_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 48, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE64_CNT */
+#define DEV5G_RX_SIZE64_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 52, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE65TO127_CNT */
+#define DEV5G_RX_SIZE65TO127_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 56, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE128TO255_CNT */
+#define DEV5G_RX_SIZE128TO255_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 60, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE256TO511_CNT */
+#define DEV5G_RX_SIZE256TO511_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 64, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE512TO1023_CNT */
+#define DEV5G_RX_SIZE512TO1023_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 68, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE1024TO1518_CNT */
+#define DEV5G_RX_SIZE1024TO1518_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 72, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE1519TOMAX_CNT */
+#define DEV5G_RX_SIZE1519TOMAX_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 76, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_IPG_SHRINK_CNT */
+#define DEV5G_RX_IPG_SHRINK_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 80, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:TX_PAUSE_CNT */
+#define DEV5G_TX_PAUSE_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 84, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:TX_UC_CNT */
+#define DEV5G_TX_UC_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 88, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:TX_MC_CNT */
+#define DEV5G_TX_MC_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 92, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:TX_BC_CNT */
+#define DEV5G_TX_BC_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 96, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE64_CNT */
+#define DEV5G_TX_SIZE64_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 100, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE65TO127_CNT */
+#define DEV5G_TX_SIZE65TO127_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 104, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE128TO255_CNT */
+#define DEV5G_TX_SIZE128TO255_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 108, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE256TO511_CNT */
+#define DEV5G_TX_SIZE256TO511_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 112, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE512TO1023_CNT */
+#define DEV5G_TX_SIZE512TO1023_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 116, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE1024TO1518_CNT */
+#define DEV5G_TX_SIZE1024TO1518_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 120, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE1519TOMAX_CNT */
+#define DEV5G_TX_SIZE1519TOMAX_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 124, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_ALIGNMENT_LOST_CNT */
+#define DEV5G_RX_ALIGNMENT_LOST_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 128, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_TAGGED_FRMS_CNT */
+#define DEV5G_RX_TAGGED_FRMS_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 132, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_UNTAGGED_FRMS_CNT */
+#define DEV5G_RX_UNTAGGED_FRMS_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 136, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:TX_TAGGED_FRMS_CNT */
+#define DEV5G_TX_TAGGED_FRMS_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 140, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:TX_UNTAGGED_FRMS_CNT */
+#define DEV5G_TX_UNTAGGED_FRMS_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 144, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SYMBOL_ERR_CNT */
+#define DEV5G_PMAC_RX_SYMBOL_ERR_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 148, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_PAUSE_CNT */
+#define DEV5G_PMAC_RX_PAUSE_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 152, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_UNSUP_OPCODE_CNT */
+#define DEV5G_PMAC_RX_UNSUP_OPCODE_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 156, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_UC_CNT */
+#define DEV5G_PMAC_RX_UC_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 160, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_MC_CNT */
+#define DEV5G_PMAC_RX_MC_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 164, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_BC_CNT */
+#define DEV5G_PMAC_RX_BC_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 168, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_CRC_ERR_CNT */
+#define DEV5G_PMAC_RX_CRC_ERR_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 172, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_UNDERSIZE_CNT */
+#define DEV5G_PMAC_RX_UNDERSIZE_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 176, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_FRAGMENTS_CNT */
+#define DEV5G_PMAC_RX_FRAGMENTS_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 180, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_IN_RANGE_LEN_ERR_CNT */
+#define DEV5G_PMAC_RX_IN_RANGE_LEN_ERR_CNT(t) __REG(TARGET_DEV5G,\
+ t, 13, 60, 0, 1, 312, 184, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT */
+#define DEV5G_PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT(t) __REG(TARGET_DEV5G,\
+ t, 13, 60, 0, 1, 312, 188, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_OVERSIZE_CNT */
+#define DEV5G_PMAC_RX_OVERSIZE_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 192, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_JABBERS_CNT */
+#define DEV5G_PMAC_RX_JABBERS_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 196, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE64_CNT */
+#define DEV5G_PMAC_RX_SIZE64_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 200, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE65TO127_CNT */
+#define DEV5G_PMAC_RX_SIZE65TO127_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 204, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE128TO255_CNT */
+#define DEV5G_PMAC_RX_SIZE128TO255_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 208, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE256TO511_CNT */
+#define DEV5G_PMAC_RX_SIZE256TO511_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 212, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE512TO1023_CNT */
+#define DEV5G_PMAC_RX_SIZE512TO1023_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 216, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE1024TO1518_CNT */
+#define DEV5G_PMAC_RX_SIZE1024TO1518_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 220, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE1519TOMAX_CNT */
+#define DEV5G_PMAC_RX_SIZE1519TOMAX_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 224, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_PAUSE_CNT */
+#define DEV5G_PMAC_TX_PAUSE_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 228, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_UC_CNT */
+#define DEV5G_PMAC_TX_UC_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 232, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_MC_CNT */
+#define DEV5G_PMAC_TX_MC_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 236, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_BC_CNT */
+#define DEV5G_PMAC_TX_BC_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 240, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE64_CNT */
+#define DEV5G_PMAC_TX_SIZE64_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 244, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE65TO127_CNT */
+#define DEV5G_PMAC_TX_SIZE65TO127_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 248, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE128TO255_CNT */
+#define DEV5G_PMAC_TX_SIZE128TO255_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 252, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE256TO511_CNT */
+#define DEV5G_PMAC_TX_SIZE256TO511_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 256, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE512TO1023_CNT */
+#define DEV5G_PMAC_TX_SIZE512TO1023_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 260, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE1024TO1518_CNT */
+#define DEV5G_PMAC_TX_SIZE1024TO1518_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 264, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE1519TOMAX_CNT */
+#define DEV5G_PMAC_TX_SIZE1519TOMAX_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 268, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_ALIGNMENT_LOST_CNT */
+#define DEV5G_PMAC_RX_ALIGNMENT_LOST_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 272, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:MM_RX_ASSEMBLY_ERR_CNT */
+#define DEV5G_MM_RX_ASSEMBLY_ERR_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 276, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:MM_RX_SMD_ERR_CNT */
+#define DEV5G_MM_RX_SMD_ERR_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 280, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:MM_RX_ASSEMBLY_OK_CNT */
+#define DEV5G_MM_RX_ASSEMBLY_OK_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 284, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:MM_RX_MERGE_FRAG_CNT */
+#define DEV5G_MM_RX_MERGE_FRAG_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 288, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:MM_TX_PFRAGMENT_CNT */
+#define DEV5G_MM_TX_PFRAGMENT_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 292, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_HIH_CKSM_ERR_CNT */
+#define DEV5G_RX_HIH_CKSM_ERR_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 296, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:RX_XGMII_PROT_ERR_CNT */
+#define DEV5G_RX_XGMII_PROT_ERR_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 300, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_HIH_CKSM_ERR_CNT */
+#define DEV5G_PMAC_RX_HIH_CKSM_ERR_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 304, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_XGMII_PROT_ERR_CNT */
+#define DEV5G_PMAC_RX_XGMII_PROT_ERR_CNT(t) __REG(TARGET_DEV5G, t, 13, 60, 0, 1, 312, 308, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_40BIT:RX_IN_BYTES_CNT */
+#define DEV5G_RX_IN_BYTES_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 0, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_40BIT:RX_IN_BYTES_MSB_CNT */
+#define DEV5G_RX_IN_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 4, 0, 1, 4)
+
+#define DEV5G_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT GENMASK(7, 0)
+#define DEV5G_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(DEV5G_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT, x)
+#define DEV5G_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(DEV5G_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT, x)
+
+/* DEV10G:DEV_STATISTICS_40BIT:RX_OK_BYTES_CNT */
+#define DEV5G_RX_OK_BYTES_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 8, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_40BIT:RX_OK_BYTES_MSB_CNT */
+#define DEV5G_RX_OK_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 12, 0, 1, 4)
+
+#define DEV5G_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT GENMASK(7, 0)
+#define DEV5G_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(DEV5G_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT, x)
+#define DEV5G_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(DEV5G_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT, x)
+
+/* DEV10G:DEV_STATISTICS_40BIT:RX_BAD_BYTES_CNT */
+#define DEV5G_RX_BAD_BYTES_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 16, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_40BIT:RX_BAD_BYTES_MSB_CNT */
+#define DEV5G_RX_BAD_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 20, 0, 1, 4)
+
+#define DEV5G_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT GENMASK(7, 0)
+#define DEV5G_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(DEV5G_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT, x)
+#define DEV5G_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(DEV5G_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT, x)
+
+/* DEV10G:DEV_STATISTICS_40BIT:TX_OUT_BYTES_CNT */
+#define DEV5G_TX_OUT_BYTES_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 24, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_40BIT:TX_OUT_BYTES_MSB_CNT */
+#define DEV5G_TX_OUT_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 28, 0, 1, 4)
+
+#define DEV5G_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT GENMASK(7, 0)
+#define DEV5G_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(DEV5G_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT, x)
+#define DEV5G_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(DEV5G_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT, x)
+
+/* DEV10G:DEV_STATISTICS_40BIT:TX_OK_BYTES_CNT */
+#define DEV5G_TX_OK_BYTES_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 32, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_40BIT:TX_OK_BYTES_MSB_CNT */
+#define DEV5G_TX_OK_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 36, 0, 1, 4)
+
+#define DEV5G_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT GENMASK(7, 0)
+#define DEV5G_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(DEV5G_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT, x)
+#define DEV5G_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(DEV5G_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT, x)
+
+/* DEV10G:DEV_STATISTICS_40BIT:PMAC_RX_OK_BYTES_CNT */
+#define DEV5G_PMAC_RX_OK_BYTES_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 40, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_40BIT:PMAC_RX_OK_BYTES_MSB_CNT */
+#define DEV5G_PMAC_RX_OK_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 44, 0, 1, 4)
+
+#define DEV5G_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT GENMASK(7, 0)
+#define DEV5G_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(DEV5G_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT, x)
+#define DEV5G_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(DEV5G_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT, x)
+
+/* DEV10G:DEV_STATISTICS_40BIT:PMAC_RX_BAD_BYTES_CNT */
+#define DEV5G_PMAC_RX_BAD_BYTES_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 48, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_40BIT:PMAC_RX_BAD_BYTES_MSB_CNT */
+#define DEV5G_PMAC_RX_BAD_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 52, 0, 1, 4)
+
+#define DEV5G_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT GENMASK(7, 0)
+#define DEV5G_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(DEV5G_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT, x)
+#define DEV5G_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(DEV5G_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT, x)
+
+/* DEV10G:DEV_STATISTICS_40BIT:PMAC_TX_OK_BYTES_CNT */
+#define DEV5G_PMAC_TX_OK_BYTES_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 56, 0, 1, 4)
+
+/* DEV10G:DEV_STATISTICS_40BIT:PMAC_TX_OK_BYTES_MSB_CNT */
+#define DEV5G_PMAC_TX_OK_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G, t, 13, 372, 0, 1, 64, 60, 0, 1, 4)
+
+#define DEV5G_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT GENMASK(7, 0)
+#define DEV5G_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT_SET(x)\
+ FIELD_PREP(DEV5G_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT, x)
+#define DEV5G_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT_GET(x)\
+ FIELD_GET(DEV5G_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT, x)
+
+/* DEV10G:DEV_CFG_STATUS:DEV_RST_CTRL */
+#define DEV5G_DEV_RST_CTRL(t) __REG(TARGET_DEV5G, t, 13, 436, 0, 1, 52, 0, 0, 1, 4)
+
+#define DEV5G_DEV_RST_CTRL_PARDET_MODE_ENA BIT(28)
+#define DEV5G_DEV_RST_CTRL_PARDET_MODE_ENA_SET(x)\
+ FIELD_PREP(DEV5G_DEV_RST_CTRL_PARDET_MODE_ENA, x)
+#define DEV5G_DEV_RST_CTRL_PARDET_MODE_ENA_GET(x)\
+ FIELD_GET(DEV5G_DEV_RST_CTRL_PARDET_MODE_ENA, x)
+
+#define DEV5G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS BIT(27)
+#define DEV5G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS_SET(x)\
+ FIELD_PREP(DEV5G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS, x)
+#define DEV5G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS_GET(x)\
+ FIELD_GET(DEV5G_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS, x)
+
+#define DEV5G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS GENMASK(26, 25)
+#define DEV5G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS_SET(x)\
+ FIELD_PREP(DEV5G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS, x)
+#define DEV5G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS_GET(x)\
+ FIELD_GET(DEV5G_DEV_RST_CTRL_MUXED_USXGMII_NETWORK_PORTS, x)
+
+#define DEV5G_DEV_RST_CTRL_SERDES_SPEED_SEL GENMASK(24, 23)
+#define DEV5G_DEV_RST_CTRL_SERDES_SPEED_SEL_SET(x)\
+ FIELD_PREP(DEV5G_DEV_RST_CTRL_SERDES_SPEED_SEL, x)
+#define DEV5G_DEV_RST_CTRL_SERDES_SPEED_SEL_GET(x)\
+ FIELD_GET(DEV5G_DEV_RST_CTRL_SERDES_SPEED_SEL, x)
+
+#define DEV5G_DEV_RST_CTRL_SPEED_SEL GENMASK(22, 20)
+#define DEV5G_DEV_RST_CTRL_SPEED_SEL_SET(x)\
+ FIELD_PREP(DEV5G_DEV_RST_CTRL_SPEED_SEL, x)
+#define DEV5G_DEV_RST_CTRL_SPEED_SEL_GET(x)\
+ FIELD_GET(DEV5G_DEV_RST_CTRL_SPEED_SEL, x)
+
+#define DEV5G_DEV_RST_CTRL_PCS_TX_RST BIT(12)
+#define DEV5G_DEV_RST_CTRL_PCS_TX_RST_SET(x)\
+ FIELD_PREP(DEV5G_DEV_RST_CTRL_PCS_TX_RST, x)
+#define DEV5G_DEV_RST_CTRL_PCS_TX_RST_GET(x)\
+ FIELD_GET(DEV5G_DEV_RST_CTRL_PCS_TX_RST, x)
+
+#define DEV5G_DEV_RST_CTRL_PCS_RX_RST BIT(8)
+#define DEV5G_DEV_RST_CTRL_PCS_RX_RST_SET(x)\
+ FIELD_PREP(DEV5G_DEV_RST_CTRL_PCS_RX_RST, x)
+#define DEV5G_DEV_RST_CTRL_PCS_RX_RST_GET(x)\
+ FIELD_GET(DEV5G_DEV_RST_CTRL_PCS_RX_RST, x)
+
+#define DEV5G_DEV_RST_CTRL_MAC_TX_RST BIT(4)
+#define DEV5G_DEV_RST_CTRL_MAC_TX_RST_SET(x)\
+ FIELD_PREP(DEV5G_DEV_RST_CTRL_MAC_TX_RST, x)
+#define DEV5G_DEV_RST_CTRL_MAC_TX_RST_GET(x)\
+ FIELD_GET(DEV5G_DEV_RST_CTRL_MAC_TX_RST, x)
+
+#define DEV5G_DEV_RST_CTRL_MAC_RX_RST BIT(0)
+#define DEV5G_DEV_RST_CTRL_MAC_RX_RST_SET(x)\
+ FIELD_PREP(DEV5G_DEV_RST_CTRL_MAC_RX_RST, x)
+#define DEV5G_DEV_RST_CTRL_MAC_RX_RST_GET(x)\
+ FIELD_GET(DEV5G_DEV_RST_CTRL_MAC_RX_RST, x)
+
+/* DSM:RAM_CTRL:RAM_INIT */
+#define DSM_RAM_INIT __REG(TARGET_DSM, 0, 1, 0, 0, 1, 4, 0, 0, 1, 4)
+
+#define DSM_RAM_INIT_RAM_INIT BIT(1)
+#define DSM_RAM_INIT_RAM_INIT_SET(x)\
+ FIELD_PREP(DSM_RAM_INIT_RAM_INIT, x)
+#define DSM_RAM_INIT_RAM_INIT_GET(x)\
+ FIELD_GET(DSM_RAM_INIT_RAM_INIT, x)
+
+#define DSM_RAM_INIT_RAM_CFG_HOOK BIT(0)
+#define DSM_RAM_INIT_RAM_CFG_HOOK_SET(x)\
+ FIELD_PREP(DSM_RAM_INIT_RAM_CFG_HOOK, x)
+#define DSM_RAM_INIT_RAM_CFG_HOOK_GET(x)\
+ FIELD_GET(DSM_RAM_INIT_RAM_CFG_HOOK, x)
+
+/* DSM:CFG:BUF_CFG */
+#define DSM_BUF_CFG(r) __REG(TARGET_DSM, 0, 1, 20, 0, 1, 3528, 0, r, 67, 4)
+
+#define DSM_BUF_CFG_CSC_STAT_DIS BIT(13)
+#define DSM_BUF_CFG_CSC_STAT_DIS_SET(x)\
+ FIELD_PREP(DSM_BUF_CFG_CSC_STAT_DIS, x)
+#define DSM_BUF_CFG_CSC_STAT_DIS_GET(x)\
+ FIELD_GET(DSM_BUF_CFG_CSC_STAT_DIS, x)
+
+#define DSM_BUF_CFG_AGING_ENA BIT(12)
+#define DSM_BUF_CFG_AGING_ENA_SET(x)\
+ FIELD_PREP(DSM_BUF_CFG_AGING_ENA, x)
+#define DSM_BUF_CFG_AGING_ENA_GET(x)\
+ FIELD_GET(DSM_BUF_CFG_AGING_ENA, x)
+
+#define DSM_BUF_CFG_UNDERFLOW_WATCHDOG_DIS BIT(11)
+#define DSM_BUF_CFG_UNDERFLOW_WATCHDOG_DIS_SET(x)\
+ FIELD_PREP(DSM_BUF_CFG_UNDERFLOW_WATCHDOG_DIS, x)
+#define DSM_BUF_CFG_UNDERFLOW_WATCHDOG_DIS_GET(x)\
+ FIELD_GET(DSM_BUF_CFG_UNDERFLOW_WATCHDOG_DIS, x)
+
+#define DSM_BUF_CFG_UNDERFLOW_WATCHDOG_TIMEOUT GENMASK(10, 0)
+#define DSM_BUF_CFG_UNDERFLOW_WATCHDOG_TIMEOUT_SET(x)\
+ FIELD_PREP(DSM_BUF_CFG_UNDERFLOW_WATCHDOG_TIMEOUT, x)
+#define DSM_BUF_CFG_UNDERFLOW_WATCHDOG_TIMEOUT_GET(x)\
+ FIELD_GET(DSM_BUF_CFG_UNDERFLOW_WATCHDOG_TIMEOUT, x)
+
+/* DSM:CFG:DEV_TX_STOP_WM_CFG */
+#define DSM_DEV_TX_STOP_WM_CFG(r) __REG(TARGET_DSM, 0, 1, 20, 0, 1, 3528, 1360, r, 67, 4)
+
+#define DSM_DEV_TX_STOP_WM_CFG_FAST_STARTUP_ENA BIT(9)
+#define DSM_DEV_TX_STOP_WM_CFG_FAST_STARTUP_ENA_SET(x)\
+ FIELD_PREP(DSM_DEV_TX_STOP_WM_CFG_FAST_STARTUP_ENA, x)
+#define DSM_DEV_TX_STOP_WM_CFG_FAST_STARTUP_ENA_GET(x)\
+ FIELD_GET(DSM_DEV_TX_STOP_WM_CFG_FAST_STARTUP_ENA, x)
+
+#define DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA BIT(8)
+#define DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA_SET(x)\
+ FIELD_PREP(DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA, x)
+#define DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA_GET(x)\
+ FIELD_GET(DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA, x)
+
+#define DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM GENMASK(7, 1)
+#define DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM_SET(x)\
+ FIELD_PREP(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM, x)
+#define DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM_GET(x)\
+ FIELD_GET(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM, x)
+
+#define DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR BIT(0)
+#define DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR_SET(x)\
+ FIELD_PREP(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR, x)
+#define DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR_GET(x)\
+ FIELD_GET(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR, x)
+
+/* DSM:CFG:RX_PAUSE_CFG */
+#define DSM_RX_PAUSE_CFG(r) __REG(TARGET_DSM, 0, 1, 20, 0, 1, 3528, 1628, r, 67, 4)
+
+#define DSM_RX_PAUSE_CFG_RX_PAUSE_EN BIT(1)
+#define DSM_RX_PAUSE_CFG_RX_PAUSE_EN_SET(x)\
+ FIELD_PREP(DSM_RX_PAUSE_CFG_RX_PAUSE_EN, x)
+#define DSM_RX_PAUSE_CFG_RX_PAUSE_EN_GET(x)\
+ FIELD_GET(DSM_RX_PAUSE_CFG_RX_PAUSE_EN, x)
+
+#define DSM_RX_PAUSE_CFG_FC_OBEY_LOCAL BIT(0)
+#define DSM_RX_PAUSE_CFG_FC_OBEY_LOCAL_SET(x)\
+ FIELD_PREP(DSM_RX_PAUSE_CFG_FC_OBEY_LOCAL, x)
+#define DSM_RX_PAUSE_CFG_FC_OBEY_LOCAL_GET(x)\
+ FIELD_GET(DSM_RX_PAUSE_CFG_FC_OBEY_LOCAL, x)
+
+/* DSM:CFG:MAC_CFG */
+#define DSM_MAC_CFG(r) __REG(TARGET_DSM, 0, 1, 20, 0, 1, 3528, 2432, r, 67, 4)
+
+#define DSM_MAC_CFG_TX_PAUSE_VAL GENMASK(31, 16)
+#define DSM_MAC_CFG_TX_PAUSE_VAL_SET(x)\
+ FIELD_PREP(DSM_MAC_CFG_TX_PAUSE_VAL, x)
+#define DSM_MAC_CFG_TX_PAUSE_VAL_GET(x)\
+ FIELD_GET(DSM_MAC_CFG_TX_PAUSE_VAL, x)
+
+#define DSM_MAC_CFG_HDX_BACKPREASSURE BIT(2)
+#define DSM_MAC_CFG_HDX_BACKPREASSURE_SET(x)\
+ FIELD_PREP(DSM_MAC_CFG_HDX_BACKPREASSURE, x)
+#define DSM_MAC_CFG_HDX_BACKPREASSURE_GET(x)\
+ FIELD_GET(DSM_MAC_CFG_HDX_BACKPREASSURE, x)
+
+#define DSM_MAC_CFG_SEND_PAUSE_FRM_TWICE BIT(1)
+#define DSM_MAC_CFG_SEND_PAUSE_FRM_TWICE_SET(x)\
+ FIELD_PREP(DSM_MAC_CFG_SEND_PAUSE_FRM_TWICE, x)
+#define DSM_MAC_CFG_SEND_PAUSE_FRM_TWICE_GET(x)\
+ FIELD_GET(DSM_MAC_CFG_SEND_PAUSE_FRM_TWICE, x)
+
+#define DSM_MAC_CFG_TX_PAUSE_XON_XOFF BIT(0)
+#define DSM_MAC_CFG_TX_PAUSE_XON_XOFF_SET(x)\
+ FIELD_PREP(DSM_MAC_CFG_TX_PAUSE_XON_XOFF, x)
+#define DSM_MAC_CFG_TX_PAUSE_XON_XOFF_GET(x)\
+ FIELD_GET(DSM_MAC_CFG_TX_PAUSE_XON_XOFF, x)
+
+/* DSM:CFG:MAC_ADDR_BASE_HIGH_CFG */
+#define DSM_MAC_ADDR_BASE_HIGH_CFG(r) __REG(TARGET_DSM, 0, 1, 20, 0, 1, 3528, 2700, r, 65, 4)
+
+#define DSM_MAC_ADDR_BASE_HIGH_CFG_MAC_ADDR_HIGH GENMASK(23, 0)
+#define DSM_MAC_ADDR_BASE_HIGH_CFG_MAC_ADDR_HIGH_SET(x)\
+ FIELD_PREP(DSM_MAC_ADDR_BASE_HIGH_CFG_MAC_ADDR_HIGH, x)
+#define DSM_MAC_ADDR_BASE_HIGH_CFG_MAC_ADDR_HIGH_GET(x)\
+ FIELD_GET(DSM_MAC_ADDR_BASE_HIGH_CFG_MAC_ADDR_HIGH, x)
+
+/* DSM:CFG:MAC_ADDR_BASE_LOW_CFG */
+#define DSM_MAC_ADDR_BASE_LOW_CFG(r) __REG(TARGET_DSM, 0, 1, 20, 0, 1, 3528, 2960, r, 65, 4)
+
+#define DSM_MAC_ADDR_BASE_LOW_CFG_MAC_ADDR_LOW GENMASK(23, 0)
+#define DSM_MAC_ADDR_BASE_LOW_CFG_MAC_ADDR_LOW_SET(x)\
+ FIELD_PREP(DSM_MAC_ADDR_BASE_LOW_CFG_MAC_ADDR_LOW, x)
+#define DSM_MAC_ADDR_BASE_LOW_CFG_MAC_ADDR_LOW_GET(x)\
+ FIELD_GET(DSM_MAC_ADDR_BASE_LOW_CFG_MAC_ADDR_LOW, x)
+
+/* DSM:CFG:TAXI_CAL_CFG */
+#define DSM_TAXI_CAL_CFG(r) __REG(TARGET_DSM, 0, 1, 20, 0, 1, 3528, 3224, r, 9, 4)
+
+#define DSM_TAXI_CAL_CFG_CAL_IDX GENMASK(20, 15)
+#define DSM_TAXI_CAL_CFG_CAL_IDX_SET(x)\
+ FIELD_PREP(DSM_TAXI_CAL_CFG_CAL_IDX, x)
+#define DSM_TAXI_CAL_CFG_CAL_IDX_GET(x)\
+ FIELD_GET(DSM_TAXI_CAL_CFG_CAL_IDX, x)
+
+#define DSM_TAXI_CAL_CFG_CAL_CUR_LEN GENMASK(14, 9)
+#define DSM_TAXI_CAL_CFG_CAL_CUR_LEN_SET(x)\
+ FIELD_PREP(DSM_TAXI_CAL_CFG_CAL_CUR_LEN, x)
+#define DSM_TAXI_CAL_CFG_CAL_CUR_LEN_GET(x)\
+ FIELD_GET(DSM_TAXI_CAL_CFG_CAL_CUR_LEN, x)
+
+#define DSM_TAXI_CAL_CFG_CAL_CUR_VAL GENMASK(8, 5)
+#define DSM_TAXI_CAL_CFG_CAL_CUR_VAL_SET(x)\
+ FIELD_PREP(DSM_TAXI_CAL_CFG_CAL_CUR_VAL, x)
+#define DSM_TAXI_CAL_CFG_CAL_CUR_VAL_GET(x)\
+ FIELD_GET(DSM_TAXI_CAL_CFG_CAL_CUR_VAL, x)
+
+#define DSM_TAXI_CAL_CFG_CAL_PGM_VAL GENMASK(4, 1)
+#define DSM_TAXI_CAL_CFG_CAL_PGM_VAL_SET(x)\
+ FIELD_PREP(DSM_TAXI_CAL_CFG_CAL_PGM_VAL, x)
+#define DSM_TAXI_CAL_CFG_CAL_PGM_VAL_GET(x)\
+ FIELD_GET(DSM_TAXI_CAL_CFG_CAL_PGM_VAL, x)
+
+#define DSM_TAXI_CAL_CFG_CAL_PGM_ENA BIT(0)
+#define DSM_TAXI_CAL_CFG_CAL_PGM_ENA_SET(x)\
+ FIELD_PREP(DSM_TAXI_CAL_CFG_CAL_PGM_ENA, x)
+#define DSM_TAXI_CAL_CFG_CAL_PGM_ENA_GET(x)\
+ FIELD_GET(DSM_TAXI_CAL_CFG_CAL_PGM_ENA, x)
+
+/* EACL:POL_CFG:POL_EACL_CFG */
+#define EACL_POL_EACL_CFG __REG(TARGET_EACL, 0, 1, 150608, 0, 1, 780, 768, 0, 1, 4)
+
+#define EACL_POL_EACL_CFG_EACL_CNT_MARKED_AS_DROPPED BIT(5)
+#define EACL_POL_EACL_CFG_EACL_CNT_MARKED_AS_DROPPED_SET(x)\
+ FIELD_PREP(EACL_POL_EACL_CFG_EACL_CNT_MARKED_AS_DROPPED, x)
+#define EACL_POL_EACL_CFG_EACL_CNT_MARKED_AS_DROPPED_GET(x)\
+ FIELD_GET(EACL_POL_EACL_CFG_EACL_CNT_MARKED_AS_DROPPED, x)
+
+#define EACL_POL_EACL_CFG_EACL_ALLOW_FP_COPY BIT(4)
+#define EACL_POL_EACL_CFG_EACL_ALLOW_FP_COPY_SET(x)\
+ FIELD_PREP(EACL_POL_EACL_CFG_EACL_ALLOW_FP_COPY, x)
+#define EACL_POL_EACL_CFG_EACL_ALLOW_FP_COPY_GET(x)\
+ FIELD_GET(EACL_POL_EACL_CFG_EACL_ALLOW_FP_COPY, x)
+
+#define EACL_POL_EACL_CFG_EACL_ALLOW_CPU_COPY BIT(3)
+#define EACL_POL_EACL_CFG_EACL_ALLOW_CPU_COPY_SET(x)\
+ FIELD_PREP(EACL_POL_EACL_CFG_EACL_ALLOW_CPU_COPY, x)
+#define EACL_POL_EACL_CFG_EACL_ALLOW_CPU_COPY_GET(x)\
+ FIELD_GET(EACL_POL_EACL_CFG_EACL_ALLOW_CPU_COPY, x)
+
+#define EACL_POL_EACL_CFG_EACL_FORCE_CLOSE BIT(2)
+#define EACL_POL_EACL_CFG_EACL_FORCE_CLOSE_SET(x)\
+ FIELD_PREP(EACL_POL_EACL_CFG_EACL_FORCE_CLOSE, x)
+#define EACL_POL_EACL_CFG_EACL_FORCE_CLOSE_GET(x)\
+ FIELD_GET(EACL_POL_EACL_CFG_EACL_FORCE_CLOSE, x)
+
+#define EACL_POL_EACL_CFG_EACL_FORCE_OPEN BIT(1)
+#define EACL_POL_EACL_CFG_EACL_FORCE_OPEN_SET(x)\
+ FIELD_PREP(EACL_POL_EACL_CFG_EACL_FORCE_OPEN, x)
+#define EACL_POL_EACL_CFG_EACL_FORCE_OPEN_GET(x)\
+ FIELD_GET(EACL_POL_EACL_CFG_EACL_FORCE_OPEN, x)
+
+#define EACL_POL_EACL_CFG_EACL_FORCE_INIT BIT(0)
+#define EACL_POL_EACL_CFG_EACL_FORCE_INIT_SET(x)\
+ FIELD_PREP(EACL_POL_EACL_CFG_EACL_FORCE_INIT, x)
+#define EACL_POL_EACL_CFG_EACL_FORCE_INIT_GET(x)\
+ FIELD_GET(EACL_POL_EACL_CFG_EACL_FORCE_INIT, x)
+
+/* EACL:RAM_CTRL:RAM_INIT */
+#define EACL_RAM_INIT __REG(TARGET_EACL, 0, 1, 118736, 0, 1, 4, 0, 0, 1, 4)
+
+#define EACL_RAM_INIT_RAM_INIT BIT(1)
+#define EACL_RAM_INIT_RAM_INIT_SET(x)\
+ FIELD_PREP(EACL_RAM_INIT_RAM_INIT, x)
+#define EACL_RAM_INIT_RAM_INIT_GET(x)\
+ FIELD_GET(EACL_RAM_INIT_RAM_INIT, x)
+
+#define EACL_RAM_INIT_RAM_CFG_HOOK BIT(0)
+#define EACL_RAM_INIT_RAM_CFG_HOOK_SET(x)\
+ FIELD_PREP(EACL_RAM_INIT_RAM_CFG_HOOK, x)
+#define EACL_RAM_INIT_RAM_CFG_HOOK_GET(x)\
+ FIELD_GET(EACL_RAM_INIT_RAM_CFG_HOOK, x)
+
+/* FDMA:FDMA:FDMA_CH_ACTIVATE */
+#define FDMA_CH_ACTIVATE __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 0, 0, 1, 4)
+
+#define FDMA_CH_ACTIVATE_CH_ACTIVATE GENMASK(7, 0)
+#define FDMA_CH_ACTIVATE_CH_ACTIVATE_SET(x)\
+ FIELD_PREP(FDMA_CH_ACTIVATE_CH_ACTIVATE, x)
+#define FDMA_CH_ACTIVATE_CH_ACTIVATE_GET(x)\
+ FIELD_GET(FDMA_CH_ACTIVATE_CH_ACTIVATE, x)
+
+/* FDMA:FDMA:FDMA_CH_RELOAD */
+#define FDMA_CH_RELOAD __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 4, 0, 1, 4)
+
+#define FDMA_CH_RELOAD_CH_RELOAD GENMASK(7, 0)
+#define FDMA_CH_RELOAD_CH_RELOAD_SET(x)\
+ FIELD_PREP(FDMA_CH_RELOAD_CH_RELOAD, x)
+#define FDMA_CH_RELOAD_CH_RELOAD_GET(x)\
+ FIELD_GET(FDMA_CH_RELOAD_CH_RELOAD, x)
+
+/* FDMA:FDMA:FDMA_CH_DISABLE */
+#define FDMA_CH_DISABLE __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 8, 0, 1, 4)
+
+#define FDMA_CH_DISABLE_CH_DISABLE GENMASK(7, 0)
+#define FDMA_CH_DISABLE_CH_DISABLE_SET(x)\
+ FIELD_PREP(FDMA_CH_DISABLE_CH_DISABLE, x)
+#define FDMA_CH_DISABLE_CH_DISABLE_GET(x)\
+ FIELD_GET(FDMA_CH_DISABLE_CH_DISABLE, x)
+
+/* FDMA:FDMA:FDMA_DCB_LLP */
+#define FDMA_DCB_LLP(r) __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 52, r, 8, 4)
+
+/* FDMA:FDMA:FDMA_DCB_LLP1 */
+#define FDMA_DCB_LLP1(r) __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 84, r, 8, 4)
+
+/* FDMA:FDMA:FDMA_DCB_LLP_PREV */
+#define FDMA_DCB_LLP_PREV(r) __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 116, r, 8, 4)
+
+/* FDMA:FDMA:FDMA_DCB_LLP_PREV1 */
+#define FDMA_DCB_LLP_PREV1(r) __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 148, r, 8, 4)
+
+/* FDMA:FDMA:FDMA_CH_CFG */
+#define FDMA_CH_CFG(r) __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 224, r, 8, 4)
+
+#define FDMA_CH_CFG_CH_XTR_STATUS_MODE BIT(7)
+#define FDMA_CH_CFG_CH_XTR_STATUS_MODE_SET(x)\
+ FIELD_PREP(FDMA_CH_CFG_CH_XTR_STATUS_MODE, x)
+#define FDMA_CH_CFG_CH_XTR_STATUS_MODE_GET(x)\
+ FIELD_GET(FDMA_CH_CFG_CH_XTR_STATUS_MODE, x)
+
+#define FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY BIT(6)
+#define FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY_SET(x)\
+ FIELD_PREP(FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY, x)
+#define FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY_GET(x)\
+ FIELD_GET(FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY, x)
+
+#define FDMA_CH_CFG_CH_INJ_PORT BIT(5)
+#define FDMA_CH_CFG_CH_INJ_PORT_SET(x)\
+ FIELD_PREP(FDMA_CH_CFG_CH_INJ_PORT, x)
+#define FDMA_CH_CFG_CH_INJ_PORT_GET(x)\
+ FIELD_GET(FDMA_CH_CFG_CH_INJ_PORT, x)
+
+#define FDMA_CH_CFG_CH_DCB_DB_CNT GENMASK(4, 1)
+#define FDMA_CH_CFG_CH_DCB_DB_CNT_SET(x)\
+ FIELD_PREP(FDMA_CH_CFG_CH_DCB_DB_CNT, x)
+#define FDMA_CH_CFG_CH_DCB_DB_CNT_GET(x)\
+ FIELD_GET(FDMA_CH_CFG_CH_DCB_DB_CNT, x)
+
+#define FDMA_CH_CFG_CH_MEM BIT(0)
+#define FDMA_CH_CFG_CH_MEM_SET(x)\
+ FIELD_PREP(FDMA_CH_CFG_CH_MEM, x)
+#define FDMA_CH_CFG_CH_MEM_GET(x)\
+ FIELD_GET(FDMA_CH_CFG_CH_MEM, x)
+
+/* FDMA:FDMA:FDMA_CH_TRANSLATE */
+#define FDMA_CH_TRANSLATE(r) __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 256, r, 8, 4)
+
+#define FDMA_CH_TRANSLATE_OFFSET GENMASK(15, 0)
+#define FDMA_CH_TRANSLATE_OFFSET_SET(x)\
+ FIELD_PREP(FDMA_CH_TRANSLATE_OFFSET, x)
+#define FDMA_CH_TRANSLATE_OFFSET_GET(x)\
+ FIELD_GET(FDMA_CH_TRANSLATE_OFFSET, x)
+
+/* FDMA:FDMA:FDMA_XTR_CFG */
+#define FDMA_XTR_CFG __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 364, 0, 1, 4)
+
+#define FDMA_XTR_CFG_XTR_FIFO_WM GENMASK(15, 11)
+#define FDMA_XTR_CFG_XTR_FIFO_WM_SET(x)\
+ FIELD_PREP(FDMA_XTR_CFG_XTR_FIFO_WM, x)
+#define FDMA_XTR_CFG_XTR_FIFO_WM_GET(x)\
+ FIELD_GET(FDMA_XTR_CFG_XTR_FIFO_WM, x)
+
+#define FDMA_XTR_CFG_XTR_ARB_SAT GENMASK(10, 0)
+#define FDMA_XTR_CFG_XTR_ARB_SAT_SET(x)\
+ FIELD_PREP(FDMA_XTR_CFG_XTR_ARB_SAT, x)
+#define FDMA_XTR_CFG_XTR_ARB_SAT_GET(x)\
+ FIELD_GET(FDMA_XTR_CFG_XTR_ARB_SAT, x)
+
+/* FDMA:FDMA:FDMA_PORT_CTRL */
+#define FDMA_PORT_CTRL(r) __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 376, r, 2, 4)
+
+#define FDMA_PORT_CTRL_INJ_STOP BIT(4)
+#define FDMA_PORT_CTRL_INJ_STOP_SET(x)\
+ FIELD_PREP(FDMA_PORT_CTRL_INJ_STOP, x)
+#define FDMA_PORT_CTRL_INJ_STOP_GET(x)\
+ FIELD_GET(FDMA_PORT_CTRL_INJ_STOP, x)
+
+#define FDMA_PORT_CTRL_INJ_STOP_FORCE BIT(3)
+#define FDMA_PORT_CTRL_INJ_STOP_FORCE_SET(x)\
+ FIELD_PREP(FDMA_PORT_CTRL_INJ_STOP_FORCE, x)
+#define FDMA_PORT_CTRL_INJ_STOP_FORCE_GET(x)\
+ FIELD_GET(FDMA_PORT_CTRL_INJ_STOP_FORCE, x)
+
+#define FDMA_PORT_CTRL_XTR_STOP BIT(2)
+#define FDMA_PORT_CTRL_XTR_STOP_SET(x)\
+ FIELD_PREP(FDMA_PORT_CTRL_XTR_STOP, x)
+#define FDMA_PORT_CTRL_XTR_STOP_GET(x)\
+ FIELD_GET(FDMA_PORT_CTRL_XTR_STOP, x)
+
+#define FDMA_PORT_CTRL_XTR_BUF_IS_EMPTY BIT(1)
+#define FDMA_PORT_CTRL_XTR_BUF_IS_EMPTY_SET(x)\
+ FIELD_PREP(FDMA_PORT_CTRL_XTR_BUF_IS_EMPTY, x)
+#define FDMA_PORT_CTRL_XTR_BUF_IS_EMPTY_GET(x)\
+ FIELD_GET(FDMA_PORT_CTRL_XTR_BUF_IS_EMPTY, x)
+
+#define FDMA_PORT_CTRL_XTR_BUF_RST BIT(0)
+#define FDMA_PORT_CTRL_XTR_BUF_RST_SET(x)\
+ FIELD_PREP(FDMA_PORT_CTRL_XTR_BUF_RST, x)
+#define FDMA_PORT_CTRL_XTR_BUF_RST_GET(x)\
+ FIELD_GET(FDMA_PORT_CTRL_XTR_BUF_RST, x)
+
+/* FDMA:FDMA:FDMA_INTR_DCB */
+#define FDMA_INTR_DCB __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 384, 0, 1, 4)
+
+#define FDMA_INTR_DCB_INTR_DCB GENMASK(7, 0)
+#define FDMA_INTR_DCB_INTR_DCB_SET(x)\
+ FIELD_PREP(FDMA_INTR_DCB_INTR_DCB, x)
+#define FDMA_INTR_DCB_INTR_DCB_GET(x)\
+ FIELD_GET(FDMA_INTR_DCB_INTR_DCB, x)
+
+/* FDMA:FDMA:FDMA_INTR_DCB_ENA */
+#define FDMA_INTR_DCB_ENA __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 388, 0, 1, 4)
+
+#define FDMA_INTR_DCB_ENA_INTR_DCB_ENA GENMASK(7, 0)
+#define FDMA_INTR_DCB_ENA_INTR_DCB_ENA_SET(x)\
+ FIELD_PREP(FDMA_INTR_DCB_ENA_INTR_DCB_ENA, x)
+#define FDMA_INTR_DCB_ENA_INTR_DCB_ENA_GET(x)\
+ FIELD_GET(FDMA_INTR_DCB_ENA_INTR_DCB_ENA, x)
+
+/* FDMA:FDMA:FDMA_INTR_DB */
+#define FDMA_INTR_DB __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 392, 0, 1, 4)
+
+#define FDMA_INTR_DB_INTR_DB GENMASK(7, 0)
+#define FDMA_INTR_DB_INTR_DB_SET(x)\
+ FIELD_PREP(FDMA_INTR_DB_INTR_DB, x)
+#define FDMA_INTR_DB_INTR_DB_GET(x)\
+ FIELD_GET(FDMA_INTR_DB_INTR_DB, x)
+
+/* FDMA:FDMA:FDMA_INTR_DB_ENA */
+#define FDMA_INTR_DB_ENA __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 396, 0, 1, 4)
+
+#define FDMA_INTR_DB_ENA_INTR_DB_ENA GENMASK(7, 0)
+#define FDMA_INTR_DB_ENA_INTR_DB_ENA_SET(x)\
+ FIELD_PREP(FDMA_INTR_DB_ENA_INTR_DB_ENA, x)
+#define FDMA_INTR_DB_ENA_INTR_DB_ENA_GET(x)\
+ FIELD_GET(FDMA_INTR_DB_ENA_INTR_DB_ENA, x)
+
+/* FDMA:FDMA:FDMA_INTR_ERR */
+#define FDMA_INTR_ERR __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 400, 0, 1, 4)
+
+#define FDMA_INTR_ERR_INTR_PORT_ERR GENMASK(9, 8)
+#define FDMA_INTR_ERR_INTR_PORT_ERR_SET(x)\
+ FIELD_PREP(FDMA_INTR_ERR_INTR_PORT_ERR, x)
+#define FDMA_INTR_ERR_INTR_PORT_ERR_GET(x)\
+ FIELD_GET(FDMA_INTR_ERR_INTR_PORT_ERR, x)
+
+#define FDMA_INTR_ERR_INTR_CH_ERR GENMASK(7, 0)
+#define FDMA_INTR_ERR_INTR_CH_ERR_SET(x)\
+ FIELD_PREP(FDMA_INTR_ERR_INTR_CH_ERR, x)
+#define FDMA_INTR_ERR_INTR_CH_ERR_GET(x)\
+ FIELD_GET(FDMA_INTR_ERR_INTR_CH_ERR, x)
+
+/* FDMA:FDMA:FDMA_ERRORS */
+#define FDMA_ERRORS __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 412, 0, 1, 4)
+
+#define FDMA_ERRORS_ERR_XTR_WR GENMASK(31, 30)
+#define FDMA_ERRORS_ERR_XTR_WR_SET(x)\
+ FIELD_PREP(FDMA_ERRORS_ERR_XTR_WR, x)
+#define FDMA_ERRORS_ERR_XTR_WR_GET(x)\
+ FIELD_GET(FDMA_ERRORS_ERR_XTR_WR, x)
+
+#define FDMA_ERRORS_ERR_XTR_OVF GENMASK(29, 28)
+#define FDMA_ERRORS_ERR_XTR_OVF_SET(x)\
+ FIELD_PREP(FDMA_ERRORS_ERR_XTR_OVF, x)
+#define FDMA_ERRORS_ERR_XTR_OVF_GET(x)\
+ FIELD_GET(FDMA_ERRORS_ERR_XTR_OVF, x)
+
+#define FDMA_ERRORS_ERR_XTR_TAXI32_OVF GENMASK(27, 26)
+#define FDMA_ERRORS_ERR_XTR_TAXI32_OVF_SET(x)\
+ FIELD_PREP(FDMA_ERRORS_ERR_XTR_TAXI32_OVF, x)
+#define FDMA_ERRORS_ERR_XTR_TAXI32_OVF_GET(x)\
+ FIELD_GET(FDMA_ERRORS_ERR_XTR_TAXI32_OVF, x)
+
+#define FDMA_ERRORS_ERR_DCB_XTR_DATAL GENMASK(25, 24)
+#define FDMA_ERRORS_ERR_DCB_XTR_DATAL_SET(x)\
+ FIELD_PREP(FDMA_ERRORS_ERR_DCB_XTR_DATAL, x)
+#define FDMA_ERRORS_ERR_DCB_XTR_DATAL_GET(x)\
+ FIELD_GET(FDMA_ERRORS_ERR_DCB_XTR_DATAL, x)
+
+#define FDMA_ERRORS_ERR_DCB_RD GENMASK(23, 16)
+#define FDMA_ERRORS_ERR_DCB_RD_SET(x)\
+ FIELD_PREP(FDMA_ERRORS_ERR_DCB_RD, x)
+#define FDMA_ERRORS_ERR_DCB_RD_GET(x)\
+ FIELD_GET(FDMA_ERRORS_ERR_DCB_RD, x)
+
+#define FDMA_ERRORS_ERR_INJ_RD GENMASK(15, 10)
+#define FDMA_ERRORS_ERR_INJ_RD_SET(x)\
+ FIELD_PREP(FDMA_ERRORS_ERR_INJ_RD, x)
+#define FDMA_ERRORS_ERR_INJ_RD_GET(x)\
+ FIELD_GET(FDMA_ERRORS_ERR_INJ_RD, x)
+
+#define FDMA_ERRORS_ERR_INJ_OUT_OF_SYNC GENMASK(9, 8)
+#define FDMA_ERRORS_ERR_INJ_OUT_OF_SYNC_SET(x)\
+ FIELD_PREP(FDMA_ERRORS_ERR_INJ_OUT_OF_SYNC, x)
+#define FDMA_ERRORS_ERR_INJ_OUT_OF_SYNC_GET(x)\
+ FIELD_GET(FDMA_ERRORS_ERR_INJ_OUT_OF_SYNC, x)
+
+#define FDMA_ERRORS_ERR_CH_WR GENMASK(7, 0)
+#define FDMA_ERRORS_ERR_CH_WR_SET(x)\
+ FIELD_PREP(FDMA_ERRORS_ERR_CH_WR, x)
+#define FDMA_ERRORS_ERR_CH_WR_GET(x)\
+ FIELD_GET(FDMA_ERRORS_ERR_CH_WR, x)
+
+/* FDMA:FDMA:FDMA_ERRORS_2 */
+#define FDMA_ERRORS_2 __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 416, 0, 1, 4)
+
+#define FDMA_ERRORS_2_ERR_XTR_FRAG GENMASK(1, 0)
+#define FDMA_ERRORS_2_ERR_XTR_FRAG_SET(x)\
+ FIELD_PREP(FDMA_ERRORS_2_ERR_XTR_FRAG, x)
+#define FDMA_ERRORS_2_ERR_XTR_FRAG_GET(x)\
+ FIELD_GET(FDMA_ERRORS_2_ERR_XTR_FRAG, x)
+
+/* FDMA:FDMA:FDMA_CTRL */
+#define FDMA_CTRL __REG(TARGET_FDMA, 0, 1, 8, 0, 1, 428, 424, 0, 1, 4)
+
+#define FDMA_CTRL_NRESET BIT(0)
+#define FDMA_CTRL_NRESET_SET(x)\
+ FIELD_PREP(FDMA_CTRL_NRESET, x)
+#define FDMA_CTRL_NRESET_GET(x)\
+ FIELD_GET(FDMA_CTRL_NRESET, x)
+
+/* DEVCPU_GCB:CHIP_REGS:CHIP_ID */
+#define GCB_CHIP_ID __REG(TARGET_GCB, 0, 1, 0, 0, 1, 424, 0, 0, 1, 4)
+
+#define GCB_CHIP_ID_REV_ID GENMASK(31, 28)
+#define GCB_CHIP_ID_REV_ID_SET(x)\
+ FIELD_PREP(GCB_CHIP_ID_REV_ID, x)
+#define GCB_CHIP_ID_REV_ID_GET(x)\
+ FIELD_GET(GCB_CHIP_ID_REV_ID, x)
+
+#define GCB_CHIP_ID_PART_ID GENMASK(27, 12)
+#define GCB_CHIP_ID_PART_ID_SET(x)\
+ FIELD_PREP(GCB_CHIP_ID_PART_ID, x)
+#define GCB_CHIP_ID_PART_ID_GET(x)\
+ FIELD_GET(GCB_CHIP_ID_PART_ID, x)
+
+#define GCB_CHIP_ID_MFG_ID GENMASK(11, 1)
+#define GCB_CHIP_ID_MFG_ID_SET(x)\
+ FIELD_PREP(GCB_CHIP_ID_MFG_ID, x)
+#define GCB_CHIP_ID_MFG_ID_GET(x)\
+ FIELD_GET(GCB_CHIP_ID_MFG_ID, x)
+
+#define GCB_CHIP_ID_ONE BIT(0)
+#define GCB_CHIP_ID_ONE_SET(x)\
+ FIELD_PREP(GCB_CHIP_ID_ONE, x)
+#define GCB_CHIP_ID_ONE_GET(x)\
+ FIELD_GET(GCB_CHIP_ID_ONE, x)
+
+/* DEVCPU_GCB:CHIP_REGS:SOFT_RST */
+#define GCB_SOFT_RST __REG(TARGET_GCB, 0, 1, 0, 0, 1, 424, 8, 0, 1, 4)
+
+#define GCB_SOFT_RST_SOFT_NON_CFG_RST BIT(2)
+#define GCB_SOFT_RST_SOFT_NON_CFG_RST_SET(x)\
+ FIELD_PREP(GCB_SOFT_RST_SOFT_NON_CFG_RST, x)
+#define GCB_SOFT_RST_SOFT_NON_CFG_RST_GET(x)\
+ FIELD_GET(GCB_SOFT_RST_SOFT_NON_CFG_RST, x)
+
+#define GCB_SOFT_RST_SOFT_SWC_RST BIT(1)
+#define GCB_SOFT_RST_SOFT_SWC_RST_SET(x)\
+ FIELD_PREP(GCB_SOFT_RST_SOFT_SWC_RST, x)
+#define GCB_SOFT_RST_SOFT_SWC_RST_GET(x)\
+ FIELD_GET(GCB_SOFT_RST_SOFT_SWC_RST, x)
+
+#define GCB_SOFT_RST_SOFT_CHIP_RST BIT(0)
+#define GCB_SOFT_RST_SOFT_CHIP_RST_SET(x)\
+ FIELD_PREP(GCB_SOFT_RST_SOFT_CHIP_RST, x)
+#define GCB_SOFT_RST_SOFT_CHIP_RST_GET(x)\
+ FIELD_GET(GCB_SOFT_RST_SOFT_CHIP_RST, x)
+
+/* DEVCPU_GCB:CHIP_REGS:HW_SGPIO_SD_CFG */
+#define GCB_HW_SGPIO_SD_CFG __REG(TARGET_GCB, 0, 1, 0, 0, 1, 424, 20, 0, 1, 4)
+
+#define GCB_HW_SGPIO_SD_CFG_SD_HIGH_ENA BIT(1)
+#define GCB_HW_SGPIO_SD_CFG_SD_HIGH_ENA_SET(x)\
+ FIELD_PREP(GCB_HW_SGPIO_SD_CFG_SD_HIGH_ENA, x)
+#define GCB_HW_SGPIO_SD_CFG_SD_HIGH_ENA_GET(x)\
+ FIELD_GET(GCB_HW_SGPIO_SD_CFG_SD_HIGH_ENA, x)
+
+#define GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL BIT(0)
+#define GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL_SET(x)\
+ FIELD_PREP(GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL, x)
+#define GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL_GET(x)\
+ FIELD_GET(GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL, x)
+
+/* DEVCPU_GCB:CHIP_REGS:HW_SGPIO_TO_SD_MAP_CFG */
+#define GCB_HW_SGPIO_TO_SD_MAP_CFG(r) __REG(TARGET_GCB, 0, 1, 0, 0, 1, 424, 24, r, 65, 4)
+
+#define GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL GENMASK(8, 0)
+#define GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL_SET(x)\
+ FIELD_PREP(GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL, x)
+#define GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL_GET(x)\
+ FIELD_GET(GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL, x)
+
+/* DEVCPU_GCB:SIO_CTRL:SIO_CLOCK */
+#define GCB_SIO_CLOCK(g) __REG(TARGET_GCB, 0, 1, 876, g, 3, 280, 20, 0, 1, 4)
+
+#define GCB_SIO_CLOCK_SIO_CLK_FREQ GENMASK(19, 8)
+#define GCB_SIO_CLOCK_SIO_CLK_FREQ_SET(x)\
+ FIELD_PREP(GCB_SIO_CLOCK_SIO_CLK_FREQ, x)
+#define GCB_SIO_CLOCK_SIO_CLK_FREQ_GET(x)\
+ FIELD_GET(GCB_SIO_CLOCK_SIO_CLK_FREQ, x)
+
+#define GCB_SIO_CLOCK_SYS_CLK_PERIOD GENMASK(7, 0)
+#define GCB_SIO_CLOCK_SYS_CLK_PERIOD_SET(x)\
+ FIELD_PREP(GCB_SIO_CLOCK_SYS_CLK_PERIOD, x)
+#define GCB_SIO_CLOCK_SYS_CLK_PERIOD_GET(x)\
+ FIELD_GET(GCB_SIO_CLOCK_SYS_CLK_PERIOD, x)
+
+/* HSCH:HSCH_MISC:SYS_CLK_PER */
+#define HSCH_SYS_CLK_PER __REG(TARGET_HSCH, 0, 1, 163104, 0, 1, 648, 640, 0, 1, 4)
+
+#define HSCH_SYS_CLK_PER_SYS_CLK_PER_100PS GENMASK(7, 0)
+#define HSCH_SYS_CLK_PER_SYS_CLK_PER_100PS_SET(x)\
+ FIELD_PREP(HSCH_SYS_CLK_PER_SYS_CLK_PER_100PS, x)
+#define HSCH_SYS_CLK_PER_SYS_CLK_PER_100PS_GET(x)\
+ FIELD_GET(HSCH_SYS_CLK_PER_SYS_CLK_PER_100PS, x)
+
+/* HSCH:SYSTEM:FLUSH_CTRL */
+#define HSCH_FLUSH_CTRL __REG(TARGET_HSCH, 0, 1, 184000, 0, 1, 312, 4, 0, 1, 4)
+
+#define HSCH_FLUSH_CTRL_FLUSH_ENA BIT(27)
+#define HSCH_FLUSH_CTRL_FLUSH_ENA_SET(x)\
+ FIELD_PREP(HSCH_FLUSH_CTRL_FLUSH_ENA, x)
+#define HSCH_FLUSH_CTRL_FLUSH_ENA_GET(x)\
+ FIELD_GET(HSCH_FLUSH_CTRL_FLUSH_ENA, x)
+
+#define HSCH_FLUSH_CTRL_FLUSH_SRC BIT(26)
+#define HSCH_FLUSH_CTRL_FLUSH_SRC_SET(x)\
+ FIELD_PREP(HSCH_FLUSH_CTRL_FLUSH_SRC, x)
+#define HSCH_FLUSH_CTRL_FLUSH_SRC_GET(x)\
+ FIELD_GET(HSCH_FLUSH_CTRL_FLUSH_SRC, x)
+
+#define HSCH_FLUSH_CTRL_FLUSH_DST BIT(25)
+#define HSCH_FLUSH_CTRL_FLUSH_DST_SET(x)\
+ FIELD_PREP(HSCH_FLUSH_CTRL_FLUSH_DST, x)
+#define HSCH_FLUSH_CTRL_FLUSH_DST_GET(x)\
+ FIELD_GET(HSCH_FLUSH_CTRL_FLUSH_DST, x)
+
+#define HSCH_FLUSH_CTRL_FLUSH_PORT GENMASK(24, 18)
+#define HSCH_FLUSH_CTRL_FLUSH_PORT_SET(x)\
+ FIELD_PREP(HSCH_FLUSH_CTRL_FLUSH_PORT, x)
+#define HSCH_FLUSH_CTRL_FLUSH_PORT_GET(x)\
+ FIELD_GET(HSCH_FLUSH_CTRL_FLUSH_PORT, x)
+
+#define HSCH_FLUSH_CTRL_FLUSH_QUEUE BIT(17)
+#define HSCH_FLUSH_CTRL_FLUSH_QUEUE_SET(x)\
+ FIELD_PREP(HSCH_FLUSH_CTRL_FLUSH_QUEUE, x)
+#define HSCH_FLUSH_CTRL_FLUSH_QUEUE_GET(x)\
+ FIELD_GET(HSCH_FLUSH_CTRL_FLUSH_QUEUE, x)
+
+#define HSCH_FLUSH_CTRL_FLUSH_SE BIT(16)
+#define HSCH_FLUSH_CTRL_FLUSH_SE_SET(x)\
+ FIELD_PREP(HSCH_FLUSH_CTRL_FLUSH_SE, x)
+#define HSCH_FLUSH_CTRL_FLUSH_SE_GET(x)\
+ FIELD_GET(HSCH_FLUSH_CTRL_FLUSH_SE, x)
+
+#define HSCH_FLUSH_CTRL_FLUSH_HIER GENMASK(15, 0)
+#define HSCH_FLUSH_CTRL_FLUSH_HIER_SET(x)\
+ FIELD_PREP(HSCH_FLUSH_CTRL_FLUSH_HIER, x)
+#define HSCH_FLUSH_CTRL_FLUSH_HIER_GET(x)\
+ FIELD_GET(HSCH_FLUSH_CTRL_FLUSH_HIER, x)
+
+/* HSCH:SYSTEM:PORT_MODE */
+#define HSCH_PORT_MODE(r) __REG(TARGET_HSCH, 0, 1, 184000, 0, 1, 312, 8, r, 70, 4)
+
+#define HSCH_PORT_MODE_DEQUEUE_DIS BIT(4)
+#define HSCH_PORT_MODE_DEQUEUE_DIS_SET(x)\
+ FIELD_PREP(HSCH_PORT_MODE_DEQUEUE_DIS, x)
+#define HSCH_PORT_MODE_DEQUEUE_DIS_GET(x)\
+ FIELD_GET(HSCH_PORT_MODE_DEQUEUE_DIS, x)
+
+#define HSCH_PORT_MODE_AGE_DIS BIT(3)
+#define HSCH_PORT_MODE_AGE_DIS_SET(x)\
+ FIELD_PREP(HSCH_PORT_MODE_AGE_DIS, x)
+#define HSCH_PORT_MODE_AGE_DIS_GET(x)\
+ FIELD_GET(HSCH_PORT_MODE_AGE_DIS, x)
+
+#define HSCH_PORT_MODE_TRUNC_ENA BIT(2)
+#define HSCH_PORT_MODE_TRUNC_ENA_SET(x)\
+ FIELD_PREP(HSCH_PORT_MODE_TRUNC_ENA, x)
+#define HSCH_PORT_MODE_TRUNC_ENA_GET(x)\
+ FIELD_GET(HSCH_PORT_MODE_TRUNC_ENA, x)
+
+#define HSCH_PORT_MODE_EIR_REMARK_ENA BIT(1)
+#define HSCH_PORT_MODE_EIR_REMARK_ENA_SET(x)\
+ FIELD_PREP(HSCH_PORT_MODE_EIR_REMARK_ENA, x)
+#define HSCH_PORT_MODE_EIR_REMARK_ENA_GET(x)\
+ FIELD_GET(HSCH_PORT_MODE_EIR_REMARK_ENA, x)
+
+#define HSCH_PORT_MODE_CPU_PRIO_MODE BIT(0)
+#define HSCH_PORT_MODE_CPU_PRIO_MODE_SET(x)\
+ FIELD_PREP(HSCH_PORT_MODE_CPU_PRIO_MODE, x)
+#define HSCH_PORT_MODE_CPU_PRIO_MODE_GET(x)\
+ FIELD_GET(HSCH_PORT_MODE_CPU_PRIO_MODE, x)
+
+/* HSCH:SYSTEM:OUTB_SHARE_ENA */
+#define HSCH_OUTB_SHARE_ENA(r) __REG(TARGET_HSCH, 0, 1, 184000, 0, 1, 312, 288, r, 5, 4)
+
+#define HSCH_OUTB_SHARE_ENA_OUTB_SHARE_ENA GENMASK(7, 0)
+#define HSCH_OUTB_SHARE_ENA_OUTB_SHARE_ENA_SET(x)\
+ FIELD_PREP(HSCH_OUTB_SHARE_ENA_OUTB_SHARE_ENA, x)
+#define HSCH_OUTB_SHARE_ENA_OUTB_SHARE_ENA_GET(x)\
+ FIELD_GET(HSCH_OUTB_SHARE_ENA_OUTB_SHARE_ENA, x)
+
+/* HSCH:MMGT:RESET_CFG */
+#define HSCH_RESET_CFG __REG(TARGET_HSCH, 0, 1, 162368, 0, 1, 16, 8, 0, 1, 4)
+
+#define HSCH_RESET_CFG_CORE_ENA BIT(0)
+#define HSCH_RESET_CFG_CORE_ENA_SET(x)\
+ FIELD_PREP(HSCH_RESET_CFG_CORE_ENA, x)
+#define HSCH_RESET_CFG_CORE_ENA_GET(x)\
+ FIELD_GET(HSCH_RESET_CFG_CORE_ENA, x)
+
+/* HSCH:TAS_CONFIG:TAS_STATEMACHINE_CFG */
+#define HSCH_TAS_STATEMACHINE_CFG __REG(TARGET_HSCH, 0, 1, 162384, 0, 1, 12, 8, 0, 1, 4)
+
+#define HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY GENMASK(7, 0)
+#define HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY_SET(x)\
+ FIELD_PREP(HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY, x)
+#define HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY_GET(x)\
+ FIELD_GET(HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY, x)
+
+/* LRN:COMMON:COMMON_ACCESS_CTRL */
+#define LRN_COMMON_ACCESS_CTRL __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 0, 0, 1, 4)
+
+#define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_COL GENMASK(21, 20)
+#define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_COL_SET(x)\
+ FIELD_PREP(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_COL, x)
+#define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_COL_GET(x)\
+ FIELD_GET(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_COL, x)
+
+#define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_TYPE BIT(19)
+#define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_TYPE_SET(x)\
+ FIELD_PREP(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_TYPE, x)
+#define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_TYPE_GET(x)\
+ FIELD_GET(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_TYPE, x)
+
+#define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW GENMASK(18, 5)
+#define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW_SET(x)\
+ FIELD_PREP(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW, x)
+#define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW_GET(x)\
+ FIELD_GET(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW, x)
+
+#define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_CMD GENMASK(4, 1)
+#define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_CMD_SET(x)\
+ FIELD_PREP(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_CMD, x)
+#define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_CMD_GET(x)\
+ FIELD_GET(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_CMD, x)
+
+#define LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT BIT(0)
+#define LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT_SET(x)\
+ FIELD_PREP(LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT, x)
+#define LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT_GET(x)\
+ FIELD_GET(LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT, x)
+
+/* LRN:COMMON:MAC_ACCESS_CFG_0 */
+#define LRN_MAC_ACCESS_CFG_0 __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 4, 0, 1, 4)
+
+#define LRN_MAC_ACCESS_CFG_0_MAC_ENTRY_FID GENMASK(28, 16)
+#define LRN_MAC_ACCESS_CFG_0_MAC_ENTRY_FID_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_0_MAC_ENTRY_FID, x)
+#define LRN_MAC_ACCESS_CFG_0_MAC_ENTRY_FID_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_0_MAC_ENTRY_FID, x)
+
+#define LRN_MAC_ACCESS_CFG_0_MAC_ENTRY_MAC_MSB GENMASK(15, 0)
+#define LRN_MAC_ACCESS_CFG_0_MAC_ENTRY_MAC_MSB_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_0_MAC_ENTRY_MAC_MSB, x)
+#define LRN_MAC_ACCESS_CFG_0_MAC_ENTRY_MAC_MSB_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_0_MAC_ENTRY_MAC_MSB, x)
+
+/* LRN:COMMON:MAC_ACCESS_CFG_1 */
+#define LRN_MAC_ACCESS_CFG_1 __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 8, 0, 1, 4)
+
+/* LRN:COMMON:MAC_ACCESS_CFG_2 */
+#define LRN_MAC_ACCESS_CFG_2 __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 12, 0, 1, 4)
+
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_SRC_KILL_FWD BIT(28)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_SRC_KILL_FWD_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_SRC_KILL_FWD, x)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_SRC_KILL_FWD_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_SRC_KILL_FWD, x)
+
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_NXT_LRN_ALL BIT(27)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_NXT_LRN_ALL_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_NXT_LRN_ALL, x)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_NXT_LRN_ALL_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_NXT_LRN_ALL, x)
+
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_CPU_QU GENMASK(26, 24)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_CPU_QU_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_CPU_QU, x)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_CPU_QU_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_CPU_QU, x)
+
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_CPU_COPY BIT(23)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_CPU_COPY_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_CPU_COPY, x)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_CPU_COPY_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_CPU_COPY, x)
+
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_VLAN_IGNORE BIT(22)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_VLAN_IGNORE_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_VLAN_IGNORE, x)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_VLAN_IGNORE_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_VLAN_IGNORE, x)
+
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_MIRROR BIT(21)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_MIRROR_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_MIRROR, x)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_MIRROR_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_MIRROR, x)
+
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_AGE_FLAG GENMASK(20, 19)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_AGE_FLAG_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_AGE_FLAG, x)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_AGE_FLAG_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_AGE_FLAG, x)
+
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_AGE_INTERVAL GENMASK(18, 17)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_AGE_INTERVAL_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_AGE_INTERVAL, x)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_AGE_INTERVAL_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_AGE_INTERVAL, x)
+
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_LOCKED BIT(16)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_LOCKED_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_LOCKED, x)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_LOCKED_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_LOCKED, x)
+
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_VLD BIT(15)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_VLD_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_VLD, x)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_VLD_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_VLD, x)
+
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_TYPE GENMASK(14, 12)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_TYPE_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_TYPE, x)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_TYPE_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_TYPE, x)
+
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR GENMASK(11, 0)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR, x)
+#define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR, x)
+
+/* LRN:COMMON:MAC_ACCESS_CFG_3 */
+#define LRN_MAC_ACCESS_CFG_3 __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 16, 0, 1, 4)
+
+#define LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX GENMASK(10, 0)
+#define LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX_SET(x)\
+ FIELD_PREP(LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX, x)
+#define LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX_GET(x)\
+ FIELD_GET(LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX, x)
+
+/* LRN:COMMON:SCAN_NEXT_CFG */
+#define LRN_SCAN_NEXT_CFG __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 20, 0, 1, 4)
+
+#define LRN_SCAN_NEXT_CFG_SCAN_AGE_FLAG_UPDATE_SEL GENMASK(21, 19)
+#define LRN_SCAN_NEXT_CFG_SCAN_AGE_FLAG_UPDATE_SEL_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_SCAN_AGE_FLAG_UPDATE_SEL, x)
+#define LRN_SCAN_NEXT_CFG_SCAN_AGE_FLAG_UPDATE_SEL_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_SCAN_AGE_FLAG_UPDATE_SEL, x)
+
+#define LRN_SCAN_NEXT_CFG_SCAN_NXT_LRN_ALL_UPDATE_SEL GENMASK(18, 17)
+#define LRN_SCAN_NEXT_CFG_SCAN_NXT_LRN_ALL_UPDATE_SEL_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_SCAN_NXT_LRN_ALL_UPDATE_SEL, x)
+#define LRN_SCAN_NEXT_CFG_SCAN_NXT_LRN_ALL_UPDATE_SEL_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_SCAN_NXT_LRN_ALL_UPDATE_SEL, x)
+
+#define LRN_SCAN_NEXT_CFG_SCAN_AGE_FILTER_SEL GENMASK(16, 15)
+#define LRN_SCAN_NEXT_CFG_SCAN_AGE_FILTER_SEL_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_SCAN_AGE_FILTER_SEL, x)
+#define LRN_SCAN_NEXT_CFG_SCAN_AGE_FILTER_SEL_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_SCAN_AGE_FILTER_SEL, x)
+
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_MOVE_FOUND_ENA BIT(14)
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_MOVE_FOUND_ENA_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_SCAN_NEXT_MOVE_FOUND_ENA, x)
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_MOVE_FOUND_ENA_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_SCAN_NEXT_MOVE_FOUND_ENA, x)
+
+#define LRN_SCAN_NEXT_CFG_NXT_LRN_ALL_FILTER_ENA BIT(13)
+#define LRN_SCAN_NEXT_CFG_NXT_LRN_ALL_FILTER_ENA_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_NXT_LRN_ALL_FILTER_ENA, x)
+#define LRN_SCAN_NEXT_CFG_NXT_LRN_ALL_FILTER_ENA_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_NXT_LRN_ALL_FILTER_ENA, x)
+
+#define LRN_SCAN_NEXT_CFG_SCAN_USE_PORT_FILTER_ENA BIT(12)
+#define LRN_SCAN_NEXT_CFG_SCAN_USE_PORT_FILTER_ENA_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_SCAN_USE_PORT_FILTER_ENA, x)
+#define LRN_SCAN_NEXT_CFG_SCAN_USE_PORT_FILTER_ENA_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_SCAN_USE_PORT_FILTER_ENA, x)
+
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_REMOVE_FOUND_ENA BIT(11)
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_REMOVE_FOUND_ENA_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_SCAN_NEXT_REMOVE_FOUND_ENA, x)
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_REMOVE_FOUND_ENA_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_SCAN_NEXT_REMOVE_FOUND_ENA, x)
+
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_UNTIL_FOUND_ENA BIT(10)
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_UNTIL_FOUND_ENA_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_SCAN_NEXT_UNTIL_FOUND_ENA, x)
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_UNTIL_FOUND_ENA_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_SCAN_NEXT_UNTIL_FOUND_ENA, x)
+
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_INC_AGE_BITS_ENA BIT(9)
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_INC_AGE_BITS_ENA_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_SCAN_NEXT_INC_AGE_BITS_ENA, x)
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_INC_AGE_BITS_ENA_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_SCAN_NEXT_INC_AGE_BITS_ENA, x)
+
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_AGED_ONLY_ENA BIT(8)
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_AGED_ONLY_ENA_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_SCAN_NEXT_AGED_ONLY_ENA, x)
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_AGED_ONLY_ENA_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_SCAN_NEXT_AGED_ONLY_ENA, x)
+
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_IGNORE_LOCKED_ENA BIT(7)
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_IGNORE_LOCKED_ENA_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_SCAN_NEXT_IGNORE_LOCKED_ENA, x)
+#define LRN_SCAN_NEXT_CFG_SCAN_NEXT_IGNORE_LOCKED_ENA_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_SCAN_NEXT_IGNORE_LOCKED_ENA, x)
+
+#define LRN_SCAN_NEXT_CFG_SCAN_AGE_INTERVAL_MASK GENMASK(6, 3)
+#define LRN_SCAN_NEXT_CFG_SCAN_AGE_INTERVAL_MASK_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_SCAN_AGE_INTERVAL_MASK, x)
+#define LRN_SCAN_NEXT_CFG_SCAN_AGE_INTERVAL_MASK_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_SCAN_AGE_INTERVAL_MASK, x)
+
+#define LRN_SCAN_NEXT_CFG_ISDX_LIMIT_IDX_FILTER_ENA BIT(2)
+#define LRN_SCAN_NEXT_CFG_ISDX_LIMIT_IDX_FILTER_ENA_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_ISDX_LIMIT_IDX_FILTER_ENA, x)
+#define LRN_SCAN_NEXT_CFG_ISDX_LIMIT_IDX_FILTER_ENA_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_ISDX_LIMIT_IDX_FILTER_ENA, x)
+
+#define LRN_SCAN_NEXT_CFG_FID_FILTER_ENA BIT(1)
+#define LRN_SCAN_NEXT_CFG_FID_FILTER_ENA_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_FID_FILTER_ENA, x)
+#define LRN_SCAN_NEXT_CFG_FID_FILTER_ENA_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_FID_FILTER_ENA, x)
+
+#define LRN_SCAN_NEXT_CFG_ADDR_FILTER_ENA BIT(0)
+#define LRN_SCAN_NEXT_CFG_ADDR_FILTER_ENA_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_ADDR_FILTER_ENA, x)
+#define LRN_SCAN_NEXT_CFG_ADDR_FILTER_ENA_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_ADDR_FILTER_ENA, x)
+
+/* LRN:COMMON:SCAN_NEXT_CFG_1 */
+#define LRN_SCAN_NEXT_CFG_1 __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 24, 0, 1, 4)
+
+#define LRN_SCAN_NEXT_CFG_1_PORT_MOVE_NEW_ADDR GENMASK(30, 16)
+#define LRN_SCAN_NEXT_CFG_1_PORT_MOVE_NEW_ADDR_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_1_PORT_MOVE_NEW_ADDR, x)
+#define LRN_SCAN_NEXT_CFG_1_PORT_MOVE_NEW_ADDR_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_1_PORT_MOVE_NEW_ADDR, x)
+
+#define LRN_SCAN_NEXT_CFG_1_SCAN_ENTRY_ADDR_MASK GENMASK(14, 0)
+#define LRN_SCAN_NEXT_CFG_1_SCAN_ENTRY_ADDR_MASK_SET(x)\
+ FIELD_PREP(LRN_SCAN_NEXT_CFG_1_SCAN_ENTRY_ADDR_MASK, x)
+#define LRN_SCAN_NEXT_CFG_1_SCAN_ENTRY_ADDR_MASK_GET(x)\
+ FIELD_GET(LRN_SCAN_NEXT_CFG_1_SCAN_ENTRY_ADDR_MASK, x)
+
+/* LRN:COMMON:AUTOAGE_CFG */
+#define LRN_AUTOAGE_CFG(r) __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 36, r, 4, 4)
+
+#define LRN_AUTOAGE_CFG_UNIT_SIZE GENMASK(29, 28)
+#define LRN_AUTOAGE_CFG_UNIT_SIZE_SET(x)\
+ FIELD_PREP(LRN_AUTOAGE_CFG_UNIT_SIZE, x)
+#define LRN_AUTOAGE_CFG_UNIT_SIZE_GET(x)\
+ FIELD_GET(LRN_AUTOAGE_CFG_UNIT_SIZE, x)
+
+#define LRN_AUTOAGE_CFG_PERIOD_VAL GENMASK(27, 0)
+#define LRN_AUTOAGE_CFG_PERIOD_VAL_SET(x)\
+ FIELD_PREP(LRN_AUTOAGE_CFG_PERIOD_VAL, x)
+#define LRN_AUTOAGE_CFG_PERIOD_VAL_GET(x)\
+ FIELD_GET(LRN_AUTOAGE_CFG_PERIOD_VAL, x)
+
+/* LRN:COMMON:AUTOAGE_CFG_1 */
+#define LRN_AUTOAGE_CFG_1 __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 52, 0, 1, 4)
+
+#define LRN_AUTOAGE_CFG_1_PAUSE_AUTO_AGE_ENA BIT(25)
+#define LRN_AUTOAGE_CFG_1_PAUSE_AUTO_AGE_ENA_SET(x)\
+ FIELD_PREP(LRN_AUTOAGE_CFG_1_PAUSE_AUTO_AGE_ENA, x)
+#define LRN_AUTOAGE_CFG_1_PAUSE_AUTO_AGE_ENA_GET(x)\
+ FIELD_GET(LRN_AUTOAGE_CFG_1_PAUSE_AUTO_AGE_ENA, x)
+
+#define LRN_AUTOAGE_CFG_1_CELLS_BETWEEN_ENTRY_SCAN GENMASK(24, 15)
+#define LRN_AUTOAGE_CFG_1_CELLS_BETWEEN_ENTRY_SCAN_SET(x)\
+ FIELD_PREP(LRN_AUTOAGE_CFG_1_CELLS_BETWEEN_ENTRY_SCAN, x)
+#define LRN_AUTOAGE_CFG_1_CELLS_BETWEEN_ENTRY_SCAN_GET(x)\
+ FIELD_GET(LRN_AUTOAGE_CFG_1_CELLS_BETWEEN_ENTRY_SCAN, x)
+
+#define LRN_AUTOAGE_CFG_1_CLK_PERIOD_01NS GENMASK(14, 7)
+#define LRN_AUTOAGE_CFG_1_CLK_PERIOD_01NS_SET(x)\
+ FIELD_PREP(LRN_AUTOAGE_CFG_1_CLK_PERIOD_01NS, x)
+#define LRN_AUTOAGE_CFG_1_CLK_PERIOD_01NS_GET(x)\
+ FIELD_GET(LRN_AUTOAGE_CFG_1_CLK_PERIOD_01NS, x)
+
+#define LRN_AUTOAGE_CFG_1_USE_PORT_FILTER_ENA BIT(6)
+#define LRN_AUTOAGE_CFG_1_USE_PORT_FILTER_ENA_SET(x)\
+ FIELD_PREP(LRN_AUTOAGE_CFG_1_USE_PORT_FILTER_ENA, x)
+#define LRN_AUTOAGE_CFG_1_USE_PORT_FILTER_ENA_GET(x)\
+ FIELD_GET(LRN_AUTOAGE_CFG_1_USE_PORT_FILTER_ENA, x)
+
+#define LRN_AUTOAGE_CFG_1_FORCE_HW_SCAN_SHOT GENMASK(5, 2)
+#define LRN_AUTOAGE_CFG_1_FORCE_HW_SCAN_SHOT_SET(x)\
+ FIELD_PREP(LRN_AUTOAGE_CFG_1_FORCE_HW_SCAN_SHOT, x)
+#define LRN_AUTOAGE_CFG_1_FORCE_HW_SCAN_SHOT_GET(x)\
+ FIELD_GET(LRN_AUTOAGE_CFG_1_FORCE_HW_SCAN_SHOT, x)
+
+#define LRN_AUTOAGE_CFG_1_FORCE_HW_SCAN_STOP_SHOT BIT(1)
+#define LRN_AUTOAGE_CFG_1_FORCE_HW_SCAN_STOP_SHOT_SET(x)\
+ FIELD_PREP(LRN_AUTOAGE_CFG_1_FORCE_HW_SCAN_STOP_SHOT, x)
+#define LRN_AUTOAGE_CFG_1_FORCE_HW_SCAN_STOP_SHOT_GET(x)\
+ FIELD_GET(LRN_AUTOAGE_CFG_1_FORCE_HW_SCAN_STOP_SHOT, x)
+
+#define LRN_AUTOAGE_CFG_1_FORCE_IDLE_ENA BIT(0)
+#define LRN_AUTOAGE_CFG_1_FORCE_IDLE_ENA_SET(x)\
+ FIELD_PREP(LRN_AUTOAGE_CFG_1_FORCE_IDLE_ENA, x)
+#define LRN_AUTOAGE_CFG_1_FORCE_IDLE_ENA_GET(x)\
+ FIELD_GET(LRN_AUTOAGE_CFG_1_FORCE_IDLE_ENA, x)
+
+/* LRN:COMMON:AUTOAGE_CFG_2 */
+#define LRN_AUTOAGE_CFG_2 __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 56, 0, 1, 4)
+
+#define LRN_AUTOAGE_CFG_2_NEXT_ROW GENMASK(17, 4)
+#define LRN_AUTOAGE_CFG_2_NEXT_ROW_SET(x)\
+ FIELD_PREP(LRN_AUTOAGE_CFG_2_NEXT_ROW, x)
+#define LRN_AUTOAGE_CFG_2_NEXT_ROW_GET(x)\
+ FIELD_GET(LRN_AUTOAGE_CFG_2_NEXT_ROW, x)
+
+#define LRN_AUTOAGE_CFG_2_SCAN_ONGOING_STATUS GENMASK(3, 0)
+#define LRN_AUTOAGE_CFG_2_SCAN_ONGOING_STATUS_SET(x)\
+ FIELD_PREP(LRN_AUTOAGE_CFG_2_SCAN_ONGOING_STATUS, x)
+#define LRN_AUTOAGE_CFG_2_SCAN_ONGOING_STATUS_GET(x)\
+ FIELD_GET(LRN_AUTOAGE_CFG_2_SCAN_ONGOING_STATUS, x)
+
+/* PCIE_DM_EP:PF0_ATU_CAP:IATU_REGION_CTRL_2_OFF_OUTBOUND_0 */
+#define PCEP_RCTRL_2_OUT_0 __REG(TARGET_PCEP, 0, 1, 3145728, 0, 1, 130852, 4, 0, 1, 4)
+
+#define PCEP_RCTRL_2_OUT_0_MSG_CODE GENMASK(7, 0)
+#define PCEP_RCTRL_2_OUT_0_MSG_CODE_SET(x)\
+ FIELD_PREP(PCEP_RCTRL_2_OUT_0_MSG_CODE, x)
+#define PCEP_RCTRL_2_OUT_0_MSG_CODE_GET(x)\
+ FIELD_GET(PCEP_RCTRL_2_OUT_0_MSG_CODE, x)
+
+#define PCEP_RCTRL_2_OUT_0_TAG GENMASK(15, 8)
+#define PCEP_RCTRL_2_OUT_0_TAG_SET(x)\
+ FIELD_PREP(PCEP_RCTRL_2_OUT_0_TAG, x)
+#define PCEP_RCTRL_2_OUT_0_TAG_GET(x)\
+ FIELD_GET(PCEP_RCTRL_2_OUT_0_TAG, x)
+
+#define PCEP_RCTRL_2_OUT_0_TAG_SUBSTITUTE_EN BIT(16)
+#define PCEP_RCTRL_2_OUT_0_TAG_SUBSTITUTE_EN_SET(x)\
+ FIELD_PREP(PCEP_RCTRL_2_OUT_0_TAG_SUBSTITUTE_EN, x)
+#define PCEP_RCTRL_2_OUT_0_TAG_SUBSTITUTE_EN_GET(x)\
+ FIELD_GET(PCEP_RCTRL_2_OUT_0_TAG_SUBSTITUTE_EN, x)
+
+#define PCEP_RCTRL_2_OUT_0_FUNC_BYPASS BIT(19)
+#define PCEP_RCTRL_2_OUT_0_FUNC_BYPASS_SET(x)\
+ FIELD_PREP(PCEP_RCTRL_2_OUT_0_FUNC_BYPASS, x)
+#define PCEP_RCTRL_2_OUT_0_FUNC_BYPASS_GET(x)\
+ FIELD_GET(PCEP_RCTRL_2_OUT_0_FUNC_BYPASS, x)
+
+#define PCEP_RCTRL_2_OUT_0_SNP BIT(20)
+#define PCEP_RCTRL_2_OUT_0_SNP_SET(x)\
+ FIELD_PREP(PCEP_RCTRL_2_OUT_0_SNP, x)
+#define PCEP_RCTRL_2_OUT_0_SNP_GET(x)\
+ FIELD_GET(PCEP_RCTRL_2_OUT_0_SNP, x)
+
+#define PCEP_RCTRL_2_OUT_0_INHIBIT_PAYLOAD BIT(22)
+#define PCEP_RCTRL_2_OUT_0_INHIBIT_PAYLOAD_SET(x)\
+ FIELD_PREP(PCEP_RCTRL_2_OUT_0_INHIBIT_PAYLOAD, x)
+#define PCEP_RCTRL_2_OUT_0_INHIBIT_PAYLOAD_GET(x)\
+ FIELD_GET(PCEP_RCTRL_2_OUT_0_INHIBIT_PAYLOAD, x)
+
+#define PCEP_RCTRL_2_OUT_0_HEADER_SUBSTITUTE_EN BIT(23)
+#define PCEP_RCTRL_2_OUT_0_HEADER_SUBSTITUTE_EN_SET(x)\
+ FIELD_PREP(PCEP_RCTRL_2_OUT_0_HEADER_SUBSTITUTE_EN, x)
+#define PCEP_RCTRL_2_OUT_0_HEADER_SUBSTITUTE_EN_GET(x)\
+ FIELD_GET(PCEP_RCTRL_2_OUT_0_HEADER_SUBSTITUTE_EN, x)
+
+#define PCEP_RCTRL_2_OUT_0_CFG_SHIFT_MODE BIT(28)
+#define PCEP_RCTRL_2_OUT_0_CFG_SHIFT_MODE_SET(x)\
+ FIELD_PREP(PCEP_RCTRL_2_OUT_0_CFG_SHIFT_MODE, x)
+#define PCEP_RCTRL_2_OUT_0_CFG_SHIFT_MODE_GET(x)\
+ FIELD_GET(PCEP_RCTRL_2_OUT_0_CFG_SHIFT_MODE, x)
+
+#define PCEP_RCTRL_2_OUT_0_INVERT_MODE BIT(29)
+#define PCEP_RCTRL_2_OUT_0_INVERT_MODE_SET(x)\
+ FIELD_PREP(PCEP_RCTRL_2_OUT_0_INVERT_MODE, x)
+#define PCEP_RCTRL_2_OUT_0_INVERT_MODE_GET(x)\
+ FIELD_GET(PCEP_RCTRL_2_OUT_0_INVERT_MODE, x)
+
+#define PCEP_RCTRL_2_OUT_0_REGION_EN BIT(31)
+#define PCEP_RCTRL_2_OUT_0_REGION_EN_SET(x)\
+ FIELD_PREP(PCEP_RCTRL_2_OUT_0_REGION_EN, x)
+#define PCEP_RCTRL_2_OUT_0_REGION_EN_GET(x)\
+ FIELD_GET(PCEP_RCTRL_2_OUT_0_REGION_EN, x)
+
+/* PCIE_DM_EP:PF0_ATU_CAP:IATU_LWR_BASE_ADDR_OFF_OUTBOUND_0 */
+#define PCEP_ADDR_LWR_OUT_0 __REG(TARGET_PCEP, 0, 1, 3145728, 0, 1, 130852, 8, 0, 1, 4)
+
+#define PCEP_ADDR_LWR_OUT_0_LWR_BASE_HW GENMASK(15, 0)
+#define PCEP_ADDR_LWR_OUT_0_LWR_BASE_HW_SET(x)\
+ FIELD_PREP(PCEP_ADDR_LWR_OUT_0_LWR_BASE_HW, x)
+#define PCEP_ADDR_LWR_OUT_0_LWR_BASE_HW_GET(x)\
+ FIELD_GET(PCEP_ADDR_LWR_OUT_0_LWR_BASE_HW, x)
+
+#define PCEP_ADDR_LWR_OUT_0_LWR_BASE_RW GENMASK(31, 16)
+#define PCEP_ADDR_LWR_OUT_0_LWR_BASE_RW_SET(x)\
+ FIELD_PREP(PCEP_ADDR_LWR_OUT_0_LWR_BASE_RW, x)
+#define PCEP_ADDR_LWR_OUT_0_LWR_BASE_RW_GET(x)\
+ FIELD_GET(PCEP_ADDR_LWR_OUT_0_LWR_BASE_RW, x)
+
+/* PCIE_DM_EP:PF0_ATU_CAP:IATU_UPPER_BASE_ADDR_OFF_OUTBOUND_0 */
+#define PCEP_ADDR_UPR_OUT_0 __REG(TARGET_PCEP, 0, 1, 3145728, 0, 1, 130852, 12, 0, 1, 4)
+
+/* PCIE_DM_EP:PF0_ATU_CAP:IATU_LIMIT_ADDR_OFF_OUTBOUND_0 */
+#define PCEP_ADDR_LIM_OUT_0 __REG(TARGET_PCEP, 0, 1, 3145728, 0, 1, 130852, 16, 0, 1, 4)
+
+#define PCEP_ADDR_LIM_OUT_0_LIMIT_ADDR_HW GENMASK(15, 0)
+#define PCEP_ADDR_LIM_OUT_0_LIMIT_ADDR_HW_SET(x)\
+ FIELD_PREP(PCEP_ADDR_LIM_OUT_0_LIMIT_ADDR_HW, x)
+#define PCEP_ADDR_LIM_OUT_0_LIMIT_ADDR_HW_GET(x)\
+ FIELD_GET(PCEP_ADDR_LIM_OUT_0_LIMIT_ADDR_HW, x)
+
+#define PCEP_ADDR_LIM_OUT_0_LIMIT_ADDR_RW GENMASK(31, 16)
+#define PCEP_ADDR_LIM_OUT_0_LIMIT_ADDR_RW_SET(x)\
+ FIELD_PREP(PCEP_ADDR_LIM_OUT_0_LIMIT_ADDR_RW, x)
+#define PCEP_ADDR_LIM_OUT_0_LIMIT_ADDR_RW_GET(x)\
+ FIELD_GET(PCEP_ADDR_LIM_OUT_0_LIMIT_ADDR_RW, x)
+
+/* PCIE_DM_EP:PF0_ATU_CAP:IATU_LWR_TARGET_ADDR_OFF_OUTBOUND_0 */
+#define PCEP_ADDR_LWR_TGT_OUT_0 __REG(TARGET_PCEP, 0, 1, 3145728, 0, 1, 130852, 20, 0, 1, 4)
+
+/* PCIE_DM_EP:PF0_ATU_CAP:IATU_UPPER_TARGET_ADDR_OFF_OUTBOUND_0 */
+#define PCEP_ADDR_UPR_TGT_OUT_0 __REG(TARGET_PCEP, 0, 1, 3145728, 0, 1, 130852, 24, 0, 1, 4)
+
+/* PCIE_DM_EP:PF0_ATU_CAP:IATU_UPPR_LIMIT_ADDR_OFF_OUTBOUND_0 */
+#define PCEP_ADDR_UPR_LIM_OUT_0 __REG(TARGET_PCEP, 0, 1, 3145728, 0, 1, 130852, 32, 0, 1, 4)
+
+#define PCEP_ADDR_UPR_LIM_OUT_0_UPPR_LIMIT_ADDR_RW GENMASK(1, 0)
+#define PCEP_ADDR_UPR_LIM_OUT_0_UPPR_LIMIT_ADDR_RW_SET(x)\
+ FIELD_PREP(PCEP_ADDR_UPR_LIM_OUT_0_UPPR_LIMIT_ADDR_RW, x)
+#define PCEP_ADDR_UPR_LIM_OUT_0_UPPR_LIMIT_ADDR_RW_GET(x)\
+ FIELD_GET(PCEP_ADDR_UPR_LIM_OUT_0_UPPR_LIMIT_ADDR_RW, x)
+
+#define PCEP_ADDR_UPR_LIM_OUT_0_UPPR_LIMIT_ADDR_HW GENMASK(31, 2)
+#define PCEP_ADDR_UPR_LIM_OUT_0_UPPR_LIMIT_ADDR_HW_SET(x)\
+ FIELD_PREP(PCEP_ADDR_UPR_LIM_OUT_0_UPPR_LIMIT_ADDR_HW, x)
+#define PCEP_ADDR_UPR_LIM_OUT_0_UPPR_LIMIT_ADDR_HW_GET(x)\
+ FIELD_GET(PCEP_ADDR_UPR_LIM_OUT_0_UPPR_LIMIT_ADDR_HW, x)
+
+/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_CFG */
+#define PCS10G_BR_PCS_CFG(t) __REG(TARGET_PCS10G_BR, t, 12, 0, 0, 1, 56, 0, 0, 1, 4)
+
+#define PCS10G_BR_PCS_CFG_PCS_ENA BIT(31)
+#define PCS10G_BR_PCS_CFG_PCS_ENA_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_CFG_PCS_ENA, x)
+#define PCS10G_BR_PCS_CFG_PCS_ENA_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_CFG_PCS_ENA, x)
+
+#define PCS10G_BR_PCS_CFG_PMA_LOOPBACK_ENA BIT(30)
+#define PCS10G_BR_PCS_CFG_PMA_LOOPBACK_ENA_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_CFG_PMA_LOOPBACK_ENA, x)
+#define PCS10G_BR_PCS_CFG_PMA_LOOPBACK_ENA_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_CFG_PMA_LOOPBACK_ENA, x)
+
+#define PCS10G_BR_PCS_CFG_SH_CNT_MAX GENMASK(29, 24)
+#define PCS10G_BR_PCS_CFG_SH_CNT_MAX_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_CFG_SH_CNT_MAX, x)
+#define PCS10G_BR_PCS_CFG_SH_CNT_MAX_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_CFG_SH_CNT_MAX, x)
+
+#define PCS10G_BR_PCS_CFG_RX_DATA_FLIP BIT(18)
+#define PCS10G_BR_PCS_CFG_RX_DATA_FLIP_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_CFG_RX_DATA_FLIP, x)
+#define PCS10G_BR_PCS_CFG_RX_DATA_FLIP_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_CFG_RX_DATA_FLIP, x)
+
+#define PCS10G_BR_PCS_CFG_RESYNC_ENA BIT(15)
+#define PCS10G_BR_PCS_CFG_RESYNC_ENA_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_CFG_RESYNC_ENA, x)
+#define PCS10G_BR_PCS_CFG_RESYNC_ENA_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_CFG_RESYNC_ENA, x)
+
+#define PCS10G_BR_PCS_CFG_LF_GEN_DIS BIT(14)
+#define PCS10G_BR_PCS_CFG_LF_GEN_DIS_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_CFG_LF_GEN_DIS, x)
+#define PCS10G_BR_PCS_CFG_LF_GEN_DIS_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_CFG_LF_GEN_DIS, x)
+
+#define PCS10G_BR_PCS_CFG_RX_TEST_MODE BIT(13)
+#define PCS10G_BR_PCS_CFG_RX_TEST_MODE_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_CFG_RX_TEST_MODE, x)
+#define PCS10G_BR_PCS_CFG_RX_TEST_MODE_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_CFG_RX_TEST_MODE, x)
+
+#define PCS10G_BR_PCS_CFG_RX_SCR_DISABLE BIT(12)
+#define PCS10G_BR_PCS_CFG_RX_SCR_DISABLE_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_CFG_RX_SCR_DISABLE, x)
+#define PCS10G_BR_PCS_CFG_RX_SCR_DISABLE_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_CFG_RX_SCR_DISABLE, x)
+
+#define PCS10G_BR_PCS_CFG_TX_DATA_FLIP BIT(7)
+#define PCS10G_BR_PCS_CFG_TX_DATA_FLIP_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_CFG_TX_DATA_FLIP, x)
+#define PCS10G_BR_PCS_CFG_TX_DATA_FLIP_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_CFG_TX_DATA_FLIP, x)
+
+#define PCS10G_BR_PCS_CFG_AN_LINK_CTRL_ENA BIT(6)
+#define PCS10G_BR_PCS_CFG_AN_LINK_CTRL_ENA_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_CFG_AN_LINK_CTRL_ENA, x)
+#define PCS10G_BR_PCS_CFG_AN_LINK_CTRL_ENA_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_CFG_AN_LINK_CTRL_ENA, x)
+
+#define PCS10G_BR_PCS_CFG_TX_TEST_MODE BIT(4)
+#define PCS10G_BR_PCS_CFG_TX_TEST_MODE_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_CFG_TX_TEST_MODE, x)
+#define PCS10G_BR_PCS_CFG_TX_TEST_MODE_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_CFG_TX_TEST_MODE, x)
+
+#define PCS10G_BR_PCS_CFG_TX_SCR_DISABLE BIT(3)
+#define PCS10G_BR_PCS_CFG_TX_SCR_DISABLE_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_CFG_TX_SCR_DISABLE, x)
+#define PCS10G_BR_PCS_CFG_TX_SCR_DISABLE_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_CFG_TX_SCR_DISABLE, x)
+
+/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_SD_CFG */
+#define PCS10G_BR_PCS_SD_CFG(t) __REG(TARGET_PCS10G_BR, t, 12, 0, 0, 1, 56, 4, 0, 1, 4)
+
+#define PCS10G_BR_PCS_SD_CFG_SD_SEL BIT(8)
+#define PCS10G_BR_PCS_SD_CFG_SD_SEL_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_SD_CFG_SD_SEL, x)
+#define PCS10G_BR_PCS_SD_CFG_SD_SEL_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_SD_CFG_SD_SEL, x)
+
+#define PCS10G_BR_PCS_SD_CFG_SD_POL BIT(4)
+#define PCS10G_BR_PCS_SD_CFG_SD_POL_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_SD_CFG_SD_POL, x)
+#define PCS10G_BR_PCS_SD_CFG_SD_POL_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_SD_CFG_SD_POL, x)
+
+#define PCS10G_BR_PCS_SD_CFG_SD_ENA BIT(0)
+#define PCS10G_BR_PCS_SD_CFG_SD_ENA_SET(x)\
+ FIELD_PREP(PCS10G_BR_PCS_SD_CFG_SD_ENA, x)
+#define PCS10G_BR_PCS_SD_CFG_SD_ENA_GET(x)\
+ FIELD_GET(PCS10G_BR_PCS_SD_CFG_SD_ENA, x)
+
+/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_CFG */
+#define PCS25G_BR_PCS_CFG(t) __REG(TARGET_PCS25G_BR, t, 8, 0, 0, 1, 56, 0, 0, 1, 4)
+
+#define PCS25G_BR_PCS_CFG_PCS_ENA BIT(31)
+#define PCS25G_BR_PCS_CFG_PCS_ENA_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_CFG_PCS_ENA, x)
+#define PCS25G_BR_PCS_CFG_PCS_ENA_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_CFG_PCS_ENA, x)
+
+#define PCS25G_BR_PCS_CFG_PMA_LOOPBACK_ENA BIT(30)
+#define PCS25G_BR_PCS_CFG_PMA_LOOPBACK_ENA_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_CFG_PMA_LOOPBACK_ENA, x)
+#define PCS25G_BR_PCS_CFG_PMA_LOOPBACK_ENA_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_CFG_PMA_LOOPBACK_ENA, x)
+
+#define PCS25G_BR_PCS_CFG_SH_CNT_MAX GENMASK(29, 24)
+#define PCS25G_BR_PCS_CFG_SH_CNT_MAX_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_CFG_SH_CNT_MAX, x)
+#define PCS25G_BR_PCS_CFG_SH_CNT_MAX_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_CFG_SH_CNT_MAX, x)
+
+#define PCS25G_BR_PCS_CFG_RX_DATA_FLIP BIT(18)
+#define PCS25G_BR_PCS_CFG_RX_DATA_FLIP_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_CFG_RX_DATA_FLIP, x)
+#define PCS25G_BR_PCS_CFG_RX_DATA_FLIP_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_CFG_RX_DATA_FLIP, x)
+
+#define PCS25G_BR_PCS_CFG_RESYNC_ENA BIT(15)
+#define PCS25G_BR_PCS_CFG_RESYNC_ENA_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_CFG_RESYNC_ENA, x)
+#define PCS25G_BR_PCS_CFG_RESYNC_ENA_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_CFG_RESYNC_ENA, x)
+
+#define PCS25G_BR_PCS_CFG_LF_GEN_DIS BIT(14)
+#define PCS25G_BR_PCS_CFG_LF_GEN_DIS_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_CFG_LF_GEN_DIS, x)
+#define PCS25G_BR_PCS_CFG_LF_GEN_DIS_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_CFG_LF_GEN_DIS, x)
+
+#define PCS25G_BR_PCS_CFG_RX_TEST_MODE BIT(13)
+#define PCS25G_BR_PCS_CFG_RX_TEST_MODE_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_CFG_RX_TEST_MODE, x)
+#define PCS25G_BR_PCS_CFG_RX_TEST_MODE_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_CFG_RX_TEST_MODE, x)
+
+#define PCS25G_BR_PCS_CFG_RX_SCR_DISABLE BIT(12)
+#define PCS25G_BR_PCS_CFG_RX_SCR_DISABLE_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_CFG_RX_SCR_DISABLE, x)
+#define PCS25G_BR_PCS_CFG_RX_SCR_DISABLE_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_CFG_RX_SCR_DISABLE, x)
+
+#define PCS25G_BR_PCS_CFG_TX_DATA_FLIP BIT(7)
+#define PCS25G_BR_PCS_CFG_TX_DATA_FLIP_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_CFG_TX_DATA_FLIP, x)
+#define PCS25G_BR_PCS_CFG_TX_DATA_FLIP_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_CFG_TX_DATA_FLIP, x)
+
+#define PCS25G_BR_PCS_CFG_AN_LINK_CTRL_ENA BIT(6)
+#define PCS25G_BR_PCS_CFG_AN_LINK_CTRL_ENA_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_CFG_AN_LINK_CTRL_ENA, x)
+#define PCS25G_BR_PCS_CFG_AN_LINK_CTRL_ENA_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_CFG_AN_LINK_CTRL_ENA, x)
+
+#define PCS25G_BR_PCS_CFG_TX_TEST_MODE BIT(4)
+#define PCS25G_BR_PCS_CFG_TX_TEST_MODE_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_CFG_TX_TEST_MODE, x)
+#define PCS25G_BR_PCS_CFG_TX_TEST_MODE_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_CFG_TX_TEST_MODE, x)
+
+#define PCS25G_BR_PCS_CFG_TX_SCR_DISABLE BIT(3)
+#define PCS25G_BR_PCS_CFG_TX_SCR_DISABLE_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_CFG_TX_SCR_DISABLE, x)
+#define PCS25G_BR_PCS_CFG_TX_SCR_DISABLE_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_CFG_TX_SCR_DISABLE, x)
+
+/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_SD_CFG */
+#define PCS25G_BR_PCS_SD_CFG(t) __REG(TARGET_PCS25G_BR, t, 8, 0, 0, 1, 56, 4, 0, 1, 4)
+
+#define PCS25G_BR_PCS_SD_CFG_SD_SEL BIT(8)
+#define PCS25G_BR_PCS_SD_CFG_SD_SEL_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_SD_CFG_SD_SEL, x)
+#define PCS25G_BR_PCS_SD_CFG_SD_SEL_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_SD_CFG_SD_SEL, x)
+
+#define PCS25G_BR_PCS_SD_CFG_SD_POL BIT(4)
+#define PCS25G_BR_PCS_SD_CFG_SD_POL_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_SD_CFG_SD_POL, x)
+#define PCS25G_BR_PCS_SD_CFG_SD_POL_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_SD_CFG_SD_POL, x)
+
+#define PCS25G_BR_PCS_SD_CFG_SD_ENA BIT(0)
+#define PCS25G_BR_PCS_SD_CFG_SD_ENA_SET(x)\
+ FIELD_PREP(PCS25G_BR_PCS_SD_CFG_SD_ENA, x)
+#define PCS25G_BR_PCS_SD_CFG_SD_ENA_GET(x)\
+ FIELD_GET(PCS25G_BR_PCS_SD_CFG_SD_ENA, x)
+
+/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_CFG */
+#define PCS5G_BR_PCS_CFG(t) __REG(TARGET_PCS5G_BR, t, 13, 0, 0, 1, 56, 0, 0, 1, 4)
+
+#define PCS5G_BR_PCS_CFG_PCS_ENA BIT(31)
+#define PCS5G_BR_PCS_CFG_PCS_ENA_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_CFG_PCS_ENA, x)
+#define PCS5G_BR_PCS_CFG_PCS_ENA_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_CFG_PCS_ENA, x)
+
+#define PCS5G_BR_PCS_CFG_PMA_LOOPBACK_ENA BIT(30)
+#define PCS5G_BR_PCS_CFG_PMA_LOOPBACK_ENA_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_CFG_PMA_LOOPBACK_ENA, x)
+#define PCS5G_BR_PCS_CFG_PMA_LOOPBACK_ENA_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_CFG_PMA_LOOPBACK_ENA, x)
+
+#define PCS5G_BR_PCS_CFG_SH_CNT_MAX GENMASK(29, 24)
+#define PCS5G_BR_PCS_CFG_SH_CNT_MAX_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_CFG_SH_CNT_MAX, x)
+#define PCS5G_BR_PCS_CFG_SH_CNT_MAX_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_CFG_SH_CNT_MAX, x)
+
+#define PCS5G_BR_PCS_CFG_RX_DATA_FLIP BIT(18)
+#define PCS5G_BR_PCS_CFG_RX_DATA_FLIP_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_CFG_RX_DATA_FLIP, x)
+#define PCS5G_BR_PCS_CFG_RX_DATA_FLIP_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_CFG_RX_DATA_FLIP, x)
+
+#define PCS5G_BR_PCS_CFG_RESYNC_ENA BIT(15)
+#define PCS5G_BR_PCS_CFG_RESYNC_ENA_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_CFG_RESYNC_ENA, x)
+#define PCS5G_BR_PCS_CFG_RESYNC_ENA_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_CFG_RESYNC_ENA, x)
+
+#define PCS5G_BR_PCS_CFG_LF_GEN_DIS BIT(14)
+#define PCS5G_BR_PCS_CFG_LF_GEN_DIS_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_CFG_LF_GEN_DIS, x)
+#define PCS5G_BR_PCS_CFG_LF_GEN_DIS_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_CFG_LF_GEN_DIS, x)
+
+#define PCS5G_BR_PCS_CFG_RX_TEST_MODE BIT(13)
+#define PCS5G_BR_PCS_CFG_RX_TEST_MODE_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_CFG_RX_TEST_MODE, x)
+#define PCS5G_BR_PCS_CFG_RX_TEST_MODE_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_CFG_RX_TEST_MODE, x)
+
+#define PCS5G_BR_PCS_CFG_RX_SCR_DISABLE BIT(12)
+#define PCS5G_BR_PCS_CFG_RX_SCR_DISABLE_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_CFG_RX_SCR_DISABLE, x)
+#define PCS5G_BR_PCS_CFG_RX_SCR_DISABLE_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_CFG_RX_SCR_DISABLE, x)
+
+#define PCS5G_BR_PCS_CFG_TX_DATA_FLIP BIT(7)
+#define PCS5G_BR_PCS_CFG_TX_DATA_FLIP_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_CFG_TX_DATA_FLIP, x)
+#define PCS5G_BR_PCS_CFG_TX_DATA_FLIP_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_CFG_TX_DATA_FLIP, x)
+
+#define PCS5G_BR_PCS_CFG_AN_LINK_CTRL_ENA BIT(6)
+#define PCS5G_BR_PCS_CFG_AN_LINK_CTRL_ENA_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_CFG_AN_LINK_CTRL_ENA, x)
+#define PCS5G_BR_PCS_CFG_AN_LINK_CTRL_ENA_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_CFG_AN_LINK_CTRL_ENA, x)
+
+#define PCS5G_BR_PCS_CFG_TX_TEST_MODE BIT(4)
+#define PCS5G_BR_PCS_CFG_TX_TEST_MODE_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_CFG_TX_TEST_MODE, x)
+#define PCS5G_BR_PCS_CFG_TX_TEST_MODE_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_CFG_TX_TEST_MODE, x)
+
+#define PCS5G_BR_PCS_CFG_TX_SCR_DISABLE BIT(3)
+#define PCS5G_BR_PCS_CFG_TX_SCR_DISABLE_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_CFG_TX_SCR_DISABLE, x)
+#define PCS5G_BR_PCS_CFG_TX_SCR_DISABLE_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_CFG_TX_SCR_DISABLE, x)
+
+/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_SD_CFG */
+#define PCS5G_BR_PCS_SD_CFG(t) __REG(TARGET_PCS5G_BR, t, 13, 0, 0, 1, 56, 4, 0, 1, 4)
+
+#define PCS5G_BR_PCS_SD_CFG_SD_SEL BIT(8)
+#define PCS5G_BR_PCS_SD_CFG_SD_SEL_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_SD_CFG_SD_SEL, x)
+#define PCS5G_BR_PCS_SD_CFG_SD_SEL_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_SD_CFG_SD_SEL, x)
+
+#define PCS5G_BR_PCS_SD_CFG_SD_POL BIT(4)
+#define PCS5G_BR_PCS_SD_CFG_SD_POL_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_SD_CFG_SD_POL, x)
+#define PCS5G_BR_PCS_SD_CFG_SD_POL_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_SD_CFG_SD_POL, x)
+
+#define PCS5G_BR_PCS_SD_CFG_SD_ENA BIT(0)
+#define PCS5G_BR_PCS_SD_CFG_SD_ENA_SET(x)\
+ FIELD_PREP(PCS5G_BR_PCS_SD_CFG_SD_ENA, x)
+#define PCS5G_BR_PCS_SD_CFG_SD_ENA_GET(x)\
+ FIELD_GET(PCS5G_BR_PCS_SD_CFG_SD_ENA, x)
+
+/* PORT_CONF:HW_CFG:DEV5G_MODES */
+#define PORT_CONF_DEV5G_MODES __REG(TARGET_PORT_CONF, 0, 1, 0, 0, 1, 24, 0, 0, 1, 4)
+
+#define PORT_CONF_DEV5G_MODES_DEV5G_D0_MODE BIT(0)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D0_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D0_MODE, x)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D0_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D0_MODE, x)
+
+#define PORT_CONF_DEV5G_MODES_DEV5G_D1_MODE BIT(1)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D1_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D1_MODE, x)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D1_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D1_MODE, x)
+
+#define PORT_CONF_DEV5G_MODES_DEV5G_D2_MODE BIT(2)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D2_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D2_MODE, x)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D2_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D2_MODE, x)
+
+#define PORT_CONF_DEV5G_MODES_DEV5G_D3_MODE BIT(3)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D3_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D3_MODE, x)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D3_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D3_MODE, x)
+
+#define PORT_CONF_DEV5G_MODES_DEV5G_D4_MODE BIT(4)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D4_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D4_MODE, x)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D4_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D4_MODE, x)
+
+#define PORT_CONF_DEV5G_MODES_DEV5G_D5_MODE BIT(5)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D5_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D5_MODE, x)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D5_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D5_MODE, x)
+
+#define PORT_CONF_DEV5G_MODES_DEV5G_D6_MODE BIT(6)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D6_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D6_MODE, x)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D6_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D6_MODE, x)
+
+#define PORT_CONF_DEV5G_MODES_DEV5G_D7_MODE BIT(7)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D7_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D7_MODE, x)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D7_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D7_MODE, x)
+
+#define PORT_CONF_DEV5G_MODES_DEV5G_D8_MODE BIT(8)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D8_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D8_MODE, x)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D8_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D8_MODE, x)
+
+#define PORT_CONF_DEV5G_MODES_DEV5G_D9_MODE BIT(9)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D9_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D9_MODE, x)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D9_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D9_MODE, x)
+
+#define PORT_CONF_DEV5G_MODES_DEV5G_D10_MODE BIT(10)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D10_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D10_MODE, x)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D10_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D10_MODE, x)
+
+#define PORT_CONF_DEV5G_MODES_DEV5G_D11_MODE BIT(11)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D11_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D11_MODE, x)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D11_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D11_MODE, x)
+
+#define PORT_CONF_DEV5G_MODES_DEV5G_D64_MODE BIT(12)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D64_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D64_MODE, x)
+#define PORT_CONF_DEV5G_MODES_DEV5G_D64_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D64_MODE, x)
+
+/* PORT_CONF:HW_CFG:DEV10G_MODES */
+#define PORT_CONF_DEV10G_MODES __REG(TARGET_PORT_CONF, 0, 1, 0, 0, 1, 24, 4, 0, 1, 4)
+
+#define PORT_CONF_DEV10G_MODES_DEV10G_D12_MODE BIT(0)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D12_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D12_MODE, x)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D12_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D12_MODE, x)
+
+#define PORT_CONF_DEV10G_MODES_DEV10G_D13_MODE BIT(1)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D13_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D13_MODE, x)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D13_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D13_MODE, x)
+
+#define PORT_CONF_DEV10G_MODES_DEV10G_D14_MODE BIT(2)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D14_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D14_MODE, x)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D14_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D14_MODE, x)
+
+#define PORT_CONF_DEV10G_MODES_DEV10G_D15_MODE BIT(3)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D15_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D15_MODE, x)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D15_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D15_MODE, x)
+
+#define PORT_CONF_DEV10G_MODES_DEV10G_D48_MODE BIT(4)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D48_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D48_MODE, x)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D48_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D48_MODE, x)
+
+#define PORT_CONF_DEV10G_MODES_DEV10G_D49_MODE BIT(5)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D49_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D49_MODE, x)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D49_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D49_MODE, x)
+
+#define PORT_CONF_DEV10G_MODES_DEV10G_D50_MODE BIT(6)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D50_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D50_MODE, x)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D50_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D50_MODE, x)
+
+#define PORT_CONF_DEV10G_MODES_DEV10G_D51_MODE BIT(7)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D51_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D51_MODE, x)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D51_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D51_MODE, x)
+
+#define PORT_CONF_DEV10G_MODES_DEV10G_D52_MODE BIT(8)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D52_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D52_MODE, x)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D52_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D52_MODE, x)
+
+#define PORT_CONF_DEV10G_MODES_DEV10G_D53_MODE BIT(9)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D53_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D53_MODE, x)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D53_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D53_MODE, x)
+
+#define PORT_CONF_DEV10G_MODES_DEV10G_D54_MODE BIT(10)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D54_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D54_MODE, x)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D54_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D54_MODE, x)
+
+#define PORT_CONF_DEV10G_MODES_DEV10G_D55_MODE BIT(11)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D55_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D55_MODE, x)
+#define PORT_CONF_DEV10G_MODES_DEV10G_D55_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D55_MODE, x)
+
+/* PORT_CONF:HW_CFG:DEV25G_MODES */
+#define PORT_CONF_DEV25G_MODES __REG(TARGET_PORT_CONF, 0, 1, 0, 0, 1, 24, 8, 0, 1, 4)
+
+#define PORT_CONF_DEV25G_MODES_DEV25G_D56_MODE BIT(0)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D56_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV25G_MODES_DEV25G_D56_MODE, x)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D56_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV25G_MODES_DEV25G_D56_MODE, x)
+
+#define PORT_CONF_DEV25G_MODES_DEV25G_D57_MODE BIT(1)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D57_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV25G_MODES_DEV25G_D57_MODE, x)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D57_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV25G_MODES_DEV25G_D57_MODE, x)
+
+#define PORT_CONF_DEV25G_MODES_DEV25G_D58_MODE BIT(2)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D58_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV25G_MODES_DEV25G_D58_MODE, x)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D58_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV25G_MODES_DEV25G_D58_MODE, x)
+
+#define PORT_CONF_DEV25G_MODES_DEV25G_D59_MODE BIT(3)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D59_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV25G_MODES_DEV25G_D59_MODE, x)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D59_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV25G_MODES_DEV25G_D59_MODE, x)
+
+#define PORT_CONF_DEV25G_MODES_DEV25G_D60_MODE BIT(4)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D60_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV25G_MODES_DEV25G_D60_MODE, x)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D60_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV25G_MODES_DEV25G_D60_MODE, x)
+
+#define PORT_CONF_DEV25G_MODES_DEV25G_D61_MODE BIT(5)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D61_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV25G_MODES_DEV25G_D61_MODE, x)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D61_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV25G_MODES_DEV25G_D61_MODE, x)
+
+#define PORT_CONF_DEV25G_MODES_DEV25G_D62_MODE BIT(6)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D62_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV25G_MODES_DEV25G_D62_MODE, x)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D62_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV25G_MODES_DEV25G_D62_MODE, x)
+
+#define PORT_CONF_DEV25G_MODES_DEV25G_D63_MODE BIT(7)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D63_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_DEV25G_MODES_DEV25G_D63_MODE, x)
+#define PORT_CONF_DEV25G_MODES_DEV25G_D63_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_DEV25G_MODES_DEV25G_D63_MODE, x)
+
+/* PORT_CONF:HW_CFG:QSGMII_ENA */
+#define PORT_CONF_QSGMII_ENA __REG(TARGET_PORT_CONF, 0, 1, 0, 0, 1, 24, 12, 0, 1, 4)
+
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_0 BIT(0)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_0_SET(x)\
+ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_0, x)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_0_GET(x)\
+ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_0, x)
+
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_1 BIT(1)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_1_SET(x)\
+ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_1, x)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_1_GET(x)\
+ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_1, x)
+
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_2 BIT(2)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_2_SET(x)\
+ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_2, x)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_2_GET(x)\
+ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_2, x)
+
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_3 BIT(3)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_3_SET(x)\
+ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_3, x)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_3_GET(x)\
+ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_3, x)
+
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_4 BIT(4)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_4_SET(x)\
+ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_4, x)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_4_GET(x)\
+ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_4, x)
+
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_5 BIT(5)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_5_SET(x)\
+ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_5, x)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_5_GET(x)\
+ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_5, x)
+
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_6 BIT(6)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_6_SET(x)\
+ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_6, x)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_6_GET(x)\
+ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_6, x)
+
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_7 BIT(7)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_7_SET(x)\
+ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_7, x)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_7_GET(x)\
+ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_7, x)
+
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_8 BIT(8)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_8_SET(x)\
+ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_8, x)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_8_GET(x)\
+ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_8, x)
+
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_9 BIT(9)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_9_SET(x)\
+ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_9, x)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_9_GET(x)\
+ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_9, x)
+
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_10 BIT(10)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_10_SET(x)\
+ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_10, x)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_10_GET(x)\
+ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_10, x)
+
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_11 BIT(11)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_11_SET(x)\
+ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_11, x)
+#define PORT_CONF_QSGMII_ENA_QSGMII_ENA_11_GET(x)\
+ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_11, x)
+
+/* PORT_CONF:USGMII_CFG_STAT:USGMII_CFG */
+#define PORT_CONF_USGMII_CFG(g) __REG(TARGET_PORT_CONF, 0, 1, 72, g, 6, 8, 0, 0, 1, 4)
+
+#define PORT_CONF_USGMII_CFG_BYPASS_SCRAM BIT(9)
+#define PORT_CONF_USGMII_CFG_BYPASS_SCRAM_SET(x)\
+ FIELD_PREP(PORT_CONF_USGMII_CFG_BYPASS_SCRAM, x)
+#define PORT_CONF_USGMII_CFG_BYPASS_SCRAM_GET(x)\
+ FIELD_GET(PORT_CONF_USGMII_CFG_BYPASS_SCRAM, x)
+
+#define PORT_CONF_USGMII_CFG_BYPASS_DESCRAM BIT(8)
+#define PORT_CONF_USGMII_CFG_BYPASS_DESCRAM_SET(x)\
+ FIELD_PREP(PORT_CONF_USGMII_CFG_BYPASS_DESCRAM, x)
+#define PORT_CONF_USGMII_CFG_BYPASS_DESCRAM_GET(x)\
+ FIELD_GET(PORT_CONF_USGMII_CFG_BYPASS_DESCRAM, x)
+
+#define PORT_CONF_USGMII_CFG_FLIP_LANES BIT(7)
+#define PORT_CONF_USGMII_CFG_FLIP_LANES_SET(x)\
+ FIELD_PREP(PORT_CONF_USGMII_CFG_FLIP_LANES, x)
+#define PORT_CONF_USGMII_CFG_FLIP_LANES_GET(x)\
+ FIELD_GET(PORT_CONF_USGMII_CFG_FLIP_LANES, x)
+
+#define PORT_CONF_USGMII_CFG_SHYST_DIS BIT(6)
+#define PORT_CONF_USGMII_CFG_SHYST_DIS_SET(x)\
+ FIELD_PREP(PORT_CONF_USGMII_CFG_SHYST_DIS, x)
+#define PORT_CONF_USGMII_CFG_SHYST_DIS_GET(x)\
+ FIELD_GET(PORT_CONF_USGMII_CFG_SHYST_DIS, x)
+
+#define PORT_CONF_USGMII_CFG_E_DET_ENA BIT(5)
+#define PORT_CONF_USGMII_CFG_E_DET_ENA_SET(x)\
+ FIELD_PREP(PORT_CONF_USGMII_CFG_E_DET_ENA, x)
+#define PORT_CONF_USGMII_CFG_E_DET_ENA_GET(x)\
+ FIELD_GET(PORT_CONF_USGMII_CFG_E_DET_ENA, x)
+
+#define PORT_CONF_USGMII_CFG_USE_I1_ENA BIT(4)
+#define PORT_CONF_USGMII_CFG_USE_I1_ENA_SET(x)\
+ FIELD_PREP(PORT_CONF_USGMII_CFG_USE_I1_ENA, x)
+#define PORT_CONF_USGMII_CFG_USE_I1_ENA_GET(x)\
+ FIELD_GET(PORT_CONF_USGMII_CFG_USE_I1_ENA, x)
+
+#define PORT_CONF_USGMII_CFG_QUAD_MODE BIT(1)
+#define PORT_CONF_USGMII_CFG_QUAD_MODE_SET(x)\
+ FIELD_PREP(PORT_CONF_USGMII_CFG_QUAD_MODE, x)
+#define PORT_CONF_USGMII_CFG_QUAD_MODE_GET(x)\
+ FIELD_GET(PORT_CONF_USGMII_CFG_QUAD_MODE, x)
+
+/* QFWD:SYSTEM:SWITCH_PORT_MODE */
+#define QFWD_SWITCH_PORT_MODE(r) __REG(TARGET_QFWD, 0, 1, 0, 0, 1, 340, 0, r, 70, 4)
+
+#define QFWD_SWITCH_PORT_MODE_PORT_ENA BIT(19)
+#define QFWD_SWITCH_PORT_MODE_PORT_ENA_SET(x)\
+ FIELD_PREP(QFWD_SWITCH_PORT_MODE_PORT_ENA, x)
+#define QFWD_SWITCH_PORT_MODE_PORT_ENA_GET(x)\
+ FIELD_GET(QFWD_SWITCH_PORT_MODE_PORT_ENA, x)
+
+#define QFWD_SWITCH_PORT_MODE_FWD_URGENCY GENMASK(18, 10)
+#define QFWD_SWITCH_PORT_MODE_FWD_URGENCY_SET(x)\
+ FIELD_PREP(QFWD_SWITCH_PORT_MODE_FWD_URGENCY, x)
+#define QFWD_SWITCH_PORT_MODE_FWD_URGENCY_GET(x)\
+ FIELD_GET(QFWD_SWITCH_PORT_MODE_FWD_URGENCY, x)
+
+#define QFWD_SWITCH_PORT_MODE_YEL_RSRVD GENMASK(9, 6)
+#define QFWD_SWITCH_PORT_MODE_YEL_RSRVD_SET(x)\
+ FIELD_PREP(QFWD_SWITCH_PORT_MODE_YEL_RSRVD, x)
+#define QFWD_SWITCH_PORT_MODE_YEL_RSRVD_GET(x)\
+ FIELD_GET(QFWD_SWITCH_PORT_MODE_YEL_RSRVD, x)
+
+#define QFWD_SWITCH_PORT_MODE_INGRESS_DROP_MODE BIT(5)
+#define QFWD_SWITCH_PORT_MODE_INGRESS_DROP_MODE_SET(x)\
+ FIELD_PREP(QFWD_SWITCH_PORT_MODE_INGRESS_DROP_MODE, x)
+#define QFWD_SWITCH_PORT_MODE_INGRESS_DROP_MODE_GET(x)\
+ FIELD_GET(QFWD_SWITCH_PORT_MODE_INGRESS_DROP_MODE, x)
+
+#define QFWD_SWITCH_PORT_MODE_IGR_NO_SHARING BIT(4)
+#define QFWD_SWITCH_PORT_MODE_IGR_NO_SHARING_SET(x)\
+ FIELD_PREP(QFWD_SWITCH_PORT_MODE_IGR_NO_SHARING, x)
+#define QFWD_SWITCH_PORT_MODE_IGR_NO_SHARING_GET(x)\
+ FIELD_GET(QFWD_SWITCH_PORT_MODE_IGR_NO_SHARING, x)
+
+#define QFWD_SWITCH_PORT_MODE_EGR_NO_SHARING BIT(3)
+#define QFWD_SWITCH_PORT_MODE_EGR_NO_SHARING_SET(x)\
+ FIELD_PREP(QFWD_SWITCH_PORT_MODE_EGR_NO_SHARING, x)
+#define QFWD_SWITCH_PORT_MODE_EGR_NO_SHARING_GET(x)\
+ FIELD_GET(QFWD_SWITCH_PORT_MODE_EGR_NO_SHARING, x)
+
+#define QFWD_SWITCH_PORT_MODE_EGRESS_DROP_MODE BIT(2)
+#define QFWD_SWITCH_PORT_MODE_EGRESS_DROP_MODE_SET(x)\
+ FIELD_PREP(QFWD_SWITCH_PORT_MODE_EGRESS_DROP_MODE, x)
+#define QFWD_SWITCH_PORT_MODE_EGRESS_DROP_MODE_GET(x)\
+ FIELD_GET(QFWD_SWITCH_PORT_MODE_EGRESS_DROP_MODE, x)
+
+#define QFWD_SWITCH_PORT_MODE_EGRESS_RSRV_DIS BIT(1)
+#define QFWD_SWITCH_PORT_MODE_EGRESS_RSRV_DIS_SET(x)\
+ FIELD_PREP(QFWD_SWITCH_PORT_MODE_EGRESS_RSRV_DIS, x)
+#define QFWD_SWITCH_PORT_MODE_EGRESS_RSRV_DIS_GET(x)\
+ FIELD_GET(QFWD_SWITCH_PORT_MODE_EGRESS_RSRV_DIS, x)
+
+#define QFWD_SWITCH_PORT_MODE_LEARNALL_MORE BIT(0)
+#define QFWD_SWITCH_PORT_MODE_LEARNALL_MORE_SET(x)\
+ FIELD_PREP(QFWD_SWITCH_PORT_MODE_LEARNALL_MORE, x)
+#define QFWD_SWITCH_PORT_MODE_LEARNALL_MORE_GET(x)\
+ FIELD_GET(QFWD_SWITCH_PORT_MODE_LEARNALL_MORE, x)
+
+/* QRES:RES_CTRL:RES_CFG */
+#define QRES_RES_CFG(g) __REG(TARGET_QRES, 0, 1, 0, g, 5120, 16, 0, 0, 1, 4)
+
+#define QRES_RES_CFG_WM_HIGH GENMASK(11, 0)
+#define QRES_RES_CFG_WM_HIGH_SET(x)\
+ FIELD_PREP(QRES_RES_CFG_WM_HIGH, x)
+#define QRES_RES_CFG_WM_HIGH_GET(x)\
+ FIELD_GET(QRES_RES_CFG_WM_HIGH, x)
+
+/* QRES:RES_CTRL:RES_STAT */
+#define QRES_RES_STAT(g) __REG(TARGET_QRES, 0, 1, 0, g, 5120, 16, 4, 0, 1, 4)
+
+#define QRES_RES_STAT_MAXUSE GENMASK(20, 0)
+#define QRES_RES_STAT_MAXUSE_SET(x)\
+ FIELD_PREP(QRES_RES_STAT_MAXUSE, x)
+#define QRES_RES_STAT_MAXUSE_GET(x)\
+ FIELD_GET(QRES_RES_STAT_MAXUSE, x)
+
+/* QRES:RES_CTRL:RES_STAT_CUR */
+#define QRES_RES_STAT_CUR(g) __REG(TARGET_QRES, 0, 1, 0, g, 5120, 16, 8, 0, 1, 4)
+
+#define QRES_RES_STAT_CUR_INUSE GENMASK(20, 0)
+#define QRES_RES_STAT_CUR_INUSE_SET(x)\
+ FIELD_PREP(QRES_RES_STAT_CUR_INUSE, x)
+#define QRES_RES_STAT_CUR_INUSE_GET(x)\
+ FIELD_GET(QRES_RES_STAT_CUR_INUSE, x)
+
+/* DEVCPU_QS:XTR:XTR_GRP_CFG */
+#define QS_XTR_GRP_CFG(r) __REG(TARGET_QS, 0, 1, 0, 0, 1, 36, 0, r, 2, 4)
+
+#define QS_XTR_GRP_CFG_MODE GENMASK(3, 2)
+#define QS_XTR_GRP_CFG_MODE_SET(x)\
+ FIELD_PREP(QS_XTR_GRP_CFG_MODE, x)
+#define QS_XTR_GRP_CFG_MODE_GET(x)\
+ FIELD_GET(QS_XTR_GRP_CFG_MODE, x)
+
+#define QS_XTR_GRP_CFG_STATUS_WORD_POS BIT(1)
+#define QS_XTR_GRP_CFG_STATUS_WORD_POS_SET(x)\
+ FIELD_PREP(QS_XTR_GRP_CFG_STATUS_WORD_POS, x)
+#define QS_XTR_GRP_CFG_STATUS_WORD_POS_GET(x)\
+ FIELD_GET(QS_XTR_GRP_CFG_STATUS_WORD_POS, x)
+
+#define QS_XTR_GRP_CFG_BYTE_SWAP BIT(0)
+#define QS_XTR_GRP_CFG_BYTE_SWAP_SET(x)\
+ FIELD_PREP(QS_XTR_GRP_CFG_BYTE_SWAP, x)
+#define QS_XTR_GRP_CFG_BYTE_SWAP_GET(x)\
+ FIELD_GET(QS_XTR_GRP_CFG_BYTE_SWAP, x)
+
+/* DEVCPU_QS:XTR:XTR_RD */
+#define QS_XTR_RD(r) __REG(TARGET_QS, 0, 1, 0, 0, 1, 36, 8, r, 2, 4)
+
+/* DEVCPU_QS:XTR:XTR_FLUSH */
+#define QS_XTR_FLUSH __REG(TARGET_QS, 0, 1, 0, 0, 1, 36, 24, 0, 1, 4)
+
+#define QS_XTR_FLUSH_FLUSH GENMASK(1, 0)
+#define QS_XTR_FLUSH_FLUSH_SET(x)\
+ FIELD_PREP(QS_XTR_FLUSH_FLUSH, x)
+#define QS_XTR_FLUSH_FLUSH_GET(x)\
+ FIELD_GET(QS_XTR_FLUSH_FLUSH, x)
+
+/* DEVCPU_QS:XTR:XTR_DATA_PRESENT */
+#define QS_XTR_DATA_PRESENT __REG(TARGET_QS, 0, 1, 0, 0, 1, 36, 28, 0, 1, 4)
+
+#define QS_XTR_DATA_PRESENT_DATA_PRESENT GENMASK(1, 0)
+#define QS_XTR_DATA_PRESENT_DATA_PRESENT_SET(x)\
+ FIELD_PREP(QS_XTR_DATA_PRESENT_DATA_PRESENT, x)
+#define QS_XTR_DATA_PRESENT_DATA_PRESENT_GET(x)\
+ FIELD_GET(QS_XTR_DATA_PRESENT_DATA_PRESENT, x)
+
+/* DEVCPU_QS:INJ:INJ_GRP_CFG */
+#define QS_INJ_GRP_CFG(r) __REG(TARGET_QS, 0, 1, 36, 0, 1, 40, 0, r, 2, 4)
+
+#define QS_INJ_GRP_CFG_MODE GENMASK(3, 2)
+#define QS_INJ_GRP_CFG_MODE_SET(x)\
+ FIELD_PREP(QS_INJ_GRP_CFG_MODE, x)
+#define QS_INJ_GRP_CFG_MODE_GET(x)\
+ FIELD_GET(QS_INJ_GRP_CFG_MODE, x)
+
+#define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0)
+#define QS_INJ_GRP_CFG_BYTE_SWAP_SET(x)\
+ FIELD_PREP(QS_INJ_GRP_CFG_BYTE_SWAP, x)
+#define QS_INJ_GRP_CFG_BYTE_SWAP_GET(x)\
+ FIELD_GET(QS_INJ_GRP_CFG_BYTE_SWAP, x)
+
+/* DEVCPU_QS:INJ:INJ_WR */
+#define QS_INJ_WR(r) __REG(TARGET_QS, 0, 1, 36, 0, 1, 40, 8, r, 2, 4)
+
+/* DEVCPU_QS:INJ:INJ_CTRL */
+#define QS_INJ_CTRL(r) __REG(TARGET_QS, 0, 1, 36, 0, 1, 40, 16, r, 2, 4)
+
+#define QS_INJ_CTRL_GAP_SIZE GENMASK(24, 21)
+#define QS_INJ_CTRL_GAP_SIZE_SET(x)\
+ FIELD_PREP(QS_INJ_CTRL_GAP_SIZE, x)
+#define QS_INJ_CTRL_GAP_SIZE_GET(x)\
+ FIELD_GET(QS_INJ_CTRL_GAP_SIZE, x)
+
+#define QS_INJ_CTRL_ABORT BIT(20)
+#define QS_INJ_CTRL_ABORT_SET(x)\
+ FIELD_PREP(QS_INJ_CTRL_ABORT, x)
+#define QS_INJ_CTRL_ABORT_GET(x)\
+ FIELD_GET(QS_INJ_CTRL_ABORT, x)
+
+#define QS_INJ_CTRL_EOF BIT(19)
+#define QS_INJ_CTRL_EOF_SET(x)\
+ FIELD_PREP(QS_INJ_CTRL_EOF, x)
+#define QS_INJ_CTRL_EOF_GET(x)\
+ FIELD_GET(QS_INJ_CTRL_EOF, x)
+
+#define QS_INJ_CTRL_SOF BIT(18)
+#define QS_INJ_CTRL_SOF_SET(x)\
+ FIELD_PREP(QS_INJ_CTRL_SOF, x)
+#define QS_INJ_CTRL_SOF_GET(x)\
+ FIELD_GET(QS_INJ_CTRL_SOF, x)
+
+#define QS_INJ_CTRL_VLD_BYTES GENMASK(17, 16)
+#define QS_INJ_CTRL_VLD_BYTES_SET(x)\
+ FIELD_PREP(QS_INJ_CTRL_VLD_BYTES, x)
+#define QS_INJ_CTRL_VLD_BYTES_GET(x)\
+ FIELD_GET(QS_INJ_CTRL_VLD_BYTES, x)
+
+/* DEVCPU_QS:INJ:INJ_STATUS */
+#define QS_INJ_STATUS __REG(TARGET_QS, 0, 1, 36, 0, 1, 40, 24, 0, 1, 4)
+
+#define QS_INJ_STATUS_WMARK_REACHED GENMASK(5, 4)
+#define QS_INJ_STATUS_WMARK_REACHED_SET(x)\
+ FIELD_PREP(QS_INJ_STATUS_WMARK_REACHED, x)
+#define QS_INJ_STATUS_WMARK_REACHED_GET(x)\
+ FIELD_GET(QS_INJ_STATUS_WMARK_REACHED, x)
+
+#define QS_INJ_STATUS_FIFO_RDY GENMASK(3, 2)
+#define QS_INJ_STATUS_FIFO_RDY_SET(x)\
+ FIELD_PREP(QS_INJ_STATUS_FIFO_RDY, x)
+#define QS_INJ_STATUS_FIFO_RDY_GET(x)\
+ FIELD_GET(QS_INJ_STATUS_FIFO_RDY, x)
+
+#define QS_INJ_STATUS_INJ_IN_PROGRESS GENMASK(1, 0)
+#define QS_INJ_STATUS_INJ_IN_PROGRESS_SET(x)\
+ FIELD_PREP(QS_INJ_STATUS_INJ_IN_PROGRESS, x)
+#define QS_INJ_STATUS_INJ_IN_PROGRESS_GET(x)\
+ FIELD_GET(QS_INJ_STATUS_INJ_IN_PROGRESS, x)
+
+/* QSYS:PAUSE_CFG:PAUSE_CFG */
+#define QSYS_PAUSE_CFG(r) __REG(TARGET_QSYS, 0, 1, 544, 0, 1, 1128, 0, r, 70, 4)
+
+#define QSYS_PAUSE_CFG_PAUSE_START GENMASK(25, 14)
+#define QSYS_PAUSE_CFG_PAUSE_START_SET(x)\
+ FIELD_PREP(QSYS_PAUSE_CFG_PAUSE_START, x)
+#define QSYS_PAUSE_CFG_PAUSE_START_GET(x)\
+ FIELD_GET(QSYS_PAUSE_CFG_PAUSE_START, x)
+
+#define QSYS_PAUSE_CFG_PAUSE_STOP GENMASK(13, 2)
+#define QSYS_PAUSE_CFG_PAUSE_STOP_SET(x)\
+ FIELD_PREP(QSYS_PAUSE_CFG_PAUSE_STOP, x)
+#define QSYS_PAUSE_CFG_PAUSE_STOP_GET(x)\
+ FIELD_GET(QSYS_PAUSE_CFG_PAUSE_STOP, x)
+
+#define QSYS_PAUSE_CFG_PAUSE_ENA BIT(1)
+#define QSYS_PAUSE_CFG_PAUSE_ENA_SET(x)\
+ FIELD_PREP(QSYS_PAUSE_CFG_PAUSE_ENA, x)
+#define QSYS_PAUSE_CFG_PAUSE_ENA_GET(x)\
+ FIELD_GET(QSYS_PAUSE_CFG_PAUSE_ENA, x)
+
+#define QSYS_PAUSE_CFG_AGGRESSIVE_TAILDROP_ENA BIT(0)
+#define QSYS_PAUSE_CFG_AGGRESSIVE_TAILDROP_ENA_SET(x)\
+ FIELD_PREP(QSYS_PAUSE_CFG_AGGRESSIVE_TAILDROP_ENA, x)
+#define QSYS_PAUSE_CFG_AGGRESSIVE_TAILDROP_ENA_GET(x)\
+ FIELD_GET(QSYS_PAUSE_CFG_AGGRESSIVE_TAILDROP_ENA, x)
+
+/* QSYS:PAUSE_CFG:ATOP */
+#define QSYS_ATOP(r) __REG(TARGET_QSYS, 0, 1, 544, 0, 1, 1128, 284, r, 70, 4)
+
+#define QSYS_ATOP_ATOP GENMASK(11, 0)
+#define QSYS_ATOP_ATOP_SET(x)\
+ FIELD_PREP(QSYS_ATOP_ATOP, x)
+#define QSYS_ATOP_ATOP_GET(x)\
+ FIELD_GET(QSYS_ATOP_ATOP, x)
+
+/* QSYS:PAUSE_CFG:FWD_PRESSURE */
+#define QSYS_FWD_PRESSURE(r) __REG(TARGET_QSYS, 0, 1, 544, 0, 1, 1128, 564, r, 70, 4)
+
+#define QSYS_FWD_PRESSURE_FWD_PRESSURE GENMASK(11, 1)
+#define QSYS_FWD_PRESSURE_FWD_PRESSURE_SET(x)\
+ FIELD_PREP(QSYS_FWD_PRESSURE_FWD_PRESSURE, x)
+#define QSYS_FWD_PRESSURE_FWD_PRESSURE_GET(x)\
+ FIELD_GET(QSYS_FWD_PRESSURE_FWD_PRESSURE, x)
+
+#define QSYS_FWD_PRESSURE_FWD_PRESSURE_DIS BIT(0)
+#define QSYS_FWD_PRESSURE_FWD_PRESSURE_DIS_SET(x)\
+ FIELD_PREP(QSYS_FWD_PRESSURE_FWD_PRESSURE_DIS, x)
+#define QSYS_FWD_PRESSURE_FWD_PRESSURE_DIS_GET(x)\
+ FIELD_GET(QSYS_FWD_PRESSURE_FWD_PRESSURE_DIS, x)
+
+/* QSYS:PAUSE_CFG:ATOP_TOT_CFG */
+#define QSYS_ATOP_TOT_CFG __REG(TARGET_QSYS, 0, 1, 544, 0, 1, 1128, 844, 0, 1, 4)
+
+#define QSYS_ATOP_TOT_CFG_ATOP_TOT GENMASK(11, 0)
+#define QSYS_ATOP_TOT_CFG_ATOP_TOT_SET(x)\
+ FIELD_PREP(QSYS_ATOP_TOT_CFG_ATOP_TOT, x)
+#define QSYS_ATOP_TOT_CFG_ATOP_TOT_GET(x)\
+ FIELD_GET(QSYS_ATOP_TOT_CFG_ATOP_TOT, x)
+
+/* QSYS:CALCFG:CAL_AUTO */
+#define QSYS_CAL_AUTO(r) __REG(TARGET_QSYS, 0, 1, 2304, 0, 1, 40, 0, r, 7, 4)
+
+#define QSYS_CAL_AUTO_CAL_AUTO GENMASK(29, 0)
+#define QSYS_CAL_AUTO_CAL_AUTO_SET(x)\
+ FIELD_PREP(QSYS_CAL_AUTO_CAL_AUTO, x)
+#define QSYS_CAL_AUTO_CAL_AUTO_GET(x)\
+ FIELD_GET(QSYS_CAL_AUTO_CAL_AUTO, x)
+
+/* QSYS:CALCFG:CAL_CTRL */
+#define QSYS_CAL_CTRL __REG(TARGET_QSYS, 0, 1, 2304, 0, 1, 40, 36, 0, 1, 4)
+
+#define QSYS_CAL_CTRL_CAL_MODE GENMASK(14, 11)
+#define QSYS_CAL_CTRL_CAL_MODE_SET(x)\
+ FIELD_PREP(QSYS_CAL_CTRL_CAL_MODE, x)
+#define QSYS_CAL_CTRL_CAL_MODE_GET(x)\
+ FIELD_GET(QSYS_CAL_CTRL_CAL_MODE, x)
+
+#define QSYS_CAL_CTRL_CAL_AUTO_GRANT_RATE GENMASK(10, 1)
+#define QSYS_CAL_CTRL_CAL_AUTO_GRANT_RATE_SET(x)\
+ FIELD_PREP(QSYS_CAL_CTRL_CAL_AUTO_GRANT_RATE, x)
+#define QSYS_CAL_CTRL_CAL_AUTO_GRANT_RATE_GET(x)\
+ FIELD_GET(QSYS_CAL_CTRL_CAL_AUTO_GRANT_RATE, x)
+
+#define QSYS_CAL_CTRL_CAL_AUTO_ERROR BIT(0)
+#define QSYS_CAL_CTRL_CAL_AUTO_ERROR_SET(x)\
+ FIELD_PREP(QSYS_CAL_CTRL_CAL_AUTO_ERROR, x)
+#define QSYS_CAL_CTRL_CAL_AUTO_ERROR_GET(x)\
+ FIELD_GET(QSYS_CAL_CTRL_CAL_AUTO_ERROR, x)
+
+/* QSYS:RAM_CTRL:RAM_INIT */
+#define QSYS_RAM_INIT __REG(TARGET_QSYS, 0, 1, 2344, 0, 1, 4, 0, 0, 1, 4)
+
+#define QSYS_RAM_INIT_RAM_INIT BIT(1)
+#define QSYS_RAM_INIT_RAM_INIT_SET(x)\
+ FIELD_PREP(QSYS_RAM_INIT_RAM_INIT, x)
+#define QSYS_RAM_INIT_RAM_INIT_GET(x)\
+ FIELD_GET(QSYS_RAM_INIT_RAM_INIT, x)
+
+#define QSYS_RAM_INIT_RAM_CFG_HOOK BIT(0)
+#define QSYS_RAM_INIT_RAM_CFG_HOOK_SET(x)\
+ FIELD_PREP(QSYS_RAM_INIT_RAM_CFG_HOOK, x)
+#define QSYS_RAM_INIT_RAM_CFG_HOOK_GET(x)\
+ FIELD_GET(QSYS_RAM_INIT_RAM_CFG_HOOK, x)
+
+/* REW:COMMON:OWN_UPSID */
+#define REW_OWN_UPSID(r) __REG(TARGET_REW, 0, 1, 387264, 0, 1, 1232, 0, r, 3, 4)
+
+#define REW_OWN_UPSID_OWN_UPSID GENMASK(4, 0)
+#define REW_OWN_UPSID_OWN_UPSID_SET(x)\
+ FIELD_PREP(REW_OWN_UPSID_OWN_UPSID, x)
+#define REW_OWN_UPSID_OWN_UPSID_GET(x)\
+ FIELD_GET(REW_OWN_UPSID_OWN_UPSID, x)
+
+/* REW:PORT:PORT_VLAN_CFG */
+#define REW_PORT_VLAN_CFG(g) __REG(TARGET_REW, 0, 1, 360448, g, 70, 256, 0, 0, 1, 4)
+
+#define REW_PORT_VLAN_CFG_PORT_PCP GENMASK(15, 13)
+#define REW_PORT_VLAN_CFG_PORT_PCP_SET(x)\
+ FIELD_PREP(REW_PORT_VLAN_CFG_PORT_PCP, x)
+#define REW_PORT_VLAN_CFG_PORT_PCP_GET(x)\
+ FIELD_GET(REW_PORT_VLAN_CFG_PORT_PCP, x)
+
+#define REW_PORT_VLAN_CFG_PORT_DEI BIT(12)
+#define REW_PORT_VLAN_CFG_PORT_DEI_SET(x)\
+ FIELD_PREP(REW_PORT_VLAN_CFG_PORT_DEI, x)
+#define REW_PORT_VLAN_CFG_PORT_DEI_GET(x)\
+ FIELD_GET(REW_PORT_VLAN_CFG_PORT_DEI, x)
+
+#define REW_PORT_VLAN_CFG_PORT_VID GENMASK(11, 0)
+#define REW_PORT_VLAN_CFG_PORT_VID_SET(x)\
+ FIELD_PREP(REW_PORT_VLAN_CFG_PORT_VID, x)
+#define REW_PORT_VLAN_CFG_PORT_VID_GET(x)\
+ FIELD_GET(REW_PORT_VLAN_CFG_PORT_VID, x)
+
+/* REW:PORT:TAG_CTRL */
+#define REW_TAG_CTRL(g) __REG(TARGET_REW, 0, 1, 360448, g, 70, 256, 132, 0, 1, 4)
+
+#define REW_TAG_CTRL_TAG_CFG_OBEY_WAS_TAGGED BIT(13)
+#define REW_TAG_CTRL_TAG_CFG_OBEY_WAS_TAGGED_SET(x)\
+ FIELD_PREP(REW_TAG_CTRL_TAG_CFG_OBEY_WAS_TAGGED, x)
+#define REW_TAG_CTRL_TAG_CFG_OBEY_WAS_TAGGED_GET(x)\
+ FIELD_GET(REW_TAG_CTRL_TAG_CFG_OBEY_WAS_TAGGED, x)
+
+#define REW_TAG_CTRL_TAG_CFG GENMASK(12, 11)
+#define REW_TAG_CTRL_TAG_CFG_SET(x)\
+ FIELD_PREP(REW_TAG_CTRL_TAG_CFG, x)
+#define REW_TAG_CTRL_TAG_CFG_GET(x)\
+ FIELD_GET(REW_TAG_CTRL_TAG_CFG, x)
+
+#define REW_TAG_CTRL_TAG_TPID_CFG GENMASK(10, 8)
+#define REW_TAG_CTRL_TAG_TPID_CFG_SET(x)\
+ FIELD_PREP(REW_TAG_CTRL_TAG_TPID_CFG, x)
+#define REW_TAG_CTRL_TAG_TPID_CFG_GET(x)\
+ FIELD_GET(REW_TAG_CTRL_TAG_TPID_CFG, x)
+
+#define REW_TAG_CTRL_TAG_VID_CFG GENMASK(7, 6)
+#define REW_TAG_CTRL_TAG_VID_CFG_SET(x)\
+ FIELD_PREP(REW_TAG_CTRL_TAG_VID_CFG, x)
+#define REW_TAG_CTRL_TAG_VID_CFG_GET(x)\
+ FIELD_GET(REW_TAG_CTRL_TAG_VID_CFG, x)
+
+#define REW_TAG_CTRL_TAG_PCP_CFG GENMASK(5, 3)
+#define REW_TAG_CTRL_TAG_PCP_CFG_SET(x)\
+ FIELD_PREP(REW_TAG_CTRL_TAG_PCP_CFG, x)
+#define REW_TAG_CTRL_TAG_PCP_CFG_GET(x)\
+ FIELD_GET(REW_TAG_CTRL_TAG_PCP_CFG, x)
+
+#define REW_TAG_CTRL_TAG_DEI_CFG GENMASK(2, 0)
+#define REW_TAG_CTRL_TAG_DEI_CFG_SET(x)\
+ FIELD_PREP(REW_TAG_CTRL_TAG_DEI_CFG, x)
+#define REW_TAG_CTRL_TAG_DEI_CFG_GET(x)\
+ FIELD_GET(REW_TAG_CTRL_TAG_DEI_CFG, x)
+
+/* REW:RAM_CTRL:RAM_INIT */
+#define REW_RAM_INIT __REG(TARGET_REW, 0, 1, 378696, 0, 1, 4, 0, 0, 1, 4)
+
+#define REW_RAM_INIT_RAM_INIT BIT(1)
+#define REW_RAM_INIT_RAM_INIT_SET(x)\
+ FIELD_PREP(REW_RAM_INIT_RAM_INIT, x)
+#define REW_RAM_INIT_RAM_INIT_GET(x)\
+ FIELD_GET(REW_RAM_INIT_RAM_INIT, x)
+
+#define REW_RAM_INIT_RAM_CFG_HOOK BIT(0)
+#define REW_RAM_INIT_RAM_CFG_HOOK_SET(x)\
+ FIELD_PREP(REW_RAM_INIT_RAM_CFG_HOOK, x)
+#define REW_RAM_INIT_RAM_CFG_HOOK_GET(x)\
+ FIELD_GET(REW_RAM_INIT_RAM_CFG_HOOK, x)
+
+/* VCAP_SUPER:RAM_CTRL:RAM_INIT */
+#define VCAP_SUPER_RAM_INIT __REG(TARGET_VCAP_SUPER, 0, 1, 1120, 0, 1, 4, 0, 0, 1, 4)
+
+#define VCAP_SUPER_RAM_INIT_RAM_INIT BIT(1)
+#define VCAP_SUPER_RAM_INIT_RAM_INIT_SET(x)\
+ FIELD_PREP(VCAP_SUPER_RAM_INIT_RAM_INIT, x)
+#define VCAP_SUPER_RAM_INIT_RAM_INIT_GET(x)\
+ FIELD_GET(VCAP_SUPER_RAM_INIT_RAM_INIT, x)
+
+#define VCAP_SUPER_RAM_INIT_RAM_CFG_HOOK BIT(0)
+#define VCAP_SUPER_RAM_INIT_RAM_CFG_HOOK_SET(x)\
+ FIELD_PREP(VCAP_SUPER_RAM_INIT_RAM_CFG_HOOK, x)
+#define VCAP_SUPER_RAM_INIT_RAM_CFG_HOOK_GET(x)\
+ FIELD_GET(VCAP_SUPER_RAM_INIT_RAM_CFG_HOOK, x)
+
+/* VOP:RAM_CTRL:RAM_INIT */
+#define VOP_RAM_INIT __REG(TARGET_VOP, 0, 1, 279176, 0, 1, 4, 0, 0, 1, 4)
+
+#define VOP_RAM_INIT_RAM_INIT BIT(1)
+#define VOP_RAM_INIT_RAM_INIT_SET(x)\
+ FIELD_PREP(VOP_RAM_INIT_RAM_INIT, x)
+#define VOP_RAM_INIT_RAM_INIT_GET(x)\
+ FIELD_GET(VOP_RAM_INIT_RAM_INIT, x)
+
+#define VOP_RAM_INIT_RAM_CFG_HOOK BIT(0)
+#define VOP_RAM_INIT_RAM_CFG_HOOK_SET(x)\
+ FIELD_PREP(VOP_RAM_INIT_RAM_CFG_HOOK, x)
+#define VOP_RAM_INIT_RAM_CFG_HOOK_GET(x)\
+ FIELD_GET(VOP_RAM_INIT_RAM_CFG_HOOK, x)
+
+/* XQS:SYSTEM:STAT_CFG */
+#define XQS_STAT_CFG __REG(TARGET_XQS, 0, 1, 6768, 0, 1, 872, 860, 0, 1, 4)
+
+#define XQS_STAT_CFG_STAT_CLEAR_SHOT GENMASK(21, 18)
+#define XQS_STAT_CFG_STAT_CLEAR_SHOT_SET(x)\
+ FIELD_PREP(XQS_STAT_CFG_STAT_CLEAR_SHOT, x)
+#define XQS_STAT_CFG_STAT_CLEAR_SHOT_GET(x)\
+ FIELD_GET(XQS_STAT_CFG_STAT_CLEAR_SHOT, x)
+
+#define XQS_STAT_CFG_STAT_VIEW GENMASK(17, 5)
+#define XQS_STAT_CFG_STAT_VIEW_SET(x)\
+ FIELD_PREP(XQS_STAT_CFG_STAT_VIEW, x)
+#define XQS_STAT_CFG_STAT_VIEW_GET(x)\
+ FIELD_GET(XQS_STAT_CFG_STAT_VIEW, x)
+
+#define XQS_STAT_CFG_STAT_SRV_PKT_ONLY BIT(4)
+#define XQS_STAT_CFG_STAT_SRV_PKT_ONLY_SET(x)\
+ FIELD_PREP(XQS_STAT_CFG_STAT_SRV_PKT_ONLY, x)
+#define XQS_STAT_CFG_STAT_SRV_PKT_ONLY_GET(x)\
+ FIELD_GET(XQS_STAT_CFG_STAT_SRV_PKT_ONLY, x)
+
+#define XQS_STAT_CFG_STAT_WRAP_DIS GENMASK(3, 0)
+#define XQS_STAT_CFG_STAT_WRAP_DIS_SET(x)\
+ FIELD_PREP(XQS_STAT_CFG_STAT_WRAP_DIS, x)
+#define XQS_STAT_CFG_STAT_WRAP_DIS_GET(x)\
+ FIELD_GET(XQS_STAT_CFG_STAT_WRAP_DIS, x)
+
+/* XQS:QLIMIT_SHR:QLIMIT_SHR_TOP_CFG */
+#define XQS_QLIMIT_SHR_TOP_CFG(g) __REG(TARGET_XQS, 0, 1, 7936, g, 4, 48, 0, 0, 1, 4)
+
+#define XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP GENMASK(14, 0)
+#define XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP_SET(x)\
+ FIELD_PREP(XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP, x)
+#define XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP_GET(x)\
+ FIELD_GET(XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP, x)
+
+/* XQS:QLIMIT_SHR:QLIMIT_SHR_ATOP_CFG */
+#define XQS_QLIMIT_SHR_ATOP_CFG(g) __REG(TARGET_XQS, 0, 1, 7936, g, 4, 48, 4, 0, 1, 4)
+
+#define XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP GENMASK(14, 0)
+#define XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP_SET(x)\
+ FIELD_PREP(XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP, x)
+#define XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP_GET(x)\
+ FIELD_GET(XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP, x)
+
+/* XQS:QLIMIT_SHR:QLIMIT_SHR_CTOP_CFG */
+#define XQS_QLIMIT_SHR_CTOP_CFG(g) __REG(TARGET_XQS, 0, 1, 7936, g, 4, 48, 8, 0, 1, 4)
+
+#define XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP GENMASK(14, 0)
+#define XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP_SET(x)\
+ FIELD_PREP(XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP, x)
+#define XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP_GET(x)\
+ FIELD_GET(XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP, x)
+
+/* XQS:QLIMIT_SHR:QLIMIT_SHR_QLIM_CFG */
+#define XQS_QLIMIT_SHR_QLIM_CFG(g) __REG(TARGET_XQS, 0, 1, 7936, g, 4, 48, 12, 0, 1, 4)
+
+#define XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM GENMASK(14, 0)
+#define XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM_SET(x)\
+ FIELD_PREP(XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM, x)
+#define XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM_GET(x)\
+ FIELD_GET(XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM, x)
+
+/* XQS:STAT:CNT */
+#define XQS_CNT(g) __REG(TARGET_XQS, 0, 1, 0, g, 1024, 4, 0, 0, 1, 4)
+
+#endif /* _SPARX5_MAIN_REGS_H_ */
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
new file mode 100644
index 000000000000..9d485a9d1f1f
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include "sparx5_main_regs.h"
+#include "sparx5_main.h"
+#include "sparx5_port.h"
+
+/* The IFH bit position of the first VSTAX bit. This is because the
+ * VSTAX bit positions in Data sheet is starting from zero.
+ */
+#define VSTAX 73
+
+static void ifh_encode_bitfield(void *ifh, u64 value, u32 pos, u32 width)
+{
+ u8 *ifh_hdr = ifh;
+ /* Calculate the Start IFH byte position of this IFH bit position */
+ u32 byte = (35 - (pos / 8));
+ /* Calculate the Start bit position in the Start IFH byte */
+ u32 bit = (pos % 8);
+ u64 encode = GENMASK(bit + width - 1, bit) & (value << bit);
+
+ /* Max width is 5 bytes - 40 bits. In worst case this will
+ * spread over 6 bytes - 48 bits
+ */
+ compiletime_assert(width <= 40, "Unsupported width, must be <= 40");
+
+ /* The b0-b7 goes into the start IFH byte */
+ if (encode & 0xFF)
+ ifh_hdr[byte] |= (u8)((encode & 0xFF));
+ /* The b8-b15 goes into the next IFH byte */
+ if (encode & 0xFF00)
+ ifh_hdr[byte - 1] |= (u8)((encode & 0xFF00) >> 8);
+ /* The b16-b23 goes into the next IFH byte */
+ if (encode & 0xFF0000)
+ ifh_hdr[byte - 2] |= (u8)((encode & 0xFF0000) >> 16);
+ /* The b24-b31 goes into the next IFH byte */
+ if (encode & 0xFF000000)
+ ifh_hdr[byte - 3] |= (u8)((encode & 0xFF000000) >> 24);
+ /* The b32-b39 goes into the next IFH byte */
+ if (encode & 0xFF00000000)
+ ifh_hdr[byte - 4] |= (u8)((encode & 0xFF00000000) >> 32);
+ /* The b40-b47 goes into the next IFH byte */
+ if (encode & 0xFF0000000000)
+ ifh_hdr[byte - 5] |= (u8)((encode & 0xFF0000000000) >> 40);
+}
+
+static void sparx5_set_port_ifh(void *ifh_hdr, u16 portno)
+{
+ /* VSTAX.RSV = 1. MSBit must be 1 */
+ ifh_encode_bitfield(ifh_hdr, 1, VSTAX + 79, 1);
+ /* VSTAX.INGR_DROP_MODE = Enable. Don't make head-of-line blocking */
+ ifh_encode_bitfield(ifh_hdr, 1, VSTAX + 55, 1);
+ /* MISC.CPU_MASK/DPORT = Destination port */
+ ifh_encode_bitfield(ifh_hdr, portno, 29, 8);
+ /* MISC.PIPELINE_PT */
+ ifh_encode_bitfield(ifh_hdr, 16, 37, 5);
+ /* MISC.PIPELINE_ACT */
+ ifh_encode_bitfield(ifh_hdr, 1, 42, 3);
+ /* FWD.SRC_PORT = CPU */
+ ifh_encode_bitfield(ifh_hdr, SPX5_PORT_CPU, 46, 7);
+ /* FWD.SFLOW_ID (disable SFlow sampling) */
+ ifh_encode_bitfield(ifh_hdr, 124, 57, 7);
+ /* FWD.UPDATE_FCS = Enable. Enforce update of FCS. */
+ ifh_encode_bitfield(ifh_hdr, 1, 67, 1);
+}
+
+static int sparx5_port_open(struct net_device *ndev)
+{
+ struct sparx5_port *port = netdev_priv(ndev);
+ int err = 0;
+
+ sparx5_port_enable(port, true);
+ err = phylink_of_phy_connect(port->phylink, port->of_node, 0);
+ if (err) {
+ netdev_err(ndev, "Could not attach to PHY\n");
+ return err;
+ }
+
+ phylink_start(port->phylink);
+
+ if (!ndev->phydev) {
+ /* power up serdes */
+ port->conf.power_down = false;
+ if (port->conf.serdes_reset)
+ err = sparx5_serdes_set(port->sparx5, port, &port->conf);
+ else
+ err = phy_power_on(port->serdes);
+ if (err)
+ netdev_err(ndev, "%s failed\n", __func__);
+ }
+
+ return err;
+}
+
+static int sparx5_port_stop(struct net_device *ndev)
+{
+ struct sparx5_port *port = netdev_priv(ndev);
+ int err = 0;
+
+ sparx5_port_enable(port, false);
+ phylink_stop(port->phylink);
+ phylink_disconnect_phy(port->phylink);
+
+ if (!ndev->phydev) {
+ /* power down serdes */
+ port->conf.power_down = true;
+ if (port->conf.serdes_reset)
+ err = sparx5_serdes_set(port->sparx5, port, &port->conf);
+ else
+ err = phy_power_off(port->serdes);
+ if (err)
+ netdev_err(ndev, "%s failed\n", __func__);
+ }
+ return 0;
+}
+
+static void sparx5_set_rx_mode(struct net_device *dev)
+{
+ struct sparx5_port *port = netdev_priv(dev);
+ struct sparx5 *sparx5 = port->sparx5;
+
+ if (!test_bit(port->portno, sparx5->bridge_mask))
+ __dev_mc_sync(dev, sparx5_mc_sync, sparx5_mc_unsync);
+}
+
+static int sparx5_port_get_phys_port_name(struct net_device *dev,
+ char *buf, size_t len)
+{
+ struct sparx5_port *port = netdev_priv(dev);
+ int ret;
+
+ ret = snprintf(buf, len, "p%d", port->portno);
+ if (ret >= len)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int sparx5_set_mac_address(struct net_device *dev, void *p)
+{
+ struct sparx5_port *port = netdev_priv(dev);
+ struct sparx5 *sparx5 = port->sparx5;
+ const struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ /* Remove current */
+ sparx5_mact_forget(sparx5, dev->dev_addr, port->pvid);
+
+ /* Add new */
+ sparx5_mact_learn(sparx5, PGID_CPU, addr->sa_data, port->pvid);
+
+ /* Record the address */
+ ether_addr_copy(dev->dev_addr, addr->sa_data);
+
+ return 0;
+}
+
+static int sparx5_get_port_parent_id(struct net_device *dev,
+ struct netdev_phys_item_id *ppid)
+{
+ struct sparx5_port *sparx5_port = netdev_priv(dev);
+ struct sparx5 *sparx5 = sparx5_port->sparx5;
+
+ ppid->id_len = sizeof(sparx5->base_mac);
+ memcpy(&ppid->id, &sparx5->base_mac, ppid->id_len);
+
+ return 0;
+}
+
+static const struct net_device_ops sparx5_port_netdev_ops = {
+ .ndo_open = sparx5_port_open,
+ .ndo_stop = sparx5_port_stop,
+ .ndo_start_xmit = sparx5_port_xmit_impl,
+ .ndo_set_rx_mode = sparx5_set_rx_mode,
+ .ndo_get_phys_port_name = sparx5_port_get_phys_port_name,
+ .ndo_set_mac_address = sparx5_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_get_stats64 = sparx5_get_stats64,
+ .ndo_get_port_parent_id = sparx5_get_port_parent_id,
+};
+
+bool sparx5_netdevice_check(const struct net_device *dev)
+{
+ return dev && (dev->netdev_ops == &sparx5_port_netdev_ops);
+}
+
+struct net_device *sparx5_create_netdev(struct sparx5 *sparx5, u32 portno)
+{
+ struct sparx5_port *spx5_port;
+ struct net_device *ndev;
+ u64 val;
+
+ ndev = devm_alloc_etherdev(sparx5->dev, sizeof(struct sparx5_port));
+ if (!ndev)
+ return ERR_PTR(-ENOMEM);
+
+ SET_NETDEV_DEV(ndev, sparx5->dev);
+ spx5_port = netdev_priv(ndev);
+ spx5_port->ndev = ndev;
+ spx5_port->sparx5 = sparx5;
+ spx5_port->portno = portno;
+ sparx5_set_port_ifh(spx5_port->ifh, portno);
+
+ ndev->netdev_ops = &sparx5_port_netdev_ops;
+ ndev->ethtool_ops = &sparx5_ethtool_ops;
+
+ val = ether_addr_to_u64(sparx5->base_mac) + portno + 1;
+ u64_to_ether_addr(val, ndev->dev_addr);
+
+ return ndev;
+}
+
+int sparx5_register_netdevs(struct sparx5 *sparx5)
+{
+ int portno;
+ int err;
+
+ for (portno = 0; portno < SPX5_PORTS; portno++)
+ if (sparx5->ports[portno]) {
+ err = register_netdev(sparx5->ports[portno]->ndev);
+ if (err) {
+ dev_err(sparx5->dev,
+ "port: %02u: netdev registration failed\n",
+ portno);
+ return err;
+ }
+ sparx5_port_inj_timer_setup(sparx5->ports[portno]);
+ }
+ return 0;
+}
+
+void sparx5_destroy_netdevs(struct sparx5 *sparx5)
+{
+ struct sparx5_port *port;
+ int portno;
+
+ for (portno = 0; portno < SPX5_PORTS; portno++) {
+ port = sparx5->ports[portno];
+ if (port && port->phylink) {
+ /* Disconnect the phy */
+ rtnl_lock();
+ sparx5_port_stop(port->ndev);
+ phylink_disconnect_phy(port->phylink);
+ rtnl_unlock();
+ phylink_destroy(port->phylink);
+ port->phylink = NULL;
+ }
+ }
+}
+
+void sparx5_unregister_netdevs(struct sparx5 *sparx5)
+{
+ int portno;
+
+ for (portno = 0; portno < SPX5_PORTS; portno++)
+ if (sparx5->ports[portno])
+ unregister_netdev(sparx5->ports[portno]->ndev);
+}
+
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
new file mode 100644
index 000000000000..09ca7a3bafdc
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include "sparx5_main_regs.h"
+#include "sparx5_main.h"
+
+#define XTR_EOF_0 ntohl((__force __be32)0x80000000u)
+#define XTR_EOF_1 ntohl((__force __be32)0x80000001u)
+#define XTR_EOF_2 ntohl((__force __be32)0x80000002u)
+#define XTR_EOF_3 ntohl((__force __be32)0x80000003u)
+#define XTR_PRUNED ntohl((__force __be32)0x80000004u)
+#define XTR_ABORT ntohl((__force __be32)0x80000005u)
+#define XTR_ESCAPE ntohl((__force __be32)0x80000006u)
+#define XTR_NOT_READY ntohl((__force __be32)0x80000007u)
+
+#define XTR_VALID_BYTES(x) (4 - ((x) & 3))
+
+#define INJ_TIMEOUT_NS 50000
+
+struct frame_info {
+ int src_port;
+};
+
+static void sparx5_xtr_flush(struct sparx5 *sparx5, u8 grp)
+{
+ /* Start flush */
+ spx5_wr(QS_XTR_FLUSH_FLUSH_SET(BIT(grp)), sparx5, QS_XTR_FLUSH);
+
+ /* Allow to drain */
+ mdelay(1);
+
+ /* All Queues normal */
+ spx5_wr(0, sparx5, QS_XTR_FLUSH);
+}
+
+static void sparx5_ifh_parse(u32 *ifh, struct frame_info *info)
+{
+ u8 *xtr_hdr = (u8 *)ifh;
+
+ /* FWD is bit 45-72 (28 bits), but we only read the 27 LSB for now */
+ u32 fwd =
+ ((u32)xtr_hdr[27] << 24) |
+ ((u32)xtr_hdr[28] << 16) |
+ ((u32)xtr_hdr[29] << 8) |
+ ((u32)xtr_hdr[30] << 0);
+ fwd = (fwd >> 5);
+ info->src_port = FIELD_GET(GENMASK(7, 1), fwd);
+}
+
+static void sparx5_xtr_grp(struct sparx5 *sparx5, u8 grp, bool byte_swap)
+{
+ bool eof_flag = false, pruned_flag = false, abort_flag = false;
+ struct net_device *netdev;
+ struct sparx5_port *port;
+ struct frame_info fi;
+ int i, byte_cnt = 0;
+ struct sk_buff *skb;
+ u32 ifh[IFH_LEN];
+ u32 *rxbuf;
+
+ /* Get IFH */
+ for (i = 0; i < IFH_LEN; i++)
+ ifh[i] = spx5_rd(sparx5, QS_XTR_RD(grp));
+
+ /* Decode IFH (whats needed) */
+ sparx5_ifh_parse(ifh, &fi);
+
+ /* Map to port netdev */
+ port = fi.src_port < SPX5_PORTS ?
+ sparx5->ports[fi.src_port] : NULL;
+ if (!port || !port->ndev) {
+ dev_err(sparx5->dev, "Data on inactive port %d\n", fi.src_port);
+ sparx5_xtr_flush(sparx5, grp);
+ return;
+ }
+
+ /* Have netdev, get skb */
+ netdev = port->ndev;
+ skb = netdev_alloc_skb(netdev, netdev->mtu + ETH_HLEN);
+ if (!skb) {
+ sparx5_xtr_flush(sparx5, grp);
+ dev_err(sparx5->dev, "No skb allocated\n");
+ netdev->stats.rx_dropped++;
+ return;
+ }
+ rxbuf = (u32 *)skb->data;
+
+ /* Now, pull frame data */
+ while (!eof_flag) {
+ u32 val = spx5_rd(sparx5, QS_XTR_RD(grp));
+ u32 cmp = val;
+
+ if (byte_swap)
+ cmp = ntohl((__force __be32)val);
+
+ switch (cmp) {
+ case XTR_NOT_READY:
+ break;
+ case XTR_ABORT:
+ /* No accompanying data */
+ abort_flag = true;
+ eof_flag = true;
+ break;
+ case XTR_EOF_0:
+ case XTR_EOF_1:
+ case XTR_EOF_2:
+ case XTR_EOF_3:
+ /* This assumes STATUS_WORD_POS == 1, Status
+ * just after last data
+ */
+ byte_cnt -= (4 - XTR_VALID_BYTES(val));
+ eof_flag = true;
+ break;
+ case XTR_PRUNED:
+ /* But get the last 4 bytes as well */
+ eof_flag = true;
+ pruned_flag = true;
+ fallthrough;
+ case XTR_ESCAPE:
+ *rxbuf = spx5_rd(sparx5, QS_XTR_RD(grp));
+ byte_cnt += 4;
+ rxbuf++;
+ break;
+ default:
+ *rxbuf = val;
+ byte_cnt += 4;
+ rxbuf++;
+ }
+ }
+
+ if (abort_flag || pruned_flag || !eof_flag) {
+ netdev_err(netdev, "Discarded frame: abort:%d pruned:%d eof:%d\n",
+ abort_flag, pruned_flag, eof_flag);
+ kfree_skb(skb);
+ netdev->stats.rx_dropped++;
+ return;
+ }
+
+ /* Everything we see on an interface that is in the HW bridge
+ * has already been forwarded
+ */
+ if (test_bit(port->portno, sparx5->bridge_mask))
+ skb->offload_fwd_mark = 1;
+
+ /* Finish up skb */
+ skb_put(skb, byte_cnt - ETH_FCS_LEN);
+ eth_skb_pad(skb);
+ skb->protocol = eth_type_trans(skb, netdev);
+ netif_rx(skb);
+ netdev->stats.rx_bytes += skb->len;
+ netdev->stats.rx_packets++;
+}
+
+static int sparx5_inject(struct sparx5 *sparx5,
+ u32 *ifh,
+ struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ int grp = INJ_QUEUE;
+ u32 val, w, count;
+ u8 *buf;
+
+ val = spx5_rd(sparx5, QS_INJ_STATUS);
+ if (!(QS_INJ_STATUS_FIFO_RDY_GET(val) & BIT(grp))) {
+ pr_err_ratelimited("Injection: Queue not ready: 0x%lx\n",
+ QS_INJ_STATUS_FIFO_RDY_GET(val));
+ return -EBUSY;
+ }
+
+ /* Indicate SOF */
+ spx5_wr(QS_INJ_CTRL_SOF_SET(1) |
+ QS_INJ_CTRL_GAP_SIZE_SET(1),
+ sparx5, QS_INJ_CTRL(grp));
+
+ /* Write the IFH to the chip. */
+ for (w = 0; w < IFH_LEN; w++)
+ spx5_wr(ifh[w], sparx5, QS_INJ_WR(grp));
+
+ /* Write words, round up */
+ count = DIV_ROUND_UP(skb->len, 4);
+ buf = skb->data;
+ for (w = 0; w < count; w++, buf += 4) {
+ val = get_unaligned((const u32 *)buf);
+ spx5_wr(val, sparx5, QS_INJ_WR(grp));
+ }
+
+ /* Add padding */
+ while (w < (60 / 4)) {
+ spx5_wr(0, sparx5, QS_INJ_WR(grp));
+ w++;
+ }
+
+ /* Indicate EOF and valid bytes in last word */
+ spx5_wr(QS_INJ_CTRL_GAP_SIZE_SET(1) |
+ QS_INJ_CTRL_VLD_BYTES_SET(skb->len < 60 ? 0 : skb->len % 4) |
+ QS_INJ_CTRL_EOF_SET(1),
+ sparx5, QS_INJ_CTRL(grp));
+
+ /* Add dummy CRC */
+ spx5_wr(0, sparx5, QS_INJ_WR(grp));
+ w++;
+
+ val = spx5_rd(sparx5, QS_INJ_STATUS);
+ if (QS_INJ_STATUS_WMARK_REACHED_GET(val) & BIT(grp)) {
+ struct sparx5_port *port = netdev_priv(ndev);
+
+ pr_err_ratelimited("Injection: Watermark reached: 0x%lx\n",
+ QS_INJ_STATUS_WMARK_REACHED_GET(val));
+ netif_stop_queue(ndev);
+ hrtimer_start(&port->inj_timer, INJ_TIMEOUT_NS,
+ HRTIMER_MODE_REL);
+ }
+
+ return NETDEV_TX_OK;
+}
+
+int sparx5_port_xmit_impl(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_device_stats *stats = &dev->stats;
+ struct sparx5_port *port = netdev_priv(dev);
+ struct sparx5 *sparx5 = port->sparx5;
+ int ret;
+
+ ret = sparx5_inject(sparx5, port->ifh, skb, dev);
+
+ if (ret == NETDEV_TX_OK) {
+ stats->tx_bytes += skb->len;
+ stats->tx_packets++;
+ skb_tx_timestamp(skb);
+ dev_kfree_skb_any(skb);
+ } else {
+ stats->tx_dropped++;
+ }
+ return ret;
+}
+
+static enum hrtimer_restart sparx5_injection_timeout(struct hrtimer *tmr)
+{
+ struct sparx5_port *port = container_of(tmr, struct sparx5_port,
+ inj_timer);
+ int grp = INJ_QUEUE;
+ u32 val;
+
+ val = spx5_rd(port->sparx5, QS_INJ_STATUS);
+ if (QS_INJ_STATUS_WMARK_REACHED_GET(val) & BIT(grp)) {
+ pr_err_ratelimited("Injection: Reset watermark count\n");
+ /* Reset Watermark count to restart */
+ spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR_SET(1),
+ DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR,
+ port->sparx5,
+ DSM_DEV_TX_STOP_WM_CFG(port->portno));
+ }
+ netif_wake_queue(port->ndev);
+ return HRTIMER_NORESTART;
+}
+
+int sparx5_manual_injection_mode(struct sparx5 *sparx5)
+{
+ const int byte_swap = 1;
+ int portno;
+
+ /* Change mode to manual extraction and injection */
+ spx5_wr(QS_XTR_GRP_CFG_MODE_SET(1) |
+ QS_XTR_GRP_CFG_STATUS_WORD_POS_SET(1) |
+ QS_XTR_GRP_CFG_BYTE_SWAP_SET(byte_swap),
+ sparx5, QS_XTR_GRP_CFG(XTR_QUEUE));
+ spx5_wr(QS_INJ_GRP_CFG_MODE_SET(1) |
+ QS_INJ_GRP_CFG_BYTE_SWAP_SET(byte_swap),
+ sparx5, QS_INJ_GRP_CFG(INJ_QUEUE));
+
+ /* CPU ports capture setup */
+ for (portno = SPX5_PORT_CPU_0; portno <= SPX5_PORT_CPU_1; portno++) {
+ /* ASM CPU port: No preamble, IFH, enable padding */
+ spx5_wr(ASM_PORT_CFG_PAD_ENA_SET(1) |
+ ASM_PORT_CFG_NO_PREAMBLE_ENA_SET(1) |
+ ASM_PORT_CFG_INJ_FORMAT_CFG_SET(1), /* 1 = IFH */
+ sparx5, ASM_PORT_CFG(portno));
+
+ /* Reset WM cnt to unclog queued frames */
+ spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR_SET(1),
+ DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR,
+ sparx5,
+ DSM_DEV_TX_STOP_WM_CFG(portno));
+
+ /* Set Disassembler Stop Watermark level */
+ spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM_SET(0),
+ DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM,
+ sparx5,
+ DSM_DEV_TX_STOP_WM_CFG(portno));
+
+ /* Enable Disassembler buffer underrun watchdog
+ */
+ spx5_rmw(DSM_BUF_CFG_UNDERFLOW_WATCHDOG_DIS_SET(0),
+ DSM_BUF_CFG_UNDERFLOW_WATCHDOG_DIS,
+ sparx5,
+ DSM_BUF_CFG(portno));
+ }
+ return 0;
+}
+
+irqreturn_t sparx5_xtr_handler(int irq, void *_sparx5)
+{
+ struct sparx5 *s5 = _sparx5;
+ int poll = 64;
+
+ /* Check data in queue */
+ while (spx5_rd(s5, QS_XTR_DATA_PRESENT) & BIT(XTR_QUEUE) && poll-- > 0)
+ sparx5_xtr_grp(s5, XTR_QUEUE, false);
+
+ return IRQ_HANDLED;
+}
+
+void sparx5_port_inj_timer_setup(struct sparx5_port *port)
+{
+ hrtimer_init(&port->inj_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ port->inj_timer.function = sparx5_injection_timeout;
+}
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_phylink.c b/drivers/net/ethernet/microchip/sparx5/sparx5_phylink.c
new file mode 100644
index 000000000000..af70e2795125
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_phylink.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include <linux/module.h>
+#include <linux/phylink.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/sfp.h>
+
+#include "sparx5_main_regs.h"
+#include "sparx5_main.h"
+#include "sparx5_port.h"
+
+static bool port_conf_has_changed(struct sparx5_port_config *a, struct sparx5_port_config *b)
+{
+ if (a->speed != b->speed ||
+ a->portmode != b->portmode ||
+ a->autoneg != b->autoneg ||
+ a->pause_adv != b->pause_adv ||
+ a->power_down != b->power_down ||
+ a->media != b->media)
+ return true;
+ return false;
+}
+
+static void sparx5_phylink_validate(struct phylink_config *config,
+ unsigned long *supported,
+ struct phylink_link_state *state)
+{
+ struct sparx5_port *port = netdev_priv(to_net_dev(config->dev));
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+ phylink_set(mask, Autoneg);
+ phylink_set_port_modes(mask);
+ phylink_set(mask, Pause);
+ phylink_set(mask, Asym_Pause);
+
+ switch (state->interface) {
+ case PHY_INTERFACE_MODE_5GBASER:
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_25GBASER:
+ case PHY_INTERFACE_MODE_NA:
+ if (port->conf.bandwidth == SPEED_5000)
+ phylink_set(mask, 5000baseT_Full);
+ if (port->conf.bandwidth == SPEED_10000) {
+ phylink_set(mask, 5000baseT_Full);
+ phylink_set(mask, 10000baseT_Full);
+ phylink_set(mask, 10000baseCR_Full);
+ phylink_set(mask, 10000baseSR_Full);
+ phylink_set(mask, 10000baseLR_Full);
+ phylink_set(mask, 10000baseLRM_Full);
+ phylink_set(mask, 10000baseER_Full);
+ }
+ if (port->conf.bandwidth == SPEED_25000) {
+ phylink_set(mask, 5000baseT_Full);
+ phylink_set(mask, 10000baseT_Full);
+ phylink_set(mask, 10000baseCR_Full);
+ phylink_set(mask, 10000baseSR_Full);
+ phylink_set(mask, 10000baseLR_Full);
+ phylink_set(mask, 10000baseLRM_Full);
+ phylink_set(mask, 10000baseER_Full);
+ phylink_set(mask, 25000baseCR_Full);
+ phylink_set(mask, 25000baseSR_Full);
+ }
+ if (state->interface != PHY_INTERFACE_MODE_NA)
+ break;
+ fallthrough;
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
+ phylink_set(mask, 10baseT_Half);
+ phylink_set(mask, 10baseT_Full);
+ phylink_set(mask, 100baseT_Half);
+ phylink_set(mask, 100baseT_Full);
+ phylink_set(mask, 1000baseT_Full);
+ phylink_set(mask, 1000baseX_Full);
+ if (state->interface != PHY_INTERFACE_MODE_NA)
+ break;
+ fallthrough;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ if (state->interface != PHY_INTERFACE_MODE_2500BASEX) {
+ phylink_set(mask, 1000baseT_Full);
+ phylink_set(mask, 1000baseX_Full);
+ }
+ if (state->interface == PHY_INTERFACE_MODE_2500BASEX ||
+ state->interface == PHY_INTERFACE_MODE_NA) {
+ phylink_set(mask, 2500baseT_Full);
+ phylink_set(mask, 2500baseX_Full);
+ }
+ break;
+ default:
+ bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+ return;
+ }
+ bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
+ bitmap_and(state->advertising, state->advertising, mask,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+}
+
+static void sparx5_phylink_mac_config(struct phylink_config *config,
+ unsigned int mode,
+ const struct phylink_link_state *state)
+{
+ /* Currently not used */
+}
+
+static void sparx5_phylink_mac_link_up(struct phylink_config *config,
+ struct phy_device *phy,
+ unsigned int mode,
+ phy_interface_t interface,
+ int speed, int duplex,
+ bool tx_pause, bool rx_pause)
+{
+ struct sparx5_port *port = netdev_priv(to_net_dev(config->dev));
+ struct sparx5_port_config conf;
+ int err;
+
+ conf = port->conf;
+ conf.duplex = duplex;
+ conf.pause = 0;
+ conf.pause |= tx_pause ? MLO_PAUSE_TX : 0;
+ conf.pause |= rx_pause ? MLO_PAUSE_RX : 0;
+ conf.speed = speed;
+ /* Configure the port to speed/duplex/pause */
+ err = sparx5_port_config(port->sparx5, port, &conf);
+ if (err)
+ netdev_err(port->ndev, "port config failed: %d\n", err);
+}
+
+static void sparx5_phylink_mac_link_down(struct phylink_config *config,
+ unsigned int mode,
+ phy_interface_t interface)
+{
+ /* Currently not used */
+}
+
+static struct sparx5_port *sparx5_pcs_to_port(struct phylink_pcs *pcs)
+{
+ return container_of(pcs, struct sparx5_port, phylink_pcs);
+}
+
+static void sparx5_pcs_get_state(struct phylink_pcs *pcs,
+ struct phylink_link_state *state)
+{
+ struct sparx5_port *port = sparx5_pcs_to_port(pcs);
+ struct sparx5_port_status status;
+
+ sparx5_get_port_status(port->sparx5, port, &status);
+ state->link = status.link && !status.link_down;
+ state->an_complete = status.an_complete;
+ state->speed = status.speed;
+ state->duplex = status.duplex;
+ state->pause = status.pause;
+}
+
+static int sparx5_pcs_config(struct phylink_pcs *pcs,
+ unsigned int mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ struct sparx5_port *port = sparx5_pcs_to_port(pcs);
+ struct sparx5_port_config conf;
+ int ret = 0;
+
+ conf = port->conf;
+ conf.power_down = false;
+ conf.portmode = interface;
+ conf.inband = phylink_autoneg_inband(mode);
+ conf.autoneg = phylink_test(advertising, Autoneg);
+ conf.pause_adv = 0;
+ if (phylink_test(advertising, Pause))
+ conf.pause_adv |= ADVERTISE_1000XPAUSE;
+ if (phylink_test(advertising, Asym_Pause))
+ conf.pause_adv |= ADVERTISE_1000XPSE_ASYM;
+ if (sparx5_is_baser(interface)) {
+ if (phylink_test(advertising, FIBRE))
+ conf.media = PHY_MEDIA_SR;
+ else
+ conf.media = PHY_MEDIA_DAC;
+ }
+ if (!port_conf_has_changed(&port->conf, &conf))
+ return ret;
+ /* Enable the PCS matching this interface type */
+ ret = sparx5_port_pcs_set(port->sparx5, port, &conf);
+ if (ret)
+ netdev_err(port->ndev, "port PCS config failed: %d\n", ret);
+ return ret;
+}
+
+static void sparx5_pcs_aneg_restart(struct phylink_pcs *pcs)
+{
+ /* Currently not used */
+}
+
+const struct phylink_pcs_ops sparx5_phylink_pcs_ops = {
+ .pcs_get_state = sparx5_pcs_get_state,
+ .pcs_config = sparx5_pcs_config,
+ .pcs_an_restart = sparx5_pcs_aneg_restart,
+};
+
+const struct phylink_mac_ops sparx5_phylink_mac_ops = {
+ .validate = sparx5_phylink_validate,
+ .mac_config = sparx5_phylink_mac_config,
+ .mac_link_down = sparx5_phylink_mac_link_down,
+ .mac_link_up = sparx5_phylink_mac_link_up,
+};
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
new file mode 100644
index 000000000000..d2e3250928bf
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
@@ -0,0 +1,1146 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include <linux/module.h>
+#include <linux/phy/phy.h>
+
+#include "sparx5_main_regs.h"
+#include "sparx5_main.h"
+#include "sparx5_port.h"
+
+#define SPX5_ETYPE_TAG_C 0x8100
+#define SPX5_ETYPE_TAG_S 0x88a8
+
+#define SPX5_WAIT_US 1000
+#define SPX5_WAIT_MAX_US 2000
+
+enum port_error {
+ SPX5_PERR_SPEED,
+ SPX5_PERR_IFTYPE,
+};
+
+#define PAUSE_DISCARD 0xC
+#define ETH_MAXLEN (ETH_DATA_LEN + ETH_HLEN + ETH_FCS_LEN)
+
+static void decode_sgmii_word(u16 lp_abil, struct sparx5_port_status *status)
+{
+ status->an_complete = true;
+ if (!(lp_abil & LPA_SGMII_LINK)) {
+ status->link = false;
+ return;
+ }
+
+ switch (lp_abil & LPA_SGMII_SPD_MASK) {
+ case LPA_SGMII_10:
+ status->speed = SPEED_10;
+ break;
+ case LPA_SGMII_100:
+ status->speed = SPEED_100;
+ break;
+ case LPA_SGMII_1000:
+ status->speed = SPEED_1000;
+ break;
+ default:
+ status->link = false;
+ return;
+ }
+ if (lp_abil & LPA_SGMII_FULL_DUPLEX)
+ status->duplex = DUPLEX_FULL;
+ else
+ status->duplex = DUPLEX_HALF;
+}
+
+static void decode_cl37_word(u16 lp_abil, uint16_t ld_abil, struct sparx5_port_status *status)
+{
+ status->link = !(lp_abil & ADVERTISE_RFAULT) && status->link;
+ status->an_complete = true;
+ status->duplex = (ADVERTISE_1000XFULL & lp_abil) ?
+ DUPLEX_FULL : DUPLEX_UNKNOWN; // 1G HDX not supported
+
+ if ((ld_abil & ADVERTISE_1000XPAUSE) &&
+ (lp_abil & ADVERTISE_1000XPAUSE)) {
+ status->pause = MLO_PAUSE_RX | MLO_PAUSE_TX;
+ } else if ((ld_abil & ADVERTISE_1000XPSE_ASYM) &&
+ (lp_abil & ADVERTISE_1000XPSE_ASYM)) {
+ status->pause |= (lp_abil & ADVERTISE_1000XPAUSE) ?
+ MLO_PAUSE_TX : 0;
+ status->pause |= (ld_abil & ADVERTISE_1000XPAUSE) ?
+ MLO_PAUSE_RX : 0;
+ } else {
+ status->pause = MLO_PAUSE_NONE;
+ }
+}
+
+static int sparx5_get_dev2g5_status(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_status *status)
+{
+ u32 portno = port->portno;
+ u16 lp_adv, ld_adv;
+ u32 value;
+
+ /* Get PCS Link down sticky */
+ value = spx5_rd(sparx5, DEV2G5_PCS1G_STICKY(portno));
+ status->link_down = DEV2G5_PCS1G_STICKY_LINK_DOWN_STICKY_GET(value);
+ if (status->link_down) /* Clear the sticky */
+ spx5_wr(value, sparx5, DEV2G5_PCS1G_STICKY(portno));
+
+ /* Get both current Link and Sync status */
+ value = spx5_rd(sparx5, DEV2G5_PCS1G_LINK_STATUS(portno));
+ status->link = DEV2G5_PCS1G_LINK_STATUS_LINK_STATUS_GET(value) &&
+ DEV2G5_PCS1G_LINK_STATUS_SYNC_STATUS_GET(value);
+
+ if (port->conf.portmode == PHY_INTERFACE_MODE_1000BASEX)
+ status->speed = SPEED_1000;
+ else if (port->conf.portmode == PHY_INTERFACE_MODE_2500BASEX)
+ status->speed = SPEED_2500;
+
+ status->duplex = DUPLEX_FULL;
+
+ /* Get PCS ANEG status register */
+ value = spx5_rd(sparx5, DEV2G5_PCS1G_ANEG_STATUS(portno));
+
+ /* Aneg complete provides more information */
+ if (DEV2G5_PCS1G_ANEG_STATUS_ANEG_COMPLETE_GET(value)) {
+ lp_adv = DEV2G5_PCS1G_ANEG_STATUS_LP_ADV_ABILITY_GET(value);
+ if (port->conf.portmode == PHY_INTERFACE_MODE_SGMII) {
+ decode_sgmii_word(lp_adv, status);
+ } else {
+ value = spx5_rd(sparx5, DEV2G5_PCS1G_ANEG_CFG(portno));
+ ld_adv = DEV2G5_PCS1G_ANEG_CFG_ADV_ABILITY_GET(value);
+ decode_cl37_word(lp_adv, ld_adv, status);
+ }
+ }
+ return 0;
+}
+
+static int sparx5_get_sfi_status(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_status *status)
+{
+ bool high_speed_dev = sparx5_is_baser(port->conf.portmode);
+ u32 portno = port->portno;
+ u32 value, dev, tinst;
+ void __iomem *inst;
+
+ if (!high_speed_dev) {
+ netdev_err(port->ndev, "error: low speed and SFI mode\n");
+ return -EINVAL;
+ }
+
+ dev = sparx5_to_high_dev(portno);
+ tinst = sparx5_port_dev_index(portno);
+ inst = spx5_inst_get(sparx5, dev, tinst);
+
+ value = spx5_inst_rd(inst, DEV10G_MAC_TX_MONITOR_STICKY(0));
+ if (value != DEV10G_MAC_TX_MONITOR_STICKY_IDLE_STATE_STICKY) {
+ /* The link is or has been down. Clear the sticky bit */
+ status->link_down = 1;
+ spx5_inst_wr(0xffffffff, inst, DEV10G_MAC_TX_MONITOR_STICKY(0));
+ value = spx5_inst_rd(inst, DEV10G_MAC_TX_MONITOR_STICKY(0));
+ }
+ status->link = (value == DEV10G_MAC_TX_MONITOR_STICKY_IDLE_STATE_STICKY);
+ status->duplex = DUPLEX_FULL;
+ if (port->conf.portmode == PHY_INTERFACE_MODE_5GBASER)
+ status->speed = SPEED_5000;
+ else if (port->conf.portmode == PHY_INTERFACE_MODE_10GBASER)
+ status->speed = SPEED_10000;
+ else
+ status->speed = SPEED_25000;
+
+ return 0;
+}
+
+/* Get link status of 1000Base-X/in-band and SFI ports.
+ */
+int sparx5_get_port_status(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_status *status)
+{
+ memset(status, 0, sizeof(*status));
+ status->speed = port->conf.speed;
+ if (port->conf.power_down) {
+ status->link = false;
+ return 0;
+ }
+ switch (port->conf.portmode) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ return sparx5_get_dev2g5_status(sparx5, port, status);
+ case PHY_INTERFACE_MODE_5GBASER:
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_25GBASER:
+ return sparx5_get_sfi_status(sparx5, port, status);
+ case PHY_INTERFACE_MODE_NA:
+ return 0;
+ default:
+ netdev_err(port->ndev, "Status not supported");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int sparx5_port_error(struct sparx5_port *port,
+ struct sparx5_port_config *conf,
+ enum port_error errtype)
+{
+ switch (errtype) {
+ case SPX5_PERR_SPEED:
+ netdev_err(port->ndev,
+ "Interface does not support speed: %u: for %s\n",
+ conf->speed, phy_modes(conf->portmode));
+ break;
+ case SPX5_PERR_IFTYPE:
+ netdev_err(port->ndev,
+ "Switch port does not support interface type: %s\n",
+ phy_modes(conf->portmode));
+ break;
+ default:
+ netdev_err(port->ndev,
+ "Interface configuration error\n");
+ }
+
+ return -EINVAL;
+}
+
+static int sparx5_port_verify_speed(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_config *conf)
+{
+ if ((sparx5_port_is_2g5(port->portno) &&
+ conf->speed > SPEED_2500) ||
+ (sparx5_port_is_5g(port->portno) &&
+ conf->speed > SPEED_5000) ||
+ (sparx5_port_is_10g(port->portno) &&
+ conf->speed > SPEED_10000))
+ return sparx5_port_error(port, conf, SPX5_PERR_SPEED);
+
+ switch (conf->portmode) {
+ case PHY_INTERFACE_MODE_NA:
+ return -EINVAL;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ if (conf->speed != SPEED_1000 ||
+ sparx5_port_is_2g5(port->portno))
+ return sparx5_port_error(port, conf, SPX5_PERR_SPEED);
+ if (sparx5_port_is_2g5(port->portno))
+ return sparx5_port_error(port, conf, SPX5_PERR_IFTYPE);
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ if (conf->speed != SPEED_2500 ||
+ sparx5_port_is_2g5(port->portno))
+ return sparx5_port_error(port, conf, SPX5_PERR_SPEED);
+ break;
+ case PHY_INTERFACE_MODE_QSGMII:
+ if (port->portno > 47)
+ return sparx5_port_error(port, conf, SPX5_PERR_IFTYPE);
+ fallthrough;
+ case PHY_INTERFACE_MODE_SGMII:
+ if (conf->speed != SPEED_1000 &&
+ conf->speed != SPEED_100 &&
+ conf->speed != SPEED_10 &&
+ conf->speed != SPEED_2500)
+ return sparx5_port_error(port, conf, SPX5_PERR_SPEED);
+ break;
+ case PHY_INTERFACE_MODE_5GBASER:
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_25GBASER:
+ if ((conf->speed != SPEED_5000 &&
+ conf->speed != SPEED_10000 &&
+ conf->speed != SPEED_25000))
+ return sparx5_port_error(port, conf, SPX5_PERR_SPEED);
+ break;
+ default:
+ return sparx5_port_error(port, conf, SPX5_PERR_IFTYPE);
+ }
+ return 0;
+}
+
+static bool sparx5_dev_change(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_config *conf)
+{
+ return sparx5_is_baser(port->conf.portmode) ^
+ sparx5_is_baser(conf->portmode);
+}
+
+static int sparx5_port_flush_poll(struct sparx5 *sparx5, u32 portno)
+{
+ u32 value, resource, prio, delay_cnt = 0;
+ bool poll_src = true;
+ char *mem = "";
+
+ /* Resource == 0: Memory tracked per source (SRC-MEM)
+ * Resource == 1: Frame references tracked per source (SRC-REF)
+ * Resource == 2: Memory tracked per destination (DST-MEM)
+ * Resource == 3: Frame references tracked per destination. (DST-REF)
+ */
+ while (1) {
+ bool empty = true;
+
+ for (resource = 0; resource < (poll_src ? 2 : 1); resource++) {
+ u32 base;
+
+ base = (resource == 0 ? 2048 : 0) + SPX5_PRIOS * portno;
+ for (prio = 0; prio < SPX5_PRIOS; prio++) {
+ value = spx5_rd(sparx5,
+ QRES_RES_STAT(base + prio));
+ if (value) {
+ mem = resource == 0 ?
+ "DST-MEM" : "SRC-MEM";
+ empty = false;
+ }
+ }
+ }
+
+ if (empty)
+ break;
+
+ if (delay_cnt++ == 2000) {
+ dev_err(sparx5->dev,
+ "Flush timeout port %u. %s queue not empty\n",
+ portno, mem);
+ return -EINVAL;
+ }
+
+ usleep_range(SPX5_WAIT_US, SPX5_WAIT_MAX_US);
+ }
+ return 0;
+}
+
+static int sparx5_port_disable(struct sparx5 *sparx5, struct sparx5_port *port, bool high_spd_dev)
+{
+ u32 tinst = high_spd_dev ?
+ sparx5_port_dev_index(port->portno) : port->portno;
+ u32 dev = high_spd_dev ?
+ sparx5_to_high_dev(port->portno) : TARGET_DEV2G5;
+ void __iomem *devinst = spx5_inst_get(sparx5, dev, tinst);
+ u32 spd = port->conf.speed;
+ u32 spd_prm;
+ int err;
+
+ if (high_spd_dev) {
+ /* 1: Reset the PCS Rx clock domain */
+ spx5_inst_rmw(DEV10G_DEV_RST_CTRL_PCS_RX_RST,
+ DEV10G_DEV_RST_CTRL_PCS_RX_RST,
+ devinst,
+ DEV10G_DEV_RST_CTRL(0));
+
+ /* 2: Disable MAC frame reception */
+ spx5_inst_rmw(0,
+ DEV10G_MAC_ENA_CFG_RX_ENA,
+ devinst,
+ DEV10G_MAC_ENA_CFG(0));
+ } else {
+ /* 1: Reset the PCS Rx clock domain */
+ spx5_inst_rmw(DEV2G5_DEV_RST_CTRL_PCS_RX_RST,
+ DEV2G5_DEV_RST_CTRL_PCS_RX_RST,
+ devinst,
+ DEV2G5_DEV_RST_CTRL(0));
+ /* 2: Disable MAC frame reception */
+ spx5_inst_rmw(0,
+ DEV2G5_MAC_ENA_CFG_RX_ENA,
+ devinst,
+ DEV2G5_MAC_ENA_CFG(0));
+ }
+ /* 3: Disable traffic being sent to or from switch port->portno */
+ spx5_rmw(0,
+ QFWD_SWITCH_PORT_MODE_PORT_ENA,
+ sparx5,
+ QFWD_SWITCH_PORT_MODE(port->portno));
+
+ /* 4: Disable dequeuing from the egress queues */
+ spx5_rmw(HSCH_PORT_MODE_DEQUEUE_DIS,
+ HSCH_PORT_MODE_DEQUEUE_DIS,
+ sparx5,
+ HSCH_PORT_MODE(port->portno));
+
+ /* 5: Disable Flowcontrol */
+ spx5_rmw(QSYS_PAUSE_CFG_PAUSE_STOP_SET(0xFFF - 1),
+ QSYS_PAUSE_CFG_PAUSE_STOP,
+ sparx5,
+ QSYS_PAUSE_CFG(port->portno));
+
+ spd_prm = spd == SPEED_10 ? 1000 : spd == SPEED_100 ? 100 : 10;
+ /* 6: Wait while the last frame is exiting the queues */
+ usleep_range(8 * spd_prm, 10 * spd_prm);
+
+ /* 7: Flush the queues accociated with the port->portno */
+ spx5_rmw(HSCH_FLUSH_CTRL_FLUSH_PORT_SET(port->portno) |
+ HSCH_FLUSH_CTRL_FLUSH_DST_SET(1) |
+ HSCH_FLUSH_CTRL_FLUSH_SRC_SET(1) |
+ HSCH_FLUSH_CTRL_FLUSH_ENA_SET(1),
+ HSCH_FLUSH_CTRL_FLUSH_PORT |
+ HSCH_FLUSH_CTRL_FLUSH_DST |
+ HSCH_FLUSH_CTRL_FLUSH_SRC |
+ HSCH_FLUSH_CTRL_FLUSH_ENA,
+ sparx5,
+ HSCH_FLUSH_CTRL);
+
+ /* 8: Enable dequeuing from the egress queues */
+ spx5_rmw(0,
+ HSCH_PORT_MODE_DEQUEUE_DIS,
+ sparx5,
+ HSCH_PORT_MODE(port->portno));
+
+ /* 9: Wait until flushing is complete */
+ err = sparx5_port_flush_poll(sparx5, port->portno);
+ if (err)
+ return err;
+
+ /* 10: Reset the MAC clock domain */
+ if (high_spd_dev) {
+ spx5_inst_rmw(DEV10G_DEV_RST_CTRL_PCS_TX_RST_SET(1) |
+ DEV10G_DEV_RST_CTRL_MAC_RX_RST_SET(1) |
+ DEV10G_DEV_RST_CTRL_MAC_TX_RST_SET(1),
+ DEV10G_DEV_RST_CTRL_PCS_TX_RST |
+ DEV10G_DEV_RST_CTRL_MAC_RX_RST |
+ DEV10G_DEV_RST_CTRL_MAC_TX_RST,
+ devinst,
+ DEV10G_DEV_RST_CTRL(0));
+
+ } else {
+ spx5_inst_rmw(DEV2G5_DEV_RST_CTRL_SPEED_SEL_SET(3) |
+ DEV2G5_DEV_RST_CTRL_PCS_TX_RST_SET(1) |
+ DEV2G5_DEV_RST_CTRL_PCS_RX_RST_SET(1) |
+ DEV2G5_DEV_RST_CTRL_MAC_TX_RST_SET(1) |
+ DEV2G5_DEV_RST_CTRL_MAC_RX_RST_SET(1),
+ DEV2G5_DEV_RST_CTRL_SPEED_SEL |
+ DEV2G5_DEV_RST_CTRL_PCS_TX_RST |
+ DEV2G5_DEV_RST_CTRL_PCS_RX_RST |
+ DEV2G5_DEV_RST_CTRL_MAC_TX_RST |
+ DEV2G5_DEV_RST_CTRL_MAC_RX_RST,
+ devinst,
+ DEV2G5_DEV_RST_CTRL(0));
+ }
+ /* 11: Clear flushing */
+ spx5_rmw(HSCH_FLUSH_CTRL_FLUSH_PORT_SET(port->portno) |
+ HSCH_FLUSH_CTRL_FLUSH_ENA_SET(0),
+ HSCH_FLUSH_CTRL_FLUSH_PORT |
+ HSCH_FLUSH_CTRL_FLUSH_ENA,
+ sparx5,
+ HSCH_FLUSH_CTRL);
+
+ if (high_spd_dev) {
+ u32 pcs = sparx5_to_pcs_dev(port->portno);
+ void __iomem *pcsinst = spx5_inst_get(sparx5, pcs, tinst);
+
+ /* 12: Disable 5G/10G/25 BaseR PCS */
+ spx5_inst_rmw(PCS10G_BR_PCS_CFG_PCS_ENA_SET(0),
+ PCS10G_BR_PCS_CFG_PCS_ENA,
+ pcsinst,
+ PCS10G_BR_PCS_CFG(0));
+
+ if (sparx5_port_is_25g(port->portno))
+ /* Disable 25G PCS */
+ spx5_rmw(DEV25G_PCS25G_CFG_PCS25G_ENA_SET(0),
+ DEV25G_PCS25G_CFG_PCS25G_ENA,
+ sparx5,
+ DEV25G_PCS25G_CFG(tinst));
+ } else {
+ /* 12: Disable 1G PCS */
+ spx5_rmw(DEV2G5_PCS1G_CFG_PCS_ENA_SET(0),
+ DEV2G5_PCS1G_CFG_PCS_ENA,
+ sparx5,
+ DEV2G5_PCS1G_CFG(port->portno));
+ }
+
+ /* The port is now flushed and disabled */
+ return 0;
+}
+
+static int sparx5_port_fifo_sz(struct sparx5 *sparx5,
+ u32 portno, u32 speed)
+{
+ u32 sys_clk = sparx5_clk_period(sparx5->coreclock);
+ const u32 taxi_dist[SPX5_PORTS_ALL] = {
+ 6, 8, 10, 6, 8, 10, 6, 8, 10, 6, 8, 10,
+ 4, 4, 4, 4,
+ 11, 12, 13, 14, 15, 16, 17, 18,
+ 11, 12, 13, 14, 15, 16, 17, 18,
+ 11, 12, 13, 14, 15, 16, 17, 18,
+ 11, 12, 13, 14, 15, 16, 17, 18,
+ 4, 6, 8, 4, 6, 8, 6, 8,
+ 2, 2, 2, 2, 2, 2, 2, 4, 2
+ };
+ u32 mac_per = 6400, tmp1, tmp2, tmp3;
+ u32 fifo_width = 16;
+ u32 mac_width = 8;
+ u32 addition = 0;
+
+ switch (speed) {
+ case SPEED_25000:
+ return 0;
+ case SPEED_10000:
+ mac_per = 6400;
+ mac_width = 8;
+ addition = 1;
+ break;
+ case SPEED_5000:
+ mac_per = 12800;
+ mac_width = 8;
+ addition = 0;
+ break;
+ case SPEED_2500:
+ mac_per = 3200;
+ mac_width = 1;
+ addition = 0;
+ break;
+ case SPEED_1000:
+ mac_per = 8000;
+ mac_width = 1;
+ addition = 0;
+ break;
+ case SPEED_100:
+ case SPEED_10:
+ return 1;
+ default:
+ break;
+ }
+
+ tmp1 = 1000 * mac_width / fifo_width;
+ tmp2 = 3000 + ((12000 + 2 * taxi_dist[portno] * 1000)
+ * sys_clk / mac_per);
+ tmp3 = tmp1 * tmp2 / 1000;
+ return (tmp3 + 2000 + 999) / 1000 + addition;
+}
+
+/* Configure port muxing:
+ * QSGMII: 4x2G5 devices
+ */
+static int sparx5_port_mux_set(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_config *conf)
+{
+ u32 portno = port->portno;
+ u32 inst;
+
+ if (port->conf.portmode == conf->portmode)
+ return 0; /* Nothing to do */
+
+ switch (conf->portmode) {
+ case PHY_INTERFACE_MODE_QSGMII: /* QSGMII: 4x2G5 devices. Mode Q' */
+ inst = (portno - portno % 4) / 4;
+ spx5_rmw(BIT(inst),
+ BIT(inst),
+ sparx5,
+ PORT_CONF_QSGMII_ENA);
+
+ if ((portno / 4 % 2) == 0) {
+ /* Affects d0-d3,d8-d11..d40-d43 */
+ spx5_rmw(PORT_CONF_USGMII_CFG_BYPASS_SCRAM_SET(1) |
+ PORT_CONF_USGMII_CFG_BYPASS_DESCRAM_SET(1) |
+ PORT_CONF_USGMII_CFG_QUAD_MODE_SET(1),
+ PORT_CONF_USGMII_CFG_BYPASS_SCRAM |
+ PORT_CONF_USGMII_CFG_BYPASS_DESCRAM |
+ PORT_CONF_USGMII_CFG_QUAD_MODE,
+ sparx5,
+ PORT_CONF_USGMII_CFG((portno / 8)));
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int sparx5_port_max_tags_set(struct sparx5 *sparx5,
+ struct sparx5_port *port)
+{
+ enum sparx5_port_max_tags max_tags = port->max_vlan_tags;
+ int tag_ct = max_tags == SPX5_PORT_MAX_TAGS_ONE ? 1 :
+ max_tags == SPX5_PORT_MAX_TAGS_TWO ? 2 : 0;
+ bool dtag = max_tags == SPX5_PORT_MAX_TAGS_TWO;
+ enum sparx5_vlan_port_type vlan_type = port->vlan_type;
+ bool dotag = max_tags != SPX5_PORT_MAX_TAGS_NONE;
+ u32 dev = sparx5_to_high_dev(port->portno);
+ u32 tinst = sparx5_port_dev_index(port->portno);
+ void __iomem *inst = spx5_inst_get(sparx5, dev, tinst);
+ u32 etype;
+
+ etype = (vlan_type == SPX5_VLAN_PORT_TYPE_S_CUSTOM ?
+ port->custom_etype :
+ vlan_type == SPX5_VLAN_PORT_TYPE_C ?
+ SPX5_ETYPE_TAG_C : SPX5_ETYPE_TAG_S);
+
+ spx5_wr(DEV2G5_MAC_TAGS_CFG_TAG_ID_SET(etype) |
+ DEV2G5_MAC_TAGS_CFG_PB_ENA_SET(dtag) |
+ DEV2G5_MAC_TAGS_CFG_VLAN_AWR_ENA_SET(dotag) |
+ DEV2G5_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA_SET(dotag),
+ sparx5,
+ DEV2G5_MAC_TAGS_CFG(port->portno));
+
+ if (sparx5_port_is_2g5(port->portno))
+ return 0;
+
+ spx5_inst_rmw(DEV10G_MAC_TAGS_CFG_TAG_ID_SET(etype) |
+ DEV10G_MAC_TAGS_CFG_TAG_ENA_SET(dotag),
+ DEV10G_MAC_TAGS_CFG_TAG_ID |
+ DEV10G_MAC_TAGS_CFG_TAG_ENA,
+ inst,
+ DEV10G_MAC_TAGS_CFG(0, 0));
+
+ spx5_inst_rmw(DEV10G_MAC_NUM_TAGS_CFG_NUM_TAGS_SET(tag_ct),
+ DEV10G_MAC_NUM_TAGS_CFG_NUM_TAGS,
+ inst,
+ DEV10G_MAC_NUM_TAGS_CFG(0));
+
+ spx5_inst_rmw(DEV10G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK_SET(dotag),
+ DEV10G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK,
+ inst,
+ DEV10G_MAC_MAXLEN_CFG(0));
+ return 0;
+}
+
+static int sparx5_port_fwd_urg(struct sparx5 *sparx5, u32 speed)
+{
+ u32 clk_period_ps = 1600; /* 625Mhz for now */
+ u32 urg = 672000;
+
+ switch (speed) {
+ case SPEED_10:
+ case SPEED_100:
+ case SPEED_1000:
+ urg = 672000;
+ break;
+ case SPEED_2500:
+ urg = 270000;
+ break;
+ case SPEED_5000:
+ urg = 135000;
+ break;
+ case SPEED_10000:
+ urg = 67200;
+ break;
+ case SPEED_25000:
+ urg = 27000;
+ break;
+ }
+ return urg / clk_period_ps - 1;
+}
+
+static u16 sparx5_wm_enc(u16 value)
+{
+ if (value >= 2048)
+ return 2048 + value / 16;
+
+ return value;
+}
+
+static int sparx5_port_fc_setup(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_config *conf)
+{
+ bool fc_obey = conf->pause & MLO_PAUSE_RX ? 1 : 0;
+ u32 pause_stop = 0xFFF - 1; /* FC gen disabled */
+
+ if (conf->pause & MLO_PAUSE_TX)
+ pause_stop = sparx5_wm_enc(4 * (ETH_MAXLEN /
+ SPX5_BUFFER_CELL_SZ));
+
+ /* Set HDX flowcontrol */
+ spx5_rmw(DSM_MAC_CFG_HDX_BACKPREASSURE_SET(conf->duplex == DUPLEX_HALF),
+ DSM_MAC_CFG_HDX_BACKPREASSURE,
+ sparx5,
+ DSM_MAC_CFG(port->portno));
+
+ /* Obey flowcontrol */
+ spx5_rmw(DSM_RX_PAUSE_CFG_RX_PAUSE_EN_SET(fc_obey),
+ DSM_RX_PAUSE_CFG_RX_PAUSE_EN,
+ sparx5,
+ DSM_RX_PAUSE_CFG(port->portno));
+
+ /* Disable forward pressure */
+ spx5_rmw(QSYS_FWD_PRESSURE_FWD_PRESSURE_DIS_SET(fc_obey),
+ QSYS_FWD_PRESSURE_FWD_PRESSURE_DIS,
+ sparx5,
+ QSYS_FWD_PRESSURE(port->portno));
+
+ /* Generate pause frames */
+ spx5_rmw(QSYS_PAUSE_CFG_PAUSE_STOP_SET(pause_stop),
+ QSYS_PAUSE_CFG_PAUSE_STOP,
+ sparx5,
+ QSYS_PAUSE_CFG(port->portno));
+
+ return 0;
+}
+
+static u16 sparx5_get_aneg_word(struct sparx5_port_config *conf)
+{
+ if (conf->portmode == PHY_INTERFACE_MODE_1000BASEX) /* cl-37 aneg */
+ return (conf->pause_adv | ADVERTISE_LPACK | ADVERTISE_1000XFULL);
+ else
+ return 1; /* Enable SGMII Aneg */
+}
+
+int sparx5_serdes_set(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_config *conf)
+{
+ int portmode, err, speed = conf->speed;
+
+ if (conf->portmode == PHY_INTERFACE_MODE_QSGMII &&
+ ((port->portno % 4) != 0)) {
+ return 0;
+ }
+ if (sparx5_is_baser(conf->portmode)) {
+ if (conf->portmode == PHY_INTERFACE_MODE_25GBASER)
+ speed = SPEED_25000;
+ else if (conf->portmode == PHY_INTERFACE_MODE_10GBASER)
+ speed = SPEED_10000;
+ else
+ speed = SPEED_5000;
+ }
+
+ err = phy_set_media(port->serdes, conf->media);
+ if (err)
+ return err;
+ if (speed > 0) {
+ err = phy_set_speed(port->serdes, speed);
+ if (err)
+ return err;
+ }
+ if (conf->serdes_reset) {
+ err = phy_reset(port->serdes);
+ if (err)
+ return err;
+ }
+
+ /* Configure SerDes with port parameters
+ * For BaseR, the serdes driver supports 10GGBASE-R and speed 5G/10G/25G
+ */
+ portmode = conf->portmode;
+ if (sparx5_is_baser(conf->portmode))
+ portmode = PHY_INTERFACE_MODE_10GBASER;
+ err = phy_set_mode_ext(port->serdes, PHY_MODE_ETHERNET, portmode);
+ if (err)
+ return err;
+ conf->serdes_reset = false;
+ return err;
+}
+
+static int sparx5_port_pcs_low_set(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_config *conf)
+{
+ bool sgmii = false, inband_aneg = false;
+ int err;
+
+ if (port->conf.inband) {
+ if (conf->portmode == PHY_INTERFACE_MODE_SGMII ||
+ conf->portmode == PHY_INTERFACE_MODE_QSGMII)
+ inband_aneg = true; /* Cisco-SGMII in-band-aneg */
+ else if (conf->portmode == PHY_INTERFACE_MODE_1000BASEX &&
+ conf->autoneg)
+ inband_aneg = true; /* Clause-37 in-band-aneg */
+
+ err = sparx5_serdes_set(sparx5, port, conf);
+ if (err)
+ return -EINVAL;
+ } else {
+ sgmii = true; /* Phy is connnected to the MAC */
+ }
+
+ /* Choose SGMII or 1000BaseX/2500BaseX PCS mode */
+ spx5_rmw(DEV2G5_PCS1G_MODE_CFG_SGMII_MODE_ENA_SET(sgmii),
+ DEV2G5_PCS1G_MODE_CFG_SGMII_MODE_ENA,
+ sparx5,
+ DEV2G5_PCS1G_MODE_CFG(port->portno));
+
+ /* Enable PCS */
+ spx5_wr(DEV2G5_PCS1G_CFG_PCS_ENA_SET(1),
+ sparx5,
+ DEV2G5_PCS1G_CFG(port->portno));
+
+ if (inband_aneg) {
+ u16 abil = sparx5_get_aneg_word(conf);
+
+ /* Enable in-band aneg */
+ spx5_wr(DEV2G5_PCS1G_ANEG_CFG_ADV_ABILITY_SET(abil) |
+ DEV2G5_PCS1G_ANEG_CFG_SW_RESOLVE_ENA_SET(1) |
+ DEV2G5_PCS1G_ANEG_CFG_ANEG_ENA_SET(1) |
+ DEV2G5_PCS1G_ANEG_CFG_ANEG_RESTART_ONE_SHOT_SET(1),
+ sparx5,
+ DEV2G5_PCS1G_ANEG_CFG(port->portno));
+ } else {
+ spx5_wr(0, sparx5, DEV2G5_PCS1G_ANEG_CFG(port->portno));
+ }
+
+ /* Take PCS out of reset */
+ spx5_rmw(DEV2G5_DEV_RST_CTRL_SPEED_SEL_SET(2) |
+ DEV2G5_DEV_RST_CTRL_PCS_TX_RST_SET(0) |
+ DEV2G5_DEV_RST_CTRL_PCS_RX_RST_SET(0),
+ DEV2G5_DEV_RST_CTRL_SPEED_SEL |
+ DEV2G5_DEV_RST_CTRL_PCS_TX_RST |
+ DEV2G5_DEV_RST_CTRL_PCS_RX_RST,
+ sparx5,
+ DEV2G5_DEV_RST_CTRL(port->portno));
+
+ return 0;
+}
+
+static int sparx5_port_pcs_high_set(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_config *conf)
+{
+ u32 clk_spd = conf->portmode == PHY_INTERFACE_MODE_5GBASER ? 1 : 0;
+ u32 pix = sparx5_port_dev_index(port->portno);
+ u32 dev = sparx5_to_high_dev(port->portno);
+ u32 pcs = sparx5_to_pcs_dev(port->portno);
+ void __iomem *devinst;
+ void __iomem *pcsinst;
+ int err;
+
+ devinst = spx5_inst_get(sparx5, dev, pix);
+ pcsinst = spx5_inst_get(sparx5, pcs, pix);
+
+ /* SFI : No in-band-aneg. Speeds 5G/10G/25G */
+ err = sparx5_serdes_set(sparx5, port, conf);
+ if (err)
+ return -EINVAL;
+ if (conf->portmode == PHY_INTERFACE_MODE_25GBASER) {
+ /* Enable PCS for 25G device, speed 25G */
+ spx5_rmw(DEV25G_PCS25G_CFG_PCS25G_ENA_SET(1),
+ DEV25G_PCS25G_CFG_PCS25G_ENA,
+ sparx5,
+ DEV25G_PCS25G_CFG(pix));
+ } else {
+ /* Enable PCS for 5G/10G/25G devices, speed 5G/10G */
+ spx5_inst_rmw(PCS10G_BR_PCS_CFG_PCS_ENA_SET(1),
+ PCS10G_BR_PCS_CFG_PCS_ENA,
+ pcsinst,
+ PCS10G_BR_PCS_CFG(0));
+ }
+
+ /* Enable 5G/10G/25G MAC module */
+ spx5_inst_wr(DEV10G_MAC_ENA_CFG_RX_ENA_SET(1) |
+ DEV10G_MAC_ENA_CFG_TX_ENA_SET(1),
+ devinst,
+ DEV10G_MAC_ENA_CFG(0));
+
+ /* Take the device out of reset */
+ spx5_inst_rmw(DEV10G_DEV_RST_CTRL_PCS_RX_RST_SET(0) |
+ DEV10G_DEV_RST_CTRL_PCS_TX_RST_SET(0) |
+ DEV10G_DEV_RST_CTRL_MAC_RX_RST_SET(0) |
+ DEV10G_DEV_RST_CTRL_MAC_TX_RST_SET(0) |
+ DEV10G_DEV_RST_CTRL_SPEED_SEL_SET(clk_spd),
+ DEV10G_DEV_RST_CTRL_PCS_RX_RST |
+ DEV10G_DEV_RST_CTRL_PCS_TX_RST |
+ DEV10G_DEV_RST_CTRL_MAC_RX_RST |
+ DEV10G_DEV_RST_CTRL_MAC_TX_RST |
+ DEV10G_DEV_RST_CTRL_SPEED_SEL,
+ devinst,
+ DEV10G_DEV_RST_CTRL(0));
+
+ return 0;
+}
+
+/* Switch between 1G/2500 and 5G/10G/25G devices */
+static void sparx5_dev_switch(struct sparx5 *sparx5, int port, bool hsd)
+{
+ int bt_indx = BIT(sparx5_port_dev_index(port));
+
+ if (sparx5_port_is_5g(port)) {
+ spx5_rmw(hsd ? 0 : bt_indx,
+ bt_indx,
+ sparx5,
+ PORT_CONF_DEV5G_MODES);
+ } else if (sparx5_port_is_10g(port)) {
+ spx5_rmw(hsd ? 0 : bt_indx,
+ bt_indx,
+ sparx5,
+ PORT_CONF_DEV10G_MODES);
+ } else if (sparx5_port_is_25g(port)) {
+ spx5_rmw(hsd ? 0 : bt_indx,
+ bt_indx,
+ sparx5,
+ PORT_CONF_DEV25G_MODES);
+ }
+}
+
+/* Configure speed/duplex dependent registers */
+static int sparx5_port_config_low_set(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_config *conf)
+{
+ u32 clk_spd, gig_mode, tx_gap, hdx_gap_1, hdx_gap_2;
+ bool fdx = conf->duplex == DUPLEX_FULL;
+ int spd = conf->speed;
+
+ clk_spd = spd == SPEED_10 ? 0 : spd == SPEED_100 ? 1 : 2;
+ gig_mode = spd == SPEED_1000 || spd == SPEED_2500;
+ tx_gap = spd == SPEED_1000 ? 4 : fdx ? 6 : 5;
+ hdx_gap_1 = spd == SPEED_1000 ? 0 : spd == SPEED_100 ? 1 : 2;
+ hdx_gap_2 = spd == SPEED_1000 ? 0 : spd == SPEED_100 ? 4 : 1;
+
+ /* GIG/FDX mode */
+ spx5_rmw(DEV2G5_MAC_MODE_CFG_GIGA_MODE_ENA_SET(gig_mode) |
+ DEV2G5_MAC_MODE_CFG_FDX_ENA_SET(fdx),
+ DEV2G5_MAC_MODE_CFG_GIGA_MODE_ENA |
+ DEV2G5_MAC_MODE_CFG_FDX_ENA,
+ sparx5,
+ DEV2G5_MAC_MODE_CFG(port->portno));
+
+ /* Set MAC IFG Gaps */
+ spx5_wr(DEV2G5_MAC_IFG_CFG_TX_IFG_SET(tx_gap) |
+ DEV2G5_MAC_IFG_CFG_RX_IFG1_SET(hdx_gap_1) |
+ DEV2G5_MAC_IFG_CFG_RX_IFG2_SET(hdx_gap_2),
+ sparx5,
+ DEV2G5_MAC_IFG_CFG(port->portno));
+
+ /* Disabling frame aging when in HDX (due to HDX issue) */
+ spx5_rmw(HSCH_PORT_MODE_AGE_DIS_SET(fdx == 0),
+ HSCH_PORT_MODE_AGE_DIS,
+ sparx5,
+ HSCH_PORT_MODE(port->portno));
+
+ /* Enable MAC module */
+ spx5_wr(DEV2G5_MAC_ENA_CFG_RX_ENA |
+ DEV2G5_MAC_ENA_CFG_TX_ENA,
+ sparx5,
+ DEV2G5_MAC_ENA_CFG(port->portno));
+
+ /* Select speed and take MAC out of reset */
+ spx5_rmw(DEV2G5_DEV_RST_CTRL_SPEED_SEL_SET(clk_spd) |
+ DEV2G5_DEV_RST_CTRL_MAC_TX_RST_SET(0) |
+ DEV2G5_DEV_RST_CTRL_MAC_RX_RST_SET(0),
+ DEV2G5_DEV_RST_CTRL_SPEED_SEL |
+ DEV2G5_DEV_RST_CTRL_MAC_TX_RST |
+ DEV2G5_DEV_RST_CTRL_MAC_RX_RST,
+ sparx5,
+ DEV2G5_DEV_RST_CTRL(port->portno));
+
+ return 0;
+}
+
+int sparx5_port_pcs_set(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_config *conf)
+
+{
+ bool high_speed_dev = sparx5_is_baser(conf->portmode);
+ int err;
+
+ if (sparx5_dev_change(sparx5, port, conf)) {
+ /* switch device */
+ sparx5_dev_switch(sparx5, port->portno, high_speed_dev);
+
+ /* Disable the not-in-use device */
+ err = sparx5_port_disable(sparx5, port, !high_speed_dev);
+ if (err)
+ return err;
+ }
+ /* Disable the port before re-configuring */
+ err = sparx5_port_disable(sparx5, port, high_speed_dev);
+ if (err)
+ return -EINVAL;
+
+ if (high_speed_dev)
+ err = sparx5_port_pcs_high_set(sparx5, port, conf);
+ else
+ err = sparx5_port_pcs_low_set(sparx5, port, conf);
+
+ if (err)
+ return -EINVAL;
+
+ if (port->conf.inband) {
+ /* Enable/disable 1G counters in ASM */
+ spx5_rmw(ASM_PORT_CFG_CSC_STAT_DIS_SET(high_speed_dev),
+ ASM_PORT_CFG_CSC_STAT_DIS,
+ sparx5,
+ ASM_PORT_CFG(port->portno));
+
+ /* Enable/disable 1G counters in DSM */
+ spx5_rmw(DSM_BUF_CFG_CSC_STAT_DIS_SET(high_speed_dev),
+ DSM_BUF_CFG_CSC_STAT_DIS,
+ sparx5,
+ DSM_BUF_CFG(port->portno));
+ }
+
+ port->conf = *conf;
+
+ return 0;
+}
+
+int sparx5_port_config(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_config *conf)
+{
+ bool high_speed_dev = sparx5_is_baser(conf->portmode);
+ int err, urgency, stop_wm;
+
+ err = sparx5_port_verify_speed(sparx5, port, conf);
+ if (err)
+ return err;
+
+ /* high speed device is already configured */
+ if (!high_speed_dev)
+ sparx5_port_config_low_set(sparx5, port, conf);
+
+ /* Configure flow control */
+ err = sparx5_port_fc_setup(sparx5, port, conf);
+ if (err)
+ return err;
+
+ /* Set the DSM stop watermark */
+ stop_wm = sparx5_port_fifo_sz(sparx5, port->portno, conf->speed);
+ spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM_SET(stop_wm),
+ DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM,
+ sparx5,
+ DSM_DEV_TX_STOP_WM_CFG(port->portno));
+
+ /* Enable port in queue system */
+ urgency = sparx5_port_fwd_urg(sparx5, conf->speed);
+ spx5_rmw(QFWD_SWITCH_PORT_MODE_PORT_ENA_SET(1) |
+ QFWD_SWITCH_PORT_MODE_FWD_URGENCY_SET(urgency),
+ QFWD_SWITCH_PORT_MODE_PORT_ENA |
+ QFWD_SWITCH_PORT_MODE_FWD_URGENCY,
+ sparx5,
+ QFWD_SWITCH_PORT_MODE(port->portno));
+
+ /* Save the new values */
+ port->conf = *conf;
+
+ return 0;
+}
+
+/* Initialize port config to default */
+int sparx5_port_init(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_config *conf)
+{
+ u32 pause_start = sparx5_wm_enc(6 * (ETH_MAXLEN / SPX5_BUFFER_CELL_SZ));
+ u32 atop = sparx5_wm_enc(20 * (ETH_MAXLEN / SPX5_BUFFER_CELL_SZ));
+ u32 devhigh = sparx5_to_high_dev(port->portno);
+ u32 pix = sparx5_port_dev_index(port->portno);
+ u32 pcs = sparx5_to_pcs_dev(port->portno);
+ bool sd_pol = port->signd_active_high;
+ bool sd_sel = !port->signd_internal;
+ bool sd_ena = port->signd_enable;
+ u32 pause_stop = 0xFFF - 1; /* FC generate disabled */
+ void __iomem *devinst;
+ void __iomem *pcsinst;
+ int err;
+
+ devinst = spx5_inst_get(sparx5, devhigh, pix);
+ pcsinst = spx5_inst_get(sparx5, pcs, pix);
+
+ /* Set the mux port mode */
+ err = sparx5_port_mux_set(sparx5, port, conf);
+ if (err)
+ return err;
+
+ /* Configure MAC vlan awareness */
+ err = sparx5_port_max_tags_set(sparx5, port);
+ if (err)
+ return err;
+
+ /* Set Max Length */
+ spx5_rmw(DEV2G5_MAC_MAXLEN_CFG_MAX_LEN_SET(ETH_MAXLEN),
+ DEV2G5_MAC_MAXLEN_CFG_MAX_LEN,
+ sparx5,
+ DEV2G5_MAC_MAXLEN_CFG(port->portno));
+
+ /* 1G/2G5: Signal Detect configuration */
+ spx5_wr(DEV2G5_PCS1G_SD_CFG_SD_POL_SET(sd_pol) |
+ DEV2G5_PCS1G_SD_CFG_SD_SEL_SET(sd_sel) |
+ DEV2G5_PCS1G_SD_CFG_SD_ENA_SET(sd_ena),
+ sparx5,
+ DEV2G5_PCS1G_SD_CFG(port->portno));
+
+ /* Set Pause WM hysteresis */
+ spx5_rmw(QSYS_PAUSE_CFG_PAUSE_START_SET(pause_start) |
+ QSYS_PAUSE_CFG_PAUSE_STOP_SET(pause_stop) |
+ QSYS_PAUSE_CFG_PAUSE_ENA_SET(1),
+ QSYS_PAUSE_CFG_PAUSE_START |
+ QSYS_PAUSE_CFG_PAUSE_STOP |
+ QSYS_PAUSE_CFG_PAUSE_ENA,
+ sparx5,
+ QSYS_PAUSE_CFG(port->portno));
+
+ /* Port ATOP. Frames are tail dropped when this WM is hit */
+ spx5_wr(QSYS_ATOP_ATOP_SET(atop),
+ sparx5,
+ QSYS_ATOP(port->portno));
+
+ /* Discard pause frame 01-80-C2-00-00-01 */
+ spx5_wr(PAUSE_DISCARD, sparx5, ANA_CL_CAPTURE_BPDU_CFG(port->portno));
+
+ if (conf->portmode == PHY_INTERFACE_MODE_QSGMII ||
+ conf->portmode == PHY_INTERFACE_MODE_SGMII) {
+ err = sparx5_serdes_set(sparx5, port, conf);
+ if (err)
+ return err;
+
+ if (!sparx5_port_is_2g5(port->portno))
+ /* Enable shadow device */
+ spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA_SET(1),
+ DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA,
+ sparx5,
+ DSM_DEV_TX_STOP_WM_CFG(port->portno));
+
+ sparx5_dev_switch(sparx5, port->portno, false);
+ }
+ if (conf->portmode == PHY_INTERFACE_MODE_QSGMII) {
+ // All ports must be PCS enabled in QSGMII mode
+ spx5_rmw(DEV2G5_DEV_RST_CTRL_PCS_TX_RST_SET(0),
+ DEV2G5_DEV_RST_CTRL_PCS_TX_RST,
+ sparx5,
+ DEV2G5_DEV_RST_CTRL(port->portno));
+ }
+ /* Default IFGs for 1G */
+ spx5_wr(DEV2G5_MAC_IFG_CFG_TX_IFG_SET(6) |
+ DEV2G5_MAC_IFG_CFG_RX_IFG1_SET(0) |
+ DEV2G5_MAC_IFG_CFG_RX_IFG2_SET(0),
+ sparx5,
+ DEV2G5_MAC_IFG_CFG(port->portno));
+
+ if (sparx5_port_is_2g5(port->portno))
+ return 0; /* Low speed device only - return */
+
+ /* Now setup the high speed device */
+ if (conf->portmode == PHY_INTERFACE_MODE_NA)
+ conf->portmode = PHY_INTERFACE_MODE_10GBASER;
+
+ if (sparx5_is_baser(conf->portmode))
+ sparx5_dev_switch(sparx5, port->portno, true);
+
+ /* Set Max Length */
+ spx5_inst_rmw(DEV10G_MAC_MAXLEN_CFG_MAX_LEN_SET(ETH_MAXLEN),
+ DEV10G_MAC_MAXLEN_CFG_MAX_LEN,
+ devinst,
+ DEV10G_MAC_ENA_CFG(0));
+
+ /* Handle Signal Detect in 10G PCS */
+ spx5_inst_wr(PCS10G_BR_PCS_SD_CFG_SD_POL_SET(sd_pol) |
+ PCS10G_BR_PCS_SD_CFG_SD_SEL_SET(sd_sel) |
+ PCS10G_BR_PCS_SD_CFG_SD_ENA_SET(sd_ena),
+ pcsinst,
+ PCS10G_BR_PCS_SD_CFG(0));
+
+ if (sparx5_port_is_25g(port->portno)) {
+ /* Handle Signal Detect in 25G PCS */
+ spx5_wr(DEV25G_PCS25G_SD_CFG_SD_POL_SET(sd_pol) |
+ DEV25G_PCS25G_SD_CFG_SD_SEL_SET(sd_sel) |
+ DEV25G_PCS25G_SD_CFG_SD_ENA_SET(sd_ena),
+ sparx5,
+ DEV25G_PCS25G_SD_CFG(pix));
+ }
+
+ return 0;
+}
+
+void sparx5_port_enable(struct sparx5_port *port, bool enable)
+{
+ struct sparx5 *sparx5 = port->sparx5;
+
+ /* Enable port for frame transfer? */
+ spx5_rmw(QFWD_SWITCH_PORT_MODE_PORT_ENA_SET(enable),
+ QFWD_SWITCH_PORT_MODE_PORT_ENA,
+ sparx5,
+ QFWD_SWITCH_PORT_MODE(port->portno));
+}
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_port.h b/drivers/net/ethernet/microchip/sparx5/sparx5_port.h
new file mode 100644
index 000000000000..fd05ab6436d1
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_port.h
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#ifndef __SPARX5_PORT_H__
+#define __SPARX5_PORT_H__
+
+#include "sparx5_main.h"
+
+static inline bool sparx5_port_is_2g5(int portno)
+{
+ return portno >= 16 && portno <= 47;
+}
+
+static inline bool sparx5_port_is_5g(int portno)
+{
+ return portno <= 11 || portno == 64;
+}
+
+static inline bool sparx5_port_is_10g(int portno)
+{
+ return (portno >= 12 && portno <= 15) || (portno >= 48 && portno <= 55);
+}
+
+static inline bool sparx5_port_is_25g(int portno)
+{
+ return portno >= 56 && portno <= 63;
+}
+
+static inline u32 sparx5_to_high_dev(int port)
+{
+ if (sparx5_port_is_5g(port))
+ return TARGET_DEV5G;
+ if (sparx5_port_is_10g(port))
+ return TARGET_DEV10G;
+ return TARGET_DEV25G;
+}
+
+static inline u32 sparx5_to_pcs_dev(int port)
+{
+ if (sparx5_port_is_5g(port))
+ return TARGET_PCS5G_BR;
+ if (sparx5_port_is_10g(port))
+ return TARGET_PCS10G_BR;
+ return TARGET_PCS25G_BR;
+}
+
+static inline int sparx5_port_dev_index(int port)
+{
+ if (sparx5_port_is_2g5(port))
+ return port;
+ if (sparx5_port_is_5g(port))
+ return (port <= 11 ? port : 12);
+ if (sparx5_port_is_10g(port))
+ return (port >= 12 && port <= 15) ?
+ port - 12 : port - 44;
+ return (port - 56);
+}
+
+int sparx5_port_init(struct sparx5 *sparx5,
+ struct sparx5_port *spx5_port,
+ struct sparx5_port_config *conf);
+
+int sparx5_port_config(struct sparx5 *sparx5,
+ struct sparx5_port *spx5_port,
+ struct sparx5_port_config *conf);
+
+int sparx5_port_pcs_set(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_config *conf);
+
+int sparx5_serdes_set(struct sparx5 *sparx5,
+ struct sparx5_port *spx5_port,
+ struct sparx5_port_config *conf);
+
+struct sparx5_port_status {
+ bool link;
+ bool link_down;
+ int speed;
+ bool an_complete;
+ int duplex;
+ int pause;
+};
+
+int sparx5_get_port_status(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ struct sparx5_port_status *status);
+
+void sparx5_port_enable(struct sparx5_port *port, bool enable);
+
+#endif /* __SPARX5_PORT_H__ */
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c b/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c
new file mode 100644
index 000000000000..a72e3b3b596e
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c
@@ -0,0 +1,510 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include <linux/if_bridge.h>
+#include <net/switchdev.h>
+
+#include "sparx5_main_regs.h"
+#include "sparx5_main.h"
+
+static struct workqueue_struct *sparx5_owq;
+
+struct sparx5_switchdev_event_work {
+ struct work_struct work;
+ struct switchdev_notifier_fdb_info fdb_info;
+ struct net_device *dev;
+ unsigned long event;
+};
+
+static void sparx5_port_attr_bridge_flags(struct sparx5_port *port,
+ struct switchdev_brport_flags flags)
+{
+ if (flags.mask & BR_MCAST_FLOOD)
+ sparx5_pgid_update_mask(port, PGID_MC_FLOOD, true);
+}
+
+static void sparx5_attr_stp_state_set(struct sparx5_port *port,
+ u8 state)
+{
+ struct sparx5 *sparx5 = port->sparx5;
+
+ if (!test_bit(port->portno, sparx5->bridge_mask)) {
+ netdev_err(port->ndev,
+ "Controlling non-bridged port %d?\n", port->portno);
+ return;
+ }
+
+ switch (state) {
+ case BR_STATE_FORWARDING:
+ set_bit(port->portno, sparx5->bridge_fwd_mask);
+ fallthrough;
+ case BR_STATE_LEARNING:
+ set_bit(port->portno, sparx5->bridge_lrn_mask);
+ break;
+
+ default:
+ /* All other states treated as blocking */
+ clear_bit(port->portno, sparx5->bridge_fwd_mask);
+ clear_bit(port->portno, sparx5->bridge_lrn_mask);
+ break;
+ }
+
+ /* apply the bridge_fwd_mask to all the ports */
+ sparx5_update_fwd(sparx5);
+}
+
+static void sparx5_port_attr_ageing_set(struct sparx5_port *port,
+ unsigned long ageing_clock_t)
+{
+ unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
+ u32 ageing_time = jiffies_to_msecs(ageing_jiffies);
+
+ sparx5_set_ageing(port->sparx5, ageing_time);
+}
+
+static int sparx5_port_attr_set(struct net_device *dev, const void *ctx,
+ const struct switchdev_attr *attr,
+ struct netlink_ext_ack *extack)
+{
+ struct sparx5_port *port = netdev_priv(dev);
+
+ switch (attr->id) {
+ case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
+ sparx5_port_attr_bridge_flags(port, attr->u.brport_flags);
+ break;
+ case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
+ sparx5_attr_stp_state_set(port, attr->u.stp_state);
+ break;
+ case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
+ sparx5_port_attr_ageing_set(port, attr->u.ageing_time);
+ break;
+ case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
+ port->vlan_aware = attr->u.vlan_filtering;
+ sparx5_vlan_port_apply(port->sparx5, port);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int sparx5_port_bridge_join(struct sparx5_port *port,
+ struct net_device *bridge)
+{
+ struct sparx5 *sparx5 = port->sparx5;
+
+ if (bitmap_empty(sparx5->bridge_mask, SPX5_PORTS))
+ /* First bridged port */
+ sparx5->hw_bridge_dev = bridge;
+ else
+ if (sparx5->hw_bridge_dev != bridge)
+ /* This is adding the port to a second bridge, this is
+ * unsupported
+ */
+ return -ENODEV;
+
+ set_bit(port->portno, sparx5->bridge_mask);
+
+ /* Port enters in bridge mode therefor don't need to copy to CPU
+ * frames for multicast in case the bridge is not requesting them
+ */
+ __dev_mc_unsync(port->ndev, sparx5_mc_unsync);
+
+ return 0;
+}
+
+static void sparx5_port_bridge_leave(struct sparx5_port *port,
+ struct net_device *bridge)
+{
+ struct sparx5 *sparx5 = port->sparx5;
+
+ clear_bit(port->portno, sparx5->bridge_mask);
+ if (bitmap_empty(sparx5->bridge_mask, SPX5_PORTS))
+ sparx5->hw_bridge_dev = NULL;
+
+ /* Clear bridge vlan settings before updating the port settings */
+ port->vlan_aware = 0;
+ port->pvid = NULL_VID;
+ port->vid = NULL_VID;
+
+ /* Port enters in host more therefore restore mc list */
+ __dev_mc_sync(port->ndev, sparx5_mc_sync, sparx5_mc_unsync);
+}
+
+static int sparx5_port_changeupper(struct net_device *dev,
+ struct netdev_notifier_changeupper_info *info)
+{
+ struct sparx5_port *port = netdev_priv(dev);
+ int err = 0;
+
+ if (netif_is_bridge_master(info->upper_dev)) {
+ if (info->linking)
+ err = sparx5_port_bridge_join(port, info->upper_dev);
+ else
+ sparx5_port_bridge_leave(port, info->upper_dev);
+
+ sparx5_vlan_port_apply(port->sparx5, port);
+ }
+
+ return err;
+}
+
+static int sparx5_port_add_addr(struct net_device *dev, bool up)
+{
+ struct sparx5_port *port = netdev_priv(dev);
+ struct sparx5 *sparx5 = port->sparx5;
+ u16 vid = port->pvid;
+
+ if (up)
+ sparx5_mact_learn(sparx5, PGID_CPU, port->ndev->dev_addr, vid);
+ else
+ sparx5_mact_forget(sparx5, port->ndev->dev_addr, vid);
+
+ return 0;
+}
+
+static int sparx5_netdevice_port_event(struct net_device *dev,
+ struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ int err = 0;
+
+ if (!sparx5_netdevice_check(dev))
+ return 0;
+
+ switch (event) {
+ case NETDEV_CHANGEUPPER:
+ err = sparx5_port_changeupper(dev, ptr);
+ break;
+ case NETDEV_PRE_UP:
+ err = sparx5_port_add_addr(dev, true);
+ break;
+ case NETDEV_DOWN:
+ err = sparx5_port_add_addr(dev, false);
+ break;
+ }
+
+ return err;
+}
+
+static int sparx5_netdevice_event(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ int ret = 0;
+
+ ret = sparx5_netdevice_port_event(dev, nb, event, ptr);
+
+ return notifier_from_errno(ret);
+}
+
+static void sparx5_switchdev_bridge_fdb_event_work(struct work_struct *work)
+{
+ struct sparx5_switchdev_event_work *switchdev_work =
+ container_of(work, struct sparx5_switchdev_event_work, work);
+ struct net_device *dev = switchdev_work->dev;
+ struct switchdev_notifier_fdb_info *fdb_info;
+ struct sparx5_port *port;
+ struct sparx5 *sparx5;
+
+ rtnl_lock();
+ if (!sparx5_netdevice_check(dev))
+ goto out;
+
+ port = netdev_priv(dev);
+ sparx5 = port->sparx5;
+
+ fdb_info = &switchdev_work->fdb_info;
+
+ switch (switchdev_work->event) {
+ case SWITCHDEV_FDB_ADD_TO_DEVICE:
+ if (!fdb_info->added_by_user)
+ break;
+ sparx5_add_mact_entry(sparx5, port, fdb_info->addr,
+ fdb_info->vid);
+ break;
+ case SWITCHDEV_FDB_DEL_TO_DEVICE:
+ if (!fdb_info->added_by_user)
+ break;
+ sparx5_del_mact_entry(sparx5, fdb_info->addr, fdb_info->vid);
+ break;
+ }
+
+out:
+ rtnl_unlock();
+ kfree(switchdev_work->fdb_info.addr);
+ kfree(switchdev_work);
+ dev_put(dev);
+}
+
+static void sparx5_schedule_work(struct work_struct *work)
+{
+ queue_work(sparx5_owq, work);
+}
+
+static int sparx5_switchdev_event(struct notifier_block *unused,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+ struct sparx5_switchdev_event_work *switchdev_work;
+ struct switchdev_notifier_fdb_info *fdb_info;
+ struct switchdev_notifier_info *info = ptr;
+ int err;
+
+ switch (event) {
+ case SWITCHDEV_PORT_ATTR_SET:
+ err = switchdev_handle_port_attr_set(dev, ptr,
+ sparx5_netdevice_check,
+ sparx5_port_attr_set);
+ return notifier_from_errno(err);
+ case SWITCHDEV_FDB_ADD_TO_DEVICE:
+ fallthrough;
+ case SWITCHDEV_FDB_DEL_TO_DEVICE:
+ switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
+ if (!switchdev_work)
+ return NOTIFY_BAD;
+
+ switchdev_work->dev = dev;
+ switchdev_work->event = event;
+
+ fdb_info = container_of(info,
+ struct switchdev_notifier_fdb_info,
+ info);
+ INIT_WORK(&switchdev_work->work,
+ sparx5_switchdev_bridge_fdb_event_work);
+ memcpy(&switchdev_work->fdb_info, ptr,
+ sizeof(switchdev_work->fdb_info));
+ switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
+ if (!switchdev_work->fdb_info.addr)
+ goto err_addr_alloc;
+
+ ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
+ fdb_info->addr);
+ dev_hold(dev);
+
+ sparx5_schedule_work(&switchdev_work->work);
+ break;
+ }
+
+ return NOTIFY_DONE;
+err_addr_alloc:
+ kfree(switchdev_work);
+ return NOTIFY_BAD;
+}
+
+static void sparx5_sync_port_dev_addr(struct sparx5 *sparx5,
+ struct sparx5_port *port,
+ u16 vid, bool add)
+{
+ if (!port ||
+ !test_bit(port->portno, sparx5->bridge_mask))
+ return; /* Skip null/host interfaces */
+
+ /* Bridge connects to vid? */
+ if (add) {
+ /* Add port MAC address from the VLAN */
+ sparx5_mact_learn(sparx5, PGID_CPU,
+ port->ndev->dev_addr, vid);
+ } else {
+ /* Control port addr visibility depending on
+ * port VLAN connectivity.
+ */
+ if (test_bit(port->portno, sparx5->vlan_mask[vid]))
+ sparx5_mact_learn(sparx5, PGID_CPU,
+ port->ndev->dev_addr, vid);
+ else
+ sparx5_mact_forget(sparx5,
+ port->ndev->dev_addr, vid);
+ }
+}
+
+static void sparx5_sync_bridge_dev_addr(struct net_device *dev,
+ struct sparx5 *sparx5,
+ u16 vid, bool add)
+{
+ int i;
+
+ /* First, handle bridge address'es */
+ if (add) {
+ sparx5_mact_learn(sparx5, PGID_CPU, dev->dev_addr,
+ vid);
+ sparx5_mact_learn(sparx5, PGID_BCAST, dev->broadcast,
+ vid);
+ } else {
+ sparx5_mact_forget(sparx5, dev->dev_addr, vid);
+ sparx5_mact_forget(sparx5, dev->broadcast, vid);
+ }
+
+ /* Now look at bridged ports */
+ for (i = 0; i < SPX5_PORTS; i++)
+ sparx5_sync_port_dev_addr(sparx5, sparx5->ports[i], vid, add);
+}
+
+static int sparx5_handle_port_vlan_add(struct net_device *dev,
+ struct notifier_block *nb,
+ const struct switchdev_obj_port_vlan *v)
+{
+ struct sparx5_port *port = netdev_priv(dev);
+
+ if (netif_is_bridge_master(dev)) {
+ if (v->flags & BRIDGE_VLAN_INFO_BRENTRY) {
+ struct sparx5 *sparx5 =
+ container_of(nb, struct sparx5,
+ switchdev_blocking_nb);
+
+ sparx5_sync_bridge_dev_addr(dev, sparx5, v->vid, true);
+ }
+ return 0;
+ }
+
+ if (!sparx5_netdevice_check(dev))
+ return -EOPNOTSUPP;
+
+ return sparx5_vlan_vid_add(port, v->vid,
+ v->flags & BRIDGE_VLAN_INFO_PVID,
+ v->flags & BRIDGE_VLAN_INFO_UNTAGGED);
+}
+
+static int sparx5_handle_port_obj_add(struct net_device *dev,
+ struct notifier_block *nb,
+ struct switchdev_notifier_port_obj_info *info)
+{
+ const struct switchdev_obj *obj = info->obj;
+ int err;
+
+ switch (obj->id) {
+ case SWITCHDEV_OBJ_ID_PORT_VLAN:
+ err = sparx5_handle_port_vlan_add(dev, nb,
+ SWITCHDEV_OBJ_PORT_VLAN(obj));
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ info->handled = true;
+ return err;
+}
+
+static int sparx5_handle_port_vlan_del(struct net_device *dev,
+ struct notifier_block *nb,
+ u16 vid)
+{
+ struct sparx5_port *port = netdev_priv(dev);
+ int ret;
+
+ /* Master bridge? */
+ if (netif_is_bridge_master(dev)) {
+ struct sparx5 *sparx5 =
+ container_of(nb, struct sparx5,
+ switchdev_blocking_nb);
+
+ sparx5_sync_bridge_dev_addr(dev, sparx5, vid, false);
+ return 0;
+ }
+
+ if (!sparx5_netdevice_check(dev))
+ return -EOPNOTSUPP;
+
+ ret = sparx5_vlan_vid_del(port, vid);
+ if (ret)
+ return ret;
+
+ /* Delete the port MAC address with the matching VLAN information */
+ sparx5_mact_forget(port->sparx5, port->ndev->dev_addr, vid);
+
+ return 0;
+}
+
+static int sparx5_handle_port_obj_del(struct net_device *dev,
+ struct notifier_block *nb,
+ struct switchdev_notifier_port_obj_info *info)
+{
+ const struct switchdev_obj *obj = info->obj;
+ int err;
+
+ switch (obj->id) {
+ case SWITCHDEV_OBJ_ID_PORT_VLAN:
+ err = sparx5_handle_port_vlan_del(dev, nb,
+ SWITCHDEV_OBJ_PORT_VLAN(obj)->vid);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ info->handled = true;
+ return err;
+}
+
+static int sparx5_switchdev_blocking_event(struct notifier_block *nb,
+ unsigned long event,
+ void *ptr)
+{
+ struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+ int err;
+
+ switch (event) {
+ case SWITCHDEV_PORT_OBJ_ADD:
+ err = sparx5_handle_port_obj_add(dev, nb, ptr);
+ return notifier_from_errno(err);
+ case SWITCHDEV_PORT_OBJ_DEL:
+ err = sparx5_handle_port_obj_del(dev, nb, ptr);
+ return notifier_from_errno(err);
+ case SWITCHDEV_PORT_ATTR_SET:
+ err = switchdev_handle_port_attr_set(dev, ptr,
+ sparx5_netdevice_check,
+ sparx5_port_attr_set);
+ return notifier_from_errno(err);
+ }
+
+ return NOTIFY_DONE;
+}
+
+int sparx5_register_notifier_blocks(struct sparx5 *s5)
+{
+ int err;
+
+ s5->netdevice_nb.notifier_call = sparx5_netdevice_event;
+ err = register_netdevice_notifier(&s5->netdevice_nb);
+ if (err)
+ return err;
+
+ s5->switchdev_nb.notifier_call = sparx5_switchdev_event;
+ err = register_switchdev_notifier(&s5->switchdev_nb);
+ if (err)
+ goto err_switchdev_nb;
+
+ s5->switchdev_blocking_nb.notifier_call = sparx5_switchdev_blocking_event;
+ err = register_switchdev_blocking_notifier(&s5->switchdev_blocking_nb);
+ if (err)
+ goto err_switchdev_blocking_nb;
+
+ sparx5_owq = alloc_ordered_workqueue("sparx5_order", 0);
+ if (!sparx5_owq) {
+ err = -ENOMEM;
+ goto err_switchdev_blocking_nb;
+ }
+
+ return 0;
+
+err_switchdev_blocking_nb:
+ unregister_switchdev_notifier(&s5->switchdev_nb);
+err_switchdev_nb:
+ unregister_netdevice_notifier(&s5->netdevice_nb);
+
+ return err;
+}
+
+void sparx5_unregister_notifier_blocks(struct sparx5 *s5)
+{
+ destroy_workqueue(sparx5_owq);
+
+ unregister_switchdev_blocking_notifier(&s5->switchdev_blocking_nb);
+ unregister_switchdev_notifier(&s5->switchdev_nb);
+ unregister_netdevice_notifier(&s5->netdevice_nb);
+}
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c
new file mode 100644
index 000000000000..4ce490a25f33
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include "sparx5_main_regs.h"
+#include "sparx5_main.h"
+
+static int sparx5_vlant_set_mask(struct sparx5 *sparx5, u16 vid)
+{
+ u32 mask[3];
+
+ /* Divide up mask in 32 bit words */
+ bitmap_to_arr32(mask, sparx5->vlan_mask[vid], SPX5_PORTS);
+
+ /* Output mask to respective registers */
+ spx5_wr(mask[0], sparx5, ANA_L3_VLAN_MASK_CFG(vid));
+ spx5_wr(mask[1], sparx5, ANA_L3_VLAN_MASK_CFG1(vid));
+ spx5_wr(mask[2], sparx5, ANA_L3_VLAN_MASK_CFG2(vid));
+
+ return 0;
+}
+
+void sparx5_vlan_init(struct sparx5 *sparx5)
+{
+ u16 vid;
+
+ spx5_rmw(ANA_L3_VLAN_CTRL_VLAN_ENA_SET(1),
+ ANA_L3_VLAN_CTRL_VLAN_ENA,
+ sparx5,
+ ANA_L3_VLAN_CTRL);
+
+ /* Map VLAN = FID */
+ for (vid = NULL_VID; vid < VLAN_N_VID; vid++)
+ spx5_rmw(ANA_L3_VLAN_CFG_VLAN_FID_SET(vid),
+ ANA_L3_VLAN_CFG_VLAN_FID,
+ sparx5,
+ ANA_L3_VLAN_CFG(vid));
+}
+
+void sparx5_vlan_port_setup(struct sparx5 *sparx5, int portno)
+{
+ struct sparx5_port *port = sparx5->ports[portno];
+
+ /* Configure PVID */
+ spx5_rmw(ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA_SET(0) |
+ ANA_CL_VLAN_CTRL_PORT_VID_SET(port->pvid),
+ ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA |
+ ANA_CL_VLAN_CTRL_PORT_VID,
+ sparx5,
+ ANA_CL_VLAN_CTRL(port->portno));
+}
+
+int sparx5_vlan_vid_add(struct sparx5_port *port, u16 vid, bool pvid,
+ bool untagged)
+{
+ struct sparx5 *sparx5 = port->sparx5;
+ int ret;
+
+ /* Make the port a member of the VLAN */
+ set_bit(port->portno, sparx5->vlan_mask[vid]);
+ ret = sparx5_vlant_set_mask(sparx5, vid);
+ if (ret)
+ return ret;
+
+ /* Default ingress vlan classification */
+ if (pvid)
+ port->pvid = vid;
+
+ /* Untagged egress vlan classification */
+ if (untagged && port->vid != vid) {
+ if (port->vid) {
+ netdev_err(port->ndev,
+ "Port already has a native VLAN: %d\n",
+ port->vid);
+ return -EBUSY;
+ }
+ port->vid = vid;
+ }
+
+ sparx5_vlan_port_apply(sparx5, port);
+
+ return 0;
+}
+
+int sparx5_vlan_vid_del(struct sparx5_port *port, u16 vid)
+{
+ struct sparx5 *sparx5 = port->sparx5;
+ int ret;
+
+ /* 8021q removes VID 0 on module unload for all interfaces
+ * with VLAN filtering feature. We need to keep it to receive
+ * untagged traffic.
+ */
+ if (vid == 0)
+ return 0;
+
+ /* Stop the port from being a member of the vlan */
+ clear_bit(port->portno, sparx5->vlan_mask[vid]);
+ ret = sparx5_vlant_set_mask(sparx5, vid);
+ if (ret)
+ return ret;
+
+ /* Ingress */
+ if (port->pvid == vid)
+ port->pvid = 0;
+
+ /* Egress */
+ if (port->vid == vid)
+ port->vid = 0;
+
+ sparx5_vlan_port_apply(sparx5, port);
+
+ return 0;
+}
+
+void sparx5_pgid_update_mask(struct sparx5_port *port, int pgid, bool enable)
+{
+ struct sparx5 *sparx5 = port->sparx5;
+ u32 val, mask;
+
+ /* mask is spread across 3 registers x 32 bit */
+ if (port->portno < 32) {
+ mask = BIT(port->portno);
+ val = enable ? mask : 0;
+ spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG(pgid));
+ } else if (port->portno < 64) {
+ mask = BIT(port->portno - 32);
+ val = enable ? mask : 0;
+ spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG1(pgid));
+ } else if (port->portno < SPX5_PORTS) {
+ mask = BIT(port->portno - 64);
+ val = enable ? mask : 0;
+ spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG2(pgid));
+ } else {
+ netdev_err(port->ndev, "Invalid port no: %d\n", port->portno);
+ }
+}
+
+void sparx5_update_fwd(struct sparx5 *sparx5)
+{
+ DECLARE_BITMAP(workmask, SPX5_PORTS);
+ u32 mask[3];
+ int port;
+
+ /* Divide up fwd mask in 32 bit words */
+ bitmap_to_arr32(mask, sparx5->bridge_fwd_mask, SPX5_PORTS);
+
+ /* Update flood masks */
+ for (port = PGID_UC_FLOOD; port <= PGID_BCAST; port++) {
+ spx5_wr(mask[0], sparx5, ANA_AC_PGID_CFG(port));
+ spx5_wr(mask[1], sparx5, ANA_AC_PGID_CFG1(port));
+ spx5_wr(mask[2], sparx5, ANA_AC_PGID_CFG2(port));
+ }
+
+ /* Update SRC masks */
+ for (port = 0; port < SPX5_PORTS; port++) {
+ if (test_bit(port, sparx5->bridge_fwd_mask)) {
+ /* Allow to send to all bridged but self */
+ bitmap_copy(workmask, sparx5->bridge_fwd_mask, SPX5_PORTS);
+ clear_bit(port, workmask);
+ bitmap_to_arr32(mask, workmask, SPX5_PORTS);
+ spx5_wr(mask[0], sparx5, ANA_AC_SRC_CFG(port));
+ spx5_wr(mask[1], sparx5, ANA_AC_SRC_CFG1(port));
+ spx5_wr(mask[2], sparx5, ANA_AC_SRC_CFG2(port));
+ } else {
+ spx5_wr(0, sparx5, ANA_AC_SRC_CFG(port));
+ spx5_wr(0, sparx5, ANA_AC_SRC_CFG1(port));
+ spx5_wr(0, sparx5, ANA_AC_SRC_CFG2(port));
+ }
+ }
+
+ /* Learning enabled only for bridged ports */
+ bitmap_and(workmask, sparx5->bridge_fwd_mask,
+ sparx5->bridge_lrn_mask, SPX5_PORTS);
+ bitmap_to_arr32(mask, workmask, SPX5_PORTS);
+
+ /* Apply learning mask */
+ spx5_wr(mask[0], sparx5, ANA_L2_AUTO_LRN_CFG);
+ spx5_wr(mask[1], sparx5, ANA_L2_AUTO_LRN_CFG1);
+ spx5_wr(mask[2], sparx5, ANA_L2_AUTO_LRN_CFG2);
+}
+
+void sparx5_vlan_port_apply(struct sparx5 *sparx5,
+ struct sparx5_port *port)
+
+{
+ u32 val;
+
+ /* Configure PVID, vlan aware */
+ val = ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA_SET(port->vlan_aware) |
+ ANA_CL_VLAN_CTRL_VLAN_POP_CNT_SET(port->vlan_aware) |
+ ANA_CL_VLAN_CTRL_PORT_VID_SET(port->pvid);
+ spx5_wr(val, sparx5, ANA_CL_VLAN_CTRL(port->portno));
+
+ val = 0;
+ if (port->vlan_aware && !port->pvid)
+ /* If port is vlan-aware and tagged, drop untagged and
+ * priority tagged frames.
+ */
+ val = ANA_CL_VLAN_FILTER_CTRL_TAG_REQUIRED_ENA_SET(1) |
+ ANA_CL_VLAN_FILTER_CTRL_PRIO_CTAG_DIS_SET(1) |
+ ANA_CL_VLAN_FILTER_CTRL_PRIO_STAG_DIS_SET(1);
+ spx5_wr(val, sparx5,
+ ANA_CL_VLAN_FILTER_CTRL(port->portno, 0));
+
+ /* Egress configuration (REW_TAG_CFG): VLAN tag type to 8021Q */
+ val = REW_TAG_CTRL_TAG_TPID_CFG_SET(0);
+ if (port->vlan_aware) {
+ if (port->vid)
+ /* Tag all frames except when VID == DEFAULT_VLAN */
+ val |= REW_TAG_CTRL_TAG_CFG_SET(1);
+ else
+ val |= REW_TAG_CTRL_TAG_CFG_SET(3);
+ }
+ spx5_wr(val, sparx5, REW_TAG_CTRL(port->portno));
+
+ /* Egress VID */
+ spx5_rmw(REW_PORT_VLAN_CFG_PORT_VID_SET(port->vid),
+ REW_PORT_VLAN_CFG_PORT_VID,
+ sparx5,
+ REW_PORT_VLAN_CFG(port->portno));
+}
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 04d067243457..fff78900fc8a 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -1230,8 +1230,10 @@ static int mana_create_txq(struct mana_port_context *apc,
cq->gdma_id = cq->gdma_cq->id;
- if (WARN_ON(cq->gdma_id >= gc->max_num_cqs))
- return -EINVAL;
+ if (WARN_ON(cq->gdma_id >= gc->max_num_cqs)) {
+ err = -EINVAL;
+ goto out;
+ }
gc->cq_table[cq->gdma_id] = cq->gdma_cq;
@@ -1387,8 +1389,7 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
gc = gd->gdma_context;
- rxq = kzalloc(sizeof(*rxq) +
- RX_BUFFERS_PER_QUEUE * sizeof(struct mana_recv_buf_oob),
+ rxq = kzalloc(struct_size(rxq, rx_oobs, RX_BUFFERS_PER_QUEUE),
GFP_KERNEL);
if (!rxq)
return NULL;
diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c
index b85733942053..49def6934cad 100644
--- a/drivers/net/ethernet/moxa/moxart_ether.c
+++ b/drivers/net/ethernet/moxa/moxart_ether.c
@@ -481,13 +481,12 @@ static int moxart_mac_probe(struct platform_device *pdev)
priv->ndev = ndev;
priv->pdev = pdev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ndev->base_addr = res->start;
- priv->base = devm_ioremap_resource(p_dev, res);
+ priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(priv->base)) {
ret = PTR_ERR(priv->base);
goto init_fail;
}
+ ndev->base_addr = res->start;
spin_lock_init(&priv->txlock);
@@ -541,10 +540,8 @@ static int moxart_mac_probe(struct platform_device *pdev)
SET_NETDEV_DEV(ndev, &pdev->dev);
ret = register_netdev(ndev);
- if (ret) {
- free_netdev(ndev);
+ if (ret)
goto init_fail;
- }
netdev_dbg(ndev, "%s: IRQ=%d address=%pM\n",
__func__, ndev->irq, ndev->dev_addr);
diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c
index aad33d22c33f..e9d260d84bf3 100644
--- a/drivers/net/ethernet/mscc/ocelot_net.c
+++ b/drivers/net/ethernet/mscc/ocelot_net.c
@@ -939,7 +939,7 @@ static void ocelot_port_attr_mc_set(struct ocelot *ocelot, int port, bool mc)
ANA_PORT_CPU_FWD_CFG, port);
}
-static int ocelot_port_attr_set(struct net_device *dev,
+static int ocelot_port_attr_set(struct net_device *dev, const void *ctx,
const struct switchdev_attr *attr,
struct netlink_ext_ack *extack)
{
@@ -948,6 +948,9 @@ static int ocelot_port_attr_set(struct net_device *dev,
int port = priv->chip_port;
int err = 0;
+ if (ctx && ctx != priv)
+ return 0;
+
switch (attr->id) {
case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
ocelot_port_attr_stp_state_set(ocelot, port, attr->u.stp_state);
@@ -1058,12 +1061,16 @@ ocelot_port_obj_mrp_del_ring_role(struct net_device *dev,
return ocelot_mrp_del_ring_role(ocelot, port, mrp);
}
-static int ocelot_port_obj_add(struct net_device *dev,
+static int ocelot_port_obj_add(struct net_device *dev, const void *ctx,
const struct switchdev_obj *obj,
struct netlink_ext_ack *extack)
{
+ struct ocelot_port_private *priv = netdev_priv(dev);
int ret = 0;
+ if (ctx && ctx != priv)
+ return 0;
+
switch (obj->id) {
case SWITCHDEV_OBJ_ID_PORT_VLAN:
ret = ocelot_port_obj_add_vlan(dev,
@@ -1086,11 +1093,15 @@ static int ocelot_port_obj_add(struct net_device *dev,
return ret;
}
-static int ocelot_port_obj_del(struct net_device *dev,
+static int ocelot_port_obj_del(struct net_device *dev, const void *ctx,
const struct switchdev_obj *obj)
{
+ struct ocelot_port_private *priv = netdev_priv(dev);
int ret = 0;
+ if (ctx && ctx != priv)
+ return 0;
+
switch (obj->id) {
case SWITCHDEV_OBJ_ID_PORT_VLAN:
ret = ocelot_vlan_vid_del(dev,
@@ -1143,10 +1154,14 @@ static int ocelot_switchdev_sync(struct ocelot *ocelot, int port,
struct net_device *bridge_dev,
struct netlink_ext_ack *extack)
{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+ struct ocelot_port_private *priv;
clock_t ageing_time;
u8 stp_state;
int err;
+ priv = container_of(ocelot_port, struct ocelot_port_private, port);
+
ocelot_inherit_brport_flags(ocelot, port, brport_dev);
stp_state = br_port_get_stp_state(brport_dev);
@@ -1160,16 +1175,12 @@ static int ocelot_switchdev_sync(struct ocelot *ocelot, int port,
ageing_time = br_get_ageing_time(bridge_dev);
ocelot_port_attr_ageing_set(ocelot, port, ageing_time);
- err = br_mdb_replay(bridge_dev, brport_dev,
+ err = br_mdb_replay(bridge_dev, brport_dev, priv, true,
&ocelot_switchdev_blocking_nb, extack);
if (err && err != -EOPNOTSUPP)
return err;
- err = br_fdb_replay(bridge_dev, brport_dev, &ocelot_switchdev_nb);
- if (err)
- return err;
-
- err = br_vlan_replay(bridge_dev, brport_dev,
+ err = br_vlan_replay(bridge_dev, brport_dev, priv, true,
&ocelot_switchdev_blocking_nb, extack);
if (err && err != -EOPNOTSUPP)
return err;
@@ -1287,6 +1298,7 @@ static int ocelot_netdevice_lag_leave(struct net_device *dev,
}
static int ocelot_netdevice_changeupper(struct net_device *dev,
+ struct net_device *brport_dev,
struct netdev_notifier_changeupper_info *info)
{
struct netlink_ext_ack *extack;
@@ -1296,11 +1308,11 @@ static int ocelot_netdevice_changeupper(struct net_device *dev,
if (netif_is_bridge_master(info->upper_dev)) {
if (info->linking)
- err = ocelot_netdevice_bridge_join(dev, dev,
+ err = ocelot_netdevice_bridge_join(dev, brport_dev,
info->upper_dev,
extack);
else
- err = ocelot_netdevice_bridge_leave(dev, dev,
+ err = ocelot_netdevice_bridge_leave(dev, brport_dev,
info->upper_dev);
}
if (netif_is_lag_master(info->upper_dev)) {
@@ -1335,7 +1347,7 @@ ocelot_netdevice_lag_changeupper(struct net_device *dev,
if (ocelot_port->bond != dev)
return NOTIFY_OK;
- err = ocelot_netdevice_changeupper(lower, info);
+ err = ocelot_netdevice_changeupper(lower, dev, info);
if (err)
return notifier_from_errno(err);
}
@@ -1374,7 +1386,7 @@ static int ocelot_netdevice_event(struct notifier_block *unused,
struct netdev_notifier_changeupper_info *info = ptr;
if (ocelot_netdevice_dev_check(dev))
- return ocelot_netdevice_changeupper(dev, info);
+ return ocelot_netdevice_changeupper(dev, dev, info);
if (netif_is_lag_master(dev))
return ocelot_netdevice_lag_changeupper(dev, info);
diff --git a/drivers/net/ethernet/natsemi/natsemi.c b/drivers/net/ethernet/natsemi/natsemi.c
index b81e1487945c..51b4b25d15ad 100644
--- a/drivers/net/ethernet/natsemi/natsemi.c
+++ b/drivers/net/ethernet/natsemi/natsemi.c
@@ -969,7 +969,7 @@ static int natsemi_probe1(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
err_create_file:
- unregister_netdev(dev);
+ unregister_netdev(dev);
err_register_netdev:
iounmap(ioaddr);
@@ -3103,14 +3103,14 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case SIOCSMIIREG: /* Write MII PHY register. */
if (dev->if_port == PORT_TP) {
if ((data->phy_id & 0x1f) == np->phy_addr_external) {
- if ((data->reg_num & 0x1f) == MII_ADVERTISE)
+ if ((data->reg_num & 0x1f) == MII_ADVERTISE)
np->advertising = data->val_in;
mdio_write(dev, data->reg_num & 0x1f,
data->val_in);
}
} else {
if ((data->phy_id & 0x1f) == np->phy_addr_external) {
- if ((data->reg_num & 0x1f) == MII_ADVERTISE)
+ if ((data->reg_num & 0x1f) == MII_ADVERTISE)
np->advertising = data->val_in;
}
move_int_phy(dev, data->phy_id & 0x1f);
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index 9cfcd5500462..0b017d4f5c08 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -1101,6 +1101,8 @@ static int s2io_print_pci_mode(struct s2io_nic *nic)
* @nic: device private variable
* @link: link status (UP/DOWN) used to enable/disable continuous
* transmit interrupts
+ * @may_sleep: parameter indicates if sleeping when waiting for
+ * command complete
* Description: The function configures transmit traffic interrupts
* Return Value: SUCCESS on success and
* '-1' on failure
@@ -2743,7 +2745,7 @@ static int s2io_chk_rx_buffers(struct s2io_nic *nic, struct ring_info *ring)
}
/**
- * s2io_poll - Rx interrupt handler for NAPI support
+ * s2io_poll_msix - Rx interrupt handler for NAPI support
* @napi : pointer to the napi structure.
* @budget : The number of packets that were budgeted to be processed
* during one pass through the 'Poll" function.
@@ -3323,6 +3325,8 @@ static void s2io_updt_xpak_counter(struct net_device *dev)
* @addr: address
* @busy_bit: bit to check for busy
* @bit_state: state to check
+ * @may_sleep: parameter indicates if sleeping when waiting for
+ * command complete
* Description: Function that waits for a command to Write into RMAC
* ADDR DATA registers to be completed and returns either success or
* error depending on whether the command was complete or not.
@@ -4868,6 +4872,8 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev)
/**
* s2io_set_multicast - entry point for multicast address enable/disable.
* @dev : pointer to the device structure
+ * @may_sleep: parameter indicates if sleeping when waiting for command
+ * complete
* Description:
* This function is a driver entry point which gets called by the kernel
* whenever multicast addresses must be enabled/disabled. This also gets
@@ -5288,7 +5294,7 @@ s2io_ethtool_set_link_ksettings(struct net_device *dev,
}
/**
- * s2io_ethtol_get_link_ksettings - Return link specific information.
+ * s2io_ethtool_get_link_ksettings - Return link specific information.
* @dev: pointer to netdev
* @cmd : pointer to the structure with parameters given by ethtool
* to return link information.
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.c b/drivers/net/ethernet/neterion/vxge/vxge-config.c
index 5162b938a1ac..a3204a7ef750 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-config.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-config.c
@@ -3784,6 +3784,7 @@ vxge_hw_rts_rth_data0_data1_get(u32 j, u64 *data0, u64 *data1,
VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_ENTRY_EN |
VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_DATA(
itable[j]);
+ return;
default:
return;
}
@@ -4884,7 +4885,7 @@ vpath_open_exit1:
}
/**
- * vxge_hw_vpath_rx_doorbell_post - Close the handle got from previous vpath
+ * vxge_hw_vpath_rx_doorbell_init - Close the handle got from previous vpath
* (vpath) open
* @vp: Handle got from previous vpath open
*
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c
index 87892bd992b1..82eef4c72f01 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-main.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c
@@ -87,7 +87,7 @@ static unsigned int bw_percentage[VXGE_HW_MAX_VIRTUAL_PATHS] =
module_param_array(bw_percentage, uint, NULL, 0);
static struct vxge_drv_config *driver_config;
-static enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev);
+static void vxge_reset_all_vpaths(struct vxgedev *vdev);
static inline int is_vxge_card_up(struct vxgedev *vdev)
{
@@ -1606,7 +1606,6 @@ static void vxge_config_ci_for_tti_rti(struct vxgedev *vdev)
static int do_vxge_reset(struct vxgedev *vdev, int event)
{
- enum vxge_hw_status status;
int ret = 0, vp_id, i;
vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
@@ -1709,14 +1708,7 @@ static int do_vxge_reset(struct vxgedev *vdev, int event)
netif_tx_stop_all_queues(vdev->ndev);
if (event == VXGE_LL_FULL_RESET) {
- status = vxge_reset_all_vpaths(vdev);
- if (status != VXGE_HW_OK) {
- vxge_debug_init(VXGE_ERR,
- "fatal: %s: can not reset vpaths",
- vdev->ndev->name);
- ret = -EPERM;
- goto out;
- }
+ vxge_reset_all_vpaths(vdev);
}
if (event == VXGE_LL_COMPL_RESET) {
@@ -1799,7 +1791,7 @@ static void vxge_reset(struct work_struct *work)
}
/**
- * vxge_poll - Receive handler when Receive Polling is used.
+ * vxge_poll_msix - Receive handler when Receive Polling is used.
* @napi: pointer to the napi structure.
* @budget: Number of packets budgeted to be processed in this iteration.
*
@@ -1969,9 +1961,8 @@ static enum vxge_hw_status vxge_rth_configure(struct vxgedev *vdev)
}
/* reset vpaths */
-static enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev)
+static void vxge_reset_all_vpaths(struct vxgedev *vdev)
{
- enum vxge_hw_status status = VXGE_HW_OK;
struct vxge_vpath *vpath;
int i;
@@ -1986,18 +1977,16 @@ static enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev)
"vxge_hw_vpath_recover_"
"from_reset failed for vpath: "
"%d", i);
- return status;
+ return;
}
} else {
vxge_debug_init(VXGE_ERR,
"vxge_hw_vpath_reset failed for "
"vpath:%d", i);
- return status;
+ return;
}
}
}
-
- return status;
}
/* close vpaths */
@@ -2676,11 +2665,7 @@ static int vxge_set_features(struct net_device *dev, netdev_features_t features)
/* !netif_running() ensured by vxge_fix_features() */
vdev->devh->config.rth_en = !!(features & NETIF_F_RXHASH);
- if (vxge_reset_all_vpaths(vdev) != VXGE_HW_OK) {
- dev->features = features ^ NETIF_F_RXHASH;
- vdev->devh->config.rth_en = !!(dev->features & NETIF_F_RXHASH);
- return -EIO;
- }
+ vxge_reset_all_vpaths(vdev);
return 0;
}
@@ -3693,10 +3678,9 @@ static int vxge_config_vpaths(struct vxge_hw_device_config *device_config,
driver_config->vpath_per_dev = 1;
for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++)
- if (!vxge_bVALn(vpath_mask, i, 1))
- continue;
- else
+ if (vxge_bVALn(vpath_mask, i, 1))
default_no_vpath++;
+
if (default_no_vpath < driver_config->vpath_per_dev)
driver_config->vpath_per_dev = default_no_vpath;
@@ -4752,7 +4736,7 @@ _exit0:
}
/**
- * vxge_rem_nic - Free the PCI device
+ * vxge_remove - Free the PCI device
* @pdev: structure containing the PCI related information of the device.
* Description: This function is called by the Pci subsystem to release a
* PCI device and free up all resource held up by the device.
diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile
index d31772ae511d..9cff3d48acbc 100644
--- a/drivers/net/ethernet/netronome/nfp/Makefile
+++ b/drivers/net/ethernet/netronome/nfp/Makefile
@@ -51,7 +51,8 @@ nfp-objs += \
flower/metadata.o \
flower/offload.o \
flower/tunnel_conf.o \
- flower/qos_conf.o
+ flower/qos_conf.o \
+ flower/conntrack.o
endif
ifeq ($(CONFIG_BPF_SYSCALL),y)
diff --git a/drivers/net/ethernet/netronome/nfp/ccm_mbox.c b/drivers/net/ethernet/netronome/nfp/ccm_mbox.c
index f0783aa9e66e..4247bca09807 100644
--- a/drivers/net/ethernet/netronome/nfp/ccm_mbox.c
+++ b/drivers/net/ethernet/netronome/nfp/ccm_mbox.c
@@ -36,7 +36,7 @@ enum nfp_net_mbox_cmsg_state {
};
/**
- * struct nfp_ccm_mbox_skb_cb - CCM mailbox specific info
+ * struct nfp_ccm_mbox_cmsg_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)
diff --git a/drivers/net/ethernet/netronome/nfp/flower/conntrack.c b/drivers/net/ethernet/netronome/nfp/flower/conntrack.c
new file mode 100644
index 000000000000..062bb2db68bf
--- /dev/null
+++ b/drivers/net/ethernet/netronome/nfp/flower/conntrack.c
@@ -0,0 +1,1168 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/* Copyright (C) 2021 Corigine, Inc. */
+
+#include "conntrack.h"
+
+const struct rhashtable_params nfp_tc_ct_merge_params = {
+ .head_offset = offsetof(struct nfp_fl_ct_tc_merge,
+ hash_node),
+ .key_len = sizeof(unsigned long) * 2,
+ .key_offset = offsetof(struct nfp_fl_ct_tc_merge, cookie),
+ .automatic_shrinking = true,
+};
+
+const struct rhashtable_params nfp_nft_ct_merge_params = {
+ .head_offset = offsetof(struct nfp_fl_nft_tc_merge,
+ hash_node),
+ .key_len = sizeof(unsigned long) * 3,
+ .key_offset = offsetof(struct nfp_fl_nft_tc_merge, cookie),
+ .automatic_shrinking = true,
+};
+
+static struct flow_action_entry *get_flow_act(struct flow_rule *rule,
+ enum flow_action_id act_id);
+
+/**
+ * get_hashentry() - Wrapper around hashtable lookup.
+ * @ht: hashtable where entry could be found
+ * @key: key to lookup
+ * @params: hashtable params
+ * @size: size of entry to allocate if not in table
+ *
+ * Returns an entry from a hashtable. If entry does not exist
+ * yet allocate the memory for it and return the new entry.
+ */
+static void *get_hashentry(struct rhashtable *ht, void *key,
+ const struct rhashtable_params params, size_t size)
+{
+ void *result;
+
+ result = rhashtable_lookup_fast(ht, key, params);
+
+ if (result)
+ return result;
+
+ result = kzalloc(size, GFP_KERNEL);
+ if (!result)
+ return ERR_PTR(-ENOMEM);
+
+ return result;
+}
+
+bool is_pre_ct_flow(struct flow_cls_offload *flow)
+{
+ struct flow_action_entry *act;
+ int i;
+
+ flow_action_for_each(i, act, &flow->rule->action) {
+ if (act->id == FLOW_ACTION_CT && !act->ct.action)
+ return true;
+ }
+ return false;
+}
+
+bool is_post_ct_flow(struct flow_cls_offload *flow)
+{
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
+ struct flow_dissector *dissector = rule->match.dissector;
+ struct flow_match_ct ct;
+
+ if (dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CT)) {
+ flow_rule_match_ct(rule, &ct);
+ if (ct.key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED)
+ return true;
+ }
+ return false;
+}
+
+static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
+ struct nfp_fl_ct_flow_entry *entry2)
+{
+ unsigned int ovlp_keys = entry1->rule->match.dissector->used_keys &
+ entry2->rule->match.dissector->used_keys;
+ bool out;
+
+ /* check the overlapped fields one by one, the unmasked part
+ * should not conflict with each other.
+ */
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL)) {
+ struct flow_match_control match1, match2;
+
+ flow_rule_match_control(entry1->rule, &match1);
+ flow_rule_match_control(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_BASIC)) {
+ struct flow_match_basic match1, match2;
+
+ flow_rule_match_basic(entry1->rule, &match1);
+ flow_rule_match_basic(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
+ struct flow_match_ipv4_addrs match1, match2;
+
+ flow_rule_match_ipv4_addrs(entry1->rule, &match1);
+ flow_rule_match_ipv4_addrs(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
+ struct flow_match_ipv6_addrs match1, match2;
+
+ flow_rule_match_ipv6_addrs(entry1->rule, &match1);
+ flow_rule_match_ipv6_addrs(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_PORTS)) {
+ struct flow_match_ports match1, match2;
+
+ flow_rule_match_ports(entry1->rule, &match1);
+ flow_rule_match_ports(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
+ struct flow_match_eth_addrs match1, match2;
+
+ flow_rule_match_eth_addrs(entry1->rule, &match1);
+ flow_rule_match_eth_addrs(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_VLAN)) {
+ struct flow_match_vlan match1, match2;
+
+ flow_rule_match_vlan(entry1->rule, &match1);
+ flow_rule_match_vlan(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_MPLS)) {
+ struct flow_match_mpls match1, match2;
+
+ flow_rule_match_mpls(entry1->rule, &match1);
+ flow_rule_match_mpls(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_TCP)) {
+ struct flow_match_tcp match1, match2;
+
+ flow_rule_match_tcp(entry1->rule, &match1);
+ flow_rule_match_tcp(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_IP)) {
+ struct flow_match_ip match1, match2;
+
+ flow_rule_match_ip(entry1->rule, &match1);
+ flow_rule_match_ip(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_KEYID)) {
+ struct flow_match_enc_keyid match1, match2;
+
+ flow_rule_match_enc_keyid(entry1->rule, &match1);
+ flow_rule_match_enc_keyid(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
+ struct flow_match_ipv4_addrs match1, match2;
+
+ flow_rule_match_enc_ipv4_addrs(entry1->rule, &match1);
+ flow_rule_match_enc_ipv4_addrs(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS)) {
+ struct flow_match_ipv6_addrs match1, match2;
+
+ flow_rule_match_enc_ipv6_addrs(entry1->rule, &match1);
+ flow_rule_match_enc_ipv6_addrs(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
+ struct flow_match_control match1, match2;
+
+ flow_rule_match_enc_control(entry1->rule, &match1);
+ flow_rule_match_enc_control(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_IP)) {
+ struct flow_match_ip match1, match2;
+
+ flow_rule_match_enc_ip(entry1->rule, &match1);
+ flow_rule_match_enc_ip(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_OPTS)) {
+ struct flow_match_enc_opts match1, match2;
+
+ flow_rule_match_enc_opts(entry1->rule, &match1);
+ flow_rule_match_enc_opts(entry2->rule, &match2);
+ COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+ if (out)
+ goto check_failed;
+ }
+
+ return 0;
+
+check_failed:
+ return -EINVAL;
+}
+
+static int nfp_ct_check_mangle_merge(struct flow_action_entry *a_in,
+ struct flow_rule *rule)
+{
+ enum flow_action_mangle_base htype = a_in->mangle.htype;
+ u32 offset = a_in->mangle.offset;
+
+ switch (htype) {
+ case FLOW_ACT_MANGLE_HDR_TYPE_ETH:
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS))
+ return -EOPNOTSUPP;
+ break;
+ case FLOW_ACT_MANGLE_HDR_TYPE_IP4:
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
+ struct flow_match_ip match;
+
+ flow_rule_match_ip(rule, &match);
+ if (offset == offsetof(struct iphdr, ttl) &&
+ match.mask->ttl)
+ return -EOPNOTSUPP;
+ if (offset == round_down(offsetof(struct iphdr, tos), 4) &&
+ match.mask->tos)
+ return -EOPNOTSUPP;
+ }
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
+ struct flow_match_ipv4_addrs match;
+
+ flow_rule_match_ipv4_addrs(rule, &match);
+ if (offset == offsetof(struct iphdr, saddr) &&
+ match.mask->src)
+ return -EOPNOTSUPP;
+ if (offset == offsetof(struct iphdr, daddr) &&
+ match.mask->dst)
+ return -EOPNOTSUPP;
+ }
+ break;
+ case FLOW_ACT_MANGLE_HDR_TYPE_IP6:
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
+ struct flow_match_ip match;
+
+ flow_rule_match_ip(rule, &match);
+ if (offset == round_down(offsetof(struct ipv6hdr, hop_limit), 4) &&
+ match.mask->ttl)
+ return -EOPNOTSUPP;
+ /* for ipv6, tos and flow_lbl are in the same word */
+ if (offset == round_down(offsetof(struct ipv6hdr, flow_lbl), 4) &&
+ match.mask->tos)
+ return -EOPNOTSUPP;
+ }
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
+ struct flow_match_ipv6_addrs match;
+
+ flow_rule_match_ipv6_addrs(rule, &match);
+ if (offset >= offsetof(struct ipv6hdr, saddr) &&
+ offset < offsetof(struct ipv6hdr, daddr) &&
+ memchr_inv(&match.mask->src, 0, sizeof(match.mask->src)))
+ return -EOPNOTSUPP;
+ if (offset >= offsetof(struct ipv6hdr, daddr) &&
+ offset < sizeof(struct ipv6hdr) &&
+ memchr_inv(&match.mask->dst, 0, sizeof(match.mask->dst)))
+ return -EOPNOTSUPP;
+ }
+ break;
+ case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
+ case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
+ /* currently only can modify ports */
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS))
+ return -EOPNOTSUPP;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int nfp_ct_merge_act_check(struct nfp_fl_ct_flow_entry *pre_ct_entry,
+ struct nfp_fl_ct_flow_entry *post_ct_entry,
+ struct nfp_fl_ct_flow_entry *nft_entry)
+{
+ struct flow_action_entry *act;
+ int err, i;
+
+ /* Check for pre_ct->action conflicts */
+ flow_action_for_each(i, act, &pre_ct_entry->rule->action) {
+ switch (act->id) {
+ case FLOW_ACTION_MANGLE:
+ err = nfp_ct_check_mangle_merge(act, nft_entry->rule);
+ if (err)
+ return err;
+ err = nfp_ct_check_mangle_merge(act, post_ct_entry->rule);
+ if (err)
+ return err;
+ break;
+ case FLOW_ACTION_VLAN_PUSH:
+ case FLOW_ACTION_VLAN_POP:
+ case FLOW_ACTION_VLAN_MANGLE:
+ case FLOW_ACTION_MPLS_PUSH:
+ case FLOW_ACTION_MPLS_POP:
+ case FLOW_ACTION_MPLS_MANGLE:
+ return -EOPNOTSUPP;
+ default:
+ break;
+ }
+ }
+
+ /* Check for nft->action conflicts */
+ flow_action_for_each(i, act, &nft_entry->rule->action) {
+ switch (act->id) {
+ case FLOW_ACTION_MANGLE:
+ err = nfp_ct_check_mangle_merge(act, post_ct_entry->rule);
+ if (err)
+ return err;
+ break;
+ case FLOW_ACTION_VLAN_PUSH:
+ case FLOW_ACTION_VLAN_POP:
+ case FLOW_ACTION_VLAN_MANGLE:
+ case FLOW_ACTION_MPLS_PUSH:
+ case FLOW_ACTION_MPLS_POP:
+ case FLOW_ACTION_MPLS_MANGLE:
+ return -EOPNOTSUPP;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+static int nfp_ct_check_meta(struct nfp_fl_ct_flow_entry *post_ct_entry,
+ struct nfp_fl_ct_flow_entry *nft_entry)
+{
+ struct flow_dissector *dissector = post_ct_entry->rule->match.dissector;
+ struct flow_action_entry *ct_met;
+ struct flow_match_ct ct;
+ int i;
+
+ ct_met = get_flow_act(nft_entry->rule, FLOW_ACTION_CT_METADATA);
+ if (ct_met && (dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CT))) {
+ u32 *act_lbl;
+
+ act_lbl = ct_met->ct_metadata.labels;
+ flow_rule_match_ct(post_ct_entry->rule, &ct);
+ for (i = 0; i < 4; i++) {
+ if ((ct.key->ct_labels[i] & ct.mask->ct_labels[i]) ^
+ (act_lbl[i] & ct.mask->ct_labels[i]))
+ return -EINVAL;
+ }
+
+ if ((ct.key->ct_mark & ct.mask->ct_mark) ^
+ (ct_met->ct_metadata.mark & ct.mask->ct_mark))
+ return -EINVAL;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int nfp_fl_ct_add_offload(struct nfp_fl_nft_tc_merge *m_entry)
+{
+ return 0;
+}
+
+static int nfp_fl_ct_del_offload(struct nfp_app *app, unsigned long cookie,
+ struct net_device *netdev)
+{
+ return 0;
+}
+
+static int nfp_ct_do_nft_merge(struct nfp_fl_ct_zone_entry *zt,
+ struct nfp_fl_ct_flow_entry *nft_entry,
+ struct nfp_fl_ct_tc_merge *tc_m_entry)
+{
+ struct nfp_fl_ct_flow_entry *post_ct_entry, *pre_ct_entry;
+ struct nfp_fl_nft_tc_merge *nft_m_entry;
+ unsigned long new_cookie[3];
+ int err;
+
+ pre_ct_entry = tc_m_entry->pre_ct_parent;
+ post_ct_entry = tc_m_entry->post_ct_parent;
+
+ err = nfp_ct_merge_act_check(pre_ct_entry, post_ct_entry, nft_entry);
+ if (err)
+ return err;
+
+ /* Check that the two tc flows are also compatible with
+ * the nft entry. No need to check the pre_ct and post_ct
+ * entries as that was already done during pre_merge.
+ * The nft entry does not have a netdev or chain populated, so
+ * skip this check.
+ */
+ err = nfp_ct_merge_check(pre_ct_entry, nft_entry);
+ if (err)
+ return err;
+ err = nfp_ct_merge_check(post_ct_entry, nft_entry);
+ if (err)
+ return err;
+ err = nfp_ct_check_meta(post_ct_entry, nft_entry);
+ if (err)
+ return err;
+
+ /* Combine tc_merge and nft cookies for this cookie. */
+ new_cookie[0] = tc_m_entry->cookie[0];
+ new_cookie[1] = tc_m_entry->cookie[1];
+ new_cookie[2] = nft_entry->cookie;
+ nft_m_entry = get_hashentry(&zt->nft_merge_tb,
+ &new_cookie,
+ nfp_nft_ct_merge_params,
+ sizeof(*nft_m_entry));
+
+ if (IS_ERR(nft_m_entry))
+ return PTR_ERR(nft_m_entry);
+
+ /* nft_m_entry already present, not merging again */
+ if (!memcmp(&new_cookie, nft_m_entry->cookie, sizeof(new_cookie)))
+ return 0;
+
+ memcpy(&nft_m_entry->cookie, &new_cookie, sizeof(new_cookie));
+ nft_m_entry->zt = zt;
+ nft_m_entry->tc_m_parent = tc_m_entry;
+ nft_m_entry->nft_parent = nft_entry;
+ nft_m_entry->tc_flower_cookie = 0;
+ /* Copy the netdev from one the pre_ct entry. When the tc_m_entry was created
+ * it only combined them if the netdevs were the same, so can use any of them.
+ */
+ nft_m_entry->netdev = pre_ct_entry->netdev;
+
+ /* Add this entry to the tc_m_list and nft_flow lists */
+ list_add(&nft_m_entry->tc_merge_list, &tc_m_entry->children);
+ list_add(&nft_m_entry->nft_flow_list, &nft_entry->children);
+
+ /* Generate offload structure and send to nfp */
+ err = nfp_fl_ct_add_offload(nft_m_entry);
+ if (err)
+ goto err_nft_ct_offload;
+
+ err = rhashtable_insert_fast(&zt->nft_merge_tb, &nft_m_entry->hash_node,
+ nfp_nft_ct_merge_params);
+ if (err)
+ goto err_nft_ct_merge_insert;
+
+ zt->nft_merge_count++;
+
+ return err;
+
+err_nft_ct_merge_insert:
+ nfp_fl_ct_del_offload(zt->priv->app, nft_m_entry->tc_flower_cookie,
+ nft_m_entry->netdev);
+err_nft_ct_offload:
+ list_del(&nft_m_entry->tc_merge_list);
+ list_del(&nft_m_entry->nft_flow_list);
+ kfree(nft_m_entry);
+ return err;
+}
+
+static int nfp_ct_do_tc_merge(struct nfp_fl_ct_zone_entry *zt,
+ struct nfp_fl_ct_flow_entry *ct_entry1,
+ struct nfp_fl_ct_flow_entry *ct_entry2)
+{
+ struct nfp_fl_ct_flow_entry *post_ct_entry, *pre_ct_entry;
+ struct nfp_fl_ct_flow_entry *nft_entry, *nft_tmp;
+ struct nfp_fl_ct_tc_merge *m_entry;
+ unsigned long new_cookie[2];
+ int err;
+
+ if (ct_entry1->type == CT_TYPE_PRE_CT) {
+ pre_ct_entry = ct_entry1;
+ post_ct_entry = ct_entry2;
+ } else {
+ post_ct_entry = ct_entry1;
+ pre_ct_entry = ct_entry2;
+ }
+
+ if (post_ct_entry->netdev != pre_ct_entry->netdev)
+ return -EINVAL;
+ /* Checks that the chain_index of the filter matches the
+ * chain_index of the GOTO action.
+ */
+ if (post_ct_entry->chain_index != pre_ct_entry->chain_index)
+ return -EINVAL;
+
+ err = nfp_ct_merge_check(post_ct_entry, pre_ct_entry);
+ if (err)
+ return err;
+
+ new_cookie[0] = pre_ct_entry->cookie;
+ new_cookie[1] = post_ct_entry->cookie;
+ m_entry = get_hashentry(&zt->tc_merge_tb, &new_cookie,
+ nfp_tc_ct_merge_params, sizeof(*m_entry));
+ if (IS_ERR(m_entry))
+ return PTR_ERR(m_entry);
+
+ /* m_entry already present, not merging again */
+ if (!memcmp(&new_cookie, m_entry->cookie, sizeof(new_cookie)))
+ return 0;
+
+ memcpy(&m_entry->cookie, &new_cookie, sizeof(new_cookie));
+ m_entry->zt = zt;
+ m_entry->post_ct_parent = post_ct_entry;
+ m_entry->pre_ct_parent = pre_ct_entry;
+
+ /* Add this entry to the pre_ct and post_ct lists */
+ list_add(&m_entry->post_ct_list, &post_ct_entry->children);
+ list_add(&m_entry->pre_ct_list, &pre_ct_entry->children);
+ INIT_LIST_HEAD(&m_entry->children);
+
+ err = rhashtable_insert_fast(&zt->tc_merge_tb, &m_entry->hash_node,
+ nfp_tc_ct_merge_params);
+ if (err)
+ goto err_ct_tc_merge_insert;
+ zt->tc_merge_count++;
+
+ /* Merge with existing nft flows */
+ list_for_each_entry_safe(nft_entry, nft_tmp, &zt->nft_flows_list,
+ list_node) {
+ nfp_ct_do_nft_merge(zt, nft_entry, m_entry);
+ }
+
+ return 0;
+
+err_ct_tc_merge_insert:
+ list_del(&m_entry->post_ct_list);
+ list_del(&m_entry->pre_ct_list);
+ kfree(m_entry);
+ return err;
+}
+
+static struct
+nfp_fl_ct_zone_entry *get_nfp_zone_entry(struct nfp_flower_priv *priv,
+ u16 zone, bool wildcarded)
+{
+ struct nfp_fl_ct_zone_entry *zt;
+ int err;
+
+ if (wildcarded && priv->ct_zone_wc)
+ return priv->ct_zone_wc;
+
+ if (!wildcarded) {
+ zt = get_hashentry(&priv->ct_zone_table, &zone,
+ nfp_zone_table_params, sizeof(*zt));
+
+ /* If priv is set this is an existing entry, just return it */
+ if (IS_ERR(zt) || zt->priv)
+ return zt;
+ } else {
+ zt = kzalloc(sizeof(*zt), GFP_KERNEL);
+ if (!zt)
+ return ERR_PTR(-ENOMEM);
+ }
+
+ zt->zone = zone;
+ zt->priv = priv;
+ zt->nft = NULL;
+
+ /* init the various hash tables and lists*/
+ INIT_LIST_HEAD(&zt->pre_ct_list);
+ INIT_LIST_HEAD(&zt->post_ct_list);
+ INIT_LIST_HEAD(&zt->nft_flows_list);
+
+ err = rhashtable_init(&zt->tc_merge_tb, &nfp_tc_ct_merge_params);
+ if (err)
+ goto err_tc_merge_tb_init;
+
+ err = rhashtable_init(&zt->nft_merge_tb, &nfp_nft_ct_merge_params);
+ if (err)
+ goto err_nft_merge_tb_init;
+
+ if (wildcarded) {
+ priv->ct_zone_wc = zt;
+ } else {
+ err = rhashtable_insert_fast(&priv->ct_zone_table,
+ &zt->hash_node,
+ nfp_zone_table_params);
+ if (err)
+ goto err_zone_insert;
+ }
+
+ return zt;
+
+err_zone_insert:
+ rhashtable_destroy(&zt->nft_merge_tb);
+err_nft_merge_tb_init:
+ rhashtable_destroy(&zt->tc_merge_tb);
+err_tc_merge_tb_init:
+ kfree(zt);
+ return ERR_PTR(err);
+}
+
+static struct
+nfp_fl_ct_flow_entry *nfp_fl_ct_add_flow(struct nfp_fl_ct_zone_entry *zt,
+ struct net_device *netdev,
+ struct flow_cls_offload *flow,
+ bool is_nft, struct netlink_ext_ack *extack)
+{
+ struct nf_flow_match *nft_match = NULL;
+ struct nfp_fl_ct_flow_entry *entry;
+ struct nfp_fl_ct_map_entry *map;
+ struct flow_action_entry *act;
+ int err, i;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return ERR_PTR(-ENOMEM);
+
+ entry->rule = flow_rule_alloc(flow->rule->action.num_entries);
+ if (!entry->rule) {
+ err = -ENOMEM;
+ goto err_pre_ct_rule;
+ }
+
+ /* nft flows gets destroyed after callback return, so need
+ * to do a full copy instead of just a reference.
+ */
+ if (is_nft) {
+ nft_match = kzalloc(sizeof(*nft_match), GFP_KERNEL);
+ if (!nft_match) {
+ err = -ENOMEM;
+ goto err_pre_ct_act;
+ }
+ memcpy(&nft_match->dissector, flow->rule->match.dissector,
+ sizeof(nft_match->dissector));
+ memcpy(&nft_match->mask, flow->rule->match.mask,
+ sizeof(nft_match->mask));
+ memcpy(&nft_match->key, flow->rule->match.key,
+ sizeof(nft_match->key));
+ entry->rule->match.dissector = &nft_match->dissector;
+ entry->rule->match.mask = &nft_match->mask;
+ entry->rule->match.key = &nft_match->key;
+ } else {
+ entry->rule->match.dissector = flow->rule->match.dissector;
+ entry->rule->match.mask = flow->rule->match.mask;
+ entry->rule->match.key = flow->rule->match.key;
+ }
+
+ entry->zt = zt;
+ entry->netdev = netdev;
+ entry->cookie = flow->cookie;
+ entry->chain_index = flow->common.chain_index;
+ entry->tun_offset = NFP_FL_CT_NO_TUN;
+
+ /* Copy over action data. Unfortunately we do not get a handle to the
+ * original tcf_action data, and the flow objects gets destroyed, so we
+ * cannot just save a pointer to this either, so need to copy over the
+ * data unfortunately.
+ */
+ entry->rule->action.num_entries = flow->rule->action.num_entries;
+ flow_action_for_each(i, act, &flow->rule->action) {
+ struct flow_action_entry *new_act;
+
+ new_act = &entry->rule->action.entries[i];
+ memcpy(new_act, act, sizeof(struct flow_action_entry));
+ /* Entunnel is a special case, need to allocate and copy
+ * tunnel info.
+ */
+ if (act->id == FLOW_ACTION_TUNNEL_ENCAP) {
+ struct ip_tunnel_info *tun = act->tunnel;
+ size_t tun_size = sizeof(*tun) + tun->options_len;
+
+ new_act->tunnel = kmemdup(tun, tun_size, GFP_ATOMIC);
+ if (!new_act->tunnel) {
+ err = -ENOMEM;
+ goto err_pre_ct_tun_cp;
+ }
+ entry->tun_offset = i;
+ }
+ }
+
+ INIT_LIST_HEAD(&entry->children);
+
+ /* Now add a ct map entry to flower-priv */
+ map = get_hashentry(&zt->priv->ct_map_table, &flow->cookie,
+ nfp_ct_map_params, sizeof(*map));
+ if (IS_ERR(map)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "offload error: ct map entry creation failed");
+ err = -ENOMEM;
+ goto err_ct_flow_insert;
+ }
+ map->cookie = flow->cookie;
+ map->ct_entry = entry;
+ err = rhashtable_insert_fast(&zt->priv->ct_map_table,
+ &map->hash_node,
+ nfp_ct_map_params);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "offload error: ct map entry table add failed");
+ goto err_map_insert;
+ }
+
+ return entry;
+
+err_map_insert:
+ kfree(map);
+err_ct_flow_insert:
+ if (entry->tun_offset != NFP_FL_CT_NO_TUN)
+ kfree(entry->rule->action.entries[entry->tun_offset].tunnel);
+err_pre_ct_tun_cp:
+ kfree(nft_match);
+err_pre_ct_act:
+ kfree(entry->rule);
+err_pre_ct_rule:
+ kfree(entry);
+ return ERR_PTR(err);
+}
+
+static void cleanup_nft_merge_entry(struct nfp_fl_nft_tc_merge *m_entry)
+{
+ struct nfp_fl_ct_zone_entry *zt;
+ int err;
+
+ zt = m_entry->zt;
+
+ /* Flow is in HW, need to delete */
+ if (m_entry->tc_flower_cookie) {
+ err = nfp_fl_ct_del_offload(zt->priv->app, m_entry->tc_flower_cookie,
+ m_entry->netdev);
+ if (err)
+ return;
+ }
+
+ WARN_ON_ONCE(rhashtable_remove_fast(&zt->nft_merge_tb,
+ &m_entry->hash_node,
+ nfp_nft_ct_merge_params));
+ zt->nft_merge_count--;
+ list_del(&m_entry->tc_merge_list);
+ list_del(&m_entry->nft_flow_list);
+
+ kfree(m_entry);
+}
+
+static void nfp_free_nft_merge_children(void *entry, bool is_nft_flow)
+{
+ struct nfp_fl_nft_tc_merge *m_entry, *tmp;
+
+ /* These post entries are parts of two lists, one is a list of nft_entries
+ * and the other is of from a list of tc_merge structures. Iterate
+ * through the relevant list and cleanup the entries.
+ */
+
+ if (is_nft_flow) {
+ /* Need to iterate through list of nft_flow entries*/
+ struct nfp_fl_ct_flow_entry *ct_entry = entry;
+
+ list_for_each_entry_safe(m_entry, tmp, &ct_entry->children,
+ nft_flow_list) {
+ cleanup_nft_merge_entry(m_entry);
+ }
+ } else {
+ /* Need to iterate through list of tc_merged_flow entries*/
+ struct nfp_fl_ct_tc_merge *ct_entry = entry;
+
+ list_for_each_entry_safe(m_entry, tmp, &ct_entry->children,
+ tc_merge_list) {
+ cleanup_nft_merge_entry(m_entry);
+ }
+ }
+}
+
+static void nfp_del_tc_merge_entry(struct nfp_fl_ct_tc_merge *m_ent)
+{
+ struct nfp_fl_ct_zone_entry *zt;
+ int err;
+
+ zt = m_ent->zt;
+ err = rhashtable_remove_fast(&zt->tc_merge_tb,
+ &m_ent->hash_node,
+ nfp_tc_ct_merge_params);
+ if (err)
+ pr_warn("WARNING: could not remove merge_entry from hashtable\n");
+ zt->tc_merge_count--;
+ list_del(&m_ent->post_ct_list);
+ list_del(&m_ent->pre_ct_list);
+
+ if (!list_empty(&m_ent->children))
+ nfp_free_nft_merge_children(m_ent, false);
+ kfree(m_ent);
+}
+
+static void nfp_free_tc_merge_children(struct nfp_fl_ct_flow_entry *entry)
+{
+ struct nfp_fl_ct_tc_merge *m_ent, *tmp;
+
+ switch (entry->type) {
+ case CT_TYPE_PRE_CT:
+ list_for_each_entry_safe(m_ent, tmp, &entry->children, pre_ct_list) {
+ nfp_del_tc_merge_entry(m_ent);
+ }
+ break;
+ case CT_TYPE_POST_CT:
+ list_for_each_entry_safe(m_ent, tmp, &entry->children, post_ct_list) {
+ nfp_del_tc_merge_entry(m_ent);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void nfp_fl_ct_clean_flow_entry(struct nfp_fl_ct_flow_entry *entry)
+{
+ list_del(&entry->list_node);
+
+ if (!list_empty(&entry->children)) {
+ if (entry->type == CT_TYPE_NFT)
+ nfp_free_nft_merge_children(entry, true);
+ else
+ nfp_free_tc_merge_children(entry);
+ }
+
+ if (entry->tun_offset != NFP_FL_CT_NO_TUN)
+ kfree(entry->rule->action.entries[entry->tun_offset].tunnel);
+
+ if (entry->type == CT_TYPE_NFT) {
+ struct nf_flow_match *nft_match;
+
+ nft_match = container_of(entry->rule->match.dissector,
+ struct nf_flow_match, dissector);
+ kfree(nft_match);
+ }
+
+ kfree(entry->rule);
+ kfree(entry);
+}
+
+static struct flow_action_entry *get_flow_act(struct flow_rule *rule,
+ enum flow_action_id act_id)
+{
+ struct flow_action_entry *act = NULL;
+ int i;
+
+ flow_action_for_each(i, act, &rule->action) {
+ if (act->id == act_id)
+ return act;
+ }
+ return NULL;
+}
+
+static void
+nfp_ct_merge_tc_entries(struct nfp_fl_ct_flow_entry *ct_entry1,
+ struct nfp_fl_ct_zone_entry *zt_src,
+ struct nfp_fl_ct_zone_entry *zt_dst)
+{
+ struct nfp_fl_ct_flow_entry *ct_entry2, *ct_tmp;
+ struct list_head *ct_list;
+
+ if (ct_entry1->type == CT_TYPE_PRE_CT)
+ ct_list = &zt_src->post_ct_list;
+ else if (ct_entry1->type == CT_TYPE_POST_CT)
+ ct_list = &zt_src->pre_ct_list;
+ else
+ return;
+
+ list_for_each_entry_safe(ct_entry2, ct_tmp, ct_list,
+ list_node) {
+ nfp_ct_do_tc_merge(zt_dst, ct_entry2, ct_entry1);
+ }
+}
+
+static void
+nfp_ct_merge_nft_with_tc(struct nfp_fl_ct_flow_entry *nft_entry,
+ struct nfp_fl_ct_zone_entry *zt)
+{
+ struct nfp_fl_ct_tc_merge *tc_merge_entry;
+ struct rhashtable_iter iter;
+
+ rhashtable_walk_enter(&zt->tc_merge_tb, &iter);
+ rhashtable_walk_start(&iter);
+ while ((tc_merge_entry = rhashtable_walk_next(&iter)) != NULL) {
+ if (IS_ERR(tc_merge_entry))
+ continue;
+ rhashtable_walk_stop(&iter);
+ nfp_ct_do_nft_merge(zt, nft_entry, tc_merge_entry);
+ rhashtable_walk_start(&iter);
+ }
+ rhashtable_walk_stop(&iter);
+ rhashtable_walk_exit(&iter);
+}
+
+int nfp_fl_ct_handle_pre_ct(struct nfp_flower_priv *priv,
+ struct net_device *netdev,
+ struct flow_cls_offload *flow,
+ struct netlink_ext_ack *extack)
+{
+ struct flow_action_entry *ct_act, *ct_goto;
+ struct nfp_fl_ct_flow_entry *ct_entry;
+ struct nfp_fl_ct_zone_entry *zt;
+ int err;
+
+ ct_act = get_flow_act(flow->rule, FLOW_ACTION_CT);
+ if (!ct_act) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "unsupported offload: Conntrack action empty in conntrack offload");
+ return -EOPNOTSUPP;
+ }
+
+ ct_goto = get_flow_act(flow->rule, FLOW_ACTION_GOTO);
+ if (!ct_goto) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "unsupported offload: Conntrack requires ACTION_GOTO");
+ return -EOPNOTSUPP;
+ }
+
+ zt = get_nfp_zone_entry(priv, ct_act->ct.zone, false);
+ if (IS_ERR(zt)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "offload error: Could not create zone table entry");
+ return PTR_ERR(zt);
+ }
+
+ if (!zt->nft) {
+ zt->nft = ct_act->ct.flow_table;
+ err = nf_flow_table_offload_add_cb(zt->nft, nfp_fl_ct_handle_nft_flow, zt);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "offload error: Could not register nft_callback");
+ return err;
+ }
+ }
+
+ /* Add entry to pre_ct_list */
+ ct_entry = nfp_fl_ct_add_flow(zt, netdev, flow, false, extack);
+ if (IS_ERR(ct_entry))
+ return PTR_ERR(ct_entry);
+ ct_entry->type = CT_TYPE_PRE_CT;
+ ct_entry->chain_index = ct_goto->chain_index;
+ list_add(&ct_entry->list_node, &zt->pre_ct_list);
+ zt->pre_ct_count++;
+
+ nfp_ct_merge_tc_entries(ct_entry, zt, zt);
+
+ /* Need to check and merge with tables in the wc_zone as well */
+ if (priv->ct_zone_wc)
+ nfp_ct_merge_tc_entries(ct_entry, priv->ct_zone_wc, zt);
+
+ return 0;
+}
+
+int nfp_fl_ct_handle_post_ct(struct nfp_flower_priv *priv,
+ struct net_device *netdev,
+ struct flow_cls_offload *flow,
+ struct netlink_ext_ack *extack)
+{
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
+ struct nfp_fl_ct_flow_entry *ct_entry;
+ struct nfp_fl_ct_zone_entry *zt;
+ bool wildcarded = false;
+ struct flow_match_ct ct;
+
+ flow_rule_match_ct(rule, &ct);
+ if (!ct.mask->ct_zone) {
+ wildcarded = true;
+ } else if (ct.mask->ct_zone != U16_MAX) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "unsupported offload: partially wildcarded ct_zone is not supported");
+ return -EOPNOTSUPP;
+ }
+
+ zt = get_nfp_zone_entry(priv, ct.key->ct_zone, wildcarded);
+ if (IS_ERR(zt)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "offload error: Could not create zone table entry");
+ return PTR_ERR(zt);
+ }
+
+ /* Add entry to post_ct_list */
+ ct_entry = nfp_fl_ct_add_flow(zt, netdev, flow, false, extack);
+ if (IS_ERR(ct_entry))
+ return PTR_ERR(ct_entry);
+
+ ct_entry->type = CT_TYPE_POST_CT;
+ ct_entry->chain_index = flow->common.chain_index;
+ list_add(&ct_entry->list_node, &zt->post_ct_list);
+ zt->post_ct_count++;
+
+ if (wildcarded) {
+ /* Iterate through all zone tables if not empty, look for merges with
+ * pre_ct entries and merge them.
+ */
+ struct rhashtable_iter iter;
+ struct nfp_fl_ct_zone_entry *zone_table;
+
+ rhashtable_walk_enter(&priv->ct_zone_table, &iter);
+ rhashtable_walk_start(&iter);
+ while ((zone_table = rhashtable_walk_next(&iter)) != NULL) {
+ if (IS_ERR(zone_table))
+ continue;
+ rhashtable_walk_stop(&iter);
+ nfp_ct_merge_tc_entries(ct_entry, zone_table, zone_table);
+ rhashtable_walk_start(&iter);
+ }
+ rhashtable_walk_stop(&iter);
+ rhashtable_walk_exit(&iter);
+ } else {
+ nfp_ct_merge_tc_entries(ct_entry, zt, zt);
+ }
+
+ return 0;
+}
+
+static int
+nfp_fl_ct_offload_nft_flow(struct nfp_fl_ct_zone_entry *zt, struct flow_cls_offload *flow)
+{
+ struct nfp_fl_ct_map_entry *ct_map_ent;
+ struct nfp_fl_ct_flow_entry *ct_entry;
+ struct netlink_ext_ack *extack = NULL;
+
+ ASSERT_RTNL();
+
+ extack = flow->common.extack;
+ switch (flow->command) {
+ case FLOW_CLS_REPLACE:
+ /* Netfilter can request offload multiple times for the same
+ * flow - protect against adding duplicates.
+ */
+ ct_map_ent = rhashtable_lookup_fast(&zt->priv->ct_map_table, &flow->cookie,
+ nfp_ct_map_params);
+ if (!ct_map_ent) {
+ ct_entry = nfp_fl_ct_add_flow(zt, NULL, flow, true, extack);
+ if (IS_ERR(ct_entry))
+ return PTR_ERR(ct_entry);
+ ct_entry->type = CT_TYPE_NFT;
+ list_add(&ct_entry->list_node, &zt->nft_flows_list);
+ zt->nft_flows_count++;
+ nfp_ct_merge_nft_with_tc(ct_entry, zt);
+ }
+ return 0;
+ case FLOW_CLS_DESTROY:
+ ct_map_ent = rhashtable_lookup_fast(&zt->priv->ct_map_table, &flow->cookie,
+ nfp_ct_map_params);
+ return nfp_fl_ct_del_flow(ct_map_ent);
+ case FLOW_CLS_STATS:
+ return 0;
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+int nfp_fl_ct_handle_nft_flow(enum tc_setup_type type, void *type_data, void *cb_priv)
+{
+ struct flow_cls_offload *flow = type_data;
+ struct nfp_fl_ct_zone_entry *zt = cb_priv;
+ int err = -EOPNOTSUPP;
+
+ switch (type) {
+ case TC_SETUP_CLSFLOWER:
+ rtnl_lock();
+ err = nfp_fl_ct_offload_nft_flow(zt, flow);
+ rtnl_unlock();
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return err;
+}
+
+static void
+nfp_fl_ct_clean_nft_entries(struct nfp_fl_ct_zone_entry *zt)
+{
+ struct nfp_fl_ct_flow_entry *nft_entry, *ct_tmp;
+ struct nfp_fl_ct_map_entry *ct_map_ent;
+
+ list_for_each_entry_safe(nft_entry, ct_tmp, &zt->nft_flows_list,
+ list_node) {
+ ct_map_ent = rhashtable_lookup_fast(&zt->priv->ct_map_table,
+ &nft_entry->cookie,
+ nfp_ct_map_params);
+ nfp_fl_ct_del_flow(ct_map_ent);
+ }
+}
+
+int nfp_fl_ct_del_flow(struct nfp_fl_ct_map_entry *ct_map_ent)
+{
+ struct nfp_fl_ct_flow_entry *ct_entry;
+ struct nfp_fl_ct_zone_entry *zt;
+ struct rhashtable *m_table;
+
+ if (!ct_map_ent)
+ return -ENOENT;
+
+ zt = ct_map_ent->ct_entry->zt;
+ ct_entry = ct_map_ent->ct_entry;
+ m_table = &zt->priv->ct_map_table;
+
+ switch (ct_entry->type) {
+ case CT_TYPE_PRE_CT:
+ zt->pre_ct_count--;
+ rhashtable_remove_fast(m_table, &ct_map_ent->hash_node,
+ nfp_ct_map_params);
+ nfp_fl_ct_clean_flow_entry(ct_entry);
+ kfree(ct_map_ent);
+
+ if (!zt->pre_ct_count) {
+ zt->nft = NULL;
+ nfp_fl_ct_clean_nft_entries(zt);
+ }
+ break;
+ case CT_TYPE_POST_CT:
+ zt->post_ct_count--;
+ rhashtable_remove_fast(m_table, &ct_map_ent->hash_node,
+ nfp_ct_map_params);
+ nfp_fl_ct_clean_flow_entry(ct_entry);
+ kfree(ct_map_ent);
+ break;
+ case CT_TYPE_NFT:
+ zt->nft_flows_count--;
+ rhashtable_remove_fast(m_table, &ct_map_ent->hash_node,
+ nfp_ct_map_params);
+ nfp_fl_ct_clean_flow_entry(ct_map_ent->ct_entry);
+ kfree(ct_map_ent);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/netronome/nfp/flower/conntrack.h b/drivers/net/ethernet/netronome/nfp/flower/conntrack.h
new file mode 100644
index 000000000000..170b6cdb8cd0
--- /dev/null
+++ b/drivers/net/ethernet/netronome/nfp/flower/conntrack.h
@@ -0,0 +1,231 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/* Copyright (C) 2021 Corigine, Inc. */
+
+#ifndef __NFP_FLOWER_CONNTRACK_H__
+#define __NFP_FLOWER_CONNTRACK_H__ 1
+
+#include <net/netfilter/nf_flow_table.h>
+#include "main.h"
+
+#define NFP_FL_CT_NO_TUN 0xff
+
+#define COMPARE_UNMASKED_FIELDS(__match1, __match2, __out) \
+ do { \
+ typeof(__match1) _match1 = (__match1); \
+ typeof(__match2) _match2 = (__match2); \
+ bool *_out = (__out); \
+ int i, size = sizeof(*(_match1).key); \
+ char *k1, *m1, *k2, *m2; \
+ *_out = false; \
+ k1 = (char *)_match1.key; \
+ m1 = (char *)_match1.mask; \
+ k2 = (char *)_match2.key; \
+ m2 = (char *)_match2.mask; \
+ for (i = 0; i < size; i++) \
+ if ((k1[i] & m1[i] & m2[i]) ^ \
+ (k2[i] & m1[i] & m2[i])) { \
+ *_out = true; \
+ break; \
+ } \
+ } while (0) \
+
+extern const struct rhashtable_params nfp_zone_table_params;
+extern const struct rhashtable_params nfp_ct_map_params;
+extern const struct rhashtable_params nfp_tc_ct_merge_params;
+extern const struct rhashtable_params nfp_nft_ct_merge_params;
+
+/**
+ * struct nfp_fl_ct_zone_entry - Zone entry containing conntrack flow information
+ * @zone: The zone number, used as lookup key in hashtable
+ * @hash_node: Used by the hashtable
+ * @priv: Pointer to nfp_flower_priv data
+ * @nft: Pointer to nf_flowtable for this zone
+ *
+ * @pre_ct_list: The pre_ct_list of nfp_fl_ct_flow_entry entries
+ * @pre_ct_count: Keep count of the number of pre_ct entries
+ *
+ * @post_ct_list: The post_ct_list of nfp_fl_ct_flow_entry entries
+ * @post_ct_count: Keep count of the number of post_ct entries
+ *
+ * @tc_merge_tb: The table of merged tc flows
+ * @tc_merge_count: Keep count of the number of merged tc entries
+ *
+ * @nft_flows_list: The list of nft relatednfp_fl_ct_flow_entry entries
+ * @nft_flows_count: Keep count of the number of nft_flow entries
+ *
+ * @nft_merge_tb: The table of merged tc+nft flows
+ * @nft_merge_count: Keep count of the number of merged tc+nft entries
+ */
+struct nfp_fl_ct_zone_entry {
+ u16 zone;
+ struct rhash_head hash_node;
+
+ struct nfp_flower_priv *priv;
+ struct nf_flowtable *nft;
+
+ struct list_head pre_ct_list;
+ unsigned int pre_ct_count;
+
+ struct list_head post_ct_list;
+ unsigned int post_ct_count;
+
+ struct rhashtable tc_merge_tb;
+ unsigned int tc_merge_count;
+
+ struct list_head nft_flows_list;
+ unsigned int nft_flows_count;
+
+ struct rhashtable nft_merge_tb;
+ unsigned int nft_merge_count;
+};
+
+enum ct_entry_type {
+ CT_TYPE_PRE_CT,
+ CT_TYPE_NFT,
+ CT_TYPE_POST_CT,
+};
+
+/**
+ * struct nfp_fl_ct_flow_entry - Flow entry containing conntrack flow information
+ * @cookie: Flow cookie, same as original TC flow, used as key
+ * @list_node: Used by the list
+ * @chain_index: Chain index of the original flow
+ * @netdev: netdev structure.
+ * @type: Type of pre-entry from enum ct_entry_type
+ * @zt: Reference to the zone table this belongs to
+ * @children: List of tc_merge flows this flow forms part of
+ * @rule: Reference to the original TC flow rule
+ * @stats: Used to cache stats for updating
+ * @tun_offset: Used to indicate tunnel action offset in action list
+ */
+struct nfp_fl_ct_flow_entry {
+ unsigned long cookie;
+ struct list_head list_node;
+ u32 chain_index;
+ enum ct_entry_type type;
+ struct net_device *netdev;
+ struct nfp_fl_ct_zone_entry *zt;
+ struct list_head children;
+ struct flow_rule *rule;
+ struct flow_stats stats;
+ u8 tun_offset; // Set to NFP_FL_CT_NO_TUN if no tun
+};
+
+/**
+ * struct nfp_fl_ct_tc_merge - Merge of two flows from tc
+ * @cookie: Flow cookie, combination of pre and post ct cookies
+ * @hash_node: Used by the hashtable
+ * @pre_ct_list: This entry is part of a pre_ct_list
+ * @post_ct_list: This entry is part of a post_ct_list
+ * @zt: Reference to the zone table this belongs to
+ * @pre_ct_parent: The pre_ct_parent
+ * @post_ct_parent: The post_ct_parent
+ * @children: List of nft merged entries
+ */
+struct nfp_fl_ct_tc_merge {
+ unsigned long cookie[2];
+ struct rhash_head hash_node;
+ struct list_head pre_ct_list;
+ struct list_head post_ct_list;
+ struct nfp_fl_ct_zone_entry *zt;
+ struct nfp_fl_ct_flow_entry *pre_ct_parent;
+ struct nfp_fl_ct_flow_entry *post_ct_parent;
+ struct list_head children;
+};
+
+/**
+ * struct nfp_fl_nft_tc_merge - Merge of tc_merge flows with nft flow
+ * @netdev: Ingress netdev name
+ * @cookie: Flow cookie, combination of tc_merge and nft cookies
+ * @hash_node: Used by the hashtable
+ * @zt: Reference to the zone table this belongs to
+ * @nft_flow_list: This entry is part of a nft_flows_list
+ * @tc_merge_list: This entry is part of a ct_merge_list
+ * @tc_m_parent: The tc_merge parent
+ * @nft_parent: The nft_entry parent
+ * @tc_flower_cookie: The cookie of the flow offloaded to the nfp
+ * @flow_pay: Reference to the offloaded flow struct
+ */
+struct nfp_fl_nft_tc_merge {
+ struct net_device *netdev;
+ unsigned long cookie[3];
+ struct rhash_head hash_node;
+ struct nfp_fl_ct_zone_entry *zt;
+ struct list_head nft_flow_list;
+ struct list_head tc_merge_list;
+ struct nfp_fl_ct_tc_merge *tc_m_parent;
+ struct nfp_fl_ct_flow_entry *nft_parent;
+ unsigned long tc_flower_cookie;
+ struct nfp_fl_payload *flow_pay;
+};
+
+/**
+ * struct nfp_fl_ct_map_entry - Map between flow cookie and specific ct_flow
+ * @cookie: Flow cookie, same as original TC flow, used as key
+ * @hash_node: Used by the hashtable
+ * @ct_entry: Pointer to corresponding ct_entry
+ */
+struct nfp_fl_ct_map_entry {
+ unsigned long cookie;
+ struct rhash_head hash_node;
+ struct nfp_fl_ct_flow_entry *ct_entry;
+};
+
+bool is_pre_ct_flow(struct flow_cls_offload *flow);
+bool is_post_ct_flow(struct flow_cls_offload *flow);
+
+/**
+ * nfp_fl_ct_handle_pre_ct() - Handles -trk conntrack rules
+ * @priv: Pointer to app priv
+ * @netdev: netdev structure.
+ * @flow: TC flower classifier offload structure.
+ * @extack: Extack pointer for errors
+ *
+ * Adds a new entry to the relevant zone table and tries to
+ * merge with other +trk+est entries and offload if possible.
+ *
+ * Return: negative value on error, 0 if configured successfully.
+ */
+int nfp_fl_ct_handle_pre_ct(struct nfp_flower_priv *priv,
+ struct net_device *netdev,
+ struct flow_cls_offload *flow,
+ struct netlink_ext_ack *extack);
+/**
+ * nfp_fl_ct_handle_post_ct() - Handles +trk+est conntrack rules
+ * @priv: Pointer to app priv
+ * @netdev: netdev structure.
+ * @flow: TC flower classifier offload structure.
+ * @extack: Extack pointer for errors
+ *
+ * Adds a new entry to the relevant zone table and tries to
+ * merge with other -trk entries and offload if possible.
+ *
+ * Return: negative value on error, 0 if configured successfully.
+ */
+int nfp_fl_ct_handle_post_ct(struct nfp_flower_priv *priv,
+ struct net_device *netdev,
+ struct flow_cls_offload *flow,
+ struct netlink_ext_ack *extack);
+
+/**
+ * nfp_fl_ct_clean_flow_entry() - Free a nfp_fl_ct_flow_entry
+ * @entry: Flow entry to cleanup
+ */
+void nfp_fl_ct_clean_flow_entry(struct nfp_fl_ct_flow_entry *entry);
+
+/**
+ * nfp_fl_ct_del_flow() - Handle flow_del callbacks for conntrack
+ * @ct_map_ent: ct map entry for the flow that needs deleting
+ */
+int nfp_fl_ct_del_flow(struct nfp_fl_ct_map_entry *ct_map_ent);
+
+/**
+ * nfp_fl_ct_handle_nft_flow() - Handle flower flow callbacks for nft table
+ * @type: Type provided by callback
+ * @type_data: Callback data
+ * @cb_priv: Pointer to data provided when registering the callback, in this
+ * case it's the zone table.
+ */
+int nfp_fl_ct_handle_nft_flow(enum tc_setup_type type, void *type_data,
+ void *cb_priv);
+#endif
diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h
index 31377923ea3d..0fbd682ccf72 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/main.h
+++ b/drivers/net/ethernet/netronome/nfp/flower/main.h
@@ -193,6 +193,9 @@ struct nfp_fl_internal_ports {
* @qos_stats_lock: Lock on qos stats updates
* @pre_tun_rule_cnt: Number of pre-tunnel rules offloaded
* @merge_table: Hash table to store merged flows
+ * @ct_zone_table: Hash table used to store the different zones
+ * @ct_zone_wc: Special zone entry for wildcarded zone matches
+ * @ct_map_table: Hash table used to referennce ct flows
*/
struct nfp_flower_priv {
struct nfp_app *app;
@@ -227,6 +230,9 @@ struct nfp_flower_priv {
spinlock_t qos_stats_lock; /* Protect the qos stats */
int pre_tun_rule_cnt;
struct rhashtable merge_table;
+ struct rhashtable ct_zone_table;
+ struct nfp_fl_ct_zone_entry *ct_zone_wc;
+ struct rhashtable ct_map_table;
};
/**
diff --git a/drivers/net/ethernet/netronome/nfp/flower/metadata.c b/drivers/net/ethernet/netronome/nfp/flower/metadata.c
index 327bb56b3ef5..621113650a9b 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/metadata.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/metadata.c
@@ -9,6 +9,7 @@
#include <net/pkt_cls.h>
#include "cmsg.h"
+#include "conntrack.h"
#include "main.h"
#include "../nfp_app.h"
@@ -496,6 +497,20 @@ const struct rhashtable_params merge_table_params = {
.key_len = sizeof(u64),
};
+const struct rhashtable_params nfp_zone_table_params = {
+ .head_offset = offsetof(struct nfp_fl_ct_zone_entry, hash_node),
+ .key_len = sizeof(u16),
+ .key_offset = offsetof(struct nfp_fl_ct_zone_entry, zone),
+ .automatic_shrinking = false,
+};
+
+const struct rhashtable_params nfp_ct_map_params = {
+ .head_offset = offsetof(struct nfp_fl_ct_map_entry, hash_node),
+ .key_len = sizeof(unsigned long),
+ .key_offset = offsetof(struct nfp_fl_ct_map_entry, cookie),
+ .automatic_shrinking = true,
+};
+
int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
unsigned int host_num_mems)
{
@@ -516,6 +531,14 @@ int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
if (err)
goto err_free_stats_ctx_table;
+ err = rhashtable_init(&priv->ct_zone_table, &nfp_zone_table_params);
+ if (err)
+ goto err_free_merge_table;
+
+ err = rhashtable_init(&priv->ct_map_table, &nfp_ct_map_params);
+ if (err)
+ goto err_free_ct_zone_table;
+
get_random_bytes(&priv->mask_id_seed, sizeof(priv->mask_id_seed));
/* Init ring buffer and unallocated mask_ids. */
@@ -523,7 +546,7 @@ int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
kmalloc_array(NFP_FLOWER_MASK_ENTRY_RS,
NFP_FLOWER_MASK_ELEMENT_RS, GFP_KERNEL);
if (!priv->mask_ids.mask_id_free_list.buf)
- goto err_free_merge_table;
+ goto err_free_ct_map_table;
priv->mask_ids.init_unallocated = NFP_FLOWER_MASK_ENTRY_RS - 1;
@@ -560,6 +583,10 @@ err_free_last_used:
kfree(priv->mask_ids.last_used);
err_free_mask_id:
kfree(priv->mask_ids.mask_id_free_list.buf);
+err_free_ct_map_table:
+ rhashtable_destroy(&priv->ct_map_table);
+err_free_ct_zone_table:
+ rhashtable_destroy(&priv->ct_zone_table);
err_free_merge_table:
rhashtable_destroy(&priv->merge_table);
err_free_stats_ctx_table:
@@ -569,6 +596,100 @@ err_free_flow_table:
return -ENOMEM;
}
+static void nfp_zone_table_entry_destroy(struct nfp_fl_ct_zone_entry *zt)
+{
+ if (!zt)
+ return;
+
+ if (!list_empty(&zt->pre_ct_list)) {
+ struct rhashtable *m_table = &zt->priv->ct_map_table;
+ struct nfp_fl_ct_flow_entry *entry, *tmp;
+ struct nfp_fl_ct_map_entry *map;
+
+ WARN_ONCE(1, "pre_ct_list not empty as expected, cleaning up\n");
+ list_for_each_entry_safe(entry, tmp, &zt->pre_ct_list,
+ list_node) {
+ map = rhashtable_lookup_fast(m_table,
+ &entry->cookie,
+ nfp_ct_map_params);
+ WARN_ON_ONCE(rhashtable_remove_fast(m_table,
+ &map->hash_node,
+ nfp_ct_map_params));
+ nfp_fl_ct_clean_flow_entry(entry);
+ kfree(map);
+ }
+ }
+
+ if (!list_empty(&zt->post_ct_list)) {
+ struct rhashtable *m_table = &zt->priv->ct_map_table;
+ struct nfp_fl_ct_flow_entry *entry, *tmp;
+ struct nfp_fl_ct_map_entry *map;
+
+ WARN_ONCE(1, "post_ct_list not empty as expected, cleaning up\n");
+ list_for_each_entry_safe(entry, tmp, &zt->post_ct_list,
+ list_node) {
+ map = rhashtable_lookup_fast(m_table,
+ &entry->cookie,
+ nfp_ct_map_params);
+ WARN_ON_ONCE(rhashtable_remove_fast(m_table,
+ &map->hash_node,
+ nfp_ct_map_params));
+ nfp_fl_ct_clean_flow_entry(entry);
+ kfree(map);
+ }
+ }
+
+ if (zt->nft) {
+ nf_flow_table_offload_del_cb(zt->nft,
+ nfp_fl_ct_handle_nft_flow,
+ zt);
+ zt->nft = NULL;
+ }
+
+ if (!list_empty(&zt->nft_flows_list)) {
+ struct rhashtable *m_table = &zt->priv->ct_map_table;
+ struct nfp_fl_ct_flow_entry *entry, *tmp;
+ struct nfp_fl_ct_map_entry *map;
+
+ WARN_ONCE(1, "nft_flows_list not empty as expected, cleaning up\n");
+ list_for_each_entry_safe(entry, tmp, &zt->nft_flows_list,
+ list_node) {
+ map = rhashtable_lookup_fast(m_table,
+ &entry->cookie,
+ nfp_ct_map_params);
+ WARN_ON_ONCE(rhashtable_remove_fast(m_table,
+ &map->hash_node,
+ nfp_ct_map_params));
+ nfp_fl_ct_clean_flow_entry(entry);
+ kfree(map);
+ }
+ }
+
+ rhashtable_free_and_destroy(&zt->tc_merge_tb,
+ nfp_check_rhashtable_empty, NULL);
+ rhashtable_free_and_destroy(&zt->nft_merge_tb,
+ nfp_check_rhashtable_empty, NULL);
+
+ kfree(zt);
+}
+
+static void nfp_free_zone_table_entry(void *ptr, void *arg)
+{
+ struct nfp_fl_ct_zone_entry *zt = ptr;
+
+ nfp_zone_table_entry_destroy(zt);
+}
+
+static void nfp_free_map_table_entry(void *ptr, void *arg)
+{
+ struct nfp_fl_ct_map_entry *map = ptr;
+
+ if (!map)
+ return;
+
+ kfree(map);
+}
+
void nfp_flower_metadata_cleanup(struct nfp_app *app)
{
struct nfp_flower_priv *priv = app->priv;
@@ -582,6 +703,12 @@ void nfp_flower_metadata_cleanup(struct nfp_app *app)
nfp_check_rhashtable_empty, NULL);
rhashtable_free_and_destroy(&priv->merge_table,
nfp_check_rhashtable_empty, NULL);
+ rhashtable_free_and_destroy(&priv->ct_zone_table,
+ nfp_free_zone_table_entry, NULL);
+ nfp_zone_table_entry_destroy(priv->ct_zone_wc);
+
+ rhashtable_free_and_destroy(&priv->ct_map_table,
+ nfp_free_map_table_entry, NULL);
kvfree(priv->stats);
kfree(priv->mask_ids.mask_id_free_list.buf);
kfree(priv->mask_ids.last_used);
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index e95969c462e4..2406d33356ad 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -7,6 +7,7 @@
#include "cmsg.h"
#include "main.h"
+#include "conntrack.h"
#include "../nfpcore/nfp_cpp.h"
#include "../nfpcore/nfp_nsp.h"
#include "../nfp_app.h"
@@ -1276,6 +1277,20 @@ nfp_flower_validate_pre_tun_rule(struct nfp_app *app,
return 0;
}
+static bool offload_pre_check(struct flow_cls_offload *flow)
+{
+ struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
+ struct flow_dissector *dissector = rule->match.dissector;
+
+ if (dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CT))
+ return false;
+
+ if (flow->common.chain_index)
+ return false;
+
+ return true;
+}
+
/**
* nfp_flower_add_offload() - Adds a new flow to hardware.
* @app: Pointer to the APP handle
@@ -1302,6 +1317,15 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
if (nfp_netdev_is_nfp_repr(netdev))
port = nfp_port_from_netdev(netdev);
+ if (is_pre_ct_flow(flow))
+ return nfp_fl_ct_handle_pre_ct(priv, netdev, flow, extack);
+
+ if (is_post_ct_flow(flow))
+ return nfp_fl_ct_handle_post_ct(priv, netdev, flow, extack);
+
+ if (!offload_pre_check(flow))
+ return -EOPNOTSUPP;
+
key_layer = kmalloc(sizeof(*key_layer), GFP_KERNEL);
if (!key_layer)
return -ENOMEM;
@@ -1481,6 +1505,7 @@ nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev,
struct flow_cls_offload *flow)
{
struct nfp_flower_priv *priv = app->priv;
+ struct nfp_fl_ct_map_entry *ct_map_ent;
struct netlink_ext_ack *extack = NULL;
struct nfp_fl_payload *nfp_flow;
struct nfp_port *port = NULL;
@@ -1490,6 +1515,14 @@ nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev,
if (nfp_netdev_is_nfp_repr(netdev))
port = nfp_port_from_netdev(netdev);
+ /* Check ct_map_table */
+ ct_map_ent = rhashtable_lookup_fast(&priv->ct_map_table, &flow->cookie,
+ nfp_ct_map_params);
+ if (ct_map_ent) {
+ err = nfp_fl_ct_del_flow(ct_map_ent);
+ return err;
+ }
+
nfp_flow = nfp_flower_search_fl_table(app, flow->cookie, netdev);
if (!nfp_flow) {
NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot remove flow that does not exist");
@@ -1646,9 +1679,10 @@ nfp_flower_repr_offload(struct nfp_app *app, struct net_device *netdev,
static int nfp_flower_setup_tc_block_cb(enum tc_setup_type type,
void *type_data, void *cb_priv)
{
+ struct flow_cls_common_offload *common = type_data;
struct nfp_repr *repr = cb_priv;
- if (!tc_cls_can_offload_and_chain0(repr->netdev, type_data))
+ if (!tc_can_offload_extack(repr->netdev, common->extack))
return -EOPNOTSUPP;
switch (type) {
@@ -1746,10 +1780,6 @@ 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 flow_cls_offload *flower = type_data;
-
- if (flower->common.chain_index)
- return -EOPNOTSUPP;
switch (type) {
case TC_SETUP_CLSFLOWER:
diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
index d19c02e99114..ab70179728f6 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
@@ -21,7 +21,7 @@
#define NFP_TUN_PRE_TUN_IPV6_BIT BIT(7)
/**
- * struct nfp_tun_pre_run_rule - rule matched before decap
+ * struct nfp_tun_pre_tun_rule - rule matched before decap
* @flags: options for the rule offset
* @port_idx: index of destination MAC address for the rule
* @vlan_tci: VLAN info associated with MAC
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index eeb30680b4dc..5dfa4799c34f 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -1819,7 +1819,6 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
struct xdp_buff xdp;
int idx;
- rcu_read_lock();
xdp_prog = READ_ONCE(dp->xdp_prog);
true_bufsz = xdp_prog ? PAGE_SIZE : dp->fl_bufsz;
xdp_init_buff(&xdp, PAGE_SIZE - NFP_NET_RX_BUF_HEADROOM,
@@ -2036,7 +2035,6 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
if (!nfp_net_xdp_complete(tx_ring))
pkts_polled = budget;
}
- rcu_read_unlock();
return pkts_polled;
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
index b3cabc274121..3b8e675087de 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
@@ -103,6 +103,7 @@ nfp_repr_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
case NFP_PORT_PF_PORT:
case NFP_PORT_VF_PORT:
nfp_repr_vnic_get_stats64(repr->port, stats);
+ break;
default:
break;
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
index 94994a939277..d7ac0307797f 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
@@ -905,8 +905,7 @@ area_cache_put(struct nfp_cpp *cpp, struct nfp_cpp_area_cache *cache)
return;
/* Move to front of LRU */
- list_del(&cache->entry);
- list_add(&cache->entry, &cpp->area_cache_list);
+ list_move(&cache->entry, &cpp->area_cache_list);
mutex_unlock(&cpp->area_cache_mutex);
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c
index d4e02542e2e9..e2e5fd003ad6 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c
@@ -24,7 +24,7 @@
#define NFFW_FWID_ALL 255
-/**
+/*
* NFFW_INFO_VERSION history:
* 0: This was never actually used (before versioning), but it refers to
* the previous struct which had FWINFO_CNT = MEINFO_CNT = 120 that later
diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c
index a6861df9904f..2d097dcb7bda 100644
--- a/drivers/net/ethernet/ni/nixge.c
+++ b/drivers/net/ethernet/ni/nixge.c
@@ -1224,7 +1224,6 @@ static int nixge_of_get_resources(struct platform_device *pdev)
const struct of_device_id *of_id;
enum nixge_version version;
struct resource *ctrlres;
- struct resource *dmares;
struct net_device *ndev;
struct nixge_priv *priv;
@@ -1236,12 +1235,9 @@ static int nixge_of_get_resources(struct platform_device *pdev)
version = (enum nixge_version)of_id->data;
if (version <= NIXGE_V2)
- dmares = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->dma_regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
else
- dmares = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "dma");
-
- priv->dma_regs = devm_ioremap_resource(&pdev->dev, dmares);
+ priv->dma_regs = devm_platform_ioremap_resource_byname(pdev, "dma");
if (IS_ERR(priv->dma_regs)) {
netdev_err(ndev, "failed to map dma regs\n");
return PTR_ERR(priv->dma_regs);
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
index a6823c4d355d..108f312bc542 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
@@ -596,8 +596,6 @@ struct pch_gbe_adapter {
#define pch_gbe_hw_to_adapter(hw) container_of(hw, struct pch_gbe_adapter, hw)
-extern const char pch_driver_version[];
-
/* pch_gbe_main.c */
int pch_gbe_up(struct pch_gbe_adapter *adapter);
void pch_gbe_down(struct pch_gbe_adapter *adapter);
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c
index a58f14aca10c..660b07cb5b92 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c
@@ -8,6 +8,8 @@
#include "pch_gbe.h"
#include "pch_gbe_phy.h"
+static const char pch_driver_version[] = "1.01";
+
/*
* pch_gbe_stats - Stats item information
*/
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
index 334af49e5add..e351f3d1608f 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
@@ -8,15 +8,16 @@
#include "pch_gbe.h"
#include "pch_gbe_phy.h"
+
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_classify.h>
#include <linux/ptp_pch.h>
#include <linux/gpio.h>
-#define DRV_VERSION "1.01"
-const char pch_driver_version[] = DRV_VERSION;
-
#define PCH_GBE_MAR_ENTRIES 16
#define PCH_GBE_SHORT_PKT 64
#define DSC_INIT16 0xC000
@@ -97,8 +98,6 @@ const char pch_driver_version[] = DRV_VERSION;
#define PTP_L4_MULTICAST_SA "01:00:5e:00:01:81"
#define PTP_L2_MULTICAST_SA "01:1b:19:00:00:00"
-#define MINNOW_PHY_RESET_GPIO 13
-
static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg);
static void pch_gbe_mdio_write(struct net_device *netdev, int addr, int reg,
int data);
@@ -108,7 +107,7 @@ static int pch_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
{
u8 *data = skb->data;
unsigned int offset;
- u16 *hi, *id;
+ u16 hi, id;
u32 lo;
if (ptp_classify_raw(skb) == PTP_CLASS_NONE)
@@ -119,14 +118,11 @@ static int pch_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(seqid))
return 0;
- hi = (u16 *)(data + offset + OFF_PTP_SOURCE_UUID);
- id = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
-
- memcpy(&lo, &hi[1], sizeof(lo));
+ hi = get_unaligned_be16(data + offset + OFF_PTP_SOURCE_UUID + 0);
+ lo = get_unaligned_be32(data + offset + OFF_PTP_SOURCE_UUID + 2);
+ id = get_unaligned_be16(data + offset + OFF_PTP_SEQUENCE_ID);
- return (uid_hi == *hi &&
- uid_lo == lo &&
- seqid == *id);
+ return (uid_hi == hi && uid_lo == lo && seqid == id);
}
static void
@@ -136,7 +132,6 @@ pch_rx_timestamp(struct pch_gbe_adapter *adapter, struct sk_buff *skb)
struct pci_dev *pdev;
u64 ns;
u32 hi, lo, val;
- u16 uid, seq;
if (!adapter->hwts_rx_en)
return;
@@ -152,10 +147,7 @@ pch_rx_timestamp(struct pch_gbe_adapter *adapter, struct sk_buff *skb)
lo = pch_src_uuid_lo_read(pdev);
hi = pch_src_uuid_hi_read(pdev);
- uid = hi & 0xffff;
- seq = (hi >> 16) & 0xffff;
-
- if (!pch_ptp_match(skb, htons(uid), htonl(lo), htons(seq)))
+ if (!pch_ptp_match(skb, hi, lo, hi >> 16))
goto out;
ns = pch_rx_snap_read(pdev);
@@ -298,15 +290,12 @@ static s32 pch_gbe_mac_read_mac_addr(struct pch_gbe_hw *hw)
* @reg: Pointer of register
* @bit: Busy bit
*/
-static void pch_gbe_wait_clr_bit(void *reg, u32 bit)
+static void pch_gbe_wait_clr_bit(void __iomem *reg, u32 bit)
{
u32 tmp;
/* wait busy */
- tmp = 1000;
- while ((ioread32(reg) & bit) && --tmp)
- cpu_relax();
- if (!tmp)
+ if (readx_poll_timeout_atomic(ioread32, reg, tmp, !(tmp & bit), 0, 10))
pr_err("Error: busy bit is not cleared\n");
}
@@ -490,18 +479,13 @@ u16 pch_gbe_mac_ctrl_miim(struct pch_gbe_hw *hw, u32 addr, u32 dir, u32 reg,
u16 data)
{
struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
- u32 data_out = 0;
- unsigned int i;
unsigned long flags;
+ u32 data_out;
spin_lock_irqsave(&hw->miim_lock, flags);
- for (i = 100; i; --i) {
- if ((ioread32(&hw->reg->MIIM) & PCH_GBE_MIIM_OPER_READY))
- break;
- udelay(20);
- }
- if (i == 0) {
+ if (readx_poll_timeout_atomic(ioread32, &hw->reg->MIIM, data_out,
+ data_out & PCH_GBE_MIIM_OPER_READY, 20, 2000)) {
netdev_err(adapter->netdev, "pch-gbe.miim won't go Ready\n");
spin_unlock_irqrestore(&hw->miim_lock, flags);
return 0; /* No way to indicate timeout error */
@@ -509,12 +493,8 @@ u16 pch_gbe_mac_ctrl_miim(struct pch_gbe_hw *hw, u32 addr, u32 dir, u32 reg,
iowrite32(((reg << PCH_GBE_MIIM_REG_ADDR_SHIFT) |
(addr << PCH_GBE_MIIM_PHY_ADDR_SHIFT) |
dir | data), &hw->reg->MIIM);
- for (i = 0; i < 100; i++) {
- udelay(20);
- data_out = ioread32(&hw->reg->MIIM);
- if ((data_out & PCH_GBE_MIIM_OPER_READY))
- break;
- }
+ readx_poll_timeout_atomic(ioread32, &hw->reg->MIIM, data_out,
+ data_out & PCH_GBE_MIIM_OPER_READY, 20, 2000);
spin_unlock_irqrestore(&hw->miim_lock, flags);
netdev_dbg(adapter->netdev, "PHY %s: reg=%d, data=0x%04X\n",
@@ -2532,9 +2512,13 @@ static int pch_gbe_probe(struct pci_dev *pdev,
adapter->pdev = pdev;
adapter->hw.back = adapter;
adapter->hw.reg = pcim_iomap_table(pdev)[PCH_GBE_PCI_BAR];
+
adapter->pdata = (struct pch_gbe_privdata *)pci_id->driver_data;
- if (adapter->pdata && adapter->pdata->platform_init)
- adapter->pdata->platform_init(pdev);
+ if (adapter->pdata && adapter->pdata->platform_init) {
+ ret = adapter->pdata->platform_init(pdev);
+ if (ret)
+ goto err_free_netdev;
+ }
adapter->ptp_pdev =
pci_get_domain_bus_and_slot(pci_domain_nr(adapter->pdev->bus),
@@ -2624,26 +2608,45 @@ err_free_netdev:
return ret;
}
+static void pch_gbe_gpio_remove_table(void *table)
+{
+ gpiod_remove_lookup_table(table);
+}
+
+static int pch_gbe_gpio_add_table(struct device *dev, void *table)
+{
+ gpiod_add_lookup_table(table);
+ return devm_add_action_or_reset(dev, pch_gbe_gpio_remove_table, table);
+}
+
+static struct gpiod_lookup_table pch_gbe_minnow_gpio_table = {
+ .dev_id = "0000:02:00.1",
+ .table = {
+ GPIO_LOOKUP("sch_gpio.33158", 13, NULL, GPIO_ACTIVE_LOW),
+ {}
+ },
+};
+
/* The AR803X PHY on the MinnowBoard requires a physical pin to be toggled to
* ensure it is awake for probe and init. Request the line and reset the PHY.
*/
static int pch_gbe_minnow_platform_init(struct pci_dev *pdev)
{
- unsigned long flags = GPIOF_DIR_OUT | GPIOF_INIT_HIGH | GPIOF_EXPORT;
- unsigned gpio = MINNOW_PHY_RESET_GPIO;
+ struct gpio_desc *gpiod;
int ret;
- ret = devm_gpio_request_one(&pdev->dev, gpio, flags,
- "minnow_phy_reset");
- if (ret) {
- dev_err(&pdev->dev,
- "ERR: Can't request PHY reset GPIO line '%d'\n", gpio);
+ ret = pch_gbe_gpio_add_table(&pdev->dev, &pch_gbe_minnow_gpio_table);
+ if (ret)
return ret;
- }
- gpio_set_value(gpio, 0);
+ gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_HIGH);
+ if (IS_ERR(gpiod))
+ return dev_err_probe(&pdev->dev, PTR_ERR(gpiod),
+ "Can't request PHY reset GPIO line\n");
+
+ gpiod_set_value(gpiod, 1);
usleep_range(1250, 1500);
- gpio_set_value(gpio, 1);
+ gpiod_set_value(gpiod, 0);
usleep_range(1250, 1500);
return ret;
@@ -2722,7 +2725,6 @@ module_pci_driver(pch_gbe_driver);
MODULE_DESCRIPTION("EG20T PCH Gigabit ethernet Driver");
MODULE_AUTHOR("LAPIS SEMICONDUCTOR, <tshimizu818@gmail.com>");
MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
MODULE_DEVICE_TABLE(pci, pch_gbe_pcidev_id);
/* pch_gbe_main.c */
diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig
index 6b5ddb07ee83..98f430905ffa 100644
--- a/drivers/net/ethernet/qlogic/Kconfig
+++ b/drivers/net/ethernet/qlogic/Kconfig
@@ -110,6 +110,9 @@ config QED_RDMA
config QED_ISCSI
bool
+config QED_NVMETCP
+ bool
+
config QED_FCOE
bool
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
index 08f9477d2ee8..35ec9aab3dc7 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
@@ -1685,6 +1685,7 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max)
break;
case NETXEN_NIC_RESPONSE_DESC:
netxen_handle_fw_message(desc_cnt, consumer, sds_ring);
+ goto skip;
default:
goto skip;
}
diff --git a/drivers/net/ethernet/qlogic/qed/Makefile b/drivers/net/ethernet/qlogic/qed/Makefile
index 8251755ec18c..0d9c2fe0245d 100644
--- a/drivers/net/ethernet/qlogic/qed/Makefile
+++ b/drivers/net/ethernet/qlogic/qed/Makefile
@@ -28,6 +28,11 @@ qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o
qed-$(CONFIG_QED_LL2) += qed_ll2.o
qed-$(CONFIG_QED_OOO) += qed_ooo.o
+qed-$(CONFIG_QED_NVMETCP) += \
+ qed_nvmetcp.o \
+ qed_nvmetcp_fw_funcs.o \
+ qed_nvmetcp_ip_services.o
+
qed-$(CONFIG_QED_RDMA) += \
qed_iwarp.o \
qed_rdma.o \
diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h
index a20cb8a0c377..b590c70539b5 100644
--- a/drivers/net/ethernet/qlogic/qed/qed.h
+++ b/drivers/net/ethernet/qlogic/qed/qed.h
@@ -49,6 +49,8 @@ extern const struct qed_common_ops qed_common_ops_pass;
#define QED_MIN_WIDS (4)
#define QED_PF_DEMS_SIZE (4)
+#define QED_LLH_DONT_CARE 0
+
/* cau states */
enum qed_coalescing_mode {
QED_COAL_MODE_DISABLE,
@@ -200,6 +202,7 @@ enum qed_pci_personality {
QED_PCI_ETH,
QED_PCI_FCOE,
QED_PCI_ISCSI,
+ QED_PCI_NVMETCP,
QED_PCI_ETH_ROCE,
QED_PCI_ETH_IWARP,
QED_PCI_ETH_RDMA,
@@ -239,6 +242,7 @@ enum QED_FEATURE {
QED_PF_L2_QUE,
QED_VF,
QED_RDMA_CNQ,
+ QED_NVMETCP_CQ,
QED_ISCSI_CQ,
QED_FCOE_CQ,
QED_VF_L2_QUE,
@@ -284,6 +288,8 @@ struct qed_hw_info {
((dev)->hw_info.personality == QED_PCI_FCOE)
#define QED_IS_ISCSI_PERSONALITY(dev) \
((dev)->hw_info.personality == QED_PCI_ISCSI)
+#define QED_IS_NVMETCP_PERSONALITY(dev) \
+ ((dev)->hw_info.personality == QED_PCI_NVMETCP)
/* Resource Allocation scheme results */
u32 resc_start[QED_MAX_RESC];
@@ -592,6 +598,7 @@ struct qed_hwfn {
struct qed_ooo_info *p_ooo_info;
struct qed_rdma_info *p_rdma_info;
struct qed_iscsi_info *p_iscsi_info;
+ struct qed_nvmetcp_info *p_nvmetcp_info;
struct qed_fcoe_info *p_fcoe_info;
struct qed_pf_params pf_params;
@@ -828,6 +835,7 @@ struct qed_dev {
struct qed_eth_cb_ops *eth;
struct qed_fcoe_cb_ops *fcoe;
struct qed_iscsi_cb_ops *iscsi;
+ struct qed_nvmetcp_cb_ops *nvmetcp;
} protocol_ops;
void *ops_cookie;
@@ -999,4 +1007,10 @@ int qed_mfw_fill_tlv_data(struct qed_hwfn *hwfn,
void qed_hw_info_set_offload_tc(struct qed_hw_info *p_info, u8 tc);
void qed_periodic_db_rec_start(struct qed_hwfn *p_hwfn);
+
+int qed_llh_add_src_tcp_port_filter(struct qed_dev *cdev, u16 src_port);
+int qed_llh_add_dst_tcp_port_filter(struct qed_dev *cdev, u16 dest_port);
+void qed_llh_remove_src_tcp_port_filter(struct qed_dev *cdev, u16 src_port);
+void qed_llh_remove_dst_tcp_port_filter(struct qed_dev *cdev, u16 src_port);
+void qed_llh_clear_all_filters(struct qed_dev *cdev);
#endif /* _QED_H */
diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
index 0a22f8ce9a2c..5a0a3cbcc1c1 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -94,14 +94,14 @@ struct src_ent {
static bool src_proto(enum protocol_type type)
{
- return type == PROTOCOLID_ISCSI ||
+ return type == PROTOCOLID_TCP_ULP ||
type == PROTOCOLID_FCOE ||
type == PROTOCOLID_IWARP;
}
static bool tm_cid_proto(enum protocol_type type)
{
- return type == PROTOCOLID_ISCSI ||
+ return type == PROTOCOLID_TCP_ULP ||
type == PROTOCOLID_FCOE ||
type == PROTOCOLID_ROCE ||
type == PROTOCOLID_IWARP;
@@ -2072,7 +2072,6 @@ int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn, u32 rdma_tasks)
PROTOCOLID_FCOE,
p_params->num_cons,
0);
-
qed_cxt_set_proto_tid_count(p_hwfn, PROTOCOLID_FCOE,
QED_CXT_FCOE_TID_SEG, 0,
p_params->num_tasks, true);
@@ -2090,13 +2089,12 @@ int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn, u32 rdma_tasks)
if (p_params->num_cons && p_params->num_tasks) {
qed_cxt_set_proto_cid_count(p_hwfn,
- PROTOCOLID_ISCSI,
+ PROTOCOLID_TCP_ULP,
p_params->num_cons,
0);
-
qed_cxt_set_proto_tid_count(p_hwfn,
- PROTOCOLID_ISCSI,
- QED_CXT_ISCSI_TID_SEG,
+ PROTOCOLID_TCP_ULP,
+ QED_CXT_TCP_ULP_TID_SEG,
0,
p_params->num_tasks,
true);
@@ -2106,6 +2104,29 @@ int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn, u32 rdma_tasks)
}
break;
}
+ case QED_PCI_NVMETCP:
+ {
+ struct qed_nvmetcp_pf_params *p_params;
+
+ p_params = &p_hwfn->pf_params.nvmetcp_pf_params;
+
+ if (p_params->num_cons && p_params->num_tasks) {
+ qed_cxt_set_proto_cid_count(p_hwfn,
+ PROTOCOLID_TCP_ULP,
+ p_params->num_cons,
+ 0);
+ qed_cxt_set_proto_tid_count(p_hwfn,
+ PROTOCOLID_TCP_ULP,
+ QED_CXT_TCP_ULP_TID_SEG,
+ 0,
+ p_params->num_tasks,
+ true);
+ } else {
+ DP_INFO(p_hwfn->cdev,
+ "NvmeTCP personality used without setting params!\n");
+ }
+ break;
+ }
default:
return -EINVAL;
}
@@ -2129,8 +2150,9 @@ int qed_cxt_get_tid_mem_info(struct qed_hwfn *p_hwfn,
seg = QED_CXT_FCOE_TID_SEG;
break;
case QED_PCI_ISCSI:
- proto = PROTOCOLID_ISCSI;
- seg = QED_CXT_ISCSI_TID_SEG;
+ case QED_PCI_NVMETCP:
+ proto = PROTOCOLID_TCP_ULP;
+ seg = QED_CXT_TCP_ULP_TID_SEG;
break;
default:
return -EINVAL;
@@ -2455,8 +2477,9 @@ int qed_cxt_get_task_ctx(struct qed_hwfn *p_hwfn,
seg = QED_CXT_FCOE_TID_SEG;
break;
case QED_PCI_ISCSI:
- proto = PROTOCOLID_ISCSI;
- seg = QED_CXT_ISCSI_TID_SEG;
+ case QED_PCI_NVMETCP:
+ proto = PROTOCOLID_TCP_ULP;
+ seg = QED_CXT_TCP_ULP_TID_SEG;
break;
default:
return -EINVAL;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.h b/drivers/net/ethernet/qlogic/qed/qed_cxt.h
index 056e79620a0e..8adb7ed0c12d 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.h
@@ -50,7 +50,7 @@ int qed_cxt_get_cid_info(struct qed_hwfn *p_hwfn,
int qed_cxt_get_tid_mem_info(struct qed_hwfn *p_hwfn,
struct qed_tid_mem *p_info);
-#define QED_CXT_ISCSI_TID_SEG PROTOCOLID_ISCSI
+#define QED_CXT_TCP_ULP_TID_SEG PROTOCOLID_TCP_ULP
#define QED_CXT_ROCE_TID_SEG PROTOCOLID_ROCE
#define QED_CXT_FCOE_TID_SEG PROTOCOLID_FCOE
enum qed_cxt_elem_type {
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index d2f5855b2ea7..0410c3604abd 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -37,6 +37,7 @@
#include "qed_sriov.h"
#include "qed_vf.h"
#include "qed_rdma.h"
+#include "qed_nvmetcp.h"
static DEFINE_SPINLOCK(qm_lock);
@@ -667,7 +668,8 @@ qed_llh_set_engine_affin(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
}
/* 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))
+ if (QED_IS_FCOE_PERSONALITY(p_hwfn) || QED_IS_ISCSI_PERSONALITY(p_hwfn) ||
+ QED_IS_NVMETCP_PERSONALITY(p_hwfn))
eng = cdev->fir_affin ? QED_ENG1 : QED_ENG0;
else /* L2_PERSONALITY */
eng = QED_BOTH_ENG;
@@ -1164,6 +1166,9 @@ void qed_llh_remove_mac_filter(struct qed_dev *cdev,
if (!test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits))
goto out;
+ if (QED_IS_NVMETCP_PERSONALITY(p_hwfn))
+ return;
+
ether_addr_copy(filter.mac.addr, mac_addr);
rc = qed_llh_shadow_remove_filter(cdev, ppfid, &filter, &filter_idx,
&ref_cnt);
@@ -1381,6 +1386,11 @@ void qed_resc_free(struct qed_dev *cdev)
qed_ooo_free(p_hwfn);
}
+ if (p_hwfn->hw_info.personality == QED_PCI_NVMETCP) {
+ qed_nvmetcp_free(p_hwfn);
+ qed_ooo_free(p_hwfn);
+ }
+
if (QED_IS_RDMA_PERSONALITY(p_hwfn) && rdma_info) {
qed_spq_unregister_async_cb(p_hwfn, rdma_info->proto);
qed_rdma_info_free(p_hwfn);
@@ -1423,6 +1433,7 @@ static u32 qed_get_pq_flags(struct qed_hwfn *p_hwfn)
flags |= PQ_FLAGS_OFLD;
break;
case QED_PCI_ISCSI:
+ case QED_PCI_NVMETCP:
flags |= PQ_FLAGS_ACK | PQ_FLAGS_OOO | PQ_FLAGS_OFLD;
break;
case QED_PCI_ETH_ROCE:
@@ -2263,10 +2274,11 @@ int qed_resc_alloc(struct qed_dev *cdev)
* at the same time
*/
n_eqes += num_cons + 2 * MAX_NUM_VFS_BB + n_srq;
- } else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
+ } else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI ||
+ p_hwfn->hw_info.personality == QED_PCI_NVMETCP) {
num_cons =
qed_cxt_get_proto_cid_count(p_hwfn,
- PROTOCOLID_ISCSI,
+ PROTOCOLID_TCP_ULP,
NULL);
n_eqes += 2 * num_cons;
}
@@ -2313,6 +2325,15 @@ int qed_resc_alloc(struct qed_dev *cdev)
goto alloc_err;
}
+ if (p_hwfn->hw_info.personality == QED_PCI_NVMETCP) {
+ rc = qed_nvmetcp_alloc(p_hwfn);
+ if (rc)
+ goto alloc_err;
+ rc = qed_ooo_alloc(p_hwfn);
+ if (rc)
+ goto alloc_err;
+ }
+
if (QED_IS_RDMA_PERSONALITY(p_hwfn)) {
rc = qed_rdma_info_alloc(p_hwfn);
if (rc)
@@ -2393,6 +2414,11 @@ void qed_resc_setup(struct qed_dev *cdev)
qed_iscsi_setup(p_hwfn);
qed_ooo_setup(p_hwfn);
}
+
+ if (p_hwfn->hw_info.personality == QED_PCI_NVMETCP) {
+ qed_nvmetcp_setup(p_hwfn);
+ qed_ooo_setup(p_hwfn);
+ }
}
}
@@ -2854,7 +2880,8 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn,
/* Protocol Configuration */
STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_TCP_RT_OFFSET,
- (p_hwfn->hw_info.personality == QED_PCI_ISCSI) ? 1 : 0);
+ ((p_hwfn->hw_info.personality == QED_PCI_ISCSI) ||
+ (p_hwfn->hw_info.personality == QED_PCI_NVMETCP)) ? 1 : 0);
STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_FCOE_RT_OFFSET,
(p_hwfn->hw_info.personality == QED_PCI_FCOE) ? 1 : 0);
STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_ROCE_RT_OFFSET, 0);
@@ -3535,14 +3562,21 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn)
feat_num[QED_ISCSI_CQ] = min_t(u32, sb_cnt.cnt,
RESC_NUM(p_hwfn,
QED_CMDQS_CQS));
+
+ if (QED_IS_NVMETCP_PERSONALITY(p_hwfn))
+ feat_num[QED_NVMETCP_CQ] = min_t(u32, sb_cnt.cnt,
+ RESC_NUM(p_hwfn,
+ QED_CMDQS_CQS));
+
DP_VERBOSE(p_hwfn,
NETIF_MSG_PROBE,
- "#PF_L2_QUEUES=%d VF_L2_QUEUES=%d #ROCE_CNQ=%d FCOE_CQ=%d ISCSI_CQ=%d #SBS=%d\n",
+ "#PF_L2_QUEUES=%d VF_L2_QUEUES=%d #ROCE_CNQ=%d FCOE_CQ=%d ISCSI_CQ=%d NVMETCP_CQ=%d #SBS=%d\n",
(int)FEAT_NUM(p_hwfn, QED_PF_L2_QUE),
(int)FEAT_NUM(p_hwfn, QED_VF_L2_QUE),
(int)FEAT_NUM(p_hwfn, QED_RDMA_CNQ),
(int)FEAT_NUM(p_hwfn, QED_FCOE_CQ),
(int)FEAT_NUM(p_hwfn, QED_ISCSI_CQ),
+ (int)FEAT_NUM(p_hwfn, QED_NVMETCP_CQ),
(int)sb_cnt.cnt);
}
@@ -3734,7 +3768,8 @@ int qed_hw_get_dflt_resc(struct qed_hwfn *p_hwfn,
break;
case QED_BDQ:
if (p_hwfn->hw_info.personality != QED_PCI_ISCSI &&
- p_hwfn->hw_info.personality != QED_PCI_FCOE)
+ p_hwfn->hw_info.personality != QED_PCI_FCOE &&
+ p_hwfn->hw_info.personality != QED_PCI_NVMETCP)
*p_resc_num = 0;
else
*p_resc_num = 1;
@@ -3755,7 +3790,8 @@ int qed_hw_get_dflt_resc(struct qed_hwfn *p_hwfn,
*p_resc_start = 0;
else if (p_hwfn->cdev->num_ports_in_engine == 4)
*p_resc_start = p_hwfn->port_id;
- else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI)
+ else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI ||
+ p_hwfn->hw_info.personality == QED_PCI_NVMETCP)
*p_resc_start = p_hwfn->port_id;
else if (p_hwfn->hw_info.personality == QED_PCI_FCOE)
*p_resc_start = p_hwfn->port_id + 2;
@@ -5326,3 +5362,93 @@ void qed_set_fw_mac_addr(__le16 *fw_msb,
((u8 *)fw_lsb)[0] = mac[5];
((u8 *)fw_lsb)[1] = mac[4];
}
+
+static int qed_llh_shadow_remove_all_filters(struct qed_dev *cdev, u8 ppfid)
+{
+ 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, 0, "remove_all");
+ if (rc)
+ return rc;
+
+ p_filters = p_llh_info->pp_filters[ppfid];
+ memset(p_filters, 0, NIG_REG_LLH_FUNC_FILTER_EN_SIZE *
+ sizeof(*p_filters));
+
+ return 0;
+}
+
+static void qed_llh_clear_ppfid_filters(struct qed_dev *cdev, u8 ppfid)
+{
+ struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
+ struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
+ u8 filter_idx, abs_ppfid;
+ int rc = 0;
+
+ if (!p_ptt)
+ return;
+
+ if (!test_bit(QED_MF_LLH_PROTO_CLSS, &cdev->mf_bits) &&
+ !test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits))
+ goto out;
+
+ rc = qed_llh_abs_ppfid(cdev, ppfid, &abs_ppfid);
+ if (rc)
+ goto out;
+
+ rc = qed_llh_shadow_remove_all_filters(cdev, ppfid);
+ if (rc)
+ goto out;
+
+ for (filter_idx = 0; filter_idx < NIG_REG_LLH_FUNC_FILTER_EN_SIZE;
+ filter_idx++) {
+ rc = qed_llh_remove_filter(p_hwfn, p_ptt,
+ abs_ppfid, filter_idx);
+ if (rc)
+ goto out;
+ }
+out:
+ qed_ptt_release(p_hwfn, p_ptt);
+}
+
+int qed_llh_add_src_tcp_port_filter(struct qed_dev *cdev, u16 src_port)
+{
+ return qed_llh_add_protocol_filter(cdev, 0,
+ QED_LLH_FILTER_TCP_SRC_PORT,
+ src_port, QED_LLH_DONT_CARE);
+}
+
+void qed_llh_remove_src_tcp_port_filter(struct qed_dev *cdev, u16 src_port)
+{
+ qed_llh_remove_protocol_filter(cdev, 0,
+ QED_LLH_FILTER_TCP_SRC_PORT,
+ src_port, QED_LLH_DONT_CARE);
+}
+
+int qed_llh_add_dst_tcp_port_filter(struct qed_dev *cdev, u16 dest_port)
+{
+ return qed_llh_add_protocol_filter(cdev, 0,
+ QED_LLH_FILTER_TCP_DEST_PORT,
+ QED_LLH_DONT_CARE, dest_port);
+}
+
+void qed_llh_remove_dst_tcp_port_filter(struct qed_dev *cdev, u16 dest_port)
+{
+ qed_llh_remove_protocol_filter(cdev, 0,
+ QED_LLH_FILTER_TCP_DEST_PORT,
+ QED_LLH_DONT_CARE, dest_port);
+}
+
+void qed_llh_clear_all_filters(struct qed_dev *cdev)
+{
+ u8 ppfid;
+
+ if (!test_bit(QED_MF_LLH_PROTO_CLSS, &cdev->mf_bits) &&
+ !test_bit(QED_MF_LLH_MAC_CLSS, &cdev->mf_bits))
+ return;
+
+ for (ppfid = 0; ppfid < cdev->p_llh_info->num_ppfid; ppfid++)
+ qed_llh_clear_ppfid_filters(cdev, ppfid);
+}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h
index 559df9f4d656..fb1baa2da2d0 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h
@@ -20,6 +20,7 @@
#include <linux/qed/fcoe_common.h>
#include <linux/qed/eth_common.h>
#include <linux/qed/iscsi_common.h>
+#include <linux/qed/nvmetcp_common.h>
#include <linux/qed/iwarp_common.h>
#include <linux/qed/rdma_common.h>
#include <linux/qed/roce_common.h>
@@ -1118,7 +1119,7 @@ struct outer_tag_config_struct {
/* personality per PF */
enum personality_type {
BAD_PERSONALITY_TYP,
- PERSONALITY_ISCSI,
+ PERSONALITY_TCP_ULP,
PERSONALITY_FCOE,
PERSONALITY_RDMA_AND_ETH,
PERSONALITY_RDMA,
@@ -12147,7 +12148,8 @@ struct public_func {
#define FUNC_MF_CFG_PROTOCOL_ISCSI 0x00000010
#define FUNC_MF_CFG_PROTOCOL_FCOE 0x00000020
#define FUNC_MF_CFG_PROTOCOL_ROCE 0x00000030
-#define FUNC_MF_CFG_PROTOCOL_MAX 0x00000030
+#define FUNC_MF_CFG_PROTOCOL_NVMETCP 0x00000040
+#define FUNC_MF_CFG_PROTOCOL_MAX 0x00000040
#define FUNC_MF_CFG_MIN_BW_MASK 0x0000ff00
#define FUNC_MF_CFG_MIN_BW_SHIFT 8
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
index 4eae4ee3538f..db926d8b3033 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
@@ -158,7 +158,7 @@ qed_sp_iscsi_func_start(struct qed_hwfn *p_hwfn,
rc = qed_sp_init_request(p_hwfn, &p_ent,
ISCSI_RAMROD_CMD_ID_INIT_FUNC,
- PROTOCOLID_ISCSI, &init_data);
+ PROTOCOLID_TCP_ULP, &init_data);
if (rc)
return rc;
@@ -250,7 +250,7 @@ qed_sp_iscsi_func_start(struct qed_hwfn *p_hwfn,
p_hwfn->p_iscsi_info->event_context = event_context;
p_hwfn->p_iscsi_info->event_cb = async_event_cb;
- qed_spq_register_async_cb(p_hwfn, PROTOCOLID_ISCSI,
+ qed_spq_register_async_cb(p_hwfn, PROTOCOLID_TCP_ULP,
qed_iscsi_async_event);
return qed_spq_post(p_hwfn, p_ent, NULL);
@@ -286,7 +286,7 @@ static int qed_sp_iscsi_conn_offload(struct qed_hwfn *p_hwfn,
rc = qed_sp_init_request(p_hwfn, &p_ent,
ISCSI_RAMROD_CMD_ID_OFFLOAD_CONN,
- PROTOCOLID_ISCSI, &init_data);
+ PROTOCOLID_TCP_ULP, &init_data);
if (rc)
return rc;
@@ -453,7 +453,7 @@ static int qed_sp_iscsi_conn_update(struct qed_hwfn *p_hwfn,
struct iscsi_conn_update_ramrod_params *p_ramrod = NULL;
struct qed_spq_entry *p_ent = NULL;
struct qed_sp_init_data init_data;
- int rc = -EINVAL;
+ int rc;
u32 dval;
/* Get SPQ entry */
@@ -465,7 +465,7 @@ static int qed_sp_iscsi_conn_update(struct qed_hwfn *p_hwfn,
rc = qed_sp_init_request(p_hwfn, &p_ent,
ISCSI_RAMROD_CMD_ID_UPDATE_CONN,
- PROTOCOLID_ISCSI, &init_data);
+ PROTOCOLID_TCP_ULP, &init_data);
if (rc)
return rc;
@@ -506,7 +506,7 @@ qed_sp_iscsi_mac_update(struct qed_hwfn *p_hwfn,
rc = qed_sp_init_request(p_hwfn, &p_ent,
ISCSI_RAMROD_CMD_ID_MAC_UPDATE,
- PROTOCOLID_ISCSI, &init_data);
+ PROTOCOLID_TCP_ULP, &init_data);
if (rc)
return rc;
@@ -548,7 +548,7 @@ static int qed_sp_iscsi_conn_terminate(struct qed_hwfn *p_hwfn,
rc = qed_sp_init_request(p_hwfn, &p_ent,
ISCSI_RAMROD_CMD_ID_TERMINATION_CONN,
- PROTOCOLID_ISCSI, &init_data);
+ PROTOCOLID_TCP_ULP, &init_data);
if (rc)
return rc;
@@ -582,7 +582,7 @@ static int qed_sp_iscsi_conn_clear_sq(struct qed_hwfn *p_hwfn,
rc = qed_sp_init_request(p_hwfn, &p_ent,
ISCSI_RAMROD_CMD_ID_CLEAR_SQ,
- PROTOCOLID_ISCSI, &init_data);
+ PROTOCOLID_TCP_ULP, &init_data);
if (rc)
return rc;
@@ -606,13 +606,13 @@ static int qed_sp_iscsi_func_stop(struct qed_hwfn *p_hwfn,
rc = qed_sp_init_request(p_hwfn, &p_ent,
ISCSI_RAMROD_CMD_ID_DESTROY_FUNC,
- PROTOCOLID_ISCSI, &init_data);
+ PROTOCOLID_TCP_ULP, &init_data);
if (rc)
return rc;
rc = qed_spq_post(p_hwfn, p_ent, NULL);
- qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_ISCSI);
+ qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_TCP_ULP);
return rc;
}
@@ -786,7 +786,7 @@ static int qed_iscsi_acquire_connection(struct qed_hwfn *p_hwfn,
u32 icid;
spin_lock_bh(&p_hwfn->p_iscsi_info->lock);
- rc = qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_ISCSI, &icid);
+ rc = qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_TCP_ULP, &icid);
spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
if (rc)
return rc;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 49783f365079..02a4610d9330 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -960,7 +960,8 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn *p_hwfn,
if (test_bit(QED_MF_LL2_NON_UNICAST, &p_hwfn->cdev->mf_bits) &&
p_ramrod->main_func_queue && conn_type != QED_LL2_TYPE_ROCE &&
- conn_type != QED_LL2_TYPE_IWARP) {
+ conn_type != QED_LL2_TYPE_IWARP &&
+ (!QED_IS_NVMETCP_PERSONALITY(p_hwfn))) {
p_ramrod->mf_si_bcast_accept_all = 1;
p_ramrod->mf_si_mcast_accept_all = 1;
} else {
@@ -1037,8 +1038,8 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn,
case QED_LL2_TYPE_FCOE:
p_ramrod->conn_type = PROTOCOLID_FCOE;
break;
- case QED_LL2_TYPE_ISCSI:
- p_ramrod->conn_type = PROTOCOLID_ISCSI;
+ case QED_LL2_TYPE_TCP_ULP:
+ p_ramrod->conn_type = PROTOCOLID_TCP_ULP;
break;
case QED_LL2_TYPE_ROCE:
p_ramrod->conn_type = PROTOCOLID_ROCE;
@@ -1047,8 +1048,9 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn,
p_ramrod->conn_type = PROTOCOLID_IWARP;
break;
case QED_LL2_TYPE_OOO:
- if (p_hwfn->hw_info.personality == QED_PCI_ISCSI)
- p_ramrod->conn_type = PROTOCOLID_ISCSI;
+ if (p_hwfn->hw_info.personality == QED_PCI_ISCSI ||
+ p_hwfn->hw_info.personality == QED_PCI_NVMETCP)
+ p_ramrod->conn_type = PROTOCOLID_TCP_ULP;
else
p_ramrod->conn_type = PROTOCOLID_IWARP;
break;
@@ -1634,7 +1636,8 @@ int qed_ll2_establish_connection(void *cxt, u8 connection_handle)
if (rc)
goto out;
- if (!QED_IS_RDMA_PERSONALITY(p_hwfn))
+ if (!QED_IS_RDMA_PERSONALITY(p_hwfn) &&
+ !QED_IS_NVMETCP_PERSONALITY(p_hwfn))
qed_wr(p_hwfn, p_ptt, PRS_REG_USE_LIGHT_L2, 1);
qed_ll2_establish_connection_ooo(p_hwfn, p_ll2_conn);
@@ -2376,7 +2379,8 @@ out:
static bool qed_ll2_is_storage_eng1(struct qed_dev *cdev)
{
return (QED_IS_FCOE_PERSONALITY(QED_LEADING_HWFN(cdev)) ||
- QED_IS_ISCSI_PERSONALITY(QED_LEADING_HWFN(cdev))) &&
+ QED_IS_ISCSI_PERSONALITY(QED_LEADING_HWFN(cdev)) ||
+ QED_IS_NVMETCP_PERSONALITY(QED_LEADING_HWFN(cdev))) &&
(QED_AFFIN_HWFN(cdev) != QED_LEADING_HWFN(cdev));
}
@@ -2402,11 +2406,13 @@ static int qed_ll2_stop(struct qed_dev *cdev)
if (cdev->ll2->handle == QED_LL2_UNUSED_HANDLE)
return 0;
+ if (!QED_IS_NVMETCP_PERSONALITY(p_hwfn))
+ qed_llh_remove_mac_filter(cdev, 0, cdev->ll2_mac_address);
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))
+ if (QED_IS_ISCSI_PERSONALITY(p_hwfn) || QED_IS_NVMETCP_PERSONALITY(p_hwfn))
qed_ll2_stop_ooo(p_hwfn);
/* In CMT mode, LL2 is always started on engine 0 for a storage PF */
@@ -2442,7 +2448,8 @@ static int __qed_ll2_start(struct qed_hwfn *p_hwfn,
conn_type = QED_LL2_TYPE_FCOE;
break;
case QED_PCI_ISCSI:
- conn_type = QED_LL2_TYPE_ISCSI;
+ case QED_PCI_NVMETCP:
+ conn_type = QED_LL2_TYPE_TCP_ULP;
break;
case QED_PCI_ETH_ROCE:
conn_type = QED_LL2_TYPE_ROCE;
@@ -2567,7 +2574,7 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
}
}
- if (QED_IS_ISCSI_PERSONALITY(p_hwfn)) {
+ if (QED_IS_ISCSI_PERSONALITY(p_hwfn) || QED_IS_NVMETCP_PERSONALITY(p_hwfn)) {
DP_VERBOSE(cdev, QED_MSG_STORAGE, "Starting OOO LL2 queue\n");
rc = qed_ll2_start_ooo(p_hwfn, params);
if (rc) {
@@ -2576,10 +2583,13 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
}
}
- 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_IS_NVMETCP_PERSONALITY(p_hwfn)) {
+ 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;
+ }
+
}
ether_addr_copy(cdev->ll2_mac_address, params->ll2_mac_address);
@@ -2587,7 +2597,7 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
return 0;
err3:
- if (QED_IS_ISCSI_PERSONALITY(p_hwfn))
+ if (QED_IS_ISCSI_PERSONALITY(p_hwfn) || QED_IS_NVMETCP_PERSONALITY(p_hwfn))
qed_ll2_stop_ooo(p_hwfn);
err2:
if (b_is_storage_eng1)
diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
index cd882c453394..4387292c37e2 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
@@ -2446,6 +2446,9 @@ qed_mcp_get_shmem_proto(struct qed_hwfn *p_hwfn,
case FUNC_MF_CFG_PROTOCOL_ISCSI:
*p_proto = QED_PCI_ISCSI;
break;
+ case FUNC_MF_CFG_PROTOCOL_NVMETCP:
+ *p_proto = QED_PCI_NVMETCP;
+ break;
case FUNC_MF_CFG_PROTOCOL_FCOE:
*p_proto = QED_PCI_FCOE;
break;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_mng_tlv.c b/drivers/net/ethernet/qlogic/qed/qed_mng_tlv.c
index 3e3192a3ad9b..6190adf965bc 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_mng_tlv.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_mng_tlv.c
@@ -1306,7 +1306,8 @@ int qed_mfw_process_tlv_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
}
if ((tlv_group & QED_MFW_TLV_ISCSI) &&
- p_hwfn->hw_info.personality != QED_PCI_ISCSI) {
+ p_hwfn->hw_info.personality != QED_PCI_ISCSI &&
+ p_hwfn->hw_info.personality != QED_PCI_NVMETCP) {
DP_VERBOSE(p_hwfn, QED_MSG_SP,
"Skipping iSCSI TLVs for non-iSCSI function\n");
tlv_group &= ~QED_MFW_TLV_ISCSI;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_nvmetcp.c b/drivers/net/ethernet/qlogic/qed/qed_nvmetcp.c
new file mode 100644
index 000000000000..f19128c8d9cc
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qed/qed_nvmetcp.c
@@ -0,0 +1,829 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/* Copyright 2021 Marvell. All rights reserved. */
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <asm/param.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/qed/qed_nvmetcp_if.h>
+#include "qed.h"
+#include "qed_cxt.h"
+#include "qed_dev_api.h"
+#include "qed_hsi.h"
+#include "qed_hw.h"
+#include "qed_int.h"
+#include "qed_nvmetcp.h"
+#include "qed_ll2.h"
+#include "qed_mcp.h"
+#include "qed_sp.h"
+#include "qed_reg_addr.h"
+#include "qed_nvmetcp_fw_funcs.h"
+
+static int qed_nvmetcp_async_event(struct qed_hwfn *p_hwfn, u8 fw_event_code,
+ u16 echo, union event_ring_data *data,
+ u8 fw_return_code)
+{
+ if (p_hwfn->p_nvmetcp_info->event_cb) {
+ struct qed_nvmetcp_info *p_nvmetcp = p_hwfn->p_nvmetcp_info;
+
+ return p_nvmetcp->event_cb(p_nvmetcp->event_context,
+ fw_event_code, data);
+ } else {
+ DP_NOTICE(p_hwfn, "nvmetcp async completion is not set\n");
+
+ return -EINVAL;
+ }
+}
+
+static int qed_sp_nvmetcp_func_start(struct qed_hwfn *p_hwfn,
+ enum spq_mode comp_mode,
+ struct qed_spq_comp_cb *p_comp_addr,
+ void *event_context,
+ nvmetcp_event_cb_t async_event_cb)
+{
+ struct nvmetcp_init_ramrod_params *p_ramrod = NULL;
+ struct qed_nvmetcp_pf_params *p_params = NULL;
+ struct scsi_init_func_queues *p_queue = NULL;
+ struct nvmetcp_spe_func_init *p_init = NULL;
+ struct qed_sp_init_data init_data = {};
+ struct qed_spq_entry *p_ent = NULL;
+ int rc = 0;
+ u16 val;
+ u8 i;
+
+ /* Get SPQ entry */
+ init_data.cid = qed_spq_get_cid(p_hwfn);
+ init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+ init_data.comp_mode = comp_mode;
+ init_data.p_comp_data = p_comp_addr;
+ rc = qed_sp_init_request(p_hwfn, &p_ent,
+ NVMETCP_RAMROD_CMD_ID_INIT_FUNC,
+ PROTOCOLID_TCP_ULP, &init_data);
+ if (rc)
+ return rc;
+
+ p_ramrod = &p_ent->ramrod.nvmetcp_init;
+ p_init = &p_ramrod->nvmetcp_init_spe;
+ p_params = &p_hwfn->pf_params.nvmetcp_pf_params;
+ p_queue = &p_init->q_params;
+ p_init->num_sq_pages_in_ring = p_params->num_sq_pages_in_ring;
+ p_init->num_r2tq_pages_in_ring = p_params->num_r2tq_pages_in_ring;
+ p_init->num_uhq_pages_in_ring = p_params->num_uhq_pages_in_ring;
+ p_init->ll2_rx_queue_id = RESC_START(p_hwfn, QED_LL2_RAM_QUEUE) +
+ p_params->ll2_ooo_queue_id;
+ SET_FIELD(p_init->flags, NVMETCP_SPE_FUNC_INIT_NVMETCP_MODE, 1);
+ p_init->func_params.log_page_size = ilog2(PAGE_SIZE);
+ p_init->func_params.num_tasks = cpu_to_le16(p_params->num_tasks);
+ p_init->debug_flags = p_params->debug_mode;
+ DMA_REGPAIR_LE(p_queue->glbl_q_params_addr,
+ p_params->glbl_q_params_addr);
+ p_queue->cq_num_entries = cpu_to_le16(QED_NVMETCP_FW_CQ_SIZE);
+ p_queue->num_queues = p_params->num_queues;
+ val = RESC_START(p_hwfn, QED_CMDQS_CQS);
+ p_queue->queue_relative_offset = cpu_to_le16((u16)val);
+ p_queue->cq_sb_pi = p_params->gl_rq_pi;
+
+ for (i = 0; i < p_params->num_queues; i++) {
+ val = qed_get_igu_sb_id(p_hwfn, i);
+ p_queue->cq_cmdq_sb_num_arr[i] = cpu_to_le16(val);
+ }
+
+ SET_FIELD(p_queue->q_validity,
+ SCSI_INIT_FUNC_QUEUES_CMD_VALID, 0);
+ p_queue->cmdq_num_entries = 0;
+ p_queue->bdq_resource_id = (u8)RESC_START(p_hwfn, QED_BDQ);
+ p_ramrod->tcp_init.two_msl_timer = cpu_to_le32(QED_TCP_TWO_MSL_TIMER);
+ p_ramrod->tcp_init.tx_sws_timer = cpu_to_le16(QED_TCP_SWS_TIMER);
+ p_init->half_way_close_timeout = cpu_to_le16(QED_TCP_HALF_WAY_CLOSE_TIMEOUT);
+ p_ramrod->tcp_init.max_fin_rt = QED_TCP_MAX_FIN_RT;
+ SET_FIELD(p_ramrod->nvmetcp_init_spe.params,
+ NVMETCP_SPE_FUNC_INIT_MAX_SYN_RT, QED_TCP_MAX_FIN_RT);
+ p_hwfn->p_nvmetcp_info->event_context = event_context;
+ p_hwfn->p_nvmetcp_info->event_cb = async_event_cb;
+ qed_spq_register_async_cb(p_hwfn, PROTOCOLID_TCP_ULP,
+ qed_nvmetcp_async_event);
+
+ return qed_spq_post(p_hwfn, p_ent, NULL);
+}
+
+static int qed_sp_nvmetcp_func_stop(struct qed_hwfn *p_hwfn,
+ enum spq_mode comp_mode,
+ struct qed_spq_comp_cb *p_comp_addr)
+{
+ struct qed_spq_entry *p_ent = NULL;
+ struct qed_sp_init_data init_data;
+ int rc;
+
+ /* Get SPQ entry */
+ memset(&init_data, 0, sizeof(init_data));
+ init_data.cid = qed_spq_get_cid(p_hwfn);
+ init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+ init_data.comp_mode = comp_mode;
+ init_data.p_comp_data = p_comp_addr;
+ rc = qed_sp_init_request(p_hwfn, &p_ent,
+ NVMETCP_RAMROD_CMD_ID_DESTROY_FUNC,
+ PROTOCOLID_TCP_ULP, &init_data);
+ if (rc)
+ return rc;
+
+ rc = qed_spq_post(p_hwfn, p_ent, NULL);
+ qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_TCP_ULP);
+
+ return rc;
+}
+
+static int qed_fill_nvmetcp_dev_info(struct qed_dev *cdev,
+ struct qed_dev_nvmetcp_info *info)
+{
+ struct qed_hwfn *hwfn = QED_AFFIN_HWFN(cdev);
+ int rc;
+
+ memset(info, 0, sizeof(*info));
+ rc = qed_fill_dev_info(cdev, &info->common);
+ info->port_id = MFW_PORT(hwfn);
+ info->num_cqs = FEAT_NUM(hwfn, QED_NVMETCP_CQ);
+
+ return rc;
+}
+
+static void qed_register_nvmetcp_ops(struct qed_dev *cdev,
+ struct qed_nvmetcp_cb_ops *ops,
+ void *cookie)
+{
+ cdev->protocol_ops.nvmetcp = ops;
+ cdev->ops_cookie = cookie;
+}
+
+static int qed_nvmetcp_stop(struct qed_dev *cdev)
+{
+ int rc;
+
+ if (!(cdev->flags & QED_FLAG_STORAGE_STARTED)) {
+ DP_NOTICE(cdev, "nvmetcp already stopped\n");
+
+ return 0;
+ }
+
+ if (!hash_empty(cdev->connections)) {
+ DP_NOTICE(cdev,
+ "Can't stop nvmetcp - not all connections were returned\n");
+
+ return -EINVAL;
+ }
+
+ /* Stop the nvmetcp */
+ rc = qed_sp_nvmetcp_func_stop(QED_AFFIN_HWFN(cdev), QED_SPQ_MODE_EBLOCK,
+ NULL);
+ cdev->flags &= ~QED_FLAG_STORAGE_STARTED;
+
+ return rc;
+}
+
+static int qed_nvmetcp_start(struct qed_dev *cdev,
+ struct qed_nvmetcp_tid *tasks,
+ void *event_context,
+ nvmetcp_event_cb_t async_event_cb)
+{
+ struct qed_tid_mem *tid_info;
+ int rc;
+
+ if (cdev->flags & QED_FLAG_STORAGE_STARTED) {
+ DP_NOTICE(cdev, "nvmetcp already started;\n");
+
+ return 0;
+ }
+
+ rc = qed_sp_nvmetcp_func_start(QED_AFFIN_HWFN(cdev),
+ QED_SPQ_MODE_EBLOCK, NULL,
+ event_context, async_event_cb);
+ if (rc) {
+ DP_NOTICE(cdev, "Failed to start nvmetcp\n");
+
+ return rc;
+ }
+
+ cdev->flags |= QED_FLAG_STORAGE_STARTED;
+ hash_init(cdev->connections);
+
+ if (!tasks)
+ return 0;
+
+ tid_info = kzalloc(sizeof(*tid_info), GFP_KERNEL);
+ if (!tid_info) {
+ qed_nvmetcp_stop(cdev);
+
+ return -ENOMEM;
+ }
+
+ 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_nvmetcp_stop(cdev);
+ kfree(tid_info);
+
+ return rc;
+ }
+
+ /* Fill task information */
+ tasks->size = tid_info->tid_size;
+ tasks->num_tids_per_block = tid_info->num_tids_per_block;
+ memcpy(tasks->blocks, tid_info->blocks,
+ MAX_TID_BLOCKS_NVMETCP * sizeof(u8 *));
+ kfree(tid_info);
+
+ return 0;
+}
+
+static struct qed_hash_nvmetcp_con *qed_nvmetcp_get_hash(struct qed_dev *cdev,
+ u32 handle)
+{
+ struct qed_hash_nvmetcp_con *hash_con = NULL;
+
+ if (!(cdev->flags & QED_FLAG_STORAGE_STARTED))
+ return NULL;
+
+ hash_for_each_possible(cdev->connections, hash_con, node, handle) {
+ if (hash_con->con->icid == handle)
+ break;
+ }
+
+ if (!hash_con || hash_con->con->icid != handle)
+ return NULL;
+
+ return hash_con;
+}
+
+static int qed_sp_nvmetcp_conn_offload(struct qed_hwfn *p_hwfn,
+ struct qed_nvmetcp_conn *p_conn,
+ enum spq_mode comp_mode,
+ struct qed_spq_comp_cb *p_comp_addr)
+{
+ struct nvmetcp_spe_conn_offload *p_ramrod = NULL;
+ struct tcp_offload_params_opt2 *p_tcp = NULL;
+ struct qed_sp_init_data init_data = { 0 };
+ struct qed_spq_entry *p_ent = NULL;
+ dma_addr_t r2tq_pbl_addr;
+ dma_addr_t xhq_pbl_addr;
+ dma_addr_t uhq_pbl_addr;
+ u16 physical_q;
+ int rc = 0;
+ u8 i;
+
+ /* Get SPQ entry */
+ init_data.cid = p_conn->icid;
+ init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+ init_data.comp_mode = comp_mode;
+ init_data.p_comp_data = p_comp_addr;
+ rc = qed_sp_init_request(p_hwfn, &p_ent,
+ NVMETCP_RAMROD_CMD_ID_OFFLOAD_CONN,
+ PROTOCOLID_TCP_ULP, &init_data);
+ if (rc)
+ return rc;
+
+ p_ramrod = &p_ent->ramrod.nvmetcp_conn_offload;
+
+ /* Transmission PQ is the first of the PF */
+ physical_q = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OFLD);
+ p_conn->physical_q0 = cpu_to_le16(physical_q);
+ p_ramrod->nvmetcp.physical_q0 = cpu_to_le16(physical_q);
+
+ /* nvmetcp Pure-ACK PQ */
+ physical_q = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_ACK);
+ p_conn->physical_q1 = cpu_to_le16(physical_q);
+ p_ramrod->nvmetcp.physical_q1 = cpu_to_le16(physical_q);
+ p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id);
+ DMA_REGPAIR_LE(p_ramrod->nvmetcp.sq_pbl_addr, p_conn->sq_pbl_addr);
+ r2tq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->r2tq);
+ DMA_REGPAIR_LE(p_ramrod->nvmetcp.r2tq_pbl_addr, r2tq_pbl_addr);
+ xhq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->xhq);
+ DMA_REGPAIR_LE(p_ramrod->nvmetcp.xhq_pbl_addr, xhq_pbl_addr);
+ uhq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->uhq);
+ DMA_REGPAIR_LE(p_ramrod->nvmetcp.uhq_pbl_addr, uhq_pbl_addr);
+ p_ramrod->nvmetcp.flags = p_conn->offl_flags;
+ p_ramrod->nvmetcp.default_cq = p_conn->default_cq;
+ p_ramrod->nvmetcp.initial_ack = 0;
+ DMA_REGPAIR_LE(p_ramrod->nvmetcp.nvmetcp.cccid_itid_table_addr,
+ p_conn->nvmetcp_cccid_itid_table_addr);
+ p_ramrod->nvmetcp.nvmetcp.cccid_max_range =
+ cpu_to_le16(p_conn->nvmetcp_cccid_max_range);
+ p_tcp = &p_ramrod->tcp;
+ qed_set_fw_mac_addr(&p_tcp->remote_mac_addr_hi,
+ &p_tcp->remote_mac_addr_mid,
+ &p_tcp->remote_mac_addr_lo, p_conn->remote_mac);
+ qed_set_fw_mac_addr(&p_tcp->local_mac_addr_hi,
+ &p_tcp->local_mac_addr_mid,
+ &p_tcp->local_mac_addr_lo, p_conn->local_mac);
+ p_tcp->vlan_id = cpu_to_le16(p_conn->vlan_id);
+ p_tcp->flags = cpu_to_le16(p_conn->tcp_flags);
+ p_tcp->ip_version = p_conn->ip_version;
+ if (p_tcp->ip_version == TCP_IPV6) {
+ for (i = 0; i < 4; i++) {
+ p_tcp->remote_ip[i] = cpu_to_le32(p_conn->remote_ip[i]);
+ p_tcp->local_ip[i] = cpu_to_le32(p_conn->local_ip[i]);
+ }
+ } else {
+ p_tcp->remote_ip[0] = cpu_to_le32(p_conn->remote_ip[0]);
+ p_tcp->local_ip[0] = cpu_to_le32(p_conn->local_ip[0]);
+ }
+
+ p_tcp->flow_label = cpu_to_le32(p_conn->flow_label);
+ p_tcp->ttl = p_conn->ttl;
+ p_tcp->tos_or_tc = p_conn->tos_or_tc;
+ p_tcp->remote_port = cpu_to_le16(p_conn->remote_port);
+ p_tcp->local_port = cpu_to_le16(p_conn->local_port);
+ p_tcp->mss = cpu_to_le16(p_conn->mss);
+ p_tcp->rcv_wnd_scale = p_conn->rcv_wnd_scale;
+ p_tcp->connect_mode = p_conn->connect_mode;
+ p_tcp->cwnd = cpu_to_le32(p_conn->cwnd);
+ p_tcp->ka_max_probe_cnt = p_conn->ka_max_probe_cnt;
+ p_tcp->ka_timeout = cpu_to_le32(p_conn->ka_timeout);
+ p_tcp->max_rt_time = cpu_to_le32(p_conn->max_rt_time);
+ p_tcp->ka_interval = cpu_to_le32(p_conn->ka_interval);
+
+ return qed_spq_post(p_hwfn, p_ent, NULL);
+}
+
+static int qed_sp_nvmetcp_conn_update(struct qed_hwfn *p_hwfn,
+ struct qed_nvmetcp_conn *p_conn,
+ enum spq_mode comp_mode,
+ struct qed_spq_comp_cb *p_comp_addr)
+{
+ struct nvmetcp_conn_update_ramrod_params *p_ramrod = NULL;
+ struct qed_spq_entry *p_ent = NULL;
+ struct qed_sp_init_data init_data;
+ int rc = -EINVAL;
+ u32 dval;
+
+ /* Get SPQ entry */
+ memset(&init_data, 0, sizeof(init_data));
+ init_data.cid = p_conn->icid;
+ init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+ init_data.comp_mode = comp_mode;
+ init_data.p_comp_data = p_comp_addr;
+
+ rc = qed_sp_init_request(p_hwfn, &p_ent,
+ NVMETCP_RAMROD_CMD_ID_UPDATE_CONN,
+ PROTOCOLID_TCP_ULP, &init_data);
+ if (rc)
+ return rc;
+
+ p_ramrod = &p_ent->ramrod.nvmetcp_conn_update;
+ p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id);
+ p_ramrod->flags = p_conn->update_flag;
+ p_ramrod->max_seq_size = cpu_to_le32(p_conn->max_seq_size);
+ dval = p_conn->max_recv_pdu_length;
+ p_ramrod->max_recv_pdu_length = cpu_to_le32(dval);
+ dval = p_conn->max_send_pdu_length;
+ p_ramrod->max_send_pdu_length = cpu_to_le32(dval);
+ p_ramrod->first_seq_length = cpu_to_le32(p_conn->first_seq_length);
+
+ return qed_spq_post(p_hwfn, p_ent, NULL);
+}
+
+static int qed_sp_nvmetcp_conn_terminate(struct qed_hwfn *p_hwfn,
+ struct qed_nvmetcp_conn *p_conn,
+ enum spq_mode comp_mode,
+ struct qed_spq_comp_cb *p_comp_addr)
+{
+ struct nvmetcp_spe_conn_termination *p_ramrod = NULL;
+ struct qed_spq_entry *p_ent = NULL;
+ struct qed_sp_init_data init_data;
+ int rc = -EINVAL;
+
+ /* Get SPQ entry */
+ memset(&init_data, 0, sizeof(init_data));
+ init_data.cid = p_conn->icid;
+ init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+ init_data.comp_mode = comp_mode;
+ init_data.p_comp_data = p_comp_addr;
+ rc = qed_sp_init_request(p_hwfn, &p_ent,
+ NVMETCP_RAMROD_CMD_ID_TERMINATION_CONN,
+ PROTOCOLID_TCP_ULP, &init_data);
+ if (rc)
+ return rc;
+
+ p_ramrod = &p_ent->ramrod.nvmetcp_conn_terminate;
+ p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id);
+ p_ramrod->abortive = p_conn->abortive_dsconnect;
+
+ return qed_spq_post(p_hwfn, p_ent, NULL);
+}
+
+static int qed_sp_nvmetcp_conn_clear_sq(struct qed_hwfn *p_hwfn,
+ struct qed_nvmetcp_conn *p_conn,
+ enum spq_mode comp_mode,
+ struct qed_spq_comp_cb *p_comp_addr)
+{
+ struct qed_spq_entry *p_ent = NULL;
+ struct qed_sp_init_data init_data;
+ int rc = -EINVAL;
+
+ /* Get SPQ entry */
+ memset(&init_data, 0, sizeof(init_data));
+ init_data.cid = p_conn->icid;
+ init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+ init_data.comp_mode = comp_mode;
+ init_data.p_comp_data = p_comp_addr;
+ rc = qed_sp_init_request(p_hwfn, &p_ent,
+ NVMETCP_RAMROD_CMD_ID_CLEAR_SQ,
+ PROTOCOLID_TCP_ULP, &init_data);
+ if (rc)
+ return rc;
+
+ return qed_spq_post(p_hwfn, p_ent, NULL);
+}
+
+static void __iomem *qed_nvmetcp_get_db_addr(struct qed_hwfn *p_hwfn, u32 cid)
+{
+ return (u8 __iomem *)p_hwfn->doorbells +
+ qed_db_addr(cid, DQ_DEMS_LEGACY);
+}
+
+static int qed_nvmetcp_allocate_connection(struct qed_hwfn *p_hwfn,
+ struct qed_nvmetcp_conn **p_out_conn)
+{
+ struct qed_chain_init_params params = {
+ .mode = QED_CHAIN_MODE_PBL,
+ .intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE,
+ .cnt_type = QED_CHAIN_CNT_TYPE_U16,
+ };
+ struct qed_nvmetcp_pf_params *p_params = NULL;
+ struct qed_nvmetcp_conn *p_conn = NULL;
+ int rc = 0;
+
+ /* Try finding a free connection that can be used */
+ spin_lock_bh(&p_hwfn->p_nvmetcp_info->lock);
+ if (!list_empty(&p_hwfn->p_nvmetcp_info->free_list))
+ p_conn = list_first_entry(&p_hwfn->p_nvmetcp_info->free_list,
+ struct qed_nvmetcp_conn, list_entry);
+ if (p_conn) {
+ list_del(&p_conn->list_entry);
+ spin_unlock_bh(&p_hwfn->p_nvmetcp_info->lock);
+ *p_out_conn = p_conn;
+
+ return 0;
+ }
+ spin_unlock_bh(&p_hwfn->p_nvmetcp_info->lock);
+
+ /* Need to allocate a new connection */
+ p_params = &p_hwfn->pf_params.nvmetcp_pf_params;
+ p_conn = kzalloc(sizeof(*p_conn), GFP_KERNEL);
+ if (!p_conn)
+ return -ENOMEM;
+
+ params.num_elems = p_params->num_r2tq_pages_in_ring *
+ QED_CHAIN_PAGE_SIZE / sizeof(struct nvmetcp_wqe);
+ params.elem_size = sizeof(struct nvmetcp_wqe);
+ rc = qed_chain_alloc(p_hwfn->cdev, &p_conn->r2tq, &params);
+ if (rc)
+ goto nomem_r2tq;
+
+ params.num_elems = p_params->num_uhq_pages_in_ring *
+ QED_CHAIN_PAGE_SIZE / sizeof(struct iscsi_uhqe);
+ params.elem_size = sizeof(struct iscsi_uhqe);
+ rc = qed_chain_alloc(p_hwfn->cdev, &p_conn->uhq, &params);
+ if (rc)
+ goto nomem_uhq;
+
+ params.elem_size = sizeof(struct iscsi_xhqe);
+ rc = qed_chain_alloc(p_hwfn->cdev, &p_conn->xhq, &params);
+ if (rc)
+ goto nomem;
+
+ p_conn->free_on_delete = true;
+ *p_out_conn = p_conn;
+
+ return 0;
+
+nomem:
+ qed_chain_free(p_hwfn->cdev, &p_conn->uhq);
+nomem_uhq:
+ qed_chain_free(p_hwfn->cdev, &p_conn->r2tq);
+nomem_r2tq:
+ kfree(p_conn);
+
+ return -ENOMEM;
+}
+
+static int qed_nvmetcp_acquire_connection(struct qed_hwfn *p_hwfn,
+ struct qed_nvmetcp_conn **p_out_conn)
+{
+ struct qed_nvmetcp_conn *p_conn = NULL;
+ int rc = 0;
+ u32 icid;
+
+ spin_lock_bh(&p_hwfn->p_nvmetcp_info->lock);
+ rc = qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_TCP_ULP, &icid);
+ spin_unlock_bh(&p_hwfn->p_nvmetcp_info->lock);
+
+ if (rc)
+ return rc;
+
+ rc = qed_nvmetcp_allocate_connection(p_hwfn, &p_conn);
+ if (rc) {
+ spin_lock_bh(&p_hwfn->p_nvmetcp_info->lock);
+ qed_cxt_release_cid(p_hwfn, icid);
+ spin_unlock_bh(&p_hwfn->p_nvmetcp_info->lock);
+
+ return rc;
+ }
+
+ p_conn->icid = icid;
+ p_conn->conn_id = (u16)icid;
+ p_conn->fw_cid = (p_hwfn->hw_info.opaque_fid << 16) | icid;
+ *p_out_conn = p_conn;
+
+ return rc;
+}
+
+static void qed_nvmetcp_release_connection(struct qed_hwfn *p_hwfn,
+ struct qed_nvmetcp_conn *p_conn)
+{
+ spin_lock_bh(&p_hwfn->p_nvmetcp_info->lock);
+ list_add_tail(&p_conn->list_entry, &p_hwfn->p_nvmetcp_info->free_list);
+ qed_cxt_release_cid(p_hwfn, p_conn->icid);
+ spin_unlock_bh(&p_hwfn->p_nvmetcp_info->lock);
+}
+
+static void qed_nvmetcp_free_connection(struct qed_hwfn *p_hwfn,
+ struct qed_nvmetcp_conn *p_conn)
+{
+ qed_chain_free(p_hwfn->cdev, &p_conn->xhq);
+ qed_chain_free(p_hwfn->cdev, &p_conn->uhq);
+ qed_chain_free(p_hwfn->cdev, &p_conn->r2tq);
+ kfree(p_conn);
+}
+
+int qed_nvmetcp_alloc(struct qed_hwfn *p_hwfn)
+{
+ struct qed_nvmetcp_info *p_nvmetcp_info;
+
+ p_nvmetcp_info = kzalloc(sizeof(*p_nvmetcp_info), GFP_KERNEL);
+ if (!p_nvmetcp_info)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&p_nvmetcp_info->free_list);
+ p_hwfn->p_nvmetcp_info = p_nvmetcp_info;
+
+ return 0;
+}
+
+void qed_nvmetcp_setup(struct qed_hwfn *p_hwfn)
+{
+ spin_lock_init(&p_hwfn->p_nvmetcp_info->lock);
+}
+
+void qed_nvmetcp_free(struct qed_hwfn *p_hwfn)
+{
+ struct qed_nvmetcp_conn *p_conn = NULL;
+
+ if (!p_hwfn->p_nvmetcp_info)
+ return;
+
+ while (!list_empty(&p_hwfn->p_nvmetcp_info->free_list)) {
+ p_conn = list_first_entry(&p_hwfn->p_nvmetcp_info->free_list,
+ struct qed_nvmetcp_conn, list_entry);
+ if (p_conn) {
+ list_del(&p_conn->list_entry);
+ qed_nvmetcp_free_connection(p_hwfn, p_conn);
+ }
+ }
+
+ kfree(p_hwfn->p_nvmetcp_info);
+ p_hwfn->p_nvmetcp_info = NULL;
+}
+
+static int qed_nvmetcp_acquire_conn(struct qed_dev *cdev,
+ u32 *handle,
+ u32 *fw_cid, void __iomem **p_doorbell)
+{
+ struct qed_hash_nvmetcp_con *hash_con;
+ int rc;
+
+ /* Allocate a hashed connection */
+ hash_con = kzalloc(sizeof(*hash_con), GFP_ATOMIC);
+ if (!hash_con)
+ return -ENOMEM;
+
+ /* Acquire the connection */
+ rc = qed_nvmetcp_acquire_connection(QED_AFFIN_HWFN(cdev),
+ &hash_con->con);
+ if (rc) {
+ DP_NOTICE(cdev, "Failed to acquire Connection\n");
+ kfree(hash_con);
+
+ return rc;
+ }
+
+ /* Added the connection to hash table */
+ *handle = hash_con->con->icid;
+ *fw_cid = hash_con->con->fw_cid;
+ hash_add(cdev->connections, &hash_con->node, *handle);
+ if (p_doorbell)
+ *p_doorbell = qed_nvmetcp_get_db_addr(QED_AFFIN_HWFN(cdev),
+ *handle);
+
+ return 0;
+}
+
+static int qed_nvmetcp_release_conn(struct qed_dev *cdev, u32 handle)
+{
+ struct qed_hash_nvmetcp_con *hash_con;
+
+ hash_con = qed_nvmetcp_get_hash(cdev, handle);
+ if (!hash_con) {
+ DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
+ handle);
+
+ return -EINVAL;
+ }
+
+ hlist_del(&hash_con->node);
+ qed_nvmetcp_release_connection(QED_AFFIN_HWFN(cdev), hash_con->con);
+ kfree(hash_con);
+
+ return 0;
+}
+
+static int qed_nvmetcp_offload_conn(struct qed_dev *cdev, u32 handle,
+ struct qed_nvmetcp_params_offload *conn_info)
+{
+ struct qed_hash_nvmetcp_con *hash_con;
+ struct qed_nvmetcp_conn *con;
+
+ hash_con = qed_nvmetcp_get_hash(cdev, handle);
+ if (!hash_con) {
+ DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
+ handle);
+
+ return -EINVAL;
+ }
+
+ /* Update the connection with information from the params */
+ con = hash_con->con;
+
+ /* FW initializations */
+ con->layer_code = NVMETCP_SLOW_PATH_LAYER_CODE;
+ con->sq_pbl_addr = conn_info->sq_pbl_addr;
+ con->nvmetcp_cccid_max_range = conn_info->nvmetcp_cccid_max_range;
+ con->nvmetcp_cccid_itid_table_addr = conn_info->nvmetcp_cccid_itid_table_addr;
+ con->default_cq = conn_info->default_cq;
+ SET_FIELD(con->offl_flags, NVMETCP_CONN_OFFLOAD_PARAMS_TARGET_MODE, 0);
+ SET_FIELD(con->offl_flags, NVMETCP_CONN_OFFLOAD_PARAMS_NVMETCP_MODE, 1);
+ SET_FIELD(con->offl_flags, NVMETCP_CONN_OFFLOAD_PARAMS_TCP_ON_CHIP_1B, 1);
+
+ /* Networking and TCP stack initializations */
+ ether_addr_copy(con->local_mac, conn_info->src.mac);
+ ether_addr_copy(con->remote_mac, conn_info->dst.mac);
+ memcpy(con->local_ip, conn_info->src.ip, sizeof(con->local_ip));
+ memcpy(con->remote_ip, conn_info->dst.ip, sizeof(con->remote_ip));
+ con->local_port = conn_info->src.port;
+ con->remote_port = conn_info->dst.port;
+ con->vlan_id = conn_info->vlan_id;
+
+ if (conn_info->timestamp_en)
+ SET_FIELD(con->tcp_flags, TCP_OFFLOAD_PARAMS_OPT2_TS_EN, 1);
+
+ if (conn_info->delayed_ack_en)
+ SET_FIELD(con->tcp_flags, TCP_OFFLOAD_PARAMS_OPT2_DA_EN, 1);
+
+ if (conn_info->tcp_keep_alive_en)
+ SET_FIELD(con->tcp_flags, TCP_OFFLOAD_PARAMS_OPT2_KA_EN, 1);
+
+ if (conn_info->ecn_en)
+ SET_FIELD(con->tcp_flags, TCP_OFFLOAD_PARAMS_OPT2_ECN_EN, 1);
+
+ con->ip_version = conn_info->ip_version;
+ con->flow_label = QED_TCP_FLOW_LABEL;
+ con->ka_max_probe_cnt = conn_info->ka_max_probe_cnt;
+ con->ka_timeout = conn_info->ka_timeout;
+ con->ka_interval = conn_info->ka_interval;
+ con->max_rt_time = conn_info->max_rt_time;
+ con->ttl = conn_info->ttl;
+ con->tos_or_tc = conn_info->tos_or_tc;
+ con->mss = conn_info->mss;
+ con->cwnd = conn_info->cwnd;
+ con->rcv_wnd_scale = conn_info->rcv_wnd_scale;
+ con->connect_mode = 0;
+
+ return qed_sp_nvmetcp_conn_offload(QED_AFFIN_HWFN(cdev), con,
+ QED_SPQ_MODE_EBLOCK, NULL);
+}
+
+static int qed_nvmetcp_update_conn(struct qed_dev *cdev,
+ u32 handle,
+ struct qed_nvmetcp_params_update *conn_info)
+{
+ struct qed_hash_nvmetcp_con *hash_con;
+ struct qed_nvmetcp_conn *con;
+
+ hash_con = qed_nvmetcp_get_hash(cdev, handle);
+ if (!hash_con) {
+ DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
+ handle);
+
+ return -EINVAL;
+ }
+
+ /* Update the connection with information from the params */
+ con = hash_con->con;
+ SET_FIELD(con->update_flag,
+ ISCSI_CONN_UPDATE_RAMROD_PARAMS_INITIAL_R2T, 0);
+ SET_FIELD(con->update_flag,
+ ISCSI_CONN_UPDATE_RAMROD_PARAMS_IMMEDIATE_DATA, 1);
+ if (conn_info->hdr_digest_en)
+ SET_FIELD(con->update_flag, ISCSI_CONN_UPDATE_RAMROD_PARAMS_HD_EN, 1);
+
+ if (conn_info->data_digest_en)
+ SET_FIELD(con->update_flag, ISCSI_CONN_UPDATE_RAMROD_PARAMS_DD_EN, 1);
+
+ /* Placeholder - initialize pfv, cpda, hpda */
+
+ con->max_seq_size = conn_info->max_io_size;
+ con->max_recv_pdu_length = conn_info->max_recv_pdu_length;
+ con->max_send_pdu_length = conn_info->max_send_pdu_length;
+ con->first_seq_length = conn_info->max_io_size;
+
+ return qed_sp_nvmetcp_conn_update(QED_AFFIN_HWFN(cdev), con,
+ QED_SPQ_MODE_EBLOCK, NULL);
+}
+
+static int qed_nvmetcp_clear_conn_sq(struct qed_dev *cdev, u32 handle)
+{
+ struct qed_hash_nvmetcp_con *hash_con;
+
+ hash_con = qed_nvmetcp_get_hash(cdev, handle);
+ if (!hash_con) {
+ DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
+ handle);
+
+ return -EINVAL;
+ }
+
+ return qed_sp_nvmetcp_conn_clear_sq(QED_AFFIN_HWFN(cdev), hash_con->con,
+ QED_SPQ_MODE_EBLOCK, NULL);
+}
+
+static int qed_nvmetcp_destroy_conn(struct qed_dev *cdev,
+ u32 handle, u8 abrt_conn)
+{
+ struct qed_hash_nvmetcp_con *hash_con;
+
+ hash_con = qed_nvmetcp_get_hash(cdev, handle);
+ if (!hash_con) {
+ DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
+ handle);
+
+ return -EINVAL;
+ }
+
+ hash_con->con->abortive_dsconnect = abrt_conn;
+
+ return qed_sp_nvmetcp_conn_terminate(QED_AFFIN_HWFN(cdev), hash_con->con,
+ QED_SPQ_MODE_EBLOCK, NULL);
+}
+
+static const struct qed_nvmetcp_ops qed_nvmetcp_ops_pass = {
+ .common = &qed_common_ops_pass,
+ .ll2 = &qed_ll2_ops_pass,
+ .fill_dev_info = &qed_fill_nvmetcp_dev_info,
+ .register_ops = &qed_register_nvmetcp_ops,
+ .start = &qed_nvmetcp_start,
+ .stop = &qed_nvmetcp_stop,
+ .acquire_conn = &qed_nvmetcp_acquire_conn,
+ .release_conn = &qed_nvmetcp_release_conn,
+ .offload_conn = &qed_nvmetcp_offload_conn,
+ .update_conn = &qed_nvmetcp_update_conn,
+ .destroy_conn = &qed_nvmetcp_destroy_conn,
+ .clear_sq = &qed_nvmetcp_clear_conn_sq,
+ .add_src_tcp_port_filter = &qed_llh_add_src_tcp_port_filter,
+ .remove_src_tcp_port_filter = &qed_llh_remove_src_tcp_port_filter,
+ .add_dst_tcp_port_filter = &qed_llh_add_dst_tcp_port_filter,
+ .remove_dst_tcp_port_filter = &qed_llh_remove_dst_tcp_port_filter,
+ .clear_all_filters = &qed_llh_clear_all_filters,
+ .init_read_io = &init_nvmetcp_host_read_task,
+ .init_write_io = &init_nvmetcp_host_write_task,
+ .init_icreq_exchange = &init_nvmetcp_init_conn_req_task,
+ .init_task_cleanup = &init_cleanup_task_nvmetcp
+};
+
+const struct qed_nvmetcp_ops *qed_get_nvmetcp_ops(void)
+{
+ return &qed_nvmetcp_ops_pass;
+}
+EXPORT_SYMBOL(qed_get_nvmetcp_ops);
+
+void qed_put_nvmetcp_ops(void)
+{
+}
+EXPORT_SYMBOL(qed_put_nvmetcp_ops);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_nvmetcp.h b/drivers/net/ethernet/qlogic/qed/qed_nvmetcp.h
new file mode 100644
index 000000000000..e5e9d075bf4f
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qed/qed_nvmetcp.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/* Copyright 2021 Marvell. All rights reserved. */
+
+#ifndef _QED_NVMETCP_H
+#define _QED_NVMETCP_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/qed/tcp_common.h>
+#include <linux/qed/qed_nvmetcp_if.h>
+#include <linux/qed/qed_chain.h>
+#include "qed.h"
+#include "qed_hsi.h"
+#include "qed_mcp.h"
+#include "qed_sp.h"
+
+#define QED_NVMETCP_FW_CQ_SIZE (4 * 1024)
+
+/* tcp parameters */
+#define QED_TCP_FLOW_LABEL 0
+#define QED_TCP_TWO_MSL_TIMER 4000
+#define QED_TCP_HALF_WAY_CLOSE_TIMEOUT 10
+#define QED_TCP_MAX_FIN_RT 2
+#define QED_TCP_SWS_TIMER 5000
+
+struct qed_nvmetcp_info {
+ spinlock_t lock; /* Connection resources. */
+ struct list_head free_list;
+ u16 max_num_outstanding_tasks;
+ void *event_context;
+ nvmetcp_event_cb_t event_cb;
+};
+
+struct qed_hash_nvmetcp_con {
+ struct hlist_node node;
+ struct qed_nvmetcp_conn *con;
+};
+
+struct qed_nvmetcp_conn {
+ struct list_head list_entry;
+ bool free_on_delete;
+ u16 conn_id;
+ u32 icid;
+ u32 fw_cid;
+ u8 layer_code;
+ u8 offl_flags;
+ u8 connect_mode;
+ dma_addr_t sq_pbl_addr;
+ struct qed_chain r2tq;
+ struct qed_chain xhq;
+ struct qed_chain uhq;
+ u8 local_mac[6];
+ u8 remote_mac[6];
+ u8 ip_version;
+ u8 ka_max_probe_cnt;
+ u16 vlan_id;
+ u16 tcp_flags;
+ u32 remote_ip[4];
+ u32 local_ip[4];
+ u32 flow_label;
+ u32 ka_timeout;
+ u32 ka_interval;
+ u32 max_rt_time;
+ u8 ttl;
+ u8 tos_or_tc;
+ u16 remote_port;
+ u16 local_port;
+ u16 mss;
+ u8 rcv_wnd_scale;
+ u32 rcv_wnd;
+ u32 cwnd;
+ u8 update_flag;
+ u8 default_cq;
+ u8 abortive_dsconnect;
+ u32 max_seq_size;
+ u32 max_recv_pdu_length;
+ u32 max_send_pdu_length;
+ u32 first_seq_length;
+ u16 physical_q0;
+ u16 physical_q1;
+ u16 nvmetcp_cccid_max_range;
+ dma_addr_t nvmetcp_cccid_itid_table_addr;
+};
+
+#if IS_ENABLED(CONFIG_QED_NVMETCP)
+int qed_nvmetcp_alloc(struct qed_hwfn *p_hwfn);
+void qed_nvmetcp_setup(struct qed_hwfn *p_hwfn);
+void qed_nvmetcp_free(struct qed_hwfn *p_hwfn);
+
+#else /* IS_ENABLED(CONFIG_QED_NVMETCP) */
+static inline int qed_nvmetcp_alloc(struct qed_hwfn *p_hwfn)
+{
+ return -EINVAL;
+}
+
+static inline void qed_nvmetcp_setup(struct qed_hwfn *p_hwfn) {}
+static inline void qed_nvmetcp_free(struct qed_hwfn *p_hwfn) {}
+
+#endif /* IS_ENABLED(CONFIG_QED_NVMETCP) */
+
+#endif
diff --git a/drivers/net/ethernet/qlogic/qed/qed_nvmetcp_fw_funcs.c b/drivers/net/ethernet/qlogic/qed/qed_nvmetcp_fw_funcs.c
new file mode 100644
index 000000000000..c1dd71d19f3f
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qed/qed_nvmetcp_fw_funcs.c
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/* Copyright 2021 Marvell. All rights reserved. */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <linux/qed/common_hsi.h>
+#include <linux/qed/storage_common.h>
+#include <linux/qed/nvmetcp_common.h>
+#include <linux/qed/qed_nvmetcp_if.h>
+#include "qed_nvmetcp_fw_funcs.h"
+
+#define NVMETCP_NUM_SGES_IN_CACHE 0x4
+
+bool nvmetcp_is_slow_sgl(u16 num_sges, bool small_mid_sge)
+{
+ return (num_sges > SCSI_NUM_SGES_SLOW_SGL_THR && small_mid_sge);
+}
+
+void init_scsi_sgl_context(struct scsi_sgl_params *ctx_sgl_params,
+ struct scsi_cached_sges *ctx_data_desc,
+ struct storage_sgl_task_params *sgl_params)
+{
+ u8 num_sges_to_init = (u8)(sgl_params->num_sges > NVMETCP_NUM_SGES_IN_CACHE ?
+ NVMETCP_NUM_SGES_IN_CACHE : sgl_params->num_sges);
+ u8 sge_index;
+
+ /* sgl params */
+ ctx_sgl_params->sgl_addr.lo = cpu_to_le32(sgl_params->sgl_phys_addr.lo);
+ ctx_sgl_params->sgl_addr.hi = cpu_to_le32(sgl_params->sgl_phys_addr.hi);
+ ctx_sgl_params->sgl_total_length = cpu_to_le32(sgl_params->total_buffer_size);
+ ctx_sgl_params->sgl_num_sges = cpu_to_le16(sgl_params->num_sges);
+
+ for (sge_index = 0; sge_index < num_sges_to_init; sge_index++) {
+ ctx_data_desc->sge[sge_index].sge_addr.lo =
+ cpu_to_le32(sgl_params->sgl[sge_index].sge_addr.lo);
+ ctx_data_desc->sge[sge_index].sge_addr.hi =
+ cpu_to_le32(sgl_params->sgl[sge_index].sge_addr.hi);
+ ctx_data_desc->sge[sge_index].sge_len =
+ cpu_to_le32(sgl_params->sgl[sge_index].sge_len);
+ }
+}
+
+static inline u32 calc_rw_task_size(struct nvmetcp_task_params *task_params,
+ enum nvmetcp_task_type task_type)
+{
+ u32 io_size;
+
+ if (task_type == NVMETCP_TASK_TYPE_HOST_WRITE)
+ io_size = task_params->tx_io_size;
+ else
+ io_size = task_params->rx_io_size;
+
+ if (unlikely(!io_size))
+ return 0;
+
+ return io_size;
+}
+
+static inline void init_sqe(struct nvmetcp_task_params *task_params,
+ struct storage_sgl_task_params *sgl_task_params,
+ enum nvmetcp_task_type task_type)
+{
+ if (!task_params->sqe)
+ return;
+
+ memset(task_params->sqe, 0, sizeof(*task_params->sqe));
+ task_params->sqe->task_id = cpu_to_le16(task_params->itid);
+
+ switch (task_type) {
+ case NVMETCP_TASK_TYPE_HOST_WRITE: {
+ u32 buf_size = 0;
+ u32 num_sges = 0;
+
+ SET_FIELD(task_params->sqe->contlen_cdbsize,
+ NVMETCP_WQE_CDB_SIZE_OR_NVMETCP_CMD, 1);
+ SET_FIELD(task_params->sqe->flags, NVMETCP_WQE_WQE_TYPE,
+ NVMETCP_WQE_TYPE_NORMAL);
+ if (task_params->tx_io_size) {
+ if (task_params->send_write_incapsule)
+ buf_size = calc_rw_task_size(task_params, task_type);
+
+ if (nvmetcp_is_slow_sgl(sgl_task_params->num_sges,
+ sgl_task_params->small_mid_sge))
+ num_sges = NVMETCP_WQE_NUM_SGES_SLOWIO;
+ else
+ num_sges = min((u16)sgl_task_params->num_sges,
+ (u16)SCSI_NUM_SGES_SLOW_SGL_THR);
+ }
+ SET_FIELD(task_params->sqe->flags, NVMETCP_WQE_NUM_SGES, num_sges);
+ SET_FIELD(task_params->sqe->contlen_cdbsize, NVMETCP_WQE_CONT_LEN, buf_size);
+ } break;
+
+ case NVMETCP_TASK_TYPE_HOST_READ: {
+ SET_FIELD(task_params->sqe->flags, NVMETCP_WQE_WQE_TYPE,
+ NVMETCP_WQE_TYPE_NORMAL);
+ SET_FIELD(task_params->sqe->contlen_cdbsize,
+ NVMETCP_WQE_CDB_SIZE_OR_NVMETCP_CMD, 1);
+ } break;
+
+ case NVMETCP_TASK_TYPE_INIT_CONN_REQUEST: {
+ SET_FIELD(task_params->sqe->flags, NVMETCP_WQE_WQE_TYPE,
+ NVMETCP_WQE_TYPE_MIDDLE_PATH);
+
+ if (task_params->tx_io_size) {
+ SET_FIELD(task_params->sqe->contlen_cdbsize, NVMETCP_WQE_CONT_LEN,
+ task_params->tx_io_size);
+ SET_FIELD(task_params->sqe->flags, NVMETCP_WQE_NUM_SGES,
+ min((u16)sgl_task_params->num_sges,
+ (u16)SCSI_NUM_SGES_SLOW_SGL_THR));
+ }
+ } break;
+
+ case NVMETCP_TASK_TYPE_CLEANUP:
+ SET_FIELD(task_params->sqe->flags, NVMETCP_WQE_WQE_TYPE,
+ NVMETCP_WQE_TYPE_TASK_CLEANUP);
+
+ default:
+ break;
+ }
+}
+
+/* The following function initializes of NVMeTCP task params */
+static inline void
+init_nvmetcp_task_params(struct e5_nvmetcp_task_context *context,
+ struct nvmetcp_task_params *task_params,
+ enum nvmetcp_task_type task_type)
+{
+ context->ystorm_st_context.state.cccid = task_params->host_cccid;
+ SET_FIELD(context->ustorm_st_context.error_flags, USTORM_NVMETCP_TASK_ST_CTX_NVME_TCP, 1);
+ context->ustorm_st_context.nvme_tcp_opaque_lo = cpu_to_le32(task_params->opq.lo);
+ context->ustorm_st_context.nvme_tcp_opaque_hi = cpu_to_le32(task_params->opq.hi);
+}
+
+/* The following function initializes default values to all tasks */
+static inline void
+init_default_nvmetcp_task(struct nvmetcp_task_params *task_params,
+ void *pdu_header, void *nvme_cmd,
+ enum nvmetcp_task_type task_type)
+{
+ struct e5_nvmetcp_task_context *context = task_params->context;
+ const u8 val_byte = context->mstorm_ag_context.cdu_validation;
+ u8 dw_index;
+
+ memset(context, 0, sizeof(*context));
+ init_nvmetcp_task_params(context, task_params,
+ (enum nvmetcp_task_type)task_type);
+
+ /* Swapping requirements used below, will be removed in future FW versions */
+ if (task_type == NVMETCP_TASK_TYPE_HOST_WRITE ||
+ task_type == NVMETCP_TASK_TYPE_HOST_READ) {
+ for (dw_index = 0;
+ dw_index < QED_NVMETCP_CMN_HDR_SIZE / sizeof(u32);
+ dw_index++)
+ context->ystorm_st_context.pdu_hdr.task_hdr.reg[dw_index] =
+ cpu_to_le32(__swab32(((u32 *)pdu_header)[dw_index]));
+
+ for (dw_index = QED_NVMETCP_CMN_HDR_SIZE / sizeof(u32);
+ dw_index < QED_NVMETCP_CMD_HDR_SIZE / sizeof(u32);
+ dw_index++)
+ context->ystorm_st_context.pdu_hdr.task_hdr.reg[dw_index] =
+ cpu_to_le32(__swab32(((u32 *)nvme_cmd)[dw_index - 2]));
+ } else {
+ for (dw_index = 0;
+ dw_index < QED_NVMETCP_NON_IO_HDR_SIZE / sizeof(u32);
+ dw_index++)
+ context->ystorm_st_context.pdu_hdr.task_hdr.reg[dw_index] =
+ cpu_to_le32(__swab32(((u32 *)pdu_header)[dw_index]));
+ }
+
+ /* M-Storm Context: */
+ context->mstorm_ag_context.cdu_validation = val_byte;
+ context->mstorm_st_context.task_type = (u8)(task_type);
+ context->mstorm_ag_context.task_cid = cpu_to_le16(task_params->conn_icid);
+
+ /* Ustorm Context: */
+ SET_FIELD(context->ustorm_ag_context.flags1, E5_USTORM_NVMETCP_TASK_AG_CTX_R2T2RECV, 1);
+ context->ustorm_st_context.task_type = (u8)(task_type);
+ context->ustorm_st_context.cq_rss_number = task_params->cq_rss_number;
+ context->ustorm_ag_context.icid = cpu_to_le16(task_params->conn_icid);
+}
+
+/* The following function initializes the U-Storm Task Contexts */
+static inline void
+init_ustorm_task_contexts(struct ustorm_nvmetcp_task_st_ctx *ustorm_st_context,
+ struct e5_ustorm_nvmetcp_task_ag_ctx *ustorm_ag_context,
+ u32 remaining_recv_len,
+ u32 expected_data_transfer_len, u8 num_sges,
+ bool tx_dif_conn_err_en)
+{
+ /* Remaining data to be received in bytes. Used in validations*/
+ ustorm_st_context->rem_rcv_len = cpu_to_le32(remaining_recv_len);
+ ustorm_ag_context->exp_data_acked = cpu_to_le32(expected_data_transfer_len);
+ ustorm_st_context->exp_data_transfer_len = cpu_to_le32(expected_data_transfer_len);
+ SET_FIELD(ustorm_st_context->reg1_map, REG1_NUM_SGES, num_sges);
+ SET_FIELD(ustorm_ag_context->flags2, E5_USTORM_NVMETCP_TASK_AG_CTX_DIF_ERROR_CF_EN,
+ tx_dif_conn_err_en ? 1 : 0);
+}
+
+/* The following function initializes Local Completion Contexts: */
+static inline void
+set_local_completion_context(struct e5_nvmetcp_task_context *context)
+{
+ SET_FIELD(context->ystorm_st_context.state.flags,
+ YSTORM_NVMETCP_TASK_STATE_LOCAL_COMP, 1);
+ SET_FIELD(context->ustorm_st_context.flags,
+ USTORM_NVMETCP_TASK_ST_CTX_LOCAL_COMP, 1);
+}
+
+/* Common Fastpath task init function: */
+static inline void
+init_rw_nvmetcp_task(struct nvmetcp_task_params *task_params,
+ enum nvmetcp_task_type task_type,
+ void *pdu_header, void *nvme_cmd,
+ struct storage_sgl_task_params *sgl_task_params)
+{
+ struct e5_nvmetcp_task_context *context = task_params->context;
+ u32 task_size = calc_rw_task_size(task_params, task_type);
+ bool slow_io = false;
+ u8 num_sges = 0;
+
+ init_default_nvmetcp_task(task_params, pdu_header, nvme_cmd, task_type);
+
+ /* Tx/Rx: */
+ if (task_params->tx_io_size) {
+ /* if data to transmit: */
+ init_scsi_sgl_context(&context->ystorm_st_context.state.sgl_params,
+ &context->ystorm_st_context.state.data_desc,
+ sgl_task_params);
+ slow_io = nvmetcp_is_slow_sgl(sgl_task_params->num_sges,
+ sgl_task_params->small_mid_sge);
+ num_sges =
+ (u8)(!slow_io ? min((u32)sgl_task_params->num_sges,
+ (u32)SCSI_NUM_SGES_SLOW_SGL_THR) :
+ NVMETCP_WQE_NUM_SGES_SLOWIO);
+ if (slow_io) {
+ SET_FIELD(context->ystorm_st_context.state.flags,
+ YSTORM_NVMETCP_TASK_STATE_SLOW_IO, 1);
+ }
+ } else if (task_params->rx_io_size) {
+ /* if data to receive: */
+ init_scsi_sgl_context(&context->mstorm_st_context.sgl_params,
+ &context->mstorm_st_context.data_desc,
+ sgl_task_params);
+ num_sges =
+ (u8)(!nvmetcp_is_slow_sgl(sgl_task_params->num_sges,
+ sgl_task_params->small_mid_sge) ?
+ min((u32)sgl_task_params->num_sges,
+ (u32)SCSI_NUM_SGES_SLOW_SGL_THR) :
+ NVMETCP_WQE_NUM_SGES_SLOWIO);
+ context->mstorm_st_context.rem_task_size = cpu_to_le32(task_size);
+ }
+
+ /* Ustorm context: */
+ init_ustorm_task_contexts(&context->ustorm_st_context,
+ &context->ustorm_ag_context,
+ /* Remaining Receive length is the Task Size */
+ task_size,
+ /* The size of the transmitted task */
+ task_size,
+ /* num_sges */
+ num_sges,
+ false);
+
+ /* Set exp_data_acked */
+ if (task_type == NVMETCP_TASK_TYPE_HOST_WRITE) {
+ if (task_params->send_write_incapsule)
+ context->ustorm_ag_context.exp_data_acked = task_size;
+ else
+ context->ustorm_ag_context.exp_data_acked = 0;
+ } else if (task_type == NVMETCP_TASK_TYPE_HOST_READ) {
+ context->ustorm_ag_context.exp_data_acked = 0;
+ }
+
+ context->ustorm_ag_context.exp_cont_len = 0;
+ init_sqe(task_params, sgl_task_params, task_type);
+}
+
+static void
+init_common_initiator_read_task(struct nvmetcp_task_params *task_params,
+ struct nvme_tcp_cmd_pdu *cmd_pdu_header,
+ struct nvme_command *nvme_cmd,
+ struct storage_sgl_task_params *sgl_task_params)
+{
+ init_rw_nvmetcp_task(task_params, NVMETCP_TASK_TYPE_HOST_READ,
+ cmd_pdu_header, nvme_cmd, sgl_task_params);
+}
+
+void init_nvmetcp_host_read_task(struct nvmetcp_task_params *task_params,
+ struct nvme_tcp_cmd_pdu *cmd_pdu_header,
+ struct nvme_command *nvme_cmd,
+ struct storage_sgl_task_params *sgl_task_params)
+{
+ init_common_initiator_read_task(task_params, (void *)cmd_pdu_header,
+ (void *)nvme_cmd, sgl_task_params);
+}
+
+static void
+init_common_initiator_write_task(struct nvmetcp_task_params *task_params,
+ struct nvme_tcp_cmd_pdu *cmd_pdu_header,
+ struct nvme_command *nvme_cmd,
+ struct storage_sgl_task_params *sgl_task_params)
+{
+ init_rw_nvmetcp_task(task_params, NVMETCP_TASK_TYPE_HOST_WRITE,
+ cmd_pdu_header, nvme_cmd, sgl_task_params);
+}
+
+void init_nvmetcp_host_write_task(struct nvmetcp_task_params *task_params,
+ struct nvme_tcp_cmd_pdu *cmd_pdu_header,
+ struct nvme_command *nvme_cmd,
+ struct storage_sgl_task_params *sgl_task_params)
+{
+ init_common_initiator_write_task(task_params, (void *)cmd_pdu_header,
+ (void *)nvme_cmd, sgl_task_params);
+}
+
+static void
+init_common_login_request_task(struct nvmetcp_task_params *task_params,
+ void *login_req_pdu_header,
+ struct storage_sgl_task_params *tx_sgl_task_params,
+ struct storage_sgl_task_params *rx_sgl_task_params)
+{
+ struct e5_nvmetcp_task_context *context = task_params->context;
+
+ init_default_nvmetcp_task(task_params, (void *)login_req_pdu_header, NULL,
+ NVMETCP_TASK_TYPE_INIT_CONN_REQUEST);
+
+ /* Ustorm Context: */
+ init_ustorm_task_contexts(&context->ustorm_st_context,
+ &context->ustorm_ag_context,
+
+ /* Remaining Receive length is the Task Size */
+ task_params->rx_io_size ?
+ rx_sgl_task_params->total_buffer_size : 0,
+
+ /* The size of the transmitted task */
+ task_params->tx_io_size ?
+ tx_sgl_task_params->total_buffer_size : 0,
+ 0, /* num_sges */
+ 0); /* tx_dif_conn_err_en */
+
+ /* SGL context: */
+ if (task_params->tx_io_size)
+ init_scsi_sgl_context(&context->ystorm_st_context.state.sgl_params,
+ &context->ystorm_st_context.state.data_desc,
+ tx_sgl_task_params);
+ if (task_params->rx_io_size)
+ init_scsi_sgl_context(&context->mstorm_st_context.sgl_params,
+ &context->mstorm_st_context.data_desc,
+ rx_sgl_task_params);
+
+ context->mstorm_st_context.rem_task_size =
+ cpu_to_le32(task_params->rx_io_size ?
+ rx_sgl_task_params->total_buffer_size : 0);
+ init_sqe(task_params, tx_sgl_task_params, NVMETCP_TASK_TYPE_INIT_CONN_REQUEST);
+}
+
+/* The following function initializes Login task in Host mode: */
+void init_nvmetcp_init_conn_req_task(struct nvmetcp_task_params *task_params,
+ struct nvme_tcp_icreq_pdu *init_conn_req_pdu_hdr,
+ struct storage_sgl_task_params *tx_sgl_task_params,
+ struct storage_sgl_task_params *rx_sgl_task_params)
+{
+ init_common_login_request_task(task_params, init_conn_req_pdu_hdr,
+ tx_sgl_task_params, rx_sgl_task_params);
+}
+
+void init_cleanup_task_nvmetcp(struct nvmetcp_task_params *task_params)
+{
+ init_sqe(task_params, NULL, NVMETCP_TASK_TYPE_CLEANUP);
+}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_nvmetcp_fw_funcs.h b/drivers/net/ethernet/qlogic/qed/qed_nvmetcp_fw_funcs.h
new file mode 100644
index 000000000000..1d5ddc217bdb
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qed/qed_nvmetcp_fw_funcs.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/* Copyright 2021 Marvell. All rights reserved. */
+
+#ifndef _QED_NVMETCP_FW_FUNCS_H
+#define _QED_NVMETCP_FW_FUNCS_H
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <linux/qed/common_hsi.h>
+#include <linux/qed/storage_common.h>
+#include <linux/qed/nvmetcp_common.h>
+#include <linux/qed/qed_nvmetcp_if.h>
+
+#if IS_ENABLED(CONFIG_QED_NVMETCP)
+
+void init_nvmetcp_host_read_task(struct nvmetcp_task_params *task_params,
+ struct nvme_tcp_cmd_pdu *cmd_pdu_header,
+ struct nvme_command *nvme_cmd,
+ struct storage_sgl_task_params *sgl_task_params);
+void init_nvmetcp_host_write_task(struct nvmetcp_task_params *task_params,
+ struct nvme_tcp_cmd_pdu *cmd_pdu_header,
+ struct nvme_command *nvme_cmd,
+ struct storage_sgl_task_params *sgl_task_params);
+void init_nvmetcp_init_conn_req_task(struct nvmetcp_task_params *task_params,
+ struct nvme_tcp_icreq_pdu *init_conn_req_pdu_hdr,
+ struct storage_sgl_task_params *tx_sgl_task_params,
+ struct storage_sgl_task_params *rx_sgl_task_params);
+void init_cleanup_task_nvmetcp(struct nvmetcp_task_params *task_params);
+
+#else /* IS_ENABLED(CONFIG_QED_NVMETCP) */
+
+#endif /* IS_ENABLED(CONFIG_QED_NVMETCP) */
+
+#endif /* _QED_NVMETCP_FW_FUNCS_H */
diff --git a/drivers/net/ethernet/qlogic/qed/qed_nvmetcp_ip_services.c b/drivers/net/ethernet/qlogic/qed/qed_nvmetcp_ip_services.c
new file mode 100644
index 000000000000..96a2077fd315
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qed/qed_nvmetcp_ip_services.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/*
+ * Copyright 2021 Marvell. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <asm/param.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/errno.h>
+
+#include <net/tcp.h>
+
+#include <linux/qed/qed_nvmetcp_ip_services_if.h>
+
+#define QED_IP_RESOL_TIMEOUT 4
+
+int qed_route_ipv4(struct sockaddr_storage *local_addr,
+ struct sockaddr_storage *remote_addr,
+ struct sockaddr *hardware_address,
+ struct net_device **ndev)
+{
+ struct neighbour *neigh = NULL;
+ __be32 *loc_ip, *rem_ip;
+ struct rtable *rt;
+ int rc = -ENXIO;
+ int retry;
+
+ loc_ip = &((struct sockaddr_in *)local_addr)->sin_addr.s_addr;
+ rem_ip = &((struct sockaddr_in *)remote_addr)->sin_addr.s_addr;
+ *ndev = NULL;
+ rt = ip_route_output(&init_net, *rem_ip, *loc_ip, 0/*tos*/, 0/*oif*/);
+ if (IS_ERR(rt)) {
+ pr_err("lookup route failed\n");
+ rc = PTR_ERR(rt);
+ goto return_err;
+ }
+
+ neigh = dst_neigh_lookup(&rt->dst, rem_ip);
+ if (!neigh) {
+ rc = -ENOMEM;
+ ip_rt_put(rt);
+ goto return_err;
+ }
+
+ *ndev = rt->dst.dev;
+ ip_rt_put(rt);
+
+ /* If not resolved, kick-off state machine towards resolution */
+ if (!(neigh->nud_state & NUD_VALID))
+ neigh_event_send(neigh, NULL);
+
+ /* query neighbor until resolved or timeout */
+ retry = QED_IP_RESOL_TIMEOUT;
+ while (!(neigh->nud_state & NUD_VALID) && retry > 0) {
+ msleep(1000);
+ retry--;
+ }
+
+ if (neigh->nud_state & NUD_VALID) {
+ /* copy resolved MAC address */
+ neigh_ha_snapshot(hardware_address->sa_data, neigh, *ndev);
+ hardware_address->sa_family = (*ndev)->type;
+ rc = 0;
+ }
+
+ neigh_release(neigh);
+ if (!(*loc_ip)) {
+ *loc_ip = inet_select_addr(*ndev, *rem_ip, RT_SCOPE_UNIVERSE);
+ local_addr->ss_family = AF_INET;
+ }
+
+return_err:
+
+ return rc;
+}
+EXPORT_SYMBOL(qed_route_ipv4);
+
+int qed_route_ipv6(struct sockaddr_storage *local_addr,
+ struct sockaddr_storage *remote_addr,
+ struct sockaddr *hardware_address,
+ struct net_device **ndev)
+{
+ struct neighbour *neigh = NULL;
+ struct dst_entry *dst;
+ struct flowi6 fl6;
+ int rc = -ENXIO;
+ int retry;
+
+ memset(&fl6, 0, sizeof(fl6));
+ fl6.saddr = ((struct sockaddr_in6 *)local_addr)->sin6_addr;
+ fl6.daddr = ((struct sockaddr_in6 *)remote_addr)->sin6_addr;
+ dst = ip6_route_output(&init_net, NULL, &fl6);
+ if (!dst || dst->error) {
+ if (dst) {
+ dst_release(dst);
+ pr_err("lookup route failed %d\n", dst->error);
+ }
+
+ goto out;
+ }
+
+ neigh = dst_neigh_lookup(dst, &fl6.daddr);
+ if (neigh) {
+ *ndev = ip6_dst_idev(dst)->dev;
+
+ /* If not resolved, kick-off state machine towards resolution */
+ if (!(neigh->nud_state & NUD_VALID))
+ neigh_event_send(neigh, NULL);
+
+ /* query neighbor until resolved or timeout */
+ retry = QED_IP_RESOL_TIMEOUT;
+ while (!(neigh->nud_state & NUD_VALID) && retry > 0) {
+ msleep(1000);
+ retry--;
+ }
+
+ if (neigh->nud_state & NUD_VALID) {
+ neigh_ha_snapshot((u8 *)hardware_address->sa_data,
+ neigh, *ndev);
+ hardware_address->sa_family = (*ndev)->type;
+ rc = 0;
+ }
+
+ neigh_release(neigh);
+
+ if (ipv6_addr_any(&fl6.saddr)) {
+ if (ipv6_dev_get_saddr(dev_net(*ndev), *ndev,
+ &fl6.daddr, 0, &fl6.saddr)) {
+ pr_err("Unable to find source IP address\n");
+ goto out;
+ }
+
+ local_addr->ss_family = AF_INET6;
+ ((struct sockaddr_in6 *)local_addr)->sin6_addr =
+ fl6.saddr;
+ }
+ }
+
+ dst_release(dst);
+
+out:
+
+ return rc;
+}
+EXPORT_SYMBOL(qed_route_ipv6);
+
+void qed_vlan_get_ndev(struct net_device **ndev, u16 *vlan_id)
+{
+ if (is_vlan_dev(*ndev)) {
+ *vlan_id = vlan_dev_vlan_id(*ndev);
+ *ndev = vlan_dev_real_dev(*ndev);
+ }
+}
+EXPORT_SYMBOL(qed_vlan_get_ndev);
+
+struct pci_dev *qed_validate_ndev(struct net_device *ndev)
+{
+ struct pci_dev *pdev = NULL;
+ struct net_device *upper;
+
+ for_each_pci_dev(pdev) {
+ if (pdev && pdev->driver &&
+ !strcmp(pdev->driver->name, "qede")) {
+ upper = pci_get_drvdata(pdev);
+ if (upper->ifindex == ndev->ifindex)
+ return pdev;
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(qed_validate_ndev);
+
+__be16 qed_get_in_port(struct sockaddr_storage *sa)
+{
+ return sa->ss_family == AF_INET
+ ? ((struct sockaddr_in *)sa)->sin_port
+ : ((struct sockaddr_in6 *)sa)->sin6_port;
+}
+EXPORT_SYMBOL(qed_get_in_port);
+
+int qed_fetch_tcp_port(struct sockaddr_storage local_ip_addr,
+ struct socket **sock, u16 *port)
+{
+ struct sockaddr_storage sa;
+ int rc = 0;
+
+ rc = sock_create(local_ip_addr.ss_family, SOCK_STREAM, IPPROTO_TCP,
+ sock);
+ if (rc) {
+ pr_warn("failed to create socket: %d\n", rc);
+ goto err;
+ }
+
+ (*sock)->sk->sk_allocation = GFP_KERNEL;
+ sk_set_memalloc((*sock)->sk);
+
+ rc = kernel_bind(*sock, (struct sockaddr *)&local_ip_addr,
+ sizeof(local_ip_addr));
+
+ if (rc) {
+ pr_warn("failed to bind socket: %d\n", rc);
+ goto err_sock;
+ }
+
+ rc = kernel_getsockname(*sock, (struct sockaddr *)&sa);
+ if (rc < 0) {
+ pr_warn("getsockname() failed: %d\n", rc);
+ goto err_sock;
+ }
+
+ *port = ntohs(qed_get_in_port(&sa));
+
+ return 0;
+
+err_sock:
+ sock_release(*sock);
+ sock = NULL;
+err:
+
+ return rc;
+}
+EXPORT_SYMBOL(qed_fetch_tcp_port);
+
+void qed_return_tcp_port(struct socket *sock)
+{
+ if (sock && sock->sk) {
+ tcp_set_state(sock->sk, TCP_CLOSE);
+ sock_release(sock);
+ }
+}
+EXPORT_SYMBOL(qed_return_tcp_port);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ooo.c b/drivers/net/ethernet/qlogic/qed/qed_ooo.c
index 88353aa404dc..b8c5641b29a8 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ooo.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ooo.c
@@ -16,7 +16,7 @@
#include "qed_ll2.h"
#include "qed_ooo.h"
#include "qed_cxt.h"
-
+#include "qed_nvmetcp.h"
static struct qed_ooo_archipelago
*qed_ooo_seek_archipelago(struct qed_hwfn *p_hwfn,
struct qed_ooo_info
@@ -83,7 +83,8 @@ int qed_ooo_alloc(struct qed_hwfn *p_hwfn)
switch (p_hwfn->hw_info.personality) {
case QED_PCI_ISCSI:
- proto = PROTOCOLID_ISCSI;
+ case QED_PCI_NVMETCP:
+ proto = PROTOCOLID_TCP_ULP;
break;
case QED_PCI_ETH_RDMA:
case QED_PCI_ETH_IWARP:
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h
index 993f1357b6fc..60ff3222bf55 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_sp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h
@@ -100,6 +100,11 @@ union ramrod_data {
struct iscsi_spe_conn_mac_update iscsi_conn_mac_update;
struct iscsi_spe_conn_termination iscsi_conn_terminate;
+ struct nvmetcp_init_ramrod_params nvmetcp_init;
+ struct nvmetcp_spe_conn_offload nvmetcp_conn_offload;
+ struct nvmetcp_conn_update_ramrod_params nvmetcp_conn_update;
+ struct nvmetcp_spe_conn_termination nvmetcp_conn_terminate;
+
struct vf_start_ramrod_data vf_start;
struct vf_stop_ramrod_data vf_stop;
};
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
index aa71adcf31ee..b4ed54ffef9b 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
@@ -385,7 +385,8 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
p_ramrod->personality = PERSONALITY_FCOE;
break;
case QED_PCI_ISCSI:
- p_ramrod->personality = PERSONALITY_ISCSI;
+ case QED_PCI_NVMETCP:
+ p_ramrod->personality = PERSONALITY_TCP_ULP;
break;
case QED_PCI_ETH_ROCE:
case QED_PCI_ETH_IWARP:
diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c
index 8e150dd4f899..065e9004598e 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_fp.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c
@@ -1089,13 +1089,7 @@ static bool qede_rx_xdp(struct qede_dev *edev,
xdp_prepare_buff(&xdp, page_address(bd->data), *data_offset,
*len, false);
- /* Queues always have a full reset currently, so for the time
- * being until there's atomic program replace just mark read
- * side for map helpers.
- */
- rcu_read_lock();
act = bpf_prog_run_xdp(prog, &xdp);
- rcu_read_unlock();
/* Recalculate, as XDP might have changed the headers */
*data_offset = xdp.data - xdp.data_hard_start;
diff --git a/drivers/net/ethernet/qlogic/qede/qede_rdma.c b/drivers/net/ethernet/qlogic/qede/qede_rdma.c
index 2f6598086d9b..6304514a6f2c 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_rdma.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_rdma.c
@@ -247,12 +247,10 @@ static struct qede_rdma_event_work *
qede_rdma_get_free_event_node(struct qede_dev *edev)
{
struct qede_rdma_event_work *event_node = NULL;
- struct list_head *list_node = NULL;
bool found = false;
- list_for_each(list_node, &edev->rdma_info.rdma_event_list) {
- event_node = list_entry(list_node, struct qede_rdma_event_work,
- list);
+ list_for_each_entry(event_node, &edev->rdma_info.rdma_event_list,
+ list) {
if (!work_pending(&event_node->work)) {
found = true;
break;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index d2c190732d3e..0a2f34fc8b24 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -746,7 +746,7 @@ static int qlcnic_83xx_idc_unknown_state(struct qlcnic_adapter *adapter)
}
/**
- * qlcnic_83xx_idc_cold_state
+ * qlcnic_83xx_idc_cold_state_handler
*
* @adapter: adapter structure
*
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
index c4297aea7d15..711609503ba6 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
@@ -180,7 +180,7 @@ static int qlcnic_83xx_init_non_privileged_vnic(struct qlcnic_adapter *adapter)
}
/**
- * qlcnic_83xx_vnic_opmode
+ * qlcnic_83xx_config_vnic_opmode
*
* @adapter: adapter structure
* Identify virtual NIC operational modes.
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index e1b8490bed0a..4b8bc46f55c2 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -460,12 +460,10 @@ int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr)
{
struct qlcnic_mac_vlan_list *cur;
- struct list_head *head;
int err = -EINVAL;
/* Delete MAC from the existing list */
- list_for_each(head, &adapter->mac_list) {
- cur = list_entry(head, struct qlcnic_mac_vlan_list, list);
+ list_for_each_entry(cur, &adapter->mac_list, list) {
if (ether_addr_equal(addr, cur->mac_addr)) {
err = qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
0, QLCNIC_MAC_DEL);
@@ -483,11 +481,9 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan,
enum qlcnic_mac_type mac_type)
{
struct qlcnic_mac_vlan_list *cur;
- struct list_head *head;
/* look up if already exists */
- list_for_each(head, &adapter->mac_list) {
- cur = list_entry(head, struct qlcnic_mac_vlan_list, list);
+ list_for_each_entry(cur, &adapter->mac_list, list) {
if (ether_addr_equal(addr, cur->mac_addr) &&
cur->vlan_id == vlan)
return 0;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
index 601d22495a88..95ecc84dddcd 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
@@ -203,7 +203,6 @@ int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
int qlcnic_82xx_alloc_mbx_args(struct qlcnic_cmd_args *,
struct qlcnic_adapter *, u32);
-int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32);
int qlcnic_82xx_get_board_info(struct qlcnic_adapter *);
int qlcnic_82xx_config_led(struct qlcnic_adapter *, u32, u32);
void qlcnic_82xx_get_func_no(struct qlcnic_adapter *);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index bdf15d2a6431..af4c516a9e7c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -1390,6 +1390,7 @@ static int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int ma
break;
case QLCNIC_RESPONSE_DESC:
qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
+ goto skip;
default:
goto skip;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 3beafc60747e..a4fa507903ee 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -319,10 +319,8 @@ int qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
static void qlcnic_delete_adapter_mac(struct qlcnic_adapter *adapter)
{
struct qlcnic_mac_vlan_list *cur;
- struct list_head *head;
- list_for_each(head, &adapter->mac_list) {
- cur = list_entry(head, struct qlcnic_mac_vlan_list, list);
+ list_for_each_entry(cur, &adapter->mac_list, list) {
if (ether_addr_equal_unaligned(adapter->mac_addr, cur->mac_addr)) {
qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
0, QLCNIC_MAC_DEL);
@@ -3344,9 +3342,6 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
do {
msleep(1000);
prev_state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
-
- if (prev_state == QLCNIC_DEV_QUISCENT)
- continue;
} while ((prev_state != QLCNIC_DEV_READY) && --dev_init_timeo);
if (!dev_init_timeo) {
@@ -3456,6 +3451,7 @@ wait_npar:
adapter->fw_wait_cnt = 0;
return;
}
+ break;
case QLCNIC_DEV_FAILED:
break;
default:
diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c
index 8543bf3c3484..ad655f0a4965 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac.c
@@ -735,12 +735,13 @@ static int emac_remove(struct platform_device *pdev)
put_device(&adpt->phydev->mdio.dev);
mdiobus_unregister(adpt->mii_bus);
- free_netdev(netdev);
if (adpt->phy.digital)
iounmap(adpt->phy.digital);
iounmap(adpt->phy.base);
+ free_netdev(netdev);
+
return 0;
}
diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c
index 702aa217a27a..d59fff2fbcc6 100644
--- a/drivers/net/ethernet/qualcomm/qca_debug.c
+++ b/drivers/net/ethernet/qualcomm/qca_debug.c
@@ -62,6 +62,7 @@ static const char qcaspi_gstrings_stats[][ETH_GSTRING_LEN] = {
"SPI errors",
"Write verify errors",
"Buffer available errors",
+ "Bad signature",
};
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index ab9b02574a15..b64c254e00ba 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -504,8 +504,12 @@ qcaspi_qca7k_sync(struct qcaspi *qca, int event)
qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature);
qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature);
if (signature != QCASPI_GOOD_SIGNATURE) {
+ if (qca->sync == QCASPI_SYNC_READY)
+ qca->stats.bad_signature++;
+
qca->sync = QCASPI_SYNC_UNKNOWN;
netdev_dbg(qca->net_dev, "sync: got CPU on, but signature was invalid, restart\n");
+ return;
} else {
/* ensure that the WRBUF is empty */
qcaspi_read_register(qca, SPI_REG_WRBUF_SPC_AVA,
@@ -523,10 +527,14 @@ qcaspi_qca7k_sync(struct qcaspi *qca, int event)
switch (qca->sync) {
case QCASPI_SYNC_READY:
- /* Read signature, if not valid go to unknown state. */
+ /* Check signature twice, if not valid go to unknown state. */
qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature);
+ if (signature != QCASPI_GOOD_SIGNATURE)
+ qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature);
+
if (signature != QCASPI_GOOD_SIGNATURE) {
qca->sync = QCASPI_SYNC_UNKNOWN;
+ qca->stats.bad_signature++;
netdev_dbg(qca->net_dev, "sync: bad signature, restart\n");
/* don't reset right away */
return;
@@ -653,8 +661,7 @@ qcaspi_intr_handler(int irq, void *data)
struct qcaspi *qca = data;
qca->intr_req++;
- if (qca->spi_thread &&
- qca->spi_thread->state != TASK_RUNNING)
+ if (qca->spi_thread)
wake_up_process(qca->spi_thread);
return IRQ_HANDLED;
@@ -777,8 +784,7 @@ qcaspi_netdev_xmit(struct sk_buff *skb, struct net_device *dev)
netif_trans_update(dev);
- if (qca->spi_thread &&
- qca->spi_thread->state != TASK_RUNNING)
+ if (qca->spi_thread)
wake_up_process(qca->spi_thread);
return NETDEV_TX_OK;
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h
index d13a67e20d65..3067356106f0 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.h
+++ b/drivers/net/ethernet/qualcomm/qca_spi.h
@@ -75,6 +75,7 @@ struct qcaspi_stats {
u64 spi_err;
u64 write_verify_failed;
u64 buf_avail_err;
+ u64 bad_signature;
};
struct qcaspi {
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
index 8d51b0cb545c..27b1663c476e 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
@@ -163,7 +163,8 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
struct ifla_rmnet_flags *flags;
flags = nla_data(data[IFLA_RMNET_FLAGS]);
- data_format = flags->flags & flags->mask;
+ data_format &= ~flags->mask;
+ data_format |= flags->flags & flags->mask;
}
netdev_dbg(dev, "data format [0x%08X]\n", data_format);
@@ -336,7 +337,8 @@ static int rmnet_changelink(struct net_device *dev, struct nlattr *tb[],
old_data_format = port->data_format;
flags = nla_data(data[IFLA_RMNET_FLAGS]);
- port->data_format = flags->flags & flags->mask;
+ port->data_format &= ~flags->mask;
+ port->data_format |= flags->flags & flags->mask;
if (rmnet_vnd_update_dev_mtu(port, real_dev)) {
port->data_format = old_data_format;
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
index 8d8d4690a074..3d3cba56c516 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2013-2014, 2016-2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016-2018, 2021 The Linux Foundation.
+ * All rights reserved.
*
* RMNET Data configuration engine
*/
@@ -48,6 +49,7 @@ struct rmnet_pcpu_stats {
struct rmnet_priv_stats {
u64 csum_ok;
+ u64 csum_ip4_header_bad;
u64 csum_valid_unset;
u64 csum_validation_failed;
u64 csum_err_bad_buffer;
@@ -56,6 +58,7 @@ struct rmnet_priv_stats {
u64 csum_fragmented_pkt;
u64 csum_skipped;
u64 csum_sw;
+ u64 csum_hw;
};
struct rmnet_priv {
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
index 0be5ac7ab261..bfbd7847f946 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 2021, The Linux Foundation. All rights reserved.
*
* RMNET Data ingress/egress handler
*/
@@ -82,12 +82,18 @@ __rmnet_map_ingress_handler(struct sk_buff *skb,
skb->dev = ep->egress_dev;
- /* Subtract MAP header */
- skb_pull(skb, sizeof(struct rmnet_map_header));
- rmnet_set_skb_proto(skb);
-
- if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4) {
- if (!rmnet_map_checksum_downlink_packet(skb, len + pad))
+ if ((port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV5) &&
+ (map_header->flags & MAP_NEXT_HEADER_FLAG)) {
+ if (rmnet_map_process_next_hdr_packet(skb, len))
+ goto free_skb;
+ skb_pull(skb, sizeof(*map_header));
+ rmnet_set_skb_proto(skb);
+ } else {
+ /* Subtract MAP header */
+ skb_pull(skb, sizeof(*map_header));
+ rmnet_set_skb_proto(skb);
+ if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4 &&
+ !rmnet_map_checksum_downlink_packet(skb, len + pad))
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
@@ -128,7 +134,7 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
struct rmnet_port *port, u8 mux_id,
struct net_device *orig_dev)
{
- int required_headroom, additional_header_len;
+ int required_headroom, additional_header_len, csum_type = 0;
struct rmnet_map_header *map_header;
additional_header_len = 0;
@@ -136,18 +142,23 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
if (port->data_format & RMNET_FLAGS_EGRESS_MAP_CKSUMV4) {
additional_header_len = sizeof(struct rmnet_map_ul_csum_header);
- required_headroom += additional_header_len;
+ csum_type = RMNET_FLAGS_EGRESS_MAP_CKSUMV4;
+ } else if (port->data_format & RMNET_FLAGS_EGRESS_MAP_CKSUMV5) {
+ additional_header_len = sizeof(struct rmnet_map_v5_csum_header);
+ csum_type = RMNET_FLAGS_EGRESS_MAP_CKSUMV5;
}
- if (skb_headroom(skb) < required_headroom) {
- if (pskb_expand_head(skb, required_headroom, 0, GFP_ATOMIC))
- return -ENOMEM;
- }
+ required_headroom += additional_header_len;
+
+ if (skb_cow_head(skb, required_headroom) < 0)
+ return -ENOMEM;
- if (port->data_format & RMNET_FLAGS_EGRESS_MAP_CKSUMV4)
- rmnet_map_checksum_uplink_packet(skb, orig_dev);
+ if (csum_type)
+ rmnet_map_checksum_uplink_packet(skb, port, orig_dev,
+ csum_type);
- map_header = rmnet_map_add_map_header(skb, additional_header_len, 0);
+ map_header = rmnet_map_add_map_header(skb, additional_header_len,
+ port, 0);
if (!map_header)
return -ENOMEM;
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
index 2aea153f4247..e5a0b38f7dbe 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 2021, The Linux Foundation. All rights reserved.
*/
#ifndef _RMNET_MAP_H_
@@ -43,10 +43,15 @@ enum rmnet_map_commands {
struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb,
struct rmnet_port *port);
struct rmnet_map_header *rmnet_map_add_map_header(struct sk_buff *skb,
- int hdrlen, int pad);
+ int hdrlen,
+ struct rmnet_port *port,
+ int pad);
void rmnet_map_command(struct sk_buff *skb, struct rmnet_port *port);
int rmnet_map_checksum_downlink_packet(struct sk_buff *skb, u16 len);
void rmnet_map_checksum_uplink_packet(struct sk_buff *skb,
- struct net_device *orig_dev);
+ struct rmnet_port *port,
+ struct net_device *orig_dev,
+ int csum_type);
+int rmnet_map_process_next_hdr_packet(struct sk_buff *skb, u16 len);
#endif /* _RMNET_MAP_H_ */
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
index 0ac2ff828320..3676976c875b 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 2021, The Linux Foundation. All rights reserved.
*
* RMNET Data MAP protocol
*/
@@ -8,6 +8,7 @@
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/ip6_checksum.h>
+#include <linux/bitfield.h>
#include "rmnet_config.h"
#include "rmnet_map.h"
#include "rmnet_private.h"
@@ -18,23 +19,13 @@
static __sum16 *rmnet_map_get_csum_field(unsigned char protocol,
const void *txporthdr)
{
- __sum16 *check = NULL;
+ if (protocol == IPPROTO_TCP)
+ return &((struct tcphdr *)txporthdr)->check;
- switch (protocol) {
- case IPPROTO_TCP:
- check = &(((struct tcphdr *)txporthdr)->check);
- break;
-
- case IPPROTO_UDP:
- check = &(((struct udphdr *)txporthdr)->check);
- break;
+ if (protocol == IPPROTO_UDP)
+ return &((struct udphdr *)txporthdr)->check;
- default:
- check = NULL;
- break;
- }
-
- return check;
+ return NULL;
}
static int
@@ -42,71 +33,74 @@ rmnet_map_ipv4_dl_csum_trailer(struct sk_buff *skb,
struct rmnet_map_dl_csum_trailer *csum_trailer,
struct rmnet_priv *priv)
{
- __sum16 *csum_field, csum_temp, pseudo_csum, hdr_csum, ip_payload_csum;
- u16 csum_value, csum_value_final;
- struct iphdr *ip4h;
- void *txporthdr;
- __be16 addend;
-
- ip4h = (struct iphdr *)(skb->data);
- if ((ntohs(ip4h->frag_off) & IP_MF) ||
- ((ntohs(ip4h->frag_off) & IP_OFFSET) > 0)) {
+ struct iphdr *ip4h = (struct iphdr *)skb->data;
+ void *txporthdr = skb->data + ip4h->ihl * 4;
+ __sum16 *csum_field, pseudo_csum;
+ __sum16 ip_payload_csum;
+
+ /* Computing the checksum over just the IPv4 header--including its
+ * checksum field--should yield 0. If it doesn't, the IP header
+ * is bad, so return an error and let the IP layer drop it.
+ */
+ if (ip_fast_csum(ip4h, ip4h->ihl)) {
+ priv->stats.csum_ip4_header_bad++;
+ return -EINVAL;
+ }
+
+ /* We don't support checksum offload on IPv4 fragments */
+ if (ip_is_fragment(ip4h)) {
priv->stats.csum_fragmented_pkt++;
return -EOPNOTSUPP;
}
- txporthdr = skb->data + ip4h->ihl * 4;
-
+ /* Checksum offload is only supported for UDP and TCP protocols */
csum_field = rmnet_map_get_csum_field(ip4h->protocol, txporthdr);
-
if (!csum_field) {
priv->stats.csum_err_invalid_transport++;
return -EPROTONOSUPPORT;
}
- /* RFC 768 - Skip IPv4 UDP packets where sender checksum field is 0 */
- if (*csum_field == 0 && ip4h->protocol == IPPROTO_UDP) {
+ /* RFC 768: UDP checksum is optional for IPv4, and is 0 if unused */
+ if (!*csum_field && ip4h->protocol == IPPROTO_UDP) {
priv->stats.csum_skipped++;
return 0;
}
- csum_value = ~ntohs(csum_trailer->csum_value);
- hdr_csum = ~ip_fast_csum(ip4h, (int)ip4h->ihl);
- ip_payload_csum = csum16_sub((__force __sum16)csum_value,
- (__force __be16)hdr_csum);
-
- pseudo_csum = ~csum_tcpudp_magic(ip4h->saddr, ip4h->daddr,
- ntohs(ip4h->tot_len) - ip4h->ihl * 4,
- ip4h->protocol, 0);
- addend = (__force __be16)ntohs((__force __be16)pseudo_csum);
- pseudo_csum = csum16_add(ip_payload_csum, addend);
-
- addend = (__force __be16)ntohs((__force __be16)*csum_field);
- csum_temp = ~csum16_sub(pseudo_csum, addend);
- csum_value_final = (__force u16)csum_temp;
-
- if (unlikely(csum_value_final == 0)) {
- switch (ip4h->protocol) {
- case IPPROTO_UDP:
- /* RFC 768 - DL4 1's complement rule for UDP csum 0 */
- csum_value_final = ~csum_value_final;
- break;
-
- case IPPROTO_TCP:
- /* DL4 Non-RFC compliant TCP checksum found */
- if (*csum_field == (__force __sum16)0xFFFF)
- csum_value_final = ~csum_value_final;
- break;
- }
- }
-
- if (csum_value_final == ntohs((__force __be16)*csum_field)) {
- priv->stats.csum_ok++;
- return 0;
- } else {
+ /* The checksum value in the trailer is computed over the entire
+ * IP packet, including the IP header and payload. To derive the
+ * transport checksum from this, we first subract the contribution
+ * of the IP header from the trailer checksum. We then add the
+ * checksum computed over the pseudo header.
+ *
+ * We verified above that the IP header contributes zero to the
+ * trailer checksum. Therefore the checksum in the trailer is
+ * just the checksum computed over the IP payload.
+
+ * If the IP payload arrives intact, adding the pseudo header
+ * checksum to the IP payload checksum will yield 0xffff (negative
+ * zero). This means the trailer checksum and the pseudo checksum
+ * are additive inverses of each other. Put another way, the
+ * message passes the checksum test if the trailer checksum value
+ * is the negated pseudo header checksum.
+ *
+ * Knowing this, we don't even need to examine the transport
+ * header checksum value; it is already accounted for in the
+ * checksum value found in the trailer.
+ */
+ ip_payload_csum = csum_trailer->csum_value;
+
+ pseudo_csum = csum_tcpudp_magic(ip4h->saddr, ip4h->daddr,
+ ntohs(ip4h->tot_len) - ip4h->ihl * 4,
+ ip4h->protocol, 0);
+
+ /* The cast is required to ensure only the low 16 bits are examined */
+ if (ip_payload_csum != (__sum16)~pseudo_csum) {
priv->stats.csum_validation_failed++;
return -EINVAL;
}
+
+ priv->stats.csum_ok++;
+ return 0;
}
#if IS_ENABLED(CONFIG_IPV6)
@@ -115,76 +109,66 @@ rmnet_map_ipv6_dl_csum_trailer(struct sk_buff *skb,
struct rmnet_map_dl_csum_trailer *csum_trailer,
struct rmnet_priv *priv)
{
- __sum16 *csum_field, ip6_payload_csum, pseudo_csum, csum_temp;
- u16 csum_value, csum_value_final;
- __be16 ip6_hdr_csum, addend;
- struct ipv6hdr *ip6h;
- void *txporthdr;
- u32 length;
-
- ip6h = (struct ipv6hdr *)(skb->data);
-
- txporthdr = skb->data + sizeof(struct ipv6hdr);
+ struct ipv6hdr *ip6h = (struct ipv6hdr *)skb->data;
+ void *txporthdr = skb->data + sizeof(*ip6h);
+ __sum16 *csum_field, pseudo_csum;
+ __sum16 ip6_payload_csum;
+ __be16 ip_header_csum;
+
+ /* Checksum offload is only supported for UDP and TCP protocols;
+ * the packet cannot include any IPv6 extension headers
+ */
csum_field = rmnet_map_get_csum_field(ip6h->nexthdr, txporthdr);
-
if (!csum_field) {
priv->stats.csum_err_invalid_transport++;
return -EPROTONOSUPPORT;
}
- csum_value = ~ntohs(csum_trailer->csum_value);
- ip6_hdr_csum = (__force __be16)
- ~ntohs((__force __be16)ip_compute_csum(ip6h,
- (int)(txporthdr - (void *)(skb->data))));
- ip6_payload_csum = csum16_sub((__force __sum16)csum_value,
- ip6_hdr_csum);
-
- length = (ip6h->nexthdr == IPPROTO_UDP) ?
- ntohs(((struct udphdr *)txporthdr)->len) :
- ntohs(ip6h->payload_len);
- pseudo_csum = ~(csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
- length, ip6h->nexthdr, 0));
- addend = (__force __be16)ntohs((__force __be16)pseudo_csum);
- pseudo_csum = csum16_add(ip6_payload_csum, addend);
-
- addend = (__force __be16)ntohs((__force __be16)*csum_field);
- csum_temp = ~csum16_sub(pseudo_csum, addend);
- csum_value_final = (__force u16)csum_temp;
-
- if (unlikely(csum_value_final == 0)) {
- switch (ip6h->nexthdr) {
- case IPPROTO_UDP:
- /* RFC 2460 section 8.1
- * DL6 One's complement rule for UDP checksum 0
- */
- csum_value_final = ~csum_value_final;
- break;
-
- case IPPROTO_TCP:
- /* DL6 Non-RFC compliant TCP checksum found */
- if (*csum_field == (__force __sum16)0xFFFF)
- csum_value_final = ~csum_value_final;
- break;
- }
- }
-
- if (csum_value_final == ntohs((__force __be16)*csum_field)) {
- priv->stats.csum_ok++;
- return 0;
- } else {
+ /* The checksum value in the trailer is computed over the entire
+ * IP packet, including the IP header and payload. To derive the
+ * transport checksum from this, we first subract the contribution
+ * of the IP header from the trailer checksum. We then add the
+ * checksum computed over the pseudo header.
+ */
+ ip_header_csum = (__force __be16)ip_fast_csum(ip6h, sizeof(*ip6h) / 4);
+ ip6_payload_csum = csum16_sub(csum_trailer->csum_value, ip_header_csum);
+
+ pseudo_csum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+ ntohs(ip6h->payload_len),
+ ip6h->nexthdr, 0);
+
+ /* It's sufficient to compare the IP payload checksum with the
+ * negated pseudo checksum to determine whether the packet
+ * checksum was good. (See further explanation in comments
+ * in rmnet_map_ipv4_dl_csum_trailer()).
+ *
+ * The cast is required to ensure only the low 16 bits are
+ * examined.
+ */
+ if (ip6_payload_csum != (__sum16)~pseudo_csum) {
priv->stats.csum_validation_failed++;
return -EINVAL;
}
+
+ priv->stats.csum_ok++;
+ return 0;
+}
+#else
+static int
+rmnet_map_ipv6_dl_csum_trailer(struct sk_buff *skb,
+ struct rmnet_map_dl_csum_trailer *csum_trailer,
+ struct rmnet_priv *priv)
+{
+ return 0;
}
#endif
-static void rmnet_map_complement_ipv4_txporthdr_csum_field(void *iphdr)
+static void rmnet_map_complement_ipv4_txporthdr_csum_field(struct iphdr *ip4h)
{
- struct iphdr *ip4h = (struct iphdr *)iphdr;
void *txphdr;
u16 *csum;
- txphdr = iphdr + ip4h->ihl * 4;
+ txphdr = (void *)ip4h + ip4h->ihl * 4;
if (ip4h->protocol == IPPROTO_TCP || ip4h->protocol == IPPROTO_UDP) {
csum = (u16 *)rmnet_map_get_csum_field(ip4h->protocol, txphdr);
@@ -193,15 +177,14 @@ static void rmnet_map_complement_ipv4_txporthdr_csum_field(void *iphdr)
}
static void
-rmnet_map_ipv4_ul_csum_header(void *iphdr,
+rmnet_map_ipv4_ul_csum_header(struct iphdr *iphdr,
struct rmnet_map_ul_csum_header *ul_header,
struct sk_buff *skb)
{
- struct iphdr *ip4h = iphdr;
u16 val;
val = MAP_CSUM_UL_ENABLED_FLAG;
- if (ip4h->protocol == IPPROTO_UDP)
+ if (iphdr->protocol == IPPROTO_UDP)
val |= MAP_CSUM_UL_UDP_FLAG;
val |= skb->csum_offset & MAP_CSUM_UL_OFFSET_MASK;
@@ -214,13 +197,13 @@ rmnet_map_ipv4_ul_csum_header(void *iphdr,
}
#if IS_ENABLED(CONFIG_IPV6)
-static void rmnet_map_complement_ipv6_txporthdr_csum_field(void *ip6hdr)
+static void
+rmnet_map_complement_ipv6_txporthdr_csum_field(struct ipv6hdr *ip6h)
{
- struct ipv6hdr *ip6h = (struct ipv6hdr *)ip6hdr;
void *txphdr;
u16 *csum;
- txphdr = ip6hdr + sizeof(struct ipv6hdr);
+ txphdr = ip6h + 1;
if (ip6h->nexthdr == IPPROTO_TCP || ip6h->nexthdr == IPPROTO_UDP) {
csum = (u16 *)rmnet_map_get_csum_field(ip6h->nexthdr, txphdr);
@@ -229,15 +212,14 @@ static void rmnet_map_complement_ipv6_txporthdr_csum_field(void *ip6hdr)
}
static void
-rmnet_map_ipv6_ul_csum_header(void *ip6hdr,
+rmnet_map_ipv6_ul_csum_header(struct ipv6hdr *ipv6hdr,
struct rmnet_map_ul_csum_header *ul_header,
struct sk_buff *skb)
{
- struct ipv6hdr *ip6h = ip6hdr;
u16 val;
val = MAP_CSUM_UL_ENABLED_FLAG;
- if (ip6h->nexthdr == IPPROTO_UDP)
+ if (ipv6hdr->nexthdr == IPPROTO_UDP)
val |= MAP_CSUM_UL_UDP_FLAG;
val |= skb->csum_offset & MAP_CSUM_UL_OFFSET_MASK;
@@ -246,16 +228,73 @@ rmnet_map_ipv6_ul_csum_header(void *ip6hdr,
skb->ip_summed = CHECKSUM_NONE;
- rmnet_map_complement_ipv6_txporthdr_csum_field(ip6hdr);
+ rmnet_map_complement_ipv6_txporthdr_csum_field(ipv6hdr);
+}
+#else
+static void
+rmnet_map_ipv6_ul_csum_header(void *ip6hdr,
+ struct rmnet_map_ul_csum_header *ul_header,
+ struct sk_buff *skb)
+{
}
#endif
+static void rmnet_map_v5_checksum_uplink_packet(struct sk_buff *skb,
+ struct rmnet_port *port,
+ struct net_device *orig_dev)
+{
+ struct rmnet_priv *priv = netdev_priv(orig_dev);
+ struct rmnet_map_v5_csum_header *ul_header;
+
+ ul_header = skb_push(skb, sizeof(*ul_header));
+ memset(ul_header, 0, sizeof(*ul_header));
+ ul_header->header_info = u8_encode_bits(RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD,
+ MAPV5_HDRINFO_HDR_TYPE_FMASK);
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ void *iph = ip_hdr(skb);
+ __sum16 *check;
+ void *trans;
+ u8 proto;
+
+ if (skb->protocol == htons(ETH_P_IP)) {
+ u16 ip_len = ((struct iphdr *)iph)->ihl * 4;
+
+ proto = ((struct iphdr *)iph)->protocol;
+ trans = iph + ip_len;
+ } else if (IS_ENABLED(CONFIG_IPV6) &&
+ skb->protocol == htons(ETH_P_IPV6)) {
+ u16 ip_len = sizeof(struct ipv6hdr);
+
+ proto = ((struct ipv6hdr *)iph)->nexthdr;
+ trans = iph + ip_len;
+ } else {
+ priv->stats.csum_err_invalid_ip_version++;
+ goto sw_csum;
+ }
+
+ check = rmnet_map_get_csum_field(proto, trans);
+ if (check) {
+ skb->ip_summed = CHECKSUM_NONE;
+ /* Ask for checksum offloading */
+ ul_header->csum_info |= MAPV5_CSUMINFO_VALID_FLAG;
+ priv->stats.csum_hw++;
+ return;
+ }
+ }
+
+sw_csum:
+ priv->stats.csum_sw++;
+}
+
/* Adds MAP header to front of skb->data
* Padding is calculated and set appropriately in MAP header. Mux ID is
* initialized to 0.
*/
struct rmnet_map_header *rmnet_map_add_map_header(struct sk_buff *skb,
- int hdrlen, int pad)
+ int hdrlen,
+ struct rmnet_port *port,
+ int pad)
{
struct rmnet_map_header *map_header;
u32 padding, map_datalen;
@@ -266,6 +305,10 @@ struct rmnet_map_header *rmnet_map_add_map_header(struct sk_buff *skb,
skb_push(skb, sizeof(struct rmnet_map_header));
memset(map_header, 0, sizeof(struct rmnet_map_header));
+ /* Set next_hdr bit for csum offload packets */
+ if (port->data_format & RMNET_FLAGS_EGRESS_MAP_CKSUMV5)
+ map_header->flags |= MAP_NEXT_HEADER_FLAG;
+
if (pad == RMNET_MAP_NO_PAD_BYTES) {
map_header->pkt_len = htons(map_datalen);
return map_header;
@@ -300,8 +343,11 @@ done:
struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb,
struct rmnet_port *port)
{
+ struct rmnet_map_v5_csum_header *next_hdr = NULL;
struct rmnet_map_header *maph;
+ void *data = skb->data;
struct sk_buff *skbn;
+ u8 nexthdr_type;
u32 packet_len;
if (skb->len == 0)
@@ -310,8 +356,18 @@ struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb,
maph = (struct rmnet_map_header *)skb->data;
packet_len = ntohs(maph->pkt_len) + sizeof(*maph);
- if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4)
+ if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4) {
packet_len += sizeof(struct rmnet_map_dl_csum_trailer);
+ } else if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV5) {
+ if (!(maph->flags & MAP_CMD_FLAG)) {
+ packet_len += sizeof(*next_hdr);
+ if (maph->flags & MAP_NEXT_HEADER_FLAG)
+ next_hdr = data + sizeof(*maph);
+ else
+ /* Mapv5 data pkt without csum hdr is invalid */
+ return NULL;
+ }
+ }
if (((int)skb->len - (int)packet_len) < 0)
return NULL;
@@ -320,6 +376,13 @@ struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb,
if (!maph->pkt_len)
return NULL;
+ if (next_hdr) {
+ nexthdr_type = u8_get_bits(next_hdr->header_info,
+ MAPV5_HDRINFO_HDR_TYPE_FMASK);
+ if (nexthdr_type != RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD)
+ return NULL;
+ }
+
skbn = alloc_skb(packet_len + RMNET_MAP_DEAGGR_SPACING, GFP_ATOMIC);
if (!skbn)
return NULL;
@@ -355,28 +418,19 @@ int rmnet_map_checksum_downlink_packet(struct sk_buff *skb, u16 len)
return -EINVAL;
}
- if (skb->protocol == htons(ETH_P_IP)) {
+ if (skb->protocol == htons(ETH_P_IP))
return rmnet_map_ipv4_dl_csum_trailer(skb, csum_trailer, priv);
- } else if (skb->protocol == htons(ETH_P_IPV6)) {
-#if IS_ENABLED(CONFIG_IPV6)
+
+ if (IS_ENABLED(CONFIG_IPV6) && skb->protocol == htons(ETH_P_IPV6))
return rmnet_map_ipv6_dl_csum_trailer(skb, csum_trailer, priv);
-#else
- priv->stats.csum_err_invalid_ip_version++;
- return -EPROTONOSUPPORT;
-#endif
- } else {
- priv->stats.csum_err_invalid_ip_version++;
- return -EPROTONOSUPPORT;
- }
- return 0;
+ priv->stats.csum_err_invalid_ip_version++;
+
+ return -EPROTONOSUPPORT;
}
-/* Generates UL checksum meta info header for IPv4 and IPv6 over TCP and UDP
- * packets that are supported for UL checksum offload.
- */
-void rmnet_map_checksum_uplink_packet(struct sk_buff *skb,
- struct net_device *orig_dev)
+static void rmnet_map_v4_checksum_uplink_packet(struct sk_buff *skb,
+ struct net_device *orig_dev)
{
struct rmnet_priv *priv = netdev_priv(orig_dev);
struct rmnet_map_ul_csum_header *ul_header;
@@ -389,28 +443,80 @@ void rmnet_map_checksum_uplink_packet(struct sk_buff *skb,
(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))))
goto sw_csum;
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- iphdr = (char *)ul_header +
- sizeof(struct rmnet_map_ul_csum_header);
+ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ goto sw_csum;
- if (skb->protocol == htons(ETH_P_IP)) {
- rmnet_map_ipv4_ul_csum_header(iphdr, ul_header, skb);
- return;
- } else if (skb->protocol == htons(ETH_P_IPV6)) {
-#if IS_ENABLED(CONFIG_IPV6)
- rmnet_map_ipv6_ul_csum_header(iphdr, ul_header, skb);
- return;
-#else
- priv->stats.csum_err_invalid_ip_version++;
- goto sw_csum;
-#endif
- } else {
- priv->stats.csum_err_invalid_ip_version++;
- }
+ iphdr = (char *)ul_header +
+ sizeof(struct rmnet_map_ul_csum_header);
+
+ if (skb->protocol == htons(ETH_P_IP)) {
+ rmnet_map_ipv4_ul_csum_header(iphdr, ul_header, skb);
+ priv->stats.csum_hw++;
+ return;
+ }
+
+ if (IS_ENABLED(CONFIG_IPV6) && skb->protocol == htons(ETH_P_IPV6)) {
+ rmnet_map_ipv6_ul_csum_header(iphdr, ul_header, skb);
+ priv->stats.csum_hw++;
+ return;
}
+ priv->stats.csum_err_invalid_ip_version++;
+
sw_csum:
memset(ul_header, 0, sizeof(*ul_header));
priv->stats.csum_sw++;
}
+
+/* Generates UL checksum meta info header for IPv4 and IPv6 over TCP and UDP
+ * packets that are supported for UL checksum offload.
+ */
+void rmnet_map_checksum_uplink_packet(struct sk_buff *skb,
+ struct rmnet_port *port,
+ struct net_device *orig_dev,
+ int csum_type)
+{
+ switch (csum_type) {
+ case RMNET_FLAGS_EGRESS_MAP_CKSUMV4:
+ rmnet_map_v4_checksum_uplink_packet(skb, orig_dev);
+ break;
+ case RMNET_FLAGS_EGRESS_MAP_CKSUMV5:
+ rmnet_map_v5_checksum_uplink_packet(skb, port, orig_dev);
+ break;
+ default:
+ break;
+ }
+}
+
+/* Process a MAPv5 packet header */
+int rmnet_map_process_next_hdr_packet(struct sk_buff *skb,
+ u16 len)
+{
+ struct rmnet_priv *priv = netdev_priv(skb->dev);
+ struct rmnet_map_v5_csum_header *next_hdr;
+ u8 nexthdr_type;
+
+ next_hdr = (struct rmnet_map_v5_csum_header *)(skb->data +
+ sizeof(struct rmnet_map_header));
+
+ nexthdr_type = u8_get_bits(next_hdr->header_info,
+ MAPV5_HDRINFO_HDR_TYPE_FMASK);
+
+ if (nexthdr_type != RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD)
+ return -EINVAL;
+
+ if (unlikely(!(skb->dev->features & NETIF_F_RXCSUM))) {
+ priv->stats.csum_sw++;
+ } else if (next_hdr->csum_info & MAPV5_CSUMINFO_VALID_FLAG) {
+ priv->stats.csum_ok++;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ priv->stats.csum_valid_unset++;
+ }
+
+ /* Pull csum v5 header */
+ skb_pull(skb, sizeof(*next_hdr));
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
index ab1e0fcccabb..13d8eb43a485 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
@@ -166,6 +166,7 @@ static const struct net_device_ops rmnet_vnd_ops = {
static const char rmnet_gstrings_stats[][ETH_GSTRING_LEN] = {
"Checksum ok",
+ "Bad IPv4 header checksum",
"Checksum valid bit not set",
"Checksum validation failed",
"Checksum error bad buffer",
@@ -174,6 +175,7 @@ static const char rmnet_gstrings_stats[][ETH_GSTRING_LEN] = {
"Checksum skipped on ip fragment",
"Checksum skipped",
"Checksum computed in software",
+ "Checksum computed in hardware",
};
static void rmnet_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
diff --git a/drivers/net/ethernet/rdc/r6040.c b/drivers/net/ethernet/rdc/r6040.c
index 7c74318620b1..47e9998b62f0 100644
--- a/drivers/net/ethernet/rdc/r6040.c
+++ b/drivers/net/ethernet/rdc/r6040.c
@@ -200,7 +200,7 @@ static int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg)
int limit = MAC_DEF_TIMEOUT;
u16 cmd;
- iowrite16(MDIO_READ + reg + (phy_addr << 8), ioaddr + MMDIO);
+ iowrite16(MDIO_READ | reg | (phy_addr << 8), ioaddr + MMDIO);
/* Wait for the read bit to be cleared */
while (limit--) {
cmd = ioread16(ioaddr + MMDIO);
@@ -224,7 +224,7 @@ static int r6040_phy_write(void __iomem *ioaddr,
iowrite16(val, ioaddr + MMWD);
/* Write the command to the MDIO bus */
- iowrite16(MDIO_WRITE + reg + (phy_addr << 8), ioaddr + MMDIO);
+ iowrite16(MDIO_WRITE | reg | (phy_addr << 8), ioaddr + MMDIO);
/* Wait for the write bit to be cleared */
while (limit--) {
cmd = ioread16(ioaddr + MMDIO);
@@ -544,7 +544,7 @@ static int r6040_rx(struct net_device *dev, int limit)
skb_ptr->dev = priv->dev;
/* Do not count the CRC */
- skb_put(skb_ptr, descptr->len - 4);
+ skb_put(skb_ptr, descptr->len - ETH_FCS_LEN);
dma_unmap_single(&priv->pdev->dev, le32_to_cpu(descptr->buf),
MAX_BUF_SIZE, DMA_FROM_DEVICE);
skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev);
@@ -552,7 +552,7 @@ static int r6040_rx(struct net_device *dev, int limit)
/* Send to upper layer */
netif_receive_skb(skb_ptr);
dev->stats.rx_packets++;
- dev->stats.rx_bytes += descptr->len - 4;
+ dev->stats.rx_bytes += descptr->len - ETH_FCS_LEN;
/* put new skb into descriptor */
descptr->skb_ptr = new_skb;
@@ -943,6 +943,7 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
+ .nway_reset = phy_ethtool_nway_reset,
};
static const struct net_device_ops r6040_netdev_ops = {
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index 4e44313b7651..9677e257e9a1 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -6,7 +6,7 @@
Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c]
Copyright 2001 Manfred Spraul [natsemi.c]
Copyright 1999-2001 by Donald Becker. [natsemi.c]
- Written 1997-2001 by Donald Becker. [8139too.c]
+ Written 1997-2001 by Donald Becker. [8139too.c]
Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>. [acenic.c]
This software may be used and distributed according to the terms of
@@ -947,8 +947,8 @@ static struct net_device_stats *cp_get_stats(struct net_device *dev)
/* The chip only need report frame silently dropped. */
spin_lock_irqsave(&cp->lock, flags);
- if (netif_running(dev) && netif_device_present(dev))
- __cp_get_stats(cp);
+ if (netif_running(dev) && netif_device_present(dev))
+ __cp_get_stats(cp);
spin_unlock_irqrestore(&cp->lock, flags);
return &dev->stats;
diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c
index 1e5a453dea14..f0608f050050 100644
--- a/drivers/net/ethernet/realtek/8139too.c
+++ b/drivers/net/ethernet/realtek/8139too.c
@@ -11,7 +11,7 @@
-----<snip>-----
- Written 1997-2001 by Donald Becker.
+ Written 1997-2001 by Donald Becker.
This software may be used and distributed according to the
terms of the GNU General Public License (GPL), incorporated
herein by reference. Drivers based on or derived from this
@@ -548,8 +548,8 @@ static const struct {
{ "RTL-8100",
HW_REVID(1, 1, 1, 1, 0, 1, 0),
- HasLWake,
- },
+ HasLWake,
+ },
{ "RTL-8100B/8139D",
HW_REVID(1, 1, 1, 0, 1, 0, 1),
diff --git a/drivers/net/ethernet/realtek/atp.c b/drivers/net/ethernet/realtek/atp.c
index 9e3b35c97e63..b6c849b258a0 100644
--- a/drivers/net/ethernet/realtek/atp.c
+++ b/drivers/net/ethernet/realtek/atp.c
@@ -497,8 +497,8 @@ static void write_packet(long ioaddr, int length, unsigned char *packet, int pad
{
if (length & 1)
{
- length++;
- pad_len++;
+ length++;
+ pad_len++;
}
outb(EOC+MAR, ioaddr + PAR_DATA);
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 2ee72dc431cd..f744557c33a3 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -34,8 +34,6 @@
#include "r8169.h"
#include "r8169_firmware.h"
-#define MODULENAME "r8169"
-
#define FIRMWARE_8168D_1 "rtl_nic/rtl8168d-1.fw"
#define FIRMWARE_8168D_2 "rtl_nic/rtl8168d-2.fw"
#define FIRMWARE_8168E_1 "rtl_nic/rtl8168e-1.fw"
@@ -1454,7 +1452,7 @@ static void rtl8169_get_drvinfo(struct net_device *dev,
struct rtl8169_private *tp = netdev_priv(dev);
struct rtl_fw *rtl_fw = tp->rtl_fw;
- strlcpy(info->driver, MODULENAME, sizeof(info->driver));
+ strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
strlcpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info));
BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version));
if (rtl_fw)
@@ -3510,7 +3508,6 @@ static void rtl_hw_start_8106(struct rtl8169_private *tp)
rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000);
rtl_pcie_state_l2l3_disable(tp);
- rtl_hw_aspm_clkreq_enable(tp, true);
}
DECLARE_RTL_COND(rtl_mac_ocp_e00e_cond)
@@ -4117,6 +4114,7 @@ static unsigned int rtl_quirk_packet_padto(struct rtl8169_private *tp,
case RTL_GIGA_MAC_VER_61:
case RTL_GIGA_MAC_VER_63:
padto = max_t(unsigned int, padto, ETH_ZLEN);
+ break;
default:
break;
}
@@ -5305,7 +5303,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return -ENODEV;
}
- rc = pcim_iomap_regions(pdev, BIT(region), MODULENAME);
+ rc = pcim_iomap_regions(pdev, BIT(region), KBUILD_MODNAME);
if (rc < 0) {
dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
return rc;
@@ -5440,7 +5438,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
static struct pci_driver rtl8169_pci_driver = {
- .name = MODULENAME,
+ .name = KBUILD_MODNAME,
.id_table = rtl8169_pci_tbl,
.probe = rtl_init_one,
.remove = rtl_remove_one,
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 4afff320dfd0..69c50f81e1cb 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -2047,13 +2047,6 @@ static int ravb_probe(struct platform_device *pdev)
return -EINVAL;
}
- /* Get base address */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "invalid resource\n");
- return -EINVAL;
- }
-
ndev = alloc_etherdev_mqs(sizeof(struct ravb_private),
NUM_TX_QUEUE, NUM_RX_QUEUE);
if (!ndev)
@@ -2065,9 +2058,6 @@ static int ravb_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
- /* The Ether-specific entries in the device structure. */
- ndev->base_addr = res->start;
-
chip_id = (enum ravb_chip_id)of_device_get_match_data(&pdev->dev);
if (chip_id == RCAR_GEN3)
@@ -2089,12 +2079,15 @@ static int ravb_probe(struct platform_device *pdev)
priv->num_rx_ring[RAVB_BE] = BE_RX_RING_SIZE;
priv->num_tx_ring[RAVB_NC] = NC_TX_RING_SIZE;
priv->num_rx_ring[RAVB_NC] = NC_RX_RING_SIZE;
- priv->addr = devm_ioremap_resource(&pdev->dev, res);
+ priv->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(priv->addr)) {
error = PTR_ERR(priv->addr);
goto out_release;
}
+ /* The Ether-specific entries in the device structure. */
+ ndev->base_addr = res->start;
+
spin_lock_init(&priv->lock);
INIT_WORK(&priv->work, ravb_tx_timeout_work);
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 713d3629b4c1..840478692a37 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -3225,9 +3225,6 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
struct net_device *ndev;
int ret;
- /* get base addr */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
ndev = alloc_etherdev(sizeof(struct sh_eth_private));
if (!ndev)
return -ENOMEM;
@@ -3245,7 +3242,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
mdp = netdev_priv(ndev);
mdp->num_tx_ring = TX_RING_SIZE;
mdp->num_rx_ring = RX_RING_SIZE;
- mdp->addr = devm_ioremap_resource(&pdev->dev, res);
+ mdp->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(mdp->addr)) {
ret = PTR_ERR(mdp->addr);
goto out_release;
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
index 971f1e54b652..090bcd2fb758 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
@@ -789,7 +789,7 @@ static void sxgbe_tx_queue_clean(struct sxgbe_tx_queue *tqueue)
}
/**
- * sxgbe_tx_clean:
+ * sxgbe_tx_all_clean:
* @priv: driver private structure
* Description: it reclaims resources after transmission completes.
*/
@@ -1015,7 +1015,7 @@ static void sxgbe_tx_timer(struct timer_list *t)
}
/**
- * sxgbe_init_tx_coalesce: init tx mitigation options.
+ * sxgbe_tx_init_coalesce: init tx mitigation options.
* @priv: driver private structure
* Description:
* This inits the transmit coalesce parameters: i.e. timer rate,
diff --git a/drivers/net/ethernet/seeq/ether3.c b/drivers/net/ethernet/seeq/ether3.c
index 65c98837ec45..16a4cbae9326 100644
--- a/drivers/net/ethernet/seeq/ether3.c
+++ b/drivers/net/ethernet/seeq/ether3.c
@@ -617,7 +617,7 @@ if (next_ptr < RX_START || next_ptr >= RX_END) {
break;
}
/*
- * ignore our own packets...
+ * ignore our own packets...
*/
if (!(*(unsigned long *)&dev->dev_addr[0] ^ *(unsigned long *)&addrs[2+6]) &&
!(*(unsigned short *)&dev->dev_addr[4] ^ *(unsigned short *)&addrs[2+10])) {
@@ -672,7 +672,7 @@ done:
*/
if (!(ether3_inw(REG_STATUS) & STAT_RXON)) {
dev->stats.rx_dropped++;
- ether3_outw(next_ptr, REG_RECVPTR);
+ ether3_outw(next_ptr, REG_RECVPTR);
ether3_outw(priv(dev)->regs.command | CMD_RXON, REG_COMMAND);
}
@@ -690,11 +690,11 @@ static void ether3_tx(struct net_device *dev)
do {
unsigned long status;
- /*
+ /*
* Read the packet header
- */
+ */
ether3_setbuffer(dev, buffer_read, tx_tail * 0x600);
- status = ether3_readlong(dev);
+ status = ether3_readlong(dev);
/*
* Check to see if this packet has been transmitted
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index c3f35da1b82a..e7e2223aebbf 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -370,9 +370,9 @@ static int efx_ef10_get_mac_address_vf(struct efx_nic *efx, u8 *mac_address)
return 0;
}
-static ssize_t efx_ef10_show_link_control_flag(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t link_control_flag_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct efx_nic *efx = dev_get_drvdata(dev);
@@ -382,9 +382,9 @@ static ssize_t efx_ef10_show_link_control_flag(struct device *dev,
? 1 : 0);
}
-static ssize_t efx_ef10_show_primary_flag(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t primary_flag_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct efx_nic *efx = dev_get_drvdata(dev);
@@ -519,9 +519,8 @@ static void efx_ef10_cleanup_vlans(struct efx_nic *efx)
mutex_unlock(&nic_data->vlan_lock);
}
-static DEVICE_ATTR(link_control_flag, 0444, efx_ef10_show_link_control_flag,
- NULL);
-static DEVICE_ATTR(primary_flag, 0444, efx_ef10_show_primary_flag, NULL);
+static DEVICE_ATTR_RO(link_control_flag);
+static DEVICE_ATTR_RO(primary_flag);
static int efx_ef10_probe(struct efx_nic *efx)
{
@@ -1070,7 +1069,8 @@ static int efx_ef10_probe_vf(struct efx_nic *efx)
/* If the parent PF has no VF data structure, it doesn't know about this
* VF so fail probe. The VF needs to be re-created. This can happen
- * if the PF driver is unloaded while the VF is assigned to a guest.
+ * if the PF driver was unloaded while any VF was assigned to a guest
+ * (using Xen, only).
*/
pci_dev_pf = efx->pci_dev->physfn;
if (pci_dev_pf) {
diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c
index 21fa6c0e8873..752d6406f07e 100644
--- a/drivers/net/ethernet/sfc/ef10_sriov.c
+++ b/drivers/net/ethernet/sfc/ef10_sriov.c
@@ -122,8 +122,7 @@ static void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx)
struct ef10_vf *vf = nic_data->vf + i;
/* If VF is assigned, do not free the vport */
- if (vf->pci_dev &&
- vf->pci_dev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
+ if (vf->pci_dev && pci_is_dev_assigned(vf->pci_dev))
continue;
if (vf->vport_assigned) {
@@ -207,9 +206,7 @@ static int efx_ef10_sriov_alloc_vf_vswitching(struct efx_nic *efx)
return 0;
fail:
- efx_ef10_sriov_free_vf_vports(efx);
- kfree(nic_data->vf);
- nic_data->vf = NULL;
+ efx_ef10_sriov_free_vf_vswitching(efx);
return rc;
}
@@ -402,12 +399,17 @@ fail1:
return rc;
}
+/* Disable SRIOV and remove VFs
+ * If some VFs are attached to a guest (using Xen, only) nothing is
+ * done if force=false, and vports are freed if force=true (for the non
+ * attachedc ones, only) but SRIOV is not disabled and VFs are not
+ * removed in either case.
+ */
static int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force)
{
struct pci_dev *dev = efx->pci_dev;
- unsigned int vfs_assigned = 0;
-
- vfs_assigned = pci_vfs_assigned(dev);
+ unsigned int vfs_assigned = pci_vfs_assigned(dev);
+ int rc = 0;
if (vfs_assigned && !force) {
netif_info(efx, drv, efx->net_dev, "VFs are assigned to guests; "
@@ -417,10 +419,12 @@ static int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force)
if (!vfs_assigned)
pci_disable_sriov(dev);
+ else
+ rc = -EBUSY;
efx_ef10_sriov_free_vf_vswitching(efx);
efx->vf_count = 0;
- return 0;
+ return rc;
}
int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs)
@@ -439,24 +443,18 @@ int efx_ef10_sriov_init(struct efx_nic *efx)
void efx_ef10_sriov_fini(struct efx_nic *efx)
{
struct efx_ef10_nic_data *nic_data = efx->nic_data;
- unsigned int i;
int rc;
if (!nic_data->vf) {
- /* Remove any un-assigned orphaned VFs */
+ /* Remove any un-assigned orphaned VFs. This can happen if the PF driver
+ * was unloaded while any VF was assigned to a guest (using Xen, only).
+ */
if (pci_num_vf(efx->pci_dev) && !pci_vfs_assigned(efx->pci_dev))
pci_disable_sriov(efx->pci_dev);
return;
}
- /* Remove any VFs in the host */
- for (i = 0; i < efx->vf_count; ++i) {
- struct efx_nic *vf_efx = nic_data->vf[i].efx;
-
- if (vf_efx)
- vf_efx->pci_dev->driver->remove(vf_efx->pci_dev);
- }
-
+ /* Disable SRIOV and remove any VFs in the host */
rc = efx_ef10_pci_sriov_disable(efx, true);
if (rc)
netif_dbg(efx, drv, efx->net_dev,
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index c746ca7235f1..37fcf2eb0741 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -689,13 +689,13 @@ static struct notifier_block efx_netdev_notifier = {
.notifier_call = efx_netdev_event,
};
-static ssize_t
-show_phy_type(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t phy_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct efx_nic *efx = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", efx->phy_type);
}
-static DEVICE_ATTR(phy_type, 0444, show_phy_type, NULL);
+static DEVICE_ATTR_RO(phy_type);
static int efx_register_netdev(struct efx_nic *efx)
{
@@ -722,8 +722,7 @@ static int efx_register_netdev(struct efx_nic *efx)
efx->state = STATE_READY;
smp_mb(); /* ensure we change state before checking reset_pending */
if (efx->reset_pending) {
- netif_err(efx, probe, efx->net_dev,
- "aborting probe due to scheduled reset\n");
+ pci_err(efx->pci_dev, "aborting probe due to scheduled reset\n");
rc = -EIO;
goto fail_locked;
}
@@ -990,8 +989,7 @@ static int efx_pci_probe_main(struct efx_nic *efx)
rc = efx->type->init(efx);
up_write(&efx->filter_sem);
if (rc) {
- netif_err(efx, probe, efx->net_dev,
- "failed to initialise NIC\n");
+ pci_err(efx->pci_dev, "failed to initialise NIC\n");
goto fail3;
}
@@ -1038,8 +1036,8 @@ static int efx_pci_probe_post_io(struct efx_nic *efx)
if (efx->type->sriov_init) {
rc = efx->type->sriov_init(efx);
if (rc)
- netif_err(efx, probe, efx->net_dev,
- "SR-IOV can't be enabled rc %d\n", rc);
+ pci_err(efx->pci_dev, "SR-IOV can't be enabled rc %d\n",
+ rc);
}
/* Determine netdevice features */
@@ -1106,8 +1104,7 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
if (rc)
goto fail1;
- netif_info(efx, probe, efx->net_dev,
- "Solarflare NIC detected\n");
+ pci_info(pci_dev, "Solarflare NIC detected\n");
if (!efx->type->is_vf)
efx_probe_vpd_strings(efx);
diff --git a/drivers/net/ethernet/sfc/efx_channels.c b/drivers/net/ethernet/sfc/efx_channels.c
index a3ca406a3561..e5b0d795c301 100644
--- a/drivers/net/ethernet/sfc/efx_channels.c
+++ b/drivers/net/ethernet/sfc/efx_channels.c
@@ -152,6 +152,7 @@ static int efx_allocate_msix_channels(struct efx_nic *efx,
* maximum size.
*/
tx_per_ev = EFX_MAX_EVQ_SIZE / EFX_TXQ_MAX_ENT(efx);
+ tx_per_ev = min(tx_per_ev, EFX_MAX_TXQ_PER_CHANNEL);
n_xdp_tx = num_possible_cpus();
n_xdp_ev = DIV_ROUND_UP(n_xdp_tx, tx_per_ev);
@@ -169,6 +170,8 @@ static int efx_allocate_msix_channels(struct efx_nic *efx,
netif_err(efx, drv, efx->net_dev,
"Insufficient resources for %d XDP event queues (%d other channels, max %d)\n",
n_xdp_ev, n_channels, max_channels);
+ netif_err(efx, drv, efx->net_dev,
+ "XDP_TX and XDP_REDIRECT will not work on this interface");
efx->n_xdp_channels = 0;
efx->xdp_tx_per_channel = 0;
efx->xdp_tx_queue_count = 0;
@@ -176,12 +179,14 @@ static int efx_allocate_msix_channels(struct efx_nic *efx,
netif_err(efx, drv, efx->net_dev,
"Insufficient resources for %d XDP TX queues (%d other channels, max VIs %d)\n",
n_xdp_tx, n_channels, efx->max_vis);
+ netif_err(efx, drv, efx->net_dev,
+ "XDP_TX and XDP_REDIRECT will not work on this interface");
efx->n_xdp_channels = 0;
efx->xdp_tx_per_channel = 0;
efx->xdp_tx_queue_count = 0;
} else {
efx->n_xdp_channels = n_xdp_ev;
- efx->xdp_tx_per_channel = EFX_MAX_TXQ_PER_CHANNEL;
+ efx->xdp_tx_per_channel = tx_per_ev;
efx->xdp_tx_queue_count = n_xdp_tx;
n_channels += n_xdp_ev;
netif_dbg(efx, drv, efx->net_dev,
@@ -891,18 +896,20 @@ int efx_set_channels(struct efx_nic *efx)
if (efx_channel_is_xdp_tx(channel)) {
efx_for_each_channel_tx_queue(tx_queue, channel) {
tx_queue->queue = next_queue++;
- netif_dbg(efx, drv, efx->net_dev, "Channel %u TXQ %u is XDP %u, HW %u\n",
- channel->channel, tx_queue->label,
- xdp_queue_number, tx_queue->queue);
+
/* We may have a few left-over XDP TX
* queues owing to xdp_tx_queue_count
* not dividing evenly by EFX_MAX_TXQ_PER_CHANNEL.
* We still allocate and probe those
* TXQs, but never use them.
*/
- if (xdp_queue_number < efx->xdp_tx_queue_count)
+ if (xdp_queue_number < efx->xdp_tx_queue_count) {
+ netif_dbg(efx, drv, efx->net_dev, "Channel %u TXQ %u is XDP %u, HW %u\n",
+ channel->channel, tx_queue->label,
+ xdp_queue_number, tx_queue->queue);
efx->xdp_tx_queues[xdp_queue_number] = tx_queue;
- xdp_queue_number++;
+ xdp_queue_number++;
+ }
}
} else {
efx_for_each_channel_tx_queue(tx_queue, channel) {
@@ -914,8 +921,7 @@ int efx_set_channels(struct efx_nic *efx)
}
}
}
- if (xdp_queue_number)
- efx->xdp_tx_queue_count = xdp_queue_number;
+ WARN_ON(xdp_queue_number != efx->xdp_tx_queue_count);
rc = netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels);
if (rc)
diff --git a/drivers/net/ethernet/sfc/efx_common.c b/drivers/net/ethernet/sfc/efx_common.c
index de797e1ac5a9..896b59253197 100644
--- a/drivers/net/ethernet/sfc/efx_common.c
+++ b/drivers/net/ethernet/sfc/efx_common.c
@@ -1160,8 +1160,9 @@ void efx_fini_io(struct efx_nic *efx)
}
#ifdef CONFIG_SFC_MCDI_LOGGING
-static ssize_t show_mcdi_log(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t mcdi_logging_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct efx_nic *efx = dev_get_drvdata(dev);
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
@@ -1169,8 +1170,9 @@ static ssize_t show_mcdi_log(struct device *dev, struct device_attribute *attr,
return scnprintf(buf, PAGE_SIZE, "%d\n", mcdi->logging_enabled);
}
-static ssize_t set_mcdi_log(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t mcdi_logging_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct efx_nic *efx = dev_get_drvdata(dev);
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
@@ -1180,7 +1182,7 @@ static ssize_t set_mcdi_log(struct device *dev, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(mcdi_logging, 0644, show_mcdi_log, set_mcdi_log);
+static DEVICE_ATTR_RW(mcdi_logging);
void efx_init_mcdi_logging(struct efx_nic *efx)
{
diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c
index 5e7a57b680ca..9ec752a43c75 100644
--- a/drivers/net/ethernet/sfc/falcon/efx.c
+++ b/drivers/net/ethernet/sfc/falcon/efx.c
@@ -2254,12 +2254,12 @@ static struct notifier_block ef4_netdev_notifier = {
};
static ssize_t
-show_phy_type(struct device *dev, struct device_attribute *attr, char *buf)
+phy_type_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct ef4_nic *efx = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", efx->phy_type);
}
-static DEVICE_ATTR(phy_type, 0444, show_phy_type, NULL);
+static DEVICE_ATTR_RO(phy_type);
static int ef4_register_netdev(struct ef4_nic *efx)
{
diff --git a/drivers/net/ethernet/sfc/falcon/falcon_boards.c b/drivers/net/ethernet/sfc/falcon/falcon_boards.c
index 729a05c1b0cf..2d2d8099011e 100644
--- a/drivers/net/ethernet/sfc/falcon/falcon_boards.c
+++ b/drivers/net/ethernet/sfc/falcon/falcon_boards.c
@@ -354,16 +354,16 @@ fail_on:
return rc;
}
-static ssize_t show_phy_flash_cfg(struct device *dev,
+static ssize_t phy_flash_cfg_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ef4_nic *efx = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL));
}
-static ssize_t set_phy_flash_cfg(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t phy_flash_cfg_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct ef4_nic *efx = dev_get_drvdata(dev);
enum ef4_phy_mode old_mode, new_mode;
@@ -396,7 +396,7 @@ static ssize_t set_phy_flash_cfg(struct device *dev,
return err ? err : count;
}
-static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg);
+static DEVICE_ATTR_RW(phy_flash_cfg);
static void sfe4001_fini(struct ef4_nic *efx)
{
diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c
index 49df02ecee91..148dcd48b58d 100644
--- a/drivers/net/ethernet/sfc/farch.c
+++ b/drivers/net/ethernet/sfc/farch.c
@@ -1668,13 +1668,17 @@ void efx_farch_rx_pull_indir_table(struct efx_nic *efx)
*/
void efx_farch_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw)
{
- unsigned vi_count, buftbl_min, total_tx_channels;
-
+ unsigned vi_count, total_tx_channels;
#ifdef CONFIG_SFC_SRIOV
- struct siena_nic_data *nic_data = efx->nic_data;
+ struct siena_nic_data *nic_data;
+ unsigned buftbl_min;
#endif
total_tx_channels = efx->n_tx_channels + efx->n_extra_tx_channels;
+ vi_count = max(efx->n_channels, total_tx_channels * EFX_MAX_TXQ_PER_CHANNEL);
+
+#ifdef CONFIG_SFC_SRIOV
+ nic_data = efx->nic_data;
/* Account for the buffer table entries backing the datapath channels
* and the descriptor caches for those channels.
*/
@@ -1682,9 +1686,6 @@ void efx_farch_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw)
total_tx_channels * EFX_MAX_TXQ_PER_CHANNEL * EFX_MAX_DMAQ_SIZE +
efx->n_channels * EFX_MAX_EVQ_SIZE)
* sizeof(efx_qword_t) / EFX_BUF_SIZE);
- vi_count = max(efx->n_channels, total_tx_channels * EFX_MAX_TXQ_PER_CHANNEL);
-
-#ifdef CONFIG_SFC_SRIOV
if (efx->type->sriov_wanted) {
if (efx->type->sriov_wanted(efx)) {
unsigned vi_dc_entries, buftbl_free;
diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c
index 17b8119c48e5..606750938b89 100644
--- a/drivers/net/ethernet/sfc/rx.c
+++ b/drivers/net/ethernet/sfc/rx.c
@@ -260,18 +260,14 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel,
s16 offset;
int err;
- rcu_read_lock();
- xdp_prog = rcu_dereference(efx->xdp_prog);
- if (!xdp_prog) {
- rcu_read_unlock();
+ xdp_prog = rcu_dereference_bh(efx->xdp_prog);
+ if (!xdp_prog)
return true;
- }
rx_queue = efx_channel_get_rx_queue(channel);
if (unlikely(channel->rx_pkt_n_frags > 1)) {
/* We can't do XDP on fragmented packets - drop. */
- rcu_read_unlock();
efx_free_rx_buffers(rx_queue, rx_buf,
channel->rx_pkt_n_frags);
if (net_ratelimit())
@@ -296,7 +292,6 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel,
rx_buf->len, false);
xdp_act = bpf_prog_run_xdp(xdp_prog, &xdp);
- rcu_read_unlock();
offset = (u8 *)xdp.data - *ehp;
diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c
index 6eef0f45b133..2b29fd4cbdf4 100644
--- a/drivers/net/ethernet/sgi/ioc3-eth.c
+++ b/drivers/net/ethernet/sgi/ioc3-eth.c
@@ -835,6 +835,10 @@ static int ioc3eth_probe(struct platform_device *pdev)
int err;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_err(&pdev->dev, "Invalid resource\n");
+ return -EINVAL;
+ }
/* get mac addr from one wire prom */
if (ioc3eth_get_mac_addr(regs, mac_addr))
return -EPROBE_DEFER; /* not available yet */
diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c
index 620c26f71be8..ca9c00b7f588 100644
--- a/drivers/net/ethernet/sis/sis900.c
+++ b/drivers/net/ethernet/sis/sis900.c
@@ -678,12 +678,12 @@ static int sis900_mii_probe(struct net_device *net_dev)
/* Reset phy if default phy is internal sis900 */
if ((sis_priv->mii->phy_id0 == 0x001D) &&
((sis_priv->mii->phy_id1&0xFFF0) == 0x8000))
- status = sis900_reset_phy(net_dev, sis_priv->cur_phy);
+ status = sis900_reset_phy(net_dev, sis_priv->cur_phy);
/* workaround for ICS1893 PHY */
if ((sis_priv->mii->phy_id0 == 0x0015) &&
((sis_priv->mii->phy_id1&0xFFF0) == 0xF440))
- mdio_write(net_dev, sis_priv->cur_phy, 0x0018, 0xD200);
+ mdio_write(net_dev, sis_priv->cur_phy, 0x0018, 0xD200);
if(status & MII_STAT_LINK){
while (poll_bit) {
@@ -727,7 +727,7 @@ static int sis900_mii_probe(struct net_device *net_dev)
static u16 sis900_default_phy(struct net_device * net_dev)
{
struct sis900_private *sis_priv = netdev_priv(net_dev);
- struct mii_phy *phy = NULL, *phy_home = NULL,
+ struct mii_phy *phy = NULL, *phy_home = NULL,
*default_phy = NULL, *phy_lan = NULL;
u16 status;
@@ -1339,18 +1339,18 @@ static void sis900_timer(struct timer_list *t)
} else {
/* Link ON -> OFF */
if (!(status & MII_STAT_LINK)){
- netif_carrier_off(net_dev);
+ netif_carrier_off(net_dev);
if(netif_msg_link(sis_priv))
- printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
+ printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
- /* Change mode issue */
- if ((mii_phy->phy_id0 == 0x001D) &&
- ((mii_phy->phy_id1 & 0xFFF0) == 0x8000))
- sis900_reset_phy(net_dev, sis_priv->cur_phy);
+ /* Change mode issue */
+ if ((mii_phy->phy_id0 == 0x001D) &&
+ ((mii_phy->phy_id1 & 0xFFF0) == 0x8000))
+ sis900_reset_phy(net_dev, sis_priv->cur_phy);
sis630_set_eq(net_dev, sis_priv->chipset_rev);
- goto LookForLink;
+ goto LookForLink;
}
}
@@ -2331,7 +2331,7 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map)
case IF_PORT_10BASE2: /* 10Base2 */
case IF_PORT_AUI: /* AUI */
case IF_PORT_100BASEFX: /* 100BaseFx */
- /* These Modes are not supported (are they?)*/
+ /* These Modes are not supported (are they?)*/
return -EOPNOTSUPP;
default:
diff --git a/drivers/net/ethernet/smsc/smc9194.c b/drivers/net/ethernet/smsc/smc9194.c
index 4b2330deed47..bf7c8c8b1350 100644
--- a/drivers/net/ethernet/smsc/smc9194.c
+++ b/drivers/net/ethernet/smsc/smc9194.c
@@ -182,8 +182,8 @@ struct smc_local {
struct sk_buff * saved_skb;
/*
- . This keeps track of how many packets that I have
- . sent out. When an TX_EMPTY interrupt comes, I know
+ . This keeps track of how many packets that I have
+ . sent out. When an TX_EMPTY interrupt comes, I know
. that all of these have been sent.
*/
int packets_waiting;
@@ -343,7 +343,7 @@ static void smc_reset( int ioaddr )
/* Note: It doesn't seem that waiting for the MMU busy is needed here,
but this is a place where future chipsets _COULD_ break. Be wary
- of issuing another MMU command right after this */
+ of issuing another MMU command right after this */
outb( 0, ioaddr + INT_MASK );
}
@@ -521,9 +521,9 @@ static netdev_tx_t smc_wait_to_send_packet(struct sk_buff *skb,
SMC_SELECT_BANK( 2 );
outw( MC_ALLOC | numPages, ioaddr + MMU_CMD );
/*
- . Performance Hack
+ . Performance Hack
.
- . wait a short amount of time.. if I can send a packet now, I send
+ . wait a short amount of time.. if I can send a packet now, I send
. it now. Otherwise, I enable an interrupt and wait for one to be
. available.
.
@@ -540,17 +540,17 @@ static netdev_tx_t smc_wait_to_send_packet(struct sk_buff *skb,
if ( status & IM_ALLOC_INT ) {
/* acknowledge the interrupt */
outb( IM_ALLOC_INT, ioaddr + INTERRUPT );
- break;
+ break;
}
- } while ( -- time_out );
+ } while ( -- time_out );
- if ( !time_out ) {
+ if ( !time_out ) {
/* oh well, wait until the chip finds memory later */
SMC_ENABLE_INT( IM_ALLOC_INT );
PRINTK2((CARDNAME": memory allocation deferred.\n"));
/* it's deferred, but I'll handle it later */
return NETDEV_TX_OK;
- }
+ }
/* or YES! I can send the packet now.. */
smc_hardware_send_packet(dev);
netif_wake_queue(dev);
@@ -616,7 +616,7 @@ static void smc_hardware_send_packet( struct net_device * dev )
#endif
/* send the packet length ( +6 for status, length and ctl byte )
- and the status word ( set to zeros ) */
+ and the status word ( set to zeros ) */
#ifdef USE_32_BIT
outl( (length +6 ) << 16 , ioaddr + DATA_1 );
#else
@@ -629,8 +629,8 @@ static void smc_hardware_send_packet( struct net_device * dev )
/* send the actual data
. I _think_ it's faster to send the longs first, and then
. mop up by sending the last word. It depends heavily
- . on alignment, at least on the 486. Maybe it would be
- . a good idea to check which is optimal? But that could take
+ . on alignment, at least on the 486. Maybe it would be
+ . a good idea to check which is optimal? But that could take
. almost as much time as is saved?
*/
#ifdef USE_32_BIT
@@ -757,7 +757,7 @@ static int __init smc_findirq(int ioaddr)
outb( IM_ALLOC_INT, ioaddr + INT_MASK );
/*
- . Allocate 512 bytes of memory. Note that the chip was just
+ . Allocate 512 bytes of memory. Note that the chip was just
. reset so all the memory is available
*/
outw( MC_ALLOC | 1, ioaddr + MMU_CMD );
@@ -871,7 +871,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
goto err_out;
}
/* The above MIGHT indicate a device, but I need to write to further
- test this. */
+ test this. */
outw( 0x0, ioaddr + BANK_SELECT );
bank = inw( ioaddr + BANK_SELECT );
if ( (bank & 0xFF00 ) != 0x3300 ) {
@@ -879,7 +879,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
goto err_out;
}
/* well, we've already written once, so hopefully another time won't
- hurt. This time, I need to switch the bank register to bank 1,
+ hurt. This time, I need to switch the bank register to bank 1,
so I can access the base address register */
SMC_SELECT_BANK(1);
base_address_register = inw( ioaddr + BASE );
@@ -917,7 +917,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
dev->base_addr = ioaddr;
/*
- . Get the MAC address ( bank 1, regs 4 - 9 )
+ . Get the MAC address ( bank 1, regs 4 - 9 )
*/
SMC_SELECT_BANK( 1 );
for ( i = 0; i < 6; i += 2 ) {
@@ -938,8 +938,8 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
/*
Now, I want to find out more about the chip. This is sort of
- redundant, but it's cleaner to have it in both, rather than having
- one VERY long probe procedure.
+ redundant, but it's cleaner to have it in both, rather than having
+ one VERY long probe procedure.
*/
SMC_SELECT_BANK(3);
revision_register = inw( ioaddr + REVISION );
@@ -967,7 +967,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
/*
. If dev->irq is 0, then the device has to be banged on to see
. what the IRQ is.
- .
+ .
. This banging doesn't always detect the IRQ, for unknown reasons.
. a workaround is to reset the chip and try again.
.
@@ -978,7 +978,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
.
. Specifying an IRQ is done with the assumption that the user knows
. what (s)he is doing. No checking is done!!!!
- .
+ .
*/
if ( dev->irq < 2 ) {
int trials;
@@ -1070,7 +1070,7 @@ static int smc_open(struct net_device *dev)
}
/*
- According to Becker, I have to set the hardware address
+ According to Becker, I have to set the hardware address
at this point, because the (l)user can set it with an
ioctl. Easily done...
*/
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index cbde83f620a0..813ea941b91a 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -671,19 +671,19 @@ smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
status = SMC_GET_INT(lp);
if (status & IM_ALLOC_INT) {
SMC_ACK_INT(lp, IM_ALLOC_INT);
- break;
+ break;
}
- } while (--poll_count);
+ } while (--poll_count);
smc_special_unlock(&lp->lock, flags);
lp->pending_tx_skb = skb;
- if (!poll_count) {
+ if (!poll_count) {
/* oh well, wait until the chip finds memory later */
netif_stop_queue(dev);
DBG(2, dev, "TX memory allocation deferred.\n");
SMC_ENABLE_INT(lp, IM_ALLOC_INT);
- } else {
+ } else {
/*
* Allocation succeeded: push packet to the chip's own memory
* immediately.
@@ -1790,7 +1790,7 @@ static int smc_findirq(struct smc_local *lp)
SMC_SET_INT_MASK(lp, IM_ALLOC_INT);
/*
- * Allocate 512 bytes of memory. Note that the chip was just
+ * Allocate 512 bytes of memory. Note that the chip was just
* reset so all the memory is available
*/
SMC_SET_MMU_CMD(lp, MC_ALLOC | 1);
@@ -1998,8 +1998,8 @@ static int smc_probe(struct net_device *dev, void __iomem *ioaddr,
/* Grab the IRQ */
retval = request_irq(dev->irq, smc_interrupt, irq_flags, dev->name, dev);
- if (retval)
- goto err_out;
+ if (retval)
+ goto err_out;
#ifdef CONFIG_ARCH_PXA
# ifdef SMC_USE_PXA_DMA
diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c
index dfc85cc68173..20d148c019d8 100644
--- a/drivers/net/ethernet/socionext/netsec.c
+++ b/drivers/net/ethernet/socionext/netsec.c
@@ -958,7 +958,6 @@ static int netsec_process_rx(struct netsec_priv *priv, int budget)
xdp_init_buff(&xdp, PAGE_SIZE, &dring->xdp_rxq);
- rcu_read_lock();
xdp_prog = READ_ONCE(priv->xdp_prog);
dma_dir = page_pool_get_dma_dir(dring->page_pool);
@@ -1069,8 +1068,6 @@ next:
}
netsec_finalize_xdp_rx(priv, xdp_act, xdp_xmit);
- rcu_read_unlock();
-
return done;
}
diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c
index fcbb4bb31408..5eb6bb4f7b6c 100644
--- a/drivers/net/ethernet/socionext/sni_ave.c
+++ b/drivers/net/ethernet/socionext/sni_ave.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* sni_ave.c - Socionext UniPhier AVE ethernet driver
* Copyright 2014 Panasonic Corporation
* Copyright 2015-2017 Socionext Inc.
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 7737e4d0bb9e..ac3c248d4f9b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -66,6 +66,18 @@ config DWMAC_ANARION
This selects the Anarion SoC glue layer support for the stmmac driver.
+config DWMAC_INGENIC
+ tristate "Ingenic MAC support"
+ default MACH_INGENIC
+ depends on OF && HAS_IOMEM && (MACH_INGENIC || COMPILE_TEST)
+ select MFD_SYSCON
+ help
+ Support for ethernet controller on Ingenic SoCs.
+
+ This selects Ingenic SoCs glue layer support for the stmmac
+ device driver. This driver is used on for the Ingenic SoCs
+ MAC ethernet controller.
+
config DWMAC_IPQ806X
tristate "QCA IPQ806x DWMAC support"
default ARCH_QCOM
@@ -238,6 +250,15 @@ config DWMAC_INTEL
This selects the Intel platform specific bus support for the
stmmac driver. This driver is used for Intel Quark/EHL/TGL.
+config DWMAC_LOONGSON
+ tristate "Loongson PCI DWMAC support"
+ default MACH_LOONGSON64
+ depends on STMMAC_ETH && PCI
+ depends on COMMON_CLK
+ help
+ This selects the LOONGSON PCI bus support for the stmmac driver,
+ Support for ethernet controller on Loongson-2K1000 SoC and LS7A1000 bridge.
+
config STMMAC_PCI
tristate "STMMAC PCI bus support"
depends on STMMAC_ETH && PCI
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index f2e478b884b0..d4e12e9ace4f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -14,6 +14,7 @@ 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
+obj-$(CONFIG_DWMAC_INGENIC) += dwmac-ingenic.o
obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o
obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o
obj-$(CONFIG_DWMAC_MEDIATEK) += dwmac-mediatek.o
@@ -36,4 +37,5 @@ dwmac-altr-socfpga-objs := altr_tse_pcs.o dwmac-socfpga.o
obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
obj-$(CONFIG_DWMAC_INTEL) += dwmac-intel.o
+obj-$(CONFIG_DWMAC_LOONGSON) += dwmac-loongson.o
stmmac-pci-objs:= stmmac_pci.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 619e3c0760d6..5fecc83f175b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -503,8 +503,7 @@ struct mac_device_info {
const struct stmmac_hwtimestamp *ptp;
const struct stmmac_tc_ops *tc;
const struct stmmac_mmc_ops *mmc;
- const struct mdio_xpcs_ops *xpcs;
- struct mdio_xpcs_args xpcs_args;
+ struct dw_xpcs *xpcs;
struct mii_regs mii; /* MII register Addresses */
struct mac_link link;
void __iomem *pcsr; /* vpointer to device CSRs */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c
new file mode 100644
index 000000000000..9a6d819b84ae
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c
@@ -0,0 +1,398 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * dwmac-ingenic.c - Ingenic SoCs DWMAC specific glue layer
+ *
+ * Copyright (c) 2021 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_net.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/stmmac.h>
+
+#include "stmmac_platform.h"
+
+#define MACPHYC_TXCLK_SEL_MASK GENMASK(31, 31)
+#define MACPHYC_TXCLK_SEL_OUTPUT 0x1
+#define MACPHYC_TXCLK_SEL_INPUT 0x0
+#define MACPHYC_MODE_SEL_MASK GENMASK(31, 31)
+#define MACPHYC_MODE_SEL_RMII 0x0
+#define MACPHYC_TX_SEL_MASK GENMASK(19, 19)
+#define MACPHYC_TX_SEL_ORIGIN 0x0
+#define MACPHYC_TX_SEL_DELAY 0x1
+#define MACPHYC_TX_DELAY_MASK GENMASK(18, 12)
+#define MACPHYC_RX_SEL_MASK GENMASK(11, 11)
+#define MACPHYC_RX_SEL_ORIGIN 0x0
+#define MACPHYC_RX_SEL_DELAY 0x1
+#define MACPHYC_RX_DELAY_MASK GENMASK(10, 4)
+#define MACPHYC_SOFT_RST_MASK GENMASK(3, 3)
+#define MACPHYC_PHY_INFT_MASK GENMASK(2, 0)
+#define MACPHYC_PHY_INFT_RMII 0x4
+#define MACPHYC_PHY_INFT_RGMII 0x1
+#define MACPHYC_PHY_INFT_GMII 0x0
+#define MACPHYC_PHY_INFT_MII 0x0
+
+#define MACPHYC_TX_DELAY_PS_MAX 2496
+#define MACPHYC_TX_DELAY_PS_MIN 20
+
+#define MACPHYC_RX_DELAY_PS_MAX 2496
+#define MACPHYC_RX_DELAY_PS_MIN 20
+
+enum ingenic_mac_version {
+ ID_JZ4775,
+ ID_X1000,
+ ID_X1600,
+ ID_X1830,
+ ID_X2000,
+};
+
+struct ingenic_mac {
+ const struct ingenic_soc_info *soc_info;
+ struct device *dev;
+ struct regmap *regmap;
+
+ int rx_delay;
+ int tx_delay;
+};
+
+struct ingenic_soc_info {
+ enum ingenic_mac_version version;
+ u32 mask;
+
+ int (*set_mode)(struct plat_stmmacenet_data *plat_dat);
+};
+
+static int ingenic_mac_init(struct plat_stmmacenet_data *plat_dat)
+{
+ struct ingenic_mac *mac = plat_dat->bsp_priv;
+ int ret;
+
+ if (mac->soc_info->set_mode) {
+ ret = mac->soc_info->set_mode(plat_dat);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int jz4775_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
+{
+ struct ingenic_mac *mac = plat_dat->bsp_priv;
+ unsigned int val;
+
+ switch (plat_dat->interface) {
+ case PHY_INTERFACE_MODE_MII:
+ val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |
+ FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_MII);
+ dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_MII\n");
+ break;
+
+ case PHY_INTERFACE_MODE_GMII:
+ val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |
+ FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_GMII);
+ dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_GMII\n");
+ break;
+
+ case PHY_INTERFACE_MODE_RMII:
+ val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |
+ FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);
+ dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
+ break;
+
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |
+ FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RGMII);
+ dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RGMII\n");
+ break;
+
+ default:
+ dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
+ return -EINVAL;
+ }
+
+ /* Update MAC PHY control register */
+ return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
+}
+
+static int x1000_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
+{
+ struct ingenic_mac *mac = plat_dat->bsp_priv;
+
+ switch (plat_dat->interface) {
+ case PHY_INTERFACE_MODE_RMII:
+ dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
+ break;
+
+ default:
+ dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
+ return -EINVAL;
+ }
+
+ /* Update MAC PHY control register */
+ return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, 0);
+}
+
+static int x1600_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
+{
+ struct ingenic_mac *mac = plat_dat->bsp_priv;
+ unsigned int val;
+
+ switch (plat_dat->interface) {
+ case PHY_INTERFACE_MODE_RMII:
+ val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);
+ dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
+ break;
+
+ default:
+ dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
+ return -EINVAL;
+ }
+
+ /* Update MAC PHY control register */
+ return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
+}
+
+static int x1830_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
+{
+ struct ingenic_mac *mac = plat_dat->bsp_priv;
+ unsigned int val;
+
+ switch (plat_dat->interface) {
+ case PHY_INTERFACE_MODE_RMII:
+ val = FIELD_PREP(MACPHYC_MODE_SEL_MASK, MACPHYC_MODE_SEL_RMII) |
+ FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);
+ dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
+ break;
+
+ default:
+ dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
+ return -EINVAL;
+ }
+
+ /* Update MAC PHY control register */
+ return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
+}
+
+static int x2000_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
+{
+ struct ingenic_mac *mac = plat_dat->bsp_priv;
+ unsigned int val;
+
+ switch (plat_dat->interface) {
+ case PHY_INTERFACE_MODE_RMII:
+ val = FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN) |
+ FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN) |
+ FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);
+ dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
+ break;
+
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RGMII);
+
+ if (mac->tx_delay == 0)
+ val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN);
+ else
+ val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_DELAY) |
+ FIELD_PREP(MACPHYC_TX_DELAY_MASK, (mac->tx_delay + 9750) / 19500 - 1);
+
+ if (mac->rx_delay == 0)
+ val |= FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN);
+ else
+ val |= FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_DELAY) |
+ FIELD_PREP(MACPHYC_RX_DELAY_MASK, (mac->rx_delay + 9750) / 19500 - 1);
+
+ dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RGMII\n");
+ break;
+
+ default:
+ dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
+ return -EINVAL;
+ }
+
+ /* Update MAC PHY control register */
+ return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
+}
+
+static int ingenic_mac_probe(struct platform_device *pdev)
+{
+ struct plat_stmmacenet_data *plat_dat;
+ struct stmmac_resources stmmac_res;
+ struct ingenic_mac *mac;
+ const struct ingenic_soc_info *data;
+ u32 tx_delay_ps, rx_delay_ps;
+ int ret;
+
+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
+ if (ret)
+ return ret;
+
+ plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
+ if (IS_ERR(plat_dat))
+ return PTR_ERR(plat_dat);
+
+ mac = devm_kzalloc(&pdev->dev, sizeof(*mac), GFP_KERNEL);
+ if (!mac) {
+ ret = -ENOMEM;
+ goto err_remove_config_dt;
+ }
+
+ data = of_device_get_match_data(&pdev->dev);
+ if (!data) {
+ dev_err(&pdev->dev, "No of match data provided\n");
+ ret = -EINVAL;
+ goto err_remove_config_dt;
+ }
+
+ /* Get MAC PHY control register */
+ mac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "mode-reg");
+ if (IS_ERR(mac->regmap)) {
+ dev_err(&pdev->dev, "%s: Failed to get syscon regmap\n", __func__);
+ ret = PTR_ERR(mac->regmap);
+ goto err_remove_config_dt;
+ }
+
+ if (!of_property_read_u32(pdev->dev.of_node, "tx-clk-delay-ps", &tx_delay_ps)) {
+ if (tx_delay_ps >= MACPHYC_TX_DELAY_PS_MIN &&
+ tx_delay_ps <= MACPHYC_TX_DELAY_PS_MAX) {
+ mac->tx_delay = tx_delay_ps * 1000;
+ } else {
+ dev_err(&pdev->dev, "Invalid TX clock delay: %dps\n", tx_delay_ps);
+ return -EINVAL;
+ }
+ }
+
+ if (!of_property_read_u32(pdev->dev.of_node, "rx-clk-delay-ps", &rx_delay_ps)) {
+ if (rx_delay_ps >= MACPHYC_RX_DELAY_PS_MIN &&
+ rx_delay_ps <= MACPHYC_RX_DELAY_PS_MAX) {
+ mac->rx_delay = rx_delay_ps * 1000;
+ } else {
+ dev_err(&pdev->dev, "Invalid RX clock delay: %dps\n", rx_delay_ps);
+ return -EINVAL;
+ }
+ }
+
+ mac->soc_info = data;
+ mac->dev = &pdev->dev;
+
+ plat_dat->bsp_priv = mac;
+
+ ret = ingenic_mac_init(plat_dat);
+ if (ret)
+ goto err_remove_config_dt;
+
+ ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+ if (ret)
+ goto err_remove_config_dt;
+
+ return 0;
+
+err_remove_config_dt:
+ stmmac_remove_config_dt(pdev, plat_dat);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ingenic_mac_suspend(struct device *dev)
+{
+ int ret;
+
+ ret = stmmac_suspend(dev);
+
+ return ret;
+}
+
+static int ingenic_mac_resume(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ int ret;
+
+ ret = ingenic_mac_init(priv->plat);
+ if (ret)
+ return ret;
+
+ ret = stmmac_resume(dev);
+
+ return ret;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(ingenic_mac_pm_ops, ingenic_mac_suspend, ingenic_mac_resume);
+
+static struct ingenic_soc_info jz4775_soc_info = {
+ .version = ID_JZ4775,
+ .mask = MACPHYC_TXCLK_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
+
+ .set_mode = jz4775_mac_set_mode,
+};
+
+static struct ingenic_soc_info x1000_soc_info = {
+ .version = ID_X1000,
+ .mask = MACPHYC_SOFT_RST_MASK,
+
+ .set_mode = x1000_mac_set_mode,
+};
+
+static struct ingenic_soc_info x1600_soc_info = {
+ .version = ID_X1600,
+ .mask = MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
+
+ .set_mode = x1600_mac_set_mode,
+};
+
+static struct ingenic_soc_info x1830_soc_info = {
+ .version = ID_X1830,
+ .mask = MACPHYC_MODE_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
+
+ .set_mode = x1830_mac_set_mode,
+};
+
+static struct ingenic_soc_info x2000_soc_info = {
+ .version = ID_X2000,
+ .mask = MACPHYC_TX_SEL_MASK | MACPHYC_TX_DELAY_MASK | MACPHYC_RX_SEL_MASK |
+ MACPHYC_RX_DELAY_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
+
+ .set_mode = x2000_mac_set_mode,
+};
+
+static const struct of_device_id ingenic_mac_of_matches[] = {
+ { .compatible = "ingenic,jz4775-mac", .data = &jz4775_soc_info },
+ { .compatible = "ingenic,x1000-mac", .data = &x1000_soc_info },
+ { .compatible = "ingenic,x1600-mac", .data = &x1600_soc_info },
+ { .compatible = "ingenic,x1830-mac", .data = &x1830_soc_info },
+ { .compatible = "ingenic,x2000-mac", .data = &x2000_soc_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ingenic_mac_of_matches);
+
+static struct platform_driver ingenic_mac_driver = {
+ .probe = ingenic_mac_probe,
+ .remove = stmmac_pltfr_remove,
+ .driver = {
+ .name = "ingenic-mac",
+ .pm = pm_ptr(&ingenic_mac_pm_ops),
+ .of_match_table = ingenic_mac_of_matches,
+ },
+};
+module_platform_driver(ingenic_mac_driver);
+
+MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>");
+MODULE_DESCRIPTION("Ingenic SoCs DWMAC specific glue layer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
index 80728a4c0e3f..8e8778cfbbad 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
@@ -10,22 +10,6 @@
#include "stmmac.h"
#include "stmmac_ptp.h"
-#define INTEL_MGBE_ADHOC_ADDR 0x15
-#define INTEL_MGBE_XPCS_ADDR 0x16
-
-/* Selection for PTP Clock Freq belongs to PSE & PCH GbE */
-#define PSE_PTP_CLK_FREQ_MASK (GMAC_GPO0 | GMAC_GPO3)
-#define PSE_PTP_CLK_FREQ_19_2MHZ (GMAC_GPO0)
-#define PSE_PTP_CLK_FREQ_200MHZ (GMAC_GPO0 | GMAC_GPO3)
-#define PSE_PTP_CLK_FREQ_256MHZ (0)
-#define PCH_PTP_CLK_FREQ_MASK (GMAC_GPO0)
-#define PCH_PTP_CLK_FREQ_19_2MHZ (GMAC_GPO0)
-#define PCH_PTP_CLK_FREQ_200MHZ (0)
-
-/* Cross-timestamping defines */
-#define ART_CPUID_LEAF 0x15
-#define EHL_PSE_ART_MHZ 19200000
-
struct intel_priv_data {
int mdio_adhoc_addr; /* mdio address for serdes & etc */
unsigned long crossts_adj;
@@ -102,6 +86,22 @@ static int intel_serdes_powerup(struct net_device *ndev, void *priv_data)
serdes_phy_addr = intel_priv->mdio_adhoc_addr;
+ /* Set the serdes rate and the PCLK rate */
+ data = mdiobus_read(priv->mii, serdes_phy_addr,
+ SERDES_GCR0);
+
+ data &= ~SERDES_RATE_MASK;
+ data &= ~SERDES_PCLK_MASK;
+
+ if (priv->plat->max_speed == 2500)
+ data |= SERDES_RATE_PCIE_GEN2 << SERDES_RATE_PCIE_SHIFT |
+ SERDES_PCLK_37p5MHZ << SERDES_PCLK_SHIFT;
+ else
+ data |= SERDES_RATE_PCIE_GEN1 << SERDES_RATE_PCIE_SHIFT |
+ SERDES_PCLK_70MHZ << SERDES_PCLK_SHIFT;
+
+ mdiobus_write(priv->mii, serdes_phy_addr, SERDES_GCR0, data);
+
/* assert clk_req */
data = mdiobus_read(priv->mii, serdes_phy_addr, SERDES_GCR0);
data |= SERDES_PLL_CLK;
@@ -230,6 +230,32 @@ static void intel_serdes_powerdown(struct net_device *ndev, void *intel_data)
}
}
+static void intel_speed_mode_2500(struct net_device *ndev, void *intel_data)
+{
+ struct intel_priv_data *intel_priv = intel_data;
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ int serdes_phy_addr = 0;
+ u32 data = 0;
+
+ serdes_phy_addr = intel_priv->mdio_adhoc_addr;
+
+ /* Determine the link speed mode: 2.5Gbps/1Gbps */
+ data = mdiobus_read(priv->mii, serdes_phy_addr,
+ SERDES_GCR);
+
+ if (((data & SERDES_LINK_MODE_MASK) >> SERDES_LINK_MODE_SHIFT) ==
+ SERDES_LINK_MODE_2G5) {
+ dev_info(priv->device, "Link Speed Mode: 2.5Gbps\n");
+ priv->plat->max_speed = 2500;
+ priv->plat->phy_interface = PHY_INTERFACE_MODE_2500BASEX;
+ priv->plat->mdio_bus_data->xpcs_an_inband = false;
+ } else {
+ priv->plat->max_speed = 1000;
+ priv->plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
+ priv->plat->mdio_bus_data->xpcs_an_inband = true;
+ }
+}
+
/* Program PTP Clock Frequency for different variant of
* Intel mGBE that has slightly different GPO mapping
*/
@@ -429,6 +455,17 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
plat->force_sf_dma_mode = 0;
plat->tso_en = 1;
+ /* Multiplying factor to the clk_eee_i clock time
+ * period to make it closer to 100 ns. This value
+ * should be programmed such that the clk_eee_time_period *
+ * (MULT_FACT_100NS + 1) should be within 80 ns to 120 ns
+ * clk_eee frequency is 19.2Mhz
+ * clk_eee_time_period is 52ns
+ * 52ns * (1 + 1) = 104ns
+ * MULT_FACT_100NS = 1
+ */
+ plat->mult_fact_100ns = 1;
+
plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
for (i = 0; i < plat->rx_queues_to_use; i++) {
@@ -556,6 +593,17 @@ static int ehl_common_data(struct pci_dev *pdev,
plat->rx_queues_to_use = 8;
plat->tx_queues_to_use = 8;
plat->clk_ptp_rate = 200000000;
+ plat->use_phy_wol = 1;
+
+ plat->safety_feat_cfg->tsoee = 1;
+ plat->safety_feat_cfg->mrxpee = 1;
+ plat->safety_feat_cfg->mestee = 1;
+ plat->safety_feat_cfg->mrxee = 1;
+ plat->safety_feat_cfg->mtxee = 1;
+ plat->safety_feat_cfg->epsi = 0;
+ plat->safety_feat_cfg->edpp = 0;
+ plat->safety_feat_cfg->prtyen = 0;
+ plat->safety_feat_cfg->tmouten = 0;
return intel_mgbe_common_data(pdev, plat);
}
@@ -565,7 +613,7 @@ static int ehl_sgmii_data(struct pci_dev *pdev,
{
plat->bus_id = 1;
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
-
+ plat->speed_mode_2500 = intel_speed_mode_2500;
plat->serdes_powerup = intel_serdes_powerup;
plat->serdes_powerdown = intel_serdes_powerdown;
@@ -618,6 +666,7 @@ static int ehl_pse0_sgmii1g_data(struct pci_dev *pdev,
struct plat_stmmacenet_data *plat)
{
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
+ plat->speed_mode_2500 = intel_speed_mode_2500;
plat->serdes_powerup = intel_serdes_powerup;
plat->serdes_powerdown = intel_serdes_powerdown;
return ehl_pse0_common_data(pdev, plat);
@@ -656,6 +705,7 @@ static int ehl_pse1_sgmii1g_data(struct pci_dev *pdev,
struct plat_stmmacenet_data *plat)
{
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
+ plat->speed_mode_2500 = intel_speed_mode_2500;
plat->serdes_powerup = intel_serdes_powerup;
plat->serdes_powerdown = intel_serdes_powerdown;
return ehl_pse1_common_data(pdev, plat);
@@ -672,6 +722,16 @@ static int tgl_common_data(struct pci_dev *pdev,
plat->tx_queues_to_use = 4;
plat->clk_ptp_rate = 200000000;
+ plat->safety_feat_cfg->tsoee = 1;
+ plat->safety_feat_cfg->mrxpee = 0;
+ plat->safety_feat_cfg->mestee = 1;
+ plat->safety_feat_cfg->mrxee = 1;
+ plat->safety_feat_cfg->mtxee = 1;
+ plat->safety_feat_cfg->epsi = 0;
+ plat->safety_feat_cfg->edpp = 0;
+ plat->safety_feat_cfg->prtyen = 0;
+ plat->safety_feat_cfg->tmouten = 0;
+
return intel_mgbe_common_data(pdev, plat);
}
@@ -680,6 +740,7 @@ static int tgl_sgmii_phy0_data(struct pci_dev *pdev,
{
plat->bus_id = 1;
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
+ plat->speed_mode_2500 = intel_speed_mode_2500;
plat->serdes_powerup = intel_serdes_powerup;
plat->serdes_powerdown = intel_serdes_powerdown;
return tgl_common_data(pdev, plat);
@@ -694,6 +755,7 @@ static int tgl_sgmii_phy1_data(struct pci_dev *pdev,
{
plat->bus_id = 2;
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
+ plat->speed_mode_2500 = intel_speed_mode_2500;
plat->serdes_powerup = intel_serdes_powerup;
plat->serdes_powerdown = intel_serdes_powerdown;
return tgl_common_data(pdev, plat);
@@ -948,6 +1010,12 @@ static int intel_eth_pci_probe(struct pci_dev *pdev,
if (!plat->dma_cfg)
return -ENOMEM;
+ plat->safety_feat_cfg = devm_kzalloc(&pdev->dev,
+ sizeof(*plat->safety_feat_cfg),
+ GFP_KERNEL);
+ if (!plat->safety_feat_cfg)
+ return -ENOMEM;
+
/* Enable pci device */
ret = pcim_enable_device(pdev);
if (ret) {
@@ -1020,7 +1088,7 @@ err_alloc_irq:
/**
* intel_eth_pci_remove
*
- * @pdev: platform device pointer
+ * @pdev: pci device pointer
* Description: this function calls the main to free the net resources
* and releases the PCI resources.
*/
@@ -1050,6 +1118,7 @@ static int __maybe_unused intel_eth_pci_suspend(struct device *dev)
return ret;
pci_wake_from_d3(pdev, true);
+ pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
index 542acb8ce467..0a37987478c1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
@@ -9,6 +9,7 @@
#define POLL_DELAY_US 8
/* SERDES Register */
+#define SERDES_GCR 0x0 /* Global Conguration */
#define SERDES_GSR0 0x5 /* Global Status Reg0 */
#define SERDES_GCR0 0xb /* Global Configuration Reg0 */
@@ -17,8 +18,36 @@
#define SERDES_PHY_RX_CLK BIT(1) /* PSE SGMII PHY rx clk */
#define SERDES_RST BIT(2) /* Serdes Reset */
#define SERDES_PWR_ST_MASK GENMASK(6, 4) /* Serdes Power state*/
+#define SERDES_RATE_MASK GENMASK(9, 8)
+#define SERDES_PCLK_MASK GENMASK(14, 12) /* PCLK rate to PHY */
+#define SERDES_LINK_MODE_MASK GENMASK(2, 1)
+#define SERDES_LINK_MODE_SHIFT 1
#define SERDES_PWR_ST_SHIFT 4
#define SERDES_PWR_ST_P0 0x0
#define SERDES_PWR_ST_P3 0x3
+#define SERDES_LINK_MODE_2G5 0x3
+#define SERSED_LINK_MODE_1G 0x2
+#define SERDES_PCLK_37p5MHZ 0x0
+#define SERDES_PCLK_70MHZ 0x1
+#define SERDES_RATE_PCIE_GEN1 0x0
+#define SERDES_RATE_PCIE_GEN2 0x1
+#define SERDES_RATE_PCIE_SHIFT 8
+#define SERDES_PCLK_SHIFT 12
+
+#define INTEL_MGBE_ADHOC_ADDR 0x15
+#define INTEL_MGBE_XPCS_ADDR 0x16
+
+/* Cross-timestamping defines */
+#define ART_CPUID_LEAF 0x15
+#define EHL_PSE_ART_MHZ 19200000
+
+/* Selection for PTP Clock Freq belongs to PSE & PCH GbE */
+#define PSE_PTP_CLK_FREQ_MASK (GMAC_GPO0 | GMAC_GPO3)
+#define PSE_PTP_CLK_FREQ_19_2MHZ (GMAC_GPO0)
+#define PSE_PTP_CLK_FREQ_200MHZ (GMAC_GPO0 | GMAC_GPO3)
+#define PSE_PTP_CLK_FREQ_256MHZ (0)
+#define PCH_PTP_CLK_FREQ_MASK (GMAC_GPO0)
+#define PCH_PTP_CLK_FREQ_19_2MHZ (GMAC_GPO0)
+#define PCH_PTP_CLK_FREQ_200MHZ (0)
#endif /* __DWMAC_INTEL_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
new file mode 100644
index 000000000000..4c9a37dd0d3f
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2020, Loongson Corporation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/pci.h>
+#include <linux/dmi.h>
+#include <linux/device.h>
+#include <linux/of_irq.h>
+#include "stmmac.h"
+
+static int loongson_default_data(struct plat_stmmacenet_data *plat)
+{
+ plat->clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
+ plat->has_gmac = 1;
+ plat->force_sf_dma_mode = 1;
+
+ /* Set default value for multicast hash bins */
+ plat->multicast_filter_bins = HASH_TABLE_SIZE;
+
+ /* Set default value for unicast filter entries */
+ plat->unicast_filter_entries = 1;
+
+ /* Set the maxmtu to a default of JUMBO_LEN */
+ plat->maxmtu = JUMBO_LEN;
+
+ /* Set default number of RX and TX queues to use */
+ plat->tx_queues_to_use = 1;
+ plat->rx_queues_to_use = 1;
+
+ /* Disable Priority config by default */
+ plat->tx_queues_cfg[0].use_prio = false;
+ plat->rx_queues_cfg[0].use_prio = false;
+
+ /* Disable RX queues routing by default */
+ plat->rx_queues_cfg[0].pkt_route = 0x0;
+
+ /* Default to phy auto-detection */
+ plat->phy_addr = -1;
+
+ plat->dma_cfg->pbl = 32;
+ plat->dma_cfg->pblx8 = true;
+
+ plat->multicast_filter_bins = 256;
+ return 0;
+}
+
+static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct plat_stmmacenet_data *plat;
+ struct stmmac_resources res;
+ struct device_node *np;
+ int ret, i, phy_mode;
+ bool mdio = false;
+
+ np = dev_of_node(&pdev->dev);
+
+ if (!np) {
+ pr_info("dwmac_loongson_pci: No OF node\n");
+ return -ENODEV;
+ }
+
+ if (!of_device_is_compatible(np, "loongson, pci-gmac")) {
+ pr_info("dwmac_loongson_pci: Incompatible OF node\n");
+ return -ENODEV;
+ }
+
+ plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
+ if (!plat)
+ return -ENOMEM;
+
+ if (plat->mdio_node) {
+ dev_err(&pdev->dev, "Found MDIO subnode\n");
+ mdio = true;
+ }
+
+ if (mdio) {
+ plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
+ sizeof(*plat->mdio_bus_data),
+ GFP_KERNEL);
+ if (!plat->mdio_bus_data)
+ return -ENOMEM;
+ plat->mdio_bus_data->needs_reset = true;
+ }
+
+ plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg), GFP_KERNEL);
+ if (!plat->dma_cfg)
+ return -ENOMEM;
+
+ /* Enable pci device */
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n", __func__);
+ return ret;
+ }
+
+ /* Get the base address of device */
+ for (i = 0; i < PCI_STD_NUM_BARS; i++) {
+ if (pci_resource_len(pdev, i) == 0)
+ continue;
+ ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
+ if (ret)
+ return ret;
+ break;
+ }
+
+ plat->bus_id = of_alias_get_id(np, "ethernet");
+ if (plat->bus_id < 0)
+ plat->bus_id = pci_dev_id(pdev);
+
+ phy_mode = device_get_phy_mode(&pdev->dev);
+ if (phy_mode < 0)
+ dev_err(&pdev->dev, "phy_mode not found\n");
+
+ plat->phy_interface = phy_mode;
+ plat->interface = PHY_INTERFACE_MODE_GMII;
+
+ pci_set_master(pdev);
+
+ loongson_default_data(plat);
+ pci_enable_msi(pdev);
+ memset(&res, 0, sizeof(res));
+ res.addr = pcim_iomap_table(pdev)[0];
+
+ res.irq = of_irq_get_byname(np, "macirq");
+ if (res.irq < 0) {
+ dev_err(&pdev->dev, "IRQ macirq not found\n");
+ ret = -ENODEV;
+ }
+
+ res.wol_irq = of_irq_get_byname(np, "eth_wake_irq");
+ if (res.wol_irq < 0) {
+ dev_info(&pdev->dev, "IRQ eth_wake_irq not found, using macirq\n");
+ res.wol_irq = res.irq;
+ }
+
+ res.lpi_irq = of_irq_get_byname(np, "eth_lpi");
+ if (res.lpi_irq < 0) {
+ dev_err(&pdev->dev, "IRQ eth_lpi not found\n");
+ ret = -ENODEV;
+ }
+
+ return stmmac_dvr_probe(&pdev->dev, plat, &res);
+}
+
+static void loongson_dwmac_remove(struct pci_dev *pdev)
+{
+ int i;
+
+ stmmac_dvr_remove(&pdev->dev);
+
+ for (i = 0; i < PCI_STD_NUM_BARS; i++) {
+ if (pci_resource_len(pdev, i) == 0)
+ continue;
+ pcim_iounmap_regions(pdev, BIT(i));
+ break;
+ }
+
+ pci_disable_device(pdev);
+}
+
+static int __maybe_unused loongson_dwmac_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ int ret;
+
+ ret = stmmac_suspend(dev);
+ if (ret)
+ return ret;
+
+ ret = pci_save_state(pdev);
+ if (ret)
+ return ret;
+
+ pci_disable_device(pdev);
+ pci_wake_from_d3(pdev, true);
+ return 0;
+}
+
+static int __maybe_unused loongson_dwmac_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ int ret;
+
+ pci_restore_state(pdev);
+ pci_set_power_state(pdev, PCI_D0);
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ pci_set_master(pdev);
+
+ return stmmac_resume(dev);
+}
+
+static SIMPLE_DEV_PM_OPS(loongson_dwmac_pm_ops, loongson_dwmac_suspend,
+ loongson_dwmac_resume);
+
+static const struct pci_device_id loongson_dwmac_id_table[] = {
+ { PCI_VDEVICE(LOONGSON, 0x7a03) },
+ {}
+};
+MODULE_DEVICE_TABLE(pci, loongson_dwmac_id_table);
+
+struct pci_driver loongson_dwmac_driver = {
+ .name = "dwmac-loongson-pci",
+ .id_table = loongson_dwmac_id_table,
+ .probe = loongson_dwmac_probe,
+ .remove = loongson_dwmac_remove,
+ .driver = {
+ .pm = &loongson_dwmac_pm_ops,
+ },
+};
+
+module_pci_driver(loongson_dwmac_driver);
+
+MODULE_DESCRIPTION("Loongson DWMAC PCI driver");
+MODULE_AUTHOR("Qing Zhang <zhangqing@loongson.cn>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
index 84382fc5cc4d..5c74b6279d69 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
@@ -454,7 +454,6 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
struct stmmac_resources stmmac_res;
const struct ethqos_emac_driver_data *data;
struct qcom_ethqos *ethqos;
- struct resource *res;
int ret;
ret = stmmac_get_platform_resources(pdev, &stmmac_res);
@@ -474,8 +473,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
}
ethqos->pdev = pdev;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rgmii");
- ethqos->rgmii_base = devm_ioremap_resource(&pdev->dev, res);
+ ethqos->rgmii_base = devm_platform_ioremap_resource_byname(pdev, "rgmii");
if (IS_ERR(ethqos->rgmii_base)) {
ret = PTR_ERR(ethqos->rgmii_base);
goto err_mem;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 8d28a536e1bb..280ac0129572 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -33,11 +33,13 @@ struct rk_gmac_ops {
void (*set_rgmii_speed)(struct rk_priv_data *bsp_priv, int speed);
void (*set_rmii_speed)(struct rk_priv_data *bsp_priv, int speed);
void (*integrated_phy_powerup)(struct rk_priv_data *bsp_priv);
+ u32 regs[];
};
struct rk_priv_data {
struct platform_device *pdev;
phy_interface_t phy_iface;
+ int id;
struct regulator *regulator;
bool suspended;
const struct rk_gmac_ops *ops;
@@ -482,6 +484,54 @@ static const struct rk_gmac_ops rk3288_ops = {
.set_rmii_speed = rk3288_set_rmii_speed,
};
+#define RK3308_GRF_MAC_CON0 0x04a0
+
+/* RK3308_GRF_MAC_CON0 */
+#define RK3308_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(2) | GRF_CLR_BIT(3) | \
+ GRF_BIT(4))
+#define RK3308_GMAC_FLOW_CTRL GRF_BIT(3)
+#define RK3308_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
+#define RK3308_GMAC_SPEED_10M GRF_CLR_BIT(0)
+#define RK3308_GMAC_SPEED_100M GRF_BIT(0)
+
+static void rk3308_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0,
+ RK3308_GMAC_PHY_INTF_SEL_RMII);
+}
+
+static void rk3308_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ if (speed == 10) {
+ regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0,
+ RK3308_GMAC_SPEED_10M);
+ } else if (speed == 100) {
+ regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0,
+ RK3308_GMAC_SPEED_100M);
+ } else {
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+ }
+}
+
+static const struct rk_gmac_ops rk3308_ops = {
+ .set_to_rmii = rk3308_set_to_rmii,
+ .set_rmii_speed = rk3308_set_rmii_speed,
+};
+
#define RK3328_GRF_MAC_CON0 0x0900
#define RK3328_GRF_MAC_CON1 0x0904
#define RK3328_GRF_MAC_CON2 0x0908
@@ -948,6 +998,107 @@ static const struct rk_gmac_ops rk3399_ops = {
.set_rmii_speed = rk3399_set_rmii_speed,
};
+#define RK3568_GRF_GMAC0_CON0 0x0380
+#define RK3568_GRF_GMAC0_CON1 0x0384
+#define RK3568_GRF_GMAC1_CON0 0x0388
+#define RK3568_GRF_GMAC1_CON1 0x038c
+
+/* RK3568_GRF_GMAC0_CON1 && RK3568_GRF_GMAC1_CON1 */
+#define RK3568_GMAC_PHY_INTF_SEL_RGMII \
+ (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6))
+#define RK3568_GMAC_PHY_INTF_SEL_RMII \
+ (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6))
+#define RK3568_GMAC_FLOW_CTRL GRF_BIT(3)
+#define RK3568_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
+#define RK3568_GMAC_RXCLK_DLY_ENABLE GRF_BIT(1)
+#define RK3568_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(1)
+#define RK3568_GMAC_TXCLK_DLY_ENABLE GRF_BIT(0)
+#define RK3568_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(0)
+
+/* RK3568_GRF_GMAC0_CON0 && RK3568_GRF_GMAC1_CON0 */
+#define RK3568_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
+#define RK3568_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+ u32 con0, con1;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ con0 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON0 :
+ RK3568_GRF_GMAC0_CON0;
+ con1 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON1 :
+ RK3568_GRF_GMAC0_CON1;
+
+ regmap_write(bsp_priv->grf, con0,
+ RK3568_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3568_GMAC_CLK_TX_DL_CFG(tx_delay));
+
+ regmap_write(bsp_priv->grf, con1,
+ RK3568_GMAC_PHY_INTF_SEL_RGMII |
+ RK3568_GMAC_RXCLK_DLY_ENABLE |
+ RK3568_GMAC_TXCLK_DLY_ENABLE);
+}
+
+static void rk3568_set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+ u32 con1;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ con1 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON1 :
+ RK3568_GRF_GMAC0_CON1;
+ regmap_write(bsp_priv->grf, con1, RK3568_GMAC_PHY_INTF_SEL_RMII);
+}
+
+static void rk3568_set_gmac_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+ unsigned long rate;
+ int ret;
+
+ switch (speed) {
+ case 10:
+ rate = 2500000;
+ break;
+ case 100:
+ rate = 25000000;
+ break;
+ case 1000:
+ rate = 125000000;
+ break;
+ default:
+ dev_err(dev, "unknown speed value for GMAC speed=%d", speed);
+ return;
+ }
+
+ ret = clk_set_rate(bsp_priv->clk_mac_speed, rate);
+ if (ret)
+ dev_err(dev, "%s: set clk_mac_speed rate %ld failed %d\n",
+ __func__, rate, ret);
+}
+
+static const struct rk_gmac_ops rk3568_ops = {
+ .set_to_rgmii = rk3568_set_to_rgmii,
+ .set_to_rmii = rk3568_set_to_rmii,
+ .set_rgmii_speed = rk3568_set_gmac_speed,
+ .set_rmii_speed = rk3568_set_gmac_speed,
+ .regs = {
+ 0xfe2a0000, /* gmac0 */
+ 0xfe010000, /* gmac1 */
+ 0x0, /* sentinel */
+ },
+};
+
#define RV1108_GRF_GMAC_CON0 0X0900
/* RV1108_GRF_GMAC_CON0 */
@@ -1216,6 +1367,7 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
{
struct rk_priv_data *bsp_priv;
struct device *dev = &pdev->dev;
+ struct resource *res;
int ret;
const char *strings = NULL;
int value;
@@ -1227,6 +1379,22 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
of_get_phy_mode(dev->of_node, &bsp_priv->phy_iface);
bsp_priv->ops = ops;
+ /* Some SoCs have multiple MAC controllers, which need
+ * to be distinguished.
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res) {
+ int i = 0;
+
+ while (ops->regs[i]) {
+ if (ops->regs[i] == res->start) {
+ bsp_priv->id = i;
+ break;
+ }
+ i++;
+ }
+ }
+
bsp_priv->regulator = devm_regulator_get_optional(dev, "phy");
if (IS_ERR(bsp_priv->regulator)) {
if (PTR_ERR(bsp_priv->regulator) == -EPROBE_DEFER) {
@@ -1294,11 +1462,36 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
return bsp_priv;
}
+static int rk_gmac_check_ops(struct rk_priv_data *bsp_priv)
+{
+ switch (bsp_priv->phy_iface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ if (!bsp_priv->ops->set_to_rgmii)
+ return -EINVAL;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ if (!bsp_priv->ops->set_to_rmii)
+ return -EINVAL;
+ break;
+ default:
+ dev_err(&bsp_priv->pdev->dev,
+ "unsupported interface %d", bsp_priv->phy_iface);
+ }
+ return 0;
+}
+
static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
{
int ret;
struct device *dev = &bsp_priv->pdev->dev;
+ ret = rk_gmac_check_ops(bsp_priv);
+ if (ret)
+ return ret;
+
ret = gmac_clk_enable(bsp_priv, true);
if (ret)
return ret;
@@ -1369,10 +1562,12 @@ static void rk_fix_speed(void *priv, unsigned int speed)
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
- bsp_priv->ops->set_rgmii_speed(bsp_priv, speed);
+ if (bsp_priv->ops->set_rgmii_speed)
+ bsp_priv->ops->set_rgmii_speed(bsp_priv, speed);
break;
case PHY_INTERFACE_MODE_RMII:
- bsp_priv->ops->set_rmii_speed(bsp_priv, speed);
+ if (bsp_priv->ops->set_rmii_speed)
+ bsp_priv->ops->set_rmii_speed(bsp_priv, speed);
break;
default:
dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface);
@@ -1400,7 +1595,11 @@ static int rk_gmac_probe(struct platform_device *pdev)
if (IS_ERR(plat_dat))
return PTR_ERR(plat_dat);
- plat_dat->has_gmac = true;
+ /* If the stmmac is not already selected as gmac4,
+ * then make sure we fallback to gmac.
+ */
+ if (!plat_dat->has_gmac4)
+ plat_dat->has_gmac = true;
plat_dat->fix_mac_speed = rk_fix_speed;
plat_dat->bsp_priv = rk_gmac_setup(pdev, plat_dat, data);
@@ -1477,10 +1676,12 @@ static const struct of_device_id rk_gmac_dwmac_match[] = {
{ .compatible = "rockchip,rk3128-gmac", .data = &rk3128_ops },
{ .compatible = "rockchip,rk3228-gmac", .data = &rk3228_ops },
{ .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops },
+ { .compatible = "rockchip,rk3308-gmac", .data = &rk3308_ops },
{ .compatible = "rockchip,rk3328-gmac", .data = &rk3328_ops },
{ .compatible = "rockchip,rk3366-gmac", .data = &rk3366_ops },
{ .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops },
{ .compatible = "rockchip,rk3399-gmac", .data = &rk3399_ops },
+ { .compatible = "rockchip,rk3568-gmac", .data = &rk3568_ops },
{ .compatible = "rockchip,rv1108-gmac", .data = &rv1108_ops },
{ }
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index f35c03c9f91e..67ba083eb90c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -1358,6 +1358,7 @@ int dwmac4_setup(struct stmmac_priv *priv)
mac->link.speed10 = GMAC_CONFIG_PS;
mac->link.speed100 = GMAC_CONFIG_FES | GMAC_CONFIG_PS;
mac->link.speed1000 = 0;
+ mac->link.speed2500 = GMAC_CONFIG_FES;
mac->link.speed_mask = GMAC_CONFIG_FES | GMAC_CONFIG_PS;
mac->mii.addr = GMAC_MDIO_ADDR;
mac->mii.data = GMAC_MDIO_DATA;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
index d8c6ff725237..9c2d40f853ed 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
@@ -183,7 +183,8 @@ static void dwmac5_handle_dma_err(struct net_device *ndev,
STAT_OFF(dma_errors), stats);
}
-int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp)
+int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp,
+ struct stmmac_safety_feature_cfg *safety_feat_cfg)
{
u32 value;
@@ -193,11 +194,16 @@ int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp)
/* 1. Enable Safety Features */
value = readl(ioaddr + MTL_ECC_CONTROL);
value |= MEEAO; /* MTL ECC Error Addr Status Override */
- value |= TSOEE; /* TSO ECC */
- value |= MRXPEE; /* MTL RX Parser ECC */
- value |= MESTEE; /* MTL EST ECC */
- value |= MRXEE; /* MTL RX FIFO ECC */
- value |= MTXEE; /* MTL TX FIFO ECC */
+ if (safety_feat_cfg->tsoee)
+ value |= TSOEE; /* TSO ECC */
+ if (safety_feat_cfg->mrxpee)
+ value |= MRXPEE; /* MTL RX Parser ECC */
+ if (safety_feat_cfg->mestee)
+ value |= MESTEE; /* MTL EST ECC */
+ if (safety_feat_cfg->mrxee)
+ value |= MRXEE; /* MTL RX FIFO ECC */
+ if (safety_feat_cfg->mtxee)
+ value |= MTXEE; /* MTL TX FIFO ECC */
writel(value, ioaddr + MTL_ECC_CONTROL);
/* 2. Enable MTL Safety Interrupts */
@@ -219,13 +225,16 @@ int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp)
/* 5. Enable Parity and Timeout for FSM */
value = readl(ioaddr + MAC_FSM_CONTROL);
- value |= PRTYEN; /* FSM Parity Feature */
- value |= TMOUTEN; /* FSM Timeout Feature */
+ if (safety_feat_cfg->prtyen)
+ value |= PRTYEN; /* FSM Parity Feature */
+ if (safety_feat_cfg->tmouten)
+ value |= TMOUTEN; /* FSM Timeout Feature */
writel(value, ioaddr + MAC_FSM_CONTROL);
/* 4. Enable Data Parity Protection */
value = readl(ioaddr + MTL_DPP_CONTROL);
- value |= EDPP;
+ if (safety_feat_cfg->edpp)
+ value |= EDPP;
writel(value, ioaddr + MTL_DPP_CONTROL);
/*
@@ -235,7 +244,8 @@ int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp)
if (asp <= 0x2)
return 0;
- value |= EPSI;
+ if (safety_feat_cfg->epsi)
+ value |= EPSI;
writel(value, ioaddr + MTL_DPP_CONTROL);
return 0;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
index 6b2fd37b29ad..53c138d0ff48 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
@@ -137,7 +137,8 @@
#define GMAC_INT_FPE_EN BIT(17)
-int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp);
+int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp,
+ struct stmmac_safety_feature_cfg *safety_cfg);
int dwmac5_safety_feat_irq_status(struct net_device *ndev,
void __iomem *ioaddr, unsigned int asp,
struct stmmac_safety_stats *stats);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index ad4df9bddcf3..c4d78fa93663 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -801,7 +801,9 @@ static void dwxgmac3_handle_dma_err(struct net_device *ndev,
dwxgmac3_dma_errors, STAT_OFF(dma_errors), stats);
}
-static int dwxgmac3_safety_feat_config(void __iomem *ioaddr, unsigned int asp)
+static int
+dwxgmac3_safety_feat_config(void __iomem *ioaddr, unsigned int asp,
+ struct stmmac_safety_feature_cfg *safety_cfg)
{
u32 value;
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 6d5e0f2b03ce..6dc1c98ebec8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -348,7 +348,8 @@ struct stmmac_ops {
void (*pcs_rane)(void __iomem *ioaddr, bool restart);
void (*pcs_get_adv_lp)(void __iomem *ioaddr, struct rgmii_adv *adv);
/* Safety Features */
- int (*safety_feat_config)(void __iomem *ioaddr, unsigned int asp);
+ int (*safety_feat_config)(void __iomem *ioaddr, unsigned int asp,
+ struct stmmac_safety_feature_cfg *safety_cfg);
int (*safety_feat_irq_status)(struct net_device *ndev,
void __iomem *ioaddr, unsigned int asp,
struct stmmac_safety_stats *stats);
@@ -612,18 +613,6 @@ struct stmmac_mmc_ops {
#define stmmac_mmc_read(__priv, __args...) \
stmmac_do_void_callback(__priv, mmc, read, __args)
-/* XPCS callbacks */
-#define stmmac_xpcs_validate(__priv, __args...) \
- stmmac_do_callback(__priv, xpcs, validate, __args)
-#define stmmac_xpcs_config(__priv, __args...) \
- stmmac_do_callback(__priv, xpcs, config, __args)
-#define stmmac_xpcs_get_state(__priv, __args...) \
- stmmac_do_callback(__priv, xpcs, get_state, __args)
-#define stmmac_xpcs_link_up(__priv, __args...) \
- stmmac_do_callback(__priv, xpcs, link_up, __args)
-#define stmmac_xpcs_probe(__priv, __args...) \
- stmmac_do_callback(__priv, xpcs, probe, __args)
-
struct stmmac_regs_off {
u32 ptp_off;
u32 mmc_off;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index b6cd43eda7ac..fcdb1d20389b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -75,7 +75,7 @@ struct stmmac_tx_queue {
unsigned int cur_tx;
unsigned int dirty_tx;
dma_addr_t dma_tx_phy;
- u32 tx_tail_addr;
+ dma_addr_t tx_tail_addr;
u32 mss;
};
@@ -311,6 +311,7 @@ enum stmmac_state {
int stmmac_mdio_unregister(struct net_device *ndev);
int stmmac_mdio_register(struct net_device *ndev);
int stmmac_mdio_reset(struct mii_bus *mii);
+int stmmac_xpcs_setup(struct mii_bus *mii);
void stmmac_set_ethtool_ops(struct net_device *netdev);
void stmmac_ptp_register(struct stmmac_priv *priv);
@@ -338,9 +339,9 @@ static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv)
static inline unsigned int stmmac_rx_offset(struct stmmac_priv *priv)
{
if (stmmac_xdp_is_enabled(priv))
- return XDP_PACKET_HEADROOM;
+ return XDP_PACKET_HEADROOM + NET_IP_ALIGN;
- return 0;
+ return NET_SKB_PAD + NET_IP_ALIGN;
}
void stmmac_disable_rx_queue(struct stmmac_priv *priv, u32 queue);
@@ -348,6 +349,9 @@ void stmmac_enable_rx_queue(struct stmmac_priv *priv, u32 queue);
void stmmac_disable_tx_queue(struct stmmac_priv *priv, u32 queue);
void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue);
int stmmac_xsk_wakeup(struct net_device *dev, u32 queue, u32 flags);
+struct timespec64 stmmac_calc_tas_basetime(ktime_t old_base_time,
+ ktime_t current_time,
+ u64 cycle_time);
#if IS_ENABLED(CONFIG_STMMAC_SELFTESTS)
void stmmac_selftest_run(struct net_device *dev,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 61b11639ee0c..d0ce608b81c3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -720,6 +720,14 @@ static int stmmac_ethtool_op_set_eee(struct net_device *dev,
netdev_warn(priv->dev,
"Setting EEE tx-lpi is not supported\n");
+ if (priv->hw->xpcs) {
+ ret = xpcs_config_eee(priv->hw->xpcs,
+ priv->plat->mult_fact_100ns,
+ edata->eee_enabled);
+ if (ret)
+ return ret;
+ }
+
if (!edata->eee_enabled)
stmmac_disable_eee_mode(priv);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index c87202cbd3d6..7b8404a21544 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -931,6 +931,11 @@ static void stmmac_validate(struct phylink_config *config,
if ((max_speed > 0) && (max_speed < 1000)) {
phylink_set(mask, 1000baseT_Full);
phylink_set(mask, 1000baseX_Full);
+ } else if (priv->plat->has_gmac4) {
+ if (!max_speed || max_speed >= 2500) {
+ phylink_set(mac_supported, 2500baseT_Full);
+ phylink_set(mac_supported, 2500baseX_Full);
+ }
} else if (priv->plat->has_xgmac) {
if (!max_speed || (max_speed >= 2500)) {
phylink_set(mac_supported, 2500baseT_Full);
@@ -996,29 +1001,14 @@ static void stmmac_validate(struct phylink_config *config,
linkmode_andnot(state->advertising, state->advertising, mask);
/* If PCS is supported, check which modes it supports. */
- stmmac_xpcs_validate(priv, &priv->hw->xpcs_args, supported, state);
-}
-
-static void stmmac_mac_pcs_get_state(struct phylink_config *config,
- struct phylink_link_state *state)
-{
- struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
-
- state->link = 0;
- stmmac_xpcs_get_state(priv, &priv->hw->xpcs_args, state);
+ if (priv->hw->xpcs)
+ xpcs_validate(priv->hw->xpcs, supported, state);
}
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));
-
- stmmac_xpcs_config(priv, &priv->hw->xpcs_args, state);
-}
-
-static void stmmac_mac_an_restart(struct phylink_config *config)
-{
- /* Not Supported */
+ /* Nothing to do, xpcs_config() handles everything */
}
static void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up)
@@ -1031,8 +1021,8 @@ static void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up)
if (is_up && *hs_enable) {
stmmac_fpe_send_mpacket(priv, priv->ioaddr, MPACKET_VERIFY);
} else {
- *lo_state = FPE_EVENT_UNKNOWN;
- *lp_state = FPE_EVENT_UNKNOWN;
+ *lo_state = FPE_STATE_OFF;
+ *lp_state = FPE_STATE_OFF;
}
}
@@ -1060,8 +1050,6 @@ static void stmmac_mac_link_up(struct phylink_config *config,
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
u32 ctrl;
- stmmac_xpcs_link_up(priv, &priv->hw->xpcs_args, speed, interface);
-
ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
ctrl &= ~priv->hw->link.speed_mask;
@@ -1154,9 +1142,7 @@ static void stmmac_mac_link_up(struct phylink_config *config,
static const struct phylink_mac_ops stmmac_phylink_mac_ops = {
.validate = stmmac_validate,
- .mac_pcs_get_state = stmmac_mac_pcs_get_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,
};
@@ -1233,6 +1219,7 @@ static int stmmac_init_phy(struct net_device *dev)
static int stmmac_phy_setup(struct stmmac_priv *priv)
{
+ struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
struct fwnode_handle *fwnode = of_fwnode_handle(priv->plat->phylink_node);
int mode = priv->plat->phy_interface;
struct phylink *phylink;
@@ -1242,7 +1229,7 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
priv->phylink_config.pcs_poll = true;
if (priv->plat->mdio_bus_data)
priv->phylink_config.ovr_an_inband =
- priv->plat->mdio_bus_data->xpcs_an_inband;
+ mdio_bus_data->xpcs_an_inband;
if (!fwnode)
fwnode = dev_fwnode(priv->device);
@@ -1252,6 +1239,9 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
if (IS_ERR(phylink))
return PTR_ERR(phylink);
+ if (priv->hw->xpcs)
+ phylink_set_pcs(phylink, &priv->hw->xpcs->pcs);
+
priv->phylink = phylink;
return 0;
}
@@ -3173,7 +3163,8 @@ static void stmmac_safety_feat_configuration(struct stmmac_priv *priv)
{
if (priv->dma_cap.asp) {
netdev_info(priv->dev, "Enabling Safety Features\n");
- stmmac_safety_feat_config(priv, priv->ioaddr, priv->dma_cap.asp);
+ stmmac_safety_feat_config(priv, priv->ioaddr, priv->dma_cap.asp,
+ priv->plat->safety_feat_cfg);
} else {
netdev_info(priv->dev, "No Safety Features support found\n");
}
@@ -3415,8 +3406,8 @@ static void stmmac_free_irq(struct net_device *dev,
static int stmmac_request_irq_multi_msi(struct net_device *dev)
{
- enum request_irq_err irq_err = REQ_IRQ_ERR_NO;
struct stmmac_priv *priv = netdev_priv(dev);
+ enum request_irq_err irq_err;
cpumask_t cpu_mask;
int irq_idx = 0;
char *int_name;
@@ -3563,8 +3554,8 @@ irq_error:
static int stmmac_request_irq_single(struct net_device *dev)
{
- enum request_irq_err irq_err = REQ_IRQ_ERR_NO;
struct stmmac_priv *priv = netdev_priv(dev);
+ enum request_irq_err irq_err;
int ret;
ret = request_irq(dev->irq, stmmac_interrupt,
@@ -3574,7 +3565,7 @@ static int stmmac_request_irq_single(struct net_device *dev)
"%s: ERROR: allocating the IRQ %d (error: %d)\n",
__func__, dev->irq, ret);
irq_err = REQ_IRQ_ERR_MAC;
- return ret;
+ goto irq_error;
}
/* Request the Wake IRQ in case of another line
@@ -3588,7 +3579,7 @@ static int stmmac_request_irq_single(struct net_device *dev)
"%s: ERROR: allocating the WoL IRQ %d (%d)\n",
__func__, priv->wol_irq, ret);
irq_err = REQ_IRQ_ERR_WOL;
- return ret;
+ goto irq_error;
}
}
@@ -3638,6 +3629,7 @@ static int stmmac_request_irq(struct net_device *dev)
int stmmac_open(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
+ int mode = priv->plat->phy_interface;
int bfsize = 0;
u32 chan;
int ret;
@@ -3650,7 +3642,8 @@ int stmmac_open(struct net_device *dev)
if (priv->hw->pcs != STMMAC_PCS_TBI &&
priv->hw->pcs != STMMAC_PCS_RTBI &&
- priv->hw->xpcs_args.an_mode != DW_AN_C73) {
+ (!priv->hw->xpcs ||
+ xpcs_get_an_mode(priv->hw->xpcs, mode) != DW_AN_C73)) {
ret = stmmac_init_phy(dev);
if (ret) {
netdev_err(priv->dev,
@@ -4658,7 +4651,6 @@ static int stmmac_xdp_xmit_back(struct stmmac_priv *priv,
return res;
}
-/* This function assumes rcu_read_lock() is held by the caller. */
static int __stmmac_xdp_run_prog(struct stmmac_priv *priv,
struct bpf_prog *prog,
struct xdp_buff *xdp)
@@ -4700,17 +4692,14 @@ static struct sk_buff *stmmac_xdp_run_prog(struct stmmac_priv *priv,
struct bpf_prog *prog;
int res;
- rcu_read_lock();
-
prog = READ_ONCE(priv->xdp_prog);
if (!prog) {
res = STMMAC_XDP_PASS;
- goto unlock;
+ goto out;
}
res = __stmmac_xdp_run_prog(priv, prog, xdp);
-unlock:
- rcu_read_unlock();
+out:
return ERR_PTR(-res);
}
@@ -4980,10 +4969,8 @@ read_again:
buf->xdp->data_end = buf->xdp->data + buf1_len;
xsk_buff_dma_sync_for_cpu(buf->xdp, rx_q->xsk_pool);
- rcu_read_lock();
prog = READ_ONCE(priv->xdp_prog);
res = __stmmac_xdp_run_prog(priv, prog, buf->xdp);
- rcu_read_unlock();
switch (res) {
case STMMAC_XDP_PASS:
@@ -5138,7 +5125,7 @@ read_again:
/* Buffer is good. Go on. */
- prefetch(page_address(buf->page));
+ prefetch(page_address(buf->page) + buf->page_offset);
if (buf->sec_page)
prefetch(page_address(buf->sec_page));
@@ -5171,12 +5158,9 @@ read_again:
dma_sync_single_for_cpu(priv->device, buf->addr,
buf1_len, dma_dir);
- xdp.data = page_address(buf->page) + buf->page_offset;
- xdp.data_end = xdp.data + buf1_len;
- xdp.data_hard_start = page_address(buf->page);
- xdp_set_data_meta_invalid(&xdp);
- xdp.frame_sz = buf_sz;
- xdp.rxq = &rx_q->xdp_rxq;
+ xdp_init_buff(&xdp, buf_sz, &rx_q->xdp_rxq);
+ xdp_prepare_buff(&xdp, page_address(buf->page),
+ buf->page_offset, buf1_len, false);
pre_len = xdp.data_end - xdp.data_hard_start -
buf->page_offset;
@@ -6545,7 +6529,8 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
* register (if supported).
*/
priv->plat->enh_desc = priv->dma_cap.enh_desc;
- priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up;
+ priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up &&
+ !priv->plat->use_phy_wol;
priv->hw->pmt = priv->plat->pmt;
if (priv->dma_cap.hash_tb_sz) {
priv->hw->multicast_filter_bins =
@@ -6854,6 +6839,11 @@ int stmmac_dvr_probe(struct device *device,
reset_control_reset(priv->plat->stmmac_rst);
}
+ ret = reset_control_deassert(priv->plat->stmmac_ahb_rst);
+ if (ret == -ENOTSUPP)
+ dev_err(priv->device, "unable to bring out of ahb reset: %pe\n",
+ ERR_PTR(ret));
+
/* Init MAC and get the capabilities */
ret = stmmac_hw_init(priv);
if (ret)
@@ -7005,6 +6995,15 @@ int stmmac_dvr_probe(struct device *device,
}
}
+ if (priv->plat->speed_mode_2500)
+ priv->plat->speed_mode_2500(ndev, priv->plat->bsp_priv);
+
+ if (priv->plat->mdio_bus_data && priv->plat->mdio_bus_data->has_xpcs) {
+ ret = stmmac_xpcs_setup(priv->mii);
+ if (ret)
+ goto error_xpcs_setup;
+ }
+
ret = stmmac_phy_setup(priv);
if (ret) {
netdev_err(ndev, "failed to setup phy (%d)\n", ret);
@@ -7041,6 +7040,7 @@ error_serdes_powerup:
unregister_netdev(ndev);
error_netdev_register:
phylink_destroy(priv->phylink);
+error_xpcs_setup:
error_phy_setup:
if (priv->hw->pcs != STMMAC_PCS_TBI &&
priv->hw->pcs != STMMAC_PCS_RTBI)
@@ -7085,6 +7085,7 @@ int stmmac_dvr_remove(struct device *dev)
phylink_destroy(priv->phylink);
if (priv->plat->stmmac_rst)
reset_control_assert(priv->plat->stmmac_rst);
+ reset_control_assert(priv->plat->stmmac_ahb_rst);
pm_runtime_put(dev);
pm_runtime_disable(dev);
if (priv->hw->pcs != STMMAC_PCS_TBI &&
@@ -7170,6 +7171,7 @@ int stmmac_suspend(struct device *dev)
priv->plat->rx_queues_to_use, false);
stmmac_fpe_handshake(priv, false);
+ stmmac_fpe_stop_wq(priv);
}
priv->speed = SPEED_UNKNOWN;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index b750074f8f9c..a5d150c5f3d8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -397,6 +397,41 @@ int stmmac_mdio_reset(struct mii_bus *bus)
return 0;
}
+int stmmac_xpcs_setup(struct mii_bus *bus)
+{
+ struct net_device *ndev = bus->priv;
+ struct mdio_device *mdiodev;
+ struct stmmac_priv *priv;
+ struct dw_xpcs *xpcs;
+ int mode, addr;
+
+ priv = netdev_priv(ndev);
+ mode = priv->plat->phy_interface;
+
+ /* Try to probe the XPCS by scanning all addresses. */
+ for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
+ mdiodev = mdio_device_create(bus, addr);
+ if (IS_ERR(mdiodev))
+ continue;
+
+ xpcs = xpcs_create(mdiodev, mode);
+ if (IS_ERR_OR_NULL(xpcs)) {
+ mdio_device_free(mdiodev);
+ continue;
+ }
+
+ priv->hw->xpcs = xpcs;
+ break;
+ }
+
+ if (!priv->hw->xpcs) {
+ dev_warn(priv->device, "No xPCS found\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
/**
* stmmac_mdio_register
* @ndev: net device structure
@@ -444,14 +479,6 @@ int stmmac_mdio_register(struct net_device *ndev)
max_addr = PHY_MAX_ADDR;
}
- if (mdio_bus_data->has_xpcs) {
- priv->hw->xpcs = mdio_xpcs_get_ops();
- if (!priv->hw->xpcs) {
- err = -ENODEV;
- goto bus_register_fail;
- }
- }
-
if (mdio_bus_data->needs_reset)
new_bus->reset = &stmmac_mdio_reset;
@@ -503,30 +530,10 @@ int stmmac_mdio_register(struct net_device *ndev)
found = 1;
}
- /* Try to probe the XPCS by scanning all addresses. */
- if (priv->hw->xpcs) {
- struct mdio_xpcs_args *xpcs = &priv->hw->xpcs_args;
- int ret, mode = priv->plat->phy_interface;
- max_addr = PHY_MAX_ADDR;
-
- xpcs->bus = new_bus;
-
- for (addr = 0; addr < max_addr; addr++) {
- xpcs->addr = addr;
-
- ret = stmmac_xpcs_probe(priv, xpcs, mode);
- if (!ret) {
- found = 1;
- break;
- }
- }
- }
-
if (!found && !mdio_node) {
dev_warn(dev, "No PHY found\n");
- mdiobus_unregister(new_bus);
- mdiobus_free(new_bus);
- return -ENODEV;
+ err = -ENODEV;
+ goto no_phy_found;
}
bus_register_done:
@@ -534,6 +541,8 @@ bus_register_done:
return 0;
+no_phy_found:
+ mdiobus_unregister(new_bus);
bus_register_fail:
mdiobus_free(new_bus);
return err;
@@ -551,6 +560,11 @@ int stmmac_mdio_unregister(struct net_device *ndev)
if (!priv->mii)
return 0;
+ if (priv->hw->xpcs) {
+ mdio_device_free(priv->hw->xpcs->mdiodev);
+ xpcs_destroy(priv->hw->xpcs);
+ }
+
mdiobus_unregister(priv->mii);
priv->mii->priv = NULL;
mdiobus_free(priv->mii);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 95e0e4d6f74d..fcf17d8a0494 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -174,6 +174,12 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
if (!plat->dma_cfg)
return -ENOMEM;
+ plat->safety_feat_cfg = devm_kzalloc(&pdev->dev,
+ sizeof(*plat->safety_feat_cfg),
+ GFP_KERNEL);
+ if (!plat->safety_feat_cfg)
+ return -ENOMEM;
+
/* Enable pci device */
ret = pci_enable_device(pdev);
if (ret) {
@@ -203,6 +209,16 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
res.wol_irq = pdev->irq;
res.irq = pdev->irq;
+ plat->safety_feat_cfg->tsoee = 1;
+ plat->safety_feat_cfg->mrxpee = 1;
+ plat->safety_feat_cfg->mestee = 1;
+ plat->safety_feat_cfg->mrxee = 1;
+ plat->safety_feat_cfg->mtxee = 1;
+ plat->safety_feat_cfg->epsi = 1;
+ plat->safety_feat_cfg->edpp = 1;
+ plat->safety_feat_cfg->prtyen = 1;
+ plat->safety_feat_cfg->tmouten = 1;
+
return stmmac_dvr_probe(&pdev->dev, plat, &res);
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index a696ada013eb..5ca710844cc1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -230,8 +230,6 @@ static int stmmac_mtl_setup(struct platform_device *pdev,
plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WFQ;
else if (of_property_read_bool(tx_node, "snps,tx-sched-dwrr"))
plat->tx_sched_algorithm = MTL_TX_ALGORITHM_DWRR;
- else if (of_property_read_bool(tx_node, "snps,tx-sched-sp"))
- plat->tx_sched_algorithm = MTL_TX_ALGORITHM_SP;
else
plat->tx_sched_algorithm = MTL_TX_ALGORITHM_SP;
@@ -399,6 +397,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
struct device_node *np = pdev->dev.of_node;
struct plat_stmmacenet_data *plat;
struct stmmac_dma_cfg *dma_cfg;
+ int phy_mode;
void *ret;
int rc;
@@ -414,10 +413,11 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
eth_zero_addr(mac);
}
- plat->phy_interface = device_get_phy_mode(&pdev->dev);
- if (plat->phy_interface < 0)
- return ERR_PTR(plat->phy_interface);
+ phy_mode = device_get_phy_mode(&pdev->dev);
+ if (phy_mode < 0)
+ return ERR_PTR(phy_mode);
+ plat->phy_interface = phy_mode;
plat->interface = stmmac_of_get_mac_mode(np);
if (plat->interface < 0)
plat->interface = plat->phy_interface;
@@ -602,6 +602,13 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
goto error_hw_init;
}
+ plat->stmmac_ahb_rst = devm_reset_control_get_optional_shared(
+ &pdev->dev, "ahb");
+ if (IS_ERR(plat->stmmac_ahb_rst)) {
+ ret = plat->stmmac_ahb_rst;
+ goto error_hw_init;
+ }
+
return plat;
error_hw_init:
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
index 4e86cdf2bc9f..580cc035536b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
@@ -62,7 +62,8 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
u32 sec, nsec;
u32 quotient, reminder;
int neg_adj = 0;
- bool xmac;
+ bool xmac, est_rst = false;
+ int ret;
xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac;
@@ -75,10 +76,48 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
sec = quotient;
nsec = reminder;
+ /* If EST is enabled, disabled it before adjust ptp time. */
+ if (priv->plat->est && priv->plat->est->enable) {
+ est_rst = true;
+ mutex_lock(&priv->plat->est->lock);
+ priv->plat->est->enable = false;
+ stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
+ priv->plat->clk_ptp_rate);
+ mutex_unlock(&priv->plat->est->lock);
+ }
+
spin_lock_irqsave(&priv->ptp_lock, flags);
stmmac_adjust_systime(priv, priv->ptpaddr, sec, nsec, neg_adj, xmac);
spin_unlock_irqrestore(&priv->ptp_lock, flags);
+ /* Caculate new basetime and re-configured EST after PTP time adjust. */
+ if (est_rst) {
+ struct timespec64 current_time, time;
+ ktime_t current_time_ns, basetime;
+ u64 cycle_time;
+
+ mutex_lock(&priv->plat->est->lock);
+ priv->ptp_clock_ops.gettime64(&priv->ptp_clock_ops, &current_time);
+ current_time_ns = timespec64_to_ktime(current_time);
+ time.tv_nsec = priv->plat->est->btr_reserve[0];
+ time.tv_sec = priv->plat->est->btr_reserve[1];
+ basetime = timespec64_to_ktime(time);
+ cycle_time = priv->plat->est->ctr[1] * NSEC_PER_SEC +
+ priv->plat->est->ctr[0];
+ time = stmmac_calc_tas_basetime(basetime,
+ current_time_ns,
+ cycle_time);
+
+ priv->plat->est->btr[0] = (u32)time.tv_nsec;
+ priv->plat->est->btr[1] = (u32)time.tv_sec;
+ priv->plat->est->enable = true;
+ ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
+ priv->plat->clk_ptp_rate);
+ mutex_unlock(&priv->plat->est->lock);
+ if (ret)
+ netdev_err(priv->dev, "failed to configure EST\n");
+ }
+
return 0;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index 4e70efc45458..4f3b6437b114 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -573,10 +573,8 @@ static int tc_add_flow(struct stmmac_priv *priv,
for (i = 0; i < ARRAY_SIZE(tc_flow_parsers); i++) {
ret = tc_flow_parsers[i].fn(priv, cls, entry);
- if (!ret) {
+ if (!ret)
entry->in_use = true;
- continue;
- }
}
if (!entry->in_use)
@@ -713,12 +711,35 @@ static int tc_setup_cls(struct stmmac_priv *priv,
return ret;
}
+struct timespec64 stmmac_calc_tas_basetime(ktime_t old_base_time,
+ ktime_t current_time,
+ u64 cycle_time)
+{
+ struct timespec64 time;
+
+ if (ktime_after(old_base_time, current_time)) {
+ time = ktime_to_timespec64(old_base_time);
+ } else {
+ s64 n;
+ ktime_t base_time;
+
+ n = div64_s64(ktime_sub_ns(current_time, old_base_time),
+ cycle_time);
+ base_time = ktime_add_ns(old_base_time,
+ (n + 1) * cycle_time);
+
+ time = ktime_to_timespec64(base_time);
+ }
+
+ return time;
+}
+
static int tc_setup_taprio(struct stmmac_priv *priv,
struct tc_taprio_qopt_offload *qopt)
{
u32 size, wid = priv->dma_cap.estwid, dep = priv->dma_cap.estdep;
struct plat_stmmacenet_data *plat = priv->plat;
- struct timespec64 time, current_time;
+ struct timespec64 time, current_time, qopt_time;
ktime_t current_time_ns;
bool fpe = false;
int i, ret = 0;
@@ -775,14 +796,18 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
GFP_KERNEL);
if (!plat->est)
return -ENOMEM;
+
+ mutex_init(&priv->plat->est->lock);
} else {
memset(plat->est, 0, sizeof(*plat->est));
}
size = qopt->num_entries;
+ mutex_lock(&priv->plat->est->lock);
priv->plat->est->gcl_size = size;
priv->plat->est->enable = qopt->enable;
+ mutex_unlock(&priv->plat->est->lock);
for (i = 0; i < size; i++) {
s64 delta_ns = qopt->entries[i].interval;
@@ -813,32 +838,28 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
priv->plat->est->gcl[i] = delta_ns | (gates << wid);
}
+ mutex_lock(&priv->plat->est->lock);
/* Adjust for real system time */
priv->ptp_clock_ops.gettime64(&priv->ptp_clock_ops, &current_time);
current_time_ns = timespec64_to_ktime(current_time);
- if (ktime_after(qopt->base_time, current_time_ns)) {
- time = ktime_to_timespec64(qopt->base_time);
- } else {
- ktime_t base_time;
- s64 n;
-
- n = div64_s64(ktime_sub_ns(current_time_ns, qopt->base_time),
- qopt->cycle_time);
- base_time = ktime_add_ns(qopt->base_time,
- (n + 1) * qopt->cycle_time);
-
- time = ktime_to_timespec64(base_time);
- }
+ time = stmmac_calc_tas_basetime(qopt->base_time, current_time_ns,
+ qopt->cycle_time);
priv->plat->est->btr[0] = (u32)time.tv_nsec;
priv->plat->est->btr[1] = (u32)time.tv_sec;
+ qopt_time = ktime_to_timespec64(qopt->base_time);
+ priv->plat->est->btr_reserve[0] = (u32)qopt_time.tv_nsec;
+ priv->plat->est->btr_reserve[1] = (u32)qopt_time.tv_sec;
+
ctr = qopt->cycle_time;
priv->plat->est->ctr[0] = do_div(ctr, NSEC_PER_SEC);
priv->plat->est->ctr[1] = (u32)ctr;
- if (fpe && !priv->dma_cap.fpesel)
+ if (fpe && !priv->dma_cap.fpesel) {
+ mutex_unlock(&priv->plat->est->lock);
return -EOPNOTSUPP;
+ }
/* Actual FPE register configuration will be done after FPE handshake
* is success.
@@ -847,6 +868,7 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
priv->plat->clk_ptp_rate);
+ mutex_unlock(&priv->plat->est->lock);
if (ret) {
netdev_err(priv->dev, "failed to configure EST\n");
goto disable;
@@ -862,9 +884,11 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
return 0;
disable:
+ mutex_lock(&priv->plat->est->lock);
priv->plat->est->enable = false;
stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
priv->plat->clk_ptp_rate);
+ mutex_unlock(&priv->plat->est->lock);
priv->plat->fpe_cfg->enable = false;
stmmac_fpe_configure(priv, priv->ioaddr,
diff --git a/drivers/net/ethernet/sun/cassini.c b/drivers/net/ethernet/sun/cassini.c
index 54f45d8c79a7..981685c88308 100644
--- a/drivers/net/ethernet/sun/cassini.c
+++ b/drivers/net/ethernet/sun/cassini.c
@@ -486,7 +486,7 @@ page_err:
/* initialize spare pool of rx buffers, but allocate during the open */
static void cas_spare_init(struct cas *cp)
{
- spin_lock(&cp->rx_inuse_lock);
+ spin_lock(&cp->rx_inuse_lock);
INIT_LIST_HEAD(&cp->rx_inuse_list);
spin_unlock(&cp->rx_inuse_lock);
diff --git a/drivers/net/ethernet/sun/ldmvsw.c b/drivers/net/ethernet/sun/ldmvsw.c
index 01ea0d6f8819..50bd4e3b0af9 100644
--- a/drivers/net/ethernet/sun/ldmvsw.c
+++ b/drivers/net/ethernet/sun/ldmvsw.c
@@ -404,7 +404,7 @@ err_out_free_dev:
return err;
}
-static int vsw_port_remove(struct vio_dev *vdev)
+static void vsw_port_remove(struct vio_dev *vdev)
{
struct vnet_port *port = dev_get_drvdata(&vdev->dev);
unsigned long flags;
@@ -430,8 +430,6 @@ static int vsw_port_remove(struct vio_dev *vdev)
free_netdev(port->dev);
}
-
- return 0;
}
static void vsw_cleanup(void)
diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c
index 9790656cf970..cfb9e21b18b7 100644
--- a/drivers/net/ethernet/sun/sungem.c
+++ b/drivers/net/ethernet/sun/sungem.c
@@ -1258,8 +1258,8 @@ static void gem_begin_auto_negotiation(struct gem *gp,
&advertising, ep->link_modes.advertising);
if (gp->phy_type != phy_mii_mdio0 &&
- gp->phy_type != phy_mii_mdio1)
- goto non_mii;
+ gp->phy_type != phy_mii_mdio1)
+ goto non_mii;
/* Setup advertise */
if (found_mii_phy(gp))
@@ -1410,7 +1410,7 @@ static int gem_set_link_modes(struct gem *gp)
if (gp->phy_type == phy_serialink ||
gp->phy_type == phy_serdes) {
- u32 pcs_lpa = readl(gp->regs + PCS_MIILP);
+ u32 pcs_lpa = readl(gp->regs + PCS_MIILP);
if (pcs_lpa & (PCS_MIIADV_SP | PCS_MIIADV_AP))
pause = 1;
@@ -1892,7 +1892,7 @@ static void gem_init_mac(struct gem *gp)
static void gem_init_pause_thresholds(struct gem *gp)
{
- u32 cfg;
+ u32 cfg;
/* Calculate pause thresholds. Setting the OFF threshold to the
* full RX fifo size effectively disables PAUSE generation which
@@ -1914,15 +1914,15 @@ static void gem_init_pause_thresholds(struct gem *gp)
/* Configure the chip "burst" DMA mode & enable some
* HW bug fixes on Apple version
*/
- cfg = 0;
- if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+ cfg = 0;
+ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
cfg |= GREG_CFG_RONPAULBIT | GREG_CFG_ENBUG2FIX;
#if !defined(CONFIG_SPARC64) && !defined(CONFIG_ALPHA)
- cfg |= GREG_CFG_IBURST;
+ cfg |= GREG_CFG_IBURST;
#endif
- cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
- cfg |= ((31 << 6) & GREG_CFG_RXDMALIM);
- writel(cfg, gp->regs + GREG_CFG);
+ cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
+ cfg |= ((31 << 6) & GREG_CFG_RXDMALIM);
+ writel(cfg, gp->regs + GREG_CFG);
/* If Infinite Burst didn't stick, then use different
* thresholds (and Apple bug fixes don't exist)
diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c
index 54b53dbdb33c..a2c1a404c52d 100644
--- a/drivers/net/ethernet/sun/sunhme.c
+++ b/drivers/net/ethernet/sun/sunhme.c
@@ -2286,8 +2286,8 @@ static netdev_tx_t happy_meal_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct happy_meal *hp = netdev_priv(dev);
- int entry;
- u32 tx_flags;
+ int entry;
+ u32 tx_flags;
tx_flags = TXFLAG_OWN;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -2301,7 +2301,7 @@ static netdev_tx_t happy_meal_start_xmit(struct sk_buff *skb,
spin_lock_irq(&hp->happy_lock);
- if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) {
+ if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev);
spin_unlock_irq(&hp->happy_lock);
printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n",
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c
index 96b883f965f6..58ee89223951 100644
--- a/drivers/net/ethernet/sun/sunvnet.c
+++ b/drivers/net/ethernet/sun/sunvnet.c
@@ -510,7 +510,7 @@ err_out_put_mdesc:
return err;
}
-static int vnet_port_remove(struct vio_dev *vdev)
+static void vnet_port_remove(struct vio_dev *vdev)
{
struct vnet_port *port = dev_get_drvdata(&vdev->dev);
@@ -533,7 +533,6 @@ static int vnet_port_remove(struct vio_dev *vdev)
kfree(port);
}
- return 0;
}
static const struct vio_device_id vnet_port_match[] = {
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index 6a67b026df0b..718539cdd2f2 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -1506,12 +1506,12 @@ static void am65_cpsw_nuss_free_tx_chns(void *data)
for (i = 0; i < common->tx_ch_num; i++) {
struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];
- if (!IS_ERR_OR_NULL(tx_chn->tx_chn))
- k3_udma_glue_release_tx_chn(tx_chn->tx_chn);
-
if (!IS_ERR_OR_NULL(tx_chn->desc_pool))
k3_cppi_desc_pool_destroy(tx_chn->desc_pool);
+ if (!IS_ERR_OR_NULL(tx_chn->tx_chn))
+ k3_udma_glue_release_tx_chn(tx_chn->tx_chn);
+
memset(tx_chn, 0, sizeof(*tx_chn));
}
}
@@ -1531,12 +1531,12 @@ void am65_cpsw_nuss_remove_tx_chns(struct am65_cpsw_common *common)
netif_napi_del(&tx_chn->napi_tx);
- if (!IS_ERR_OR_NULL(tx_chn->tx_chn))
- k3_udma_glue_release_tx_chn(tx_chn->tx_chn);
-
if (!IS_ERR_OR_NULL(tx_chn->desc_pool))
k3_cppi_desc_pool_destroy(tx_chn->desc_pool);
+ if (!IS_ERR_OR_NULL(tx_chn->tx_chn))
+ k3_udma_glue_release_tx_chn(tx_chn->tx_chn);
+
memset(tx_chn, 0, sizeof(*tx_chn));
}
}
@@ -1624,11 +1624,11 @@ static void am65_cpsw_nuss_free_rx_chns(void *data)
rx_chn = &common->rx_chns;
- if (!IS_ERR_OR_NULL(rx_chn->rx_chn))
- k3_udma_glue_release_rx_chn(rx_chn->rx_chn);
-
if (!IS_ERR_OR_NULL(rx_chn->desc_pool))
k3_cppi_desc_pool_destroy(rx_chn->desc_pool);
+
+ if (!IS_ERR_OR_NULL(rx_chn->rx_chn))
+ k3_udma_glue_release_rx_chn(rx_chn->rx_chn);
}
static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
diff --git a/drivers/net/ethernet/ti/am65-cpsw-switchdev.c b/drivers/net/ethernet/ti/am65-cpsw-switchdev.c
index 23cfb91e9c4d..9c29b363e9ae 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-switchdev.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-switchdev.c
@@ -84,7 +84,7 @@ static int am65_cpsw_port_attr_br_flags_pre_set(struct net_device *netdev,
return 0;
}
-static int am65_cpsw_port_attr_set(struct net_device *ndev,
+static int am65_cpsw_port_attr_set(struct net_device *ndev, const void *ctx,
const struct switchdev_attr *attr,
struct netlink_ext_ack *extack)
{
@@ -302,7 +302,7 @@ static int am65_cpsw_port_mdb_del(struct am65_cpsw_port *port,
return 0;
}
-static int am65_cpsw_port_obj_add(struct net_device *ndev,
+static int am65_cpsw_port_obj_add(struct net_device *ndev, const void *ctx,
const struct switchdev_obj *obj,
struct netlink_ext_ack *extack)
{
@@ -329,7 +329,7 @@ static int am65_cpsw_port_obj_add(struct net_device *ndev,
return err;
}
-static int am65_cpsw_port_obj_del(struct net_device *ndev,
+static int am65_cpsw_port_obj_del(struct net_device *ndev, const void *ctx,
const struct switchdev_obj *obj)
{
struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
diff --git a/drivers/net/ethernet/ti/am65-cpts.c b/drivers/net/ethernet/ti/am65-cpts.c
index 9caaae79fc95..c30a6e510aa3 100644
--- a/drivers/net/ethernet/ti/am65-cpts.c
+++ b/drivers/net/ethernet/ti/am65-cpts.c
@@ -1037,11 +1037,9 @@ static int am65_cpts_probe(struct platform_device *pdev)
struct device_node *node = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct am65_cpts *cpts;
- struct resource *res;
void __iomem *base;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cpts");
- base = devm_ioremap_resource(dev, res);
+ base = devm_platform_ioremap_resource_byname(pdev, "cpts");
if (IS_ERR(base))
return PTR_ERR(base);
diff --git a/drivers/net/ethernet/ti/cpsw-phy-sel.c b/drivers/net/ethernet/ti/cpsw-phy-sel.c
index 6e72ecbe5cf7..e8f38e3f7706 100644
--- a/drivers/net/ethernet/ti/cpsw-phy-sel.c
+++ b/drivers/net/ethernet/ti/cpsw-phy-sel.c
@@ -206,7 +206,6 @@ static const struct of_device_id cpsw_phy_sel_id_table[] = {
static int cpsw_phy_sel_probe(struct platform_device *pdev)
{
- struct resource *res;
const struct of_device_id *of_id;
struct cpsw_phy_sel_priv *priv;
@@ -223,8 +222,7 @@ static int cpsw_phy_sel_probe(struct platform_device *pdev)
priv->dev = &pdev->dev;
priv->cpsw_phy_sel = of_id->data;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gmii-sel");
- priv->gmii_sel = devm_ioremap_resource(&pdev->dev, res);
+ priv->gmii_sel = devm_platform_ioremap_resource_byname(pdev, "gmii-sel");
if (IS_ERR(priv->gmii_sel))
return PTR_ERR(priv->gmii_sel);
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index c0cd7de88316..cbbd0f665796 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -430,8 +430,8 @@ static void cpsw_rx_handler(void *token, int len, int status)
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);
+ /* mark skb for recycling */
+ skb_mark_for_recycle(skb, page, pool);
netif_receive_skb(skb);
ndev->stats.rx_bytes += len;
@@ -1532,8 +1532,7 @@ static int cpsw_probe(struct platform_device *pdev)
}
cpsw->bus_freq_mhz = clk_get_rate(clk) / 1000000;
- ss_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ss_regs = devm_ioremap_resource(dev, ss_res);
+ ss_regs = devm_platform_get_and_ioremap_resource(pdev, 0, &ss_res);
if (IS_ERR(ss_regs))
return PTR_ERR(ss_regs);
cpsw->regs = ss_regs;
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index d828f856237a..0c75e0576ee1 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -70,7 +70,7 @@ enum {
};
/**
- * struct ale_dev_id - The ALE version/SoC specific configuration
+ * struct cpsw_ale_dev_id - The ALE version/SoC specific configuration
* @dev_id: ALE version/SoC id
* @features: features supported by ALE
* @tbl_entries: number of ALE entries
diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c
index 69b7a4e0220a..57d279fdcc9f 100644
--- a/drivers/net/ethernet/ti/cpsw_new.c
+++ b/drivers/net/ethernet/ti/cpsw_new.c
@@ -373,8 +373,8 @@ static void cpsw_rx_handler(void *token, int len, int status)
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);
+ /* mark skb for recycling */
+ skb_mark_for_recycle(skb, page, pool);
netif_receive_skb(skb);
ndev->stats.rx_bytes += len;
@@ -1883,8 +1883,7 @@ static int cpsw_probe(struct platform_device *pdev)
}
cpsw->bus_freq_mhz = clk_get_rate(clk) / 1000000;
- ss_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ss_regs = devm_ioremap_resource(dev, ss_res);
+ ss_regs = devm_platform_get_and_ioremap_resource(pdev, 0, &ss_res);
if (IS_ERR(ss_regs)) {
ret = PTR_ERR(ss_regs);
return ret;
diff --git a/drivers/net/ethernet/ti/cpsw_priv.c b/drivers/net/ethernet/ti/cpsw_priv.c
index 5862f0a4a975..ecc2a6b7e28f 100644
--- a/drivers/net/ethernet/ti/cpsw_priv.c
+++ b/drivers/net/ethernet/ti/cpsw_priv.c
@@ -1328,13 +1328,9 @@ int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp,
struct bpf_prog *prog;
u32 act;
- rcu_read_lock();
-
prog = READ_ONCE(priv->xdp_prog);
- if (!prog) {
- ret = CPSW_XDP_PASS;
- goto out;
- }
+ if (!prog)
+ return CPSW_XDP_PASS;
act = bpf_prog_run_xdp(prog, xdp);
/* XDP prog might have changed packet data and boundaries */
@@ -1378,10 +1374,8 @@ int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp,
ndev->stats.rx_bytes += *len;
ndev->stats.rx_packets++;
out:
- rcu_read_unlock();
return ret;
drop:
- rcu_read_unlock();
page_pool_recycle_direct(cpsw->page_pool[ch], page);
return ret;
}
diff --git a/drivers/net/ethernet/ti/cpsw_switchdev.c b/drivers/net/ethernet/ti/cpsw_switchdev.c
index 05a64fb7a04f..f7fb6e17dadd 100644
--- a/drivers/net/ethernet/ti/cpsw_switchdev.c
+++ b/drivers/net/ethernet/ti/cpsw_switchdev.c
@@ -86,7 +86,7 @@ static int cpsw_port_attr_br_flags_pre_set(struct net_device *netdev,
return 0;
}
-static int cpsw_port_attr_set(struct net_device *ndev,
+static int cpsw_port_attr_set(struct net_device *ndev, const void *ctx,
const struct switchdev_attr *attr,
struct netlink_ext_ack *extack)
{
@@ -310,7 +310,7 @@ static int cpsw_port_mdb_del(struct cpsw_priv *priv,
return err;
}
-static int cpsw_port_obj_add(struct net_device *ndev,
+static int cpsw_port_obj_add(struct net_device *ndev, const void *ctx,
const struct switchdev_obj *obj,
struct netlink_ext_ack *extack)
{
@@ -338,7 +338,7 @@ static int cpsw_port_obj_add(struct net_device *ndev,
return err;
}
-static int cpsw_port_obj_del(struct net_device *ndev,
+static int cpsw_port_obj_del(struct net_device *ndev, const void *ctx,
const struct switchdev_obj *obj)
{
struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index f9417b44cae8..c674e34b6839 100644
--- a/drivers/net/ethernet/ti/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -1814,13 +1814,12 @@ static int davinci_emac_probe(struct platform_device *pdev)
priv->bus_freq_mhz = (u32)(emac_bus_frequency / 1000000);
/* Get EMAC platform data */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->emac_base_phys = res->start + pdata->ctrl_reg_offset;
- priv->remap_addr = devm_ioremap_resource(&pdev->dev, res);
+ priv->remap_addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(priv->remap_addr)) {
rc = PTR_ERR(priv->remap_addr);
goto no_pdata;
}
+ priv->emac_base_phys = res->start + pdata->ctrl_reg_offset;
res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (res_ctrl) {
diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c
index 0b2ce4bdc2c3..e0cb713193ea 100644
--- a/drivers/net/ethernet/ti/tlan.c
+++ b/drivers/net/ethernet/ti/tlan.c
@@ -313,9 +313,8 @@ static void tlan_remove_one(struct pci_dev *pdev)
pci_release_regions(pdev);
#endif
- free_netdev(dev);
-
cancel_work_sync(&priv->tlan_tqueue);
+ free_netdev(dev);
}
static void tlan_start(struct net_device *dev)
diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c
index fecc4d7b00b0..88426b5e410b 100644
--- a/drivers/net/ethernet/via/via-velocity.c
+++ b/drivers/net/ethernet/via/via-velocity.c
@@ -1897,7 +1897,7 @@ static void velocity_error(struct velocity_info *vptr, int status)
}
/**
- * tx_srv - transmit interrupt service
+ * velocity_tx_srv - transmit interrupt service
* @vptr: Velocity
*
* Scan the queues looking for transmitted packets that
@@ -2453,7 +2453,7 @@ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
/**
- * velocity_get_status - statistics callback
+ * velocity_get_stats - statistics callback
* @dev: network device
*
* Callback from the network layer to allow driver statistics
@@ -3723,7 +3723,7 @@ static int __init velocity_init_module(void)
}
/**
- * velocity_cleanup - module unload
+ * velocity_cleanup_module - module unload
*
* When the velocity hardware is unloaded this function is called.
* It will clean up the notifiers and the unregister the PCI
diff --git a/drivers/net/ethernet/wiznet/w5100.c b/drivers/net/ethernet/wiznet/w5100.c
index ec5db481c9cd..811815f8cd3b 100644
--- a/drivers/net/ethernet/wiznet/w5100.c
+++ b/drivers/net/ethernet/wiznet/w5100.c
@@ -263,19 +263,14 @@ static int w5100_writebulk_direct(struct net_device *ndev, u32 addr,
static int w5100_mmio_init(struct net_device *ndev)
{
struct platform_device *pdev = to_platform_device(ndev->dev.parent);
- struct w5100_priv *priv = netdev_priv(ndev);
struct w5100_mmio_priv *mmio_priv = w5100_mmio_priv(ndev);
- struct resource *mem;
spin_lock_init(&mmio_priv->reg_lock);
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mmio_priv->base = devm_ioremap_resource(&pdev->dev, mem);
+ mmio_priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(mmio_priv->base))
return PTR_ERR(mmio_priv->base);
- netdev_info(ndev, "at 0x%llx irq %d\n", (u64)mem->start, priv->irq);
-
return 0;
}
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 9a13953ea70f..60a4f79b8fa1 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -942,10 +942,8 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
wmb();
lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
- if (temac_check_tx_bd_space(lp, MAX_SKB_FRAGS + 1)) {
- netdev_info(ndev, "%s -> netif_stop_queue\n", __func__);
+ if (temac_check_tx_bd_space(lp, MAX_SKB_FRAGS + 1))
netif_stop_queue(ndev);
- }
return NETDEV_TX_OK;
}
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index b508c9453f40..13cd799541aa 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -1543,6 +1543,7 @@ static void axienet_validate(struct phylink_config *config,
case PHY_INTERFACE_MODE_MII:
phylink_set(mask, 100baseT_Full);
phylink_set(mask, 10baseT_Full);
+ fallthrough;
default:
break;
}
@@ -1893,8 +1894,7 @@ static int axienet_probe(struct platform_device *pdev)
goto cleanup_clk;
/* Map device registers */
- ethres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- lp->regs = devm_ioremap_resource(&pdev->dev, ethres);
+ lp->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &ethres);
if (IS_ERR(lp->regs)) {
ret = PTR_ERR(lp->regs);
goto cleanup_clk;
@@ -2009,9 +2009,7 @@ static int axienet_probe(struct platform_device *pdev)
lp->eth_irq = platform_get_irq_optional(pdev, 0);
} else {
/* Check for these resources directly on the Ethernet node. */
- struct resource *res = platform_get_resource(pdev,
- IORESOURCE_MEM, 1);
- lp->dma_regs = devm_ioremap_resource(&pdev->dev, res);
+ lp->dma_regs = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
lp->rx_irq = platform_get_irq(pdev, 1);
lp->tx_irq = platform_get_irq(pdev, 0);
lp->eth_irq = platform_get_irq_optional(pdev, 2);
diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
index d9d58a7dabee..b06377fe7293 100644
--- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c
+++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
@@ -1189,9 +1189,8 @@ static int xemaclite_of_probe(struct platform_device *ofdev)
}
dev_info(dev,
- "Xilinx EmacLite at 0x%08lX mapped to 0x%08lX, irq=%d\n",
- (unsigned long __force)ndev->mem_start,
- (unsigned long __force)lp->base_addr, ndev->irq);
+ "Xilinx EmacLite at 0x%08lX mapped to 0x%p, irq=%d\n",
+ (unsigned long __force)ndev->mem_start, lp->base_addr, ndev->irq);
return 0;
error:
diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c
index 2049d76a0e68..4f6db6f5c272 100644
--- a/drivers/net/ethernet/xircom/xirc2ps_cs.c
+++ b/drivers/net/ethernet/xircom/xirc2ps_cs.c
@@ -1232,7 +1232,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (pktlen < ETH_ZLEN)
{
if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
+ return NETDEV_TX_OK;
pktlen = ETH_ZLEN;
}
diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c
index cb89323855d8..7ae754eadf22 100644
--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
+++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
@@ -37,6 +37,8 @@
#include <linux/module.h>
#include <linux/soc/ixp4xx/npe.h>
#include <linux/soc/ixp4xx/qmgr.h>
+#include <mach/hardware.h>
+#include <linux/soc/ixp4xx/cpu.h>
#include "ixp46x_ts.h"
@@ -1425,7 +1427,6 @@ static int ixp4xx_eth_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
struct eth_plat_info *plat;
struct net_device *ndev;
- struct resource *res;
struct port *port;
int err;
@@ -1482,10 +1483,7 @@ static int ixp4xx_eth_probe(struct platform_device *pdev)
port->id = plat->npe;
/* Get the port resource and remap */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
- port->regs = devm_ioremap_resource(dev, res);
+ port->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(port->regs))
return PTR_ERR(port->regs);
@@ -1531,8 +1529,8 @@ static int ixp4xx_eth_probe(struct platform_device *pdev)
phydev = of_phy_get_and_connect(ndev, np, ixp4xx_adjust_link);
} else {
phydev = mdiobus_get_phy(mdio_bus, plat->phy);
- if (IS_ERR(phydev)) {
- err = PTR_ERR(phydev);
+ if (!phydev) {
+ err = -ENODEV;
dev_err(dev, "could not connect phydev (%d)\n", err);
goto err_free_mem;
}
diff --git a/drivers/net/ethernet/xscale/ptp_ixp46x.c b/drivers/net/ethernet/xscale/ptp_ixp46x.c
index 9ecc395239e9..99d4d9439d05 100644
--- a/drivers/net/ethernet/xscale/ptp_ixp46x.c
+++ b/drivers/net/ethernet/xscale/ptp_ixp46x.c
@@ -12,9 +12,8 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
-#include <linux/module.h>
-
#include <linux/ptp_clock_kernel.h>
+#include <linux/soc/ixp4xx/cpu.h>
#include "ixp46x_ts.h"
diff --git a/drivers/net/fddi/defza.c b/drivers/net/fddi/defza.c
index 14f07050b6b1..0de2c4552f5e 100644
--- a/drivers/net/fddi/defza.c
+++ b/drivers/net/fddi/defza.c
@@ -1504,9 +1504,8 @@ err_out_resource:
release_mem_region(start, len);
err_out_kfree:
- free_netdev(dev);
-
pr_err("%s: initialization failure, aborting!\n", fp->name);
+ free_netdev(dev);
return ret;
}
diff --git a/drivers/net/fddi/skfp/ess.c b/drivers/net/fddi/skfp/ess.c
index 35110c0c00a0..41107338f0c0 100644
--- a/drivers/net/fddi/skfp/ess.c
+++ b/drivers/net/fddi/skfp/ess.c
@@ -379,17 +379,17 @@ static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhe
* if the payload is greater than zero.
* For the SBAPayload and the SBAOverhead we have the following
* unite quations
- * _ _
+ * _ _
* | bytes |
* SBAPayload = | 8000 ------ |
* | s |
* - -
- * _ _
+ * _ _
* | bytes |
* SBAOverhead = | ------ |
* | T-NEG |
* - -
- *
+ *
* T-NEG is described by the equation:
*
* (-) fddiMACT-NEG
diff --git a/drivers/net/fddi/skfp/h/supern_2.h b/drivers/net/fddi/skfp/h/supern_2.h
index 78ae8ea4007c..0bbbd411d000 100644
--- a/drivers/net/fddi/skfp/h/supern_2.h
+++ b/drivers/net/fddi/skfp/h/supern_2.h
@@ -1025,7 +1025,7 @@ struct tx_queue {
#define PLC_QELM_A_BIST 0x5b6b /* BIST signature of QELM Rev. A */
/*
- FDDI board recources
+ FDDI board recources
*/
/*
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 466622664424..185c8a398681 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c
@@ -90,16 +90,8 @@ static struct platform_driver fjes_driver = {
};
static struct resource fjes_resource[] = {
- {
- .flags = IORESOURCE_MEM,
- .start = 0,
- .end = 0,
- },
- {
- .flags = IORESOURCE_IRQ,
- .start = 0,
- .end = 0,
- },
+ DEFINE_RES_MEM(0, 1),
+ DEFINE_RES_IRQ(0)
};
static bool is_extended_socket_device(struct acpi_device *device)
@@ -1262,6 +1254,10 @@ static int fjes_probe(struct platform_device *plat_dev)
adapter->interrupt_watch_enable = false;
res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0);
+ if (!res) {
+ err = -EINVAL;
+ goto err_free_control_wq;
+ }
hw->hw_res.start = res->start;
hw->hw_res.size = resource_size(res);
hw->hw_res.irq = platform_get_irq(plat_dev, 0);
diff --git a/drivers/net/fjes/fjes_trace.h b/drivers/net/fjes/fjes_trace.h
index 9237b69d8e21..6437ddbd7842 100644
--- a/drivers/net/fjes/fjes_trace.h
+++ b/drivers/net/fjes/fjes_trace.h
@@ -232,7 +232,7 @@ TRACE_EVENT(fjes_hw_start_debug_err,
__string(err, err)
),
TP_fast_assign(
- __assign_str(err, err)
+ __assign_str(err, err);
),
TP_printk("%s", __get_str(err))
);
@@ -258,7 +258,7 @@ TRACE_EVENT(fjes_hw_stop_debug_err,
__string(err, err)
),
TP_fast_assign(
- __assign_str(err, err)
+ __assign_str(err, err);
),
TP_printk("%s", __get_str(err))
);
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 39c00f050fbd..30e0a10595a1 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -201,6 +201,7 @@ static int gtp_rx(struct pdp_ctx *pctx, struct sk_buff *skb,
* calculate the transport header.
*/
skb_reset_network_header(skb);
+ skb_reset_mac_header(skb);
skb->dev = pctx->dev;
@@ -436,7 +437,7 @@ static inline void gtp1_push_header(struct sk_buff *skb, struct pdp_ctx *pctx)
gtp1->length = htons(payload_len);
gtp1->tid = htonl(pctx->u.v1.o_tei);
- /* TODO: Suppport for extension header, sequence number and N-PDU.
+ /* TODO: Support for extension header, sequence number and N-PDU.
* Update the length field if any of them is available.
*/
}
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 80f41945709f..fcf3af76b6d7 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -428,7 +428,7 @@ out:
* and sent on to some IP layer for further processing.
*/
static void sixpack_receive_buf(struct tty_struct *tty,
- const unsigned char *cp, char *fp, int count)
+ const unsigned char *cp, const char *fp, int count)
{
struct sixpack *sp;
int count1;
@@ -716,11 +716,11 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file,
err = 0;
break;
- case SIOCSIFHWADDR: {
- char addr[AX25_ADDR_LEN];
+ case SIOCSIFHWADDR: {
+ char addr[AX25_ADDR_LEN];
- if (copy_from_user(&addr,
- (void __user *) arg, AX25_ADDR_LEN)) {
+ if (copy_from_user(&addr,
+ (void __user *)arg, AX25_ADDR_LEN)) {
err = -EFAULT;
break;
}
@@ -728,11 +728,9 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file,
netif_tx_lock_bh(dev);
memcpy(dev->dev_addr, &addr, AX25_ADDR_LEN);
netif_tx_unlock_bh(dev);
-
err = 0;
break;
}
-
default:
err = tty_mode_ioctl(tty, file, cmd, arg);
}
@@ -744,6 +742,7 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file,
static struct tty_ldisc_ops sp_ldisc = {
.owner = THIS_MODULE,
+ .num = N_6PACK,
.name = "6pack",
.open = sixpack_open,
.close = sixpack_close,
@@ -766,21 +765,16 @@ static int __init sixpack_init_driver(void)
printk(msg_banner);
/* Register the provided line protocol discipline */
- if ((status = tty_register_ldisc(N_6PACK, &sp_ldisc)) != 0)
+ status = tty_register_ldisc(&sp_ldisc);
+ if (status)
printk(msg_regfail, status);
return status;
}
-static const char msg_unregfail[] = KERN_ERR \
- "6pack: can't unregister line discipline (err = %d)\n";
-
static void __exit sixpack_exit_driver(void)
{
- int ret;
-
- if ((ret = tty_unregister_ldisc(N_6PACK)))
- printk(msg_unregfail, ret);
+ tty_unregister_ldisc(&sp_ldisc);
}
/* encode an AX.25 packet into 6pack */
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index e4e4981ac1d2..4435a1195194 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -231,7 +231,7 @@ struct baycom_state {
#if 0
static inline void append_crc_ccitt(unsigned char *buffer, int len)
{
- unsigned int crc = 0xffff;
+ unsigned int crc = 0xffff;
for (;len>0;len--)
crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buffer++) & 0xff];
@@ -390,7 +390,7 @@ static void encode_hdlc(struct baycom_state *bc)
for (j = 0; j < 8; j++)
if (unlikely(!(notbitstream & (0x1f0 << j)))) {
bitstream &= ~(0x100 << j);
- bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) |
+ bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) |
((bitbuf & ~(((2 << j) << numbit) - 1)) << 1);
numbit++;
notbitstream = ~bitstream;
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 1ad6085994b1..0e623c2e8b2d 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -368,7 +368,7 @@ static int bpq_close(struct net_device *dev)
/* ------------------------------------------------------------------------ */
-
+#ifdef CONFIG_PROC_FS
/*
* Proc filesystem
*/
@@ -440,7 +440,7 @@ static const struct seq_operations bpq_seqops = {
.stop = bpq_seq_stop,
.show = bpq_seq_show,
};
-
+#endif
/* ------------------------------------------------------------------------ */
static const struct net_device_ops bpq_netdev_ops = {
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index 9e0058154ac3..cbaf1cdde7cb 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -74,7 +74,7 @@
static inline void append_crc_ccitt(unsigned char *buffer, int len)
{
- unsigned int crc = crc_ccitt(0xffff, buffer, len) ^ 0xffff;
+ unsigned int crc = crc_ccitt(0xffff, buffer, len) ^ 0xffff;
buffer += len;
*buffer++ = crc;
*buffer++ = crc >> 8;
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 7685a1721597..8666110bec55 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -276,7 +276,7 @@ static void ax_bump(struct mkiss *ax)
*/
*ax->rbuff &= ~0x20;
}
- }
+ }
count = ax->rcount;
@@ -501,7 +501,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
default:
count = kiss_esc(p, ax->xbuff, len);
}
- }
+ }
spin_unlock_bh(&ax->buflock);
set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
@@ -816,7 +816,7 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file,
dev = ax->dev;
switch (cmd) {
- case SIOCGIFNAME:
+ case SIOCGIFNAME:
err = copy_to_user((void __user *) arg, ax->dev->name,
strlen(ax->dev->name) + 1) ? -EFAULT : 0;
break;
@@ -872,7 +872,7 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file,
* and sent on to the AX.25 layer for further processing.
*/
static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
struct mkiss *ax = mkiss_get(tty);
@@ -934,6 +934,7 @@ out:
static struct tty_ldisc_ops ax_ldisc = {
.owner = THIS_MODULE,
+ .num = N_AX25,
.name = "mkiss",
.open = mkiss_open,
.close = mkiss_close,
@@ -953,22 +954,16 @@ static int __init mkiss_init_driver(void)
printk(banner);
- status = tty_register_ldisc(N_AX25, &ax_ldisc);
+ status = tty_register_ldisc(&ax_ldisc);
if (status != 0)
printk(msg_regfail, status);
return status;
}
-static const char msg_unregfail[] = KERN_ERR \
- "mkiss: can't unregister line discipline (err = %d)\n";
-
static void __exit mkiss_exit_driver(void)
{
- int ret;
-
- if ((ret = tty_unregister_ldisc(N_AX25)))
- printk(msg_unregfail, ret);
+ tty_unregister_ldisc(&ax_ldisc);
}
MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>");
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 4690c6a59054..3f1edd0526a4 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1192,18 +1192,18 @@ static void t_tail(struct timer_list *t)
unsigned long flags;
spin_lock_irqsave(&scc->lock, flags);
- del_timer(&scc->tx_wdog);
- scc_key_trx(scc, TX_OFF);
+ del_timer(&scc->tx_wdog);
+ scc_key_trx(scc, TX_OFF);
spin_unlock_irqrestore(&scc->lock, flags);
- if (scc->stat.tx_state == TXS_TIMEOUT) /* we had a timeout? */
- {
- scc->stat.tx_state = TXS_WAIT;
+ if (scc->stat.tx_state == TXS_TIMEOUT) /* we had a timeout? */
+ {
+ scc->stat.tx_state = TXS_WAIT;
scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100);
- return;
- }
-
- scc->stat.tx_state = TXS_IDLE;
+ return;
+ }
+
+ scc->stat.tx_state = TXS_IDLE;
netif_wake_queue(scc->dev);
}
@@ -1580,7 +1580,7 @@ static int scc_net_open(struct net_device *dev)
{
struct scc_channel *scc = (struct scc_channel *) dev->ml_priv;
- if (!scc->init)
+ if (!scc->init)
return -EINVAL;
scc->tx_buff = NULL;
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 5ab53e9942f3..d4911041596c 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -668,7 +668,7 @@ static void yam_tx_byte(struct net_device *dev, struct yam_port *yp)
}
yp->tx_len = skb->len - 1; /* strip KISS byte */
if (yp->tx_len >= YAM_MAX_FRAME || yp->tx_len < 2) {
- dev_kfree_skb_any(skb);
+ dev_kfree_skb_any(skb);
break;
}
skb_copy_from_linear_data_offset(skb, 1,
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 442c520ab8f3..bc48855dff10 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -895,9 +895,16 @@ static inline u32 netvsc_rqstor_size(unsigned long ringbytes)
ringbytes / NETVSC_MIN_IN_MSG_SIZE;
}
+/* XFER PAGE packets can specify a maximum of 375 ranges for NDIS >= 6.0
+ * and a maximum of 64 ranges for NDIS < 6.0 with no RSC; with RSC, this
+ * limit is raised to 562 (= NVSP_RSC_MAX).
+ */
+#define NETVSC_MAX_XFER_PAGE_RANGES NVSP_RSC_MAX
#define NETVSC_XFER_HEADER_SIZE(rng_cnt) \
(offsetof(struct vmtransfer_page_packet_header, ranges) + \
(rng_cnt) * sizeof(struct vmtransfer_page_range))
+#define NETVSC_MAX_PKT_SIZE (NETVSC_XFER_HEADER_SIZE(NETVSC_MAX_XFER_PAGE_RANGES) + \
+ sizeof(struct nvsp_message) + (sizeof(u32) * VRSS_SEND_TAB_SIZE))
struct multi_send_data {
struct sk_buff *skb; /* skb containing the pkt */
@@ -1163,6 +1170,7 @@ struct rndis_set_request {
u32 info_buflen;
u32 info_buf_offset;
u32 dev_vc_handle;
+ u8 info_buf[];
};
/* Response to NdisSetRequest */
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 9d07c9ce4be2..7bd935412853 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -757,7 +757,7 @@ static void netvsc_send_tx_complete(struct net_device *ndev,
int queue_sends;
u64 cmd_rqst;
- cmd_rqst = vmbus_request_addr(&channel->requestor, (u64)desc->trans_id);
+ cmd_rqst = channel->request_addr_callback(channel, (u64)desc->trans_id);
if (cmd_rqst == VMBUS_RQST_ERROR) {
netdev_err(ndev, "Incorrect transaction id\n");
return;
@@ -817,8 +817,8 @@ static void netvsc_send_completion(struct net_device *ndev,
/* First check if this is a VMBUS completion without data payload */
if (!msglen) {
- cmd_rqst = vmbus_request_addr(&incoming_channel->requestor,
- (u64)desc->trans_id);
+ cmd_rqst = incoming_channel->request_addr_callback(incoming_channel,
+ (u64)desc->trans_id);
if (cmd_rqst == VMBUS_RQST_ERROR) {
netdev_err(ndev, "Invalid transaction id\n");
return;
@@ -1649,7 +1649,11 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device,
netvsc_poll, NAPI_POLL_WEIGHT);
/* Open the channel */
+ device->channel->next_request_id_callback = vmbus_next_request_id;
+ device->channel->request_addr_callback = vmbus_request_addr;
device->channel->rqstor_size = netvsc_rqstor_size(netvsc_ring_bytes);
+ device->channel->max_pkt_size = NETVSC_MAX_PKT_SIZE;
+
ret = vmbus_open(device->channel, netvsc_ring_bytes,
netvsc_ring_bytes, NULL, 0,
netvsc_channel_cb, net_device->chan_table);
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index f682a5572d84..382bebc2420d 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -2384,6 +2384,9 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
dev_hold(vf_netdev);
rcu_assign_pointer(net_device_ctx->vf_netdev, vf_netdev);
+ if (ndev->needed_headroom < vf_netdev->needed_headroom)
+ ndev->needed_headroom = vf_netdev->needed_headroom;
+
vf_netdev->wanted_features = ndev->features;
netdev_update_features(vf_netdev);
@@ -2462,6 +2465,8 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev)
RCU_INIT_POINTER(net_device_ctx->vf_netdev, NULL);
dev_put(vf_netdev);
+ ndev->needed_headroom = RNDIS_AND_PPI_SIZE;
+
return NOTIFY_OK;
}
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index c0e89e107d57..f6c9c2a670f9 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -1051,10 +1051,8 @@ static int rndis_filter_set_packet_filter(struct rndis_device *dev,
set = &request->request_msg.msg.set_req;
set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
set->info_buflen = sizeof(u32);
- set->info_buf_offset = sizeof(struct rndis_set_request);
-
- memcpy((void *)(unsigned long)set + sizeof(struct rndis_set_request),
- &new_filter, sizeof(u32));
+ set->info_buf_offset = offsetof(typeof(*set), info_buf);
+ memcpy(set->info_buf, &new_filter, sizeof(u32));
ret = rndis_filter_send_request(dev, request);
if (ret == 0) {
@@ -1259,7 +1257,11 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc)
/* Set the channel before opening.*/
nvchan->channel = new_sc;
+ new_sc->next_request_id_callback = vmbus_next_request_id;
+ new_sc->request_addr_callback = vmbus_request_addr;
new_sc->rqstor_size = netvsc_rqstor_size(netvsc_ring_bytes);
+ new_sc->max_pkt_size = NETVSC_MAX_PKT_SIZE;
+
ret = vmbus_open(new_sc, netvsc_ring_bytes,
netvsc_ring_bytes, NULL, 0,
netvsc_channel_cb, nvchan);
diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
index da9135231c07..ebc976b7fcc2 100644
--- a/drivers/net/ieee802154/mac802154_hwsim.c
+++ b/drivers/net/ieee802154/mac802154_hwsim.c
@@ -480,7 +480,7 @@ static int hwsim_del_edge_nl(struct sk_buff *msg, struct genl_info *info)
struct hwsim_edge *e;
u32 v0, v1;
- if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] &&
+ if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] ||
!info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
return -EINVAL;
@@ -715,6 +715,8 @@ static int hwsim_subscribe_all_others(struct hwsim_phy *phy)
return 0;
+sub_fail:
+ hwsim_edge_unsubscribe_me(phy);
me_fail:
rcu_read_lock();
list_for_each_entry_rcu(e, &phy->edges, list) {
@@ -722,8 +724,6 @@ me_fail:
hwsim_free_edge(e);
}
rcu_read_unlock();
-sub_fail:
- hwsim_edge_unsubscribe_me(phy);
return -ENOMEM;
}
@@ -824,12 +824,17 @@ err_pib:
static void hwsim_del(struct hwsim_phy *phy)
{
struct hwsim_pib *pib;
+ struct hwsim_edge *e;
hwsim_edge_unsubscribe_me(phy);
list_del(&phy->list);
rcu_read_lock();
+ list_for_each_entry_rcu(e, &phy->edges, list) {
+ list_del_rcu(&e->list);
+ hwsim_free_edge(e);
+ }
pib = rcu_dereference(phy->pib);
rcu_read_unlock();
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index ab7022582154..e9258a9f3702 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -16,10 +16,10 @@
by Patrick McHardy and then maintained by Andre Correa.
You need the tc action mirror or redirect to feed this device
- packets.
+ packets.
- Authors: Jamal Hadi Salim (2005)
+ Authors: Jamal Hadi Salim (2005)
*/
diff --git a/drivers/net/ipa/Makefile b/drivers/net/ipa/Makefile
index 1efe1a88104b..506f8d5cd4ee 100644
--- a/drivers/net/ipa/Makefile
+++ b/drivers/net/ipa/Makefile
@@ -7,8 +7,9 @@ ipa-y := ipa_main.o ipa_clock.o ipa_reg.o ipa_mem.o \
ipa_table.o ipa_interrupt.o gsi.o gsi_trans.o \
ipa_gsi.o ipa_smp2p.o ipa_uc.o \
ipa_endpoint.o ipa_cmd.o ipa_modem.o \
- ipa_resource.o ipa_qmi.o ipa_qmi_msg.o
+ ipa_resource.o ipa_qmi.o ipa_qmi_msg.o \
+ ipa_sysfs.o
-ipa-y += ipa_data-v3.5.1.o ipa_data-v4.2.o \
- ipa_data-v4.5.o ipa_data-v4.9.o \
- ipa_data-v4.11.o
+ipa-y += ipa_data-v3.1.o ipa_data-v3.5.1.o \
+ ipa_data-v4.2.o ipa_data-v4.5.o \
+ ipa_data-v4.9.o ipa_data-v4.11.o
diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c
index e374079603cf..427c68b2ad8f 100644
--- a/drivers/net/ipa/gsi.c
+++ b/drivers/net/ipa/gsi.c
@@ -210,13 +210,65 @@ static void gsi_irq_setup(struct gsi *gsi)
iowrite32(0, gsi->virt + GSI_CNTXT_GLOB_IRQ_EN_OFFSET);
iowrite32(0, gsi->virt + GSI_CNTXT_SRC_IEOB_IRQ_MSK_OFFSET);
- /* The inter-EE registers are in the non-adjusted address range */
- iowrite32(0, gsi->virt_raw + GSI_INTER_EE_SRC_CH_IRQ_MSK_OFFSET);
- iowrite32(0, gsi->virt_raw + GSI_INTER_EE_SRC_EV_CH_IRQ_MSK_OFFSET);
+ /* The inter-EE interrupts are not supported for IPA v3.0-v3.1 */
+ if (gsi->version > IPA_VERSION_3_1) {
+ u32 offset;
+
+ /* These registers are in the non-adjusted address range */
+ offset = GSI_INTER_EE_SRC_CH_IRQ_MSK_OFFSET;
+ iowrite32(0, gsi->virt_raw + offset);
+ offset = GSI_INTER_EE_SRC_EV_CH_IRQ_MSK_OFFSET;
+ iowrite32(0, gsi->virt_raw + offset);
+ }
iowrite32(0, gsi->virt + GSI_CNTXT_GSI_IRQ_EN_OFFSET);
}
+/* Get # supported channel and event rings; there is no gsi_ring_teardown() */
+static int gsi_ring_setup(struct gsi *gsi)
+{
+ struct device *dev = gsi->dev;
+ u32 count;
+ u32 val;
+
+ if (gsi->version < IPA_VERSION_3_5_1) {
+ /* No HW_PARAM_2 register prior to IPA v3.5.1, assume the max */
+ gsi->channel_count = GSI_CHANNEL_COUNT_MAX;
+ gsi->evt_ring_count = GSI_EVT_RING_COUNT_MAX;
+
+ return 0;
+ }
+
+ val = ioread32(gsi->virt + GSI_GSI_HW_PARAM_2_OFFSET);
+
+ count = u32_get_bits(val, NUM_CH_PER_EE_FMASK);
+ if (!count) {
+ dev_err(dev, "GSI reports zero channels supported\n");
+ return -EINVAL;
+ }
+ if (count > GSI_CHANNEL_COUNT_MAX) {
+ dev_warn(dev, "limiting to %u channels; hardware supports %u\n",
+ GSI_CHANNEL_COUNT_MAX, count);
+ count = GSI_CHANNEL_COUNT_MAX;
+ }
+ gsi->channel_count = count;
+
+ count = u32_get_bits(val, NUM_EV_PER_EE_FMASK);
+ if (!count) {
+ dev_err(dev, "GSI reports zero event rings supported\n");
+ return -EINVAL;
+ }
+ if (count > GSI_EVT_RING_COUNT_MAX) {
+ dev_warn(dev,
+ "limiting to %u event rings; hardware supports %u\n",
+ GSI_EVT_RING_COUNT_MAX, count);
+ count = GSI_EVT_RING_COUNT_MAX;
+ }
+ gsi->evt_ring_count = count;
+
+ return 0;
+}
+
/* Event ring commands are performed one at a time. Their completion
* is signaled by the event ring control GSI interrupt type, which is
* only enabled when we issue an event ring command. Only the event
@@ -1827,43 +1879,21 @@ static void gsi_channel_teardown(struct gsi *gsi)
/* Setup function for GSI. GSI firmware must be loaded and initialized */
int gsi_setup(struct gsi *gsi)
{
- struct device *dev = gsi->dev;
u32 val;
+ int ret;
/* Here is where we first touch the GSI hardware */
val = ioread32(gsi->virt + GSI_GSI_STATUS_OFFSET);
if (!(val & ENABLED_FMASK)) {
- dev_err(dev, "GSI has not been enabled\n");
+ dev_err(gsi->dev, "GSI has not been enabled\n");
return -EIO;
}
gsi_irq_setup(gsi); /* No matching teardown required */
- val = ioread32(gsi->virt + GSI_GSI_HW_PARAM_2_OFFSET);
-
- gsi->channel_count = u32_get_bits(val, NUM_CH_PER_EE_FMASK);
- if (!gsi->channel_count) {
- dev_err(dev, "GSI reports zero channels supported\n");
- return -EINVAL;
- }
- if (gsi->channel_count > GSI_CHANNEL_COUNT_MAX) {
- dev_warn(dev,
- "limiting to %u channels; hardware supports %u\n",
- GSI_CHANNEL_COUNT_MAX, gsi->channel_count);
- gsi->channel_count = GSI_CHANNEL_COUNT_MAX;
- }
-
- gsi->evt_ring_count = u32_get_bits(val, NUM_EV_PER_EE_FMASK);
- if (!gsi->evt_ring_count) {
- dev_err(dev, "GSI reports zero event rings supported\n");
- return -EINVAL;
- }
- if (gsi->evt_ring_count > GSI_EVT_RING_COUNT_MAX) {
- dev_warn(dev,
- "limiting to %u event rings; hardware supports %u\n",
- GSI_EVT_RING_COUNT_MAX, gsi->evt_ring_count);
- gsi->evt_ring_count = GSI_EVT_RING_COUNT_MAX;
- }
+ ret = gsi_ring_setup(gsi); /* No matching teardown required */
+ if (ret)
+ return ret;
/* Initialize the error log */
iowrite32(0, gsi->virt + GSI_ERROR_LOG_OFFSET);
diff --git a/drivers/net/ipa/gsi.h b/drivers/net/ipa/gsi.h
index d5996bdb20ef..81cd7b07f6e1 100644
--- a/drivers/net/ipa/gsi.h
+++ b/drivers/net/ipa/gsi.h
@@ -17,7 +17,7 @@
/* Maximum number of channels and event rings supported by the driver */
#define GSI_CHANNEL_COUNT_MAX 23
-#define GSI_EVT_RING_COUNT_MAX 20
+#define GSI_EVT_RING_COUNT_MAX 24
/* Maximum TLV FIFO size for a channel; 64 here is arbitrary (and high) */
#define GSI_TLV_MAX 64
diff --git a/drivers/net/ipa/gsi_reg.h b/drivers/net/ipa/gsi_reg.h
index cb42c5ae86fa..bf9593d9eaea 100644
--- a/drivers/net/ipa/gsi_reg.h
+++ b/drivers/net/ipa/gsi_reg.h
@@ -52,7 +52,8 @@
*/
#define GSI_EE_REG_ADJUST 0x0000d000 /* IPA v4.5+ */
-/* The two inter-EE IRQ register offsets are relative to gsi->virt_raw */
+/* The inter-EE IRQ registers are relative to gsi->virt_raw (IPA v3.5+) */
+
#define GSI_INTER_EE_SRC_CH_IRQ_MSK_OFFSET \
GSI_INTER_EE_N_SRC_CH_IRQ_MSK_OFFSET(GSI_EE_AP)
#define GSI_INTER_EE_N_SRC_CH_IRQ_MSK_OFFSET(ee) \
diff --git a/drivers/net/ipa/ipa_cmd.c b/drivers/net/ipa/ipa_cmd.c
index 525cdf28d9ea..af44ca41189e 100644
--- a/drivers/net/ipa/ipa_cmd.c
+++ b/drivers/net/ipa/ipa_cmd.c
@@ -200,41 +200,55 @@ bool ipa_cmd_table_valid(struct ipa *ipa, const struct ipa_mem *mem,
/* Validate the memory region that holds headers */
static bool ipa_cmd_header_valid(struct ipa *ipa)
{
- const struct ipa_mem *mem = &ipa->mem[IPA_MEM_MODEM_HEADER];
struct device *dev = &ipa->pdev->dev;
+ const struct ipa_mem *mem;
u32 offset_max;
u32 size_max;
+ u32 offset;
u32 size;
- /* In ipa_cmd_hdr_init_local_add() we record the offset and size
- * of the header table memory area. Make sure the offset and size
- * fit in the fields that need to hold them, and that the entire
- * range is within the overall IPA memory range.
+ /* In ipa_cmd_hdr_init_local_add() we record the offset and size of
+ * the header table memory area in an immediate command. Make sure
+ * the offset and size fit in the fields that need to hold them, and
+ * that the entire range is within the overall IPA memory range.
*/
offset_max = field_max(HDR_INIT_LOCAL_FLAGS_HDR_ADDR_FMASK);
- if (mem->offset > offset_max ||
- ipa->mem_offset > offset_max - mem->offset) {
+ size_max = field_max(HDR_INIT_LOCAL_FLAGS_TABLE_SIZE_FMASK);
+
+ /* The header memory area contains both the modem and AP header
+ * regions. The modem portion defines the address of the region.
+ */
+ mem = ipa_mem_find(ipa, IPA_MEM_MODEM_HEADER);
+ offset = mem->offset;
+ size = mem->size;
+
+ /* Make sure the offset fits in the IPA command */
+ if (offset > offset_max || ipa->mem_offset > offset_max - offset) {
dev_err(dev, "header table region offset too large\n");
dev_err(dev, " (0x%04x + 0x%04x > 0x%04x)\n",
- ipa->mem_offset, mem->offset, offset_max);
+ ipa->mem_offset, offset, offset_max);
return false;
}
- size_max = field_max(HDR_INIT_LOCAL_FLAGS_TABLE_SIZE_FMASK);
- size = ipa->mem[IPA_MEM_MODEM_HEADER].size;
- size += ipa->mem[IPA_MEM_AP_HEADER].size;
+ /* Add the size of the AP portion (if defined) to the combined size */
+ mem = ipa_mem_find(ipa, IPA_MEM_AP_HEADER);
+ if (mem)
+ size += mem->size;
+ /* Make sure the combined size fits in the IPA command */
if (size > size_max) {
dev_err(dev, "header table region size too large\n");
dev_err(dev, " (0x%04x > 0x%08x)\n", size, size_max);
return false;
}
- if (size > ipa->mem_size || mem->offset > ipa->mem_size - size) {
+
+ /* Make sure the entire combined area fits in IPA memory */
+ if (size > ipa->mem_size || offset > ipa->mem_size - size) {
dev_err(dev, "header table region out of range\n");
dev_err(dev, " (0x%04x + 0x%04x > 0x%04x)\n",
- mem->offset, size, ipa->mem_size);
+ offset, size, ipa->mem_size);
return false;
}
diff --git a/drivers/net/ipa/ipa_data-v3.1.c b/drivers/net/ipa/ipa_data-v3.1.c
new file mode 100644
index 000000000000..4c28189462a7
--- /dev/null
+++ b/drivers/net/ipa/ipa_data-v3.1.c
@@ -0,0 +1,533 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2019-2021 Linaro Ltd.
+ */
+
+#include <linux/log2.h>
+
+#include "gsi.h"
+#include "ipa_data.h"
+#include "ipa_endpoint.h"
+#include "ipa_mem.h"
+
+/** enum ipa_resource_type - IPA resource types for an SoC having IPA v3.1 */
+enum ipa_resource_type {
+ /* Source resource types; first must have value 0 */
+ IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS = 0,
+ IPA_RESOURCE_TYPE_SRC_HDR_SECTORS,
+ IPA_RESOURCE_TYPE_SRC_HDRI1_BUFFER,
+ IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS,
+ IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF,
+ IPA_RESOURCE_TYPE_SRC_HDRI2_BUFFERS,
+ IPA_RESOURCE_TYPE_SRC_HPS_DMARS,
+ IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES,
+
+ /* Destination resource types; first must have value 0 */
+ IPA_RESOURCE_TYPE_DST_DATA_SECTORS = 0,
+ IPA_RESOURCE_TYPE_DST_DATA_SECTOR_LISTS,
+ IPA_RESOURCE_TYPE_DST_DPS_DMARS,
+};
+
+/* Resource groups used for an SoC having IPA v3.1 */
+enum ipa_rsrc_group_id {
+ /* Source resource group identifiers */
+ IPA_RSRC_GROUP_SRC_UL = 0,
+ IPA_RSRC_GROUP_SRC_DL,
+ IPA_RSRC_GROUP_SRC_DIAG,
+ IPA_RSRC_GROUP_SRC_DMA,
+ IPA_RSRC_GROUP_SRC_UNUSED,
+ IPA_RSRC_GROUP_SRC_UC_RX_Q,
+ IPA_RSRC_GROUP_SRC_COUNT, /* Last in set; not a source group */
+
+ /* Destination resource group identifiers */
+ IPA_RSRC_GROUP_DST_UL = 0,
+ IPA_RSRC_GROUP_DST_DL,
+ IPA_RSRC_GROUP_DST_DIAG_DPL,
+ IPA_RSRC_GROUP_DST_DMA,
+ IPA_RSRC_GROUP_DST_Q6ZIP_GENERAL,
+ IPA_RSRC_GROUP_DST_Q6ZIP_ENGINE,
+ IPA_RSRC_GROUP_DST_COUNT, /* Last; not a destination group */
+};
+
+/* QSB configuration data for an SoC having IPA v3.1 */
+static const struct ipa_qsb_data ipa_qsb_data[] = {
+ [IPA_QSB_MASTER_DDR] = {
+ .max_writes = 8,
+ .max_reads = 8,
+ },
+ [IPA_QSB_MASTER_PCIE] = {
+ .max_writes = 2,
+ .max_reads = 8,
+ },
+};
+
+/* Endpoint data for an SoC having IPA v3.1 */
+static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
+ [IPA_ENDPOINT_AP_COMMAND_TX] = {
+ .ee_id = GSI_EE_AP,
+ .channel_id = 6,
+ .endpoint_id = 22,
+ .toward_ipa = true,
+ .channel = {
+ .tre_count = 256,
+ .event_count = 256,
+ .tlv_count = 18,
+ },
+ .endpoint = {
+ .config = {
+ .resource_group = IPA_RSRC_GROUP_SRC_UL,
+ .dma_mode = true,
+ .dma_endpoint = IPA_ENDPOINT_AP_LAN_RX,
+ .tx = {
+ .seq_type = IPA_SEQ_DMA,
+ },
+ },
+ },
+ },
+ [IPA_ENDPOINT_AP_LAN_RX] = {
+ .ee_id = GSI_EE_AP,
+ .channel_id = 7,
+ .endpoint_id = 15,
+ .toward_ipa = false,
+ .channel = {
+ .tre_count = 256,
+ .event_count = 256,
+ .tlv_count = 8,
+ },
+ .endpoint = {
+ .config = {
+ .resource_group = IPA_RSRC_GROUP_SRC_UL,
+ .aggregation = true,
+ .status_enable = true,
+ .rx = {
+ .pad_align = ilog2(sizeof(u32)),
+ },
+ },
+ },
+ },
+ [IPA_ENDPOINT_AP_MODEM_TX] = {
+ .ee_id = GSI_EE_AP,
+ .channel_id = 5,
+ .endpoint_id = 3,
+ .toward_ipa = true,
+ .channel = {
+ .tre_count = 512,
+ .event_count = 512,
+ .tlv_count = 16,
+ },
+ .endpoint = {
+ .filter_support = true,
+ .config = {
+ .resource_group = IPA_RSRC_GROUP_SRC_UL,
+ .checksum = true,
+ .qmap = true,
+ .status_enable = true,
+ .tx = {
+ .seq_type = IPA_SEQ_2_PASS_SKIP_LAST_UC,
+ .status_endpoint =
+ IPA_ENDPOINT_MODEM_AP_RX,
+ },
+ },
+ },
+ },
+ [IPA_ENDPOINT_AP_MODEM_RX] = {
+ .ee_id = GSI_EE_AP,
+ .channel_id = 8,
+ .endpoint_id = 16,
+ .toward_ipa = false,
+ .channel = {
+ .tre_count = 256,
+ .event_count = 256,
+ .tlv_count = 8,
+ },
+ .endpoint = {
+ .config = {
+ .resource_group = IPA_RSRC_GROUP_DST_DL,
+ .checksum = true,
+ .qmap = true,
+ .aggregation = true,
+ .rx = {
+ .aggr_close_eof = true,
+ },
+ },
+ },
+ },
+ [IPA_ENDPOINT_MODEM_LAN_TX] = {
+ .ee_id = GSI_EE_MODEM,
+ .channel_id = 4,
+ .endpoint_id = 9,
+ .toward_ipa = true,
+ .endpoint = {
+ .filter_support = true,
+ },
+ },
+ [IPA_ENDPOINT_MODEM_AP_TX] = {
+ .ee_id = GSI_EE_MODEM,
+ .channel_id = 0,
+ .endpoint_id = 5,
+ .toward_ipa = true,
+ .endpoint = {
+ .filter_support = true,
+ },
+ },
+ [IPA_ENDPOINT_MODEM_AP_RX] = {
+ .ee_id = GSI_EE_MODEM,
+ .channel_id = 5,
+ .endpoint_id = 18,
+ .toward_ipa = false,
+ },
+};
+
+/* Source resource configuration data for an SoC having IPA v3.1 */
+static const struct ipa_resource ipa_resource_src[] = {
+ [IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS] = {
+ .limits[IPA_RSRC_GROUP_SRC_UL] = {
+ .min = 3, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DL] = {
+ .min = 3, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DIAG] = {
+ .min = 1, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DMA] = {
+ .min = 1, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
+ .min = 2, .max = 255,
+ },
+ },
+ [IPA_RESOURCE_TYPE_SRC_HDR_SECTORS] = {
+ .limits[IPA_RSRC_GROUP_SRC_UL] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DL] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DIAG] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DMA] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
+ .min = 0, .max = 255,
+ },
+ },
+ [IPA_RESOURCE_TYPE_SRC_HDRI1_BUFFER] = {
+ .limits[IPA_RSRC_GROUP_SRC_UL] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DL] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DIAG] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DMA] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
+ .min = 0, .max = 255,
+ },
+ },
+ [IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS] = {
+ .limits[IPA_RSRC_GROUP_SRC_UL] = {
+ .min = 14, .max = 14,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DL] = {
+ .min = 16, .max = 16,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DIAG] = {
+ .min = 5, .max = 5,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DMA] = {
+ .min = 5, .max = 5,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
+ .min = 8, .max = 8,
+ },
+ },
+ [IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF] = {
+ .limits[IPA_RSRC_GROUP_SRC_UL] = {
+ .min = 19, .max = 19,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DL] = {
+ .min = 26, .max = 26,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DIAG] = {
+ .min = 5, .max = 5, /* 3 downstream */
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DMA] = {
+ .min = 5, .max = 5, /* 7 downstream */
+ },
+ .limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
+ .min = 8, .max = 8,
+ },
+ },
+ [IPA_RESOURCE_TYPE_SRC_HDRI2_BUFFERS] = {
+ .limits[IPA_RSRC_GROUP_SRC_UL] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DL] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DIAG] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DMA] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
+ .min = 0, .max = 255,
+ },
+ },
+ [IPA_RESOURCE_TYPE_SRC_HPS_DMARS] = {
+ .limits[IPA_RSRC_GROUP_SRC_UL] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DL] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DIAG] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DMA] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
+ .min = 0, .max = 255,
+ },
+ },
+ [IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES] = {
+ .limits[IPA_RSRC_GROUP_SRC_UL] = {
+ .min = 19, .max = 19,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DL] = {
+ .min = 26, .max = 26,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DIAG] = {
+ .min = 5, .max = 5,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DMA] = {
+ .min = 5, .max = 5,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
+ .min = 8, .max = 8,
+ },
+ },
+};
+
+/* Destination resource configuration data for an SoC having IPA v3.1 */
+static const struct ipa_resource ipa_resource_dst[] = {
+ [IPA_RESOURCE_TYPE_DST_DATA_SECTORS] = {
+ .limits[IPA_RSRC_GROUP_DST_UL] = {
+ .min = 3, .max = 3, /* 2 downstream */
+ },
+ .limits[IPA_RSRC_GROUP_DST_DL] = {
+ .min = 3, .max = 3,
+ },
+ .limits[IPA_RSRC_GROUP_DST_DIAG_DPL] = {
+ .min = 1, .max = 1, /* 0 downstream */
+ },
+ /* IPA_RSRC_GROUP_DST_DMA uses 2 downstream */
+ .limits[IPA_RSRC_GROUP_DST_Q6ZIP_GENERAL] = {
+ .min = 3, .max = 3,
+ },
+ .limits[IPA_RSRC_GROUP_DST_Q6ZIP_ENGINE] = {
+ .min = 3, .max = 3,
+ },
+ },
+ [IPA_RESOURCE_TYPE_DST_DATA_SECTOR_LISTS] = {
+ .limits[IPA_RSRC_GROUP_DST_UL] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_DST_DL] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_DST_DIAG_DPL] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_DST_DMA] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_DST_Q6ZIP_GENERAL] = {
+ .min = 0, .max = 255,
+ },
+ .limits[IPA_RSRC_GROUP_DST_Q6ZIP_ENGINE] = {
+ .min = 0, .max = 255,
+ },
+ },
+ [IPA_RESOURCE_TYPE_DST_DPS_DMARS] = {
+ .limits[IPA_RSRC_GROUP_DST_UL] = {
+ .min = 1, .max = 1,
+ },
+ .limits[IPA_RSRC_GROUP_DST_DL] = {
+ .min = 1, .max = 1,
+ },
+ .limits[IPA_RSRC_GROUP_DST_DIAG_DPL] = {
+ .min = 1, .max = 1,
+ },
+ .limits[IPA_RSRC_GROUP_DST_DMA] = {
+ .min = 1, .max = 1,
+ },
+ .limits[IPA_RSRC_GROUP_DST_Q6ZIP_GENERAL] = {
+ .min = 1, .max = 1,
+ },
+ },
+};
+
+/* Resource configuration data for an SoC having IPA v3.1 */
+static const struct ipa_resource_data ipa_resource_data = {
+ .rsrc_group_src_count = IPA_RSRC_GROUP_SRC_COUNT,
+ .rsrc_group_dst_count = IPA_RSRC_GROUP_DST_COUNT,
+ .resource_src_count = ARRAY_SIZE(ipa_resource_src),
+ .resource_src = ipa_resource_src,
+ .resource_dst_count = ARRAY_SIZE(ipa_resource_dst),
+ .resource_dst = ipa_resource_dst,
+};
+
+/* IPA-resident memory region data for an SoC having IPA v3.1 */
+static const struct ipa_mem ipa_mem_local_data[] = {
+ {
+ .id = IPA_MEM_UC_SHARED,
+ .offset = 0x0000,
+ .size = 0x0080,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_UC_INFO,
+ .offset = 0x0080,
+ .size = 0x0200,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_V4_FILTER_HASHED,
+ .offset = 0x0288,
+ .size = 0x0078,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_V4_FILTER,
+ .offset = 0x0308,
+ .size = 0x0078,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_V6_FILTER_HASHED,
+ .offset = 0x0388,
+ .size = 0x0078,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_V6_FILTER,
+ .offset = 0x0408,
+ .size = 0x0078,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_V4_ROUTE_HASHED,
+ .offset = 0x0488,
+ .size = 0x0078,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_V4_ROUTE,
+ .offset = 0x0508,
+ .size = 0x0078,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_V6_ROUTE_HASHED,
+ .offset = 0x0588,
+ .size = 0x0078,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_V6_ROUTE,
+ .offset = 0x0608,
+ .size = 0x0078,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_MODEM_HEADER,
+ .offset = 0x0688,
+ .size = 0x0140,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_MODEM_PROC_CTX,
+ .offset = 0x07d0,
+ .size = 0x0200,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_AP_PROC_CTX,
+ .offset = 0x09d0,
+ .size = 0x0200,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_MODEM,
+ .offset = 0x0bd8,
+ .size = 0x1424,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_END_MARKER,
+ .offset = 0x2000,
+ .size = 0,
+ .canary_count = 1,
+ },
+};
+
+/* Memory configuration data for an SoC having IPA v3.1 */
+static const struct ipa_mem_data ipa_mem_data = {
+ .local_count = ARRAY_SIZE(ipa_mem_local_data),
+ .local = ipa_mem_local_data,
+ .imem_addr = 0x146bd000,
+ .imem_size = 0x00002000,
+ .smem_id = 497,
+ .smem_size = 0x00002000,
+};
+
+/* Interconnect bandwidths are in 1000 byte/second units */
+static const struct ipa_interconnect_data ipa_interconnect_data[] = {
+ {
+ .name = "memory",
+ .peak_bandwidth = 640000, /* 640 MBps */
+ .average_bandwidth = 80000, /* 80 MBps */
+ },
+ {
+ .name = "imem",
+ .peak_bandwidth = 640000, /* 640 MBps */
+ .average_bandwidth = 80000, /* 80 MBps */
+ },
+ /* Average bandwidth is unused for the next interconnect */
+ {
+ .name = "config",
+ .peak_bandwidth = 80000, /* 80 MBps */
+ .average_bandwidth = 0, /* unused */
+ },
+};
+
+/* Clock and interconnect configuration data for an SoC having IPA v3.1 */
+static const struct ipa_clock_data ipa_clock_data = {
+ .core_clock_rate = 16 * 1000 * 1000, /* Hz */
+ .interconnect_count = ARRAY_SIZE(ipa_interconnect_data),
+ .interconnect_data = ipa_interconnect_data,
+};
+
+/* Configuration data for an SoC having IPA v3.1 */
+const struct ipa_data ipa_data_v3_1 = {
+ .version = IPA_VERSION_3_1,
+ .backward_compat = BCR_CMDQ_L_LACK_ONE_ENTRY_FMASK,
+ .qsb_count = ARRAY_SIZE(ipa_qsb_data),
+ .qsb_data = ipa_qsb_data,
+ .endpoint_count = ARRAY_SIZE(ipa_gsi_endpoint_data),
+ .endpoint_data = ipa_gsi_endpoint_data,
+ .resource_data = &ipa_resource_data,
+ .mem_data = &ipa_mem_data,
+ .clock_data = &ipa_clock_data,
+};
diff --git a/drivers/net/ipa/ipa_data-v3.5.1.c b/drivers/net/ipa/ipa_data-v3.5.1.c
index ead1a82f32f5..af536ef8c120 100644
--- a/drivers/net/ipa/ipa_data-v3.5.1.c
+++ b/drivers/net/ipa/ipa_data-v3.5.1.c
@@ -271,77 +271,92 @@ static const struct ipa_resource_data ipa_resource_data = {
/* IPA-resident memory region data for an SoC having IPA v3.5.1 */
static const struct ipa_mem ipa_mem_local_data[] = {
- [IPA_MEM_UC_SHARED] = {
+ {
+ .id = IPA_MEM_UC_SHARED,
.offset = 0x0000,
.size = 0x0080,
.canary_count = 0,
},
- [IPA_MEM_UC_INFO] = {
+ {
+ .id = IPA_MEM_UC_INFO,
.offset = 0x0080,
.size = 0x0200,
.canary_count = 0,
},
- [IPA_MEM_V4_FILTER_HASHED] = {
+ {
+ .id = IPA_MEM_V4_FILTER_HASHED,
.offset = 0x0288,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V4_FILTER] = {
+ {
+ .id = IPA_MEM_V4_FILTER,
.offset = 0x0308,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_FILTER_HASHED] = {
+ {
+ .id = IPA_MEM_V6_FILTER_HASHED,
.offset = 0x0388,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_FILTER] = {
+ {
+ .id = IPA_MEM_V6_FILTER,
.offset = 0x0408,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V4_ROUTE_HASHED] = {
+ {
+ .id = IPA_MEM_V4_ROUTE_HASHED,
.offset = 0x0488,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V4_ROUTE] = {
+ {
+ .id = IPA_MEM_V4_ROUTE,
.offset = 0x0508,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_ROUTE_HASHED] = {
+ {
+ .id = IPA_MEM_V6_ROUTE_HASHED,
.offset = 0x0588,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_ROUTE] = {
+ {
+ .id = IPA_MEM_V6_ROUTE,
.offset = 0x0608,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_MODEM_HEADER] = {
+ {
+ .id = IPA_MEM_MODEM_HEADER,
.offset = 0x0688,
.size = 0x0140,
.canary_count = 2,
},
- [IPA_MEM_MODEM_PROC_CTX] = {
+ {
+ .id = IPA_MEM_MODEM_PROC_CTX,
.offset = 0x07d0,
.size = 0x0200,
.canary_count = 2,
},
- [IPA_MEM_AP_PROC_CTX] = {
+ {
+ .id = IPA_MEM_AP_PROC_CTX,
.offset = 0x09d0,
.size = 0x0200,
.canary_count = 0,
},
- [IPA_MEM_MODEM] = {
+ {
+ .id = IPA_MEM_MODEM,
.offset = 0x0bd8,
.size = 0x1024,
.canary_count = 0,
},
- [IPA_MEM_UC_EVENT_RING] = {
+ {
+ .id = IPA_MEM_UC_EVENT_RING,
.offset = 0x1c00,
.size = 0x0400,
.canary_count = 1,
diff --git a/drivers/net/ipa/ipa_data-v4.11.c b/drivers/net/ipa/ipa_data-v4.11.c
index 05806ceae8b5..9353efbd504f 100644
--- a/drivers/net/ipa/ipa_data-v4.11.c
+++ b/drivers/net/ipa/ipa_data-v4.11.c
@@ -220,112 +220,134 @@ static const struct ipa_resource_data ipa_resource_data = {
/* IPA-resident memory region data for an SoC having IPA v4.11 */
static const struct ipa_mem ipa_mem_local_data[] = {
- [IPA_MEM_UC_SHARED] = {
+ {
+ .id = IPA_MEM_UC_SHARED,
.offset = 0x0000,
.size = 0x0080,
.canary_count = 0,
},
- [IPA_MEM_UC_INFO] = {
+ {
+ .id = IPA_MEM_UC_INFO,
.offset = 0x0080,
.size = 0x0200,
.canary_count = 0,
},
- [IPA_MEM_V4_FILTER_HASHED] = {
+ {
+ .id = IPA_MEM_V4_FILTER_HASHED,
.offset = 0x0288,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V4_FILTER] = {
+ {
+ .id = IPA_MEM_V4_FILTER,
.offset = 0x0308,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_FILTER_HASHED] = {
+ {
+ .id = IPA_MEM_V6_FILTER_HASHED,
.offset = 0x0388,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_FILTER] = {
+ {
+ .id = IPA_MEM_V6_FILTER,
.offset = 0x0408,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V4_ROUTE_HASHED] = {
+ {
+ .id = IPA_MEM_V4_ROUTE_HASHED,
.offset = 0x0488,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V4_ROUTE] = {
+ {
+ .id = IPA_MEM_V4_ROUTE,
.offset = 0x0508,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_ROUTE_HASHED] = {
+ {
+ .id = IPA_MEM_V6_ROUTE_HASHED,
.offset = 0x0588,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_ROUTE] = {
+ {
+ .id = IPA_MEM_V6_ROUTE,
.offset = 0x0608,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_MODEM_HEADER] = {
+ {
+ .id = IPA_MEM_MODEM_HEADER,
.offset = 0x0688,
.size = 0x0240,
.canary_count = 2,
},
- [IPA_MEM_AP_HEADER] = {
+ {
+ .id = IPA_MEM_AP_HEADER,
.offset = 0x08c8,
.size = 0x0200,
.canary_count = 0,
},
- [IPA_MEM_MODEM_PROC_CTX] = {
+ {
+ .id = IPA_MEM_MODEM_PROC_CTX,
.offset = 0x0ad0,
.size = 0x0200,
.canary_count = 2,
},
- [IPA_MEM_AP_PROC_CTX] = {
+ {
+ .id = IPA_MEM_AP_PROC_CTX,
.offset = 0x0cd0,
.size = 0x0200,
.canary_count = 0,
},
- [IPA_MEM_NAT_TABLE] = {
+ {
+ .id = IPA_MEM_NAT_TABLE,
.offset = 0x0ee0,
.size = 0x0d00,
.canary_count = 4,
},
- [IPA_MEM_PDN_CONFIG] = {
+ {
+ .id = IPA_MEM_PDN_CONFIG,
.offset = 0x1be8,
.size = 0x0050,
.canary_count = 0,
},
- [IPA_MEM_STATS_QUOTA_MODEM] = {
+ {
+ .id = IPA_MEM_STATS_QUOTA_MODEM,
.offset = 0x1c40,
.size = 0x0030,
.canary_count = 4,
},
- [IPA_MEM_STATS_QUOTA_AP] = {
+ {
+ .id = IPA_MEM_STATS_QUOTA_AP,
.offset = 0x1c70,
.size = 0x0048,
.canary_count = 0,
},
- [IPA_MEM_STATS_TETHERING] = {
+ {
+ .id = IPA_MEM_STATS_TETHERING,
.offset = 0x1cb8,
.size = 0x0238,
.canary_count = 0,
},
- [IPA_MEM_STATS_DROP] = {
+ {
+ .id = IPA_MEM_STATS_DROP,
.offset = 0x1ef0,
.size = 0x0020,
.canary_count = 0,
},
- [IPA_MEM_MODEM] = {
+ {
+ .id = IPA_MEM_MODEM,
.offset = 0x1f18,
.size = 0x100c,
.canary_count = 2,
},
- [IPA_MEM_UC_EVENT_RING] = {
+ {
+ .id = IPA_MEM_END_MARKER,
.offset = 0x3000,
.size = 0x0000,
.canary_count = 1,
diff --git a/drivers/net/ipa/ipa_data-v4.2.c b/drivers/net/ipa/ipa_data-v4.2.c
index 8744f19c6401..3b09b7baa95f 100644
--- a/drivers/net/ipa/ipa_data-v4.2.c
+++ b/drivers/net/ipa/ipa_data-v4.2.c
@@ -219,92 +219,110 @@ static const struct ipa_resource_data ipa_resource_data = {
/* IPA-resident memory region data for an SoC having IPA v4.2 */
static const struct ipa_mem ipa_mem_local_data[] = {
- [IPA_MEM_UC_SHARED] = {
+ {
+ .id = IPA_MEM_UC_SHARED,
.offset = 0x0000,
.size = 0x0080,
.canary_count = 0,
},
- [IPA_MEM_UC_INFO] = {
+ {
+ .id = IPA_MEM_UC_INFO,
.offset = 0x0080,
.size = 0x0200,
.canary_count = 0,
},
- [IPA_MEM_V4_FILTER_HASHED] = {
+ {
+ .id = IPA_MEM_V4_FILTER_HASHED,
.offset = 0x0288,
.size = 0,
.canary_count = 2,
},
- [IPA_MEM_V4_FILTER] = {
+ {
+ .id = IPA_MEM_V4_FILTER,
.offset = 0x0290,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_FILTER_HASHED] = {
+ {
+ .id = IPA_MEM_V6_FILTER_HASHED,
.offset = 0x0310,
.size = 0,
.canary_count = 2,
},
- [IPA_MEM_V6_FILTER] = {
+ {
+ .id = IPA_MEM_V6_FILTER,
.offset = 0x0318,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V4_ROUTE_HASHED] = {
+ {
+ .id = IPA_MEM_V4_ROUTE_HASHED,
.offset = 0x0398,
.size = 0,
.canary_count = 2,
},
- [IPA_MEM_V4_ROUTE] = {
+ {
+ .id = IPA_MEM_V4_ROUTE,
.offset = 0x03a0,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_ROUTE_HASHED] = {
+ {
+ .id = IPA_MEM_V6_ROUTE_HASHED,
.offset = 0x0420,
.size = 0,
.canary_count = 2,
},
- [IPA_MEM_V6_ROUTE] = {
+ {
+ .id = IPA_MEM_V6_ROUTE,
.offset = 0x0428,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_MODEM_HEADER] = {
+ {
+ .id = IPA_MEM_MODEM_HEADER,
.offset = 0x04a8,
.size = 0x0140,
.canary_count = 2,
},
- [IPA_MEM_MODEM_PROC_CTX] = {
+ {
+ .id = IPA_MEM_MODEM_PROC_CTX,
.offset = 0x05f0,
.size = 0x0200,
.canary_count = 2,
},
- [IPA_MEM_AP_PROC_CTX] = {
+ {
+ .id = IPA_MEM_AP_PROC_CTX,
.offset = 0x07f0,
.size = 0x0200,
.canary_count = 0,
},
- [IPA_MEM_PDN_CONFIG] = {
+ {
+ .id = IPA_MEM_PDN_CONFIG,
.offset = 0x09f8,
.size = 0x0050,
.canary_count = 2,
},
- [IPA_MEM_STATS_QUOTA_MODEM] = {
+ {
+ .id = IPA_MEM_STATS_QUOTA_MODEM,
.offset = 0x0a50,
.size = 0x0060,
.canary_count = 2,
},
- [IPA_MEM_STATS_TETHERING] = {
+ {
+ .id = IPA_MEM_STATS_TETHERING,
.offset = 0x0ab0,
.size = 0x0140,
.canary_count = 0,
},
- [IPA_MEM_MODEM] = {
+ {
+ .id = IPA_MEM_MODEM,
.offset = 0x0bf0,
.size = 0x140c,
.canary_count = 0,
},
- [IPA_MEM_UC_EVENT_RING] = {
+ {
+ .id = IPA_MEM_END_MARKER,
.offset = 0x2000,
.size = 0,
.canary_count = 1,
diff --git a/drivers/net/ipa/ipa_data-v4.5.c b/drivers/net/ipa/ipa_data-v4.5.c
index 5f67a3a909ee..a99b6478fa3a 100644
--- a/drivers/net/ipa/ipa_data-v4.5.c
+++ b/drivers/net/ipa/ipa_data-v4.5.c
@@ -265,117 +265,140 @@ static const struct ipa_resource_data ipa_resource_data = {
/* IPA-resident memory region data for an SoC having IPA v4.5 */
static const struct ipa_mem ipa_mem_local_data[] = {
- [IPA_MEM_UC_SHARED] = {
+ {
+ .id = IPA_MEM_UC_SHARED,
.offset = 0x0000,
.size = 0x0080,
.canary_count = 0,
},
- [IPA_MEM_UC_INFO] = {
+ {
+ .id = IPA_MEM_UC_INFO,
.offset = 0x0080,
.size = 0x0200,
.canary_count = 0,
},
- [IPA_MEM_V4_FILTER_HASHED] = {
+ {
+ .id = IPA_MEM_V4_FILTER_HASHED,
.offset = 0x0288,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V4_FILTER] = {
+ {
+ .id = IPA_MEM_V4_FILTER,
.offset = 0x0308,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_FILTER_HASHED] = {
+ {
+ .id = IPA_MEM_V6_FILTER_HASHED,
.offset = 0x0388,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_FILTER] = {
+ {
+ .id = IPA_MEM_V6_FILTER,
.offset = 0x0408,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V4_ROUTE_HASHED] = {
+ {
+ .id = IPA_MEM_V4_ROUTE_HASHED,
.offset = 0x0488,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V4_ROUTE] = {
+ {
+ .id = IPA_MEM_V4_ROUTE,
.offset = 0x0508,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_ROUTE_HASHED] = {
+ {
+ .id = IPA_MEM_V6_ROUTE_HASHED,
.offset = 0x0588,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_ROUTE] = {
+ {
+ .id = IPA_MEM_V6_ROUTE,
.offset = 0x0608,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_MODEM_HEADER] = {
+ {
+ .id = IPA_MEM_MODEM_HEADER,
.offset = 0x0688,
.size = 0x0240,
.canary_count = 2,
},
- [IPA_MEM_AP_HEADER] = {
+ {
+ .id = IPA_MEM_AP_HEADER,
.offset = 0x08c8,
.size = 0x0200,
.canary_count = 0,
},
- [IPA_MEM_MODEM_PROC_CTX] = {
+ {
+ .id = IPA_MEM_MODEM_PROC_CTX,
.offset = 0x0ad0,
.size = 0x0b20,
.canary_count = 2,
},
- [IPA_MEM_AP_PROC_CTX] = {
+ {
+ .id = IPA_MEM_AP_PROC_CTX,
.offset = 0x15f0,
.size = 0x0200,
.canary_count = 0,
},
- [IPA_MEM_NAT_TABLE] = {
+ {
+ .id = IPA_MEM_NAT_TABLE,
.offset = 0x1800,
.size = 0x0d00,
.canary_count = 4,
},
- [IPA_MEM_STATS_QUOTA_MODEM] = {
+ {
+ .id = IPA_MEM_STATS_QUOTA_MODEM,
.offset = 0x2510,
.size = 0x0030,
.canary_count = 4,
},
- [IPA_MEM_STATS_QUOTA_AP] = {
+ {
+ .id = IPA_MEM_STATS_QUOTA_AP,
.offset = 0x2540,
.size = 0x0048,
.canary_count = 0,
},
- [IPA_MEM_STATS_TETHERING] = {
+ {
+ .id = IPA_MEM_STATS_TETHERING,
.offset = 0x2588,
.size = 0x0238,
.canary_count = 0,
},
- [IPA_MEM_STATS_FILTER_ROUTE] = {
+ {
+ .id = IPA_MEM_STATS_FILTER_ROUTE,
.offset = 0x27c0,
.size = 0x0800,
.canary_count = 0,
},
- [IPA_MEM_STATS_DROP] = {
+ {
+ .id = IPA_MEM_STATS_DROP,
.offset = 0x2fc0,
.size = 0x0020,
.canary_count = 0,
},
- [IPA_MEM_MODEM] = {
+ {
+ .id = IPA_MEM_MODEM,
.offset = 0x2fe8,
.size = 0x0800,
.canary_count = 2,
},
- [IPA_MEM_UC_EVENT_RING] = {
+ {
+ .id = IPA_MEM_UC_EVENT_RING,
.offset = 0x3800,
.size = 0x1000,
.canary_count = 1,
},
- [IPA_MEM_PDN_CONFIG] = {
+ {
+ .id = IPA_MEM_PDN_CONFIG,
.offset = 0x4800,
.size = 0x0050,
.canary_count = 0,
diff --git a/drivers/net/ipa/ipa_data-v4.9.c b/drivers/net/ipa/ipa_data-v4.9.c
index e41be790f45e..798d43e1eb13 100644
--- a/drivers/net/ipa/ipa_data-v4.9.c
+++ b/drivers/net/ipa/ipa_data-v4.9.c
@@ -263,116 +263,140 @@ static const struct ipa_resource_data ipa_resource_data = {
/* IPA-resident memory region data for an SoC having IPA v4.9 */
static const struct ipa_mem ipa_mem_local_data[] = {
- [IPA_MEM_UC_SHARED] = {
+ {
+ .id = IPA_MEM_UC_SHARED,
.offset = 0x0000,
.size = 0x0080,
.canary_count = 0,
},
- [IPA_MEM_UC_INFO] = {
+ {
+ .id = IPA_MEM_UC_INFO,
.offset = 0x0080,
.size = 0x0200,
.canary_count = 0,
},
- [IPA_MEM_V4_FILTER_HASHED] = { .offset = 0x0288,
+ {
+ .id = IPA_MEM_V4_FILTER_HASHED,
+ .offset = 0x0288,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V4_FILTER] = {
+ {
+ .id = IPA_MEM_V4_FILTER,
.offset = 0x0308,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_FILTER_HASHED] = {
+ {
+ .id = IPA_MEM_V6_FILTER_HASHED,
.offset = 0x0388,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_FILTER] = {
+ {
+ .id = IPA_MEM_V6_FILTER,
.offset = 0x0408,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V4_ROUTE_HASHED] = {
+ {
+ .id = IPA_MEM_V4_ROUTE_HASHED,
.offset = 0x0488,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V4_ROUTE] = {
+ {
+ .id = IPA_MEM_V4_ROUTE,
.offset = 0x0508,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_ROUTE_HASHED] = {
+ {
+ .id = IPA_MEM_V6_ROUTE_HASHED,
.offset = 0x0588,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_V6_ROUTE] = {
+ {
+ .id = IPA_MEM_V6_ROUTE,
.offset = 0x0608,
.size = 0x0078,
.canary_count = 2,
},
- [IPA_MEM_MODEM_HEADER] = {
+ {
+ .id = IPA_MEM_MODEM_HEADER,
.offset = 0x0688,
.size = 0x0240,
.canary_count = 2,
},
- [IPA_MEM_AP_HEADER] = {
+ {
+ .id = IPA_MEM_AP_HEADER,
.offset = 0x08c8,
.size = 0x0200,
.canary_count = 0,
},
- [IPA_MEM_MODEM_PROC_CTX] = {
+ {
+ .id = IPA_MEM_MODEM_PROC_CTX,
.offset = 0x0ad0,
.size = 0x0b20,
.canary_count = 2,
},
- [IPA_MEM_AP_PROC_CTX] = {
+ {
+ .id = IPA_MEM_AP_PROC_CTX,
.offset = 0x15f0,
.size = 0x0200,
.canary_count = 0,
},
- [IPA_MEM_NAT_TABLE] = {
+ {
+ .id = IPA_MEM_NAT_TABLE,
.offset = 0x1800,
.size = 0x0d00,
.canary_count = 4,
},
- [IPA_MEM_STATS_QUOTA_MODEM] = {
+ {
+ .id = IPA_MEM_STATS_QUOTA_MODEM,
.offset = 0x2510,
.size = 0x0030,
.canary_count = 4,
},
- [IPA_MEM_STATS_QUOTA_AP] = {
+ {
+ .id = IPA_MEM_STATS_QUOTA_AP,
.offset = 0x2540,
.size = 0x0048,
.canary_count = 0,
},
- [IPA_MEM_STATS_TETHERING] = {
+ {
+ .id = IPA_MEM_STATS_TETHERING,
.offset = 0x2588,
.size = 0x0238,
.canary_count = 0,
},
- [IPA_MEM_STATS_FILTER_ROUTE] = {
+ {
+ .id = IPA_MEM_STATS_FILTER_ROUTE,
.offset = 0x27c0,
.size = 0x0800,
.canary_count = 0,
},
- [IPA_MEM_STATS_DROP] = {
+ {
+ .id = IPA_MEM_STATS_DROP,
.offset = 0x2fc0,
.size = 0x0020,
.canary_count = 0,
},
- [IPA_MEM_MODEM] = {
+ {
+ .id = IPA_MEM_MODEM,
.offset = 0x2fe8,
.size = 0x0800,
.canary_count = 2,
},
- [IPA_MEM_UC_EVENT_RING] = {
+ {
+ .id = IPA_MEM_UC_EVENT_RING,
.offset = 0x3800,
.size = 0x1000,
.canary_count = 1,
},
- [IPA_MEM_PDN_CONFIG] = {
+ {
+ .id = IPA_MEM_PDN_CONFIG,
.offset = 0x4800,
.size = 0x0050,
.canary_count = 0,
diff --git a/drivers/net/ipa/ipa_data.h b/drivers/net/ipa/ipa_data.h
index 5c4c8d72d7d8..5bc244c8f94e 100644
--- a/drivers/net/ipa/ipa_data.h
+++ b/drivers/net/ipa/ipa_data.h
@@ -300,6 +300,7 @@ struct ipa_data {
const struct ipa_clock_data *clock_data;
};
+extern const struct ipa_data ipa_data_v3_1;
extern const struct ipa_data ipa_data_v3_5_1;
extern const struct ipa_data ipa_data_v4_2;
extern const struct ipa_data ipa_data_v4_5;
diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c
index ccc99ad983eb..ab02669bae4e 100644
--- a/drivers/net/ipa/ipa_endpoint.c
+++ b/drivers/net/ipa/ipa_endpoint.c
@@ -75,8 +75,6 @@ struct ipa_status {
#define IPA_STATUS_FLAGS1_RT_RULE_ID_FMASK GENMASK(31, 22)
#define IPA_STATUS_FLAGS2_TAG_FMASK GENMASK_ULL(63, 16)
-#ifdef IPA_VALIDATE
-
static bool ipa_endpoint_data_valid_one(struct ipa *ipa, u32 count,
const struct ipa_gsi_endpoint_data *all_data,
const struct ipa_gsi_endpoint_data *data)
@@ -88,11 +86,6 @@ static bool ipa_endpoint_data_valid_one(struct ipa *ipa, u32 count,
if (ipa_gsi_endpoint_data_empty(data))
return true;
- /* IPA v4.5+ uses checksum offload, not yet supported by RMNet */
- if (ipa->version >= IPA_VERSION_4_5)
- if (data->endpoint.config.checksum)
- return false;
-
if (!data->toward_ipa) {
if (data->endpoint.filter_support) {
dev_err(dev, "filtering not supported for "
@@ -230,27 +223,6 @@ static bool ipa_endpoint_data_valid(struct ipa *ipa, u32 count,
return true;
}
-#else /* !IPA_VALIDATE */
-
-static bool ipa_endpoint_data_valid(struct ipa *ipa, u32 count,
- const struct ipa_gsi_endpoint_data *data)
-{
- const struct ipa_gsi_endpoint_data *dp = data;
- enum ipa_endpoint_name name;
-
- if (ipa->version < IPA_VERSION_4_5)
- return true;
-
- /* IPA v4.5+ uses checksum offload, not yet supported by RMNet */
- for (name = 0; name < count; name++, dp++)
- if (data->endpoint.config.checksum)
- return false;
-
- return true;
-}
-
-#endif /* !IPA_VALIDATE */
-
/* Allocate a transaction to use on a non-command endpoint */
static struct gsi_trans *ipa_endpoint_trans_alloc(struct ipa_endpoint *endpoint,
u32 tre_count)
@@ -457,28 +429,34 @@ int ipa_endpoint_modem_exception_reset_all(struct ipa *ipa)
static void ipa_endpoint_init_cfg(struct ipa_endpoint *endpoint)
{
u32 offset = IPA_REG_ENDP_INIT_CFG_N_OFFSET(endpoint->endpoint_id);
+ enum ipa_cs_offload_en enabled;
u32 val = 0;
/* FRAG_OFFLOAD_EN is 0 */
if (endpoint->data->checksum) {
+ enum ipa_version version = endpoint->ipa->version;
+
if (endpoint->toward_ipa) {
u32 checksum_offset;
- val |= u32_encode_bits(IPA_CS_OFFLOAD_UL,
- CS_OFFLOAD_EN_FMASK);
/* Checksum header offset is in 4-byte units */
checksum_offset = sizeof(struct rmnet_map_header);
checksum_offset /= sizeof(u32);
val |= u32_encode_bits(checksum_offset,
CS_METADATA_HDR_OFFSET_FMASK);
+
+ enabled = version < IPA_VERSION_4_5
+ ? IPA_CS_OFFLOAD_UL
+ : IPA_CS_OFFLOAD_INLINE;
} else {
- val |= u32_encode_bits(IPA_CS_OFFLOAD_DL,
- CS_OFFLOAD_EN_FMASK);
+ enabled = version < IPA_VERSION_4_5
+ ? IPA_CS_OFFLOAD_DL
+ : IPA_CS_OFFLOAD_INLINE;
}
} else {
- val |= u32_encode_bits(IPA_CS_OFFLOAD_NONE,
- CS_OFFLOAD_EN_FMASK);
+ enabled = IPA_CS_OFFLOAD_NONE;
}
+ val |= u32_encode_bits(enabled, CS_OFFLOAD_EN_FMASK);
/* CS_GEN_QMB_MASTER_SEL is 0 */
iowrite32(val, endpoint->ipa->reg_virt + offset);
@@ -498,6 +476,27 @@ static void ipa_endpoint_init_nat(struct ipa_endpoint *endpoint)
iowrite32(val, endpoint->ipa->reg_virt + offset);
}
+static u32
+ipa_qmap_header_size(enum ipa_version version, struct ipa_endpoint *endpoint)
+{
+ u32 header_size = sizeof(struct rmnet_map_header);
+
+ /* Without checksum offload, we just have the MAP header */
+ if (!endpoint->data->checksum)
+ return header_size;
+
+ if (version < IPA_VERSION_4_5) {
+ /* Checksum header inserted for AP TX endpoints only */
+ if (endpoint->toward_ipa)
+ header_size += sizeof(struct rmnet_map_ul_csum_header);
+ } else {
+ /* Checksum header is used in both directions */
+ header_size += sizeof(struct rmnet_map_v5_csum_header);
+ }
+
+ return header_size;
+}
+
/**
* ipa_endpoint_init_hdr() - Initialize HDR endpoint configuration register
* @endpoint: Endpoint pointer
@@ -526,13 +525,11 @@ static void ipa_endpoint_init_hdr(struct ipa_endpoint *endpoint)
u32 val = 0;
if (endpoint->data->qmap) {
- size_t header_size = sizeof(struct rmnet_map_header);
enum ipa_version version = ipa->version;
+ size_t header_size;
- /* We might supply a checksum header after the QMAP header */
- if (endpoint->toward_ipa && endpoint->data->checksum)
- header_size += sizeof(struct rmnet_map_ul_csum_header);
- val |= ipa_header_size_encoded(version, header_size);
+ header_size = ipa_qmap_header_size(version, endpoint);
+ val = ipa_header_size_encoded(version, header_size);
/* Define how to fill fields in a received QMAP header */
if (!endpoint->toward_ipa) {
@@ -1734,6 +1731,21 @@ int ipa_endpoint_config(struct ipa *ipa)
u32 max;
u32 val;
+ /* Prior to IPAv3.5, the FLAVOR_0 register was not supported.
+ * Furthermore, the endpoints were not grouped such that TX
+ * endpoint numbers started with 0 and RX endpoints had numbers
+ * higher than all TX endpoints, so we can't do the simple
+ * direction check used for newer hardware below.
+ *
+ * For hardware that doesn't support the FLAVOR_0 register,
+ * just set the available mask to support any endpoint, and
+ * assume the configuration is valid.
+ */
+ if (ipa->version < IPA_VERSION_3_5) {
+ ipa->available = ~0;
+ return 0;
+ }
+
/* Find out about the endpoints supplied by the hardware, and ensure
* the highest one doesn't exceed the number we support.
*/
diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
index 9915603ed10b..9810c61a0320 100644
--- a/drivers/net/ipa/ipa_main.c
+++ b/drivers/net/ipa/ipa_main.c
@@ -31,6 +31,7 @@
#include "ipa_uc.h"
#include "ipa_interrupt.h"
#include "gsi_trans.h"
+#include "ipa_sysfs.h"
/**
* DOC: The IP Accelerator
@@ -399,16 +400,20 @@ static void ipa_hardware_config(struct ipa *ipa, const struct ipa_data *data)
/* Implement some hardware workarounds */
if (version >= IPA_VERSION_4_0 && version < IPA_VERSION_4_5) {
- /* Enable open global clocks (not needed for IPA v4.5) */
- val = GLOBAL_FMASK;
- val |= GLOBAL_2X_CLK_FMASK;
- iowrite32(val, ipa->reg_virt + IPA_REG_CLKON_CFG_OFFSET);
-
/* Disable PA mask to allow HOLB drop */
val = ioread32(ipa->reg_virt + IPA_REG_TX_CFG_OFFSET);
val &= ~PA_MASK_EN_FMASK;
iowrite32(val, ipa->reg_virt + IPA_REG_TX_CFG_OFFSET);
+
+ /* Enable open global clocks in the CLKON configuration */
+ val = GLOBAL_FMASK | GLOBAL_2X_CLK_FMASK;
+ } else if (version == IPA_VERSION_3_1) {
+ val = MISC_FMASK; /* Disable MISC clock gating */
+ } else {
+ val = 0; /* No CLKON configuration needed */
}
+ if (val)
+ iowrite32(val, ipa->reg_virt + IPA_REG_CLKON_CFG_OFFSET);
ipa_hardware_config_comp(ipa);
@@ -529,6 +534,7 @@ static int ipa_firmware_load(struct device *dev)
}
ret = of_address_to_resource(node, 0, &res);
+ of_node_put(node);
if (ret) {
dev_err(dev, "error %d getting \"memory-region\" resource\n",
ret);
@@ -573,6 +579,10 @@ out_release_firmware:
static const struct of_device_id ipa_match[] = {
{
+ .compatible = "qcom,msm8998-ipa",
+ .data = &ipa_data_v3_1,
+ },
+ {
.compatible = "qcom,sdm845-ipa",
.data = &ipa_data_v3_5_1,
},
@@ -639,6 +649,27 @@ static void ipa_validate_build(void)
#endif /* IPA_VALIDATE */
}
+static bool ipa_version_valid(enum ipa_version version)
+{
+ switch (version) {
+ case IPA_VERSION_3_0:
+ case IPA_VERSION_3_1:
+ case IPA_VERSION_3_5:
+ case IPA_VERSION_3_5_1:
+ case IPA_VERSION_4_0:
+ case IPA_VERSION_4_1:
+ case IPA_VERSION_4_2:
+ case IPA_VERSION_4_5:
+ case IPA_VERSION_4_7:
+ case IPA_VERSION_4_9:
+ case IPA_VERSION_4_11:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
/**
* ipa_probe() - IPA platform driver probe function
* @pdev: Platform device pointer
@@ -676,11 +707,15 @@ static int ipa_probe(struct platform_device *pdev)
/* Get configuration data early; needed for clock initialization */
data = of_device_get_match_data(dev);
if (!data) {
- /* This is really IPA_VALIDATE (should never happen) */
dev_err(dev, "matched hardware not supported\n");
return -ENODEV;
}
+ if (!ipa_version_valid(data->version)) {
+ dev_err(dev, "invalid IPA version\n");
+ return -EINVAL;
+ }
+
/* If we need Trust Zone, make sure it's available */
modem_init = of_property_read_bool(dev->of_node, "modem-init");
if (!modem_init)
@@ -881,6 +916,13 @@ static const struct dev_pm_ops ipa_pm_ops = {
.resume = ipa_resume,
};
+static const struct attribute_group *ipa_attribute_groups[] = {
+ &ipa_attribute_group,
+ &ipa_feature_attribute_group,
+ &ipa_modem_attribute_group,
+ NULL,
+};
+
static struct platform_driver ipa_driver = {
.probe = ipa_probe,
.remove = ipa_remove,
@@ -889,6 +931,7 @@ static struct platform_driver ipa_driver = {
.name = "ipa",
.pm = &ipa_pm_ops,
.of_match_table = ipa_match,
+ .dev_groups = ipa_attribute_groups,
},
};
diff --git a/drivers/net/ipa/ipa_mem.c b/drivers/net/ipa/ipa_mem.c
index 1624125e7459..4337b0920d3d 100644
--- a/drivers/net/ipa/ipa_mem.c
+++ b/drivers/net/ipa/ipa_mem.c
@@ -26,11 +26,26 @@
/* SMEM host id representing the modem. */
#define QCOM_SMEM_HOST_MODEM 1
+const struct ipa_mem *ipa_mem_find(struct ipa *ipa, enum ipa_mem_id mem_id)
+{
+ u32 i;
+
+ for (i = 0; i < ipa->mem_count; i++) {
+ const struct ipa_mem *mem = &ipa->mem[i];
+
+ if (mem->id == mem_id)
+ return mem;
+ }
+
+ return NULL;
+}
+
/* Add an immediate command to a transaction that zeroes a memory region */
static void
-ipa_mem_zero_region_add(struct gsi_trans *trans, const struct ipa_mem *mem)
+ipa_mem_zero_region_add(struct gsi_trans *trans, enum ipa_mem_id mem_id)
{
struct ipa *ipa = container_of(trans->gsi, struct ipa, gsi);
+ const struct ipa_mem *mem = ipa_mem_find(ipa, mem_id);
dma_addr_t addr = ipa->zero_addr;
if (!mem->size)
@@ -60,6 +75,7 @@ ipa_mem_zero_region_add(struct gsi_trans *trans, const struct ipa_mem *mem)
int ipa_mem_setup(struct ipa *ipa)
{
dma_addr_t addr = ipa->zero_addr;
+ const struct ipa_mem *mem;
struct gsi_trans *trans;
u32 offset;
u16 size;
@@ -74,39 +90,136 @@ int ipa_mem_setup(struct ipa *ipa)
return -EBUSY;
}
- /* Initialize IPA-local header memory. The modem and AP header
- * regions are contiguous, and initialized together.
+ /* Initialize IPA-local header memory. The AP header region, if
+ * present, is contiguous with and follows the modem header region,
+ * and they are initialized together.
*/
- offset = ipa->mem[IPA_MEM_MODEM_HEADER].offset;
- size = ipa->mem[IPA_MEM_MODEM_HEADER].size;
- size += ipa->mem[IPA_MEM_AP_HEADER].size;
+ mem = ipa_mem_find(ipa, IPA_MEM_MODEM_HEADER);
+ offset = mem->offset;
+ size = mem->size;
+ mem = ipa_mem_find(ipa, IPA_MEM_AP_HEADER);
+ if (mem)
+ size += mem->size;
ipa_cmd_hdr_init_local_add(trans, offset, size, addr);
- ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_MODEM_PROC_CTX]);
-
- ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_AP_PROC_CTX]);
-
- ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_MODEM]);
+ ipa_mem_zero_region_add(trans, IPA_MEM_MODEM_PROC_CTX);
+ ipa_mem_zero_region_add(trans, IPA_MEM_AP_PROC_CTX);
+ ipa_mem_zero_region_add(trans, IPA_MEM_MODEM);
gsi_trans_commit_wait(trans);
/* Tell the hardware where the processing context area is located */
- offset = ipa->mem_offset + ipa->mem[IPA_MEM_MODEM_PROC_CTX].offset;
+ mem = ipa_mem_find(ipa, IPA_MEM_MODEM_PROC_CTX);
+ offset = ipa->mem_offset + mem->offset;
val = proc_cntxt_base_addr_encoded(ipa->version, offset);
iowrite32(val, ipa->reg_virt + IPA_REG_LOCAL_PKT_PROC_CNTXT_OFFSET);
return 0;
}
-#ifdef IPA_VALIDATE
+/* Is the given memory region ID is valid for the current IPA version? */
+static bool ipa_mem_id_valid(struct ipa *ipa, enum ipa_mem_id mem_id)
+{
+ enum ipa_version version = ipa->version;
+
+ switch (mem_id) {
+ case IPA_MEM_UC_SHARED:
+ case IPA_MEM_UC_INFO:
+ case IPA_MEM_V4_FILTER_HASHED:
+ case IPA_MEM_V4_FILTER:
+ case IPA_MEM_V6_FILTER_HASHED:
+ case IPA_MEM_V6_FILTER:
+ case IPA_MEM_V4_ROUTE_HASHED:
+ case IPA_MEM_V4_ROUTE:
+ case IPA_MEM_V6_ROUTE_HASHED:
+ case IPA_MEM_V6_ROUTE:
+ case IPA_MEM_MODEM_HEADER:
+ case IPA_MEM_AP_HEADER:
+ case IPA_MEM_MODEM_PROC_CTX:
+ case IPA_MEM_AP_PROC_CTX:
+ case IPA_MEM_MODEM:
+ case IPA_MEM_UC_EVENT_RING:
+ case IPA_MEM_PDN_CONFIG:
+ case IPA_MEM_STATS_QUOTA_MODEM:
+ case IPA_MEM_STATS_QUOTA_AP:
+ case IPA_MEM_END_MARKER: /* pseudo region */
+ break;
+
+ case IPA_MEM_STATS_TETHERING:
+ case IPA_MEM_STATS_DROP:
+ if (version < IPA_VERSION_4_0)
+ return false;
+ break;
+
+ case IPA_MEM_STATS_V4_FILTER:
+ case IPA_MEM_STATS_V6_FILTER:
+ case IPA_MEM_STATS_V4_ROUTE:
+ case IPA_MEM_STATS_V6_ROUTE:
+ if (version < IPA_VERSION_4_0 || version > IPA_VERSION_4_2)
+ return false;
+ break;
+
+ case IPA_MEM_NAT_TABLE:
+ case IPA_MEM_STATS_FILTER_ROUTE:
+ if (version < IPA_VERSION_4_5)
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
-static bool ipa_mem_valid(struct ipa *ipa, enum ipa_mem_id mem_id)
+/* Must the given memory region be present in the configuration? */
+static bool ipa_mem_id_required(struct ipa *ipa, enum ipa_mem_id mem_id)
+{
+ switch (mem_id) {
+ case IPA_MEM_UC_SHARED:
+ case IPA_MEM_UC_INFO:
+ case IPA_MEM_V4_FILTER_HASHED:
+ case IPA_MEM_V4_FILTER:
+ case IPA_MEM_V6_FILTER_HASHED:
+ case IPA_MEM_V6_FILTER:
+ case IPA_MEM_V4_ROUTE_HASHED:
+ case IPA_MEM_V4_ROUTE:
+ case IPA_MEM_V6_ROUTE_HASHED:
+ case IPA_MEM_V6_ROUTE:
+ case IPA_MEM_MODEM_HEADER:
+ case IPA_MEM_MODEM_PROC_CTX:
+ case IPA_MEM_AP_PROC_CTX:
+ case IPA_MEM_MODEM:
+ return true;
+
+ case IPA_MEM_PDN_CONFIG:
+ case IPA_MEM_STATS_QUOTA_MODEM:
+ case IPA_MEM_STATS_TETHERING:
+ return ipa->version >= IPA_VERSION_4_0;
+
+ default:
+ return false; /* Anything else is optional */
+ }
+}
+
+static bool ipa_mem_valid_one(struct ipa *ipa, const struct ipa_mem *mem)
{
- const struct ipa_mem *mem = &ipa->mem[mem_id];
struct device *dev = &ipa->pdev->dev;
+ enum ipa_mem_id mem_id = mem->id;
u16 size_multiple;
+ /* Make sure the memory region is valid for this version of IPA */
+ if (!ipa_mem_id_valid(ipa, mem_id)) {
+ dev_err(dev, "region id %u not valid\n", mem_id);
+ return false;
+ }
+
+ if (!mem->size && !mem->canary_count) {
+ dev_err(dev, "empty memory region %u\n", mem_id);
+ return false;
+ }
+
/* Other than modem memory, sizes must be a multiple of 8 */
size_multiple = mem_id == IPA_MEM_MODEM ? 4 : 8;
if (mem->size % size_multiple)
@@ -117,23 +230,74 @@ static bool ipa_mem_valid(struct ipa *ipa, enum ipa_mem_id mem_id)
else if (mem->offset < mem->canary_count * sizeof(__le32))
dev_err(dev, "region %u offset too small for %hu canaries\n",
mem_id, mem->canary_count);
- else if (mem->offset + mem->size > ipa->mem_size)
- dev_err(dev, "region %u ends beyond memory limit (0x%08x)\n",
- mem_id, ipa->mem_size);
+ else if (mem_id == IPA_MEM_END_MARKER && mem->size)
+ dev_err(dev, "non-zero end marker region size\n");
else
return true;
return false;
}
-#else /* !IPA_VALIDATE */
-
-static bool ipa_mem_valid(struct ipa *ipa, enum ipa_mem_id mem_id)
+/* Verify each defined memory region is valid. */
+static bool ipa_mem_valid(struct ipa *ipa, const struct ipa_mem_data *mem_data)
{
+ DECLARE_BITMAP(regions, IPA_MEM_COUNT) = { };
+ struct device *dev = &ipa->pdev->dev;
+ enum ipa_mem_id mem_id;
+ u32 i;
+
+ if (mem_data->local_count > IPA_MEM_COUNT) {
+ dev_err(dev, "too many memory regions (%u > %u)\n",
+ mem_data->local_count, IPA_MEM_COUNT);
+ return false;
+ }
+
+ for (i = 0; i < mem_data->local_count; i++) {
+ const struct ipa_mem *mem = &mem_data->local[i];
+
+ if (__test_and_set_bit(mem->id, regions)) {
+ dev_err(dev, "duplicate memory region %u\n", mem->id);
+ return false;
+ }
+
+ /* Defined regions have non-zero size and/or canary count */
+ if (!ipa_mem_valid_one(ipa, mem))
+ return false;
+ }
+
+ /* Now see if any required regions are not defined */
+ for (mem_id = find_first_zero_bit(regions, IPA_MEM_COUNT);
+ mem_id < IPA_MEM_COUNT;
+ mem_id = find_next_zero_bit(regions, IPA_MEM_COUNT, mem_id + 1)) {
+ if (ipa_mem_id_required(ipa, mem_id))
+ dev_err(dev, "required memory region %u missing\n",
+ mem_id);
+ }
+
return true;
}
-#endif /*! IPA_VALIDATE */
+/* Do all memory regions fit within the IPA local memory? */
+static bool ipa_mem_size_valid(struct ipa *ipa)
+{
+ struct device *dev = &ipa->pdev->dev;
+ u32 limit = ipa->mem_size;
+ u32 i;
+
+ for (i = 0; i < ipa->mem_count; i++) {
+ const struct ipa_mem *mem = &ipa->mem[i];
+
+ if (mem->offset + mem->size <= limit)
+ continue;
+
+ dev_err(dev, "region %u ends beyond memory limit (0x%08x)\n",
+ mem->id, limit);
+
+ return false;
+ }
+
+ return true;
+}
/**
* ipa_mem_config() - Configure IPA shared memory
@@ -144,11 +308,12 @@ static bool ipa_mem_valid(struct ipa *ipa, enum ipa_mem_id mem_id)
int ipa_mem_config(struct ipa *ipa)
{
struct device *dev = &ipa->pdev->dev;
- enum ipa_mem_id mem_id;
+ const struct ipa_mem *mem;
dma_addr_t addr;
u32 mem_size;
void *virt;
u32 val;
+ u32 i;
/* Check the advertised location and size of the shared memory area */
val = ioread32(ipa->reg_virt + IPA_REG_SHARED_MEM_SIZE_OFFSET);
@@ -168,6 +333,10 @@ int ipa_mem_config(struct ipa *ipa)
mem_size);
}
+ /* We know our memory size; make sure regions are all in range */
+ if (!ipa_mem_size_valid(ipa))
+ return -EINVAL;
+
/* Prealloc DMA memory for zeroing regions */
virt = dma_alloc_coherent(dev, IPA_MEM_MAX, &addr, GFP_KERNEL);
if (!virt)
@@ -176,29 +345,18 @@ int ipa_mem_config(struct ipa *ipa)
ipa->zero_virt = virt;
ipa->zero_size = IPA_MEM_MAX;
- /* Verify each defined memory region is valid, and if indicated
- * for the region, write "canary" values in the space prior to
- * the region's base address.
+ /* For each defined region, write "canary" values in the
+ * space prior to the region's base address if indicated.
*/
- for (mem_id = 0; mem_id < ipa->mem_count; mem_id++) {
- const struct ipa_mem *mem = &ipa->mem[mem_id];
- u16 canary_count;
+ for (i = 0; i < ipa->mem_count; i++) {
+ u16 canary_count = ipa->mem[i].canary_count;
__le32 *canary;
- /* Validate all regions (even undefined ones) */
- if (!ipa_mem_valid(ipa, mem_id))
- goto err_dma_free;
-
- /* Skip over undefined regions */
- if (!mem->offset && !mem->size)
- continue;
-
- canary_count = mem->canary_count;
if (!canary_count)
continue;
/* Write canary values in the space before the region */
- canary = ipa->mem_virt + ipa->mem_offset + mem->offset;
+ canary = ipa->mem_virt + ipa->mem_offset + ipa->mem[i].offset;
do
*--canary = IPA_MEM_CANARY_VAL;
while (--canary_count);
@@ -212,8 +370,9 @@ int ipa_mem_config(struct ipa *ipa)
if (!ipa_cmd_data_valid(ipa))
goto err_dma_free;
- /* Verify the microcontroller ring alignment (0 is OK too) */
- if (ipa->mem[IPA_MEM_UC_EVENT_RING].offset % 1024) {
+ /* Verify the microcontroller ring alignment (if defined) */
+ mem = ipa_mem_find(ipa, IPA_MEM_UC_EVENT_RING);
+ if (mem && mem->offset % 1024) {
dev_err(dev, "microcontroller ring not 1024-byte aligned\n");
goto err_dma_free;
}
@@ -261,11 +420,9 @@ int ipa_mem_zero_modem(struct ipa *ipa)
return -EBUSY;
}
- ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_MODEM_HEADER]);
-
- ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_MODEM_PROC_CTX]);
-
- ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_MODEM]);
+ ipa_mem_zero_region_add(trans, IPA_MEM_MODEM_HEADER);
+ ipa_mem_zero_region_add(trans, IPA_MEM_MODEM_PROC_CTX);
+ ipa_mem_zero_region_add(trans, IPA_MEM_MODEM);
gsi_trans_commit_wait(trans);
@@ -380,7 +537,7 @@ static int ipa_smem_init(struct ipa *ipa, u32 item, size_t size)
* (in this case, the modem). An allocation from SMEM is persistent
* until the AP reboots; there is no way to free an allocated SMEM
* region. Allocation only reserves the space; to use it you need
- * to "get" a pointer it (this implies no reference counting).
+ * to "get" a pointer it (this does not imply reference counting).
* The item might have already been allocated, in which case we
* use it unless the size isn't what we expect.
*/
@@ -457,11 +614,12 @@ int ipa_mem_init(struct ipa *ipa, const struct ipa_mem_data *mem_data)
struct resource *res;
int ret;
- if (mem_data->local_count > IPA_MEM_COUNT) {
- dev_err(dev, "to many memory regions (%u > %u)\n",
- mem_data->local_count, IPA_MEM_COUNT);
+ /* Make sure the set of defined memory regions is valid */
+ if (!ipa_mem_valid(ipa, mem_data))
return -EINVAL;
- }
+
+ ipa->mem_count = mem_data->local_count;
+ ipa->mem = mem_data->local;
ret = dma_set_mask_and_coherent(&ipa->pdev->dev, DMA_BIT_MASK(64));
if (ret) {
@@ -486,10 +644,6 @@ int ipa_mem_init(struct ipa *ipa, const struct ipa_mem_data *mem_data)
ipa->mem_addr = res->start;
ipa->mem_size = resource_size(res);
- /* The ipa->mem[] array is indexed by enum ipa_mem_id values */
- ipa->mem_count = mem_data->local_count;
- ipa->mem = mem_data->local;
-
ret = ipa_imem_init(ipa, mem_data->imem_addr, mem_data->imem_size);
if (ret)
goto err_unmap;
diff --git a/drivers/net/ipa/ipa_mem.h b/drivers/net/ipa/ipa_mem.h
index a422aec69e5d..570bfdd99bff 100644
--- a/drivers/net/ipa/ipa_mem.h
+++ b/drivers/net/ipa/ipa_mem.h
@@ -54,37 +54,43 @@ enum ipa_mem_id {
IPA_MEM_V6_ROUTE_HASHED, /* 2 canaries */
IPA_MEM_V6_ROUTE, /* 2 canaries */
IPA_MEM_MODEM_HEADER, /* 2 canaries */
- IPA_MEM_AP_HEADER, /* 0 canaries */
+ IPA_MEM_AP_HEADER, /* 0 canaries, optional */
IPA_MEM_MODEM_PROC_CTX, /* 2 canaries */
IPA_MEM_AP_PROC_CTX, /* 0 canaries */
- IPA_MEM_NAT_TABLE, /* 4 canaries (IPA v4.5 and above) */
- IPA_MEM_PDN_CONFIG, /* 0/2 canaries (IPA v4.0 and above) */
- IPA_MEM_STATS_QUOTA_MODEM, /* 2/4 canaries (IPA v4.0 and above) */
- IPA_MEM_STATS_QUOTA_AP, /* 0 canaries (IPA v4.0 and above) */
- IPA_MEM_STATS_TETHERING, /* 0 canaries (IPA v4.0 and above) */
+ IPA_MEM_MODEM, /* 0/2 canaries */
+ IPA_MEM_UC_EVENT_RING, /* 1 canary, optional */
+ IPA_MEM_PDN_CONFIG, /* 0/2 canaries (IPA v4.0+) */
+ IPA_MEM_STATS_QUOTA_MODEM, /* 2/4 canaries (IPA v4.0+) */
+ IPA_MEM_STATS_QUOTA_AP, /* 0 canaries, optional (IPA v4.0+) */
+ IPA_MEM_STATS_TETHERING, /* 0 canaries (IPA v4.0+) */
+ IPA_MEM_STATS_DROP, /* 0 canaries, optional (IPA v4.0+) */
+ /* The next 5 filter and route statistics regions are optional */
IPA_MEM_STATS_V4_FILTER, /* 0 canaries (IPA v4.0-v4.2) */
IPA_MEM_STATS_V6_FILTER, /* 0 canaries (IPA v4.0-v4.2) */
IPA_MEM_STATS_V4_ROUTE, /* 0 canaries (IPA v4.0-v4.2) */
IPA_MEM_STATS_V6_ROUTE, /* 0 canaries (IPA v4.0-v4.2) */
- IPA_MEM_STATS_FILTER_ROUTE, /* 0 canaries (IPA v4.5 and above) */
- IPA_MEM_STATS_DROP, /* 0 canaries (IPA v4.0 and above) */
- IPA_MEM_MODEM, /* 0/2 canaries */
- IPA_MEM_UC_EVENT_RING, /* 1 canary */
+ IPA_MEM_STATS_FILTER_ROUTE, /* 0 canaries (IPA v4.5+) */
+ IPA_MEM_NAT_TABLE, /* 4 canaries, optional (IPA v4.5+) */
+ IPA_MEM_END_MARKER, /* 1 canary (not a real region) */
IPA_MEM_COUNT, /* Number of regions (not an index) */
};
/**
* struct ipa_mem - IPA local memory region description
+ * @id: memory region identifier
* @offset: offset in IPA memory space to base of the region
* @size: size in bytes base of the region
* @canary_count: Number of 32-bit "canary" values that precede region
*/
struct ipa_mem {
+ enum ipa_mem_id id;
u32 offset;
u16 size;
u16 canary_count;
};
+const struct ipa_mem *ipa_mem_find(struct ipa *ipa, enum ipa_mem_id mem_id);
+
int ipa_mem_config(struct ipa *ipa);
void ipa_mem_deconfig(struct ipa *ipa);
diff --git a/drivers/net/ipa/ipa_qmi.c b/drivers/net/ipa/ipa_qmi.c
index 593665efbcf9..4661105ce7ab 100644
--- a/drivers/net/ipa/ipa_qmi.c
+++ b/drivers/net/ipa/ipa_qmi.c
@@ -298,32 +298,32 @@ init_modem_driver_req(struct ipa_qmi *ipa_qmi)
req.platform_type_valid = 1;
req.platform_type = IPA_QMI_PLATFORM_TYPE_MSM_ANDROID;
- mem = &ipa->mem[IPA_MEM_MODEM_HEADER];
+ mem = ipa_mem_find(ipa, IPA_MEM_MODEM_HEADER);
if (mem->size) {
req.hdr_tbl_info_valid = 1;
req.hdr_tbl_info.start = ipa->mem_offset + mem->offset;
req.hdr_tbl_info.end = req.hdr_tbl_info.start + mem->size - 1;
}
- mem = &ipa->mem[IPA_MEM_V4_ROUTE];
+ mem = ipa_mem_find(ipa, IPA_MEM_V4_ROUTE);
req.v4_route_tbl_info_valid = 1;
req.v4_route_tbl_info.start = ipa->mem_offset + mem->offset;
req.v4_route_tbl_info.count = mem->size / sizeof(__le64);
- mem = &ipa->mem[IPA_MEM_V6_ROUTE];
+ mem = ipa_mem_find(ipa, IPA_MEM_V6_ROUTE);
req.v6_route_tbl_info_valid = 1;
req.v6_route_tbl_info.start = ipa->mem_offset + mem->offset;
req.v6_route_tbl_info.count = mem->size / sizeof(__le64);
- mem = &ipa->mem[IPA_MEM_V4_FILTER];
+ mem = ipa_mem_find(ipa, IPA_MEM_V4_FILTER);
req.v4_filter_tbl_start_valid = 1;
req.v4_filter_tbl_start = ipa->mem_offset + mem->offset;
- mem = &ipa->mem[IPA_MEM_V6_FILTER];
+ mem = ipa_mem_find(ipa, IPA_MEM_V6_FILTER);
req.v6_filter_tbl_start_valid = 1;
req.v6_filter_tbl_start = ipa->mem_offset + mem->offset;
- mem = &ipa->mem[IPA_MEM_MODEM];
+ mem = ipa_mem_find(ipa, IPA_MEM_MODEM);
if (mem->size) {
req.modem_mem_info_valid = 1;
req.modem_mem_info.start = ipa->mem_offset + mem->offset;
@@ -336,7 +336,7 @@ init_modem_driver_req(struct ipa_qmi *ipa_qmi)
/* skip_uc_load_valid and skip_uc_load are set above */
- mem = &ipa->mem[IPA_MEM_MODEM_PROC_CTX];
+ mem = ipa_mem_find(ipa, IPA_MEM_MODEM_PROC_CTX);
if (mem->size) {
req.hdr_proc_ctx_tbl_info_valid = 1;
req.hdr_proc_ctx_tbl_info.start =
@@ -347,7 +347,7 @@ init_modem_driver_req(struct ipa_qmi *ipa_qmi)
/* Nothing to report for the compression table (zip_tbl_info) */
- mem = &ipa->mem[IPA_MEM_V4_ROUTE_HASHED];
+ mem = ipa_mem_find(ipa, IPA_MEM_V4_ROUTE_HASHED);
if (mem->size) {
req.v4_hash_route_tbl_info_valid = 1;
req.v4_hash_route_tbl_info.start =
@@ -355,7 +355,7 @@ init_modem_driver_req(struct ipa_qmi *ipa_qmi)
req.v4_hash_route_tbl_info.count = mem->size / sizeof(__le64);
}
- mem = &ipa->mem[IPA_MEM_V6_ROUTE_HASHED];
+ mem = ipa_mem_find(ipa, IPA_MEM_V6_ROUTE_HASHED);
if (mem->size) {
req.v6_hash_route_tbl_info_valid = 1;
req.v6_hash_route_tbl_info.start =
@@ -363,22 +363,21 @@ init_modem_driver_req(struct ipa_qmi *ipa_qmi)
req.v6_hash_route_tbl_info.count = mem->size / sizeof(__le64);
}
- mem = &ipa->mem[IPA_MEM_V4_FILTER_HASHED];
+ mem = ipa_mem_find(ipa, IPA_MEM_V4_FILTER_HASHED);
if (mem->size) {
req.v4_hash_filter_tbl_start_valid = 1;
req.v4_hash_filter_tbl_start = ipa->mem_offset + mem->offset;
}
- mem = &ipa->mem[IPA_MEM_V6_FILTER_HASHED];
+ mem = ipa_mem_find(ipa, IPA_MEM_V6_FILTER_HASHED);
if (mem->size) {
req.v6_hash_filter_tbl_start_valid = 1;
req.v6_hash_filter_tbl_start = ipa->mem_offset + mem->offset;
}
- /* None of the stats fields are valid (IPA v4.0 and above) */
-
+ /* The stats fields are only valid for IPA v4.0+ */
if (ipa->version >= IPA_VERSION_4_0) {
- mem = &ipa->mem[IPA_MEM_STATS_QUOTA_MODEM];
+ mem = ipa_mem_find(ipa, IPA_MEM_STATS_QUOTA_MODEM);
if (mem->size) {
req.hw_stats_quota_base_addr_valid = 1;
req.hw_stats_quota_base_addr =
@@ -387,8 +386,9 @@ init_modem_driver_req(struct ipa_qmi *ipa_qmi)
req.hw_stats_quota_size = ipa->mem_offset + mem->size;
}
- mem = &ipa->mem[IPA_MEM_STATS_DROP];
- if (mem->size) {
+ /* If the DROP stats region is defined, include it */
+ mem = ipa_mem_find(ipa, IPA_MEM_STATS_DROP);
+ if (mem && mem->size) {
req.hw_stats_drop_base_addr_valid = 1;
req.hw_stats_drop_base_addr =
ipa->mem_offset + mem->offset;
diff --git a/drivers/net/ipa/ipa_reg.h b/drivers/net/ipa/ipa_reg.h
index 286ea9634c49..b89dec5865a5 100644
--- a/drivers/net/ipa/ipa_reg.h
+++ b/drivers/net/ipa/ipa_reg.h
@@ -368,6 +368,7 @@ enum ipa_cs_offload_en {
IPA_CS_OFFLOAD_NONE = 0x0,
IPA_CS_OFFLOAD_UL = 0x1, /* Before IPA v4.5 (TX) */
IPA_CS_OFFLOAD_DL = 0x2, /* Before IPA v4.5 (RX) */
+ IPA_CS_OFFLOAD_INLINE = 0x1, /* IPA v4.5 (TX and RX) */
};
/* Valid only for TX (IPA consumer) endpoints */
diff --git a/drivers/net/ipa/ipa_smp2p.c b/drivers/net/ipa/ipa_smp2p.c
index a5f7a79a1923..93270e50b6b3 100644
--- a/drivers/net/ipa/ipa_smp2p.c
+++ b/drivers/net/ipa/ipa_smp2p.c
@@ -8,6 +8,7 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
+#include <linux/panic_notifier.h>
#include <linux/soc/qcom/smem.h>
#include <linux/soc/qcom/smem_state.h>
@@ -176,11 +177,8 @@ static int ipa_smp2p_irq_init(struct ipa_smp2p *smp2p, const char *name,
int ret;
ret = platform_get_irq_byname(smp2p->ipa->pdev, name);
- if (ret <= 0) {
- dev_err(dev, "DT error %d getting \"%s\" IRQ property\n",
- ret, name);
+ if (ret <= 0)
return ret ? : -EINVAL;
- }
irq = ret;
ret = request_threaded_irq(irq, NULL, handler, 0, name, smp2p);
diff --git a/drivers/net/ipa/ipa_sysfs.c b/drivers/net/ipa/ipa_sysfs.c
new file mode 100644
index 000000000000..ff61dbdd70d8
--- /dev/null
+++ b/drivers/net/ipa/ipa_sysfs.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Copyright (C) 2021 Linaro Ltd. */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+
+#include "ipa.h"
+#include "ipa_version.h"
+#include "ipa_sysfs.h"
+
+static const char *ipa_version_string(struct ipa *ipa)
+{
+ switch (ipa->version) {
+ case IPA_VERSION_3_0:
+ return "3.0";
+ case IPA_VERSION_3_1:
+ return "3.1";
+ case IPA_VERSION_3_5:
+ return "3.5";
+ case IPA_VERSION_3_5_1:
+ return "3.5.1";
+ case IPA_VERSION_4_0:
+ return "4.0";
+ case IPA_VERSION_4_1:
+ return "4.1";
+ case IPA_VERSION_4_2:
+ return "4.2";
+ case IPA_VERSION_4_5:
+ return "4.5";
+ case IPA_VERSION_4_7:
+ return "4.7";
+ case IPA_VERSION_4_9:
+ return "4.9";
+ case IPA_VERSION_4_11:
+ return "4.11";
+ default:
+ return "0.0"; /* Won't happen (checked at probe time) */
+ }
+}
+
+static ssize_t
+version_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct ipa *ipa = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n", ipa_version_string(ipa));
+}
+
+static DEVICE_ATTR_RO(version);
+
+static struct attribute *ipa_attrs[] = {
+ &dev_attr_version.attr,
+ NULL
+};
+
+const struct attribute_group ipa_attribute_group = {
+ .attrs = ipa_attrs,
+};
+
+static const char *ipa_offload_string(struct ipa *ipa)
+{
+ return ipa->version < IPA_VERSION_4_5 ? "MAPv4" : "MAPv5";
+}
+
+static ssize_t rx_offload_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ipa *ipa = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n", ipa_offload_string(ipa));
+}
+
+static DEVICE_ATTR_RO(rx_offload);
+
+static ssize_t tx_offload_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ipa *ipa = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n", ipa_offload_string(ipa));
+}
+
+static DEVICE_ATTR_RO(tx_offload);
+
+static struct attribute *ipa_feature_attrs[] = {
+ &dev_attr_rx_offload.attr,
+ &dev_attr_tx_offload.attr,
+ NULL
+};
+
+const struct attribute_group ipa_feature_attribute_group = {
+ .name = "feature",
+ .attrs = ipa_feature_attrs,
+};
+
+static ssize_t
+ipa_endpoint_id_show(struct ipa *ipa, char *buf, enum ipa_endpoint_name name)
+{
+ u32 endpoint_id = ipa->name_map[name]->endpoint_id;
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", endpoint_id);
+}
+
+static ssize_t rx_endpoint_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ipa *ipa = dev_get_drvdata(dev);
+
+ return ipa_endpoint_id_show(ipa, buf, IPA_ENDPOINT_AP_MODEM_RX);
+}
+
+static DEVICE_ATTR_RO(rx_endpoint_id);
+
+static ssize_t tx_endpoint_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ipa *ipa = dev_get_drvdata(dev);
+
+ return ipa_endpoint_id_show(ipa, buf, IPA_ENDPOINT_AP_MODEM_TX);
+}
+
+static DEVICE_ATTR_RO(tx_endpoint_id);
+
+static struct attribute *ipa_modem_attrs[] = {
+ &dev_attr_rx_endpoint_id.attr,
+ &dev_attr_tx_endpoint_id.attr,
+ NULL
+};
+
+const struct attribute_group ipa_modem_attribute_group = {
+ .name = "modem",
+ .attrs = ipa_modem_attrs,
+};
diff --git a/drivers/net/ipa/ipa_sysfs.h b/drivers/net/ipa/ipa_sysfs.h
new file mode 100644
index 000000000000..b34e5650bf8c
--- /dev/null
+++ b/drivers/net/ipa/ipa_sysfs.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2019-2021 Linaro Ltd.
+ */
+#ifndef _IPA_SYSFS_H_
+#define _IPA_SYSFS_H_
+
+struct attribute_group;
+
+extern const struct attribute_group ipa_attribute_group;
+extern const struct attribute_group ipa_feature_attribute_group;
+extern const struct attribute_group ipa_modem_attribute_group;
+
+#endif /* _IPA_SYSFS_H_ */
diff --git a/drivers/net/ipa/ipa_table.c b/drivers/net/ipa/ipa_table.c
index 3168d72f4245..c617a9156f26 100644
--- a/drivers/net/ipa/ipa_table.c
+++ b/drivers/net/ipa/ipa_table.c
@@ -150,29 +150,16 @@ static void ipa_table_validate_build(void)
}
static bool
-ipa_table_valid_one(struct ipa *ipa, bool route, bool ipv6, bool hashed)
+ipa_table_valid_one(struct ipa *ipa, enum ipa_mem_id mem_id, bool route)
{
+ const struct ipa_mem *mem = ipa_mem_find(ipa, mem_id);
struct device *dev = &ipa->pdev->dev;
- const struct ipa_mem *mem;
u32 size;
- if (route) {
- if (ipv6)
- mem = hashed ? &ipa->mem[IPA_MEM_V6_ROUTE_HASHED]
- : &ipa->mem[IPA_MEM_V6_ROUTE];
- else
- mem = hashed ? &ipa->mem[IPA_MEM_V4_ROUTE_HASHED]
- : &ipa->mem[IPA_MEM_V4_ROUTE];
+ if (route)
size = IPA_ROUTE_COUNT_MAX * sizeof(__le64);
- } else {
- if (ipv6)
- mem = hashed ? &ipa->mem[IPA_MEM_V6_FILTER_HASHED]
- : &ipa->mem[IPA_MEM_V6_FILTER];
- else
- mem = hashed ? &ipa->mem[IPA_MEM_V4_FILTER_HASHED]
- : &ipa->mem[IPA_MEM_V4_FILTER];
+ else
size = (1 + IPA_FILTER_COUNT_MAX) * sizeof(__le64);
- }
if (!ipa_cmd_table_valid(ipa, mem, route, ipv6, hashed))
return false;
@@ -185,9 +172,8 @@ ipa_table_valid_one(struct ipa *ipa, bool route, bool ipv6, bool hashed)
if (hashed && !mem->size)
return true;
- dev_err(dev, "IPv%c %s%s table region size 0x%02x, expected 0x%02x\n",
- ipv6 ? '6' : '4', hashed ? "hashed " : "",
- route ? "route" : "filter", mem->size, size);
+ dev_err(dev, "%s table region %u size 0x%02x, expected 0x%02x\n",
+ route ? "route" : "filter", mem_id, mem->size, size);
return false;
}
@@ -195,16 +181,16 @@ ipa_table_valid_one(struct ipa *ipa, bool route, bool ipv6, bool hashed)
/* Verify the filter and route table memory regions are the expected size */
bool ipa_table_valid(struct ipa *ipa)
{
- bool valid = true;
+ bool valid;
- valid = valid && ipa_table_valid_one(ipa, false, false, false);
- valid = valid && ipa_table_valid_one(ipa, false, false, true);
- valid = valid && ipa_table_valid_one(ipa, false, true, false);
- valid = valid && ipa_table_valid_one(ipa, false, true, true);
- valid = valid && ipa_table_valid_one(ipa, true, false, false);
- valid = valid && ipa_table_valid_one(ipa, true, false, true);
- valid = valid && ipa_table_valid_one(ipa, true, true, false);
- valid = valid && ipa_table_valid_one(ipa, true, true, true);
+ valid = ipa_table_valid_one(IPA_MEM_V4_FILTER, false);
+ valid = valid && ipa_table_valid_one(IPA_MEM_V4_FILTER_HASHED, false);
+ valid = valid && ipa_table_valid_one(IPA_MEM_V6_FILTER, false);
+ valid = valid && ipa_table_valid_one(IPA_MEM_V6_FILTER_HASHED, false);
+ valid = valid && ipa_table_valid_one(IPA_MEM_V4_ROUTE, true);
+ valid = valid && ipa_table_valid_one(IPA_MEM_V4_ROUTE_HASHED, true);
+ valid = valid && ipa_table_valid_one(IPA_MEM_V6_ROUTE, true);
+ valid = valid && ipa_table_valid_one(IPA_MEM_V6_ROUTE_HASHED, true);
return valid;
}
@@ -256,14 +242,15 @@ static dma_addr_t ipa_table_addr(struct ipa *ipa, bool filter_mask, u16 count)
}
static void ipa_table_reset_add(struct gsi_trans *trans, bool filter,
- u16 first, u16 count, const struct ipa_mem *mem)
+ u16 first, u16 count, enum ipa_mem_id mem_id)
{
struct ipa *ipa = container_of(trans->gsi, struct ipa, gsi);
+ const struct ipa_mem *mem = ipa_mem_find(ipa, mem_id);
dma_addr_t addr;
u32 offset;
u16 size;
- /* Nothing to do if the table memory regions is empty */
+ /* Nothing to do if the table memory region is empty */
if (!mem->size)
return;
@@ -282,16 +269,13 @@ static void ipa_table_reset_add(struct gsi_trans *trans, bool filter,
* for the IPv4 and IPv6 non-hashed and hashed filter tables.
*/
static int
-ipa_filter_reset_table(struct ipa *ipa, const struct ipa_mem *mem, bool modem)
+ipa_filter_reset_table(struct ipa *ipa, enum ipa_mem_id mem_id, bool modem)
{
u32 ep_mask = ipa->filter_map;
u32 count = hweight32(ep_mask);
struct gsi_trans *trans;
enum gsi_ee_id ee_id;
- if (!mem->size)
- return 0;
-
trans = ipa_cmd_trans_alloc(ipa, count);
if (!trans) {
dev_err(&ipa->pdev->dev,
@@ -311,7 +295,7 @@ ipa_filter_reset_table(struct ipa *ipa, const struct ipa_mem *mem, bool modem)
if (endpoint->ee_id != ee_id)
continue;
- ipa_table_reset_add(trans, true, endpoint_id, 1, mem);
+ ipa_table_reset_add(trans, true, endpoint_id, 1, mem_id);
}
gsi_trans_commit_wait(trans);
@@ -327,20 +311,18 @@ static int ipa_filter_reset(struct ipa *ipa, bool modem)
{
int ret;
- ret = ipa_filter_reset_table(ipa, &ipa->mem[IPA_MEM_V4_FILTER], modem);
+ ret = ipa_filter_reset_table(ipa, IPA_MEM_V4_FILTER, modem);
if (ret)
return ret;
- ret = ipa_filter_reset_table(ipa, &ipa->mem[IPA_MEM_V4_FILTER_HASHED],
- modem);
+ ret = ipa_filter_reset_table(ipa, IPA_MEM_V4_FILTER_HASHED, modem);
if (ret)
return ret;
- ret = ipa_filter_reset_table(ipa, &ipa->mem[IPA_MEM_V6_FILTER], modem);
+ ret = ipa_filter_reset_table(ipa, IPA_MEM_V6_FILTER, modem);
if (ret)
return ret;
- ret = ipa_filter_reset_table(ipa, &ipa->mem[IPA_MEM_V6_FILTER_HASHED],
- modem);
+ ret = ipa_filter_reset_table(ipa, IPA_MEM_V6_FILTER_HASHED, modem);
return ret;
}
@@ -371,15 +353,13 @@ static int ipa_route_reset(struct ipa *ipa, bool modem)
count = IPA_ROUTE_AP_COUNT;
}
+ ipa_table_reset_add(trans, false, first, count, IPA_MEM_V4_ROUTE);
ipa_table_reset_add(trans, false, first, count,
- &ipa->mem[IPA_MEM_V4_ROUTE]);
- ipa_table_reset_add(trans, false, first, count,
- &ipa->mem[IPA_MEM_V4_ROUTE_HASHED]);
+ IPA_MEM_V4_ROUTE_HASHED);
+ ipa_table_reset_add(trans, false, first, count, IPA_MEM_V6_ROUTE);
ipa_table_reset_add(trans, false, first, count,
- &ipa->mem[IPA_MEM_V6_ROUTE]);
- ipa_table_reset_add(trans, false, first, count,
- &ipa->mem[IPA_MEM_V6_ROUTE_HASHED]);
+ IPA_MEM_V6_ROUTE_HASHED);
gsi_trans_commit_wait(trans);
@@ -433,10 +413,12 @@ int ipa_table_hash_flush(struct ipa *ipa)
static void ipa_table_init_add(struct gsi_trans *trans, bool filter,
enum ipa_cmd_opcode opcode,
- const struct ipa_mem *mem,
- const struct ipa_mem *hash_mem)
+ enum ipa_mem_id mem_id,
+ enum ipa_mem_id hash_mem_id)
{
struct ipa *ipa = container_of(trans->gsi, struct ipa, gsi);
+ const struct ipa_mem *hash_mem = ipa_mem_find(ipa, hash_mem_id);
+ const struct ipa_mem *mem = ipa_mem_find(ipa, mem_id);
dma_addr_t hash_addr;
dma_addr_t addr;
u16 hash_count;
@@ -477,20 +459,16 @@ int ipa_table_setup(struct ipa *ipa)
}
ipa_table_init_add(trans, false, IPA_CMD_IP_V4_ROUTING_INIT,
- &ipa->mem[IPA_MEM_V4_ROUTE],
- &ipa->mem[IPA_MEM_V4_ROUTE_HASHED]);
+ IPA_MEM_V4_ROUTE, IPA_MEM_V4_ROUTE_HASHED);
ipa_table_init_add(trans, false, IPA_CMD_IP_V6_ROUTING_INIT,
- &ipa->mem[IPA_MEM_V6_ROUTE],
- &ipa->mem[IPA_MEM_V6_ROUTE_HASHED]);
+ IPA_MEM_V6_ROUTE, IPA_MEM_V6_ROUTE_HASHED);
ipa_table_init_add(trans, true, IPA_CMD_IP_V4_FILTER_INIT,
- &ipa->mem[IPA_MEM_V4_FILTER],
- &ipa->mem[IPA_MEM_V4_FILTER_HASHED]);
+ IPA_MEM_V4_FILTER, IPA_MEM_V4_FILTER_HASHED);
ipa_table_init_add(trans, true, IPA_CMD_IP_V6_FILTER_INIT,
- &ipa->mem[IPA_MEM_V6_FILTER],
- &ipa->mem[IPA_MEM_V6_FILTER_HASHED]);
+ IPA_MEM_V6_FILTER, IPA_MEM_V6_FILTER_HASHED);
gsi_trans_commit_wait(trans);
diff --git a/drivers/net/ipa/ipa_uc.c b/drivers/net/ipa/ipa_uc.c
index 2756363e6938..fd9219863234 100644
--- a/drivers/net/ipa/ipa_uc.c
+++ b/drivers/net/ipa/ipa_uc.c
@@ -116,7 +116,8 @@ enum ipa_uc_event {
static struct ipa_uc_mem_area *ipa_uc_shared(struct ipa *ipa)
{
- u32 offset = ipa->mem_offset + ipa->mem[IPA_MEM_UC_SHARED].offset;
+ const struct ipa_mem *mem = ipa_mem_find(ipa, IPA_MEM_UC_SHARED);
+ u32 offset = ipa->mem_offset + mem->offset;
return ipa->mem_virt + offset;
}
diff --git a/drivers/net/ipa/ipa_version.h b/drivers/net/ipa/ipa_version.h
index ee2b3d02f3cd..6c16c895d842 100644
--- a/drivers/net/ipa/ipa_version.h
+++ b/drivers/net/ipa/ipa_version.h
@@ -21,6 +21,8 @@
* @IPA_VERSION_4_11: IPA version 4.11/GSI version 2.11 (2.1.1)
*
* Defines the version of IPA (and GSI) hardware present on the platform.
+ * Please update ipa_version_valid() and ipa_version_string() whenever a
+ * new version is added.
*/
enum ipa_version {
IPA_VERSION_3_0,
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 92425e1fd70c..93dc48b9b4f2 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -1819,7 +1819,7 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
ctx.sa.rx_sa = rx_sa;
ctx.secy = secy;
memcpy(ctx.sa.key, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]),
- MACSEC_KEYID_LEN);
+ secy->key_len);
err = macsec_offload(ops->mdo_add_rxsa, &ctx);
if (err)
@@ -2061,7 +2061,7 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
ctx.sa.tx_sa = tx_sa;
ctx.secy = secy;
memcpy(ctx.sa.key, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]),
- MACSEC_KEYID_LEN);
+ secy->key_len);
err = macsec_offload(ops->mdo_add_txsa, &ctx);
if (err)
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 1b998aa481f8..80de9768ecd4 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -1781,7 +1781,7 @@ static int macvlan_device_event(struct notifier_block *unused,
unregister_netdevice_many(&list_kill);
break;
case NETDEV_PRE_TYPE_CHANGE:
- /* Forbid underlaying device to change its type. */
+ /* Forbid underlying device to change its type. */
return NOTIFY_BAD;
case NETDEV_NOTIFY_PEERS:
diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig
index d06e06f5e31a..99a6c13a11af 100644
--- a/drivers/net/mdio/Kconfig
+++ b/drivers/net/mdio/Kconfig
@@ -19,6 +19,13 @@ config MDIO_BUS
reflects whether the mdio_bus/mdio_device code is built as a
loadable module or built-in.
+config FWNODE_MDIO
+ def_tristate PHYLIB
+ depends on (ACPI || OF) || COMPILE_TEST
+ select FIXED_PHY
+ help
+ FWNODE MDIO bus (Ethernet PHY) accessors
+
config OF_MDIO
def_tristate PHYLIB
depends on OF
@@ -27,6 +34,13 @@ config OF_MDIO
help
OpenFirmware MDIO bus (Ethernet PHY) accessors
+config ACPI_MDIO
+ def_tristate PHYLIB
+ depends on ACPI
+ depends on PHYLIB
+ help
+ ACPI MDIO bus (Ethernet PHY) accessors
+
if MDIO_BUS
config MDIO_DEVRES
diff --git a/drivers/net/mdio/Makefile b/drivers/net/mdio/Makefile
index c3ec0ef989df..15f8dc4042ce 100644
--- a/drivers/net/mdio/Makefile
+++ b/drivers/net/mdio/Makefile
@@ -1,7 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for Linux MDIO bus drivers
-obj-$(CONFIG_OF_MDIO) += of_mdio.o
+obj-$(CONFIG_ACPI_MDIO) += acpi_mdio.o
+obj-$(CONFIG_FWNODE_MDIO) += fwnode_mdio.o
+obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_MDIO_ASPEED) += mdio-aspeed.o
obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o
diff --git a/drivers/net/mdio/acpi_mdio.c b/drivers/net/mdio/acpi_mdio.c
new file mode 100644
index 000000000000..d77c987fda9c
--- /dev/null
+++ b/drivers/net/mdio/acpi_mdio.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ACPI helpers for the MDIO (Ethernet PHY) API
+ *
+ * This file provides helper functions for extracting PHY device information
+ * out of the ACPI ASL and using it to populate an mii_bus.
+ */
+
+#include <linux/acpi.h>
+#include <linux/acpi_mdio.h>
+#include <linux/bits.h>
+#include <linux/dev_printk.h>
+#include <linux/fwnode_mdio.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+MODULE_AUTHOR("Calvin Johnson <calvin.johnson@oss.nxp.com>");
+MODULE_LICENSE("GPL");
+
+/**
+ * acpi_mdiobus_register - Register mii_bus and create PHYs from the ACPI ASL.
+ * @mdio: pointer to mii_bus structure
+ * @fwnode: pointer to fwnode of MDIO bus. This fwnode is expected to represent
+ * an ACPI device object corresponding to the MDIO bus and its children are
+ * expected to correspond to the PHY devices on that bus.
+ *
+ * This function registers the mii_bus structure and registers a phy_device
+ * for each child node of @fwnode.
+ */
+int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode)
+{
+ struct fwnode_handle *child;
+ u32 addr;
+ int ret;
+
+ /* Mask out all PHYs from auto probing. */
+ mdio->phy_mask = GENMASK(31, 0);
+ ret = mdiobus_register(mdio);
+ if (ret)
+ return ret;
+
+ ACPI_COMPANION_SET(&mdio->dev, to_acpi_device_node(fwnode));
+
+ /* Loop over the child nodes and register a phy_device for each PHY */
+ fwnode_for_each_child_node(fwnode, child) {
+ ret = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), &addr);
+ if (ret || addr >= PHY_MAX_ADDR)
+ continue;
+
+ ret = fwnode_mdiobus_register_phy(mdio, child, addr);
+ if (ret == -ENODEV)
+ dev_err(&mdio->dev,
+ "MDIO device at address %d is missing.\n",
+ addr);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(acpi_mdiobus_register);
diff --git a/drivers/net/mdio/fwnode_mdio.c b/drivers/net/mdio/fwnode_mdio.c
new file mode 100644
index 000000000000..1becb1a731f6
--- /dev/null
+++ b/drivers/net/mdio/fwnode_mdio.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * fwnode helpers for the MDIO (Ethernet PHY) API
+ *
+ * This file provides helper functions for extracting PHY device information
+ * out of the fwnode and using it to populate an mii_bus.
+ */
+
+#include <linux/acpi.h>
+#include <linux/fwnode_mdio.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+
+MODULE_AUTHOR("Calvin Johnson <calvin.johnson@oss.nxp.com>");
+MODULE_LICENSE("GPL");
+
+static struct mii_timestamper *
+fwnode_find_mii_timestamper(struct fwnode_handle *fwnode)
+{
+ struct of_phandle_args arg;
+ int err;
+
+ if (is_acpi_node(fwnode))
+ return NULL;
+
+ err = of_parse_phandle_with_fixed_args(to_of_node(fwnode),
+ "timestamper", 1, 0, &arg);
+ if (err == -ENOENT)
+ return NULL;
+ else if (err)
+ return ERR_PTR(err);
+
+ if (arg.args_count != 1)
+ return ERR_PTR(-EINVAL);
+
+ return register_mii_timestamper(arg.np, arg.args[0]);
+}
+
+int fwnode_mdiobus_phy_device_register(struct mii_bus *mdio,
+ struct phy_device *phy,
+ struct fwnode_handle *child, u32 addr)
+{
+ int rc;
+
+ rc = fwnode_irq_get(child, 0);
+ if (rc == -EPROBE_DEFER)
+ return rc;
+
+ if (rc > 0) {
+ phy->irq = rc;
+ mdio->irq[addr] = rc;
+ } else {
+ phy->irq = mdio->irq[addr];
+ }
+
+ if (fwnode_property_read_bool(child, "broken-turn-around"))
+ mdio->phy_ignore_ta_mask |= 1 << addr;
+
+ fwnode_property_read_u32(child, "reset-assert-us",
+ &phy->mdio.reset_assert_delay);
+ fwnode_property_read_u32(child, "reset-deassert-us",
+ &phy->mdio.reset_deassert_delay);
+
+ /* Associate the fwnode with the device structure so it
+ * can be looked up later
+ */
+ fwnode_handle_get(child);
+ device_set_node(&phy->mdio.dev, child);
+
+ /* All data is now stored in the phy struct;
+ * register it
+ */
+ rc = phy_device_register(phy);
+ if (rc) {
+ fwnode_handle_put(child);
+ return rc;
+ }
+
+ dev_dbg(&mdio->dev, "registered phy %p fwnode at address %i\n",
+ child, addr);
+ return 0;
+}
+EXPORT_SYMBOL(fwnode_mdiobus_phy_device_register);
+
+int fwnode_mdiobus_register_phy(struct mii_bus *bus,
+ struct fwnode_handle *child, u32 addr)
+{
+ struct mii_timestamper *mii_ts = NULL;
+ struct phy_device *phy;
+ bool is_c45 = false;
+ u32 phy_id;
+ int rc;
+
+ mii_ts = fwnode_find_mii_timestamper(child);
+ if (IS_ERR(mii_ts))
+ return PTR_ERR(mii_ts);
+
+ rc = fwnode_property_match_string(child, "compatible",
+ "ethernet-phy-ieee802.3-c45");
+ if (rc >= 0)
+ is_c45 = true;
+
+ if (is_c45 || fwnode_get_phy_id(child, &phy_id))
+ phy = get_phy_device(bus, addr, is_c45);
+ else
+ phy = phy_device_create(bus, addr, phy_id, 0, NULL);
+ if (IS_ERR(phy)) {
+ unregister_mii_timestamper(mii_ts);
+ return PTR_ERR(phy);
+ }
+
+ if (is_acpi_node(child)) {
+ phy->irq = bus->irq[addr];
+
+ /* Associate the fwnode with the device structure so it
+ * can be looked up later.
+ */
+ phy->mdio.dev.fwnode = child;
+
+ /* All data is now stored in the phy struct, so register it */
+ rc = phy_device_register(phy);
+ if (rc) {
+ phy_device_free(phy);
+ fwnode_handle_put(phy->mdio.dev.fwnode);
+ return rc;
+ }
+ } else if (is_of_node(child)) {
+ rc = fwnode_mdiobus_phy_device_register(bus, phy, child, addr);
+ if (rc) {
+ unregister_mii_timestamper(mii_ts);
+ phy_device_free(phy);
+ return rc;
+ }
+ }
+
+ /* phy->mii_ts may already be defined by the PHY driver. A
+ * mii_timestamper probed via the device tree will still have
+ * precedence.
+ */
+ if (mii_ts)
+ phy->mii_ts = mii_ts;
+ return 0;
+}
+EXPORT_SYMBOL(fwnode_mdiobus_register_phy);
diff --git a/drivers/net/mdio/mdio-bcm-unimac.c b/drivers/net/mdio/mdio-bcm-unimac.c
index 5d171e7f118d..bfc9be23c973 100644
--- a/drivers/net/mdio/mdio-bcm-unimac.c
+++ b/drivers/net/mdio/mdio-bcm-unimac.c
@@ -203,7 +203,7 @@ static void unimac_mdio_clk_set(struct unimac_mdio_priv *priv)
return;
}
- /* The MDIO clock is the reference clock (typicaly 250Mhz) divided by
+ /* The MDIO clock is the reference clock (typically 250Mhz) divided by
* 2 x (MDIO_CLK_DIV + 1)
*/
reg = unimac_mdio_readl(priv, MDIO_CFG);
diff --git a/drivers/net/mdio/mdio-ipq8064.c b/drivers/net/mdio/mdio-ipq8064.c
index 8fe8f0119fc1..bd1aea2d5a26 100644
--- a/drivers/net/mdio/mdio-ipq8064.c
+++ b/drivers/net/mdio/mdio-ipq8064.c
@@ -7,33 +7,33 @@
#include <linux/delay.h>
#include <linux/kernel.h>
-#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_mdio.h>
-#include <linux/phy.h>
+#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
/* MII address register definitions */
-#define MII_ADDR_REG_ADDR 0x10
-#define MII_BUSY BIT(0)
-#define MII_WRITE BIT(1)
-#define MII_CLKRANGE_60_100M (0 << 2)
-#define MII_CLKRANGE_100_150M (1 << 2)
-#define MII_CLKRANGE_20_35M (2 << 2)
-#define MII_CLKRANGE_35_60M (3 << 2)
-#define MII_CLKRANGE_150_250M (4 << 2)
-#define MII_CLKRANGE_250_300M (5 << 2)
+#define MII_ADDR_REG_ADDR 0x10
+#define MII_BUSY BIT(0)
+#define MII_WRITE BIT(1)
+#define MII_CLKRANGE(x) ((x) << 2)
+#define MII_CLKRANGE_60_100M MII_CLKRANGE(0)
+#define MII_CLKRANGE_100_150M MII_CLKRANGE(1)
+#define MII_CLKRANGE_20_35M MII_CLKRANGE(2)
+#define MII_CLKRANGE_35_60M MII_CLKRANGE(3)
+#define MII_CLKRANGE_150_250M MII_CLKRANGE(4)
+#define MII_CLKRANGE_250_300M MII_CLKRANGE(5)
#define MII_CLKRANGE_MASK GENMASK(4, 2)
#define MII_REG_SHIFT 6
#define MII_REG_MASK GENMASK(10, 6)
#define MII_ADDR_SHIFT 11
#define MII_ADDR_MASK GENMASK(15, 11)
-#define MII_DATA_REG_ADDR 0x14
+#define MII_DATA_REG_ADDR 0x14
-#define MII_MDIO_DELAY_USEC (1000)
-#define MII_MDIO_RETRY_MSEC (10)
+#define MII_MDIO_DELAY_USEC (1000)
+#define MII_MDIO_RETRY_MSEC (10)
struct ipq8064_mdio {
struct regmap *base; /* NSS_GMAC0_BASE */
@@ -65,7 +65,7 @@ ipq8064_mdio_read(struct mii_bus *bus, int phy_addr, int reg_offset)
((reg_offset << MII_REG_SHIFT) & MII_REG_MASK);
regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr);
- usleep_range(8, 10);
+ usleep_range(10, 13);
err = ipq8064_mdio_wait_busy(priv);
if (err)
@@ -91,19 +91,46 @@ ipq8064_mdio_write(struct mii_bus *bus, int phy_addr, int reg_offset, u16 data)
((reg_offset << MII_REG_SHIFT) & MII_REG_MASK);
regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr);
- usleep_range(8, 10);
+
+ /* For the specific reg 31 extra time is needed or the next
+ * read will produce garbage data.
+ */
+ if (reg_offset == 31)
+ usleep_range(30, 43);
+ else
+ usleep_range(10, 13);
return ipq8064_mdio_wait_busy(priv);
}
+static const struct regmap_config ipq8064_mdio_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .can_multi_write = false,
+ /* the mdio lock is used by any user of this mdio driver */
+ .disable_locking = true,
+
+ .cache_type = REGCACHE_NONE,
+};
+
static int
ipq8064_mdio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct ipq8064_mdio *priv;
+ struct resource res;
struct mii_bus *bus;
+ void __iomem *base;
int ret;
+ if (of_address_to_resource(np, 0, &res))
+ return -ENOMEM;
+
+ base = ioremap(res.start, resource_size(&res));
+ if (!base)
+ return -ENOMEM;
+
bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv));
if (!bus)
return -ENOMEM;
@@ -115,15 +142,10 @@ ipq8064_mdio_probe(struct platform_device *pdev)
bus->parent = &pdev->dev;
priv = bus->priv;
- priv->base = device_node_to_regmap(np);
- if (IS_ERR(priv->base)) {
- if (priv->base == ERR_PTR(-EPROBE_DEFER))
- return -EPROBE_DEFER;
-
- dev_err(&pdev->dev, "error getting device regmap, error=%pe\n",
- priv->base);
+ priv->base = devm_regmap_init_mmio(&pdev->dev, base,
+ &ipq8064_mdio_regmap_config);
+ if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- }
ret = of_mdiobus_register(bus, np);
if (ret)
diff --git a/drivers/net/mdio/mdio-mscc-miim.c b/drivers/net/mdio/mdio-mscc-miim.c
index b36e5ea04ddf..2d67e12c8262 100644
--- a/drivers/net/mdio/mdio-mscc-miim.c
+++ b/drivers/net/mdio/mdio-mscc-miim.c
@@ -139,10 +139,6 @@ static int mscc_miim_probe(struct platform_device *pdev)
struct mscc_miim_dev *dev;
int ret;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
-
bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*dev));
if (!bus)
return -ENOMEM;
@@ -155,7 +151,7 @@ static int mscc_miim_probe(struct platform_device *pdev)
bus->parent = &pdev->dev;
dev = bus->priv;
- dev->regs = devm_ioremap_resource(&pdev->dev, res);
+ dev->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(dev->regs)) {
dev_err(&pdev->dev, "Unable to map MIIM registers\n");
return PTR_ERR(dev->regs);
diff --git a/drivers/net/mdio/mdio-mux-bcm-iproc.c b/drivers/net/mdio/mdio-mux-bcm-iproc.c
index 03261e6b9ceb..014c0baedbd2 100644
--- a/drivers/net/mdio/mdio-mux-bcm-iproc.c
+++ b/drivers/net/mdio/mdio-mux-bcm-iproc.c
@@ -65,7 +65,7 @@ static void mdio_mux_iproc_config(struct iproc_mdiomux_desc *md)
writel(val, md->base + MDIO_SCAN_CTRL_OFFSET);
if (md->core_clk) {
- /* use rate adjust regs to derrive the mdio's operating
+ /* use rate adjust regs to derive the mdio's operating
* frequency from the specified core clock
*/
divisor = clk_get_rate(md->core_clk) / MDIO_OPERATING_FREQUENCY;
@@ -187,7 +187,9 @@ static int mdio_mux_iproc_probe(struct platform_device *pdev)
return -ENOMEM;
md->dev = &pdev->dev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ md->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(md->base))
+ return PTR_ERR(md->base);
if (res->start & 0xfff) {
/* For backward compatibility in case the
* base address is specified with an offset.
@@ -196,9 +198,6 @@ static int mdio_mux_iproc_probe(struct platform_device *pdev)
res->start &= ~0xfff;
res->end = res->start + MDIO_REG_ADDR_SPACE_SIZE - 1;
}
- md->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(md->base))
- return PTR_ERR(md->base);
md->mii_bus = devm_mdiobus_alloc(&pdev->dev);
if (!md->mii_bus) {
diff --git a/drivers/net/mdio/mdio-mux-meson-g12a.c b/drivers/net/mdio/mdio-mux-meson-g12a.c
index bf86c9c7a288..b8866bc3f2e8 100644
--- a/drivers/net/mdio/mdio-mux-meson-g12a.c
+++ b/drivers/net/mdio/mdio-mux-meson-g12a.c
@@ -95,7 +95,7 @@ static int g12a_ephy_pll_enable(struct clk_hw *hw)
/* Poll on the digital lock instead of the usual analog lock
* This is done because bit 31 is unreliable on some SoC. Bit
- * 31 may indicate that the PLL is not lock eventhough the clock
+ * 31 may indicate that the PLL is not lock even though the clock
* is actually running
*/
return readl_poll_timeout(pll->base + ETH_PLL_CTL0, val,
diff --git a/drivers/net/mdio/of_mdio.c b/drivers/net/mdio/of_mdio.c
index 094494a68ddf..9e3c815a070f 100644
--- a/drivers/net/mdio/of_mdio.c
+++ b/drivers/net/mdio/of_mdio.c
@@ -10,6 +10,7 @@
#include <linux/device.h>
#include <linux/err.h>
+#include <linux/fwnode_mdio.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
@@ -29,128 +30,28 @@ MODULE_LICENSE("GPL");
* ethernet-phy-idAAAA.BBBB */
static int of_get_phy_id(struct device_node *device, u32 *phy_id)
{
- struct property *prop;
- const char *cp;
- unsigned int upper, lower;
-
- of_property_for_each_string(device, "compatible", prop, cp) {
- if (sscanf(cp, "ethernet-phy-id%4x.%4x", &upper, &lower) == 2) {
- *phy_id = ((upper & 0xFFFF) << 16) | (lower & 0xFFFF);
- return 0;
- }
- }
- return -EINVAL;
-}
-
-static struct mii_timestamper *of_find_mii_timestamper(struct device_node *node)
-{
- struct of_phandle_args arg;
- int err;
-
- err = of_parse_phandle_with_fixed_args(node, "timestamper", 1, 0, &arg);
-
- if (err == -ENOENT)
- return NULL;
- else if (err)
- return ERR_PTR(err);
-
- if (arg.args_count != 1)
- return ERR_PTR(-EINVAL);
-
- return register_mii_timestamper(arg.np, arg.args[0]);
+ return fwnode_get_phy_id(of_fwnode_handle(device), phy_id);
}
int of_mdiobus_phy_device_register(struct mii_bus *mdio, struct phy_device *phy,
- struct device_node *child, u32 addr)
+ struct device_node *child, u32 addr)
{
- int rc;
-
- rc = of_irq_get(child, 0);
- if (rc == -EPROBE_DEFER)
- return rc;
-
- if (rc > 0) {
- phy->irq = rc;
- mdio->irq[addr] = rc;
- } else {
- phy->irq = mdio->irq[addr];
- }
-
- if (of_property_read_bool(child, "broken-turn-around"))
- mdio->phy_ignore_ta_mask |= 1 << addr;
-
- of_property_read_u32(child, "reset-assert-us",
- &phy->mdio.reset_assert_delay);
- of_property_read_u32(child, "reset-deassert-us",
- &phy->mdio.reset_deassert_delay);
-
- /* Associate the OF node with the device structure so it
- * can be looked up later */
- of_node_get(child);
- phy->mdio.dev.of_node = child;
- phy->mdio.dev.fwnode = of_fwnode_handle(child);
-
- /* All data is now stored in the phy struct;
- * register it */
- rc = phy_device_register(phy);
- if (rc) {
- of_node_put(child);
- return rc;
- }
-
- dev_dbg(&mdio->dev, "registered phy %pOFn at address %i\n",
- child, addr);
- return 0;
+ return fwnode_mdiobus_phy_device_register(mdio, phy,
+ of_fwnode_handle(child),
+ addr);
}
EXPORT_SYMBOL(of_mdiobus_phy_device_register);
static int of_mdiobus_register_phy(struct mii_bus *mdio,
struct device_node *child, u32 addr)
{
- struct mii_timestamper *mii_ts;
- struct phy_device *phy;
- bool is_c45;
- int rc;
- u32 phy_id;
-
- mii_ts = of_find_mii_timestamper(child);
- if (IS_ERR(mii_ts))
- return PTR_ERR(mii_ts);
-
- is_c45 = of_device_is_compatible(child,
- "ethernet-phy-ieee802.3-c45");
-
- if (!is_c45 && !of_get_phy_id(child, &phy_id))
- phy = phy_device_create(mdio, addr, phy_id, 0, NULL);
- else
- phy = get_phy_device(mdio, addr, is_c45);
- if (IS_ERR(phy)) {
- if (mii_ts)
- unregister_mii_timestamper(mii_ts);
- return PTR_ERR(phy);
- }
-
- rc = of_mdiobus_phy_device_register(mdio, phy, child, addr);
- if (rc) {
- if (mii_ts)
- unregister_mii_timestamper(mii_ts);
- phy_device_free(phy);
- return rc;
- }
-
- /* phy->mii_ts may already be defined by the PHY driver. A
- * mii_timestamper probed via the device tree will still have
- * precedence.
- */
- if (mii_ts)
- phy->mii_ts = mii_ts;
-
- return 0;
+ return fwnode_mdiobus_register_phy(mdio, of_fwnode_handle(child), addr);
}
static int of_mdiobus_register_device(struct mii_bus *mdio,
struct device_node *child, u32 addr)
{
+ struct fwnode_handle *fwnode = of_fwnode_handle(child);
struct mdio_device *mdiodev;
int rc;
@@ -161,9 +62,8 @@ static int of_mdiobus_register_device(struct mii_bus *mdio,
/* Associate the OF node with the device structure so it
* can be looked up later.
*/
- of_node_get(child);
- mdiodev->dev.of_node = child;
- mdiodev->dev.fwnode = of_fwnode_handle(child);
+ fwnode_handle_get(fwnode);
+ device_set_node(&mdiodev->dev, fwnode);
/* All data is now stored in the mdiodev struct; register it. */
rc = mdio_device_register(mdiodev);
@@ -262,8 +162,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
* the device tree are populated after the bus has been registered */
mdio->phy_mask = ~0;
- mdio->dev.of_node = np;
- mdio->dev.fwnode = of_fwnode_handle(np);
+ device_set_node(&mdio->dev, of_fwnode_handle(np));
/* Get bus level PHY reset GPIO details */
mdio->reset_delay_us = DEFAULT_GPIO_RESET_DELAY;
@@ -347,16 +246,7 @@ EXPORT_SYMBOL(of_mdiobus_register);
*/
struct mdio_device *of_mdio_find_device(struct device_node *np)
{
- struct device *d;
-
- if (!np)
- return NULL;
-
- d = bus_find_device_by_of_node(&mdio_bus_type, np);
- if (!d)
- return NULL;
-
- return to_mdio_device(d);
+ return fwnode_mdio_find_device(of_fwnode_handle(np));
}
EXPORT_SYMBOL(of_mdio_find_device);
@@ -369,18 +259,7 @@ EXPORT_SYMBOL(of_mdio_find_device);
*/
struct phy_device *of_phy_find_device(struct device_node *phy_np)
{
- struct mdio_device *mdiodev;
-
- mdiodev = of_mdio_find_device(phy_np);
- if (!mdiodev)
- return NULL;
-
- if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY)
- return to_phy_device(&mdiodev->dev);
-
- put_device(&mdiodev->dev);
-
- return NULL;
+ return fwnode_phy_find_device(of_fwnode_handle(phy_np));
}
EXPORT_SYMBOL(of_phy_find_device);
@@ -466,7 +345,7 @@ EXPORT_SYMBOL(of_phy_get_and_connect);
* of_phy_is_fixed_link() and of_phy_register_fixed_link() must
* support two DT bindings:
* - the old DT binding, where 'fixed-link' was a property with 5
- * cells encoding various informations about the fixed PHY
+ * cells encoding various information about the fixed PHY
* - the new DT binding, where 'fixed-link' is a sub-node of the
* Ethernet device.
*/
diff --git a/drivers/net/mhi/net.c b/drivers/net/mhi/net.c
index b806f2f8f859..e60e38c1f09d 100644
--- a/drivers/net/mhi/net.c
+++ b/drivers/net/mhi/net.c
@@ -11,6 +11,7 @@
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/u64_stats_sync.h>
+#include <linux/wwan.h>
#include "mhi.h"
@@ -18,6 +19,12 @@
#define MHI_NET_MAX_MTU 0xffff
#define MHI_NET_DEFAULT_MTU 0x4000
+/* When set to false, the default netdev (link 0) is not created, and it's up
+ * to user to create the link (via wwan rtnetlink).
+ */
+static bool create_default_iface = true;
+module_param(create_default_iface, bool, 0);
+
struct mhi_device_info {
const char *netname;
const struct mhi_net_proto *proto;
@@ -25,7 +32,7 @@ struct mhi_device_info {
static int mhi_ndo_open(struct net_device *ndev)
{
- struct mhi_net_dev *mhi_netdev = netdev_priv(ndev);
+ struct mhi_net_dev *mhi_netdev = wwan_netdev_drvpriv(ndev);
/* Feed the rx buffer pool */
schedule_delayed_work(&mhi_netdev->rx_refill, 0);
@@ -40,7 +47,7 @@ static int mhi_ndo_open(struct net_device *ndev)
static int mhi_ndo_stop(struct net_device *ndev)
{
- struct mhi_net_dev *mhi_netdev = netdev_priv(ndev);
+ struct mhi_net_dev *mhi_netdev = wwan_netdev_drvpriv(ndev);
netif_stop_queue(ndev);
netif_carrier_off(ndev);
@@ -51,7 +58,7 @@ static int mhi_ndo_stop(struct net_device *ndev)
static netdev_tx_t mhi_ndo_xmit(struct sk_buff *skb, struct net_device *ndev)
{
- struct mhi_net_dev *mhi_netdev = netdev_priv(ndev);
+ struct mhi_net_dev *mhi_netdev = wwan_netdev_drvpriv(ndev);
const struct mhi_net_proto *proto = mhi_netdev->proto;
struct mhi_device *mdev = mhi_netdev->mdev;
int err;
@@ -86,7 +93,7 @@ exit_drop:
static void mhi_ndo_get_stats64(struct net_device *ndev,
struct rtnl_link_stats64 *stats)
{
- struct mhi_net_dev *mhi_netdev = netdev_priv(ndev);
+ struct mhi_net_dev *mhi_netdev = wwan_netdev_drvpriv(ndev);
unsigned int start;
do {
@@ -295,32 +302,33 @@ static void mhi_net_rx_refill_work(struct work_struct *work)
schedule_delayed_work(&mhi_netdev->rx_refill, HZ / 2);
}
-static struct device_type wwan_type = {
- .name = "wwan",
-};
-
-static int mhi_net_probe(struct mhi_device *mhi_dev,
- const struct mhi_device_id *id)
+static int mhi_net_newlink(void *ctxt, struct net_device *ndev, u32 if_id,
+ struct netlink_ext_ack *extack)
{
- const struct mhi_device_info *info = (struct mhi_device_info *)id->driver_data;
- struct device *dev = &mhi_dev->dev;
+ const struct mhi_device_info *info;
+ struct mhi_device *mhi_dev = ctxt;
struct mhi_net_dev *mhi_netdev;
- struct net_device *ndev;
int err;
- ndev = alloc_netdev(sizeof(*mhi_netdev), info->netname,
- NET_NAME_PREDICTABLE, mhi_net_setup);
- if (!ndev)
- return -ENOMEM;
+ info = (struct mhi_device_info *)mhi_dev->id->driver_data;
+
+ /* For now we only support one link (link context 0), driver must be
+ * reworked to break 1:1 relationship for net MBIM and to forward setup
+ * call to rmnet(QMAP) otherwise.
+ */
+ if (if_id != 0)
+ return -EINVAL;
+
+ if (dev_get_drvdata(&mhi_dev->dev))
+ return -EBUSY;
+
+ mhi_netdev = wwan_netdev_drvpriv(ndev);
- mhi_netdev = netdev_priv(ndev);
- dev_set_drvdata(dev, mhi_netdev);
+ dev_set_drvdata(&mhi_dev->dev, mhi_netdev);
mhi_netdev->ndev = ndev;
mhi_netdev->mdev = mhi_dev;
mhi_netdev->skbagg_head = NULL;
mhi_netdev->proto = info->proto;
- SET_NETDEV_DEV(ndev, &mhi_dev->dev);
- SET_NETDEV_DEVTYPE(ndev, &wwan_type);
INIT_DELAYED_WORK(&mhi_netdev->rx_refill, mhi_net_rx_refill_work);
u64_stats_init(&mhi_netdev->stats.rx_syncp);
@@ -334,7 +342,10 @@ static int mhi_net_probe(struct mhi_device *mhi_dev,
/* Number of transfer descriptors determines size of the queue */
mhi_netdev->rx_queue_sz = mhi_get_free_desc_count(mhi_dev, DMA_FROM_DEVICE);
- err = register_netdev(ndev);
+ if (extack)
+ err = register_netdevice(ndev);
+ else
+ err = register_netdev(ndev);
if (err)
goto out_err;
@@ -347,23 +358,89 @@ static int mhi_net_probe(struct mhi_device *mhi_dev,
return 0;
out_err_proto:
- unregister_netdev(ndev);
+ unregister_netdevice(ndev);
out_err:
free_netdev(ndev);
return err;
}
-static void mhi_net_remove(struct mhi_device *mhi_dev)
+static void mhi_net_dellink(void *ctxt, struct net_device *ndev,
+ struct list_head *head)
{
- struct mhi_net_dev *mhi_netdev = dev_get_drvdata(&mhi_dev->dev);
+ struct mhi_net_dev *mhi_netdev = wwan_netdev_drvpriv(ndev);
+ struct mhi_device *mhi_dev = ctxt;
- unregister_netdev(mhi_netdev->ndev);
+ if (head)
+ unregister_netdevice_queue(ndev, head);
+ else
+ unregister_netdev(ndev);
- mhi_unprepare_from_transfer(mhi_netdev->mdev);
+ mhi_unprepare_from_transfer(mhi_dev);
kfree_skb(mhi_netdev->skbagg_head);
- free_netdev(mhi_netdev->ndev);
+ dev_set_drvdata(&mhi_dev->dev, NULL);
+}
+
+static const struct wwan_ops mhi_wwan_ops = {
+ .priv_size = sizeof(struct mhi_net_dev),
+ .setup = mhi_net_setup,
+ .newlink = mhi_net_newlink,
+ .dellink = mhi_net_dellink,
+};
+
+static int mhi_net_probe(struct mhi_device *mhi_dev,
+ const struct mhi_device_id *id)
+{
+ const struct mhi_device_info *info = (struct mhi_device_info *)id->driver_data;
+ struct mhi_controller *cntrl = mhi_dev->mhi_cntrl;
+ struct net_device *ndev;
+ int err;
+
+ err = wwan_register_ops(&cntrl->mhi_dev->dev, &mhi_wwan_ops, mhi_dev,
+ WWAN_NO_DEFAULT_LINK);
+ if (err)
+ return err;
+
+ if (!create_default_iface)
+ return 0;
+
+ /* Create a default interface which is used as either RMNET real-dev,
+ * MBIM link 0 or ip link 0)
+ */
+ ndev = alloc_netdev(sizeof(struct mhi_net_dev), info->netname,
+ NET_NAME_PREDICTABLE, mhi_net_setup);
+ if (!ndev) {
+ err = -ENOMEM;
+ goto err_unregister;
+ }
+
+ SET_NETDEV_DEV(ndev, &mhi_dev->dev);
+
+ err = mhi_net_newlink(mhi_dev, ndev, 0, NULL);
+ if (err)
+ goto err_release;
+
+ return 0;
+
+err_release:
+ free_netdev(ndev);
+err_unregister:
+ wwan_unregister_ops(&cntrl->mhi_dev->dev);
+
+ return err;
+}
+
+static void mhi_net_remove(struct mhi_device *mhi_dev)
+{
+ struct mhi_net_dev *mhi_netdev = dev_get_drvdata(&mhi_dev->dev);
+ struct mhi_controller *cntrl = mhi_dev->mhi_cntrl;
+
+ /* WWAN core takes care of removing remaining links */
+ wwan_unregister_ops(&cntrl->mhi_dev->dev);
+
+ if (create_default_iface)
+ mhi_net_dellink(mhi_dev, mhi_netdev->ndev, NULL);
}
static const struct mhi_device_info mhi_hwip0 = {
diff --git a/drivers/net/mhi/proto_mbim.c b/drivers/net/mhi/proto_mbim.c
index fc72b3f6ec9e..bf1ad863237d 100644
--- a/drivers/net/mhi/proto_mbim.c
+++ b/drivers/net/mhi/proto_mbim.c
@@ -16,6 +16,7 @@
#include <linux/ip.h>
#include <linux/mii.h>
#include <linux/netdevice.h>
+#include <linux/wwan.h>
#include <linux/skbuff.h>
#include <linux/usb.h>
#include <linux/usb/cdc.h>
@@ -56,7 +57,7 @@ static void __mbim_errors_inc(struct mhi_net_dev *dev)
static int mbim_rx_verify_nth16(struct sk_buff *skb)
{
- struct mhi_net_dev *dev = netdev_priv(skb->dev);
+ struct mhi_net_dev *dev = wwan_netdev_drvpriv(skb->dev);
struct mbim_context *ctx = dev->proto_data;
struct usb_cdc_ncm_nth16 *nth16;
int len;
@@ -102,7 +103,7 @@ static int mbim_rx_verify_nth16(struct sk_buff *skb)
static int mbim_rx_verify_ndp16(struct sk_buff *skb, struct usb_cdc_ncm_ndp16 *ndp16)
{
- struct mhi_net_dev *dev = netdev_priv(skb->dev);
+ struct mhi_net_dev *dev = wwan_netdev_drvpriv(skb->dev);
int ret;
if (le16_to_cpu(ndp16->wLength) < USB_CDC_NCM_NDP16_LENGTH_MIN) {
diff --git a/drivers/net/mii.c b/drivers/net/mii.c
index e71ebb933266..779c3a96dba7 100644
--- a/drivers/net/mii.c
+++ b/drivers/net/mii.c
@@ -81,7 +81,7 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
if (mii->supports_gmii) {
- ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
+ ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
}
diff --git a/drivers/net/netdevsim/bus.c b/drivers/net/netdevsim/bus.c
index 0e9511661601..ccec29970d5b 100644
--- a/drivers/net/netdevsim/bus.c
+++ b/drivers/net/netdevsim/bus.c
@@ -27,21 +27,34 @@ static struct nsim_bus_dev *to_nsim_bus_dev(struct device *dev)
static int nsim_bus_dev_vfs_enable(struct nsim_bus_dev *nsim_bus_dev,
unsigned int num_vfs)
{
- nsim_bus_dev->vfconfigs = kcalloc(num_vfs,
- sizeof(struct nsim_vf_config),
- GFP_KERNEL | __GFP_NOWARN);
+ struct nsim_dev *nsim_dev;
+ int err = 0;
+
+ if (nsim_bus_dev->max_vfs < num_vfs)
+ return -ENOMEM;
+
if (!nsim_bus_dev->vfconfigs)
return -ENOMEM;
nsim_bus_dev->num_vfs = num_vfs;
- return 0;
+ nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
+ if (nsim_esw_mode_is_switchdev(nsim_dev)) {
+ err = nsim_esw_switchdev_enable(nsim_dev, NULL);
+ if (err)
+ nsim_bus_dev->num_vfs = 0;
+ }
+
+ return err;
}
-static void nsim_bus_dev_vfs_disable(struct nsim_bus_dev *nsim_bus_dev)
+void nsim_bus_dev_vfs_disable(struct nsim_bus_dev *nsim_bus_dev)
{
- kfree(nsim_bus_dev->vfconfigs);
- nsim_bus_dev->vfconfigs = NULL;
+ struct nsim_dev *nsim_dev;
+
nsim_bus_dev->num_vfs = 0;
+ nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
+ if (nsim_esw_mode_is_switchdev(nsim_dev))
+ nsim_esw_legacy_enable(nsim_dev, NULL);
}
static ssize_t
@@ -56,7 +69,7 @@ nsim_bus_dev_numvfs_store(struct device *dev, struct device_attribute *attr,
if (ret)
return ret;
- rtnl_lock();
+ mutex_lock(&nsim_bus_dev->vfs_lock);
if (nsim_bus_dev->num_vfs == num_vfs)
goto exit_good;
if (nsim_bus_dev->num_vfs && num_vfs) {
@@ -74,7 +87,7 @@ nsim_bus_dev_numvfs_store(struct device *dev, struct device_attribute *attr,
exit_good:
ret = count;
exit_unlock:
- rtnl_unlock();
+ mutex_unlock(&nsim_bus_dev->vfs_lock);
return ret;
}
@@ -92,6 +105,79 @@ static struct device_attribute nsim_bus_dev_numvfs_attr =
__ATTR(sriov_numvfs, 0664, nsim_bus_dev_numvfs_show,
nsim_bus_dev_numvfs_store);
+ssize_t nsim_bus_dev_max_vfs_read(struct file *file,
+ char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct nsim_bus_dev *nsim_bus_dev = file->private_data;
+ char buf[11];
+ ssize_t len;
+
+ len = snprintf(buf, sizeof(buf), "%u\n", nsim_bus_dev->max_vfs);
+ if (len < 0)
+ return len;
+
+ return simple_read_from_buffer(data, count, ppos, buf, len);
+}
+
+ssize_t nsim_bus_dev_max_vfs_write(struct file *file,
+ const char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct nsim_bus_dev *nsim_bus_dev = file->private_data;
+ struct nsim_vf_config *vfconfigs;
+ ssize_t ret;
+ char buf[10];
+ u32 val;
+
+ if (*ppos != 0)
+ return 0;
+
+ if (count >= sizeof(buf))
+ return -ENOSPC;
+
+ mutex_lock(&nsim_bus_dev->vfs_lock);
+ /* Reject if VFs are configured */
+ if (nsim_bus_dev->num_vfs) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ ret = copy_from_user(buf, data, count);
+ if (ret) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+
+ buf[count] = '\0';
+ ret = kstrtouint(buf, 10, &val);
+ if (ret) {
+ ret = -EIO;
+ goto unlock;
+ }
+
+ /* max_vfs limited by the maximum number of provided port indexes */
+ if (val > NSIM_DEV_VF_PORT_INDEX_MAX - NSIM_DEV_VF_PORT_INDEX_BASE) {
+ ret = -ERANGE;
+ goto unlock;
+ }
+
+ vfconfigs = kcalloc(val, sizeof(struct nsim_vf_config), GFP_KERNEL | __GFP_NOWARN);
+ if (!vfconfigs) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ kfree(nsim_bus_dev->vfconfigs);
+ nsim_bus_dev->vfconfigs = vfconfigs;
+ nsim_bus_dev->max_vfs = val;
+ *ppos += count;
+ ret = count;
+unlock:
+ mutex_unlock(&nsim_bus_dev->vfs_lock);
+ return ret;
+}
+
static ssize_t
new_port_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -113,7 +199,7 @@ new_port_store(struct device *dev, struct device_attribute *attr,
mutex_lock(&nsim_bus_dev->nsim_bus_reload_lock);
devlink_reload_disable(devlink);
- ret = nsim_dev_port_add(nsim_bus_dev, port_index);
+ ret = nsim_dev_port_add(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index);
devlink_reload_enable(devlink);
mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock);
return ret ? ret : count;
@@ -142,7 +228,7 @@ del_port_store(struct device *dev, struct device_attribute *attr,
mutex_lock(&nsim_bus_dev->nsim_bus_reload_lock);
devlink_reload_disable(devlink);
- ret = nsim_dev_port_del(nsim_bus_dev, port_index);
+ ret = nsim_dev_port_del(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index);
devlink_reload_enable(devlink);
mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock);
return ret ? ret : count;
@@ -168,9 +254,6 @@ static const struct attribute_group *nsim_bus_dev_attr_groups[] = {
static void nsim_bus_dev_release(struct device *dev)
{
- struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev);
-
- nsim_bus_dev_vfs_disable(nsim_bus_dev);
}
static struct device_type nsim_bus_dev_type = {
@@ -311,6 +394,8 @@ static struct bus_type nsim_bus = {
.num_vf = nsim_num_vf,
};
+#define NSIM_BUS_DEV_MAX_VFS 4
+
static struct nsim_bus_dev *
nsim_bus_dev_new(unsigned int id, unsigned int port_count)
{
@@ -329,15 +414,28 @@ nsim_bus_dev_new(unsigned int id, unsigned int port_count)
nsim_bus_dev->dev.type = &nsim_bus_dev_type;
nsim_bus_dev->port_count = port_count;
nsim_bus_dev->initial_net = current->nsproxy->net_ns;
+ nsim_bus_dev->max_vfs = NSIM_BUS_DEV_MAX_VFS;
mutex_init(&nsim_bus_dev->nsim_bus_reload_lock);
+ mutex_init(&nsim_bus_dev->vfs_lock);
/* Disallow using nsim_bus_dev */
smp_store_release(&nsim_bus_dev->init, false);
+ nsim_bus_dev->vfconfigs = kcalloc(nsim_bus_dev->max_vfs,
+ sizeof(struct nsim_vf_config),
+ GFP_KERNEL | __GFP_NOWARN);
+ if (!nsim_bus_dev->vfconfigs) {
+ err = -ENOMEM;
+ goto err_nsim_bus_dev_id_free;
+ }
+
err = device_register(&nsim_bus_dev->dev);
if (err)
- goto err_nsim_bus_dev_id_free;
+ goto err_nsim_vfs_free;
+
return nsim_bus_dev;
+err_nsim_vfs_free:
+ kfree(nsim_bus_dev->vfconfigs);
err_nsim_bus_dev_id_free:
ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id);
err_nsim_bus_dev_free:
@@ -351,6 +449,7 @@ static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev)
smp_store_release(&nsim_bus_dev->init, false);
device_unregister(&nsim_bus_dev->dev);
ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id);
+ kfree(nsim_bus_dev->vfconfigs);
kfree(nsim_bus_dev);
}
diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
index 6189a4c0d39e..6348307bfa84 100644
--- a/drivers/net/netdevsim/dev.c
+++ b/drivers/net/netdevsim/dev.c
@@ -35,6 +35,25 @@
#include "netdevsim.h"
+static unsigned int
+nsim_dev_port_index(enum nsim_dev_port_type type, unsigned int port_index)
+{
+ switch (type) {
+ case NSIM_DEV_PORT_TYPE_VF:
+ port_index = NSIM_DEV_VF_PORT_INDEX_BASE + port_index;
+ break;
+ case NSIM_DEV_PORT_TYPE_PF:
+ break;
+ }
+
+ return port_index;
+}
+
+static inline unsigned int nsim_dev_port_index_to_vf_index(unsigned int port_index)
+{
+ return port_index - NSIM_DEV_VF_PORT_INDEX_BASE;
+}
+
static struct dentry *nsim_dev_ddir;
#define NSIM_DEV_DUMMY_REGION_SIZE (1024 * 32)
@@ -192,9 +211,18 @@ static const struct file_operations nsim_dev_trap_fa_cookie_fops = {
.owner = THIS_MODULE,
};
+static const struct file_operations nsim_dev_max_vfs_fops = {
+ .open = simple_open,
+ .read = nsim_bus_dev_max_vfs_read,
+ .write = nsim_bus_dev_max_vfs_write,
+ .llseek = generic_file_llseek,
+ .owner = THIS_MODULE,
+};
+
static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev)
{
char dev_ddir_name[sizeof(DRV_NAME) + 10];
+ int err;
sprintf(dev_ddir_name, DRV_NAME "%u", nsim_dev->nsim_bus_dev->dev.id);
nsim_dev->ddir = debugfs_create_dir(dev_ddir_name, nsim_dev_ddir);
@@ -231,30 +259,84 @@ static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev)
debugfs_create_bool("fail_trap_policer_counter_get", 0600,
nsim_dev->ddir,
&nsim_dev->fail_trap_policer_counter_get);
+ nsim_dev->max_vfs = debugfs_create_file("max_vfs",
+ 0600,
+ nsim_dev->ddir,
+ nsim_dev->nsim_bus_dev,
+ &nsim_dev_max_vfs_fops);
+ nsim_dev->nodes_ddir = debugfs_create_dir("rate_nodes", nsim_dev->ddir);
+ if (IS_ERR(nsim_dev->nodes_ddir)) {
+ err = PTR_ERR(nsim_dev->nodes_ddir);
+ goto err_out;
+ }
+ debugfs_create_bool("fail_trap_drop_counter_get", 0600,
+ nsim_dev->ddir,
+ &nsim_dev->fail_trap_drop_counter_get);
nsim_udp_tunnels_debugfs_create(nsim_dev);
return 0;
+
+err_out:
+ debugfs_remove_recursive(nsim_dev->ports_ddir);
+ debugfs_remove_recursive(nsim_dev->ddir);
+ return err;
}
static void nsim_dev_debugfs_exit(struct nsim_dev *nsim_dev)
{
+ debugfs_remove_recursive(nsim_dev->nodes_ddir);
debugfs_remove_recursive(nsim_dev->ports_ddir);
debugfs_remove_recursive(nsim_dev->ddir);
}
+static ssize_t nsim_dev_rate_parent_read(struct file *file,
+ char __user *data,
+ size_t count, loff_t *ppos)
+{
+ char **name_ptr = file->private_data;
+ size_t len;
+
+ if (!*name_ptr)
+ return 0;
+
+ len = strlen(*name_ptr);
+ return simple_read_from_buffer(data, count, ppos, *name_ptr, len);
+}
+
+static const struct file_operations nsim_dev_rate_parent_fops = {
+ .open = simple_open,
+ .read = nsim_dev_rate_parent_read,
+ .llseek = generic_file_llseek,
+ .owner = THIS_MODULE,
+};
+
static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev,
struct nsim_dev_port *nsim_dev_port)
{
+ struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev;
+ unsigned int port_index = nsim_dev_port->port_index;
char port_ddir_name[16];
char dev_link_name[32];
- sprintf(port_ddir_name, "%u", nsim_dev_port->port_index);
+ sprintf(port_ddir_name, "%u", port_index);
nsim_dev_port->ddir = debugfs_create_dir(port_ddir_name,
nsim_dev->ports_ddir);
if (IS_ERR(nsim_dev_port->ddir))
return PTR_ERR(nsim_dev_port->ddir);
- sprintf(dev_link_name, "../../../" DRV_NAME "%u",
- nsim_dev->nsim_bus_dev->dev.id);
+ sprintf(dev_link_name, "../../../" DRV_NAME "%u", nsim_bus_dev->dev.id);
+ if (nsim_dev_port_is_vf(nsim_dev_port)) {
+ unsigned int vf_id = nsim_dev_port_index_to_vf_index(port_index);
+
+ debugfs_create_u16("tx_share", 0400, nsim_dev_port->ddir,
+ &nsim_bus_dev->vfconfigs[vf_id].min_tx_rate);
+ debugfs_create_u16("tx_max", 0400, nsim_dev_port->ddir,
+ &nsim_bus_dev->vfconfigs[vf_id].max_tx_rate);
+ nsim_dev_port->rate_parent = debugfs_create_file("rate_parent",
+ 0400,
+ nsim_dev_port->ddir,
+ &nsim_dev_port->parent_name,
+ &nsim_dev_rate_parent_fops);
+ }
debugfs_create_symlink("dev", nsim_dev_port->ddir, dev_link_name);
return 0;
@@ -407,6 +489,74 @@ static void nsim_dev_dummy_region_exit(struct nsim_dev *nsim_dev)
devlink_region_destroy(nsim_dev->dummy_region);
}
+static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port);
+int nsim_esw_legacy_enable(struct nsim_dev *nsim_dev, struct netlink_ext_ack *extack)
+{
+ struct devlink *devlink = priv_to_devlink(nsim_dev);
+ struct nsim_dev_port *nsim_dev_port, *tmp;
+
+ devlink_rate_nodes_destroy(devlink);
+ mutex_lock(&nsim_dev->port_list_lock);
+ list_for_each_entry_safe(nsim_dev_port, tmp, &nsim_dev->port_list, list)
+ if (nsim_dev_port_is_vf(nsim_dev_port))
+ __nsim_dev_port_del(nsim_dev_port);
+ mutex_unlock(&nsim_dev->port_list_lock);
+ nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY;
+ return 0;
+}
+
+int nsim_esw_switchdev_enable(struct nsim_dev *nsim_dev, struct netlink_ext_ack *extack)
+{
+ struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev;
+ int i, err;
+
+ for (i = 0; i < nsim_bus_dev->num_vfs; i++) {
+ err = nsim_dev_port_add(nsim_bus_dev, NSIM_DEV_PORT_TYPE_VF, i);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to initialize VFs' netdevsim ports");
+ pr_err("Failed to initialize VF id=%d. %d.\n", i, err);
+ goto err_port_add_vfs;
+ }
+ }
+ nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
+ return 0;
+
+err_port_add_vfs:
+ for (i--; i >= 0; i--)
+ nsim_dev_port_del(nsim_bus_dev, NSIM_DEV_PORT_TYPE_VF, i);
+ return err;
+}
+
+static int nsim_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
+ struct netlink_ext_ack *extack)
+{
+ struct nsim_dev *nsim_dev = devlink_priv(devlink);
+ int err = 0;
+
+ mutex_lock(&nsim_dev->nsim_bus_dev->vfs_lock);
+ if (mode == nsim_dev->esw_mode)
+ goto unlock;
+
+ if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
+ err = nsim_esw_legacy_enable(nsim_dev, extack);
+ else if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
+ err = nsim_esw_switchdev_enable(nsim_dev, extack);
+ else
+ err = -EINVAL;
+
+unlock:
+ mutex_unlock(&nsim_dev->nsim_bus_dev->vfs_lock);
+ return err;
+}
+
+static int nsim_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
+{
+ struct nsim_dev *nsim_dev = devlink_priv(devlink);
+
+ *mode = nsim_dev->esw_mode;
+ return 0;
+}
+
struct nsim_trap_item {
void *trap_ctx;
enum devlink_trap_action action;
@@ -416,6 +566,7 @@ struct nsim_trap_data {
struct delayed_work trap_report_dw;
struct nsim_trap_item *trap_items_arr;
u64 *trap_policers_cnt_arr;
+ u64 trap_pkt_cnt;
struct nsim_dev *nsim_dev;
spinlock_t trap_lock; /* Protects trap_items_arr */
};
@@ -892,7 +1043,190 @@ nsim_dev_devlink_trap_policer_counter_get(struct devlink *devlink,
return 0;
}
+#define NSIM_LINK_SPEED_MAX 5000 /* Mbps */
+#define NSIM_LINK_SPEED_UNIT 125000 /* 1 Mbps given in bytes/sec to avoid
+ * u64 overflow during conversion from
+ * bytes to bits.
+ */
+
+static int nsim_rate_bytes_to_units(char *name, u64 *rate, struct netlink_ext_ack *extack)
+{
+ u64 val;
+ u32 rem;
+
+ val = div_u64_rem(*rate, NSIM_LINK_SPEED_UNIT, &rem);
+ if (rem) {
+ pr_err("%s rate value %lluBps not in link speed units of 1Mbps.\n",
+ name, *rate);
+ NL_SET_ERR_MSG_MOD(extack, "TX rate value not in link speed units of 1Mbps.");
+ return -EINVAL;
+ }
+
+ if (val > NSIM_LINK_SPEED_MAX) {
+ pr_err("%s rate value %lluMbps exceed link maximum speed 5000Mbps.\n",
+ name, val);
+ NL_SET_ERR_MSG_MOD(extack, "TX rate value exceed link maximum speed 5000Mbps.");
+ return -EINVAL;
+ }
+ *rate = val;
+ return 0;
+}
+
+static int nsim_leaf_tx_share_set(struct devlink_rate *devlink_rate, void *priv,
+ u64 tx_share, struct netlink_ext_ack *extack)
+{
+ struct nsim_dev_port *nsim_dev_port = priv;
+ struct nsim_bus_dev *nsim_bus_dev = nsim_dev_port->ns->nsim_bus_dev;
+ int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index);
+ int err;
+
+ err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack);
+ if (err)
+ return err;
+
+ nsim_bus_dev->vfconfigs[vf_id].min_tx_rate = tx_share;
+ return 0;
+}
+
+static int nsim_leaf_tx_max_set(struct devlink_rate *devlink_rate, void *priv,
+ u64 tx_max, struct netlink_ext_ack *extack)
+{
+ struct nsim_dev_port *nsim_dev_port = priv;
+ struct nsim_bus_dev *nsim_bus_dev = nsim_dev_port->ns->nsim_bus_dev;
+ int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index);
+ int err;
+
+ err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack);
+ if (err)
+ return err;
+
+ nsim_bus_dev->vfconfigs[vf_id].max_tx_rate = tx_max;
+ return 0;
+}
+
+struct nsim_rate_node {
+ struct dentry *ddir;
+ struct dentry *rate_parent;
+ char *parent_name;
+ u16 tx_share;
+ u16 tx_max;
+};
+
+static int nsim_node_tx_share_set(struct devlink_rate *devlink_rate, void *priv,
+ u64 tx_share, struct netlink_ext_ack *extack)
+{
+ struct nsim_rate_node *nsim_node = priv;
+ int err;
+
+ err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack);
+ if (err)
+ return err;
+
+ nsim_node->tx_share = tx_share;
+ return 0;
+}
+
+static int nsim_node_tx_max_set(struct devlink_rate *devlink_rate, void *priv,
+ u64 tx_max, struct netlink_ext_ack *extack)
+{
+ struct nsim_rate_node *nsim_node = priv;
+ int err;
+
+ err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack);
+ if (err)
+ return err;
+
+ nsim_node->tx_max = tx_max;
+ return 0;
+}
+
+static int nsim_rate_node_new(struct devlink_rate *node, void **priv,
+ struct netlink_ext_ack *extack)
+{
+ struct nsim_dev *nsim_dev = devlink_priv(node->devlink);
+ struct nsim_rate_node *nsim_node;
+
+ if (!nsim_esw_mode_is_switchdev(nsim_dev)) {
+ NL_SET_ERR_MSG_MOD(extack, "Node creation allowed only in switchdev mode.");
+ return -EOPNOTSUPP;
+ }
+
+ nsim_node = kzalloc(sizeof(*nsim_node), GFP_KERNEL);
+ if (!nsim_node)
+ return -ENOMEM;
+
+ nsim_node->ddir = debugfs_create_dir(node->name, nsim_dev->nodes_ddir);
+
+ debugfs_create_u16("tx_share", 0400, nsim_node->ddir, &nsim_node->tx_share);
+ debugfs_create_u16("tx_max", 0400, nsim_node->ddir, &nsim_node->tx_max);
+ nsim_node->rate_parent = debugfs_create_file("rate_parent", 0400,
+ nsim_node->ddir,
+ &nsim_node->parent_name,
+ &nsim_dev_rate_parent_fops);
+
+ *priv = nsim_node;
+ return 0;
+}
+
+static int nsim_rate_node_del(struct devlink_rate *node, void *priv,
+ struct netlink_ext_ack *extack)
+{
+ struct nsim_rate_node *nsim_node = priv;
+
+ debugfs_remove(nsim_node->rate_parent);
+ debugfs_remove_recursive(nsim_node->ddir);
+ kfree(nsim_node);
+ return 0;
+}
+
+static int nsim_rate_leaf_parent_set(struct devlink_rate *child,
+ struct devlink_rate *parent,
+ void *priv_child, void *priv_parent,
+ struct netlink_ext_ack *extack)
+{
+ struct nsim_dev_port *nsim_dev_port = priv_child;
+
+ if (parent)
+ nsim_dev_port->parent_name = parent->name;
+ else
+ nsim_dev_port->parent_name = NULL;
+ return 0;
+}
+
+static int nsim_rate_node_parent_set(struct devlink_rate *child,
+ struct devlink_rate *parent,
+ void *priv_child, void *priv_parent,
+ struct netlink_ext_ack *extack)
+{
+ struct nsim_rate_node *nsim_node = priv_child;
+
+ if (parent)
+ nsim_node->parent_name = parent->name;
+ else
+ nsim_node->parent_name = NULL;
+ return 0;
+}
+
+static int
+nsim_dev_devlink_trap_drop_counter_get(struct devlink *devlink,
+ const struct devlink_trap *trap,
+ u64 *p_drops)
+{
+ struct nsim_dev *nsim_dev = devlink_priv(devlink);
+ u64 *cnt;
+
+ if (nsim_dev->fail_trap_drop_counter_get)
+ return -EINVAL;
+
+ cnt = &nsim_dev->trap_data->trap_pkt_cnt;
+ *p_drops = (*cnt)++;
+
+ return 0;
+}
+
static const struct devlink_ops nsim_dev_devlink_ops = {
+ .eswitch_mode_set = nsim_devlink_eswitch_mode_set,
+ .eswitch_mode_get = nsim_devlink_eswitch_mode_get,
.supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT |
DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK,
.reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT),
@@ -905,32 +1239,52 @@ static const struct devlink_ops nsim_dev_devlink_ops = {
.trap_group_set = nsim_dev_devlink_trap_group_set,
.trap_policer_set = nsim_dev_devlink_trap_policer_set,
.trap_policer_counter_get = nsim_dev_devlink_trap_policer_counter_get,
+ .rate_leaf_tx_share_set = nsim_leaf_tx_share_set,
+ .rate_leaf_tx_max_set = nsim_leaf_tx_max_set,
+ .rate_node_tx_share_set = nsim_node_tx_share_set,
+ .rate_node_tx_max_set = nsim_node_tx_max_set,
+ .rate_node_new = nsim_rate_node_new,
+ .rate_node_del = nsim_rate_node_del,
+ .rate_leaf_parent_set = nsim_rate_leaf_parent_set,
+ .rate_node_parent_set = nsim_rate_node_parent_set,
+ .trap_drop_counter_get = nsim_dev_devlink_trap_drop_counter_get,
};
#define NSIM_DEV_MAX_MACS_DEFAULT 32
#define NSIM_DEV_TEST1_DEFAULT true
-static int __nsim_dev_port_add(struct nsim_dev *nsim_dev,
+static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type,
unsigned int port_index)
{
+ struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev;
struct devlink_port_attrs attrs = {};
struct nsim_dev_port *nsim_dev_port;
struct devlink_port *devlink_port;
int err;
+ if (type == NSIM_DEV_PORT_TYPE_VF && !nsim_bus_dev->num_vfs)
+ return -EINVAL;
+
nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL);
if (!nsim_dev_port)
return -ENOMEM;
- nsim_dev_port->port_index = port_index;
+ nsim_dev_port->port_index = nsim_dev_port_index(type, port_index);
+ nsim_dev_port->port_type = type;
devlink_port = &nsim_dev_port->devlink_port;
- attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
- attrs.phys.port_number = port_index + 1;
+ if (nsim_dev_port_is_pf(nsim_dev_port)) {
+ attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
+ attrs.phys.port_number = port_index + 1;
+ } else {
+ attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF;
+ attrs.pci_vf.pf = 0;
+ attrs.pci_vf.vf = port_index;
+ }
memcpy(attrs.switch_id.id, nsim_dev->switch_id.id, nsim_dev->switch_id.id_len);
attrs.switch_id.id_len = nsim_dev->switch_id.id_len;
devlink_port_attrs_set(devlink_port, &attrs);
err = devlink_port_register(priv_to_devlink(nsim_dev), devlink_port,
- port_index);
+ nsim_dev_port->port_index);
if (err)
goto err_port_free;
@@ -944,11 +1298,20 @@ static int __nsim_dev_port_add(struct nsim_dev *nsim_dev,
goto err_port_debugfs_exit;
}
+ if (nsim_dev_port_is_vf(nsim_dev_port)) {
+ err = devlink_rate_leaf_create(&nsim_dev_port->devlink_port,
+ nsim_dev_port);
+ if (err)
+ goto err_nsim_destroy;
+ }
+
devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev);
list_add(&nsim_dev_port->list, &nsim_dev->port_list);
return 0;
+err_nsim_destroy:
+ nsim_destroy(nsim_dev_port->ns);
err_port_debugfs_exit:
nsim_dev_port_debugfs_exit(nsim_dev_port);
err_dl_port_unregister:
@@ -963,6 +1326,8 @@ static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port)
struct devlink_port *devlink_port = &nsim_dev_port->devlink_port;
list_del(&nsim_dev_port->list);
+ if (nsim_dev_port_is_vf(nsim_dev_port))
+ devlink_rate_leaf_destroy(&nsim_dev_port->devlink_port);
devlink_port_type_clear(devlink_port);
nsim_destroy(nsim_dev_port->ns);
nsim_dev_port_debugfs_exit(nsim_dev_port);
@@ -987,7 +1352,7 @@ static int nsim_dev_port_add_all(struct nsim_dev *nsim_dev,
int i, err;
for (i = 0; i < port_count; i++) {
- err = __nsim_dev_port_add(nsim_dev, i);
+ err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_PF, i);
if (err)
goto err_port_del_all;
}
@@ -1134,6 +1499,7 @@ int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev)
devlink_params_publish(devlink);
devlink_reload_enable(devlink);
+ nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY;
return 0;
err_psample_exit:
@@ -1169,6 +1535,12 @@ static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev)
if (devlink_is_reload_failed(devlink))
return;
debugfs_remove(nsim_dev->take_snapshot);
+
+ mutex_lock(&nsim_dev->nsim_bus_dev->vfs_lock);
+ if (nsim_dev->nsim_bus_dev->num_vfs)
+ nsim_bus_dev_vfs_disable(nsim_dev->nsim_bus_dev);
+ mutex_unlock(&nsim_dev->nsim_bus_dev->vfs_lock);
+
nsim_dev_port_del_all(nsim_dev);
nsim_dev_psample_exit(nsim_dev);
nsim_dev_health_exit(nsim_dev);
@@ -1197,32 +1569,34 @@ void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev)
}
static struct nsim_dev_port *
-__nsim_dev_port_lookup(struct nsim_dev *nsim_dev, unsigned int port_index)
+__nsim_dev_port_lookup(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type,
+ unsigned int port_index)
{
struct nsim_dev_port *nsim_dev_port;
+ port_index = nsim_dev_port_index(type, port_index);
list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list)
if (nsim_dev_port->port_index == port_index)
return nsim_dev_port;
return NULL;
}
-int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev,
+int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type,
unsigned int port_index)
{
struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
int err;
mutex_lock(&nsim_dev->port_list_lock);
- if (__nsim_dev_port_lookup(nsim_dev, port_index))
+ if (__nsim_dev_port_lookup(nsim_dev, type, port_index))
err = -EEXIST;
else
- err = __nsim_dev_port_add(nsim_dev, port_index);
+ err = __nsim_dev_port_add(nsim_dev, type, port_index);
mutex_unlock(&nsim_dev->port_list_lock);
return err;
}
-int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev,
+int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type,
unsigned int port_index)
{
struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
@@ -1230,7 +1604,7 @@ int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev,
int err = 0;
mutex_lock(&nsim_dev->port_list_lock);
- nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, port_index);
+ nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, type, port_index);
if (!nsim_dev_port)
err = -ENOENT;
else
diff --git a/drivers/net/netdevsim/ipsec.c b/drivers/net/netdevsim/ipsec.c
index 3811f1bde84e..b80ed2ffd45e 100644
--- a/drivers/net/netdevsim/ipsec.c
+++ b/drivers/net/netdevsim/ipsec.c
@@ -85,7 +85,7 @@ static int nsim_ipsec_parse_proto_keys(struct xfrm_state *xs,
u32 *mykey, u32 *mysalt)
{
const char aes_gcm_name[] = "rfc4106(gcm(aes))";
- struct net_device *dev = xs->xso.dev;
+ struct net_device *dev = xs->xso.real_dev;
unsigned char *key_data;
char *alg_name = NULL;
int key_len;
@@ -134,7 +134,7 @@ static int nsim_ipsec_add_sa(struct xfrm_state *xs)
u16 sa_idx;
int ret;
- dev = xs->xso.dev;
+ dev = xs->xso.real_dev;
ns = netdev_priv(dev);
ipsec = &ns->ipsec;
@@ -194,7 +194,7 @@ static int nsim_ipsec_add_sa(struct xfrm_state *xs)
static void nsim_ipsec_del_sa(struct xfrm_state *xs)
{
- struct netdevsim *ns = netdev_priv(xs->xso.dev);
+ struct netdevsim *ns = netdev_priv(xs->xso.real_dev);
struct nsim_ipsec *ipsec = &ns->ipsec;
u16 sa_idx;
@@ -211,7 +211,7 @@ static void nsim_ipsec_del_sa(struct xfrm_state *xs)
static bool nsim_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs)
{
- struct netdevsim *ns = netdev_priv(xs->xso.dev);
+ struct netdevsim *ns = netdev_priv(xs->xso.real_dev);
struct nsim_ipsec *ipsec = &ns->ipsec;
ipsec->ok++;
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index 659d3dceb687..c3aeb15843e2 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -113,6 +113,11 @@ static int nsim_set_vf_rate(struct net_device *dev, int vf, int min, int max)
struct netdevsim *ns = netdev_priv(dev);
struct nsim_bus_dev *nsim_bus_dev = ns->nsim_bus_dev;
+ if (nsim_esw_mode_is_switchdev(ns->nsim_dev)) {
+ pr_err("Not supported in switchdev mode. Please use devlink API.\n");
+ return -EOPNOTSUPP;
+ }
+
if (vf >= nsim_bus_dev->num_vfs)
return -EINVAL;
@@ -261,6 +266,18 @@ static const struct net_device_ops nsim_netdev_ops = {
.ndo_get_devlink_port = nsim_get_devlink_port,
};
+static const struct net_device_ops nsim_vf_netdev_ops = {
+ .ndo_start_xmit = nsim_start_xmit,
+ .ndo_set_rx_mode = nsim_set_rx_mode,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = nsim_change_mtu,
+ .ndo_get_stats64 = nsim_get_stats64,
+ .ndo_setup_tc = nsim_setup_tc,
+ .ndo_set_features = nsim_set_features,
+ .ndo_get_devlink_port = nsim_get_devlink_port,
+};
+
static void nsim_setup(struct net_device *dev)
{
ether_setup(dev);
@@ -280,6 +297,49 @@ static void nsim_setup(struct net_device *dev)
dev->max_mtu = ETH_MAX_MTU;
}
+static int nsim_init_netdevsim(struct netdevsim *ns)
+{
+ int err;
+
+ ns->netdev->netdev_ops = &nsim_netdev_ops;
+
+ err = nsim_udp_tunnels_info_create(ns->nsim_dev, ns->netdev);
+ if (err)
+ return err;
+
+ rtnl_lock();
+ err = nsim_bpf_init(ns);
+ if (err)
+ goto err_utn_destroy;
+
+ nsim_ipsec_init(ns);
+
+ err = register_netdevice(ns->netdev);
+ if (err)
+ goto err_ipsec_teardown;
+ rtnl_unlock();
+ return 0;
+
+err_ipsec_teardown:
+ nsim_ipsec_teardown(ns);
+ nsim_bpf_uninit(ns);
+err_utn_destroy:
+ rtnl_unlock();
+ nsim_udp_tunnels_info_destroy(ns->netdev);
+ return err;
+}
+
+static int nsim_init_netdevsim_vf(struct netdevsim *ns)
+{
+ int err;
+
+ ns->netdev->netdev_ops = &nsim_vf_netdev_ops;
+ rtnl_lock();
+ err = register_netdevice(ns->netdev);
+ rtnl_unlock();
+ return err;
+}
+
struct netdevsim *
nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port)
{
@@ -299,33 +359,15 @@ nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port)
ns->nsim_dev_port = nsim_dev_port;
ns->nsim_bus_dev = nsim_dev->nsim_bus_dev;
SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev);
- dev->netdev_ops = &nsim_netdev_ops;
nsim_ethtool_init(ns);
-
- err = nsim_udp_tunnels_info_create(nsim_dev, dev);
+ if (nsim_dev_port_is_pf(nsim_dev_port))
+ err = nsim_init_netdevsim(ns);
+ else
+ err = nsim_init_netdevsim_vf(ns);
if (err)
goto err_free_netdev;
-
- rtnl_lock();
- err = nsim_bpf_init(ns);
- if (err)
- goto err_utn_destroy;
-
- nsim_ipsec_init(ns);
-
- err = register_netdevice(dev);
- if (err)
- goto err_ipsec_teardown;
- rtnl_unlock();
-
return ns;
-err_ipsec_teardown:
- nsim_ipsec_teardown(ns);
- nsim_bpf_uninit(ns);
-err_utn_destroy:
- rtnl_unlock();
- nsim_udp_tunnels_info_destroy(dev);
err_free_netdev:
free_netdev(dev);
return ERR_PTR(err);
@@ -337,10 +379,13 @@ void nsim_destroy(struct netdevsim *ns)
rtnl_lock();
unregister_netdevice(dev);
- nsim_ipsec_teardown(ns);
- nsim_bpf_uninit(ns);
+ if (nsim_dev_port_is_pf(ns->nsim_dev_port)) {
+ nsim_ipsec_teardown(ns);
+ nsim_bpf_uninit(ns);
+ }
rtnl_unlock();
- nsim_udp_tunnels_info_destroy(dev);
+ if (nsim_dev_port_is_pf(ns->nsim_dev_port))
+ nsim_udp_tunnels_info_destroy(dev);
free_netdev(dev);
}
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index 7ff24e03577b..ae462957dcee 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h
@@ -197,11 +197,22 @@ static inline void nsim_dev_psample_exit(struct nsim_dev *nsim_dev)
}
#endif
+enum nsim_dev_port_type {
+ NSIM_DEV_PORT_TYPE_PF,
+ NSIM_DEV_PORT_TYPE_VF,
+};
+
+#define NSIM_DEV_VF_PORT_INDEX_BASE 128
+#define NSIM_DEV_VF_PORT_INDEX_MAX UINT_MAX
+
struct nsim_dev_port {
struct list_head list;
struct devlink_port devlink_port;
unsigned int port_index;
+ enum nsim_dev_port_type port_type;
struct dentry *ddir;
+ struct dentry *rate_parent;
+ char *parent_name;
struct netdevsim *ns;
};
@@ -212,6 +223,8 @@ struct nsim_dev {
struct dentry *ddir;
struct dentry *ports_ddir;
struct dentry *take_snapshot;
+ struct dentry *max_vfs;
+ struct dentry *nodes_ddir;
struct bpf_offload_dev *bpf_dev;
bool bpf_bind_accept;
bool bpf_bind_verifier_accept;
@@ -236,6 +249,7 @@ struct nsim_dev {
bool fail_trap_group_set;
bool fail_trap_policer_set;
bool fail_trap_policer_counter_get;
+ bool fail_trap_drop_counter_get;
struct {
struct udp_tunnel_nic_shared utn_shared;
u32 __ports[2][NSIM_UDP_TUNNEL_N_PORTS];
@@ -247,8 +261,22 @@ struct nsim_dev {
u32 sleep;
} udp_ports;
struct nsim_dev_psample *psample;
+ u16 esw_mode;
};
+int nsim_esw_legacy_enable(struct nsim_dev *nsim_dev, struct netlink_ext_ack *extack);
+int nsim_esw_switchdev_enable(struct nsim_dev *nsim_dev, struct netlink_ext_ack *extack);
+
+static inline bool nsim_esw_mode_is_legacy(struct nsim_dev *nsim_dev)
+{
+ return nsim_dev->esw_mode == DEVLINK_ESWITCH_MODE_LEGACY;
+}
+
+static inline bool nsim_esw_mode_is_switchdev(struct nsim_dev *nsim_dev)
+{
+ return nsim_dev->esw_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV;
+}
+
static inline struct net *nsim_dev_net(struct nsim_dev *nsim_dev)
{
return devlink_net(priv_to_devlink(nsim_dev));
@@ -259,8 +287,10 @@ void nsim_dev_exit(void);
int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev);
void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev);
int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev,
+ enum nsim_dev_port_type type,
unsigned int port_index);
int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev,
+ enum nsim_dev_port_type type,
unsigned int port_index);
struct nsim_fib_data *nsim_fib_create(struct devlink *devlink,
@@ -269,6 +299,23 @@ void nsim_fib_destroy(struct devlink *devlink, struct nsim_fib_data *fib_data);
u64 nsim_fib_get_val(struct nsim_fib_data *fib_data,
enum nsim_resource_id res_id, bool max);
+ssize_t nsim_bus_dev_max_vfs_read(struct file *file,
+ char __user *data,
+ size_t count, loff_t *ppos);
+ssize_t nsim_bus_dev_max_vfs_write(struct file *file,
+ const char __user *data,
+ size_t count, loff_t *ppos);
+void nsim_bus_dev_vfs_disable(struct nsim_bus_dev *nsim_bus_dev);
+
+static inline bool nsim_dev_port_is_pf(struct nsim_dev_port *nsim_dev_port)
+{
+ return nsim_dev_port->port_type == NSIM_DEV_PORT_TYPE_PF;
+}
+
+static inline bool nsim_dev_port_is_vf(struct nsim_dev_port *nsim_dev_port)
+{
+ return nsim_dev_port->port_type == NSIM_DEV_PORT_TYPE_VF;
+}
#if IS_ENABLED(CONFIG_XFRM_OFFLOAD)
void nsim_ipsec_init(struct netdevsim *ns);
void nsim_ipsec_teardown(struct netdevsim *ns);
@@ -308,7 +355,9 @@ struct nsim_bus_dev {
struct net *initial_net; /* Purpose of this is to carry net pointer
* during the probe time only.
*/
+ unsigned int max_vfs;
unsigned int num_vfs;
+ struct mutex vfs_lock; /* Protects vfconfigs */
struct nsim_vf_config *vfconfigs;
/* Lock for devlink->reload_enabled in netdevsim module */
struct mutex nsim_bus_reload_lock;
diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile
index c23146755972..0603d469bd57 100644
--- a/drivers/net/pcs/Makefile
+++ b/drivers/net/pcs/Makefile
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for Linux PCS drivers
-obj-$(CONFIG_PCS_XPCS) += pcs-xpcs.o
+pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o
+
+obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o
obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
diff --git a/drivers/net/pcs/pcs-xpcs-nxp.c b/drivers/net/pcs/pcs-xpcs-nxp.c
new file mode 100644
index 000000000000..984c9f7f16a8
--- /dev/null
+++ b/drivers/net/pcs/pcs-xpcs-nxp.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2021 NXP Semiconductors
+ */
+#include <linux/pcs/pcs-xpcs.h>
+#include "pcs-xpcs.h"
+
+/* LANE_DRIVER1_0 register */
+#define SJA1110_LANE_DRIVER1_0 0x8038
+#define SJA1110_TXDRV(x) (((x) << 12) & GENMASK(14, 12))
+
+/* LANE_DRIVER2_0 register */
+#define SJA1110_LANE_DRIVER2_0 0x803a
+#define SJA1110_TXDRVTRIM_LSB(x) ((x) & GENMASK_ULL(15, 0))
+
+/* LANE_DRIVER2_1 register */
+#define SJA1110_LANE_DRIVER2_1 0x803b
+#define SJA1110_LANE_DRIVER2_1_RSV BIT(9)
+#define SJA1110_TXDRVTRIM_MSB(x) (((x) & GENMASK_ULL(23, 16)) >> 16)
+
+/* LANE_TRIM register */
+#define SJA1110_LANE_TRIM 0x8040
+#define SJA1110_TXTEN BIT(11)
+#define SJA1110_TXRTRIM(x) (((x) << 8) & GENMASK(10, 8))
+#define SJA1110_TXPLL_BWSEL BIT(7)
+#define SJA1110_RXTEN BIT(6)
+#define SJA1110_RXRTRIM(x) (((x) << 3) & GENMASK(5, 3))
+#define SJA1110_CDR_GAIN BIT(2)
+#define SJA1110_ACCOUPLE_RXVCM_EN BIT(0)
+
+/* LANE_DATAPATH_1 register */
+#define SJA1110_LANE_DATAPATH_1 0x8037
+
+/* POWERDOWN_ENABLE register */
+#define SJA1110_POWERDOWN_ENABLE 0x8041
+#define SJA1110_TXPLL_PD BIT(12)
+#define SJA1110_TXPD BIT(11)
+#define SJA1110_RXPKDETEN BIT(10)
+#define SJA1110_RXCH_PD BIT(9)
+#define SJA1110_RXBIAS_PD BIT(8)
+#define SJA1110_RESET_SER_EN BIT(7)
+#define SJA1110_RESET_SER BIT(6)
+#define SJA1110_RESET_DES BIT(5)
+#define SJA1110_RCVEN BIT(4)
+
+/* RXPLL_CTRL0 register */
+#define SJA1110_RXPLL_CTRL0 0x8065
+#define SJA1110_RXPLL_FBDIV(x) (((x) << 2) & GENMASK(9, 2))
+
+/* RXPLL_CTRL1 register */
+#define SJA1110_RXPLL_CTRL1 0x8066
+#define SJA1110_RXPLL_REFDIV(x) ((x) & GENMASK(4, 0))
+
+/* TXPLL_CTRL0 register */
+#define SJA1110_TXPLL_CTRL0 0x806d
+#define SJA1110_TXPLL_FBDIV(x) ((x) & GENMASK(11, 0))
+
+/* TXPLL_CTRL1 register */
+#define SJA1110_TXPLL_CTRL1 0x806e
+#define SJA1110_TXPLL_REFDIV(x) ((x) & GENMASK(5, 0))
+
+/* RX_DATA_DETECT register */
+#define SJA1110_RX_DATA_DETECT 0x8045
+
+/* RX_CDR_CTLE register */
+#define SJA1110_RX_CDR_CTLE 0x8042
+
+/* In NXP SJA1105, the PCS is integrated with a PMA that has the TX lane
+ * polarity inverted by default (PLUS is MINUS, MINUS is PLUS). To obtain
+ * normal non-inverted behavior, the TX lane polarity must be inverted in the
+ * PCS, via the DIGITAL_CONTROL_2 register.
+ */
+int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs)
+{
+ return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL2,
+ DW_VR_MII_DIG_CTRL2_TX_POL_INV);
+}
+
+static int nxp_sja1110_pma_config(struct dw_xpcs *xpcs,
+ u16 txpll_fbdiv, u16 txpll_refdiv,
+ u16 rxpll_fbdiv, u16 rxpll_refdiv,
+ u16 rx_cdr_ctle)
+{
+ u16 val;
+ int ret;
+
+ /* Program TX PLL feedback divider and reference divider settings for
+ * correct oscillation frequency.
+ */
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL0,
+ SJA1110_TXPLL_FBDIV(txpll_fbdiv));
+ if (ret < 0)
+ return ret;
+
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL1,
+ SJA1110_TXPLL_REFDIV(txpll_refdiv));
+ if (ret < 0)
+ return ret;
+
+ /* Program transmitter amplitude and disable amplitude trimming */
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER1_0,
+ SJA1110_TXDRV(0x5));
+ if (ret < 0)
+ return ret;
+
+ val = SJA1110_TXDRVTRIM_LSB(0xffffffull);
+
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER2_0, val);
+ if (ret < 0)
+ return ret;
+
+ val = SJA1110_TXDRVTRIM_MSB(0xffffffull) | SJA1110_LANE_DRIVER2_1_RSV;
+
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER2_1, val);
+ if (ret < 0)
+ return ret;
+
+ /* Enable input and output resistor terminations for low BER. */
+ val = SJA1110_ACCOUPLE_RXVCM_EN | SJA1110_CDR_GAIN |
+ SJA1110_RXRTRIM(4) | SJA1110_RXTEN | SJA1110_TXPLL_BWSEL |
+ SJA1110_TXRTRIM(3) | SJA1110_TXTEN;
+
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_TRIM, val);
+ if (ret < 0)
+ return ret;
+
+ /* Select PCS as transmitter data source. */
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DATAPATH_1, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Program RX PLL feedback divider and reference divider for correct
+ * oscillation frequency.
+ */
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL0,
+ SJA1110_RXPLL_FBDIV(rxpll_fbdiv));
+ if (ret < 0)
+ return ret;
+
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL1,
+ SJA1110_RXPLL_REFDIV(rxpll_refdiv));
+ if (ret < 0)
+ return ret;
+
+ /* Program threshold for receiver signal detector.
+ * Enable control of RXPLL by receiver signal detector to disable RXPLL
+ * when an input signal is not present.
+ */
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RX_DATA_DETECT, 0x0005);
+ if (ret < 0)
+ return ret;
+
+ /* Enable TX and RX PLLs and circuits.
+ * Release reset of PMA to enable data flow to/from PCS.
+ */
+ ret = xpcs_read(xpcs, MDIO_MMD_VEND2, SJA1110_POWERDOWN_ENABLE);
+ if (ret < 0)
+ return ret;
+
+ val = ret & ~(SJA1110_TXPLL_PD | SJA1110_TXPD | SJA1110_RXCH_PD |
+ SJA1110_RXBIAS_PD | SJA1110_RESET_SER_EN |
+ SJA1110_RESET_SER | SJA1110_RESET_DES);
+ val |= SJA1110_RXPKDETEN | SJA1110_RCVEN;
+
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_POWERDOWN_ENABLE, val);
+ if (ret < 0)
+ return ret;
+
+ /* Program continuous-time linear equalizer (CTLE) settings. */
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RX_CDR_CTLE,
+ rx_cdr_ctle);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs)
+{
+ return nxp_sja1110_pma_config(xpcs, 0x19, 0x1, 0x19, 0x1, 0x212a);
+}
+
+int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs)
+{
+ return nxp_sja1110_pma_config(xpcs, 0x7d, 0x2, 0x7d, 0x2, 0x732a);
+}
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 944ba105cac1..63fda3fc40aa 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -11,80 +11,10 @@
#include <linux/mdio.h>
#include <linux/phylink.h>
#include <linux/workqueue.h>
+#include "pcs-xpcs.h"
-#define SYNOPSYS_XPCS_USXGMII_ID 0x7996ced0
-#define SYNOPSYS_XPCS_10GKR_ID 0x7996ced0
-#define SYNOPSYS_XPCS_XLGMII_ID 0x7996ced0
-#define SYNOPSYS_XPCS_SGMII_ID 0x7996ced0
-#define SYNOPSYS_XPCS_MASK 0xffffffff
-
-/* Vendor regs access */
-#define DW_VENDOR BIT(15)
-
-/* VR_XS_PCS */
-#define DW_USXGMII_RST BIT(10)
-#define DW_USXGMII_EN BIT(9)
-#define DW_VR_XS_PCS_DIG_STS 0x0010
-#define DW_RXFIFO_ERR GENMASK(6, 5)
-
-/* SR_MII */
-#define DW_USXGMII_FULL BIT(8)
-#define DW_USXGMII_SS_MASK (BIT(13) | BIT(6) | BIT(5))
-#define DW_USXGMII_10000 (BIT(13) | BIT(6))
-#define DW_USXGMII_5000 (BIT(13) | BIT(5))
-#define DW_USXGMII_2500 (BIT(5))
-#define DW_USXGMII_1000 (BIT(6))
-#define DW_USXGMII_100 (BIT(13))
-#define DW_USXGMII_10 (0)
-
-/* SR_AN */
-#define DW_SR_AN_ADV1 0x10
-#define DW_SR_AN_ADV2 0x11
-#define DW_SR_AN_ADV3 0x12
-#define DW_SR_AN_LP_ABL1 0x13
-#define DW_SR_AN_LP_ABL2 0x14
-#define DW_SR_AN_LP_ABL3 0x15
-
-/* Clause 73 Defines */
-/* AN_LP_ABL1 */
-#define DW_C73_PAUSE BIT(10)
-#define DW_C73_ASYM_PAUSE BIT(11)
-#define DW_C73_AN_ADV_SF 0x1
-/* AN_LP_ABL2 */
-#define DW_C73_1000KX BIT(5)
-#define DW_C73_10000KX4 BIT(6)
-#define DW_C73_10000KR BIT(7)
-/* AN_LP_ABL3 */
-#define DW_C73_2500KX BIT(0)
-#define DW_C73_5000KR BIT(1)
-
-/* Clause 37 Defines */
-/* VR MII MMD registers offsets */
-#define DW_VR_MII_DIG_CTRL1 0x8000
-#define DW_VR_MII_AN_CTRL 0x8001
-#define DW_VR_MII_AN_INTR_STS 0x8002
-
-/* VR_MII_DIG_CTRL1 */
-#define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9)
-
-/* VR_MII_AN_CTRL */
-#define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT 3
-#define DW_VR_MII_TX_CONFIG_MASK BIT(3)
-#define DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII 0x1
-#define DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII 0x0
-#define DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT 1
-#define DW_VR_MII_PCS_MODE_MASK GENMASK(2, 1)
-#define DW_VR_MII_PCS_MODE_C37_1000BASEX 0x0
-#define DW_VR_MII_PCS_MODE_C37_SGMII 0x2
-
-/* VR_MII_AN_INTR_STS */
-#define DW_VR_MII_AN_STS_C37_ANSGM_FD BIT(1)
-#define DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT 2
-#define DW_VR_MII_AN_STS_C37_ANSGM_SP GENMASK(3, 2)
-#define DW_VR_MII_C37_ANSGM_SP_10 0x0
-#define DW_VR_MII_C37_ANSGM_SP_100 0x1
-#define DW_VR_MII_C37_ANSGM_SP_1000 0x2
-#define DW_VR_MII_C37_ANSGM_SP_LNKSTS BIT(4)
+#define phylink_pcs_to_xpcs(pl_pcs) \
+ container_of((pl_pcs), struct dw_xpcs, pcs)
static const int xpcs_usxgmii_features[] = {
ETHTOOL_LINK_MODE_Pause_BIT,
@@ -144,96 +74,141 @@ static const int xpcs_sgmii_features[] = {
__ETHTOOL_LINK_MODE_MASK_NBITS,
};
+static const int xpcs_2500basex_features[] = {
+ ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+ ETHTOOL_LINK_MODE_Autoneg_BIT,
+ ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
+ ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+ __ETHTOOL_LINK_MODE_MASK_NBITS,
+};
+
static const phy_interface_t xpcs_usxgmii_interfaces[] = {
PHY_INTERFACE_MODE_USXGMII,
- PHY_INTERFACE_MODE_MAX,
};
static const phy_interface_t xpcs_10gkr_interfaces[] = {
PHY_INTERFACE_MODE_10GKR,
- PHY_INTERFACE_MODE_MAX,
};
static const phy_interface_t xpcs_xlgmii_interfaces[] = {
PHY_INTERFACE_MODE_XLGMII,
- PHY_INTERFACE_MODE_MAX,
};
static const phy_interface_t xpcs_sgmii_interfaces[] = {
PHY_INTERFACE_MODE_SGMII,
+};
+
+static const phy_interface_t xpcs_2500basex_interfaces[] = {
+ PHY_INTERFACE_MODE_2500BASEX,
PHY_INTERFACE_MODE_MAX,
};
-static struct xpcs_id {
- u32 id;
- u32 mask;
+enum {
+ DW_XPCS_USXGMII,
+ DW_XPCS_10GKR,
+ DW_XPCS_XLGMII,
+ DW_XPCS_SGMII,
+ DW_XPCS_2500BASEX,
+ DW_XPCS_INTERFACE_MAX,
+};
+
+struct xpcs_compat {
const int *supported;
const phy_interface_t *interface;
+ int num_interfaces;
int an_mode;
-} xpcs_id_list[] = {
- {
- .id = SYNOPSYS_XPCS_USXGMII_ID,
- .mask = SYNOPSYS_XPCS_MASK,
- .supported = xpcs_usxgmii_features,
- .interface = xpcs_usxgmii_interfaces,
- .an_mode = DW_AN_C73,
- }, {
- .id = SYNOPSYS_XPCS_10GKR_ID,
- .mask = SYNOPSYS_XPCS_MASK,
- .supported = xpcs_10gkr_features,
- .interface = xpcs_10gkr_interfaces,
- .an_mode = DW_AN_C73,
- }, {
- .id = SYNOPSYS_XPCS_XLGMII_ID,
- .mask = SYNOPSYS_XPCS_MASK,
- .supported = xpcs_xlgmii_features,
- .interface = xpcs_xlgmii_interfaces,
- .an_mode = DW_AN_C73,
- }, {
- .id = SYNOPSYS_XPCS_SGMII_ID,
- .mask = SYNOPSYS_XPCS_MASK,
- .supported = xpcs_sgmii_features,
- .interface = xpcs_sgmii_interfaces,
- .an_mode = DW_AN_C37_SGMII,
- },
+ int (*pma_config)(struct dw_xpcs *xpcs);
};
-static int xpcs_read(struct mdio_xpcs_args *xpcs, int dev, u32 reg)
+struct xpcs_id {
+ u32 id;
+ u32 mask;
+ const struct xpcs_compat *compat;
+};
+
+static const struct xpcs_compat *xpcs_find_compat(const struct xpcs_id *id,
+ phy_interface_t interface)
+{
+ int i, j;
+
+ for (i = 0; i < DW_XPCS_INTERFACE_MAX; i++) {
+ const struct xpcs_compat *compat = &id->compat[i];
+
+ for (j = 0; j < compat->num_interfaces; j++)
+ if (compat->interface[j] == interface)
+ return compat;
+ }
+
+ return NULL;
+}
+
+int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface)
+{
+ const struct xpcs_compat *compat;
+
+ compat = xpcs_find_compat(xpcs->id, interface);
+ if (!compat)
+ return -ENODEV;
+
+ return compat->an_mode;
+}
+EXPORT_SYMBOL_GPL(xpcs_get_an_mode);
+
+static bool __xpcs_linkmode_supported(const struct xpcs_compat *compat,
+ enum ethtool_link_mode_bit_indices linkmode)
{
- u32 reg_addr = MII_ADDR_C45 | dev << 16 | reg;
+ int i;
- return mdiobus_read(xpcs->bus, xpcs->addr, reg_addr);
+ for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
+ if (compat->supported[i] == linkmode)
+ return true;
+
+ return false;
}
-static int xpcs_write(struct mdio_xpcs_args *xpcs, int dev, u32 reg, u16 val)
+#define xpcs_linkmode_supported(compat, mode) \
+ __xpcs_linkmode_supported(compat, ETHTOOL_LINK_MODE_ ## mode ## _BIT)
+
+int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg)
{
- u32 reg_addr = MII_ADDR_C45 | dev << 16 | reg;
+ u32 reg_addr = mdiobus_c45_addr(dev, reg);
+ struct mii_bus *bus = xpcs->mdiodev->bus;
+ int addr = xpcs->mdiodev->addr;
- return mdiobus_write(xpcs->bus, xpcs->addr, reg_addr, val);
+ return mdiobus_read(bus, addr, reg_addr);
}
-static int xpcs_read_vendor(struct mdio_xpcs_args *xpcs, int dev, u32 reg)
+int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val)
+{
+ u32 reg_addr = mdiobus_c45_addr(dev, reg);
+ struct mii_bus *bus = xpcs->mdiodev->bus;
+ int addr = xpcs->mdiodev->addr;
+
+ return mdiobus_write(bus, addr, reg_addr, val);
+}
+
+static int xpcs_read_vendor(struct dw_xpcs *xpcs, int dev, u32 reg)
{
return xpcs_read(xpcs, dev, DW_VENDOR | reg);
}
-static int xpcs_write_vendor(struct mdio_xpcs_args *xpcs, int dev, int reg,
+static int xpcs_write_vendor(struct dw_xpcs *xpcs, int dev, int reg,
u16 val)
{
return xpcs_write(xpcs, dev, DW_VENDOR | reg, val);
}
-static int xpcs_read_vpcs(struct mdio_xpcs_args *xpcs, int reg)
+static int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg)
{
return xpcs_read_vendor(xpcs, MDIO_MMD_PCS, reg);
}
-static int xpcs_write_vpcs(struct mdio_xpcs_args *xpcs, int reg, u16 val)
+static int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val)
{
return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val);
}
-static int xpcs_poll_reset(struct mdio_xpcs_args *xpcs, int dev)
+static int xpcs_poll_reset(struct dw_xpcs *xpcs, int dev)
{
/* Poll until the reset bit clears (50ms per retry == 0.6 sec) */
unsigned int retries = 12;
@@ -249,15 +224,17 @@ static int xpcs_poll_reset(struct mdio_xpcs_args *xpcs, int dev)
return (ret & MDIO_CTRL1_RESET) ? -ETIMEDOUT : 0;
}
-static int xpcs_soft_reset(struct mdio_xpcs_args *xpcs)
+static int xpcs_soft_reset(struct dw_xpcs *xpcs,
+ const struct xpcs_compat *compat)
{
int ret, dev;
- switch (xpcs->an_mode) {
+ switch (compat->an_mode) {
case DW_AN_C73:
dev = MDIO_MMD_PCS;
break;
case DW_AN_C37_SGMII:
+ case DW_2500BASEX:
dev = MDIO_MMD_VEND2;
break;
default:
@@ -274,10 +251,10 @@ static int xpcs_soft_reset(struct mdio_xpcs_args *xpcs)
#define xpcs_warn(__xpcs, __state, __args...) \
({ \
if ((__state)->link) \
- dev_warn(&(__xpcs)->bus->dev, ##__args); \
+ dev_warn(&(__xpcs)->mdiodev->dev, ##__args); \
})
-static int xpcs_read_fault_c73(struct mdio_xpcs_args *xpcs,
+static int xpcs_read_fault_c73(struct dw_xpcs *xpcs,
struct phylink_link_state *state)
{
int ret;
@@ -328,7 +305,7 @@ static int xpcs_read_fault_c73(struct mdio_xpcs_args *xpcs,
return 0;
}
-static int xpcs_read_link_c73(struct mdio_xpcs_args *xpcs, bool an)
+static int xpcs_read_link_c73(struct dw_xpcs *xpcs, bool an)
{
bool link = true;
int ret;
@@ -368,7 +345,7 @@ static int xpcs_get_max_usxgmii_speed(const unsigned long *supported)
return max;
}
-static int xpcs_config_usxgmii(struct mdio_xpcs_args *xpcs, int speed)
+static void xpcs_config_usxgmii(struct dw_xpcs *xpcs, int speed)
{
int ret, speed_sel;
@@ -393,36 +370,44 @@ static int xpcs_config_usxgmii(struct mdio_xpcs_args *xpcs, int speed)
break;
default:
/* Nothing to do here */
- return -EINVAL;
+ return;
}
ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1);
if (ret < 0)
- return ret;
+ goto out;
ret = xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_EN);
if (ret < 0)
- return ret;
+ goto out;
ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
if (ret < 0)
- return ret;
+ goto out;
ret &= ~DW_USXGMII_SS_MASK;
ret |= speed_sel | DW_USXGMII_FULL;
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, ret);
if (ret < 0)
- return ret;
+ goto out;
ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1);
if (ret < 0)
- return ret;
+ goto out;
- return xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_RST);
+ ret = xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_RST);
+ if (ret < 0)
+ goto out;
+
+ return;
+
+out:
+ pr_err("%s: XPCS access returned %pe\n", __func__, ERR_PTR(ret));
}
-static int _xpcs_config_aneg_c73(struct mdio_xpcs_args *xpcs)
+static int _xpcs_config_aneg_c73(struct dw_xpcs *xpcs,
+ const struct xpcs_compat *compat)
{
int ret, adv;
@@ -434,7 +419,7 @@ static int _xpcs_config_aneg_c73(struct mdio_xpcs_args *xpcs)
/* SR_AN_ADV3 */
adv = 0;
- if (phylink_test(xpcs->supported, 2500baseX_Full))
+ if (xpcs_linkmode_supported(compat, 2500baseX_Full))
adv |= DW_C73_2500KX;
/* TODO: 5000baseKR */
@@ -445,11 +430,11 @@ static int _xpcs_config_aneg_c73(struct mdio_xpcs_args *xpcs)
/* SR_AN_ADV2 */
adv = 0;
- if (phylink_test(xpcs->supported, 1000baseKX_Full))
+ if (xpcs_linkmode_supported(compat, 1000baseKX_Full))
adv |= DW_C73_1000KX;
- if (phylink_test(xpcs->supported, 10000baseKX4_Full))
+ if (xpcs_linkmode_supported(compat, 10000baseKX4_Full))
adv |= DW_C73_10000KX4;
- if (phylink_test(xpcs->supported, 10000baseKR_Full))
+ if (xpcs_linkmode_supported(compat, 10000baseKR_Full))
adv |= DW_C73_10000KR;
ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV2, adv);
@@ -458,19 +443,20 @@ static int _xpcs_config_aneg_c73(struct mdio_xpcs_args *xpcs)
/* SR_AN_ADV1 */
adv = DW_C73_AN_ADV_SF;
- if (phylink_test(xpcs->supported, Pause))
+ if (xpcs_linkmode_supported(compat, Pause))
adv |= DW_C73_PAUSE;
- if (phylink_test(xpcs->supported, Asym_Pause))
+ if (xpcs_linkmode_supported(compat, Asym_Pause))
adv |= DW_C73_ASYM_PAUSE;
return xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV1, adv);
}
-static int xpcs_config_aneg_c73(struct mdio_xpcs_args *xpcs)
+static int xpcs_config_aneg_c73(struct dw_xpcs *xpcs,
+ const struct xpcs_compat *compat)
{
int ret;
- ret = _xpcs_config_aneg_c73(xpcs);
+ ret = _xpcs_config_aneg_c73(xpcs, compat);
if (ret < 0)
return ret;
@@ -483,8 +469,9 @@ static int xpcs_config_aneg_c73(struct mdio_xpcs_args *xpcs)
return xpcs_write(xpcs, MDIO_MMD_AN, MDIO_CTRL1, ret);
}
-static int xpcs_aneg_done_c73(struct mdio_xpcs_args *xpcs,
- struct phylink_link_state *state)
+static int xpcs_aneg_done_c73(struct dw_xpcs *xpcs,
+ struct phylink_link_state *state,
+ const struct xpcs_compat *compat)
{
int ret;
@@ -499,7 +486,7 @@ static int xpcs_aneg_done_c73(struct mdio_xpcs_args *xpcs,
/* Check if Aneg outcome is valid */
if (!(ret & DW_C73_AN_ADV_SF)) {
- xpcs_config_aneg_c73(xpcs);
+ xpcs_config_aneg_c73(xpcs, compat);
return 0;
}
@@ -509,7 +496,7 @@ static int xpcs_aneg_done_c73(struct mdio_xpcs_args *xpcs,
return 0;
}
-static int xpcs_read_lpa_c73(struct mdio_xpcs_args *xpcs,
+static int xpcs_read_lpa_c73(struct dw_xpcs *xpcs,
struct phylink_link_state *state)
{
int ret;
@@ -558,7 +545,7 @@ static int xpcs_read_lpa_c73(struct mdio_xpcs_args *xpcs,
return 0;
}
-static void xpcs_resolve_lpa_c73(struct mdio_xpcs_args *xpcs,
+static void xpcs_resolve_lpa_c73(struct dw_xpcs *xpcs,
struct phylink_link_state *state)
{
int max_speed = xpcs_get_max_usxgmii_speed(state->lp_advertising);
@@ -568,7 +555,7 @@ static void xpcs_resolve_lpa_c73(struct mdio_xpcs_args *xpcs,
state->duplex = DUPLEX_FULL;
}
-static int xpcs_get_max_xlgmii_speed(struct mdio_xpcs_args *xpcs,
+static int xpcs_get_max_xlgmii_speed(struct dw_xpcs *xpcs,
struct phylink_link_state *state)
{
unsigned long *adv = state->advertising;
@@ -622,7 +609,7 @@ static int xpcs_get_max_xlgmii_speed(struct mdio_xpcs_args *xpcs,
return speed;
}
-static void xpcs_resolve_pma(struct mdio_xpcs_args *xpcs,
+static void xpcs_resolve_pma(struct dw_xpcs *xpcs,
struct phylink_link_state *state)
{
state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
@@ -641,16 +628,70 @@ static void xpcs_resolve_pma(struct mdio_xpcs_args *xpcs,
}
}
-static int xpcs_validate(struct mdio_xpcs_args *xpcs,
- unsigned long *supported,
- struct phylink_link_state *state)
+void xpcs_validate(struct dw_xpcs *xpcs, unsigned long *supported,
+ struct phylink_link_state *state)
{
- linkmode_and(supported, supported, xpcs->supported);
- linkmode_and(state->advertising, state->advertising, xpcs->supported);
- return 0;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(xpcs_supported);
+ const struct xpcs_compat *compat;
+ int i;
+
+ /* phylink expects us to report all supported modes with
+ * PHY_INTERFACE_MODE_NA, just don't limit the supported and
+ * advertising masks and exit.
+ */
+ if (state->interface == PHY_INTERFACE_MODE_NA)
+ return;
+
+ bitmap_zero(xpcs_supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+
+ compat = xpcs_find_compat(xpcs->id, state->interface);
+
+ /* Populate the supported link modes for this
+ * PHY interface type
+ */
+ if (compat)
+ for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
+ set_bit(compat->supported[i], xpcs_supported);
+
+ linkmode_and(supported, supported, xpcs_supported);
+ linkmode_and(state->advertising, state->advertising, xpcs_supported);
}
+EXPORT_SYMBOL_GPL(xpcs_validate);
-static int xpcs_config_aneg_c37_sgmii(struct mdio_xpcs_args *xpcs)
+int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable)
+{
+ int ret;
+
+ if (enable) {
+ /* Enable EEE */
+ ret = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
+ DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
+ DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
+ mult_fact_100ns << DW_VR_MII_EEE_MULT_FACT_100NS_SHIFT;
+ } else {
+ ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0);
+ if (ret < 0)
+ return ret;
+ ret &= ~(DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
+ DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
+ DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
+ DW_VR_MII_EEE_MULT_FACT_100NS);
+ }
+
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0, ret);
+ if (ret < 0)
+ return ret;
+
+ ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1);
+ if (ret < 0)
+ return ret;
+
+ ret |= DW_VR_MII_EEE_TRN_LPI;
+ return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1, ret);
+}
+EXPORT_SYMBOL_GPL(xpcs_config_eee);
+
+static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, unsigned int mode)
{
int ret;
@@ -686,26 +727,61 @@ static int xpcs_config_aneg_c37_sgmii(struct mdio_xpcs_args *xpcs)
if (ret < 0)
return ret;
- ret |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+ if (phylink_autoneg_inband(mode))
+ ret |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+ else
+ ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
}
-static int xpcs_config(struct mdio_xpcs_args *xpcs,
- const struct phylink_link_state *state)
+static int xpcs_config_2500basex(struct dw_xpcs *xpcs)
+{
+ int ret;
+
+ ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
+ if (ret < 0)
+ return ret;
+ ret |= DW_VR_MII_DIG_CTRL1_2G5_EN;
+ ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
+ if (ret < 0)
+ return ret;
+
+ ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL);
+ if (ret < 0)
+ return ret;
+ ret &= ~AN_CL37_EN;
+ ret |= SGMII_SPEED_SS6;
+ ret &= ~SGMII_SPEED_SS13;
+ return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, ret);
+}
+
+int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
+ unsigned int mode)
{
+ const struct xpcs_compat *compat;
int ret;
- switch (xpcs->an_mode) {
+ compat = xpcs_find_compat(xpcs->id, interface);
+ if (!compat)
+ return -ENODEV;
+
+ switch (compat->an_mode) {
case DW_AN_C73:
- if (state->an_enabled) {
- ret = xpcs_config_aneg_c73(xpcs);
+ if (phylink_autoneg_inband(mode)) {
+ ret = xpcs_config_aneg_c73(xpcs, compat);
if (ret)
return ret;
}
break;
case DW_AN_C37_SGMII:
- ret = xpcs_config_aneg_c37_sgmii(xpcs);
+ ret = xpcs_config_aneg_c37_sgmii(xpcs, mode);
+ if (ret)
+ return ret;
+ break;
+ case DW_2500BASEX:
+ ret = xpcs_config_2500basex(xpcs);
if (ret)
return ret;
break;
@@ -713,11 +789,29 @@ static int xpcs_config(struct mdio_xpcs_args *xpcs,
return -1;
}
+ if (compat->pma_config) {
+ ret = compat->pma_config(xpcs);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
+EXPORT_SYMBOL_GPL(xpcs_do_config);
+
+static int xpcs_config(struct phylink_pcs *pcs, unsigned int mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
+
+ return xpcs_do_config(xpcs, interface, mode);
+}
-static int xpcs_get_state_c73(struct mdio_xpcs_args *xpcs,
- struct phylink_link_state *state)
+static int xpcs_get_state_c73(struct dw_xpcs *xpcs,
+ struct phylink_link_state *state,
+ const struct xpcs_compat *compat)
{
int ret;
@@ -727,16 +821,16 @@ static int xpcs_get_state_c73(struct mdio_xpcs_args *xpcs,
/* ... and then we check the faults. */
ret = xpcs_read_fault_c73(xpcs, state);
if (ret) {
- ret = xpcs_soft_reset(xpcs);
+ ret = xpcs_soft_reset(xpcs, compat);
if (ret)
return ret;
state->link = 0;
- return xpcs_config(xpcs, state);
+ return xpcs_do_config(xpcs, state->interface, MLO_AN_INBAND);
}
- if (state->an_enabled && xpcs_aneg_done_c73(xpcs, state)) {
+ if (state->an_enabled && xpcs_aneg_done_c73(xpcs, state, compat)) {
state->an_complete = true;
xpcs_read_lpa_c73(xpcs, state);
xpcs_resolve_lpa_c73(xpcs, state);
@@ -749,7 +843,7 @@ static int xpcs_get_state_c73(struct mdio_xpcs_args *xpcs,
return 0;
}
-static int xpcs_get_state_c37_sgmii(struct mdio_xpcs_args *xpcs,
+static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
struct phylink_link_state *state)
{
int ret;
@@ -790,39 +884,81 @@ static int xpcs_get_state_c37_sgmii(struct mdio_xpcs_args *xpcs,
return 0;
}
-static int xpcs_get_state(struct mdio_xpcs_args *xpcs,
- struct phylink_link_state *state)
+static void xpcs_get_state(struct phylink_pcs *pcs,
+ struct phylink_link_state *state)
{
+ struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
+ const struct xpcs_compat *compat;
int ret;
- switch (xpcs->an_mode) {
+ compat = xpcs_find_compat(xpcs->id, state->interface);
+ if (!compat)
+ return;
+
+ switch (compat->an_mode) {
case DW_AN_C73:
- ret = xpcs_get_state_c73(xpcs, state);
- if (ret)
- return ret;
+ ret = xpcs_get_state_c73(xpcs, state, compat);
+ if (ret) {
+ pr_err("xpcs_get_state_c73 returned %pe\n",
+ ERR_PTR(ret));
+ return;
+ }
break;
case DW_AN_C37_SGMII:
ret = xpcs_get_state_c37_sgmii(xpcs, state);
- if (ret)
- return ret;
+ if (ret) {
+ pr_err("xpcs_get_state_c37_sgmii returned %pe\n",
+ ERR_PTR(ret));
+ }
break;
default:
- return -1;
+ return;
}
+}
- return 0;
+static void xpcs_link_up_sgmii(struct dw_xpcs *xpcs, unsigned int mode,
+ int speed, int duplex)
+{
+ int val, ret;
+
+ if (phylink_autoneg_inband(mode))
+ return;
+
+ switch (speed) {
+ case SPEED_1000:
+ val = BMCR_SPEED1000;
+ break;
+ case SPEED_100:
+ val = BMCR_SPEED100;
+ break;
+ case SPEED_10:
+ val = BMCR_SPEED10;
+ break;
+ default:
+ return;
+ }
+
+ if (duplex == DUPLEX_FULL)
+ val |= BMCR_FULLDPLX;
+
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, val);
+ if (ret)
+ pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret));
}
-static int xpcs_link_up(struct mdio_xpcs_args *xpcs, int speed,
- phy_interface_t interface)
+void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
+ phy_interface_t interface, int speed, int duplex)
{
+ struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
+
if (interface == PHY_INTERFACE_MODE_USXGMII)
return xpcs_config_usxgmii(xpcs, speed);
-
- return 0;
+ if (interface == PHY_INTERFACE_MODE_SGMII)
+ return xpcs_link_up_sgmii(xpcs, mode, speed, duplex);
}
+EXPORT_SYMBOL_GPL(xpcs_link_up);
-static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs)
+static u32 xpcs_get_id(struct dw_xpcs *xpcs)
{
int ret;
u32 id;
@@ -838,8 +974,10 @@ static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs)
if (ret < 0)
return 0xffffffff;
- /* If Device IDs are not all zeros, we found C73 AN-type device */
- if (id | ret)
+ /* If Device IDs are not all zeros or all ones,
+ * we found C73 AN-type device
+ */
+ if ((id | ret) && (id | ret) != 0xffffffff)
return id | ret;
/* Next, search C37 PCS using Vendor-Specific MII MMD */
@@ -860,60 +998,141 @@ static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs)
return 0xffffffff;
}
-static bool xpcs_check_features(struct mdio_xpcs_args *xpcs,
- struct xpcs_id *match,
- phy_interface_t interface)
-{
- int i;
-
- for (i = 0; match->interface[i] != PHY_INTERFACE_MODE_MAX; i++) {
- if (match->interface[i] == interface)
- break;
- }
+static const struct xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
+ [DW_XPCS_USXGMII] = {
+ .supported = xpcs_usxgmii_features,
+ .interface = xpcs_usxgmii_interfaces,
+ .num_interfaces = ARRAY_SIZE(xpcs_usxgmii_interfaces),
+ .an_mode = DW_AN_C73,
+ },
+ [DW_XPCS_10GKR] = {
+ .supported = xpcs_10gkr_features,
+ .interface = xpcs_10gkr_interfaces,
+ .num_interfaces = ARRAY_SIZE(xpcs_10gkr_interfaces),
+ .an_mode = DW_AN_C73,
+ },
+ [DW_XPCS_XLGMII] = {
+ .supported = xpcs_xlgmii_features,
+ .interface = xpcs_xlgmii_interfaces,
+ .num_interfaces = ARRAY_SIZE(xpcs_xlgmii_interfaces),
+ .an_mode = DW_AN_C73,
+ },
+ [DW_XPCS_SGMII] = {
+ .supported = xpcs_sgmii_features,
+ .interface = xpcs_sgmii_interfaces,
+ .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
+ .an_mode = DW_AN_C37_SGMII,
+ },
+ [DW_XPCS_2500BASEX] = {
+ .supported = xpcs_2500basex_features,
+ .interface = xpcs_2500basex_interfaces,
+ .num_interfaces = ARRAY_SIZE(xpcs_2500basex_features),
+ .an_mode = DW_2500BASEX,
+ },
+};
- if (match->interface[i] == PHY_INTERFACE_MODE_MAX)
- return false;
+static const struct xpcs_compat nxp_sja1105_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
+ [DW_XPCS_SGMII] = {
+ .supported = xpcs_sgmii_features,
+ .interface = xpcs_sgmii_interfaces,
+ .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
+ .an_mode = DW_AN_C37_SGMII,
+ .pma_config = nxp_sja1105_sgmii_pma_config,
+ },
+};
- for (i = 0; match->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
- set_bit(match->supported[i], xpcs->supported);
+static const struct xpcs_compat nxp_sja1110_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
+ [DW_XPCS_SGMII] = {
+ .supported = xpcs_sgmii_features,
+ .interface = xpcs_sgmii_interfaces,
+ .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
+ .an_mode = DW_AN_C37_SGMII,
+ .pma_config = nxp_sja1110_sgmii_pma_config,
+ },
+ [DW_XPCS_2500BASEX] = {
+ .supported = xpcs_2500basex_features,
+ .interface = xpcs_2500basex_interfaces,
+ .num_interfaces = ARRAY_SIZE(xpcs_2500basex_interfaces),
+ .an_mode = DW_2500BASEX,
+ .pma_config = nxp_sja1110_2500basex_pma_config,
+ },
+};
- xpcs->an_mode = match->an_mode;
+static const struct xpcs_id xpcs_id_list[] = {
+ {
+ .id = SYNOPSYS_XPCS_ID,
+ .mask = SYNOPSYS_XPCS_MASK,
+ .compat = synopsys_xpcs_compat,
+ }, {
+ .id = NXP_SJA1105_XPCS_ID,
+ .mask = SYNOPSYS_XPCS_MASK,
+ .compat = nxp_sja1105_xpcs_compat,
+ }, {
+ .id = NXP_SJA1110_XPCS_ID,
+ .mask = SYNOPSYS_XPCS_MASK,
+ .compat = nxp_sja1110_xpcs_compat,
+ },
+};
- return true;
-}
+static const struct phylink_pcs_ops xpcs_phylink_ops = {
+ .pcs_config = xpcs_config,
+ .pcs_get_state = xpcs_get_state,
+ .pcs_link_up = xpcs_link_up,
+};
-static int xpcs_probe(struct mdio_xpcs_args *xpcs, phy_interface_t interface)
+struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
+ phy_interface_t interface)
{
- u32 xpcs_id = xpcs_get_id(xpcs);
- struct xpcs_id *match = NULL;
- int i;
+ struct dw_xpcs *xpcs;
+ u32 xpcs_id;
+ int i, ret;
+
+ xpcs = kzalloc(sizeof(*xpcs), GFP_KERNEL);
+ if (!xpcs)
+ return NULL;
+
+ xpcs->mdiodev = mdiodev;
+
+ xpcs_id = xpcs_get_id(xpcs);
for (i = 0; i < ARRAY_SIZE(xpcs_id_list); i++) {
- struct xpcs_id *entry = &xpcs_id_list[i];
+ const struct xpcs_id *entry = &xpcs_id_list[i];
+ const struct xpcs_compat *compat;
+
+ if ((xpcs_id & entry->mask) != entry->id)
+ continue;
- if ((xpcs_id & entry->mask) == entry->id) {
- match = entry;
+ xpcs->id = entry;
- if (xpcs_check_features(xpcs, match, interface))
- return xpcs_soft_reset(xpcs);
+ compat = xpcs_find_compat(entry, interface);
+ if (!compat) {
+ ret = -ENODEV;
+ goto out;
}
+
+ xpcs->pcs.ops = &xpcs_phylink_ops;
+ xpcs->pcs.poll = true;
+
+ ret = xpcs_soft_reset(xpcs, compat);
+ if (ret)
+ goto out;
+
+ return xpcs;
}
- return -ENODEV;
-}
+ ret = -ENODEV;
-static struct mdio_xpcs_ops xpcs_ops = {
- .validate = xpcs_validate,
- .config = xpcs_config,
- .get_state = xpcs_get_state,
- .link_up = xpcs_link_up,
- .probe = xpcs_probe,
-};
+out:
+ kfree(xpcs);
+
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(xpcs_create);
-struct mdio_xpcs_ops *mdio_xpcs_get_ops(void)
+void xpcs_destroy(struct dw_xpcs *xpcs)
{
- return &xpcs_ops;
+ kfree(xpcs);
}
-EXPORT_SYMBOL_GPL(mdio_xpcs_get_ops);
+EXPORT_SYMBOL_GPL(xpcs_destroy);
MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/pcs/pcs-xpcs.h b/drivers/net/pcs/pcs-xpcs.h
new file mode 100644
index 000000000000..35651d32a224
--- /dev/null
+++ b/drivers/net/pcs/pcs-xpcs.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 Synopsys, Inc. and/or its affiliates.
+ * Synopsys DesignWare XPCS helpers
+ *
+ * Author: Jose Abreu <Jose.Abreu@synopsys.com>
+ */
+
+#define SYNOPSYS_XPCS_ID 0x7996ced0
+#define SYNOPSYS_XPCS_MASK 0xffffffff
+
+/* Vendor regs access */
+#define DW_VENDOR BIT(15)
+
+/* VR_XS_PCS */
+#define DW_USXGMII_RST BIT(10)
+#define DW_USXGMII_EN BIT(9)
+#define DW_VR_XS_PCS_DIG_STS 0x0010
+#define DW_RXFIFO_ERR GENMASK(6, 5)
+
+/* SR_MII */
+#define DW_USXGMII_FULL BIT(8)
+#define DW_USXGMII_SS_MASK (BIT(13) | BIT(6) | BIT(5))
+#define DW_USXGMII_10000 (BIT(13) | BIT(6))
+#define DW_USXGMII_5000 (BIT(13) | BIT(5))
+#define DW_USXGMII_2500 (BIT(5))
+#define DW_USXGMII_1000 (BIT(6))
+#define DW_USXGMII_100 (BIT(13))
+#define DW_USXGMII_10 (0)
+
+/* SR_AN */
+#define DW_SR_AN_ADV1 0x10
+#define DW_SR_AN_ADV2 0x11
+#define DW_SR_AN_ADV3 0x12
+#define DW_SR_AN_LP_ABL1 0x13
+#define DW_SR_AN_LP_ABL2 0x14
+#define DW_SR_AN_LP_ABL3 0x15
+
+/* Clause 73 Defines */
+/* AN_LP_ABL1 */
+#define DW_C73_PAUSE BIT(10)
+#define DW_C73_ASYM_PAUSE BIT(11)
+#define DW_C73_AN_ADV_SF 0x1
+/* AN_LP_ABL2 */
+#define DW_C73_1000KX BIT(5)
+#define DW_C73_10000KX4 BIT(6)
+#define DW_C73_10000KR BIT(7)
+/* AN_LP_ABL3 */
+#define DW_C73_2500KX BIT(0)
+#define DW_C73_5000KR BIT(1)
+
+/* Clause 37 Defines */
+/* VR MII MMD registers offsets */
+#define DW_VR_MII_MMD_CTRL 0x0000
+#define DW_VR_MII_DIG_CTRL1 0x8000
+#define DW_VR_MII_AN_CTRL 0x8001
+#define DW_VR_MII_AN_INTR_STS 0x8002
+/* Enable 2.5G Mode */
+#define DW_VR_MII_DIG_CTRL1_2G5_EN BIT(2)
+/* EEE Mode Control Register */
+#define DW_VR_MII_EEE_MCTRL0 0x8006
+#define DW_VR_MII_EEE_MCTRL1 0x800b
+#define DW_VR_MII_DIG_CTRL2 0x80e1
+
+/* VR_MII_DIG_CTRL1 */
+#define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9)
+
+/* VR_MII_DIG_CTRL2 */
+#define DW_VR_MII_DIG_CTRL2_TX_POL_INV BIT(4)
+#define DW_VR_MII_DIG_CTRL2_RX_POL_INV BIT(0)
+
+/* VR_MII_AN_CTRL */
+#define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT 3
+#define DW_VR_MII_TX_CONFIG_MASK BIT(3)
+#define DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII 0x1
+#define DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII 0x0
+#define DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT 1
+#define DW_VR_MII_PCS_MODE_MASK GENMASK(2, 1)
+#define DW_VR_MII_PCS_MODE_C37_1000BASEX 0x0
+#define DW_VR_MII_PCS_MODE_C37_SGMII 0x2
+
+/* VR_MII_AN_INTR_STS */
+#define DW_VR_MII_AN_STS_C37_ANSGM_FD BIT(1)
+#define DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT 2
+#define DW_VR_MII_AN_STS_C37_ANSGM_SP GENMASK(3, 2)
+#define DW_VR_MII_C37_ANSGM_SP_10 0x0
+#define DW_VR_MII_C37_ANSGM_SP_100 0x1
+#define DW_VR_MII_C37_ANSGM_SP_1000 0x2
+#define DW_VR_MII_C37_ANSGM_SP_LNKSTS BIT(4)
+
+/* SR MII MMD Control defines */
+#define AN_CL37_EN BIT(12) /* Enable Clause 37 auto-nego */
+#define SGMII_SPEED_SS13 BIT(13) /* SGMII speed along with SS6 */
+#define SGMII_SPEED_SS6 BIT(6) /* SGMII speed along with SS13 */
+
+/* VR MII EEE Control 0 defines */
+#define DW_VR_MII_EEE_LTX_EN BIT(0) /* LPI Tx Enable */
+#define DW_VR_MII_EEE_LRX_EN BIT(1) /* LPI Rx Enable */
+#define DW_VR_MII_EEE_TX_QUIET_EN BIT(2) /* Tx Quiet Enable */
+#define DW_VR_MII_EEE_RX_QUIET_EN BIT(3) /* Rx Quiet Enable */
+#define DW_VR_MII_EEE_TX_EN_CTRL BIT(4) /* Tx Control Enable */
+#define DW_VR_MII_EEE_RX_EN_CTRL BIT(7) /* Rx Control Enable */
+
+#define DW_VR_MII_EEE_MULT_FACT_100NS_SHIFT 8
+#define DW_VR_MII_EEE_MULT_FACT_100NS GENMASK(11, 8)
+
+/* VR MII EEE Control 1 defines */
+#define DW_VR_MII_EEE_TRN_LPI BIT(0) /* Transparent Mode Enable */
+
+int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg);
+int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val);
+
+int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs);
+int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs);
+int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 288bf405ebdb..c56f703ae998 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -207,6 +207,11 @@ config MARVELL_88X2222_PHY
Support for the Marvell 88X2222 Dual-port Multi-speed Ethernet
Transceiver.
+config MEDIATEK_GE_PHY
+ tristate "MediaTek Gigabit Ethernet PHYs"
+ help
+ Supports the MediaTek Gigabit Ethernet PHYs.
+
config MICREL_PHY
tristate "Micrel PHYs"
help
@@ -229,6 +234,12 @@ config MICROSEMI_PHY
help
Currently supports VSC8514, VSC8530, VSC8531, VSC8540 and VSC8541 PHYs
+config MOTORCOMM_PHY
+ tristate "Motorcomm PHYs"
+ help
+ Enables support for Motorcomm network PHYs.
+ Currently supports the YT8511 gigabit PHY.
+
config NATIONAL_PHY
tristate "National Semiconductor PHYs"
help
@@ -247,10 +258,11 @@ config NXP_TJA11XX_PHY
Currently supports the NXP TJA1100 and TJA1101 PHY.
config AT803X_PHY
- tristate "Qualcomm Atheros AR803X PHYs"
+ tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs"
depends on REGULATOR
help
- Currently supports the AR8030, AR8031, AR8033 and AR8035 model
+ Currently supports the AR8030, AR8031, AR8033, AR8035 and internal
+ QCA8337(Internal qca8k PHY) model
config QSEMI_PHY
tristate "Quality Semiconductor PHYs"
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index bcda7ed2455d..172bb193ae6a 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -64,12 +64,14 @@ obj-$(CONFIG_LXT_PHY) += lxt.o
obj-$(CONFIG_MARVELL_10G_PHY) += marvell10g.o
obj-$(CONFIG_MARVELL_PHY) += marvell.o
obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o
+obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o
obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o
obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
obj-$(CONFIG_MICREL_PHY) += micrel.o
obj-$(CONFIG_MICROCHIP_PHY) += microchip.o
obj-$(CONFIG_MICROCHIP_T1_PHY) += microchip_t1.o
obj-$(CONFIG_MICROSEMI_PHY) += mscc/
+obj-$(CONFIG_MOTORCOMM_PHY) += motorcomm.o
obj-$(CONFIG_NATIONAL_PHY) += national.o
obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp-c45-tja11xx.o
obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
index 55a0b91816e2..5ce6da62cc8e 100644
--- a/drivers/net/phy/adin.c
+++ b/drivers/net/phy/adin.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
-/**
+/*
* Driver for Analog Devices Industrial Ethernet PHYs
*
* Copyright 2019 Analog Devices Inc.
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index 32af52dd5aed..5d62b85a4024 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -83,8 +83,8 @@
#define AT803X_MODE_CFG_MASK 0x0F
#define AT803X_MODE_CFG_SGMII 0x01
-#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
-#define AT803X_PSSR_MR_AN_COMPLETE 0x0200
+#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
+#define AT803X_PSSR_MR_AN_COMPLETE 0x0200
#define AT803X_DEBUG_REG_0 0x00
#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
@@ -92,10 +92,16 @@
#define AT803X_DEBUG_REG_5 0x05
#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
+#define AT803X_DEBUG_REG_3C 0x3C
+
+#define AT803X_DEBUG_REG_3D 0x3D
+
#define AT803X_DEBUG_REG_1F 0x1F
#define AT803X_DEBUG_PLL_ON BIT(2)
#define AT803X_DEBUG_RGMII_1V8 BIT(3)
+#define MDIO_AZ_DEBUG 0x800D
+
/* AT803x supports either the XTAL input pad, an internal PLL or the
* DSP as clock reference for the clock output pad. The XTAL reference
* is only used for 25 MHz output, all other frequencies need the PLL.
@@ -128,33 +134,59 @@
#define AT803X_CLK_OUT_STRENGTH_HALF 1
#define AT803X_CLK_OUT_STRENGTH_QUARTER 2
-#define AT803X_DEFAULT_DOWNSHIFT 5
-#define AT803X_MIN_DOWNSHIFT 2
-#define AT803X_MAX_DOWNSHIFT 9
+#define AT803X_DEFAULT_DOWNSHIFT 5
+#define AT803X_MIN_DOWNSHIFT 2
+#define AT803X_MAX_DOWNSHIFT 9
#define AT803X_MMD3_SMARTEEE_CTL1 0x805b
#define AT803X_MMD3_SMARTEEE_CTL2 0x805c
#define AT803X_MMD3_SMARTEEE_CTL3 0x805d
#define AT803X_MMD3_SMARTEEE_CTL3_LPI_EN BIT(8)
-#define ATH9331_PHY_ID 0x004dd041
-#define ATH8030_PHY_ID 0x004dd076
-#define ATH8031_PHY_ID 0x004dd074
-#define ATH8032_PHY_ID 0x004dd023
-#define ATH8035_PHY_ID 0x004dd072
+#define ATH9331_PHY_ID 0x004dd041
+#define ATH8030_PHY_ID 0x004dd076
+#define ATH8031_PHY_ID 0x004dd074
+#define ATH8032_PHY_ID 0x004dd023
+#define ATH8035_PHY_ID 0x004dd072
#define AT8030_PHY_ID_MASK 0xffffffef
-#define AT803X_PAGE_FIBER 0
-#define AT803X_PAGE_COPPER 1
+#define QCA8327_PHY_ID 0x004dd034
+#define QCA8337_PHY_ID 0x004dd036
+#define QCA8K_PHY_ID_MASK 0xffffffff
+
+#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
+
+#define AT803X_PAGE_FIBER 0
+#define AT803X_PAGE_COPPER 1
+
+/* don't turn off internal PLL */
+#define AT803X_KEEP_PLL_ENABLED BIT(0)
+#define AT803X_DISABLE_SMARTEEE BIT(1)
MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver");
MODULE_AUTHOR("Matus Ujhelyi");
MODULE_LICENSE("GPL");
+enum stat_access_type {
+ PHY,
+ MMD
+};
+
+struct at803x_hw_stat {
+ const char *string;
+ u8 reg;
+ u32 mask;
+ enum stat_access_type access_type;
+};
+
+static struct at803x_hw_stat at803x_hw_stats[] = {
+ { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
+ { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
+ { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
+};
+
struct at803x_priv {
int flags;
-#define AT803X_KEEP_PLL_ENABLED BIT(0) /* don't turn off internal PLL */
-#define AT803X_DISABLE_SMARTEEE BIT(1)
u16 clk_25m_reg;
u16 clk_25m_mask;
u8 smarteee_lpi_tw_1g;
@@ -162,6 +194,7 @@ struct at803x_priv {
struct regulator_dev *vddio_rdev;
struct regulator_dev *vddh_rdev;
struct regulator *vddio;
+ u64 stats[ARRAY_SIZE(at803x_hw_stats)];
};
struct at803x_context {
@@ -173,6 +206,17 @@ struct at803x_context {
u16 led_control;
};
+static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data)
+{
+ int ret;
+
+ ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
+ if (ret < 0)
+ return ret;
+
+ return phy_write(phydev, AT803X_DEBUG_DATA, data);
+}
+
static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
{
int ret;
@@ -335,6 +379,53 @@ static void at803x_get_wol(struct phy_device *phydev,
wol->wolopts |= WAKE_MAGIC;
}
+static int at803x_get_sset_count(struct phy_device *phydev)
+{
+ return ARRAY_SIZE(at803x_hw_stats);
+}
+
+static void at803x_get_strings(struct phy_device *phydev, u8 *data)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++) {
+ strscpy(data + i * ETH_GSTRING_LEN,
+ at803x_hw_stats[i].string, ETH_GSTRING_LEN);
+ }
+}
+
+static u64 at803x_get_stat(struct phy_device *phydev, int i)
+{
+ struct at803x_hw_stat stat = at803x_hw_stats[i];
+ struct at803x_priv *priv = phydev->priv;
+ int val;
+ u64 ret;
+
+ if (stat.access_type == MMD)
+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
+ else
+ val = phy_read(phydev, stat.reg);
+
+ if (val < 0) {
+ ret = U64_MAX;
+ } else {
+ val = val & stat.mask;
+ priv->stats[i] += val;
+ ret = priv->stats[i];
+ }
+
+ return ret;
+}
+
+static void at803x_get_stats(struct phy_device *phydev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++)
+ data[i] = at803x_get_stat(phydev, i);
+}
+
static int at803x_suspend(struct phy_device *phydev)
{
int value;
@@ -610,6 +701,34 @@ static void at803x_remove(struct phy_device *phydev)
regulator_disable(priv->vddio);
}
+static int at803x_get_features(struct phy_device *phydev)
+{
+ int err;
+
+ err = genphy_read_abilities(phydev);
+ if (err)
+ return err;
+
+ if (!at803x_match_phy_id(phydev, ATH8031_PHY_ID))
+ return 0;
+
+ /* AR8031/AR8033 have different status registers
+ * for copper and fiber operation. However, the
+ * extended status register is the same for both
+ * operation modes.
+ *
+ * As a result of that, ESTATUS_1000_XFULL is set
+ * to 1 even when operating in copper TP mode.
+ *
+ * Remove this mode from the supported link modes,
+ * as this driver currently only supports copper
+ * operation.
+ */
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
+ phydev->supported);
+ return 0;
+}
+
static int at803x_smarteee_config(struct phy_device *phydev)
{
struct at803x_priv *priv = phydev->priv;
@@ -1170,6 +1289,34 @@ static int at803x_cable_test_start(struct phy_device *phydev)
return 0;
}
+static int qca83xx_config_init(struct phy_device *phydev)
+{
+ u8 switch_revision;
+
+ switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
+
+ switch (switch_revision) {
+ case 1:
+ /* For 100M waveform */
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_0, 0x02ea);
+ /* Turn on Gigabit clock */
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x68a0);
+ break;
+
+ case 2:
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
+ fallthrough;
+ case 4:
+ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x6860);
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_5, 0x2c46);
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
+ break;
+ }
+
+ return 0;
+}
+
static struct phy_driver at803x_driver[] = {
{
/* Qualcomm Atheros AR8035 */
@@ -1225,7 +1372,7 @@ static struct phy_driver at803x_driver[] = {
.resume = at803x_resume,
.read_page = at803x_read_page,
.write_page = at803x_write_page,
- /* PHY_GBIT_FEATURES */
+ .get_features = at803x_get_features,
.read_status = at803x_read_status,
.config_intr = &at803x_config_intr,
.handle_interrupt = at803x_handle_interrupt,
@@ -1266,7 +1413,20 @@ static struct phy_driver at803x_driver[] = {
.read_status = at803x_read_status,
.soft_reset = genphy_soft_reset,
.config_aneg = at803x_config_aneg,
-} };
+}, {
+ /* QCA8337 */
+ .phy_id = QCA8337_PHY_ID,
+ .phy_id_mask = QCA8K_PHY_ID_MASK,
+ .name = "QCA PHY 8337",
+ /* PHY_GBIT_FEATURES */
+ .probe = at803x_probe,
+ .flags = PHY_IS_INTERNAL,
+ .config_init = qca83xx_config_init,
+ .soft_reset = genphy_soft_reset,
+ .get_sset_count = at803x_get_sset_count,
+ .get_strings = at803x_get_strings,
+ .get_stats = at803x_get_stats,
+}, };
module_phy_driver(at803x_driver);
diff --git a/drivers/net/phy/ax88796b.c b/drivers/net/phy/ax88796b.c
index 79bf7ef1fcfd..457896337505 100644
--- a/drivers/net/phy/ax88796b.c
+++ b/drivers/net/phy/ax88796b.c
@@ -10,6 +10,8 @@
#include <linux/mii.h>
#include <linux/phy.h>
+#define PHY_ID_ASIX_AX88772A 0x003b1861
+#define PHY_ID_ASIX_AX88772C 0x003b1881
#define PHY_ID_ASIX_AX88796B 0x003b1841
MODULE_DESCRIPTION("Asix PHY driver");
@@ -39,7 +41,75 @@ static int asix_soft_reset(struct phy_device *phydev)
return genphy_soft_reset(phydev);
}
-static struct phy_driver asix_driver[] = { {
+/* AX88772A is not working properly with some old switches (NETGEAR EN 108TP):
+ * after autoneg is done and the link status is reported as active, the MII_LPA
+ * register is 0. This issue is not reproducible on AX88772C.
+ */
+static int asix_ax88772a_read_status(struct phy_device *phydev)
+{
+ int ret, val;
+
+ ret = genphy_update_link(phydev);
+ if (ret)
+ return ret;
+
+ if (!phydev->link)
+ return 0;
+
+ /* If MII_LPA is 0, phy_resolve_aneg_linkmode() will fail to resolve
+ * linkmode so use MII_BMCR as default values.
+ */
+ val = phy_read(phydev, MII_BMCR);
+ if (val < 0)
+ return val;
+
+ if (val & BMCR_SPEED100)
+ phydev->speed = SPEED_100;
+ else
+ phydev->speed = SPEED_10;
+
+ if (val & BMCR_FULLDPLX)
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ ret = genphy_read_lpa(phydev);
+ if (ret < 0)
+ return ret;
+
+ if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
+ phy_resolve_aneg_linkmode(phydev);
+
+ return 0;
+}
+
+static void asix_ax88772a_link_change_notify(struct phy_device *phydev)
+{
+ /* Reset PHY, otherwise MII_LPA will provide outdated information.
+ * This issue is reproducible only with some link partner PHYs
+ */
+ if (phydev->state == PHY_NOLINK && phydev->drv->soft_reset)
+ phydev->drv->soft_reset(phydev);
+}
+
+static struct phy_driver asix_driver[] = {
+{
+ PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772A),
+ .name = "Asix Electronics AX88772A",
+ .flags = PHY_IS_INTERNAL,
+ .read_status = asix_ax88772a_read_status,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .soft_reset = asix_soft_reset,
+ .link_change_notify = asix_ax88772a_link_change_notify,
+}, {
+ PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772C),
+ .name = "Asix Electronics AX88772C",
+ .flags = PHY_IS_INTERNAL,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .soft_reset = asix_soft_reset,
+}, {
.phy_id = PHY_ID_ASIX_AX88796B,
.name = "Asix Electronics AX88796B",
.phy_id_mask = 0xfffffff0,
@@ -50,6 +120,8 @@ static struct phy_driver asix_driver[] = { {
module_phy_driver(asix_driver);
static struct mdio_device_id __maybe_unused asix_tbl[] = {
+ { PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772A) },
+ { PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772C) },
{ PHY_ID_ASIX_AX88796B, 0xfffffff0 },
{ }
};
diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c
index 4ac8fd190e9d..313563482690 100644
--- a/drivers/net/phy/bcm87xx.c
+++ b/drivers/net/phy/bcm87xx.c
@@ -54,9 +54,9 @@ static int bcm87xx_of_reg_init(struct phy_device *phydev)
u16 reg = be32_to_cpup(paddr++);
u16 mask = be32_to_cpup(paddr++);
u16 val_bits = be32_to_cpup(paddr++);
- int val;
u32 regnum = mdiobus_c45_addr(devid, reg);
- val = 0;
+ int val = 0;
+
if (mask) {
val = phy_read(phydev, regnum);
if (val < 0) {
diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c
index a3b3842c67e5..4ac4bce1bf32 100644
--- a/drivers/net/phy/davicom.c
+++ b/drivers/net/phy/davicom.c
@@ -43,10 +43,10 @@
#define MII_DM9161_INTR_DPLX_CHANGE 0x0010
#define MII_DM9161_INTR_SPD_CHANGE 0x0008
#define MII_DM9161_INTR_LINK_CHANGE 0x0004
-#define MII_DM9161_INTR_INIT 0x0000
+#define MII_DM9161_INTR_INIT 0x0000
#define MII_DM9161_INTR_STOP \
-(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
- | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
+ (MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK | \
+ MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
#define MII_DM9161_INTR_CHANGE \
(MII_DM9161_INTR_DPLX_CHANGE | \
MII_DM9161_INTR_SPD_CHANGE | \
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index 0d79f68f301c..705c16675b80 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -170,9 +170,9 @@ static ushort gpio_tab[GPIO_TABLE_SIZE] = {
module_param(chosen_phy, int, 0444);
module_param_array(gpio_tab, ushort, NULL, 0444);
-MODULE_PARM_DESC(chosen_phy, \
+MODULE_PARM_DESC(chosen_phy,
"The address of the PHY to use for the ancillary clock features");
-MODULE_PARM_DESC(gpio_tab, \
+MODULE_PARM_DESC(gpio_tab,
"Which GPIO line to use for which purpose: cal,perout,extts1,...,extts6");
static void dp83640_gpio_defaults(struct ptp_pin_desc *pd)
@@ -615,6 +615,7 @@ static void prune_rx_ts(struct dp83640_private *dp83640)
static void enable_broadcast(struct phy_device *phydev, int init_page, int on)
{
int val;
+
phy_write(phydev, PAGESEL, 0);
val = phy_read(phydev, PHYCR2);
if (on)
diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c
index 09e07b902d3a..be1b71d7cab7 100644
--- a/drivers/net/phy/et1011c.c
+++ b/drivers/net/phy/et1011c.c
@@ -46,8 +46,8 @@ MODULE_LICENSE("GPL");
static int et1011c_config_aneg(struct phy_device *phydev)
{
- int ctl = 0;
- ctl = phy_read(phydev, MII_BMCR);
+ int ctl = phy_read(phydev, MII_BMCR);
+
if (ctl < 0)
return ctl;
ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 |
@@ -60,9 +60,10 @@ static int et1011c_config_aneg(struct phy_device *phydev)
static int et1011c_read_status(struct phy_device *phydev)
{
+ static int speed;
int ret;
u32 val;
- static int speed;
+
ret = genphy_read_status(phydev);
if (speed != phydev->speed) {
@@ -72,10 +73,10 @@ static int et1011c_read_status(struct phy_device *phydev)
ET1011C_GIGABIT_SPEED) {
val = phy_read(phydev, ET1011C_CONFIG_REG);
val &= ~ET1011C_TX_FIFO_MASK;
- phy_write(phydev, ET1011C_CONFIG_REG, val\
- | ET1011C_GMII_INTERFACE\
- | ET1011C_SYS_CLK_EN\
- | ET1011C_TX_FIFO_DEPTH_16);
+ phy_write(phydev, ET1011C_CONFIG_REG, val |
+ ET1011C_GMII_INTERFACE |
+ ET1011C_SYS_CLK_EN |
+ ET1011C_TX_FIFO_DEPTH_16);
}
}
diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c
index 18d81f43f2a8..c65fb5f5d2dc 100644
--- a/drivers/net/phy/fixed_phy.c
+++ b/drivers/net/phy/fixed_phy.c
@@ -161,8 +161,8 @@ static int fixed_phy_add_gpiod(unsigned int irq, int phy_addr,
}
int fixed_phy_add(unsigned int irq, int phy_addr,
- struct fixed_phy_status *status) {
-
+ struct fixed_phy_status *status)
+{
return fixed_phy_add_gpiod(irq, phy_addr, status, NULL);
}
EXPORT_SYMBOL_GPL(fixed_phy_add);
diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c
index bde3356a2f86..e3bf827b7959 100644
--- a/drivers/net/phy/lxt.c
+++ b/drivers/net/phy/lxt.c
@@ -242,8 +242,8 @@ static int lxt973a2_read_status(struct phy_device *phydev)
return lpa;
/* If both registers are equal, it is suspect but not
- * impossible, hence a new try
- */
+ * impossible, hence a new try
+ */
} while (lpa == adv && retry--);
mii_lpa_to_linkmode_lpa_t(phydev->lp_advertising, lpa);
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index e6721c1c26c2..3de93c9f2744 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -367,39 +367,24 @@ static irqreturn_t marvell_handle_interrupt(struct phy_device *phydev)
static int marvell_set_polarity(struct phy_device *phydev, int polarity)
{
- int reg;
- int err;
- int val;
-
- /* get the current settings */
- reg = phy_read(phydev, MII_M1011_PHY_SCR);
- if (reg < 0)
- return reg;
+ u16 val;
- val = reg;
- val &= ~MII_M1011_PHY_SCR_AUTO_CROSS;
switch (polarity) {
case ETH_TP_MDI:
- val |= MII_M1011_PHY_SCR_MDI;
+ val = MII_M1011_PHY_SCR_MDI;
break;
case ETH_TP_MDI_X:
- val |= MII_M1011_PHY_SCR_MDI_X;
+ val = MII_M1011_PHY_SCR_MDI_X;
break;
case ETH_TP_MDI_AUTO:
case ETH_TP_MDI_INVALID:
default:
- val |= MII_M1011_PHY_SCR_AUTO_CROSS;
+ val = MII_M1011_PHY_SCR_AUTO_CROSS;
break;
}
- if (val != reg) {
- /* Set the new polarity value in the register */
- err = phy_write(phydev, MII_M1011_PHY_SCR, val);
- if (err)
- return err;
- }
-
- return val != reg;
+ return phy_modify_changed(phydev, MII_M1011_PHY_SCR,
+ MII_M1011_PHY_SCR_AUTO_CROSS, val);
}
static int marvell_config_aneg(struct phy_device *phydev)
@@ -824,14 +809,19 @@ static int m88e1111_config_init_rgmii_delays(struct phy_device *phydev)
{
int delay;
- if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_RGMII_ID:
delay = MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY;
- } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
delay = MII_M1111_RGMII_RX_DELAY;
- } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
delay = MII_M1111_RGMII_TX_DELAY;
- } else {
+ break;
+ default:
delay = 0;
+ break;
}
return phy_modify(phydev, MII_M1111_PHY_EXT_CR,
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index bbbc6ac8fa82..53a433442803 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -78,6 +78,11 @@ enum {
/* Temperature read register (88E2110 only) */
MV_PCS_TEMP = 0x8042,
+ /* Number of ports on the device */
+ MV_PCS_PORT_INFO = 0xd00d,
+ MV_PCS_PORT_INFO_NPORTS_MASK = 0x0380,
+ MV_PCS_PORT_INFO_NPORTS_SHIFT = 7,
+
/* These registers appear at 0x800X and 0xa00X - the 0xa00X control
* registers appear to set themselves to the 0x800X when AN is
* restarted, but status registers appear readable from either.
@@ -966,6 +971,30 @@ static const struct mv3310_chip mv2111_type = {
#endif
};
+static int mv3310_get_number_of_ports(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_PORT_INFO);
+ if (ret < 0)
+ return ret;
+
+ ret &= MV_PCS_PORT_INFO_NPORTS_MASK;
+ ret >>= MV_PCS_PORT_INFO_NPORTS_SHIFT;
+
+ return ret + 1;
+}
+
+static int mv3310_match_phy_device(struct phy_device *phydev)
+{
+ return mv3310_get_number_of_ports(phydev) == 1;
+}
+
+static int mv3340_match_phy_device(struct phy_device *phydev)
+{
+ return mv3310_get_number_of_ports(phydev) == 4;
+}
+
static int mv211x_match_phy_device(struct phy_device *phydev, bool has_5g)
{
int val;
@@ -994,7 +1023,8 @@ static int mv2111_match_phy_device(struct phy_device *phydev)
static struct phy_driver mv3310_drivers[] = {
{
.phy_id = MARVELL_PHY_ID_88X3310,
- .phy_id_mask = MARVELL_PHY_ID_88X33X0_MASK,
+ .phy_id_mask = MARVELL_PHY_ID_MASK,
+ .match_phy_device = mv3310_match_phy_device,
.name = "mv88x3310",
.driver_data = &mv3310_type,
.get_features = mv3310_get_features,
@@ -1011,8 +1041,9 @@ static struct phy_driver mv3310_drivers[] = {
.set_loopback = genphy_c45_loopback,
},
{
- .phy_id = MARVELL_PHY_ID_88X3340,
- .phy_id_mask = MARVELL_PHY_ID_88X33X0_MASK,
+ .phy_id = MARVELL_PHY_ID_88X3310,
+ .phy_id_mask = MARVELL_PHY_ID_MASK,
+ .match_phy_device = mv3340_match_phy_device,
.name = "mv88x3340",
.driver_data = &mv3340_type,
.get_features = mv3310_get_features,
@@ -1069,8 +1100,7 @@ static struct phy_driver mv3310_drivers[] = {
module_phy_driver(mv3310_drivers);
static struct mdio_device_id __maybe_unused mv3310_tbl[] = {
- { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_88X33X0_MASK },
- { MARVELL_PHY_ID_88X3340, MARVELL_PHY_ID_88X33X0_MASK },
+ { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E2110, MARVELL_PHY_ID_MASK },
{ },
};
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 6045ad3def12..53f034fc2ef7 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -175,6 +175,7 @@ EXPORT_SYMBOL(mdiobus_alloc_size);
static void mdiobus_release(struct device *d)
{
struct mii_bus *bus = to_mii_bus(d);
+
BUG_ON(bus->state != MDIOBUS_RELEASED &&
/* for compatibility with error handling in drivers */
bus->state != MDIOBUS_ALLOCATED);
@@ -458,8 +459,7 @@ static void of_mdiobus_link_mdiodev(struct mii_bus *bus,
continue;
if (addr == mdiodev->addr) {
- dev->of_node = child;
- dev->fwnode = of_fwnode_handle(child);
+ device_set_node(dev, of_fwnode_handle(child));
return;
}
}
diff --git a/drivers/net/phy/mdio_device.c b/drivers/net/phy/mdio_device.c
index 0837319a52d7..c94cb5382dc9 100644
--- a/drivers/net/phy/mdio_device.c
+++ b/drivers/net/phy/mdio_device.c
@@ -77,7 +77,7 @@ int mdio_device_register(struct mdio_device *mdiodev)
{
int err;
- dev_dbg(&mdiodev->dev, "mdio_device_register\n");
+ dev_dbg(&mdiodev->dev, "%s\n", __func__);
err = mdiobus_register_device(mdiodev);
if (err)
@@ -188,7 +188,7 @@ int mdio_driver_register(struct mdio_driver *drv)
struct mdio_driver_common *mdiodrv = &drv->mdiodrv;
int retval;
- pr_debug("mdio_driver_register: %s\n", mdiodrv->driver.name);
+ pr_debug("%s: %s\n", __func__, mdiodrv->driver.name);
mdiodrv->driver.bus = &mdio_bus_type;
mdiodrv->driver.probe = mdio_probe;
diff --git a/drivers/net/phy/mediatek-ge.c b/drivers/net/phy/mediatek-ge.c
new file mode 100644
index 000000000000..11ff335d6228
--- /dev/null
+++ b/drivers/net/phy/mediatek-ge.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+
+#define MTK_EXT_PAGE_ACCESS 0x1f
+#define MTK_PHY_PAGE_STANDARD 0x0000
+#define MTK_PHY_PAGE_EXTENDED 0x0001
+#define MTK_PHY_PAGE_EXTENDED_2 0x0002
+#define MTK_PHY_PAGE_EXTENDED_3 0x0003
+#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
+#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
+
+static int mtk_gephy_read_page(struct phy_device *phydev)
+{
+ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+}
+
+static int mtk_gephy_write_page(struct phy_device *phydev, int page)
+{
+ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+}
+
+static void mtk_gephy_config_init(struct phy_device *phydev)
+{
+ /* Disable EEE */
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
+
+ /* Enable HW auto downshift */
+ phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
+
+ /* Increase SlvDPSready time */
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+ __phy_write(phydev, 0x10, 0xafae);
+ __phy_write(phydev, 0x12, 0x2f);
+ __phy_write(phydev, 0x10, 0x8fae);
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+ /* Adjust 100_mse_threshold */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
+
+ /* Disable mcc */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
+}
+
+static int mt7530_phy_config_init(struct phy_device *phydev)
+{
+ mtk_gephy_config_init(phydev);
+
+ /* Increase post_update_timer */
+ phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
+
+ return 0;
+}
+
+static int mt7531_phy_config_init(struct phy_device *phydev)
+{
+ if (phydev->interface != PHY_INTERFACE_MODE_INTERNAL)
+ return -EINVAL;
+
+ mtk_gephy_config_init(phydev);
+
+ /* PHY link down power saving enable */
+ phy_set_bits(phydev, 0x17, BIT(4));
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
+
+ /* Set TX Pair delay selection */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
+
+ return 0;
+}
+
+static struct phy_driver mtk_gephy_driver[] = {
+ {
+ PHY_ID_MATCH_EXACT(0x03a29412),
+ .name = "MediaTek MT7530 PHY",
+ .config_init = mt7530_phy_config_init,
+ /* Interrupts are handled by the switch, not the PHY
+ * itself.
+ */
+ .config_intr = genphy_no_config_intr,
+ .handle_interrupt = genphy_handle_interrupt_no_ack,
+ .read_page = mtk_gephy_read_page,
+ .write_page = mtk_gephy_write_page,
+ },
+ {
+ PHY_ID_MATCH_EXACT(0x03a29441),
+ .name = "MediaTek MT7531 PHY",
+ .config_init = mt7531_phy_config_init,
+ /* Interrupts are handled by the switch, not the PHY
+ * itself.
+ */
+ .config_intr = genphy_no_config_intr,
+ .handle_interrupt = genphy_handle_interrupt_no_ack,
+ .read_page = mtk_gephy_read_page,
+ .write_page = mtk_gephy_write_page,
+ },
+};
+
+module_phy_driver(mtk_gephy_driver);
+
+static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
+ { PHY_ID_MATCH_VENDOR(0x03a29400) },
+ { }
+};
+
+MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
+MODULE_AUTHOR("DENG, Qingfang <dqfext@gmail.com>");
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl);
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index a14a00328fa3..4d53886f7d51 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -20,6 +20,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/ethtool_netlink.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/phy.h>
@@ -38,42 +39,60 @@
/* general Interrupt control/status reg in vendor specific block. */
#define MII_KSZPHY_INTCS 0x1B
-#define KSZPHY_INTCS_JABBER BIT(15)
-#define KSZPHY_INTCS_RECEIVE_ERR BIT(14)
-#define KSZPHY_INTCS_PAGE_RECEIVE BIT(13)
-#define KSZPHY_INTCS_PARELLEL BIT(12)
-#define KSZPHY_INTCS_LINK_PARTNER_ACK BIT(11)
-#define KSZPHY_INTCS_LINK_DOWN BIT(10)
-#define KSZPHY_INTCS_REMOTE_FAULT BIT(9)
-#define KSZPHY_INTCS_LINK_UP BIT(8)
-#define KSZPHY_INTCS_ALL (KSZPHY_INTCS_LINK_UP |\
+#define KSZPHY_INTCS_JABBER BIT(15)
+#define KSZPHY_INTCS_RECEIVE_ERR BIT(14)
+#define KSZPHY_INTCS_PAGE_RECEIVE BIT(13)
+#define KSZPHY_INTCS_PARELLEL BIT(12)
+#define KSZPHY_INTCS_LINK_PARTNER_ACK BIT(11)
+#define KSZPHY_INTCS_LINK_DOWN BIT(10)
+#define KSZPHY_INTCS_REMOTE_FAULT BIT(9)
+#define KSZPHY_INTCS_LINK_UP BIT(8)
+#define KSZPHY_INTCS_ALL (KSZPHY_INTCS_LINK_UP |\
KSZPHY_INTCS_LINK_DOWN)
-#define KSZPHY_INTCS_LINK_DOWN_STATUS BIT(2)
-#define KSZPHY_INTCS_LINK_UP_STATUS BIT(0)
-#define KSZPHY_INTCS_STATUS (KSZPHY_INTCS_LINK_DOWN_STATUS |\
+#define KSZPHY_INTCS_LINK_DOWN_STATUS BIT(2)
+#define KSZPHY_INTCS_LINK_UP_STATUS BIT(0)
+#define KSZPHY_INTCS_STATUS (KSZPHY_INTCS_LINK_DOWN_STATUS |\
KSZPHY_INTCS_LINK_UP_STATUS)
+/* LinkMD Control/Status */
+#define KSZ8081_LMD 0x1d
+#define KSZ8081_LMD_ENABLE_TEST BIT(15)
+#define KSZ8081_LMD_STAT_NORMAL 0
+#define KSZ8081_LMD_STAT_OPEN 1
+#define KSZ8081_LMD_STAT_SHORT 2
+#define KSZ8081_LMD_STAT_FAIL 3
+#define KSZ8081_LMD_STAT_MASK GENMASK(14, 13)
+/* Short cable (<10 meter) has been detected by LinkMD */
+#define KSZ8081_LMD_SHORT_INDICATOR BIT(12)
+#define KSZ8081_LMD_DELTA_TIME_MASK GENMASK(8, 0)
+
/* PHY Control 1 */
-#define MII_KSZPHY_CTRL_1 0x1e
+#define MII_KSZPHY_CTRL_1 0x1e
+#define KSZ8081_CTRL1_MDIX_STAT BIT(4)
/* PHY Control 2 / PHY Control (if no PHY Control 1) */
-#define MII_KSZPHY_CTRL_2 0x1f
-#define MII_KSZPHY_CTRL MII_KSZPHY_CTRL_2
+#define MII_KSZPHY_CTRL_2 0x1f
+#define MII_KSZPHY_CTRL MII_KSZPHY_CTRL_2
/* bitmap of PHY register to set interrupt mode */
+#define KSZ8081_CTRL2_HP_MDIX BIT(15)
+#define KSZ8081_CTRL2_MDI_MDI_X_SELECT BIT(14)
+#define KSZ8081_CTRL2_DISABLE_AUTO_MDIX BIT(13)
+#define KSZ8081_CTRL2_FORCE_LINK BIT(11)
+#define KSZ8081_CTRL2_POWER_SAVING BIT(10)
#define KSZPHY_CTRL_INT_ACTIVE_HIGH BIT(9)
#define KSZPHY_RMII_REF_CLK_SEL BIT(7)
/* Write/read to/from extended registers */
-#define MII_KSZPHY_EXTREG 0x0b
-#define KSZPHY_EXTREG_WRITE 0x8000
+#define MII_KSZPHY_EXTREG 0x0b
+#define KSZPHY_EXTREG_WRITE 0x8000
-#define MII_KSZPHY_EXTREG_WRITE 0x0c
-#define MII_KSZPHY_EXTREG_READ 0x0d
+#define MII_KSZPHY_EXTREG_WRITE 0x0c
+#define MII_KSZPHY_EXTREG_READ 0x0d
/* Extended registers */
-#define MII_KSZPHY_CLK_CONTROL_PAD_SKEW 0x104
-#define MII_KSZPHY_RX_DATA_PAD_SKEW 0x105
-#define MII_KSZPHY_TX_DATA_PAD_SKEW 0x106
+#define MII_KSZPHY_CLK_CONTROL_PAD_SKEW 0x104
+#define MII_KSZPHY_RX_DATA_PAD_SKEW 0x105
+#define MII_KSZPHY_TX_DATA_PAD_SKEW 0x106
#define PS_TO_REG 200
@@ -422,6 +441,87 @@ static int ksz8081_config_init(struct phy_device *phydev)
return kszphy_config_init(phydev);
}
+static int ksz8081_config_mdix(struct phy_device *phydev, u8 ctrl)
+{
+ u16 val;
+
+ switch (ctrl) {
+ case ETH_TP_MDI:
+ val = KSZ8081_CTRL2_DISABLE_AUTO_MDIX;
+ break;
+ case ETH_TP_MDI_X:
+ val = KSZ8081_CTRL2_DISABLE_AUTO_MDIX |
+ KSZ8081_CTRL2_MDI_MDI_X_SELECT;
+ break;
+ case ETH_TP_MDI_AUTO:
+ val = 0;
+ break;
+ default:
+ return 0;
+ }
+
+ return phy_modify(phydev, MII_KSZPHY_CTRL_2,
+ KSZ8081_CTRL2_HP_MDIX |
+ KSZ8081_CTRL2_MDI_MDI_X_SELECT |
+ KSZ8081_CTRL2_DISABLE_AUTO_MDIX,
+ KSZ8081_CTRL2_HP_MDIX | val);
+}
+
+static int ksz8081_config_aneg(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = genphy_config_aneg(phydev);
+ if (ret)
+ return ret;
+
+ /* The MDI-X configuration is automatically changed by the PHY after
+ * switching from autoneg off to on. So, take MDI-X configuration under
+ * own control and set it after autoneg configuration was done.
+ */
+ return ksz8081_config_mdix(phydev, phydev->mdix_ctrl);
+}
+
+static int ksz8081_mdix_update(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_read(phydev, MII_KSZPHY_CTRL_2);
+ if (ret < 0)
+ return ret;
+
+ if (ret & KSZ8081_CTRL2_DISABLE_AUTO_MDIX) {
+ if (ret & KSZ8081_CTRL2_MDI_MDI_X_SELECT)
+ phydev->mdix_ctrl = ETH_TP_MDI_X;
+ else
+ phydev->mdix_ctrl = ETH_TP_MDI;
+ } else {
+ phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
+ }
+
+ ret = phy_read(phydev, MII_KSZPHY_CTRL_1);
+ if (ret < 0)
+ return ret;
+
+ if (ret & KSZ8081_CTRL1_MDIX_STAT)
+ phydev->mdix = ETH_TP_MDI;
+ else
+ phydev->mdix = ETH_TP_MDI_X;
+
+ return 0;
+}
+
+static int ksz8081_read_status(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = ksz8081_mdix_update(phydev);
+ if (ret < 0)
+ return ret;
+
+ return genphy_read_status(phydev);
+}
+
static int ksz8061_config_init(struct phy_device *phydev)
{
int ret;
@@ -488,8 +588,7 @@ static int ksz9021_load_values_from_of(struct phy_device *phydev,
static int ksz9021_config_init(struct phy_device *phydev)
{
- const struct device *dev = &phydev->mdio.dev;
- const struct device_node *of_node = dev->of_node;
+ const struct device_node *of_node;
const struct device *dev_walker;
/* The Micrel driver has a deprecated option to place phy OF
@@ -711,8 +810,7 @@ static int ksz9031_config_rgmii_delay(struct phy_device *phydev)
static int ksz9031_config_init(struct phy_device *phydev)
{
- const struct device *dev = &phydev->mdio.dev;
- const struct device_node *of_node = dev->of_node;
+ const struct device_node *of_node;
static const char *clk_skews[2] = {"rxc-skew-ps", "txc-skew-ps"};
static const char *rx_data_skews[4] = {
"rxd0-skew-ps", "rxd1-skew-ps",
@@ -907,8 +1005,7 @@ static int ksz9131_config_rgmii_delay(struct phy_device *phydev)
static int ksz9131_config_init(struct phy_device *phydev)
{
- const struct device *dev = &phydev->mdio.dev;
- struct device_node *of_node = dev->of_node;
+ struct device_node *of_node;
char *clk_skews[2] = {"rxc-skew-psec", "txc-skew-psec"};
char *rx_data_skews[4] = {
"rxd0-skew-psec", "rxd1-skew-psec",
@@ -1048,6 +1145,92 @@ static int ksz8873mll_config_aneg(struct phy_device *phydev)
return 0;
}
+static int ksz886x_config_mdix(struct phy_device *phydev, u8 ctrl)
+{
+ u16 val;
+
+ switch (ctrl) {
+ case ETH_TP_MDI:
+ val = KSZ886X_BMCR_DISABLE_AUTO_MDIX;
+ break;
+ case ETH_TP_MDI_X:
+ /* Note: The naming of the bit KSZ886X_BMCR_FORCE_MDI is bit
+ * counter intuitive, the "-X" in "1 = Force MDI" in the data
+ * sheet seems to be missing:
+ * 1 = Force MDI (sic!) (transmit on RX+/RX- pins)
+ * 0 = Normal operation (transmit on TX+/TX- pins)
+ */
+ val = KSZ886X_BMCR_DISABLE_AUTO_MDIX | KSZ886X_BMCR_FORCE_MDI;
+ break;
+ case ETH_TP_MDI_AUTO:
+ val = 0;
+ break;
+ default:
+ return 0;
+ }
+
+ return phy_modify(phydev, MII_BMCR,
+ KSZ886X_BMCR_HP_MDIX | KSZ886X_BMCR_FORCE_MDI |
+ KSZ886X_BMCR_DISABLE_AUTO_MDIX,
+ KSZ886X_BMCR_HP_MDIX | val);
+}
+
+static int ksz886x_config_aneg(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = genphy_config_aneg(phydev);
+ if (ret)
+ return ret;
+
+ /* The MDI-X configuration is automatically changed by the PHY after
+ * switching from autoneg off to on. So, take MDI-X configuration under
+ * own control and set it after autoneg configuration was done.
+ */
+ return ksz886x_config_mdix(phydev, phydev->mdix_ctrl);
+}
+
+static int ksz886x_mdix_update(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_read(phydev, MII_BMCR);
+ if (ret < 0)
+ return ret;
+
+ if (ret & KSZ886X_BMCR_DISABLE_AUTO_MDIX) {
+ if (ret & KSZ886X_BMCR_FORCE_MDI)
+ phydev->mdix_ctrl = ETH_TP_MDI_X;
+ else
+ phydev->mdix_ctrl = ETH_TP_MDI;
+ } else {
+ phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
+ }
+
+ ret = phy_read(phydev, MII_KSZPHY_CTRL);
+ if (ret < 0)
+ return ret;
+
+ /* Same reverse logic as KSZ886X_BMCR_FORCE_MDI */
+ if (ret & KSZ886X_CTRL_MDIX_STAT)
+ phydev->mdix = ETH_TP_MDI_X;
+ else
+ phydev->mdix = ETH_TP_MDI;
+
+ return 0;
+}
+
+static int ksz886x_read_status(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = ksz886x_mdix_update(phydev);
+ if (ret < 0)
+ return ret;
+
+ return genphy_read_status(phydev);
+}
+
static int kszphy_get_sset_count(struct phy_device *phydev)
{
return ARRAY_SIZE(kszphy_hw_stats);
@@ -1193,6 +1376,167 @@ static int kszphy_probe(struct phy_device *phydev)
return 0;
}
+static int ksz886x_cable_test_start(struct phy_device *phydev)
+{
+ if (phydev->dev_flags & MICREL_KSZ8_P1_ERRATA)
+ return -EOPNOTSUPP;
+
+ /* If autoneg is enabled, we won't be able to test cross pair
+ * short. In this case, the PHY will "detect" a link and
+ * confuse the internal state machine - disable auto neg here.
+ * If autoneg is disabled, we should set the speed to 10mbit.
+ */
+ return phy_clear_bits(phydev, MII_BMCR, BMCR_ANENABLE | BMCR_SPEED100);
+}
+
+static int ksz886x_cable_test_result_trans(u16 status)
+{
+ switch (FIELD_GET(KSZ8081_LMD_STAT_MASK, status)) {
+ case KSZ8081_LMD_STAT_NORMAL:
+ return ETHTOOL_A_CABLE_RESULT_CODE_OK;
+ case KSZ8081_LMD_STAT_SHORT:
+ return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
+ case KSZ8081_LMD_STAT_OPEN:
+ return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
+ case KSZ8081_LMD_STAT_FAIL:
+ fallthrough;
+ default:
+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
+ }
+}
+
+static bool ksz886x_cable_test_failed(u16 status)
+{
+ return FIELD_GET(KSZ8081_LMD_STAT_MASK, status) ==
+ KSZ8081_LMD_STAT_FAIL;
+}
+
+static bool ksz886x_cable_test_fault_length_valid(u16 status)
+{
+ switch (FIELD_GET(KSZ8081_LMD_STAT_MASK, status)) {
+ case KSZ8081_LMD_STAT_OPEN:
+ fallthrough;
+ case KSZ8081_LMD_STAT_SHORT:
+ return true;
+ }
+ return false;
+}
+
+static int ksz886x_cable_test_fault_length(u16 status)
+{
+ int dt;
+
+ /* According to the data sheet the distance to the fault is
+ * DELTA_TIME * 0.4 meters.
+ */
+ dt = FIELD_GET(KSZ8081_LMD_DELTA_TIME_MASK, status);
+
+ return (dt * 400) / 10;
+}
+
+static int ksz886x_cable_test_wait_for_completion(struct phy_device *phydev)
+{
+ int val, ret;
+
+ ret = phy_read_poll_timeout(phydev, KSZ8081_LMD, val,
+ !(val & KSZ8081_LMD_ENABLE_TEST),
+ 30000, 100000, true);
+
+ return ret < 0 ? ret : 0;
+}
+
+static int ksz886x_cable_test_one_pair(struct phy_device *phydev, int pair)
+{
+ static const int ethtool_pair[] = {
+ ETHTOOL_A_CABLE_PAIR_A,
+ ETHTOOL_A_CABLE_PAIR_B,
+ };
+ int ret, val, mdix;
+
+ /* There is no way to choice the pair, like we do one ksz9031.
+ * We can workaround this limitation by using the MDI-X functionality.
+ */
+ if (pair == 0)
+ mdix = ETH_TP_MDI;
+ else
+ mdix = ETH_TP_MDI_X;
+
+ switch (phydev->phy_id & MICREL_PHY_ID_MASK) {
+ case PHY_ID_KSZ8081:
+ ret = ksz8081_config_mdix(phydev, mdix);
+ break;
+ case PHY_ID_KSZ886X:
+ ret = ksz886x_config_mdix(phydev, mdix);
+ break;
+ default:
+ ret = -ENODEV;
+ }
+
+ if (ret)
+ return ret;
+
+ /* Now we are ready to fire. This command will send a 100ns pulse
+ * to the pair.
+ */
+ ret = phy_write(phydev, KSZ8081_LMD, KSZ8081_LMD_ENABLE_TEST);
+ if (ret)
+ return ret;
+
+ ret = ksz886x_cable_test_wait_for_completion(phydev);
+ if (ret)
+ return ret;
+
+ val = phy_read(phydev, KSZ8081_LMD);
+ if (val < 0)
+ return val;
+
+ if (ksz886x_cable_test_failed(val))
+ return -EAGAIN;
+
+ ret = ethnl_cable_test_result(phydev, ethtool_pair[pair],
+ ksz886x_cable_test_result_trans(val));
+ if (ret)
+ return ret;
+
+ if (!ksz886x_cable_test_fault_length_valid(val))
+ return 0;
+
+ return ethnl_cable_test_fault_length(phydev, ethtool_pair[pair],
+ ksz886x_cable_test_fault_length(val));
+}
+
+static int ksz886x_cable_test_get_status(struct phy_device *phydev,
+ bool *finished)
+{
+ unsigned long pair_mask = 0x3;
+ int retries = 20;
+ int pair, ret;
+
+ *finished = false;
+
+ /* Try harder if link partner is active */
+ while (pair_mask && retries--) {
+ for_each_set_bit(pair, &pair_mask, 4) {
+ ret = ksz886x_cable_test_one_pair(phydev, pair);
+ if (ret == -EAGAIN)
+ continue;
+ if (ret < 0)
+ return ret;
+ clear_bit(pair, &pair_mask);
+ }
+ /* If link partner is in autonegotiation mode it will send 2ms
+ * of FLPs with at least 6ms of silence.
+ * Add 2ms sleep to have better chances to hit this silence.
+ */
+ if (pair_mask)
+ msleep(2);
+ }
+
+ *finished = true;
+
+ return ret;
+}
+
static struct phy_driver ksphy_driver[] = {
{
.phy_id = PHY_ID_KS8737,
@@ -1299,11 +1643,14 @@ static struct phy_driver ksphy_driver[] = {
.phy_id = PHY_ID_KSZ8081,
.name = "Micrel KSZ8081 or KSZ8091",
.phy_id_mask = MICREL_PHY_ID_MASK,
+ .flags = PHY_POLL_CABLE_TEST,
/* PHY_BASIC_FEATURES */
.driver_data = &ksz8081_type,
.probe = kszphy_probe,
.config_init = ksz8081_config_init,
.soft_reset = genphy_soft_reset,
+ .config_aneg = ksz8081_config_aneg,
+ .read_status = ksz8081_read_status,
.config_intr = kszphy_config_intr,
.handle_interrupt = kszphy_handle_interrupt,
.get_sset_count = kszphy_get_sset_count,
@@ -1311,6 +1658,8 @@ static struct phy_driver ksphy_driver[] = {
.get_stats = kszphy_get_stats,
.suspend = kszphy_suspend,
.resume = kszphy_resume,
+ .cable_test_start = ksz886x_cable_test_start,
+ .cable_test_get_status = ksz886x_cable_test_get_status,
}, {
.phy_id = PHY_ID_KSZ8061,
.name = "Micrel KSZ8061",
@@ -1399,9 +1748,14 @@ static struct phy_driver ksphy_driver[] = {
.phy_id_mask = MICREL_PHY_ID_MASK,
.name = "Micrel KSZ8851 Ethernet MAC or KSZ886X Switch",
/* PHY_BASIC_FEATURES */
+ .flags = PHY_POLL_CABLE_TEST,
.config_init = kszphy_config_init,
+ .config_aneg = ksz886x_config_aneg,
+ .read_status = ksz886x_read_status,
.suspend = genphy_suspend,
.resume = genphy_resume,
+ .cable_test_start = ksz886x_cable_test_start,
+ .cable_test_get_status = ksz886x_cable_test_get_status,
}, {
.name = "Micrel KSZ87XX Switch",
/* PHY_BASIC_FEATURES */
diff --git a/drivers/net/phy/mii_timestamper.c b/drivers/net/phy/mii_timestamper.c
index b71b7456462d..51ae0593a04f 100644
--- a/drivers/net/phy/mii_timestamper.c
+++ b/drivers/net/phy/mii_timestamper.c
@@ -111,6 +111,9 @@ void unregister_mii_timestamper(struct mii_timestamper *mii_ts)
struct mii_timestamping_desc *desc;
struct list_head *this;
+ if (!mii_ts)
+ return;
+
/* mii_timestamper statically registered by the PHY driver won't use the
* register_mii_timestamper() and thus don't have ->device set. Don't
* try to unregister these.
diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c
new file mode 100644
index 000000000000..7e6ac2c5e27e
--- /dev/null
+++ b/drivers/net/phy/motorcomm.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Motorcomm PHYs
+ *
+ * Author: Peter Geis <pgwipeout@gmail.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+
+#define PHY_ID_YT8511 0x0000010a
+
+#define YT8511_PAGE_SELECT 0x1e
+#define YT8511_PAGE 0x1f
+#define YT8511_EXT_CLK_GATE 0x0c
+#define YT8511_EXT_DELAY_DRIVE 0x0d
+#define YT8511_EXT_SLEEP_CTRL 0x27
+
+/* 2b00 25m from pll
+ * 2b01 25m from xtl *default*
+ * 2b10 62.m from pll
+ * 2b11 125m from pll
+ */
+#define YT8511_CLK_125M (BIT(2) | BIT(1))
+#define YT8511_PLLON_SLP BIT(14)
+
+/* RX Delay enabled = 1.8ns 1000T, 8ns 10/100T */
+#define YT8511_DELAY_RX BIT(0)
+
+/* TX Gig-E Delay is bits 7:4, default 0x5
+ * TX Fast-E Delay is bits 15:12, default 0xf
+ * Delay = 150ps * N - 250ps
+ * On = 2000ps, off = 50ps
+ */
+#define YT8511_DELAY_GE_TX_EN (0xf << 4)
+#define YT8511_DELAY_GE_TX_DIS (0x2 << 4)
+#define YT8511_DELAY_FE_TX_EN (0xf << 12)
+#define YT8511_DELAY_FE_TX_DIS (0x2 << 12)
+
+static int yt8511_read_page(struct phy_device *phydev)
+{
+ return __phy_read(phydev, YT8511_PAGE_SELECT);
+};
+
+static int yt8511_write_page(struct phy_device *phydev, int page)
+{
+ return __phy_write(phydev, YT8511_PAGE_SELECT, page);
+};
+
+static int yt8511_config_init(struct phy_device *phydev)
+{
+ int oldpage, ret = 0;
+ unsigned int ge, fe;
+
+ oldpage = phy_select_page(phydev, YT8511_EXT_CLK_GATE);
+ if (oldpage < 0)
+ goto err_restore_page;
+
+ /* set rgmii delay mode */
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ ge = YT8511_DELAY_GE_TX_DIS;
+ fe = YT8511_DELAY_FE_TX_DIS;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ ge = YT8511_DELAY_RX | YT8511_DELAY_GE_TX_DIS;
+ fe = YT8511_DELAY_FE_TX_DIS;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ ge = YT8511_DELAY_GE_TX_EN;
+ fe = YT8511_DELAY_FE_TX_EN;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ ge = YT8511_DELAY_RX | YT8511_DELAY_GE_TX_EN;
+ fe = YT8511_DELAY_FE_TX_EN;
+ break;
+ default: /* do not support other modes */
+ ret = -EOPNOTSUPP;
+ goto err_restore_page;
+ }
+
+ ret = __phy_modify(phydev, YT8511_PAGE, (YT8511_DELAY_RX | YT8511_DELAY_GE_TX_EN), ge);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* set clock mode to 125mhz */
+ ret = __phy_modify(phydev, YT8511_PAGE, 0, YT8511_CLK_125M);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* fast ethernet delay is in a separate page */
+ ret = __phy_write(phydev, YT8511_PAGE_SELECT, YT8511_EXT_DELAY_DRIVE);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = __phy_modify(phydev, YT8511_PAGE, YT8511_DELAY_FE_TX_EN, fe);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* leave pll enabled in sleep */
+ ret = __phy_write(phydev, YT8511_PAGE_SELECT, YT8511_EXT_SLEEP_CTRL);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = __phy_modify(phydev, YT8511_PAGE, 0, YT8511_PLLON_SLP);
+ if (ret < 0)
+ goto err_restore_page;
+
+err_restore_page:
+ return phy_restore_page(phydev, oldpage, ret);
+}
+
+static struct phy_driver motorcomm_phy_drvs[] = {
+ {
+ PHY_ID_MATCH_EXACT(PHY_ID_YT8511),
+ .name = "YT8511 Gigabit Ethernet",
+ .config_init = yt8511_config_init,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .read_page = yt8511_read_page,
+ .write_page = yt8511_write_page,
+ },
+};
+
+module_phy_driver(motorcomm_phy_drvs);
+
+MODULE_DESCRIPTION("Motorcomm PHY driver");
+MODULE_AUTHOR("Peter Geis");
+MODULE_LICENSE("GPL");
+
+static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {
+ { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) },
+ { /* sentinal */ }
+};
+
+MODULE_DEVICE_TABLE(mdio, motorcomm_tbl);
diff --git a/drivers/net/phy/mscc/mscc_macsec.c b/drivers/net/phy/mscc/mscc_macsec.c
index 10be266e48e8..b7b2521c73fb 100644
--- a/drivers/net/phy/mscc/mscc_macsec.c
+++ b/drivers/net/phy/mscc/mscc_macsec.c
@@ -501,7 +501,7 @@ static u32 vsc8584_macsec_flow_context_id(struct macsec_flow *flow)
}
/* Derive the AES key to get a key for the hash autentication */
-static int vsc8584_macsec_derive_key(const u8 key[MACSEC_KEYID_LEN],
+static int vsc8584_macsec_derive_key(const u8 key[MACSEC_MAX_KEY_LEN],
u16 key_len, u8 hkey[16])
{
const u8 input[AES_BLOCK_SIZE] = {0};
diff --git a/drivers/net/phy/mscc/mscc_macsec.h b/drivers/net/phy/mscc/mscc_macsec.h
index 9c6d25e36de2..453304bae778 100644
--- a/drivers/net/phy/mscc/mscc_macsec.h
+++ b/drivers/net/phy/mscc/mscc_macsec.h
@@ -81,7 +81,7 @@ struct macsec_flow {
/* Highest takes precedence [0..15] */
u8 priority;
- u8 key[MACSEC_KEYID_LEN];
+ u8 key[MACSEC_MAX_KEY_LEN];
union {
struct macsec_rx_sa *rx_sa;
diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c
index 46160baaafe3..9ae9cc6b23c2 100644
--- a/drivers/net/phy/national.c
+++ b/drivers/net/phy/national.c
@@ -68,7 +68,8 @@ static int ns_ack_interrupt(struct phy_device *phydev)
return ret;
/* Clear the interrupt status bit by writing a “1”
- * to the corresponding bit in INT_CLEAR (2:0 are reserved) */
+ * to the corresponding bit in INT_CLEAR (2:0 are reserved)
+ */
ret = phy_write(phydev, DP83865_INT_CLEAR, ret & ~0x7);
return ret;
@@ -150,7 +151,8 @@ static int ns_config_init(struct phy_device *phydev)
{
ns_giga_speed_fallback(phydev, ALL_FALLBACK_ON);
/* In the latest MAC or switches design, the 10 Mbps loopback
- is desired to be turned off. */
+ * is desired to be turned off.
+ */
ns_10_base_t_hdx_loopack(phydev, hdx_loopback_off);
return ns_ack_interrupt(phydev);
}
diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c
index 26b9c0d7cb9d..91a327f67a42 100644
--- a/drivers/net/phy/nxp-c45-tja11xx.c
+++ b/drivers/net/phy/nxp-c45-tja11xx.c
@@ -13,6 +13,9 @@
#include <linux/phy.h>
#include <linux/processor.h>
#include <linux/property.h>
+#include <linux/ptp_classify.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/net_tstamp.h>
#define PHY_ID_TJA_1103 0x001BB010
@@ -57,6 +60,9 @@
#define VEND1_PORT_CONTROL 0x8040
#define PORT_CONTROL_EN BIT(14)
+#define VEND1_PORT_ABILITIES 0x8046
+#define PTP_ABILITY BIT(3)
+
#define VEND1_PORT_INFRA_CONTROL 0xAC00
#define PORT_INFRA_CONTROL_EN BIT(14)
@@ -91,13 +97,106 @@
#define VEND1_TX_IPG_LENGTH 0xAFD1
#define COUNTER_EN BIT(15)
+#define VEND1_LTC_LOAD_CTRL 0x1105
+#define READ_LTC BIT(2)
+#define LOAD_LTC BIT(0)
+
+#define VEND1_LTC_WR_NSEC_0 0x1106
+#define VEND1_LTC_WR_NSEC_1 0x1107
+#define VEND1_LTC_WR_SEC_0 0x1108
+#define VEND1_LTC_WR_SEC_1 0x1109
+
+#define VEND1_LTC_RD_NSEC_0 0x110A
+#define VEND1_LTC_RD_NSEC_1 0x110B
+#define VEND1_LTC_RD_SEC_0 0x110C
+#define VEND1_LTC_RD_SEC_1 0x110D
+
+#define VEND1_RATE_ADJ_SUBNS_0 0x110F
+#define VEND1_RATE_ADJ_SUBNS_1 0x1110
+#define CLK_RATE_ADJ_LD BIT(15)
+#define CLK_RATE_ADJ_DIR BIT(14)
+
+#define VEND1_HW_LTC_LOCK_CTRL 0x1115
+#define HW_LTC_LOCK_EN BIT(0)
+
+#define VEND1_PTP_IRQ_EN 0x1131
+#define VEND1_PTP_IRQ_STATUS 0x1132
+#define PTP_IRQ_EGR_TS BIT(0)
+
+#define VEND1_RX_TS_INSRT_CTRL 0x114D
+#define RX_TS_INSRT_MODE2 0x02
+
+#define VEND1_EGR_RING_DATA_0 0x114E
+#define VEND1_EGR_RING_DATA_1_SEQ_ID 0x114F
+#define VEND1_EGR_RING_DATA_2_NSEC_15_0 0x1150
+#define VEND1_EGR_RING_DATA_3 0x1151
+#define VEND1_EGR_RING_CTRL 0x1154
+
+#define RING_DATA_0_DOMAIN_NUMBER GENMASK(7, 0)
+#define RING_DATA_0_MSG_TYPE GENMASK(11, 8)
+#define RING_DATA_0_SEC_4_2 GENMASK(14, 2)
+#define RING_DATA_0_TS_VALID BIT(15)
+
+#define RING_DATA_3_NSEC_29_16 GENMASK(13, 0)
+#define RING_DATA_3_SEC_1_0 GENMASK(15, 14)
+#define RING_DATA_5_SEC_16_5 GENMASK(15, 4)
+#define RING_DONE BIT(0)
+
+#define TS_SEC_MASK GENMASK(1, 0)
+
+#define VEND1_PORT_FUNC_ENABLES 0x8048
+#define PTP_ENABLE BIT(3)
+
+#define VEND1_PORT_PTP_CONTROL 0x9000
+#define PORT_PTP_CONTROL_BYPASS BIT(11)
+
+#define VEND1_PTP_CLK_PERIOD 0x1104
+#define PTP_CLK_PERIOD_100BT1 15ULL
+
+#define VEND1_EVENT_MSG_FILT 0x1148
+#define EVENT_MSG_FILT_ALL 0x0F
+#define EVENT_MSG_FILT_NONE 0x00
+
+#define VEND1_TX_PIPE_DLY_NS 0x1149
+#define VEND1_TX_PIPEDLY_SUBNS 0x114A
+#define VEND1_RX_PIPE_DLY_NS 0x114B
+#define VEND1_RX_PIPEDLY_SUBNS 0x114C
+
#define RGMII_PERIOD_PS 8000U
#define PS_PER_DEGREE div_u64(RGMII_PERIOD_PS, 360)
#define MIN_ID_PS 1644U
#define MAX_ID_PS 2260U
#define DEFAULT_ID_PS 2000U
+#define PPM_TO_SUBNS_INC(ppb) div_u64(GENMASK(31, 0) * (ppb) * \
+ PTP_CLK_PERIOD_100BT1, NSEC_PER_SEC)
+
+#define NXP_C45_SKB_CB(skb) ((struct nxp_c45_skb_cb *)(skb)->cb)
+
+struct nxp_c45_skb_cb {
+ struct ptp_header *header;
+ unsigned int type;
+};
+
+struct nxp_c45_hwts {
+ u32 nsec;
+ u32 sec;
+ u8 domain_number;
+ u16 sequence_id;
+ u8 msg_type;
+};
+
struct nxp_c45_phy {
+ struct phy_device *phydev;
+ struct mii_timestamper mii_ts;
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info caps;
+ struct sk_buff_head tx_queue;
+ struct sk_buff_head rx_queue;
+ /* used to access the PTP registers atomic */
+ struct mutex ptp_lock;
+ int hwts_tx;
+ int hwts_rx;
u32 tx_delay;
u32 rx_delay;
};
@@ -110,6 +209,382 @@ struct nxp_c45_phy_stats {
u16 mask;
};
+static bool nxp_c45_poll_txts(struct phy_device *phydev)
+{
+ return phydev->irq <= 0;
+}
+
+static int _nxp_c45_ptp_gettimex64(struct ptp_clock_info *ptp,
+ struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_LOAD_CTRL,
+ READ_LTC);
+ ts->tv_nsec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
+ VEND1_LTC_RD_NSEC_0);
+ ts->tv_nsec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
+ VEND1_LTC_RD_NSEC_1) << 16;
+ ts->tv_sec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
+ VEND1_LTC_RD_SEC_0);
+ ts->tv_sec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
+ VEND1_LTC_RD_SEC_1) << 16;
+
+ return 0;
+}
+
+static int nxp_c45_ptp_gettimex64(struct ptp_clock_info *ptp,
+ struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+
+ mutex_lock(&priv->ptp_lock);
+ _nxp_c45_ptp_gettimex64(ptp, ts, sts);
+ mutex_unlock(&priv->ptp_lock);
+
+ return 0;
+}
+
+static int _nxp_c45_ptp_settime64(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_NSEC_0,
+ ts->tv_nsec);
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_NSEC_1,
+ ts->tv_nsec >> 16);
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_SEC_0,
+ ts->tv_sec);
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_SEC_1,
+ ts->tv_sec >> 16);
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_LOAD_CTRL,
+ LOAD_LTC);
+
+ return 0;
+}
+
+static int nxp_c45_ptp_settime64(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+
+ mutex_lock(&priv->ptp_lock);
+ _nxp_c45_ptp_settime64(ptp, ts);
+ mutex_unlock(&priv->ptp_lock);
+
+ return 0;
+}
+
+static int nxp_c45_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
+{
+ struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+ s32 ppb = scaled_ppm_to_ppb(scaled_ppm);
+ u64 subns_inc_val;
+ bool inc;
+
+ mutex_lock(&priv->ptp_lock);
+ inc = ppb >= 0;
+ ppb = abs(ppb);
+
+ subns_inc_val = PPM_TO_SUBNS_INC(ppb);
+
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_RATE_ADJ_SUBNS_0,
+ subns_inc_val);
+ subns_inc_val >>= 16;
+ subns_inc_val |= CLK_RATE_ADJ_LD;
+ if (inc)
+ subns_inc_val |= CLK_RATE_ADJ_DIR;
+
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_RATE_ADJ_SUBNS_1,
+ subns_inc_val);
+ mutex_unlock(&priv->ptp_lock);
+
+ return 0;
+}
+
+static int nxp_c45_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+ struct timespec64 now, then;
+
+ mutex_lock(&priv->ptp_lock);
+ then = ns_to_timespec64(delta);
+ _nxp_c45_ptp_gettimex64(ptp, &now, NULL);
+ now = timespec64_add(now, then);
+ _nxp_c45_ptp_settime64(ptp, &now);
+ mutex_unlock(&priv->ptp_lock);
+
+ return 0;
+}
+
+static void nxp_c45_reconstruct_ts(struct timespec64 *ts,
+ struct nxp_c45_hwts *hwts)
+{
+ ts->tv_nsec = hwts->nsec;
+ if ((ts->tv_sec & TS_SEC_MASK) < (hwts->sec & TS_SEC_MASK))
+ ts->tv_sec -= TS_SEC_MASK + 1;
+ ts->tv_sec &= ~TS_SEC_MASK;
+ ts->tv_sec |= hwts->sec & TS_SEC_MASK;
+}
+
+static bool nxp_c45_match_ts(struct ptp_header *header,
+ struct nxp_c45_hwts *hwts,
+ unsigned int type)
+{
+ return ntohs(header->sequence_id) == hwts->sequence_id &&
+ ptp_get_msgtype(header, type) == hwts->msg_type &&
+ header->domain_number == hwts->domain_number;
+}
+
+static bool nxp_c45_get_hwtxts(struct nxp_c45_phy *priv,
+ struct nxp_c45_hwts *hwts)
+{
+ bool valid;
+ u16 reg;
+
+ mutex_lock(&priv->ptp_lock);
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EGR_RING_CTRL,
+ RING_DONE);
+ reg = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EGR_RING_DATA_0);
+ valid = !!(reg & RING_DATA_0_TS_VALID);
+ if (!valid)
+ goto nxp_c45_get_hwtxts_out;
+
+ hwts->domain_number = reg;
+ hwts->msg_type = (reg & RING_DATA_0_MSG_TYPE) >> 8;
+ hwts->sec = (reg & RING_DATA_0_SEC_4_2) >> 10;
+ hwts->sequence_id = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
+ VEND1_EGR_RING_DATA_1_SEQ_ID);
+ hwts->nsec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
+ VEND1_EGR_RING_DATA_2_NSEC_15_0);
+ reg = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EGR_RING_DATA_3);
+ hwts->nsec |= (reg & RING_DATA_3_NSEC_29_16) << 16;
+ hwts->sec |= (reg & RING_DATA_3_SEC_1_0) >> 14;
+
+nxp_c45_get_hwtxts_out:
+ mutex_unlock(&priv->ptp_lock);
+ return valid;
+}
+
+static void nxp_c45_process_txts(struct nxp_c45_phy *priv,
+ struct nxp_c45_hwts *txts)
+{
+ struct sk_buff *skb, *tmp, *skb_match = NULL;
+ struct skb_shared_hwtstamps shhwtstamps;
+ struct timespec64 ts;
+ unsigned long flags;
+ bool ts_match;
+ s64 ts_ns;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ skb_queue_walk_safe(&priv->tx_queue, skb, tmp) {
+ ts_match = nxp_c45_match_ts(NXP_C45_SKB_CB(skb)->header, txts,
+ NXP_C45_SKB_CB(skb)->type);
+ if (!ts_match)
+ continue;
+ skb_match = skb;
+ __skb_unlink(skb, &priv->tx_queue);
+ break;
+ }
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+
+ if (skb_match) {
+ nxp_c45_ptp_gettimex64(&priv->caps, &ts, NULL);
+ nxp_c45_reconstruct_ts(&ts, txts);
+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+ ts_ns = timespec64_to_ns(&ts);
+ shhwtstamps.hwtstamp = ns_to_ktime(ts_ns);
+ skb_complete_tx_timestamp(skb_match, &shhwtstamps);
+ } else {
+ phydev_warn(priv->phydev,
+ "the tx timestamp doesn't match with any skb\n");
+ }
+}
+
+static long nxp_c45_do_aux_work(struct ptp_clock_info *ptp)
+{
+ struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+ bool poll_txts = nxp_c45_poll_txts(priv->phydev);
+ struct skb_shared_hwtstamps *shhwtstamps_rx;
+ struct nxp_c45_hwts hwts;
+ bool reschedule = false;
+ struct timespec64 ts;
+ struct sk_buff *skb;
+ bool txts_valid;
+ u32 ts_raw;
+
+ while (!skb_queue_empty_lockless(&priv->tx_queue) && poll_txts) {
+ txts_valid = nxp_c45_get_hwtxts(priv, &hwts);
+ if (unlikely(!txts_valid)) {
+ /* Still more skbs in the queue */
+ reschedule = true;
+ break;
+ }
+
+ nxp_c45_process_txts(priv, &hwts);
+ }
+
+ while ((skb = skb_dequeue(&priv->rx_queue)) != NULL) {
+ nxp_c45_ptp_gettimex64(&priv->caps, &ts, NULL);
+ ts_raw = __be32_to_cpu(NXP_C45_SKB_CB(skb)->header->reserved2);
+ hwts.sec = ts_raw >> 30;
+ hwts.nsec = ts_raw & GENMASK(29, 0);
+ nxp_c45_reconstruct_ts(&ts, &hwts);
+ shhwtstamps_rx = skb_hwtstamps(skb);
+ shhwtstamps_rx->hwtstamp = ns_to_ktime(timespec64_to_ns(&ts));
+ NXP_C45_SKB_CB(skb)->header->reserved2 = 0;
+ netif_rx_ni(skb);
+ }
+
+ return reschedule ? 1 : -1;
+}
+
+static int nxp_c45_init_ptp_clock(struct nxp_c45_phy *priv)
+{
+ priv->caps = (struct ptp_clock_info) {
+ .owner = THIS_MODULE,
+ .name = "NXP C45 PHC",
+ .max_adj = 16666666,
+ .adjfine = nxp_c45_ptp_adjfine,
+ .adjtime = nxp_c45_ptp_adjtime,
+ .gettimex64 = nxp_c45_ptp_gettimex64,
+ .settime64 = nxp_c45_ptp_settime64,
+ .do_aux_work = nxp_c45_do_aux_work,
+ };
+
+ priv->ptp_clock = ptp_clock_register(&priv->caps,
+ &priv->phydev->mdio.dev);
+
+ if (IS_ERR(priv->ptp_clock))
+ return PTR_ERR(priv->ptp_clock);
+
+ if (!priv->ptp_clock)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void nxp_c45_txtstamp(struct mii_timestamper *mii_ts,
+ struct sk_buff *skb, int type)
+{
+ struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy,
+ mii_ts);
+
+ switch (priv->hwts_tx) {
+ case HWTSTAMP_TX_ON:
+ NXP_C45_SKB_CB(skb)->type = type;
+ NXP_C45_SKB_CB(skb)->header = ptp_parse_header(skb, type);
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ skb_queue_tail(&priv->tx_queue, skb);
+ if (nxp_c45_poll_txts(priv->phydev))
+ ptp_schedule_worker(priv->ptp_clock, 0);
+ break;
+ case HWTSTAMP_TX_OFF:
+ default:
+ kfree_skb(skb);
+ break;
+ }
+}
+
+static bool nxp_c45_rxtstamp(struct mii_timestamper *mii_ts,
+ struct sk_buff *skb, int type)
+{
+ struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy,
+ mii_ts);
+ struct ptp_header *header = ptp_parse_header(skb, type);
+
+ if (!header)
+ return false;
+
+ if (!priv->hwts_rx)
+ return false;
+
+ NXP_C45_SKB_CB(skb)->header = header;
+ skb_queue_tail(&priv->rx_queue, skb);
+ ptp_schedule_worker(priv->ptp_clock, 0);
+
+ return true;
+}
+
+static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts,
+ struct ifreq *ifreq)
+{
+ struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy,
+ mii_ts);
+ struct phy_device *phydev = priv->phydev;
+ struct hwtstamp_config cfg;
+
+ if (copy_from_user(&cfg, ifreq->ifr_data, sizeof(cfg)))
+ return -EFAULT;
+
+ if (cfg.tx_type < 0 || cfg.tx_type > HWTSTAMP_TX_ON)
+ return -ERANGE;
+
+ priv->hwts_tx = cfg.tx_type;
+
+ switch (cfg.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ priv->hwts_rx = 0;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ priv->hwts_rx = 1;
+ cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ if (priv->hwts_rx || priv->hwts_tx) {
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_EVENT_MSG_FILT,
+ EVENT_MSG_FILT_ALL);
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PORT_PTP_CONTROL,
+ PORT_PTP_CONTROL_BYPASS);
+ } else {
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_EVENT_MSG_FILT,
+ EVENT_MSG_FILT_NONE);
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_PTP_CONTROL,
+ PORT_PTP_CONTROL_BYPASS);
+ }
+
+ if (nxp_c45_poll_txts(priv->phydev))
+ goto nxp_c45_no_ptp_irq;
+
+ if (priv->hwts_tx)
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PTP_IRQ_EN, PTP_IRQ_EGR_TS);
+ else
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PTP_IRQ_EN, PTP_IRQ_EGR_TS);
+
+nxp_c45_no_ptp_irq:
+ return copy_to_user(ifreq->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+}
+
+static int nxp_c45_ts_info(struct mii_timestamper *mii_ts,
+ struct ethtool_ts_info *ts_info)
+{
+ struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy,
+ mii_ts);
+
+ ts_info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+ ts_info->phc_index = ptp_clock_index(priv->ptp_clock);
+ ts_info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
+ ts_info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT);
+
+ return 0;
+}
+
static const struct nxp_c45_phy_stats nxp_c45_hw_stats[] = {
{ "phy_symbol_error_cnt", MDIO_MMD_VEND1,
VEND1_SYMBOL_ERROR_COUNTER, 0, GENMASK(15, 0) },
@@ -205,7 +680,9 @@ static int nxp_c45_config_intr(struct phy_device *phydev)
static irqreturn_t nxp_c45_handle_interrupt(struct phy_device *phydev)
{
+ struct nxp_c45_phy *priv = phydev->priv;
irqreturn_t ret = IRQ_NONE;
+ struct nxp_c45_hwts hwts;
int irq;
irq = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_IRQ_STATUS);
@@ -216,6 +693,18 @@ static irqreturn_t nxp_c45_handle_interrupt(struct phy_device *phydev)
ret = IRQ_HANDLED;
}
+ /* There is no need for ACK.
+ * The irq signal will be asserted until the EGR TS FIFO will be
+ * emptied.
+ */
+ irq = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_IRQ_STATUS);
+ if (irq & PTP_IRQ_EGR_TS) {
+ while (nxp_c45_get_hwtxts(priv, &hwts))
+ nxp_c45_process_txts(priv, &hwts);
+
+ ret = IRQ_HANDLED;
+ }
+
return ret;
}
@@ -546,6 +1035,12 @@ static int nxp_c45_config_init(struct phy_device *phydev)
return ret;
}
+ /* Bug workaround for SJA1110 rev B: enable write access
+ * to MDIO_MMD_PMAPMD
+ */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F8, 1);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01F9, 2);
+
phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONFIG,
PHY_CONFIG_AUTO);
@@ -566,20 +1061,60 @@ static int nxp_c45_config_init(struct phy_device *phydev)
phydev->autoneg = AUTONEG_DISABLE;
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK_PERIOD,
+ PTP_CLK_PERIOD_100BT1);
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_HW_LTC_LOCK_CTRL,
+ HW_LTC_LOCK_EN);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_TS_INSRT_CTRL,
+ RX_TS_INSRT_MODE2);
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_FUNC_ENABLES,
+ PTP_ENABLE);
+
return nxp_c45_start_op(phydev);
}
static int nxp_c45_probe(struct phy_device *phydev)
{
struct nxp_c45_phy *priv;
+ int ptp_ability;
+ int ret = 0;
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ skb_queue_head_init(&priv->tx_queue);
+ skb_queue_head_init(&priv->rx_queue);
+
+ priv->phydev = phydev;
+
phydev->priv = priv;
- return 0;
+ mutex_init(&priv->ptp_lock);
+
+ ptp_ability = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PORT_ABILITIES);
+ ptp_ability = !!(ptp_ability & PTP_ABILITY);
+ if (!ptp_ability) {
+ phydev_dbg(phydev, "the phy does not support PTP");
+ goto no_ptp_support;
+ }
+
+ if (IS_ENABLED(CONFIG_PTP_1588_CLOCK) &&
+ IS_ENABLED(CONFIG_NETWORK_PHY_TIMESTAMPING)) {
+ priv->mii_ts.rxtstamp = nxp_c45_rxtstamp;
+ priv->mii_ts.txtstamp = nxp_c45_txtstamp;
+ priv->mii_ts.hwtstamp = nxp_c45_hwtstamp;
+ priv->mii_ts.ts_info = nxp_c45_ts_info;
+ phydev->mii_ts = &priv->mii_ts;
+ ret = nxp_c45_init_ptp_clock(priv);
+ } else {
+ phydev_dbg(phydev, "PTP support not enabled even if the phy supports it");
+ }
+
+no_ptp_support:
+
+ return ret;
}
static struct phy_driver nxp_c45_driver[] = {
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index f4816b7d31b3..c617dbcad6ea 100644
--- a/drivers/net/phy/phy-c45.c
+++ b/drivers/net/phy/phy-c45.c
@@ -172,7 +172,7 @@ EXPORT_SYMBOL_GPL(genphy_c45_an_config_aneg);
* @phydev: target phy_device struct
*
* Disable auto-negotiation in the Clause 45 PHY. The link parameters
- * parameters are controlled through the PMA/PMD MMD registers.
+ * are controlled through the PMA/PMD MMD registers.
*
* Returns zero on success, negative errno code on failure.
*/
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index 8d333d3084ed..2870c33b8975 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -76,7 +76,8 @@ EXPORT_SYMBOL_GPL(phy_duplex_to_str);
/* A mapping of all SUPPORTED settings to speed/duplex. This table
* must be grouped by speed and sorted in descending match priority
- * - iow, descending speed. */
+ * - iow, descending speed.
+ */
#define PHY_SETTING(s, d, b) { .speed = SPEED_ ## s, .duplex = DUPLEX_ ## d, \
.bit = ETHTOOL_LINK_MODE_ ## b ## _BIT}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 1f0512e39c65..8eeb26d8aeb7 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -380,8 +380,7 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
else if (val & BMCR_SPEED100)
phydev->speed = SPEED_100;
else phydev->speed = SPEED_10;
- }
- else {
+ } else {
if (phydev->autoneg == AUTONEG_DISABLE)
change_autoneg = true;
phydev->autoneg = AUTONEG_ENABLE;
@@ -1136,6 +1135,9 @@ void phy_state_machine(struct work_struct *work)
else if (do_suspend)
phy_suspend(phydev);
+ if (err == -ENODEV)
+ return;
+
if (err < 0)
phy_error(phydev);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 0a2d8bedf73d..5d5f9a9ee768 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -9,6 +9,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/acpi.h>
#include <linux/bitmap.h>
#include <linux/delay.h>
#include <linux/errno.h>
@@ -833,6 +834,27 @@ static int get_phy_c22_id(struct mii_bus *bus, int addr, u32 *phy_id)
return 0;
}
+/* Extract the phy ID from the compatible string of the form
+ * ethernet-phy-idAAAA.BBBB.
+ */
+int fwnode_get_phy_id(struct fwnode_handle *fwnode, u32 *phy_id)
+{
+ unsigned int upper, lower;
+ const char *cp;
+ int ret;
+
+ ret = fwnode_property_read_string(fwnode, "compatible", &cp);
+ if (ret)
+ return ret;
+
+ if (sscanf(cp, "ethernet-phy-id%4x.%4x", &upper, &lower) != 2)
+ return -EINVAL;
+
+ *phy_id = ((upper & GENMASK(15, 0)) << 16) | (lower & GENMASK(15, 0));
+ return 0;
+}
+EXPORT_SYMBOL(fwnode_get_phy_id);
+
/**
* get_phy_device - reads the specified PHY device and returns its @phy_device
* struct
@@ -870,6 +892,18 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
if (r)
return ERR_PTR(r);
+ /* PHY device such as the Marvell Alaska 88E2110 will return a PHY ID
+ * of 0 when probed using get_phy_c22_id() with no error. Proceed to
+ * probe with C45 to see if we're able to get a valid PHY ID in the C45
+ * space, if successful, create the C45 PHY device.
+ */
+ if (!is_c45 && phy_id == 0 && bus->probe_capabilities >= MDIOBUS_C45) {
+ r = get_phy_c45_ids(bus, addr, &c45_ids);
+ if (!r)
+ return phy_device_create(bus, addr, phy_id,
+ true, &c45_ids);
+ }
+
return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids);
}
EXPORT_SYMBOL(get_phy_device);
@@ -923,8 +957,7 @@ EXPORT_SYMBOL(phy_device_register);
*/
void phy_device_remove(struct phy_device *phydev)
{
- if (phydev->mii_ts)
- unregister_mii_timestamper(phydev->mii_ts);
+ unregister_mii_timestamper(phydev->mii_ts);
device_del(&phydev->mdio.dev);
@@ -2864,6 +2897,90 @@ static bool phy_drv_supports_irq(struct phy_driver *phydrv)
}
/**
+ * fwnode_mdio_find_device - Given a fwnode, find the mdio_device
+ * @fwnode: pointer to the mdio_device's fwnode
+ *
+ * If successful, returns a pointer to the mdio_device with the embedded
+ * struct device refcount incremented by one, or NULL on failure.
+ * The caller should call put_device() on the mdio_device after its use.
+ */
+struct mdio_device *fwnode_mdio_find_device(struct fwnode_handle *fwnode)
+{
+ struct device *d;
+
+ if (!fwnode)
+ return NULL;
+
+ d = bus_find_device_by_fwnode(&mdio_bus_type, fwnode);
+ if (!d)
+ return NULL;
+
+ return to_mdio_device(d);
+}
+EXPORT_SYMBOL(fwnode_mdio_find_device);
+
+/**
+ * fwnode_phy_find_device - For provided phy_fwnode, find phy_device.
+ *
+ * @phy_fwnode: Pointer to the phy's fwnode.
+ *
+ * If successful, returns a pointer to the phy_device with the embedded
+ * struct device refcount incremented by one, or NULL on failure.
+ */
+struct phy_device *fwnode_phy_find_device(struct fwnode_handle *phy_fwnode)
+{
+ struct mdio_device *mdiodev;
+
+ mdiodev = fwnode_mdio_find_device(phy_fwnode);
+ if (!mdiodev)
+ return NULL;
+
+ if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY)
+ return to_phy_device(&mdiodev->dev);
+
+ put_device(&mdiodev->dev);
+
+ return NULL;
+}
+EXPORT_SYMBOL(fwnode_phy_find_device);
+
+/**
+ * device_phy_find_device - For the given device, get the phy_device
+ * @dev: Pointer to the given device
+ *
+ * Refer return conditions of fwnode_phy_find_device().
+ */
+struct phy_device *device_phy_find_device(struct device *dev)
+{
+ return fwnode_phy_find_device(dev_fwnode(dev));
+}
+EXPORT_SYMBOL_GPL(device_phy_find_device);
+
+/**
+ * fwnode_get_phy_node - Get the phy_node using the named reference.
+ * @fwnode: Pointer to fwnode from which phy_node has to be obtained.
+ *
+ * Refer return conditions of fwnode_find_reference().
+ * For ACPI, only "phy-handle" is supported. Legacy DT properties "phy"
+ * and "phy-device" are not supported in ACPI. DT supports all the three
+ * named references to the phy node.
+ */
+struct fwnode_handle *fwnode_get_phy_node(struct fwnode_handle *fwnode)
+{
+ struct fwnode_handle *phy_node;
+
+ /* Only phy-handle is used for ACPI */
+ phy_node = fwnode_find_reference(fwnode, "phy-handle", 0);
+ if (is_acpi_node(fwnode) || !IS_ERR(phy_node))
+ return phy_node;
+ phy_node = fwnode_find_reference(fwnode, "phy", 0);
+ if (IS_ERR(phy_node))
+ phy_node = fwnode_find_reference(fwnode, "phy-device", 0);
+ return phy_node;
+}
+EXPORT_SYMBOL_GPL(fwnode_get_phy_node);
+
+/**
* phy_probe - probe and init a PHY device
* @dev: device to probe and init
*
@@ -2883,7 +3000,7 @@ static int phy_probe(struct device *dev)
/* Disable the interrupt if the PHY doesn't support it
* but the interrupt is still a valid one
*/
- if (!phy_drv_supports_irq(phydrv) && phy_interrupt_is_valid(phydev))
+ if (!phy_drv_supports_irq(phydrv) && phy_interrupt_is_valid(phydev))
phydev->irq = PHY_POLL;
if (phydrv->flags & PHY_IS_INTERNAL)
@@ -2904,15 +3021,14 @@ static int phy_probe(struct device *dev)
* a controller will attach, and may modify one
* or both of these values
*/
- if (phydrv->features) {
+ if (phydrv->features)
linkmode_copy(phydev->supported, phydrv->features);
- } else if (phydrv->get_features) {
+ else if (phydrv->get_features)
err = phydrv->get_features(phydev);
- } else if (phydev->is_c45) {
+ else if (phydev->is_c45)
err = genphy_c45_pma_read_abilities(phydev);
- } else {
+ else
err = genphy_read_abilities(phydev);
- }
if (err)
goto out;
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 96d8e88b4e46..eb29ef53d971 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -5,6 +5,7 @@
*
* Copyright (C) 2015 Russell King
*/
+#include <linux/acpi.h>
#include <linux/ethtool.h>
#include <linux/export.h>
#include <linux/gpio/consumer.h>
@@ -181,7 +182,8 @@ static int phylink_parse_fixedlink(struct phylink *pl,
pl->link_config.duplex = DUPLEX_FULL;
/* We treat the "pause" and "asym-pause" terminology as
- * defining the link partner's ability. */
+ * defining the link partner's ability.
+ */
if (fwnode_property_read_bool(fixed_node, "pause"))
__set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
pl->link_config.lp_advertising);
@@ -311,6 +313,11 @@ static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode)
phylink_set(pl->supported, 5000baseT_Full);
break;
+ case PHY_INTERFACE_MODE_25GBASER:
+ phylink_set(pl->supported, 25000baseCR_Full);
+ phylink_set(pl->supported, 25000baseKR_Full);
+ phylink_set(pl->supported, 25000baseSR_Full);
+ fallthrough;
case PHY_INTERFACE_MODE_USXGMII:
case PHY_INTERFACE_MODE_10GKR:
case PHY_INTERFACE_MODE_10GBASER:
@@ -679,7 +686,8 @@ static void phylink_resolve(struct work_struct *w)
phylink_mac_pcs_get_state(pl, &link_state);
/* If we have a phy, the "up" state is the union of
- * both the PHY and the MAC */
+ * both the PHY and the MAC
+ */
if (pl->phydev)
link_state.link &= pl->phy_state.link;
@@ -688,7 +696,8 @@ static void phylink_resolve(struct work_struct *w)
link_state.interface = pl->phy_state.interface;
/* If we have a PHY, we need to update with
- * the PHY flow control bits. */
+ * the PHY flow control bits.
+ */
link_state.pause = pl->phy_state.pause;
mac_config = true;
}
@@ -1084,7 +1093,26 @@ EXPORT_SYMBOL_GPL(phylink_connect_phy);
int phylink_of_phy_connect(struct phylink *pl, struct device_node *dn,
u32 flags)
{
- struct device_node *phy_node;
+ return phylink_fwnode_phy_connect(pl, of_fwnode_handle(dn), flags);
+}
+EXPORT_SYMBOL_GPL(phylink_of_phy_connect);
+
+/**
+ * phylink_fwnode_phy_connect() - connect the PHY specified in the fwnode.
+ * @pl: a pointer to a &struct phylink returned from phylink_create()
+ * @fwnode: a pointer to a &struct fwnode_handle.
+ * @flags: PHY-specific flags to communicate to the PHY device driver
+ *
+ * Connect the phy specified @fwnode to the phylink instance specified
+ * by @pl.
+ *
+ * Returns 0 on success or a negative errno.
+ */
+int phylink_fwnode_phy_connect(struct phylink *pl,
+ struct fwnode_handle *fwnode,
+ u32 flags)
+{
+ struct fwnode_handle *phy_fwnode;
struct phy_device *phy_dev;
int ret;
@@ -1094,28 +1122,25 @@ int phylink_of_phy_connect(struct phylink *pl, struct device_node *dn,
phy_interface_mode_is_8023z(pl->link_interface)))
return 0;
- phy_node = of_parse_phandle(dn, "phy-handle", 0);
- if (!phy_node)
- phy_node = of_parse_phandle(dn, "phy", 0);
- if (!phy_node)
- phy_node = of_parse_phandle(dn, "phy-device", 0);
-
- if (!phy_node) {
+ phy_fwnode = fwnode_get_phy_node(fwnode);
+ if (IS_ERR(phy_fwnode)) {
if (pl->cfg_link_an_mode == MLO_AN_PHY)
return -ENODEV;
return 0;
}
- phy_dev = of_phy_find_device(phy_node);
+ phy_dev = fwnode_phy_find_device(phy_fwnode);
/* We're done with the phy_node handle */
- of_node_put(phy_node);
+ fwnode_handle_put(phy_fwnode);
if (!phy_dev)
return -ENODEV;
ret = phy_attach_direct(pl->netdev, phy_dev, flags,
pl->link_interface);
- if (ret)
+ if (ret) {
+ phy_device_free(phy_dev);
return ret;
+ }
ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface);
if (ret)
@@ -1123,7 +1148,7 @@ int phylink_of_phy_connect(struct phylink *pl, struct device_node *dn,
return ret;
}
-EXPORT_SYMBOL_GPL(phylink_of_phy_connect);
+EXPORT_SYMBOL_GPL(phylink_fwnode_phy_connect);
/**
* phylink_disconnect_phy() - disconnect any PHY attached to the phylink
@@ -1358,11 +1383,10 @@ int phylink_ethtool_ksettings_get(struct phylink *pl,
ASSERT_RTNL();
- if (pl->phydev) {
+ if (pl->phydev)
phy_ethtool_ksettings_get(pl->phydev, kset);
- } else {
+ else
kset->base.port = pl->link_port;
- }
linkmode_copy(kset->link_modes.supported, pl->supported);
diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c
index d5c1aaa8236a..30d15f7c9b03 100644
--- a/drivers/net/phy/qsemi.c
+++ b/drivers/net/phy/qsemi.c
@@ -100,6 +100,7 @@ static int qs6612_ack_interrupt(struct phy_device *phydev)
static int qs6612_config_intr(struct phy_device *phydev)
{
int err;
+
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
/* clear any interrupts before enabling them */
err = qs6612_ack_interrupt(phydev);
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 821e85a97367..11be60333fa8 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -8,6 +8,7 @@
* Copyright (c) 2004 Freescale Semiconductor, Inc.
*/
#include <linux/bitops.h>
+#include <linux/of.h>
#include <linux/phy.h>
#include <linux/module.h>
#include <linux/delay.h>
@@ -27,6 +28,7 @@
#define RTL821x_PAGE_SELECT 0x1f
#define RTL8211F_PHYCR1 0x18
+#define RTL8211F_PHYCR2 0x19
#define RTL8211F_INSR 0x1d
#define RTL8211F_TX_DELAY BIT(8)
@@ -40,6 +42,8 @@
#define RTL8211E_TX_DELAY BIT(12)
#define RTL8211E_RX_DELAY BIT(11)
+#define RTL8211F_CLKOUT_EN BIT(0)
+
#define RTL8201F_ISR 0x1e
#define RTL8201F_ISR_ANERR BIT(15)
#define RTL8201F_ISR_DUPLEX BIT(13)
@@ -71,6 +75,11 @@ MODULE_DESCRIPTION("Realtek PHY driver");
MODULE_AUTHOR("Johnson Leung");
MODULE_LICENSE("GPL");
+struct rtl821x_priv {
+ u16 phycr1;
+ u16 phycr2;
+};
+
static int rtl821x_read_page(struct phy_device *phydev)
{
return __phy_read(phydev, RTL821x_PAGE_SELECT);
@@ -81,6 +90,37 @@ static int rtl821x_write_page(struct phy_device *phydev, int page)
return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
}
+static int rtl821x_probe(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct rtl821x_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1);
+ if (ret < 0)
+ return ret;
+
+ priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF);
+ if (of_property_read_bool(dev->of_node, "realtek,aldps-enable"))
+ priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF;
+
+ ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2);
+ if (ret < 0)
+ return ret;
+
+ priv->phycr2 = ret & RTL8211F_CLKOUT_EN;
+ if (of_property_read_bool(dev->of_node, "realtek,clkout-disable"))
+ priv->phycr2 &= ~RTL8211F_CLKOUT_EN;
+
+ phydev->priv = priv;
+
+ return 0;
+}
+
static int rtl8201_ack_interrupt(struct phy_device *phydev)
{
int err;
@@ -291,13 +331,19 @@ static int rtl8211c_config_init(struct phy_device *phydev)
static int rtl8211f_config_init(struct phy_device *phydev)
{
+ struct rtl821x_priv *priv = phydev->priv;
struct device *dev = &phydev->mdio.dev;
u16 val_txdly, val_rxdly;
- u16 val;
int ret;
- val = RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_XTAL_OFF;
- phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1, val, val);
+ ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1,
+ RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF,
+ priv->phycr1);
+ if (ret < 0) {
+ dev_err(dev, "aldps mode configuration failed: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
switch (phydev->interface) {
case PHY_INTERFACE_MODE_RGMII:
@@ -354,6 +400,27 @@ static int rtl8211f_config_init(struct phy_device *phydev)
val_rxdly ? "enabled" : "disabled");
}
+ ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2,
+ RTL8211F_CLKOUT_EN, priv->phycr2);
+ if (ret < 0) {
+ dev_err(dev, "clkout configuration failed: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
+ return genphy_soft_reset(phydev);
+}
+
+static int rtl821x_resume(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = genphy_resume(phydev);
+ if (ret < 0)
+ return ret;
+
+ msleep(20);
+
return 0;
}
@@ -847,12 +914,13 @@ static struct phy_driver realtek_drvs[] = {
}, {
PHY_ID_MATCH_EXACT(0x001cc916),
.name = "RTL8211F Gigabit Ethernet",
+ .probe = rtl821x_probe,
.config_init = &rtl8211f_config_init,
.read_status = rtlgen_read_status,
.config_intr = &rtl8211f_config_intr,
.handle_interrupt = rtl8211f_handle_interrupt,
.suspend = genphy_suspend,
- .resume = genphy_resume,
+ .resume = rtl821x_resume,
.read_page = rtl821x_read_page,
.write_page = rtl821x_write_page,
}, {
diff --git a/drivers/net/phy/rockchip.c b/drivers/net/phy/rockchip.c
index 52f1f65320fe..bb13e75183ee 100644
--- a/drivers/net/phy/rockchip.c
+++ b/drivers/net/phy/rockchip.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
-/**
+/*
* drivers/net/phy/rockchip.c
*
* Driver for ROCKCHIP Ethernet PHYs
diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
index e61de66e973b..7362f8c3271c 100644
--- a/drivers/net/phy/sfp-bus.c
+++ b/drivers/net/phy/sfp-bus.c
@@ -392,6 +392,11 @@ EXPORT_SYMBOL_GPL(sfp_parse_support);
phy_interface_t sfp_select_interface(struct sfp_bus *bus,
unsigned long *link_modes)
{
+ if (phylink_test(link_modes, 25000baseCR_Full) ||
+ phylink_test(link_modes, 25000baseKR_Full) ||
+ phylink_test(link_modes, 25000baseSR_Full))
+ return PHY_INTERFACE_MODE_25GBASER;
+
if (phylink_test(link_modes, 10000baseCR_Full) ||
phylink_test(link_modes, 10000baseSR_Full) ||
phylink_test(link_modes, 10000baseLR_Full) ||
@@ -624,14 +629,14 @@ static void sfp_upstream_clear(struct sfp_bus *bus)
* be put via sfp_bus_put() when done.
*
* Returns:
- * - on success, a pointer to the sfp_bus structure,
- * - %NULL if no SFP is specified,
- * - on failure, an error pointer value:
+ * - on success, a pointer to the sfp_bus structure,
+ * - %NULL if no SFP is specified,
+ * - on failure, an error pointer value:
*
- * - corresponding to the errors detailed for
- * fwnode_property_get_reference_args().
- * - %-ENOMEM if we failed to allocate the bus.
- * - an error from the upstream's connect_phy() method.
+ * - corresponding to the errors detailed for
+ * fwnode_property_get_reference_args().
+ * - %-ENOMEM if we failed to allocate the bus.
+ * - an error from the upstream's connect_phy() method.
*/
struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode)
{
@@ -666,14 +671,14 @@ EXPORT_SYMBOL_GPL(sfp_bus_find_fwnode);
* bus, so it is safe to put the bus after this call.
*
* Returns:
- * - on success, a pointer to the sfp_bus structure,
- * - %NULL if no SFP is specified,
- * - on failure, an error pointer value:
+ * - on success, a pointer to the sfp_bus structure,
+ * - %NULL if no SFP is specified,
+ * - on failure, an error pointer value:
*
- * - corresponding to the errors detailed for
- * fwnode_property_get_reference_args().
- * - %-ENOMEM if we failed to allocate the bus.
- * - an error from the upstream's connect_phy() method.
+ * - corresponding to the errors detailed for
+ * fwnode_property_get_reference_args().
+ * - %-ENOMEM if we failed to allocate the bus.
+ * - an error from the upstream's connect_phy() method.
*/
int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
const struct sfp_upstream_ops *ops)
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index 37f722c763d7..34e90216bd2c 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -2153,7 +2153,7 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
case SFP_S_INIT:
if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) {
- /* TX_FAULT is still asserted after t_init or
+ /* TX_FAULT is still asserted after t_init
* or t_start_up, so assume there is a fault.
*/
sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT,
diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c
index ca49c1ad3efc..8b5445a724ce 100644
--- a/drivers/net/phy/spi_ks8995.c
+++ b/drivers/net/phy/spi_ks8995.c
@@ -160,11 +160,11 @@ static const struct spi_device_id ks8995_id[] = {
MODULE_DEVICE_TABLE(spi, ks8995_id);
static const struct of_device_id ks8895_spi_of_match[] = {
- { .compatible = "micrel,ks8995" },
- { .compatible = "micrel,ksz8864" },
- { .compatible = "micrel,ksz8795" },
- { },
- };
+ { .compatible = "micrel,ks8995" },
+ { .compatible = "micrel,ksz8864" },
+ { .compatible = "micrel,ksz8795" },
+ { },
+};
MODULE_DEVICE_TABLE(of, ks8895_spi_of_match);
static inline u8 get_chip_id(u8 val)
diff --git a/drivers/net/phy/ste10Xp.c b/drivers/net/phy/ste10Xp.c
index 431fe5e0ce31..309e4c3496c4 100644
--- a/drivers/net/phy/ste10Xp.c
+++ b/drivers/net/phy/ste10Xp.c
@@ -20,12 +20,12 @@
#include <linux/mii.h>
#include <linux/phy.h>
-#define MII_XCIIS 0x11 /* Configuration Info IRQ & Status Reg */
-#define MII_XIE 0x12 /* Interrupt Enable Register */
+#define MII_XCIIS 0x11 /* Configuration Info IRQ & Status Reg */
+#define MII_XIE 0x12 /* Interrupt Enable Register */
#define MII_XIE_DEFAULT_MASK 0x0070 /* ANE complete, Remote Fault, Link Down */
#define STE101P_PHY_ID 0x00061c50
-#define STE100P_PHY_ID 0x1c040011
+#define STE100P_PHY_ID 0x1c040011
static int ste10Xp_config_init(struct phy_device *phydev)
{
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index 16704e243162..897b979ec03c 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -249,7 +249,8 @@ static int vsc73xx_config_aneg(struct phy_device *phydev)
/* This adds a skew for both TX and RX clocks, so the skew should only be
* applied to "rgmii-id" interfaces. It may not work as expected
- * on "rgmii-txid", "rgmii-rxid" or "rgmii" interfaces. */
+ * on "rgmii-txid", "rgmii-rxid" or "rgmii" interfaces.
+ */
static int vsc8601_add_skew(struct phy_device *phydev)
{
int ret;
diff --git a/drivers/net/ppp/bsd_comp.c b/drivers/net/ppp/bsd_comp.c
index 61fedb23d3cf..db0dc36d12e3 100644
--- a/drivers/net/ppp/bsd_comp.c
+++ b/drivers/net/ppp/bsd_comp.c
@@ -436,7 +436,7 @@ static void *bsd_alloc (unsigned char *options, int opt_len, int decomp)
* Initialize the data information for the compression code
*/
db->totlen = sizeof (struct bsd_db) +
- (sizeof (struct bsd_dict) * hsize);
+ (sizeof (struct bsd_dict) * hsize);
db->hsize = hsize;
db->hshift = hshift;
diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c
index 8b41aa3fb64e..29a93d6bfe37 100644
--- a/drivers/net/ppp/ppp_async.c
+++ b/drivers/net/ppp/ppp_async.c
@@ -98,7 +98,7 @@ static int ppp_async_send(struct ppp_channel *chan, struct sk_buff *skb);
static int ppp_async_push(struct asyncppp *ap);
static void ppp_async_flush_output(struct asyncppp *ap);
static void ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
- char *flags, int count);
+ const char *flags, int count);
static int ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd,
unsigned long arg);
static void ppp_async_process(struct tasklet_struct *t);
@@ -340,7 +340,7 @@ ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
/* May sleep, don't call from interrupt level or with interrupts disabled */
static void
ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
- char *cflags, int count)
+ const char *cflags, int count)
{
struct asyncppp *ap = ap_get(tty);
unsigned long flags;
@@ -372,6 +372,7 @@ ppp_asynctty_wakeup(struct tty_struct *tty)
static struct tty_ldisc_ops ppp_ldisc = {
.owner = THIS_MODULE,
+ .num = N_PPP,
.name = "ppp",
.open = ppp_asynctty_open,
.close = ppp_asynctty_close,
@@ -389,7 +390,7 @@ ppp_async_init(void)
{
int err;
- err = tty_register_ldisc(N_PPP, &ppp_ldisc);
+ err = tty_register_ldisc(&ppp_ldisc);
if (err != 0)
printk(KERN_ERR "PPP_async: error %d registering line disc.\n",
err);
@@ -829,7 +830,7 @@ process_input_packet(struct asyncppp *ap)
static void
ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
- char *flags, int count)
+ const char *flags, int count)
{
struct sk_buff *skb;
int c, i, j, n, s, f;
@@ -1015,8 +1016,7 @@ static void async_lcp_peek(struct asyncppp *ap, unsigned char *data,
static void __exit ppp_async_cleanup(void)
{
- if (tty_unregister_ldisc(N_PPP) != 0)
- printk(KERN_ERR "failed to unregister PPP line discipline\n");
+ tty_unregister_ldisc(&ppp_ldisc);
}
module_init(ppp_async_init);
diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c
index 576b6a93bf23..af3e048695b6 100644
--- a/drivers/net/ppp/ppp_synctty.c
+++ b/drivers/net/ppp/ppp_synctty.c
@@ -94,7 +94,7 @@ static void ppp_sync_process(struct tasklet_struct *t);
static int ppp_sync_push(struct syncppp *ap);
static void ppp_sync_flush_output(struct syncppp *ap);
static void ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
- char *flags, int count);
+ const char *flags, int count);
static const struct ppp_channel_ops sync_ops = {
.start_xmit = ppp_sync_send,
@@ -333,7 +333,7 @@ ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
/* May sleep, don't call from interrupt level or with interrupts disabled */
static void
ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
- char *cflags, int count)
+ const char *cflags, int count)
{
struct syncppp *ap = sp_get(tty);
unsigned long flags;
@@ -365,6 +365,7 @@ ppp_sync_wakeup(struct tty_struct *tty)
static struct tty_ldisc_ops ppp_sync_ldisc = {
.owner = THIS_MODULE,
+ .num = N_SYNC_PPP,
.name = "pppsync",
.open = ppp_sync_open,
.close = ppp_sync_close,
@@ -382,7 +383,7 @@ ppp_sync_init(void)
{
int err;
- err = tty_register_ldisc(N_SYNC_PPP, &ppp_sync_ldisc);
+ err = tty_register_ldisc(&ppp_sync_ldisc);
if (err != 0)
printk(KERN_ERR "PPP_sync: error %d registering line disc.\n",
err);
@@ -665,7 +666,7 @@ ppp_sync_flush_output(struct syncppp *ap)
*/
static void
ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
- char *flags, int count)
+ const char *flags, int count)
{
struct sk_buff *skb;
unsigned char *p;
@@ -726,8 +727,7 @@ err:
static void __exit
ppp_sync_cleanup(void)
{
- if (tty_unregister_ldisc(N_SYNC_PPP) != 0)
- printk(KERN_ERR "failed to unregister Sync PPP line discipline\n");
+ tty_unregister_ldisc(&ppp_sync_ldisc);
}
module_init(ppp_sync_init);
diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c
index f78ceba42e57..ba93bab948e0 100644
--- a/drivers/net/slip/slhc.c
+++ b/drivers/net/slip/slhc.c
@@ -325,7 +325,7 @@ found:
* Found it -- move to the front on the connection list.
*/
if(lcs == ocs) {
- /* found at most recently used */
+ /* found at most recently used */
} else if (cs == ocs) {
/* found at least recently used */
comp->xmit_oldest = lcs->cs_this;
diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c
index 1ab124eba8eb..dc84cb844319 100644
--- a/drivers/net/slip/slip.c
+++ b/drivers/net/slip/slip.c
@@ -685,7 +685,7 @@ static void sl_setup(struct net_device *dev)
*/
static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
struct slip *sl = tty->disc_data;
@@ -1263,6 +1263,7 @@ static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static struct tty_ldisc_ops sl_ldisc = {
.owner = THIS_MODULE,
+ .num = N_SLIP,
.name = "slip",
.open = slip_open,
.close = slip_close,
@@ -1298,7 +1299,7 @@ static int __init slip_init(void)
return -ENOMEM;
/* Fill in our line protocol discipline, and register it */
- status = tty_register_ldisc(N_SLIP, &sl_ldisc);
+ status = tty_register_ldisc(&sl_ldisc);
if (status != 0) {
printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status);
kfree(slip_devs);
@@ -1359,9 +1360,7 @@ static void __exit slip_exit(void)
kfree(slip_devs);
slip_devs = NULL;
- i = tty_unregister_ldisc(N_SLIP);
- if (i != 0)
- printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i);
+ tty_unregister_ldisc(&sl_ldisc);
}
module_init(slip_init);
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 84f832806313..2ced021f4faf 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -2559,15 +2559,15 @@ static int tun_flags(struct tun_struct *tun)
return tun->flags & (TUN_FEATURES | IFF_PERSIST | IFF_TUN | IFF_TAP);
}
-static ssize_t tun_show_flags(struct device *dev, struct device_attribute *attr,
+static ssize_t tun_flags_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct tun_struct *tun = netdev_priv(to_net_dev(dev));
return sprintf(buf, "0x%x\n", tun_flags(tun));
}
-static ssize_t tun_show_owner(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t owner_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct tun_struct *tun = netdev_priv(to_net_dev(dev));
return uid_valid(tun->owner)?
@@ -2576,8 +2576,8 @@ static ssize_t tun_show_owner(struct device *dev, struct device_attribute *attr,
sprintf(buf, "-1\n");
}
-static ssize_t tun_show_group(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t group_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct tun_struct *tun = netdev_priv(to_net_dev(dev));
return gid_valid(tun->group) ?
@@ -2586,9 +2586,9 @@ static ssize_t tun_show_group(struct device *dev, struct device_attribute *attr,
sprintf(buf, "-1\n");
}
-static DEVICE_ATTR(tun_flags, 0444, tun_show_flags, NULL);
-static DEVICE_ATTR(owner, 0444, tun_show_owner, NULL);
-static DEVICE_ATTR(group, 0444, tun_show_group, NULL);
+static DEVICE_ATTR_RO(tun_flags);
+static DEVICE_ATTR_RO(owner);
+static DEVICE_ATTR_RO(group);
static struct attribute *tun_dev_attrs[] = {
&dev_attr_tun_flags.attr,
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index fbbe78643631..4c5d69732a7e 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -164,12 +164,14 @@ config USB_NET_AX8817X
depends on USB_USBNET
select CRC32
select PHYLIB
+ select AX88796B_PHY
+ imply NET_SELFTESTS
default y
help
This option adds support for ASIX AX88xxx based USB 2.0
10/100 Ethernet adapters.
- This driver should work with at least the following devices:
+ This driver should work with at least the following devices:
* Aten UC210T
* ASIX AX88172
* Billionton Systems, USB2AR
@@ -220,13 +222,13 @@ config USB_NET_CDCETHER
CDC Ethernet is an implementation option for DOCSIS cable modems
that support USB connectivity, used for non-Microsoft USB hosts.
The Linux-USB CDC Ethernet Gadget driver is an open implementation.
- This driver should work with at least the following devices:
+ This driver should work with at least the following devices:
* Dell Wireless 5530 HSPA
- * Ericsson PipeRider (all variants)
+ * Ericsson PipeRider (all variants)
* Ericsson Mobile Broadband Module (all variants)
- * Motorola (DM100 and SB4100)
- * Broadcom Cable Modem (reference design)
+ * Motorola (DM100 and SB4100)
+ * Broadcom Cable Modem (reference design)
* Toshiba (PCX1100U and F3507g/F3607gw)
* ...
diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h
index 3b53685301de..e1994a246122 100644
--- a/drivers/net/usb/asix.h
+++ b/drivers/net/usb/asix.h
@@ -25,6 +25,8 @@
#include <linux/usb/usbnet.h>
#include <linux/slab.h>
#include <linux/if_vlan.h>
+#include <linux/phy.h>
+#include <net/selftests.h>
#define DRIVER_VERSION "22-Dec-2011"
#define DRIVER_NAME "asix"
@@ -178,6 +180,10 @@ struct asix_common_private {
u16 presvd_phy_advertise;
u16 presvd_phy_bmcr;
struct asix_rx_fixup_info rx_fixup_info;
+ struct mii_bus *mdio;
+ struct phy_device *phydev;
+ u16 phy_addr;
+ char phy_name[20];
};
extern const struct driver_info ax88172a_info;
@@ -205,8 +211,7 @@ struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
int asix_set_sw_mii(struct usbnet *dev, int in_pm);
int asix_set_hw_mii(struct usbnet *dev, int in_pm);
-int asix_read_phy_addr(struct usbnet *dev, int internal);
-int asix_get_phy_addr(struct usbnet *dev);
+int asix_read_phy_addr(struct usbnet *dev, bool internal);
int asix_sw_reset(struct usbnet *dev, u8 flags, int in_pm);
@@ -215,6 +220,7 @@ int asix_write_rx_ctl(struct usbnet *dev, u16 mode, int in_pm);
u16 asix_read_medium_status(struct usbnet *dev, int in_pm);
int asix_write_medium_mode(struct usbnet *dev, u16 mode, int in_pm);
+void asix_adjust_link(struct net_device *netdev);
int asix_write_gpio(struct usbnet *dev, u16 value, int sleep, int in_pm);
@@ -223,6 +229,9 @@ void asix_set_multicast(struct net_device *net);
int asix_mdio_read(struct net_device *netdev, int phy_id, int loc);
void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val);
+int asix_mdio_bus_read(struct mii_bus *bus, int phy_id, int regnum);
+int asix_mdio_bus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val);
+
int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc);
void asix_mdio_write_nopm(struct net_device *netdev, int phy_id, int loc,
int val);
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c
index 7bc6e8f856fe..ac92bc52a85e 100644
--- a/drivers/net/usb/asix_common.c
+++ b/drivers/net/usb/asix_common.c
@@ -288,32 +288,33 @@ int asix_set_hw_mii(struct usbnet *dev, int in_pm)
return ret;
}
-int asix_read_phy_addr(struct usbnet *dev, int internal)
+int asix_read_phy_addr(struct usbnet *dev, bool internal)
{
- int offset = (internal ? 1 : 0);
+ int ret, offset;
u8 buf[2];
- int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf, 0);
- netdev_dbg(dev->net, "asix_get_phy_addr()\n");
+ ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf, 0);
+ if (ret < 0)
+ goto error;
if (ret < 2) {
- netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret);
- goto out;
+ ret = -EIO;
+ goto error;
}
- netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n",
- *((__le16 *)buf));
+
+ offset = (internal ? 1 : 0);
ret = buf[offset];
-out:
+ netdev_dbg(dev->net, "%s PHY address 0x%x\n",
+ internal ? "internal" : "external", ret);
+
return ret;
-}
-int asix_get_phy_addr(struct usbnet *dev)
-{
- /* return the address of the internal phy */
- return asix_read_phy_addr(dev, 1);
-}
+error:
+ netdev_err(dev->net, "Error reading PHY_ID register: %02x\n", ret);
+ return ret;
+}
int asix_sw_reset(struct usbnet *dev, u8 flags, int in_pm)
{
@@ -383,6 +384,27 @@ int asix_write_medium_mode(struct usbnet *dev, u16 mode, int in_pm)
return ret;
}
+/* set MAC link settings according to information from phylib */
+void asix_adjust_link(struct net_device *netdev)
+{
+ struct phy_device *phydev = netdev->phydev;
+ struct usbnet *dev = netdev_priv(netdev);
+ u16 mode = 0;
+
+ if (phydev->link) {
+ mode = AX88772_MEDIUM_DEFAULT;
+
+ if (phydev->duplex == DUPLEX_HALF)
+ mode &= ~AX_MEDIUM_FD;
+
+ if (phydev->speed != SPEED_100)
+ mode &= ~AX_MEDIUM_PS;
+ }
+
+ asix_write_medium_mode(dev, mode, 0);
+ phy_print_status(phydev);
+}
+
int asix_write_gpio(struct usbnet *dev, u16 value, int sleep, int in_pm)
{
int ret;
@@ -463,18 +485,23 @@ int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
return ret;
}
- asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
- (__u16)loc, 2, &res, 0);
- asix_set_hw_mii(dev, 0);
+ ret = asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2,
+ &res, 0);
+ if (ret < 0)
+ goto out;
+
+ ret = asix_set_hw_mii(dev, 0);
+out:
mutex_unlock(&dev->phy_mutex);
netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
phy_id, loc, le16_to_cpu(res));
- return le16_to_cpu(res);
+ return ret < 0 ? ret : le16_to_cpu(res);
}
-void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+static int __asix_mdio_write(struct net_device *netdev, int phy_id, int loc,
+ int val)
{
struct usbnet *dev = netdev_priv(netdev);
__le16 res = cpu_to_le16(val);
@@ -494,15 +521,40 @@ void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG,
0, 0, 1, &smsr, 0);
} while (!(smsr & AX_HOST_EN) && (i++ < 30) && (ret != -ENODEV));
- if (ret == -ENODEV) {
- mutex_unlock(&dev->phy_mutex);
- return;
- }
- asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
- (__u16)loc, 2, &res, 0);
- asix_set_hw_mii(dev, 0);
+ if (ret == -ENODEV)
+ goto out;
+
+ ret = asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2,
+ &res, 0);
+ if (ret < 0)
+ goto out;
+
+ ret = asix_set_hw_mii(dev, 0);
+out:
mutex_unlock(&dev->phy_mutex);
+
+ return ret < 0 ? ret : 0;
+}
+
+void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+{
+ __asix_mdio_write(netdev, phy_id, loc, val);
+}
+
+/* MDIO read and write wrappers for phylib */
+int asix_mdio_bus_read(struct mii_bus *bus, int phy_id, int regnum)
+{
+ struct usbnet *priv = bus->priv;
+
+ return asix_mdio_read(priv->net, phy_id, regnum);
+}
+
+int asix_mdio_bus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val)
+{
+ struct usbnet *priv = bus->priv;
+
+ return __asix_mdio_write(priv->net, phy_id, regnum, val);
}
int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc)
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 19a8fafb8f04..2c115216420a 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -262,7 +262,10 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
dev->mii.mdio_write = asix_mdio_write;
dev->mii.phy_id_mask = 0x3f;
dev->mii.reg_num_mask = 0x1f;
- dev->mii.phy_id = asix_get_phy_addr(dev);
+
+ dev->mii.phy_id = asix_read_phy_addr(dev, true);
+ if (dev->mii.phy_id < 0)
+ return dev->mii.phy_id;
dev->net->netdev_ops = &ax88172_netdev_ops;
dev->net->ethtool_ops = &ax88172_ethtool_ops;
@@ -280,9 +283,29 @@ out:
return ret;
}
+static void ax88772_ethtool_get_strings(struct net_device *netdev, u32 sset,
+ u8 *data)
+{
+ switch (sset) {
+ case ETH_SS_TEST:
+ net_selftest_get_strings(data);
+ break;
+ }
+}
+
+static int ax88772_ethtool_get_sset_count(struct net_device *ndev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_TEST:
+ return net_selftest_get_count();
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static const struct ethtool_ops ax88772_ethtool_ops = {
.get_drvinfo = asix_get_drvinfo,
- .get_link = asix_get_link,
+ .get_link = usbnet_get_link,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_wol = asix_get_wol,
@@ -290,37 +313,18 @@ static const struct ethtool_ops ax88772_ethtool_ops = {
.get_eeprom_len = asix_get_eeprom_len,
.get_eeprom = asix_get_eeprom,
.set_eeprom = asix_set_eeprom,
- .nway_reset = usbnet_nway_reset,
- .get_link_ksettings = usbnet_get_link_ksettings_mii,
- .set_link_ksettings = usbnet_set_link_ksettings_mii,
+ .nway_reset = phy_ethtool_nway_reset,
+ .get_link_ksettings = phy_ethtool_get_link_ksettings,
+ .set_link_ksettings = phy_ethtool_set_link_ksettings,
+ .self_test = net_selftest,
+ .get_strings = ax88772_ethtool_get_strings,
+ .get_sset_count = ax88772_ethtool_get_sset_count,
};
-static int ax88772_link_reset(struct usbnet *dev)
-{
- u16 mode;
- struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
-
- mii_check_media(&dev->mii, 1, 1);
- mii_ethtool_gset(&dev->mii, &ecmd);
- mode = AX88772_MEDIUM_DEFAULT;
-
- if (ethtool_cmd_speed(&ecmd) != SPEED_100)
- mode &= ~AX_MEDIUM_PS;
-
- if (ecmd.duplex != DUPLEX_FULL)
- mode &= ~AX_MEDIUM_FD;
-
- netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
- ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
-
- asix_write_medium_mode(dev, mode, 0);
-
- return 0;
-}
-
static int ax88772_reset(struct usbnet *dev)
{
struct asix_data *data = (struct asix_data *)&dev->data;
+ struct asix_common_private *priv = dev->driver_priv;
int ret;
/* Rewrite MAC address */
@@ -339,6 +343,8 @@ static int ax88772_reset(struct usbnet *dev)
if (ret < 0)
goto out;
+ phy_start(priv->phydev);
+
return 0;
out:
@@ -583,7 +589,7 @@ static const struct net_device_ops ax88772_netdev_ops = {
.ndo_get_stats64 = dev_get_tstats64,
.ndo_set_mac_address = asix_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
- .ndo_do_ioctl = asix_ioctl,
+ .ndo_do_ioctl = phy_do_ioctl_running,
.ndo_set_rx_mode = asix_set_multicast,
};
@@ -592,6 +598,9 @@ static void ax88772_suspend(struct usbnet *dev)
struct asix_common_private *priv = dev->driver_priv;
u16 medium;
+ if (netif_running(dev->net))
+ phy_stop(priv->phydev);
+
/* Stop MAC operation */
medium = asix_read_medium_status(dev, 1);
medium &= ~AX_MEDIUM_RE;
@@ -599,14 +608,6 @@ static void ax88772_suspend(struct usbnet *dev)
netdev_dbg(dev->net, "ax88772_suspend: medium=0x%04x\n",
asix_read_medium_status(dev, 1));
-
- /* Preserve BMCR for restoring */
- priv->presvd_phy_bmcr =
- asix_mdio_read_nopm(dev->net, dev->mii.phy_id, MII_BMCR);
-
- /* Preserve ANAR for restoring */
- priv->presvd_phy_advertise =
- asix_mdio_read_nopm(dev->net, dev->mii.phy_id, MII_ADVERTISE);
}
static int asix_suspend(struct usb_interface *intf, pm_message_t message)
@@ -620,39 +621,22 @@ static int asix_suspend(struct usb_interface *intf, pm_message_t message)
return usbnet_suspend(intf, message);
}
-static void ax88772_restore_phy(struct usbnet *dev)
-{
- struct asix_common_private *priv = dev->driver_priv;
-
- if (priv->presvd_phy_advertise) {
- /* Restore Advertisement control reg */
- asix_mdio_write_nopm(dev->net, dev->mii.phy_id, MII_ADVERTISE,
- priv->presvd_phy_advertise);
-
- /* Restore BMCR */
- if (priv->presvd_phy_bmcr & BMCR_ANENABLE)
- priv->presvd_phy_bmcr |= BMCR_ANRESTART;
-
- asix_mdio_write_nopm(dev->net, dev->mii.phy_id, MII_BMCR,
- priv->presvd_phy_bmcr);
-
- priv->presvd_phy_advertise = 0;
- priv->presvd_phy_bmcr = 0;
- }
-}
-
static void ax88772_resume(struct usbnet *dev)
{
+ struct asix_common_private *priv = dev->driver_priv;
int i;
for (i = 0; i < 3; i++)
if (!ax88772_hw_reset(dev, 1))
break;
- ax88772_restore_phy(dev);
+
+ if (netif_running(dev->net))
+ phy_start(priv->phydev);
}
static void ax88772a_resume(struct usbnet *dev)
{
+ struct asix_common_private *priv = dev->driver_priv;
int i;
for (i = 0; i < 3; i++) {
@@ -660,7 +644,8 @@ static void ax88772a_resume(struct usbnet *dev)
break;
}
- ax88772_restore_phy(dev);
+ if (netif_running(dev->net))
+ phy_start(priv->phydev);
}
static int asix_resume(struct usb_interface *intf)
@@ -674,12 +659,62 @@ static int asix_resume(struct usb_interface *intf)
return usbnet_resume(intf);
}
+static int ax88772_init_mdio(struct usbnet *dev)
+{
+ struct asix_common_private *priv = dev->driver_priv;
+
+ priv->mdio = devm_mdiobus_alloc(&dev->udev->dev);
+ if (!priv->mdio)
+ return -ENOMEM;
+
+ priv->mdio->priv = dev;
+ priv->mdio->read = &asix_mdio_bus_read;
+ priv->mdio->write = &asix_mdio_bus_write;
+ priv->mdio->name = "Asix MDIO Bus";
+ /* mii bus name is usb-<usb bus number>-<usb device number> */
+ snprintf(priv->mdio->id, MII_BUS_ID_SIZE, "usb-%03d:%03d",
+ dev->udev->bus->busnum, dev->udev->devnum);
+
+ return devm_mdiobus_register(&dev->udev->dev, priv->mdio);
+}
+
+static int ax88772_init_phy(struct usbnet *dev)
+{
+ struct asix_common_private *priv = dev->driver_priv;
+ int ret;
+
+ ret = asix_read_phy_addr(dev, true);
+ if (ret < 0)
+ return ret;
+
+ priv->phy_addr = ret;
+
+ snprintf(priv->phy_name, sizeof(priv->phy_name), PHY_ID_FMT,
+ priv->mdio->id, priv->phy_addr);
+
+ priv->phydev = phy_connect(dev->net, priv->phy_name, &asix_adjust_link,
+ PHY_INTERFACE_MODE_INTERNAL);
+ if (IS_ERR(priv->phydev)) {
+ netdev_err(dev->net, "Could not connect to PHY device %s\n",
+ priv->phy_name);
+ ret = PTR_ERR(priv->phydev);
+ return ret;
+ }
+
+ phy_suspend(priv->phydev);
+ priv->phydev->mac_managed_pm = 1;
+
+ phy_attached_info(priv->phydev);
+
+ return 0;
+}
+
static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
{
- int ret, i;
u8 buf[ETH_ALEN] = {0}, chipcode = 0;
- u32 phyid;
struct asix_common_private *priv;
+ int ret, i;
+ u32 phyid;
usbnet_get_endpoints(dev, intf);
@@ -711,14 +746,6 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
asix_set_netdev_dev_addr(dev, buf);
- /* Initialize MII structure */
- dev->mii.dev = dev->net;
- dev->mii.mdio_read = asix_mdio_read;
- dev->mii.mdio_write = asix_mdio_write;
- dev->mii.phy_id_mask = 0x1f;
- dev->mii.reg_num_mask = 0x1f;
- dev->mii.phy_id = asix_get_phy_addr(dev);
-
dev->net->netdev_ops = &ax88772_netdev_ops;
dev->net->ethtool_ops = &ax88772_ethtool_ops;
dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */
@@ -746,11 +773,11 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
dev->rx_urb_size = 2048;
}
- dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL);
- if (!dev->driver_priv)
+ priv = devm_kzalloc(&dev->udev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- priv = dev->driver_priv;
+ dev->driver_priv = priv;
priv->presvd_phy_bmcr = 0;
priv->presvd_phy_advertise = 0;
@@ -762,13 +789,32 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
priv->suspend = ax88772_suspend;
}
+ ret = ax88772_init_mdio(dev);
+ if (ret)
+ return ret;
+
+ return ax88772_init_phy(dev);
+}
+
+static int ax88772_stop(struct usbnet *dev)
+{
+ struct asix_common_private *priv = dev->driver_priv;
+
+ /* On unplugged USB, we will get MDIO communication errors and the
+ * PHY will be set in to PHY_HALTED state.
+ */
+ if (priv->phydev->state != PHY_HALTED)
+ phy_stop(priv->phydev);
+
return 0;
}
static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)
{
+ struct asix_common_private *priv = dev->driver_priv;
+
+ phy_disconnect(priv->phydev);
asix_rx_fixup_common_free(dev->driver_priv);
- kfree(dev->driver_priv);
}
static const struct ethtool_ops ax88178_ethtool_ops = {
@@ -1081,7 +1127,10 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
dev->mii.phy_id_mask = 0x1f;
dev->mii.reg_num_mask = 0xff;
dev->mii.supports_gmii = 1;
- dev->mii.phy_id = asix_get_phy_addr(dev);
+
+ dev->mii.phy_id = asix_read_phy_addr(dev, true);
+ if (dev->mii.phy_id < 0)
+ return dev->mii.phy_id;
dev->net->netdev_ops = &ax88178_netdev_ops;
dev->net->ethtool_ops = &ax88178_ethtool_ops;
@@ -1153,8 +1202,8 @@ static const struct driver_info ax88772_info = {
.bind = ax88772_bind,
.unbind = ax88772_unbind,
.status = asix_status,
- .link_reset = ax88772_link_reset,
.reset = ax88772_reset,
+ .stop = ax88772_stop,
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
.rx_fixup = asix_rx_fixup_common,
.tx_fixup = asix_tx_fixup,
@@ -1165,7 +1214,6 @@ static const struct driver_info ax88772b_info = {
.bind = ax88772_bind,
.unbind = ax88772_unbind,
.status = asix_status,
- .link_reset = ax88772_link_reset,
.reset = ax88772_reset,
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
FLAG_MULTI_PACKET,
@@ -1201,7 +1249,6 @@ static const struct driver_info hg20f9_info = {
.bind = ax88772_bind,
.unbind = ax88772_unbind,
.status = asix_status,
- .link_reset = ax88772_link_reset,
.reset = ax88772_reset,
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
FLAG_MULTI_PACKET,
diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c
index b404c9462dce..530947d7477b 100644
--- a/drivers/net/usb/ax88172a.c
+++ b/drivers/net/usb/ax88172a.c
@@ -25,20 +25,6 @@ struct ax88172a_private {
struct asix_rx_fixup_info rx_fixup_info;
};
-/* MDIO read and write wrappers for phylib */
-static int asix_mdio_bus_read(struct mii_bus *bus, int phy_id, int regnum)
-{
- return asix_mdio_read(((struct usbnet *)bus->priv)->net, phy_id,
- regnum);
-}
-
-static int asix_mdio_bus_write(struct mii_bus *bus, int phy_id, int regnum,
- u16 val)
-{
- asix_mdio_write(((struct usbnet *)bus->priv)->net, phy_id, regnum, val);
- return 0;
-}
-
/* set MAC link settings according to information from phylib */
static void ax88172a_adjust_link(struct net_device *netdev)
{
@@ -219,7 +205,12 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf)
goto free;
}
- priv->phy_addr = asix_read_phy_addr(dev, priv->use_embdphy);
+ ret = asix_read_phy_addr(dev, priv->use_embdphy);
+ if (ret < 0)
+ goto free;
+
+ priv->phy_addr = ret;
+
ax88172a_reset_phy(dev, priv->use_embdphy);
/* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 7eb0109e9baa..eb3817d70f2b 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -217,7 +217,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
goto bad_desc;
}
skip:
- /* Communcation class functions with bmCapabilities are not
+ /* Communication class functions with bmCapabilities are not
* RNDIS. But some Wireless class RNDIS functions use
* bmCapabilities for their own purpose. The failsafe is
* therefore applied only to Communication class RNDIS
diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c
index 5db66272fc82..4c4ab7b38d78 100644
--- a/drivers/net/usb/cdc_mbim.c
+++ b/drivers/net/usb/cdc_mbim.c
@@ -168,6 +168,7 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)
subdriver = usb_cdc_wdm_register(ctx->control,
&dev->status->desc,
le16_to_cpu(ctx->mbim_desc->wMaxControlMessage),
+ WWAN_PORT_MBIM,
cdc_mbim_wdm_manage_power);
if (IS_ERR(subdriver)) {
ret = PTR_ERR(subdriver);
@@ -300,8 +301,8 @@ error:
return NULL;
}
-/* Some devices are known to send Neigbor Solicitation messages and
- * require Neigbor Advertisement replies. The IPv6 core will not
+/* Some devices are known to send Neighbor Solicitation messages and
+ * require Neighbor Advertisement replies. The IPv6 core will not
* respond since IFF_NOARP is set, so we must handle them ourselves.
*/
static void do_neigh_solicit(struct usbnet *dev, u8 *buf, u16 tci)
@@ -588,7 +589,7 @@ static const struct driver_info cdc_mbim_info_zlp = {
*
* Note: The current implementation of this feature restricts each NTB
* to a single NDP, implying that multiplexed sessions cannot share an
- * NTB. This might affect performace for multiplexed sessions.
+ * NTB. This might affect performance for multiplexed sessions.
*/
static const struct driver_info cdc_mbim_info_ndp_to_end = {
.description = "CDC MBIM",
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index df0d1837e4ed..24753a4da7e6 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -192,7 +192,8 @@ static u32 cdc_ncm_check_tx_max(struct usbnet *dev, u32 new_tx)
return val;
}
-static ssize_t cdc_ncm_show_min_tx_pkt(struct device *d, struct device_attribute *attr, char *buf)
+static ssize_t min_tx_pkt_show(struct device *d,
+ struct device_attribute *attr, char *buf)
{
struct usbnet *dev = netdev_priv(to_net_dev(d));
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
@@ -200,7 +201,8 @@ static ssize_t cdc_ncm_show_min_tx_pkt(struct device *d, struct device_attribute
return sprintf(buf, "%u\n", ctx->min_tx_pkt);
}
-static ssize_t cdc_ncm_show_rx_max(struct device *d, struct device_attribute *attr, char *buf)
+static ssize_t rx_max_show(struct device *d,
+ struct device_attribute *attr, char *buf)
{
struct usbnet *dev = netdev_priv(to_net_dev(d));
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
@@ -208,7 +210,8 @@ static ssize_t cdc_ncm_show_rx_max(struct device *d, struct device_attribute *at
return sprintf(buf, "%u\n", ctx->rx_max);
}
-static ssize_t cdc_ncm_show_tx_max(struct device *d, struct device_attribute *attr, char *buf)
+static ssize_t tx_max_show(struct device *d,
+ struct device_attribute *attr, char *buf)
{
struct usbnet *dev = netdev_priv(to_net_dev(d));
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
@@ -216,7 +219,8 @@ static ssize_t cdc_ncm_show_tx_max(struct device *d, struct device_attribute *at
return sprintf(buf, "%u\n", ctx->tx_max);
}
-static ssize_t cdc_ncm_show_tx_timer_usecs(struct device *d, struct device_attribute *attr, char *buf)
+static ssize_t tx_timer_usecs_show(struct device *d,
+ struct device_attribute *attr, char *buf)
{
struct usbnet *dev = netdev_priv(to_net_dev(d));
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
@@ -224,7 +228,9 @@ static ssize_t cdc_ncm_show_tx_timer_usecs(struct device *d, struct device_attri
return sprintf(buf, "%u\n", ctx->timer_interval / (u32)NSEC_PER_USEC);
}
-static ssize_t cdc_ncm_store_min_tx_pkt(struct device *d, struct device_attribute *attr, const char *buf, size_t len)
+static ssize_t min_tx_pkt_store(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct usbnet *dev = netdev_priv(to_net_dev(d));
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
@@ -238,7 +244,9 @@ static ssize_t cdc_ncm_store_min_tx_pkt(struct device *d, struct device_attribu
return len;
}
-static ssize_t cdc_ncm_store_rx_max(struct device *d, struct device_attribute *attr, const char *buf, size_t len)
+static ssize_t rx_max_store(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct usbnet *dev = netdev_priv(to_net_dev(d));
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
@@ -251,7 +259,9 @@ static ssize_t cdc_ncm_store_rx_max(struct device *d, struct device_attribute *
return len;
}
-static ssize_t cdc_ncm_store_tx_max(struct device *d, struct device_attribute *attr, const char *buf, size_t len)
+static ssize_t tx_max_store(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct usbnet *dev = netdev_priv(to_net_dev(d));
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
@@ -264,7 +274,9 @@ static ssize_t cdc_ncm_store_tx_max(struct device *d, struct device_attribute *
return len;
}
-static ssize_t cdc_ncm_store_tx_timer_usecs(struct device *d, struct device_attribute *attr, const char *buf, size_t len)
+static ssize_t tx_timer_usecs_store(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct usbnet *dev = netdev_priv(to_net_dev(d));
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
@@ -285,10 +297,10 @@ static ssize_t cdc_ncm_store_tx_timer_usecs(struct device *d, struct device_att
return len;
}
-static DEVICE_ATTR(min_tx_pkt, 0644, cdc_ncm_show_min_tx_pkt, cdc_ncm_store_min_tx_pkt);
-static DEVICE_ATTR(rx_max, 0644, cdc_ncm_show_rx_max, cdc_ncm_store_rx_max);
-static DEVICE_ATTR(tx_max, 0644, cdc_ncm_show_tx_max, cdc_ncm_store_tx_max);
-static DEVICE_ATTR(tx_timer_usecs, 0644, cdc_ncm_show_tx_timer_usecs, cdc_ncm_store_tx_timer_usecs);
+static DEVICE_ATTR_RW(min_tx_pkt);
+static DEVICE_ATTR_RW(rx_max);
+static DEVICE_ATTR_RW(tx_max);
+static DEVICE_ATTR_RW(tx_timer_usecs);
static ssize_t ndp_to_end_show(struct device *d, struct device_attribute *attr, char *buf)
{
@@ -628,7 +640,7 @@ out:
/* set MTU to max supported by the device if necessary */
dev->net->mtu = min_t(int, dev->net->mtu, ctx->max_datagram_size - cdc_ncm_eth_hlen(dev));
- /* do not exceed operater preferred MTU */
+ /* do not exceed operator preferred MTU */
if (ctx->mbim_extended_desc) {
mbim_mtu = le16_to_cpu(ctx->mbim_extended_desc->wMTU);
if (mbim_mtu != 0 && mbim_mtu < dev->net->mtu)
@@ -685,7 +697,7 @@ static int cdc_ncm_setup(struct usbnet *dev)
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
u32 def_rx, def_tx;
- /* be conservative when selecting intial buffer size to
+ /* be conservative when selecting initial buffer size to
* increase the number of hosts this will work for
*/
def_rx = min_t(u32, CDC_NCM_NTB_DEF_SIZE_RX,
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 5c779cc0ea11..63006838bdcc 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -457,9 +457,8 @@ static const struct usb_device_id hso_ids[] = {
MODULE_DEVICE_TABLE(usb, hso_ids);
/* Sysfs attribute */
-static ssize_t hso_sysfs_show_porttype(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t hsotype_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct hso_device *hso_dev = dev_get_drvdata(dev);
char *port_name;
@@ -505,7 +504,7 @@ static ssize_t hso_sysfs_show_porttype(struct device *dev,
return sprintf(buf, "%s\n", port_name);
}
-static DEVICE_ATTR(hsotype, 0444, hso_sysfs_show_porttype, NULL);
+static DEVICE_ATTR_RO(hsotype);
static struct attribute *hso_serial_dev_attrs[] = {
&dev_attr_hsotype.attr,
@@ -1357,10 +1356,10 @@ out:
}
/* how much room is there for writing */
-static int hso_serial_write_room(struct tty_struct *tty)
+static unsigned int hso_serial_write_room(struct tty_struct *tty)
{
struct hso_serial *serial = tty->driver_data;
- int room;
+ unsigned int room;
unsigned long flags;
spin_lock_irqsave(&serial->serial_lock, flags);
@@ -1404,11 +1403,11 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
}
/* how many characters in the buffer */
-static int hso_serial_chars_in_buffer(struct tty_struct *tty)
+static unsigned int hso_serial_chars_in_buffer(struct tty_struct *tty)
{
struct hso_serial *serial = tty->driver_data;
- int chars;
unsigned long flags;
+ unsigned int chars;
/* sanity check */
if (serial == NULL)
diff --git a/drivers/net/usb/huawei_cdc_ncm.c b/drivers/net/usb/huawei_cdc_ncm.c
index a87f0dabcdb7..849b77330bf2 100644
--- a/drivers/net/usb/huawei_cdc_ncm.c
+++ b/drivers/net/usb/huawei_cdc_ncm.c
@@ -96,6 +96,7 @@ static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev,
subdriver = usb_cdc_wdm_register(ctx->control,
&usbnet_dev->status->desc,
1024, /* wMaxCommand */
+ WWAN_PORT_AT,
huawei_cdc_ncm_wdm_manage_power);
if (IS_ERR(subdriver)) {
ret = PTR_ERR(subdriver);
diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c
index ed05f992c612..6fde41550de1 100644
--- a/drivers/net/usb/int51x1.c
+++ b/drivers/net/usb/int51x1.c
@@ -61,7 +61,7 @@ static struct sk_buff *int51x1_tx_fixup(struct usbnet *dev,
int need_tail = 0;
__le16 *len;
- /* if packet and our header is smaler than 64 pad to 64 (+ ZLP) */
+ /* if packet and our header is smaller than 64 pad to 64 (+ ZLP) */
if ((pack_with_header_len) < dev->maxpacket)
need_tail = dev->maxpacket - pack_with_header_len + 1;
/*
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index 02bce40a67e5..25489389ea49 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -298,7 +298,7 @@ struct lan78xx_net;
struct lan78xx_priv {
struct lan78xx_net *dev;
u32 rfe_ctl;
- u32 mchash_table[DP_SEL_VHF_HASH_LEN]; /* multicat hash table */
+ u32 mchash_table[DP_SEL_VHF_HASH_LEN]; /* multicast hash table */
u32 pfilter_table[NUM_OF_MAF][2]; /* perfect filter table */
u32 vlan_table[DP_SEL_VHF_VLAN_LEN];
struct mutex dataport_mutex; /* for dataport access */
diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c
index 217a2d8fa47b..b2495fa80171 100644
--- a/drivers/net/usb/lg-vl600.c
+++ b/drivers/net/usb/lg-vl600.c
@@ -31,7 +31,7 @@
* Windows/Mac drivers do send a couple of such frames to the device
* during initialisation, with protocol set to 0x0906 or 0x0b06 and (what
* seems to be) a flag in the .dummy_flags. This doesn't seem necessary
- * for modem operation but can possibly be used for GPS or other funcitons.
+ * for modem operation but can possibly be used for GPS or other functions.
*/
struct vl600_frame_hdr {
@@ -72,7 +72,7 @@ static int vl600_bind(struct usbnet *dev, struct usb_interface *intf)
/* ARP packets don't go through, but they're also of no use. The
* subnet has only two hosts anyway: us and the gateway / DHCP
* server (probably simulated by modem firmware or network operator)
- * whose address changes everytime we connect to the intarwebz and
+ * whose address changes every time we connect to the intarwebz and
* who doesn't bother answering ARP requests either. So hardware
* addresses have no meaning, the destination and the source of every
* packet depend only on whether it is on the IN or OUT endpoint. */
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
index 9f9352a4522f..2469bdcb1a04 100644
--- a/drivers/net/usb/mcs7830.c
+++ b/drivers/net/usb/mcs7830.c
@@ -601,7 +601,7 @@ MODULE_DEVICE_TABLE(usb, products);
static int mcs7830_reset_resume (struct usb_interface *intf)
{
- /* YES, this function is successful enough that ethtool -d
+ /* YES, this function is successful enough that ethtool -d
does show same output pre-/post-suspend */
struct usbnet *dev = usb_get_intfdata(intf);
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index bc55ec739af9..6a2e4f884b12 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -710,7 +710,8 @@ static int qmi_wwan_register_subdriver(struct usbnet *dev)
/* register subdriver */
subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc,
- 4096, &qmi_wwan_cdc_wdm_manage_power);
+ 4096, WWAN_PORT_QMI,
+ &qmi_wwan_cdc_wdm_manage_power);
if (IS_ERR(subdriver)) {
dev_err(&info->control->dev, "subdriver registration failed\n");
rv = PTR_ERR(subdriver);
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index e25bfb7021ed..1692d3b1b6e1 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -931,6 +931,8 @@ struct r8152 {
u32 rx_pending;
u32 fc_pause_on, fc_pause_off;
+ unsigned int pipe_in, pipe_out, pipe_intr, pipe_ctrl_in, pipe_ctrl_out;
+
u32 support_2500full:1;
u32 lenovo_macpassthru:1;
u32 dell_tb_rx_agg_bug:1;
@@ -1198,7 +1200,7 @@ int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
if (!tmp)
return -ENOMEM;
- ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
+ ret = usb_control_msg(tp->udev, tp->pipe_ctrl_in,
RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
value, index, tmp, size, 500);
if (ret < 0)
@@ -1221,7 +1223,7 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
if (!tmp)
return -ENOMEM;
- ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
+ ret = usb_control_msg(tp->udev, tp->pipe_ctrl_out,
RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
value, index, tmp, size, 500);
@@ -2041,7 +2043,7 @@ static int alloc_all_mem(struct r8152 *tp)
goto err1;
tp->intr_interval = (int)ep_intr->desc.bInterval;
- usb_fill_int_urb(tp->intr_urb, tp->udev, usb_rcvintpipe(tp->udev, 3),
+ usb_fill_int_urb(tp->intr_urb, tp->udev, tp->pipe_intr,
tp->intr_buff, INTBUFSIZE, intr_callback,
tp, tp->intr_interval);
@@ -2305,7 +2307,7 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
if (ret < 0)
goto out_tx_fill;
- usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2),
+ usb_fill_bulk_urb(agg->urb, tp->udev, tp->pipe_out,
agg->head, (int)(tx_data - (u8 *)agg->head),
(usb_complete_t)write_bulk_callback, agg);
@@ -2445,7 +2447,7 @@ static int rx_bottom(struct r8152 *tp, int budget)
unsigned int pkt_len, rx_frag_head_sz;
struct sk_buff *skb;
- /* limite the skb numbers for rx_queue */
+ /* limit the skb numbers for rx_queue */
if (unlikely(skb_queue_len(&tp->rx_queue) >= 1000))
break;
@@ -2620,7 +2622,7 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
!test_bit(WORK_ENABLE, &tp->flags) || !netif_carrier_ok(tp->netdev))
return 0;
- usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1),
+ usb_fill_bulk_urb(agg->urb, tp->udev, tp->pipe_in,
agg->buffer, tp->rx_buf_sz,
(usb_complete_t)read_bulk_callback, agg);
@@ -8211,7 +8213,7 @@ static int rtl8152_post_reset(struct usb_interface *intf)
if (!tp)
return 0;
- /* reset the MAC adddress in case of policy change */
+ /* reset the MAC address in case of policy change */
if (determine_ethernet_addr(tp, &sa) >= 0) {
rtnl_lock();
dev_set_mac_address (tp->netdev, &sa, NULL);
@@ -8967,6 +8969,79 @@ static int rtl8152_set_ringparam(struct net_device *netdev,
return 0;
}
+static void rtl8152_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
+{
+ struct r8152 *tp = netdev_priv(netdev);
+ u16 bmcr, lcladv, rmtadv;
+ u8 cap;
+
+ if (usb_autopm_get_interface(tp->intf) < 0)
+ return;
+
+ mutex_lock(&tp->control);
+
+ bmcr = r8152_mdio_read(tp, MII_BMCR);
+ lcladv = r8152_mdio_read(tp, MII_ADVERTISE);
+ rmtadv = r8152_mdio_read(tp, MII_LPA);
+
+ mutex_unlock(&tp->control);
+
+ usb_autopm_put_interface(tp->intf);
+
+ if (!(bmcr & BMCR_ANENABLE)) {
+ pause->autoneg = 0;
+ pause->rx_pause = 0;
+ pause->tx_pause = 0;
+ return;
+ }
+
+ pause->autoneg = 1;
+
+ cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
+
+ if (cap & FLOW_CTRL_RX)
+ pause->rx_pause = 1;
+
+ if (cap & FLOW_CTRL_TX)
+ pause->tx_pause = 1;
+}
+
+static int rtl8152_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
+{
+ struct r8152 *tp = netdev_priv(netdev);
+ u16 old, new1;
+ u8 cap = 0;
+ int ret;
+
+ ret = usb_autopm_get_interface(tp->intf);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&tp->control);
+
+ if (pause->autoneg && !(r8152_mdio_read(tp, MII_BMCR) & BMCR_ANENABLE)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (pause->rx_pause)
+ cap |= FLOW_CTRL_RX;
+
+ if (pause->tx_pause)
+ cap |= FLOW_CTRL_TX;
+
+ old = r8152_mdio_read(tp, MII_ADVERTISE);
+ new1 = (old & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) | mii_advertise_flowctrl(cap);
+ if (old != new1)
+ r8152_mdio_write(tp, MII_ADVERTISE, new1);
+
+out:
+ mutex_unlock(&tp->control);
+ usb_autopm_put_interface(tp->intf);
+
+ return ret;
+}
+
static const struct ethtool_ops ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
.get_drvinfo = rtl8152_get_drvinfo,
@@ -8989,6 +9064,8 @@ static const struct ethtool_ops ops = {
.set_tunable = rtl8152_set_tunable,
.get_ringparam = rtl8152_get_ringparam,
.set_ringparam = rtl8152_set_ringparam,
+ .get_pauseparam = rtl8152_get_pauseparam,
+ .set_pauseparam = rtl8152_set_pauseparam,
};
static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@ -9432,6 +9509,12 @@ static int rtl8152_probe(struct usb_interface *intf,
tp->intf = intf;
tp->version = version;
+ tp->pipe_ctrl_in = usb_rcvctrlpipe(udev, 0);
+ tp->pipe_ctrl_out = usb_sndctrlpipe(udev, 0);
+ tp->pipe_in = usb_rcvbulkpipe(udev, 1);
+ tp->pipe_out = usb_sndbulkpipe(udev, 2);
+ tp->pipe_intr = usb_rcvintpipe(udev, 3);
+
switch (version) {
case RTL_VER_01:
case RTL_VER_02:
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index f813ca9dec53..85a8b96e39a6 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -324,7 +324,7 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags)
* For RX we handle drivers that zero-pad to end-of-packet.
* Don't let userspace change these settings.
*
- * NOTE: there still seems to be wierdness here, as if we need
+ * NOTE: there still seems to be weirdness here, as if we need
* to do some more things to make sure WinCE targets accept this.
* They default to jumbograms of 8KB or 16KB, which is absurd
* for such low data rates and which is also more than Linux
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index ecf62849f4c1..470e1c1e6353 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -74,6 +74,23 @@ MODULE_PARM_DESC (msg_level, "Override default message level");
/*-------------------------------------------------------------------------*/
+static const char * const usbnet_event_names[] = {
+ [EVENT_TX_HALT] = "EVENT_TX_HALT",
+ [EVENT_RX_HALT] = "EVENT_RX_HALT",
+ [EVENT_RX_MEMORY] = "EVENT_RX_MEMORY",
+ [EVENT_STS_SPLIT] = "EVENT_STS_SPLIT",
+ [EVENT_LINK_RESET] = "EVENT_LINK_RESET",
+ [EVENT_RX_PAUSED] = "EVENT_RX_PAUSED",
+ [EVENT_DEV_ASLEEP] = "EVENT_DEV_ASLEEP",
+ [EVENT_DEV_OPEN] = "EVENT_DEV_OPEN",
+ [EVENT_DEVICE_REPORT_IDLE] = "EVENT_DEVICE_REPORT_IDLE",
+ [EVENT_NO_RUNTIME_PM] = "EVENT_NO_RUNTIME_PM",
+ [EVENT_RX_KILL] = "EVENT_RX_KILL",
+ [EVENT_LINK_CHANGE] = "EVENT_LINK_CHANGE",
+ [EVENT_SET_RX_MODE] = "EVENT_SET_RX_MODE",
+ [EVENT_NO_IP_ALIGN] = "EVENT_NO_IP_ALIGN",
+};
+
/* handles CDC Ethernet and many other network "bulk data" interfaces */
int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf)
{
@@ -452,9 +469,9 @@ void usbnet_defer_kevent (struct usbnet *dev, int work)
{
set_bit (work, &dev->flags);
if (!schedule_work (&dev->kevent))
- netdev_dbg(dev->net, "kevent %d may have been dropped\n", work);
+ netdev_dbg(dev->net, "kevent %s may have been dropped\n", usbnet_event_names[work]);
else
- netdev_dbg(dev->net, "kevent %d scheduled\n", work);
+ netdev_dbg(dev->net, "kevent %s scheduled\n", usbnet_event_names[work]);
}
EXPORT_SYMBOL_GPL(usbnet_defer_kevent);
@@ -1597,6 +1614,9 @@ void usbnet_disconnect (struct usb_interface *intf)
xdev->bus->bus_name, xdev->devpath,
dev->driver_info->description);
+ if (dev->driver_info->unbind)
+ dev->driver_info->unbind(dev, intf);
+
net = dev->net;
unregister_netdev (net);
@@ -1604,9 +1624,6 @@ void usbnet_disconnect (struct usb_interface *intf)
usb_scuttle_anchored_urbs(&dev->deferred);
- if (dev->driver_info->unbind)
- dev->driver_info->unbind (dev, intf);
-
usb_kill_urb(dev->interrupt);
usb_free_urb(dev->interrupt);
kfree(dev->padding_pkt);
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 78a01c71a17c..56c3f8519093 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -380,7 +380,7 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
struct page *page, unsigned int offset,
unsigned int len, unsigned int truesize,
bool hdr_valid, unsigned int metasize,
- unsigned int headroom)
+ bool whole_page)
{
struct sk_buff *skb;
struct virtio_net_hdr_mrg_rxbuf *hdr;
@@ -398,16 +398,28 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
else
hdr_padded_len = sizeof(struct padded_vnet_hdr);
- /* If headroom is not 0, there is an offset between the beginning of the
+ /* If whole_page, there is an offset between the beginning of the
* data and the allocated space, otherwise the data and the allocated
* space are aligned.
*
* Buffers with headroom use PAGE_SIZE as alloc size, see
* add_recvbuf_mergeable() + get_mergeable_buf_len()
*/
- truesize = headroom ? PAGE_SIZE : truesize;
- tailroom = truesize - len - headroom - (hdr_padded_len - hdr_len);
- buf = p - headroom;
+ if (whole_page) {
+ /* Buffers with whole_page use PAGE_SIZE as alloc size,
+ * see add_recvbuf_mergeable() + get_mergeable_buf_len()
+ */
+ truesize = PAGE_SIZE;
+
+ /* page maybe head page, so we should get the buf by p, not the
+ * page
+ */
+ tailroom = truesize - len - offset_in_page(p);
+ buf = (char *)((unsigned long)p & PAGE_MASK);
+ } else {
+ tailroom = truesize - len;
+ buf = p;
+ }
len -= hdr_len;
offset += hdr_padded_len;
@@ -721,6 +733,12 @@ static struct sk_buff *receive_small(struct net_device *dev,
len -= vi->hdr_len;
stats->bytes += len;
+ if (unlikely(len > GOOD_PACKET_LEN)) {
+ pr_debug("%s: rx error: len %u exceeds max size %d\n",
+ dev->name, len, GOOD_PACKET_LEN);
+ dev->stats.rx_length_errors++;
+ goto err_len;
+ }
rcu_read_lock();
xdp_prog = rcu_dereference(rq->xdp_prog);
if (xdp_prog) {
@@ -824,6 +842,7 @@ err:
err_xdp:
rcu_read_unlock();
stats->xdp_drops++;
+err_len:
stats->drops++;
put_page(page);
xdp_xmit:
@@ -877,6 +896,12 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
head_skb = NULL;
stats->bytes += len - vi->hdr_len;
+ if (unlikely(len > truesize)) {
+ pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
+ dev->name, len, (unsigned long)ctx);
+ dev->stats.rx_length_errors++;
+ goto err_skb;
+ }
rcu_read_lock();
xdp_prog = rcu_dereference(rq->xdp_prog);
if (xdp_prog) {
@@ -953,8 +978,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
put_page(page);
head_skb = page_to_skb(vi, rq, xdp_page, offset,
len, PAGE_SIZE, false,
- metasize,
- VIRTIO_XDP_HEADROOM);
+ metasize, true);
return head_skb;
}
break;
@@ -1004,15 +1028,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
}
rcu_read_unlock();
- if (unlikely(len > truesize)) {
- pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
- dev->name, len, (unsigned long)ctx);
- dev->stats.rx_length_errors++;
- goto err_skb;
- }
-
head_skb = page_to_skb(vi, rq, page, offset, len, truesize, !xdp_prog,
- metasize, headroom);
+ metasize, !!headroom);
curr_skb = head_skb;
if (unlikely(!curr_skb))
@@ -1499,12 +1516,16 @@ static void virtnet_poll_cleantx(struct receive_queue *rq)
return;
if (__netif_tx_trylock(txq)) {
- free_old_xmit_skbs(sq, true);
+ do {
+ virtqueue_disable_cb(sq->vq);
+ free_old_xmit_skbs(sq, true);
+ } while (unlikely(!virtqueue_enable_cb_delayed(sq->vq)));
+
+ if (sq->vq->num_free >= 2 + MAX_SKB_FRAGS)
+ netif_tx_wake_queue(txq);
+
__netif_tx_unlock(txq);
}
-
- if (sq->vq->num_free >= 2 + MAX_SKB_FRAGS)
- netif_tx_wake_queue(txq);
}
static int virtnet_poll(struct napi_struct *napi, int budget)
@@ -1575,6 +1596,8 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget)
struct virtnet_info *vi = sq->vq->vdev->priv;
unsigned int index = vq2txq(sq->vq);
struct netdev_queue *txq;
+ int opaque;
+ bool done;
if (unlikely(is_xdp_raw_buffer_queue(vi, index))) {
/* We don't need to enable cb for XDP */
@@ -1584,14 +1607,32 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget)
txq = netdev_get_tx_queue(vi->dev, index);
__netif_tx_lock(txq, raw_smp_processor_id());
+ virtqueue_disable_cb(sq->vq);
free_old_xmit_skbs(sq, true);
- __netif_tx_unlock(txq);
-
- virtqueue_napi_complete(napi, sq->vq, 0);
if (sq->vq->num_free >= 2 + MAX_SKB_FRAGS)
netif_tx_wake_queue(txq);
+ opaque = virtqueue_enable_cb_prepare(sq->vq);
+
+ done = napi_complete_done(napi, 0);
+
+ if (!done)
+ virtqueue_disable_cb(sq->vq);
+
+ __netif_tx_unlock(txq);
+
+ if (done) {
+ if (unlikely(virtqueue_poll(sq->vq, opaque))) {
+ if (napi_schedule_prep(napi)) {
+ __netif_tx_lock(txq, raw_smp_processor_id());
+ virtqueue_disable_cb(sq->vq);
+ __netif_tx_unlock(txq);
+ __napi_schedule(napi);
+ }
+ }
+ }
+
return 0;
}
@@ -1619,7 +1660,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
virtio_is_little_endian(vi->vdev), false,
0))
- BUG();
+ return -EPROTO;
if (vi->mergeable_rx_bufs)
hdr->num_buffers = 0;
@@ -1653,10 +1694,14 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
bool use_napi = sq->napi.weight;
/* Free up any pending old buffers before queueing new ones. */
- free_old_xmit_skbs(sq, false);
+ do {
+ if (use_napi)
+ virtqueue_disable_cb(sq->vq);
+
+ free_old_xmit_skbs(sq, false);
- if (use_napi && kick)
- virtqueue_enable_cb_delayed(sq->vq);
+ } while (use_napi && kick &&
+ unlikely(!virtqueue_enable_cb_delayed(sq->vq)));
/* timestamp packet in software */
skb_tx_timestamp(skb);
@@ -1726,6 +1771,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
{
struct scatterlist *sgs[4], hdr, stat;
unsigned out_num = 0, tmp;
+ int ret;
/* Caller should know better */
BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ));
@@ -1745,7 +1791,12 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
sgs[out_num] = &stat;
BUG_ON(out_num + 1 > ARRAY_SIZE(sgs));
- virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC);
+ ret = virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC);
+ if (ret < 0) {
+ dev_warn(&vi->vdev->dev,
+ "Failed to add sgs for command vq: %d\n.", ret);
+ return false;
+ }
if (unlikely(!virtqueue_kick(vi->cvq)))
return vi->ctrl->status == VIRTIO_NET_OK;
@@ -2830,8 +2881,8 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
ctx[rxq2vq(i)] = true;
}
- ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
- names, ctx, NULL);
+ ret = virtio_find_vqs_ctx(vi->vdev, total_vqs, vqs, callbacks,
+ names, ctx, NULL);
if (ret)
goto err_find;
@@ -3293,8 +3344,11 @@ static __maybe_unused int virtnet_restore(struct virtio_device *vdev)
virtnet_set_queues(vi, vi->curr_queue_pairs);
err = virtnet_cpu_notif_add(vi);
- if (err)
+ if (err) {
+ virtnet_freeze_down(vdev);
+ remove_vq_common(vi);
return err;
+ }
return 0;
}
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index c0bd9cbc43b1..1b483cf2b1ca 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -1,7 +1,7 @@
/*
* Linux driver for VMware's vmxnet3 ethernet NIC.
*
- * Copyright (C) 2008-2020, VMware, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2021, VMware, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -26,6 +26,10 @@
#include "vmxnet3_int.h"
+#include <net/vxlan.h>
+#include <net/geneve.h>
+
+#define VXLAN_UDP_PORT 8472
struct vmxnet3_stat_desc {
char desc[ETH_GSTRING_LEN];
@@ -262,6 +266,8 @@ netdev_features_t vmxnet3_features_check(struct sk_buff *skb,
if (VMXNET3_VERSION_GE_4(adapter) &&
skb->encapsulation && skb->ip_summed == CHECKSUM_PARTIAL) {
u8 l4_proto = 0;
+ u16 port;
+ struct udphdr *udph;
switch (vlan_get_protocol(skb)) {
case htons(ETH_P_IP):
@@ -274,8 +280,20 @@ netdev_features_t vmxnet3_features_check(struct sk_buff *skb,
return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
}
- if (l4_proto != IPPROTO_UDP)
+ switch (l4_proto) {
+ case IPPROTO_UDP:
+ udph = udp_hdr(skb);
+ port = be16_to_cpu(udph->dest);
+ /* Check if offloaded port is supported */
+ if (port != GENEVE_UDP_PORT &&
+ port != IANA_VXLAN_UDP_PORT &&
+ port != VXLAN_UDP_PORT) {
+ return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
+ }
+ break;
+ default:
return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
+ }
}
return features;
}
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 28a6c4cfe9b8..2b1b944d4b28 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -274,7 +274,7 @@ vrf_map_register_dev(struct net_device *dev, struct netlink_ext_ack *extack)
int res;
/* we pre-allocate elements used in the spin-locked section (so that we
- * keep the spinlock as short as possibile).
+ * keep the spinlock as short as possible).
*/
new_me = vrf_map_elem_alloc(GFP_KERNEL);
if (!new_me)
@@ -1366,22 +1366,22 @@ static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev,
int orig_iif = skb->skb_iif;
bool need_strict = rt6_need_strict(&ipv6_hdr(skb)->daddr);
bool is_ndisc = ipv6_ndisc_frame(skb);
- bool is_ll_src;
/* loopback, multicast & non-ND link-local traffic; do not push through
* packet taps again. Reset pkt_type for upper layers to process skb.
- * for packets with lladdr src, however, skip so that the dst can be
- * determine at input using original ifindex in the case that daddr
- * needs strict
+ * For strict packets with a source LLA, determine the dst using the
+ * original ifindex.
*/
- is_ll_src = ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL;
- if (skb->pkt_type == PACKET_LOOPBACK ||
- (need_strict && !is_ndisc && !is_ll_src)) {
+ if (skb->pkt_type == PACKET_LOOPBACK || (need_strict && !is_ndisc)) {
skb->dev = vrf_dev;
skb->skb_iif = vrf_dev->ifindex;
IP6CB(skb)->flags |= IP6SKB_L3SLAVE;
+
if (skb->pkt_type == PACKET_LOOPBACK)
skb->pkt_type = PACKET_HOST;
+ else if (ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)
+ vrf_ip6_input_dst(skb, vrf_dev, orig_iif);
+
goto out;
}
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 02a14f1b938a..5a8df5a195cb 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -2164,6 +2164,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
struct neighbour *n;
struct nd_msg *msg;
+ rcu_read_lock();
in6_dev = __in6_dev_get(dev);
if (!in6_dev)
goto out;
@@ -2215,6 +2216,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
}
out:
+ rcu_read_unlock();
consume_skb(skb);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 83c9481995dd..473df2505c8e 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -49,7 +49,7 @@ config COSA
network device.
You will need user-space utilities COSA or SRP boards for downloading
- the firmware to the cards and to set them up. Look at the
+ the firmware to the cards and to set them up. Look at the
<http://www.fi.muni.cz/~kas/cosa/> for more information. You can also
read the comment at the top of the <file:drivers/net/wan/cosa.c> for
details about the cards and the driver itself.
@@ -108,7 +108,7 @@ config HDLC
Generic HDLC driver currently supports raw HDLC, Cisco HDLC, Frame
Relay, synchronous Point-to-Point Protocol (PPP) and X.25.
- To compile this driver as a module, choose M here: the
+ To compile this driver as a module, choose M here: the
module will be called hdlc.
If unsure, say N.
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index c354a5143e99..059c2f7133be 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -28,9 +28,8 @@
#include "hd64570.h"
-
-static const char* version = "Moxa C101 driver version: 1.15";
-static const char* devname = "C101";
+static const char *version = "Moxa C101 driver version: 1.15";
+static const char *devname = "C101";
#undef DEBUG_PKT
#define DEBUG_RINGS
@@ -51,7 +50,6 @@ static const char* devname = "C101";
static char *hw; /* pointer to hw=xxx command line string */
-
typedef struct card_s {
struct net_device *dev;
spinlock_t lock; /* TX lock */
@@ -72,14 +70,13 @@ typedef struct card_s {
u8 page;
struct card_s *next_card;
-}card_t;
+} card_t;
typedef card_t port_t;
static card_t *first_card;
static card_t **new_card = &first_card;
-
#define sca_in(reg, card) readb((card)->win0base + C101_SCA + (reg))
#define sca_out(value, reg, card) writeb(value, (card)->win0base + C101_SCA + (reg))
#define sca_inw(reg, card) readw((card)->win0base + C101_SCA + (reg))
@@ -87,19 +84,18 @@ static card_t **new_card = &first_card;
/* EDA address register must be set in EDAL, EDAH order - 8 bit ISA bus */
#define sca_outw(value, reg, card) do { \
writeb(value & 0xFF, (card)->win0base + C101_SCA + (reg)); \
- writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg + 1));\
-} while(0)
+ writeb((value >> 8) & 0xFF, (card)->win0base + C101_SCA + (reg + 1));\
+} while (0)
#define port_to_card(port) (port)
#define log_node(port) (0)
#define phy_node(port) (0)
#define winsize(card) (C101_WINDOW_SIZE)
#define win0base(card) ((card)->win0base)
-#define winbase(card) ((card)->win0base + 0x2000)
+#define winbase(card) ((card)->win0base + 0x2000)
#define get_port(card, port) (card)
static void sca_msci_intr(port_t *port);
-
static inline u8 sca_get_page(card_t *card)
{
return card->page;
@@ -111,10 +107,8 @@ static inline void openwin(card_t *card, u8 page)
writeb(page, card->win0base + C101_PAGE);
}
-
#include "hd64570.c"
-
static inline void set_carrier(port_t *port)
{
if (!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD))
@@ -123,7 +117,6 @@ static inline void set_carrier(port_t *port)
netif_carrier_off(port_to_dev(port));
}
-
static void sca_msci_intr(port_t *port)
{
u8 stat = sca_in(MSCI0_OFFSET + ST1, port); /* read MSCI ST1 status */
@@ -145,13 +138,12 @@ static void sca_msci_intr(port_t *port)
set_carrier(port);
}
-
static void c101_set_iface(port_t *port)
{
u8 rxs = port->rxs & CLK_BRG_MASK;
u8 txs = port->txs & CLK_BRG_MASK;
- switch(port->settings.clock_type) {
+ switch (port->settings.clock_type) {
case CLOCK_INT:
rxs |= CLK_BRG_RX; /* TX clock */
txs |= CLK_RXCLK_TX; /* BRG output */
@@ -179,7 +171,6 @@ static void c101_set_iface(port_t *port)
sca_set_port(port);
}
-
static int c101_open(struct net_device *dev)
{
port_t *port = dev_to_port(dev);
@@ -206,7 +197,6 @@ static int c101_open(struct net_device *dev)
return 0;
}
-
static int c101_close(struct net_device *dev)
{
port_t *port = dev_to_port(dev);
@@ -218,7 +208,6 @@ static int c101_close(struct net_device *dev)
return 0;
}
-
static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
const size_t size = sizeof(sync_serial_settings);
@@ -240,7 +229,7 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (cmd != SIOCWANDEV)
return hdlc_ioctl(dev, ifr, cmd);
- switch(ifr->ifr_settings.type) {
+ switch (ifr->ifr_settings.type) {
case IF_GET_IFACE:
ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;
if (ifr->ifr_settings.size < size) {
@@ -252,7 +241,7 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return 0;
case IF_IFACE_SYNC_SERIAL:
- if(!capable(CAP_NET_ADMIN))
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(&new_line, line, size))
@@ -276,8 +265,6 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
}
-
-
static void c101_destroy_card(card_t *card)
{
readb(card->win0base + C101_PAGE); /* Resets SCA? */
@@ -309,18 +296,18 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
card_t *card;
int result;
- if (irq<3 || irq>15 || irq == 6) /* FIXME */ {
+ if (irq < 3 || irq > 15 || irq == 6) /* FIXME */ {
pr_err("invalid IRQ value\n");
return -ENODEV;
}
- if (winbase < 0xC0000 || winbase > 0xDFFFF || (winbase & 0x3FFF) !=0) {
+ if (winbase < 0xC0000 || winbase > 0xDFFFF || (winbase & 0x3FFF) != 0) {
pr_err("invalid RAM value\n");
return -ENODEV;
}
card = kzalloc(sizeof(card_t), GFP_KERNEL);
- if (card == NULL)
+ if (!card)
return -ENOBUFS;
card->dev = alloc_hdlcdev(card);
@@ -392,11 +379,9 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
return 0;
}
-
-
static int __init c101_init(void)
{
- if (hw == NULL) {
+ if (!hw) {
#ifdef MODULE
pr_info("no card initialized\n");
#endif
@@ -419,26 +404,25 @@ static int __init c101_init(void)
if (*hw == '\x0')
return first_card ? 0 : -EINVAL;
- }while(*hw++ == ':');
+ } while (*hw++ == ':');
pr_err("invalid hardware parameters\n");
return first_card ? 0 : -EINVAL;
}
-
static void __exit c101_cleanup(void)
{
card_t *card = first_card;
while (card) {
card_t *ptr = card;
+
card = card->next_card;
unregister_hdlc_device(port_to_dev(ptr));
c101_destroy_card(ptr);
}
}
-
module_init(c101_init);
module_exit(c101_cleanup);
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 2369ca250cd6..43caab0b7dee 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -1,13 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* $Id: cosa.c,v 1.31 2000/03/08 17:47:16 kas Exp $ */
-/*
- * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz>
+/* Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz>
* Generic HDLC port Copyright (C) 2008 Krzysztof Halasa <khc@pm.waw.pl>
*/
-/*
- * The driver for the SRP and COSA synchronous serial cards.
+/* The driver for the SRP and COSA synchronous serial cards.
*
* HARDWARE INFO
*
@@ -90,7 +88,7 @@
#define COSA_MAX_ID_STRING 128
/* Maximum length of the channel name */
-#define COSA_MAX_NAME (sizeof("cosaXXXcXXX")+1)
+#define COSA_MAX_NAME (sizeof("cosaXXXcXXX") + 1)
/* Per-channel data structure */
@@ -124,9 +122,9 @@ struct channel_data {
};
/* cosa->firmware_status bits */
-#define COSA_FW_RESET (1<<0) /* Is the ROM monitor active? */
-#define COSA_FW_DOWNLOAD (1<<1) /* Is the microcode downloaded? */
-#define COSA_FW_START (1<<2) /* Is the microcode running? */
+#define COSA_FW_RESET BIT(0) /* Is the ROM monitor active? */
+#define COSA_FW_DOWNLOAD BIT(1) /* Is the microcode downloaded? */
+#define COSA_FW_START BIT(2) /* Is the microcode running? */
struct cosa_data {
int num; /* Card number */
@@ -152,28 +150,25 @@ struct cosa_data {
char *type; /* card type */
};
-/*
- * Define this if you want all the possible ports to be autoprobed.
+/* Define this if you want all the possible ports to be autoprobed.
* It is here but it probably is not a good idea to use this.
*/
-/* #define COSA_ISA_AUTOPROBE 1 */
+/* #define COSA_ISA_AUTOPROBE 1*/
-/*
- * Character device major number. 117 was allocated for us.
+/* Character device major number. 117 was allocated for us.
* The value of 0 means to allocate a first free one.
*/
static DEFINE_MUTEX(cosa_chardev_mutex);
static int cosa_major = 117;
-/*
- * Encoding of the minor numbers:
+/* Encoding of the minor numbers:
* The lowest CARD_MINOR_BITS bits means the channel on the single card,
* the highest bits means the card number.
*/
#define CARD_MINOR_BITS 4 /* How many bits in minor number are reserved
- * for the single card */
-/*
- * The following depends on CARD_MINOR_BITS. Unfortunately, the "MODULE_STRING"
+ * for the single card
+ */
+/* The following depends on CARD_MINOR_BITS. Unfortunately, the "MODULE_STRING"
* macro doesn't like anything other than the raw number as an argument :-(
*/
#define MAX_CARDS 16
@@ -184,8 +179,7 @@ static int cosa_major = 117;
#define DRIVER_TXMAP_SHIFT 2
#define DRIVER_TXMAP_MASK 0x0c /* FIXME: 0xfc for 8-channel version */
-/*
- * for cosa->rxtx - indicates whether either transmit or receive is
+/* for cosa->rxtx - indicates whether either transmit or receive is
* in progress. These values are mean number of the bit.
*/
#define TXBIT 0
@@ -198,22 +192,22 @@ static int cosa_major = 117;
#undef DEBUG_IRQS //1 /* Print the message when the IRQ is received */
#undef DEBUG_IO //1 /* Dump the I/O traffic */
-#define TX_TIMEOUT (5*HZ)
+#define TX_TIMEOUT (5 * HZ)
/* Maybe the following should be allocated dynamically */
static struct cosa_data cosa_cards[MAX_CARDS];
static int nr_cards;
#ifdef COSA_ISA_AUTOPROBE
-static int io[MAX_CARDS+1] = { 0x220, 0x228, 0x210, 0x218, 0, };
+static int io[MAX_CARDS + 1] = {0x220, 0x228, 0x210, 0x218, 0,};
/* NOTE: DMA is not autoprobed!!! */
-static int dma[MAX_CARDS+1] = { 1, 7, 1, 7, 1, 7, 1, 7, 0, };
+static int dma[MAX_CARDS + 1] = {1, 7, 1, 7, 1, 7, 1, 7, 0,};
#else
-static int io[MAX_CARDS+1];
-static int dma[MAX_CARDS+1];
+static int io[MAX_CARDS + 1];
+static int dma[MAX_CARDS + 1];
#endif
/* IRQ can be safely autoprobed */
-static int irq[MAX_CARDS+1] = { -1, -1, -1, -1, -1, -1, 0, };
+static int irq[MAX_CARDS + 1] = {-1, -1, -1, -1, -1, -1, 0,};
/* for class stuff*/
static struct class *cosa_class;
@@ -244,14 +238,14 @@ MODULE_LICENSE("GPL");
#define cosa_inw inw
#endif
-#define is_8bit(cosa) (!(cosa->datareg & 0x08))
+#define is_8bit(cosa) (!((cosa)->datareg & 0x08))
-#define cosa_getstatus(cosa) (cosa_inb(cosa->statusreg))
-#define cosa_putstatus(cosa, stat) (cosa_outb(stat, cosa->statusreg))
-#define cosa_getdata16(cosa) (cosa_inw(cosa->datareg))
-#define cosa_getdata8(cosa) (cosa_inb(cosa->datareg))
-#define cosa_putdata16(cosa, dt) (cosa_outw(dt, cosa->datareg))
-#define cosa_putdata8(cosa, dt) (cosa_outb(dt, cosa->datareg))
+#define cosa_getstatus(cosa) (cosa_inb((cosa)->statusreg))
+#define cosa_putstatus(cosa, stat) (cosa_outb(stat, (cosa)->statusreg))
+#define cosa_getdata16(cosa) (cosa_inw((cosa)->datareg))
+#define cosa_getdata8(cosa) (cosa_inb((cosa)->datareg))
+#define cosa_putdata16(cosa, dt) (cosa_outw(dt, (cosa)->datareg))
+#define cosa_putdata8(cosa, dt) (cosa_outb(dt, (cosa)->datareg))
/* Initialization stuff */
static int cosa_probe(int ioaddr, int irq, int dma);
@@ -280,14 +274,14 @@ static char *chrdev_setup_rx(struct channel_data *channel, int size);
static int chrdev_rx_done(struct channel_data *channel);
static int chrdev_tx_done(struct channel_data *channel, int size);
static ssize_t cosa_read(struct file *file,
- char __user *buf, size_t count, loff_t *ppos);
+ char __user *buf, size_t count, loff_t *ppos);
static ssize_t cosa_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos);
+ const char __user *buf, size_t count, loff_t *ppos);
static unsigned int cosa_poll(struct file *file, poll_table *poll);
static int cosa_open(struct inode *inode, struct file *file);
static int cosa_release(struct inode *inode, struct file *file);
static long cosa_chardev_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg);
+ unsigned long arg);
#ifdef COSA_FASYNC_WORKING
static int cosa_fasync(struct inode *inode, struct file *file, int on);
#endif
@@ -337,7 +331,7 @@ static void debug_status_in(struct cosa_data *cosa, int status);
static void debug_status_out(struct cosa_data *cosa, int status);
#endif
-static inline struct channel_data* dev_to_chan(struct net_device *dev)
+static inline struct channel_data *dev_to_chan(struct net_device *dev)
{
return (struct channel_data *)dev_to_hdlc(dev)->priv;
}
@@ -355,15 +349,16 @@ static int __init cosa_init(void)
goto out;
}
} else {
- if (!(cosa_major=register_chrdev(0, "cosa", &cosa_fops))) {
+ cosa_major = register_chrdev(0, "cosa", &cosa_fops);
+ if (!cosa_major) {
pr_warn("unable to register chardev\n");
err = -EIO;
goto out;
}
}
- for (i=0; i<MAX_CARDS; i++)
+ for (i = 0; i < MAX_CARDS; i++)
cosa_cards[i].num = -1;
- for (i=0; io[i] != 0 && i < MAX_CARDS; i++)
+ for (i = 0; io[i] != 0 && i < MAX_CARDS; i++)
cosa_probe(io[i], irq[i], dma[i]);
if (!nr_cards) {
pr_warn("no devices found\n");
@@ -426,7 +421,7 @@ static const struct net_device_ops cosa_ops = {
static int cosa_probe(int base, int irq, int dma)
{
- struct cosa_data *cosa = cosa_cards+nr_cards;
+ struct cosa_data *cosa = cosa_cards + nr_cards;
int i, err = 0;
memset(cosa, 0, sizeof(struct cosa_data));
@@ -438,7 +433,8 @@ static int cosa_probe(int base, int irq, int dma)
return -1;
}
/* I/O address should be between 0x100 and 0x3ff and should be
- * multiple of 8. */
+ * multiple of 8.
+ */
if (base < 0x100 || base > 0x3ff || base & 0x7) {
pr_info("invalid I/O address 0x%x\n", base);
return -1;
@@ -448,8 +444,9 @@ static int cosa_probe(int base, int irq, int dma)
pr_info("invalid DMA %d\n", dma);
return -1;
}
- /* and finally, on 16-bit COSA DMA should be 4-7 and
- * I/O base should not be multiple of 0x10 */
+ /* and finally, on 16-bit COSA DMA should be 4-7 and
+ * I/O base should not be multiple of 0x10
+ */
if (((base & 0x8) && dma < 4) || (!(base & 0x8) && dma > 3)) {
pr_info("8/16 bit base and DMA mismatch (base=0x%x, dma=%d)\n",
base, dma);
@@ -458,12 +455,12 @@ static int cosa_probe(int base, int irq, int dma)
cosa->dma = dma;
cosa->datareg = base;
- cosa->statusreg = is_8bit(cosa)?base+1:base+2;
+ cosa->statusreg = is_8bit(cosa) ? base + 1 : base + 2;
spin_lock_init(&cosa->lock);
- if (!request_region(base, is_8bit(cosa)?2:4,"cosa"))
+ if (!request_region(base, is_8bit(cosa) ? 2 : 4, "cosa"))
return -1;
-
+
if (cosa_reset_and_read_id(cosa, cosa->id_string) < 0) {
printk(KERN_DEBUG "probe at 0x%x failed.\n", base);
err = -1;
@@ -471,11 +468,11 @@ static int cosa_probe(int base, int irq, int dma)
}
/* Test the validity of identification string */
- if (!strncmp(cosa->id_string, "SRP", 3))
+ if (!strncmp(cosa->id_string, "SRP", 3)) {
cosa->type = "srp";
- else if (!strncmp(cosa->id_string, "COSA", 4))
- cosa->type = is_8bit(cosa)? "cosa8": "cosa16";
- else {
+ } else if (!strncmp(cosa->id_string, "COSA", 4)) {
+ cosa->type = is_8bit(cosa) ? "cosa8" : "cosa16";
+ } else {
/* Print a warning only if we are not autoprobing */
#ifndef COSA_ISA_AUTOPROBE
pr_info("valid signature not found at 0x%x\n", base);
@@ -483,9 +480,9 @@ static int cosa_probe(int base, int irq, int dma)
err = -1;
goto err_out;
}
- /* Update the name of the region now we know the type of card */
- release_region(base, is_8bit(cosa)?2:4);
- if (!request_region(base, is_8bit(cosa)?2:4, cosa->type)) {
+ /* Update the name of the region now we know the type of card */
+ release_region(base, is_8bit(cosa) ? 2 : 4);
+ if (!request_region(base, is_8bit(cosa) ? 2 : 4, cosa->type)) {
printk(KERN_DEBUG "changing name at 0x%x failed.\n", base);
return -1;
}
@@ -495,8 +492,7 @@ static int cosa_probe(int base, int irq, int dma)
unsigned long irqs;
/* pr_info("IRQ autoprobe\n"); */
irqs = probe_irq_on();
- /*
- * Enable interrupt on tx buffer empty (it sure is)
+ /* Enable interrupt on tx buffer empty (it sure is)
* really sure ?
* FIXME: When this code is not used as module, we should
* probably call udelay() instead of the interruptible sleep.
@@ -536,8 +532,8 @@ static int cosa_probe(int base, int irq, int dma)
err = -1;
goto err_out1;
}
-
- cosa->bouncebuf = kmalloc(COSA_MTU, GFP_KERNEL|GFP_DMA);
+
+ cosa->bouncebuf = kmalloc(COSA_MTU, GFP_KERNEL | GFP_DMA);
if (!cosa->bouncebuf) {
err = -ENOMEM;
goto err_out2;
@@ -563,7 +559,8 @@ static int cosa_probe(int base, int irq, int dma)
sema_init(&chan->wsem, 1);
/* Register the network interface */
- if (!(chan->netdev = alloc_hdlcdev(chan))) {
+ chan->netdev = alloc_hdlcdev(chan);
+ if (!chan->netdev) {
pr_warn("%s: alloc_hdlcdev failed\n", chan->name);
err = -ENOMEM;
goto err_hdlcdev;
@@ -603,12 +600,11 @@ err_out2:
err_out1:
free_irq(cosa->irq, cosa);
err_out:
- release_region(cosa->datareg,is_8bit(cosa)?2:4);
+ release_region(cosa->datareg, is_8bit(cosa) ? 2 : 4);
pr_notice("cosa%d: allocating resources failed\n", cosa->num);
return err;
}
-
/*---------- network device ---------- */
static int cosa_net_attach(struct net_device *dev, unsigned short encoding,
@@ -659,7 +655,7 @@ static int cosa_net_open(struct net_device *dev)
}
static netdev_tx_t cosa_net_tx(struct sk_buff *skb,
- struct net_device *dev)
+ struct net_device *dev)
{
struct channel_data *chan = dev_to_chan(dev);
@@ -714,13 +710,12 @@ static int cosa_net_close(struct net_device *dev)
static char *cosa_net_setup_rx(struct channel_data *chan, int size)
{
- /*
- * We can safely fall back to non-dma-able memory, because we have
+ /* We can safely fall back to non-dma-able memory, because we have
* the cosa->bouncebuf pre-allocated.
*/
kfree_skb(chan->rx_skb);
chan->rx_skb = dev_alloc_skb(size);
- if (chan->rx_skb == NULL) {
+ if (!chan->rx_skb) {
pr_notice("%s: Memory squeeze, dropping packet\n", chan->name);
chan->netdev->stats.rx_dropped++;
return NULL;
@@ -767,7 +762,7 @@ static int cosa_net_tx_done(struct channel_data *chan, int size)
/*---------- Character device ---------- */
static ssize_t cosa_read(struct file *file,
- char __user *buf, size_t count, loff_t *ppos)
+ char __user *buf, size_t count, loff_t *ppos)
{
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
@@ -782,9 +777,9 @@ static ssize_t cosa_read(struct file *file,
}
if (mutex_lock_interruptible(&chan->rlock))
return -ERESTARTSYS;
-
- chan->rxdata = kmalloc(COSA_MTU, GFP_DMA|GFP_KERNEL);
- if (chan->rxdata == NULL) {
+
+ chan->rxdata = kmalloc(COSA_MTU, GFP_DMA | GFP_KERNEL);
+ if (!chan->rxdata) {
mutex_unlock(&chan->rlock);
return -ENOMEM;
}
@@ -840,9 +835,8 @@ static int chrdev_rx_done(struct channel_data *chan)
return 1;
}
-
static ssize_t cosa_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos)
+ const char __user *buf, size_t count, loff_t *ppos)
{
DECLARE_WAITQUEUE(wait, current);
struct channel_data *chan = file->private_data;
@@ -860,10 +854,10 @@ static ssize_t cosa_write(struct file *file,
if (count > COSA_MTU)
count = COSA_MTU;
-
+
/* Allocate the buffer */
- kbuf = kmalloc(count, GFP_KERNEL|GFP_DMA);
- if (kbuf == NULL) {
+ kbuf = kmalloc(count, GFP_KERNEL | GFP_DMA);
+ if (!kbuf) {
up(&chan->wsem);
return -ENOMEM;
}
@@ -872,7 +866,7 @@ static ssize_t cosa_write(struct file *file,
kfree(kbuf);
return -EFAULT;
}
- chan->tx_status=0;
+ chan->tx_status = 0;
cosa_start_tx(chan, kbuf, count);
spin_lock_irqsave(&cosa->lock, flags);
@@ -927,20 +921,20 @@ static int cosa_open(struct inode *inode, struct file *file)
int ret = 0;
mutex_lock(&cosa_chardev_mutex);
- if ((n=iminor(file_inode(file))>>CARD_MINOR_BITS)
- >= nr_cards) {
+ n = iminor(file_inode(file)) >> CARD_MINOR_BITS;
+ if (n >= nr_cards) {
ret = -ENODEV;
goto out;
}
- cosa = cosa_cards+n;
+ cosa = cosa_cards + n;
- if ((n=iminor(file_inode(file))
- & ((1<<CARD_MINOR_BITS)-1)) >= cosa->nchannels) {
+ n = iminor(file_inode(file)) & ((1 << CARD_MINOR_BITS) - 1);
+ if (n >= cosa->nchannels) {
ret = -ENODEV;
goto out;
}
chan = cosa->chan + n;
-
+
file->private_data = chan;
spin_lock_irqsave(&cosa->lock, flags);
@@ -982,26 +976,25 @@ static struct fasync_struct *fasync[256] = { NULL, };
/* To be done ... */
static int cosa_fasync(struct inode *inode, struct file *file, int on)
{
- int port = iminor(inode);
+ int port = iminor(inode);
return fasync_helper(inode, file, on, &fasync[port]);
}
#endif
-
/* ---------- Ioctls ---------- */
-/*
- * Ioctl subroutines can safely be made inline, because they are called
+/* Ioctl subroutines can safely be made inline, because they are called
* only from cosa_ioctl().
*/
static inline int cosa_reset(struct cosa_data *cosa)
{
char idstring[COSA_MAX_ID_STRING];
+
if (cosa->usage > 1)
pr_info("cosa%d: WARNING: reset requested with cosa->usage > 1 (%d). Odd things may happen.\n",
cosa->num, cosa->usage);
- cosa->firmware_status &= ~(COSA_FW_RESET|COSA_FW_START);
+ cosa->firmware_status &= ~(COSA_FW_RESET | COSA_FW_START);
if (cosa_reset_and_read_id(cosa, idstring) < 0) {
pr_notice("cosa%d: reset failed\n", cosa->num);
return -EIO;
@@ -1025,7 +1018,7 @@ static inline int cosa_download(struct cosa_data *cosa, void __user *arg)
cosa->name, cosa->firmware_status);
return -EPERM;
}
-
+
if (copy_from_user(&d, arg, sizeof(d)))
return -EFAULT;
@@ -1034,9 +1027,8 @@ static inline int cosa_download(struct cosa_data *cosa, void __user *arg)
if (d.len < 0 || d.len > COSA_MAX_FIRMWARE_SIZE)
return -EINVAL;
-
/* If something fails, force the user to reset the card */
- cosa->firmware_status &= ~(COSA_FW_RESET|COSA_FW_DOWNLOAD);
+ cosa->firmware_status &= ~(COSA_FW_RESET | COSA_FW_DOWNLOAD);
i = download(cosa, d.code, d.len, d.addr);
if (i < 0) {
@@ -1046,7 +1038,7 @@ static inline int cosa_download(struct cosa_data *cosa, void __user *arg)
}
pr_info("cosa%d: downloading microcode - 0x%04x bytes at 0x%04x\n",
cosa->num, d.len, d.addr);
- cosa->firmware_status |= COSA_FW_RESET|COSA_FW_DOWNLOAD;
+ cosa->firmware_status |= COSA_FW_RESET | COSA_FW_DOWNLOAD;
return 0;
}
@@ -1091,14 +1083,15 @@ static inline int cosa_start(struct cosa_data *cosa, int address)
pr_info("cosa%d: WARNING: start microcode requested with cosa->usage > 1 (%d). Odd things may happen.\n",
cosa->num, cosa->usage);
- if ((cosa->firmware_status & (COSA_FW_RESET|COSA_FW_DOWNLOAD))
- != (COSA_FW_RESET|COSA_FW_DOWNLOAD)) {
+ if ((cosa->firmware_status & (COSA_FW_RESET | COSA_FW_DOWNLOAD))
+ != (COSA_FW_RESET | COSA_FW_DOWNLOAD)) {
pr_notice("%s: download the microcode and/or reset the card first (status %d)\n",
cosa->name, cosa->firmware_status);
return -EPERM;
}
cosa->firmware_status &= ~COSA_FW_RESET;
- if ((i=startmicrocode(cosa, address)) < 0) {
+ i = startmicrocode(cosa, address);
+ if (i < 0) {
pr_notice("cosa%d: start microcode at 0x%04x failed: %d\n",
cosa->num, address, i);
return -EIO;
@@ -1108,11 +1101,12 @@ static inline int cosa_start(struct cosa_data *cosa, int address)
cosa->firmware_status |= COSA_FW_START;
return 0;
}
-
+
/* Buffer of size at least COSA_MAX_ID_STRING is expected */
static inline int cosa_getidstr(struct cosa_data *cosa, char __user *string)
{
- int l = strlen(cosa->id_string)+1;
+ int l = strlen(cosa->id_string) + 1;
+
if (copy_to_user(string, cosa->id_string, l))
return -EFAULT;
return l;
@@ -1121,16 +1115,19 @@ static inline int cosa_getidstr(struct cosa_data *cosa, char __user *string)
/* Buffer of size at least COSA_MAX_ID_STRING is expected */
static inline int cosa_gettype(struct cosa_data *cosa, char __user *string)
{
- int l = strlen(cosa->type)+1;
+ int l = strlen(cosa->type) + 1;
+
if (copy_to_user(string, cosa->type, l))
return -EFAULT;
return l;
}
static int cosa_ioctl_common(struct cosa_data *cosa,
- struct channel_data *channel, unsigned int cmd, unsigned long arg)
+ struct channel_data *channel, unsigned int cmd,
+ unsigned long arg)
{
void __user *argp = (void __user *)arg;
+
switch (cmd) {
case COSAIORSET: /* Reset the device */
if (!capable(CAP_NET_ADMIN))
@@ -1143,7 +1140,7 @@ static int cosa_ioctl_common(struct cosa_data *cosa,
case COSAIODOWNLD: /* Download the firmware */
if (!capable(CAP_SYS_RAWIO))
return -EACCES;
-
+
return cosa_download(cosa, argp);
case COSAIORMEM:
if (!capable(CAP_SYS_RAWIO))
@@ -1176,6 +1173,7 @@ static int cosa_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
int rv;
struct channel_data *chan = dev_to_chan(dev);
+
rv = cosa_ioctl_common(chan->cosa, chan, cmd,
(unsigned long)ifr->ifr_data);
if (rv != -ENOIOCTLCMD)
@@ -1184,7 +1182,7 @@ static int cosa_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
static long cosa_chardev_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
+ unsigned long arg)
{
struct channel_data *channel = file->private_data;
struct cosa_data *cosa;
@@ -1197,11 +1195,9 @@ static long cosa_chardev_ioctl(struct file *file, unsigned int cmd,
return ret;
}
-
/*---------- HW layer interface ---------- */
-/*
- * The higher layer can bind itself to the HW layer by setting the callbacks
+/* The higher layer can bind itself to the HW layer by setting the callbacks
* in the channel_data structure and by using these routines.
*/
static void cosa_enable_rx(struct channel_data *chan)
@@ -1220,8 +1216,7 @@ static void cosa_disable_rx(struct channel_data *chan)
put_driver_status(cosa);
}
-/*
- * FIXME: This routine probably should check for cosa_start_tx() called when
+/* FIXME: This routine probably should check for cosa_start_tx() called when
* the previous transmit is still unfinished. In this case the non-zero
* return value should indicate to the caller that the queuing(sp?) up
* the transmit has failed.
@@ -1235,7 +1230,7 @@ static int cosa_start_tx(struct channel_data *chan, char *buf, int len)
pr_info("cosa%dc%d: starting tx(0x%x)",
chan->cosa->num, chan->num, len);
- for (i=0; i<len; i++)
+ for (i = 0; i < len; i++)
pr_cont(" %02x", buf[i]&0xff);
pr_cont("\n");
#endif
@@ -1262,10 +1257,10 @@ static void put_driver_status(struct cosa_data *cosa)
status = (cosa->rxbitmap ? DRIVER_RX_READY : 0)
| (cosa->txbitmap ? DRIVER_TX_READY : 0)
- | (cosa->txbitmap? ~(cosa->txbitmap<<DRIVER_TXMAP_SHIFT)
- &DRIVER_TXMAP_MASK : 0);
+ | (cosa->txbitmap ? ~(cosa->txbitmap << DRIVER_TXMAP_SHIFT)
+ & DRIVER_TXMAP_MASK : 0);
if (!cosa->rxtx) {
- if (cosa->rxbitmap|cosa->txbitmap) {
+ if (cosa->rxbitmap | cosa->txbitmap) {
if (!cosa->enabled) {
cosa_putstatus(cosa, SR_RX_INT_ENA);
#ifdef DEBUG_IO
@@ -1294,10 +1289,10 @@ static void put_driver_status_nolock(struct cosa_data *cosa)
status = (cosa->rxbitmap ? DRIVER_RX_READY : 0)
| (cosa->txbitmap ? DRIVER_TX_READY : 0)
- | (cosa->txbitmap? ~(cosa->txbitmap<<DRIVER_TXMAP_SHIFT)
- &DRIVER_TXMAP_MASK : 0);
+ | (cosa->txbitmap ? ~(cosa->txbitmap << DRIVER_TXMAP_SHIFT)
+ & DRIVER_TXMAP_MASK : 0);
- if (cosa->rxbitmap|cosa->txbitmap) {
+ if (cosa->rxbitmap | cosa->txbitmap) {
cosa_putstatus(cosa, SR_RX_INT_ENA);
#ifdef DEBUG_IO
debug_status_out(cosa, SR_RX_INT_ENA);
@@ -1316,8 +1311,7 @@ static void put_driver_status_nolock(struct cosa_data *cosa)
#endif
}
-/*
- * The "kickme" function: When the DMA times out, this is called to
+/* The "kickme" function: When the DMA times out, this is called to
* clean up the driver status.
* FIXME: Preliminary support, the interface is probably wrong.
*/
@@ -1344,7 +1338,7 @@ static void cosa_kick(struct cosa_data *cosa)
udelay(100);
cosa_putstatus(cosa, 0);
udelay(100);
- (void) cosa_getdata8(cosa);
+ (void)cosa_getdata8(cosa);
udelay(100);
cosa_putdata8(cosa, 0);
udelay(100);
@@ -1352,8 +1346,7 @@ static void cosa_kick(struct cosa_data *cosa)
spin_unlock_irqrestore(&cosa->lock, flags);
}
-/*
- * Check if the whole buffer is DMA-able. It means it is below the 16M of
+/* Check if the whole buffer is DMA-able. It means it is below the 16M of
* physical memory and doesn't span the 64k boundary. For now it seems
* SKB's never do this, but we'll check this anyway.
*/
@@ -1361,9 +1354,10 @@ static int cosa_dma_able(struct channel_data *chan, char *buf, int len)
{
static int count;
unsigned long b = (unsigned long)buf;
- if (b+len >= MAX_DMA_ADDRESS)
+
+ if (b + len >= MAX_DMA_ADDRESS)
return 0;
- if ((b^ (b+len)) & 0x10000) {
+ if ((b ^ (b + len)) & 0x10000) {
if (count++ < 5)
pr_info("%s: packet spanning a 64k boundary\n",
chan->name);
@@ -1372,11 +1366,9 @@ static int cosa_dma_able(struct channel_data *chan, char *buf, int len)
return 1;
}
-
/* ---------- The SRP/COSA ROM monitor functions ---------- */
-/*
- * Downloading SRP microcode: say "w" to SRP monitor, it answers by "w=",
+/* Downloading SRP microcode: say "w" to SRP monitor, it answers by "w=",
* drivers need to say 4-digit hex number meaning start address of the microcode
* separated by a single space. Monitor replies by saying " =". Now driver
* has to write 4-digit hex number meaning the last byte address ended
@@ -1387,18 +1379,27 @@ static int download(struct cosa_data *cosa, const char __user *microcode, int le
{
int i;
- if (put_wait_data(cosa, 'w') == -1) return -1;
+ if (put_wait_data(cosa, 'w') == -1)
+ return -1;
if ((i=get_wait_data(cosa)) != 'w') { printk("dnld: 0x%04x\n",i); return -2;}
- if (get_wait_data(cosa) != '=') return -3;
-
- if (puthexnumber(cosa, address) < 0) return -4;
- if (put_wait_data(cosa, ' ') == -1) return -10;
- if (get_wait_data(cosa) != ' ') return -11;
- if (get_wait_data(cosa) != '=') return -12;
-
- if (puthexnumber(cosa, address+length-1) < 0) return -13;
- if (put_wait_data(cosa, ' ') == -1) return -18;
- if (get_wait_data(cosa) != ' ') return -19;
+ if (get_wait_data(cosa) != '=')
+ return -3;
+
+ if (puthexnumber(cosa, address) < 0)
+ return -4;
+ if (put_wait_data(cosa, ' ') == -1)
+ return -10;
+ if (get_wait_data(cosa) != ' ')
+ return -11;
+ if (get_wait_data(cosa) != '=')
+ return -12;
+
+ if (puthexnumber(cosa, address + length - 1) < 0)
+ return -13;
+ if (put_wait_data(cosa, ' ') == -1)
+ return -18;
+ if (get_wait_data(cosa) != ' ')
+ return -19;
while (length--) {
char c;
@@ -1413,43 +1414,53 @@ static int download(struct cosa_data *cosa, const char __user *microcode, int le
microcode++;
}
- if (get_wait_data(cosa) != '\r') return -21;
- if (get_wait_data(cosa) != '\n') return -22;
- if (get_wait_data(cosa) != '.') return -23;
+ if (get_wait_data(cosa) != '\r')
+ return -21;
+ if (get_wait_data(cosa) != '\n')
+ return -22;
+ if (get_wait_data(cosa) != '.')
+ return -23;
#if 0
printk(KERN_DEBUG "cosa%d: download completed.\n", cosa->num);
#endif
return 0;
}
-
-/*
- * Starting microcode is done via the "g" command of the SRP monitor.
+/* Starting microcode is done via the "g" command of the SRP monitor.
* The chat should be the following: "g" "g=" "<addr><CR>"
* "<CR><CR><LF><CR><LF>".
*/
static int startmicrocode(struct cosa_data *cosa, int address)
{
- if (put_wait_data(cosa, 'g') == -1) return -1;
- if (get_wait_data(cosa) != 'g') return -2;
- if (get_wait_data(cosa) != '=') return -3;
-
- if (puthexnumber(cosa, address) < 0) return -4;
- if (put_wait_data(cosa, '\r') == -1) return -5;
-
- if (get_wait_data(cosa) != '\r') return -6;
- if (get_wait_data(cosa) != '\r') return -7;
- if (get_wait_data(cosa) != '\n') return -8;
- if (get_wait_data(cosa) != '\r') return -9;
- if (get_wait_data(cosa) != '\n') return -10;
+ if (put_wait_data(cosa, 'g') == -1)
+ return -1;
+ if (get_wait_data(cosa) != 'g')
+ return -2;
+ if (get_wait_data(cosa) != '=')
+ return -3;
+
+ if (puthexnumber(cosa, address) < 0)
+ return -4;
+ if (put_wait_data(cosa, '\r') == -1)
+ return -5;
+
+ if (get_wait_data(cosa) != '\r')
+ return -6;
+ if (get_wait_data(cosa) != '\r')
+ return -7;
+ if (get_wait_data(cosa) != '\n')
+ return -8;
+ if (get_wait_data(cosa) != '\r')
+ return -9;
+ if (get_wait_data(cosa) != '\n')
+ return -10;
#if 0
printk(KERN_DEBUG "cosa%d: microcode started\n", cosa->num);
#endif
return 0;
}
-/*
- * Reading memory is done via the "r" command of the SRP monitor.
+/* Reading memory is done via the "r" command of the SRP monitor.
* The chat is the following "r" "r=" "<addr> " " =" "<last_byte> " " "
* Then driver can read the data and the conversation is finished
* by SRP monitor sending "<CR><LF>." (dot at the end).
@@ -1459,27 +1470,39 @@ static int startmicrocode(struct cosa_data *cosa, int address)
*/
static int readmem(struct cosa_data *cosa, char __user *microcode, int length, int address)
{
- if (put_wait_data(cosa, 'r') == -1) return -1;
- if ((get_wait_data(cosa)) != 'r') return -2;
- if ((get_wait_data(cosa)) != '=') return -3;
-
- if (puthexnumber(cosa, address) < 0) return -4;
- if (put_wait_data(cosa, ' ') == -1) return -5;
- if (get_wait_data(cosa) != ' ') return -6;
- if (get_wait_data(cosa) != '=') return -7;
-
- if (puthexnumber(cosa, address+length-1) < 0) return -8;
- if (put_wait_data(cosa, ' ') == -1) return -9;
- if (get_wait_data(cosa) != ' ') return -10;
+ if (put_wait_data(cosa, 'r') == -1)
+ return -1;
+ if ((get_wait_data(cosa)) != 'r')
+ return -2;
+ if ((get_wait_data(cosa)) != '=')
+ return -3;
+
+ if (puthexnumber(cosa, address) < 0)
+ return -4;
+ if (put_wait_data(cosa, ' ') == -1)
+ return -5;
+ if (get_wait_data(cosa) != ' ')
+ return -6;
+ if (get_wait_data(cosa) != '=')
+ return -7;
+
+ if (puthexnumber(cosa, address + length - 1) < 0)
+ return -8;
+ if (put_wait_data(cosa, ' ') == -1)
+ return -9;
+ if (get_wait_data(cosa) != ' ')
+ return -10;
while (length--) {
char c;
int i;
- if ((i=get_wait_data(cosa)) == -1) {
+
+ i = get_wait_data(cosa);
+ if (i == -1) {
pr_info("0x%04x bytes remaining\n", length);
return -11;
}
- c=i;
+ c = i;
#if 1
if (put_user(c, microcode))
return -23; /* ??? */
@@ -1489,22 +1512,24 @@ static int readmem(struct cosa_data *cosa, char __user *microcode, int length, i
microcode++;
}
- if (get_wait_data(cosa) != '\r') return -21;
- if (get_wait_data(cosa) != '\n') return -22;
- if (get_wait_data(cosa) != '.') return -23;
+ if (get_wait_data(cosa) != '\r')
+ return -21;
+ if (get_wait_data(cosa) != '\n')
+ return -22;
+ if (get_wait_data(cosa) != '.')
+ return -23;
#if 0
printk(KERN_DEBUG "cosa%d: readmem completed.\n", cosa->num);
#endif
return 0;
}
-/*
- * This function resets the device and reads the initial prompt
+/* This function resets the device and reads the initial prompt
* of the device's ROM monitor.
*/
static int cosa_reset_and_read_id(struct cosa_data *cosa, char *idstring)
{
- int i=0, id=0, prev=0, curr=0;
+ int i = 0, id = 0, prev = 0, curr = 0;
/* Reset the card ... */
cosa_putstatus(cosa, 0);
@@ -1514,18 +1539,18 @@ static int cosa_reset_and_read_id(struct cosa_data *cosa, char *idstring)
/* Disable all IRQs from the card */
cosa_putstatus(cosa, 0);
- /*
- * Try to read the ID string. The card then prints out the
+ /* Try to read the ID string. The card then prints out the
* identification string ended by the "\n\x2e".
*
* The following loop is indexed through i (instead of id)
* to avoid looping forever when for any reason
* the port returns '\r', '\n' or '\x2e' permanently.
*/
- for (i=0; i<COSA_MAX_ID_STRING-1; i++, prev=curr) {
- if ((curr = get_wait_data(cosa)) == -1) {
+ for (i = 0; i < COSA_MAX_ID_STRING - 1; i++, prev = curr) {
+ curr = get_wait_data(cosa);
+ if (curr == -1)
return -1;
- }
+
curr &= 0xff;
if (curr != '\r' && curr != '\n' && curr != 0x2e)
idstring[id++] = curr;
@@ -1537,11 +1562,9 @@ static int cosa_reset_and_read_id(struct cosa_data *cosa, char *idstring)
return id;
}
-
/* ---------- Auxiliary routines for COSA/SRP monitor ---------- */
-/*
- * This routine gets the data byte from the card waiting for the SR_RX_RDY
+/* This routine gets the data byte from the card waiting for the SR_RX_RDY
* bit to be set in a loop. It should be used in the exceptional cases
* only (for example when resetting the card or downloading the firmware.
*/
@@ -1553,10 +1576,11 @@ static int get_wait_data(struct cosa_data *cosa)
/* read data and return them */
if (cosa_getstatus(cosa) & SR_RX_RDY) {
short r;
+
r = cosa_getdata8(cosa);
#if 0
pr_info("get_wait_data returning after %d retries\n",
- 999-retries);
+ 999 - retries);
#endif
return r;
}
@@ -1568,20 +1592,20 @@ static int get_wait_data(struct cosa_data *cosa)
return -1;
}
-/*
- * This routine puts the data byte to the card waiting for the SR_TX_RDY
+/* This routine puts the data byte to the card waiting for the SR_TX_RDY
* bit to be set in a loop. It should be used in the exceptional cases
* only (for example when resetting the card or downloading the firmware).
*/
static int put_wait_data(struct cosa_data *cosa, int data)
{
int retries = 1000;
+
while (--retries) {
/* read data and return them */
if (cosa_getstatus(cosa) & SR_TX_RDY) {
cosa_putdata8(cosa, data);
#if 0
- pr_info("Putdata: %d retries\n", 999-retries);
+ pr_info("Putdata: %d retries\n", 999 - retries);
#endif
return 0;
}
@@ -1594,9 +1618,8 @@ static int put_wait_data(struct cosa_data *cosa, int data)
cosa->num, cosa_getstatus(cosa));
return -1;
}
-
-/*
- * The following routine puts the hexadecimal number into the SRP monitor
+
+/* The following routine puts the hexadecimal number into the SRP monitor
* and verifies the proper echo of the sent bytes. Returns 0 on success,
* negative number on failure (-1,-3,-5,-7) means that put_wait_data() failed,
* (-2,-4,-6,-8) means that reading echo failed.
@@ -1608,26 +1631,24 @@ static int puthexnumber(struct cosa_data *cosa, int number)
/* Well, I should probably replace this by something faster. */
sprintf(temp, "%04X", number);
- for (i=0; i<4; i++) {
+ for (i = 0; i < 4; i++) {
if (put_wait_data(cosa, temp[i]) == -1) {
pr_notice("cosa%d: puthexnumber failed to write byte %d\n",
cosa->num, i);
- return -1-2*i;
+ return -1 - 2 * i;
}
if (get_wait_data(cosa) != temp[i]) {
pr_notice("cosa%d: puthexhumber failed to read echo of byte %d\n",
cosa->num, i);
- return -2-2*i;
+ return -2 - 2 * i;
}
}
return 0;
}
-
/* ---------- Interrupt routines ---------- */
-/*
- * There are three types of interrupt:
+/* There are three types of interrupt:
* At the beginning of transmit - this handled is in tx_interrupt(),
* at the beginning of receive - it is in rx_interrupt() and
* at the end of transmit/receive - it is the eot_interrupt() function.
@@ -1635,14 +1656,13 @@ static int puthexnumber(struct cosa_data *cosa, int number)
* COSA status byte. I have moved the rx/tx/eot interrupt handling into
* separate functions to make it more readable. These functions are inline,
* so there should be no overhead of function call.
- *
+ *
* In the COSA bus-master mode, we need to tell the card the address of a
* buffer. Unfortunately, COSA may be too slow for us, so we must busy-wait.
* It's time to use the bottom half :-(
*/
-/*
- * Transmit interrupt routine - called when COSA is willing to obtain
+/* Transmit interrupt routine - called when COSA is willing to obtain
* data from the OS. The most tricky part of the routine is selection
* of channel we (OS) want to send packet for. For SRP we should probably
* use the round-robin approach. The newer COSA firmwares have a simple
@@ -1667,7 +1687,8 @@ static inline void tx_interrupt(struct cosa_data *cosa, int status)
set_bit(TXBIT, &cosa->rxtx);
if (!test_bit(IRQBIT, &cosa->rxtx)) {
/* flow control, see the comment above */
- int i=0;
+ int i = 0;
+
if (!cosa->txbitmap) {
pr_warn("%s: No channel wants data in TX IRQ. Expect DMA timeout.\n",
cosa->name);
@@ -1681,9 +1702,10 @@ static inline void tx_interrupt(struct cosa_data *cosa, int status)
i++;
if (cosa->txchan >= cosa->nchannels)
cosa->txchan = 0;
- if (!(cosa->txbitmap & (1<<cosa->txchan)))
+ if (!(cosa->txbitmap & (1 << cosa->txchan)))
continue;
- if (~status & (1 << (cosa->txchan+DRIVER_TXMAP_SHIFT)))
+ if (~status &
+ (1 << (cosa->txchan + DRIVER_TXMAP_SHIFT)))
break;
/* in second pass, accept first ready-to-TX channel */
if (i > cosa->nchannels) {
@@ -1698,12 +1720,13 @@ static inline void tx_interrupt(struct cosa_data *cosa, int status)
}
cosa->txsize = cosa->chan[cosa->txchan].txsize;
- if (cosa_dma_able(cosa->chan+cosa->txchan,
- cosa->chan[cosa->txchan].txbuf, cosa->txsize)) {
+ if (cosa_dma_able(cosa->chan + cosa->txchan,
+ cosa->chan[cosa->txchan].txbuf,
+ cosa->txsize)) {
cosa->txbuf = cosa->chan[cosa->txchan].txbuf;
} else {
memcpy(cosa->bouncebuf, cosa->chan[cosa->txchan].txbuf,
- cosa->txsize);
+ cosa->txsize);
cosa->txbuf = cosa->bouncebuf;
}
}
@@ -1711,12 +1734,12 @@ static inline void tx_interrupt(struct cosa_data *cosa, int status)
if (is_8bit(cosa)) {
if (!test_bit(IRQBIT, &cosa->rxtx)) {
cosa_putstatus(cosa, SR_TX_INT_ENA);
- cosa_putdata8(cosa, ((cosa->txchan << 5) & 0xe0)|
+ cosa_putdata8(cosa, ((cosa->txchan << 5) & 0xe0) |
((cosa->txsize >> 8) & 0x1f));
#ifdef DEBUG_IO
debug_status_out(cosa, SR_TX_INT_ENA);
- debug_data_out(cosa, ((cosa->txchan << 5) & 0xe0)|
- ((cosa->txsize >> 8) & 0x1f));
+ debug_data_out(cosa, ((cosa->txchan << 5) & 0xe0) |
+ ((cosa->txsize >> 8) & 0x1f));
debug_data_in(cosa, cosa_getdata8(cosa));
#else
cosa_getdata8(cosa);
@@ -1727,20 +1750,20 @@ static inline void tx_interrupt(struct cosa_data *cosa, int status)
} else {
clear_bit(IRQBIT, &cosa->rxtx);
cosa_putstatus(cosa, 0);
- cosa_putdata8(cosa, cosa->txsize&0xff);
+ cosa_putdata8(cosa, cosa->txsize & 0xff);
#ifdef DEBUG_IO
debug_status_out(cosa, 0);
- debug_data_out(cosa, cosa->txsize&0xff);
+ debug_data_out(cosa, cosa->txsize & 0xff);
#endif
}
} else {
cosa_putstatus(cosa, SR_TX_INT_ENA);
- cosa_putdata16(cosa, ((cosa->txchan<<13) & 0xe000)
+ cosa_putdata16(cosa, ((cosa->txchan << 13) & 0xe000)
| (cosa->txsize & 0x1fff));
#ifdef DEBUG_IO
debug_status_out(cosa, SR_TX_INT_ENA);
- debug_data_out(cosa, ((cosa->txchan<<13) & 0xe000)
- | (cosa->txsize & 0x1fff));
+ debug_data_out(cosa, ((cosa->txchan << 13) & 0xe000) |
+ (cosa->txsize & 0x1fff));
debug_data_in(cosa, cosa_getdata8(cosa));
debug_status_out(cosa, 0);
#else
@@ -1751,25 +1774,28 @@ static inline void tx_interrupt(struct cosa_data *cosa, int status)
if (cosa->busmaster) {
unsigned long addr = virt_to_bus(cosa->txbuf);
- int count=0;
+ int count = 0;
+
pr_info("busmaster IRQ\n");
- while (!(cosa_getstatus(cosa)&SR_TX_RDY)) {
+ while (!(cosa_getstatus(cosa) & SR_TX_RDY)) {
count++;
udelay(10);
- if (count > 1000) break;
+ if (count > 1000)
+ break;
}
pr_info("status %x\n", cosa_getstatus(cosa));
pr_info("ready after %d loops\n", count);
- cosa_putdata16(cosa, (addr >> 16)&0xffff);
+ cosa_putdata16(cosa, (addr >> 16) & 0xffff);
count = 0;
- while (!(cosa_getstatus(cosa)&SR_TX_RDY)) {
+ while (!(cosa_getstatus(cosa) & SR_TX_RDY)) {
count++;
- if (count > 1000) break;
+ if (count > 1000)
+ break;
udelay(10);
}
pr_info("ready after %d loops\n", count);
- cosa_putdata16(cosa, addr &0xffff);
+ cosa_putdata16(cosa, addr & 0xffff);
flags1 = claim_dma_lock();
set_dma_mode(cosa->dma, DMA_MODE_CASCADE);
enable_dma(cosa->dma);
@@ -1785,9 +1811,9 @@ static inline void tx_interrupt(struct cosa_data *cosa, int status)
enable_dma(cosa->dma);
release_dma_lock(flags1);
}
- cosa_putstatus(cosa, SR_TX_DMA_ENA|SR_USR_INT_ENA);
+ cosa_putstatus(cosa, SR_TX_DMA_ENA | SR_USR_INT_ENA);
#ifdef DEBUG_IO
- debug_status_out(cosa, SR_TX_DMA_ENA|SR_USR_INT_ENA);
+ debug_status_out(cosa, SR_TX_DMA_ENA | SR_USR_INT_ENA);
#endif
spin_unlock_irqrestore(&cosa->lock, flags);
}
@@ -1806,7 +1832,7 @@ static inline void rx_interrupt(struct cosa_data *cosa, int status)
if (!test_bit(IRQBIT, &cosa->rxtx)) {
set_bit(IRQBIT, &cosa->rxtx);
put_driver_status_nolock(cosa);
- cosa->rxsize = cosa_getdata8(cosa) <<8;
+ cosa->rxsize = cosa_getdata8(cosa) << 8;
#ifdef DEBUG_IO
debug_data_in(cosa, cosa->rxsize >> 8);
#endif
@@ -1859,20 +1885,20 @@ reject: /* Reject the packet */
disable_dma(cosa->dma);
clear_dma_ff(cosa->dma);
set_dma_mode(cosa->dma, DMA_MODE_READ);
- if (cosa_dma_able(cosa->rxchan, cosa->rxbuf, cosa->rxsize & 0x1fff)) {
+ if (cosa_dma_able(cosa->rxchan, cosa->rxbuf, cosa->rxsize & 0x1fff))
set_dma_addr(cosa->dma, virt_to_bus(cosa->rxbuf));
- } else {
+ else
set_dma_addr(cosa->dma, virt_to_bus(cosa->bouncebuf));
- }
- set_dma_count(cosa->dma, (cosa->rxsize&0x1fff));
+
+ set_dma_count(cosa->dma, (cosa->rxsize & 0x1fff));
enable_dma(cosa->dma);
release_dma_lock(flags);
spin_lock_irqsave(&cosa->lock, flags);
- cosa_putstatus(cosa, SR_RX_DMA_ENA|SR_USR_INT_ENA);
+ cosa_putstatus(cosa, SR_RX_DMA_ENA | SR_USR_INT_ENA);
if (!is_8bit(cosa) && (status & SR_TX_RDY))
cosa_putdata8(cosa, DRIVER_RX_READY);
#ifdef DEBUG_IO
- debug_status_out(cosa, SR_RX_DMA_ENA|SR_USR_INT_ENA);
+ debug_status_out(cosa, SR_RX_DMA_ENA | SR_USR_INT_ENA);
if (!is_8bit(cosa) && (status & SR_TX_RDY))
debug_data_cmd(cosa, DRIVER_RX_READY);
#endif
@@ -1882,13 +1908,15 @@ reject: /* Reject the packet */
static inline void eot_interrupt(struct cosa_data *cosa, int status)
{
unsigned long flags, flags1;
+
spin_lock_irqsave(&cosa->lock, flags);
flags1 = claim_dma_lock();
disable_dma(cosa->dma);
clear_dma_ff(cosa->dma);
release_dma_lock(flags1);
if (test_bit(TXBIT, &cosa->rxtx)) {
- struct channel_data *chan = cosa->chan+cosa->txchan;
+ struct channel_data *chan = cosa->chan + cosa->txchan;
+
if (chan->tx_done)
if (chan->tx_done(chan, cosa->txsize))
clear_bit(chan->num, &cosa->txbitmap);
@@ -1896,9 +1924,10 @@ static inline void eot_interrupt(struct cosa_data *cosa, int status)
#ifdef DEBUG_DATA
{
int i;
+
pr_info("cosa%dc%d: done rx(0x%x)",
cosa->num, cosa->rxchan->num, cosa->rxsize);
- for (i=0; i<cosa->rxsize; i++)
+ for (i = 0; i < cosa->rxsize; i++)
pr_cont(" %02x", cosa->rxbuf[i]&0xff);
pr_cont("\n");
}
@@ -1914,8 +1943,7 @@ static inline void eot_interrupt(struct cosa_data *cosa, int status)
} else {
pr_notice("cosa%d: unexpected EOT interrupt\n", cosa->num);
}
- /*
- * Clear the RXBIT, TXBIT and IRQBIT (the latest should be
+ /* Clear the RXBIT, TXBIT and IRQBIT (the latest should be
* cleared anyway). We should do it as soon as possible
* so that we can tell the COSA we are done and to give it a time
* for recovery.
@@ -1968,10 +1996,8 @@ again:
return IRQ_HANDLED;
}
-
/* ---------- I/O debugging routines ---------- */
-/*
- * These routines can be used to monitor COSA/SRP I/O and to printk()
+/* These routines can be used to monitor COSA/SRP I/O and to printk()
* the data being transferred on the data and status I/O port in a
* readable way.
*/
@@ -1980,6 +2006,7 @@ again:
static void debug_status_in(struct cosa_data *cosa, int status)
{
char *s;
+
switch (status & SR_CMD_FROM_SRP_MASK) {
case SR_UP_REQUEST:
s = "RX_REQ";
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 5de71e44fc5a..b3466e084e84 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * FarSync WAN driver for Linux (2.6.x kernel version)
+/* FarSync WAN driver for Linux (2.6.x kernel version)
*
* Actually sync driver for X.21, V.35 and V.24 on FarSync T-series cards
*
@@ -30,8 +29,7 @@
#include "farsync.h"
-/*
- * Module info
+/* Module info
*/
MODULE_AUTHOR("R.J.Dunlop <bob.dunlop@farsite.co.uk>");
MODULE_DESCRIPTION("FarSync T-Series WAN driver. FarSite Communications Ltd.");
@@ -49,20 +47,23 @@ MODULE_LICENSE("GPL");
/* Default parameters for the link
*/
#define FST_TX_QUEUE_LEN 100 /* At 8Mbps a longer queue length is
- * useful */
+ * useful
+ */
#define FST_TXQ_DEPTH 16 /* This one is for the buffering
* of frames on the way down to the card
* so that we can keep the card busy
* and maximise throughput
*/
#define FST_HIGH_WATER_MARK 12 /* Point at which we flow control
- * network layer */
+ * network layer
+ */
#define FST_LOW_WATER_MARK 8 /* Point at which we remove flow
- * control from network layer */
+ * control from network layer
+ */
#define FST_MAX_MTU 8000 /* Huge but possible */
#define FST_DEF_MTU 1500 /* Common sane value */
-#define FST_TX_TIMEOUT (2*HZ)
+#define FST_TX_TIMEOUT (2 * HZ)
#ifdef ARPHRD_RAWHDLC
#define ARPHRD_MYTYPE ARPHRD_RAWHDLC /* Raw frames */
@@ -70,13 +71,12 @@ MODULE_LICENSE("GPL");
#define ARPHRD_MYTYPE ARPHRD_HDLC /* Cisco-HDLC (keepalives etc) */
#endif
-/*
- * Modules parameters and associated variables
+/* Modules parameters and associated variables
*/
static int fst_txq_low = FST_LOW_WATER_MARK;
static int fst_txq_high = FST_HIGH_WATER_MARK;
static int fst_max_reads = 7;
-static int fst_excluded_cards = 0;
+static int fst_excluded_cards;
static int fst_excluded_list[FST_MAX_CARDS];
module_param(fst_txq_low, int, 0);
@@ -105,9 +105,11 @@ module_param_array(fst_excluded_list, int, NULL, 0);
#define FST_MEMSIZE 0x100000 /* Size of card memory (1Mb) */
#define SMC_BASE 0x00002000L /* Base offset of the shared memory window main
- * configuration structure */
+ * configuration structure
+ */
#define BFM_BASE 0x00010000L /* Base offset of the shared memory window DMA
- * buffers */
+ * buffers
+ */
#define LEN_TX_BUFFER 8192 /* Size of packet buffers */
#define LEN_RX_BUFFER 8192
@@ -377,8 +379,7 @@ struct fst_shared {
#define INTCSR_9054 0x68 /* Interrupt control/status register */
/* 9054 DMA Registers */
-/*
- * Note that we will be using DMA Channel 0 for copying rx data
+/* Note that we will be using DMA Channel 0 for copying rx data
* and Channel 1 for copying tx data
*/
#define DMAMODE0 0x80
@@ -421,7 +422,7 @@ struct buf_window {
/* Per port (line or channel) information
*/
struct fst_port_info {
- struct net_device *dev; /* Device struct - must be first */
+ struct net_device *dev; /* Device struct - must be first */
struct fst_card_info *card; /* Card we're associated with */
int index; /* Port index on the card */
int hwif; /* Line hardware (lineInterface copy) */
@@ -431,8 +432,7 @@ struct fst_port_info {
int txpos; /* Next Tx buffer to use */
int txipos; /* Next Tx buffer to check for free */
int start; /* Indication of start/stop to network */
- /*
- * A sixteen entry transmit queue
+ /* A sixteen entry transmit queue
*/
int txqs; /* index to get next buffer to tx */
int txqe; /* index to queue next packet */
@@ -479,9 +479,7 @@ struct fst_card_info {
#define dev_to_port(D) (dev_to_hdlc(D)->priv)
#define port_to_dev(P) ((P)->dev)
-
-/*
- * Shared memory window access macros
+/* Shared memory window access macros
*
* We have a nice memory based structure above, which could be directly
* mapped on i386 but might not work on other architectures unless we use
@@ -491,16 +489,15 @@ struct fst_card_info {
*/
#define WIN_OFFSET(X) ((long)&(((struct fst_shared *)SMC_BASE)->X))
-#define FST_RDB(C,E) readb ((C)->mem + WIN_OFFSET(E))
-#define FST_RDW(C,E) readw ((C)->mem + WIN_OFFSET(E))
-#define FST_RDL(C,E) readl ((C)->mem + WIN_OFFSET(E))
+#define FST_RDB(C, E) (readb((C)->mem + WIN_OFFSET(E)))
+#define FST_RDW(C, E) (readw((C)->mem + WIN_OFFSET(E)))
+#define FST_RDL(C, E) (readl((C)->mem + WIN_OFFSET(E)))
-#define FST_WRB(C,E,B) writeb ((B), (C)->mem + WIN_OFFSET(E))
-#define FST_WRW(C,E,W) writew ((W), (C)->mem + WIN_OFFSET(E))
-#define FST_WRL(C,E,L) writel ((L), (C)->mem + WIN_OFFSET(E))
+#define FST_WRB(C, E, B) (writeb((B), (C)->mem + WIN_OFFSET(E)))
+#define FST_WRW(C, E, W) (writew((W), (C)->mem + WIN_OFFSET(E)))
+#define FST_WRL(C, E, L) (writel((L), (C)->mem + WIN_OFFSET(E)))
-/*
- * Debug support
+/* Debug support
*/
#if FST_DEBUG
@@ -524,43 +521,41 @@ do { \
} while (0)
#endif
-/*
- * PCI ID lookup table
+/* PCI ID lookup table
*/
static const struct pci_device_id fst_pci_dev_id[] = {
- {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T2P, PCI_ANY_ID,
+ {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T2P, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, FST_TYPE_T2P},
- {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T4P, PCI_ANY_ID,
+ {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T4P, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, FST_TYPE_T4P},
- {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T1U, PCI_ANY_ID,
+ {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T1U, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, FST_TYPE_T1U},
- {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T2U, PCI_ANY_ID,
+ {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T2U, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, FST_TYPE_T2U},
- {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T4U, PCI_ANY_ID,
+ {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T4U, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, FST_TYPE_T4U},
- {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_TE1, PCI_ANY_ID,
+ {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_TE1, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, FST_TYPE_TE1},
- {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_TE1C, PCI_ANY_ID,
+ {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_TE1C, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, FST_TYPE_TE1},
{0,} /* End */
};
MODULE_DEVICE_TABLE(pci, fst_pci_dev_id);
-/*
- * Device Driver Work Queues
+/* Device Driver Work Queues
*
- * So that we don't spend too much time processing events in the
- * Interrupt Service routine, we will declare a work queue per Card
+ * So that we don't spend too much time processing events in the
+ * Interrupt Service routine, we will declare a work queue per Card
* and make the ISR schedule a task in the queue for later execution.
* In the 2.4 Kernel we used to use the immediate queue for BH's
- * Now that they are gone, tasklets seem to be much better than work
+ * Now that they are gone, tasklets seem to be much better than work
* queues.
*/
@@ -578,18 +573,16 @@ static u64 fst_work_txq;
static u64 fst_work_intq;
static void
-fst_q_work_item(u64 * queue, int card_index)
+fst_q_work_item(u64 *queue, int card_index)
{
unsigned long flags;
u64 mask;
- /*
- * Grab the queue exclusively
+ /* Grab the queue exclusively
*/
spin_lock_irqsave(&fst_work_q_lock, flags);
- /*
- * Making an entry in the queue is simply a matter of setting
+ /* Making an entry in the queue is simply a matter of setting
* a bit for the card indicating that there is work to do in the
* bottom half for the card. Note the limitation of 64 cards.
* That ought to be enough
@@ -606,8 +599,7 @@ fst_process_tx_work_q(struct tasklet_struct *unused)
u64 work_txq;
int i;
- /*
- * Grab the queue exclusively
+ /* Grab the queue exclusively
*/
dbg(DBG_TX, "fst_process_tx_work_q\n");
spin_lock_irqsave(&fst_work_q_lock, flags);
@@ -615,12 +607,11 @@ fst_process_tx_work_q(struct tasklet_struct *unused)
fst_work_txq = 0;
spin_unlock_irqrestore(&fst_work_q_lock, flags);
- /*
- * Call the bottom half for each card with work waiting
+ /* Call the bottom half for each card with work waiting
*/
for (i = 0; i < FST_MAX_CARDS; i++) {
if (work_txq & 0x01) {
- if (fst_card_array[i] != NULL) {
+ if (fst_card_array[i]) {
dbg(DBG_TX, "Calling tx bh for card %d\n", i);
do_bottom_half_tx(fst_card_array[i]);
}
@@ -636,8 +627,7 @@ fst_process_int_work_q(struct tasklet_struct *unused)
u64 work_intq;
int i;
- /*
- * Grab the queue exclusively
+ /* Grab the queue exclusively
*/
dbg(DBG_INTR, "fst_process_int_work_q\n");
spin_lock_irqsave(&fst_work_q_lock, flags);
@@ -645,12 +635,11 @@ fst_process_int_work_q(struct tasklet_struct *unused)
fst_work_intq = 0;
spin_unlock_irqrestore(&fst_work_q_lock, flags);
- /*
- * Call the bottom half for each card with work waiting
+ /* Call the bottom half for each card with work waiting
*/
for (i = 0; i < FST_MAX_CARDS; i++) {
if (work_intq & 0x01) {
- if (fst_card_array[i] != NULL) {
+ if (fst_card_array[i]) {
dbg(DBG_INTR,
"Calling rx & tx bh for card %d\n", i);
do_bottom_half_rx(fst_card_array[i]);
@@ -683,19 +672,16 @@ fst_cpureset(struct fst_card_info *card)
dbg(DBG_ASS,
"Error in reading interrupt line register\n");
}
- /*
- * Assert PLX software reset and Am186 hardware reset
+ /* Assert PLX software reset and Am186 hardware reset
* and then deassert the PLX software reset but 186 still in reset
*/
outw(0x440f, card->pci_conf + CNTRL_9054 + 2);
outw(0x040f, card->pci_conf + CNTRL_9054 + 2);
- /*
- * We are delaying here to allow the 9054 to reset itself
+ /* We are delaying here to allow the 9054 to reset itself
*/
usleep_range(10, 20);
outw(0x240f, card->pci_conf + CNTRL_9054 + 2);
- /*
- * We are delaying here to allow the 9054 to reload its eeprom
+ /* We are delaying here to allow the 9054 to reload its eeprom
*/
usleep_range(10, 20);
outw(0x040f, card->pci_conf + CNTRL_9054 + 2);
@@ -720,19 +706,17 @@ static inline void
fst_cpurelease(struct fst_card_info *card)
{
if (card->family == FST_FAMILY_TXU) {
- /*
- * Force posted writes to complete
+ /* Force posted writes to complete
*/
- (void) readb(card->mem);
+ (void)readb(card->mem);
- /*
- * Release LRESET DO = 1
+ /* Release LRESET DO = 1
* Then release Local Hold, DO = 1
*/
outw(0x040e, card->pci_conf + CNTRL_9054 + 2);
outw(0x040f, card->pci_conf + CNTRL_9054 + 2);
} else {
- (void) readb(card->ctlmem);
+ (void)readb(card->ctlmem);
}
}
@@ -742,7 +726,7 @@ static inline void
fst_clear_intr(struct fst_card_info *card)
{
if (card->family == FST_FAMILY_TXU) {
- (void) readb(card->ctlmem);
+ (void)readb(card->ctlmem);
} else {
/* Poke the appropriate PLX chip register (same as enabling interrupts)
*/
@@ -755,11 +739,10 @@ fst_clear_intr(struct fst_card_info *card)
static inline void
fst_enable_intr(struct fst_card_info *card)
{
- if (card->family == FST_FAMILY_TXU) {
+ if (card->family == FST_FAMILY_TXU)
outl(0x0f0c0900, card->pci_conf + INTCSR_9054);
- } else {
+ else
outw(0x0543, card->pci_conf + INTCSR_9052);
- }
}
/* Disable card interrupts
@@ -767,11 +750,10 @@ fst_enable_intr(struct fst_card_info *card)
static inline void
fst_disable_intr(struct fst_card_info *card)
{
- if (card->family == FST_FAMILY_TXU) {
+ if (card->family == FST_FAMILY_TXU)
outl(0x00000000, card->pci_conf + INTCSR_9054);
- } else {
+ else
outw(0x0000, card->pci_conf + INTCSR_9052);
- }
}
/* Process the result of trying to pass a received frame up the stack
@@ -782,8 +764,7 @@ fst_process_rx_status(int rx_status, char *name)
switch (rx_status) {
case NET_RX_SUCCESS:
{
- /*
- * Nothing to do here
+ /* Nothing to do here
*/
break;
}
@@ -800,11 +781,10 @@ fst_process_rx_status(int rx_status, char *name)
static inline void
fst_init_dma(struct fst_card_info *card)
{
- /*
- * This is only required for the PLX 9054
+ /* This is only required for the PLX 9054
*/
if (card->family == FST_FAMILY_TXU) {
- pci_set_master(card->device);
+ pci_set_master(card->device);
outl(0x00020441, card->pci_conf + DMAMODE0);
outl(0x00020441, card->pci_conf + DMAMODE1);
outl(0x0, card->pci_conf + DMATHR);
@@ -819,8 +799,7 @@ fst_tx_dma_complete(struct fst_card_info *card, struct fst_port_info *port,
{
struct net_device *dev = port_to_dev(port);
- /*
- * Everything is now set, just tell the card to go
+ /* Everything is now set, just tell the card to go
*/
dbg(DBG_TX, "fst_tx_dma_complete\n");
FST_WRB(card, txDescrRing[port->index][txpos].bits,
@@ -830,8 +809,7 @@ fst_tx_dma_complete(struct fst_card_info *card, struct fst_port_info *port,
netif_trans_update(dev);
}
-/*
- * Mark it for our own raw sockets interface
+/* Mark it for our own raw sockets interface
*/
static __be16 farsync_type_trans(struct sk_buff *skb, struct net_device *dev)
{
@@ -874,55 +852,47 @@ fst_rx_dma_complete(struct fst_card_info *card, struct fst_port_info *port,
dev->stats.rx_dropped++;
}
-/*
- * Receive a frame through the DMA
+/* Receive a frame through the DMA
*/
static inline void
fst_rx_dma(struct fst_card_info *card, dma_addr_t dma, u32 mem, int len)
{
- /*
- * This routine will setup the DMA and start it
+ /* This routine will setup the DMA and start it
*/
dbg(DBG_RX, "In fst_rx_dma %x %x %d\n", (u32)dma, mem, len);
- if (card->dmarx_in_progress) {
+ if (card->dmarx_in_progress)
dbg(DBG_ASS, "In fst_rx_dma while dma in progress\n");
- }
outl(dma, card->pci_conf + DMAPADR0); /* Copy to here */
outl(mem, card->pci_conf + DMALADR0); /* from here */
outl(len, card->pci_conf + DMASIZ0); /* for this length */
outl(0x00000000c, card->pci_conf + DMADPR0); /* In this direction */
- /*
- * We use the dmarx_in_progress flag to flag the channel as busy
+ /* We use the dmarx_in_progress flag to flag the channel as busy
*/
card->dmarx_in_progress = 1;
outb(0x03, card->pci_conf + DMACSR0); /* Start the transfer */
}
-/*
- * Send a frame through the DMA
+/* Send a frame through the DMA
*/
static inline void
fst_tx_dma(struct fst_card_info *card, dma_addr_t dma, u32 mem, int len)
{
- /*
- * This routine will setup the DMA and start it.
+ /* This routine will setup the DMA and start it.
*/
dbg(DBG_TX, "In fst_tx_dma %x %x %d\n", (u32)dma, mem, len);
- if (card->dmatx_in_progress) {
+ if (card->dmatx_in_progress)
dbg(DBG_ASS, "In fst_tx_dma while dma in progress\n");
- }
outl(dma, card->pci_conf + DMAPADR1); /* Copy from here */
outl(mem, card->pci_conf + DMALADR1); /* to here */
outl(len, card->pci_conf + DMASIZ1); /* for this length */
outl(0x000000004, card->pci_conf + DMADPR1); /* In this direction */
- /*
- * We use the dmatx_in_progress to flag the channel as busy
+ /* We use the dmatx_in_progress to flag the channel as busy
*/
card->dmatx_in_progress = 1;
outb(0x03, card->pci_conf + DMACSR1); /* Start the transfer */
@@ -958,12 +928,11 @@ fst_issue_cmd(struct fst_port_info *port, unsigned short cmd)
mbval = FST_RDW(card, portMailbox[port->index][0]);
}
- if (safety > 0) {
+ if (safety > 0)
dbg(DBG_CMD, "Mailbox clear after %d jiffies\n", safety);
- }
- if (mbval == NAK) {
+
+ if (mbval == NAK)
dbg(DBG_CMD, "issue_cmd: previous command was NAK'd\n");
- }
FST_WRW(card, portMailbox[port->index][0], cmd);
@@ -998,8 +967,7 @@ fst_op_lower(struct fst_port_info *port, unsigned int outputs)
fst_issue_cmd(port, SETV24O);
}
-/*
- * Setup port Rx buffers
+/* Setup port Rx buffers
*/
static void
fst_rx_config(struct fst_port_info *port)
@@ -1016,8 +984,8 @@ fst_rx_config(struct fst_port_info *port)
for (i = 0; i < NUM_RX_BUFFER; i++) {
offset = BUF_OFFSET(rxBuffer[pi][i][0]);
- FST_WRW(card, rxDescrRing[pi][i].ladr, (u16) offset);
- FST_WRB(card, rxDescrRing[pi][i].hadr, (u8) (offset >> 16));
+ FST_WRW(card, rxDescrRing[pi][i].ladr, (u16)offset);
+ FST_WRB(card, rxDescrRing[pi][i].hadr, (u8)(offset >> 16));
FST_WRW(card, rxDescrRing[pi][i].bcnt, cnv_bcnt(LEN_RX_BUFFER));
FST_WRW(card, rxDescrRing[pi][i].mcnt, LEN_RX_BUFFER);
FST_WRB(card, rxDescrRing[pi][i].bits, DMA_OWN);
@@ -1026,8 +994,7 @@ fst_rx_config(struct fst_port_info *port)
spin_unlock_irqrestore(&card->card_lock, flags);
}
-/*
- * Setup port Tx buffers
+/* Setup port Tx buffers
*/
static void
fst_tx_config(struct fst_port_info *port)
@@ -1044,8 +1011,8 @@ fst_tx_config(struct fst_port_info *port)
for (i = 0; i < NUM_TX_BUFFER; i++) {
offset = BUF_OFFSET(txBuffer[pi][i][0]);
- FST_WRW(card, txDescrRing[pi][i].ladr, (u16) offset);
- FST_WRB(card, txDescrRing[pi][i].hadr, (u8) (offset >> 16));
+ FST_WRW(card, txDescrRing[pi][i].ladr, (u16)offset);
+ FST_WRB(card, txDescrRing[pi][i].hadr, (u8)(offset >> 16));
FST_WRW(card, txDescrRing[pi][i].bcnt, 0);
FST_WRB(card, txDescrRing[pi][i].bits, 0);
}
@@ -1069,16 +1036,14 @@ fst_intr_te1_alarm(struct fst_card_info *card, struct fst_port_info *port)
ais = FST_RDB(card, suStatus.alarmIndicationSignal);
if (los) {
- /*
- * Lost the link
+ /* Lost the link
*/
if (netif_carrier_ok(port_to_dev(port))) {
dbg(DBG_INTR, "Net carrier off\n");
netif_carrier_off(port_to_dev(port));
}
} else {
- /*
- * Link available
+ /* Link available
*/
if (!netif_carrier_ok(port_to_dev(port))) {
dbg(DBG_INTR, "Net carrier on\n");
@@ -1110,7 +1075,7 @@ fst_intr_ctlchg(struct fst_card_info *card, struct fst_port_info *port)
signals = FST_RDL(card, v24DebouncedSts[port->index]);
- if (signals & (((port->hwif == X21) || (port->hwif == X21D))
+ if (signals & ((port->hwif == X21 || port->hwif == X21D)
? IPSTS_INDICATE : IPSTS_DCD)) {
if (!netif_carrier_ok(port_to_dev(port))) {
dbg(DBG_INTR, "DCD active\n");
@@ -1132,8 +1097,7 @@ fst_log_rx_error(struct fst_card_info *card, struct fst_port_info *port,
{
struct net_device *dev = port_to_dev(port);
- /*
- * Increment the appropriate error counter
+ /* Increment the appropriate error counter
*/
dev->stats.rx_errors++;
if (dmabits & RX_OFLO) {
@@ -1168,15 +1132,14 @@ fst_recover_rx_error(struct fst_card_info *card, struct fst_port_info *port,
int pi;
pi = port->index;
- /*
- * Discard buffer descriptors until we see the start of the
+ /* Discard buffer descriptors until we see the start of the
* next frame. Note that for long frames this could be in
- * a subsequent interrupt.
+ * a subsequent interrupt.
*/
i = 0;
while ((dmabits & (DMA_OWN | RX_STP)) == 0) {
FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN);
- rxp = (rxp+1) % NUM_RX_BUFFER;
+ rxp = (rxp + 1) % NUM_RX_BUFFER;
if (++i > NUM_RX_BUFFER) {
dbg(DBG_ASS, "intr_rx: Discarding more bufs"
" than we have\n");
@@ -1190,11 +1153,9 @@ fst_recover_rx_error(struct fst_card_info *card, struct fst_port_info *port,
/* Discard the terminal buffer */
if (!(dmabits & DMA_OWN)) {
FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN);
- rxp = (rxp+1) % NUM_RX_BUFFER;
+ rxp = (rxp + 1) % NUM_RX_BUFFER;
}
port->rxpos = rxp;
- return;
-
}
/* Rx complete interrupt
@@ -1219,17 +1180,15 @@ fst_intr_rx(struct fst_card_info *card, struct fst_port_info *port)
pi, rxp);
return;
}
- if (card->dmarx_in_progress) {
+ if (card->dmarx_in_progress)
return;
- }
/* Get buffer length */
len = FST_RDW(card, rxDescrRing[pi][rxp].mcnt);
/* Discard the CRC */
len -= 2;
if (len == 0) {
- /*
- * This seems to happen on the TE1 interface sometimes
+ /* This seems to happen on the TE1 interface sometimes
* so throw the frame away and log the event.
*/
pr_err("Frame received with 0 length. Card %d Port %d\n",
@@ -1237,7 +1196,7 @@ fst_intr_rx(struct fst_card_info *card, struct fst_port_info *port)
/* Return descriptor to card */
FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN);
- rxp = (rxp+1) % NUM_RX_BUFFER;
+ rxp = (rxp + 1) % NUM_RX_BUFFER;
port->rxpos = rxp;
return;
}
@@ -1254,7 +1213,8 @@ fst_intr_rx(struct fst_card_info *card, struct fst_port_info *port)
}
/* Allocate SKB */
- if ((skb = dev_alloc_skb(len)) == NULL) {
+ skb = dev_alloc_skb(len);
+ if (!skb) {
dbg(DBG_RX, "intr_rx: can't allocate buffer\n");
dev->stats.rx_dropped++;
@@ -1262,18 +1222,17 @@ fst_intr_rx(struct fst_card_info *card, struct fst_port_info *port)
/* Return descriptor to card */
FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN);
- rxp = (rxp+1) % NUM_RX_BUFFER;
+ rxp = (rxp + 1) % NUM_RX_BUFFER;
port->rxpos = rxp;
return;
}
- /*
- * We know the length we need to receive, len.
+ /* We know the length we need to receive, len.
* It's not worth using the DMA for reads of less than
* FST_MIN_DMA_LEN
*/
- if ((len < FST_MIN_DMA_LEN) || (card->family == FST_FAMILY_TXP)) {
+ if (len < FST_MIN_DMA_LEN || card->family == FST_FAMILY_TXP) {
memcpy_fromio(skb_put(skb, len),
card->mem + BUF_OFFSET(rxBuffer[pi][rxp][0]),
len);
@@ -1307,12 +1266,11 @@ fst_intr_rx(struct fst_card_info *card, struct fst_port_info *port)
dbg(DBG_ASS, "About to increment rxpos by more than 1\n");
dbg(DBG_ASS, "rxp = %d rxpos = %d\n", rxp, port->rxpos);
}
- rxp = (rxp+1) % NUM_RX_BUFFER;
+ rxp = (rxp + 1) % NUM_RX_BUFFER;
port->rxpos = rxp;
}
-/*
- * The bottom halfs to the ISR
+/* The bottom half to the ISR
*
*/
@@ -1326,8 +1284,7 @@ do_bottom_half_tx(struct fst_card_info *card)
unsigned long flags;
struct net_device *dev;
- /*
- * Find a free buffer for the transmit
+ /* Find a free buffer for the transmit
* Step through each port on this card
*/
@@ -1340,39 +1297,36 @@ do_bottom_half_tx(struct fst_card_info *card)
while (!(FST_RDB(card, txDescrRing[pi][port->txpos].bits) &
DMA_OWN) &&
!(card->dmatx_in_progress)) {
- /*
- * There doesn't seem to be a txdone event per-se
+ /* There doesn't seem to be a txdone event per-se
* We seem to have to deduce it, by checking the DMA_OWN
* bit on the next buffer we think we can use
*/
spin_lock_irqsave(&card->card_lock, flags);
- if ((txq_length = port->txqe - port->txqs) < 0) {
- /*
- * This is the case where one has wrapped and the
+ txq_length = port->txqe - port->txqs;
+ if (txq_length < 0) {
+ /* This is the case where one has wrapped and the
* maths gives us a negative number
*/
txq_length = txq_length + FST_TXQ_DEPTH;
}
spin_unlock_irqrestore(&card->card_lock, flags);
if (txq_length > 0) {
- /*
- * There is something to send
+ /* There is something to send
*/
spin_lock_irqsave(&card->card_lock, flags);
skb = port->txq[port->txqs];
port->txqs++;
- if (port->txqs == FST_TXQ_DEPTH) {
+ if (port->txqs == FST_TXQ_DEPTH)
port->txqs = 0;
- }
+
spin_unlock_irqrestore(&card->card_lock, flags);
- /*
- * copy the data and set the required indicators on the
+ /* copy the data and set the required indicators on the
* card.
*/
FST_WRW(card, txDescrRing[pi][port->txpos].bcnt,
cnv_bcnt(skb->len));
- if ((skb->len < FST_MIN_DMA_LEN) ||
- (card->family == FST_FAMILY_TXP)) {
+ if (skb->len < FST_MIN_DMA_LEN ||
+ card->family == FST_FAMILY_TXP) {
/* Enqueue the packet with normal io */
memcpy_toio(card->mem +
BUF_OFFSET(txBuffer[pi]
@@ -1401,8 +1355,7 @@ do_bottom_half_tx(struct fst_card_info *card)
}
if (++port->txpos >= NUM_TX_BUFFER)
port->txpos = 0;
- /*
- * If we have flow control on, can we now release it?
+ /* If we have flow control on, can we now release it?
*/
if (port->start) {
if (txq_length < fst_txq_low) {
@@ -1413,8 +1366,7 @@ do_bottom_half_tx(struct fst_card_info *card)
}
dev_kfree_skb(skb);
} else {
- /*
- * Nothing to send so break out of the while loop
+ /* Nothing to send so break out of the while loop
*/
break;
}
@@ -1438,8 +1390,7 @@ do_bottom_half_rx(struct fst_card_info *card)
while (!(FST_RDB(card, rxDescrRing[pi][port->rxpos].bits)
& DMA_OWN) && !(card->dmarx_in_progress)) {
if (rx_count > fst_max_reads) {
- /*
- * Don't spend forever in receive processing
+ /* Don't spend forever in receive processing
* Schedule another event
*/
fst_q_work_item(&fst_work_intq, card->card_no);
@@ -1452,8 +1403,7 @@ do_bottom_half_rx(struct fst_card_info *card)
}
}
-/*
- * The interrupt service routine
+/* The interrupt service routine
* Dev_id is our fst_card_info pointer
*/
static irqreturn_t
@@ -1468,8 +1418,7 @@ fst_intr(int dummy, void *dev_id)
unsigned int do_card_interrupt;
unsigned int int_retry_count;
- /*
- * Check to see if the interrupt was for this card
+ /* Check to see if the interrupt was for this card
* return if not
* Note that the call to clear the interrupt is important
*/
@@ -1478,10 +1427,9 @@ fst_intr(int dummy, void *dev_id)
pr_err("Interrupt received for card %d in a non running state (%d)\n",
card->card_no, card->state);
- /*
- * It is possible to really be running, i.e. we have re-loaded
+ /* It is possible to really be running, i.e. we have re-loaded
* a running card
- * Clear and reprime the interrupt source
+ * Clear and reprime the interrupt source
*/
fst_clear_intr(card);
return IRQ_HANDLED;
@@ -1490,8 +1438,7 @@ fst_intr(int dummy, void *dev_id)
/* Clear and reprime the interrupt source */
fst_clear_intr(card);
- /*
- * Is the interrupt for this card (handshake == 1)
+ /* Is the interrupt for this card (handshake == 1)
*/
do_card_interrupt = 0;
if (FST_RDB(card, interruptHandshake) == 1) {
@@ -1500,13 +1447,11 @@ fst_intr(int dummy, void *dev_id)
FST_WRB(card, interruptHandshake, 0xEE);
}
if (card->family == FST_FAMILY_TXU) {
- /*
- * Is it a DMA Interrupt
+ /* Is it a DMA Interrupt
*/
dma_intcsr = inl(card->pci_conf + INTCSR_9054);
if (dma_intcsr & 0x00200000) {
- /*
- * DMA Channel 0 (Rx transfer complete)
+ /* DMA Channel 0 (Rx transfer complete)
*/
dbg(DBG_RX, "DMA Rx xfer complete\n");
outb(0x8, card->pci_conf + DMACSR0);
@@ -1517,8 +1462,7 @@ fst_intr(int dummy, void *dev_id)
do_card_interrupt += FST_RX_DMA_INT;
}
if (dma_intcsr & 0x00400000) {
- /*
- * DMA Channel 1 (Tx transfer complete)
+ /* DMA Channel 1 (Tx transfer complete)
*/
dbg(DBG_TX, "DMA Tx xfer complete\n");
outb(0x8, card->pci_conf + DMACSR1);
@@ -1529,8 +1473,7 @@ fst_intr(int dummy, void *dev_id)
}
}
- /*
- * Have we been missing Interrupts
+ /* Have we been missing Interrupts
*/
int_retry_count = FST_RDL(card, interruptRetryCount);
if (int_retry_count) {
@@ -1539,9 +1482,8 @@ fst_intr(int dummy, void *dev_id)
FST_WRL(card, interruptRetryCount, 0);
}
- if (!do_card_interrupt) {
+ if (!do_card_interrupt)
return IRQ_HANDLED;
- }
/* Scehdule the bottom half of the ISR */
fst_q_work_item(&fst_work_intq, card->card_no);
@@ -1611,7 +1553,7 @@ fst_intr(int dummy, void *dev_id)
rdidx = 0;
}
FST_WRB(card, interruptEvent.rdindex, rdidx);
- return IRQ_HANDLED;
+ return IRQ_HANDLED;
}
/* Check that the shared memory configuration is one that we can handle
@@ -1635,7 +1577,8 @@ check_started_ok(struct fst_card_info *card)
return;
}
/* Firmware status flag, 0x00 = initialising, 0x01 = OK, 0xFF = fail */
- if ((i = FST_RDB(card, taskStatus)) == 0x01) {
+ i = FST_RDB(card, taskStatus);
+ if (i == 0x01) {
card->state = FST_RUNNING;
} else if (i == 0xFF) {
pr_err("Firmware initialisation failed. Card halted\n");
@@ -1665,8 +1608,8 @@ set_conf_from_info(struct fst_card_info *card, struct fst_port_info *port,
int err;
unsigned char my_framing;
- /* Set things according to the user set valid flags
- * Several of the old options have been invalidated/replaced by the
+ /* Set things according to the user set valid flags
+ * Several of the old options have been invalidated/replaced by the
* generic hdlc package.
*/
err = 0;
@@ -1740,9 +1683,8 @@ set_conf_from_info(struct fst_card_info *card, struct fst_port_info *port,
#endif
}
#if FST_DEBUG
- if (info->valid & FSTVAL_DEBUG) {
+ if (info->valid & FSTVAL_DEBUG)
fst_debug_mask = info->debug;
- }
#endif
return err;
@@ -1754,7 +1696,7 @@ gather_conf_info(struct fst_card_info *card, struct fst_port_info *port,
{
int i;
- memset(info, 0, sizeof (struct fstioc_info));
+ memset(info, 0, sizeof(struct fstioc_info));
i = port->index;
info->kernelVersion = LINUX_VERSION_CODE;
@@ -1787,27 +1729,23 @@ gather_conf_info(struct fst_card_info *card, struct fst_port_info *port,
info->cardMode = FST_RDW(card, cardMode);
info->smcFirmwareVersion = FST_RDL(card, smcFirmwareVersion);
- /*
- * The T2U can report cable presence for both A or B
- * in bits 0 and 1 of cableStatus. See which port we are and
+ /* The T2U can report cable presence for both A or B
+ * in bits 0 and 1 of cableStatus. See which port we are and
* do the mapping.
*/
if (card->family == FST_FAMILY_TXU) {
if (port->index == 0) {
- /*
- * Port A
+ /* Port A
*/
info->cableStatus = info->cableStatus & 1;
} else {
- /*
- * Port B
+ /* Port B
*/
info->cableStatus = info->cableStatus >> 1;
info->cableStatus = info->cableStatus & 1;
}
}
- /*
- * Some additional bits if we are TE1
+ /* Some additional bits if we are TE1
*/
if (card->type == FST_TYPE_TE1) {
info->lineSpeed = FST_RDL(card, suConfig.dataRate);
@@ -1851,14 +1789,12 @@ fst_set_iface(struct fst_card_info *card, struct fst_port_info *port,
sync_serial_settings sync;
int i;
- if (ifr->ifr_settings.size != sizeof (sync)) {
+ if (ifr->ifr_settings.size != sizeof(sync))
return -ENOMEM;
- }
if (copy_from_user
- (&sync, ifr->ifr_settings.ifs_ifsu.sync, sizeof (sync))) {
+ (&sync, ifr->ifr_settings.ifs_ifsu.sync, sizeof(sync)))
return -EFAULT;
- }
if (sync.loopback)
return -EINVAL;
@@ -1951,12 +1887,11 @@ fst_get_iface(struct fst_card_info *card, struct fst_port_info *port,
ifr->ifr_settings.type = IF_IFACE_X21;
break;
}
- if (ifr->ifr_settings.size == 0) {
+ if (ifr->ifr_settings.size == 0)
return 0; /* only type requested */
- }
- if (ifr->ifr_settings.size < sizeof (sync)) {
+
+ if (ifr->ifr_settings.size < sizeof(sync))
return -ENOMEM;
- }
i = port->index;
memset(&sync, 0, sizeof(sync));
@@ -1966,11 +1901,10 @@ fst_get_iface(struct fst_card_info *card, struct fst_port_info *port,
INTCLK ? CLOCK_INT : CLOCK_EXT;
sync.loopback = 0;
- if (copy_to_user(ifr->ifr_settings.ifs_ifsu.sync, &sync, sizeof (sync))) {
+ if (copy_to_user(ifr->ifr_settings.ifs_ifsu.sync, &sync, sizeof(sync)))
return -EFAULT;
- }
- ifr->ifr_settings.size = sizeof (sync);
+ ifr->ifr_settings.size = sizeof(sync);
return 0;
}
@@ -2008,21 +1942,19 @@ fst_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
/* First copy in the header with the length and offset of data
* to write
*/
- if (ifr->ifr_data == NULL) {
+ if (!ifr->ifr_data)
return -EINVAL;
- }
+
if (copy_from_user(&wrthdr, ifr->ifr_data,
- sizeof (struct fstioc_write))) {
+ sizeof(struct fstioc_write)))
return -EFAULT;
- }
/* Sanity check the parameters. We don't support partial writes
* when going over the top
*/
if (wrthdr.size > FST_MEMSIZE || wrthdr.offset > FST_MEMSIZE ||
- wrthdr.size + wrthdr.offset > FST_MEMSIZE) {
+ wrthdr.size + wrthdr.offset > FST_MEMSIZE)
return -ENXIO;
- }
/* Now copy the data to the card. */
@@ -2037,9 +1969,9 @@ fst_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
/* Writes to the memory of a card in the reset state constitute
* a download
*/
- if (card->state == FST_RESET) {
+ if (card->state == FST_RESET)
card->state = FST_DOWNLOAD;
- }
+
return 0;
case FSTGETCONF:
@@ -2059,21 +1991,18 @@ fst_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
}
- if (ifr->ifr_data == NULL) {
+ if (!ifr->ifr_data)
return -EINVAL;
- }
gather_conf_info(card, port, &info);
- if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) {
+ if (copy_to_user(ifr->ifr_data, &info, sizeof(info)))
return -EFAULT;
- }
+
return 0;
case FSTSETCONF:
-
- /*
- * Most of the settings have been moved to the generic ioctls
+ /* Most of the settings have been moved to the generic ioctls
* this just covers debug and board ident now
*/
@@ -2082,9 +2011,8 @@ fst_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
card->card_no, card->state);
return -EIO;
}
- if (copy_from_user(&info, ifr->ifr_data, sizeof (info))) {
+ if (copy_from_user(&info, ifr->ifr_data, sizeof(info)))
return -EFAULT;
- }
return set_conf_from_info(card, port, &info);
@@ -2150,7 +2078,7 @@ fst_openport(struct fst_port_info *port)
port->run = 1;
signals = FST_RDL(port->card, v24DebouncedSts[port->index]);
- if (signals & (((port->hwif == X21) || (port->hwif == X21D))
+ if (signals & ((port->hwif == X21 || port->hwif == X21D)
? IPSTS_INDICATE : IPSTS_DCD))
netif_carrier_on(port_to_dev(port));
else
@@ -2159,7 +2087,6 @@ fst_openport(struct fst_port_info *port)
port->txqe = 0;
port->txqs = 0;
}
-
}
static void
@@ -2185,7 +2112,7 @@ fst_open(struct net_device *dev)
port = dev_to_port(dev);
if (!try_module_get(THIS_MODULE))
- return -EBUSY;
+ return -EBUSY;
if (port->mode != FST_RAW) {
err = hdlc_open(dev);
@@ -2220,9 +2147,9 @@ fst_close(struct net_device *dev)
netif_stop_queue(dev);
fst_closeport(dev_to_port(dev));
- if (port->mode != FST_RAW) {
+ if (port->mode != FST_RAW)
hdlc_close(dev);
- }
+
module_put(THIS_MODULE);
return 0;
}
@@ -2230,8 +2157,7 @@ fst_close(struct net_device *dev)
static int
fst_attach(struct net_device *dev, unsigned short encoding, unsigned short parity)
{
- /*
- * Setting currently fixed in FarSync card so we check and forget
+ /* Setting currently fixed in FarSync card so we check and forget
*/
if (encoding != ENCODING_NRZ || parity != PARITY_CRC16_PR1_CCITT)
return -EINVAL;
@@ -2289,23 +2215,21 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
- /*
- * We are always going to queue the packet
+ /* We are always going to queue the packet
* so that the bottom half is the only place we tx from
* Check there is room in the port txq
*/
spin_lock_irqsave(&card->card_lock, flags);
- if ((txq_length = port->txqe - port->txqs) < 0) {
- /*
- * This is the case where the next free has wrapped but the
+ txq_length = port->txqe - port->txqs;
+ if (txq_length < 0) {
+ /* This is the case where the next free has wrapped but the
* last used hasn't
*/
txq_length = txq_length + FST_TXQ_DEPTH;
}
spin_unlock_irqrestore(&card->card_lock, flags);
if (txq_length > fst_txq_high) {
- /*
- * We have got enough buffers in the pipeline. Ask the network
+ /* We have got enough buffers in the pipeline. Ask the network
* layer to stop sending frames down
*/
netif_stop_queue(dev);
@@ -2313,8 +2237,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (txq_length == FST_TXQ_DEPTH - 1) {
- /*
- * This shouldn't have happened but such is life
+ /* This shouldn't have happened but such is life
*/
dev_kfree_skb(skb);
dev->stats.tx_errors++;
@@ -2323,8 +2246,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
- /*
- * queue the buffer
+ /* queue the buffer
*/
spin_lock_irqsave(&card->card_lock, flags);
port->txq[port->txqe] = skb;
@@ -2340,8 +2262,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
-/*
- * Card setup having checked hardware resources.
+/* Card setup having checked hardware resources.
* Should be pretty bizarre if we get an error here (kernel memory
* exhaustion is one possibility). If we do see a problem we report it
* via a printk and leave the corresponding interface and all that follow
@@ -2371,7 +2292,7 @@ fst_init_card(struct fst_card_info *card)
err = register_hdlc_device(card->ports[i].dev);
if (err < 0) {
pr_err("Cannot register HDLC device for port %d (errno %d)\n",
- i, -err);
+ i, -err);
while (i--)
unregister_hdlc_device(card->ports[i].dev);
return err;
@@ -2393,14 +2314,13 @@ static const struct net_device_ops fst_ops = {
.ndo_tx_timeout = fst_tx_timeout,
};
-/*
- * Initialise card when detected.
+/* Initialise card when detected.
* Returns 0 to indicate success, or errno otherwise.
*/
static int
fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int no_of_cards_added = 0;
+ static int no_of_cards_added;
struct fst_card_info *card;
int err = 0;
int i;
@@ -2411,17 +2331,15 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#if FST_DEBUG
dbg(DBG_ASS, "The value of debug mask is %x\n", fst_debug_mask);
#endif
- /*
- * We are going to be clever and allow certain cards not to be
+ /* We are going to be clever and allow certain cards not to be
* configured. An exclude list can be provided in /etc/modules.conf
*/
if (fst_excluded_cards != 0) {
- /*
- * There are cards to exclude
+ /* There are cards to exclude
*
*/
for (i = 0; i < fst_excluded_cards; i++) {
- if ((pdev->devfn) >> 3 == fst_excluded_list[i]) {
+ if (pdev->devfn >> 3 == fst_excluded_list[i]) {
pr_info("FarSync PCI device %d not assigned\n",
(pdev->devfn) >> 3);
return -EBUSY;
@@ -2431,16 +2349,18 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Allocate driver private data */
card = kzalloc(sizeof(struct fst_card_info), GFP_KERNEL);
- if (card == NULL)
+ if (!card)
return -ENOMEM;
/* Try to enable the device */
- if ((err = pci_enable_device(pdev)) != 0) {
+ err = pci_enable_device(pdev);
+ if (err) {
pr_err("Failed to enable card. Err %d\n", -err);
goto enable_fail;
}
- if ((err = pci_request_regions(pdev, "FarSync")) !=0) {
+ err = pci_request_regions(pdev, "FarSync");
+ if (err) {
pr_err("Failed to allocate regions. Err %d\n", -err);
goto regions_fail;
}
@@ -2449,12 +2369,14 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
card->pci_conf = pci_resource_start(pdev, 1);
card->phys_mem = pci_resource_start(pdev, 2);
card->phys_ctlmem = pci_resource_start(pdev, 3);
- if ((card->mem = ioremap(card->phys_mem, FST_MEMSIZE)) == NULL) {
+ card->mem = ioremap(card->phys_mem, FST_MEMSIZE);
+ if (!card->mem) {
pr_err("Physical memory remap failed\n");
err = -ENODEV;
goto ioremap_physmem_fail;
}
- if ((card->ctlmem = ioremap(card->phys_ctlmem, 0x10)) == NULL) {
+ card->ctlmem = ioremap(card->phys_ctlmem, 0x10);
+ if (!card->ctlmem) {
pr_err("Control memory remap failed\n");
err = -ENODEV;
goto ioremap_ctlmem_fail;
@@ -2474,19 +2396,20 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
card->family = ((ent->driver_data == FST_TYPE_T2P) ||
(ent->driver_data == FST_TYPE_T4P))
? FST_FAMILY_TXP : FST_FAMILY_TXU;
- if ((ent->driver_data == FST_TYPE_T1U) ||
- (ent->driver_data == FST_TYPE_TE1))
+ if (ent->driver_data == FST_TYPE_T1U ||
+ ent->driver_data == FST_TYPE_TE1)
card->nports = 1;
else
card->nports = ((ent->driver_data == FST_TYPE_T2P) ||
(ent->driver_data == FST_TYPE_T2U)) ? 2 : 4;
card->state = FST_UNINIT;
- spin_lock_init ( &card->card_lock );
+ spin_lock_init(&card->card_lock);
- for ( i = 0 ; i < card->nports ; i++ ) {
+ for (i = 0; i < card->nports; i++) {
struct net_device *dev = alloc_hdlcdev(&card->ports[i]);
hdlc_device *hdlc;
+
if (!dev) {
while (i--)
free_netdev(card->ports[i].dev);
@@ -2495,29 +2418,29 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto hdlcdev_fail;
}
card->ports[i].dev = dev;
- card->ports[i].card = card;
- card->ports[i].index = i;
- card->ports[i].run = 0;
+ card->ports[i].card = card;
+ card->ports[i].index = i;
+ card->ports[i].run = 0;
hdlc = dev_to_hdlc(dev);
- /* Fill in the net device info */
+ /* Fill in the net device info */
/* Since this is a PCI setup this is purely
* informational. Give them the buffer addresses
* and basic card I/O.
*/
- dev->mem_start = card->phys_mem
- + BUF_OFFSET ( txBuffer[i][0][0]);
- dev->mem_end = card->phys_mem
- + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER - 1][LEN_RX_BUFFER - 1]);
- dev->base_addr = card->pci_conf;
- dev->irq = card->irq;
+ dev->mem_start = card->phys_mem
+ + BUF_OFFSET(txBuffer[i][0][0]);
+ dev->mem_end = card->phys_mem
+ + BUF_OFFSET(txBuffer[i][NUM_TX_BUFFER - 1][LEN_RX_BUFFER - 1]);
+ dev->base_addr = card->pci_conf;
+ dev->irq = card->irq;
dev->netdev_ops = &fst_ops;
dev->tx_queue_len = FST_TX_QUEUE_LEN;
dev->watchdog_timeo = FST_TX_TIMEOUT;
- hdlc->attach = fst_attach;
- hdlc->xmit = fst_start_xmit;
+ hdlc->attach = fst_attach;
+ hdlc->xmit = fst_start_xmit;
}
card->device = pdev;
@@ -2549,13 +2472,12 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto init_card_fail;
if (card->family == FST_FAMILY_TXU) {
- /*
- * Allocate a dma buffer for transmit and receives
+ /* Allocate a dma buffer for transmit and receives
*/
card->rx_dma_handle_host =
dma_alloc_coherent(&card->device->dev, FST_MAX_MTU,
&card->rx_dma_handle_card, GFP_KERNEL);
- if (card->rx_dma_handle_host == NULL) {
+ if (!card->rx_dma_handle_host) {
pr_err("Could not allocate rx dma buffer\n");
err = -ENOMEM;
goto rx_dma_fail;
@@ -2563,7 +2485,7 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
card->tx_dma_handle_host =
dma_alloc_coherent(&card->device->dev, FST_MAX_MTU,
&card->tx_dma_handle_card, GFP_KERNEL);
- if (card->tx_dma_handle_host == NULL) {
+ if (!card->tx_dma_handle_host) {
pr_err("Could not allocate tx dma buffer\n");
err = -ENOMEM;
goto tx_dma_fail;
@@ -2598,8 +2520,7 @@ enable_fail:
return err;
}
-/*
- * Cleanup and close down a card
+/* Cleanup and close down a card
*/
static void
fst_remove_one(struct pci_dev *pdev)
@@ -2611,6 +2532,7 @@ fst_remove_one(struct pci_dev *pdev)
for (i = 0; i < card->nports; i++) {
struct net_device *dev = port_to_dev(&card->ports[i]);
+
unregister_hdlc_device(dev);
}
@@ -2621,8 +2543,7 @@ fst_remove_one(struct pci_dev *pdev)
iounmap(card->mem);
pci_release_regions(pdev);
if (card->family == FST_FAMILY_TXU) {
- /*
- * Free dma buffers
+ /* Free dma buffers
*/
dma_free_coherent(&card->device->dev, FST_MAX_MTU,
card->rx_dma_handle_host,
diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c
index 7eac6a3e1cde..39f05fabbfa4 100644
--- a/drivers/net/wan/fsl_ucc_hdlc.c
+++ b/drivers/net/wan/fsl_ucc_hdlc.c
@@ -1171,9 +1171,8 @@ static int ucc_hdlc_probe(struct platform_device *pdev)
ut_info->uf_info.irq = irq_of_parse_and_map(np, 0);
uhdlc_priv = kzalloc(sizeof(*uhdlc_priv), GFP_KERNEL);
- if (!uhdlc_priv) {
+ if (!uhdlc_priv)
return -ENOMEM;
- }
dev_set_drvdata(&pdev->dev, uhdlc_priv);
uhdlc_priv->dev = &pdev->dev;
diff --git a/drivers/net/wan/hd64570.c b/drivers/net/wan/hd64570.c
index 058e48182838..0d19e39fec86 100644
--- a/drivers/net/wan/hd64570.c
+++ b/drivers/net/wan/hd64570.c
@@ -47,7 +47,6 @@
#define SCA_INTR_DMAC_RX(node) (node ? 0x20 : 0x02)
#define SCA_INTR_DMAC_TX(node) (node ? 0x40 : 0x04)
-
static inline struct net_device *port_to_dev(port_t *port)
{
return port->dev;
@@ -59,12 +58,18 @@ static inline int sca_intr_status(card_t *card)
u8 isr0 = sca_in(ISR0, card);
u8 isr1 = sca_in(ISR1, card);
- if (isr1 & 0x03) result |= SCA_INTR_DMAC_RX(0);
- if (isr1 & 0x0C) result |= SCA_INTR_DMAC_TX(0);
- if (isr1 & 0x30) result |= SCA_INTR_DMAC_RX(1);
- if (isr1 & 0xC0) result |= SCA_INTR_DMAC_TX(1);
- if (isr0 & 0x0F) result |= SCA_INTR_MSCI(0);
- if (isr0 & 0xF0) result |= SCA_INTR_MSCI(1);
+ if (isr1 & 0x03)
+ result |= SCA_INTR_DMAC_RX(0);
+ if (isr1 & 0x0C)
+ result |= SCA_INTR_DMAC_TX(0);
+ if (isr1 & 0x30)
+ result |= SCA_INTR_DMAC_RX(1);
+ if (isr1 & 0xC0)
+ result |= SCA_INTR_DMAC_TX(1);
+ if (isr0 & 0x0F)
+ result |= SCA_INTR_MSCI(0);
+ if (isr0 & 0xF0)
+ result |= SCA_INTR_MSCI(1);
if (!(result & SCA_INTR_DMAC_TX(0)))
if (sca_in(DSR_TX(0), card) & DSR_EOM)
@@ -76,7 +81,7 @@ static inline int sca_intr_status(card_t *card)
return result;
}
-static inline port_t* dev_to_port(struct net_device *dev)
+static inline port_t *dev_to_port(struct net_device *dev)
{
return dev_to_hdlc(dev)->priv;
}
@@ -87,7 +92,6 @@ static inline u16 next_desc(port_t *port, u16 desc, int transmit)
: port_to_card(port)->rx_ring_buffers);
}
-
static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit)
{
u16 rx_buffs = port_to_card(port)->rx_ring_buffers;
@@ -98,14 +102,12 @@ static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit)
transmit * rx_buffs + desc;
}
-
static inline u16 desc_offset(port_t *port, u16 desc, int transmit)
{
/* Descriptor offset always fits in 16 bits */
return desc_abs_number(port, desc, transmit) * sizeof(pkt_desc);
}
-
static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc,
int transmit)
{
@@ -118,14 +120,12 @@ static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc,
#endif
}
-
static inline u32 buffer_offset(port_t *port, u16 desc, int transmit)
{
return port_to_card(port)->buff_offset +
desc_abs_number(port, desc, transmit) * (u32)HDLC_MAX_MRU;
}
-
static inline void sca_set_carrier(port_t *port)
{
if (!(sca_in(get_msci(port) + ST3, port_to_card(port)) & ST3_DCD)) {
@@ -143,7 +143,6 @@ static inline void sca_set_carrier(port_t *port)
}
}
-
static void sca_init_port(port_t *port)
{
card_t *card = port_to_card(port);
@@ -213,13 +212,12 @@ static void sca_init_port(port_t *port)
sca_set_carrier(port);
}
-
#ifdef NEED_SCA_MSCI_INTR
/* MSCI interrupt service */
static inline void sca_msci_intr(port_t *port)
{
u16 msci = get_msci(port);
- card_t* card = port_to_card(port);
+ card_t *card = port_to_card(port);
u8 stat = sca_in(msci + ST1, card); /* read MSCI ST1 status */
/* Reset MSCI TX underrun and CDCD status bit */
@@ -236,7 +234,6 @@ static inline void sca_msci_intr(port_t *port)
}
#endif
-
static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc,
u16 rxin)
{
@@ -265,8 +262,9 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc,
memcpy_fromio(skb->data, winbase(card) + buff, maxlen);
openwin(card, page + 1);
memcpy_fromio(skb->data + maxlen, winbase(card), len - maxlen);
- } else
+ } else {
memcpy_fromio(skb->data, winbase(card) + buff, len);
+ }
#ifndef PAGE0_ALWAYS_MAPPED
openwin(card, 0); /* select pkt_desc table page back */
@@ -282,7 +280,6 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc,
netif_rx(skb);
}
-
/* Receive DMA interrupt service */
static inline void sca_rx_intr(port_t *port)
{
@@ -304,7 +301,7 @@ static inline void sca_rx_intr(port_t *port)
pkt_desc __iomem *desc;
u32 cda = sca_inw(dmac + CDAL, card);
- if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc)))
+ if (cda >= desc_off && (cda < desc_off + sizeof(pkt_desc)))
break; /* No frame received */
desc = desc_address(port, port->rxin, 0);
@@ -322,8 +319,9 @@ static inline void sca_rx_intr(port_t *port)
dev->stats.rx_crc_errors++;
if (stat & ST_RX_EOM)
port->rxpart = 0; /* received last fragment */
- } else
+ } else {
sca_rx(card, port, desc, port->rxin);
+ }
/* Set new error descriptor address */
sca_outw(desc_off, dmac + EDAL, card);
@@ -334,13 +332,12 @@ static inline void sca_rx_intr(port_t *port)
sca_out(DSR_DE, DSR_RX(phy_node(port)), card);
}
-
/* Transmit DMA interrupt service */
static inline void sca_tx_intr(port_t *port)
{
struct net_device *dev = port_to_dev(port);
u16 dmac = get_dmac_tx(port);
- card_t* card = port_to_card(port);
+ card_t *card = port_to_card(port);
u8 stat;
spin_lock(&port->lock);
@@ -356,7 +353,8 @@ static inline void sca_tx_intr(port_t *port)
u32 desc_off = desc_offset(port, port->txlast, 1);
u32 cda = sca_inw(dmac + CDAL, card);
- if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc)))
+
+ if (cda >= desc_off && (cda < desc_off + sizeof(pkt_desc)))
break; /* Transmitter is/will_be sending this frame */
desc = desc_address(port, port->txlast, 1);
@@ -370,8 +368,7 @@ static inline void sca_tx_intr(port_t *port)
spin_unlock(&port->lock);
}
-
-static irqreturn_t sca_intr(int irq, void* dev_id)
+static irqreturn_t sca_intr(int irq, void *dev_id)
{
card_t *card = dev_id;
int i;
@@ -379,10 +376,11 @@ static irqreturn_t sca_intr(int irq, void* dev_id)
int handled = 0;
u8 page = sca_get_page(card);
- while((stat = sca_intr_status(card)) != 0) {
+ while ((stat = sca_intr_status(card)) != 0) {
handled = 1;
for (i = 0; i < 2; i++) {
port_t *port = get_port(card, i);
+
if (port) {
if (stat & SCA_INTR_MSCI(i))
sca_msci_intr(port);
@@ -400,15 +398,13 @@ static irqreturn_t sca_intr(int irq, void* dev_id)
return IRQ_RETVAL(handled);
}
-
static void sca_set_port(port_t *port)
{
- card_t* card = port_to_card(port);
+ card_t *card = port_to_card(port);
u16 msci = get_msci(port);
u8 md2 = sca_in(msci + MD2, card);
unsigned int tmc, br = 10, brv = 1024;
-
if (port->settings.clock_rate > 0) {
/* Try lower br for better accuracy*/
do {
@@ -417,14 +413,15 @@ static void sca_set_port(port_t *port)
/* Baud Rate = CLOCK_BASE / TMC / 2^BR */
tmc = CLOCK_BASE / brv / port->settings.clock_rate;
- }while (br > 1 && tmc <= 128);
+ } while (br > 1 && tmc <= 128);
if (tmc < 1) {
tmc = 1;
br = 0; /* For baud=CLOCK_BASE we use tmc=1 br=0 */
brv = 1;
- } else if (tmc > 255)
+ } else if (tmc > 255) {
tmc = 256; /* tmc=0 means 256 - low baud rates */
+ }
port->settings.clock_rate = CLOCK_BASE / brv / tmc;
} else {
@@ -450,34 +447,50 @@ static void sca_set_port(port_t *port)
md2 &= ~MD2_LOOPBACK;
sca_out(md2, msci + MD2, card);
-
}
-
static void sca_open(struct net_device *dev)
{
port_t *port = dev_to_port(dev);
- card_t* card = port_to_card(port);
+ card_t *card = port_to_card(port);
u16 msci = get_msci(port);
u8 md0, md2;
- switch(port->encoding) {
- case ENCODING_NRZ: md2 = MD2_NRZ; break;
- case ENCODING_NRZI: md2 = MD2_NRZI; break;
- case ENCODING_FM_MARK: md2 = MD2_FM_MARK; break;
- case ENCODING_FM_SPACE: md2 = MD2_FM_SPACE; break;
- default: md2 = MD2_MANCHESTER;
+ switch (port->encoding) {
+ case ENCODING_NRZ:
+ md2 = MD2_NRZ;
+ break;
+ case ENCODING_NRZI:
+ md2 = MD2_NRZI;
+ break;
+ case ENCODING_FM_MARK:
+ md2 = MD2_FM_MARK;
+ break;
+ case ENCODING_FM_SPACE:
+ md2 = MD2_FM_SPACE;
+ break;
+ default:
+ md2 = MD2_MANCHESTER;
}
if (port->settings.loopback)
md2 |= MD2_LOOPBACK;
- switch(port->parity) {
- case PARITY_CRC16_PR0: md0 = MD0_HDLC | MD0_CRC_16_0; break;
- case PARITY_CRC16_PR1: md0 = MD0_HDLC | MD0_CRC_16; break;
- case PARITY_CRC16_PR0_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU_0; break;
- case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU; break;
- default: md0 = MD0_HDLC | MD0_CRC_NONE;
+ switch (port->parity) {
+ case PARITY_CRC16_PR0:
+ md0 = MD0_HDLC | MD0_CRC_16_0;
+ break;
+ case PARITY_CRC16_PR1:
+ md0 = MD0_HDLC | MD0_CRC_16;
+ break;
+ case PARITY_CRC16_PR0_CCITT:
+ md0 = MD0_HDLC | MD0_CRC_ITU_0;
+ break;
+ case PARITY_CRC16_PR1_CCITT:
+ md0 = MD0_HDLC | MD0_CRC_ITU;
+ break;
+ default:
+ md0 = MD0_HDLC | MD0_CRC_NONE;
}
sca_out(CMD_RESET, msci + CMD, card);
@@ -494,9 +507,9 @@ static void sca_open(struct net_device *dev)
sca_out(0x14, msci + TRC1, card); /* +1=TXRDY/DMA deactiv condition */
/* We're using the following interrupts:
- - TXINT (DMAC completed all transmisions, underrun or DCD change)
- - all DMA interrupts
-*/
+ * - TXINT (DMAC completed all transmisions, underrun or DCD change)
+ * - all DMA interrupts
+ */
sca_set_carrier(port);
/* MSCI TX INT and RX INT A IRQ enable */
@@ -517,11 +530,10 @@ static void sca_open(struct net_device *dev)
netif_start_queue(dev);
}
-
static void sca_close(struct net_device *dev)
{
port_t *port = dev_to_port(dev);
- card_t* card = port_to_card(port);
+ card_t *card = port_to_card(port);
/* reset channel */
sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port));
@@ -535,7 +547,6 @@ static void sca_close(struct net_device *dev)
netif_stop_queue(dev);
}
-
static int sca_attach(struct net_device *dev, unsigned short encoding,
unsigned short parity)
{
@@ -558,7 +569,6 @@ static int sca_attach(struct net_device *dev, unsigned short encoding,
return 0;
}
-
#ifdef DEBUG_RINGS
static void sca_dump_rings(struct net_device *dev)
{
@@ -613,7 +623,6 @@ static void sca_dump_rings(struct net_device *dev)
}
#endif /* DEBUG_RINGS */
-
static netdev_tx_t sca_xmit(struct sk_buff *skb, struct net_device *dev)
{
port_t *port = dev_to_port(dev);
@@ -645,8 +654,9 @@ static netdev_tx_t sca_xmit(struct sk_buff *skb, struct net_device *dev)
memcpy_toio(winbase(card) + buff, skb->data, maxlen);
openwin(card, page + 1);
memcpy_toio(winbase(card), skb->data + maxlen, len - maxlen);
- } else
+ } else {
memcpy_toio(winbase(card) + buff, skb->data, len);
+ }
#ifndef PAGE0_ALWAYS_MAPPED
openwin(card, 0); /* select pkt_desc table page back */
@@ -670,7 +680,6 @@ static netdev_tx_t sca_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
-
#ifdef NEED_DETECT_RAM
static u32 sca_detect_ram(card_t *card, u8 __iomem *rambase, u32 ramsize)
{
@@ -699,7 +708,6 @@ static u32 sca_detect_ram(card_t *card, u8 __iomem *rambase, u32 ramsize)
}
#endif /* NEED_DETECT_RAM */
-
static void sca_init(card_t *card, int wait_states)
{
sca_out(wait_states, WCRL, card); /* Wait Control */
diff --git a/drivers/net/wan/hd64572.c b/drivers/net/wan/hd64572.c
index 9f60e3969bf8..b89b03a6aba7 100644
--- a/drivers/net/wan/hd64572.c
+++ b/drivers/net/wan/hd64572.c
@@ -41,20 +41,20 @@
#define NAPI_WEIGHT 16
-#define get_msci(port) (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET)
-#define get_dmac_rx(port) (port->chan ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)
-#define get_dmac_tx(port) (port->chan ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)
+#define get_msci(port) ((port)->chan ? MSCI1_OFFSET : MSCI0_OFFSET)
+#define get_dmac_rx(port) ((port)->chan ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)
+#define get_dmac_tx(port) ((port)->chan ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)
-#define sca_in(reg, card) readb(card->scabase + (reg))
-#define sca_out(value, reg, card) writeb(value, card->scabase + (reg))
-#define sca_inw(reg, card) readw(card->scabase + (reg))
-#define sca_outw(value, reg, card) writew(value, card->scabase + (reg))
-#define sca_inl(reg, card) readl(card->scabase + (reg))
-#define sca_outl(value, reg, card) writel(value, card->scabase + (reg))
+#define sca_in(reg, card) readb((card)->scabase + (reg))
+#define sca_out(value, reg, card) writeb(value, (card)->scabase + (reg))
+#define sca_inw(reg, card) readw((card)->scabase + (reg))
+#define sca_outw(value, reg, card) writew(value, (card)->scabase + (reg))
+#define sca_inl(reg, card) readl((card)->scabase + (reg))
+#define sca_outl(value, reg, card) writel(value, (card)->scabase + (reg))
static int sca_poll(struct napi_struct *napi, int budget);
-static inline port_t* dev_to_port(struct net_device *dev)
+static inline port_t *dev_to_port(struct net_device *dev)
{
return dev_to_hdlc(dev)->priv;
}
@@ -81,14 +81,12 @@ static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit)
return port->chan * (rx_buffs + tx_buffs) + transmit * rx_buffs + desc;
}
-
static inline u16 desc_offset(port_t *port, u16 desc, int transmit)
{
/* Descriptor offset always fits in 16 bits */
return desc_abs_number(port, desc, transmit) * sizeof(pkt_desc);
}
-
static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc,
int transmit)
{
@@ -96,14 +94,12 @@ static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc,
desc_offset(port, desc, transmit));
}
-
static inline u32 buffer_offset(port_t *port, u16 desc, int transmit)
{
return port->card->buff_offset +
desc_abs_number(port, desc, transmit) * (u32)HDLC_MAX_MRU;
}
-
static inline void sca_set_carrier(port_t *port)
{
if (!(sca_in(get_msci(port) + ST3, port->card) & ST3_DCD)) {
@@ -121,7 +117,6 @@ static inline void sca_set_carrier(port_t *port)
}
}
-
static void sca_init_port(port_t *port)
{
card_t *card = port->card;
@@ -181,12 +176,11 @@ static void sca_init_port(port_t *port)
netif_napi_add(port->netdev, &port->napi, sca_poll, NAPI_WEIGHT);
}
-
/* MSCI interrupt service */
static inline void sca_msci_intr(port_t *port)
{
u16 msci = get_msci(port);
- card_t* card = port->card;
+ card_t *card = port->card;
if (sca_in(msci + ST1, card) & ST1_CDCD) {
/* Reset MSCI CDCD status bit */
@@ -195,7 +189,6 @@ static inline void sca_msci_intr(port_t *port)
}
}
-
static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc,
u16 rxin)
{
@@ -225,7 +218,6 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc,
netif_receive_skb(skb);
}
-
/* Receive DMA service */
static inline int sca_rx_done(port_t *port, int budget)
{
@@ -281,12 +273,11 @@ static inline int sca_rx_done(port_t *port, int budget)
return received;
}
-
/* Transmit DMA service */
static inline void sca_tx_done(port_t *port)
{
struct net_device *dev = port->netdev;
- card_t* card = port->card;
+ card_t *card = port->card;
u8 stat;
unsigned count = 0;
@@ -321,7 +312,6 @@ static inline void sca_tx_done(port_t *port)
spin_unlock(&port->lock);
}
-
static int sca_poll(struct napi_struct *napi, int budget)
{
port_t *port = container_of(napi, port_t, napi);
@@ -363,15 +353,13 @@ static irqreturn_t sca_intr(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
-
static void sca_set_port(port_t *port)
{
- card_t* card = port->card;
+ card_t *card = port->card;
u16 msci = get_msci(port);
u8 md2 = sca_in(msci + MD2, card);
unsigned int tmc, br = 10, brv = 1024;
-
if (port->settings.clock_rate > 0) {
/* Try lower br for better accuracy*/
do {
@@ -380,14 +368,15 @@ static void sca_set_port(port_t *port)
/* Baud Rate = CLOCK_BASE / TMC / 2^BR */
tmc = CLOCK_BASE / brv / port->settings.clock_rate;
- }while (br > 1 && tmc <= 128);
+ } while (br > 1 && tmc <= 128);
if (tmc < 1) {
tmc = 1;
br = 0; /* For baud=CLOCK_BASE we use tmc=1 br=0 */
brv = 1;
- } else if (tmc > 255)
+ } else if (tmc > 255) {
tmc = 256; /* tmc=0 means 256 - low baud rates */
+ }
port->settings.clock_rate = CLOCK_BASE / brv / tmc;
} else {
@@ -414,34 +403,50 @@ static void sca_set_port(port_t *port)
md2 &= ~MD2_LOOPBACK;
sca_out(md2, msci + MD2, card);
-
}
-
static void sca_open(struct net_device *dev)
{
port_t *port = dev_to_port(dev);
- card_t* card = port->card;
+ card_t *card = port->card;
u16 msci = get_msci(port);
u8 md0, md2;
- switch(port->encoding) {
- case ENCODING_NRZ: md2 = MD2_NRZ; break;
- case ENCODING_NRZI: md2 = MD2_NRZI; break;
- case ENCODING_FM_MARK: md2 = MD2_FM_MARK; break;
- case ENCODING_FM_SPACE: md2 = MD2_FM_SPACE; break;
- default: md2 = MD2_MANCHESTER;
+ switch (port->encoding) {
+ case ENCODING_NRZ:
+ md2 = MD2_NRZ;
+ break;
+ case ENCODING_NRZI:
+ md2 = MD2_NRZI;
+ break;
+ case ENCODING_FM_MARK:
+ md2 = MD2_FM_MARK;
+ break;
+ case ENCODING_FM_SPACE:
+ md2 = MD2_FM_SPACE;
+ break;
+ default:
+ md2 = MD2_MANCHESTER;
}
if (port->settings.loopback)
md2 |= MD2_LOOPBACK;
- switch(port->parity) {
- case PARITY_CRC16_PR0: md0 = MD0_HDLC | MD0_CRC_16_0; break;
- case PARITY_CRC16_PR1: md0 = MD0_HDLC | MD0_CRC_16; break;
- case PARITY_CRC32_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU32; break;
- case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU; break;
- default: md0 = MD0_HDLC | MD0_CRC_NONE;
+ switch (port->parity) {
+ case PARITY_CRC16_PR0:
+ md0 = MD0_HDLC | MD0_CRC_16_0;
+ break;
+ case PARITY_CRC16_PR1:
+ md0 = MD0_HDLC | MD0_CRC_16;
+ break;
+ case PARITY_CRC32_PR1_CCITT:
+ md0 = MD0_HDLC | MD0_CRC_ITU32;
+ break;
+ case PARITY_CRC16_PR1_CCITT:
+ md0 = MD0_HDLC | MD0_CRC_ITU;
+ break;
+ default:
+ md0 = MD0_HDLC | MD0_CRC_NONE;
}
sca_out(CMD_RESET, msci + CMD, card);
@@ -476,7 +481,6 @@ static void sca_open(struct net_device *dev)
netif_start_queue(dev);
}
-
static void sca_close(struct net_device *dev)
{
port_t *port = dev_to_port(dev);
@@ -488,7 +492,6 @@ static void sca_close(struct net_device *dev)
netif_stop_queue(dev);
}
-
static int sca_attach(struct net_device *dev, unsigned short encoding,
unsigned short parity)
{
@@ -511,7 +514,6 @@ static int sca_attach(struct net_device *dev, unsigned short encoding,
return 0;
}
-
#ifdef DEBUG_RINGS
static void sca_dump_rings(struct net_device *dev)
{
@@ -558,7 +560,6 @@ static void sca_dump_rings(struct net_device *dev)
}
#endif /* DEBUG_RINGS */
-
static netdev_tx_t sca_xmit(struct sk_buff *skb, struct net_device *dev)
{
port_t *port = dev_to_port(dev);
@@ -600,7 +601,6 @@ static netdev_tx_t sca_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
-
static u32 sca_detect_ram(card_t *card, u8 __iomem *rambase, u32 ramsize)
{
/* Round RAM size to 32 bits, fill from end to start */
@@ -619,7 +619,6 @@ static u32 sca_detect_ram(card_t *card, u8 __iomem *rambase, u32 ramsize)
return i;
}
-
static void sca_init(card_t *card, int wait_states)
{
sca_out(wait_states, WCRL, card); /* Wait Control */
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index 1bdd3df0867a..dd6312b69861 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -36,8 +36,7 @@
#include <linux/slab.h>
#include <net/net_namespace.h>
-
-static const char* version = "HDLC support module revision 1.22";
+static const char *version = "HDLC support module revision 1.22";
#undef DEBUG_LINK
@@ -74,25 +73,24 @@ netdev_tx_t hdlc_start_xmit(struct sk_buff *skb, struct net_device *dev)
return hdlc->xmit(skb, dev); /* call hardware driver directly */
}
+EXPORT_SYMBOL(hdlc_start_xmit);
static inline void hdlc_proto_start(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
+
if (hdlc->proto->start)
hdlc->proto->start(dev);
}
-
-
static inline void hdlc_proto_stop(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
+
if (hdlc->proto->stop)
hdlc->proto->stop(dev);
}
-
-
static int hdlc_device_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
@@ -141,8 +139,6 @@ carrier_exit:
return NOTIFY_DONE;
}
-
-
/* Must be called by hardware driver when HDLC device is being opened */
int hdlc_open(struct net_device *dev)
{
@@ -152,11 +148,12 @@ int hdlc_open(struct net_device *dev)
hdlc->carrier, hdlc->open);
#endif
- if (hdlc->proto == NULL)
+ if (!hdlc->proto)
return -ENOSYS; /* no protocol attached */
if (hdlc->proto->open) {
int result = hdlc->proto->open(dev);
+
if (result)
return result;
}
@@ -166,16 +163,16 @@ int hdlc_open(struct net_device *dev)
if (hdlc->carrier) {
netdev_info(dev, "Carrier detected\n");
hdlc_proto_start(dev);
- } else
+ } else {
netdev_info(dev, "No carrier\n");
+ }
hdlc->open = 1;
spin_unlock_irq(&hdlc->state_lock);
return 0;
}
-
-
+EXPORT_SYMBOL(hdlc_open);
/* Must be called by hardware driver when HDLC device is being closed */
void hdlc_close(struct net_device *dev)
@@ -197,8 +194,7 @@ void hdlc_close(struct net_device *dev)
if (hdlc->proto->close)
hdlc->proto->close(dev);
}
-
-
+EXPORT_SYMBOL(hdlc_close);
int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
@@ -217,12 +213,14 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
/* Not handled by currently attached protocol (if any) */
while (proto) {
- if ((result = proto->ioctl(dev, ifr)) != -EINVAL)
+ result = proto->ioctl(dev, ifr);
+ if (result != -EINVAL)
return result;
proto = proto->next;
}
return -EINVAL;
}
+EXPORT_SYMBOL(hdlc_ioctl);
static const struct header_ops hdlc_null_ops;
@@ -256,12 +254,14 @@ static void hdlc_setup(struct net_device *dev)
struct net_device *alloc_hdlcdev(void *priv)
{
struct net_device *dev;
+
dev = alloc_netdev(sizeof(struct hdlc_device), "hdlc%d",
NET_NAME_UNKNOWN, hdlc_setup);
if (dev)
dev_to_hdlc(dev)->priv = priv;
return dev;
}
+EXPORT_SYMBOL(alloc_hdlcdev);
void unregister_hdlc_device(struct net_device *dev)
{
@@ -270,8 +270,7 @@ void unregister_hdlc_device(struct net_device *dev)
unregister_netdevice(dev);
rtnl_unlock();
}
-
-
+EXPORT_SYMBOL(unregister_hdlc_device);
int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
size_t size)
@@ -287,7 +286,7 @@ int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
if (size) {
dev_to_hdlc(dev)->state = kmalloc(size, GFP_KERNEL);
- if (dev_to_hdlc(dev)->state == NULL) {
+ if (!dev_to_hdlc(dev)->state) {
module_put(proto->module);
return -ENOBUFS;
}
@@ -296,7 +295,7 @@ int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
return 0;
}
-
+EXPORT_SYMBOL(attach_hdlc_protocol);
int detach_hdlc_protocol(struct net_device *dev)
{
@@ -322,7 +321,7 @@ int detach_hdlc_protocol(struct net_device *dev)
return 0;
}
-
+EXPORT_SYMBOL(detach_hdlc_protocol);
void register_hdlc_protocol(struct hdlc_proto *proto)
{
@@ -331,7 +330,7 @@ void register_hdlc_protocol(struct hdlc_proto *proto)
first_proto = proto;
rtnl_unlock();
}
-
+EXPORT_SYMBOL(register_hdlc_protocol);
void unregister_hdlc_protocol(struct hdlc_proto *proto)
{
@@ -346,54 +345,38 @@ void unregister_hdlc_protocol(struct hdlc_proto *proto)
*p = proto->next;
rtnl_unlock();
}
-
-
+EXPORT_SYMBOL(unregister_hdlc_protocol);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("HDLC support module");
MODULE_LICENSE("GPL v2");
-EXPORT_SYMBOL(hdlc_start_xmit);
-EXPORT_SYMBOL(hdlc_open);
-EXPORT_SYMBOL(hdlc_close);
-EXPORT_SYMBOL(hdlc_ioctl);
-EXPORT_SYMBOL(alloc_hdlcdev);
-EXPORT_SYMBOL(unregister_hdlc_device);
-EXPORT_SYMBOL(register_hdlc_protocol);
-EXPORT_SYMBOL(unregister_hdlc_protocol);
-EXPORT_SYMBOL(attach_hdlc_protocol);
-EXPORT_SYMBOL(detach_hdlc_protocol);
-
static struct packet_type hdlc_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_HDLC),
.func = hdlc_rcv,
};
-
static struct notifier_block hdlc_notifier = {
.notifier_call = hdlc_device_event,
};
-
static int __init hdlc_module_init(void)
{
int result;
pr_info("%s\n", version);
- if ((result = register_netdevice_notifier(&hdlc_notifier)) != 0)
+ result = register_netdevice_notifier(&hdlc_notifier);
+ if (result)
return result;
dev_add_pack(&hdlc_packet_type);
return 0;
}
-
-
static void __exit hdlc_module_exit(void)
{
dev_remove_pack(&hdlc_packet_type);
unregister_netdevice_notifier(&hdlc_notifier);
}
-
module_init(hdlc_module_init);
module_exit(hdlc_module_exit);
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index cb5898f7d68c..c54fdae950fb 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -28,13 +28,11 @@
#define CISCO_ADDR_REPLY 1 /* Cisco address reply */
#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
-
struct hdlc_header {
u8 address;
u8 control;
__be16 protocol;
-}__packed;
-
+} __packed;
struct cisco_packet {
__be32 type; /* code */
@@ -42,11 +40,10 @@ struct cisco_packet {
__be32 par2;
__be16 rel; /* reliability */
__be32 time;
-}__packed;
+} __packed;
#define CISCO_PACKET_LEN 18
#define CISCO_BIG_PACKET_LEN 20
-
struct cisco_state {
cisco_proto settings;
@@ -59,16 +56,13 @@ struct cisco_state {
u32 rxseq; /* RX sequence number */
};
-
static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr);
-
-static inline struct cisco_state* state(hdlc_device *hdlc)
+static inline struct cisco_state *state(hdlc_device *hdlc)
{
return (struct cisco_state *)hdlc->state;
}
-
static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
u16 type, const void *daddr, const void *saddr,
unsigned int len)
@@ -79,7 +73,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
#endif
skb_push(skb, sizeof(struct hdlc_header));
- data = (struct hdlc_header*)skb->data;
+ data = (struct hdlc_header *)skb->data;
if (type == CISCO_KEEPALIVE)
data->address = CISCO_MULTICAST;
else
@@ -90,8 +84,6 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
return sizeof(struct hdlc_header);
}
-
-
static void cisco_keepalive_send(struct net_device *dev, u32 type,
__be32 par1, __be32 par2)
{
@@ -100,13 +92,12 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
skb = dev_alloc_skb(sizeof(struct hdlc_header) +
sizeof(struct cisco_packet));
- if (!skb) {
- netdev_warn(dev, "Memory squeeze on %s()\n", __func__);
+ if (!skb)
return;
- }
+
skb_reserve(skb, 4);
cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0);
- data = (struct cisco_packet*)(skb->data + 4);
+ data = (struct cisco_packet *)(skb->data + 4);
data->type = htonl(type);
data->par1 = par1;
@@ -124,11 +115,9 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
dev_queue_xmit(skb);
}
-
-
static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
{
- struct hdlc_header *data = (struct hdlc_header*)skb->data;
+ struct hdlc_header *data = (struct hdlc_header *)skb->data;
if (skb->len < sizeof(struct hdlc_header))
return cpu_to_be16(ETH_P_HDLC);
@@ -148,13 +137,12 @@ static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
}
}
-
static int cisco_rx(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
hdlc_device *hdlc = dev_to_hdlc(dev);
struct cisco_state *st = state(hdlc);
- struct hdlc_header *data = (struct hdlc_header*)skb->data;
+ struct hdlc_header *data = (struct hdlc_header *)skb->data;
struct cisco_packet *cisco_data;
struct in_device *in_dev;
__be32 addr, mask;
@@ -183,10 +171,10 @@ static int cisco_rx(struct sk_buff *skb)
goto rx_error;
}
- cisco_data = (struct cisco_packet*)(skb->data + sizeof
+ cisco_data = (struct cisco_packet *)(skb->data + sizeof
(struct hdlc_header));
- switch (ntohl (cisco_data->type)) {
+ switch (ntohl(cisco_data->type)) {
case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
@@ -226,6 +214,7 @@ static int cisco_rx(struct sk_buff *skb)
st->last_poll = jiffies;
if (!st->up) {
u32 sec, min, hrs, days;
+
sec = ntohl(cisco_data->time) / 1000;
min = sec / 60; sec -= min * 60;
hrs = min / 60; min -= hrs * 60;
@@ -253,8 +242,6 @@ rx_error:
return NET_RX_DROP;
}
-
-
static void cisco_timer(struct timer_list *t)
{
struct cisco_state *st = from_timer(st, t, timer);
@@ -276,8 +263,6 @@ static void cisco_timer(struct timer_list *t)
add_timer(&st->timer);
}
-
-
static void cisco_start(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -294,8 +279,6 @@ static void cisco_start(struct net_device *dev)
add_timer(&st->timer);
}
-
-
static void cisco_stop(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -310,7 +293,6 @@ static void cisco_stop(struct net_device *dev)
spin_unlock_irqrestore(&st->lock, flags);
}
-
static struct hdlc_proto proto = {
.start = cisco_start,
.stop = cisco_stop,
@@ -359,7 +341,8 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
new_settings.timeout < 2)
return -EINVAL;
- result = hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+ result = hdlc->attach(dev, ENCODING_NRZ,
+ PARITY_CRC16_PR1_CCITT);
if (result)
return result;
@@ -381,23 +364,19 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL;
}
-
-static int __init mod_init(void)
+static int __init hdlc_cisco_init(void)
{
register_hdlc_protocol(&proto);
return 0;
}
-
-
-static void __exit mod_exit(void)
+static void __exit hdlc_cisco_exit(void)
{
unregister_hdlc_protocol(&proto);
}
-
-module_init(mod_init);
-module_exit(mod_exit);
+module_init(hdlc_cisco_init);
+module_exit(hdlc_cisco_exit);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("Cisco HDLC protocol support for generic HDLC");
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index 0720f5f92caa..25e3564ce118 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -6,16 +6,16 @@
* Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
*
- Theory of PVC state
+ Theory of PVC state
DCE mode:
(exist,new) -> 0,0 when "PVC create" or if "link unreliable"
- 0,x -> 1,1 if "link reliable" when sending FULL STATUS
- 1,1 -> 1,0 if received FULL STATUS ACK
+ 0,x -> 1,1 if "link reliable" when sending FULL STATUS
+ 1,1 -> 1,0 if received FULL STATUS ACK
(active) -> 0 when "ifconfig PVC down" or "link unreliable" or "PVC create"
- -> 1 when "PVC up" and (exist,new) = 1,0
+ -> 1 when "PVC up" and (exist,new) = 1,0
DTE mode:
(exist,new,active) = FULL STATUS if "link reliable"
@@ -60,7 +60,6 @@
#define NLPID_CCITT_ANSI_LMI 0x08
#define NLPID_CISCO_LMI 0x09
-
#define LMI_CCITT_ANSI_DLCI 0 /* LMI DLCI */
#define LMI_CISCO_DLCI 1023
@@ -86,7 +85,6 @@
#define LMI_CCITT_CISCO_LENGTH 13 /* LMI frame lengths */
#define LMI_ANSI_LENGTH 14
-
struct fr_hdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned ea1: 1;
@@ -111,7 +109,6 @@ struct fr_hdr {
#endif
} __packed;
-
struct pvc_device {
struct net_device *frad;
struct net_device *main;
@@ -128,7 +125,7 @@ struct pvc_device {
unsigned int fecn: 1;
unsigned int becn: 1;
unsigned int bandwidth; /* Cisco LMI reporting only */
- }state;
+ } state;
};
struct frad_state {
@@ -149,29 +146,24 @@ struct frad_state {
u8 rxseq; /* RX sequence number */
};
-
static int fr_ioctl(struct net_device *dev, struct ifreq *ifr);
-
static inline u16 q922_to_dlci(u8 *hdr)
{
return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4);
}
-
static inline void dlci_to_q922(u8 *hdr, u16 dlci)
{
hdr[0] = (dlci >> 2) & 0xFC;
hdr[1] = ((dlci << 4) & 0xF0) | 0x01;
}
-
-static inline struct frad_state* state(hdlc_device *hdlc)
+static inline struct frad_state *state(hdlc_device *hdlc)
{
- return(struct frad_state *)(hdlc->state);
+ return (struct frad_state *)(hdlc->state);
}
-
static inline struct pvc_device *find_pvc(hdlc_device *hdlc, u16 dlci)
{
struct pvc_device *pvc = state(hdlc)->first_pvc;
@@ -187,7 +179,6 @@ static inline struct pvc_device *find_pvc(hdlc_device *hdlc, u16 dlci)
return NULL;
}
-
static struct pvc_device *add_pvc(struct net_device *dev, u16 dlci)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -215,13 +206,11 @@ static struct pvc_device *add_pvc(struct net_device *dev, u16 dlci)
return pvc;
}
-
static inline int pvc_is_used(struct pvc_device *pvc)
{
return pvc->main || pvc->ether;
}
-
static inline void pvc_carrier(int on, struct pvc_device *pvc)
{
if (on) {
@@ -241,7 +230,6 @@ static inline void pvc_carrier(int on, struct pvc_device *pvc)
}
}
-
static inline void delete_unused_pvcs(hdlc_device *hdlc)
{
struct pvc_device **pvc_p = &state(hdlc)->first_pvc;
@@ -260,7 +248,6 @@ static inline void delete_unused_pvcs(hdlc_device *hdlc)
}
}
-
static inline struct net_device **get_dev_p(struct pvc_device *pvc,
int type)
{
@@ -270,7 +257,6 @@ static inline struct net_device **get_dev_p(struct pvc_device *pvc,
return &pvc->main;
}
-
static int fr_hard_header(struct sk_buff *skb, u16 dlci)
{
if (!skb->dev) { /* Control packets */
@@ -334,8 +320,6 @@ static int fr_hard_header(struct sk_buff *skb, u16 dlci)
return 0;
}
-
-
static int pvc_open(struct net_device *dev)
{
struct pvc_device *pvc = dev->ml_priv;
@@ -345,6 +329,7 @@ static int pvc_open(struct net_device *dev)
if (pvc->open_count++ == 0) {
hdlc_device *hdlc = dev_to_hdlc(pvc->frad);
+
if (state(hdlc)->settings.lmi == LMI_NONE)
pvc->state.active = netif_carrier_ok(pvc->frad);
@@ -354,14 +339,13 @@ static int pvc_open(struct net_device *dev)
return 0;
}
-
-
static int pvc_close(struct net_device *dev)
{
struct pvc_device *pvc = dev->ml_priv;
if (--pvc->open_count == 0) {
hdlc_device *hdlc = dev_to_hdlc(pvc->frad);
+
if (state(hdlc)->settings.lmi == LMI_NONE)
pvc->state.active = 0;
@@ -373,8 +357,6 @@ static int pvc_close(struct net_device *dev)
return 0;
}
-
-
static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct pvc_device *pvc = dev->ml_priv;
@@ -465,15 +447,12 @@ static inline void fr_log_dlci_active(struct pvc_device *pvc)
pvc->state.active ? "active" : "inactive");
}
-
-
static inline u8 fr_lmi_nextseq(u8 x)
{
x++;
return x ? x : 1;
}
-
static void fr_lmi_send(struct net_device *dev, int fullrep)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -495,17 +474,16 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
}
skb = dev_alloc_skb(len);
- if (!skb) {
- netdev_warn(dev, "Memory squeeze on fr_lmi_send()\n");
+ if (!skb)
return;
- }
+
memset(skb->data, 0, len);
skb_reserve(skb, 4);
- if (lmi == LMI_CISCO) {
+ if (lmi == LMI_CISCO)
fr_hard_header(skb, LMI_CISCO_DLCI);
- } else {
+ else
fr_hard_header(skb, LMI_CCITT_ANSI_DLCI);
- }
+
data = skb_tail_pointer(skb);
data[i++] = LMI_CALLREF;
data[i++] = dce ? LMI_STATUS : LMI_STATUS_ENQUIRY;
@@ -569,8 +547,6 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
dev_queue_xmit(skb);
}
-
-
static void fr_set_link_state(int reliable, struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -603,7 +579,6 @@ static void fr_set_link_state(int reliable, struct net_device *dev)
}
}
-
static void fr_timer(struct timer_list *t)
{
struct frad_state *st = from_timer(st, t, timer);
@@ -637,10 +612,10 @@ static void fr_timer(struct timer_list *t)
fr_set_link_state(reliable, dev);
}
- if (state(hdlc)->settings.dce)
+ if (state(hdlc)->settings.dce) {
state(hdlc)->timer.expires = jiffies +
state(hdlc)->settings.t392 * HZ;
- else {
+ } else {
if (state(hdlc)->n391cnt)
state(hdlc)->n391cnt--;
@@ -655,7 +630,6 @@ static void fr_timer(struct timer_list *t)
add_timer(&state(hdlc)->timer);
}
-
static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -696,8 +670,9 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
return 1;
}
i = 7;
- } else
+ } else {
i = 6;
+ }
if (skb->data[i] != (lmi == LMI_CCITT ? LMI_CCITT_REPTYPE :
LMI_ANSI_CISCO_REPTYPE)) {
@@ -814,8 +789,8 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
}
i++;
- new = !! (skb->data[i + 2] & 0x08);
- active = !! (skb->data[i + 2] & 0x02);
+ new = !!(skb->data[i + 2] & 0x08);
+ active = !!(skb->data[i + 2] & 0x02);
if (lmi == LMI_CISCO) {
dlci = (skb->data[i] << 8) | skb->data[i + 1];
bw = (skb->data[i + 3] << 16) |
@@ -962,8 +937,8 @@ static int fr_rx(struct sk_buff *skb)
pvc->state.becn ^= 1;
}
-
- if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (!skb) {
frad->stats.rx_dropped++;
return NET_RX_DROP;
}
@@ -1018,8 +993,6 @@ rx_drop:
return NET_RX_DROP;
}
-
-
static void fr_start(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -1040,11 +1013,11 @@ static void fr_start(struct net_device *dev)
/* First poll after 1 s */
state(hdlc)->timer.expires = jiffies + HZ;
add_timer(&state(hdlc)->timer);
- } else
+ } else {
fr_set_link_state(1, dev);
+ }
}
-
static void fr_stop(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -1056,7 +1029,6 @@ static void fr_stop(struct net_device *dev)
fr_set_link_state(0, dev);
}
-
static void fr_close(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -1071,7 +1043,6 @@ static void fr_close(struct net_device *dev)
}
}
-
static void pvc_setup(struct net_device *dev)
{
dev->type = ARPHRD_DLCI;
@@ -1095,7 +1066,8 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
struct net_device *dev;
int used;
- if ((pvc = add_pvc(frad, dlci)) == NULL) {
+ pvc = add_pvc(frad, dlci);
+ if (!pvc) {
netdev_warn(frad, "Memory squeeze on fr_add_pvc()\n");
return -ENOBUFS;
}
@@ -1121,7 +1093,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
dev->priv_flags &= ~IFF_TX_SKB_SHARING;
eth_hw_addr_random(dev);
} else {
- *(__be16*)dev->dev_addr = htons(dlci);
+ *(__be16 *)dev->dev_addr = htons(dlci);
dlci_to_q922(dev->broadcast, dlci);
}
dev->netdev_ops = &pvc_ops;
@@ -1147,17 +1119,17 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
return 0;
}
-
-
static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
{
struct pvc_device *pvc;
struct net_device *dev;
- if ((pvc = find_pvc(hdlc, dlci)) == NULL)
+ pvc = find_pvc(hdlc, dlci);
+ if (!pvc)
return -ENOENT;
- if ((dev = *get_dev_p(pvc, type)) == NULL)
+ dev = *get_dev_p(pvc, type);
+ if (!dev)
return -ENOENT;
if (dev->flags & IFF_UP)
@@ -1174,12 +1146,11 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
return 0;
}
-
-
static void fr_destroy(struct net_device *frad)
{
hdlc_device *hdlc = dev_to_hdlc(frad);
struct pvc_device *pvc = state(hdlc)->first_pvc;
+
state(hdlc)->first_pvc = NULL; /* All PVCs destroyed */
state(hdlc)->dce_pvc_count = 0;
state(hdlc)->dce_changed = 1;
@@ -1198,7 +1169,6 @@ static void fr_destroy(struct net_device *frad)
}
}
-
static struct hdlc_proto proto = {
.close = fr_close,
.start = fr_start,
@@ -1209,7 +1179,6 @@ static struct hdlc_proto proto = {
.module = THIS_MODULE,
};
-
static int fr_ioctl(struct net_device *dev, struct ifreq *ifr)
{
fr_proto __user *fr_s = ifr->ifr_settings.ifs_ifsu.fr;
@@ -1259,7 +1228,8 @@ static int fr_ioctl(struct net_device *dev, struct ifreq *ifr)
new_settings.dce != 1))
return -EINVAL;
- result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+ result = hdlc->attach(dev, ENCODING_NRZ,
+ PARITY_CRC16_PR1_CCITT);
if (result)
return result;
@@ -1309,22 +1279,19 @@ static int fr_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL;
}
-
-static int __init mod_init(void)
+static int __init hdlc_fr_init(void)
{
register_hdlc_protocol(&proto);
return 0;
}
-
-static void __exit mod_exit(void)
+static void __exit hdlc_fr_exit(void)
{
unregister_hdlc_protocol(&proto);
}
-
-module_init(mod_init);
-module_exit(mod_exit);
+module_init(hdlc_fr_init);
+module_exit(hdlc_fr_exit);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("Frame-Relay protocol support for generic HDLC");
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index 261b53fc8e04..b81ecf432a0c 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -41,6 +41,7 @@ static const char *const code_names[CP_CODES] = {
"0", "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq",
"TermAck", "CodeRej", "ProtoRej", "EchoReq", "EchoReply", "Discard"
};
+
static char debug_buffer[64 + 3 * DEBUG_CP];
#endif
@@ -58,7 +59,6 @@ struct cp_header {
__be16 len;
};
-
struct proto {
struct net_device *dev;
struct timer_list timer;
@@ -91,6 +91,7 @@ static const char *const state_names[STATES] = {
"Closed", "Stopped", "Stopping", "ReqSent", "AckRecv", "AckSent",
"Opened"
};
+
static const char *const event_names[EVENTS] = {
"Start", "Stop", "TO+", "TO-", "RCR+", "RCR-", "RCA", "RCN",
"RTR", "RTA", "RUC", "RXJ+", "RXJ-"
@@ -101,12 +102,12 @@ static struct sk_buff_head tx_queue; /* used when holding the spin lock */
static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr);
-static inline struct ppp* get_ppp(struct net_device *dev)
+static inline struct ppp *get_ppp(struct net_device *dev)
{
return (struct ppp *)dev_to_hdlc(dev)->state;
}
-static inline struct proto* get_proto(struct net_device *dev, u16 pid)
+static inline struct proto *get_proto(struct net_device *dev, u16 pid)
{
struct ppp *ppp = get_ppp(dev);
@@ -122,7 +123,7 @@ static inline struct proto* get_proto(struct net_device *dev, u16 pid)
}
}
-static inline const char* proto_name(u16 pid)
+static inline const char *proto_name(u16 pid)
{
switch (pid) {
case PID_LCP:
@@ -138,7 +139,7 @@ static inline const char* proto_name(u16 pid)
static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev)
{
- struct hdlc_header *data = (struct hdlc_header*)skb->data;
+ struct hdlc_header *data = (struct hdlc_header *)skb->data;
if (skb->len < sizeof(struct hdlc_header))
return htons(ETH_P_HDLC);
@@ -160,7 +161,6 @@ static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev)
}
}
-
static int ppp_hard_header(struct sk_buff *skb, struct net_device *dev,
u16 type, const void *daddr, const void *saddr,
unsigned int len)
@@ -171,7 +171,7 @@ static int ppp_hard_header(struct sk_buff *skb, struct net_device *dev,
#endif
skb_push(skb, sizeof(struct hdlc_header));
- data = (struct hdlc_header*)skb->data;
+ data = (struct hdlc_header *)skb->data;
data->address = HDLC_ADDR_ALLSTATIONS;
data->control = HDLC_CTRL_UI;
@@ -193,10 +193,10 @@ static int ppp_hard_header(struct sk_buff *skb, struct net_device *dev,
return sizeof(struct hdlc_header);
}
-
static void ppp_tx_flush(void)
{
struct sk_buff *skb;
+
while ((skb = skb_dequeue(&tx_queue)) != NULL)
dev_queue_xmit(skb);
}
@@ -219,10 +219,9 @@ static void ppp_tx_cp(struct net_device *dev, u16 pid, u8 code,
skb = dev_alloc_skb(sizeof(struct hdlc_header) +
sizeof(struct cp_header) + magic_len + len);
- if (!skb) {
- netdev_warn(dev, "out of memory in ppp_tx_cp()\n");
+ if (!skb)
return;
- }
+
skb_reserve(skb, sizeof(struct hdlc_header));
cp = skb_put(skb, sizeof(struct cp_header));
@@ -256,7 +255,6 @@ static void ppp_tx_cp(struct net_device *dev, u16 pid, u8 code,
skb_queue_tail(&tx_queue, skb);
}
-
/* State transition table (compare STD-51)
Events Actions
TO+ = Timeout with counter > 0 irc = Initialize-Restart-Count
@@ -294,7 +292,6 @@ static int cp_table[EVENTS][STATES] = {
{ 0 , 1 , 1 , 1 , 1 , 1 ,IRC|STR|2}, /* RXJ- */
};
-
/* SCA: RCR+ must supply id, len and data
SCN: RCR- must supply code, id, len and data
STA: RTR must supply id
@@ -369,7 +366,6 @@ static void ppp_cp_event(struct net_device *dev, u16 pid, u16 event, u8 code,
#endif
}
-
static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id,
unsigned int req_len, const u8 *data)
{
@@ -378,7 +374,8 @@ static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id,
u8 *out;
unsigned int len = req_len, nak_len = 0, rej_len = 0;
- if (!(out = kmalloc(len, GFP_ATOMIC))) {
+ out = kmalloc(len, GFP_ATOMIC);
+ if (!out) {
dev->stats.rx_dropped++;
return; /* out of memory, ignore CR packet */
}
@@ -435,7 +432,7 @@ err_out:
static int ppp_rx(struct sk_buff *skb)
{
- struct hdlc_header *hdr = (struct hdlc_header*)skb->data;
+ struct hdlc_header *hdr = (struct hdlc_header *)skb->data;
struct net_device *dev = skb->dev;
struct ppp *ppp = get_ppp(dev);
struct proto *proto;
@@ -493,7 +490,7 @@ static int ppp_rx(struct sk_buff *skb)
if (pid == PID_LCP)
switch (cp->code) {
case LCP_PROTO_REJ:
- pid = ntohs(*(__be16*)skb->data);
+ pid = ntohs(*(__be16 *)skb->data);
if (pid == PID_LCP || pid == PID_IPCP ||
pid == PID_IPV6CP)
ppp_cp_event(dev, pid, RXJ_BAD, 0, 0,
@@ -615,7 +612,6 @@ static void ppp_timer(struct timer_list *t)
ppp_tx_flush();
}
-
static void ppp_start(struct net_device *dev)
{
struct ppp *ppp = get_ppp(dev);
@@ -623,6 +619,7 @@ static void ppp_start(struct net_device *dev)
for (i = 0; i < IDX_COUNT; i++) {
struct proto *proto = &ppp->protos[i];
+
proto->dev = dev;
timer_setup(&proto->timer, ppp_timer, 0);
proto->state = CLOSED;
@@ -680,7 +677,8 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
/* no settable parameters */
- result = hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+ result = hdlc->attach(dev, ENCODING_NRZ,
+ PARITY_CRC16_PR1_CCITT);
if (result)
return result;
@@ -707,22 +705,20 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL;
}
-
-static int __init mod_init(void)
+static int __init hdlc_ppp_init(void)
{
skb_queue_head_init(&tx_queue);
register_hdlc_protocol(&proto);
return 0;
}
-static void __exit mod_exit(void)
+static void __exit hdlc_ppp_exit(void)
{
unregister_hdlc_protocol(&proto);
}
-
-module_init(mod_init);
-module_exit(mod_exit);
+module_init(hdlc_ppp_init);
+module_exit(hdlc_ppp_exit);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("PPP protocol support for generic HDLC");
diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c
index 388fcc09b4dd..54d28496fefd 100644
--- a/drivers/net/wan/hdlc_raw.c
+++ b/drivers/net/wan/hdlc_raw.c
@@ -90,7 +90,7 @@ static int raw_ioctl(struct net_device *dev, struct ifreq *ifr)
}
-static int __init mod_init(void)
+static int __init hdlc_raw_init(void)
{
register_hdlc_protocol(&proto);
return 0;
@@ -98,14 +98,14 @@ static int __init mod_init(void)
-static void __exit mod_exit(void)
+static void __exit hdlc_raw_exit(void)
{
unregister_hdlc_protocol(&proto);
}
-module_init(mod_init);
-module_exit(mod_exit);
+module_init(hdlc_raw_init);
+module_exit(hdlc_raw_exit);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("Raw HDLC protocol support for generic HDLC");
diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c
index c70a518b8b47..927596276a07 100644
--- a/drivers/net/wan/hdlc_raw_eth.c
+++ b/drivers/net/wan/hdlc_raw_eth.c
@@ -110,7 +110,7 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
}
-static int __init mod_init(void)
+static int __init hdlc_eth_init(void)
{
register_hdlc_protocol(&proto);
return 0;
@@ -118,14 +118,14 @@ static int __init mod_init(void)
-static void __exit mod_exit(void)
+static void __exit hdlc_eth_exit(void)
{
unregister_hdlc_protocol(&proto);
}
-module_init(mod_init);
-module_exit(mod_exit);
+module_init(hdlc_eth_init);
+module_exit(hdlc_eth_exit);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("Ethernet encapsulation support for generic HDLC");
diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c
index ba8c36c7ea91..9b7ebf8bd85c 100644
--- a/drivers/net/wan/hdlc_x25.c
+++ b/drivers/net/wan/hdlc_x25.c
@@ -56,10 +56,8 @@ static void x25_connect_disconnect(struct net_device *dev, int reason, int code)
unsigned char *ptr;
skb = __dev_alloc_skb(1, GFP_ATOMIC | __GFP_NOMEMALLOC);
- if (!skb) {
- netdev_err(dev, "out of memory\n");
+ if (!skb)
return;
- }
ptr = skb_put(skb, 1);
*ptr = code;
@@ -70,22 +68,16 @@ static void x25_connect_disconnect(struct net_device *dev, int reason, int code)
tasklet_schedule(&x25st->rx_tasklet);
}
-
-
static void x25_connected(struct net_device *dev, int reason)
{
x25_connect_disconnect(dev, reason, X25_IFACE_CONNECT);
}
-
-
static void x25_disconnected(struct net_device *dev, int reason)
{
x25_connect_disconnect(dev, reason, X25_IFACE_DISCONNECT);
}
-
-
static int x25_data_indication(struct net_device *dev, struct sk_buff *skb)
{
struct x25_state *x25st = state(dev_to_hdlc(dev));
@@ -108,8 +100,6 @@ static int x25_data_indication(struct net_device *dev, struct sk_buff *skb)
return NET_RX_SUCCESS;
}
-
-
static void x25_data_transmit(struct net_device *dev, struct sk_buff *skb)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -123,8 +113,6 @@ static void x25_data_transmit(struct net_device *dev, struct sk_buff *skb)
hdlc->xmit(skb, dev); /* Ignore return value :-( */
}
-
-
static netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -149,13 +137,15 @@ static netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev)
switch (skb->data[0]) {
case X25_IFACE_DATA: /* Data to be transmitted */
skb_pull(skb, 1);
- if ((result = lapb_data_request(dev, skb)) != LAPB_OK)
+ result = lapb_data_request(dev, skb);
+ if (result != LAPB_OK)
dev_kfree_skb(skb);
spin_unlock_bh(&x25st->up_lock);
return NETDEV_TX_OK;
case X25_IFACE_CONNECT:
- if ((result = lapb_connect_request(dev))!= LAPB_OK) {
+ result = lapb_connect_request(dev);
+ if (result != LAPB_OK) {
if (result == LAPB_CONNECTED)
/* Send connect confirm. msg to level 3 */
x25_connected(dev, 0);
@@ -166,7 +156,8 @@ static netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev)
break;
case X25_IFACE_DISCONNECT:
- if ((result = lapb_disconnect_request(dev)) != LAPB_OK) {
+ result = lapb_disconnect_request(dev);
+ if (result != LAPB_OK) {
if (result == LAPB_NOTCONNECTED)
/* Send disconnect confirm. msg to level 3 */
x25_disconnected(dev, 0);
@@ -185,8 +176,6 @@ static netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
-
-
static int x25_open(struct net_device *dev)
{
static const struct lapb_register_struct cb = {
@@ -232,8 +221,6 @@ static int x25_open(struct net_device *dev)
return 0;
}
-
-
static void x25_close(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -247,15 +234,14 @@ static void x25_close(struct net_device *dev)
tasklet_kill(&x25st->rx_tasklet);
}
-
-
static int x25_rx(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
hdlc_device *hdlc = dev_to_hdlc(dev);
struct x25_state *x25st = state(hdlc);
- if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (!skb) {
dev->stats.rx_dropped++;
return NET_RX_DROP;
}
@@ -279,7 +265,6 @@ static int x25_rx(struct sk_buff *skb)
return NET_RX_DROP;
}
-
static struct hdlc_proto proto = {
.open = x25_open,
.close = x25_close,
@@ -289,7 +274,6 @@ static struct hdlc_proto proto = {
.module = THIS_MODULE,
};
-
static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
{
x25_hdlc_proto __user *x25_s = ifr->ifr_settings.ifs_ifsu.x25;
@@ -326,35 +310,36 @@ static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
new_settings.t1 = 3;
new_settings.t2 = 1;
new_settings.n2 = 10;
- }
- else {
+ } else {
if (copy_from_user(&new_settings, x25_s, size))
return -EFAULT;
if ((new_settings.dce != 0 &&
- new_settings.dce != 1) ||
- (new_settings.modulo != 8 &&
- new_settings.modulo != 128) ||
- new_settings.window < 1 ||
- (new_settings.modulo == 8 &&
- new_settings.window > 7) ||
- (new_settings.modulo == 128 &&
- new_settings.window > 127) ||
- new_settings.t1 < 1 ||
- new_settings.t1 > 255 ||
- new_settings.t2 < 1 ||
- new_settings.t2 > 255 ||
- new_settings.n2 < 1 ||
- new_settings.n2 > 255)
+ new_settings.dce != 1) ||
+ (new_settings.modulo != 8 &&
+ new_settings.modulo != 128) ||
+ new_settings.window < 1 ||
+ (new_settings.modulo == 8 &&
+ new_settings.window > 7) ||
+ (new_settings.modulo == 128 &&
+ new_settings.window > 127) ||
+ new_settings.t1 < 1 ||
+ new_settings.t1 > 255 ||
+ new_settings.t2 < 1 ||
+ new_settings.t2 > 255 ||
+ new_settings.n2 < 1 ||
+ new_settings.n2 > 255)
return -EINVAL;
}
- result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+ result = hdlc->attach(dev, ENCODING_NRZ,
+ PARITY_CRC16_PR1_CCITT);
if (result)
return result;
- if ((result = attach_hdlc_protocol(dev, &proto,
- sizeof(struct x25_state))))
+ result = attach_hdlc_protocol(dev, &proto,
+ sizeof(struct x25_state));
+ if (result)
return result;
memcpy(&state(hdlc)->settings, &new_settings, size);
@@ -380,23 +365,19 @@ static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL;
}
-
-static int __init mod_init(void)
+static int __init hdlc_x25_init(void)
{
register_hdlc_protocol(&proto);
return 0;
}
-
-
-static void __exit mod_exit(void)
+static void __exit hdlc_x25_exit(void)
{
unregister_hdlc_protocol(&proto);
}
-
-module_init(mod_init);
-module_exit(mod_exit);
+module_init(hdlc_x25_init);
+module_exit(hdlc_x25_exit);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("X.25 protocol support for generic HDLC");
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index 6c05c4c8914a..fd61a7cc4fdf 100644
--- a/drivers/net/wan/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Comtrol SV11 card driver
+/* Comtrol SV11 card driver
*
* This is a slightly odd Z85230 synchronous driver. All you need to
* know basically is
@@ -9,7 +8,7 @@
*
* It supports DMA using two DMA channels in SYNC mode. The driver doesn't
* use these facilities
- *
+ *
* The control port is at io+1, the data at io+3 and turning off the DMA
* is done by writing 0 to io+4
*
@@ -44,17 +43,15 @@
static int dma;
-/*
- * Network driver support routines
+/* Network driver support routines
*/
-static inline struct z8530_dev* dev_to_sv(struct net_device *dev)
+static inline struct z8530_dev *dev_to_sv(struct net_device *dev)
{
return (struct z8530_dev *)dev_to_hdlc(dev)->priv;
}
-/*
- * Frame receive. Simple for our card as we do HDLC and there
+/* Frame receive. Simple for our card as we do HDLC and there
* is no funny garbage involved
*/
@@ -65,15 +62,13 @@ static void hostess_input(struct z8530_channel *c, struct sk_buff *skb)
skb->protocol = hdlc_type_trans(skb, c->netdevice);
skb_reset_mac_header(skb);
skb->dev = c->netdevice;
- /*
- * Send it to the PPP layer. We don't have time to process
+ /* Send it to the PPP layer. We don't have time to process
* it right now.
*/
netif_rx(skb);
}
-/*
- * We've been placed in the UP state
+/* We've been placed in the UP state
*/
static int hostess_open(struct net_device *d)
@@ -81,19 +76,18 @@ static int hostess_open(struct net_device *d)
struct z8530_dev *sv11 = dev_to_sv(d);
int err = -1;
- /*
- * Link layer up
+ /* Link layer up
*/
switch (dma) {
- case 0:
- err = z8530_sync_open(d, &sv11->chanA);
- break;
- case 1:
- err = z8530_sync_dma_open(d, &sv11->chanA);
- break;
- case 2:
- err = z8530_sync_txdma_open(d, &sv11->chanA);
- break;
+ case 0:
+ err = z8530_sync_open(d, &sv11->chanA);
+ break;
+ case 1:
+ err = z8530_sync_dma_open(d, &sv11->chanA);
+ break;
+ case 2:
+ err = z8530_sync_txdma_open(d, &sv11->chanA);
+ break;
}
if (err)
@@ -102,15 +96,15 @@ static int hostess_open(struct net_device *d)
err = hdlc_open(d);
if (err) {
switch (dma) {
- case 0:
- z8530_sync_close(d, &sv11->chanA);
- break;
- case 1:
- z8530_sync_dma_close(d, &sv11->chanA);
- break;
- case 2:
- z8530_sync_txdma_close(d, &sv11->chanA);
- break;
+ case 0:
+ z8530_sync_close(d, &sv11->chanA);
+ break;
+ case 1:
+ z8530_sync_dma_close(d, &sv11->chanA);
+ break;
+ case 2:
+ z8530_sync_txdma_close(d, &sv11->chanA);
+ break;
}
return err;
}
@@ -127,8 +121,7 @@ static int hostess_open(struct net_device *d)
static int hostess_close(struct net_device *d)
{
struct z8530_dev *sv11 = dev_to_sv(d);
- /*
- * Discard new frames
+ /* Discard new frames
*/
sv11->chanA.rx_function = z8530_null_rx;
@@ -136,32 +129,29 @@ static int hostess_close(struct net_device *d)
netif_stop_queue(d);
switch (dma) {
- case 0:
- z8530_sync_close(d, &sv11->chanA);
- break;
- case 1:
- z8530_sync_dma_close(d, &sv11->chanA);
- break;
- case 2:
- z8530_sync_txdma_close(d, &sv11->chanA);
- break;
+ case 0:
+ z8530_sync_close(d, &sv11->chanA);
+ break;
+ case 1:
+ z8530_sync_dma_close(d, &sv11->chanA);
+ break;
+ case 2:
+ z8530_sync_txdma_close(d, &sv11->chanA);
+ break;
}
return 0;
}
static int hostess_ioctl(struct net_device *d, struct ifreq *ifr, int cmd)
{
- /* struct z8530_dev *sv11=dev_to_sv(d);
- z8530_ioctl(d,&sv11->chanA,ifr,cmd) */
return hdlc_ioctl(d, ifr, cmd);
}
-/*
- * Passed network frames, fire them downwind.
+/* Passed network frames, fire them downwind.
*/
static netdev_tx_t hostess_queue_xmit(struct sk_buff *skb,
- struct net_device *d)
+ struct net_device *d)
{
return z8530_queue_xmit(&dev_to_sv(d)->chanA, skb);
}
@@ -174,8 +164,7 @@ static int hostess_attach(struct net_device *dev, unsigned short encoding,
return -EINVAL;
}
-/*
- * Description block for a Comtrol Hostess SV11 card
+/* Description block for a Comtrol Hostess SV11 card
*/
static const struct net_device_ops hostess_ops = {
@@ -189,8 +178,7 @@ static struct z8530_dev *sv11_init(int iobase, int irq)
{
struct z8530_dev *sv;
struct net_device *netdev;
- /*
- * Get the needed I/O space
+ /* Get the needed I/O space
*/
if (!request_region(iobase, 8, "Comtrol SV11")) {
@@ -202,8 +190,7 @@ static struct z8530_dev *sv11_init(int iobase, int irq)
if (!sv)
goto err_kzalloc;
- /*
- * Stuff in the I/O addressing
+ /* Stuff in the I/O addressing
*/
sv->active = 0;
@@ -218,7 +205,8 @@ static struct z8530_dev *sv11_init(int iobase, int irq)
outb(0, iobase + 4); /* DMA off */
/* We want a fast IRQ for this device. Actually we'd like an even faster
- IRQ ;) - This is one driver RtLinux is made for */
+ * IRQ ;) - This is one driver RtLinux is made for
+ */
if (request_irq(irq, z8530_interrupt, 0,
"Hostess SV11", sv) < 0) {
@@ -232,8 +220,7 @@ static struct z8530_dev *sv11_init(int iobase, int irq)
sv->chanB.dev = sv;
if (dma) {
- /*
- * You can have DMA off or 1 and 3 thats the lot
+ /* You can have DMA off or 1 and 3 thats the lot
* on the Comtrol.
*/
sv->chanA.txdma = 3;
@@ -248,11 +235,11 @@ static struct z8530_dev *sv11_init(int iobase, int irq)
}
/* Kill our private IRQ line the hostess can end up chattering
- until the configuration is set */
+ * until the configuration is set
+ */
disable_irq(irq);
- /*
- * Begin normal initialise
+ /* Begin normal initialise
*/
if (z8530_init(sv)) {
@@ -268,8 +255,7 @@ static struct z8530_dev *sv11_init(int iobase, int irq)
enable_irq(irq);
- /*
- * Now we can take the IRQ
+ /* Now we can take the IRQ
*/
sv->chanA.netdevice = netdev = alloc_hdlcdev(sv);
@@ -340,7 +326,8 @@ static struct z8530_dev *sv11_unit;
int init_module(void)
{
- if ((sv11_unit = sv11_init(io, irq)) == NULL)
+ sv11_unit = sv11_init(io, irq);
+ if (!sv11_unit)
return -ENODEV;
return 0;
}
diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c
index ecea09fd21cb..3c51ab239fb2 100644
--- a/drivers/net/wan/ixp4xx_hss.c
+++ b/drivers/net/wan/ixp4xx_hss.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/soc/ixp4xx/npe.h>
#include <linux/soc/ixp4xx/qmgr.h>
+#include <linux/soc/ixp4xx/cpu.h>
#define DEBUG_DESC 0
#define DEBUG_RX 0
@@ -83,7 +84,6 @@
#define PKT_HDLC_CRC_32 0x2 /* default = CRC-16 */
#define PKT_HDLC_MSB_ENDIAN 0x4 /* default = LE */
-
/* hss_config, PCRs */
/* Frame sync sampling, default = active low */
#define PCR_FRM_SYNC_ACTIVE_HIGH 0x40000000
@@ -150,26 +150,24 @@
/* HSS number, default = 0 (first) */
#define CCR_SECOND_HSS 0x01000000
-
/* hss_config, clkCR: main:10, num:10, denom:12 */
-#define CLK42X_SPEED_EXP ((0x3FF << 22) | ( 2 << 12) | 15) /*65 KHz*/
-
-#define CLK42X_SPEED_512KHZ (( 130 << 22) | ( 2 << 12) | 15)
-#define CLK42X_SPEED_1536KHZ (( 43 << 22) | ( 18 << 12) | 47)
-#define CLK42X_SPEED_1544KHZ (( 43 << 22) | ( 33 << 12) | 192)
-#define CLK42X_SPEED_2048KHZ (( 32 << 22) | ( 34 << 12) | 63)
-#define CLK42X_SPEED_4096KHZ (( 16 << 22) | ( 34 << 12) | 127)
-#define CLK42X_SPEED_8192KHZ (( 8 << 22) | ( 34 << 12) | 255)
-
-#define CLK46X_SPEED_512KHZ (( 130 << 22) | ( 24 << 12) | 127)
-#define CLK46X_SPEED_1536KHZ (( 43 << 22) | (152 << 12) | 383)
-#define CLK46X_SPEED_1544KHZ (( 43 << 22) | ( 66 << 12) | 385)
-#define CLK46X_SPEED_2048KHZ (( 32 << 22) | (280 << 12) | 511)
-#define CLK46X_SPEED_4096KHZ (( 16 << 22) | (280 << 12) | 1023)
-#define CLK46X_SPEED_8192KHZ (( 8 << 22) | (280 << 12) | 2047)
-
-/*
- * HSS_CONFIG_CLOCK_CR register consists of 3 parts:
+#define CLK42X_SPEED_EXP ((0x3FF << 22) | (2 << 12) | 15) /*65 KHz*/
+
+#define CLK42X_SPEED_512KHZ ((130 << 22) | (2 << 12) | 15)
+#define CLK42X_SPEED_1536KHZ ((43 << 22) | (18 << 12) | 47)
+#define CLK42X_SPEED_1544KHZ ((43 << 22) | (33 << 12) | 192)
+#define CLK42X_SPEED_2048KHZ ((32 << 22) | (34 << 12) | 63)
+#define CLK42X_SPEED_4096KHZ ((16 << 22) | (34 << 12) | 127)
+#define CLK42X_SPEED_8192KHZ ((8 << 22) | (34 << 12) | 255)
+
+#define CLK46X_SPEED_512KHZ ((130 << 22) | (24 << 12) | 127)
+#define CLK46X_SPEED_1536KHZ ((43 << 22) | (152 << 12) | 383)
+#define CLK46X_SPEED_1544KHZ ((43 << 22) | (66 << 12) | 385)
+#define CLK46X_SPEED_2048KHZ ((32 << 22) | (280 << 12) | 511)
+#define CLK46X_SPEED_4096KHZ ((16 << 22) | (280 << 12) | 1023)
+#define CLK46X_SPEED_8192KHZ ((8 << 22) | (280 << 12) | 2047)
+
+/* HSS_CONFIG_CLOCK_CR register consists of 3 parts:
* A (10 bits), B (10 bits) and C (12 bits).
* IXP42x HSS clock generator operation (verified with an oscilloscope):
* Each clock bit takes 7.5 ns (1 / 133.xx MHz).
@@ -208,7 +206,6 @@
#define HSS_CONFIG_TX_LUT 0x18 /* channel look-up tables */
#define HSS_CONFIG_RX_LUT 0x38
-
/* NPE command codes */
/* writes the ConfigWord value to the location specified by offset */
#define PORT_CONFIG_WRITE 0x40
@@ -220,7 +217,8 @@
#define PORT_ERROR_READ 0x42
/* triggers the NPE to reset internal status and enable the HssPacketized
- operation for the flow specified by pPipe */
+ * operation for the flow specified by pPipe
+ */
#define PKT_PIPE_FLOW_ENABLE 0x50
#define PKT_PIPE_FLOW_DISABLE 0x51
#define PKT_NUM_PIPES_WRITE 0x52
@@ -235,12 +233,12 @@
#define ERR_HDLC_ALIGN 2 /* HDLC alignment error */
#define ERR_HDLC_FCS 3 /* HDLC Frame Check Sum error */
#define ERR_RXFREE_Q_EMPTY 4 /* RX-free queue became empty while receiving
- this packet (if buf_len < pkt_len) */
+ * this packet (if buf_len < pkt_len)
+ */
#define ERR_HDLC_TOO_LONG 5 /* HDLC frame size too long */
#define ERR_HDLC_ABORT 6 /* abort sequence received */
#define ERR_DISCONNECTING 7 /* disconnect is in progress */
-
#ifdef __ARMEB__
typedef struct sk_buff buffer_t;
#define free_buffer dev_kfree_skb
@@ -308,7 +306,6 @@ struct desc {
u32 __reserved1[4];
};
-
#define rx_desc_phys(port, n) ((port)->desc_tab_phys + \
(n) * sizeof(struct desc))
#define rx_desc_ptr(port, n) (&(port)->desc_tab[n])
@@ -327,7 +324,7 @@ static DEFINE_SPINLOCK(npe_lock);
static const struct {
int tx, txdone, rx, rxfree;
-}queue_ids[2] = {{HSS0_PKT_TX0_QUEUE, HSS0_PKT_TXDONE_QUEUE, HSS0_PKT_RX_QUEUE,
+} queue_ids[2] = {{HSS0_PKT_TX0_QUEUE, HSS0_PKT_TXDONE_QUEUE, HSS0_PKT_RX_QUEUE,
HSS0_PKT_RXFREE0_QUEUE},
{HSS1_PKT_TX0_QUEUE, HSS1_PKT_TXDONE_QUEUE, HSS1_PKT_RX_QUEUE,
HSS1_PKT_RXFREE0_QUEUE},
@@ -337,7 +334,7 @@ static const struct {
* utility functions
****************************************************************************/
-static inline struct port* dev_to_port(struct net_device *dev)
+static inline struct port *dev_to_port(struct net_device *dev)
{
return dev_to_hdlc(dev)->priv;
}
@@ -346,6 +343,7 @@ static inline struct port* dev_to_port(struct net_device *dev)
static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt)
{
int i;
+
for (i = 0; i < cnt; i++)
dest[i] = swab32(src[i]);
}
@@ -355,9 +353,10 @@ static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt)
* HSS access
****************************************************************************/
-static void hss_npe_send(struct port *port, struct msg *msg, const char* what)
+static void hss_npe_send(struct port *port, struct msg *msg, const char *what)
{
- u32 *val = (u32*)msg;
+ u32 *val = (u32 *)msg;
+
if (npe_send_message(port->npe, msg, what)) {
pr_crit("HSS-%i: unable to send command [%08X:%08X] to %s\n",
port->id, val[0], val[1], npe_name(port->npe));
@@ -513,10 +512,12 @@ static int hss_load_firmware(struct port *port)
if (port->initialized)
return 0;
- if (!npe_running(port->npe) &&
- (err = npe_load_firmware(port->npe, npe_name(port->npe),
- port->dev)))
- return err;
+ if (!npe_running(port->npe)) {
+ err = npe_load_firmware(port->npe, npe_name(port->npe),
+ port->dev);
+ if (err)
+ return err;
+ }
/* HDLC mode configuration */
memset(&msg, 0, sizeof(msg));
@@ -567,7 +568,6 @@ static inline void debug_pkt(struct net_device *dev, const char *func,
#endif
}
-
static inline void debug_desc(u32 phys, struct desc *desc)
{
#if DEBUG_DESC
@@ -583,7 +583,8 @@ static inline int queue_get_desc(unsigned int queue, struct port *port,
u32 phys, tab_phys, n_desc;
struct desc *tab;
- if (!(phys = qmgr_get_entry(queue)))
+ phys = qmgr_get_entry(queue);
+ if (!phys)
return -1;
BUG_ON(phys & 0x1F);
@@ -603,10 +604,10 @@ static inline void queue_put_desc(unsigned int queue, u32 phys,
BUG_ON(phys & 0x1F);
qmgr_put_entry(queue, phys);
/* Don't check for queue overflow here, we've allocated sufficient
- length and queues >= 32 don't support this check anyway. */
+ * length and queues >= 32 don't support this check anyway.
+ */
}
-
static inline void dma_unmap_tx(struct port *port, struct desc *desc)
{
#ifdef __ARMEB__
@@ -619,7 +620,6 @@ static inline void dma_unmap_tx(struct port *port, struct desc *desc)
#endif
}
-
static void hss_hdlc_set_carrier(void *pdev, int carrier)
{
struct net_device *netdev = pdev;
@@ -670,7 +670,8 @@ static int hss_hdlc_poll(struct napi_struct *napi, int budget)
u32 phys;
#endif
- if ((n = queue_get_desc(rxq, port, 0)) < 0) {
+ n = queue_get_desc(rxq, port, 0);
+ if (n < 0) {
#if DEBUG_RX
printk(KERN_DEBUG "%s: hss_hdlc_poll"
" napi_complete\n", dev->name);
@@ -705,7 +706,8 @@ static int hss_hdlc_poll(struct napi_struct *napi, int budget)
switch (desc->status) {
case 0:
#ifdef __ARMEB__
- if ((skb = netdev_alloc_skb(dev, RX_SIZE)) != NULL) {
+ skb = netdev_alloc_skb(dev, RX_SIZE);
+ if (skb) {
phys = dma_map_single(&dev->dev, skb->data,
RX_SIZE,
DMA_FROM_DEVICE);
@@ -784,7 +786,6 @@ static int hss_hdlc_poll(struct napi_struct *napi, int budget)
return received; /* not all work done */
}
-
static void hss_hdlc_txdone_irq(void *pdev)
{
struct net_device *dev = pdev;
@@ -854,7 +855,8 @@ static int hss_hdlc_xmit(struct sk_buff *skb, struct net_device *dev)
#else
offset = (int)skb->data & 3; /* keep 32-bit alignment */
bytes = ALIGN(offset + len, 4);
- if (!(mem = kmalloc(bytes, GFP_ATOMIC))) {
+ mem = kmalloc(bytes, GFP_ATOMIC);
+ if (!mem) {
dev_kfree_skb(skb);
dev->stats.tx_dropped++;
return NETDEV_TX_OK;
@@ -910,7 +912,6 @@ static int hss_hdlc_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
-
static int request_hdlc_queues(struct port *port)
{
int err;
@@ -974,8 +975,9 @@ static int init_hdlc_queues(struct port *port)
return -ENOMEM;
}
- if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL,
- &port->desc_tab_phys)))
+ port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL,
+ &port->desc_tab_phys);
+ if (!port->desc_tab)
return -ENOMEM;
memset(port->desc_tab, 0, POOL_ALLOC_SIZE);
memset(port->rx_buff_tab, 0, sizeof(port->rx_buff_tab)); /* tables */
@@ -987,11 +989,13 @@ static int init_hdlc_queues(struct port *port)
buffer_t *buff;
void *data;
#ifdef __ARMEB__
- if (!(buff = netdev_alloc_skb(port->netdev, RX_SIZE)))
+ buff = netdev_alloc_skb(port->netdev, RX_SIZE);
+ if (!buff)
return -ENOMEM;
data = buff->data;
#else
- if (!(buff = kmalloc(RX_SIZE, GFP_KERNEL)))
+ buff = kmalloc(RX_SIZE, GFP_KERNEL);
+ if (!buff)
return -ENOMEM;
data = buff;
#endif
@@ -1016,6 +1020,7 @@ static void destroy_hdlc_queues(struct port *port)
for (i = 0; i < RX_DESCS; i++) {
struct desc *desc = rx_desc_ptr(port, i);
buffer_t *buff = port->rx_buff_tab[i];
+
if (buff) {
dma_unmap_single(&port->netdev->dev,
desc->data, RX_SIZE,
@@ -1026,6 +1031,7 @@ static void destroy_hdlc_queues(struct port *port)
for (i = 0; i < TX_DESCS; i++) {
struct desc *desc = tx_desc_ptr(port, i);
buffer_t *buff = port->tx_buff_tab[i];
+
if (buff) {
dma_unmap_tx(port, desc);
free_buffer(buff);
@@ -1047,23 +1053,29 @@ static int hss_hdlc_open(struct net_device *dev)
unsigned long flags;
int i, err = 0;
- if ((err = hdlc_open(dev)))
+ err = hdlc_open(dev);
+ if (err)
return err;
- if ((err = hss_load_firmware(port)))
+ err = hss_load_firmware(port);
+ if (err)
goto err_hdlc_close;
- if ((err = request_hdlc_queues(port)))
+ err = request_hdlc_queues(port);
+ if (err)
goto err_hdlc_close;
- if ((err = init_hdlc_queues(port)))
+ err = init_hdlc_queues(port);
+ if (err)
goto err_destroy_queues;
spin_lock_irqsave(&npe_lock, flags);
- if (port->plat->open)
- if ((err = port->plat->open(port->id, dev,
- hss_hdlc_set_carrier)))
+ if (port->plat->open) {
+ err = port->plat->open(port->id, dev, hss_hdlc_set_carrier);
+ if (err)
goto err_unlock;
+ }
+
spin_unlock_irqrestore(&npe_lock, flags);
/* Populate queues with buffers, no failure after this point */
@@ -1160,7 +1172,6 @@ static int hss_hdlc_close(struct net_device *dev)
return 0;
}
-
static int hss_hdlc_attach(struct net_device *dev, unsigned short encoding,
unsigned short parity)
{
@@ -1169,7 +1180,7 @@ static int hss_hdlc_attach(struct net_device *dev, unsigned short encoding,
if (encoding != ENCODING_NRZ)
return -EINVAL;
- switch(parity) {
+ switch (parity) {
case PARITY_CRC16_PR1_CCITT:
port->hdlc_cfg = 0;
return 0;
@@ -1224,6 +1235,7 @@ static void find_best_clock(u32 timer_freq, u32 rate, u32 *best, u32 *reg)
for (b = 0; b < 0x400; b++) {
u64 c = (b + 1) * (u64)rate;
+
do_div(c, timer_freq - rate * a);
c--;
if (c >= 0xFFF) { /* 12-bit - no need to check more 'b's */
@@ -1255,7 +1267,7 @@ static int hss_hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (cmd != SIOCWANDEV)
return hdlc_ioctl(dev, ifr, cmd);
- switch(ifr->ifr_settings.type) {
+ switch (ifr->ifr_settings.type) {
case IF_GET_IFACE:
ifr->ifr_settings.type = IF_IFACE_V35;
if (ifr->ifr_settings.size < size) {
@@ -1272,7 +1284,7 @@ static int hss_hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case IF_IFACE_SYNC_SERIAL:
case IF_IFACE_V35:
- if(!capable(CAP_NET_ADMIN))
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(&new_line, line, size))
return -EFAULT;
@@ -1288,11 +1300,11 @@ static int hss_hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EINVAL;
port->clock_type = clk; /* Update settings */
- if (clk == CLOCK_INT)
+ if (clk == CLOCK_INT) {
find_best_clock(port->plat->timer_freq,
new_line.clock_rate,
&port->clock_rate, &port->clock_reg);
- else {
+ } else {
port->clock_rate = 0;
port->clock_reg = CLK42X_SPEED_2048KHZ;
}
@@ -1334,15 +1346,19 @@ static int hss_init_one(struct platform_device *pdev)
hdlc_device *hdlc;
int err;
- if ((port = kzalloc(sizeof(*port), GFP_KERNEL)) == NULL)
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port)
return -ENOMEM;
- if ((port->npe = npe_request(0)) == NULL) {
+ port->npe = npe_request(0);
+ if (!port->npe) {
err = -ENODEV;
goto err_free;
}
- if ((port->netdev = dev = alloc_hdlcdev(port)) == NULL) {
+ dev = alloc_hdlcdev(port);
+ port->netdev = alloc_hdlcdev(port);
+ if (!port->netdev) {
err = -ENOMEM;
goto err_plat;
}
@@ -1361,7 +1377,8 @@ static int hss_init_one(struct platform_device *pdev)
port->plat = pdev->dev.platform_data;
netif_napi_add(dev, &port->napi, hss_hdlc_poll, NAPI_WEIGHT);
- if ((err = register_hdlc_device(dev)))
+ err = register_hdlc_device(dev);
+ if (err)
goto err_free_netdev;
platform_set_drvdata(pdev, port);
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index 59646865a3a4..89d31adc3809 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -6,7 +6,7 @@
*
* This is a "pseudo" network driver to allow LAPB over Ethernet.
*
- * This driver can use any ethernet destination address, and can be
+ * This driver can use any ethernet destination address, and can be
* limited to accept frames from one dedicated ethernet card only.
*
* History
@@ -44,7 +44,8 @@
static const u8 bcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
/* If this number is made larger, check that the temporary string buffer
- * in lapbeth_new_device is large enough to store the probe device name.*/
+ * in lapbeth_new_device is large enough to store the probe device name.
+ */
#define MAXLAPBDEV 100
struct lapbethdev {
@@ -64,15 +65,14 @@ static void lapbeth_disconnected(struct net_device *dev, int reason);
/* ------------------------------------------------------------------------ */
-/*
- * Get the LAPB device for the ethernet device
+/* Get the LAPB device for the ethernet device
*/
static struct lapbethdev *lapbeth_get_x25_dev(struct net_device *dev)
{
struct lapbethdev *lapbeth;
list_for_each_entry_rcu(lapbeth, &lapbeth_devices, node, lockdep_rtnl_is_held()) {
- if (lapbeth->ethdev == dev)
+ if (lapbeth->ethdev == dev)
return lapbeth;
}
return NULL;
@@ -105,10 +105,10 @@ static int lapbeth_napi_poll(struct napi_struct *napi, int budget)
return processed;
}
-/*
- * Receive a LAPB frame via an ethernet interface.
+/* Receive a LAPB frame via an ethernet interface.
*/
-static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev)
+static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *ptype, struct net_device *orig_dev)
{
int len, err;
struct lapbethdev *lapbeth;
@@ -116,7 +116,8 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
if (dev_net(dev) != &init_net)
goto drop;
- if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (!skb)
return NET_RX_DROP;
if (!pskb_may_pull(skb, 2))
@@ -137,7 +138,8 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
skb_pull(skb, 2); /* Remove the length bytes */
skb_trim(skb, len); /* Set the length of the data */
- if ((err = lapb_data_received(lapbeth->axdev, skb)) != LAPB_OK) {
+ err = lapb_data_received(lapbeth->axdev, skb);
+ if (err != LAPB_OK) {
printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err);
goto drop_unlock;
}
@@ -177,11 +179,10 @@ static int lapbeth_data_indication(struct net_device *dev, struct sk_buff *skb)
return NET_RX_SUCCESS;
}
-/*
- * Send a LAPB frame via an ethernet interface
+/* Send a LAPB frame via an ethernet interface
*/
static netdev_tx_t lapbeth_xmit(struct sk_buff *skb,
- struct net_device *dev)
+ struct net_device *dev)
{
struct lapbethdev *lapbeth = netdev_priv(dev);
int err;
@@ -219,7 +220,8 @@ static netdev_tx_t lapbeth_xmit(struct sk_buff *skb,
skb_pull(skb, 1);
- if ((err = lapb_data_request(dev, skb)) != LAPB_OK) {
+ err = lapb_data_request(dev, skb);
+ if (err != LAPB_OK) {
pr_err("lapb_data_request error - %d\n", err);
goto drop;
}
@@ -263,10 +265,8 @@ static void lapbeth_connected(struct net_device *dev, int reason)
unsigned char *ptr;
struct sk_buff *skb = __dev_alloc_skb(1, GFP_ATOMIC | __GFP_NOMEMALLOC);
- if (!skb) {
- pr_err("out of memory\n");
+ if (!skb)
return;
- }
ptr = skb_put(skb, 1);
*ptr = X25_IFACE_CONNECT;
@@ -283,10 +283,8 @@ static void lapbeth_disconnected(struct net_device *dev, int reason)
unsigned char *ptr;
struct sk_buff *skb = __dev_alloc_skb(1, GFP_ATOMIC | __GFP_NOMEMALLOC);
- if (!skb) {
- pr_err("out of memory\n");
+ if (!skb)
return;
- }
ptr = skb_put(skb, 1);
*ptr = X25_IFACE_DISCONNECT;
@@ -297,17 +295,16 @@ static void lapbeth_disconnected(struct net_device *dev, int reason)
napi_schedule(&lapbeth->napi);
}
-/*
- * Set AX.25 callsign
+/* Set AX.25 callsign
*/
static int lapbeth_set_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr *sa = addr;
+
memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
return 0;
}
-
static const struct lapb_register_struct lapbeth_callbacks = {
.connect_confirmation = lapbeth_connected,
.connect_indication = lapbeth_connected,
@@ -317,8 +314,7 @@ static const struct lapb_register_struct lapbeth_callbacks = {
.data_transmit = lapbeth_data_transmit,
};
-/*
- * open/close a device
+/* open/close a device
*/
static int lapbeth_open(struct net_device *dev)
{
@@ -327,7 +323,8 @@ static int lapbeth_open(struct net_device *dev)
napi_enable(&lapbeth->napi);
- if ((err = lapb_register(dev, &lapbeth_callbacks)) != LAPB_OK) {
+ err = lapb_register(dev, &lapbeth_callbacks);
+ if (err != LAPB_OK) {
pr_err("lapb_register error: %d\n", err);
return -ENODEV;
}
@@ -348,7 +345,8 @@ static int lapbeth_close(struct net_device *dev)
lapbeth->up = false;
spin_unlock_bh(&lapbeth->up_lock);
- if ((err = lapb_unregister(dev)) != LAPB_OK)
+ err = lapb_unregister(dev);
+ if (err != LAPB_OK)
pr_err("lapb_unregister error: %d\n", err);
napi_disable(&lapbeth->napi);
@@ -375,8 +373,7 @@ static void lapbeth_setup(struct net_device *dev)
dev->addr_len = 0;
}
-/*
- * Setup a new device.
+/* Setup a new device.
*/
static int lapbeth_new_device(struct net_device *dev)
{
@@ -427,8 +424,7 @@ fail:
goto out;
}
-/*
- * Free a lapb network device.
+/* Free a lapb network device.
*/
static void lapbeth_free_device(struct lapbethdev *lapbeth)
{
@@ -437,8 +433,7 @@ static void lapbeth_free_device(struct lapbethdev *lapbeth)
unregister_netdevice(lapbeth->axdev);
}
-/*
- * Handle device status changes.
+/* Handle device status changes.
*
* Called from notifier with RTNL held.
*/
@@ -457,13 +452,13 @@ static int lapbeth_device_event(struct notifier_block *this,
switch (event) {
case NETDEV_UP:
/* New ethernet device -> new LAPB interface */
- if (lapbeth_get_x25_dev(dev) == NULL)
+ if (!lapbeth_get_x25_dev(dev))
lapbeth_new_device(dev);
break;
case NETDEV_GOING_DOWN:
/* ethernet device closes -> close LAPB interface */
lapbeth = lapbeth_get_x25_dev(dev);
- if (lapbeth)
+ if (lapbeth)
dev_close(lapbeth->axdev);
break;
case NETDEV_UNREGISTER:
diff --git a/drivers/net/wan/lmc/lmc.h b/drivers/net/wan/lmc/lmc.h
index 38961793adad..3bd541c868d5 100644
--- a/drivers/net/wan/lmc/lmc.h
+++ b/drivers/net/wan/lmc/lmc.h
@@ -9,7 +9,7 @@
*/
int lmc_probe(struct net_device * dev);
unsigned lmc_mii_readreg(lmc_softc_t * const sc, unsigned
- devaddr, unsigned regno);
+ devaddr, unsigned regno);
void lmc_mii_writereg(lmc_softc_t * const sc, unsigned devaddr,
unsigned regno, unsigned data);
void lmc_led_on(lmc_softc_t * const, u32);
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
index 5bf4463873b1..bdb6dc2409bc 100644
--- a/drivers/net/wan/n2.c
+++ b/drivers/net/wan/n2.c
@@ -32,9 +32,8 @@
#include <asm/io.h>
#include "hd64570.h"
-
-static const char* version = "SDL RISCom/N2 driver version: 1.15";
-static const char* devname = "RISCom/N2";
+static const char *version = "SDL RISCom/N2 driver version: 1.15";
+static const char *devname = "RISCom/N2";
#undef DEBUG_PKT
#define DEBUG_RINGS
@@ -64,11 +63,9 @@ static char *hw; /* pointer to hw=xxx command line string */
#define PCR_ENWIN 4 /* Open window */
#define PCR_BUS16 8 /* 16-bit bus */
-
/* Memory Base Address Register */
#define N2_BAR 2
-
/* Page Scan Register */
#define N2_PSR 4
#define WIN16K 0x00
@@ -78,7 +75,6 @@ static char *hw; /* pointer to hw=xxx command line string */
#define PSR_DMAEN 0x80
#define PSR_PAGEBITS 0x0F
-
/* Modem Control Reg */
#define N2_MCR 6
#define CLOCK_OUT_PORT1 0x80
@@ -90,7 +86,6 @@ static char *hw; /* pointer to hw=xxx command line string */
#define DTR_PORT1 0x02
#define DTR_PORT0 0x01
-
typedef struct port_s {
struct net_device *dev;
struct card_s *card;
@@ -106,9 +101,7 @@ typedef struct port_s {
u8 rxs, txs, tmc; /* SCA registers */
u8 phy_node; /* physical port # - 0 or 1 */
u8 log_node; /* logical port # */
-}port_t;
-
-
+} port_t;
typedef struct card_s {
u8 __iomem *winbase; /* ISA window base address */
@@ -122,13 +115,11 @@ typedef struct card_s {
port_t ports[2];
struct card_s *next_card;
-}card_t;
-
+} card_t;
static card_t *first_card;
static card_t **new_card = &first_card;
-
#define sca_reg(reg, card) (0x8000 | (card)->io | \
((reg) & 0x0F) | (((reg) & 0xF0) << 6))
#define sca_in(reg, card) inb(sca_reg(reg, card))
@@ -144,23 +135,20 @@ static card_t **new_card = &first_card;
#define get_port(card, port) ((card)->ports[port].valid ? \
&(card)->ports[port] : NULL)
-
static __inline__ u8 sca_get_page(card_t *card)
{
return inb(card->io + N2_PSR) & PSR_PAGEBITS;
}
-
static __inline__ void openwin(card_t *card, u8 page)
{
u8 psr = inb(card->io + N2_PSR);
+
outb((psr & ~PSR_PAGEBITS) | page, card->io + N2_PSR);
}
-
#include "hd64570.c"
-
static void n2_set_iface(port_t *port)
{
card_t *card = port->card;
@@ -170,7 +158,7 @@ static void n2_set_iface(port_t *port)
u8 rxs = port->rxs & CLK_BRG_MASK;
u8 txs = port->txs & CLK_BRG_MASK;
- switch(port->settings.clock_type) {
+ switch (port->settings.clock_type) {
case CLOCK_INT:
mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0;
rxs |= CLK_BRG_RX; /* BRG output */
@@ -203,13 +191,12 @@ static void n2_set_iface(port_t *port)
sca_set_port(port);
}
-
-
static int n2_open(struct net_device *dev)
{
port_t *port = dev_to_port(dev);
int io = port->card->io;
- u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1:TX422_PORT0);
+ u8 mcr = inb(io + N2_MCR) |
+ (port->phy_node ? TX422_PORT1 : TX422_PORT0);
int result;
result = hdlc_open(dev);
@@ -226,13 +213,12 @@ static int n2_open(struct net_device *dev)
return 0;
}
-
-
static int n2_close(struct net_device *dev)
{
port_t *port = dev_to_port(dev);
int io = port->card->io;
- u8 mcr = inb(io+N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0);
+ u8 mcr = inb(io + N2_MCR) |
+ (port->phy_node ? TX422_PORT1 : TX422_PORT0);
sca_close(dev);
mcr |= port->phy_node ? DTR_PORT1 : DTR_PORT0; /* set DTR OFF */
@@ -241,8 +227,6 @@ static int n2_close(struct net_device *dev)
return 0;
}
-
-
static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
const size_t size = sizeof(sync_serial_settings);
@@ -259,7 +243,7 @@ static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (cmd != SIOCWANDEV)
return hdlc_ioctl(dev, ifr, cmd);
- switch(ifr->ifr_settings.type) {
+ switch (ifr->ifr_settings.type) {
case IF_GET_IFACE:
ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;
if (ifr->ifr_settings.size < size) {
@@ -271,7 +255,7 @@ static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return 0;
case IF_IFACE_SYNC_SERIAL:
- if(!capable(CAP_NET_ADMIN))
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(&new_line, line, size))
@@ -295,8 +279,6 @@ static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
}
-
-
static void n2_destroy_card(card_t *card)
{
int cnt;
@@ -304,6 +286,7 @@ static void n2_destroy_card(card_t *card)
for (cnt = 0; cnt < 2; cnt++)
if (card->ports[cnt].card) {
struct net_device *dev = port_to_dev(&card->ports[cnt]);
+
unregister_hdlc_device(dev);
}
@@ -354,7 +337,7 @@ static int __init n2_run(unsigned long io, unsigned long irq,
}
card = kzalloc(sizeof(card_t), GFP_KERNEL);
- if (card == NULL)
+ if (!card)
return -ENOBUFS;
card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
@@ -486,11 +469,9 @@ static int __init n2_run(unsigned long io, unsigned long irq,
return 0;
}
-
-
static int __init n2_init(void)
{
- if (hw==NULL) {
+ if (!hw) {
#ifdef MODULE
pr_info("no card initialized\n");
#endif
@@ -515,7 +496,7 @@ static int __init n2_init(void)
if (*hw++ != ',')
break;
- while(1) {
+ while (1) {
if (*hw == '0' && !valid[0])
valid[0] = 1; /* Port 0 enabled */
else if (*hw == '1' && !valid[1])
@@ -533,25 +514,24 @@ static int __init n2_init(void)
if (*hw == '\x0')
return first_card ? 0 : -EINVAL;
- }while(*hw++ == ':');
+ } while (*hw++ == ':');
pr_err("invalid hardware parameters\n");
return first_card ? 0 : -EINVAL;
}
-
static void __exit n2_cleanup(void)
{
card_t *card = first_card;
while (card) {
card_t *ptr = card;
+
card = card->next_card;
n2_destroy_card(ptr);
}
}
-
module_init(n2_init);
module_exit(n2_cleanup);
diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c
index 001fd378d417..7b123a771aa6 100644
--- a/drivers/net/wan/pc300too.c
+++ b/drivers/net/wan/pc300too.c
@@ -44,7 +44,7 @@
#define MAX_TX_BUFFERS 10
static int pci_clock_freq = 33000000;
-static int use_crystal_clock = 0;
+static int use_crystal_clock;
static unsigned int CLOCK_BASE;
/* Masks to access the init_ctrl PLX register */
@@ -52,11 +52,9 @@ static unsigned int CLOCK_BASE;
#define PC300_CHMEDIA_MASK(port) (0x00000020UL << ((port) * 3))
#define PC300_CTYPE_MASK (0x00000800UL)
-
enum { PC300_RSV = 1, PC300_X21, PC300_TE }; /* card types */
-/*
- * PLX PCI9050-1 local configuration and shared runtime registers.
+/* PLX PCI9050-1 local configuration and shared runtime registers.
* This structure can be used to access 9050 registers (memory mapped).
*/
typedef struct {
@@ -69,9 +67,7 @@ typedef struct {
u32 cs_base[4]; /* 3C-48h : Chip Select Base Addrs */
u32 intr_ctrl_stat; /* 4Ch : Interrupt Control/Status */
u32 init_ctrl; /* 50h : EEPROM ctrl, Init Ctrl, etc */
-}plx9050;
-
-
+} plx9050;
typedef struct port_s {
struct napi_struct napi;
@@ -88,9 +84,7 @@ typedef struct port_s {
u16 txlast;
u8 rxs, txs, tmc; /* SCA registers */
u8 chan; /* physical port # - 0 or 1 */
-}port_t;
-
-
+} port_t;
typedef struct card_s {
int type; /* RSV, X21, etc. */
@@ -105,26 +99,24 @@ typedef struct card_s {
u8 irq; /* interrupt request level */
port_t ports[2];
-}card_t;
-
+} card_t;
#define get_port(card, port) ((port) < (card)->n_ports ? \
(&(card)->ports[port]) : (NULL))
#include "hd64572.c"
-
static void pc300_set_iface(port_t *port)
{
card_t *card = port->card;
- u32 __iomem * init_ctrl = &card->plxbase->init_ctrl;
+ u32 __iomem *init_ctrl = &card->plxbase->init_ctrl;
u16 msci = get_msci(port);
u8 rxs = port->rxs & CLK_BRG_MASK;
u8 txs = port->txs & CLK_BRG_MASK;
sca_out(EXS_TES1, (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
port->card);
- switch(port->settings.clock_type) {
+ switch (port->settings.clock_type) {
case CLOCK_INT:
rxs |= CLK_BRG; /* BRG output */
txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */
@@ -162,13 +154,11 @@ static void pc300_set_iface(port_t *port)
}
}
-
-
static int pc300_open(struct net_device *dev)
{
port_t *port = dev_to_port(dev);
-
int result = hdlc_open(dev);
+
if (result)
return result;
@@ -177,8 +167,6 @@ static int pc300_open(struct net_device *dev)
return 0;
}
-
-
static int pc300_close(struct net_device *dev)
{
sca_close(dev);
@@ -186,8 +174,6 @@ static int pc300_close(struct net_device *dev)
return 0;
}
-
-
static int pc300_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
const size_t size = sizeof(sync_serial_settings);
@@ -214,7 +200,6 @@ static int pc300_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (copy_to_user(line, &port->settings, size))
return -EFAULT;
return 0;
-
}
if (port->card->type == PC300_X21 &&
@@ -255,8 +240,6 @@ static int pc300_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return 0;
}
-
-
static void pc300_pci_remove_one(struct pci_dev *pdev)
{
int i;
@@ -314,7 +297,7 @@ static int pc300_pci_init_one(struct pci_dev *pdev,
}
card = kzalloc(sizeof(card_t), GFP_KERNEL);
- if (card == NULL) {
+ if (!card) {
pci_release_regions(pdev);
pci_disable_device(pdev);
return -ENOBUFS;
@@ -338,9 +321,7 @@ static int pc300_pci_init_one(struct pci_dev *pdev,
ramphys = pci_resource_start(pdev, 3) & PCI_BASE_ADDRESS_MEM_MASK;
card->rambase = pci_ioremap_bar(pdev, 3);
- if (card->plxbase == NULL ||
- card->scabase == NULL ||
- card->rambase == NULL) {
+ if (!card->plxbase || !card->scabase || !card->rambase) {
pr_err("ioremap() failed\n");
pc300_pci_remove_one(pdev);
return -ENOMEM;
@@ -365,12 +346,14 @@ static int pc300_pci_init_one(struct pci_dev *pdev,
else
card->n_ports = 2;
- for (i = 0; i < card->n_ports; i++)
- if (!(card->ports[i].netdev = alloc_hdlcdev(&card->ports[i]))) {
+ for (i = 0; i < card->n_ports; i++) {
+ card->ports[i].netdev = alloc_hdlcdev(&card->ports[i]);
+ if (!card->ports[i].netdev) {
pr_err("unable to allocate memory\n");
pc300_pci_remove_one(pdev);
return -ENOMEM;
}
+ }
/* Reset PLX */
p = &card->plxbase->init_ctrl;
@@ -442,6 +425,7 @@ static int pc300_pci_init_one(struct pci_dev *pdev,
port_t *port = &card->ports[i];
struct net_device *dev = port->netdev;
hdlc_device *hdlc = dev_to_hdlc(dev);
+
port->chan = i;
spin_lock_init(&port->lock);
@@ -472,8 +456,6 @@ static int pc300_pci_init_one(struct pci_dev *pdev,
return 0;
}
-
-
static const struct pci_device_id pc300_pci_tbl[] = {
{ PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_1, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, 0 },
@@ -486,7 +468,6 @@ static const struct pci_device_id pc300_pci_tbl[] = {
{ 0, }
};
-
static struct pci_driver pc300_pci_driver = {
.name = "PC300",
.id_table = pc300_pci_tbl,
@@ -494,7 +475,6 @@ static struct pci_driver pc300_pci_driver = {
.remove = pc300_pci_remove_one,
};
-
static int __init pc300_init_module(void)
{
if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) {
@@ -511,8 +491,6 @@ static int __init pc300_init_module(void)
return pci_register_driver(&pc300_pci_driver);
}
-
-
static void __exit pc300_cleanup_module(void)
{
pci_unregister_driver(&pc300_pci_driver);
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index ba5cc0c53833..dee9c4e15eca 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -42,8 +42,7 @@
static int pci_clock_freq = 33000000;
#define CLOCK_BASE pci_clock_freq
-/*
- * PLX PCI9052 local configuration and shared runtime registers.
+/* PLX PCI9052 local configuration and shared runtime registers.
* This structure can be used to access 9052 registers (memory mapped).
*/
typedef struct {
@@ -56,9 +55,7 @@ typedef struct {
u32 cs_base[4]; /* 3C-48h : Chip Select Base Addrs */
u32 intr_ctrl_stat; /* 4Ch : Interrupt Control/Status */
u32 init_ctrl; /* 50h : EEPROM ctrl, Init Ctrl, etc */
-}plx9052;
-
-
+} plx9052;
typedef struct port_s {
struct napi_struct napi;
@@ -74,9 +71,7 @@ typedef struct port_s {
u16 txlast;
u8 rxs, txs, tmc; /* SCA registers */
u8 chan; /* physical port # - 0 or 1 */
-}port_t;
-
-
+} port_t;
typedef struct card_s {
u8 __iomem *rambase; /* buffer memory base (virtual) */
@@ -88,15 +83,15 @@ typedef struct card_s {
u8 irq; /* interrupt request level */
port_t ports[2];
-}card_t;
-
+} card_t;
-#define get_port(card, port) (&card->ports[port])
+#define get_port(card, port) (&(card)->ports[port])
#define sca_flush(card) (sca_in(IER0, card))
static inline void new_memcpy_toio(char __iomem *dest, char *src, int length)
{
int len;
+
do {
len = length > 256 ? 256 : length;
memcpy_toio(dest, src, len);
@@ -112,7 +107,6 @@ static inline void new_memcpy_toio(char __iomem *dest, char *src, int length)
#include "hd64572.c"
-
static void pci200_set_iface(port_t *port)
{
card_t *card = port->card;
@@ -122,7 +116,7 @@ static void pci200_set_iface(port_t *port)
sca_out(EXS_TES1, (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
port->card);
- switch(port->settings.clock_type) {
+ switch (port->settings.clock_type) {
case CLOCK_INT:
rxs |= CLK_BRG; /* BRG output */
txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */
@@ -151,13 +145,11 @@ static void pci200_set_iface(port_t *port)
sca_set_port(port);
}
-
-
static int pci200_open(struct net_device *dev)
{
port_t *port = dev_to_port(dev);
-
int result = hdlc_open(dev);
+
if (result)
return result;
@@ -167,8 +159,6 @@ static int pci200_open(struct net_device *dev)
return 0;
}
-
-
static int pci200_close(struct net_device *dev)
{
sca_close(dev);
@@ -177,8 +167,6 @@ static int pci200_close(struct net_device *dev)
return 0;
}
-
-
static int pci200_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
const size_t size = sizeof(sync_serial_settings);
@@ -195,7 +183,7 @@ static int pci200_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (cmd != SIOCWANDEV)
return hdlc_ioctl(dev, ifr, cmd);
- switch(ifr->ifr_settings.type) {
+ switch (ifr->ifr_settings.type) {
case IF_GET_IFACE:
ifr->ifr_settings.type = IF_IFACE_V35;
if (ifr->ifr_settings.size < size) {
@@ -233,8 +221,6 @@ static int pci200_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
}
-
-
static void pci200_pci_remove_one(struct pci_dev *pdev)
{
int i;
@@ -292,7 +278,7 @@ static int pci200_pci_init_one(struct pci_dev *pdev,
}
card = kzalloc(sizeof(card_t), GFP_KERNEL);
- if (card == NULL) {
+ if (!card) {
pci_release_regions(pdev);
pci_disable_device(pdev);
return -ENOBUFS;
@@ -314,18 +300,16 @@ static int pci200_pci_init_one(struct pci_dev *pdev,
return -EFAULT;
}
- plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK;
+ plxphys = pci_resource_start(pdev, 0) & PCI_BASE_ADDRESS_MEM_MASK;
card->plxbase = ioremap(plxphys, PCI200SYN_PLX_SIZE);
- scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK;
+ scaphys = pci_resource_start(pdev, 2) & PCI_BASE_ADDRESS_MEM_MASK;
card->scabase = ioremap(scaphys, PCI200SYN_SCA_SIZE);
- ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK;
+ ramphys = pci_resource_start(pdev, 3) & PCI_BASE_ADDRESS_MEM_MASK;
card->rambase = pci_ioremap_bar(pdev, 3);
- if (card->plxbase == NULL ||
- card->scabase == NULL ||
- card->rambase == NULL) {
+ if (!card->plxbase || !card->scabase || !card->rambase) {
pr_err("ioremap() failed\n");
pci200_pci_remove_one(pdev);
return -EFAULT;
@@ -380,6 +364,7 @@ static int pci200_pci_init_one(struct pci_dev *pdev,
port_t *port = &card->ports[i];
struct net_device *dev = port->netdev;
hdlc_device *hdlc = dev_to_hdlc(dev);
+
port->chan = i;
spin_lock_init(&port->lock);
@@ -407,15 +392,12 @@ static int pci200_pci_init_one(struct pci_dev *pdev,
return 0;
}
-
-
static const struct pci_device_id pci200_pci_tbl[] = {
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_PLX,
PCI_DEVICE_ID_PLX_PCI200SYN, 0, 0, 0 },
{ 0, }
};
-
static struct pci_driver pci200_pci_driver = {
.name = "PCI200SYN",
.id_table = pci200_pci_tbl,
@@ -423,7 +405,6 @@ static struct pci_driver pci200_pci_driver = {
.remove = pci200_pci_remove_one,
};
-
static int __init pci200_init_module(void)
{
if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) {
@@ -433,8 +414,6 @@ static int __init pci200_init_module(void)
return pci_register_driver(&pci200_pci_driver);
}
-
-
static void __exit pci200_cleanup_module(void)
{
pci_unregister_driver(&pci200_pci_driver);
diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
index 7dddc9dcbe23..4403e219ca03 100644
--- a/drivers/net/wan/sealevel.c
+++ b/drivers/net/wan/sealevel.c
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Sealevel Systems 4021 driver.
+/* Sealevel Systems 4021 driver.
*
* (c) Copyright 1999, 2001 Alan Cox
* (c) Copyright 2001 Red Hat Inc.
@@ -29,32 +28,25 @@
#include <asm/byteorder.h>
#include "z85230.h"
-
-struct slvl_device
-{
+struct slvl_device {
struct z8530_channel *chan;
int channel;
};
-
-struct slvl_board
-{
+struct slvl_board {
struct slvl_device dev[2];
struct z8530_dev board;
int iobase;
};
-/*
- * Network driver support routines
- */
+ /* Network driver support routines */
-static inline struct slvl_device* dev_to_chan(struct net_device *dev)
+static inline struct slvl_device *dev_to_chan(struct net_device *dev)
{
return (struct slvl_device *)dev_to_hdlc(dev)->priv;
}
-/*
- * Frame receive. Simple for our card as we do HDLC and there
+/* Frame receive. Simple for our card as we do HDLC and there
* is no funny garbage involved
*/
@@ -68,9 +60,7 @@ static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb)
netif_rx(skb);
}
-/*
- * We've been placed in the UP state
- */
+ /* We've been placed in the UP state */
static int sealevel_open(struct net_device *d)
{
@@ -78,17 +68,15 @@ static int sealevel_open(struct net_device *d)
int err = -1;
int unit = slvl->channel;
- /*
- * Link layer up.
- */
+ /* Link layer up. */
switch (unit) {
- case 0:
- err = z8530_sync_dma_open(d, slvl->chan);
- break;
- case 1:
- err = z8530_sync_open(d, slvl->chan);
- break;
+ case 0:
+ err = z8530_sync_dma_open(d, slvl->chan);
+ break;
+ case 1:
+ err = z8530_sync_open(d, slvl->chan);
+ break;
}
if (err)
@@ -97,21 +85,18 @@ static int sealevel_open(struct net_device *d)
err = hdlc_open(d);
if (err) {
switch (unit) {
- case 0:
- z8530_sync_dma_close(d, slvl->chan);
- break;
- case 1:
- z8530_sync_close(d, slvl->chan);
- break;
+ case 0:
+ z8530_sync_dma_close(d, slvl->chan);
+ break;
+ case 1:
+ z8530_sync_close(d, slvl->chan);
+ break;
}
return err;
}
slvl->chan->rx_function = sealevel_input;
- /*
- * Go go go
- */
netif_start_queue(d);
return 0;
}
@@ -121,9 +106,7 @@ static int sealevel_close(struct net_device *d)
struct slvl_device *slvl = dev_to_chan(d);
int unit = slvl->channel;
- /*
- * Discard new frames
- */
+ /* Discard new frames */
slvl->chan->rx_function = z8530_null_rx;
@@ -131,12 +114,12 @@ static int sealevel_close(struct net_device *d)
netif_stop_queue(d);
switch (unit) {
- case 0:
- z8530_sync_dma_close(d, slvl->chan);
- break;
- case 1:
- z8530_sync_close(d, slvl->chan);
- break;
+ case 0:
+ z8530_sync_dma_close(d, slvl->chan);
+ break;
+ case 1:
+ z8530_sync_close(d, slvl->chan);
+ break;
}
return 0;
}
@@ -144,16 +127,15 @@ static int sealevel_close(struct net_device *d)
static int sealevel_ioctl(struct net_device *d, struct ifreq *ifr, int cmd)
{
/* struct slvl_device *slvl=dev_to_chan(d);
- z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd) */
+ * z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd)
+ */
return hdlc_ioctl(d, ifr, cmd);
}
-/*
- * Passed network frames, fire them downwind.
- */
+/* Passed network frames, fire them downwind. */
static netdev_tx_t sealevel_queue_xmit(struct sk_buff *skb,
- struct net_device *d)
+ struct net_device *d)
{
return z8530_queue_xmit(dev_to_chan(d)->chan, skb);
}
@@ -176,6 +158,7 @@ static const struct net_device_ops sealevel_ops = {
static int slvl_setup(struct slvl_device *sv, int iobase, int irq)
{
struct net_device *dev = alloc_hdlcdev(sv);
+
if (!dev)
return -1;
@@ -195,10 +178,7 @@ static int slvl_setup(struct slvl_device *sv, int iobase, int irq)
return 0;
}
-
-/*
- * Allocate and setup Sealevel board.
- */
+/* Allocate and setup Sealevel board. */
static __init struct slvl_board *slvl_init(int iobase, int irq,
int txdma, int rxdma, int slow)
@@ -206,9 +186,7 @@ static __init struct slvl_board *slvl_init(int iobase, int irq,
struct z8530_dev *dev;
struct slvl_board *b;
- /*
- * Get the needed I/O space
- */
+ /* Get the needed I/O space */
if (!request_region(iobase, 8, "Sealevel 4021")) {
pr_warn("I/O 0x%X already in use\n", iobase);
@@ -227,17 +205,13 @@ static __init struct slvl_board *slvl_init(int iobase, int irq,
dev = &b->board;
- /*
- * Stuff in the I/O addressing
- */
+ /* Stuff in the I/O addressing */
dev->active = 0;
b->iobase = iobase;
- /*
- * Select 8530 delays for the old board
- */
+ /* Select 8530 delays for the old board */
if (slow)
iobase |= Z8530_PORT_SLEEP;
@@ -250,15 +224,13 @@ static __init struct slvl_board *slvl_init(int iobase, int irq,
dev->chanA.irqs = &z8530_nop;
dev->chanB.irqs = &z8530_nop;
- /*
- * Assert DTR enable DMA
- */
+ /* Assert DTR enable DMA */
outb(3 | (1 << 7), b->iobase + 4);
-
/* We want a fast IRQ for this device. Actually we'd like an even faster
- IRQ ;) - This is one driver RtLinux is made for */
+ * IRQ ;) - This is one driver RtLinux is made for
+ */
if (request_irq(irq, z8530_interrupt, 0,
"SeaLevel", dev) < 0) {
@@ -282,9 +254,7 @@ static __init struct slvl_board *slvl_init(int iobase, int irq,
disable_irq(irq);
- /*
- * Begin normal initialise
- */
+ /* Begin normal initialise */
if (z8530_init(dev) != 0) {
pr_err("Z8530 series device not found\n");
@@ -299,9 +269,7 @@ static __init struct slvl_board *slvl_init(int iobase, int irq,
z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230);
}
- /*
- * Now we can take the IRQ
- */
+ /* Now we can take the IRQ */
enable_irq(irq);
@@ -338,6 +306,7 @@ static void __exit slvl_shutdown(struct slvl_board *b)
for (u = 0; u < 2; u++) {
struct net_device *d = b->dev[u].chan->netdevice;
+
unregister_hdlc_device(d);
free_netdev(d);
}
@@ -351,12 +320,11 @@ static void __exit slvl_shutdown(struct slvl_board *b)
kfree(b);
}
-
-static int io=0x238;
-static int txdma=1;
-static int rxdma=3;
-static int irq=5;
-static bool slow=false;
+static int io = 0x238;
+static int txdma = 1;
+static int rxdma = 3;
+static int irq = 5;
+static bool slow;
module_param_hw(io, int, ioport, 0);
MODULE_PARM_DESC(io, "The I/O base of the Sealevel card");
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index a83133388de9..f22e48415e6f 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -32,7 +32,7 @@
#include "wanxl.h"
-static const char* version = "wanXL serial card driver version: 0.48";
+static const char *version = "wanXL serial card driver version: 0.48";
#define PLX_CTL_RESET 0x40000000 /* adapter reset */
@@ -50,24 +50,21 @@ static const char* version = "wanXL serial card driver version: 0.48";
/* MAILBOX #2 - DRAM SIZE */
#define MBX2_MEMSZ_MASK 0xFFFF0000 /* PUTS Memory Size Register mask */
-
struct port {
struct net_device *dev;
struct card *card;
spinlock_t lock; /* for wanxl_xmit */
- int node; /* physical port #0 - 3 */
+ int node; /* physical port #0 - 3 */
unsigned int clock_type;
int tx_in, tx_out;
struct sk_buff *tx_skbs[TX_BUFFERS];
};
-
struct card_status {
desc_t rx_descs[RX_QUEUE_LENGTH];
port_status_t port_status[4];
};
-
struct card {
int n_ports; /* 1, 2 or 4 ports */
u8 irq;
@@ -81,25 +78,22 @@ struct card {
struct port ports[]; /* 1 - 4 port structures follow */
};
-
-
static inline struct port *dev_to_port(struct net_device *dev)
{
return (struct port *)dev_to_hdlc(dev)->priv;
}
-
static inline port_status_t *get_status(struct port *port)
{
return &port->card->status->port_status[port->node];
}
-
#ifdef DEBUG_PCI
static inline dma_addr_t pci_map_single_debug(struct pci_dev *pdev, void *ptr,
size_t size, int direction)
{
dma_addr_t addr = dma_map_single(&pdev->dev, ptr, size, direction);
+
if (addr + size > 0x100000000LL)
pr_crit("%s: pci_map_single() returned memory at 0x%llx!\n",
pci_name(pdev), (unsigned long long)addr);
@@ -110,7 +104,6 @@ static inline dma_addr_t pci_map_single_debug(struct pci_dev *pdev, void *ptr,
#define pci_map_single pci_map_single_debug
#endif
-
/* Cable and/or personality module change interrupt service */
static inline void wanxl_cable_intr(struct port *port)
{
@@ -118,22 +111,46 @@ static inline void wanxl_cable_intr(struct port *port)
int valid = 1;
const char *cable, *pm, *dte = "", *dsr = "", *dcd = "";
- switch(value & 0x7) {
- case STATUS_CABLE_V35: cable = "V.35"; break;
- case STATUS_CABLE_X21: cable = "X.21"; break;
- case STATUS_CABLE_V24: cable = "V.24"; break;
- case STATUS_CABLE_EIA530: cable = "EIA530"; break;
- case STATUS_CABLE_NONE: cable = "no"; break;
- default: cable = "invalid";
+ switch (value & 0x7) {
+ case STATUS_CABLE_V35:
+ cable = "V.35";
+ break;
+ case STATUS_CABLE_X21:
+ cable = "X.21";
+ break;
+ case STATUS_CABLE_V24:
+ cable = "V.24";
+ break;
+ case STATUS_CABLE_EIA530:
+ cable = "EIA530";
+ break;
+ case STATUS_CABLE_NONE:
+ cable = "no";
+ break;
+ default:
+ cable = "invalid";
}
- switch((value >> STATUS_CABLE_PM_SHIFT) & 0x7) {
- case STATUS_CABLE_V35: pm = "V.35"; break;
- case STATUS_CABLE_X21: pm = "X.21"; break;
- case STATUS_CABLE_V24: pm = "V.24"; break;
- case STATUS_CABLE_EIA530: pm = "EIA530"; break;
- case STATUS_CABLE_NONE: pm = "no personality"; valid = 0; break;
- default: pm = "invalid personality"; valid = 0;
+ switch ((value >> STATUS_CABLE_PM_SHIFT) & 0x7) {
+ case STATUS_CABLE_V35:
+ pm = "V.35";
+ break;
+ case STATUS_CABLE_X21:
+ pm = "X.21";
+ break;
+ case STATUS_CABLE_V24:
+ pm = "V.24";
+ break;
+ case STATUS_CABLE_EIA530:
+ pm = "EIA530";
+ break;
+ case STATUS_CABLE_NONE:
+ pm = "no personality";
+ valid = 0;
+ break;
+ default:
+ pm = "invalid personality";
+ valid = 0;
}
if (valid) {
@@ -154,14 +171,13 @@ static inline void wanxl_cable_intr(struct port *port)
netif_carrier_off(port->dev);
}
-
-
/* Transmit complete interrupt service */
static inline void wanxl_tx_intr(struct port *port)
{
struct net_device *dev = port->dev;
+
while (1) {
- desc_t *desc = &get_status(port)->tx_descs[port->tx_in];
+ desc_t *desc = &get_status(port)->tx_descs[port->tx_in];
struct sk_buff *skb = port->tx_skbs[port->tx_in];
switch (desc->stat) {
@@ -179,34 +195,33 @@ static inline void wanxl_tx_intr(struct port *port)
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
}
- desc->stat = PACKET_EMPTY; /* Free descriptor */
+ desc->stat = PACKET_EMPTY; /* Free descriptor */
dma_unmap_single(&port->card->pdev->dev, desc->address,
skb->len, DMA_TO_DEVICE);
dev_consume_skb_irq(skb);
- port->tx_in = (port->tx_in + 1) % TX_BUFFERS;
- }
+ port->tx_in = (port->tx_in + 1) % TX_BUFFERS;
+ }
}
-
-
/* Receive complete interrupt service */
static inline void wanxl_rx_intr(struct card *card)
{
desc_t *desc;
+
while (desc = &card->status->rx_descs[card->rx_in],
desc->stat != PACKET_EMPTY) {
- if ((desc->stat & PACKET_PORT_MASK) > card->n_ports)
+ if ((desc->stat & PACKET_PORT_MASK) > card->n_ports) {
pr_crit("%s: received packet for nonexistent port\n",
pci_name(card->pdev));
- else {
+ } else {
struct sk_buff *skb = card->rx_skbs[card->rx_in];
struct port *port = &card->ports[desc->stat &
PACKET_PORT_MASK];
struct net_device *dev = port->dev;
- if (!skb)
+ if (!skb) {
dev->stats.rx_dropped++;
- else {
+ } else {
dma_unmap_single(&card->pdev->dev,
desc->address, BUFFER_LENGTH,
DMA_FROM_DEVICE);
@@ -239,21 +254,18 @@ static inline void wanxl_rx_intr(struct card *card)
}
}
-
-
-static irqreturn_t wanxl_intr(int irq, void* dev_id)
+static irqreturn_t wanxl_intr(int irq, void *dev_id)
{
struct card *card = dev_id;
- int i;
- u32 stat;
- int handled = 0;
-
+ int i;
+ u32 stat;
+ int handled = 0;
- while((stat = readl(card->plx + PLX_DOORBELL_FROM_CARD)) != 0) {
- handled = 1;
+ while ((stat = readl(card->plx + PLX_DOORBELL_FROM_CARD)) != 0) {
+ handled = 1;
writel(stat, card->plx + PLX_DOORBELL_FROM_CARD);
- for (i = 0; i < card->n_ports; i++) {
+ for (i = 0; i < card->n_ports; i++) {
if (stat & (1 << (DOORBELL_FROM_CARD_TX_0 + i)))
wanxl_tx_intr(&card->ports[i]);
if (stat & (1 << (DOORBELL_FROM_CARD_CABLE_0 + i)))
@@ -261,23 +273,21 @@ static irqreturn_t wanxl_intr(int irq, void* dev_id)
}
if (stat & (1 << DOORBELL_FROM_CARD_RX))
wanxl_rx_intr(card);
- }
+ }
- return IRQ_RETVAL(handled);
+ return IRQ_RETVAL(handled);
}
-
-
static netdev_tx_t wanxl_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct port *port = dev_to_port(dev);
desc_t *desc;
- spin_lock(&port->lock);
+ spin_lock(&port->lock);
desc = &get_status(port)->tx_descs[port->tx_out];
- if (desc->stat != PACKET_EMPTY) {
- /* should never happen - previous xmit should stop queue */
+ if (desc->stat != PACKET_EMPTY) {
+ /* should never happen - previous xmit should stop queue */
#ifdef DEBUG_PKT
printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name);
#endif
@@ -312,8 +322,6 @@ static netdev_tx_t wanxl_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
-
-
static int wanxl_attach(struct net_device *dev, unsigned short encoding,
unsigned short parity)
{
@@ -335,8 +343,6 @@ static int wanxl_attach(struct net_device *dev, unsigned short encoding,
return 0;
}
-
-
static int wanxl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
const size_t size = sizeof(sync_serial_settings);
@@ -384,11 +390,9 @@ static int wanxl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
default:
return hdlc_ioctl(dev, ifr, cmd);
- }
+ }
}
-
-
static int wanxl_open(struct net_device *dev)
{
struct port *port = dev_to_port(dev);
@@ -400,7 +404,9 @@ static int wanxl_open(struct net_device *dev)
netdev_err(dev, "port already open\n");
return -EIO;
}
- if ((i = hdlc_open(dev)) != 0)
+
+ i = hdlc_open(dev);
+ if (i)
return i;
port->tx_in = port->tx_out = 0;
@@ -423,8 +429,6 @@ static int wanxl_open(struct net_device *dev)
return -EFAULT;
}
-
-
static int wanxl_close(struct net_device *dev)
{
struct port *port = dev_to_port(dev);
@@ -461,8 +465,6 @@ static int wanxl_close(struct net_device *dev)
return 0;
}
-
-
static struct net_device_stats *wanxl_get_stats(struct net_device *dev)
{
struct port *port = dev_to_port(dev);
@@ -474,8 +476,6 @@ static struct net_device_stats *wanxl_get_stats(struct net_device *dev)
return &dev->stats;
}
-
-
static int wanxl_puts_command(struct card *card, u32 cmd)
{
unsigned long timeout = jiffies + 5 * HZ;
@@ -486,13 +486,11 @@ static int wanxl_puts_command(struct card *card, u32 cmd)
return 0;
schedule();
- }while (time_after(timeout, jiffies));
+ } while (time_after(timeout, jiffies));
return -1;
}
-
-
static void wanxl_reset(struct card *card)
{
u32 old_value = readl(card->plx + PLX_CONTROL) & ~PLX_CTL_RESET;
@@ -505,8 +503,6 @@ static void wanxl_reset(struct card *card)
readl(card->plx + PLX_CONTROL); /* wait for posted write */
}
-
-
static void wanxl_pci_remove_one(struct pci_dev *pdev)
{
struct card *card = pci_get_drvdata(pdev);
@@ -543,7 +539,6 @@ static void wanxl_pci_remove_one(struct pci_dev *pdev)
kfree(card);
}
-
#include "wanxlfw.inc"
static const struct net_device_ops wanxl_ops = {
@@ -574,12 +569,14 @@ static int wanxl_pci_init_one(struct pci_dev *pdev,
return i;
/* QUICC can only access first 256 MB of host RAM directly,
- but PLX9060 DMA does 32-bits for actual packet data transfers */
+ * but PLX9060 DMA does 32-bits for actual packet data transfers
+ */
/* FIXME when PCI/DMA subsystems are fixed.
- We set both dma_mask and consistent_dma_mask to 28 bits
- and pray pci_alloc_consistent() will use this info. It should
- work on most platforms */
+ * We set both dma_mask and consistent_dma_mask to 28 bits
+ * and pray pci_alloc_consistent() will use this info. It should
+ * work on most platforms
+ */
if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(28)) ||
dma_set_mask(&pdev->dev, DMA_BIT_MASK(28))) {
pr_err("No usable DMA configuration\n");
@@ -594,13 +591,18 @@ static int wanxl_pci_init_one(struct pci_dev *pdev,
}
switch (pdev->device) {
- case PCI_DEVICE_ID_SBE_WANXL100: ports = 1; break;
- case PCI_DEVICE_ID_SBE_WANXL200: ports = 2; break;
- default: ports = 4;
+ case PCI_DEVICE_ID_SBE_WANXL100:
+ ports = 1;
+ break;
+ case PCI_DEVICE_ID_SBE_WANXL200:
+ ports = 2;
+ break;
+ default:
+ ports = 4;
}
card = kzalloc(struct_size(card, ports, ports), GFP_KERNEL);
- if (card == NULL) {
+ if (!card) {
pci_release_regions(pdev);
pci_disable_device(pdev);
return -ENOBUFS;
@@ -612,7 +614,7 @@ static int wanxl_pci_init_one(struct pci_dev *pdev,
card->status = dma_alloc_coherent(&pdev->dev,
sizeof(struct card_status),
&card->status_address, GFP_KERNEL);
- if (card->status == NULL) {
+ if (!card->status) {
wanxl_pci_remove_one(pdev);
return -ENOBUFS;
}
@@ -624,8 +626,9 @@ static int wanxl_pci_init_one(struct pci_dev *pdev,
#endif
/* FIXME when PCI/DMA subsystems are fixed.
- We set both dma_mask and consistent_dma_mask back to 32 bits
- to indicate the card can do 32-bit DMA addressing */
+ * We set both dma_mask and consistent_dma_mask back to 32 bits
+ * to indicate the card can do 32-bit DMA addressing
+ */
if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)) ||
dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
pr_err("No usable DMA configuration\n");
@@ -639,7 +642,7 @@ static int wanxl_pci_init_one(struct pci_dev *pdev,
card->plx = ioremap(plx_phy, 0x70);
if (!card->plx) {
pr_err("ioremap() failed\n");
- wanxl_pci_remove_one(pdev);
+ wanxl_pci_remove_one(pdev);
return -EFAULT;
}
@@ -656,7 +659,7 @@ static int wanxl_pci_init_one(struct pci_dev *pdev,
return -ENODEV;
}
- switch(stat & 0xC0) {
+ switch (stat & 0xC0) {
case 0x00: /* hmm - PUTS completed with non-zero code? */
case 0x80: /* PUTS still testing the hardware */
break;
@@ -677,7 +680,6 @@ static int wanxl_pci_init_one(struct pci_dev *pdev,
/* set up on-board RAM mapping */
mem_phy = pci_resource_start(pdev, 2);
-
/* sanity check the board's reported memory size */
if (ramsize < BUFFERS_ADDR +
(TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH * ports) {
@@ -697,6 +699,7 @@ static int wanxl_pci_init_one(struct pci_dev *pdev,
for (i = 0; i < RX_QUEUE_LENGTH; i++) {
struct sk_buff *skb = dev_alloc_skb(BUFFER_LENGTH);
+
card->rx_skbs[i] = skb;
if (skb)
card->status->rx_descs[i].address =
@@ -707,12 +710,12 @@ static int wanxl_pci_init_one(struct pci_dev *pdev,
mem = ioremap(mem_phy, PDM_OFFSET + sizeof(firmware));
if (!mem) {
pr_err("ioremap() failed\n");
- wanxl_pci_remove_one(pdev);
+ wanxl_pci_remove_one(pdev);
return -EFAULT;
}
for (i = 0; i < sizeof(firmware); i += 4)
- writel(ntohl(*(__be32*)(firmware + i)), mem + PDM_OFFSET + i);
+ writel(ntohl(*(__be32 *)(firmware + i)), mem + PDM_OFFSET + i);
for (i = 0; i < ports; i++)
writel(card->status_address +
@@ -732,10 +735,11 @@ static int wanxl_pci_init_one(struct pci_dev *pdev,
timeout = jiffies + 5 * HZ;
do {
- if ((stat = readl(card->plx + PLX_MAILBOX_5)) != 0)
+ stat = readl(card->plx + PLX_MAILBOX_5);
+ if (stat)
break;
schedule();
- }while (time_after(timeout, jiffies));
+ } while (time_after(timeout, jiffies));
if (!stat) {
pr_warn("%s: timeout while initializing card firmware\n",
@@ -764,6 +768,7 @@ static int wanxl_pci_init_one(struct pci_dev *pdev,
hdlc_device *hdlc;
struct port *port = &card->ports[i];
struct net_device *dev = alloc_hdlcdev(port);
+
if (!dev) {
pr_err("%s: unable to allocate memory\n",
pci_name(pdev));
@@ -813,7 +818,6 @@ static const struct pci_device_id wanxl_pci_tbl[] = {
{ 0, }
};
-
static struct pci_driver wanxl_pci_driver = {
.name = "wanXL",
.id_table = wanxl_pci_tbl,
@@ -821,7 +825,6 @@ static struct pci_driver wanxl_pci_driver = {
.remove = wanxl_pci_remove_one,
};
-
static int __init wanxl_init_module(void)
{
#ifdef MODULE
@@ -835,7 +838,6 @@ static void __exit wanxl_cleanup_module(void)
pci_unregister_driver(&wanxl_pci_driver);
}
-
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("SBE Inc. wanXL serial port driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index 138930c66ad2..982a03488a00 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * (c) Copyright 1998 Alan Cox <alan@lxorguk.ukuu.org.uk>
+/* (c) Copyright 1998 Alan Cox <alan@lxorguk.ukuu.org.uk>
* (c) Copyright 2000, 2001 Red Hat Inc
*
* Development of this driver was funded by Equiinet Ltd
@@ -12,7 +10,7 @@
* Asynchronous mode dropped for 2.2. For 2.5 we will attempt the
* unification of all the Z85x30 asynchronous drivers for real.
*
- * DMA now uses get_free_page as kmalloc buffers may span a 64K
+ * DMA now uses get_free_page as kmalloc buffers may span a 64K
* boundary.
*
* Modified for SMP safety and SMP locking by Alan Cox
@@ -55,14 +53,13 @@
#include "z85230.h"
-
/**
* z8530_read_port - Architecture specific interface function
* @p: port to read
*
* Provided port access methods. The Comtrol SV11 requires no delays
* between accesses and uses PC I/O. Some drivers may need a 5uS delay
- *
+ *
* In the longer term this should become an architecture specific
* section so that this can become a generic driver interface for all
* platforms. For now we only handle PC I/O ports with or without the
@@ -74,8 +71,9 @@
static inline int z8530_read_port(unsigned long p)
{
- u8 r=inb(Z8530_PORT_OF(p));
- if(p&Z8530_PORT_SLEEP) /* gcc should figure this out efficiently ! */
+ u8 r = inb(Z8530_PORT_OF(p));
+
+ if (p & Z8530_PORT_SLEEP) /* gcc should figure this out efficiently ! */
udelay(5);
return r;
}
@@ -95,34 +93,30 @@ static inline int z8530_read_port(unsigned long p)
* dread 5uS sanity delay.
*/
-
static inline void z8530_write_port(unsigned long p, u8 d)
{
- outb(d,Z8530_PORT_OF(p));
- if(p&Z8530_PORT_SLEEP)
+ outb(d, Z8530_PORT_OF(p));
+ if (p & Z8530_PORT_SLEEP)
udelay(5);
}
-
-
static void z8530_rx_done(struct z8530_channel *c);
static void z8530_tx_done(struct z8530_channel *c);
-
/**
- * read_zsreg - Read a register from a Z85230
+ * read_zsreg - Read a register from a Z85230
* @c: Z8530 channel to read from (2 per chip)
* @reg: Register to read
* FIXME: Use a spinlock.
- *
+ *
* Most of the Z8530 registers are indexed off the control registers.
* A read is done by writing to the control register and reading the
* register back. The caller must hold the lock
*/
-
+
static inline u8 read_zsreg(struct z8530_channel *c, u8 reg)
{
- if(reg)
+ if (reg)
z8530_write_port(c->ctrlio, reg);
return z8530_read_port(c->ctrlio);
}
@@ -138,7 +132,8 @@ static inline u8 read_zsreg(struct z8530_channel *c, u8 reg)
static inline u8 read_zsdata(struct z8530_channel *c)
{
u8 r;
- r=z8530_read_port(c->dataio);
+
+ r = z8530_read_port(c->dataio);
return r;
}
@@ -156,10 +151,9 @@ static inline u8 read_zsdata(struct z8530_channel *c)
*/
static inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val)
{
- if(reg)
+ if (reg)
z8530_write_port(c->ctrlio, reg);
z8530_write_port(c->ctrlio, val);
-
}
/**
@@ -182,108 +176,94 @@ static inline void write_zsctrl(struct z8530_channel *c, u8 val)
*
* Write directly to the data register on the Z8530
*/
-
-
static inline void write_zsdata(struct z8530_channel *c, u8 val)
{
z8530_write_port(c->dataio, val);
}
-/*
- * Register loading parameters for a dead port
+/* Register loading parameters for a dead port
*/
-
-u8 z8530_dead_port[]=
-{
+
+u8 z8530_dead_port[] = {
255
};
-
EXPORT_SYMBOL(z8530_dead_port);
-/*
- * Register loading parameters for currently supported circuit types
+/* Register loading parameters for currently supported circuit types
*/
-
-/*
- * Data clocked by telco end. This is the correct data for the UK
+/* Data clocked by telco end. This is the correct data for the UK
* "kilostream" service, and most other similar services.
*/
-
-u8 z8530_hdlc_kilostream[]=
-{
- 4, SYNC_ENAB|SDLC|X1CLK,
+
+u8 z8530_hdlc_kilostream[] = {
+ 4, SYNC_ENAB | SDLC | X1CLK,
2, 0, /* No vector */
1, 0,
- 3, ENT_HM|RxCRC_ENAB|Rx8,
- 5, TxCRC_ENAB|RTS|TxENAB|Tx8|DTR,
+ 3, ENT_HM | RxCRC_ENAB | Rx8,
+ 5, TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR,
9, 0, /* Disable interrupts */
6, 0xFF,
7, FLAG,
- 10, ABUNDER|NRZ|CRCPS,/*MARKIDLE ??*/
+ 10, ABUNDER | NRZ | CRCPS,/*MARKIDLE ??*/
11, TCTRxCP,
14, DISDPLL,
- 15, DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE,
- 1, EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx,
- 9, NV|MIE|NORESET,
+ 15, DCDIE | SYNCIE | CTSIE | TxUIE | BRKIE,
+ 1, EXT_INT_ENAB | TxINT_ENAB | INT_ALL_Rx,
+ 9, NV | MIE | NORESET,
255
};
-
EXPORT_SYMBOL(z8530_hdlc_kilostream);
-/*
- * As above but for enhanced chips.
+/* As above but for enhanced chips.
*/
-
-u8 z8530_hdlc_kilostream_85230[]=
-{
- 4, SYNC_ENAB|SDLC|X1CLK,
+
+u8 z8530_hdlc_kilostream_85230[] = {
+ 4, SYNC_ENAB | SDLC | X1CLK,
2, 0, /* No vector */
1, 0,
- 3, ENT_HM|RxCRC_ENAB|Rx8,
- 5, TxCRC_ENAB|RTS|TxENAB|Tx8|DTR,
+ 3, ENT_HM | RxCRC_ENAB | Rx8,
+ 5, TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR,
9, 0, /* Disable interrupts */
6, 0xFF,
7, FLAG,
- 10, ABUNDER|NRZ|CRCPS, /* MARKIDLE?? */
+ 10, ABUNDER | NRZ | CRCPS, /* MARKIDLE?? */
11, TCTRxCP,
14, DISDPLL,
- 15, DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE,
- 1, EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx,
- 9, NV|MIE|NORESET,
+ 15, DCDIE | SYNCIE | CTSIE | TxUIE | BRKIE,
+ 1, EXT_INT_ENAB | TxINT_ENAB | INT_ALL_Rx,
+ 9, NV | MIE | NORESET,
23, 3, /* Extended mode AUTO TX and EOM*/
-
+
255
};
-
EXPORT_SYMBOL(z8530_hdlc_kilostream_85230);
/**
* z8530_flush_fifo - Flush on chip RX FIFO
* @c: Channel to flush
*
- * Flush the receive FIFO. There is no specific option for this, we
+ * Flush the receive FIFO. There is no specific option for this, we
* blindly read bytes and discard them. Reading when there is no data
* is harmless. The 8530 has a 4 byte FIFO, the 85230 has 8 bytes.
- *
+ *
* All locking is handled for the caller. On return data may still be
* present if it arrived during the flush.
*/
-
+
static void z8530_flush_fifo(struct z8530_channel *c)
{
read_zsreg(c, R1);
read_zsreg(c, R1);
read_zsreg(c, R1);
read_zsreg(c, R1);
- if(c->dev->type==Z85230)
- {
+ if (c->dev->type == Z85230) {
read_zsreg(c, R1);
read_zsreg(c, R1);
read_zsreg(c, R1);
read_zsreg(c, R1);
}
-}
+}
/**
* z8530_rtsdtr - Control the outgoing DTS/RTS line
@@ -309,7 +289,7 @@ static void z8530_rtsdtr(struct z8530_channel *c, int set)
* z8530_rx - Handle a PIO receive event
* @c: Z8530 channel to process
*
- * Receive handler for receiving in PIO mode. This is much like the
+ * Receive handler for receiving in PIO mode. This is much like the
* async one but not quite the same or as complex
*
* Note: Its intended that this handler can easily be separated from
@@ -322,77 +302,63 @@ static void z8530_rtsdtr(struct z8530_channel *c, int set)
* other code - this is true in the RT case too.
*
* We only cover the sync cases for this. If you want 2Mbit async
- * do it yourself but consider medical assistance first. This non DMA
- * synchronous mode is portable code. The DMA mode assumes PCI like
+ * do it yourself but consider medical assistance first. This non DMA
+ * synchronous mode is portable code. The DMA mode assumes PCI like
* ISA DMA
*
* Called with the device lock held
*/
-
+
static void z8530_rx(struct z8530_channel *c)
{
- u8 ch,stat;
+ u8 ch, stat;
- while(1)
- {
+ while (1) {
/* FIFO empty ? */
- if(!(read_zsreg(c, R0)&1))
+ if (!(read_zsreg(c, R0) & 1))
break;
- ch=read_zsdata(c);
- stat=read_zsreg(c, R1);
-
- /*
- * Overrun ?
+ ch = read_zsdata(c);
+ stat = read_zsreg(c, R1);
+
+ /* Overrun ?
*/
- if(c->count < c->max)
- {
- *c->dptr++=ch;
+ if (c->count < c->max) {
+ *c->dptr++ = ch;
c->count++;
}
- if(stat&END_FR)
- {
-
- /*
- * Error ?
+ if (stat & END_FR) {
+ /* Error ?
*/
- if(stat&(Rx_OVR|CRC_ERR))
- {
+ if (stat & (Rx_OVR | CRC_ERR)) {
/* Rewind the buffer and return */
- if(c->skb)
- c->dptr=c->skb->data;
- c->count=0;
- if(stat&Rx_OVR)
- {
+ if (c->skb)
+ c->dptr = c->skb->data;
+ c->count = 0;
+ if (stat & Rx_OVR) {
pr_warn("%s: overrun\n", c->dev->name);
c->rx_overrun++;
}
- if(stat&CRC_ERR)
- {
+ if (stat & CRC_ERR) {
c->rx_crc_err++;
/* printk("crc error\n"); */
}
/* Shove the frame upstream */
- }
- else
- {
- /*
- * Drop the lock for RX processing, or
- * there are deadlocks
- */
+ } else {
+ /* Drop the lock for RX processing, or
+ * there are deadlocks
+ */
z8530_rx_done(c);
write_zsctrl(c, RES_Rx_CRC);
}
}
}
- /*
- * Clear irq
+ /* Clear irq
*/
write_zsctrl(c, ERR_RES);
write_zsctrl(c, RES_H_IUS);
}
-
/**
* z8530_tx - Handle a PIO transmit event
* @c: Z8530 channel to process
@@ -402,35 +368,31 @@ static void z8530_rx(struct z8530_channel *c)
* in as possible, its quite possible that we won't keep up with the
* data rate otherwise.
*/
-
+
static void z8530_tx(struct z8530_channel *c)
{
- while(c->txcount) {
+ while (c->txcount) {
/* FIFO full ? */
- if(!(read_zsreg(c, R0)&4))
+ if (!(read_zsreg(c, R0) & 4))
return;
c->txcount--;
- /*
- * Shovel out the byte
+ /* Shovel out the byte
*/
write_zsreg(c, R8, *c->tx_ptr++);
write_zsctrl(c, RES_H_IUS);
/* We are about to underflow */
- if(c->txcount==0)
- {
+ if (c->txcount == 0) {
write_zsctrl(c, RES_EOM_L);
- write_zsreg(c, R10, c->regs[10]&~ABUNDER);
+ write_zsreg(c, R10, c->regs[10] & ~ABUNDER);
}
}
-
- /*
- * End of frame TX - fire another one
+ /* End of frame TX - fire another one
*/
-
+
write_zsctrl(c, RES_Tx_P);
- z8530_tx_done(c);
+ z8530_tx_done(c);
write_zsctrl(c, RES_H_IUS);
}
@@ -460,8 +422,7 @@ static void z8530_status(struct z8530_channel *chan)
z8530_tx_done(chan);
}
- if (altered & chan->dcdcheck)
- {
+ if (altered & chan->dcdcheck) {
if (status & chan->dcdcheck) {
pr_info("%s: DCD raised\n", chan->dev->name);
write_zsreg(chan, R3, chan->regs[3] | RxENABLE);
@@ -474,7 +435,6 @@ static void z8530_status(struct z8530_channel *chan)
if (chan->netdevice)
netif_carrier_off(chan->netdevice);
}
-
}
write_zsctrl(chan, RES_EXT_INT);
write_zsctrl(chan, RES_H_IUS);
@@ -485,7 +445,6 @@ struct z8530_irqhandler z8530_sync = {
.tx = z8530_tx,
.status = z8530_status,
};
-
EXPORT_SYMBOL(z8530_sync);
/**
@@ -497,31 +456,27 @@ EXPORT_SYMBOL(z8530_sync);
* events are handled by the DMA hardware. We get a kick here only if
* a frame ended.
*/
-
+
static void z8530_dma_rx(struct z8530_channel *chan)
{
- if(chan->rxdma_on)
- {
+ if (chan->rxdma_on) {
/* Special condition check only */
u8 status;
-
+
read_zsreg(chan, R7);
read_zsreg(chan, R6);
-
- status=read_zsreg(chan, R1);
-
- if(status&END_FR)
- {
+
+ status = read_zsreg(chan, R1);
+
+ if (status & END_FR)
z8530_rx_done(chan); /* Fire up the next one */
- }
+
write_zsctrl(chan, ERR_RES);
write_zsctrl(chan, RES_H_IUS);
- }
- else
- {
+ } else {
/* DMA is off right now, drain the slow way */
z8530_rx(chan);
- }
+ }
}
/**
@@ -531,11 +486,9 @@ static void z8530_dma_rx(struct z8530_channel *chan)
* We have received an interrupt while doing DMA transmissions. It
* shouldn't happen. Scream loudly if it does.
*/
-
static void z8530_dma_tx(struct z8530_channel *chan)
{
- if(!chan->dma_tx)
- {
+ if (!chan->dma_tx) {
pr_warn("Hey who turned the DMA off?\n");
z8530_tx(chan);
return;
@@ -548,40 +501,35 @@ static void z8530_dma_tx(struct z8530_channel *chan)
/**
* z8530_dma_status - Handle a DMA status exception
* @chan: Z8530 channel to process
- *
+ *
* A status event occurred on the Z8530. We receive these for two reasons
* when in DMA mode. Firstly if we finished a packet transfer we get one
* and kick the next packet out. Secondly we may see a DCD change.
*
*/
-
static void z8530_dma_status(struct z8530_channel *chan)
{
u8 status, altered;
- status=read_zsreg(chan, R0);
- altered=chan->status^status;
-
- chan->status=status;
+ status = read_zsreg(chan, R0);
+ altered = chan->status ^ status;
+ chan->status = status;
- if(chan->dma_tx)
- {
- if(status&TxEOM)
- {
+ if (chan->dma_tx) {
+ if (status & TxEOM) {
unsigned long flags;
-
- flags=claim_dma_lock();
+
+ flags = claim_dma_lock();
disable_dma(chan->txdma);
- clear_dma_ff(chan->txdma);
- chan->txdma_on=0;
+ clear_dma_ff(chan->txdma);
+ chan->txdma_on = 0;
release_dma_lock(flags);
z8530_tx_done(chan);
}
}
- if (altered & chan->dcdcheck)
- {
+ if (altered & chan->dcdcheck) {
if (status & chan->dcdcheck) {
pr_info("%s: DCD raised\n", chan->dev->name);
write_zsreg(chan, R3, chan->regs[3] | RxENABLE);
@@ -621,21 +569,18 @@ static struct z8530_irqhandler z8530_txdma_sync = {
* (eg the MacII) we must clear the interrupt cause or die.
*/
-
static void z8530_rx_clear(struct z8530_channel *c)
{
- /*
- * Data and status bytes
+ /* Data and status bytes
*/
u8 stat;
read_zsdata(c);
- stat=read_zsreg(c, R1);
-
- if(stat&END_FR)
+ stat = read_zsreg(c, R1);
+
+ if (stat & END_FR)
write_zsctrl(c, RES_Rx_CRC);
- /*
- * Clear irq
+ /* Clear irq
*/
write_zsctrl(c, ERR_RES);
write_zsctrl(c, RES_H_IUS);
@@ -667,8 +612,9 @@ static void z8530_tx_clear(struct z8530_channel *c)
static void z8530_status_clear(struct z8530_channel *chan)
{
- u8 status=read_zsreg(chan, R0);
- if(status&TxEOM)
+ u8 status = read_zsreg(chan, R0);
+
+ if (status & TxEOM)
write_zsctrl(chan, ERR_RES);
write_zsctrl(chan, RES_EXT_INT);
write_zsctrl(chan, RES_H_IUS);
@@ -679,13 +625,11 @@ struct z8530_irqhandler z8530_nop = {
.tx = z8530_tx_clear,
.status = z8530_status_clear,
};
-
-
EXPORT_SYMBOL(z8530_nop);
/**
* z8530_interrupt - Handle an interrupt from a Z8530
- * @irq: Interrupt number
+ * @irq: Interrupt number
* @dev_id: The Z8530 device that is interrupting.
*
* A Z85[2]30 device has stuck its hand in the air for attention.
@@ -701,78 +645,73 @@ EXPORT_SYMBOL(z8530_nop);
irqreturn_t z8530_interrupt(int irq, void *dev_id)
{
- struct z8530_dev *dev=dev_id;
+ struct z8530_dev *dev = dev_id;
u8 intr;
static volatile int locker=0;
- int work=0;
+ int work = 0;
struct z8530_irqhandler *irqs;
-
- if(locker)
- {
+
+ if (locker) {
pr_err("IRQ re-enter\n");
return IRQ_NONE;
}
- locker=1;
+ locker = 1;
spin_lock(&dev->lock);
- while(++work<5000)
- {
-
+ while (++work < 5000) {
intr = read_zsreg(&dev->chanA, R3);
- if(!(intr & (CHARxIP|CHATxIP|CHAEXT|CHBRxIP|CHBTxIP|CHBEXT)))
+ if (!(intr &
+ (CHARxIP | CHATxIP | CHAEXT | CHBRxIP | CHBTxIP | CHBEXT)))
break;
-
- /* This holds the IRQ status. On the 8530 you must read it from chan
- A even though it applies to the whole chip */
-
+
+ /* This holds the IRQ status. On the 8530 you must read it
+ * from chan A even though it applies to the whole chip
+ */
+
/* Now walk the chip and see what it is wanting - it may be
- an IRQ for someone else remember */
-
- irqs=dev->chanA.irqs;
+ * an IRQ for someone else remember
+ */
+
+ irqs = dev->chanA.irqs;
- if(intr & (CHARxIP|CHATxIP|CHAEXT))
- {
- if(intr&CHARxIP)
+ if (intr & (CHARxIP | CHATxIP | CHAEXT)) {
+ if (intr & CHARxIP)
irqs->rx(&dev->chanA);
- if(intr&CHATxIP)
+ if (intr & CHATxIP)
irqs->tx(&dev->chanA);
- if(intr&CHAEXT)
+ if (intr & CHAEXT)
irqs->status(&dev->chanA);
}
- irqs=dev->chanB.irqs;
+ irqs = dev->chanB.irqs;
- if(intr & (CHBRxIP|CHBTxIP|CHBEXT))
- {
- if(intr&CHBRxIP)
+ if (intr & (CHBRxIP | CHBTxIP | CHBEXT)) {
+ if (intr & CHBRxIP)
irqs->rx(&dev->chanB);
- if(intr&CHBTxIP)
+ if (intr & CHBTxIP)
irqs->tx(&dev->chanB);
- if(intr&CHBEXT)
+ if (intr & CHBEXT)
irqs->status(&dev->chanB);
}
}
spin_unlock(&dev->lock);
- if(work==5000)
+ if (work == 5000)
pr_err("%s: interrupt jammed - abort(0x%X)!\n",
dev->name, intr);
/* Ok all done */
- locker=0;
+ locker = 0;
return IRQ_HANDLED;
}
-
EXPORT_SYMBOL(z8530_interrupt);
-static const u8 reg_init[16]=
-{
- 0,0,0,0,
- 0,0,0,0,
- 0,0,0,0,
- 0x55,0,0,0
+static const u8 reg_init[16] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0x55, 0, 0, 0
};
-
/**
* z8530_sync_open - Open a Z8530 channel for PIO
* @dev: The network interface we are using
@@ -781,7 +720,6 @@ static const u8 reg_init[16]=
* Switch a Z8530 into synchronous mode without DMA assist. We
* raise the RTS/DTR and commence network operation.
*/
-
int z8530_sync_open(struct net_device *dev, struct z8530_channel *c)
{
unsigned long flags;
@@ -789,7 +727,7 @@ int z8530_sync_open(struct net_device *dev, struct z8530_channel *c)
spin_lock_irqsave(c->lock, flags);
c->sync = 1;
- c->mtu = dev->mtu+64;
+ c->mtu = dev->mtu + 64;
c->count = 0;
c->skb = NULL;
c->skb2 = NULL;
@@ -798,17 +736,15 @@ int z8530_sync_open(struct net_device *dev, struct z8530_channel *c)
/* This loads the double buffer up */
z8530_rx_done(c); /* Load the frame ring */
z8530_rx_done(c); /* Load the backup frame */
- z8530_rtsdtr(c,1);
+ z8530_rtsdtr(c, 1);
c->dma_tx = 0;
- c->regs[R1]|=TxINT_ENAB;
+ c->regs[R1] |= TxINT_ENAB;
write_zsreg(c, R1, c->regs[R1]);
- write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+ write_zsreg(c, R3, c->regs[R3] | RxENABLE);
spin_unlock_irqrestore(c->lock, flags);
return 0;
}
-
-
EXPORT_SYMBOL(z8530_sync_open);
/**
@@ -819,25 +755,23 @@ EXPORT_SYMBOL(z8530_sync_open);
* Close down a Z8530 interface and switch its interrupt handlers
* to discard future events.
*/
-
int z8530_sync_close(struct net_device *dev, struct z8530_channel *c)
{
u8 chk;
unsigned long flags;
-
+
spin_lock_irqsave(c->lock, flags);
c->irqs = &z8530_nop;
c->max = 0;
c->sync = 0;
-
- chk=read_zsreg(c,R0);
+
+ chk = read_zsreg(c, R0);
write_zsreg(c, R3, c->regs[R3]);
- z8530_rtsdtr(c,0);
+ z8530_rtsdtr(c, 0);
spin_unlock_irqrestore(c->lock, flags);
return 0;
}
-
EXPORT_SYMBOL(z8530_sync_close);
/**
@@ -849,91 +783,83 @@ EXPORT_SYMBOL(z8530_sync_close);
* ISA DMA channels must be available for this to work. We assume ISA
* DMA driven I/O and PC limits on access.
*/
-
int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c)
{
unsigned long cflags, dflags;
-
+
c->sync = 1;
- c->mtu = dev->mtu+64;
+ c->mtu = dev->mtu + 64;
c->count = 0;
c->skb = NULL;
c->skb2 = NULL;
- /*
- * Load the DMA interfaces up
+
+ /* Load the DMA interfaces up
*/
c->rxdma_on = 0;
c->txdma_on = 0;
-
- /*
- * Allocate the DMA flip buffers. Limit by page size.
+
+ /* Allocate the DMA flip buffers. Limit by page size.
* Everyone runs 1500 mtu or less on wan links so this
* should be fine.
*/
-
- if(c->mtu > PAGE_SIZE/2)
+
+ if (c->mtu > PAGE_SIZE / 2)
return -EMSGSIZE;
-
- c->rx_buf[0]=(void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
- if(c->rx_buf[0]==NULL)
+
+ c->rx_buf[0] = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!c->rx_buf[0])
return -ENOBUFS;
- c->rx_buf[1]=c->rx_buf[0]+PAGE_SIZE/2;
-
- c->tx_dma_buf[0]=(void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
- if(c->tx_dma_buf[0]==NULL)
- {
+ c->rx_buf[1] = c->rx_buf[0] + PAGE_SIZE / 2;
+
+ c->tx_dma_buf[0] = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!c->tx_dma_buf[0]) {
free_page((unsigned long)c->rx_buf[0]);
- c->rx_buf[0]=NULL;
+ c->rx_buf[0] = NULL;
return -ENOBUFS;
}
- c->tx_dma_buf[1]=c->tx_dma_buf[0]+PAGE_SIZE/2;
+ c->tx_dma_buf[1] = c->tx_dma_buf[0] + PAGE_SIZE / 2;
- c->tx_dma_used=0;
+ c->tx_dma_used = 0;
c->dma_tx = 1;
- c->dma_num=0;
- c->dma_ready=1;
-
- /*
- * Enable DMA control mode
+ c->dma_num = 0;
+ c->dma_ready = 1;
+
+ /* Enable DMA control mode
*/
spin_lock_irqsave(c->lock, cflags);
-
- /*
- * TX DMA via DIR/REQ
+
+ /* TX DMA via DIR/REQ
+ */
+
+ c->regs[R14] |= DTRREQ;
+ write_zsreg(c, R14, c->regs[R14]);
+
+ c->regs[R1] &= ~TxINT_ENAB;
+ write_zsreg(c, R1, c->regs[R1]);
+
+ /* RX DMA via W/Req
*/
-
- c->regs[R14]|= DTRREQ;
- write_zsreg(c, R14, c->regs[R14]);
- c->regs[R1]&= ~TxINT_ENAB;
+ c->regs[R1] |= WT_FN_RDYFN;
+ c->regs[R1] |= WT_RDY_RT;
+ c->regs[R1] |= INT_ERR_Rx;
+ c->regs[R1] &= ~TxINT_ENAB;
write_zsreg(c, R1, c->regs[R1]);
-
- /*
- * RX DMA via W/Req
- */
-
- c->regs[R1]|= WT_FN_RDYFN;
- c->regs[R1]|= WT_RDY_RT;
- c->regs[R1]|= INT_ERR_Rx;
- c->regs[R1]&= ~TxINT_ENAB;
+ c->regs[R1] |= WT_RDY_ENAB;
write_zsreg(c, R1, c->regs[R1]);
- c->regs[R1]|= WT_RDY_ENAB;
- write_zsreg(c, R1, c->regs[R1]);
-
- /*
- * DMA interrupts
+
+ /* DMA interrupts
+ */
+
+ /* Set up the DMA configuration
*/
-
- /*
- * Set up the DMA configuration
- */
-
- dflags=claim_dma_lock();
-
+
+ dflags = claim_dma_lock();
+
disable_dma(c->rxdma);
clear_dma_ff(c->rxdma);
- set_dma_mode(c->rxdma, DMA_MODE_READ|0x10);
+ set_dma_mode(c->rxdma, DMA_MODE_READ | 0x10);
set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[0]));
set_dma_count(c->rxdma, c->mtu);
enable_dma(c->rxdma);
@@ -942,26 +868,24 @@ int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c)
clear_dma_ff(c->txdma);
set_dma_mode(c->txdma, DMA_MODE_WRITE);
disable_dma(c->txdma);
-
+
release_dma_lock(dflags);
-
- /*
- * Select the DMA interrupt handlers
+
+ /* Select the DMA interrupt handlers
*/
c->rxdma_on = 1;
c->txdma_on = 1;
c->tx_dma_used = 1;
-
+
c->irqs = &z8530_dma_sync;
- z8530_rtsdtr(c,1);
- write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+ z8530_rtsdtr(c, 1);
+ write_zsreg(c, R3, c->regs[R3] | RxENABLE);
spin_unlock_irqrestore(c->lock, cflags);
-
+
return 0;
}
-
EXPORT_SYMBOL(z8530_sync_dma_open);
/**
@@ -972,66 +896,60 @@ EXPORT_SYMBOL(z8530_sync_dma_open);
* Shut down a DMA mode synchronous interface. Halt the DMA, and
* free the buffers.
*/
-
int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c)
{
u8 chk;
unsigned long flags;
-
+
c->irqs = &z8530_nop;
c->max = 0;
c->sync = 0;
-
- /*
- * Disable the PC DMA channels
+
+ /* Disable the PC DMA channels
*/
-
- flags=claim_dma_lock();
+
+ flags = claim_dma_lock();
disable_dma(c->rxdma);
clear_dma_ff(c->rxdma);
-
+
c->rxdma_on = 0;
-
+
disable_dma(c->txdma);
clear_dma_ff(c->txdma);
release_dma_lock(flags);
-
+
c->txdma_on = 0;
c->tx_dma_used = 0;
spin_lock_irqsave(c->lock, flags);
- /*
- * Disable DMA control mode
+ /* Disable DMA control mode
*/
-
- c->regs[R1]&= ~WT_RDY_ENAB;
- write_zsreg(c, R1, c->regs[R1]);
- c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx);
- c->regs[R1]|= INT_ALL_Rx;
+
+ c->regs[R1] &= ~WT_RDY_ENAB;
write_zsreg(c, R1, c->regs[R1]);
- c->regs[R14]&= ~DTRREQ;
- write_zsreg(c, R14, c->regs[R14]);
-
- if(c->rx_buf[0])
- {
+ c->regs[R1] &= ~(WT_RDY_RT | WT_FN_RDYFN | INT_ERR_Rx);
+ c->regs[R1] |= INT_ALL_Rx;
+ write_zsreg(c, R1, c->regs[R1]);
+ c->regs[R14] &= ~DTRREQ;
+ write_zsreg(c, R14, c->regs[R14]);
+
+ if (c->rx_buf[0]) {
free_page((unsigned long)c->rx_buf[0]);
- c->rx_buf[0]=NULL;
+ c->rx_buf[0] = NULL;
}
- if(c->tx_dma_buf[0])
- {
+ if (c->tx_dma_buf[0]) {
free_page((unsigned long)c->tx_dma_buf[0]);
- c->tx_dma_buf[0]=NULL;
+ c->tx_dma_buf[0] = NULL;
}
- chk=read_zsreg(c,R0);
+ chk = read_zsreg(c, R0);
write_zsreg(c, R3, c->regs[R3]);
- z8530_rtsdtr(c,0);
+ z8530_rtsdtr(c, 0);
spin_unlock_irqrestore(c->lock, flags);
return 0;
}
-
EXPORT_SYMBOL(z8530_sync_dma_close);
/**
@@ -1050,65 +968,58 @@ int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c)
printk("Opening sync interface for TX-DMA\n");
c->sync = 1;
- c->mtu = dev->mtu+64;
+ c->mtu = dev->mtu + 64;
c->count = 0;
c->skb = NULL;
c->skb2 = NULL;
-
- /*
- * Allocate the DMA flip buffers. Limit by page size.
+
+ /* Allocate the DMA flip buffers. Limit by page size.
* Everyone runs 1500 mtu or less on wan links so this
* should be fine.
*/
-
- if(c->mtu > PAGE_SIZE/2)
+
+ if (c->mtu > PAGE_SIZE / 2)
return -EMSGSIZE;
-
- c->tx_dma_buf[0]=(void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
- if(c->tx_dma_buf[0]==NULL)
- return -ENOBUFS;
- c->tx_dma_buf[1] = c->tx_dma_buf[0] + PAGE_SIZE/2;
+ c->tx_dma_buf[0] = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!c->tx_dma_buf[0])
+ return -ENOBUFS;
+ c->tx_dma_buf[1] = c->tx_dma_buf[0] + PAGE_SIZE / 2;
spin_lock_irqsave(c->lock, cflags);
- /*
- * Load the PIO receive ring
+ /* Load the PIO receive ring
*/
z8530_rx_done(c);
z8530_rx_done(c);
- /*
- * Load the DMA interfaces up
+ /* Load the DMA interfaces up
*/
c->rxdma_on = 0;
c->txdma_on = 0;
-
- c->tx_dma_used=0;
- c->dma_num=0;
- c->dma_ready=1;
+
+ c->tx_dma_used = 0;
+ c->dma_num = 0;
+ c->dma_ready = 1;
c->dma_tx = 1;
- /*
- * Enable DMA control mode
+ /* Enable DMA control mode
*/
- /*
- * TX DMA via DIR/REQ
- */
- c->regs[R14]|= DTRREQ;
- write_zsreg(c, R14, c->regs[R14]);
-
- c->regs[R1]&= ~TxINT_ENAB;
+ /* TX DMA via DIR/REQ
+ */
+ c->regs[R14] |= DTRREQ;
+ write_zsreg(c, R14, c->regs[R14]);
+
+ c->regs[R1] &= ~TxINT_ENAB;
write_zsreg(c, R1, c->regs[R1]);
-
- /*
- * Set up the DMA configuration
- */
-
+
+ /* Set up the DMA configuration
+ */
+
dflags = claim_dma_lock();
disable_dma(c->txdma);
@@ -1117,23 +1028,21 @@ int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c)
disable_dma(c->txdma);
release_dma_lock(dflags);
-
- /*
- * Select the DMA interrupt handlers
+
+ /* Select the DMA interrupt handlers
*/
c->rxdma_on = 0;
c->txdma_on = 1;
c->tx_dma_used = 1;
-
+
c->irqs = &z8530_txdma_sync;
- z8530_rtsdtr(c,1);
- write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+ z8530_rtsdtr(c, 1);
+ write_zsreg(c, R3, c->regs[R3] | RxENABLE);
spin_unlock_irqrestore(c->lock, cflags);
-
+
return 0;
}
-
EXPORT_SYMBOL(z8530_sync_txdma_open);
/**
@@ -1141,7 +1050,7 @@ EXPORT_SYMBOL(z8530_sync_txdma_open);
* @dev: Network device to detach
* @c: Z8530 channel to move into discard mode
*
- * Shut down a DMA/PIO split mode synchronous interface. Halt the DMA,
+ * Shut down a DMA/PIO split mode synchronous interface. Halt the DMA,
* and free the buffers.
*/
@@ -1150,17 +1059,15 @@ int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c)
unsigned long dflags, cflags;
u8 chk;
-
spin_lock_irqsave(c->lock, cflags);
-
+
c->irqs = &z8530_nop;
c->max = 0;
c->sync = 0;
-
- /*
- * Disable the PC DMA channels
+
+ /* Disable the PC DMA channels
*/
-
+
dflags = claim_dma_lock();
disable_dma(c->txdma);
@@ -1170,41 +1077,34 @@ int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c)
release_dma_lock(dflags);
- /*
- * Disable DMA control mode
+ /* Disable DMA control mode
*/
-
- c->regs[R1]&= ~WT_RDY_ENAB;
- write_zsreg(c, R1, c->regs[R1]);
- c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx);
- c->regs[R1]|= INT_ALL_Rx;
+
+ c->regs[R1] &= ~WT_RDY_ENAB;
+ write_zsreg(c, R1, c->regs[R1]);
+ c->regs[R1] &= ~(WT_RDY_RT | WT_FN_RDYFN | INT_ERR_Rx);
+ c->regs[R1] |= INT_ALL_Rx;
write_zsreg(c, R1, c->regs[R1]);
- c->regs[R14]&= ~DTRREQ;
- write_zsreg(c, R14, c->regs[R14]);
-
- if(c->tx_dma_buf[0])
- {
+ c->regs[R14] &= ~DTRREQ;
+ write_zsreg(c, R14, c->regs[R14]);
+
+ if (c->tx_dma_buf[0]) {
free_page((unsigned long)c->tx_dma_buf[0]);
- c->tx_dma_buf[0]=NULL;
+ c->tx_dma_buf[0] = NULL;
}
- chk=read_zsreg(c,R0);
+ chk = read_zsreg(c, R0);
write_zsreg(c, R3, c->regs[R3]);
- z8530_rtsdtr(c,0);
+ z8530_rtsdtr(c, 0);
spin_unlock_irqrestore(c->lock, cflags);
return 0;
}
-
-
EXPORT_SYMBOL(z8530_sync_txdma_close);
-
-/*
- * Name strings for Z8530 chips. SGI claim to have a 130, Zilog deny
+/* Name strings for Z8530 chips. SGI claim to have a 130, Zilog deny
* it exists...
*/
-
-static const char *z8530_type_name[]={
+static const char * const z8530_type_name[] = {
"Z8530",
"Z85C30",
"Z85230"
@@ -1224,78 +1124,71 @@ static const char *z8530_type_name[]={
void z8530_describe(struct z8530_dev *dev, char *mapping, unsigned long io)
{
pr_info("%s: %s found at %s 0x%lX, IRQ %d\n",
- dev->name,
+ dev->name,
z8530_type_name[dev->type],
mapping,
Z8530_PORT_OF(io),
dev->irq);
}
-
EXPORT_SYMBOL(z8530_describe);
-/*
- * Locked operation part of the z8530 init code
+/* Locked operation part of the z8530 init code
*/
-
static inline int do_z8530_init(struct z8530_dev *dev)
{
/* NOP the interrupt handlers first - we might get a
- floating IRQ transition when we reset the chip */
- dev->chanA.irqs=&z8530_nop;
- dev->chanB.irqs=&z8530_nop;
- dev->chanA.dcdcheck=DCD;
- dev->chanB.dcdcheck=DCD;
+ * floating IRQ transition when we reset the chip
+ */
+ dev->chanA.irqs = &z8530_nop;
+ dev->chanB.irqs = &z8530_nop;
+ dev->chanA.dcdcheck = DCD;
+ dev->chanB.dcdcheck = DCD;
/* Reset the chip */
write_zsreg(&dev->chanA, R9, 0xC0);
udelay(200);
/* Now check its valid */
write_zsreg(&dev->chanA, R12, 0xAA);
- if(read_zsreg(&dev->chanA, R12)!=0xAA)
+ if (read_zsreg(&dev->chanA, R12) != 0xAA)
return -ENODEV;
write_zsreg(&dev->chanA, R12, 0x55);
- if(read_zsreg(&dev->chanA, R12)!=0x55)
+ if (read_zsreg(&dev->chanA, R12) != 0x55)
return -ENODEV;
-
- dev->type=Z8530;
-
- /*
- * See the application note.
+
+ dev->type = Z8530;
+
+ /* See the application note.
*/
-
+
write_zsreg(&dev->chanA, R15, 0x01);
-
- /*
- * If we can set the low bit of R15 then
+
+ /* If we can set the low bit of R15 then
* the chip is enhanced.
*/
-
- if(read_zsreg(&dev->chanA, R15)==0x01)
- {
+
+ if (read_zsreg(&dev->chanA, R15) == 0x01) {
/* This C30 versus 230 detect is from Klaus Kudielka's dmascc */
/* Put a char in the fifo */
write_zsreg(&dev->chanA, R8, 0);
- if(read_zsreg(&dev->chanA, R0)&Tx_BUF_EMP)
+ if (read_zsreg(&dev->chanA, R0) & Tx_BUF_EMP)
dev->type = Z85230; /* Has a FIFO */
else
dev->type = Z85C30; /* Z85C30, 1 byte FIFO */
}
-
- /*
- * The code assumes R7' and friends are
+
+ /* The code assumes R7' and friends are
* off. Use write_zsext() for these and keep
* this bit clear.
*/
-
+
write_zsreg(&dev->chanA, R15, 0);
-
- /*
- * At this point it looks like the chip is behaving
+
+ /* At this point it looks like the chip is behaving
*/
-
+
memcpy(dev->chanA.regs, reg_init, 16);
- memcpy(dev->chanB.regs, reg_init ,16);
-
+ memcpy(dev->chanB.regs, reg_init, 16);
+
return 0;
}
@@ -1332,36 +1225,32 @@ int z8530_init(struct z8530_dev *dev)
return ret;
}
-
-
EXPORT_SYMBOL(z8530_init);
/**
* z8530_shutdown - Shutdown a Z8530 device
* @dev: The Z8530 chip to shutdown
*
- * We set the interrupt handlers to silence any interrupts. We then
+ * We set the interrupt handlers to silence any interrupts. We then
* reset the chip and wait 100uS to be sure the reset completed. Just
* in case the caller then tries to do stuff.
*
* This is called without the lock held
*/
-
int z8530_shutdown(struct z8530_dev *dev)
{
unsigned long flags;
/* Reset the chip */
spin_lock_irqsave(&dev->lock, flags);
- dev->chanA.irqs=&z8530_nop;
- dev->chanB.irqs=&z8530_nop;
+ dev->chanA.irqs = &z8530_nop;
+ dev->chanB.irqs = &z8530_nop;
write_zsreg(&dev->chanA, R9, 0xC0);
/* We must lock the udelay, the chip is offlimits here */
udelay(100);
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
-
EXPORT_SYMBOL(z8530_shutdown);
/**
@@ -1370,7 +1259,7 @@ EXPORT_SYMBOL(z8530_shutdown);
* @rtable: table of register, value pairs
* FIXME: ioctl to allow user uploaded tables
*
- * Load a Z8530 channel up from the system data. We use +16 to
+ * Load a Z8530 channel up from the system data. We use +16 to
* indicate the "prime" registers. The value 255 terminates the
* table.
*/
@@ -1381,41 +1270,39 @@ int z8530_channel_load(struct z8530_channel *c, u8 *rtable)
spin_lock_irqsave(c->lock, flags);
- while(*rtable!=255)
- {
- int reg=*rtable++;
- if(reg>0x0F)
- write_zsreg(c, R15, c->regs[15]|1);
- write_zsreg(c, reg&0x0F, *rtable);
- if(reg>0x0F)
- write_zsreg(c, R15, c->regs[15]&~1);
- c->regs[reg]=*rtable++;
+ while (*rtable != 255) {
+ int reg = *rtable++;
+
+ if (reg > 0x0F)
+ write_zsreg(c, R15, c->regs[15] | 1);
+ write_zsreg(c, reg & 0x0F, *rtable);
+ if (reg > 0x0F)
+ write_zsreg(c, R15, c->regs[15] & ~1);
+ c->regs[reg] = *rtable++;
}
- c->rx_function=z8530_null_rx;
- c->skb=NULL;
- c->tx_skb=NULL;
- c->tx_next_skb=NULL;
- c->mtu=1500;
- c->max=0;
- c->count=0;
- c->status=read_zsreg(c, R0);
- c->sync=1;
- write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+ c->rx_function = z8530_null_rx;
+ c->skb = NULL;
+ c->tx_skb = NULL;
+ c->tx_next_skb = NULL;
+ c->mtu = 1500;
+ c->max = 0;
+ c->count = 0;
+ c->status = read_zsreg(c, R0);
+ c->sync = 1;
+ write_zsreg(c, R3, c->regs[R3] | RxENABLE);
spin_unlock_irqrestore(c->lock, flags);
return 0;
}
-
EXPORT_SYMBOL(z8530_channel_load);
-
/**
* z8530_tx_begin - Begin packet transmission
* @c: The Z8530 channel to kick
*
* This is the speed sensitive side of transmission. If we are called
* and no buffer is being transmitted we commence the next buffer. If
- * nothing is queued we idle the sync.
+ * nothing is queued we idle the sync.
*
* Note: We are handling this code path in the interrupt path, keep it
* fast or bad things will happen.
@@ -1426,85 +1313,68 @@ EXPORT_SYMBOL(z8530_channel_load);
static void z8530_tx_begin(struct z8530_channel *c)
{
unsigned long flags;
- if(c->tx_skb)
+
+ if (c->tx_skb)
return;
-
- c->tx_skb=c->tx_next_skb;
- c->tx_next_skb=NULL;
- c->tx_ptr=c->tx_next_ptr;
-
- if(c->tx_skb==NULL)
- {
+
+ c->tx_skb = c->tx_next_skb;
+ c->tx_next_skb = NULL;
+ c->tx_ptr = c->tx_next_ptr;
+
+ if (!c->tx_skb) {
/* Idle on */
- if(c->dma_tx)
- {
- flags=claim_dma_lock();
+ if (c->dma_tx) {
+ flags = claim_dma_lock();
disable_dma(c->txdma);
- /*
- * Check if we crapped out.
+ /* Check if we crapped out.
*/
- if (get_dma_residue(c->txdma))
- {
+ if (get_dma_residue(c->txdma)) {
c->netdevice->stats.tx_dropped++;
c->netdevice->stats.tx_fifo_errors++;
}
release_dma_lock(flags);
}
- c->txcount=0;
- }
- else
- {
- c->txcount=c->tx_skb->len;
-
-
- if(c->dma_tx)
- {
- /*
- * FIXME. DMA is broken for the original 8530,
+ c->txcount = 0;
+ } else {
+ c->txcount = c->tx_skb->len;
+
+ if (c->dma_tx) {
+ /* FIXME. DMA is broken for the original 8530,
* on the older parts we need to set a flag and
* wait for a further TX interrupt to fire this
- * stage off
+ * stage off
*/
-
- flags=claim_dma_lock();
+
+ flags = claim_dma_lock();
disable_dma(c->txdma);
- /*
- * These two are needed by the 8530/85C30
+ /* These two are needed by the 8530/85C30
* and must be issued when idling.
*/
-
- if(c->dev->type!=Z85230)
- {
+ if (c->dev->type != Z85230) {
write_zsctrl(c, RES_Tx_CRC);
write_zsctrl(c, RES_EOM_L);
- }
- write_zsreg(c, R10, c->regs[10]&~ABUNDER);
+ }
+ write_zsreg(c, R10, c->regs[10] & ~ABUNDER);
clear_dma_ff(c->txdma);
set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr));
set_dma_count(c->txdma, c->txcount);
enable_dma(c->txdma);
release_dma_lock(flags);
write_zsctrl(c, RES_EOM_L);
- write_zsreg(c, R5, c->regs[R5]|TxENAB);
- }
- else
- {
-
+ write_zsreg(c, R5, c->regs[R5] | TxENAB);
+ } else {
/* ABUNDER off */
write_zsreg(c, R10, c->regs[10]);
write_zsctrl(c, RES_Tx_CRC);
-
- while(c->txcount && (read_zsreg(c,R0)&Tx_BUF_EMP))
- {
+
+ while (c->txcount && (read_zsreg(c, R0) & Tx_BUF_EMP)) {
write_zsreg(c, R8, *c->tx_ptr++);
c->txcount--;
}
-
}
}
- /*
- * Since we emptied tx_skb we can ask for more
+ /* Since we emptied tx_skb we can ask for more
*/
netif_wake_queue(c->netdevice);
}
@@ -1525,7 +1395,7 @@ static void z8530_tx_done(struct z8530_channel *c)
struct sk_buff *skb;
/* Actually this can happen.*/
- if (c->tx_skb == NULL)
+ if (!c->tx_skb)
return;
skb = c->tx_skb;
@@ -1544,12 +1414,10 @@ static void z8530_tx_done(struct z8530_channel *c)
* We point the receive handler at this function when idle. Instead
* of processing the frames we get to throw them away.
*/
-
void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb)
{
dev_kfree_skb_any(skb);
}
-
EXPORT_SYMBOL(z8530_null_rx);
/**
@@ -1564,67 +1432,58 @@ EXPORT_SYMBOL(z8530_null_rx);
*
* Called with the lock held
*/
-
static void z8530_rx_done(struct z8530_channel *c)
{
struct sk_buff *skb;
int ct;
-
- /*
- * Is our receive engine in DMA mode
+
+ /* Is our receive engine in DMA mode
*/
-
- if(c->rxdma_on)
- {
- /*
- * Save the ready state and the buffer currently
+ if (c->rxdma_on) {
+ /* Save the ready state and the buffer currently
* being used as the DMA target
*/
-
- int ready=c->dma_ready;
- unsigned char *rxb=c->rx_buf[c->dma_num];
+ int ready = c->dma_ready;
+ unsigned char *rxb = c->rx_buf[c->dma_num];
unsigned long flags;
-
- /*
- * Complete this DMA. Necessary to find the length
- */
-
- flags=claim_dma_lock();
-
+
+ /* Complete this DMA. Necessary to find the length
+ */
+ flags = claim_dma_lock();
+
disable_dma(c->rxdma);
clear_dma_ff(c->rxdma);
- c->rxdma_on=0;
- ct=c->mtu-get_dma_residue(c->rxdma);
- if(ct<0)
- ct=2; /* Shit happens.. */
- c->dma_ready=0;
-
- /*
- * Normal case: the other slot is free, start the next DMA
+ c->rxdma_on = 0;
+ ct = c->mtu - get_dma_residue(c->rxdma);
+ if (ct < 0)
+ ct = 2; /* Shit happens.. */
+ c->dma_ready = 0;
+
+ /* Normal case: the other slot is free, start the next DMA
* into it immediately.
*/
-
- if(ready)
- {
- c->dma_num^=1;
- set_dma_mode(c->rxdma, DMA_MODE_READ|0x10);
+
+ if (ready) {
+ c->dma_num ^= 1;
+ set_dma_mode(c->rxdma, DMA_MODE_READ | 0x10);
set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[c->dma_num]));
set_dma_count(c->rxdma, c->mtu);
c->rxdma_on = 1;
enable_dma(c->rxdma);
- /* Stop any frames that we missed the head of
- from passing */
+ /* Stop any frames that we missed the head of
+ * from passing
+ */
write_zsreg(c, R0, RES_Rx_CRC);
- }
- else
+ } else {
/* Can't occur as we dont reenable the DMA irq until
- after the flip is done */
+ * after the flip is done
+ */
netdev_warn(c->netdevice, "DMA flip overrun!\n");
+ }
release_dma_lock(flags);
- /*
- * Shove the old buffer into an sk_buff. We can't DMA
+ /* Shove the old buffer into an sk_buff. We can't DMA
* directly into one on a PC - it might be above the 16Mb
* boundary. Optimisation - we could check to see if we
* can avoid the copy. Optimisation 2 - make the memcpy
@@ -1632,7 +1491,7 @@ static void z8530_rx_done(struct z8530_channel *c)
*/
skb = dev_alloc_skb(ct);
- if (skb == NULL) {
+ if (!skb) {
c->netdevice->stats.rx_dropped++;
netdev_warn(c->netdevice, "Memory squeeze\n");
} else {
@@ -1646,8 +1505,7 @@ static void z8530_rx_done(struct z8530_channel *c)
RT_LOCK;
skb = c->skb;
- /*
- * The game we play for non DMA is similar. We want to
+ /* The game we play for non DMA is similar. We want to
* get the controller set up for the next packet as fast
* as possible. We potentially only have one byte + the
* fifo length for this. Thus we want to flip to the new
@@ -1658,7 +1516,7 @@ static void z8530_rx_done(struct z8530_channel *c)
* sync IRQ for the RT_LOCK area.
*
*/
- ct=c->count;
+ ct = c->count;
c->skb = c->skb2;
c->count = 0;
@@ -1673,15 +1531,13 @@ static void z8530_rx_done(struct z8530_channel *c)
RT_UNLOCK;
c->skb2 = dev_alloc_skb(c->mtu);
- if (c->skb2 == NULL)
- netdev_warn(c->netdevice, "memory squeeze\n");
- else
+ if (c->skb2)
skb_put(c->skb2, c->mtu);
+
c->netdevice->stats.rx_packets++;
c->netdevice->stats.rx_bytes += ct;
}
- /*
- * If we received a frame we must now process it.
+ /* If we received a frame we must now process it.
*/
if (skb) {
skb_trim(skb, ct);
@@ -1702,9 +1558,10 @@ static void z8530_rx_done(struct z8530_channel *c)
static inline int spans_boundary(struct sk_buff *skb)
{
- unsigned long a=(unsigned long)skb->data;
- a^=(a+skb->len);
- if(a&0x00010000) /* If the 64K bit is different.. */
+ unsigned long a = (unsigned long)skb->data;
+
+ a ^= (a + skb->len);
+ if (a & 0x00010000) /* If the 64K bit is different.. */
return 1;
return 0;
}
@@ -1715,60 +1572,54 @@ static inline int spans_boundary(struct sk_buff *skb)
* @skb: The packet to kick down the channel
*
* Queue a packet for transmission. Because we have rather
- * hard to hit interrupt latencies for the Z85230 per packet
+ * hard to hit interrupt latencies for the Z85230 per packet
* even in DMA mode we do the flip to DMA buffer if needed here
* not in the IRQ.
*
- * Called from the network code. The lock is not held at this
+ * Called from the network code. The lock is not held at this
* point.
*/
-
netdev_tx_t z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb)
{
unsigned long flags;
-
+
netif_stop_queue(c->netdevice);
- if(c->tx_next_skb)
+ if (c->tx_next_skb)
return NETDEV_TX_BUSY;
-
/* PC SPECIFIC - DMA limits */
-
- /*
- * If we will DMA the transmit and its gone over the ISA bus
+ /* If we will DMA the transmit and its gone over the ISA bus
* limit, then copy to the flip buffer
*/
-
- if(c->dma_tx && ((unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024 || spans_boundary(skb)))
- {
- /*
- * Send the flip buffer, and flip the flippy bit.
+
+ if (c->dma_tx &&
+ ((unsigned long)(virt_to_bus(skb->data + skb->len)) >=
+ 16 * 1024 * 1024 || spans_boundary(skb))) {
+ /* Send the flip buffer, and flip the flippy bit.
* We don't care which is used when just so long as
* we never use the same buffer twice in a row. Since
* only one buffer can be going out at a time the other
* has to be safe.
*/
- c->tx_next_ptr=c->tx_dma_buf[c->tx_dma_used];
- c->tx_dma_used^=1; /* Flip temp buffer */
+ c->tx_next_ptr = c->tx_dma_buf[c->tx_dma_used];
+ c->tx_dma_used ^= 1; /* Flip temp buffer */
skb_copy_from_linear_data(skb, c->tx_next_ptr, skb->len);
+ } else {
+ c->tx_next_ptr = skb->data;
}
- else
- c->tx_next_ptr=skb->data;
RT_LOCK;
- c->tx_next_skb=skb;
+ c->tx_next_skb = skb;
RT_UNLOCK;
-
+
spin_lock_irqsave(c->lock, flags);
z8530_tx_begin(c);
spin_unlock_irqrestore(c->lock, flags);
-
+
return NETDEV_TX_OK;
}
-
EXPORT_SYMBOL(z8530_queue_xmit);
-/*
- * Module support
+/* Module support
*/
static const char banner[] __initconst =
KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n";
diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c
index 869524852fba..ab8f77ae5e66 100644
--- a/drivers/net/wireless/ath/ath10k/ahb.c
+++ b/drivers/net/wireless/ath/ath10k/ahb.c
@@ -442,14 +442,7 @@ static int ath10k_ahb_resource_init(struct ath10k *ar)
pdev = ar_ahb->pdev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ath10k_err(ar, "failed to get memory resource\n");
- ret = -ENXIO;
- goto out;
- }
-
- ar_ahb->mem = devm_ioremap_resource(&pdev->dev, res);
+ ar_ahb->mem = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(ar_ahb->mem)) {
ath10k_err(ar, "mem ioremap error\n");
ret = PTR_ERR(ar_ahb->mem);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 648ed36f845f..5aeff2d9f6cf 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -301,7 +301,7 @@ struct ath10k_fw_stats_pdev {
s32 underrun;
u32 hw_paused;
s32 tx_abort;
- s32 mpdus_requed;
+ s32 mpdus_requeued;
u32 tx_ko;
u32 data_rc;
u32 self_triggers;
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index fd052f6ed019..39378e3f9b2b 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1105,7 +1105,7 @@ static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
"d_tx_ppdu_reaped",
"d_tx_fifo_underrun",
"d_tx_ppdu_abort",
- "d_tx_mpdu_requed",
+ "d_tx_mpdu_requeued",
"d_tx_excessive_retries",
"d_tx_hw_rate",
"d_tx_dropped_sw_retries",
@@ -1205,7 +1205,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
data[i++] = pdev_stats->hw_reaped;
data[i++] = pdev_stats->underrun;
data[i++] = pdev_stats->tx_abort;
- data[i++] = pdev_stats->mpdus_requed;
+ data[i++] = pdev_stats->mpdus_requeued;
data[i++] = pdev_stats->tx_ko;
data[i++] = pdev_stats->data_rc;
data[i++] = pdev_stats->sw_retry_failure;
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index dbc8aef82a65..ec689e3ce48a 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -1283,8 +1283,8 @@ struct htt_dbg_stats_wal_tx_stats {
/* Num PPDUs cleaned up in TX abort */
__le32 tx_abort;
- /* Num MPDUs requed by SW */
- __le32 mpdus_requed;
+ /* Num MPDUs requeued by SW */
+ __le32 mpdus_requeued;
/* excessive retries */
__le32 tx_ko;
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 7ffb5d5b2a70..adbaeb67eedf 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1787,7 +1787,6 @@ static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar,
struct ath10k_peer *peer;
union htt_rx_pn_t *last_pn, new_pn = {0};
struct ieee80211_hdr *hdr;
- bool more_frags;
u8 tid, frag_number;
u32 seq;
@@ -1805,7 +1804,6 @@ static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar,
last_pn = &peer->frag_tids_last_pn[tid];
new_pn.pn48 = ath10k_htt_rx_h_get_pn(ar, skb, offset, enctype);
- more_frags = ieee80211_has_morefrags(hdr->frame_control);
frag_number = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
seq = (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 5ce4f8d038b9..c272b290fa73 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -5592,6 +5592,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
if (arvif->nohwcrypt &&
!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
+ ret = -EINVAL;
ath10k_warn(ar, "cryptmode module param needed for sw crypto\n");
goto err;
}
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index e7fde635e0ee..71878ab35b93 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -3685,8 +3685,10 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
if (bus_params.chip_id != 0xffffffff) {
if (!ath10k_pci_chip_is_supported(pdev->device,
- bus_params.chip_id))
+ bus_params.chip_id)) {
+ ret = -ENODEV;
goto err_unsupported;
+ }
}
}
@@ -3697,11 +3699,15 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
}
bus_params.chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
- if (bus_params.chip_id == 0xffffffff)
+ if (bus_params.chip_id == 0xffffffff) {
+ ret = -ENODEV;
goto err_unsupported;
+ }
- if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id))
- goto err_free_irq;
+ if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) {
+ ret = -ENODEV;
+ goto err_unsupported;
+ }
ret = ath10k_core_register(ar, &bus_params);
if (ret) {
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index 862d0901c5b8..cf64898b9447 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -235,7 +235,6 @@ u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe);
void ath10k_pci_hif_power_down(struct ath10k *ar);
int ath10k_pci_alloc_pipes(struct ath10k *ar);
void ath10k_pci_free_pipes(struct ath10k *ar);
-void ath10k_pci_free_pipes(struct ath10k *ar);
void ath10k_pci_rx_replenish_retry(struct timer_list *t);
void ath10k_pci_ce_deinit(struct ath10k *ar);
void ath10k_pci_init_napi(struct ath10k *ar);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index d48b922215eb..b8a4bbfe10b8 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2795,7 +2795,7 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
switch (ar->scan.state) {
case ATH10K_SCAN_IDLE:
case ATH10K_SCAN_STARTING:
- ath10k_warn(ar, "received chan info event without a scan request, ignoring\n");
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "received chan info event without a scan request, ignoring\n");
goto exit;
case ATH10K_SCAN_RUNNING:
case ATH10K_SCAN_ABORTING:
@@ -2867,7 +2867,7 @@ void ath10k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src,
dst->hw_reaped = __le32_to_cpu(src->hw_reaped);
dst->underrun = __le32_to_cpu(src->underrun);
dst->tx_abort = __le32_to_cpu(src->tx_abort);
- dst->mpdus_requed = __le32_to_cpu(src->mpdus_requed);
+ dst->mpdus_requeued = __le32_to_cpu(src->mpdus_requeued);
dst->tx_ko = __le32_to_cpu(src->tx_ko);
dst->data_rc = __le32_to_cpu(src->data_rc);
dst->self_triggers = __le32_to_cpu(src->self_triggers);
@@ -2895,7 +2895,7 @@ ath10k_wmi_10_4_pull_pdev_stats_tx(const struct wmi_10_4_pdev_stats_tx *src,
dst->hw_reaped = __le32_to_cpu(src->hw_reaped);
dst->underrun = __le32_to_cpu(src->underrun);
dst->tx_abort = __le32_to_cpu(src->tx_abort);
- dst->mpdus_requed = __le32_to_cpu(src->mpdus_requed);
+ dst->mpdus_requeued = __le32_to_cpu(src->mpdus_requeued);
dst->tx_ko = __le32_to_cpu(src->tx_ko);
dst->data_rc = __le32_to_cpu(src->data_rc);
dst->self_triggers = __le32_to_cpu(src->self_triggers);
@@ -8270,7 +8270,7 @@ ath10k_wmi_fw_pdev_tx_stats_fill(const struct ath10k_fw_stats_pdev *pdev,
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
"PPDUs cleaned", pdev->tx_abort);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "MPDUs requed", pdev->mpdus_requed);
+ "MPDUs requeued", pdev->mpdus_requeued);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
"Excessive retries", pdev->tx_ko);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index d870f7067cb7..41c1a3d339c2 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -4371,8 +4371,8 @@ struct wmi_pdev_stats_tx {
/* Num PPDUs cleaned up in TX abort */
__le32 tx_abort;
- /* Num MPDUs requed by SW */
- __le32 mpdus_requed;
+ /* Num MPDUs requeued by SW */
+ __le32 mpdus_requeued;
/* excessive retries */
__le32 tx_ko;
@@ -4444,8 +4444,8 @@ struct wmi_10_4_pdev_stats_tx {
/* Num PPDUs cleaned up in TX abort */
__le32 tx_abort;
- /* Num MPDUs requed by SW */
- __le32 mpdus_requed;
+ /* Num MPDUs requeued by SW */
+ __le32 mpdus_requeued;
/* excessive retries */
__le32 tx_ko;
@@ -7418,7 +7418,6 @@ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len);
int ath10k_wmi_connect(struct ath10k *ar);
-struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len);
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
u32 cmd_id);
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 77ce3347ab86..969bf1a590d9 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -70,6 +70,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.cold_boot_calib = true,
.supports_suspend = false,
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
+ .fix_l1ss = true,
},
{
.hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -110,6 +111,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.cold_boot_calib = true,
.supports_suspend = false,
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
+ .fix_l1ss = true,
},
{
.name = "qca6390 hw2.0",
@@ -149,6 +151,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.cold_boot_calib = false,
.supports_suspend = true,
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
+ .fix_l1ss = true,
},
{
.name = "qcn9074 hw1.0",
@@ -186,6 +189,47 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.cold_boot_calib = false,
.supports_suspend = false,
.hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074),
+ .fix_l1ss = true,
+ },
+ {
+ .name = "wcn6855 hw2.0",
+ .hw_rev = ATH11K_HW_WCN6855_HW20,
+ .fw = {
+ .dir = "WCN6855/hw2.0",
+ .board_size = 256 * 1024,
+ .cal_size = 256 * 1024,
+ },
+ .max_radios = 3,
+ .bdf_addr = 0x4B0C0000,
+ .hw_ops = &wcn6855_ops,
+ .ring_mask = &ath11k_hw_ring_mask_qca6390,
+ .internal_sleep_clock = true,
+ .regs = &wcn6855_regs,
+ .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390,
+ .host_ce_config = ath11k_host_ce_config_qca6390,
+ .ce_count = 9,
+ .target_ce_config = ath11k_target_ce_config_wlan_qca6390,
+ .target_ce_count = 9,
+ .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390,
+ .svc_to_ce_map_len = 14,
+ .single_pdev_only = true,
+ .rxdma1_enable = false,
+ .num_rxmda_per_pdev = 2,
+ .rx_mac_buf_ring = true,
+ .vdev_start_delay = true,
+ .htt_peer_map_v2 = false,
+ .tcl_0_only = true,
+ .spectral_fft_sz = 0,
+
+ .interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP),
+ .supports_monitor = false,
+ .supports_shadow_regs = true,
+ .idle_ps = true,
+ .cold_boot_calib = false,
+ .supports_suspend = true,
+ .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),
+ .fix_l1ss = false,
},
};
@@ -488,7 +532,8 @@ static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab,
if (len < ALIGN(ie_len, 4)) {
ath11k_err(ab, "invalid length for board ie_id %d ie_len %zu len %zu\n",
ie_id, ie_len, len);
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
switch (ie_id) {
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 55af982deca7..018fb2385f2a 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -107,6 +107,7 @@ enum ath11k_hw_rev {
ATH11K_HW_QCA6390_HW20,
ATH11K_HW_IPQ6018_HW10,
ATH11K_HW_QCN9074_HW10,
+ ATH11K_HW_WCN6855_HW20,
};
enum ath11k_firmware_mode {
@@ -795,8 +796,8 @@ struct ath11k_fw_stats_pdev {
s32 underrun;
/* Num PPDUs cleaned up in TX abort */
s32 tx_abort;
- /* Num MPDUs requed by SW */
- s32 mpdus_requed;
+ /* Num MPDUs requeued by SW */
+ s32 mpdus_requeued;
/* excessive retries */
u32 tx_ko;
/* data hw rate code */
diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
index ec93f14e6d2a..9e0c90da99d3 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
@@ -89,7 +89,7 @@ static inline void htt_print_tx_pdev_stats_cmn_tlv(const void *tag_buf,
len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_abort = %u",
htt_stats_buf->tx_abort);
len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_requeued = %u",
- htt_stats_buf->mpdu_requed);
+ htt_stats_buf->mpdu_requeued);
len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_xretry = %u",
htt_stats_buf->tx_xretry);
len += HTT_DBG_OUT(buf + len, buf_len - len, "data_rc = %u",
diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h
index 567a26d485a9..d428f52003a4 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h
+++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h
@@ -147,7 +147,7 @@ struct htt_tx_pdev_stats_cmn_tlv {
u32 hw_flush;
u32 hw_filt;
u32 tx_abort;
- u32 mpdu_requed;
+ u32 mpdu_requeued;
u32 tx_xretry;
u32 data_rc;
u32 mpdu_dropped_xretry;
diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c
index 04f6c4e0658b..b0c8f6290099 100644
--- a/drivers/net/wireless/ath/ath11k/dp.c
+++ b/drivers/net/wireless/ath/ath11k/dp.c
@@ -342,7 +342,6 @@ static int ath11k_dp_srng_common_setup(struct ath11k_base *ab)
struct ath11k_dp *dp = &ab->dp;
struct hal_srng *srng;
int i, ret;
- u32 ring_hash_map;
ret = ath11k_dp_srng_setup(ab, &dp->wbm_desc_rel_ring,
HAL_SW2WBM_RELEASE, 0, 0,
@@ -439,20 +438,9 @@ static int ath11k_dp_srng_common_setup(struct ath11k_base *ab)
}
/* When hash based routing of rx packet is enabled, 32 entries to map
- * the hash values to the ring will be configured. Each hash entry uses
- * three bits to map to a particular ring. The ring mapping will be
- * 0:TCL, 1:SW1, 2:SW2, 3:SW3, 4:SW4, 5:Release, 6:FW and 7:Not used.
+ * the hash values to the ring will be configured.
*/
- ring_hash_map = HAL_HASH_ROUTING_RING_SW1 << 0 |
- HAL_HASH_ROUTING_RING_SW2 << 3 |
- HAL_HASH_ROUTING_RING_SW3 << 6 |
- HAL_HASH_ROUTING_RING_SW4 << 9 |
- HAL_HASH_ROUTING_RING_SW1 << 12 |
- HAL_HASH_ROUTING_RING_SW2 << 15 |
- HAL_HASH_ROUTING_RING_SW3 << 18 |
- HAL_HASH_ROUTING_RING_SW4 << 21;
-
- ath11k_hal_reo_hw_setup(ab, ring_hash_map);
+ ab->hw_params.hw_ops->reo_setup(ab);
return 0;
diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c
index 08e3c72d9237..eaa0edca5576 100644
--- a/drivers/net/wireless/ath/ath11k/hal.c
+++ b/drivers/net/wireless/ath/ath11k/hal.c
@@ -382,6 +382,16 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab,
val = FIELD_PREP(HAL_REO1_RING_ID_ENTRY_SIZE, srng->entry_size);
ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_ID_OFFSET(ab), val);
+ if (srng->ring_id == HAL_SRNG_RING_ID_WBM_IDLE_LINK) {
+ ath11k_hif_write32(ab, reg_base, (u32)srng->ring_base_paddr);
+ val = FIELD_PREP(HAL_TCL1_RING_BASE_MSB_RING_BASE_ADDR_MSB,
+ ((u64)srng->ring_base_paddr >>
+ HAL_ADDR_MSB_REG_SHIFT)) |
+ FIELD_PREP(HAL_TCL1_RING_BASE_MSB_RING_SIZE,
+ (srng->entry_size * srng->num_entries));
+ ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_BASE_MSB_OFFSET(ab), val);
+ }
+
/* interrupt setup */
/* NOTE: IPQ8074 v2 requires the interrupt timer threshold in the
* unit of 8 usecs instead of 1 usec (as required by v1).
diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h
index 91d1428b8b94..35ed3a14e200 100644
--- a/drivers/net/wireless/ath/ath11k/hal.h
+++ b/drivers/net/wireless/ath/ath11k/hal.h
@@ -120,6 +120,7 @@ struct ath11k_base;
#define HAL_REO1_DEST_RING_CTRL_IX_1 0x00000008
#define HAL_REO1_DEST_RING_CTRL_IX_2 0x0000000c
#define HAL_REO1_DEST_RING_CTRL_IX_3 0x00000010
+#define HAL_REO1_MISC_CTL 0x00000630
#define HAL_REO1_RING_BASE_LSB(ab) ab->hw_params.regs->hal_reo1_ring_base_lsb
#define HAL_REO1_RING_BASE_MSB(ab) ab->hw_params.regs->hal_reo1_ring_base_msb
#define HAL_REO1_RING_ID(ab) ab->hw_params.regs->hal_reo1_ring_id
@@ -280,6 +281,7 @@ struct ath11k_base;
#define HAL_REO1_GEN_ENABLE_FRAG_DST_RING GENMASK(25, 23)
#define HAL_REO1_GEN_ENABLE_AGING_LIST_ENABLE BIT(2)
#define HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE BIT(3)
+#define HAL_REO1_MISC_CTL_FRAGMENT_DST_RING GENMASK(20, 17)
/* CE ring bit field mask and shift */
#define HAL_CE_DST_R0_DEST_CTRL_MAX_LEN GENMASK(15, 0)
@@ -906,7 +908,6 @@ void ath11k_hal_reo_qdesc_setup(void *vaddr, int tid, u32 ba_window_size,
u32 start_seq, enum hal_pn_type type);
void ath11k_hal_reo_init_cmd_ring(struct ath11k_base *ab,
struct hal_srng *srng);
-void ath11k_hal_reo_hw_setup(struct ath11k_base *ab, u32 ring_hash_map);
void ath11k_hal_setup_link_idle_list(struct ath11k_base *ab,
struct hal_wbm_idle_scatter_list *sbuf,
u32 nsbufs, u32 tot_link_desc,
diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.c b/drivers/net/wireless/ath/ath11k/hal_rx.c
index fac2396edf32..325055ca41ab 100644
--- a/drivers/net/wireless/ath/ath11k/hal_rx.c
+++ b/drivers/net/wireless/ath/ath11k/hal_rx.c
@@ -801,43 +801,6 @@ void ath11k_hal_reo_init_cmd_ring(struct ath11k_base *ab,
}
}
-void ath11k_hal_reo_hw_setup(struct ath11k_base *ab, u32 ring_hash_map)
-{
- u32 reo_base = HAL_SEQ_WCSS_UMAC_REO_REG;
- u32 val;
-
- val = ath11k_hif_read32(ab, reo_base + HAL_REO1_GEN_ENABLE);
-
- val &= ~HAL_REO1_GEN_ENABLE_FRAG_DST_RING;
- val |= FIELD_PREP(HAL_REO1_GEN_ENABLE_FRAG_DST_RING,
- HAL_SRNG_RING_ID_REO2SW1) |
- FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_LIST_ENABLE, 1) |
- FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE, 1);
- ath11k_hif_write32(ab, reo_base + HAL_REO1_GEN_ENABLE, val);
-
- ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_0(ab),
- HAL_DEFAULT_REO_TIMEOUT_USEC);
- ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_1(ab),
- HAL_DEFAULT_REO_TIMEOUT_USEC);
- ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_2(ab),
- HAL_DEFAULT_REO_TIMEOUT_USEC);
- ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_3(ab),
- HAL_DEFAULT_REO_TIMEOUT_USEC);
-
- ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_0,
- FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP,
- ring_hash_map));
- ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_1,
- FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP,
- ring_hash_map));
- ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_2,
- FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP,
- ring_hash_map));
- ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_3,
- FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP,
- ring_hash_map));
-}
-
static enum hal_rx_mon_status
ath11k_hal_rx_parse_mon_status_tlv(struct ath11k_base *ab,
struct hal_rx_mon_ppdu_info *ppdu_info,
@@ -1128,12 +1091,9 @@ ath11k_hal_rx_parse_mon_status_tlv(struct ath11k_base *ab,
break;
}
case HAL_RX_MPDU_START: {
- struct hal_rx_mpdu_info *mpdu_info =
- (struct hal_rx_mpdu_info *)tlv_data;
u16 peer_id;
- peer_id = FIELD_GET(HAL_RX_MPDU_INFO_INFO0_PEERID,
- __le32_to_cpu(mpdu_info->info0));
+ peer_id = ab->hw_params.hw_ops->mpdu_info_get_peerid(tlv_data);
if (peer_id)
ppdu_info->peer_id = peer_id;
break;
diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.h b/drivers/net/wireless/ath/ath11k/hal_rx.h
index d464a270c049..0f1f04b812b9 100644
--- a/drivers/net/wireless/ath/ath11k/hal_rx.h
+++ b/drivers/net/wireless/ath/ath11k/hal_rx.h
@@ -254,12 +254,20 @@ struct hal_rx_phyrx_rssi_legacy_info {
} __packed;
#define HAL_RX_MPDU_INFO_INFO0_PEERID GENMASK(31, 16)
+#define HAL_RX_MPDU_INFO_INFO0_PEERID_WCN6855 GENMASK(15, 0)
+
struct hal_rx_mpdu_info {
__le32 rsvd0;
__le32 info0;
__le32 rsvd1[21];
} __packed;
+struct hal_rx_mpdu_info_wcn6855 {
+ __le32 rsvd0[8];
+ __le32 info0;
+ __le32 rsvd1[14];
+} __packed;
+
#define HAL_RX_PPDU_END_DURATION GENMASK(23, 0)
struct hal_rx_ppdu_end_duration {
__le32 rsvd0[9];
diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c
index 377ae8d5b58f..d9596903b0a5 100644
--- a/drivers/net/wireless/ath/ath11k/hw.c
+++ b/drivers/net/wireless/ath/ath11k/hw.c
@@ -10,6 +10,7 @@
#include "hw.h"
#include "core.h"
#include "ce.h"
+#include "hif.h"
/* Map from pdev index to hw mac index */
static u8 ath11k_hw_ipq8074_mac_from_pdev_id(int pdev_idx)
@@ -45,6 +46,13 @@ static void ath11k_hw_qcn9074_tx_mesh_enable(struct ath11k_base *ab,
true);
}
+static void ath11k_hw_wcn6855_tx_mesh_enable(struct ath11k_base *ab,
+ struct hal_tcl_data_cmd *tcl_cmd)
+{
+ tcl_cmd->info3 |= FIELD_PREP(HAL_QCN9074_TCL_DATA_CMD_INFO3_MESH_ENABLE,
+ true);
+}
+
static void ath11k_init_wmi_config_qca6390(struct ath11k_base *ab,
struct target_resource_config *config)
{
@@ -91,6 +99,52 @@ static void ath11k_init_wmi_config_qca6390(struct ath11k_base *ab,
config->num_keep_alive_pattern = 0;
}
+static void ath11k_hw_ipq8074_reo_setup(struct ath11k_base *ab)
+{
+ u32 reo_base = HAL_SEQ_WCSS_UMAC_REO_REG;
+ u32 val;
+ /* Each hash entry uses three bits to map to a particular ring. */
+ u32 ring_hash_map = HAL_HASH_ROUTING_RING_SW1 << 0 |
+ HAL_HASH_ROUTING_RING_SW2 << 3 |
+ HAL_HASH_ROUTING_RING_SW3 << 6 |
+ HAL_HASH_ROUTING_RING_SW4 << 9 |
+ HAL_HASH_ROUTING_RING_SW1 << 12 |
+ HAL_HASH_ROUTING_RING_SW2 << 15 |
+ HAL_HASH_ROUTING_RING_SW3 << 18 |
+ HAL_HASH_ROUTING_RING_SW4 << 21;
+
+ val = ath11k_hif_read32(ab, reo_base + HAL_REO1_GEN_ENABLE);
+
+ val &= ~HAL_REO1_GEN_ENABLE_FRAG_DST_RING;
+ val |= FIELD_PREP(HAL_REO1_GEN_ENABLE_FRAG_DST_RING,
+ HAL_SRNG_RING_ID_REO2SW1) |
+ FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_LIST_ENABLE, 1) |
+ FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE, 1);
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_GEN_ENABLE, val);
+
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_0(ab),
+ HAL_DEFAULT_REO_TIMEOUT_USEC);
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_1(ab),
+ HAL_DEFAULT_REO_TIMEOUT_USEC);
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_2(ab),
+ HAL_DEFAULT_REO_TIMEOUT_USEC);
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_3(ab),
+ HAL_DEFAULT_REO_TIMEOUT_USEC);
+
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_0,
+ FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP,
+ ring_hash_map));
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_1,
+ FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP,
+ ring_hash_map));
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_2,
+ FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP,
+ ring_hash_map));
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_3,
+ FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP,
+ ring_hash_map));
+}
+
static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab,
struct target_resource_config *config)
{
@@ -489,6 +543,228 @@ static u8 *ath11k_hw_qcn9074_rx_desc_get_msdu_payload(struct hal_rx_desc *desc)
return &desc->u.qcn9074.msdu_payload[0];
}
+static bool ath11k_hw_wcn6855_rx_desc_get_first_msdu(struct hal_rx_desc *desc)
+{
+ return !!FIELD_GET(RX_MSDU_END_INFO2_FIRST_MSDU_WCN6855,
+ __le32_to_cpu(desc->u.wcn6855.msdu_end.info2));
+}
+
+static bool ath11k_hw_wcn6855_rx_desc_get_last_msdu(struct hal_rx_desc *desc)
+{
+ return !!FIELD_GET(RX_MSDU_END_INFO2_LAST_MSDU_WCN6855,
+ __le32_to_cpu(desc->u.wcn6855.msdu_end.info2));
+}
+
+static u8 ath11k_hw_wcn6855_rx_desc_get_l3_pad_bytes(struct hal_rx_desc *desc)
+{
+ return FIELD_GET(RX_MSDU_END_INFO2_L3_HDR_PADDING,
+ __le32_to_cpu(desc->u.wcn6855.msdu_end.info2));
+}
+
+static u8 *ath11k_hw_wcn6855_rx_desc_get_hdr_status(struct hal_rx_desc *desc)
+{
+ return desc->u.wcn6855.hdr_status;
+}
+
+static bool ath11k_hw_wcn6855_rx_desc_encrypt_valid(struct hal_rx_desc *desc)
+{
+ return __le32_to_cpu(desc->u.wcn6855.mpdu_start.info1) &
+ RX_MPDU_START_INFO1_ENCRYPT_INFO_VALID;
+}
+
+static u32 ath11k_hw_wcn6855_rx_desc_get_encrypt_type(struct hal_rx_desc *desc)
+{
+ return FIELD_GET(RX_MPDU_START_INFO2_ENC_TYPE,
+ __le32_to_cpu(desc->u.wcn6855.mpdu_start.info2));
+}
+
+static u8 ath11k_hw_wcn6855_rx_desc_get_decap_type(struct hal_rx_desc *desc)
+{
+ return FIELD_GET(RX_MSDU_START_INFO2_DECAP_FORMAT,
+ __le32_to_cpu(desc->u.wcn6855.msdu_start.info2));
+}
+
+static u8 ath11k_hw_wcn6855_rx_desc_get_mesh_ctl(struct hal_rx_desc *desc)
+{
+ return FIELD_GET(RX_MSDU_START_INFO2_MESH_CTRL_PRESENT,
+ __le32_to_cpu(desc->u.wcn6855.msdu_start.info2));
+}
+
+static bool ath11k_hw_wcn6855_rx_desc_get_mpdu_seq_ctl_vld(struct hal_rx_desc *desc)
+{
+ return !!FIELD_GET(RX_MPDU_START_INFO1_MPDU_SEQ_CTRL_VALID,
+ __le32_to_cpu(desc->u.wcn6855.mpdu_start.info1));
+}
+
+static bool ath11k_hw_wcn6855_rx_desc_get_mpdu_fc_valid(struct hal_rx_desc *desc)
+{
+ return !!FIELD_GET(RX_MPDU_START_INFO1_MPDU_FCTRL_VALID,
+ __le32_to_cpu(desc->u.wcn6855.mpdu_start.info1));
+}
+
+static u16 ath11k_hw_wcn6855_rx_desc_get_mpdu_start_seq_no(struct hal_rx_desc *desc)
+{
+ return FIELD_GET(RX_MPDU_START_INFO1_MPDU_SEQ_NUM,
+ __le32_to_cpu(desc->u.wcn6855.mpdu_start.info1));
+}
+
+static u16 ath11k_hw_wcn6855_rx_desc_get_msdu_len(struct hal_rx_desc *desc)
+{
+ return FIELD_GET(RX_MSDU_START_INFO1_MSDU_LENGTH,
+ __le32_to_cpu(desc->u.wcn6855.msdu_start.info1));
+}
+
+static u8 ath11k_hw_wcn6855_rx_desc_get_msdu_sgi(struct hal_rx_desc *desc)
+{
+ return FIELD_GET(RX_MSDU_START_INFO3_SGI,
+ __le32_to_cpu(desc->u.wcn6855.msdu_start.info3));
+}
+
+static u8 ath11k_hw_wcn6855_rx_desc_get_msdu_rate_mcs(struct hal_rx_desc *desc)
+{
+ return FIELD_GET(RX_MSDU_START_INFO3_RATE_MCS,
+ __le32_to_cpu(desc->u.wcn6855.msdu_start.info3));
+}
+
+static u8 ath11k_hw_wcn6855_rx_desc_get_msdu_rx_bw(struct hal_rx_desc *desc)
+{
+ return FIELD_GET(RX_MSDU_START_INFO3_RECV_BW,
+ __le32_to_cpu(desc->u.wcn6855.msdu_start.info3));
+}
+
+static u32 ath11k_hw_wcn6855_rx_desc_get_msdu_freq(struct hal_rx_desc *desc)
+{
+ return __le32_to_cpu(desc->u.wcn6855.msdu_start.phy_meta_data);
+}
+
+static u8 ath11k_hw_wcn6855_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc)
+{
+ return FIELD_GET(RX_MSDU_START_INFO3_PKT_TYPE,
+ __le32_to_cpu(desc->u.wcn6855.msdu_start.info3));
+}
+
+static u8 ath11k_hw_wcn6855_rx_desc_get_msdu_nss(struct hal_rx_desc *desc)
+{
+ return FIELD_GET(RX_MSDU_START_INFO3_MIMO_SS_BITMAP,
+ __le32_to_cpu(desc->u.wcn6855.msdu_start.info3));
+}
+
+static u8 ath11k_hw_wcn6855_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc)
+{
+ return FIELD_GET(RX_MPDU_START_INFO2_TID_WCN6855,
+ __le32_to_cpu(desc->u.wcn6855.mpdu_start.info2));
+}
+
+static u16 ath11k_hw_wcn6855_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc)
+{
+ return __le16_to_cpu(desc->u.wcn6855.mpdu_start.sw_peer_id);
+}
+
+static void ath11k_hw_wcn6855_rx_desc_copy_attn_end(struct hal_rx_desc *fdesc,
+ struct hal_rx_desc *ldesc)
+{
+ memcpy((u8 *)&fdesc->u.wcn6855.msdu_end, (u8 *)&ldesc->u.wcn6855.msdu_end,
+ sizeof(struct rx_msdu_end_wcn6855));
+ memcpy((u8 *)&fdesc->u.wcn6855.attention, (u8 *)&ldesc->u.wcn6855.attention,
+ sizeof(struct rx_attention));
+ memcpy((u8 *)&fdesc->u.wcn6855.mpdu_end, (u8 *)&ldesc->u.wcn6855.mpdu_end,
+ sizeof(struct rx_mpdu_end));
+}
+
+static u32 ath11k_hw_wcn6855_rx_desc_get_mpdu_start_tag(struct hal_rx_desc *desc)
+{
+ return FIELD_GET(HAL_TLV_HDR_TAG,
+ __le32_to_cpu(desc->u.wcn6855.mpdu_start_tag));
+}
+
+static u32 ath11k_hw_wcn6855_rx_desc_get_mpdu_ppdu_id(struct hal_rx_desc *desc)
+{
+ return __le16_to_cpu(desc->u.wcn6855.mpdu_start.phy_ppdu_id);
+}
+
+static void ath11k_hw_wcn6855_rx_desc_set_msdu_len(struct hal_rx_desc *desc, u16 len)
+{
+ u32 info = __le32_to_cpu(desc->u.wcn6855.msdu_start.info1);
+
+ info &= ~RX_MSDU_START_INFO1_MSDU_LENGTH;
+ info |= FIELD_PREP(RX_MSDU_START_INFO1_MSDU_LENGTH, len);
+
+ desc->u.wcn6855.msdu_start.info1 = __cpu_to_le32(info);
+}
+
+static
+struct rx_attention *ath11k_hw_wcn6855_rx_desc_get_attention(struct hal_rx_desc *desc)
+{
+ return &desc->u.wcn6855.attention;
+}
+
+static u8 *ath11k_hw_wcn6855_rx_desc_get_msdu_payload(struct hal_rx_desc *desc)
+{
+ return &desc->u.wcn6855.msdu_payload[0];
+}
+
+static void ath11k_hw_wcn6855_reo_setup(struct ath11k_base *ab)
+{
+ u32 reo_base = HAL_SEQ_WCSS_UMAC_REO_REG;
+ u32 val;
+ /* Each hash entry uses four bits to map to a particular ring. */
+ u32 ring_hash_map = HAL_HASH_ROUTING_RING_SW1 << 0 |
+ HAL_HASH_ROUTING_RING_SW2 << 4 |
+ HAL_HASH_ROUTING_RING_SW3 << 8 |
+ HAL_HASH_ROUTING_RING_SW4 << 12 |
+ HAL_HASH_ROUTING_RING_SW1 << 16 |
+ HAL_HASH_ROUTING_RING_SW2 << 20 |
+ HAL_HASH_ROUTING_RING_SW3 << 24 |
+ HAL_HASH_ROUTING_RING_SW4 << 28;
+
+ val = ath11k_hif_read32(ab, reo_base + HAL_REO1_GEN_ENABLE);
+ val |= FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_LIST_ENABLE, 1) |
+ FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE, 1);
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_GEN_ENABLE, val);
+
+ val = ath11k_hif_read32(ab, reo_base + HAL_REO1_MISC_CTL);
+ val &= ~HAL_REO1_MISC_CTL_FRAGMENT_DST_RING;
+ val |= FIELD_PREP(HAL_REO1_MISC_CTL_FRAGMENT_DST_RING, HAL_SRNG_RING_ID_REO2SW1);
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_MISC_CTL, val);
+
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_0(ab),
+ HAL_DEFAULT_REO_TIMEOUT_USEC);
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_1(ab),
+ HAL_DEFAULT_REO_TIMEOUT_USEC);
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_2(ab),
+ HAL_DEFAULT_REO_TIMEOUT_USEC);
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_3(ab),
+ HAL_DEFAULT_REO_TIMEOUT_USEC);
+
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_2,
+ ring_hash_map);
+ ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_3,
+ ring_hash_map);
+}
+
+static u16 ath11k_hw_ipq8074_mpdu_info_get_peerid(u8 *tlv_data)
+{
+ u16 peer_id = 0;
+ struct hal_rx_mpdu_info *mpdu_info =
+ (struct hal_rx_mpdu_info *)tlv_data;
+
+ peer_id = FIELD_GET(HAL_RX_MPDU_INFO_INFO0_PEERID,
+ __le32_to_cpu(mpdu_info->info0));
+
+ return peer_id;
+}
+
+static u16 ath11k_hw_wcn6855_mpdu_info_get_peerid(u8 *tlv_data)
+{
+ u16 peer_id = 0;
+ struct hal_rx_mpdu_info_wcn6855 *mpdu_info =
+ (struct hal_rx_mpdu_info_wcn6855 *)tlv_data;
+
+ peer_id = FIELD_GET(HAL_RX_MPDU_INFO_INFO0_PEERID_WCN6855,
+ __le32_to_cpu(mpdu_info->info0));
+ return peer_id;
+}
+
const struct ath11k_hw_ops ipq8074_ops = {
.get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id,
.wmi_init_config = ath11k_init_wmi_config_ipq8074,
@@ -521,6 +797,8 @@ const struct ath11k_hw_ops ipq8074_ops = {
.rx_desc_set_msdu_len = ath11k_hw_ipq8074_rx_desc_set_msdu_len,
.rx_desc_get_attention = ath11k_hw_ipq8074_rx_desc_get_attention,
.rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload,
+ .reo_setup = ath11k_hw_ipq8074_reo_setup,
+ .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid,
};
const struct ath11k_hw_ops ipq6018_ops = {
@@ -555,6 +833,8 @@ const struct ath11k_hw_ops ipq6018_ops = {
.rx_desc_set_msdu_len = ath11k_hw_ipq8074_rx_desc_set_msdu_len,
.rx_desc_get_attention = ath11k_hw_ipq8074_rx_desc_get_attention,
.rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload,
+ .reo_setup = ath11k_hw_ipq8074_reo_setup,
+ .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid,
};
const struct ath11k_hw_ops qca6390_ops = {
@@ -589,6 +869,8 @@ const struct ath11k_hw_ops qca6390_ops = {
.rx_desc_set_msdu_len = ath11k_hw_ipq8074_rx_desc_set_msdu_len,
.rx_desc_get_attention = ath11k_hw_ipq8074_rx_desc_get_attention,
.rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload,
+ .reo_setup = ath11k_hw_ipq8074_reo_setup,
+ .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid,
};
const struct ath11k_hw_ops qcn9074_ops = {
@@ -623,6 +905,44 @@ const struct ath11k_hw_ops qcn9074_ops = {
.rx_desc_set_msdu_len = ath11k_hw_qcn9074_rx_desc_set_msdu_len,
.rx_desc_get_attention = ath11k_hw_qcn9074_rx_desc_get_attention,
.rx_desc_get_msdu_payload = ath11k_hw_qcn9074_rx_desc_get_msdu_payload,
+ .reo_setup = ath11k_hw_ipq8074_reo_setup,
+ .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid,
+};
+
+const struct ath11k_hw_ops wcn6855_ops = {
+ .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id,
+ .wmi_init_config = ath11k_init_wmi_config_qca6390,
+ .mac_id_to_pdev_id = ath11k_hw_mac_id_to_pdev_id_qca6390,
+ .mac_id_to_srng_id = ath11k_hw_mac_id_to_srng_id_qca6390,
+ .tx_mesh_enable = ath11k_hw_wcn6855_tx_mesh_enable,
+ .rx_desc_get_first_msdu = ath11k_hw_wcn6855_rx_desc_get_first_msdu,
+ .rx_desc_get_last_msdu = ath11k_hw_wcn6855_rx_desc_get_last_msdu,
+ .rx_desc_get_l3_pad_bytes = ath11k_hw_wcn6855_rx_desc_get_l3_pad_bytes,
+ .rx_desc_get_hdr_status = ath11k_hw_wcn6855_rx_desc_get_hdr_status,
+ .rx_desc_encrypt_valid = ath11k_hw_wcn6855_rx_desc_encrypt_valid,
+ .rx_desc_get_encrypt_type = ath11k_hw_wcn6855_rx_desc_get_encrypt_type,
+ .rx_desc_get_decap_type = ath11k_hw_wcn6855_rx_desc_get_decap_type,
+ .rx_desc_get_mesh_ctl = ath11k_hw_wcn6855_rx_desc_get_mesh_ctl,
+ .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_wcn6855_rx_desc_get_mpdu_seq_ctl_vld,
+ .rx_desc_get_mpdu_fc_valid = ath11k_hw_wcn6855_rx_desc_get_mpdu_fc_valid,
+ .rx_desc_get_mpdu_start_seq_no = ath11k_hw_wcn6855_rx_desc_get_mpdu_start_seq_no,
+ .rx_desc_get_msdu_len = ath11k_hw_wcn6855_rx_desc_get_msdu_len,
+ .rx_desc_get_msdu_sgi = ath11k_hw_wcn6855_rx_desc_get_msdu_sgi,
+ .rx_desc_get_msdu_rate_mcs = ath11k_hw_wcn6855_rx_desc_get_msdu_rate_mcs,
+ .rx_desc_get_msdu_rx_bw = ath11k_hw_wcn6855_rx_desc_get_msdu_rx_bw,
+ .rx_desc_get_msdu_freq = ath11k_hw_wcn6855_rx_desc_get_msdu_freq,
+ .rx_desc_get_msdu_pkt_type = ath11k_hw_wcn6855_rx_desc_get_msdu_pkt_type,
+ .rx_desc_get_msdu_nss = ath11k_hw_wcn6855_rx_desc_get_msdu_nss,
+ .rx_desc_get_mpdu_tid = ath11k_hw_wcn6855_rx_desc_get_mpdu_tid,
+ .rx_desc_get_mpdu_peer_id = ath11k_hw_wcn6855_rx_desc_get_mpdu_peer_id,
+ .rx_desc_copy_attn_end_tlv = ath11k_hw_wcn6855_rx_desc_copy_attn_end,
+ .rx_desc_get_mpdu_start_tag = ath11k_hw_wcn6855_rx_desc_get_mpdu_start_tag,
+ .rx_desc_get_mpdu_ppdu_id = ath11k_hw_wcn6855_rx_desc_get_mpdu_ppdu_id,
+ .rx_desc_set_msdu_len = ath11k_hw_wcn6855_rx_desc_set_msdu_len,
+ .rx_desc_get_attention = ath11k_hw_wcn6855_rx_desc_get_attention,
+ .rx_desc_get_msdu_payload = ath11k_hw_wcn6855_rx_desc_get_msdu_payload,
+ .reo_setup = ath11k_hw_wcn6855_reo_setup,
+ .mpdu_info_get_peerid = ath11k_hw_wcn6855_mpdu_info_get_peerid,
};
#define ATH11K_TX_RING_MASK_0 0x1
@@ -1688,3 +2008,74 @@ const struct ath11k_hw_regs qcn9074_regs = {
.pcie_qserdes_sysclk_en_sel = 0x01e0e0a8,
.pcie_pcs_osc_dtct_config_base = 0x01e0f45c,
};
+
+const struct ath11k_hw_regs wcn6855_regs = {
+ /* SW2TCL(x) R0 ring configuration address */
+ .hal_tcl1_ring_base_lsb = 0x00000690,
+ .hal_tcl1_ring_base_msb = 0x00000694,
+ .hal_tcl1_ring_id = 0x00000698,
+ .hal_tcl1_ring_misc = 0x000006a0,
+ .hal_tcl1_ring_tp_addr_lsb = 0x000006ac,
+ .hal_tcl1_ring_tp_addr_msb = 0x000006b0,
+ .hal_tcl1_ring_consumer_int_setup_ix0 = 0x000006c0,
+ .hal_tcl1_ring_consumer_int_setup_ix1 = 0x000006c4,
+ .hal_tcl1_ring_msi1_base_lsb = 0x000006d8,
+ .hal_tcl1_ring_msi1_base_msb = 0x000006dc,
+ .hal_tcl1_ring_msi1_data = 0x000006e0,
+ .hal_tcl2_ring_base_lsb = 0x000006e8,
+ .hal_tcl_ring_base_lsb = 0x00000798,
+
+ /* TCL STATUS ring address */
+ .hal_tcl_status_ring_base_lsb = 0x000008a0,
+
+ /* REO2SW(x) R0 ring configuration address */
+ .hal_reo1_ring_base_lsb = 0x00000244,
+ .hal_reo1_ring_base_msb = 0x00000248,
+ .hal_reo1_ring_id = 0x0000024c,
+ .hal_reo1_ring_misc = 0x00000254,
+ .hal_reo1_ring_hp_addr_lsb = 0x00000258,
+ .hal_reo1_ring_hp_addr_msb = 0x0000025c,
+ .hal_reo1_ring_producer_int_setup = 0x00000268,
+ .hal_reo1_ring_msi1_base_lsb = 0x0000028c,
+ .hal_reo1_ring_msi1_base_msb = 0x00000290,
+ .hal_reo1_ring_msi1_data = 0x00000294,
+ .hal_reo2_ring_base_lsb = 0x0000029c,
+ .hal_reo1_aging_thresh_ix_0 = 0x000005bc,
+ .hal_reo1_aging_thresh_ix_1 = 0x000005c0,
+ .hal_reo1_aging_thresh_ix_2 = 0x000005c4,
+ .hal_reo1_aging_thresh_ix_3 = 0x000005c8,
+
+ /* REO2SW(x) R2 ring pointers (head/tail) address */
+ .hal_reo1_ring_hp = 0x00003030,
+ .hal_reo1_ring_tp = 0x00003034,
+ .hal_reo2_ring_hp = 0x00003038,
+
+ /* REO2TCL R0 ring configuration address */
+ .hal_reo_tcl_ring_base_lsb = 0x00000454,
+ .hal_reo_tcl_ring_hp = 0x00003060,
+
+ /* REO status address */
+ .hal_reo_status_ring_base_lsb = 0x0000055c,
+ .hal_reo_status_hp = 0x00003078,
+
+ /* WCSS relative address */
+ .hal_seq_wcss_umac_ce0_src_reg = 0x1b80000,
+ .hal_seq_wcss_umac_ce0_dst_reg = 0x1b81000,
+ .hal_seq_wcss_umac_ce1_src_reg = 0x1b82000,
+ .hal_seq_wcss_umac_ce1_dst_reg = 0x1b83000,
+
+ /* WBM Idle address */
+ .hal_wbm_idle_link_ring_base_lsb = 0x00000870,
+ .hal_wbm_idle_link_ring_misc = 0x00000880,
+
+ /* SW2WBM release address */
+ .hal_wbm_release_ring_base_lsb = 0x000001e8,
+
+ /* WBM2SW release address */
+ .hal_wbm0_release_ring_base_lsb = 0x00000920,
+ .hal_wbm1_release_ring_base_lsb = 0x00000978,
+
+ /* PCIe base address */
+ .pcie_qserdes_sysclk_en_sel = 0x01e0c0ac,
+ .pcie_pcs_osc_dtct_config_base = 0x01e0c628,
+};
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index c81a6328361d..62f5978b3005 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -162,6 +162,7 @@ struct ath11k_hw_params {
bool cold_boot_calib;
bool supports_suspend;
u32 hal_desc_sz;
+ bool fix_l1ss;
};
struct ath11k_hw_ops {
@@ -199,12 +200,15 @@ struct ath11k_hw_ops {
void (*rx_desc_set_msdu_len)(struct hal_rx_desc *desc, u16 len);
struct rx_attention *(*rx_desc_get_attention)(struct hal_rx_desc *desc);
u8 *(*rx_desc_get_msdu_payload)(struct hal_rx_desc *desc);
+ void (*reo_setup)(struct ath11k_base *ab);
+ u16 (*mpdu_info_get_peerid)(u8 *tlv_data);
};
extern const struct ath11k_hw_ops ipq8074_ops;
extern const struct ath11k_hw_ops ipq6018_ops;
extern const struct ath11k_hw_ops qca6390_ops;
extern const struct ath11k_hw_ops qcn9074_ops;
+extern const struct ath11k_hw_ops wcn6855_ops;
extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074;
extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390;
@@ -318,5 +322,6 @@ struct ath11k_hw_regs {
extern const struct ath11k_hw_regs ipq8074_regs;
extern const struct ath11k_hw_regs qca6390_regs;
extern const struct ath11k_hw_regs qcn9074_regs;
+extern const struct ath11k_hw_regs wcn6855_regs;
#endif
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index 9d0ff150ec30..e9b3689331ec 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -1314,10 +1314,16 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar,
arg->he_flag = true;
- memcpy(&arg->peer_he_cap_macinfo, he_cap->he_cap_elem.mac_cap_info,
- sizeof(arg->peer_he_cap_macinfo));
- memcpy(&arg->peer_he_cap_phyinfo, he_cap->he_cap_elem.phy_cap_info,
- sizeof(arg->peer_he_cap_phyinfo));
+ memcpy_and_pad(&arg->peer_he_cap_macinfo,
+ sizeof(arg->peer_he_cap_macinfo),
+ he_cap->he_cap_elem.mac_cap_info,
+ sizeof(he_cap->he_cap_elem.mac_cap_info),
+ 0);
+ memcpy_and_pad(&arg->peer_he_cap_phyinfo,
+ sizeof(arg->peer_he_cap_phyinfo),
+ he_cap->he_cap_elem.phy_cap_info,
+ sizeof(he_cap->he_cap_elem.phy_cap_info),
+ 0);
arg->peer_he_ops = vif->bss_conf.he_oper.params;
/* the top most byte is used to indicate BSS color info */
@@ -5379,11 +5385,6 @@ ath11k_mac_update_vif_chan(struct ath11k *ar,
if (WARN_ON(!arvif->is_up))
continue;
- ret = ath11k_mac_setup_bcn_tmpl(arvif);
- if (ret)
- ath11k_warn(ab, "failed to update bcn tmpl during csa: %d\n",
- ret);
-
ret = ath11k_mac_vdev_restart(arvif, &vifs[i].new_ctx->def);
if (ret) {
ath11k_warn(ab, "failed to restart vdev %d: %d\n",
@@ -5391,6 +5392,11 @@ ath11k_mac_update_vif_chan(struct ath11k *ar,
continue;
}
+ ret = ath11k_mac_setup_bcn_tmpl(arvif);
+ if (ret)
+ ath11k_warn(ab, "failed to update bcn tmpl during csa: %d\n",
+ ret);
+
ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
arvif->bssid);
if (ret) {
diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c
index 27b394d115e2..75cc2d80fde8 100644
--- a/drivers/net/wireless/ath/ath11k/mhi.c
+++ b/drivers/net/wireless/ath/ath11k/mhi.c
@@ -354,6 +354,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
ath11k_mhi_config = &ath11k_mhi_config_qcn9074;
break;
case ATH11K_HW_QCA6390_HW20:
+ case ATH11K_HW_WCN6855_HW20:
ath11k_mhi_config = &ath11k_mhi_config_qca6390;
break;
default:
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index 0f31eb566fb6..646ad79f309c 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -36,10 +36,12 @@
#define QCA6390_DEVICE_ID 0x1101
#define QCN9074_DEVICE_ID 0x1104
+#define WCN6855_DEVICE_ID 0x1103
static const struct pci_device_id ath11k_pci_id_table[] = {
{ PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) },
- /* TODO: add QCN9074_DEVICE_ID) once firmware issues are resolved */
+ { PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) },
+ { PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) },
{0}
};
@@ -432,7 +434,8 @@ static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
ath11k_pci_enable_ltssm(ab);
ath11k_pci_clear_all_intrs(ab);
ath11k_pci_set_wlaon_pwr_ctrl(ab);
- ath11k_pci_fix_l1ss(ab);
+ if (ab->hw_params.fix_l1ss)
+ ath11k_pci_fix_l1ss(ab);
}
ath11k_mhi_clear_vector(ab);
@@ -1176,12 +1179,26 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
.get_ce_msi_idx = ath11k_pci_get_ce_msi_idx,
};
+static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor)
+{
+ u32 soc_hw_version;
+
+ soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
+ *major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
+ soc_hw_version);
+ *minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
+ soc_hw_version);
+
+ ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
+ *major, *minor);
+}
+
static int ath11k_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_dev)
{
struct ath11k_base *ab;
struct ath11k_pci *ab_pci;
- u32 soc_hw_version, soc_hw_version_major, soc_hw_version_minor;
+ u32 soc_hw_version_major, soc_hw_version_minor;
int ret;
ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
@@ -1209,15 +1226,8 @@ static int ath11k_pci_probe(struct pci_dev *pdev,
switch (pci_dev->device) {
case QCA6390_DEVICE_ID:
- soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
- soc_hw_version_major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
- soc_hw_version);
- soc_hw_version_minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
- soc_hw_version);
-
- ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
- soc_hw_version_major, soc_hw_version_minor);
-
+ ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
+ &soc_hw_version_minor);
switch (soc_hw_version_major) {
case 2:
ab->hw_rev = ATH11K_HW_QCA6390_HW20;
@@ -1235,6 +1245,21 @@ static int ath11k_pci_probe(struct pci_dev *pdev,
ab->bus_params.static_window_map = true;
ab->hw_rev = ATH11K_HW_QCN9074_HW10;
break;
+ case WCN6855_DEVICE_ID:
+ ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
+ &soc_hw_version_minor);
+ switch (soc_hw_version_major) {
+ case 2:
+ ab->hw_rev = ATH11K_HW_WCN6855_HW20;
+ break;
+ default:
+ dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n",
+ soc_hw_version_major, soc_hw_version_minor);
+ ret = -EOPNOTSUPP;
+ goto err_pci_free_region;
+ }
+ ab_pci->msi_config = &ath11k_msi_config[0];
+ break;
default:
dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
pci_dev->device);
diff --git a/drivers/net/wireless/ath/ath11k/rx_desc.h b/drivers/net/wireless/ath/ath11k/rx_desc.h
index 0cdb4a1f816e..79c50804d7dc 100644
--- a/drivers/net/wireless/ath/ath11k/rx_desc.h
+++ b/drivers/net/wireless/ath/ath11k/rx_desc.h
@@ -368,6 +368,7 @@ struct rx_attention {
#define RX_MPDU_START_INFO2_BSSID_HIT BIT(9)
#define RX_MPDU_START_INFO2_BSSID_NUM GENMASK(13, 10)
#define RX_MPDU_START_INFO2_TID GENMASK(17, 14)
+#define RX_MPDU_START_INFO2_TID_WCN6855 GENMASK(18, 15)
#define RX_MPDU_START_INFO3_REO_DEST_IND GENMASK(4, 0)
#define RX_MPDU_START_INFO3_FLOW_ID_TOEPLITZ BIT(7)
@@ -546,6 +547,31 @@ struct rx_mpdu_start_qcn9074 {
__le32 ht_ctrl;
} __packed;
+struct rx_mpdu_start_wcn6855 {
+ __le32 info3;
+ __le32 reo_queue_desc_lo;
+ __le32 info4;
+ __le32 pn[4];
+ __le32 info2;
+ __le32 peer_meta_data;
+ __le16 info0;
+ __le16 phy_ppdu_id;
+ __le16 ast_index;
+ __le16 sw_peer_id;
+ __le32 info1;
+ __le32 info5;
+ __le32 info6;
+ __le16 frame_ctrl;
+ __le16 duration;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ __le16 seq_ctrl;
+ u8 addr4[ETH_ALEN];
+ __le16 qos_ctrl;
+ __le32 ht_ctrl;
+} __packed;
+
/* rx_mpdu_start
*
* rxpcu_mpdu_filter_in_category
@@ -804,6 +830,20 @@ struct rx_msdu_start_qcn9074 {
__le16 vlan_stag_c1;
} __packed;
+struct rx_msdu_start_wcn6855 {
+ __le16 info0;
+ __le16 phy_ppdu_id;
+ __le32 info1;
+ __le32 info2;
+ __le32 toeplitz_hash;
+ __le32 flow_id_toeplitz;
+ __le32 info3;
+ __le32 ppdu_start_timestamp;
+ __le32 phy_meta_data;
+ __le16 vlan_ctag_ci;
+ __le16 vlan_stag_ci;
+} __packed;
+
/* rx_msdu_start
*
* rxpcu_mpdu_filter_in_category
@@ -988,7 +1028,9 @@ struct rx_msdu_start_qcn9074 {
#define RX_MSDU_END_INFO2_REPORTED_MPDU_LEN GENMASK(13, 0)
#define RX_MSDU_END_INFO2_FIRST_MSDU BIT(14)
+#define RX_MSDU_END_INFO2_FIRST_MSDU_WCN6855 BIT(28)
#define RX_MSDU_END_INFO2_LAST_MSDU BIT(15)
+#define RX_MSDU_END_INFO2_LAST_MSDU_WCN6855 BIT(29)
#define RX_MSDU_END_INFO2_SA_IDX_TIMEOUT BIT(16)
#define RX_MSDU_END_INFO2_DA_IDX_TIMEOUT BIT(17)
#define RX_MSDU_END_INFO2_MSDU_LIMIT_ERR BIT(18)
@@ -1037,6 +1079,31 @@ struct rx_msdu_end_ipq8074 {
__le16 sa_sw_peer_id;
} __packed;
+struct rx_msdu_end_wcn6855 {
+ __le16 info0;
+ __le16 phy_ppdu_id;
+ __le16 ip_hdr_cksum;
+ __le16 reported_mpdu_len;
+ __le32 info1;
+ __le32 ext_wapi_pn[2];
+ __le32 info4;
+ __le32 ipv6_options_crc;
+ __le32 tcp_seq_num;
+ __le32 tcp_ack_num;
+ __le16 info3;
+ __le16 window_size;
+ __le32 info2;
+ __le16 sa_idx;
+ __le16 da_idx;
+ __le32 info5;
+ __le32 fse_metadata;
+ __le16 cce_metadata;
+ __le16 sa_sw_peer_id;
+ __le32 rule_indication[2];
+ __le32 info6;
+ __le32 info7;
+} __packed;
+
#define RX_MSDU_END_MPDU_LENGTH_INFO GENMASK(13, 0)
#define RX_MSDU_END_INFO2_DA_OFFSET GENMASK(5, 0)
@@ -1400,10 +1467,30 @@ struct hal_rx_desc_qcn9074 {
u8 msdu_payload[0];
} __packed;
+struct hal_rx_desc_wcn6855 {
+ __le32 msdu_end_tag;
+ struct rx_msdu_end_wcn6855 msdu_end;
+ __le32 rx_attn_tag;
+ struct rx_attention attention;
+ __le32 msdu_start_tag;
+ struct rx_msdu_start_wcn6855 msdu_start;
+ u8 rx_padding0[HAL_RX_DESC_PADDING0_BYTES];
+ __le32 mpdu_start_tag;
+ struct rx_mpdu_start_wcn6855 mpdu_start;
+ __le32 mpdu_end_tag;
+ struct rx_mpdu_end mpdu_end;
+ u8 rx_padding1[HAL_RX_DESC_PADDING1_BYTES];
+ __le32 hdr_status_tag;
+ __le32 phy_ppdu_id;
+ u8 hdr_status[HAL_RX_DESC_HDR_STATUS_LEN];
+ u8 msdu_payload[0];
+} __packed;
+
struct hal_rx_desc {
union {
struct hal_rx_desc_ipq8074 ipq8074;
struct hal_rx_desc_qcn9074 qcn9074;
+ struct hal_rx_desc_wcn6855 wcn6855;
} u;
} __packed;
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
index 5ca2d80679b6..6c253eae9d06 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -5235,7 +5235,7 @@ ath11k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src,
dst->hw_reaped = src->hw_reaped;
dst->underrun = src->underrun;
dst->tx_abort = src->tx_abort;
- dst->mpdus_requed = src->mpdus_requed;
+ dst->mpdus_requeued = src->mpdus_requeued;
dst->tx_ko = src->tx_ko;
dst->data_rc = src->data_rc;
dst->self_triggers = src->self_triggers;
@@ -5505,7 +5505,7 @@ ath11k_wmi_fw_pdev_tx_stats_fill(const struct ath11k_fw_stats_pdev *pdev,
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
"PPDUs cleaned", pdev->tx_abort);
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- "MPDUs requed", pdev->mpdus_requed);
+ "MPDUs requeued", pdev->mpdus_requeued);
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
"Excessive retries", pdev->tx_ko);
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h
index 3ade1ddd35c9..d35c47e0b19d 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -4171,8 +4171,8 @@ struct wmi_pdev_stats_tx {
/* Num PPDUs cleaned up in TX abort */
s32 tx_abort;
- /* Num MPDUs requed by SW */
- s32 mpdus_requed;
+ /* Num MPDUs requeued by SW */
+ s32 mpdus_requeued;
/* excessive retries */
u32 tx_ko;
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index f2db7cf16566..3f4ce4e9c532 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -855,7 +855,7 @@ ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
}
/**
- * at5k_hw_stop_rx_pcu() - Stop RX engine
+ * ath5k_hw_stop_rx_pcu() - Stop RX engine
* @ah: The &struct ath5k_hw
*
* Stops RX engine on PCU
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 29527e8dcced..fefdc6753acd 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -3303,8 +3303,8 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
if (ret < 0)
return ret;
} else {
- ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
- MATCHED_SSID_FILTER, 0);
+ ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
+ MATCHED_SSID_FILTER, 0);
if (ret < 0)
return ret;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 76b538942a79..5184a0aacfe2 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -522,6 +522,8 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0;
rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7);
rxs->enc_flags |= (rxsp->status4 & AR_GI) ? RX_ENC_FLAG_SHORT_GI : 0;
+ rxs->enc_flags |=
+ (rxsp->status4 & AR_STBC) ? (1 << RX_ENC_FLAG_STBC_SHIFT) : 0;
rxs->bw = (rxsp->status4 & AR_2040) ? RATE_INFO_BW_40 : RATE_INFO_BW_20;
rxs->evm0 = rxsp->status6;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 45f6402478b5..139831539da3 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -307,6 +307,11 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
hchan = ah->curchan;
}
+ if (!hchan) {
+ fastcc = false;
+ hchan = ath9k_cmn_get_channel(sc->hw, ah, &sc->cur_chan->chandef);
+ }
+
if (!ath_prepare_reset(sc))
fastcc = false;
@@ -2649,7 +2654,7 @@ static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw,
static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- u16 duration)
+ struct ieee80211_prep_tx_info *info)
{
struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
diff --git a/drivers/net/wireless/ath/carl9170/Kconfig b/drivers/net/wireless/ath/carl9170/Kconfig
index b2d760873992..ba9bea79381c 100644
--- a/drivers/net/wireless/ath/carl9170/Kconfig
+++ b/drivers/net/wireless/ath/carl9170/Kconfig
@@ -16,13 +16,11 @@ config CARL9170
config CARL9170_LEDS
bool "SoftLED Support"
- depends on CARL9170
- select MAC80211_LEDS
- select LEDS_CLASS
- select NEW_LEDS
default y
+ depends on CARL9170
+ depends on MAC80211_LEDS
help
- This option is necessary, if you want your device' LEDs to blink
+ This option is necessary, if you want your device's LEDs to blink.
Say Y, unless you need the LEDs for firmware debugging.
diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c
index eae9abf540a7..b53ebb3ac9a2 100644
--- a/drivers/net/wireless/ath/hw.c
+++ b/drivers/net/wireless/ath/hw.c
@@ -24,7 +24,7 @@
#define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg)
/**
- * ath_hw_set_bssid_mask - filter out bssids we listen
+ * ath_hw_setbssidmask - filter out bssids we listen
*
* @common: the ath_common struct for the device.
*
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
index 63079231e48e..8e1dbfda6538 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.c
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
@@ -800,7 +800,7 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
(char *)ctl_skb->skb->data, ctl_skb->skb->len);
/* Move the head of the ring to the next empty descriptor */
- ch->head_blk_ctl = ctl_skb->next;
+ ch->head_blk_ctl = ctl_skb->next;
/* Commit all previous writes and set descriptors to VALID */
wmb();
diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h
index 65ef893f2736..455143c4164e 100644
--- a/drivers/net/wireless/ath/wcn36xx/hal.h
+++ b/drivers/net/wireless/ath/wcn36xx/hal.h
@@ -3464,8 +3464,12 @@ struct wcn36xx_hal_rem_bcn_filter_req {
#define WCN36XX_HAL_OFFLOAD_DISABLE 0
#define WCN36XX_HAL_OFFLOAD_ENABLE 1
#define WCN36XX_HAL_OFFLOAD_BCAST_FILTER_ENABLE 0x2
+#define WCN36XX_HAL_OFFLOAD_MCAST_FILTER_ENABLE 0x4
+#define WCN36XX_HAL_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE \
+ (WCN36XX_HAL_OFFLOAD_ENABLE | WCN36XX_HAL_OFFLOAD_MCAST_FILTER_ENABLE)
#define WCN36XX_HAL_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE \
- (HAL_OFFLOAD_ENABLE|HAL_OFFLOAD_BCAST_FILTER_ENABLE)
+ (WCN36XX_HAL_OFFLOAD_ENABLE | WCN36XX_HAL_OFFLOAD_BCAST_FILTER_ENABLE)
+#define WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX 0x02
struct wcn36xx_hal_ns_offload_params {
u8 src_ipv6_addr[WCN36XX_HAL_IPV6_ADDR_LEN];
@@ -3487,10 +3491,10 @@ struct wcn36xx_hal_ns_offload_params {
/* slot index for this offload */
u32 slot_index;
u8 bss_index;
-};
+} __packed;
struct wcn36xx_hal_host_offload_req {
- u8 offload_Type;
+ u8 offload_type;
/* enable or disable */
u8 enable;
@@ -3499,13 +3503,13 @@ struct wcn36xx_hal_host_offload_req {
u8 host_ipv4_addr[4];
u8 host_ipv6_addr[WCN36XX_HAL_IPV6_ADDR_LEN];
} u;
-};
+} __packed;
struct wcn36xx_hal_host_offload_req_msg {
struct wcn36xx_hal_msg_header header;
struct wcn36xx_hal_host_offload_req host_offload_params;
struct wcn36xx_hal_ns_offload_params ns_offload_params;
-};
+} __packed;
/* Packet Types. */
#define WCN36XX_HAL_KEEP_ALIVE_NULL_PKT 1
@@ -4901,7 +4905,7 @@ struct wcn36xx_hal_gtk_offload_req_msg {
u64 key_replay_counter;
u8 bss_index;
-};
+} __packed;
struct wcn36xx_hal_gtk_offload_rsp_msg {
struct wcn36xx_hal_msg_header header;
@@ -4915,7 +4919,7 @@ struct wcn36xx_hal_gtk_offload_rsp_msg {
struct wcn36xx_hal_gtk_offload_get_info_req_msg {
struct wcn36xx_hal_msg_header header;
u8 bss_index;
-};
+} __packed;
struct wcn36xx_hal_gtk_offload_get_info_rsp_msg {
struct wcn36xx_hal_msg_header header;
@@ -4939,7 +4943,7 @@ struct wcn36xx_hal_gtk_offload_get_info_rsp_msg {
u32 igtk_rekey_count;
u8 bss_index;
-};
+} __packed;
struct dhcp_info {
/* Indicates the device mode which indicates about the DHCP activity */
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index afb4877eaad8..d202f2128df2 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -25,6 +25,7 @@
#include <linux/rpmsg.h>
#include <linux/soc/qcom/smem_state.h>
#include <linux/soc/qcom/wcnss_ctrl.h>
+#include <net/ipv6.h>
#include "wcn36xx.h"
#include "testmode.h"
@@ -172,7 +173,9 @@ static struct ieee80211_supported_band wcn_band_5ghz = {
#ifdef CONFIG_PM
static const struct wiphy_wowlan_support wowlan_support = {
- .flags = WIPHY_WOWLAN_ANY
+ .flags = WIPHY_WOWLAN_ANY |
+ WIPHY_WOWLAN_MAGIC_PKT |
+ WIPHY_WOWLAN_SUPPORTS_GTK_REKEY
};
#endif
@@ -293,23 +296,16 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
goto out_free_dxe_pool;
}
- wcn->hal_buf = kmalloc(WCN36XX_HAL_BUF_SIZE, GFP_KERNEL);
- if (!wcn->hal_buf) {
- wcn36xx_err("Failed to allocate smd buf\n");
- ret = -ENOMEM;
- goto out_free_dxe_ctl;
- }
-
ret = wcn36xx_smd_load_nv(wcn);
if (ret) {
wcn36xx_err("Failed to push NV to chip\n");
- goto out_free_smd_buf;
+ goto out_free_dxe_ctl;
}
ret = wcn36xx_smd_start(wcn);
if (ret) {
wcn36xx_err("Failed to start chip\n");
- goto out_free_smd_buf;
+ goto out_free_dxe_ctl;
}
if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
@@ -336,8 +332,6 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
out_smd_stop:
wcn36xx_smd_stop(wcn);
-out_free_smd_buf:
- kfree(wcn->hal_buf);
out_free_dxe_ctl:
wcn36xx_dxe_free_ctl_blks(wcn);
out_free_dxe_pool:
@@ -372,8 +366,6 @@ static void wcn36xx_stop(struct ieee80211_hw *hw)
wcn36xx_dxe_free_mem_pools(wcn);
wcn36xx_dxe_free_ctl_blks(wcn);
-
- kfree(wcn->hal_buf);
}
static void wcn36xx_change_ps(struct wcn36xx *wcn, bool enable)
@@ -1088,28 +1080,91 @@ static int wcn36xx_sta_remove(struct ieee80211_hw *hw,
#ifdef CONFIG_PM
+static struct ieee80211_vif *wcn36xx_get_first_assoc_vif(struct wcn36xx *wcn)
+{
+ struct wcn36xx_vif *vif_priv = NULL;
+ struct ieee80211_vif *vif = NULL;
+
+ list_for_each_entry(vif_priv, &wcn->vif_list, list) {
+ if (vif_priv->sta_assoc) {
+ vif = wcn36xx_priv_to_vif(vif_priv);
+ break;
+ }
+ }
+ return vif;
+}
+
static int wcn36xx_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow)
{
struct wcn36xx *wcn = hw->priv;
+ struct ieee80211_vif *vif = NULL;
+ int ret = 0;
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac suspend\n");
- flush_workqueue(wcn->hal_ind_wq);
- wcn36xx_smd_set_power_params(wcn, true);
- return 0;
+ mutex_lock(&wcn->conf_mutex);
+
+ vif = wcn36xx_get_first_assoc_vif(wcn);
+ if (vif) {
+ ret = wcn36xx_smd_arp_offload(wcn, vif, true);
+ if (ret)
+ goto out;
+ ret = wcn36xx_smd_ipv6_ns_offload(wcn, vif, true);
+ if (ret)
+ goto out;
+ ret = wcn36xx_smd_gtk_offload(wcn, vif, true);
+ if (ret)
+ goto out;
+ ret = wcn36xx_smd_set_power_params(wcn, true);
+ if (ret)
+ goto out;
+ ret = wcn36xx_smd_wlan_host_suspend_ind(wcn);
+ }
+out:
+ mutex_unlock(&wcn->conf_mutex);
+ return ret;
}
static int wcn36xx_resume(struct ieee80211_hw *hw)
{
struct wcn36xx *wcn = hw->priv;
+ struct ieee80211_vif *vif = NULL;
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac resume\n");
- flush_workqueue(wcn->hal_ind_wq);
- wcn36xx_smd_set_power_params(wcn, false);
+ mutex_lock(&wcn->conf_mutex);
+ vif = wcn36xx_get_first_assoc_vif(wcn);
+ if (vif) {
+ wcn36xx_smd_host_resume(wcn);
+ wcn36xx_smd_set_power_params(wcn, false);
+ wcn36xx_smd_gtk_offload_get_info(wcn, vif);
+ wcn36xx_smd_gtk_offload(wcn, vif, false);
+ wcn36xx_smd_ipv6_ns_offload(wcn, vif, false);
+ wcn36xx_smd_arp_offload(wcn, vif, false);
+ }
+ mutex_unlock(&wcn->conf_mutex);
+
return 0;
}
+static void wcn36xx_set_rekey_data(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_gtk_rekey_data *data)
+{
+ struct wcn36xx *wcn = hw->priv;
+ struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
+
+ mutex_lock(&wcn->conf_mutex);
+
+ memcpy(vif_priv->rekey_data.kek, data->kek, NL80211_KEK_LEN);
+ memcpy(vif_priv->rekey_data.kck, data->kck, NL80211_KCK_LEN);
+ vif_priv->rekey_data.replay_ctr =
+ cpu_to_le64(be64_to_cpup((__be64 *)data->replay_ctr));
+ vif_priv->rekey_data.valid = true;
+
+ mutex_unlock(&wcn->conf_mutex);
+}
+
#endif
static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
@@ -1176,6 +1231,34 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
return ret;
}
+#if IS_ENABLED(CONFIG_IPV6)
+static void wcn36xx_ipv6_addr_change(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct inet6_dev *idev)
+{
+ struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
+ struct inet6_ifaddr *ifa;
+ int idx = 0;
+
+ memset(vif_priv->tentative_addrs, 0, sizeof(vif_priv->tentative_addrs));
+
+ read_lock_bh(&idev->lock);
+ list_for_each_entry(ifa, &idev->addr_list, if_list) {
+ vif_priv->target_ipv6_addrs[idx] = ifa->addr;
+ if (ifa->flags & IFA_F_TENTATIVE)
+ __set_bit(idx, vif_priv->tentative_addrs);
+ idx++;
+ if (idx >= WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX)
+ break;
+ wcn36xx_dbg(WCN36XX_DBG_MAC, "%pI6 %s\n", &ifa->addr,
+ (ifa->flags & IFA_F_TENTATIVE) ? "tentative" : NULL);
+ }
+ read_unlock_bh(&idev->lock);
+
+ vif_priv->num_target_ipv6_addrs = idx;
+}
+#endif
+
static const struct ieee80211_ops wcn36xx_ops = {
.start = wcn36xx_start,
.stop = wcn36xx_stop,
@@ -1184,6 +1267,7 @@ static const struct ieee80211_ops wcn36xx_ops = {
#ifdef CONFIG_PM
.suspend = wcn36xx_suspend,
.resume = wcn36xx_resume,
+ .set_rekey_data = wcn36xx_set_rekey_data,
#endif
.config = wcn36xx_config,
.prepare_multicast = wcn36xx_prepare_multicast,
@@ -1199,6 +1283,9 @@ static const struct ieee80211_ops wcn36xx_ops = {
.sta_add = wcn36xx_sta_add,
.sta_remove = wcn36xx_sta_remove,
.ampdu_action = wcn36xx_ampdu_action,
+#if IS_ENABLED(CONFIG_IPV6)
+ .ipv6_addr_change = wcn36xx_ipv6_addr_change,
+#endif
CFG80211_TESTMODE_CMD(wcn36xx_tm_cmd)
};
@@ -1401,6 +1488,12 @@ static int wcn36xx_probe(struct platform_device *pdev)
mutex_init(&wcn->hal_mutex);
mutex_init(&wcn->scan_lock);
+ wcn->hal_buf = devm_kmalloc(wcn->dev, WCN36XX_HAL_BUF_SIZE, GFP_KERNEL);
+ if (!wcn->hal_buf) {
+ ret = -ENOMEM;
+ goto out_wq;
+ }
+
ret = dma_set_mask_and_coherent(wcn->dev, DMA_BIT_MASK(32));
if (ret < 0) {
wcn36xx_err("failed to set DMA mask: %d\n", ret);
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index d0c3a1557e8d..0e3be17d8cea 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -445,22 +445,12 @@ out:
return ret;
}
-static void init_hal_msg(struct wcn36xx_hal_msg_header *hdr,
- enum wcn36xx_hal_host_msg_type msg_type,
- size_t msg_size)
-{
- memset(hdr, 0, msg_size + sizeof(*hdr));
- hdr->msg_type = msg_type;
- hdr->msg_version = WCN36XX_HAL_MSG_VERSION0;
- hdr->len = msg_size + sizeof(*hdr);
-}
-
#define __INIT_HAL_MSG(msg_body, type, version) \
do { \
- memset(&msg_body, 0, sizeof(msg_body)); \
- msg_body.header.msg_type = type; \
- msg_body.header.msg_version = version; \
- msg_body.header.len = sizeof(msg_body); \
+ memset(&(msg_body), 0, sizeof(msg_body)); \
+ (msg_body).header.msg_type = type; \
+ (msg_body).header.msg_version = version; \
+ (msg_body).header.len = sizeof(msg_body); \
} while (0) \
#define INIT_HAL_MSG(msg_body, type) \
@@ -2729,8 +2719,7 @@ int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
msg_body = (struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *)
wcn->hal_buf;
- init_hal_msg(&msg_body->header, WCN36XX_HAL_8023_MULTICAST_LIST_REQ,
- sizeof(msg_body->mc_addr_list));
+ INIT_HAL_MSG(*msg_body, WCN36XX_HAL_8023_MULTICAST_LIST_REQ);
/* An empty list means all mc traffic will be received */
if (fp)
@@ -2756,6 +2745,269 @@ out:
return ret;
}
+int wcn36xx_smd_arp_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+ bool enable)
+{
+ struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
+ struct wcn36xx_hal_host_offload_req_msg msg_body;
+ int ret;
+
+ mutex_lock(&wcn->hal_mutex);
+
+ INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_OFFLOAD_REQ);
+ msg_body.host_offload_params.offload_type =
+ WCN36XX_HAL_IPV4_ARP_REPLY_OFFLOAD;
+ if (enable) {
+ msg_body.host_offload_params.enable =
+ WCN36XX_HAL_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE;
+ memcpy(&msg_body.host_offload_params.u,
+ &vif->bss_conf.arp_addr_list[0], sizeof(__be32));
+ }
+ msg_body.ns_offload_params.bss_index = vif_priv->bss_index;
+
+ PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+ ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+ if (ret) {
+ wcn36xx_err("Sending host_offload_arp failed\n");
+ goto out;
+ }
+ ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+ if (ret) {
+ wcn36xx_err("host_offload_arp failed err=%d\n", ret);
+ goto out;
+ }
+out:
+ mutex_unlock(&wcn->hal_mutex);
+ return ret;
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+int wcn36xx_smd_ipv6_ns_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+ bool enable)
+{
+ struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
+ struct wcn36xx_hal_host_offload_req_msg msg_body;
+ struct wcn36xx_hal_ns_offload_params *ns_params;
+ struct wcn36xx_hal_host_offload_req *ho_params;
+ int ret;
+
+ mutex_lock(&wcn->hal_mutex);
+
+ INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_OFFLOAD_REQ);
+ ho_params = &msg_body.host_offload_params;
+ ns_params = &msg_body.ns_offload_params;
+
+ ho_params->offload_type = WCN36XX_HAL_IPV6_NS_OFFLOAD;
+ if (enable) {
+ ho_params->enable =
+ WCN36XX_HAL_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE;
+ if (vif_priv->num_target_ipv6_addrs) {
+ memcpy(&ho_params->u,
+ &vif_priv->target_ipv6_addrs[0].in6_u,
+ sizeof(struct in6_addr));
+ memcpy(&ns_params->target_ipv6_addr1,
+ &vif_priv->target_ipv6_addrs[0].in6_u,
+ sizeof(struct in6_addr));
+ ns_params->target_ipv6_addr1_valid = 1;
+ }
+ if (vif_priv->num_target_ipv6_addrs > 1) {
+ memcpy(&ns_params->target_ipv6_addr2,
+ &vif_priv->target_ipv6_addrs[1].in6_u,
+ sizeof(struct in6_addr));
+ ns_params->target_ipv6_addr2_valid = 1;
+ }
+ }
+ memcpy(&ns_params->self_addr, vif->addr, ETH_ALEN);
+ ns_params->bss_index = vif_priv->bss_index;
+
+ PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+ ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+ if (ret) {
+ wcn36xx_err("Sending host_offload_arp failed\n");
+ goto out;
+ }
+ ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+ if (ret) {
+ wcn36xx_err("host_offload_arp failed err=%d\n", ret);
+ goto out;
+ }
+out:
+ mutex_unlock(&wcn->hal_mutex);
+ return ret;
+}
+#else
+int wcn36xx_smd_ipv6_ns_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+ bool enable)
+{
+ return 0;
+}
+#endif
+
+int wcn36xx_smd_gtk_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+ bool enable)
+{
+ struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
+ struct wcn36xx_hal_gtk_offload_req_msg msg_body;
+ int ret;
+
+ mutex_lock(&wcn->hal_mutex);
+
+ INIT_HAL_MSG(msg_body, WCN36XX_HAL_GTK_OFFLOAD_REQ);
+
+ if (enable) {
+ memcpy(&msg_body.kek, vif_priv->rekey_data.kek, NL80211_KEK_LEN);
+ memcpy(&msg_body.kck, vif_priv->rekey_data.kck, NL80211_KCK_LEN);
+ msg_body.key_replay_counter =
+ le64_to_cpu(vif_priv->rekey_data.replay_ctr);
+ msg_body.bss_index = vif_priv->bss_index;
+ } else {
+ msg_body.flags = WCN36XX_HAL_GTK_OFFLOAD_FLAGS_DISABLE;
+ }
+
+ PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+ ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+ if (ret) {
+ wcn36xx_err("Sending host_offload_arp failed\n");
+ goto out;
+ }
+ ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+ if (ret) {
+ wcn36xx_err("host_offload_arp failed err=%d\n", ret);
+ goto out;
+ }
+out:
+ mutex_unlock(&wcn->hal_mutex);
+ return ret;
+}
+
+static int wcn36xx_smd_gtk_offload_get_info_rsp(struct wcn36xx *wcn,
+ struct ieee80211_vif *vif)
+{
+ struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
+ struct wcn36xx_hal_gtk_offload_get_info_rsp_msg *rsp;
+ __be64 replay_ctr;
+
+ if (wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len))
+ return -EIO;
+
+ rsp = (struct wcn36xx_hal_gtk_offload_get_info_rsp_msg *)wcn->hal_buf;
+
+ if (rsp->bss_index != vif_priv->bss_index) {
+ wcn36xx_err("gtk_offload_info invalid response bss index %d\n",
+ rsp->bss_index);
+ return -ENOENT;
+ }
+
+ if (vif_priv->rekey_data.replay_ctr != cpu_to_le64(rsp->key_replay_counter)) {
+ replay_ctr = cpu_to_be64(rsp->key_replay_counter);
+ vif_priv->rekey_data.replay_ctr =
+ cpu_to_le64(rsp->key_replay_counter);
+ ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid,
+ (void *)&replay_ctr, GFP_KERNEL);
+ wcn36xx_dbg(WCN36XX_DBG_HAL,
+ "GTK replay counter increment %llu\n",
+ rsp->key_replay_counter);
+ }
+
+ wcn36xx_dbg(WCN36XX_DBG_HAL,
+ "gtk offload info status %d last_rekey_status %d "
+ "replay_counter %llu total_rekey_count %d gtk_rekey_count %d "
+ "igtk_rekey_count %d bss_index %d\n",
+ rsp->status, rsp->last_rekey_status,
+ rsp->key_replay_counter, rsp->total_rekey_count,
+ rsp->gtk_rekey_count, rsp->igtk_rekey_count,
+ rsp->bss_index);
+
+ return 0;
+}
+
+int wcn36xx_smd_gtk_offload_get_info(struct wcn36xx *wcn,
+ struct ieee80211_vif *vif)
+{
+ struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
+ struct wcn36xx_hal_gtk_offload_get_info_req_msg msg_body;
+ int ret;
+
+ mutex_lock(&wcn->hal_mutex);
+
+ INIT_HAL_MSG(msg_body, WCN36XX_HAL_GTK_OFFLOAD_GETINFO_REQ);
+
+ msg_body.bss_index = vif_priv->bss_index;
+
+ PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+ ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+ if (ret) {
+ wcn36xx_err("Sending gtk_offload_get_info failed\n");
+ goto out;
+ }
+ ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+ if (ret) {
+ wcn36xx_err("gtk_offload_get_info failed err=%d\n", ret);
+ goto out;
+ }
+ ret = wcn36xx_smd_gtk_offload_get_info_rsp(wcn, vif);
+out:
+ mutex_unlock(&wcn->hal_mutex);
+ return ret;
+}
+
+int wcn36xx_smd_wlan_host_suspend_ind(struct wcn36xx *wcn)
+{
+ struct wcn36xx_hal_wlan_host_suspend_ind_msg msg_body;
+ int ret;
+
+ mutex_lock(&wcn->hal_mutex);
+
+ INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_SUSPEND_IND);
+ msg_body.configured_mcst_bcst_filter_setting = 0;
+ msg_body.active_session_count = 1;
+ PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+ ret = rpmsg_send(wcn->smd_channel, wcn->hal_buf, msg_body.header.len);
+
+ mutex_unlock(&wcn->hal_mutex);
+
+ return ret;
+}
+
+int wcn36xx_smd_host_resume(struct wcn36xx *wcn)
+{
+ struct wcn36xx_hal_wlan_host_resume_req_msg msg_body;
+ struct wcn36xx_hal_host_resume_rsp_msg *rsp;
+ int ret;
+
+ mutex_lock(&wcn->hal_mutex);
+
+ INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_RESUME_REQ);
+ msg_body.configured_mcst_bcst_filter_setting = 0;
+
+ PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+ ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+ if (ret) {
+ wcn36xx_err("Sending wlan_host_resume failed\n");
+ goto out;
+ }
+ ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+ if (ret) {
+ wcn36xx_err("wlan_host_resume err=%d\n", ret);
+ goto out;
+ }
+
+ rsp = (struct wcn36xx_hal_host_resume_rsp_msg *)wcn->hal_buf;
+ if (rsp->status)
+ wcn36xx_warn("wlan_host_resume status=%d\n", rsp->status);
+
+out:
+ mutex_unlock(&wcn->hal_mutex);
+
+ return ret;
+}
+
int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev,
void *buf, int len, void *priv, u32 addr)
{
@@ -2804,6 +3056,10 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev,
case WCN36XX_HAL_8023_MULTICAST_LIST_RSP:
case WCN36XX_HAL_START_SCAN_OFFLOAD_RSP:
case WCN36XX_HAL_STOP_SCAN_OFFLOAD_RSP:
+ case WCN36XX_HAL_HOST_OFFLOAD_RSP:
+ case WCN36XX_HAL_GTK_OFFLOAD_RSP:
+ case WCN36XX_HAL_GTK_OFFLOAD_GETINFO_RSP:
+ case WCN36XX_HAL_HOST_RESUME_RSP:
memcpy(wcn->hal_buf, buf, len);
wcn->hal_rsp_len = len;
complete(&wcn->hal_rsp_compl);
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
index 462860572e1f..d8bded03945d 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.h
+++ b/drivers/net/wireless/ath/wcn36xx/smd.h
@@ -146,4 +146,21 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev,
int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
struct ieee80211_vif *vif,
struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp);
+
+int wcn36xx_smd_arp_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+ bool enable);
+
+int wcn36xx_smd_ipv6_ns_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+ bool enable);
+
+int wcn36xx_smd_gtk_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+ bool enable);
+
+int wcn36xx_smd_gtk_offload_get_info(struct wcn36xx *wcn,
+ struct ieee80211_vif *vif);
+
+int wcn36xx_smd_wlan_host_suspend_ind(struct wcn36xx *wcn);
+
+int wcn36xx_smd_host_resume(struct wcn36xx *wcn);
+
#endif /* _SMD_H_ */
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index 71fa9992b118..6121d8a5641a 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -18,6 +18,7 @@
#define _WCN36XX_H_
#include <linux/completion.h>
+#include <linux/in6.h>
#include <linux/printk.h>
#include <linux/spinlock.h>
#include <net/mac80211.h>
@@ -136,6 +137,19 @@ struct wcn36xx_vif {
u8 self_dpu_desc_index;
u8 self_ucast_dpu_sign;
+#if IS_ENABLED(CONFIG_IPV6)
+ /* IPv6 addresses for WoWLAN */
+ struct in6_addr target_ipv6_addrs[WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX];
+ unsigned long tentative_addrs[BITS_TO_LONGS(WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX)];
+ int num_target_ipv6_addrs;
+#endif
+ /* WoWLAN GTK rekey data */
+ struct {
+ u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN];
+ __le64 replay_ctr;
+ bool valid;
+ } rekey_data;
+
struct list_head sta_list;
};
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 6746fd206d2a..1ff2679963f0 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -2842,9 +2842,7 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil)
wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
mutex_unlock(&wil->vif_mutex);
if (p2p_wdev) {
- wiphy_lock(wil->wiphy);
cfg80211_unregister_wdev(p2p_wdev);
- wiphy_unlock(wil->wiphy);
kfree(p2p_wdev);
}
}
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index d13d081fdcc6..67172385a5d6 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -9,7 +9,7 @@
#include "wil6210.h"
#include "trace.h"
-/**
+/*
* Theory of operation:
*
* There is ISR pseudo-cause register,
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 02ad44997e87..2dc8406736f4 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -224,7 +224,7 @@ struct auth_no_hdr {
u8 led_polarity = LED_POLARITY_LOW_ACTIVE;
/**
- * return AHB address for given firmware internal (linker) address
+ * wmi_addr_remap - return AHB address for given firmware internal (linker) address
* @x: internal address
* If address have no valid AHB mapping, return 0
*/
@@ -242,7 +242,7 @@ static u32 wmi_addr_remap(u32 x)
}
/**
- * find fw_mapping entry by section name
+ * wil_find_fw_mapping - find fw_mapping entry by section name
* @section: section name
*
* Return pointer to section or NULL if not found
@@ -260,7 +260,7 @@ struct fw_map *wil_find_fw_mapping(const char *section)
}
/**
- * Check address validity for WMI buffer; remap if needed
+ * wmi_buffer_block - Check address validity for WMI buffer; remap if needed
* @wil: driver data
* @ptr_: internal (linker) fw/ucode address
* @size: if non zero, validate the block does not
diff --git a/drivers/net/wireless/broadcom/b43/debugfs.c b/drivers/net/wireless/broadcom/b43/debugfs.c
index 89a25aefb327..efa98444e3fb 100644
--- a/drivers/net/wireless/broadcom/b43/debugfs.c
+++ b/drivers/net/wireless/broadcom/b43/debugfs.c
@@ -643,24 +643,14 @@ bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
return enabled;
}
-static void b43_remove_dynamic_debug(struct b43_wldev *dev)
-{
- struct b43_dfsentry *e = dev->dfsentry;
- int i;
-
- for (i = 0; i < __B43_NR_DYNDBG; i++)
- debugfs_remove(e->dyn_debug_dentries[i]);
-}
-
static void b43_add_dynamic_debug(struct b43_wldev *dev)
{
struct b43_dfsentry *e = dev->dfsentry;
#define add_dyn_dbg(name, id, initstate) do { \
e->dyn_debug[id] = (initstate); \
- e->dyn_debug_dentries[id] = \
- debugfs_create_bool(name, 0600, e->subdir, \
- &(e->dyn_debug[id])); \
+ debugfs_create_bool(name, 0600, e->subdir, \
+ &(e->dyn_debug[id])); \
} while (0)
add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, false);
@@ -713,10 +703,9 @@ void b43_debugfs_add_device(struct b43_wldev *dev)
#define ADD_FILE(name, mode) \
do { \
- e->file_##name.dentry = \
- debugfs_create_file(__stringify(name), \
- mode, e->subdir, dev, \
- &fops_##name.fops); \
+ debugfs_create_file(__stringify(name), \
+ mode, e->subdir, dev, \
+ &fops_##name.fops); \
} while (0)
@@ -746,19 +735,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev)
e = dev->dfsentry;
if (!e)
return;
- b43_remove_dynamic_debug(dev);
-
- debugfs_remove(e->file_shm16read.dentry);
- debugfs_remove(e->file_shm16write.dentry);
- debugfs_remove(e->file_shm32read.dentry);
- debugfs_remove(e->file_shm32write.dentry);
- debugfs_remove(e->file_mmio16read.dentry);
- debugfs_remove(e->file_mmio16write.dentry);
- debugfs_remove(e->file_mmio32read.dentry);
- debugfs_remove(e->file_mmio32write.dentry);
- debugfs_remove(e->file_txstat.dentry);
- debugfs_remove(e->file_restart.dentry);
- debugfs_remove(e->file_loctls.dentry);
debugfs_remove(e->subdir);
kfree(e->txstatlog.log);
diff --git a/drivers/net/wireless/broadcom/b43/debugfs.h b/drivers/net/wireless/broadcom/b43/debugfs.h
index 0bf437c86c67..6f6b500b8881 100644
--- a/drivers/net/wireless/broadcom/b43/debugfs.h
+++ b/drivers/net/wireless/broadcom/b43/debugfs.h
@@ -32,7 +32,6 @@ struct b43_txstatus_log {
};
struct b43_dfs_file {
- struct dentry *dentry;
char *buffer;
size_t data_len;
};
@@ -70,8 +69,6 @@ struct b43_dfsentry {
/* Enabled/Disabled list for the dynamic debugging features. */
bool dyn_debug[__B43_NR_DYNDBG];
- /* Dentries for the dynamic debugging entries. */
- struct dentry *dyn_debug_dentries[__B43_NR_DYNDBG];
};
bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature);
diff --git a/drivers/net/wireless/broadcom/b43/phy_n.c b/drivers/net/wireless/broadcom/b43/phy_n.c
index 665b737fbb0d..cf3ccf4ddfe7 100644
--- a/drivers/net/wireless/broadcom/b43/phy_n.c
+++ b/drivers/net/wireless/broadcom/b43/phy_n.c
@@ -4592,58 +4592,11 @@ static void b43_nphy_spur_workaround(struct b43_wldev *dev)
{
struct b43_phy_n *nphy = dev->phy.n;
- u8 channel = dev->phy.channel;
- int tone[2] = { 57, 58 };
- u32 noise[2] = { 0x3FF, 0x3FF };
-
B43_WARN_ON(dev->phy.rev < 3);
if (nphy->hang_avoid)
b43_nphy_stay_in_carrier_search(dev, 1);
- if (nphy->gband_spurwar_en) {
- /* TODO: N PHY Adjust Analog Pfbw (7) */
- if (channel == 11 && b43_is_40mhz(dev)) {
- ; /* TODO: N PHY Adjust Min Noise Var(2, tone, noise)*/
- } else {
- ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/
- }
- /* TODO: N PHY Adjust CRS Min Power (0x1E) */
- }
-
- if (nphy->aband_spurwar_en) {
- if (channel == 54) {
- tone[0] = 0x20;
- noise[0] = 0x25F;
- } else if (channel == 38 || channel == 102 || channel == 118) {
- if (0 /* FIXME */) {
- tone[0] = 0x20;
- noise[0] = 0x21F;
- } else {
- tone[0] = 0;
- noise[0] = 0;
- }
- } else if (channel == 134) {
- tone[0] = 0x20;
- noise[0] = 0x21F;
- } else if (channel == 151) {
- tone[0] = 0x10;
- noise[0] = 0x23F;
- } else if (channel == 153 || channel == 161) {
- tone[0] = 0x30;
- noise[0] = 0x23F;
- } else {
- tone[0] = 0;
- noise[0] = 0;
- }
-
- if (!tone[0] && !noise[0]) {
- ; /* TODO: N PHY Adjust Min Noise Var(1, tone, noise)*/
- } else {
- ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/
- }
- }
-
if (nphy->hang_avoid)
b43_nphy_stay_in_carrier_search(dev, 0);
}
diff --git a/drivers/net/wireless/broadcom/b43legacy/debugfs.c b/drivers/net/wireless/broadcom/b43legacy/debugfs.c
index e7e4293c01f2..6b0e8d117061 100644
--- a/drivers/net/wireless/broadcom/b43legacy/debugfs.c
+++ b/drivers/net/wireless/broadcom/b43legacy/debugfs.c
@@ -336,24 +336,14 @@ int b43legacy_debug(struct b43legacy_wldev *dev, enum b43legacy_dyndbg feature)
return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
}
-static void b43legacy_remove_dynamic_debug(struct b43legacy_wldev *dev)
-{
- struct b43legacy_dfsentry *e = dev->dfsentry;
- int i;
-
- for (i = 0; i < __B43legacy_NR_DYNDBG; i++)
- debugfs_remove(e->dyn_debug_dentries[i]);
-}
-
static void b43legacy_add_dynamic_debug(struct b43legacy_wldev *dev)
{
struct b43legacy_dfsentry *e = dev->dfsentry;
#define add_dyn_dbg(name, id, initstate) do { \
e->dyn_debug[id] = (initstate); \
- e->dyn_debug_dentries[id] = \
- debugfs_create_bool(name, 0600, e->subdir, \
- &(e->dyn_debug[id])); \
+ debugfs_create_bool(name, 0600, e->subdir, \
+ &(e->dyn_debug[id])); \
} while (0)
add_dyn_dbg("debug_xmitpower", B43legacy_DBG_XMITPOWER, false);
@@ -396,11 +386,9 @@ void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev)
#define ADD_FILE(name, mode) \
do { \
- e->file_##name.dentry = \
- debugfs_create_file(__stringify(name), \
- mode, e->subdir, dev, \
- &fops_##name.fops); \
- e->file_##name.dentry = NULL; \
+ debugfs_create_file(__stringify(name), mode, \
+ e->subdir, dev, \
+ &fops_##name.fops); \
} while (0)
@@ -424,13 +412,6 @@ void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev)
e = dev->dfsentry;
if (!e)
return;
- b43legacy_remove_dynamic_debug(dev);
-
- debugfs_remove(e->file_tsf.dentry);
- debugfs_remove(e->file_ucode_regs.dentry);
- debugfs_remove(e->file_shm.dentry);
- debugfs_remove(e->file_txstat.dentry);
- debugfs_remove(e->file_restart.dentry);
debugfs_remove(e->subdir);
kfree(e->txstatlog.log);
diff --git a/drivers/net/wireless/broadcom/b43legacy/debugfs.h b/drivers/net/wireless/broadcom/b43legacy/debugfs.h
index 7a37764406b1..924130880dfe 100644
--- a/drivers/net/wireless/broadcom/b43legacy/debugfs.h
+++ b/drivers/net/wireless/broadcom/b43legacy/debugfs.h
@@ -28,7 +28,6 @@ struct b43legacy_txstatus_log {
};
struct b43legacy_dfs_file {
- struct dentry *dentry;
char *buffer;
size_t data_len;
};
@@ -49,8 +48,6 @@ struct b43legacy_dfsentry {
/* Enabled/Disabled list for the dynamic debugging features. */
bool dyn_debug[__B43legacy_NR_DYNDBG];
- /* Dentries for the dynamic debugging entries. */
- struct dentry *dyn_debug_dentries[__B43legacy_NR_DYNDBG];
};
int b43legacy_debug(struct b43legacy_wldev *dev,
diff --git a/drivers/net/wireless/broadcom/b43legacy/dma.c b/drivers/net/wireless/broadcom/b43legacy/dma.c
index 7e2f70c4207c..6869f2bf1bae 100644
--- a/drivers/net/wireless/broadcom/b43legacy/dma.c
+++ b/drivers/net/wireless/broadcom/b43legacy/dma.c
@@ -213,19 +213,6 @@ return dev->dma.tx_ring1;
return ring;
}
-/* Bcm4301-ring to mac80211-queue mapping */
-static inline int txring_to_priority(struct b43legacy_dmaring *ring)
-{
- static const u8 idx_to_prio[] =
- { 3, 2, 1, 0, 4, 5, };
-
-/*FIXME: have only one queue, for now */
-return 0;
-
- return idx_to_prio[ring->index];
-}
-
-
static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type,
int controller_idx)
{
diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c
index f64ebff68308..eec3af9c3745 100644
--- a/drivers/net/wireless/broadcom/b43legacy/main.c
+++ b/drivers/net/wireless/broadcom/b43legacy/main.c
@@ -391,7 +391,7 @@ void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf)
* registers, we should take care of register overflows.
* In theory, the whole tsf read process should be atomic.
* We try to be atomic here, by restaring the read process,
- * if any of the high registers changed (overflew).
+ * if any of the high registers changed (overflowed).
*/
if (dev->dev->id.revision >= 3) {
u32 low;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index f4405d7861b6..cedba56fc448 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -2767,8 +2767,9 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
struct brcmf_sta_info_le sta_info_le;
u32 sta_flags;
u32 is_tdls_peer;
- s32 total_rssi;
- s32 count_rssi;
+ s32 total_rssi_avg = 0;
+ s32 total_rssi = 0;
+ s32 count_rssi = 0;
int rssi;
u32 i;
@@ -2834,25 +2835,27 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES);
sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes);
}
- total_rssi = 0;
- count_rssi = 0;
for (i = 0; i < BRCMF_ANT_MAX; i++) {
- if (sta_info_le.rssi[i]) {
- sinfo->chain_signal_avg[count_rssi] =
- sta_info_le.rssi[i];
- sinfo->chain_signal[count_rssi] =
- sta_info_le.rssi[i];
- total_rssi += sta_info_le.rssi[i];
- count_rssi++;
- }
+ if (sta_info_le.rssi[i] == 0 ||
+ sta_info_le.rx_lastpkt_rssi[i] == 0)
+ continue;
+ sinfo->chains |= BIT(count_rssi);
+ sinfo->chain_signal[count_rssi] =
+ sta_info_le.rx_lastpkt_rssi[i];
+ sinfo->chain_signal_avg[count_rssi] =
+ sta_info_le.rssi[i];
+ total_rssi += sta_info_le.rx_lastpkt_rssi[i];
+ total_rssi_avg += sta_info_le.rssi[i];
+ count_rssi++;
}
if (count_rssi) {
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);
- sinfo->chains = count_rssi;
-
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
- total_rssi /= count_rssi;
- sinfo->signal = total_rssi;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG);
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);
+ sinfo->filled |=
+ BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
+ sinfo->signal = total_rssi / count_rssi;
+ sinfo->signal_avg = total_rssi_avg / count_rssi;
} else if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
&ifp->vif->sme_state)) {
memset(&scb_val, 0, sizeof(scb_val));
@@ -2892,8 +2895,13 @@ brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
&cfg->assoclist,
sizeof(cfg->assoclist));
if (err) {
- bphy_err(drvr, "BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n",
- err);
+ /* GET_ASSOCLIST unsupported by firmware of older chips */
+ if (err == -EBADE)
+ bphy_info_once(drvr, "BRCMF_C_GET_ASSOCLIST unsupported\n");
+ else
+ bphy_err(drvr, "BRCMF_C_GET_ASSOCLIST failed, err=%d\n",
+ err);
+
cfg->assoclist.count = 0;
return -EOPNOTSUPP;
}
@@ -6848,7 +6856,12 @@ static int brcmf_setup_wiphybands(struct brcmf_cfg80211_info *cfg)
err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
if (err) {
- bphy_err(drvr, "rxchain error (%d)\n", err);
+ /* rxchain unsupported by firmware of older chips */
+ if (err == -EBADE)
+ bphy_info_once(drvr, "rxchain unsupported\n");
+ else
+ bphy_err(drvr, "rxchain error (%d)\n", err);
+
nchain = 1;
} else {
for (nchain = 0; rxchain; nchain++)
@@ -7442,18 +7455,23 @@ static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
s32 found_index;
int i;
- country_codes = drvr->settings->country_codes;
- if (!country_codes) {
- brcmf_dbg(TRACE, "No country codes configured for device\n");
- return -EINVAL;
- }
-
if ((alpha2[0] == ccreq->country_abbrev[0]) &&
(alpha2[1] == ccreq->country_abbrev[1])) {
brcmf_dbg(TRACE, "Country code already set\n");
return -EAGAIN;
}
+ country_codes = drvr->settings->country_codes;
+ if (!country_codes) {
+ brcmf_dbg(TRACE, "No country codes configured for device, using ISO3166 code and 0 rev\n");
+ memset(ccreq, 0, sizeof(*ccreq));
+ ccreq->country_abbrev[0] = alpha2[0];
+ ccreq->country_abbrev[1] = alpha2[1];
+ ccreq->ccode[0] = alpha2[0];
+ ccreq->ccode[1] = alpha2[1];
+ return 0;
+ }
+
found_index = -1;
for (i = 0; i < country_codes->table_size; i++) {
cc = &country_codes->table[i];
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index cee1682d2333..db5f8535fdb5 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -188,9 +188,14 @@ static void _brcmf_set_multicast_list(struct work_struct *work)
/*Finally, pick up the PROMISC flag */
cmd_value = (ndev->flags & IFF_PROMISC) ? true : false;
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PROMISC, cmd_value);
- if (err < 0)
- bphy_err(drvr, "Setting BRCMF_C_SET_PROMISC failed, %d\n",
- err);
+ if (err < 0) {
+ /* PROMISC unsupported by firmware of older chips */
+ if (err == -EBADE)
+ bphy_info_once(drvr, "BRCMF_C_SET_PROMISC unsupported\n");
+ else
+ bphy_err(drvr, "Setting BRCMF_C_SET_PROMISC failed, err=%d\n",
+ err);
+ }
brcmf_configure_arp_nd_offload(ifp, !cmd_value);
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
index 44ba6f389fa9..9bb5f709d41a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h
@@ -60,6 +60,10 @@ void __brcmf_err(struct brcmf_bus *bus, const char *func, const char *fmt, ...);
##__VA_ARGS__); \
} while (0)
+#define bphy_info_once(drvr, fmt, ...) \
+ wiphy_info_once((drvr)->wiphy, "%s: " fmt, __func__, \
+ ##__VA_ARGS__)
+
#if defined(DEBUG) || defined(CONFIG_BRCM_TRACING)
/* For debug/tracing purposes treat info messages as errors */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
index 46c66415b4a6..e290dec9c53d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h
@@ -32,6 +32,13 @@ static const char BRCM_ ## fw_name ## _FIRMWARE_BASENAME[] = \
BRCMF_FW_DEFAULT_PATH fw_base; \
MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".bin")
+/* Firmware and Country Local Matrix files */
+#define BRCMF_FW_CLM_DEF(fw_name, fw_base) \
+static const char BRCM_ ## fw_name ## _FIRMWARE_BASENAME[] = \
+ BRCMF_FW_DEFAULT_PATH fw_base; \
+MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".bin"); \
+MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".clm_blob")
+
#define BRCMF_FW_ENTRY(chipid, mask, name) \
{ chipid, mask, BRCM_ ## name ## _FIRMWARE_BASENAME }
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
index a7554265f95f..2f7bc3a70c65 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
@@ -12,12 +12,59 @@
#include "common.h"
#include "of.h"
+static int brcmf_of_get_country_codes(struct device *dev,
+ struct brcmf_mp_device *settings)
+{
+ struct device_node *np = dev->of_node;
+ struct brcmfmac_pd_cc_entry *cce;
+ struct brcmfmac_pd_cc *cc;
+ int count;
+ int i;
+
+ count = of_property_count_strings(np, "brcm,ccode-map");
+ if (count < 0) {
+ /* The property is optional, so return success if it doesn't
+ * exist. Otherwise propagate the error code.
+ */
+ return (count == -EINVAL) ? 0 : count;
+ }
+
+ cc = devm_kzalloc(dev, sizeof(*cc) + count * sizeof(*cce), GFP_KERNEL);
+ if (!cc)
+ return -ENOMEM;
+
+ cc->table_size = count;
+
+ for (i = 0; i < count; i++) {
+ const char *map;
+
+ cce = &cc->table[i];
+
+ if (of_property_read_string_index(np, "brcm,ccode-map",
+ i, &map))
+ continue;
+
+ /* String format e.g. US-Q2-86 */
+ if (sscanf(map, "%2c-%2c-%d", cce->iso3166, cce->cc,
+ &cce->rev) != 3)
+ brcmf_err("failed to read country map %s\n", map);
+ else
+ brcmf_dbg(INFO, "%s-%s-%d\n", cce->iso3166, cce->cc,
+ cce->rev);
+ }
+
+ settings->country_codes = cc;
+
+ return 0;
+}
+
void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
struct brcmf_mp_device *settings)
{
struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio;
struct device_node *root, *np = dev->of_node;
int irq;
+ int err;
u32 irqf;
u32 val;
@@ -43,8 +90,14 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
of_node_put(root);
}
- if (!np || bus_type != BRCMF_BUSTYPE_SDIO ||
- !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
+ if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
+ return;
+
+ err = brcmf_of_get_country_codes(dev, settings);
+ if (err)
+ brcmf_err("failed to get OF country code map (err=%d)\n", err);
+
+ if (bus_type != BRCMF_BUSTYPE_SDIO)
return;
if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
index 34cd8a7401fe..9ac0d8c73d5a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
@@ -2037,7 +2037,7 @@ static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p,
}
/**
- * Change a P2P Role.
+ * brcmf_p2p_ifchange - Change a P2P Role.
* @cfg: driver private data for cfg80211 interface.
* @if_type: interface type.
* Returns 0 if success.
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index 143a705b5cb3..c49dd0c36ae4 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -48,8 +48,8 @@ enum brcmf_pcie_state {
BRCMF_FW_DEF(43602, "brcmfmac43602-pcie");
BRCMF_FW_DEF(4350, "brcmfmac4350-pcie");
BRCMF_FW_DEF(4350C, "brcmfmac4350c2-pcie");
-BRCMF_FW_DEF(4356, "brcmfmac4356-pcie");
-BRCMF_FW_DEF(43570, "brcmfmac43570-pcie");
+BRCMF_FW_CLM_DEF(4356, "brcmfmac4356-pcie");
+BRCMF_FW_CLM_DEF(43570, "brcmfmac43570-pcie");
BRCMF_FW_DEF(4358, "brcmfmac4358-pcie");
BRCMF_FW_DEF(4359, "brcmfmac4359-pcie");
BRCMF_FW_DEF(4364, "brcmfmac4364-pcie");
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 16ed325795a8..97ee9e2e2e35 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -616,18 +616,18 @@ BRCMF_FW_DEF(43362, "brcmfmac43362-sdio");
BRCMF_FW_DEF(4339, "brcmfmac4339-sdio");
BRCMF_FW_DEF(43430A0, "brcmfmac43430a0-sdio");
/* Note the names are not postfixed with a1 for backward compatibility */
-BRCMF_FW_DEF(43430A1, "brcmfmac43430-sdio");
-BRCMF_FW_DEF(43455, "brcmfmac43455-sdio");
+BRCMF_FW_CLM_DEF(43430A1, "brcmfmac43430-sdio");
+BRCMF_FW_CLM_DEF(43455, "brcmfmac43455-sdio");
BRCMF_FW_DEF(43456, "brcmfmac43456-sdio");
-BRCMF_FW_DEF(4354, "brcmfmac4354-sdio");
-BRCMF_FW_DEF(4356, "brcmfmac4356-sdio");
+BRCMF_FW_CLM_DEF(4354, "brcmfmac4354-sdio");
+BRCMF_FW_CLM_DEF(4356, "brcmfmac4356-sdio");
BRCMF_FW_DEF(4359, "brcmfmac4359-sdio");
-BRCMF_FW_DEF(4373, "brcmfmac4373-sdio");
-BRCMF_FW_DEF(43012, "brcmfmac43012-sdio");
+BRCMF_FW_CLM_DEF(4373, "brcmfmac4373-sdio");
+BRCMF_FW_CLM_DEF(43012, "brcmfmac43012-sdio");
/* firmware config files */
-MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcm/brcmfmac*-sdio.*.txt");
-MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcm/brcmfmac*-pcie.*.txt");
+MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.txt");
+MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txt");
static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143),
@@ -1291,7 +1291,7 @@ static void brcmf_sdio_free_glom(struct brcmf_sdio *bus)
}
}
-/**
+/*
* brcmfmac sdio bus specific header
* This is the lowest layer header wrapped on the packets transmitted between
* host and WiFi dongle which contains information needed for SDIO core and
@@ -4162,7 +4162,6 @@ static int brcmf_sdio_bus_reset(struct device *dev)
if (ret) {
brcmf_err("Failed to probe after sdio device reset: ret %d\n",
ret);
- brcmf_sdiod_remove(sdiodev);
}
return ret;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/aiutils.c
index 53365977bfd6..2084b506a450 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/aiutils.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/aiutils.c
@@ -531,9 +531,6 @@ void ai_detach(struct si_pub *sih)
sii = container_of(sih, struct si_info, pub);
- if (sii == NULL)
- return;
-
kfree(sii);
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
index 39f3af2d0439..eadac0f5590f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
@@ -1220,6 +1220,7 @@ static int brcms_bcma_probe(struct bcma_device *pdev)
{
struct brcms_info *wl;
struct ieee80211_hw *hw;
+ int ret;
dev_info(&pdev->dev, "mfg %x core %x rev %d class %d irq %d\n",
pdev->id.manuf, pdev->id.id, pdev->id.rev, pdev->id.class,
@@ -1244,11 +1245,16 @@ static int brcms_bcma_probe(struct bcma_device *pdev)
wl = brcms_attach(pdev);
if (!wl) {
pr_err("%s: brcms_attach failed!\n", __func__);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_free_ieee80211;
}
brcms_led_register(wl);
return 0;
+
+err_free_ieee80211:
+ ieee80211_free_hw(hw);
+ return ret;
}
static int brcms_suspend(struct bcma_device *pdev)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
index 763e0ec583d7..26de1bd7fee9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
@@ -6607,7 +6607,8 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
IEEE80211_STYPE_RTS);
- memcpy(&rts->ra, &h->addr1, 2 * ETH_ALEN);
+ memcpy(&rts->ra, &h->addr1, ETH_ALEN);
+ memcpy(&rts->ta, &h->addr2, ETH_ALEN);
}
/* mainrate
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.h
index aa4ab53bf634..af86c7fc5112 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.h
@@ -29,7 +29,6 @@ void brcms_c_stf_ss_update(struct brcms_c_info *wlc, struct brcms_band *band);
void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc);
int brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val, bool force);
bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val);
-void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc);
void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc);
u16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, u32 rspec);
u16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc, u32 rspec);
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
index 23fbddd0c1f8..47eb89b773cf 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
@@ -5356,7 +5356,7 @@ struct ipw2100_wep_key {
#define WEP_STR_128(x) x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10]
/**
- * Set a the wep key
+ * ipw2100_set_key() - Set a the wep key
*
* @priv: struct to work on
* @idx: index of the key we want to set
diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile
index 14b0db28143b..d86918d162aa 100644
--- a/drivers/net/wireless/intel/iwlwifi/Makefile
+++ b/drivers/net/wireless/intel/iwlwifi/Makefile
@@ -16,9 +16,10 @@ iwlwifi-objs += iwl-trans.o
iwlwifi-objs += queue/tx.o
iwlwifi-objs += fw/img.o fw/notif-wait.o
-iwlwifi-objs += fw/dbg.o fw/pnvm.o
+iwlwifi-objs += fw/dbg.o fw/pnvm.o fw/dump.o
iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o
iwlwifi-$(CONFIG_ACPI) += fw/acpi.o
+iwlwifi-$(CONFIG_EFI) += fw/uefi.o
iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += fw/debugfs.o
iwlwifi-objs += $(iwlwifi-m)
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
index c2315dea9a23..7f1faa9d97b4 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2021 Intel Corporation
*/
#include <linux/module.h>
#include <linux/stringify.h>
@@ -9,7 +9,7 @@
#include "iwl-prph.h"
/* Highest firmware API version supported */
-#define IWL_22000_UCODE_API_MAX 63
+#define IWL_22000_UCODE_API_MAX 64
/* Lowest firmware API version supported */
#define IWL_22000_UCODE_API_MIN 39
@@ -47,6 +47,7 @@
#define IWL_MA_A_GF_A_FW_PRE "iwlwifi-ma-a0-gf-a0-"
#define IWL_MA_A_GF4_A_FW_PRE "iwlwifi-ma-a0-gf4-a0-"
#define IWL_MA_A_MR_A_FW_PRE "iwlwifi-ma-a0-mr-a0-"
+#define IWL_MA_A_FM_A_FW_PRE "iwlwifi-ma-a0-fm-a0-"
#define IWL_SNJ_A_MR_A_FW_PRE "iwlwifi-SoSnj-a0-mr-a0-"
#define IWL_BZ_A_HR_B_FW_PRE "iwlwifi-bz-a0-hr-b0-"
#define IWL_BZ_A_GF_A_FW_PRE "iwlwifi-bz-a0-gf-a0-"
@@ -93,6 +94,8 @@
IWL_MA_A_GF4_A_FW_PRE __stringify(api) ".ucode"
#define IWL_MA_A_MR_A_FW_MODULE_FIRMWARE(api) \
IWL_MA_A_MR_A_FW_PRE __stringify(api) ".ucode"
+#define IWL_MA_A_FM_A_FW_MODULE_FIRMWARE(api) \
+ IWL_MA_A_FM_A_FW_PRE __stringify(api) ".ucode"
#define IWL_SNJ_A_MR_A_MODULE_FIRMWARE(api) \
IWL_SNJ_A_MR_A_FW_PRE __stringify(api) ".ucode"
#define IWL_BZ_A_HR_B_MODULE_FIRMWARE(api) \
@@ -389,6 +392,7 @@ const char iwl_ax201_name[] = "Intel(R) Wi-Fi 6 AX201 160MHz";
const char iwl_ax203_name[] = "Intel(R) Wi-Fi 6 AX203";
const char iwl_ax211_name[] = "Intel(R) Wi-Fi 6E AX211 160MHz";
const char iwl_ax221_name[] = "Intel(R) Wi-Fi 6E AX221 160MHz";
+const char iwl_ax231_name[] = "Intel(R) Wi-Fi 6E AX231 160MHz";
const char iwl_ax411_name[] = "Intel(R) Wi-Fi 6E AX411 160MHz";
const char iwl_ax200_killer_1650w_name[] =
@@ -724,6 +728,13 @@ const struct iwl_cfg iwl_cfg_ma_a0_mr_a0 = {
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
+const struct iwl_cfg iwl_cfg_ma_a0_fm_a0 = {
+ .fw_name_pre = IWL_MA_A_FM_A_FW_PRE,
+ .uhb_supported = true,
+ IWL_DEVICE_AX210,
+ .num_rbds = IWL_NUM_RBDS_AX210_HE,
+};
+
const struct iwl_cfg iwl_cfg_snj_a0_mr_a0 = {
.fw_name_pre = IWL_SNJ_A_MR_A_FW_PRE,
.uhb_supported = true,
@@ -797,6 +808,7 @@ MODULE_FIRMWARE(IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_MA_A_GF_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_MA_A_GF4_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_MA_A_MR_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL_MA_A_FM_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_SNJ_A_MR_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL_BZ_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
index df1297358379..871533beff30 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2021 Intel Corporation
*/
#include <linux/module.h>
#include <linux/stringify.h>
@@ -171,8 +171,12 @@ const char iwl9260_killer_1550_name[] =
"Killer (R) Wireless-AC 1550 Wireless Network Adapter (9260NGW) 160MHz";
const char iwl9560_killer_1550i_name[] =
"Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)";
+const char iwl9560_killer_1550i_160_name[] =
+ "Killer(R) Wireless-AC 1550i Wireless Network Adapter (9560NGW) 160MHz";
const char iwl9560_killer_1550s_name[] =
"Killer (R) Wireless-AC 1550s Wireless Network Adapter (9560NGW)";
+const char iwl9560_killer_1550s_160_name[] =
+ "Killer(R) Wireless-AC 1550s Wireless Network Adapter (9560D2W) 160MHz";
const struct iwl_cfg iwl9260_2ac_cfg = {
.fw_name_pre = IWL9260_FW_PRE,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index e31bba836c6f..34933f133a0a 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -163,6 +163,27 @@ int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func,
}
IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8);
+/*
+ * Evaluate a DSM with no arguments and a u32 return value,
+ */
+int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func,
+ const guid_t *guid, u32 *value)
+{
+ int ret;
+ u64 val;
+
+ ret = iwl_acpi_get_dsm_integer(dev, rev, func,
+ guid, &val, sizeof(u32));
+
+ if (ret < 0)
+ return ret;
+
+ /* cast val (u64) to be u32 */
+ *value = (u32)val;
+ return 0;
+}
+IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u32);
+
union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
union acpi_object *data,
int data_size, int *tbl_rev)
@@ -696,68 +717,37 @@ int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt,
}
IWL_EXPORT_SYMBOL(iwl_sar_geo_init);
-static u32 iwl_acpi_eval_dsm_func(struct device *dev, enum iwl_dsm_funcs_rev_0 eval_func)
-{
- union acpi_object *obj;
- u32 ret;
-
- obj = iwl_acpi_get_dsm_object(dev, 0,
- eval_func, NULL,
- &iwl_guid);
-
- if (IS_ERR(obj)) {
- IWL_DEBUG_DEV_RADIO(dev,
- "ACPI: DSM func '%d': Got Error in obj = %ld\n",
- eval_func,
- PTR_ERR(obj));
- return 0;
- }
-
- if (obj->type != ACPI_TYPE_INTEGER) {
- IWL_DEBUG_DEV_RADIO(dev,
- "ACPI: DSM func '%d' did not return a valid object, type=%d\n",
- eval_func,
- obj->type);
- ret = 0;
- goto out;
- }
-
- ret = obj->integer.value;
- IWL_DEBUG_DEV_RADIO(dev,
- "ACPI: DSM method evaluated: func='%d', ret=%d\n",
- eval_func,
- ret);
-out:
- ACPI_FREE(obj);
- return ret;
-}
-
__le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)
{
- u32 ret;
+ int ret;
+ u8 value;
__le32 config_bitmap = 0;
/*
** Evaluate func 'DSM_FUNC_ENABLE_INDONESIA_5G2'
*/
- ret = iwl_acpi_eval_dsm_func(fwrt->dev, DSM_FUNC_ENABLE_INDONESIA_5G2);
+ ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0,
+ DSM_FUNC_ENABLE_INDONESIA_5G2,
+ &iwl_guid, &value);
- if (ret == DSM_VALUE_INDONESIA_ENABLE)
+ if (!ret && value == DSM_VALUE_INDONESIA_ENABLE)
config_bitmap |=
cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK);
/*
** Evaluate func 'DSM_FUNC_DISABLE_SRD'
*/
- ret = iwl_acpi_eval_dsm_func(fwrt->dev, DSM_FUNC_DISABLE_SRD);
-
- if (ret == DSM_VALUE_SRD_PASSIVE)
- config_bitmap |=
- cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK);
-
- else if (ret == DSM_VALUE_SRD_DISABLE)
- config_bitmap |=
- cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK);
+ ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0,
+ DSM_FUNC_DISABLE_SRD,
+ &iwl_guid, &value);
+ if (!ret) {
+ if (value == DSM_VALUE_SRD_PASSIVE)
+ config_bitmap |=
+ cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK);
+ else if (value == DSM_VALUE_SRD_DISABLE)
+ config_bitmap |=
+ cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK);
+ }
return config_bitmap;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
index d16e6ec08c9f..b858e998999c 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
@@ -78,6 +78,7 @@ enum iwl_dsm_funcs_rev_0 {
DSM_FUNC_DISABLE_SRD = 1,
DSM_FUNC_ENABLE_INDONESIA_5G2 = 2,
DSM_FUNC_11AX_ENABLEMENT = 6,
+ DSM_FUNC_ENABLE_UNII4_CHAN = 7
};
enum iwl_dsm_values_srd {
@@ -116,6 +117,9 @@ void *iwl_acpi_get_object(struct device *dev, acpi_string method);
int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func,
const guid_t *guid, u8 *value);
+int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func,
+ const guid_t *guid, u32 *value);
+
union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
union acpi_object *data,
int data_size, int *tbl_rev);
@@ -182,6 +186,12 @@ static inline int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func,
return -ENOENT;
}
+static inline int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func,
+ const guid_t *guid, u32 *value)
+{
+ return -ENOENT;
+}
+
static inline union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
union acpi_object *data,
int data_size,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
index c625d319142e..ce060c3dfd7b 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
@@ -535,11 +535,6 @@ enum iwl_legacy_cmds {
OFFLOADS_QUERY_CMD = 0xd5,
/**
- * @REMOTE_WAKE_CONFIG_CMD: &struct iwl_wowlan_remote_wake_config
- */
- REMOTE_WAKE_CONFIG_CMD = 0xd6,
-
- /**
* @D0I3_END_CMD: End D0i3/D3 state, no command data
*/
D0I3_END_CMD = 0xed,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
index 758639084e0c..b2e7ef3ddc88 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2012-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@@ -159,6 +159,22 @@ struct iwl_proto_offload_cmd_v3_large {
struct iwl_ns_config ns_config[IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L];
} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_3 */
+/**
+ * struct iwl_proto_offload_cmd_v4 - ARP/NS offload configuration
+ * @sta_id: station id
+ * @common: common/IPv4 configuration
+ * @num_valid_ipv6_addrs: number of valid IPv6 addresses
+ * @targ_addrs: target IPv6 addresses
+ * @ns_config: NS offload configurations
+ */
+struct iwl_proto_offload_cmd_v4 {
+ __le32 sta_id;
+ struct iwl_proto_offload_cmd_common common;
+ __le32 num_valid_ipv6_addrs;
+ struct iwl_targ_addr targ_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L];
+ struct iwl_ns_config ns_config[IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L];
+} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_4 */
+
/*
* WOWLAN_PATTERNS
*/
@@ -302,13 +318,23 @@ struct iwl_wowlan_patterns_cmd {
/**
* @n_patterns: number of patterns
*/
- __le32 n_patterns;
+ u8 n_patterns;
+
+ /**
+ * @n_patterns: sta_id
+ */
+ u8 sta_id;
+
+ /**
+ * @reserved: reserved for alignment
+ */
+ __le16 reserved;
/**
* @patterns: the patterns, array length in @n_patterns
*/
struct iwl_wowlan_pattern_v2 patterns[];
-} __packed; /* WOWLAN_PATTERN_ARRAY_API_S_VER_2 */
+} __packed; /* WOWLAN_PATTERN_ARRAY_API_S_VER_3 */
enum iwl_wowlan_wakeup_filters {
IWL_WOWLAN_WAKEUP_MAGIC_PACKET = BIT(0),
@@ -339,9 +365,10 @@ enum iwl_wowlan_flags {
};
/**
- * struct iwl_wowlan_config_cmd - WoWLAN configuration
+ * struct iwl_wowlan_config_cmd - WoWLAN configuration (versions 5 and 6)
* @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters
- * @non_qos_seq: non-QoS sequence counter to use next
+ * @non_qos_seq: non-QoS sequence counter to use next.
+ * Reserved if the struct has version >= 6.
* @qos_seq: QoS sequence counters to use next
* @wowlan_ba_teardown_tids: bitmap of BA sessions to tear down
* @is_11n_connection: indicates HT connection
@@ -456,6 +483,23 @@ struct iwl_wowlan_kek_kck_material_cmd_v3 {
__le32 bigtk_cipher;
} __packed; /* KEK_KCK_MATERIAL_API_S_VER_3 */
+struct iwl_wowlan_kek_kck_material_cmd_v4 {
+ __le32 sta_id;
+ u8 kck[IWL_KCK_MAX_SIZE];
+ u8 kek[IWL_KEK_MAX_SIZE];
+ __le16 kck_len;
+ __le16 kek_len;
+ __le64 replay_ctr;
+ __le32 akm;
+ __le32 gtk_cipher;
+ __le32 igtk_cipher;
+ __le32 bigtk_cipher;
+} __packed; /* KEK_KCK_MATERIAL_API_S_VER_4 */
+
+struct iwl_wowlan_get_status_cmd {
+ __le32 sta_id;
+} __packed; /* WOWLAN_GET_STATUSES_CMD_API_S_VER_1 */
+
#define RF_KILL_INDICATOR_FOR_WOWLAN 0x87
enum iwl_wowlan_rekey_status {
@@ -604,12 +648,13 @@ struct iwl_wowlan_status_v7 {
} __packed; /* WOWLAN_STATUSES_API_S_VER_7 */
/**
- * struct iwl_wowlan_status_v9 - WoWLAN status (version 9)
+ * struct iwl_wowlan_status_v9 - WoWLAN status (versions 9 and 10)
* @gtk: GTK data
* @igtk: IGTK data
* @replay_ctr: GTK rekey replay counter
* @pattern_number: number of the matched pattern
- * @non_qos_seq_ctr: non-QoS sequence counter to use next
+ * @non_qos_seq_ctr: non-QoS sequence counter to use next.
+ * Reserved if the struct has version >= 10.
* @qos_seq_ctr: QoS sequence counters to use next
* @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason
* @num_of_gtk_rekeys: number of GTK rekeys
@@ -638,7 +683,7 @@ struct iwl_wowlan_status_v9 {
u8 tid_tear_down;
u8 reserved[3];
u8 wake_packet[]; /* can be truncated from _length to _bufsize */
-} __packed; /* WOWLAN_STATUSES_API_S_VER_9 */
+} __packed; /* WOWLAN_STATUSES_RSP_API_S_VER_9 */
/**
* struct iwl_wowlan_status - WoWLAN status
@@ -683,55 +728,6 @@ static inline u8 iwlmvm_wowlan_gtk_idx(struct iwl_wowlan_gtk_status *gtk)
return gtk->key_flags & IWL_WOWLAN_GTK_IDX_MASK;
}
-#define IWL_WOWLAN_TCP_MAX_PACKET_LEN 64
-#define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN 128
-#define IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS 2048
-
-struct iwl_tcp_packet_info {
- __le16 tcp_pseudo_header_checksum;
- __le16 tcp_payload_length;
-} __packed; /* TCP_PACKET_INFO_API_S_VER_2 */
-
-struct iwl_tcp_packet {
- struct iwl_tcp_packet_info info;
- u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8];
- u8 data[IWL_WOWLAN_TCP_MAX_PACKET_LEN];
-} __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */
-
-struct iwl_remote_wake_packet {
- struct iwl_tcp_packet_info info;
- u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8];
- u8 data[IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN];
-} __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */
-
-struct iwl_wowlan_remote_wake_config {
- __le32 connection_max_time; /* unused */
- /* TCP_PROTOCOL_CONFIG_API_S_VER_1 */
- u8 max_syn_retries;
- u8 max_data_retries;
- u8 tcp_syn_ack_timeout;
- u8 tcp_ack_timeout;
-
- struct iwl_tcp_packet syn_tx;
- struct iwl_tcp_packet synack_rx;
- struct iwl_tcp_packet keepalive_ack_rx;
- struct iwl_tcp_packet fin_tx;
-
- struct iwl_remote_wake_packet keepalive_tx;
- struct iwl_remote_wake_packet wake_rx;
-
- /* REMOTE_WAKE_OFFSET_INFO_API_S_VER_1 */
- u8 sequence_number_offset;
- u8 sequence_number_length;
- u8 token_offset;
- u8 token_length;
- /* REMOTE_WAKE_PROTOCOL_PARAMS_API_S_VER_1 */
- __le32 initial_sequence_number;
- __le16 keepalive_interval;
- __le16 num_tokens;
- u8 tokens[IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS];
-} __packed; /* REMOTE_WAKE_CONFIG_API_S_VER_2 */
-
/* TODO: NetDetect API */
#endif /* __iwl_fw_api_d3_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h
index d299bba3aa54..985b0dc5b52a 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h
@@ -64,6 +64,12 @@ enum iwl_data_path_subcmd_ids {
RX_NO_DATA_NOTIF = 0xF5,
/**
+ * @THERMAL_DUAL_CHAIN_DISABLE_REQ: firmware request for SMPS mode,
+ * &struct iwl_thermal_dual_chain_request
+ */
+ THERMAL_DUAL_CHAIN_REQUEST = 0xF6,
+
+ /**
* @TLC_MNG_UPDATE_NOTIF: &struct iwl_tlc_update_notif
*/
TLC_MNG_UPDATE_NOTIF = 0xF7,
@@ -169,4 +175,24 @@ struct iwl_datapath_monitor_notif {
u8 reserved[3];
} __packed; /* MONITOR_NTF_API_S_VER_1 */
+/**
+ * enum iwl_thermal_dual_chain_req_events - firmware SMPS request event
+ * @THERMAL_DUAL_CHAIN_REQ_ENABLE: (re-)enable dual-chain operation
+ * (subject to other constraints)
+ * @THERMAL_DUAL_CHAIN_REQ_DISABLE: disable dual-chain operation
+ * (static SMPS)
+ */
+enum iwl_thermal_dual_chain_req_events {
+ THERMAL_DUAL_CHAIN_REQ_ENABLE,
+ THERMAL_DUAL_CHAIN_REQ_DISABLE,
+}; /* THERMAL_DUAL_CHAIN_DISABLE_STATE_API_E_VER_1 */
+
+/**
+ * struct iwl_thermal_dual_chain_request - SMPS request
+ * @event: the type of request, see &enum iwl_thermal_dual_chain_req_events
+ */
+struct iwl_thermal_dual_chain_request {
+ __le32 event;
+} __packed; /* THERMAL_DUAL_CHAIN_DISABLE_REQ_NTFY_API_S_VER_1 */
+
#endif /* __iwl_fw_api_datapath_h__ */
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 996d5cc5bd9a..5a2d9a1f7e73 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2021 Intel Corporation
*/
#ifndef __iwl_fw_dbg_tlv_h__
#define __iwl_fw_dbg_tlv_h__
@@ -11,6 +11,7 @@
#define IWL_FW_INI_MAX_NAME 32
#define IWL_FW_INI_MAX_CFG_NAME 64
#define IWL_FW_INI_DOMAIN_ALWAYS_ON 0
+#define IWL_FW_INI_REGION_V2_MASK 0x0000FFFF
/**
* struct iwl_fw_ini_hcmd
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
index dc8f2777e944..cf48c6fa8f65 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
@@ -453,6 +453,25 @@ struct iwl_lari_config_change_cmd_v3 {
} __packed; /* LARI_CHANGE_CONF_CMD_S_VER_3 */
/**
+ * struct iwl_lari_config_change_cmd_v4 - change LARI configuration
+ * @config_bitmap: Bitmap of the config commands. Each bit will trigger a
+ * different predefined FW config operation.
+ * @oem_uhb_allow_bitmap: Bitmap of UHB enabled MCC sets.
+ * @oem_11ax_allow_bitmap: Bitmap of 11ax allowed MCCs. There are two bits
+ * per country, one to indicate whether to override and the other to
+ * indicate the value to use.
+ * @oem_unii4_allow_bitmap: Bitmap of unii4 allowed MCCs.There are two bits
+ * per country, one to indicate whether to override and the other to
+ * indicate allow/disallow unii4 channels.
+ */
+struct iwl_lari_config_change_cmd_v4 {
+ __le32 config_bitmap;
+ __le32 oem_uhb_allow_bitmap;
+ __le32 oem_11ax_allow_bitmap;
+ __le32 oem_unii4_allow_bitmap;
+} __packed; /* LARI_CHANGE_CONF_CMD_S_VER_4 */
+
+/**
* struct iwl_pnvm_init_complete_ntfy - PNVM initialization complete
* @status: PNVM image loading status
*/
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
index cc4e18ca9566..df7c55e06f54 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
@@ -1933,6 +1933,13 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list,
u32 num_of_ranges, i, size;
void *range;
+ /*
+ * The higher part of the ID in version 2 is irrelevant for
+ * us, so mask it out.
+ */
+ if (le32_to_cpu(reg->hdr.version) == 2)
+ id &= IWL_FW_INI_REGION_V2_MASK;
+
if (!ops->get_num_of_ranges || !ops->get_size || !ops->fill_mem_hdr ||
!ops->fill_range)
return 0;
@@ -1957,7 +1964,7 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list,
num_of_ranges = ops->get_num_of_ranges(fwrt, reg_data);
header = (void *)tlv->data;
- header->region_id = reg->id;
+ header->region_id = cpu_to_le32(id);
header->num_of_ranges = cpu_to_le32(num_of_ranges);
header->name_len = cpu_to_le32(IWL_FW_INI_MAX_NAME);
memcpy(header->name, reg->name, IWL_FW_INI_MAX_NAME);
@@ -2752,44 +2759,6 @@ void iwl_fw_dbg_stop_sync(struct iwl_fw_runtime *fwrt)
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_stop_sync);
-#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;
- 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))
- 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);
-}
-IWL_EXPORT_SYMBOL(iwl_fw_error_print_fseq_regs);
-
static int iwl_fw_dbg_suspend_resume_hcmd(struct iwl_trans *trans, bool suspend)
{
struct iwl_dbg_suspend_resume_cmd cmd = {
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
index 49fa2f5f8c7e..c0e84ef84f5d 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2005-2014, 2018-2019 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2019, 2021 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@@ -321,4 +321,6 @@ static inline void iwl_fwrt_update_fw_versions(struct iwl_fw_runtime *fwrt,
fwrt->dump.fw_ver.umac_minor = le32_to_cpu(umac->umac_minor);
}
}
+
+void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt);
#endif /* __iwl_fw_dbg_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
new file mode 100644
index 000000000000..a1842205e86a
--- /dev/null
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
+ * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
+ * Copyright (C) 2015-2017 Intel Deutschland GmbH
+ */
+#include <linux/devcoredump.h>
+#include "iwl-drv.h"
+#include "runtime.h"
+#include "dbg.h"
+#include "debugfs.h"
+#include "iwl-io.h"
+#include "iwl-prph.h"
+#include "iwl-csr.h"
+
+/*
+ * Note: This structure is read from the device with IO accesses,
+ * and the reading already does the endian conversion. As it is
+ * read with u32-sized accesses, any members with a different size
+ * need to be ordered correctly though!
+ */
+struct iwl_error_event_table_v1 {
+ u32 valid; /* (nonzero) valid, (0) log is empty */
+ u32 error_id; /* type of error */
+ u32 pc; /* program counter */
+ u32 blink1; /* branch link */
+ u32 blink2; /* branch link */
+ u32 ilink1; /* interrupt link */
+ u32 ilink2; /* interrupt link */
+ u32 data1; /* error-specific data */
+ u32 data2; /* error-specific data */
+ u32 data3; /* error-specific data */
+ u32 bcon_time; /* beacon timer */
+ u32 tsf_low; /* network timestamp function timer */
+ u32 tsf_hi; /* network timestamp function timer */
+ u32 gp1; /* GP1 timer register */
+ u32 gp2; /* GP2 timer register */
+ u32 gp3; /* GP3 timer register */
+ u32 ucode_ver; /* uCode version */
+ u32 hw_ver; /* HW Silicon version */
+ u32 brd_ver; /* HW board version */
+ u32 log_pc; /* log program counter */
+ u32 frame_ptr; /* frame pointer */
+ u32 stack_ptr; /* stack pointer */
+ u32 hcmd; /* last host command header */
+ u32 isr0; /* isr status register LMPM_NIC_ISR0:
+ * rxtx_flag */
+ u32 isr1; /* isr status register LMPM_NIC_ISR1:
+ * host_flag */
+ u32 isr2; /* isr status register LMPM_NIC_ISR2:
+ * enc_flag */
+ u32 isr3; /* isr status register LMPM_NIC_ISR3:
+ * time_flag */
+ u32 isr4; /* isr status register LMPM_NIC_ISR4:
+ * wico interrupt */
+ u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */
+ u32 wait_event; /* wait event() caller address */
+ u32 l2p_control; /* L2pControlField */
+ u32 l2p_duration; /* L2pDurationField */
+ u32 l2p_mhvalid; /* L2pMhValidBits */
+ u32 l2p_addr_match; /* L2pAddrMatchStat */
+ u32 lmpm_pmg_sel; /* indicate which clocks are turned on
+ * (LMPM_PMG_SEL) */
+ u32 u_timestamp; /* indicate when the date and time of the
+ * compilation */
+ u32 flow_handler; /* FH read/write pointers, RX credit */
+} __packed /* LOG_ERROR_TABLE_API_S_VER_1 */;
+
+struct iwl_error_event_table {
+ u32 valid; /* (nonzero) valid, (0) log is empty */
+ u32 error_id; /* type of error */
+ u32 trm_hw_status0; /* TRM HW status */
+ u32 trm_hw_status1; /* TRM HW status */
+ u32 blink2; /* branch link */
+ u32 ilink1; /* interrupt link */
+ u32 ilink2; /* interrupt link */
+ u32 data1; /* error-specific data */
+ u32 data2; /* error-specific data */
+ u32 data3; /* error-specific data */
+ u32 bcon_time; /* beacon timer */
+ u32 tsf_low; /* network timestamp function timer */
+ u32 tsf_hi; /* network timestamp function timer */
+ u32 gp1; /* GP1 timer register */
+ u32 gp2; /* GP2 timer register */
+ u32 fw_rev_type; /* firmware revision type */
+ u32 major; /* uCode version major */
+ u32 minor; /* uCode version minor */
+ u32 hw_ver; /* HW Silicon version */
+ u32 brd_ver; /* HW board version */
+ u32 log_pc; /* log program counter */
+ u32 frame_ptr; /* frame pointer */
+ u32 stack_ptr; /* stack pointer */
+ u32 hcmd; /* last host command header */
+ u32 isr0; /* isr status register LMPM_NIC_ISR0:
+ * rxtx_flag */
+ u32 isr1; /* isr status register LMPM_NIC_ISR1:
+ * host_flag */
+ u32 isr2; /* isr status register LMPM_NIC_ISR2:
+ * enc_flag */
+ u32 isr3; /* isr status register LMPM_NIC_ISR3:
+ * time_flag */
+ u32 isr4; /* isr status register LMPM_NIC_ISR4:
+ * wico interrupt */
+ u32 last_cmd_id; /* last HCMD id handled by the firmware */
+ u32 wait_event; /* wait event() caller address */
+ u32 l2p_control; /* L2pControlField */
+ u32 l2p_duration; /* L2pDurationField */
+ u32 l2p_mhvalid; /* L2pMhValidBits */
+ u32 l2p_addr_match; /* L2pAddrMatchStat */
+ u32 lmpm_pmg_sel; /* indicate which clocks are turned on
+ * (LMPM_PMG_SEL) */
+ u32 u_timestamp; /* indicate when the date and time of the
+ * compilation */
+ u32 flow_handler; /* FH read/write pointers, RX credit */
+} __packed /* LOG_ERROR_TABLE_API_S_VER_3 */;
+
+/*
+ * UMAC error struct - relevant starting from family 8000 chip.
+ * Note: This structure is read from the device with IO accesses,
+ * and the reading already does the endian conversion. As it is
+ * read with u32-sized accesses, any members with a different size
+ * need to be ordered correctly though!
+ */
+struct iwl_umac_error_event_table {
+ u32 valid; /* (nonzero) valid, (0) log is empty */
+ u32 error_id; /* type of error */
+ u32 blink1; /* branch link */
+ u32 blink2; /* branch link */
+ u32 ilink1; /* interrupt link */
+ u32 ilink2; /* interrupt link */
+ u32 data1; /* error-specific data */
+ u32 data2; /* error-specific data */
+ u32 data3; /* error-specific data */
+ u32 umac_major;
+ u32 umac_minor;
+ u32 frame_pointer; /* core register 27*/
+ u32 stack_pointer; /* core register 28 */
+ u32 cmd_header; /* latest host cmd sent to UMAC */
+ u32 nic_isr_pref; /* ISR status register */
+} __packed;
+
+#define ERROR_START_OFFSET (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+
+static void iwl_fwrt_dump_umac_error_log(struct iwl_fw_runtime *fwrt)
+{
+ struct iwl_trans *trans = fwrt->trans;
+ struct iwl_umac_error_event_table table = {};
+ u32 base = fwrt->trans->dbg.umac_error_event_table;
+
+ if (!base &&
+ !(fwrt->trans->dbg.error_event_table_tlv_status &
+ IWL_ERROR_EVENT_TABLE_UMAC))
+ return;
+
+ iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
+
+ if (table.valid)
+ fwrt->dump.umac_err_id = table.error_id;
+
+ if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
+ IWL_ERR(trans, "Start IWL Error Log Dump:\n");
+ IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n",
+ fwrt->trans->status, table.valid);
+ }
+
+ IWL_ERR(fwrt, "0x%08X | %s\n", table.error_id,
+ iwl_fw_lookup_assert_desc(table.error_id));
+ IWL_ERR(fwrt, "0x%08X | umac branchlink1\n", table.blink1);
+ IWL_ERR(fwrt, "0x%08X | umac branchlink2\n", table.blink2);
+ IWL_ERR(fwrt, "0x%08X | umac interruptlink1\n", table.ilink1);
+ IWL_ERR(fwrt, "0x%08X | umac interruptlink2\n", table.ilink2);
+ IWL_ERR(fwrt, "0x%08X | umac data1\n", table.data1);
+ IWL_ERR(fwrt, "0x%08X | umac data2\n", table.data2);
+ IWL_ERR(fwrt, "0x%08X | umac data3\n", table.data3);
+ IWL_ERR(fwrt, "0x%08X | umac major\n", table.umac_major);
+ IWL_ERR(fwrt, "0x%08X | umac minor\n", table.umac_minor);
+ IWL_ERR(fwrt, "0x%08X | frame pointer\n", table.frame_pointer);
+ IWL_ERR(fwrt, "0x%08X | stack pointer\n", table.stack_pointer);
+ IWL_ERR(fwrt, "0x%08X | last host cmd\n", table.cmd_header);
+ IWL_ERR(fwrt, "0x%08X | isr status reg\n", table.nic_isr_pref);
+}
+
+static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_num)
+{
+ struct iwl_trans *trans = fwrt->trans;
+ struct iwl_error_event_table table = {};
+ u32 val, base = fwrt->trans->dbg.lmac_error_event_table[lmac_num];
+
+ if (fwrt->cur_fw_img == IWL_UCODE_INIT) {
+ if (!base)
+ base = fwrt->fw->init_errlog_ptr;
+ } else {
+ if (!base)
+ base = fwrt->fw->inst_errlog_ptr;
+ }
+
+ if (base < 0x400000) {
+ IWL_ERR(fwrt,
+ "Not valid error log pointer 0x%08X for %s uCode\n",
+ base,
+ (fwrt->cur_fw_img == IWL_UCODE_INIT)
+ ? "Init" : "RT");
+ return;
+ }
+
+ /* check if there is a HW error */
+ val = iwl_trans_read_mem32(trans, base);
+ if (((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50)) {
+ int err;
+
+ IWL_ERR(trans, "HW error, resetting before reading\n");
+
+ /* reset the device */
+ iwl_trans_sw_reset(trans);
+
+ err = iwl_finish_nic_init(trans, trans->trans_cfg);
+ if (err)
+ return;
+ }
+
+ iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
+
+ if (table.valid)
+ fwrt->dump.lmac_err_id[lmac_num] = table.error_id;
+
+ if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
+ IWL_ERR(trans, "Start IWL Error Log Dump:\n");
+ IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n",
+ fwrt->trans->status, table.valid);
+ }
+
+ /* Do not change this output - scripts rely on it */
+
+ IWL_ERR(fwrt, "Loaded firmware version: %s\n", fwrt->fw->fw_version);
+
+ IWL_ERR(fwrt, "0x%08X | %-28s\n", table.error_id,
+ iwl_fw_lookup_assert_desc(table.error_id));
+ IWL_ERR(fwrt, "0x%08X | trm_hw_status0\n", table.trm_hw_status0);
+ IWL_ERR(fwrt, "0x%08X | trm_hw_status1\n", table.trm_hw_status1);
+ IWL_ERR(fwrt, "0x%08X | branchlink2\n", table.blink2);
+ IWL_ERR(fwrt, "0x%08X | interruptlink1\n", table.ilink1);
+ IWL_ERR(fwrt, "0x%08X | interruptlink2\n", table.ilink2);
+ IWL_ERR(fwrt, "0x%08X | data1\n", table.data1);
+ IWL_ERR(fwrt, "0x%08X | data2\n", table.data2);
+ IWL_ERR(fwrt, "0x%08X | data3\n", table.data3);
+ IWL_ERR(fwrt, "0x%08X | beacon time\n", table.bcon_time);
+ IWL_ERR(fwrt, "0x%08X | tsf low\n", table.tsf_low);
+ IWL_ERR(fwrt, "0x%08X | tsf hi\n", table.tsf_hi);
+ IWL_ERR(fwrt, "0x%08X | time gp1\n", table.gp1);
+ IWL_ERR(fwrt, "0x%08X | time gp2\n", table.gp2);
+ IWL_ERR(fwrt, "0x%08X | uCode revision type\n", table.fw_rev_type);
+ IWL_ERR(fwrt, "0x%08X | uCode version major\n", table.major);
+ IWL_ERR(fwrt, "0x%08X | uCode version minor\n", table.minor);
+ IWL_ERR(fwrt, "0x%08X | hw version\n", table.hw_ver);
+ IWL_ERR(fwrt, "0x%08X | board version\n", table.brd_ver);
+ IWL_ERR(fwrt, "0x%08X | hcmd\n", table.hcmd);
+ IWL_ERR(fwrt, "0x%08X | isr0\n", table.isr0);
+ IWL_ERR(fwrt, "0x%08X | isr1\n", table.isr1);
+ IWL_ERR(fwrt, "0x%08X | isr2\n", table.isr2);
+ IWL_ERR(fwrt, "0x%08X | isr3\n", table.isr3);
+ IWL_ERR(fwrt, "0x%08X | isr4\n", table.isr4);
+ IWL_ERR(fwrt, "0x%08X | last cmd Id\n", table.last_cmd_id);
+ IWL_ERR(fwrt, "0x%08X | wait_event\n", table.wait_event);
+ IWL_ERR(fwrt, "0x%08X | l2p_control\n", table.l2p_control);
+ IWL_ERR(fwrt, "0x%08X | l2p_duration\n", table.l2p_duration);
+ IWL_ERR(fwrt, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid);
+ IWL_ERR(fwrt, "0x%08X | l2p_addr_match\n", table.l2p_addr_match);
+ IWL_ERR(fwrt, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
+ IWL_ERR(fwrt, "0x%08X | timestamp\n", table.u_timestamp);
+ IWL_ERR(fwrt, "0x%08X | flow_handler\n", table.flow_handler);
+}
+
+/*
+ * TCM error struct.
+ * Note: This structure is read from the device with IO accesses,
+ * and the reading already does the endian conversion. As it is
+ * read with u32-sized accesses, any members with a different size
+ * need to be ordered correctly though!
+ */
+struct iwl_tcm_error_event_table {
+ u32 valid;
+ u32 error_id;
+ u32 blink2;
+ u32 ilink1;
+ u32 ilink2;
+ u32 data1, data2, data3;
+ u32 logpc;
+ u32 frame_pointer;
+ u32 stack_pointer;
+ u32 msgid;
+ u32 isr;
+ u32 hw_status[5];
+ u32 sw_status[1];
+ u32 reserved[4];
+} __packed; /* TCM_LOG_ERROR_TABLE_API_S_VER_1 */
+
+static void iwl_fwrt_dump_tcm_error_log(struct iwl_fw_runtime *fwrt)
+{
+ struct iwl_trans *trans = fwrt->trans;
+ struct iwl_tcm_error_event_table table = {};
+ u32 base = fwrt->trans->dbg.tcm_error_event_table;
+ int i;
+
+ if (!base ||
+ !(fwrt->trans->dbg.error_event_table_tlv_status &
+ IWL_ERROR_EVENT_TABLE_TCM))
+ return;
+
+ iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
+
+ IWL_ERR(fwrt, "TCM status:\n");
+ IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id);
+ IWL_ERR(fwrt, "0x%08X | tcm branchlink2\n", table.blink2);
+ IWL_ERR(fwrt, "0x%08X | tcm interruptlink1\n", table.ilink1);
+ IWL_ERR(fwrt, "0x%08X | tcm interruptlink2\n", table.ilink2);
+ IWL_ERR(fwrt, "0x%08X | tcm data1\n", table.data1);
+ IWL_ERR(fwrt, "0x%08X | tcm data2\n", table.data2);
+ IWL_ERR(fwrt, "0x%08X | tcm data3\n", table.data3);
+ IWL_ERR(fwrt, "0x%08X | tcm log PC\n", table.logpc);
+ IWL_ERR(fwrt, "0x%08X | tcm frame pointer\n", table.frame_pointer);
+ IWL_ERR(fwrt, "0x%08X | tcm stack pointer\n", table.stack_pointer);
+ IWL_ERR(fwrt, "0x%08X | tcm msg ID\n", table.msgid);
+ IWL_ERR(fwrt, "0x%08X | tcm ISR status\n", table.isr);
+ for (i = 0; i < ARRAY_SIZE(table.hw_status); i++)
+ IWL_ERR(fwrt, "0x%08X | tcm HW status[%d]\n",
+ table.hw_status[i], i);
+ for (i = 0; i < ARRAY_SIZE(table.sw_status); i++)
+ IWL_ERR(fwrt, "0x%08X | tcm SW status[%d]\n",
+ table.sw_status[i], i);
+}
+
+static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt)
+{
+ struct iwl_trans *trans = fwrt->trans;
+ u32 error, data1;
+
+ if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) {
+ error = UMAG_SB_CPU_2_STATUS;
+ data1 = UMAG_SB_CPU_1_STATUS;
+ } else if (fwrt->trans->trans_cfg->device_family >=
+ IWL_DEVICE_FAMILY_8000) {
+ error = SB_CPU_2_STATUS;
+ data1 = SB_CPU_1_STATUS;
+ } else {
+ return;
+ }
+
+ error = iwl_read_umac_prph(trans, UMAG_SB_CPU_2_STATUS);
+
+ IWL_ERR(trans, "IML/ROM dump:\n");
+
+ if (error & 0xFFFF0000)
+ IWL_ERR(trans, "0x%04X | IML/ROM SYSASSERT\n", error >> 16);
+
+ IWL_ERR(fwrt, "0x%08X | IML/ROM error/state\n", error);
+ IWL_ERR(fwrt, "0x%08X | IML/ROM data1\n",
+ iwl_read_umac_prph(trans, data1));
+
+ if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000)
+ IWL_ERR(fwrt, "0x%08X | IML/ROM WFPM_AUTH_KEY_0\n",
+ iwl_read_umac_prph(trans, SB_MODIFY_CFG_FLAG));
+}
+
+#define FSEQ_REG(x) { .addr = (x), .str = #x, }
+
+static void iwl_fwrt_dump_fseq_regs(struct iwl_fw_runtime *fwrt)
+{
+ struct iwl_trans *trans = fwrt->trans;
+ 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))
+ 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);
+}
+
+void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt)
+{
+ if (!test_bit(STATUS_DEVICE_ENABLED, &fwrt->trans->status)) {
+ IWL_ERR(fwrt,
+ "DEVICE_ENABLED bit is not set. Aborting dump.\n");
+ return;
+ }
+
+ iwl_fwrt_dump_lmac_error_log(fwrt, 0);
+ if (fwrt->trans->dbg.lmac_error_event_table[1])
+ iwl_fwrt_dump_lmac_error_log(fwrt, 1);
+ iwl_fwrt_dump_umac_error_log(fwrt);
+ iwl_fwrt_dump_tcm_error_log(fwrt);
+ iwl_fwrt_dump_iml_error_log(fwrt);
+ iwl_fwrt_dump_fseq_regs(fwrt);
+}
+IWL_EXPORT_SYMBOL(iwl_fwrt_dump_error_logs);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
index f9c5cf538ad1..9a8c7b7a0816 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2008-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2008-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -52,7 +52,8 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_INIT_DATA = 4,
IWL_UCODE_TLV_BOOT = 5,
IWL_UCODE_TLV_PROBE_MAX_LEN = 6, /* a u32 value */
- IWL_UCODE_TLV_PAN = 7,
+ IWL_UCODE_TLV_PAN = 7, /* deprecated -- only used in DVM */
+ IWL_UCODE_TLV_MEM_DESC = 7, /* replaces PAN in non-DVM */
IWL_UCODE_TLV_RUNT_EVTLOG_PTR = 8,
IWL_UCODE_TLV_RUNT_EVTLOG_SIZE = 9,
IWL_UCODE_TLV_RUNT_ERRLOG_PTR = 10,
@@ -97,6 +98,7 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_PNVM_VERSION = 62,
IWL_UCODE_TLV_PNVM_SKU = 64,
+ IWL_UCODE_TLV_TCM_DEBUG_ADDRS = 65,
IWL_UCODE_TLV_FW_NUM_STATIONS = IWL_UCODE_TLV_CONST_BASE + 0,
@@ -277,10 +279,11 @@ enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_BAND_IN_RX_DATA = (__force iwl_ucode_tlv_api_t)59,
- NUM_IWL_UCODE_TLV_API
#ifdef __CHECKER__
- /* sparse says it cannot increment the previous enum member */
- = 128
+ /* sparse says it cannot increment the previous enum member */
+#define NUM_IWL_UCODE_TLV_API 128
+#else
+ NUM_IWL_UCODE_TLV_API
#endif
};
@@ -411,6 +414,7 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_PROTECTED_TWT = (__force iwl_ucode_tlv_capa_t)56,
IWL_UCODE_TLV_CAPA_FW_RESET_HANDSHAKE = (__force iwl_ucode_tlv_capa_t)57,
IWL_UCODE_TLV_CAPA_PASSIVE_6GHZ_SCAN = (__force iwl_ucode_tlv_capa_t)58,
+ IWL_UCODE_TLV_CAPA_BROADCAST_TWT = (__force iwl_ucode_tlv_capa_t)60,
/* set 2 */
IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64,
@@ -446,10 +450,11 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT = (__force iwl_ucode_tlv_capa_t)100,
IWL_UCODE_TLV_CAPA_RFIM_SUPPORT = (__force iwl_ucode_tlv_capa_t)102,
- NUM_IWL_UCODE_TLV_CAPA
#ifdef __CHECKER__
- /* sparse says it cannot increment the previous enum member */
- = 128
+ /* sparse says it cannot increment the previous enum member */
+#define NUM_IWL_UCODE_TLV_CAPA 128
+#else
+ NUM_IWL_UCODE_TLV_CAPA
#endif
};
@@ -946,6 +951,10 @@ struct iwl_fw_cmd_version {
u8 notif_ver;
} __packed;
+struct iwl_fw_tcm_error_addr {
+ __le32 addr;
+}; /* FW_TLV_TCM_ERROR_INFO_ADDRS_S */
+
static inline size_t _iwl_tlv_array_len(const struct iwl_ucode_tlv *tlv,
size_t fixed_size, size_t var_size)
{
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
index 40f2109a097f..2403490cbc26 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
@@ -10,7 +10,7 @@
#include "fw/api/commands.h"
#include "fw/api/nvm-reg.h"
#include "fw/api/alive.h"
-#include <linux/efi.h>
+#include "fw/uefi.h"
struct iwl_pnvm_section {
__le32 offset;
@@ -220,83 +220,6 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data,
return -ENOENT;
}
-#if defined(CONFIG_EFI)
-
-#define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \
- 0xb2, 0xec, 0xf5, 0xa3, \
- 0x59, 0x4f, 0x4a, 0xea)
-
-#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm"
-
-#define IWL_HARDCODED_PNVM_SIZE 4096
-
-struct pnvm_sku_package {
- u8 rev;
- u8 reserved1[3];
- u32 total_size;
- u8 n_skus;
- u8 reserved2[11];
- u8 data[];
-};
-
-static int iwl_pnvm_get_from_efi(struct iwl_trans *trans,
- u8 **data, size_t *len)
-{
- struct efivar_entry *pnvm_efivar;
- struct pnvm_sku_package *package;
- unsigned long package_size;
- int err;
-
- pnvm_efivar = kzalloc(sizeof(*pnvm_efivar), GFP_KERNEL);
- if (!pnvm_efivar)
- return -ENOMEM;
-
- memcpy(&pnvm_efivar->var.VariableName, IWL_UEFI_OEM_PNVM_NAME,
- sizeof(IWL_UEFI_OEM_PNVM_NAME));
- pnvm_efivar->var.VendorGuid = IWL_EFI_VAR_GUID;
-
- /*
- * TODO: we hardcode a maximum length here, because reading
- * from the UEFI is not working. To implement this properly,
- * we have to call efivar_entry_size().
- */
- package_size = IWL_HARDCODED_PNVM_SIZE;
-
- package = kmalloc(package_size, GFP_KERNEL);
- if (!package) {
- err = -ENOMEM;
- goto out;
- }
-
- err = efivar_entry_get(pnvm_efivar, NULL, &package_size, package);
- if (err) {
- IWL_DEBUG_FW(trans,
- "PNVM UEFI variable not found %d (len %lu)\n",
- err, package_size);
- goto out;
- }
-
- IWL_DEBUG_FW(trans, "Read PNVM fro UEFI with size %lu\n", package_size);
-
- *data = kmemdup(package->data, *len, GFP_KERNEL);
- if (!*data)
- err = -ENOMEM;
- *len = package_size - sizeof(*package);
-
-out:
- kfree(package);
- kfree(pnvm_efivar);
-
- return err;
-}
-#else /* CONFIG_EFI */
-static inline int iwl_pnvm_get_from_efi(struct iwl_trans *trans,
- u8 **data, size_t *len)
-{
- return -EOPNOTSUPP;
-}
-#endif /* CONFIG_EFI */
-
static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len)
{
const struct firmware *pnvm;
@@ -335,6 +258,7 @@ int iwl_pnvm_load(struct iwl_trans *trans,
{
u8 *data;
size_t len;
+ struct pnvm_sku_package *package;
struct iwl_notification_wait pnvm_wait;
static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP,
PNVM_INIT_COMPLETE_NTFY) };
@@ -356,9 +280,19 @@ int iwl_pnvm_load(struct iwl_trans *trans,
}
/* First attempt to get the PNVM from BIOS */
- ret = iwl_pnvm_get_from_efi(trans, &data, &len);
- if (!ret)
- goto parse;
+ package = iwl_uefi_get_pnvm(trans, &len);
+ if (!IS_ERR_OR_NULL(package)) {
+ data = kmemdup(package->data, len, GFP_KERNEL);
+
+ /* free package regardless of whether kmemdup succeeded */
+ kfree(package);
+
+ if (data) {
+ /* we need only the data size */
+ len -= sizeof(*package);
+ goto parse;
+ }
+ }
/* If it's not available, try from the filesystem */
ret = iwl_pnvm_get_from_fs(trans, &data, &len);
@@ -379,6 +313,30 @@ parse:
kfree(data);
skip_parse:
+ data = NULL;
+ /* now try to get the reduce power table, if not loaded yet */
+ if (!trans->reduce_power_loaded) {
+ data = iwl_uefi_get_reduced_power(trans, &len);
+ if (IS_ERR_OR_NULL(data)) {
+ /*
+ * Pretend we've loaded it - at least we've tried and
+ * couldn't load it at all, so there's no point in
+ * trying again over and over.
+ */
+ trans->reduce_power_loaded = true;
+
+ goto skip_reduce_power;
+ }
+ }
+
+ ret = iwl_trans_set_reduce_power(trans, data, len);
+ if (ret)
+ IWL_DEBUG_FW(trans,
+ "Failed to set reduce power table %d\n",
+ ret);
+ kfree(data);
+
+skip_reduce_power:
iwl_init_notification_wait(notif_wait, &pnvm_wait,
ntf_cmds, ARRAY_SIZE(ntf_cmds),
iwl_pnvm_complete_fn, trans);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h
index e4f91bce222d..61d3d4e0b7d9 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/******************************************************************************
*
- * Copyright(c) 2020 Intel Corporation
+ * Copyright(c) 2020-2021 Intel Corporation
*
*****************************************************************************/
@@ -10,7 +10,7 @@
#include "fw/notif-wait.h"
-#define MVM_UCODE_PNVM_TIMEOUT (HZ / 10)
+#define MVM_UCODE_PNVM_TIMEOUT (HZ / 4)
int iwl_pnvm_load(struct iwl_trans *trans,
struct iwl_notif_wait_data *notif_wait);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
new file mode 100644
index 000000000000..a7c79d814aa4
--- /dev/null
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright(c) 2021 Intel Corporation
+ */
+
+#include "iwl-drv.h"
+#include "pnvm.h"
+#include "iwl-prph.h"
+#include "iwl-io.h"
+
+#include "fw/uefi.h"
+#include "fw/api/alive.h"
+#include <linux/efi.h>
+
+#define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \
+ 0xb2, 0xec, 0xf5, 0xa3, \
+ 0x59, 0x4f, 0x4a, 0xea)
+
+void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
+{
+ struct efivar_entry *pnvm_efivar;
+ void *data;
+ unsigned long package_size;
+ int err;
+
+ *len = 0;
+
+ pnvm_efivar = kzalloc(sizeof(*pnvm_efivar), GFP_KERNEL);
+ if (!pnvm_efivar)
+ return ERR_PTR(-ENOMEM);
+
+ memcpy(&pnvm_efivar->var.VariableName, IWL_UEFI_OEM_PNVM_NAME,
+ sizeof(IWL_UEFI_OEM_PNVM_NAME));
+ pnvm_efivar->var.VendorGuid = IWL_EFI_VAR_GUID;
+
+ /*
+ * TODO: we hardcode a maximum length here, because reading
+ * from the UEFI is not working. To implement this properly,
+ * we have to call efivar_entry_size().
+ */
+ package_size = IWL_HARDCODED_PNVM_SIZE;
+
+ data = kmalloc(package_size, GFP_KERNEL);
+ if (!data) {
+ data = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ err = efivar_entry_get(pnvm_efivar, NULL, &package_size, data);
+ if (err) {
+ IWL_DEBUG_FW(trans,
+ "PNVM UEFI variable not found %d (len %zd)\n",
+ err, package_size);
+ kfree(data);
+ data = ERR_PTR(err);
+ goto out;
+ }
+
+ IWL_DEBUG_FW(trans, "Read PNVM from UEFI with size %zd\n", package_size);
+ *len = package_size;
+
+out:
+ kfree(pnvm_efivar);
+
+ return data;
+}
+
+static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans,
+ const u8 *data, size_t len)
+{
+ struct iwl_ucode_tlv *tlv;
+ u8 *reduce_power_data = NULL, *tmp;
+ u32 size = 0;
+
+ IWL_DEBUG_FW(trans, "Handling REDUCE_POWER section\n");
+
+ while (len >= sizeof(*tlv)) {
+ u32 tlv_len, tlv_type;
+
+ len -= sizeof(*tlv);
+ tlv = (void *)data;
+
+ tlv_len = le32_to_cpu(tlv->length);
+ tlv_type = le32_to_cpu(tlv->type);
+
+ if (len < tlv_len) {
+ IWL_ERR(trans, "invalid TLV len: %zd/%u\n",
+ len, tlv_len);
+ reduce_power_data = ERR_PTR(-EINVAL);
+ goto out;
+ }
+
+ data += sizeof(*tlv);
+
+ switch (tlv_type) {
+ case IWL_UCODE_TLV_MEM_DESC: {
+ IWL_DEBUG_FW(trans,
+ "Got IWL_UCODE_TLV_MEM_DESC len %d\n",
+ tlv_len);
+
+ IWL_DEBUG_FW(trans, "Adding data (size %d)\n", tlv_len);
+
+ tmp = krealloc(reduce_power_data, size + tlv_len, GFP_KERNEL);
+ if (!tmp) {
+ IWL_DEBUG_FW(trans,
+ "Couldn't allocate (more) reduce_power_data\n");
+
+ reduce_power_data = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ reduce_power_data = tmp;
+
+ memcpy(reduce_power_data + size, data, tlv_len);
+
+ size += tlv_len;
+
+ break;
+ }
+ case IWL_UCODE_TLV_PNVM_SKU:
+ IWL_DEBUG_FW(trans,
+ "New REDUCE_POWER section started, stop parsing.\n");
+ goto done;
+ default:
+ IWL_DEBUG_FW(trans, "Found TLV 0x%0x, len %d\n",
+ tlv_type, tlv_len);
+ break;
+ }
+
+ len -= ALIGN(tlv_len, 4);
+ data += ALIGN(tlv_len, 4);
+ }
+
+done:
+ if (!size) {
+ IWL_DEBUG_FW(trans, "Empty REDUCE_POWER, skipping.\n");
+ reduce_power_data = ERR_PTR(-ENOENT);
+ goto out;
+ }
+
+ IWL_INFO(trans, "loaded REDUCE_POWER\n");
+
+out:
+ return reduce_power_data;
+}
+
+static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
+ const u8 *data, size_t len)
+{
+ struct iwl_ucode_tlv *tlv;
+ void *sec_data;
+
+ IWL_DEBUG_FW(trans, "Parsing REDUCE_POWER data\n");
+
+ while (len >= sizeof(*tlv)) {
+ u32 tlv_len, tlv_type;
+
+ len -= sizeof(*tlv);
+ tlv = (void *)data;
+
+ tlv_len = le32_to_cpu(tlv->length);
+ tlv_type = le32_to_cpu(tlv->type);
+
+ if (len < tlv_len) {
+ IWL_ERR(trans, "invalid TLV len: %zd/%u\n",
+ len, tlv_len);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (tlv_type == IWL_UCODE_TLV_PNVM_SKU) {
+ struct iwl_sku_id *sku_id =
+ (void *)(data + sizeof(*tlv));
+
+ IWL_DEBUG_FW(trans,
+ "Got IWL_UCODE_TLV_PNVM_SKU len %d\n",
+ tlv_len);
+ IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n",
+ le32_to_cpu(sku_id->data[0]),
+ le32_to_cpu(sku_id->data[1]),
+ le32_to_cpu(sku_id->data[2]));
+
+ data += sizeof(*tlv) + ALIGN(tlv_len, 4);
+ len -= ALIGN(tlv_len, 4);
+
+ if (trans->sku_id[0] == le32_to_cpu(sku_id->data[0]) &&
+ trans->sku_id[1] == le32_to_cpu(sku_id->data[1]) &&
+ trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) {
+ sec_data = iwl_uefi_reduce_power_section(trans,
+ data,
+ len);
+ if (!IS_ERR(sec_data))
+ return sec_data;
+ } else {
+ IWL_DEBUG_FW(trans, "SKU ID didn't match!\n");
+ }
+ } else {
+ data += sizeof(*tlv) + ALIGN(tlv_len, 4);
+ len -= ALIGN(tlv_len, 4);
+ }
+ }
+
+ return ERR_PTR(-ENOENT);
+}
+
+void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
+{
+ struct efivar_entry *reduce_power_efivar;
+ struct pnvm_sku_package *package;
+ void *data = NULL;
+ unsigned long package_size;
+ int err;
+
+ *len = 0;
+
+ reduce_power_efivar = kzalloc(sizeof(*reduce_power_efivar), GFP_KERNEL);
+ if (!reduce_power_efivar)
+ return ERR_PTR(-ENOMEM);
+
+ memcpy(&reduce_power_efivar->var.VariableName, IWL_UEFI_REDUCED_POWER_NAME,
+ sizeof(IWL_UEFI_REDUCED_POWER_NAME));
+ reduce_power_efivar->var.VendorGuid = IWL_EFI_VAR_GUID;
+
+ /*
+ * TODO: we hardcode a maximum length here, because reading
+ * from the UEFI is not working. To implement this properly,
+ * we have to call efivar_entry_size().
+ */
+ package_size = IWL_HARDCODED_REDUCE_POWER_SIZE;
+
+ package = kmalloc(package_size, GFP_KERNEL);
+ if (!package) {
+ package = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ err = efivar_entry_get(reduce_power_efivar, NULL, &package_size, package);
+ if (err) {
+ IWL_DEBUG_FW(trans,
+ "Reduced Power UEFI variable not found %d (len %lu)\n",
+ err, package_size);
+ kfree(package);
+ data = ERR_PTR(err);
+ goto out;
+ }
+
+ IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n",
+ package_size);
+ *len = package_size;
+
+ IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n",
+ package->rev, package->total_size, package->n_skus);
+
+ data = iwl_uefi_reduce_power_parse(trans, package->data,
+ *len - sizeof(*package));
+
+ kfree(package);
+
+out:
+ kfree(reduce_power_efivar);
+
+ return data;
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
new file mode 100644
index 000000000000..45d0b36d79b5
--- /dev/null
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright(c) 2021 Intel Corporation
+ */
+
+
+#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm"
+#define IWL_UEFI_REDUCED_POWER_NAME L"UefiCnvWlanReducedPower"
+
+/*
+ * TODO: we have these hardcoded values that the caller must pass,
+ * because reading from the UEFI is not working. To implement this
+ * properly, we have to change iwl_pnvm_get_from_uefi() to call
+ * efivar_entry_size() and return the value to the caller instead.
+ */
+#define IWL_HARDCODED_PNVM_SIZE 4096
+#define IWL_HARDCODED_REDUCE_POWER_SIZE 32768
+
+struct pnvm_sku_package {
+ u8 rev;
+ u32 total_size;
+ u8 n_skus;
+ u32 reserved[2];
+ u8 data[];
+} __packed;
+
+#ifdef CONFIG_EFI
+void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len);
+void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len);
+#else /* CONFIG_EFI */
+static inline
+void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline
+void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+#endif /* CONFIG_EFI */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
index b35ffdfdf14b..bf6ee56d4d96 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
@@ -426,6 +426,7 @@ struct iwl_cfg {
#define IWL_CFG_RF_TYPE_HR1 0x10C
#define IWL_CFG_RF_TYPE_GF 0x10D
#define IWL_CFG_RF_TYPE_MR 0x110
+#define IWL_CFG_RF_TYPE_FM 0x112
#define IWL_CFG_RF_ID_TH 0x1
#define IWL_CFG_RF_ID_TH1 0x1
@@ -505,8 +506,11 @@ extern const char iwl_ax201_killer_1650s_name[];
extern const char iwl_ax201_killer_1650i_name[];
extern const char iwl_ax210_killer_1675w_name[];
extern const char iwl_ax210_killer_1675x_name[];
+extern const char iwl9560_killer_1550i_160_name[];
+extern const char iwl9560_killer_1550s_160_name[];
extern const char iwl_ax211_name[];
extern const char iwl_ax221_name[];
+extern const char iwl_ax231_name[];
extern const char iwl_ax411_name[];
#if IS_ENABLED(CONFIG_IWLDVM)
extern const struct iwl_cfg iwl5300_agn_cfg;
@@ -586,7 +590,6 @@ extern const struct iwl_cfg iwl_qu_b0_hr_b0;
extern const struct iwl_cfg iwl_qu_c0_hr_b0;
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;
@@ -613,6 +616,7 @@ extern const struct iwl_cfg iwl_cfg_ma_a0_hr_b0;
extern const struct iwl_cfg iwl_cfg_ma_a0_gf_a0;
extern const struct iwl_cfg iwl_cfg_ma_a0_gf4_a0;
extern const struct iwl_cfg iwl_cfg_ma_a0_mr_a0;
+extern const struct iwl_cfg iwl_cfg_ma_a0_fm_a0;
extern const struct iwl_cfg iwl_cfg_snj_a0_mr_a0;
extern const struct iwl_cfg iwl_cfg_so_a0_hr_a0;
extern const struct iwl_cfg iwl_cfg_quz_a0_hr_b0;
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
index 2be605cc6fbf..e1fec23ac07f 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2018, 2020 Intel Corporation
+ * Copyright (C) 2018, 2020-2021 Intel Corporation
*/
#ifndef __iwl_context_info_file_gen3_h__
#define __iwl_context_info_file_gen3_h__
@@ -128,6 +128,17 @@ struct iwl_prph_scratch_rbd_cfg {
} __packed; /* PERIPH_SCRATCH_RBD_CFG_S */
/*
+ * struct iwl_prph_scratch_uefi_cfg - prph scratch reduce power table
+ * @base_addr: reduce power table address
+ * @size: table size in dwords
+ */
+struct iwl_prph_scratch_uefi_cfg {
+ __le64 base_addr;
+ __le32 size;
+ __le32 reserved;
+} __packed; /* PERIPH_SCRATCH_UEFI_CFG_S */
+
+/*
* struct iwl_prph_scratch_ctrl_cfg - prph scratch ctrl and config
* @version: version information of context info and HW
* @control: control flags of FH configurations
@@ -141,6 +152,7 @@ struct iwl_prph_scratch_ctrl_cfg {
struct iwl_prph_scratch_pnvm_cfg pnvm_cfg;
struct iwl_prph_scratch_hwm_cfg hwm_cfg;
struct iwl_prph_scratch_rbd_cfg rbd_cfg;
+ struct iwl_prph_scratch_uefi_cfg reduce_power_cfg;
} __packed; /* PERIPH_SCRATCH_CTRL_CFG_S */
/*
@@ -151,7 +163,7 @@ struct iwl_prph_scratch_ctrl_cfg {
*/
struct iwl_prph_scratch {
struct iwl_prph_scratch_ctrl_cfg ctrl_cfg;
- __le32 reserved[16];
+ __le32 reserved[12];
struct iwl_context_info_dram dram;
} __packed; /* PERIPH_SCRATCH_S */
@@ -245,9 +257,11 @@ struct iwl_context_info_gen3 {
int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
const struct fw_img *fw);
-void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans);
+void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive);
int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
const void *data, u32 len);
+int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,
+ const void *data, u32 len);
#endif /* __iwl_context_info_file_gen3_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
index db312abd2e09..47e5a17c0f48 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2005-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2016 Intel Deutschland GmbH
*/
@@ -325,9 +325,6 @@ enum {
#define CSR_HW_RF_ID_TYPE_GF (0x0010D000)
#define CSR_HW_RF_ID_TYPE_GF4 (0x0010E000)
-/* HW_RF CHIP ID */
-#define CSR_HW_RF_ID_TYPE_CHIP_ID(_val) (((_val) >> 12) & 0xFFF)
-
/* HW_RF CHIP STEP */
#define CSR_HW_RF_STEP(_val) (((_val) >> 8) & 0xF)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
index 4cd8c39cc3e9..0ddd255a8cc1 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
@@ -57,7 +57,7 @@ dbg_ver_table[IWL_DBG_TLV_TYPE_NUM] = {
[IWL_DBG_TLV_TYPE_DEBUG_INFO] = {.min_ver = 1, .max_ver = 1,},
[IWL_DBG_TLV_TYPE_BUF_ALLOC] = {.min_ver = 1, .max_ver = 1,},
[IWL_DBG_TLV_TYPE_HCMD] = {.min_ver = 1, .max_ver = 1,},
- [IWL_DBG_TLV_TYPE_REGION] = {.min_ver = 1, .max_ver = 1,},
+ [IWL_DBG_TLV_TYPE_REGION] = {.min_ver = 1, .max_ver = 2,},
[IWL_DBG_TLV_TYPE_TRIGGER] = {.min_ver = 1, .max_ver = 1,},
};
@@ -178,9 +178,20 @@ static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans,
u32 type = le32_to_cpu(reg->type);
u32 tlv_len = sizeof(*tlv) + le32_to_cpu(tlv->length);
+ /*
+ * The higher part of the ID in version 2 is irrelevant for
+ * us, so mask it out.
+ */
+ if (le32_to_cpu(reg->hdr.version) == 2)
+ id &= IWL_FW_INI_REGION_V2_MASK;
+
if (le32_to_cpu(tlv->length) < sizeof(*reg))
return -EINVAL;
+ /* for safe use of a string from FW, limit it to IWL_FW_INI_MAX_NAME */
+ IWL_DEBUG_FW(trans, "WRT: parsing region: %.*s\n",
+ IWL_FW_INI_MAX_NAME, reg->name);
+
if (id >= IWL_FW_INI_MAX_REGION_ID) {
IWL_ERR(trans, "WRT: Invalid region id %u\n", id);
return -EINVAL;
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 884750bf7840..977dce686bdb 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -1117,6 +1117,17 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
IWL_ERROR_EVENT_TABLE_LMAC1;
break;
}
+ case IWL_UCODE_TLV_TCM_DEBUG_ADDRS: {
+ struct iwl_fw_tcm_error_addr *ptr = (void *)tlv_data;
+
+ if (tlv_len != sizeof(*ptr))
+ goto invalid_tlv_len;
+ drv->trans->dbg.tcm_error_event_table =
+ le32_to_cpu(ptr->addr) & ~FW_ADDR_CACHE_CONTROL;
+ drv->trans->dbg.error_event_table_tlv_status |=
+ IWL_ERROR_EVENT_TABLE_TCM;
+ break;
+ }
case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION:
case IWL_UCODE_TLV_TYPE_HCMD:
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index fc75d049046d..850648ebd61c 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2005-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -549,8 +549,7 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = {
.mac_cap_info[2] =
IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP,
.mac_cap_info[3] =
- IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
- IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2,
+ IEEE80211_HE_MAC_CAP3_OMI_CONTROL,
.mac_cap_info[4] =
IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU |
IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39,
@@ -579,25 +578,20 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = {
IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 |
IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8,
- .phy_cap_info[5] =
- IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 |
- IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2,
.phy_cap_info[6] =
IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT,
.phy_cap_info[7] =
IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP |
- IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI |
- IEEE80211_HE_PHY_CAP7_MAX_NC_1,
+ IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI,
.phy_cap_info[8] =
IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI |
IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G |
IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU |
- IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996,
+ IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242,
.phy_cap_info[9] =
- IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK |
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB |
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED,
@@ -632,19 +626,11 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = {
.mac_cap_info[1] =
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
- .mac_cap_info[2] =
- IEEE80211_HE_MAC_CAP2_BSR,
.mac_cap_info[3] =
- IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
- IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2,
- .mac_cap_info[4] =
- IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU,
- .mac_cap_info[5] =
- IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU,
+ IEEE80211_HE_MAC_CAP3_OMI_CONTROL,
.phy_cap_info[0] =
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
- IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
- IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G,
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G,
.phy_cap_info[1] =
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD,
.phy_cap_info[2] =
@@ -654,27 +640,14 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = {
IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 |
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM |
IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1,
- .phy_cap_info[4] =
- IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
- IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 |
- IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8,
- .phy_cap_info[5] =
- IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 |
- IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2,
.phy_cap_info[6] =
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT,
.phy_cap_info[7] =
- IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI |
- IEEE80211_HE_PHY_CAP7_MAX_NC_1,
+ IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI,
.phy_cap_info[8] =
IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI |
- IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G |
- IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
- IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU |
- IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996,
+ IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242,
.phy_cap_info[9] =
- IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
- IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB |
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED,
},
/*
@@ -745,12 +718,72 @@ static void iwl_init_he_6ghz_capa(struct iwl_trans *trans,
iftype_data[i].he_6ghz_capa.capa = cpu_to_le16(he_6ghz_capa);
}
+static void
+iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_sband_iftype_data *iftype_data,
+ u8 tx_chains, u8 rx_chains,
+ const struct iwl_fw *fw)
+{
+ bool is_ap = iftype_data->types_mask & BIT(NL80211_IFTYPE_AP);
+
+ /* Advertise an A-MPDU exponent extension based on
+ * operating band
+ */
+ if (sband->band != NL80211_BAND_2GHZ)
+ iftype_data->he_cap.he_cap_elem.mac_cap_info[3] |=
+ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_1;
+ else
+ iftype_data->he_cap.he_cap_elem.mac_cap_info[3] |=
+ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3;
+
+ if (is_ap && iwlwifi_mod_params.nvm_file)
+ iftype_data->he_cap.he_cap_elem.phy_cap_info[0] |=
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
+
+ if ((tx_chains & rx_chains) == ANT_AB) {
+ iftype_data->he_cap.he_cap_elem.phy_cap_info[5] |=
+ IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 |
+ IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2;
+ if (!is_ap)
+ iftype_data->he_cap.he_cap_elem.phy_cap_info[7] |=
+ IEEE80211_HE_PHY_CAP7_MAX_NC_2;
+ } else if (!is_ap) {
+ /* If not 2x2, we need to indicate 1x1 in the
+ * Midamble RX Max NSTS - but not for AP mode
+ */
+ iftype_data->he_cap.he_cap_elem.phy_cap_info[1] &=
+ ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS;
+ iftype_data->he_cap.he_cap_elem.phy_cap_info[2] &=
+ ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS;
+ iftype_data->he_cap.he_cap_elem.phy_cap_info[7] |=
+ IEEE80211_HE_PHY_CAP7_MAX_NC_1;
+ }
+
+ switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) {
+ case IWL_CFG_RF_TYPE_GF:
+ case IWL_CFG_RF_TYPE_MR:
+ iftype_data->he_cap.he_cap_elem.phy_cap_info[9] |=
+ IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU;
+ if (!is_ap)
+ iftype_data->he_cap.he_cap_elem.phy_cap_info[9] |=
+ IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU;
+ break;
+ }
+
+ if (fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_BROADCAST_TWT))
+ iftype_data->he_cap.he_cap_elem.mac_cap_info[2] |=
+ IEEE80211_HE_MAC_CAP2_BCAST_TWT;
+}
+
static void iwl_init_he_hw_capab(struct iwl_trans *trans,
struct iwl_nvm_data *data,
struct ieee80211_supported_band *sband,
- u8 tx_chains, u8 rx_chains)
+ u8 tx_chains, u8 rx_chains,
+ const struct iwl_fw *fw)
{
struct ieee80211_sband_iftype_data *iftype_data;
+ int i;
/* should only initialize once */
if (WARN_ON(sband->iftype_data))
@@ -777,26 +810,18 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans,
sband->iftype_data = iftype_data;
sband->n_iftype_data = ARRAY_SIZE(iwl_he_capa);
- /* If not 2x2, we need to indicate 1x1 in the Midamble RX Max NSTS */
- if ((tx_chains & rx_chains) != ANT_AB) {
- int i;
-
- for (i = 0; i < sband->n_iftype_data; i++) {
- iftype_data[i].he_cap.he_cap_elem.phy_cap_info[1] &=
- ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS;
- iftype_data[i].he_cap.he_cap_elem.phy_cap_info[2] &=
- ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS;
- iftype_data[i].he_cap.he_cap_elem.phy_cap_info[7] &=
- ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK;
- }
- }
+ for (i = 0; i < sband->n_iftype_data; i++)
+ iwl_nvm_fixup_sband_iftd(trans, sband, &iftype_data[i],
+ tx_chains, rx_chains, fw);
+
iwl_init_he_6ghz_capa(trans, data, sband, tx_chains, rx_chains);
}
static void iwl_init_sbands(struct iwl_trans *trans,
struct iwl_nvm_data *data,
const void *nvm_ch_flags, u8 tx_chains,
- u8 rx_chains, u32 sbands_flags, bool v4)
+ u8 rx_chains, u32 sbands_flags, bool v4,
+ const struct iwl_fw *fw)
{
struct device *dev = trans->dev;
const struct iwl_cfg *cfg = trans->cfg;
@@ -816,7 +841,8 @@ static void iwl_init_sbands(struct iwl_trans *trans,
tx_chains, rx_chains);
if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax)
- iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains);
+ iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains,
+ fw);
sband = &data->bands[NL80211_BAND_5GHZ];
sband->band = NL80211_BAND_5GHZ;
@@ -831,7 +857,8 @@ static void iwl_init_sbands(struct iwl_trans *trans,
tx_chains, rx_chains);
if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax)
- iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains);
+ iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains,
+ fw);
/* 6GHz band. */
sband = &data->bands[NL80211_BAND_6GHZ];
@@ -843,7 +870,8 @@ static void iwl_init_sbands(struct iwl_trans *trans,
NL80211_BAND_6GHZ);
if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax)
- iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains);
+ iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains,
+ fw);
else
sband->n_channels = 0;
if (n_channels != n_used)
@@ -1154,7 +1182,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
sbands_flags |= IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ;
iwl_init_sbands(trans, data, ch_section, tx_chains, rx_chains,
- sbands_flags, false);
+ sbands_flags, false, fw);
data->calib_version = 255;
return data;
@@ -1661,7 +1689,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
channel_profile,
nvm->valid_tx_ant & fw->valid_tx_ant,
nvm->valid_rx_ant & fw->valid_rx_ant,
- sbands_flags, v4);
+ sbands_flags, v4, fw);
iwl_free_resp(&hcmd);
return nvm;
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
index 3ce77e4eb7e3..9a9e714bf9af 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2005-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016 Intel Deutschland GmbH
*/
@@ -412,6 +412,8 @@ enum {
#define UREG_DOORBELL_TO_ISR6_RESUME BIT(19)
#define UREG_DOORBELL_TO_ISR6_PNVM BIT(20)
+#define CNVI_MBOX_C 0xA3400C
+
#define FSEQ_ERROR_CODE 0xA340C8
#define FSEQ_TOP_INIT_VERSION 0xA34038
#define FSEQ_CNVIO_INIT_VERSION 0xA3403C
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index bf569f856ad8..0199d7a5a648 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -193,6 +193,7 @@ enum iwl_error_event_table_status {
IWL_ERROR_EVENT_TABLE_LMAC1 = BIT(0),
IWL_ERROR_EVENT_TABLE_LMAC2 = BIT(1),
IWL_ERROR_EVENT_TABLE_UMAC = BIT(2),
+ IWL_ERROR_EVENT_TABLE_TCM = BIT(3),
};
/**
@@ -589,6 +590,8 @@ struct iwl_trans_ops {
void (*debugfs_cleanup)(struct iwl_trans *trans);
void (*sync_nmi)(struct iwl_trans *trans);
int (*set_pnvm)(struct iwl_trans *trans, const void *data, u32 len);
+ int (*set_reduce_power)(struct iwl_trans *trans,
+ const void *data, u32 len);
void (*interrupts)(struct iwl_trans *trans, bool enable);
};
@@ -706,6 +709,7 @@ struct iwl_self_init_dram {
* @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
+ * @tcm_error_event_table: address of TCM 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
* @internal_ini_cfg: internal debug cfg state. Uses &enum iwl_ini_cfg_state
@@ -732,6 +736,7 @@ struct iwl_trans_debug {
u32 lmac_error_event_table[2];
u32 umac_error_event_table;
+ u32 tcm_error_event_table;
unsigned int error_event_table_tlv_status;
enum iwl_ini_cfg_state internal_ini_cfg;
@@ -957,6 +962,7 @@ struct iwl_trans {
bool pm_support;
bool ltr_enabled;
u8 pnvm_loaded:1;
+ u8 reduce_power_loaded:1;
const struct iwl_hcmd_arr *command_groups;
int command_groups_size;
@@ -1420,6 +1426,20 @@ static inline int iwl_trans_set_pnvm(struct iwl_trans *trans,
return 0;
}
+static inline int iwl_trans_set_reduce_power(struct iwl_trans *trans,
+ const void *data, u32 len)
+{
+ if (trans->ops->set_reduce_power) {
+ int ret = trans->ops->set_reduce_power(trans, data, len);
+
+ if (ret)
+ return ret;
+ }
+
+ trans->reduce_power_loaded = true;
+ return 0;
+}
+
static inline bool iwl_trans_dbg_ini_valid(struct iwl_trans *trans)
{
return trans->dbg.internal_ini_cfg != IWL_INI_CFG_STATE_NOT_LOADED ||
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 2e28cf299ef4..6a259d867d90 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -104,7 +104,7 @@ static const u8 *iwl_mvm_find_max_pn(struct ieee80211_key_conf *key,
struct wowlan_key_data {
struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc;
struct iwl_wowlan_tkip_params_cmd *tkip;
- struct iwl_wowlan_kek_kck_material_cmd_v3 *kek_kck_cmd;
+ struct iwl_wowlan_kek_kck_material_cmd_v4 *kek_kck_cmd;
bool error, use_rsc_tsc, use_tkip, configure_keys;
int wep_key_idx;
};
@@ -393,14 +393,19 @@ static int iwl_mvm_send_patterns_v1(struct iwl_mvm *mvm,
}
static int iwl_mvm_send_patterns(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
struct cfg80211_wowlan *wowlan)
{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_wowlan_patterns_cmd *pattern_cmd;
struct iwl_host_cmd cmd = {
.id = WOWLAN_PATTERNS,
.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
};
int i, err;
+ int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP,
+ WOWLAN_PATTERNS,
+ IWL_FW_CMD_VER_UNKNOWN);
if (!wowlan->n_patterns)
return 0;
@@ -408,11 +413,13 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm,
cmd.len[0] = sizeof(*pattern_cmd) +
wowlan->n_patterns * sizeof(struct iwl_wowlan_pattern_v2);
- pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
+ pattern_cmd = kzalloc(cmd.len[0], GFP_KERNEL);
if (!pattern_cmd)
return -ENOMEM;
- pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
+ pattern_cmd->n_patterns = wowlan->n_patterns;
+ if (ver >= 3)
+ pattern_cmd->sta_id = mvmvif->ap_sta_id;
for (i = 0; i < wowlan->n_patterns; i++) {
int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
@@ -636,7 +643,6 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,
struct ieee80211_sta *ap_sta)
{
- int ret;
struct iwl_mvm_sta *mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta);
/* TODO: wowlan_config_cmd->wowlan_ba_teardown_tids */
@@ -646,12 +652,16 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
wowlan_config_cmd->flags = ENABLE_L3_FILTERING |
ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING;
- /* Query the last used seqno and set it */
- ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);
- if (ret < 0)
- return ret;
+ if (iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP,
+ WOWLAN_CONFIGURATION, 0) < 6) {
+ /* Query the last used seqno and set it */
+ int ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);
- wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret);
+ if (ret < 0)
+ return ret;
+
+ wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret);
+ }
iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd);
@@ -706,7 +716,8 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 cmd_flags)
{
- struct iwl_wowlan_kek_kck_material_cmd_v3 kek_kck_cmd = {};
+ struct iwl_wowlan_kek_kck_material_cmd_v4 kek_kck_cmd = {};
+ struct iwl_wowlan_kek_kck_material_cmd_v4 *_kek_kck_cmd = &kek_kck_cmd;
struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
bool unified = fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
@@ -715,7 +726,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
.use_rsc_tsc = false,
.tkip = &tkip_cmd,
.use_tkip = false,
- .kek_kck_cmd = &kek_kck_cmd,
+ .kek_kck_cmd = _kek_kck_cmd,
};
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
@@ -809,13 +820,9 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
IWL_ALWAYS_LONG_GROUP,
WOWLAN_KEK_KCK_MATERIAL,
IWL_FW_CMD_VER_UNKNOWN);
- if (WARN_ON(cmd_ver != 2 && cmd_ver != 3 &&
+ if (WARN_ON(cmd_ver != 2 && cmd_ver != 3 && cmd_ver != 4 &&
cmd_ver != IWL_FW_CMD_VER_UNKNOWN))
return -EINVAL;
- if (cmd_ver == 3)
- cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v3);
- else
- cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v2);
memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck,
mvmvif->rekey_data.kck_len);
@@ -825,6 +832,21 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
kek_kck_cmd.kek_len = cpu_to_le16(mvmvif->rekey_data.kek_len);
kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr;
kek_kck_cmd.akm = cpu_to_le32(mvmvif->rekey_data.akm);
+ kek_kck_cmd.sta_id = cpu_to_le32(mvmvif->ap_sta_id);
+
+ if (cmd_ver == 4) {
+ cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v4);
+ } else {
+ if (cmd_ver == 3)
+ cmd_size =
+ sizeof(struct iwl_wowlan_kek_kck_material_cmd_v3);
+ else
+ cmd_size =
+ sizeof(struct iwl_wowlan_kek_kck_material_cmd_v2);
+ /* skip the sta_id at the beginning */
+ _kek_kck_cmd = (void *)
+ ((u8 *)_kek_kck_cmd) + sizeof(kek_kck_cmd.sta_id);
+ }
IWL_DEBUG_WOWLAN(mvm, "setting akm %d\n",
mvmvif->rekey_data.akm);
@@ -832,7 +854,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
ret = iwl_mvm_send_cmd_pdu(mvm,
WOWLAN_KEK_KCK_MATERIAL, cmd_flags,
cmd_size,
- &kek_kck_cmd);
+ _kek_kck_cmd);
if (ret)
goto out;
}
@@ -884,7 +906,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
if (fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE))
- ret = iwl_mvm_send_patterns(mvm, wowlan);
+ ret = iwl_mvm_send_patterns(mvm, vif, wowlan);
else
ret = iwl_mvm_send_patterns_v1(mvm, wowlan);
if (ret)
@@ -1534,9 +1556,12 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
}
out:
- mvmvif->seqno_valid = true;
- /* +0x10 because the set API expects next-to-use, not last-used */
- mvmvif->seqno = le16_to_cpu(status->non_qos_seq_ctr) + 0x10;
+ if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP,
+ WOWLAN_GET_STATUSES, 0) < 10) {
+ mvmvif->seqno_valid = true;
+ /* +0x10 because the set API expects next-to-use, not last-used */
+ mvmvif->seqno = le16_to_cpu(status->non_qos_seq_ctr) + 0x10;
+ }
return true;
}
@@ -1587,15 +1612,27 @@ iwl_mvm_parse_wowlan_status_common(v6)
iwl_mvm_parse_wowlan_status_common(v7)
iwl_mvm_parse_wowlan_status_common(v9)
-struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm)
+static struct iwl_wowlan_status *
+iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
{
struct iwl_wowlan_status *status;
+ struct iwl_wowlan_get_status_cmd get_status_cmd = {
+ .sta_id = cpu_to_le32(sta_id),
+ };
struct iwl_host_cmd cmd = {
.id = WOWLAN_GET_STATUSES,
.flags = CMD_WANT_SKB,
+ .data = { &get_status_cmd, },
+ .len = { sizeof(get_status_cmd), },
};
int ret, len;
u8 notif_ver;
+ u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP,
+ WOWLAN_GET_STATUSES,
+ IWL_FW_CMD_VER_UNKNOWN);
+
+ if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN)
+ cmd.len[0] = 0;
lockdep_assert_held(&mvm->mutex);
@@ -1608,8 +1645,11 @@ struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm)
len = iwl_rx_packet_payload_len(cmd.resp_pkt);
/* default to 7 (when we have IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL) */
- notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
- WOWLAN_GET_STATUSES, 7);
+ notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP,
+ WOWLAN_GET_STATUSES, 0);
+ if (!notif_ver)
+ notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
+ WOWLAN_GET_STATUSES, 7);
if (!fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) {
@@ -1654,7 +1694,7 @@ struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm)
status->gtk[0] = v7->gtk[0];
status->igtk[0] = v7->igtk[0];
- } else if (notif_ver == 9) {
+ } else if (notif_ver == 9 || notif_ver == 10) {
struct iwl_wowlan_status_v9 *v9 = (void *)cmd.resp_pkt->data;
status = iwl_mvm_parse_wowlan_status_common_v9(mvm,
@@ -1680,29 +1720,37 @@ out_free_resp:
}
static struct iwl_wowlan_status *
-iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm)
+iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, u8 sta_id)
{
- int ret;
-
- /* only for tracing for now */
- ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, 0, 0, NULL);
- if (ret)
- IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret);
+ u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP,
+ OFFLOADS_QUERY_CMD,
+ IWL_FW_CMD_VER_UNKNOWN);
+ __le32 station_id = cpu_to_le32(sta_id);
+ u32 cmd_size = cmd_ver != IWL_FW_CMD_VER_UNKNOWN ? sizeof(station_id) : 0;
+
+ if (!mvm->net_detect) {
+ /* only for tracing for now */
+ int ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, 0,
+ cmd_size, &station_id);
+ if (ret)
+ IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret);
+ }
- return iwl_mvm_send_wowlan_get_status(mvm);
+ return iwl_mvm_send_wowlan_get_status(mvm, sta_id);
}
/* releases the MVM mutex */
static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_wowlan_status_data status;
struct iwl_wowlan_status *fw_status;
int i;
bool keep;
struct iwl_mvm_sta *mvm_ap_sta;
- fw_status = iwl_mvm_get_wakeup_status(mvm);
+ fw_status = iwl_mvm_get_wakeup_status(mvm, mvmvif->ap_sta_id);
if (IS_ERR_OR_NULL(fw_status))
goto out_unlock;
@@ -1880,7 +1928,7 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
u32 reasons = 0;
int i, n_matches, ret;
- fw_status = iwl_mvm_get_wakeup_status(mvm);
+ fw_status = iwl_mvm_get_wakeup_status(mvm, IWL_MVM_INVALID_STA);
if (!IS_ERR_OR_NULL(fw_status)) {
reasons = le32_to_cpu(fw_status->wakeup_reasons);
kfree(fw_status);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
index 38d0bfb649cc..7d9faeffd154 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -460,7 +460,7 @@ static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file,
int pos = 0;
mutex_lock(&mvm->mutex);
- iwl_mvm_get_sync_time(mvm, &curr_gp2, &curr_os);
+ iwl_mvm_get_sync_time(mvm, CLOCK_BOOTTIME, &curr_gp2, &curr_os, NULL);
mutex_unlock(&mvm->mutex);
do_div(curr_os, NSEC_PER_USEC);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
index 63d65018d098..95f883aba148 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
@@ -1023,7 +1023,9 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
mvm->fw_restart++;
/* take the return value to make compiler happy - it will fail anyway */
- ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, 0, 0, NULL);
+ ret = iwl_mvm_send_cmd_pdu(mvm,
+ WIDE_ID(LONG_GROUP, REPLY_ERROR),
+ 0, 0, NULL);
mutex_unlock(&mvm->mutex);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
index a456b8a0ae58..59cef0d89a6d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2021 Intel Corporation
*/
#include <linux/etherdevice.h>
#include <linux/math64.h>
@@ -430,6 +430,10 @@ iwl_mvm_ftm_put_target_common(struct iwl_mvm *mvm,
FTM_PUT_FLAG(TB);
else if (peer->ftm.non_trigger_based)
FTM_PUT_FLAG(NON_TB);
+
+ if ((peer->ftm.trigger_based || peer->ftm.non_trigger_based) &&
+ peer->ftm.lmr_feedback)
+ FTM_PUT_FLAG(LMR_FEEDBACK);
}
static int
@@ -879,7 +883,8 @@ static u64 iwl_mvm_ftm_get_host_time(struct iwl_mvm *mvm, __le32 fw_gp2_ts)
u32 curr_gp2, diff;
u64 now_from_boot_ns;
- iwl_mvm_get_sync_time(mvm, &curr_gp2, &now_from_boot_ns);
+ iwl_mvm_get_sync_time(mvm, CLOCK_BOOTTIME, &curr_gp2,
+ &now_from_boot_ns, NULL);
if (curr_gp2 >= gp2_ts)
diff = curr_gp2 - gp2_ts;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 8aa5f1a2c58c..38fd5886af2d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -1139,19 +1139,34 @@ static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm)
static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
{
- int cmd_ret;
- struct iwl_lari_config_change_cmd_v3 cmd = {};
+ int ret;
+ u32 value;
+ struct iwl_lari_config_change_cmd_v4 cmd = {};
cmd.config_bitmap = iwl_acpi_get_lari_config_bitmap(&mvm->fwrt);
+ ret = iwl_acpi_get_dsm_u32((&mvm->fwrt)->dev, 0, DSM_FUNC_11AX_ENABLEMENT,
+ &iwl_guid, &value);
+ if (!ret)
+ cmd.oem_11ax_allow_bitmap = cpu_to_le32(value);
/* apply more config masks here */
- if (cmd.config_bitmap) {
+ ret = iwl_acpi_get_dsm_u32((&mvm->fwrt)->dev, 0,
+ DSM_FUNC_ENABLE_UNII4_CHAN,
+ &iwl_guid, &value);
+ if (!ret)
+ cmd.oem_unii4_allow_bitmap = cpu_to_le32(value);
+
+ if (cmd.config_bitmap ||
+ cmd.oem_11ax_allow_bitmap ||
+ cmd.oem_unii4_allow_bitmap) {
size_t cmd_size;
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,
REGULATORY_AND_NVM_GROUP,
LARI_CONFIG_CHANGE, 1);
- if (cmd_ver == 3)
+ if (cmd_ver == 4)
+ cmd_size = sizeof(struct iwl_lari_config_change_cmd_v4);
+ else if (cmd_ver == 3)
cmd_size = sizeof(struct iwl_lari_config_change_cmd_v3);
else if (cmd_ver == 2)
cmd_size = sizeof(struct iwl_lari_config_change_cmd_v2);
@@ -1159,16 +1174,21 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1);
IWL_DEBUG_RADIO(mvm,
- "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x\n",
- le32_to_cpu(cmd.config_bitmap));
- cmd_ret = iwl_mvm_send_cmd_pdu(mvm,
- WIDE_ID(REGULATORY_AND_NVM_GROUP,
- LARI_CONFIG_CHANGE),
- 0, cmd_size, &cmd);
- if (cmd_ret < 0)
+ "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n",
+ le32_to_cpu(cmd.config_bitmap),
+ le32_to_cpu(cmd.oem_11ax_allow_bitmap));
+ IWL_DEBUG_RADIO(mvm,
+ "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, cmd_ver=%d\n",
+ le32_to_cpu(cmd.oem_unii4_allow_bitmap),
+ cmd_ver);
+ ret = iwl_mvm_send_cmd_pdu(mvm,
+ WIDE_ID(REGULATORY_AND_NVM_GROUP,
+ LARI_CONFIG_CHANGE),
+ 0, cmd_size, &cmd);
+ if (ret < 0)
IWL_DEBUG_RADIO(mvm,
"Failed to send LARI_CONFIG_CHANGE (%d)\n",
- cmd_ret);
+ ret);
}
}
#else /* CONFIG_ACPI */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 607d5d564928..70ebecb73c24 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -3306,14 +3306,14 @@ static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw,
static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- u16 req_duration)
+ struct ieee80211_prep_tx_info *info)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS;
u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS;
- if (req_duration > duration)
- duration = req_duration;
+ if (info->duration > duration)
+ duration = info->duration;
mutex_lock(&mvm->mutex);
/* Try really hard to protect the session and hear a beacon
@@ -3800,6 +3800,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct cfg80211_chan_def chandef;
struct iwl_mvm_phy_ctxt *phy_ctxt;
+ bool band_change_removal;
int ret, i;
IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
@@ -3880,19 +3881,30 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT);
/*
- * Change the PHY context configuration as it is currently referenced
- * only by the P2P Device MAC
+ * Check if the remain-on-channel is on a different band and that
+ * requires context removal, see iwl_mvm_phy_ctxt_changed(). If
+ * so, we'll need to release and then re-configure here, since we
+ * must not remove a PHY context that's part of a binding.
*/
- if (mvmvif->phy_ctxt->ref == 1) {
+ band_change_removal =
+ fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT) &&
+ mvmvif->phy_ctxt->channel->band != chandef.chan->band;
+
+ if (mvmvif->phy_ctxt->ref == 1 && !band_change_removal) {
+ /*
+ * Change the PHY context configuration as it is currently
+ * referenced only by the P2P Device MAC (and we can modify it)
+ */
ret = iwl_mvm_phy_ctxt_changed(mvm, mvmvif->phy_ctxt,
&chandef, 1, 1);
if (ret)
goto out_unlock;
} else {
/*
- * The PHY context is shared with other MACs. Need to remove the
- * P2P Device from the binding, allocate an new PHY context and
- * create a new binding
+ * The PHY context is shared with other MACs (or we're trying to
+ * switch bands), so remove the P2P Device from the binding,
+ * allocate an new PHY context and create a new binding.
*/
phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);
if (!phy_ctxt) {
@@ -4211,7 +4223,6 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
struct ieee80211_vif *disabled_vif = NULL;
lockdep_assert_held(&mvm->mutex);
-
iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data);
switch (vif->type) {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 4d9d4d6892fc..b50942f28bb7 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -16,6 +16,8 @@
#include <linux/thermal.h>
#endif
+#include <linux/ktime.h>
+
#include "iwl-op-mode.h"
#include "iwl-trans.h"
#include "fw/notif-wait.h"
@@ -195,6 +197,7 @@ enum iwl_mvm_smps_type_request {
IWL_MVM_SMPS_REQ_BT_COEX,
IWL_MVM_SMPS_REQ_TT,
IWL_MVM_SMPS_REQ_PROT,
+ IWL_MVM_SMPS_REQ_FW,
NUM_IWL_MVM_SMPS_REQ,
};
@@ -991,6 +994,8 @@ struct iwl_mvm {
*/
bool temperature_test; /* Debug test temperature is enabled */
+ bool fw_static_smps_request;
+
unsigned long bt_coex_last_tcm_ts;
struct iwl_mvm_tcm tcm;
@@ -1447,10 +1452,16 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
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);
+
+static inline void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
+{
+ iwl_fwrt_dump_error_logs(&mvm->fwrt);
+}
+
u8 first_antenna(u8 mask);
u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx);
-void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime);
+void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type, u32 *gp2,
+ u64 *boottime, ktime_t *realtime);
u32 iwl_mvm_get_systime(struct iwl_mvm *mvm);
/* Tx / Host Commands */
@@ -1769,7 +1780,6 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, int idx);
extern const struct file_operations iwl_dbgfs_d3_test_ops;
-struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm);
#ifdef CONFIG_PM
void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
@@ -1827,7 +1837,9 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum iwl_mvm_smps_type_request req_type,
enum ieee80211_smps_mode smps_request);
-bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm);
+bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm,
+ struct iwl_mvm_phy_ctxt *ctxt);
+void iwl_mvm_apply_fw_smps_request(struct ieee80211_vif *vif);
/* Low latency */
int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
index 1cc90e61367b..41880517e8bb 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014 Intel Corporation
+ * Copyright (C) 2012-2014, 2021 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015 Intel Deutschland GmbH
*/
@@ -36,7 +36,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
struct iwl_proto_offload_cmd_v1 v1;
struct iwl_proto_offload_cmd_v2 v2;
struct iwl_proto_offload_cmd_v3_small v3s;
- struct iwl_proto_offload_cmd_v3_large v3l;
+ struct iwl_proto_offload_cmd_v4 v4;
} cmd = {};
struct iwl_host_cmd hcmd = {
.id = PROT_OFFLOAD_CONFIG_CMD,
@@ -47,6 +47,9 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
struct iwl_proto_offload_cmd_common *common;
u32 enabled = 0, size;
u32 capa_flags = mvm->fw->ucode_capa.flags;
+ int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP,
+ PROT_OFFLOAD_CONFIG_CMD, 0);
+
#if IS_ENABLED(CONFIG_IPV6)
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int i;
@@ -72,9 +75,9 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
addrs = cmd.v3s.targ_addrs;
n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S;
} else {
- nsc = cmd.v3l.ns_config;
+ nsc = cmd.v4.ns_config;
n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L;
- addrs = cmd.v3l.targ_addrs;
+ addrs = cmd.v4.targ_addrs;
n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L;
}
@@ -116,7 +119,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
cmd.v3s.num_valid_ipv6_addrs =
cpu_to_le32(i - num_skipped);
else
- cmd.v3l.num_valid_ipv6_addrs =
+ cmd.v4.num_valid_ipv6_addrs =
cpu_to_le32(i - num_skipped);
} else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
bool found = false;
@@ -171,8 +174,17 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
common = &cmd.v3s.common;
size = sizeof(cmd.v3s);
} else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
- common = &cmd.v3l.common;
- size = sizeof(cmd.v3l);
+ common = &cmd.v4.common;
+ size = sizeof(cmd.v4);
+ if (ver < 4) {
+ /*
+ * This basically uses iwl_proto_offload_cmd_v3_large
+ * which doesn't have the sta_id parameter before the
+ * common part.
+ */
+ size -= sizeof(cmd.v4.sta_id);
+ hcmd.data[0] = common;
+ }
} else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
common = &cmd.v2.common;
size = sizeof(cmd.v2);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index ebed82c590e5..20e8d343a950 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -210,6 +210,39 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm,
ieee80211_disconnect(vif, true);
}
+void iwl_mvm_apply_fw_smps_request(struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = mvmvif->mvm;
+
+ iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_FW,
+ mvm->fw_static_smps_request ?
+ IEEE80211_SMPS_STATIC :
+ IEEE80211_SMPS_AUTOMATIC);
+}
+
+static void iwl_mvm_intf_dual_chain_req(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ iwl_mvm_apply_fw_smps_request(vif);
+}
+
+static void iwl_mvm_rx_thermal_dual_chain_req(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_thermal_dual_chain_request *req = (void *)pkt->data;
+
+ /*
+ * We could pass it to the iterator data, but also need to remember
+ * it for new interfaces that are added while in this state.
+ */
+ mvm->fw_static_smps_request =
+ req->event == cpu_to_le32(THERMAL_DUAL_CHAIN_REQ_DISABLE);
+ ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_intf_dual_chain_req, NULL);
+}
+
/**
* enum iwl_rx_handler_context context for Rx handler
* @RX_HANDLER_SYNC : this means that it will be called in the Rx path
@@ -358,6 +391,11 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER_GRP(DATA_PATH_GROUP, MONITOR_NOTIF,
iwl_mvm_rx_monitor_notif, RX_HANDLER_ASYNC_LOCKED,
struct iwl_datapath_monitor_notif),
+
+ RX_HANDLER_GRP(DATA_PATH_GROUP, THERMAL_DUAL_CHAIN_REQUEST,
+ iwl_mvm_rx_thermal_dual_chain_req,
+ RX_HANDLER_ASYNC_LOCKED,
+ struct iwl_thermal_dual_chain_request),
};
#undef RX_HANDLER
#undef RX_HANDLER_GRP
@@ -445,7 +483,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
HCMD_NAME(D3_CONFIG_CMD),
HCMD_NAME(PROT_OFFLOAD_CONFIG_CMD),
HCMD_NAME(OFFLOADS_QUERY_CMD),
- HCMD_NAME(REMOTE_WAKE_CONFIG_CMD),
HCMD_NAME(MATCH_FOUND_NOTIFICATION),
HCMD_NAME(DTS_MEASUREMENT_NOTIFICATION),
HCMD_NAME(WOWLAN_PATTERNS),
@@ -503,6 +540,7 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = {
HCMD_NAME(TLC_MNG_CONFIG_CMD),
HCMD_NAME(CHEST_COLLECTOR_FILTER_CONFIG_CMD),
HCMD_NAME(MONITOR_NOTIF),
+ HCMD_NAME(THERMAL_DUAL_CHAIN_REQUEST),
HCMD_NAME(STA_PM_NOTIF),
HCMD_NAME(MU_GROUP_MGMT_NOTIF),
HCMD_NAME(RX_QUEUES_NOTIFICATION),
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
index 0fd51f6aa206..035336a9e755 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2017 Intel Deutschland GmbH
*/
@@ -76,6 +76,7 @@ static void iwl_mvm_phy_ctxt_cmd_hdr(struct iwl_mvm_phy_ctxt *ctxt,
}
static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm,
+ struct iwl_mvm_phy_ctxt *ctxt,
__le32 *rxchain_info,
u8 chains_static,
u8 chains_dynamic)
@@ -93,11 +94,22 @@ static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm,
* between the two antennas is sufficiently different to impact
* performance.
*/
- if (active_cnt == 1 && iwl_mvm_rx_diversity_allowed(mvm)) {
+ if (active_cnt == 1 && iwl_mvm_rx_diversity_allowed(mvm, ctxt)) {
idle_cnt = 2;
active_cnt = 2;
}
+ /*
+ * If the firmware requested it, then we know that it supports
+ * getting zero for the values to indicate "use one, but pick
+ * which one yourself", which means it can dynamically pick one
+ * that e.g. has better RSSI.
+ */
+ if (mvm->fw_static_smps_request && active_cnt == 1 && idle_cnt == 1) {
+ idle_cnt = 0;
+ active_cnt = 0;
+ }
+
*rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) <<
PHY_RX_CHAIN_VALID_POS);
*rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS);
@@ -113,6 +125,7 @@ static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm,
* Add the phy configuration to the PHY context command
*/
static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm,
+ struct iwl_mvm_phy_ctxt *ctxt,
struct iwl_phy_context_cmd_v1 *cmd,
struct cfg80211_chan_def *chandef,
u8 chains_static, u8 chains_dynamic)
@@ -123,7 +136,7 @@ static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm,
/* Set the channel info data */
iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef);
- iwl_mvm_phy_ctxt_set_rxchain(mvm, &tail->rxchain_info,
+ iwl_mvm_phy_ctxt_set_rxchain(mvm, ctxt, &tail->rxchain_info,
chains_static, chains_dynamic);
tail->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm));
@@ -133,6 +146,7 @@ static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm,
* Add the phy configuration to the PHY context command
*/
static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
+ struct iwl_mvm_phy_ctxt *ctxt,
struct iwl_phy_context_cmd *cmd,
struct cfg80211_chan_def *chandef,
u8 chains_static, u8 chains_dynamic)
@@ -143,7 +157,7 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
/* Set the channel info data */
iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef);
- iwl_mvm_phy_ctxt_set_rxchain(mvm, &cmd->rxchain_info,
+ iwl_mvm_phy_ctxt_set_rxchain(mvm, ctxt, &cmd->rxchain_info,
chains_static, chains_dynamic);
}
@@ -170,7 +184,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm,
iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, action);
/* Set the command data */
- iwl_mvm_phy_ctxt_cmd_data(mvm, &cmd, chandef,
+ iwl_mvm_phy_ctxt_cmd_data(mvm, ctxt, &cmd, chandef,
chains_static,
chains_dynamic);
@@ -186,7 +200,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm,
action);
/* Set the command data */
- iwl_mvm_phy_ctxt_cmd_data_v1(mvm, &cmd, chandef,
+ iwl_mvm_phy_ctxt_cmd_data_v1(mvm, ctxt, &cmd, chandef,
chains_static,
chains_dynamic);
ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index 8e26422ca326..c0babb8d5b5c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@@ -2001,8 +2001,10 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
struct sk_buff *skb;
u8 channel, energy_a, energy_b;
struct iwl_mvm_rx_phy_data phy_data = {
+ .info_type = le32_get_bits(desc->phy_info[1],
+ IWL_RX_PHY_DATA1_INFO_TYPE_MASK),
.d0 = desc->phy_info[0],
- .info_type = IWL_RX_PHY_INFO_TYPE_NONE,
+ .d1 = desc->phy_info[1],
};
if (unlikely(iwl_rx_packet_payload_len(pkt) < sizeof(*desc)))
@@ -2015,10 +2017,6 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
energy_b = (rssi & RX_NO_DATA_CHAIN_B_MSK) >> RX_NO_DATA_CHAIN_B_POS;
channel = (rssi & RX_NO_DATA_CHANNEL_MSK) >> RX_NO_DATA_CHANNEL_POS;
- phy_data.info_type =
- le32_get_bits(desc->phy_info[1],
- IWL_RX_PHY_DATA1_INFO_TYPE_MASK);
-
/* Dont use dev_alloc_skb(), we'll have enough headroom once
* ieee80211_hdr pulled.
*/
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
index 5a0696c44f6d..0368b7101222 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -2327,9 +2327,9 @@ static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
&scan_p->general_params,
gen_flags);
- ret = iwl_mvm_fill_scan_sched_params(params,
- scan_p->periodic_params.schedule,
- &scan_p->periodic_params.delay);
+ ret = iwl_mvm_fill_scan_sched_params(params,
+ scan_p->periodic_params.schedule,
+ &scan_p->periodic_params.delay);
if (ret)
return ret;
@@ -2362,9 +2362,9 @@ static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
&scan_p->general_params,
gen_flags);
- ret = iwl_mvm_fill_scan_sched_params(params,
- scan_p->periodic_params.schedule,
- &scan_p->periodic_params.delay);
+ ret = iwl_mvm_fill_scan_sched_params(params,
+ scan_p->periodic_params.schedule,
+ &scan_p->periodic_params.delay);
if (ret)
return ret;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index f618368eda83..9c45a64c5009 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -3794,8 +3794,12 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm,
mvm_sta->disable_tx = disable;
- /* Tell mac80211 to start/stop queuing tx for this station */
- ieee80211_sta_block_awake(mvm->hw, sta, disable);
+ /*
+ * If sta PS state is handled by mac80211, tell it to start/stop
+ * queuing tx for this station.
+ */
+ if (!ieee80211_hw_check(mvm->hw, AP_LINK_PS))
+ ieee80211_sta_block_awake(mvm->hw, sta, disable);
iwl_mvm_sta_modify_disable_tx(mvm, mvm_sta, disable);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
index 83342a6a6d5b..d3307a11fcac 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
@@ -31,6 +31,13 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
return;
list_del(&te_data->list);
+
+ /*
+ * the list is only used for AUX ROC events so make sure it is always
+ * initialized
+ */
+ INIT_LIST_HEAD(&te_data->list);
+
te_data->running = false;
te_data->uid = 0;
te_data->id = TE_MAX;
@@ -310,6 +317,8 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
* and know the dtim period.
*/
iwl_mvm_te_check_disconnect(mvm, te_data->vif,
+ !te_data->vif->bss_conf.assoc ?
+ "Not associated and the time event is over already..." :
"No beacon heard and the time event is over already...");
break;
default:
@@ -607,14 +616,15 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
}
static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm,
- struct iwl_mvm_vif *mvmvif)
+ struct iwl_mvm_vif *mvmvif,
+ u32 id)
{
struct iwl_mvm_session_prot_cmd cmd = {
.id_and_color =
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
mvmvif->color)),
.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
- .conf_id = cpu_to_le32(mvmvif->time_event_data.id),
+ .conf_id = cpu_to_le32(id),
};
int ret;
@@ -632,6 +642,12 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
{
u32 id;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
+ enum nl80211_iftype iftype;
+
+ if (!te_data->vif)
+ return false;
+
+ iftype = te_data->vif->type;
/*
* It is possible that by the time we got to this point the time
@@ -656,8 +672,8 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) {
if (mvmvif && id < SESSION_PROTECT_CONF_MAX_ID) {
/* Session protection is still ongoing. Cancel it */
- iwl_mvm_cancel_session_protection(mvm, mvmvif);
- if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+ iwl_mvm_cancel_session_protection(mvm, mvmvif, id);
+ if (iftype == NL80211_IFTYPE_P2P_DEVICE) {
set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status);
iwl_mvm_roc_finished(mvm);
}
@@ -738,11 +754,6 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
IWL_ERR(mvm, "Couldn't remove the time event\n");
}
-/*
- * When the firmware supports the session protection API,
- * this is not needed since it'll automatically remove the
- * session protection after association + beacon reception.
- */
void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
@@ -756,7 +767,15 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm,
id = te_data->id;
spin_unlock_bh(&mvm->time_event_lock);
- if (id != TE_BSS_STA_AGGRESSIVE_ASSOC) {
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) {
+ if (id != SESSION_PROTECT_CONF_ASSOC) {
+ IWL_DEBUG_TE(mvm,
+ "don't remove session protection id=%u\n",
+ id);
+ return;
+ }
+ } else if (id != TE_BSS_STA_AGGRESSIVE_ASSOC) {
IWL_DEBUG_TE(mvm,
"don't remove TE with id=%u (not session protection)\n",
id);
@@ -808,6 +827,8 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,
* and know the dtim period.
*/
iwl_mvm_te_check_disconnect(mvm, vif,
+ !vif->bss_conf.assoc ?
+ "Not associated and the session protection is over already..." :
"No beacon heard and the session protection is over already...");
spin_lock_bh(&mvm->time_event_lock);
iwl_mvm_te_clear_data(mvm, te_data);
@@ -981,7 +1002,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
mvmvif = iwl_mvm_vif_from_mac80211(vif);
if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
- iwl_mvm_cancel_session_protection(mvm, mvmvif);
+ iwl_mvm_cancel_session_protection(mvm, mvmvif,
+ mvmvif->time_event_data.id);
set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status);
} else {
iwl_mvm_remove_aux_roc_te(mvm, mvmvif,
@@ -1141,6 +1163,7 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm,
iwl_mvm_te_clear_data(mvm, te_data);
te_data->duration = le32_to_cpu(cmd.duration_tu);
+ te_data->vif = vif;
spin_unlock_bh(&mvm->time_event_lock);
IWL_DEBUG_TE(mvm, "Add new session protection, duration %d TU\n",
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 1ad621d13ad3..0a13c2bda2ee 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -1032,6 +1032,9 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_INVALID_STA))
return -1;
+ if (unlikely(ieee80211_is_any_nullfunc(fc)) && sta->he_cap.has_he)
+ return -1;
+
if (unlikely(ieee80211_is_probe_resp(fc)))
iwl_mvm_probe_resp_set_noa(mvm, skb);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index c566be99a4c7..4a3d2971a98b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@@ -238,316 +238,6 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx)
return last_idx;
}
-/*
- * Note: This structure is read from the device with IO accesses,
- * and the reading already does the endian conversion. As it is
- * read with u32-sized accesses, any members with a different size
- * need to be ordered correctly though!
- */
-struct iwl_error_event_table_v1 {
- u32 valid; /* (nonzero) valid, (0) log is empty */
- u32 error_id; /* type of error */
- u32 pc; /* program counter */
- u32 blink1; /* branch link */
- u32 blink2; /* branch link */
- u32 ilink1; /* interrupt link */
- u32 ilink2; /* interrupt link */
- u32 data1; /* error-specific data */
- u32 data2; /* error-specific data */
- u32 data3; /* error-specific data */
- u32 bcon_time; /* beacon timer */
- u32 tsf_low; /* network timestamp function timer */
- u32 tsf_hi; /* network timestamp function timer */
- u32 gp1; /* GP1 timer register */
- u32 gp2; /* GP2 timer register */
- u32 gp3; /* GP3 timer register */
- u32 ucode_ver; /* uCode version */
- u32 hw_ver; /* HW Silicon version */
- u32 brd_ver; /* HW board version */
- u32 log_pc; /* log program counter */
- u32 frame_ptr; /* frame pointer */
- u32 stack_ptr; /* stack pointer */
- u32 hcmd; /* last host command header */
- u32 isr0; /* isr status register LMPM_NIC_ISR0:
- * rxtx_flag */
- u32 isr1; /* isr status register LMPM_NIC_ISR1:
- * host_flag */
- u32 isr2; /* isr status register LMPM_NIC_ISR2:
- * enc_flag */
- u32 isr3; /* isr status register LMPM_NIC_ISR3:
- * time_flag */
- u32 isr4; /* isr status register LMPM_NIC_ISR4:
- * wico interrupt */
- u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */
- u32 wait_event; /* wait event() caller address */
- u32 l2p_control; /* L2pControlField */
- u32 l2p_duration; /* L2pDurationField */
- u32 l2p_mhvalid; /* L2pMhValidBits */
- u32 l2p_addr_match; /* L2pAddrMatchStat */
- u32 lmpm_pmg_sel; /* indicate which clocks are turned on
- * (LMPM_PMG_SEL) */
- u32 u_timestamp; /* indicate when the date and time of the
- * compilation */
- u32 flow_handler; /* FH read/write pointers, RX credit */
-} __packed /* LOG_ERROR_TABLE_API_S_VER_1 */;
-
-struct iwl_error_event_table {
- u32 valid; /* (nonzero) valid, (0) log is empty */
- u32 error_id; /* type of error */
- u32 trm_hw_status0; /* TRM HW status */
- u32 trm_hw_status1; /* TRM HW status */
- u32 blink2; /* branch link */
- u32 ilink1; /* interrupt link */
- u32 ilink2; /* interrupt link */
- u32 data1; /* error-specific data */
- u32 data2; /* error-specific data */
- u32 data3; /* error-specific data */
- u32 bcon_time; /* beacon timer */
- u32 tsf_low; /* network timestamp function timer */
- u32 tsf_hi; /* network timestamp function timer */
- u32 gp1; /* GP1 timer register */
- u32 gp2; /* GP2 timer register */
- u32 fw_rev_type; /* firmware revision type */
- u32 major; /* uCode version major */
- u32 minor; /* uCode version minor */
- u32 hw_ver; /* HW Silicon version */
- u32 brd_ver; /* HW board version */
- u32 log_pc; /* log program counter */
- u32 frame_ptr; /* frame pointer */
- u32 stack_ptr; /* stack pointer */
- u32 hcmd; /* last host command header */
- u32 isr0; /* isr status register LMPM_NIC_ISR0:
- * rxtx_flag */
- u32 isr1; /* isr status register LMPM_NIC_ISR1:
- * host_flag */
- u32 isr2; /* isr status register LMPM_NIC_ISR2:
- * enc_flag */
- u32 isr3; /* isr status register LMPM_NIC_ISR3:
- * time_flag */
- u32 isr4; /* isr status register LMPM_NIC_ISR4:
- * wico interrupt */
- u32 last_cmd_id; /* last HCMD id handled by the firmware */
- u32 wait_event; /* wait event() caller address */
- u32 l2p_control; /* L2pControlField */
- u32 l2p_duration; /* L2pDurationField */
- u32 l2p_mhvalid; /* L2pMhValidBits */
- u32 l2p_addr_match; /* L2pAddrMatchStat */
- u32 lmpm_pmg_sel; /* indicate which clocks are turned on
- * (LMPM_PMG_SEL) */
- u32 u_timestamp; /* indicate when the date and time of the
- * compilation */
- u32 flow_handler; /* FH read/write pointers, RX credit */
-} __packed /* LOG_ERROR_TABLE_API_S_VER_3 */;
-
-/*
- * UMAC error struct - relevant starting from family 8000 chip.
- * Note: This structure is read from the device with IO accesses,
- * and the reading already does the endian conversion. As it is
- * read with u32-sized accesses, any members with a different size
- * need to be ordered correctly though!
- */
-struct iwl_umac_error_event_table {
- u32 valid; /* (nonzero) valid, (0) log is empty */
- u32 error_id; /* type of error */
- u32 blink1; /* branch link */
- u32 blink2; /* branch link */
- u32 ilink1; /* interrupt link */
- u32 ilink2; /* interrupt link */
- u32 data1; /* error-specific data */
- u32 data2; /* error-specific data */
- u32 data3; /* error-specific data */
- u32 umac_major;
- u32 umac_minor;
- u32 frame_pointer; /* core register 27*/
- u32 stack_pointer; /* core register 28 */
- u32 cmd_header; /* latest host cmd sent to UMAC */
- u32 nic_isr_pref; /* ISR status register */
-} __packed;
-
-#define ERROR_START_OFFSET (1 * sizeof(u32))
-#define ERROR_ELEM_SIZE (7 * sizeof(u32))
-
-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->dbg.umac_error_event_table;
-
- if (!base &&
- !(mvm->trans->dbg.error_event_table_tlv_status &
- IWL_ERROR_EVENT_TABLE_UMAC))
- return;
-
- iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
-
- if (table.valid)
- mvm->fwrt.dump.umac_err_id = table.error_id;
-
- if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
- IWL_ERR(trans, "Start IWL Error Log Dump:\n");
- IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
- mvm->status, table.valid);
- }
-
- IWL_ERR(mvm, "0x%08X | %s\n", table.error_id,
- iwl_fw_lookup_assert_desc(table.error_id));
- IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1);
- IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2);
- IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1);
- IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2);
- IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1);
- IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2);
- IWL_ERR(mvm, "0x%08X | umac data3\n", table.data3);
- IWL_ERR(mvm, "0x%08X | umac major\n", table.umac_major);
- IWL_ERR(mvm, "0x%08X | umac minor\n", table.umac_minor);
- IWL_ERR(mvm, "0x%08X | frame pointer\n", table.frame_pointer);
- IWL_ERR(mvm, "0x%08X | stack pointer\n", table.stack_pointer);
- IWL_ERR(mvm, "0x%08X | last host cmd\n", table.cmd_header);
- IWL_ERR(mvm, "0x%08X | isr status reg\n", table.nic_isr_pref);
-}
-
-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->dbg.lmac_error_event_table[lmac_num];
-
- if (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) {
- if (!base)
- base = mvm->fw->init_errlog_ptr;
- } else {
- if (!base)
- base = mvm->fw->inst_errlog_ptr;
- }
-
- if (base < 0x400000) {
- IWL_ERR(mvm,
- "Not valid error log pointer 0x%08X for %s uCode\n",
- base,
- (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT)
- ? "Init" : "RT");
- return;
- }
-
- /* check if there is a HW error */
- val = iwl_trans_read_mem32(trans, base);
- if (((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50)) {
- int err;
-
- IWL_ERR(trans, "HW error, resetting before reading\n");
-
- /* reset the device */
- iwl_trans_sw_reset(trans);
-
- err = iwl_finish_nic_init(trans, trans->trans_cfg);
- if (err)
- return;
- }
-
- iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
-
- if (table.valid)
- mvm->fwrt.dump.lmac_err_id[lmac_num] = table.error_id;
-
- if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
- IWL_ERR(trans, "Start IWL Error Log Dump:\n");
- IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
- mvm->status, table.valid);
- }
-
- /* Do not change this output - scripts rely on it */
-
- IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version);
-
- IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id,
- iwl_fw_lookup_assert_desc(table.error_id));
- IWL_ERR(mvm, "0x%08X | trm_hw_status0\n", table.trm_hw_status0);
- IWL_ERR(mvm, "0x%08X | trm_hw_status1\n", table.trm_hw_status1);
- IWL_ERR(mvm, "0x%08X | branchlink2\n", table.blink2);
- IWL_ERR(mvm, "0x%08X | interruptlink1\n", table.ilink1);
- IWL_ERR(mvm, "0x%08X | interruptlink2\n", table.ilink2);
- IWL_ERR(mvm, "0x%08X | data1\n", table.data1);
- IWL_ERR(mvm, "0x%08X | data2\n", table.data2);
- IWL_ERR(mvm, "0x%08X | data3\n", table.data3);
- IWL_ERR(mvm, "0x%08X | beacon time\n", table.bcon_time);
- IWL_ERR(mvm, "0x%08X | tsf low\n", table.tsf_low);
- IWL_ERR(mvm, "0x%08X | tsf hi\n", table.tsf_hi);
- IWL_ERR(mvm, "0x%08X | time gp1\n", table.gp1);
- IWL_ERR(mvm, "0x%08X | time gp2\n", table.gp2);
- IWL_ERR(mvm, "0x%08X | uCode revision type\n", table.fw_rev_type);
- IWL_ERR(mvm, "0x%08X | uCode version major\n", table.major);
- IWL_ERR(mvm, "0x%08X | uCode version minor\n", table.minor);
- IWL_ERR(mvm, "0x%08X | hw version\n", table.hw_ver);
- IWL_ERR(mvm, "0x%08X | board version\n", table.brd_ver);
- IWL_ERR(mvm, "0x%08X | hcmd\n", table.hcmd);
- IWL_ERR(mvm, "0x%08X | isr0\n", table.isr0);
- IWL_ERR(mvm, "0x%08X | isr1\n", table.isr1);
- IWL_ERR(mvm, "0x%08X | isr2\n", table.isr2);
- IWL_ERR(mvm, "0x%08X | isr3\n", table.isr3);
- IWL_ERR(mvm, "0x%08X | isr4\n", table.isr4);
- IWL_ERR(mvm, "0x%08X | last cmd Id\n", table.last_cmd_id);
- IWL_ERR(mvm, "0x%08X | wait_event\n", table.wait_event);
- IWL_ERR(mvm, "0x%08X | l2p_control\n", table.l2p_control);
- IWL_ERR(mvm, "0x%08X | l2p_duration\n", table.l2p_duration);
- IWL_ERR(mvm, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid);
- IWL_ERR(mvm, "0x%08X | l2p_addr_match\n", table.l2p_addr_match);
- IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
- IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp);
- IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler);
-}
-
-static void iwl_mvm_dump_iml_error_log(struct iwl_mvm *mvm)
-{
- struct iwl_trans *trans = mvm->trans;
- u32 error, data1;
-
- if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) {
- error = UMAG_SB_CPU_2_STATUS;
- data1 = UMAG_SB_CPU_1_STATUS;
- } else if (mvm->trans->trans_cfg->device_family >=
- IWL_DEVICE_FAMILY_8000) {
- error = SB_CPU_2_STATUS;
- data1 = SB_CPU_1_STATUS;
- } else {
- return;
- }
-
- error = iwl_read_umac_prph(trans, UMAG_SB_CPU_2_STATUS);
-
- IWL_ERR(trans, "IML/ROM dump:\n");
-
- if (error & 0xFFFF0000)
- IWL_ERR(trans, "0x%04X | IML/ROM SYSASSERT\n", error >> 16);
-
- IWL_ERR(mvm, "0x%08X | IML/ROM error/state\n", error);
- IWL_ERR(mvm, "0x%08X | IML/ROM data1\n",
- iwl_read_umac_prph(trans, data1));
-
- if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000)
- IWL_ERR(mvm, "0x%08X | IML/ROM WFPM_AUTH_KEY_0\n",
- iwl_read_umac_prph(trans, SB_MODIFY_CFG_FLAG));
-}
-
-void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
-{
- if (!test_bit(STATUS_DEVICE_ENABLED, &mvm->trans->status)) {
- IWL_ERR(mvm,
- "DEVICE_ENABLED bit is not set. Aborting dump.\n");
- return;
- }
-
- iwl_mvm_dump_lmac_error_log(mvm, 0);
-
- 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_mvm_dump_iml_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,
int tid, int frame_limit, u16 ssn)
{
@@ -621,7 +311,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum ieee80211_smps_mode smps_request)
{
struct iwl_mvm_vif *mvmvif;
- enum ieee80211_smps_mode smps_mode;
+ enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC;
int i;
lockdep_assert_held(&mvm->mutex);
@@ -630,10 +320,8 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1)
return;
- if (vif->type == NL80211_IFTYPE_AP)
- smps_mode = IEEE80211_SMPS_OFF;
- else
- smps_mode = IEEE80211_SMPS_AUTOMATIC;
+ if (vif->type != NL80211_IFTYPE_STATION)
+ return;
mvmvif = iwl_mvm_vif_from_mac80211(vif);
mvmvif->smps_requests[req_type] = smps_request;
@@ -683,23 +371,37 @@ void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm)
mvm->accu_radio_stats.on_time_scan += mvm->radio_stats.on_time_scan;
}
+struct iwl_mvm_diversity_iter_data {
+ struct iwl_mvm_phy_ctxt *ctxt;
+ bool result;
+};
+
static void iwl_mvm_diversity_iter(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- bool *result = _data;
+ struct iwl_mvm_diversity_iter_data *data = _data;
int i;
+ if (mvmvif->phy_ctxt != data->ctxt)
+ return;
+
for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) {
if (mvmvif->smps_requests[i] == IEEE80211_SMPS_STATIC ||
- mvmvif->smps_requests[i] == IEEE80211_SMPS_DYNAMIC)
- *result = false;
+ mvmvif->smps_requests[i] == IEEE80211_SMPS_DYNAMIC) {
+ data->result = false;
+ break;
+ }
}
}
-bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm)
+bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm,
+ struct iwl_mvm_phy_ctxt *ctxt)
{
- bool result = true;
+ struct iwl_mvm_diversity_iter_data data = {
+ .ctxt = ctxt,
+ .result = true,
+ };
lockdep_assert_held(&mvm->mutex);
@@ -711,9 +413,9 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm)
ieee80211_iterate_active_interfaces_atomic(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_diversity_iter, &result);
+ iwl_mvm_diversity_iter, &data);
- return result;
+ return data.result;
}
void iwl_mvm_send_low_latency_cmd(struct iwl_mvm *mvm,
@@ -1398,7 +1100,8 @@ u32 iwl_mvm_get_systime(struct iwl_mvm *mvm)
return iwl_read_prph(mvm->trans, reg_addr);
}
-void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime)
+void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type,
+ u32 *gp2, u64 *boottime, ktime_t *realtime)
{
bool ps_disabled;
@@ -1412,7 +1115,11 @@ void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime)
}
*gp2 = iwl_mvm_get_systime(mvm);
- *boottime = ktime_get_boottime_ns();
+
+ if (clock_type == CLOCK_BOOTTIME && boottime)
+ *boottime = ktime_get_boottime_ns();
+ else if (clock_type == CLOCK_REALTIME && realtime)
+ *realtime = ktime_get_real();
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 cecc32e7dbe8..239a722cd79d 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
@@ -79,7 +79,6 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
struct iwl_prph_scratch *prph_scratch;
struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl;
struct iwl_prph_info *prph_info;
- void *iml_img;
u32 control_flags = 0;
int ret;
int cmdq_size = max_t(u32, IWL_CMD_QUEUE_SIZE,
@@ -138,8 +137,15 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
/* Allocate prph information
* currently we don't assign to the prph info anything, but it would get
- * assigned later */
- prph_info = dma_alloc_coherent(trans->dev, sizeof(*prph_info),
+ * assigned later
+ *
+ * We also use the second half of this page to give the device some
+ * dummy TR/CR tail pointers - which shouldn't be necessary as we don't
+ * use this, but the hardware still reads/writes there and we can't let
+ * it go do that with a NULL pointer.
+ */
+ BUILD_BUG_ON(sizeof(*prph_info) > PAGE_SIZE / 2);
+ prph_info = dma_alloc_coherent(trans->dev, PAGE_SIZE,
&trans_pcie->prph_info_dma_addr,
GFP_KERNEL);
if (!prph_info) {
@@ -166,13 +172,9 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
ctxt_info_gen3->cr_head_idx_arr_base_addr =
cpu_to_le64(trans_pcie->rxq->rb_stts_dma);
ctxt_info_gen3->tr_tail_idx_arr_base_addr =
- cpu_to_le64(trans_pcie->rxq->tr_tail_dma);
+ cpu_to_le64(trans_pcie->prph_info_dma_addr + PAGE_SIZE / 2);
ctxt_info_gen3->cr_tail_idx_arr_base_addr =
- cpu_to_le64(trans_pcie->rxq->cr_tail_dma);
- ctxt_info_gen3->cr_idx_arr_size =
- cpu_to_le16(IWL_NUM_OF_COMPLETION_RINGS);
- ctxt_info_gen3->tr_idx_arr_size =
- cpu_to_le16(IWL_NUM_OF_TRANSFER_RINGS);
+ cpu_to_le64(trans_pcie->prph_info_dma_addr + 3 * PAGE_SIZE / 4);
ctxt_info_gen3->mtr_base_addr =
cpu_to_le64(trans->txqs.txq[trans->txqs.cmd.q_id]->dma_addr);
ctxt_info_gen3->mcr_base_addr =
@@ -187,14 +189,15 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
trans_pcie->prph_scratch = prph_scratch;
/* Allocate IML */
- iml_img = dma_alloc_coherent(trans->dev, trans->iml_len,
- &trans_pcie->iml_dma_addr, GFP_KERNEL);
- if (!iml_img) {
+ trans_pcie->iml = dma_alloc_coherent(trans->dev, trans->iml_len,
+ &trans_pcie->iml_dma_addr,
+ GFP_KERNEL);
+ if (!trans_pcie->iml) {
ret = -ENOMEM;
goto err_free_ctxt_info;
}
- memcpy(iml_img, trans->iml, trans->iml_len);
+ memcpy(trans_pcie->iml, trans->iml, trans->iml_len);
iwl_enable_fw_load_int_ctx_info(trans);
@@ -216,10 +219,8 @@ err_free_ctxt_info:
trans_pcie->ctxt_info_dma_addr);
trans_pcie->ctxt_info_gen3 = NULL;
err_free_prph_info:
- dma_free_coherent(trans->dev,
- sizeof(*prph_info),
- prph_info,
- trans_pcie->prph_info_dma_addr);
+ dma_free_coherent(trans->dev, PAGE_SIZE, prph_info,
+ trans_pcie->prph_info_dma_addr);
err_free_prph_scratch:
dma_free_coherent(trans->dev,
@@ -230,29 +231,40 @@ err_free_prph_scratch:
}
-void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans)
+void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ if (trans_pcie->iml) {
+ dma_free_coherent(trans->dev, trans->iml_len, trans_pcie->iml,
+ trans_pcie->iml_dma_addr);
+ trans_pcie->iml_dma_addr = 0;
+ trans_pcie->iml = NULL;
+ }
+
+ iwl_pcie_ctxt_info_free_fw_img(trans);
+
+ if (alive)
+ return;
+
if (!trans_pcie->ctxt_info_gen3)
return;
+ /* ctxt_info_gen3 and prph_scratch are still needed for PNVM load */
dma_free_coherent(trans->dev, sizeof(*trans_pcie->ctxt_info_gen3),
trans_pcie->ctxt_info_gen3,
trans_pcie->ctxt_info_dma_addr);
trans_pcie->ctxt_info_dma_addr = 0;
trans_pcie->ctxt_info_gen3 = NULL;
- iwl_pcie_ctxt_info_free_fw_img(trans);
-
dma_free_coherent(trans->dev, sizeof(*trans_pcie->prph_scratch),
trans_pcie->prph_scratch,
trans_pcie->prph_scratch_dma_addr);
trans_pcie->prph_scratch_dma_addr = 0;
trans_pcie->prph_scratch = NULL;
- dma_free_coherent(trans->dev, sizeof(*trans_pcie->prph_info),
- trans_pcie->prph_info,
+ /* this is needed for the entire lifetime */
+ dma_free_coherent(trans->dev, PAGE_SIZE, trans_pcie->prph_info,
trans_pcie->prph_info_dma_addr);
trans_pcie->prph_info_dma_addr = 0;
trans_pcie->prph_info = NULL;
@@ -290,3 +302,37 @@ int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
return 0;
}
+
+int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,
+ const void *data, u32 len)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
+ &trans_pcie->prph_scratch->ctrl_cfg;
+ int ret;
+
+ if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
+ return 0;
+
+ /* only allocate the DRAM if not allocated yet */
+ if (!trans->reduce_power_loaded) {
+ if (WARN_ON(prph_sc_ctrl->reduce_power_cfg.size))
+ return -EBUSY;
+
+ ret = iwl_pcie_ctxt_info_alloc_dma(trans, data, len,
+ &trans_pcie->reduce_power_dram);
+ if (ret < 0) {
+ IWL_DEBUG_FW(trans,
+ "Failed to allocate reduce power DMA %d.\n",
+ ret);
+ return ret;
+ }
+ }
+
+ prph_sc_ctrl->reduce_power_cfg.base_addr =
+ cpu_to_le64(trans_pcie->reduce_power_dram.physical);
+ prph_sc_ctrl->reduce_power_cfg.size =
+ cpu_to_le32(trans_pcie->reduce_power_dram.size);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index d94bd8d732e9..16baee3d52ae 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -532,6 +532,8 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
IWL_DEV_INFO(0x31DC, 0x1552, iwl9560_2ac_cfg_soc, iwl9560_killer_1550i_name),
IWL_DEV_INFO(0xA370, 0x1551, iwl9560_2ac_cfg_soc, iwl9560_killer_1550s_name),
IWL_DEV_INFO(0xA370, 0x1552, iwl9560_2ac_cfg_soc, iwl9560_killer_1550i_name),
+ IWL_DEV_INFO(0x51F0, 0x1552, iwl9560_2ac_cfg_soc, iwl9560_killer_1550s_160_name),
+ IWL_DEV_INFO(0x51F0, 0x1551, iwl9560_2ac_cfg_soc, iwl9560_killer_1550i_160_name),
IWL_DEV_INFO(0x271C, 0x0214, iwl9260_2ac_cfg, iwl9260_1_name),
@@ -1030,6 +1032,11 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB,
iwl_cfg_ma_a0_mr_a0, iwl_ax221_name),
_IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
+ IWL_CFG_MAC_TYPE_MA, IWL_CFG_ANY,
+ IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY,
+ IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB,
+ iwl_cfg_ma_a0_fm_a0, iwl_ax231_name),
+ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY,
IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY,
IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY,
IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB,
@@ -1209,14 +1216,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (cfg == &iwlax210_2ax_cfg_so_hr_a0) {
if (iwl_trans->hw_rev == CSR_HW_REV_TYPE_TY) {
iwl_trans->cfg = &iwlax210_2ax_cfg_ty_gf_a0;
- } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id) ==
- CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_JF)) {
+ } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) ==
+ CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF)) {
iwl_trans->cfg = &iwlax210_2ax_cfg_so_jf_b0;
- } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id) ==
- CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_GF)) {
+ } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) ==
+ CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF)) {
iwl_trans->cfg = &iwlax211_2ax_cfg_so_gf_a0;
- } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id) ==
- CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_GF4)) {
+ } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) ==
+ CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF4)) {
iwl_trans->cfg = &iwlax411_2ax_cfg_so_gf4_a0;
}
}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index 76a512cd2e5c..cc550f6ef957 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2003-2015, 2018-2020 Intel Corporation
+ * Copyright (C) 2003-2015, 2018-2021 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -109,12 +109,8 @@ struct iwl_rx_completion_desc {
* Address size is 32 bit in pre-9000 devices and 64 bit in 9000 devices.
* In AX210 devices it is a pointer to a list of iwl_rx_transfer_desc's
* @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
- * @ubd: driver's pointer to buffer of used receive buffer descriptors (rbd)
- * @ubd_dma: physical address of buffer of used receive buffer descriptors (rbd)
- * @tr_tail: driver's pointer to the transmission ring tail buffer
- * @tr_tail_dma: physical address of the buffer for the transmission ring tail
- * @cr_tail: driver's pointer to the completion ring tail buffer
- * @cr_tail_dma: physical address of the buffer for the completion ring tail
+ * @used_bd: driver's pointer to buffer of used receive buffer descriptors (rbd)
+ * @used_bd_dma: physical address of buffer of used receive buffer descriptors (rbd)
* @read: Shared index to newest available Rx buffer
* @write: Shared index to oldest written Rx packet
* @free_count: Number of pre-allocated buffers in rx_free
@@ -142,10 +138,6 @@ struct iwl_rxq {
struct iwl_rx_completion_desc *cd;
};
dma_addr_t used_bd_dma;
- __le16 *tr_tail;
- dma_addr_t tr_tail_dma;
- __le16 *cr_tail;
- dma_addr_t cr_tail_dma;
u32 read;
u32 write;
u32 free_count;
@@ -279,6 +271,8 @@ struct cont_rec {
* Context information addresses will be taken from here.
* This is driver's local copy for keeping track of size and
* count for allocating and freeing the memory.
+ * @iml: image loader image virtual address
+ * @iml_dma_addr: image loader image DMA address
* @trans: pointer to the generic transport area
* @scd_base_addr: scheduler sram base address in SRAM
* @kw: keep warm address
@@ -317,6 +311,7 @@ struct cont_rec {
* @alloc_page_lock: spinlock for the page allocator
* @alloc_page: allocated page to still use parts of
* @alloc_page_used: how much of the allocated page was already used (bytes)
+ * @rf_name: name/version of the CRF, if any
*/
struct iwl_trans_pcie {
struct iwl_rxq *rxq;
@@ -329,6 +324,7 @@ struct iwl_trans_pcie {
};
struct iwl_prph_info *prph_info;
struct iwl_prph_scratch *prph_scratch;
+ void *iml;
dma_addr_t ctxt_info_dma_addr;
dma_addr_t prph_info_dma_addr;
dma_addr_t prph_scratch_dma_addr;
@@ -353,6 +349,7 @@ struct iwl_trans_pcie {
struct iwl_dma_ptr kw;
struct iwl_dram_data pnvm_dram;
+ struct iwl_dram_data reduce_power_dram;
struct iwl_txq *txq_memory;
@@ -409,6 +406,8 @@ struct iwl_trans_pcie {
bool fw_reset_handshake;
bool fw_reset_done;
wait_queue_head_t fw_reset_waitq;
+
+ char rf_name[32];
};
static inline struct iwl_trans_pcie *
@@ -530,9 +529,6 @@ static inline void _iwl_disable_interrupts(struct iwl_trans *trans)
IWL_DEBUG_ISR(trans, "Disabled interrupts\n");
}
-#define IWL_NUM_OF_COMPLETION_RINGS 31
-#define IWL_NUM_OF_TRANSFER_RINGS 527
-
static inline int iwl_pcie_get_num_sections(const struct fw_img *fw,
int start)
{
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
index fb8491412be4..4f6f4b2720f0 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
@@ -663,7 +663,6 @@ static int iwl_pcie_free_bd_size(struct iwl_trans *trans, bool use_rx_td)
static void iwl_pcie_free_rxq_dma(struct iwl_trans *trans,
struct iwl_rxq *rxq)
{
- struct device *dev = trans->dev;
bool use_rx_td = (trans->trans_cfg->device_family >=
IWL_DEVICE_FAMILY_AX210);
int free_size = iwl_pcie_free_bd_size(trans, use_rx_td);
@@ -685,21 +684,6 @@ static void iwl_pcie_free_rxq_dma(struct iwl_trans *trans,
rxq->used_bd, rxq->used_bd_dma);
rxq->used_bd_dma = 0;
rxq->used_bd = NULL;
-
- if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
- return;
-
- if (rxq->tr_tail)
- dma_free_coherent(dev, sizeof(__le16),
- rxq->tr_tail, rxq->tr_tail_dma);
- rxq->tr_tail_dma = 0;
- rxq->tr_tail = NULL;
-
- if (rxq->cr_tail)
- dma_free_coherent(dev, sizeof(__le16),
- rxq->cr_tail, rxq->cr_tail_dma);
- rxq->cr_tail_dma = 0;
- rxq->cr_tail = NULL;
}
static int iwl_pcie_alloc_rxq_dma(struct iwl_trans *trans,
@@ -744,21 +728,6 @@ static int iwl_pcie_alloc_rxq_dma(struct iwl_trans *trans,
rxq->rb_stts_dma =
trans_pcie->base_rb_stts_dma + rxq->id * rb_stts_size;
- if (!use_rx_td)
- return 0;
-
- /* Allocate the driver's pointer to TR tail */
- rxq->tr_tail = dma_alloc_coherent(dev, sizeof(__le16),
- &rxq->tr_tail_dma, GFP_KERNEL);
- if (!rxq->tr_tail)
- goto err;
-
- /* Allocate the driver's pointer to CR tail */
- rxq->cr_tail = dma_alloc_coherent(dev, sizeof(__le16),
- &rxq->cr_tail_dma, GFP_KERNEL);
- if (!rxq->cr_tail)
- goto err;
-
return 0;
err:
@@ -1590,9 +1559,6 @@ restart:
out:
/* Backtrack one entry */
rxq->read = i;
- /* update cr tail with the rxq read pointer */
- if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
- *rxq->cr_tail = cpu_to_le16(r);
spin_unlock(&rxq->lock);
/*
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
index 1bcd36e9e008..a34009357227 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
@@ -149,7 +149,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans)
iwl_pcie_ctxt_info_free_paging(trans);
if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
- iwl_pcie_ctxt_info_gen3_free(trans);
+ iwl_pcie_ctxt_info_gen3_free(trans, false);
else
iwl_pcie_ctxt_info_free(trans);
@@ -240,6 +240,75 @@ static int iwl_pcie_gen2_nic_init(struct iwl_trans *trans)
return 0;
}
+static void iwl_pcie_get_rf_name(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ char *buf = trans_pcie->rf_name;
+ size_t buflen = sizeof(trans_pcie->rf_name);
+ size_t pos;
+ u32 version;
+
+ if (buf[0])
+ return;
+
+ switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) {
+ case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF):
+ pos = scnprintf(buf, buflen, "JF");
+ break;
+ case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF):
+ pos = scnprintf(buf, buflen, "GF");
+ break;
+ case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF4):
+ pos = scnprintf(buf, buflen, "GF4");
+ break;
+ case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR):
+ pos = scnprintf(buf, buflen, "HR");
+ break;
+ case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR1):
+ pos = scnprintf(buf, buflen, "HR1");
+ break;
+ case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HRCDB):
+ pos = scnprintf(buf, buflen, "HRCDB");
+ break;
+ default:
+ return;
+ }
+
+ switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) {
+ case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR):
+ case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR1):
+ case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HRCDB):
+ version = iwl_read_prph(trans, CNVI_MBOX_C);
+ switch (version) {
+ case 0x20000:
+ pos += scnprintf(buf + pos, buflen - pos, " B3");
+ break;
+ case 0x120000:
+ pos += scnprintf(buf + pos, buflen - pos, " B5");
+ break;
+ default:
+ pos += scnprintf(buf + pos, buflen - pos,
+ " (0x%x)", version);
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ pos += scnprintf(buf + pos, buflen - pos, ", rfid=0x%x",
+ trans->hw_rf_id);
+
+ IWL_INFO(trans, "Detected RF %s\n", buf);
+
+ /*
+ * also add a \n for debugfs - need to do it after printing
+ * since our IWL_INFO machinery wants to see a static \n at
+ * the end of the string
+ */
+ pos += scnprintf(buf + pos, buflen - pos, "\n");
+}
+
void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -254,7 +323,10 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr)
/* now that we got alive we can free the fw image & the context info.
* paging memory cannot be freed included since FW will still use it
*/
- iwl_pcie_ctxt_info_free(trans);
+ if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
+ iwl_pcie_ctxt_info_gen3_free(trans, true);
+ else
+ iwl_pcie_ctxt_info_free(trans);
/*
* Re-enable all the interrupts, including the RF-Kill one, now that
@@ -263,6 +335,8 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr)
iwl_enable_interrupts(trans);
mutex_lock(&trans_pcie->mutex);
iwl_pcie_check_hw_rf_kill(trans);
+
+ iwl_pcie_get_rf_name(trans);
mutex_unlock(&trans_pcie->mutex);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 239bc177a3e5..bee6b4574226 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1648,7 +1648,7 @@ static void iwl_pcie_irq_set_affinity(struct iwl_trans *trans)
if (ret)
IWL_ERR(trans_pcie->trans,
"Failed to set affinity mask for IRQ %d\n",
- i);
+ trans_pcie->msix_entries[i].vector);
}
}
@@ -1943,6 +1943,12 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
trans_pcie->pnvm_dram.block,
trans_pcie->pnvm_dram.physical);
+ if (trans_pcie->reduce_power_dram.size)
+ dma_free_coherent(trans->dev,
+ trans_pcie->reduce_power_dram.size,
+ trans_pcie->reduce_power_dram.block,
+ trans_pcie->reduce_power_dram.physical);
+
mutex_destroy(&trans_pcie->mutex);
iwl_trans_free(trans);
}
@@ -2848,11 +2854,28 @@ static ssize_t iwl_dbgfs_monitor_data_read(struct file *file,
return bytes_copied;
}
+static ssize_t iwl_dbgfs_rf_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_trans *trans = file->private_data;
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ if (!trans_pcie->rf_name[0])
+ return -ENODEV;
+
+ return simple_read_from_buffer(user_buf, count, ppos,
+ trans_pcie->rf_name,
+ strlen(trans_pcie->rf_name));
+}
+
DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
DEBUGFS_READ_FILE_OPS(fh_reg);
DEBUGFS_READ_FILE_OPS(rx_queue);
DEBUGFS_WRITE_FILE_OPS(csr);
DEBUGFS_READ_WRITE_FILE_OPS(rfkill);
+DEBUGFS_READ_FILE_OPS(rf);
+
static const struct file_operations iwl_dbgfs_tx_queue_ops = {
.owner = THIS_MODULE,
.open = iwl_dbgfs_tx_queue_open,
@@ -2879,6 +2902,7 @@ void iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans)
DEBUGFS_ADD_FILE(fh_reg, dir, 0400);
DEBUGFS_ADD_FILE(rfkill, dir, 0600);
DEBUGFS_ADD_FILE(monitor_data, dir, 0400);
+ DEBUGFS_ADD_FILE(rf, dir, 0400);
}
static void iwl_trans_pcie_debugfs_cleanup(struct iwl_trans *trans)
@@ -3400,6 +3424,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = {
.wait_txq_empty = iwl_trans_pcie_wait_txq_empty,
.rxq_dma_data = iwl_trans_pcie_rxq_dma_data,
.set_pnvm = iwl_trans_pcie_ctx_info_gen3_set_pnvm,
+ .set_reduce_power = iwl_trans_pcie_ctx_info_gen3_set_reduce_power,
#ifdef CONFIG_IWLWIFI_DEBUGFS
.debugfs_cleanup = iwl_trans_pcie_debugfs_cleanup,
#endif
@@ -3413,6 +3438,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
struct iwl_trans *trans;
int ret, addr_size;
const struct iwl_trans_ops *ops = &trans_ops_pcie_gen2;
+ void __iomem * const *table;
if (!cfg_trans->gen2)
ops = &trans_ops_pcie;
@@ -3485,9 +3511,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
goto out_no_pci;
}
- trans_pcie->hw_base = pcim_iomap_table(pdev)[0];
- if (!trans_pcie->hw_base) {
+ table = pcim_iomap_table(pdev);
+ if (!table) {
dev_err(&pdev->dev, "pcim_iomap_table failed\n");
+ ret = -ENOMEM;
+ goto out_no_pci;
+ }
+
+ trans_pcie->hw_base = table[0];
+ if (!trans_pcie->hw_base) {
+ dev_err(&pdev->dev, "couldn't find IO mem in first BAR\n");
ret = -ENODEV;
goto out_no_pci;
}
diff --git a/drivers/net/wireless/intersil/orinoco/hw.c b/drivers/net/wireless/intersil/orinoco/hw.c
index 2c7adb4be100..0aea35c9c11c 100644
--- a/drivers/net/wireless/intersil/orinoco/hw.c
+++ b/drivers/net/wireless/intersil/orinoco/hw.c
@@ -988,15 +988,18 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
* tsc must be NULL or up to 8 bytes
*/
int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
- int set_tx, const u8 *key, const u8 *rsc,
- size_t rsc_len, const u8 *tsc, size_t tsc_len)
+ int set_tx, const u8 *key, size_t key_len,
+ const u8 *rsc, size_t rsc_len,
+ const u8 *tsc, size_t tsc_len)
{
struct {
__le16 idx;
u8 rsc[ORINOCO_SEQ_LEN];
- u8 key[TKIP_KEYLEN];
- u8 tx_mic[MIC_KEYLEN];
- u8 rx_mic[MIC_KEYLEN];
+ struct {
+ u8 key[TKIP_KEYLEN];
+ u8 tx_mic[MIC_KEYLEN];
+ u8 rx_mic[MIC_KEYLEN];
+ } tkip;
u8 tsc[ORINOCO_SEQ_LEN];
} __packed buf;
struct hermes *hw = &priv->hw;
@@ -1011,8 +1014,9 @@ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
key_idx |= 0x8000;
buf.idx = cpu_to_le16(key_idx);
- memcpy(buf.key, key,
- sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic));
+ if (key_len != sizeof(buf.tkip))
+ return -EINVAL;
+ memcpy(&buf.tkip, key, sizeof(buf.tkip));
if (rsc_len > sizeof(buf.rsc))
rsc_len = sizeof(buf.rsc);
diff --git a/drivers/net/wireless/intersil/orinoco/hw.h b/drivers/net/wireless/intersil/orinoco/hw.h
index 466d1ede76f1..da5804dbdf34 100644
--- a/drivers/net/wireless/intersil/orinoco/hw.h
+++ b/drivers/net/wireless/intersil/orinoco/hw.h
@@ -38,8 +38,9 @@ int __orinoco_hw_set_wap(struct orinoco_private *priv);
int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv);
int __orinoco_hw_setup_enc(struct orinoco_private *priv);
int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
- int set_tx, const u8 *key, const u8 *rsc,
- size_t rsc_len, const u8 *tsc, size_t tsc_len);
+ int set_tx, const u8 *key, size_t key_len,
+ const u8 *rsc, size_t rsc_len,
+ const u8 *tsc, size_t tsc_len);
int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx);
int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
struct net_device *dev,
diff --git a/drivers/net/wireless/intersil/orinoco/wext.c b/drivers/net/wireless/intersil/orinoco/wext.c
index 7b6c4ae8ddb3..4a01260027bc 100644
--- a/drivers/net/wireless/intersil/orinoco/wext.c
+++ b/drivers/net/wireless/intersil/orinoco/wext.c
@@ -791,7 +791,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
err = __orinoco_hw_set_tkip_key(priv, idx,
ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
- priv->keys[idx].key,
+ priv->keys[idx].key, priv->keys[idx].key_len,
tkip_iv, ORINOCO_SEQ_LEN, NULL, 0);
if (err)
printk(KERN_ERR "%s: Error %d setting TKIP key"
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 7a6fd46d0c6e..ffa894f7312a 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -626,6 +626,7 @@ struct mac80211_hwsim_data {
u32 ciphers[ARRAY_SIZE(hwsim_ciphers)];
struct mac_address addresses[2];
+ struct ieee80211_chanctx_conf *chanctx;
int channels, idx;
bool use_chanctx;
bool destroy_on_close;
@@ -1257,7 +1258,8 @@ static inline u16 trans_tx_rate_flags_ieee2hwsim(struct ieee80211_tx_rate *rate)
static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
struct sk_buff *my_skb,
- int dst_portid)
+ int dst_portid,
+ struct ieee80211_channel *channel)
{
struct sk_buff *skb;
struct mac80211_hwsim_data *data = hw->priv;
@@ -1312,7 +1314,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags))
goto nla_put_failure;
- if (nla_put_u32(skb, HWSIM_ATTR_FREQ, data->channel->center_freq))
+ if (nla_put_u32(skb, HWSIM_ATTR_FREQ, channel->center_freq))
goto nla_put_failure;
/* We get the tx control (rate and retries) info*/
@@ -1659,7 +1661,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
_portid = READ_ONCE(data->wmediumd);
if (_portid || hwsim_virtio_enabled)
- return mac80211_hwsim_tx_frame_nl(hw, skb, _portid);
+ return mac80211_hwsim_tx_frame_nl(hw, skb, _portid, channel);
/* NO wmediumd detected, perfect medium simulation */
data->tx_pkts++;
@@ -1775,8 +1777,10 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
mac80211_hwsim_monitor_rx(hw, skb, chan);
if (_pid || hwsim_virtio_enabled)
- return mac80211_hwsim_tx_frame_nl(hw, skb, _pid);
+ return mac80211_hwsim_tx_frame_nl(hw, skb, _pid, chan);
+ data->tx_pkts++;
+ data->tx_bytes += skb->len;
mac80211_hwsim_tx_frame_no_nl(hw, skb, chan);
dev_kfree_skb(skb);
}
@@ -2514,6 +2518,11 @@ static int mac80211_hwsim_croc(struct ieee80211_hw *hw,
static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
+ struct mac80211_hwsim_data *hwsim = hw->priv;
+
+ mutex_lock(&hwsim->mutex);
+ hwsim->chanctx = ctx;
+ mutex_unlock(&hwsim->mutex);
hwsim_set_chanctx_magic(ctx);
wiphy_dbg(hw->wiphy,
"add channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
@@ -2525,6 +2534,11 @@ static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw,
static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
+ struct mac80211_hwsim_data *hwsim = hw->priv;
+
+ mutex_lock(&hwsim->mutex);
+ hwsim->chanctx = NULL;
+ mutex_unlock(&hwsim->mutex);
wiphy_dbg(hw->wiphy,
"remove channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
ctx->def.chan->center_freq, ctx->def.width,
@@ -2537,6 +2551,11 @@ static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx,
u32 changed)
{
+ struct mac80211_hwsim_data *hwsim = hw->priv;
+
+ mutex_lock(&hwsim->mutex);
+ hwsim->chanctx = ctx;
+ mutex_unlock(&hwsim->mutex);
hwsim_check_chanctx_magic(ctx);
wiphy_dbg(hw->wiphy,
"change channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
@@ -3129,6 +3148,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
hw->wiphy->max_remain_on_channel_duration = 1000;
data->if_combination.radar_detect_widths = 0;
data->if_combination.num_different_channels = data->channels;
+ data->chanctx = NULL;
} else {
data->if_combination.num_different_channels = 1;
data->if_combination.radar_detect_widths =
@@ -3638,6 +3658,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
int frame_data_len;
void *frame_data;
struct sk_buff *skb = NULL;
+ struct ieee80211_channel *channel = NULL;
if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] ||
!info->attrs[HWSIM_ATTR_FRAME] ||
@@ -3664,6 +3685,17 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
if (!data2)
goto out;
+ if (data2->use_chanctx) {
+ if (data2->tmp_chan)
+ channel = data2->tmp_chan;
+ else if (data2->chanctx)
+ channel = data2->chanctx->def.chan;
+ } else {
+ channel = data2->channel;
+ }
+ if (!channel)
+ goto out;
+
if (!hwsim_virtio_enabled) {
if (hwsim_net_get_netgroup(genl_info_net(info)) !=
data2->netgroup)
@@ -3675,7 +3707,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
/* check if radio is configured properly */
- if (data2->idle || !data2->started)
+ if ((data2->idle && !data2->tmp_chan) || !data2->started)
goto out;
/* A frame is received from user space */
@@ -3688,18 +3720,16 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
mutex_lock(&data2->mutex);
rx_status.freq = nla_get_u32(info->attrs[HWSIM_ATTR_FREQ]);
- if (rx_status.freq != data2->channel->center_freq &&
- (!data2->tmp_chan ||
- rx_status.freq != data2->tmp_chan->center_freq)) {
+ if (rx_status.freq != channel->center_freq) {
mutex_unlock(&data2->mutex);
goto out;
}
mutex_unlock(&data2->mutex);
} else {
- rx_status.freq = data2->channel->center_freq;
+ rx_status.freq = channel->center_freq;
}
- rx_status.band = data2->channel->band;
+ rx_status.band = channel->band;
rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
@@ -3796,11 +3826,6 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
return -EINVAL;
}
- if (param.channels > CFG80211_MAX_NUM_DIFFERENT_CHANNELS) {
- GENL_SET_ERR_MSG(info, "too many channels specified");
- return -EINVAL;
- }
-
if (info->attrs[HWSIM_ATTR_NO_VIF])
param.no_vif = true;
diff --git a/drivers/net/wireless/marvell/libertas/main.c b/drivers/net/wireless/marvell/libertas/main.c
index ee4cf3437e28..64fc5e410864 100644
--- a/drivers/net/wireless/marvell/libertas/main.c
+++ b/drivers/net/wireless/marvell/libertas/main.c
@@ -941,7 +941,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
wdev->netdev = dev;
priv->dev = dev;
- dev->netdev_ops = &lbs_netdev_ops;
+ dev->netdev_ops = &lbs_netdev_ops;
dev->watchdog_timeo = 5 * HZ;
dev->ethtool_ops = &lbs_ethtool_ops;
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
diff --git a/drivers/net/wireless/marvell/libertas/mesh.c b/drivers/net/wireless/marvell/libertas/mesh.c
index c68814841583..6cbba84989b8 100644
--- a/drivers/net/wireless/marvell/libertas/mesh.c
+++ b/drivers/net/wireless/marvell/libertas/mesh.c
@@ -151,13 +151,13 @@ static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
*/
/**
- * lbs_anycast_get - Get function for sysfs attribute anycast_mask
+ * anycast_mask_show - Get function for sysfs attribute anycast_mask
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer where data will be returned
*/
-static ssize_t lbs_anycast_get(struct device *dev,
- struct device_attribute *attr, char * buf)
+static ssize_t anycast_mask_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_access mesh_access;
@@ -173,14 +173,15 @@ static ssize_t lbs_anycast_get(struct device *dev,
}
/**
- * lbs_anycast_set - Set function for sysfs attribute anycast_mask
+ * anycast_mask_store - Set function for sysfs attribute anycast_mask
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer that contains new attribute value
* @count: size of buffer
*/
-static ssize_t lbs_anycast_set(struct device *dev,
- struct device_attribute *attr, const char * buf, size_t count)
+static ssize_t anycast_mask_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_access mesh_access;
@@ -199,13 +200,13 @@ static ssize_t lbs_anycast_set(struct device *dev,
}
/**
- * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit
+ * prb_rsp_limit_show - Get function for sysfs attribute prb_rsp_limit
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer where data will be returned
*/
-static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t prb_rsp_limit_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_access mesh_access;
@@ -225,14 +226,15 @@ static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
}
/**
- * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit
+ * prb_rsp_limit_store - Set function for sysfs attribute prb_rsp_limit
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer that contains new attribute value
* @count: size of buffer
*/
-static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t prb_rsp_limit_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_access mesh_access;
@@ -259,27 +261,28 @@ static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
}
/**
- * lbs_mesh_get - Get function for sysfs attribute mesh
+ * lbs_mesh_show - Get function for sysfs attribute mesh
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer where data will be returned
*/
-static ssize_t lbs_mesh_get(struct device *dev,
- struct device_attribute *attr, char * buf)
+static ssize_t lbs_mesh_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
}
/**
- * lbs_mesh_set - Set function for sysfs attribute mesh
+ * lbs_mesh_store - Set function for sysfs attribute mesh
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer that contains new attribute value
* @count: size of buffer
*/
-static ssize_t lbs_mesh_set(struct device *dev,
- struct device_attribute *attr, const char * buf, size_t count)
+static ssize_t lbs_mesh_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
int enable;
@@ -301,20 +304,19 @@ static ssize_t lbs_mesh_set(struct device *dev,
* lbs_mesh attribute to be exported per ethX interface
* through sysfs (/sys/class/net/ethX/lbs_mesh)
*/
-static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
+static DEVICE_ATTR_RW(lbs_mesh);
/*
* anycast_mask attribute to be exported per mshX interface
* through sysfs (/sys/class/net/mshX/anycast_mask)
*/
-static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
+static DEVICE_ATTR_RW(anycast_mask);
/*
* prb_rsp_limit attribute to be exported per mshX interface
* through sysfs (/sys/class/net/mshX/prb_rsp_limit)
*/
-static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
- lbs_prb_rsp_limit_set);
+static DEVICE_ATTR_RW(prb_rsp_limit);
static struct attribute *lbs_mesh_sysfs_entries[] = {
&dev_attr_anycast_mask.attr,
@@ -351,13 +353,13 @@ static int mesh_get_default_parameters(struct device *dev,
}
/**
- * bootflag_get - Get function for sysfs attribute bootflag
+ * bootflag_show - Get function for sysfs attribute bootflag
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer where data will be returned
*/
-static ssize_t bootflag_get(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t bootflag_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
@@ -371,14 +373,14 @@ static ssize_t bootflag_get(struct device *dev,
}
/**
- * bootflag_set - Set function for sysfs attribute bootflag
+ * bootflag_store - Set function for sysfs attribute bootflag
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer that contains new attribute value
* @count: size of buffer
*/
-static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t bootflag_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_config cmd;
@@ -401,13 +403,13 @@ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
}
/**
- * boottime_get - Get function for sysfs attribute boottime
+ * boottime_show - Get function for sysfs attribute boottime
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer where data will be returned
*/
-static ssize_t boottime_get(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t boottime_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
@@ -421,14 +423,15 @@ static ssize_t boottime_get(struct device *dev,
}
/**
- * boottime_set - Set function for sysfs attribute boottime
+ * boottime_store - Set function for sysfs attribute boottime
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer that contains new attribute value
* @count: size of buffer
*/
-static ssize_t boottime_set(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t boottime_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_config cmd;
@@ -460,13 +463,13 @@ static ssize_t boottime_set(struct device *dev,
}
/**
- * channel_get - Get function for sysfs attribute channel
+ * channel_show - Get function for sysfs attribute channel
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer where data will be returned
*/
-static ssize_t channel_get(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t channel_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
@@ -480,14 +483,14 @@ static ssize_t channel_get(struct device *dev,
}
/**
- * channel_set - Set function for sysfs attribute channel
+ * channel_store - Set function for sysfs attribute channel
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer that contains new attribute value
* @count: size of buffer
*/
-static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t channel_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
struct cmd_ds_mesh_config cmd;
@@ -510,13 +513,13 @@ static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
}
/**
- * mesh_id_get - Get function for sysfs attribute mesh_id
+ * mesh_id_show - Get function for sysfs attribute mesh_id
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer where data will be returned
*/
-static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t mesh_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
@@ -539,14 +542,14 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
}
/**
- * mesh_id_set - Set function for sysfs attribute mesh_id
+ * mesh_id_store - Set function for sysfs attribute mesh_id
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer that contains new attribute value
* @count: size of buffer
*/
-static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t mesh_id_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
@@ -585,13 +588,14 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
}
/**
- * protocol_id_get - Get function for sysfs attribute protocol_id
+ * protocol_id_show - Get function for sysfs attribute protocol_id
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer where data will be returned
*/
-static ssize_t protocol_id_get(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t protocol_id_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
@@ -605,14 +609,15 @@ static ssize_t protocol_id_get(struct device *dev,
}
/**
- * protocol_id_set - Set function for sysfs attribute protocol_id
+ * protocol_id_store - Set function for sysfs attribute protocol_id
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer that contains new attribute value
* @count: size of buffer
*/
-static ssize_t protocol_id_set(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t protocol_id_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
@@ -646,13 +651,13 @@ static ssize_t protocol_id_set(struct device *dev,
}
/**
- * metric_id_get - Get function for sysfs attribute metric_id
+ * metric_id_show - Get function for sysfs attribute metric_id
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer where data will be returned
*/
-static ssize_t metric_id_get(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t metric_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
@@ -666,14 +671,15 @@ static ssize_t metric_id_get(struct device *dev,
}
/**
- * metric_id_set - Set function for sysfs attribute metric_id
+ * metric_id_store - Set function for sysfs attribute metric_id
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer that contains new attribute value
* @count: size of buffer
*/
-static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t metric_id_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
@@ -707,13 +713,13 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
}
/**
- * capability_get - Get function for sysfs attribute capability
+ * capability_show - Get function for sysfs attribute capability
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer where data will be returned
*/
-static ssize_t capability_get(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t capability_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
@@ -727,14 +733,15 @@ static ssize_t capability_get(struct device *dev,
}
/**
- * capability_set - Set function for sysfs attribute capability
+ * capability_store - Set function for sysfs attribute capability
* @dev: the &struct device
* @attr: device attributes
* @buf: buffer that contains new attribute value
* @count: size of buffer
*/
-static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t capability_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
@@ -768,13 +775,13 @@ static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
}
-static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
-static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
-static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
-static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
-static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
-static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
-static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
+static DEVICE_ATTR_RW(bootflag);
+static DEVICE_ATTR_RW(boottime);
+static DEVICE_ATTR_RW(channel);
+static DEVICE_ATTR_RW(mesh_id);
+static DEVICE_ATTR_RW(protocol_id);
+static DEVICE_ATTR_RW(metric_id);
+static DEVICE_ATTR_RW(capability);
static struct attribute *boot_opts_attrs[] = {
&dev_attr_bootflag.attr,
diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
index a92916dc81a9..fe0a69e804d8 100644
--- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
@@ -48,7 +48,7 @@ static int if_usb_submit_rx_urb(struct if_usb_card *cardp);
static int if_usb_reset_device(struct lbtf_private *priv);
/**
- * if_usb_wrike_bulk_callback - call back to handle URB status
+ * if_usb_write_bulk_callback - call back to handle URB status
*
* @urb: pointer to urb structure
*/
diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h
index 470d669c7f14..2ff23ab259ab 100644
--- a/drivers/net/wireless/marvell/mwifiex/fw.h
+++ b/drivers/net/wireless/marvell/mwifiex/fw.h
@@ -995,6 +995,11 @@ struct host_cmd_ds_802_11_key_material {
struct mwifiex_ie_type_key_param_set key_param_set;
} __packed;
+struct host_cmd_ds_802_11_key_material_wep {
+ __le16 action;
+ struct mwifiex_ie_type_key_param_set key_param_set[NUM_WEP_KEYS];
+} __packed;
+
struct host_cmd_ds_gen {
__le16 command;
__le16 size;
@@ -2347,6 +2352,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_wmm_get_status get_wmm_status;
struct host_cmd_ds_802_11_key_material key_material;
struct host_cmd_ds_802_11_key_material_v2 key_material_v2;
+ struct host_cmd_ds_802_11_key_material_wep key_material_wep;
struct host_cmd_ds_version_ext verext;
struct host_cmd_ds_mgmt_frame_reg reg_mask;
struct host_cmd_ds_remain_on_chan roc_cfg;
diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index 529dfd8b7ae8..17399d4aa129 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -1445,11 +1445,18 @@ static void mwifiex_uninit_sw(struct mwifiex_adapter *adapter)
if (!priv)
continue;
rtnl_lock();
- wiphy_lock(adapter->wiphy);
if (priv->netdev &&
- priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED)
+ priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED) {
+ /*
+ * Close the netdev now, because if we do it later, the
+ * netdev notifiers will need to acquire the wiphy lock
+ * again --> deadlock.
+ */
+ dev_close(priv->wdev.netdev);
+ wiphy_lock(adapter->wiphy);
mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev);
- wiphy_unlock(adapter->wiphy);
+ wiphy_unlock(adapter->wiphy);
+ }
rtnl_unlock();
}
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 94228b316df1..46517515ba72 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -1231,7 +1231,7 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
{
struct pcie_service_card *card = adapter->card;
- u32 tmp;
+ u32 *cookie;
card->sleep_cookie_vbase = dma_alloc_coherent(&card->dev->dev,
sizeof(u32),
@@ -1242,13 +1242,11 @@ static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
"dma_alloc_coherent failed!\n");
return -ENOMEM;
}
+ cookie = (u32 *)card->sleep_cookie_vbase;
/* Init val of Sleep Cookie */
- tmp = FW_AWAKE_COOKIE;
- put_unaligned(tmp, card->sleep_cookie_vbase);
+ *cookie = FW_AWAKE_COOKIE;
- mwifiex_dbg(adapter, INFO,
- "alloc_scook: sleep cookie=0x%x\n",
- get_unaligned(card->sleep_cookie_vbase));
+ mwifiex_dbg(adapter, INFO, "alloc_scook: sleep cookie=0x%x\n", *cookie);
return 0;
}
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
index d3a968ef21ef..48ea00da1fc9 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
@@ -840,14 +840,15 @@ mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv,
}
if (!enc_key) {
- memset(&key_material->key_param_set, 0,
- (NUM_WEP_KEYS *
- sizeof(struct mwifiex_ie_type_key_param_set)));
+ struct host_cmd_ds_802_11_key_material_wep *key_material_wep =
+ (struct host_cmd_ds_802_11_key_material_wep *)key_material;
+ memset(key_material_wep->key_param_set, 0,
+ sizeof(key_material_wep->key_param_set));
ret = mwifiex_set_keyparamset_wep(priv,
- &key_material->key_param_set,
+ &key_material_wep->key_param_set[0],
&key_param_len);
cmd->size = cpu_to_le16(key_param_len +
- sizeof(key_material->action) + S_DS_GEN);
+ sizeof(key_material_wep->action) + S_DS_GEN);
return ret;
} else
memset(&key_material->key_param_set, 0,
diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c
index 84b32a5f01ee..3bf6571f4149 100644
--- a/drivers/net/wireless/marvell/mwl8k.c
+++ b/drivers/net/wireless/marvell/mwl8k.c
@@ -4552,7 +4552,7 @@ static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw,
else
rates = sta->supp_rates[NL80211_BAND_5GHZ] << 5;
legacy_rate_mask_to_array(p->legacy_rates, rates);
- memcpy(p->ht_rates, sta->ht_cap.mcs.rx_mask, 16);
+ memcpy(p->ht_rates, &sta->ht_cap.mcs, 16);
p->interop = 1;
p->amsdu_enabled = 0;
@@ -5034,7 +5034,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
ap_legacy_rates =
ap->supp_rates[NL80211_BAND_5GHZ] << 5;
}
- memcpy(ap_mcs_rates, ap->ht_cap.mcs.rx_mask, 16);
+ memcpy(ap_mcs_rates, &ap->ht_cap.mcs, 16);
rcu_read_unlock();
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 72b1cc0ecfda..5e1c1506a4c6 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -191,6 +191,7 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
q->entry[idx].txwi = txwi;
q->entry[idx].skb = skb;
+ q->entry[idx].wcid = 0xffff;
return idx;
}
@@ -349,6 +350,9 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta)
{
+ struct ieee80211_tx_status status = {
+ .sta = sta,
+ };
struct mt76_tx_info tx_info = {
.skb = skb,
};
@@ -360,11 +364,9 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
u8 *txwi;
t = mt76_get_txwi(dev);
- if (!t) {
- hw = mt76_tx_status_get_hw(dev, skb);
- ieee80211_free_txskb(hw, skb);
- return -ENOMEM;
- }
+ if (!t)
+ goto free_skb;
+
txwi = mt76_get_txwi_ptr(dev, t);
skb->prev = skb->next = NULL;
@@ -427,8 +429,13 @@ free:
}
#endif
- dev_kfree_skb(tx_info.skb);
mt76_put_txwi(dev, t);
+
+free_skb:
+ status.skb = tx_info.skb;
+ hw = mt76_tx_status_get_hw(dev, tx_info.skb);
+ ieee80211_tx_status_ext(hw, &status);
+
return ret;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 03fe62837557..d03aedc3286b 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -83,6 +83,22 @@ static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
{ .throughput = 300 * 1024, .blink_time = 50 },
};
+struct ieee80211_rate mt76_rates[] = {
+ CCK_RATE(0, 10),
+ CCK_RATE(1, 20),
+ CCK_RATE(2, 55),
+ CCK_RATE(3, 110),
+ OFDM_RATE(11, 60),
+ OFDM_RATE(15, 90),
+ OFDM_RATE(10, 120),
+ OFDM_RATE(14, 180),
+ OFDM_RATE(9, 240),
+ OFDM_RATE(13, 360),
+ OFDM_RATE(8, 480),
+ OFDM_RATE(12, 540),
+};
+EXPORT_SYMBOL_GPL(mt76_rates);
+
static int mt76_led_init(struct mt76_dev *dev)
{
struct device_node *np = dev->dev->of_node;
@@ -315,17 +331,6 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
ieee80211_hw_set(hw, MFP_CAPABLE);
ieee80211_hw_set(hw, AP_LINK_PS);
ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
-
- wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
- wiphy->interface_modes =
- BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_AP) |
-#ifdef CONFIG_MAC80211_MESH
- BIT(NL80211_IFTYPE_MESH_POINT) |
-#endif
- BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO) |
- BIT(NL80211_IFTYPE_ADHOC);
}
struct mt76_phy *
@@ -346,6 +351,17 @@ mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
phy->hw = hw;
phy->priv = hw->priv + phy_size;
+ hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+ hw->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+#ifdef CONFIG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_ADHOC);
+
return phy;
}
EXPORT_SYMBOL_GPL(mt76_alloc_phy);
@@ -428,6 +444,17 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
mutex_init(&dev->mcu.mutex);
dev->tx_worker.fn = mt76_tx_worker;
+ hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+ hw->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+#ifdef CONFIG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_ADHOC);
+
spin_lock_init(&dev->token_lock);
idr_init(&dev->token);
@@ -632,20 +659,19 @@ void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
}
EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
-void mt76_update_survey(struct mt76_dev *dev)
+void mt76_update_survey(struct mt76_phy *phy)
{
+ struct mt76_dev *dev = phy->dev;
ktime_t cur_time;
if (dev->drv->update_survey)
- dev->drv->update_survey(dev);
+ dev->drv->update_survey(phy);
cur_time = ktime_get_boottime();
- mt76_update_survey_active_time(&dev->phy, cur_time);
- if (dev->phy2)
- mt76_update_survey_active_time(dev->phy2, cur_time);
+ mt76_update_survey_active_time(phy, cur_time);
if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
- struct mt76_channel_state *state = dev->phy.chan_state;
+ struct mt76_channel_state *state = phy->chan_state;
spin_lock_bh(&dev->cc_lock);
state->cc_bss_rx += dev->cur_cc_bss_rx;
@@ -664,7 +690,7 @@ void mt76_set_channel(struct mt76_phy *phy)
int timeout = HZ / 5;
wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
- mt76_update_survey(dev);
+ mt76_update_survey(phy);
phy->chandef = *chandef;
phy->chan_state = mt76_channel_state(phy, chandef->chan);
@@ -689,7 +715,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx,
mutex_lock(&dev->mutex);
if (idx == 0 && dev->drv->update_survey)
- mt76_update_survey(dev);
+ mt76_update_survey(phy);
sband = &phy->sband_2g;
if (idx >= sband->sband.n_channels) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 36ede65919f8..25c5ceef5257 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -87,6 +87,22 @@ enum mt76_rxq_id {
__MT_RXQ_MAX
};
+enum mt76_cipher_type {
+ MT_CIPHER_NONE,
+ MT_CIPHER_WEP40,
+ MT_CIPHER_TKIP,
+ MT_CIPHER_TKIP_NO_MIC,
+ MT_CIPHER_AES_CCMP,
+ MT_CIPHER_WEP104,
+ MT_CIPHER_BIP_CMAC_128,
+ MT_CIPHER_WEP128,
+ MT_CIPHER_WAPI,
+ MT_CIPHER_CCMP_CCX,
+ MT_CIPHER_CCMP_256,
+ MT_CIPHER_GCMP,
+ MT_CIPHER_GCMP_256,
+};
+
struct mt76_queue_buf {
dma_addr_t addr;
u16 len;
@@ -320,6 +336,7 @@ enum {
struct mt76_hw_cap {
bool has_2ghz;
bool has_5ghz;
+ bool has_6ghz;
};
#define MT_DRV_TXWI_NO_FREE BIT(0)
@@ -336,7 +353,7 @@ struct mt76_driver_ops {
u16 token_size;
u8 mcs_rates;
- void (*update_survey)(struct mt76_dev *dev);
+ void (*update_survey)(struct mt76_phy *phy);
int (*tx_prepare_skb)(struct mt76_dev *dev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
@@ -738,6 +755,21 @@ enum mt76_phy_type {
MT_PHY_TYPE_HE_MU,
};
+#define CCK_RATE(_idx, _rate) { \
+ .bitrate = _rate, \
+ .flags = IEEE80211_RATE_SHORT_PREAMBLE, \
+ .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \
+ .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + _idx), \
+}
+
+#define OFDM_RATE(_idx, _rate) { \
+ .bitrate = _rate, \
+ .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
+ .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
+}
+
+extern struct ieee80211_rate mt76_rates[12];
+
#define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__)
#define __mt76_wr(dev, ...) (dev)->bus->wr((dev), __VA_ARGS__)
#define __mt76_rmw(dev, ...) (dev)->bus->rmw((dev), __VA_ARGS__)
@@ -1031,7 +1063,7 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw,
bool more_data);
bool mt76_has_tx_pending(struct mt76_phy *phy);
void mt76_set_channel(struct mt76_phy *phy);
-void mt76_update_survey(struct mt76_dev *dev);
+void mt76_update_survey(struct mt76_phy *phy);
void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time);
int mt76_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey);
@@ -1056,7 +1088,14 @@ struct sk_buff *mt76_tx_status_skb_get(struct mt76_dev *dev,
struct sk_buff_head *list);
void mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb,
struct sk_buff_head *list);
-void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid, struct sk_buff *skb);
+void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid, struct sk_buff *skb,
+ struct list_head *free_list);
+static inline void
+mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid, struct sk_buff *skb)
+{
+ __mt76_tx_complete_skb(dev, wcid, skb, NULL);
+}
+
void mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid,
bool flush);
int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -1253,4 +1292,15 @@ mt76_token_put(struct mt76_dev *dev, int token)
return txwi;
}
+
+static inline int
+mt76_get_next_pkt_id(struct mt76_wcid *wcid)
+{
+ wcid->packet_id = (wcid->packet_id + 1) & MT_PACKET_ID_MASK;
+ if (wcid->packet_id == MT_PACKET_ID_NO_ACK ||
+ wcid->packet_id == MT_PACKET_ID_NO_SKB)
+ wcid->packet_id = MT_PACKET_ID_FIRST;
+
+ return wcid->packet_id;
+}
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
index e1b2cfa56074..031d39a48a55 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
@@ -304,34 +304,6 @@ mt7603_init_hardware(struct mt7603_dev *dev)
return 0;
}
-#define CCK_RATE(_idx, _rate) { \
- .bitrate = _rate, \
- .flags = IEEE80211_RATE_SHORT_PREAMBLE, \
- .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \
- .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + _idx), \
-}
-
-#define OFDM_RATE(_idx, _rate) { \
- .bitrate = _rate, \
- .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
- .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
-}
-
-static struct ieee80211_rate mt7603_rates[] = {
- CCK_RATE(0, 10),
- CCK_RATE(1, 20),
- CCK_RATE(2, 55),
- CCK_RATE(3, 110),
- OFDM_RATE(11, 60),
- OFDM_RATE(15, 90),
- OFDM_RATE(10, 120),
- OFDM_RATE(14, 180),
- OFDM_RATE(9, 240),
- OFDM_RATE(13, 360),
- OFDM_RATE(8, 480),
- OFDM_RATE(12, 540),
-};
-
static const struct ieee80211_iface_limit if_limits[] = {
{
.max = 1,
@@ -569,8 +541,8 @@ int mt7603_register_device(struct mt7603_dev *dev)
wiphy->reg_notifier = mt7603_regd_notifier;
- ret = mt76_register_device(&dev->mt76, true, mt7603_rates,
- ARRAY_SIZE(mt7603_rates));
+ ret = mt76_register_device(&dev->mt76, true, mt76_rates,
+ ARRAY_SIZE(mt76_rates));
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
index fbceb07c5f37..3972c56136a2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
@@ -550,14 +550,27 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
u8 *data = (u8 *)rxd;
if (status->flag & RX_FLAG_DECRYPTED) {
- status->iv[0] = data[5];
- status->iv[1] = data[4];
- status->iv[2] = data[3];
- status->iv[3] = data[2];
- status->iv[4] = data[1];
- status->iv[5] = data[0];
-
- insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
+ switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) {
+ case MT_CIPHER_AES_CCMP:
+ case MT_CIPHER_CCMP_CCX:
+ case MT_CIPHER_CCMP_256:
+ insert_ccmp_hdr =
+ FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
+ fallthrough;
+ case MT_CIPHER_TKIP:
+ case MT_CIPHER_TKIP_NO_MIC:
+ case MT_CIPHER_GCMP:
+ case MT_CIPHER_GCMP_256:
+ status->iv[0] = data[5];
+ status->iv[1] = data[4];
+ status->iv[2] = data[3];
+ status->iv[3] = data[2];
+ status->iv[4] = data[1];
+ status->iv[5] = data[0];
+ break;
+ default:
+ break;
+ }
}
rxd += 4;
@@ -831,7 +844,7 @@ void mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta,
sta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
}
-static enum mt7603_cipher_type
+static enum mt76_cipher_type
mt7603_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
{
memset(key_data, 0, 32);
@@ -863,7 +876,7 @@ mt7603_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
int mt7603_wtbl_set_key(struct mt7603_dev *dev, int wcid,
struct ieee80211_key_conf *key)
{
- enum mt7603_cipher_type cipher;
+ enum mt76_cipher_type cipher;
u32 addr = mt7603_wtbl3_addr(wcid);
u8 key_data[32];
int key_len = sizeof(key_data);
@@ -1213,7 +1226,7 @@ mt7603_mac_add_txs_skb(struct mt7603_dev *dev, struct mt7603_sta *sta, int pid,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (!mt7603_fill_txs(dev, sta, info, txs_data)) {
- ieee80211_tx_info_clear_status(info);
+ info->status.rates[0].count = 0;
info->status.rates[0].idx = -1;
}
@@ -1584,12 +1597,12 @@ trigger:
return true;
}
-void mt7603_update_channel(struct mt76_dev *mdev)
+void mt7603_update_channel(struct mt76_phy *mphy)
{
- struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
+ struct mt7603_dev *dev = container_of(mphy->dev, struct mt7603_dev, mt76);
struct mt76_channel_state *state;
- state = mdev->phy.chan_state;
+ state = mphy->chan_state;
state->cc_busy += mt76_rr(dev, MT_MIB_STAT_CCA);
}
@@ -1806,7 +1819,7 @@ void mt7603_mac_work(struct work_struct *work)
mutex_lock(&dev->mt76.mutex);
dev->mphy.mac_work_count++;
- mt76_update_survey(&dev->mt76);
+ mt76_update_survey(&dev->mphy);
mt7603_edcca_check(dev);
for (i = 0, idx = 0; i < 2; i++) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
index 1df5b9fed2bb..0fd46d907638 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
@@ -256,7 +256,7 @@ void mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
void mt7603_pre_tbtt_tasklet(struct tasklet_struct *t);
-void mt7603_update_channel(struct mt76_dev *mdev);
+void mt7603_update_channel(struct mt76_phy *mphy);
void mt7603_edcca_set_strict(struct mt7603_dev *dev, bool val);
void mt7603_cca_stats_reset(struct mt7603_dev *dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h
index 6741e6907194..3b901090b29c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h
@@ -765,16 +765,4 @@ enum {
#define MT_WTBL1_OR (MT_WTBL1_BASE + 0x2300)
#define MT_WTBL1_OR_PSM_WRITE BIT(31)
-enum mt7603_cipher_type {
- MT_CIPHER_NONE,
- MT_CIPHER_WEP40,
- MT_CIPHER_TKIP,
- MT_CIPHER_TKIP_NO_MIC,
- MT_CIPHER_AES_CCMP,
- MT_CIPHER_WEP104,
- MT_CIPHER_BIP_CMAC_128,
- MT_CIPHER_WEP128,
- MT_CIPHER_WAPI,
-};
-
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile
index e8fc4a7ae9bc..83f9861ff522 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile
@@ -1,4 +1,4 @@
-#SPDX-License-Identifier: ISC
+# SPDX-License-Identifier: ISC
obj-$(CONFIG_MT7615_COMMON) += mt7615-common.o
obj-$(CONFIG_MT7615E) += mt7615e.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
index 676bb22726d6..cb4659771fd9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
@@ -75,7 +75,7 @@ mt7615_pm_set(void *data, u64 val)
if (!mt7615_wait_for_mcu_init(dev))
return 0;
- if (!mt7615_firmware_offload(dev) || !mt76_is_mmio(&dev->mt76))
+ if (!mt7615_firmware_offload(dev) || mt76_is_usb(&dev->mt76))
return -EOPNOTSUPP;
if (val == pm->enable)
@@ -319,24 +319,6 @@ mt7615_radio_read(struct seq_file *s, void *data)
return 0;
}
-static int mt7615_read_temperature(struct seq_file *s, void *data)
-{
- struct mt7615_dev *dev = dev_get_drvdata(s->private);
- int temp;
-
- if (!mt7615_wait_for_mcu_init(dev))
- return 0;
-
- /* cpu */
- mt7615_mutex_acquire(dev);
- temp = mt7615_mcu_get_temperature(dev, 0);
- mt7615_mutex_release(dev);
-
- seq_printf(s, "Temperature: %d\n", temp);
-
- return 0;
-}
-
static int
mt7615_queues_acq(struct seq_file *s, void *data)
{
@@ -566,8 +548,6 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
debugfs_create_file("reset_test", 0200, dir, dev,
&fops_reset_test);
- debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir,
- mt7615_read_temperature);
debugfs_create_file("ext_mac_addr", 0600, dir, dev, &fops_ext_mac_addr);
debugfs_create_u32("rf_wfidx", 0600, dir, &dev->debugfs_rf_wf);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
index 8004ae5c16a9..00aefea1bf61 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
@@ -81,7 +81,7 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget)
if (napi_complete(napi))
mt7615_irq_enable(dev, mt7615_tx_mcu_int_mask(dev));
- mt76_connac_pm_unref(&dev->pm);
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
return 0;
}
@@ -99,7 +99,7 @@ static int mt7615_poll_rx(struct napi_struct *napi, int budget)
return 0;
}
done = mt76_dma_rx_poll(napi, budget);
- mt76_connac_pm_unref(&dev->pm);
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
return done;
}
@@ -222,14 +222,9 @@ void mt7615_dma_start(struct mt7615_dev *dev)
int mt7615_dma_init(struct mt7615_dev *dev)
{
int rx_ring_size = MT7615_RX_RING_SIZE;
- int rx_buf_size = MT_RX_BUF_SIZE;
u32 mask;
int ret;
- /* Increase buffer size to receive large VHT MPDUs */
- if (dev->mphy.cap.has_5ghz)
- rx_buf_size *= 2;
-
mt76_dma_attach(&dev->mt76);
mt76_wr(dev, MT_WPDMA_GLO_CFG,
@@ -270,7 +265,7 @@ int mt7615_dma_init(struct mt7615_dev *dev)
/* init rx queues */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1,
- MT7615_RX_MCU_RING_SIZE, rx_buf_size,
+ MT7615_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE,
MT_RX_RING_BASE);
if (ret)
return ret;
@@ -279,7 +274,7 @@ int mt7615_dma_init(struct mt7615_dev *dev)
rx_ring_size /= 2;
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0,
- rx_ring_size, rx_buf_size, MT_RX_RING_BASE);
+ rx_ring_size, MT_RX_BUF_SIZE, MT_RX_RING_BASE);
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
index d20f05a7717d..2f1ac644e018 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
@@ -8,11 +8,61 @@
*/
#include <linux/etherdevice.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include "mt7615.h"
#include "mac.h"
#include "mcu.h"
#include "eeprom.h"
+static ssize_t mt7615_thermal_show_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mt7615_dev *mdev = dev_get_drvdata(dev);
+ int temperature;
+
+ if (!mt7615_wait_for_mcu_init(mdev))
+ return 0;
+
+ mt7615_mutex_acquire(mdev);
+ temperature = mt7615_mcu_get_temperature(mdev);
+ mt7615_mutex_release(mdev);
+
+ if (temperature < 0)
+ return temperature;
+
+ /* display in millidegree celcius */
+ return sprintf(buf, "%u\n", temperature * 1000);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, 0444, mt7615_thermal_show_temp,
+ NULL, 0);
+
+static struct attribute *mt7615_hwmon_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(mt7615_hwmon);
+
+int mt7615_thermal_init(struct mt7615_dev *dev)
+{
+ struct wiphy *wiphy = mt76_hw(dev)->wiphy;
+ struct device *hwmon;
+
+ if (!IS_REACHABLE(CONFIG_HWMON))
+ return 0;
+
+ hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev,
+ wiphy_name(wiphy), dev,
+ mt7615_hwmon_groups);
+ if (IS_ERR(hwmon))
+ return PTR_ERR(hwmon);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt7615_thermal_init);
+
static void
mt7615_phy_init(struct mt7615_dev *dev)
{
@@ -174,35 +224,6 @@ bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev)
}
EXPORT_SYMBOL_GPL(mt7615_wait_for_mcu_init);
-#define CCK_RATE(_idx, _rate) { \
- .bitrate = _rate, \
- .flags = IEEE80211_RATE_SHORT_PREAMBLE, \
- .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \
- .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)), \
-}
-
-#define OFDM_RATE(_idx, _rate) { \
- .bitrate = _rate, \
- .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
- .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
-}
-
-struct ieee80211_rate mt7615_rates[] = {
- CCK_RATE(0, 10),
- CCK_RATE(1, 20),
- CCK_RATE(2, 55),
- CCK_RATE(3, 110),
- OFDM_RATE(11, 60),
- OFDM_RATE(15, 90),
- OFDM_RATE(10, 120),
- OFDM_RATE(14, 180),
- OFDM_RATE(9, 240),
- OFDM_RATE(13, 360),
- OFDM_RATE(8, 480),
- OFDM_RATE(12, 540),
-};
-EXPORT_SYMBOL_GPL(mt7615_rates);
-
static const struct ieee80211_iface_limit if_limits[] = {
{
.max = 1,
@@ -362,7 +383,7 @@ mt7615_init_wiphy(struct ieee80211_hw *hw)
wiphy->reg_notifier = mt7615_regd_notifier;
wiphy->max_sched_scan_plan_interval =
- MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL;
+ MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL;
wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN;
wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN;
wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID;
@@ -472,8 +493,8 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
for (i = 0; i <= MT_TXQ_PSD ; i++)
mphy->q_tx[i] = dev->mphy.q_tx[i];
- ret = mt76_register_phy(mphy, true, mt7615_rates,
- ARRAY_SIZE(mt7615_rates));
+ ret = mt76_register_phy(mphy, true, mt76_rates,
+ ARRAY_SIZE(mt76_rates));
if (ret)
ieee80211_free_hw(mphy->hw);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index e2dcfee6be81..ff3f85e4087c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -20,7 +20,7 @@
#define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2)
static const struct mt7615_dfs_radar_spec etsi_radar_specs = {
- .pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 },
+ .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
.radar_pattern = {
[5] = { 1, 0, 6, 32, 28, 0, 17, 990, 5010, 1, 1 },
[6] = { 1, 0, 9, 32, 28, 0, 27, 615, 5010, 1, 1 },
@@ -34,7 +34,7 @@ static const struct mt7615_dfs_radar_spec etsi_radar_specs = {
};
static const struct mt7615_dfs_radar_spec fcc_radar_specs = {
- .pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 },
+ .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
.radar_pattern = {
[0] = { 1, 0, 9, 32, 28, 0, 13, 508, 3076, 1, 1 },
[1] = { 1, 0, 12, 32, 28, 0, 17, 140, 240, 1, 1 },
@@ -45,7 +45,7 @@ static const struct mt7615_dfs_radar_spec fcc_radar_specs = {
};
static const struct mt7615_dfs_radar_spec jp_radar_specs = {
- .pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 },
+ .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
.radar_pattern = {
[0] = { 1, 0, 8, 32, 28, 0, 13, 508, 3076, 1, 1 },
[1] = { 1, 0, 12, 32, 28, 0, 17, 140, 240, 1, 1 },
@@ -57,6 +57,33 @@ static const struct mt7615_dfs_radar_spec jp_radar_specs = {
},
};
+static enum mt76_cipher_type
+mt7615_mac_get_cipher(int cipher)
+{
+ switch (cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ return MT_CIPHER_WEP40;
+ case WLAN_CIPHER_SUITE_WEP104:
+ return MT_CIPHER_WEP104;
+ case WLAN_CIPHER_SUITE_TKIP:
+ return MT_CIPHER_TKIP;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ return MT_CIPHER_BIP_CMAC_128;
+ case WLAN_CIPHER_SUITE_CCMP:
+ return MT_CIPHER_AES_CCMP;
+ case WLAN_CIPHER_SUITE_CCMP_256:
+ return MT_CIPHER_CCMP_256;
+ case WLAN_CIPHER_SUITE_GCMP:
+ return MT_CIPHER_GCMP;
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ return MT_CIPHER_GCMP_256;
+ case WLAN_CIPHER_SUITE_SMS4:
+ return MT_CIPHER_WAPI;
+ default:
+ return MT_CIPHER_NONE;
+ }
+}
+
static struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev,
u8 idx, bool unicast)
{
@@ -313,14 +340,27 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
u8 *data = (u8 *)rxd;
if (status->flag & RX_FLAG_DECRYPTED) {
- status->iv[0] = data[5];
- status->iv[1] = data[4];
- status->iv[2] = data[3];
- status->iv[3] = data[2];
- status->iv[4] = data[1];
- status->iv[5] = data[0];
-
- insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
+ switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) {
+ case MT_CIPHER_AES_CCMP:
+ case MT_CIPHER_CCMP_CCX:
+ case MT_CIPHER_CCMP_256:
+ insert_ccmp_hdr =
+ FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
+ fallthrough;
+ case MT_CIPHER_TKIP:
+ case MT_CIPHER_TKIP_NO_MIC:
+ case MT_CIPHER_GCMP:
+ case MT_CIPHER_GCMP_256:
+ status->iv[0] = data[5];
+ status->iv[1] = data[4];
+ status->iv[2] = data[3];
+ status->iv[3] = data[2];
+ status->iv[4] = data[1];
+ status->iv[5] = data[0];
+ break;
+ default:
+ break;
+ }
}
rxd += 4;
if ((u8 *)rxd - skb->data >= skb->len)
@@ -1062,7 +1102,7 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta,
idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx;
addr = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx);
- mt76_set(dev, addr, MT_LPON_TCR_MODE); /* TSF read */
+ mt76_rmw(dev, addr, MT_LPON_TCR_MODE, MT_LPON_TCR_READ); /* TSF read */
sta->rate_set_tsf = mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0);
sta->rate_set_tsf |= rd.rateset;
@@ -1078,7 +1118,7 @@ EXPORT_SYMBOL_GPL(mt7615_mac_set_rates);
static int
mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key,
- enum mt7615_cipher_type cipher, u16 cipher_mask,
+ enum mt76_cipher_type cipher, u16 cipher_mask,
enum set_key_cmd cmd)
{
u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx) + 30 * 4;
@@ -1118,7 +1158,7 @@ mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
static int
mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid,
- enum mt7615_cipher_type cipher, u16 cipher_mask,
+ enum mt76_cipher_type cipher, u16 cipher_mask,
int keyidx, enum set_key_cmd cmd)
{
u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx), w0, w1;
@@ -1157,7 +1197,7 @@ mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid,
static void
mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, struct mt76_wcid *wcid,
- enum mt7615_cipher_type cipher, u16 cipher_mask,
+ enum mt76_cipher_type cipher, u16 cipher_mask,
enum set_key_cmd cmd)
{
u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx);
@@ -1183,7 +1223,7 @@ int __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd)
{
- enum mt7615_cipher_type cipher;
+ enum mt76_cipher_type cipher;
u16 cipher_mask = wcid->cipher;
int err;
@@ -1235,22 +1275,20 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta,
int first_idx = 0, last_idx;
int i, idx, count;
bool fixed_rate, ack_timeout;
- bool probe, ampdu, cck = false;
+ bool ampdu, cck = false;
bool rs_idx;
u32 rate_set_tsf;
u32 final_rate, final_rate_flags, final_nss, txs;
- fixed_rate = info->status.rates[0].count;
- probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
-
txs = le32_to_cpu(txs_data[1]);
- ampdu = !fixed_rate && (txs & MT_TXS1_AMPDU);
+ ampdu = txs & MT_TXS1_AMPDU;
txs = le32_to_cpu(txs_data[3]);
count = FIELD_GET(MT_TXS3_TX_COUNT, txs);
last_idx = FIELD_GET(MT_TXS3_LAST_TX_RATE, txs);
txs = le32_to_cpu(txs_data[0]);
+ fixed_rate = txs & MT_TXS0_FIXED_RATE;
final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs);
ack_timeout = txs & MT_TXS0_ACK_TIMEOUT;
@@ -1272,7 +1310,7 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta,
first_idx = max_t(int, 0, last_idx - (count - 1) / MT7615_RATE_RETRY);
- if (fixed_rate && !probe) {
+ if (fixed_rate) {
info->status.rates[0].count = count;
i = 0;
goto out;
@@ -1391,7 +1429,7 @@ static bool mt7615_mac_add_txs_skb(struct mt7615_dev *dev,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (!mt7615_fill_txs(dev, sta, info, txs_data)) {
- ieee80211_tx_info_clear_status(info);
+ info->status.rates[0].count = 0;
info->status.rates[0].idx = -1;
}
@@ -1821,43 +1859,41 @@ mt7615_phy_update_channel(struct mt76_phy *mphy, int idx)
state->noise = -(phy->noise >> 4);
}
-static void __mt7615_update_channel(struct mt7615_dev *dev)
+static void mt7615_update_survey(struct mt7615_dev *dev)
{
struct mt76_dev *mdev = &dev->mt76;
+ ktime_t cur_time;
+
+ /* MT7615 can only update both phys simultaneously
+ * since some reisters are shared across bands.
+ */
mt7615_phy_update_channel(&mdev->phy, 0);
if (mdev->phy2)
mt7615_phy_update_channel(mdev->phy2, 1);
+ cur_time = ktime_get_boottime();
+
+ mt76_update_survey_active_time(&mdev->phy, cur_time);
+ if (mdev->phy2)
+ mt76_update_survey_active_time(mdev->phy2, cur_time);
+
/* reset obss airtime */
mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR);
}
-void mt7615_update_channel(struct mt76_dev *mdev)
+void mt7615_update_channel(struct mt76_phy *mphy)
{
- struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
+ struct mt7615_dev *dev = container_of(mphy->dev, struct mt7615_dev, mt76);
if (mt76_connac_pm_wake(&dev->mphy, &dev->pm))
return;
- __mt7615_update_channel(dev);
+ mt7615_update_survey(dev);
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
}
EXPORT_SYMBOL_GPL(mt7615_update_channel);
-static void mt7615_update_survey(struct mt7615_dev *dev)
-{
- struct mt76_dev *mdev = &dev->mt76;
- ktime_t cur_time;
-
- __mt7615_update_channel(dev);
- cur_time = ktime_get_boottime();
-
- mt76_update_survey_active_time(&mdev->phy, cur_time);
- if (mdev->phy2)
- mt76_update_survey_active_time(mdev->phy2, cur_time);
-}
-
static void
mt7615_mac_update_mib_stats(struct mt7615_phy *phy)
{
@@ -1906,15 +1942,26 @@ void mt7615_pm_wake_work(struct work_struct *work)
mphy = dev->phy.mt76;
if (!mt7615_mcu_set_drv_ctrl(dev)) {
+ struct mt76_dev *mdev = &dev->mt76;
int i;
- mt76_for_each_q_rx(&dev->mt76, i)
- napi_schedule(&dev->mt76.napi[i]);
- mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
- mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
- if (test_bit(MT76_STATE_RUNNING, &mphy->state))
+ if (mt76_is_sdio(mdev)) {
+ mt76_worker_schedule(&mdev->sdio.txrx_worker);
+ } else {
+ mt76_for_each_q_rx(mdev, i)
+ napi_schedule(&mdev->napi[i]);
+ mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
+ mt76_queue_tx_cleanup(dev, mdev->q_mcu[MT_MCUQ_WM],
+ false);
+ }
+
+ if (test_bit(MT76_STATE_RUNNING, &mphy->state)) {
+ unsigned long timeout;
+
+ timeout = mt7615_get_macwork_timeout(dev);
ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
- MT7615_WATCHDOG_TIME);
+ timeout);
+ }
}
ieee80211_wake_queues(mphy->hw);
@@ -1949,6 +1996,7 @@ void mt7615_mac_work(struct work_struct *work)
{
struct mt7615_phy *phy;
struct mt76_phy *mphy;
+ unsigned long timeout;
mphy = (struct mt76_phy *)container_of(work, struct mt76_phy,
mac_work.work);
@@ -1967,8 +2015,9 @@ void mt7615_mac_work(struct work_struct *work)
mt7615_mutex_release(phy->dev);
mt76_tx_status_check(mphy->dev, NULL, false);
- ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
- MT7615_WATCHDOG_TIME);
+
+ timeout = mt7615_get_macwork_timeout(phy->dev);
+ ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, timeout);
}
void mt7615_tx_token_put(struct mt7615_dev *dev)
@@ -2049,14 +2098,12 @@ mt7615_dfs_init_radar_specs(struct mt7615_phy *phy)
{
const struct mt7615_dfs_radar_spec *radar_specs;
struct mt7615_dev *dev = phy->dev;
- int err, i;
+ int err, i, lpn = 500;
switch (dev->mt76.region) {
case NL80211_DFS_FCC:
radar_specs = &fcc_radar_specs;
- err = mt7615_mcu_set_fcc5_lpn(dev, 8);
- if (err < 0)
- return err;
+ lpn = 8;
break;
case NL80211_DFS_ETSI:
radar_specs = &etsi_radar_specs;
@@ -2068,6 +2115,11 @@ mt7615_dfs_init_radar_specs(struct mt7615_phy *phy)
return -EINVAL;
}
+ /* avoid FCC radar detection in non-FCC region */
+ err = mt7615_mcu_set_fcc5_lpn(dev, lpn);
+ if (err < 0)
+ return err;
+
for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) {
err = mt7615_mcu_set_radar_th(dev, i,
&radar_specs->radar_pattern[i]);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
index 6bf9da040196..46f283eb8d0f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
@@ -383,48 +383,6 @@ struct mt7615_dfs_radar_spec {
struct mt7615_dfs_pattern radar_pattern[16];
};
-enum mt7615_cipher_type {
- MT_CIPHER_NONE,
- MT_CIPHER_WEP40,
- MT_CIPHER_TKIP,
- MT_CIPHER_TKIP_NO_MIC,
- MT_CIPHER_AES_CCMP,
- MT_CIPHER_WEP104,
- MT_CIPHER_BIP_CMAC_128,
- MT_CIPHER_WEP128,
- MT_CIPHER_WAPI,
- MT_CIPHER_CCMP_256 = 10,
- MT_CIPHER_GCMP,
- MT_CIPHER_GCMP_256,
-};
-
-static inline enum mt7615_cipher_type
-mt7615_mac_get_cipher(int cipher)
-{
- switch (cipher) {
- case WLAN_CIPHER_SUITE_WEP40:
- return MT_CIPHER_WEP40;
- case WLAN_CIPHER_SUITE_WEP104:
- return MT_CIPHER_WEP104;
- case WLAN_CIPHER_SUITE_TKIP:
- return MT_CIPHER_TKIP;
- case WLAN_CIPHER_SUITE_AES_CMAC:
- return MT_CIPHER_BIP_CMAC_128;
- case WLAN_CIPHER_SUITE_CCMP:
- return MT_CIPHER_AES_CCMP;
- case WLAN_CIPHER_SUITE_CCMP_256:
- return MT_CIPHER_CCMP_256;
- case WLAN_CIPHER_SUITE_GCMP:
- return MT_CIPHER_GCMP;
- case WLAN_CIPHER_SUITE_GCMP_256:
- return MT_CIPHER_GCMP_256;
- case WLAN_CIPHER_SUITE_SMS4:
- return MT_CIPHER_WAPI;
- default:
- return MT_CIPHER_NONE;
- }
-}
-
static inline struct mt7615_txp_common *
mt7615_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t)
{
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index 39733b351ac4..dada43d6d879 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -28,6 +28,7 @@ static int mt7615_start(struct ieee80211_hw *hw)
{
struct mt7615_dev *dev = mt7615_hw_dev(hw);
struct mt7615_phy *phy = mt7615_hw_phy(hw);
+ unsigned long timeout;
bool running;
int ret;
@@ -78,8 +79,8 @@ static int mt7615_start(struct ieee80211_hw *hw)
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
- ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
- MT7615_WATCHDOG_TIME);
+ timeout = mt7615_get_macwork_timeout(dev);
+ ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, timeout);
if (!running)
mt7615_mac_reset_counters(dev);
@@ -240,8 +241,6 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
}
ret = mt7615_mcu_add_dev_info(phy, vif, true);
- if (ret)
- goto out;
out:
mt7615_mutex_release(dev);
@@ -352,10 +351,12 @@ out:
mt7615_mutex_release(dev);
mt76_worker_schedule(&dev->mt76.tx_worker);
- if (!mt76_testmode_enabled(phy->mt76))
+ if (!mt76_testmode_enabled(phy->mt76)) {
+ unsigned long timeout = mt7615_get_macwork_timeout(dev);
+
ieee80211_queue_delayed_work(phy->mt76->hw,
- &phy->mt76->mac_work,
- MT7615_WATCHDOG_TIME);
+ &phy->mt76->mac_work, timeout);
+ }
return ret;
}
@@ -695,7 +696,7 @@ static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw,
msta->n_rates = i;
if (mt76_connac_pm_ref(phy->mt76, &dev->pm)) {
mt7615_mac_set_rates(phy, msta, NULL, msta->rates);
- mt76_connac_pm_unref(&dev->pm);
+ mt76_connac_pm_unref(phy->mt76, &dev->pm);
}
spin_unlock_bh(&dev->mt76.lock);
}
@@ -711,7 +712,7 @@ void mt7615_tx_worker(struct mt76_worker *w)
}
mt76_tx_worker_run(&dev->mt76);
- mt76_connac_pm_unref(&dev->pm);
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
}
static void mt7615_tx(struct ieee80211_hw *hw,
@@ -741,7 +742,7 @@ static void mt7615_tx(struct ieee80211_hw *hw,
if (mt76_connac_pm_ref(mphy, &dev->pm)) {
mt76_tx(mphy, control->sta, wcid, skb);
- mt76_connac_pm_unref(&dev->pm);
+ mt76_connac_pm_unref(mphy, &dev->pm);
return;
}
@@ -881,7 +882,8 @@ mt7615_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
mt7615_mutex_acquire(dev);
- mt76_set(dev, reg, MT_LPON_TCR_MODE); /* TSF read */
+ /* TSF read */
+ mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_READ);
tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0);
tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1);
@@ -911,7 +913,33 @@ mt7615_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mt76_wr(dev, MT_LPON_UTTR0, tsf.t32[0]);
mt76_wr(dev, MT_LPON_UTTR1, tsf.t32[1]);
/* TSF software overwrite */
- mt76_set(dev, reg, MT_LPON_TCR_WRITE);
+ mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_WRITE);
+
+ mt7615_mutex_release(dev);
+}
+
+static void
+mt7615_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ s64 timestamp)
+{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct mt7615_dev *dev = mt7615_hw_dev(hw);
+ union {
+ u64 t64;
+ u32 t32[2];
+ } tsf = { .t64 = timestamp, };
+ u16 idx = mvif->mt76.omac_idx;
+ u32 reg;
+
+ idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx;
+ reg = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx);
+
+ mt7615_mutex_acquire(dev);
+
+ mt76_wr(dev, MT_LPON_UTTR0, tsf.t32[0]);
+ mt76_wr(dev, MT_LPON_UTTR1, tsf.t32[1]);
+ /* TSF software adjust*/
+ mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_ADJUST);
mt7615_mutex_release(dev);
}
@@ -1162,7 +1190,7 @@ static void mt7615_sta_set_decap_offload(struct ieee80211_hw *hw,
else
clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags);
- mt7615_mcu_sta_update_hdr_trans(dev, vif, sta);
+ mt7615_mcu_set_sta_decap_offload(dev, vif, sta);
}
#ifdef CONFIG_PM
@@ -1200,6 +1228,7 @@ static int mt7615_resume(struct ieee80211_hw *hw)
{
struct mt7615_phy *phy = mt7615_hw_phy(hw);
struct mt7615_dev *dev = mt7615_hw_dev(hw);
+ unsigned long timeout;
bool running;
mt7615_mutex_acquire(dev);
@@ -1223,8 +1252,8 @@ static int mt7615_resume(struct ieee80211_hw *hw)
mt76_connac_mcu_set_suspend_iter,
phy->mt76);
- ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
- MT7615_WATCHDOG_TIME);
+ timeout = mt7615_get_macwork_timeout(dev);
+ ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, timeout);
mt7615_mutex_release(dev);
@@ -1278,6 +1307,7 @@ const struct ieee80211_ops mt7615_ops = {
.get_stats = mt7615_get_stats,
.get_tsf = mt7615_get_tsf,
.set_tsf = mt7615_set_tsf,
+ .offset_tsf = mt7615_offset_tsf,
.get_survey = mt76_get_survey,
.get_antenna = mt76_get_antenna,
.set_antenna = mt7615_set_antenna,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index aa42af9ebfd6..f8a09692d3e4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -411,6 +411,9 @@ mt7615_mcu_rx_csa_notify(struct mt7615_dev *dev, struct sk_buff *skb)
c = (struct mt7615_mcu_csa_notify *)skb->data;
+ if (c->omac_idx > EXT_BSSID_MAX)
+ return;
+
if (ext_phy && ext_phy->omac_mask & BIT_ULL(c->omac_idx))
mphy = dev->mt76.phy2;
@@ -427,6 +430,10 @@ mt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb)
r = (struct mt7615_mcu_rdd_report *)skb->data;
+ if (!dev->radar_pattern.n_pulses && !r->long_detected &&
+ !r->constant_prf_detected && !r->staggered_prf_detected)
+ return;
+
if (r->band_idx && dev->mt76.phy2)
mphy = dev->mt76.phy2;
@@ -1021,9 +1028,10 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif,
if (IS_ERR(sskb))
return PTR_ERR(sskb);
- mt76_connac_mcu_sta_basic_tlv(sskb, vif, sta, enable);
+ mt76_connac_mcu_sta_basic_tlv(sskb, vif, sta, enable, true);
if (enable && sta)
- mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0);
+ mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0,
+ MT76_STA_INFO_STATE_ASSOC);
wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
WTBL_RESET_AND_SET, NULL,
@@ -1037,8 +1045,8 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif,
if (sta)
mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, wskb, sta,
NULL, wtbl_hdr);
- mt76_connac_mcu_wtbl_hdr_trans_tlv(wskb, &msta->wcid, NULL,
- wtbl_hdr);
+ mt76_connac_mcu_wtbl_hdr_trans_tlv(wskb, vif, &msta->wcid,
+ NULL, wtbl_hdr);
}
cmd = enable ? MCU_EXT_CMD_WTBL_UPDATE : MCU_EXT_CMD_STA_REC_UPDATE;
@@ -1058,6 +1066,26 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif,
return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
}
+static int
+mt7615_mcu_wtbl_update_hdr_trans(struct mt7615_dev *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+ struct wtbl_req_hdr *wtbl_hdr;
+ struct sk_buff *skb = NULL;
+
+ wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
+ WTBL_SET, NULL, &skb);
+ if (IS_ERR(wtbl_hdr))
+ return PTR_ERR(wtbl_hdr);
+
+ mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, &msta->wcid, NULL,
+ wtbl_hdr);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_WTBL_UPDATE,
+ true);
+}
+
static const struct mt7615_mcu_ops wtbl_update_ops = {
.add_beacon_offload = mt7615_mcu_add_beacon_offload,
.set_pm_state = mt7615_mcu_ctrl_pm_state,
@@ -1068,6 +1096,7 @@ static const struct mt7615_mcu_ops wtbl_update_ops = {
.sta_add = mt7615_mcu_wtbl_sta_add,
.set_drv_ctrl = mt7615_mcu_drv_pmctrl,
.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
+ .set_sta_decap_offload = mt7615_mcu_wtbl_update_hdr_trans,
};
static int
@@ -1120,18 +1149,21 @@ mt7615_mcu_sta_rx_ba(struct mt7615_dev *dev,
static int
__mt7615_mcu_add_sta(struct mt76_phy *phy, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, bool enable, int cmd)
+ struct ieee80211_sta *sta, bool enable, int cmd,
+ bool offload_fw)
{
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
struct mt76_sta_cmd_info info = {
.sta = sta,
.vif = vif,
+ .offload_fw = offload_fw,
.enable = enable,
+ .newly = true,
.cmd = cmd,
};
info.wcid = sta ? (struct mt76_wcid *)sta->drv_priv : &mvif->sta.wcid;
- return mt76_connac_mcu_add_sta_cmd(phy, &info);
+ return mt76_connac_mcu_sta_cmd(phy, &info);
}
static int
@@ -1139,7 +1171,19 @@ mt7615_mcu_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enable)
{
return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable,
- MCU_EXT_CMD_STA_REC_UPDATE);
+ MCU_EXT_CMD_STA_REC_UPDATE, false);
+}
+
+static int
+mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+
+ return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76,
+ vif, &msta->wcid,
+ MCU_EXT_CMD_STA_REC_UPDATE);
}
static const struct mt7615_mcu_ops sta_update_ops = {
@@ -1152,27 +1196,9 @@ static const struct mt7615_mcu_ops sta_update_ops = {
.sta_add = mt7615_mcu_add_sta,
.set_drv_ctrl = mt7615_mcu_drv_pmctrl,
.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
+ .set_sta_decap_offload = mt7615_mcu_sta_update_hdr_trans,
};
-int mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
- struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
- struct wtbl_req_hdr *wtbl_hdr;
- struct sk_buff *skb = NULL;
-
- wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
- WTBL_SET, NULL, &skb);
- if (IS_ERR(wtbl_hdr))
- return PTR_ERR(wtbl_hdr);
-
- mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, &msta->wcid, NULL, wtbl_hdr);
-
- return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_WTBL_UPDATE,
- true);
-}
-
static int
mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
{
@@ -1280,7 +1306,7 @@ mt7615_mcu_uni_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enable)
{
return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable,
- MCU_UNI_CMD_STA_REC_UPDATE);
+ MCU_UNI_CMD_STA_REC_UPDATE, true);
}
static int
@@ -1338,6 +1364,18 @@ mt7615_mcu_uni_rx_ba(struct mt7615_dev *dev,
MCU_UNI_CMD_STA_REC_UPDATE, true);
}
+static int
+mt7615_mcu_sta_uni_update_hdr_trans(struct mt7615_dev *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+
+ return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76,
+ vif, &msta->wcid,
+ MCU_UNI_CMD_STA_REC_UPDATE);
+}
+
static const struct mt7615_mcu_ops uni_update_ops = {
.add_beacon_offload = mt7615_mcu_uni_add_beacon_offload,
.set_pm_state = mt7615_mcu_uni_ctrl_pm_state,
@@ -1348,6 +1386,7 @@ static const struct mt7615_mcu_ops uni_update_ops = {
.sta_add = mt7615_mcu_uni_add_sta,
.set_drv_ctrl = mt7615_mcu_lp_drv_pmctrl,
.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
+ .set_sta_decap_offload = mt7615_mcu_sta_uni_update_hdr_trans,
};
int mt7615_mcu_restart(struct mt76_dev *dev)
@@ -2322,14 +2361,12 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd)
return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
}
-int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index)
+int mt7615_mcu_get_temperature(struct mt7615_dev *dev)
{
struct {
u8 action;
u8 rsv[3];
- } req = {
- .action = index,
- };
+ } req = {};
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_GET_TEMP, &req,
sizeof(req), true);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
index 202ea235415e..71719c787511 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
@@ -229,7 +229,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
GFP_KERNEL);
if (!bus_ops) {
ret = -ENOMEM;
- goto error;
+ goto err_free_dev;
}
bus_ops->rr = mt7615_rr;
@@ -242,17 +242,20 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
ret = devm_request_irq(mdev->dev, irq, mt7615_irq_handler,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (ret)
- goto error;
+ goto err_free_dev;
if (is_mt7663(mdev))
mt76_wr(dev, MT_PCIE_IRQ_ENABLE, 1);
ret = mt7615_register_device(dev);
if (ret)
- goto error;
+ goto err_free_irq;
return 0;
-error:
+
+err_free_irq:
+ devm_free_irq(pdev, irq, dev);
+err_free_dev:
mt76_free_device(&dev->mt76);
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index 989f05ed4377..d0c64a9b09cf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -20,7 +20,6 @@
MT7615_MAX_INTERFACES)
#define MT7615_PM_TIMEOUT (HZ / 12)
-#define MT7615_WATCHDOG_TIME (HZ / 10)
#define MT7615_HW_SCAN_TIMEOUT (HZ / 10)
#define MT7615_RESET_TIMEOUT (30 * HZ)
#define MT7615_RATE_RETRY 2
@@ -202,6 +201,7 @@ struct mt7615_phy {
#define mt7615_mcu_set_pm(dev, ...) (dev)->mcu_ops->set_pm_state((dev), __VA_ARGS__)
#define mt7615_mcu_set_drv_ctrl(dev) (dev)->mcu_ops->set_drv_ctrl((dev))
#define mt7615_mcu_set_fw_ctrl(dev) (dev)->mcu_ops->set_fw_ctrl((dev))
+#define mt7615_mcu_set_sta_decap_offload(dev, ...) (dev)->mcu_ops->set_sta_decap_offload((dev), __VA_ARGS__)
struct mt7615_mcu_ops {
int (*add_tx_ba)(struct mt7615_dev *dev,
struct ieee80211_ampdu_params *params,
@@ -221,6 +221,9 @@ struct mt7615_mcu_ops {
int (*set_pm_state)(struct mt7615_dev *dev, int band, int state);
int (*set_drv_ctrl)(struct mt7615_dev *dev);
int (*set_fw_ctrl)(struct mt7615_dev *dev);
+ int (*set_sta_decap_offload)(struct mt7615_dev *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
};
struct mt7615_dev {
@@ -356,6 +359,7 @@ static inline int mt7622_wmac_init(struct mt7615_dev *dev)
}
#endif
+int mt7615_thermal_init(struct mt7615_dev *dev);
int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
int irq, const u32 *map);
u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr);
@@ -456,6 +460,12 @@ static inline u32 mt7615_tx_mcu_int_mask(struct mt7615_dev *dev)
return MT_INT_TX_DONE(dev->mt76.q_mcu[MT_MCUQ_WM]->hw_idx);
}
+static inline unsigned long
+mt7615_get_macwork_timeout(struct mt7615_dev *dev)
+{
+ return dev->pm.enable ? HZ / 3 : HZ / 10;
+}
+
void mt7615_dma_reset(struct mt7615_dev *dev);
void mt7615_scan_work(struct work_struct *work);
void mt7615_roc_work(struct work_struct *work);
@@ -466,7 +476,7 @@ int mt7615_set_channel(struct mt7615_phy *phy);
void mt7615_init_work(struct mt7615_dev *dev);
int mt7615_mcu_restart(struct mt76_dev *dev);
-void mt7615_update_channel(struct mt76_dev *mdev);
+void mt7615_update_channel(struct mt76_phy *mphy);
bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask);
void mt7615_mac_reset_counters(struct mt7615_dev *dev);
void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy);
@@ -494,7 +504,7 @@ u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg);
int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val);
int mt7615_mcu_set_dbdc(struct mt7615_dev *dev);
int mt7615_mcu_set_eeprom(struct mt7615_dev *dev);
-int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index);
+int mt7615_mcu_get_temperature(struct mt7615_dev *dev);
int mt7615_mcu_set_tx_power(struct mt7615_phy *phy);
void mt7615_mcu_exit(struct mt7615_dev *dev);
void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb,
@@ -518,9 +528,6 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
void mt7615_mac_work(struct work_struct *work);
void mt7615_txp_skb_unmap(struct mt76_dev *dev,
struct mt76_txwi_cache *txwi);
-int mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
int mt7615_mcu_set_rx_hdr_trans_blacklist(struct mt7615_dev *dev);
int mt7615_mcu_set_fcc5_lpn(struct mt7615_dev *dev, int val);
int mt7615_mcu_set_pulse_th(struct mt7615_dev *dev,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
index ec8ec1a2033f..a2465b49ecd0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
@@ -98,7 +98,7 @@ mt7615_led_set_config(struct led_classdev *led_cdev,
addr = mt7615_reg_map(dev, MT_LED_CTRL);
mt76_wr(dev, addr, val);
- mt76_connac_pm_unref(&dev->pm);
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
}
static int
@@ -147,8 +147,12 @@ int mt7615_register_device(struct mt7615_dev *dev)
if (ret)
return ret;
- ret = mt76_register_device(&dev->mt76, true, mt7615_rates,
- ARRAY_SIZE(mt7615_rates));
+ ret = mt76_register_device(&dev->mt76, true, mt76_rates,
+ ARRAY_SIZE(mt76_rates));
+ if (ret)
+ return ret;
+
+ ret = mt7615_thermal_init(dev);
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c
index d7cbef752f9f..da87c02a73eb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c
@@ -131,20 +131,21 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct mt76_tx_info *tx_info)
{
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
- struct mt7615_sta *msta = container_of(wcid, struct mt7615_sta, wcid);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
struct ieee80211_key_conf *key = info->control.hw_key;
int pid, id;
u8 *txwi = (u8 *)txwi_ptr;
struct mt76_txwi_cache *t;
+ struct mt7615_sta *msta;
void *txp;
+ msta = wcid ? container_of(wcid, struct mt7615_sta, wcid) : NULL;
if (!wcid)
wcid = &dev->mt76.global_wcid;
pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
- if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
+ if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && msta) {
struct mt7615_phy *phy = &dev->phy;
if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && mdev->phy2)
@@ -267,6 +268,7 @@ void mt7615_mac_reset_work(struct work_struct *work)
struct mt7615_phy *phy2;
struct mt76_phy *ext_phy;
struct mt7615_dev *dev;
+ unsigned long timeout;
dev = container_of(work, struct mt7615_dev, reset_work);
ext_phy = dev->mt76.phy2;
@@ -344,11 +346,11 @@ void mt7615_mac_reset_work(struct work_struct *work)
mt7615_mutex_release(dev);
+ timeout = mt7615_get_macwork_timeout(dev);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
- MT7615_WATCHDOG_TIME);
+ timeout);
if (phy2)
ieee80211_queue_delayed_work(ext_phy->hw,
- &phy2->mt76->mac_work,
- MT7615_WATCHDOG_TIME);
+ &phy2->mt76->mac_work, timeout);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
index 63c081bb04d0..6712ad9faeaa 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
@@ -463,7 +463,9 @@ enum mt7615_reg_base {
#define MT_LPON_TCR0(_n) MT_LPON(0x010 + ((_n) * 4))
#define MT_LPON_TCR2(_n) MT_LPON(0x0f8 + ((_n) - 2) * 4)
#define MT_LPON_TCR_MODE GENMASK(1, 0)
+#define MT_LPON_TCR_READ GENMASK(1, 0)
#define MT_LPON_TCR_WRITE BIT(0)
+#define MT_LPON_TCR_ADJUST BIT(1)
#define MT_LPON_UTTR0 MT_LPON(0x018)
#define MT_LPON_UTTR1 MT_LPON(0x01c)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h
index 05180971de84..03877d89e152 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: ISC
+/* SPDX-License-Identifier: ISC */
/* Copyright (C) 2020 MediaTek Inc.
*
* Author: Sean Wang <sean.wang@mediatek.com>
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
index d1be78b0711c..45c1cd3b9f49 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
@@ -55,6 +55,7 @@ static int __mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev)
{
struct sdio_func *func = dev->mt76.sdio.func;
struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
u32 status;
int ret;
@@ -66,37 +67,45 @@ static int __mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev)
status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000);
if (ret < 0) {
dev_err(dev->mt76.dev, "Cannot get ownership from device");
- set_bit(MT76_STATE_PM, &mphy->state);
- sdio_release_host(func);
+ } else {
+ clear_bit(MT76_STATE_PM, &mphy->state);
- return ret;
+ pm->stats.last_wake_event = jiffies;
+ pm->stats.doze_time += pm->stats.last_wake_event -
+ pm->stats.last_doze_event;
}
-
sdio_release_host(func);
- dev->pm.last_activity = jiffies;
- return 0;
+ return ret;
}
static int mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
+ int ret = 0;
- if (test_and_clear_bit(MT76_STATE_PM, &mphy->state))
- return __mt7663s_mcu_drv_pmctrl(dev);
+ mutex_lock(&dev->pm.mutex);
- return 0;
+ if (test_bit(MT76_STATE_PM, &mphy->state))
+ ret = __mt7663s_mcu_drv_pmctrl(dev);
+
+ mutex_unlock(&dev->pm.mutex);
+
+ return ret;
}
static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev)
{
struct sdio_func *func = dev->mt76.sdio.func;
struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
+ int ret = 0;
u32 status;
- int ret;
- if (test_and_set_bit(MT76_STATE_PM, &mphy->state))
- return 0;
+ mutex_lock(&pm->mutex);
+
+ if (mt76_connac_skip_fw_pmctrl(mphy, pm))
+ goto out;
sdio_claim_host(func);
@@ -107,9 +116,15 @@ static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev)
if (ret < 0) {
dev_err(dev->mt76.dev, "Cannot set ownership to device");
clear_bit(MT76_STATE_PM, &mphy->state);
+ } else {
+ pm->stats.last_doze_event = jiffies;
+ pm->stats.awake_time += pm->stats.last_doze_event -
+ pm->stats.last_wake_event;
}
sdio_release_host(func);
+out:
+ mutex_unlock(&pm->mutex);
return ret;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
index 4393dd21ebbb..04f4c89b7499 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
@@ -283,9 +283,15 @@ void mt7663s_txrx_worker(struct mt76_worker *w)
{
struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
txrx_worker);
- struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
+ struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio);
+ struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
int i, nframes, ret;
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ queue_work(mdev->wq, &dev->pm.wake_work);
+ return;
+ }
+
/* disable interrupt */
sdio_claim_host(sdio->func);
sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
@@ -295,16 +301,16 @@ void mt7663s_txrx_worker(struct mt76_worker *w)
/* tx */
for (i = 0; i <= MT_TXQ_PSD; i++) {
- ret = mt7663s_tx_run_queue(dev, dev->phy.q_tx[i]);
+ ret = mt7663s_tx_run_queue(mdev, mdev->phy.q_tx[i]);
if (ret > 0)
nframes += ret;
}
- ret = mt7663s_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]);
+ ret = mt7663s_tx_run_queue(mdev, mdev->q_mcu[MT_MCUQ_WM]);
if (ret > 0)
nframes += ret;
/* rx */
- ret = mt7663s_rx_handler(dev);
+ ret = mt7663s_rx_handler(mdev);
if (ret > 0)
nframes += ret;
} while (nframes > 0);
@@ -312,6 +318,8 @@ void mt7663s_txrx_worker(struct mt76_worker *w)
/* enable interrupt */
sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
sdio_release_host(sdio->func);
+
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
}
void mt7663s_sdio_irq(struct sdio_func *func)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c
index be9a69fe1b38..f13d1b418742 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c
@@ -31,7 +31,6 @@ int mt7622_wmac_init(struct mt7615_dev *dev)
static int mt7622_wmac_probe(struct platform_device *pdev)
{
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
void __iomem *mem_base;
int irq;
@@ -39,7 +38,7 @@ static int mt7622_wmac_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- mem_base = devm_ioremap_resource(&pdev->dev, res);
+ mem_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(mem_base))
return PTR_ERR(mem_base);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
index f8d3673c2cae..996d48cca18a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
@@ -123,7 +123,7 @@ static int mt7663_usb_sdio_set_rates(struct mt7615_dev *dev,
idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx;
addr = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx);
- mt76_set(dev, addr, MT_LPON_TCR_MODE); /* TSF read */
+ mt76_rmw(dev, addr, MT_LPON_TCR_MODE, MT_LPON_TCR_READ); /* TSF read */
val = mt76_rr(dev, MT_LPON_UTTR0);
sta->rate_set_tsf = (val & ~BIT(0)) | rate->rateset;
@@ -191,14 +191,15 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info)
{
- struct mt7615_sta *msta = container_of(wcid, struct mt7615_sta, wcid);
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
struct sk_buff *skb = tx_info->skb;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct mt7615_sta *msta;
int pad;
+ msta = wcid ? container_of(wcid, struct mt7615_sta, wcid) : NULL;
if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) &&
- !msta->rate_probe) {
+ msta && !msta->rate_probe) {
/* request to configure sampling rate */
spin_lock_bh(&dev->mt76.lock);
mt7615_mac_set_rates(&dev->phy, msta, &info->control.rates[0],
@@ -323,8 +324,8 @@ int mt7663_usb_sdio_register_device(struct mt7615_dev *dev)
hw->max_tx_fragments = 1;
}
- err = mt76_register_device(&dev->mt76, true, mt7615_rates,
- ARRAY_SIZE(mt7615_rates));
+ err = mt76_register_device(&dev->mt76, true, mt76_rates,
+ ARRAY_SIZE(mt76_rates));
if (err < 0)
return err;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
index 6c889b90fd12..f49d97d0a1c5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
@@ -7,12 +7,13 @@
#include "mt76.h"
#define MT76_CONNAC_SCAN_IE_LEN 600
-#define MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL 10
+#define MT76_CONNAC_MAX_NUM_SCHED_SCAN_INTERVAL 10
+#define MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL U16_MAX
#define MT76_CONNAC_MAX_SCHED_SCAN_SSID 10
#define MT76_CONNAC_MAX_SCAN_MATCH 16
#define MT76_CONNAC_COREDUMP_TIMEOUT (HZ / 20)
-#define MT76_CONNAC_COREDUMP_SZ (128 * 1024)
+#define MT76_CONNAC_COREDUMP_SZ (1300 * 1024)
enum {
CMD_CBW_20MHZ = IEEE80211_STA_RX_BW_20,
@@ -45,6 +46,8 @@ enum {
struct mt76_connac_pm {
bool enable;
+ bool ds_enable;
+ bool suspended;
spinlock_t txq_lock;
struct {
@@ -116,19 +119,27 @@ out:
}
static inline void
-mt76_connac_pm_unref(struct mt76_connac_pm *pm)
+mt76_connac_pm_unref(struct mt76_phy *phy, struct mt76_connac_pm *pm)
{
spin_lock_bh(&pm->wake.lock);
- pm->wake.count--;
+
pm->last_activity = jiffies;
+ if (--pm->wake.count == 0 &&
+ test_bit(MT76_STATE_MCU_RUNNING, &phy->state))
+ mt76_connac_power_save_sched(phy, pm);
+
spin_unlock_bh(&pm->wake.lock);
}
static inline bool
mt76_connac_skip_fw_pmctrl(struct mt76_phy *phy, struct mt76_connac_pm *pm)
{
+ struct mt76_dev *dev = phy->dev;
bool ret;
+ if (dev->token_count)
+ return true;
+
spin_lock_bh(&pm->wake.lock);
ret = pm->wake.count || test_and_set_bit(MT76_STATE_PM, &phy->state);
spin_unlock_bh(&pm->wake.lock);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
index 6f180c92d413..af43bcb54578 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
@@ -10,13 +10,16 @@ int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm)
if (!pm->enable)
return 0;
- if (!mt76_is_mmio(dev))
+ if (mt76_is_usb(dev))
return 0;
cancel_delayed_work_sync(&pm->ps_work);
if (!test_bit(MT76_STATE_PM, &phy->state))
return 0;
+ if (pm->suspended)
+ return 0;
+
queue_work(dev->wq, &pm->wake_work);
if (!wait_event_timeout(pm->wait,
!test_bit(MT76_STATE_PM, &phy->state),
@@ -34,12 +37,15 @@ void mt76_connac_power_save_sched(struct mt76_phy *phy,
{
struct mt76_dev *dev = phy->dev;
- if (!mt76_is_mmio(dev))
+ if (mt76_is_usb(dev))
return;
if (!pm->enable)
return;
+ if (pm->suspended)
+ return;
+
pm->last_activity = jiffies;
if (!test_bit(MT76_STATE_PM, &phy->state)) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index 619561606f96..5c3a81e5f559 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -304,7 +304,7 @@ EXPORT_SYMBOL_GPL(mt76_connac_mcu_alloc_wtbl_req);
void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- bool enable)
+ bool enable, bool newly)
{
struct sta_rec_basic *basic;
struct tlv *tlv;
@@ -316,7 +316,8 @@ void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb,
basic->extra_info = cpu_to_le16(EXTRA_INFO_VER);
if (enable) {
- basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW);
+ if (newly)
+ basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW);
basic->conn_state = CONN_STATE_PORT_SECURE;
} else {
basic->conn_state = CONN_STATE_DISCONNECT;
@@ -393,6 +394,7 @@ mt76_connac_mcu_sta_uapsd(struct sk_buff *skb, struct ieee80211_vif *vif,
}
void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb,
+ struct ieee80211_vif *vif,
struct mt76_wcid *wcid,
void *sta_wtbl, void *wtbl_tlv)
{
@@ -404,9 +406,46 @@ void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb,
wtbl_tlv, sta_wtbl);
htr = (struct wtbl_hdr_trans *)tlv;
htr->no_rx_trans = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags);
+
+ if (vif->type == NL80211_IFTYPE_STATION)
+ htr->to_ds = true;
+ else
+ htr->from_ds = true;
+
+ if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) {
+ htr->to_ds = true;
+ htr->from_ds = true;
+ }
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_hdr_trans_tlv);
+int mt76_connac_mcu_sta_update_hdr_trans(struct mt76_dev *dev,
+ struct ieee80211_vif *vif,
+ struct mt76_wcid *wcid, int cmd)
+{
+ struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
+ struct wtbl_req_hdr *wtbl_hdr;
+ struct tlv *sta_wtbl;
+ struct sk_buff *skb;
+
+ skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,
+ sizeof(struct tlv));
+
+ wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(dev, wcid, WTBL_SET,
+ sta_wtbl, &skb);
+ if (IS_ERR(wtbl_hdr))
+ return PTR_ERR(wtbl_hdr);
+
+ mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, sta_wtbl, wtbl_hdr);
+
+ return mt76_mcu_skb_send_msg(dev, skb, cmd, true);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_update_hdr_trans);
+
void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev,
struct sk_buff *skb,
struct ieee80211_vif *vif,
@@ -671,7 +710,7 @@ mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif,
void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb,
struct ieee80211_sta *sta,
struct ieee80211_vif *vif,
- u8 rcpi)
+ u8 rcpi, u8 sta_state)
{
struct cfg80211_chan_def *chandef = &mphy->chandef;
enum nl80211_band band = chandef->chan->band;
@@ -736,7 +775,7 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb,
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_STATE, sizeof(*state));
state = (struct sta_rec_state *)tlv;
- state->state = 2;
+ state->state = sta_state;
if (sta->vht_cap.vht_supported) {
state->vht_opmode = sta->bandwidth;
@@ -828,8 +867,8 @@ void mt76_connac_mcu_wtbl_ht_tlv(struct mt76_dev *dev, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_ht_tlv);
-int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy,
- struct mt76_sta_cmd_info *info)
+int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy,
+ struct mt76_sta_cmd_info *info)
{
struct mt76_vif *mvif = (struct mt76_vif *)info->vif->drv_priv;
struct mt76_dev *dev = phy->dev;
@@ -841,10 +880,13 @@ int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy,
if (IS_ERR(skb))
return PTR_ERR(skb);
- mt76_connac_mcu_sta_basic_tlv(skb, info->vif, info->sta, info->enable);
- if (info->enable && info->sta)
- mt76_connac_mcu_sta_tlv(phy, skb, info->sta, info->vif,
- info->rcpi);
+ if (info->sta || !info->offload_fw)
+ mt76_connac_mcu_sta_basic_tlv(skb, info->vif, info->sta,
+ info->enable, info->newly);
+ if (info->sta && info->enable)
+ mt76_connac_mcu_sta_tlv(phy, skb, info->sta,
+ info->vif, info->rcpi,
+ info->state);
sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,
sizeof(struct tlv));
@@ -859,6 +901,8 @@ int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy,
mt76_connac_mcu_wtbl_generic_tlv(dev, skb, info->vif,
info->sta, sta_wtbl,
wtbl_hdr);
+ mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, info->vif, info->wcid,
+ sta_wtbl, wtbl_hdr);
if (info->sta)
mt76_connac_mcu_wtbl_ht_tlv(dev, skb, info->sta,
sta_wtbl, wtbl_hdr);
@@ -866,7 +910,7 @@ int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy,
return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true);
}
-EXPORT_SYMBOL_GPL(mt76_connac_mcu_add_sta_cmd);
+EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_cmd);
void mt76_connac_mcu_wtbl_ba_tlv(struct mt76_dev *dev, struct sk_buff *skb,
struct ieee80211_ampdu_params *params,
@@ -895,8 +939,10 @@ void mt76_connac_mcu_wtbl_ba_tlv(struct mt76_dev *dev, struct sk_buff *skb,
ba->rst_ba_sb = 1;
}
- if (is_mt7921(dev))
+ if (is_mt7921(dev)) {
+ ba->ba_winsize = enable ? cpu_to_le16(params->buf_size) : 0;
return;
+ }
if (enable && tx) {
u8 ba_range[] = { 4, 8, 12, 24, 36, 48, 54, 64 };
@@ -1271,6 +1317,7 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
u8 pad[3];
} __packed hdr;
struct bss_info_uni_he he;
+ struct bss_info_uni_bss_color bss_color;
} he_req = {
.hdr = {
.bss_idx = mvif->idx,
@@ -1279,8 +1326,21 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
.tag = cpu_to_le16(UNI_BSS_INFO_HE_BASIC),
.len = cpu_to_le16(sizeof(struct bss_info_uni_he)),
},
+ .bss_color = {
+ .tag = cpu_to_le16(UNI_BSS_INFO_BSS_COLOR),
+ .len = cpu_to_le16(sizeof(struct bss_info_uni_bss_color)),
+ .enable = 0,
+ .bss_color = 0,
+ },
};
+ if (enable) {
+ he_req.bss_color.enable =
+ vif->bss_conf.he_bss_color.enabled;
+ he_req.bss_color.bss_color =
+ vif->bss_conf.he_bss_color.color;
+ }
+
mt76_connac_mcu_uni_bss_he_tlv(phy, vif,
(struct tlv *)&he_req.he);
err = mt76_mcu_send_msg(mdev, MCU_UNI_CMD_BSS_INFO_UPDATE,
@@ -1463,14 +1523,16 @@ int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy,
req->version = 1;
req->seq_num = mvif->scan_seq_num | ext_phy << 7;
- if (is_mt7663(phy->dev) &&
- (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) {
- get_random_mask_addr(req->mt7663.random_mac, sreq->mac_addr,
- sreq->mac_addr_mask);
+ if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
+ u8 *addr = is_mt7663(phy->dev) ? req->mt7663.random_mac
+ : req->mt7921.random_mac;
+
req->scan_func = 1;
- } else if (is_mt7921(phy->dev)) {
- req->mt7921.bss_idx = mvif->idx;
+ get_random_mask_addr(addr, sreq->mac_addr,
+ sreq->mac_addr_mask);
}
+ if (is_mt7921(phy->dev))
+ req->mt7921.bss_idx = mvif->idx;
req->ssids_num = sreq->n_ssids;
for (i = 0; i < req->ssids_num; i++) {
@@ -1556,6 +1618,26 @@ int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable)
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_deep_sleep);
+int mt76_connac_sta_state_dp(struct mt76_dev *dev,
+ enum ieee80211_sta_state old_state,
+ enum ieee80211_sta_state new_state)
+{
+ if ((old_state == IEEE80211_STA_ASSOC &&
+ new_state == IEEE80211_STA_AUTHORIZED) ||
+ (old_state == IEEE80211_STA_NONE &&
+ new_state == IEEE80211_STA_NOTEXIST))
+ mt76_connac_mcu_set_deep_sleep(dev, true);
+
+ if ((old_state == IEEE80211_STA_NOTEXIST &&
+ new_state == IEEE80211_STA_NONE) ||
+ (old_state == IEEE80211_STA_AUTHORIZED &&
+ new_state == IEEE80211_STA_ASSOC))
+ mt76_connac_mcu_set_deep_sleep(dev, false);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sta_state_dp);
+
void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
struct mt76_connac_coredump *coredump)
{
@@ -1570,6 +1652,60 @@ void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_coredump_event);
+int mt76_connac_mcu_get_nic_capability(struct mt76_phy *phy)
+{
+ struct mt76_connac_cap_hdr {
+ __le16 n_element;
+ u8 rsv[2];
+ } __packed * hdr;
+ struct sk_buff *skb;
+ int ret, i;
+
+ ret = mt76_mcu_send_and_get_msg(phy->dev, MCU_CMD_GET_NIC_CAPAB, NULL,
+ 0, true, &skb);
+ if (ret)
+ return ret;
+
+ hdr = (struct mt76_connac_cap_hdr *)skb->data;
+ if (skb->len < sizeof(*hdr)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ skb_pull(skb, sizeof(*hdr));
+
+ for (i = 0; i < le16_to_cpu(hdr->n_element); i++) {
+ struct tlv_hdr {
+ __le32 type;
+ __le32 len;
+ } __packed * tlv = (struct tlv_hdr *)skb->data;
+ int len;
+
+ if (skb->len < sizeof(*tlv))
+ break;
+
+ skb_pull(skb, sizeof(*tlv));
+
+ len = le32_to_cpu(tlv->len);
+ if (skb->len < len)
+ break;
+
+ switch (le32_to_cpu(tlv->type)) {
+ case MT_NIC_CAP_6G:
+ phy->cap.has_6ghz = skb->data[0];
+ break;
+ default:
+ break;
+ }
+ skb_pull(skb, len);
+ }
+out:
+ dev_kfree_skb(skb);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mt76_connac_mcu_get_nic_capability);
+
static void
mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku,
struct mt76_power_limits *limits,
@@ -1632,12 +1768,15 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
142, 144, 149, 151, 153, 155, 157,
159, 161, 165
};
+ int i, n_chan, batch_size, idx = 0, tx_power, last_ch;
struct mt76_connac_sku_tlv sku_tlbv;
- int i, n_chan, batch_size, idx = 0;
struct mt76_power_limits limits;
const u8 *ch_list;
sku_len = is_mt7921(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92;
+ tx_power = 2 * phy->hw->conf.power_level;
+ if (!tx_power)
+ tx_power = 127;
if (band == NL80211_BAND_2GHZ) {
n_chan = ARRAY_SIZE(chan_list_2ghz);
@@ -1648,39 +1787,48 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
}
batch_size = DIV_ROUND_UP(n_chan, batch_len);
+ if (!phy->cap.has_5ghz)
+ last_ch = chan_list_2ghz[n_chan - 1];
+ else
+ last_ch = chan_list_5ghz[n_chan - 1];
+
for (i = 0; i < batch_size; i++) {
- bool last_msg = i == batch_size - 1;
- int num_ch = last_msg ? n_chan % batch_len : batch_len;
struct mt76_connac_tx_power_limit_tlv tx_power_tlv = {
.band = band == NL80211_BAND_2GHZ ? 1 : 2,
- .n_chan = num_ch,
- .last_msg = last_msg,
};
+ int j, err, msg_len, num_ch;
struct sk_buff *skb;
- int j, err, msg_len;
+ num_ch = i == batch_size - 1 ? n_chan % batch_len : batch_len;
msg_len = sizeof(tx_power_tlv) + num_ch * sizeof(sku_tlbv);
skb = mt76_mcu_msg_alloc(dev, NULL, msg_len);
if (!skb)
return -ENOMEM;
+ skb_reserve(skb, sizeof(tx_power_tlv));
+
BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(tx_power_tlv.alpha2));
memcpy(tx_power_tlv.alpha2, dev->alpha2, sizeof(dev->alpha2));
+ tx_power_tlv.n_chan = num_ch;
- skb_put_data(skb, &tx_power_tlv, sizeof(tx_power_tlv));
for (j = 0; j < num_ch; j++, idx++) {
struct ieee80211_channel chan = {
.hw_value = ch_list[idx],
.band = band,
};
- mt76_get_rate_power_limits(phy, &chan, &limits, 127);
+ mt76_get_rate_power_limits(phy, &chan, &limits,
+ tx_power);
+ tx_power_tlv.last_msg = ch_list[idx] == last_ch;
sku_tlbv.channel = ch_list[idx];
+
mt76_connac_mcu_build_sku(dev, sku_tlbv.pwr_limit,
&limits, band);
skb_put_data(skb, &sku_tlbv, sku_len);
}
+ __skb_push(skb, sizeof(tx_power_tlv));
+ memcpy(skb->data, &tx_power_tlv, sizeof(tx_power_tlv));
err = mt76_mcu_skb_send_msg(dev, skb,
MCU_CMD_SET_RATE_TX_POWER, false);
@@ -1695,11 +1843,20 @@ int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy)
{
int err;
- err = mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_2GHZ);
- if (err < 0)
- return err;
+ if (phy->cap.has_2ghz) {
+ err = mt76_connac_mcu_rate_txpower_band(phy,
+ NL80211_BAND_2GHZ);
+ if (err < 0)
+ return err;
+ }
+ if (phy->cap.has_5ghz) {
+ err = mt76_connac_mcu_rate_txpower_band(phy,
+ NL80211_BAND_5GHZ);
+ if (err < 0)
+ return err;
+ }
- return mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_5GHZ);
+ return 0;
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rate_txpower);
@@ -1939,7 +2096,7 @@ mt76_connac_mcu_set_wow_pattern(struct mt76_dev *dev,
ptlv->index = index;
memcpy(ptlv->pattern, pattern->pattern, pattern->pattern_len);
- memcpy(ptlv->mask, pattern->mask, pattern->pattern_len / 8);
+ memcpy(ptlv->mask, pattern->mask, DIV_ROUND_UP(pattern->pattern_len, 8));
return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD_SUSPEND, true);
}
@@ -1974,14 +2131,17 @@ mt76_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif,
};
if (wowlan->magic_pkt)
- req.wow_ctrl_tlv.trigger |= BIT(0);
+ req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_MAGIC;
if (wowlan->disconnect)
- req.wow_ctrl_tlv.trigger |= BIT(2);
+ req.wow_ctrl_tlv.trigger |= (UNI_WOW_DETECT_TYPE_DISCONNECT |
+ UNI_WOW_DETECT_TYPE_BCN_LOST);
if (wowlan->nd_config) {
mt76_connac_mcu_sched_scan_req(phy, vif, wowlan->nd_config);
- req.wow_ctrl_tlv.trigger |= BIT(5);
+ req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_SCH_SCAN_HIT;
mt76_connac_mcu_sched_scan_enable(phy, vif, suspend);
}
+ if (wowlan->n_patterns)
+ req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_BITMAP;
if (mt76_is_mmio(dev))
req.wow_ctrl_tlv.wakeup_hif = WOW_PCIE;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index a1096861d04a..1c73beb22677 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -559,6 +559,7 @@ enum {
MCU_CMD_SET_RATE_TX_POWER = MCU_CE_PREFIX | 0x5d,
MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61,
MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62,
+ MCU_CMD_GET_NIC_CAPAB = MCU_CE_PREFIX | 0x8a,
MCU_CMD_REG_WRITE = MCU_CE_PREFIX | 0xc0,
MCU_CMD_REG_READ = MCU_CE_PREFIX | MCU_QUERY_MASK | 0xc0,
MCU_CMD_CHIP_CONFIG = MCU_CE_PREFIX | 0xca,
@@ -575,6 +576,7 @@ enum {
enum {
UNI_BSS_INFO_BASIC = 0,
UNI_BSS_INFO_RLM = 2,
+ UNI_BSS_INFO_BSS_COLOR = 4,
UNI_BSS_INFO_HE_BASIC = 5,
UNI_BSS_INFO_BCN_CONTENT = 7,
UNI_BSS_INFO_QBSS = 15,
@@ -591,6 +593,36 @@ enum {
};
enum {
+ MT_NIC_CAP_TX_RESOURCE,
+ MT_NIC_CAP_TX_EFUSE_ADDR,
+ MT_NIC_CAP_COEX,
+ MT_NIC_CAP_SINGLE_SKU,
+ MT_NIC_CAP_CSUM_OFFLOAD,
+ MT_NIC_CAP_HW_VER,
+ MT_NIC_CAP_SW_VER,
+ MT_NIC_CAP_MAC_ADDR,
+ MT_NIC_CAP_PHY,
+ MT_NIC_CAP_MAC,
+ MT_NIC_CAP_FRAME_BUF,
+ MT_NIC_CAP_BEAM_FORM,
+ MT_NIC_CAP_LOCATION,
+ MT_NIC_CAP_MUMIMO,
+ MT_NIC_CAP_BUFFER_MODE_INFO,
+ MT_NIC_CAP_HW_ADIE_VERSION = 0x14,
+ MT_NIC_CAP_ANTSWP = 0x16,
+ MT_NIC_CAP_WFDMA_REALLOC,
+ MT_NIC_CAP_6G,
+};
+
+#define UNI_WOW_DETECT_TYPE_MAGIC BIT(0)
+#define UNI_WOW_DETECT_TYPE_ANY BIT(1)
+#define UNI_WOW_DETECT_TYPE_DISCONNECT BIT(2)
+#define UNI_WOW_DETECT_TYPE_GTK_REKEY_FAIL BIT(3)
+#define UNI_WOW_DETECT_TYPE_BCN_LOST BIT(4)
+#define UNI_WOW_DETECT_TYPE_SCH_SCAN_HIT BIT(5)
+#define UNI_WOW_DETECT_TYPE_BITMAP BIT(6)
+
+enum {
UNI_SUSPEND_MODE_SETTING,
UNI_SUSPEND_WOW_CTRL,
UNI_SUSPEND_WOW_GPIO_PARAM,
@@ -762,7 +794,7 @@ struct mt76_connac_sched_scan_req {
u8 intervals_num;
u8 scan_func; /* MT7663: BIT(0) eable random mac address */
struct mt76_connac_mcu_scan_channel channels[64];
- __le16 intervals[MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL];
+ __le16 intervals[MT76_CONNAC_MAX_NUM_SCHED_SCAN_INTERVAL];
union {
struct {
u8 random_mac[ETH_ALEN];
@@ -770,7 +802,9 @@ struct mt76_connac_sched_scan_req {
} mt7663;
struct {
u8 bss_idx;
- u8 pad2[63];
+ u8 pad2[19];
+ u8 random_mac[ETH_ALEN];
+ u8 pad3[38];
} mt7921;
};
} __packed;
@@ -781,6 +815,14 @@ struct mt76_connac_sched_scan_done {
__le16 pad;
} __packed;
+struct bss_info_uni_bss_color {
+ __le16 tag;
+ __le16 len;
+ u8 enable;
+ u8 bss_color;
+ u8 rsv[2];
+} __packed;
+
struct bss_info_uni_he {
__le16 tag;
__le16 len;
@@ -885,15 +927,24 @@ struct mt76_connac_suspend_tlv {
u8 pad[5];
} __packed;
+enum mt76_sta_info_state {
+ MT76_STA_INFO_STATE_NONE,
+ MT76_STA_INFO_STATE_AUTH,
+ MT76_STA_INFO_STATE_ASSOC
+};
+
struct mt76_sta_cmd_info {
struct ieee80211_sta *sta;
struct mt76_wcid *wcid;
struct ieee80211_vif *vif;
+ bool offload_fw;
bool enable;
+ bool newly;
int cmd;
u8 rcpi;
+ u8 state;
};
#define MT_SKU_POWER_LIMIT 161
@@ -963,18 +1014,23 @@ int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy);
int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif);
void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, bool enable);
+ struct ieee80211_sta *sta, bool enable,
+ bool newly);
void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta, void *sta_wtbl,
void *wtbl_tlv);
void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb,
+ struct ieee80211_vif *vif,
struct mt76_wcid *wcid,
void *sta_wtbl, void *wtbl_tlv);
+int mt76_connac_mcu_sta_update_hdr_trans(struct mt76_dev *dev,
+ struct ieee80211_vif *vif,
+ struct mt76_wcid *wcid, int cmd);
void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb,
struct ieee80211_sta *sta,
struct ieee80211_vif *vif,
- u8 rcpi);
+ u8 rcpi, u8 state);
void mt76_connac_mcu_wtbl_ht_tlv(struct mt76_dev *dev, struct sk_buff *skb,
struct ieee80211_sta *sta, void *sta_wtbl,
void *wtbl_tlv);
@@ -996,8 +1052,8 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
struct ieee80211_vif *vif,
struct mt76_wcid *wcid,
bool enable);
-int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy,
- struct mt76_sta_cmd_info *info);
+int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy,
+ struct mt76_sta_cmd_info *info);
void mt76_connac_mcu_beacon_loss_iter(void *priv, u8 *mac,
struct ieee80211_vif *vif);
int mt76_connac_mcu_set_rts_thresh(struct mt76_dev *dev, u32 val, u8 band);
@@ -1008,6 +1064,7 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len,
int mt76_connac_mcu_start_patch(struct mt76_dev *dev);
int mt76_connac_mcu_patch_sem_ctrl(struct mt76_dev *dev, bool get);
int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option);
+int mt76_connac_mcu_get_nic_capability(struct mt76_phy *phy);
int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_scan_request *scan_req);
@@ -1028,6 +1085,9 @@ int mt76_connac_mcu_update_gtk_rekey(struct ieee80211_hw *hw,
int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend);
void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
struct ieee80211_vif *vif);
+int mt76_connac_sta_state_dp(struct mt76_dev *dev,
+ enum ieee80211_sta_state old_state,
+ enum ieee80211_sta_state new_state);
int mt76_connac_mcu_chip_config(struct mt76_dev *dev);
int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable);
void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
index dd66fd12a2e6..cea24213186c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
@@ -68,7 +68,7 @@ static void mt76x0_set_chip_cap(struct mt76x02_dev *dev)
nic_conf1 &= 0xff00;
if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL)
- dev_err(dev->mt76.dev,
+ dev_dbg(dev->mt76.dev,
"driver does not support HW RF ctrl\n");
if (!mt76x02_field_valid(nic_conf0 >> 8))
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index 0da37867cb64..c32e6dc68773 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -34,24 +34,24 @@ mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
{
memset(key_data, 0, 32);
if (!key)
- return MT_CIPHER_NONE;
+ return MT76X02_CIPHER_NONE;
if (key->keylen > 32)
- return MT_CIPHER_NONE;
+ return MT76X02_CIPHER_NONE;
memcpy(key_data, key->key, key->keylen);
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
- return MT_CIPHER_WEP40;
+ return MT76X02_CIPHER_WEP40;
case WLAN_CIPHER_SUITE_WEP104:
- return MT_CIPHER_WEP104;
+ return MT76X02_CIPHER_WEP104;
case WLAN_CIPHER_SUITE_TKIP:
- return MT_CIPHER_TKIP;
+ return MT76X02_CIPHER_TKIP;
case WLAN_CIPHER_SUITE_CCMP:
- return MT_CIPHER_AES_CCMP;
+ return MT76X02_CIPHER_AES_CCMP;
default:
- return MT_CIPHER_NONE;
+ return MT76X02_CIPHER_NONE;
}
}
@@ -63,7 +63,7 @@ int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx,
u32 val;
cipher = mt76x02_mac_get_key_info(key, key_data);
- if (cipher == MT_CIPHER_NONE && key)
+ if (cipher == MT76X02_CIPHER_NONE && key)
return -EOPNOTSUPP;
val = mt76_rr(dev, MT_SKEY_MODE(vif_idx));
@@ -91,10 +91,10 @@ void mt76x02_mac_wcid_sync_pn(struct mt76x02_dev *dev, u8 idx,
eiv = mt76_rr(dev, MT_WCID_IV(idx) + 4);
pn = (u64)eiv << 16;
- if (cipher == MT_CIPHER_TKIP) {
+ if (cipher == MT76X02_CIPHER_TKIP) {
pn |= (iv >> 16) & 0xff;
pn |= (iv & 0xff) << 8;
- } else if (cipher >= MT_CIPHER_AES_CCMP) {
+ } else if (cipher >= MT76X02_CIPHER_AES_CCMP) {
pn |= iv & 0xffff;
} else {
return;
@@ -112,7 +112,7 @@ int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx,
u64 pn;
cipher = mt76x02_mac_get_key_info(key, key_data);
- if (cipher == MT_CIPHER_NONE && key)
+ if (cipher == MT76X02_CIPHER_NONE && key)
return -EOPNOTSUPP;
mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data));
@@ -126,16 +126,16 @@ int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx,
pn = atomic64_read(&key->tx_pn);
iv_data[3] = key->keyidx << 6;
- if (cipher >= MT_CIPHER_TKIP) {
+ if (cipher >= MT76X02_CIPHER_TKIP) {
iv_data[3] |= 0x20;
put_unaligned_le32(pn >> 16, &iv_data[4]);
}
- if (cipher == MT_CIPHER_TKIP) {
+ if (cipher == MT76X02_CIPHER_TKIP) {
iv_data[0] = (pn >> 8) & 0xff;
iv_data[1] = (iv_data[0] | 0x20) & 0x7f;
iv_data[2] = pn & 0xff;
- } else if (cipher >= MT_CIPHER_AES_CCMP) {
+ } else if (cipher >= MT76X02_CIPHER_AES_CCMP) {
put_unaligned_le16((pn & 0xffff), &iv_data[0]);
}
}
@@ -1022,12 +1022,12 @@ void mt76x02_mac_set_tx_protection(struct mt76x02_dev *dev, bool legacy_prot,
mt76_wr(dev, MT_TX_PROT_CFG6 + i * 4, vht_prot[i]);
}
-void mt76x02_update_channel(struct mt76_dev *mdev)
+void mt76x02_update_channel(struct mt76_phy *mphy)
{
- struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
+ struct mt76x02_dev *dev = container_of(mphy->dev, struct mt76x02_dev, mt76);
struct mt76_channel_state *state;
- state = mdev->phy.chan_state;
+ state = mphy->chan_state;
state->cc_busy += mt76_rr(dev, MT_CH_BUSY);
spin_lock_bh(&dev->mt76.cc_lock);
@@ -1169,7 +1169,7 @@ void mt76x02_mac_work(struct work_struct *work)
mutex_lock(&dev->mt76.mutex);
- mt76_update_survey(&dev->mt76);
+ mt76_update_survey(&dev->mphy);
for (i = 0, idx = 0; i < 16; i++) {
u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i));
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
index 0cfbaca50210..5dc6c834111e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
@@ -195,7 +195,7 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
struct ieee80211_sta *sta, int len);
void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq);
void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
-void mt76x02_update_channel(struct mt76_dev *mdev);
+void mt76x02_update_channel(struct mt76_phy *mphy);
void mt76x02_mac_work(struct work_struct *work);
void mt76x02_mac_cc_reset(struct mt76x02_dev *dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h
index 3e722276b5c2..fa7872ac22bf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h
@@ -692,15 +692,15 @@ struct mt76_wcid_key {
} __packed __aligned(4);
enum mt76x02_cipher_type {
- MT_CIPHER_NONE,
- MT_CIPHER_WEP40,
- MT_CIPHER_WEP104,
- MT_CIPHER_TKIP,
- MT_CIPHER_AES_CCMP,
- MT_CIPHER_CKIP40,
- MT_CIPHER_CKIP104,
- MT_CIPHER_CKIP128,
- MT_CIPHER_WAPI,
+ MT76X02_CIPHER_NONE,
+ MT76X02_CIPHER_WEP40,
+ MT76X02_CIPHER_WEP104,
+ MT76X02_CIPHER_TKIP,
+ MT76X02_CIPHER_AES_CCMP,
+ MT76X02_CIPHER_CKIP40,
+ MT76X02_CIPHER_CKIP104,
+ MT76X02_CIPHER_CKIP128,
+ MT76X02_CIPHER_WAPI,
};
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index 02db5d66735d..ccdbab341271 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -7,24 +7,18 @@
#include <linux/module.h>
#include "mt76x02.h"
-#define CCK_RATE(_idx, _rate) { \
+#define MT76x02_CCK_RATE(_idx, _rate) { \
.bitrate = _rate, \
.flags = IEEE80211_RATE_SHORT_PREAMBLE, \
.hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \
.hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + (_idx)), \
}
-#define OFDM_RATE(_idx, _rate) { \
- .bitrate = _rate, \
- .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
- .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
-}
-
struct ieee80211_rate mt76x02_rates[] = {
- CCK_RATE(0, 10),
- CCK_RATE(1, 20),
- CCK_RATE(2, 55),
- CCK_RATE(3, 110),
+ MT76x02_CCK_RATE(0, 10),
+ MT76x02_CCK_RATE(1, 20),
+ MT76x02_CCK_RATE(2, 55),
+ MT76x02_CCK_RATE(3, 110),
OFDM_RATE(0, 60),
OFDM_RATE(1, 90),
OFDM_RATE(2, 120),
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/Makefile b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile
index 40c8061787e9..80e49244348e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile
@@ -1,4 +1,4 @@
-#SPDX-License-Identifier: ISC
+# SPDX-License-Identifier: ISC
obj-$(CONFIG_MT7915E) += mt7915e.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
index 6a8ddeeecbe9..64048243e34b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
@@ -3,6 +3,7 @@
#include "mt7915.h"
#include "eeprom.h"
+#include "mcu.h"
/** global debugfs **/
@@ -16,7 +17,7 @@ mt7915_implicit_txbf_set(void *data, u64 val)
dev->ibf = !!val;
- return mt7915_mcu_set_txbf_type(dev);
+ return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE);
}
static int
@@ -147,6 +148,9 @@ mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s)
{
struct mt7915_dev *dev = s->private;
bool ext_phy = phy != &dev->phy;
+ static const char * const bw[] = {
+ "BW20", "BW40", "BW80", "BW160"
+ };
int cnt;
if (!phy)
@@ -164,11 +168,16 @@ mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s)
seq_puts(s, "Tx Beamformer Rx feedback statistics: ");
cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(ext_phy));
- seq_printf(s, "All: %ld, HE: %ld, VHT: %ld, HT: %ld\n",
+ seq_printf(s, "All: %ld, HE: %ld, VHT: %ld, HT: %ld, ",
FIELD_GET(MT_ETBF_RX_FB_ALL, cnt),
FIELD_GET(MT_ETBF_RX_FB_HE, cnt),
FIELD_GET(MT_ETBF_RX_FB_VHT, cnt),
FIELD_GET(MT_ETBF_RX_FB_HT, cnt));
+ cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(ext_phy));
+ seq_printf(s, "%s, NC: %ld, NR: %ld\n",
+ bw[FIELD_GET(MT_ETBF_RX_FB_BW, cnt)],
+ FIELD_GET(MT_ETBF_RX_FB_NC, cnt),
+ FIELD_GET(MT_ETBF_RX_FB_NR, cnt));
/* Tx Beamformee Rx NDPA & Tx feedback report */
cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(ext_phy));
@@ -204,7 +213,7 @@ mt7915_tx_stats_show(struct seq_file *file, void *data)
mt7915_txbf_stat_read_phy(mt7915_ext_phy(dev), file);
/* Tx amsdu info */
- seq_puts(file, "Tx MSDU stat:\n");
+ seq_puts(file, "Tx MSDU statistics:\n");
for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) {
stat[i] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
n += stat[i];
@@ -224,18 +233,6 @@ mt7915_tx_stats_show(struct seq_file *file, void *data)
DEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats);
-static int mt7915_read_temperature(struct seq_file *s, void *data)
-{
- struct mt7915_dev *dev = dev_get_drvdata(s->private);
- int temp;
-
- /* cpu */
- temp = mt7915_mcu_get_temperature(dev, 0);
- seq_printf(s, "Temperature: %d\n", temp);
-
- return 0;
-}
-
static int
mt7915_queues_acq(struct seq_file *s, void *data)
{
@@ -307,54 +304,23 @@ mt7915_puts_rate_txpower(struct seq_file *s, struct mt7915_phy *phy)
"RU26", "RU52", "RU106", "RU242/SU20",
"RU484/SU40", "RU996/SU80", "RU2x996/SU160"
};
- struct mt7915_dev *dev = dev_get_drvdata(s->private);
- bool ext_phy = phy != &dev->phy;
- u32 reg_base;
- int i, idx = 0;
+ s8 txpower[MT7915_SKU_RATE_NUM], *buf;
+ int i;
if (!phy)
return;
- reg_base = MT_TMAC_FP0R0(ext_phy);
- seq_printf(s, "\nBand %d\n", ext_phy);
+ seq_printf(s, "\nBand %d\n", phy != &phy->dev->phy);
- for (i = 0; i < ARRAY_SIZE(mt7915_sku_group_len); i++) {
- u8 cnt, mcs_num = mt7915_sku_group_len[i];
- s8 txpower[12];
- int j;
+ mt7915_mcu_get_txpower_sku(phy, txpower, sizeof(txpower));
+ for (i = 0, buf = txpower; i < ARRAY_SIZE(mt7915_sku_group_len); i++) {
+ u8 mcs_num = mt7915_sku_group_len[i];
- if (i == SKU_HT_BW20 || i == SKU_HT_BW40) {
- mcs_num = 8;
- } else if (i >= SKU_VHT_BW20 && i <= SKU_VHT_BW160) {
+ if (i >= SKU_VHT_BW20 && i <= SKU_VHT_BW160)
mcs_num = 10;
- } else if (i == SKU_HE_RU26) {
- reg_base = MT_TMAC_FP0R18(ext_phy);
- idx = 0;
- }
-
- for (j = 0, cnt = 0; j < DIV_ROUND_UP(mcs_num, 4); j++) {
- u32 val;
-
- if (i == SKU_VHT_BW160 && idx == 60) {
- reg_base = MT_TMAC_FP0R15(ext_phy);
- idx = 0;
- }
-
- val = mt76_rr(dev, reg_base + (idx / 4) * 4);
-
- if (idx && idx % 4)
- val >>= (idx % 4) * 8;
-
- while (val > 0 && cnt < mcs_num) {
- s8 pwr = FIELD_GET(MT_TMAC_FP_MASK, val);
-
- txpower[cnt++] = pwr;
- val >>= 8;
- idx++;
- }
- }
- mt76_seq_puts_array(s, sku_group_name[i], txpower, mcs_num);
+ mt76_seq_puts_array(s, sku_group_name[i], buf, mcs_num);
+ buf += mt7915_sku_group_len[i];
}
}
@@ -390,8 +356,6 @@ int mt7915_init_debugfs(struct mt7915_dev *dev)
debugfs_create_file("radar_trigger", 0200, dir, dev,
&fops_radar_trigger);
debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger);
- debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir,
- mt7915_read_temperature);
debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir,
mt7915_read_rate_txpower);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
index 11d0b760abd7..9182568f95c7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
@@ -19,39 +19,6 @@ int mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc)
return 0;
}
-void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
- struct sk_buff *skb)
-{
- struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
- __le32 *rxd = (__le32 *)skb->data;
- enum rx_pkt_type type;
-
- type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0]));
-
- switch (type) {
- case PKT_TYPE_TXRX_NOTIFY:
- mt7915_mac_tx_free(dev, skb);
- break;
- case PKT_TYPE_RX_EVENT:
- mt7915_mcu_rx_event(dev, skb);
- break;
-#ifdef CONFIG_NL80211_TESTMODE
- case PKT_TYPE_TXRXV:
- mt7915_mac_fill_rx_vector(dev, skb);
- break;
-#endif
- case PKT_TYPE_NORMAL:
- if (!mt7915_mac_fill_rx(dev, skb)) {
- mt76_rx(&dev->mt76, q, skb);
- return;
- }
- fallthrough;
- default:
- dev_kfree_skb(skb);
- break;
- }
-}
-
static void
mt7915_tx_cleanup(struct mt7915_dev *dev)
{
@@ -112,8 +79,6 @@ void mt7915_dma_prefetch(struct mt7915_dev *dev)
int mt7915_dma_init(struct mt7915_dev *dev)
{
- /* Increase buffer size to receive large VHT/HE MPDUs */
- int rx_buf_size = MT_RX_BUF_SIZE * 2;
u32 hif1_ofs = 0;
int ret;
@@ -177,28 +142,28 @@ int mt7915_dma_init(struct mt7915_dev *dev)
/* event from WM */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU],
MT7915_RXQ_MCU_WM, MT7915_RX_MCU_RING_SIZE,
- rx_buf_size, MT_RX_EVENT_RING_BASE);
+ MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE);
if (ret)
return ret;
/* event from WA */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
MT7915_RXQ_MCU_WA, MT7915_RX_MCU_RING_SIZE,
- rx_buf_size, MT_RX_EVENT_RING_BASE);
+ MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE);
if (ret)
return ret;
/* rx data queue */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN],
MT7915_RXQ_BAND0, MT7915_RX_RING_SIZE,
- rx_buf_size, MT_RX_DATA_RING_BASE);
+ MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE);
if (ret)
return ret;
if (dev->dbdc_support) {
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_EXT],
MT7915_RXQ_BAND1, MT7915_RX_RING_SIZE,
- rx_buf_size,
+ MT_RX_BUF_SIZE,
MT_RX_DATA_RING_BASE + hif1_ofs);
if (ret)
return ret;
@@ -207,7 +172,7 @@ int mt7915_dma_init(struct mt7915_dev *dev)
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_EXT_WA],
MT7915_RXQ_MCU_WA_EXT,
MT7915_RX_MCU_RING_SIZE,
- rx_buf_size,
+ MT_RX_BUF_SIZE,
MT_RX_EVENT_RING_BASE + hif1_ofs);
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
index 8ededf2e5279..ee3d64434821 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
@@ -4,22 +4,12 @@
#include "mt7915.h"
#include "eeprom.h"
-static u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset)
-{
- u8 *data = dev->mt76.eeprom.data;
-
- if (data[offset] == 0xff && !dev->flash_mode)
- mt7915_mcu_get_eeprom(dev, offset);
-
- return data[offset];
-}
-
static int mt7915_eeprom_load_precal(struct mt7915_dev *dev)
{
struct mt76_dev *mdev = &dev->mt76;
- u32 val;
+ u8 *eeprom = mdev->eeprom.data;
+ u32 val = eeprom[MT_EE_DO_PRE_CAL];
- val = mt7915_eeprom_read(dev, MT_EE_DO_PRE_CAL);
if (val != (MT_EE_WIFI_CAL_DPD | MT_EE_WIFI_CAL_GROUP))
return 0;
@@ -43,7 +33,13 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev)
dev->flash_mode = true;
ret = mt7915_eeprom_load_precal(dev);
} else {
- memset(dev->mt76.eeprom.data, -1, MT7915_EEPROM_SIZE);
+ u32 block_num, i;
+
+ block_num = DIV_ROUND_UP(MT7915_EEPROM_SIZE,
+ MT7915_EEPROM_BLOCK_SIZE);
+ for (i = 0; i < block_num; i++)
+ mt7915_mcu_get_eeprom(dev,
+ i * MT7915_EEPROM_BLOCK_SIZE);
}
return ret;
@@ -52,10 +48,7 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev)
static int mt7915_check_eeprom(struct mt7915_dev *dev)
{
u8 *eeprom = dev->mt76.eeprom.data;
- u16 val;
-
- mt7915_eeprom_read(dev, MT_EE_CHIP_ID);
- val = get_unaligned_le16(eeprom);
+ u16 val = get_unaligned_le16(eeprom);
switch (val) {
case 0x7915:
@@ -69,9 +62,10 @@ void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
bool ext_phy = phy != &dev->phy;
+ u8 *eeprom = dev->mt76.eeprom.data;
u32 val;
- val = mt7915_eeprom_read(dev, MT_EE_WIFI_CONF + ext_phy);
+ val = eeprom[MT_EE_WIFI_CONF + ext_phy];
val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val);
if (val == MT_EE_BAND_SEL_DEFAULT && dev->dbdc_support)
val = ext_phy ? MT_EE_BAND_SEL_5GHZ : MT_EE_BAND_SEL_2GHZ;
@@ -143,6 +137,7 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev,
struct ieee80211_channel *chan,
u8 chain_idx)
{
+ u8 *eeprom = dev->mt76.eeprom.data;
int index, target_power;
bool tssi_on;
@@ -153,18 +148,18 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev,
if (chan->band == NL80211_BAND_2GHZ) {
index = MT_EE_TX0_POWER_2G + chain_idx * 3;
- target_power = mt7915_eeprom_read(dev, index);
+ target_power = eeprom[index];
if (!tssi_on)
- target_power += mt7915_eeprom_read(dev, index + 1);
+ target_power += eeprom[index + 1];
} else {
int group = mt7915_get_channel_group(chan->hw_value);
index = MT_EE_TX0_POWER_5G + chain_idx * 12;
- target_power = mt7915_eeprom_read(dev, index + group);
+ target_power = eeprom[index + group];
if (!tssi_on)
- target_power += mt7915_eeprom_read(dev, index + 8);
+ target_power += eeprom[index + 8];
}
return target_power;
@@ -172,13 +167,14 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev,
s8 mt7915_eeprom_get_power_delta(struct mt7915_dev *dev, int band)
{
+ u8 *eeprom = dev->mt76.eeprom.data;
u32 val;
s8 delta;
if (band == NL80211_BAND_2GHZ)
- val = mt7915_eeprom_read(dev, MT_EE_RATE_DELTA_2G);
+ val = eeprom[MT_EE_RATE_DELTA_2G];
else
- val = mt7915_eeprom_read(dev, MT_EE_RATE_DELTA_5G);
+ val = eeprom[MT_EE_RATE_DELTA_5G];
if (!(val & MT_EE_RATE_DELTA_EN))
return 0;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h
index 033fb592bdf0..a43389a41800 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h
@@ -33,7 +33,7 @@ enum mt7915_eeprom_field {
#define MT_EE_WIFI_CAL_GROUP BIT(0)
#define MT_EE_WIFI_CAL_DPD GENMASK(2, 1)
#define MT_EE_CAL_UNIT 1024
-#define MT_EE_CAL_GROUP_SIZE (44 * MT_EE_CAL_UNIT)
+#define MT_EE_CAL_GROUP_SIZE (49 * MT_EE_CAL_UNIT + 16)
#define MT_EE_CAL_DPD_SIZE (54 * MT_EE_CAL_UNIT)
#define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0)
@@ -99,12 +99,15 @@ static inline bool
mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band)
{
u8 *eep = dev->mt76.eeprom.data;
+ u8 val = eep[MT_EE_WIFI_CONF + 7];
- /* TODO: DBDC */
- if (band == NL80211_BAND_5GHZ)
- return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF7_TSSI0_5G;
+ if (band == NL80211_BAND_2GHZ)
+ return val & MT_EE_WIFI_CONF7_TSSI0_2G;
+
+ if (dev->dbdc_support)
+ return val & MT_EE_WIFI_CONF7_TSSI1_5G;
else
- return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF7_TSSI0_2G;
+ return val & MT_EE_WIFI_CONF7_TSSI0_5G;
}
extern const u8 mt7915_sku_group_len[MAX_SKU_RATE_GROUP_NUM];
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index 822f3aa6bb8b..4798d6344305 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -2,39 +2,14 @@
/* Copyright (C) 2020 MediaTek Inc. */
#include <linux/etherdevice.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/thermal.h>
#include "mt7915.h"
#include "mac.h"
#include "mcu.h"
#include "eeprom.h"
-#define CCK_RATE(_idx, _rate) { \
- .bitrate = _rate, \
- .flags = IEEE80211_RATE_SHORT_PREAMBLE, \
- .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \
- .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)), \
-}
-
-#define OFDM_RATE(_idx, _rate) { \
- .bitrate = _rate, \
- .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
- .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
-}
-
-static struct ieee80211_rate mt7915_rates[] = {
- CCK_RATE(0, 10),
- CCK_RATE(1, 20),
- CCK_RATE(2, 55),
- CCK_RATE(3, 110),
- OFDM_RATE(11, 60),
- OFDM_RATE(15, 90),
- OFDM_RATE(10, 120),
- OFDM_RATE(14, 180),
- OFDM_RATE(9, 240),
- OFDM_RATE(13, 360),
- OFDM_RATE(8, 480),
- OFDM_RATE(12, 540),
-};
-
static const struct ieee80211_iface_limit if_limits[] = {
{
.max = 1,
@@ -67,6 +42,117 @@ static const struct ieee80211_iface_combination if_comb[] = {
}
};
+static ssize_t mt7915_thermal_show_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mt7915_phy *phy = dev_get_drvdata(dev);
+ int temperature;
+
+ temperature = mt7915_mcu_get_temperature(phy);
+ if (temperature < 0)
+ return temperature;
+
+ /* display in millidegree celcius */
+ return sprintf(buf, "%u\n", temperature * 1000);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, 0444, mt7915_thermal_show_temp,
+ NULL, 0);
+
+static struct attribute *mt7915_hwmon_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(mt7915_hwmon);
+
+static int
+mt7915_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ *state = MT7915_THERMAL_THROTTLE_MAX;
+
+ return 0;
+}
+
+static int
+mt7915_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct mt7915_phy *phy = cdev->devdata;
+
+ *state = phy->throttle_state;
+
+ return 0;
+}
+
+static int
+mt7915_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct mt7915_phy *phy = cdev->devdata;
+ int ret;
+
+ if (state > MT7915_THERMAL_THROTTLE_MAX)
+ return -EINVAL;
+
+ if (state == phy->throttle_state)
+ return 0;
+
+ ret = mt7915_mcu_set_thermal_throttling(phy, state);
+ if (ret)
+ return ret;
+
+ phy->throttle_state = state;
+
+ return 0;
+}
+
+static const struct thermal_cooling_device_ops mt7915_thermal_ops = {
+ .get_max_state = mt7915_thermal_get_max_throttle_state,
+ .get_cur_state = mt7915_thermal_get_cur_throttle_state,
+ .set_cur_state = mt7915_thermal_set_cur_throttle_state,
+};
+
+static void mt7915_unregister_thermal(struct mt7915_phy *phy)
+{
+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
+
+ if (!phy->cdev)
+ return;
+
+ sysfs_remove_link(&wiphy->dev.kobj, "cooling_device");
+ thermal_cooling_device_unregister(phy->cdev);
+}
+
+static int mt7915_thermal_init(struct mt7915_phy *phy)
+{
+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
+ struct thermal_cooling_device *cdev;
+ struct device *hwmon;
+
+ cdev = thermal_cooling_device_register(wiphy_name(wiphy), phy,
+ &mt7915_thermal_ops);
+ if (!IS_ERR(cdev)) {
+ if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj,
+ "cooling_device") < 0)
+ thermal_cooling_device_unregister(cdev);
+ else
+ phy->cdev = cdev;
+ }
+
+ if (!IS_REACHABLE(CONFIG_HWMON))
+ return 0;
+
+ hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev,
+ wiphy_name(wiphy), phy,
+ mt7915_hwmon_groups);
+ if (IS_ERR(hwmon))
+ return PTR_ERR(hwmon);
+
+ return 0;
+}
+
static void
mt7915_init_txpower(struct mt7915_dev *dev,
struct ieee80211_supported_band *sband)
@@ -201,7 +287,6 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF);
mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set);
- mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536);
@@ -228,20 +313,19 @@ static int mt7915_txbf_init(struct mt7915_dev *dev)
{
int ret;
-
if (dev->dbdc_support) {
- ret = mt7915_mcu_set_txbf_module(dev);
+ ret = mt7915_mcu_set_txbf(dev, MT_BF_MODULE_UPDATE);
if (ret)
return ret;
}
/* trigger sounding packets */
- ret = mt7915_mcu_set_txbf_sounding(dev);
+ ret = mt7915_mcu_set_txbf(dev, MT_BF_SOUNDING_ON);
if (ret)
return ret;
/* enable eBF */
- return mt7915_mcu_set_txbf_type(dev);
+ return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE);
}
static int mt7915_register_ext_phy(struct mt7915_dev *dev)
@@ -281,8 +365,12 @@ static int mt7915_register_ext_phy(struct mt7915_dev *dev)
if (ret)
goto error;
- ret = mt76_register_phy(mphy, true, mt7915_rates,
- ARRAY_SIZE(mt7915_rates));
+ ret = mt76_register_phy(mphy, true, mt76_rates,
+ ARRAY_SIZE(mt76_rates));
+ if (ret)
+ goto error;
+
+ ret = mt7915_thermal_init(phy);
if (ret)
goto error;
@@ -480,6 +568,9 @@ mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap,
if (nss < 2)
return;
+ /* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */
+ elem->phy_cap_info[7] |= min_t(int, nss - 1, 2) << 3;
+
if (vif != NL80211_IFTYPE_AP)
return;
@@ -493,9 +584,6 @@ mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap,
c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB;
elem->phy_cap_info[6] |= c;
-
- /* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */
- elem->phy_cap_info[7] |= min_t(int, nss - 1, 2) << 3;
}
static void
@@ -579,8 +667,6 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
switch (i) {
case NL80211_IFTYPE_AP:
- he_cap_elem->mac_cap_info[0] |=
- IEEE80211_HE_MAC_CAP0_TWT_RES;
he_cap_elem->mac_cap_info[2] |=
IEEE80211_HE_MAC_CAP2_BSR;
he_cap_elem->mac_cap_info[4] |=
@@ -594,8 +680,6 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
break;
case NL80211_IFTYPE_STATION:
- he_cap_elem->mac_cap_info[0] |=
- IEEE80211_HE_MAC_CAP0_TWT_REQ;
he_cap_elem->mac_cap_info[1] |=
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US;
@@ -690,6 +774,7 @@ static void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
if (!phy)
return;
+ mt7915_unregister_thermal(phy);
mt76_unregister_phy(mphy);
ieee80211_free_hw(mphy->hw);
}
@@ -731,8 +816,12 @@ int mt7915_register_device(struct mt7915_dev *dev)
dev->mt76.test_ops = &mt7915_testmode_ops;
#endif
- ret = mt76_register_device(&dev->mt76, true, mt7915_rates,
- ARRAY_SIZE(mt7915_rates));
+ ret = mt76_register_device(&dev->mt76, true, mt76_rates,
+ ARRAY_SIZE(mt76_rates));
+ if (ret)
+ return ret;
+
+ ret = mt7915_thermal_init(&dev->phy);
if (ret)
return ret;
@@ -748,10 +837,12 @@ int mt7915_register_device(struct mt7915_dev *dev)
void mt7915_unregister_device(struct mt7915_dev *dev)
{
mt7915_unregister_ext_phy(dev);
+ mt7915_unregister_thermal(&dev->phy);
mt76_unregister_device(&dev->mt76);
mt7915_mcu_exit(dev);
mt7915_tx_token_put(dev);
mt7915_dma_cleanup(dev);
+ tasklet_disable(&dev->irq_tasklet);
mt76_free_device(&dev->mt76);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 7a9759fb79d8..2462704094b0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -307,7 +307,8 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb,
}
}
-int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
+static int
+mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
struct mt76_phy *mphy = &dev->mt76.phy;
@@ -412,14 +413,27 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
u8 *data = (u8 *)rxd;
if (status->flag & RX_FLAG_DECRYPTED) {
- status->iv[0] = data[5];
- status->iv[1] = data[4];
- status->iv[2] = data[3];
- status->iv[3] = data[2];
- status->iv[4] = data[1];
- status->iv[5] = data[0];
-
- insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
+ switch (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1)) {
+ case MT_CIPHER_AES_CCMP:
+ case MT_CIPHER_CCMP_CCX:
+ case MT_CIPHER_CCMP_256:
+ insert_ccmp_hdr =
+ FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
+ fallthrough;
+ case MT_CIPHER_TKIP:
+ case MT_CIPHER_TKIP_NO_MIC:
+ case MT_CIPHER_GCMP:
+ case MT_CIPHER_GCMP_256:
+ status->iv[0] = data[5];
+ status->iv[1] = data[4];
+ status->iv[2] = data[3];
+ status->iv[3] = data[2];
+ status->iv[4] = data[1];
+ status->iv[5] = data[0];
+ break;
+ default:
+ break;
+ }
}
rxd += 4;
if ((u8 *)rxd - skb->data >= skb->len)
@@ -610,9 +624,10 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
return 0;
}
-#ifdef CONFIG_NL80211_TESTMODE
-void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb)
+static void
+mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb)
{
+#ifdef CONFIG_NL80211_TESTMODE
struct mt7915_phy *phy = &dev->phy;
__le32 *rxd = (__le32 *)skb->data;
__le32 *rxv_hdr = rxd + 2;
@@ -650,10 +665,10 @@ void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb)
phy->test.last_freq_offset = foe;
phy->test.last_snr = snr;
+#endif
dev_kfree_skb(skb);
}
-#endif
static void
mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
@@ -885,7 +900,7 @@ mt7915_mac_write_txwi_80211(struct mt7915_dev *dev, __le32 *txwi,
}
void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
- struct sk_buff *skb, struct mt76_wcid *wcid,
+ struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
struct ieee80211_key_conf *key, bool beacon)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -944,7 +959,12 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
txwi[3] = cpu_to_le32(val);
txwi[4] = 0;
- txwi[5] = 0;
+
+ val = FIELD_PREP(MT_TXD5_PID, pid);
+ if (pid >= MT_PACKET_ID_FIRST)
+ val |= MT_TXD5_TX_STATUS_HOST;
+ txwi[5] = cpu_to_le32(val);
+
txwi[6] = 0;
txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0;
@@ -984,11 +1004,11 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
struct ieee80211_key_conf *key = info->control.hw_key;
struct ieee80211_vif *vif = info->control.vif;
- struct mt76_tx_cb *cb = mt76_tx_skb_cb(tx_info->skb);
struct mt76_txwi_cache *t;
struct mt7915_txp *txp;
int id, i, nbuf = tx_info->nbuf - 1;
u8 *txwi = (u8 *)txwi_ptr;
+ int pid;
if (unlikely(tx_info->skb->len <= ETH_HLEN))
return -EINVAL;
@@ -996,10 +1016,10 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (!wcid)
wcid = &dev->mt76.global_wcid;
- mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
- false);
+ pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
- cb->wcid = wcid->idx;
+ mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid, key,
+ false);
txp = (struct mt7915_txp *)(txwi + MT_TXD_SIZE);
for (i = 0; i < nbuf; i++) {
@@ -1071,54 +1091,7 @@ mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
}
static void
-mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb,
- struct ieee80211_sta *sta, u8 stat,
- struct list_head *free_list)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_tx_status status = {
- .sta = sta,
- .info = info,
- .skb = skb,
- .free_list = free_list,
- };
- struct ieee80211_hw *hw;
-
- if (sta) {
- struct mt7915_sta *msta;
-
- msta = (struct mt7915_sta *)sta->drv_priv;
- status.rate = &msta->stats.tx_rate;
- }
-
-#ifdef CONFIG_NL80211_TESTMODE
- if (mt76_is_testmode_skb(mdev, skb, &hw)) {
- struct mt7915_phy *phy = mt7915_hw_phy(hw);
- struct ieee80211_vif *vif = phy->monitor_vif;
- struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
-
- mt76_tx_complete_skb(mdev, mvif->sta.wcid.idx, skb);
- return;
- }
-#endif
-
- hw = mt76_tx_status_get_hw(mdev, skb);
-
- if (info->flags & IEEE80211_TX_CTL_AMPDU)
- info->flags |= IEEE80211_TX_STAT_AMPDU;
-
- if (stat)
- ieee80211_tx_info_clear_status(info);
-
- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
- info->flags |= IEEE80211_TX_STAT_ACK;
-
- info->status.tx_time = 0;
- ieee80211_tx_status_ext(hw, &status);
-}
-
-void mt7915_txp_skb_unmap(struct mt76_dev *dev,
- struct mt76_txwi_cache *t)
+mt7915_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t)
{
struct mt7915_txp *txp;
int i;
@@ -1129,7 +1102,39 @@ void mt7915_txp_skb_unmap(struct mt76_dev *dev,
le16_to_cpu(txp->len[i]), DMA_TO_DEVICE);
}
-void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
+static void
+mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t,
+ struct ieee80211_sta *sta, struct list_head *free_list)
+{
+ struct mt76_dev *mdev = &dev->mt76;
+ struct mt76_wcid *wcid;
+ __le32 *txwi;
+ u16 wcid_idx;
+
+ mt7915_txp_skb_unmap(mdev, t);
+ if (!t->skb)
+ goto out;
+
+ txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
+ if (sta) {
+ wcid = (struct mt76_wcid *)sta->drv_priv;
+ wcid_idx = wcid->idx;
+
+ if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
+ mt7915_tx_check_aggr(sta, txwi);
+ } else {
+ wcid_idx = FIELD_GET(MT_TXD1_WLAN_IDX, le32_to_cpu(txwi[1]));
+ }
+
+ __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
+
+out:
+ t->skb = NULL;
+ mt76_put_txwi(mdev, t);
+}
+
+static void
+mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
{
struct mt7915_tx_free *free = (struct mt7915_tx_free *)skb->data;
struct mt76_dev *mdev = &dev->mt76;
@@ -1194,28 +1199,7 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
if (!txwi)
continue;
- mt7915_txp_skb_unmap(mdev, txwi);
- if (txwi->skb) {
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txwi->skb);
- void *txwi_ptr = mt76_get_txwi_ptr(mdev, txwi);
-
- if (likely(txwi->skb->protocol != cpu_to_be16(ETH_P_PAE)))
- mt7915_tx_check_aggr(sta, txwi_ptr);
-
- if (sta && !info->tx_time_est) {
- struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
- int pending;
-
- pending = atomic_dec_return(&wcid->non_aql_packets);
- if (pending < 0)
- atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
- }
-
- mt7915_tx_complete_status(mdev, txwi->skb, sta, stat, &free_list);
- txwi->skb = NULL;
- }
-
- mt76_put_txwi(mdev, txwi);
+ mt7915_txwi_free(dev, txwi, sta, &free_list);
}
mt7915_mac_sta_poll(dev);
@@ -1233,6 +1217,120 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
}
}
+static bool
+mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid,
+ __le32 *txs_data)
+{
+ struct mt76_dev *mdev = &dev->mt76;
+ struct ieee80211_tx_info *info;
+ struct sk_buff_head list;
+ struct sk_buff *skb;
+
+ mt76_tx_status_lock(mdev, &list);
+ skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list);
+ if (!skb)
+ goto out;
+
+ info = IEEE80211_SKB_CB(skb);
+ if (!(txs_data[0] & le32_to_cpu(MT_TXS0_ACK_ERROR_MASK)))
+ info->flags |= IEEE80211_TX_STAT_ACK;
+
+ info->status.ampdu_len = 1;
+ info->status.ampdu_ack_len = !!(info->flags &
+ IEEE80211_TX_STAT_ACK);
+
+ info->status.rates[0].idx = -1;
+ mt76_tx_status_skb_done(mdev, skb, &list);
+
+out:
+ mt76_tx_status_unlock(mdev, &list);
+
+ return !!skb;
+}
+
+static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data)
+{
+ struct mt7915_sta *msta = NULL;
+ struct mt76_wcid *wcid;
+ __le32 *txs_data = data;
+ u16 wcidx;
+ u32 txs;
+ u8 pid;
+
+ txs = le32_to_cpu(txs_data[0]);
+ if (FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1)
+ return;
+
+ txs = le32_to_cpu(txs_data[2]);
+ wcidx = FIELD_GET(MT_TXS2_WCID, txs);
+
+ txs = le32_to_cpu(txs_data[3]);
+ pid = FIELD_GET(MT_TXS3_PID, txs);
+
+ if (pid < MT_PACKET_ID_FIRST)
+ return;
+
+ if (wcidx >= MT7915_WTBL_SIZE)
+ return;
+
+ rcu_read_lock();
+
+ wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
+ if (!wcid)
+ goto out;
+
+ mt7915_mac_add_txs_skb(dev, wcid, pid, txs_data);
+
+ if (!wcid->sta)
+ goto out;
+
+ msta = container_of(wcid, struct mt7915_sta, wcid);
+ spin_lock_bh(&dev->sta_poll_lock);
+ if (list_empty(&msta->poll_list))
+ list_add_tail(&msta->poll_list, &dev->sta_poll_list);
+ spin_unlock_bh(&dev->sta_poll_lock);
+
+out:
+ rcu_read_unlock();
+}
+
+void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+ struct sk_buff *skb)
+{
+ struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
+ __le32 *rxd = (__le32 *)skb->data;
+ __le32 *end = (__le32 *)&skb->data[skb->len];
+ enum rx_pkt_type type;
+
+ type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0]));
+
+ switch (type) {
+ case PKT_TYPE_TXRX_NOTIFY:
+ mt7915_mac_tx_free(dev, skb);
+ break;
+ case PKT_TYPE_RX_EVENT:
+ mt7915_mcu_rx_event(dev, skb);
+ break;
+ case PKT_TYPE_TXRXV:
+ mt7915_mac_fill_rx_vector(dev, skb);
+ break;
+ case PKT_TYPE_TXS:
+ for (rxd += 2; rxd + 8 <= end; rxd += 8)
+ mt7915_mac_add_txs(dev, rxd);
+ dev_kfree_skb(skb);
+ break;
+ case PKT_TYPE_NORMAL:
+ if (!mt7915_mac_fill_rx(dev, skb)) {
+ mt76_rx(&dev->mt76, q, skb);
+ return;
+ }
+ fallthrough;
+ default:
+ dev_kfree_skb(skb);
+ break;
+ }
+}
+
void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
{
struct mt7915_dev *dev;
@@ -1254,15 +1352,8 @@ void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
e->skb = t ? t->skb : NULL;
}
- if (e->skb) {
- struct mt76_tx_cb *cb = mt76_tx_skb_cb(e->skb);
- struct mt76_wcid *wcid;
-
- wcid = rcu_dereference(dev->mt76.wcid[cb->wcid]);
-
- mt7915_tx_complete_status(mdev, e->skb, wcid_to_sta(wcid), 0,
- NULL);
- }
+ if (e->skb)
+ mt76_tx_complete_skb(mdev, e->wcid, e->skb);
}
void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy)
@@ -1296,14 +1387,10 @@ void mt7915_mac_reset_counters(struct mt7915_phy *phy)
memset(&dev->mt76.aggr_stats[i], 0, sizeof(dev->mt76.aggr_stats) / 2);
/* reset airtime counters */
- mt76_rr(dev, MT_MIB_SDR9(ext_phy));
- mt76_rr(dev, MT_MIB_SDR36(ext_phy));
- mt76_rr(dev, MT_MIB_SDR37(ext_phy));
-
- mt76_set(dev, MT_WF_RMAC_MIB_TIME0(ext_phy),
- MT_WF_RMAC_MIB_RXTIME_CLR);
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(ext_phy),
MT_WF_RMAC_MIB_RXTIME_CLR);
+
+ mt7915_mcu_get_chan_mib_info(phy, true);
}
void mt7915_mac_set_timing(struct mt7915_phy *phy)
@@ -1397,53 +1484,24 @@ mt7915_phy_get_nf(struct mt7915_phy *phy, int idx)
return sum / n;
}
-static void
-mt7915_phy_update_channel(struct mt76_phy *mphy, int idx)
+void mt7915_update_channel(struct mt76_phy *mphy)
{
- struct mt7915_dev *dev = container_of(mphy->dev, struct mt7915_dev, mt76);
struct mt7915_phy *phy = (struct mt7915_phy *)mphy->priv;
- struct mt76_channel_state *state;
- u64 busy_time, tx_time, rx_time, obss_time;
+ struct mt76_channel_state *state = mphy->chan_state;
+ bool ext_phy = phy != &phy->dev->phy;
int nf;
- busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx),
- MT_MIB_SDR9_BUSY_MASK);
- tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx),
- MT_MIB_SDR36_TXTIME_MASK);
- rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx),
- MT_MIB_SDR37_RXTIME_MASK);
- obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_AIRTIME14(idx),
- MT_MIB_OBSSTIME_MASK);
+ mt7915_mcu_get_chan_mib_info(phy, false);
- nf = mt7915_phy_get_nf(phy, idx);
+ nf = mt7915_phy_get_nf(phy, ext_phy);
if (!phy->noise)
phy->noise = nf << 4;
else if (nf)
phy->noise += nf - (phy->noise >> 4);
- state = mphy->chan_state;
- state->cc_busy += busy_time;
- state->cc_tx += tx_time;
- state->cc_rx += rx_time + obss_time;
- state->cc_bss_rx += rx_time;
state->noise = -(phy->noise >> 4);
}
-void mt7915_update_channel(struct mt76_dev *mdev)
-{
- struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
-
- mt7915_phy_update_channel(&mdev->phy, 0);
- if (mdev->phy2)
- mt7915_phy_update_channel(mdev->phy2, 1);
-
- /* reset obss airtime */
- mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
- if (mdev->phy2)
- mt76_set(dev, MT_WF_RMAC_MIB_TIME0(1),
- MT_WF_RMAC_MIB_RXTIME_CLR);
-}
-
static bool
mt7915_wait_reset_state(struct mt7915_dev *dev, u32 state)
{
@@ -1530,14 +1588,18 @@ mt7915_dma_reset(struct mt7915_dev *dev)
mt76_set(dev, MT_WFDMA0_GLO_CFG,
MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
mt76_set(dev, MT_WFDMA1_GLO_CFG,
- MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN);
+ MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN |
+ MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
if (dev->hif2) {
mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
(MT_WFDMA0_GLO_CFG_TX_DMA_EN |
MT_WFDMA0_GLO_CFG_RX_DMA_EN));
mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs,
(MT_WFDMA1_GLO_CFG_TX_DMA_EN |
- MT_WFDMA1_GLO_CFG_RX_DMA_EN));
+ MT_WFDMA1_GLO_CFG_RX_DMA_EN |
+ MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA1_GLO_CFG_OMIT_RX_INFO));
}
}
@@ -1548,14 +1610,7 @@ void mt7915_tx_token_put(struct mt7915_dev *dev)
spin_lock_bh(&dev->mt76.token_lock);
idr_for_each_entry(&dev->mt76.token, txwi, id) {
- mt7915_txp_skb_unmap(&dev->mt76, txwi);
- if (txwi->skb) {
- struct ieee80211_hw *hw;
-
- hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb);
- ieee80211_free_txskb(hw, txwi->skb);
- }
- mt76_put_txwi(&dev->mt76, txwi);
+ mt7915_txwi_free(dev, txwi, NULL, NULL);
dev->mt76.token_count--;
}
spin_unlock_bh(&dev->mt76.token_lock);
@@ -1588,11 +1643,6 @@ void mt7915_mac_reset_work(struct work_struct *work)
set_bit(MT76_RESET, &phy2->mt76->state);
cancel_delayed_work_sync(&phy2->mt76->mac_work);
}
- /* lock/unlock all queues to ensure that no tx is pending */
- mt76_txq_schedule_all(&dev->mphy);
- if (ext_phy)
- mt76_txq_schedule_all(ext_phy);
-
mt76_worker_disable(&dev->mt76.tx_worker);
napi_disable(&dev->mt76.napi[0]);
napi_disable(&dev->mt76.napi[1]);
@@ -1618,10 +1668,6 @@ void mt7915_mac_reset_work(struct work_struct *work)
if (phy2)
clear_bit(MT76_RESET, &phy2->mt76->state);
- mt76_worker_enable(&dev->mt76.tx_worker);
- napi_enable(&dev->mt76.tx_napi);
- napi_schedule(&dev->mt76.tx_napi);
-
napi_enable(&dev->mt76.napi[0]);
napi_schedule(&dev->mt76.napi[0]);
@@ -1630,14 +1676,20 @@ void mt7915_mac_reset_work(struct work_struct *work)
napi_enable(&dev->mt76.napi[2]);
napi_schedule(&dev->mt76.napi[2]);
+ tasklet_schedule(&dev->irq_tasklet);
+
+ mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
+ mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
+
+ mt76_worker_enable(&dev->mt76.tx_worker);
+
+ napi_enable(&dev->mt76.tx_napi);
+ napi_schedule(&dev->mt76.tx_napi);
ieee80211_wake_queues(mt76_hw(dev));
if (ext_phy)
ieee80211_wake_queues(ext_phy->hw);
- mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
- mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
-
mutex_unlock(&dev->mt76.mutex);
mt7915_update_beacons(dev);
@@ -1651,7 +1703,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
}
static void
-mt7915_mac_update_mib_stats(struct mt7915_phy *phy)
+mt7915_mac_update_stats(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
struct mib_stats *mib = &phy->mib;
@@ -1733,8 +1785,10 @@ void mt7915_mac_sta_rc_work(struct work_struct *work)
if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
IEEE80211_RC_NSS_CHANGED |
- IEEE80211_RC_BW_CHANGED))
+ IEEE80211_RC_BW_CHANGED)) {
+ mt7915_mcu_add_he(dev, vif, sta);
mt7915_mcu_add_rate_ctrl(dev, vif, sta);
+ }
if (changed & IEEE80211_RC_SMPS_CHANGED)
mt7915_mcu_add_smps(dev, vif, sta);
@@ -1756,11 +1810,11 @@ void mt7915_mac_work(struct work_struct *work)
mutex_lock(&mphy->dev->mutex);
- mt76_update_survey(mphy->dev);
+ mt76_update_survey(mphy);
if (++mphy->mac_work_count == 5) {
mphy->mac_work_count = 0;
- mt7915_mac_update_mib_stats(phy);
+ mt7915_mac_update_stats(phy);
}
if (++phy->sta_work_count == 10) {
@@ -1770,6 +1824,8 @@ void mt7915_mac_work(struct work_struct *work)
mutex_unlock(&mphy->dev->mutex);
+ mt76_tx_status_check(mphy->dev, NULL, false);
+
ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
MT7915_WATCHDOG_TIME);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
index 0f929fb53027..eb1885f4bd8e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
@@ -304,6 +304,62 @@ struct mt7915_tx_free {
/* will support this field in further revision */
#define MT_TX_FREE_RATE GENMASK(13, 0)
+#define MT_TXS0_FIXED_RATE BIT(31)
+#define MT_TXS0_BW GENMASK(30, 29)
+#define MT_TXS0_TID GENMASK(28, 26)
+#define MT_TXS0_AMPDU BIT(25)
+#define MT_TXS0_TXS_FORMAT GENMASK(24, 23)
+#define MT_TXS0_BA_ERROR BIT(22)
+#define MT_TXS0_PS_FLAG BIT(21)
+#define MT_TXS0_TXOP_TIMEOUT BIT(20)
+#define MT_TXS0_BIP_ERROR BIT(19)
+
+#define MT_TXS0_QUEUE_TIMEOUT BIT(18)
+#define MT_TXS0_RTS_TIMEOUT BIT(17)
+#define MT_TXS0_ACK_TIMEOUT BIT(16)
+#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16)
+
+#define MT_TXS0_TX_STATUS_HOST BIT(15)
+#define MT_TXS0_TX_STATUS_MCU BIT(14)
+#define MT_TXS0_TX_RATE GENMASK(13, 0)
+
+#define MT_TXS1_SEQNO GENMASK(31, 20)
+#define MT_TXS1_RESP_RATE GENMASK(19, 16)
+#define MT_TXS1_RXV_SEQNO GENMASK(15, 8)
+#define MT_TXS1_TX_POWER_DBM GENMASK(7, 0)
+
+#define MT_TXS2_BF_STATUS GENMASK(31, 30)
+#define MT_TXS2_LAST_TX_RATE GENMASK(29, 27)
+#define MT_TXS2_SHARED_ANTENNA BIT(26)
+#define MT_TXS2_WCID GENMASK(25, 16)
+#define MT_TXS2_TX_DELAY GENMASK(15, 0)
+
+#define MT_TXS3_PID GENMASK(31, 24)
+#define MT_TXS3_ANT_ID GENMASK(23, 0)
+
+#define MT_TXS4_TIMESTAMP GENMASK(31, 0)
+
+#define MT_TXS5_F0_FINAL_MPDU BIT(31)
+#define MT_TXS5_F0_QOS BIT(30)
+#define MT_TXS5_F0_TX_COUNT GENMASK(29, 25)
+#define MT_TXS5_F0_FRONT_TIME GENMASK(24, 0)
+#define MT_TXS5_F1_MPDU_TX_COUNT GENMASK(31, 24)
+#define MT_TXS5_F1_MPDU_TX_BYTES GENMASK(23, 0)
+
+#define MT_TXS6_F0_NOISE_3 GENMASK(31, 24)
+#define MT_TXS6_F0_NOISE_2 GENMASK(23, 16)
+#define MT_TXS6_F0_NOISE_1 GENMASK(15, 8)
+#define MT_TXS6_F0_NOISE_0 GENMASK(7, 0)
+#define MT_TXS6_F1_MPDU_FAIL_COUNT GENMASK(31, 24)
+#define MT_TXS6_F1_MPDU_FAIL_BYTES GENMASK(23, 0)
+
+#define MT_TXS7_F0_RCPI_3 GENMASK(31, 24)
+#define MT_TXS7_F0_RCPI_2 GENMASK(23, 16)
+#define MT_TXS7_F0_RCPI_1 GENMASK(15, 8)
+#define MT_TXS7_F0_RCPI_0 GENMASK(7, 0)
+#define MT_TXS7_F1_MPDU_RETRY_COUNT GENMASK(31, 24)
+#define MT_TXS7_F1_MPDU_RETRY_BYTES GENMASK(23, 0)
+
struct mt7915_dfs_pulse {
u32 max_width; /* us */
int max_pwr; /* dbm */
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index e5bd687546b6..c25f8da590dd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -139,12 +139,6 @@ static int get_omac_idx(enum nl80211_iftype type, u64 mask)
if (type != NL80211_IFTYPE_STATION)
break;
- /* next, try to find a free repeater entry for the sta */
- i = get_free_idx(mask >> REPEATER_BSSID_START, 0,
- REPEATER_BSSID_MAX - REPEATER_BSSID_START);
- if (i)
- return i + 32 - 1;
-
i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
if (i)
return i - 1;
@@ -172,6 +166,22 @@ static int get_omac_idx(enum nl80211_iftype type, u64 mask)
return -1;
}
+static void mt7915_init_bitrate_mask(struct ieee80211_vif *vif)
+{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mvif->bitrate_mask.control); i++) {
+ mvif->bitrate_mask.control[i].legacy = GENMASK(31, 0);
+ memset(mvif->bitrate_mask.control[i].ht_mcs, GENMASK(7, 0),
+ sizeof(mvif->bitrate_mask.control[i].ht_mcs));
+ memset(mvif->bitrate_mask.control[i].vht_mcs, GENMASK(15, 0),
+ sizeof(mvif->bitrate_mask.control[i].vht_mcs));
+ memset(mvif->bitrate_mask.control[i].he_mcs, GENMASK(15, 0),
+ sizeof(mvif->bitrate_mask.control[i].he_mcs));
+ }
+}
+
static int mt7915_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -241,6 +251,8 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
vif->offload_flags = 0;
vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
+ mt7915_init_bitrate_mask(vif);
+
out:
mutex_unlock(&dev->mt76.mutex);
@@ -798,7 +810,8 @@ mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->omac_idx;
/* TSF software read */
- mt76_set(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE);
+ mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE,
+ MT_LPON_TCR_SW_READ);
tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(band));
tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(band));
@@ -827,7 +840,34 @@ mt7915_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mt76_wr(dev, MT_LPON_UTTR0(band), tsf.t32[0]);
mt76_wr(dev, MT_LPON_UTTR1(band), tsf.t32[1]);
/* TSF software overwrite */
- mt76_set(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_WRITE);
+ mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE,
+ MT_LPON_TCR_SW_WRITE);
+
+ mutex_unlock(&dev->mt76.mutex);
+}
+
+static void
+mt7915_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ s64 timestamp)
+{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct mt7915_dev *dev = mt7915_hw_dev(hw);
+ struct mt7915_phy *phy = mt7915_hw_phy(hw);
+ bool band = phy != &dev->phy;
+ union {
+ u64 t64;
+ u32 t32[2];
+ } tsf = { .t64 = timestamp, };
+ u16 n;
+
+ mutex_lock(&dev->mt76.mutex);
+
+ n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->omac_idx;
+ mt76_wr(dev, MT_LPON_UTTR0(band), tsf.t32[0]);
+ mt76_wr(dev, MT_LPON_UTTR1(band), tsf.t32[1]);
+ /* TSF software adjust*/
+ mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE,
+ MT_LPON_TCR_SW_ADJUST);
mutex_unlock(&dev->mt76.mutex);
}
@@ -911,17 +951,15 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
}
-static void
-mt7915_sta_rc_update(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- u32 changed)
+static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta)
{
- struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ struct mt7915_dev *dev = msta->vif->phy->dev;
+ struct ieee80211_hw *hw = msta->vif->phy->mt76->hw;
+ u32 *changed = data;
spin_lock_bh(&dev->sta_poll_lock);
- msta->stats.changed |= changed;
+ msta->stats.changed |= *changed;
if (list_empty(&msta->rc_list))
list_add_tail(&msta->rc_list, &dev->sta_rc_list);
spin_unlock_bh(&dev->sta_poll_lock);
@@ -929,6 +967,39 @@ mt7915_sta_rc_update(struct ieee80211_hw *hw,
ieee80211_queue_work(hw, &dev->rc_work);
}
+static void mt7915_sta_rc_update(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ u32 changed)
+{
+ mt7915_sta_rc_work(&changed, sta);
+}
+
+static int
+mt7915_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ enum nl80211_band band = mvif->phy->mt76->chandef.chan->band;
+ u32 changed;
+
+ if (mask->control[band].gi == NL80211_TXRATE_FORCE_LGI)
+ return -EINVAL;
+
+ changed = IEEE80211_RC_SUPP_RATES_CHANGED;
+ mvif->bitrate_mask = *mask;
+
+ /* Update firmware rate control to add a boundary on top of table
+ * to limit the rate selection for each peer, so when set bitrates
+ * vht-mcs-5 1:9, which actually means nss = 1 mcs = 0~9. This only
+ * applies to data frames as for the other mgmt, mcast, bcast still
+ * use legacy rates as it is.
+ */
+ ieee80211_iterate_stations_atomic(hw, mt7915_sta_rc_work, &changed);
+
+ return 0;
+}
+
static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -987,9 +1058,11 @@ const struct ieee80211_ops mt7915_ops = {
.get_stats = mt7915_get_stats,
.get_tsf = mt7915_get_tsf,
.set_tsf = mt7915_set_tsf,
+ .offset_tsf = mt7915_offset_tsf,
.get_survey = mt76_get_survey,
.get_antenna = mt76_get_antenna,
.set_antenna = mt7915_set_antenna,
+ .set_bitrate_mask = mt7915_set_bitrate_mask,
.set_coverage_class = mt7915_set_coverage_class,
.sta_statistics = mt7915_sta_statistics,
.sta_set_4addr = mt7915_sta_set_4addr,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index b3f14ff67c5a..863aa18b3024 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -88,28 +88,28 @@ struct mt7915_fw_region {
#define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p)
#define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m)
-static enum mt7915_cipher_type
+static enum mcu_cipher_type
mt7915_mcu_get_cipher(int cipher)
{
switch (cipher) {
case WLAN_CIPHER_SUITE_WEP40:
- return MT_CIPHER_WEP40;
+ return MCU_CIPHER_WEP40;
case WLAN_CIPHER_SUITE_WEP104:
- return MT_CIPHER_WEP104;
+ return MCU_CIPHER_WEP104;
case WLAN_CIPHER_SUITE_TKIP:
- return MT_CIPHER_TKIP;
+ return MCU_CIPHER_TKIP;
case WLAN_CIPHER_SUITE_AES_CMAC:
- return MT_CIPHER_BIP_CMAC_128;
+ return MCU_CIPHER_BIP_CMAC_128;
case WLAN_CIPHER_SUITE_CCMP:
- return MT_CIPHER_AES_CCMP;
+ return MCU_CIPHER_AES_CCMP;
case WLAN_CIPHER_SUITE_CCMP_256:
- return MT_CIPHER_CCMP_256;
+ return MCU_CIPHER_CCMP_256;
case WLAN_CIPHER_SUITE_GCMP:
- return MT_CIPHER_GCMP;
+ return MCU_CIPHER_GCMP;
case WLAN_CIPHER_SUITE_GCMP_256:
- return MT_CIPHER_GCMP_256;
+ return MCU_CIPHER_GCMP_256;
case WLAN_CIPHER_SUITE_SMS4:
- return MT_CIPHER_WAPI;
+ return MCU_CIPHER_WAPI;
default:
return MT_CIPHER_NONE;
}
@@ -147,10 +147,10 @@ mt7915_get_he_phy_cap(struct mt7915_phy *phy, struct ieee80211_vif *vif)
}
static u8
-mt7915_get_phy_mode(struct mt76_phy *mphy, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+mt7915_get_phy_mode(struct ieee80211_vif *vif, struct ieee80211_sta *sta)
{
- enum nl80211_band band = mphy->chandef.chan->band;
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ enum nl80211_band band = mvif->phy->mt76->chandef.chan->band;
struct ieee80211_sta_ht_cap *ht_cap;
struct ieee80211_sta_vht_cap *vht_cap;
const struct ieee80211_sta_he_cap *he_cap;
@@ -163,7 +163,7 @@ mt7915_get_phy_mode(struct mt76_phy *mphy, struct ieee80211_vif *vif,
} else {
struct ieee80211_supported_band *sband;
- sband = mphy->hw->wiphy->bands[band];
+ sband = mvif->phy->mt76->hw->wiphy->bands[band];
ht_cap = &sband->ht_cap;
vht_cap = &sband->vht_cap;
@@ -209,6 +209,112 @@ mt7915_mcu_get_sta_nss(u16 mcs_map)
return nss - 1;
}
+static void
+mt7915_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs,
+ const u16 *mask)
+{
+ struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ struct cfg80211_chan_def *chandef = &msta->vif->phy->mt76->chandef;
+ int nss, max_nss = sta->rx_nss > 3 ? 4 : sta->rx_nss;
+ u16 mcs_map;
+
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_80P80:
+ mcs_map = le16_to_cpu(sta->he_cap.he_mcs_nss_supp.rx_mcs_80p80);
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ mcs_map = le16_to_cpu(sta->he_cap.he_mcs_nss_supp.rx_mcs_160);
+ break;
+ default:
+ mcs_map = le16_to_cpu(sta->he_cap.he_mcs_nss_supp.rx_mcs_80);
+ break;
+ }
+
+ for (nss = 0; nss < max_nss; nss++) {
+ int mcs;
+
+ switch ((mcs_map >> (2 * nss)) & 0x3) {
+ case IEEE80211_HE_MCS_SUPPORT_0_11:
+ mcs = GENMASK(11, 0);
+ break;
+ case IEEE80211_HE_MCS_SUPPORT_0_9:
+ mcs = GENMASK(9, 0);
+ break;
+ case IEEE80211_HE_MCS_SUPPORT_0_7:
+ mcs = GENMASK(7, 0);
+ break;
+ default:
+ mcs = 0;
+ }
+
+ mcs = mcs ? fls(mcs & mask[nss]) - 1 : -1;
+
+ switch (mcs) {
+ case 0 ... 7:
+ mcs = IEEE80211_HE_MCS_SUPPORT_0_7;
+ break;
+ case 8 ... 9:
+ mcs = IEEE80211_HE_MCS_SUPPORT_0_9;
+ break;
+ case 10 ... 11:
+ mcs = IEEE80211_HE_MCS_SUPPORT_0_11;
+ break;
+ default:
+ mcs = IEEE80211_HE_MCS_NOT_SUPPORTED;
+ break;
+ }
+ mcs_map &= ~(0x3 << (nss * 2));
+ mcs_map |= mcs << (nss * 2);
+
+ /* only support 2ss on 160MHz */
+ if (nss > 1 && (sta->bandwidth == IEEE80211_STA_RX_BW_160))
+ break;
+ }
+
+ *he_mcs = cpu_to_le16(mcs_map);
+}
+
+static void
+mt7915_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs,
+ const u16 *mask)
+{
+ u16 mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.rx_mcs_map);
+ int nss, max_nss = sta->rx_nss > 3 ? 4 : sta->rx_nss;
+ u16 mcs;
+
+ for (nss = 0; nss < max_nss; nss++, mcs_map >>= 2) {
+ switch (mcs_map & 0x3) {
+ case IEEE80211_VHT_MCS_SUPPORT_0_9:
+ mcs = GENMASK(9, 0);
+ break;
+ case IEEE80211_VHT_MCS_SUPPORT_0_8:
+ mcs = GENMASK(8, 0);
+ break;
+ case IEEE80211_VHT_MCS_SUPPORT_0_7:
+ mcs = GENMASK(7, 0);
+ break;
+ default:
+ mcs = 0;
+ }
+
+ vht_mcs[nss] = cpu_to_le16(mcs & mask[nss]);
+
+ /* only support 2ss on 160MHz */
+ if (nss > 1 && (sta->bandwidth == IEEE80211_STA_RX_BW_160))
+ break;
+ }
+}
+
+static void
+mt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs,
+ const u8 *mask)
+{
+ int nss, max_nss = sta->rx_nss > 3 ? 4 : sta->rx_nss;
+
+ for (nss = 0; nss < max_nss; nss++)
+ ht_mcs[nss] = sta->ht_cap.mcs.rx_mask[nss] & mask[nss];
+}
+
static int
mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
struct sk_buff *skb, int seq)
@@ -350,6 +456,24 @@ mt7915_mcu_rx_csa_notify(struct mt7915_dev *dev, struct sk_buff *skb)
}
static void
+mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb)
+{
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt7915_mcu_thermal_notify *t;
+ struct mt7915_phy *phy;
+
+ t = (struct mt7915_mcu_thermal_notify *)skb->data;
+ if (t->ctrl.ctrl_id != THERMAL_PROTECT_ENABLE)
+ return;
+
+ if (t->ctrl.band_idx && dev->mt76.phy2)
+ mphy = dev->mt76.phy2;
+
+ phy = (struct mt7915_phy *)mphy->priv;
+ phy->throttle_state = t->ctrl.duty.duty_cycle;
+}
+
+static void
mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb)
{
struct mt76_phy *mphy = &dev->mt76.phy;
@@ -469,6 +593,7 @@ mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb)
u16 attempts = le16_to_cpu(ra->attempts);
u16 curr = le16_to_cpu(ra->curr_rate);
u16 wcidx = le16_to_cpu(ra->wlan_idx);
+ struct ieee80211_tx_status status = {};
struct mt76_phy *mphy = &dev->mphy;
struct mt7915_sta_stats *stats;
struct mt7915_sta *msta;
@@ -500,6 +625,13 @@ mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb)
stats->per = 1000 * (attempts - success) / attempts;
}
+
+ status.sta = wcid_to_sta(wcid);
+ if (!status.sta)
+ return;
+
+ status.rate = &stats->tx_rate;
+ ieee80211_tx_status_ext(mphy->hw, &status);
}
static void
@@ -531,6 +663,9 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb)
struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data;
switch (rxd->ext_eid) {
+ case MCU_EXT_EVENT_THERMAL_PROTECT:
+ mt7915_mcu_rx_thermal_notify(dev, skb);
+ break;
case MCU_EXT_EVENT_RDD_REPORT:
mt7915_mcu_rx_radar_detected(dev, skb);
break;
@@ -733,7 +868,7 @@ mt7915_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN);
bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
bss->dtim_period = vif->bss_conf.dtim_period;
- bss->phy_mode = mt7915_get_phy_mode(phy->mt76, vif, NULL);
+ bss->phy_mode = mt7915_get_phy_mode(vif, NULL);
} else {
memcpy(bss->bssid, phy->mt76->macaddr, ETH_ALEN);
}
@@ -1072,14 +1207,14 @@ mt7915_mcu_sta_key_tlv(struct mt7915_sta *msta, struct sk_buff *skb,
sec_key = &sec->key[0];
sec_key->cipher_len = sizeof(*sec_key);
- if (cipher == MT_CIPHER_BIP_CMAC_128) {
- sec_key->cipher_id = MT_CIPHER_AES_CCMP;
+ if (cipher == MCU_CIPHER_BIP_CMAC_128) {
+ sec_key->cipher_id = MCU_CIPHER_AES_CCMP;
sec_key->key_id = bip->keyidx;
sec_key->key_len = 16;
memcpy(sec_key->key, bip->key, 16);
sec_key = &sec->key[1];
- sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128;
+ sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128;
sec_key->cipher_len = sizeof(*sec_key);
sec_key->key_len = 16;
memcpy(sec_key->key, key->key, 16);
@@ -1091,14 +1226,14 @@ mt7915_mcu_sta_key_tlv(struct mt7915_sta *msta, struct sk_buff *skb,
sec_key->key_len = key->keylen;
memcpy(sec_key->key, key->key, key->keylen);
- if (cipher == MT_CIPHER_TKIP) {
+ if (cipher == MCU_CIPHER_TKIP) {
/* Rx/Tx MIC keys are swapped */
memcpy(sec_key->key + 16, key->key + 24, 8);
memcpy(sec_key->key + 24, key->key + 16, 8);
}
/* store key_conf for BIP batch update */
- if (cipher == MT_CIPHER_AES_CCMP) {
+ if (cipher == MCU_CIPHER_AES_CCMP) {
memcpy(bip->key, key->key, key->keylen);
bip->keyidx = key->keyidx;
}
@@ -1336,8 +1471,11 @@ mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
static void
mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
{
+ struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem;
+ enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band;
+ const u16 *mcs_mask = msta->vif->bitrate_mask.control[band].he_mcs;
struct sta_rec_he *he;
struct tlv *tlv;
u32 cap = 0;
@@ -1428,15 +1566,18 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
case IEEE80211_STA_RX_BW_160:
if (elem->phy_cap_info[0] &
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
- he->max_nss_mcs[CMD_HE_MCS_BW8080] =
- he_cap->he_mcs_nss_supp.rx_mcs_80p80;
+ mt7915_mcu_set_sta_he_mcs(sta,
+ &he->max_nss_mcs[CMD_HE_MCS_BW8080],
+ mcs_mask);
- he->max_nss_mcs[CMD_HE_MCS_BW160] =
- he_cap->he_mcs_nss_supp.rx_mcs_160;
+ mt7915_mcu_set_sta_he_mcs(sta,
+ &he->max_nss_mcs[CMD_HE_MCS_BW160],
+ mcs_mask);
fallthrough;
default:
- he->max_nss_mcs[CMD_HE_MCS_BW80] =
- he_cap->he_mcs_nss_supp.rx_mcs_80;
+ mt7915_mcu_set_sta_he_mcs(sta,
+ &he->max_nss_mcs[CMD_HE_MCS_BW80],
+ mcs_mask);
break;
}
@@ -1544,27 +1685,18 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]);
}
-static int
-mt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+static void
+mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
{
- struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
- struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
- struct sk_buff *skb;
- int len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_muru);
-
- if (!sta->vht_cap.vht_supported && !sta->he_cap.has_he)
- return 0;
-
- skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
+ struct sta_rec_vht *vht;
+ struct tlv *tlv;
- /* starec muru */
- mt7915_mcu_sta_muru_tlv(skb, sta);
+ tlv = mt7915_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));
- return mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD(STA_REC_UPDATE), true);
+ vht = (struct sta_rec_vht *)tlv;
+ vht->vht_cap = cpu_to_le32(sta->vht_cap.cap);
+ vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map;
+ vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map;
}
static void
@@ -1616,17 +1748,6 @@ mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
mt7915_mcu_sta_amsdu_tlv(skb, sta);
}
- /* starec vht */
- if (sta->vht_cap.vht_supported) {
- struct sta_rec_vht *vht;
-
- tlv = mt7915_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));
- vht = (struct sta_rec_vht *)tlv;
- vht->vht_cap = cpu_to_le32(sta->vht_cap.cap);
- vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map;
- vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map;
- }
-
/* starec he */
if (sta->he_cap.has_he)
mt7915_mcu_sta_he_tlv(skb, sta);
@@ -2016,26 +2137,21 @@ mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif,
vc = mt7915_get_he_phy_cap(phy, vif);
ve = &vc->he_cap_elem;
- ebfee = !!((HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]) ||
- HE_PHY(CAP4_MU_BEAMFORMER, pe->phy_cap_info[4])) &&
+ ebfee = !!(HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]) &&
HE_PHY(CAP4_SU_BEAMFORMEE, ve->phy_cap_info[4]));
- ebf = !!((HE_PHY(CAP3_SU_BEAMFORMER, ve->phy_cap_info[3]) ||
- HE_PHY(CAP4_MU_BEAMFORMER, ve->phy_cap_info[4])) &&
+ ebf = !!(HE_PHY(CAP3_SU_BEAMFORMER, ve->phy_cap_info[3]) &&
HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]));
} else if (sta->vht_cap.vht_supported) {
struct ieee80211_sta_vht_cap *pc;
struct ieee80211_sta_vht_cap *vc;
- u32 cr, ce;
pc = &sta->vht_cap;
vc = &phy->mt76->sband_5g.sband.vht_cap;
- cr = IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
- IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
- ce = IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
- IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
- ebfee = !!((pc->cap & cr) && (vc->cap & ce));
- ebf = !!((vc->cap & cr) && (pc->cap & ce));
+ ebfee = !!((pc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) &&
+ (vc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE));
+ ebf = !!((vc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) &&
+ (pc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE));
}
/* must keep each tag independent */
@@ -2079,57 +2195,47 @@ static void
mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
struct ieee80211_vif *vif, struct ieee80211_sta *sta)
{
- struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
- struct mt76_phy *mphy = &dev->mphy;
- enum nl80211_band band;
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
+ struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
+ enum nl80211_band band = chandef->chan->band;
struct sta_rec_ra *ra;
struct tlv *tlv;
- u32 supp_rate, n_rates, cap = sta->wme ? STA_CAP_WMM : 0;
- u8 i, nss = sta->rx_nss, mcs = 0;
+ u32 supp_rate = sta->supp_rates[band];
+ u32 cap = sta->wme ? STA_CAP_WMM : 0;
tlv = mt7915_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra));
ra = (struct sta_rec_ra *)tlv;
- if (msta->wcid.ext_phy && dev->mt76.phy2)
- mphy = dev->mt76.phy2;
-
- band = mphy->chandef.chan->band;
- supp_rate = sta->supp_rates[band];
- n_rates = hweight32(supp_rate);
-
ra->valid = true;
ra->auto_rate = true;
- ra->phy_mode = mt7915_get_phy_mode(mphy, vif, sta);
- ra->channel = mphy->chandef.chan->hw_value;
+ ra->phy_mode = mt7915_get_phy_mode(vif, sta);
+ ra->channel = chandef->chan->hw_value;
ra->bw = sta->bandwidth;
- ra->rate_len = n_rates;
ra->phy.bw = sta->bandwidth;
- if (n_rates) {
+ if (supp_rate) {
+ supp_rate &= mask->control[band].legacy;
+ ra->rate_len = hweight32(supp_rate);
+
if (band == NL80211_BAND_2GHZ) {
ra->supp_mode = MODE_CCK;
ra->supp_cck_rate = supp_rate & GENMASK(3, 0);
- ra->phy.type = MT_PHY_TYPE_CCK;
- if (n_rates > 4) {
+ if (ra->rate_len > 4) {
ra->supp_mode |= MODE_OFDM;
ra->supp_ofdm_rate = supp_rate >> 4;
- ra->phy.type = MT_PHY_TYPE_OFDM;
}
} else {
ra->supp_mode = MODE_OFDM;
ra->supp_ofdm_rate = supp_rate;
- ra->phy.type = MT_PHY_TYPE_OFDM;
}
}
if (sta->ht_cap.ht_supported) {
- for (i = 0; i < nss; i++)
- ra->ht_mcs[i] = sta->ht_cap.mcs.rx_mask[i];
+ const u8 *mcs_mask = mask->control[band].ht_mcs;
- ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs;
ra->supp_mode |= MODE_HT;
- mcs = hweight32(le32_to_cpu(ra->supp_ht_mcs)) - 1;
ra->af = sta->ht_cap.ampdu_factor;
ra->ht_gf = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD);
@@ -2144,13 +2250,16 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
cap |= STA_CAP_RX_STBC;
if (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)
cap |= STA_CAP_LDPC;
+
+ mt7915_mcu_set_sta_ht_mcs(sta, ra->ht_mcs, mcs_mask);
+ ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs;
}
if (sta->vht_cap.vht_supported) {
- u16 mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.rx_mcs_map);
- u16 vht_mcs;
- u8 af, mcs_prev;
+ const u16 *mcs_mask = mask->control[band].vht_mcs;
+ u8 af;
+ ra->supp_mode |= MODE_VHT;
af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
sta->vht_cap.cap);
ra->af = max_t(u8, ra->af, af);
@@ -2167,33 +2276,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)
cap |= STA_CAP_VHT_LDPC;
- ra->supp_mode |= MODE_VHT;
- for (mcs = 0, i = 0; i < nss; i++, mcs_map >>= 2) {
- switch (mcs_map & 0x3) {
- case IEEE80211_VHT_MCS_SUPPORT_0_9:
- vht_mcs = GENMASK(9, 0);
- break;
- case IEEE80211_VHT_MCS_SUPPORT_0_8:
- vht_mcs = GENMASK(8, 0);
- break;
- case IEEE80211_VHT_MCS_SUPPORT_0_7:
- vht_mcs = GENMASK(7, 0);
- break;
- default:
- vht_mcs = 0;
- }
-
- ra->supp_vht_mcs[i] = cpu_to_le16(vht_mcs);
-
- mcs_prev = hweight16(vht_mcs) - 1;
- if (mcs_prev > mcs)
- mcs = mcs_prev;
-
- /* only support 2ss on 160MHz */
- if (i > 1 && (ra->bw == CMD_CBW_160MHZ ||
- ra->bw == CMD_CBW_8080MHZ))
- break;
- }
+ mt7915_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs, mcs_mask);
}
if (sta->he_cap.has_he) {
@@ -2201,28 +2284,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
cap |= STA_CAP_HE;
}
- ra->sta_status = cpu_to_le32(cap);
-
- switch (BIT(fls(ra->supp_mode) - 1)) {
- case MODE_VHT:
- ra->phy.type = MT_PHY_TYPE_VHT;
- ra->phy.mcs = mcs;
- ra->phy.nss = nss;
- ra->phy.stbc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC);
- ra->phy.ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
- ra->phy.sgi =
- !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80);
- break;
- case MODE_HT:
- ra->phy.type = MT_PHY_TYPE_HT;
- ra->phy.mcs = mcs;
- ra->phy.ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING;
- ra->phy.stbc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC);
- ra->phy.sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
- break;
- default:
- break;
- }
+ ra->sta_cap = cpu_to_le32(cap);
}
int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
@@ -2243,6 +2305,87 @@ int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
MCU_EXT_CMD(STA_REC_UPDATE), true);
}
+int mt7915_mcu_add_he(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ struct sk_buff *skb;
+ int len;
+
+ if (!sta->he_cap.has_he)
+ return 0;
+
+ len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_he);
+
+ skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ mt7915_mcu_sta_he_tlv(skb, sta);
+
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD(STA_REC_UPDATE), true);
+}
+
+static int
+mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+#define MT_STA_BSS_GROUP 1
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ struct {
+ __le32 action;
+ u8 wlan_idx_lo;
+ u8 status;
+ u8 wlan_idx_hi;
+ u8 rsv0[5];
+ __le32 val;
+ u8 rsv1[8];
+ } __packed req = {
+ .action = cpu_to_le32(MT_STA_BSS_GROUP),
+ .wlan_idx_lo = to_wcid_lo(msta->wcid.idx),
+ .wlan_idx_hi = to_wcid_hi(msta->wcid.idx),
+ .val = cpu_to_le32(mvif->idx % 16),
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_DRR_CTRL), &req,
+ sizeof(req), true);
+}
+
+static int
+mt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ struct sk_buff *skb;
+ int ret;
+
+ if (!sta->vht_cap.vht_supported && !sta->he_cap.has_he)
+ return 0;
+
+ ret = mt7915_mcu_add_group(dev, vif, sta);
+ if (ret)
+ return ret;
+
+ skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta,
+ MT7915_STA_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ /* wait until TxBF and MU ready to update stare vht */
+
+ /* starec muru */
+ mt7915_mcu_sta_muru_tlv(skb, sta);
+ /* starec vht */
+ mt7915_mcu_sta_vht_tlv(skb, sta);
+
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD(STA_REC_UPDATE), true);
+}
+
int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enable)
{
@@ -2253,17 +2396,14 @@ int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif,
/* must keep the order */
ret = mt7915_mcu_add_txbf(dev, vif, sta, enable);
- if (ret)
+ if (ret || !enable)
return ret;
ret = mt7915_mcu_add_mu(dev, vif, sta);
if (ret)
return ret;
- if (enable)
- return mt7915_mcu_add_rate_ctrl(dev, vif, sta);
-
- return 0;
+ return mt7915_mcu_add_rate_ctrl(dev, vif, sta);
}
int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
@@ -2432,7 +2572,7 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct sk_buff *rskb,
cont->csa_ofs = cpu_to_le16(offs->cntdwn_counter_offs[0] - 4);
buf = (u8 *)tlv + sizeof(*cont);
- mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL,
+ mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL,
true);
memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
}
@@ -3307,7 +3447,8 @@ int mt7915_mcu_set_eeprom(struct mt7915_dev *dev)
int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset)
{
struct mt7915_mcu_eeprom_info req = {
- .addr = cpu_to_le32(round_down(offset, 16)),
+ .addr = cpu_to_le32(round_down(offset,
+ MT7915_EEPROM_BLOCK_SIZE)),
};
struct mt7915_mcu_eeprom_info *res;
struct sk_buff *skb;
@@ -3321,7 +3462,7 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset)
res = (struct mt7915_mcu_eeprom_info *)skb->data;
buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr);
- memcpy(buf, res->data, 16);
+ memcpy(buf, res->data, MT7915_EEPROM_BLOCK_SIZE);
dev_kfree_skb(skb);
return 0;
@@ -3440,8 +3581,9 @@ int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
- u16 total = 2, idx, center_freq = chandef->center_freq1;
+ u16 total = 2, center_freq = chandef->center_freq1;
u8 *cal = dev->cal, *eep = dev->mt76.eeprom.data;
+ int idx;
if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_DPD))
return 0;
@@ -3469,22 +3611,128 @@ int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy)
return 0;
}
-int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index)
+int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch)
+{
+ /* strict order */
+ static const enum mt7915_chan_mib_offs offs[] = {
+ MIB_BUSY_TIME, MIB_TX_TIME, MIB_RX_TIME, MIB_OBSS_AIRTIME
+ };
+ struct mt76_channel_state *state = phy->mt76->chan_state;
+ struct mt76_channel_state *state_ts = &phy->state_ts;
+ struct mt7915_dev *dev = phy->dev;
+ struct mt7915_mcu_mib *res, req[4];
+ struct sk_buff *skb;
+ int i, ret;
+
+ for (i = 0; i < 4; i++) {
+ req[i].band = cpu_to_le32(phy != &dev->phy);
+ req[i].offs = cpu_to_le32(offs[i]);
+ }
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(GET_MIB_INFO),
+ req, sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ res = (struct mt7915_mcu_mib *)(skb->data + 20);
+
+ if (chan_switch)
+ goto out;
+
+#define __res_u64(s) le64_to_cpu(res[s].data)
+ state->cc_busy += __res_u64(0) - state_ts->cc_busy;
+ state->cc_tx += __res_u64(1) - state_ts->cc_tx;
+ state->cc_bss_rx += __res_u64(2) - state_ts->cc_bss_rx;
+ state->cc_rx += __res_u64(2) + __res_u64(3) - state_ts->cc_rx;
+
+out:
+ state_ts->cc_busy = __res_u64(0);
+ state_ts->cc_tx = __res_u64(1);
+ state_ts->cc_bss_rx = __res_u64(2);
+ state_ts->cc_rx = __res_u64(2) + __res_u64(3);
+#undef __res_u64
+
+ dev_kfree_skb(skb);
+
+ return 0;
+}
+
+int mt7915_mcu_get_temperature(struct mt7915_phy *phy)
{
+ struct mt7915_dev *dev = phy->dev;
struct {
u8 ctrl_id;
u8 action;
- u8 band;
+ u8 dbdc_idx;
u8 rsv[5];
} req = {
.ctrl_id = THERMAL_SENSOR_TEMP_QUERY,
- .action = index,
+ .dbdc_idx = phy != &dev->phy,
};
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req,
sizeof(req), true);
}
+int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state)
+{
+ struct mt7915_dev *dev = phy->dev;
+ struct {
+ struct mt7915_mcu_thermal_ctrl ctrl;
+
+ __le32 trigger_temp;
+ __le32 restore_temp;
+ __le16 sustain_time;
+ u8 rsv[2];
+ } __packed req = {
+ .ctrl = {
+ .band_idx = phy != &dev->phy,
+ },
+ };
+ int level;
+
+#define TRIGGER_TEMPERATURE 122
+#define RESTORE_TEMPERATURE 116
+#define SUSTAIN_PERIOD 10
+
+ if (!state) {
+ req.ctrl.ctrl_id = THERMAL_PROTECT_DISABLE;
+ goto out;
+ }
+
+ /* set duty cycle and level */
+ for (level = 0; level < 4; level++) {
+ int ret;
+
+ req.ctrl.ctrl_id = THERMAL_PROTECT_DUTY_CONFIG;
+ req.ctrl.duty.duty_level = level;
+ req.ctrl.duty.duty_cycle = state;
+ state = state * 4 / 5;
+
+ ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
+ &req, sizeof(req.ctrl), false);
+ if (ret)
+ return ret;
+ }
+
+ /* currently use fixed values for throttling, and would be better
+ * to implement thermal zone for dynamic trip in the long run.
+ */
+
+ /* set high-temperature trigger threshold */
+ req.ctrl.ctrl_id = THERMAL_PROTECT_ENABLE;
+ req.trigger_temp = cpu_to_le32(TRIGGER_TEMPERATURE);
+ req.restore_temp = cpu_to_le32(RESTORE_TEMPERATURE);
+ req.sustain_time = cpu_to_le16(SUSTAIN_PERIOD);
+
+out:
+ req.ctrl.type.protect_type = 1;
+ req.ctrl.type.trigger_type = 1;
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
+ &req, sizeof(req), false);
+}
+
int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx)
{
struct {
@@ -3505,7 +3753,6 @@ int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx)
int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
{
-#define MT7915_SKU_RATE_NUM 161
struct mt7915_dev *dev = phy->dev;
struct mt76_phy *mphy = phy->mt76;
struct ieee80211_hw *hw = mphy->hw;
@@ -3555,6 +3802,39 @@ int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
sizeof(req), true);
}
+int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
+{
+#define RATE_POWER_INFO 2
+ struct mt7915_dev *dev = phy->dev;
+ struct {
+ u8 format_id;
+ u8 category;
+ u8 band;
+ u8 _rsv;
+ } __packed req = {
+ .format_id = 7,
+ .category = RATE_POWER_INFO,
+ .band = phy != &dev->phy,
+ };
+ s8 res[MT7915_SKU_RATE_NUM][2];
+ struct sk_buff *skb;
+ int ret, i;
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76,
+ MCU_EXT_CMD(TX_POWER_FEATURE_CTRL),
+ &req, sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ memcpy(res, skb->data + 4, sizeof(res));
+ for (i = 0; i < len; i++)
+ txpower[i] = res[i][req.band];
+
+ dev_kfree_skb(skb);
+
+ return 0;
+}
+
int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode,
u8 en)
{
@@ -3613,57 +3893,50 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band)
&req, sizeof(req), false);
}
-int mt7915_mcu_set_txbf_module(struct mt7915_dev *dev)
-{
-#define MT_BF_MODULE_UPDATE 25
- struct {
- u8 action;
- u8 bf_num;
- u8 bf_bitmap;
- u8 bf_sel[8];
- u8 rsv[8];
- } __packed req = {
- .action = MT_BF_MODULE_UPDATE,
- .bf_num = 2,
- .bf_bitmap = GENMASK(1, 0),
- };
-
- return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req,
- sizeof(req), true);
-}
-
-int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev)
+int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action)
{
-#define MT_BF_TYPE_UPDATE 20
struct {
u8 action;
- bool ebf;
- bool ibf;
- u8 rsv;
+ union {
+ struct {
+ u8 snd_mode;
+ u8 sta_num;
+ u8 rsv;
+ u8 wlan_idx[4];
+ __le32 snd_period; /* ms */
+ } __packed snd;
+ struct {
+ bool ebf;
+ bool ibf;
+ u8 rsv;
+ } __packed type;
+ struct {
+ u8 bf_num;
+ u8 bf_bitmap;
+ u8 bf_sel[8];
+ u8 rsv[5];
+ } __packed mod;
+ };
} __packed req = {
- .action = MT_BF_TYPE_UPDATE,
- .ebf = true,
- .ibf = dev->ibf,
+ .action = action,
};
- return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req,
- sizeof(req), true);
-}
-
-int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev)
-{
-#define MT_BF_PROCESSING 4
- struct {
- u8 action;
- u8 snd_mode;
- u8 sta_num;
- u8 rsv;
- u8 wlan_idx[4];
- __le32 snd_period; /* ms */
- } __packed req = {
- .action = true,
- .snd_mode = MT_BF_PROCESSING,
- };
+#define MT_BF_PROCESSING 4
+ switch (action) {
+ case MT_BF_SOUNDING_ON:
+ req.snd.snd_mode = MT_BF_PROCESSING;
+ break;
+ case MT_BF_TYPE_UPDATE:
+ req.type.ebf = true;
+ req.type.ibf = dev->ibf;
+ break;
+ case MT_BF_MODULE_UPDATE:
+ req.mod.bf_num = 2;
+ req.mod.bf_bitmap = GENMASK(1, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req,
sizeof(req), true);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
index 42582a66e42d..edd3ba3a0c2d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
@@ -68,6 +68,29 @@ struct mt7915_mcu_rxd {
u8 s2d_index;
};
+struct mt7915_mcu_thermal_ctrl {
+ u8 ctrl_id;
+ u8 band_idx;
+ union {
+ struct {
+ u8 protect_type; /* 1: duty admit, 2: radio off */
+ u8 trigger_type; /* 0: low, 1: high */
+ } __packed type;
+ struct {
+ u8 duty_level; /* level 0~3 */
+ u8 duty_cycle;
+ } __packed duty;
+ };
+} __packed;
+
+struct mt7915_mcu_thermal_notify {
+ struct mt7915_mcu_rxd rxd;
+
+ struct mt7915_mcu_thermal_ctrl ctrl;
+ __le32 temperature;
+ u8 rsv[8];
+} __packed;
+
struct mt7915_mcu_csa_notify {
struct mt7915_mcu_rxd rxd;
@@ -193,6 +216,19 @@ struct mt7915_mcu_phy_rx_info {
#define MT_RA_RATE_DCM_EN BIT(4)
#define MT_RA_RATE_BW GENMASK(14, 13)
+struct mt7915_mcu_mib {
+ __le32 band;
+ __le32 offs;
+ __le64 data;
+} __packed;
+
+enum mt7915_chan_mib_offs {
+ MIB_BUSY_TIME = 14,
+ MIB_TX_TIME = 81,
+ MIB_RX_TIME,
+ MIB_OBSS_AIRTIME = 86
+};
+
struct edca {
u8 queue;
u8 set;
@@ -262,6 +298,7 @@ enum {
MCU_EXT_CMD_FW_LOG_2_HOST = 0x13,
MCU_EXT_CMD_TXBF_ACTION = 0x1e,
MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21,
+ MCU_EXT_CMD_THERMAL_PROT = 0x23,
MCU_EXT_CMD_STA_REC_UPDATE = 0x25,
MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26,
MCU_EXT_CMD_EDCA_UPDATE = 0x27,
@@ -277,6 +314,7 @@ enum {
MCU_EXT_CMD_MUAR_UPDATE = 0x48,
MCU_EXT_CMD_SET_RX_PATH = 0x4e,
MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58,
+ MCU_EXT_CMD_GET_MIB_INFO = 0x5a,
MCU_EXT_CMD_MWDS_SUPPORT = 0x80,
MCU_EXT_CMD_SET_SER_TRIGGER = 0x81,
MCU_EXT_CMD_SCS_CTRL = 0x82,
@@ -919,7 +957,7 @@ struct sta_rec_ra {
u8 op_vht_rx_nss;
u8 op_vht_rx_nss_type;
- __le32 sta_status;
+ __le32 sta_cap;
struct ra_phy phy;
} __packed;
@@ -1034,18 +1072,17 @@ enum {
STA_REC_MAX_NUM
};
-enum mt7915_cipher_type {
- MT_CIPHER_NONE,
- MT_CIPHER_WEP40,
- MT_CIPHER_WEP104,
- MT_CIPHER_WEP128,
- MT_CIPHER_TKIP,
- MT_CIPHER_AES_CCMP,
- MT_CIPHER_CCMP_256,
- MT_CIPHER_GCMP,
- MT_CIPHER_GCMP_256,
- MT_CIPHER_WAPI,
- MT_CIPHER_BIP_CMAC_128,
+enum mcu_cipher_type {
+ MCU_CIPHER_WEP40 = 1,
+ MCU_CIPHER_WEP104,
+ MCU_CIPHER_WEP128,
+ MCU_CIPHER_TKIP,
+ MCU_CIPHER_AES_CCMP,
+ MCU_CIPHER_CCMP_256,
+ MCU_CIPHER_GCMP,
+ MCU_CIPHER_GCMP_256,
+ MCU_CIPHER_WAPI,
+ MCU_CIPHER_BIP_CMAC_128,
};
enum {
@@ -1067,10 +1104,27 @@ enum {
};
enum {
+ THERMAL_PROTECT_PARAMETER_CTRL,
+ THERMAL_PROTECT_BASIC_INFO,
+ THERMAL_PROTECT_ENABLE,
+ THERMAL_PROTECT_DISABLE,
+ THERMAL_PROTECT_DUTY_CONFIG,
+ THERMAL_PROTECT_MECH_INFO,
+ THERMAL_PROTECT_DUTY_INFO,
+ THERMAL_PROTECT_STATE_ACT,
+};
+
+enum {
MT_EBF = BIT(0), /* explicit beamforming */
MT_IBF = BIT(1) /* implicit beamforming */
};
+enum {
+ MT_BF_SOUNDING_ON = 1,
+ MT_BF_TYPE_UPDATE = 20,
+ MT_BF_MODULE_UPDATE = 25
+};
+
#define MT7915_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_req_hdr) + \
sizeof(struct wtbl_generic) + \
sizeof(struct wtbl_rx) + \
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index 4ea8972d4e2f..3f613fae6218 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -9,7 +9,7 @@
#include "../mt76.h"
#include "regs.h"
-#define MT7915_MAX_INTERFACES 32
+#define MT7915_MAX_INTERFACES 19
#define MT7915_MAX_WMM_SETS 4
#define MT7915_WTBL_SIZE 288
#define MT7915_WTBL_RESERVED (MT7915_WTBL_SIZE - 1)
@@ -31,6 +31,7 @@
#define MT7915_ROM_PATCH "mediatek/mt7915_rom_patch.bin"
#define MT7915_EEPROM_SIZE 3584
+#define MT7915_EEPROM_BLOCK_SIZE 16
#define MT7915_TOKEN_SIZE 8192
#define MT7915_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
@@ -38,6 +39,10 @@
#define MT7915_5G_RATE_DEFAULT 0x4b /* OFDM 6M */
#define MT7915_2G_RATE_DEFAULT 0x0 /* CCK 1M */
+#define MT7915_THERMAL_THROTTLE_MAX 100
+
+#define MT7915_SKU_RATE_NUM 161
+
struct mt7915_vif;
struct mt7915_sta;
struct mt7915_dfs_pulse;
@@ -100,6 +105,7 @@ struct mt7915_vif {
struct mt7915_phy *phy;
struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
+ struct cfg80211_bitrate_mask bitrate_mask;
};
struct mib_stats {
@@ -126,6 +132,9 @@ struct mt7915_phy {
struct ieee80211_vif *monitor_vif;
+ struct thermal_cooling_device *cdev;
+ u8 throttle_state;
+
u32 rxfilter;
u64 omac_mask;
@@ -141,6 +150,7 @@ struct mt7915_phy {
u32 ampdu_ref;
struct mib_stats mib;
+ struct mt76_channel_state state_ts;
struct list_head stats_list;
u8 sta_work_count;
@@ -169,6 +179,7 @@ struct mt7915_dev {
struct mt7915_hif *hif2;
const struct mt76_bus_ops *bus_ops;
+ struct tasklet_struct irq_tasklet;
struct mt7915_phy phy;
u16 chainmask;
@@ -322,6 +333,8 @@ int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif,
bool enable);
int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
+int mt7915_mcu_add_he(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int mt7915_set_channel(struct mt7915_phy *phy);
@@ -342,9 +355,8 @@ int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val);
int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter);
int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable);
int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy);
-int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev);
-int mt7915_mcu_set_txbf_module(struct mt7915_dev *dev);
-int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev);
+int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len);
+int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action);
int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val);
int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev,
const struct mt7915_dfs_pulse *pulse);
@@ -352,7 +364,9 @@ int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index,
const struct mt7915_dfs_pattern *pattern);
int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev);
int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy);
-int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index);
+int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch);
+int mt7915_mcu_get_temperature(struct mt7915_phy *phy);
+int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state);
int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx);
int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct rate_info *rate);
@@ -374,9 +388,11 @@ void mt7915_dual_hif_set_irq_mask(struct mt7915_dev *dev, bool write_reg,
static inline void mt7915_irq_enable(struct mt7915_dev *dev, u32 mask)
{
if (dev->hif2)
- mt7915_dual_hif_set_irq_mask(dev, true, 0, mask);
+ mt7915_dual_hif_set_irq_mask(dev, false, 0, mask);
else
- mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, 0, mask);
+ mt76_set_irq_mask(&dev->mt76, 0, 0, mask);
+
+ tasklet_schedule(&dev->irq_tasklet);
}
static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask)
@@ -392,12 +408,9 @@ void mt7915_mac_reset_counters(struct mt7915_phy *phy);
void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy);
void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy);
void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
- struct sk_buff *skb, struct mt76_wcid *wcid,
+ struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
struct ieee80211_key_conf *key, bool beacon);
void mt7915_mac_set_timing(struct mt7915_phy *phy);
-int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb);
-void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb);
-void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb);
int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
@@ -417,13 +430,11 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb);
void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
void mt7915_stats_work(struct work_struct *work);
-void mt7915_txp_skb_unmap(struct mt76_dev *dev,
- struct mt76_txwi_cache *txwi);
int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force);
int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy);
void mt7915_set_stream_he_caps(struct mt7915_phy *phy);
void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy);
-void mt7915_update_channel(struct mt76_dev *mdev);
+void mt7915_update_channel(struct mt76_phy *mphy);
int mt7915_init_debugfs(struct mt7915_dev *dev);
#ifdef CONFIG_MAC80211_DEBUGFS
void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
index 643f171884cf..340b364da5f0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
@@ -94,11 +94,15 @@ mt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
}
/* TODO: support 2/4/6/8 MSI-X vectors */
-static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
+static void mt7915_irq_tasklet(struct tasklet_struct *t)
{
- struct mt7915_dev *dev = dev_instance;
+ struct mt7915_dev *dev = from_tasklet(dev, t, irq_tasklet);
u32 intr, intr1, mask;
+ mt76_wr(dev, MT_INT_MASK_CSR, 0);
+ if (dev->hif2)
+ mt76_wr(dev, MT_INT1_MASK_CSR, 0);
+
intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
intr &= dev->mt76.mmio.irqmask;
mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
@@ -111,9 +115,6 @@ static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
intr |= intr1;
}
- if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
- return IRQ_NONE;
-
trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);
mask = intr & MT_INT_RX_DONE_ALL;
@@ -150,6 +151,20 @@ static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
wake_up(&dev->reset_wait);
}
}
+}
+
+static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
+{
+ struct mt7915_dev *dev = dev_instance;
+
+ mt76_wr(dev, MT_INT_MASK_CSR, 0);
+ if (dev->hif2)
+ mt76_wr(dev, MT_INT1_MASK_CSR, 0);
+
+ if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
+ return IRQ_NONE;
+
+ tasklet_schedule(&dev->irq_tasklet);
return IRQ_HANDLED;
}
@@ -240,6 +255,8 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
if (ret)
return ret;
+ mt76_pci_disable_aspm(pdev);
+
if (id->device == 0x7916)
return mt7915_pci_hif2_probe(pdev);
@@ -250,10 +267,18 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
dev = container_of(mdev, struct mt7915_dev, mt76);
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+ if (ret < 0)
+ goto free;
+
ret = mt7915_mmio_init(mdev, pcim_iomap_table(pdev)[0], pdev->irq);
if (ret)
goto error;
+ tasklet_setup(&dev->irq_tasklet, mt7915_irq_tasklet);
+
+ mt76_wr(dev, MT_INT_MASK_CSR, 0);
+
/* master switch of PCIe tnterrupt enable */
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
@@ -266,10 +291,14 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
ret = mt7915_register_device(dev);
if (ret)
- goto error;
+ goto free_irq;
return 0;
+free_irq:
+ devm_free_irq(mdev->dev, pdev->irq, dev);
error:
+ pci_free_irq_vectors(pdev);
+free:
mt76_free_device(&dev->mt76);
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
index efe0f2904c66..a213b5cb82f8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
@@ -82,11 +82,6 @@
#define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17)
#define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18)
-#define MT_TMAC_FP0R0(_band) MT_WF_TMAC(_band, 0x020)
-#define MT_TMAC_FP0R15(_band) MT_WF_TMAC(_band, 0x080)
-#define MT_TMAC_FP0R18(_band) MT_WF_TMAC(_band, 0x270)
-#define MT_TMAC_FP_MASK GENMASK(7, 0)
-
#define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0)
#define MT_WF_DMA_BASE(_band) ((_band) ? 0xa1e00 : 0x21e00)
@@ -104,6 +99,11 @@
#define MT_ETBF_TX_FB_CPL GENMASK(31, 16)
#define MT_ETBF_TX_FB_TRI GENMASK(15, 0)
+#define MT_ETBF_RX_FB_CONT(_band) MT_WF_ETBF(_band, 0x068)
+#define MT_ETBF_RX_FB_BW GENMASK(7, 6)
+#define MT_ETBF_RX_FB_NC GENMASK(5, 3)
+#define MT_ETBF_RX_FB_NR GENMASK(2, 0)
+
#define MT_ETBF_TX_APP_CNT(_band) MT_WF_ETBF(_band, 0x0f0)
#define MT_ETBF_TX_IBF_CNT GENMASK(31, 16)
#define MT_ETBF_TX_EBF_CNT GENMASK(15, 0)
@@ -124,6 +124,8 @@
#define MT_LPON_TCR(_band, n) MT_WF_LPON(_band, 0x0a8 + (n) * 4)
#define MT_LPON_TCR_SW_MODE GENMASK(1, 0)
#define MT_LPON_TCR_SW_WRITE BIT(0)
+#define MT_LPON_TCR_SW_ADJUST BIT(1)
+#define MT_LPON_TCR_SW_READ GENMASK(1, 0)
/* MIB: band 0(0x24800), band 1(0xa4800) */
#define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800)
@@ -132,20 +134,9 @@
#define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x014)
#define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(15, 0)
-#define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c)
-#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0)
-
-#define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048)
-#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0)
-
#define MT_MIB_SDR34(_band) MT_WF_MIB(_band, 0x090)
#define MT_MIB_MU_BF_TX_CNT GENMASK(15, 0)
-#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x098)
-#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0)
-#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c)
-#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0)
-
#define MT_MIB_DR8(_band) MT_WF_MIB(_band, 0x0c0)
#define MT_MIB_DR9(_band) MT_WF_MIB(_band, 0x0c4)
#define MT_MIB_DR11(_band) MT_WF_MIB(_band, 0x0cc)
@@ -158,9 +149,6 @@
#define MT_MIB_BA_MISS_COUNT_MASK GENMASK(15, 0)
#define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(31, 16)
-#define MT_MIB_MB_SDR2(_band, n) MT_WF_MIB(_band, 0x108 + ((n) << 4))
-#define MT_MIB_FRAME_RETRIES_COUNT_MASK GENMASK(15, 0)
-
#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0x0a8 + ((n) << 2))
#define MT_TX_AGG_CNT2(_band, n) MT_WF_MIB(_band, 0x164 + ((n) << 2))
#define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x4b8 + ((n) << 2))
@@ -258,14 +246,10 @@
#define MT_WF_RFCR1_DROP_CFEND BIT(7)
#define MT_WF_RFCR1_DROP_CFACK BIT(8)
-#define MT_WF_RMAC_MIB_TIME0(_band) MT_WF_RMAC(_band, 0x03c4)
+#define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380)
#define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31)
#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30)
-#define MT_WF_RMAC_MIB_AIRTIME14(_band) MT_WF_RMAC(_band, 0x03b8)
-#define MT_MIB_OBSSTIME_MASK GENMASK(23, 0)
-#define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380)
-
/* WFDMA0 */
#define MT_WFDMA0_BASE 0xd4000
#define MT_WFDMA0(ofs) (MT_WFDMA0_BASE + (ofs))
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
index f9d81e36ef09..b220b334906b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
@@ -464,10 +464,17 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en)
static void
mt7915_tm_set_rx_frames(struct mt7915_phy *phy, bool en)
{
- if (en)
+ mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, false);
+
+ if (en) {
+ struct mt7915_dev *dev = phy->dev;
+
mt7915_tm_update_channel(phy);
- mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, en);
+ /* read-clear */
+ mt76_rr(dev, MT_MIB_SDR3(phy != &dev->phy));
+ mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, en);
+ }
}
static int
@@ -690,7 +697,11 @@ static int
mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg)
{
struct mt7915_phy *phy = mphy->priv;
+ struct mt7915_dev *dev = phy->dev;
+ bool ext_phy = phy != &dev->phy;
+ enum mt76_rxq_id q;
void *rx, *rssi;
+ u16 fcs_err;
int i;
rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX);
@@ -735,6 +746,12 @@ mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg)
nla_nest_end(msg, rx);
+ fcs_err = mt76_get_field(dev, MT_MIB_SDR3(ext_phy),
+ MT_MIB_SDR3_FCS_ERR_MASK);
+ q = ext_phy ? MT_RXQ_EXT : MT_RXQ_MAIN;
+ mphy->test.rx_stats.packets[q] += fcs_err;
+ mphy->test.rx_stats.fcs_error[q] += fcs_err;
+
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h
index 8f8533ef9859..397a6b5532bc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: ISC
+/* SPDX-License-Identifier: ISC */
/* Copyright (C) 2020 MediaTek Inc. */
#ifndef __MT7915_TESTMODE_H
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
index e531666f9fb4..0ebb59966a08 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
@@ -1,4 +1,4 @@
-#SPDX-License-Identifier: ISC
+# SPDX-License-Identifier: ISC
obj-$(CONFIG_MT7921E) += mt7921e.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
index 6ee423dd4027..77468bdae460 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
@@ -184,7 +184,10 @@ mt7921_txpwr(struct seq_file *s, void *data)
struct mt7921_txpwr txpwr;
int ret;
+ mt7921_mutex_acquire(dev);
ret = mt7921_get_txpwr_info(dev, &txpwr);
+ mt7921_mutex_release(dev);
+
if (ret)
return ret;
@@ -247,6 +250,9 @@ mt7921_pm_set(void *data, u64 val)
ieee80211_iterate_active_interfaces(mphy->hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_pm_interface_iter, mphy->priv);
+
+ mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable);
+
mt7921_mutex_release(dev);
return 0;
@@ -265,6 +271,36 @@ mt7921_pm_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7921_pm_get, mt7921_pm_set, "%lld\n");
static int
+mt7921_deep_sleep_set(void *data, u64 val)
+{
+ struct mt7921_dev *dev = data;
+ struct mt76_connac_pm *pm = &dev->pm;
+ bool enable = !!val;
+
+ mt7921_mutex_acquire(dev);
+ if (pm->ds_enable != enable) {
+ mt76_connac_mcu_set_deep_sleep(&dev->mt76, enable);
+ pm->ds_enable = enable;
+ }
+ mt7921_mutex_release(dev);
+
+ return 0;
+}
+
+static int
+mt7921_deep_sleep_get(void *data, u64 *val)
+{
+ struct mt7921_dev *dev = data;
+
+ *val = dev->pm.ds_enable;
+
+ return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_ds, mt7921_deep_sleep_get,
+ mt7921_deep_sleep_set, "%lld\n");
+
+static int
mt7921_pm_stats(struct seq_file *s, void *data)
{
struct mt7921_dev *dev = dev_get_drvdata(s->private);
@@ -355,6 +391,7 @@ int mt7921_init_debugfs(struct mt7921_dev *dev)
debugfs_create_file("chip_reset", 0600, dir, dev, &fops_reset);
debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir,
mt7921_pm_stats);
+ debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds);
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
index 71e664ee7652..7d7d43a5422f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
@@ -74,7 +74,7 @@ static int mt7921_poll_tx(struct napi_struct *napi, int budget)
mt7921_tx_cleanup(dev);
if (napi_complete(napi))
mt7921_irq_enable(dev, MT_INT_TX_DONE_ALL);
- mt76_connac_pm_unref(&dev->pm);
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
return 0;
}
@@ -92,7 +92,7 @@ static int mt7921_poll_rx(struct napi_struct *napi, int budget)
return 0;
}
done = mt76_dma_rx_poll(napi, budget);
- mt76_connac_pm_unref(&dev->pm);
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
return done;
}
@@ -313,9 +313,9 @@ static int mt7921_dma_reset(struct mt7921_dev *dev, bool force)
int mt7921_wfsys_reset(struct mt7921_dev *dev)
{
- mt76_set(dev, 0x70002600, BIT(0));
- msleep(200);
- mt76_clear(dev, 0x70002600, BIT(0));
+ mt76_clear(dev, MT_WFSYS_SW_RST_B, WFSYS_SW_RST_B);
+ msleep(50);
+ mt76_set(dev, MT_WFSYS_SW_RST_B, WFSYS_SW_RST_B);
if (!__mt76_poll_msec(&dev->mt76, MT_WFSYS_SW_RST_B,
WFSYS_SW_INIT_DONE, WFSYS_SW_INIT_DONE, 500))
@@ -380,9 +380,7 @@ int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev)
int mt7921_dma_init(struct mt7921_dev *dev)
{
- /* Increase buffer size to receive large VHT/HE MPDUs */
struct mt76_bus_ops *bus_ops;
- int rx_buf_size = MT_RX_BUF_SIZE * 2;
int ret;
dev->bus_ops = dev->mt76.bus;
@@ -402,6 +400,10 @@ int mt7921_dma_init(struct mt7921_dev *dev)
if (ret)
return ret;
+ ret = mt7921_wfsys_reset(dev);
+ if (ret)
+ return ret;
+
/* init tx queue */
ret = mt7921_init_tx_queues(&dev->phy, MT7921_TXQ_BAND0,
MT7921_TX_RING_SIZE);
@@ -426,7 +428,7 @@ int mt7921_dma_init(struct mt7921_dev *dev)
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU],
MT7921_RXQ_MCU_WM,
MT7921_RX_MCU_RING_SIZE,
- rx_buf_size, MT_RX_EVENT_RING_BASE);
+ MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE);
if (ret)
return ret;
@@ -434,14 +436,14 @@ int mt7921_dma_init(struct mt7921_dev *dev)
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
MT7921_RXQ_MCU_WM,
MT7921_RX_MCU_RING_SIZE,
- rx_buf_size, MT_WFDMA0(0x540));
+ MT_RX_BUF_SIZE, MT_WFDMA0(0x540));
if (ret)
return ret;
/* rx data */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN],
MT7921_RXQ_BAND0, MT7921_RX_RING_SIZE,
- rx_buf_size, MT_RX_DATA_RING_BASE);
+ MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE);
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index 1763ea0614ce..a9ce10b98827 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -7,34 +7,6 @@
#include "mcu.h"
#include "eeprom.h"
-#define CCK_RATE(_idx, _rate) { \
- .bitrate = _rate, \
- .flags = IEEE80211_RATE_SHORT_PREAMBLE, \
- .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \
- .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)), \
-}
-
-#define OFDM_RATE(_idx, _rate) { \
- .bitrate = _rate, \
- .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
- .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
-}
-
-static struct ieee80211_rate mt7921_rates[] = {
- CCK_RATE(0, 10),
- CCK_RATE(1, 20),
- CCK_RATE(2, 55),
- CCK_RATE(3, 110),
- OFDM_RATE(11, 60),
- OFDM_RATE(15, 90),
- OFDM_RATE(10, 120),
- OFDM_RATE(14, 180),
- OFDM_RATE(9, 240),
- OFDM_RATE(13, 360),
- OFDM_RATE(8, 480),
- OFDM_RATE(12, 540),
-};
-
static const struct ieee80211_iface_limit if_limits[] = {
{
.max = MT7921_MAX_INTERFACES,
@@ -73,11 +45,13 @@ static void
mt7921_init_wiphy(struct ieee80211_hw *hw)
{
struct mt7921_phy *phy = mt7921_hw_phy(hw);
+ struct mt7921_dev *dev = phy->dev;
struct wiphy *wiphy = hw->wiphy;
hw->queues = 4;
hw->max_rx_aggregation_subframes = 64;
hw->max_tx_aggregation_subframes = 128;
+ hw->netdev_features = NETIF_F_RXCSUM;
hw->radiotap_timestamp.units_pos =
IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US;
@@ -88,11 +62,13 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
hw->vif_data_size = sizeof(struct mt7921_vif);
wiphy->iface_combinations = if_comb;
+ wiphy->flags &= ~WIPHY_FLAG_IBSS_RSN;
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN;
wiphy->max_scan_ssids = 4;
wiphy->max_sched_scan_plan_interval =
- MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL;
+ MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL;
wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN;
wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID;
wiphy->max_match_sets = MT76_CONNAC_MAX_SCAN_MATCH;
@@ -100,46 +76,33 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
wiphy->reg_notifier = mt7921_regd_notifier;
- wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
+ wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
+ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
ieee80211_hw_set(hw, HAS_RATE_CONTROL);
ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
+ ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
ieee80211_hw_set(hw, WANT_MONITOR_VIF);
ieee80211_hw_set(hw, SUPPORTS_PS);
ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+ if (dev->pm.enable)
+ ieee80211_hw_set(hw, CONNECTION_MONITOR);
+
hw->max_tx_fragments = 4;
}
static void
mt7921_mac_init_band(struct mt7921_dev *dev, u8 band)
{
- u32 mask, set;
-
mt76_rmw_field(dev, MT_TMAC_CTCR0(band),
MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f);
mt76_set(dev, MT_TMAC_CTCR0(band),
MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN |
MT_TMAC_CTCR0_INS_DDLMT_EN);
- mask = MT_MDP_RCFR0_MCU_RX_MGMT |
- MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR |
- MT_MDP_RCFR0_MCU_RX_CTL_BAR;
- set = FIELD_PREP(MT_MDP_RCFR0_MCU_RX_MGMT, MT_MDP_TO_HIF) |
- FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR, MT_MDP_TO_HIF) |
- FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_BAR, MT_MDP_TO_HIF);
- mt76_rmw(dev, MT_MDP_BNRCFR0(band), mask, set);
-
- mask = MT_MDP_RCFR1_MCU_RX_BYPASS |
- MT_MDP_RCFR1_RX_DROPPED_UCAST |
- MT_MDP_RCFR1_RX_DROPPED_MCAST;
- set = FIELD_PREP(MT_MDP_RCFR1_MCU_RX_BYPASS, MT_MDP_TO_HIF) |
- FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_UCAST, MT_MDP_TO_HIF) |
- FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF);
- mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set);
-
mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
@@ -148,14 +111,15 @@ mt7921_mac_init_band(struct mt7921_dev *dev, u8 band)
mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
}
-void mt7921_mac_init(struct mt7921_dev *dev)
+int mt7921_mac_init(struct mt7921_dev *dev)
{
int i;
mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536);
- /* disable hardware de-agg */
- mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN);
- mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_RX_HDR_TRANS_EN);
+ /* enable hardware de-agg */
+ mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN);
+ /* enable hardware rx header translation */
+ mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_RX_HDR_TRANS_EN);
for (i = 0; i < MT7921_WTBL_SIZE; i++)
mt7921_mac_wtbl_update(dev, i,
@@ -163,7 +127,7 @@ void mt7921_mac_init(struct mt7921_dev *dev)
for (i = 0; i < 2; i++)
mt7921_mac_init_band(dev, i);
- mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0);
+ return mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0);
}
static int mt7921_init_hardware(struct mt7921_dev *dev)
@@ -203,9 +167,7 @@ static int mt7921_init_hardware(struct mt7921_dev *dev)
dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET;
rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid);
- mt7921_mac_init(dev);
-
- return 0;
+ return mt7921_mac_init(dev);
}
int mt7921_register_device(struct mt7921_dev *dev)
@@ -224,7 +186,6 @@ int mt7921_register_device(struct mt7921_dev *dev)
mutex_init(&dev->pm.mutex);
init_waitqueue_head(&dev->pm.wait);
spin_lock_init(&dev->pm.txq_lock);
- set_bit(MT76_STATE_PM, &dev->mphy.state);
INIT_LIST_HEAD(&dev->phy.stats_list);
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7921_mac_work);
INIT_DELAYED_WORK(&dev->phy.scan_work, mt7921_scan_work);
@@ -239,6 +200,8 @@ int mt7921_register_device(struct mt7921_dev *dev)
dev->pm.idle_timeout = MT7921_PM_TIMEOUT;
dev->pm.stats.last_wake_event = jiffies;
dev->pm.stats.last_doze_event = jiffies;
+ dev->pm.enable = true;
+ dev->pm.ds_enable = true;
ret = mt7921_init_hardware(dev);
if (ret)
@@ -253,19 +216,33 @@ int mt7921_register_device(struct mt7921_dev *dev)
IEEE80211_HT_CAP_MAX_AMSDU;
dev->mphy.sband_5g.sband.vht_cap.cap |=
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
- IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
+ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
+ (3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
+
dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask;
dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask;
mt76_set_stream_caps(&dev->mphy, true);
mt7921_set_stream_he_caps(&dev->phy);
- ret = mt76_register_device(&dev->mt76, true, mt7921_rates,
- ARRAY_SIZE(mt7921_rates));
+ ret = mt76_register_device(&dev->mt76, true, mt76_rates,
+ ARRAY_SIZE(mt76_rates));
+ if (ret)
+ return ret;
+
+ ret = mt7921_init_debugfs(dev);
if (ret)
return ret;
- return mt7921_init_debugfs(dev);
+ ret = mt76_connac_mcu_set_deep_sleep(&dev->mt76, dev->pm.ds_enable);
+ if (ret)
+ return ret;
+
+ dev->hw_init_done = true;
+
+ return 0;
}
void mt7921_unregister_device(struct mt7921_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index decf2d5f0ce3..7fe2e3a50428 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -308,21 +308,24 @@ mt7921_mac_assoc_rssi(struct mt7921_dev *dev, struct sk_buff *skb)
int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
{
+ u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
+ bool hdr_trans, unicast, insert_ccmp_hdr = false;
+ u8 chfreq, qos_ctl = 0, remove_pad, amsdu_info;
+ __le32 *rxv = NULL, *rxd = (__le32 *)skb->data;
struct mt76_phy *mphy = &dev->mt76.phy;
struct mt7921_phy *phy = &dev->phy;
struct ieee80211_supported_band *sband;
struct ieee80211_hdr *hdr;
- __le32 *rxd = (__le32 *)skb->data;
- __le32 *rxv = NULL;
- u32 mode = 0;
+ u32 rxd0 = le32_to_cpu(rxd[0]);
u32 rxd1 = le32_to_cpu(rxd[1]);
u32 rxd2 = le32_to_cpu(rxd[2]);
u32 rxd3 = le32_to_cpu(rxd[3]);
- bool unicast, insert_ccmp_hdr = false;
- u8 remove_pad;
+ u32 rxd4 = le32_to_cpu(rxd[4]);
+ u16 seq_ctrl = 0;
+ __le16 fc = 0;
+ u32 mode = 0;
int i, idx;
- u8 chfreq;
memset(status, 0, sizeof(*status));
@@ -332,9 +335,13 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
return -EINVAL;
+ if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR)
+ return -EINVAL;
+
chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3);
unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
+ hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS;
status->wcid = mt7921_rx_get_wcid(dev, idx, unicast);
if (status->wcid) {
@@ -357,6 +364,9 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
if (!sband->channels)
return -EINVAL;
+ if ((rxd0 & csum_mask) == csum_mask)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
if (rxd1 & MT_RXD1_NORMAL_FCS_ERR)
status->flag |= RX_FLAG_FAILED_FCS_CRC;
@@ -377,6 +387,13 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
rxd += 6;
if (rxd1 & MT_RXD1_NORMAL_GROUP_4) {
+ u32 v0 = le32_to_cpu(rxd[0]);
+ u32 v2 = le32_to_cpu(rxd[2]);
+
+ fc = cpu_to_le16(FIELD_GET(MT_RXD6_FRAME_CONTROL, v0));
+ seq_ctrl = FIELD_GET(MT_RXD8_SEQ_CTRL, v2);
+ qos_ctl = FIELD_GET(MT_RXD8_QOS_CTL, v2);
+
rxd += 4;
if ((u8 *)rxd - skb->data >= skb->len)
return -EINVAL;
@@ -386,14 +403,27 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
u8 *data = (u8 *)rxd;
if (status->flag & RX_FLAG_DECRYPTED) {
- status->iv[0] = data[5];
- status->iv[1] = data[4];
- status->iv[2] = data[3];
- status->iv[3] = data[2];
- status->iv[4] = data[1];
- status->iv[5] = data[0];
-
- insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
+ switch (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1)) {
+ case MT_CIPHER_AES_CCMP:
+ case MT_CIPHER_CCMP_CCX:
+ case MT_CIPHER_CCMP_256:
+ insert_ccmp_hdr =
+ FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
+ fallthrough;
+ case MT_CIPHER_TKIP:
+ case MT_CIPHER_TKIP_NO_MIC:
+ case MT_CIPHER_GCMP:
+ case MT_CIPHER_GCMP_256:
+ status->iv[0] = data[5];
+ status->iv[1] = data[4];
+ status->iv[2] = data[3];
+ status->iv[3] = data[2];
+ status->iv[4] = data[1];
+ status->iv[5] = data[0];
+ break;
+ default:
+ break;
+ }
}
rxd += 4;
if ((u8 *)rxd - skb->data >= skb->len)
@@ -444,16 +474,19 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1);
status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1);
status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v1);
- status->signal = status->chain_signal[0];
-
- for (i = 1; i < hweight8(mphy->antenna_mask); i++) {
- if (!(status->chains & BIT(i)))
+ status->signal = -128;
+ for (i = 0; i < hweight8(mphy->antenna_mask); i++) {
+ if (!(status->chains & BIT(i)) ||
+ status->chain_signal[i] >= 0)
continue;
status->signal = max(status->signal,
status->chain_signal[i]);
}
+ if (status->signal == -128)
+ status->flag |= RX_FLAG_NO_SIGNAL_VAL;
+
stbc = FIELD_GET(MT_PRXV_STBC, v0);
gi = FIELD_GET(MT_PRXV_SGI, v0);
cck = false;
@@ -540,10 +573,35 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
skb_pull(skb, (u8 *)rxd - skb->data + 2 * remove_pad);
- if (insert_ccmp_hdr) {
- u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
+ amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4);
+ status->amsdu = !!amsdu_info;
+ if (status->amsdu) {
+ status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME;
+ status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;
+ if (!hdr_trans) {
+ memmove(skb->data + 2, skb->data,
+ ieee80211_get_hdrlen_from_skb(skb));
+ skb_pull(skb, 2);
+ }
+ }
+
+ if (!hdr_trans) {
+ if (insert_ccmp_hdr) {
+ u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
+
+ mt76_insert_ccmp_hdr(skb, key_id);
+ }
- mt76_insert_ccmp_hdr(skb, key_id);
+ hdr = mt76_skb_get_hdr(skb);
+ fc = hdr->frame_control;
+ if (ieee80211_is_data_qos(fc)) {
+ seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
+ qos_ctl = *ieee80211_get_qos_ctl(hdr);
+ }
+ } else {
+ status->flag &= ~(RX_FLAG_RADIOTAP_HE |
+ RX_FLAG_RADIOTAP_HE_MU);
+ status->flag |= RX_FLAG_8023;
}
mt7921_mac_assoc_rssi(dev, skb);
@@ -551,14 +609,12 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
if (rxv && status->flag & RX_FLAG_RADIOTAP_HE)
mt7921_mac_decode_he_radiotap(skb, status, rxv, mode);
- hdr = mt76_skb_get_hdr(skb);
- if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control))
+ if (!status->wcid || !ieee80211_is_data_qos(fc))
return 0;
- status->aggr = unicast &&
- !ieee80211_is_qos_nullfunc(hdr->frame_control);
- status->qos_ctl = *ieee80211_get_qos_ctl(hdr);
- status->seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
+ status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc);
+ status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl);
+ status->qos_ctl = qos_ctl;
return 0;
}
@@ -676,6 +732,23 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi,
txwi[7] |= cpu_to_le32(val);
}
+static void mt7921_update_txs(struct mt76_wcid *wcid, __le32 *txwi)
+{
+ struct mt7921_sta *msta = container_of(wcid, struct mt7921_sta, wcid);
+ u32 pid, frame_type = FIELD_GET(MT_TXD2_FRAME_TYPE, txwi[2]);
+
+ if (!(frame_type & (IEEE80211_FTYPE_DATA >> 2)))
+ return;
+
+ if (time_is_after_eq_jiffies(msta->next_txs_ts))
+ return;
+
+ msta->next_txs_ts = jiffies + msecs_to_jiffies(250);
+ pid = mt76_get_next_pkt_id(wcid);
+ txwi[5] |= cpu_to_le32(MT_TXD5_TX_STATUS_MCU |
+ FIELD_PREP(MT_TXD5_PID, pid));
+}
+
void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, bool beacon)
@@ -752,6 +825,8 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
txwi[6] |= cpu_to_le32(val);
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
}
+
+ mt7921_update_txs(wcid, txwi);
}
static void
@@ -1154,18 +1229,18 @@ mt7921_phy_update_channel(struct mt76_phy *mphy, int idx)
state->noise = -(phy->noise >> 4);
}
-void mt7921_update_channel(struct mt76_dev *mdev)
+void mt7921_update_channel(struct mt76_phy *mphy)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt7921_dev *dev = container_of(mphy->dev, struct mt7921_dev, mt76);
- if (mt76_connac_pm_wake(&dev->mphy, &dev->pm))
+ if (mt76_connac_pm_wake(mphy, &dev->pm))
return;
- mt7921_phy_update_channel(&mdev->phy, 0);
+ mt7921_phy_update_channel(mphy, 0);
/* reset obss airtime */
mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
- mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
+ mt76_connac_power_save_sched(mphy, &dev->pm);
}
void mt7921_tx_token_put(struct mt7921_dev *dev)
@@ -1196,7 +1271,8 @@ mt7921_vif_connect_iter(void *priv, u8 *mac,
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
struct mt7921_dev *dev = mvif->phy->dev;
- ieee80211_disconnect(vif, true);
+ if (vif->type == NL80211_IFTYPE_STATION)
+ ieee80211_disconnect(vif, true);
mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, true);
mt7921_mcu_set_tx(dev, vif);
@@ -1212,6 +1288,7 @@ mt7921_mac_reset(struct mt7921_dev *dev)
mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
+ set_bit(MT76_RESET, &dev->mphy.state);
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
skb_queue_purge(&dev->mt76.mcu.res_q);
@@ -1227,56 +1304,64 @@ mt7921_mac_reset(struct mt7921_dev *dev)
mt7921_tx_token_put(dev);
idr_init(&dev->mt76.token);
- err = mt7921_wpdma_reset(dev, true);
- if (err)
- return err;
+ mt7921_wpdma_reset(dev, true);
mt76_for_each_q_rx(&dev->mt76, i) {
napi_enable(&dev->mt76.napi[i]);
napi_schedule(&dev->mt76.napi[i]);
}
- napi_enable(&dev->mt76.tx_napi);
- napi_schedule(&dev->mt76.tx_napi);
- mt76_worker_enable(&dev->mt76.tx_worker);
-
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
- clear_bit(MT76_STATE_PM, &dev->mphy.state);
- mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
+ mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA,
+ MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
+ MT_INT_MCU_CMD);
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
err = mt7921_run_firmware(dev);
if (err)
- return err;
+ goto out;
err = mt7921_mcu_set_eeprom(dev);
if (err)
- return err;
+ goto out;
- mt7921_mac_init(dev);
- return __mt7921_start(&dev->phy);
+ err = mt7921_mac_init(dev);
+ if (err)
+ goto out;
+
+ err = __mt7921_start(&dev->phy);
+out:
+ clear_bit(MT76_RESET, &dev->mphy.state);
+
+ napi_enable(&dev->mt76.tx_napi);
+ napi_schedule(&dev->mt76.tx_napi);
+ mt76_worker_enable(&dev->mt76.tx_worker);
+
+ return err;
}
/* system error recovery */
void mt7921_mac_reset_work(struct work_struct *work)
{
- struct ieee80211_hw *hw;
- struct mt7921_dev *dev;
+ struct mt7921_dev *dev = container_of(work, struct mt7921_dev,
+ reset_work);
+ struct ieee80211_hw *hw = mt76_hw(dev);
+ struct mt76_connac_pm *pm = &dev->pm;
int i;
- dev = container_of(work, struct mt7921_dev, reset_work);
- hw = mt76_hw(dev);
-
dev_err(dev->mt76.dev, "chip reset\n");
+ dev->hw_full_reset = true;
ieee80211_stop_queues(hw);
cancel_delayed_work_sync(&dev->mphy.mac_work);
- cancel_delayed_work_sync(&dev->pm.ps_work);
- cancel_work_sync(&dev->pm.wake_work);
+ cancel_delayed_work_sync(&pm->ps_work);
+ cancel_work_sync(&pm->wake_work);
mutex_lock(&dev->mt76.mutex);
for (i = 0; i < 10; i++) {
+ __mt7921_mcu_drv_pmctrl(dev);
+
if (!mt7921_mac_reset(dev))
break;
}
@@ -1293,16 +1378,24 @@ void mt7921_mac_reset_work(struct work_struct *work)
ieee80211_scan_completed(dev->mphy.hw, &info);
}
+ dev->hw_full_reset = false;
ieee80211_wake_queues(hw);
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_vif_connect_iter, NULL);
+ mt76_connac_power_save_sched(&dev->mt76.phy, pm);
}
void mt7921_reset(struct mt76_dev *mdev)
{
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ if (!dev->hw_init_done)
+ return;
+
+ if (dev->hw_full_reset)
+ return;
+
queue_work(dev->mt76.wq, &dev->reset_work);
}
@@ -1337,30 +1430,6 @@ mt7921_mac_update_mib_stats(struct mt7921_phy *phy)
}
}
-static void
-mt7921_mac_sta_stats_work(struct mt7921_phy *phy)
-{
- struct mt7921_dev *dev = phy->dev;
- struct mt7921_sta *msta;
- LIST_HEAD(list);
-
- spin_lock_bh(&dev->sta_poll_lock);
- list_splice_init(&phy->stats_list, &list);
-
- while (!list_empty(&list)) {
- msta = list_first_entry(&list, struct mt7921_sta, stats_list);
- list_del_init(&msta->stats_list);
- spin_unlock_bh(&dev->sta_poll_lock);
-
- /* query wtbl info to report tx rate for further devices */
- mt7921_get_wtbl_info(dev, msta->wcid.idx);
-
- spin_lock_bh(&dev->sta_poll_lock);
- }
-
- spin_unlock_bh(&dev->sta_poll_lock);
-}
-
void mt7921_mac_work(struct work_struct *work)
{
struct mt7921_phy *phy;
@@ -1372,16 +1441,12 @@ void mt7921_mac_work(struct work_struct *work)
mt7921_mutex_acquire(phy->dev);
- mt76_update_survey(mphy->dev);
+ mt76_update_survey(mphy);
if (++mphy->mac_work_count == 2) {
mphy->mac_work_count = 0;
mt7921_mac_update_mib_stats(phy);
}
- if (++phy->sta_work_count == 4) {
- phy->sta_work_count = 0;
- mt7921_mac_sta_stats_work(phy);
- }
mt7921_mutex_release(phy->dev);
ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work,
@@ -1417,13 +1482,15 @@ void mt7921_pm_power_save_work(struct work_struct *work)
{
struct mt7921_dev *dev;
unsigned long delta;
+ struct mt76_phy *mphy;
dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev,
pm.ps_work.work);
+ mphy = dev->phy.mt76;
delta = dev->pm.idle_timeout;
- if (test_bit(MT76_HW_SCANNING, &dev->mphy.state) ||
- test_bit(MT76_HW_SCHED_SCANNING, &dev->mphy.state))
+ if (test_bit(MT76_HW_SCANNING, &mphy->state) ||
+ test_bit(MT76_HW_SCHED_SCANNING, &mphy->state))
goto out;
if (time_is_after_jiffies(dev->pm.last_activity + delta)) {
@@ -1431,8 +1498,10 @@ void mt7921_pm_power_save_work(struct work_struct *work)
goto out;
}
- if (!mt7921_mcu_fw_pmctrl(dev))
+ if (!mt7921_mcu_fw_pmctrl(dev)) {
+ cancel_delayed_work_sync(&mphy->mac_work);
return;
+ }
out:
queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta);
}
@@ -1494,7 +1563,7 @@ void mt7921_coredump_work(struct work_struct *work)
break;
skb_pull(skb, sizeof(struct mt7921_mcu_rxd));
- if (data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) {
+ if (!dump || data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) {
dev_kfree_skb(skb);
continue;
}
@@ -1504,7 +1573,10 @@ void mt7921_coredump_work(struct work_struct *work)
dev_kfree_skb(skb);
}
- dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ,
- GFP_KERNEL);
+
+ if (dump)
+ dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ,
+ GFP_KERNEL);
+
mt7921_reset(&dev->mt76);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h
index 109c8849d106..3af67fac213d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h
@@ -88,6 +88,9 @@ enum rx_pkt_type {
/* RXD DW4 */
#define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 0)
+#define MT_RXD4_FIRST_AMSDU_FRAME GENMASK(1, 0)
+#define MT_RXD4_MID_AMSDU_FRAME BIT(1)
+#define MT_RXD4_LAST_AMSDU_FRAME BIT(0)
#define MT_RXD4_NORMAL_PATTERN_DROP BIT(9)
#define MT_RXD4_NORMAL_CLS BIT(10)
#define MT_RXD4_NORMAL_OFLD GENMASK(12, 11)
@@ -97,6 +100,17 @@ enum rx_pkt_type {
#define MT_RXD3_NORMAL_PF_MODE BIT(29)
#define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30)
+/* RXD GROUP4 */
+#define MT_RXD6_FRAME_CONTROL GENMASK(15, 0)
+#define MT_RXD6_TA_LO GENMASK(31, 16)
+
+#define MT_RXD7_TA_HI GENMASK(31, 0)
+
+#define MT_RXD8_SEQ_CTRL GENMASK(15, 0)
+#define MT_RXD8_QOS_CTL GENMASK(31, 16)
+
+#define MT_RXD9_HT_CONTROL GENMASK(31, 0)
+
/* P-RXV DW0 */
#define MT_PRXV_TX_RATE GENMASK(6, 0)
#define MT_PRXV_TX_DCM BIT(4)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 97a0ef331ac3..63ec140c9c37 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -79,13 +79,14 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band,
he_cap_elem->phy_cap_info[1] =
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
he_cap_elem->phy_cap_info[2] =
+ IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
- IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ;
+ IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ |
+ IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO |
+ IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO;
switch (i) {
case NL80211_IFTYPE_STATION:
- he_cap_elem->mac_cap_info[0] |=
- IEEE80211_HE_MAC_CAP0_TWT_REQ;
he_cap_elem->mac_cap_info[1] |=
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US;
@@ -102,7 +103,15 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band,
he_cap_elem->phy_cap_info[3] |=
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK |
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK;
+ he_cap_elem->phy_cap_info[4] |=
+ IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
+ IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4;
+ he_cap_elem->phy_cap_info[5] |=
+ IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK |
+ IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK;
he_cap_elem->phy_cap_info[6] |=
+ IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
+ IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB |
IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
@@ -223,54 +232,6 @@ static void mt7921_stop(struct ieee80211_hw *hw)
mt7921_mutex_release(dev);
}
-static inline int get_free_idx(u32 mask, u8 start, u8 end)
-{
- return ffs(~mask & GENMASK(end, start));
-}
-
-static int get_omac_idx(enum nl80211_iftype type, u64 mask)
-{
- int i;
-
- switch (type) {
- case NL80211_IFTYPE_STATION:
- /* prefer hw bssid slot 1-3 */
- i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3);
- if (i)
- return i - 1;
-
- /* next, try to find a free repeater entry for the sta */
- i = get_free_idx(mask >> REPEATER_BSSID_START, 0,
- REPEATER_BSSID_MAX - REPEATER_BSSID_START);
- if (i)
- return i + 32 - 1;
-
- i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
- if (i)
- return i - 1;
-
- if (~mask & BIT(HW_BSSID_0))
- return HW_BSSID_0;
-
- break;
- case NL80211_IFTYPE_MONITOR:
- /* ap uses hw bssid 0 and ext bssid */
- if (~mask & BIT(HW_BSSID_0))
- return HW_BSSID_0;
-
- i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
- if (i)
- return i - 1;
-
- break;
- default:
- WARN_ON(1);
- break;
- }
-
- return -1;
-}
-
static int mt7921_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -292,12 +253,7 @@ static int mt7921_add_interface(struct ieee80211_hw *hw,
goto out;
}
- idx = get_omac_idx(vif->type, phy->omac_mask);
- if (idx < 0) {
- ret = -ENOSPC;
- goto out;
- }
- mvif->mt76.omac_idx = idx;
+ mvif->mt76.omac_idx = mvif->mt76.idx;
mvif->phy = phy;
mvif->mt76.band_idx = 0;
mvif->mt76.wmm_idx = mvif->mt76.idx % MT7921_MAX_WMM_SETS;
@@ -369,7 +325,7 @@ static void mt7921_remove_interface(struct ieee80211_hw *hw,
spin_unlock_bh(&dev->sta_poll_lock);
}
-int mt7921_set_channel(struct mt7921_phy *phy)
+static int mt7921_set_channel(struct mt7921_phy *phy)
{
struct mt7921_dev *dev = phy->dev;
int ret;
@@ -429,6 +385,11 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
wcid_keyidx = &wcid->hw_key_idx2;
break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ if (!mvif->wep_sta)
+ return -EOPNOTSUPP;
+ break;
case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_CCMP_256:
@@ -436,8 +397,6 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
case WLAN_CIPHER_SUITE_GCMP_256:
case WLAN_CIPHER_SUITE_SMS4:
break;
- case WLAN_CIPHER_SUITE_WEP40:
- case WLAN_CIPHER_SUITE_WEP104:
default:
return -EOPNOTSUPP;
}
@@ -455,6 +414,12 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
cmd == SET_KEY ? key : NULL);
err = mt7921_mcu_add_key(dev, vif, msta, key, cmd);
+ if (err)
+ goto out;
+
+ if (key->cipher == WLAN_CIPHER_SUITE_WEP104 ||
+ key->cipher == WLAN_CIPHER_SUITE_WEP40)
+ err = mt7921_mcu_add_key(dev, vif, mvif->wep_sta, key, cmd);
out:
mt7921_mutex_release(dev);
@@ -477,6 +442,9 @@ static int mt7921_config(struct ieee80211_hw *hw, u32 changed)
mt7921_mutex_acquire(dev);
+ if (changed & IEEE80211_CONF_CHANGE_POWER)
+ mt76_connac_mcu_set_rate_txpower(phy->mt76);
+
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR);
@@ -622,7 +590,8 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw,
mt7921_mcu_uni_bss_ps(dev, vif);
if (changed & BSS_CHANGED_ASSOC) {
- mt7921_mcu_sta_add(dev, NULL, vif, true);
+ mt7921_mcu_sta_update(dev, NULL, vif, true,
+ MT76_STA_INFO_STATE_ASSOC);
mt7921_bss_bcnft_apply(dev, vif, info->assoc);
}
@@ -661,14 +630,14 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (ret)
return ret;
- if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)
- mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid,
- true);
+ if (vif->type == NL80211_IFTYPE_STATION)
+ mvif->wep_sta = msta;
mt7921_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
- ret = mt7921_mcu_sta_add(dev, sta, vif, true);
+ ret = mt7921_mcu_sta_update(dev, sta, vif, true,
+ MT76_STA_INFO_STATE_NONE);
if (ret)
return ret;
@@ -677,6 +646,27 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
return 0;
}
+void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
+ struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+
+ mt7921_mutex_acquire(dev);
+
+ if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)
+ mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid,
+ true);
+
+ mt7921_mac_wtbl_update(dev, msta->wcid.idx,
+ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+
+ mt7921_mcu_sta_update(dev, sta, vif, true, MT76_STA_INFO_STATE_ASSOC);
+
+ mt7921_mutex_release(dev);
+}
+
void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
@@ -686,13 +676,14 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid);
mt76_connac_pm_wake(&dev->mphy, &dev->pm);
- mt7921_mcu_sta_add(dev, sta, vif, false);
+ mt7921_mcu_sta_update(dev, sta, vif, false, MT76_STA_INFO_STATE_NONE);
mt7921_mac_wtbl_update(dev, msta->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
if (vif->type == NL80211_IFTYPE_STATION) {
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ mvif->wep_sta = NULL;
ewma_rssi_init(&mvif->rssi);
if (!sta->tdls)
mt76_connac_mcu_uni_add_bss(&dev->mphy, vif,
@@ -720,7 +711,7 @@ void mt7921_tx_worker(struct mt76_worker *w)
}
mt76_txq_schedule_all(&dev->mphy);
- mt76_connac_pm_unref(&dev->pm);
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
}
static void mt7921_tx(struct ieee80211_hw *hw,
@@ -750,7 +741,7 @@ static void mt7921_tx(struct ieee80211_hw *hw,
if (mt76_connac_pm_ref(mphy, &dev->pm)) {
mt76_tx(mphy, control->sta, wcid, skb);
- mt76_connac_pm_unref(&dev->pm);
+ mt76_connac_pm_unref(mphy, &dev->pm);
return;
}
@@ -831,20 +822,21 @@ mt7921_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
return ret;
}
-static int
-mt7921_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+static int mt7921_sta_state(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ enum ieee80211_sta_state old_state,
+ enum ieee80211_sta_state new_state)
{
- return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST,
- IEEE80211_STA_NONE);
-}
+ struct mt7921_dev *dev = mt7921_hw_dev(hw);
-static int
-mt7921_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
- return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE,
- IEEE80211_STA_NOTEXIST);
+ if (dev->pm.ds_enable) {
+ mt7921_mutex_acquire(dev);
+ mt76_connac_sta_state_dp(&dev->mt76, old_state, new_state);
+ mt7921_mutex_release(dev);
+ }
+
+ return mt76_sta_state(hw, vif, sta, old_state, new_state);
}
static int
@@ -1163,6 +1155,23 @@ static void mt7921_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
HZ / 2);
}
+static void mt7921_sta_set_decap_offload(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ bool enabled)
+{
+ struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
+ struct mt7921_dev *dev = mt7921_hw_dev(hw);
+
+ if (enabled)
+ set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags);
+ else
+ clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags);
+
+ mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76, vif, &msta->wcid,
+ MCU_UNI_CMD_STA_REC_UPDATE);
+}
+
const struct ieee80211_ops mt7921_ops = {
.tx = mt7921_tx,
.start = mt7921_start,
@@ -1173,10 +1182,10 @@ const struct ieee80211_ops mt7921_ops = {
.conf_tx = mt7921_conf_tx,
.configure_filter = mt7921_configure_filter,
.bss_info_changed = mt7921_bss_info_changed,
- .sta_add = mt7921_sta_add,
- .sta_remove = mt7921_sta_remove,
+ .sta_state = mt7921_sta_state,
.sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
.set_key = mt7921_set_key,
+ .sta_set_decap_offload = mt7921_sta_set_decap_offload,
.ampdu_action = mt7921_ampdu_action,
.set_rts_threshold = mt7921_set_rts_threshold,
.wake_tx_queue = mt76_wake_tx_queue,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 67dc4b4cc094..cd690c64f65b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -88,28 +88,28 @@ struct mt7921_fw_region {
#define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id)
#define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id)
-static enum mt7921_cipher_type
+static enum mcu_cipher_type
mt7921_mcu_get_cipher(int cipher)
{
switch (cipher) {
case WLAN_CIPHER_SUITE_WEP40:
- return MT_CIPHER_WEP40;
+ return MCU_CIPHER_WEP40;
case WLAN_CIPHER_SUITE_WEP104:
- return MT_CIPHER_WEP104;
+ return MCU_CIPHER_WEP104;
case WLAN_CIPHER_SUITE_TKIP:
- return MT_CIPHER_TKIP;
+ return MCU_CIPHER_TKIP;
case WLAN_CIPHER_SUITE_AES_CMAC:
- return MT_CIPHER_BIP_CMAC_128;
+ return MCU_CIPHER_BIP_CMAC_128;
case WLAN_CIPHER_SUITE_CCMP:
- return MT_CIPHER_AES_CCMP;
+ return MCU_CIPHER_AES_CCMP;
case WLAN_CIPHER_SUITE_CCMP_256:
- return MT_CIPHER_CCMP_256;
+ return MCU_CIPHER_CCMP_256;
case WLAN_CIPHER_SUITE_GCMP:
- return MT_CIPHER_GCMP;
+ return MCU_CIPHER_GCMP;
case WLAN_CIPHER_SUITE_GCMP_256:
- return MT_CIPHER_GCMP_256;
+ return MCU_CIPHER_GCMP_256;
case WLAN_CIPHER_SUITE_SMS4:
- return MT_CIPHER_WAPI;
+ return MCU_CIPHER_WAPI;
default:
return MT_CIPHER_NONE;
}
@@ -399,43 +399,6 @@ mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy,
}
static void
-mt7921_mcu_tx_rate_report(struct mt7921_dev *dev, struct sk_buff *skb,
- u16 wlan_idx)
-{
- struct mt7921_mcu_wlan_info_event *wtbl_info;
- struct mt76_phy *mphy = &dev->mphy;
- struct mt7921_sta_stats *stats;
- struct rate_info rate = {};
- struct mt7921_sta *msta;
- struct mt76_wcid *wcid;
- u8 idx;
-
- if (wlan_idx >= MT76_N_WCIDS)
- return;
-
- wtbl_info = (struct mt7921_mcu_wlan_info_event *)skb->data;
- idx = wtbl_info->rate_info.rate_idx;
- if (idx >= ARRAY_SIZE(wtbl_info->rate_info.rate))
- return;
-
- rcu_read_lock();
-
- wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
- if (!wcid)
- goto out;
-
- msta = container_of(wcid, struct mt7921_sta, wcid);
- stats = &msta->stats;
-
- /* current rate */
- mt7921_mcu_tx_rate_parse(mphy, &wtbl_info->peer_cap, &rate,
- le16_to_cpu(wtbl_info->rate_info.rate[idx]));
- stats->tx_rate = rate;
-out:
- rcu_read_unlock();
-}
-
-static void
mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb)
{
struct mt76_phy *mphy = &dev->mt76.phy;
@@ -450,22 +413,33 @@ mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb)
}
static void
-mt7921_mcu_beacon_loss_event(struct mt7921_dev *dev, struct sk_buff *skb)
+mt7921_mcu_connection_loss_iter(void *priv, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
+ struct mt76_connac_beacon_loss_event *event = priv;
+
+ if (mvif->idx != event->bss_idx)
+ return;
+
+ if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER))
+ return;
+
+ ieee80211_connection_loss(vif);
+}
+
+static void
+mt7921_mcu_connection_loss_event(struct mt7921_dev *dev, struct sk_buff *skb)
{
struct mt76_connac_beacon_loss_event *event;
- struct mt76_phy *mphy;
- u8 band_idx = 0; /* DBDC support */
+ struct mt76_phy *mphy = &dev->mt76.phy;
skb_pull(skb, sizeof(struct mt7921_mcu_rxd));
event = (struct mt76_connac_beacon_loss_event *)skb->data;
- if (band_idx && dev->mt76.phy2)
- mphy = dev->mt76.phy2;
- else
- mphy = &dev->mt76.phy;
ieee80211_iterate_active_interfaces_atomic(mphy->hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
- mt76_connac_mcu_beacon_loss_iter, event);
+ mt7921_mcu_connection_loss_iter, event);
}
static void
@@ -524,13 +498,56 @@ mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb)
}
static void
+mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb)
+{
+ struct mt7921_mcu_tx_done_event *event;
+ struct mt7921_sta *msta;
+ struct mt7921_phy *mphy = &dev->phy;
+ struct mt7921_mcu_peer_cap peer;
+ struct ieee80211_sta *sta;
+ LIST_HEAD(list);
+
+ skb_pull(skb, sizeof(struct mt7921_mcu_rxd));
+ event = (struct mt7921_mcu_tx_done_event *)skb->data;
+
+ spin_lock_bh(&dev->sta_poll_lock);
+ list_splice_init(&mphy->stats_list, &list);
+
+ while (!list_empty(&list)) {
+ msta = list_first_entry(&list, struct mt7921_sta, stats_list);
+ list_del_init(&msta->stats_list);
+
+ if (msta->wcid.idx != event->wlan_idx)
+ continue;
+
+ spin_unlock_bh(&dev->sta_poll_lock);
+
+ sta = wcid_to_sta(&msta->wcid);
+
+ /* peer config based on IEEE SPEC */
+ memset(&peer, 0x0, sizeof(peer));
+ peer.bw = event->bw;
+ peer.g2 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
+ peer.g4 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40);
+ peer.g8 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80);
+ peer.g16 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160);
+ mt7921_mcu_tx_rate_parse(mphy->mt76, &peer,
+ &msta->stats.tx_rate, event->tx_rate);
+
+ spin_lock_bh(&dev->sta_poll_lock);
+ break;
+ }
+ spin_unlock_bh(&dev->sta_poll_lock);
+}
+
+static void
mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
{
struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data;
switch (rxd->eid) {
case MCU_EVENT_BSS_BEACON_LOSS:
- mt7921_mcu_beacon_loss_event(dev, skb);
+ mt7921_mcu_connection_loss_event(dev, skb);
break;
case MCU_EVENT_SCHED_SCAN_DONE:
case MCU_EVENT_SCAN_DONE:
@@ -549,6 +566,9 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
case MCU_EVENT_LP_INFO:
mt7921_mcu_low_power_event(dev, skb);
break;
+ case MCU_EVENT_TX_DONE:
+ mt7921_mcu_tx_done_event(dev, skb);
+ break;
default:
break;
}
@@ -569,6 +589,7 @@ void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb)
rxd->eid == MCU_EVENT_SCHED_SCAN_DONE ||
rxd->eid == MCU_EVENT_BSS_ABSENCE ||
rxd->eid == MCU_EVENT_SCAN_DONE ||
+ rxd->eid == MCU_EVENT_TX_DONE ||
rxd->eid == MCU_EVENT_DBG_MSG ||
rxd->eid == MCU_EVENT_COREDUMP ||
rxd->eid == MCU_EVENT_LP_INFO ||
@@ -604,14 +625,14 @@ mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb,
sec_key = &sec->key[0];
sec_key->cipher_len = sizeof(*sec_key);
- if (cipher == MT_CIPHER_BIP_CMAC_128) {
- sec_key->cipher_id = MT_CIPHER_AES_CCMP;
+ if (cipher == MCU_CIPHER_BIP_CMAC_128) {
+ sec_key->cipher_id = MCU_CIPHER_AES_CCMP;
sec_key->key_id = bip->keyidx;
sec_key->key_len = 16;
memcpy(sec_key->key, bip->key, 16);
sec_key = &sec->key[1];
- sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128;
+ sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128;
sec_key->cipher_len = sizeof(*sec_key);
sec_key->key_len = 16;
memcpy(sec_key->key, key->key, 16);
@@ -623,14 +644,14 @@ mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb,
sec_key->key_len = key->keylen;
memcpy(sec_key->key, key->key, key->keylen);
- if (cipher == MT_CIPHER_TKIP) {
+ if (cipher == MCU_CIPHER_TKIP) {
/* Rx/Tx MIC keys are swapped */
memcpy(sec_key->key + 16, key->key + 24, 8);
memcpy(sec_key->key + 24, key->key + 16, 8);
}
/* store key_conf for BIP batch update */
- if (cipher == MT_CIPHER_AES_CCMP) {
+ if (cipher == MCU_CIPHER_AES_CCMP) {
memcpy(bip->key, key->key, key->keylen);
bip->keyidx = key->keyidx;
}
@@ -910,7 +931,7 @@ static int mt7921_load_firmware(struct mt7921_dev *dev)
ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY);
if (ret) {
dev_dbg(dev->mt76.dev, "Firmware is already download\n");
- return -EIO;
+ goto fw_loaded;
}
ret = mt7921_load_patch(dev);
@@ -928,14 +949,13 @@ static int mt7921_load_firmware(struct mt7921_dev *dev)
return -EIO;
}
+fw_loaded:
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
#ifdef CONFIG_PM
dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support;
#endif /* CONFIG_PM */
- clear_bit(MT76_STATE_PM, &dev->mphy.state);
-
dev_err(dev->mt76.dev, "Firmware init done\n");
return 0;
@@ -969,7 +989,7 @@ int mt7921_run_firmware(struct mt7921_dev *dev)
set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
mt7921_mcu_fw_log_2_host(dev, 1);
- return 0;
+ return mt76_connac_mcu_get_nic_capability(&dev->mphy);
}
int mt7921_mcu_init(struct mt7921_dev *dev)
@@ -1136,26 +1156,6 @@ int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset)
return 0;
}
-u32 mt7921_get_wtbl_info(struct mt7921_dev *dev, u32 wlan_idx)
-{
- struct mt7921_mcu_wlan_info wtbl_info = {
- .wlan_idx = cpu_to_le32(wlan_idx),
- };
- struct sk_buff *skb;
- int ret;
-
- ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CMD_GET_WTBL,
- &wtbl_info, sizeof(wtbl_info), true,
- &skb);
- if (ret)
- return ret;
-
- mt7921_mcu_tx_rate_report(dev, skb, wlan_idx);
- dev_kfree_skb(skb);
-
- return 0;
-}
-
int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif)
{
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
@@ -1268,8 +1268,9 @@ int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
sizeof(req), false);
}
-int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta,
- struct ieee80211_vif *vif, bool enable)
+int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta,
+ struct ieee80211_vif *vif, bool enable,
+ enum mt76_sta_info_state state)
{
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
int rssi = -ewma_rssi_read(&mvif->rssi);
@@ -1278,27 +1279,25 @@ int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta,
.vif = vif,
.enable = enable,
.cmd = MCU_UNI_CMD_STA_REC_UPDATE,
+ .state = state,
+ .offload_fw = true,
.rcpi = to_rcpi(rssi),
};
struct mt7921_sta *msta;
msta = sta ? (struct mt7921_sta *)sta->drv_priv : NULL;
info.wcid = msta ? &msta->wcid : &mvif->sta.wcid;
+ info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true;
- return mt76_connac_mcu_add_sta_cmd(&dev->mphy, &info);
+ return mt76_connac_mcu_sta_cmd(&dev->mphy, &info);
}
-int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
+int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
struct mt76_connac_pm *pm = &dev->pm;
int i, err = 0;
- mutex_lock(&pm->mutex);
-
- if (!test_bit(MT76_STATE_PM, &mphy->state))
- goto out;
-
for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN);
if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL,
@@ -1319,6 +1318,22 @@ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
pm->stats.doze_time += pm->stats.last_wake_event -
pm->stats.last_doze_event;
out:
+ return err;
+}
+
+int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
+{
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
+ int err = 0;
+
+ mutex_lock(&pm->mutex);
+
+ if (!test_bit(MT76_STATE_PM, &mphy->state))
+ goto out;
+
+ err = __mt7921_mcu_drv_pmctrl(dev);
+out:
mutex_unlock(&pm->mutex);
if (err)
@@ -1368,6 +1383,7 @@ mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
struct mt7921_phy *phy = priv;
struct mt7921_dev *dev = phy->dev;
+ struct ieee80211_hw *hw = mt76_hw(dev);
int ret;
if (dev->pm.enable)
@@ -1380,9 +1396,11 @@ mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
if (dev->pm.enable) {
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+ ieee80211_hw_set(hw, CONNECTION_MONITOR);
mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
} else {
vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
+ __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags);
mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
}
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
index 49823d0a3d0a..d76cf8f8dfdf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
@@ -81,6 +81,7 @@ enum {
MCU_EVENT_REG_ACCESS = 0x05,
MCU_EVENT_LP_INFO = 0x07,
MCU_EVENT_SCAN_DONE = 0x0d,
+ MCU_EVENT_TX_DONE = 0x0f,
MCU_EVENT_BSS_ABSENCE = 0x11,
MCU_EVENT_BSS_BEACON_LOSS = 0x13,
MCU_EVENT_CH_PRIVILEGE = 0x18,
@@ -197,18 +198,17 @@ struct sta_rec_sec {
struct sec_key key[2];
} __packed;
-enum mt7921_cipher_type {
- MT_CIPHER_NONE,
- MT_CIPHER_WEP40,
- MT_CIPHER_WEP104,
- MT_CIPHER_WEP128,
- MT_CIPHER_TKIP,
- MT_CIPHER_AES_CCMP,
- MT_CIPHER_CCMP_256,
- MT_CIPHER_GCMP,
- MT_CIPHER_GCMP_256,
- MT_CIPHER_WAPI,
- MT_CIPHER_BIP_CMAC_128,
+enum mcu_cipher_type {
+ MCU_CIPHER_WEP40 = 1,
+ MCU_CIPHER_WEP104,
+ MCU_CIPHER_WEP128,
+ MCU_CIPHER_TKIP,
+ MCU_CIPHER_AES_CCMP,
+ MCU_CIPHER_CCMP_256,
+ MCU_CIPHER_GCMP,
+ MCU_CIPHER_GCMP_256,
+ MCU_CIPHER_WAPI,
+ MCU_CIPHER_BIP_CMAC_128,
};
enum {
@@ -254,86 +254,6 @@ struct mt7921_mcu_reg_event {
__le32 val;
} __packed;
-struct mt7921_mcu_tx_config {
- u8 peer_addr[ETH_ALEN];
- u8 sw;
- u8 dis_rx_hdr_tran;
-
- u8 aad_om;
- u8 pfmu_idx;
- __le16 partial_aid;
-
- u8 ibf;
- u8 ebf;
- u8 is_ht;
- u8 is_vht;
-
- u8 mesh;
- u8 baf_en;
- u8 cf_ack;
- u8 rdg_ba;
-
- u8 rdg;
- u8 pm;
- u8 rts;
- u8 smps;
-
- u8 txop_ps;
- u8 not_update_ipsm;
- u8 skip_tx;
- u8 ldpc;
-
- u8 qos;
- u8 from_ds;
- u8 to_ds;
- u8 dyn_bw;
-
- u8 amdsu_cross_lg;
- u8 check_per;
- u8 gid_63;
- u8 he;
-
- u8 vht_ibf;
- u8 vht_ebf;
- u8 vht_ldpc;
- u8 he_ldpc;
-} __packed;
-
-struct mt7921_mcu_sec_config {
- u8 wpi_flag;
- u8 rv;
- u8 ikv;
- u8 rkv;
-
- u8 rcid;
- u8 rca1;
- u8 rca2;
- u8 even_pn;
-
- u8 key_id;
- u8 muar_idx;
- u8 cipher_suit;
- u8 rsv[1];
-} __packed;
-
-struct mt7921_mcu_key_config {
- u8 key[32];
-} __packed;
-
-struct mt7921_mcu_rate_info {
- u8 mpdu_fail;
- u8 mpdu_tx;
- u8 rate_idx;
- u8 rsv[1];
- __le16 rate[8];
-} __packed;
-
-struct mt7921_mcu_ba_config {
- u8 ba_en;
- u8 rsv[3];
- __le32 ba_winsize;
-} __packed;
-
struct mt7921_mcu_ant_id_config {
u8 ant_id[4];
} __packed;
@@ -357,41 +277,6 @@ struct mt7921_mcu_peer_cap {
u8 rsv[1];
} __packed;
-struct mt7921_mcu_rx_cnt {
- u8 rx_rcpi[4];
- u8 rx_cc[4];
- u8 rx_cc_sel;
- u8 ce_rmsd;
- u8 rsv[2];
-} __packed;
-
-struct mt7921_mcu_tx_cnt {
- __le16 rate1_cnt;
- __le16 rate1_fail_cnt;
- __le16 rate2_cnt;
- __le16 rate3_cnt;
- __le16 cur_bw_tx_cnt;
- __le16 cur_bw_tx_fail_cnt;
- __le16 other_bw_tx_cnt;
- __le16 other_bw_tx_fail_cnt;
-} __packed;
-
-struct mt7921_mcu_wlan_info_event {
- struct mt7921_mcu_tx_config tx_config;
- struct mt7921_mcu_sec_config sec_config;
- struct mt7921_mcu_key_config key_config;
- struct mt7921_mcu_rate_info rate_info;
- struct mt7921_mcu_ba_config ba_config;
- struct mt7921_mcu_peer_cap peer_cap;
- struct mt7921_mcu_rx_cnt rx_cnt;
- struct mt7921_mcu_tx_cnt tx_cnt;
-} __packed;
-
-struct mt7921_mcu_wlan_info {
- __le32 wlan_idx;
- struct mt7921_mcu_wlan_info_event event;
-} __packed;
-
struct mt7921_txpwr_req {
u8 ver;
u8 action;
@@ -407,4 +292,31 @@ struct mt7921_txpwr_event {
struct mt7921_txpwr txpwr;
} __packed;
+struct mt7921_mcu_tx_done_event {
+ u8 pid;
+ u8 status;
+ u16 seq;
+
+ u8 wlan_idx;
+ u8 tx_cnt;
+ u16 tx_rate;
+
+ u8 flag;
+ u8 tid;
+ u8 rsp_rate;
+ u8 mcs;
+
+ u8 bw;
+ u8 tx_pwr;
+ u8 reason;
+ u8 rsv0[1];
+
+ u32 delay;
+ u32 timestamp;
+ u32 applied_flag;
+
+ u8 txs[28];
+
+ u8 rsv1[32];
+} __packed;
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index 59862ea4951c..2d8bd6bfc820 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -92,6 +92,8 @@ struct mt7921_sta {
unsigned long ampdu_state;
struct mt7921_sta_key_conf bip;
+
+ unsigned long next_txs_ts;
};
DECLARE_EWMA(rssi, 10, 8);
@@ -100,6 +102,8 @@ struct mt7921_vif {
struct mt76_vif mt76; /* must be first */
struct mt7921_sta sta;
+ struct mt7921_sta *wep_sta;
+
struct mt7921_phy *phy;
struct ewma_rssi rssi;
@@ -156,6 +160,8 @@ struct mt7921_dev {
u16 chainmask;
struct work_struct reset_work;
+ bool hw_full_reset:1;
+ bool hw_init_done:1;
struct list_head sta_poll_list;
spinlock_t sta_poll_lock;
@@ -256,9 +262,9 @@ int mt7921_mcu_init(struct mt7921_dev *dev);
int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif,
struct mt7921_sta *msta, struct ieee80211_key_conf *key,
enum set_key_cmd cmd);
-int mt7921_set_channel(struct mt7921_phy *phy);
-int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta,
- struct ieee80211_vif *vif, bool enable);
+int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta,
+ struct ieee80211_vif *vif, bool enable,
+ enum mt76_sta_info_state state);
int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd);
int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif);
int mt7921_mcu_set_eeprom(struct mt7921_dev *dev);
@@ -318,7 +324,7 @@ static inline bool mt7921_dma_need_reinit(struct mt7921_dev *dev)
return !mt76_get_field(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT);
}
-void mt7921_mac_init(struct mt7921_dev *dev);
+int mt7921_mac_init(struct mt7921_dev *dev);
bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask);
void mt7921_mac_reset_counters(struct mt7921_phy *phy);
void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
@@ -330,6 +336,8 @@ void mt7921_mac_fill_rx_vector(struct mt7921_dev *dev, struct sk_buff *skb);
void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb);
int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
+void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt7921_mac_work(struct work_struct *work);
@@ -352,7 +360,7 @@ void mt7921_stats_work(struct work_struct *work);
void mt7921_txp_skb_unmap(struct mt76_dev *dev,
struct mt76_txwi_cache *txwi);
void mt7921_set_stream_he_caps(struct mt7921_phy *phy);
-void mt7921_update_channel(struct mt76_dev *mdev);
+void mt7921_update_channel(struct mt76_phy *mphy);
int mt7921_init_debugfs(struct mt7921_dev *dev);
int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev,
@@ -362,12 +370,12 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev,
struct ieee80211_ampdu_params *params,
bool enable);
void mt7921_scan_work(struct work_struct *work);
-u32 mt7921_get_wtbl_info(struct mt7921_dev *dev, u32 wlan_idx);
int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif);
int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
bool enable);
int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
bool enable);
+int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev);
void mt7921_pm_wake_work(struct work_struct *work);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index fa02d934f0bf..c3905bcab360 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -106,6 +106,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
.rx_poll_complete = mt7921_rx_poll_complete,
.sta_ps = mt7921_sta_ps,
.sta_add = mt7921_mac_sta_add,
+ .sta_assoc = mt7921_mac_sta_assoc,
.sta_remove = mt7921_mac_sta_remove,
.update_survey = mt7921_update_channel,
};
@@ -188,22 +189,29 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct mt76_dev *mdev = pci_get_drvdata(pdev);
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt76_connac_pm *pm = &dev->pm;
bool hif_suspend;
int i, err;
- err = mt76_connac_pm_wake(&dev->mphy, &dev->pm);
+ pm->suspended = true;
+ cancel_delayed_work_sync(&pm->ps_work);
+ cancel_work_sync(&pm->wake_work);
+
+ err = mt7921_mcu_drv_pmctrl(dev);
if (err < 0)
- return err;
+ goto restore_suspend;
hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state);
if (hif_suspend) {
err = mt76_connac_mcu_set_hif_suspend(mdev, true);
if (err)
- return err;
+ goto restore_suspend;
}
- if (!dev->pm.enable)
- mt76_connac_mcu_set_deep_sleep(&dev->mt76, true);
+ /* always enable deep sleep during suspend to reduce
+ * power consumption
+ */
+ mt76_connac_mcu_set_deep_sleep(&dev->mt76, true);
napi_disable(&mdev->tx_napi);
mt76_worker_disable(&mdev->tx_worker);
@@ -231,27 +239,30 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state)
err = mt7921_mcu_fw_pmctrl(dev);
if (err)
- goto restore;
+ goto restore_napi;
pci_save_state(pdev);
err = pci_set_power_state(pdev, pci_choose_state(pdev, state));
if (err)
- goto restore;
+ goto restore_napi;
return 0;
-restore:
+restore_napi:
mt76_for_each_q_rx(mdev, i) {
napi_enable(&mdev->napi[i]);
}
napi_enable(&mdev->tx_napi);
- if (!dev->pm.enable)
+ if (!pm->ds_enable)
mt76_connac_mcu_set_deep_sleep(&dev->mt76, false);
if (hif_suspend)
mt76_connac_mcu_set_hif_suspend(mdev, false);
+restore_suspend:
+ pm->suspended = false;
+
return err;
}
@@ -259,8 +270,10 @@ static int mt7921_pci_resume(struct pci_dev *pdev)
{
struct mt76_dev *mdev = pci_get_drvdata(pdev);
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt76_connac_pm *pm = &dev->pm;
int i, err;
+ pm->suspended = false;
err = pci_set_power_state(pdev, PCI_D0);
if (err)
return err;
@@ -291,7 +304,8 @@ static int mt7921_pci_resume(struct pci_dev *pdev)
napi_enable(&mdev->tx_napi);
napi_schedule(&mdev->tx_napi);
- if (!dev->pm.enable)
+ /* restore previous ds setting */
+ if (!pm->ds_enable)
mt76_connac_mcu_set_deep_sleep(&dev->mt76, false);
if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state))
diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c
index a18d2896ee1f..783a15635ec5 100644
--- a/drivers/net/wireless/mediatek/mt76/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/sdio.c
@@ -184,9 +184,6 @@ static int mt76s_process_tx_queue(struct mt76_dev *dev, struct mt76_queue *q)
if (!q->queued)
wake_up(&dev->tx_wait);
- if (!mcu)
- mt76_txq_schedule(&dev->phy, q->qid);
-
return nframes;
}
@@ -195,19 +192,28 @@ static void mt76s_status_worker(struct mt76_worker *w)
struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
status_worker);
struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
+ bool resched = false;
int i, nframes;
do {
+ int ndata_frames = 0;
+
nframes = mt76s_process_tx_queue(dev, dev->q_mcu[MT_MCUQ_WM]);
for (i = 0; i <= MT_TXQ_PSD; i++)
- nframes += mt76s_process_tx_queue(dev,
- dev->phy.q_tx[i]);
+ ndata_frames += mt76s_process_tx_queue(dev,
+ dev->phy.q_tx[i]);
+ nframes += ndata_frames;
+ if (ndata_frames > 0)
+ resched = true;
if (dev->drv->tx_status_data &&
!test_and_set_bit(MT76_READING_STATS, &dev->phy.state))
queue_work(dev->wq, &dev->sdio.stat_work);
} while (nframes > 0);
+
+ if (resched)
+ mt76_worker_schedule(&dev->sdio.txrx_worker);
}
static void mt76s_tx_status_data(struct work_struct *work)
@@ -256,6 +262,7 @@ mt76s_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
q->entry[q->head].skb = tx_info.skb;
q->entry[q->head].buf_sz = len;
+ q->entry[q->head].wcid = 0xffff;
smp_wmb();
diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c
index 001d0ba5f73e..f73ffbd6e622 100644
--- a/drivers/net/wireless/mediatek/mt76/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/testmode.c
@@ -88,17 +88,8 @@ static void
mt76_testmode_free_skb(struct mt76_phy *phy)
{
struct mt76_testmode_data *td = &phy->test;
- struct sk_buff *skb = td->tx_skb;
-
- if (!skb)
- return;
- if (skb_has_frag_list(skb)) {
- kfree_skb_list(skb_shinfo(skb)->frag_list);
- skb_shinfo(skb)->frag_list = NULL;
- }
-
- dev_kfree_skb(skb);
+ dev_kfree_skb(td->tx_skb);
td->tx_skb = NULL;
}
@@ -158,19 +149,18 @@ int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len)
frag_len = MT_TXP_MAX_LEN;
frag = alloc_skb(frag_len, GFP_KERNEL);
- if (!frag)
+ if (!frag) {
+ mt76_testmode_free_skb(phy);
+ dev_kfree_skb(head);
return -ENOMEM;
+ }
__skb_put_zero(frag, frag_len);
head->len += frag->len;
head->data_len += frag->len;
- if (*frag_tail) {
- (*frag_tail)->next = frag;
- frag_tail = &frag;
- } else {
- *frag_tail = frag;
- }
+ *frag_tail = frag;
+ frag_tail = &(*frag_tail)->next;
}
mt76_testmode_free_skb(phy);
@@ -531,6 +521,14 @@ mt76_testmode_dump_stats(struct mt76_phy *phy, struct sk_buff *msg)
u64 rx_fcs_error = 0;
int i;
+ if (dev->test_ops->dump_stats) {
+ int ret;
+
+ ret = dev->test_ops->dump_stats(phy, msg);
+ if (ret)
+ return ret;
+ }
+
for (i = 0; i < ARRAY_SIZE(td->rx_stats.packets); i++) {
rx_packets += td->rx_stats.packets[i];
rx_fcs_error += td->rx_stats.fcs_error[i];
@@ -545,9 +543,6 @@ mt76_testmode_dump_stats(struct mt76_phy *phy, struct sk_buff *msg)
MT76_TM_STATS_ATTR_PAD))
return -EMSGSIZE;
- if (dev->test_ops->dump_stats)
- return dev->test_ops->dump_stats(phy, msg);
-
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 53ea8de82df0..f0f7a913eaab 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -54,11 +54,23 @@ mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list)
spin_unlock_bh(&dev->status_list.lock);
+ rcu_read_lock();
while ((skb = __skb_dequeue(list)) != NULL) {
+ struct ieee80211_tx_status status = {
+ .skb = skb,
+ .info = IEEE80211_SKB_CB(skb),
+ };
+ struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
+ struct mt76_wcid *wcid;
+
+ wcid = rcu_dereference(dev->wcid[cb->wcid]);
+ if (wcid)
+ status.sta = wcid_to_sta(wcid);
+
hw = mt76_tx_status_get_hw(dev, skb);
- ieee80211_tx_status(hw, skb);
+ ieee80211_tx_status_ext(hw, &status);
}
-
+ rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(mt76_tx_status_unlock);
@@ -80,7 +92,7 @@ __mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags,
/* Tx status can be unreliable. if it fails, mark the frame as ACKed */
if (flags & MT_TX_CB_TXS_FAILED) {
- ieee80211_tx_info_clear_status(info);
+ info->status.rates[0].count = 0;
info->status.rates[0].idx = -1;
info->flags |= IEEE80211_TX_STAT_ACK;
}
@@ -117,12 +129,7 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid,
spin_lock_bh(&dev->status_list.lock);
memset(cb, 0, sizeof(*cb));
- wcid->packet_id = (wcid->packet_id + 1) & MT_PACKET_ID_MASK;
- if (wcid->packet_id == MT_PACKET_ID_NO_ACK ||
- wcid->packet_id == MT_PACKET_ID_NO_SKB)
- wcid->packet_id = MT_PACKET_ID_FIRST;
-
- pid = wcid->packet_id;
+ pid = mt76_get_next_pkt_id(wcid);
cb->wcid = wcid->idx;
cb->pktid = pid;
cb->jiffies = jiffies;
@@ -173,36 +180,37 @@ mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid, bool flush)
EXPORT_SYMBOL_GPL(mt76_tx_status_check);
static void
-mt76_tx_check_non_aql(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb)
+mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid,
+ struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct mt76_wcid *wcid;
int pending;
- if (info->tx_time_est)
- return;
-
- if (wcid_idx >= ARRAY_SIZE(dev->wcid))
+ if (!wcid || info->tx_time_est)
return;
- rcu_read_lock();
-
- wcid = rcu_dereference(dev->wcid[wcid_idx]);
- if (wcid) {
- pending = atomic_dec_return(&wcid->non_aql_packets);
- if (pending < 0)
- atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
- }
-
- rcu_read_unlock();
+ pending = atomic_dec_return(&wcid->non_aql_packets);
+ if (pending < 0)
+ atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
}
-void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb)
+void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb,
+ struct list_head *free_list)
{
+ struct ieee80211_tx_status status = {
+ .skb = skb,
+ .free_list = free_list,
+ };
+ struct mt76_wcid *wcid = NULL;
struct ieee80211_hw *hw;
struct sk_buff_head list;
- mt76_tx_check_non_aql(dev, wcid_idx, skb);
+ rcu_read_lock();
+
+ if (wcid_idx < ARRAY_SIZE(dev->wcid))
+ wcid = rcu_dereference(dev->wcid[wcid_idx]);
+
+ mt76_tx_check_non_aql(dev, wcid, skb);
#ifdef CONFIG_NL80211_TESTMODE
if (mt76_is_testmode_skb(dev, skb, &hw)) {
@@ -214,21 +222,25 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *sk
wake_up(&dev->tx_wait);
dev_kfree_skb_any(skb);
- return;
+ goto out;
}
#endif
if (!skb->prev) {
hw = mt76_tx_status_get_hw(dev, skb);
- ieee80211_free_txskb(hw, skb);
- return;
+ status.sta = wcid_to_sta(wcid);
+ ieee80211_tx_status_ext(hw, &status);
+ goto out;
}
mt76_tx_status_lock(dev, &list);
__mt76_tx_status_skb_done(dev, skb, MT_TX_CB_DMA_DONE, &list);
mt76_tx_status_unlock(dev, &list);
+
+out:
+ rcu_read_unlock();
}
-EXPORT_SYMBOL_GPL(mt76_tx_complete_skb);
+EXPORT_SYMBOL_GPL(__mt76_tx_complete_skb);
static int
__mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb,
@@ -244,11 +256,15 @@ __mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb,
non_aql = !info->tx_time_est;
idx = dev->queue_ops->tx_queue_skb(dev, q, skb, wcid, sta);
- if (idx < 0 || !sta || !non_aql)
+ if (idx < 0 || !sta)
return idx;
wcid = (struct mt76_wcid *)sta->drv_priv;
q->entry[idx].wcid = wcid->idx;
+
+ if (!non_aql)
+ return idx;
+
pending = atomic_inc_return(&wcid->non_aql_packets);
if (stop && pending >= MT_MAX_NON_AQL_PKT)
*stop = true;
@@ -285,7 +301,7 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
skb_set_queue_mapping(skb, qid);
}
- if (!(wcid->tx_info & MT_WCID_TX_INFO_SET))
+ if (wcid && !(wcid->tx_info & MT_WCID_TX_INFO_SET))
ieee80211_get_tx_rates(info->control.vif, sta, skb,
info->control.rates, 1);
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index 30bc54e98c58..1e9f60bb811a 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -925,6 +925,7 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
q->head = (q->head + 1) % q->ndesc;
q->entry[idx].skb = tx_info.skb;
+ q->entry[idx].wcid = 0xffff;
q->queued++;
return idx;
diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c
index 6bcc4a13ae6c..cc772045d526 100644
--- a/drivers/net/wireless/mediatek/mt7601u/usb.c
+++ b/drivers/net/wireless/mediatek/mt7601u/usb.c
@@ -26,6 +26,7 @@ static const struct usb_device_id mt7601u_device_table[] = {
{ USB_DEVICE(0x2717, 0x4106) },
{ USB_DEVICE(0x2955, 0x0001) },
{ USB_DEVICE(0x2955, 0x1001) },
+ { USB_DEVICE(0x2955, 0x1003) },
{ USB_DEVICE(0x2a5f, 0x1000) },
{ USB_DEVICE(0x7392, 0x7710) },
{ 0, }
diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c
index 1472e9843896..8e9aaf03a6fa 100644
--- a/drivers/net/wireless/microchip/wilc1000/spi.c
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -164,7 +164,7 @@ static int wilc_bus_probe(struct spi_device *spi)
wilc->bus_data = spi_priv;
wilc->dev_irq_num = spi->irq;
- wilc->rtc_clk = devm_clk_get(&spi->dev, "rtc_clk");
+ wilc->rtc_clk = devm_clk_get(&spi->dev, "rtc");
if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER) {
kfree(spi_priv);
return -EPROBE_DEFER;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index 5264b0a1f098..deddb0afd312 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1037,7 +1037,7 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi,
* FIXME: if we do not find matching entry, we tell that frame was
* posted without any retries. We need to find a way to fix that
* and provide retry count.
- */
+ */
if (unlikely((aggr == 1 && ampdu == 0 && real_mcs != mcs)) || !match) {
rt2800_rate_from_status(skbdesc, status, rt2x00dev->curr_band);
mcs = real_mcs;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
index d4d389e8f1b4..fb1d31b2d52a 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
@@ -446,8 +446,9 @@ static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,
* Beacons and probe responses require the tsf timestamp
* to be inserted into the frame.
*/
- if (ieee80211_is_beacon(hdr->frame_control) ||
- ieee80211_is_probe_resp(hdr->frame_control))
+ if ((ieee80211_is_beacon(hdr->frame_control) ||
+ ieee80211_is_probe_resp(hdr->frame_control)) &&
+ !(tx_info->flags & IEEE80211_TX_CTL_INJECTED))
__set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags);
if ((tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) &&
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
index d1a566cc0c9e..01735776345a 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
@@ -853,15 +853,10 @@ struct rtl8192eu_efuse {
u8 usb_optional_function;
u8 res9[2];
u8 mac_addr[ETH_ALEN]; /* 0xd7 */
- u8 res10[2];
- u8 vendor_name[7];
- u8 res11[2];
- u8 device_name[0x0b]; /* 0xe8 */
- u8 res12[2];
- u8 serial[0x0b]; /* 0xf5 */
- u8 res13[0x30];
+ u8 device_info[80];
+ u8 res11[3];
u8 unknown[0x0d]; /* 0x130 */
- u8 res14[0xc3];
+ u8 res12[0xc3];
};
struct rtl8xxxu_reg8val {
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c
index cfe2dfdae928..b06508d0cdf8 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c
@@ -554,9 +554,43 @@ rtl8192e_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40)
}
}
+static void rtl8192eu_log_next_device_info(struct rtl8xxxu_priv *priv,
+ char *record_name,
+ char *device_info,
+ unsigned int *record_offset)
+{
+ char *record = device_info + *record_offset;
+
+ /* A record is [ total length | 0x03 | value ] */
+ unsigned char l = record[0];
+
+ /*
+ * The whole device info section seems to be 80 characters, make sure
+ * we don't read further.
+ */
+ if (*record_offset + l > 80) {
+ dev_warn(&priv->udev->dev,
+ "invalid record length %d while parsing \"%s\" at offset %u.\n",
+ l, record_name, *record_offset);
+ return;
+ }
+
+ if (l >= 2) {
+ char value[80];
+
+ memcpy(value, &record[2], l - 2);
+ value[l - 2] = '\0';
+ dev_info(&priv->udev->dev, "%s: %s\n", record_name, value);
+ *record_offset = *record_offset + l;
+ } else {
+ dev_info(&priv->udev->dev, "%s not available.\n", record_name);
+ }
+}
+
static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv)
{
struct rtl8192eu_efuse *efuse = &priv->efuse_wifi.efuse8192eu;
+ unsigned int record_offset;
int i;
if (efuse->rtl_id != cpu_to_le16(0x8129))
@@ -604,12 +638,25 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv)
priv->has_xtalk = 1;
priv->xtalk = priv->efuse_wifi.efuse8192eu.xtal_k & 0x3f;
- dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name);
- dev_info(&priv->udev->dev, "Product: %.11s\n", efuse->device_name);
- if (memchr_inv(efuse->serial, 0xff, 11))
- dev_info(&priv->udev->dev, "Serial: %.11s\n", efuse->serial);
- else
- dev_info(&priv->udev->dev, "Serial not available.\n");
+ /*
+ * device_info section seems to be laid out as records
+ * [ total length | 0x03 | value ] so:
+ * - vendor length + 2
+ * - 0x03
+ * - vendor string (not null terminated)
+ * - product length + 2
+ * - 0x03
+ * - product string (not null terminated)
+ * Then there is one or 2 0x00 on all the 4 devices I own or found
+ * dumped online.
+ * As previous version of the code handled an optional serial
+ * string, I now assume there may be a third record if the
+ * length is not 0.
+ */
+ record_offset = 0;
+ rtl8192eu_log_next_device_info(priv, "Vendor", efuse->device_info, &record_offset);
+ rtl8192eu_log_next_device_info(priv, "Product", efuse->device_info, &record_offset);
+ rtl8192eu_log_next_device_info(priv, "Serial", efuse->device_info, &record_offset);
if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) {
unsigned char *raw = priv->efuse_wifi.raw;
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
index 9ff09cf7eb62..ac1061caacd6 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
@@ -5554,6 +5554,11 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb)
urb_len = skb->len;
pkt_cnt = 0;
+ if (urb_len < sizeof(struct rtl8xxxu_rxdesc16)) {
+ kfree_skb(skb);
+ return RX_TYPE_ERROR;
+ }
+
do {
rx_desc = (struct rtl8xxxu_rxdesc16 *)skb->data;
_rx_desc_le = (__le32 *)skb->data;
@@ -5581,7 +5586,7 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb)
* at least cover the rx descriptor
*/
if (pkt_cnt > 1 &&
- urb_len > (pkt_offset + sizeof(struct rtl8xxxu_rxdesc16)))
+ urb_len >= (pkt_offset + sizeof(struct rtl8xxxu_rxdesc16)))
next_skb = skb_clone(skb, GFP_ATOMIC);
rx_status = IEEE80211_SKB_RXCB(skb);
@@ -5627,7 +5632,9 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb)
pkt_cnt--;
urb_len -= pkt_offset;
- } while (skb && urb_len > 0 && pkt_cnt > 0);
+ next_skb = NULL;
+ } while (skb && pkt_cnt > 0 &&
+ urb_len >= sizeof(struct rtl8xxxu_rxdesc16));
return RX_TYPE_DATA_PKT;
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c
index 447caa4aad32..c5b8df58d4a2 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c
@@ -1721,10 +1721,6 @@ static void btc8821a2ant_tdma_duration_adjust(struct btc_coexist *btcoexist,
btc8821a2ant_ps_tdma(btcoexist,
NORMAL_EXEC, true, 14);
coex_dm->ps_tdma_du_adj_type = 14;
- } else if (max_interval == 3) {
- btc8821a2ant_ps_tdma(btcoexist,
- NORMAL_EXEC, true, 15);
- coex_dm->ps_tdma_du_adj_type = 15;
} else {
btc8821a2ant_ps_tdma(btcoexist,
NORMAL_EXEC, true, 15);
@@ -1739,10 +1735,6 @@ static void btc8821a2ant_tdma_duration_adjust(struct btc_coexist *btcoexist,
btc8821a2ant_ps_tdma(btcoexist,
NORMAL_EXEC, true, 10);
coex_dm->ps_tdma_du_adj_type = 10;
- } else if (max_interval == 3) {
- btc8821a2ant_ps_tdma(btcoexist,
- NORMAL_EXEC, true, 11);
- coex_dm->ps_tdma_du_adj_type = 11;
} else {
btc8821a2ant_ps_tdma(btcoexist,
NORMAL_EXEC, true, 11);
@@ -1759,10 +1751,6 @@ static void btc8821a2ant_tdma_duration_adjust(struct btc_coexist *btcoexist,
btc8821a2ant_ps_tdma(btcoexist,
NORMAL_EXEC, true, 6);
coex_dm->ps_tdma_du_adj_type = 6;
- } else if (max_interval == 3) {
- btc8821a2ant_ps_tdma(btcoexist,
- NORMAL_EXEC, true, 7);
- coex_dm->ps_tdma_du_adj_type = 7;
} else {
btc8821a2ant_ps_tdma(btcoexist,
NORMAL_EXEC, true, 7);
@@ -1777,10 +1765,6 @@ static void btc8821a2ant_tdma_duration_adjust(struct btc_coexist *btcoexist,
btc8821a2ant_ps_tdma(btcoexist,
NORMAL_EXEC, true, 2);
coex_dm->ps_tdma_du_adj_type = 2;
- } else if (max_interval == 3) {
- btc8821a2ant_ps_tdma(btcoexist,
- NORMAL_EXEC, true, 3);
- coex_dm->ps_tdma_du_adj_type = 3;
} else {
btc8821a2ant_ps_tdma(btcoexist,
NORMAL_EXEC, true, 3);
@@ -2810,6 +2794,7 @@ static void btc8821a2ant_action_a2dp(struct btc_coexist *btcoexist)
0x4);
}
+ /* preserve identical branches for further fine-tuning */
if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
(bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23);
@@ -2944,6 +2929,7 @@ static void btc8821a2ant_action_pan_edr(struct btc_coexist *btcoexist)
0x4);
}
+ /* preserve identical branches for further fine-tuning */
if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
(bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH))
btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 26);
@@ -3132,6 +3118,7 @@ static void btc8821a2ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+ /* preserve identical branches for further fine-tuning */
if (wifi_bw == BTC_WIFI_BW_LEGACY) {
/* for HID at 11b/g mode */
btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
@@ -3321,6 +3308,7 @@ static void btc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist)
0x4);
}
+ /* preserve identical branches for further fine-tuning */
if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
(bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23);
diff --git a/drivers/net/wireless/realtek/rtlwifi/cam.c b/drivers/net/wireless/realtek/rtlwifi/cam.c
index 7aa28da39409..7a0355dc6bab 100644
--- a/drivers/net/wireless/realtek/rtlwifi/cam.c
+++ b/drivers/net/wireless/realtek/rtlwifi/cam.c
@@ -167,7 +167,7 @@ void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index)
u32 ul_command;
u32 ul_content;
- u32 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
+ u32 ul_enc_algo;
switch (rtlpriv->sec.pairwise_enc_algorithm) {
case WEP40_ENCRYPTION:
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c
index 8d2c6d8d32d9..4ff0d4118193 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c
@@ -112,7 +112,7 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw)
}
/**
- * writeLLT - LLT table write access
+ * rtl92c_llt_write - LLT table write access
* @hw: Pointer to the ieee80211_hw structure.
* @address: LLT logical address.
* @data: LLT data content
@@ -144,7 +144,7 @@ bool rtl92c_llt_write(struct ieee80211_hw *hw, u32 address, u32 data)
}
/**
- * rtl92c_init_LLT_table - Init LLT table
+ * rtl92c_init_llt_table - Init LLT table
* @hw: Pointer to the ieee80211_hw structure.
* @boundary: Page boundary.
*
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c
index 68ec009ea157..76dd881ef9bb 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c
@@ -2574,7 +2574,7 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t)
RTPRINT(rtlpriv, FINIT, INIT_IQK,
"path-B / 2.4G LCK\n");
}
- memset(&curvecount_val[0], 0, CV_CURVE_CNT * 2);
+ memset(curvecount_val, 0, sizeof(curvecount_val));
/* Set LC calibration off */
rtl_set_rfreg(hw, (enum radio_path)index, RF_CHNLBW,
0x08000, 0x0);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c
index 38034102aacb..e474b4ec17f3 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c
@@ -513,7 +513,7 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc8,
/* This bit indicate this packet is used for FW download. */
if (tcb_desc->cmd_or_init == DESC_PACKET_TYPE_INIT) {
- /* For firmware downlaod we only need to set LINIP */
+ /* For firmware download we only need to set LINIP */
set_tx_desc_linip(pdesc, tcb_desc->last_inipkt);
/* 92SE must set as 1 for firmware download HW DMA error */
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c
index f8a1de6e9849..c98f2216734f 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c
@@ -915,7 +915,7 @@ int rtl8723e_hw_init(struct ieee80211_hw *hw)
struct rtl_phy *rtlphy = &(rtlpriv->phy);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- bool rtstatus = true;
+ bool rtstatus;
int err;
u8 tmp_u1b;
unsigned long flags;
diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c
index cedbf3825848..2551e228b581 100644
--- a/drivers/net/wireless/realtek/rtw88/coex.c
+++ b/drivers/net/wireless/realtek/rtw88/coex.c
@@ -591,8 +591,10 @@ void rtw_coex_info_response(struct rtw_dev *rtwdev, struct sk_buff *skb)
struct rtw_coex *coex = &rtwdev->coex;
u8 *payload = get_payload_from_coex_resp(skb);
- if (payload[0] != COEX_RESP_ACK_BY_WL_FW)
+ if (payload[0] != COEX_RESP_ACK_BY_WL_FW) {
+ dev_kfree_skb_any(skb);
return;
+ }
skb_queue_tail(&coex->queue, skb);
wake_up(&coex->wait);
@@ -630,20 +632,16 @@ static bool rtw_coex_get_bt_scan_type(struct rtw_dev *rtwdev, u8 *scan_type)
struct rtw_coex_info_req req = {0};
struct sk_buff *skb;
u8 *payload;
- bool ret = false;
req.op_code = BT_MP_INFO_OP_SCAN_TYPE;
skb = rtw_coex_info_request(rtwdev, &req);
if (!skb)
- goto out;
+ return false;
payload = get_payload_from_coex_resp(skb);
*scan_type = GET_COEX_RESP_BT_SCAN_TYPE(payload);
dev_kfree_skb_any(skb);
- ret = true;
-
-out:
- return ret;
+ return true;
}
static bool rtw_coex_set_lna_constrain_level(struct rtw_dev *rtwdev,
@@ -651,19 +649,15 @@ static bool rtw_coex_set_lna_constrain_level(struct rtw_dev *rtwdev,
{
struct rtw_coex_info_req req = {0};
struct sk_buff *skb;
- bool ret = false;
req.op_code = BT_MP_INFO_OP_LNA_CONSTRAINT;
req.para1 = lna_constrain_level;
skb = rtw_coex_info_request(rtwdev, &req);
if (!skb)
- goto out;
+ return false;
dev_kfree_skb_any(skb);
- ret = true;
-
-out:
- return ret;
+ return true;
}
#define case_BTSTATUS(src) \
@@ -3523,6 +3517,7 @@ static bool rtw_coex_get_bt_reg(struct rtw_dev *rtwdev,
payload = get_payload_from_coex_resp(skb);
*val = GET_COEX_RESP_BT_REG_VAL(payload);
+ dev_kfree_skb_any(skb);
return true;
}
@@ -3533,19 +3528,17 @@ static bool rtw_coex_get_bt_patch_version(struct rtw_dev *rtwdev,
struct rtw_coex_info_req req = {0};
struct sk_buff *skb;
u8 *payload;
- bool ret = false;
req.op_code = BT_MP_INFO_OP_PATCH_VER;
skb = rtw_coex_info_request(rtwdev, &req);
if (!skb)
- goto out;
+ return false;
payload = get_payload_from_coex_resp(skb);
*patch_version = GET_COEX_RESP_BT_PATCH_VER(payload);
- ret = true;
+ dev_kfree_skb_any(skb);
-out:
- return ret;
+ return true;
}
static bool rtw_coex_get_bt_supported_version(struct rtw_dev *rtwdev,
@@ -3554,19 +3547,17 @@ static bool rtw_coex_get_bt_supported_version(struct rtw_dev *rtwdev,
struct rtw_coex_info_req req = {0};
struct sk_buff *skb;
u8 *payload;
- bool ret = false;
req.op_code = BT_MP_INFO_OP_SUPP_VER;
skb = rtw_coex_info_request(rtwdev, &req);
if (!skb)
- goto out;
+ return false;
payload = get_payload_from_coex_resp(skb);
*supported_version = GET_COEX_RESP_BT_SUPP_VER(payload);
- ret = true;
+ dev_kfree_skb_any(skb);
-out:
- return ret;
+ return true;
}
static bool rtw_coex_get_bt_supported_feature(struct rtw_dev *rtwdev,
@@ -3575,19 +3566,17 @@ static bool rtw_coex_get_bt_supported_feature(struct rtw_dev *rtwdev,
struct rtw_coex_info_req req = {0};
struct sk_buff *skb;
u8 *payload;
- bool ret = false;
req.op_code = BT_MP_INFO_OP_SUPP_FEAT;
skb = rtw_coex_info_request(rtwdev, &req);
if (!skb)
- goto out;
+ return false;
payload = get_payload_from_coex_resp(skb);
*supported_feature = GET_COEX_RESP_BT_SUPP_FEAT(payload);
- ret = true;
+ dev_kfree_skb_any(skb);
-out:
- return ret;
+ return true;
}
struct rtw_coex_sta_stat_iter_data {
diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c
index 18ab472ea46c..dfd52cff5d02 100644
--- a/drivers/net/wireless/realtek/rtw88/debug.c
+++ b/drivers/net/wireless/realtek/rtw88/debug.c
@@ -11,6 +11,7 @@
#include "debug.h"
#include "phy.h"
#include "reg.h"
+#include "ps.h"
#ifdef CONFIG_RTW88_DEBUGFS
@@ -847,7 +848,13 @@ static ssize_t rtw_debugfs_set_fw_crash(struct file *filp,
if (!input)
return -EINVAL;
+ if (test_bit(RTW_FLAG_RESTARTING, rtwdev->flags))
+ return -EINPROGRESS;
+
+ mutex_lock(&rtwdev->mutex);
+ rtw_leave_lps_deep(rtwdev);
rtw_write8(rtwdev, REG_HRCV_MSG, 1);
+ mutex_unlock(&rtwdev->mutex);
return count;
}
diff --git a/drivers/net/wireless/realtek/rtw88/debug.h b/drivers/net/wireless/realtek/rtw88/debug.h
index c8efd1900a34..0dd3f9a88c8d 100644
--- a/drivers/net/wireless/realtek/rtw88/debug.h
+++ b/drivers/net/wireless/realtek/rtw88/debug.h
@@ -20,6 +20,7 @@ enum rtw_debug_mask {
RTW_DBG_BF = 0x00000800,
RTW_DBG_WOW = 0x00001000,
RTW_DBG_CFO = 0x00002000,
+ RTW_DBG_PATH_DIV = 0x00004000,
RTW_DBG_ALL = 0xffffffff
};
diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
index ea2cd4db1d3c..3bfa5ecc0053 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.c
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
@@ -127,6 +127,62 @@ static void rtw_fw_ra_report_handle(struct rtw_dev *rtwdev, u8 *payload,
rtw_iterate_stas_atomic(rtwdev, rtw_fw_ra_report_iter, &ra_data);
}
+struct rtw_beacon_filter_iter_data {
+ struct rtw_dev *rtwdev;
+ u8 *payload;
+};
+
+static void rtw_fw_bcn_filter_notify_vif_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct rtw_beacon_filter_iter_data *iter_data = data;
+ struct rtw_dev *rtwdev = iter_data->rtwdev;
+ u8 *payload = iter_data->payload;
+ u8 type = GET_BCN_FILTER_NOTIFY_TYPE(payload);
+ u8 event = GET_BCN_FILTER_NOTIFY_EVENT(payload);
+ s8 sig = (s8)GET_BCN_FILTER_NOTIFY_RSSI(payload);
+
+ switch (type) {
+ case BCN_FILTER_NOTIFY_SIGNAL_CHANGE:
+ event = event ? NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH :
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
+ ieee80211_cqm_rssi_notify(vif, event, sig, GFP_KERNEL);
+ break;
+ case BCN_FILTER_CONNECTION_LOSS:
+ ieee80211_connection_loss(vif);
+ break;
+ case BCN_FILTER_CONNECTED:
+ rtwdev->beacon_loss = false;
+ break;
+ case BCN_FILTER_NOTIFY_BEACON_LOSS:
+ rtwdev->beacon_loss = true;
+ rtw_leave_lps(rtwdev);
+ break;
+ }
+}
+
+static void rtw_fw_bcn_filter_notify(struct rtw_dev *rtwdev, u8 *payload,
+ u8 length)
+{
+ struct rtw_beacon_filter_iter_data dev_iter_data;
+
+ dev_iter_data.rtwdev = rtwdev;
+ dev_iter_data.payload = payload;
+ rtw_iterate_vifs(rtwdev, rtw_fw_bcn_filter_notify_vif_iter,
+ &dev_iter_data);
+}
+
+static void rtw_fw_scan_result(struct rtw_dev *rtwdev, u8 *payload,
+ u8 length)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+
+ dm_info->scan_density = payload[0];
+
+ rtw_dbg(rtwdev, RTW_DBG_FW, "scan.density = %x\n",
+ dm_info->scan_density);
+}
+
void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb)
{
struct rtw_c2h_cmd *c2h;
@@ -152,6 +208,9 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb)
case C2H_WLAN_INFO:
rtw_coex_wl_fwdbginfo_notify(rtwdev, c2h->payload, len);
break;
+ case C2H_BCN_FILTER_NOTIFY:
+ rtw_fw_bcn_filter_notify(rtwdev, c2h->payload, len);
+ break;
case C2H_HALMAC:
rtw_fw_c2h_cmd_handle_ext(rtwdev, skb);
break;
@@ -186,6 +245,12 @@ void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset,
break;
case C2H_WLAN_RFON:
complete(&rtwdev->lps_leave_check);
+ dev_kfree_skb_any(skb);
+ break;
+ case C2H_SCAN_RESULT:
+ complete(&rtwdev->fw_scan_density);
+ rtw_fw_scan_result(rtwdev, c2h->payload, len);
+ dev_kfree_skb_any(skb);
break;
default:
/* pass offset for further operation */
@@ -527,6 +592,45 @@ void rtw_fw_update_wl_phy_info(struct rtw_dev *rtwdev)
rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
}
+void rtw_fw_beacon_filter_config(struct rtw_dev *rtwdev, bool connect,
+ struct ieee80211_vif *vif)
+{
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
+ static const u8 rssi_min = 0, rssi_max = 100, rssi_offset = 100;
+ struct rtw_sta_info *si =
+ sta ? (struct rtw_sta_info *)sta->drv_priv : NULL;
+ s32 threshold = bss_conf->cqm_rssi_thold + rssi_offset;
+ u8 h2c_pkt[H2C_PKT_SIZE] = {0};
+
+ if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER) || !si)
+ return;
+
+ if (!connect) {
+ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_BCN_FILTER_OFFLOAD_P1);
+ SET_BCN_FILTER_OFFLOAD_P1_ENABLE(h2c_pkt, connect);
+ rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
+
+ return;
+ }
+ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_BCN_FILTER_OFFLOAD_P0);
+ ether_addr_copy(&h2c_pkt[1], bss_conf->bssid);
+ rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
+
+ memset(h2c_pkt, 0, sizeof(h2c_pkt));
+ threshold = clamp_t(s32, threshold, rssi_min, rssi_max);
+ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_BCN_FILTER_OFFLOAD_P1);
+ SET_BCN_FILTER_OFFLOAD_P1_ENABLE(h2c_pkt, connect);
+ SET_BCN_FILTER_OFFLOAD_P1_OFFLOAD_MODE(h2c_pkt,
+ BCN_FILTER_OFFLOAD_MODE_DEFAULT);
+ SET_BCN_FILTER_OFFLOAD_P1_THRESHOLD(h2c_pkt, (u8)threshold);
+ SET_BCN_FILTER_OFFLOAD_P1_BCN_LOSS_CNT(h2c_pkt, BCN_LOSS_CNT);
+ SET_BCN_FILTER_OFFLOAD_P1_MACID(h2c_pkt, si->mac_id);
+ SET_BCN_FILTER_OFFLOAD_P1_HYST(h2c_pkt, bss_conf->cqm_rssi_hyst);
+ SET_BCN_FILTER_OFFLOAD_P1_BCN_INTERVAL(h2c_pkt, bss_conf->beacon_int);
+ rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
+}
+
void rtw_fw_set_pwr_mode(struct rtw_dev *rtwdev)
{
struct rtw_lps_conf *conf = &rtwdev->lps_conf;
@@ -1613,3 +1717,13 @@ void rtw_fw_channel_switch(struct rtw_dev *rtwdev, bool enable)
rtw_fw_send_h2c_packet(rtwdev, h2c_pkt);
}
+
+void rtw_fw_scan_notify(struct rtw_dev *rtwdev, bool start)
+{
+ u8 h2c_pkt[H2C_PKT_SIZE] = {0};
+
+ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_SCAN);
+ SET_SCAN_START(h2c_pkt, start);
+
+ rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
+}
diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h
index 7c5b1d75e26f..a8a7162fbe64 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.h
+++ b/drivers/net/wireless/realtek/rtw88/fw.h
@@ -24,6 +24,14 @@
#define DLFW_BLK_SIZE_LEGACY 4
#define FW_START_ADDR_LEGACY 0x1000
+#define BCN_LOSS_CNT 10
+#define BCN_FILTER_NOTIFY_SIGNAL_CHANGE 0
+#define BCN_FILTER_CONNECTION_LOSS 1
+#define BCN_FILTER_CONNECTED 2
+#define BCN_FILTER_NOTIFY_BEACON_LOSS 3
+
+#define SCAN_NOTIFY_TIMEOUT msecs_to_jiffies(10)
+
enum rtw_c2h_cmd_id {
C2H_CCX_TX_RPT = 0x03,
C2H_BT_INFO = 0x09,
@@ -32,6 +40,8 @@ enum rtw_c2h_cmd_id {
C2H_HW_FEATURE_REPORT = 0x19,
C2H_WLAN_INFO = 0x27,
C2H_WLAN_RFON = 0x32,
+ C2H_BCN_FILTER_NOTIFY = 0x36,
+ C2H_SCAN_RESULT = 0x38,
C2H_HW_FEATURE_DUMP = 0xfd,
C2H_HALMAC = 0xff,
};
@@ -78,9 +88,20 @@ enum rtw_fw_feature {
FW_FEATURE_LPS_C2H = BIT(1),
FW_FEATURE_LCLK = BIT(2),
FW_FEATURE_PG = BIT(3),
+ FW_FEATURE_BCN_FILTER = BIT(5),
+ FW_FEATURE_NOTIFY_SCAN = BIT(6),
FW_FEATURE_MAX = BIT(31),
};
+enum rtw_beacon_filter_offload_mode {
+ BCN_FILTER_OFFLOAD_MODE_0 = 0,
+ BCN_FILTER_OFFLOAD_MODE_1,
+ BCN_FILTER_OFFLOAD_MODE_2,
+ BCN_FILTER_OFFLOAD_MODE_3,
+
+ BCN_FILTER_OFFLOAD_MODE_DEFAULT = BCN_FILTER_OFFLOAD_MODE_1,
+};
+
struct rtw_coex_info_req {
u8 seq;
u8 op_code;
@@ -237,6 +258,10 @@ struct rtw_fw_hdr_legacy {
#define GET_RA_REPORT_BW(c2h_payload) (c2h_payload[6])
#define GET_RA_REPORT_MACID(c2h_payload) (c2h_payload[1])
+#define GET_BCN_FILTER_NOTIFY_TYPE(c2h_payload) (c2h_payload[1] & 0xf)
+#define GET_BCN_FILTER_NOTIFY_EVENT(c2h_payload) (c2h_payload[1] & 0x10)
+#define GET_BCN_FILTER_NOTIFY_RSSI(c2h_payload) (c2h_payload[2] - 100)
+
/* PKT H2C */
#define H2C_PKT_CMD_ID 0xFF
#define H2C_PKT_CATEGORY 0x01
@@ -345,7 +370,10 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
#define H2C_CMD_LPS_PG_INFO 0x2b
#define H2C_CMD_RA_INFO 0x40
#define H2C_CMD_RSSI_MONITOR 0x42
+#define H2C_CMD_BCN_FILTER_OFFLOAD_P0 0x56
+#define H2C_CMD_BCN_FILTER_OFFLOAD_P1 0x57
#define H2C_CMD_WL_PHY_INFO 0x58
+#define H2C_CMD_SCAN 0x59
#define H2C_CMD_COEX_TDMA_TYPE 0x60
#define H2C_CMD_QUERY_BT_INFO 0x61
@@ -381,6 +409,23 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8))
#define SET_WL_PHY_INFO_RX_EVM(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(23, 16))
+#define SET_BCN_FILTER_OFFLOAD_P1_MACID(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
+#define SET_BCN_FILTER_OFFLOAD_P1_ENABLE(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(16))
+#define SET_BCN_FILTER_OFFLOAD_P1_HYST(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(20, 17))
+#define SET_BCN_FILTER_OFFLOAD_P1_OFFLOAD_MODE(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 21))
+#define SET_BCN_FILTER_OFFLOAD_P1_THRESHOLD(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24))
+#define SET_BCN_FILTER_OFFLOAD_P1_BCN_LOSS_CNT(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(3, 0))
+#define SET_BCN_FILTER_OFFLOAD_P1_BCN_INTERVAL(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(13, 4))
+
+#define SET_SCAN_START(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define SET_PWR_MODE_SET_MODE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(14, 8))
@@ -554,6 +599,12 @@ static inline struct rtw_c2h_cmd *get_c2h_from_skb(struct sk_buff *skb)
return (struct rtw_c2h_cmd *)(skb->data + pkt_offset);
}
+static inline bool rtw_fw_feature_check(struct rtw_fw_state *fw,
+ enum rtw_fw_feature feature)
+{
+ return !!(fw->feature & feature);
+}
+
void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset,
struct sk_buff *skb);
void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb);
@@ -577,6 +628,8 @@ void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si);
void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si);
void rtw_fw_media_status_report(struct rtw_dev *rtwdev, u8 mac_id, bool conn);
void rtw_fw_update_wl_phy_info(struct rtw_dev *rtwdev);
+void rtw_fw_beacon_filter_config(struct rtw_dev *rtwdev, bool connect,
+ struct ieee80211_vif *vif);
int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr,
u8 *buf, u32 size);
void rtw_remove_rsvd_page(struct rtw_dev *rtwdev,
@@ -607,5 +660,5 @@ void rtw_fw_h2c_cmd_dbg(struct rtw_dev *rtwdev, u8 *h2c);
void rtw_fw_c2h_cmd_isr(struct rtw_dev *rtwdev);
int rtw_fw_dump_fifo(struct rtw_dev *rtwdev, u8 fifo_sel, u32 addr, u32 size,
u32 *buffer);
-
+void rtw_fw_scan_notify(struct rtw_dev *rtwdev, bool start);
#endif
diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c
index 333df6b38113..6f5629852416 100644
--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
@@ -153,6 +153,9 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw,
u8 port = 0;
u8 bcn_ctrl = 0;
+ if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER))
+ vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
+ IEEE80211_VIF_SUPPORTS_CQM_RSSI;
rtwvif->port = port;
rtwvif->stats.tx_unicast = 0;
rtwvif->stats.rx_unicast = 0;
@@ -399,6 +402,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
rtw_write32_clr(rtwdev, REG_FWHW_TXQ_CTRL,
BIT_EN_BCNQ_DL);
}
+ if (changed & BSS_CHANGED_CQM)
+ rtw_fw_beacon_filter_config(rtwdev, true, vif);
if (changed & BSS_CHANGED_MU_GROUPS)
rtw_chip_set_gid_table(rtwdev, vif, conf);
@@ -450,6 +455,7 @@ static int rtw_ops_sta_remove(struct ieee80211_hw *hw,
{
struct rtw_dev *rtwdev = hw->priv;
+ rtw_fw_beacon_filter_config(rtwdev, false, vif);
mutex_lock(&rtwdev->mutex);
rtw_sta_remove(rtwdev, sta, true);
mutex_unlock(&rtwdev->mutex);
@@ -599,6 +605,7 @@ static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw,
rtw_vif_port_config(rtwdev, rtwvif, config);
rtw_coex_scan_notify(rtwdev, COEX_SCAN_START);
+ rtw_core_fw_scan_notify(rtwdev, true);
set_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags);
set_bit(RTW_FLAG_SCANNING, rtwdev->flags);
@@ -618,6 +625,8 @@ static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw,
clear_bit(RTW_FLAG_SCANNING, rtwdev->flags);
clear_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags);
+ rtw_core_fw_scan_notify(rtwdev, false);
+
ether_addr_copy(rtwvif->mac_addr, vif->addr);
config |= PORT_SET_MAC_ADDR;
rtw_vif_port_config(rtwdev, rtwvif, config);
@@ -629,7 +638,7 @@ static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw,
static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- u16 duration)
+ struct ieee80211_prep_tx_info *info)
{
struct rtw_dev *rtwdev = hw->priv;
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index f3a3a86fa9b5..c6364837e83b 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -2,6 +2,8 @@
/* Copyright(c) 2018-2019 Realtek Corporation
*/
+#include <linux/devcoredump.h>
+
#include "main.h"
#include "regd.h"
#include "fw.h"
@@ -239,7 +241,8 @@ static void rtw_watch_dog_work(struct work_struct *work)
* get that vif and check if device is having traffic more than the
* threshold.
*/
- if (rtwdev->ps_enabled && data.rtwvif && !ps_active)
+ if (rtwdev->ps_enabled && data.rtwvif && !ps_active &&
+ !rtwdev->beacon_loss)
rtw_enter_lps(rtwdev, data.rtwvif->port);
rtwdev->watch_dog_cnt++;
@@ -292,6 +295,7 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta,
rtw_fw_media_status_report(rtwdev, si->mac_id, true);
rtwdev->sta_cnt++;
+ rtwdev->beacon_loss = false;
rtw_info(rtwdev, "sta %pM joined with macid %d\n",
sta->addr, si->mac_id);
@@ -318,59 +322,131 @@ void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta,
sta->addr, si->mac_id);
}
-static bool rtw_fw_dump_crash_log(struct rtw_dev *rtwdev)
+struct rtw_fwcd_hdr {
+ u32 item;
+ u32 size;
+ u32 padding1;
+ u32 padding2;
+} __packed;
+
+static int rtw_fwcd_prep(struct rtw_dev *rtwdev)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+ struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc;
+ const struct rtw_fwcd_segs *segs = chip->fwcd_segs;
+ u32 prep_size = chip->fw_rxff_size + sizeof(struct rtw_fwcd_hdr);
+ u8 i;
+
+ if (segs) {
+ prep_size += segs->num * sizeof(struct rtw_fwcd_hdr);
+
+ for (i = 0; i < segs->num; i++)
+ prep_size += segs->segs[i];
+ }
+
+ desc->data = vmalloc(prep_size);
+ if (!desc->data)
+ return -ENOMEM;
+
+ desc->size = prep_size;
+ desc->next = desc->data;
+
+ return 0;
+}
+
+static u8 *rtw_fwcd_next(struct rtw_dev *rtwdev, u32 item, u32 size)
+{
+ struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc;
+ struct rtw_fwcd_hdr *hdr;
+ u8 *next;
+
+ if (!desc->data) {
+ rtw_dbg(rtwdev, RTW_DBG_FW, "fwcd isn't prepared successfully\n");
+ return NULL;
+ }
+
+ next = desc->next + sizeof(struct rtw_fwcd_hdr);
+ if (next - desc->data + size > desc->size) {
+ rtw_dbg(rtwdev, RTW_DBG_FW, "fwcd isn't prepared enough\n");
+ return NULL;
+ }
+
+ hdr = (struct rtw_fwcd_hdr *)(desc->next);
+ hdr->item = item;
+ hdr->size = size;
+ hdr->padding1 = 0x01234567;
+ hdr->padding2 = 0x89abcdef;
+ desc->next = next + size;
+
+ return next;
+}
+
+static void rtw_fwcd_dump(struct rtw_dev *rtwdev)
+{
+ struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc;
+
+ rtw_dbg(rtwdev, RTW_DBG_FW, "dump fwcd\n");
+
+ /* Data will be freed after lifetime of device coredump. After calling
+ * dev_coredump, data is supposed to be handled by the device coredump
+ * framework. Note that a new dump will be discarded if a previous one
+ * hasn't been released yet.
+ */
+ dev_coredumpv(rtwdev->dev, desc->data, desc->size, GFP_KERNEL);
+}
+
+static void rtw_fwcd_free(struct rtw_dev *rtwdev, bool free_self)
+{
+ struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc;
+
+ if (free_self) {
+ rtw_dbg(rtwdev, RTW_DBG_FW, "free fwcd by self\n");
+ vfree(desc->data);
+ }
+
+ desc->data = NULL;
+ desc->next = NULL;
+}
+
+static int rtw_fw_dump_crash_log(struct rtw_dev *rtwdev)
{
u32 size = rtwdev->chip->fw_rxff_size;
u32 *buf;
u8 seq;
- bool ret = true;
- buf = vmalloc(size);
+ buf = (u32 *)rtw_fwcd_next(rtwdev, RTW_FWCD_TLV, size);
if (!buf)
- goto exit;
+ return -ENOMEM;
if (rtw_fw_dump_fifo(rtwdev, RTW_FW_FIFO_SEL_RXBUF_FW, 0, size, buf)) {
rtw_dbg(rtwdev, RTW_DBG_FW, "dump fw fifo fail\n");
- goto free_buf;
+ return -EINVAL;
}
if (GET_FW_DUMP_LEN(buf) == 0) {
rtw_dbg(rtwdev, RTW_DBG_FW, "fw crash dump's length is 0\n");
- goto free_buf;
+ return -EINVAL;
}
seq = GET_FW_DUMP_SEQ(buf);
- if (seq > 0 && seq != (rtwdev->fw.prev_dump_seq + 1)) {
+ if (seq > 0) {
rtw_dbg(rtwdev, RTW_DBG_FW,
"fw crash dump's seq is wrong: %d\n", seq);
- goto free_buf;
- }
-
- print_hex_dump(KERN_ERR, "rtw88 fw dump: ", DUMP_PREFIX_OFFSET, 16, 1,
- buf, size, true);
-
- if (GET_FW_DUMP_MORE(buf) == 1) {
- rtwdev->fw.prev_dump_seq = seq;
- ret = false;
+ return -EINVAL;
}
-free_buf:
- vfree(buf);
-exit:
- rtw_write8(rtwdev, REG_MCU_TST_CFG, 0);
-
- return ret;
+ return 0;
}
int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size,
- const char *prefix_str)
+ u32 fwcd_item)
{
u32 rxff = rtwdev->chip->fw_rxff_size;
u32 dump_size, done_size = 0;
u8 *buf;
int ret;
- buf = vzalloc(size);
+ buf = rtw_fwcd_next(rtwdev, fwcd_item, size);
if (!buf)
return -ENOMEM;
@@ -383,7 +459,7 @@ int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size,
rtw_err(rtwdev,
"ddma fw 0x%x [+0x%x] to fw fifo fail\n",
ocp_src, done_size);
- goto exit;
+ return ret;
}
ret = rtw_fw_dump_fifo(rtwdev, RTW_FW_FIFO_SEL_RXBUF_FW, 0,
@@ -392,24 +468,18 @@ int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size,
rtw_err(rtwdev,
"dump fw 0x%x [+0x%x] from fw fifo fail\n",
ocp_src, done_size);
- goto exit;
+ return ret;
}
size -= dump_size;
done_size += dump_size;
}
- print_hex_dump(KERN_ERR, prefix_str, DUMP_PREFIX_OFFSET, 16, 1,
- buf, done_size, true);
-
-exit:
- vfree(buf);
- return ret;
+ return 0;
}
EXPORT_SYMBOL(rtw_dump_fw);
-int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size,
- const char *prefix_str)
+int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size)
{
u8 *buf;
u32 i;
@@ -419,17 +489,13 @@ int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size,
return -EINVAL;
}
- buf = vzalloc(size);
+ buf = rtw_fwcd_next(rtwdev, RTW_FWCD_REG, size);
if (!buf)
return -ENOMEM;
for (i = 0; i < size; i += 4)
*(u32 *)(buf + i) = rtw_read32(rtwdev, addr + i);
- print_hex_dump(KERN_ERR, prefix_str, DUMP_PREFIX_OFFSET, 16, 4, buf,
- size, true);
-
- vfree(buf);
return 0;
}
EXPORT_SYMBOL(rtw_dump_reg);
@@ -487,20 +553,24 @@ void rtw_fw_recovery(struct rtw_dev *rtwdev)
static void __fw_recovery_work(struct rtw_dev *rtwdev)
{
-
- /* rtw_fw_dump_crash_log() returns false indicates that there are
- * still more log to dump. Driver set 0x1cf[7:0] = 0x1 to tell firmware
- * to dump the remaining part of the log, and firmware will trigger an
- * IMR_C2HCMD interrupt to inform driver the log is ready.
- */
- if (!rtw_fw_dump_crash_log(rtwdev)) {
- rtw_write8(rtwdev, REG_HRCV_MSG, 1);
- return;
- }
- rtwdev->fw.prev_dump_seq = 0;
+ int ret = 0;
set_bit(RTW_FLAG_RESTARTING, rtwdev->flags);
- rtw_chip_dump_fw_crash(rtwdev);
+
+ ret = rtw_fwcd_prep(rtwdev);
+ if (ret)
+ goto free;
+ ret = rtw_fw_dump_crash_log(rtwdev);
+ if (ret)
+ goto free;
+ ret = rtw_chip_dump_fw_crash(rtwdev);
+ if (ret)
+ goto free;
+
+ rtw_fwcd_dump(rtwdev);
+free:
+ rtw_fwcd_free(rtwdev, !!ret);
+ rtw_write8(rtwdev, REG_MCU_TST_CFG, 0);
WARN(1, "firmware crash, start reset and recover\n");
@@ -1109,11 +1179,11 @@ static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev,
return LPS_DEEP_MODE_NONE;
if ((chip->lps_deep_mode_supported & BIT(LPS_DEEP_MODE_PG)) &&
- (fw->feature & FW_FEATURE_PG))
+ rtw_fw_feature_check(fw, FW_FEATURE_PG))
return LPS_DEEP_MODE_PG;
if ((chip->lps_deep_mode_supported & BIT(LPS_DEEP_MODE_LCLK)) &&
- (fw->feature & FW_FEATURE_LCLK))
+ rtw_fw_feature_check(fw, FW_FEATURE_LCLK))
return LPS_DEEP_MODE_LCLK;
return LPS_DEEP_MODE_NONE;
@@ -1183,6 +1253,22 @@ err:
return ret;
}
+void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start)
+{
+ if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_NOTIFY_SCAN))
+ return;
+
+ if (start) {
+ rtw_fw_scan_notify(rtwdev, true);
+ } else {
+ reinit_completion(&rtwdev->fw_scan_density);
+ rtw_fw_scan_notify(rtwdev, false);
+ if (!wait_for_completion_timeout(&rtwdev->fw_scan_density,
+ SCAN_NOTIFY_TIMEOUT))
+ rtw_warn(rtwdev, "firmware failed to report density after scan\n");
+ }
+}
+
int rtw_core_start(struct rtw_dev *rtwdev)
{
int ret;
@@ -1761,6 +1847,7 @@ int rtw_core_init(struct rtw_dev *rtwdev)
init_waitqueue_head(&rtwdev->coex.wait);
init_completion(&rtwdev->lps_leave_check);
+ init_completion(&rtwdev->fw_scan_density);
rtwdev->sec.total_cam_num = 32;
rtwdev->hal.current_channel = 1;
@@ -1812,6 +1899,7 @@ void rtw_core_deinit(struct rtw_dev *rtwdev)
destroy_workqueue(rtwdev->tx_wq);
spin_lock_irqsave(&rtwdev->tx_report.q_lock, flags);
skb_queue_purge(&rtwdev->tx_report.queue);
+ skb_queue_purge(&rtwdev->coex.queue);
spin_unlock_irqrestore(&rtwdev->tx_report.q_lock, flags);
list_for_each_entry_safe(rsvd_pkt, tmp, &rtwdev->rsvd_page_list,
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index dc3744847ba9..e5af375b3dd0 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -806,7 +806,7 @@ struct rtw_regulatory {
struct rtw_chip_ops {
int (*mac_init)(struct rtw_dev *rtwdev);
- void (*dump_fw_crash)(struct rtw_dev *rtwdev);
+ int (*dump_fw_crash)(struct rtw_dev *rtwdev);
void (*shutdown)(struct rtw_dev *rtwdev);
int (*read_efuse)(struct rtw_dev *rtwdev, u8 *map);
void (*phy_set_param)(struct rtw_dev *rtwdev);
@@ -841,6 +841,10 @@ struct rtw_chip_ops {
u8 fixrate_en, u8 *new_rate);
void (*cfo_init)(struct rtw_dev *rtwdev);
void (*cfo_track)(struct rtw_dev *rtwdev);
+ void (*config_tx_path)(struct rtw_dev *rtwdev, u8 tx_path,
+ enum rtw_bb_path tx_path_1ss,
+ enum rtw_bb_path tx_path_cck,
+ bool is_tx2_path);
/* for coex */
void (*coex_set_init)(struct rtw_dev *rtwdev);
@@ -1108,6 +1112,15 @@ enum rtw_fw_fifo_sel {
RTW_FW_FIFO_MAX,
};
+enum rtw_fwcd_item {
+ RTW_FWCD_TLV,
+ RTW_FWCD_REG,
+ RTW_FWCD_ROM,
+ RTW_FWCD_IMEM,
+ RTW_FWCD_DMEM,
+ RTW_FWCD_EMEM,
+};
+
/* hardware configuration for each IC */
struct rtw_chip_info {
struct rtw_chip_ops *ops;
@@ -1136,7 +1149,11 @@ struct rtw_chip_info {
u8 max_power_index;
u16 fw_fifo_addr[RTW_FW_FIFO_MAX];
+ const struct rtw_fwcd_segs *fwcd_segs;
+
+ u8 default_1ss_tx_path;
+ bool path_div_supported;
bool ht_supported;
bool vht_supported;
u8 lps_deep_mode_supported;
@@ -1614,6 +1631,8 @@ struct rtw_dm_info {
struct rtw_iqk_info iqk;
struct rtw_gapk_info gapk;
bool is_bt_iqk_timeout;
+
+ u8 scan_density;
};
struct rtw_efuse {
@@ -1717,6 +1736,17 @@ struct rtw_fifo_conf {
const struct rtw_rqpn *rqpn;
};
+struct rtw_fwcd_desc {
+ u32 size;
+ u8 *next;
+ u8 *data;
+};
+
+struct rtw_fwcd_segs {
+ const u32 *segs;
+ u8 num;
+};
+
#define FW_CD_TYPE 0xffff
#define FW_CD_LEN 4
#define FW_CD_VAL 0xaabbccdd
@@ -1724,11 +1754,11 @@ struct rtw_fw_state {
const struct firmware *firmware;
struct rtw_dev *rtwdev;
struct completion completion;
+ struct rtw_fwcd_desc fwcd_desc;
u16 version;
u8 sub_version;
u8 sub_index;
u16 h2c_version;
- u8 prev_dump_seq;
u32 feature;
};
@@ -1781,6 +1811,14 @@ struct rtw_hal {
[DESC_RATE_MAX];
};
+struct rtw_path_div {
+ enum rtw_bb_path current_tx_path;
+ u32 path_a_sum;
+ u32 path_b_sum;
+ u16 path_a_cnt;
+ u16 path_b_cnt;
+};
+
struct rtw_dev {
struct ieee80211_hw *hw;
struct device *dev;
@@ -1837,6 +1875,7 @@ struct rtw_dev {
/* lps power state & handler work */
struct rtw_lps_conf lps_conf;
bool ps_enabled;
+ bool beacon_loss;
struct completion lps_leave_check;
struct dentry *debugfs;
@@ -1848,11 +1887,13 @@ struct rtw_dev {
DECLARE_BITMAP(flags, NUM_OF_RTW_FLAGS);
u8 mp_mode;
+ struct rtw_path_div dm_path_div;
struct rtw_fw_state wow_fw;
struct rtw_wow_param wow;
bool need_rfk;
+ struct completion fw_scan_density;
/* hci related data, must be last */
u8 priv[] __aligned(sizeof(void *));
@@ -1923,10 +1964,12 @@ static inline void rtw_release_macid(struct rtw_dev *rtwdev, u8 mac_id)
clear_bit(mac_id, rtwdev->mac_id_map);
}
-static inline void rtw_chip_dump_fw_crash(struct rtw_dev *rtwdev)
+static inline int rtw_chip_dump_fw_crash(struct rtw_dev *rtwdev)
{
if (rtwdev->chip->ops->dump_fw_crash)
- rtwdev->chip->ops->dump_fw_crash(rtwdev);
+ return rtwdev->chip->ops->dump_fw_crash(rtwdev);
+
+ return 0;
}
void rtw_get_channel_params(struct cfg80211_chan_def *chandef,
@@ -1958,9 +2001,9 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta,
void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta,
bool fw_exist);
void rtw_fw_recovery(struct rtw_dev *rtwdev);
+void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start);
int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size,
- const char *prefix_str);
-int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size,
- const char *prefix_str);
+ u32 fwcd_item);
+int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size);
#endif
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index f59a4c462e3b..e7d17ab8f113 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -2,6 +2,7 @@
/* Copyright(c) 2018-2019 Realtek Corporation
*/
+#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "main.h"
@@ -1673,6 +1674,36 @@ static void rtw_pci_napi_deinit(struct rtw_dev *rtwdev)
netif_napi_del(&rtwpci->napi);
}
+enum rtw88_quirk_dis_pci_caps {
+ QUIRK_DIS_PCI_CAP_MSI,
+ QUIRK_DIS_PCI_CAP_ASPM,
+};
+
+static int disable_pci_caps(const struct dmi_system_id *dmi)
+{
+ uintptr_t dis_caps = (uintptr_t)dmi->driver_data;
+
+ if (dis_caps & BIT(QUIRK_DIS_PCI_CAP_MSI))
+ rtw_disable_msi = true;
+ if (dis_caps & BIT(QUIRK_DIS_PCI_CAP_ASPM))
+ rtw_pci_disable_aspm = true;
+
+ return 1;
+}
+
+static const struct dmi_system_id rtw88_pci_quirks[] = {
+ {
+ .callback = disable_pci_caps,
+ .ident = "Protempo Ltd L116HTN6SPW",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Protempo Ltd"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "L116HTN6SPW"),
+ },
+ .driver_data = (void *)BIT(QUIRK_DIS_PCI_CAP_ASPM),
+ },
+ {}
+};
+
int rtw_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -1723,6 +1754,7 @@ int rtw_pci_probe(struct pci_dev *pdev,
goto err_destroy_pci;
}
+ dmi_check_system(rtw88_pci_quirks);
rtw_pci_phy_cfg(rtwdev);
ret = rtw_register_hw(rtwdev, hw);
diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
index 8146acaf1893..569dd3cfde35 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.c
+++ b/drivers/net/wireless/realtek/rtw88/phy.c
@@ -127,6 +127,17 @@ static void rtw_phy_cfo_init(struct rtw_dev *rtwdev)
chip->ops->cfo_init(rtwdev);
}
+static void rtw_phy_tx_path_div_init(struct rtw_dev *rtwdev)
+{
+ struct rtw_path_div *path_div = &rtwdev->dm_path_div;
+
+ path_div->current_tx_path = rtwdev->chip->default_1ss_tx_path;
+ path_div->path_a_cnt = 0;
+ path_div->path_a_sum = 0;
+ path_div->path_b_cnt = 0;
+ path_div->path_b_sum = 0;
+}
+
void rtw_phy_init(struct rtw_dev *rtwdev)
{
struct rtw_chip_info *chip = rtwdev->chip;
@@ -149,6 +160,7 @@ void rtw_phy_init(struct rtw_dev *rtwdev)
dm_info->iqk.done = false;
rtw_phy_cfo_init(rtwdev);
+ rtw_phy_tx_path_div_init(rtwdev);
}
EXPORT_SYMBOL(rtw_phy_init);
@@ -695,6 +707,7 @@ void rtw_phy_dynamic_mechanism(struct rtw_dev *rtwdev)
rtw_phy_dig(rtwdev);
rtw_phy_cck_pd(rtwdev);
rtw_phy_ra_track(rtwdev);
+ rtw_phy_tx_path_diversity(rtwdev);
rtw_phy_cfo_track(rtwdev);
rtw_phy_dpk_track(rtwdev);
rtw_phy_pwr_track(rtwdev);
@@ -2315,3 +2328,71 @@ bool rtw_phy_pwrtrack_need_iqk(struct rtw_dev *rtwdev)
return false;
}
EXPORT_SYMBOL(rtw_phy_pwrtrack_need_iqk);
+
+static void rtw_phy_set_tx_path_by_reg(struct rtw_dev *rtwdev,
+ enum rtw_bb_path tx_path_sel_1ss)
+{
+ struct rtw_path_div *path_div = &rtwdev->dm_path_div;
+ enum rtw_bb_path tx_path_sel_cck = tx_path_sel_1ss;
+ struct rtw_chip_info *chip = rtwdev->chip;
+
+ if (tx_path_sel_1ss == path_div->current_tx_path)
+ return;
+
+ path_div->current_tx_path = tx_path_sel_1ss;
+ rtw_dbg(rtwdev, RTW_DBG_PATH_DIV, "Switch TX path=%s\n",
+ tx_path_sel_1ss == BB_PATH_A ? "A" : "B");
+ chip->ops->config_tx_path(rtwdev, rtwdev->hal.antenna_tx,
+ tx_path_sel_1ss, tx_path_sel_cck, false);
+}
+
+static void rtw_phy_tx_path_div_select(struct rtw_dev *rtwdev)
+{
+ struct rtw_path_div *path_div = &rtwdev->dm_path_div;
+ enum rtw_bb_path path = path_div->current_tx_path;
+ s32 rssi_a = 0, rssi_b = 0;
+
+ if (path_div->path_a_cnt)
+ rssi_a = path_div->path_a_sum / path_div->path_a_cnt;
+ else
+ rssi_a = 0;
+ if (path_div->path_b_cnt)
+ rssi_b = path_div->path_b_sum / path_div->path_b_cnt;
+ else
+ rssi_b = 0;
+
+ if (rssi_a != rssi_b)
+ path = (rssi_a > rssi_b) ? BB_PATH_A : BB_PATH_B;
+
+ path_div->path_a_cnt = 0;
+ path_div->path_a_sum = 0;
+ path_div->path_b_cnt = 0;
+ path_div->path_b_sum = 0;
+ rtw_phy_set_tx_path_by_reg(rtwdev, path);
+}
+
+static void rtw_phy_tx_path_diversity_2ss(struct rtw_dev *rtwdev)
+{
+ if (rtwdev->hal.antenna_rx != BB_PATH_AB) {
+ rtw_dbg(rtwdev, RTW_DBG_PATH_DIV,
+ "[Return] tx_Path_en=%d, rx_Path_en=%d\n",
+ rtwdev->hal.antenna_tx, rtwdev->hal.antenna_rx);
+ return;
+ }
+ if (rtwdev->sta_cnt == 0) {
+ rtw_dbg(rtwdev, RTW_DBG_PATH_DIV, "No Link\n");
+ return;
+ }
+
+ rtw_phy_tx_path_div_select(rtwdev);
+}
+
+void rtw_phy_tx_path_diversity(struct rtw_dev *rtwdev)
+{
+ struct rtw_chip_info *chip = rtwdev->chip;
+
+ if (!chip->path_div_supported)
+ return;
+
+ rtw_phy_tx_path_diversity_2ss(rtwdev);
+}
diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h
index 0b6f2fc8193c..112ed125970a 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.h
+++ b/drivers/net/wireless/realtek/rtw88/phy.h
@@ -61,6 +61,7 @@ void rtw_phy_config_swing_table(struct rtw_dev *rtwdev,
struct rtw_swing_table *swing_table);
void rtw_phy_parsing_cfo(struct rtw_dev *rtwdev,
struct rtw_rx_pkt_stat *pkt_stat);
+void rtw_phy_tx_path_diversity(struct rtw_dev *rtwdev);
struct rtw_txpwr_lmt_cfg_pair {
u8 regd;
diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c
index 3bead34c3d10..3f0ac33156d6 100644
--- a/drivers/net/wireless/realtek/rtw88/ps.c
+++ b/drivers/net/wireless/realtek/rtw88/ps.c
@@ -152,7 +152,7 @@ static void rtw_fw_leave_lps_check(struct rtw_dev *rtwdev)
else
fw = &rtwdev->fw;
- if (fw->feature & FW_FEATURE_LPS_C2H)
+ if (rtw_fw_feature_check(fw, FW_FEATURE_LPS_C2H))
ret = __rtw_fw_leave_lps_check_c2h(rtwdev);
else
ret = __rtw_fw_leave_lps_check_reg(rtwdev);
@@ -172,7 +172,7 @@ static void rtw_fw_leave_lps_check_prepare(struct rtw_dev *rtwdev)
else
fw = &rtwdev->fw;
- if (fw->feature & FW_FEATURE_LPS_C2H)
+ if (rtw_fw_feature_check(fw, FW_FEATURE_LPS_C2H))
reinit_completion(&rtwdev->lps_leave_check);
}
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index 6cb593cc33c2..8bf3cd3a3678 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -17,7 +17,6 @@
#include "util.h"
#include "bf.h"
#include "efuse.h"
-#include "coex.h"
#define IQK_DONE_8822C 0xaa
@@ -80,6 +79,13 @@ static void rtw8822c_header_file_init(struct rtw_dev *rtwdev, bool pre)
rtw_write32_set(rtwdev, REG_ENCCK, BIT_CCK_OFDM_BLK_EN);
}
+static void rtw8822c_bb_reset(struct rtw_dev *rtwdev)
+{
+ rtw_write16_set(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_BB_RSTB);
+ rtw_write16_clr(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_BB_RSTB);
+ rtw_write16_set(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_BB_RSTB);
+}
+
static void rtw8822c_dac_backup_reg(struct rtw_dev *rtwdev,
struct rtw_backup_info *backup,
struct rtw_backup_info *backup_rf)
@@ -2103,13 +2109,51 @@ static int rtw8822c_mac_init(struct rtw_dev *rtwdev)
return 0;
}
-static void rtw8822c_dump_fw_crash(struct rtw_dev *rtwdev)
+#define FWCD_SIZE_REG_8822C 0x2000
+#define FWCD_SIZE_DMEM_8822C 0x10000
+#define FWCD_SIZE_IMEM_8822C 0x10000
+#define FWCD_SIZE_EMEM_8822C 0x20000
+#define FWCD_SIZE_ROM_8822C 0x10000
+
+static const u32 __fwcd_segs_8822c[] = {
+ FWCD_SIZE_REG_8822C,
+ FWCD_SIZE_DMEM_8822C,
+ FWCD_SIZE_IMEM_8822C,
+ FWCD_SIZE_EMEM_8822C,
+ FWCD_SIZE_ROM_8822C,
+};
+
+static const struct rtw_fwcd_segs rtw8822c_fwcd_segs = {
+ .segs = __fwcd_segs_8822c,
+ .num = ARRAY_SIZE(__fwcd_segs_8822c),
+};
+
+static int rtw8822c_dump_fw_crash(struct rtw_dev *rtwdev)
{
- rtw_dump_reg(rtwdev, 0x0, 0x2000, "rtw8822c reg_");
- rtw_dump_fw(rtwdev, OCPBASE_DMEM_88XX, 0x10000, "rtw8822c DMEM_");
- rtw_dump_fw(rtwdev, OCPBASE_IMEM_88XX, 0x10000, "rtw8822c IMEM_");
- rtw_dump_fw(rtwdev, OCPBASE_EMEM_88XX, 0x20000, "rtw8822c EMEM_");
- rtw_dump_fw(rtwdev, OCPBASE_ROM_88XX, 0x10000, "rtw8822c ROM_");
+#define __dump_fw_8822c(_dev, _mem) \
+ rtw_dump_fw(_dev, OCPBASE_ ## _mem ## _88XX, \
+ FWCD_SIZE_ ## _mem ## _8822C, RTW_FWCD_ ## _mem)
+ int ret;
+
+ ret = rtw_dump_reg(rtwdev, 0x0, FWCD_SIZE_REG_8822C);
+ if (ret)
+ return ret;
+ ret = __dump_fw_8822c(rtwdev, DMEM);
+ if (ret)
+ return ret;
+ ret = __dump_fw_8822c(rtwdev, IMEM);
+ if (ret)
+ return ret;
+ ret = __dump_fw_8822c(rtwdev, EMEM);
+ if (ret)
+ return ret;
+ ret = __dump_fw_8822c(rtwdev, ROM);
+ if (ret)
+ return ret;
+
+ return 0;
+
+#undef __dump_fw_8822c
}
static void rtw8822c_rstb_3wire(struct rtw_dev *rtwdev, bool enable)
@@ -2424,10 +2468,11 @@ static void rtw8822c_config_cck_tx_path(struct rtw_dev *rtwdev, u8 tx_path,
else
rtw_write32_mask(rtwdev, REG_RXCCKSEL, 0xf0000000, 0x8);
}
+ rtw8822c_bb_reset(rtwdev);
}
static void rtw8822c_config_ofdm_tx_path(struct rtw_dev *rtwdev, u8 tx_path,
- bool is_tx2_path)
+ enum rtw_bb_path tx_path_sel_1ss)
{
if (tx_path == BB_PATH_A) {
rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x11);
@@ -2436,21 +2481,28 @@ static void rtw8822c_config_ofdm_tx_path(struct rtw_dev *rtwdev, u8 tx_path,
rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x12);
rtw_write32_mask(rtwdev, REG_TXLGMAP, 0xff, 0x0);
} else {
- if (is_tx2_path) {
+ if (tx_path_sel_1ss == BB_PATH_AB) {
rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x33);
rtw_write32_mask(rtwdev, REG_TXLGMAP, 0xffff, 0x0404);
- } else {
+ } else if (tx_path_sel_1ss == BB_PATH_B) {
+ rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x32);
+ rtw_write32_mask(rtwdev, REG_TXLGMAP, 0xffff, 0x0400);
+ } else if (tx_path_sel_1ss == BB_PATH_A) {
rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x31);
rtw_write32_mask(rtwdev, REG_TXLGMAP, 0xffff, 0x0400);
}
}
+ rtw8822c_bb_reset(rtwdev);
}
static void rtw8822c_config_tx_path(struct rtw_dev *rtwdev, u8 tx_path,
+ enum rtw_bb_path tx_path_sel_1ss,
+ enum rtw_bb_path tx_path_cck,
bool is_tx2_path)
{
- rtw8822c_config_cck_tx_path(rtwdev, tx_path, is_tx2_path);
- rtw8822c_config_ofdm_tx_path(rtwdev, tx_path, is_tx2_path);
+ rtw8822c_config_cck_tx_path(rtwdev, tx_path_cck, is_tx2_path);
+ rtw8822c_config_ofdm_tx_path(rtwdev, tx_path, tx_path_sel_1ss);
+ rtw8822c_bb_reset(rtwdev);
}
static void rtw8822c_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path,
@@ -2466,7 +2518,8 @@ static void rtw8822c_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path,
rtw_write32_mask(rtwdev, REG_ORITXCODE2, MASK20BITS, 0x11111);
rtw8822c_config_rx_path(rtwdev, rx_path);
- rtw8822c_config_tx_path(rtwdev, tx_path, is_tx2_path);
+ rtw8822c_config_tx_path(rtwdev, tx_path, BB_PATH_A, BB_PATH_A,
+ is_tx2_path);
rtw8822c_toggle_igi(rtwdev);
}
@@ -2517,6 +2570,7 @@ static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status,
static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status,
struct rtw_rx_pkt_stat *pkt_stat)
{
+ struct rtw_path_div *p_div = &rtwdev->dm_path_div;
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
u8 rxsc, bw;
s8 min_rx_power = -120;
@@ -2559,6 +2613,13 @@ static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status,
for (path = 0; path <= rtwdev->hal.rf_path_num; path++) {
rssi = rtw_phy_rf_power_2_rssi(&pkt_stat->rx_power[path], 1);
dm_info->rssi[path] = rssi;
+ if (path == RF_PATH_A) {
+ p_div->path_a_sum += rssi;
+ p_div->path_a_cnt++;
+ } else if (path == RF_PATH_B) {
+ p_div->path_b_sum += rssi;
+ p_div->path_b_cnt++;
+ }
dm_info->rx_snr[path] = pkt_stat->rx_snr[path] >> 1;
dm_info->cfo_tail[path] = (pkt_stat->cfo_tail[path] * 5) >> 1;
@@ -4371,26 +4432,28 @@ static void rtw8822c_pwrtrack_set(struct rtw_dev *rtwdev, u8 rf_path)
}
}
-static void rtw8822c_pwr_track_path(struct rtw_dev *rtwdev,
- struct rtw_swing_table *swing_table,
- u8 path)
+static void rtw8822c_pwr_track_stats(struct rtw_dev *rtwdev, u8 path)
{
- struct rtw_dm_info *dm_info = &rtwdev->dm_info;
- u8 thermal_value, delta;
+ u8 thermal_value;
if (rtwdev->efuse.thermal_meter[path] == 0xff)
return;
thermal_value = rtw_read_rf(rtwdev, path, RF_T_METER, 0x7e);
-
rtw_phy_pwrtrack_avg(rtwdev, thermal_value, path);
+}
- delta = rtw_phy_pwrtrack_get_delta(rtwdev, path);
+static void rtw8822c_pwr_track_path(struct rtw_dev *rtwdev,
+ struct rtw_swing_table *swing_table,
+ u8 path)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ u8 delta;
+ delta = rtw_phy_pwrtrack_get_delta(rtwdev, path);
dm_info->delta_power_index[path] =
rtw_phy_pwrtrack_get_pwridx(rtwdev, swing_table, path, path,
delta);
-
rtw8822c_pwrtrack_set(rtwdev, path);
}
@@ -4401,12 +4464,12 @@ static void __rtw8822c_pwr_track(struct rtw_dev *rtwdev)
rtw_phy_config_swing_table(rtwdev, &swing_table);
+ for (i = 0; i < rtwdev->hal.rf_path_num; i++)
+ rtw8822c_pwr_track_stats(rtwdev, i);
if (rtw_phy_pwrtrack_need_lck(rtwdev))
rtw8822c_do_lck(rtwdev);
-
for (i = 0; i < rtwdev->hal.rf_path_num; i++)
rtw8822c_pwr_track_path(rtwdev, &swing_table, i);
-
}
static void rtw8822c_pwr_track(struct rtw_dev *rtwdev)
@@ -4851,6 +4914,7 @@ static struct rtw_chip_ops rtw8822c_ops = {
.cfg_csi_rate = rtw_bf_cfg_csi_rate,
.cfo_init = rtw8822c_cfo_init,
.cfo_track = rtw8822c_cfo_track,
+ .config_tx_path = rtw8822c_config_tx_path,
.coex_set_init = rtw8822c_coex_cfg_init,
.coex_set_ant_switch = NULL,
@@ -5192,6 +5256,8 @@ struct rtw_chip_info rtw8822c_hw_spec = {
.band = RTW_BAND_2G | RTW_BAND_5G,
.page_size = 128,
.dig_min = 0x20,
+ .default_1ss_tx_path = BB_PATH_A,
+ .path_div_supported = true,
.ht_supported = true,
.vht_supported = true,
.lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK) | BIT(LPS_DEEP_MODE_PG),
@@ -5259,6 +5325,7 @@ struct rtw_chip_info rtw8822c_hw_spec = {
.coex_info_hw_regs = coex_info_hw_regs_8822c,
.fw_fifo_addr = {0x780, 0x700, 0x780, 0x660, 0x650, 0x680},
+ .fwcd_segs = &rtw8822c_fwcd_segs,
};
EXPORT_SYMBOL(rtw8822c_hw_spec);
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c b/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c
index 822f3da91f1b..f9e3d0779c59 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c
@@ -16812,53 +16812,53 @@ static const u32 rtw8822c_rf_a[] = {
0x92000002, 0x00000000, 0x40000000, 0x00000000,
0x03F, 0x00010E46,
0x93000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x93000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x93000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x93000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x93000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x93000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x93000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x93000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x94000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x94000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x94000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x94000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x94000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x94000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x94000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x94000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x95000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x95000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x95000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x95000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x95000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x95000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x95000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0x95000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00030246,
+ 0x03F, 0x0003D646,
0xA0000000, 0x00000000,
0x03F, 0x00002A46,
0xB0000000, 0x00000000,
@@ -18762,53 +18762,53 @@ static const u32 rtw8822c_rf_a[] = {
0x92000002, 0x00000000, 0x40000000, 0x00000000,
0x03F, 0x0000EA46,
0x93000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0xA0000000, 0x00000000,
0x03F, 0x00002A46,
0xB0000000, 0x00000000,
@@ -18957,53 +18957,53 @@ static const u32 rtw8822c_rf_a[] = {
0x92000002, 0x00000000, 0x40000000, 0x00000000,
0x03F, 0x0000EA46,
0x93000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0xA0000000, 0x00000000,
0x03F, 0x00002A46,
0xB0000000, 0x00000000,
@@ -19152,53 +19152,53 @@ static const u32 rtw8822c_rf_a[] = {
0x92000002, 0x00000000, 0x40000000, 0x00000000,
0x03F, 0x0000EA46,
0x93000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0xA0000000, 0x00000000,
0x03F, 0x00002A46,
0xB0000000, 0x00000000,
@@ -19347,53 +19347,53 @@ static const u32 rtw8822c_rf_a[] = {
0x92000002, 0x00000000, 0x40000000, 0x00000000,
0x03F, 0x0000EA46,
0x93000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x93000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x94000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000001, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000002, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000003, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000004, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000005, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000006, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000015, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0x95000016, 0x00000000, 0x40000000, 0x00000000,
- 0x03F, 0x00031E46,
+ 0x03F, 0x0003D646,
0xA0000000, 0x00000000,
0x03F, 0x00002A46,
0xB0000000, 0x00000000,
@@ -19610,21 +19610,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x93000002, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19633,21 +19633,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x93000003, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19656,21 +19656,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x93000004, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19679,21 +19679,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x93000005, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19702,21 +19702,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x93000006, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19725,21 +19725,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x93000015, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19748,21 +19748,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x93000016, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19771,21 +19771,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000001, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19794,21 +19794,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000002, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19817,21 +19817,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000003, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19840,21 +19840,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000004, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19863,21 +19863,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000005, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19886,21 +19886,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000006, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19909,21 +19909,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000015, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19932,21 +19932,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000016, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19955,21 +19955,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000001, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -19978,21 +19978,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000002, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -20001,21 +20001,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000003, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -20024,21 +20024,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000004, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -20047,21 +20047,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000005, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -20070,21 +20070,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000006, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -20093,21 +20093,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000015, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -20116,21 +20116,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000016, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -20139,21 +20139,21 @@ static const u32 rtw8822c_rf_a[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x000008C8,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x000008CB,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x000008CE,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x000008D1,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x000008D4,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000DD1,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0xA0000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000487,
@@ -38484,21 +38484,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x93000002, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38507,21 +38507,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x93000003, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38530,21 +38530,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x93000004, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38553,21 +38553,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x93000005, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38576,21 +38576,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x93000006, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38599,21 +38599,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x93000015, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38622,21 +38622,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x93000016, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38645,21 +38645,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000001, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38668,21 +38668,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000002, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38691,21 +38691,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000003, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38714,21 +38714,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000004, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38737,21 +38737,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000005, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38760,21 +38760,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000006, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38783,21 +38783,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000015, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38806,21 +38806,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x94000016, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38829,21 +38829,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000001, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38852,21 +38852,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000002, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38875,21 +38875,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000003, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38898,21 +38898,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000004, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38921,21 +38921,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000005, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38944,21 +38944,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000006, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38967,21 +38967,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000015, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -38990,21 +38990,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0x95000016, 0x00000000, 0x40000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000467,
@@ -39013,21 +39013,21 @@ static const u32 rtw8822c_rf_b[] = {
0x033, 0x00000062,
0x03F, 0x00000908,
0x033, 0x00000063,
- 0x03F, 0x00000D09,
+ 0x03F, 0x00000CC6,
0x033, 0x00000064,
- 0x03F, 0x00000D49,
+ 0x03F, 0x00000CC9,
0x033, 0x00000065,
- 0x03F, 0x00000D8A,
+ 0x03F, 0x00000CCC,
0x033, 0x00000066,
- 0x03F, 0x00000DEB,
+ 0x03F, 0x00000CCF,
0x033, 0x00000067,
- 0x03F, 0x00000DEE,
+ 0x03F, 0x00000CD2,
0x033, 0x00000068,
- 0x03F, 0x00000DF1,
+ 0x03F, 0x00000CD5,
0x033, 0x00000069,
- 0x03F, 0x00000DF4,
+ 0x03F, 0x00000DD4,
0x033, 0x0000006A,
- 0x03F, 0x00000DF7,
+ 0x03F, 0x00000DD7,
0xA0000000, 0x00000000,
0x033, 0x00000060,
0x03F, 0x00000487,
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 9fe77556858e..63ce2443f136 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -1036,14 +1036,11 @@ static bool is_associated(struct usbnet *usbdev)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
u8 bssid[ETH_ALEN];
- int ret;
if (!priv->radio_on)
return false;
- ret = get_bssid(usbdev, bssid);
-
- return (ret == 0 && !is_zero_ether_addr(bssid));
+ return (get_bssid(usbdev, bssid) == 0 && !is_zero_ether_addr(bssid));
}
static int disassociate(struct usbnet *usbdev, bool reset_ssid)
diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c
index ce9892152f4d..99b21a2c8386 100644
--- a/drivers/net/wireless/rsi/rsi_91x_hal.c
+++ b/drivers/net/wireless/rsi/rsi_91x_hal.c
@@ -203,7 +203,7 @@ int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb)
wh->frame_control |= cpu_to_le16(RSI_SET_PS_ENABLE);
if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) &&
- (common->secinfo.security_enable)) {
+ info->control.hw_key) {
if (rsi_is_cipher_wep(common))
ieee80211_size += 4;
else
@@ -470,9 +470,9 @@ int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb)
}
if (common->band == NL80211_BAND_2GHZ)
- bcn_frm->bbp_info |= cpu_to_le16(RSI_RATE_1);
+ bcn_frm->rate_info |= cpu_to_le16(RSI_RATE_1);
else
- bcn_frm->bbp_info |= cpu_to_le16(RSI_RATE_6);
+ bcn_frm->rate_info |= cpu_to_le16(RSI_RATE_6);
if (mac_bcn->data[tim_offset + 2] == 0)
bcn_frm->frame_info |= cpu_to_le16(RSI_DATA_DESC_DTIM_BEACON);
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index 16025300cddb..b66975f54567 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -837,6 +837,23 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw,
common->cqm_info.rssi_hyst);
}
+ if (changed & BSS_CHANGED_BEACON_INT) {
+ rsi_dbg(INFO_ZONE, "%s: Changed Beacon interval: %d\n",
+ __func__, bss_conf->beacon_int);
+ if (common->beacon_interval != bss->beacon_int) {
+ common->beacon_interval = bss->beacon_int;
+ if (vif->type == NL80211_IFTYPE_AP) {
+ struct vif_priv *vif_info = (struct vif_priv *)vif->drv_priv;
+
+ rsi_set_vap_capabilities(common, RSI_OPMODE_AP,
+ vif->addr, vif_info->vap_id,
+ VAP_UPDATE);
+ }
+ }
+ adapter->ps_info.listen_interval =
+ bss->beacon_int * adapter->ps_info.num_bcns_per_lis_int;
+ }
+
if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
((vif->type == NL80211_IFTYPE_AP) ||
(vif->type == NL80211_IFTYPE_P2P_GO))) {
@@ -1028,7 +1045,6 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw,
mutex_lock(&common->mutex);
switch (cmd) {
case SET_KEY:
- secinfo->security_enable = true;
status = rsi_hal_key_config(hw, vif, key, sta);
if (status) {
mutex_unlock(&common->mutex);
@@ -1047,8 +1063,6 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw,
break;
case DISABLE_KEY:
- if (vif->type == NL80211_IFTYPE_STATION)
- secinfo->security_enable = false;
rsi_dbg(ERR_ZONE, "%s: RSI del key\n", __func__);
memset(key, 0, sizeof(struct ieee80211_key_conf));
status = rsi_hal_key_config(hw, vif, key, sta);
diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index 33c76d39a8e9..891fd5f0fa76 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -1547,8 +1547,8 @@ static int rsi_eeprom_read(struct rsi_common *common)
}
/**
- * This function sends a frame to block/unblock
- * data queues in the firmware
+ * rsi_send_block_unblock_frame() - This function sends a frame to block/unblock
+ * data queues in the firmware
*
* @common: Pointer to the driver private structure.
* @block_event: Event block if true, unblock if false
@@ -1803,8 +1803,7 @@ int rsi_send_wowlan_request(struct rsi_common *common, u16 flags,
RSI_WIFI_MGMT_Q);
cmd_frame->desc.desc_dword0.frame_type = WOWLAN_CONFIG_PARAMS;
cmd_frame->host_sleep_status = sleep_status;
- if (common->secinfo.security_enable &&
- common->secinfo.gtk_cipher)
+ if (common->secinfo.gtk_cipher)
flags |= RSI_WOW_GTK_REKEY;
if (sleep_status)
cmd_frame->wow_flags = flags;
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index a1065e5a92b4..0f535850a383 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -151,7 +151,6 @@ enum edca_queue {
};
struct security_info {
- bool security_enable;
u32 ptk_cipher;
u32 gtk_cipher;
};
diff --git a/drivers/net/wireless/st/cw1200/cw1200_sdio.c b/drivers/net/wireless/st/cw1200/cw1200_sdio.c
index b65ec14136c7..4c30b5772ce0 100644
--- a/drivers/net/wireless/st/cw1200/cw1200_sdio.c
+++ b/drivers/net/wireless/st/cw1200/cw1200_sdio.c
@@ -53,6 +53,7 @@ static const struct sdio_device_id cw1200_sdio_ids[] = {
{ SDIO_DEVICE(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200) },
{ /* end: all zeroes */ },
};
+MODULE_DEVICE_TABLE(sdio, cw1200_sdio_ids);
/* hwbus_ops implemetation */
diff --git a/drivers/net/wireless/st/cw1200/scan.c b/drivers/net/wireless/st/cw1200/scan.c
index 988581cc134b..1f856fbbc0ea 100644
--- a/drivers/net/wireless/st/cw1200/scan.c
+++ b/drivers/net/wireless/st/cw1200/scan.c
@@ -75,30 +75,27 @@ int cw1200_hw_scan(struct ieee80211_hw *hw,
if (req->n_ssids > WSM_SCAN_MAX_NUM_OF_SSIDS)
return -EINVAL;
- /* will be unlocked in cw1200_scan_work() */
- down(&priv->scan.lock);
- mutex_lock(&priv->conf_mutex);
-
frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0,
req->ie_len);
- if (!frame.skb) {
- mutex_unlock(&priv->conf_mutex);
- up(&priv->scan.lock);
+ if (!frame.skb)
return -ENOMEM;
- }
if (req->ie_len)
skb_put_data(frame.skb, req->ie, req->ie_len);
+ /* will be unlocked in cw1200_scan_work() */
+ down(&priv->scan.lock);
+ mutex_lock(&priv->conf_mutex);
+
ret = wsm_set_template_frame(priv, &frame);
if (!ret) {
/* Host want to be the probe responder. */
ret = wsm_set_probe_responder(priv, true);
}
if (ret) {
- dev_kfree_skb(frame.skb);
mutex_unlock(&priv->conf_mutex);
up(&priv->scan.lock);
+ dev_kfree_skb(frame.skb);
return ret;
}
@@ -120,8 +117,8 @@ int cw1200_hw_scan(struct ieee80211_hw *hw,
++priv->scan.n_ssids;
}
- dev_kfree_skb(frame.skb);
mutex_unlock(&priv->conf_mutex);
+ dev_kfree_skb(frame.skb);
queue_work(priv->workqueue, &priv->scan.work);
return 0;
}
diff --git a/drivers/net/wireless/ti/wl1251/cmd.c b/drivers/net/wireless/ti/wl1251/cmd.c
index 498c8db2eb48..c3be81dc7970 100644
--- a/drivers/net/wireless/ti/wl1251/cmd.c
+++ b/drivers/net/wireless/ti/wl1251/cmd.c
@@ -12,7 +12,7 @@
#include "acx.h"
/**
- * send command to firmware
+ * wl1251_cmd_send - Send command to firmware
*
* @wl: wl struct
* @id: command id
@@ -59,7 +59,7 @@ out:
}
/**
- * send test command to firmware
+ * wl1251_cmd_test - Send test command to firmware
*
* @wl: wl struct
* @buf: buffer containing the command, with all headers, must work with dma
@@ -100,7 +100,7 @@ int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer)
}
/**
- * read acx from firmware
+ * wl1251_cmd_interrogate - Read acx from firmware
*
* @wl: wl struct
* @id: acx id
@@ -138,7 +138,7 @@ out:
}
/**
- * write acx value to firmware
+ * wl1251_cmd_configure - Write acx value to firmware
*
* @wl: wl struct
* @id: acx id
@@ -454,9 +454,12 @@ int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len,
cmd->channels[i].channel = channels[i]->hw_value;
}
- cmd->params.ssid_len = ssid_len;
- if (ssid)
- memcpy(cmd->params.ssid, ssid, ssid_len);
+ if (ssid) {
+ int len = clamp_val(ssid_len, 0, IEEE80211_MAX_SSID_LEN);
+
+ cmd->params.ssid_len = len;
+ memcpy(cmd->params.ssid, ssid, len);
+ }
ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd));
if (ret < 0) {
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index 9d7dbfe7fe0c..c6da0cfb4afb 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -1503,6 +1503,13 @@ static int wl12xx_get_fuse_mac(struct wl1271 *wl)
u32 mac1, mac2;
int ret;
+ /* Device may be in ELP from the bootloader or kexec */
+ ret = wlcore_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
+ if (ret < 0)
+ goto out;
+
+ usleep_range(500000, 700000);
+
ret = wlcore_set_partition(wl, &wl->ptable[PART_DRPW]);
if (ret < 0)
goto out;
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index 32a2e27cc561..8b798b5fcaf5 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -821,7 +821,7 @@ out:
/**
- * send test command to firmware
+ * wl1271_cmd_test - send test command to firmware
*
* @wl: wl struct
* @buf: buffer containing the command, with all headers, must work with dma
@@ -850,7 +850,7 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer)
EXPORT_SYMBOL_GPL(wl1271_cmd_test);
/**
- * read acx from firmware
+ * wl1271_cmd_interrogate - read acx from firmware
*
* @wl: wl struct
* @id: acx id
@@ -879,7 +879,7 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf,
}
/**
- * write acx value to firmware
+ * wlcore_cmd_configure_failsafe - write acx value to firmware
*
* @wl: wl struct
* @id: acx id
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index a68bbadae043..46ab69eab26a 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -29,18 +29,20 @@ int wlcore_event_fw_logger(struct wl1271 *wl)
u8 *buffer;
u32 internal_fw_addrbase = WL18XX_DATA_RAM_BASE_ADDRESS;
u32 addr = WL18XX_LOGGER_SDIO_BUFF_ADDR;
- u32 end_buff_addr = WL18XX_LOGGER_SDIO_BUFF_ADDR +
- WL18XX_LOGGER_BUFF_OFFSET;
+ u32 addr_ptr;
+ u32 buff_start_ptr;
+ u32 buff_read_ptr;
+ u32 buff_end_ptr;
u32 available_len;
u32 actual_len;
- u32 clear_addr;
+ u32 clear_ptr;
size_t len;
u32 start_loc;
buffer = kzalloc(WL18XX_LOGGER_SDIO_BUFF_MAX, GFP_KERNEL);
if (!buffer) {
wl1271_error("Fail to allocate fw logger memory");
- fw_log.actual_buff_size = cpu_to_le32(0);
+ actual_len = 0;
goto out;
}
@@ -49,51 +51,58 @@ int wlcore_event_fw_logger(struct wl1271 *wl)
if (ret < 0) {
wl1271_error("Fail to read logger buffer, error_id = %d",
ret);
- fw_log.actual_buff_size = cpu_to_le32(0);
+ actual_len = 0;
goto free_out;
}
memcpy(&fw_log, buffer, sizeof(fw_log));
- if (le32_to_cpu(fw_log.actual_buff_size) == 0)
+ actual_len = le32_to_cpu(fw_log.actual_buff_size);
+ if (actual_len == 0)
goto free_out;
- actual_len = le32_to_cpu(fw_log.actual_buff_size);
- start_loc = (le32_to_cpu(fw_log.buff_read_ptr) -
- internal_fw_addrbase) - addr;
- end_buff_addr += le32_to_cpu(fw_log.max_buff_size);
- available_len = end_buff_addr -
- (le32_to_cpu(fw_log.buff_read_ptr) -
- internal_fw_addrbase);
- actual_len = min(actual_len, available_len);
- len = actual_len;
+ /* Calculate the internal pointer to the fwlog structure */
+ addr_ptr = internal_fw_addrbase + addr;
+
+ /* Calculate the internal pointers to the start and end of log buffer */
+ buff_start_ptr = addr_ptr + WL18XX_LOGGER_BUFF_OFFSET;
+ buff_end_ptr = buff_start_ptr + le32_to_cpu(fw_log.max_buff_size);
+ /* Read the read pointer and validate it */
+ buff_read_ptr = le32_to_cpu(fw_log.buff_read_ptr);
+ if (buff_read_ptr < buff_start_ptr ||
+ buff_read_ptr >= buff_end_ptr) {
+ wl1271_error("buffer read pointer out of bounds: %x not in (%x-%x)\n",
+ buff_read_ptr, buff_start_ptr, buff_end_ptr);
+ goto free_out;
+ }
+
+ start_loc = buff_read_ptr - addr_ptr;
+ available_len = buff_end_ptr - buff_read_ptr;
+
+ /* Copy initial part up to the end of ring buffer */
+ len = min(actual_len, available_len);
wl12xx_copy_fwlog(wl, &buffer[start_loc], len);
- clear_addr = addr + start_loc + le32_to_cpu(fw_log.actual_buff_size) +
- internal_fw_addrbase;
+ clear_ptr = addr_ptr + start_loc + actual_len;
+ if (clear_ptr == buff_end_ptr)
+ clear_ptr = buff_start_ptr;
- len = le32_to_cpu(fw_log.actual_buff_size) - len;
+ /* Copy any remaining part from beginning of ring buffer */
+ len = actual_len - len;
if (len) {
wl12xx_copy_fwlog(wl,
&buffer[WL18XX_LOGGER_BUFF_OFFSET],
len);
- clear_addr = addr + WL18XX_LOGGER_BUFF_OFFSET + len +
- internal_fw_addrbase;
- }
-
- /* double check that clear address and write pointer are the same */
- if (clear_addr != le32_to_cpu(fw_log.buff_write_ptr)) {
- wl1271_error("Calculate of clear addr Clear = %x, write = %x",
- clear_addr, le32_to_cpu(fw_log.buff_write_ptr));
+ clear_ptr = addr_ptr + WL18XX_LOGGER_BUFF_OFFSET + len;
}
- /* indicate FW about Clear buffer */
+ /* Update the read pointer */
ret = wlcore_write32(wl, addr + WL18XX_LOGGER_READ_POINT_OFFSET,
- fw_log.buff_write_ptr);
+ clear_ptr);
free_out:
kfree(buffer);
out:
- return le32_to_cpu(fw_log.actual_buff_size);
+ return actual_len;
}
EXPORT_SYMBOL_GPL(wlcore_event_fw_logger);
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 8509b989940c..5669f17b395f 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -3242,8 +3242,8 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
* the firmware filters so that all multicast packets are passed
* This is mandatory for MDNS based discovery protocols
*/
- if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
- if (*total & FIF_ALLMULTI) {
+ if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
+ if (*total & FIF_ALLMULTI) {
ret = wl1271_acx_group_address_tbl(wl, wlvif,
false,
NULL, 0);
@@ -6784,7 +6784,7 @@ int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
if (pdev_data->family && pdev_data->family->nvs_name) {
nvs_name = pdev_data->family->nvs_name;
- ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
nvs_name, &pdev->dev, GFP_KERNEL,
wl, wlcore_nvs_cb);
if (ret < 0) {
diff --git a/drivers/net/wireless/ti/wlcore/sysfs.c b/drivers/net/wireless/ti/wlcore/sysfs.c
index 5cf0379b88b6..35b535c125b6 100644
--- a/drivers/net/wireless/ti/wlcore/sysfs.c
+++ b/drivers/net/wireless/ti/wlcore/sysfs.c
@@ -12,9 +12,9 @@
#include "debug.h"
#include "sysfs.h"
-static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t bt_coex_state_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len;
@@ -30,9 +30,9 @@ static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
}
-static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t bt_coex_state_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct wl1271 *wl = dev_get_drvdata(dev);
unsigned long res;
@@ -71,13 +71,11 @@ static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
return count;
}
-static DEVICE_ATTR(bt_coex_state, 0644,
- wl1271_sysfs_show_bt_coex_state,
- wl1271_sysfs_store_bt_coex_state);
+static DEVICE_ATTR_RW(bt_coex_state);
-static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t hw_pg_ver_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len;
@@ -94,7 +92,7 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
return len;
}
-static DEVICE_ATTR(hw_pg_ver, 0444, wl1271_sysfs_show_hw_pg_ver, NULL);
+static DEVICE_ATTR_RO(hw_pg_ver);
static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c
index 5c4cd0e1adeb..a7ceef10bf6a 100644
--- a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c
@@ -1544,14 +1544,14 @@ static int __init usb_init(void)
zd_workqueue = create_singlethread_workqueue(driver.name);
if (zd_workqueue == NULL) {
- printk(KERN_ERR "%s couldn't create workqueue\n", driver.name);
+ pr_err("%s couldn't create workqueue\n", driver.name);
return -ENOMEM;
}
r = usb_register(&driver);
if (r) {
destroy_workqueue(zd_workqueue);
- printk(KERN_ERR "%s usb_register() failed. Error number %d\n",
+ pr_err("%s usb_register() failed. Error number %d\n",
driver.name, r);
return r;
}
diff --git a/drivers/net/wwan/Kconfig b/drivers/net/wwan/Kconfig
index 7ad1920120bc..de9384326bc8 100644
--- a/drivers/net/wwan/Kconfig
+++ b/drivers/net/wwan/Kconfig
@@ -3,15 +3,9 @@
# Wireless WAN device configuration
#
-menuconfig WWAN
- bool "Wireless WAN"
- help
- This section contains Wireless WAN configuration for WWAN framework
- and drivers.
-
-if WWAN
+menu "Wireless WAN"
-config WWAN_CORE
+config WWAN
tristate "WWAN Driver Core"
help
Say Y here if you want to use the WWAN driver core. This driver
@@ -20,9 +14,19 @@ config WWAN_CORE
To compile this driver as a module, choose M here: the module will be
called wwan.
+if WWAN
+
+config WWAN_HWSIM
+ tristate "Simulated WWAN device"
+ help
+ This driver is a developer testing tool that can be used to test WWAN
+ framework.
+
+ To compile this driver as a module, choose M here: the module will be
+ called wwan_hwsim. If unsure, say N.
+
config MHI_WWAN_CTRL
tristate "MHI WWAN control driver for QCOM-based PCIe modems"
- select WWAN_CORE
depends on MHI_BUS
help
MHI WWAN CTRL allows QCOM-based PCIe modems to expose different modem
@@ -34,4 +38,35 @@ config MHI_WWAN_CTRL
To compile this driver as a module, choose M here: the module will be
called mhi_wwan_ctrl.
+config RPMSG_WWAN_CTRL
+ tristate "RPMSG WWAN control driver"
+ depends on RPMSG
+ help
+ RPMSG WWAN CTRL allows modems available via RPMSG channels to expose
+ different modem protocols/ports to userspace, including AT and QMI.
+ These protocols can be accessed directly from userspace
+ (e.g. AT commands) or via libraries/tools (e.g. libqmi, libqcdm...).
+
+ This is mainly used for modems integrated into many Qualcomm SoCs,
+ e.g. for AT and QMI on Qualcomm MSM8916 or MSM8974. Note that many
+ newer Qualcomm SoCs (e.g. SDM845) still provide an AT port through
+ this driver but the QMI messages can only be sent through
+ QRTR network sockets (CONFIG_QRTR).
+
+ To compile this driver as a module, choose M here: the module will be
+ called rpmsg_wwan_ctrl.
+
+config IOSM
+ tristate "IOSM Driver for Intel M.2 WWAN Device"
+ depends on INTEL_IOMMU
+ help
+ This driver enables Intel M.2 WWAN Device communication.
+
+ If you have one of those Intel M.2 WWAN Modules and wish to use it in
+ Linux say Y/M here.
+
+ If unsure, say N.
+
endif # WWAN
+
+endmenu
diff --git a/drivers/net/wwan/Makefile b/drivers/net/wwan/Makefile
index 556cd90958ca..d90ac33abaef 100644
--- a/drivers/net/wwan/Makefile
+++ b/drivers/net/wwan/Makefile
@@ -3,7 +3,11 @@
# Makefile for the Linux WWAN device drivers.
#
-obj-$(CONFIG_WWAN_CORE) += wwan.o
+obj-$(CONFIG_WWAN) += wwan.o
wwan-objs += wwan_core.o
+obj-$(CONFIG_WWAN_HWSIM) += wwan_hwsim.o
+
obj-$(CONFIG_MHI_WWAN_CTRL) += mhi_wwan_ctrl.o
+obj-$(CONFIG_RPMSG_WWAN_CTRL) += rpmsg_wwan_ctrl.o
+obj-$(CONFIG_IOSM) += iosm/
diff --git a/drivers/net/wwan/iosm/Makefile b/drivers/net/wwan/iosm/Makefile
new file mode 100644
index 000000000000..4f9f0ae398e1
--- /dev/null
+++ b/drivers/net/wwan/iosm/Makefile
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: (GPL-2.0-only)
+#
+# Copyright (C) 2020-21 Intel Corporation.
+#
+
+iosm-y = \
+ iosm_ipc_task_queue.o \
+ iosm_ipc_imem.o \
+ iosm_ipc_imem_ops.o \
+ iosm_ipc_mmio.o \
+ iosm_ipc_port.o \
+ iosm_ipc_wwan.o \
+ iosm_ipc_uevent.o \
+ iosm_ipc_pm.o \
+ iosm_ipc_pcie.o \
+ iosm_ipc_irq.o \
+ iosm_ipc_chnl_cfg.o \
+ iosm_ipc_protocol.o \
+ iosm_ipc_protocol_ops.o \
+ iosm_ipc_mux.o \
+ iosm_ipc_mux_codec.o
+
+obj-$(CONFIG_IOSM) := iosm.o
diff --git a/drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.c b/drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.c
new file mode 100644
index 000000000000..804e6c4f2c78
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include <linux/wwan.h>
+
+#include "iosm_ipc_chnl_cfg.h"
+
+/* Max. sizes of a downlink buffers */
+#define IPC_MEM_MAX_DL_FLASH_BUF_SIZE (16 * 1024)
+#define IPC_MEM_MAX_DL_LOOPBACK_SIZE (1 * 1024 * 1024)
+#define IPC_MEM_MAX_DL_AT_BUF_SIZE 2048
+#define IPC_MEM_MAX_DL_RPC_BUF_SIZE (32 * 1024)
+#define IPC_MEM_MAX_DL_MBIM_BUF_SIZE IPC_MEM_MAX_DL_RPC_BUF_SIZE
+
+/* Max. transfer descriptors for a pipe. */
+#define IPC_MEM_MAX_TDS_FLASH_DL 3
+#define IPC_MEM_MAX_TDS_FLASH_UL 6
+#define IPC_MEM_MAX_TDS_AT 4
+#define IPC_MEM_MAX_TDS_RPC 4
+#define IPC_MEM_MAX_TDS_MBIM IPC_MEM_MAX_TDS_RPC
+#define IPC_MEM_MAX_TDS_LOOPBACK 11
+
+/* Accumulation backoff usec */
+#define IRQ_ACC_BACKOFF_OFF 0
+
+/* MUX acc backoff 1ms */
+#define IRQ_ACC_BACKOFF_MUX 1000
+
+/* Modem channel configuration table
+ * Always reserve element zero for flash channel.
+ */
+static struct ipc_chnl_cfg modem_cfg[] = {
+ /* IP Mux */
+ { IPC_MEM_IP_CHL_ID_0, IPC_MEM_PIPE_0, IPC_MEM_PIPE_1,
+ IPC_MEM_MAX_TDS_MUX_LITE_UL, IPC_MEM_MAX_TDS_MUX_LITE_DL,
+ IPC_MEM_MAX_DL_MUX_LITE_BUF_SIZE, WWAN_PORT_UNKNOWN },
+ /* RPC - 0 */
+ { IPC_MEM_CTRL_CHL_ID_1, IPC_MEM_PIPE_2, IPC_MEM_PIPE_3,
+ IPC_MEM_MAX_TDS_RPC, IPC_MEM_MAX_TDS_RPC,
+ IPC_MEM_MAX_DL_RPC_BUF_SIZE, WWAN_PORT_UNKNOWN },
+ /* IAT0 */
+ { IPC_MEM_CTRL_CHL_ID_2, IPC_MEM_PIPE_4, IPC_MEM_PIPE_5,
+ IPC_MEM_MAX_TDS_AT, IPC_MEM_MAX_TDS_AT, IPC_MEM_MAX_DL_AT_BUF_SIZE,
+ WWAN_PORT_AT },
+ /* Trace */
+ { IPC_MEM_CTRL_CHL_ID_3, IPC_MEM_PIPE_6, IPC_MEM_PIPE_7,
+ IPC_MEM_TDS_TRC, IPC_MEM_TDS_TRC, IPC_MEM_MAX_DL_TRC_BUF_SIZE,
+ WWAN_PORT_UNKNOWN },
+ /* IAT1 */
+ { IPC_MEM_CTRL_CHL_ID_4, IPC_MEM_PIPE_8, IPC_MEM_PIPE_9,
+ IPC_MEM_MAX_TDS_AT, IPC_MEM_MAX_TDS_AT, IPC_MEM_MAX_DL_AT_BUF_SIZE,
+ WWAN_PORT_AT },
+ /* Loopback */
+ { IPC_MEM_CTRL_CHL_ID_5, IPC_MEM_PIPE_10, IPC_MEM_PIPE_11,
+ IPC_MEM_MAX_TDS_LOOPBACK, IPC_MEM_MAX_TDS_LOOPBACK,
+ IPC_MEM_MAX_DL_LOOPBACK_SIZE, WWAN_PORT_UNKNOWN },
+ /* MBIM Channel */
+ { IPC_MEM_CTRL_CHL_ID_6, IPC_MEM_PIPE_12, IPC_MEM_PIPE_13,
+ IPC_MEM_MAX_TDS_MBIM, IPC_MEM_MAX_TDS_MBIM,
+ IPC_MEM_MAX_DL_MBIM_BUF_SIZE, WWAN_PORT_MBIM },
+};
+
+int ipc_chnl_cfg_get(struct ipc_chnl_cfg *chnl_cfg, int index)
+{
+ int array_size = ARRAY_SIZE(modem_cfg);
+
+ if (index >= array_size) {
+ pr_err("index: %d and array_size %d", index, array_size);
+ return -ECHRNG;
+ }
+
+ if (index == IPC_MEM_MUX_IP_CH_IF_ID)
+ chnl_cfg->accumulation_backoff = IRQ_ACC_BACKOFF_MUX;
+ else
+ chnl_cfg->accumulation_backoff = IRQ_ACC_BACKOFF_OFF;
+
+ chnl_cfg->ul_nr_of_entries = modem_cfg[index].ul_nr_of_entries;
+ chnl_cfg->dl_nr_of_entries = modem_cfg[index].dl_nr_of_entries;
+ chnl_cfg->dl_buf_size = modem_cfg[index].dl_buf_size;
+ chnl_cfg->id = modem_cfg[index].id;
+ chnl_cfg->ul_pipe = modem_cfg[index].ul_pipe;
+ chnl_cfg->dl_pipe = modem_cfg[index].dl_pipe;
+ chnl_cfg->wwan_port_type = modem_cfg[index].wwan_port_type;
+
+ return 0;
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.h b/drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.h
new file mode 100644
index 000000000000..422471367f78
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation
+ */
+
+#ifndef IOSM_IPC_CHNL_CFG_H
+#define IOSM_IPC_CHNL_CFG_H
+
+#include "iosm_ipc_mux.h"
+
+/* Number of TDs on the trace channel */
+#define IPC_MEM_TDS_TRC 32
+
+/* Trace channel TD buffer size. */
+#define IPC_MEM_MAX_DL_TRC_BUF_SIZE 8192
+
+/* Channel ID */
+enum ipc_channel_id {
+ IPC_MEM_IP_CHL_ID_0 = 0,
+ IPC_MEM_CTRL_CHL_ID_1,
+ IPC_MEM_CTRL_CHL_ID_2,
+ IPC_MEM_CTRL_CHL_ID_3,
+ IPC_MEM_CTRL_CHL_ID_4,
+ IPC_MEM_CTRL_CHL_ID_5,
+ IPC_MEM_CTRL_CHL_ID_6,
+};
+
+/**
+ * struct ipc_chnl_cfg - IPC channel configuration structure
+ * @id: Interface ID
+ * @ul_pipe: Uplink datastream
+ * @dl_pipe: Downlink datastream
+ * @ul_nr_of_entries: Number of Transfer descriptor uplink pipe
+ * @dl_nr_of_entries: Number of Transfer descriptor downlink pipe
+ * @dl_buf_size: Downlink buffer size
+ * @wwan_port_type: Wwan subsystem port type
+ * @accumulation_backoff: Time in usec for data accumalation
+ */
+struct ipc_chnl_cfg {
+ u32 id;
+ u32 ul_pipe;
+ u32 dl_pipe;
+ u32 ul_nr_of_entries;
+ u32 dl_nr_of_entries;
+ u32 dl_buf_size;
+ u32 wwan_port_type;
+ u32 accumulation_backoff;
+};
+
+/**
+ * ipc_chnl_cfg_get - Get pipe configuration.
+ * @chnl_cfg: Array of ipc_chnl_cfg struct
+ * @index: Channel index (upto MAX_CHANNELS)
+ *
+ * Return: 0 on success and failure value on error
+ */
+int ipc_chnl_cfg_get(struct ipc_chnl_cfg *chnl_cfg, int index);
+
+#endif
diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem.c b/drivers/net/wwan/iosm/iosm_ipc_imem.c
new file mode 100644
index 000000000000..9f00e36b7f79
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_imem.c
@@ -0,0 +1,1363 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include <linux/delay.h>
+
+#include "iosm_ipc_chnl_cfg.h"
+#include "iosm_ipc_imem.h"
+#include "iosm_ipc_port.h"
+
+/* Check the wwan ips if it is valid with Channel as input. */
+static int ipc_imem_check_wwan_ips(struct ipc_mem_channel *chnl)
+{
+ if (chnl)
+ return chnl->ctype == IPC_CTYPE_WWAN &&
+ chnl->if_id == IPC_MEM_MUX_IP_CH_IF_ID;
+ return false;
+}
+
+static int ipc_imem_msg_send_device_sleep(struct iosm_imem *ipc_imem, u32 state)
+{
+ union ipc_msg_prep_args prep_args = {
+ .sleep.target = 1,
+ .sleep.state = state,
+ };
+
+ ipc_imem->device_sleep = state;
+
+ return ipc_protocol_tq_msg_send(ipc_imem->ipc_protocol,
+ IPC_MSG_PREP_SLEEP, &prep_args, NULL);
+}
+
+static bool ipc_imem_dl_skb_alloc(struct iosm_imem *ipc_imem,
+ struct ipc_pipe *pipe)
+{
+ /* limit max. nr of entries */
+ if (pipe->nr_of_queued_entries >= pipe->max_nr_of_queued_entries)
+ return false;
+
+ return ipc_protocol_dl_td_prepare(ipc_imem->ipc_protocol, pipe);
+}
+
+/* This timer handler will retry DL buff allocation if a pipe has no free buf
+ * and gives doorbell if TD is available
+ */
+static int ipc_imem_tq_td_alloc_timer(struct iosm_imem *ipc_imem, int arg,
+ void *msg, size_t size)
+{
+ bool new_buffers_available = false;
+ bool retry_allocation = false;
+ int i;
+
+ for (i = 0; i < IPC_MEM_MAX_CHANNELS; i++) {
+ struct ipc_pipe *pipe = &ipc_imem->channels[i].dl_pipe;
+
+ if (!pipe->is_open || pipe->nr_of_queued_entries > 0)
+ continue;
+
+ while (ipc_imem_dl_skb_alloc(ipc_imem, pipe))
+ new_buffers_available = true;
+
+ if (pipe->nr_of_queued_entries == 0)
+ retry_allocation = true;
+ }
+
+ if (new_buffers_available)
+ ipc_protocol_doorbell_trigger(ipc_imem->ipc_protocol,
+ IPC_HP_DL_PROCESS);
+
+ if (retry_allocation) {
+ ipc_imem->hrtimer_period =
+ ktime_set(0, IPC_TD_ALLOC_TIMER_PERIOD_MS * 1000 * 1000ULL);
+ if (!hrtimer_active(&ipc_imem->td_alloc_timer))
+ hrtimer_start(&ipc_imem->td_alloc_timer,
+ ipc_imem->hrtimer_period,
+ HRTIMER_MODE_REL);
+ }
+ return 0;
+}
+
+static enum hrtimer_restart ipc_imem_td_alloc_timer_cb(struct hrtimer *hr_timer)
+{
+ struct iosm_imem *ipc_imem =
+ container_of(hr_timer, struct iosm_imem, td_alloc_timer);
+ /* Post an async tasklet event to trigger HP update Doorbell */
+ ipc_task_queue_send_task(ipc_imem, ipc_imem_tq_td_alloc_timer, 0, NULL,
+ 0, false);
+ return HRTIMER_NORESTART;
+}
+
+/* Fast update timer tasklet handler to trigger HP update */
+static int ipc_imem_tq_fast_update_timer_cb(struct iosm_imem *ipc_imem, int arg,
+ void *msg, size_t size)
+{
+ ipc_protocol_doorbell_trigger(ipc_imem->ipc_protocol,
+ IPC_HP_FAST_TD_UPD_TMR);
+
+ return 0;
+}
+
+static enum hrtimer_restart
+ipc_imem_fast_update_timer_cb(struct hrtimer *hr_timer)
+{
+ struct iosm_imem *ipc_imem =
+ container_of(hr_timer, struct iosm_imem, fast_update_timer);
+ /* Post an async tasklet event to trigger HP update Doorbell */
+ ipc_task_queue_send_task(ipc_imem, ipc_imem_tq_fast_update_timer_cb, 0,
+ NULL, 0, false);
+ return HRTIMER_NORESTART;
+}
+
+static int ipc_imem_setup_cp_mux_cap_init(struct iosm_imem *ipc_imem,
+ struct ipc_mux_config *cfg)
+{
+ ipc_mmio_update_cp_capability(ipc_imem->mmio);
+
+ if (!ipc_imem->mmio->has_mux_lite) {
+ dev_err(ipc_imem->dev, "Failed to get Mux capability.");
+ return -EINVAL;
+ }
+
+ cfg->protocol = MUX_LITE;
+
+ cfg->ul_flow = (ipc_imem->mmio->has_ul_flow_credit == 1) ?
+ MUX_UL_ON_CREDITS :
+ MUX_UL;
+
+ /* The instance ID is same as channel ID because this is been reused
+ * for channel alloc function.
+ */
+ cfg->instance_id = IPC_MEM_MUX_IP_CH_IF_ID;
+ cfg->nr_sessions = IPC_MEM_MUX_IP_SESSION_ENTRIES;
+
+ return 0;
+}
+
+void ipc_imem_msg_send_feature_set(struct iosm_imem *ipc_imem,
+ unsigned int reset_enable, bool atomic_ctx)
+{
+ union ipc_msg_prep_args prep_args = { .feature_set.reset_enable =
+ reset_enable };
+
+ if (atomic_ctx)
+ ipc_protocol_tq_msg_send(ipc_imem->ipc_protocol,
+ IPC_MSG_PREP_FEATURE_SET, &prep_args,
+ NULL);
+ else
+ ipc_protocol_msg_send(ipc_imem->ipc_protocol,
+ IPC_MSG_PREP_FEATURE_SET, &prep_args);
+}
+
+void ipc_imem_td_update_timer_start(struct iosm_imem *ipc_imem)
+{
+ /* Use the TD update timer only in the runtime phase */
+ if (!ipc_imem->enter_runtime || ipc_imem->td_update_timer_suspended) {
+ /* trigger the doorbell irq on CP directly. */
+ ipc_protocol_doorbell_trigger(ipc_imem->ipc_protocol,
+ IPC_HP_TD_UPD_TMR_START);
+ return;
+ }
+
+ if (!hrtimer_active(&ipc_imem->tdupdate_timer)) {
+ ipc_imem->hrtimer_period =
+ ktime_set(0, TD_UPDATE_DEFAULT_TIMEOUT_USEC * 1000ULL);
+ if (!hrtimer_active(&ipc_imem->tdupdate_timer))
+ hrtimer_start(&ipc_imem->tdupdate_timer,
+ ipc_imem->hrtimer_period,
+ HRTIMER_MODE_REL);
+ }
+}
+
+void ipc_imem_hrtimer_stop(struct hrtimer *hr_timer)
+{
+ if (hrtimer_active(hr_timer))
+ hrtimer_cancel(hr_timer);
+}
+
+bool ipc_imem_ul_write_td(struct iosm_imem *ipc_imem)
+{
+ struct ipc_mem_channel *channel;
+ struct sk_buff_head *ul_list;
+ bool hpda_pending = false;
+ bool forced_hpdu = false;
+ struct ipc_pipe *pipe;
+ int i;
+
+ /* Analyze the uplink pipe of all active channels. */
+ for (i = 0; i < ipc_imem->nr_of_channels; i++) {
+ channel = &ipc_imem->channels[i];
+
+ if (channel->state != IMEM_CHANNEL_ACTIVE)
+ continue;
+
+ pipe = &channel->ul_pipe;
+
+ /* Get the reference to the skbuf accumulator list. */
+ ul_list = &channel->ul_list;
+
+ /* Fill the transfer descriptor with the uplink buffer info. */
+ hpda_pending |= ipc_protocol_ul_td_send(ipc_imem->ipc_protocol,
+ pipe, ul_list);
+
+ /* forced HP update needed for non data channels */
+ if (hpda_pending && !ipc_imem_check_wwan_ips(channel))
+ forced_hpdu = true;
+ }
+
+ if (forced_hpdu) {
+ hpda_pending = false;
+ ipc_protocol_doorbell_trigger(ipc_imem->ipc_protocol,
+ IPC_HP_UL_WRITE_TD);
+ }
+
+ return hpda_pending;
+}
+
+void ipc_imem_ipc_init_check(struct iosm_imem *ipc_imem)
+{
+ int timeout = IPC_MODEM_BOOT_TIMEOUT;
+
+ ipc_imem->ipc_requested_state = IPC_MEM_DEVICE_IPC_INIT;
+
+ /* Trigger the CP interrupt to enter the init state. */
+ ipc_doorbell_fire(ipc_imem->pcie, IPC_DOORBELL_IRQ_IPC,
+ IPC_MEM_DEVICE_IPC_INIT);
+ /* Wait for the CP update. */
+ do {
+ if (ipc_mmio_get_ipc_state(ipc_imem->mmio) ==
+ ipc_imem->ipc_requested_state) {
+ /* Prepare the MMIO space */
+ ipc_mmio_config(ipc_imem->mmio);
+
+ /* Trigger the CP irq to enter the running state. */
+ ipc_imem->ipc_requested_state =
+ IPC_MEM_DEVICE_IPC_RUNNING;
+ ipc_doorbell_fire(ipc_imem->pcie, IPC_DOORBELL_IRQ_IPC,
+ IPC_MEM_DEVICE_IPC_RUNNING);
+
+ return;
+ }
+ msleep(20);
+ } while (--timeout);
+
+ /* timeout */
+ dev_err(ipc_imem->dev, "%s: ipc_status(%d) ne. IPC_MEM_DEVICE_IPC_INIT",
+ ipc_imem_phase_get_string(ipc_imem->phase),
+ ipc_mmio_get_ipc_state(ipc_imem->mmio));
+
+ ipc_uevent_send(ipc_imem->dev, UEVENT_MDM_TIMEOUT);
+}
+
+/* Analyze the packet type and distribute it. */
+static void ipc_imem_dl_skb_process(struct iosm_imem *ipc_imem,
+ struct ipc_pipe *pipe, struct sk_buff *skb)
+{
+ u16 port_id;
+
+ if (!skb)
+ return;
+
+ /* An AT/control or IP packet is expected. */
+ switch (pipe->channel->ctype) {
+ case IPC_CTYPE_CTRL:
+ port_id = pipe->channel->channel_id;
+
+ /* Pass the packet to the wwan layer. */
+ wwan_port_rx(ipc_imem->ipc_port[port_id]->iosm_port, skb);
+ break;
+
+ case IPC_CTYPE_WWAN:
+ if (pipe->channel->if_id == IPC_MEM_MUX_IP_CH_IF_ID)
+ ipc_mux_dl_decode(ipc_imem->mux, skb);
+ break;
+ default:
+ dev_err(ipc_imem->dev, "Invalid channel type");
+ break;
+ }
+}
+
+/* Process the downlink data and pass them to the char or net layer. */
+static void ipc_imem_dl_pipe_process(struct iosm_imem *ipc_imem,
+ struct ipc_pipe *pipe)
+{
+ s32 cnt = 0, processed_td_cnt = 0;
+ struct ipc_mem_channel *channel;
+ u32 head = 0, tail = 0;
+ bool processed = false;
+ struct sk_buff *skb;
+
+ channel = pipe->channel;
+
+ ipc_protocol_get_head_tail_index(ipc_imem->ipc_protocol, pipe, &head,
+ &tail);
+ if (pipe->old_tail != tail) {
+ if (pipe->old_tail < tail)
+ cnt = tail - pipe->old_tail;
+ else
+ cnt = pipe->nr_of_entries - pipe->old_tail + tail;
+ }
+
+ processed_td_cnt = cnt;
+
+ /* Seek for pipes with pending DL data. */
+ while (cnt--) {
+ skb = ipc_protocol_dl_td_process(ipc_imem->ipc_protocol, pipe);
+
+ /* Analyze the packet type and distribute it. */
+ ipc_imem_dl_skb_process(ipc_imem, pipe, skb);
+ }
+
+ /* try to allocate new empty DL SKbs from head..tail - 1*/
+ while (ipc_imem_dl_skb_alloc(ipc_imem, pipe))
+ processed = true;
+
+ if (processed && !ipc_imem_check_wwan_ips(channel)) {
+ /* Force HP update for non IP channels */
+ ipc_protocol_doorbell_trigger(ipc_imem->ipc_protocol,
+ IPC_HP_DL_PROCESS);
+ processed = false;
+
+ /* If Fast Update timer is already running then stop */
+ ipc_imem_hrtimer_stop(&ipc_imem->fast_update_timer);
+ }
+
+ /* Any control channel process will get immediate HP update.
+ * Start Fast update timer only for IP channel if all the TDs were
+ * used in last process.
+ */
+ if (processed && (processed_td_cnt == pipe->nr_of_entries - 1)) {
+ ipc_imem->hrtimer_period =
+ ktime_set(0, FORCE_UPDATE_DEFAULT_TIMEOUT_USEC * 1000ULL);
+ hrtimer_start(&ipc_imem->fast_update_timer,
+ ipc_imem->hrtimer_period, HRTIMER_MODE_REL);
+ }
+
+ if (ipc_imem->app_notify_dl_pend)
+ complete(&ipc_imem->dl_pend_sem);
+}
+
+/* process open uplink pipe */
+static void ipc_imem_ul_pipe_process(struct iosm_imem *ipc_imem,
+ struct ipc_pipe *pipe)
+{
+ struct ipc_mem_channel *channel;
+ u32 tail = 0, head = 0;
+ struct sk_buff *skb;
+ s32 cnt = 0;
+
+ channel = pipe->channel;
+
+ /* Get the internal phase. */
+ ipc_protocol_get_head_tail_index(ipc_imem->ipc_protocol, pipe, &head,
+ &tail);
+
+ if (pipe->old_tail != tail) {
+ if (pipe->old_tail < tail)
+ cnt = tail - pipe->old_tail;
+ else
+ cnt = pipe->nr_of_entries - pipe->old_tail + tail;
+ }
+
+ /* Free UL buffers. */
+ while (cnt--) {
+ skb = ipc_protocol_ul_td_process(ipc_imem->ipc_protocol, pipe);
+
+ if (!skb)
+ continue;
+
+ /* If the user app was suspended in uplink direction - blocking
+ * write, resume it.
+ */
+ if (IPC_CB(skb)->op_type == UL_USR_OP_BLOCKED)
+ complete(&channel->ul_sem);
+
+ /* Free the skbuf element. */
+ if (IPC_CB(skb)->op_type == UL_MUX_OP_ADB) {
+ if (channel->if_id == IPC_MEM_MUX_IP_CH_IF_ID)
+ ipc_mux_ul_encoded_process(ipc_imem->mux, skb);
+ else
+ dev_err(ipc_imem->dev,
+ "OP Type is UL_MUX, unknown if_id %d",
+ channel->if_id);
+ } else {
+ ipc_pcie_kfree_skb(ipc_imem->pcie, skb);
+ }
+ }
+
+ /* Trace channel stats for IP UL pipe. */
+ if (ipc_imem_check_wwan_ips(pipe->channel))
+ ipc_mux_check_n_restart_tx(ipc_imem->mux);
+
+ if (ipc_imem->app_notify_ul_pend)
+ complete(&ipc_imem->ul_pend_sem);
+}
+
+/* Executes the irq. */
+static void ipc_imem_rom_irq_exec(struct iosm_imem *ipc_imem)
+{
+ struct ipc_mem_channel *channel;
+
+ if (ipc_imem->flash_channel_id < 0) {
+ ipc_imem->rom_exit_code = IMEM_ROM_EXIT_FAIL;
+ dev_err(ipc_imem->dev, "Missing flash app:%d",
+ ipc_imem->flash_channel_id);
+ return;
+ }
+
+ ipc_imem->rom_exit_code = ipc_mmio_get_rom_exit_code(ipc_imem->mmio);
+
+ /* Wake up the flash app to continue or to terminate depending
+ * on the CP ROM exit code.
+ */
+ channel = &ipc_imem->channels[ipc_imem->flash_channel_id];
+ complete(&channel->ul_sem);
+}
+
+/* Execute the UL bundle timer actions, generating the doorbell irq. */
+static int ipc_imem_tq_td_update_timer_cb(struct iosm_imem *ipc_imem, int arg,
+ void *msg, size_t size)
+{
+ ipc_protocol_doorbell_trigger(ipc_imem->ipc_protocol,
+ IPC_HP_TD_UPD_TMR);
+ return 0;
+}
+
+/* Consider link power management in the runtime phase. */
+static void ipc_imem_slp_control_exec(struct iosm_imem *ipc_imem)
+{
+ /* link will go down, Test pending UL packets.*/
+ if (ipc_protocol_pm_dev_sleep_handle(ipc_imem->ipc_protocol) &&
+ hrtimer_active(&ipc_imem->tdupdate_timer)) {
+ /* Generate the doorbell irq. */
+ ipc_imem_tq_td_update_timer_cb(ipc_imem, 0, NULL, 0);
+ /* Stop the TD update timer. */
+ ipc_imem_hrtimer_stop(&ipc_imem->tdupdate_timer);
+ /* Stop the fast update timer. */
+ ipc_imem_hrtimer_stop(&ipc_imem->fast_update_timer);
+ }
+}
+
+/* Execute startup timer and wait for delayed start (e.g. NAND) */
+static int ipc_imem_tq_startup_timer_cb(struct iosm_imem *ipc_imem, int arg,
+ void *msg, size_t size)
+{
+ /* Update & check the current operation phase. */
+ if (ipc_imem_phase_update(ipc_imem) != IPC_P_RUN)
+ return -EIO;
+
+ if (ipc_mmio_get_ipc_state(ipc_imem->mmio) ==
+ IPC_MEM_DEVICE_IPC_UNINIT) {
+ ipc_imem->ipc_requested_state = IPC_MEM_DEVICE_IPC_INIT;
+
+ ipc_doorbell_fire(ipc_imem->pcie, IPC_DOORBELL_IRQ_IPC,
+ IPC_MEM_DEVICE_IPC_INIT);
+
+ ipc_imem->hrtimer_period = ktime_set(0, 100 * 1000UL * 1000ULL);
+ /* reduce period to 100 ms to check for mmio init state */
+ if (!hrtimer_active(&ipc_imem->startup_timer))
+ hrtimer_start(&ipc_imem->startup_timer,
+ ipc_imem->hrtimer_period,
+ HRTIMER_MODE_REL);
+ } else if (ipc_mmio_get_ipc_state(ipc_imem->mmio) ==
+ IPC_MEM_DEVICE_IPC_INIT) {
+ /* Startup complete - disable timer */
+ ipc_imem_hrtimer_stop(&ipc_imem->startup_timer);
+
+ /* Prepare the MMIO space */
+ ipc_mmio_config(ipc_imem->mmio);
+ ipc_imem->ipc_requested_state = IPC_MEM_DEVICE_IPC_RUNNING;
+ ipc_doorbell_fire(ipc_imem->pcie, IPC_DOORBELL_IRQ_IPC,
+ IPC_MEM_DEVICE_IPC_RUNNING);
+ }
+
+ return 0;
+}
+
+static enum hrtimer_restart ipc_imem_startup_timer_cb(struct hrtimer *hr_timer)
+{
+ enum hrtimer_restart result = HRTIMER_NORESTART;
+ struct iosm_imem *ipc_imem =
+ container_of(hr_timer, struct iosm_imem, startup_timer);
+
+ if (ktime_to_ns(ipc_imem->hrtimer_period)) {
+ hrtimer_forward(&ipc_imem->startup_timer, ktime_get(),
+ ipc_imem->hrtimer_period);
+ result = HRTIMER_RESTART;
+ }
+
+ ipc_task_queue_send_task(ipc_imem, ipc_imem_tq_startup_timer_cb, 0,
+ NULL, 0, false);
+ return result;
+}
+
+/* Get the CP execution stage */
+static enum ipc_mem_exec_stage
+ipc_imem_get_exec_stage_buffered(struct iosm_imem *ipc_imem)
+{
+ return (ipc_imem->phase == IPC_P_RUN &&
+ ipc_imem->ipc_status == IPC_MEM_DEVICE_IPC_RUNNING) ?
+ ipc_protocol_get_ap_exec_stage(ipc_imem->ipc_protocol) :
+ ipc_mmio_get_exec_stage(ipc_imem->mmio);
+}
+
+/* Callback to send the modem ready uevent */
+static int ipc_imem_send_mdm_rdy_cb(struct iosm_imem *ipc_imem, int arg,
+ void *msg, size_t size)
+{
+ enum ipc_mem_exec_stage exec_stage =
+ ipc_imem_get_exec_stage_buffered(ipc_imem);
+
+ if (exec_stage == IPC_MEM_EXEC_STAGE_RUN)
+ ipc_uevent_send(ipc_imem->dev, UEVENT_MDM_READY);
+
+ return 0;
+}
+
+/* This function is executed in a task context via an ipc_worker object,
+ * as the creation or removal of device can't be done from tasklet.
+ */
+static void ipc_imem_run_state_worker(struct work_struct *instance)
+{
+ struct ipc_chnl_cfg chnl_cfg_port = { 0 };
+ struct ipc_mux_config mux_cfg;
+ struct iosm_imem *ipc_imem;
+ u8 ctrl_chl_idx = 0;
+
+ ipc_imem = container_of(instance, struct iosm_imem, run_state_worker);
+
+ if (ipc_imem->phase != IPC_P_RUN) {
+ dev_err(ipc_imem->dev,
+ "Modem link down. Exit run state worker.");
+ return;
+ }
+
+ if (!ipc_imem_setup_cp_mux_cap_init(ipc_imem, &mux_cfg))
+ ipc_imem->mux = ipc_mux_init(&mux_cfg, ipc_imem);
+
+ ipc_imem_wwan_channel_init(ipc_imem, mux_cfg.protocol);
+ if (ipc_imem->mux)
+ ipc_imem->mux->wwan = ipc_imem->wwan;
+
+ while (ctrl_chl_idx < IPC_MEM_MAX_CHANNELS) {
+ if (!ipc_chnl_cfg_get(&chnl_cfg_port, ctrl_chl_idx)) {
+ ipc_imem->ipc_port[ctrl_chl_idx] = NULL;
+ if (chnl_cfg_port.wwan_port_type != WWAN_PORT_UNKNOWN) {
+ ipc_imem_channel_init(ipc_imem, IPC_CTYPE_CTRL,
+ chnl_cfg_port,
+ IRQ_MOD_OFF);
+ ipc_imem->ipc_port[ctrl_chl_idx] =
+ ipc_port_init(ipc_imem, chnl_cfg_port);
+ }
+ }
+ ctrl_chl_idx++;
+ }
+
+ ipc_task_queue_send_task(ipc_imem, ipc_imem_send_mdm_rdy_cb, 0, NULL, 0,
+ false);
+
+ /* Complete all memory stores before setting bit */
+ smp_mb__before_atomic();
+
+ set_bit(FULLY_FUNCTIONAL, &ipc_imem->flag);
+
+ /* Complete all memory stores after setting bit */
+ smp_mb__after_atomic();
+}
+
+static void ipc_imem_handle_irq(struct iosm_imem *ipc_imem, int irq)
+{
+ enum ipc_mem_device_ipc_state curr_ipc_status;
+ enum ipc_phase old_phase, phase;
+ bool retry_allocation = false;
+ bool ul_pending = false;
+ int ch_id, i;
+
+ if (irq != IMEM_IRQ_DONT_CARE)
+ ipc_imem->ev_irq_pending[irq] = false;
+
+ /* Get the internal phase. */
+ old_phase = ipc_imem->phase;
+
+ if (old_phase == IPC_P_OFF_REQ) {
+ dev_dbg(ipc_imem->dev,
+ "[%s]: Ignoring MSI. Deinit sequence in progress!",
+ ipc_imem_phase_get_string(old_phase));
+ return;
+ }
+
+ /* Update the phase controlled by CP. */
+ phase = ipc_imem_phase_update(ipc_imem);
+
+ switch (phase) {
+ case IPC_P_RUN:
+ if (!ipc_imem->enter_runtime) {
+ /* Excute the transition from flash/boot to runtime. */
+ ipc_imem->enter_runtime = 1;
+
+ /* allow device to sleep, default value is
+ * IPC_HOST_SLEEP_ENTER_SLEEP
+ */
+ ipc_imem_msg_send_device_sleep(ipc_imem,
+ ipc_imem->device_sleep);
+
+ ipc_imem_msg_send_feature_set(ipc_imem,
+ IPC_MEM_INBAND_CRASH_SIG,
+ true);
+ }
+
+ curr_ipc_status =
+ ipc_protocol_get_ipc_status(ipc_imem->ipc_protocol);
+
+ /* check ipc_status change */
+ if (ipc_imem->ipc_status != curr_ipc_status) {
+ ipc_imem->ipc_status = curr_ipc_status;
+
+ if (ipc_imem->ipc_status ==
+ IPC_MEM_DEVICE_IPC_RUNNING) {
+ schedule_work(&ipc_imem->run_state_worker);
+ }
+ }
+
+ /* Consider power management in the runtime phase. */
+ ipc_imem_slp_control_exec(ipc_imem);
+ break; /* Continue with skbuf processing. */
+
+ /* Unexpected phases. */
+ case IPC_P_OFF:
+ case IPC_P_OFF_REQ:
+ dev_err(ipc_imem->dev, "confused phase %s",
+ ipc_imem_phase_get_string(phase));
+ return;
+
+ case IPC_P_PSI:
+ if (old_phase != IPC_P_ROM)
+ break;
+
+ fallthrough;
+ /* On CP the PSI phase is already active. */
+
+ case IPC_P_ROM:
+ /* Before CP ROM driver starts the PSI image, it sets
+ * the exit_code field on the doorbell scratchpad and
+ * triggers the irq.
+ */
+ ipc_imem_rom_irq_exec(ipc_imem);
+ return;
+
+ default:
+ break;
+ }
+
+ /* process message ring */
+ ipc_protocol_msg_process(ipc_imem, irq);
+
+ /* process all open pipes */
+ for (i = 0; i < IPC_MEM_MAX_CHANNELS; i++) {
+ struct ipc_pipe *ul_pipe = &ipc_imem->channels[i].ul_pipe;
+ struct ipc_pipe *dl_pipe = &ipc_imem->channels[i].dl_pipe;
+
+ if (dl_pipe->is_open &&
+ (irq == IMEM_IRQ_DONT_CARE || irq == dl_pipe->irq)) {
+ ipc_imem_dl_pipe_process(ipc_imem, dl_pipe);
+
+ if (dl_pipe->nr_of_queued_entries == 0)
+ retry_allocation = true;
+ }
+
+ if (ul_pipe->is_open)
+ ipc_imem_ul_pipe_process(ipc_imem, ul_pipe);
+ }
+
+ /* Try to generate new ADB or ADGH. */
+ if (ipc_mux_ul_data_encode(ipc_imem->mux))
+ ipc_imem_td_update_timer_start(ipc_imem);
+
+ /* Continue the send procedure with accumulated SIO or NETIF packets.
+ * Reset the debounce flags.
+ */
+ ul_pending |= ipc_imem_ul_write_td(ipc_imem);
+
+ /* if UL data is pending restart TD update timer */
+ if (ul_pending) {
+ ipc_imem->hrtimer_period =
+ ktime_set(0, TD_UPDATE_DEFAULT_TIMEOUT_USEC * 1000ULL);
+ if (!hrtimer_active(&ipc_imem->tdupdate_timer))
+ hrtimer_start(&ipc_imem->tdupdate_timer,
+ ipc_imem->hrtimer_period,
+ HRTIMER_MODE_REL);
+ }
+
+ /* If CP has executed the transition
+ * from IPC_INIT to IPC_RUNNING in the PSI
+ * phase, wake up the flash app to open the pipes.
+ */
+ if ((phase == IPC_P_PSI || phase == IPC_P_EBL) &&
+ ipc_imem->ipc_requested_state == IPC_MEM_DEVICE_IPC_RUNNING &&
+ ipc_mmio_get_ipc_state(ipc_imem->mmio) ==
+ IPC_MEM_DEVICE_IPC_RUNNING &&
+ ipc_imem->flash_channel_id >= 0) {
+ /* Wake up the flash app to open the pipes. */
+ ch_id = ipc_imem->flash_channel_id;
+ complete(&ipc_imem->channels[ch_id].ul_sem);
+ }
+
+ /* Reset the expected CP state. */
+ ipc_imem->ipc_requested_state = IPC_MEM_DEVICE_IPC_DONT_CARE;
+
+ if (retry_allocation) {
+ ipc_imem->hrtimer_period =
+ ktime_set(0, IPC_TD_ALLOC_TIMER_PERIOD_MS * 1000 * 1000ULL);
+ if (!hrtimer_active(&ipc_imem->td_alloc_timer))
+ hrtimer_start(&ipc_imem->td_alloc_timer,
+ ipc_imem->hrtimer_period,
+ HRTIMER_MODE_REL);
+ }
+}
+
+/* Callback by tasklet for handling interrupt events. */
+static int ipc_imem_tq_irq_cb(struct iosm_imem *ipc_imem, int arg, void *msg,
+ size_t size)
+{
+ ipc_imem_handle_irq(ipc_imem, arg);
+
+ return 0;
+}
+
+void ipc_imem_ul_send(struct iosm_imem *ipc_imem)
+{
+ /* start doorbell irq delay timer if UL is pending */
+ if (ipc_imem_ul_write_td(ipc_imem))
+ ipc_imem_td_update_timer_start(ipc_imem);
+}
+
+/* Check the execution stage and update the AP phase */
+static enum ipc_phase ipc_imem_phase_update_check(struct iosm_imem *ipc_imem,
+ enum ipc_mem_exec_stage stage)
+{
+ switch (stage) {
+ case IPC_MEM_EXEC_STAGE_BOOT:
+ if (ipc_imem->phase != IPC_P_ROM) {
+ /* Send this event only once */
+ ipc_uevent_send(ipc_imem->dev, UEVENT_ROM_READY);
+ }
+
+ ipc_imem->phase = IPC_P_ROM;
+ break;
+
+ case IPC_MEM_EXEC_STAGE_PSI:
+ ipc_imem->phase = IPC_P_PSI;
+ break;
+
+ case IPC_MEM_EXEC_STAGE_EBL:
+ ipc_imem->phase = IPC_P_EBL;
+ break;
+
+ case IPC_MEM_EXEC_STAGE_RUN:
+ if (ipc_imem->phase != IPC_P_RUN &&
+ ipc_imem->ipc_status == IPC_MEM_DEVICE_IPC_RUNNING) {
+ ipc_uevent_send(ipc_imem->dev, UEVENT_MDM_READY);
+ }
+ ipc_imem->phase = IPC_P_RUN;
+ break;
+
+ case IPC_MEM_EXEC_STAGE_CRASH:
+ if (ipc_imem->phase != IPC_P_CRASH)
+ ipc_uevent_send(ipc_imem->dev, UEVENT_CRASH);
+
+ ipc_imem->phase = IPC_P_CRASH;
+ break;
+
+ case IPC_MEM_EXEC_STAGE_CD_READY:
+ if (ipc_imem->phase != IPC_P_CD_READY)
+ ipc_uevent_send(ipc_imem->dev, UEVENT_CD_READY);
+ ipc_imem->phase = IPC_P_CD_READY;
+ break;
+
+ default:
+ /* unknown exec stage:
+ * assume that link is down and send info to listeners
+ */
+ ipc_uevent_send(ipc_imem->dev, UEVENT_CD_READY_LINK_DOWN);
+ break;
+ }
+
+ return ipc_imem->phase;
+}
+
+/* Send msg to device to open pipe */
+static bool ipc_imem_pipe_open(struct iosm_imem *ipc_imem,
+ struct ipc_pipe *pipe)
+{
+ union ipc_msg_prep_args prep_args = {
+ .pipe_open.pipe = pipe,
+ };
+
+ if (ipc_protocol_msg_send(ipc_imem->ipc_protocol,
+ IPC_MSG_PREP_PIPE_OPEN, &prep_args) == 0)
+ pipe->is_open = true;
+
+ return pipe->is_open;
+}
+
+/* Allocates the TDs for the given pipe along with firing HP update DB. */
+static int ipc_imem_tq_pipe_td_alloc(struct iosm_imem *ipc_imem, int arg,
+ void *msg, size_t size)
+{
+ struct ipc_pipe *dl_pipe = msg;
+ bool processed = false;
+ int i;
+
+ for (i = 0; i < dl_pipe->nr_of_entries - 1; i++)
+ processed |= ipc_imem_dl_skb_alloc(ipc_imem, dl_pipe);
+
+ /* Trigger the doorbell irq to inform CP that new downlink buffers are
+ * available.
+ */
+ if (processed)
+ ipc_protocol_doorbell_trigger(ipc_imem->ipc_protocol, arg);
+
+ return 0;
+}
+
+static enum hrtimer_restart
+ipc_imem_td_update_timer_cb(struct hrtimer *hr_timer)
+{
+ struct iosm_imem *ipc_imem =
+ container_of(hr_timer, struct iosm_imem, tdupdate_timer);
+
+ ipc_task_queue_send_task(ipc_imem, ipc_imem_tq_td_update_timer_cb, 0,
+ NULL, 0, false);
+ return HRTIMER_NORESTART;
+}
+
+/* Get the CP execution state and map it to the AP phase. */
+enum ipc_phase ipc_imem_phase_update(struct iosm_imem *ipc_imem)
+{
+ enum ipc_mem_exec_stage exec_stage =
+ ipc_imem_get_exec_stage_buffered(ipc_imem);
+ /* If the CP stage is undef, return the internal precalculated phase. */
+ return ipc_imem->phase == IPC_P_OFF_REQ ?
+ ipc_imem->phase :
+ ipc_imem_phase_update_check(ipc_imem, exec_stage);
+}
+
+const char *ipc_imem_phase_get_string(enum ipc_phase phase)
+{
+ switch (phase) {
+ case IPC_P_RUN:
+ return "A-RUN";
+
+ case IPC_P_OFF:
+ return "A-OFF";
+
+ case IPC_P_ROM:
+ return "A-ROM";
+
+ case IPC_P_PSI:
+ return "A-PSI";
+
+ case IPC_P_EBL:
+ return "A-EBL";
+
+ case IPC_P_CRASH:
+ return "A-CRASH";
+
+ case IPC_P_CD_READY:
+ return "A-CD_READY";
+
+ case IPC_P_OFF_REQ:
+ return "A-OFF_REQ";
+
+ default:
+ return "A-???";
+ }
+}
+
+void ipc_imem_pipe_close(struct iosm_imem *ipc_imem, struct ipc_pipe *pipe)
+{
+ union ipc_msg_prep_args prep_args = { .pipe_close.pipe = pipe };
+
+ pipe->is_open = false;
+ ipc_protocol_msg_send(ipc_imem->ipc_protocol, IPC_MSG_PREP_PIPE_CLOSE,
+ &prep_args);
+
+ ipc_imem_pipe_cleanup(ipc_imem, pipe);
+}
+
+void ipc_imem_channel_close(struct iosm_imem *ipc_imem, int channel_id)
+{
+ struct ipc_mem_channel *channel;
+
+ if (channel_id < 0 || channel_id >= ipc_imem->nr_of_channels) {
+ dev_err(ipc_imem->dev, "invalid channel id %d", channel_id);
+ return;
+ }
+
+ channel = &ipc_imem->channels[channel_id];
+
+ if (channel->state == IMEM_CHANNEL_FREE) {
+ dev_err(ipc_imem->dev, "ch[%d]: invalid channel state %d",
+ channel_id, channel->state);
+ return;
+ }
+
+ /* Free only the channel id in the CP power off mode. */
+ if (channel->state == IMEM_CHANNEL_RESERVED)
+ /* Release only the channel id. */
+ goto channel_free;
+
+ if (ipc_imem->phase == IPC_P_RUN) {
+ ipc_imem_pipe_close(ipc_imem, &channel->ul_pipe);
+ ipc_imem_pipe_close(ipc_imem, &channel->dl_pipe);
+ }
+
+ ipc_imem_pipe_cleanup(ipc_imem, &channel->ul_pipe);
+ ipc_imem_pipe_cleanup(ipc_imem, &channel->dl_pipe);
+
+channel_free:
+ ipc_imem_channel_free(channel);
+}
+
+struct ipc_mem_channel *ipc_imem_channel_open(struct iosm_imem *ipc_imem,
+ int channel_id, u32 db_id)
+{
+ struct ipc_mem_channel *channel;
+
+ if (channel_id < 0 || channel_id >= IPC_MEM_MAX_CHANNELS) {
+ dev_err(ipc_imem->dev, "invalid channel ID: %d", channel_id);
+ return NULL;
+ }
+
+ channel = &ipc_imem->channels[channel_id];
+
+ channel->state = IMEM_CHANNEL_ACTIVE;
+
+ if (!ipc_imem_pipe_open(ipc_imem, &channel->ul_pipe))
+ goto ul_pipe_err;
+
+ if (!ipc_imem_pipe_open(ipc_imem, &channel->dl_pipe))
+ goto dl_pipe_err;
+
+ /* Allocate the downlink buffers in tasklet context. */
+ if (ipc_task_queue_send_task(ipc_imem, ipc_imem_tq_pipe_td_alloc, db_id,
+ &channel->dl_pipe, 0, false)) {
+ dev_err(ipc_imem->dev, "td allocation failed : %d", channel_id);
+ goto task_failed;
+ }
+
+ /* Active channel. */
+ return channel;
+task_failed:
+ ipc_imem_pipe_close(ipc_imem, &channel->dl_pipe);
+dl_pipe_err:
+ ipc_imem_pipe_close(ipc_imem, &channel->ul_pipe);
+ul_pipe_err:
+ ipc_imem_channel_free(channel);
+ return NULL;
+}
+
+void ipc_imem_pm_suspend(struct iosm_imem *ipc_imem)
+{
+ ipc_protocol_suspend(ipc_imem->ipc_protocol);
+}
+
+void ipc_imem_pm_s2idle_sleep(struct iosm_imem *ipc_imem, bool sleep)
+{
+ ipc_protocol_s2idle_sleep(ipc_imem->ipc_protocol, sleep);
+}
+
+void ipc_imem_pm_resume(struct iosm_imem *ipc_imem)
+{
+ enum ipc_mem_exec_stage stage;
+
+ if (ipc_protocol_resume(ipc_imem->ipc_protocol)) {
+ stage = ipc_mmio_get_exec_stage(ipc_imem->mmio);
+ ipc_imem_phase_update_check(ipc_imem, stage);
+ }
+}
+
+void ipc_imem_channel_free(struct ipc_mem_channel *channel)
+{
+ /* Reset dynamic channel elements. */
+ channel->state = IMEM_CHANNEL_FREE;
+}
+
+int ipc_imem_channel_alloc(struct iosm_imem *ipc_imem, int index,
+ enum ipc_ctype ctype)
+{
+ struct ipc_mem_channel *channel;
+ int i;
+
+ /* Find channel of given type/index */
+ for (i = 0; i < ipc_imem->nr_of_channels; i++) {
+ channel = &ipc_imem->channels[i];
+ if (channel->ctype == ctype && channel->index == index)
+ break;
+ }
+
+ if (i >= ipc_imem->nr_of_channels) {
+ dev_dbg(ipc_imem->dev,
+ "no channel definition for index=%d ctype=%d", index,
+ ctype);
+ return -ECHRNG;
+ }
+
+ if (ipc_imem->channels[i].state != IMEM_CHANNEL_FREE) {
+ dev_dbg(ipc_imem->dev, "channel is in use");
+ return -EBUSY;
+ }
+
+ if (channel->ctype == IPC_CTYPE_WWAN &&
+ index == IPC_MEM_MUX_IP_CH_IF_ID)
+ channel->if_id = index;
+
+ channel->channel_id = index;
+ channel->state = IMEM_CHANNEL_RESERVED;
+
+ return i;
+}
+
+void ipc_imem_channel_init(struct iosm_imem *ipc_imem, enum ipc_ctype ctype,
+ struct ipc_chnl_cfg chnl_cfg, u32 irq_moderation)
+{
+ struct ipc_mem_channel *channel;
+
+ if (chnl_cfg.ul_pipe >= IPC_MEM_MAX_PIPES ||
+ chnl_cfg.dl_pipe >= IPC_MEM_MAX_PIPES) {
+ dev_err(ipc_imem->dev, "invalid pipe: ul_pipe=%d, dl_pipe=%d",
+ chnl_cfg.ul_pipe, chnl_cfg.dl_pipe);
+ return;
+ }
+
+ if (ipc_imem->nr_of_channels >= IPC_MEM_MAX_CHANNELS) {
+ dev_err(ipc_imem->dev, "too many channels");
+ return;
+ }
+
+ channel = &ipc_imem->channels[ipc_imem->nr_of_channels];
+ channel->channel_id = ipc_imem->nr_of_channels;
+ channel->ctype = ctype;
+ channel->index = chnl_cfg.id;
+ channel->net_err_count = 0;
+ channel->state = IMEM_CHANNEL_FREE;
+ ipc_imem->nr_of_channels++;
+
+ ipc_imem_channel_update(ipc_imem, channel->channel_id, chnl_cfg,
+ IRQ_MOD_OFF);
+
+ skb_queue_head_init(&channel->ul_list);
+
+ init_completion(&channel->ul_sem);
+}
+
+void ipc_imem_channel_update(struct iosm_imem *ipc_imem, int id,
+ struct ipc_chnl_cfg chnl_cfg, u32 irq_moderation)
+{
+ struct ipc_mem_channel *channel;
+
+ if (id < 0 || id >= ipc_imem->nr_of_channels) {
+ dev_err(ipc_imem->dev, "invalid channel id %d", id);
+ return;
+ }
+
+ channel = &ipc_imem->channels[id];
+
+ if (channel->state != IMEM_CHANNEL_FREE &&
+ channel->state != IMEM_CHANNEL_RESERVED) {
+ dev_err(ipc_imem->dev, "invalid channel state %d",
+ channel->state);
+ return;
+ }
+
+ channel->ul_pipe.nr_of_entries = chnl_cfg.ul_nr_of_entries;
+ channel->ul_pipe.pipe_nr = chnl_cfg.ul_pipe;
+ channel->ul_pipe.is_open = false;
+ channel->ul_pipe.irq = IPC_UL_PIPE_IRQ_VECTOR;
+ channel->ul_pipe.channel = channel;
+ channel->ul_pipe.dir = IPC_MEM_DIR_UL;
+ channel->ul_pipe.accumulation_backoff = chnl_cfg.accumulation_backoff;
+ channel->ul_pipe.irq_moderation = irq_moderation;
+ channel->ul_pipe.buf_size = 0;
+
+ channel->dl_pipe.nr_of_entries = chnl_cfg.dl_nr_of_entries;
+ channel->dl_pipe.pipe_nr = chnl_cfg.dl_pipe;
+ channel->dl_pipe.is_open = false;
+ channel->dl_pipe.irq = IPC_DL_PIPE_IRQ_VECTOR;
+ channel->dl_pipe.channel = channel;
+ channel->dl_pipe.dir = IPC_MEM_DIR_DL;
+ channel->dl_pipe.accumulation_backoff = chnl_cfg.accumulation_backoff;
+ channel->dl_pipe.irq_moderation = irq_moderation;
+ channel->dl_pipe.buf_size = chnl_cfg.dl_buf_size;
+}
+
+static void ipc_imem_channel_reset(struct iosm_imem *ipc_imem)
+{
+ int i;
+
+ for (i = 0; i < ipc_imem->nr_of_channels; i++) {
+ struct ipc_mem_channel *channel;
+
+ channel = &ipc_imem->channels[i];
+
+ ipc_imem_pipe_cleanup(ipc_imem, &channel->dl_pipe);
+ ipc_imem_pipe_cleanup(ipc_imem, &channel->ul_pipe);
+
+ ipc_imem_channel_free(channel);
+ }
+}
+
+void ipc_imem_pipe_cleanup(struct iosm_imem *ipc_imem, struct ipc_pipe *pipe)
+{
+ struct sk_buff *skb;
+
+ /* Force pipe to closed state also when not explicitly closed through
+ * ipc_imem_pipe_close()
+ */
+ pipe->is_open = false;
+
+ /* Empty the uplink skb accumulator. */
+ while ((skb = skb_dequeue(&pipe->channel->ul_list)))
+ ipc_pcie_kfree_skb(ipc_imem->pcie, skb);
+
+ ipc_protocol_pipe_cleanup(ipc_imem->ipc_protocol, pipe);
+}
+
+/* Send IPC protocol uninit to the modem when Link is active. */
+static void ipc_imem_device_ipc_uninit(struct iosm_imem *ipc_imem)
+{
+ int timeout = IPC_MODEM_UNINIT_TIMEOUT_MS;
+ enum ipc_mem_device_ipc_state ipc_state;
+
+ /* When PCIe link is up set IPC_UNINIT
+ * of the modem otherwise ignore it when PCIe link down happens.
+ */
+ if (ipc_pcie_check_data_link_active(ipc_imem->pcie)) {
+ /* set modem to UNINIT
+ * (in case we want to reload the AP driver without resetting
+ * the modem)
+ */
+ ipc_doorbell_fire(ipc_imem->pcie, IPC_DOORBELL_IRQ_IPC,
+ IPC_MEM_DEVICE_IPC_UNINIT);
+ ipc_state = ipc_mmio_get_ipc_state(ipc_imem->mmio);
+
+ /* Wait for maximum 30ms to allow the Modem to uninitialize the
+ * protocol.
+ */
+ while ((ipc_state <= IPC_MEM_DEVICE_IPC_DONT_CARE) &&
+ (ipc_state != IPC_MEM_DEVICE_IPC_UNINIT) &&
+ (timeout > 0)) {
+ usleep_range(1000, 1250);
+ timeout--;
+ ipc_state = ipc_mmio_get_ipc_state(ipc_imem->mmio);
+ }
+ }
+}
+
+void ipc_imem_cleanup(struct iosm_imem *ipc_imem)
+{
+ ipc_imem->phase = IPC_P_OFF_REQ;
+
+ /* forward MDM_NOT_READY to listeners */
+ ipc_uevent_send(ipc_imem->dev, UEVENT_MDM_NOT_READY);
+
+ hrtimer_cancel(&ipc_imem->td_alloc_timer);
+ hrtimer_cancel(&ipc_imem->tdupdate_timer);
+ hrtimer_cancel(&ipc_imem->fast_update_timer);
+ hrtimer_cancel(&ipc_imem->startup_timer);
+
+ /* cancel the workqueue */
+ cancel_work_sync(&ipc_imem->run_state_worker);
+
+ if (test_and_clear_bit(FULLY_FUNCTIONAL, &ipc_imem->flag)) {
+ ipc_mux_deinit(ipc_imem->mux);
+ ipc_wwan_deinit(ipc_imem->wwan);
+ ipc_port_deinit(ipc_imem->ipc_port);
+ }
+
+ ipc_imem_device_ipc_uninit(ipc_imem);
+ ipc_imem_channel_reset(ipc_imem);
+
+ ipc_protocol_deinit(ipc_imem->ipc_protocol);
+ ipc_task_deinit(ipc_imem->ipc_task);
+
+ kfree(ipc_imem->ipc_task);
+ kfree(ipc_imem->mmio);
+
+ ipc_imem->phase = IPC_P_OFF;
+}
+
+/* After CP has unblocked the PCIe link, save the start address of the doorbell
+ * scratchpad and prepare the shared memory region. If the flashing to RAM
+ * procedure shall be executed, copy the chip information from the doorbell
+ * scratchtpad to the application buffer and wake up the flash app.
+ */
+static int ipc_imem_config(struct iosm_imem *ipc_imem)
+{
+ enum ipc_phase phase;
+
+ /* Initialize the semaphore for the blocking read UL/DL transfer. */
+ init_completion(&ipc_imem->ul_pend_sem);
+
+ init_completion(&ipc_imem->dl_pend_sem);
+
+ /* clear internal flags */
+ ipc_imem->ipc_status = IPC_MEM_DEVICE_IPC_UNINIT;
+ ipc_imem->enter_runtime = 0;
+
+ phase = ipc_imem_phase_update(ipc_imem);
+
+ /* Either CP shall be in the power off or power on phase. */
+ switch (phase) {
+ case IPC_P_ROM:
+ ipc_imem->hrtimer_period = ktime_set(0, 1000 * 1000 * 1000ULL);
+ /* poll execution stage (for delayed start, e.g. NAND) */
+ if (!hrtimer_active(&ipc_imem->startup_timer))
+ hrtimer_start(&ipc_imem->startup_timer,
+ ipc_imem->hrtimer_period,
+ HRTIMER_MODE_REL);
+ return 0;
+
+ case IPC_P_PSI:
+ case IPC_P_EBL:
+ case IPC_P_RUN:
+ /* The initial IPC state is IPC_MEM_DEVICE_IPC_UNINIT. */
+ ipc_imem->ipc_requested_state = IPC_MEM_DEVICE_IPC_UNINIT;
+
+ /* Verify the exepected initial state. */
+ if (ipc_imem->ipc_requested_state ==
+ ipc_mmio_get_ipc_state(ipc_imem->mmio)) {
+ ipc_imem_ipc_init_check(ipc_imem);
+
+ return 0;
+ }
+ dev_err(ipc_imem->dev,
+ "ipc_status(%d) != IPC_MEM_DEVICE_IPC_UNINIT",
+ ipc_mmio_get_ipc_state(ipc_imem->mmio));
+ break;
+ case IPC_P_CRASH:
+ case IPC_P_CD_READY:
+ dev_dbg(ipc_imem->dev,
+ "Modem is in phase %d, reset Modem to collect CD",
+ phase);
+ return 0;
+ default:
+ dev_err(ipc_imem->dev, "unexpected operation phase %d", phase);
+ break;
+ }
+
+ complete(&ipc_imem->dl_pend_sem);
+ complete(&ipc_imem->ul_pend_sem);
+ ipc_imem->phase = IPC_P_OFF;
+ return -EIO;
+}
+
+/* Pass the dev ptr to the shared memory driver and request the entry points */
+struct iosm_imem *ipc_imem_init(struct iosm_pcie *pcie, unsigned int device_id,
+ void __iomem *mmio, struct device *dev)
+{
+ struct iosm_imem *ipc_imem = kzalloc(sizeof(*pcie->imem), GFP_KERNEL);
+
+ if (!ipc_imem)
+ return NULL;
+
+ /* Save the device address. */
+ ipc_imem->pcie = pcie;
+ ipc_imem->dev = dev;
+
+ ipc_imem->pci_device_id = device_id;
+
+ ipc_imem->ev_cdev_write_pending = false;
+ ipc_imem->cp_version = 0;
+ ipc_imem->device_sleep = IPC_HOST_SLEEP_ENTER_SLEEP;
+
+ /* Reset the flash channel id. */
+ ipc_imem->flash_channel_id = -1;
+
+ /* Reset the max number of configured channels */
+ ipc_imem->nr_of_channels = 0;
+
+ /* allocate IPC MMIO */
+ ipc_imem->mmio = ipc_mmio_init(mmio, ipc_imem->dev);
+ if (!ipc_imem->mmio) {
+ dev_err(ipc_imem->dev, "failed to initialize mmio region");
+ goto mmio_init_fail;
+ }
+
+ ipc_imem->ipc_task = kzalloc(sizeof(*ipc_imem->ipc_task),
+ GFP_KERNEL);
+
+ /* Create tasklet for event handling*/
+ if (!ipc_imem->ipc_task)
+ goto ipc_task_fail;
+
+ if (ipc_task_init(ipc_imem->ipc_task))
+ goto ipc_task_init_fail;
+
+ ipc_imem->ipc_task->dev = ipc_imem->dev;
+
+ INIT_WORK(&ipc_imem->run_state_worker, ipc_imem_run_state_worker);
+
+ ipc_imem->ipc_protocol = ipc_protocol_init(ipc_imem);
+
+ if (!ipc_imem->ipc_protocol)
+ goto protocol_init_fail;
+
+ /* The phase is set to power off. */
+ ipc_imem->phase = IPC_P_OFF;
+
+ hrtimer_init(&ipc_imem->startup_timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ ipc_imem->startup_timer.function = ipc_imem_startup_timer_cb;
+
+ hrtimer_init(&ipc_imem->tdupdate_timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ ipc_imem->tdupdate_timer.function = ipc_imem_td_update_timer_cb;
+
+ hrtimer_init(&ipc_imem->fast_update_timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ ipc_imem->fast_update_timer.function = ipc_imem_fast_update_timer_cb;
+
+ hrtimer_init(&ipc_imem->td_alloc_timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ ipc_imem->td_alloc_timer.function = ipc_imem_td_alloc_timer_cb;
+
+ if (ipc_imem_config(ipc_imem)) {
+ dev_err(ipc_imem->dev, "failed to initialize the imem");
+ goto imem_config_fail;
+ }
+
+ return ipc_imem;
+
+imem_config_fail:
+ hrtimer_cancel(&ipc_imem->td_alloc_timer);
+ hrtimer_cancel(&ipc_imem->fast_update_timer);
+ hrtimer_cancel(&ipc_imem->tdupdate_timer);
+ hrtimer_cancel(&ipc_imem->startup_timer);
+protocol_init_fail:
+ cancel_work_sync(&ipc_imem->run_state_worker);
+ ipc_task_deinit(ipc_imem->ipc_task);
+ipc_task_init_fail:
+ kfree(ipc_imem->ipc_task);
+ipc_task_fail:
+ kfree(ipc_imem->mmio);
+mmio_init_fail:
+ kfree(ipc_imem);
+ return NULL;
+}
+
+void ipc_imem_irq_process(struct iosm_imem *ipc_imem, int irq)
+{
+ /* Debounce IPC_EV_IRQ. */
+ if (ipc_imem && !ipc_imem->ev_irq_pending[irq]) {
+ ipc_imem->ev_irq_pending[irq] = true;
+ ipc_task_queue_send_task(ipc_imem, ipc_imem_tq_irq_cb, irq,
+ NULL, 0, false);
+ }
+}
+
+void ipc_imem_td_update_timer_suspend(struct iosm_imem *ipc_imem, bool suspend)
+{
+ ipc_imem->td_update_timer_suspended = suspend;
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem.h b/drivers/net/wwan/iosm/iosm_ipc_imem.h
new file mode 100644
index 000000000000..0d2f10e4cbc8
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_imem.h
@@ -0,0 +1,579 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#ifndef IOSM_IPC_IMEM_H
+#define IOSM_IPC_IMEM_H
+
+#include <linux/skbuff.h>
+#include <stdbool.h>
+
+#include "iosm_ipc_mmio.h"
+#include "iosm_ipc_pcie.h"
+#include "iosm_ipc_uevent.h"
+#include "iosm_ipc_wwan.h"
+#include "iosm_ipc_task_queue.h"
+
+struct ipc_chnl_cfg;
+
+/* IRQ moderation in usec */
+#define IRQ_MOD_OFF 0
+#define IRQ_MOD_NET 1000
+#define IRQ_MOD_TRC 4000
+
+/* Either the PSI image is accepted by CP or the suspended flash tool is waken,
+ * informed that the CP ROM driver is not ready to process the PSI image.
+ * unit : milliseconds
+ */
+#define IPC_PSI_TRANSFER_TIMEOUT 3000
+
+/* Timeout in 20 msec to wait for the modem to boot up to
+ * IPC_MEM_DEVICE_IPC_INIT state.
+ * unit : milliseconds (500 * ipc_util_msleep(20))
+ */
+#define IPC_MODEM_BOOT_TIMEOUT 500
+
+/* Wait timeout for ipc status reflects IPC_MEM_DEVICE_IPC_UNINIT
+ * unit : milliseconds
+ */
+#define IPC_MODEM_UNINIT_TIMEOUT_MS 30
+
+/* Pending time for processing data.
+ * unit : milliseconds
+ */
+#define IPC_PEND_DATA_TIMEOUT 500
+
+/* The timeout in milliseconds for application to wait for remote time. */
+#define IPC_REMOTE_TS_TIMEOUT_MS 10
+
+/* Timeout for TD allocation retry.
+ * unit : milliseconds
+ */
+#define IPC_TD_ALLOC_TIMER_PERIOD_MS 100
+
+/* Host sleep target is host */
+#define IPC_HOST_SLEEP_HOST 0
+
+/* Host sleep target is device */
+#define IPC_HOST_SLEEP_DEVICE 1
+
+/* Sleep message, target host: AP enters sleep / target device: CP is
+ * allowed to enter sleep and shall use the host sleep protocol
+ */
+#define IPC_HOST_SLEEP_ENTER_SLEEP 0
+
+/* Sleep_message, target host: AP exits sleep / target device: CP is
+ * NOT allowed to enter sleep
+ */
+#define IPC_HOST_SLEEP_EXIT_SLEEP 1
+
+#define IMEM_IRQ_DONT_CARE (-1)
+
+#define IPC_MEM_MAX_CHANNELS 7
+
+#define IPC_MEM_MUX_IP_SESSION_ENTRIES 8
+
+#define IPC_MEM_MUX_IP_CH_IF_ID 0
+
+#define TD_UPDATE_DEFAULT_TIMEOUT_USEC 1900
+
+#define FORCE_UPDATE_DEFAULT_TIMEOUT_USEC 500
+
+/* Sleep_message, target host: not applicable / target device: CP is
+ * allowed to enter sleep and shall NOT use the device sleep protocol
+ */
+#define IPC_HOST_SLEEP_ENTER_SLEEP_NO_PROTOCOL 2
+
+/* in_band_crash_signal IPC_MEM_INBAND_CRASH_SIG
+ * Modem crash notification configuration. If this value is non-zero then
+ * FEATURE_SET message will be sent to the Modem as a result the Modem will
+ * signal Crash via Execution Stage register. If this value is zero then Modem
+ * will use out-of-band method to notify about it's Crash.
+ */
+#define IPC_MEM_INBAND_CRASH_SIG 1
+
+/* Extra headroom to be allocated for DL SKBs to allow addition of Ethernet
+ * header
+ */
+#define IPC_MEM_DL_ETH_OFFSET 16
+
+#define IPC_CB(skb) ((struct ipc_skb_cb *)((skb)->cb))
+
+#define FULLY_FUNCTIONAL 0
+
+/* List of the supported UL/DL pipes. */
+enum ipc_mem_pipes {
+ IPC_MEM_PIPE_0 = 0,
+ IPC_MEM_PIPE_1,
+ IPC_MEM_PIPE_2,
+ IPC_MEM_PIPE_3,
+ IPC_MEM_PIPE_4,
+ IPC_MEM_PIPE_5,
+ IPC_MEM_PIPE_6,
+ IPC_MEM_PIPE_7,
+ IPC_MEM_PIPE_8,
+ IPC_MEM_PIPE_9,
+ IPC_MEM_PIPE_10,
+ IPC_MEM_PIPE_11,
+ IPC_MEM_PIPE_12,
+ IPC_MEM_PIPE_13,
+ IPC_MEM_PIPE_14,
+ IPC_MEM_PIPE_15,
+ IPC_MEM_PIPE_16,
+ IPC_MEM_PIPE_17,
+ IPC_MEM_PIPE_18,
+ IPC_MEM_PIPE_19,
+ IPC_MEM_PIPE_20,
+ IPC_MEM_PIPE_21,
+ IPC_MEM_PIPE_22,
+ IPC_MEM_PIPE_23,
+ IPC_MEM_MAX_PIPES
+};
+
+/* Enum defining channel states. */
+enum ipc_channel_state {
+ IMEM_CHANNEL_FREE,
+ IMEM_CHANNEL_RESERVED,
+ IMEM_CHANNEL_ACTIVE,
+ IMEM_CHANNEL_CLOSING,
+};
+
+/* Time Unit */
+enum ipc_time_unit {
+ IPC_SEC = 0,
+ IPC_MILLI_SEC = 1,
+ IPC_MICRO_SEC = 2,
+ IPC_NANO_SEC = 3,
+ IPC_PICO_SEC = 4,
+ IPC_FEMTO_SEC = 5,
+ IPC_ATTO_SEC = 6,
+};
+
+/**
+ * enum ipc_ctype - Enum defining supported channel type needed for control
+ * /IP traffic.
+ * @IPC_CTYPE_WWAN: Used for IP traffic
+ * @IPC_CTYPE_CTRL: Used for Control Communication
+ */
+enum ipc_ctype {
+ IPC_CTYPE_WWAN,
+ IPC_CTYPE_CTRL,
+};
+
+/* Pipe direction. */
+enum ipc_mem_pipe_dir {
+ IPC_MEM_DIR_UL,
+ IPC_MEM_DIR_DL,
+};
+
+/* HP update identifier. To be used as data for ipc_cp_irq_hpda_update() */
+enum ipc_hp_identifier {
+ IPC_HP_MR = 0,
+ IPC_HP_PM_TRIGGER,
+ IPC_HP_WAKEUP_SPEC_TMR,
+ IPC_HP_TD_UPD_TMR_START,
+ IPC_HP_TD_UPD_TMR,
+ IPC_HP_FAST_TD_UPD_TMR,
+ IPC_HP_UL_WRITE_TD,
+ IPC_HP_DL_PROCESS,
+ IPC_HP_NET_CHANNEL_INIT,
+ IPC_HP_CDEV_OPEN,
+};
+
+/**
+ * struct ipc_pipe - Structure for Pipe.
+ * @tdr_start: Ipc private protocol Transfer Descriptor Ring
+ * @channel: Id of the sio device, set by imem_sio_open,
+ * needed to pass DL char to the user terminal
+ * @skbr_start: Circular buffer for skbuf and the buffer
+ * reference in a tdr_start entry.
+ * @phy_tdr_start: Transfer descriptor start address
+ * @old_head: last head pointer reported to CP.
+ * @old_tail: AP read position before CP moves the read
+ * position to write/head. If CP has consumed the
+ * buffers, AP has to freed the skbuf starting at
+ * tdr_start[old_tail].
+ * @nr_of_entries: Number of elements of skb_start and tdr_start.
+ * @max_nr_of_queued_entries: Maximum number of queued entries in TDR
+ * @accumulation_backoff: Accumulation in usec for accumulation
+ * backoff (0 = no acc backoff)
+ * @irq_moderation: timer in usec for irq_moderation
+ * (0=no irq moderation)
+ * @pipe_nr: Pipe identification number
+ * @irq: Interrupt vector
+ * @dir: Direction of data stream in pipe
+ * @td_tag: Unique tag of the buffer queued
+ * @buf_size: Buffer size (in bytes) for preallocated
+ * buffers (for DL pipes)
+ * @nr_of_queued_entries: Aueued number of entries
+ * @is_open: Check for open pipe status
+ */
+struct ipc_pipe {
+ struct ipc_protocol_td *tdr_start;
+ struct ipc_mem_channel *channel;
+ struct sk_buff **skbr_start;
+ dma_addr_t phy_tdr_start;
+ u32 old_head;
+ u32 old_tail;
+ u32 nr_of_entries;
+ u32 max_nr_of_queued_entries;
+ u32 accumulation_backoff;
+ u32 irq_moderation;
+ u32 pipe_nr;
+ u32 irq;
+ enum ipc_mem_pipe_dir dir;
+ u32 td_tag;
+ u32 buf_size;
+ u16 nr_of_queued_entries;
+ u8 is_open:1;
+};
+
+/**
+ * struct ipc_mem_channel - Structure for Channel.
+ * @channel_id: Instance of the channel list and is return to the user
+ * at the end of the open operation.
+ * @ctype: Control or netif channel.
+ * @index: unique index per ctype
+ * @ul_pipe: pipe objects
+ * @dl_pipe: pipe objects
+ * @if_id: Interface ID
+ * @net_err_count: Number of downlink errors returned by ipc_wwan_receive
+ * interface at the entry point of the IP stack.
+ * @state: Free, reserved or busy (in use).
+ * @ul_sem: Needed for the blocking write or uplink transfer.
+ * @ul_list: Uplink accumulator which is filled by the uplink
+ * char app or IP stack. The socket buffer pointer are
+ * added to the descriptor list in the kthread context.
+ */
+struct ipc_mem_channel {
+ int channel_id;
+ enum ipc_ctype ctype;
+ int index;
+ struct ipc_pipe ul_pipe;
+ struct ipc_pipe dl_pipe;
+ int if_id;
+ u32 net_err_count;
+ enum ipc_channel_state state;
+ struct completion ul_sem;
+ struct sk_buff_head ul_list;
+};
+
+/**
+ * enum ipc_phase - Different AP and CP phases.
+ * The enums defined after "IPC_P_ROM" and before
+ * "IPC_P_RUN" indicates the operating state where CP can
+ * respond to any requests. So while introducing new phase
+ * this shall be taken into consideration.
+ * @IPC_P_OFF: On host PC, the PCIe device link settings are known
+ * about the combined power on. PC is running, the driver
+ * is loaded and CP is in power off mode. The PCIe bus
+ * driver call the device power mode D3hot. In this phase
+ * the driver the polls the device, until the device is in
+ * the power on state and signals the power mode D0.
+ * @IPC_P_OFF_REQ: The intermediate phase between cleanup activity starts
+ * and ends.
+ * @IPC_P_CRASH: The phase indicating CP crash
+ * @IPC_P_CD_READY: The phase indicating CP core dump is ready
+ * @IPC_P_ROM: After power on, CP starts in ROM mode and the IPC ROM
+ * driver is waiting 150 ms for the AP active notification
+ * saved in the PCI link status register.
+ * @IPC_P_PSI: Primary signed image download phase
+ * @IPC_P_EBL: Extended bootloader pahse
+ * @IPC_P_RUN: The phase after flashing to RAM is the RUNTIME phase.
+ */
+enum ipc_phase {
+ IPC_P_OFF,
+ IPC_P_OFF_REQ,
+ IPC_P_CRASH,
+ IPC_P_CD_READY,
+ IPC_P_ROM,
+ IPC_P_PSI,
+ IPC_P_EBL,
+ IPC_P_RUN,
+};
+
+/**
+ * struct iosm_imem - Current state of the IPC shared memory.
+ * @mmio: mmio instance to access CP MMIO area /
+ * doorbell scratchpad.
+ * @ipc_protocol: IPC Protocol instance
+ * @ipc_task: Task for entry into ipc task queue
+ * @wwan: WWAN device pointer
+ * @mux: IP Data multiplexing state.
+ * @sio: IPC SIO data structure pointer
+ * @ipc_port: IPC PORT data structure pointer
+ * @pcie: IPC PCIe
+ * @dev: Pointer to device structure
+ * @flash_channel_id: Reserved channel id for flashing to RAM.
+ * @ipc_requested_state: Expected IPC state on CP.
+ * @channels: Channel list with UL/DL pipe pairs.
+ * @ipc_status: local ipc_status
+ * @nr_of_channels: number of configured channels
+ * @startup_timer: startup timer for NAND support.
+ * @hrtimer_period: Hr timer period
+ * @tdupdate_timer: Delay the TD update doorbell.
+ * @fast_update_timer: forced head pointer update delay timer.
+ * @td_alloc_timer: Timer for DL pipe TD allocation retry
+ * @rom_exit_code: Mapped boot rom exit code.
+ * @enter_runtime: 1 means the transition to runtime phase was
+ * executed.
+ * @ul_pend_sem: Semaphore to wait/complete of UL TDs
+ * before closing pipe.
+ * @app_notify_ul_pend: Signal app if UL TD is pending
+ * @dl_pend_sem: Semaphore to wait/complete of DL TDs
+ * before closing pipe.
+ * @app_notify_dl_pend: Signal app if DL TD is pending
+ * @phase: Operating phase like runtime.
+ * @pci_device_id: Device ID
+ * @cp_version: CP version
+ * @device_sleep: Device sleep state
+ * @run_state_worker: Pointer to worker component for device
+ * setup operations to be called when modem
+ * reaches RUN state
+ * @ev_irq_pending: 0 means inform the IPC tasklet to
+ * process the irq actions.
+ * @flag: Flag to monitor the state of driver
+ * @td_update_timer_suspended: if true then td update timer suspend
+ * @ev_cdev_write_pending: 0 means inform the IPC tasklet to pass
+ * the accumulated uplink buffers to CP.
+ * @ev_mux_net_transmit_pending:0 means inform the IPC tasklet to pass
+ * @reset_det_n: Reset detect flag
+ * @pcie_wake_n: Pcie wake flag
+ */
+struct iosm_imem {
+ struct iosm_mmio *mmio;
+ struct iosm_protocol *ipc_protocol;
+ struct ipc_task *ipc_task;
+ struct iosm_wwan *wwan;
+ struct iosm_mux *mux;
+ struct iosm_cdev *ipc_port[IPC_MEM_MAX_CHANNELS];
+ struct iosm_pcie *pcie;
+ struct device *dev;
+ int flash_channel_id;
+ enum ipc_mem_device_ipc_state ipc_requested_state;
+ struct ipc_mem_channel channels[IPC_MEM_MAX_CHANNELS];
+ u32 ipc_status;
+ u32 nr_of_channels;
+ struct hrtimer startup_timer;
+ ktime_t hrtimer_period;
+ struct hrtimer tdupdate_timer;
+ struct hrtimer fast_update_timer;
+ struct hrtimer td_alloc_timer;
+ enum rom_exit_code rom_exit_code;
+ u32 enter_runtime;
+ struct completion ul_pend_sem;
+ u32 app_notify_ul_pend;
+ struct completion dl_pend_sem;
+ u32 app_notify_dl_pend;
+ enum ipc_phase phase;
+ u16 pci_device_id;
+ int cp_version;
+ int device_sleep;
+ struct work_struct run_state_worker;
+ u8 ev_irq_pending[IPC_IRQ_VECTORS];
+ unsigned long flag;
+ u8 td_update_timer_suspended:1,
+ ev_cdev_write_pending:1,
+ ev_mux_net_transmit_pending:1,
+ reset_det_n:1,
+ pcie_wake_n:1;
+};
+
+/**
+ * ipc_imem_init - Initialize the shared memory region
+ * @pcie: Pointer to core driver data-struct
+ * @device_id: PCI device ID
+ * @mmio: Pointer to the mmio area
+ * @dev: Pointer to device structure
+ *
+ * Returns: Initialized imem pointer on success else NULL
+ */
+struct iosm_imem *ipc_imem_init(struct iosm_pcie *pcie, unsigned int device_id,
+ void __iomem *mmio, struct device *dev);
+
+/**
+ * ipc_imem_pm_s2idle_sleep - Set PM variables to sleep/active for
+ * s2idle sleep/active
+ * @ipc_imem: Pointer to imem data-struct
+ * @sleep: Set PM Variable to sleep/active
+ */
+void ipc_imem_pm_s2idle_sleep(struct iosm_imem *ipc_imem, bool sleep);
+
+/**
+ * ipc_imem_pm_suspend - The HAL shall ask the shared memory layer
+ * whether D3 is allowed.
+ * @ipc_imem: Pointer to imem data-struct
+ */
+void ipc_imem_pm_suspend(struct iosm_imem *ipc_imem);
+
+/**
+ * ipc_imem_pm_resume - The HAL shall inform the shared memory layer
+ * that the device is active.
+ * @ipc_imem: Pointer to imem data-struct
+ */
+void ipc_imem_pm_resume(struct iosm_imem *ipc_imem);
+
+/**
+ * ipc_imem_cleanup - Inform CP and free the shared memory resources.
+ * @ipc_imem: Pointer to imem data-struct
+ */
+void ipc_imem_cleanup(struct iosm_imem *ipc_imem);
+
+/**
+ * ipc_imem_irq_process - Shift the IRQ actions to the IPC thread.
+ * @ipc_imem: Pointer to imem data-struct
+ * @irq: Irq number
+ */
+void ipc_imem_irq_process(struct iosm_imem *ipc_imem, int irq);
+
+/**
+ * imem_get_device_sleep_state - Get the device sleep state value.
+ * @ipc_imem: Pointer to imem instance
+ *
+ * Returns: device sleep state
+ */
+int imem_get_device_sleep_state(struct iosm_imem *ipc_imem);
+
+/**
+ * ipc_imem_td_update_timer_suspend - Updates the TD Update Timer suspend flag.
+ * @ipc_imem: Pointer to imem data-struct
+ * @suspend: Flag to update. If TRUE then HP update doorbell is triggered to
+ * device without any wait. If FALSE then HP update doorbell is
+ * delayed until timeout.
+ */
+void ipc_imem_td_update_timer_suspend(struct iosm_imem *ipc_imem, bool suspend);
+
+/**
+ * ipc_imem_channel_close - Release the channel resources.
+ * @ipc_imem: Pointer to imem data-struct
+ * @channel_id: Channel ID to be cleaned up.
+ */
+void ipc_imem_channel_close(struct iosm_imem *ipc_imem, int channel_id);
+
+/**
+ * ipc_imem_channel_alloc - Reserves a channel
+ * @ipc_imem: Pointer to imem data-struct
+ * @index: ID to lookup from the preallocated list.
+ * @ctype: Channel type.
+ *
+ * Returns: Index on success and failure value on error
+ */
+int ipc_imem_channel_alloc(struct iosm_imem *ipc_imem, int index,
+ enum ipc_ctype ctype);
+
+/**
+ * ipc_imem_channel_open - Establish the pipes.
+ * @ipc_imem: Pointer to imem data-struct
+ * @channel_id: Channel ID returned during alloc.
+ * @db_id: Doorbell ID for trigger identifier.
+ *
+ * Returns: Pointer of ipc_mem_channel on success and NULL on failure.
+ */
+struct ipc_mem_channel *ipc_imem_channel_open(struct iosm_imem *ipc_imem,
+ int channel_id, u32 db_id);
+
+/**
+ * ipc_imem_td_update_timer_start - Starts the TD Update Timer if not running.
+ * @ipc_imem: Pointer to imem data-struct
+ */
+void ipc_imem_td_update_timer_start(struct iosm_imem *ipc_imem);
+
+/**
+ * ipc_imem_ul_write_td - Pass the channel UL list to protocol layer for TD
+ * preparation and sending them to the device.
+ * @ipc_imem: Pointer to imem data-struct
+ *
+ * Returns: TRUE of HP Doorbell trigger is pending. FALSE otherwise.
+ */
+bool ipc_imem_ul_write_td(struct iosm_imem *ipc_imem);
+
+/**
+ * ipc_imem_ul_send - Dequeue SKB from channel list and start with
+ * the uplink transfer.If HP Doorbell is pending to be
+ * triggered then starts the TD Update Timer.
+ * @ipc_imem: Pointer to imem data-struct
+ */
+void ipc_imem_ul_send(struct iosm_imem *ipc_imem);
+
+/**
+ * ipc_imem_channel_update - Set or modify pipe config of an existing channel
+ * @ipc_imem: Pointer to imem data-struct
+ * @id: Channel config index
+ * @chnl_cfg: Channel config struct
+ * @irq_moderation: Timer in usec for irq_moderation
+ */
+void ipc_imem_channel_update(struct iosm_imem *ipc_imem, int id,
+ struct ipc_chnl_cfg chnl_cfg, u32 irq_moderation);
+
+/**
+ * ipc_imem_channel_free -Free an IPC channel.
+ * @channel: Channel to be freed
+ */
+void ipc_imem_channel_free(struct ipc_mem_channel *channel);
+
+/**
+ * ipc_imem_hrtimer_stop - Stop the hrtimer
+ * @hr_timer: Pointer to hrtimer instance
+ */
+void ipc_imem_hrtimer_stop(struct hrtimer *hr_timer);
+
+/**
+ * ipc_imem_pipe_cleanup - Reset volatile pipe content for all channels
+ * @ipc_imem: Pointer to imem data-struct
+ * @pipe: Pipe to cleaned up
+ */
+void ipc_imem_pipe_cleanup(struct iosm_imem *ipc_imem, struct ipc_pipe *pipe);
+
+/**
+ * ipc_imem_pipe_close - Send msg to device to close pipe
+ * @ipc_imem: Pointer to imem data-struct
+ * @pipe: Pipe to be closed
+ */
+void ipc_imem_pipe_close(struct iosm_imem *ipc_imem, struct ipc_pipe *pipe);
+
+/**
+ * ipc_imem_phase_update - Get the CP execution state
+ * and map it to the AP phase.
+ * @ipc_imem: Pointer to imem data-struct
+ *
+ * Returns: Current ap updated phase
+ */
+enum ipc_phase ipc_imem_phase_update(struct iosm_imem *ipc_imem);
+
+/**
+ * ipc_imem_phase_get_string - Return the current operation
+ * phase as string.
+ * @phase: AP phase
+ *
+ * Returns: AP phase string
+ */
+const char *ipc_imem_phase_get_string(enum ipc_phase phase);
+
+/**
+ * ipc_imem_msg_send_feature_set - Send feature set message to modem
+ * @ipc_imem: Pointer to imem data-struct
+ * @reset_enable: 0 = out-of-band, 1 = in-band-crash notification
+ * @atomic_ctx: if disabled call in tasklet context
+ *
+ */
+void ipc_imem_msg_send_feature_set(struct iosm_imem *ipc_imem,
+ unsigned int reset_enable, bool atomic_ctx);
+
+/**
+ * ipc_imem_ipc_init_check - Send the init event to CP, wait a certain time and
+ * set CP to runtime with the context information
+ * @ipc_imem: Pointer to imem data-struct
+ */
+void ipc_imem_ipc_init_check(struct iosm_imem *ipc_imem);
+
+/**
+ * ipc_imem_channel_init - Initialize the channel list with UL/DL pipe pairs.
+ * @ipc_imem: Pointer to imem data-struct
+ * @ctype: Channel type
+ * @chnl_cfg: Channel configuration struct
+ * @irq_moderation: Timer in usec for irq_moderation
+ */
+void ipc_imem_channel_init(struct iosm_imem *ipc_imem, enum ipc_ctype ctype,
+ struct ipc_chnl_cfg chnl_cfg, u32 irq_moderation);
+#endif
diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c
new file mode 100644
index 000000000000..0a472ce77370
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.c
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include <linux/delay.h>
+
+#include "iosm_ipc_chnl_cfg.h"
+#include "iosm_ipc_imem.h"
+#include "iosm_ipc_imem_ops.h"
+#include "iosm_ipc_port.h"
+#include "iosm_ipc_task_queue.h"
+
+/* Open a packet data online channel between the network layer and CP. */
+int ipc_imem_sys_wwan_open(struct iosm_imem *ipc_imem, int if_id)
+{
+ dev_dbg(ipc_imem->dev, "%s if id: %d",
+ ipc_imem_phase_get_string(ipc_imem->phase), if_id);
+
+ /* The network interface is only supported in the runtime phase. */
+ if (ipc_imem_phase_update(ipc_imem) != IPC_P_RUN) {
+ dev_err(ipc_imem->dev, "net:%d : refused phase %s", if_id,
+ ipc_imem_phase_get_string(ipc_imem->phase));
+ return -EIO;
+ }
+
+ return ipc_mux_open_session(ipc_imem->mux, if_id);
+}
+
+/* Release a net link to CP. */
+void ipc_imem_sys_wwan_close(struct iosm_imem *ipc_imem, int if_id,
+ int channel_id)
+{
+ if (ipc_imem->mux && if_id >= IP_MUX_SESSION_START &&
+ if_id <= IP_MUX_SESSION_END)
+ ipc_mux_close_session(ipc_imem->mux, if_id);
+}
+
+/* Tasklet call to do uplink transfer. */
+static int ipc_imem_tq_cdev_write(struct iosm_imem *ipc_imem, int arg,
+ void *msg, size_t size)
+{
+ ipc_imem->ev_cdev_write_pending = false;
+ ipc_imem_ul_send(ipc_imem);
+
+ return 0;
+}
+
+/* Through tasklet to do sio write. */
+static int ipc_imem_call_cdev_write(struct iosm_imem *ipc_imem)
+{
+ if (ipc_imem->ev_cdev_write_pending)
+ return -1;
+
+ ipc_imem->ev_cdev_write_pending = true;
+
+ return ipc_task_queue_send_task(ipc_imem, ipc_imem_tq_cdev_write, 0,
+ NULL, 0, false);
+}
+
+/* Function for transfer UL data */
+int ipc_imem_sys_wwan_transmit(struct iosm_imem *ipc_imem,
+ int if_id, int channel_id, struct sk_buff *skb)
+{
+ int ret = -EINVAL;
+
+ if (!ipc_imem || channel_id < 0)
+ goto out;
+
+ /* Is CP Running? */
+ if (ipc_imem->phase != IPC_P_RUN) {
+ dev_dbg(ipc_imem->dev, "phase %s transmit",
+ ipc_imem_phase_get_string(ipc_imem->phase));
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Route the UL packet through IP MUX Layer */
+ ret = ipc_mux_ul_trigger_encode(ipc_imem->mux, if_id, skb);
+out:
+ return ret;
+}
+
+/* Initialize wwan channel */
+void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem,
+ enum ipc_mux_protocol mux_type)
+{
+ struct ipc_chnl_cfg chnl_cfg = { 0 };
+
+ ipc_imem->cp_version = ipc_mmio_get_cp_version(ipc_imem->mmio);
+
+ /* If modem version is invalid (0xffffffff), do not initialize WWAN. */
+ if (ipc_imem->cp_version == -1) {
+ dev_err(ipc_imem->dev, "invalid CP version");
+ return;
+ }
+
+ ipc_chnl_cfg_get(&chnl_cfg, ipc_imem->nr_of_channels);
+ ipc_imem_channel_init(ipc_imem, IPC_CTYPE_WWAN, chnl_cfg,
+ IRQ_MOD_OFF);
+
+ /* WWAN registration. */
+ ipc_imem->wwan = ipc_wwan_init(ipc_imem, ipc_imem->dev);
+ if (!ipc_imem->wwan)
+ dev_err(ipc_imem->dev,
+ "failed to register the ipc_wwan interfaces");
+}
+
+/* Map SKB to DMA for transfer */
+static int ipc_imem_map_skb_to_dma(struct iosm_imem *ipc_imem,
+ struct sk_buff *skb)
+{
+ struct iosm_pcie *ipc_pcie = ipc_imem->pcie;
+ char *buf = skb->data;
+ int len = skb->len;
+ dma_addr_t mapping;
+ int ret;
+
+ ret = ipc_pcie_addr_map(ipc_pcie, buf, len, &mapping, DMA_TO_DEVICE);
+
+ if (ret)
+ goto err;
+
+ BUILD_BUG_ON(sizeof(*IPC_CB(skb)) > sizeof(skb->cb));
+
+ IPC_CB(skb)->mapping = mapping;
+ IPC_CB(skb)->direction = DMA_TO_DEVICE;
+ IPC_CB(skb)->len = len;
+ IPC_CB(skb)->op_type = (u8)UL_DEFAULT;
+
+err:
+ return ret;
+}
+
+/* return true if channel is ready for use */
+static bool ipc_imem_is_channel_active(struct iosm_imem *ipc_imem,
+ struct ipc_mem_channel *channel)
+{
+ enum ipc_phase phase;
+
+ /* Update the current operation phase. */
+ phase = ipc_imem->phase;
+
+ /* Select the operation depending on the execution stage. */
+ switch (phase) {
+ case IPC_P_RUN:
+ case IPC_P_PSI:
+ case IPC_P_EBL:
+ break;
+
+ case IPC_P_ROM:
+ /* Prepare the PSI image for the CP ROM driver and
+ * suspend the flash app.
+ */
+ if (channel->state != IMEM_CHANNEL_RESERVED) {
+ dev_err(ipc_imem->dev,
+ "ch[%d]:invalid channel state %d,expected %d",
+ channel->channel_id, channel->state,
+ IMEM_CHANNEL_RESERVED);
+ goto channel_unavailable;
+ }
+ goto channel_available;
+
+ default:
+ /* Ignore uplink actions in all other phases. */
+ dev_err(ipc_imem->dev, "ch[%d]: confused phase %d",
+ channel->channel_id, phase);
+ goto channel_unavailable;
+ }
+ /* Check the full availability of the channel. */
+ if (channel->state != IMEM_CHANNEL_ACTIVE) {
+ dev_err(ipc_imem->dev, "ch[%d]: confused channel state %d",
+ channel->channel_id, channel->state);
+ goto channel_unavailable;
+ }
+
+channel_available:
+ return true;
+
+channel_unavailable:
+ return false;
+}
+
+/* Release a sio link to CP. */
+void ipc_imem_sys_cdev_close(struct iosm_cdev *ipc_cdev)
+{
+ struct iosm_imem *ipc_imem = ipc_cdev->ipc_imem;
+ struct ipc_mem_channel *channel = ipc_cdev->channel;
+ enum ipc_phase curr_phase;
+ int status = 0;
+ u32 tail = 0;
+
+ curr_phase = ipc_imem->phase;
+
+ /* If current phase is IPC_P_OFF or SIO ID is -ve then
+ * channel is already freed. Nothing to do.
+ */
+ if (curr_phase == IPC_P_OFF) {
+ dev_err(ipc_imem->dev,
+ "nothing to do. Current Phase: %s",
+ ipc_imem_phase_get_string(curr_phase));
+ return;
+ }
+
+ if (channel->state == IMEM_CHANNEL_FREE) {
+ dev_err(ipc_imem->dev, "ch[%d]: invalid channel state %d",
+ channel->channel_id, channel->state);
+ return;
+ }
+
+ /* If there are any pending TDs then wait for Timeout/Completion before
+ * closing pipe.
+ */
+ if (channel->ul_pipe.old_tail != channel->ul_pipe.old_head) {
+ ipc_imem->app_notify_ul_pend = 1;
+
+ /* Suspend the user app and wait a certain time for processing
+ * UL Data.
+ */
+ status = wait_for_completion_interruptible_timeout
+ (&ipc_imem->ul_pend_sem,
+ msecs_to_jiffies(IPC_PEND_DATA_TIMEOUT));
+ if (status == 0) {
+ dev_dbg(ipc_imem->dev,
+ "Pend data Timeout UL-Pipe:%d Head:%d Tail:%d",
+ channel->ul_pipe.pipe_nr,
+ channel->ul_pipe.old_head,
+ channel->ul_pipe.old_tail);
+ }
+
+ ipc_imem->app_notify_ul_pend = 0;
+ }
+
+ /* If there are any pending TDs then wait for Timeout/Completion before
+ * closing pipe.
+ */
+ ipc_protocol_get_head_tail_index(ipc_imem->ipc_protocol,
+ &channel->dl_pipe, NULL, &tail);
+
+ if (tail != channel->dl_pipe.old_tail) {
+ ipc_imem->app_notify_dl_pend = 1;
+
+ /* Suspend the user app and wait a certain time for processing
+ * DL Data.
+ */
+ status = wait_for_completion_interruptible_timeout
+ (&ipc_imem->dl_pend_sem,
+ msecs_to_jiffies(IPC_PEND_DATA_TIMEOUT));
+ if (status == 0) {
+ dev_dbg(ipc_imem->dev,
+ "Pend data Timeout DL-Pipe:%d Head:%d Tail:%d",
+ channel->dl_pipe.pipe_nr,
+ channel->dl_pipe.old_head,
+ channel->dl_pipe.old_tail);
+ }
+
+ ipc_imem->app_notify_dl_pend = 0;
+ }
+
+ /* Due to wait for completion in messages, there is a small window
+ * between closing the pipe and updating the channel is closed. In this
+ * small window there could be HP update from Host Driver. Hence update
+ * the channel state as CLOSING to aviod unnecessary interrupt
+ * towards CP.
+ */
+ channel->state = IMEM_CHANNEL_CLOSING;
+
+ ipc_imem_pipe_close(ipc_imem, &channel->ul_pipe);
+ ipc_imem_pipe_close(ipc_imem, &channel->dl_pipe);
+
+ ipc_imem_channel_free(channel);
+}
+
+/* Open a PORT link to CP and return the channel */
+struct ipc_mem_channel *ipc_imem_sys_port_open(struct iosm_imem *ipc_imem,
+ int chl_id, int hp_id)
+{
+ struct ipc_mem_channel *channel;
+ int ch_id;
+
+ /* The PORT interface is only supported in the runtime phase. */
+ if (ipc_imem_phase_update(ipc_imem) != IPC_P_RUN) {
+ dev_err(ipc_imem->dev, "PORT open refused, phase %s",
+ ipc_imem_phase_get_string(ipc_imem->phase));
+ return NULL;
+ }
+
+ ch_id = ipc_imem_channel_alloc(ipc_imem, chl_id, IPC_CTYPE_CTRL);
+
+ if (ch_id < 0) {
+ dev_err(ipc_imem->dev, "reservation of an PORT chnl id failed");
+ return NULL;
+ }
+
+ channel = ipc_imem_channel_open(ipc_imem, ch_id, hp_id);
+
+ if (!channel) {
+ dev_err(ipc_imem->dev, "PORT channel id open failed");
+ return NULL;
+ }
+
+ return channel;
+}
+
+/* transfer skb to modem */
+int ipc_imem_sys_cdev_write(struct iosm_cdev *ipc_cdev, struct sk_buff *skb)
+{
+ struct ipc_mem_channel *channel = ipc_cdev->channel;
+ struct iosm_imem *ipc_imem = ipc_cdev->ipc_imem;
+ int ret = -EIO;
+
+ if (!ipc_imem_is_channel_active(ipc_imem, channel) ||
+ ipc_imem->phase == IPC_P_OFF_REQ)
+ goto out;
+
+ ret = ipc_imem_map_skb_to_dma(ipc_imem, skb);
+
+ if (ret)
+ goto out;
+
+ /* Add skb to the uplink skbuf accumulator. */
+ skb_queue_tail(&channel->ul_list, skb);
+
+ ret = ipc_imem_call_cdev_write(ipc_imem);
+
+ if (ret) {
+ skb_dequeue_tail(&channel->ul_list);
+ dev_err(ipc_cdev->dev, "channel id[%d] write failed\n",
+ ipc_cdev->channel->channel_id);
+ }
+out:
+ return ret;
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h
new file mode 100644
index 000000000000..2007fe23e9a5
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_imem_ops.h
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#ifndef IOSM_IPC_IMEM_OPS_H
+#define IOSM_IPC_IMEM_OPS_H
+
+#include "iosm_ipc_mux_codec.h"
+
+/* Maximum wait time for blocking read */
+#define IPC_READ_TIMEOUT 500
+
+/* The delay in ms for defering the unregister */
+#define SIO_UNREGISTER_DEFER_DELAY_MS 1
+
+/* Default delay till CP PSI image is running and modem updates the
+ * execution stage.
+ * unit : milliseconds
+ */
+#define PSI_START_DEFAULT_TIMEOUT 3000
+
+/* Default time out when closing SIO, till the modem is in
+ * running state.
+ * unit : milliseconds
+ */
+#define BOOT_CHECK_DEFAULT_TIMEOUT 400
+
+/* IP MUX channel range */
+#define IP_MUX_SESSION_START 0
+#define IP_MUX_SESSION_END 7
+
+/* Default IP MUX channel */
+#define IP_MUX_SESSION_DEFAULT 0
+
+/**
+ * ipc_imem_sys_port_open - Open a port link to CP.
+ * @ipc_imem: Imem instance.
+ * @chl_id: Channel Indentifier.
+ * @hp_id: HP Indentifier.
+ *
+ * Return: channel instance on success, NULL for failure
+ */
+struct ipc_mem_channel *ipc_imem_sys_port_open(struct iosm_imem *ipc_imem,
+ int chl_id, int hp_id);
+
+/**
+ * ipc_imem_sys_cdev_close - Release a sio link to CP.
+ * @ipc_cdev: iosm sio instance.
+ */
+void ipc_imem_sys_cdev_close(struct iosm_cdev *ipc_cdev);
+
+/**
+ * ipc_imem_sys_cdev_write - Route the uplink buffer to CP.
+ * @ipc_cdev: iosm_cdev instance.
+ * @skb: Pointer to skb.
+ *
+ * Return: 0 on success and failure value on error
+ */
+int ipc_imem_sys_cdev_write(struct iosm_cdev *ipc_cdev, struct sk_buff *skb);
+
+/**
+ * ipc_imem_sys_wwan_open - Open packet data online channel between network
+ * layer and CP.
+ * @ipc_imem: Imem instance.
+ * @if_id: ip link tag of the net device.
+ *
+ * Return: Channel ID on success and failure value on error
+ */
+int ipc_imem_sys_wwan_open(struct iosm_imem *ipc_imem, int if_id);
+
+/**
+ * ipc_imem_sys_wwan_close - Close packet data online channel between network
+ * layer and CP.
+ * @ipc_imem: Imem instance.
+ * @if_id: IP link id net device.
+ * @channel_id: Channel ID to be closed.
+ */
+void ipc_imem_sys_wwan_close(struct iosm_imem *ipc_imem, int if_id,
+ int channel_id);
+
+/**
+ * ipc_imem_sys_wwan_transmit - Function for transfer UL data
+ * @ipc_imem: Imem instance.
+ * @if_id: link ID of the device.
+ * @channel_id: Channel ID used
+ * @skb: Pointer to sk buffer
+ *
+ * Return: 0 on success and failure value on error
+ */
+int ipc_imem_sys_wwan_transmit(struct iosm_imem *ipc_imem, int if_id,
+ int channel_id, struct sk_buff *skb);
+/**
+ * ipc_imem_wwan_channel_init - Initializes WWAN channels and the channel for
+ * MUX.
+ * @ipc_imem: Pointer to iosm_imem struct.
+ * @mux_type: Type of mux protocol.
+ */
+void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem,
+ enum ipc_mux_protocol mux_type);
+#endif
diff --git a/drivers/net/wwan/iosm/iosm_ipc_irq.c b/drivers/net/wwan/iosm/iosm_ipc_irq.c
new file mode 100644
index 000000000000..702f50a48151
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_irq.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include "iosm_ipc_pcie.h"
+#include "iosm_ipc_protocol.h"
+
+static void ipc_write_dbell_reg(struct iosm_pcie *ipc_pcie, int irq_n, u32 data)
+{
+ void __iomem *write_reg;
+
+ /* Select the first doorbell register, which is only currently needed
+ * by CP.
+ */
+ write_reg = (void __iomem *)((u8 __iomem *)ipc_pcie->ipc_regs +
+ ipc_pcie->doorbell_write +
+ (irq_n * ipc_pcie->doorbell_reg_offset));
+
+ /* Fire the doorbell irq by writing data on the doorbell write pointer
+ * register.
+ */
+ iowrite32(data, write_reg);
+}
+
+void ipc_doorbell_fire(struct iosm_pcie *ipc_pcie, int irq_n, u32 data)
+{
+ ipc_write_dbell_reg(ipc_pcie, irq_n, data);
+}
+
+/* Threaded Interrupt handler for MSI interrupts */
+static irqreturn_t ipc_msi_interrupt(int irq, void *dev_id)
+{
+ struct iosm_pcie *ipc_pcie = dev_id;
+ int instance = irq - ipc_pcie->pci->irq;
+
+ /* Shift the MSI irq actions to the IPC tasklet. IRQ_NONE means the
+ * irq was not from the IPC device or could not be served.
+ */
+ if (instance >= ipc_pcie->nvec)
+ return IRQ_NONE;
+
+ if (!test_bit(0, &ipc_pcie->suspend))
+ ipc_imem_irq_process(ipc_pcie->imem, instance);
+
+ return IRQ_HANDLED;
+}
+
+void ipc_release_irq(struct iosm_pcie *ipc_pcie)
+{
+ struct pci_dev *pdev = ipc_pcie->pci;
+
+ if (pdev->msi_enabled) {
+ while (--ipc_pcie->nvec >= 0)
+ free_irq(pdev->irq + ipc_pcie->nvec, ipc_pcie);
+ }
+ pci_free_irq_vectors(pdev);
+}
+
+int ipc_acquire_irq(struct iosm_pcie *ipc_pcie)
+{
+ struct pci_dev *pdev = ipc_pcie->pci;
+ int i, rc = -EINVAL;
+
+ ipc_pcie->nvec = pci_alloc_irq_vectors(pdev, IPC_MSI_VECTORS,
+ IPC_MSI_VECTORS, PCI_IRQ_MSI);
+
+ if (ipc_pcie->nvec < 0) {
+ rc = ipc_pcie->nvec;
+ goto error;
+ }
+
+ if (!pdev->msi_enabled)
+ goto error;
+
+ for (i = 0; i < ipc_pcie->nvec; ++i) {
+ rc = request_threaded_irq(pdev->irq + i, NULL,
+ ipc_msi_interrupt, IRQF_ONESHOT,
+ KBUILD_MODNAME, ipc_pcie);
+ if (rc) {
+ dev_err(ipc_pcie->dev, "unable to grab IRQ, rc=%d", rc);
+ ipc_pcie->nvec = i;
+ ipc_release_irq(ipc_pcie);
+ goto error;
+ }
+ }
+
+error:
+ return rc;
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_irq.h b/drivers/net/wwan/iosm/iosm_ipc_irq.h
new file mode 100644
index 000000000000..a8ed596cb6a5
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_irq.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#ifndef IOSM_IPC_IRQ_H
+#define IOSM_IPC_IRQ_H
+
+struct iosm_pcie;
+
+/**
+ * ipc_doorbell_fire - fire doorbell to CP
+ * @ipc_pcie: Pointer to iosm_pcie
+ * @irq_n: Doorbell type
+ * @data: ipc state
+ */
+void ipc_doorbell_fire(struct iosm_pcie *ipc_pcie, int irq_n, u32 data);
+
+/**
+ * ipc_release_irq - Release the IRQ handler.
+ * @ipc_pcie: Pointer to iosm_pcie struct
+ */
+void ipc_release_irq(struct iosm_pcie *ipc_pcie);
+
+/**
+ * ipc_acquire_irq - acquire IRQ & register IRQ handler.
+ * @ipc_pcie: Pointer to iosm_pcie struct
+ *
+ * Return: 0 on success and failure value on error
+ */
+int ipc_acquire_irq(struct iosm_pcie *ipc_pcie);
+
+#endif
diff --git a/drivers/net/wwan/iosm/iosm_ipc_mmio.c b/drivers/net/wwan/iosm/iosm_ipc_mmio.c
new file mode 100644
index 000000000000..06c94b1720b6
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_mmio.c
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/slab.h>
+
+#include "iosm_ipc_mmio.h"
+
+/* Definition of MMIO offsets
+ * note that MMIO_CI offsets are relative to end of chip info structure
+ */
+
+/* MMIO chip info size in bytes */
+#define MMIO_CHIP_INFO_SIZE 60
+
+/* CP execution stage */
+#define MMIO_OFFSET_EXECUTION_STAGE 0x00
+
+/* Boot ROM Chip Info struct */
+#define MMIO_OFFSET_CHIP_INFO 0x04
+
+#define MMIO_OFFSET_ROM_EXIT_CODE 0x40
+
+#define MMIO_OFFSET_PSI_ADDRESS 0x54
+
+#define MMIO_OFFSET_PSI_SIZE 0x5C
+
+#define MMIO_OFFSET_IPC_STATUS 0x60
+
+#define MMIO_OFFSET_CONTEXT_INFO 0x64
+
+#define MMIO_OFFSET_BASE_ADDR 0x6C
+
+#define MMIO_OFFSET_END_ADDR 0x74
+
+#define MMIO_OFFSET_CP_VERSION 0xF0
+
+#define MMIO_OFFSET_CP_CAPABILITIES 0xF4
+
+/* Timeout in 50 msec to wait for the modem boot code to write a valid
+ * execution stage into mmio area
+ */
+#define IPC_MMIO_EXEC_STAGE_TIMEOUT 50
+
+/* check if exec stage has one of the valid values */
+static bool ipc_mmio_is_valid_exec_stage(enum ipc_mem_exec_stage stage)
+{
+ switch (stage) {
+ case IPC_MEM_EXEC_STAGE_BOOT:
+ case IPC_MEM_EXEC_STAGE_PSI:
+ case IPC_MEM_EXEC_STAGE_EBL:
+ case IPC_MEM_EXEC_STAGE_RUN:
+ case IPC_MEM_EXEC_STAGE_CRASH:
+ case IPC_MEM_EXEC_STAGE_CD_READY:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void ipc_mmio_update_cp_capability(struct iosm_mmio *ipc_mmio)
+{
+ u32 cp_cap;
+ unsigned int ver;
+
+ ver = ipc_mmio_get_cp_version(ipc_mmio);
+ cp_cap = readl(ipc_mmio->base + ipc_mmio->offset.cp_capability);
+
+ ipc_mmio->has_mux_lite = (ver >= IOSM_CP_VERSION) &&
+ !(cp_cap & DL_AGGR) && !(cp_cap & UL_AGGR);
+
+ ipc_mmio->has_ul_flow_credit =
+ (ver >= IOSM_CP_VERSION) && (cp_cap & UL_FLOW_CREDIT);
+}
+
+struct iosm_mmio *ipc_mmio_init(void __iomem *mmio, struct device *dev)
+{
+ struct iosm_mmio *ipc_mmio = kzalloc(sizeof(*ipc_mmio), GFP_KERNEL);
+ int retries = IPC_MMIO_EXEC_STAGE_TIMEOUT;
+ enum ipc_mem_exec_stage stage;
+
+ if (!ipc_mmio)
+ return NULL;
+
+ ipc_mmio->dev = dev;
+
+ ipc_mmio->base = mmio;
+
+ ipc_mmio->offset.exec_stage = MMIO_OFFSET_EXECUTION_STAGE;
+
+ /* Check for a valid execution stage to make sure that the boot code
+ * has correctly initialized the MMIO area.
+ */
+ do {
+ stage = ipc_mmio_get_exec_stage(ipc_mmio);
+ if (ipc_mmio_is_valid_exec_stage(stage))
+ break;
+
+ msleep(20);
+ } while (retries-- > 0);
+
+ if (!retries) {
+ dev_err(ipc_mmio->dev, "invalid exec stage %X", stage);
+ goto init_fail;
+ }
+
+ ipc_mmio->offset.chip_info = MMIO_OFFSET_CHIP_INFO;
+
+ /* read chip info size and version from chip info structure */
+ ipc_mmio->chip_info_version =
+ ioread8(ipc_mmio->base + ipc_mmio->offset.chip_info);
+
+ /* Increment of 2 is needed as the size value in the chip info
+ * excludes the version and size field, which are always present
+ */
+ ipc_mmio->chip_info_size =
+ ioread8(ipc_mmio->base + ipc_mmio->offset.chip_info + 1) + 2;
+
+ if (ipc_mmio->chip_info_size != MMIO_CHIP_INFO_SIZE) {
+ dev_err(ipc_mmio->dev, "Unexpected Chip Info");
+ goto init_fail;
+ }
+
+ ipc_mmio->offset.rom_exit_code = MMIO_OFFSET_ROM_EXIT_CODE;
+
+ ipc_mmio->offset.psi_address = MMIO_OFFSET_PSI_ADDRESS;
+ ipc_mmio->offset.psi_size = MMIO_OFFSET_PSI_SIZE;
+ ipc_mmio->offset.ipc_status = MMIO_OFFSET_IPC_STATUS;
+ ipc_mmio->offset.context_info = MMIO_OFFSET_CONTEXT_INFO;
+ ipc_mmio->offset.ap_win_base = MMIO_OFFSET_BASE_ADDR;
+ ipc_mmio->offset.ap_win_end = MMIO_OFFSET_END_ADDR;
+
+ ipc_mmio->offset.cp_version = MMIO_OFFSET_CP_VERSION;
+ ipc_mmio->offset.cp_capability = MMIO_OFFSET_CP_CAPABILITIES;
+
+ return ipc_mmio;
+
+init_fail:
+ kfree(ipc_mmio);
+ return NULL;
+}
+
+enum ipc_mem_exec_stage ipc_mmio_get_exec_stage(struct iosm_mmio *ipc_mmio)
+{
+ if (!ipc_mmio)
+ return IPC_MEM_EXEC_STAGE_INVALID;
+
+ return (enum ipc_mem_exec_stage)readl(ipc_mmio->base +
+ ipc_mmio->offset.exec_stage);
+}
+
+void ipc_mmio_copy_chip_info(struct iosm_mmio *ipc_mmio, void *dest,
+ size_t size)
+{
+ if (ipc_mmio && dest)
+ memcpy_fromio(dest, ipc_mmio->base + ipc_mmio->offset.chip_info,
+ size);
+}
+
+enum ipc_mem_device_ipc_state ipc_mmio_get_ipc_state(struct iosm_mmio *ipc_mmio)
+{
+ if (!ipc_mmio)
+ return IPC_MEM_DEVICE_IPC_INVALID;
+
+ return (enum ipc_mem_device_ipc_state)
+ readl(ipc_mmio->base + ipc_mmio->offset.ipc_status);
+}
+
+enum rom_exit_code ipc_mmio_get_rom_exit_code(struct iosm_mmio *ipc_mmio)
+{
+ if (!ipc_mmio)
+ return IMEM_ROM_EXIT_FAIL;
+
+ return (enum rom_exit_code)readl(ipc_mmio->base +
+ ipc_mmio->offset.rom_exit_code);
+}
+
+void ipc_mmio_config(struct iosm_mmio *ipc_mmio)
+{
+ if (!ipc_mmio)
+ return;
+
+ /* AP memory window (full window is open and active so that modem checks
+ * each AP address) 0 means don't check on modem side.
+ */
+ iowrite64_lo_hi(0, ipc_mmio->base + ipc_mmio->offset.ap_win_base);
+ iowrite64_lo_hi(0, ipc_mmio->base + ipc_mmio->offset.ap_win_end);
+
+ iowrite64_lo_hi(ipc_mmio->context_info_addr,
+ ipc_mmio->base + ipc_mmio->offset.context_info);
+}
+
+void ipc_mmio_set_psi_addr_and_size(struct iosm_mmio *ipc_mmio, dma_addr_t addr,
+ u32 size)
+{
+ if (!ipc_mmio)
+ return;
+
+ iowrite64_lo_hi(addr, ipc_mmio->base + ipc_mmio->offset.psi_address);
+ writel(size, ipc_mmio->base + ipc_mmio->offset.psi_size);
+}
+
+void ipc_mmio_set_contex_info_addr(struct iosm_mmio *ipc_mmio, phys_addr_t addr)
+{
+ if (!ipc_mmio)
+ return;
+
+ /* store context_info address. This will be stored in the mmio area
+ * during IPC_MEM_DEVICE_IPC_INIT state via ipc_mmio_config()
+ */
+ ipc_mmio->context_info_addr = addr;
+}
+
+int ipc_mmio_get_cp_version(struct iosm_mmio *ipc_mmio)
+{
+ return ipc_mmio ? readl(ipc_mmio->base + ipc_mmio->offset.cp_version) :
+ -EFAULT;
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_mmio.h b/drivers/net/wwan/iosm/iosm_ipc_mmio.h
new file mode 100644
index 000000000000..45e6923da78f
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_mmio.h
@@ -0,0 +1,183 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#ifndef IOSM_IPC_MMIO_H
+#define IOSM_IPC_MMIO_H
+
+/* Minimal IOSM CP VERSION which has valid CP_CAPABILITIES field */
+#define IOSM_CP_VERSION 0x0100UL
+
+/* DL dir Aggregation support mask */
+#define DL_AGGR BIT(23)
+
+/* UL dir Aggregation support mask */
+#define UL_AGGR BIT(22)
+
+/* UL flow credit support mask */
+#define UL_FLOW_CREDIT BIT(21)
+
+/* Possible states of the IPC finite state machine. */
+enum ipc_mem_device_ipc_state {
+ IPC_MEM_DEVICE_IPC_UNINIT,
+ IPC_MEM_DEVICE_IPC_INIT,
+ IPC_MEM_DEVICE_IPC_RUNNING,
+ IPC_MEM_DEVICE_IPC_RECOVERY,
+ IPC_MEM_DEVICE_IPC_ERROR,
+ IPC_MEM_DEVICE_IPC_DONT_CARE,
+ IPC_MEM_DEVICE_IPC_INVALID = -1
+};
+
+/* Boot ROM exit status. */
+enum rom_exit_code {
+ IMEM_ROM_EXIT_OPEN_EXT = 0x01,
+ IMEM_ROM_EXIT_OPEN_MEM = 0x02,
+ IMEM_ROM_EXIT_CERT_EXT = 0x10,
+ IMEM_ROM_EXIT_CERT_MEM = 0x20,
+ IMEM_ROM_EXIT_FAIL = 0xFF
+};
+
+/* Boot stages */
+enum ipc_mem_exec_stage {
+ IPC_MEM_EXEC_STAGE_RUN = 0x600DF00D,
+ IPC_MEM_EXEC_STAGE_CRASH = 0x8BADF00D,
+ IPC_MEM_EXEC_STAGE_CD_READY = 0xBADC0DED,
+ IPC_MEM_EXEC_STAGE_BOOT = 0xFEEDB007,
+ IPC_MEM_EXEC_STAGE_PSI = 0xFEEDBEEF,
+ IPC_MEM_EXEC_STAGE_EBL = 0xFEEDCAFE,
+ IPC_MEM_EXEC_STAGE_INVALID = 0xFFFFFFFF
+};
+
+/* mmio scratchpad info */
+struct mmio_offset {
+ int exec_stage;
+ int chip_info;
+ int rom_exit_code;
+ int psi_address;
+ int psi_size;
+ int ipc_status;
+ int context_info;
+ int ap_win_base;
+ int ap_win_end;
+ int cp_version;
+ int cp_capability;
+};
+
+/**
+ * struct iosm_mmio - MMIO region mapped to the doorbell scratchpad.
+ * @base: Base address of MMIO region
+ * @dev: Pointer to device structure
+ * @offset: Start offset
+ * @context_info_addr: Physical base address of context info structure
+ * @chip_info_version: Version of chip info structure
+ * @chip_info_size: Size of chip info structure
+ * @has_mux_lite: It doesn't support mux aggergation
+ * @has_ul_flow_credit: Ul flow credit support
+ * @has_slp_no_prot: Device sleep no protocol support
+ * @has_mcr_support: Usage of mcr support
+ */
+struct iosm_mmio {
+ unsigned char __iomem *base;
+ struct device *dev;
+ struct mmio_offset offset;
+ phys_addr_t context_info_addr;
+ unsigned int chip_info_version;
+ unsigned int chip_info_size;
+ u8 has_mux_lite:1,
+ has_ul_flow_credit:1,
+ has_slp_no_prot:1,
+ has_mcr_support:1;
+};
+
+/**
+ * ipc_mmio_init - Allocate mmio instance data
+ * @mmio_addr: Mapped AP base address of the MMIO area.
+ * @dev: Pointer to device structure
+ *
+ * Returns: address of mmio instance data or NULL if fails.
+ */
+struct iosm_mmio *ipc_mmio_init(void __iomem *mmio_addr, struct device *dev);
+
+/**
+ * ipc_mmio_set_psi_addr_and_size - Set start address and size of the
+ * primary system image (PSI) for the
+ * FW dowload.
+ * @ipc_mmio: Pointer to mmio instance
+ * @addr: PSI address
+ * @size: PSI immage size
+ */
+void ipc_mmio_set_psi_addr_and_size(struct iosm_mmio *ipc_mmio, dma_addr_t addr,
+ u32 size);
+
+/**
+ * ipc_mmio_set_contex_info_addr - Stores the Context Info Address in
+ * MMIO instance to share it with CP during
+ * mmio_init.
+ * @ipc_mmio: Pointer to mmio instance
+ * @addr: 64-bit address of AP context information.
+ */
+void ipc_mmio_set_contex_info_addr(struct iosm_mmio *ipc_mmio,
+ phys_addr_t addr);
+
+/**
+ * ipc_mmio_get_cp_version - Get the CP IPC version
+ * @ipc_mmio: Pointer to mmio instance
+ *
+ * Returns: version number on success and failure value on error.
+ */
+int ipc_mmio_get_cp_version(struct iosm_mmio *ipc_mmio);
+
+/**
+ * ipc_mmio_get_rom_exit_code - Get exit code from CP boot rom download app
+ * @ipc_mmio: Pointer to mmio instance
+ *
+ * Returns: exit code from CP boot rom download APP
+ */
+enum rom_exit_code ipc_mmio_get_rom_exit_code(struct iosm_mmio *ipc_mmio);
+
+/**
+ * ipc_mmio_get_exec_stage - Query CP execution stage
+ * @ipc_mmio: Pointer to mmio instance
+ *
+ * Returns: CP execution stage
+ */
+enum ipc_mem_exec_stage ipc_mmio_get_exec_stage(struct iosm_mmio *ipc_mmio);
+
+/**
+ * ipc_mmio_get_ipc_state - Query CP IPC state
+ * @ipc_mmio: Pointer to mmio instance
+ *
+ * Returns: CP IPC state
+ */
+enum ipc_mem_device_ipc_state
+ipc_mmio_get_ipc_state(struct iosm_mmio *ipc_mmio);
+
+/**
+ * ipc_mmio_copy_chip_info - Copy size bytes of CP chip info structure
+ * into caller provided buffer
+ * @ipc_mmio: Pointer to mmio instance
+ * @dest: Pointer to caller provided buff
+ * @size: Number of bytes to copy
+ */
+void ipc_mmio_copy_chip_info(struct iosm_mmio *ipc_mmio, void *dest,
+ size_t size);
+
+/**
+ * ipc_mmio_config - Write context info and AP memory range addresses.
+ * This needs to be called when CP is in
+ * IPC_MEM_DEVICE_IPC_INIT state
+ *
+ * @ipc_mmio: Pointer to mmio instance
+ */
+void ipc_mmio_config(struct iosm_mmio *ipc_mmio);
+
+/**
+ * ipc_mmio_update_cp_capability - Read and update modem capability, from mmio
+ * capability offset
+ *
+ * @ipc_mmio: Pointer to mmio instance
+ */
+void ipc_mmio_update_cp_capability(struct iosm_mmio *ipc_mmio);
+
+#endif
diff --git a/drivers/net/wwan/iosm/iosm_ipc_mux.c b/drivers/net/wwan/iosm/iosm_ipc_mux.c
new file mode 100644
index 000000000000..c1c77ce699da
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_mux.c
@@ -0,0 +1,455 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include "iosm_ipc_mux_codec.h"
+
+/* At the begin of the runtime phase the IP MUX channel shall created. */
+static int ipc_mux_channel_create(struct iosm_mux *ipc_mux)
+{
+ int channel_id;
+
+ channel_id = ipc_imem_channel_alloc(ipc_mux->imem, ipc_mux->instance_id,
+ IPC_CTYPE_WWAN);
+
+ if (channel_id < 0) {
+ dev_err(ipc_mux->dev,
+ "allocation of the MUX channel id failed");
+ ipc_mux->state = MUX_S_ERROR;
+ ipc_mux->event = MUX_E_NOT_APPLICABLE;
+ goto no_channel;
+ }
+
+ /* Establish the MUX channel in blocking mode. */
+ ipc_mux->channel = ipc_imem_channel_open(ipc_mux->imem, channel_id,
+ IPC_HP_NET_CHANNEL_INIT);
+
+ if (!ipc_mux->channel) {
+ dev_err(ipc_mux->dev, "ipc_imem_channel_open failed");
+ ipc_mux->state = MUX_S_ERROR;
+ ipc_mux->event = MUX_E_NOT_APPLICABLE;
+ return -ENODEV; /* MUX channel is not available. */
+ }
+
+ /* Define the MUX active state properties. */
+ ipc_mux->state = MUX_S_ACTIVE;
+ ipc_mux->event = MUX_E_NO_ORDERS;
+
+no_channel:
+ return channel_id;
+}
+
+/* Reset the session/if id state. */
+static void ipc_mux_session_free(struct iosm_mux *ipc_mux, int if_id)
+{
+ struct mux_session *if_entry;
+
+ if_entry = &ipc_mux->session[if_id];
+ /* Reset the session state. */
+ if_entry->wwan = NULL;
+}
+
+/* Create and send the session open command. */
+static struct mux_cmd_open_session_resp *
+ipc_mux_session_open_send(struct iosm_mux *ipc_mux, int if_id)
+{
+ struct mux_cmd_open_session_resp *open_session_resp;
+ struct mux_acb *acb = &ipc_mux->acb;
+ union mux_cmd_param param;
+
+ /* open_session commands to one ACB and start transmission. */
+ param.open_session.flow_ctrl = 0;
+ param.open_session.ipv4v6_hints = 0;
+ param.open_session.reserved2 = 0;
+ param.open_session.dl_head_pad_len = cpu_to_le32(IPC_MEM_DL_ETH_OFFSET);
+
+ /* Finish and transfer ACB. The user thread is suspended.
+ * It is a blocking function call, until CP responds or timeout.
+ */
+ acb->wanted_response = MUX_CMD_OPEN_SESSION_RESP;
+ if (ipc_mux_dl_acb_send_cmds(ipc_mux, MUX_CMD_OPEN_SESSION, if_id, 0,
+ &param, sizeof(param.open_session), true,
+ false) ||
+ acb->got_response != MUX_CMD_OPEN_SESSION_RESP) {
+ dev_err(ipc_mux->dev, "if_id %d: OPEN_SESSION send failed",
+ if_id);
+ return NULL;
+ }
+
+ open_session_resp = &ipc_mux->acb.got_param.open_session_resp;
+ if (open_session_resp->response != cpu_to_le32(MUX_CMD_RESP_SUCCESS)) {
+ dev_err(ipc_mux->dev,
+ "if_id %d,session open failed,response=%d", if_id,
+ open_session_resp->response);
+ return NULL;
+ }
+
+ return open_session_resp;
+}
+
+/* Open the first IP session. */
+static bool ipc_mux_session_open(struct iosm_mux *ipc_mux,
+ struct mux_session_open *session_open)
+{
+ struct mux_cmd_open_session_resp *open_session_resp;
+ int if_id;
+
+ /* Search for a free session interface id. */
+ if_id = le32_to_cpu(session_open->if_id);
+ if (if_id < 0 || if_id >= ipc_mux->nr_sessions) {
+ dev_err(ipc_mux->dev, "invalid interface id=%d", if_id);
+ return false;
+ }
+
+ /* Create and send the session open command.
+ * It is a blocking function call, until CP responds or timeout.
+ */
+ open_session_resp = ipc_mux_session_open_send(ipc_mux, if_id);
+ if (!open_session_resp) {
+ ipc_mux_session_free(ipc_mux, if_id);
+ session_open->if_id = cpu_to_le32(-1);
+ return false;
+ }
+
+ /* Initialize the uplink skb accumulator. */
+ skb_queue_head_init(&ipc_mux->session[if_id].ul_list);
+
+ ipc_mux->session[if_id].dl_head_pad_len = IPC_MEM_DL_ETH_OFFSET;
+ ipc_mux->session[if_id].ul_head_pad_len =
+ le32_to_cpu(open_session_resp->ul_head_pad_len);
+ ipc_mux->session[if_id].wwan = ipc_mux->wwan;
+
+ /* Reset the flow ctrl stats of the session */
+ ipc_mux->session[if_id].flow_ctl_en_cnt = 0;
+ ipc_mux->session[if_id].flow_ctl_dis_cnt = 0;
+ ipc_mux->session[if_id].ul_flow_credits = 0;
+ ipc_mux->session[if_id].net_tx_stop = false;
+ ipc_mux->session[if_id].flow_ctl_mask = 0;
+
+ /* Save and return the assigned if id. */
+ session_open->if_id = cpu_to_le32(if_id);
+
+ return true;
+}
+
+/* Free pending session UL packet. */
+static void ipc_mux_session_reset(struct iosm_mux *ipc_mux, int if_id)
+{
+ /* Reset the session/if id state. */
+ ipc_mux_session_free(ipc_mux, if_id);
+
+ /* Empty the uplink skb accumulator. */
+ skb_queue_purge(&ipc_mux->session[if_id].ul_list);
+}
+
+static void ipc_mux_session_close(struct iosm_mux *ipc_mux,
+ struct mux_session_close *msg)
+{
+ int if_id;
+
+ /* Copy the session interface id. */
+ if_id = le32_to_cpu(msg->if_id);
+
+ if (if_id < 0 || if_id >= ipc_mux->nr_sessions) {
+ dev_err(ipc_mux->dev, "invalid session id %d", if_id);
+ return;
+ }
+
+ /* Create and send the session close command.
+ * It is a blocking function call, until CP responds or timeout.
+ */
+ if (ipc_mux_dl_acb_send_cmds(ipc_mux, MUX_CMD_CLOSE_SESSION, if_id, 0,
+ NULL, 0, true, false))
+ dev_err(ipc_mux->dev, "if_id %d: CLOSE_SESSION send failed",
+ if_id);
+
+ /* Reset the flow ctrl stats of the session */
+ ipc_mux->session[if_id].flow_ctl_en_cnt = 0;
+ ipc_mux->session[if_id].flow_ctl_dis_cnt = 0;
+ ipc_mux->session[if_id].flow_ctl_mask = 0;
+
+ ipc_mux_session_reset(ipc_mux, if_id);
+}
+
+static void ipc_mux_channel_close(struct iosm_mux *ipc_mux,
+ struct mux_channel_close *channel_close_p)
+{
+ int i;
+
+ /* Free pending session UL packet. */
+ for (i = 0; i < ipc_mux->nr_sessions; i++)
+ if (ipc_mux->session[i].wwan)
+ ipc_mux_session_reset(ipc_mux, i);
+
+ ipc_imem_channel_close(ipc_mux->imem, ipc_mux->channel_id);
+
+ /* Reset the MUX object. */
+ ipc_mux->state = MUX_S_INACTIVE;
+ ipc_mux->event = MUX_E_INACTIVE;
+}
+
+/* CP has interrupted AP. If AP is in IP MUX mode, execute the pending ops. */
+static int ipc_mux_schedule(struct iosm_mux *ipc_mux, union mux_msg *msg)
+{
+ enum mux_event order;
+ bool success;
+ int ret = -EIO;
+
+ if (!ipc_mux->initialized) {
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ order = msg->common.event;
+
+ switch (ipc_mux->state) {
+ case MUX_S_INACTIVE:
+ if (order != MUX_E_MUX_SESSION_OPEN)
+ goto out; /* Wait for the request to open a session */
+
+ if (ipc_mux->event == MUX_E_INACTIVE)
+ /* Establish the MUX channel and the new state. */
+ ipc_mux->channel_id = ipc_mux_channel_create(ipc_mux);
+
+ if (ipc_mux->state != MUX_S_ACTIVE) {
+ ret = ipc_mux->channel_id; /* Missing the MUX channel */
+ goto out;
+ }
+
+ /* Disable the TD update timer and open the first IP session. */
+ ipc_imem_td_update_timer_suspend(ipc_mux->imem, true);
+ ipc_mux->event = MUX_E_MUX_SESSION_OPEN;
+ success = ipc_mux_session_open(ipc_mux, &msg->session_open);
+
+ ipc_imem_td_update_timer_suspend(ipc_mux->imem, false);
+ if (success)
+ ret = ipc_mux->channel_id;
+ goto out;
+
+ case MUX_S_ACTIVE:
+ switch (order) {
+ case MUX_E_MUX_SESSION_OPEN:
+ /* Disable the TD update timer and open a session */
+ ipc_imem_td_update_timer_suspend(ipc_mux->imem, true);
+ ipc_mux->event = MUX_E_MUX_SESSION_OPEN;
+ success = ipc_mux_session_open(ipc_mux,
+ &msg->session_open);
+ ipc_imem_td_update_timer_suspend(ipc_mux->imem, false);
+ if (success)
+ ret = ipc_mux->channel_id;
+ goto out;
+
+ case MUX_E_MUX_SESSION_CLOSE:
+ /* Release an IP session. */
+ ipc_mux->event = MUX_E_MUX_SESSION_CLOSE;
+ ipc_mux_session_close(ipc_mux, &msg->session_close);
+ ret = ipc_mux->channel_id;
+ goto out;
+
+ case MUX_E_MUX_CHANNEL_CLOSE:
+ /* Close the MUX channel pipes. */
+ ipc_mux->event = MUX_E_MUX_CHANNEL_CLOSE;
+ ipc_mux_channel_close(ipc_mux, &msg->channel_close);
+ ret = ipc_mux->channel_id;
+ goto out;
+
+ default:
+ /* Invalid order. */
+ goto out;
+ }
+
+ default:
+ dev_err(ipc_mux->dev,
+ "unexpected MUX transition: state=%d, event=%d",
+ ipc_mux->state, ipc_mux->event);
+ }
+out:
+ return ret;
+}
+
+struct iosm_mux *ipc_mux_init(struct ipc_mux_config *mux_cfg,
+ struct iosm_imem *imem)
+{
+ struct iosm_mux *ipc_mux = kzalloc(sizeof(*ipc_mux), GFP_KERNEL);
+ int i, ul_tds, ul_td_size;
+ struct sk_buff_head *free_list;
+ struct sk_buff *skb;
+
+ if (!ipc_mux)
+ return NULL;
+
+ ipc_mux->protocol = mux_cfg->protocol;
+ ipc_mux->ul_flow = mux_cfg->ul_flow;
+ ipc_mux->nr_sessions = mux_cfg->nr_sessions;
+ ipc_mux->instance_id = mux_cfg->instance_id;
+ ipc_mux->wwan_q_offset = 0;
+
+ ipc_mux->pcie = imem->pcie;
+ ipc_mux->imem = imem;
+ ipc_mux->ipc_protocol = imem->ipc_protocol;
+ ipc_mux->dev = imem->dev;
+ ipc_mux->wwan = imem->wwan;
+
+ /* Get the reference to the UL ADB list. */
+ free_list = &ipc_mux->ul_adb.free_list;
+
+ /* Initialize the list with free ADB. */
+ skb_queue_head_init(free_list);
+
+ ul_td_size = IPC_MEM_MAX_DL_MUX_LITE_BUF_SIZE;
+
+ ul_tds = IPC_MEM_MAX_TDS_MUX_LITE_UL;
+
+ ipc_mux->ul_adb.dest_skb = NULL;
+
+ ipc_mux->initialized = true;
+ ipc_mux->adb_prep_ongoing = false;
+ ipc_mux->size_needed = 0;
+ ipc_mux->ul_data_pend_bytes = 0;
+ ipc_mux->state = MUX_S_INACTIVE;
+ ipc_mux->ev_mux_net_transmit_pending = false;
+ ipc_mux->tx_transaction_id = 0;
+ ipc_mux->rr_next_session = 0;
+ ipc_mux->event = MUX_E_INACTIVE;
+ ipc_mux->channel_id = -1;
+ ipc_mux->channel = NULL;
+
+ /* Allocate the list of UL ADB. */
+ for (i = 0; i < ul_tds; i++) {
+ dma_addr_t mapping;
+
+ skb = ipc_pcie_alloc_skb(ipc_mux->pcie, ul_td_size, GFP_ATOMIC,
+ &mapping, DMA_TO_DEVICE, 0);
+ if (!skb) {
+ ipc_mux_deinit(ipc_mux);
+ return NULL;
+ }
+ /* Extend the UL ADB list. */
+ skb_queue_tail(free_list, skb);
+ }
+
+ return ipc_mux;
+}
+
+/* Informs the network stack to restart transmission for all opened session if
+ * Flow Control is not ON for that session.
+ */
+static void ipc_mux_restart_tx_for_all_sessions(struct iosm_mux *ipc_mux)
+{
+ struct mux_session *session;
+ int idx;
+
+ for (idx = 0; idx < ipc_mux->nr_sessions; idx++) {
+ session = &ipc_mux->session[idx];
+
+ if (!session->wwan)
+ continue;
+
+ /* If flow control of the session is OFF and if there was tx
+ * stop then restart. Inform the network interface to restart
+ * sending data.
+ */
+ if (session->flow_ctl_mask == 0) {
+ session->net_tx_stop = false;
+ ipc_mux_netif_tx_flowctrl(session, idx, false);
+ }
+ }
+}
+
+/* Informs the network stack to stop sending further pkt for all opened
+ * sessions
+ */
+static void ipc_mux_stop_netif_for_all_sessions(struct iosm_mux *ipc_mux)
+{
+ struct mux_session *session;
+ int idx;
+
+ for (idx = 0; idx < ipc_mux->nr_sessions; idx++) {
+ session = &ipc_mux->session[idx];
+
+ if (!session->wwan)
+ continue;
+
+ ipc_mux_netif_tx_flowctrl(session, session->if_id, true);
+ }
+}
+
+void ipc_mux_check_n_restart_tx(struct iosm_mux *ipc_mux)
+{
+ if (ipc_mux->ul_flow == MUX_UL) {
+ int low_thresh = IPC_MEM_MUX_UL_FLOWCTRL_LOW_B;
+
+ if (ipc_mux->ul_data_pend_bytes < low_thresh)
+ ipc_mux_restart_tx_for_all_sessions(ipc_mux);
+ }
+}
+
+int ipc_mux_get_max_sessions(struct iosm_mux *ipc_mux)
+{
+ return ipc_mux ? ipc_mux->nr_sessions : -EFAULT;
+}
+
+enum ipc_mux_protocol ipc_mux_get_active_protocol(struct iosm_mux *ipc_mux)
+{
+ return ipc_mux ? ipc_mux->protocol : MUX_UNKNOWN;
+}
+
+int ipc_mux_open_session(struct iosm_mux *ipc_mux, int session_nr)
+{
+ struct mux_session_open *session_open;
+ union mux_msg mux_msg;
+
+ session_open = &mux_msg.session_open;
+ session_open->event = MUX_E_MUX_SESSION_OPEN;
+
+ session_open->if_id = cpu_to_le32(session_nr);
+ ipc_mux->session[session_nr].flags |= IPC_MEM_WWAN_MUX;
+ return ipc_mux_schedule(ipc_mux, &mux_msg);
+}
+
+int ipc_mux_close_session(struct iosm_mux *ipc_mux, int session_nr)
+{
+ struct mux_session_close *session_close;
+ union mux_msg mux_msg;
+ int ret_val;
+
+ session_close = &mux_msg.session_close;
+ session_close->event = MUX_E_MUX_SESSION_CLOSE;
+
+ session_close->if_id = cpu_to_le32(session_nr);
+ ret_val = ipc_mux_schedule(ipc_mux, &mux_msg);
+ ipc_mux->session[session_nr].flags &= ~IPC_MEM_WWAN_MUX;
+
+ return ret_val;
+}
+
+void ipc_mux_deinit(struct iosm_mux *ipc_mux)
+{
+ struct mux_channel_close *channel_close;
+ struct sk_buff_head *free_list;
+ union mux_msg mux_msg;
+ struct sk_buff *skb;
+
+ if (!ipc_mux->initialized)
+ return;
+ ipc_mux_stop_netif_for_all_sessions(ipc_mux);
+
+ channel_close = &mux_msg.channel_close;
+ channel_close->event = MUX_E_MUX_CHANNEL_CLOSE;
+ ipc_mux_schedule(ipc_mux, &mux_msg);
+
+ /* Empty the ADB free list. */
+ free_list = &ipc_mux->ul_adb.free_list;
+
+ /* Remove from the head of the downlink queue. */
+ while ((skb = skb_dequeue(free_list)))
+ ipc_pcie_kfree_skb(ipc_mux->pcie, skb);
+
+ if (ipc_mux->channel) {
+ ipc_mux->channel->ul_pipe.is_open = false;
+ ipc_mux->channel->dl_pipe.is_open = false;
+ }
+
+ kfree(ipc_mux);
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_mux.h b/drivers/net/wwan/iosm/iosm_ipc_mux.h
new file mode 100644
index 000000000000..ddd2cd0bd911
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_mux.h
@@ -0,0 +1,343 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#ifndef IOSM_IPC_MUX_H
+#define IOSM_IPC_MUX_H
+
+#include "iosm_ipc_protocol.h"
+
+/* Size of the buffer for the IP MUX data buffer. */
+#define IPC_MEM_MAX_DL_MUX_BUF_SIZE (16 * 1024)
+#define IPC_MEM_MAX_UL_ADB_BUF_SIZE IPC_MEM_MAX_DL_MUX_BUF_SIZE
+
+/* Size of the buffer for the IP MUX Lite data buffer. */
+#define IPC_MEM_MAX_DL_MUX_LITE_BUF_SIZE (2 * 1024)
+
+/* TD counts for IP MUX Lite */
+#define IPC_MEM_MAX_TDS_MUX_LITE_UL 800
+#define IPC_MEM_MAX_TDS_MUX_LITE_DL 1200
+
+/* open session request (AP->CP) */
+#define MUX_CMD_OPEN_SESSION 1
+
+/* response to open session request (CP->AP) */
+#define MUX_CMD_OPEN_SESSION_RESP 2
+
+/* close session request (AP->CP) */
+#define MUX_CMD_CLOSE_SESSION 3
+
+/* response to close session request (CP->AP) */
+#define MUX_CMD_CLOSE_SESSION_RESP 4
+
+/* Flow control command with mask of the flow per queue/flow. */
+#define MUX_LITE_CMD_FLOW_CTL 5
+
+/* ACK the flow control command. Shall have the same Transaction ID as the
+ * matching FLOW_CTL command.
+ */
+#define MUX_LITE_CMD_FLOW_CTL_ACK 6
+
+/* Command for report packet indicating link quality metrics. */
+#define MUX_LITE_CMD_LINK_STATUS_REPORT 7
+
+/* Response to a report packet */
+#define MUX_LITE_CMD_LINK_STATUS_REPORT_RESP 8
+
+/* Used to reset a command/response state. */
+#define MUX_CMD_INVALID 255
+
+/* command response : command processed successfully */
+#define MUX_CMD_RESP_SUCCESS 0
+
+/* MUX for route link devices */
+#define IPC_MEM_WWAN_MUX BIT(0)
+
+/* Initiated actions to change the state of the MUX object. */
+enum mux_event {
+ MUX_E_INACTIVE, /* No initiated actions. */
+ MUX_E_MUX_SESSION_OPEN, /* Create the MUX channel and a session. */
+ MUX_E_MUX_SESSION_CLOSE, /* Release a session. */
+ MUX_E_MUX_CHANNEL_CLOSE, /* Release the MUX channel. */
+ MUX_E_NO_ORDERS, /* No MUX order. */
+ MUX_E_NOT_APPLICABLE, /* Defect IP MUX. */
+};
+
+/* MUX session open command. */
+struct mux_session_open {
+ enum mux_event event;
+ __le32 if_id;
+};
+
+/* MUX session close command. */
+struct mux_session_close {
+ enum mux_event event;
+ __le32 if_id;
+};
+
+/* MUX channel close command. */
+struct mux_channel_close {
+ enum mux_event event;
+};
+
+/* Default message type to find out the right message type. */
+struct mux_common {
+ enum mux_event event;
+};
+
+/* List of ops in MUX mode. */
+union mux_msg {
+ struct mux_session_open session_open;
+ struct mux_session_close session_close;
+ struct mux_channel_close channel_close;
+ struct mux_common common;
+};
+
+/* Parameter definition of the open session command. */
+struct mux_cmd_open_session {
+ u8 flow_ctrl; /* 0: Flow control disabled (flow allowed). */
+ /* 1: Flow control enabled (flow not allowed)*/
+ u8 ipv4v6_hints; /* 0: IPv4/IPv6 hints not supported.*/
+ /* 1: IPv4/IPv6 hints supported*/
+ __le16 reserved2; /* Reserved. Set to zero. */
+ __le32 dl_head_pad_len; /* Maximum length supported */
+ /* for DL head padding on a datagram. */
+};
+
+/* Parameter definition of the open session response. */
+struct mux_cmd_open_session_resp {
+ __le32 response; /* Response code */
+ u8 flow_ctrl; /* 0: Flow control disabled (flow allowed). */
+ /* 1: Flow control enabled (flow not allowed) */
+ u8 ipv4v6_hints; /* 0: IPv4/IPv6 hints not supported */
+ /* 1: IPv4/IPv6 hints supported */
+ __le16 reserved2; /* Reserved. Set to zero. */
+ __le32 ul_head_pad_len; /* Actual length supported for */
+ /* UL head padding on adatagram.*/
+};
+
+/* Parameter definition of the close session response code */
+struct mux_cmd_close_session_resp {
+ __le32 response;
+};
+
+/* Parameter definition of the flow control command. */
+struct mux_cmd_flow_ctl {
+ __le32 mask; /* indicating the desired flow control */
+ /* state for various flows/queues */
+};
+
+/* Parameter definition of the link status report code*/
+struct mux_cmd_link_status_report {
+ u8 payload;
+};
+
+/* Parameter definition of the link status report response code. */
+struct mux_cmd_link_status_report_resp {
+ __le32 response;
+};
+
+/**
+ * union mux_cmd_param - Union-definition of the command parameters.
+ * @open_session: Inband command for open session
+ * @open_session_resp: Inband command for open session response
+ * @close_session_resp: Inband command for close session response
+ * @flow_ctl: In-band flow control on the opened interfaces
+ * @link_status: In-band Link Status Report
+ * @link_status_resp: In-band command for link status report response
+ */
+union mux_cmd_param {
+ struct mux_cmd_open_session open_session;
+ struct mux_cmd_open_session_resp open_session_resp;
+ struct mux_cmd_close_session_resp close_session_resp;
+ struct mux_cmd_flow_ctl flow_ctl;
+ struct mux_cmd_link_status_report link_status;
+ struct mux_cmd_link_status_report_resp link_status_resp;
+};
+
+/* States of the MUX object.. */
+enum mux_state {
+ MUX_S_INACTIVE, /* IP MUX is unused. */
+ MUX_S_ACTIVE, /* IP MUX channel is available. */
+ MUX_S_ERROR, /* Defect IP MUX. */
+};
+
+/* Supported MUX protocols. */
+enum ipc_mux_protocol {
+ MUX_UNKNOWN,
+ MUX_LITE,
+};
+
+/* Supported UL data transfer methods. */
+enum ipc_mux_ul_flow {
+ MUX_UL_UNKNOWN,
+ MUX_UL, /* Normal UL data transfer */
+ MUX_UL_ON_CREDITS, /* UL data transfer will be based on credits */
+};
+
+/* List of the MUX session. */
+struct mux_session {
+ struct iosm_wwan *wwan; /*Network i/f used for communication*/
+ int if_id; /* i/f id for session open message.*/
+ u32 flags;
+ u32 ul_head_pad_len; /* Nr of bytes for UL head padding. */
+ u32 dl_head_pad_len; /* Nr of bytes for DL head padding. */
+ struct sk_buff_head ul_list; /* skb entries for an ADT. */
+ u32 flow_ctl_mask; /* UL flow control */
+ u32 flow_ctl_en_cnt; /* Flow control Enable cmd count */
+ u32 flow_ctl_dis_cnt; /* Flow Control Disable cmd count */
+ int ul_flow_credits; /* UL flow credits */
+ u8 net_tx_stop:1,
+ flush:1; /* flush net interface ? */
+};
+
+/* State of a single UL data block. */
+struct mux_adb {
+ struct sk_buff *dest_skb; /* Current UL skb for the data block. */
+ u8 *buf; /* ADB memory. */
+ struct mux_adgh *adgh; /* ADGH pointer */
+ struct sk_buff *qlth_skb; /* QLTH pointer */
+ u32 *next_table_index; /* Pointer to next table index. */
+ struct sk_buff_head free_list; /* List of alloc. ADB for the UL sess.*/
+ int size; /* Size of the ADB memory. */
+ u32 if_cnt; /* Statistic counter */
+ u32 dg_cnt_total;
+ u32 payload_size;
+};
+
+/* Temporary ACB state. */
+struct mux_acb {
+ struct sk_buff *skb; /* Used UL skb. */
+ int if_id; /* Session id. */
+ u32 wanted_response;
+ u32 got_response;
+ u32 cmd;
+ union mux_cmd_param got_param; /* Received command/response parameter */
+};
+
+/**
+ * struct iosm_mux - Structure of the data multiplexing over an IP channel.
+ * @dev: Pointer to device structure
+ * @session: Array of the MUX sessions.
+ * @channel: Reference to the IP MUX channel
+ * @pcie: Pointer to iosm_pcie struct
+ * @imem: Pointer to iosm_imem
+ * @wwan: Poinetr to iosm_wwan
+ * @ipc_protocol: Pointer to iosm_protocol
+ * @channel_id: Channel ID for MUX
+ * @protocol: Type of the MUX protocol
+ * @ul_flow: UL Flow type
+ * @nr_sessions: Number of sessions
+ * @instance_id: Instance ID
+ * @state: States of the MUX object
+ * @event: Initiated actions to change the state of the MUX object
+ * @tx_transaction_id: Transaction id for the ACB command.
+ * @rr_next_session: Next session number for round robin.
+ * @ul_adb: State of the UL ADB/ADGH.
+ * @size_needed: Variable to store the size needed during ADB preparation
+ * @ul_data_pend_bytes: Pending UL data to be processed in bytes
+ * @acb: Temporary ACB state
+ * @wwan_q_offset: This will hold the offset of the given instance
+ * Useful while passing or receiving packets from
+ * wwan/imem layer.
+ * @initialized: MUX object is initialized
+ * @ev_mux_net_transmit_pending:
+ * 0 means inform the IPC tasklet to pass the
+ * accumulated uplink ADB to CP.
+ * @adb_prep_ongoing: Flag for ADB preparation status
+ */
+struct iosm_mux {
+ struct device *dev;
+ struct mux_session session[IPC_MEM_MUX_IP_SESSION_ENTRIES];
+ struct ipc_mem_channel *channel;
+ struct iosm_pcie *pcie;
+ struct iosm_imem *imem;
+ struct iosm_wwan *wwan;
+ struct iosm_protocol *ipc_protocol;
+ int channel_id;
+ enum ipc_mux_protocol protocol;
+ enum ipc_mux_ul_flow ul_flow;
+ int nr_sessions;
+ int instance_id;
+ enum mux_state state;
+ enum mux_event event;
+ u32 tx_transaction_id;
+ int rr_next_session;
+ struct mux_adb ul_adb;
+ int size_needed;
+ long long ul_data_pend_bytes;
+ struct mux_acb acb;
+ int wwan_q_offset;
+ u8 initialized:1,
+ ev_mux_net_transmit_pending:1,
+ adb_prep_ongoing:1;
+};
+
+/* MUX configuration structure */
+struct ipc_mux_config {
+ enum ipc_mux_protocol protocol;
+ enum ipc_mux_ul_flow ul_flow;
+ int nr_sessions;
+ int instance_id;
+};
+
+/**
+ * ipc_mux_init - Allocates and Init MUX instance
+ * @mux_cfg: Pointer to MUX configuration structure
+ * @ipc_imem: Pointer to imem data-struct
+ *
+ * Returns: Initialized mux pointer on success else NULL
+ */
+struct iosm_mux *ipc_mux_init(struct ipc_mux_config *mux_cfg,
+ struct iosm_imem *ipc_imem);
+
+/**
+ * ipc_mux_deinit - Deallocates MUX instance
+ * @ipc_mux: Pointer to the MUX instance.
+ */
+void ipc_mux_deinit(struct iosm_mux *ipc_mux);
+
+/**
+ * ipc_mux_check_n_restart_tx - Checks for pending UL date bytes and then
+ * it restarts the net interface tx queue if
+ * device has set flow control as off.
+ * @ipc_mux: Pointer to MUX data-struct
+ */
+void ipc_mux_check_n_restart_tx(struct iosm_mux *ipc_mux);
+
+/**
+ * ipc_mux_get_active_protocol - Returns the active MUX protocol type.
+ * @ipc_mux: Pointer to MUX data-struct
+ *
+ * Returns: enum of type ipc_mux_protocol
+ */
+enum ipc_mux_protocol ipc_mux_get_active_protocol(struct iosm_mux *ipc_mux);
+
+/**
+ * ipc_mux_open_session - Opens a MUX session for IP traffic.
+ * @ipc_mux: Pointer to MUX data-struct
+ * @session_nr: Interface ID or session number
+ *
+ * Returns: channel id on success, failure value on error
+ */
+int ipc_mux_open_session(struct iosm_mux *ipc_mux, int session_nr);
+
+/**
+ * ipc_mux_close_session - Closes a MUX session.
+ * @ipc_mux: Pointer to MUX data-struct
+ * @session_nr: Interface ID or session number
+ *
+ * Returns: channel id on success, failure value on error
+ */
+int ipc_mux_close_session(struct iosm_mux *ipc_mux, int session_nr);
+
+/**
+ * ipc_mux_get_max_sessions - Retuns the maximum sessions supported on the
+ * provided MUX instance..
+ * @ipc_mux: Pointer to MUX data-struct
+ *
+ * Returns: Number of sessions supported on Success and failure value on error
+ */
+int ipc_mux_get_max_sessions(struct iosm_mux *ipc_mux);
+#endif
diff --git a/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c b/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c
new file mode 100644
index 000000000000..562de275797a
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c
@@ -0,0 +1,910 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include <linux/nospec.h>
+
+#include "iosm_ipc_imem_ops.h"
+#include "iosm_ipc_mux_codec.h"
+#include "iosm_ipc_task_queue.h"
+
+/* Test the link power state and send a MUX command in blocking mode. */
+static int ipc_mux_tq_cmd_send(struct iosm_imem *ipc_imem, int arg, void *msg,
+ size_t size)
+{
+ struct iosm_mux *ipc_mux = ipc_imem->mux;
+ const struct mux_acb *acb = msg;
+
+ skb_queue_tail(&ipc_mux->channel->ul_list, acb->skb);
+ ipc_imem_ul_send(ipc_mux->imem);
+
+ return 0;
+}
+
+static int ipc_mux_acb_send(struct iosm_mux *ipc_mux, bool blocking)
+{
+ struct completion *completion = &ipc_mux->channel->ul_sem;
+ int ret = ipc_task_queue_send_task(ipc_mux->imem, ipc_mux_tq_cmd_send,
+ 0, &ipc_mux->acb,
+ sizeof(ipc_mux->acb), false);
+ if (ret) {
+ dev_err(ipc_mux->dev, "unable to send mux command");
+ return ret;
+ }
+
+ /* if blocking, suspend the app and wait for irq in the flash or
+ * crash phase. return false on timeout to indicate failure.
+ */
+ if (blocking) {
+ u32 wait_time_milliseconds = IPC_MUX_CMD_RUN_DEFAULT_TIMEOUT;
+
+ reinit_completion(completion);
+
+ if (wait_for_completion_interruptible_timeout
+ (completion, msecs_to_jiffies(wait_time_milliseconds)) ==
+ 0) {
+ dev_err(ipc_mux->dev, "ch[%d] timeout",
+ ipc_mux->channel_id);
+ ipc_uevent_send(ipc_mux->imem->dev, UEVENT_MDM_TIMEOUT);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+/* Prepare mux Command */
+static struct mux_lite_cmdh *ipc_mux_lite_add_cmd(struct iosm_mux *ipc_mux,
+ u32 cmd, struct mux_acb *acb,
+ void *param, u32 param_size)
+{
+ struct mux_lite_cmdh *cmdh = (struct mux_lite_cmdh *)acb->skb->data;
+
+ cmdh->signature = cpu_to_le32(MUX_SIG_CMDH);
+ cmdh->command_type = cpu_to_le32(cmd);
+ cmdh->if_id = acb->if_id;
+
+ acb->cmd = cmd;
+
+ cmdh->cmd_len = cpu_to_le16(offsetof(struct mux_lite_cmdh, param) +
+ param_size);
+ cmdh->transaction_id = cpu_to_le32(ipc_mux->tx_transaction_id++);
+
+ if (param)
+ memcpy(&cmdh->param, param, param_size);
+
+ skb_put(acb->skb, le16_to_cpu(cmdh->cmd_len));
+
+ return cmdh;
+}
+
+static int ipc_mux_acb_alloc(struct iosm_mux *ipc_mux)
+{
+ struct mux_acb *acb = &ipc_mux->acb;
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+
+ /* Allocate skb memory for the uplink buffer. */
+ skb = ipc_pcie_alloc_skb(ipc_mux->pcie, MUX_MAX_UL_ACB_BUF_SIZE,
+ GFP_ATOMIC, &mapping, DMA_TO_DEVICE, 0);
+ if (!skb)
+ return -ENOMEM;
+
+ /* Save the skb address. */
+ acb->skb = skb;
+
+ memset(skb->data, 0, MUX_MAX_UL_ACB_BUF_SIZE);
+
+ return 0;
+}
+
+int ipc_mux_dl_acb_send_cmds(struct iosm_mux *ipc_mux, u32 cmd_type, u8 if_id,
+ u32 transaction_id, union mux_cmd_param *param,
+ size_t res_size, bool blocking, bool respond)
+{
+ struct mux_acb *acb = &ipc_mux->acb;
+ struct mux_lite_cmdh *ack_lite;
+ int ret = 0;
+
+ acb->if_id = if_id;
+ ret = ipc_mux_acb_alloc(ipc_mux);
+ if (ret)
+ return ret;
+
+ ack_lite = ipc_mux_lite_add_cmd(ipc_mux, cmd_type, acb, param,
+ res_size);
+ if (respond)
+ ack_lite->transaction_id = cpu_to_le32(transaction_id);
+
+ ret = ipc_mux_acb_send(ipc_mux, blocking);
+
+ return ret;
+}
+
+void ipc_mux_netif_tx_flowctrl(struct mux_session *session, int idx, bool on)
+{
+ /* Inform the network interface to start/stop flow ctrl */
+ ipc_wwan_tx_flowctrl(session->wwan, idx, on);
+}
+
+static int ipc_mux_dl_cmdresps_decode_process(struct iosm_mux *ipc_mux,
+ struct mux_lite_cmdh *cmdh)
+{
+ struct mux_acb *acb = &ipc_mux->acb;
+
+ switch (le32_to_cpu(cmdh->command_type)) {
+ case MUX_CMD_OPEN_SESSION_RESP:
+ case MUX_CMD_CLOSE_SESSION_RESP:
+ /* Resume the control application. */
+ acb->got_param = cmdh->param;
+ break;
+
+ case MUX_LITE_CMD_FLOW_CTL_ACK:
+ /* This command type is not expected as response for
+ * Aggregation version of the protocol. So return non-zero.
+ */
+ if (ipc_mux->protocol != MUX_LITE)
+ return -EINVAL;
+
+ dev_dbg(ipc_mux->dev, "if %u FLOW_CTL_ACK %u received",
+ cmdh->if_id, le32_to_cpu(cmdh->transaction_id));
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ acb->wanted_response = MUX_CMD_INVALID;
+ acb->got_response = le32_to_cpu(cmdh->command_type);
+ complete(&ipc_mux->channel->ul_sem);
+
+ return 0;
+}
+
+static int ipc_mux_dl_dlcmds_decode_process(struct iosm_mux *ipc_mux,
+ struct mux_lite_cmdh *cmdh)
+{
+ union mux_cmd_param *param = &cmdh->param;
+ struct mux_session *session;
+ int new_size;
+
+ dev_dbg(ipc_mux->dev, "if_id[%d]: dlcmds decode process %d",
+ cmdh->if_id, le32_to_cpu(cmdh->command_type));
+
+ switch (le32_to_cpu(cmdh->command_type)) {
+ case MUX_LITE_CMD_FLOW_CTL:
+
+ if (cmdh->if_id >= ipc_mux->nr_sessions) {
+ dev_err(ipc_mux->dev, "if_id [%d] not valid",
+ cmdh->if_id);
+ return -EINVAL; /* No session interface id. */
+ }
+
+ session = &ipc_mux->session[cmdh->if_id];
+
+ new_size = offsetof(struct mux_lite_cmdh, param) +
+ sizeof(param->flow_ctl);
+ if (param->flow_ctl.mask == cpu_to_le32(0xFFFFFFFF)) {
+ /* Backward Compatibility */
+ if (cmdh->cmd_len == cpu_to_le16(new_size))
+ session->flow_ctl_mask =
+ le32_to_cpu(param->flow_ctl.mask);
+ else
+ session->flow_ctl_mask = ~0;
+ /* if CP asks for FLOW CTRL Enable
+ * then set our internal flow control Tx flag
+ * to limit uplink session queueing
+ */
+ session->net_tx_stop = true;
+ /* Update the stats */
+ session->flow_ctl_en_cnt++;
+ } else if (param->flow_ctl.mask == 0) {
+ /* Just reset the Flow control mask and let
+ * mux_flow_ctrl_low_thre_b take control on
+ * our internal Tx flag and enabling kernel
+ * flow control
+ */
+ /* Backward Compatibility */
+ if (cmdh->cmd_len == cpu_to_le16(new_size))
+ session->flow_ctl_mask =
+ le32_to_cpu(param->flow_ctl.mask);
+ else
+ session->flow_ctl_mask = 0;
+ /* Update the stats */
+ session->flow_ctl_dis_cnt++;
+ } else {
+ break;
+ }
+
+ dev_dbg(ipc_mux->dev, "if[%u] FLOW CTRL 0x%08X", cmdh->if_id,
+ le32_to_cpu(param->flow_ctl.mask));
+ break;
+
+ case MUX_LITE_CMD_LINK_STATUS_REPORT:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Decode and Send appropriate response to a command block. */
+static void ipc_mux_dl_cmd_decode(struct iosm_mux *ipc_mux, struct sk_buff *skb)
+{
+ struct mux_lite_cmdh *cmdh = (struct mux_lite_cmdh *)skb->data;
+ __le32 trans_id = cmdh->transaction_id;
+
+ if (ipc_mux_dl_cmdresps_decode_process(ipc_mux, cmdh)) {
+ /* Unable to decode command response indicates the cmd_type
+ * may be a command instead of response. So try to decoding it.
+ */
+ if (!ipc_mux_dl_dlcmds_decode_process(ipc_mux, cmdh)) {
+ /* Decoded command may need a response. Give the
+ * response according to the command type.
+ */
+ union mux_cmd_param *mux_cmd = NULL;
+ size_t size = 0;
+ u32 cmd = MUX_LITE_CMD_LINK_STATUS_REPORT_RESP;
+
+ if (cmdh->command_type ==
+ cpu_to_le32(MUX_LITE_CMD_LINK_STATUS_REPORT)) {
+ mux_cmd = &cmdh->param;
+ mux_cmd->link_status_resp.response =
+ cpu_to_le32(MUX_CMD_RESP_SUCCESS);
+ /* response field is u32 */
+ size = sizeof(u32);
+ } else if (cmdh->command_type ==
+ cpu_to_le32(MUX_LITE_CMD_FLOW_CTL)) {
+ cmd = MUX_LITE_CMD_FLOW_CTL_ACK;
+ } else {
+ return;
+ }
+
+ if (ipc_mux_dl_acb_send_cmds(ipc_mux, cmd, cmdh->if_id,
+ le32_to_cpu(trans_id),
+ mux_cmd, size, false,
+ true))
+ dev_err(ipc_mux->dev,
+ "if_id %d: cmd send failed",
+ cmdh->if_id);
+ }
+ }
+}
+
+/* Pass the DL packet to the netif layer. */
+static int ipc_mux_net_receive(struct iosm_mux *ipc_mux, int if_id,
+ struct iosm_wwan *wwan, u32 offset,
+ u8 service_class, struct sk_buff *skb)
+{
+ struct sk_buff *dest_skb = skb_clone(skb, GFP_ATOMIC);
+
+ if (!dest_skb)
+ return -ENOMEM;
+
+ skb_pull(dest_skb, offset);
+ skb_set_tail_pointer(dest_skb, dest_skb->len);
+ /* Pass the packet to the netif layer. */
+ dest_skb->priority = service_class;
+
+ return ipc_wwan_receive(wwan, dest_skb, false, if_id);
+}
+
+/* Decode Flow Credit Table in the block */
+static void ipc_mux_dl_fcth_decode(struct iosm_mux *ipc_mux,
+ unsigned char *block)
+{
+ struct ipc_mem_lite_gen_tbl *fct = (struct ipc_mem_lite_gen_tbl *)block;
+ struct iosm_wwan *wwan;
+ int ul_credits;
+ int if_id;
+
+ if (fct->vfl_length != sizeof(fct->vfl.nr_of_bytes)) {
+ dev_err(ipc_mux->dev, "unexpected FCT length: %d",
+ fct->vfl_length);
+ return;
+ }
+
+ if_id = fct->if_id;
+ if (if_id >= ipc_mux->nr_sessions) {
+ dev_err(ipc_mux->dev, "not supported if_id: %d", if_id);
+ return;
+ }
+
+ /* Is the session active ? */
+ if_id = array_index_nospec(if_id, ipc_mux->nr_sessions);
+ wwan = ipc_mux->session[if_id].wwan;
+ if (!wwan) {
+ dev_err(ipc_mux->dev, "session Net ID is NULL");
+ return;
+ }
+
+ ul_credits = fct->vfl.nr_of_bytes;
+
+ dev_dbg(ipc_mux->dev, "Flow_Credit:: if_id[%d] Old: %d Grants: %d",
+ if_id, ipc_mux->session[if_id].ul_flow_credits, ul_credits);
+
+ /* Update the Flow Credit information from ADB */
+ ipc_mux->session[if_id].ul_flow_credits += ul_credits;
+
+ /* Check whether the TX can be started */
+ if (ipc_mux->session[if_id].ul_flow_credits > 0) {
+ ipc_mux->session[if_id].net_tx_stop = false;
+ ipc_mux_netif_tx_flowctrl(&ipc_mux->session[if_id],
+ ipc_mux->session[if_id].if_id, false);
+ }
+}
+
+/* Decode non-aggregated datagram */
+static void ipc_mux_dl_adgh_decode(struct iosm_mux *ipc_mux,
+ struct sk_buff *skb)
+{
+ u32 pad_len, packet_offset;
+ struct iosm_wwan *wwan;
+ struct mux_adgh *adgh;
+ u8 *block = skb->data;
+ int rc = 0;
+ u8 if_id;
+
+ adgh = (struct mux_adgh *)block;
+
+ if (adgh->signature != cpu_to_le32(MUX_SIG_ADGH)) {
+ dev_err(ipc_mux->dev, "invalid ADGH signature received");
+ return;
+ }
+
+ if_id = adgh->if_id;
+ if (if_id >= ipc_mux->nr_sessions) {
+ dev_err(ipc_mux->dev, "invalid if_id while decoding %d", if_id);
+ return;
+ }
+
+ /* Is the session active ? */
+ if_id = array_index_nospec(if_id, ipc_mux->nr_sessions);
+ wwan = ipc_mux->session[if_id].wwan;
+ if (!wwan) {
+ dev_err(ipc_mux->dev, "session Net ID is NULL");
+ return;
+ }
+
+ /* Store the pad len for the corresponding session
+ * Pad bytes as negotiated in the open session less the header size
+ * (see session management chapter for details).
+ * If resulting padding is zero or less, the additional head padding is
+ * omitted. For e.g., if HEAD_PAD_LEN = 16 or less, this field is
+ * omitted if HEAD_PAD_LEN = 20, then this field will have 4 bytes
+ * set to zero
+ */
+ pad_len =
+ ipc_mux->session[if_id].dl_head_pad_len - IPC_MEM_DL_ETH_OFFSET;
+ packet_offset = sizeof(*adgh) + pad_len;
+
+ if_id += ipc_mux->wwan_q_offset;
+
+ /* Pass the packet to the netif layer */
+ rc = ipc_mux_net_receive(ipc_mux, if_id, wwan, packet_offset,
+ adgh->service_class, skb);
+ if (rc) {
+ dev_err(ipc_mux->dev, "mux adgh decoding error");
+ return;
+ }
+ ipc_mux->session[if_id].flush = 1;
+}
+
+void ipc_mux_dl_decode(struct iosm_mux *ipc_mux, struct sk_buff *skb)
+{
+ u32 signature;
+
+ if (!skb->data)
+ return;
+
+ /* Decode the MUX header type. */
+ signature = le32_to_cpup((__le32 *)skb->data);
+
+ switch (signature) {
+ case MUX_SIG_ADGH:
+ ipc_mux_dl_adgh_decode(ipc_mux, skb);
+ break;
+
+ case MUX_SIG_FCTH:
+ ipc_mux_dl_fcth_decode(ipc_mux, skb->data);
+ break;
+
+ case MUX_SIG_CMDH:
+ ipc_mux_dl_cmd_decode(ipc_mux, skb);
+ break;
+
+ default:
+ dev_err(ipc_mux->dev, "invalid ABH signature");
+ }
+
+ ipc_pcie_kfree_skb(ipc_mux->pcie, skb);
+}
+
+static int ipc_mux_ul_skb_alloc(struct iosm_mux *ipc_mux,
+ struct mux_adb *ul_adb, u32 type)
+{
+ /* Take the first element of the free list. */
+ struct sk_buff *skb = skb_dequeue(&ul_adb->free_list);
+ int qlt_size;
+
+ if (!skb)
+ return -EBUSY; /* Wait for a free ADB skb. */
+
+ /* Mark it as UL ADB to select the right free operation. */
+ IPC_CB(skb)->op_type = (u8)UL_MUX_OP_ADB;
+
+ switch (type) {
+ case MUX_SIG_ADGH:
+ /* Save the ADB memory settings. */
+ ul_adb->dest_skb = skb;
+ ul_adb->buf = skb->data;
+ ul_adb->size = IPC_MEM_MAX_DL_MUX_LITE_BUF_SIZE;
+ /* reset statistic counter */
+ ul_adb->if_cnt = 0;
+ ul_adb->payload_size = 0;
+ ul_adb->dg_cnt_total = 0;
+
+ ul_adb->adgh = (struct mux_adgh *)skb->data;
+ memset(ul_adb->adgh, 0, sizeof(struct mux_adgh));
+ break;
+
+ case MUX_SIG_QLTH:
+ qlt_size = offsetof(struct ipc_mem_lite_gen_tbl, vfl) +
+ (MUX_QUEUE_LEVEL * sizeof(struct mux_lite_vfl));
+
+ if (qlt_size > IPC_MEM_MAX_DL_MUX_LITE_BUF_SIZE) {
+ dev_err(ipc_mux->dev,
+ "can't support. QLT size:%d SKB size: %d",
+ qlt_size, IPC_MEM_MAX_DL_MUX_LITE_BUF_SIZE);
+ return -ERANGE;
+ }
+
+ ul_adb->qlth_skb = skb;
+ memset((ul_adb->qlth_skb)->data, 0, qlt_size);
+ skb_put(skb, qlt_size);
+ break;
+ }
+
+ return 0;
+}
+
+static void ipc_mux_ul_adgh_finish(struct iosm_mux *ipc_mux)
+{
+ struct mux_adb *ul_adb = &ipc_mux->ul_adb;
+ u16 adgh_len;
+ long long bytes;
+ char *str;
+
+ if (!ul_adb->dest_skb) {
+ dev_err(ipc_mux->dev, "no dest skb");
+ return;
+ }
+
+ adgh_len = le16_to_cpu(ul_adb->adgh->length);
+ skb_put(ul_adb->dest_skb, adgh_len);
+ skb_queue_tail(&ipc_mux->channel->ul_list, ul_adb->dest_skb);
+ ul_adb->dest_skb = NULL;
+
+ if (ipc_mux->ul_flow == MUX_UL_ON_CREDITS) {
+ struct mux_session *session;
+
+ session = &ipc_mux->session[ul_adb->adgh->if_id];
+ str = "available_credits";
+ bytes = (long long)session->ul_flow_credits;
+
+ } else {
+ str = "pend_bytes";
+ bytes = ipc_mux->ul_data_pend_bytes;
+ ipc_mux->ul_data_pend_bytes = ipc_mux->ul_data_pend_bytes +
+ adgh_len;
+ }
+
+ dev_dbg(ipc_mux->dev, "UL ADGH: size=%u, if_id=%d, payload=%d, %s=%lld",
+ adgh_len, ul_adb->adgh->if_id, ul_adb->payload_size,
+ str, bytes);
+}
+
+/* Allocates an ADB from the free list and initializes it with ADBH */
+static bool ipc_mux_ul_adb_allocate(struct iosm_mux *ipc_mux,
+ struct mux_adb *adb, int *size_needed,
+ u32 type)
+{
+ bool ret_val = false;
+ int status;
+
+ if (!adb->dest_skb) {
+ /* Allocate memory for the ADB including of the
+ * datagram table header.
+ */
+ status = ipc_mux_ul_skb_alloc(ipc_mux, adb, type);
+ if (status)
+ /* Is a pending ADB available ? */
+ ret_val = true; /* None. */
+
+ /* Update size need to zero only for new ADB memory */
+ *size_needed = 0;
+ }
+
+ return ret_val;
+}
+
+/* Informs the network stack to stop sending further packets for all opened
+ * sessions
+ */
+static void ipc_mux_stop_tx_for_all_sessions(struct iosm_mux *ipc_mux)
+{
+ struct mux_session *session;
+ int idx;
+
+ for (idx = 0; idx < ipc_mux->nr_sessions; idx++) {
+ session = &ipc_mux->session[idx];
+
+ if (!session->wwan)
+ continue;
+
+ session->net_tx_stop = true;
+ }
+}
+
+/* Sends Queue Level Table of all opened sessions */
+static bool ipc_mux_lite_send_qlt(struct iosm_mux *ipc_mux)
+{
+ struct ipc_mem_lite_gen_tbl *qlt;
+ struct mux_session *session;
+ bool qlt_updated = false;
+ int i;
+ int qlt_size;
+
+ if (!ipc_mux->initialized || ipc_mux->state != MUX_S_ACTIVE)
+ return qlt_updated;
+
+ qlt_size = offsetof(struct ipc_mem_lite_gen_tbl, vfl) +
+ MUX_QUEUE_LEVEL * sizeof(struct mux_lite_vfl);
+
+ for (i = 0; i < ipc_mux->nr_sessions; i++) {
+ session = &ipc_mux->session[i];
+
+ if (!session->wwan || session->flow_ctl_mask)
+ continue;
+
+ if (ipc_mux_ul_skb_alloc(ipc_mux, &ipc_mux->ul_adb,
+ MUX_SIG_QLTH)) {
+ dev_err(ipc_mux->dev,
+ "no reserved mem to send QLT of if_id: %d", i);
+ break;
+ }
+
+ /* Prepare QLT */
+ qlt = (struct ipc_mem_lite_gen_tbl *)(ipc_mux->ul_adb.qlth_skb)
+ ->data;
+ qlt->signature = cpu_to_le32(MUX_SIG_QLTH);
+ qlt->length = cpu_to_le16(qlt_size);
+ qlt->if_id = i;
+ qlt->vfl_length = MUX_QUEUE_LEVEL * sizeof(struct mux_lite_vfl);
+ qlt->reserved[0] = 0;
+ qlt->reserved[1] = 0;
+
+ qlt->vfl.nr_of_bytes = session->ul_list.qlen;
+
+ /* Add QLT to the transfer list. */
+ skb_queue_tail(&ipc_mux->channel->ul_list,
+ ipc_mux->ul_adb.qlth_skb);
+
+ qlt_updated = true;
+ ipc_mux->ul_adb.qlth_skb = NULL;
+ }
+
+ if (qlt_updated)
+ /* Updates the TDs with ul_list */
+ (void)ipc_imem_ul_write_td(ipc_mux->imem);
+
+ return qlt_updated;
+}
+
+/* Checks the available credits for the specified session and returns
+ * number of packets for which credits are available.
+ */
+static int ipc_mux_ul_bytes_credits_check(struct iosm_mux *ipc_mux,
+ struct mux_session *session,
+ struct sk_buff_head *ul_list,
+ int max_nr_of_pkts)
+{
+ int pkts_to_send = 0;
+ struct sk_buff *skb;
+ int credits = 0;
+
+ if (ipc_mux->ul_flow == MUX_UL_ON_CREDITS) {
+ credits = session->ul_flow_credits;
+ if (credits <= 0) {
+ dev_dbg(ipc_mux->dev,
+ "FC::if_id[%d] Insuff.Credits/Qlen:%d/%u",
+ session->if_id, session->ul_flow_credits,
+ session->ul_list.qlen); /* nr_of_bytes */
+ return 0;
+ }
+ } else {
+ credits = IPC_MEM_MUX_UL_FLOWCTRL_HIGH_B -
+ ipc_mux->ul_data_pend_bytes;
+ if (credits <= 0) {
+ ipc_mux_stop_tx_for_all_sessions(ipc_mux);
+
+ dev_dbg(ipc_mux->dev,
+ "if_id[%d] encod. fail Bytes: %llu, thresh: %d",
+ session->if_id, ipc_mux->ul_data_pend_bytes,
+ IPC_MEM_MUX_UL_FLOWCTRL_HIGH_B);
+ return 0;
+ }
+ }
+
+ /* Check if there are enough credits/bytes available to send the
+ * requested max_nr_of_pkts. Otherwise restrict the nr_of_pkts
+ * depending on available credits.
+ */
+ skb_queue_walk(ul_list, skb)
+ {
+ if (!(credits >= skb->len && pkts_to_send < max_nr_of_pkts))
+ break;
+ credits -= skb->len;
+ pkts_to_send++;
+ }
+
+ return pkts_to_send;
+}
+
+/* Encode the UL IP packet according to Lite spec. */
+static int ipc_mux_ul_adgh_encode(struct iosm_mux *ipc_mux, int session_id,
+ struct mux_session *session,
+ struct sk_buff_head *ul_list,
+ struct mux_adb *adb, int nr_of_pkts)
+{
+ int offset = sizeof(struct mux_adgh);
+ int adb_updated = -EINVAL;
+ struct sk_buff *src_skb;
+ int aligned_size = 0;
+ int nr_of_skb = 0;
+ u32 pad_len = 0;
+
+ /* Re-calculate the number of packets depending on number of bytes to be
+ * processed/available credits.
+ */
+ nr_of_pkts = ipc_mux_ul_bytes_credits_check(ipc_mux, session, ul_list,
+ nr_of_pkts);
+
+ /* If calculated nr_of_pkts from available credits is <= 0
+ * then nothing to do.
+ */
+ if (nr_of_pkts <= 0)
+ return 0;
+
+ /* Read configured UL head_pad_length for session.*/
+ if (session->ul_head_pad_len > IPC_MEM_DL_ETH_OFFSET)
+ pad_len = session->ul_head_pad_len - IPC_MEM_DL_ETH_OFFSET;
+
+ /* Process all pending UL packets for this session
+ * depending on the allocated datagram table size.
+ */
+ while (nr_of_pkts > 0) {
+ /* get destination skb allocated */
+ if (ipc_mux_ul_adb_allocate(ipc_mux, adb, &ipc_mux->size_needed,
+ MUX_SIG_ADGH)) {
+ dev_err(ipc_mux->dev, "no reserved memory for ADGH");
+ return -ENOMEM;
+ }
+
+ /* Peek at the head of the list. */
+ src_skb = skb_peek(ul_list);
+ if (!src_skb) {
+ dev_err(ipc_mux->dev,
+ "skb peek return NULL with count : %d",
+ nr_of_pkts);
+ break;
+ }
+
+ /* Calculate the memory value. */
+ aligned_size = ALIGN((pad_len + src_skb->len), 4);
+
+ ipc_mux->size_needed = sizeof(struct mux_adgh) + aligned_size;
+
+ if (ipc_mux->size_needed > adb->size) {
+ dev_dbg(ipc_mux->dev, "size needed %d, adgh size %d",
+ ipc_mux->size_needed, adb->size);
+ /* Return 1 if any IP packet is added to the transfer
+ * list.
+ */
+ return nr_of_skb ? 1 : 0;
+ }
+
+ /* Add buffer (without head padding to next pending transfer) */
+ memcpy(adb->buf + offset + pad_len, src_skb->data,
+ src_skb->len);
+
+ adb->adgh->signature = cpu_to_le32(MUX_SIG_ADGH);
+ adb->adgh->if_id = session_id;
+ adb->adgh->length =
+ cpu_to_le16(sizeof(struct mux_adgh) + pad_len +
+ src_skb->len);
+ adb->adgh->service_class = src_skb->priority;
+ adb->adgh->next_count = --nr_of_pkts;
+ adb->dg_cnt_total++;
+ adb->payload_size += src_skb->len;
+
+ if (ipc_mux->ul_flow == MUX_UL_ON_CREDITS)
+ /* Decrement the credit value as we are processing the
+ * datagram from the UL list.
+ */
+ session->ul_flow_credits -= src_skb->len;
+
+ /* Remove the processed elements and free it. */
+ src_skb = skb_dequeue(ul_list);
+ dev_kfree_skb(src_skb);
+ nr_of_skb++;
+
+ ipc_mux_ul_adgh_finish(ipc_mux);
+ }
+
+ if (nr_of_skb) {
+ /* Send QLT info to modem if pending bytes > high watermark
+ * in case of mux lite
+ */
+ if (ipc_mux->ul_flow == MUX_UL_ON_CREDITS ||
+ ipc_mux->ul_data_pend_bytes >=
+ IPC_MEM_MUX_UL_FLOWCTRL_LOW_B)
+ adb_updated = ipc_mux_lite_send_qlt(ipc_mux);
+ else
+ adb_updated = 1;
+
+ /* Updates the TDs with ul_list */
+ (void)ipc_imem_ul_write_td(ipc_mux->imem);
+ }
+
+ return adb_updated;
+}
+
+bool ipc_mux_ul_data_encode(struct iosm_mux *ipc_mux)
+{
+ struct sk_buff_head *ul_list;
+ struct mux_session *session;
+ int updated = 0;
+ int session_id;
+ int dg_n;
+ int i;
+
+ if (!ipc_mux || ipc_mux->state != MUX_S_ACTIVE ||
+ ipc_mux->adb_prep_ongoing)
+ return false;
+
+ ipc_mux->adb_prep_ongoing = true;
+
+ for (i = 0; i < ipc_mux->nr_sessions; i++) {
+ session_id = ipc_mux->rr_next_session;
+ session = &ipc_mux->session[session_id];
+
+ /* Go to next handle rr_next_session overflow */
+ ipc_mux->rr_next_session++;
+ if (ipc_mux->rr_next_session >= ipc_mux->nr_sessions)
+ ipc_mux->rr_next_session = 0;
+
+ if (!session->wwan || session->flow_ctl_mask ||
+ session->net_tx_stop)
+ continue;
+
+ ul_list = &session->ul_list;
+
+ /* Is something pending in UL and flow ctrl off */
+ dg_n = skb_queue_len(ul_list);
+ if (dg_n > MUX_MAX_UL_DG_ENTRIES)
+ dg_n = MUX_MAX_UL_DG_ENTRIES;
+
+ if (dg_n == 0)
+ /* Nothing to do for ipc_mux session
+ * -> try next session id.
+ */
+ continue;
+
+ updated = ipc_mux_ul_adgh_encode(ipc_mux, session_id, session,
+ ul_list, &ipc_mux->ul_adb,
+ dg_n);
+ }
+
+ ipc_mux->adb_prep_ongoing = false;
+ return updated == 1;
+}
+
+void ipc_mux_ul_encoded_process(struct iosm_mux *ipc_mux, struct sk_buff *skb)
+{
+ struct mux_adgh *adgh;
+ u16 adgh_len;
+
+ adgh = (struct mux_adgh *)skb->data;
+ adgh_len = le16_to_cpu(adgh->length);
+
+ if (adgh->signature == cpu_to_le32(MUX_SIG_ADGH) &&
+ ipc_mux->ul_flow == MUX_UL)
+ ipc_mux->ul_data_pend_bytes = ipc_mux->ul_data_pend_bytes -
+ adgh_len;
+
+ if (ipc_mux->ul_flow == MUX_UL)
+ dev_dbg(ipc_mux->dev, "ul_data_pend_bytes: %lld",
+ ipc_mux->ul_data_pend_bytes);
+
+ /* Reset the skb settings. */
+ skb->tail = 0;
+ skb->len = 0;
+
+ /* Add the consumed ADB to the free list. */
+ skb_queue_tail((&ipc_mux->ul_adb.free_list), skb);
+}
+
+/* Start the NETIF uplink send transfer in MUX mode. */
+static int ipc_mux_tq_ul_trigger_encode(struct iosm_imem *ipc_imem, int arg,
+ void *msg, size_t size)
+{
+ struct iosm_mux *ipc_mux = ipc_imem->mux;
+ bool ul_data_pend = false;
+
+ /* Add session UL data to a ADB and ADGH */
+ ul_data_pend = ipc_mux_ul_data_encode(ipc_mux);
+ if (ul_data_pend)
+ /* Delay the doorbell irq */
+ ipc_imem_td_update_timer_start(ipc_mux->imem);
+
+ /* reset the debounce flag */
+ ipc_mux->ev_mux_net_transmit_pending = false;
+
+ return 0;
+}
+
+int ipc_mux_ul_trigger_encode(struct iosm_mux *ipc_mux, int if_id,
+ struct sk_buff *skb)
+{
+ struct mux_session *session = &ipc_mux->session[if_id];
+ int ret = -EINVAL;
+
+ if (ipc_mux->channel &&
+ ipc_mux->channel->state != IMEM_CHANNEL_ACTIVE) {
+ dev_err(ipc_mux->dev,
+ "channel state is not IMEM_CHANNEL_ACTIVE");
+ goto out;
+ }
+
+ if (!session->wwan) {
+ dev_err(ipc_mux->dev, "session net ID is NULL");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ /* Session is under flow control.
+ * Check if packet can be queued in session list, if not
+ * suspend net tx
+ */
+ if (skb_queue_len(&session->ul_list) >=
+ (session->net_tx_stop ?
+ IPC_MEM_MUX_UL_SESS_FCON_THRESHOLD :
+ (IPC_MEM_MUX_UL_SESS_FCON_THRESHOLD *
+ IPC_MEM_MUX_UL_SESS_FCOFF_THRESHOLD_FACTOR))) {
+ ipc_mux_netif_tx_flowctrl(session, session->if_id, true);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* Add skb to the uplink skb accumulator. */
+ skb_queue_tail(&session->ul_list, skb);
+
+ /* Inform the IPC kthread to pass uplink IP packets to CP. */
+ if (!ipc_mux->ev_mux_net_transmit_pending) {
+ ipc_mux->ev_mux_net_transmit_pending = true;
+ ret = ipc_task_queue_send_task(ipc_mux->imem,
+ ipc_mux_tq_ul_trigger_encode, 0,
+ NULL, 0, false);
+ if (ret)
+ goto out;
+ }
+ dev_dbg(ipc_mux->dev, "mux ul if[%d] qlen=%d/%u, len=%d/%d, prio=%d",
+ if_id, skb_queue_len(&session->ul_list), session->ul_list.qlen,
+ skb->len, skb->truesize, skb->priority);
+ ret = 0;
+out:
+ return ret;
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_mux_codec.h b/drivers/net/wwan/iosm/iosm_ipc_mux_codec.h
new file mode 100644
index 000000000000..4a74e3c9457f
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_mux_codec.h
@@ -0,0 +1,193 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#ifndef IOSM_IPC_MUX_CODEC_H
+#define IOSM_IPC_MUX_CODEC_H
+
+#include "iosm_ipc_mux.h"
+
+/* Queue level size and reporting
+ * >1 is enable, 0 is disable
+ */
+#define MUX_QUEUE_LEVEL 1
+
+/* Size of the buffer for the IP MUX commands. */
+#define MUX_MAX_UL_ACB_BUF_SIZE 256
+
+/* Maximum number of packets in a go per session */
+#define MUX_MAX_UL_DG_ENTRIES 100
+
+/* ADGH: Signature of the Datagram Header. */
+#define MUX_SIG_ADGH 0x48474441
+
+/* CMDH: Signature of the Command Header. */
+#define MUX_SIG_CMDH 0x48444D43
+
+/* QLTH: Signature of the Queue Level Table */
+#define MUX_SIG_QLTH 0x48544C51
+
+/* FCTH: Signature of the Flow Credit Table */
+#define MUX_SIG_FCTH 0x48544346
+
+/* MUX UL session threshold factor */
+#define IPC_MEM_MUX_UL_SESS_FCOFF_THRESHOLD_FACTOR (4)
+
+/* Size of the buffer for the IP MUX Lite data buffer. */
+#define IPC_MEM_MAX_DL_MUX_LITE_BUF_SIZE (2 * 1024)
+
+/* MUX UL session threshold in number of packets */
+#define IPC_MEM_MUX_UL_SESS_FCON_THRESHOLD (64)
+
+/* Default time out for sending IPC session commands like
+ * open session, close session etc
+ * unit : milliseconds
+ */
+#define IPC_MUX_CMD_RUN_DEFAULT_TIMEOUT 1000 /* 1 second */
+
+/* MUX UL flow control lower threshold in bytes */
+#define IPC_MEM_MUX_UL_FLOWCTRL_LOW_B 10240 /* 10KB */
+
+/* MUX UL flow control higher threshold in bytes (5ms worth of data)*/
+#define IPC_MEM_MUX_UL_FLOWCTRL_HIGH_B (110 * 1024)
+
+/**
+ * struct mux_adgh - Aggregated Datagram Header.
+ * @signature: Signature of the Aggregated Datagram Header(0x48474441)
+ * @length: Length (in bytes) of the datagram header. This length
+ * shall include the header size. Min value: 0x10
+ * @if_id: ID of the interface the datagrams belong to
+ * @opt_ipv4v6: Indicates IPv4(=0)/IPv6(=1), It is optional if not
+ * used set it to zero.
+ * @reserved: Reserved bits. Set to zero.
+ * @service_class: Service class identifier for the datagram.
+ * @next_count: Count of the datagrams that shall be following this
+ * datagrams for this interface. A count of zero means
+ * the next datagram may not belong to this interface.
+ * @reserved1: Reserved bytes, Set to zero
+ */
+struct mux_adgh {
+ __le32 signature;
+ __le16 length;
+ u8 if_id;
+ u8 opt_ipv4v6;
+ u8 service_class;
+ u8 next_count;
+ u8 reserved1[6];
+};
+
+/**
+ * struct mux_lite_cmdh - MUX Lite Command Header
+ * @signature: Signature of the Command Header(0x48444D43)
+ * @cmd_len: Length (in bytes) of the command. This length shall
+ * include the header size. Minimum value: 0x10
+ * @if_id: ID of the interface the commands in the table belong to.
+ * @reserved: Reserved Set to zero.
+ * @command_type: Command Enum.
+ * @transaction_id: 4 byte value shall be generated and sent along with a
+ * command Responses and ACKs shall have the same
+ * Transaction ID as their commands. It shall be unique to
+ * the command transaction on the given interface.
+ * @param: Optional parameters used with the command.
+ */
+struct mux_lite_cmdh {
+ __le32 signature;
+ __le16 cmd_len;
+ u8 if_id;
+ u8 reserved;
+ __le32 command_type;
+ __le32 transaction_id;
+ union mux_cmd_param param;
+};
+
+/**
+ * struct mux_lite_vfl - value field in generic table
+ * @nr_of_bytes: Number of bytes available to transmit in the queue.
+ */
+struct mux_lite_vfl {
+ u32 nr_of_bytes;
+};
+
+/**
+ * struct ipc_mem_lite_gen_tbl - Generic table format for Queue Level
+ * and Flow Credit
+ * @signature: Signature of the table
+ * @length: Length of the table
+ * @if_id: ID of the interface the table belongs to
+ * @vfl_length: Value field length
+ * @reserved: Reserved
+ * @vfl: Value field of variable length
+ */
+struct ipc_mem_lite_gen_tbl {
+ __le32 signature;
+ __le16 length;
+ u8 if_id;
+ u8 vfl_length;
+ u32 reserved[2];
+ struct mux_lite_vfl vfl;
+};
+
+/**
+ * ipc_mux_dl_decode -Route the DL packet through the IP MUX layer
+ * depending on Header.
+ * @ipc_mux: Pointer to MUX data-struct
+ * @skb: Pointer to ipc_skb.
+ */
+void ipc_mux_dl_decode(struct iosm_mux *ipc_mux, struct sk_buff *skb);
+
+/**
+ * ipc_mux_dl_acb_send_cmds - Respond to the Command blocks.
+ * @ipc_mux: Pointer to MUX data-struct
+ * @cmd_type: Command
+ * @if_id: Session interface id.
+ * @transaction_id: Command transaction id.
+ * @param: Pointer to command params.
+ * @res_size: Response size
+ * @blocking: True for blocking send
+ * @respond: If true return transaction ID
+ *
+ * Returns: 0 in success and failure value on error
+ */
+int ipc_mux_dl_acb_send_cmds(struct iosm_mux *ipc_mux, u32 cmd_type, u8 if_id,
+ u32 transaction_id, union mux_cmd_param *param,
+ size_t res_size, bool blocking, bool respond);
+
+/**
+ * ipc_mux_netif_tx_flowctrl - Enable/Disable TX flow control on MUX sessions.
+ * @session: Pointer to mux_session struct
+ * @idx: Session ID
+ * @on: true for Enable and false for disable flow control
+ */
+void ipc_mux_netif_tx_flowctrl(struct mux_session *session, int idx, bool on);
+
+/**
+ * ipc_mux_ul_trigger_encode - Route the UL packet through the IP MUX layer
+ * for encoding.
+ * @ipc_mux: Pointer to MUX data-struct
+ * @if_id: Session ID.
+ * @skb: Pointer to ipc_skb.
+ *
+ * Returns: 0 if successfully encoded
+ * failure value on error
+ * -EBUSY if packet has to be retransmitted.
+ */
+int ipc_mux_ul_trigger_encode(struct iosm_mux *ipc_mux, int if_id,
+ struct sk_buff *skb);
+/**
+ * ipc_mux_ul_data_encode - UL encode function for calling from Tasklet context.
+ * @ipc_mux: Pointer to MUX data-struct
+ *
+ * Returns: TRUE if any packet of any session is encoded FALSE otherwise.
+ */
+bool ipc_mux_ul_data_encode(struct iosm_mux *ipc_mux);
+
+/**
+ * ipc_mux_ul_encoded_process - Handles the Modem processed UL data by adding
+ * the SKB to the UL free list.
+ * @ipc_mux: Pointer to MUX data-struct
+ * @skb: Pointer to ipc_skb.
+ */
+void ipc_mux_ul_encoded_process(struct iosm_mux *ipc_mux, struct sk_buff *skb);
+
+#endif
diff --git a/drivers/net/wwan/iosm/iosm_ipc_pcie.c b/drivers/net/wwan/iosm/iosm_ipc_pcie.c
new file mode 100644
index 000000000000..7f7d364d3a51
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_pcie.c
@@ -0,0 +1,580 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <net/rtnetlink.h>
+
+#include "iosm_ipc_imem.h"
+#include "iosm_ipc_pcie.h"
+#include "iosm_ipc_protocol.h"
+
+MODULE_DESCRIPTION("IOSM Driver");
+MODULE_LICENSE("GPL v2");
+
+/* WWAN GUID */
+static guid_t wwan_acpi_guid = GUID_INIT(0xbad01b75, 0x22a8, 0x4f48, 0x87, 0x92,
+ 0xbd, 0xde, 0x94, 0x67, 0x74, 0x7d);
+
+static void ipc_pcie_resources_release(struct iosm_pcie *ipc_pcie)
+{
+ /* Free the MSI resources. */
+ ipc_release_irq(ipc_pcie);
+
+ /* Free mapped doorbell scratchpad bus memory into CPU space. */
+ iounmap(ipc_pcie->scratchpad);
+
+ /* Free mapped IPC_REGS bus memory into CPU space. */
+ iounmap(ipc_pcie->ipc_regs);
+
+ /* Releases all PCI I/O and memory resources previously reserved by a
+ * successful call to pci_request_regions. Call this function only
+ * after all use of the PCI regions has ceased.
+ */
+ pci_release_regions(ipc_pcie->pci);
+}
+
+static void ipc_pcie_cleanup(struct iosm_pcie *ipc_pcie)
+{
+ /* Free the shared memory resources. */
+ ipc_imem_cleanup(ipc_pcie->imem);
+
+ ipc_pcie_resources_release(ipc_pcie);
+
+ /* Signal to the system that the PCI device is not in use. */
+ pci_disable_device(ipc_pcie->pci);
+}
+
+static void ipc_pcie_deinit(struct iosm_pcie *ipc_pcie)
+{
+ kfree(ipc_pcie->imem);
+ kfree(ipc_pcie);
+}
+
+static void ipc_pcie_remove(struct pci_dev *pci)
+{
+ struct iosm_pcie *ipc_pcie = pci_get_drvdata(pci);
+
+ ipc_pcie_cleanup(ipc_pcie);
+
+ ipc_pcie_deinit(ipc_pcie);
+}
+
+static int ipc_pcie_resources_request(struct iosm_pcie *ipc_pcie)
+{
+ struct pci_dev *pci = ipc_pcie->pci;
+ u32 cap = 0;
+ u32 ret;
+
+ /* Reserved PCI I/O and memory resources.
+ * Mark all PCI regions associated with PCI device pci as
+ * being reserved by owner IOSM_IPC.
+ */
+ ret = pci_request_regions(pci, "IOSM_IPC");
+ if (ret) {
+ dev_err(ipc_pcie->dev, "failed pci request regions");
+ goto pci_request_region_fail;
+ }
+
+ /* Reserve the doorbell IPC REGS memory resources.
+ * Remap the memory into CPU space. Arrange for the physical address
+ * (BAR) to be visible from this driver.
+ * pci_ioremap_bar() ensures that the memory is marked uncachable.
+ */
+ ipc_pcie->ipc_regs = pci_ioremap_bar(pci, ipc_pcie->ipc_regs_bar_nr);
+
+ if (!ipc_pcie->ipc_regs) {
+ dev_err(ipc_pcie->dev, "IPC REGS ioremap error");
+ ret = -EBUSY;
+ goto ipc_regs_remap_fail;
+ }
+
+ /* Reserve the MMIO scratchpad memory resources.
+ * Remap the memory into CPU space. Arrange for the physical address
+ * (BAR) to be visible from this driver.
+ * pci_ioremap_bar() ensures that the memory is marked uncachable.
+ */
+ ipc_pcie->scratchpad =
+ pci_ioremap_bar(pci, ipc_pcie->scratchpad_bar_nr);
+
+ if (!ipc_pcie->scratchpad) {
+ dev_err(ipc_pcie->dev, "doorbell scratchpad ioremap error");
+ ret = -EBUSY;
+ goto scratch_remap_fail;
+ }
+
+ /* Install the irq handler triggered by CP. */
+ ret = ipc_acquire_irq(ipc_pcie);
+ if (ret) {
+ dev_err(ipc_pcie->dev, "acquiring MSI irq failed!");
+ goto irq_acquire_fail;
+ }
+
+ /* Enable bus-mastering for the IOSM IPC device. */
+ pci_set_master(pci);
+
+ /* Enable LTR if possible
+ * This is needed for L1.2!
+ */
+ pcie_capability_read_dword(ipc_pcie->pci, PCI_EXP_DEVCAP2, &cap);
+ if (cap & PCI_EXP_DEVCAP2_LTR)
+ pcie_capability_set_word(ipc_pcie->pci, PCI_EXP_DEVCTL2,
+ PCI_EXP_DEVCTL2_LTR_EN);
+
+ dev_dbg(ipc_pcie->dev, "link between AP and CP is fully on");
+
+ return ret;
+
+irq_acquire_fail:
+ iounmap(ipc_pcie->scratchpad);
+scratch_remap_fail:
+ iounmap(ipc_pcie->ipc_regs);
+ipc_regs_remap_fail:
+ pci_release_regions(pci);
+pci_request_region_fail:
+ return ret;
+}
+
+bool ipc_pcie_check_aspm_enabled(struct iosm_pcie *ipc_pcie,
+ bool parent)
+{
+ struct pci_dev *pdev;
+ u16 value = 0;
+ u32 enabled;
+
+ if (parent)
+ pdev = ipc_pcie->pci->bus->self;
+ else
+ pdev = ipc_pcie->pci;
+
+ pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &value);
+ enabled = value & PCI_EXP_LNKCTL_ASPMC;
+ dev_dbg(ipc_pcie->dev, "ASPM L1: 0x%04X 0x%03X", pdev->device, value);
+
+ return (enabled == PCI_EXP_LNKCTL_ASPM_L1 ||
+ enabled == PCI_EXP_LNKCTL_ASPMC);
+}
+
+bool ipc_pcie_check_data_link_active(struct iosm_pcie *ipc_pcie)
+{
+ struct pci_dev *parent;
+ u16 link_status = 0;
+
+ if (!ipc_pcie->pci->bus || !ipc_pcie->pci->bus->self) {
+ dev_err(ipc_pcie->dev, "root port not found");
+ return false;
+ }
+
+ parent = ipc_pcie->pci->bus->self;
+
+ pcie_capability_read_word(parent, PCI_EXP_LNKSTA, &link_status);
+ dev_dbg(ipc_pcie->dev, "Link status: 0x%04X", link_status);
+
+ return link_status & PCI_EXP_LNKSTA_DLLLA;
+}
+
+static bool ipc_pcie_check_aspm_supported(struct iosm_pcie *ipc_pcie,
+ bool parent)
+{
+ struct pci_dev *pdev;
+ u32 support;
+ u32 cap = 0;
+
+ if (parent)
+ pdev = ipc_pcie->pci->bus->self;
+ else
+ pdev = ipc_pcie->pci;
+ pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &cap);
+ support = u32_get_bits(cap, PCI_EXP_LNKCAP_ASPMS);
+ if (support < PCI_EXP_LNKCTL_ASPM_L1) {
+ dev_dbg(ipc_pcie->dev, "ASPM L1 not supported: 0x%04X",
+ pdev->device);
+ return false;
+ }
+ return true;
+}
+
+void ipc_pcie_config_aspm(struct iosm_pcie *ipc_pcie)
+{
+ bool parent_aspm_enabled, dev_aspm_enabled;
+
+ /* check if both root port and child supports ASPM L1 */
+ if (!ipc_pcie_check_aspm_supported(ipc_pcie, true) ||
+ !ipc_pcie_check_aspm_supported(ipc_pcie, false))
+ return;
+
+ parent_aspm_enabled = ipc_pcie_check_aspm_enabled(ipc_pcie, true);
+ dev_aspm_enabled = ipc_pcie_check_aspm_enabled(ipc_pcie, false);
+
+ dev_dbg(ipc_pcie->dev, "ASPM parent: %s device: %s",
+ parent_aspm_enabled ? "Enabled" : "Disabled",
+ dev_aspm_enabled ? "Enabled" : "Disabled");
+}
+
+/* Initializes PCIe endpoint configuration */
+static void ipc_pcie_config_init(struct iosm_pcie *ipc_pcie)
+{
+ /* BAR0 is used for doorbell */
+ ipc_pcie->ipc_regs_bar_nr = IPC_DOORBELL_BAR0;
+
+ /* update HW configuration */
+ ipc_pcie->scratchpad_bar_nr = IPC_SCRATCHPAD_BAR2;
+ ipc_pcie->doorbell_reg_offset = IPC_DOORBELL_CH_OFFSET;
+ ipc_pcie->doorbell_write = IPC_WRITE_PTR_REG_0;
+ ipc_pcie->doorbell_capture = IPC_CAPTURE_PTR_REG_0;
+}
+
+/* This will read the BIOS WWAN RTD3 settings:
+ * D0L1.2/D3L2/Disabled
+ */
+static enum ipc_pcie_sleep_state ipc_pcie_read_bios_cfg(struct device *dev)
+{
+ union acpi_object *object;
+ acpi_handle handle_acpi;
+
+ handle_acpi = ACPI_HANDLE(dev);
+ if (!handle_acpi) {
+ pr_debug("pci device is NOT ACPI supporting device\n");
+ goto default_ret;
+ }
+
+ object = acpi_evaluate_dsm(handle_acpi, &wwan_acpi_guid, 0, 3, NULL);
+
+ if (object && object->integer.value == 3)
+ return IPC_PCIE_D3L2;
+
+default_ret:
+ return IPC_PCIE_D0L12;
+}
+
+static int ipc_pcie_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ struct iosm_pcie *ipc_pcie = kzalloc(sizeof(*ipc_pcie), GFP_KERNEL);
+
+ pr_debug("Probing device 0x%X from the vendor 0x%X", pci_id->device,
+ pci_id->vendor);
+
+ if (!ipc_pcie)
+ goto ret_fail;
+
+ /* Initialize ipc dbg component for the PCIe device */
+ ipc_pcie->dev = &pci->dev;
+
+ /* Set the driver specific data. */
+ pci_set_drvdata(pci, ipc_pcie);
+
+ /* Save the address of the PCI device configuration. */
+ ipc_pcie->pci = pci;
+
+ /* Update platform configuration */
+ ipc_pcie_config_init(ipc_pcie);
+
+ /* Initialize the device before it is used. Ask low-level code
+ * to enable I/O and memory. Wake up the device if it was suspended.
+ */
+ if (pci_enable_device(pci)) {
+ dev_err(ipc_pcie->dev, "failed to enable the AP PCIe device");
+ /* If enable of PCIe device has failed then calling
+ * ipc_pcie_cleanup will panic the system. More over
+ * ipc_pcie_cleanup() is required to be called after
+ * ipc_imem_mount()
+ */
+ goto pci_enable_fail;
+ }
+
+ ipc_pcie_config_aspm(ipc_pcie);
+ dev_dbg(ipc_pcie->dev, "PCIe device enabled.");
+
+ /* Read WWAN RTD3 BIOS Setting
+ */
+ ipc_pcie->d3l2_support = ipc_pcie_read_bios_cfg(&pci->dev);
+
+ ipc_pcie->suspend = 0;
+
+ if (ipc_pcie_resources_request(ipc_pcie))
+ goto resources_req_fail;
+
+ /* Establish the link to the imem layer. */
+ ipc_pcie->imem = ipc_imem_init(ipc_pcie, pci->device,
+ ipc_pcie->scratchpad, ipc_pcie->dev);
+ if (!ipc_pcie->imem) {
+ dev_err(ipc_pcie->dev, "failed to init imem");
+ goto imem_init_fail;
+ }
+
+ return 0;
+
+imem_init_fail:
+ ipc_pcie_resources_release(ipc_pcie);
+resources_req_fail:
+ pci_disable_device(pci);
+pci_enable_fail:
+ kfree(ipc_pcie);
+ret_fail:
+ return -EIO;
+}
+
+static const struct pci_device_id iosm_ipc_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, INTEL_CP_DEVICE_7560_ID) },
+ {}
+};
+MODULE_DEVICE_TABLE(pci, iosm_ipc_ids);
+
+/* Enter sleep in s2idle case
+ */
+static int __maybe_unused ipc_pcie_suspend_s2idle(struct iosm_pcie *ipc_pcie)
+{
+ ipc_cp_irq_sleep_control(ipc_pcie, IPC_MEM_DEV_PM_FORCE_SLEEP);
+
+ /* Complete all memory stores before setting bit */
+ smp_mb__before_atomic();
+
+ set_bit(0, &ipc_pcie->suspend);
+
+ /* Complete all memory stores after setting bit */
+ smp_mb__after_atomic();
+
+ ipc_imem_pm_s2idle_sleep(ipc_pcie->imem, true);
+
+ return 0;
+}
+
+/* Resume from sleep in s2idle case
+ */
+static int __maybe_unused ipc_pcie_resume_s2idle(struct iosm_pcie *ipc_pcie)
+{
+ ipc_cp_irq_sleep_control(ipc_pcie, IPC_MEM_DEV_PM_FORCE_ACTIVE);
+
+ ipc_imem_pm_s2idle_sleep(ipc_pcie->imem, false);
+
+ /* Complete all memory stores before clearing bit. */
+ smp_mb__before_atomic();
+
+ clear_bit(0, &ipc_pcie->suspend);
+
+ /* Complete all memory stores after clearing bit. */
+ smp_mb__after_atomic();
+ return 0;
+}
+
+int __maybe_unused ipc_pcie_suspend(struct iosm_pcie *ipc_pcie)
+{
+ struct pci_dev *pdev;
+ int ret;
+
+ pdev = ipc_pcie->pci;
+
+ /* Execute D3 one time. */
+ if (pdev->current_state != PCI_D0) {
+ dev_dbg(ipc_pcie->dev, "done for PM=%d", pdev->current_state);
+ return 0;
+ }
+
+ /* The HAL shall ask the shared memory layer whether D3 is allowed. */
+ ipc_imem_pm_suspend(ipc_pcie->imem);
+
+ /* Save the PCI configuration space of a device before suspending. */
+ ret = pci_save_state(pdev);
+
+ if (ret) {
+ dev_err(ipc_pcie->dev, "pci_save_state error=%d", ret);
+ return ret;
+ }
+
+ /* Set the power state of a PCI device.
+ * Transition a device to a new power state, using the device's PCI PM
+ * registers.
+ */
+ ret = pci_set_power_state(pdev, PCI_D3cold);
+
+ if (ret) {
+ dev_err(ipc_pcie->dev, "pci_set_power_state error=%d", ret);
+ return ret;
+ }
+
+ dev_dbg(ipc_pcie->dev, "SUSPEND done");
+ return ret;
+}
+
+int __maybe_unused ipc_pcie_resume(struct iosm_pcie *ipc_pcie)
+{
+ int ret;
+
+ /* Set the power state of a PCI device.
+ * Transition a device to a new power state, using the device's PCI PM
+ * registers.
+ */
+ ret = pci_set_power_state(ipc_pcie->pci, PCI_D0);
+
+ if (ret) {
+ dev_err(ipc_pcie->dev, "pci_set_power_state error=%d", ret);
+ return ret;
+ }
+
+ pci_restore_state(ipc_pcie->pci);
+
+ /* The HAL shall inform the shared memory layer that the device is
+ * active.
+ */
+ ipc_imem_pm_resume(ipc_pcie->imem);
+
+ dev_dbg(ipc_pcie->dev, "RESUME done");
+ return ret;
+}
+
+static int __maybe_unused ipc_pcie_suspend_cb(struct device *dev)
+{
+ struct iosm_pcie *ipc_pcie;
+ struct pci_dev *pdev;
+
+ pdev = to_pci_dev(dev);
+
+ ipc_pcie = pci_get_drvdata(pdev);
+
+ switch (ipc_pcie->d3l2_support) {
+ case IPC_PCIE_D0L12:
+ ipc_pcie_suspend_s2idle(ipc_pcie);
+ break;
+ case IPC_PCIE_D3L2:
+ ipc_pcie_suspend(ipc_pcie);
+ break;
+ }
+
+ return 0;
+}
+
+static int __maybe_unused ipc_pcie_resume_cb(struct device *dev)
+{
+ struct iosm_pcie *ipc_pcie;
+ struct pci_dev *pdev;
+
+ pdev = to_pci_dev(dev);
+
+ ipc_pcie = pci_get_drvdata(pdev);
+
+ switch (ipc_pcie->d3l2_support) {
+ case IPC_PCIE_D0L12:
+ ipc_pcie_resume_s2idle(ipc_pcie);
+ break;
+ case IPC_PCIE_D3L2:
+ ipc_pcie_resume(ipc_pcie);
+ break;
+ }
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(iosm_ipc_pm, ipc_pcie_suspend_cb, ipc_pcie_resume_cb);
+
+static struct pci_driver iosm_ipc_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = ipc_pcie_probe,
+ .remove = ipc_pcie_remove,
+ .driver = {
+ .pm = &iosm_ipc_pm,
+ },
+ .id_table = iosm_ipc_ids,
+};
+
+int ipc_pcie_addr_map(struct iosm_pcie *ipc_pcie, unsigned char *data,
+ size_t size, dma_addr_t *mapping, int direction)
+{
+ if (ipc_pcie->pci) {
+ *mapping = dma_map_single(&ipc_pcie->pci->dev, data, size,
+ direction);
+ if (dma_mapping_error(&ipc_pcie->pci->dev, *mapping)) {
+ dev_err(ipc_pcie->dev, "dma mapping failed");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+void ipc_pcie_addr_unmap(struct iosm_pcie *ipc_pcie, size_t size,
+ dma_addr_t mapping, int direction)
+{
+ if (!mapping)
+ return;
+ if (ipc_pcie->pci)
+ dma_unmap_single(&ipc_pcie->pci->dev, mapping, size, direction);
+}
+
+struct sk_buff *ipc_pcie_alloc_local_skb(struct iosm_pcie *ipc_pcie,
+ gfp_t flags, size_t size)
+{
+ struct sk_buff *skb;
+
+ if (!ipc_pcie || !size) {
+ pr_err("invalid pcie object or size");
+ return NULL;
+ }
+
+ skb = __netdev_alloc_skb(NULL, size, flags);
+ if (!skb)
+ return NULL;
+
+ IPC_CB(skb)->op_type = (u8)UL_DEFAULT;
+ IPC_CB(skb)->mapping = 0;
+
+ return skb;
+}
+
+struct sk_buff *ipc_pcie_alloc_skb(struct iosm_pcie *ipc_pcie, size_t size,
+ gfp_t flags, dma_addr_t *mapping,
+ int direction, size_t headroom)
+{
+ struct sk_buff *skb = ipc_pcie_alloc_local_skb(ipc_pcie, flags,
+ size + headroom);
+ if (!skb)
+ return NULL;
+
+ if (headroom)
+ skb_reserve(skb, headroom);
+
+ if (ipc_pcie_addr_map(ipc_pcie, skb->data, size, mapping, direction)) {
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+
+ BUILD_BUG_ON(sizeof(*IPC_CB(skb)) > sizeof(skb->cb));
+
+ /* Store the mapping address in skb scratch pad for later usage */
+ IPC_CB(skb)->mapping = *mapping;
+ IPC_CB(skb)->direction = direction;
+ IPC_CB(skb)->len = size;
+
+ return skb;
+}
+
+void ipc_pcie_kfree_skb(struct iosm_pcie *ipc_pcie, struct sk_buff *skb)
+{
+ if (!skb)
+ return;
+
+ ipc_pcie_addr_unmap(ipc_pcie, IPC_CB(skb)->len, IPC_CB(skb)->mapping,
+ IPC_CB(skb)->direction);
+ IPC_CB(skb)->mapping = 0;
+ dev_kfree_skb(skb);
+}
+
+static int __init iosm_ipc_driver_init(void)
+{
+ if (pci_register_driver(&iosm_ipc_driver)) {
+ pr_err("registering of IOSM PCIe driver failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void __exit iosm_ipc_driver_exit(void)
+{
+ pci_unregister_driver(&iosm_ipc_driver);
+}
+
+module_init(iosm_ipc_driver_init);
+module_exit(iosm_ipc_driver_exit);
diff --git a/drivers/net/wwan/iosm/iosm_ipc_pcie.h b/drivers/net/wwan/iosm/iosm_ipc_pcie.h
new file mode 100644
index 000000000000..7d1f0cd7364c
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_pcie.h
@@ -0,0 +1,209 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#ifndef IOSM_IPC_PCIE_H
+#define IOSM_IPC_PCIE_H
+
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/skbuff.h>
+
+#include "iosm_ipc_irq.h"
+
+/* Device ID */
+#define INTEL_CP_DEVICE_7560_ID 0x7560
+
+/* Define for BAR area usage */
+#define IPC_DOORBELL_BAR0 0
+#define IPC_SCRATCHPAD_BAR2 2
+
+/* Defines for DOORBELL registers information */
+#define IPC_DOORBELL_CH_OFFSET BIT(5)
+#define IPC_WRITE_PTR_REG_0 BIT(4)
+#define IPC_CAPTURE_PTR_REG_0 BIT(3)
+
+/* Number of MSI used for IPC */
+#define IPC_MSI_VECTORS 1
+
+/* Total number of Maximum IPC IRQ vectors used for IPC */
+#define IPC_IRQ_VECTORS IPC_MSI_VECTORS
+
+/**
+ * enum ipc_pcie_sleep_state - Enum type to different sleep state transitions
+ * @IPC_PCIE_D0L12: Put the sleep state in D0L12
+ * @IPC_PCIE_D3L2: Put the sleep state in D3L2
+ */
+enum ipc_pcie_sleep_state {
+ IPC_PCIE_D0L12,
+ IPC_PCIE_D3L2,
+};
+
+/**
+ * struct iosm_pcie - IPC_PCIE struct.
+ * @pci: Address of the device description
+ * @dev: Pointer to generic device structure
+ * @ipc_regs: Remapped CP doorbell address of the irq register
+ * set, to fire the doorbell irq.
+ * @scratchpad: Remapped CP scratchpad address, to send the
+ * configuration. tuple and the IPC descriptors
+ * to CP in the ROM phase. The config tuple
+ * information are saved on the MSI scratchpad.
+ * @imem: Pointer to imem data struct
+ * @ipc_regs_bar_nr: BAR number to be used for IPC doorbell
+ * @scratchpad_bar_nr: BAR number to be used for Scratchpad
+ * @nvec: number of requested irq vectors
+ * @doorbell_reg_offset: doorbell_reg_offset
+ * @doorbell_write: doorbell write register
+ * @doorbell_capture: doorbell capture resgister
+ * @suspend: S2IDLE sleep/active
+ * @d3l2_support: Read WWAN RTD3 BIOS setting for D3L2 support
+ */
+struct iosm_pcie {
+ struct pci_dev *pci;
+ struct device *dev;
+ void __iomem *ipc_regs;
+ void __iomem *scratchpad;
+ struct iosm_imem *imem;
+ int ipc_regs_bar_nr;
+ int scratchpad_bar_nr;
+ int nvec;
+ u32 doorbell_reg_offset;
+ u32 doorbell_write;
+ u32 doorbell_capture;
+ unsigned long suspend;
+ enum ipc_pcie_sleep_state d3l2_support;
+};
+
+/**
+ * struct ipc_skb_cb - Struct definition of the socket buffer which is mapped to
+ * the cb field of sbk
+ * @mapping: Store physical or IOVA mapped address of skb virtual add.
+ * @direction: DMA direction
+ * @len: Length of the DMA mapped region
+ * @op_type: Expected values are defined about enum ipc_ul_usr_op.
+ */
+struct ipc_skb_cb {
+ dma_addr_t mapping;
+ int direction;
+ int len;
+ u8 op_type;
+};
+
+/**
+ * enum ipc_ul_usr_op - Control operation to execute the right action on
+ * the user interface.
+ * @UL_USR_OP_BLOCKED: The uplink app was blocked until CP confirms that the
+ * uplink buffer was consumed triggered by the IRQ.
+ * @UL_MUX_OP_ADB: In MUX mode the UL ADB shall be addedd to the free list.
+ * @UL_DEFAULT: SKB in non muxing mode
+ */
+enum ipc_ul_usr_op {
+ UL_USR_OP_BLOCKED,
+ UL_MUX_OP_ADB,
+ UL_DEFAULT,
+};
+
+/**
+ * ipc_pcie_addr_map - Maps the kernel's virtual address to either IOVA
+ * address space or Physical address space, the mapping is
+ * stored in the skb's cb.
+ * @ipc_pcie: Pointer to struct iosm_pcie
+ * @data: Skb mem containing data
+ * @size: Data size
+ * @mapping: Dma mapping address
+ * @direction: Data direction
+ *
+ * Returns: 0 on success and failure value on error
+ */
+int ipc_pcie_addr_map(struct iosm_pcie *ipc_pcie, unsigned char *data,
+ size_t size, dma_addr_t *mapping, int direction);
+
+/**
+ * ipc_pcie_addr_unmap - Unmaps the skb memory region from IOVA address space
+ * @ipc_pcie: Pointer to struct iosm_pcie
+ * @size: Data size
+ * @mapping: Dma mapping address
+ * @direction: Data direction
+ */
+void ipc_pcie_addr_unmap(struct iosm_pcie *ipc_pcie, size_t size,
+ dma_addr_t mapping, int direction);
+
+/**
+ * ipc_pcie_alloc_skb - Allocate an uplink SKB for the given size.
+ * @ipc_pcie: Pointer to struct iosm_pcie
+ * @size: Size of the SKB required.
+ * @flags: Allocation flags
+ * @mapping: Copies either mapped IOVA add. or converted Phy address
+ * @direction: DMA data direction
+ * @headroom: Header data offset
+ *
+ * Returns: Pointer to ipc_skb on Success, NULL on failure.
+ */
+struct sk_buff *ipc_pcie_alloc_skb(struct iosm_pcie *ipc_pcie, size_t size,
+ gfp_t flags, dma_addr_t *mapping,
+ int direction, size_t headroom);
+
+/**
+ * ipc_pcie_alloc_local_skb - Allocate a local SKB for the given size.
+ * @ipc_pcie: Pointer to struct iosm_pcie
+ * @flags: Allocation flags
+ * @size: Size of the SKB required.
+ *
+ * Returns: Pointer to ipc_skb on Success, NULL on failure.
+ */
+struct sk_buff *ipc_pcie_alloc_local_skb(struct iosm_pcie *ipc_pcie,
+ gfp_t flags, size_t size);
+
+/**
+ * ipc_pcie_kfree_skb - Free skb allocated by ipc_pcie_alloc_*_skb().
+ * @ipc_pcie: Pointer to struct iosm_pcie
+ * @skb: Pointer to the skb
+ */
+void ipc_pcie_kfree_skb(struct iosm_pcie *ipc_pcie, struct sk_buff *skb);
+
+/**
+ * ipc_pcie_check_data_link_active - Check Data Link Layer Active
+ * @ipc_pcie: Pointer to struct iosm_pcie
+ *
+ * Returns: true if active, otherwise false
+ */
+bool ipc_pcie_check_data_link_active(struct iosm_pcie *ipc_pcie);
+
+/**
+ * ipc_pcie_suspend - Callback invoked by pm_runtime_suspend. It decrements
+ * the device's usage count then, carry out a suspend,
+ * either synchronous or asynchronous.
+ * @ipc_pcie: Pointer to struct iosm_pcie
+ *
+ * Returns: 0 on success and failure value on error
+ */
+int ipc_pcie_suspend(struct iosm_pcie *ipc_pcie);
+
+/**
+ * ipc_pcie_resume - Callback invoked by pm_runtime_resume. It increments
+ * the device's usage count then, carry out a resume,
+ * either synchronous or asynchronous.
+ * @ipc_pcie: Pointer to struct iosm_pcie
+ *
+ * Returns: 0 on success and failure value on error
+ */
+int ipc_pcie_resume(struct iosm_pcie *ipc_pcie);
+
+/**
+ * ipc_pcie_check_aspm_enabled - Check if ASPM L1 is already enabled
+ * @ipc_pcie: Pointer to struct iosm_pcie
+ * @parent: True if checking ASPM L1 for parent else false
+ *
+ * Returns: true if ASPM is already enabled else false
+ */
+bool ipc_pcie_check_aspm_enabled(struct iosm_pcie *ipc_pcie,
+ bool parent);
+/**
+ * ipc_pcie_config_aspm - Configure ASPM L1
+ * @ipc_pcie: Pointer to struct iosm_pcie
+ */
+void ipc_pcie_config_aspm(struct iosm_pcie *ipc_pcie);
+
+#endif
diff --git a/drivers/net/wwan/iosm/iosm_ipc_pm.c b/drivers/net/wwan/iosm/iosm_ipc_pm.c
new file mode 100644
index 000000000000..413601c72dcd
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_pm.c
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include "iosm_ipc_protocol.h"
+
+/* Timeout value in MS for the PM to wait for device to reach active state */
+#define IPC_PM_ACTIVE_TIMEOUT_MS (500)
+
+/* Note that here "active" has the value 1, as compared to the enums
+ * ipc_mem_host_pm_state or ipc_mem_dev_pm_state, where "active" is 0
+ */
+#define IPC_PM_SLEEP (0)
+#define CONSUME_STATE (0)
+#define IPC_PM_ACTIVE (1)
+
+void ipc_pm_signal_hpda_doorbell(struct iosm_pm *ipc_pm, u32 identifier,
+ bool host_slp_check)
+{
+ if (host_slp_check && ipc_pm->host_pm_state != IPC_MEM_HOST_PM_ACTIVE &&
+ ipc_pm->host_pm_state != IPC_MEM_HOST_PM_ACTIVE_WAIT) {
+ ipc_pm->pending_hpda_update = true;
+ dev_dbg(ipc_pm->dev,
+ "Pend HPDA update set. Host PM_State: %d identifier:%d",
+ ipc_pm->host_pm_state, identifier);
+ return;
+ }
+
+ if (!ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_IRQ, true)) {
+ ipc_pm->pending_hpda_update = true;
+ dev_dbg(ipc_pm->dev, "Pending HPDA update set. identifier:%d",
+ identifier);
+ return;
+ }
+ ipc_pm->pending_hpda_update = false;
+
+ /* Trigger the irq towards CP */
+ ipc_cp_irq_hpda_update(ipc_pm->pcie, identifier);
+
+ ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_IRQ, false);
+}
+
+/* Wake up the device if it is in low power mode. */
+static bool ipc_pm_link_activate(struct iosm_pm *ipc_pm)
+{
+ if (ipc_pm->cp_state == IPC_MEM_DEV_PM_ACTIVE)
+ return true;
+
+ if (ipc_pm->cp_state == IPC_MEM_DEV_PM_SLEEP) {
+ if (ipc_pm->ap_state == IPC_MEM_DEV_PM_SLEEP) {
+ /* Wake up the device. */
+ ipc_cp_irq_sleep_control(ipc_pm->pcie,
+ IPC_MEM_DEV_PM_WAKEUP);
+ ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE_WAIT;
+
+ goto not_active;
+ }
+
+ if (ipc_pm->ap_state == IPC_MEM_DEV_PM_ACTIVE_WAIT)
+ goto not_active;
+
+ return true;
+ }
+
+not_active:
+ /* link is not ready */
+ return false;
+}
+
+bool ipc_pm_wait_for_device_active(struct iosm_pm *ipc_pm)
+{
+ bool ret_val = false;
+
+ if (ipc_pm->ap_state != IPC_MEM_DEV_PM_ACTIVE) {
+ /* Complete all memory stores before setting bit */
+ smp_mb__before_atomic();
+
+ /* Wait for IPC_PM_ACTIVE_TIMEOUT_MS for Device sleep state
+ * machine to enter ACTIVE state.
+ */
+ set_bit(0, &ipc_pm->host_sleep_pend);
+
+ /* Complete all memory stores after setting bit */
+ smp_mb__after_atomic();
+
+ if (!wait_for_completion_interruptible_timeout
+ (&ipc_pm->host_sleep_complete,
+ msecs_to_jiffies(IPC_PM_ACTIVE_TIMEOUT_MS))) {
+ dev_err(ipc_pm->dev,
+ "PM timeout. Expected State:%d. Actual: %d",
+ IPC_MEM_DEV_PM_ACTIVE, ipc_pm->ap_state);
+ goto active_timeout;
+ }
+ }
+
+ ret_val = true;
+active_timeout:
+ /* Complete all memory stores before clearing bit */
+ smp_mb__before_atomic();
+
+ /* Reset the atomic variable in any case as device sleep
+ * state machine change is no longer of interest.
+ */
+ clear_bit(0, &ipc_pm->host_sleep_pend);
+
+ /* Complete all memory stores after clearing bit */
+ smp_mb__after_atomic();
+
+ return ret_val;
+}
+
+static void ipc_pm_on_link_sleep(struct iosm_pm *ipc_pm)
+{
+ /* pending sleep ack and all conditions are cleared
+ * -> signal SLEEP__ACK to CP
+ */
+ ipc_pm->cp_state = IPC_MEM_DEV_PM_SLEEP;
+ ipc_pm->ap_state = IPC_MEM_DEV_PM_SLEEP;
+
+ ipc_cp_irq_sleep_control(ipc_pm->pcie, IPC_MEM_DEV_PM_SLEEP);
+}
+
+static void ipc_pm_on_link_wake(struct iosm_pm *ipc_pm, bool ack)
+{
+ ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE;
+
+ if (ack) {
+ ipc_pm->cp_state = IPC_MEM_DEV_PM_ACTIVE;
+
+ ipc_cp_irq_sleep_control(ipc_pm->pcie, IPC_MEM_DEV_PM_ACTIVE);
+
+ /* check the consume state !!! */
+ if (test_bit(CONSUME_STATE, &ipc_pm->host_sleep_pend))
+ complete(&ipc_pm->host_sleep_complete);
+ }
+
+ /* Check for pending HPDA update.
+ * Pending HP update could be because of sending message was
+ * put on hold due to Device sleep state or due to TD update
+ * which could be because of Device Sleep and Host Sleep
+ * states.
+ */
+ if (ipc_pm->pending_hpda_update &&
+ ipc_pm->host_pm_state == IPC_MEM_HOST_PM_ACTIVE)
+ ipc_pm_signal_hpda_doorbell(ipc_pm, IPC_HP_PM_TRIGGER, true);
+}
+
+bool ipc_pm_trigger(struct iosm_pm *ipc_pm, enum ipc_pm_unit unit, bool active)
+{
+ union ipc_pm_cond old_cond;
+ union ipc_pm_cond new_cond;
+ bool link_active;
+
+ /* Save the current D3 state. */
+ new_cond = ipc_pm->pm_cond;
+ old_cond = ipc_pm->pm_cond;
+
+ /* Calculate the power state only in the runtime phase. */
+ switch (unit) {
+ case IPC_PM_UNIT_IRQ: /* CP irq */
+ new_cond.irq = active;
+ break;
+
+ case IPC_PM_UNIT_LINK: /* Device link state. */
+ new_cond.link = active;
+ break;
+
+ case IPC_PM_UNIT_HS: /* Host sleep trigger requires Link. */
+ new_cond.hs = active;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Something changed ? */
+ if (old_cond.raw == new_cond.raw) {
+ /* Stay in the current PM state. */
+ link_active = old_cond.link == IPC_PM_ACTIVE;
+ goto ret;
+ }
+
+ ipc_pm->pm_cond = new_cond;
+
+ if (new_cond.link)
+ ipc_pm_on_link_wake(ipc_pm, unit == IPC_PM_UNIT_LINK);
+ else if (unit == IPC_PM_UNIT_LINK)
+ ipc_pm_on_link_sleep(ipc_pm);
+
+ if (old_cond.link == IPC_PM_SLEEP && new_cond.raw) {
+ link_active = ipc_pm_link_activate(ipc_pm);
+ goto ret;
+ }
+
+ link_active = old_cond.link == IPC_PM_ACTIVE;
+
+ret:
+ return link_active;
+}
+
+bool ipc_pm_prepare_host_sleep(struct iosm_pm *ipc_pm)
+{
+ /* suspend not allowed if host_pm_state is not IPC_MEM_HOST_PM_ACTIVE */
+ if (ipc_pm->host_pm_state != IPC_MEM_HOST_PM_ACTIVE) {
+ dev_err(ipc_pm->dev, "host_pm_state=%d\tExpected to be: %d",
+ ipc_pm->host_pm_state, IPC_MEM_HOST_PM_ACTIVE);
+ return false;
+ }
+
+ ipc_pm->host_pm_state = IPC_MEM_HOST_PM_SLEEP_WAIT_D3;
+
+ return true;
+}
+
+bool ipc_pm_prepare_host_active(struct iosm_pm *ipc_pm)
+{
+ if (ipc_pm->host_pm_state != IPC_MEM_HOST_PM_SLEEP) {
+ dev_err(ipc_pm->dev, "host_pm_state=%d\tExpected to be: %d",
+ ipc_pm->host_pm_state, IPC_MEM_HOST_PM_SLEEP);
+ return false;
+ }
+
+ /* Sending Sleep Exit message to CP. Update the state */
+ ipc_pm->host_pm_state = IPC_MEM_HOST_PM_ACTIVE_WAIT;
+
+ return true;
+}
+
+void ipc_pm_set_s2idle_sleep(struct iosm_pm *ipc_pm, bool sleep)
+{
+ if (sleep) {
+ ipc_pm->ap_state = IPC_MEM_DEV_PM_SLEEP;
+ ipc_pm->cp_state = IPC_MEM_DEV_PM_SLEEP;
+ ipc_pm->device_sleep_notification = IPC_MEM_DEV_PM_SLEEP;
+ } else {
+ ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE;
+ ipc_pm->cp_state = IPC_MEM_DEV_PM_ACTIVE;
+ ipc_pm->device_sleep_notification = IPC_MEM_DEV_PM_ACTIVE;
+ ipc_pm->pm_cond.link = IPC_PM_ACTIVE;
+ }
+}
+
+bool ipc_pm_dev_slp_notification(struct iosm_pm *ipc_pm, u32 cp_pm_req)
+{
+ if (cp_pm_req == ipc_pm->device_sleep_notification)
+ return false;
+
+ ipc_pm->device_sleep_notification = cp_pm_req;
+
+ /* Evaluate the PM request. */
+ switch (ipc_pm->cp_state) {
+ case IPC_MEM_DEV_PM_ACTIVE:
+ switch (cp_pm_req) {
+ case IPC_MEM_DEV_PM_ACTIVE:
+ break;
+
+ case IPC_MEM_DEV_PM_SLEEP:
+ /* Inform the PM that the device link can go down. */
+ ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_LINK, false);
+ return true;
+
+ default:
+ dev_err(ipc_pm->dev,
+ "loc-pm=%d active: confused req-pm=%d",
+ ipc_pm->cp_state, cp_pm_req);
+ break;
+ }
+ break;
+
+ case IPC_MEM_DEV_PM_SLEEP:
+ switch (cp_pm_req) {
+ case IPC_MEM_DEV_PM_ACTIVE:
+ /* Inform the PM that the device link is active. */
+ ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_LINK, true);
+ break;
+
+ case IPC_MEM_DEV_PM_SLEEP:
+ break;
+
+ default:
+ dev_err(ipc_pm->dev,
+ "loc-pm=%d sleep: confused req-pm=%d",
+ ipc_pm->cp_state, cp_pm_req);
+ break;
+ }
+ break;
+
+ default:
+ dev_err(ipc_pm->dev, "confused loc-pm=%d, req-pm=%d",
+ ipc_pm->cp_state, cp_pm_req);
+ break;
+ }
+
+ return false;
+}
+
+void ipc_pm_init(struct iosm_protocol *ipc_protocol)
+{
+ struct iosm_imem *ipc_imem = ipc_protocol->imem;
+ struct iosm_pm *ipc_pm = &ipc_protocol->pm;
+
+ ipc_pm->pcie = ipc_imem->pcie;
+ ipc_pm->dev = ipc_imem->dev;
+
+ ipc_pm->pm_cond.irq = IPC_PM_SLEEP;
+ ipc_pm->pm_cond.hs = IPC_PM_SLEEP;
+ ipc_pm->pm_cond.link = IPC_PM_ACTIVE;
+
+ ipc_pm->cp_state = IPC_MEM_DEV_PM_ACTIVE;
+ ipc_pm->ap_state = IPC_MEM_DEV_PM_ACTIVE;
+ ipc_pm->host_pm_state = IPC_MEM_HOST_PM_ACTIVE;
+
+ /* Create generic wait-for-completion handler for Host Sleep
+ * and device sleep coordination.
+ */
+ init_completion(&ipc_pm->host_sleep_complete);
+
+ /* Complete all memory stores before clearing bit */
+ smp_mb__before_atomic();
+
+ clear_bit(0, &ipc_pm->host_sleep_pend);
+
+ /* Complete all memory stores after clearing bit */
+ smp_mb__after_atomic();
+}
+
+void ipc_pm_deinit(struct iosm_protocol *proto)
+{
+ struct iosm_pm *ipc_pm = &proto->pm;
+
+ complete(&ipc_pm->host_sleep_complete);
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_pm.h b/drivers/net/wwan/iosm/iosm_ipc_pm.h
new file mode 100644
index 000000000000..e7c00f388cb0
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_pm.h
@@ -0,0 +1,207 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#ifndef IOSM_IPC_PM_H
+#define IOSM_IPC_PM_H
+
+/* Trigger the doorbell interrupt on cp to change the PM sleep/active status */
+#define ipc_cp_irq_sleep_control(ipc_pcie, data) \
+ ipc_doorbell_fire(ipc_pcie, IPC_DOORBELL_IRQ_SLEEP, data)
+
+/* Trigger the doorbell interrupt on CP to do hpda update */
+#define ipc_cp_irq_hpda_update(ipc_pcie, data) \
+ ipc_doorbell_fire(ipc_pcie, IPC_DOORBELL_IRQ_HPDA, 0xFF & (data))
+
+/**
+ * union ipc_pm_cond - Conditions for D3 and the sleep message to CP.
+ * @raw: raw/combined value for faster check
+ * @irq: IRQ towards CP
+ * @hs: Host Sleep
+ * @link: Device link state.
+ */
+union ipc_pm_cond {
+ unsigned int raw;
+
+ struct {
+ unsigned int irq:1,
+ hs:1,
+ link:1;
+ };
+};
+
+/**
+ * enum ipc_mem_host_pm_state - Possible states of the HOST SLEEP finite state
+ * machine.
+ * @IPC_MEM_HOST_PM_ACTIVE: Host is active
+ * @IPC_MEM_HOST_PM_ACTIVE_WAIT: Intermediate state before going to
+ * active
+ * @IPC_MEM_HOST_PM_SLEEP_WAIT_IDLE: Intermediate state to wait for idle
+ * before going into sleep
+ * @IPC_MEM_HOST_PM_SLEEP_WAIT_D3: Intermediate state to wait for D3
+ * before going to sleep
+ * @IPC_MEM_HOST_PM_SLEEP: after this state the interface is not
+ * accessible host is in suspend to RAM
+ * @IPC_MEM_HOST_PM_SLEEP_WAIT_EXIT_SLEEP: Intermediate state before exiting
+ * sleep
+ */
+enum ipc_mem_host_pm_state {
+ IPC_MEM_HOST_PM_ACTIVE,
+ IPC_MEM_HOST_PM_ACTIVE_WAIT,
+ IPC_MEM_HOST_PM_SLEEP_WAIT_IDLE,
+ IPC_MEM_HOST_PM_SLEEP_WAIT_D3,
+ IPC_MEM_HOST_PM_SLEEP,
+ IPC_MEM_HOST_PM_SLEEP_WAIT_EXIT_SLEEP,
+};
+
+/**
+ * enum ipc_mem_dev_pm_state - Possible states of the DEVICE SLEEP finite state
+ * machine.
+ * @IPC_MEM_DEV_PM_ACTIVE: IPC_MEM_DEV_PM_ACTIVE is the initial
+ * power management state.
+ * IRQ(struct ipc_mem_device_info:
+ * device_sleep_notification)
+ * and DOORBELL-IRQ-HPDA(data) values.
+ * @IPC_MEM_DEV_PM_SLEEP: IPC_MEM_DEV_PM_SLEEP is PM state for
+ * sleep.
+ * @IPC_MEM_DEV_PM_WAKEUP: DOORBELL-IRQ-DEVICE_WAKE(data).
+ * @IPC_MEM_DEV_PM_HOST_SLEEP: DOORBELL-IRQ-HOST_SLEEP(data).
+ * @IPC_MEM_DEV_PM_ACTIVE_WAIT: Local intermediate states.
+ * @IPC_MEM_DEV_PM_FORCE_SLEEP: DOORBELL-IRQ-FORCE_SLEEP.
+ * @IPC_MEM_DEV_PM_FORCE_ACTIVE: DOORBELL-IRQ-FORCE_ACTIVE.
+ */
+enum ipc_mem_dev_pm_state {
+ IPC_MEM_DEV_PM_ACTIVE,
+ IPC_MEM_DEV_PM_SLEEP,
+ IPC_MEM_DEV_PM_WAKEUP,
+ IPC_MEM_DEV_PM_HOST_SLEEP,
+ IPC_MEM_DEV_PM_ACTIVE_WAIT,
+ IPC_MEM_DEV_PM_FORCE_SLEEP = 7,
+ IPC_MEM_DEV_PM_FORCE_ACTIVE,
+};
+
+/**
+ * struct iosm_pm - Power management instance
+ * @pcie: Pointer to iosm_pcie structure
+ * @dev: Pointer to device structure
+ * @host_pm_state: PM states for host
+ * @host_sleep_pend: Variable to indicate Host Sleep Pending
+ * @host_sleep_complete: Generic wait-for-completion used in
+ * case of Host Sleep
+ * @pm_cond: Conditions for power management
+ * @ap_state: Current power management state, the
+ * initial state is IPC_MEM_DEV_PM_ACTIVE eq. 0.
+ * @cp_state: PM State of CP
+ * @device_sleep_notification: last handled device_sleep_notfication
+ * @pending_hpda_update: is a HPDA update pending?
+ */
+struct iosm_pm {
+ struct iosm_pcie *pcie;
+ struct device *dev;
+ enum ipc_mem_host_pm_state host_pm_state;
+ unsigned long host_sleep_pend;
+ struct completion host_sleep_complete;
+ union ipc_pm_cond pm_cond;
+ enum ipc_mem_dev_pm_state ap_state;
+ enum ipc_mem_dev_pm_state cp_state;
+ u32 device_sleep_notification;
+ u8 pending_hpda_update:1;
+};
+
+/**
+ * enum ipc_pm_unit - Power management units.
+ * @IPC_PM_UNIT_IRQ: IRQ towards CP
+ * @IPC_PM_UNIT_HS: Host Sleep for converged protocol
+ * @IPC_PM_UNIT_LINK: Link state controlled by CP.
+ */
+enum ipc_pm_unit {
+ IPC_PM_UNIT_IRQ,
+ IPC_PM_UNIT_HS,
+ IPC_PM_UNIT_LINK,
+};
+
+/**
+ * ipc_pm_init - Allocate power management component
+ * @ipc_protocol: Pointer to iosm_protocol structure
+ */
+void ipc_pm_init(struct iosm_protocol *ipc_protocol);
+
+/**
+ * ipc_pm_deinit - Free power management component, invalidating its pointer.
+ * @ipc_protocol: Pointer to iosm_protocol structure
+ */
+void ipc_pm_deinit(struct iosm_protocol *ipc_protocol);
+
+/**
+ * ipc_pm_dev_slp_notification - Handle a sleep notification message from the
+ * device. This can be called from interrupt state
+ * This function handles Host Sleep requests too
+ * if the Host Sleep protocol is register based.
+ * @ipc_pm: Pointer to power management component
+ * @sleep_notification: Actual notification from device
+ *
+ * Returns: true if dev sleep state has to be checked, false otherwise.
+ */
+bool ipc_pm_dev_slp_notification(struct iosm_pm *ipc_pm,
+ u32 sleep_notification);
+
+/**
+ * ipc_pm_set_s2idle_sleep - Set PM variables to sleep/active
+ * @ipc_pm: Pointer to power management component
+ * @sleep: true to enter sleep/false to exit sleep
+ */
+void ipc_pm_set_s2idle_sleep(struct iosm_pm *ipc_pm, bool sleep);
+
+/**
+ * ipc_pm_prepare_host_sleep - Prepare the PM for sleep by entering
+ * IPC_MEM_HOST_PM_SLEEP_WAIT_D3 state.
+ * @ipc_pm: Pointer to power management component
+ *
+ * Returns: true on success, false if the host was not active.
+ */
+bool ipc_pm_prepare_host_sleep(struct iosm_pm *ipc_pm);
+
+/**
+ * ipc_pm_prepare_host_active - Prepare the PM for wakeup by entering
+ * IPC_MEM_HOST_PM_ACTIVE_WAIT state.
+ * @ipc_pm: Pointer to power management component
+ *
+ * Returns: true on success, false if the host was not sleeping.
+ */
+bool ipc_pm_prepare_host_active(struct iosm_pm *ipc_pm);
+
+/**
+ * ipc_pm_wait_for_device_active - Wait upto IPC_PM_ACTIVE_TIMEOUT_MS ms
+ * for the device to reach active state
+ * @ipc_pm: Pointer to power management component
+ *
+ * Returns: true if device is active, false on timeout
+ */
+bool ipc_pm_wait_for_device_active(struct iosm_pm *ipc_pm);
+
+/**
+ * ipc_pm_signal_hpda_doorbell - Wake up the device if it is in low power mode
+ * and trigger a head pointer update interrupt.
+ * @ipc_pm: Pointer to power management component
+ * @identifier: specifies what component triggered hpda update irq
+ * @host_slp_check: if set to true then Host Sleep state machine check will
+ * be performed. If Host Sleep state machine allows HP
+ * update then only doorbell is triggered otherwise pending
+ * flag will be set. If set to false then Host Sleep check
+ * will not be performed. This is helpful for Host Sleep
+ * negotiation through message ring.
+ */
+void ipc_pm_signal_hpda_doorbell(struct iosm_pm *ipc_pm, u32 identifier,
+ bool host_slp_check);
+/**
+ * ipc_pm_trigger - Update power manager and wake up the link if needed
+ * @ipc_pm: Pointer to power management component
+ * @unit: Power management units
+ * @active: Device link state
+ *
+ * Returns: true if link is unchanged or active, false otherwise
+ */
+bool ipc_pm_trigger(struct iosm_pm *ipc_pm, enum ipc_pm_unit unit, bool active);
+
+#endif
diff --git a/drivers/net/wwan/iosm/iosm_ipc_port.c b/drivers/net/wwan/iosm/iosm_ipc_port.c
new file mode 100644
index 000000000000..beb944847398
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_port.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include "iosm_ipc_chnl_cfg.h"
+#include "iosm_ipc_imem_ops.h"
+#include "iosm_ipc_port.h"
+
+/* open logical channel for control communication */
+static int ipc_port_ctrl_start(struct wwan_port *port)
+{
+ struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port);
+ int ret = 0;
+
+ ipc_port->channel = ipc_imem_sys_port_open(ipc_port->ipc_imem,
+ ipc_port->chl_id,
+ IPC_HP_CDEV_OPEN);
+ if (!ipc_port->channel)
+ ret = -EIO;
+
+ return ret;
+}
+
+/* close logical channel */
+static void ipc_port_ctrl_stop(struct wwan_port *port)
+{
+ struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port);
+
+ ipc_imem_sys_cdev_close(ipc_port);
+}
+
+/* transfer control data to modem */
+static int ipc_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)
+{
+ struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port);
+
+ return ipc_imem_sys_cdev_write(ipc_port, skb);
+}
+
+static const struct wwan_port_ops ipc_wwan_ctrl_ops = {
+ .start = ipc_port_ctrl_start,
+ .stop = ipc_port_ctrl_stop,
+ .tx = ipc_port_ctrl_tx,
+};
+
+/* Port init func */
+struct iosm_cdev *ipc_port_init(struct iosm_imem *ipc_imem,
+ struct ipc_chnl_cfg ipc_port_cfg)
+{
+ struct iosm_cdev *ipc_port = kzalloc(sizeof(*ipc_port), GFP_KERNEL);
+ enum wwan_port_type port_type = ipc_port_cfg.wwan_port_type;
+ enum ipc_channel_id chl_id = ipc_port_cfg.id;
+
+ if (!ipc_port)
+ return NULL;
+
+ ipc_port->dev = ipc_imem->dev;
+ ipc_port->pcie = ipc_imem->pcie;
+
+ ipc_port->port_type = port_type;
+ ipc_port->chl_id = chl_id;
+ ipc_port->ipc_imem = ipc_imem;
+
+ ipc_port->iosm_port = wwan_create_port(ipc_port->dev, port_type,
+ &ipc_wwan_ctrl_ops, ipc_port);
+
+ return ipc_port;
+}
+
+/* Port deinit func */
+void ipc_port_deinit(struct iosm_cdev *port[])
+{
+ struct iosm_cdev *ipc_port;
+ u8 ctrl_chl_nr;
+
+ for (ctrl_chl_nr = 0; ctrl_chl_nr < IPC_MEM_MAX_CHANNELS;
+ ctrl_chl_nr++) {
+ if (port[ctrl_chl_nr]) {
+ ipc_port = port[ctrl_chl_nr];
+ wwan_remove_port(ipc_port->iosm_port);
+ kfree(ipc_port);
+ }
+ }
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_port.h b/drivers/net/wwan/iosm/iosm_ipc_port.h
new file mode 100644
index 000000000000..11bc8ed21616
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_port.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#ifndef IOSM_IPC_PORT_H
+#define IOSM_IPC_PORT_H
+
+#include <linux/wwan.h>
+
+#include "iosm_ipc_imem_ops.h"
+
+/**
+ * struct iosm_cdev - State of the char driver layer.
+ * @iosm_port: Pointer of type wwan_port
+ * @ipc_imem: imem instance
+ * @dev: Pointer to device struct
+ * @pcie: PCIe component
+ * @port_type: WWAN port type
+ * @channel: Channel instance
+ * @chl_id: Channel Indentifier
+ */
+struct iosm_cdev {
+ struct wwan_port *iosm_port;
+ struct iosm_imem *ipc_imem;
+ struct device *dev;
+ struct iosm_pcie *pcie;
+ enum wwan_port_type port_type;
+ struct ipc_mem_channel *channel;
+ enum ipc_channel_id chl_id;
+};
+
+/**
+ * ipc_port_init - Allocate IPC port & register to wwan subsystem for AT/MBIM
+ * communication.
+ * @ipc_imem: Pointer to iosm_imem structure
+ * @ipc_port_cfg: IPC Port Config
+ *
+ * Returns: 0 on success & NULL on failure
+ */
+struct iosm_cdev *ipc_port_init(struct iosm_imem *ipc_imem,
+ struct ipc_chnl_cfg ipc_port_cfg);
+
+/**
+ * ipc_port_deinit - Free IPC port & unregister port with wwan subsystem.
+ * @ipc_port: Array of pointer to the ipc port data-struct
+ */
+void ipc_port_deinit(struct iosm_cdev *ipc_port[]);
+
+#endif
diff --git a/drivers/net/wwan/iosm/iosm_ipc_protocol.c b/drivers/net/wwan/iosm/iosm_ipc_protocol.c
new file mode 100644
index 000000000000..834d8b146a94
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_protocol.c
@@ -0,0 +1,283 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include "iosm_ipc_imem.h"
+#include "iosm_ipc_protocol.h"
+#include "iosm_ipc_protocol_ops.h"
+#include "iosm_ipc_pm.h"
+#include "iosm_ipc_task_queue.h"
+
+int ipc_protocol_tq_msg_send(struct iosm_protocol *ipc_protocol,
+ enum ipc_msg_prep_type msg_type,
+ union ipc_msg_prep_args *prep_args,
+ struct ipc_rsp *response)
+{
+ int index = ipc_protocol_msg_prep(ipc_protocol->imem, msg_type,
+ prep_args);
+
+ /* Store reference towards caller specified response in response ring
+ * and signal CP
+ */
+ if (index >= 0 && index < IPC_MEM_MSG_ENTRIES) {
+ ipc_protocol->rsp_ring[index] = response;
+ ipc_protocol_msg_hp_update(ipc_protocol->imem);
+ }
+
+ return index;
+}
+
+/* Callback for message send */
+static int ipc_protocol_tq_msg_send_cb(struct iosm_imem *ipc_imem, int arg,
+ void *msg, size_t size)
+{
+ struct ipc_call_msg_send_args *send_args = msg;
+ struct iosm_protocol *ipc_protocol = ipc_imem->ipc_protocol;
+
+ return ipc_protocol_tq_msg_send(ipc_protocol, send_args->msg_type,
+ send_args->prep_args,
+ send_args->response);
+}
+
+/* Remove reference to a response. This is typically used when a requestor timed
+ * out and is no longer interested in the response.
+ */
+static int ipc_protocol_tq_msg_remove(struct iosm_imem *ipc_imem, int arg,
+ void *msg, size_t size)
+{
+ struct iosm_protocol *ipc_protocol = ipc_imem->ipc_protocol;
+
+ ipc_protocol->rsp_ring[arg] = NULL;
+ return 0;
+}
+
+int ipc_protocol_msg_send(struct iosm_protocol *ipc_protocol,
+ enum ipc_msg_prep_type prep,
+ union ipc_msg_prep_args *prep_args)
+{
+ struct ipc_call_msg_send_args send_args;
+ unsigned int exec_timeout;
+ struct ipc_rsp response;
+ int index;
+
+ exec_timeout = (ipc_protocol_get_ap_exec_stage(ipc_protocol) ==
+ IPC_MEM_EXEC_STAGE_RUN ?
+ IPC_MSG_COMPLETE_RUN_DEFAULT_TIMEOUT :
+ IPC_MSG_COMPLETE_BOOT_DEFAULT_TIMEOUT);
+
+ /* Trap if called from non-preemptible context */
+ might_sleep();
+
+ response.status = IPC_MEM_MSG_CS_INVALID;
+ init_completion(&response.completion);
+
+ send_args.msg_type = prep;
+ send_args.prep_args = prep_args;
+ send_args.response = &response;
+
+ /* Allocate and prepare message to be sent in tasklet context.
+ * A positive index returned form tasklet_call references the message
+ * in case it needs to be cancelled when there is a timeout.
+ */
+ index = ipc_task_queue_send_task(ipc_protocol->imem,
+ ipc_protocol_tq_msg_send_cb, 0,
+ &send_args, 0, true);
+
+ if (index < 0) {
+ dev_err(ipc_protocol->dev, "msg %d failed", prep);
+ return index;
+ }
+
+ /* Wait for the device to respond to the message */
+ switch (wait_for_completion_timeout(&response.completion,
+ msecs_to_jiffies(exec_timeout))) {
+ case 0:
+ /* Timeout, there was no response from the device.
+ * Remove the reference to the local response completion
+ * object as we are no longer interested in the response.
+ */
+ ipc_task_queue_send_task(ipc_protocol->imem,
+ ipc_protocol_tq_msg_remove, index,
+ NULL, 0, true);
+ dev_err(ipc_protocol->dev, "msg timeout");
+ ipc_uevent_send(ipc_protocol->pcie->dev, UEVENT_MDM_TIMEOUT);
+ break;
+ default:
+ /* We got a response in time; check completion status: */
+ if (response.status != IPC_MEM_MSG_CS_SUCCESS) {
+ dev_err(ipc_protocol->dev,
+ "msg completion status error %d",
+ response.status);
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static int ipc_protocol_msg_send_host_sleep(struct iosm_protocol *ipc_protocol,
+ u32 state)
+{
+ union ipc_msg_prep_args prep_args = {
+ .sleep.target = 0,
+ .sleep.state = state,
+ };
+
+ return ipc_protocol_msg_send(ipc_protocol, IPC_MSG_PREP_SLEEP,
+ &prep_args);
+}
+
+void ipc_protocol_doorbell_trigger(struct iosm_protocol *ipc_protocol,
+ u32 identifier)
+{
+ ipc_pm_signal_hpda_doorbell(&ipc_protocol->pm, identifier, true);
+}
+
+bool ipc_protocol_pm_dev_sleep_handle(struct iosm_protocol *ipc_protocol)
+{
+ u32 ipc_status = ipc_protocol_get_ipc_status(ipc_protocol);
+ u32 requested;
+
+ if (ipc_status != IPC_MEM_DEVICE_IPC_RUNNING) {
+ dev_err(ipc_protocol->dev,
+ "irq ignored, CP IPC state is %d, should be RUNNING",
+ ipc_status);
+
+ /* Stop further processing. */
+ return false;
+ }
+
+ /* Get a copy of the requested PM state by the device and the local
+ * device PM state.
+ */
+ requested = ipc_protocol_pm_dev_get_sleep_notification(ipc_protocol);
+
+ return ipc_pm_dev_slp_notification(&ipc_protocol->pm, requested);
+}
+
+static int ipc_protocol_tq_wakeup_dev_slp(struct iosm_imem *ipc_imem, int arg,
+ void *msg, size_t size)
+{
+ struct iosm_pm *ipc_pm = &ipc_imem->ipc_protocol->pm;
+
+ /* Wakeup from device sleep if it is not ACTIVE */
+ ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_HS, true);
+
+ ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_HS, false);
+
+ return 0;
+}
+
+void ipc_protocol_s2idle_sleep(struct iosm_protocol *ipc_protocol, bool sleep)
+{
+ ipc_pm_set_s2idle_sleep(&ipc_protocol->pm, sleep);
+}
+
+bool ipc_protocol_suspend(struct iosm_protocol *ipc_protocol)
+{
+ if (!ipc_pm_prepare_host_sleep(&ipc_protocol->pm))
+ goto err;
+
+ ipc_task_queue_send_task(ipc_protocol->imem,
+ ipc_protocol_tq_wakeup_dev_slp, 0, NULL, 0,
+ true);
+
+ if (!ipc_pm_wait_for_device_active(&ipc_protocol->pm)) {
+ ipc_uevent_send(ipc_protocol->pcie->dev, UEVENT_MDM_TIMEOUT);
+ goto err;
+ }
+
+ /* Send the sleep message for sync sys calls. */
+ dev_dbg(ipc_protocol->dev, "send TARGET_HOST, ENTER_SLEEP");
+ if (ipc_protocol_msg_send_host_sleep(ipc_protocol,
+ IPC_HOST_SLEEP_ENTER_SLEEP)) {
+ /* Sending ENTER_SLEEP message failed, we are still active */
+ ipc_protocol->pm.host_pm_state = IPC_MEM_HOST_PM_ACTIVE;
+ goto err;
+ }
+
+ ipc_protocol->pm.host_pm_state = IPC_MEM_HOST_PM_SLEEP;
+ return true;
+err:
+ return false;
+}
+
+bool ipc_protocol_resume(struct iosm_protocol *ipc_protocol)
+{
+ if (!ipc_pm_prepare_host_active(&ipc_protocol->pm))
+ return false;
+
+ dev_dbg(ipc_protocol->dev, "send TARGET_HOST, EXIT_SLEEP");
+ if (ipc_protocol_msg_send_host_sleep(ipc_protocol,
+ IPC_HOST_SLEEP_EXIT_SLEEP)) {
+ ipc_protocol->pm.host_pm_state = IPC_MEM_HOST_PM_SLEEP;
+ return false;
+ }
+
+ ipc_protocol->pm.host_pm_state = IPC_MEM_HOST_PM_ACTIVE;
+
+ return true;
+}
+
+struct iosm_protocol *ipc_protocol_init(struct iosm_imem *ipc_imem)
+{
+ struct iosm_protocol *ipc_protocol =
+ kzalloc(sizeof(*ipc_protocol), GFP_KERNEL);
+ struct ipc_protocol_context_info *p_ci;
+ u64 addr;
+
+ if (!ipc_protocol)
+ return NULL;
+
+ ipc_protocol->dev = ipc_imem->dev;
+ ipc_protocol->pcie = ipc_imem->pcie;
+ ipc_protocol->imem = ipc_imem;
+ ipc_protocol->p_ap_shm = NULL;
+ ipc_protocol->phy_ap_shm = 0;
+
+ ipc_protocol->old_msg_tail = 0;
+
+ ipc_protocol->p_ap_shm =
+ pci_alloc_consistent(ipc_protocol->pcie->pci,
+ sizeof(*ipc_protocol->p_ap_shm),
+ &ipc_protocol->phy_ap_shm);
+
+ if (!ipc_protocol->p_ap_shm) {
+ dev_err(ipc_protocol->dev, "pci shm alloc error");
+ kfree(ipc_protocol);
+ return NULL;
+ }
+
+ /* Prepare the context info for CP. */
+ addr = ipc_protocol->phy_ap_shm;
+ p_ci = &ipc_protocol->p_ap_shm->ci;
+ p_ci->device_info_addr =
+ addr + offsetof(struct ipc_protocol_ap_shm, device_info);
+ p_ci->head_array =
+ addr + offsetof(struct ipc_protocol_ap_shm, head_array);
+ p_ci->tail_array =
+ addr + offsetof(struct ipc_protocol_ap_shm, tail_array);
+ p_ci->msg_head = addr + offsetof(struct ipc_protocol_ap_shm, msg_head);
+ p_ci->msg_tail = addr + offsetof(struct ipc_protocol_ap_shm, msg_tail);
+ p_ci->msg_ring_addr =
+ addr + offsetof(struct ipc_protocol_ap_shm, msg_ring);
+ p_ci->msg_ring_entries = cpu_to_le16(IPC_MEM_MSG_ENTRIES);
+ p_ci->msg_irq_vector = IPC_MSG_IRQ_VECTOR;
+ p_ci->device_info_irq_vector = IPC_DEVICE_IRQ_VECTOR;
+
+ ipc_mmio_set_contex_info_addr(ipc_imem->mmio, addr);
+
+ ipc_pm_init(ipc_protocol);
+
+ return ipc_protocol;
+}
+
+void ipc_protocol_deinit(struct iosm_protocol *proto)
+{
+ pci_free_consistent(proto->pcie->pci, sizeof(*proto->p_ap_shm),
+ proto->p_ap_shm, proto->phy_ap_shm);
+
+ ipc_pm_deinit(proto);
+ kfree(proto);
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_protocol.h b/drivers/net/wwan/iosm/iosm_ipc_protocol.h
new file mode 100644
index 000000000000..9b3a6d86ece7
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_protocol.h
@@ -0,0 +1,237 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#ifndef IOSM_IPC_PROTOCOL_H
+#define IOSM_IPC_PROTOCOL_H
+
+#include "iosm_ipc_imem.h"
+#include "iosm_ipc_pm.h"
+#include "iosm_ipc_protocol_ops.h"
+
+/* Trigger the doorbell interrupt on CP. */
+#define IPC_DOORBELL_IRQ_HPDA 0
+#define IPC_DOORBELL_IRQ_IPC 1
+#define IPC_DOORBELL_IRQ_SLEEP 2
+
+/* IRQ vector number. */
+#define IPC_DEVICE_IRQ_VECTOR 0
+#define IPC_MSG_IRQ_VECTOR 0
+#define IPC_UL_PIPE_IRQ_VECTOR 0
+#define IPC_DL_PIPE_IRQ_VECTOR 0
+
+#define IPC_MEM_MSG_ENTRIES 128
+
+/* Default time out for sending IPC messages like open pipe, close pipe etc.
+ * during run mode.
+ *
+ * If the message interface lock to CP times out, the link to CP is broken.
+ * mode : run mode (IPC_MEM_EXEC_STAGE_RUN)
+ * unit : milliseconds
+ */
+#define IPC_MSG_COMPLETE_RUN_DEFAULT_TIMEOUT 500 /* 0.5 seconds */
+
+/* Default time out for sending IPC messages like open pipe, close pipe etc.
+ * during boot mode.
+ *
+ * If the message interface lock to CP times out, the link to CP is broken.
+ * mode : boot mode
+ * (IPC_MEM_EXEC_STAGE_BOOT | IPC_MEM_EXEC_STAGE_PSI | IPC_MEM_EXEC_STAGE_EBL)
+ * unit : milliseconds
+ */
+#define IPC_MSG_COMPLETE_BOOT_DEFAULT_TIMEOUT 500 /* 0.5 seconds */
+
+/**
+ * struct ipc_protocol_context_info - Structure of the context info
+ * @device_info_addr: 64 bit address to device info
+ * @head_array: 64 bit address to head pointer arr for the pipes
+ * @tail_array: 64 bit address to tail pointer arr for the pipes
+ * @msg_head: 64 bit address to message head pointer
+ * @msg_tail: 64 bit address to message tail pointer
+ * @msg_ring_addr: 64 bit pointer to the message ring buffer
+ * @msg_ring_entries: This field provides the number of entries which
+ * the MR can hold
+ * @msg_irq_vector: This field provides the IRQ which shall be
+ * generated by the EP device when generating
+ * completion for Messages.
+ * @device_info_irq_vector: This field provides the IRQ which shall be
+ * generated by the EP dev after updating Dev. Info
+ */
+struct ipc_protocol_context_info {
+ phys_addr_t device_info_addr;
+ phys_addr_t head_array;
+ phys_addr_t tail_array;
+ phys_addr_t msg_head;
+ phys_addr_t msg_tail;
+ phys_addr_t msg_ring_addr;
+ __le16 msg_ring_entries;
+ u8 msg_irq_vector;
+ u8 device_info_irq_vector;
+};
+
+/**
+ * struct ipc_protocol_device_info - Structure for the device information
+ * @execution_stage: CP execution stage
+ * @ipc_status: IPC states
+ * @device_sleep_notification: Requested device pm states
+ */
+struct ipc_protocol_device_info {
+ __le32 execution_stage;
+ __le32 ipc_status;
+ __le32 device_sleep_notification;
+};
+
+/**
+ * struct ipc_protocol_ap_shm - Protocol Shared Memory Structure
+ * @ci: Context information struct
+ * @device_info: Device information struct
+ * @msg_head: Point to msg head
+ * @head_array: Array of head pointer
+ * @msg_tail: Point to msg tail
+ * @tail_array: Array of tail pointer
+ * @msg_ring: Circular buffers for the read/tail and write/head
+ * indeces.
+ */
+struct ipc_protocol_ap_shm {
+ struct ipc_protocol_context_info ci;
+ struct ipc_protocol_device_info device_info;
+ __le32 msg_head;
+ __le32 head_array[IPC_MEM_MAX_PIPES];
+ __le32 msg_tail;
+ __le32 tail_array[IPC_MEM_MAX_PIPES];
+ union ipc_mem_msg_entry msg_ring[IPC_MEM_MSG_ENTRIES];
+};
+
+/**
+ * struct iosm_protocol - Structure for IPC protocol.
+ * @p_ap_shm: Pointer to Protocol Shared Memory Structure
+ * @pm: Instance to struct iosm_pm
+ * @pcie: Pointer to struct iosm_pcie
+ * @imem: Pointer to struct iosm_imem
+ * @rsp_ring: Array of OS completion objects to be triggered once CP
+ * acknowledges a request in the message ring
+ * @dev: Pointer to device structure
+ * @phy_ap_shm: Physical/Mapped representation of the shared memory info
+ * @old_msg_tail: Old msg tail ptr, until AP has handled ACK's from CP
+ */
+struct iosm_protocol {
+ struct ipc_protocol_ap_shm *p_ap_shm;
+ struct iosm_pm pm;
+ struct iosm_pcie *pcie;
+ struct iosm_imem *imem;
+ struct ipc_rsp *rsp_ring[IPC_MEM_MSG_ENTRIES];
+ struct device *dev;
+ phys_addr_t phy_ap_shm;
+ u32 old_msg_tail;
+};
+
+/**
+ * struct ipc_call_msg_send_args - Structure for message argument for
+ * tasklet function.
+ * @prep_args: Arguments for message preparation function
+ * @response: Can be NULL if result can be ignored
+ * @msg_type: Message Type
+ */
+struct ipc_call_msg_send_args {
+ union ipc_msg_prep_args *prep_args;
+ struct ipc_rsp *response;
+ enum ipc_msg_prep_type msg_type;
+};
+
+/**
+ * ipc_protocol_tq_msg_send - prepare the msg and send to CP
+ * @ipc_protocol: Pointer to ipc_protocol instance
+ * @msg_type: Message type
+ * @prep_args: Message arguments
+ * @response: Pointer to a response object which has a
+ * completion object and return code.
+ *
+ * Returns: 0 on success and failure value on error
+ */
+int ipc_protocol_tq_msg_send(struct iosm_protocol *ipc_protocol,
+ enum ipc_msg_prep_type msg_type,
+ union ipc_msg_prep_args *prep_args,
+ struct ipc_rsp *response);
+
+/**
+ * ipc_protocol_msg_send - Send ipc control message to CP and wait for response
+ * @ipc_protocol: Pointer to ipc_protocol instance
+ * @prep: Message type
+ * @prep_args: Message arguments
+ *
+ * Returns: 0 on success and failure value on error
+ */
+int ipc_protocol_msg_send(struct iosm_protocol *ipc_protocol,
+ enum ipc_msg_prep_type prep,
+ union ipc_msg_prep_args *prep_args);
+
+/**
+ * ipc_protocol_suspend - Signal to CP that host wants to go to sleep (suspend).
+ * @ipc_protocol: Pointer to ipc_protocol instance
+ *
+ * Returns: true if host can suspend, false if suspend must be aborted.
+ */
+bool ipc_protocol_suspend(struct iosm_protocol *ipc_protocol);
+
+/**
+ * ipc_protocol_s2idle_sleep - Call PM function to set PM variables in s2idle
+ * sleep/active case
+ * @ipc_protocol: Pointer to ipc_protocol instance
+ * @sleep: True for sleep/False for active
+ */
+void ipc_protocol_s2idle_sleep(struct iosm_protocol *ipc_protocol, bool sleep);
+
+/**
+ * ipc_protocol_resume - Signal to CP that host wants to resume operation.
+ * @ipc_protocol: Pointer to ipc_protocol instance
+ *
+ * Returns: true if host can resume, false if there is a problem.
+ */
+bool ipc_protocol_resume(struct iosm_protocol *ipc_protocol);
+
+/**
+ * ipc_protocol_pm_dev_sleep_handle - Handles the Device Sleep state change
+ * notification.
+ * @ipc_protocol: Pointer to ipc_protocol instance.
+ *
+ * Returns: true if sleep notification handled, false otherwise.
+ */
+bool ipc_protocol_pm_dev_sleep_handle(struct iosm_protocol *ipc_protocol);
+
+/**
+ * ipc_protocol_doorbell_trigger - Wrapper for PM function which wake up the
+ * device if it is in low power mode
+ * and trigger a head pointer update interrupt.
+ * @ipc_protocol: Pointer to ipc_protocol instance.
+ * @identifier: Specifies what component triggered hpda
+ * update irq
+ */
+void ipc_protocol_doorbell_trigger(struct iosm_protocol *ipc_protocol,
+ u32 identifier);
+
+/**
+ * ipc_protocol_sleep_notification_string - Returns last Sleep Notification as
+ * string.
+ * @ipc_protocol: Instance pointer of Protocol module.
+ *
+ * Returns: Pointer to string.
+ */
+const char *
+ipc_protocol_sleep_notification_string(struct iosm_protocol *ipc_protocol);
+
+/**
+ * ipc_protocol_init - Allocates IPC protocol instance
+ * @ipc_imem: Pointer to iosm_imem structure
+ *
+ * Returns: Address of IPC protocol instance on success & NULL on failure.
+ */
+struct iosm_protocol *ipc_protocol_init(struct iosm_imem *ipc_imem);
+
+/**
+ * ipc_protocol_deinit - Deallocates IPC protocol instance
+ * @ipc_protocol: pointer to the IPC protocol instance
+ */
+void ipc_protocol_deinit(struct iosm_protocol *ipc_protocol);
+
+#endif
diff --git a/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c b/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c
new file mode 100644
index 000000000000..91109e27efd3
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c
@@ -0,0 +1,552 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include "iosm_ipc_protocol.h"
+#include "iosm_ipc_protocol_ops.h"
+
+/* Get the next free message element.*/
+static union ipc_mem_msg_entry *
+ipc_protocol_free_msg_get(struct iosm_protocol *ipc_protocol, int *index)
+{
+ u32 head = le32_to_cpu(ipc_protocol->p_ap_shm->msg_head);
+ u32 new_head = (head + 1) % IPC_MEM_MSG_ENTRIES;
+ union ipc_mem_msg_entry *msg;
+
+ if (new_head == le32_to_cpu(ipc_protocol->p_ap_shm->msg_tail)) {
+ dev_err(ipc_protocol->dev, "message ring is full");
+ return NULL;
+ }
+
+ /* Get the pointer to the next free message element,
+ * reset the fields and mark is as invalid.
+ */
+ msg = &ipc_protocol->p_ap_shm->msg_ring[head];
+ memset(msg, 0, sizeof(*msg));
+
+ /* return index in message ring */
+ *index = head;
+
+ return msg;
+}
+
+/* Updates the message ring Head pointer */
+void ipc_protocol_msg_hp_update(struct iosm_imem *ipc_imem)
+{
+ struct iosm_protocol *ipc_protocol = ipc_imem->ipc_protocol;
+ u32 head = le32_to_cpu(ipc_protocol->p_ap_shm->msg_head);
+ u32 new_head = (head + 1) % IPC_MEM_MSG_ENTRIES;
+
+ /* Update head pointer and fire doorbell. */
+ ipc_protocol->p_ap_shm->msg_head = cpu_to_le32(new_head);
+ ipc_protocol->old_msg_tail =
+ le32_to_cpu(ipc_protocol->p_ap_shm->msg_tail);
+
+ ipc_pm_signal_hpda_doorbell(&ipc_protocol->pm, IPC_HP_MR, false);
+}
+
+/* Allocate and prepare a OPEN_PIPE message.
+ * This also allocates the memory for the new TDR structure and
+ * updates the pipe structure referenced in the preparation arguments.
+ */
+static int ipc_protocol_msg_prepipe_open(struct iosm_protocol *ipc_protocol,
+ union ipc_msg_prep_args *args)
+{
+ int index;
+ union ipc_mem_msg_entry *msg =
+ ipc_protocol_free_msg_get(ipc_protocol, &index);
+ struct ipc_pipe *pipe = args->pipe_open.pipe;
+ struct ipc_protocol_td *tdr;
+ struct sk_buff **skbr;
+
+ if (!msg) {
+ dev_err(ipc_protocol->dev, "failed to get free message");
+ return -EIO;
+ }
+
+ /* Allocate the skbuf elements for the skbuf which are on the way.
+ * SKB ring is internal memory allocation for driver. No need to
+ * re-calculate the start and end addresses.
+ */
+ skbr = kcalloc(pipe->nr_of_entries, sizeof(*skbr), GFP_ATOMIC);
+ if (!skbr)
+ return -ENOMEM;
+
+ /* Allocate the transfer descriptors for the pipe. */
+ tdr = pci_alloc_consistent(ipc_protocol->pcie->pci,
+ pipe->nr_of_entries * sizeof(*tdr),
+ &pipe->phy_tdr_start);
+ if (!tdr) {
+ kfree(skbr);
+ dev_err(ipc_protocol->dev, "tdr alloc error");
+ return -ENOMEM;
+ }
+
+ pipe->max_nr_of_queued_entries = pipe->nr_of_entries - 1;
+ pipe->nr_of_queued_entries = 0;
+ pipe->tdr_start = tdr;
+ pipe->skbr_start = skbr;
+ pipe->old_tail = 0;
+
+ ipc_protocol->p_ap_shm->head_array[pipe->pipe_nr] = 0;
+
+ msg->open_pipe.type_of_message = IPC_MEM_MSG_OPEN_PIPE;
+ msg->open_pipe.pipe_nr = pipe->pipe_nr;
+ msg->open_pipe.tdr_addr = cpu_to_le64(pipe->phy_tdr_start);
+ msg->open_pipe.tdr_entries = cpu_to_le16(pipe->nr_of_entries);
+ msg->open_pipe.accumulation_backoff =
+ cpu_to_le32(pipe->accumulation_backoff);
+ msg->open_pipe.irq_vector = cpu_to_le32(pipe->irq);
+
+ return index;
+}
+
+static int ipc_protocol_msg_prepipe_close(struct iosm_protocol *ipc_protocol,
+ union ipc_msg_prep_args *args)
+{
+ int index = -1;
+ union ipc_mem_msg_entry *msg =
+ ipc_protocol_free_msg_get(ipc_protocol, &index);
+ struct ipc_pipe *pipe = args->pipe_close.pipe;
+
+ if (!msg)
+ return -EIO;
+
+ msg->close_pipe.type_of_message = IPC_MEM_MSG_CLOSE_PIPE;
+ msg->close_pipe.pipe_nr = pipe->pipe_nr;
+
+ dev_dbg(ipc_protocol->dev, "IPC_MEM_MSG_CLOSE_PIPE(pipe_nr=%d)",
+ msg->close_pipe.pipe_nr);
+
+ return index;
+}
+
+static int ipc_protocol_msg_prep_sleep(struct iosm_protocol *ipc_protocol,
+ union ipc_msg_prep_args *args)
+{
+ int index = -1;
+ union ipc_mem_msg_entry *msg =
+ ipc_protocol_free_msg_get(ipc_protocol, &index);
+
+ if (!msg) {
+ dev_err(ipc_protocol->dev, "failed to get free message");
+ return -EIO;
+ }
+
+ /* Prepare and send the host sleep message to CP to enter or exit D3. */
+ msg->host_sleep.type_of_message = IPC_MEM_MSG_SLEEP;
+ msg->host_sleep.target = args->sleep.target; /* 0=host, 1=device */
+
+ /* state; 0=enter, 1=exit 2=enter w/o protocol */
+ msg->host_sleep.state = args->sleep.state;
+
+ dev_dbg(ipc_protocol->dev, "IPC_MEM_MSG_SLEEP(target=%d; state=%d)",
+ msg->host_sleep.target, msg->host_sleep.state);
+
+ return index;
+}
+
+static int ipc_protocol_msg_prep_feature_set(struct iosm_protocol *ipc_protocol,
+ union ipc_msg_prep_args *args)
+{
+ int index = -1;
+ union ipc_mem_msg_entry *msg =
+ ipc_protocol_free_msg_get(ipc_protocol, &index);
+
+ if (!msg) {
+ dev_err(ipc_protocol->dev, "failed to get free message");
+ return -EIO;
+ }
+
+ msg->feature_set.type_of_message = IPC_MEM_MSG_FEATURE_SET;
+ msg->feature_set.reset_enable = args->feature_set.reset_enable <<
+ RESET_BIT;
+
+ dev_dbg(ipc_protocol->dev, "IPC_MEM_MSG_FEATURE_SET(reset_enable=%d)",
+ msg->feature_set.reset_enable >> RESET_BIT);
+
+ return index;
+}
+
+/* Processes the message consumed by CP. */
+bool ipc_protocol_msg_process(struct iosm_imem *ipc_imem, int irq)
+{
+ struct iosm_protocol *ipc_protocol = ipc_imem->ipc_protocol;
+ struct ipc_rsp **rsp_ring = ipc_protocol->rsp_ring;
+ bool msg_processed = false;
+ u32 i;
+
+ if (le32_to_cpu(ipc_protocol->p_ap_shm->msg_tail) >=
+ IPC_MEM_MSG_ENTRIES) {
+ dev_err(ipc_protocol->dev, "msg_tail out of range: %d",
+ le32_to_cpu(ipc_protocol->p_ap_shm->msg_tail));
+ return msg_processed;
+ }
+
+ if (irq != IMEM_IRQ_DONT_CARE &&
+ irq != ipc_protocol->p_ap_shm->ci.msg_irq_vector)
+ return msg_processed;
+
+ for (i = ipc_protocol->old_msg_tail;
+ i != le32_to_cpu(ipc_protocol->p_ap_shm->msg_tail);
+ i = (i + 1) % IPC_MEM_MSG_ENTRIES) {
+ union ipc_mem_msg_entry *msg =
+ &ipc_protocol->p_ap_shm->msg_ring[i];
+
+ dev_dbg(ipc_protocol->dev, "msg[%d]: type=%u status=%d", i,
+ msg->common.type_of_message,
+ msg->common.completion_status);
+
+ /* Update response with status and wake up waiting requestor */
+ if (rsp_ring[i]) {
+ rsp_ring[i]->status =
+ le32_to_cpu(msg->common.completion_status);
+ complete(&rsp_ring[i]->completion);
+ rsp_ring[i] = NULL;
+ }
+ msg_processed = true;
+ }
+
+ ipc_protocol->old_msg_tail = i;
+ return msg_processed;
+}
+
+/* Sends data from UL list to CP for the provided pipe by updating the Head
+ * pointer of given pipe.
+ */
+bool ipc_protocol_ul_td_send(struct iosm_protocol *ipc_protocol,
+ struct ipc_pipe *pipe,
+ struct sk_buff_head *p_ul_list)
+{
+ struct ipc_protocol_td *td;
+ bool hpda_pending = false;
+ struct sk_buff *skb;
+ s32 free_elements;
+ u32 head;
+ u32 tail;
+
+ if (!ipc_protocol->p_ap_shm) {
+ dev_err(ipc_protocol->dev, "driver is not initialized");
+ return false;
+ }
+
+ /* Get head and tail of the td list and calculate
+ * the number of free elements.
+ */
+ head = le32_to_cpu(ipc_protocol->p_ap_shm->head_array[pipe->pipe_nr]);
+ tail = pipe->old_tail;
+
+ while (!skb_queue_empty(p_ul_list)) {
+ if (head < tail)
+ free_elements = tail - head - 1;
+ else
+ free_elements =
+ pipe->nr_of_entries - head + ((s32)tail - 1);
+
+ if (free_elements <= 0) {
+ dev_dbg(ipc_protocol->dev,
+ "no free td elements for UL pipe %d",
+ pipe->pipe_nr);
+ break;
+ }
+
+ /* Get the td address. */
+ td = &pipe->tdr_start[head];
+
+ /* Take the first element of the uplink list and add it
+ * to the td list.
+ */
+ skb = skb_dequeue(p_ul_list);
+ if (WARN_ON(!skb))
+ break;
+
+ /* Save the reference to the uplink skbuf. */
+ pipe->skbr_start[head] = skb;
+
+ td->buffer.address = IPC_CB(skb)->mapping;
+ td->scs = cpu_to_le32(skb->len) & cpu_to_le32(SIZE_MASK);
+ td->next = 0;
+
+ pipe->nr_of_queued_entries++;
+
+ /* Calculate the new head and save it. */
+ head++;
+ if (head >= pipe->nr_of_entries)
+ head = 0;
+
+ ipc_protocol->p_ap_shm->head_array[pipe->pipe_nr] =
+ cpu_to_le32(head);
+ }
+
+ if (pipe->old_head != head) {
+ dev_dbg(ipc_protocol->dev, "New UL TDs Pipe:%d", pipe->pipe_nr);
+
+ pipe->old_head = head;
+ /* Trigger doorbell because of pending UL packets. */
+ hpda_pending = true;
+ }
+
+ return hpda_pending;
+}
+
+/* Checks for Tail pointer update from CP and returns the data as SKB. */
+struct sk_buff *ipc_protocol_ul_td_process(struct iosm_protocol *ipc_protocol,
+ struct ipc_pipe *pipe)
+{
+ struct ipc_protocol_td *p_td = &pipe->tdr_start[pipe->old_tail];
+ struct sk_buff *skb = pipe->skbr_start[pipe->old_tail];
+
+ pipe->nr_of_queued_entries--;
+ pipe->old_tail++;
+ if (pipe->old_tail >= pipe->nr_of_entries)
+ pipe->old_tail = 0;
+
+ if (!p_td->buffer.address) {
+ dev_err(ipc_protocol->dev, "Td buffer address is NULL");
+ return NULL;
+ }
+
+ if (p_td->buffer.address != IPC_CB(skb)->mapping) {
+ dev_err(ipc_protocol->dev,
+ "pipe %d: invalid buf_addr or skb_data",
+ pipe->pipe_nr);
+ return NULL;
+ }
+
+ return skb;
+}
+
+/* Allocates an SKB for CP to send data and updates the Head Pointer
+ * of the given Pipe#.
+ */
+bool ipc_protocol_dl_td_prepare(struct iosm_protocol *ipc_protocol,
+ struct ipc_pipe *pipe)
+{
+ struct ipc_protocol_td *td;
+ dma_addr_t mapping = 0;
+ u32 head, new_head;
+ struct sk_buff *skb;
+ u32 tail;
+
+ /* Get head and tail of the td list and calculate
+ * the number of free elements.
+ */
+ head = le32_to_cpu(ipc_protocol->p_ap_shm->head_array[pipe->pipe_nr]);
+ tail = le32_to_cpu(ipc_protocol->p_ap_shm->tail_array[pipe->pipe_nr]);
+
+ new_head = head + 1;
+ if (new_head >= pipe->nr_of_entries)
+ new_head = 0;
+
+ if (new_head == tail)
+ return false;
+
+ /* Get the td address. */
+ td = &pipe->tdr_start[head];
+
+ /* Allocate the skbuf for the descriptor. */
+ skb = ipc_pcie_alloc_skb(ipc_protocol->pcie, pipe->buf_size, GFP_ATOMIC,
+ &mapping, DMA_FROM_DEVICE,
+ IPC_MEM_DL_ETH_OFFSET);
+ if (!skb)
+ return false;
+
+ td->buffer.address = mapping;
+ td->scs = cpu_to_le32(pipe->buf_size) & cpu_to_le32(SIZE_MASK);
+ td->next = 0;
+
+ /* store the new head value. */
+ ipc_protocol->p_ap_shm->head_array[pipe->pipe_nr] =
+ cpu_to_le32(new_head);
+
+ /* Save the reference to the skbuf. */
+ pipe->skbr_start[head] = skb;
+
+ pipe->nr_of_queued_entries++;
+
+ return true;
+}
+
+/* Processes DL TD's */
+struct sk_buff *ipc_protocol_dl_td_process(struct iosm_protocol *ipc_protocol,
+ struct ipc_pipe *pipe)
+{
+ u32 tail =
+ le32_to_cpu(ipc_protocol->p_ap_shm->tail_array[pipe->pipe_nr]);
+ struct ipc_protocol_td *p_td;
+ struct sk_buff *skb;
+
+ if (!pipe->tdr_start)
+ return NULL;
+
+ /* Copy the reference to the downlink buffer. */
+ p_td = &pipe->tdr_start[pipe->old_tail];
+ skb = pipe->skbr_start[pipe->old_tail];
+
+ /* Reset the ring elements. */
+ pipe->skbr_start[pipe->old_tail] = NULL;
+
+ pipe->nr_of_queued_entries--;
+
+ pipe->old_tail++;
+ if (pipe->old_tail >= pipe->nr_of_entries)
+ pipe->old_tail = 0;
+
+ if (!skb) {
+ dev_err(ipc_protocol->dev, "skb is null");
+ goto ret;
+ } else if (!p_td->buffer.address) {
+ dev_err(ipc_protocol->dev, "td/buffer address is null");
+ ipc_pcie_kfree_skb(ipc_protocol->pcie, skb);
+ skb = NULL;
+ goto ret;
+ }
+
+ if (!IPC_CB(skb)) {
+ dev_err(ipc_protocol->dev, "pipe# %d, tail: %d skb_cb is NULL",
+ pipe->pipe_nr, tail);
+ ipc_pcie_kfree_skb(ipc_protocol->pcie, skb);
+ skb = NULL;
+ goto ret;
+ }
+
+ if (p_td->buffer.address != IPC_CB(skb)->mapping) {
+ dev_err(ipc_protocol->dev, "invalid buf=%p or skb=%p",
+ (void *)p_td->buffer.address, skb->data);
+ ipc_pcie_kfree_skb(ipc_protocol->pcie, skb);
+ skb = NULL;
+ goto ret;
+ } else if ((le32_to_cpu(p_td->scs) & SIZE_MASK) > pipe->buf_size) {
+ dev_err(ipc_protocol->dev, "invalid buffer size %d > %d",
+ le32_to_cpu(p_td->scs) & SIZE_MASK,
+ pipe->buf_size);
+ ipc_pcie_kfree_skb(ipc_protocol->pcie, skb);
+ skb = NULL;
+ goto ret;
+ } else if (le32_to_cpu(p_td->scs) >> COMPLETION_STATUS ==
+ IPC_MEM_TD_CS_ABORT) {
+ /* Discard aborted buffers. */
+ dev_dbg(ipc_protocol->dev, "discard 'aborted' buffers");
+ ipc_pcie_kfree_skb(ipc_protocol->pcie, skb);
+ skb = NULL;
+ goto ret;
+ }
+
+ /* Set the length field in skbuf. */
+ skb_put(skb, le32_to_cpu(p_td->scs) & SIZE_MASK);
+
+ret:
+ return skb;
+}
+
+void ipc_protocol_get_head_tail_index(struct iosm_protocol *ipc_protocol,
+ struct ipc_pipe *pipe, u32 *head,
+ u32 *tail)
+{
+ struct ipc_protocol_ap_shm *ipc_ap_shm = ipc_protocol->p_ap_shm;
+
+ if (head)
+ *head = le32_to_cpu(ipc_ap_shm->head_array[pipe->pipe_nr]);
+
+ if (tail)
+ *tail = le32_to_cpu(ipc_ap_shm->tail_array[pipe->pipe_nr]);
+}
+
+/* Frees the TDs given to CP. */
+void ipc_protocol_pipe_cleanup(struct iosm_protocol *ipc_protocol,
+ struct ipc_pipe *pipe)
+{
+ struct sk_buff *skb;
+ u32 head;
+ u32 tail;
+
+ /* Get the start and the end of the buffer list. */
+ head = le32_to_cpu(ipc_protocol->p_ap_shm->head_array[pipe->pipe_nr]);
+ tail = pipe->old_tail;
+
+ /* Reset tail and head to 0. */
+ ipc_protocol->p_ap_shm->tail_array[pipe->pipe_nr] = 0;
+ ipc_protocol->p_ap_shm->head_array[pipe->pipe_nr] = 0;
+
+ /* Free pending uplink and downlink buffers. */
+ if (pipe->skbr_start) {
+ while (head != tail) {
+ /* Get the reference to the skbuf,
+ * which is on the way and free it.
+ */
+ skb = pipe->skbr_start[tail];
+ if (skb)
+ ipc_pcie_kfree_skb(ipc_protocol->pcie, skb);
+
+ tail++;
+ if (tail >= pipe->nr_of_entries)
+ tail = 0;
+ }
+
+ kfree(pipe->skbr_start);
+ pipe->skbr_start = NULL;
+ }
+
+ pipe->old_tail = 0;
+
+ /* Free and reset the td and skbuf circular buffers. kfree is save! */
+ if (pipe->tdr_start) {
+ pci_free_consistent(ipc_protocol->pcie->pci,
+ sizeof(*pipe->tdr_start) *
+ pipe->nr_of_entries,
+ pipe->tdr_start, pipe->phy_tdr_start);
+
+ pipe->tdr_start = NULL;
+ }
+}
+
+enum ipc_mem_device_ipc_state ipc_protocol_get_ipc_status(struct iosm_protocol
+ *ipc_protocol)
+{
+ return (enum ipc_mem_device_ipc_state)
+ le32_to_cpu(ipc_protocol->p_ap_shm->device_info.ipc_status);
+}
+
+enum ipc_mem_exec_stage
+ipc_protocol_get_ap_exec_stage(struct iosm_protocol *ipc_protocol)
+{
+ return le32_to_cpu(ipc_protocol->p_ap_shm->device_info.execution_stage);
+}
+
+int ipc_protocol_msg_prep(struct iosm_imem *ipc_imem,
+ enum ipc_msg_prep_type msg_type,
+ union ipc_msg_prep_args *args)
+{
+ struct iosm_protocol *ipc_protocol = ipc_imem->ipc_protocol;
+
+ switch (msg_type) {
+ case IPC_MSG_PREP_SLEEP:
+ return ipc_protocol_msg_prep_sleep(ipc_protocol, args);
+
+ case IPC_MSG_PREP_PIPE_OPEN:
+ return ipc_protocol_msg_prepipe_open(ipc_protocol, args);
+
+ case IPC_MSG_PREP_PIPE_CLOSE:
+ return ipc_protocol_msg_prepipe_close(ipc_protocol, args);
+
+ case IPC_MSG_PREP_FEATURE_SET:
+ return ipc_protocol_msg_prep_feature_set(ipc_protocol, args);
+
+ /* Unsupported messages in protocol */
+ case IPC_MSG_PREP_MAP:
+ case IPC_MSG_PREP_UNMAP:
+ default:
+ dev_err(ipc_protocol->dev,
+ "unsupported message type: %d in protocol", msg_type);
+ return -EINVAL;
+ }
+}
+
+u32
+ipc_protocol_pm_dev_get_sleep_notification(struct iosm_protocol *ipc_protocol)
+{
+ struct ipc_protocol_ap_shm *ipc_ap_shm = ipc_protocol->p_ap_shm;
+
+ return le32_to_cpu(ipc_ap_shm->device_info.device_sleep_notification);
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.h b/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.h
new file mode 100644
index 000000000000..35aa1387306e
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.h
@@ -0,0 +1,444 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#ifndef IOSM_IPC_PROTOCOL_OPS_H
+#define IOSM_IPC_PROTOCOL_OPS_H
+
+#define SIZE_MASK 0x00FFFFFF
+#define COMPLETION_STATUS 24
+#define RESET_BIT 7
+
+/**
+ * enum ipc_mem_td_cs - Completion status of a TD
+ * @IPC_MEM_TD_CS_INVALID: Initial status - td not yet used.
+ * @IPC_MEM_TD_CS_PARTIAL_TRANSFER: More data pending -> next TD used for this
+ * @IPC_MEM_TD_CS_END_TRANSFER: IO transfer is complete.
+ * @IPC_MEM_TD_CS_OVERFLOW: IO transfer to small for the buff to write
+ * @IPC_MEM_TD_CS_ABORT: TD marked as abort and shall be discarded
+ * by AP.
+ * @IPC_MEM_TD_CS_ERROR: General error.
+ */
+enum ipc_mem_td_cs {
+ IPC_MEM_TD_CS_INVALID,
+ IPC_MEM_TD_CS_PARTIAL_TRANSFER,
+ IPC_MEM_TD_CS_END_TRANSFER,
+ IPC_MEM_TD_CS_OVERFLOW,
+ IPC_MEM_TD_CS_ABORT,
+ IPC_MEM_TD_CS_ERROR,
+};
+
+/**
+ * enum ipc_mem_msg_cs - Completion status of IPC Message
+ * @IPC_MEM_MSG_CS_INVALID: Initial status.
+ * @IPC_MEM_MSG_CS_SUCCESS: IPC Message completion success.
+ * @IPC_MEM_MSG_CS_ERROR: Message send error.
+ */
+enum ipc_mem_msg_cs {
+ IPC_MEM_MSG_CS_INVALID,
+ IPC_MEM_MSG_CS_SUCCESS,
+ IPC_MEM_MSG_CS_ERROR,
+};
+
+/**
+ * struct ipc_msg_prep_args_pipe - struct for pipe args for message preparation
+ * @pipe: Pipe to open/close
+ */
+struct ipc_msg_prep_args_pipe {
+ struct ipc_pipe *pipe;
+};
+
+/**
+ * struct ipc_msg_prep_args_sleep - struct for sleep args for message
+ * preparation
+ * @target: 0=host, 1=device
+ * @state: 0=enter sleep, 1=exit sleep
+ */
+struct ipc_msg_prep_args_sleep {
+ unsigned int target;
+ unsigned int state;
+};
+
+/**
+ * struct ipc_msg_prep_feature_set - struct for feature set argument for
+ * message preparation
+ * @reset_enable: 0=out-of-band, 1=in-band-crash notification
+ */
+struct ipc_msg_prep_feature_set {
+ u8 reset_enable;
+};
+
+/**
+ * struct ipc_msg_prep_map - struct for map argument for message preparation
+ * @region_id: Region to map
+ * @addr: Pcie addr of region to map
+ * @size: Size of the region to map
+ */
+struct ipc_msg_prep_map {
+ unsigned int region_id;
+ unsigned long addr;
+ size_t size;
+};
+
+/**
+ * struct ipc_msg_prep_unmap - struct for unmap argument for message preparation
+ * @region_id: Region to unmap
+ */
+struct ipc_msg_prep_unmap {
+ unsigned int region_id;
+};
+
+/**
+ * struct ipc_msg_prep_args - Union to handle different message types
+ * @pipe_open: Pipe open message preparation struct
+ * @pipe_close: Pipe close message preparation struct
+ * @sleep: Sleep message preparation struct
+ * @feature_set: Feature set message preparation struct
+ * @map: Memory map message preparation struct
+ * @unmap: Memory unmap message preparation struct
+ */
+union ipc_msg_prep_args {
+ struct ipc_msg_prep_args_pipe pipe_open;
+ struct ipc_msg_prep_args_pipe pipe_close;
+ struct ipc_msg_prep_args_sleep sleep;
+ struct ipc_msg_prep_feature_set feature_set;
+ struct ipc_msg_prep_map map;
+ struct ipc_msg_prep_unmap unmap;
+};
+
+/**
+ * enum ipc_msg_prep_type - Enum for message prepare actions
+ * @IPC_MSG_PREP_SLEEP: Sleep message preparation type
+ * @IPC_MSG_PREP_PIPE_OPEN: Pipe open message preparation type
+ * @IPC_MSG_PREP_PIPE_CLOSE: Pipe close message preparation type
+ * @IPC_MSG_PREP_FEATURE_SET: Feature set message preparation type
+ * @IPC_MSG_PREP_MAP: Memory map message preparation type
+ * @IPC_MSG_PREP_UNMAP: Memory unmap message preparation type
+ */
+enum ipc_msg_prep_type {
+ IPC_MSG_PREP_SLEEP,
+ IPC_MSG_PREP_PIPE_OPEN,
+ IPC_MSG_PREP_PIPE_CLOSE,
+ IPC_MSG_PREP_FEATURE_SET,
+ IPC_MSG_PREP_MAP,
+ IPC_MSG_PREP_UNMAP,
+};
+
+/**
+ * struct ipc_rsp - Response to sent message
+ * @completion: For waking up requestor
+ * @status: Completion status
+ */
+struct ipc_rsp {
+ struct completion completion;
+ enum ipc_mem_msg_cs status;
+};
+
+/**
+ * enum ipc_mem_msg - Type-definition of the messages.
+ * @IPC_MEM_MSG_OPEN_PIPE: AP ->CP: Open a pipe
+ * @IPC_MEM_MSG_CLOSE_PIPE: AP ->CP: Close a pipe
+ * @IPC_MEM_MSG_ABORT_PIPE: AP ->CP: wait for completion of the
+ * running transfer and abort all pending
+ * IO-transfers for the pipe
+ * @IPC_MEM_MSG_SLEEP: AP ->CP: host enter or exit sleep
+ * @IPC_MEM_MSG_FEATURE_SET: AP ->CP: Intel feature configuration
+ */
+enum ipc_mem_msg {
+ IPC_MEM_MSG_OPEN_PIPE = 0x01,
+ IPC_MEM_MSG_CLOSE_PIPE = 0x02,
+ IPC_MEM_MSG_ABORT_PIPE = 0x03,
+ IPC_MEM_MSG_SLEEP = 0x04,
+ IPC_MEM_MSG_FEATURE_SET = 0xF0,
+};
+
+/**
+ * struct ipc_mem_msg_open_pipe - Message structure for open pipe
+ * @tdr_addr: Tdr address
+ * @tdr_entries: Tdr entries
+ * @pipe_nr: Pipe number
+ * @type_of_message: Message type
+ * @irq_vector: MSI vector number
+ * @accumulation_backoff: Time in usec for data accumalation
+ * @completion_status: Message Completion Status
+ */
+struct ipc_mem_msg_open_pipe {
+ __le64 tdr_addr;
+ __le16 tdr_entries;
+ u8 pipe_nr;
+ u8 type_of_message;
+ __le32 irq_vector;
+ __le32 accumulation_backoff;
+ __le32 completion_status;
+};
+
+/**
+ * struct ipc_mem_msg_close_pipe - Message structure for close pipe
+ * @reserved1: Reserved
+ * @reserved2: Reserved
+ * @pipe_nr: Pipe number
+ * @type_of_message: Message type
+ * @reserved3: Reserved
+ * @reserved4: Reserved
+ * @completion_status: Message Completion Status
+ */
+struct ipc_mem_msg_close_pipe {
+ __le32 reserved1[2];
+ __le16 reserved2;
+ u8 pipe_nr;
+ u8 type_of_message;
+ __le32 reserved3;
+ __le32 reserved4;
+ __le32 completion_status;
+};
+
+/**
+ * struct ipc_mem_msg_abort_pipe - Message structure for abort pipe
+ * @reserved1: Reserved
+ * @reserved2: Reserved
+ * @pipe_nr: Pipe number
+ * @type_of_message: Message type
+ * @reserved3: Reserved
+ * @reserved4: Reserved
+ * @completion_status: Message Completion Status
+ */
+struct ipc_mem_msg_abort_pipe {
+ __le32 reserved1[2];
+ __le16 reserved2;
+ u8 pipe_nr;
+ u8 type_of_message;
+ __le32 reserved3;
+ __le32 reserved4;
+ __le32 completion_status;
+};
+
+/**
+ * struct ipc_mem_msg_host_sleep - Message structure for sleep message.
+ * @reserved1: Reserved
+ * @target: 0=host, 1=device, host or EP devie
+ * is the message target
+ * @state: 0=enter sleep, 1=exit sleep,
+ * 2=enter sleep no protocol
+ * @reserved2: Reserved
+ * @type_of_message: Message type
+ * @reserved3: Reserved
+ * @reserved4: Reserved
+ * @completion_status: Message Completion Status
+ */
+struct ipc_mem_msg_host_sleep {
+ __le32 reserved1[2];
+ u8 target;
+ u8 state;
+ u8 reserved2;
+ u8 type_of_message;
+ __le32 reserved3;
+ __le32 reserved4;
+ __le32 completion_status;
+};
+
+/**
+ * struct ipc_mem_msg_feature_set - Message structure for feature_set message
+ * @reserved1: Reserved
+ * @reserved2: Reserved
+ * @reset_enable: 0=out-of-band, 1=in-band-crash notification
+ * @type_of_message: Message type
+ * @reserved3: Reserved
+ * @reserved4: Reserved
+ * @completion_status: Message Completion Status
+ */
+struct ipc_mem_msg_feature_set {
+ __le32 reserved1[2];
+ __le16 reserved2;
+ u8 reset_enable;
+ u8 type_of_message;
+ __le32 reserved3;
+ __le32 reserved4;
+ __le32 completion_status;
+};
+
+/**
+ * struct ipc_mem_msg_common - Message structure for completion status update.
+ * @reserved1: Reserved
+ * @reserved2: Reserved
+ * @type_of_message: Message type
+ * @reserved3: Reserved
+ * @reserved4: Reserved
+ * @completion_status: Message Completion Status
+ */
+struct ipc_mem_msg_common {
+ __le32 reserved1[2];
+ u8 reserved2[3];
+ u8 type_of_message;
+ __le32 reserved3;
+ __le32 reserved4;
+ __le32 completion_status;
+};
+
+/**
+ * union ipc_mem_msg_entry - Union with all possible messages.
+ * @open_pipe: Open pipe message struct
+ * @close_pipe: Close pipe message struct
+ * @abort_pipe: Abort pipe message struct
+ * @host_sleep: Host sleep message struct
+ * @feature_set: Featuer set message struct
+ * @common: Used to access msg_type and to set the completion status
+ */
+union ipc_mem_msg_entry {
+ struct ipc_mem_msg_open_pipe open_pipe;
+ struct ipc_mem_msg_close_pipe close_pipe;
+ struct ipc_mem_msg_abort_pipe abort_pipe;
+ struct ipc_mem_msg_host_sleep host_sleep;
+ struct ipc_mem_msg_feature_set feature_set;
+ struct ipc_mem_msg_common common;
+};
+
+/* Transfer descriptor definition. */
+struct ipc_protocol_td {
+ union {
+ /* 0 : 63 - 64-bit address of a buffer in host memory. */
+ dma_addr_t address;
+ struct {
+ /* 0 : 31 - 32 bit address */
+ __le32 address;
+ /* 32 : 63 - corresponding descriptor */
+ __le32 desc;
+ } __packed shm;
+ } buffer;
+
+ /* 0 - 2nd byte - Size of the buffer.
+ * The host provides the size of the buffer queued.
+ * The EP device reads this value and shall update
+ * it for downlink transfers to indicate the
+ * amount of data written in buffer.
+ * 3rd byte - This field provides the completion status
+ * of the TD. When queuing the TD, the host sets
+ * the status to 0. The EP device updates this
+ * field when completing the TD.
+ */
+ __le32 scs;
+
+ /* 0th - nr of following descriptors
+ * 1 - 3rd byte - reserved
+ */
+ __le32 next;
+} __packed;
+
+/**
+ * ipc_protocol_msg_prep - Prepare message based upon message type
+ * @ipc_imem: iosm_protocol instance
+ * @msg_type: message prepare type
+ * @args: message arguments
+ *
+ * Return: 0 on success and failure value on error
+ */
+int ipc_protocol_msg_prep(struct iosm_imem *ipc_imem,
+ enum ipc_msg_prep_type msg_type,
+ union ipc_msg_prep_args *args);
+
+/**
+ * ipc_protocol_msg_hp_update - Function for head pointer update
+ * of message ring
+ * @ipc_imem: iosm_protocol instance
+ */
+void ipc_protocol_msg_hp_update(struct iosm_imem *ipc_imem);
+
+/**
+ * ipc_protocol_msg_process - Function for processing responses
+ * to IPC messages
+ * @ipc_imem: iosm_protocol instance
+ * @irq: IRQ vector
+ *
+ * Return: True on success, false if error
+ */
+bool ipc_protocol_msg_process(struct iosm_imem *ipc_imem, int irq);
+
+/**
+ * ipc_protocol_ul_td_send - Function for sending the data to CP
+ * @ipc_protocol: iosm_protocol instance
+ * @pipe: Pipe instance
+ * @p_ul_list: uplink sk_buff list
+ *
+ * Return: true in success, false in case of error
+ */
+bool ipc_protocol_ul_td_send(struct iosm_protocol *ipc_protocol,
+ struct ipc_pipe *pipe,
+ struct sk_buff_head *p_ul_list);
+
+/**
+ * ipc_protocol_ul_td_process - Function for processing the sent data
+ * @ipc_protocol: iosm_protocol instance
+ * @pipe: Pipe instance
+ *
+ * Return: sk_buff instance
+ */
+struct sk_buff *ipc_protocol_ul_td_process(struct iosm_protocol *ipc_protocol,
+ struct ipc_pipe *pipe);
+
+/**
+ * ipc_protocol_dl_td_prepare - Function for providing DL TDs to CP
+ * @ipc_protocol: iosm_protocol instance
+ * @pipe: Pipe instance
+ *
+ * Return: true in success, false in case of error
+ */
+bool ipc_protocol_dl_td_prepare(struct iosm_protocol *ipc_protocol,
+ struct ipc_pipe *pipe);
+
+/**
+ * ipc_protocol_dl_td_process - Function for processing the DL data
+ * @ipc_protocol: iosm_protocol instance
+ * @pipe: Pipe instance
+ *
+ * Return: sk_buff instance
+ */
+struct sk_buff *ipc_protocol_dl_td_process(struct iosm_protocol *ipc_protocol,
+ struct ipc_pipe *pipe);
+
+/**
+ * ipc_protocol_get_head_tail_index - Function for getting Head and Tail
+ * pointer index of given pipe
+ * @ipc_protocol: iosm_protocol instance
+ * @pipe: Pipe Instance
+ * @head: head pointer index of the given pipe
+ * @tail: tail pointer index of the given pipe
+ */
+void ipc_protocol_get_head_tail_index(struct iosm_protocol *ipc_protocol,
+ struct ipc_pipe *pipe, u32 *head,
+ u32 *tail);
+/**
+ * ipc_protocol_get_ipc_status - Function for getting the IPC Status
+ * @ipc_protocol: iosm_protocol instance
+ *
+ * Return: Returns IPC State
+ */
+enum ipc_mem_device_ipc_state ipc_protocol_get_ipc_status(struct iosm_protocol
+ *ipc_protocol);
+
+/**
+ * ipc_protocol_pipe_cleanup - Function to cleanup pipe resources
+ * @ipc_protocol: iosm_protocol instance
+ * @pipe: Pipe instance
+ */
+void ipc_protocol_pipe_cleanup(struct iosm_protocol *ipc_protocol,
+ struct ipc_pipe *pipe);
+
+/**
+ * ipc_protocol_get_ap_exec_stage - Function for getting AP Exec Stage
+ * @ipc_protocol: pointer to struct iosm protocol
+ *
+ * Return: returns BOOT Stages
+ */
+enum ipc_mem_exec_stage
+ipc_protocol_get_ap_exec_stage(struct iosm_protocol *ipc_protocol);
+
+/**
+ * ipc_protocol_pm_dev_get_sleep_notification - Function for getting Dev Sleep
+ * notification
+ * @ipc_protocol: iosm_protocol instance
+ *
+ * Return: Returns dev PM State
+ */
+u32 ipc_protocol_pm_dev_get_sleep_notification(struct iosm_protocol
+ *ipc_protocol);
+#endif
diff --git a/drivers/net/wwan/iosm/iosm_ipc_task_queue.c b/drivers/net/wwan/iosm/iosm_ipc_task_queue.c
new file mode 100644
index 000000000000..852a99166144
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_task_queue.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include "iosm_ipc_imem.h"
+#include "iosm_ipc_task_queue.h"
+
+/* Actual tasklet function, will be called whenever tasklet is scheduled.
+ * Calls event handler involves callback for each element in the message queue
+ */
+static void ipc_task_queue_handler(unsigned long data)
+{
+ struct ipc_task_queue *ipc_task = (struct ipc_task_queue *)data;
+ unsigned int q_rpos = ipc_task->q_rpos;
+
+ /* Loop over the input queue contents. */
+ while (q_rpos != ipc_task->q_wpos) {
+ /* Get the current first queue element. */
+ struct ipc_task_queue_args *args = &ipc_task->args[q_rpos];
+
+ /* Process the input message. */
+ if (args->func)
+ args->response = args->func(args->ipc_imem, args->arg,
+ args->msg, args->size);
+
+ /* Signal completion for synchronous calls */
+ if (args->completion)
+ complete(args->completion);
+
+ /* Free message if copy was allocated. */
+ if (args->is_copy)
+ kfree(args->msg);
+
+ /* Set invalid queue element. Technically
+ * spin_lock_irqsave is not required here as
+ * the array element has been processed already
+ * so we can assume that immediately after processing
+ * ipc_task element, queue will not rotate again to
+ * ipc_task same element within such short time.
+ */
+ args->completion = NULL;
+ args->func = NULL;
+ args->msg = NULL;
+ args->size = 0;
+ args->is_copy = false;
+
+ /* calculate the new read ptr and update the volatile read
+ * ptr
+ */
+ q_rpos = (q_rpos + 1) % IPC_THREAD_QUEUE_SIZE;
+ ipc_task->q_rpos = q_rpos;
+ }
+}
+
+/* Free memory alloc and trigger completions left in the queue during dealloc */
+static void ipc_task_queue_cleanup(struct ipc_task_queue *ipc_task)
+{
+ unsigned int q_rpos = ipc_task->q_rpos;
+
+ while (q_rpos != ipc_task->q_wpos) {
+ struct ipc_task_queue_args *args = &ipc_task->args[q_rpos];
+
+ if (args->completion)
+ complete(args->completion);
+
+ if (args->is_copy)
+ kfree(args->msg);
+
+ q_rpos = (q_rpos + 1) % IPC_THREAD_QUEUE_SIZE;
+ ipc_task->q_rpos = q_rpos;
+ }
+}
+
+/* Add a message to the queue and trigger the ipc_task. */
+static int
+ipc_task_queue_add_task(struct iosm_imem *ipc_imem,
+ int arg, void *msg,
+ int (*func)(struct iosm_imem *ipc_imem, int arg,
+ void *msg, size_t size),
+ size_t size, bool is_copy, bool wait)
+{
+ struct tasklet_struct *ipc_tasklet = ipc_imem->ipc_task->ipc_tasklet;
+ struct ipc_task_queue *ipc_task = &ipc_imem->ipc_task->ipc_queue;
+ struct completion completion;
+ unsigned int pos, nextpos;
+ unsigned long flags;
+ int result = -EIO;
+
+ init_completion(&completion);
+
+ /* tasklet send may be called from both interrupt or thread
+ * context, therefore protect queue operation by spinlock
+ */
+ spin_lock_irqsave(&ipc_task->q_lock, flags);
+
+ pos = ipc_task->q_wpos;
+ nextpos = (pos + 1) % IPC_THREAD_QUEUE_SIZE;
+
+ /* Get next queue position. */
+ if (nextpos != ipc_task->q_rpos) {
+ /* Get the reference to the queue element and save the passed
+ * values.
+ */
+ ipc_task->args[pos].arg = arg;
+ ipc_task->args[pos].msg = msg;
+ ipc_task->args[pos].func = func;
+ ipc_task->args[pos].ipc_imem = ipc_imem;
+ ipc_task->args[pos].size = size;
+ ipc_task->args[pos].is_copy = is_copy;
+ ipc_task->args[pos].completion = wait ? &completion : NULL;
+ ipc_task->args[pos].response = -1;
+
+ /* apply write barrier so that ipc_task->q_rpos elements
+ * are updated before ipc_task->q_wpos is being updated.
+ */
+ smp_wmb();
+
+ /* Update the status of the free queue space. */
+ ipc_task->q_wpos = nextpos;
+ result = 0;
+ }
+
+ spin_unlock_irqrestore(&ipc_task->q_lock, flags);
+
+ if (result == 0) {
+ tasklet_schedule(ipc_tasklet);
+
+ if (wait) {
+ wait_for_completion(&completion);
+ result = ipc_task->args[pos].response;
+ }
+ } else {
+ dev_err(ipc_imem->ipc_task->dev, "queue is full");
+ }
+
+ return result;
+}
+
+int ipc_task_queue_send_task(struct iosm_imem *imem,
+ int (*func)(struct iosm_imem *ipc_imem, int arg,
+ void *msg, size_t size),
+ int arg, void *msg, size_t size, bool wait)
+{
+ bool is_copy = false;
+ void *copy = msg;
+ int ret = -ENOMEM;
+
+ if (size > 0) {
+ copy = kmemdup(msg, size, GFP_ATOMIC);
+ if (!copy)
+ goto out;
+
+ is_copy = true;
+ }
+
+ ret = ipc_task_queue_add_task(imem, arg, copy, func,
+ size, is_copy, wait);
+ if (ret < 0) {
+ dev_err(imem->ipc_task->dev,
+ "add task failed for %ps %d, %p, %zu, %d", func, arg,
+ copy, size, is_copy);
+ if (is_copy)
+ kfree(copy);
+ goto out;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+int ipc_task_init(struct ipc_task *ipc_task)
+{
+ struct ipc_task_queue *ipc_queue = &ipc_task->ipc_queue;
+
+ ipc_task->ipc_tasklet = kzalloc(sizeof(*ipc_task->ipc_tasklet),
+ GFP_KERNEL);
+
+ if (!ipc_task->ipc_tasklet)
+ return -ENOMEM;
+
+ /* Initialize the spinlock needed to protect the message queue of the
+ * ipc_task
+ */
+ spin_lock_init(&ipc_queue->q_lock);
+
+ tasklet_init(ipc_task->ipc_tasklet, ipc_task_queue_handler,
+ (unsigned long)ipc_queue);
+ return 0;
+}
+
+void ipc_task_deinit(struct ipc_task *ipc_task)
+{
+ tasklet_kill(ipc_task->ipc_tasklet);
+
+ kfree(ipc_task->ipc_tasklet);
+ /* This will free/complete any outstanding messages,
+ * without calling the actual handler
+ */
+ ipc_task_queue_cleanup(&ipc_task->ipc_queue);
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_task_queue.h b/drivers/net/wwan/iosm/iosm_ipc_task_queue.h
new file mode 100644
index 000000000000..df6e9cd925a9
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_task_queue.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#ifndef IOSM_IPC_TASK_QUEUE_H
+#define IOSM_IPC_TASK_QUEUE_H
+
+/* Number of available element for the input message queue of the IPC
+ * ipc_task
+ */
+#define IPC_THREAD_QUEUE_SIZE 256
+
+/**
+ * struct ipc_task_queue_args - Struct for Task queue elements
+ * @ipc_imem: Pointer to struct iosm_imem
+ * @msg: Message argument for tasklet function. (optional, can be NULL)
+ * @completion: OS object used to wait for the tasklet function to finish for
+ * synchronous calls
+ * @func: Function to be called in tasklet (tl) context
+ * @arg: Generic integer argument for tasklet function (optional)
+ * @size: Message size argument for tasklet function (optional)
+ * @response: Return code of tasklet function for synchronous calls
+ * @is_copy: Is true if msg contains a pointer to a copy of the original msg
+ * for async. calls that needs to be freed once the tasklet returns
+ */
+struct ipc_task_queue_args {
+ struct iosm_imem *ipc_imem;
+ void *msg;
+ struct completion *completion;
+ int (*func)(struct iosm_imem *ipc_imem, int arg, void *msg,
+ size_t size);
+ int arg;
+ size_t size;
+ int response;
+ u8 is_copy:1;
+};
+
+/**
+ * struct ipc_task_queue - Struct for Task queue
+ * @q_lock: Protect the message queue of the ipc ipc_task
+ * @args: Message queue of the IPC ipc_task
+ * @q_rpos: First queue element to process.
+ * @q_wpos: First free element of the input queue.
+ */
+struct ipc_task_queue {
+ spinlock_t q_lock; /* for atomic operation on queue */
+ struct ipc_task_queue_args args[IPC_THREAD_QUEUE_SIZE];
+ unsigned int q_rpos;
+ unsigned int q_wpos;
+};
+
+/**
+ * struct ipc_task - Struct for Task
+ * @dev: Pointer to device structure
+ * @ipc_tasklet: Tasklet for serialized work offload
+ * from interrupts and OS callbacks
+ * @ipc_queue: Task for entry into ipc task queue
+ */
+struct ipc_task {
+ struct device *dev;
+ struct tasklet_struct *ipc_tasklet;
+ struct ipc_task_queue ipc_queue;
+};
+
+/**
+ * ipc_task_init - Allocate a tasklet
+ * @ipc_task: Pointer to ipc_task structure
+ * Returns: 0 on success and failure value on error.
+ */
+int ipc_task_init(struct ipc_task *ipc_task);
+
+/**
+ * ipc_task_deinit - Free a tasklet, invalidating its pointer.
+ * @ipc_task: Pointer to ipc_task structure
+ */
+void ipc_task_deinit(struct ipc_task *ipc_task);
+
+/**
+ * ipc_task_queue_send_task - Synchronously/Asynchronously call a function in
+ * tasklet context.
+ * @imem: Pointer to iosm_imem struct
+ * @func: Function to be called in tasklet context
+ * @arg: Integer argument for func
+ * @msg: Message pointer argument for func
+ * @size: Size argument for func
+ * @wait: if true wait for result
+ *
+ * Returns: Result value returned by func or failure value if func could not
+ * be called.
+ */
+int ipc_task_queue_send_task(struct iosm_imem *imem,
+ int (*func)(struct iosm_imem *ipc_imem, int arg,
+ void *msg, size_t size),
+ int arg, void *msg, size_t size, bool wait);
+
+#endif
diff --git a/drivers/net/wwan/iosm/iosm_ipc_uevent.c b/drivers/net/wwan/iosm/iosm_ipc_uevent.c
new file mode 100644
index 000000000000..d12188ffed7e
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_uevent.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include <linux/device.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
+
+#include "iosm_ipc_uevent.h"
+
+/* Update the uevent in work queue context */
+static void ipc_uevent_work(struct work_struct *data)
+{
+ struct ipc_uevent_info *info;
+ char *envp[2] = { NULL, NULL };
+
+ info = container_of(data, struct ipc_uevent_info, work);
+
+ envp[0] = info->uevent;
+
+ if (kobject_uevent_env(&info->dev->kobj, KOBJ_CHANGE, envp))
+ pr_err("uevent %s failed to sent", info->uevent);
+
+ kfree(info);
+}
+
+void ipc_uevent_send(struct device *dev, char *uevent)
+{
+ struct ipc_uevent_info *info = kzalloc(sizeof(*info), GFP_ATOMIC);
+
+ if (!info)
+ return;
+
+ /* Initialize the kernel work queue */
+ INIT_WORK(&info->work, ipc_uevent_work);
+
+ /* Store the device and event information */
+ info->dev = dev;
+ snprintf(info->uevent, MAX_UEVENT_LEN, "IOSM_EVENT=%s", uevent);
+
+ /* Schedule uevent in process context using work queue */
+ schedule_work(&info->work);
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_uevent.h b/drivers/net/wwan/iosm/iosm_ipc_uevent.h
new file mode 100644
index 000000000000..2e45c051b5f4
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_uevent.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#ifndef IOSM_IPC_UEVENT_H
+#define IOSM_IPC_UEVENT_H
+
+/* Baseband event strings */
+#define UEVENT_MDM_NOT_READY "MDM_NOT_READY"
+#define UEVENT_ROM_READY "ROM_READY"
+#define UEVENT_MDM_READY "MDM_READY"
+#define UEVENT_CRASH "CRASH"
+#define UEVENT_CD_READY "CD_READY"
+#define UEVENT_CD_READY_LINK_DOWN "CD_READY_LINK_DOWN"
+#define UEVENT_MDM_TIMEOUT "MDM_TIMEOUT"
+
+/* Maximum length of user events */
+#define MAX_UEVENT_LEN 64
+
+/**
+ * struct ipc_uevent_info - Uevent information structure.
+ * @dev: Pointer to device structure
+ * @uevent: Uevent information
+ * @work: Uevent work struct
+ */
+struct ipc_uevent_info {
+ struct device *dev;
+ char uevent[MAX_UEVENT_LEN];
+ struct work_struct work;
+};
+
+/**
+ * ipc_uevent_send - Send modem event to user space.
+ * @dev: Generic device pointer
+ * @uevent: Uevent information
+ *
+ */
+void ipc_uevent_send(struct device *dev, char *uevent);
+
+#endif
diff --git a/drivers/net/wwan/iosm/iosm_ipc_wwan.c b/drivers/net/wwan/iosm/iosm_ipc_wwan.c
new file mode 100644
index 000000000000..b2357ad5d517
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_wwan.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_link.h>
+#include <linux/rtnetlink.h>
+#include <linux/wwan.h>
+
+#include "iosm_ipc_chnl_cfg.h"
+#include "iosm_ipc_imem_ops.h"
+#include "iosm_ipc_wwan.h"
+
+#define IOSM_IP_TYPE_MASK 0xF0
+#define IOSM_IP_TYPE_IPV4 0x40
+#define IOSM_IP_TYPE_IPV6 0x60
+
+#define IOSM_IF_ID_PAYLOAD 2
+
+/**
+ * struct iosm_netdev_priv - netdev WWAN driver specific private data
+ * @ipc_wwan: Pointer to iosm_wwan struct
+ * @netdev: Pointer to network interface device structure
+ * @if_id: Interface id for device.
+ * @ch_id: IPC channel number for which interface device is created.
+ */
+struct iosm_netdev_priv {
+ struct iosm_wwan *ipc_wwan;
+ struct net_device *netdev;
+ int if_id;
+ int ch_id;
+};
+
+/**
+ * struct iosm_wwan - This structure contains information about WWAN root device
+ * and interface to the IPC layer.
+ * @ipc_imem: Pointer to imem data-struct
+ * @sub_netlist: List of active netdevs
+ * @dev: Pointer device structure
+ * @if_mutex: Mutex used for add and remove interface id
+ */
+struct iosm_wwan {
+ struct iosm_imem *ipc_imem;
+ struct iosm_netdev_priv __rcu *sub_netlist[IP_MUX_SESSION_END + 1];
+ struct device *dev;
+ struct mutex if_mutex; /* Mutex used for add and remove interface id */
+};
+
+/* Bring-up the wwan net link */
+static int ipc_wwan_link_open(struct net_device *netdev)
+{
+ struct iosm_netdev_priv *priv = wwan_netdev_drvpriv(netdev);
+ struct iosm_wwan *ipc_wwan = priv->ipc_wwan;
+ int if_id = priv->if_id;
+ int ret;
+
+ if (if_id < IP_MUX_SESSION_START ||
+ if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist))
+ return -EINVAL;
+
+ mutex_lock(&ipc_wwan->if_mutex);
+
+ /* get channel id */
+ priv->ch_id = ipc_imem_sys_wwan_open(ipc_wwan->ipc_imem, if_id);
+
+ if (priv->ch_id < 0) {
+ dev_err(ipc_wwan->dev,
+ "cannot connect wwan0 & id %d to the IPC mem layer",
+ if_id);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* enable tx path, DL data may follow */
+ netif_start_queue(netdev);
+
+ dev_dbg(ipc_wwan->dev, "Channel id %d allocated to if_id %d",
+ priv->ch_id, priv->if_id);
+
+ ret = 0;
+out:
+ mutex_unlock(&ipc_wwan->if_mutex);
+ return ret;
+}
+
+/* Bring-down the wwan net link */
+static int ipc_wwan_link_stop(struct net_device *netdev)
+{
+ struct iosm_netdev_priv *priv = wwan_netdev_drvpriv(netdev);
+
+ netif_stop_queue(netdev);
+
+ mutex_lock(&priv->ipc_wwan->if_mutex);
+ ipc_imem_sys_wwan_close(priv->ipc_wwan->ipc_imem, priv->if_id,
+ priv->ch_id);
+ priv->ch_id = -1;
+ mutex_unlock(&priv->ipc_wwan->if_mutex);
+
+ return 0;
+}
+
+/* Transmit a packet */
+static int ipc_wwan_link_transmit(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ struct iosm_netdev_priv *priv = wwan_netdev_drvpriv(netdev);
+ struct iosm_wwan *ipc_wwan = priv->ipc_wwan;
+ unsigned int len = skb->len;
+ int if_id = priv->if_id;
+ int ret;
+
+ /* Interface IDs from 1 to 8 are for IP data
+ * & from 257 to 261 are for non-IP data
+ */
+ if (if_id < IP_MUX_SESSION_START ||
+ if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist))
+ return -EINVAL;
+
+ /* Send the SKB to device for transmission */
+ ret = ipc_imem_sys_wwan_transmit(ipc_wwan->ipc_imem,
+ if_id, priv->ch_id, skb);
+
+ /* Return code of zero is success */
+ if (ret == 0) {
+ netdev->stats.tx_packets++;
+ netdev->stats.tx_bytes += len;
+ ret = NETDEV_TX_OK;
+ } else if (ret == -EBUSY) {
+ ret = NETDEV_TX_BUSY;
+ dev_err(ipc_wwan->dev, "unable to push packets");
+ } else {
+ goto exit;
+ }
+
+ return ret;
+
+exit:
+ /* Log any skb drop */
+ if (if_id)
+ dev_dbg(ipc_wwan->dev, "skb dropped. IF_ID: %d, ret: %d", if_id,
+ ret);
+
+ dev_kfree_skb_any(skb);
+ netdev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+}
+
+/* Ops structure for wwan net link */
+static const struct net_device_ops ipc_inm_ops = {
+ .ndo_open = ipc_wwan_link_open,
+ .ndo_stop = ipc_wwan_link_stop,
+ .ndo_start_xmit = ipc_wwan_link_transmit,
+};
+
+/* Setup function for creating new net link */
+static void ipc_wwan_setup(struct net_device *iosm_dev)
+{
+ iosm_dev->header_ops = NULL;
+ iosm_dev->hard_header_len = 0;
+ iosm_dev->priv_flags |= IFF_NO_QUEUE;
+
+ iosm_dev->type = ARPHRD_NONE;
+ iosm_dev->mtu = ETH_DATA_LEN;
+ iosm_dev->min_mtu = ETH_MIN_MTU;
+ iosm_dev->max_mtu = ETH_MAX_MTU;
+
+ iosm_dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+
+ iosm_dev->netdev_ops = &ipc_inm_ops;
+}
+
+/* Create new wwan net link */
+static int ipc_wwan_newlink(void *ctxt, struct net_device *dev,
+ u32 if_id, struct netlink_ext_ack *extack)
+{
+ struct iosm_wwan *ipc_wwan = ctxt;
+ struct iosm_netdev_priv *priv;
+ int err;
+
+ if (if_id < IP_MUX_SESSION_START ||
+ if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist))
+ return -EINVAL;
+
+ priv = wwan_netdev_drvpriv(dev);
+ priv->if_id = if_id;
+ priv->netdev = dev;
+ priv->ipc_wwan = ipc_wwan;
+
+ mutex_lock(&ipc_wwan->if_mutex);
+ if (rcu_access_pointer(ipc_wwan->sub_netlist[if_id])) {
+ err = -EBUSY;
+ goto out_unlock;
+ }
+
+ err = register_netdevice(dev);
+ if (err)
+ goto out_unlock;
+
+ rcu_assign_pointer(ipc_wwan->sub_netlist[if_id], priv);
+ mutex_unlock(&ipc_wwan->if_mutex);
+
+ netif_device_attach(dev);
+
+ return 0;
+
+out_unlock:
+ mutex_unlock(&ipc_wwan->if_mutex);
+ return err;
+}
+
+static void ipc_wwan_dellink(void *ctxt, struct net_device *dev,
+ struct list_head *head)
+{
+ struct iosm_netdev_priv *priv = wwan_netdev_drvpriv(dev);
+ struct iosm_wwan *ipc_wwan = ctxt;
+ int if_id = priv->if_id;
+
+ if (WARN_ON(if_id < IP_MUX_SESSION_START ||
+ if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist)))
+ return;
+
+ mutex_lock(&ipc_wwan->if_mutex);
+
+ if (WARN_ON(rcu_access_pointer(ipc_wwan->sub_netlist[if_id]) != priv))
+ goto unlock;
+
+ RCU_INIT_POINTER(ipc_wwan->sub_netlist[if_id], NULL);
+ /* unregistering includes synchronize_net() */
+ unregister_netdevice(dev);
+
+unlock:
+ mutex_unlock(&ipc_wwan->if_mutex);
+}
+
+static const struct wwan_ops iosm_wwan_ops = {
+ .priv_size = sizeof(struct iosm_netdev_priv),
+ .setup = ipc_wwan_setup,
+ .newlink = ipc_wwan_newlink,
+ .dellink = ipc_wwan_dellink,
+};
+
+int ipc_wwan_receive(struct iosm_wwan *ipc_wwan, struct sk_buff *skb_arg,
+ bool dss, int if_id)
+{
+ struct sk_buff *skb = skb_arg;
+ struct net_device_stats *stats;
+ struct iosm_netdev_priv *priv;
+ int ret;
+
+ if ((skb->data[0] & IOSM_IP_TYPE_MASK) == IOSM_IP_TYPE_IPV4)
+ skb->protocol = htons(ETH_P_IP);
+ else if ((skb->data[0] & IOSM_IP_TYPE_MASK) ==
+ IOSM_IP_TYPE_IPV6)
+ skb->protocol = htons(ETH_P_IPV6);
+
+ skb->pkt_type = PACKET_HOST;
+
+ if (if_id < IP_MUX_SESSION_START ||
+ if_id > IP_MUX_SESSION_END) {
+ ret = -EINVAL;
+ goto free;
+ }
+
+ rcu_read_lock();
+ priv = rcu_dereference(ipc_wwan->sub_netlist[if_id]);
+ if (!priv) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+ skb->dev = priv->netdev;
+ stats = &priv->netdev->stats;
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+
+ ret = netif_rx(skb);
+ skb = NULL;
+unlock:
+ rcu_read_unlock();
+free:
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+void ipc_wwan_tx_flowctrl(struct iosm_wwan *ipc_wwan, int if_id, bool on)
+{
+ struct net_device *netdev;
+ struct iosm_netdev_priv *priv;
+ bool is_tx_blk;
+
+ rcu_read_lock();
+ priv = rcu_dereference(ipc_wwan->sub_netlist[if_id]);
+ if (!priv) {
+ rcu_read_unlock();
+ return;
+ }
+
+ netdev = priv->netdev;
+
+ is_tx_blk = netif_queue_stopped(netdev);
+
+ if (on)
+ dev_dbg(ipc_wwan->dev, "session id[%d]: flowctrl enable",
+ if_id);
+
+ if (on && !is_tx_blk)
+ netif_stop_queue(netdev);
+ else if (!on && is_tx_blk)
+ netif_wake_queue(netdev);
+ rcu_read_unlock();
+}
+
+struct iosm_wwan *ipc_wwan_init(struct iosm_imem *ipc_imem, struct device *dev)
+{
+ struct iosm_wwan *ipc_wwan;
+
+ ipc_wwan = kzalloc(sizeof(*ipc_wwan), GFP_KERNEL);
+ if (!ipc_wwan)
+ return NULL;
+
+ ipc_wwan->dev = dev;
+ ipc_wwan->ipc_imem = ipc_imem;
+
+ /* WWAN core will create a netdev for the default IP MUX channel */
+ if (wwan_register_ops(ipc_wwan->dev, &iosm_wwan_ops, ipc_wwan,
+ IP_MUX_SESSION_DEFAULT)) {
+ kfree(ipc_wwan);
+ return NULL;
+ }
+
+ mutex_init(&ipc_wwan->if_mutex);
+
+ return ipc_wwan;
+}
+
+void ipc_wwan_deinit(struct iosm_wwan *ipc_wwan)
+{
+ /* This call will remove all child netdev(s) */
+ wwan_unregister_ops(ipc_wwan->dev);
+
+ mutex_destroy(&ipc_wwan->if_mutex);
+
+ kfree(ipc_wwan);
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_wwan.h b/drivers/net/wwan/iosm/iosm_ipc_wwan.h
new file mode 100644
index 000000000000..4925f22dff0a
--- /dev/null
+++ b/drivers/net/wwan/iosm/iosm_ipc_wwan.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Copyright (C) 2020-21 Intel Corporation.
+ */
+
+#ifndef IOSM_IPC_WWAN_H
+#define IOSM_IPC_WWAN_H
+
+/**
+ * ipc_wwan_init - Allocate, Init and register WWAN device
+ * @ipc_imem: Pointer to imem data-struct
+ * @dev: Pointer to device structure
+ *
+ * Returns: Pointer to instance on success else NULL
+ */
+struct iosm_wwan *ipc_wwan_init(struct iosm_imem *ipc_imem, struct device *dev);
+
+/**
+ * ipc_wwan_deinit - Unregister and free WWAN device, clear pointer
+ * @ipc_wwan: Pointer to wwan instance data
+ */
+void ipc_wwan_deinit(struct iosm_wwan *ipc_wwan);
+
+/**
+ * ipc_wwan_receive - Receive a downlink packet from CP.
+ * @ipc_wwan: Pointer to wwan instance
+ * @skb_arg: Pointer to struct sk_buff
+ * @dss: Set to true if interafce id is from 257 to 261,
+ * else false
+ * @if_id: Interface ID
+ *
+ * Return: 0 on success and failure value on error
+ */
+int ipc_wwan_receive(struct iosm_wwan *ipc_wwan, struct sk_buff *skb_arg,
+ bool dss, int if_id);
+
+/**
+ * ipc_wwan_tx_flowctrl - Enable/Disable TX flow control
+ * @ipc_wwan: Pointer to wwan instance
+ * @id: Ipc mux channel session id
+ * @on: if true then flow ctrl would be enabled else disable
+ *
+ */
+void ipc_wwan_tx_flowctrl(struct iosm_wwan *ipc_wwan, int id, bool on);
+
+/**
+ * ipc_wwan_is_tx_stopped - Checks if Tx stopped for a Interface id.
+ * @ipc_wwan: Pointer to wwan instance
+ * @id: Ipc mux channel session id
+ *
+ * Return: true if stopped, false otherwise
+ */
+bool ipc_wwan_is_tx_stopped(struct iosm_wwan *ipc_wwan, int id);
+
+#endif
diff --git a/drivers/net/wwan/rpmsg_wwan_ctrl.c b/drivers/net/wwan/rpmsg_wwan_ctrl.c
new file mode 100644
index 000000000000..31c24420ab2e
--- /dev/null
+++ b/drivers/net/wwan/rpmsg_wwan_ctrl.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net> */
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rpmsg.h>
+#include <linux/wwan.h>
+
+struct rpmsg_wwan_dev {
+ /* Lower level is a rpmsg dev, upper level is a wwan port */
+ struct rpmsg_device *rpdev;
+ struct wwan_port *wwan_port;
+ struct rpmsg_endpoint *ept;
+};
+
+static int rpmsg_wwan_ctrl_callback(struct rpmsg_device *rpdev,
+ void *buf, int len, void *priv, u32 src)
+{
+ struct rpmsg_wwan_dev *rpwwan = priv;
+ struct sk_buff *skb;
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ skb_put_data(skb, buf, len);
+ wwan_port_rx(rpwwan->wwan_port, skb);
+ return 0;
+}
+
+static int rpmsg_wwan_ctrl_start(struct wwan_port *port)
+{
+ struct rpmsg_wwan_dev *rpwwan = wwan_port_get_drvdata(port);
+ struct rpmsg_channel_info chinfo = {
+ .src = rpwwan->rpdev->src,
+ .dst = RPMSG_ADDR_ANY,
+ };
+
+ strncpy(chinfo.name, rpwwan->rpdev->id.name, RPMSG_NAME_SIZE);
+ rpwwan->ept = rpmsg_create_ept(rpwwan->rpdev, rpmsg_wwan_ctrl_callback,
+ rpwwan, chinfo);
+ if (!rpwwan->ept)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static void rpmsg_wwan_ctrl_stop(struct wwan_port *port)
+{
+ struct rpmsg_wwan_dev *rpwwan = wwan_port_get_drvdata(port);
+
+ rpmsg_destroy_ept(rpwwan->ept);
+ rpwwan->ept = NULL;
+}
+
+static int rpmsg_wwan_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)
+{
+ struct rpmsg_wwan_dev *rpwwan = wwan_port_get_drvdata(port);
+ int ret;
+
+ ret = rpmsg_trysend(rpwwan->ept, skb->data, skb->len);
+ if (ret)
+ return ret;
+
+ consume_skb(skb);
+ return 0;
+}
+
+static int rpmsg_wwan_ctrl_tx_blocking(struct wwan_port *port, struct sk_buff *skb)
+{
+ struct rpmsg_wwan_dev *rpwwan = wwan_port_get_drvdata(port);
+ int ret;
+
+ ret = rpmsg_send(rpwwan->ept, skb->data, skb->len);
+ if (ret)
+ return ret;
+
+ consume_skb(skb);
+ return 0;
+}
+
+static __poll_t rpmsg_wwan_ctrl_tx_poll(struct wwan_port *port,
+ struct file *filp, poll_table *wait)
+{
+ struct rpmsg_wwan_dev *rpwwan = wwan_port_get_drvdata(port);
+
+ return rpmsg_poll(rpwwan->ept, filp, wait);
+}
+
+static const struct wwan_port_ops rpmsg_wwan_pops = {
+ .start = rpmsg_wwan_ctrl_start,
+ .stop = rpmsg_wwan_ctrl_stop,
+ .tx = rpmsg_wwan_ctrl_tx,
+ .tx_blocking = rpmsg_wwan_ctrl_tx_blocking,
+ .tx_poll = rpmsg_wwan_ctrl_tx_poll,
+};
+
+static struct device *rpmsg_wwan_find_parent(struct device *dev)
+{
+ /* Select first platform device as parent for the WWAN ports.
+ * On Qualcomm platforms this is usually the platform device that
+ * represents the modem remote processor. This might need to be
+ * adjusted when adding device IDs for other platforms.
+ */
+ for (dev = dev->parent; dev; dev = dev->parent) {
+ if (dev_is_platform(dev))
+ return dev;
+ }
+ return NULL;
+}
+
+static int rpmsg_wwan_ctrl_probe(struct rpmsg_device *rpdev)
+{
+ struct rpmsg_wwan_dev *rpwwan;
+ struct wwan_port *port;
+ struct device *parent;
+
+ parent = rpmsg_wwan_find_parent(&rpdev->dev);
+ if (!parent)
+ return -ENODEV;
+
+ rpwwan = devm_kzalloc(&rpdev->dev, sizeof(*rpwwan), GFP_KERNEL);
+ if (!rpwwan)
+ return -ENOMEM;
+
+ rpwwan->rpdev = rpdev;
+ dev_set_drvdata(&rpdev->dev, rpwwan);
+
+ /* Register as a wwan port, id.driver_data contains wwan port type */
+ port = wwan_create_port(parent, rpdev->id.driver_data,
+ &rpmsg_wwan_pops, rpwwan);
+ if (IS_ERR(port))
+ return PTR_ERR(port);
+
+ rpwwan->wwan_port = port;
+
+ return 0;
+};
+
+static void rpmsg_wwan_ctrl_remove(struct rpmsg_device *rpdev)
+{
+ struct rpmsg_wwan_dev *rpwwan = dev_get_drvdata(&rpdev->dev);
+
+ wwan_remove_port(rpwwan->wwan_port);
+}
+
+static const struct rpmsg_device_id rpmsg_wwan_ctrl_id_table[] = {
+ /* RPMSG channels for Qualcomm SoCs with integrated modem */
+ { .name = "DATA5_CNTL", .driver_data = WWAN_PORT_QMI },
+ { .name = "DATA4", .driver_data = WWAN_PORT_AT },
+ {},
+};
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_wwan_ctrl_id_table);
+
+static struct rpmsg_driver rpmsg_wwan_ctrl_driver = {
+ .drv.name = "rpmsg_wwan_ctrl",
+ .id_table = rpmsg_wwan_ctrl_id_table,
+ .probe = rpmsg_wwan_ctrl_probe,
+ .remove = rpmsg_wwan_ctrl_remove,
+};
+module_rpmsg_driver(rpmsg_wwan_ctrl_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("RPMSG WWAN CTRL Driver");
+MODULE_AUTHOR("Stephan Gerhold <stephan@gerhold.net>");
diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c
index cff04e532c1e..3e16c318e705 100644
--- a/drivers/net/wwan/wwan_core.c
+++ b/drivers/net/wwan/wwan_core.c
@@ -12,9 +12,13 @@
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/termios.h>
#include <linux/wwan.h>
+#include <net/rtnetlink.h>
+#include <uapi/linux/wwan.h>
-#define WWAN_MAX_MINORS 256 /* 256 minors allowed with register_chrdev() */
+/* Maximum number of minors in use */
+#define WWAN_MAX_MINORS (1 << MINORBITS)
static DEFINE_MUTEX(wwan_register_lock); /* WWAN device create|remove lock */
static DEFINE_IDA(minors); /* minors for WWAN port chardevs */
@@ -34,11 +38,15 @@ static int wwan_major;
* @id: WWAN device unique ID.
* @dev: Underlying device.
* @port_id: Current available port ID to pick.
+ * @ops: wwan device ops
+ * @ops_ctxt: context to pass to ops
*/
struct wwan_device {
unsigned int id;
struct device dev;
atomic_t port_id;
+ const struct wwan_ops *ops;
+ void *ops_ctxt;
};
/**
@@ -51,6 +59,8 @@ struct wwan_device {
* @dev: Underlying device
* @rxq: Buffer inbound queue
* @waitqueue: The waitqueue for port fops (read/write/poll)
+ * @data_lock: Port specific data access serialization
+ * @at_data: AT port specific data
*/
struct wwan_port {
enum wwan_port_type type;
@@ -61,8 +71,29 @@ struct wwan_port {
struct device dev;
struct sk_buff_head rxq;
wait_queue_head_t waitqueue;
+ struct mutex data_lock; /* Port specific data access serialization */
+ union {
+ struct {
+ struct ktermios termios;
+ int mdmbits;
+ } at_data;
+ };
};
+static ssize_t index_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct wwan_device *wwan = to_wwan_dev(dev);
+
+ return sprintf(buf, "%d\n", wwan->id);
+}
+static DEVICE_ATTR_RO(index);
+
+static struct attribute *wwan_dev_attrs[] = {
+ &dev_attr_index.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(wwan_dev);
+
static void wwan_dev_destroy(struct device *dev)
{
struct wwan_device *wwandev = to_wwan_dev(dev);
@@ -74,11 +105,13 @@ static void wwan_dev_destroy(struct device *dev)
static const struct device_type wwan_dev_type = {
.name = "wwan_dev",
.release = wwan_dev_destroy,
+ .groups = wwan_dev_groups,
};
static int wwan_dev_parent_match(struct device *dev, const void *parent)
{
- return (dev->type == &wwan_dev_type && dev->parent == parent);
+ return (dev->type == &wwan_dev_type &&
+ (dev->parent == parent || dev == parent));
}
static struct wwan_device *wwan_dev_get_by_parent(struct device *parent)
@@ -92,6 +125,23 @@ static struct wwan_device *wwan_dev_get_by_parent(struct device *parent)
return to_wwan_dev(dev);
}
+static int wwan_dev_name_match(struct device *dev, const void *name)
+{
+ return dev->type == &wwan_dev_type &&
+ strcmp(dev_name(dev), name) == 0;
+}
+
+static struct wwan_device *wwan_dev_get_by_name(const char *name)
+{
+ struct device *dev;
+
+ dev = class_find_device(wwan_class, NULL, name, wwan_dev_name_match);
+ if (!dev)
+ return ERR_PTR(-ENODEV);
+
+ return to_wwan_dev(dev);
+}
+
/* This function allocates and registers a new WWAN device OR if a WWAN device
* already exist for the given parent, it gets a reference and return it.
* This function is not exported (for now), it is called indirectly via
@@ -156,9 +206,14 @@ static void wwan_remove_dev(struct wwan_device *wwandev)
/* WWAN device is created and registered (get+add) along with its first
* child port, and subsequent port registrations only grab a reference
* (get). The WWAN device must then be unregistered (del+put) along with
- * its latest port, and reference simply dropped (put) otherwise.
+ * its last port, and reference simply dropped (put) otherwise. In the
+ * same fashion, we must not unregister it when the ops are still there.
*/
- ret = device_for_each_child(&wwandev->dev, NULL, is_wwan_child);
+ if (wwandev->ops)
+ ret = 1;
+ else
+ ret = device_for_each_child(&wwandev->dev, NULL, is_wwan_child);
+
if (!ret)
device_unregister(&wwandev->dev);
else
@@ -169,12 +224,53 @@ static void wwan_remove_dev(struct wwan_device *wwandev)
/* ------- WWAN port management ------- */
+static const struct {
+ const char * const name; /* Port type name */
+ const char * const devsuf; /* Port devce name suffix */
+} wwan_port_types[WWAN_PORT_MAX + 1] = {
+ [WWAN_PORT_AT] = {
+ .name = "AT",
+ .devsuf = "at",
+ },
+ [WWAN_PORT_MBIM] = {
+ .name = "MBIM",
+ .devsuf = "mbim",
+ },
+ [WWAN_PORT_QMI] = {
+ .name = "QMI",
+ .devsuf = "qmi",
+ },
+ [WWAN_PORT_QCDM] = {
+ .name = "QCDM",
+ .devsuf = "qcdm",
+ },
+ [WWAN_PORT_FIREHOSE] = {
+ .name = "FIREHOSE",
+ .devsuf = "firehose",
+ },
+};
+
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct wwan_port *port = to_wwan_port(dev);
+
+ return sprintf(buf, "%s\n", wwan_port_types[port->type].name);
+}
+static DEVICE_ATTR_RO(type);
+
+static struct attribute *wwan_port_attrs[] = {
+ &dev_attr_type.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(wwan_port);
+
static void wwan_port_destroy(struct device *dev)
{
struct wwan_port *port = to_wwan_port(dev);
ida_free(&minors, MINOR(port->dev.devt));
- skb_queue_purge(&port->rxq);
+ mutex_destroy(&port->data_lock);
mutex_destroy(&port->ops_lock);
kfree(port);
}
@@ -182,6 +278,7 @@ static void wwan_port_destroy(struct device *dev)
static const struct device_type wwan_port_dev_type = {
.name = "wwan_port",
.release = wwan_port_destroy,
+ .groups = wwan_port_groups,
};
static int wwan_port_minor_match(struct device *dev, const void *minor)
@@ -201,14 +298,55 @@ static struct wwan_port *wwan_port_get_by_minor(unsigned int minor)
return to_wwan_port(dev);
}
-/* Keep aligned with wwan_port_type enum */
-static const char * const wwan_port_type_str[] = {
- "AT",
- "MBIM",
- "QMI",
- "QCDM",
- "FIREHOSE"
-};
+/* Allocate and set unique name based on passed format
+ *
+ * Name allocation approach is highly inspired by the __dev_alloc_name()
+ * function.
+ *
+ * To avoid names collision, the caller must prevent the new port device
+ * registration as well as concurrent invocation of this function.
+ */
+static int __wwan_port_dev_assign_name(struct wwan_port *port, const char *fmt)
+{
+ struct wwan_device *wwandev = to_wwan_dev(port->dev.parent);
+ const unsigned int max_ports = PAGE_SIZE * 8;
+ struct class_dev_iter iter;
+ unsigned long *idmap;
+ struct device *dev;
+ char buf[0x20];
+ int id;
+
+ idmap = (unsigned long *)get_zeroed_page(GFP_KERNEL);
+ if (!idmap)
+ return -ENOMEM;
+
+ /* Collect ids of same name format ports */
+ class_dev_iter_init(&iter, wwan_class, NULL, &wwan_port_dev_type);
+ while ((dev = class_dev_iter_next(&iter))) {
+ if (dev->parent != &wwandev->dev)
+ continue;
+ if (sscanf(dev_name(dev), fmt, &id) != 1)
+ continue;
+ if (id < 0 || id >= max_ports)
+ continue;
+ set_bit(id, idmap);
+ }
+ class_dev_iter_exit(&iter);
+
+ /* Allocate unique id */
+ id = find_first_zero_bit(idmap, max_ports);
+ free_page((unsigned long)idmap);
+
+ snprintf(buf, sizeof(buf), fmt, id); /* Name generation */
+
+ dev = device_find_child_by_name(&wwandev->dev, buf);
+ if (dev) {
+ put_device(dev);
+ return -ENFILE;
+ }
+
+ return dev_set_name(&port->dev, buf);
+}
struct wwan_port *wwan_create_port(struct device *parent,
enum wwan_port_type type,
@@ -218,8 +356,9 @@ struct wwan_port *wwan_create_port(struct device *parent,
struct wwan_device *wwandev;
struct wwan_port *port;
int minor, err = -ENOMEM;
+ char namefmt[0x20];
- if (type >= WWAN_PORT_MAX || !ops)
+ if (type > WWAN_PORT_MAX || !ops)
return ERR_PTR(-EINVAL);
/* A port is always a child of a WWAN device, retrieve (allocate or
@@ -245,6 +384,7 @@ struct wwan_port *wwan_create_port(struct device *parent,
mutex_init(&port->ops_lock);
skb_queue_head_init(&port->rxq);
init_waitqueue_head(&port->waitqueue);
+ mutex_init(&port->data_lock);
port->dev.parent = &wwandev->dev;
port->dev.class = wwan_class;
@@ -252,12 +392,18 @@ struct wwan_port *wwan_create_port(struct device *parent,
port->dev.devt = MKDEV(wwan_major, minor);
dev_set_drvdata(&port->dev, drvdata);
- /* create unique name based on wwan device id, port index and type */
- dev_set_name(&port->dev, "wwan%up%u%s", wwandev->id,
- atomic_inc_return(&wwandev->port_id),
- wwan_port_type_str[port->type]);
+ /* allocate unique name based on wwan device id, port type and number */
+ snprintf(namefmt, sizeof(namefmt), "wwan%u%s%%d", wwandev->id,
+ wwan_port_types[port->type].devsuf);
+ /* Serialize ports registration */
+ mutex_lock(&wwan_register_lock);
+
+ __wwan_port_dev_assign_name(port, namefmt);
err = device_register(&port->dev);
+
+ mutex_unlock(&wwan_register_lock);
+
if (err)
goto error_put_device;
@@ -346,12 +492,16 @@ static void wwan_port_op_stop(struct wwan_port *port)
{
mutex_lock(&port->ops_lock);
port->start_count--;
- if (port->ops && !port->start_count)
- port->ops->stop(port);
+ if (!port->start_count) {
+ if (port->ops)
+ port->ops->stop(port);
+ skb_queue_purge(&port->rxq);
+ }
mutex_unlock(&port->ops_lock);
}
-static int wwan_port_op_tx(struct wwan_port *port, struct sk_buff *skb)
+static int wwan_port_op_tx(struct wwan_port *port, struct sk_buff *skb,
+ bool nonblock)
{
int ret;
@@ -361,7 +511,10 @@ static int wwan_port_op_tx(struct wwan_port *port, struct sk_buff *skb)
goto out_unlock;
}
- ret = port->ops->tx(port, skb);
+ if (nonblock || !port->ops->tx_blocking)
+ ret = port->ops->tx(port, skb);
+ else
+ ret = port->ops->tx_blocking(port, skb);
out_unlock:
mutex_unlock(&port->ops_lock);
@@ -488,7 +641,7 @@ static ssize_t wwan_port_fops_write(struct file *filp, const char __user *buf,
return -EFAULT;
}
- ret = wwan_port_op_tx(port, skb);
+ ret = wwan_port_op_tx(port, skb, !!(filp->f_flags & O_NONBLOCK));
if (ret) {
kfree_skb(skb);
return ret;
@@ -504,16 +657,124 @@ static __poll_t wwan_port_fops_poll(struct file *filp, poll_table *wait)
poll_wait(filp, &port->waitqueue, wait);
- if (!is_write_blocked(port))
+ mutex_lock(&port->ops_lock);
+ if (port->ops && port->ops->tx_poll)
+ mask |= port->ops->tx_poll(port, filp, wait);
+ else if (!is_write_blocked(port))
mask |= EPOLLOUT | EPOLLWRNORM;
if (!is_read_blocked(port))
mask |= EPOLLIN | EPOLLRDNORM;
if (!port->ops)
mask |= EPOLLHUP | EPOLLERR;
+ mutex_unlock(&port->ops_lock);
return mask;
}
+/* Implements minimalistic stub terminal IOCTLs support */
+static long wwan_port_fops_at_ioctl(struct wwan_port *port, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = 0;
+
+ mutex_lock(&port->data_lock);
+
+ switch (cmd) {
+ case TCFLSH:
+ break;
+
+ case TCGETS:
+ if (copy_to_user((void __user *)arg, &port->at_data.termios,
+ sizeof(struct termios)))
+ ret = -EFAULT;
+ break;
+
+ case TCSETS:
+ case TCSETSW:
+ case TCSETSF:
+ if (copy_from_user(&port->at_data.termios, (void __user *)arg,
+ sizeof(struct termios)))
+ ret = -EFAULT;
+ break;
+
+#ifdef TCGETS2
+ case TCGETS2:
+ if (copy_to_user((void __user *)arg, &port->at_data.termios,
+ sizeof(struct termios2)))
+ ret = -EFAULT;
+ break;
+
+ case TCSETS2:
+ case TCSETSW2:
+ case TCSETSF2:
+ if (copy_from_user(&port->at_data.termios, (void __user *)arg,
+ sizeof(struct termios2)))
+ ret = -EFAULT;
+ break;
+#endif
+
+ case TIOCMGET:
+ ret = put_user(port->at_data.mdmbits, (int __user *)arg);
+ break;
+
+ case TIOCMSET:
+ case TIOCMBIC:
+ case TIOCMBIS: {
+ int mdmbits;
+
+ if (copy_from_user(&mdmbits, (int __user *)arg, sizeof(int))) {
+ ret = -EFAULT;
+ break;
+ }
+ if (cmd == TIOCMBIC)
+ port->at_data.mdmbits &= ~mdmbits;
+ else if (cmd == TIOCMBIS)
+ port->at_data.mdmbits |= mdmbits;
+ else
+ port->at_data.mdmbits = mdmbits;
+ break;
+ }
+
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+
+ mutex_unlock(&port->data_lock);
+
+ return ret;
+}
+
+static long wwan_port_fops_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct wwan_port *port = filp->private_data;
+ int res;
+
+ if (port->type == WWAN_PORT_AT) { /* AT port specific IOCTLs */
+ res = wwan_port_fops_at_ioctl(port, cmd, arg);
+ if (res != -ENOIOCTLCMD)
+ return res;
+ }
+
+ switch (cmd) {
+ case TIOCINQ: { /* aka SIOCINQ aka FIONREAD */
+ unsigned long flags;
+ struct sk_buff *skb;
+ int amount = 0;
+
+ spin_lock_irqsave(&port->rxq.lock, flags);
+ skb_queue_walk(&port->rxq, skb)
+ amount += skb->len;
+ spin_unlock_irqrestore(&port->rxq.lock, flags);
+
+ return put_user(amount, (int __user *)arg);
+ }
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
static const struct file_operations wwan_port_fops = {
.owner = THIS_MODULE,
.open = wwan_port_fops_open,
@@ -521,28 +782,345 @@ static const struct file_operations wwan_port_fops = {
.read = wwan_port_fops_read,
.write = wwan_port_fops_write,
.poll = wwan_port_fops_poll,
+ .unlocked_ioctl = wwan_port_fops_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = compat_ptr_ioctl,
+#endif
.llseek = noop_llseek,
};
+static int wwan_rtnl_validate(struct nlattr *tb[], struct nlattr *data[],
+ struct netlink_ext_ack *extack)
+{
+ if (!data)
+ return -EINVAL;
+
+ if (!tb[IFLA_PARENT_DEV_NAME])
+ return -EINVAL;
+
+ if (!data[IFLA_WWAN_LINK_ID])
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct device_type wwan_type = { .name = "wwan" };
+
+static struct net_device *wwan_rtnl_alloc(struct nlattr *tb[],
+ const char *ifname,
+ unsigned char name_assign_type,
+ unsigned int num_tx_queues,
+ unsigned int num_rx_queues)
+{
+ const char *devname = nla_data(tb[IFLA_PARENT_DEV_NAME]);
+ struct wwan_device *wwandev = wwan_dev_get_by_name(devname);
+ struct net_device *dev;
+ unsigned int priv_size;
+
+ if (IS_ERR(wwandev))
+ return ERR_CAST(wwandev);
+
+ /* only supported if ops were registered (not just ports) */
+ if (!wwandev->ops) {
+ dev = ERR_PTR(-EOPNOTSUPP);
+ goto out;
+ }
+
+ priv_size = sizeof(struct wwan_netdev_priv) + wwandev->ops->priv_size;
+ dev = alloc_netdev_mqs(priv_size, ifname, name_assign_type,
+ wwandev->ops->setup, num_tx_queues, num_rx_queues);
+
+ if (dev) {
+ SET_NETDEV_DEV(dev, &wwandev->dev);
+ SET_NETDEV_DEVTYPE(dev, &wwan_type);
+ }
+
+out:
+ /* release the reference */
+ put_device(&wwandev->dev);
+ return dev;
+}
+
+static int wwan_rtnl_newlink(struct net *src_net, struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[],
+ struct netlink_ext_ack *extack)
+{
+ struct wwan_device *wwandev = wwan_dev_get_by_parent(dev->dev.parent);
+ u32 link_id = nla_get_u32(data[IFLA_WWAN_LINK_ID]);
+ struct wwan_netdev_priv *priv = netdev_priv(dev);
+ int ret;
+
+ if (IS_ERR(wwandev))
+ return PTR_ERR(wwandev);
+
+ /* shouldn't have a netdev (left) with us as parent so WARN */
+ if (WARN_ON(!wwandev->ops)) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ priv->link_id = link_id;
+ if (wwandev->ops->newlink)
+ ret = wwandev->ops->newlink(wwandev->ops_ctxt, dev,
+ link_id, extack);
+ else
+ ret = register_netdevice(dev);
+
+out:
+ /* release the reference */
+ put_device(&wwandev->dev);
+ return ret;
+}
+
+static void wwan_rtnl_dellink(struct net_device *dev, struct list_head *head)
+{
+ struct wwan_device *wwandev = wwan_dev_get_by_parent(dev->dev.parent);
+
+ if (IS_ERR(wwandev))
+ return;
+
+ /* shouldn't have a netdev (left) with us as parent so WARN */
+ if (WARN_ON(!wwandev->ops))
+ goto out;
+
+ if (wwandev->ops->dellink)
+ wwandev->ops->dellink(wwandev->ops_ctxt, dev, head);
+ else
+ unregister_netdevice_queue(dev, head);
+
+out:
+ /* release the reference */
+ put_device(&wwandev->dev);
+}
+
+static size_t wwan_rtnl_get_size(const struct net_device *dev)
+{
+ return
+ nla_total_size(4) + /* IFLA_WWAN_LINK_ID */
+ 0;
+}
+
+static int wwan_rtnl_fill_info(struct sk_buff *skb,
+ const struct net_device *dev)
+{
+ struct wwan_netdev_priv *priv = netdev_priv(dev);
+
+ if (nla_put_u32(skb, IFLA_WWAN_LINK_ID, priv->link_id))
+ goto nla_put_failure;
+
+ return 0;
+
+nla_put_failure:
+ return -EMSGSIZE;
+}
+
+static const struct nla_policy wwan_rtnl_policy[IFLA_WWAN_MAX + 1] = {
+ [IFLA_WWAN_LINK_ID] = { .type = NLA_U32 },
+};
+
+static struct rtnl_link_ops wwan_rtnl_link_ops __read_mostly = {
+ .kind = "wwan",
+ .maxtype = __IFLA_WWAN_MAX,
+ .alloc = wwan_rtnl_alloc,
+ .validate = wwan_rtnl_validate,
+ .newlink = wwan_rtnl_newlink,
+ .dellink = wwan_rtnl_dellink,
+ .get_size = wwan_rtnl_get_size,
+ .fill_info = wwan_rtnl_fill_info,
+ .policy = wwan_rtnl_policy,
+};
+
+static void wwan_create_default_link(struct wwan_device *wwandev,
+ u32 def_link_id)
+{
+ struct nlattr *tb[IFLA_MAX + 1], *linkinfo[IFLA_INFO_MAX + 1];
+ struct nlattr *data[IFLA_WWAN_MAX + 1];
+ struct net_device *dev;
+ struct nlmsghdr *nlh;
+ struct sk_buff *msg;
+
+ /* Forge attributes required to create a WWAN netdev. We first
+ * build a netlink message and then parse it. This looks
+ * odd, but such approach is less error prone.
+ */
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (WARN_ON(!msg))
+ return;
+ nlh = nlmsg_put(msg, 0, 0, RTM_NEWLINK, 0, 0);
+ if (WARN_ON(!nlh))
+ goto free_attrs;
+
+ if (nla_put_string(msg, IFLA_PARENT_DEV_NAME, dev_name(&wwandev->dev)))
+ goto free_attrs;
+ tb[IFLA_LINKINFO] = nla_nest_start(msg, IFLA_LINKINFO);
+ if (!tb[IFLA_LINKINFO])
+ goto free_attrs;
+ linkinfo[IFLA_INFO_DATA] = nla_nest_start(msg, IFLA_INFO_DATA);
+ if (!linkinfo[IFLA_INFO_DATA])
+ goto free_attrs;
+ if (nla_put_u32(msg, IFLA_WWAN_LINK_ID, def_link_id))
+ goto free_attrs;
+ nla_nest_end(msg, linkinfo[IFLA_INFO_DATA]);
+ nla_nest_end(msg, tb[IFLA_LINKINFO]);
+
+ nlmsg_end(msg, nlh);
+
+ /* The next three parsing calls can not fail */
+ nlmsg_parse_deprecated(nlh, 0, tb, IFLA_MAX, NULL, NULL);
+ nla_parse_nested_deprecated(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
+ NULL, NULL);
+ nla_parse_nested_deprecated(data, IFLA_WWAN_MAX,
+ linkinfo[IFLA_INFO_DATA], NULL, NULL);
+
+ rtnl_lock();
+
+ dev = rtnl_create_link(&init_net, "wwan%d", NET_NAME_ENUM,
+ &wwan_rtnl_link_ops, tb, NULL);
+ if (WARN_ON(IS_ERR(dev)))
+ goto unlock;
+
+ if (WARN_ON(wwan_rtnl_newlink(&init_net, dev, tb, data, NULL))) {
+ free_netdev(dev);
+ goto unlock;
+ }
+
+unlock:
+ rtnl_unlock();
+
+free_attrs:
+ nlmsg_free(msg);
+}
+
+/**
+ * wwan_register_ops - register WWAN device ops
+ * @parent: Device to use as parent and shared by all WWAN ports and
+ * created netdevs
+ * @ops: operations to register
+ * @ctxt: context to pass to operations
+ * @def_link_id: id of the default link that will be automatically created by
+ * the WWAN core for the WWAN device. The default link will not be created
+ * if the passed value is WWAN_NO_DEFAULT_LINK.
+ *
+ * Returns: 0 on success, a negative error code on failure
+ */
+int wwan_register_ops(struct device *parent, const struct wwan_ops *ops,
+ void *ctxt, u32 def_link_id)
+{
+ struct wwan_device *wwandev;
+
+ if (WARN_ON(!parent || !ops || !ops->setup))
+ return -EINVAL;
+
+ wwandev = wwan_create_dev(parent);
+ if (!wwandev)
+ return -ENOMEM;
+
+ if (WARN_ON(wwandev->ops)) {
+ wwan_remove_dev(wwandev);
+ return -EBUSY;
+ }
+
+ wwandev->ops = ops;
+ wwandev->ops_ctxt = ctxt;
+
+ /* NB: we do not abort ops registration in case of default link
+ * creation failure. Link ops is the management interface, while the
+ * default link creation is a service option. And we should not prevent
+ * a user from manually creating a link latter if service option failed
+ * now.
+ */
+ if (def_link_id != WWAN_NO_DEFAULT_LINK)
+ wwan_create_default_link(wwandev, def_link_id);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wwan_register_ops);
+
+/* Enqueue child netdev deletion */
+static int wwan_child_dellink(struct device *dev, void *data)
+{
+ struct list_head *kill_list = data;
+
+ if (dev->type == &wwan_type)
+ wwan_rtnl_dellink(to_net_dev(dev), kill_list);
+
+ return 0;
+}
+
+/**
+ * wwan_unregister_ops - remove WWAN device ops
+ * @parent: Device to use as parent and shared by all WWAN ports and
+ * created netdevs
+ */
+void wwan_unregister_ops(struct device *parent)
+{
+ struct wwan_device *wwandev = wwan_dev_get_by_parent(parent);
+ LIST_HEAD(kill_list);
+
+ if (WARN_ON(IS_ERR(wwandev)))
+ return;
+ if (WARN_ON(!wwandev->ops)) {
+ put_device(&wwandev->dev);
+ return;
+ }
+
+ /* put the reference obtained by wwan_dev_get_by_parent(),
+ * we should still have one (that the owner is giving back
+ * now) due to the ops being assigned.
+ */
+ put_device(&wwandev->dev);
+
+ rtnl_lock(); /* Prevent concurent netdev(s) creation/destroying */
+
+ /* Remove all child netdev(s), using batch removing */
+ device_for_each_child(&wwandev->dev, &kill_list,
+ wwan_child_dellink);
+ unregister_netdevice_many(&kill_list);
+
+ wwandev->ops = NULL; /* Finally remove ops */
+
+ rtnl_unlock();
+
+ wwandev->ops_ctxt = NULL;
+ wwan_remove_dev(wwandev);
+}
+EXPORT_SYMBOL_GPL(wwan_unregister_ops);
+
static int __init wwan_init(void)
{
+ int err;
+
+ err = rtnl_link_register(&wwan_rtnl_link_ops);
+ if (err)
+ return err;
+
wwan_class = class_create(THIS_MODULE, "wwan");
- if (IS_ERR(wwan_class))
- return PTR_ERR(wwan_class);
+ if (IS_ERR(wwan_class)) {
+ err = PTR_ERR(wwan_class);
+ goto unregister;
+ }
/* chrdev used for wwan ports */
- wwan_major = register_chrdev(0, "wwan_port", &wwan_port_fops);
+ wwan_major = __register_chrdev(0, 0, WWAN_MAX_MINORS, "wwan_port",
+ &wwan_port_fops);
if (wwan_major < 0) {
- class_destroy(wwan_class);
- return wwan_major;
+ err = wwan_major;
+ goto destroy;
}
return 0;
+
+destroy:
+ class_destroy(wwan_class);
+unregister:
+ rtnl_link_unregister(&wwan_rtnl_link_ops);
+ return err;
}
static void __exit wwan_exit(void)
{
- unregister_chrdev(wwan_major, "wwan_port");
+ __unregister_chrdev(wwan_major, 0, WWAN_MAX_MINORS, "wwan_port");
+ rtnl_link_unregister(&wwan_rtnl_link_ops);
class_destroy(wwan_class);
}
diff --git a/drivers/net/wwan/wwan_hwsim.c b/drivers/net/wwan/wwan_hwsim.c
new file mode 100644
index 000000000000..5b62cf3b3c42
--- /dev/null
+++ b/drivers/net/wwan/wwan_hwsim.c
@@ -0,0 +1,547 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * WWAN device simulator for WWAN framework testing.
+ *
+ * Copyright (c) 2021, Sergey Ryazanov <ryazanov.s.a@gmail.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wwan.h>
+#include <linux/debugfs.h>
+#include <linux/workqueue.h>
+
+#include <net/arp.h>
+
+static int wwan_hwsim_devsnum = 2;
+module_param_named(devices, wwan_hwsim_devsnum, int, 0444);
+MODULE_PARM_DESC(devices, "Number of simulated devices");
+
+static struct class *wwan_hwsim_class;
+
+static struct dentry *wwan_hwsim_debugfs_topdir;
+static struct dentry *wwan_hwsim_debugfs_devcreate;
+
+static DEFINE_SPINLOCK(wwan_hwsim_devs_lock);
+static LIST_HEAD(wwan_hwsim_devs);
+static unsigned int wwan_hwsim_dev_idx;
+
+struct wwan_hwsim_dev {
+ struct list_head list;
+ unsigned int id;
+ struct device dev;
+ struct work_struct del_work;
+ struct dentry *debugfs_topdir;
+ struct dentry *debugfs_portcreate;
+ spinlock_t ports_lock; /* Serialize ports creation/deletion */
+ unsigned int port_idx;
+ struct list_head ports;
+};
+
+struct wwan_hwsim_port {
+ struct list_head list;
+ unsigned int id;
+ struct wwan_hwsim_dev *dev;
+ struct wwan_port *wwan;
+ struct work_struct del_work;
+ struct dentry *debugfs_topdir;
+ enum { /* AT command parser state */
+ AT_PARSER_WAIT_A,
+ AT_PARSER_WAIT_T,
+ AT_PARSER_WAIT_TERM,
+ AT_PARSER_SKIP_LINE,
+ } pstate;
+};
+
+static const struct file_operations wwan_hwsim_debugfs_portdestroy_fops;
+static const struct file_operations wwan_hwsim_debugfs_portcreate_fops;
+static const struct file_operations wwan_hwsim_debugfs_devdestroy_fops;
+static void wwan_hwsim_port_del_work(struct work_struct *work);
+static void wwan_hwsim_dev_del_work(struct work_struct *work);
+
+static netdev_tx_t wwan_hwsim_netdev_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
+ consume_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops wwan_hwsim_netdev_ops = {
+ .ndo_start_xmit = wwan_hwsim_netdev_xmit,
+};
+
+static void wwan_hwsim_netdev_setup(struct net_device *ndev)
+{
+ ndev->netdev_ops = &wwan_hwsim_netdev_ops;
+ ndev->needs_free_netdev = true;
+
+ ndev->mtu = ETH_DATA_LEN;
+ ndev->min_mtu = ETH_MIN_MTU;
+ ndev->max_mtu = ETH_MAX_MTU;
+
+ ndev->type = ARPHRD_NONE;
+ ndev->flags = IFF_POINTOPOINT | IFF_NOARP;
+}
+
+static const struct wwan_ops wwan_hwsim_wwan_rtnl_ops = {
+ .priv_size = 0, /* No private data */
+ .setup = wwan_hwsim_netdev_setup,
+};
+
+static int wwan_hwsim_port_start(struct wwan_port *wport)
+{
+ struct wwan_hwsim_port *port = wwan_port_get_drvdata(wport);
+
+ port->pstate = AT_PARSER_WAIT_A;
+
+ return 0;
+}
+
+static void wwan_hwsim_port_stop(struct wwan_port *wport)
+{
+}
+
+/* Implements a minimalistic AT commands parser that echo input back and
+ * reply with 'OK' to each input command. See AT command protocol details in the
+ * ITU-T V.250 recomendations document.
+ *
+ * Be aware that this processor is not fully V.250 compliant.
+ */
+static int wwan_hwsim_port_tx(struct wwan_port *wport, struct sk_buff *in)
+{
+ struct wwan_hwsim_port *port = wwan_port_get_drvdata(wport);
+ struct sk_buff *out;
+ int i, n, s;
+
+ /* Estimate a max possible number of commands by counting the number of
+ * termination chars (S3 param, CR by default). And then allocate the
+ * output buffer that will be enough to fit the echo and result codes of
+ * all commands.
+ */
+ for (i = 0, n = 0; i < in->len; ++i)
+ if (in->data[i] == '\r')
+ n++;
+ n = in->len + n * (2 + 2 + 2); /* Output buffer size */
+ out = alloc_skb(n, GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ for (i = 0, s = 0; i < in->len; ++i) {
+ char c = in->data[i];
+
+ if (port->pstate == AT_PARSER_WAIT_A) {
+ if (c == 'A' || c == 'a')
+ port->pstate = AT_PARSER_WAIT_T;
+ else if (c != '\n') /* Ignore formating char */
+ port->pstate = AT_PARSER_SKIP_LINE;
+ } else if (port->pstate == AT_PARSER_WAIT_T) {
+ if (c == 'T' || c == 't')
+ port->pstate = AT_PARSER_WAIT_TERM;
+ else
+ port->pstate = AT_PARSER_SKIP_LINE;
+ } else if (port->pstate == AT_PARSER_WAIT_TERM) {
+ if (c != '\r')
+ continue;
+ /* Consume the trailing formatting char as well */
+ if ((i + 1) < in->len && in->data[i + 1] == '\n')
+ i++;
+ n = i - s + 1;
+ memcpy(skb_put(out, n), &in->data[s], n);/* Echo */
+ memcpy(skb_put(out, 6), "\r\nOK\r\n", 6);
+ s = i + 1;
+ port->pstate = AT_PARSER_WAIT_A;
+ } else if (port->pstate == AT_PARSER_SKIP_LINE) {
+ if (c != '\r')
+ continue;
+ port->pstate = AT_PARSER_WAIT_A;
+ }
+ }
+
+ if (i > s) {
+ /* Echo the processed portion of a not yet completed command */
+ n = i - s;
+ memcpy(skb_put(out, n), &in->data[s], n);
+ }
+
+ consume_skb(in);
+
+ wwan_port_rx(wport, out);
+
+ return 0;
+}
+
+static const struct wwan_port_ops wwan_hwsim_port_ops = {
+ .start = wwan_hwsim_port_start,
+ .stop = wwan_hwsim_port_stop,
+ .tx = wwan_hwsim_port_tx,
+};
+
+static struct wwan_hwsim_port *wwan_hwsim_port_new(struct wwan_hwsim_dev *dev)
+{
+ struct wwan_hwsim_port *port;
+ char name[0x10];
+ int err;
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return ERR_PTR(-ENOMEM);
+
+ port->dev = dev;
+
+ spin_lock(&dev->ports_lock);
+ port->id = dev->port_idx++;
+ spin_unlock(&dev->ports_lock);
+
+ port->wwan = wwan_create_port(&dev->dev, WWAN_PORT_AT,
+ &wwan_hwsim_port_ops,
+ port);
+ if (IS_ERR(port->wwan)) {
+ err = PTR_ERR(port->wwan);
+ goto err_free_port;
+ }
+
+ INIT_WORK(&port->del_work, wwan_hwsim_port_del_work);
+
+ snprintf(name, sizeof(name), "port%u", port->id);
+ port->debugfs_topdir = debugfs_create_dir(name, dev->debugfs_topdir);
+ debugfs_create_file("destroy", 0200, port->debugfs_topdir, port,
+ &wwan_hwsim_debugfs_portdestroy_fops);
+
+ return port;
+
+err_free_port:
+ kfree(port);
+
+ return ERR_PTR(err);
+}
+
+static void wwan_hwsim_port_del(struct wwan_hwsim_port *port)
+{
+ debugfs_remove(port->debugfs_topdir);
+
+ /* Make sure that there is no pending deletion work */
+ if (current_work() != &port->del_work)
+ cancel_work_sync(&port->del_work);
+
+ wwan_remove_port(port->wwan);
+ kfree(port);
+}
+
+static void wwan_hwsim_port_del_work(struct work_struct *work)
+{
+ struct wwan_hwsim_port *port =
+ container_of(work, typeof(*port), del_work);
+ struct wwan_hwsim_dev *dev = port->dev;
+
+ spin_lock(&dev->ports_lock);
+ if (list_empty(&port->list)) {
+ /* Someone else deleting port at the moment */
+ spin_unlock(&dev->ports_lock);
+ return;
+ }
+ list_del_init(&port->list);
+ spin_unlock(&dev->ports_lock);
+
+ wwan_hwsim_port_del(port);
+}
+
+static void wwan_hwsim_dev_release(struct device *sysdev)
+{
+ struct wwan_hwsim_dev *dev = container_of(sysdev, typeof(*dev), dev);
+
+ kfree(dev);
+}
+
+static struct wwan_hwsim_dev *wwan_hwsim_dev_new(void)
+{
+ struct wwan_hwsim_dev *dev;
+ int err;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock(&wwan_hwsim_devs_lock);
+ dev->id = wwan_hwsim_dev_idx++;
+ spin_unlock(&wwan_hwsim_devs_lock);
+
+ dev->dev.release = wwan_hwsim_dev_release;
+ dev->dev.class = wwan_hwsim_class;
+ dev_set_name(&dev->dev, "hwsim%u", dev->id);
+
+ spin_lock_init(&dev->ports_lock);
+ INIT_LIST_HEAD(&dev->ports);
+
+ err = device_register(&dev->dev);
+ if (err)
+ goto err_free_dev;
+
+ INIT_WORK(&dev->del_work, wwan_hwsim_dev_del_work);
+
+ err = wwan_register_ops(&dev->dev, &wwan_hwsim_wwan_rtnl_ops, dev, 1);
+ if (err)
+ goto err_unreg_dev;
+
+ dev->debugfs_topdir = debugfs_create_dir(dev_name(&dev->dev),
+ wwan_hwsim_debugfs_topdir);
+ debugfs_create_file("destroy", 0200, dev->debugfs_topdir, dev,
+ &wwan_hwsim_debugfs_devdestroy_fops);
+ dev->debugfs_portcreate =
+ debugfs_create_file("portcreate", 0200,
+ dev->debugfs_topdir, dev,
+ &wwan_hwsim_debugfs_portcreate_fops);
+
+ return dev;
+
+err_unreg_dev:
+ device_unregister(&dev->dev);
+ /* Memory will be freed in the device release callback */
+
+ return ERR_PTR(err);
+
+err_free_dev:
+ kfree(dev);
+
+ return ERR_PTR(err);
+}
+
+static void wwan_hwsim_dev_del(struct wwan_hwsim_dev *dev)
+{
+ debugfs_remove(dev->debugfs_portcreate); /* Avoid new ports */
+
+ spin_lock(&dev->ports_lock);
+ while (!list_empty(&dev->ports)) {
+ struct wwan_hwsim_port *port;
+
+ port = list_first_entry(&dev->ports, struct wwan_hwsim_port,
+ list);
+ list_del_init(&port->list);
+ spin_unlock(&dev->ports_lock);
+ wwan_hwsim_port_del(port);
+ spin_lock(&dev->ports_lock);
+ }
+ spin_unlock(&dev->ports_lock);
+
+ debugfs_remove(dev->debugfs_topdir);
+
+ /* This will remove all child netdev(s) */
+ wwan_unregister_ops(&dev->dev);
+
+ /* Make sure that there is no pending deletion work */
+ if (current_work() != &dev->del_work)
+ cancel_work_sync(&dev->del_work);
+
+ device_unregister(&dev->dev);
+ /* Memory will be freed in the device release callback */
+}
+
+static void wwan_hwsim_dev_del_work(struct work_struct *work)
+{
+ struct wwan_hwsim_dev *dev = container_of(work, typeof(*dev), del_work);
+
+ spin_lock(&wwan_hwsim_devs_lock);
+ if (list_empty(&dev->list)) {
+ /* Someone else deleting device at the moment */
+ spin_unlock(&wwan_hwsim_devs_lock);
+ return;
+ }
+ list_del_init(&dev->list);
+ spin_unlock(&wwan_hwsim_devs_lock);
+
+ wwan_hwsim_dev_del(dev);
+}
+
+static ssize_t wwan_hwsim_debugfs_portdestroy_write(struct file *file,
+ const char __user *usrbuf,
+ size_t count, loff_t *ppos)
+{
+ struct wwan_hwsim_port *port = file->private_data;
+
+ /* We can not delete port here since it will cause a deadlock due to
+ * waiting this callback to finish in the debugfs_remove() call. So,
+ * use workqueue.
+ */
+ schedule_work(&port->del_work);
+
+ return count;
+}
+
+static const struct file_operations wwan_hwsim_debugfs_portdestroy_fops = {
+ .write = wwan_hwsim_debugfs_portdestroy_write,
+ .open = simple_open,
+ .llseek = noop_llseek,
+};
+
+static ssize_t wwan_hwsim_debugfs_portcreate_write(struct file *file,
+ const char __user *usrbuf,
+ size_t count, loff_t *ppos)
+{
+ struct wwan_hwsim_dev *dev = file->private_data;
+ struct wwan_hwsim_port *port;
+
+ port = wwan_hwsim_port_new(dev);
+ if (IS_ERR(port))
+ return PTR_ERR(port);
+
+ spin_lock(&dev->ports_lock);
+ list_add_tail(&port->list, &dev->ports);
+ spin_unlock(&dev->ports_lock);
+
+ return count;
+}
+
+static const struct file_operations wwan_hwsim_debugfs_portcreate_fops = {
+ .write = wwan_hwsim_debugfs_portcreate_write,
+ .open = simple_open,
+ .llseek = noop_llseek,
+};
+
+static ssize_t wwan_hwsim_debugfs_devdestroy_write(struct file *file,
+ const char __user *usrbuf,
+ size_t count, loff_t *ppos)
+{
+ struct wwan_hwsim_dev *dev = file->private_data;
+
+ /* We can not delete device here since it will cause a deadlock due to
+ * waiting this callback to finish in the debugfs_remove() call. So,
+ * use workqueue.
+ */
+ schedule_work(&dev->del_work);
+
+ return count;
+}
+
+static const struct file_operations wwan_hwsim_debugfs_devdestroy_fops = {
+ .write = wwan_hwsim_debugfs_devdestroy_write,
+ .open = simple_open,
+ .llseek = noop_llseek,
+};
+
+static ssize_t wwan_hwsim_debugfs_devcreate_write(struct file *file,
+ const char __user *usrbuf,
+ size_t count, loff_t *ppos)
+{
+ struct wwan_hwsim_dev *dev;
+
+ dev = wwan_hwsim_dev_new();
+ if (IS_ERR(dev))
+ return PTR_ERR(dev);
+
+ spin_lock(&wwan_hwsim_devs_lock);
+ list_add_tail(&dev->list, &wwan_hwsim_devs);
+ spin_unlock(&wwan_hwsim_devs_lock);
+
+ return count;
+}
+
+static const struct file_operations wwan_hwsim_debugfs_devcreate_fops = {
+ .write = wwan_hwsim_debugfs_devcreate_write,
+ .open = simple_open,
+ .llseek = noop_llseek,
+};
+
+static int __init wwan_hwsim_init_devs(void)
+{
+ struct wwan_hwsim_dev *dev;
+ int i, j;
+
+ for (i = 0; i < wwan_hwsim_devsnum; ++i) {
+ dev = wwan_hwsim_dev_new();
+ if (IS_ERR(dev))
+ return PTR_ERR(dev);
+
+ spin_lock(&wwan_hwsim_devs_lock);
+ list_add_tail(&dev->list, &wwan_hwsim_devs);
+ spin_unlock(&wwan_hwsim_devs_lock);
+
+ /* Create a couple of ports per each device to accelerate
+ * the simulator readiness time.
+ */
+ for (j = 0; j < 2; ++j) {
+ struct wwan_hwsim_port *port;
+
+ port = wwan_hwsim_port_new(dev);
+ if (IS_ERR(port))
+ return PTR_ERR(port);
+
+ spin_lock(&dev->ports_lock);
+ list_add_tail(&port->list, &dev->ports);
+ spin_unlock(&dev->ports_lock);
+ }
+ }
+
+ return 0;
+}
+
+static void wwan_hwsim_free_devs(void)
+{
+ struct wwan_hwsim_dev *dev;
+
+ spin_lock(&wwan_hwsim_devs_lock);
+ while (!list_empty(&wwan_hwsim_devs)) {
+ dev = list_first_entry(&wwan_hwsim_devs, struct wwan_hwsim_dev,
+ list);
+ list_del_init(&dev->list);
+ spin_unlock(&wwan_hwsim_devs_lock);
+ wwan_hwsim_dev_del(dev);
+ spin_lock(&wwan_hwsim_devs_lock);
+ }
+ spin_unlock(&wwan_hwsim_devs_lock);
+}
+
+static int __init wwan_hwsim_init(void)
+{
+ int err;
+
+ if (wwan_hwsim_devsnum < 0 || wwan_hwsim_devsnum > 128)
+ return -EINVAL;
+
+ wwan_hwsim_class = class_create(THIS_MODULE, "wwan_hwsim");
+ if (IS_ERR(wwan_hwsim_class))
+ return PTR_ERR(wwan_hwsim_class);
+
+ wwan_hwsim_debugfs_topdir = debugfs_create_dir("wwan_hwsim", NULL);
+ wwan_hwsim_debugfs_devcreate =
+ debugfs_create_file("devcreate", 0200,
+ wwan_hwsim_debugfs_topdir, NULL,
+ &wwan_hwsim_debugfs_devcreate_fops);
+
+ err = wwan_hwsim_init_devs();
+ if (err)
+ goto err_clean_devs;
+
+ return 0;
+
+err_clean_devs:
+ wwan_hwsim_free_devs();
+ debugfs_remove(wwan_hwsim_debugfs_topdir);
+ class_destroy(wwan_hwsim_class);
+
+ return err;
+}
+
+static void __exit wwan_hwsim_exit(void)
+{
+ debugfs_remove(wwan_hwsim_debugfs_devcreate); /* Avoid new devs */
+ wwan_hwsim_free_devs();
+ flush_scheduled_work(); /* Wait deletion works completion */
+ debugfs_remove(wwan_hwsim_debugfs_topdir);
+ class_destroy(wwan_hwsim_class);
+}
+
+module_init(wwan_hwsim_init);
+module_exit(wwan_hwsim_exit);
+
+MODULE_AUTHOR("Sergey Ryazanov");
+MODULE_DESCRIPTION("Device simulator for WWAN framework");
+MODULE_LICENSE("GPL");
diff --git a/drivers/nfc/fdp/fdp.c b/drivers/nfc/fdp/fdp.c
index fe0719ed81a0..528745862738 100644
--- a/drivers/nfc/fdp/fdp.c
+++ b/drivers/nfc/fdp/fdp.c
@@ -149,7 +149,7 @@ static void fdp_nci_send_patch_cb(struct nci_dev *ndev)
wake_up(&info->setup_wq);
}
-/**
+/*
* Register a packet sent counter and a callback
*
* We have no other way of knowing when all firmware packets were sent out
@@ -167,7 +167,7 @@ static void fdp_nci_set_data_pkt_counter(struct nci_dev *ndev,
info->data_pkt_counter_cb = cb;
}
-/**
+/*
* The device is expecting a stream of packets. All packets need to
* have the PBF flag set to 0x0 (last packet) even if the firmware
* file is segmented and there are multiple packets. If we give the
@@ -237,28 +237,18 @@ static int fdp_nci_send_patch(struct nci_dev *ndev, u8 conn_id, u8 type)
static int fdp_nci_open(struct nci_dev *ndev)
{
struct fdp_nci_info *info = nci_get_drvdata(ndev);
- struct device *dev = &info->phy->i2c_dev->dev;
-
- dev_dbg(dev, "%s\n", __func__);
return info->phy_ops->enable(info->phy);
}
static int fdp_nci_close(struct nci_dev *ndev)
{
- struct fdp_nci_info *info = nci_get_drvdata(ndev);
- struct device *dev = &info->phy->i2c_dev->dev;
-
- dev_dbg(dev, "%s\n", __func__);
return 0;
}
static int fdp_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
{
struct fdp_nci_info *info = nci_get_drvdata(ndev);
- struct device *dev = &info->phy->i2c_dev->dev;
-
- dev_dbg(dev, "%s\n", __func__);
if (atomic_dec_and_test(&info->data_pkt_counter))
info->data_pkt_counter_cb(ndev);
@@ -266,16 +256,6 @@ static int fdp_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
return info->phy_ops->write(info->phy, skb);
}
-int fdp_nci_recv_frame(struct nci_dev *ndev, struct sk_buff *skb)
-{
- struct fdp_nci_info *info = nci_get_drvdata(ndev);
- struct device *dev = &info->phy->i2c_dev->dev;
-
- dev_dbg(dev, "%s\n", __func__);
- return nci_recv_frame(ndev, skb);
-}
-EXPORT_SYMBOL(fdp_nci_recv_frame);
-
static int fdp_nci_request_firmware(struct nci_dev *ndev)
{
struct fdp_nci_info *info = nci_get_drvdata(ndev);
@@ -286,7 +266,7 @@ static int fdp_nci_request_firmware(struct nci_dev *ndev)
r = request_firmware(&info->ram_patch, FDP_RAM_PATCH_NAME, dev);
if (r < 0) {
nfc_err(dev, "RAM patch request error\n");
- goto error;
+ return r;
}
data = (u8 *) info->ram_patch->data;
@@ -303,7 +283,7 @@ static int fdp_nci_request_firmware(struct nci_dev *ndev)
r = request_firmware(&info->otp_patch, FDP_OTP_PATCH_NAME, dev);
if (r < 0) {
nfc_err(dev, "OTP patch request error\n");
- goto out;
+ return 0;
}
data = (u8 *) info->otp_patch->data;
@@ -315,10 +295,7 @@ static int fdp_nci_request_firmware(struct nci_dev *ndev)
dev_dbg(dev, "OTP patch version: %d, size: %d\n",
info->otp_patch_version, (int) info->otp_patch->size);
-out:
return 0;
-error:
- return r;
}
static void fdp_nci_release_firmware(struct nci_dev *ndev)
@@ -476,8 +453,6 @@ static int fdp_nci_setup(struct nci_dev *ndev)
int r;
u8 patched = 0;
- dev_dbg(dev, "%s\n", __func__);
-
r = nci_core_init(ndev);
if (r)
goto error;
@@ -585,9 +560,7 @@ static int fdp_nci_core_reset_ntf_packet(struct nci_dev *ndev,
struct sk_buff *skb)
{
struct fdp_nci_info *info = nci_get_drvdata(ndev);
- struct device *dev = &info->phy->i2c_dev->dev;
- dev_dbg(dev, "%s\n", __func__);
info->setup_reset_ntf = 1;
wake_up(&info->setup_wq);
@@ -598,9 +571,7 @@ static int fdp_nci_prop_patch_ntf_packet(struct nci_dev *ndev,
struct sk_buff *skb)
{
struct fdp_nci_info *info = nci_get_drvdata(ndev);
- struct device *dev = &info->phy->i2c_dev->dev;
- dev_dbg(dev, "%s\n", __func__);
info->setup_patch_ntf = 1;
info->setup_patch_status = skb->data[0];
wake_up(&info->setup_wq);
@@ -773,11 +744,6 @@ EXPORT_SYMBOL(fdp_nci_probe);
void fdp_nci_remove(struct nci_dev *ndev)
{
- struct fdp_nci_info *info = nci_get_drvdata(ndev);
- struct device *dev = &info->phy->i2c_dev->dev;
-
- dev_dbg(dev, "%s\n", __func__);
-
nci_unregister_device(ndev);
nci_free_device(ndev);
}
diff --git a/drivers/nfc/fdp/fdp.h b/drivers/nfc/fdp/fdp.h
index 9bd1f3f23e2d..ead3b21ccae6 100644
--- a/drivers/nfc/fdp/fdp.h
+++ b/drivers/nfc/fdp/fdp.h
@@ -25,6 +25,5 @@ int fdp_nci_probe(struct fdp_i2c_phy *phy, struct nfc_phy_ops *phy_ops,
struct nci_dev **ndev, int tx_headroom, int tx_tailroom,
u8 clock_type, u32 clock_freq, u8 *fw_vsc_cfg);
void fdp_nci_remove(struct nci_dev *ndev);
-int fdp_nci_recv_frame(struct nci_dev *ndev, struct sk_buff *skb);
#endif /* __LOCAL_FDP_H_ */
diff --git a/drivers/nfc/fdp/i2c.c b/drivers/nfc/fdp/i2c.c
index adaa1a7147f9..c5596e514648 100644
--- a/drivers/nfc/fdp/i2c.c
+++ b/drivers/nfc/fdp/i2c.c
@@ -49,7 +49,6 @@ static int fdp_nci_i2c_enable(void *phy_id)
{
struct fdp_i2c_phy *phy = phy_id;
- dev_dbg(&phy->i2c_dev->dev, "%s\n", __func__);
fdp_nci_i2c_reset(phy);
return 0;
@@ -59,7 +58,6 @@ static void fdp_nci_i2c_disable(void *phy_id)
{
struct fdp_i2c_phy *phy = phy_id;
- dev_dbg(&phy->i2c_dev->dev, "%s\n", __func__);
fdp_nci_i2c_reset(phy);
}
@@ -197,7 +195,6 @@ flush:
static irqreturn_t fdp_nci_i2c_irq_thread_fn(int irq, void *phy_id)
{
struct fdp_i2c_phy *phy = phy_id;
- struct i2c_client *client;
struct sk_buff *skb;
int r;
@@ -206,9 +203,6 @@ static irqreturn_t fdp_nci_i2c_irq_thread_fn(int irq, void *phy_id)
return IRQ_NONE;
}
- client = phy->i2c_dev;
- dev_dbg(&client->dev, "%s\n", __func__);
-
r = fdp_nci_i2c_read(phy, &skb);
if (r == -EREMOTEIO)
@@ -217,7 +211,7 @@ static irqreturn_t fdp_nci_i2c_irq_thread_fn(int irq, void *phy_id)
return IRQ_HANDLED;
if (skb != NULL)
- fdp_nci_recv_frame(phy->ndev, skb);
+ nci_recv_frame(phy->ndev, skb);
return IRQ_HANDLED;
}
@@ -288,8 +282,6 @@ static int fdp_nci_i2c_probe(struct i2c_client *client)
u32 clock_freq;
int r = 0;
- dev_dbg(dev, "%s\n", __func__);
-
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
nfc_err(dev, "No I2C_FUNC_I2C support\n");
return -ENODEV;
@@ -351,8 +343,6 @@ static int fdp_nci_i2c_remove(struct i2c_client *client)
{
struct fdp_i2c_phy *phy = i2c_get_clientdata(client);
- dev_dbg(&client->dev, "%s\n", __func__);
-
fdp_nci_remove(phy->ndev);
fdp_nci_i2c_disable(phy);
@@ -368,7 +358,7 @@ MODULE_DEVICE_TABLE(acpi, fdp_nci_i2c_acpi_match);
static struct i2c_driver fdp_nci_i2c_driver = {
.driver = {
.name = FDP_I2C_DRIVER_NAME,
- .acpi_match_table = ACPI_PTR(fdp_nci_i2c_acpi_match),
+ .acpi_match_table = fdp_nci_i2c_acpi_match,
},
.probe_new = fdp_nci_i2c_probe,
.remove = fdp_nci_i2c_remove,
diff --git a/drivers/nfc/mei_phy.c b/drivers/nfc/mei_phy.c
index 0f43bb389566..e56cea716cd2 100644
--- a/drivers/nfc/mei_phy.c
+++ b/drivers/nfc/mei_phy.c
@@ -98,8 +98,6 @@ static int mei_nfc_if_version(struct nfc_mei_phy *phy)
size_t if_version_length;
int bytes_recv, r;
- pr_info("%s\n", __func__);
-
memset(&cmd, 0, sizeof(struct mei_nfc_cmd));
cmd.hdr.cmd = MEI_NFC_CMD_MAINTENANCE;
cmd.hdr.data_size = 1;
@@ -146,8 +144,6 @@ static int mei_nfc_connect(struct nfc_mei_phy *phy)
size_t connect_length, connect_resp_length;
int bytes_recv, r;
- pr_info("%s\n", __func__);
-
connect_length = sizeof(struct mei_nfc_cmd) +
sizeof(struct mei_nfc_connect);
@@ -320,8 +316,6 @@ static int nfc_mei_phy_enable(void *phy_id)
int r;
struct nfc_mei_phy *phy = phy_id;
- pr_info("%s\n", __func__);
-
if (phy->powered == 1)
return 0;
@@ -363,8 +357,6 @@ static void nfc_mei_phy_disable(void *phy_id)
{
struct nfc_mei_phy *phy = phy_id;
- pr_info("%s\n", __func__);
-
mei_cldev_disable(phy->cldev);
phy->powered = 0;
diff --git a/drivers/nfc/microread/microread.c b/drivers/nfc/microread/microread.c
index 8d3988457c58..b1d3975e8a81 100644
--- a/drivers/nfc/microread/microread.c
+++ b/drivers/nfc/microread/microread.c
@@ -364,7 +364,6 @@ static void microread_im_transceive_cb(void *context, struct sk_buff *skb,
case MICROREAD_CB_TYPE_READER_ALL:
if (err == 0) {
if (skb->len == 0) {
- err = -EPROTO;
kfree_skb(skb);
info->async_cb(info->async_cb_context, NULL,
-EPROTO);
diff --git a/drivers/nfc/nfcmrvl/fw_dnld.c b/drivers/nfc/nfcmrvl/fw_dnld.c
index 52c8ae504e32..aaccb8b76b3e 100644
--- a/drivers/nfc/nfcmrvl/fw_dnld.c
+++ b/drivers/nfc/nfcmrvl/fw_dnld.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell NFC driver: Firmware downloader
*
* Copyright (C) 2015, Marvell International Ltd.
- *
- * This software file (the "File") is distributed by Marvell International
- * Ltd. under the terms of the GNU General Public License Version 2, June 1991
- * (the "License"). You may use, redistribute and/or modify this File in
- * accordance with the terms and conditions of the License, a copy of which
- * is available on the worldwide web at
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
- *
- * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
- * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
- * this warranty disclaimer.
*/
#include <linux/module.h>
@@ -50,8 +39,8 @@ enum {
};
/*
-** Patterns for responses
-*/
+ * Patterns for responses
+ */
static const uint8_t nci_pattern_core_reset_ntf[] = {
0x60, 0x00, 0x02, 0xA0, 0x01
@@ -451,7 +440,7 @@ static void fw_dnld_rx_work(struct work_struct *work)
}
}
-int nfcmrvl_fw_dnld_init(struct nfcmrvl_private *priv)
+int nfcmrvl_fw_dnld_init(struct nfcmrvl_private *priv)
{
char name[32];
@@ -465,13 +454,13 @@ int nfcmrvl_fw_dnld_init(struct nfcmrvl_private *priv)
return 0;
}
-void nfcmrvl_fw_dnld_deinit(struct nfcmrvl_private *priv)
+void nfcmrvl_fw_dnld_deinit(struct nfcmrvl_private *priv)
{
destroy_workqueue(priv->fw_dnld.rx_wq);
}
-void nfcmrvl_fw_dnld_recv_frame(struct nfcmrvl_private *priv,
- struct sk_buff *skb)
+void nfcmrvl_fw_dnld_recv_frame(struct nfcmrvl_private *priv,
+ struct sk_buff *skb)
{
/* Discard command timer */
if (timer_pending(&priv->ndev->cmd_timer))
diff --git a/drivers/nfc/nfcmrvl/fw_dnld.h b/drivers/nfc/nfcmrvl/fw_dnld.h
index 058ce77b3cbc..7c4d91b01910 100644
--- a/drivers/nfc/nfcmrvl/fw_dnld.h
+++ b/drivers/nfc/nfcmrvl/fw_dnld.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Marvell NFC driver: Firmware downloader
*
* Copyright (C) 2015, Marvell International Ltd.
- *
- * This software file (the "File") is distributed by Marvell International
- * Ltd. under the terms of the GNU General Public License Version 2, June 1991
- * (the "License"). You may use, redistribute and/or modify this File in
- * accordance with the terms and conditions of the License, a copy of which
- * is available on the worldwide web at
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
- *
- * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
- * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
- * this warranty disclaimer.
- **/
+ */
#ifndef __NFCMRVL_FW_DNLD_H__
#define __NFCMRVL_FW_DNLD_H__
diff --git a/drivers/nfc/nfcmrvl/i2c.c b/drivers/nfc/nfcmrvl/i2c.c
index c5420616b7bc..59a529e72d96 100644
--- a/drivers/nfc/nfcmrvl/i2c.c
+++ b/drivers/nfc/nfcmrvl/i2c.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell NFC-over-I2C driver: I2C interface related functions
*
* Copyright (C) 2015, Marvell International Ltd.
- *
- * This software file (the "File") is distributed by Marvell International
- * Ltd. under the terms of the GNU General Public License Version 2, June 1991
- * (the "License"). You may use, redistribute and/or modify this File in
- * accordance with the terms and conditions of the License, a copy of which
- * is available on the worldwide web at
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
- *
- * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
- * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
- * this warranty disclaimer.
- **/
+ */
#include <linux/module.h>
#include <linux/interrupt.h>
@@ -49,11 +38,6 @@ static int nfcmrvl_i2c_read(struct nfcmrvl_i2c_drv_data *drv_data,
return -EBADMSG;
}
- if (nci_hdr.plen > NCI_MAX_PAYLOAD_SIZE) {
- nfc_err(&drv_data->i2c->dev, "invalid packet payload size\n");
- return -EBADMSG;
- }
-
*skb = nci_skb_alloc(drv_data->priv->ndev,
nci_hdr.plen + NCI_CTRL_HDR_SIZE, GFP_KERNEL);
if (!*skb)
@@ -260,7 +244,7 @@ static int nfcmrvl_i2c_remove(struct i2c_client *client)
}
-static const struct of_device_id of_nfcmrvl_i2c_match[] = {
+static const struct of_device_id of_nfcmrvl_i2c_match[] __maybe_unused = {
{ .compatible = "marvell,nfc-i2c", },
{},
};
diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c
index 529be35ac178..a4620b480c4f 100644
--- a/drivers/nfc/nfcmrvl/main.c
+++ b/drivers/nfc/nfcmrvl/main.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell NFC driver: major functions
*
* Copyright (C) 2014-2015 Marvell International Ltd.
- *
- * This software file (the "File") is distributed by Marvell International
- * Ltd. under the terms of the GNU General Public License Version 2, June 1991
- * (the "License"). You may use, redistribute and/or modify this File in
- * accordance with the terms and conditions of the License, a copy of which
- * is available on the worldwide web at
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
- *
- * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
- * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
- * this warranty disclaimer.
*/
#include <linux/module.h>
diff --git a/drivers/nfc/nfcmrvl/nfcmrvl.h b/drivers/nfc/nfcmrvl/nfcmrvl.h
index e84ee18c73ae..a715543bc9bf 100644
--- a/drivers/nfc/nfcmrvl/nfcmrvl.h
+++ b/drivers/nfc/nfcmrvl/nfcmrvl.h
@@ -1,20 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Marvell NFC driver
*
* Copyright (C) 2014-2015, Marvell International Ltd.
- *
- * This software file (the "File") is distributed by Marvell International
- * Ltd. under the terms of the GNU General Public License Version 2, June 1991
- * (the "License"). You may use, redistribute and/or modify this File in
- * accordance with the terms and conditions of the License, a copy of which
- * is available on the worldwide web at
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
- *
- * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
- * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
- * this warranty disclaimer.
- **/
+ */
#ifndef _NFCMRVL_H_
#define _NFCMRVL_H_
@@ -36,16 +25,16 @@
#define NFCMRVL_NCI_MAX_EVENT_SIZE 260
/*
-** NCI FW Parmaters
-*/
+ * NCI FW Parameters
+ */
#define NFCMRVL_PB_BAIL_OUT 0x11
#define NFCMRVL_PROP_REF_CLOCK 0xF0
#define NFCMRVL_PROP_SET_HI_CONFIG 0xF1
/*
-** HCI defines
-*/
+ * HCI defines
+ */
#define NFCMRVL_HCI_EVENT_HEADER_SIZE 0x04
#define NFCMRVL_HCI_EVENT_CODE 0x04
@@ -78,8 +67,8 @@ struct nfcmrvl_private {
bool support_fw_dnld;
/*
- ** PHY related information
- */
+ * PHY related information
+ */
/* PHY driver context */
void *drv_data;
diff --git a/drivers/nfc/nfcmrvl/spi.c b/drivers/nfc/nfcmrvl/spi.c
index dec0d3eb3648..66696321c645 100644
--- a/drivers/nfc/nfcmrvl/spi.c
+++ b/drivers/nfc/nfcmrvl/spi.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell NFC-over-SPI driver: SPI interface related functions
*
* Copyright (C) 2015, Marvell International Ltd.
- *
- * This software file (the "File") is distributed by Marvell International
- * Ltd. under the terms of the GNU General Public License Version 2, June 1991
- * (the "License"). You may use, redistribute and/or modify this File in
- * accordance with the terms and conditions of the License, a copy of which
- * is available on the worldwide web at
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
- *
- * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
- * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
- * this warranty disclaimer.
- **/
+ */
#include <linux/module.h>
#include <linux/interrupt.h>
@@ -196,7 +185,7 @@ static int nfcmrvl_spi_remove(struct spi_device *spi)
return 0;
}
-static const struct of_device_id of_nfcmrvl_spi_match[] = {
+static const struct of_device_id of_nfcmrvl_spi_match[] __maybe_unused = {
{ .compatible = "marvell,nfc-spi", },
{},
};
diff --git a/drivers/nfc/nfcmrvl/uart.c b/drivers/nfc/nfcmrvl/uart.c
index 7194dd7ef0f1..50d86c90b9dd 100644
--- a/drivers/nfc/nfcmrvl/uart.c
+++ b/drivers/nfc/nfcmrvl/uart.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell NFC-over-UART driver
*
* Copyright (C) 2015, Marvell International Ltd.
- *
- * This software file (the "File") is distributed by Marvell International
- * Ltd. under the terms of the GNU General Public License Version 2, June 1991
- * (the "License"). You may use, redistribute and/or modify this File in
- * accordance with the terms and conditions of the License, a copy of which
- * is available on the worldwide web at
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
- *
- * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
- * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
- * this warranty disclaimer.
*/
#include <linux/module.h>
@@ -29,8 +18,8 @@ static unsigned int break_control;
static int reset_n_io = -EINVAL;
/*
-** NFCMRVL NCI OPS
-*/
+ * NFCMRVL NCI OPS
+ */
static int nfcmrvl_uart_nci_open(struct nfcmrvl_private *priv)
{
@@ -103,8 +92,8 @@ static int nfcmrvl_uart_parse_dt(struct device_node *node,
}
/*
-** NCI UART OPS
-*/
+ * NCI UART OPS
+ */
static int nfcmrvl_nci_uart_open(struct nci_uart *nu)
{
@@ -178,10 +167,10 @@ static void nfcmrvl_nci_uart_tx_done(struct nci_uart *nu)
return;
/*
- ** To ensure that if the NFCC goes in DEEP SLEEP sate we can wake him
- ** up. we set BREAK. Once we will be ready to send again we will remove
- ** it.
- */
+ * To ensure that if the NFCC goes in DEEP SLEEP sate we can wake him
+ * up. we set BREAK. Once we will be ready to send again we will remove
+ * it.
+ */
if (priv->config.break_control && nu->tty->ops->break_ctl) {
nu->tty->ops->break_ctl(nu->tty, -1);
usleep_range(1000, 3000);
@@ -200,23 +189,7 @@ static struct nci_uart nfcmrvl_nci_uart = {
.tx_done = nfcmrvl_nci_uart_tx_done,
}
};
-
-/*
-** Module init
-*/
-
-static int nfcmrvl_uart_init_module(void)
-{
- return nci_uart_register(&nfcmrvl_nci_uart);
-}
-
-static void nfcmrvl_uart_exit_module(void)
-{
- nci_uart_unregister(&nfcmrvl_nci_uart);
-}
-
-module_init(nfcmrvl_uart_init_module);
-module_exit(nfcmrvl_uart_exit_module);
+module_driver(nfcmrvl_nci_uart, nci_uart_register, nci_uart_unregister);
MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell NFC-over-UART");
diff --git a/drivers/nfc/nfcmrvl/usb.c b/drivers/nfc/nfcmrvl/usb.c
index bcd563cb556c..9d649b45300b 100644
--- a/drivers/nfc/nfcmrvl/usb.c
+++ b/drivers/nfc/nfcmrvl/usb.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell NFC-over-USB driver: USB interface related functions
*
* Copyright (C) 2014, Marvell International Ltd.
- *
- * This software file (the "File") is distributed by Marvell International
- * Ltd. under the terms of the GNU General Public License Version 2, June 1991
- * (the "License"). You may use, redistribute and/or modify this File in
- * accordance with the terms and conditions of the License, a copy of which
- * is available on the worldwide web at
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
- *
- * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
- * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
- * this warranty disclaimer.
- **/
+ */
#include <linux/module.h>
#include <linux/usb.h>
@@ -68,7 +57,6 @@ static int nfcmrvl_inc_tx(struct nfcmrvl_usb_drv_data *drv_data)
static void nfcmrvl_bulk_complete(struct urb *urb)
{
struct nfcmrvl_usb_drv_data *drv_data = urb->context;
- struct sk_buff *skb;
int err;
dev_dbg(&drv_data->udev->dev, "urb %p status %d count %d\n",
@@ -78,6 +66,8 @@ static void nfcmrvl_bulk_complete(struct urb *urb)
return;
if (!urb->status) {
+ struct sk_buff *skb;
+
skb = nci_skb_alloc(drv_data->priv->ndev, urb->actual_length,
GFP_ATOMIC);
if (!skb) {
@@ -296,7 +286,6 @@ static void nfcmrvl_waker(struct work_struct *work)
static int nfcmrvl_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct usb_endpoint_descriptor *ep_desc;
struct nfcmrvl_usb_drv_data *drv_data;
struct nfcmrvl_private *priv;
int i;
@@ -314,18 +303,16 @@ static int nfcmrvl_probe(struct usb_interface *intf,
return -ENOMEM;
for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
+ struct usb_endpoint_descriptor *ep_desc;
+
ep_desc = &intf->cur_altsetting->endpoint[i].desc;
if (!drv_data->bulk_tx_ep &&
usb_endpoint_is_bulk_out(ep_desc)) {
drv_data->bulk_tx_ep = ep_desc;
- continue;
- }
-
- if (!drv_data->bulk_rx_ep &&
- usb_endpoint_is_bulk_in(ep_desc)) {
+ } else if (!drv_data->bulk_rx_ep &&
+ usb_endpoint_is_bulk_in(ep_desc)) {
drv_data->bulk_rx_ep = ep_desc;
- continue;
}
}
diff --git a/drivers/nfc/nxp-nci/core.c b/drivers/nfc/nxp-nci/core.c
index a0ce95a287c5..2b0c7232e91f 100644
--- a/drivers/nfc/nxp-nci/core.c
+++ b/drivers/nfc/nxp-nci/core.c
@@ -70,21 +70,16 @@ static int nxp_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
struct nxp_nci_info *info = nci_get_drvdata(ndev);
int r;
- if (!info->phy_ops->write) {
- r = -ENOTSUPP;
- goto send_exit;
- }
+ if (!info->phy_ops->write)
+ return -EOPNOTSUPP;
- if (info->mode != NXP_NCI_MODE_NCI) {
- r = -EINVAL;
- goto send_exit;
- }
+ if (info->mode != NXP_NCI_MODE_NCI)
+ return -EINVAL;
r = info->phy_ops->write(info->phy_id, skb);
if (r < 0)
kfree_skb(skb);
-send_exit:
return r;
}
@@ -104,10 +99,8 @@ int nxp_nci_probe(void *phy_id, struct device *pdev,
int r;
info = devm_kzalloc(pdev, sizeof(struct nxp_nci_info), GFP_KERNEL);
- if (!info) {
- r = -ENOMEM;
- goto probe_exit;
- }
+ if (!info)
+ return -ENOMEM;
info->phy_id = phy_id;
info->pdev = pdev;
@@ -120,31 +113,25 @@ int nxp_nci_probe(void *phy_id, struct device *pdev,
if (info->phy_ops->set_mode) {
r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
if (r < 0)
- goto probe_exit;
+ return r;
}
info->mode = NXP_NCI_MODE_COLD;
info->ndev = nci_allocate_device(&nxp_nci_ops, NXP_NCI_NFC_PROTOCOLS,
NXP_NCI_HDR_LEN, 0);
- if (!info->ndev) {
- r = -ENOMEM;
- goto probe_exit;
- }
+ if (!info->ndev)
+ return -ENOMEM;
nci_set_parent_dev(info->ndev, pdev);
nci_set_drvdata(info->ndev, info);
r = nci_register_device(info->ndev);
- if (r < 0)
- goto probe_exit_free_nci;
+ if (r < 0) {
+ nci_free_device(info->ndev);
+ return r;
+ }
*ndev = info->ndev;
-
- goto probe_exit;
-
-probe_exit_free_nci:
- nci_free_device(info->ndev);
-probe_exit:
return r;
}
EXPORT_SYMBOL(nxp_nci_probe);
diff --git a/drivers/nfc/nxp-nci/firmware.c b/drivers/nfc/nxp-nci/firmware.c
index dae0c8030e95..119bf305c642 100644
--- a/drivers/nfc/nxp-nci/firmware.c
+++ b/drivers/nfc/nxp-nci/firmware.c
@@ -95,10 +95,8 @@ static int nxp_nci_fw_send_chunk(struct nxp_nci_info *info)
int r;
skb = nci_skb_alloc(info->ndev, info->max_payload, GFP_KERNEL);
- if (!skb) {
- r = -ENOMEM;
- goto chunk_exit;
- }
+ if (!skb)
+ return -ENOMEM;
chunk_len = info->max_payload - NXP_NCI_FW_HDR_LEN - NXP_NCI_FW_CRC_LEN;
remaining_len = fw_info->frame_size - fw_info->written;
@@ -124,7 +122,6 @@ static int nxp_nci_fw_send_chunk(struct nxp_nci_info *info)
kfree_skb(skb);
-chunk_exit:
return r;
}
diff --git a/drivers/nfc/pn533/i2c.c b/drivers/nfc/pn533/i2c.c
index 795da9b85d56..e6bf8cfe3aa7 100644
--- a/drivers/nfc/pn533/i2c.c
+++ b/drivers/nfc/pn533/i2c.c
@@ -174,9 +174,6 @@ static int pn533_i2c_probe(struct i2c_client *client,
struct pn533 *priv;
int r = 0;
- dev_dbg(&client->dev, "%s\n", __func__);
- dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
-
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
return -ENODEV;
@@ -195,9 +192,8 @@ static int pn533_i2c_probe(struct i2c_client *client,
phy, &i2c_phy_ops, NULL,
&phy->i2c_dev->dev);
- if (IS_ERR(priv)) {
+ if (IS_ERR(priv))
return PTR_ERR(priv);
- }
phy->priv = priv;
r = pn532_i2c_nfc_alloc(priv, PN533_NO_TYPE_B_PROTOCOLS, &client->dev);
@@ -239,8 +235,6 @@ static int pn533_i2c_remove(struct i2c_client *client)
{
struct pn533_i2c_phy *phy = i2c_get_clientdata(client);
- dev_dbg(&client->dev, "%s\n", __func__);
-
free_irq(client->irq, phy);
pn53x_unregister_nfc(phy->priv);
@@ -249,7 +243,7 @@ static int pn533_i2c_remove(struct i2c_client *client)
return 0;
}
-static const struct of_device_id of_pn533_i2c_match[] = {
+static const struct of_device_id of_pn533_i2c_match[] __maybe_unused = {
{ .compatible = "nxp,pn532", },
/*
* NOTE: The use of the compatibles with the trailing "...-i2c" is
diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c
index 2c7f9916f206..cd64bfe20402 100644
--- a/drivers/nfc/pn533/pn533.c
+++ b/drivers/nfc/pn533/pn533.c
@@ -1075,8 +1075,6 @@ static int pn533_tm_get_data_complete(struct pn533 *dev, void *arg,
u8 status, ret, mi;
int rc;
- dev_dbg(dev->dev, "%s\n", __func__);
-
if (IS_ERR(resp)) {
skb_queue_purge(&dev->resp_q);
return PTR_ERR(resp);
@@ -1124,8 +1122,6 @@ static void pn533_wq_tm_mi_recv(struct work_struct *work)
struct sk_buff *skb;
int rc;
- dev_dbg(dev->dev, "%s\n", __func__);
-
skb = pn533_alloc_skb(dev, 0);
if (!skb)
return;
@@ -1148,8 +1144,6 @@ static void pn533_wq_tm_mi_send(struct work_struct *work)
struct sk_buff *skb;
int rc;
- dev_dbg(dev->dev, "%s\n", __func__);
-
/* Grab the first skb in the queue */
skb = skb_dequeue(&dev->fragment_skb);
if (skb == NULL) { /* No more data */
@@ -1186,8 +1180,6 @@ static void pn533_wq_tg_get_data(struct work_struct *work)
struct sk_buff *skb;
int rc;
- dev_dbg(dev->dev, "%s\n", __func__);
-
skb = pn533_alloc_skb(dev, 0);
if (!skb)
return;
@@ -1206,8 +1198,6 @@ static int pn533_init_target_complete(struct pn533 *dev, struct sk_buff *resp)
size_t gb_len;
int rc;
- dev_dbg(dev->dev, "%s\n", __func__);
-
if (resp->len < ATR_REQ_GB_OFFSET + 1)
return -EINVAL;
@@ -1260,8 +1250,6 @@ static int pn533_rf_complete(struct pn533 *dev, void *arg,
{
int rc = 0;
- dev_dbg(dev->dev, "%s\n", __func__);
-
if (IS_ERR(resp)) {
rc = PTR_ERR(resp);
@@ -1283,8 +1271,6 @@ static void pn533_wq_rf(struct work_struct *work)
struct sk_buff *skb;
int rc;
- dev_dbg(dev->dev, "%s\n", __func__);
-
skb = pn533_alloc_skb(dev, 2);
if (!skb)
return;
@@ -1360,8 +1346,6 @@ static int pn533_poll_dep(struct nfc_dev *nfc_dev)
u8 *next, nfcid3[NFC_NFCID3_MAXSIZE];
u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3};
- dev_dbg(dev->dev, "%s", __func__);
-
if (!dev->gb) {
dev->gb = nfc_get_local_general_bytes(nfc_dev, &dev->gb_len);
@@ -1511,8 +1495,6 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg,
struct pn533_poll_modulations *cur_mod;
int rc;
- dev_dbg(dev->dev, "%s\n", __func__);
-
if (IS_ERR(resp)) {
rc = PTR_ERR(resp);
@@ -1783,8 +1765,6 @@ static int pn533_activate_target_nfcdep(struct pn533 *dev)
struct sk_buff *skb;
struct sk_buff *resp;
- dev_dbg(dev->dev, "%s\n", __func__);
-
skb = pn533_alloc_skb(dev, sizeof(u8) * 2); /*TG + Next*/
if (!skb)
return -ENOMEM;
@@ -1866,8 +1846,6 @@ static int pn533_deactivate_target_complete(struct pn533 *dev, void *arg,
{
int rc = 0;
- dev_dbg(dev->dev, "%s\n", __func__);
-
if (IS_ERR(resp)) {
rc = PTR_ERR(resp);
@@ -1892,8 +1870,6 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev,
struct sk_buff *skb;
int rc;
- dev_dbg(dev->dev, "%s\n", __func__);
-
if (!dev->tgt_active_prot) {
nfc_err(dev->dev, "There is no active target\n");
return;
@@ -1988,8 +1964,6 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
u8 *next, *arg, nfcid3[NFC_NFCID3_MAXSIZE];
u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3};
- dev_dbg(dev->dev, "%s\n", __func__);
-
if (dev->poll_mod_count) {
nfc_err(dev->dev,
"Cannot bring the DEP link up while polling\n");
@@ -2067,8 +2041,6 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
- dev_dbg(dev->dev, "%s\n", __func__);
-
pn533_poll_reset_mod_list(dev);
if (dev->tgt_mode || dev->tgt_active_prot)
@@ -2092,8 +2064,6 @@ static struct sk_buff *pn533_build_response(struct pn533 *dev)
struct sk_buff *skb, *tmp, *t;
unsigned int skb_len = 0, tmp_len = 0;
- dev_dbg(dev->dev, "%s\n", __func__);
-
if (skb_queue_empty(&dev->resp_q))
return NULL;
@@ -2133,8 +2103,6 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
int rc = 0;
u8 status, ret, mi;
- dev_dbg(dev->dev, "%s\n", __func__);
-
if (IS_ERR(resp)) {
rc = PTR_ERR(resp);
goto _error;
@@ -2288,8 +2256,6 @@ static int pn533_transceive(struct nfc_dev *nfc_dev,
struct pn533_data_exchange_arg *arg = NULL;
int rc;
- dev_dbg(dev->dev, "%s\n", __func__);
-
if (!dev->tgt_active_prot) {
nfc_err(dev->dev,
"Can't exchange data if there is no active target\n");
@@ -2356,8 +2322,6 @@ static int pn533_tm_send_complete(struct pn533 *dev, void *arg,
{
u8 status;
- dev_dbg(dev->dev, "%s\n", __func__);
-
if (IS_ERR(resp))
return PTR_ERR(resp);
@@ -2388,8 +2352,6 @@ static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
int rc;
- dev_dbg(dev->dev, "%s\n", __func__);
-
/* let's split in multiple chunks if size's too big */
if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
rc = pn533_fill_fragment_skbs(dev, skb);
@@ -2426,8 +2388,6 @@ static void pn533_wq_mi_recv(struct work_struct *work)
struct sk_buff *skb;
int rc;
- dev_dbg(dev->dev, "%s\n", __func__);
-
skb = pn533_alloc_skb(dev, PN533_CMD_DATAEXCH_HEAD_LEN);
if (!skb)
goto error;
@@ -2476,8 +2436,6 @@ static void pn533_wq_mi_send(struct work_struct *work)
struct sk_buff *skb;
int rc;
- dev_dbg(dev->dev, "%s\n", __func__);
-
/* Grab the first skb in the queue */
skb = skb_dequeue(&dev->fragment_skb);
@@ -2533,8 +2491,6 @@ static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
struct sk_buff *resp;
int skb_len;
- dev_dbg(dev->dev, "%s\n", __func__);
-
skb_len = sizeof(cfgitem) + cfgdata_len; /* cfgitem + cfgdata */
skb = pn533_alloc_skb(dev, skb_len);
@@ -2580,8 +2536,6 @@ static int pn533_pasori_fw_reset(struct pn533 *dev)
struct sk_buff *skb;
struct sk_buff *resp;
- dev_dbg(dev->dev, "%s\n", __func__);
-
skb = pn533_alloc_skb(dev, sizeof(u8));
if (!skb)
return -ENOMEM;
diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c
index a0665d8ea85b..7bdaf8263070 100644
--- a/drivers/nfc/pn533/uart.c
+++ b/drivers/nfc/pn533/uart.c
@@ -319,7 +319,7 @@ static struct serdev_device_driver pn532_uart_driver = {
.remove = pn532_uart_remove,
.driver = {
.name = "pn532_uart",
- .of_match_table = of_match_ptr(pn532_uart_of_match),
+ .of_match_table = pn532_uart_of_match,
},
};
diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c
index 84d2bfabf42b..bd7f7478d189 100644
--- a/drivers/nfc/pn533/usb.c
+++ b/drivers/nfc/pn533/usb.c
@@ -354,8 +354,6 @@ static void pn533_acr122_poweron_rdr_resp(struct urb *urb)
{
struct pn533_acr122_poweron_rdr_arg *arg = urb->context;
- dev_dbg(&urb->dev->dev, "%s\n", __func__);
-
print_hex_dump_debug("ACR122 RX: ", DUMP_PREFIX_NONE, 16, 1,
urb->transfer_buffer, urb->transfer_buffer_length,
false);
@@ -375,8 +373,6 @@ static int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy)
void *cntx;
struct pn533_acr122_poweron_rdr_arg arg;
- dev_dbg(&phy->udev->dev, "%s\n", __func__);
-
buffer = kmemdup(cmd, sizeof(cmd), GFP_KERNEL);
if (!buffer)
return -ENOMEM;
diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c
index 4ac8cb262559..de59e439c369 100644
--- a/drivers/nfc/pn544/i2c.c
+++ b/drivers/nfc/pn544/i2c.c
@@ -50,7 +50,7 @@ static const struct i2c_device_id pn544_hci_i2c_id_table[] = {
MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table);
-static const struct acpi_device_id pn544_hci_i2c_acpi_match[] = {
+static const struct acpi_device_id pn544_hci_i2c_acpi_match[] __maybe_unused = {
{"NXP5440", 0},
{}
};
@@ -241,8 +241,6 @@ static int pn544_hci_i2c_enable(void *phy_id)
{
struct pn544_i2c_phy *phy = phy_id;
- pr_info("%s\n", __func__);
-
pn544_hci_i2c_enable_mode(phy, PN544_HCI_MODE);
phy->powered = 1;
@@ -875,9 +873,6 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
struct pn544_i2c_phy *phy;
int r = 0;
- dev_dbg(&client->dev, "%s\n", __func__);
- dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
-
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
return -ENODEV;
@@ -937,8 +932,6 @@ static int pn544_hci_i2c_remove(struct i2c_client *client)
{
struct pn544_i2c_phy *phy = i2c_get_clientdata(client);
- dev_dbg(&client->dev, "%s\n", __func__);
-
cancel_work_sync(&phy->fw_work);
if (phy->fw_work_state != FW_WORK_STATE_IDLE)
pn544_hci_i2c_fw_work_complete(phy, -ENODEV);
@@ -951,7 +944,7 @@ static int pn544_hci_i2c_remove(struct i2c_client *client)
return 0;
}
-static const struct of_device_id of_pn544_i2c_match[] = {
+static const struct of_device_id of_pn544_i2c_match[] __maybe_unused = {
{ .compatible = "nxp,pn544-i2c", },
{},
};
diff --git a/drivers/nfc/port100.c b/drivers/nfc/port100.c
index 8e4d355dc3ae..4df926cc37d0 100644
--- a/drivers/nfc/port100.c
+++ b/drivers/nfc/port100.c
@@ -94,7 +94,7 @@ struct port100;
typedef void (*port100_send_async_complete_t)(struct port100 *dev, void *arg,
struct sk_buff *resp);
-/**
+/*
* Setting sets structure for in_set_rf command
*
* @in_*_set_number: Represent the entry indexes in the port-100 RF Base Table.
@@ -145,7 +145,7 @@ static const struct port100_in_rf_setting in_rf_settings[] = {
};
/**
- * Setting sets structure for tg_set_rf command
+ * struct port100_tg_rf_setting - Setting sets structure for tg_set_rf command
*
* @tg_set_number: Represents the entry index in the port-100 RF Base Table.
* This table contains multiple RF setting sets required for RF
diff --git a/drivers/nfc/s3fwrn5/i2c.c b/drivers/nfc/s3fwrn5/i2c.c
index 897394167522..4d1cf1bb55b0 100644
--- a/drivers/nfc/s3fwrn5/i2c.c
+++ b/drivers/nfc/s3fwrn5/i2c.c
@@ -6,6 +6,7 @@
* Robert Baldyga <r.baldyga@samsung.com>
*/
+#include <linux/clk.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/delay.h>
@@ -22,6 +23,7 @@
struct s3fwrn5_i2c_phy {
struct phy_common common;
struct i2c_client *i2c_dev;
+ struct clk *clk;
unsigned int irq_skip:1;
};
@@ -207,17 +209,40 @@ static int s3fwrn5_i2c_probe(struct i2c_client *client,
if (ret < 0)
return ret;
+ phy->clk = devm_clk_get_optional(&client->dev, NULL);
+ if (IS_ERR(phy->clk))
+ return dev_err_probe(&client->dev, PTR_ERR(phy->clk),
+ "failed to get clock\n");
+
+ /*
+ * S3FWRN5 depends on a clock input ("XI" pin) to function properly.
+ * Depending on the hardware configuration this could be an always-on
+ * oscillator or some external clock that must be explicitly enabled.
+ * Make sure the clock is running before starting S3FWRN5.
+ */
+ ret = clk_prepare_enable(phy->clk);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to enable clock: %d\n", ret);
+ return ret;
+ }
+
ret = s3fwrn5_probe(&phy->common.ndev, phy, &phy->i2c_dev->dev,
&i2c_phy_ops);
if (ret < 0)
- return ret;
+ goto disable_clk;
ret = devm_request_threaded_irq(&client->dev, phy->i2c_dev->irq, NULL,
s3fwrn5_i2c_irq_thread_fn, IRQF_ONESHOT,
S3FWRN5_I2C_DRIVER_NAME, phy);
if (ret)
- s3fwrn5_remove(phy->common.ndev);
+ goto s3fwrn5_remove;
+ return 0;
+
+s3fwrn5_remove:
+ s3fwrn5_remove(phy->common.ndev);
+disable_clk:
+ clk_disable_unprepare(phy->clk);
return ret;
}
@@ -226,6 +251,7 @@ static int s3fwrn5_i2c_remove(struct i2c_client *client)
struct s3fwrn5_i2c_phy *phy = i2c_get_clientdata(client);
s3fwrn5_remove(phy->common.ndev);
+ clk_disable_unprepare(phy->clk);
return 0;
}
@@ -236,7 +262,7 @@ static const struct i2c_device_id s3fwrn5_i2c_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, s3fwrn5_i2c_id_table);
-static const struct of_device_id of_s3fwrn5_i2c_match[] = {
+static const struct of_device_id of_s3fwrn5_i2c_match[] __maybe_unused = {
{ .compatible = "samsung,s3fwrn5-i2c", },
{}
};
diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c
index 55d600cd3861..46981405e8b1 100644
--- a/drivers/nfc/st-nci/i2c.c
+++ b/drivers/nfc/st-nci/i2c.c
@@ -206,9 +206,6 @@ static int st_nci_i2c_probe(struct i2c_client *client,
struct st_nci_i2c_phy *phy;
int r;
- dev_dbg(&client->dev, "%s\n", __func__);
- dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
-
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
return -ENODEV;
@@ -261,8 +258,6 @@ static int st_nci_i2c_remove(struct i2c_client *client)
{
struct st_nci_i2c_phy *phy = i2c_get_clientdata(client);
- dev_dbg(&client->dev, "%s\n", __func__);
-
ndlc_remove(phy->ndlc);
return 0;
@@ -274,14 +269,14 @@ static const struct i2c_device_id st_nci_i2c_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, st_nci_i2c_id_table);
-static const struct acpi_device_id st_nci_i2c_acpi_match[] = {
+static const struct acpi_device_id st_nci_i2c_acpi_match[] __maybe_unused = {
{"SMO2101"},
{"SMO2102"},
{}
};
MODULE_DEVICE_TABLE(acpi, st_nci_i2c_acpi_match);
-static const struct of_device_id of_st_nci_i2c_match[] = {
+static const struct of_device_id of_st_nci_i2c_match[] __maybe_unused = {
{ .compatible = "st,st21nfcb-i2c", },
{ .compatible = "st,st21nfcb_i2c", },
{ .compatible = "st,st21nfcc-i2c", },
diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c
index 1cba8f69d3ae..5fd89f72969d 100644
--- a/drivers/nfc/st-nci/se.c
+++ b/drivers/nfc/st-nci/se.c
@@ -470,8 +470,6 @@ int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx)
{
int r;
- pr_debug("st_nci_disable_se\n");
-
/*
* According to upper layer, se_idx == NFC_SE_UICC when
* info->se_info.se_status->is_uicc_enable is true should never happen
@@ -496,8 +494,6 @@ int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx)
{
int r;
- pr_debug("st_nci_enable_se\n");
-
/*
* According to upper layer, se_idx == NFC_SE_UICC when
* info->se_info.se_status->is_uicc_enable is true should never happen.
@@ -534,10 +530,8 @@ static int st_nci_hci_network_init(struct nci_dev *ndev)
dest_params =
kzalloc(sizeof(struct core_conn_create_dest_spec_params) +
sizeof(struct dest_spec_params), GFP_KERNEL);
- if (dest_params == NULL) {
- r = -ENOMEM;
- goto exit;
- }
+ if (dest_params == NULL)
+ return -ENOMEM;
dest_params->type = NCI_DESTINATION_SPECIFIC_PARAM_NFCEE_TYPE;
dest_params->length = sizeof(struct dest_spec_params);
@@ -594,8 +588,6 @@ static int st_nci_hci_network_init(struct nci_dev *ndev)
free_dest_params:
kfree(dest_params);
-
-exit:
return r;
}
@@ -606,8 +598,6 @@ int st_nci_discover_se(struct nci_dev *ndev)
int se_count = 0;
struct st_nci_info *info = nci_get_drvdata(ndev);
- pr_debug("st_nci_discover_se\n");
-
r = st_nci_hci_network_init(ndev);
if (r != 0)
return r;
diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c
index 09df6ea65840..250d56f204c3 100644
--- a/drivers/nfc/st-nci/spi.c
+++ b/drivers/nfc/st-nci/spi.c
@@ -216,9 +216,6 @@ static int st_nci_spi_probe(struct spi_device *dev)
struct st_nci_spi_phy *phy;
int r;
- dev_dbg(&dev->dev, "%s\n", __func__);
- dev_dbg(&dev->dev, "IRQ: %d\n", dev->irq);
-
/* Check SPI platform functionnalities */
if (!dev) {
pr_debug("%s: dev is NULL. Device is not accessible.\n",
@@ -274,8 +271,6 @@ static int st_nci_spi_remove(struct spi_device *dev)
{
struct st_nci_spi_phy *phy = spi_get_drvdata(dev);
- dev_dbg(&dev->dev, "%s\n", __func__);
-
ndlc_remove(phy->ndlc);
return 0;
@@ -287,13 +282,13 @@ static struct spi_device_id st_nci_spi_id_table[] = {
};
MODULE_DEVICE_TABLE(spi, st_nci_spi_id_table);
-static const struct acpi_device_id st_nci_spi_acpi_match[] = {
+static const struct acpi_device_id st_nci_spi_acpi_match[] __maybe_unused = {
{"SMO2101", 0},
{}
};
MODULE_DEVICE_TABLE(acpi, st_nci_spi_acpi_match);
-static const struct of_device_id of_st_nci_spi_match[] = {
+static const struct of_device_id of_st_nci_spi_match[] __maybe_unused = {
{ .compatible = "st,st21nfcb-spi", },
{}
};
diff --git a/drivers/nfc/st-nci/vendor_cmds.c b/drivers/nfc/st-nci/vendor_cmds.c
index c6a9d30a4dba..94b600029a2a 100644
--- a/drivers/nfc/st-nci/vendor_cmds.c
+++ b/drivers/nfc/st-nci/vendor_cmds.c
@@ -98,7 +98,7 @@ static int st_nci_hci_dm_get_info(struct nfc_dev *dev, void *data,
r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, ST_NCI_HCI_DM_GETINFO,
data, data_len, &skb);
if (r)
- goto exit;
+ return r;
msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
HCI_DM_GET_INFO, skb->len);
@@ -117,7 +117,6 @@ static int st_nci_hci_dm_get_info(struct nfc_dev *dev, void *data,
free_skb:
kfree_skb(skb);
-exit:
return r;
}
@@ -131,7 +130,7 @@ static int st_nci_hci_dm_get_data(struct nfc_dev *dev, void *data,
r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, ST_NCI_HCI_DM_GETDATA,
data, data_len, &skb);
if (r)
- goto exit;
+ return r;
msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
HCI_DM_GET_DATA, skb->len);
@@ -150,7 +149,6 @@ static int st_nci_hci_dm_get_data(struct nfc_dev *dev, void *data,
free_skb:
kfree_skb(skb);
-exit:
return r;
}
@@ -216,7 +214,7 @@ static int st_nci_hci_get_param(struct nfc_dev *dev, void *data,
r = nci_hci_get_param(ndev, param->gate, param->data, &skb);
if (r)
- goto exit;
+ return r;
msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
HCI_GET_PARAM, skb->len);
@@ -235,7 +233,6 @@ static int st_nci_hci_get_param(struct nfc_dev *dev, void *data,
free_skb:
kfree_skb(skb);
-exit:
return r;
}
@@ -262,7 +259,7 @@ static int st_nci_hci_dm_vdc_measurement_value(struct nfc_dev *dev, void *data,
ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE,
data, data_len, &skb);
if (r)
- goto exit;
+ return r;
msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
HCI_DM_VDC_MEASUREMENT_VALUE, skb->len);
@@ -281,7 +278,6 @@ static int st_nci_hci_dm_vdc_measurement_value(struct nfc_dev *dev, void *data,
free_skb:
kfree_skb(skb);
-exit:
return r;
}
@@ -299,7 +295,7 @@ static int st_nci_hci_dm_vdc_value_comparison(struct nfc_dev *dev, void *data,
ST_NCI_HCI_DM_VDC_VALUE_COMPARISON,
data, data_len, &skb);
if (r)
- goto exit;
+ return r;
msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
HCI_DM_VDC_VALUE_COMPARISON, skb->len);
@@ -318,7 +314,6 @@ static int st_nci_hci_dm_vdc_value_comparison(struct nfc_dev *dev, void *data,
free_skb:
kfree_skb(skb);
-exit:
return r;
}
diff --git a/drivers/nfc/st21nfca/dep.c b/drivers/nfc/st21nfca/dep.c
index 8874d605b14f..1ec651e31064 100644
--- a/drivers/nfc/st21nfca/dep.c
+++ b/drivers/nfc/st21nfca/dep.c
@@ -196,38 +196,29 @@ static int st21nfca_tm_recv_atr_req(struct nfc_hci_dev *hdev,
skb_trim(skb, skb->len - 1);
- if (!skb->len) {
- r = -EIO;
- goto exit;
- }
+ if (!skb->len)
+ return -EIO;
- if (skb->len < ST21NFCA_ATR_REQ_MIN_SIZE) {
- r = -EPROTO;
- goto exit;
- }
+ if (skb->len < ST21NFCA_ATR_REQ_MIN_SIZE)
+ return -EPROTO;
atr_req = (struct st21nfca_atr_req *)skb->data;
- if (atr_req->length < sizeof(struct st21nfca_atr_req)) {
- r = -EPROTO;
- goto exit;
- }
+ if (atr_req->length < sizeof(struct st21nfca_atr_req))
+ return -EPROTO;
r = st21nfca_tm_send_atr_res(hdev, atr_req);
if (r)
- goto exit;
+ return r;
gb_len = skb->len - sizeof(struct st21nfca_atr_req);
r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
NFC_COMM_PASSIVE, atr_req->gbi, gb_len);
if (r)
- goto exit;
-
- r = 0;
+ return r;
-exit:
- return r;
+ return 0;
}
static int st21nfca_tm_send_psl_res(struct nfc_hci_dev *hdev,
@@ -280,25 +271,18 @@ static int st21nfca_tm_recv_psl_req(struct nfc_hci_dev *hdev,
struct sk_buff *skb)
{
struct st21nfca_psl_req *psl_req;
- int r;
skb_trim(skb, skb->len - 1);
- if (!skb->len) {
- r = -EIO;
- goto exit;
- }
+ if (!skb->len)
+ return -EIO;
psl_req = (struct st21nfca_psl_req *)skb->data;
- if (skb->len < sizeof(struct st21nfca_psl_req)) {
- r = -EIO;
- goto exit;
- }
+ if (skb->len < sizeof(struct st21nfca_psl_req))
+ return -EIO;
- r = st21nfca_tm_send_psl_res(hdev, psl_req);
-exit:
- return r;
+ return st21nfca_tm_send_psl_res(hdev, psl_req);
}
int st21nfca_tm_send_dep_res(struct nfc_hci_dev *hdev, struct sk_buff *skb)
@@ -324,7 +308,6 @@ static int st21nfca_tm_recv_dep_req(struct nfc_hci_dev *hdev,
{
struct st21nfca_dep_req_res *dep_req;
u8 size;
- int r;
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
skb_trim(skb, skb->len - 1);
@@ -332,20 +315,16 @@ static int st21nfca_tm_recv_dep_req(struct nfc_hci_dev *hdev,
size = 4;
dep_req = (struct st21nfca_dep_req_res *)skb->data;
- if (skb->len < size) {
- r = -EIO;
- goto exit;
- }
+ if (skb->len < size)
+ return -EIO;
if (ST21NFCA_NFC_DEP_DID_BIT_SET(dep_req->pfb))
size++;
if (ST21NFCA_NFC_DEP_NAD_BIT_SET(dep_req->pfb))
size++;
- if (skb->len < size) {
- r = -EIO;
- goto exit;
- }
+ if (skb->len < size)
+ return -EIO;
/* Receiving DEP_REQ - Decoding */
switch (ST21NFCA_NFC_DEP_PFB_TYPE(dep_req->pfb)) {
@@ -364,8 +343,6 @@ static int st21nfca_tm_recv_dep_req(struct nfc_hci_dev *hdev,
skb_pull(skb, size);
return nfc_tm_data_received(hdev->ndev, skb);
-exit:
- return r;
}
static int st21nfca_tm_event_send_data(struct nfc_hci_dev *hdev,
diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c
index 23ed11f91213..7a9f4d71707e 100644
--- a/drivers/nfc/st21nfca/i2c.c
+++ b/drivers/nfc/st21nfca/i2c.c
@@ -502,9 +502,6 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
struct st21nfca_i2c_phy *phy;
int r;
- dev_dbg(&client->dev, "%s\n", __func__);
- dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
-
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
return -ENODEV;
@@ -568,8 +565,6 @@ static int st21nfca_hci_i2c_remove(struct i2c_client *client)
{
struct st21nfca_i2c_phy *phy = i2c_get_clientdata(client);
- dev_dbg(&client->dev, "%s\n", __func__);
-
st21nfca_hci_remove(phy->hdev);
if (phy->powered)
@@ -584,13 +579,13 @@ static const struct i2c_device_id st21nfca_hci_i2c_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, st21nfca_hci_i2c_id_table);
-static const struct acpi_device_id st21nfca_hci_i2c_acpi_match[] = {
+static const struct acpi_device_id st21nfca_hci_i2c_acpi_match[] __maybe_unused = {
{"SMO2100", 0},
{}
};
MODULE_DEVICE_TABLE(acpi, st21nfca_hci_i2c_acpi_match);
-static const struct of_device_id of_st21nfca_i2c_match[] = {
+static const struct of_device_id of_st21nfca_i2c_match[] __maybe_unused = {
{ .compatible = "st,st21nfca-i2c", },
{ .compatible = "st,st21nfca_i2c", },
{}
diff --git a/drivers/nfc/st95hf/core.c b/drivers/nfc/st95hf/core.c
index 457854765983..2dc788c363fd 100644
--- a/drivers/nfc/st95hf/core.c
+++ b/drivers/nfc/st95hf/core.c
@@ -926,10 +926,8 @@ static int st95hf_in_send_cmd(struct nfc_digital_dev *ddev,
int len_data_to_tag = 0;
skb_resp = nfc_alloc_recv_skb(MAX_RESPONSE_BUFFER_SIZE, GFP_KERNEL);
- if (!skb_resp) {
- rc = -ENOMEM;
- goto error;
- }
+ if (!skb_resp)
+ return -ENOMEM;
switch (stcontext->current_rf_tech) {
case NFC_DIGITAL_RF_TECH_106A:
@@ -986,7 +984,6 @@ static int st95hf_in_send_cmd(struct nfc_digital_dev *ddev,
free_skb_resp:
kfree_skb(skb_resp);
-error:
return rc;
}
@@ -1059,9 +1056,9 @@ static const struct spi_device_id st95hf_id[] = {
};
MODULE_DEVICE_TABLE(spi, st95hf_id);
-static const struct of_device_id st95hf_spi_of_match[] = {
- { .compatible = "st,st95hf" },
- { },
+static const struct of_device_id st95hf_spi_of_match[] __maybe_unused = {
+ { .compatible = "st,st95hf" },
+ {},
};
MODULE_DEVICE_TABLE(of, st95hf_spi_of_match);
diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c
index 7b9556291eb1..088d3dd6f6fa 100644
--- a/drivers/nvdimm/blk.c
+++ b/drivers/nvdimm/blk.c
@@ -228,49 +228,34 @@ static const struct block_device_operations nd_blk_fops = {
.submit_bio = nd_blk_submit_bio,
};
-static void nd_blk_release_queue(void *q)
-{
- blk_cleanup_queue(q);
-}
-
static void nd_blk_release_disk(void *disk)
{
del_gendisk(disk);
- put_disk(disk);
+ blk_cleanup_disk(disk);
}
static int nsblk_attach_disk(struct nd_namespace_blk *nsblk)
{
struct device *dev = &nsblk->common.dev;
resource_size_t available_disk_size;
- struct request_queue *q;
struct gendisk *disk;
u64 internal_nlba;
internal_nlba = div_u64(nsblk->size, nsblk_internal_lbasize(nsblk));
available_disk_size = internal_nlba * nsblk_sector_size(nsblk);
- q = blk_alloc_queue(NUMA_NO_NODE);
- if (!q)
- return -ENOMEM;
- if (devm_add_action_or_reset(dev, nd_blk_release_queue, q))
- return -ENOMEM;
-
- blk_queue_max_hw_sectors(q, UINT_MAX);
- blk_queue_logical_block_size(q, nsblk_sector_size(nsblk));
- blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
-
- disk = alloc_disk(0);
+ disk = blk_alloc_disk(NUMA_NO_NODE);
if (!disk)
return -ENOMEM;
- disk->first_minor = 0;
disk->fops = &nd_blk_fops;
- disk->queue = q;
- disk->flags = GENHD_FL_EXT_DEVT;
disk->private_data = nsblk;
nvdimm_namespace_disk_name(&nsblk->common, disk->disk_name);
+ blk_queue_max_hw_sectors(disk->queue, UINT_MAX);
+ blk_queue_logical_block_size(disk->queue, nsblk_sector_size(nsblk));
+ blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue);
+
if (devm_add_action_or_reset(dev, nd_blk_release_disk, disk))
return -ENOMEM;
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index 18a267d5073f..92dec4952297 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -1521,35 +1521,25 @@ static int btt_blk_init(struct btt *btt)
struct nd_btt *nd_btt = btt->nd_btt;
struct nd_namespace_common *ndns = nd_btt->ndns;
- /* create a new disk and request queue for btt */
- btt->btt_queue = blk_alloc_queue(NUMA_NO_NODE);
- if (!btt->btt_queue)
+ btt->btt_disk = blk_alloc_disk(NUMA_NO_NODE);
+ if (!btt->btt_disk)
return -ENOMEM;
- btt->btt_disk = alloc_disk(0);
- if (!btt->btt_disk) {
- blk_cleanup_queue(btt->btt_queue);
- return -ENOMEM;
- }
-
nvdimm_namespace_disk_name(ndns, btt->btt_disk->disk_name);
btt->btt_disk->first_minor = 0;
btt->btt_disk->fops = &btt_fops;
btt->btt_disk->private_data = btt;
- btt->btt_disk->queue = btt->btt_queue;
- btt->btt_disk->flags = GENHD_FL_EXT_DEVT;
- blk_queue_logical_block_size(btt->btt_queue, btt->sector_size);
- blk_queue_max_hw_sectors(btt->btt_queue, UINT_MAX);
- blk_queue_flag_set(QUEUE_FLAG_NONROT, btt->btt_queue);
+ blk_queue_logical_block_size(btt->btt_disk->queue, btt->sector_size);
+ blk_queue_max_hw_sectors(btt->btt_disk->queue, UINT_MAX);
+ blk_queue_flag_set(QUEUE_FLAG_NONROT, btt->btt_disk->queue);
if (btt_meta_size(btt)) {
int rc = nd_integrity_init(btt->btt_disk, btt_meta_size(btt));
if (rc) {
del_gendisk(btt->btt_disk);
- put_disk(btt->btt_disk);
- blk_cleanup_queue(btt->btt_queue);
+ blk_cleanup_disk(btt->btt_disk);
return rc;
}
}
@@ -1564,8 +1554,7 @@ static int btt_blk_init(struct btt *btt)
static void btt_blk_cleanup(struct btt *btt)
{
del_gendisk(btt->btt_disk);
- put_disk(btt->btt_disk);
- blk_cleanup_queue(btt->btt_queue);
+ blk_cleanup_disk(btt->btt_disk);
}
/**
diff --git a/drivers/nvdimm/btt.h b/drivers/nvdimm/btt.h
index aa53e0b769bd..0c76c0333f6e 100644
--- a/drivers/nvdimm/btt.h
+++ b/drivers/nvdimm/btt.h
@@ -201,7 +201,6 @@ struct badblocks;
/**
* struct btt - handle for a BTT instance
* @btt_disk: Pointer to the gendisk for BTT device
- * @btt_queue: Pointer to the request queue for the BTT device
* @arena_list: Head of the list of arenas
* @debugfs_dir: Debugfs dentry
* @nd_btt: Parent nd_btt struct
@@ -219,7 +218,6 @@ struct badblocks;
*/
struct btt {
struct gendisk *btt_disk;
- struct request_queue *btt_queue;
struct list_head arena_list;
struct dentry *debugfs_dir;
struct nd_btt *nd_btt;
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 3a777d0073b7..e6aa87043a95 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -363,8 +363,13 @@ struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
nvdimm_bus->dev.groups = nd_desc->attr_groups;
nvdimm_bus->dev.bus = &nvdimm_bus_type;
nvdimm_bus->dev.of_node = nd_desc->of_node;
- dev_set_name(&nvdimm_bus->dev, "ndbus%d", nvdimm_bus->id);
- rc = device_register(&nvdimm_bus->dev);
+ device_initialize(&nvdimm_bus->dev);
+ device_set_pm_not_required(&nvdimm_bus->dev);
+ rc = dev_set_name(&nvdimm_bus->dev, "ndbus%d", nvdimm_bus->id);
+ if (rc)
+ goto err;
+
+ rc = device_add(&nvdimm_bus->dev);
if (rc) {
dev_dbg(&nvdimm_bus->dev, "registration failed: %d\n", rc);
goto err;
@@ -396,21 +401,10 @@ static int child_unregister(struct device *dev, void *data)
if (dev->class)
return 0;
- if (is_nvdimm(dev)) {
- struct nvdimm *nvdimm = to_nvdimm(dev);
- bool dev_put = false;
-
- /* We are shutting down. Make state frozen artificially. */
- nvdimm_bus_lock(dev);
- set_bit(NVDIMM_SECURITY_FROZEN, &nvdimm->sec.flags);
- if (test_and_clear_bit(NDD_WORK_PENDING, &nvdimm->flags))
- dev_put = true;
- nvdimm_bus_unlock(dev);
- cancel_delayed_work_sync(&nvdimm->dwork);
- if (dev_put)
- put_device(dev);
- }
- nd_device_unregister(dev, ND_SYNC);
+ if (is_nvdimm(dev))
+ nvdimm_delete(to_nvdimm(dev));
+ else
+ nd_device_unregister(dev, ND_SYNC);
return 0;
}
@@ -536,6 +530,7 @@ void __nd_device_register(struct device *dev)
set_dev_node(dev, to_nd_region(dev)->numa_node);
dev->bus = &nvdimm_bus_type;
+ device_set_pm_not_required(dev);
if (dev->parent) {
get_device(dev->parent);
if (dev_to_node(dev) == NUMA_NO_NODE)
@@ -728,18 +723,41 @@ const struct attribute_group nd_numa_attribute_group = {
.is_visible = nd_numa_attr_visible,
};
+static void ndctl_release(struct device *dev)
+{
+ kfree(dev);
+}
+
int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus)
{
dev_t devt = MKDEV(nvdimm_bus_major, nvdimm_bus->id);
struct device *dev;
+ int rc;
- dev = device_create(nd_class, &nvdimm_bus->dev, devt, nvdimm_bus,
- "ndctl%d", nvdimm_bus->id);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+ device_initialize(dev);
+ device_set_pm_not_required(dev);
+ dev->class = nd_class;
+ dev->parent = &nvdimm_bus->dev;
+ dev->devt = devt;
+ dev->release = ndctl_release;
+ rc = dev_set_name(dev, "ndctl%d", nvdimm_bus->id);
+ if (rc)
+ goto err;
- if (IS_ERR(dev))
- dev_dbg(&nvdimm_bus->dev, "failed to register ndctl%d: %ld\n",
- nvdimm_bus->id, PTR_ERR(dev));
- return PTR_ERR_OR_ZERO(dev);
+ rc = device_add(dev);
+ if (rc) {
+ dev_dbg(&nvdimm_bus->dev, "failed to register ndctl%d: %d\n",
+ nvdimm_bus->id, rc);
+ goto err;
+ }
+ return 0;
+
+err:
+ put_device(dev);
+ return rc;
}
void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus)
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index 9d208570d059..dc7449a40003 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -642,6 +642,24 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
}
EXPORT_SYMBOL_GPL(__nvdimm_create);
+void nvdimm_delete(struct nvdimm *nvdimm)
+{
+ struct device *dev = &nvdimm->dev;
+ bool dev_put = false;
+
+ /* We are shutting down. Make state frozen artificially. */
+ nvdimm_bus_lock(dev);
+ set_bit(NVDIMM_SECURITY_FROZEN, &nvdimm->sec.flags);
+ if (test_and_clear_bit(NDD_WORK_PENDING, &nvdimm->flags))
+ dev_put = true;
+ nvdimm_bus_unlock(dev);
+ cancel_delayed_work_sync(&nvdimm->dwork);
+ if (dev_put)
+ put_device(dev);
+ nd_device_unregister(dev, ND_SYNC);
+}
+EXPORT_SYMBOL_GPL(nvdimm_delete);
+
static void shutdown_security_notify(void *data)
{
struct nvdimm *nvdimm = data;
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index ed10a8b66068..1e0615b8565e 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -335,10 +335,9 @@ static const struct attribute_group *pmem_attribute_groups[] = {
static void pmem_pagemap_cleanup(struct dev_pagemap *pgmap)
{
- struct request_queue *q =
- container_of(pgmap->ref, struct request_queue, q_usage_counter);
+ struct pmem_device *pmem = pgmap->owner;
- blk_cleanup_queue(q);
+ blk_cleanup_disk(pmem->disk);
}
static void pmem_release_queue(void *pgmap)
@@ -361,7 +360,6 @@ static void pmem_release_disk(void *__pmem)
kill_dax(pmem->dax_dev);
put_dax(pmem->dax_dev);
del_gendisk(pmem->disk);
- put_disk(pmem->disk);
}
static const struct dev_pagemap_ops fsdax_pagemap_ops = {
@@ -422,10 +420,13 @@ static int pmem_attach_disk(struct device *dev,
return -EBUSY;
}
- q = blk_alloc_queue(dev_to_node(dev));
- if (!q)
+ disk = blk_alloc_disk(nid);
+ if (!disk)
return -ENOMEM;
+ q = disk->queue;
+ pmem->disk = disk;
+ pmem->pgmap.owner = pmem;
pmem->pfn_flags = PFN_DEV;
pmem->pgmap.ref = &q->q_usage_counter;
if (is_nd_pfn(dev)) {
@@ -470,14 +471,7 @@ static int pmem_attach_disk(struct device *dev,
if (pmem->pfn_flags & PFN_MAP)
blk_queue_flag_set(QUEUE_FLAG_DAX, q);
- disk = alloc_disk_node(0, nid);
- if (!disk)
- return -ENOMEM;
- pmem->disk = disk;
-
disk->fops = &pmem_fops;
- disk->queue = q;
- disk->flags = GENHD_FL_EXT_DEVT;
disk->private_data = pmem;
nvdimm_namespace_disk_name(ndns, disk->disk_name);
set_capacity(disk, (pmem->size - pmem->pfn_pad - pmem->data_offset)
@@ -491,7 +485,6 @@ static int pmem_attach_disk(struct device *dev,
flags = DAXDEV_F_SYNC;
dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops, flags);
if (IS_ERR(dax_dev)) {
- put_disk(disk);
return PTR_ERR(dax_dev);
}
dax_write_cache(dax_dev, nvdimm_has_cache(nd_region));
diff --git a/drivers/nvme/host/Kconfig b/drivers/nvme/host/Kconfig
index 494675aeaaad..c3f3d77f1aac 100644
--- a/drivers/nvme/host/Kconfig
+++ b/drivers/nvme/host/Kconfig
@@ -21,7 +21,7 @@ config NVME_MULTIPATH
help
This option enables support for multipath access to NVMe
subsystems. If this option is enabled only a single
- /dev/nvmeXnY device will show up for each NVMe namespaces,
+ /dev/nvmeXnY device will show up for each NVMe namespace,
even if it is accessible through multiple controllers.
config NVME_HWMON
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 66973bb56305..11779be42186 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -57,6 +57,26 @@ static bool force_apst;
module_param(force_apst, bool, 0644);
MODULE_PARM_DESC(force_apst, "allow APST for newly enumerated devices even if quirked off");
+static unsigned long apst_primary_timeout_ms = 100;
+module_param(apst_primary_timeout_ms, ulong, 0644);
+MODULE_PARM_DESC(apst_primary_timeout_ms,
+ "primary APST timeout in ms");
+
+static unsigned long apst_secondary_timeout_ms = 2000;
+module_param(apst_secondary_timeout_ms, ulong, 0644);
+MODULE_PARM_DESC(apst_secondary_timeout_ms,
+ "secondary APST timeout in ms");
+
+static unsigned long apst_primary_latency_tol_us = 15000;
+module_param(apst_primary_latency_tol_us, ulong, 0644);
+MODULE_PARM_DESC(apst_primary_latency_tol_us,
+ "primary APST latency tolerance in us");
+
+static unsigned long apst_secondary_latency_tol_us = 100000;
+module_param(apst_secondary_latency_tol_us, ulong, 0644);
+MODULE_PARM_DESC(apst_secondary_latency_tol_us,
+ "secondary APST latency tolerance in us");
+
static bool streams;
module_param(streams, bool, 0644);
MODULE_PARM_DESC(streams, "turn on support for Streams write directives");
@@ -589,6 +609,7 @@ EXPORT_SYMBOL_NS_GPL(nvme_put_ns, NVME_TARGET_PASSTHRU);
static inline void nvme_clear_nvme_request(struct request *req)
{
+ nvme_req(req)->status = 0;
nvme_req(req)->retries = 0;
nvme_req(req)->flags = 0;
req->rq_flags |= RQF_DONTPREP;
@@ -611,6 +632,8 @@ static inline void nvme_init_request(struct request *req,
cmd->common.flags &= ~NVME_CMD_SGL_ALL;
req->cmd_flags |= REQ_FAILFAST_DRIVER;
+ if (req->mq_hctx->type == HCTX_TYPE_POLL)
+ req->cmd_flags |= REQ_HIPRI;
nvme_clear_nvme_request(req);
memcpy(nvme_req(req)->cmd, cmd, sizeof(*cmd));
}
@@ -701,9 +724,7 @@ EXPORT_SYMBOL_GPL(__nvme_check_ready);
static int nvme_toggle_streams(struct nvme_ctrl *ctrl, bool enable)
{
- struct nvme_command c;
-
- memset(&c, 0, sizeof(c));
+ struct nvme_command c = { };
c.directive.opcode = nvme_admin_directive_send;
c.directive.nsid = cpu_to_le32(NVME_NSID_ALL);
@@ -728,9 +749,8 @@ static int nvme_enable_streams(struct nvme_ctrl *ctrl)
static int nvme_get_stream_params(struct nvme_ctrl *ctrl,
struct streams_directive_params *s, u32 nsid)
{
- struct nvme_command c;
+ struct nvme_command c = { };
- memset(&c, 0, sizeof(c));
memset(s, 0, sizeof(*s));
c.directive.opcode = nvme_admin_directive_recv;
@@ -1012,29 +1032,23 @@ blk_status_t nvme_setup_cmd(struct nvme_ns *ns, struct request *req)
}
EXPORT_SYMBOL_GPL(nvme_setup_cmd);
-static void nvme_end_sync_rq(struct request *rq, blk_status_t error)
-{
- struct completion *waiting = rq->end_io_data;
-
- rq->end_io_data = NULL;
- complete(waiting);
-}
-
-static void nvme_execute_rq_polled(struct request_queue *q,
- struct gendisk *bd_disk, struct request *rq, int at_head)
+/*
+ * Return values:
+ * 0: success
+ * >0: nvme controller's cqe status response
+ * <0: kernel error in lieu of controller response
+ */
+static int nvme_execute_rq(struct gendisk *disk, struct request *rq,
+ bool at_head)
{
- DECLARE_COMPLETION_ONSTACK(wait);
-
- WARN_ON_ONCE(!test_bit(QUEUE_FLAG_POLL, &q->queue_flags));
+ blk_status_t status;
- rq->cmd_flags |= REQ_HIPRI;
- rq->end_io_data = &wait;
- blk_execute_rq_nowait(bd_disk, rq, at_head, nvme_end_sync_rq);
-
- while (!completion_done(&wait)) {
- blk_poll(q, request_to_qc_t(rq->mq_hctx, rq), true);
- cond_resched();
- }
+ status = blk_execute_rq(disk, rq, at_head);
+ if (nvme_req(rq)->flags & NVME_REQ_CANCELLED)
+ return -EINTR;
+ if (nvme_req(rq)->status)
+ return nvme_req(rq)->status;
+ return blk_status_to_errno(status);
}
/*
@@ -1044,7 +1058,7 @@ static void nvme_execute_rq_polled(struct request_queue *q,
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)
+ blk_mq_req_flags_t flags)
{
struct request *req;
int ret;
@@ -1065,16 +1079,9 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
goto out;
}
- if (poll)
- nvme_execute_rq_polled(req->q, NULL, req, at_head);
- else
- blk_execute_rq(NULL, req, at_head);
- if (result)
+ ret = nvme_execute_rq(NULL, req, at_head);
+ if (result && ret >= 0)
*result = nvme_req(req)->result;
- if (nvme_req(req)->flags & NVME_REQ_CANCELLED)
- ret = -EINTR;
- else
- ret = nvme_req(req)->status;
out:
blk_mq_free_request(req);
return ret;
@@ -1085,7 +1092,7 @@ int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
void *buffer, unsigned bufflen)
{
return __nvme_submit_sync_cmd(q, cmd, NULL, buffer, bufflen, 0,
- NVME_QID_ANY, 0, 0, false);
+ NVME_QID_ANY, 0, 0);
}
EXPORT_SYMBOL_GPL(nvme_submit_sync_cmd);
@@ -1162,18 +1169,21 @@ static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects)
}
}
-void nvme_execute_passthru_rq(struct request *rq)
+int nvme_execute_passthru_rq(struct request *rq)
{
struct nvme_command *cmd = nvme_req(rq)->cmd;
struct nvme_ctrl *ctrl = nvme_req(rq)->ctrl;
struct nvme_ns *ns = rq->q->queuedata;
struct gendisk *disk = ns ? ns->disk : NULL;
u32 effects;
+ int ret;
effects = nvme_passthru_start(ctrl, ns, cmd->common.opcode);
- blk_execute_rq(disk, rq, 0);
+ ret = nvme_execute_rq(disk, rq, false);
if (effects) /* nothing to be done for zero cmd effects */
nvme_passthru_end(ctrl, effects);
+
+ return ret;
}
EXPORT_SYMBOL_NS_GPL(nvme_execute_passthru_rq, NVME_TARGET_PASSTHRU);
@@ -1440,16 +1450,15 @@ static int nvme_features(struct nvme_ctrl *dev, u8 op, unsigned int fid,
unsigned int dword11, void *buffer, size_t buflen, u32 *result)
{
union nvme_result res = { 0 };
- struct nvme_command c;
+ struct nvme_command c = { };
int ret;
- memset(&c, 0, sizeof(c));
c.features.opcode = op;
c.features.fid = cpu_to_le32(fid);
c.features.dword11 = cpu_to_le32(dword11);
ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &res,
- buffer, buflen, 0, NVME_QID_ANY, 0, 0, false);
+ buffer, buflen, 0, NVME_QID_ANY, 0, 0);
if (ret >= 0 && result)
*result = le32_to_cpu(res.u32);
return ret;
@@ -1522,36 +1531,6 @@ static void nvme_enable_aen(struct nvme_ctrl *ctrl)
queue_work(nvme_wq, &ctrl->async_event_work);
}
-/*
- * Issue ioctl requests on the first available path. Note that unlike normal
- * block layer requests we will not retry failed request on another controller.
- */
-struct nvme_ns *nvme_get_ns_from_disk(struct gendisk *disk,
- struct nvme_ns_head **head, int *srcu_idx)
-{
-#ifdef CONFIG_NVME_MULTIPATH
- if (disk->fops == &nvme_ns_head_ops) {
- struct nvme_ns *ns;
-
- *head = disk->private_data;
- *srcu_idx = srcu_read_lock(&(*head)->srcu);
- ns = nvme_find_path(*head);
- if (!ns)
- srcu_read_unlock(&(*head)->srcu, *srcu_idx);
- return ns;
- }
-#endif
- *head = NULL;
- *srcu_idx = -1;
- return disk->private_data;
-}
-
-void nvme_put_ns_from_disk(struct nvme_ns_head *head, int idx)
-{
- if (head)
- srcu_read_unlock(&head->srcu, idx);
-}
-
static int nvme_ns_open(struct nvme_ns *ns)
{
@@ -1601,9 +1580,8 @@ int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo)
static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type,
u32 max_integrity_segments)
{
- struct blk_integrity integrity;
+ struct blk_integrity integrity = { };
- memset(&integrity, 0, sizeof(integrity));
switch (pi_type) {
case NVME_NS_DPS_PI_TYPE3:
integrity.profile = &t10_pi_type3_crc;
@@ -1948,30 +1926,45 @@ static char nvme_pr_type(enum pr_type type)
}
};
+static int nvme_send_ns_head_pr_command(struct block_device *bdev,
+ struct nvme_command *c, u8 data[16])
+{
+ struct nvme_ns_head *head = bdev->bd_disk->private_data;
+ int srcu_idx = srcu_read_lock(&head->srcu);
+ struct nvme_ns *ns = nvme_find_path(head);
+ int ret = -EWOULDBLOCK;
+
+ if (ns) {
+ c->common.nsid = cpu_to_le32(ns->head->ns_id);
+ ret = nvme_submit_sync_cmd(ns->queue, c, data, 16);
+ }
+ srcu_read_unlock(&head->srcu, srcu_idx);
+ return ret;
+}
+
+static int nvme_send_ns_pr_command(struct nvme_ns *ns, struct nvme_command *c,
+ u8 data[16])
+{
+ c->common.nsid = cpu_to_le32(ns->head->ns_id);
+ return nvme_submit_sync_cmd(ns->queue, c, data, 16);
+}
+
static int nvme_pr_command(struct block_device *bdev, u32 cdw10,
u64 key, u64 sa_key, u8 op)
{
- struct nvme_ns_head *head = NULL;
- struct nvme_ns *ns;
- struct nvme_command c;
- int srcu_idx, ret;
+ struct nvme_command c = { };
u8 data[16] = { 0, };
- ns = nvme_get_ns_from_disk(bdev->bd_disk, &head, &srcu_idx);
- if (unlikely(!ns))
- return -EWOULDBLOCK;
-
put_unaligned_le64(key, &data[0]);
put_unaligned_le64(sa_key, &data[8]);
- memset(&c, 0, sizeof(c));
c.common.opcode = op;
- c.common.nsid = cpu_to_le32(ns->head->ns_id);
c.common.cdw10 = cpu_to_le32(cdw10);
- ret = nvme_submit_sync_cmd(ns->queue, &c, data, 16);
- nvme_put_ns_from_disk(head, srcu_idx);
- return ret;
+ if (IS_ENABLED(CONFIG_NVME_MULTIPATH) &&
+ bdev->bd_disk->fops == &nvme_ns_head_ops)
+ return nvme_send_ns_head_pr_command(bdev, &c, data);
+ return nvme_send_ns_pr_command(bdev->bd_disk->private_data, &c, data);
}
static int nvme_pr_register(struct block_device *bdev, u64 old,
@@ -2036,9 +2029,8 @@ int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
bool send)
{
struct nvme_ctrl *ctrl = data;
- struct nvme_command cmd;
+ struct nvme_command cmd = { };
- memset(&cmd, 0, sizeof(cmd));
if (send)
cmd.common.opcode = nvme_admin_security_send;
else
@@ -2048,11 +2040,22 @@ int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
cmd.common.cdw11 = cpu_to_le32(len);
return __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, NULL, buffer, len, 0,
- NVME_QID_ANY, 1, 0, false);
+ NVME_QID_ANY, 1, 0);
}
EXPORT_SYMBOL_GPL(nvme_sec_submit);
#endif /* CONFIG_BLK_SED_OPAL */
+#ifdef CONFIG_BLK_DEV_ZONED
+static int nvme_report_zones(struct gendisk *disk, sector_t sector,
+ unsigned int nr_zones, report_zones_cb cb, void *data)
+{
+ return nvme_ns_report_zones(disk->private_data, sector, nr_zones, cb,
+ data);
+}
+#else
+#define nvme_report_zones NULL
+#endif /* CONFIG_BLK_DEV_ZONED */
+
static const struct block_device_operations nvme_bdev_ops = {
.owner = THIS_MODULE,
.ioctl = nvme_ioctl,
@@ -2218,13 +2221,53 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
}
/*
+ * The function checks whether the given total (exlat + enlat) latency of
+ * a power state allows the latter to be used as an APST transition target.
+ * It does so by comparing the latency to the primary and secondary latency
+ * tolerances defined by module params. If there's a match, the corresponding
+ * timeout value is returned and the matching tolerance index (1 or 2) is
+ * reported.
+ */
+static bool nvme_apst_get_transition_time(u64 total_latency,
+ u64 *transition_time, unsigned *last_index)
+{
+ if (total_latency <= apst_primary_latency_tol_us) {
+ if (*last_index == 1)
+ return false;
+ *last_index = 1;
+ *transition_time = apst_primary_timeout_ms;
+ return true;
+ }
+ if (apst_secondary_timeout_ms &&
+ total_latency <= apst_secondary_latency_tol_us) {
+ if (*last_index <= 2)
+ return false;
+ *last_index = 2;
+ *transition_time = apst_secondary_timeout_ms;
+ return true;
+ }
+ return false;
+}
+
+/*
* APST (Autonomous Power State Transition) lets us program a table of power
* state transitions that the controller will perform automatically.
- * We configure it with a simple heuristic: we are willing to spend at most 2%
- * of the time transitioning between power states. Therefore, when running in
- * any given state, we will enter the next lower-power non-operational state
- * after waiting 50 * (enlat + exlat) microseconds, as long as that state's exit
- * latency is under the requested maximum latency.
+ *
+ * Depending on module params, one of the two supported techniques will be used:
+ *
+ * - If the parameters provide explicit timeouts and tolerances, they will be
+ * used to build a table with up to 2 non-operational states to transition to.
+ * The default parameter values were selected based on the values used by
+ * Microsoft's and Intel's NVMe drivers. Yet, since we don't implement dynamic
+ * regeneration of the APST table in the event of switching between external
+ * and battery power, the timeouts and tolerances reflect a compromise
+ * between values used by Microsoft for AC and battery scenarios.
+ * - If not, we'll configure the table with a simple heuristic: we are willing
+ * to spend at most 2% of the time transitioning between power states.
+ * Therefore, when running in any given state, we will enter the next
+ * lower-power non-operational state after waiting 50 * (enlat + exlat)
+ * microseconds, as long as that state's exit latency is under the requested
+ * maximum latency.
*
* We will not autonomously enter any non-operational state for which the total
* latency exceeds ps_max_latency_us.
@@ -2240,6 +2283,7 @@ static int nvme_configure_apst(struct nvme_ctrl *ctrl)
int max_ps = -1;
int state;
int ret;
+ unsigned last_lt_index = UINT_MAX;
/*
* If APST isn't supported or if we haven't been initialized yet,
@@ -2298,13 +2342,19 @@ static int nvme_configure_apst(struct nvme_ctrl *ctrl)
le32_to_cpu(ctrl->psd[state].entry_lat);
/*
- * This state is good. Use it as the APST idle target for
- * higher power states.
+ * This state is good. It can be used as the APST idle target
+ * for higher power states.
*/
- transition_ms = total_latency_us + 19;
- do_div(transition_ms, 20);
- if (transition_ms > (1 << 24) - 1)
- transition_ms = (1 << 24) - 1;
+ if (apst_primary_timeout_ms && apst_primary_latency_tol_us) {
+ if (!nvme_apst_get_transition_time(total_latency_us,
+ &transition_ms, &last_lt_index))
+ continue;
+ } else {
+ transition_ms = total_latency_us + 19;
+ do_div(transition_ms, 20);
+ if (transition_ms > (1 << 24) - 1)
+ transition_ms = (1 << 24) - 1;
+ }
target = cpu_to_le64((state << 3) | (transition_ms << 8));
if (max_ps == -1)
@@ -3701,7 +3751,6 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
disk->fops = &nvme_bdev_ops;
disk->private_data = ns;
disk->queue = ns->queue;
- disk->flags = GENHD_FL_EXT_DEVT;
/*
* Without the multipath code enabled, multiple controller per
* subsystems are visible as devices and thus we cannot use the
@@ -4069,6 +4118,11 @@ static int nvme_class_uevent(struct device *dev, struct kobj_uevent_env *env)
ret = add_uevent_var(env, "NVME_HOST_TRADDR=%s",
opts->host_traddr ?: "none");
+ if (ret)
+ return ret;
+
+ ret = add_uevent_var(env, "NVME_HOST_IFACE=%s",
+ opts->host_iface ?: "none");
}
return ret;
}
diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index 34a84d2086c7..a5469fd9d4c3 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -112,6 +112,9 @@ int nvmf_get_address(struct nvme_ctrl *ctrl, char *buf, int size)
if (ctrl->opts->mask & NVMF_OPT_HOST_TRADDR)
len += scnprintf(buf + len, size - len, "%shost_traddr=%s",
(len) ? "," : "", ctrl->opts->host_traddr);
+ if (ctrl->opts->mask & NVMF_OPT_HOST_IFACE)
+ len += scnprintf(buf + len, size - len, "%shost_iface=%s",
+ (len) ? "," : "", ctrl->opts->host_iface);
len += scnprintf(buf + len, size - len, "\n");
return len;
@@ -151,7 +154,7 @@ int nvmf_reg_read32(struct nvme_ctrl *ctrl, u32 off, u32 *val)
cmd.prop_get.offset = cpu_to_le32(off);
ret = __nvme_submit_sync_cmd(ctrl->fabrics_q, &cmd, &res, NULL, 0, 0,
- NVME_QID_ANY, 0, 0, false);
+ NVME_QID_ANY, 0, 0);
if (ret >= 0)
*val = le64_to_cpu(res.u64);
@@ -187,18 +190,17 @@ EXPORT_SYMBOL_GPL(nvmf_reg_read32);
*/
int nvmf_reg_read64(struct nvme_ctrl *ctrl, u32 off, u64 *val)
{
- struct nvme_command cmd;
+ struct nvme_command cmd = { };
union nvme_result res;
int ret;
- memset(&cmd, 0, sizeof(cmd));
cmd.prop_get.opcode = nvme_fabrics_command;
cmd.prop_get.fctype = nvme_fabrics_type_property_get;
cmd.prop_get.attrib = 1;
cmd.prop_get.offset = cpu_to_le32(off);
ret = __nvme_submit_sync_cmd(ctrl->fabrics_q, &cmd, &res, NULL, 0, 0,
- NVME_QID_ANY, 0, 0, false);
+ NVME_QID_ANY, 0, 0);
if (ret >= 0)
*val = le64_to_cpu(res.u64);
@@ -233,10 +235,9 @@ EXPORT_SYMBOL_GPL(nvmf_reg_read64);
*/
int nvmf_reg_write32(struct nvme_ctrl *ctrl, u32 off, u32 val)
{
- struct nvme_command cmd;
+ struct nvme_command cmd = { };
int ret;
- memset(&cmd, 0, sizeof(cmd));
cmd.prop_set.opcode = nvme_fabrics_command;
cmd.prop_set.fctype = nvme_fabrics_type_property_set;
cmd.prop_set.attrib = 0;
@@ -244,7 +245,7 @@ int nvmf_reg_write32(struct nvme_ctrl *ctrl, u32 off, u32 val)
cmd.prop_set.value = cpu_to_le64(val);
ret = __nvme_submit_sync_cmd(ctrl->fabrics_q, &cmd, NULL, NULL, 0, 0,
- NVME_QID_ANY, 0, 0, false);
+ NVME_QID_ANY, 0, 0);
if (unlikely(ret))
dev_err(ctrl->device,
"Property Set error: %d, offset %#x\n",
@@ -254,28 +255,23 @@ int nvmf_reg_write32(struct nvme_ctrl *ctrl, u32 off, u32 val)
EXPORT_SYMBOL_GPL(nvmf_reg_write32);
/**
- * nvmf_log_connect_error() - Error-parsing-diagnostic print
- * out function for connect() errors.
- *
- * @ctrl: the specific /dev/nvmeX device that had the error.
- *
- * @errval: Error code to be decoded in a more human-friendly
- * printout.
- *
- * @offset: For use with the NVMe error code NVME_SC_CONNECT_INVALID_PARAM.
- *
- * @cmd: This is the SQE portion of a submission capsule.
- *
- * @data: This is the "Data" portion of a submission capsule.
+ * nvmf_log_connect_error() - Error-parsing-diagnostic print out function for
+ * connect() errors.
+ * @ctrl: The specific /dev/nvmeX device that had the error.
+ * @errval: Error code to be decoded in a more human-friendly
+ * printout.
+ * @offset: For use with the NVMe error code
+ * NVME_SC_CONNECT_INVALID_PARAM.
+ * @cmd: This is the SQE portion of a submission capsule.
+ * @data: This is the "Data" portion of a submission capsule.
*/
static void nvmf_log_connect_error(struct nvme_ctrl *ctrl,
int errval, int offset, struct nvme_command *cmd,
struct nvmf_connect_data *data)
{
- int err_sctype = errval & (~NVME_SC_DNR);
+ int err_sctype = errval & ~NVME_SC_DNR;
switch (err_sctype) {
-
case (NVME_SC_CONNECT_INVALID_PARAM):
if (offset >> 16) {
char *inv_data = "Connect Invalid Data Parameter";
@@ -318,35 +314,30 @@ static void nvmf_log_connect_error(struct nvme_ctrl *ctrl,
}
}
break;
-
case NVME_SC_CONNECT_INVALID_HOST:
dev_err(ctrl->device,
"Connect for subsystem %s is not allowed, hostnqn: %s\n",
data->subsysnqn, data->hostnqn);
break;
-
case NVME_SC_CONNECT_CTRL_BUSY:
dev_err(ctrl->device,
"Connect command failed: controller is busy or not available\n");
break;
-
case NVME_SC_CONNECT_FORMAT:
dev_err(ctrl->device,
"Connect incompatible format: %d",
cmd->connect.recfmt);
break;
-
case NVME_SC_HOST_PATH_ERROR:
dev_err(ctrl->device,
"Connect command failed: host path error\n");
break;
-
default:
dev_err(ctrl->device,
"Connect command failed, error wo/DNR bit: %d\n",
err_sctype);
break;
- } /* switch (err_sctype) */
+ }
}
/**
@@ -371,12 +362,11 @@ static void nvmf_log_connect_error(struct nvme_ctrl *ctrl,
*/
int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl)
{
- struct nvme_command cmd;
+ struct nvme_command cmd = { };
union nvme_result res;
struct nvmf_connect_data *data;
int ret;
- memset(&cmd, 0, sizeof(cmd));
cmd.connect.opcode = nvme_fabrics_command;
cmd.connect.fctype = nvme_fabrics_type_connect;
cmd.connect.qid = 0;
@@ -401,7 +391,7 @@ int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl)
ret = __nvme_submit_sync_cmd(ctrl->fabrics_q, &cmd, &res,
data, sizeof(*data), 0, NVME_QID_ANY, 1,
- BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT, false);
+ BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
if (ret) {
nvmf_log_connect_error(ctrl, ret, le32_to_cpu(res.u32),
&cmd, data);
@@ -425,7 +415,6 @@ EXPORT_SYMBOL_GPL(nvmf_connect_admin_queue);
* @qid: NVMe I/O queue number for the new I/O connection between
* host and target (note qid == 0 is illegal as this is
* the Admin queue, per NVMe standard).
- * @poll: Whether or not to poll for the completion of the connect cmd.
*
* This function issues a fabrics-protocol connection
* of a NVMe I/O queue (via NVMe Fabrics "Connect" command)
@@ -437,14 +426,13 @@ EXPORT_SYMBOL_GPL(nvmf_connect_admin_queue);
* > 0: NVMe error status code
* < 0: Linux errno error code
*/
-int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid, bool poll)
+int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid)
{
- struct nvme_command cmd;
+ struct nvme_command cmd = { };
struct nvmf_connect_data *data;
union nvme_result res;
int ret;
- memset(&cmd, 0, sizeof(cmd));
cmd.connect.opcode = nvme_fabrics_command;
cmd.connect.fctype = nvme_fabrics_type_connect;
cmd.connect.qid = cpu_to_le16(qid);
@@ -464,7 +452,7 @@ int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid, bool poll)
ret = __nvme_submit_sync_cmd(ctrl->connect_q, &cmd, &res,
data, sizeof(*data), 0, qid, 1,
- BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT, poll);
+ BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
if (ret) {
nvmf_log_connect_error(ctrl, ret, le32_to_cpu(res.u32),
&cmd, data);
@@ -550,6 +538,7 @@ static const match_table_t opt_tokens = {
{ NVMF_OPT_KATO, "keep_alive_tmo=%d" },
{ NVMF_OPT_HOSTNQN, "hostnqn=%s" },
{ NVMF_OPT_HOST_TRADDR, "host_traddr=%s" },
+ { NVMF_OPT_HOST_IFACE, "host_iface=%s" },
{ NVMF_OPT_HOST_ID, "hostid=%s" },
{ NVMF_OPT_DUP_CONNECT, "duplicate_connect" },
{ NVMF_OPT_DISABLE_SQFLOW, "disable_sqflow" },
@@ -759,6 +748,15 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
kfree(opts->host_traddr);
opts->host_traddr = p;
break;
+ case NVMF_OPT_HOST_IFACE:
+ p = match_strdup(args);
+ if (!p) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ kfree(opts->host_iface);
+ opts->host_iface = p;
+ break;
case NVMF_OPT_HOST_ID:
p = match_strdup(args);
if (!p) {
@@ -943,6 +941,7 @@ void nvmf_free_options(struct nvmf_ctrl_options *opts)
kfree(opts->trsvcid);
kfree(opts->subsysnqn);
kfree(opts->host_traddr);
+ kfree(opts->host_iface);
kfree(opts);
}
EXPORT_SYMBOL_GPL(nvmf_free_options);
diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h
index d7f7974dc208..a146cb903869 100644
--- a/drivers/nvme/host/fabrics.h
+++ b/drivers/nvme/host/fabrics.h
@@ -66,6 +66,7 @@ enum {
NVMF_OPT_NR_POLL_QUEUES = 1 << 18,
NVMF_OPT_TOS = 1 << 19,
NVMF_OPT_FAIL_FAST_TMO = 1 << 20,
+ NVMF_OPT_HOST_IFACE = 1 << 21,
};
/**
@@ -83,7 +84,9 @@ enum {
* @trsvcid: The transport-specific TRSVCID field for a port on the
* subsystem which is adding a controller.
* @host_traddr: A transport-specific field identifying the NVME host port
- * to use for the connection to the controller.
+ * to use for the connection to the controller.
+ * @host_iface: A transport-specific field identifying the NVME host
+ * interface to use for the connection to the controller.
* @queue_size: Number of IO queue elements.
* @nr_io_queues: Number of controller IO queues that will be established.
* @reconnect_delay: Time between two consecutive reconnect attempts.
@@ -108,6 +111,7 @@ struct nvmf_ctrl_options {
char *traddr;
char *trsvcid;
char *host_traddr;
+ char *host_iface;
size_t queue_size;
unsigned int nr_io_queues;
unsigned int reconnect_delay;
@@ -178,7 +182,7 @@ int nvmf_reg_read32(struct nvme_ctrl *ctrl, u32 off, u32 *val);
int nvmf_reg_read64(struct nvme_ctrl *ctrl, u32 off, u64 *val);
int nvmf_reg_write32(struct nvme_ctrl *ctrl, u32 off, u32 val);
int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl);
-int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid, bool poll);
+int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid);
int nvmf_register_transport(struct nvmf_transport_ops *ops);
void nvmf_unregister_transport(struct nvmf_transport_ops *ops);
void nvmf_free_options(struct nvmf_ctrl_options *opts);
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index f183f9fa03d0..b08a61ca283f 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -9,7 +9,7 @@
#include <uapi/scsi/fc/fc_els.h>
#include <linux/delay.h>
#include <linux/overflow.h>
-
+#include <linux/blk-cgroup.h>
#include "nvme.h"
#include "fabrics.h"
#include <linux/nvme-fc-driver.h>
@@ -2346,7 +2346,7 @@ nvme_fc_connect_io_queues(struct nvme_fc_ctrl *ctrl, u16 qsize)
(qsize / 5));
if (ret)
break;
- ret = nvmf_connect_io_queue(&ctrl->ctrl, i, false);
+ ret = nvmf_connect_io_queue(&ctrl->ctrl, i);
if (ret)
break;
@@ -3112,7 +3112,7 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)
}
/* FC-NVME supports normal SGL Data Block Descriptors */
- if (!(ctrl->ctrl.sgls & ((1 << 0) | (1 << 1)))) {
+ if (!nvme_ctrl_sgl_supported(&ctrl->ctrl)) {
dev_err(ctrl->ctrl.device,
"Mandatory sgls are not supported!\n");
ret = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
@@ -3808,10 +3808,80 @@ process_local_list:
return count;
}
+
+/* Parse the cgroup id from a buf and return the length of cgrpid */
+static int fc_parse_cgrpid(const char *buf, u64 *id)
+{
+ char cgrp_id[16+1];
+ int cgrpid_len, j;
+
+ memset(cgrp_id, 0x0, sizeof(cgrp_id));
+ for (cgrpid_len = 0, j = 0; cgrpid_len < 17; cgrpid_len++) {
+ if (buf[cgrpid_len] != ':')
+ cgrp_id[cgrpid_len] = buf[cgrpid_len];
+ else {
+ j = 1;
+ break;
+ }
+ }
+ if (!j)
+ return -EINVAL;
+ if (kstrtou64(cgrp_id, 16, id) < 0)
+ return -EINVAL;
+ return cgrpid_len;
+}
+
+/*
+ * fc_update_appid: Parse and update the appid in the blkcg associated with
+ * cgroupid.
+ * @buf: buf contains both cgrpid and appid info
+ * @count: size of the buffer
+ */
+static int fc_update_appid(const char *buf, size_t count)
+{
+ u64 cgrp_id;
+ int appid_len = 0;
+ int cgrpid_len = 0;
+ char app_id[FC_APPID_LEN];
+ int ret = 0;
+
+ if (buf[count-1] == '\n')
+ count--;
+
+ if ((count > (16+1+FC_APPID_LEN)) || (!strchr(buf, ':')))
+ return -EINVAL;
+
+ cgrpid_len = fc_parse_cgrpid(buf, &cgrp_id);
+ if (cgrpid_len < 0)
+ return -EINVAL;
+ appid_len = count - cgrpid_len - 1;
+ if (appid_len > FC_APPID_LEN)
+ return -EINVAL;
+
+ memset(app_id, 0x0, sizeof(app_id));
+ memcpy(app_id, &buf[cgrpid_len+1], appid_len);
+ ret = blkcg_set_fc_appid(app_id, cgrp_id, sizeof(app_id));
+ if (ret < 0)
+ return ret;
+ return count;
+}
+
+static ssize_t fc_appid_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int ret = 0;
+
+ ret = fc_update_appid(buf, count);
+ if (ret < 0)
+ return -EINVAL;
+ return count;
+}
static DEVICE_ATTR(nvme_discovery, 0200, NULL, nvme_fc_nvme_discovery_store);
+static DEVICE_ATTR(appid_store, 0200, NULL, fc_appid_store);
static struct attribute *nvme_fc_attrs[] = {
&dev_attr_nvme_discovery.attr,
+ &dev_attr_appid_store.attr,
NULL
};
diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
index 9557ead02de1..305ddd415e45 100644
--- a/drivers/nvme/host/ioctl.c
+++ b/drivers/nvme/host/ioctl.c
@@ -93,11 +93,7 @@ static int nvme_submit_user_cmd(struct request_queue *q,
}
}
- nvme_execute_passthru_rq(req);
- if (nvme_req(req)->flags & NVME_REQ_CANCELLED)
- ret = -EINTR;
- else
- ret = nvme_req(req)->status;
+ ret = nvme_execute_passthru_rq(req);
if (result)
*result = le64_to_cpu(nvme_req(req)->result.u64);
if (meta && !ret && !write) {
@@ -177,6 +173,20 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
metadata, meta_len, lower_32_bits(io.slba), NULL, 0);
}
+static bool nvme_validate_passthru_nsid(struct nvme_ctrl *ctrl,
+ struct nvme_ns *ns, __u32 nsid)
+{
+ if (ns && nsid != ns->head->ns_id) {
+ dev_err(ctrl->device,
+ "%s: nsid (%u) in cmd does not match nsid (%u)"
+ "of namespace\n",
+ current->comm, nsid, ns->head->ns_id);
+ return false;
+ }
+
+ return true;
+}
+
static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
struct nvme_passthru_cmd __user *ucmd)
{
@@ -192,12 +202,8 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
return -EFAULT;
if (cmd.flags)
return -EINVAL;
- if (ns && cmd.nsid != ns->head->ns_id) {
- dev_err(ctrl->device,
- "%s: nsid (%u) in cmd does not match nsid (%u) of namespace\n",
- current->comm, cmd.nsid, ns->head->ns_id);
+ if (!nvme_validate_passthru_nsid(ctrl, ns, cmd.nsid))
return -EINVAL;
- }
memset(&c, 0, sizeof(c));
c.common.opcode = cmd.opcode;
@@ -242,12 +248,8 @@ static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
return -EFAULT;
if (cmd.flags)
return -EINVAL;
- if (ns && cmd.nsid != ns->head->ns_id) {
- dev_err(ctrl->device,
- "%s: nsid (%u) in cmd does not match nsid (%u) of namespace\n",
- current->comm, cmd.nsid, ns->head->ns_id);
+ if (!nvme_validate_passthru_nsid(ctrl, ns, cmd.nsid))
return -EINVAL;
- }
memset(&c, 0, sizeof(c));
c.common.opcode = cmd.opcode;
@@ -372,12 +374,13 @@ long nvme_ns_chr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
#ifdef CONFIG_NVME_MULTIPATH
static int nvme_ns_head_ctrl_ioctl(struct nvme_ns *ns, unsigned int cmd,
void __user *argp, struct nvme_ns_head *head, int srcu_idx)
+ __releases(&head->srcu)
{
struct nvme_ctrl *ctrl = ns->ctrl;
int ret;
nvme_get_ctrl(ns->ctrl);
- nvme_put_ns_from_disk(head, srcu_idx);
+ srcu_read_unlock(&head->srcu, srcu_idx);
ret = nvme_ctrl_ioctl(ns->ctrl, cmd, argp);
nvme_put_ctrl(ctrl);
@@ -387,14 +390,15 @@ static int nvme_ns_head_ctrl_ioctl(struct nvme_ns *ns, unsigned int cmd,
int nvme_ns_head_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct nvme_ns_head *head = NULL;
+ struct nvme_ns_head *head = bdev->bd_disk->private_data;
void __user *argp = (void __user *)arg;
struct nvme_ns *ns;
- int srcu_idx, ret;
+ int srcu_idx, ret = -EWOULDBLOCK;
- ns = nvme_get_ns_from_disk(bdev->bd_disk, &head, &srcu_idx);
- if (unlikely(!ns))
- return -EWOULDBLOCK;
+ srcu_idx = srcu_read_lock(&head->srcu);
+ ns = nvme_find_path(head);
+ if (!ns)
+ goto out_unlock;
/*
* Handle ioctls that apply to the controller instead of the namespace
@@ -402,12 +406,11 @@ int nvme_ns_head_ioctl(struct block_device *bdev, fmode_t mode,
* deadlock when deleting namespaces using the passthrough interface.
*/
if (is_ctrl_ioctl(cmd))
- ret = nvme_ns_head_ctrl_ioctl(ns, cmd, argp, head, srcu_idx);
- else {
- ret = nvme_ns_ioctl(ns, cmd, argp);
- nvme_put_ns_from_disk(head, srcu_idx);
- }
+ return nvme_ns_head_ctrl_ioctl(ns, cmd, argp, head, srcu_idx);
+ ret = nvme_ns_ioctl(ns, cmd, argp);
+out_unlock:
+ srcu_read_unlock(&head->srcu, srcu_idx);
return ret;
}
@@ -419,21 +422,19 @@ long nvme_ns_head_chr_ioctl(struct file *file, unsigned int cmd,
container_of(cdev, struct nvme_ns_head, cdev);
void __user *argp = (void __user *)arg;
struct nvme_ns *ns;
- int srcu_idx, ret;
+ int srcu_idx, ret = -EWOULDBLOCK;
srcu_idx = srcu_read_lock(&head->srcu);
ns = nvme_find_path(head);
- if (!ns) {
- srcu_read_unlock(&head->srcu, srcu_idx);
- return -EWOULDBLOCK;
- }
+ if (!ns)
+ goto out_unlock;
if (is_ctrl_ioctl(cmd))
return nvme_ns_head_ctrl_ioctl(ns, cmd, argp, head, srcu_idx);
ret = nvme_ns_ioctl(ns, cmd, argp);
- nvme_put_ns_from_disk(head, srcu_idx);
-
+out_unlock:
+ srcu_read_unlock(&head->srcu, srcu_idx);
return ret;
}
#endif /* CONFIG_NVME_MULTIPATH */
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index f81871c7128a..0ea5298469c3 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -349,6 +349,25 @@ static void nvme_ns_head_release(struct gendisk *disk, fmode_t mode)
nvme_put_ns_head(disk->private_data);
}
+#ifdef CONFIG_BLK_DEV_ZONED
+static int nvme_ns_head_report_zones(struct gendisk *disk, sector_t sector,
+ unsigned int nr_zones, report_zones_cb cb, void *data)
+{
+ struct nvme_ns_head *head = disk->private_data;
+ struct nvme_ns *ns;
+ int srcu_idx, ret = -EWOULDBLOCK;
+
+ srcu_idx = srcu_read_lock(&head->srcu);
+ ns = nvme_find_path(head);
+ if (ns)
+ ret = nvme_ns_report_zones(ns, sector, nr_zones, cb, data);
+ srcu_read_unlock(&head->srcu, srcu_idx);
+ return ret;
+}
+#else
+#define nvme_ns_head_report_zones NULL
+#endif /* CONFIG_BLK_DEV_ZONED */
+
const struct block_device_operations nvme_ns_head_ops = {
.owner = THIS_MODULE,
.submit_bio = nvme_ns_head_submit_bio,
@@ -356,7 +375,7 @@ const struct block_device_operations nvme_ns_head_ops = {
.release = nvme_ns_head_release,
.ioctl = nvme_ns_head_ioctl,
.getgeo = nvme_getgeo,
- .report_zones = nvme_report_zones,
+ .report_zones = nvme_ns_head_report_zones,
.pr_ops = &nvme_pr_ops,
};
@@ -416,18 +435,12 @@ static void nvme_requeue_work(struct work_struct *work)
next = bio->bi_next;
bio->bi_next = NULL;
- /*
- * Reset disk to the mpath node and resubmit to select a new
- * path.
- */
- bio_set_dev(bio, head->disk->part0);
submit_bio_noacct(bio);
}
}
int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
{
- struct request_queue *q;
bool vwc = false;
mutex_init(&head->lock);
@@ -443,34 +456,24 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
if (!(ctrl->subsys->cmic & NVME_CTRL_CMIC_MULTI_CTRL) || !multipath)
return 0;
- q = blk_alloc_queue(ctrl->numa_node);
- if (!q)
- goto out;
- blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
- /* set to a default value for 512 until disk is validated */
- blk_queue_logical_block_size(q, 512);
- blk_set_stacking_limits(&q->limits);
-
- /* we need to propagate up the VMC settings */
- if (ctrl->vwc & NVME_CTRL_VWC_PRESENT)
- vwc = true;
- blk_queue_write_cache(q, vwc, vwc);
-
- head->disk = alloc_disk(0);
+ head->disk = blk_alloc_disk(ctrl->numa_node);
if (!head->disk)
- goto out_cleanup_queue;
+ return -ENOMEM;
head->disk->fops = &nvme_ns_head_ops;
head->disk->private_data = head;
- head->disk->queue = q;
- head->disk->flags = GENHD_FL_EXT_DEVT;
sprintf(head->disk->disk_name, "nvme%dn%d",
ctrl->subsys->instance, head->instance);
- return 0;
-out_cleanup_queue:
- blk_cleanup_queue(q);
-out:
- return -ENOMEM;
+ blk_queue_flag_set(QUEUE_FLAG_NONROT, head->disk->queue);
+ /* set to a default value of 512 until the disk is validated */
+ blk_queue_logical_block_size(head->disk->queue, 512);
+ blk_set_stacking_limits(&head->disk->queue->limits);
+
+ /* we need to propagate up the VMC settings */
+ if (ctrl->vwc & NVME_CTRL_VWC_PRESENT)
+ vwc = true;
+ blk_queue_write_cache(head->disk->queue, vwc, vwc);
+ return 0;
}
static void nvme_mpath_set_live(struct nvme_ns *ns)
@@ -769,16 +772,7 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head)
/* make sure all pending bios are cleaned up */
kblockd_schedule_work(&head->requeue_work);
flush_work(&head->requeue_work);
- blk_cleanup_queue(head->disk->queue);
- if (!test_bit(NVME_NSHEAD_DISK_LIVE, &head->flags)) {
- /*
- * if device_add_disk wasn't called, prevent
- * disk release to put a bogus reference on the
- * request queue
- */
- head->disk->queue = NULL;
- }
- put_disk(head->disk);
+ blk_cleanup_disk(head->disk);
}
void nvme_mpath_init_ctrl(struct nvme_ctrl *ctrl)
@@ -799,6 +793,13 @@ int nvme_mpath_init_identify(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
!(ctrl->subsys->cmic & NVME_CTRL_CMIC_ANA))
return 0;
+ if (!ctrl->max_namespaces ||
+ ctrl->max_namespaces > le32_to_cpu(id->nn)) {
+ dev_err(ctrl->device,
+ "Invalid MNAN value %u\n", ctrl->max_namespaces);
+ return -EINVAL;
+ }
+
ctrl->anacap = id->anacap;
ctrl->anatt = id->anatt;
ctrl->nanagrpid = le32_to_cpu(id->nanagrpid);
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 0015860ec12b..18ef8dd03a90 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -658,7 +658,7 @@ int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
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);
+ blk_mq_req_flags_t flags);
int nvme_set_features(struct nvme_ctrl *dev, unsigned int fid,
unsigned int dword11, void *buffer, size_t buflen,
u32 *result);
@@ -674,9 +674,6 @@ int nvme_delete_ctrl(struct nvme_ctrl *ctrl);
void nvme_queue_scan(struct nvme_ctrl *ctrl);
int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp, u8 csi,
void *log, size_t size, u64 offset);
-struct nvme_ns *nvme_get_ns_from_disk(struct gendisk *disk,
- struct nvme_ns_head **head, int *srcu_idx);
-void nvme_put_ns_from_disk(struct nvme_ns_head *head, int idx);
bool nvme_tryget_ns_head(struct nvme_ns_head *head);
void nvme_put_ns_head(struct nvme_ns_head *head);
int nvme_cdev_add(struct cdev *cdev, struct device *cdev_device,
@@ -697,6 +694,7 @@ extern const struct attribute_group *nvme_ns_id_attr_groups[];
extern const struct pr_ops nvme_pr_ops;
extern const struct block_device_operations nvme_ns_head_ops;
+struct nvme_ns *nvme_find_path(struct nvme_ns_head *head);
#ifdef CONFIG_NVME_MULTIPATH
static inline bool nvme_ctrl_use_ana(struct nvme_ctrl *ctrl)
{
@@ -718,7 +716,6 @@ void nvme_mpath_uninit(struct nvme_ctrl *ctrl);
void nvme_mpath_stop(struct nvme_ctrl *ctrl);
bool nvme_mpath_clear_current_path(struct nvme_ns *ns);
void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl);
-struct nvme_ns *nvme_find_path(struct nvme_ns_head *head);
static inline void nvme_mpath_check_last_path(struct nvme_ns *ns)
{
@@ -810,17 +807,14 @@ static inline void nvme_mpath_start_freeze(struct nvme_subsystem *subsys)
#endif /* CONFIG_NVME_MULTIPATH */
int nvme_revalidate_zones(struct nvme_ns *ns);
+int nvme_ns_report_zones(struct nvme_ns *ns, sector_t sector,
+ unsigned int nr_zones, report_zones_cb cb, void *data);
#ifdef CONFIG_BLK_DEV_ZONED
int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf);
-int nvme_report_zones(struct gendisk *disk, sector_t sector,
- unsigned int nr_zones, report_zones_cb cb, void *data);
-
blk_status_t nvme_setup_zone_mgmt_send(struct nvme_ns *ns, struct request *req,
struct nvme_command *cmnd,
enum nvme_zone_mgmt_action action);
#else
-#define nvme_report_zones NULL
-
static inline blk_status_t nvme_setup_zone_mgmt_send(struct nvme_ns *ns,
struct request *req, struct nvme_command *cmnd,
enum nvme_zone_mgmt_action action)
@@ -875,9 +869,14 @@ static inline void nvme_hwmon_exit(struct nvme_ctrl *ctrl)
}
#endif
+static inline bool nvme_ctrl_sgl_supported(struct nvme_ctrl *ctrl)
+{
+ return ctrl->sgls & ((1 << 0) | (1 << 1));
+}
+
u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
u8 opcode);
-void nvme_execute_passthru_rq(struct request *rq);
+int nvme_execute_passthru_rq(struct request *rq);
struct nvme_ctrl *nvme_ctrl_from_file(struct file *file);
struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid);
void nvme_put_ns(struct nvme_ns *ns);
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index a29b170701fc..320051f5a3dd 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -307,13 +307,12 @@ static void nvme_dbbuf_free(struct nvme_queue *nvmeq)
static void nvme_dbbuf_set(struct nvme_dev *dev)
{
- struct nvme_command c;
+ struct nvme_command c = { };
unsigned int i;
if (!dev->dbbuf_dbs)
return;
- memset(&c, 0, sizeof(c));
c.dbbuf.opcode = nvme_admin_dbbuf;
c.dbbuf.prp1 = cpu_to_le64(dev->dbbuf_dbs_dma_addr);
c.dbbuf.prp2 = cpu_to_le64(dev->dbbuf_eis_dma_addr);
@@ -536,7 +535,7 @@ static inline bool nvme_pci_use_sgls(struct nvme_dev *dev, struct request *req)
avg_seg_size = DIV_ROUND_UP(blk_rq_payload_bytes(req), nseg);
- if (!(dev->ctrl.sgls & ((1 << 0) | (1 << 1))))
+ if (!nvme_ctrl_sgl_supported(&dev->ctrl))
return false;
if (!iod->nvmeq->qid)
return false;
@@ -559,7 +558,6 @@ static void nvme_free_prps(struct nvme_dev *dev, struct request *req)
dma_pool_free(dev->prp_page_pool, prp_list, dma_addr);
dma_addr = next_dma_addr;
}
-
}
static void nvme_free_sgls(struct nvme_dev *dev, struct request *req)
@@ -576,7 +574,6 @@ static void nvme_free_sgls(struct nvme_dev *dev, struct request *req)
dma_pool_free(dev->prp_page_pool, sg_list, dma_addr);
dma_addr = next_dma_addr;
}
-
}
static void nvme_unmap_sg(struct nvme_dev *dev, struct request *req)
@@ -855,7 +852,7 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
&cmnd->rw, &bv);
if (iod->nvmeq->qid && sgl_threshold &&
- dev->ctrl.sgls & ((1 << 0) | (1 << 1)))
+ nvme_ctrl_sgl_supported(&dev->ctrl))
return nvme_setup_sgl_simple(dev, req,
&cmnd->rw, &bv);
}
@@ -1032,7 +1029,7 @@ static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, u16 idx)
static inline void nvme_update_cq_head(struct nvme_queue *nvmeq)
{
- u16 tmp = nvmeq->cq_head + 1;
+ u32 tmp = nvmeq->cq_head + 1;
if (tmp == nvmeq->q_depth) {
nvmeq->cq_head = 0;
@@ -1114,9 +1111,8 @@ static void nvme_pci_submit_async_event(struct nvme_ctrl *ctrl)
{
struct nvme_dev *dev = to_nvme_dev(ctrl);
struct nvme_queue *nvmeq = &dev->queues[0];
- struct nvme_command c;
+ struct nvme_command c = { };
- memset(&c, 0, sizeof(c));
c.common.opcode = nvme_admin_async_event;
c.common.command_id = NVME_AQ_BLK_MQ_DEPTH;
nvme_submit_cmd(nvmeq, &c, true);
@@ -1124,9 +1120,8 @@ static void nvme_pci_submit_async_event(struct nvme_ctrl *ctrl)
static int adapter_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id)
{
- struct nvme_command c;
+ struct nvme_command c = { };
- memset(&c, 0, sizeof(c));
c.delete_queue.opcode = opcode;
c.delete_queue.qid = cpu_to_le16(id);
@@ -1136,7 +1131,7 @@ static int adapter_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id)
static int adapter_alloc_cq(struct nvme_dev *dev, u16 qid,
struct nvme_queue *nvmeq, s16 vector)
{
- struct nvme_command c;
+ struct nvme_command c = { };
int flags = NVME_QUEUE_PHYS_CONTIG;
if (!test_bit(NVMEQ_POLLED, &nvmeq->flags))
@@ -1146,7 +1141,6 @@ static int adapter_alloc_cq(struct nvme_dev *dev, u16 qid,
* Note: we (ab)use the fact that the prp fields survive if no data
* is attached to the request.
*/
- memset(&c, 0, sizeof(c));
c.create_cq.opcode = nvme_admin_create_cq;
c.create_cq.prp1 = cpu_to_le64(nvmeq->cq_dma_addr);
c.create_cq.cqid = cpu_to_le16(qid);
@@ -1161,7 +1155,7 @@ static int adapter_alloc_sq(struct nvme_dev *dev, u16 qid,
struct nvme_queue *nvmeq)
{
struct nvme_ctrl *ctrl = &dev->ctrl;
- struct nvme_command c;
+ struct nvme_command c = { };
int flags = NVME_QUEUE_PHYS_CONTIG;
/*
@@ -1176,7 +1170,6 @@ static int adapter_alloc_sq(struct nvme_dev *dev, u16 qid,
* Note: we (ab)use the fact that the prp fields survive if no data
* is attached to the request.
*/
- memset(&c, 0, sizeof(c));
c.create_sq.opcode = nvme_admin_create_sq;
c.create_sq.prp1 = cpu_to_le64(nvmeq->sq_dma_addr);
c.create_sq.sqid = cpu_to_le16(qid);
@@ -1257,7 +1250,7 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
struct nvme_queue *nvmeq = iod->nvmeq;
struct nvme_dev *dev = nvmeq->dev;
struct request *abort_req;
- struct nvme_command cmd;
+ struct nvme_command cmd = { };
u32 csts = readl(dev->bar + NVME_REG_CSTS);
/* If PCI error recovery process is happening, we cannot reset or
@@ -1337,7 +1330,6 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
}
iod->aborted = 1;
- memset(&cmd, 0, sizeof(cmd));
cmd.abort.opcode = nvme_admin_abort_cmd;
cmd.abort.cid = req->tag;
cmd.abort.sqid = cpu_to_le16(nvmeq->qid);
@@ -1562,6 +1554,28 @@ static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid)
wmb(); /* ensure the first interrupt sees the initialization */
}
+/*
+ * Try getting shutdown_lock while setting up IO queues.
+ */
+static int nvme_setup_io_queues_trylock(struct nvme_dev *dev)
+{
+ /*
+ * Give up if the lock is being held by nvme_dev_disable.
+ */
+ if (!mutex_trylock(&dev->shutdown_lock))
+ return -ENODEV;
+
+ /*
+ * Controller is in wrong state, fail early.
+ */
+ if (dev->ctrl.state != NVME_CTRL_CONNECTING) {
+ mutex_unlock(&dev->shutdown_lock);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled)
{
struct nvme_dev *dev = nvmeq->dev;
@@ -1590,8 +1604,11 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled)
goto release_cq;
nvmeq->cq_vector = vector;
- nvme_init_queue(nvmeq, qid);
+ result = nvme_setup_io_queues_trylock(dev);
+ if (result)
+ return result;
+ nvme_init_queue(nvmeq, qid);
if (!polled) {
result = queue_request_irq(nvmeq);
if (result < 0)
@@ -1599,10 +1616,12 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled)
}
set_bit(NVMEQ_ENABLED, &nvmeq->flags);
+ mutex_unlock(&dev->shutdown_lock);
return result;
release_sq:
dev->online_queues--;
+ mutex_unlock(&dev->shutdown_lock);
adapter_delete_sq(dev, qid);
release_cq:
adapter_delete_cq(dev, qid);
@@ -1888,10 +1907,9 @@ static int nvme_set_host_mem(struct nvme_dev *dev, u32 bits)
{
u32 host_mem_size = dev->host_mem_size >> NVME_CTRL_PAGE_SHIFT;
u64 dma_addr = dev->host_mem_descs_dma;
- struct nvme_command c;
+ struct nvme_command c = { };
int ret;
- memset(&c, 0, sizeof(c));
c.features.opcode = nvme_admin_set_features;
c.features.fid = cpu_to_le32(NVME_FEAT_HOST_MEM_BUF);
c.features.dword11 = cpu_to_le32(bits);
@@ -2176,7 +2194,18 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
if (nr_io_queues == 0)
return 0;
- clear_bit(NVMEQ_ENABLED, &adminq->flags);
+ /*
+ * Free IRQ resources as soon as NVMEQ_ENABLED bit transitions
+ * from set to unset. If there is a window to it is truely freed,
+ * pci_free_irq_vectors() jumping into this window will crash.
+ * And take lock to avoid racing with pci_free_irq_vectors() in
+ * nvme_dev_disable() path.
+ */
+ result = nvme_setup_io_queues_trylock(dev);
+ if (result)
+ return result;
+ if (test_and_clear_bit(NVMEQ_ENABLED, &adminq->flags))
+ pci_free_irq(pdev, 0, adminq);
if (dev->cmb_use_sqes) {
result = nvme_cmb_qdepth(dev, nr_io_queues,
@@ -2192,14 +2221,17 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
result = nvme_remap_bar(dev, size);
if (!result)
break;
- if (!--nr_io_queues)
- return -ENOMEM;
+ if (!--nr_io_queues) {
+ result = -ENOMEM;
+ goto out_unlock;
+ }
} while (1);
adminq->q_db = dev->dbs;
retry:
/* Deregister the admin queue's interrupt */
- pci_free_irq(pdev, 0, adminq);
+ if (test_and_clear_bit(NVMEQ_ENABLED, &adminq->flags))
+ pci_free_irq(pdev, 0, adminq);
/*
* If we enable msix early due to not intx, disable it again before
@@ -2208,8 +2240,10 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
pci_free_irq_vectors(pdev);
result = nvme_setup_irqs(dev, nr_io_queues);
- if (result <= 0)
- return -EIO;
+ if (result <= 0) {
+ result = -EIO;
+ goto out_unlock;
+ }
dev->num_vecs = result;
result = max(result - 1, 1);
@@ -2223,8 +2257,9 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
*/
result = queue_request_irq(adminq);
if (result)
- return result;
+ goto out_unlock;
set_bit(NVMEQ_ENABLED, &adminq->flags);
+ mutex_unlock(&dev->shutdown_lock);
result = nvme_create_io_queues(dev);
if (result || dev->online_queues < 2)
@@ -2233,6 +2268,9 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
if (dev->online_queues - 1 < dev->max_qid) {
nr_io_queues = dev->online_queues - 1;
nvme_disable_io_queues(dev);
+ result = nvme_setup_io_queues_trylock(dev);
+ if (result)
+ return result;
nvme_suspend_io_queues(dev);
goto retry;
}
@@ -2241,6 +2279,9 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
dev->io_queues[HCTX_TYPE_READ],
dev->io_queues[HCTX_TYPE_POLL]);
return 0;
+out_unlock:
+ mutex_unlock(&dev->shutdown_lock);
+ return result;
}
static void nvme_del_queue_end(struct request *req, blk_status_t error)
@@ -2265,9 +2306,8 @@ static int nvme_delete_queue(struct nvme_queue *nvmeq, u8 opcode)
{
struct request_queue *q = nvmeq->dev->ctrl.admin_q;
struct request *req;
- struct nvme_command cmd;
+ struct nvme_command cmd = { };
- memset(&cmd, 0, sizeof(cmd));
cmd.delete_queue.opcode = opcode;
cmd.delete_queue.qid = cpu_to_le16(nvmeq->qid);
@@ -2828,54 +2868,6 @@ static unsigned long check_vendor_combination_bug(struct pci_dev *pdev)
return 0;
}
-#ifdef CONFIG_ACPI
-static bool nvme_acpi_storage_d3(struct pci_dev *dev)
-{
- struct acpi_device *adev;
- struct pci_dev *root;
- acpi_handle handle;
- acpi_status status;
- u8 val;
-
- /*
- * Look for _DSD property specifying that the storage device on the port
- * must use D3 to support deep platform power savings during
- * suspend-to-idle.
- */
- root = pcie_find_root_port(dev);
- if (!root)
- return false;
-
- adev = ACPI_COMPANION(&root->dev);
- if (!adev)
- return false;
-
- /*
- * The property is defined in the PXSX device for South complex ports
- * and in the PEGP device for North complex ports.
- */
- status = acpi_get_handle(adev->handle, "PXSX", &handle);
- if (ACPI_FAILURE(status)) {
- status = acpi_get_handle(adev->handle, "PEGP", &handle);
- if (ACPI_FAILURE(status))
- return false;
- }
-
- if (acpi_bus_get_device(handle, &adev))
- return false;
-
- if (fwnode_property_read_u8(acpi_fwnode_handle(adev), "StorageD3Enable",
- &val))
- return false;
- return val == 1;
-}
-#else
-static inline bool nvme_acpi_storage_d3(struct pci_dev *dev)
-{
- return false;
-}
-#endif /* CONFIG_ACPI */
-
static void nvme_async_probe(void *data, async_cookie_t cookie)
{
struct nvme_dev *dev = data;
@@ -2925,7 +2917,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
quirks |= check_vendor_combination_bug(pdev);
- if (!noacpi && nvme_acpi_storage_d3(pdev)) {
+ if (!noacpi && acpi_storage_d3(&pdev->dev)) {
/*
* Some systems use a bios work around to ask for D3 on
* platforms that support kernel managed suspend.
@@ -3020,7 +3012,6 @@ static void nvme_remove(struct pci_dev *pdev)
if (!pci_device_is_present(pdev)) {
nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DEAD);
nvme_dev_disable(dev, true);
- nvme_dev_remove_admin(dev);
}
flush_work(&dev->ctrl.reset_work);
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index 4697a94c0945..7f6b3a991501 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -680,11 +680,10 @@ static void nvme_rdma_stop_io_queues(struct nvme_rdma_ctrl *ctrl)
static int nvme_rdma_start_queue(struct nvme_rdma_ctrl *ctrl, int idx)
{
struct nvme_rdma_queue *queue = &ctrl->queues[idx];
- bool poll = nvme_rdma_poll_queue(queue);
int ret;
if (idx)
- ret = nvmf_connect_io_queue(&ctrl->ctrl, idx, poll);
+ ret = nvmf_connect_io_queue(&ctrl->ctrl, idx);
else
ret = nvmf_connect_admin_queue(&ctrl->ctrl);
@@ -1088,7 +1087,7 @@ static void nvme_rdma_reconnect_or_remove(struct nvme_rdma_ctrl *ctrl)
static int nvme_rdma_setup_ctrl(struct nvme_rdma_ctrl *ctrl, bool new)
{
- int ret = -EINVAL;
+ int ret;
bool changed;
ret = nvme_rdma_configure_admin_queue(ctrl, new);
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 34f4b3402f7c..8cb15ee5b249 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -1455,6 +1455,20 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
}
}
+ if (nctrl->opts->mask & NVMF_OPT_HOST_IFACE) {
+ char *iface = nctrl->opts->host_iface;
+ sockptr_t optval = KERNEL_SOCKPTR(iface);
+
+ ret = sock_setsockopt(queue->sock, SOL_SOCKET, SO_BINDTODEVICE,
+ optval, strlen(iface));
+ if (ret) {
+ dev_err(nctrl->device,
+ "failed to bind to interface %s queue %d err %d\n",
+ iface, qid, ret);
+ goto err_sock;
+ }
+ }
+
queue->hdr_digest = nctrl->opts->hdr_digest;
queue->data_digest = nctrl->opts->data_digest;
if (queue->hdr_digest || queue->data_digest) {
@@ -1559,7 +1573,7 @@ static int nvme_tcp_start_queue(struct nvme_ctrl *nctrl, int idx)
int ret;
if (idx)
- ret = nvmf_connect_io_queue(nctrl, idx, false);
+ ret = nvmf_connect_io_queue(nctrl, idx);
else
ret = nvmf_connect_admin_queue(nctrl);
@@ -1973,11 +1987,13 @@ static int nvme_tcp_setup_ctrl(struct nvme_ctrl *ctrl, bool new)
return ret;
if (ctrl->icdoff) {
+ ret = -EOPNOTSUPP;
dev_err(ctrl->device, "icdoff is not supported!\n");
goto destroy_admin;
}
- if (!(ctrl->sgls & ((1 << 0) | (1 << 1)))) {
+ if (!nvme_ctrl_sgl_supported(ctrl)) {
+ ret = -EOPNOTSUPP;
dev_err(ctrl->device, "Mandatory sgls are not supported!\n");
goto destroy_admin;
}
@@ -2515,6 +2531,15 @@ static struct nvme_ctrl *nvme_tcp_create_ctrl(struct device *dev,
}
}
+ if (opts->mask & NVMF_OPT_HOST_IFACE) {
+ if (!__dev_get_by_name(&init_net, opts->host_iface)) {
+ pr_err("invalid interface passed: %s\n",
+ opts->host_iface);
+ ret = -ENODEV;
+ goto out_free_ctrl;
+ }
+ }
+
if (!opts->duplicate_connect && nvme_tcp_existing_controller(opts)) {
ret = -EALREADY;
goto out_free_ctrl;
@@ -2571,7 +2596,7 @@ static struct nvmf_transport_ops nvme_tcp_transport = {
NVMF_OPT_HOST_TRADDR | NVMF_OPT_CTRL_LOSS_TMO |
NVMF_OPT_HDR_DIGEST | NVMF_OPT_DATA_DIGEST |
NVMF_OPT_NR_WRITE_QUEUES | NVMF_OPT_NR_POLL_QUEUES |
- NVMF_OPT_TOS,
+ NVMF_OPT_TOS | NVMF_OPT_HOST_IFACE,
.create_ctrl = nvme_tcp_create_ctrl,
};
diff --git a/drivers/nvme/host/zns.c b/drivers/nvme/host/zns.c
index 475dd45c3db4..d95010481fce 100644
--- a/drivers/nvme/host/zns.c
+++ b/drivers/nvme/host/zns.c
@@ -171,8 +171,8 @@ static int nvme_zone_parse_entry(struct nvme_ns *ns,
return cb(&zone, idx, data);
}
-static int nvme_ns_report_zones(struct nvme_ns *ns, sector_t sector,
- unsigned int nr_zones, report_zones_cb cb, void *data)
+int nvme_ns_report_zones(struct nvme_ns *ns, sector_t sector,
+ unsigned int nr_zones, report_zones_cb cb, void *data)
{
struct nvme_zone_report *report;
struct nvme_command c = { };
@@ -180,6 +180,9 @@ static int nvme_ns_report_zones(struct nvme_ns *ns, sector_t sector,
unsigned int nz, i;
size_t buflen;
+ if (ns->head->ids.csi != NVME_CSI_ZNS)
+ return -EINVAL;
+
report = nvme_zns_alloc_report_buffer(ns, nr_zones, &buflen);
if (!report)
return -ENOMEM;
@@ -227,26 +230,6 @@ out_free:
return ret;
}
-int nvme_report_zones(struct gendisk *disk, sector_t sector,
- unsigned int nr_zones, report_zones_cb cb, void *data)
-{
- struct nvme_ns_head *head = NULL;
- struct nvme_ns *ns;
- int srcu_idx, ret;
-
- ns = nvme_get_ns_from_disk(disk, &head, &srcu_idx);
- if (unlikely(!ns))
- return -EWOULDBLOCK;
-
- if (ns->head->ids.csi == NVME_CSI_ZNS)
- ret = nvme_ns_report_zones(ns, sector, nr_zones, cb, data);
- else
- ret = -EINVAL;
- nvme_put_ns_from_disk(head, srcu_idx);
-
- return ret;
-}
-
blk_status_t nvme_setup_zone_mgmt_send(struct nvme_ns *ns, struct request *req,
struct nvme_command *c, enum nvme_zone_mgmt_action action)
{
diff --git a/drivers/nvme/target/Makefile b/drivers/nvme/target/Makefile
index ebf91fc4c72e..9837e580fa7e 100644
--- a/drivers/nvme/target/Makefile
+++ b/drivers/nvme/target/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_NVME_TARGET_TCP) += nvmet-tcp.o
nvmet-y += core.o configfs.o admin-cmd.o fabrics-cmd.o \
discovery.o io-cmd-file.o io-cmd-bdev.o
nvmet-$(CONFIG_NVME_TARGET_PASSTHRU) += passthru.o
+nvmet-$(CONFIG_BLK_DEV_ZONED) += zns.o
nvme-loop-y += loop.o
nvmet-rdma-y += rdma.o
nvmet-fc-y += fc.o
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index dcd49a72f2f3..0cb98f2bbc8c 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -162,15 +162,8 @@ out:
nvmet_req_complete(req, status);
}
-static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
+static void nvmet_get_cmd_effects_nvm(struct nvme_effects_log *log)
{
- u16 status = NVME_SC_INTERNAL;
- struct nvme_effects_log *log;
-
- log = kzalloc(sizeof(*log), GFP_KERNEL);
- if (!log)
- goto out;
-
log->acs[nvme_admin_get_log_page] = cpu_to_le32(1 << 0);
log->acs[nvme_admin_identify] = cpu_to_le32(1 << 0);
log->acs[nvme_admin_abort_cmd] = cpu_to_le32(1 << 0);
@@ -184,9 +177,45 @@ static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
log->iocs[nvme_cmd_flush] = cpu_to_le32(1 << 0);
log->iocs[nvme_cmd_dsm] = cpu_to_le32(1 << 0);
log->iocs[nvme_cmd_write_zeroes] = cpu_to_le32(1 << 0);
+}
- status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log));
+static void nvmet_get_cmd_effects_zns(struct nvme_effects_log *log)
+{
+ log->iocs[nvme_cmd_zone_append] = cpu_to_le32(1 << 0);
+ log->iocs[nvme_cmd_zone_mgmt_send] = cpu_to_le32(1 << 0);
+ log->iocs[nvme_cmd_zone_mgmt_recv] = cpu_to_le32(1 << 0);
+}
+
+static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
+{
+ struct nvme_effects_log *log;
+ u16 status = NVME_SC_SUCCESS;
+ log = kzalloc(sizeof(*log), GFP_KERNEL);
+ if (!log) {
+ status = NVME_SC_INTERNAL;
+ goto out;
+ }
+
+ switch (req->cmd->get_log_page.csi) {
+ case NVME_CSI_NVM:
+ nvmet_get_cmd_effects_nvm(log);
+ break;
+ case NVME_CSI_ZNS:
+ if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
+ status = NVME_SC_INVALID_IO_CMD_SET;
+ goto free;
+ }
+ nvmet_get_cmd_effects_nvm(log);
+ nvmet_get_cmd_effects_zns(log);
+ break;
+ default:
+ status = NVME_SC_INVALID_LOG_PAGE;
+ goto free;
+ }
+
+ status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log));
+free:
kfree(log);
out:
nvmet_req_complete(req, status);
@@ -313,22 +342,6 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req)
nvmet_req_complete(req, NVME_SC_INVALID_FIELD | NVME_SC_DNR);
}
-static u16 nvmet_set_model_number(struct nvmet_subsys *subsys)
-{
- u16 status = 0;
-
- mutex_lock(&subsys->lock);
- if (!subsys->model_number) {
- subsys->model_number =
- kstrdup(NVMET_DEFAULT_CTRL_MODEL, GFP_KERNEL);
- if (!subsys->model_number)
- status = NVME_SC_INTERNAL;
- }
- mutex_unlock(&subsys->lock);
-
- return status;
-}
-
static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
{
struct nvmet_ctrl *ctrl = req->sq->ctrl;
@@ -337,14 +350,10 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
u32 cmd_capsule_size;
u16 status = 0;
- /*
- * If there is no model number yet, set it now. It will then remain
- * stable for the life time of the subsystem.
- */
- if (!subsys->model_number) {
- status = nvmet_set_model_number(subsys);
- if (status)
- goto out;
+ if (!subsys->subsys_discovered) {
+ mutex_lock(&subsys->lock);
+ subsys->subsys_discovered = true;
+ mutex_unlock(&subsys->lock);
}
id = kzalloc(sizeof(*id), GFP_KERNEL);
@@ -357,9 +366,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
id->vid = 0;
id->ssvid = 0;
- memset(id->sn, ' ', sizeof(id->sn));
- bin2hex(id->sn, &ctrl->subsys->serial,
- min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2));
+ memcpy(id->sn, ctrl->subsys->serial, NVMET_SN_MAX_SIZE);
memcpy_and_pad(id->mn, sizeof(id->mn), subsys->model_number,
strlen(subsys->model_number), ' ');
memcpy_and_pad(id->fr, sizeof(id->fr),
@@ -415,7 +422,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
/* no enforcement soft-limit for maxcmd - pick arbitrary high value */
id->maxcmd = cpu_to_le16(NVMET_MAX_CMD);
- id->nn = cpu_to_le32(ctrl->subsys->max_nsid);
+ id->nn = cpu_to_le32(NVMET_MAX_NAMESPACES);
id->mnan = cpu_to_le32(NVMET_MAX_NAMESPACES);
id->oncs = cpu_to_le16(NVME_CTRL_ONCS_DSM |
NVME_CTRL_ONCS_WRITE_ZEROES);
@@ -635,6 +642,12 @@ static void nvmet_execute_identify_desclist(struct nvmet_req *req)
goto out;
}
+ status = nvmet_copy_ns_identifier(req, NVME_NIDT_CSI,
+ NVME_NIDT_CSI_LEN,
+ &req->ns->csi, &off);
+ if (status)
+ goto out;
+
if (sg_zero_buffer(req->sg, req->sg_cnt, NVME_IDENTIFY_DATA_SIZE - off,
off) != NVME_IDENTIFY_DATA_SIZE - off)
status = NVME_SC_INTERNAL | NVME_SC_DNR;
@@ -643,6 +656,23 @@ out:
nvmet_req_complete(req, status);
}
+static bool nvmet_handle_identify_desclist(struct nvmet_req *req)
+{
+ switch (req->cmd->identify.csi) {
+ case NVME_CSI_NVM:
+ nvmet_execute_identify_desclist(req);
+ return true;
+ case NVME_CSI_ZNS:
+ if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
+ nvmet_execute_identify_desclist(req);
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
static void nvmet_execute_identify(struct nvmet_req *req)
{
if (!nvmet_check_transfer_len(req, NVME_IDENTIFY_DATA_SIZE))
@@ -650,19 +680,54 @@ static void nvmet_execute_identify(struct nvmet_req *req)
switch (req->cmd->identify.cns) {
case NVME_ID_CNS_NS:
- return nvmet_execute_identify_ns(req);
+ switch (req->cmd->identify.csi) {
+ case NVME_CSI_NVM:
+ return nvmet_execute_identify_ns(req);
+ default:
+ break;
+ }
+ break;
+ case NVME_ID_CNS_CS_NS:
+ if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
+ switch (req->cmd->identify.csi) {
+ case NVME_CSI_ZNS:
+ return nvmet_execute_identify_cns_cs_ns(req);
+ default:
+ break;
+ }
+ }
+ break;
case NVME_ID_CNS_CTRL:
- return nvmet_execute_identify_ctrl(req);
+ switch (req->cmd->identify.csi) {
+ case NVME_CSI_NVM:
+ return nvmet_execute_identify_ctrl(req);
+ }
+ break;
+ case NVME_ID_CNS_CS_CTRL:
+ if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
+ switch (req->cmd->identify.csi) {
+ case NVME_CSI_ZNS:
+ return nvmet_execute_identify_cns_cs_ctrl(req);
+ default:
+ break;
+ }
+ }
+ break;
case NVME_ID_CNS_NS_ACTIVE_LIST:
- return nvmet_execute_identify_nslist(req);
+ switch (req->cmd->identify.csi) {
+ case NVME_CSI_NVM:
+ return nvmet_execute_identify_nslist(req);
+ default:
+ break;
+ }
+ break;
case NVME_ID_CNS_NS_DESC_LIST:
- return nvmet_execute_identify_desclist(req);
+ if (nvmet_handle_identify_desclist(req) == true)
+ return;
+ break;
}
- pr_debug("unhandled identify cns %d on qid %d\n",
- req->cmd->identify.cns, req->sq->qid);
- req->error_loc = offsetof(struct nvme_identify, cns);
- nvmet_req_complete(req, NVME_SC_INVALID_FIELD | NVME_SC_DNR);
+ nvmet_req_cns_error_complete(req);
}
/*
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index 65a0cf99f557..273555127188 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -1007,13 +1007,26 @@ static ssize_t nvmet_subsys_attr_version_show(struct config_item *item,
NVME_MINOR(subsys->ver));
}
-static ssize_t nvmet_subsys_attr_version_store(struct config_item *item,
- const char *page, size_t count)
+static ssize_t
+nvmet_subsys_attr_version_store_locked(struct nvmet_subsys *subsys,
+ const char *page, size_t count)
{
- struct nvmet_subsys *subsys = to_subsys(item);
int major, minor, tertiary = 0;
int ret;
+ if (subsys->subsys_discovered) {
+ if (NVME_TERTIARY(subsys->ver))
+ pr_err("Can't set version number. %llu.%llu.%llu is already assigned\n",
+ NVME_MAJOR(subsys->ver),
+ NVME_MINOR(subsys->ver),
+ NVME_TERTIARY(subsys->ver));
+ else
+ pr_err("Can't set version number. %llu.%llu is already assigned\n",
+ NVME_MAJOR(subsys->ver),
+ NVME_MINOR(subsys->ver));
+ return -EINVAL;
+ }
+
/* passthru subsystems use the underlying controller's version */
if (nvmet_passthru_ctrl(subsys))
return -EINVAL;
@@ -1022,35 +1035,84 @@ static ssize_t nvmet_subsys_attr_version_store(struct config_item *item,
if (ret != 2 && ret != 3)
return -EINVAL;
- down_write(&nvmet_config_sem);
subsys->ver = NVME_VS(major, minor, tertiary);
- up_write(&nvmet_config_sem);
return count;
}
+
+static ssize_t nvmet_subsys_attr_version_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct nvmet_subsys *subsys = to_subsys(item);
+ ssize_t ret;
+
+ down_write(&nvmet_config_sem);
+ mutex_lock(&subsys->lock);
+ ret = nvmet_subsys_attr_version_store_locked(subsys, page, count);
+ mutex_unlock(&subsys->lock);
+ up_write(&nvmet_config_sem);
+
+ return ret;
+}
CONFIGFS_ATTR(nvmet_subsys_, attr_version);
+/* See Section 1.5 of NVMe 1.4 */
+static bool nvmet_is_ascii(const char c)
+{
+ return c >= 0x20 && c <= 0x7e;
+}
+
static ssize_t nvmet_subsys_attr_serial_show(struct config_item *item,
char *page)
{
struct nvmet_subsys *subsys = to_subsys(item);
- return snprintf(page, PAGE_SIZE, "%llx\n", subsys->serial);
+ return snprintf(page, PAGE_SIZE, "%s\n", subsys->serial);
}
-static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item,
- const char *page, size_t count)
+static ssize_t
+nvmet_subsys_attr_serial_store_locked(struct nvmet_subsys *subsys,
+ const char *page, size_t count)
{
- u64 serial;
+ int pos, len = strcspn(page, "\n");
- if (sscanf(page, "%llx\n", &serial) != 1)
+ if (subsys->subsys_discovered) {
+ pr_err("Can't set serial number. %s is already assigned\n",
+ subsys->serial);
return -EINVAL;
+ }
+
+ if (!len || len > NVMET_SN_MAX_SIZE) {
+ pr_err("Serial Number can not be empty or exceed %d Bytes\n",
+ NVMET_SN_MAX_SIZE);
+ return -EINVAL;
+ }
+
+ for (pos = 0; pos < len; pos++) {
+ if (!nvmet_is_ascii(page[pos])) {
+ pr_err("Serial Number must contain only ASCII strings\n");
+ return -EINVAL;
+ }
+ }
+
+ memcpy_and_pad(subsys->serial, NVMET_SN_MAX_SIZE, page, len, ' ');
+
+ return count;
+}
+
+static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct nvmet_subsys *subsys = to_subsys(item);
+ ssize_t ret;
down_write(&nvmet_config_sem);
- to_subsys(item)->serial = serial;
+ mutex_lock(&subsys->lock);
+ ret = nvmet_subsys_attr_serial_store_locked(subsys, page, count);
+ mutex_unlock(&subsys->lock);
up_write(&nvmet_config_sem);
- return count;
+ return ret;
}
CONFIGFS_ATTR(nvmet_subsys_, attr_serial);
@@ -1118,20 +1180,8 @@ static ssize_t nvmet_subsys_attr_model_show(struct config_item *item,
char *page)
{
struct nvmet_subsys *subsys = to_subsys(item);
- int ret;
-
- mutex_lock(&subsys->lock);
- ret = snprintf(page, PAGE_SIZE, "%s\n", subsys->model_number ?
- subsys->model_number : NVMET_DEFAULT_CTRL_MODEL);
- mutex_unlock(&subsys->lock);
-
- return ret;
-}
-/* See Section 1.5 of NVMe 1.4 */
-static bool nvmet_is_ascii(const char c)
-{
- return c >= 0x20 && c <= 0x7e;
+ return snprintf(page, PAGE_SIZE, "%s\n", subsys->model_number);
}
static ssize_t nvmet_subsys_attr_model_store_locked(struct nvmet_subsys *subsys,
@@ -1139,7 +1189,7 @@ static ssize_t nvmet_subsys_attr_model_store_locked(struct nvmet_subsys *subsys,
{
int pos = 0, len;
- if (subsys->model_number) {
+ if (subsys->subsys_discovered) {
pr_err("Can't set model number. %s is already assigned\n",
subsys->model_number);
return -EINVAL;
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index b20b8d0a1144..ac7210a3ea1c 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -16,6 +16,7 @@
#include "nvmet.h"
struct workqueue_struct *buffered_io_wq;
+struct workqueue_struct *zbd_wq;
static const struct nvmet_fabrics_ops *nvmet_transports[NVMF_TRTYPE_MAX];
static DEFINE_IDA(cntlid_ida);
@@ -43,43 +44,34 @@ DECLARE_RWSEM(nvmet_ana_sem);
inline u16 errno_to_nvme_status(struct nvmet_req *req, int errno)
{
- u16 status;
-
switch (errno) {
case 0:
- status = NVME_SC_SUCCESS;
- break;
+ return NVME_SC_SUCCESS;
case -ENOSPC:
req->error_loc = offsetof(struct nvme_rw_command, length);
- status = NVME_SC_CAP_EXCEEDED | NVME_SC_DNR;
- break;
+ return NVME_SC_CAP_EXCEEDED | NVME_SC_DNR;
case -EREMOTEIO:
req->error_loc = offsetof(struct nvme_rw_command, slba);
- status = NVME_SC_LBA_RANGE | NVME_SC_DNR;
- break;
+ return NVME_SC_LBA_RANGE | NVME_SC_DNR;
case -EOPNOTSUPP:
req->error_loc = offsetof(struct nvme_common_command, opcode);
switch (req->cmd->common.opcode) {
case nvme_cmd_dsm:
case nvme_cmd_write_zeroes:
- status = NVME_SC_ONCS_NOT_SUPPORTED | NVME_SC_DNR;
- break;
+ return NVME_SC_ONCS_NOT_SUPPORTED | NVME_SC_DNR;
default:
- status = NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
+ return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
}
break;
case -ENODATA:
req->error_loc = offsetof(struct nvme_rw_command, nsid);
- status = NVME_SC_ACCESS_DENIED;
- break;
+ return NVME_SC_ACCESS_DENIED;
case -EIO:
fallthrough;
default:
req->error_loc = offsetof(struct nvme_common_command, opcode);
- status = NVME_SC_INTERNAL | NVME_SC_DNR;
+ return NVME_SC_INTERNAL | NVME_SC_DNR;
}
-
- return status;
}
u16 nvmet_report_invalid_opcode(struct nvmet_req *req)
@@ -122,11 +114,11 @@ u16 nvmet_zero_sgl(struct nvmet_req *req, off_t off, size_t len)
return 0;
}
-static unsigned int nvmet_max_nsid(struct nvmet_subsys *subsys)
+static u32 nvmet_max_nsid(struct nvmet_subsys *subsys)
{
- unsigned long nsid = 0;
struct nvmet_ns *cur;
unsigned long idx;
+ u32 nsid = 0;
xa_for_each(&subsys->namespaces, idx, cur)
nsid = cur->nsid;
@@ -141,14 +133,13 @@ static u32 nvmet_async_event_result(struct nvmet_async_event *aen)
static void nvmet_async_events_failall(struct nvmet_ctrl *ctrl)
{
- u16 status = NVME_SC_INTERNAL | NVME_SC_DNR;
struct nvmet_req *req;
mutex_lock(&ctrl->lock);
while (ctrl->nr_async_event_cmds) {
req = ctrl->async_event_cmds[--ctrl->nr_async_event_cmds];
mutex_unlock(&ctrl->lock);
- nvmet_req_complete(req, status);
+ nvmet_req_complete(req, NVME_SC_INTERNAL | NVME_SC_DNR);
mutex_lock(&ctrl->lock);
}
mutex_unlock(&ctrl->lock);
@@ -412,7 +403,6 @@ void nvmet_start_keep_alive_timer(struct nvmet_ctrl *ctrl)
pr_debug("ctrl %d start keep-alive timer for %d secs\n",
ctrl->cntlid, ctrl->kato);
- INIT_DELAYED_WORK(&ctrl->ka_work, nvmet_keep_alive_timer);
schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ);
}
@@ -693,6 +683,7 @@ struct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid)
uuid_gen(&ns->uuid);
ns->buffered_io = false;
+ ns->csi = NVME_CSI_NVM;
return ns;
}
@@ -895,10 +886,18 @@ static u16 nvmet_parse_io_cmd(struct nvmet_req *req)
return ret;
}
- if (req->ns->file)
- return nvmet_file_parse_io_cmd(req);
-
- return nvmet_bdev_parse_io_cmd(req);
+ switch (req->ns->csi) {
+ case NVME_CSI_NVM:
+ if (req->ns->file)
+ return nvmet_file_parse_io_cmd(req);
+ return nvmet_bdev_parse_io_cmd(req);
+ case NVME_CSI_ZNS:
+ if (IS_ENABLED(CONFIG_BLK_DEV_ZONED))
+ return nvmet_bdev_zns_parse_io_cmd(req);
+ return NVME_SC_INVALID_IO_CMD_SET;
+ default:
+ return NVME_SC_INVALID_IO_CMD_SET;
+ }
}
bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq,
@@ -1119,6 +1118,17 @@ static inline u8 nvmet_cc_iocqes(u32 cc)
return (cc >> NVME_CC_IOCQES_SHIFT) & 0xf;
}
+static inline bool nvmet_css_supported(u8 cc_css)
+{
+ switch (cc_css <<= NVME_CC_CSS_SHIFT) {
+ case NVME_CC_CSS_NVM:
+ case NVME_CC_CSS_CSI:
+ return true;
+ default:
+ return false;
+ }
+}
+
static void nvmet_start_ctrl(struct nvmet_ctrl *ctrl)
{
lockdep_assert_held(&ctrl->lock);
@@ -1138,7 +1148,7 @@ static void nvmet_start_ctrl(struct nvmet_ctrl *ctrl)
if (nvmet_cc_mps(ctrl->cc) != 0 ||
nvmet_cc_ams(ctrl->cc) != 0 ||
- nvmet_cc_css(ctrl->cc) != 0) {
+ !nvmet_css_supported(nvmet_cc_css(ctrl->cc))) {
ctrl->csts = NVME_CSTS_CFS;
return;
}
@@ -1189,6 +1199,8 @@ static void nvmet_init_cap(struct nvmet_ctrl *ctrl)
{
/* command sets supported: NVMe command set: */
ctrl->cap = (1ULL << 37);
+ /* Controller supports one or more I/O Command Sets */
+ ctrl->cap |= (1ULL << 43);
/* CC.EN timeout in 500msec units: */
ctrl->cap |= (15ULL << 24);
/* maximum queue entries supported: */
@@ -1358,6 +1370,7 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
INIT_LIST_HEAD(&ctrl->async_events);
INIT_RADIX_TREE(&ctrl->p2p_ns_map, GFP_KERNEL);
INIT_WORK(&ctrl->fatal_err_work, nvmet_fatal_error_handler);
+ INIT_DELAYED_WORK(&ctrl->ka_work, nvmet_keep_alive_timer);
memcpy(ctrl->subsysnqn, subsysnqn, NVMF_NQN_SIZE);
memcpy(ctrl->hostnqn, hostnqn, NVMF_NQN_SIZE);
@@ -1499,6 +1512,8 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
enum nvme_subsys_type type)
{
struct nvmet_subsys *subsys;
+ char serial[NVMET_SN_MAX_SIZE / 2];
+ int ret;
subsys = kzalloc(sizeof(*subsys), GFP_KERNEL);
if (!subsys)
@@ -1506,7 +1521,14 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
subsys->ver = NVMET_DEFAULT_VS;
/* generate a random serial number as our controllers are ephemeral: */
- get_random_bytes(&subsys->serial, sizeof(subsys->serial));
+ get_random_bytes(&serial, sizeof(serial));
+ bin2hex(subsys->serial, &serial, sizeof(serial));
+
+ subsys->model_number = kstrdup(NVMET_DEFAULT_CTRL_MODEL, GFP_KERNEL);
+ if (!subsys->model_number) {
+ ret = -ENOMEM;
+ goto free_subsys;
+ }
switch (type) {
case NVME_NQN_NVME:
@@ -1517,15 +1539,15 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
break;
default:
pr_err("%s: Unknown Subsystem type - %d\n", __func__, type);
- kfree(subsys);
- return ERR_PTR(-EINVAL);
+ ret = -EINVAL;
+ goto free_mn;
}
subsys->type = type;
subsys->subsysnqn = kstrndup(subsysnqn, NVMF_NQN_SIZE,
GFP_KERNEL);
if (!subsys->subsysnqn) {
- kfree(subsys);
- return ERR_PTR(-ENOMEM);
+ ret = -ENOMEM;
+ goto free_mn;
}
subsys->cntlid_min = NVME_CNTLID_MIN;
subsys->cntlid_max = NVME_CNTLID_MAX;
@@ -1537,6 +1559,12 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
INIT_LIST_HEAD(&subsys->hosts);
return subsys;
+
+free_mn:
+ kfree(subsys->model_number);
+free_subsys:
+ kfree(subsys);
+ return ERR_PTR(ret);
}
static void nvmet_subsys_free(struct kref *ref)
@@ -1575,11 +1603,15 @@ static int __init nvmet_init(void)
nvmet_ana_group_enabled[NVMET_DEFAULT_ANA_GRPID] = 1;
+ zbd_wq = alloc_workqueue("nvmet-zbd-wq", WQ_MEM_RECLAIM, 0);
+ if (!zbd_wq)
+ return -ENOMEM;
+
buffered_io_wq = alloc_workqueue("nvmet-buffered-io-wq",
WQ_MEM_RECLAIM, 0);
if (!buffered_io_wq) {
error = -ENOMEM;
- goto out;
+ goto out_free_zbd_work_queue;
}
error = nvmet_init_discovery();
@@ -1595,7 +1627,8 @@ out_exit_discovery:
nvmet_exit_discovery();
out_free_work_queue:
destroy_workqueue(buffered_io_wq);
-out:
+out_free_zbd_work_queue:
+ destroy_workqueue(zbd_wq);
return error;
}
@@ -1605,6 +1638,7 @@ static void __exit nvmet_exit(void)
nvmet_exit_discovery();
ida_destroy(&cntlid_ida);
destroy_workqueue(buffered_io_wq);
+ destroy_workqueue(zbd_wq);
BUILD_BUG_ON(sizeof(struct nvmf_disc_rsp_page_entry) != 1024);
BUILD_BUG_ON(sizeof(struct nvmf_disc_rsp_page_hdr) != 1024);
diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c
index fc3645fc2c24..7aa62bc6ae84 100644
--- a/drivers/nvme/target/discovery.c
+++ b/drivers/nvme/target/discovery.c
@@ -244,7 +244,6 @@ static void nvmet_execute_disc_identify(struct nvmet_req *req)
{
struct nvmet_ctrl *ctrl = req->sq->ctrl;
struct nvme_id_ctrl *id;
- const char model[] = "Linux";
u16 status = 0;
if (!nvmet_check_transfer_len(req, NVME_IDENTIFY_DATA_SIZE))
@@ -262,11 +261,10 @@ static void nvmet_execute_disc_identify(struct nvmet_req *req)
goto out;
}
- memset(id->sn, ' ', sizeof(id->sn));
- bin2hex(id->sn, &ctrl->subsys->serial,
- min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2));
+ memcpy(id->sn, ctrl->subsys->serial, NVMET_SN_MAX_SIZE);
memset(id->fr, ' ', sizeof(id->fr));
- memcpy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1, ' ');
+ memcpy_and_pad(id->mn, sizeof(id->mn), ctrl->subsys->model_number,
+ strlen(ctrl->subsys->model_number), ' ');
memcpy_and_pad(id->fr, sizeof(id->fr),
UTS_RELEASE, strlen(UTS_RELEASE), ' ');
diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c
index 19e113240fff..22b5108168a6 100644
--- a/drivers/nvme/target/fc.c
+++ b/drivers/nvme/target/fc.c
@@ -2511,13 +2511,6 @@ nvmet_fc_handle_fcp_rqst(struct nvmet_fc_tgtport *tgtport,
int ret;
/*
- * if there is no nvmet mapping to the targetport there
- * shouldn't be requests. just terminate them.
- */
- if (!tgtport->pe)
- goto transport_error;
-
- /*
* Fused commands are currently not supported in the linux
* implementation.
*
@@ -2544,7 +2537,8 @@ nvmet_fc_handle_fcp_rqst(struct nvmet_fc_tgtport *tgtport,
fod->req.cmd = &fod->cmdiubuf.sqe;
fod->req.cqe = &fod->rspiubuf.cqe;
- fod->req.port = tgtport->pe->port;
+ if (tgtport->pe)
+ fod->req.port = tgtport->pe->port;
/* clear any response payload */
memset(&fod->rspiubuf, 0, sizeof(fod->rspiubuf));
diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 429263ca9b97..0fc2781ab970 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -47,6 +47,14 @@ void nvmet_bdev_set_limits(struct block_device *bdev, struct nvme_id_ns *id)
id->nows = to0based(ql->io_opt / ql->logical_block_size);
}
+void nvmet_bdev_ns_disable(struct nvmet_ns *ns)
+{
+ if (ns->bdev) {
+ blkdev_put(ns->bdev, FMODE_WRITE | FMODE_READ);
+ ns->bdev = NULL;
+ }
+}
+
static void nvmet_bdev_ns_enable_integrity(struct nvmet_ns *ns)
{
struct blk_integrity *bi = bdev_get_integrity(ns->bdev);
@@ -86,15 +94,15 @@ int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY_T10))
nvmet_bdev_ns_enable_integrity(ns);
- return 0;
-}
-
-void nvmet_bdev_ns_disable(struct nvmet_ns *ns)
-{
- if (ns->bdev) {
- blkdev_put(ns->bdev, FMODE_WRITE | FMODE_READ);
- ns->bdev = NULL;
+ if (bdev_is_zoned(ns->bdev)) {
+ if (!nvmet_bdev_zns_enable(ns)) {
+ nvmet_bdev_ns_disable(ns);
+ return -EINVAL;
+ }
+ ns->csi = NVME_CSI_ZNS;
}
+
+ return 0;
}
void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns)
@@ -102,7 +110,7 @@ void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns)
ns->size = i_size_read(ns->bdev->bd_inode);
}
-static u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts)
+u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts)
{
u16 status = NVME_SC_SUCCESS;
@@ -164,8 +172,7 @@ static void nvmet_bio_done(struct bio *bio)
struct nvmet_req *req = bio->bi_private;
nvmet_req_complete(req, blk_to_nvme_status(req, bio->bi_status));
- if (bio != &req->b.inline_bio)
- bio_put(bio);
+ nvmet_req_bio_put(req, bio);
}
#ifdef CONFIG_BLK_DEV_INTEGRITY
@@ -174,11 +181,10 @@ static int nvmet_bdev_alloc_bip(struct nvmet_req *req, struct bio *bio,
{
struct blk_integrity *bi;
struct bio_integrity_payload *bip;
- struct block_device *bdev = req->ns->bdev;
int rc;
size_t resid, len;
- bi = bdev_get_integrity(bdev);
+ bi = bdev_get_integrity(req->ns->bdev);
if (unlikely(!bi)) {
pr_err("Unable to locate bio_integrity\n");
return -ENODEV;
@@ -430,9 +436,7 @@ static void nvmet_bdev_execute_write_zeroes(struct nvmet_req *req)
u16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req)
{
- struct nvme_command *cmd = req->cmd;
-
- switch (cmd->common.opcode) {
+ switch (req->cmd->common.opcode) {
case nvme_cmd_read:
case nvme_cmd_write:
req->execute = nvmet_bdev_execute_rw;
diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c
index 7fdbdc496597..1dd1a0fe2e81 100644
--- a/drivers/nvme/target/io-cmd-file.c
+++ b/drivers/nvme/target/io-cmd-file.c
@@ -385,9 +385,7 @@ static void nvmet_file_execute_write_zeroes(struct nvmet_req *req)
u16 nvmet_file_parse_io_cmd(struct nvmet_req *req)
{
- struct nvme_command *cmd = req->cmd;
-
- switch (cmd->common.opcode) {
+ switch (req->cmd->common.opcode) {
case nvme_cmd_read:
case nvme_cmd_write:
req->execute = nvmet_file_execute_rw;
diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c
index a5c4a1865026..3a17a7e26bbf 100644
--- a/drivers/nvme/target/loop.c
+++ b/drivers/nvme/target/loop.c
@@ -337,7 +337,7 @@ static int nvme_loop_connect_io_queues(struct nvme_loop_ctrl *ctrl)
int i, ret;
for (i = 1; i < ctrl->ctrl.queue_count; i++) {
- ret = nvmf_connect_io_queue(&ctrl->ctrl, i, false);
+ ret = nvmf_connect_io_queue(&ctrl->ctrl, i);
if (ret)
return ret;
set_bit(NVME_LOOP_Q_LIVE, &ctrl->queues[i].flags);
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 53aea9a8056e..06dd3d537f07 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -28,6 +28,7 @@
#define NVMET_NO_ERROR_LOC ((u16)-1)
#define NVMET_DEFAULT_CTRL_MODEL "Linux"
#define NVMET_MN_MAX_SIZE 40
+#define NVMET_SN_MAX_SIZE 20
/*
* Supported optional AENs:
@@ -82,6 +83,7 @@ struct nvmet_ns {
struct pci_dev *p2p_dev;
int pi_type;
int metadata_size;
+ u8 csi;
};
static inline struct nvmet_ns *to_nvmet_ns(struct config_item *item)
@@ -217,7 +219,7 @@ struct nvmet_subsys {
struct xarray namespaces;
unsigned int nr_namespaces;
- unsigned int max_nsid;
+ u32 max_nsid;
u16 cntlid_min;
u16 cntlid_max;
@@ -229,7 +231,8 @@ struct nvmet_subsys {
u16 max_qid;
u64 ver;
- u64 serial;
+ char serial[NVMET_SN_MAX_SIZE];
+ bool subsys_discovered;
char *subsysnqn;
bool pi_support;
@@ -247,6 +250,10 @@ struct nvmet_subsys {
unsigned int admin_timeout;
unsigned int io_timeout;
#endif /* CONFIG_NVME_TARGET_PASSTHRU */
+
+#ifdef CONFIG_BLK_DEV_ZONED
+ u8 zasl;
+#endif /* CONFIG_BLK_DEV_ZONED */
};
static inline struct nvmet_subsys *to_subsys(struct config_item *item)
@@ -332,6 +339,12 @@ struct nvmet_req {
struct work_struct work;
bool use_workqueue;
} p;
+#ifdef CONFIG_BLK_DEV_ZONED
+ struct {
+ struct bio inline_bio;
+ struct work_struct zmgmt_work;
+ } z;
+#endif /* CONFIG_BLK_DEV_ZONED */
};
int sg_cnt;
int metadata_sg_cnt;
@@ -351,6 +364,7 @@ struct nvmet_req {
};
extern struct workqueue_struct *buffered_io_wq;
+extern struct workqueue_struct *zbd_wq;
static inline void nvmet_set_result(struct nvmet_req *req, u32 result)
{
@@ -400,6 +414,7 @@ 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_bdev_zns_parse_io_cmd(struct nvmet_req *req);
u16 nvmet_parse_admin_cmd(struct nvmet_req *req);
u16 nvmet_parse_discovery_cmd(struct nvmet_req *req);
u16 nvmet_parse_fabrics_cmd(struct nvmet_req *req);
@@ -527,6 +542,14 @@ void nvmet_ns_changed(struct nvmet_subsys *subsys, u32 nsid);
void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns);
int nvmet_file_ns_revalidate(struct nvmet_ns *ns);
void nvmet_ns_revalidate(struct nvmet_ns *ns);
+u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts);
+
+bool nvmet_bdev_zns_enable(struct nvmet_ns *ns);
+void nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req);
+void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req);
+void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req);
+void nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req);
+void nvmet_bdev_execute_zone_append(struct nvmet_req *req);
static inline u32 nvmet_rw_data_len(struct nvmet_req *req)
{
@@ -622,4 +645,18 @@ static inline bool nvmet_use_inline_bvec(struct nvmet_req *req)
req->sg_cnt <= NVMET_MAX_INLINE_BIOVEC;
}
+static inline void nvmet_req_cns_error_complete(struct nvmet_req *req)
+{
+ pr_debug("unhandled identify cns %d on qid %d\n",
+ req->cmd->identify.cns, req->sq->qid);
+ req->error_loc = offsetof(struct nvme_identify, cns);
+ nvmet_req_complete(req, NVME_SC_INVALID_FIELD | NVME_SC_DNR);
+}
+
+static inline void nvmet_req_bio_put(struct nvmet_req *req, struct bio *bio)
+{
+ if (bio != &req->b.inline_bio)
+ bio_put(bio);
+}
+
#endif /* _NVMET_H */
diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c
index 39b1473f7204..225cd1ffbe45 100644
--- a/drivers/nvme/target/passthru.c
+++ b/drivers/nvme/target/passthru.c
@@ -153,11 +153,10 @@ static void nvmet_passthru_execute_cmd_work(struct work_struct *w)
{
struct nvmet_req *req = container_of(w, struct nvmet_req, p.work);
struct request *rq = req->p.rq;
- u16 status;
+ int status;
- nvme_execute_passthru_rq(rq);
+ status = nvme_execute_passthru_rq(rq);
- status = nvme_req(rq)->status;
if (status == NVME_SC_SUCCESS &&
req->cmd->common.opcode == nvme_admin_identify) {
switch (req->cmd->identify.cns) {
@@ -168,7 +167,8 @@ static void nvmet_passthru_execute_cmd_work(struct work_struct *w)
nvmet_passthru_override_id_ns(req);
break;
}
- }
+ } else if (status < 0)
+ status = NVME_SC_INTERNAL;
req->cqe->result = nvme_req(rq)->result;
nvmet_req_complete(req, status);
@@ -206,8 +206,7 @@ static int nvmet_passthru_map_sg(struct nvmet_req *req, struct request *rq)
for_each_sg(req->sg, sg, req->sg_cnt, i) {
if (bio_add_pc_page(rq->q, bio, sg_page(sg), sg->length,
sg->offset) < sg->length) {
- if (bio != &req->p.inline_bio)
- bio_put(bio);
+ nvmet_req_bio_put(req, bio);
return -EINVAL;
}
}
diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index 7d607f435e36..891174ccd44b 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -1257,7 +1257,7 @@ out_err:
static int nvmet_rdma_create_queue_ib(struct nvmet_rdma_queue *queue)
{
- struct ib_qp_init_attr qp_attr;
+ struct ib_qp_init_attr qp_attr = { };
struct nvmet_rdma_device *ndev = queue->dev;
int nr_cqe, ret, i, factor;
@@ -1275,7 +1275,6 @@ static int nvmet_rdma_create_queue_ib(struct nvmet_rdma_queue *queue)
goto out;
}
- memset(&qp_attr, 0, sizeof(qp_attr));
qp_attr.qp_context = queue;
qp_attr.event_handler = nvmet_rdma_qp_event;
qp_attr.send_cq = queue->cq;
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index d8aceef83284..07ee347ea3f3 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -1497,7 +1497,6 @@ static void nvmet_tcp_state_change(struct sock *sk)
case TCP_CLOSE_WAIT:
case TCP_CLOSE:
/* FALLTHRU */
- sk->sk_user_data = NULL;
nvmet_tcp_schedule_release_queue(queue);
break;
default:
diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
new file mode 100644
index 000000000000..17f8b7a45f21
--- /dev/null
+++ b/drivers/nvme/target/zns.c
@@ -0,0 +1,615 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NVMe ZNS-ZBD command implementation.
+ * Copyright (C) 2021 Western Digital Corporation or its affiliates.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/nvme.h>
+#include <linux/blkdev.h>
+#include "nvmet.h"
+
+/*
+ * We set the Memory Page Size Minimum (MPSMIN) for target controller to 0
+ * which gets added by 12 in the nvme_enable_ctrl() which results in 2^12 = 4k
+ * as page_shift value. When calculating the ZASL use shift by 12.
+ */
+#define NVMET_MPSMIN_SHIFT 12
+
+static inline u8 nvmet_zasl(unsigned int zone_append_sects)
+{
+ /*
+ * Zone Append Size Limit (zasl) is expressed as a power of 2 value
+ * with the minimum memory page size (i.e. 12) as unit.
+ */
+ return ilog2(zone_append_sects >> (NVMET_MPSMIN_SHIFT - 9));
+}
+
+static int validate_conv_zones_cb(struct blk_zone *z,
+ unsigned int i, void *data)
+{
+ if (z->type == BLK_ZONE_TYPE_CONVENTIONAL)
+ return -EOPNOTSUPP;
+ return 0;
+}
+
+bool nvmet_bdev_zns_enable(struct nvmet_ns *ns)
+{
+ struct request_queue *q = ns->bdev->bd_disk->queue;
+ u8 zasl = nvmet_zasl(queue_max_zone_append_sectors(q));
+ struct gendisk *bd_disk = ns->bdev->bd_disk;
+ int ret;
+
+ if (ns->subsys->zasl) {
+ if (ns->subsys->zasl > zasl)
+ return false;
+ }
+ ns->subsys->zasl = zasl;
+
+ /*
+ * Generic zoned block devices may have a smaller last zone which is
+ * not supported by ZNS. Exclude zoned drives that have such smaller
+ * last zone.
+ */
+ if (get_capacity(bd_disk) & (bdev_zone_sectors(ns->bdev) - 1))
+ return false;
+ /*
+ * ZNS does not define a conventional zone type. If the underlying
+ * device has a bitmap set indicating the existence of conventional
+ * zones, reject the device. Otherwise, use report zones to detect if
+ * the device has conventional zones.
+ */
+ if (ns->bdev->bd_disk->queue->conv_zones_bitmap)
+ return false;
+
+ ret = blkdev_report_zones(ns->bdev, 0, blkdev_nr_zones(bd_disk),
+ validate_conv_zones_cb, NULL);
+ if (ret < 0)
+ return false;
+
+ ns->blksize_shift = blksize_bits(bdev_logical_block_size(ns->bdev));
+
+ return true;
+}
+
+void nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req)
+{
+ u8 zasl = req->sq->ctrl->subsys->zasl;
+ struct nvmet_ctrl *ctrl = req->sq->ctrl;
+ struct nvme_id_ctrl_zns *id;
+ u16 status;
+
+ id = kzalloc(sizeof(*id), GFP_KERNEL);
+ if (!id) {
+ status = NVME_SC_INTERNAL;
+ goto out;
+ }
+
+ if (ctrl->ops->get_mdts)
+ id->zasl = min_t(u8, ctrl->ops->get_mdts(ctrl), zasl);
+ else
+ id->zasl = zasl;
+
+ status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
+
+ kfree(id);
+out:
+ nvmet_req_complete(req, status);
+}
+
+void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req)
+{
+ struct nvme_id_ns_zns *id_zns;
+ u64 zsze;
+ u16 status;
+
+ if (le32_to_cpu(req->cmd->identify.nsid) == NVME_NSID_ALL) {
+ req->error_loc = offsetof(struct nvme_identify, nsid);
+ status = NVME_SC_INVALID_NS | NVME_SC_DNR;
+ goto out;
+ }
+
+ id_zns = kzalloc(sizeof(*id_zns), GFP_KERNEL);
+ if (!id_zns) {
+ status = NVME_SC_INTERNAL;
+ goto out;
+ }
+
+ status = nvmet_req_find_ns(req);
+ if (status) {
+ status = NVME_SC_INTERNAL;
+ goto done;
+ }
+
+ if (!bdev_is_zoned(req->ns->bdev)) {
+ req->error_loc = offsetof(struct nvme_identify, nsid);
+ status = NVME_SC_INVALID_NS | NVME_SC_DNR;
+ goto done;
+ }
+
+ nvmet_ns_revalidate(req->ns);
+ zsze = (bdev_zone_sectors(req->ns->bdev) << 9) >>
+ req->ns->blksize_shift;
+ id_zns->lbafe[0].zsze = cpu_to_le64(zsze);
+ id_zns->mor = cpu_to_le32(bdev_max_open_zones(req->ns->bdev));
+ id_zns->mar = cpu_to_le32(bdev_max_active_zones(req->ns->bdev));
+
+done:
+ status = nvmet_copy_to_sgl(req, 0, id_zns, sizeof(*id_zns));
+ kfree(id_zns);
+out:
+ nvmet_req_complete(req, status);
+}
+
+static u16 nvmet_bdev_validate_zone_mgmt_recv(struct nvmet_req *req)
+{
+ sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->zmr.slba);
+ u32 out_bufsize = (le32_to_cpu(req->cmd->zmr.numd) + 1) << 2;
+
+ if (sect >= get_capacity(req->ns->bdev->bd_disk)) {
+ req->error_loc = offsetof(struct nvme_zone_mgmt_recv_cmd, slba);
+ return NVME_SC_LBA_RANGE | NVME_SC_DNR;
+ }
+
+ if (out_bufsize < sizeof(struct nvme_zone_report)) {
+ req->error_loc = offsetof(struct nvme_zone_mgmt_recv_cmd, numd);
+ return NVME_SC_INVALID_FIELD | NVME_SC_DNR;
+ }
+
+ if (req->cmd->zmr.zra != NVME_ZRA_ZONE_REPORT) {
+ req->error_loc = offsetof(struct nvme_zone_mgmt_recv_cmd, zra);
+ return NVME_SC_INVALID_FIELD | NVME_SC_DNR;
+ }
+
+ switch (req->cmd->zmr.pr) {
+ case 0:
+ case 1:
+ break;
+ default:
+ req->error_loc = offsetof(struct nvme_zone_mgmt_recv_cmd, pr);
+ return NVME_SC_INVALID_FIELD | NVME_SC_DNR;
+ }
+
+ switch (req->cmd->zmr.zrasf) {
+ case NVME_ZRASF_ZONE_REPORT_ALL:
+ case NVME_ZRASF_ZONE_STATE_EMPTY:
+ case NVME_ZRASF_ZONE_STATE_IMP_OPEN:
+ case NVME_ZRASF_ZONE_STATE_EXP_OPEN:
+ case NVME_ZRASF_ZONE_STATE_CLOSED:
+ case NVME_ZRASF_ZONE_STATE_FULL:
+ case NVME_ZRASF_ZONE_STATE_READONLY:
+ case NVME_ZRASF_ZONE_STATE_OFFLINE:
+ break;
+ default:
+ req->error_loc =
+ offsetof(struct nvme_zone_mgmt_recv_cmd, zrasf);
+ return NVME_SC_INVALID_FIELD | NVME_SC_DNR;
+ }
+
+ return NVME_SC_SUCCESS;
+}
+
+struct nvmet_report_zone_data {
+ struct nvmet_req *req;
+ u64 out_buf_offset;
+ u64 out_nr_zones;
+ u64 nr_zones;
+ u8 zrasf;
+};
+
+static int nvmet_bdev_report_zone_cb(struct blk_zone *z, unsigned i, void *d)
+{
+ static const unsigned int nvme_zrasf_to_blk_zcond[] = {
+ [NVME_ZRASF_ZONE_STATE_EMPTY] = BLK_ZONE_COND_EMPTY,
+ [NVME_ZRASF_ZONE_STATE_IMP_OPEN] = BLK_ZONE_COND_IMP_OPEN,
+ [NVME_ZRASF_ZONE_STATE_EXP_OPEN] = BLK_ZONE_COND_EXP_OPEN,
+ [NVME_ZRASF_ZONE_STATE_CLOSED] = BLK_ZONE_COND_CLOSED,
+ [NVME_ZRASF_ZONE_STATE_READONLY] = BLK_ZONE_COND_READONLY,
+ [NVME_ZRASF_ZONE_STATE_FULL] = BLK_ZONE_COND_FULL,
+ [NVME_ZRASF_ZONE_STATE_OFFLINE] = BLK_ZONE_COND_OFFLINE,
+ };
+ struct nvmet_report_zone_data *rz = d;
+
+ if (rz->zrasf != NVME_ZRASF_ZONE_REPORT_ALL &&
+ z->cond != nvme_zrasf_to_blk_zcond[rz->zrasf])
+ return 0;
+
+ if (rz->nr_zones < rz->out_nr_zones) {
+ struct nvme_zone_descriptor zdesc = { };
+ u16 status;
+
+ zdesc.zcap = nvmet_sect_to_lba(rz->req->ns, z->capacity);
+ zdesc.zslba = nvmet_sect_to_lba(rz->req->ns, z->start);
+ zdesc.wp = nvmet_sect_to_lba(rz->req->ns, z->wp);
+ zdesc.za = z->reset ? 1 << 2 : 0;
+ zdesc.zs = z->cond << 4;
+ zdesc.zt = z->type;
+
+ status = nvmet_copy_to_sgl(rz->req, rz->out_buf_offset, &zdesc,
+ sizeof(zdesc));
+ if (status)
+ return -EINVAL;
+
+ rz->out_buf_offset += sizeof(zdesc);
+ }
+
+ rz->nr_zones++;
+
+ return 0;
+}
+
+static unsigned long nvmet_req_nr_zones_from_slba(struct nvmet_req *req)
+{
+ unsigned int sect = nvmet_lba_to_sect(req->ns, req->cmd->zmr.slba);
+
+ return blkdev_nr_zones(req->ns->bdev->bd_disk) -
+ (sect >> ilog2(bdev_zone_sectors(req->ns->bdev)));
+}
+
+static unsigned long get_nr_zones_from_buf(struct nvmet_req *req, u32 bufsize)
+{
+ if (bufsize <= sizeof(struct nvme_zone_report))
+ return 0;
+
+ return (bufsize - sizeof(struct nvme_zone_report)) /
+ sizeof(struct nvme_zone_descriptor);
+}
+
+static void nvmet_bdev_zone_zmgmt_recv_work(struct work_struct *w)
+{
+ struct nvmet_req *req = container_of(w, struct nvmet_req, z.zmgmt_work);
+ sector_t start_sect = nvmet_lba_to_sect(req->ns, req->cmd->zmr.slba);
+ unsigned long req_slba_nr_zones = nvmet_req_nr_zones_from_slba(req);
+ u32 out_bufsize = (le32_to_cpu(req->cmd->zmr.numd) + 1) << 2;
+ __le64 nr_zones;
+ u16 status;
+ int ret;
+ struct nvmet_report_zone_data rz_data = {
+ .out_nr_zones = get_nr_zones_from_buf(req, out_bufsize),
+ /* leave the place for report zone header */
+ .out_buf_offset = sizeof(struct nvme_zone_report),
+ .zrasf = req->cmd->zmr.zrasf,
+ .nr_zones = 0,
+ .req = req,
+ };
+
+ status = nvmet_bdev_validate_zone_mgmt_recv(req);
+ if (status)
+ goto out;
+
+ if (!req_slba_nr_zones) {
+ status = NVME_SC_SUCCESS;
+ goto out;
+ }
+
+ ret = blkdev_report_zones(req->ns->bdev, start_sect, req_slba_nr_zones,
+ nvmet_bdev_report_zone_cb, &rz_data);
+ if (ret < 0) {
+ status = NVME_SC_INTERNAL;
+ goto out;
+ }
+
+ /*
+ * When partial bit is set nr_zones must indicate the number of zone
+ * descriptors actually transferred.
+ */
+ if (req->cmd->zmr.pr)
+ rz_data.nr_zones = min(rz_data.nr_zones, rz_data.out_nr_zones);
+
+ nr_zones = cpu_to_le64(rz_data.nr_zones);
+ status = nvmet_copy_to_sgl(req, 0, &nr_zones, sizeof(nr_zones));
+
+out:
+ nvmet_req_complete(req, status);
+}
+
+void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req)
+{
+ INIT_WORK(&req->z.zmgmt_work, nvmet_bdev_zone_zmgmt_recv_work);
+ queue_work(zbd_wq, &req->z.zmgmt_work);
+}
+
+static inline enum req_opf zsa_req_op(u8 zsa)
+{
+ switch (zsa) {
+ case NVME_ZONE_OPEN:
+ return REQ_OP_ZONE_OPEN;
+ case NVME_ZONE_CLOSE:
+ return REQ_OP_ZONE_CLOSE;
+ case NVME_ZONE_FINISH:
+ return REQ_OP_ZONE_FINISH;
+ case NVME_ZONE_RESET:
+ return REQ_OP_ZONE_RESET;
+ default:
+ return REQ_OP_LAST;
+ }
+}
+
+static u16 blkdev_zone_mgmt_errno_to_nvme_status(int ret)
+{
+ switch (ret) {
+ case 0:
+ return NVME_SC_SUCCESS;
+ case -EINVAL:
+ case -EIO:
+ return NVME_SC_ZONE_INVALID_TRANSITION | NVME_SC_DNR;
+ default:
+ return NVME_SC_INTERNAL;
+ }
+}
+
+struct nvmet_zone_mgmt_send_all_data {
+ unsigned long *zbitmap;
+ struct nvmet_req *req;
+};
+
+static int zmgmt_send_scan_cb(struct blk_zone *z, unsigned i, void *d)
+{
+ struct nvmet_zone_mgmt_send_all_data *data = d;
+
+ switch (zsa_req_op(data->req->cmd->zms.zsa)) {
+ case REQ_OP_ZONE_OPEN:
+ switch (z->cond) {
+ case BLK_ZONE_COND_CLOSED:
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case REQ_OP_ZONE_CLOSE:
+ switch (z->cond) {
+ case BLK_ZONE_COND_IMP_OPEN:
+ case BLK_ZONE_COND_EXP_OPEN:
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case REQ_OP_ZONE_FINISH:
+ switch (z->cond) {
+ case BLK_ZONE_COND_IMP_OPEN:
+ case BLK_ZONE_COND_EXP_OPEN:
+ case BLK_ZONE_COND_CLOSED:
+ break;
+ default:
+ return 0;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ set_bit(i, data->zbitmap);
+
+ return 0;
+}
+
+static u16 nvmet_bdev_zone_mgmt_emulate_all(struct nvmet_req *req)
+{
+ struct block_device *bdev = req->ns->bdev;
+ unsigned int nr_zones = blkdev_nr_zones(bdev->bd_disk);
+ struct request_queue *q = bdev_get_queue(bdev);
+ struct bio *bio = NULL;
+ sector_t sector = 0;
+ int ret;
+ struct nvmet_zone_mgmt_send_all_data d = {
+ .req = req,
+ };
+
+ d.zbitmap = kcalloc_node(BITS_TO_LONGS(nr_zones), sizeof(*(d.zbitmap)),
+ GFP_NOIO, q->node);
+ if (!d.zbitmap) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Scan and build bitmap of the eligible zones */
+ ret = blkdev_report_zones(bdev, 0, nr_zones, zmgmt_send_scan_cb, &d);
+ if (ret != nr_zones) {
+ if (ret > 0)
+ ret = -EIO;
+ goto out;
+ } else {
+ /* We scanned all the zones */
+ ret = 0;
+ }
+
+ while (sector < get_capacity(bdev->bd_disk)) {
+ if (test_bit(blk_queue_zone_no(q, sector), d.zbitmap)) {
+ bio = blk_next_bio(bio, 0, GFP_KERNEL);
+ bio->bi_opf = zsa_req_op(req->cmd->zms.zsa) | REQ_SYNC;
+ bio->bi_iter.bi_sector = sector;
+ bio_set_dev(bio, bdev);
+ /* This may take a while, so be nice to others */
+ cond_resched();
+ }
+ sector += blk_queue_zone_sectors(q);
+ }
+
+ if (bio) {
+ ret = submit_bio_wait(bio);
+ bio_put(bio);
+ }
+
+out:
+ kfree(d.zbitmap);
+
+ return blkdev_zone_mgmt_errno_to_nvme_status(ret);
+}
+
+static u16 nvmet_bdev_execute_zmgmt_send_all(struct nvmet_req *req)
+{
+ int ret;
+
+ switch (zsa_req_op(req->cmd->zms.zsa)) {
+ case REQ_OP_ZONE_RESET:
+ ret = blkdev_zone_mgmt(req->ns->bdev, REQ_OP_ZONE_RESET, 0,
+ get_capacity(req->ns->bdev->bd_disk),
+ GFP_KERNEL);
+ if (ret < 0)
+ return blkdev_zone_mgmt_errno_to_nvme_status(ret);
+ break;
+ case REQ_OP_ZONE_OPEN:
+ case REQ_OP_ZONE_CLOSE:
+ case REQ_OP_ZONE_FINISH:
+ return nvmet_bdev_zone_mgmt_emulate_all(req);
+ default:
+ /* this is needed to quiet compiler warning */
+ req->error_loc = offsetof(struct nvme_zone_mgmt_send_cmd, zsa);
+ return NVME_SC_INVALID_FIELD | NVME_SC_DNR;
+ }
+
+ return NVME_SC_SUCCESS;
+}
+
+static void nvmet_bdev_zmgmt_send_work(struct work_struct *w)
+{
+ struct nvmet_req *req = container_of(w, struct nvmet_req, z.zmgmt_work);
+ sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->zms.slba);
+ enum req_opf op = zsa_req_op(req->cmd->zms.zsa);
+ struct block_device *bdev = req->ns->bdev;
+ sector_t zone_sectors = bdev_zone_sectors(bdev);
+ u16 status = NVME_SC_SUCCESS;
+ int ret;
+
+ if (op == REQ_OP_LAST) {
+ req->error_loc = offsetof(struct nvme_zone_mgmt_send_cmd, zsa);
+ status = NVME_SC_ZONE_INVALID_TRANSITION | NVME_SC_DNR;
+ goto out;
+ }
+
+ /* when select all bit is set slba field is ignored */
+ if (req->cmd->zms.select_all) {
+ status = nvmet_bdev_execute_zmgmt_send_all(req);
+ goto out;
+ }
+
+ if (sect >= get_capacity(bdev->bd_disk)) {
+ req->error_loc = offsetof(struct nvme_zone_mgmt_send_cmd, slba);
+ status = NVME_SC_LBA_RANGE | NVME_SC_DNR;
+ goto out;
+ }
+
+ if (sect & (zone_sectors - 1)) {
+ req->error_loc = offsetof(struct nvme_zone_mgmt_send_cmd, slba);
+ status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
+ goto out;
+ }
+
+ ret = blkdev_zone_mgmt(bdev, op, sect, zone_sectors, GFP_KERNEL);
+ if (ret < 0)
+ status = blkdev_zone_mgmt_errno_to_nvme_status(ret);
+
+out:
+ nvmet_req_complete(req, status);
+}
+
+void nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req)
+{
+ INIT_WORK(&req->z.zmgmt_work, nvmet_bdev_zmgmt_send_work);
+ queue_work(zbd_wq, &req->z.zmgmt_work);
+}
+
+static void nvmet_bdev_zone_append_bio_done(struct bio *bio)
+{
+ struct nvmet_req *req = bio->bi_private;
+
+ if (bio->bi_status == BLK_STS_OK) {
+ req->cqe->result.u64 =
+ nvmet_sect_to_lba(req->ns, bio->bi_iter.bi_sector);
+ }
+
+ nvmet_req_complete(req, blk_to_nvme_status(req, bio->bi_status));
+ nvmet_req_bio_put(req, bio);
+}
+
+void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
+{
+ sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
+ u16 status = NVME_SC_SUCCESS;
+ unsigned int total_len = 0;
+ struct scatterlist *sg;
+ struct bio *bio;
+ int sg_cnt;
+
+ /* Request is completed on len mismatch in nvmet_check_transter_len() */
+ if (!nvmet_check_transfer_len(req, nvmet_rw_data_len(req)))
+ return;
+
+ if (!req->sg_cnt) {
+ nvmet_req_complete(req, 0);
+ return;
+ }
+
+ if (sect >= get_capacity(req->ns->bdev->bd_disk)) {
+ req->error_loc = offsetof(struct nvme_rw_command, slba);
+ status = NVME_SC_LBA_RANGE | NVME_SC_DNR;
+ goto out;
+ }
+
+ if (sect & (bdev_zone_sectors(req->ns->bdev) - 1)) {
+ req->error_loc = offsetof(struct nvme_rw_command, slba);
+ status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
+ goto out;
+ }
+
+ if (nvmet_use_inline_bvec(req)) {
+ bio = &req->z.inline_bio;
+ bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
+ } else {
+ bio = bio_alloc(GFP_KERNEL, req->sg_cnt);
+ }
+
+ bio->bi_opf = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
+ bio->bi_end_io = nvmet_bdev_zone_append_bio_done;
+ bio_set_dev(bio, req->ns->bdev);
+ bio->bi_iter.bi_sector = sect;
+ bio->bi_private = req;
+ if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
+ bio->bi_opf |= REQ_FUA;
+
+ for_each_sg(req->sg, sg, req->sg_cnt, sg_cnt) {
+ struct page *p = sg_page(sg);
+ unsigned int l = sg->length;
+ unsigned int o = sg->offset;
+ unsigned int ret;
+
+ ret = bio_add_zone_append_page(bio, p, l, o);
+ if (ret != sg->length) {
+ status = NVME_SC_INTERNAL;
+ goto out_put_bio;
+ }
+ total_len += sg->length;
+ }
+
+ if (total_len != nvmet_rw_data_len(req)) {
+ status = NVME_SC_INTERNAL | NVME_SC_DNR;
+ goto out_put_bio;
+ }
+
+ submit_bio(bio);
+ return;
+
+out_put_bio:
+ nvmet_req_bio_put(req, bio);
+out:
+ nvmet_req_complete(req, status);
+}
+
+u16 nvmet_bdev_zns_parse_io_cmd(struct nvmet_req *req)
+{
+ struct nvme_command *cmd = req->cmd;
+
+ switch (cmd->common.opcode) {
+ case nvme_cmd_zone_append:
+ req->execute = nvmet_bdev_execute_zone_append;
+ return 0;
+ case nvme_cmd_zone_mgmt_recv:
+ req->execute = nvmet_bdev_execute_zone_mgmt_recv;
+ return 0;
+ case nvme_cmd_zone_mgmt_send:
+ req->execute = nvmet_bdev_execute_zone_mgmt_send;
+ return 0;
+ default:
+ return nvmet_bdev_parse_io_cmd(req);
+ }
+}
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index bca671ff4e54..b3bc30a04ed7 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -180,6 +180,7 @@ static const char * const nvmem_type_str[] = {
[NVMEM_TYPE_EEPROM] = "EEPROM",
[NVMEM_TYPE_OTP] = "OTP",
[NVMEM_TYPE_BATTERY_BACKED] = "Battery backed",
+ [NVMEM_TYPE_FRAM] = "FRAM",
};
#ifdef CONFIG_DEBUG_LOCK_ALLOC
@@ -359,6 +360,9 @@ static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem,
if (!config->base_dev)
return -EINVAL;
+ if (config->type == NVMEM_TYPE_FRAM)
+ bin_attr_nvmem_eeprom_compat.attr.name = "fram";
+
nvmem->eeprom = bin_attr_nvmem_eeprom_compat;
nvmem->eeprom.attr.mode = nvmem_bin_attr_get_umode(nvmem);
nvmem->eeprom.size = nvmem->size;
@@ -686,15 +690,17 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
continue;
if (len < 2 * sizeof(u32)) {
dev_err(dev, "nvmem: invalid reg on %pOF\n", child);
+ of_node_put(child);
return -EINVAL;
}
cell = kzalloc(sizeof(*cell), GFP_KERNEL);
- if (!cell)
+ if (!cell) {
+ of_node_put(child);
return -ENOMEM;
+ }
cell->nvmem = nvmem;
- cell->np = of_node_get(child);
cell->offset = be32_to_cpup(addr++);
cell->bytes = be32_to_cpup(addr);
cell->name = kasprintf(GFP_KERNEL, "%pOFn", child);
@@ -715,11 +721,12 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
cell->name, nvmem->stride);
/* Cells already added will be freed later. */
kfree_const(cell->name);
- of_node_put(cell->np);
kfree(cell);
+ of_node_put(child);
return -EINVAL;
}
+ cell->np = of_node_get(child);
nvmem_cell_add(cell);
}
@@ -789,7 +796,9 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
nvmem->reg_write = config->reg_write;
nvmem->keepout = config->keepout;
nvmem->nkeepout = config->nkeepout;
- if (!config->no_of_node)
+ if (config->of_node)
+ nvmem->dev.of_node = config->of_node;
+ else if (!config->no_of_node)
nvmem->dev.of_node = config->dev->of_node;
switch (config->id) {
@@ -1606,9 +1615,9 @@ int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val)
}
EXPORT_SYMBOL_GPL(nvmem_cell_read_u64);
-static void *nvmem_cell_read_variable_common(struct device *dev,
- const char *cell_id,
- size_t max_len, size_t *len)
+static const void *nvmem_cell_read_variable_common(struct device *dev,
+ const char *cell_id,
+ size_t max_len, size_t *len)
{
struct nvmem_cell *cell;
int nbits;
@@ -1652,7 +1661,7 @@ int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id,
u32 *val)
{
size_t len;
- u8 *buf;
+ const u8 *buf;
int i;
buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len);
@@ -1683,7 +1692,7 @@ int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id,
u64 *val)
{
size_t len;
- u8 *buf;
+ const u8 *buf;
int i;
buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len);
diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c
index d6d3f24685a8..81fbad5e939d 100644
--- a/drivers/nvmem/qfprom.c
+++ b/drivers/nvmem/qfprom.c
@@ -122,6 +122,7 @@ static const struct qfprom_soc_compatible_data sc7280_qfprom = {
.keepout = sc7280_qfprom_keepout,
.nkeepout = ARRAY_SIZE(sc7280_qfprom_keepout)
};
+
/**
* qfprom_disable_fuse_blowing() - Undo enabling of fuse blowing.
* @priv: Our driver data.
@@ -195,9 +196,9 @@ static int qfprom_enable_fuse_blowing(const struct qfprom_priv *priv,
}
/*
- * Hardware requires 1.8V min for fuse blowing; this may be
- * a rail shared do don't specify a max--regulator constraints
- * will handle.
+ * Hardware requires a minimum voltage for fuse blowing.
+ * This may be a shared rail so don't specify a maximum.
+ * Regulator constraints will cap to the actual maximum.
*/
ret = regulator_set_voltage(priv->vcc, qfprom_blow_uV, INT_MAX);
if (ret) {
@@ -399,7 +400,7 @@ static int qfprom_probe(struct platform_device *pdev)
if (major_version == 7 && minor_version == 8)
priv->soc_data = &qfprom_7_8_data;
- if (major_version == 7 && minor_version == 15)
+ else if (major_version == 7 && minor_version == 15)
priv->soc_data = &qfprom_7_15_data;
priv->vcc = devm_regulator_get(&pdev->dev, "vcc");
diff --git a/drivers/nvmem/sprd-efuse.c b/drivers/nvmem/sprd-efuse.c
index 59523245db8a..4f1fcbfec394 100644
--- a/drivers/nvmem/sprd-efuse.c
+++ b/drivers/nvmem/sprd-efuse.c
@@ -234,7 +234,7 @@ static int sprd_efuse_raw_prog(struct sprd_efuse *efuse, u32 blk, bool doub,
status = readl(efuse->base + SPRD_EFUSE_ERR_FLAG);
if (status) {
dev_err(efuse->dev,
- "write error status %d of block %d\n", ret, blk);
+ "write error status %u of block %d\n", status, blk);
writel(SPRD_EFUSE_ERR_CLR_MASK,
efuse->base + SPRD_EFUSE_ERR_CLR);
diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
index e26ef1bbf198..275b9155e473 100644
--- a/drivers/nvmem/sunxi_sid.c
+++ b/drivers/nvmem/sunxi_sid.c
@@ -142,6 +142,7 @@ static int sunxi_sid_probe(struct platform_device *pdev)
nvmem_cfg->dev = dev;
nvmem_cfg->name = "sunxi-sid";
+ nvmem_cfg->type = NVMEM_TYPE_OTP;
nvmem_cfg->read_only = true;
nvmem_cfg->size = cfg->size;
nvmem_cfg->word_size = 1;
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 18450437d5d5..3dfeae8912df 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -75,9 +75,7 @@ config OF_NET
def_bool y
config OF_RESERVED_MEM
- bool
- depends on OF_EARLY_FLATTREE
- default y if DMA_DECLARE_COHERENT || DMA_CMA
+ def_bool OF_EARLY_FLATTREE
config OF_RESOLVE
bool
diff --git a/drivers/of/address.c b/drivers/of/address.c
index aca94c348bd4..94f017d808c4 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -23,9 +23,8 @@
#define OF_CHECK_COUNTS(na, ns) (OF_CHECK_ADDR_COUNT(na) && (ns) > 0)
static struct of_bus *of_match_bus(struct device_node *np);
-static int __of_address_to_resource(struct device_node *dev,
- const __be32 *addrp, u64 size, unsigned int flags,
- const char *name, struct resource *r);
+static int __of_address_to_resource(struct device_node *dev, int index,
+ int bar_no, struct resource *r);
static bool of_mmio_is_nonposted(struct device_node *np);
/* Debug utility */
@@ -77,9 +76,7 @@ static u64 of_bus_default_map(__be32 *addr, const __be32 *range,
s = of_read_number(range + na + pna, ns);
da = of_read_number(addr, na);
- pr_debug("default map, cp=%llx, s=%llx, da=%llx\n",
- (unsigned long long)cp, (unsigned long long)s,
- (unsigned long long)da);
+ pr_debug("default map, cp=%llx, s=%llx, da=%llx\n", cp, s, da);
if (da < cp || da >= (cp + s))
return OF_BAD_ADDR;
@@ -185,9 +182,7 @@ static u64 of_bus_pci_map(__be32 *addr, const __be32 *range, int na, int ns,
s = of_read_number(range + na + pna, ns);
da = of_read_number(addr + 1, na - 1);
- pr_debug("PCI map, cp=%llx, s=%llx, da=%llx\n",
- (unsigned long long)cp, (unsigned long long)s,
- (unsigned long long)da);
+ pr_debug("PCI map, cp=%llx, s=%llx, da=%llx\n", cp, s, da);
if (da < cp || da >= (cp + s))
return OF_BAD_ADDR;
@@ -198,62 +193,16 @@ static int of_bus_pci_translate(__be32 *addr, u64 offset, int na)
{
return of_bus_default_translate(addr + 1, offset, na - 1);
}
-
-const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
- unsigned int *flags)
-{
- const __be32 *prop;
- unsigned int psize;
- struct device_node *parent;
- struct of_bus *bus;
- int onesize, i, na, ns;
-
- /* Get parent & match bus type */
- parent = of_get_parent(dev);
- if (parent == NULL)
- return NULL;
- bus = of_match_bus(parent);
- if (strcmp(bus->name, "pci")) {
- of_node_put(parent);
- return NULL;
- }
- bus->count_cells(dev, &na, &ns);
- of_node_put(parent);
- if (!OF_CHECK_ADDR_COUNT(na))
- return NULL;
-
- /* Get "reg" or "assigned-addresses" property */
- prop = of_get_property(dev, bus->addresses, &psize);
- if (prop == NULL)
- return NULL;
- psize /= 4;
-
- onesize = na + ns;
- for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) {
- u32 val = be32_to_cpu(prop[0]);
- if ((val & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
- if (size)
- *size = of_read_number(prop + na, ns);
- if (flags)
- *flags = bus->get_flags(prop);
- return prop;
- }
- }
- return NULL;
-}
-EXPORT_SYMBOL(of_get_pci_address);
+#endif /* CONFIG_PCI */
int of_pci_address_to_resource(struct device_node *dev, int bar,
struct resource *r)
{
- const __be32 *addrp;
- u64 size;
- unsigned int flags;
- addrp = of_get_pci_address(dev, bar, &size, &flags);
- if (addrp == NULL)
- return -EINVAL;
- return __of_address_to_resource(dev, addrp, size, flags, NULL, r);
+ if (!IS_ENABLED(CONFIG_PCI))
+ return -ENOSYS;
+
+ return __of_address_to_resource(dev, -1, bar, r);
}
EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
@@ -280,6 +229,9 @@ int of_pci_range_to_resource(struct of_pci_range *range,
res->parent = res->child = res->sibling = NULL;
res->name = np->full_name;
+ if (!IS_ENABLED(CONFIG_PCI))
+ return -ENOSYS;
+
if (res->flags & IORESOURCE_IO) {
unsigned long port;
err = pci_register_io_range(&np->fwnode, range->cpu_addr,
@@ -310,7 +262,6 @@ invalid_range:
return err;
}
EXPORT_SYMBOL(of_pci_range_to_resource);
-#endif /* CONFIG_PCI */
/*
* ISA bus specific translator
@@ -344,9 +295,7 @@ static u64 of_bus_isa_map(__be32 *addr, const __be32 *range, int na, int ns,
s = of_read_number(range + na + pna, ns);
da = of_read_number(addr + 1, na - 1);
- pr_debug("ISA map, cp=%llx, s=%llx, da=%llx\n",
- (unsigned long long)cp, (unsigned long long)s,
- (unsigned long long)da);
+ pr_debug("ISA map, cp=%llx, s=%llx, da=%llx\n", cp, s, da);
if (da < cp || da >= (cp + s))
return OF_BAD_ADDR;
@@ -501,7 +450,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
finish:
of_dump_addr("parent translation for:", addr, pna);
- pr_debug("with offset: %llx\n", (unsigned long long)offset);
+ pr_debug("with offset: %llx\n", offset);
/* Translate it into parent bus space */
return pbus->translate(addr, offset, pna);
@@ -675,8 +624,8 @@ u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
}
EXPORT_SYMBOL(of_translate_dma_address);
-const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
- unsigned int *flags)
+const __be32 *__of_get_address(struct device_node *dev, int index, int bar_no,
+ u64 *size, unsigned int *flags)
{
const __be32 *prop;
unsigned int psize;
@@ -689,6 +638,10 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
if (parent == NULL)
return NULL;
bus = of_match_bus(parent);
+ if (strcmp(bus->name, "pci") && (bar_no >= 0)) {
+ of_node_put(parent);
+ return NULL;
+ }
bus->count_cells(dev, &na, &ns);
of_node_put(parent);
if (!OF_CHECK_ADDR_COUNT(na))
@@ -701,17 +654,21 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
psize /= 4;
onesize = na + ns;
- for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
- if (i == index) {
+ for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) {
+ u32 val = be32_to_cpu(prop[0]);
+ /* PCI bus matches on BAR number instead of index */
+ if (((bar_no >= 0) && ((val & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0))) ||
+ ((index >= 0) && (i == index))) {
if (size)
*size = of_read_number(prop + na, ns);
if (flags)
*flags = bus->get_flags(prop);
return prop;
}
+ }
return NULL;
}
-EXPORT_SYMBOL(of_get_address);
+EXPORT_SYMBOL(__of_get_address);
static int parser_init(struct of_pci_range_parser *parser,
struct device_node *node, const char *name)
@@ -834,11 +791,22 @@ static u64 of_translate_ioport(struct device_node *dev, const __be32 *in_addr,
return port;
}
-static int __of_address_to_resource(struct device_node *dev,
- const __be32 *addrp, u64 size, unsigned int flags,
- const char *name, struct resource *r)
+static int __of_address_to_resource(struct device_node *dev, int index, int bar_no,
+ struct resource *r)
{
u64 taddr;
+ const __be32 *addrp;
+ u64 size;
+ unsigned int flags;
+ const char *name = NULL;
+
+ addrp = __of_get_address(dev, index, bar_no, &size, &flags);
+ if (addrp == NULL)
+ return -EINVAL;
+
+ /* Get optional "reg-names" property to add a name to a resource */
+ if (index >= 0)
+ of_property_read_string_index(dev, "reg-names", index, &name);
if (flags & IORESOURCE_MEM)
taddr = of_translate_address(dev, addrp);
@@ -876,19 +844,7 @@ static int __of_address_to_resource(struct device_node *dev,
int of_address_to_resource(struct device_node *dev, int index,
struct resource *r)
{
- const __be32 *addrp;
- u64 size;
- unsigned int flags;
- const char *name = NULL;
-
- addrp = of_get_address(dev, index, &size, &flags);
- if (addrp == NULL)
- return -EINVAL;
-
- /* Get optional "reg-names" property to add a name to a resource */
- of_property_read_string_index(dev, "reg-names", index, &name);
-
- return __of_address_to_resource(dev, addrp, size, flags, name, r);
+ return __of_address_to_resource(dev, index, -1, r);
}
EXPORT_SYMBOL_GPL(of_address_to_resource);
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index ba17a80b8c79..e0f96e3ef1da 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -510,11 +510,11 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
if (size &&
early_init_dt_reserve_memory_arch(base, size, nomap) == 0)
- pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n",
- uname, &base, (unsigned long)size / SZ_1M);
+ pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n",
+ uname, &base, (unsigned long)(size / SZ_1M));
else
- pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n",
- uname, &base, (unsigned long)size / SZ_1M);
+ pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n",
+ uname, &base, (unsigned long)(size / SZ_1M));
len -= t_len;
if (first) {
@@ -900,8 +900,7 @@ static void __init early_init_dt_check_for_initrd(unsigned long node)
phys_initrd_start = start;
phys_initrd_size = end - start;
- pr_debug("initrd_start=0x%llx initrd_end=0x%llx\n",
- (unsigned long long)start, (unsigned long long)end);
+ pr_debug("initrd_start=0x%llx initrd_end=0x%llx\n", start, end);
}
#else
static inline void early_init_dt_check_for_initrd(unsigned long node)
@@ -1027,8 +1026,7 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
if (size == 0)
continue;
- pr_debug(" - %llx , %llx\n", (unsigned long long)base,
- (unsigned long long)size);
+ pr_debug(" - %llx, %llx\n", base, size);
early_init_dt_add_memory_arch(base, size);
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index d717efbd637d..631489f7f8c0 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -171,4 +171,8 @@ static inline int of_dma_get_range(struct device_node *np,
}
#endif
+void fdt_init_reserved_mem(void);
+void fdt_reserved_mem_save_node(unsigned long node, const char *uname,
+ phys_addr_t base, phys_addr_t size);
+
#endif /* _LINUX_OF_PRIVATE_H */
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 15e2417974d6..fd3964d24224 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -22,6 +22,8 @@
#include <linux/slab.h>
#include <linux/memblock.h>
+#include "of_private.h"
+
#define MAX_RESERVED_REGIONS 64
static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
static int reserved_mem_count;
@@ -40,7 +42,7 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
*res_base = base;
if (nomap)
- return memblock_remove(base, size);
+ return memblock_mark_nomap(base, size);
return memblock_reserve(base, size);
}
@@ -134,9 +136,9 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
ret = early_init_dt_alloc_reserved_memory_arch(size,
align, start, end, nomap, &base);
if (ret == 0) {
- pr_debug("allocated memory for '%s' node: base %pa, size %ld MiB\n",
+ pr_debug("allocated memory for '%s' node: base %pa, size %lu MiB\n",
uname, &base,
- (unsigned long)size / SZ_1M);
+ (unsigned long)(size / SZ_1M));
break;
}
len -= t_len;
@@ -146,8 +148,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
ret = early_init_dt_alloc_reserved_memory_arch(size, align,
0, 0, nomap, &base);
if (ret == 0)
- pr_debug("allocated memory for '%s' node: base %pa, size %ld MiB\n",
- uname, &base, (unsigned long)size / SZ_1M);
+ pr_debug("allocated memory for '%s' node: base %pa, size %lu MiB\n",
+ uname, &base, (unsigned long)(size / SZ_1M));
}
if (base == 0) {
@@ -273,9 +275,10 @@ void __init fdt_init_reserved_mem(void)
if (err != 0 && err != -ENOENT) {
pr_info("node %s compatible matching fail\n",
rmem->name);
- memblock_free(rmem->base, rmem->size);
if (nomap)
- memblock_add(rmem->base, rmem->size);
+ memblock_clear_nomap(rmem->base, rmem->size);
+ else
+ memblock_free(rmem->base, rmem->size);
}
}
}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 25d448f5af91..74afbb7a4f5e 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -17,7 +17,6 @@
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
-#include <linux/of_iommu.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 819a20acaa93..8c056972a6dd 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1209,11 +1209,7 @@ static void __init of_unittest_match_node(void)
}
}
-static struct resource test_bus_res = {
- .start = 0xfffffff8,
- .end = 0xfffffff9,
- .flags = IORESOURCE_MEM,
-};
+static struct resource test_bus_res = DEFINE_RES_MEM(0xfffffff8, 2);
static const struct platform_device_info test_bus_info = {
.name = "unittest-bus",
};
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index e366218d6736..b335c077f215 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -893,6 +893,16 @@ static int _set_required_opps(struct device *dev,
if (!required_opp_tables)
return 0;
+ /*
+ * We only support genpd's OPPs in the "required-opps" for now, as we
+ * don't know much about other use cases. Error out if the required OPP
+ * doesn't belong to a genpd.
+ */
+ if (unlikely(!required_opp_tables[0]->is_genpd)) {
+ dev_err(dev, "required-opps don't belong to a genpd\n");
+ return -ENOENT;
+ }
+
/* required-opps not fully initialized yet */
if (lazy_linking_pending(opp_table))
return -EBUSY;
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index c582a9ca397b..d298e38aaf7e 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -197,21 +197,8 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
required_opp_tables[i] = _find_table_of_opp_np(required_np);
of_node_put(required_np);
- if (IS_ERR(required_opp_tables[i])) {
+ if (IS_ERR(required_opp_tables[i]))
lazy = true;
- continue;
- }
-
- /*
- * We only support genpd's OPPs in the "required-opps" for now,
- * as we don't know how much about other cases. Error out if the
- * required OPP doesn't belong to a genpd.
- */
- if (!required_opp_tables[i]->is_genpd) {
- dev_err(dev, "required-opp doesn't belong to genpd: %pOF\n",
- required_np);
- goto free_required_tables;
- }
}
/* Let's do the linking later on */
@@ -379,13 +366,6 @@ static void lazy_link_required_opp_table(struct opp_table *new_table)
struct dev_pm_opp *opp;
int i, ret;
- /*
- * We only support genpd's OPPs in the "required-opps" for now,
- * as we don't know much about other cases.
- */
- if (!new_table->is_genpd)
- return;
-
mutex_lock(&opp_table_lock);
list_for_each_entry_safe(opp_table, temp, &lazy_opp_tables, lazy) {
@@ -433,8 +413,7 @@ static void lazy_link_required_opp_table(struct opp_table *new_table)
/* All required opp-tables found, remove from lazy list */
if (!lazy) {
- list_del(&opp_table->lazy);
- INIT_LIST_HEAD(&opp_table->lazy);
+ list_del_init(&opp_table->lazy);
list_for_each_entry(opp, &opp_table->opp_list, node)
_required_opps_available(opp, opp_table->required_opp_count);
@@ -874,7 +853,7 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
return ERR_PTR(-ENOMEM);
ret = _read_opp_key(new_opp, opp_table, np, &rate_not_available);
- if (ret < 0 && !opp_table->is_genpd) {
+ if (ret < 0) {
dev_err(dev, "%s: opp key field not found\n", __func__);
goto free_opp;
}
diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c
index ebaf6867b457..456776bd8ee6 100644
--- a/drivers/parisc/power.c
+++ b/drivers/parisc/power.c
@@ -38,6 +38,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/notifier.h>
+#include <linux/panic_notifier.h>
#include <linux/reboot.h>
#include <linux/sched/signal.h>
#include <linux/kthread.h>
diff --git a/drivers/parport/probe.c b/drivers/parport/probe.c
index 7e6d713fa5ac..5d1b9aacb130 100644
--- a/drivers/parport/probe.c
+++ b/drivers/parport/probe.c
@@ -8,8 +8,8 @@
#include <linux/module.h>
#include <linux/parport.h>
-#include <linux/ctype.h>
#include <linux/string.h>
+#include <linux/string_helpers.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -74,11 +74,7 @@ static void parse_data(struct parport *port, int device, char *str)
u = sep + strlen (sep) - 1;
while (u >= p && *u == ' ')
*u-- = '\0';
- u = p;
- while (*u) {
- *u = toupper(*u);
- u++;
- }
+ string_upper(p, p);
if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) {
kfree(info->mfr);
info->mfr = kstrdup(sep, GFP_KERNEL);
@@ -90,8 +86,7 @@ static void parse_data(struct parport *port, int device, char *str)
kfree(info->class_name);
info->class_name = kstrdup(sep, GFP_KERNEL);
- for (u = sep; *u; u++)
- *u = toupper(*u);
+ string_upper(sep, sep);
for (i = 0; classes[i].token; i++) {
if (!strcmp(classes[i].token, sep)) {
info->class = i;
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 2f2c8a1729f9..5e1e3796efa4 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -37,6 +37,14 @@ config PCI_FTPCI100
depends on OF
default ARCH_GEMINI
+config PCI_IXP4XX
+ bool "Intel IXP4xx PCI controller"
+ depends on ARM && OF
+ default ARCH_IXP4XX
+ help
+ Say Y here if you want support for the PCI host controller found
+ in the Intel IXP4xx XScale-based network processor SoC.
+
config PCI_TEGRA
bool "NVIDIA Tegra PCIe controller"
depends on ARCH_TEGRA || COMPILE_TEST
diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index 63e3880a3e87..aaf30b3dcc14 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PCIE_CADENCE) += cadence/
obj-$(CONFIG_PCI_FTPCI100) += pci-ftpci100.o
+obj-$(CONFIG_PCI_IXP4XX) += pci-ixp4xx.o
obj-$(CONFIG_PCI_HYPERV) += pci-hyperv.o
obj-$(CONFIG_PCI_HYPERV_INTERFACE) += pci-hyperv-intf.o
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 254d2570f8c9..30db2d68c17a 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -263,9 +263,12 @@ struct cdns_pcie_ops {
* struct cdns_pcie - private data for Cadence PCIe controller drivers
* @reg_base: IO mapped register base
* @mem_res: start/end offsets in the physical system memory to map PCI accesses
+ * @dev: PCIe controller
* @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint.
- * @bus: In Root Complex mode, the bus number
- * @ops: Platform specific ops to control various inputs from Cadence PCIe
+ * @phy_count: number of supported PHY devices
+ * @phy: list of pointers to specific PHY control blocks
+ * @link: list of pointers to corresponding device link representations
+ * @ops: Platform-specific ops to control various inputs from Cadence PCIe
* wrapper
*/
struct cdns_pcie {
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index 0cf1333c0440..80fc98acf097 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -37,6 +37,7 @@
#define IMX8MQ_GPR_PCIE_REF_USE_PAD BIT(9)
#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN BIT(10)
#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE BIT(11)
+#define IMX8MQ_GPR_PCIE_VREG_BYPASS BIT(12)
#define IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE GENMASK(11, 8)
#define IMX8MQ_PCIE2_BASE_ADDR 0x33c00000
@@ -80,6 +81,7 @@ struct imx6_pcie {
u32 tx_swing_full;
u32 tx_swing_low;
struct regulator *vpcie;
+ struct regulator *vph;
void __iomem *phy_base;
/* power domain for pcie */
@@ -621,6 +623,17 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
imx6_pcie_grp_offset(imx6_pcie),
IMX8MQ_GPR_PCIE_REF_USE_PAD,
IMX8MQ_GPR_PCIE_REF_USE_PAD);
+ /*
+ * Regarding the datasheet, the PCIE_VPH is suggested
+ * to be 1.8V. If the PCIE_VPH is supplied by 3.3V, the
+ * VREG_BYPASS should be cleared to zero.
+ */
+ if (imx6_pcie->vph &&
+ regulator_get_voltage(imx6_pcie->vph) > 3000000)
+ regmap_update_bits(imx6_pcie->iomuxc_gpr,
+ imx6_pcie_grp_offset(imx6_pcie),
+ IMX8MQ_GPR_PCIE_VREG_BYPASS,
+ 0);
break;
case IMX7D:
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
@@ -1002,10 +1015,8 @@ static int imx6_pcie_probe(struct platform_device *pdev)
return ret;
}
imx6_pcie->phy_base = devm_ioremap_resource(dev, &res);
- if (IS_ERR(imx6_pcie->phy_base)) {
- dev_err(dev, "Unable to map PCIe PHY\n");
+ if (IS_ERR(imx6_pcie->phy_base))
return PTR_ERR(imx6_pcie->phy_base);
- }
}
dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1130,6 +1141,13 @@ static int imx6_pcie_probe(struct platform_device *pdev)
imx6_pcie->vpcie = NULL;
}
+ imx6_pcie->vph = devm_regulator_get_optional(&pdev->dev, "vph");
+ if (IS_ERR(imx6_pcie->vph)) {
+ if (PTR_ERR(imx6_pcie->vph) != -ENODEV)
+ return PTR_ERR(imx6_pcie->vph);
+ imx6_pcie->vph = NULL;
+ }
+
platform_set_drvdata(pdev, imx6_pcie);
ret = imx6_pcie_attach_pd(dev);
@@ -1175,6 +1193,7 @@ static const struct imx6_pcie_drvdata drvdata[] = {
.variant = IMX6QP,
.flags = IMX6_PCIE_FLAG_IMX6_PHY |
IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE,
+ .dbi_length = 0x200,
},
[IMX7D] = {
.variant = IMX7D,
diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c
index f89a7d24ba28..d15cf35fa7f2 100644
--- a/drivers/pci/controller/dwc/pcie-intel-gw.c
+++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
@@ -39,6 +39,10 @@
#define PCIE_APP_IRN_PM_TO_ACK BIT(9)
#define PCIE_APP_IRN_LINK_AUTO_BW_STAT BIT(11)
#define PCIE_APP_IRN_BW_MGT BIT(12)
+#define PCIE_APP_IRN_INTA BIT(13)
+#define PCIE_APP_IRN_INTB BIT(14)
+#define PCIE_APP_IRN_INTC BIT(15)
+#define PCIE_APP_IRN_INTD BIT(16)
#define PCIE_APP_IRN_MSG_LTR BIT(18)
#define PCIE_APP_IRN_SYS_ERR_RC BIT(29)
#define PCIE_APP_INTX_OFST 12
@@ -48,10 +52,8 @@
PCIE_APP_IRN_RX_VDM_MSG | PCIE_APP_IRN_SYS_ERR_RC | \
PCIE_APP_IRN_PM_TO_ACK | PCIE_APP_IRN_MSG_LTR | \
PCIE_APP_IRN_BW_MGT | PCIE_APP_IRN_LINK_AUTO_BW_STAT | \
- (PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTA) | \
- (PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTB) | \
- (PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTC) | \
- (PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTD))
+ PCIE_APP_IRN_INTA | PCIE_APP_IRN_INTB | \
+ PCIE_APP_IRN_INTC | PCIE_APP_IRN_INTD)
#define BUS_IATU_OFFSET SZ_256M
#define RESET_INTERVAL_MS 100
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 504669e3afe0..3ec7b29d5dc7 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1826,7 +1826,7 @@ static int tegra_pcie_ep_raise_msi_irq(struct tegra_pcie_dw *pcie, u16 irq)
if (unlikely(irq > 31))
return -EINVAL;
- appl_writel(pcie, (1 << irq), APPL_MSI_CTRL_1);
+ appl_writel(pcie, BIT(irq), APPL_MSI_CTRL_1);
return 0;
}
@@ -2214,6 +2214,8 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
goto fail_host_init;
}
+ dw_pcie_setup_rc(&pcie->pci.pp);
+
ret = tegra_pcie_dw_start_link(&pcie->pci);
if (ret < 0)
goto fail_host_init;
diff --git a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
index ee0156921ebc..306950272fd6 100644
--- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
+++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
@@ -42,17 +42,6 @@ struct ls_pcie_g4 {
int irq;
};
-static inline u32 ls_pcie_g4_lut_readl(struct ls_pcie_g4 *pcie, u32 off)
-{
- return ioread32(pcie->pci.csr_axi_slave_base + PCIE_LUT_OFF + off);
-}
-
-static inline void ls_pcie_g4_lut_writel(struct ls_pcie_g4 *pcie,
- u32 off, u32 val)
-{
- iowrite32(val, pcie->pci.csr_axi_slave_base + PCIE_LUT_OFF + off);
-}
-
static inline u32 ls_pcie_g4_pf_readl(struct ls_pcie_g4 *pcie, u32 off)
{
return ioread32(pcie->pci.csr_axi_slave_base + PCIE_PF_OFF + off);
diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c
index e3f5e7ab7606..c95ebe808f92 100644
--- a/drivers/pci/controller/pci-aardvark.c
+++ b/drivers/pci/controller/pci-aardvark.c
@@ -57,7 +57,7 @@
#define PIO_COMPLETION_STATUS_UR 1
#define PIO_COMPLETION_STATUS_CRS 2
#define PIO_COMPLETION_STATUS_CA 4
-#define PIO_NON_POSTED_REQ BIT(0)
+#define PIO_NON_POSTED_REQ BIT(10)
#define PIO_ADDR_LS (PIO_BASE_ADDR + 0x8)
#define PIO_ADDR_MS (PIO_BASE_ADDR + 0xc)
#define PIO_WR_DATA (PIO_BASE_ADDR + 0x10)
@@ -125,6 +125,7 @@
#define LTSSM_MASK 0x3f
#define LTSSM_L0 0x10
#define RC_BAR_CONFIG 0x300
+#define VENDOR_ID_REG (LMI_BASE_ADDR + 0x44)
/* PCIe core controller registers */
#define CTRL_CORE_BASE_ADDR 0x18000
@@ -385,6 +386,16 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
reg |= (IS_RC_MSK << IS_RC_SHIFT);
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+ /*
+ * Replace incorrect PCI vendor id value 0x1b4b by correct value 0x11ab.
+ * VENDOR_ID_REG contains vendor id in low 16 bits and subsystem vendor
+ * id in high 16 bits. Updating this register changes readback value of
+ * read-only vendor id bits in PCIE_CORE_DEV_ID_REG register. Workaround
+ * for erratum 4.1: "The value of device and vendor ID is incorrect".
+ */
+ reg = (PCI_VENDOR_ID_MARVELL << 16) | PCI_VENDOR_ID_MARVELL;
+ advk_writel(pcie, reg, VENDOR_ID_REG);
+
/* Set Advanced Error Capabilities and Control PF0 register */
reg = PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX |
PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN |
diff --git a/drivers/pci/controller/pci-ftpci100.c b/drivers/pci/controller/pci-ftpci100.c
index da3cd216da00..aefef1986201 100644
--- a/drivers/pci/controller/pci-ftpci100.c
+++ b/drivers/pci/controller/pci-ftpci100.c
@@ -34,12 +34,12 @@
* Special configuration registers directly in the first few words
* in I/O space.
*/
-#define PCI_IOSIZE 0x00
-#define PCI_PROT 0x04 /* AHB protection */
-#define PCI_CTRL 0x08 /* PCI control signal */
-#define PCI_SOFTRST 0x10 /* Soft reset counter and response error enable */
-#define PCI_CONFIG 0x28 /* PCI configuration command register */
-#define PCI_DATA 0x2C
+#define FTPCI_IOSIZE 0x00
+#define FTPCI_PROT 0x04 /* AHB protection */
+#define FTPCI_CTRL 0x08 /* PCI control signal */
+#define FTPCI_SOFTRST 0x10 /* Soft reset counter and response error enable */
+#define FTPCI_CONFIG 0x28 /* PCI configuration command register */
+#define FTPCI_DATA 0x2C
#define FARADAY_PCI_STATUS_CMD 0x04 /* Status and command */
#define FARADAY_PCI_PMC 0x40 /* Power management control */
@@ -195,9 +195,9 @@ static int faraday_raw_pci_read_config(struct faraday_pci *p, int bus_number,
PCI_CONF_FUNCTION(PCI_FUNC(fn)) |
PCI_CONF_WHERE(config) |
PCI_CONF_ENABLE,
- p->base + PCI_CONFIG);
+ p->base + FTPCI_CONFIG);
- *value = readl(p->base + PCI_DATA);
+ *value = readl(p->base + FTPCI_DATA);
if (size == 1)
*value = (*value >> (8 * (config & 3))) & 0xFF;
@@ -230,17 +230,17 @@ static int faraday_raw_pci_write_config(struct faraday_pci *p, int bus_number,
PCI_CONF_FUNCTION(PCI_FUNC(fn)) |
PCI_CONF_WHERE(config) |
PCI_CONF_ENABLE,
- p->base + PCI_CONFIG);
+ p->base + FTPCI_CONFIG);
switch (size) {
case 4:
- writel(value, p->base + PCI_DATA);
+ writel(value, p->base + FTPCI_DATA);
break;
case 2:
- writew(value, p->base + PCI_DATA + (config & 3));
+ writew(value, p->base + FTPCI_DATA + (config & 3));
break;
case 1:
- writeb(value, p->base + PCI_DATA + (config & 3));
+ writeb(value, p->base + FTPCI_DATA + (config & 3));
break;
default:
ret = PCIBIOS_BAD_REGISTER_NUMBER;
@@ -469,7 +469,7 @@ static int faraday_pci_probe(struct platform_device *pdev)
if (!faraday_res_to_memcfg(io->start - win->offset,
resource_size(io), &val)) {
/* setup I/O space size */
- writel(val, p->base + PCI_IOSIZE);
+ writel(val, p->base + FTPCI_IOSIZE);
} else {
dev_err(dev, "illegal IO mem size\n");
return -EINVAL;
@@ -477,11 +477,11 @@ static int faraday_pci_probe(struct platform_device *pdev)
}
/* Setup hostbridge */
- val = readl(p->base + PCI_CTRL);
+ val = readl(p->base + FTPCI_CTRL);
val |= PCI_COMMAND_IO;
val |= PCI_COMMAND_MEMORY;
val |= PCI_COMMAND_MASTER;
- writel(val, p->base + PCI_CTRL);
+ writel(val, p->base + FTPCI_CTRL);
/* Mask and clear all interrupts */
faraday_raw_pci_write_config(p, 0, 0, FARADAY_PCI_CTRL2 + 2, 2, 0xF000);
if (variant->cascaded_irq) {
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index 6511648271b2..a53bd8728d0d 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -444,7 +444,6 @@ enum hv_pcibus_state {
hv_pcibus_probed,
hv_pcibus_installed,
hv_pcibus_removing,
- hv_pcibus_removed,
hv_pcibus_maximum
};
@@ -453,7 +452,6 @@ struct hv_pcibus_device {
/* Protocol version negotiated with the host */
enum pci_protocol_version_t protocol_version;
enum hv_pcibus_state state;
- refcount_t remove_lock;
struct hv_device *hdev;
resource_size_t low_mmio_space;
resource_size_t high_mmio_space;
@@ -461,7 +459,6 @@ struct hv_pcibus_device {
struct resource *low_mmio_res;
struct resource *high_mmio_res;
struct completion *survey_event;
- struct completion remove_event;
struct pci_bus *pci_bus;
spinlock_t config_lock; /* Avoid two threads writing index page */
spinlock_t device_list_lock; /* Protect lists below */
@@ -593,9 +590,6 @@ static void put_pcichild(struct hv_pci_dev *hpdev)
kfree(hpdev);
}
-static void get_hvpcibus(struct hv_pcibus_device *hv_pcibus);
-static void put_hvpcibus(struct hv_pcibus_device *hv_pcibus);
-
/*
* There is no good way to get notified from vmbus_onoffer_rescind(),
* so let's use polling here, since this is not a hot path.
@@ -2064,10 +2058,8 @@ static void pci_devices_present_work(struct work_struct *work)
}
spin_unlock_irqrestore(&hbus->device_list_lock, flags);
- if (!dr) {
- put_hvpcibus(hbus);
+ if (!dr)
return;
- }
/* First, mark all existing children as reported missing. */
spin_lock_irqsave(&hbus->device_list_lock, flags);
@@ -2150,7 +2142,6 @@ static void pci_devices_present_work(struct work_struct *work)
break;
}
- put_hvpcibus(hbus);
kfree(dr);
}
@@ -2191,12 +2182,10 @@ static int hv_pci_start_relations_work(struct hv_pcibus_device *hbus,
list_add_tail(&dr->list_entry, &hbus->dr_list);
spin_unlock_irqrestore(&hbus->device_list_lock, flags);
- if (pending_dr) {
+ if (pending_dr)
kfree(dr_wrk);
- } else {
- get_hvpcibus(hbus);
+ else
queue_work(hbus->wq, &dr_wrk->wrk);
- }
return 0;
}
@@ -2339,8 +2328,6 @@ static void hv_eject_device_work(struct work_struct *work)
put_pcichild(hpdev);
put_pcichild(hpdev);
/* hpdev has been freed. Do not use it any more. */
-
- put_hvpcibus(hbus);
}
/**
@@ -2364,7 +2351,6 @@ static void hv_pci_eject_device(struct hv_pci_dev *hpdev)
hpdev->state = hv_pcichild_ejecting;
get_pcichild(hpdev);
INIT_WORK(&hpdev->wrk, hv_eject_device_work);
- get_hvpcibus(hbus);
queue_work(hbus->wq, &hpdev->wrk);
}
@@ -2964,17 +2950,6 @@ static int hv_send_resources_released(struct hv_device *hdev)
return 0;
}
-static void get_hvpcibus(struct hv_pcibus_device *hbus)
-{
- refcount_inc(&hbus->remove_lock);
-}
-
-static void put_hvpcibus(struct hv_pcibus_device *hbus)
-{
- if (refcount_dec_and_test(&hbus->remove_lock))
- complete(&hbus->remove_event);
-}
-
#define HVPCI_DOM_MAP_SIZE (64 * 1024)
static DECLARE_BITMAP(hvpci_dom_map, HVPCI_DOM_MAP_SIZE);
@@ -3094,14 +3069,12 @@ static int hv_pci_probe(struct hv_device *hdev,
hbus->sysdata.domain = dom;
hbus->hdev = hdev;
- refcount_set(&hbus->remove_lock, 1);
INIT_LIST_HEAD(&hbus->children);
INIT_LIST_HEAD(&hbus->dr_list);
INIT_LIST_HEAD(&hbus->resources_for_children);
spin_lock_init(&hbus->config_lock);
spin_lock_init(&hbus->device_list_lock);
spin_lock_init(&hbus->retarget_msi_interrupt_lock);
- init_completion(&hbus->remove_event);
hbus->wq = alloc_ordered_workqueue("hv_pci_%x", 0,
hbus->sysdata.domain);
if (!hbus->wq) {
@@ -3243,8 +3216,9 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs)
struct pci_packet teardown_packet;
u8 buffer[sizeof(struct pci_message)];
} pkt;
- struct hv_dr_state *dr;
struct hv_pci_compl comp_pkt;
+ struct hv_pci_dev *hpdev, *tmp;
+ unsigned long flags;
int ret;
/*
@@ -3256,9 +3230,16 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs)
if (!keep_devs) {
/* Delete any children which might still exist. */
- dr = kzalloc(sizeof(*dr), GFP_KERNEL);
- if (dr && hv_pci_start_relations_work(hbus, dr))
- kfree(dr);
+ spin_lock_irqsave(&hbus->device_list_lock, flags);
+ list_for_each_entry_safe(hpdev, tmp, &hbus->children, list_entry) {
+ list_del(&hpdev->list_entry);
+ if (hpdev->pci_slot)
+ pci_destroy_slot(hpdev->pci_slot);
+ /* For the two refs got in new_pcichild_device() */
+ put_pcichild(hpdev);
+ put_pcichild(hpdev);
+ }
+ spin_unlock_irqrestore(&hbus->device_list_lock, flags);
}
ret = hv_send_resources_released(hdev);
@@ -3301,13 +3282,23 @@ static int hv_pci_remove(struct hv_device *hdev)
hbus = hv_get_drvdata(hdev);
if (hbus->state == hv_pcibus_installed) {
+ tasklet_disable(&hdev->channel->callback_event);
+ hbus->state = hv_pcibus_removing;
+ tasklet_enable(&hdev->channel->callback_event);
+ destroy_workqueue(hbus->wq);
+ hbus->wq = NULL;
+ /*
+ * At this point, no work is running or can be scheduled
+ * on hbus-wq. We can't race with hv_pci_devices_present()
+ * or hv_pci_eject_device(), it's safe to proceed.
+ */
+
/* Remove the bus from PCI's point of view. */
pci_lock_rescan_remove();
pci_stop_root_bus(hbus->pci_bus);
hv_pci_remove_slots(hbus);
pci_remove_root_bus(hbus->pci_bus);
pci_unlock_rescan_remove();
- hbus->state = hv_pcibus_removed;
}
ret = hv_pci_bus_exit(hdev, false);
@@ -3320,9 +3311,6 @@ static int hv_pci_remove(struct hv_device *hdev)
hv_pci_free_bridge_windows(hbus);
irq_domain_remove(hbus->irq_domain);
irq_domain_free_fwnode(hbus->sysdata.fwnode);
- put_hvpcibus(hbus);
- wait_for_completion(&hbus->remove_event);
- destroy_workqueue(hbus->wq);
hv_put_dom_num(hbus->sysdata.domain);
@@ -3476,6 +3464,9 @@ static void __exit exit_hv_pci_drv(void)
static int __init init_hv_pci_drv(void)
{
+ if (!hv_is_hyperv_initialized())
+ return -ENODEV;
+
/* Set the invalid domain number's bit, so it will not be used */
set_bit(HVPCI_DOM_INVALID, hvpci_dom_map);
diff --git a/drivers/pci/controller/pci-ixp4xx.c b/drivers/pci/controller/pci-ixp4xx.c
new file mode 100644
index 000000000000..896a45b24236
--- /dev/null
+++ b/drivers/pci/controller/pci-ixp4xx.c
@@ -0,0 +1,671 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support for Intel IXP4xx PCI host controller
+ *
+ * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * Based on the IXP4xx arch/arm/mach-ixp4xx/common-pci.c driver
+ * Copyright (C) 2002 Intel Corporation
+ * Copyright (C) 2003 Greg Ungerer <gerg@linux-m68k.org>
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ * Copyright (C) 2005 Deepak Saxena <dsaxena@plexity.net>
+ * Copyright (C) 2005 Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * TODO:
+ * - Test IO-space access
+ * - DMA support
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_pci.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/bits.h>
+
+/* Register offsets */
+#define IXP4XX_PCI_NP_AD 0x00
+#define IXP4XX_PCI_NP_CBE 0x04
+#define IXP4XX_PCI_NP_WDATA 0x08
+#define IXP4XX_PCI_NP_RDATA 0x0c
+#define IXP4XX_PCI_CRP_AD_CBE 0x10
+#define IXP4XX_PCI_CRP_WDATA 0x14
+#define IXP4XX_PCI_CRP_RDATA 0x18
+#define IXP4XX_PCI_CSR 0x1c
+#define IXP4XX_PCI_ISR 0x20
+#define IXP4XX_PCI_INTEN 0x24
+#define IXP4XX_PCI_DMACTRL 0x28
+#define IXP4XX_PCI_AHBMEMBASE 0x2c
+#define IXP4XX_PCI_AHBIOBASE 0x30
+#define IXP4XX_PCI_PCIMEMBASE 0x34
+#define IXP4XX_PCI_AHBDOORBELL 0x38
+#define IXP4XX_PCI_PCIDOORBELL 0x3c
+#define IXP4XX_PCI_ATPDMA0_AHBADDR 0x40
+#define IXP4XX_PCI_ATPDMA0_PCIADDR 0x44
+#define IXP4XX_PCI_ATPDMA0_LENADDR 0x48
+#define IXP4XX_PCI_ATPDMA1_AHBADDR 0x4c
+#define IXP4XX_PCI_ATPDMA1_PCIADDR 0x50
+#define IXP4XX_PCI_ATPDMA1_LENADDR 0x54
+
+/* CSR bit definitions */
+#define IXP4XX_PCI_CSR_HOST BIT(0)
+#define IXP4XX_PCI_CSR_ARBEN BIT(1)
+#define IXP4XX_PCI_CSR_ADS BIT(2)
+#define IXP4XX_PCI_CSR_PDS BIT(3)
+#define IXP4XX_PCI_CSR_ABE BIT(4)
+#define IXP4XX_PCI_CSR_DBT BIT(5)
+#define IXP4XX_PCI_CSR_ASE BIT(8)
+#define IXP4XX_PCI_CSR_IC BIT(15)
+#define IXP4XX_PCI_CSR_PRST BIT(16)
+
+/* ISR (Interrupt status) Register bit definitions */
+#define IXP4XX_PCI_ISR_PSE BIT(0)
+#define IXP4XX_PCI_ISR_PFE BIT(1)
+#define IXP4XX_PCI_ISR_PPE BIT(2)
+#define IXP4XX_PCI_ISR_AHBE BIT(3)
+#define IXP4XX_PCI_ISR_APDC BIT(4)
+#define IXP4XX_PCI_ISR_PADC BIT(5)
+#define IXP4XX_PCI_ISR_ADB BIT(6)
+#define IXP4XX_PCI_ISR_PDB BIT(7)
+
+/* INTEN (Interrupt Enable) Register bit definitions */
+#define IXP4XX_PCI_INTEN_PSE BIT(0)
+#define IXP4XX_PCI_INTEN_PFE BIT(1)
+#define IXP4XX_PCI_INTEN_PPE BIT(2)
+#define IXP4XX_PCI_INTEN_AHBE BIT(3)
+#define IXP4XX_PCI_INTEN_APDC BIT(4)
+#define IXP4XX_PCI_INTEN_PADC BIT(5)
+#define IXP4XX_PCI_INTEN_ADB BIT(6)
+#define IXP4XX_PCI_INTEN_PDB BIT(7)
+
+/* Shift value for byte enable on NP cmd/byte enable register */
+#define IXP4XX_PCI_NP_CBE_BESL 4
+
+/* PCI commands supported by NP access unit */
+#define NP_CMD_IOREAD 0x2
+#define NP_CMD_IOWRITE 0x3
+#define NP_CMD_CONFIGREAD 0xa
+#define NP_CMD_CONFIGWRITE 0xb
+#define NP_CMD_MEMREAD 0x6
+#define NP_CMD_MEMWRITE 0x7
+
+/* Constants for CRP access into local config space */
+#define CRP_AD_CBE_BESL 20
+#define CRP_AD_CBE_WRITE 0x00010000
+
+/* Special PCI configuration space registers for this controller */
+#define IXP4XX_PCI_RTOTTO 0x40
+
+struct ixp4xx_pci {
+ struct device *dev;
+ void __iomem *base;
+ bool errata_hammer;
+ bool host_mode;
+};
+
+/*
+ * The IXP4xx has a peculiar address bus that will change the
+ * byte order on SoC peripherals depending on whether the device
+ * operates in big-endian or little-endian mode. That means that
+ * readl() and writel() that always use little-endian access
+ * will not work for SoC peripherals such as the PCI controller
+ * when used in big-endian mode. The accesses to the individual
+ * PCI devices on the other hand, are always little-endian and
+ * can use readl() and writel().
+ *
+ * For local AHB bus access we need to use __raw_[readl|writel]()
+ * to make sure that we access the SoC devices in the CPU native
+ * endianness.
+ */
+static inline u32 ixp4xx_readl(struct ixp4xx_pci *p, u32 reg)
+{
+ return __raw_readl(p->base + reg);
+}
+
+static inline void ixp4xx_writel(struct ixp4xx_pci *p, u32 reg, u32 val)
+{
+ __raw_writel(val, p->base + reg);
+}
+
+static int ixp4xx_pci_check_master_abort(struct ixp4xx_pci *p)
+{
+ u32 isr = ixp4xx_readl(p, IXP4XX_PCI_ISR);
+
+ if (isr & IXP4XX_PCI_ISR_PFE) {
+ /* Make sure the master abort bit is reset */
+ ixp4xx_writel(p, IXP4XX_PCI_ISR, IXP4XX_PCI_ISR_PFE);
+ dev_dbg(p->dev, "master abort detected\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ixp4xx_pci_read(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 *data)
+{
+ ixp4xx_writel(p, IXP4XX_PCI_NP_AD, addr);
+
+ if (p->errata_hammer) {
+ int i;
+
+ /*
+ * PCI workaround - only works if NP PCI space reads have
+ * no side effects. Hammer the register and read twice 8
+ * times. last one will be good.
+ */
+ for (i = 0; i < 8; i++) {
+ ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd);
+ *data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA);
+ *data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA);
+ }
+ } else {
+ ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd);
+ *data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA);
+ }
+
+ return ixp4xx_pci_check_master_abort(p);
+}
+
+static int ixp4xx_pci_write(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 data)
+{
+ ixp4xx_writel(p, IXP4XX_PCI_NP_AD, addr);
+
+ /* Set up the write */
+ ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd);
+
+ /* Execute the write by writing to NP_WDATA */
+ ixp4xx_writel(p, IXP4XX_PCI_NP_WDATA, data);
+
+ return ixp4xx_pci_check_master_abort(p);
+}
+
+static u32 ixp4xx_config_addr(u8 bus_num, u16 devfn, int where)
+{
+ /* Root bus is always 0 in this hardware */
+ if (bus_num == 0) {
+ /* type 0 */
+ return BIT(32-PCI_SLOT(devfn)) | ((PCI_FUNC(devfn)) << 8) |
+ (where & ~3);
+ } else {
+ /* type 1 */
+ return (bus_num << 16) | ((PCI_SLOT(devfn)) << 11) |
+ ((PCI_FUNC(devfn)) << 8) | (where & ~3) | 1;
+ }
+}
+
+/*
+ * CRP functions are "Controller Configuration Port" accesses
+ * initiated from within this driver itself to read/write PCI
+ * control information in the config space.
+ */
+static u32 ixp4xx_crp_byte_lane_enable_bits(u32 n, int size)
+{
+ if (size == 1)
+ return (0xf & ~BIT(n)) << CRP_AD_CBE_BESL;
+ if (size == 2)
+ return (0xf & ~(BIT(n) | BIT(n+1))) << CRP_AD_CBE_BESL;
+ if (size == 4)
+ return 0;
+ return 0xffffffff;
+}
+
+static int ixp4xx_crp_read_config(struct ixp4xx_pci *p, int where, int size,
+ u32 *value)
+{
+ u32 n, cmd, val;
+
+ n = where % 4;
+ cmd = where & ~3;
+
+ dev_dbg(p->dev, "%s from %d size %d cmd %08x\n",
+ __func__, where, size, cmd);
+
+ ixp4xx_writel(p, IXP4XX_PCI_CRP_AD_CBE, cmd);
+ val = ixp4xx_readl(p, IXP4XX_PCI_CRP_RDATA);
+
+ val >>= (8*n);
+ switch (size) {
+ case 1:
+ val &= U8_MAX;
+ dev_dbg(p->dev, "%s read byte %02x\n", __func__, val);
+ break;
+ case 2:
+ val &= U16_MAX;
+ dev_dbg(p->dev, "%s read word %04x\n", __func__, val);
+ break;
+ case 4:
+ val &= U32_MAX;
+ dev_dbg(p->dev, "%s read long %08x\n", __func__, val);
+ break;
+ default:
+ /* Should not happen */
+ dev_err(p->dev, "%s illegal size\n", __func__);
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *value = val;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int ixp4xx_crp_write_config(struct ixp4xx_pci *p, int where, int size,
+ u32 value)
+{
+ u32 n, cmd, val;
+
+ n = where % 4;
+ cmd = ixp4xx_crp_byte_lane_enable_bits(n, size);
+ if (cmd == 0xffffffff)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ cmd |= where & ~3;
+ cmd |= CRP_AD_CBE_WRITE;
+
+ val = value << (8*n);
+
+ dev_dbg(p->dev, "%s to %d size %d cmd %08x val %08x\n",
+ __func__, where, size, cmd, val);
+
+ ixp4xx_writel(p, IXP4XX_PCI_CRP_AD_CBE, cmd);
+ ixp4xx_writel(p, IXP4XX_PCI_CRP_WDATA, val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ * Then follows the functions that read and write from the common PCI
+ * configuration space.
+ */
+static u32 ixp4xx_byte_lane_enable_bits(u32 n, int size)
+{
+ if (size == 1)
+ return (0xf & ~BIT(n)) << 4;
+ if (size == 2)
+ return (0xf & ~(BIT(n) | BIT(n+1))) << 4;
+ if (size == 4)
+ return 0;
+ return 0xffffffff;
+}
+
+static int ixp4xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *value)
+{
+ struct ixp4xx_pci *p = bus->sysdata;
+ u32 n, addr, val, cmd;
+ u8 bus_num = bus->number;
+ int ret;
+
+ *value = 0xffffffff;
+ n = where % 4;
+ cmd = ixp4xx_byte_lane_enable_bits(n, size);
+ if (cmd == 0xffffffff)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ addr = ixp4xx_config_addr(bus_num, devfn, where);
+ cmd |= NP_CMD_CONFIGREAD;
+ dev_dbg(p->dev, "read_config from %d size %d dev %d:%d:%d address: %08x cmd: %08x\n",
+ where, size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), addr, cmd);
+
+ ret = ixp4xx_pci_read(p, addr, cmd, &val);
+ if (ret)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ val >>= (8*n);
+ switch (size) {
+ case 1:
+ val &= U8_MAX;
+ dev_dbg(p->dev, "%s read byte %02x\n", __func__, val);
+ break;
+ case 2:
+ val &= U16_MAX;
+ dev_dbg(p->dev, "%s read word %04x\n", __func__, val);
+ break;
+ case 4:
+ val &= U32_MAX;
+ dev_dbg(p->dev, "%s read long %08x\n", __func__, val);
+ break;
+ default:
+ /* Should not happen */
+ dev_err(p->dev, "%s illegal size\n", __func__);
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *value = val;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int ixp4xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 value)
+{
+ struct ixp4xx_pci *p = bus->sysdata;
+ u32 n, addr, val, cmd;
+ u8 bus_num = bus->number;
+ int ret;
+
+ n = where % 4;
+ cmd = ixp4xx_byte_lane_enable_bits(n, size);
+ if (cmd == 0xffffffff)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ addr = ixp4xx_config_addr(bus_num, devfn, where);
+ cmd |= NP_CMD_CONFIGWRITE;
+ val = value << (8*n);
+
+ dev_dbg(p->dev, "write_config_byte %#x to %d size %d dev %d:%d:%d addr: %08x cmd %08x\n",
+ value, where, size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), addr, cmd);
+
+ ret = ixp4xx_pci_write(p, addr, cmd, val);
+ if (ret)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops ixp4xx_pci_ops = {
+ .read = ixp4xx_pci_read_config,
+ .write = ixp4xx_pci_write_config,
+};
+
+static u32 ixp4xx_pci_addr_to_64mconf(phys_addr_t addr)
+{
+ u8 base;
+
+ base = ((addr & 0xff000000) >> 24);
+ return (base << 24) | ((base + 1) << 16)
+ | ((base + 2) << 8) | (base + 3);
+}
+
+static int ixp4xx_pci_parse_map_ranges(struct ixp4xx_pci *p)
+{
+ struct device *dev = p->dev;
+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(p);
+ struct resource_entry *win;
+ struct resource *res;
+ phys_addr_t addr;
+
+ win = resource_list_first_type(&bridge->windows, IORESOURCE_MEM);
+ if (win) {
+ u32 pcimembase;
+
+ res = win->res;
+ addr = res->start - win->offset;
+
+ if (res->flags & IORESOURCE_PREFETCH)
+ res->name = "IXP4xx PCI PRE-MEM";
+ else
+ res->name = "IXP4xx PCI NON-PRE-MEM";
+
+ dev_dbg(dev, "%s window %pR, bus addr %pa\n",
+ res->name, res, &addr);
+ if (resource_size(res) != SZ_64M) {
+ dev_err(dev, "memory range is not 64MB\n");
+ return -EINVAL;
+ }
+
+ pcimembase = ixp4xx_pci_addr_to_64mconf(addr);
+ /* Commit configuration */
+ ixp4xx_writel(p, IXP4XX_PCI_PCIMEMBASE, pcimembase);
+ } else {
+ dev_err(dev, "no AHB memory mapping defined\n");
+ }
+
+ win = resource_list_first_type(&bridge->windows, IORESOURCE_IO);
+ if (win) {
+ res = win->res;
+
+ addr = pci_pio_to_address(res->start);
+ if (addr & 0xff) {
+ dev_err(dev, "IO mem at uneven address: %pa\n", &addr);
+ return -EINVAL;
+ }
+
+ res->name = "IXP4xx PCI IO MEM";
+ /*
+ * Setup I/O space location for PCI->AHB access, the
+ * upper 24 bits of the address goes into the lower
+ * 24 bits of this register.
+ */
+ ixp4xx_writel(p, IXP4XX_PCI_AHBIOBASE, (addr >> 8));
+ } else {
+ dev_info(dev, "no IO space AHB memory mapping defined\n");
+ }
+
+ return 0;
+}
+
+static int ixp4xx_pci_parse_map_dma_ranges(struct ixp4xx_pci *p)
+{
+ struct device *dev = p->dev;
+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(p);
+ struct resource_entry *win;
+ struct resource *res;
+ phys_addr_t addr;
+ u32 ahbmembase;
+
+ win = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM);
+ if (win) {
+ res = win->res;
+ addr = res->start - win->offset;
+
+ if (resource_size(res) != SZ_64M) {
+ dev_err(dev, "DMA memory range is not 64MB\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "DMA MEM BASE: %pa\n", &addr);
+ /*
+ * 4 PCI-to-AHB windows of 16 MB each, write the 8 high bits
+ * into each byte of the PCI_AHBMEMBASE register.
+ */
+ ahbmembase = ixp4xx_pci_addr_to_64mconf(addr);
+ /* Commit AHB membase */
+ ixp4xx_writel(p, IXP4XX_PCI_AHBMEMBASE, ahbmembase);
+ } else {
+ dev_err(dev, "no DMA memory range defined\n");
+ }
+
+ return 0;
+}
+
+/* Only used to get context for abort handling */
+static struct ixp4xx_pci *ixp4xx_pci_abort_singleton;
+
+static int ixp4xx_pci_abort_handler(unsigned long addr, unsigned int fsr,
+ struct pt_regs *regs)
+{
+ struct ixp4xx_pci *p = ixp4xx_pci_abort_singleton;
+ u32 isr, status;
+ int ret;
+
+ isr = ixp4xx_readl(p, IXP4XX_PCI_ISR);
+ ret = ixp4xx_crp_read_config(p, PCI_STATUS, 2, &status);
+ if (ret) {
+ dev_err(p->dev, "unable to read abort status\n");
+ return -EINVAL;
+ }
+
+ dev_err(p->dev,
+ "PCI: abort_handler addr = %#lx, isr = %#x, status = %#x\n",
+ addr, isr, status);
+
+ /* Make sure the Master Abort bit is reset */
+ ixp4xx_writel(p, IXP4XX_PCI_ISR, IXP4XX_PCI_ISR_PFE);
+ status |= PCI_STATUS_REC_MASTER_ABORT;
+ ret = ixp4xx_crp_write_config(p, PCI_STATUS, 2, status);
+ if (ret)
+ dev_err(p->dev, "unable to clear abort status bit\n");
+
+ /*
+ * If it was an imprecise abort, then we need to correct the
+ * return address to be _after_ the instruction.
+ */
+ if (fsr & (1 << 10)) {
+ dev_err(p->dev, "imprecise abort\n");
+ regs->ARM_pc += 4;
+ }
+
+ return 0;
+}
+
+static int __init ixp4xx_pci_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct ixp4xx_pci *p;
+ struct pci_host_bridge *host;
+ int ret;
+ u32 val;
+ phys_addr_t addr;
+ u32 basereg[4] = {
+ PCI_BASE_ADDRESS_0,
+ PCI_BASE_ADDRESS_1,
+ PCI_BASE_ADDRESS_2,
+ PCI_BASE_ADDRESS_3,
+ };
+ int i;
+
+ host = devm_pci_alloc_host_bridge(dev, sizeof(*p));
+ if (!host)
+ return -ENOMEM;
+
+ host->ops = &ixp4xx_pci_ops;
+ p = pci_host_bridge_priv(host);
+ host->sysdata = p;
+ p->dev = dev;
+ dev_set_drvdata(dev, p);
+
+ /*
+ * Set up quirk for erratic behaviour in the 42x variant
+ * when accessing config space.
+ */
+ if (of_device_is_compatible(np, "intel,ixp42x-pci")) {
+ p->errata_hammer = true;
+ dev_info(dev, "activate hammering errata\n");
+ }
+
+ p->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(p->base))
+ return PTR_ERR(p->base);
+
+ val = ixp4xx_readl(p, IXP4XX_PCI_CSR);
+ p->host_mode = !!(val & IXP4XX_PCI_CSR_HOST);
+ dev_info(dev, "controller is in %s mode\n",
+ p->host_mode ? "host" : "option");
+
+ /* Hook in our fault handler for PCI errors */
+ ixp4xx_pci_abort_singleton = p;
+ hook_fault_code(16+6, ixp4xx_pci_abort_handler, SIGBUS, 0,
+ "imprecise external abort");
+
+ ret = ixp4xx_pci_parse_map_ranges(p);
+ if (ret)
+ return ret;
+
+ ret = ixp4xx_pci_parse_map_dma_ranges(p);
+ if (ret)
+ return ret;
+
+ /* This is only configured in host mode */
+ if (p->host_mode) {
+ addr = __pa(PAGE_OFFSET);
+ /* This is a noop (0x00) but explains what is going on */
+ addr |= PCI_BASE_ADDRESS_SPACE_MEMORY;
+
+ for (i = 0; i < 4; i++) {
+ /* Write this directly into the config space */
+ ret = ixp4xx_crp_write_config(p, basereg[i], 4, addr);
+ if (ret)
+ dev_err(dev, "failed to set up PCI_BASE_ADDRESS_%d\n", i);
+ else
+ dev_info(dev, "set PCI_BASE_ADDR_%d to %pa\n", i, &addr);
+ addr += SZ_16M;
+ }
+
+ /*
+ * Enable CSR window at 64 MiB to allow PCI masters to continue
+ * prefetching past the 64 MiB boundary, if all AHB to PCI
+ * windows are consecutive.
+ */
+ ret = ixp4xx_crp_write_config(p, PCI_BASE_ADDRESS_4, 4, addr);
+ if (ret)
+ dev_err(dev, "failed to set up PCI_BASE_ADDRESS_4\n");
+ else
+ dev_info(dev, "set PCI_BASE_ADDR_4 to %pa\n", &addr);
+
+ /*
+ * Put the IO memory window at the very end of physical memory
+ * at 0xfffffc00. This is when the system is trying to access IO
+ * memory over AHB.
+ */
+ addr = 0xfffffc00;
+ addr |= PCI_BASE_ADDRESS_SPACE_IO;
+ ret = ixp4xx_crp_write_config(p, PCI_BASE_ADDRESS_5, 4, addr);
+ if (ret)
+ dev_err(dev, "failed to set up PCI_BASE_ADDRESS_5\n");
+ else
+ dev_info(dev, "set PCI_BASE_ADDR_5 to %pa\n", &addr);
+
+ /*
+ * Retry timeout to 0x80
+ * Transfer ready timeout to 0xff
+ */
+ ret = ixp4xx_crp_write_config(p, IXP4XX_PCI_RTOTTO, 4,
+ 0x000080ff);
+ if (ret)
+ dev_err(dev, "failed to set up TRDY limit\n");
+ else
+ dev_info(dev, "set TRDY limit to 0x80ff\n");
+ }
+
+ /* Clear interrupts */
+ val = IXP4XX_PCI_ISR_PSE | IXP4XX_PCI_ISR_PFE | IXP4XX_PCI_ISR_PPE | IXP4XX_PCI_ISR_AHBE;
+ ixp4xx_writel(p, IXP4XX_PCI_ISR, val);
+
+ /*
+ * Set Initialize Complete in PCI Control Register: allow IXP4XX to
+ * generate PCI configuration cycles. Specify that the AHB bus is
+ * operating in big-endian mode. Set up byte lane swapping between
+ * little-endian PCI and the big-endian AHB bus.
+ */
+ val = IXP4XX_PCI_CSR_IC | IXP4XX_PCI_CSR_ABE;
+ if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ val |= (IXP4XX_PCI_CSR_PDS | IXP4XX_PCI_CSR_ADS);
+ ixp4xx_writel(p, IXP4XX_PCI_CSR, val);
+
+ ret = ixp4xx_crp_write_config(p, PCI_COMMAND, 2, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+ if (ret)
+ dev_err(dev, "unable to initialize master and command memory\n");
+ else
+ dev_info(dev, "initialized as master\n");
+
+ pci_host_probe(host);
+
+ return 0;
+}
+
+static const struct of_device_id ixp4xx_pci_of_match[] = {
+ {
+ .compatible = "intel,ixp42x-pci",
+ },
+ {
+ .compatible = "intel,ixp43x-pci",
+ },
+ {},
+};
+
+/*
+ * This driver needs to be a builtin module with suppressed bind
+ * attributes since the probe() is initializing a hard exception
+ * handler and this can only be done from __init-tagged code
+ * sections. This module cannot be removed and inserted at all.
+ */
+static struct platform_driver ixp4xx_pci_driver = {
+ .driver = {
+ .name = "ixp4xx-pci",
+ .suppress_bind_attrs = true,
+ .of_match_table = ixp4xx_pci_of_match,
+ },
+};
+builtin_platform_driver_probe(ixp4xx_pci_driver, ixp4xx_pci_probe);
diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c
index 8069bd9232d4..c979229a6d0d 100644
--- a/drivers/pci/controller/pci-tegra.c
+++ b/drivers/pci/controller/pci-tegra.c
@@ -2539,6 +2539,7 @@ static const struct of_device_id tegra_pcie_of_match[] = {
{ .compatible = "nvidia,tegra20-pcie", .data = &tegra20_pcie },
{ },
};
+MODULE_DEVICE_TABLE(of, tegra_pcie_of_match);
static void *tegra_pcie_ports_seq_start(struct seq_file *s, loff_t *pos)
{
diff --git a/drivers/pci/controller/pci-xgene.c b/drivers/pci/controller/pci-xgene.c
index 7f503dd4ff81..e64536047b65 100644
--- a/drivers/pci/controller/pci-xgene.c
+++ b/drivers/pci/controller/pci-xgene.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
-/**
+/*
* APM X-Gene PCIe Driver
*
* Copyright (c) 2014 Applied Micro Circuits Corporation.
@@ -485,7 +485,7 @@ static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port,
{
void __iomem *cfg_base = port->cfg_base;
struct device *dev = port->dev;
- void *bar_addr;
+ void __iomem *bar_addr;
u32 pim_reg;
u64 cpu_addr = entry->res->start;
u64 pci_addr = cpu_addr - entry->offset;
diff --git a/drivers/pci/controller/pcie-iproc-msi.c b/drivers/pci/controller/pcie-iproc-msi.c
index eede4e8f3f75..35a82124a126 100644
--- a/drivers/pci/controller/pcie-iproc-msi.c
+++ b/drivers/pci/controller/pcie-iproc-msi.c
@@ -49,7 +49,7 @@ enum iproc_msi_reg {
struct iproc_msi;
/**
- * iProc MSI group
+ * struct iproc_msi_grp - iProc MSI group
*
* One MSI group is allocated per GIC interrupt, serviced by one iProc MSI
* event queue.
@@ -65,7 +65,7 @@ struct iproc_msi_grp {
};
/**
- * iProc event queue based MSI
+ * struct iproc_msi - iProc event queue based MSI
*
* Only meant to be used on platforms without MSI support integrated into the
* GIC.
@@ -171,7 +171,7 @@ static struct irq_chip iproc_msi_irq_chip = {
static struct msi_domain_info iproc_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 = &iproc_msi_irq_chip,
};
@@ -250,20 +250,23 @@ static int iproc_msi_irq_domain_alloc(struct irq_domain *domain,
struct iproc_msi *msi = domain->host_data;
int hwirq, i;
+ if (msi->nr_cpus > 1 && nr_irqs > 1)
+ return -EINVAL;
+
mutex_lock(&msi->bitmap_lock);
- /* Allocate 'nr_cpus' number of MSI vectors each time */
- hwirq = bitmap_find_next_zero_area(msi->bitmap, msi->nr_msi_vecs, 0,
- msi->nr_cpus, 0);
- if (hwirq < msi->nr_msi_vecs) {
- bitmap_set(msi->bitmap, hwirq, msi->nr_cpus);
- } else {
- mutex_unlock(&msi->bitmap_lock);
- return -ENOSPC;
- }
+ /*
+ * Allocate 'nr_irqs' multiplied by 'nr_cpus' number of MSI vectors
+ * each time
+ */
+ hwirq = bitmap_find_free_region(msi->bitmap, msi->nr_msi_vecs,
+ order_base_2(msi->nr_cpus * nr_irqs));
mutex_unlock(&msi->bitmap_lock);
+ if (hwirq < 0)
+ return -ENOSPC;
+
for (i = 0; i < nr_irqs; i++) {
irq_domain_set_info(domain, virq + i, hwirq + i,
&iproc_msi_bottom_irq_chip,
@@ -284,7 +287,8 @@ static void iproc_msi_irq_domain_free(struct irq_domain *domain,
mutex_lock(&msi->bitmap_lock);
hwirq = hwirq_to_canonical_hwirq(msi, data->hwirq);
- bitmap_clear(msi->bitmap, hwirq, msi->nr_cpus);
+ bitmap_release_region(msi->bitmap, hwirq,
+ order_base_2(msi->nr_cpus * nr_irqs));
mutex_unlock(&msi->bitmap_lock);
@@ -539,6 +543,9 @@ int iproc_msi_init(struct iproc_pcie *pcie, struct device_node *node)
mutex_init(&msi->bitmap_lock);
msi->nr_cpus = num_possible_cpus();
+ if (msi->nr_cpus == 1)
+ iproc_msi_domain_info.flags |= MSI_FLAG_MULTI_PCI_MSI;
+
msi->nr_irqs = of_irq_count(node);
if (!msi->nr_irqs) {
dev_err(pcie->dev, "found no MSI GIC interrupt\n");
diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c
index 02e52f698eeb..30ac5fbefbbf 100644
--- a/drivers/pci/controller/pcie-iproc.c
+++ b/drivers/pci/controller/pcie-iproc.c
@@ -89,8 +89,8 @@
#define IPROC_PCIE_REG_INVALID 0xffff
/**
- * iProc PCIe outbound mapping controller specific parameters
- *
+ * struct iproc_pcie_ob_map - iProc PCIe outbound mapping controller-specific
+ * parameters
* @window_sizes: list of supported outbound mapping window sizes in MB
* @nr_sizes: number of supported outbound mapping window sizes
*/
@@ -136,22 +136,20 @@ static const struct iproc_pcie_ob_map paxb_v2_ob_map[] = {
};
/**
- * iProc PCIe inbound mapping type
+ * enum iproc_pcie_ib_map_type - iProc PCIe inbound mapping type
+ * @IPROC_PCIE_IB_MAP_MEM: DDR memory
+ * @IPROC_PCIE_IB_MAP_IO: device I/O memory
+ * @IPROC_PCIE_IB_MAP_INVALID: invalid or unused
*/
enum iproc_pcie_ib_map_type {
- /* for DDR memory */
IPROC_PCIE_IB_MAP_MEM = 0,
-
- /* for device I/O memory */
IPROC_PCIE_IB_MAP_IO,
-
- /* invalid or unused */
IPROC_PCIE_IB_MAP_INVALID
};
/**
- * iProc PCIe inbound mapping controller specific parameters
- *
+ * struct iproc_pcie_ib_map - iProc PCIe inbound mapping controller-specific
+ * parameters
* @type: inbound mapping region type
* @size_unit: inbound mapping region size unit, could be SZ_1K, SZ_1M, or
* SZ_1G
@@ -437,7 +435,7 @@ static inline void iproc_pcie_write_reg(struct iproc_pcie *pcie,
writel(val, pcie->base + offset);
}
-/**
+/*
* APB error forwarding can be disabled during access of configuration
* registers of the endpoint device, to prevent unsupported requests
* (typically seen during enumeration with multi-function devices) from
@@ -619,7 +617,7 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_SUCCESSFUL;
}
-/**
+/*
* Note access to the configuration registers are protected at the higher layer
* by 'pci_lock' in drivers/pci/access.c
*/
@@ -897,7 +895,7 @@ static inline int iproc_pcie_ob_write(struct iproc_pcie *pcie, int window_idx,
return 0;
}
-/**
+/*
* Some iProc SoCs require the SW to configure the outbound address mapping
*
* Outbound address translation:
diff --git a/drivers/pci/controller/pcie-iproc.h b/drivers/pci/controller/pcie-iproc.h
index c2676e442f55..dcca315897c8 100644
--- a/drivers/pci/controller/pcie-iproc.h
+++ b/drivers/pci/controller/pcie-iproc.h
@@ -7,7 +7,13 @@
#define _PCIE_IPROC_H
/**
- * iProc PCIe interface type
+ * enum iproc_pcie_type - iProc PCIe interface type
+ * @IPROC_PCIE_PAXB_BCMA: BCMA-based host controllers
+ * @IPROC_PCIE_PAXB: PAXB-based host controllers for
+ * NS, NSP, Cygnus, NS2, and Pegasus SOCs
+ * @IPROC_PCIE_PAXB_V2: PAXB-based host controllers for Stingray SoCs
+ * @IPROC_PCIE_PAXC: PAXC-based host controllers
+ * @IPROC_PCIE_PAXC_V2: PAXC-based host controllers (second generation)
*
* PAXB is the wrapper used in root complex that can be connected to an
* external endpoint device.
@@ -24,7 +30,7 @@ enum iproc_pcie_type {
};
/**
- * iProc PCIe outbound mapping
+ * struct iproc_pcie_ob - iProc PCIe outbound mapping
* @axi_offset: offset from the AXI address to the internal address used by
* the iProc PCIe core
* @nr_windows: total number of supported outbound mapping windows
@@ -35,7 +41,7 @@ struct iproc_pcie_ob {
};
/**
- * iProc PCIe inbound mapping
+ * struct iproc_pcie_ib - iProc PCIe inbound mapping
* @nr_regions: total number of supported inbound mapping regions
*/
struct iproc_pcie_ib {
@@ -47,13 +53,13 @@ struct iproc_pcie_ib_map;
struct iproc_msi;
/**
- * iProc PCIe device
- *
+ * struct iproc_pcie - iProc PCIe device
* @dev: pointer to device data structure
* @type: iProc PCIe interface type
* @reg_offsets: register offsets
* @base: PCIe host controller I/O register base
* @base_addr: PCIe host controller register base physical address
+ * @mem: host bridge memory window resource
* @phy: optional PHY device that controls the Serdes
* @map_irq: function callback to map interrupts
* @ep_is_internal: indicates an internal emulated endpoint device is connected
diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c
index 3c5b97716d40..f3aeb8d4eaca 100644
--- a/drivers/pci/controller/pcie-mediatek-gen3.c
+++ b/drivers/pci/controller/pcie-mediatek-gen3.c
@@ -1012,6 +1012,7 @@ static const struct of_device_id mtk_pcie_of_match[] = {
{ .compatible = "mediatek,mt8192-pcie" },
{},
};
+MODULE_DEVICE_TABLE(of, mtk_pcie_of_match);
static struct platform_driver mtk_pcie_driver = {
.probe = mtk_pcie_probe,
diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c
index 62a042e75d9a..25bee693834f 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -991,10 +991,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "subsys");
if (regs) {
pcie->base = devm_ioremap_resource(dev, regs);
- if (IS_ERR(pcie->base)) {
- dev_err(dev, "failed to map shared register\n");
+ if (IS_ERR(pcie->base))
return PTR_ERR(pcie->base);
- }
}
pcie->free_ck = devm_clk_get(dev, "free_ck");
diff --git a/drivers/pci/controller/pcie-microchip-host.c b/drivers/pci/controller/pcie-microchip-host.c
index 89c68c56d93b..fdab8202ae5d 100644
--- a/drivers/pci/controller/pcie-microchip-host.c
+++ b/drivers/pci/controller/pcie-microchip-host.c
@@ -341,7 +341,7 @@ static struct event_map local_status_to_event[] = {
LOCAL_STATUS_TO_EVENT_MAP(PM_MSI_INT_SYS_ERR),
};
-struct {
+static struct {
u32 base;
u32 offset;
u32 mask;
diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c
index f1d08a1b1591..78d04ac29cd5 100644
--- a/drivers/pci/controller/pcie-rockchip-host.c
+++ b/drivers/pci/controller/pcie-rockchip-host.c
@@ -592,10 +592,6 @@ static int rockchip_pcie_parse_host_dt(struct rockchip_pcie *rockchip)
if (err)
return err;
- err = rockchip_pcie_setup_irq(rockchip);
- if (err)
- return err;
-
rockchip->vpcie12v = devm_regulator_get_optional(dev, "vpcie12v");
if (IS_ERR(rockchip->vpcie12v)) {
if (PTR_ERR(rockchip->vpcie12v) != -ENODEV)
@@ -973,8 +969,6 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
if (err)
goto err_vpcie;
- rockchip_pcie_enable_interrupts(rockchip);
-
err = rockchip_pcie_init_irq_domain(rockchip);
if (err < 0)
goto err_deinit_port;
@@ -992,6 +986,12 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
bridge->sysdata = rockchip;
bridge->ops = &rockchip_pcie_ops;
+ err = rockchip_pcie_setup_irq(rockchip);
+ if (err)
+ goto err_remove_irq_domain;
+
+ rockchip_pcie_enable_interrupts(rockchip);
+
err = pci_host_probe(bridge);
if (err < 0)
goto err_remove_irq_domain;
diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c
index d2a1920bb055..1c40d2506aef 100644
--- a/drivers/pci/ecam.c
+++ b/drivers/pci/ecam.c
@@ -32,7 +32,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
struct pci_config_window *cfg;
unsigned int bus_range, bus_range_max, bsz;
struct resource *conflict;
- int i, err;
+ int err;
if (busr->start > busr->end)
return ERR_PTR(-EINVAL);
@@ -50,6 +50,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
cfg->busr.start = busr->start;
cfg->busr.end = busr->end;
cfg->busr.flags = IORESOURCE_BUS;
+ cfg->bus_shift = bus_shift;
bus_range = resource_size(&cfg->busr);
bus_range_max = resource_size(cfgres) >> bus_shift;
if (bus_range > bus_range_max) {
@@ -77,13 +78,6 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
cfg->winp = kcalloc(bus_range, sizeof(*cfg->winp), GFP_KERNEL);
if (!cfg->winp)
goto err_exit_malloc;
- for (i = 0; i < bus_range; i++) {
- cfg->winp[i] =
- pci_remap_cfgspace(cfgres->start + i * bsz,
- bsz);
- if (!cfg->winp[i])
- goto err_exit_iomap;
- }
} else {
cfg->win = pci_remap_cfgspace(cfgres->start, bus_range * bsz);
if (!cfg->win)
@@ -129,6 +123,44 @@ void pci_ecam_free(struct pci_config_window *cfg)
}
EXPORT_SYMBOL_GPL(pci_ecam_free);
+static int pci_ecam_add_bus(struct pci_bus *bus)
+{
+ struct pci_config_window *cfg = bus->sysdata;
+ unsigned int bsz = 1 << cfg->bus_shift;
+ unsigned int busn = bus->number;
+ phys_addr_t start;
+
+ if (!per_bus_mapping)
+ return 0;
+
+ if (busn < cfg->busr.start || busn > cfg->busr.end)
+ return -EINVAL;
+
+ busn -= cfg->busr.start;
+ start = cfg->res.start + busn * bsz;
+
+ cfg->winp[busn] = pci_remap_cfgspace(start, bsz);
+ if (!cfg->winp[busn])
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void pci_ecam_remove_bus(struct pci_bus *bus)
+{
+ struct pci_config_window *cfg = bus->sysdata;
+ unsigned int busn = bus->number;
+
+ if (!per_bus_mapping || busn < cfg->busr.start || busn > cfg->busr.end)
+ return;
+
+ busn -= cfg->busr.start;
+ if (cfg->winp[busn]) {
+ iounmap(cfg->winp[busn]);
+ cfg->winp[busn] = NULL;
+ }
+}
+
/*
* Function to implement the pci_ops ->map_bus method
*/
@@ -167,6 +199,8 @@ EXPORT_SYMBOL_GPL(pci_ecam_map_bus);
/* ECAM ops */
const struct pci_ecam_ops pci_generic_ecam_ops = {
.pci_ops = {
+ .add_bus = pci_ecam_add_bus,
+ .remove_bus = pci_ecam_remove_bus,
.map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read,
.write = pci_generic_config_write,
@@ -178,6 +212,8 @@ EXPORT_SYMBOL_GPL(pci_generic_ecam_ops);
/* ECAM ops for 32-bit access only (non-compliant) */
const struct pci_ecam_ops pci_32b_ops = {
.pci_ops = {
+ .add_bus = pci_ecam_add_bus,
+ .remove_bus = pci_ecam_remove_bus,
.map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read32,
.write = pci_generic_config_write32,
@@ -187,6 +223,8 @@ const struct pci_ecam_ops pci_32b_ops = {
/* ECAM ops for 32-bit read only (non-compliant) */
const struct pci_ecam_ops pci_32b_read_ops = {
.pci_ops = {
+ .add_bus = pci_ecam_add_bus,
+ .remove_bus = pci_ecam_remove_bus,
.map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read32,
.write = pci_generic_config_write,
diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h
index f33ff2bca414..3fdd1b9bd8c3 100644
--- a/drivers/pci/hotplug/cpci_hotplug.h
+++ b/drivers/pci/hotplug/cpci_hotplug.h
@@ -75,6 +75,9 @@ int cpci_hp_unregister_bus(struct pci_bus *bus);
int cpci_hp_start(void);
int cpci_hp_stop(void);
+/* Global variables */
+extern int cpci_debug;
+
/*
* Internal function prototypes, these functions should not be used by
* board/chassis drivers.
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index 2c16adb7f4ec..6c48066acb44 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -19,8 +19,6 @@
#define MY_NAME "cpci_hotplug"
-extern int cpci_debug;
-
#define dbg(format, arg...) \
do { \
if (cpci_debug) \
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index b8aacb41a83c..f99a7927e5a8 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -296,9 +296,10 @@ static int ctrl_slot_cleanup(struct controller *ctrl)
*
* Won't work for more than one PCI-PCI bridge in a slot.
*
- * @bus_num - bus number of PCI device
- * @dev_num - device number of PCI device
- * @slot - Pointer to u8 where slot number will be returned
+ * @bus: pointer to the PCI bus structure
+ * @bus_num: bus number of PCI device
+ * @dev_num: device number of PCI device
+ * @slot: Pointer to u8 where slot number will be returned
*
* Output: SUCCESS or FAILURE
*/
diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
index 68de958a9be8..1b26ca0b3701 100644
--- a/drivers/pci/hotplug/cpqphp_ctrl.c
+++ b/drivers/pci/hotplug/cpqphp_ctrl.c
@@ -1877,7 +1877,7 @@ static void interrupt_event_handler(struct controller *ctrl)
/**
* cpqhp_pushbutton_thread - handle pushbutton events
- * @slot: target slot (struct)
+ * @t: pointer to struct timer_list which holds all timer-related callbacks
*
* Scheduled procedure to handle blocking stuff for the pushbuttons.
* Handles all pending events and exits.
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index 5ac31f683b85..058d5937d8a9 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -73,7 +73,7 @@ static ssize_t power_read_file(struct pci_slot *pci_slot, char *buf)
if (retval)
return retval;
- return sprintf(buf, "%d\n", value);
+ return sysfs_emit(buf, "%d\n", value);
}
static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf,
@@ -130,7 +130,7 @@ static ssize_t attention_read_file(struct pci_slot *pci_slot, char *buf)
if (retval)
return retval;
- return sprintf(buf, "%d\n", value);
+ return sysfs_emit(buf, "%d\n", value);
}
static ssize_t attention_write_file(struct pci_slot *pci_slot, const char *buf,
@@ -175,7 +175,7 @@ static ssize_t latch_read_file(struct pci_slot *pci_slot, char *buf)
if (retval)
return retval;
- return sprintf(buf, "%d\n", value);
+ return sysfs_emit(buf, "%d\n", value);
}
static struct pci_slot_attribute hotplug_slot_attr_latch = {
@@ -192,7 +192,7 @@ static ssize_t presence_read_file(struct pci_slot *pci_slot, char *buf)
if (retval)
return retval;
- return sprintf(buf, "%d\n", value);
+ return sysfs_emit(buf, "%d\n", value);
}
static struct pci_slot_attribute hotplug_slot_attr_presence = {
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 4fd200d8b0a9..d4a930881054 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -47,6 +47,9 @@ extern int pciehp_poll_time;
* struct controller - PCIe hotplug controller
* @pcie: pointer to the controller's PCIe port service device
* @slot_cap: cached copy of the Slot Capabilities register
+ * @inband_presence_disabled: In-Band Presence Detect Disable supported by
+ * controller and disabled per spec recommendation (PCIe r5.0, appendix I
+ * implementation note)
* @slot_ctrl: cached copy of the Slot Control register
* @ctrl_lock: serializes writes to the Slot Control register
* @cmd_started: jiffies when the Slot Control register was last written;
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index fb3840e222ad..9d06939736c0 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -563,6 +563,32 @@ void pciehp_power_off_slot(struct controller *ctrl)
PCI_EXP_SLTCTL_PWR_OFF);
}
+static void pciehp_ignore_dpc_link_change(struct controller *ctrl,
+ struct pci_dev *pdev, int irq)
+{
+ /*
+ * Ignore link changes which occurred while waiting for DPC recovery.
+ * Could be several if DPC triggered multiple times consecutively.
+ */
+ synchronize_hardirq(irq);
+ atomic_and(~PCI_EXP_SLTSTA_DLLSC, &ctrl->pending_events);
+ if (pciehp_poll_mode)
+ pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
+ PCI_EXP_SLTSTA_DLLSC);
+ ctrl_info(ctrl, "Slot(%s): Link Down/Up ignored (recovered by DPC)\n",
+ slot_name(ctrl));
+
+ /*
+ * If the link is unexpectedly down after successful recovery,
+ * the corresponding link change may have been ignored above.
+ * Synthesize it to ensure that it is acted on.
+ */
+ down_read(&ctrl->reset_lock);
+ if (!pciehp_check_link_active(ctrl))
+ pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC);
+ up_read(&ctrl->reset_lock);
+}
+
static irqreturn_t pciehp_isr(int irq, void *dev_id)
{
struct controller *ctrl = (struct controller *)dev_id;
@@ -707,6 +733,16 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
}
/*
+ * Ignore Link Down/Up events caused by Downstream Port Containment
+ * if recovery from the error succeeded.
+ */
+ if ((events & PCI_EXP_SLTSTA_DLLSC) && pci_dpc_recovered(pdev) &&
+ ctrl->state == ON_STATE) {
+ events &= ~PCI_EXP_SLTSTA_DLLSC;
+ pciehp_ignore_dpc_link_change(ctrl, pdev, irq);
+ }
+
+ /*
* Disable requests have higher priority than Presence Detect Changed
* or Data Link Layer State Changed events.
*/
diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
index dbfa0b55d31a..068b7810a574 100644
--- a/drivers/pci/hotplug/rpadlpar_sysfs.c
+++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
@@ -50,7 +50,7 @@ static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr,
static ssize_t add_slot_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
- return sprintf(buf, "0\n");
+ return sysfs_emit(buf, "0\n");
}
static ssize_t remove_slot_store(struct kobject *kobj,
@@ -80,7 +80,7 @@ static ssize_t remove_slot_store(struct kobject *kobj,
static ssize_t remove_slot_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
- return sprintf(buf, "0\n");
+ return sysfs_emit(buf, "0\n");
}
static struct kobj_attribute add_slot_attr =
diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c
index 45658bb5c554..64beed7a26be 100644
--- a/drivers/pci/hotplug/shpchp_sysfs.c
+++ b/drivers/pci/hotplug/shpchp_sysfs.c
@@ -24,50 +24,54 @@
static ssize_t show_ctrl(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pci_dev *pdev;
- char *out = buf;
int index, busnr;
struct resource *res;
struct pci_bus *bus;
+ size_t len = 0;
pdev = to_pci_dev(dev);
bus = pdev->subordinate;
- out += sprintf(buf, "Free resources: memory\n");
+ len += sysfs_emit_at(buf, len, "Free resources: memory\n");
pci_bus_for_each_resource(bus, res, index) {
if (res && (res->flags & IORESOURCE_MEM) &&
!(res->flags & IORESOURCE_PREFETCH)) {
- out += sprintf(out, "start = %8.8llx, length = %8.8llx\n",
- (unsigned long long)res->start,
- (unsigned long long)resource_size(res));
+ len += sysfs_emit_at(buf, len,
+ "start = %8.8llx, length = %8.8llx\n",
+ (unsigned long long)res->start,
+ (unsigned long long)resource_size(res));
}
}
- out += sprintf(out, "Free resources: prefetchable memory\n");
+ len += sysfs_emit_at(buf, len, "Free resources: prefetchable memory\n");
pci_bus_for_each_resource(bus, res, index) {
if (res && (res->flags & IORESOURCE_MEM) &&
(res->flags & IORESOURCE_PREFETCH)) {
- out += sprintf(out, "start = %8.8llx, length = %8.8llx\n",
- (unsigned long long)res->start,
- (unsigned long long)resource_size(res));
+ len += sysfs_emit_at(buf, len,
+ "start = %8.8llx, length = %8.8llx\n",
+ (unsigned long long)res->start,
+ (unsigned long long)resource_size(res));
}
}
- out += sprintf(out, "Free resources: IO\n");
+ len += sysfs_emit_at(buf, len, "Free resources: IO\n");
pci_bus_for_each_resource(bus, res, index) {
if (res && (res->flags & IORESOURCE_IO)) {
- out += sprintf(out, "start = %8.8llx, length = %8.8llx\n",
- (unsigned long long)res->start,
- (unsigned long long)resource_size(res));
+ len += sysfs_emit_at(buf, len,
+ "start = %8.8llx, length = %8.8llx\n",
+ (unsigned long long)res->start,
+ (unsigned long long)resource_size(res));
}
}
- out += sprintf(out, "Free resources: bus numbers\n");
+ len += sysfs_emit_at(buf, len, "Free resources: bus numbers\n");
for (busnr = bus->busn_res.start; busnr <= bus->busn_res.end; busnr++) {
if (!pci_find_bus(pci_domain_nr(bus), busnr))
break;
}
if (busnr < bus->busn_res.end)
- out += sprintf(out, "start = %8.8x, length = %8.8x\n",
- busnr, (int)(bus->busn_res.end - busnr));
+ len += sysfs_emit_at(buf, len,
+ "start = %8.8x, length = %8.8x\n",
+ busnr, (int)(bus->busn_res.end - busnr));
- return out - buf;
+ return len;
}
static DEVICE_ATTR(ctrl, S_IRUGO, show_ctrl, NULL);
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index afc06e6ce115..dafdc652fcd0 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -346,7 +346,7 @@ static ssize_t sriov_totalvfs_show(struct device *dev,
{
struct pci_dev *pdev = to_pci_dev(dev);
- return sprintf(buf, "%u\n", pci_sriov_get_totalvfs(pdev));
+ return sysfs_emit(buf, "%u\n", pci_sriov_get_totalvfs(pdev));
}
static ssize_t sriov_numvfs_show(struct device *dev,
@@ -361,7 +361,7 @@ static ssize_t sriov_numvfs_show(struct device *dev,
num_vfs = pdev->sriov->num_VFs;
device_unlock(&pdev->dev);
- return sprintf(buf, "%u\n", num_vfs);
+ return sysfs_emit(buf, "%u\n", num_vfs);
}
/*
@@ -391,9 +391,16 @@ static ssize_t sriov_numvfs_store(struct device *dev,
if (num_vfs == pdev->sriov->num_VFs)
goto exit;
+ /* is PF driver loaded */
+ if (!pdev->driver) {
+ pci_info(pdev, "no driver bound to device; cannot configure SR-IOV\n");
+ ret = -ENOENT;
+ goto exit;
+ }
+
/* is PF driver loaded w/callback */
- if (!pdev->driver || !pdev->driver->sriov_configure) {
- pci_info(pdev, "Driver does not support SRIOV configuration via sysfs\n");
+ if (!pdev->driver->sriov_configure) {
+ pci_info(pdev, "driver does not support SR-IOV configuration via sysfs\n");
ret = -ENOENT;
goto exit;
}
@@ -435,7 +442,7 @@ static ssize_t sriov_offset_show(struct device *dev,
{
struct pci_dev *pdev = to_pci_dev(dev);
- return sprintf(buf, "%u\n", pdev->sriov->offset);
+ return sysfs_emit(buf, "%u\n", pdev->sriov->offset);
}
static ssize_t sriov_stride_show(struct device *dev,
@@ -444,7 +451,7 @@ static ssize_t sriov_stride_show(struct device *dev,
{
struct pci_dev *pdev = to_pci_dev(dev);
- return sprintf(buf, "%u\n", pdev->sriov->stride);
+ return sysfs_emit(buf, "%u\n", pdev->sriov->stride);
}
static ssize_t sriov_vf_device_show(struct device *dev,
@@ -453,7 +460,7 @@ static ssize_t sriov_vf_device_show(struct device *dev,
{
struct pci_dev *pdev = to_pci_dev(dev);
- return sprintf(buf, "%x\n", pdev->sriov->vf_device);
+ return sysfs_emit(buf, "%x\n", pdev->sriov->vf_device);
}
static ssize_t sriov_drivers_autoprobe_show(struct device *dev,
@@ -462,7 +469,7 @@ static ssize_t sriov_drivers_autoprobe_show(struct device *dev,
{
struct pci_dev *pdev = to_pci_dev(dev);
- return sprintf(buf, "%u\n", pdev->sriov->drivers_autoprobe);
+ return sysfs_emit(buf, "%u\n", pdev->sriov->drivers_autoprobe);
}
static ssize_t sriov_drivers_autoprobe_store(struct device *dev,
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 217dc9f0231f..9232255c8515 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -464,11 +464,11 @@ static ssize_t msi_mode_show(struct device *dev, struct device_attribute *attr,
return retval;
entry = irq_get_msi_desc(irq);
- if (entry)
- return sprintf(buf, "%s\n",
- entry->msi_attrib.is_msix ? "msix" : "msi");
+ if (!entry)
+ return -ENODEV;
- return -ENODEV;
+ return sysfs_emit(buf, "%s\n",
+ entry->msi_attrib.is_msix ? "msix" : "msi");
}
static int populate_msi_sysfs(struct pci_dev *pdev)
diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
index 196382630363..50cdde3e9a8b 100644
--- a/drivers/pci/p2pdma.c
+++ b/drivers/pci/p2pdma.c
@@ -48,12 +48,16 @@ static ssize_t size_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
+ struct pci_p2pdma *p2pdma;
size_t size = 0;
- if (pdev->p2pdma->pool)
- size = gen_pool_size(pdev->p2pdma->pool);
+ rcu_read_lock();
+ p2pdma = rcu_dereference(pdev->p2pdma);
+ if (p2pdma && p2pdma->pool)
+ size = gen_pool_size(p2pdma->pool);
+ rcu_read_unlock();
- return scnprintf(buf, PAGE_SIZE, "%zd\n", size);
+ return sysfs_emit(buf, "%zd\n", size);
}
static DEVICE_ATTR_RO(size);
@@ -61,12 +65,16 @@ static ssize_t available_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
+ struct pci_p2pdma *p2pdma;
size_t avail = 0;
- if (pdev->p2pdma->pool)
- avail = gen_pool_avail(pdev->p2pdma->pool);
+ rcu_read_lock();
+ p2pdma = rcu_dereference(pdev->p2pdma);
+ if (p2pdma && p2pdma->pool)
+ avail = gen_pool_avail(p2pdma->pool);
+ rcu_read_unlock();
- return scnprintf(buf, PAGE_SIZE, "%zd\n", avail);
+ return sysfs_emit(buf, "%zd\n", avail);
}
static DEVICE_ATTR_RO(available);
@@ -74,9 +82,16 @@ static ssize_t published_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
+ struct pci_p2pdma *p2pdma;
+ bool published = false;
- return scnprintf(buf, PAGE_SIZE, "%d\n",
- pdev->p2pdma->p2pmem_published);
+ rcu_read_lock();
+ p2pdma = rcu_dereference(pdev->p2pdma);
+ if (p2pdma)
+ published = p2pdma->p2pmem_published;
+ rcu_read_unlock();
+
+ return sysfs_emit(buf, "%d\n", published);
}
static DEVICE_ATTR_RO(published);
@@ -95,8 +110,9 @@ static const struct attribute_group p2pmem_group = {
static void pci_p2pdma_release(void *data)
{
struct pci_dev *pdev = data;
- struct pci_p2pdma *p2pdma = pdev->p2pdma;
+ struct pci_p2pdma *p2pdma;
+ p2pdma = rcu_dereference_protected(pdev->p2pdma, 1);
if (!p2pdma)
return;
@@ -128,16 +144,14 @@ static int pci_p2pdma_setup(struct pci_dev *pdev)
if (error)
goto out_pool_destroy;
- pdev->p2pdma = p2p;
-
error = sysfs_create_group(&pdev->dev.kobj, &p2pmem_group);
if (error)
goto out_pool_destroy;
+ rcu_assign_pointer(pdev->p2pdma, p2p);
return 0;
out_pool_destroy:
- pdev->p2pdma = NULL;
gen_pool_destroy(p2p->pool);
out:
devm_kfree(&pdev->dev, p2p);
@@ -159,6 +173,7 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
{
struct pci_p2pdma_pagemap *p2p_pgmap;
struct dev_pagemap *pgmap;
+ struct pci_p2pdma *p2pdma;
void *addr;
int error;
@@ -200,7 +215,8 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
goto pgmap_free;
}
- error = gen_pool_add_owner(pdev->p2pdma->pool, (unsigned long)addr,
+ p2pdma = rcu_dereference_protected(pdev->p2pdma, 1);
+ error = gen_pool_add_owner(p2pdma->pool, (unsigned long)addr,
pci_bus_address(pdev, bar) + offset,
range_len(&pgmap->range), dev_to_node(&pdev->dev),
pgmap->ref);
@@ -308,10 +324,41 @@ static const struct pci_p2pdma_whitelist_entry {
{}
};
+/*
+ * This lookup function tries to find the PCI device corresponding to a given
+ * host bridge.
+ *
+ * It assumes the host bridge device is the first PCI device in the
+ * bus->devices list and that the devfn is 00.0. These assumptions should hold
+ * for all the devices in the whitelist above.
+ *
+ * This function is equivalent to pci_get_slot(host->bus, 0), however it does
+ * not take the pci_bus_sem lock seeing __host_bridge_whitelist() must not
+ * sleep.
+ *
+ * For this to be safe, the caller should hold a reference to a device on the
+ * bridge, which should ensure the host_bridge device will not be freed
+ * or removed from the head of the devices list.
+ */
+static struct pci_dev *pci_host_bridge_dev(struct pci_host_bridge *host)
+{
+ struct pci_dev *root;
+
+ root = list_first_entry_or_null(&host->bus->devices,
+ struct pci_dev, bus_list);
+
+ if (!root)
+ return NULL;
+ if (root->devfn != PCI_DEVFN(0, 0))
+ return NULL;
+
+ return root;
+}
+
static bool __host_bridge_whitelist(struct pci_host_bridge *host,
- bool same_host_bridge)
+ bool same_host_bridge, bool warn)
{
- struct pci_dev *root = pci_get_slot(host->bus, PCI_DEVFN(0, 0));
+ struct pci_dev *root = pci_host_bridge_dev(host);
const struct pci_p2pdma_whitelist_entry *entry;
unsigned short vendor, device;
@@ -320,7 +367,6 @@ static bool __host_bridge_whitelist(struct pci_host_bridge *host,
vendor = root->vendor;
device = root->device;
- pci_dev_put(root);
for (entry = pci_p2pdma_whitelist; entry->vendor; entry++) {
if (vendor != entry->vendor || device != entry->device)
@@ -331,6 +377,10 @@ static bool __host_bridge_whitelist(struct pci_host_bridge *host,
return true;
}
+ if (warn)
+ pci_warn(root, "Host bridge not in P2PDMA whitelist: %04x:%04x\n",
+ vendor, device);
+
return false;
}
@@ -338,44 +388,90 @@ static bool __host_bridge_whitelist(struct pci_host_bridge *host,
* If we can't find a common upstream bridge take a look at the root
* complex and compare it to a whitelist of known good hardware.
*/
-static bool host_bridge_whitelist(struct pci_dev *a, struct pci_dev *b)
+static bool host_bridge_whitelist(struct pci_dev *a, struct pci_dev *b,
+ bool warn)
{
struct pci_host_bridge *host_a = pci_find_host_bridge(a->bus);
struct pci_host_bridge *host_b = pci_find_host_bridge(b->bus);
if (host_a == host_b)
- return __host_bridge_whitelist(host_a, true);
+ return __host_bridge_whitelist(host_a, true, warn);
- if (__host_bridge_whitelist(host_a, false) &&
- __host_bridge_whitelist(host_b, false))
+ if (__host_bridge_whitelist(host_a, false, warn) &&
+ __host_bridge_whitelist(host_b, false, warn))
return true;
return false;
}
+static unsigned long map_types_idx(struct pci_dev *client)
+{
+ return (pci_domain_nr(client->bus) << 16) |
+ (client->bus->number << 8) | client->devfn;
+}
+
+/*
+ * Calculate the P2PDMA mapping type and distance between two PCI devices.
+ *
+ * If the two devices are the same PCI function, return
+ * PCI_P2PDMA_MAP_BUS_ADDR and a distance of 0.
+ *
+ * If they are two functions of the same device, return
+ * PCI_P2PDMA_MAP_BUS_ADDR and a distance of 2 (one hop up to the bridge,
+ * then one hop back down to another function of the same device).
+ *
+ * In the case where two devices are connected to the same PCIe switch,
+ * return a distance of 4. This corresponds to the following PCI tree:
+ *
+ * -+ Root Port
+ * \+ Switch Upstream Port
+ * +-+ Switch Downstream Port 0
+ * + \- Device A
+ * \-+ Switch Downstream Port 1
+ * \- Device B
+ *
+ * The distance is 4 because we traverse from Device A to Downstream Port 0
+ * to the common Switch Upstream Port, back down to Downstream Port 1 and
+ * then to Device B. The mapping type returned depends on the ACS
+ * redirection setting of the ports along the path.
+ *
+ * If ACS redirect is set on any port in the path, traffic between the
+ * devices will go through the host bridge, so return
+ * PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; otherwise return
+ * PCI_P2PDMA_MAP_BUS_ADDR.
+ *
+ * Any two devices that have a data path that goes through the host bridge
+ * will consult a whitelist. If the host bridge is in the whitelist, return
+ * PCI_P2PDMA_MAP_THRU_HOST_BRIDGE with the distance set to the number of
+ * ports per above. If the device is not in the whitelist, return
+ * PCI_P2PDMA_MAP_NOT_SUPPORTED.
+ */
static enum pci_p2pdma_map_type
-__upstream_bridge_distance(struct pci_dev *provider, struct pci_dev *client,
- int *dist, bool *acs_redirects, struct seq_buf *acs_list)
+calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client,
+ int *dist, bool verbose)
{
+ enum pci_p2pdma_map_type map_type = PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
struct pci_dev *a = provider, *b = client, *bb;
+ bool acs_redirects = false;
+ struct pci_p2pdma *p2pdma;
+ struct seq_buf acs_list;
+ int acs_cnt = 0;
int dist_a = 0;
int dist_b = 0;
- int acs_cnt = 0;
+ char buf[128];
- if (acs_redirects)
- *acs_redirects = false;
+ seq_buf_init(&acs_list, buf, sizeof(buf));
/*
* Note, we don't need to take references to devices returned by
* pci_upstream_bridge() seeing we hold a reference to a child
* device which will already hold a reference to the upstream bridge.
*/
-
while (a) {
dist_b = 0;
if (pci_bridge_has_acs_redir(a)) {
- seq_buf_print_bus_devfn(acs_list, a);
+ seq_buf_print_bus_devfn(&acs_list, a);
acs_cnt++;
}
@@ -393,10 +489,8 @@ __upstream_bridge_distance(struct pci_dev *provider, struct pci_dev *client,
dist_a++;
}
- if (dist)
- *dist = dist_a + dist_b;
-
- return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
+ *dist = dist_a + dist_b;
+ goto map_through_host_bridge;
check_b_path_acs:
bb = b;
@@ -406,124 +500,45 @@ check_b_path_acs:
break;
if (pci_bridge_has_acs_redir(bb)) {
- seq_buf_print_bus_devfn(acs_list, bb);
+ seq_buf_print_bus_devfn(&acs_list, bb);
acs_cnt++;
}
bb = pci_upstream_bridge(bb);
}
- if (dist)
- *dist = dist_a + dist_b;
-
- if (acs_cnt) {
- if (acs_redirects)
- *acs_redirects = true;
-
- return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
- }
-
- return PCI_P2PDMA_MAP_BUS_ADDR;
-}
-
-static unsigned long map_types_idx(struct pci_dev *client)
-{
- return (pci_domain_nr(client->bus) << 16) |
- (client->bus->number << 8) | client->devfn;
-}
-
-/*
- * Find the distance through the nearest common upstream bridge between
- * two PCI devices.
- *
- * If the two devices are the same device then 0 will be returned.
- *
- * If there are two virtual functions of the same device behind the same
- * bridge port then 2 will be returned (one step down to the PCIe switch,
- * then one step back to the same device).
- *
- * In the case where two devices are connected to the same PCIe switch, the
- * value 4 will be returned. This corresponds to the following PCI tree:
- *
- * -+ Root Port
- * \+ Switch Upstream Port
- * +-+ Switch Downstream Port
- * + \- Device A
- * \-+ Switch Downstream Port
- * \- Device B
- *
- * The distance is 4 because we traverse from Device A through the downstream
- * port of the switch, to the common upstream port, back up to the second
- * downstream port and then to Device B.
- *
- * Any two devices that cannot communicate using p2pdma will return
- * PCI_P2PDMA_MAP_NOT_SUPPORTED.
- *
- * Any two devices that have a data path that goes through the host bridge
- * will consult a whitelist. If the host bridges are on the whitelist,
- * this function will return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE.
- *
- * If either bridge is not on the whitelist this function returns
- * PCI_P2PDMA_MAP_NOT_SUPPORTED.
- *
- * If a bridge which has any ACS redirection bits set is in the path,
- * acs_redirects will be set to true. In this case, a list of all infringing
- * bridge addresses will be populated in acs_list (assuming it's non-null)
- * for printk purposes.
- */
-static enum pci_p2pdma_map_type
-upstream_bridge_distance(struct pci_dev *provider, struct pci_dev *client,
- int *dist, bool *acs_redirects, struct seq_buf *acs_list)
-{
- enum pci_p2pdma_map_type map_type;
-
- map_type = __upstream_bridge_distance(provider, client, dist,
- acs_redirects, acs_list);
+ *dist = dist_a + dist_b;
- if (map_type == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE) {
- if (!cpu_supports_p2pdma() &&
- !host_bridge_whitelist(provider, client))
- map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
+ if (!acs_cnt) {
+ map_type = PCI_P2PDMA_MAP_BUS_ADDR;
+ goto done;
}
- if (provider->p2pdma)
- xa_store(&provider->p2pdma->map_types, map_types_idx(client),
- xa_mk_value(map_type), GFP_KERNEL);
-
- return map_type;
-}
-
-static enum pci_p2pdma_map_type
-upstream_bridge_distance_warn(struct pci_dev *provider, struct pci_dev *client,
- int *dist)
-{
- struct seq_buf acs_list;
- bool acs_redirects;
- int ret;
-
- seq_buf_init(&acs_list, kmalloc(PAGE_SIZE, GFP_KERNEL), PAGE_SIZE);
- if (!acs_list.buffer)
- return -ENOMEM;
-
- ret = upstream_bridge_distance(provider, client, dist, &acs_redirects,
- &acs_list);
- if (acs_redirects) {
+ if (verbose) {
+ acs_list.buffer[acs_list.len-1] = 0; /* drop final semicolon */
pci_warn(client, "ACS redirect is set between the client and provider (%s)\n",
pci_name(provider));
- /* Drop final semicolon */
- acs_list.buffer[acs_list.len-1] = 0;
pci_warn(client, "to disable ACS redirect for this path, add the kernel parameter: pci=disable_acs_redir=%s\n",
acs_list.buffer);
}
+ acs_redirects = true;
- if (ret == PCI_P2PDMA_MAP_NOT_SUPPORTED) {
- pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge or whitelisted host bridge\n",
- pci_name(provider));
+map_through_host_bridge:
+ if (!cpu_supports_p2pdma() &&
+ !host_bridge_whitelist(provider, client, acs_redirects)) {
+ if (verbose)
+ pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge or whitelisted host bridge\n",
+ pci_name(provider));
+ map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
}
-
- kfree(acs_list.buffer);
-
- return ret;
+done:
+ rcu_read_lock();
+ p2pdma = rcu_dereference(provider->p2pdma);
+ if (p2pdma)
+ xa_store(&p2pdma->map_types, map_types_idx(client),
+ xa_mk_value(map_type), GFP_KERNEL);
+ rcu_read_unlock();
+ return map_type;
}
/**
@@ -546,11 +561,11 @@ upstream_bridge_distance_warn(struct pci_dev *provider, struct pci_dev *client,
int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients,
int num_clients, bool verbose)
{
+ enum pci_p2pdma_map_type map;
bool not_supported = false;
struct pci_dev *pci_client;
int total_dist = 0;
- int distance;
- int i, ret;
+ int i, distance;
if (num_clients == 0)
return -1;
@@ -564,16 +579,12 @@ int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients,
return -1;
}
- if (verbose)
- ret = upstream_bridge_distance_warn(provider,
- pci_client, &distance);
- else
- ret = upstream_bridge_distance(provider, pci_client,
- &distance, NULL, NULL);
+ map = calc_map_type_and_dist(provider, pci_client, &distance,
+ verbose);
pci_dev_put(pci_client);
- if (ret == PCI_P2PDMA_MAP_NOT_SUPPORTED)
+ if (map == PCI_P2PDMA_MAP_NOT_SUPPORTED)
not_supported = true;
if (not_supported && !verbose)
@@ -595,7 +606,15 @@ EXPORT_SYMBOL_GPL(pci_p2pdma_distance_many);
*/
bool pci_has_p2pmem(struct pci_dev *pdev)
{
- return pdev->p2pdma && pdev->p2pdma->p2pmem_published;
+ struct pci_p2pdma *p2pdma;
+ bool res;
+
+ rcu_read_lock();
+ p2pdma = rcu_dereference(pdev->p2pdma);
+ res = p2pdma && p2pdma->p2pmem_published;
+ rcu_read_unlock();
+
+ return res;
}
EXPORT_SYMBOL_GPL(pci_has_p2pmem);
@@ -675,6 +694,7 @@ void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size)
{
void *ret = NULL;
struct percpu_ref *ref;
+ struct pci_p2pdma *p2pdma;
/*
* Pairs with synchronize_rcu() in pci_p2pdma_release() to
@@ -682,16 +702,16 @@ void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size)
* read-lock.
*/
rcu_read_lock();
- if (unlikely(!pdev->p2pdma))
+ p2pdma = rcu_dereference(pdev->p2pdma);
+ if (unlikely(!p2pdma))
goto out;
- ret = (void *)gen_pool_alloc_owner(pdev->p2pdma->pool, size,
- (void **) &ref);
+ ret = (void *)gen_pool_alloc_owner(p2pdma->pool, size, (void **) &ref);
if (!ret)
goto out;
if (unlikely(!percpu_ref_tryget_live(ref))) {
- gen_pool_free(pdev->p2pdma->pool, (unsigned long) ret, size);
+ gen_pool_free(p2pdma->pool, (unsigned long) ret, size);
ret = NULL;
goto out;
}
@@ -710,8 +730,9 @@ EXPORT_SYMBOL_GPL(pci_alloc_p2pmem);
void pci_free_p2pmem(struct pci_dev *pdev, void *addr, size_t size)
{
struct percpu_ref *ref;
+ struct pci_p2pdma *p2pdma = rcu_dereference_protected(pdev->p2pdma, 1);
- gen_pool_free_owner(pdev->p2pdma->pool, (uintptr_t)addr, size,
+ gen_pool_free_owner(p2pdma->pool, (uintptr_t)addr, size,
(void **) &ref);
percpu_ref_put(ref);
}
@@ -725,9 +746,13 @@ EXPORT_SYMBOL_GPL(pci_free_p2pmem);
*/
pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev, void *addr)
{
+ struct pci_p2pdma *p2pdma;
+
if (!addr)
return 0;
- if (!pdev->p2pdma)
+
+ p2pdma = rcu_dereference_protected(pdev->p2pdma, 1);
+ if (!p2pdma)
return 0;
/*
@@ -735,7 +760,7 @@ pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev, void *addr)
* bus address as the physical address. So gen_pool_virt_to_phys()
* actually returns the bus address despite the misleading name.
*/
- return gen_pool_virt_to_phys(pdev->p2pdma->pool, (unsigned long)addr);
+ return gen_pool_virt_to_phys(p2pdma->pool, (unsigned long)addr);
}
EXPORT_SYMBOL_GPL(pci_p2pmem_virt_to_bus);
@@ -806,19 +831,40 @@ EXPORT_SYMBOL_GPL(pci_p2pmem_free_sgl);
*/
void pci_p2pmem_publish(struct pci_dev *pdev, bool publish)
{
- if (pdev->p2pdma)
- pdev->p2pdma->p2pmem_published = publish;
+ struct pci_p2pdma *p2pdma;
+
+ rcu_read_lock();
+ p2pdma = rcu_dereference(pdev->p2pdma);
+ if (p2pdma)
+ p2pdma->p2pmem_published = publish;
+ rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(pci_p2pmem_publish);
-static enum pci_p2pdma_map_type pci_p2pdma_map_type(struct pci_dev *provider,
- struct pci_dev *client)
+static enum pci_p2pdma_map_type pci_p2pdma_map_type(struct dev_pagemap *pgmap,
+ struct device *dev)
{
+ enum pci_p2pdma_map_type type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
+ struct pci_dev *provider = to_p2p_pgmap(pgmap)->provider;
+ struct pci_dev *client;
+ struct pci_p2pdma *p2pdma;
+
if (!provider->p2pdma)
return PCI_P2PDMA_MAP_NOT_SUPPORTED;
- return xa_to_value(xa_load(&provider->p2pdma->map_types,
- map_types_idx(client)));
+ if (!dev_is_pci(dev))
+ return PCI_P2PDMA_MAP_NOT_SUPPORTED;
+
+ client = to_pci_dev(dev);
+
+ rcu_read_lock();
+ p2pdma = rcu_dereference(provider->p2pdma);
+
+ if (p2pdma)
+ type = xa_to_value(xa_load(&p2pdma->map_types,
+ map_types_idx(client)));
+ rcu_read_unlock();
+ return type;
}
static int __pci_p2pdma_map_sg(struct pci_p2pdma_pagemap *p2p_pgmap,
@@ -853,14 +899,8 @@ int pci_p2pdma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
{
struct pci_p2pdma_pagemap *p2p_pgmap =
to_p2p_pgmap(sg_page(sg)->pgmap);
- struct pci_dev *client;
-
- if (WARN_ON_ONCE(!dev_is_pci(dev)))
- return 0;
- client = to_pci_dev(dev);
-
- switch (pci_p2pdma_map_type(p2p_pgmap->provider, client)) {
+ switch (pci_p2pdma_map_type(sg_page(sg)->pgmap, dev)) {
case PCI_P2PDMA_MAP_THRU_HOST_BRIDGE:
return dma_map_sg_attrs(dev, sg, nents, dir, attrs);
case PCI_P2PDMA_MAP_BUS_ADDR:
@@ -884,17 +924,9 @@ EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg_attrs);
void pci_p2pdma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir, unsigned long attrs)
{
- struct pci_p2pdma_pagemap *p2p_pgmap =
- to_p2p_pgmap(sg_page(sg)->pgmap);
enum pci_p2pdma_map_type map_type;
- struct pci_dev *client;
-
- if (WARN_ON_ONCE(!dev_is_pci(dev)))
- return;
-
- client = to_pci_dev(dev);
- map_type = pci_p2pdma_map_type(p2p_pgmap->provider, client);
+ map_type = pci_p2pdma_map_type(sg_page(sg)->pgmap, dev);
if (map_type == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE)
dma_unmap_sg_attrs(dev, sg, nents, dir, attrs);
diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c
index c32f3b7540e8..0c6446519640 100644
--- a/drivers/pci/pci-label.c
+++ b/drivers/pci/pci-label.c
@@ -139,14 +139,17 @@ enum acpi_attr_enum {
ACPI_ATTR_INDEX_SHOW,
};
-static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf)
+static int dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf)
{
int len;
+
len = utf16s_to_utf8s((const wchar_t *)obj->buffer.pointer,
obj->buffer.length,
UTF16_LITTLE_ENDIAN,
- buf, PAGE_SIZE);
- buf[len] = '\n';
+ buf, PAGE_SIZE - 1);
+ buf[len++] = '\n';
+
+ return len;
}
static int dsm_get_label(struct device *dev, char *buf,
@@ -154,7 +157,7 @@ static int dsm_get_label(struct device *dev, char *buf,
{
acpi_handle handle = ACPI_HANDLE(dev);
union acpi_object *obj, *tmp;
- int len = -1;
+ int len = 0;
if (!handle)
return -1;
@@ -175,20 +178,19 @@ static int dsm_get_label(struct device *dev, char *buf,
* this entry must return a null string.
*/
if (attr == ACPI_ATTR_INDEX_SHOW) {
- scnprintf(buf, PAGE_SIZE, "%llu\n", tmp->integer.value);
+ len = sysfs_emit(buf, "%llu\n", tmp->integer.value);
} else if (attr == ACPI_ATTR_LABEL_SHOW) {
if (tmp[1].type == ACPI_TYPE_STRING)
- scnprintf(buf, PAGE_SIZE, "%s\n",
- tmp[1].string.pointer);
+ len = sysfs_emit(buf, "%s\n",
+ tmp[1].string.pointer);
else if (tmp[1].type == ACPI_TYPE_BUFFER)
- dsm_label_utf16s_to_utf8s(tmp + 1, buf);
+ len = dsm_label_utf16s_to_utf8s(tmp + 1, buf);
}
- len = strlen(buf) > 0 ? strlen(buf) : -1;
}
ACPI_FREE(obj);
- return len;
+ return len > 0 ? len : -1;
}
static ssize_t label_show(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index beb8d1f4fafe..5d63df7c1820 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -537,7 +537,7 @@ static ssize_t devspec_show(struct device *dev,
if (np == NULL)
return 0;
- return sysfs_emit(buf, "%pOF", np);
+ return sysfs_emit(buf, "%pOF\n", np);
}
static DEVICE_ATTR_RO(devspec);
#endif
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b717680377a9..aacf575c15cf 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1900,11 +1900,21 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
int err;
int i, bars = 0;
- if (atomic_inc_return(&dev->enable_cnt) > 1) {
- pci_update_current_state(dev, dev->current_state);
- return 0; /* already enabled */
+ /*
+ * Power state could be unknown at this point, either due to a fresh
+ * boot or a device removal call. So get the current power state
+ * so that things like MSI message writing will behave as expected
+ * (e.g. if the device really is in D0 at enable time).
+ */
+ if (dev->pm_cap) {
+ u16 pmcsr;
+ pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
+ dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
}
+ if (atomic_inc_return(&dev->enable_cnt) > 1)
+ return 0; /* already enabled */
+
bridge = pci_upstream_bridge(dev);
if (bridge)
pci_enable_bridge(bridge);
@@ -5020,6 +5030,16 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
return pci_reset_hotplug_slot(dev->slot->hotplug, probe);
}
+static int pci_reset_bus_function(struct pci_dev *dev, int probe)
+{
+ int rc;
+
+ rc = pci_dev_reset_slot_function(dev, probe);
+ if (rc != -ENOTTY)
+ return rc;
+ return pci_parent_bus_reset(dev, probe);
+}
+
static void pci_dev_lock(struct pci_dev *dev)
{
pci_cfg_access_lock(dev);
@@ -5028,7 +5048,7 @@ static void pci_dev_lock(struct pci_dev *dev)
}
/* Return 1 on successful lock, 0 on contention */
-static int pci_dev_trylock(struct pci_dev *dev)
+int pci_dev_trylock(struct pci_dev *dev)
{
if (pci_cfg_access_trylock(dev)) {
if (device_trylock(&dev->dev))
@@ -5038,12 +5058,14 @@ static int pci_dev_trylock(struct pci_dev *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(pci_dev_trylock);
-static void pci_dev_unlock(struct pci_dev *dev)
+void pci_dev_unlock(struct pci_dev *dev)
{
device_unlock(&dev->dev);
pci_cfg_access_unlock(dev);
}
+EXPORT_SYMBOL_GPL(pci_dev_unlock);
static void pci_dev_save_and_disable(struct pci_dev *dev)
{
@@ -5140,10 +5162,7 @@ int __pci_reset_function_locked(struct pci_dev *dev)
rc = pci_pm_reset(dev, 0);
if (rc != -ENOTTY)
return rc;
- rc = pci_dev_reset_slot_function(dev, 0);
- if (rc != -ENOTTY)
- return rc;
- return pci_parent_bus_reset(dev, 0);
+ return pci_reset_bus_function(dev, 0);
}
EXPORT_SYMBOL_GPL(__pci_reset_function_locked);
@@ -5175,11 +5194,8 @@ int pci_probe_reset_function(struct pci_dev *dev)
rc = pci_pm_reset(dev, 1);
if (rc != -ENOTTY)
return rc;
- rc = pci_dev_reset_slot_function(dev, 1);
- if (rc != -ENOTTY)
- return rc;
- return pci_parent_bus_reset(dev, 1);
+ return pci_reset_bus_function(dev, 1);
}
/**
@@ -6439,34 +6455,40 @@ static ssize_t resource_alignment_show(struct bus_type *bus, char *buf)
spin_lock(&resource_alignment_lock);
if (resource_alignment_param)
- count = scnprintf(buf, PAGE_SIZE, "%s", resource_alignment_param);
+ count = sysfs_emit(buf, "%s\n", resource_alignment_param);
spin_unlock(&resource_alignment_lock);
- /*
- * When set by the command line, resource_alignment_param will not
- * have a trailing line feed, which is ugly. So conditionally add
- * it here.
- */
- if (count >= 2 && buf[count - 2] != '\n' && count < PAGE_SIZE - 1) {
- buf[count - 1] = '\n';
- buf[count++] = 0;
- }
-
return count;
}
static ssize_t resource_alignment_store(struct bus_type *bus,
const char *buf, size_t count)
{
- char *param = kstrndup(buf, count, GFP_KERNEL);
+ char *param, *old, *end;
+ if (count >= (PAGE_SIZE - 1))
+ return -EINVAL;
+
+ param = kstrndup(buf, count, GFP_KERNEL);
if (!param)
return -ENOMEM;
+ end = strchr(param, '\n');
+ if (end)
+ *end = '\0';
+
spin_lock(&resource_alignment_lock);
- kfree(resource_alignment_param);
- resource_alignment_param = param;
+ old = resource_alignment_param;
+ if (strlen(param)) {
+ resource_alignment_param = param;
+ } else {
+ kfree(param);
+ resource_alignment_param = NULL;
+ }
spin_unlock(&resource_alignment_lock);
+
+ kfree(old);
+
return count;
}
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 37c913bbc6e1..93dcdd431072 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -324,8 +324,8 @@ struct pci_sriov {
/**
* pci_dev_set_io_state - Set the new error state if possible.
*
- * @dev - pci device to set new error_state
- * @new - the state we want dev to be in
+ * @dev: PCI device to set new error_state
+ * @new: the state we want dev to be in
*
* Must be called with device_lock held.
*
@@ -385,6 +385,8 @@ static inline bool pci_dev_is_disconnected(const struct pci_dev *dev)
/* pci_dev priv_flags */
#define PCI_DEV_ADDED 0
+#define PCI_DPC_RECOVERED 1
+#define PCI_DPC_RECOVERING 2
static inline void pci_dev_assign_added(struct pci_dev *dev, bool added)
{
@@ -439,10 +441,12 @@ void pci_restore_dpc_state(struct pci_dev *dev);
void pci_dpc_init(struct pci_dev *pdev);
void dpc_process_error(struct pci_dev *pdev);
pci_ers_result_t dpc_reset_link(struct pci_dev *pdev);
+bool pci_dpc_recovered(struct pci_dev *pdev);
#else
static inline void pci_save_dpc_state(struct pci_dev *dev) {}
static inline void pci_restore_dpc_state(struct pci_dev *dev) {}
static inline void pci_dpc_init(struct pci_dev *pdev) {}
+static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
#endif
#ifdef CONFIG_PCIEPORTBUS
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index ec943cee5ecc..df4ba9b384c2 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -529,21 +529,23 @@ static const char *aer_agent_string[] = {
char *buf) \
{ \
unsigned int i; \
- char *str = buf; \
struct pci_dev *pdev = to_pci_dev(dev); \
u64 *stats = pdev->aer_stats->stats_array; \
+ size_t len = 0; \
\
for (i = 0; i < ARRAY_SIZE(strings_array); i++) { \
if (strings_array[i]) \
- str += sprintf(str, "%s %llu\n", \
- strings_array[i], stats[i]); \
+ len += sysfs_emit_at(buf, len, "%s %llu\n", \
+ strings_array[i], \
+ stats[i]); \
else if (stats[i]) \
- str += sprintf(str, #stats_array "_bit[%d] %llu\n",\
- i, stats[i]); \
+ len += sysfs_emit_at(buf, len, \
+ #stats_array "_bit[%d] %llu\n",\
+ i, stats[i]); \
} \
- str += sprintf(str, "TOTAL_%s %llu\n", total_string, \
- pdev->aer_stats->total_field); \
- return str-buf; \
+ len += sysfs_emit_at(buf, len, "TOTAL_%s %llu\n", total_string, \
+ pdev->aer_stats->total_field); \
+ return len; \
} \
static DEVICE_ATTR_RO(name)
@@ -563,7 +565,7 @@ aer_stats_dev_attr(aer_dev_nonfatal, dev_nonfatal_errs,
char *buf) \
{ \
struct pci_dev *pdev = to_pci_dev(dev); \
- return sprintf(buf, "%llu\n", pdev->aer_stats->field); \
+ return sysfs_emit(buf, "%llu\n", pdev->aer_stats->field); \
} \
static DEVICE_ATTR_RO(name)
@@ -983,7 +985,7 @@ static void aer_recover_work_func(struct work_struct *work)
pdev = pci_get_domain_bus_and_slot(entry.domain, entry.bus,
entry.devfn);
if (!pdev) {
- pr_err("AER recover: Can not find pci_dev for %04x:%02x:%02x:%x\n",
+ pr_err("no pci_dev for %04x:%02x:%02x.%x\n",
entry.domain, entry.bus,
PCI_SLOT(entry.devfn), PCI_FUNC(entry.devfn));
continue;
@@ -1022,7 +1024,7 @@ void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
&aer_recover_ring_lock))
schedule_work(&aer_recover_work);
else
- pr_err("AER recover: Buffer overflow when recovering AER for %04x:%02x:%02x:%x\n",
+ pr_err("buffer overflow in recovery for %04x:%02x:%02x.%x\n",
domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
}
EXPORT_SYMBOL_GPL(aer_recover_queue);
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index ac0557a305af..013a47f587ce 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -1208,7 +1208,7 @@ static ssize_t aspm_attr_show_common(struct device *dev,
struct pci_dev *pdev = to_pci_dev(dev);
struct pcie_link_state *link = pcie_aspm_get_link(pdev);
- return sprintf(buf, "%d\n", (link->aspm_enabled & state) ? 1 : 0);
+ return sysfs_emit(buf, "%d\n", (link->aspm_enabled & state) ? 1 : 0);
}
static ssize_t aspm_attr_store_common(struct device *dev,
@@ -1265,7 +1265,7 @@ static ssize_t clkpm_show(struct device *dev,
struct pci_dev *pdev = to_pci_dev(dev);
struct pcie_link_state *link = pcie_aspm_get_link(pdev);
- return sprintf(buf, "%d\n", link->clkpm_enabled);
+ return sysfs_emit(buf, "%d\n", link->clkpm_enabled);
}
static ssize_t clkpm_store(struct device *dev,
diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c
index e05aba86a317..c556e7beafe3 100644
--- a/drivers/pci/pcie/dpc.c
+++ b/drivers/pci/pcie/dpc.c
@@ -71,6 +71,58 @@ void pci_restore_dpc_state(struct pci_dev *dev)
pci_write_config_word(dev, dev->dpc_cap + PCI_EXP_DPC_CTL, *cap);
}
+static DECLARE_WAIT_QUEUE_HEAD(dpc_completed_waitqueue);
+
+#ifdef CONFIG_HOTPLUG_PCI_PCIE
+static bool dpc_completed(struct pci_dev *pdev)
+{
+ u16 status;
+
+ pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_STATUS, &status);
+ if ((status != 0xffff) && (status & PCI_EXP_DPC_STATUS_TRIGGER))
+ return false;
+
+ if (test_bit(PCI_DPC_RECOVERING, &pdev->priv_flags))
+ return false;
+
+ return true;
+}
+
+/**
+ * pci_dpc_recovered - whether DPC triggered and has recovered successfully
+ * @pdev: PCI device
+ *
+ * Return true if DPC was triggered for @pdev and has recovered successfully.
+ * Wait for recovery if it hasn't completed yet. Called from the PCIe hotplug
+ * driver to recognize and ignore Link Down/Up events caused by DPC.
+ */
+bool pci_dpc_recovered(struct pci_dev *pdev)
+{
+ struct pci_host_bridge *host;
+
+ if (!pdev->dpc_cap)
+ return false;
+
+ /*
+ * Synchronization between hotplug and DPC is not supported
+ * if DPC is owned by firmware and EDR is not enabled.
+ */
+ host = pci_find_host_bridge(pdev->bus);
+ if (!host->native_dpc && !IS_ENABLED(CONFIG_PCIE_EDR))
+ return false;
+
+ /*
+ * Need a timeout in case DPC never completes due to failure of
+ * dpc_wait_rp_inactive(). The spec doesn't mandate a time limit,
+ * but reports indicate that DPC completes within 4 seconds.
+ */
+ wait_event_timeout(dpc_completed_waitqueue, dpc_completed(pdev),
+ msecs_to_jiffies(4000));
+
+ return test_and_clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
+}
+#endif /* CONFIG_HOTPLUG_PCI_PCIE */
+
static int dpc_wait_rp_inactive(struct pci_dev *pdev)
{
unsigned long timeout = jiffies + HZ;
@@ -91,8 +143,11 @@ static int dpc_wait_rp_inactive(struct pci_dev *pdev)
pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
{
+ pci_ers_result_t ret;
u16 cap;
+ set_bit(PCI_DPC_RECOVERING, &pdev->priv_flags);
+
/*
* DPC disables the Link automatically in hardware, so it has
* already been reset by the time we get here.
@@ -106,18 +161,27 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
if (!pcie_wait_for_link(pdev, false))
pci_info(pdev, "Data Link Layer Link Active not cleared in 1000 msec\n");
- if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev))
- return PCI_ERS_RESULT_DISCONNECT;
+ if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev)) {
+ clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
+ ret = PCI_ERS_RESULT_DISCONNECT;
+ goto out;
+ }
pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS,
PCI_EXP_DPC_STATUS_TRIGGER);
if (!pcie_wait_for_link(pdev, true)) {
pci_info(pdev, "Data Link Layer Link Active not set in 1000 msec\n");
- return PCI_ERS_RESULT_DISCONNECT;
+ clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
+ ret = PCI_ERS_RESULT_DISCONNECT;
+ } else {
+ set_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
+ ret = PCI_ERS_RESULT_RECOVERED;
}
-
- return PCI_ERS_RESULT_RECOVERED;
+out:
+ clear_bit(PCI_DPC_RECOVERING, &pdev->priv_flags);
+ wake_up_all(&dpc_completed_waitqueue);
+ return ret;
}
static void dpc_process_rp_pio_error(struct pci_dev *pdev)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 275204646c68..79177ac37880 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1576,6 +1576,26 @@ static void set_pcie_untrusted(struct pci_dev *dev)
dev->untrusted = true;
}
+static void pci_set_removable(struct pci_dev *dev)
+{
+ struct pci_dev *parent = pci_upstream_bridge(dev);
+
+ /*
+ * We (only) consider everything downstream from an external_facing
+ * device to be removable by the user. We're mainly concerned with
+ * consumer platforms with user accessible thunderbolt ports that are
+ * vulnerable to DMA attacks, and we expect those ports to be marked by
+ * the firmware as external_facing. Devices in traditional hotplug
+ * slots can technically be removed, but the expectation is that unless
+ * the port is marked with external_facing, such devices are less
+ * accessible to user / may not be removed by end user, and thus not
+ * exposed as "removable" to userspace.
+ */
+ if (parent &&
+ (parent->external_facing || dev_is_removable(&parent->dev)))
+ dev_set_removable(&dev->dev, DEVICE_REMOVABLE);
+}
+
/**
* pci_ext_cfg_is_aliased - Is ext config space just an alias of std config?
* @dev: PCI device
@@ -1823,6 +1843,8 @@ int pci_setup_device(struct pci_dev *dev)
/* Early fixups, before probing the BARs */
pci_fixup_device(pci_fixup_early, dev);
+ pci_set_removable(dev);
+
pci_info(dev, "[%04x:%04x] type %02x class %#08x\n",
dev->vendor, dev->device, dev->hdr_type, dev->class);
@@ -2227,6 +2249,7 @@ static void pci_release_dev(struct device *dev)
pci_bus_put(pci_dev->bus);
kfree(pci_dev->driver_override);
bitmap_free(pci_dev->dma_alias_mask);
+ dev_dbg(dev, "device released\n");
kfree(pci_dev);
}
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 9bab07302bbf..d32fbfc93ea9 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -230,8 +230,8 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
break;
}
/* If arch decided it can't, fall through... */
-#endif /* HAVE_PCI_MMAP */
fallthrough;
+#endif /* HAVE_PCI_MMAP */
default:
ret = -EINVAL;
break;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 22b2bb1109c9..6d74386eadc2 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -27,6 +27,7 @@
#include <linux/nvme.h>
#include <linux/platform_data/x86/apple.h>
#include <linux/pm_runtime.h>
+#include <linux/suspend.h>
#include <linux/switchtec.h>
#include <asm/dma.h> /* isa_dma_bridge_buggy */
#include "pci.h"
@@ -3656,6 +3657,16 @@ static void quirk_apple_poweroff_thunderbolt(struct pci_dev *dev)
return;
if (pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM)
return;
+
+ /*
+ * SXIO/SXFP/SXLF turns off power to the Thunderbolt controller.
+ * We don't know how to turn it back on again, but firmware does,
+ * so we can only use SXIO/SXFP/SXLF if we're suspending via
+ * firmware.
+ */
+ if (!pm_suspend_via_firmware())
+ return;
+
bridge = ACPI_HANDLE(&dev->dev);
if (!bridge)
return;
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index d627dd9179b4..751a26668e3a 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -39,19 +39,19 @@ static const struct sysfs_ops pci_slot_sysfs_ops = {
static ssize_t address_read_file(struct pci_slot *slot, char *buf)
{
if (slot->number == 0xff)
- return sprintf(buf, "%04x:%02x\n",
- pci_domain_nr(slot->bus),
- slot->bus->number);
- else
- return sprintf(buf, "%04x:%02x:%02x\n",
- pci_domain_nr(slot->bus),
- slot->bus->number,
- slot->number);
+ return sysfs_emit(buf, "%04x:%02x\n",
+ pci_domain_nr(slot->bus),
+ slot->bus->number);
+
+ return sysfs_emit(buf, "%04x:%02x:%02x\n",
+ pci_domain_nr(slot->bus),
+ slot->bus->number,
+ slot->number);
}
static ssize_t bus_speed_read(enum pci_bus_speed speed, char *buf)
{
- return sprintf(buf, "%s\n", pci_speed_string(speed));
+ return sysfs_emit(buf, "%s\n", pci_speed_string(speed));
}
static ssize_t max_speed_read_file(struct pci_slot *slot, char *buf)
diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c
index ba52459928f7..0b301f8be9ed 100644
--- a/drivers/pci/switch/switchtec.c
+++ b/drivers/pci/switch/switchtec.c
@@ -280,7 +280,7 @@ static ssize_t device_version_show(struct device *dev,
ver = ioread32(&stdev->mmio_sys_info->device_version);
- return sprintf(buf, "%x\n", ver);
+ return sysfs_emit(buf, "%x\n", ver);
}
static DEVICE_ATTR_RO(device_version);
@@ -292,7 +292,7 @@ static ssize_t fw_version_show(struct device *dev,
ver = ioread32(&stdev->mmio_sys_info->firmware_version);
- return sprintf(buf, "%08x\n", ver);
+ return sysfs_emit(buf, "%08x\n", ver);
}
static DEVICE_ATTR_RO(fw_version);
@@ -344,7 +344,7 @@ static ssize_t component_vendor_show(struct device *dev,
/* component_vendor field not supported after gen3 */
if (stdev->gen != SWITCHTEC_GEN3)
- return sprintf(buf, "none\n");
+ return sysfs_emit(buf, "none\n");
return io_string_show(buf, &si->gen3.component_vendor,
sizeof(si->gen3.component_vendor));
@@ -359,9 +359,9 @@ static ssize_t component_id_show(struct device *dev,
/* component_id field not supported after gen3 */
if (stdev->gen != SWITCHTEC_GEN3)
- return sprintf(buf, "none\n");
+ return sysfs_emit(buf, "none\n");
- return sprintf(buf, "PM%04X\n", id);
+ return sysfs_emit(buf, "PM%04X\n", id);
}
static DEVICE_ATTR_RO(component_id);
@@ -373,9 +373,9 @@ static ssize_t component_revision_show(struct device *dev,
/* component_revision field not supported after gen3 */
if (stdev->gen != SWITCHTEC_GEN3)
- return sprintf(buf, "255\n");
+ return sysfs_emit(buf, "255\n");
- return sprintf(buf, "%d\n", rev);
+ return sysfs_emit(buf, "%d\n", rev);
}
static DEVICE_ATTR_RO(component_revision);
@@ -384,7 +384,7 @@ static ssize_t partition_show(struct device *dev,
{
struct switchtec_dev *stdev = to_stdev(dev);
- return sprintf(buf, "%d\n", stdev->partition);
+ return sysfs_emit(buf, "%d\n", stdev->partition);
}
static DEVICE_ATTR_RO(partition);
@@ -393,7 +393,7 @@ static ssize_t partition_count_show(struct device *dev,
{
struct switchtec_dev *stdev = to_stdev(dev);
- return sprintf(buf, "%d\n", stdev->partition_count);
+ return sysfs_emit(buf, "%d\n", stdev->partition_count);
}
static DEVICE_ATTR_RO(partition_count);
diff --git a/drivers/perf/arm-cci.c b/drivers/perf/arm-cci.c
index 666d8a9b557f..54aca3a62814 100644
--- a/drivers/perf/arm-cci.c
+++ b/drivers/perf/arm-cci.c
@@ -37,7 +37,7 @@
#define CCI_PMU_CNTR_SIZE(model) ((model)->cntr_size)
#define CCI_PMU_CNTR_BASE(model, idx) ((idx) * CCI_PMU_CNTR_SIZE(model))
-#define CCI_PMU_CNTR_MASK ((1ULL << 32) -1)
+#define CCI_PMU_CNTR_MASK ((1ULL << 32) - 1)
#define CCI_PMU_CNTR_LAST(cci_pmu) (cci_pmu->num_cntrs - 1)
#define CCI_PMU_MAX_HW_CNTRS(model) \
@@ -806,7 +806,7 @@ static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *ev
return cci_pmu->model->get_event_idx(cci_pmu, hw, cci_event);
/* Generic code to find an unused idx from the mask */
- for(idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++)
+ for (idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++)
if (!test_and_set_bit(idx, hw->used_mask))
return idx;
diff --git a/drivers/perf/arm-ccn.c b/drivers/perf/arm-ccn.c
index 96d47cb302dd..a96c31604545 100644
--- a/drivers/perf/arm-ccn.c
+++ b/drivers/perf/arm-ccn.c
@@ -1211,7 +1211,7 @@ static int arm_ccn_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
perf_pmu_migrate_context(&dt->pmu, cpu, target);
dt->cpu = target;
if (ccn->irq)
- WARN_ON(irq_set_affinity_hint(ccn->irq, cpumask_of(dt->cpu)));
+ WARN_ON(irq_set_affinity(ccn->irq, cpumask_of(dt->cpu)));
return 0;
}
@@ -1291,7 +1291,7 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn)
/* Also make sure that the overflow interrupt is handled by this CPU */
if (ccn->irq) {
- err = irq_set_affinity_hint(ccn->irq, cpumask_of(ccn->dt.cpu));
+ err = irq_set_affinity(ccn->irq, cpumask_of(ccn->dt.cpu));
if (err) {
dev_err(ccn->dev, "Failed to set interrupt affinity!\n");
goto error_set_affinity;
@@ -1325,8 +1325,6 @@ static void arm_ccn_pmu_cleanup(struct arm_ccn *ccn)
cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_CCN_ONLINE,
&ccn->dt.node);
- if (ccn->irq)
- irq_set_affinity_hint(ccn->irq, NULL);
for (i = 0; i < ccn->num_xps; i++)
writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL);
writel(0, ccn->dt.base + CCN_DT_PMCR);
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index 56a5c355701d..bc3cba5f8c5d 100644
--- a/drivers/perf/arm-cmn.c
+++ b/drivers/perf/arm-cmn.c
@@ -31,7 +31,7 @@
#define CMN_CI_CHILD_COUNT GENMASK_ULL(15, 0)
#define CMN_CI_CHILD_PTR_OFFSET GENMASK_ULL(31, 16)
-#define CMN_CHILD_NODE_ADDR GENMASK(27,0)
+#define CMN_CHILD_NODE_ADDR GENMASK(27, 0)
#define CMN_CHILD_NODE_EXTERNAL BIT(31)
#define CMN_ADDR_NODE_PTR GENMASK(27, 14)
@@ -1162,7 +1162,7 @@ static int arm_cmn_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
perf_pmu_migrate_context(&cmn->pmu, cpu, target);
for (i = 0; i < cmn->num_dtcs; i++)
- irq_set_affinity_hint(cmn->dtc[i].irq, cpumask_of(target));
+ irq_set_affinity(cmn->dtc[i].irq, cpumask_of(target));
cmn->cpu = target;
return 0;
}
@@ -1212,7 +1212,7 @@ static int arm_cmn_init_irqs(struct arm_cmn *cmn)
irq = cmn->dtc[i].irq;
for (j = i; j--; ) {
if (cmn->dtc[j].irq == irq) {
- cmn->dtc[j].irq_friend = j - i;
+ cmn->dtc[j].irq_friend = i - j;
goto next;
}
}
@@ -1222,7 +1222,7 @@ static int arm_cmn_init_irqs(struct arm_cmn *cmn)
if (err)
return err;
- err = irq_set_affinity_hint(irq, cpumask_of(cmn->cpu));
+ err = irq_set_affinity(irq, cpumask_of(cmn->cpu));
if (err)
return err;
next:
@@ -1568,16 +1568,11 @@ static int arm_cmn_probe(struct platform_device *pdev)
static int arm_cmn_remove(struct platform_device *pdev)
{
struct arm_cmn *cmn = platform_get_drvdata(pdev);
- int i;
writel_relaxed(0, cmn->dtc[0].base + CMN_DT_DTC_CTL);
perf_pmu_unregister(&cmn->pmu);
cpuhp_state_remove_instance(arm_cmn_hp_state, &cmn->cpuhp_node);
-
- for (i = 0; i < cmn->num_dtcs; i++)
- irq_set_affinity_hint(cmn->dtc[i].irq, NULL);
-
return 0;
}
diff --git a/drivers/perf/arm_dmc620_pmu.c b/drivers/perf/arm_dmc620_pmu.c
index b6c2511d59af..280a6ae3e27c 100644
--- a/drivers/perf/arm_dmc620_pmu.c
+++ b/drivers/perf/arm_dmc620_pmu.c
@@ -421,7 +421,7 @@ static struct dmc620_pmu_irq *__dmc620_pmu_get_irq(int irq_num)
if (ret)
goto out_free_aff;
- ret = irq_set_affinity_hint(irq_num, cpumask_of(irq->cpu));
+ ret = irq_set_affinity(irq_num, cpumask_of(irq->cpu));
if (ret)
goto out_free_irq;
@@ -475,7 +475,6 @@ static void dmc620_pmu_put_irq(struct dmc620_pmu *dmc620_pmu)
list_del(&irq->irqs_node);
mutex_unlock(&dmc620_pmu_irqs_lock);
- WARN_ON(irq_set_affinity_hint(irq->irq_num, NULL));
free_irq(irq->irq_num, irq);
cpuhp_state_remove_instance_nocalls(cpuhp_state_num, &irq->node);
kfree(irq);
@@ -622,7 +621,7 @@ static int dmc620_pmu_cpu_teardown(unsigned int cpu,
perf_pmu_migrate_context(&dmc620_pmu->pmu, irq->cpu, target);
mutex_unlock(&dmc620_pmu_irqs_lock);
- WARN_ON(irq_set_affinity_hint(irq->irq_num, cpumask_of(target)));
+ WARN_ON(irq_set_affinity(irq->irq_num, cpumask_of(target)));
irq->cpu = target;
return 0;
diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c
index 196faea074d0..a36698a90d2f 100644
--- a/drivers/perf/arm_dsu_pmu.c
+++ b/drivers/perf/arm_dsu_pmu.c
@@ -687,7 +687,7 @@ static void dsu_pmu_probe_pmu(struct dsu_pmu *dsu_pmu)
static void dsu_pmu_set_active_cpu(int cpu, struct dsu_pmu *dsu_pmu)
{
cpumask_set_cpu(cpu, &dsu_pmu->active_cpu);
- if (irq_set_affinity_hint(dsu_pmu->irq, &dsu_pmu->active_cpu))
+ if (irq_set_affinity(dsu_pmu->irq, &dsu_pmu->active_cpu))
pr_warn("Failed to set irq affinity to %d\n", cpu);
}
@@ -769,7 +769,6 @@ static int dsu_pmu_device_probe(struct platform_device *pdev)
if (rc) {
cpuhp_state_remove_instance(dsu_pmu_cpuhp_state,
&dsu_pmu->cpuhp_node);
- irq_set_affinity_hint(dsu_pmu->irq, NULL);
}
return rc;
@@ -781,7 +780,6 @@ static int dsu_pmu_device_remove(struct platform_device *pdev)
perf_pmu_unregister(&dsu_pmu->pmu);
cpuhp_state_remove_instance(dsu_pmu_cpuhp_state, &dsu_pmu->cpuhp_node);
- irq_set_affinity_hint(dsu_pmu->irq, NULL);
return 0;
}
@@ -840,10 +838,8 @@ static int dsu_pmu_cpu_teardown(unsigned int cpu, struct hlist_node *node)
dst = dsu_pmu_get_online_cpu_any_but(dsu_pmu, cpu);
/* If there are no active CPUs in the DSU, leave IRQ disabled */
- if (dst >= nr_cpu_ids) {
- irq_set_affinity_hint(dsu_pmu->irq, NULL);
+ if (dst >= nr_cpu_ids)
return 0;
- }
perf_pmu_migrate_context(&dsu_pmu->pmu, cpu, dst);
dsu_pmu_set_active_cpu(dst, dsu_pmu);
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index d4f7f1f9cc77..3cbc3baf087f 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -563,14 +563,14 @@ static int armpmu_filter_match(struct perf_event *event)
return ret;
}
-static ssize_t armpmu_cpumask_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t cpus_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct arm_pmu *armpmu = to_arm_pmu(dev_get_drvdata(dev));
return cpumap_print_to_pagebuf(true, buf, &armpmu->supported_cpus);
}
-static DEVICE_ATTR(cpus, S_IRUGO, armpmu_cpumask_show, NULL);
+static DEVICE_ATTR_RO(cpus);
static struct attribute *armpmu_common_attrs[] = {
&dev_attr_cpus.attr,
@@ -644,11 +644,9 @@ int armpmu_request_irq(int irq, int cpu)
}
irq_flags = IRQF_PERCPU |
- IRQF_NOBALANCING |
+ IRQF_NOBALANCING | IRQF_NO_AUTOEN |
IRQF_NO_THREAD;
- irq_set_status_flags(irq, IRQ_NOAUTOEN);
-
err = request_nmi(irq, handler, irq_flags, "arm-pmu",
per_cpu_ptr(&cpu_armpmu, cpu));
@@ -670,7 +668,7 @@ int armpmu_request_irq(int irq, int cpu)
&cpu_armpmu);
irq_ops = &percpu_pmuirq_ops;
} else {
- has_nmi= true;
+ has_nmi = true;
irq_ops = &percpu_pmunmi_ops;
}
} else {
@@ -869,10 +867,8 @@ static struct arm_pmu *__armpmu_alloc(gfp_t flags)
int cpu;
pmu = kzalloc(sizeof(*pmu), flags);
- if (!pmu) {
- pr_info("failed to allocate PMU device!\n");
+ if (!pmu)
goto out;
- }
pmu->hw_events = alloc_percpu_gfp(struct pmu_hw_events, flags);
if (!pmu->hw_events) {
diff --git a/drivers/perf/arm_smmuv3_pmu.c b/drivers/perf/arm_smmuv3_pmu.c
index ff6fab4bae30..226348822ab3 100644
--- a/drivers/perf/arm_smmuv3_pmu.c
+++ b/drivers/perf/arm_smmuv3_pmu.c
@@ -277,7 +277,7 @@ static int smmu_pmu_apply_event_filter(struct smmu_pmu *smmu_pmu,
struct perf_event *event, int idx)
{
u32 span, sid;
- unsigned int num_ctrs = smmu_pmu->num_counters;
+ unsigned int cur_idx, num_ctrs = smmu_pmu->num_counters;
bool filter_en = !!get_filter_enable(event);
span = filter_en ? get_filter_span(event) :
@@ -285,17 +285,19 @@ static int smmu_pmu_apply_event_filter(struct smmu_pmu *smmu_pmu,
sid = filter_en ? get_filter_stream_id(event) :
SMMU_PMCG_DEFAULT_FILTER_SID;
- /* Support individual filter settings */
- if (!smmu_pmu->global_filter) {
+ cur_idx = find_first_bit(smmu_pmu->used_counters, num_ctrs);
+ /*
+ * Per-counter filtering, or scheduling the first globally-filtered
+ * event into an empty PMU so idx == 0 and it works out equivalent.
+ */
+ if (!smmu_pmu->global_filter || cur_idx == num_ctrs) {
smmu_pmu_set_event_filter(event, idx, span, sid);
return 0;
}
- /* Requested settings same as current global settings*/
- idx = find_first_bit(smmu_pmu->used_counters, num_ctrs);
- if (idx == num_ctrs ||
- smmu_pmu_check_global_filter(smmu_pmu->events[idx], event)) {
- smmu_pmu_set_event_filter(event, 0, span, sid);
+ /* Otherwise, must match whatever's currently scheduled */
+ if (smmu_pmu_check_global_filter(smmu_pmu->events[cur_idx], event)) {
+ smmu_pmu_set_evtyper(smmu_pmu, idx, get_event(event));
return 0;
}
@@ -509,11 +511,8 @@ static ssize_t smmu_pmu_event_show(struct device *dev,
return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id);
}
-#define SMMU_EVENT_ATTR(name, config) \
- (&((struct perf_pmu_events_attr) { \
- .attr = __ATTR(name, 0444, smmu_pmu_event_show, NULL), \
- .id = config, \
- }).attr.attr)
+#define SMMU_EVENT_ATTR(name, config) \
+ PMU_EVENT_ATTR_ID(name, smmu_pmu_event_show, config)
static struct attribute *smmu_pmu_events[] = {
SMMU_EVENT_ATTR(cycles, 0),
@@ -628,7 +627,7 @@ static int smmu_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
perf_pmu_migrate_context(&smmu_pmu->pmu, cpu, target);
smmu_pmu->on_cpu = target;
- WARN_ON(irq_set_affinity_hint(smmu_pmu->irq, cpumask_of(target)));
+ WARN_ON(irq_set_affinity(smmu_pmu->irq, cpumask_of(target)));
return 0;
}
@@ -839,15 +838,14 @@ static int smmu_pmu_probe(struct platform_device *pdev)
/* Pick one CPU to be the preferred one to use */
smmu_pmu->on_cpu = raw_smp_processor_id();
- WARN_ON(irq_set_affinity_hint(smmu_pmu->irq,
- cpumask_of(smmu_pmu->on_cpu)));
+ WARN_ON(irq_set_affinity(smmu_pmu->irq, cpumask_of(smmu_pmu->on_cpu)));
err = cpuhp_state_add_instance_nocalls(cpuhp_state_num,
&smmu_pmu->node);
if (err) {
dev_err(dev, "Error %d registering hotplug, PMU @%pa\n",
err, &res_0->start);
- goto out_clear_affinity;
+ return err;
}
err = perf_pmu_register(&smmu_pmu->pmu, name, -1);
@@ -866,8 +864,6 @@ static int smmu_pmu_probe(struct platform_device *pdev)
out_unregister:
cpuhp_state_remove_instance_nocalls(cpuhp_state_num, &smmu_pmu->node);
-out_clear_affinity:
- irq_set_affinity_hint(smmu_pmu->irq, NULL);
return err;
}
@@ -877,7 +873,6 @@ static int smmu_pmu_remove(struct platform_device *pdev)
perf_pmu_unregister(&smmu_pmu->pmu);
cpuhp_state_remove_instance_nocalls(cpuhp_state_num, &smmu_pmu->node);
- irq_set_affinity_hint(smmu_pmu->irq, NULL);
return 0;
}
diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c
index 8a1e86ab2d8e..d44bcc29d99c 100644
--- a/drivers/perf/arm_spe_pmu.c
+++ b/drivers/perf/arm_spe_pmu.c
@@ -231,15 +231,14 @@ static const struct attribute_group arm_spe_pmu_format_group = {
.attrs = arm_spe_pmu_formats_attr,
};
-static ssize_t arm_spe_pmu_get_attr_cpumask(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t cpumask_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct arm_spe_pmu *spe_pmu = dev_get_drvdata(dev);
return cpumap_print_to_pagebuf(true, buf, &spe_pmu->supported_cpus);
}
-static DEVICE_ATTR(cpumask, S_IRUGO, arm_spe_pmu_get_attr_cpumask, NULL);
+static DEVICE_ATTR_RO(cpumask);
static struct attribute *arm_spe_pmu_attrs[] = {
&dev_attr_cpumask.attr,
@@ -1044,7 +1043,6 @@ static void __arm_spe_pmu_dev_probe(void *info)
spe_pmu->max_record_sz, spe_pmu->align, spe_pmu->features);
spe_pmu->features |= SPE_PMU_FEAT_DEV_PROBED;
- return;
}
static void __arm_spe_pmu_reset_local(void)
@@ -1190,10 +1188,8 @@ static int arm_spe_pmu_device_probe(struct platform_device *pdev)
}
spe_pmu = devm_kzalloc(dev, sizeof(*spe_pmu), GFP_KERNEL);
- if (!spe_pmu) {
- dev_err(dev, "failed to allocate spe_pmu\n");
+ if (!spe_pmu)
return -ENOMEM;
- }
spe_pmu->handle = alloc_percpu(typeof(*spe_pmu->handle));
if (!spe_pmu->handle)
diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c
index 2bbb93188064..94ebc1ecace7 100644
--- a/drivers/perf/fsl_imx8_ddr_perf.c
+++ b/drivers/perf/fsl_imx8_ddr_perf.c
@@ -222,11 +222,8 @@ ddr_pmu_event_show(struct device *dev, struct device_attribute *attr,
return sysfs_emit(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)
+#define IMX8_DDR_PMU_EVENT_ATTR(_name, _id) \
+ PMU_EVENT_ATTR_ID(_name, ddr_pmu_event_show, _id)
static struct attribute *ddr_perf_events_attrs[] = {
IMX8_DDR_PMU_EVENT_ATTR(cycles, EVENT_CYCLES_ID),
@@ -674,7 +671,7 @@ static int ddr_perf_offline_cpu(unsigned int cpu, struct hlist_node *node)
perf_pmu_migrate_context(&pmu->pmu, cpu, target);
pmu->cpu = target;
- WARN_ON(irq_set_affinity_hint(pmu->irq, cpumask_of(pmu->cpu)));
+ WARN_ON(irq_set_affinity(pmu->irq, cpumask_of(pmu->cpu)));
return 0;
}
@@ -705,8 +702,10 @@ static int ddr_perf_probe(struct platform_device *pdev)
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, DDR_PERF_DEV_NAME "%d",
num);
- if (!name)
- return -ENOMEM;
+ if (!name) {
+ ret = -ENOMEM;
+ goto cpuhp_state_err;
+ }
pmu->devtype_data = of_device_get_match_data(&pdev->dev);
@@ -749,7 +748,7 @@ static int ddr_perf_probe(struct platform_device *pdev)
}
pmu->irq = irq;
- ret = irq_set_affinity_hint(pmu->irq, cpumask_of(pmu->cpu));
+ ret = irq_set_affinity(pmu->irq, cpumask_of(pmu->cpu));
if (ret) {
dev_err(pmu->dev, "Failed to set interrupt affinity!\n");
goto ddr_perf_err;
@@ -777,7 +776,6 @@ static int ddr_perf_remove(struct platform_device *pdev)
cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node);
cpuhp_remove_multi_state(pmu->cpuhp_state);
- irq_set_affinity_hint(pmu->irq, NULL);
perf_pmu_unregister(&pmu->pmu);
diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
index 7c8a4bc21db4..62299ab5a9be 100644
--- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
@@ -2,7 +2,7 @@
/*
* HiSilicon SoC DDRC uncore Hardware event counters support
*
- * Copyright (C) 2017 Hisilicon Limited
+ * Copyright (C) 2017 HiSilicon Limited
* Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
* Anurup M <anurup.m@huawei.com>
*
@@ -537,7 +537,6 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
dev_err(ddrc_pmu->dev, "DDRC PMU register failed!\n");
cpuhp_state_remove_instance_nocalls(
CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE, &ddrc_pmu->node);
- irq_set_affinity_hint(ddrc_pmu->irq, NULL);
}
return ret;
@@ -550,8 +549,6 @@ static int hisi_ddrc_pmu_remove(struct platform_device *pdev)
perf_pmu_unregister(&ddrc_pmu->pmu);
cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
&ddrc_pmu->node);
- irq_set_affinity_hint(ddrc_pmu->irq, NULL);
-
return 0;
}
diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
index 0316fabe32f1..393513150106 100644
--- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
@@ -2,7 +2,7 @@
/*
* HiSilicon SoC HHA uncore Hardware event counters support
*
- * Copyright (C) 2017 Hisilicon Limited
+ * Copyright (C) 2017 HiSilicon Limited
* Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
* Anurup M <anurup.m@huawei.com>
*
@@ -90,7 +90,7 @@ static void hisi_hha_pmu_config_ds(struct perf_event *event)
val = readl(hha_pmu->base + HHA_DATSRC_CTRL);
val |= HHA_DATSRC_SKT_EN;
- writel(ds_skt, hha_pmu->base + HHA_DATSRC_CTRL);
+ writel(val, hha_pmu->base + HHA_DATSRC_CTRL);
}
}
@@ -104,7 +104,7 @@ static void hisi_hha_pmu_clear_ds(struct perf_event *event)
val = readl(hha_pmu->base + HHA_DATSRC_CTRL);
val &= ~HHA_DATSRC_SKT_EN;
- writel(ds_skt, hha_pmu->base + HHA_DATSRC_CTRL);
+ writel(val, hha_pmu->base + HHA_DATSRC_CTRL);
}
}
@@ -540,7 +540,6 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev)
dev_err(hha_pmu->dev, "HHA PMU register failed!\n");
cpuhp_state_remove_instance_nocalls(
CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, &hha_pmu->node);
- irq_set_affinity_hint(hha_pmu->irq, NULL);
}
return ret;
@@ -553,8 +552,6 @@ static int hisi_hha_pmu_remove(struct platform_device *pdev)
perf_pmu_unregister(&hha_pmu->pmu);
cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
&hha_pmu->node);
- irq_set_affinity_hint(hha_pmu->irq, NULL);
-
return 0;
}
diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
index bf9f7772cac9..560ab964c8b5 100644
--- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
@@ -2,7 +2,7 @@
/*
* HiSilicon SoC L3C uncore Hardware event counters support
*
- * Copyright (C) 2017 Hisilicon Limited
+ * Copyright (C) 2017 HiSilicon Limited
* Author: Anurup M <anurup.m@huawei.com>
* Shaokun Zhang <zhangshaokun@hisilicon.com>
*
@@ -578,7 +578,6 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
dev_err(l3c_pmu->dev, "L3C PMU register failed!\n");
cpuhp_state_remove_instance_nocalls(
CPUHP_AP_PERF_ARM_HISI_L3_ONLINE, &l3c_pmu->node);
- irq_set_affinity_hint(l3c_pmu->irq, NULL);
}
return ret;
@@ -591,8 +590,6 @@ static int hisi_l3c_pmu_remove(struct platform_device *pdev)
perf_pmu_unregister(&l3c_pmu->pmu);
cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
&l3c_pmu->node);
- irq_set_affinity_hint(l3c_pmu->irq, NULL);
-
return 0;
}
diff --git a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
index 14f23eb31248..83264ec0a957 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
@@ -333,7 +333,7 @@ static struct attribute *hisi_pa_pmu_identifier_attrs[] = {
NULL
};
-static struct attribute_group hisi_pa_pmu_identifier_group = {
+static const struct attribute_group hisi_pa_pmu_identifier_group = {
.attrs = hisi_pa_pmu_identifier_attrs,
};
@@ -436,7 +436,6 @@ static int hisi_pa_pmu_probe(struct platform_device *pdev)
dev_err(pa_pmu->dev, "PMU register failed, ret = %d\n", ret);
cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
&pa_pmu->node);
- irq_set_affinity_hint(pa_pmu->irq, NULL);
return ret;
}
@@ -451,8 +450,6 @@ static int hisi_pa_pmu_remove(struct platform_device *pdev)
perf_pmu_unregister(&pa_pmu->pmu);
cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
&pa_pmu->node);
- irq_set_affinity_hint(pa_pmu->irq, NULL);
-
return 0;
}
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
index 13c68b5e39c4..a738aeab5c04 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
@@ -2,7 +2,7 @@
/*
* HiSilicon SoC Hardware event counters support
*
- * Copyright (C) 2017 Hisilicon Limited
+ * Copyright (C) 2017 HiSilicon Limited
* Author: Anurup M <anurup.m@huawei.com>
* Shaokun Zhang <zhangshaokun@hisilicon.com>
*
@@ -488,7 +488,7 @@ int hisi_uncore_pmu_online_cpu(unsigned int cpu, struct hlist_node *node)
hisi_pmu->on_cpu = cpu;
/* Overflow interrupt also should use the same CPU */
- WARN_ON(irq_set_affinity_hint(hisi_pmu->irq, cpumask_of(cpu)));
+ WARN_ON(irq_set_affinity(hisi_pmu->irq, cpumask_of(cpu)));
return 0;
}
@@ -521,7 +521,7 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
perf_pmu_migrate_context(&hisi_pmu->pmu, cpu, target);
/* Use this CPU for event counting */
hisi_pmu->on_cpu = target;
- WARN_ON(irq_set_affinity_hint(hisi_pmu->irq, cpumask_of(target)));
+ WARN_ON(irq_set_affinity(hisi_pmu->irq, cpumask_of(target)));
return 0;
}
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
index ea9d89bbc1ea..7f5841d6f592 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
@@ -2,7 +2,7 @@
/*
* HiSilicon SoC Hardware event counters support
*
- * Copyright (C) 2017 Hisilicon Limited
+ * Copyright (C) 2017 HiSilicon Limited
* Author: Anurup M <anurup.m@huawei.com>
* Shaokun Zhang <zhangshaokun@hisilicon.com>
*
diff --git a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
index 46be312fa126..6aedc303ff56 100644
--- a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
@@ -2,7 +2,7 @@
/*
* HiSilicon SLLC uncore Hardware event counters support
*
- * Copyright (C) 2020 Hisilicon Limited
+ * Copyright (C) 2020 HiSilicon Limited
* Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
*
* This code is based on the uncore PMUs like arm-cci and arm-ccn.
@@ -366,7 +366,7 @@ static struct attribute *hisi_sllc_pmu_identifier_attrs[] = {
NULL
};
-static struct attribute_group hisi_sllc_pmu_identifier_group = {
+static const struct attribute_group hisi_sllc_pmu_identifier_group = {
.attrs = hisi_sllc_pmu_identifier_attrs,
};
@@ -465,7 +465,6 @@ static int hisi_sllc_pmu_probe(struct platform_device *pdev)
dev_err(sllc_pmu->dev, "PMU register failed, ret = %d\n", ret);
cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
&sllc_pmu->node);
- irq_set_affinity_hint(sllc_pmu->irq, NULL);
return ret;
}
@@ -481,8 +480,6 @@ static int hisi_sllc_pmu_remove(struct platform_device *pdev)
perf_pmu_unregister(&sllc_pmu->pmu);
cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
&sllc_pmu->node);
- irq_set_affinity_hint(sllc_pmu->irq, NULL);
-
return 0;
}
diff --git a/drivers/perf/qcom_l2_pmu.c b/drivers/perf/qcom_l2_pmu.c
index fc54a80f9c5c..5b093badd0f6 100644
--- a/drivers/perf/qcom_l2_pmu.c
+++ b/drivers/perf/qcom_l2_pmu.c
@@ -679,11 +679,8 @@ static ssize_t l2cache_pmu_event_show(struct device *dev,
return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id);
}
-#define L2CACHE_EVENT_ATTR(_name, _id) \
- (&((struct perf_pmu_events_attr[]) { \
- { .attr = __ATTR(_name, 0444, l2cache_pmu_event_show, NULL), \
- .id = _id, } \
- })[0].attr.attr)
+#define L2CACHE_EVENT_ATTR(_name, _id) \
+ PMU_EVENT_ATTR_ID(_name, l2cache_pmu_event_show, _id)
static struct attribute *l2_cache_pmu_events[] = {
L2CACHE_EVENT_ATTR(cycles, L2_EVENT_CYCLES),
@@ -869,14 +866,14 @@ static int l2_cache_pmu_probe_cluster(struct device *dev, void *data)
irq = platform_get_irq(sdev, 0);
if (irq < 0)
return irq;
- irq_set_status_flags(irq, IRQ_NOAUTOEN);
cluster->irq = irq;
cluster->l2cache_pmu = l2cache_pmu;
cluster->on_cpu = -1;
err = devm_request_irq(&pdev->dev, irq, l2_cache_handle_irq,
- IRQF_NOBALANCING | IRQF_NO_THREAD,
+ IRQF_NOBALANCING | IRQF_NO_THREAD |
+ IRQF_NO_AUTOEN,
"l2-cache-pmu", cluster);
if (err) {
dev_err(&pdev->dev,
diff --git a/drivers/perf/qcom_l3_pmu.c b/drivers/perf/qcom_l3_pmu.c
index bba078077c93..1ff2ff6582bf 100644
--- a/drivers/perf/qcom_l3_pmu.c
+++ b/drivers/perf/qcom_l3_pmu.c
@@ -647,10 +647,7 @@ static ssize_t l3cache_pmu_event_show(struct device *dev,
}
#define L3CACHE_EVENT_ATTR(_name, _id) \
- (&((struct perf_pmu_events_attr[]) { \
- { .attr = __ATTR(_name, 0444, l3cache_pmu_event_show, NULL), \
- .id = _id, } \
- })[0].attr.attr)
+ PMU_EVENT_ATTR_ID(_name, l3cache_pmu_event_show, _id)
static struct attribute *qcom_l3_cache_pmu_events[] = {
L3CACHE_EVENT_ATTR(cycles, L3_EVENT_CYCLES),
@@ -670,15 +667,15 @@ static const struct attribute_group qcom_l3_cache_pmu_events_group = {
/* cpumask */
-static ssize_t qcom_l3_cache_pmu_cpumask_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t cpumask_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct l3cache_pmu *l3pmu = to_l3cache_pmu(dev_get_drvdata(dev));
return cpumap_print_to_pagebuf(true, buf, &l3pmu->cpumask);
}
-static DEVICE_ATTR(cpumask, 0444, qcom_l3_cache_pmu_cpumask_show, NULL);
+static DEVICE_ATTR_RO(cpumask);
static struct attribute *qcom_l3_cache_pmu_cpumask_attrs[] = {
&dev_attr_cpumask.attr,
@@ -767,10 +764,8 @@ static int qcom_l3_cache_pmu_probe(struct platform_device *pdev)
memrc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
l3pmu->regs = devm_ioremap_resource(&pdev->dev, memrc);
- if (IS_ERR(l3pmu->regs)) {
- dev_err(&pdev->dev, "Can't map PMU @%pa\n", &memrc->start);
+ if (IS_ERR(l3pmu->regs))
return PTR_ERR(l3pmu->regs);
- }
qcom_l3_cache__init(l3pmu);
diff --git a/drivers/perf/thunderx2_pmu.c b/drivers/perf/thunderx2_pmu.c
index 06a6d569b0b5..fc1a376ee906 100644
--- a/drivers/perf/thunderx2_pmu.c
+++ b/drivers/perf/thunderx2_pmu.c
@@ -817,10 +817,8 @@ static struct tx2_uncore_pmu *tx2_uncore_pmu_init_dev(struct device *dev,
}
base = devm_ioremap_resource(dev, &res);
- if (IS_ERR(base)) {
- dev_err(dev, "PMU type %d: Fail to map resource\n", type);
+ if (IS_ERR(base))
return NULL;
- }
tx2_pmu = devm_kzalloc(dev, sizeof(*tx2_pmu), GFP_KERNEL);
if (!tx2_pmu)
diff --git a/drivers/perf/xgene_pmu.c b/drivers/perf/xgene_pmu.c
index ffe3bdeec845..2b6d476bd213 100644
--- a/drivers/perf/xgene_pmu.c
+++ b/drivers/perf/xgene_pmu.c
@@ -278,17 +278,14 @@ static const struct attribute_group mc_pmu_v3_format_attr_group = {
static ssize_t xgene_pmu_event_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct dev_ext_attribute *eattr;
+ struct perf_pmu_events_attr *pmu_attr =
+ container_of(attr, struct perf_pmu_events_attr, attr);
- eattr = container_of(attr, struct dev_ext_attribute, attr);
- return sysfs_emit(buf, "config=0x%lx\n", (unsigned long) eattr->var);
+ return sysfs_emit(buf, "config=0x%llx\n", pmu_attr->id);
}
#define XGENE_PMU_EVENT_ATTR(_name, _config) \
- (&((struct dev_ext_attribute[]) { \
- { .attr = __ATTR(_name, S_IRUGO, xgene_pmu_event_show, NULL), \
- .var = (void *) _config, } \
- })[0].attr.attr)
+ PMU_EVENT_ATTR_ID(_name, xgene_pmu_event_show, _config)
static struct attribute *l3c_pmu_events_attrs[] = {
XGENE_PMU_EVENT_ATTR(cycle-count, 0x00),
@@ -604,15 +601,15 @@ static const struct attribute_group mc_pmu_v3_events_attr_group = {
/*
* sysfs cpumask attributes
*/
-static ssize_t xgene_pmu_cpumask_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t cpumask_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct xgene_pmu_dev *pmu_dev = to_pmu_dev(dev_get_drvdata(dev));
return cpumap_print_to_pagebuf(true, buf, &pmu_dev->parent->cpu);
}
-static DEVICE_ATTR(cpumask, S_IRUGO, xgene_pmu_cpumask_show, NULL);
+static DEVICE_ATTR_RO(cpumask);
static struct attribute *xgene_pmu_cpumask_attrs[] = {
&dev_attr_cpumask.attr,
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 54c1f2f0985f..7dd35f1b9cc5 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -61,6 +61,15 @@ config USB_LGM_PHY
interface to interact with USB GEN-II and USB 3.x PHY that is part
of the Intel network SOC.
+config PHY_CAN_TRANSCEIVER
+ tristate "CAN transceiver PHY"
+ select GENERIC_PHY
+ help
+ This option enables support for CAN transceivers as a PHY. This
+ driver provides function for putting the transceivers in various
+ functional modes using gpios and sets the attribute max link
+ rate, for CAN drivers.
+
source "drivers/phy/allwinner/Kconfig"
source "drivers/phy/amlogic/Kconfig"
source "drivers/phy/broadcom/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index adac1b1a39d1..01e9efffc726 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -5,6 +5,7 @@
obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o
+obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o
obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
diff --git a/drivers/phy/broadcom/phy-bcm-ns-usb3.c b/drivers/phy/broadcom/phy-bcm-ns-usb3.c
index eb10ffa13a62..b1adaecc26f8 100644
--- a/drivers/phy/broadcom/phy-bcm-ns-usb3.c
+++ b/drivers/phy/broadcom/phy-bcm-ns-usb3.c
@@ -215,10 +215,8 @@ static int bcm_ns_usb3_mdio_probe(struct mdio_device *mdiodev)
return err;
usb3->dmp = devm_ioremap_resource(dev, &res);
- if (IS_ERR(usb3->dmp)) {
- dev_err(dev, "Failed to map DMP regs\n");
+ if (IS_ERR(usb3->dmp))
return PTR_ERR(usb3->dmp);
- }
usb3->phy = devm_phy_create(dev, NULL, &ops);
if (IS_ERR(usb3->phy)) {
diff --git a/drivers/phy/hisilicon/Kconfig b/drivers/phy/hisilicon/Kconfig
index 1c73053bcc98..4d008cfc279c 100644
--- a/drivers/phy/hisilicon/Kconfig
+++ b/drivers/phy/hisilicon/Kconfig
@@ -23,6 +23,16 @@ config PHY_HI3660_USB
To compile this driver as a module, choose M here.
+config PHY_HI3670_USB
+ tristate "hi3670 USB PHY support"
+ depends on (ARCH_HISI && ARM64) || COMPILE_TEST
+ select GENERIC_PHY
+ select MFD_SYSCON
+ help
+ Enable this to support the HISILICON HI3670 USB PHY.
+
+ To compile this driver as a module, choose M here.
+
config PHY_HISTB_COMBPHY
tristate "HiSilicon STB SoCs COMBPHY support"
depends on (ARCH_HISI && ARM64) || COMPILE_TEST
diff --git a/drivers/phy/hisilicon/Makefile b/drivers/phy/hisilicon/Makefile
index 92e874ae9c74..51729868145b 100644
--- a/drivers/phy/hisilicon/Makefile
+++ b/drivers/phy/hisilicon/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_PHY_HI6220_USB) += phy-hi6220-usb.o
obj-$(CONFIG_PHY_HI3660_USB) += phy-hi3660-usb3.o
+obj-$(CONFIG_PHY_HI3670_USB) += phy-hi3670-usb3.o
obj-$(CONFIG_PHY_HISTB_COMBPHY) += phy-histb-combphy.o
obj-$(CONFIG_PHY_HISI_INNO_USB2) += phy-hisi-inno-usb2.o
obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o
diff --git a/drivers/staging/hikey9xx/phy-hi3670-usb3.c b/drivers/phy/hisilicon/phy-hi3670-usb3.c
index e7e579ce0302..b9ffe08abaab 100644
--- a/drivers/staging/hikey9xx/phy-hi3670-usb3.c
+++ b/drivers/phy/hisilicon/phy-hi3670-usb3.c
@@ -148,10 +148,8 @@ static int hi3670_phy_cr_clk(struct regmap *usb31misc)
return ret;
/* Clock down */
- ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
- CFG54_USB31PHY_CR_CLK, 0);
-
- return ret;
+ return regmap_update_bits(usb31misc, USB_MISC_CFG54,
+ CFG54_USB31PHY_CR_CLK, 0);
}
static int hi3670_phy_cr_set_sel(struct regmap *usb31misc)
@@ -215,17 +213,14 @@ static int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr)
return ret;
reg = FIELD_PREP(CFG54_USB31PHY_CR_ADDR_MASK, addr);
- ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
- CFG54_USB31PHY_CR_ADDR_MASK, reg);
- return ret;
+ return regmap_update_bits(usb31misc, USB_MISC_CFG54,
+ CFG54_USB31PHY_CR_ADDR_MASK, reg);
}
static int hi3670_phy_cr_read(struct regmap *usb31misc, u32 addr, u32 *val)
{
- int reg;
- int i;
- int ret;
+ int reg, i, ret;
for (i = 0; i < 100; i++) {
ret = hi3670_phy_cr_clk(usb31misc);
@@ -286,9 +281,7 @@ static int hi3670_phy_cr_write(struct regmap *usb31misc, u32 addr, u32 val)
if (ret)
return ret;
- ret = hi3670_phy_cr_wait_ack(usb31misc);
-
- return ret;
+ return hi3670_phy_cr_wait_ack(usb31misc);
}
static int hi3670_phy_set_params(struct hi3670_priv *priv)
diff --git a/drivers/phy/intel/phy-intel-keembay-emmc.c b/drivers/phy/intel/phy-intel-keembay-emmc.c
index eb7c635ed89a..0eb11ac7c2e2 100644
--- a/drivers/phy/intel/phy-intel-keembay-emmc.c
+++ b/drivers/phy/intel/phy-intel-keembay-emmc.c
@@ -95,7 +95,8 @@ static int keembay_emmc_phy_power(struct phy *phy, bool on_off)
else
freqsel = 0x0;
- if (mhz < 50 || mhz > 200)
+ /* Check for EMMC clock rate*/
+ if (mhz > 175)
dev_warn(&phy->dev, "Unsupported rate: %d MHz\n", mhz);
/*
diff --git a/drivers/phy/marvell/phy-mmp3-hsic.c b/drivers/phy/marvell/phy-mmp3-hsic.c
index 47c1e8894939..7cccf01848d8 100644
--- a/drivers/phy/marvell/phy-mmp3-hsic.c
+++ b/drivers/phy/marvell/phy-mmp3-hsic.c
@@ -47,10 +47,8 @@ static int mmp3_hsic_phy_probe(struct platform_device *pdev)
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, resource);
- if (IS_ERR(base)) {
- dev_err(dev, "failed to remap PHY regs\n");
+ if (IS_ERR(base))
return PTR_ERR(base);
- }
phy = devm_phy_create(dev, NULL, &mmp3_hsic_phy_ops);
if (IS_ERR(phy)) {
diff --git a/drivers/phy/mediatek/phy-mtk-hdmi.c b/drivers/phy/mediatek/phy-mtk-hdmi.c
index 8313bd517e4c..8ad8f717ef43 100644
--- a/drivers/phy/mediatek/phy-mtk-hdmi.c
+++ b/drivers/phy/mediatek/phy-mtk-hdmi.c
@@ -119,9 +119,7 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev)
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hdmi_phy->regs = devm_ioremap_resource(dev, mem);
if (IS_ERR(hdmi_phy->regs)) {
- ret = PTR_ERR(hdmi_phy->regs);
- dev_err(dev, "Failed to get memory resource: %d\n", ret);
- return ret;
+ return PTR_ERR(hdmi_phy->regs);
}
ref_clk = devm_clk_get(dev, "pll_ref");
diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
index c51114d8e437..01cf31633019 100644
--- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
+++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
@@ -151,9 +151,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mipi_tx->regs = devm_ioremap_resource(dev, mem);
if (IS_ERR(mipi_tx->regs)) {
- ret = PTR_ERR(mipi_tx->regs);
- dev_err(dev, "Failed to get memory resource: %d\n", ret);
- return ret;
+ return PTR_ERR(mipi_tx->regs);
}
ref_clk = devm_clk_get(dev, NULL);
diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c
new file mode 100644
index 000000000000..c2cb93b4df71
--- /dev/null
+++ b/drivers/phy/phy-can-transceiver.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * phy-can-transceiver.c - phy driver for CAN transceivers
+ *
+ * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com
+ *
+ */
+#include<linux/phy/phy.h>
+#include<linux/platform_device.h>
+#include<linux/module.h>
+#include<linux/gpio.h>
+#include<linux/gpio/consumer.h>
+
+struct can_transceiver_data {
+ u32 flags;
+#define CAN_TRANSCEIVER_STB_PRESENT BIT(0)
+#define CAN_TRANSCEIVER_EN_PRESENT BIT(1)
+};
+
+struct can_transceiver_phy {
+ struct phy *generic_phy;
+ struct gpio_desc *standby_gpio;
+ struct gpio_desc *enable_gpio;
+};
+
+/* Power on function */
+static int can_transceiver_phy_power_on(struct phy *phy)
+{
+ struct can_transceiver_phy *can_transceiver_phy = phy_get_drvdata(phy);
+
+ if (can_transceiver_phy->standby_gpio)
+ gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 0);
+ if (can_transceiver_phy->enable_gpio)
+ gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 1);
+
+ return 0;
+}
+
+/* Power off function */
+static int can_transceiver_phy_power_off(struct phy *phy)
+{
+ struct can_transceiver_phy *can_transceiver_phy = phy_get_drvdata(phy);
+
+ if (can_transceiver_phy->standby_gpio)
+ gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 1);
+ if (can_transceiver_phy->enable_gpio)
+ gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 0);
+
+ return 0;
+}
+
+static const struct phy_ops can_transceiver_phy_ops = {
+ .power_on = can_transceiver_phy_power_on,
+ .power_off = can_transceiver_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static const struct can_transceiver_data tcan1042_drvdata = {
+ .flags = CAN_TRANSCEIVER_STB_PRESENT,
+};
+
+static const struct can_transceiver_data tcan1043_drvdata = {
+ .flags = CAN_TRANSCEIVER_STB_PRESENT | CAN_TRANSCEIVER_EN_PRESENT,
+};
+
+static const struct of_device_id can_transceiver_phy_ids[] = {
+ {
+ .compatible = "ti,tcan1042",
+ .data = &tcan1042_drvdata
+ },
+ {
+ .compatible = "ti,tcan1043",
+ .data = &tcan1043_drvdata
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, can_transceiver_phy_ids);
+
+static int can_transceiver_phy_probe(struct platform_device *pdev)
+{
+ struct phy_provider *phy_provider;
+ struct device *dev = &pdev->dev;
+ struct can_transceiver_phy *can_transceiver_phy;
+ const struct can_transceiver_data *drvdata;
+ const struct of_device_id *match;
+ struct phy *phy;
+ struct gpio_desc *standby_gpio;
+ struct gpio_desc *enable_gpio;
+ u32 max_bitrate = 0;
+
+ can_transceiver_phy = devm_kzalloc(dev, sizeof(struct can_transceiver_phy), GFP_KERNEL);
+ if (!can_transceiver_phy)
+ return -ENOMEM;
+
+ match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node);
+ drvdata = match->data;
+
+ phy = devm_phy_create(dev, dev->of_node,
+ &can_transceiver_phy_ops);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "failed to create can transceiver phy\n");
+ return PTR_ERR(phy);
+ }
+
+ device_property_read_u32(dev, "max-bitrate", &max_bitrate);
+ if (!max_bitrate)
+ dev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit\n");
+ phy->attrs.max_link_rate = max_bitrate;
+
+ can_transceiver_phy->generic_phy = phy;
+
+ if (drvdata->flags & CAN_TRANSCEIVER_STB_PRESENT) {
+ standby_gpio = devm_gpiod_get(dev, "standby", GPIOD_OUT_HIGH);
+ if (IS_ERR(standby_gpio))
+ return PTR_ERR(standby_gpio);
+ can_transceiver_phy->standby_gpio = standby_gpio;
+ }
+
+ if (drvdata->flags & CAN_TRANSCEIVER_EN_PRESENT) {
+ enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(enable_gpio))
+ return PTR_ERR(enable_gpio);
+ can_transceiver_phy->enable_gpio = enable_gpio;
+ }
+
+ phy_set_drvdata(can_transceiver_phy->generic_phy, can_transceiver_phy);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static struct platform_driver can_transceiver_phy_driver = {
+ .probe = can_transceiver_phy_probe,
+ .driver = {
+ .name = "can-transceiver-phy",
+ .of_match_table = can_transceiver_phy_ids,
+ },
+};
+
+module_platform_driver(can_transceiver_phy_driver);
+
+MODULE_AUTHOR("Faiz Abbas <faiz_abbas@ti.com>");
+MODULE_AUTHOR("Aswath Govindraju <a-govindraju@ti.com>");
+MODULE_DESCRIPTION("CAN TRANSCEIVER PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-core-mipi-dphy.c b/drivers/phy/phy-core-mipi-dphy.c
index 77fe65367ce5..288c9c67aa74 100644
--- a/drivers/phy/phy-core-mipi-dphy.c
+++ b/drivers/phy/phy-core-mipi-dphy.c
@@ -15,7 +15,7 @@
/*
* Minimum D-PHY timings based on MIPI D-PHY specification. Derived
* from the valid ranges specified in Section 6.9, Table 14, Page 41
- * of the D-PHY specification (v2.1).
+ * of the D-PHY specification (v1.2).
*/
int phy_mipi_dphy_get_default_config(unsigned long pixel_clock,
unsigned int bpp,
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index ccb575b13777..91e28d6ce450 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -697,16 +697,18 @@ struct phy *phy_get(struct device *dev, const char *string)
struct phy *phy;
struct device_link *link;
- if (string == NULL) {
- dev_WARN(dev, "missing string\n");
- return ERR_PTR(-EINVAL);
- }
-
if (dev->of_node) {
- index = of_property_match_string(dev->of_node, "phy-names",
- string);
+ if (string)
+ index = of_property_match_string(dev->of_node, "phy-names",
+ string);
+ else
+ index = 0;
phy = _of_phy_get(dev->of_node, index);
} else {
+ if (string == NULL) {
+ dev_WARN(dev, "missing string\n");
+ return ERR_PTR(-EINVAL);
+ }
phy = phy_find(dev, string);
}
if (IS_ERR(phy))
diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c
index f4cd590fbde7..d0f4546648f0 100644
--- a/drivers/phy/phy-xgene.c
+++ b/drivers/phy/phy-xgene.c
@@ -961,7 +961,8 @@ static void xgene_phy_sata_cfg_lanes(struct xgene_phy_ctx *ctx)
serdes_wr(ctx, lane, RXTX_REG1, val);
/* Latch VTT value based on the termination to ground and
- enable TX FIFO */
+ * enable TX FIFO
+ */
serdes_rd(ctx, lane, RXTX_REG2, &val);
val = RXTX_REG2_VTT_ENA_SET(val, 0x1);
val = RXTX_REG2_VTT_SEL_SET(val, 0x1);
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 7877f70cf86f..cfe359488f5c 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -35,6 +35,7 @@
#define PLL_READY_GATE_EN BIT(3)
/* QPHY_PCS_STATUS bit */
#define PHYSTATUS BIT(6)
+#define PHYSTATUS_4_20 BIT(7)
/* QPHY_PCS_READY_STATUS & QPHY_COM_PCS_READY_STATUS bit */
#define PCS_READY BIT(0)
@@ -143,6 +144,13 @@ static const unsigned int msm8996_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_READY_STATUS] = 0x168,
};
+static const unsigned int ipq_pciephy_gen3_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_SW_RESET] = 0x00,
+ [QPHY_START_CTRL] = 0x44,
+ [QPHY_PCS_STATUS] = 0x14,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = 0x40,
+};
+
static const unsigned int pciephy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_COM_SW_RESET] = 0x400,
[QPHY_COM_POWER_DOWN_CONTROL] = 0x404,
@@ -614,6 +622,113 @@ static const struct qmp_phy_init_tbl msm8996_usb3_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_POWER_STATE_CONFIG2, 0x08),
};
+static const struct qmp_phy_init_tbl ipq6018_pcie_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_PER1, 0x7d),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_PER2, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE1_MODE0, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE2_MODE0, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE1_MODE1, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE2_MODE1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_BIAS_EN_CLKBUFLR_EN, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_ENABLE1, 0x90),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_SYS_CLK_CTRL, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_SYSCLK_BUF_ENABLE, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP1_MODE0, 0xd4),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP2_MODE0, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP1_MODE1, 0xaa),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP2_MODE1, 0x29),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_BG_TRIM, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_CP_CTRL_MODE0, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_CP_CTRL_MODE1, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_RCTRL_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_CCTRL_MODE0, 0x28),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_CCTRL_MODE1, 0x28),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_BIAS_EN_CTRL_BY_PSM, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_SYSCLK_EN_SEL, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_RESETSM_CNTRL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP_EN, 0x42),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_DEC_START_MODE0, 0x68),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_DEC_START_MODE1, 0x53),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START1_MODE0, 0xab),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START2_MODE0, 0xaa),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START3_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START1_MODE1, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START2_MODE1, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START3_MODE1, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN0_MODE0, 0xa0),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN0_MODE1, 0xa0),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE1_MODE0, 0x24),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE2_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE1_MODE1, 0xb4),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE2_MODE1, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_SELECT, 0x32),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_HSCLK_SEL, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_CORE_CLK_EN, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_CMN_CONFIG, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_PLL_CORECLK_DIV_MODE1, 0x08),
+};
+
+static const struct qmp_phy_init_tbl ipq6018_pcie_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_TX0_RES_CODE_LANE_OFFSET_TX, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_TX0_LANE_MODE_1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_TX0_RCV_DETECT_LVL_2, 0x12),
+};
+
+static const struct qmp_phy_init_tbl ipq6018_pcie_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_RX0_UCDR_FO_GAIN, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_UCDR_SO_GAIN, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_UCDR_PI_CONTROLS, 0x70),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL2, 0x61),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL3, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL4, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_IDAC_TSETTLE_LOW, 0xc0),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_IDAC_TSETTLE_HIGH, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x73),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_SIGDET_ENABLES, 0x1c),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_SIGDET_CNTRL, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_SIGDET_DEGLITCH_CNTRL, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_00_LOW, 0xf0),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_00_HIGH, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_00_HIGH2, 0x2f),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_00_HIGH3, 0xd3),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_00_HIGH4, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_01_LOW, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_01_HIGH, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_01_HIGH2, 0xc8),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_01_HIGH3, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_01_HIGH4, 0xb1),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_10_LOW, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_10_HIGH, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_10_HIGH2, 0xc8),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_10_HIGH3, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_RX_MODE_10_HIGH4, 0xb1),
+ QMP_PHY_INIT_CFG(QSERDES_RX0_DFE_EN_TIMER, 0x04),
+};
+
+static const struct qmp_phy_init_tbl ipq6018_pcie_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(PCS_COM_FLL_CNTRL1, 0x01),
+ QMP_PHY_INIT_CFG(PCS_COM_REFGEN_REQ_CONFIG1, 0x0d),
+ QMP_PHY_INIT_CFG(PCS_COM_G12S1_TXDEEMPH_M3P5DB, 0x10),
+ QMP_PHY_INIT_CFG(PCS_COM_RX_SIGDET_LVL, 0xaa),
+ QMP_PHY_INIT_CFG(PCS_COM_P2U3_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
+ QMP_PHY_INIT_CFG(PCS_COM_RX_DCC_CAL_CONFIG, 0x01),
+ QMP_PHY_INIT_CFG(PCS_COM_EQ_CONFIG5, 0x01),
+ QMP_PHY_INIT_CFG(PCS_PCIE_POWER_STATE_CONFIG2, 0x0d),
+ QMP_PHY_INIT_CFG(PCS_PCIE_POWER_STATE_CONFIG4, 0x07),
+ QMP_PHY_INIT_CFG(PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
+ QMP_PHY_INIT_CFG(PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
+ QMP_PHY_INIT_CFG(PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
+ QMP_PHY_INIT_CFG(PCS_PCIE_OSC_DTCT_ACTIONS, 0x00),
+ QMP_PHY_INIT_CFG(PCS_PCIE_EQ_CONFIG1, 0x11),
+ QMP_PHY_INIT_CFG(PCS_PCIE_PRESET_P10_PRE, 0x00),
+ QMP_PHY_INIT_CFG(PCS_PCIE_PRESET_P10_POST, 0x58),
+};
+
static const struct qmp_phy_init_tbl ipq8074_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x18),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10),
@@ -2110,6 +2225,101 @@ static const struct qmp_phy_init_tbl sdx55_usb3_uniphy_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_RX_GM_CAL, 0x1f),
};
+static const struct qmp_phy_init_tbl sdx55_qmp_pcie_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BG_TIMER, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYS_CLK_CTRL, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE1, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x19),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE1, 0x19),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE1, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x46),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_CFG, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE1, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x4b),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE1, 0x50),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0, 0xfb),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE1, 0xfb),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE0, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_CONFIG, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_MISC1, 0x88),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTERNAL_DIG_CORECLK_DIV, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_MODE, 0x17),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_DC_LEVEL_CTRL, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x56),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1d),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0x4b),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x22),
+};
+
+static const struct qmp_phy_init_tbl sdx55_qmp_pcie_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_TX_LANE_MODE_1, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_TX_LANE_MODE_2, 0xf6),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_TX_LANE_MODE_3, 0x13),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_TX_VMODE_CTRL1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_TX_PI_QEC_CTRL, 0x00),
+};
+
+static const struct qmp_phy_init_tbl sdx55_qmp_pcie_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_FO_GAIN_RATE2, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_UCDR_PI_CONTROLS, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_AUX_DATA_TCOARSE_TFINE, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_DFE_3, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_DFE_DAC_ENABLE1, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_DFE_DAC_ENABLE2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_VGA_CAL_CNTRL2, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x27),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_MODE_RATE_0_1_B1, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_MODE_RATE_0_1_B2, 0x5a),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_MODE_RATE_0_1_B3, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_MODE_RATE_0_1_B4, 0x37),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_MODE_RATE2_B0, 0xbd),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_MODE_RATE2_B1, 0xf9),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_MODE_RATE2_B2, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_MODE_RATE2_B3, 0xce),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_MODE_RATE2_B4, 0x62),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_MODE_RATE3_B0, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_MODE_RATE3_B1, 0x7d),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_MODE_RATE3_B2, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_MODE_RATE3_B3, 0xcf),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_RX_MODE_RATE3_B4, 0xd6),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_PHPRE_CTRL, 0xa0),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38),
+ QMP_PHY_INIT_CFG(QSERDES_V4_20_RX_MARG_COARSE_CTRL2, 0x12),
+};
+
+static const struct qmp_phy_init_tbl sdx55_qmp_pcie_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_RX_SIGDET_LVL, 0x77),
+ QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_EQ_CONFIG2, 0x01),
+ QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_EQ_CONFIG4, 0x16),
+ QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_EQ_CONFIG5, 0x02),
+};
+
+static const struct qmp_phy_init_tbl sdx55_qmp_pcie_pcs_misc_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_EQ_CONFIG1, 0x17),
+ QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_G3_RXEQEVAL_TIME, 0x13),
+ QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_G4_RXEQEVAL_TIME, 0x13),
+ QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_G4_EQ_CONFIG2, 0x01),
+ QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_G4_EQ_CONFIG5, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_LANE1_INSIG_SW_CTRL2, 0x00),
+ QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_LANE1_INSIG_MX_CTRL2, 0x00),
+};
+
static const struct qmp_phy_init_tbl sm8350_ufsphy_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0xd9),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_SEL, 0x11),
@@ -2411,6 +2621,8 @@ struct qmp_phy_cfg {
unsigned int start_ctrl;
unsigned int pwrdn_ctrl;
unsigned int mask_com_pcs_ready;
+ /* bit offset of PHYSTATUS in QPHY_PCS_STATUS register */
+ unsigned int phy_status;
/* true, if PHY has a separate PHY_COM control block */
bool has_phy_com_ctrl;
@@ -2624,6 +2836,7 @@ static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
};
static const struct qmp_phy_cfg msm8996_pciephy_cfg = {
@@ -2649,6 +2862,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_com_pcs_ready = PCS_READY,
+ .phy_status = PHYSTATUS,
.has_phy_com_ctrl = true,
.has_lane_rst = true,
@@ -2678,6 +2892,7 @@ static const struct qmp_phy_cfg msm8996_ufs_cfg = {
.start_ctrl = SERDES_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
.no_pcs_sw_reset = true,
};
@@ -2704,6 +2919,7 @@ static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
};
static const char * const ipq8074_pciephy_clk_l[] = {
@@ -2736,6 +2952,37 @@ static const struct qmp_phy_cfg ipq8074_pciephy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS,
+
+ .has_phy_com_ctrl = false,
+ .has_lane_rst = false,
+ .has_pwrdn_delay = true,
+ .pwrdn_delay_min = 995, /* us */
+ .pwrdn_delay_max = 1005, /* us */
+};
+
+static const struct qmp_phy_cfg ipq6018_pciephy_cfg = {
+ .type = PHY_TYPE_PCIE,
+ .nlanes = 1,
+
+ .serdes_tbl = ipq6018_pcie_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(ipq6018_pcie_serdes_tbl),
+ .tx_tbl = ipq6018_pcie_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(ipq6018_pcie_tx_tbl),
+ .rx_tbl = ipq6018_pcie_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(ipq6018_pcie_rx_tbl),
+ .pcs_tbl = ipq6018_pcie_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(ipq6018_pcie_pcs_tbl),
+ .clk_list = ipq8074_pciephy_clk_l,
+ .num_clks = ARRAY_SIZE(ipq8074_pciephy_clk_l),
+ .reset_list = ipq8074_pciephy_reset_l,
+ .num_resets = ARRAY_SIZE(ipq8074_pciephy_reset_l),
+ .vreg_list = NULL,
+ .num_vregs = 0,
+ .regs = ipq_pciephy_gen3_regs_layout,
+
+ .start_ctrl = SERDES_START | PCS_START,
+ .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.has_phy_com_ctrl = false,
.has_lane_rst = false,
@@ -2768,6 +3015,7 @@ static const struct qmp_phy_cfg sdm845_qmp_pciephy_cfg = {
.start_ctrl = PCS_START | SERDES_START,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS,
.has_pwrdn_delay = true,
.pwrdn_delay_min = 995, /* us */
@@ -2796,6 +3044,7 @@ static const struct qmp_phy_cfg sdm845_qhp_pciephy_cfg = {
.start_ctrl = PCS_START | SERDES_START,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS,
.has_pwrdn_delay = true,
.pwrdn_delay_min = 995, /* us */
@@ -2834,6 +3083,7 @@ static const struct qmp_phy_cfg sm8250_qmp_gen3x1_pciephy_cfg = {
.start_ctrl = PCS_START | SERDES_START,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS,
.has_pwrdn_delay = true,
.pwrdn_delay_min = 995, /* us */
@@ -2872,6 +3122,7 @@ static const struct qmp_phy_cfg sm8250_qmp_gen3x2_pciephy_cfg = {
.start_ctrl = PCS_START | SERDES_START,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS,
.is_dual_lane_phy = true,
.has_pwrdn_delay = true,
@@ -2901,6 +3152,7 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
.has_pwrdn_delay = true,
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
@@ -2932,6 +3184,7 @@ static const struct qmp_phy_cfg sc7180_usb3phy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
.has_pwrdn_delay = true,
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
@@ -3003,6 +3256,7 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
.has_pwrdn_delay = true,
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
@@ -3029,6 +3283,7 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
.start_ctrl = SERDES_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
.is_dual_lane_phy = true,
.no_pcs_sw_reset = true,
@@ -3056,6 +3311,7 @@ static const struct qmp_phy_cfg msm8998_pciephy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS,
};
static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
@@ -3080,6 +3336,7 @@ static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
.is_dual_lane_phy = true,
};
@@ -3104,6 +3361,7 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
.start_ctrl = SERDES_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
.is_dual_lane_phy = true,
};
@@ -3130,6 +3388,8 @@ static const struct qmp_phy_cfg sm8150_usb3phy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
+
.has_pwrdn_delay = true,
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
@@ -3161,6 +3421,7 @@ static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
.has_pwrdn_delay = true,
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
@@ -3189,6 +3450,7 @@ static const struct qmp_phy_cfg sm8250_usb3phy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
.has_pwrdn_delay = true,
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
@@ -3220,6 +3482,7 @@ static const struct qmp_phy_cfg sm8250_usb3_uniphy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
.has_pwrdn_delay = true,
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
@@ -3288,12 +3551,45 @@ static const struct qmp_phy_cfg sdx55_usb3_uniphy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
.has_pwrdn_delay = true,
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
};
+static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = {
+ .type = PHY_TYPE_PCIE,
+ .nlanes = 2,
+
+ .serdes_tbl = sdx55_qmp_pcie_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(sdx55_qmp_pcie_serdes_tbl),
+ .tx_tbl = sdx55_qmp_pcie_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(sdx55_qmp_pcie_tx_tbl),
+ .rx_tbl = sdx55_qmp_pcie_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(sdx55_qmp_pcie_rx_tbl),
+ .pcs_tbl = sdx55_qmp_pcie_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(sdx55_qmp_pcie_pcs_tbl),
+ .pcs_misc_tbl = sdx55_qmp_pcie_pcs_misc_tbl,
+ .pcs_misc_tbl_num = ARRAY_SIZE(sdx55_qmp_pcie_pcs_misc_tbl),
+ .clk_list = sdm845_pciephy_clk_l,
+ .num_clks = ARRAY_SIZE(sdm845_pciephy_clk_l),
+ .reset_list = sdm845_pciephy_reset_l,
+ .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = sm8250_pcie_regs_layout,
+
+ .start_ctrl = PCS_START | SERDES_START,
+ .pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS_4_20,
+
+ .is_dual_lane_phy = true,
+ .has_pwrdn_delay = true,
+ .pwrdn_delay_min = 995, /* us */
+ .pwrdn_delay_max = 1005, /* us */
+};
+
static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
.type = PHY_TYPE_UFS,
.nlanes = 2,
@@ -3314,6 +3610,7 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
.start_ctrl = SERDES_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
.is_dual_lane_phy = true,
};
@@ -3340,6 +3637,7 @@ static const struct qmp_phy_cfg sm8350_usb3phy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
.has_pwrdn_delay = true,
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
@@ -3371,6 +3669,7 @@ static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS,
.has_pwrdn_delay = true,
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
@@ -3993,10 +4292,8 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
}
ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
- if (ret) {
- dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
+ if (ret)
goto err_rst;
- }
if (cfg->has_phy_dp_com_ctrl) {
qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL,
@@ -4238,7 +4535,7 @@ static int qcom_qmp_phy_power_on(struct phy *phy)
ready = PCS_READY;
} else {
status = pcs + cfg->regs[QPHY_PCS_STATUS];
- mask = PHYSTATUS;
+ mask = cfg->phy_status;
ready = 0;
}
@@ -4430,10 +4727,8 @@ static int __maybe_unused qcom_qmp_phy_runtime_resume(struct device *dev)
}
ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
- if (ret) {
- dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
+ if (ret)
return ret;
- }
ret = clk_prepare_enable(qphy->pipe_clk);
if (ret) {
@@ -4928,6 +5223,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
.compatible = "qcom,ipq8074-qmp-pcie-phy",
.data = &ipq8074_pciephy_cfg,
}, {
+ .compatible = "qcom,ipq6018-qmp-pcie-phy",
+ .data = &ipq6018_pciephy_cfg,
+ }, {
.compatible = "qcom,sc7180-qmp-usb3-phy",
.data = &sc7180_usb3phy_cfg,
}, {
@@ -4991,6 +5289,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
.compatible = "qcom,sm8250-qmp-modem-pcie-phy",
.data = &sm8250_qmp_gen3x2_pciephy_cfg,
}, {
+ .compatible = "qcom,sdx55-qmp-pcie-phy",
+ .data = &sdx55_qmp_pciephy_cfg,
+ }, {
.compatible = "qcom,sdx55-qmp-usb3-uni-phy",
.data = &sdx55_usb3_uniphy_cfg,
}, {
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h
index 67bd2dd0d8c5..6592b58b13f6 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.h
@@ -6,6 +6,138 @@
#ifndef QCOM_PHY_QMP_H_
#define QCOM_PHY_QMP_H_
+/* QMP V2 PHY for PCIE gen3 ports - QSERDES PLL registers */
+
+#define QSERDES_PLL_BG_TIMER 0x00c
+#define QSERDES_PLL_SSC_PER1 0x01c
+#define QSERDES_PLL_SSC_PER2 0x020
+#define QSERDES_PLL_SSC_STEP_SIZE1_MODE0 0x024
+#define QSERDES_PLL_SSC_STEP_SIZE2_MODE0 0x028
+#define QSERDES_PLL_SSC_STEP_SIZE1_MODE1 0x02c
+#define QSERDES_PLL_SSC_STEP_SIZE2_MODE1 0x030
+#define QSERDES_PLL_BIAS_EN_CLKBUFLR_EN 0x03c
+#define QSERDES_PLL_CLK_ENABLE1 0x040
+#define QSERDES_PLL_SYS_CLK_CTRL 0x044
+#define QSERDES_PLL_SYSCLK_BUF_ENABLE 0x048
+#define QSERDES_PLL_PLL_IVCO 0x050
+#define QSERDES_PLL_LOCK_CMP1_MODE0 0x054
+#define QSERDES_PLL_LOCK_CMP2_MODE0 0x058
+#define QSERDES_PLL_LOCK_CMP1_MODE1 0x060
+#define QSERDES_PLL_LOCK_CMP2_MODE1 0x064
+#define QSERDES_PLL_BG_TRIM 0x074
+#define QSERDES_PLL_CLK_EP_DIV_MODE0 0x078
+#define QSERDES_PLL_CLK_EP_DIV_MODE1 0x07c
+#define QSERDES_PLL_CP_CTRL_MODE0 0x080
+#define QSERDES_PLL_CP_CTRL_MODE1 0x084
+#define QSERDES_PLL_PLL_RCTRL_MODE0 0x088
+#define QSERDES_PLL_PLL_RCTRL_MODE1 0x08C
+#define QSERDES_PLL_PLL_CCTRL_MODE0 0x090
+#define QSERDES_PLL_PLL_CCTRL_MODE1 0x094
+#define QSERDES_PLL_BIAS_EN_CTRL_BY_PSM 0x0a4
+#define QSERDES_PLL_SYSCLK_EN_SEL 0x0a8
+#define QSERDES_PLL_RESETSM_CNTRL 0x0b0
+#define QSERDES_PLL_LOCK_CMP_EN 0x0c4
+#define QSERDES_PLL_DEC_START_MODE0 0x0cc
+#define QSERDES_PLL_DEC_START_MODE1 0x0d0
+#define QSERDES_PLL_DIV_FRAC_START1_MODE0 0x0d8
+#define QSERDES_PLL_DIV_FRAC_START2_MODE0 0x0dc
+#define QSERDES_PLL_DIV_FRAC_START3_MODE0 0x0e0
+#define QSERDES_PLL_DIV_FRAC_START1_MODE1 0x0e4
+#define QSERDES_PLL_DIV_FRAC_START2_MODE1 0x0e8
+#define QSERDES_PLL_DIV_FRAC_START3_MODE1 0x0eC
+#define QSERDES_PLL_INTEGLOOP_GAIN0_MODE0 0x100
+#define QSERDES_PLL_INTEGLOOP_GAIN1_MODE0 0x104
+#define QSERDES_PLL_INTEGLOOP_GAIN0_MODE1 0x108
+#define QSERDES_PLL_INTEGLOOP_GAIN1_MODE1 0x10c
+#define QSERDES_PLL_VCO_TUNE_MAP 0x120
+#define QSERDES_PLL_VCO_TUNE1_MODE0 0x124
+#define QSERDES_PLL_VCO_TUNE2_MODE0 0x128
+#define QSERDES_PLL_VCO_TUNE1_MODE1 0x12c
+#define QSERDES_PLL_VCO_TUNE2_MODE1 0x130
+#define QSERDES_PLL_VCO_TUNE_TIMER1 0x13c
+#define QSERDES_PLL_VCO_TUNE_TIMER2 0x140
+#define QSERDES_PLL_CLK_SELECT 0x16c
+#define QSERDES_PLL_HSCLK_SEL 0x170
+#define QSERDES_PLL_CORECLK_DIV 0x17c
+#define QSERDES_PLL_CORE_CLK_EN 0x184
+#define QSERDES_PLL_CMN_CONFIG 0x18c
+#define QSERDES_PLL_SVS_MODE_CLK_SEL 0x194
+#define QSERDES_PLL_CORECLK_DIV_MODE1 0x1b4
+
+/* QMP V2 PHY for PCIE gen3 ports - QSERDES TX registers */
+
+#define QSERDES_TX0_RES_CODE_LANE_OFFSET_TX 0x03c
+#define QSERDES_TX0_HIGHZ_DRVR_EN 0x058
+#define QSERDES_TX0_LANE_MODE_1 0x084
+#define QSERDES_TX0_RCV_DETECT_LVL_2 0x09c
+
+/* QMP V2 PHY for PCIE gen3 ports - QSERDES RX registers */
+
+#define QSERDES_RX0_UCDR_FO_GAIN 0x008
+#define QSERDES_RX0_UCDR_SO_GAIN 0x014
+#define QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE 0x034
+#define QSERDES_RX0_UCDR_PI_CONTROLS 0x044
+#define QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL2 0x0ec
+#define QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL3 0x0f0
+#define QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL4 0x0f4
+#define QSERDES_RX0_RX_IDAC_TSETTLE_LOW 0x0f8
+#define QSERDES_RX0_RX_IDAC_TSETTLE_HIGH 0x0fc
+#define QSERDES_RX0_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x110
+#define QSERDES_RX0_RX_OFFSET_ADAPTOR_CNTRL2 0x114
+#define QSERDES_RX0_SIGDET_ENABLES 0x118
+#define QSERDES_RX0_SIGDET_CNTRL 0x11c
+#define QSERDES_RX0_SIGDET_DEGLITCH_CNTRL 0x124
+#define QSERDES_RX0_RX_MODE_00_LOW 0x170
+#define QSERDES_RX0_RX_MODE_00_HIGH 0x174
+#define QSERDES_RX0_RX_MODE_00_HIGH2 0x178
+#define QSERDES_RX0_RX_MODE_00_HIGH3 0x17c
+#define QSERDES_RX0_RX_MODE_00_HIGH4 0x180
+#define QSERDES_RX0_RX_MODE_01_LOW 0x184
+#define QSERDES_RX0_RX_MODE_01_HIGH 0x188
+#define QSERDES_RX0_RX_MODE_01_HIGH2 0x18c
+#define QSERDES_RX0_RX_MODE_01_HIGH3 0x190
+#define QSERDES_RX0_RX_MODE_01_HIGH4 0x194
+#define QSERDES_RX0_RX_MODE_10_LOW 0x198
+#define QSERDES_RX0_RX_MODE_10_HIGH 0x19c
+#define QSERDES_RX0_RX_MODE_10_HIGH2 0x1a0
+#define QSERDES_RX0_RX_MODE_10_HIGH3 0x1a4
+#define QSERDES_RX0_RX_MODE_10_HIGH4 0x1a8
+#define QSERDES_RX0_DFE_EN_TIMER 0x1b4
+
+/* QMP V2 PHY for PCIE gen3 ports - PCS registers */
+
+#define PCS_COM_FLL_CNTRL1 0x098
+#define PCS_COM_FLL_CNTRL2 0x09c
+#define PCS_COM_FLL_CNT_VAL_L 0x0a0
+#define PCS_COM_FLL_CNT_VAL_H_TOL 0x0a4
+#define PCS_COM_FLL_MAN_CODE 0x0a8
+#define PCS_COM_REFGEN_REQ_CONFIG1 0x0dc
+#define PCS_COM_G12S1_TXDEEMPH_M3P5DB 0x16c
+#define PCS_COM_RX_SIGDET_LVL 0x188
+#define PCS_COM_P2U3_WAKEUP_DLY_TIME_AUXCLK_L 0x1a4
+#define PCS_COM_P2U3_WAKEUP_DLY_TIME_AUXCLK_H 0x1a8
+#define PCS_COM_RX_DCC_CAL_CONFIG 0x1d8
+#define PCS_COM_EQ_CONFIG5 0x1ec
+
+/* QMP V2 PHY for PCIE gen3 ports - PCS Misc registers */
+
+#define PCS_PCIE_POWER_STATE_CONFIG2 0x40c
+#define PCS_PCIE_POWER_STATE_CONFIG4 0x414
+#define PCS_PCIE_ENDPOINT_REFCLK_DRIVE 0x41c
+#define PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L 0x440
+#define PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_H 0x444
+#define PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L 0x448
+#define PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_H 0x44c
+#define PCS_PCIE_OSC_DTCT_CONFIG2 0x45c
+#define PCS_PCIE_OSC_DTCT_MODE2_CONFIG2 0x478
+#define PCS_PCIE_OSC_DTCT_MODE2_CONFIG4 0x480
+#define PCS_PCIE_OSC_DTCT_MODE2_CONFIG5 0x484
+#define PCS_PCIE_OSC_DTCT_ACTIONS 0x490
+#define PCS_PCIE_EQ_CONFIG1 0x4a0
+#define PCS_PCIE_EQ_CONFIG2 0x4a4
+#define PCS_PCIE_PRESET_P10_PRE 0x4bc
+#define PCS_PCIE_PRESET_P10_POST 0x4e0
+
/* Only for QMP V2 PHY - QSERDES COM registers */
#define QSERDES_COM_BG_TIMER 0x00c
#define QSERDES_COM_SSC_EN_CENTER 0x010
@@ -420,6 +552,7 @@
#define QSERDES_V4_COM_SYSCLK_EN_SEL 0x094
#define QSERDES_V4_COM_RESETSM_CNTRL 0x09c
#define QSERDES_V4_COM_LOCK_CMP_EN 0x0a4
+#define QSERDES_V4_COM_LOCK_CMP_CFG 0x0a8
#define QSERDES_V4_COM_LOCK_CMP1_MODE0 0x0ac
#define QSERDES_V4_COM_LOCK_CMP2_MODE0 0x0b0
#define QSERDES_V4_COM_LOCK_CMP1_MODE1 0x0b4
@@ -434,6 +567,8 @@
#define QSERDES_V4_COM_DIV_FRAC_START3_MODE1 0x0e0
#define QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0 0x0ec
#define QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0 0x0f0
+#define QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE1 0x0f4
+#define QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE1 0x0f8
#define QSERDES_V4_COM_VCO_TUNE_CTRL 0x108
#define QSERDES_V4_COM_VCO_TUNE_MAP 0x10c
#define QSERDES_V4_COM_VCO_TUNE1_MODE0 0x110
@@ -451,11 +586,15 @@
#define QSERDES_V4_COM_C_READY_STATUS 0x178
#define QSERDES_V4_COM_CMN_CONFIG 0x17c
#define QSERDES_V4_COM_SVS_MODE_CLK_SEL 0x184
+#define QSERDES_V4_COM_CMN_MISC1 0x19c
+#define QSERDES_V4_COM_INTERNAL_DIG_CORECLK_DIV 0x1a0
+#define QSERDES_V4_COM_CMN_MODE 0x1a4
+#define QSERDES_V4_COM_VCO_DC_LEVEL_CTRL 0x1a8
#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0 0x1ac
#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0 0x1b0
#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1 0x1b4
-#define QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL 0x1bc
#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1 0x1b8
+#define QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL 0x1bc
/* Only for QMP V4 PHY - TX registers */
#define QSERDES_V4_TX_CLKBUF_ENABLE 0x08
@@ -485,6 +624,13 @@
#define QSERDES_V4_TX_VMODE_CTRL1 0xe8
#define QSERDES_V4_TX_PI_QEC_CTRL 0x104
+/* Only for QMP V4_20 PHY - TX registers */
+#define QSERDES_V4_20_TX_LANE_MODE_1 0x88
+#define QSERDES_V4_20_TX_LANE_MODE_2 0x8c
+#define QSERDES_V4_20_TX_LANE_MODE_3 0x90
+#define QSERDES_V4_20_TX_VMODE_CTRL1 0xc4
+#define QSERDES_V4_20_TX_PI_QEC_CTRL 0xe0
+
/* Only for QMP V4 PHY - RX registers */
#define QSERDES_V4_RX_UCDR_FO_GAIN 0x008
#define QSERDES_V4_RX_UCDR_SO_GAIN 0x014
@@ -551,6 +697,33 @@
#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_STATUS 0x0d8
#define QSERDES_V4_DP_PHY_STATUS 0x0dc
+/* Only for QMP V4_20 PHY - RX registers */
+#define QSERDES_V4_20_RX_FO_GAIN_RATE2 0x008
+#define QSERDES_V4_20_RX_UCDR_PI_CONTROLS 0x058
+#define QSERDES_V4_20_RX_AUX_DATA_TCOARSE_TFINE 0x0ac
+#define QSERDES_V4_20_RX_DFE_3 0x110
+#define QSERDES_V4_20_RX_DFE_DAC_ENABLE1 0x134
+#define QSERDES_V4_20_RX_DFE_DAC_ENABLE2 0x138
+#define QSERDES_V4_20_RX_VGA_CAL_CNTRL2 0x150
+#define QSERDES_V4_20_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x178
+#define QSERDES_V4_20_RX_RX_MODE_RATE_0_1_B1 0x1c8
+#define QSERDES_V4_20_RX_RX_MODE_RATE_0_1_B2 0x1cc
+#define QSERDES_V4_20_RX_RX_MODE_RATE_0_1_B3 0x1d0
+#define QSERDES_V4_20_RX_RX_MODE_RATE_0_1_B4 0x1d4
+#define QSERDES_V4_20_RX_RX_MODE_RATE2_B0 0x1d8
+#define QSERDES_V4_20_RX_RX_MODE_RATE2_B1 0x1dc
+#define QSERDES_V4_20_RX_RX_MODE_RATE2_B2 0x1e0
+#define QSERDES_V4_20_RX_RX_MODE_RATE2_B3 0x1e4
+#define QSERDES_V4_20_RX_RX_MODE_RATE2_B4 0x1e8
+#define QSERDES_V4_20_RX_RX_MODE_RATE3_B0 0x1ec
+#define QSERDES_V4_20_RX_RX_MODE_RATE3_B1 0x1f0
+#define QSERDES_V4_20_RX_RX_MODE_RATE3_B2 0x1f4
+#define QSERDES_V4_20_RX_RX_MODE_RATE3_B3 0x1f8
+#define QSERDES_V4_20_RX_RX_MODE_RATE3_B4 0x1fc
+#define QSERDES_V4_20_RX_PHPRE_CTRL 0x200
+#define QSERDES_V4_20_RX_DFE_CTLE_POST_CAL_OFFSET 0x20c
+#define QSERDES_V4_20_RX_MARG_COARSE_CTRL2 0x23c
+
/* Only for QMP V4 PHY - UFS PCS registers */
#define QPHY_V4_PCS_UFS_PHY_START 0x000
#define QPHY_V4_PCS_UFS_POWER_DOWN_CONTROL 0x004
@@ -836,6 +1009,12 @@
#define QPHY_V4_PCS_USB3_SIGDET_STARTUP_TIMER_VAL 0x354
#define QPHY_V4_PCS_USB3_TEST_CONTROL 0x358
+/* Only for QMP V4_20 PHY - USB/PCIe PCS registers */
+#define QPHY_V4_20_PCS_RX_SIGDET_LVL 0x188
+#define QPHY_V4_20_PCS_EQ_CONFIG2 0x1d8
+#define QPHY_V4_20_PCS_EQ_CONFIG4 0x1e0
+#define QPHY_V4_20_PCS_EQ_CONFIG5 0x1e4
+
/* Only for QMP V4 PHY - UNI has 0x300 offset for PCS_USB3 regs */
#define QPHY_V4_PCS_USB3_UNI_LFPS_DET_HIGH_COUNT_VAL 0x618
#define QPHY_V4_PCS_USB3_UNI_RXEQTRAINING_DFE_TIME_S2 0x638
@@ -861,6 +1040,14 @@
#define QPHY_V4_PCS_PCIE_PRESET_P10_PRE 0xbc
#define QPHY_V4_PCS_PCIE_PRESET_P10_POST 0xe0
+#define QPHY_V4_20_PCS_PCIE_EQ_CONFIG1 0x0a0
+#define QPHY_V4_20_PCS_PCIE_G3_RXEQEVAL_TIME 0x0f0
+#define QPHY_V4_20_PCS_PCIE_G4_RXEQEVAL_TIME 0x0f4
+#define QPHY_V4_20_PCS_PCIE_G4_EQ_CONFIG2 0x0fc
+#define QPHY_V4_20_PCS_PCIE_G4_EQ_CONFIG5 0x108
+#define QPHY_V4_20_PCS_LANE1_INSIG_SW_CTRL2 0x824
+#define QPHY_V4_20_PCS_LANE1_INSIG_MX_CTRL2 0x828
+
/* Only for QMP V5 PHY - QSERDES COM registers */
#define QSERDES_V5_COM_PLL_IVCO 0x058
#define QSERDES_V5_COM_CP_CTRL_MODE0 0x074
diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 8f1bf7e2186b..3c1d3b71c825 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -219,6 +219,22 @@ static const struct qusb2_phy_init_tbl msm8998_init_tbl[] = {
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19),
};
+static const struct qusb2_phy_init_tbl sm6115_init_tbl[] = {
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xf8),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0x53),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0x81),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0x17),
+
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),
+
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TEST2, 0x14),
+
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
+};
+
static const unsigned int qusb2_v2_regs_layout[] = {
[QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8,
[QUSB2PHY_PLL_STATUS] = 0x1a0,
@@ -342,6 +358,18 @@ static const struct qusb2_phy_cfg sdm660_phy_cfg = {
.autoresume_en = BIT(3),
};
+static const struct qusb2_phy_cfg sm6115_phy_cfg = {
+ .tbl = sm6115_init_tbl,
+ .tbl_num = ARRAY_SIZE(sm6115_init_tbl),
+ .regs = msm8996_regs_layout,
+
+ .has_pll_test = true,
+ .se_clk_scheme_default = true,
+ .disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
+ .mask_core_ready = PLL_LOCKED,
+ .autoresume_en = BIT(3),
+};
+
static const char * const qusb2_phy_vreg_names[] = {
"vdda-pll", "vdda-phy-dpdm",
};
@@ -889,6 +917,12 @@ static const struct of_device_id qusb2_phy_of_match_table[] = {
.compatible = "qcom,sdm660-qusb2-phy",
.data = &sdm660_phy_cfg,
}, {
+ .compatible = "qcom,sm4250-qusb2-phy",
+ .data = &sm6115_phy_cfg,
+ }, {
+ .compatible = "qcom,sm6115-qusb2-phy",
+ .data = &sm6115_phy_cfg,
+ }, {
/*
* Deprecated. Only here to support legacy device
* trees that didn't include "qcom,qusb2-v2-phy"
diff --git a/drivers/phy/ralink/Kconfig b/drivers/phy/ralink/Kconfig
index ecc309ba9fee..c2373b30b8a6 100644
--- a/drivers/phy/ralink/Kconfig
+++ b/drivers/phy/ralink/Kconfig
@@ -4,7 +4,7 @@
#
config PHY_MT7621_PCI
tristate "MediaTek MT7621 PCI PHY Driver"
- depends on RALINK && OF
+ depends on (RALINK && OF) || COMPILE_TEST
select GENERIC_PHY
select REGMAP_MMIO
help
diff --git a/drivers/phy/ralink/phy-mt7621-pci.c b/drivers/phy/ralink/phy-mt7621-pci.c
index 2a9465f4bb3a..5e6530f545b5 100644
--- a/drivers/phy/ralink/phy-mt7621-pci.c
+++ b/drivers/phy/ralink/phy-mt7621-pci.c
@@ -5,6 +5,7 @@
*/
#include <dt-bindings/phy/phy.h>
+#include <linux/clk.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/module.h>
@@ -14,8 +15,6 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/sys_soc.h>
-#include <mt7621.h>
-#include <ralink_regs.h>
#define RG_PE1_PIPE_REG 0x02c
#define RG_PE1_PIPE_RST BIT(12)
@@ -62,8 +61,6 @@
#define RG_PE1_FRC_MSTCKDIV BIT(5)
-#define XTAL_MASK GENMASK(8, 6)
-
#define MAX_PHYS 2
/**
@@ -71,6 +68,7 @@
* @dev: pointer to device
* @regmap: kernel regmap pointer
* @phy: pointer to the kernel PHY device
+ * @sys_clk: pointer to the system XTAL clock
* @port_base: base register
* @has_dual_port: if the phy has dual ports.
* @bypass_pipe_rst: mark if 'mt7621_bypass_pipe_rst'
@@ -80,6 +78,7 @@ struct mt7621_pci_phy {
struct device *dev;
struct regmap *regmap;
struct phy *phy;
+ struct clk *sys_clk;
void __iomem *port_base;
bool has_dual_port;
bool bypass_pipe_rst;
@@ -116,12 +115,14 @@ static void mt7621_bypass_pipe_rst(struct mt7621_pci_phy *phy)
}
}
-static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy)
+static int mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy)
{
struct device *dev = phy->dev;
- u32 xtal_mode;
+ unsigned long clk_rate;
- xtal_mode = FIELD_GET(XTAL_MASK, rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0));
+ clk_rate = clk_get_rate(phy->sys_clk);
+ if (!clk_rate)
+ return -EINVAL;
/* Set PCIe Port PHY to disable SSC */
/* Debug Xtal Type */
@@ -139,13 +140,13 @@ static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy)
RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
}
- if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */
+ if (clk_rate == 40000000) { /* 40MHz Xtal */
/* Set Pre-divider ratio (for host mode) */
mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, RG_PE1_H_PLL_PREDIV,
FIELD_PREP(RG_PE1_H_PLL_PREDIV, 0x01));
dev_dbg(dev, "Xtal is 40MHz\n");
- } else if (xtal_mode >= 6) { /* 25MHz Xal */
+ } else if (clk_rate == 25000000) { /* 25MHz Xal */
mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, RG_PE1_H_PLL_PREDIV,
FIELD_PREP(RG_PE1_H_PLL_PREDIV, 0x00));
@@ -196,13 +197,15 @@ static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy)
mt7621_phy_rmw(phy, RG_PE1_H_PLL_BR_REG, RG_PE1_H_PLL_BR,
FIELD_PREP(RG_PE1_H_PLL_BR, 0x00));
- if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */
+ if (clk_rate == 40000000) { /* 40MHz Xtal */
/* set force mode enable of da_pe1_mstckdiv */
mt7621_phy_rmw(phy, RG_PE1_MSTCKDIV_REG,
RG_PE1_MSTCKDIV | RG_PE1_FRC_MSTCKDIV,
FIELD_PREP(RG_PE1_MSTCKDIV, 0x01) |
RG_PE1_FRC_MSTCKDIV);
}
+
+ return 0;
}
static int mt7621_pci_phy_init(struct phy *phy)
@@ -212,9 +215,7 @@ static int mt7621_pci_phy_init(struct phy *phy)
if (mphy->bypass_pipe_rst)
mt7621_bypass_pipe_rst(mphy);
- mt7621_set_phy_for_ssc(mphy);
-
- return 0;
+ return mt7621_set_phy_for_ssc(mphy);
}
static int mt7621_pci_phy_power_on(struct phy *phy)
@@ -272,8 +273,8 @@ static struct phy *mt7621_pcie_phy_of_xlate(struct device *dev,
mt7621_phy->has_dual_port = args->args[0];
- dev_info(dev, "PHY for 0x%08x (dual port = %d)\n",
- (unsigned int)mt7621_phy->port_base, mt7621_phy->has_dual_port);
+ dev_dbg(dev, "PHY for 0x%px (dual port = %d)\n",
+ mt7621_phy->port_base, mt7621_phy->has_dual_port);
return mt7621_phy->phy;
}
@@ -324,6 +325,12 @@ static int mt7621_pci_phy_probe(struct platform_device *pdev)
return PTR_ERR(phy->phy);
}
+ phy->sys_clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(phy->sys_clk)) {
+ dev_err(dev, "failed to get phy clock\n");
+ return PTR_ERR(phy->sys_clk);
+ }
+
phy_set_drvdata(phy->phy, phy);
provider = devm_of_phy_provider_register(dev, mt7621_pcie_phy_of_xlate);
diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index 159285f42e5c..e812adad7242 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -48,6 +48,15 @@ config PHY_ROCKCHIP_INNO_USB2
help
Support for Rockchip USB2.0 PHY with Innosilicon IP block.
+config PHY_ROCKCHIP_INNO_CSIDPHY
+ tristate "Rockchip Innosilicon MIPI CSI PHY driver"
+ depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
+ select GENERIC_PHY
+ select GENERIC_PHY_MIPI_DPHY
+ help
+ Enable this to support the Rockchip MIPI CSI PHY with
+ Innosilicon IP block.
+
config PHY_ROCKCHIP_INNO_DSIDPHY
tristate "Rockchip Innosilicon MIPI/LVDS/TTL PHY driver"
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile
index c3cfc7f0af5c..f0eec212b2aa 100644
--- a/drivers/phy/rockchip/Makefile
+++ b/drivers/phy/rockchip/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o
obj-$(CONFIG_PHY_ROCKCHIP_DPHY_RX0) += phy-rockchip-dphy-rx0.o
obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
+obj-$(CONFIG_PHY_ROCKCHIP_INNO_CSIDPHY) += phy-rockchip-inno-csidphy.o
obj-$(CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY) += phy-rockchip-inno-dsidphy.o
obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI) += phy-rockchip-inno-hdmi.o
obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
new file mode 100644
index 000000000000..ca13a604ab4f
--- /dev/null
+++ b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
@@ -0,0 +1,459 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip MIPI RX Innosilicon DPHY driver
+ *
+ * Copyright (C) 2021 Fuzhou Rockchip Electronics Co., Ltd.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mipi-dphy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+/* GRF */
+#define RK1808_GRF_PD_VI_CON_OFFSET 0x0430
+
+#define RK3326_GRF_PD_VI_CON_OFFSET 0x0430
+
+#define RK3368_GRF_SOC_CON6_OFFSET 0x0418
+
+/* PHY */
+#define CSIDPHY_CTRL_LANE_ENABLE 0x00
+#define CSIDPHY_CTRL_LANE_ENABLE_CK BIT(6)
+#define CSIDPHY_CTRL_LANE_ENABLE_MASK GENMASK(5, 2)
+#define CSIDPHY_CTRL_LANE_ENABLE_UNDEFINED BIT(0)
+
+/* not present on all variants */
+#define CSIDPHY_CTRL_PWRCTL 0x04
+#define CSIDPHY_CTRL_PWRCTL_UNDEFINED GENMASK(7, 5)
+#define CSIDPHY_CTRL_PWRCTL_SYNCRST BIT(2)
+#define CSIDPHY_CTRL_PWRCTL_LDO_PD BIT(1)
+#define CSIDPHY_CTRL_PWRCTL_PLL_PD BIT(0)
+
+#define CSIDPHY_CTRL_DIG_RST 0x80
+#define CSIDPHY_CTRL_DIG_RST_UNDEFINED 0x1e
+#define CSIDPHY_CTRL_DIG_RST_RESET BIT(0)
+
+/* offset after ths_settle_offset */
+#define CSIDPHY_CLK_THS_SETTLE 0
+#define CSIDPHY_LANE_THS_SETTLE(n) (((n) + 1) * 0x80)
+#define CSIDPHY_THS_SETTLE_MASK GENMASK(6, 0)
+
+/* offset after calib_offset */
+#define CSIDPHY_CLK_CALIB_EN 0
+#define CSIDPHY_LANE_CALIB_EN(n) (((n) + 1) * 0x80)
+#define CSIDPHY_CALIB_EN BIT(7)
+
+/* Configure the count time of the THS-SETTLE by protocol. */
+#define RK1808_CSIDPHY_CLK_WR_THS_SETTLE 0x160
+#define RK3326_CSIDPHY_CLK_WR_THS_SETTLE 0x100
+#define RK3368_CSIDPHY_CLK_WR_THS_SETTLE 0x100
+
+/* Calibration reception enable */
+#define RK1808_CSIDPHY_CLK_CALIB_EN 0x168
+
+/*
+ * The higher 16-bit of this register is used for write protection
+ * only if BIT(x + 16) set to 1 the BIT(x) can be written.
+ */
+#define HIWORD_UPDATE(val, mask, shift) \
+ ((val) << (shift) | (mask) << ((shift) + 16))
+
+#define HZ_TO_MHZ(freq) div_u64(freq, 1000 * 1000)
+
+enum dphy_reg_id {
+ /* rk1808 & rk3326 */
+ GRF_DPHY_CSIPHY_FORCERXMODE,
+ GRF_DPHY_CSIPHY_CLKLANE_EN,
+ GRF_DPHY_CSIPHY_DATALANE_EN,
+};
+
+struct dphy_reg {
+ u32 offset;
+ u32 mask;
+ u32 shift;
+};
+
+#define PHY_REG(_offset, _width, _shift) \
+ { .offset = _offset, .mask = BIT(_width) - 1, .shift = _shift, }
+
+static const struct dphy_reg rk1808_grf_dphy_regs[] = {
+ [GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK1808_GRF_PD_VI_CON_OFFSET, 4, 0),
+ [GRF_DPHY_CSIPHY_CLKLANE_EN] = PHY_REG(RK1808_GRF_PD_VI_CON_OFFSET, 1, 8),
+ [GRF_DPHY_CSIPHY_DATALANE_EN] = PHY_REG(RK1808_GRF_PD_VI_CON_OFFSET, 4, 4),
+};
+
+static const struct dphy_reg rk3326_grf_dphy_regs[] = {
+ [GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET, 4, 0),
+ [GRF_DPHY_CSIPHY_CLKLANE_EN] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET, 1, 8),
+ [GRF_DPHY_CSIPHY_DATALANE_EN] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET, 4, 4),
+};
+
+static const struct dphy_reg rk3368_grf_dphy_regs[] = {
+ [GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK3368_GRF_SOC_CON6_OFFSET, 4, 8),
+};
+
+struct hsfreq_range {
+ u32 range_h;
+ u8 cfg_bit;
+};
+
+struct dphy_drv_data {
+ int pwrctl_offset;
+ int ths_settle_offset;
+ int calib_offset;
+ const struct hsfreq_range *hsfreq_ranges;
+ int num_hsfreq_ranges;
+ const struct dphy_reg *grf_regs;
+};
+
+struct rockchip_inno_csidphy {
+ struct device *dev;
+ void __iomem *phy_base;
+ struct clk *pclk;
+ struct regmap *grf;
+ struct reset_control *rst;
+ const struct dphy_drv_data *drv_data;
+ struct phy_configure_opts_mipi_dphy config;
+ u8 hsfreq;
+};
+
+static inline void write_grf_reg(struct rockchip_inno_csidphy *priv,
+ int index, u8 value)
+{
+ const struct dphy_drv_data *drv_data = priv->drv_data;
+ const struct dphy_reg *reg = &drv_data->grf_regs[index];
+
+ if (reg->offset)
+ regmap_write(priv->grf, reg->offset,
+ HIWORD_UPDATE(value, reg->mask, reg->shift));
+}
+
+/* These tables must be sorted by .range_h ascending. */
+static const struct hsfreq_range rk1808_mipidphy_hsfreq_ranges[] = {
+ { 109, 0x02}, { 149, 0x03}, { 199, 0x06}, { 249, 0x06},
+ { 299, 0x06}, { 399, 0x08}, { 499, 0x0b}, { 599, 0x0e},
+ { 699, 0x10}, { 799, 0x12}, { 999, 0x16}, {1199, 0x1e},
+ {1399, 0x23}, {1599, 0x2d}, {1799, 0x32}, {1999, 0x37},
+ {2199, 0x3c}, {2399, 0x41}, {2499, 0x46}
+};
+
+static const struct hsfreq_range rk3326_mipidphy_hsfreq_ranges[] = {
+ { 109, 0x00}, { 149, 0x01}, { 199, 0x02}, { 249, 0x03},
+ { 299, 0x04}, { 399, 0x05}, { 499, 0x06}, { 599, 0x07},
+ { 699, 0x08}, { 799, 0x09}, { 899, 0x0a}, {1099, 0x0b},
+ {1249, 0x0c}, {1349, 0x0d}, {1500, 0x0e}
+};
+
+static const struct hsfreq_range rk3368_mipidphy_hsfreq_ranges[] = {
+ { 109, 0x00}, { 149, 0x01}, { 199, 0x02}, { 249, 0x03},
+ { 299, 0x04}, { 399, 0x05}, { 499, 0x06}, { 599, 0x07},
+ { 699, 0x08}, { 799, 0x09}, { 899, 0x0a}, {1099, 0x0b},
+ {1249, 0x0c}, {1349, 0x0d}, {1500, 0x0e}
+};
+
+static void rockchip_inno_csidphy_ths_settle(struct rockchip_inno_csidphy *priv,
+ int hsfreq, int offset)
+{
+ const struct dphy_drv_data *drv_data = priv->drv_data;
+ u32 val;
+
+ val = readl(priv->phy_base + drv_data->ths_settle_offset + offset);
+ val &= ~CSIDPHY_THS_SETTLE_MASK;
+ val |= hsfreq;
+ writel(val, priv->phy_base + drv_data->ths_settle_offset + offset);
+}
+
+static int rockchip_inno_csidphy_configure(struct phy *phy,
+ union phy_configure_opts *opts)
+{
+ struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
+ const struct dphy_drv_data *drv_data = priv->drv_data;
+ struct phy_configure_opts_mipi_dphy *config = &opts->mipi_dphy;
+ unsigned int hsfreq = 0;
+ unsigned int i;
+ u64 data_rate_mbps;
+ int ret;
+
+ /* pass with phy_mipi_dphy_get_default_config (with pixel rate?) */
+ ret = phy_mipi_dphy_config_validate(config);
+ if (ret)
+ return ret;
+
+ data_rate_mbps = HZ_TO_MHZ(config->hs_clk_rate);
+
+ dev_dbg(priv->dev, "lanes %d - data_rate_mbps %llu\n",
+ config->lanes, data_rate_mbps);
+ for (i = 0; i < drv_data->num_hsfreq_ranges; i++) {
+ if (drv_data->hsfreq_ranges[i].range_h >= data_rate_mbps) {
+ hsfreq = drv_data->hsfreq_ranges[i].cfg_bit;
+ break;
+ }
+ }
+ if (!hsfreq)
+ return -EINVAL;
+
+ priv->hsfreq = hsfreq;
+ priv->config = *config;
+ return 0;
+}
+
+static int rockchip_inno_csidphy_power_on(struct phy *phy)
+{
+ struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
+ const struct dphy_drv_data *drv_data = priv->drv_data;
+ u64 data_rate_mbps = HZ_TO_MHZ(priv->config.hs_clk_rate);
+ u32 val;
+ int ret, i;
+
+ ret = clk_enable(priv->pclk);
+ if (ret < 0)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret < 0) {
+ clk_disable(priv->pclk);
+ return ret;
+ }
+
+ /* phy start */
+ if (drv_data->pwrctl_offset >= 0)
+ writel(CSIDPHY_CTRL_PWRCTL_UNDEFINED |
+ CSIDPHY_CTRL_PWRCTL_SYNCRST,
+ priv->phy_base + drv_data->pwrctl_offset);
+
+ /* set data lane num and enable clock lane */
+ val = FIELD_PREP(CSIDPHY_CTRL_LANE_ENABLE_MASK, GENMASK(priv->config.lanes - 1, 0)) |
+ FIELD_PREP(CSIDPHY_CTRL_LANE_ENABLE_CK, 1) |
+ FIELD_PREP(CSIDPHY_CTRL_LANE_ENABLE_UNDEFINED, 1);
+ writel(val, priv->phy_base + CSIDPHY_CTRL_LANE_ENABLE);
+
+ /* Reset dphy analog part */
+ if (drv_data->pwrctl_offset >= 0)
+ writel(CSIDPHY_CTRL_PWRCTL_UNDEFINED,
+ priv->phy_base + drv_data->pwrctl_offset);
+ usleep_range(500, 1000);
+
+ /* Reset dphy digital part */
+ writel(CSIDPHY_CTRL_DIG_RST_UNDEFINED,
+ priv->phy_base + CSIDPHY_CTRL_DIG_RST);
+ writel(CSIDPHY_CTRL_DIG_RST_UNDEFINED + CSIDPHY_CTRL_DIG_RST_RESET,
+ priv->phy_base + CSIDPHY_CTRL_DIG_RST);
+
+ /* not into receive mode/wait stopstate */
+ write_grf_reg(priv, GRF_DPHY_CSIPHY_FORCERXMODE, 0x0);
+
+ /* enable calibration */
+ if (data_rate_mbps > 1500 && drv_data->calib_offset >= 0) {
+ writel(CSIDPHY_CALIB_EN,
+ priv->phy_base + drv_data->calib_offset +
+ CSIDPHY_CLK_CALIB_EN);
+ for (i = 0; i < priv->config.lanes; i++)
+ writel(CSIDPHY_CALIB_EN,
+ priv->phy_base + drv_data->calib_offset +
+ CSIDPHY_LANE_CALIB_EN(i));
+ }
+
+ rockchip_inno_csidphy_ths_settle(priv, priv->hsfreq,
+ CSIDPHY_CLK_THS_SETTLE);
+ for (i = 0; i < priv->config.lanes; i++)
+ rockchip_inno_csidphy_ths_settle(priv, priv->hsfreq,
+ CSIDPHY_LANE_THS_SETTLE(i));
+
+ write_grf_reg(priv, GRF_DPHY_CSIPHY_CLKLANE_EN, 0x1);
+ write_grf_reg(priv, GRF_DPHY_CSIPHY_DATALANE_EN,
+ GENMASK(priv->config.lanes - 1, 0));
+
+ return 0;
+}
+
+static int rockchip_inno_csidphy_power_off(struct phy *phy)
+{
+ struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
+ const struct dphy_drv_data *drv_data = priv->drv_data;
+
+ /* disable all lanes */
+ writel(CSIDPHY_CTRL_LANE_ENABLE_UNDEFINED,
+ priv->phy_base + CSIDPHY_CTRL_LANE_ENABLE);
+
+ /* disable pll and ldo */
+ if (drv_data->pwrctl_offset >= 0)
+ writel(CSIDPHY_CTRL_PWRCTL_UNDEFINED |
+ CSIDPHY_CTRL_PWRCTL_LDO_PD |
+ CSIDPHY_CTRL_PWRCTL_PLL_PD,
+ priv->phy_base + drv_data->pwrctl_offset);
+ usleep_range(500, 1000);
+
+ pm_runtime_put(priv->dev);
+ clk_disable(priv->pclk);
+
+ return 0;
+}
+
+static int rockchip_inno_csidphy_init(struct phy *phy)
+{
+ struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
+
+ return clk_prepare(priv->pclk);
+}
+
+static int rockchip_inno_csidphy_exit(struct phy *phy)
+{
+ struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
+
+ clk_unprepare(priv->pclk);
+
+ return 0;
+}
+
+static const struct phy_ops rockchip_inno_csidphy_ops = {
+ .power_on = rockchip_inno_csidphy_power_on,
+ .power_off = rockchip_inno_csidphy_power_off,
+ .init = rockchip_inno_csidphy_init,
+ .exit = rockchip_inno_csidphy_exit,
+ .configure = rockchip_inno_csidphy_configure,
+ .owner = THIS_MODULE,
+};
+
+static const struct dphy_drv_data rk1808_mipidphy_drv_data = {
+ .pwrctl_offset = -1,
+ .ths_settle_offset = RK1808_CSIDPHY_CLK_WR_THS_SETTLE,
+ .calib_offset = RK1808_CSIDPHY_CLK_CALIB_EN,
+ .hsfreq_ranges = rk1808_mipidphy_hsfreq_ranges,
+ .num_hsfreq_ranges = ARRAY_SIZE(rk1808_mipidphy_hsfreq_ranges),
+ .grf_regs = rk1808_grf_dphy_regs,
+};
+
+static const struct dphy_drv_data rk3326_mipidphy_drv_data = {
+ .pwrctl_offset = CSIDPHY_CTRL_PWRCTL,
+ .ths_settle_offset = RK3326_CSIDPHY_CLK_WR_THS_SETTLE,
+ .calib_offset = -1,
+ .hsfreq_ranges = rk3326_mipidphy_hsfreq_ranges,
+ .num_hsfreq_ranges = ARRAY_SIZE(rk3326_mipidphy_hsfreq_ranges),
+ .grf_regs = rk3326_grf_dphy_regs,
+};
+
+static const struct dphy_drv_data rk3368_mipidphy_drv_data = {
+ .pwrctl_offset = CSIDPHY_CTRL_PWRCTL,
+ .ths_settle_offset = RK3368_CSIDPHY_CLK_WR_THS_SETTLE,
+ .calib_offset = -1,
+ .hsfreq_ranges = rk3368_mipidphy_hsfreq_ranges,
+ .num_hsfreq_ranges = ARRAY_SIZE(rk3368_mipidphy_hsfreq_ranges),
+ .grf_regs = rk3368_grf_dphy_regs,
+};
+
+static const struct of_device_id rockchip_inno_csidphy_match_id[] = {
+ {
+ .compatible = "rockchip,px30-csi-dphy",
+ .data = &rk3326_mipidphy_drv_data,
+ },
+ {
+ .compatible = "rockchip,rk1808-csi-dphy",
+ .data = &rk1808_mipidphy_drv_data,
+ },
+ {
+ .compatible = "rockchip,rk3326-csi-dphy",
+ .data = &rk3326_mipidphy_drv_data,
+ },
+ {
+ .compatible = "rockchip,rk3368-csi-dphy",
+ .data = &rk3368_mipidphy_drv_data,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rockchip_inno_csidphy_match_id);
+
+static int rockchip_inno_csidphy_probe(struct platform_device *pdev)
+{
+ struct rockchip_inno_csidphy *priv;
+ struct device *dev = &pdev->dev;
+ struct phy_provider *phy_provider;
+ struct phy *phy;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ platform_set_drvdata(pdev, priv);
+
+ priv->drv_data = of_device_get_match_data(dev);
+ if (!priv->drv_data) {
+ dev_err(dev, "Can't find device data\n");
+ return -ENODEV;
+ }
+
+ priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "rockchip,grf");
+ if (IS_ERR(priv->grf)) {
+ dev_err(dev, "Can't find GRF syscon\n");
+ return PTR_ERR(priv->grf);
+ }
+
+ priv->phy_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->phy_base))
+ return PTR_ERR(priv->phy_base);
+
+ priv->pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(priv->pclk)) {
+ dev_err(dev, "failed to get pclk\n");
+ return PTR_ERR(priv->pclk);
+ }
+
+ priv->rst = devm_reset_control_get(dev, "apb");
+ if (IS_ERR(priv->rst)) {
+ dev_err(dev, "failed to get system reset control\n");
+ return PTR_ERR(priv->rst);
+ }
+
+ phy = devm_phy_create(dev, NULL, &rockchip_inno_csidphy_ops);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "failed to create phy\n");
+ return PTR_ERR(phy);
+ }
+
+ phy_set_drvdata(phy, priv);
+
+ 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(phy_provider);
+ }
+
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+
+static int rockchip_inno_csidphy_remove(struct platform_device *pdev)
+{
+ struct rockchip_inno_csidphy *priv = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(priv->dev);
+
+ return 0;
+}
+
+static struct platform_driver rockchip_inno_csidphy_driver = {
+ .driver = {
+ .name = "rockchip-inno-csidphy",
+ .of_match_table = rockchip_inno_csidphy_match_id,
+ },
+ .probe = rockchip_inno_csidphy_probe,
+ .remove = rockchip_inno_csidphy_remove,
+};
+
+module_platform_driver(rockchip_inno_csidphy_driver);
+MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
+MODULE_DESCRIPTION("Rockchip MIPI Innosilicon CSI-DPHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
index a37f3f342642..80acca4e9e14 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
@@ -620,7 +620,7 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
- const struct pre_pll_config *cfg = pre_pll_cfg_table;
+ const struct pre_pll_config *cfg;
unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate);
u32 v;
int ret;
@@ -774,7 +774,7 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
- const struct pre_pll_config *cfg = pre_pll_cfg_table;
+ const struct pre_pll_config *cfg;
unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate);
u32 val;
int ret;
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index 46ebdb1460a3..beacac1dd253 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -1256,6 +1256,49 @@ static const struct rockchip_usb2phy_cfg rk3228_phy_cfgs[] = {
{ /* sentinel */ }
};
+static const struct rockchip_usb2phy_cfg rk3308_phy_cfgs[] = {
+ {
+ .reg = 0x100,
+ .num_ports = 2,
+ .clkout_ctl = { 0x108, 4, 4, 1, 0 },
+ .port_cfgs = {
+ [USB2PHY_PORT_OTG] = {
+ .phy_sus = { 0x0100, 8, 0, 0, 0x1d1 },
+ .bvalid_det_en = { 0x3020, 2, 2, 0, 1 },
+ .bvalid_det_st = { 0x3024, 2, 2, 0, 1 },
+ .bvalid_det_clr = { 0x3028, 2, 2, 0, 1 },
+ .ls_det_en = { 0x3020, 0, 0, 0, 1 },
+ .ls_det_st = { 0x3024, 0, 0, 0, 1 },
+ .ls_det_clr = { 0x3028, 0, 0, 0, 1 },
+ .utmi_avalid = { 0x0120, 10, 10, 0, 1 },
+ .utmi_bvalid = { 0x0120, 9, 9, 0, 1 },
+ .utmi_ls = { 0x0120, 5, 4, 0, 1 },
+ },
+ [USB2PHY_PORT_HOST] = {
+ .phy_sus = { 0x0104, 8, 0, 0, 0x1d1 },
+ .ls_det_en = { 0x3020, 1, 1, 0, 1 },
+ .ls_det_st = { 0x3024, 1, 1, 0, 1 },
+ .ls_det_clr = { 0x3028, 1, 1, 0, 1 },
+ .utmi_ls = { 0x0120, 17, 16, 0, 1 },
+ .utmi_hstdet = { 0x0120, 19, 19, 0, 1 }
+ }
+ },
+ .chg_det = {
+ .opmode = { 0x0100, 3, 0, 5, 1 },
+ .cp_det = { 0x0120, 24, 24, 0, 1 },
+ .dcp_det = { 0x0120, 23, 23, 0, 1 },
+ .dp_det = { 0x0120, 25, 25, 0, 1 },
+ .idm_sink_en = { 0x0108, 8, 8, 0, 1 },
+ .idp_sink_en = { 0x0108, 7, 7, 0, 1 },
+ .idp_src_en = { 0x0108, 9, 9, 0, 1 },
+ .rdm_pdwn_en = { 0x0108, 10, 10, 0, 1 },
+ .vdm_src_en = { 0x0108, 12, 12, 0, 1 },
+ .vdp_src_en = { 0x0108, 11, 11, 0, 1 },
+ },
+ },
+ { /* sentinel */ }
+};
+
static const struct rockchip_usb2phy_cfg rk3328_phy_cfgs[] = {
{
.reg = 0x100,
@@ -1425,6 +1468,7 @@ static const struct rockchip_usb2phy_cfg rv1108_phy_cfgs[] = {
static const struct of_device_id rockchip_usb2phy_dt_match[] = {
{ .compatible = "rockchip,px30-usb2phy", .data = &rk3328_phy_cfgs },
{ .compatible = "rockchip,rk3228-usb2phy", .data = &rk3228_phy_cfgs },
+ { .compatible = "rockchip,rk3308-usb2phy", .data = &rk3308_phy_cfgs },
{ .compatible = "rockchip,rk3328-usb2phy", .data = &rk3328_phy_cfgs },
{ .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs },
{ .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs },
diff --git a/drivers/phy/socionext/phy-uniphier-pcie.c b/drivers/phy/socionext/phy-uniphier-pcie.c
index e4adab375c73..6bdbd1f214dd 100644
--- a/drivers/phy/socionext/phy-uniphier-pcie.c
+++ b/drivers/phy/socionext/phy-uniphier-pcie.c
@@ -24,11 +24,13 @@
#define PORT_SEL_1 FIELD_PREP(PORT_SEL_MASK, 1)
#define PCL_PHY_TEST_I 0x2000
-#define PCL_PHY_TEST_O 0x2004
#define TESTI_DAT_MASK GENMASK(13, 6)
#define TESTI_ADR_MASK GENMASK(5, 1)
#define TESTI_WR_EN BIT(0)
+#define PCL_PHY_TEST_O 0x2004
+#define TESTO_DAT_MASK GENMASK(7, 0)
+
#define PCL_PHY_RESET 0x200c
#define PCL_PHY_RESET_N_MNMODE BIT(8) /* =1:manual */
#define PCL_PHY_RESET_N BIT(0) /* =1:deasssert */
@@ -77,11 +79,12 @@ static void uniphier_pciephy_set_param(struct uniphier_pciephy_priv *priv,
val = FIELD_PREP(TESTI_DAT_MASK, 1);
val |= FIELD_PREP(TESTI_ADR_MASK, reg);
uniphier_pciephy_testio_write(priv, val);
- val = readl(priv->base + PCL_PHY_TEST_O);
+ val = readl(priv->base + PCL_PHY_TEST_O) & TESTO_DAT_MASK;
/* update value */
- val &= ~FIELD_PREP(TESTI_DAT_MASK, mask);
- val = FIELD_PREP(TESTI_DAT_MASK, mask & param);
+ val &= ~mask;
+ val |= mask & param;
+ val = FIELD_PREP(TESTI_DAT_MASK, val);
val |= FIELD_PREP(TESTI_ADR_MASK, reg);
uniphier_pciephy_testio_write(priv, val);
uniphier_pciephy_testio_write(priv, val | TESTI_WR_EN);
diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c
index c184f4e34584..3e491dfb2525 100644
--- a/drivers/phy/st/phy-stm32-usbphyc.c
+++ b/drivers/phy/st/phy-stm32-usbphyc.c
@@ -57,6 +57,7 @@ struct pll_params {
struct stm32_usbphyc_phy {
struct phy *phy;
struct stm32_usbphyc *usbphyc;
+ struct regulator *vbus;
u32 index;
bool active;
};
@@ -291,9 +292,31 @@ static int stm32_usbphyc_phy_exit(struct phy *phy)
return stm32_usbphyc_pll_disable(usbphyc);
}
+static int stm32_usbphyc_phy_power_on(struct phy *phy)
+{
+ struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy);
+
+ if (usbphyc_phy->vbus)
+ return regulator_enable(usbphyc_phy->vbus);
+
+ return 0;
+}
+
+static int stm32_usbphyc_phy_power_off(struct phy *phy)
+{
+ struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy);
+
+ if (usbphyc_phy->vbus)
+ return regulator_disable(usbphyc_phy->vbus);
+
+ return 0;
+}
+
static const struct phy_ops stm32_usbphyc_phy_ops = {
.init = stm32_usbphyc_phy_init,
.exit = stm32_usbphyc_phy_exit,
+ .power_on = stm32_usbphyc_phy_power_on,
+ .power_off = stm32_usbphyc_phy_power_off,
.owner = THIS_MODULE,
};
@@ -519,6 +542,14 @@ static int stm32_usbphyc_probe(struct platform_device *pdev)
usbphyc->phys[port]->index = index;
usbphyc->phys[port]->active = false;
+ usbphyc->phys[port]->vbus = devm_regulator_get_optional(&phy->dev, "vbus");
+ if (IS_ERR(usbphyc->phys[port]->vbus)) {
+ ret = PTR_ERR(usbphyc->phys[port]->vbus);
+ if (ret == -EPROBE_DEFER)
+ goto put_child;
+ usbphyc->phys[port]->vbus = NULL;
+ }
+
port++;
}
diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c
index 5d64f69b39a9..ae3915ed9fef 100644
--- a/drivers/phy/tegra/xusb-tegra186.c
+++ b/drivers/phy/tegra/xusb-tegra186.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2016-2019, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2016-2020, NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/delay.h>
@@ -113,6 +113,117 @@
#define ID_OVERRIDE_FLOATING ID_OVERRIDE(8)
#define ID_OVERRIDE_GROUNDED ID_OVERRIDE(0)
+/* XUSB AO registers */
+#define XUSB_AO_USB_DEBOUNCE_DEL (0x4)
+#define UHSIC_LINE_DEB_CNT(x) (((x) & 0xf) << 4)
+#define UTMIP_LINE_DEB_CNT(x) ((x) & 0xf)
+
+#define XUSB_AO_UTMIP_TRIGGERS(x) (0x40 + (x) * 4)
+#define CLR_WALK_PTR BIT(0)
+#define CAP_CFG BIT(1)
+#define CLR_WAKE_ALARM BIT(3)
+
+#define XUSB_AO_UHSIC_TRIGGERS(x) (0x60 + (x) * 4)
+#define HSIC_CLR_WALK_PTR BIT(0)
+#define HSIC_CLR_WAKE_ALARM BIT(3)
+#define HSIC_CAP_CFG BIT(4)
+
+#define XUSB_AO_UTMIP_SAVED_STATE(x) (0x70 + (x) * 4)
+#define SPEED(x) ((x) & 0x3)
+#define UTMI_HS SPEED(0)
+#define UTMI_FS SPEED(1)
+#define UTMI_LS SPEED(2)
+#define UTMI_RST SPEED(3)
+
+#define XUSB_AO_UHSIC_SAVED_STATE(x) (0x90 + (x) * 4)
+#define MODE(x) ((x) & 0x1)
+#define MODE_HS MODE(0)
+#define MODE_RST MODE(1)
+
+#define XUSB_AO_UTMIP_SLEEPWALK_CFG(x) (0xd0 + (x) * 4)
+#define XUSB_AO_UHSIC_SLEEPWALK_CFG(x) (0xf0 + (x) * 4)
+#define FAKE_USBOP_VAL BIT(0)
+#define FAKE_USBON_VAL BIT(1)
+#define FAKE_USBOP_EN BIT(2)
+#define FAKE_USBON_EN BIT(3)
+#define FAKE_STROBE_VAL BIT(0)
+#define FAKE_DATA_VAL BIT(1)
+#define FAKE_STROBE_EN BIT(2)
+#define FAKE_DATA_EN BIT(3)
+#define WAKE_WALK_EN BIT(14)
+#define MASTER_ENABLE BIT(15)
+#define LINEVAL_WALK_EN BIT(16)
+#define WAKE_VAL(x) (((x) & 0xf) << 17)
+#define WAKE_VAL_NONE WAKE_VAL(12)
+#define WAKE_VAL_ANY WAKE_VAL(15)
+#define WAKE_VAL_DS10 WAKE_VAL(2)
+#define LINE_WAKEUP_EN BIT(21)
+#define MASTER_CFG_SEL BIT(22)
+
+#define XUSB_AO_UTMIP_SLEEPWALK(x) (0x100 + (x) * 4)
+/* phase A */
+#define USBOP_RPD_A BIT(0)
+#define USBON_RPD_A BIT(1)
+#define AP_A BIT(4)
+#define AN_A BIT(5)
+#define HIGHZ_A BIT(6)
+/* phase B */
+#define USBOP_RPD_B BIT(8)
+#define USBON_RPD_B BIT(9)
+#define AP_B BIT(12)
+#define AN_B BIT(13)
+#define HIGHZ_B BIT(14)
+/* phase C */
+#define USBOP_RPD_C BIT(16)
+#define USBON_RPD_C BIT(17)
+#define AP_C BIT(20)
+#define AN_C BIT(21)
+#define HIGHZ_C BIT(22)
+/* phase D */
+#define USBOP_RPD_D BIT(24)
+#define USBON_RPD_D BIT(25)
+#define AP_D BIT(28)
+#define AN_D BIT(29)
+#define HIGHZ_D BIT(30)
+
+#define XUSB_AO_UHSIC_SLEEPWALK(x) (0x120 + (x) * 4)
+/* phase A */
+#define RPD_STROBE_A BIT(0)
+#define RPD_DATA0_A BIT(1)
+#define RPU_STROBE_A BIT(2)
+#define RPU_DATA0_A BIT(3)
+/* phase B */
+#define RPD_STROBE_B BIT(8)
+#define RPD_DATA0_B BIT(9)
+#define RPU_STROBE_B BIT(10)
+#define RPU_DATA0_B BIT(11)
+/* phase C */
+#define RPD_STROBE_C BIT(16)
+#define RPD_DATA0_C BIT(17)
+#define RPU_STROBE_C BIT(18)
+#define RPU_DATA0_C BIT(19)
+/* phase D */
+#define RPD_STROBE_D BIT(24)
+#define RPD_DATA0_D BIT(25)
+#define RPU_STROBE_D BIT(26)
+#define RPU_DATA0_D BIT(27)
+
+#define XUSB_AO_UTMIP_PAD_CFG(x) (0x130 + (x) * 4)
+#define FSLS_USE_XUSB_AO BIT(3)
+#define TRK_CTRL_USE_XUSB_AO BIT(4)
+#define RPD_CTRL_USE_XUSB_AO BIT(5)
+#define RPU_USE_XUSB_AO BIT(6)
+#define VREG_USE_XUSB_AO BIT(7)
+#define USBOP_VAL_PD BIT(8)
+#define USBON_VAL_PD BIT(9)
+#define E_DPD_OVRD_EN BIT(10)
+#define E_DPD_OVRD_VAL BIT(11)
+
+#define XUSB_AO_UHSIC_PAD_CFG(x) (0x150 + (x) * 4)
+#define STROBE_VAL_PD BIT(0)
+#define DATA0_VAL_PD BIT(1)
+#define USE_XUSB_AO BIT(4)
+
#define TEGRA186_LANE(_name, _offset, _shift, _mask, _type) \
{ \
.name = _name, \
@@ -130,16 +241,37 @@ struct tegra_xusb_fuse_calibration {
u32 rpd_ctrl;
};
+struct tegra186_xusb_padctl_context {
+ u32 vbus_id;
+ u32 usb2_pad_mux;
+ u32 usb2_port_cap;
+ u32 ss_port_cap;
+};
+
struct tegra186_xusb_padctl {
struct tegra_xusb_padctl base;
+ void __iomem *ao_regs;
struct tegra_xusb_fuse_calibration calib;
/* UTMI bias and tracking */
struct clk *usb2_trk_clk;
unsigned int bias_pad_enable;
+
+ /* padctl context */
+ struct tegra186_xusb_padctl_context context;
};
+static inline void ao_writel(struct tegra186_xusb_padctl *priv, u32 value, unsigned int offset)
+{
+ writel(value, priv->ao_regs + offset);
+}
+
+static inline u32 ao_readl(struct tegra186_xusb_padctl *priv, unsigned int offset)
+{
+ return readl(priv->ao_regs + offset);
+}
+
static inline struct tegra186_xusb_padctl *
to_tegra186_xusb_padctl(struct tegra_xusb_padctl *padctl)
{
@@ -180,9 +312,264 @@ static void tegra186_usb2_lane_remove(struct tegra_xusb_lane *lane)
kfree(usb2);
}
+static int tegra186_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
+ enum usb_device_speed speed)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
+ unsigned int index = lane->index;
+ u32 value;
+
+ mutex_lock(&padctl->lock);
+
+ /* ensure sleepwalk logic is disabled */
+ value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+ value &= ~MASTER_ENABLE;
+ ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+
+ /* ensure sleepwalk logics are in low power mode */
+ value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+ value |= MASTER_CFG_SEL;
+ ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+
+ /* set debounce time */
+ value = ao_readl(priv, XUSB_AO_USB_DEBOUNCE_DEL);
+ value &= ~UTMIP_LINE_DEB_CNT(~0);
+ value |= UTMIP_LINE_DEB_CNT(1);
+ ao_writel(priv, value, XUSB_AO_USB_DEBOUNCE_DEL);
+
+ /* ensure fake events of sleepwalk logic are desiabled */
+ value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+ value &= ~(FAKE_USBOP_VAL | FAKE_USBON_VAL |
+ FAKE_USBOP_EN | FAKE_USBON_EN);
+ ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+
+ /* ensure wake events of sleepwalk logic are not latched */
+ value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+ value &= ~LINE_WAKEUP_EN;
+ ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+
+ /* disable wake event triggers of sleepwalk logic */
+ value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+ value &= ~WAKE_VAL(~0);
+ value |= WAKE_VAL_NONE;
+ ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+
+ /* power down the line state detectors of the pad */
+ value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
+ value |= (USBOP_VAL_PD | USBON_VAL_PD);
+ ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
+
+ /* save state per speed */
+ value = ao_readl(priv, XUSB_AO_UTMIP_SAVED_STATE(index));
+ value &= ~SPEED(~0);
+
+ switch (speed) {
+ case USB_SPEED_HIGH:
+ value |= UTMI_HS;
+ break;
+
+ case USB_SPEED_FULL:
+ value |= UTMI_FS;
+ break;
+
+ case USB_SPEED_LOW:
+ value |= UTMI_LS;
+ break;
+
+ default:
+ value |= UTMI_RST;
+ break;
+ }
+
+ ao_writel(priv, value, XUSB_AO_UTMIP_SAVED_STATE(index));
+
+ /* enable the trigger of the sleepwalk logic */
+ value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+ value |= LINEVAL_WALK_EN;
+ value &= ~WAKE_WALK_EN;
+ ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+
+ /* reset the walk pointer and clear the alarm of the sleepwalk logic,
+ * as well as capture the configuration of the USB2.0 pad
+ */
+ value = ao_readl(priv, XUSB_AO_UTMIP_TRIGGERS(index));
+ value |= (CLR_WALK_PTR | CLR_WAKE_ALARM | CAP_CFG);
+ ao_writel(priv, value, XUSB_AO_UTMIP_TRIGGERS(index));
+
+ /* setup the pull-ups and pull-downs of the signals during the four
+ * stages of sleepwalk.
+ * if device is connected, program sleepwalk logic to maintain a J and
+ * keep driving K upon seeing remote wake.
+ */
+ value = USBOP_RPD_A | USBOP_RPD_B | USBOP_RPD_C | USBOP_RPD_D;
+ value |= USBON_RPD_A | USBON_RPD_B | USBON_RPD_C | USBON_RPD_D;
+
+ switch (speed) {
+ case USB_SPEED_HIGH:
+ case USB_SPEED_FULL:
+ /* J state: D+/D- = high/low, K state: D+/D- = low/high */
+ value |= HIGHZ_A;
+ value |= AP_A;
+ value |= AN_B | AN_C | AN_D;
+ break;
+
+ case USB_SPEED_LOW:
+ /* J state: D+/D- = low/high, K state: D+/D- = high/low */
+ value |= HIGHZ_A;
+ value |= AN_A;
+ value |= AP_B | AP_C | AP_D;
+ break;
+
+ default:
+ value |= HIGHZ_A | HIGHZ_B | HIGHZ_C | HIGHZ_D;
+ break;
+ }
+
+ ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK(index));
+
+ /* power up the line state detectors of the pad */
+ value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
+ value &= ~(USBOP_VAL_PD | USBON_VAL_PD);
+ ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
+
+ usleep_range(150, 200);
+
+ /* switch the electric control of the USB2.0 pad to XUSB_AO */
+ value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
+ value |= FSLS_USE_XUSB_AO | TRK_CTRL_USE_XUSB_AO | RPD_CTRL_USE_XUSB_AO |
+ RPU_USE_XUSB_AO | VREG_USE_XUSB_AO;
+ ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
+
+ /* set the wake signaling trigger events */
+ value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+ value &= ~WAKE_VAL(~0);
+ value |= WAKE_VAL_ANY;
+ ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+
+ /* enable the wake detection */
+ value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+ value |= MASTER_ENABLE | LINE_WAKEUP_EN;
+ ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static int tegra186_utmi_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
+ unsigned int index = lane->index;
+ u32 value;
+
+ mutex_lock(&padctl->lock);
+
+ /* disable the wake detection */
+ value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+ value &= ~(MASTER_ENABLE | LINE_WAKEUP_EN);
+ ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+
+ /* switch the electric control of the USB2.0 pad to XUSB vcore logic */
+ value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
+ value &= ~(FSLS_USE_XUSB_AO | TRK_CTRL_USE_XUSB_AO | RPD_CTRL_USE_XUSB_AO |
+ RPU_USE_XUSB_AO | VREG_USE_XUSB_AO);
+ ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
+
+ /* disable wake event triggers of sleepwalk logic */
+ value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+ value &= ~WAKE_VAL(~0);
+ value |= WAKE_VAL_NONE;
+ ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+
+ /* power down the line state detectors of the port */
+ value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
+ value |= USBOP_VAL_PD | USBON_VAL_PD;
+ ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
+
+ /* clear alarm of the sleepwalk logic */
+ value = ao_readl(priv, XUSB_AO_UTMIP_TRIGGERS(index));
+ value |= CLR_WAKE_ALARM;
+ ao_writel(priv, value, XUSB_AO_UTMIP_TRIGGERS(index));
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static int tegra186_utmi_enable_phy_wake(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ u32 value;
+
+ mutex_lock(&padctl->lock);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= USB2_PORT_WAKEUP_EVENT(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+ usleep_range(10, 20);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static int tegra186_utmi_disable_phy_wake(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ u32 value;
+
+ mutex_lock(&padctl->lock);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+ value &= ~ALL_WAKE_EVENTS;
+ value &= ~USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+ usleep_range(10, 20);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= USB2_PORT_WAKEUP_EVENT(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static bool tegra186_utmi_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ u32 value;
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+ if ((value & USB2_PORT_WAKE_INTERRUPT_ENABLE(index)) &&
+ (value & USB2_PORT_WAKEUP_EVENT(index)))
+ return true;
+
+ return false;
+}
+
static const struct tegra_xusb_lane_ops tegra186_usb2_lane_ops = {
.probe = tegra186_usb2_lane_probe,
.remove = tegra186_usb2_lane_remove,
+ .enable_phy_sleepwalk = tegra186_utmi_enable_phy_sleepwalk,
+ .disable_phy_sleepwalk = tegra186_utmi_disable_phy_sleepwalk,
+ .enable_phy_wake = tegra186_utmi_enable_phy_wake,
+ .disable_phy_wake = tegra186_utmi_disable_phy_wake,
+ .remote_wake_detected = tegra186_utmi_phy_remote_wake_detected,
};
static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl)
@@ -656,10 +1043,128 @@ static void tegra186_usb3_lane_remove(struct tegra_xusb_lane *lane)
kfree(usb3);
}
+static int tegra186_usb3_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
+ enum usb_device_speed speed)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ u32 value;
+
+ mutex_lock(&padctl->lock);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
+ value |= SSPX_ELPG_CLAMP_EN_EARLY(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
+
+ usleep_range(100, 200);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
+ value |= SSPX_ELPG_CLAMP_EN(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
+
+ usleep_range(250, 350);
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static int tegra186_usb3_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ u32 value;
+
+ mutex_lock(&padctl->lock);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
+ value &= ~SSPX_ELPG_CLAMP_EN_EARLY(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
+
+ usleep_range(100, 200);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
+ value &= ~SSPX_ELPG_CLAMP_EN(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static int tegra186_usb3_enable_phy_wake(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ u32 value;
+
+ mutex_lock(&padctl->lock);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= SS_PORT_WAKEUP_EVENT(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+ usleep_range(10, 20);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= SS_PORT_WAKE_INTERRUPT_ENABLE(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static int tegra186_usb3_disable_phy_wake(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ u32 value;
+
+ mutex_lock(&padctl->lock);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+ value &= ~ALL_WAKE_EVENTS;
+ value &= ~SS_PORT_WAKE_INTERRUPT_ENABLE(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+ usleep_range(10, 20);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= SS_PORT_WAKEUP_EVENT(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static bool tegra186_usb3_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ u32 value;
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+ if ((value & SS_PORT_WAKE_INTERRUPT_ENABLE(index)) && (value & SS_PORT_WAKEUP_EVENT(index)))
+ return true;
+
+ return false;
+}
+
static const struct tegra_xusb_lane_ops tegra186_usb3_lane_ops = {
.probe = tegra186_usb3_lane_probe,
.remove = tegra186_usb3_lane_remove,
+ .enable_phy_sleepwalk = tegra186_usb3_enable_phy_sleepwalk,
+ .disable_phy_sleepwalk = tegra186_usb3_disable_phy_sleepwalk,
+ .enable_phy_wake = tegra186_usb3_enable_phy_wake,
+ .disable_phy_wake = tegra186_usb3_disable_phy_wake,
+ .remote_wake_detected = tegra186_usb3_phy_remote_wake_detected,
};
+
static int tegra186_usb3_port_enable(struct tegra_xusb_port *port)
{
return 0;
@@ -913,7 +1418,9 @@ static struct tegra_xusb_padctl *
tegra186_xusb_padctl_probe(struct device *dev,
const struct tegra_xusb_padctl_soc *soc)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct tegra186_xusb_padctl *priv;
+ struct resource *res;
int err;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -923,6 +1430,11 @@ tegra186_xusb_padctl_probe(struct device *dev,
priv->base.dev = dev;
priv->base.soc = soc;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ao");
+ priv->ao_regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->ao_regs))
+ return ERR_CAST(priv->ao_regs);
+
err = tegra186_xusb_read_fuse_calibration(priv);
if (err < 0)
return ERR_PTR(err);
@@ -930,6 +1442,40 @@ tegra186_xusb_padctl_probe(struct device *dev,
return &priv->base;
}
+static void tegra186_xusb_padctl_save(struct tegra_xusb_padctl *padctl)
+{
+ struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
+
+ priv->context.vbus_id = padctl_readl(padctl, USB2_VBUS_ID);
+ priv->context.usb2_pad_mux = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
+ priv->context.usb2_port_cap = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
+ priv->context.ss_port_cap = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CAP);
+}
+
+static void tegra186_xusb_padctl_restore(struct tegra_xusb_padctl *padctl)
+{
+ struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
+
+ padctl_writel(padctl, priv->context.usb2_pad_mux, XUSB_PADCTL_USB2_PAD_MUX);
+ padctl_writel(padctl, priv->context.usb2_port_cap, XUSB_PADCTL_USB2_PORT_CAP);
+ padctl_writel(padctl, priv->context.ss_port_cap, XUSB_PADCTL_SS_PORT_CAP);
+ padctl_writel(padctl, priv->context.vbus_id, USB2_VBUS_ID);
+}
+
+static int tegra186_xusb_padctl_suspend_noirq(struct tegra_xusb_padctl *padctl)
+{
+ tegra186_xusb_padctl_save(padctl);
+
+ return 0;
+}
+
+static int tegra186_xusb_padctl_resume_noirq(struct tegra_xusb_padctl *padctl)
+{
+ tegra186_xusb_padctl_restore(padctl);
+
+ return 0;
+}
+
static void tegra186_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
{
}
@@ -937,6 +1483,8 @@ static void tegra186_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
static const struct tegra_xusb_padctl_ops tegra186_xusb_padctl_ops = {
.probe = tegra186_xusb_padctl_probe,
.remove = tegra186_xusb_padctl_remove,
+ .suspend_noirq = tegra186_xusb_padctl_suspend_noirq,
+ .resume_noirq = tegra186_xusb_padctl_resume_noirq,
.vbus_override = tegra186_xusb_padctl_vbus_override,
};
diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c
index 66bd4613835b..eedfc7c2cc05 100644
--- a/drivers/phy/tegra/xusb-tegra210.c
+++ b/drivers/phy/tegra/xusb-tegra210.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2014-2020, NVIDIA CORPORATION. All rights reserved.
* Copyright (C) 2015 Google, Inc.
*/
@@ -11,8 +11,10 @@
#include <linux/mailbox_client.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>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
@@ -52,6 +54,20 @@
#define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(x, v) (((v) & 0x7) << ((x) * 5))
#define XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED 0x7
+#define XUSB_PADCTL_ELPG_PROGRAM_0 0x20
+#define USB2_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x))
+#define USB2_PORT_WAKEUP_EVENT(x) BIT((x) + 7)
+#define SS_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 14)
+#define SS_PORT_WAKEUP_EVENT(x) BIT((x) + 21)
+#define USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 28)
+#define USB2_HSIC_PORT_WAKEUP_EVENT(x) BIT((x) + 30)
+#define ALL_WAKE_EVENTS ( \
+ USB2_PORT_WAKEUP_EVENT(0) | USB2_PORT_WAKEUP_EVENT(1) | \
+ USB2_PORT_WAKEUP_EVENT(2) | USB2_PORT_WAKEUP_EVENT(3) | \
+ SS_PORT_WAKEUP_EVENT(0) | SS_PORT_WAKEUP_EVENT(1) | \
+ SS_PORT_WAKEUP_EVENT(2) | SS_PORT_WAKEUP_EVENT(3) | \
+ USB2_HSIC_PORT_WAKEUP_EVENT(0))
+
#define XUSB_PADCTL_ELPG_PROGRAM1 0x024
#define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN (1 << 31)
#define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 30)
@@ -90,6 +106,8 @@
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2)
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD (1 << 1)
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD (1 << 0)
+#define RPD_CTRL(x) (((x) & 0x1f) << 26)
+#define RPD_CTRL_VALUE(x) (((x) >> 26) & 0x1f)
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 11)
@@ -108,6 +126,8 @@
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT 12
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK 0x7f
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL 0x1e
+#define TCTRL_VALUE(x) (((x) & 0x3f) >> 0)
+#define PCTRL_VALUE(x) (((x) >> 6) & 0x3f)
#define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x300 + (x) * 0x20)
#define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE (1 << 18)
@@ -198,6 +218,18 @@
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN BIT(18)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD BIT(13)
+#define XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(x) (0x464 + (x) * 0x40)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ BIT(0)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD BIT(1)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK GENMASK(5, 4)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL GENMASK(5, 4)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD BIT(24)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ BIT(8)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD BIT(9)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK GENMASK(13, 12)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL GENMASK(13, 12)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD BIT(25)
+
#define XUSB_PADCTL_UPHY_PLL_S0_CTL1 0x860
#define XUSB_PADCTL_UPHY_PLL_S0_CTL2 0x864
@@ -209,6 +241,7 @@
#define XUSB_PADCTL_UPHY_PLL_S0_CTL8 0x87c
#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1 0x960
+#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2 0x964
#define XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(x) (0xa60 + (x) * 0x40)
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT 16
@@ -238,16 +271,161 @@
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED 0
+/* USB2 SLEEPWALK registers */
+#define UTMIP(_port, _offset1, _offset2) \
+ (((_port) <= 2) ? (_offset1) : (_offset2))
+
+#define PMC_UTMIP_UHSIC_SLEEP_CFG(x) UTMIP(x, 0x1fc, 0x4d0)
+#define UTMIP_MASTER_ENABLE(x) UTMIP(x, BIT(8 * (x)), BIT(0))
+#define UTMIP_FSLS_USE_PMC(x) UTMIP(x, BIT(8 * (x) + 1), \
+ BIT(1))
+#define UTMIP_PCTRL_USE_PMC(x) UTMIP(x, BIT(8 * (x) + 2), \
+ BIT(2))
+#define UTMIP_TCTRL_USE_PMC(x) UTMIP(x, BIT(8 * (x) + 3), \
+ BIT(3))
+#define UTMIP_WAKE_VAL(_port, _value) (((_value) & 0xf) << \
+ (UTMIP(_port, 8 * (_port) + 4, 4)))
+#define UTMIP_WAKE_VAL_NONE(_port) UTMIP_WAKE_VAL(_port, 12)
+#define UTMIP_WAKE_VAL_ANY(_port) UTMIP_WAKE_VAL(_port, 15)
+
+#define PMC_UTMIP_UHSIC_SLEEP_CFG1 (0x4d0)
+#define UTMIP_RPU_SWITC_LOW_USE_PMC_PX(x) BIT((x) + 8)
+#define UTMIP_RPD_CTRL_USE_PMC_PX(x) BIT((x) + 16)
+
+#define PMC_UTMIP_MASTER_CONFIG (0x274)
+#define UTMIP_PWR(x) UTMIP(x, BIT(x), BIT(4))
+#define UHSIC_PWR BIT(3)
+
+#define PMC_USB_DEBOUNCE_DEL (0xec)
+#define DEBOUNCE_VAL(x) (((x) & 0xffff) << 0)
+#define UTMIP_LINE_DEB_CNT(x) (((x) & 0xf) << 16)
+#define UHSIC_LINE_DEB_CNT(x) (((x) & 0xf) << 20)
+
+#define PMC_UTMIP_UHSIC_FAKE(x) UTMIP(x, 0x218, 0x294)
+#define UTMIP_FAKE_USBOP_VAL(x) UTMIP(x, BIT(4 * (x)), BIT(8))
+#define UTMIP_FAKE_USBON_VAL(x) UTMIP(x, BIT(4 * (x) + 1), \
+ BIT(9))
+#define UTMIP_FAKE_USBOP_EN(x) UTMIP(x, BIT(4 * (x) + 2), \
+ BIT(10))
+#define UTMIP_FAKE_USBON_EN(x) UTMIP(x, BIT(4 * (x) + 3), \
+ BIT(11))
+
+#define PMC_UTMIP_UHSIC_SLEEPWALK_CFG(x) UTMIP(x, 0x200, 0x288)
+#define UTMIP_LINEVAL_WALK_EN(x) UTMIP(x, BIT(8 * (x) + 7), \
+ BIT(15))
+
+#define PMC_USB_AO (0xf0)
+#define USBOP_VAL_PD(x) UTMIP(x, BIT(4 * (x)), BIT(20))
+#define USBON_VAL_PD(x) UTMIP(x, BIT(4 * (x) + 1), \
+ BIT(21))
+#define STROBE_VAL_PD BIT(12)
+#define DATA0_VAL_PD BIT(13)
+#define DATA1_VAL_PD BIT(24)
+
+#define PMC_UTMIP_UHSIC_SAVED_STATE(x) UTMIP(x, 0x1f0, 0x280)
+#define SPEED(_port, _value) (((_value) & 0x3) << \
+ (UTMIP(_port, 8 * (_port), 8)))
+#define UTMI_HS(_port) SPEED(_port, 0)
+#define UTMI_FS(_port) SPEED(_port, 1)
+#define UTMI_LS(_port) SPEED(_port, 2)
+#define UTMI_RST(_port) SPEED(_port, 3)
+
+#define PMC_UTMIP_UHSIC_TRIGGERS (0x1ec)
+#define UTMIP_CLR_WALK_PTR(x) UTMIP(x, BIT(x), BIT(16))
+#define UTMIP_CAP_CFG(x) UTMIP(x, BIT((x) + 4), BIT(17))
+#define UTMIP_CLR_WAKE_ALARM(x) UTMIP(x, BIT((x) + 12), \
+ BIT(19))
+#define UHSIC_CLR_WALK_PTR BIT(3)
+#define UHSIC_CLR_WAKE_ALARM BIT(15)
+
+#define PMC_UTMIP_SLEEPWALK_PX(x) UTMIP(x, 0x204 + (4 * (x)), \
+ 0x4e0)
+/* phase A */
+#define UTMIP_USBOP_RPD_A BIT(0)
+#define UTMIP_USBON_RPD_A BIT(1)
+#define UTMIP_AP_A BIT(4)
+#define UTMIP_AN_A BIT(5)
+#define UTMIP_HIGHZ_A BIT(6)
+/* phase B */
+#define UTMIP_USBOP_RPD_B BIT(8)
+#define UTMIP_USBON_RPD_B BIT(9)
+#define UTMIP_AP_B BIT(12)
+#define UTMIP_AN_B BIT(13)
+#define UTMIP_HIGHZ_B BIT(14)
+/* phase C */
+#define UTMIP_USBOP_RPD_C BIT(16)
+#define UTMIP_USBON_RPD_C BIT(17)
+#define UTMIP_AP_C BIT(20)
+#define UTMIP_AN_C BIT(21)
+#define UTMIP_HIGHZ_C BIT(22)
+/* phase D */
+#define UTMIP_USBOP_RPD_D BIT(24)
+#define UTMIP_USBON_RPD_D BIT(25)
+#define UTMIP_AP_D BIT(28)
+#define UTMIP_AN_D BIT(29)
+#define UTMIP_HIGHZ_D BIT(30)
+
+#define PMC_UTMIP_UHSIC_LINE_WAKEUP (0x26c)
+#define UTMIP_LINE_WAKEUP_EN(x) UTMIP(x, BIT(x), BIT(4))
+#define UHSIC_LINE_WAKEUP_EN BIT(3)
+
+#define PMC_UTMIP_TERM_PAD_CFG (0x1f8)
+#define PCTRL_VAL(x) (((x) & 0x3f) << 1)
+#define TCTRL_VAL(x) (((x) & 0x3f) << 7)
+
+#define PMC_UTMIP_PAD_CFGX(x) (0x4c0 + (4 * (x)))
+#define RPD_CTRL_PX(x) (((x) & 0x1f) << 22)
+
+#define PMC_UHSIC_SLEEP_CFG PMC_UTMIP_UHSIC_SLEEP_CFG(0)
+#define UHSIC_MASTER_ENABLE BIT(24)
+#define UHSIC_WAKE_VAL(_value) (((_value) & 0xf) << 28)
+#define UHSIC_WAKE_VAL_SD10 UHSIC_WAKE_VAL(2)
+#define UHSIC_WAKE_VAL_NONE UHSIC_WAKE_VAL(12)
+
+#define PMC_UHSIC_FAKE PMC_UTMIP_UHSIC_FAKE(0)
+#define UHSIC_FAKE_STROBE_VAL BIT(12)
+#define UHSIC_FAKE_DATA_VAL BIT(13)
+#define UHSIC_FAKE_STROBE_EN BIT(14)
+#define UHSIC_FAKE_DATA_EN BIT(15)
+
+#define PMC_UHSIC_SAVED_STATE PMC_UTMIP_UHSIC_SAVED_STATE(0)
+#define UHSIC_MODE(_value) (((_value) & 0x1) << 24)
+#define UHSIC_HS UHSIC_MODE(0)
+#define UHSIC_RST UHSIC_MODE(1)
+
+#define PMC_UHSIC_SLEEPWALK_CFG PMC_UTMIP_UHSIC_SLEEPWALK_CFG(0)
+#define UHSIC_WAKE_WALK_EN BIT(30)
+#define UHSIC_LINEVAL_WALK_EN BIT(31)
+
+#define PMC_UHSIC_SLEEPWALK_P0 (0x210)
+#define UHSIC_DATA0_RPD_A BIT(1)
+#define UHSIC_DATA0_RPU_B BIT(11)
+#define UHSIC_DATA0_RPU_C BIT(19)
+#define UHSIC_DATA0_RPU_D BIT(27)
+#define UHSIC_STROBE_RPU_A BIT(2)
+#define UHSIC_STROBE_RPD_B BIT(8)
+#define UHSIC_STROBE_RPD_C BIT(16)
+#define UHSIC_STROBE_RPD_D BIT(24)
+
struct tegra210_xusb_fuse_calibration {
u32 hs_curr_level[4];
u32 hs_term_range_adj;
u32 rpd_ctrl;
};
+struct tegra210_xusb_padctl_context {
+ u32 usb2_pad_mux;
+ u32 usb2_port_cap;
+ u32 ss_port_map;
+ u32 usb3_pad_mux;
+};
+
struct tegra210_xusb_padctl {
struct tegra_xusb_padctl base;
+ struct regmap *regmap;
struct tegra210_xusb_fuse_calibration fuse;
+ struct tegra210_xusb_padctl_context context;
};
static inline struct tegra210_xusb_padctl *
@@ -256,23 +434,51 @@ to_tegra210_xusb_padctl(struct tegra_xusb_padctl *padctl)
return container_of(padctl, struct tegra210_xusb_padctl, base);
}
+static const struct tegra_xusb_lane_map tegra210_usb3_map[] = {
+ { 0, "pcie", 6 },
+ { 1, "pcie", 5 },
+ { 2, "pcie", 0 },
+ { 2, "pcie", 3 },
+ { 3, "pcie", 4 },
+ { 3, "sata", 0 },
+ { 0, NULL, 0 }
+};
+
+static int tegra210_usb3_lane_map(struct tegra_xusb_lane *lane)
+{
+ const struct tegra_xusb_lane_map *map;
+
+ for (map = tegra210_usb3_map; map->type; map++) {
+ if (map->index == lane->index &&
+ strcmp(map->type, lane->pad->soc->name) == 0) {
+ dev_dbg(lane->pad->padctl->dev, "lane = %s map to port = usb3-%d\n",
+ lane->pad->soc->lanes[lane->index].name, map->port);
+ return map->port;
+ }
+ }
+
+ return -EINVAL;
+}
+
/* must be called under padctl->lock */
static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl)
{
struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie);
unsigned long timeout;
u32 value;
+ unsigned int i;
int err;
- if (pcie->enable > 0) {
- pcie->enable++;
+ if (pcie->enable)
return 0;
- }
err = clk_prepare_enable(pcie->pll);
if (err < 0)
return err;
+ if (tegra210_plle_hw_sequence_is_enabled())
+ goto skip_pll_init;
+
err = reset_control_deassert(pcie->rst);
if (err < 0)
goto disable;
@@ -455,7 +661,14 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl)
tegra210_xusb_pll_hw_sequence_start();
- pcie->enable++;
+skip_pll_init:
+ pcie->enable = true;
+
+ for (i = 0; i < padctl->pcie->soc->num_lanes; i++) {
+ value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
+ value |= XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(i);
+ padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
+ }
return 0;
@@ -469,34 +682,44 @@ disable:
static void tegra210_pex_uphy_disable(struct tegra_xusb_padctl *padctl)
{
struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie);
+ u32 value;
+ unsigned int i;
- mutex_lock(&padctl->lock);
+ if (WARN_ON(!pcie->enable))
+ return;
- if (WARN_ON(pcie->enable == 0))
- goto unlock;
+ pcie->enable = false;
- if (--pcie->enable > 0)
- goto unlock;
+ for (i = 0; i < padctl->pcie->soc->num_lanes; i++) {
+ value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
+ value &= ~XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(i);
+ padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
+ }
- reset_control_assert(pcie->rst);
clk_disable_unprepare(pcie->pll);
-
-unlock:
- mutex_unlock(&padctl->lock);
}
/* must be called under padctl->lock */
-static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl, bool usb)
+static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl)
{
struct tegra_xusb_sata_pad *sata = to_sata_pad(padctl->sata);
+ struct tegra_xusb_lane *lane = tegra_xusb_find_lane(padctl, "sata", 0);
unsigned long timeout;
u32 value;
+ unsigned int i;
int err;
+ bool usb;
- if (sata->enable > 0) {
- sata->enable++;
+ if (sata->enable)
return 0;
- }
+
+ if (IS_ERR(lane))
+ return 0;
+
+ if (tegra210_plle_hw_sequence_is_enabled())
+ goto skip_pll_init;
+
+ usb = tegra_xusb_lane_check(lane, "usb3-ss");
err = clk_prepare_enable(sata->pll);
if (err < 0)
@@ -697,7 +920,14 @@ static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl, bool usb)
tegra210_sata_pll_hw_sequence_start();
- sata->enable++;
+skip_pll_init:
+ sata->enable = true;
+
+ for (i = 0; i < padctl->sata->soc->num_lanes; i++) {
+ value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
+ value |= XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(i);
+ padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
+ }
return 0;
@@ -711,31 +941,27 @@ disable:
static void tegra210_sata_uphy_disable(struct tegra_xusb_padctl *padctl)
{
struct tegra_xusb_sata_pad *sata = to_sata_pad(padctl->sata);
+ u32 value;
+ unsigned int i;
- mutex_lock(&padctl->lock);
+ if (WARN_ON(!sata->enable))
+ return;
- if (WARN_ON(sata->enable == 0))
- goto unlock;
+ sata->enable = false;
- if (--sata->enable > 0)
- goto unlock;
+ for (i = 0; i < padctl->sata->soc->num_lanes; i++) {
+ value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
+ value &= ~XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(i);
+ padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
+ }
- reset_control_assert(sata->rst);
clk_disable_unprepare(sata->pll);
-
-unlock:
- mutex_unlock(&padctl->lock);
}
-static int tegra210_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
+static void tegra210_aux_mux_lp0_clamp_disable(struct tegra_xusb_padctl *padctl)
{
u32 value;
- mutex_lock(&padctl->lock);
-
- if (padctl->enable++ > 0)
- goto out;
-
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN;
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
@@ -751,24 +977,12 @@ static int tegra210_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN;
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
-
-out:
- mutex_unlock(&padctl->lock);
- return 0;
}
-static int tegra210_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
+static void tegra210_aux_mux_lp0_clamp_enable(struct tegra_xusb_padctl *padctl)
{
u32 value;
- mutex_lock(&padctl->lock);
-
- if (WARN_ON(padctl->enable == 0))
- goto out;
-
- if (--padctl->enable > 0)
- goto out;
-
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN;
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
@@ -784,12 +998,38 @@ static int tegra210_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN;
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+}
+
+static int tegra210_uphy_init(struct tegra_xusb_padctl *padctl)
+{
+ if (padctl->pcie)
+ tegra210_pex_uphy_enable(padctl);
+
+ if (padctl->sata)
+ tegra210_sata_uphy_enable(padctl);
+
+ if (!tegra210_plle_hw_sequence_is_enabled())
+ tegra210_plle_hw_sequence_start();
+ else
+ dev_dbg(padctl->dev, "PLLE is already in HW control\n");
+
+ tegra210_aux_mux_lp0_clamp_disable(padctl);
-out:
- mutex_unlock(&padctl->lock);
return 0;
}
+static void __maybe_unused
+tegra210_uphy_deinit(struct tegra_xusb_padctl *padctl)
+{
+ tegra210_aux_mux_lp0_clamp_enable(padctl);
+
+ if (padctl->sata)
+ tegra210_sata_uphy_disable(padctl);
+
+ if (padctl->pcie)
+ tegra210_pex_uphy_disable(padctl);
+}
+
static int tegra210_hsic_set_idle(struct tegra_xusb_padctl *padctl,
unsigned int index, bool idle)
{
@@ -815,6 +1055,643 @@ static int tegra210_hsic_set_idle(struct tegra_xusb_padctl *padctl,
return 0;
}
+static int tegra210_usb3_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
+ enum usb_device_speed speed)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ int port = tegra210_usb3_lane_map(lane);
+ struct device *dev = padctl->dev;
+ u32 value;
+
+ if (port < 0) {
+ dev_err(dev, "invalid usb3 port number\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&padctl->lock);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
+ value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+
+ usleep_range(100, 200);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
+ value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+
+ usleep_range(250, 350);
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static int tegra210_usb3_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ int port = tegra210_usb3_lane_map(lane);
+ struct device *dev = padctl->dev;
+ u32 value;
+
+ if (port < 0) {
+ dev_err(dev, "invalid usb3 port number\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&padctl->lock);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
+ value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+
+ usleep_range(100, 200);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
+ value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static int tegra210_usb3_enable_phy_wake(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ int port = tegra210_usb3_lane_map(lane);
+ struct device *dev = padctl->dev;
+ u32 value;
+
+ if (port < 0) {
+ dev_err(dev, "invalid usb3 port number\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&padctl->lock);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= SS_PORT_WAKEUP_EVENT(port);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+ usleep_range(10, 20);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= SS_PORT_WAKE_INTERRUPT_ENABLE(port);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static int tegra210_usb3_disable_phy_wake(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ int port = tegra210_usb3_lane_map(lane);
+ struct device *dev = padctl->dev;
+ u32 value;
+
+ if (port < 0) {
+ dev_err(dev, "invalid usb3 port number\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&padctl->lock);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ value &= ~ALL_WAKE_EVENTS;
+ value &= ~SS_PORT_WAKE_INTERRUPT_ENABLE(port);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+ usleep_range(10, 20);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= SS_PORT_WAKEUP_EVENT(port);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static bool tegra210_usb3_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ int index = tegra210_usb3_lane_map(lane);
+ u32 value;
+
+ if (index < 0)
+ return false;
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ if ((value & SS_PORT_WAKE_INTERRUPT_ENABLE(index)) && (value & SS_PORT_WAKEUP_EVENT(index)))
+ return true;
+
+ return false;
+}
+
+static int tegra210_utmi_enable_phy_wake(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ u32 value;
+
+ mutex_lock(&padctl->lock);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= USB2_PORT_WAKEUP_EVENT(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+ usleep_range(10, 20);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static int tegra210_utmi_disable_phy_wake(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ u32 value;
+
+ mutex_lock(&padctl->lock);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ value &= ~ALL_WAKE_EVENTS;
+ value &= ~USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+ usleep_range(10, 20);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= USB2_PORT_WAKEUP_EVENT(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static bool tegra210_utmi_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ u32 value;
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ if ((value & USB2_PORT_WAKE_INTERRUPT_ENABLE(index)) &&
+ (value & USB2_PORT_WAKEUP_EVENT(index)))
+ return true;
+
+ return false;
+}
+
+static int tegra210_hsic_enable_phy_wake(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ u32 value;
+
+ mutex_lock(&padctl->lock);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= USB2_HSIC_PORT_WAKEUP_EVENT(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+ usleep_range(10, 20);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static int tegra210_hsic_disable_phy_wake(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ u32 value;
+
+ mutex_lock(&padctl->lock);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ value &= ~ALL_WAKE_EVENTS;
+ value &= ~USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+ usleep_range(10, 20);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ value &= ~ALL_WAKE_EVENTS;
+ value |= USB2_HSIC_PORT_WAKEUP_EVENT(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+ mutex_unlock(&padctl->lock);
+
+ return 0;
+}
+
+static bool tegra210_hsic_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ u32 value;
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+ if ((value & USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index)) &&
+ (value & USB2_HSIC_PORT_WAKEUP_EVENT(index)))
+ return true;
+
+ return false;
+}
+
+#define padctl_pmc_readl(_priv, _offset) \
+({ \
+ u32 value; \
+ WARN(regmap_read(_priv->regmap, _offset, &value), "read %s failed\n", #_offset);\
+ value; \
+})
+
+#define padctl_pmc_writel(_priv, _value, _offset) \
+ WARN(regmap_write(_priv->regmap, _offset, _value), "write %s failed\n", #_offset)
+
+static int tegra210_pmc_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
+ enum usb_device_speed speed)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
+ unsigned int port = lane->index;
+ u32 value, tctrl, pctrl, rpd_ctrl;
+
+ if (!priv->regmap)
+ return -EOPNOTSUPP;
+
+ if (speed > USB_SPEED_HIGH)
+ return -EINVAL;
+
+ value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
+ tctrl = TCTRL_VALUE(value);
+ pctrl = PCTRL_VALUE(value);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
+ rpd_ctrl = RPD_CTRL_VALUE(value);
+
+ /* ensure sleepwalk logic is disabled */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+ value &= ~UTMIP_MASTER_ENABLE(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+ /* ensure sleepwalk logics are in low power mode */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
+ value |= UTMIP_PWR(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG);
+
+ /* set debounce time */
+ value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
+ value &= ~UTMIP_LINE_DEB_CNT(~0);
+ value |= UTMIP_LINE_DEB_CNT(0x1);
+ padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL);
+
+ /* ensure fake events of sleepwalk logic are desiabled */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_FAKE(port));
+ value &= ~(UTMIP_FAKE_USBOP_VAL(port) | UTMIP_FAKE_USBON_VAL(port) |
+ UTMIP_FAKE_USBOP_EN(port) | UTMIP_FAKE_USBON_EN(port));
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_FAKE(port));
+
+ /* ensure wake events of sleepwalk logic are not latched */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+ value &= ~UTMIP_LINE_WAKEUP_EN(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+
+ /* disable wake event triggers of sleepwalk logic */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+ value &= ~UTMIP_WAKE_VAL(port, ~0);
+ value |= UTMIP_WAKE_VAL_NONE(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+ /* power down the line state detectors of the pad */
+ value = padctl_pmc_readl(priv, PMC_USB_AO);
+ value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
+ padctl_pmc_writel(priv, value, PMC_USB_AO);
+
+ /* save state per speed */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SAVED_STATE(port));
+ value &= ~SPEED(port, ~0);
+
+ switch (speed) {
+ case USB_SPEED_HIGH:
+ value |= UTMI_HS(port);
+ break;
+
+ case USB_SPEED_FULL:
+ value |= UTMI_FS(port);
+ break;
+
+ case USB_SPEED_LOW:
+ value |= UTMI_LS(port);
+ break;
+
+ default:
+ value |= UTMI_RST(port);
+ break;
+ }
+
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SAVED_STATE(port));
+
+ /* enable the trigger of the sleepwalk logic */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
+ value |= UTMIP_LINEVAL_WALK_EN(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
+
+ /*
+ * Reset the walk pointer and clear the alarm of the sleepwalk logic,
+ * as well as capture the configuration of the USB2.0 pad.
+ */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
+ value |= UTMIP_CLR_WALK_PTR(port) | UTMIP_CLR_WAKE_ALARM(port) | UTMIP_CAP_CFG(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
+
+ /* program electrical parameters read from XUSB PADCTL */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_TERM_PAD_CFG);
+ value &= ~(TCTRL_VAL(~0) | PCTRL_VAL(~0));
+ value |= (TCTRL_VAL(tctrl) | PCTRL_VAL(pctrl));
+ padctl_pmc_writel(priv, value, PMC_UTMIP_TERM_PAD_CFG);
+
+ value = padctl_pmc_readl(priv, PMC_UTMIP_PAD_CFGX(port));
+ value &= ~RPD_CTRL_PX(~0);
+ value |= RPD_CTRL_PX(rpd_ctrl);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_PAD_CFGX(port));
+
+ /*
+ * Set up the pull-ups and pull-downs of the signals during the four
+ * stages of sleepwalk. If a device is connected, program sleepwalk
+ * logic to maintain a J and keep driving K upon seeing remote wake.
+ */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_SLEEPWALK_PX(port));
+ value = UTMIP_USBOP_RPD_A | UTMIP_USBOP_RPD_B | UTMIP_USBOP_RPD_C | UTMIP_USBOP_RPD_D;
+ value |= UTMIP_USBON_RPD_A | UTMIP_USBON_RPD_B | UTMIP_USBON_RPD_C | UTMIP_USBON_RPD_D;
+
+ switch (speed) {
+ case USB_SPEED_HIGH:
+ case USB_SPEED_FULL:
+ /* J state: D+/D- = high/low, K state: D+/D- = low/high */
+ value |= UTMIP_HIGHZ_A;
+ value |= UTMIP_AP_A;
+ value |= UTMIP_AN_B | UTMIP_AN_C | UTMIP_AN_D;
+ break;
+
+ case USB_SPEED_LOW:
+ /* J state: D+/D- = low/high, K state: D+/D- = high/low */
+ value |= UTMIP_HIGHZ_A;
+ value |= UTMIP_AN_A;
+ value |= UTMIP_AP_B | UTMIP_AP_C | UTMIP_AP_D;
+ break;
+
+ default:
+ value |= UTMIP_HIGHZ_A | UTMIP_HIGHZ_B | UTMIP_HIGHZ_C | UTMIP_HIGHZ_D;
+ break;
+ }
+
+ padctl_pmc_writel(priv, value, PMC_UTMIP_SLEEPWALK_PX(port));
+
+ /* power up the line state detectors of the pad */
+ value = padctl_pmc_readl(priv, PMC_USB_AO);
+ value &= ~(USBOP_VAL_PD(port) | USBON_VAL_PD(port));
+ padctl_pmc_writel(priv, value, PMC_USB_AO);
+
+ usleep_range(50, 100);
+
+ /* switch the electric control of the USB2.0 pad to PMC */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+ value |= UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) | UTMIP_TCTRL_USE_PMC(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
+ value |= UTMIP_RPD_CTRL_USE_PMC_PX(port) | UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1);
+
+ /* set the wake signaling trigger events */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+ value &= ~UTMIP_WAKE_VAL(port, ~0);
+ value |= UTMIP_WAKE_VAL_ANY(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+ /* enable the wake detection */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+ value |= UTMIP_MASTER_ENABLE(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+ value |= UTMIP_LINE_WAKEUP_EN(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+
+ return 0;
+}
+
+static int tegra210_pmc_utmi_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
+ unsigned int port = lane->index;
+ u32 value;
+
+ if (!priv->regmap)
+ return -EOPNOTSUPP;
+
+ /* disable the wake detection */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+ value &= ~UTMIP_MASTER_ENABLE(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+ value &= ~UTMIP_LINE_WAKEUP_EN(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+
+ /* switch the electric control of the USB2.0 pad to XUSB or USB2 */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+ value &= ~(UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) |
+ UTMIP_TCTRL_USE_PMC(port));
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
+ value &= ~(UTMIP_RPD_CTRL_USE_PMC_PX(port) | UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port));
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1);
+
+ /* disable wake event triggers of sleepwalk logic */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+ value &= ~UTMIP_WAKE_VAL(port, ~0);
+ value |= UTMIP_WAKE_VAL_NONE(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+ /* power down the line state detectors of the port */
+ value = padctl_pmc_readl(priv, PMC_USB_AO);
+ value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
+ padctl_pmc_writel(priv, value, PMC_USB_AO);
+
+ /* clear alarm of the sleepwalk logic */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
+ value |= UTMIP_CLR_WAKE_ALARM(port);
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
+
+ return 0;
+}
+
+static int tegra210_pmc_hsic_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
+ enum usb_device_speed speed)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
+ u32 value;
+
+ if (!priv->regmap)
+ return -EOPNOTSUPP;
+
+ /* ensure sleepwalk logic is disabled */
+ value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
+ value &= ~UHSIC_MASTER_ENABLE;
+ padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
+
+ /* ensure sleepwalk logics are in low power mode */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
+ value |= UHSIC_PWR;
+ padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG);
+
+ /* set debounce time */
+ value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
+ value &= ~UHSIC_LINE_DEB_CNT(~0);
+ value |= UHSIC_LINE_DEB_CNT(0x1);
+ padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL);
+
+ /* ensure fake events of sleepwalk logic are desiabled */
+ value = padctl_pmc_readl(priv, PMC_UHSIC_FAKE);
+ value &= ~(UHSIC_FAKE_STROBE_VAL | UHSIC_FAKE_DATA_VAL |
+ UHSIC_FAKE_STROBE_EN | UHSIC_FAKE_DATA_EN);
+ padctl_pmc_writel(priv, value, PMC_UHSIC_FAKE);
+
+ /* ensure wake events of sleepwalk logic are not latched */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+ value &= ~UHSIC_LINE_WAKEUP_EN;
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+
+ /* disable wake event triggers of sleepwalk logic */
+ value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
+ value &= ~UHSIC_WAKE_VAL(~0);
+ value |= UHSIC_WAKE_VAL_NONE;
+ padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
+
+ /* power down the line state detectors of the port */
+ value = padctl_pmc_readl(priv, PMC_USB_AO);
+ value |= STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD;
+ padctl_pmc_writel(priv, value, PMC_USB_AO);
+
+ /* save state, HSIC always comes up as HS */
+ value = padctl_pmc_readl(priv, PMC_UHSIC_SAVED_STATE);
+ value &= ~UHSIC_MODE(~0);
+ value |= UHSIC_HS;
+ padctl_pmc_writel(priv, value, PMC_UHSIC_SAVED_STATE);
+
+ /* enable the trigger of the sleepwalk logic */
+ value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_CFG);
+ value |= UHSIC_WAKE_WALK_EN | UHSIC_LINEVAL_WALK_EN;
+ padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_CFG);
+
+ /*
+ * Reset the walk pointer and clear the alarm of the sleepwalk logic,
+ * as well as capture the configuration of the USB2.0 port.
+ */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
+ value |= UHSIC_CLR_WALK_PTR | UHSIC_CLR_WAKE_ALARM;
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
+
+ /*
+ * Set up the pull-ups and pull-downs of the signals during the four
+ * stages of sleepwalk. Maintain a HSIC IDLE and keep driving HSIC
+ * RESUME upon remote wake.
+ */
+ value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_P0);
+ value = UHSIC_DATA0_RPD_A | UHSIC_DATA0_RPU_B | UHSIC_DATA0_RPU_C | UHSIC_DATA0_RPU_D |
+ UHSIC_STROBE_RPU_A | UHSIC_STROBE_RPD_B | UHSIC_STROBE_RPD_C | UHSIC_STROBE_RPD_D;
+ padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_P0);
+
+ /* power up the line state detectors of the port */
+ value = padctl_pmc_readl(priv, PMC_USB_AO);
+ value &= ~(STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD);
+ padctl_pmc_writel(priv, value, PMC_USB_AO);
+
+ usleep_range(50, 100);
+
+ /* set the wake signaling trigger events */
+ value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
+ value &= ~UHSIC_WAKE_VAL(~0);
+ value |= UHSIC_WAKE_VAL_SD10;
+ padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
+
+ /* enable the wake detection */
+ value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
+ value |= UHSIC_MASTER_ENABLE;
+ padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
+
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+ value |= UHSIC_LINE_WAKEUP_EN;
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+
+ return 0;
+}
+
+static int tegra210_pmc_hsic_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
+ u32 value;
+
+ if (!priv->regmap)
+ return -EOPNOTSUPP;
+
+ /* disable the wake detection */
+ value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
+ value &= ~UHSIC_MASTER_ENABLE;
+ padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
+
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+ value &= ~UHSIC_LINE_WAKEUP_EN;
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+
+ /* disable wake event triggers of sleepwalk logic */
+ value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
+ value &= ~UHSIC_WAKE_VAL(~0);
+ value |= UHSIC_WAKE_VAL_NONE;
+ padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
+
+ /* power down the line state detectors of the port */
+ value = padctl_pmc_readl(priv, PMC_USB_AO);
+ value |= STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD;
+ padctl_pmc_writel(priv, value, PMC_USB_AO);
+
+ /* clear alarm of the sleepwalk logic */
+ value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
+ value |= UHSIC_CLR_WAKE_ALARM;
+ padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
+
+ return 0;
+}
+
static int tegra210_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl,
unsigned int index, bool enable)
{
@@ -911,14 +1788,36 @@ static void tegra210_usb2_lane_remove(struct tegra_xusb_lane *lane)
static const struct tegra_xusb_lane_ops tegra210_usb2_lane_ops = {
.probe = tegra210_usb2_lane_probe,
.remove = tegra210_usb2_lane_remove,
+ .enable_phy_sleepwalk = tegra210_pmc_utmi_enable_phy_sleepwalk,
+ .disable_phy_sleepwalk = tegra210_pmc_utmi_disable_phy_sleepwalk,
+ .enable_phy_wake = tegra210_utmi_enable_phy_wake,
+ .disable_phy_wake = tegra210_utmi_disable_phy_wake,
+ .remote_wake_detected = tegra210_utmi_phy_remote_wake_detected,
};
static int tegra210_usb2_phy_init(struct phy *phy)
{
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ unsigned int index = lane->index;
+ struct tegra_xusb_usb2_port *port;
+ int err;
u32 value;
+ port = tegra_xusb_find_usb2_port(padctl, index);
+ if (!port) {
+ dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
+ return -ENODEV;
+ }
+
+ if (port->supply && port->mode == USB_DR_MODE_HOST) {
+ err = regulator_enable(port->supply);
+ if (err)
+ return err;
+ }
+
+ mutex_lock(&padctl->lock);
+
value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
value &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK <<
XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT);
@@ -926,14 +1825,31 @@ static int tegra210_usb2_phy_init(struct phy *phy)
XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
- return tegra210_xusb_padctl_enable(padctl);
+ mutex_unlock(&padctl->lock);
+
+ return 0;
}
static int tegra210_usb2_phy_exit(struct phy *phy)
{
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ struct tegra_xusb_usb2_port *port;
+ int err;
- return tegra210_xusb_padctl_disable(lane->pad->padctl);
+ port = tegra_xusb_find_usb2_port(padctl, lane->index);
+ if (!port) {
+ dev_err(&phy->dev, "no port found for USB2 lane %u\n", lane->index);
+ return -ENODEV;
+ }
+
+ if (port->supply && port->mode == USB_DR_MODE_HOST) {
+ err = regulator_disable(port->supply);
+ if (err)
+ return err;
+ }
+
+ return 0;
}
static int tegra210_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
@@ -1053,6 +1969,8 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
priv = to_tegra210_xusb_padctl(padctl);
+ mutex_lock(&padctl->lock);
+
if (port->usb3_port_fake != -1) {
value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(
@@ -1146,14 +2064,6 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
padctl_writel(padctl, value,
XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
- if (port->supply && port->mode == USB_DR_MODE_HOST) {
- err = regulator_enable(port->supply);
- if (err)
- return err;
- }
-
- mutex_lock(&padctl->lock);
-
if (pad->enable > 0) {
pad->enable++;
mutex_unlock(&padctl->lock);
@@ -1162,7 +2072,7 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
err = clk_prepare_enable(pad->clk);
if (err)
- goto disable_regulator;
+ goto out;
value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK <<
@@ -1194,8 +2104,7 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
return 0;
-disable_regulator:
- regulator_disable(port->supply);
+out:
mutex_unlock(&padctl->lock);
return err;
}
@@ -1254,7 +2163,6 @@ static int tegra210_usb2_phy_power_off(struct phy *phy)
padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
out:
- regulator_disable(port->supply);
mutex_unlock(&padctl->lock);
return 0;
}
@@ -1376,6 +2284,11 @@ static void tegra210_hsic_lane_remove(struct tegra_xusb_lane *lane)
static const struct tegra_xusb_lane_ops tegra210_hsic_lane_ops = {
.probe = tegra210_hsic_lane_probe,
.remove = tegra210_hsic_lane_remove,
+ .enable_phy_sleepwalk = tegra210_pmc_hsic_enable_phy_sleepwalk,
+ .disable_phy_sleepwalk = tegra210_pmc_hsic_disable_phy_sleepwalk,
+ .enable_phy_wake = tegra210_hsic_enable_phy_wake,
+ .disable_phy_wake = tegra210_hsic_disable_phy_wake,
+ .remote_wake_detected = tegra210_hsic_phy_remote_wake_detected,
};
static int tegra210_hsic_phy_init(struct phy *phy)
@@ -1391,14 +2304,12 @@ static int tegra210_hsic_phy_init(struct phy *phy)
XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
- return tegra210_xusb_padctl_enable(padctl);
+ return 0;
}
static int tegra210_hsic_phy_exit(struct phy *phy)
{
- struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
-
- return tegra210_xusb_padctl_disable(lane->pad->padctl);
+ return 0;
}
static int tegra210_hsic_phy_power_on(struct phy *phy)
@@ -1582,6 +2493,55 @@ static const struct tegra_xusb_pad_soc tegra210_hsic_pad = {
.ops = &tegra210_hsic_ops,
};
+static void tegra210_uphy_lane_iddq_enable(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ u32 value;
+
+ value = padctl_readl(padctl, lane->soc->regs.misc_ctl2);
+ value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD;
+ value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD;
+ value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD;
+ value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD;
+ value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ;
+ value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK;
+ value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL;
+ value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ;
+ value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK;
+ value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL;
+ padctl_writel(padctl, value, lane->soc->regs.misc_ctl2);
+}
+
+static void tegra210_uphy_lane_iddq_disable(struct tegra_xusb_lane *lane)
+{
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ u32 value;
+
+ value = padctl_readl(padctl, lane->soc->regs.misc_ctl2);
+ value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD;
+ value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD;
+ value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD;
+ value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD;
+ value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ;
+ value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK;
+ value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL;
+ value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ;
+ value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK;
+ value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL;
+ padctl_writel(padctl, value, lane->soc->regs.misc_ctl2);
+}
+
+#define TEGRA210_UPHY_LANE(_name, _offset, _shift, _mask, _type, _misc) \
+ { \
+ .name = _name, \
+ .offset = _offset, \
+ .shift = _shift, \
+ .mask = _mask, \
+ .num_funcs = ARRAY_SIZE(tegra210_##_type##_functions), \
+ .funcs = tegra210_##_type##_functions, \
+ .regs.misc_ctl2 = _misc, \
+ }
+
static const char *tegra210_pcie_functions[] = {
"pcie-x1",
"usb3-ss",
@@ -1590,15 +2550,137 @@ static const char *tegra210_pcie_functions[] = {
};
static const struct tegra_xusb_lane_soc tegra210_pcie_lanes[] = {
- TEGRA210_LANE("pcie-0", 0x028, 12, 0x3, pcie),
- TEGRA210_LANE("pcie-1", 0x028, 14, 0x3, pcie),
- TEGRA210_LANE("pcie-2", 0x028, 16, 0x3, pcie),
- TEGRA210_LANE("pcie-3", 0x028, 18, 0x3, pcie),
- TEGRA210_LANE("pcie-4", 0x028, 20, 0x3, pcie),
- TEGRA210_LANE("pcie-5", 0x028, 22, 0x3, pcie),
- TEGRA210_LANE("pcie-6", 0x028, 24, 0x3, pcie),
+ TEGRA210_UPHY_LANE("pcie-0", 0x028, 12, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)),
+ TEGRA210_UPHY_LANE("pcie-1", 0x028, 14, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(1)),
+ TEGRA210_UPHY_LANE("pcie-2", 0x028, 16, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(2)),
+ TEGRA210_UPHY_LANE("pcie-3", 0x028, 18, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(3)),
+ TEGRA210_UPHY_LANE("pcie-4", 0x028, 20, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(4)),
+ TEGRA210_UPHY_LANE("pcie-5", 0x028, 22, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(5)),
+ TEGRA210_UPHY_LANE("pcie-6", 0x028, 24, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(6)),
};
+static struct tegra_xusb_usb3_port *
+tegra210_lane_to_usb3_port(struct tegra_xusb_lane *lane)
+{
+ int port;
+
+ if (!lane || !lane->pad || !lane->pad->padctl)
+ return NULL;
+
+ port = tegra210_usb3_lane_map(lane);
+ if (port < 0)
+ return NULL;
+
+ return tegra_xusb_find_usb3_port(lane->pad->padctl, port);
+}
+
+static int tegra210_usb3_phy_power_on(struct phy *phy)
+{
+ struct device *dev = &phy->dev;
+ struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ struct tegra_xusb_usb3_port *usb3 = tegra210_lane_to_usb3_port(lane);
+ unsigned int index;
+ u32 value;
+
+ if (!usb3) {
+ dev_err(dev, "no USB3 port found for lane %u\n", lane->index);
+ return -ENODEV;
+ }
+
+ index = usb3->base.index;
+
+ value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
+
+ if (!usb3->internal)
+ value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index);
+ else
+ value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index);
+
+ value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(index);
+ value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(index, usb3->port);
+ padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index));
+ value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK <<
+ XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT);
+ value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL <<
+ XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT;
+ padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index));
+
+ value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index));
+ value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK <<
+ XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT);
+ value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL <<
+ XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT;
+ padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index));
+
+ padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL,
+ XUSB_PADCTL_UPHY_USB3_PADX_ECTL3(index));
+
+ value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index));
+ value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK <<
+ XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT);
+ value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL <<
+ XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT;
+ padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index));
+
+ padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL,
+ XUSB_PADCTL_UPHY_USB3_PADX_ECTL6(index));
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
+ value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+
+ usleep_range(100, 200);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
+ value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+
+ usleep_range(100, 200);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
+ value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+
+ return 0;
+}
+
+static int tegra210_usb3_phy_power_off(struct phy *phy)
+{
+ struct device *dev = &phy->dev;
+ struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ struct tegra_xusb_usb3_port *usb3 = tegra210_lane_to_usb3_port(lane);
+ unsigned int index;
+ u32 value;
+
+ if (!usb3) {
+ dev_err(dev, "no USB3 port found for lane %u\n", lane->index);
+ return -ENODEV;
+ }
+
+ index = usb3->base.index;
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
+ value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+
+ usleep_range(100, 200);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
+ value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+
+ usleep_range(250, 350);
+
+ value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
+ value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index);
+ padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+
+ return 0;
+}
static struct tegra_xusb_lane *
tegra210_pcie_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
unsigned int index)
@@ -1635,40 +2717,40 @@ static void tegra210_pcie_lane_remove(struct tegra_xusb_lane *lane)
static const struct tegra_xusb_lane_ops tegra210_pcie_lane_ops = {
.probe = tegra210_pcie_lane_probe,
.remove = tegra210_pcie_lane_remove,
+ .iddq_enable = tegra210_uphy_lane_iddq_enable,
+ .iddq_disable = tegra210_uphy_lane_iddq_disable,
+ .enable_phy_sleepwalk = tegra210_usb3_enable_phy_sleepwalk,
+ .disable_phy_sleepwalk = tegra210_usb3_disable_phy_sleepwalk,
+ .enable_phy_wake = tegra210_usb3_enable_phy_wake,
+ .disable_phy_wake = tegra210_usb3_disable_phy_wake,
+ .remote_wake_detected = tegra210_usb3_phy_remote_wake_detected,
};
static int tegra210_pcie_phy_init(struct phy *phy)
{
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
- return tegra210_xusb_padctl_enable(lane->pad->padctl);
-}
+ mutex_lock(&padctl->lock);
-static int tegra210_pcie_phy_exit(struct phy *phy)
-{
- struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+ tegra210_uphy_init(padctl);
+
+ mutex_unlock(&padctl->lock);
- return tegra210_xusb_padctl_disable(lane->pad->padctl);
+ return 0;
}
static int tegra210_pcie_phy_power_on(struct phy *phy)
{
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
- u32 value;
- int err;
+ int err = 0;
mutex_lock(&padctl->lock);
- err = tegra210_pex_uphy_enable(padctl);
- if (err < 0)
- goto unlock;
-
- value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
- value |= XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->index);
- padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
+ if (tegra_xusb_lane_check(lane, "usb3-ss"))
+ err = tegra210_usb3_phy_power_on(phy);
-unlock:
mutex_unlock(&padctl->lock);
return err;
}
@@ -1677,20 +2759,19 @@ static int tegra210_pcie_phy_power_off(struct phy *phy)
{
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
- u32 value;
+ int err = 0;
- value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
- value &= ~XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->index);
- padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
+ mutex_lock(&padctl->lock);
- tegra210_pex_uphy_disable(padctl);
+ if (tegra_xusb_lane_check(lane, "usb3-ss"))
+ err = tegra210_usb3_phy_power_off(phy);
- return 0;
+ mutex_unlock(&padctl->lock);
+ return err;
}
static const struct phy_ops tegra210_pcie_phy_ops = {
.init = tegra210_pcie_phy_init,
- .exit = tegra210_pcie_phy_exit,
.power_on = tegra210_pcie_phy_power_on,
.power_off = tegra210_pcie_phy_power_off,
.owner = THIS_MODULE,
@@ -1767,7 +2848,7 @@ static const struct tegra_xusb_pad_soc tegra210_pcie_pad = {
};
static const struct tegra_xusb_lane_soc tegra210_sata_lanes[] = {
- TEGRA210_LANE("sata-0", 0x028, 30, 0x3, pcie),
+ TEGRA210_UPHY_LANE("sata-0", 0x028, 30, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2),
};
static struct tegra_xusb_lane *
@@ -1806,40 +2887,39 @@ static void tegra210_sata_lane_remove(struct tegra_xusb_lane *lane)
static const struct tegra_xusb_lane_ops tegra210_sata_lane_ops = {
.probe = tegra210_sata_lane_probe,
.remove = tegra210_sata_lane_remove,
+ .iddq_enable = tegra210_uphy_lane_iddq_enable,
+ .iddq_disable = tegra210_uphy_lane_iddq_disable,
+ .enable_phy_sleepwalk = tegra210_usb3_enable_phy_sleepwalk,
+ .disable_phy_sleepwalk = tegra210_usb3_disable_phy_sleepwalk,
+ .enable_phy_wake = tegra210_usb3_enable_phy_wake,
+ .disable_phy_wake = tegra210_usb3_disable_phy_wake,
+ .remote_wake_detected = tegra210_usb3_phy_remote_wake_detected,
};
static int tegra210_sata_phy_init(struct phy *phy)
{
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+ struct tegra_xusb_padctl *padctl = lane->pad->padctl;
- return tegra210_xusb_padctl_enable(lane->pad->padctl);
-}
+ mutex_lock(&padctl->lock);
-static int tegra210_sata_phy_exit(struct phy *phy)
-{
- struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+ tegra210_uphy_init(padctl);
- return tegra210_xusb_padctl_disable(lane->pad->padctl);
+ mutex_unlock(&padctl->lock);
+ return 0;
}
static int tegra210_sata_phy_power_on(struct phy *phy)
{
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
- u32 value;
- int err;
+ int err = 0;
mutex_lock(&padctl->lock);
- err = tegra210_sata_uphy_enable(padctl, false);
- if (err < 0)
- goto unlock;
-
- value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
- value |= XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->index);
- padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
+ if (tegra_xusb_lane_check(lane, "usb3-ss"))
+ err = tegra210_usb3_phy_power_on(phy);
-unlock:
mutex_unlock(&padctl->lock);
return err;
}
@@ -1848,20 +2928,19 @@ static int tegra210_sata_phy_power_off(struct phy *phy)
{
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
- u32 value;
+ int err = 0;
- value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
- value &= ~XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->index);
- padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
+ mutex_lock(&padctl->lock);
- tegra210_sata_uphy_disable(lane->pad->padctl);
+ if (tegra_xusb_lane_check(lane, "usb3-ss"))
+ err = tegra210_usb3_phy_power_off(phy);
- return 0;
+ mutex_unlock(&padctl->lock);
+ return err;
}
static const struct phy_ops tegra210_sata_phy_ops = {
.init = tegra210_sata_phy_init,
- .exit = tegra210_sata_phy_exit,
.power_on = tegra210_sata_phy_power_on,
.power_off = tegra210_sata_phy_power_off,
.owner = THIS_MODULE,
@@ -1984,137 +3063,13 @@ static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = {
static int tegra210_usb3_port_enable(struct tegra_xusb_port *port)
{
- struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
- struct tegra_xusb_padctl *padctl = port->padctl;
- struct tegra_xusb_lane *lane = usb3->base.lane;
- unsigned int index = port->index;
- u32 value;
- int err;
-
- value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
-
- if (!usb3->internal)
- value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index);
- else
- value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index);
-
- value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(index);
- value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(index, usb3->port);
- padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
-
- /*
- * TODO: move this code into the PCIe/SATA PHY ->power_on() callbacks
- * and conditionalize based on mux function? This seems to work, but
- * might not be the exact proper sequence.
- */
- err = regulator_enable(usb3->supply);
- if (err < 0)
- return err;
-
- value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index));
- value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK <<
- XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT);
- value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL <<
- XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT;
- padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index));
-
- value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index));
- value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK <<
- XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT);
- value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL <<
- XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT;
- padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index));
-
- padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL,
- XUSB_PADCTL_UPHY_USB3_PADX_ECTL3(index));
-
- value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index));
- value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK <<
- XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT);
- value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL <<
- XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT;
- padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index));
-
- padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL,
- XUSB_PADCTL_UPHY_USB3_PADX_ECTL6(index));
-
- if (lane->pad == padctl->sata)
- err = tegra210_sata_uphy_enable(padctl, true);
- else
- err = tegra210_pex_uphy_enable(padctl);
-
- if (err) {
- dev_err(&port->dev, "%s: failed to enable UPHY: %d\n",
- __func__, err);
- return err;
- }
-
- value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
- value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index);
- padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
-
- usleep_range(100, 200);
-
- value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
- value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index);
- padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
-
- usleep_range(100, 200);
-
- value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
- value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index);
- padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
-
return 0;
}
static void tegra210_usb3_port_disable(struct tegra_xusb_port *port)
{
- struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
- struct tegra_xusb_padctl *padctl = port->padctl;
- struct tegra_xusb_lane *lane = port->lane;
- unsigned int index = port->index;
- u32 value;
-
- value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
- value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index);
- padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
-
- usleep_range(100, 200);
-
- value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
- value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index);
- padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
-
- usleep_range(250, 350);
-
- value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
- value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index);
- padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
-
- if (lane->pad == padctl->sata)
- tegra210_sata_uphy_disable(padctl);
- else
- tegra210_pex_uphy_disable(padctl);
-
- regulator_disable(usb3->supply);
-
- value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
- value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(index);
- value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(index, 0x7);
- padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
}
-static const struct tegra_xusb_lane_map tegra210_usb3_map[] = {
- { 0, "pcie", 6 },
- { 1, "pcie", 5 },
- { 2, "pcie", 0 },
- { 2, "pcie", 3 },
- { 3, "pcie", 4 },
- { 3, "pcie", 4 },
- { 0, NULL, 0 }
-};
-
static struct tegra_xusb_lane *
tegra210_usb3_port_map(struct tegra_xusb_port *port)
{
@@ -2188,6 +3143,8 @@ tegra210_xusb_padctl_probe(struct device *dev,
const struct tegra_xusb_padctl_soc *soc)
{
struct tegra210_xusb_padctl *padctl;
+ struct platform_device *pdev;
+ struct device_node *np;
int err;
padctl = devm_kzalloc(dev, sizeof(*padctl), GFP_KERNEL);
@@ -2201,6 +3158,26 @@ tegra210_xusb_padctl_probe(struct device *dev,
if (err < 0)
return ERR_PTR(err);
+ np = of_parse_phandle(dev->of_node, "nvidia,pmc", 0);
+ if (!np) {
+ dev_warn(dev, "nvidia,pmc property is missing\n");
+ goto out;
+ }
+
+ pdev = of_find_device_by_node(np);
+ if (!pdev) {
+ dev_warn(dev, "PMC device is not available\n");
+ goto out;
+ }
+
+ if (!platform_get_drvdata(pdev))
+ return ERR_PTR(-EPROBE_DEFER);
+
+ padctl->regmap = dev_get_regmap(&pdev->dev, "usb_sleepwalk");
+ if (!padctl->regmap)
+ dev_info(dev, "failed to find PMC regmap\n");
+
+out:
return &padctl->base;
}
@@ -2208,9 +3185,75 @@ static void tegra210_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
{
}
+static void tegra210_xusb_padctl_save(struct tegra_xusb_padctl *padctl)
+{
+ struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
+
+ priv->context.usb2_pad_mux =
+ padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
+ priv->context.usb2_port_cap =
+ padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
+ priv->context.ss_port_map =
+ padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
+ priv->context.usb3_pad_mux =
+ padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
+}
+
+static void tegra210_xusb_padctl_restore(struct tegra_xusb_padctl *padctl)
+{
+ struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
+ struct tegra_xusb_lane *lane;
+
+ padctl_writel(padctl, priv->context.usb2_pad_mux,
+ XUSB_PADCTL_USB2_PAD_MUX);
+ padctl_writel(padctl, priv->context.usb2_port_cap,
+ XUSB_PADCTL_USB2_PORT_CAP);
+ padctl_writel(padctl, priv->context.ss_port_map,
+ XUSB_PADCTL_SS_PORT_MAP);
+
+ list_for_each_entry(lane, &padctl->lanes, list) {
+ if (lane->pad->ops->iddq_enable)
+ tegra210_uphy_lane_iddq_enable(lane);
+ }
+
+ padctl_writel(padctl, priv->context.usb3_pad_mux,
+ XUSB_PADCTL_USB3_PAD_MUX);
+
+ list_for_each_entry(lane, &padctl->lanes, list) {
+ if (lane->pad->ops->iddq_disable)
+ tegra210_uphy_lane_iddq_disable(lane);
+ }
+}
+
+static int tegra210_xusb_padctl_suspend_noirq(struct tegra_xusb_padctl *padctl)
+{
+ mutex_lock(&padctl->lock);
+
+ tegra210_uphy_deinit(padctl);
+
+ tegra210_xusb_padctl_save(padctl);
+
+ mutex_unlock(&padctl->lock);
+ return 0;
+}
+
+static int tegra210_xusb_padctl_resume_noirq(struct tegra_xusb_padctl *padctl)
+{
+ mutex_lock(&padctl->lock);
+
+ tegra210_xusb_padctl_restore(padctl);
+
+ tegra210_uphy_init(padctl);
+
+ mutex_unlock(&padctl->lock);
+ return 0;
+}
+
static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = {
.probe = tegra210_xusb_padctl_probe,
.remove = tegra210_xusb_padctl_remove,
+ .suspend_noirq = tegra210_xusb_padctl_suspend_noirq,
+ .resume_noirq = tegra210_xusb_padctl_resume_noirq,
.usb3_set_lfps_detect = tegra210_usb3_set_lfps_detect,
.hsic_set_idle = tegra210_hsic_set_idle,
.vbus_override = tegra210_xusb_padctl_vbus_override,
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
index 941006f503e4..0aadac678191 100644
--- a/drivers/phy/tegra/xusb.c
+++ b/drivers/phy/tegra/xusb.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2014-2020, NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/delay.h>
@@ -321,11 +321,17 @@ static void tegra_xusb_lane_program(struct tegra_xusb_lane *lane)
if (soc->num_funcs < 2)
return;
+ if (lane->pad->ops->iddq_enable)
+ lane->pad->ops->iddq_enable(lane);
+
/* choose function */
value = padctl_readl(padctl, soc->offset);
value &= ~(soc->mask << soc->shift);
value |= lane->function << soc->shift;
padctl_writel(padctl, value, soc->offset);
+
+ if (lane->pad->ops->iddq_disable)
+ lane->pad->ops->iddq_disable(lane);
}
static void tegra_xusb_pad_program(struct tegra_xusb_pad *pad)
@@ -376,7 +382,7 @@ static int tegra_xusb_setup_pads(struct tegra_xusb_padctl *padctl)
return 0;
}
-static bool tegra_xusb_lane_check(struct tegra_xusb_lane *lane,
+bool tegra_xusb_lane_check(struct tegra_xusb_lane *lane,
const char *function)
{
const char *func = lane->soc->funcs[lane->function];
@@ -1267,10 +1273,36 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev)
return err;
}
+static int tegra_xusb_padctl_suspend_noirq(struct device *dev)
+{
+ struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev);
+
+ if (padctl->soc && padctl->soc->ops && padctl->soc->ops->suspend_noirq)
+ return padctl->soc->ops->suspend_noirq(padctl);
+
+ return 0;
+}
+
+static int tegra_xusb_padctl_resume_noirq(struct device *dev)
+{
+ struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev);
+
+ if (padctl->soc && padctl->soc->ops && padctl->soc->ops->resume_noirq)
+ return padctl->soc->ops->resume_noirq(padctl);
+
+ return 0;
+}
+
+static const struct dev_pm_ops tegra_xusb_padctl_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_xusb_padctl_suspend_noirq,
+ tegra_xusb_padctl_resume_noirq)
+};
+
static struct platform_driver tegra_xusb_padctl_driver = {
.driver = {
.name = "tegra-xusb-padctl",
.of_match_table = tegra_xusb_padctl_of_match,
+ .pm = &tegra_xusb_padctl_pm_ops,
},
.probe = tegra_xusb_padctl_probe,
.remove = tegra_xusb_padctl_remove,
@@ -1337,6 +1369,62 @@ int tegra_xusb_padctl_hsic_set_idle(struct tegra_xusb_padctl *padctl,
}
EXPORT_SYMBOL_GPL(tegra_xusb_padctl_hsic_set_idle);
+int tegra_xusb_padctl_enable_phy_sleepwalk(struct tegra_xusb_padctl *padctl, struct phy *phy,
+ enum usb_device_speed speed)
+{
+ struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+
+ if (lane->pad->ops->enable_phy_sleepwalk)
+ return lane->pad->ops->enable_phy_sleepwalk(lane, speed);
+
+ return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(tegra_xusb_padctl_enable_phy_sleepwalk);
+
+int tegra_xusb_padctl_disable_phy_sleepwalk(struct tegra_xusb_padctl *padctl, struct phy *phy)
+{
+ struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+
+ if (lane->pad->ops->disable_phy_sleepwalk)
+ return lane->pad->ops->disable_phy_sleepwalk(lane);
+
+ return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(tegra_xusb_padctl_disable_phy_sleepwalk);
+
+int tegra_xusb_padctl_enable_phy_wake(struct tegra_xusb_padctl *padctl, struct phy *phy)
+{
+ struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+
+ if (lane->pad->ops->enable_phy_wake)
+ return lane->pad->ops->enable_phy_wake(lane);
+
+ return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(tegra_xusb_padctl_enable_phy_wake);
+
+int tegra_xusb_padctl_disable_phy_wake(struct tegra_xusb_padctl *padctl, struct phy *phy)
+{
+ struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+
+ if (lane->pad->ops->disable_phy_wake)
+ return lane->pad->ops->disable_phy_wake(lane);
+
+ return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(tegra_xusb_padctl_disable_phy_wake);
+
+bool tegra_xusb_padctl_remote_wake_detected(struct tegra_xusb_padctl *padctl, struct phy *phy)
+{
+ struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+
+ if (lane->pad->ops->remote_wake_detected)
+ return lane->pad->ops->remote_wake_detected(lane);
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(tegra_xusb_padctl_remote_wake_detected);
+
int tegra_xusb_padctl_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl,
unsigned int port, bool enable)
{
diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h
index ea35af747066..034f7a2c28d6 100644
--- a/drivers/phy/tegra/xusb.h
+++ b/drivers/phy/tegra/xusb.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2014-2020, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2015, Google Inc.
*/
@@ -11,6 +11,7 @@
#include <linux/mutex.h>
#include <linux/workqueue.h>
+#include <linux/usb/ch9.h>
#include <linux/usb/otg.h>
#include <linux/usb/role.h>
@@ -35,6 +36,10 @@ struct tegra_xusb_lane_soc {
const char * const *funcs;
unsigned int num_funcs;
+
+ struct {
+ unsigned int misc_ctl2;
+ } regs;
};
struct tegra_xusb_lane {
@@ -126,8 +131,17 @@ struct tegra_xusb_lane_ops {
struct device_node *np,
unsigned int index);
void (*remove)(struct tegra_xusb_lane *lane);
+ void (*iddq_enable)(struct tegra_xusb_lane *lane);
+ void (*iddq_disable)(struct tegra_xusb_lane *lane);
+ int (*enable_phy_sleepwalk)(struct tegra_xusb_lane *lane, enum usb_device_speed speed);
+ int (*disable_phy_sleepwalk)(struct tegra_xusb_lane *lane);
+ int (*enable_phy_wake)(struct tegra_xusb_lane *lane);
+ int (*disable_phy_wake)(struct tegra_xusb_lane *lane);
+ bool (*remote_wake_detected)(struct tegra_xusb_lane *lane);
};
+bool tegra_xusb_lane_check(struct tegra_xusb_lane *lane, const char *function);
+
/*
* pads
*/
@@ -230,7 +244,7 @@ struct tegra_xusb_pcie_pad {
struct reset_control *rst;
struct clk *pll;
- unsigned int enable;
+ bool enable;
};
static inline struct tegra_xusb_pcie_pad *
@@ -245,7 +259,7 @@ struct tegra_xusb_sata_pad {
struct reset_control *rst;
struct clk *pll;
- unsigned int enable;
+ bool enable;
};
static inline struct tegra_xusb_sata_pad *
@@ -388,6 +402,8 @@ struct tegra_xusb_padctl_ops {
const struct tegra_xusb_padctl_soc *soc);
void (*remove)(struct tegra_xusb_padctl *padctl);
+ int (*suspend_noirq)(struct tegra_xusb_padctl *padctl);
+ int (*resume_noirq)(struct tegra_xusb_padctl *padctl);
int (*usb3_save_context)(struct tegra_xusb_padctl *padctl,
unsigned int index);
int (*hsic_set_idle)(struct tegra_xusb_padctl *padctl,
diff --git a/drivers/phy/ti/phy-dm816x-usb.c b/drivers/phy/ti/phy-dm816x-usb.c
index 57adc08a89b2..9fe6ea6fdae5 100644
--- a/drivers/phy/ti/phy-dm816x-usb.c
+++ b/drivers/phy/ti/phy-dm816x-usb.c
@@ -242,19 +242,28 @@ static int dm816x_usb_phy_probe(struct platform_device *pdev)
pm_runtime_enable(phy->dev);
generic_phy = devm_phy_create(phy->dev, NULL, &ops);
- if (IS_ERR(generic_phy))
- return PTR_ERR(generic_phy);
+ if (IS_ERR(generic_phy)) {
+ error = PTR_ERR(generic_phy);
+ goto clk_unprepare;
+ }
phy_set_drvdata(generic_phy, phy);
phy_provider = devm_of_phy_provider_register(phy->dev,
of_phy_simple_xlate);
- if (IS_ERR(phy_provider))
- return PTR_ERR(phy_provider);
+ if (IS_ERR(phy_provider)) {
+ error = PTR_ERR(phy_provider);
+ goto clk_unprepare;
+ }
usb_add_phy_dev(&phy->phy);
return 0;
+
+clk_unprepare:
+ pm_runtime_disable(phy->dev);
+ clk_unprepare(phy->refclk);
+ return error;
}
static int dm816x_usb_phy_remove(struct platform_device *pdev)
diff --git a/drivers/phy/ti/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c
index 812e5409d359..5771e2486a3b 100644
--- a/drivers/phy/ti/phy-twl4030-usb.c
+++ b/drivers/phy/ti/phy-twl4030-usb.c
@@ -544,8 +544,8 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
return 0;
}
-static ssize_t twl4030_usb_vbus_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t vbus_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct twl4030_usb *twl = dev_get_drvdata(dev);
int ret = -EINVAL;
@@ -557,7 +557,7 @@ static ssize_t twl4030_usb_vbus_show(struct device *dev,
return ret;
}
-static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL);
+static DEVICE_ATTR_RO(vbus);
static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
{
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index c2c7e7963ed0..f38f12801f18 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -336,6 +336,8 @@ config PINCTRL_ZYNQMP
Configuration can include the mux function to select on those
pin(s)/group(s), and various pin configuration parameters
such as pull-up, slew rate, etc.
+ This driver can also be built as a module. If so, the module
+ will be called pinctrl-zynqmp.
config PINCTRL_INGENIC
bool "Pinctrl driver for the Ingenic JZ47xx SoCs"
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
index eeab093a7815..a3fa03bcd9a3 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
@@ -46,8 +46,10 @@
#define SCU620 0x620 /* Disable GPIO Internal Pull-Down #4 */
#define SCU634 0x634 /* Disable GPIO Internal Pull-Down #5 */
#define SCU638 0x638 /* Disable GPIO Internal Pull-Down #6 */
+#define SCU690 0x690 /* Multi-function Pin Control #24 */
#define SCU694 0x694 /* Multi-function Pin Control #25 */
#define SCU69C 0x69C /* Multi-function Pin Control #27 */
+#define SCU6D0 0x6D0 /* Multi-function Pin Control #29 */
#define SCUC20 0xC20 /* PCIE configuration Setting Control */
#define ASPEED_G6_NR_PINS 256
@@ -81,13 +83,17 @@ FUNC_GROUP_DECL(I2C12, L26, K24);
#define K26 4
SIG_EXPR_LIST_DECL_SESG(K26, MACLINK1, MACLINK1, SIG_DESC_SET(SCU410, 4));
SIG_EXPR_LIST_DECL_SESG(K26, SCL13, I2C13, SIG_DESC_SET(SCU4B0, 4));
-PIN_DECL_2(K26, GPIOA4, MACLINK1, SCL13);
+SIG_EXPR_LIST_DECL_SESG(K26, SGPS2CK, SGPS2, SIG_DESC_SET(SCU690, 4));
+SIG_EXPR_LIST_DECL_SESG(K26, SGPM2CLK, SGPM2, SIG_DESC_SET(SCU6D0, 4));
+PIN_DECL_4(K26, GPIOA4, MACLINK1, SCL13, SGPS2CK, SGPM2CLK);
FUNC_GROUP_DECL(MACLINK1, K26);
#define L24 5
SIG_EXPR_LIST_DECL_SESG(L24, MACLINK2, MACLINK2, SIG_DESC_SET(SCU410, 5));
SIG_EXPR_LIST_DECL_SESG(L24, SDA13, I2C13, SIG_DESC_SET(SCU4B0, 5));
-PIN_DECL_2(L24, GPIOA5, MACLINK2, SDA13);
+SIG_EXPR_LIST_DECL_SESG(L24, SGPS2LD, SGPS2, SIG_DESC_SET(SCU690, 5));
+SIG_EXPR_LIST_DECL_SESG(L24, SGPM2LD, SGPM2, SIG_DESC_SET(SCU6D0, 5));
+PIN_DECL_4(L24, GPIOA5, MACLINK2, SDA13, SGPS2LD, SGPM2LD);
FUNC_GROUP_DECL(MACLINK2, L24);
FUNC_GROUP_DECL(I2C13, K26, L24);
@@ -95,16 +101,22 @@ FUNC_GROUP_DECL(I2C13, K26, L24);
#define L23 6
SIG_EXPR_LIST_DECL_SESG(L23, MACLINK3, MACLINK3, SIG_DESC_SET(SCU410, 6));
SIG_EXPR_LIST_DECL_SESG(L23, SCL14, I2C14, SIG_DESC_SET(SCU4B0, 6));
-PIN_DECL_2(L23, GPIOA6, MACLINK3, SCL14);
+SIG_EXPR_LIST_DECL_SESG(L23, SGPS2O, SGPS2, SIG_DESC_SET(SCU690, 6));
+SIG_EXPR_LIST_DECL_SESG(L23, SGPM2O, SGPM2, SIG_DESC_SET(SCU6D0, 6));
+PIN_DECL_4(L23, GPIOA6, MACLINK3, SCL14, SGPS2O, SGPM2O);
FUNC_GROUP_DECL(MACLINK3, L23);
#define K25 7
SIG_EXPR_LIST_DECL_SESG(K25, MACLINK4, MACLINK4, SIG_DESC_SET(SCU410, 7));
SIG_EXPR_LIST_DECL_SESG(K25, SDA14, I2C14, SIG_DESC_SET(SCU4B0, 7));
-PIN_DECL_2(K25, GPIOA7, MACLINK4, SDA14);
+SIG_EXPR_LIST_DECL_SESG(K25, SGPS2I, SGPS2, SIG_DESC_SET(SCU690, 7));
+SIG_EXPR_LIST_DECL_SESG(K25, SGPM2I, SGPM2, SIG_DESC_SET(SCU6D0, 7));
+PIN_DECL_4(K25, GPIOA7, MACLINK4, SDA14, SGPS2I, SGPM2I);
FUNC_GROUP_DECL(MACLINK4, K25);
FUNC_GROUP_DECL(I2C14, L23, K25);
+FUNC_GROUP_DECL(SGPM2, K26, L24, L23, K25);
+FUNC_GROUP_DECL(SGPS2, K26, L24, L23, K25);
#define J26 8
SIG_EXPR_LIST_DECL_SESG(J26, SALT1, SALT1, SIG_DESC_SET(SCU410, 8));
@@ -2060,7 +2072,9 @@ static const struct aspeed_pin_group aspeed_g6_groups[] = {
ASPEED_PINCTRL_GROUP(EMMCG4),
ASPEED_PINCTRL_GROUP(EMMCG8),
ASPEED_PINCTRL_GROUP(SGPM1),
+ ASPEED_PINCTRL_GROUP(SGPM2),
ASPEED_PINCTRL_GROUP(SGPS1),
+ ASPEED_PINCTRL_GROUP(SGPS2),
ASPEED_PINCTRL_GROUP(SIOONCTRL),
ASPEED_PINCTRL_GROUP(SIOPBI),
ASPEED_PINCTRL_GROUP(SIOPBO),
@@ -2276,7 +2290,9 @@ static const struct aspeed_pin_function aspeed_g6_functions[] = {
ASPEED_PINCTRL_FUNC(SD1),
ASPEED_PINCTRL_FUNC(SD2),
ASPEED_PINCTRL_FUNC(SGPM1),
+ ASPEED_PINCTRL_FUNC(SGPM2),
ASPEED_PINCTRL_FUNC(SGPS1),
+ ASPEED_PINCTRL_FUNC(SGPS2),
ASPEED_PINCTRL_FUNC(SIOONCTRL),
ASPEED_PINCTRL_FUNC(SIOPBI),
ASPEED_PINCTRL_FUNC(SIOPBO),
diff --git a/drivers/pinctrl/aspeed/pinmux-aspeed.h b/drivers/pinctrl/aspeed/pinmux-aspeed.h
index dba5875ff276..b69ba6b360a2 100644
--- a/drivers/pinctrl/aspeed/pinmux-aspeed.h
+++ b/drivers/pinctrl/aspeed/pinmux-aspeed.h
@@ -730,6 +730,15 @@ struct aspeed_pin_desc {
SIG_EXPR_LIST_PTR(pin, low), \
SIG_EXPR_LIST_PTR(pin, other))
+#define PIN_DECL_4(pin, other, prio1, prio2, prio3, prio4) \
+ SIG_EXPR_LIST_DECL_SESG(pin, other, other); \
+ PIN_DECL_(pin, \
+ SIG_EXPR_LIST_PTR(pin, prio1), \
+ SIG_EXPR_LIST_PTR(pin, prio2), \
+ SIG_EXPR_LIST_PTR(pin, prio3), \
+ SIG_EXPR_LIST_PTR(pin, prio4), \
+ SIG_EXPR_LIST_PTR(pin, other))
+
#define GROUP_SYM(group) group_pins_ ## group
#define GROUP_DECL(group, ...) \
static const int GROUP_SYM(group)[] = { __VA_ARGS__ }
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
index 1d21129f7751..2c87af1180c4 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -1274,9 +1274,13 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
char *name;
girq->parents[i] = irq_of_parse_and_map(np, i);
- if (!is_7211)
+ if (!is_7211) {
+ if (!girq->parents[i]) {
+ girq->num_parents = i;
+ break;
+ }
continue;
-
+ }
/* Skip over the all banks interrupts */
pc->wake_irq[i] = irq_of_parse_and_map(np, i +
BCM2835_NUM_IRQS + 1);
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm6318.c b/drivers/pinctrl/bcm/pinctrl-bcm6318.c
index 77fd9b58067d..9311220fb6cb 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm6318.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm6318.c
@@ -452,7 +452,7 @@ static int bcm6318_gpio_request_enable(struct pinctrl_dev *pctldev,
return 0;
}
-static struct pinctrl_ops bcm6318_pctl_ops = {
+static const struct pinctrl_ops bcm6318_pctl_ops = {
.dt_free_map = pinctrl_utils_free_map,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.get_group_name = bcm6318_pinctrl_get_group_name,
@@ -460,7 +460,7 @@ static struct pinctrl_ops bcm6318_pctl_ops = {
.get_groups_count = bcm6318_pinctrl_get_group_count,
};
-static struct pinmux_ops bcm6318_pmx_ops = {
+static const struct pinmux_ops bcm6318_pmx_ops = {
.get_function_groups = bcm6318_pinctrl_get_groups,
.get_function_name = bcm6318_pinctrl_get_func_name,
.get_functions_count = bcm6318_pinctrl_get_func_count,
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm63268.c b/drivers/pinctrl/bcm/pinctrl-bcm63268.c
index d4c5fad7fb7d..1c1060a39597 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm63268.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm63268.c
@@ -597,7 +597,7 @@ static int bcm63268_gpio_request_enable(struct pinctrl_dev *pctldev,
return 0;
}
-static struct pinctrl_ops bcm63268_pctl_ops = {
+static const struct pinctrl_ops bcm63268_pctl_ops = {
.dt_free_map = pinctrl_utils_free_map,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.get_group_name = bcm63268_pinctrl_get_group_name,
@@ -605,7 +605,7 @@ static struct pinctrl_ops bcm63268_pctl_ops = {
.get_groups_count = bcm63268_pinctrl_get_group_count,
};
-static struct pinmux_ops bcm63268_pmx_ops = {
+static const struct pinmux_ops bcm63268_pmx_ops = {
.get_function_groups = bcm63268_pinctrl_get_groups,
.get_function_name = bcm63268_pinctrl_get_func_name,
.get_functions_count = bcm63268_pinctrl_get_func_count,
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm6328.c b/drivers/pinctrl/bcm/pinctrl-bcm6328.c
index c9efce600550..ffa8864abab6 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm6328.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm6328.c
@@ -358,7 +358,7 @@ static int bcm6328_gpio_request_enable(struct pinctrl_dev *pctldev,
return 0;
}
-static struct pinctrl_ops bcm6328_pctl_ops = {
+static const struct pinctrl_ops bcm6328_pctl_ops = {
.dt_free_map = pinctrl_utils_free_map,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.get_group_name = bcm6328_pinctrl_get_group_name,
@@ -366,7 +366,7 @@ static struct pinctrl_ops bcm6328_pctl_ops = {
.get_groups_count = bcm6328_pinctrl_get_group_count,
};
-static struct pinmux_ops bcm6328_pmx_ops = {
+static const struct pinmux_ops bcm6328_pmx_ops = {
.get_function_groups = bcm6328_pinctrl_get_groups,
.get_function_name = bcm6328_pinctrl_get_func_name,
.get_functions_count = bcm6328_pinctrl_get_func_count,
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm6358.c b/drivers/pinctrl/bcm/pinctrl-bcm6358.c
index d638578727f3..9f6cd7447887 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm6358.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm6358.c
@@ -303,7 +303,7 @@ static int bcm6358_gpio_request_enable(struct pinctrl_dev *pctldev,
return regmap_field_update_bits(priv->overlays, mask, 0);
}
-static struct pinctrl_ops bcm6358_pctl_ops = {
+static const struct pinctrl_ops bcm6358_pctl_ops = {
.dt_free_map = pinctrl_utils_free_map,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.get_group_name = bcm6358_pinctrl_get_group_name,
@@ -311,7 +311,7 @@ static struct pinctrl_ops bcm6358_pctl_ops = {
.get_groups_count = bcm6358_pinctrl_get_group_count,
};
-static struct pinmux_ops bcm6358_pmx_ops = {
+static const struct pinmux_ops bcm6358_pmx_ops = {
.get_function_groups = bcm6358_pinctrl_get_groups,
.get_function_name = bcm6358_pinctrl_get_func_name,
.get_functions_count = bcm6358_pinctrl_get_func_count,
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm6362.c b/drivers/pinctrl/bcm/pinctrl-bcm6362.c
index 40ef495b6301..13c7230949b2 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm6362.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm6362.c
@@ -571,7 +571,7 @@ static int bcm6362_gpio_request_enable(struct pinctrl_dev *pctldev,
return 0;
}
-static struct pinctrl_ops bcm6362_pctl_ops = {
+static const struct pinctrl_ops bcm6362_pctl_ops = {
.dt_free_map = pinctrl_utils_free_map,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.get_group_name = bcm6362_pinctrl_get_group_name,
@@ -579,7 +579,7 @@ static struct pinctrl_ops bcm6362_pctl_ops = {
.get_groups_count = bcm6362_pinctrl_get_group_count,
};
-static struct pinmux_ops bcm6362_pmx_ops = {
+static const struct pinmux_ops bcm6362_pmx_ops = {
.get_function_groups = bcm6362_pinctrl_get_groups,
.get_function_name = bcm6362_pinctrl_get_func_name,
.get_functions_count = bcm6362_pinctrl_get_func_count,
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm6368.c b/drivers/pinctrl/bcm/pinctrl-bcm6368.c
index 838095f9e890..b33a74aec82b 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm6368.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm6368.c
@@ -457,7 +457,7 @@ static int bcm6368_gpio_request_enable(struct pinctrl_dev *pctldev,
return 0;
}
-static struct pinctrl_ops bcm6368_pctl_ops = {
+static const struct pinctrl_ops bcm6368_pctl_ops = {
.dt_free_map = pinctrl_utils_free_map,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.get_group_name = bcm6368_pinctrl_get_group_name,
@@ -465,7 +465,7 @@ static struct pinctrl_ops bcm6368_pctl_ops = {
.get_groups_count = bcm6368_pinctrl_get_group_count,
};
-static struct pinmux_ops bcm6368_pmx_ops = {
+static const struct pinmux_ops bcm6368_pmx_ops = {
.get_function_groups = bcm6368_pinctrl_get_groups,
.get_function_name = bcm6368_pinctrl_get_func_name,
.get_functions_count = bcm6368_pinctrl_get_func_count,
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm63xx.h b/drivers/pinctrl/bcm/pinctrl-bcm63xx.h
index 3bdb50021f1b..d58c8cd5b6b8 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm63xx.h
+++ b/drivers/pinctrl/bcm/pinctrl-bcm63xx.h
@@ -12,8 +12,8 @@
#define BCM63XX_BANK_GPIOS 32
struct bcm63xx_pinctrl_soc {
- struct pinctrl_ops *pctl_ops;
- struct pinmux_ops *pmx_ops;
+ const struct pinctrl_ops *pctl_ops;
+ const struct pinmux_ops *pmx_ops;
const struct pinctrl_pin_desc *pins;
unsigned npins;
diff --git a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
index e2bd2dce6bb4..dc511b9a6b43 100644
--- a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
@@ -813,10 +813,8 @@ static int iproc_gpio_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (res) {
chip->io_ctrl = devm_ioremap_resource(dev, res);
- if (IS_ERR(chip->io_ctrl)) {
- dev_err(dev, "unable to map I/O memory\n");
+ if (IS_ERR(chip->io_ctrl))
return PTR_ERR(chip->io_ctrl);
- }
if (of_device_is_compatible(dev->of_node,
"brcm,cygnus-ccm-gpio"))
io_ctrl_type = IOCTRL_TYPE_CDRU;
diff --git a/drivers/pinctrl/intel/pinctrl-tigerlake.c b/drivers/pinctrl/intel/pinctrl-tigerlake.c
index 75b6d66955bf..3e4ef2b87526 100644
--- a/drivers/pinctrl/intel/pinctrl-tigerlake.c
+++ b/drivers/pinctrl/intel/pinctrl-tigerlake.c
@@ -749,6 +749,7 @@ static const struct acpi_device_id tgl_pinctrl_acpi_match[] = {
{ "INT34C5", (kernel_ulong_t)&tgllp_soc_data },
{ "INT34C6", (kernel_ulong_t)&tglh_soc_data },
{ "INTC1055", (kernel_ulong_t)&tgllp_soc_data },
+ { "INTC1057", (kernel_ulong_t)&tgllp_soc_data },
{ }
};
MODULE_DEVICE_TABLE(acpi, tgl_pinctrl_acpi_match);
diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 90f0c8255eaf..7040a7a7bd5d 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -153,6 +153,13 @@ config PINCTRL_MT8195
depends on ARM64 || COMPILE_TEST
select PINCTRL_MTK_PARIS
+config PINCTRL_MT8365
+ bool "Mediatek MT8365 pin control"
+ depends on OF
+ depends on ARM64 || COMPILE_TEST
+ default ARM64 && ARCH_MEDIATEK
+ select PINCTRL_MTK
+
config PINCTRL_MT8516
bool "Mediatek MT8516 pin control"
depends on OF
diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
index 06fde993ace2..1bb7f9c65bc2 100644
--- a/drivers/pinctrl/mediatek/Makefile
+++ b/drivers/pinctrl/mediatek/Makefile
@@ -22,5 +22,6 @@ obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
obj-$(CONFIG_PINCTRL_MT8183) += pinctrl-mt8183.o
obj-$(CONFIG_PINCTRL_MT8192) += pinctrl-mt8192.o
obj-$(CONFIG_PINCTRL_MT8195) += pinctrl-mt8195.o
+obj-$(CONFIG_PINCTRL_MT8365) += pinctrl-mt8365.o
obj-$(CONFIG_PINCTRL_MT8516) += pinctrl-mt8516.o
obj-$(CONFIG_PINCTRL_MT6397) += pinctrl-mt6397.o
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2701.c b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
index df8c6fb12955..37228dd5103e 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt2701.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
@@ -523,6 +523,9 @@ static const struct mtk_pinctrl_devdata mt2701_pinctrl_data = {
.port_shf = 4,
.port_mask = 0x1f,
.port_align = 4,
+ .mode_mask = 0xf,
+ .mode_per_reg = 5,
+ .mode_shf = 4,
.eint_hw = {
.port_mask = 6,
.ports = 6,
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2712.c b/drivers/pinctrl/mediatek/pinctrl-mt2712.c
index 8398d55c01cb..ba35fc6cc138 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt2712.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2712.c
@@ -576,6 +576,9 @@ static const struct mtk_pinctrl_devdata mt2712_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
+ .mode_mask = 0xf,
+ .mode_per_reg = 5,
+ .mode_shf = 4,
.eint_hw = {
.port_mask = 0xf,
.ports = 8,
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6397.c b/drivers/pinctrl/mediatek/pinctrl-mt6397.c
index a1914e0e49c7..bc5c3dfcdc76 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt6397.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt6397.c
@@ -33,6 +33,9 @@ static const struct mtk_pinctrl_devdata mt6397_pinctrl_data = {
.port_shf = 3,
.port_mask = 0x3,
.port_align = 2,
+ .mode_mask = 0xf,
+ .mode_per_reg = 5,
+ .mode_shf = 4,
};
static int mt6397_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8127.c b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
index 5f05be056309..eaf5c76b14c7 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8127.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
@@ -292,6 +292,9 @@ static const struct mtk_pinctrl_devdata mt8127_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
+ .mode_mask = 0xf,
+ .mode_per_reg = 5,
+ .mode_shf = 4,
.eint_hw = {
.port_mask = 7,
.ports = 6,
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8135.c b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
index 9ac784c48873..b8f4080aab45 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8135.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
@@ -305,6 +305,9 @@ static const struct mtk_pinctrl_devdata mt8135_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
+ .mode_mask = 0xf,
+ .mode_per_reg = 5,
+ .mode_shf = 4,
.eint_hw = {
.port_mask = 7,
.ports = 6,
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8167.c b/drivers/pinctrl/mediatek/pinctrl-mt8167.c
index 7b68886bad16..ba12ef795e52 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8167.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8167.c
@@ -324,6 +324,9 @@ static const struct mtk_pinctrl_devdata mt8167_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
+ .mode_mask = 0xf,
+ .mode_per_reg = 5,
+ .mode_shf = 4,
.eint_hw = {
.port_mask = 7,
.ports = 6,
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8173.c b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
index 75e7c0978337..fc99df8a11c6 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8173.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
@@ -332,6 +332,9 @@ static const struct mtk_pinctrl_devdata mt8173_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
+ .mode_mask = 0xf,
+ .mode_per_reg = 5,
+ .mode_shf = 4,
.eint_hw = {
.port_mask = 7,
.ports = 6,
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8365.c b/drivers/pinctrl/mediatek/pinctrl-mt8365.c
new file mode 100644
index 000000000000..22c33c3cb581
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8365.c
@@ -0,0 +1,502 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 MediaTek Inc.
+ * Author: Zhiyong Tao <zhiyong.tao@mediatek.com>
+ */
+
+#include <dt-bindings/pinctrl/mt65xx.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "pinctrl-mtk-common.h"
+#include "pinctrl-mtk-mt8365.h"
+
+static const struct mtk_drv_group_desc mt8365_drv_grp[] = {
+ /* 0E4E8SR 4/8/12/16 */
+ MTK_DRV_GRP(4, 16, 1, 2, 4),
+ /* 0E2E4SR 2/4/6/8 */
+ MTK_DRV_GRP(2, 8, 1, 2, 2),
+ /* E8E4E2 2/4/6/8/10/12/14/16 */
+ MTK_DRV_GRP(2, 16, 0, 2, 2)
+};
+
+static const struct mtk_pin_drv_grp mt8365_pin_drv[] = {
+
+ MTK_PIN_DRV_GRP(0, 0x710, 0, 2),
+ MTK_PIN_DRV_GRP(1, 0x710, 0, 2),
+ MTK_PIN_DRV_GRP(2, 0x710, 0, 2),
+ MTK_PIN_DRV_GRP(3, 0x710, 0, 2),
+ MTK_PIN_DRV_GRP(4, 0x710, 4, 2),
+ MTK_PIN_DRV_GRP(5, 0x710, 4, 2),
+ MTK_PIN_DRV_GRP(6, 0x710, 4, 2),
+ MTK_PIN_DRV_GRP(7, 0x710, 4, 2),
+ MTK_PIN_DRV_GRP(8, 0x710, 8, 2),
+ MTK_PIN_DRV_GRP(9, 0x710, 8, 2),
+ MTK_PIN_DRV_GRP(10, 0x710, 8, 2),
+ MTK_PIN_DRV_GRP(11, 0x710, 8, 2),
+ MTK_PIN_DRV_GRP(12, 0x710, 12, 2),
+ MTK_PIN_DRV_GRP(13, 0x710, 12, 2),
+ MTK_PIN_DRV_GRP(14, 0x710, 12, 2),
+ MTK_PIN_DRV_GRP(15, 0x710, 12, 2),
+ MTK_PIN_DRV_GRP(16, 0x710, 16, 2),
+ MTK_PIN_DRV_GRP(17, 0x710, 16, 2),
+ MTK_PIN_DRV_GRP(18, 0x710, 16, 2),
+ MTK_PIN_DRV_GRP(19, 0x710, 20, 2),
+ MTK_PIN_DRV_GRP(20, 0x710, 24, 2),
+ MTK_PIN_DRV_GRP(21, 0x710, 24, 2),
+ MTK_PIN_DRV_GRP(22, 0x710, 28, 2),
+ MTK_PIN_DRV_GRP(23, 0x720, 0, 2),
+ MTK_PIN_DRV_GRP(24, 0x720, 0, 2),
+ MTK_PIN_DRV_GRP(25, 0x720, 0, 2),
+ MTK_PIN_DRV_GRP(26, 0x720, 4, 2),
+ MTK_PIN_DRV_GRP(27, 0x720, 4, 2),
+ MTK_PIN_DRV_GRP(28, 0x720, 4, 2),
+ MTK_PIN_DRV_GRP(29, 0x720, 4, 2),
+ MTK_PIN_DRV_GRP(30, 0x720, 8, 2),
+ MTK_PIN_DRV_GRP(31, 0x720, 8, 2),
+ MTK_PIN_DRV_GRP(32, 0x720, 8, 2),
+ MTK_PIN_DRV_GRP(33, 0x720, 8, 2),
+ MTK_PIN_DRV_GRP(34, 0x720, 8, 2),
+ MTK_PIN_DRV_GRP(35, 0x720, 12, 2),
+ MTK_PIN_DRV_GRP(36, 0x720, 12, 2),
+ MTK_PIN_DRV_GRP(37, 0x720, 12, 2),
+ MTK_PIN_DRV_GRP(38, 0x720, 12, 2),
+ MTK_PIN_DRV_GRP(39, 0x720, 12, 2),
+ MTK_PIN_DRV_GRP(40, 0x720, 12, 2),
+ MTK_PIN_DRV_GRP(41, 0x720, 16, 2),
+ MTK_PIN_DRV_GRP(42, 0x720, 16, 2),
+ MTK_PIN_DRV_GRP(43, 0x720, 16, 2),
+ MTK_PIN_DRV_GRP(44, 0x720, 16, 2),
+ MTK_PIN_DRV_GRP(45, 0x720, 20, 2),
+ MTK_PIN_DRV_GRP(46, 0x720, 20, 2),
+ MTK_PIN_DRV_GRP(47, 0x720, 20, 2),
+ MTK_PIN_DRV_GRP(48, 0x720, 20, 2),
+ MTK_PIN_DRV_GRP(49, 0x720, 24, 2),
+ MTK_PIN_DRV_GRP(50, 0x720, 24, 2),
+ MTK_PIN_DRV_GRP(51, 0x720, 24, 2),
+ MTK_PIN_DRV_GRP(52, 0x720, 24, 2),
+ MTK_PIN_DRV_GRP(53, 0x720, 24, 2),
+ MTK_PIN_DRV_GRP(54, 0x720, 24, 2),
+ MTK_PIN_DRV_GRP(55, 0x720, 24, 2),
+ MTK_PIN_DRV_GRP(56, 0x720, 24, 2),
+ MTK_PIN_DRV_GRP(57, 0x720, 28, 2),
+ MTK_PIN_DRV_GRP(58, 0x720, 28, 2),
+ MTK_PIN_DRV_GRP(59, 0x730, 0, 2),
+ MTK_PIN_DRV_GRP(60, 0x730, 0, 2),
+ MTK_PIN_DRV_GRP(61, 0x730, 4, 2),
+ MTK_PIN_DRV_GRP(62, 0x730, 4, 2),
+ MTK_PIN_DRV_GRP(63, 0x730, 8, 2),
+ MTK_PIN_DRV_GRP(64, 0x730, 8, 2),
+ MTK_PIN_DRV_GRP(65, 0x730, 12, 2),
+ MTK_PIN_DRV_GRP(66, 0x730, 12, 2),
+ MTK_PIN_DRV_GRP(67, 0x730, 12, 2),
+ MTK_PIN_DRV_GRP(68, 0x730, 12, 2),
+ MTK_PIN_DRV_GRP(69, 0x730, 12, 2),
+ MTK_PIN_DRV_GRP(70, 0x730, 12, 2),
+ MTK_PIN_DRV_GRP(71, 0x730, 16, 2),
+ MTK_PIN_DRV_GRP(72, 0x730, 16, 2),
+ MTK_PIN_DRV_GRP(73, 0x730, 16, 2),
+ MTK_PIN_DRV_GRP(74, 0x730, 16, 2),
+ MTK_PIN_DRV_GRP(75, 0x730, 16, 2),
+ MTK_PIN_DRV_GRP(76, 0x730, 16, 2),
+ MTK_PIN_DRV_GRP(77, 0x730, 16, 2),
+ MTK_PIN_DRV_GRP(78, 0x730, 16, 2),
+ MTK_PIN_DRV_GRP(79, 0x730, 16, 2),
+ MTK_PIN_DRV_GRP(80, 0x730, 20, 2),
+ MTK_PIN_DRV_GRP(81, 0x730, 24, 2),
+ MTK_PIN_DRV_GRP(82, 0x730, 28, 2),
+ MTK_PIN_DRV_GRP(83, 0x730, 28, 2),
+ MTK_PIN_DRV_GRP(84, 0x730, 28, 2),
+ MTK_PIN_DRV_GRP(85, 0x730, 28, 2),
+ MTK_PIN_DRV_GRP(86, 0x740, 12, 2),
+ MTK_PIN_DRV_GRP(87, 0x740, 16, 2),
+ MTK_PIN_DRV_GRP(88, 0x740, 20, 2),
+ MTK_PIN_DRV_GRP(89, 0x740, 24, 2),
+ MTK_PIN_DRV_GRP(90, 0x740, 24, 2),
+ MTK_PIN_DRV_GRP(91, 0x740, 24, 2),
+ MTK_PIN_DRV_GRP(92, 0x740, 24, 2),
+ MTK_PIN_DRV_GRP(93, 0x750, 8, 2),
+ MTK_PIN_DRV_GRP(94, 0x750, 8, 2),
+ MTK_PIN_DRV_GRP(95, 0x750, 8, 2),
+ MTK_PIN_DRV_GRP(96, 0x750, 8, 2),
+ MTK_PIN_DRV_GRP(97, 0x750, 24, 2),
+ MTK_PIN_DRV_GRP(98, 0x750, 28, 2),
+ MTK_PIN_DRV_GRP(99, 0x760, 0, 2),
+ MTK_PIN_DRV_GRP(100, 0x750, 8, 2),
+ MTK_PIN_DRV_GRP(101, 0x750, 8, 2),
+ MTK_PIN_DRV_GRP(102, 0x750, 8, 2),
+ MTK_PIN_DRV_GRP(103, 0x750, 8, 2),
+ MTK_PIN_DRV_GRP(104, 0x760, 20, 2),
+ MTK_PIN_DRV_GRP(105, 0x760, 24, 2),
+ MTK_PIN_DRV_GRP(106, 0x760, 24, 2),
+ MTK_PIN_DRV_GRP(107, 0x760, 24, 2),
+ MTK_PIN_DRV_GRP(108, 0x760, 24, 2),
+ MTK_PIN_DRV_GRP(109, 0x760, 24, 2),
+ MTK_PIN_DRV_GRP(110, 0x760, 28, 2),
+ MTK_PIN_DRV_GRP(111, 0x760, 28, 2),
+ MTK_PIN_DRV_GRP(112, 0x760, 28, 2),
+ MTK_PIN_DRV_GRP(113, 0x760, 28, 2),
+ MTK_PIN_DRV_GRP(114, 0x770, 0, 2),
+ MTK_PIN_DRV_GRP(115, 0x770, 0, 2),
+ MTK_PIN_DRV_GRP(116, 0x770, 0, 2),
+ MTK_PIN_DRV_GRP(117, 0x770, 4, 2),
+ MTK_PIN_DRV_GRP(118, 0x770, 4, 2),
+ MTK_PIN_DRV_GRP(119, 0x770, 4, 2),
+ MTK_PIN_DRV_GRP(120, 0x770, 8, 2),
+ MTK_PIN_DRV_GRP(121, 0x770, 8, 2),
+ MTK_PIN_DRV_GRP(122, 0x770, 8, 2),
+ MTK_PIN_DRV_GRP(123, 0x770, 12, 2),
+ MTK_PIN_DRV_GRP(124, 0x770, 12, 2),
+ MTK_PIN_DRV_GRP(125, 0x770, 12, 2),
+ MTK_PIN_DRV_GRP(126, 0x770, 16, 2),
+ MTK_PIN_DRV_GRP(127, 0x770, 16, 2),
+ MTK_PIN_DRV_GRP(128, 0x770, 16, 2),
+ MTK_PIN_DRV_GRP(129, 0x770, 20, 2),
+ MTK_PIN_DRV_GRP(130, 0x770, 20, 2),
+ MTK_PIN_DRV_GRP(131, 0x770, 20, 2),
+ MTK_PIN_DRV_GRP(132, 0x770, 20, 2),
+ MTK_PIN_DRV_GRP(133, 0x770, 20, 2),
+ MTK_PIN_DRV_GRP(134, 0x770, 20, 2),
+ MTK_PIN_DRV_GRP(135, 0x770, 20, 2),
+ MTK_PIN_DRV_GRP(136, 0x770, 24, 2),
+ MTK_PIN_DRV_GRP(137, 0x770, 24, 2),
+ MTK_PIN_DRV_GRP(138, 0x770, 24, 2),
+ MTK_PIN_DRV_GRP(139, 0x770, 24, 2),
+ MTK_PIN_DRV_GRP(140, 0x770, 24, 2),
+ MTK_PIN_DRV_GRP(141, 0x770, 24, 2),
+ MTK_PIN_DRV_GRP(142, 0x770, 24, 2),
+ MTK_PIN_DRV_GRP(143, 0x770, 24, 2),
+ MTK_PIN_DRV_GRP(144, 0x770, 24, 2),
+};
+
+static const struct mtk_pin_spec_pupd_set_samereg mt8365_spec_pupd[] = {
+ MTK_PIN_PUPD_SPEC_SR(22, 0x070, 0, 2, 1),
+ MTK_PIN_PUPD_SPEC_SR(23, 0x070, 3, 5, 4),
+ MTK_PIN_PUPD_SPEC_SR(24, 0x070, 6, 8, 7),
+ MTK_PIN_PUPD_SPEC_SR(25, 0x070, 9, 11, 10),
+ MTK_PIN_PUPD_SPEC_SR(80, 0x070, 14, 13, 12),
+ MTK_PIN_PUPD_SPEC_SR(81, 0x070, 17, 16, 15),
+ MTK_PIN_PUPD_SPEC_SR(82, 0x070, 20, 19, 18),
+ MTK_PIN_PUPD_SPEC_SR(83, 0x070, 23, 22, 21),
+ MTK_PIN_PUPD_SPEC_SR(84, 0x070, 26, 25, 24),
+ MTK_PIN_PUPD_SPEC_SR(85, 0x070, 29, 28, 27),
+ MTK_PIN_PUPD_SPEC_SR(86, 0x080, 2, 1, 0),
+ MTK_PIN_PUPD_SPEC_SR(87, 0x080, 5, 4, 3),
+ MTK_PIN_PUPD_SPEC_SR(88, 0x080, 8, 7, 6),
+ MTK_PIN_PUPD_SPEC_SR(89, 0x080, 11, 10, 9),
+ MTK_PIN_PUPD_SPEC_SR(90, 0x080, 14, 13, 12),
+ MTK_PIN_PUPD_SPEC_SR(91, 0x080, 17, 16, 15),
+ MTK_PIN_PUPD_SPEC_SR(92, 0x080, 20, 19, 18),
+ MTK_PIN_PUPD_SPEC_SR(93, 0x080, 23, 22, 21),
+ MTK_PIN_PUPD_SPEC_SR(94, 0x080, 26, 25, 24),
+ MTK_PIN_PUPD_SPEC_SR(95, 0x080, 29, 28, 27),
+ MTK_PIN_PUPD_SPEC_SR(96, 0x090, 2, 1, 0),
+ MTK_PIN_PUPD_SPEC_SR(97, 0x090, 5, 4, 3),
+ MTK_PIN_PUPD_SPEC_SR(98, 0x090, 8, 7, 6),
+ MTK_PIN_PUPD_SPEC_SR(99, 0x090, 11, 10, 9),
+ MTK_PIN_PUPD_SPEC_SR(100, 0x090, 14, 13, 12),
+ MTK_PIN_PUPD_SPEC_SR(101, 0x090, 17, 16, 15),
+ MTK_PIN_PUPD_SPEC_SR(102, 0x090, 20, 19, 18),
+ MTK_PIN_PUPD_SPEC_SR(103, 0x090, 23, 22, 21),
+ MTK_PIN_PUPD_SPEC_SR(104, 0x090, 26, 25, 24),
+ MTK_PIN_PUPD_SPEC_SR(105, 0x090, 29, 28, 27),
+ MTK_PIN_PUPD_SPEC_SR(106, 0x0F0, 2, 1, 0),
+ MTK_PIN_PUPD_SPEC_SR(107, 0x0F0, 5, 4, 3),
+ MTK_PIN_PUPD_SPEC_SR(108, 0x0F0, 8, 7, 6),
+ MTK_PIN_PUPD_SPEC_SR(109, 0x0F0, 11, 10, 9),
+};
+
+static const struct mtk_pin_ies_smt_set mt8365_ies_set[] = {
+ MTK_PIN_IES_SMT_SPEC(0, 3, 0x410, 0),
+ MTK_PIN_IES_SMT_SPEC(4, 7, 0x410, 1),
+ MTK_PIN_IES_SMT_SPEC(8, 11, 0x410, 2),
+ MTK_PIN_IES_SMT_SPEC(12, 15, 0x410, 3),
+ MTK_PIN_IES_SMT_SPEC(16, 18, 0x410, 4),
+ MTK_PIN_IES_SMT_SPEC(19, 19, 0x410, 5),
+ MTK_PIN_IES_SMT_SPEC(20, 21, 0x410, 6),
+ MTK_PIN_IES_SMT_SPEC(22, 22, 0x410, 7),
+ MTK_PIN_IES_SMT_SPEC(23, 25, 0x410, 8),
+ MTK_PIN_IES_SMT_SPEC(26, 29, 0x410, 9),
+ MTK_PIN_IES_SMT_SPEC(30, 34, 0x410, 10),
+ MTK_PIN_IES_SMT_SPEC(35, 40, 0x410, 11),
+ MTK_PIN_IES_SMT_SPEC(41, 44, 0x410, 12),
+ MTK_PIN_IES_SMT_SPEC(45, 48, 0x410, 13),
+ MTK_PIN_IES_SMT_SPEC(49, 56, 0x410, 14),
+ MTK_PIN_IES_SMT_SPEC(57, 58, 0x410, 15),
+ MTK_PIN_IES_SMT_SPEC(59, 60, 0x410, 16),
+ MTK_PIN_IES_SMT_SPEC(61, 62, 0x410, 17),
+ MTK_PIN_IES_SMT_SPEC(63, 64, 0x410, 18),
+ MTK_PIN_IES_SMT_SPEC(65, 70, 0x410, 19),
+ MTK_PIN_IES_SMT_SPEC(71, 79, 0x410, 20),
+ MTK_PIN_IES_SMT_SPEC(80, 80, 0x410, 21),
+ MTK_PIN_IES_SMT_SPEC(81, 81, 0x410, 22),
+ MTK_PIN_IES_SMT_SPEC(82, 82, 0x410, 23),
+ MTK_PIN_IES_SMT_SPEC(83, 83, 0x410, 24),
+ MTK_PIN_IES_SMT_SPEC(84, 84, 0x410, 25),
+ MTK_PIN_IES_SMT_SPEC(85, 85, 0x410, 26),
+ MTK_PIN_IES_SMT_SPEC(86, 86, 0x410, 27),
+ MTK_PIN_IES_SMT_SPEC(87, 87, 0x410, 28),
+ MTK_PIN_IES_SMT_SPEC(88, 88, 0x410, 29),
+ MTK_PIN_IES_SMT_SPEC(89, 89, 0x410, 30),
+ MTK_PIN_IES_SMT_SPEC(90, 90, 0x410, 31),
+ MTK_PIN_IES_SMT_SPEC(91, 91, 0x420, 0),
+ MTK_PIN_IES_SMT_SPEC(92, 92, 0x420, 1),
+ MTK_PIN_IES_SMT_SPEC(93, 93, 0x420, 2),
+ MTK_PIN_IES_SMT_SPEC(94, 94, 0x420, 3),
+ MTK_PIN_IES_SMT_SPEC(95, 95, 0x420, 4),
+ MTK_PIN_IES_SMT_SPEC(96, 96, 0x420, 5),
+ MTK_PIN_IES_SMT_SPEC(97, 97, 0x420, 6),
+ MTK_PIN_IES_SMT_SPEC(98, 98, 0x420, 7),
+ MTK_PIN_IES_SMT_SPEC(99, 99, 0x420, 8),
+ MTK_PIN_IES_SMT_SPEC(100, 100, 0x420, 9),
+ MTK_PIN_IES_SMT_SPEC(101, 101, 0x420, 10),
+ MTK_PIN_IES_SMT_SPEC(102, 102, 0x420, 11),
+ MTK_PIN_IES_SMT_SPEC(103, 103, 0x420, 12),
+ MTK_PIN_IES_SMT_SPEC(104, 104, 0x420, 13),
+ MTK_PIN_IES_SMT_SPEC(105, 109, 0x420, 14),
+ MTK_PIN_IES_SMT_SPEC(110, 113, 0x420, 15),
+ MTK_PIN_IES_SMT_SPEC(114, 112, 0x420, 16),
+ MTK_PIN_IES_SMT_SPEC(117, 119, 0x420, 17),
+ MTK_PIN_IES_SMT_SPEC(120, 122, 0x420, 18),
+ MTK_PIN_IES_SMT_SPEC(123, 125, 0x420, 19),
+ MTK_PIN_IES_SMT_SPEC(126, 128, 0x420, 20),
+ MTK_PIN_IES_SMT_SPEC(129, 135, 0x420, 21),
+ MTK_PIN_IES_SMT_SPEC(136, 144, 0x420, 22),
+};
+
+static const struct mtk_pin_ies_smt_set mt8365_smt_set[] = {
+ MTK_PIN_IES_SMT_SPEC(0, 0, 0x470, 0),
+ MTK_PIN_IES_SMT_SPEC(1, 1, 0x470, 0),
+ MTK_PIN_IES_SMT_SPEC(2, 2, 0x470, 0),
+ MTK_PIN_IES_SMT_SPEC(3, 3, 0x470, 0),
+ MTK_PIN_IES_SMT_SPEC(4, 4, 0x470, 1),
+ MTK_PIN_IES_SMT_SPEC(5, 5, 0x470, 1),
+ MTK_PIN_IES_SMT_SPEC(6, 6, 0x470, 1),
+ MTK_PIN_IES_SMT_SPEC(7, 7, 0x470, 1),
+ MTK_PIN_IES_SMT_SPEC(8, 8, 0x470, 2),
+ MTK_PIN_IES_SMT_SPEC(9, 9, 0x470, 2),
+ MTK_PIN_IES_SMT_SPEC(10, 10, 0x470, 2),
+ MTK_PIN_IES_SMT_SPEC(11, 11, 0x470, 2),
+ MTK_PIN_IES_SMT_SPEC(12, 12, 0x470, 3),
+ MTK_PIN_IES_SMT_SPEC(13, 13, 0x470, 3),
+ MTK_PIN_IES_SMT_SPEC(14, 14, 0x470, 3),
+ MTK_PIN_IES_SMT_SPEC(15, 15, 0x470, 3),
+ MTK_PIN_IES_SMT_SPEC(16, 16, 0x470, 4),
+ MTK_PIN_IES_SMT_SPEC(17, 17, 0x470, 4),
+ MTK_PIN_IES_SMT_SPEC(18, 18, 0x470, 4),
+ MTK_PIN_IES_SMT_SPEC(19, 19, 0x470, 5),
+ MTK_PIN_IES_SMT_SPEC(20, 20, 0x470, 6),
+ MTK_PIN_IES_SMT_SPEC(21, 21, 0x470, 6),
+ MTK_PIN_IES_SMT_SPEC(22, 22, 0x470, 7),
+ MTK_PIN_IES_SMT_SPEC(23, 23, 0x470, 8),
+ MTK_PIN_IES_SMT_SPEC(24, 24, 0x470, 8),
+ MTK_PIN_IES_SMT_SPEC(25, 25, 0x470, 8),
+ MTK_PIN_IES_SMT_SPEC(26, 26, 0x470, 9),
+ MTK_PIN_IES_SMT_SPEC(27, 27, 0x470, 9),
+ MTK_PIN_IES_SMT_SPEC(28, 28, 0x470, 9),
+ MTK_PIN_IES_SMT_SPEC(29, 29, 0x470, 9),
+ MTK_PIN_IES_SMT_SPEC(30, 30, 0x470, 10),
+ MTK_PIN_IES_SMT_SPEC(31, 31, 0x470, 10),
+ MTK_PIN_IES_SMT_SPEC(32, 32, 0x470, 10),
+ MTK_PIN_IES_SMT_SPEC(33, 33, 0x470, 10),
+ MTK_PIN_IES_SMT_SPEC(34, 34, 0x470, 10),
+ MTK_PIN_IES_SMT_SPEC(35, 35, 0x470, 11),
+ MTK_PIN_IES_SMT_SPEC(36, 36, 0x470, 11),
+ MTK_PIN_IES_SMT_SPEC(37, 37, 0x470, 11),
+ MTK_PIN_IES_SMT_SPEC(38, 38, 0x470, 11),
+ MTK_PIN_IES_SMT_SPEC(39, 39, 0x470, 11),
+ MTK_PIN_IES_SMT_SPEC(40, 40, 0x470, 11),
+ MTK_PIN_IES_SMT_SPEC(41, 41, 0x470, 12),
+ MTK_PIN_IES_SMT_SPEC(42, 42, 0x470, 12),
+ MTK_PIN_IES_SMT_SPEC(43, 43, 0x470, 12),
+ MTK_PIN_IES_SMT_SPEC(44, 44, 0x470, 12),
+ MTK_PIN_IES_SMT_SPEC(45, 45, 0x470, 13),
+ MTK_PIN_IES_SMT_SPEC(46, 46, 0x470, 13),
+ MTK_PIN_IES_SMT_SPEC(47, 47, 0x470, 13),
+ MTK_PIN_IES_SMT_SPEC(48, 48, 0x470, 13),
+ MTK_PIN_IES_SMT_SPEC(49, 49, 0x470, 14),
+ MTK_PIN_IES_SMT_SPEC(50, 50, 0x470, 14),
+ MTK_PIN_IES_SMT_SPEC(51, 51, 0x470, 14),
+ MTK_PIN_IES_SMT_SPEC(52, 52, 0x470, 14),
+ MTK_PIN_IES_SMT_SPEC(53, 53, 0x470, 14),
+ MTK_PIN_IES_SMT_SPEC(54, 54, 0x470, 14),
+ MTK_PIN_IES_SMT_SPEC(55, 55, 0x470, 14),
+ MTK_PIN_IES_SMT_SPEC(56, 56, 0x470, 14),
+ MTK_PIN_IES_SMT_SPEC(57, 57, 0x470, 15),
+ MTK_PIN_IES_SMT_SPEC(58, 58, 0x470, 15),
+ MTK_PIN_IES_SMT_SPEC(59, 59, 0x470, 16),
+ MTK_PIN_IES_SMT_SPEC(60, 60, 0x470, 16),
+ MTK_PIN_IES_SMT_SPEC(61, 61, 0x470, 17),
+ MTK_PIN_IES_SMT_SPEC(62, 62, 0x470, 17),
+ MTK_PIN_IES_SMT_SPEC(63, 63, 0x470, 18),
+ MTK_PIN_IES_SMT_SPEC(64, 64, 0x470, 18),
+ MTK_PIN_IES_SMT_SPEC(65, 65, 0x470, 19),
+ MTK_PIN_IES_SMT_SPEC(66, 66, 0x470, 19),
+ MTK_PIN_IES_SMT_SPEC(67, 67, 0x470, 19),
+ MTK_PIN_IES_SMT_SPEC(68, 68, 0x470, 19),
+ MTK_PIN_IES_SMT_SPEC(69, 69, 0x470, 19),
+ MTK_PIN_IES_SMT_SPEC(70, 70, 0x470, 19),
+ MTK_PIN_IES_SMT_SPEC(71, 71, 0x470, 20),
+ MTK_PIN_IES_SMT_SPEC(72, 72, 0x470, 20),
+ MTK_PIN_IES_SMT_SPEC(73, 73, 0x470, 20),
+ MTK_PIN_IES_SMT_SPEC(74, 74, 0x470, 20),
+ MTK_PIN_IES_SMT_SPEC(75, 75, 0x470, 20),
+ MTK_PIN_IES_SMT_SPEC(76, 76, 0x470, 20),
+ MTK_PIN_IES_SMT_SPEC(77, 77, 0x470, 20),
+ MTK_PIN_IES_SMT_SPEC(78, 78, 0x470, 20),
+ MTK_PIN_IES_SMT_SPEC(79, 79, 0x470, 20),
+ MTK_PIN_IES_SMT_SPEC(80, 80, 0x470, 21),
+ MTK_PIN_IES_SMT_SPEC(81, 81, 0x470, 22),
+ MTK_PIN_IES_SMT_SPEC(82, 82, 0x470, 23),
+ MTK_PIN_IES_SMT_SPEC(83, 83, 0x470, 24),
+ MTK_PIN_IES_SMT_SPEC(84, 84, 0x470, 25),
+ MTK_PIN_IES_SMT_SPEC(85, 85, 0x470, 26),
+ MTK_PIN_IES_SMT_SPEC(86, 86, 0x470, 27),
+ MTK_PIN_IES_SMT_SPEC(87, 87, 0x470, 28),
+ MTK_PIN_IES_SMT_SPEC(88, 88, 0x470, 29),
+ MTK_PIN_IES_SMT_SPEC(89, 89, 0x470, 30),
+ MTK_PIN_IES_SMT_SPEC(90, 90, 0x470, 31),
+ MTK_PIN_IES_SMT_SPEC(91, 91, 0x480, 0),
+ MTK_PIN_IES_SMT_SPEC(92, 92, 0x480, 1),
+ MTK_PIN_IES_SMT_SPEC(93, 93, 0x480, 2),
+ MTK_PIN_IES_SMT_SPEC(94, 94, 0x480, 3),
+ MTK_PIN_IES_SMT_SPEC(95, 95, 0x480, 4),
+ MTK_PIN_IES_SMT_SPEC(96, 96, 0x480, 5),
+ MTK_PIN_IES_SMT_SPEC(97, 97, 0x480, 6),
+ MTK_PIN_IES_SMT_SPEC(98, 98, 0x480, 7),
+ MTK_PIN_IES_SMT_SPEC(99, 99, 0x480, 8),
+ MTK_PIN_IES_SMT_SPEC(100, 100, 0x480, 9),
+ MTK_PIN_IES_SMT_SPEC(101, 101, 0x480, 10),
+ MTK_PIN_IES_SMT_SPEC(102, 102, 0x480, 11),
+ MTK_PIN_IES_SMT_SPEC(103, 103, 0x480, 12),
+ MTK_PIN_IES_SMT_SPEC(104, 104, 0x480, 13),
+ MTK_PIN_IES_SMT_SPEC(105, 105, 0x480, 14),
+ MTK_PIN_IES_SMT_SPEC(106, 106, 0x480, 14),
+ MTK_PIN_IES_SMT_SPEC(107, 107, 0x480, 14),
+ MTK_PIN_IES_SMT_SPEC(108, 108, 0x480, 14),
+ MTK_PIN_IES_SMT_SPEC(109, 109, 0x480, 14),
+ MTK_PIN_IES_SMT_SPEC(110, 110, 0x480, 15),
+ MTK_PIN_IES_SMT_SPEC(111, 111, 0x480, 15),
+ MTK_PIN_IES_SMT_SPEC(112, 112, 0x480, 15),
+ MTK_PIN_IES_SMT_SPEC(113, 113, 0x480, 15),
+ MTK_PIN_IES_SMT_SPEC(114, 114, 0x480, 16),
+ MTK_PIN_IES_SMT_SPEC(115, 115, 0x480, 16),
+ MTK_PIN_IES_SMT_SPEC(116, 116, 0x480, 16),
+ MTK_PIN_IES_SMT_SPEC(117, 117, 0x480, 17),
+ MTK_PIN_IES_SMT_SPEC(118, 118, 0x480, 17),
+ MTK_PIN_IES_SMT_SPEC(119, 119, 0x480, 17),
+ MTK_PIN_IES_SMT_SPEC(120, 120, 0x480, 18),
+ MTK_PIN_IES_SMT_SPEC(121, 121, 0x480, 18),
+ MTK_PIN_IES_SMT_SPEC(122, 122, 0x480, 18),
+ MTK_PIN_IES_SMT_SPEC(123, 123, 0x480, 19),
+ MTK_PIN_IES_SMT_SPEC(124, 124, 0x480, 19),
+ MTK_PIN_IES_SMT_SPEC(125, 125, 0x480, 19),
+ MTK_PIN_IES_SMT_SPEC(126, 126, 0x480, 20),
+ MTK_PIN_IES_SMT_SPEC(127, 127, 0x480, 20),
+ MTK_PIN_IES_SMT_SPEC(128, 128, 0x480, 20),
+ MTK_PIN_IES_SMT_SPEC(129, 129, 0x480, 21),
+ MTK_PIN_IES_SMT_SPEC(130, 130, 0x480, 21),
+ MTK_PIN_IES_SMT_SPEC(131, 131, 0x480, 21),
+ MTK_PIN_IES_SMT_SPEC(132, 132, 0x480, 21),
+ MTK_PIN_IES_SMT_SPEC(133, 133, 0x480, 21),
+ MTK_PIN_IES_SMT_SPEC(134, 134, 0x480, 21),
+ MTK_PIN_IES_SMT_SPEC(135, 135, 0x480, 21),
+ MTK_PIN_IES_SMT_SPEC(136, 136, 0x480, 22),
+ MTK_PIN_IES_SMT_SPEC(137, 137, 0x480, 22),
+ MTK_PIN_IES_SMT_SPEC(138, 138, 0x480, 22),
+ MTK_PIN_IES_SMT_SPEC(139, 139, 0x480, 22),
+ MTK_PIN_IES_SMT_SPEC(140, 140, 0x480, 22),
+ MTK_PIN_IES_SMT_SPEC(141, 141, 0x480, 22),
+ MTK_PIN_IES_SMT_SPEC(142, 142, 0x480, 22),
+ MTK_PIN_IES_SMT_SPEC(143, 143, 0x480, 22),
+ MTK_PIN_IES_SMT_SPEC(144, 144, 0x480, 22),
+};
+
+static int mt8365_spec_pull_set(struct regmap *regmap, unsigned int pin,
+ unsigned char align, bool isup, unsigned int r1r0)
+{
+ return mtk_pctrl_spec_pull_set_samereg(regmap, mt8365_spec_pupd,
+ ARRAY_SIZE(mt8365_spec_pupd), pin, align, isup, r1r0);
+}
+
+static int mt8365_ies_smt_set(struct regmap *regmap, unsigned int pin,
+ unsigned char align, int value, enum pin_config_param arg)
+{
+ if (arg == PIN_CONFIG_INPUT_ENABLE)
+ return mtk_pconf_spec_set_ies_smt_range(regmap, mt8365_ies_set,
+ ARRAY_SIZE(mt8365_ies_set), pin, align, value);
+ else if (arg == PIN_CONFIG_INPUT_SCHMITT_ENABLE)
+ return mtk_pconf_spec_set_ies_smt_range(regmap, mt8365_smt_set,
+ ARRAY_SIZE(mt8365_smt_set), pin, align, value);
+ return -EINVAL;
+}
+
+static const struct mtk_pinctrl_devdata mt8365_pinctrl_data = {
+ .pins = mtk_pins_mt8365,
+ .npins = ARRAY_SIZE(mtk_pins_mt8365),
+ .grp_desc = mt8365_drv_grp,
+ .n_grp_cls = ARRAY_SIZE(mt8365_drv_grp),
+ .pin_drv_grp = mt8365_pin_drv,
+ .n_pin_drv_grps = ARRAY_SIZE(mt8365_pin_drv),
+ .spec_pull_set = mt8365_spec_pull_set,
+ .spec_ies_smt_set = mt8365_ies_smt_set,
+ .dir_offset = 0x0140,
+ .dout_offset = 0x00A0,
+ .din_offset = 0x0000,
+ .pinmux_offset = 0x01E0,
+ .ies_offset = 0x0410,
+ .smt_offset = 0x0470,
+ .pullen_offset = 0x0860,
+ .pullsel_offset = 0x0900,
+ .drv_offset = 0x0710,
+ .type1_start = 145,
+ .type1_end = 145,
+ .port_shf = 4,
+ .port_mask = 0x1f,
+ .port_align = 4,
+ .mode_mask = 0x1f,
+ .mode_per_reg = 10,
+ .mode_shf = 5,
+ .eint_hw = {
+ .port_mask = 7,
+ .ports = 5,
+ .ap_num = 160,
+ .db_cnt = 160,
+ },
+};
+
+static int mtk_pinctrl_probe(struct platform_device *pdev)
+{
+ return mtk_pctrl_init(pdev, &mt8365_pinctrl_data, NULL);
+}
+
+static const struct of_device_id mt8365_pctrl_match[] = {
+ {
+ .compatible = "mediatek,mt8365-pinctrl",
+ },
+ {}
+};
+
+static struct platform_driver mtk_pinctrl_driver = {
+ .probe = mtk_pinctrl_probe,
+ .driver = {
+ .name = "mediatek-mt8365-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = mt8365_pctrl_match,
+ .pm = &mtk_eint_pm_ops,
+ },
+};
+
+static int __init mtk_pinctrl_init(void)
+{
+ return platform_driver_register(&mtk_pinctrl_driver);
+}
+arch_initcall(mtk_pinctrl_init);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MediaTek MT8365 Pinctrl Driver");
+MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao@mediatek.com>");
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8516.c b/drivers/pinctrl/mediatek/pinctrl-mt8516.c
index b375426aa61e..219fb4bc341f 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8516.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8516.c
@@ -324,6 +324,9 @@ static const struct mtk_pinctrl_devdata mt8516_pinctrl_data = {
.port_shf = 4,
.port_mask = 0xf,
.port_align = 4,
+ .mode_mask = 0xf,
+ .mode_per_reg = 5,
+ .mode_shf = 4,
.eint_hw = {
.port_mask = 7,
.ports = 6,
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index a02ad10ec6fa..5f7c421ab6e7 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -33,7 +33,6 @@
#include "mtk-eint.h"
#include "pinctrl-mtk-common.h"
-#define MAX_GPIO_MODE_PER_REG 5
#define GPIO_MODE_BITS 3
#define GPIO_MODE_PREFIX "GPIO"
@@ -61,7 +60,7 @@ static struct regmap *mtk_get_regmap(struct mtk_pinctrl *pctl,
static unsigned int mtk_get_port(struct mtk_pinctrl *pctl, unsigned long pin)
{
/* Different SoC has different mask and port shift. */
- return ((pin >> 4) & pctl->devdata->port_mask)
+ return ((pin >> pctl->devdata->mode_shf) & pctl->devdata->port_mask)
<< pctl->devdata->port_shf;
}
@@ -74,7 +73,7 @@ static int mtk_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
- bit = BIT(offset & 0xf);
+ bit = BIT(offset & pctl->devdata->mode_mask);
if (pctl->devdata->spec_dir_set)
pctl->devdata->spec_dir_set(&reg_addr, offset);
@@ -96,7 +95,7 @@ static void mtk_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dout_offset;
- bit = BIT(offset & 0xf);
+ bit = BIT(offset & pctl->devdata->mode_mask);
if (value)
reg_addr = SET_ADDR(reg_addr, pctl);
@@ -135,13 +134,13 @@ static int mtk_pconf_set_ies_smt(struct mtk_pinctrl *pctl, unsigned pin,
pin, pctl->devdata->port_align, value, arg);
}
- bit = BIT(pin & 0xf);
-
if (arg == PIN_CONFIG_INPUT_ENABLE)
offset = pctl->devdata->ies_offset;
else
offset = pctl->devdata->smt_offset;
+ bit = BIT(offset & pctl->devdata->mode_mask);
+
if (value)
reg_addr = SET_ADDR(mtk_get_port(pctl, pin) + offset, pctl);
else
@@ -311,7 +310,7 @@ static int mtk_pconf_set_pull_select(struct mtk_pinctrl *pctl,
return -EINVAL;
}
- bit = BIT(pin & 0xf);
+ bit = BIT(pin & pctl->devdata->mode_mask);
if (enable)
reg_pullen = SET_ADDR(mtk_get_port(pctl, pin) +
pctl->devdata->pullen_offset, pctl);
@@ -683,11 +682,11 @@ static int mtk_pmx_set_mode(struct pinctrl_dev *pctldev,
pctl->devdata->spec_pinmux_set(mtk_get_regmap(pctl, pin),
pin, mode);
- reg_addr = ((pin / MAX_GPIO_MODE_PER_REG) << pctl->devdata->port_shf)
+ reg_addr = ((pin / pctl->devdata->mode_per_reg) << pctl->devdata->port_shf)
+ pctl->devdata->pinmux_offset;
mode &= mask;
- bit = pin % MAX_GPIO_MODE_PER_REG;
+ bit = pin % pctl->devdata->mode_per_reg;
mask <<= (GPIO_MODE_BITS * bit);
val = (mode << (GPIO_MODE_BITS * bit));
return regmap_update_bits(mtk_get_regmap(pctl, pin),
@@ -798,7 +797,7 @@ static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
- bit = BIT(offset & 0xf);
+ bit = BIT(offset & pctl->devdata->mode_mask);
if (pctl->devdata->spec_dir_set)
pctl->devdata->spec_dir_set(&reg_addr, offset);
@@ -820,7 +819,7 @@ static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset)
reg_addr = mtk_get_port(pctl, offset) +
pctl->devdata->din_offset;
- bit = BIT(offset & 0xf);
+ bit = BIT(offset & pctl->devdata->mode_mask);
regmap_read(pctl->regmap1, reg_addr, &read_val);
return !!(read_val & bit);
}
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
index 69364b56803f..98f27cdc609a 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
@@ -254,6 +254,9 @@ struct mtk_pinctrl_devdata {
unsigned char port_align;
struct mtk_eint_hw eint_hw;
struct mtk_eint_regs *eint_regs;
+ unsigned int mode_mask;
+ unsigned int mode_per_reg;
+ unsigned int mode_shf;
};
struct mtk_pinctrl {
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt8365.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8365.h
new file mode 100644
index 000000000000..39e17532c460
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8365.h
@@ -0,0 +1,1511 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Zhiyong Tao <zhiyong.tao@mediatek.com>
+ *
+ */
+
+#ifndef __PINCTRL_MTK_MT8365_H
+#define __PINCTRL_MTK_MT8365_H
+
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-mtk-common.h"
+
+static const struct mtk_desc_pin mtk_pins_mt8365[] = {
+ MTK_PIN(
+ PINCTRL_PIN(0, "GPIO0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 0),
+ MTK_FUNCTION(0, "GPIO0"),
+ MTK_FUNCTION(1, "DPI_D0"),
+ MTK_FUNCTION(2, "PWM_A"),
+ MTK_FUNCTION(3, "I2S2_BCK"),
+ MTK_FUNCTION(4, "EXT_TXD0"),
+ MTK_FUNCTION(5, "CONN_MCU_TDO"),
+ MTK_FUNCTION(7, "DBG_MON_A0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(1, "GPIO1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 1),
+ MTK_FUNCTION(0, "GPIO1"),
+ MTK_FUNCTION(1, "DPI_D1"),
+ MTK_FUNCTION(2, "PWM_B"),
+ MTK_FUNCTION(3, "I2S2_LRCK"),
+ MTK_FUNCTION(4, "EXT_TXD1"),
+ MTK_FUNCTION(5, "CONN_MCU_DBGACK_N"),
+ MTK_FUNCTION(7, "DBG_MON_A1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(2, "GPIO2"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 2),
+ MTK_FUNCTION(0, "GPIO2"),
+ MTK_FUNCTION(1, "DPI_D2"),
+ MTK_FUNCTION(2, "PWM_C"),
+ MTK_FUNCTION(3, "I2S2_MCK"),
+ MTK_FUNCTION(4, "EXT_TXD2"),
+ MTK_FUNCTION(5, "CONN_MCU_DBGI_N"),
+ MTK_FUNCTION(7, "DBG_MON_A2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(3, "GPIO3"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 3),
+ MTK_FUNCTION(0, "GPIO3"),
+ MTK_FUNCTION(1, "DPI_D3"),
+ MTK_FUNCTION(2, "CLKM0"),
+ MTK_FUNCTION(3, "I2S2_DI"),
+ MTK_FUNCTION(4, "EXT_TXD3"),
+ MTK_FUNCTION(5, "CONN_MCU_TCK"),
+ MTK_FUNCTION(6, "CONN_MCU_AICE_TCKC"),
+ MTK_FUNCTION(7, "DBG_MON_A3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(4, "GPIO4"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 4),
+ MTK_FUNCTION(0, "GPIO4"),
+ MTK_FUNCTION(1, "DPI_D4"),
+ MTK_FUNCTION(2, "CLKM1"),
+ MTK_FUNCTION(3, "I2S1_BCK"),
+ MTK_FUNCTION(4, "EXT_TXC"),
+ MTK_FUNCTION(5, "CONN_MCU_TDI"),
+ MTK_FUNCTION(6, "VDEC_TEST_CK"),
+ MTK_FUNCTION(7, "DBG_MON_A4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(5, "GPIO5"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 5),
+ MTK_FUNCTION(0, "GPIO5"),
+ MTK_FUNCTION(1, "DPI_D5"),
+ MTK_FUNCTION(2, "CLKM2"),
+ MTK_FUNCTION(3, "I2S1_LRCK"),
+ MTK_FUNCTION(4, "EXT_RXER"),
+ MTK_FUNCTION(5, "CONN_MCU_TRST_B"),
+ MTK_FUNCTION(6, "MM_TEST_CK"),
+ MTK_FUNCTION(7, "DBG_MON_A5")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(6, "GPIO6"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 6),
+ MTK_FUNCTION(0, "GPIO6"),
+ MTK_FUNCTION(1, "DPI_D6"),
+ MTK_FUNCTION(2, "CLKM3"),
+ MTK_FUNCTION(3, "I2S1_MCK"),
+ MTK_FUNCTION(4, "EXT_RXC"),
+ MTK_FUNCTION(5, "CONN_MCU_TMS"),
+ MTK_FUNCTION(6, "CONN_MCU_AICE_TMSC"),
+ MTK_FUNCTION(7, "DBG_MON_A6")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(7, "GPIO7"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 7),
+ MTK_FUNCTION(0, "GPIO7"),
+ MTK_FUNCTION(1, "DPI_D7"),
+ MTK_FUNCTION(3, "I2S1_DO"),
+ MTK_FUNCTION(4, "EXT_RXDV"),
+ MTK_FUNCTION(5, "CONN_DSP_JCK"),
+ MTK_FUNCTION(7, "DBG_MON_A7")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(8, "GPIO8"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 8),
+ MTK_FUNCTION(0, "GPIO8"),
+ MTK_FUNCTION(1, "DPI_D8"),
+ MTK_FUNCTION(2, "SPI_CLK"),
+ MTK_FUNCTION(3, "I2S0_BCK"),
+ MTK_FUNCTION(4, "EXT_RXD0"),
+ MTK_FUNCTION(5, "CONN_DSP_JINTP"),
+ MTK_FUNCTION(7, "DBG_MON_A8")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(9, "GPIO9"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 9),
+ MTK_FUNCTION(0, "GPIO9"),
+ MTK_FUNCTION(1, "DPI_D9"),
+ MTK_FUNCTION(2, "SPI_CSB"),
+ MTK_FUNCTION(3, "I2S0_LRCK"),
+ MTK_FUNCTION(4, "EXT_RXD1"),
+ MTK_FUNCTION(5, "CONN_DSP_JDI"),
+ MTK_FUNCTION(7, "DBG_MON_A9")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(10, "GPIO10"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 10),
+ MTK_FUNCTION(0, "GPIO10"),
+ MTK_FUNCTION(1, "DPI_D10"),
+ MTK_FUNCTION(2, "SPI_MI"),
+ MTK_FUNCTION(3, "I2S0_MCK"),
+ MTK_FUNCTION(4, "EXT_RXD2"),
+ MTK_FUNCTION(5, "CONN_DSP_JMS"),
+ MTK_FUNCTION(7, "DBG_MON_A10")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(11, "GPIO11"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 11),
+ MTK_FUNCTION(0, "GPIO11"),
+ MTK_FUNCTION(1, "DPI_D11"),
+ MTK_FUNCTION(2, "SPI_MO"),
+ MTK_FUNCTION(3, "I2S0_DI"),
+ MTK_FUNCTION(4, "EXT_RXD3"),
+ MTK_FUNCTION(5, "CONN_DSP_JDO"),
+ MTK_FUNCTION(7, "DBG_MON_A11")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(12, "GPIO12"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 12),
+ MTK_FUNCTION(0, "GPIO12"),
+ MTK_FUNCTION(1, "DPI_DE"),
+ MTK_FUNCTION(2, "UCTS1"),
+ MTK_FUNCTION(3, "I2S3_BCK"),
+ MTK_FUNCTION(4, "EXT_TXEN"),
+ MTK_FUNCTION(5, "O_WIFI_TXD"),
+ MTK_FUNCTION(7, "DBG_MON_A12")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(13, "GPIO13"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 13),
+ MTK_FUNCTION(0, "GPIO13"),
+ MTK_FUNCTION(1, "DPI_VSYNC"),
+ MTK_FUNCTION(2, "URTS1"),
+ MTK_FUNCTION(3, "I2S3_LRCK"),
+ MTK_FUNCTION(4, "EXT_COL"),
+ MTK_FUNCTION(5, "SPDIF_IN"),
+ MTK_FUNCTION(7, "DBG_MON_A13")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(14, "GPIO14"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 14),
+ MTK_FUNCTION(0, "GPIO14"),
+ MTK_FUNCTION(1, "DPI_CK"),
+ MTK_FUNCTION(2, "UCTS2"),
+ MTK_FUNCTION(3, "I2S3_MCK"),
+ MTK_FUNCTION(4, "EXT_MDIO"),
+ MTK_FUNCTION(5, "SPDIF_OUT"),
+ MTK_FUNCTION(6, "DVFSRC_EXT_REQ"),
+ MTK_FUNCTION(7, "DBG_MON_A14")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(15, "GPIO15"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 15),
+ MTK_FUNCTION(0, "GPIO15"),
+ MTK_FUNCTION(1, "DPI_HSYNC"),
+ MTK_FUNCTION(2, "URTS2"),
+ MTK_FUNCTION(3, "I2S3_DO"),
+ MTK_FUNCTION(4, "EXT_MDC"),
+ MTK_FUNCTION(5, "IRRX"),
+ MTK_FUNCTION(6, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(7, "DBG_MON_A15")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(16, "GPIO16"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 16),
+ MTK_FUNCTION(0, "GPIO16"),
+ MTK_FUNCTION(1, "DPI_D12"),
+ MTK_FUNCTION(2, "USB_DRVVBUS"),
+ MTK_FUNCTION(3, "PWM_A"),
+ MTK_FUNCTION(4, "CLKM0"),
+ MTK_FUNCTION(5, "ANT_SEL0"),
+ MTK_FUNCTION(6, "TSF_IN"),
+ MTK_FUNCTION(7, "DBG_MON_A16")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(17, "GPIO17"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 17),
+ MTK_FUNCTION(0, "GPIO17"),
+ MTK_FUNCTION(1, "DPI_D13"),
+ MTK_FUNCTION(2, "IDDIG"),
+ MTK_FUNCTION(3, "PWM_B"),
+ MTK_FUNCTION(4, "CLKM1"),
+ MTK_FUNCTION(5, "ANT_SEL1"),
+ MTK_FUNCTION(6, "DVFSRC_EXT_REQ"),
+ MTK_FUNCTION(7, "DBG_MON_A17")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(18, "GPIO18"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 18),
+ MTK_FUNCTION(0, "GPIO18"),
+ MTK_FUNCTION(1, "DPI_D14"),
+ MTK_FUNCTION(2, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(3, "PWM_C"),
+ MTK_FUNCTION(4, "CLKM2"),
+ MTK_FUNCTION(5, "ANT_SEL2"),
+ MTK_FUNCTION(6, "MFG_TEST_CK"),
+ MTK_FUNCTION(7, "DBG_MON_A18")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(19, "DISP_PWM"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 19),
+ MTK_FUNCTION(0, "GPIO19"),
+ MTK_FUNCTION(1, "DISP_PWM"),
+ MTK_FUNCTION(2, "PWM_A"),
+ MTK_FUNCTION(7, "DBG_MON_A19")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(20, "LCM_RST"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 20),
+ MTK_FUNCTION(0, "GPIO20"),
+ MTK_FUNCTION(1, "LCM_RST"),
+ MTK_FUNCTION(2, "PWM_B"),
+ MTK_FUNCTION(7, "DBG_MON_A20")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(21, "DSI_TE"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 21),
+ MTK_FUNCTION(0, "GPIO21"),
+ MTK_FUNCTION(1, "DSI_TE"),
+ MTK_FUNCTION(2, "PWM_C"),
+ MTK_FUNCTION(3, "ANT_SEL0"),
+ MTK_FUNCTION(4, "DVFSRC_EXT_REQ"),
+ MTK_FUNCTION(7, "DBG_MON_A21")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(22, "KPROW0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 22),
+ MTK_FUNCTION(0, "GPIO22"),
+ MTK_FUNCTION(1, "KPROW0"),
+ MTK_FUNCTION(7, "DBG_MON_A22")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(23, "KPROW1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 23),
+ MTK_FUNCTION(0, "GPIO23"),
+ MTK_FUNCTION(1, "KPROW1"),
+ MTK_FUNCTION(2, "IDDIG"),
+ MTK_FUNCTION(3, "WIFI_TXD"),
+ MTK_FUNCTION(4, "CLKM3"),
+ MTK_FUNCTION(5, "ANT_SEL1"),
+ MTK_FUNCTION(6, "EXT_FRAME_SYNC"),
+ MTK_FUNCTION(7, "DBG_MON_B0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(24, "KPCOL0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 24),
+ MTK_FUNCTION(0, "GPIO24"),
+ MTK_FUNCTION(1, "KPCOL0"),
+ MTK_FUNCTION(7, "DBG_MON_A23")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(25, "KPCOL1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 25),
+ MTK_FUNCTION(0, "GPIO25"),
+ MTK_FUNCTION(1, "KPCOL1"),
+ MTK_FUNCTION(2, "USB_DRVVBUS"),
+ MTK_FUNCTION(3, "APU_JTAG_TRST"),
+ MTK_FUNCTION(4, "UDI_NTRST_XI"),
+ MTK_FUNCTION(5, "DFD_NTRST_XI"),
+ MTK_FUNCTION(6, "CONN_TEST_CK"),
+ MTK_FUNCTION(7, "DBG_MON_B1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(26, "SPI_CS"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 26),
+ MTK_FUNCTION(0, "GPIO26"),
+ MTK_FUNCTION(1, "SPI_CSB"),
+ MTK_FUNCTION(3, "APU_JTAG_TMS"),
+ MTK_FUNCTION(4, "UDI_TMS_XI"),
+ MTK_FUNCTION(5, "DFD_TMS_XI"),
+ MTK_FUNCTION(6, "CONN_TEST_CK"),
+ MTK_FUNCTION(7, "DBG_MON_A24")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(27, "SPI_CK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 27),
+ MTK_FUNCTION(0, "GPIO27"),
+ MTK_FUNCTION(1, "SPI_CLK"),
+ MTK_FUNCTION(3, "APU_JTAG_TCK"),
+ MTK_FUNCTION(4, "UDI_TCK_XI"),
+ MTK_FUNCTION(5, "DFD_TCK_XI"),
+ MTK_FUNCTION(6, "APU_TEST_CK"),
+ MTK_FUNCTION(7, "DBG_MON_A25")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(28, "SPI_MI"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 28),
+ MTK_FUNCTION(0, "GPIO28"),
+ MTK_FUNCTION(1, "SPI_MI"),
+ MTK_FUNCTION(2, "SPI_MO"),
+ MTK_FUNCTION(3, "APU_JTAG_TDI"),
+ MTK_FUNCTION(4, "UDI_TDI_XI"),
+ MTK_FUNCTION(5, "DFD_TDI_XI"),
+ MTK_FUNCTION(6, "DSP_TEST_CK"),
+ MTK_FUNCTION(7, "DBG_MON_A26")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(29, "SPI_MO"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 29),
+ MTK_FUNCTION(0, "GPIO29"),
+ MTK_FUNCTION(1, "SPI_MO"),
+ MTK_FUNCTION(2, "SPI_MI"),
+ MTK_FUNCTION(3, "APU_JTAG_TDO"),
+ MTK_FUNCTION(4, "UDI_TDO"),
+ MTK_FUNCTION(5, "DFD_TDO"),
+ MTK_FUNCTION(6, "DVFSRC_EXT_REQ"),
+ MTK_FUNCTION(7, "DBG_MON_A27")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(30, "JTMS"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 30),
+ MTK_FUNCTION(0, "GPIO30"),
+ MTK_FUNCTION(1, "JTMS"),
+ MTK_FUNCTION(2, "DFD_TMS_XI"),
+ MTK_FUNCTION(3, "UDI_TMS_XI"),
+ MTK_FUNCTION(4, "MCU_SPM_TMS"),
+ MTK_FUNCTION(5, "CONN_MCU_TMS"),
+ MTK_FUNCTION(6, "CONN_MCU_AICE_TMSC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(31, "JTCK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 31),
+ MTK_FUNCTION(0, "GPIO31"),
+ MTK_FUNCTION(1, "JTCK"),
+ MTK_FUNCTION(2, "DFD_TCK_XI"),
+ MTK_FUNCTION(3, "UDI_TCK_XI"),
+ MTK_FUNCTION(4, "MCU_SPM_TCK"),
+ MTK_FUNCTION(5, "CONN_MCU_TCK"),
+ MTK_FUNCTION(6, "CONN_MCU_AICE_TCKC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(32, "JTDI"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 32),
+ MTK_FUNCTION(0, "GPIO32"),
+ MTK_FUNCTION(1, "JTDI"),
+ MTK_FUNCTION(2, "DFD_TDI_XI"),
+ MTK_FUNCTION(3, "UDI_TDI_XI"),
+ MTK_FUNCTION(4, "MCU_SPM_TDI"),
+ MTK_FUNCTION(5, "CONN_MCU_TDI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(33, "JTDO"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 33),
+ MTK_FUNCTION(0, "GPIO33"),
+ MTK_FUNCTION(1, "JTDO"),
+ MTK_FUNCTION(2, "DFD_TDO"),
+ MTK_FUNCTION(3, "UDI_TDO"),
+ MTK_FUNCTION(4, "MCU_SPM_TDO"),
+ MTK_FUNCTION(5, "CONN_MCU_TDO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(34, "JTRST"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 34),
+ MTK_FUNCTION(0, "GPIO34"),
+ MTK_FUNCTION(1, "JTRST"),
+ MTK_FUNCTION(2, "DFD_NTRST_XI"),
+ MTK_FUNCTION(3, "UDI_NTRST_XI"),
+ MTK_FUNCTION(4, "MCU_SPM_NTRST"),
+ MTK_FUNCTION(5, "CONN_MCU_TRST_B")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(35, "URXD0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 35),
+ MTK_FUNCTION(0, "GPIO35"),
+ MTK_FUNCTION(1, "URXD0"),
+ MTK_FUNCTION(2, "UTXD0"),
+ MTK_FUNCTION(7, "DSP_URXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(36, "UTXD0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 36),
+ MTK_FUNCTION(0, "GPIO36"),
+ MTK_FUNCTION(1, "UTXD0"),
+ MTK_FUNCTION(2, "URXD0"),
+ MTK_FUNCTION(7, "DSP_UTXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(37, "URXD1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 37),
+ MTK_FUNCTION(0, "GPIO37"),
+ MTK_FUNCTION(1, "URXD1"),
+ MTK_FUNCTION(2, "UTXD1"),
+ MTK_FUNCTION(3, "UCTS2"),
+ MTK_FUNCTION(4, "DVFSRC_EXT_REQ"),
+ MTK_FUNCTION(5, "CONN_UART0_RXD"),
+ MTK_FUNCTION(6, "I2S0_MCK"),
+ MTK_FUNCTION(7, "DSP_URXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(38, "UTXD1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 38),
+ MTK_FUNCTION(0, "GPIO38"),
+ MTK_FUNCTION(1, "UTXD1"),
+ MTK_FUNCTION(2, "URXD1"),
+ MTK_FUNCTION(3, "URTS2"),
+ MTK_FUNCTION(4, "ANT_SEL2"),
+ MTK_FUNCTION(5, "CONN_UART0_TXD"),
+ MTK_FUNCTION(6, "I2S1_MCK"),
+ MTK_FUNCTION(7, "DSP_UTXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(39, "URXD2"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 39),
+ MTK_FUNCTION(0, "GPIO39"),
+ MTK_FUNCTION(1, "URXD2"),
+ MTK_FUNCTION(2, "UTXD2"),
+ MTK_FUNCTION(3, "UCTS1"),
+ MTK_FUNCTION(4, "IDDIG"),
+ MTK_FUNCTION(5, "CONN_MCU_DBGACK_N"),
+ MTK_FUNCTION(6, "I2S2_MCK"),
+ MTK_FUNCTION(7, "DSP_URXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(40, "UTXD2"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 40),
+ MTK_FUNCTION(0, "GPIO40"),
+ MTK_FUNCTION(1, "UTXD2"),
+ MTK_FUNCTION(2, "URXD2"),
+ MTK_FUNCTION(3, "URTS1"),
+ MTK_FUNCTION(4, "USB_DRVVBUS"),
+ MTK_FUNCTION(5, "CONN_MCU_DBGI_N"),
+ MTK_FUNCTION(6, "I2S3_MCK"),
+ MTK_FUNCTION(7, "DSP_UTXD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(41, "PWRAP_SPI0_MI"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 41),
+ MTK_FUNCTION(0, "GPIO41"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_MI"),
+ MTK_FUNCTION(2, "PWRAP_SPI0_MO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(42, "PWRAP_SPI0_MO"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 42),
+ MTK_FUNCTION(0, "GPIO42"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_MO"),
+ MTK_FUNCTION(2, "PWRAP_SPI0_MI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(43, "PWRAP_SPI0_CK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 43),
+ MTK_FUNCTION(0, "GPIO43"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_CK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(44, "PWRAP_SPI0_CSN"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 44),
+ MTK_FUNCTION(0, "GPIO44"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_CSN")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(45, "RTC32K_CK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 45),
+ MTK_FUNCTION(0, "GPIO45"),
+ MTK_FUNCTION(1, "RTC32K_CK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(46, "WATCHDOG"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 46),
+ MTK_FUNCTION(0, "GPIO46"),
+ MTK_FUNCTION(1, "WATCHDOG")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(47, "SRCLKENA0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 47),
+ MTK_FUNCTION(0, "GPIO47"),
+ MTK_FUNCTION(1, "SRCLKENA0"),
+ MTK_FUNCTION(2, "SRCLKENA1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(48, "SRCLKENA1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 48),
+ MTK_FUNCTION(0, "GPIO48"),
+ MTK_FUNCTION(1, "SRCLKENA1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(49, "AUD_CLK_MOSI"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 49),
+ MTK_FUNCTION(0, "GPIO49"),
+ MTK_FUNCTION(1, "AUD_CLK_MOSI"),
+ MTK_FUNCTION(2, "AUD_CLK_MISO"),
+ MTK_FUNCTION(3, "I2S1_MCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(50, "AUD_SYNC_MOSI"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 50),
+ MTK_FUNCTION(0, "GPIO50"),
+ MTK_FUNCTION(1, "AUD_SYNC_MOSI"),
+ MTK_FUNCTION(2, "AUD_SYNC_MISO"),
+ MTK_FUNCTION(3, "I2S1_BCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(51, "AUD_DAT_MOSI0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 51),
+ MTK_FUNCTION(0, "GPIO51"),
+ MTK_FUNCTION(1, "AUD_DAT_MOSI0"),
+ MTK_FUNCTION(2, "AUD_DAT_MISO0"),
+ MTK_FUNCTION(3, "I2S1_LRCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(52, "AUD_DAT_MOSI1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 52),
+ MTK_FUNCTION(0, "GPIO52"),
+ MTK_FUNCTION(1, "AUD_DAT_MOSI1"),
+ MTK_FUNCTION(2, "AUD_DAT_MISO1"),
+ MTK_FUNCTION(3, "I2S1_DO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(53, "AUD_CLK_MISO"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 53),
+ MTK_FUNCTION(0, "GPIO53"),
+ MTK_FUNCTION(1, "AUD_CLK_MISO"),
+ MTK_FUNCTION(2, "AUD_CLK_MOSI"),
+ MTK_FUNCTION(3, "I2S2_MCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(54, "AUD_SYNC_MISO"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 54),
+ MTK_FUNCTION(0, "GPIO54"),
+ MTK_FUNCTION(1, "AUD_SYNC_MISO"),
+ MTK_FUNCTION(2, "AUD_SYNC_MOSI"),
+ MTK_FUNCTION(3, "I2S2_BCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(55, "AUD_DAT_MISO0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 55),
+ MTK_FUNCTION(0, "GPIO55"),
+ MTK_FUNCTION(1, "AUD_DAT_MISO0"),
+ MTK_FUNCTION(2, "AUD_DAT_MOSI0"),
+ MTK_FUNCTION(3, "I2S2_LRCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(56, "AUD_DAT_MISO1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 56),
+ MTK_FUNCTION(0, "GPIO56"),
+ MTK_FUNCTION(1, "AUD_DAT_MISO1"),
+ MTK_FUNCTION(2, "AUD_DAT_MOSI1"),
+ MTK_FUNCTION(3, "I2S2_DI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(57, "SDA0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 57),
+ MTK_FUNCTION(0, "GPIO57"),
+ MTK_FUNCTION(1, "SDA0_0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(58, "SCL0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 58),
+ MTK_FUNCTION(0, "GPIO58"),
+ MTK_FUNCTION(1, "SCL0_0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(59, "SDA1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 59),
+ MTK_FUNCTION(0, "GPIO59"),
+ MTK_FUNCTION(1, "SDA1_0"),
+ MTK_FUNCTION(6, "USB_SDA"),
+ MTK_FUNCTION(7, "DBG_SDA")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(60, "SCL1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 60),
+ MTK_FUNCTION(0, "GPIO60"),
+ MTK_FUNCTION(1, "SCL1_0"),
+ MTK_FUNCTION(6, "USB_SCL"),
+ MTK_FUNCTION(7, "DBG_SCL")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(61, "SDA2"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 61),
+ MTK_FUNCTION(0, "GPIO61"),
+ MTK_FUNCTION(1, "SDA2_0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(62, "SCL2"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 62),
+ MTK_FUNCTION(0, "GPIO62"),
+ MTK_FUNCTION(1, "SCL2_0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(63, "SDA3"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 63),
+ MTK_FUNCTION(0, "GPIO63"),
+ MTK_FUNCTION(1, "SDA3_0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(64, "SCL3"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 64),
+ MTK_FUNCTION(0, "GPIO64"),
+ MTK_FUNCTION(1, "SCL3_0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(65, "CMMCLK0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 65),
+ MTK_FUNCTION(0, "GPIO65"),
+ MTK_FUNCTION(1, "CMMCLK0"),
+ MTK_FUNCTION(2, "CMMCLK1"),
+ MTK_FUNCTION(7, "DBG_MON_A28")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(66, "CMMCLK1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 66),
+ MTK_FUNCTION(0, "GPIO66"),
+ MTK_FUNCTION(1, "CMMCLK1"),
+ MTK_FUNCTION(2, "CMMCLK0"),
+ MTK_FUNCTION(7, "DBG_MON_B2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(67, "CMPCLK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 67),
+ MTK_FUNCTION(0, "GPIO67"),
+ MTK_FUNCTION(1, "CMPCLK"),
+ MTK_FUNCTION(2, "ANT_SEL0"),
+ MTK_FUNCTION(4, "TDM_RX_BCK"),
+ MTK_FUNCTION(5, "I2S0_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_B3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(68, "CMDAT0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 68),
+ MTK_FUNCTION(0, "GPIO68"),
+ MTK_FUNCTION(1, "CMDAT0"),
+ MTK_FUNCTION(2, "ANT_SEL1"),
+ MTK_FUNCTION(4, "TDM_RX_LRCK"),
+ MTK_FUNCTION(5, "I2S0_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_B4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(69, "CMDAT1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 69),
+ MTK_FUNCTION(0, "GPIO69"),
+ MTK_FUNCTION(1, "CMDAT1"),
+ MTK_FUNCTION(2, "ANT_SEL2"),
+ MTK_FUNCTION(3, "DVFSRC_EXT_REQ"),
+ MTK_FUNCTION(4, "TDM_RX_MCK"),
+ MTK_FUNCTION(5, "I2S0_MCK"),
+ MTK_FUNCTION(7, "DBG_MON_B5")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(70, "CMDAT2"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 70),
+ MTK_FUNCTION(0, "GPIO70"),
+ MTK_FUNCTION(1, "CMDAT2"),
+ MTK_FUNCTION(2, "ANT_SEL3"),
+ MTK_FUNCTION(4, "TDM_RX_DI"),
+ MTK_FUNCTION(5, "I2S0_DI"),
+ MTK_FUNCTION(7, "DBG_MON_B6")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(71, "CMDAT3"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 71),
+ MTK_FUNCTION(0, "GPIO71"),
+ MTK_FUNCTION(1, "CMDAT3"),
+ MTK_FUNCTION(2, "ANT_SEL4"),
+ MTK_FUNCTION(7, "DBG_MON_B7")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(72, "CMDAT4"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 72),
+ MTK_FUNCTION(0, "GPIO72"),
+ MTK_FUNCTION(1, "CMDAT4"),
+ MTK_FUNCTION(2, "ANT_SEL5"),
+ MTK_FUNCTION(5, "I2S3_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_B8")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(73, "CMDAT5"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 73),
+ MTK_FUNCTION(0, "GPIO73"),
+ MTK_FUNCTION(1, "CMDAT5"),
+ MTK_FUNCTION(2, "ANT_SEL6"),
+ MTK_FUNCTION(5, "I2S3_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_B9")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(74, "CMDAT6"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 74),
+ MTK_FUNCTION(0, "GPIO74"),
+ MTK_FUNCTION(1, "CMDAT6"),
+ MTK_FUNCTION(2, "ANT_SEL7"),
+ MTK_FUNCTION(5, "I2S3_MCK"),
+ MTK_FUNCTION(7, "DBG_MON_B10")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(75, "CMDAT7"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 75),
+ MTK_FUNCTION(0, "GPIO75"),
+ MTK_FUNCTION(1, "CMDAT7"),
+ MTK_FUNCTION(5, "I2S3_DO"),
+ MTK_FUNCTION(7, "DBG_MON_B11")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(76, "CMDAT8"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 76),
+ MTK_FUNCTION(0, "GPIO76"),
+ MTK_FUNCTION(1, "CMDAT8"),
+ MTK_FUNCTION(5, "PCM_CLK"),
+ MTK_FUNCTION(7, "DBG_MON_A29")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(77, "CMDAT9"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 77),
+ MTK_FUNCTION(0, "GPIO77"),
+ MTK_FUNCTION(1, "CMDAT9"),
+ MTK_FUNCTION(5, "PCM_SYNC"),
+ MTK_FUNCTION(7, "DBG_MON_A30")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(78, "CMHSYNC"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 78),
+ MTK_FUNCTION(0, "GPIO78"),
+ MTK_FUNCTION(1, "CMHSYNC"),
+ MTK_FUNCTION(5, "PCM_RX"),
+ MTK_FUNCTION(7, "DBG_MON_A31")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(79, "CMVSYNC"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 79),
+ MTK_FUNCTION(0, "GPIO79"),
+ MTK_FUNCTION(1, "CMVSYNC"),
+ MTK_FUNCTION(5, "PCM_TX"),
+ MTK_FUNCTION(7, "DBG_MON_A32")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(80, "MSDC2_CMD"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 80),
+ MTK_FUNCTION(0, "GPIO80"),
+ MTK_FUNCTION(1, "MSDC2_CMD"),
+ MTK_FUNCTION(2, "TDM_TX_LRCK"),
+ MTK_FUNCTION(3, "UTXD1"),
+ MTK_FUNCTION(4, "DPI_D19"),
+ MTK_FUNCTION(5, "UDI_TMS_XI"),
+ MTK_FUNCTION(6, "ADSP_JTAG_TMS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(81, "MSDC2_CLK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 81),
+ MTK_FUNCTION(0, "GPIO81"),
+ MTK_FUNCTION(1, "MSDC2_CLK"),
+ MTK_FUNCTION(2, "TDM_TX_BCK"),
+ MTK_FUNCTION(3, "URXD1"),
+ MTK_FUNCTION(4, "DPI_D20"),
+ MTK_FUNCTION(5, "UDI_TCK_XI"),
+ MTK_FUNCTION(6, "ADSP_JTAG_TCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(82, "MSDC2_DAT0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 82),
+ MTK_FUNCTION(0, "GPIO82"),
+ MTK_FUNCTION(1, "MSDC2_DAT0"),
+ MTK_FUNCTION(2, "TDM_TX_DATA0"),
+ MTK_FUNCTION(3, "UTXD2"),
+ MTK_FUNCTION(4, "DPI_D21"),
+ MTK_FUNCTION(5, "UDI_TDI_XI"),
+ MTK_FUNCTION(6, "ADSP_JTAG_TDI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(83, "MSDC2_DAT1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 83),
+ MTK_FUNCTION(0, "GPIO83"),
+ MTK_FUNCTION(1, "MSDC2_DAT1"),
+ MTK_FUNCTION(2, "TDM_TX_DATA1"),
+ MTK_FUNCTION(3, "URXD2"),
+ MTK_FUNCTION(4, "DPI_D22"),
+ MTK_FUNCTION(5, "UDI_TDO"),
+ MTK_FUNCTION(6, "ADSP_JTAG_TDO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(84, "MSDC2_DAT2"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 84),
+ MTK_FUNCTION(0, "GPIO84"),
+ MTK_FUNCTION(1, "MSDC2_DAT2"),
+ MTK_FUNCTION(2, "TDM_TX_DATA2"),
+ MTK_FUNCTION(3, "PWM_A"),
+ MTK_FUNCTION(4, "DPI_D23"),
+ MTK_FUNCTION(5, "UDI_NTRST_XI"),
+ MTK_FUNCTION(6, "ADSP_JTAG_TRST")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(85, "MSDC2_DAT3"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 85),
+ MTK_FUNCTION(0, "GPIO85"),
+ MTK_FUNCTION(1, "MSDC2_DAT3"),
+ MTK_FUNCTION(2, "TDM_TX_DATA3"),
+ MTK_FUNCTION(3, "PWM_B"),
+ MTK_FUNCTION(5, "EXT_FRAME_SYNC")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(86, "MSDC2_DSL"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 86),
+ MTK_FUNCTION(0, "GPIO86"),
+ MTK_FUNCTION(1, "MSDC2_DSL"),
+ MTK_FUNCTION(2, "TDM_TX_MCK"),
+ MTK_FUNCTION(3, "PWM_C")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(87, "MSDC1_CMD"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 87),
+ MTK_FUNCTION(0, "GPIO87"),
+ MTK_FUNCTION(1, "MSDC1_CMD"),
+ MTK_FUNCTION(2, "CONN_MCU_AICE_TMSC"),
+ MTK_FUNCTION(3, "DFD_TMS_XI"),
+ MTK_FUNCTION(4, "APU_JTAG_TMS"),
+ MTK_FUNCTION(5, "MCU_SPM_TMS"),
+ MTK_FUNCTION(6, "CONN_DSP_JMS"),
+ MTK_FUNCTION(7, "ADSP_JTAG_TMS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(88, "MSDC1_CLK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 88),
+ MTK_FUNCTION(0, "GPIO88"),
+ MTK_FUNCTION(1, "MSDC1_CLK"),
+ MTK_FUNCTION(2, "CONN_MCU_AICE_TCKC"),
+ MTK_FUNCTION(3, "DFD_TCK_XI"),
+ MTK_FUNCTION(4, "APU_JTAG_TCK"),
+ MTK_FUNCTION(5, "MCU_SPM_TCK"),
+ MTK_FUNCTION(6, "CONN_DSP_JCK"),
+ MTK_FUNCTION(7, "ADSP_JTAG_TCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(89, "MSDC1_DAT0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 89),
+ MTK_FUNCTION(0, "GPIO89"),
+ MTK_FUNCTION(1, "MSDC1_DAT0"),
+ MTK_FUNCTION(2, "PWM_C"),
+ MTK_FUNCTION(3, "DFD_TDI_XI"),
+ MTK_FUNCTION(4, "APU_JTAG_TDI"),
+ MTK_FUNCTION(5, "MCU_SPM_TDI"),
+ MTK_FUNCTION(6, "CONN_DSP_JDI"),
+ MTK_FUNCTION(7, "ADSP_JTAG_TDI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(90, "MSDC1_DAT1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 90),
+ MTK_FUNCTION(0, "GPIO90"),
+ MTK_FUNCTION(1, "MSDC1_DAT1"),
+ MTK_FUNCTION(2, "SPDIF_IN"),
+ MTK_FUNCTION(3, "DFD_TDO"),
+ MTK_FUNCTION(4, "APU_JTAG_TDO"),
+ MTK_FUNCTION(5, "MCU_SPM_TDO"),
+ MTK_FUNCTION(6, "CONN_DSP_JDO"),
+ MTK_FUNCTION(7, "ADSP_JTAG_TDO")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(91, "MSDC1_DAT2"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 91),
+ MTK_FUNCTION(0, "GPIO91"),
+ MTK_FUNCTION(1, "MSDC1_DAT2"),
+ MTK_FUNCTION(2, "SPDIF_OUT"),
+ MTK_FUNCTION(3, "DFD_NTRST_XI"),
+ MTK_FUNCTION(4, "APU_JTAG_TRST"),
+ MTK_FUNCTION(5, "MCU_SPM_NTRST"),
+ MTK_FUNCTION(6, "CONN_DSP_JINTP"),
+ MTK_FUNCTION(7, "ADSP_JTAG_TRST")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(92, "MSDC1_DAT3"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 92),
+ MTK_FUNCTION(0, "GPIO92"),
+ MTK_FUNCTION(1, "MSDC1_DAT3"),
+ MTK_FUNCTION(2, "IRRX"),
+ MTK_FUNCTION(3, "PWM_A")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(93, "MSDC0_DAT7"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 93),
+ MTK_FUNCTION(0, "GPIO93"),
+ MTK_FUNCTION(1, "MSDC0_DAT7"),
+ MTK_FUNCTION(2, "NLD7")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(94, "MSDC0_DAT6"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 94),
+ MTK_FUNCTION(0, "GPIO94"),
+ MTK_FUNCTION(1, "MSDC0_DAT6"),
+ MTK_FUNCTION(2, "NLD6")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(95, "MSDC0_DAT5"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 95),
+ MTK_FUNCTION(0, "GPIO95"),
+ MTK_FUNCTION(1, "MSDC0_DAT5"),
+ MTK_FUNCTION(2, "NLD4")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(96, "MSDC0_DAT4"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 96),
+ MTK_FUNCTION(0, "GPIO96"),
+ MTK_FUNCTION(1, "MSDC0_DAT4"),
+ MTK_FUNCTION(2, "NLD3")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(97, "MSDC0_RSTB"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 97),
+ MTK_FUNCTION(0, "GPIO97"),
+ MTK_FUNCTION(1, "MSDC0_RSTB"),
+ MTK_FUNCTION(2, "NLD0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(98, "MSDC0_CMD"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 98),
+ MTK_FUNCTION(0, "GPIO98"),
+ MTK_FUNCTION(1, "MSDC0_CMD"),
+ MTK_FUNCTION(2, "NALE")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(99, "MSDC0_CLK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 99),
+ MTK_FUNCTION(0, "GPIO99"),
+ MTK_FUNCTION(1, "MSDC0_CLK"),
+ MTK_FUNCTION(2, "NWEB")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(100, "MSDC0_DAT3"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 100),
+ MTK_FUNCTION(0, "GPIO100"),
+ MTK_FUNCTION(1, "MSDC0_DAT3"),
+ MTK_FUNCTION(2, "NLD1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(101, "MSDC0_DAT2"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 101),
+ MTK_FUNCTION(0, "GPIO101"),
+ MTK_FUNCTION(1, "MSDC0_DAT2"),
+ MTK_FUNCTION(2, "NLD5")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(102, "MSDC0_DAT1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 102),
+ MTK_FUNCTION(0, "GPIO102"),
+ MTK_FUNCTION(1, "MSDC0_DAT1"),
+ MTK_FUNCTION(2, "NDQS")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(103, "MSDC0_DAT0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 103),
+ MTK_FUNCTION(0, "GPIO103"),
+ MTK_FUNCTION(1, "MSDC0_DAT0"),
+ MTK_FUNCTION(2, "NLD2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(104, "MSDC0_DSL"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 104),
+ MTK_FUNCTION(0, "GPIO104"),
+ MTK_FUNCTION(1, "MSDC0_DSL")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(105, "NCLE"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 105),
+ MTK_FUNCTION(0, "GPIO105"),
+ MTK_FUNCTION(1, "NCLE"),
+ MTK_FUNCTION(2, "TDM_RX_MCK"),
+ MTK_FUNCTION(7, "DBG_MON_B12")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(106, "NCEB1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 106),
+ MTK_FUNCTION(0, "GPIO106"),
+ MTK_FUNCTION(1, "NCEB1"),
+ MTK_FUNCTION(2, "TDM_RX_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_B13")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(107, "NCEB0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 107),
+ MTK_FUNCTION(0, "GPIO107"),
+ MTK_FUNCTION(1, "NCEB0"),
+ MTK_FUNCTION(2, "TDM_RX_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_B14")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(108, "NREB"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 108),
+ MTK_FUNCTION(0, "GPIO108"),
+ MTK_FUNCTION(1, "NREB"),
+ MTK_FUNCTION(2, "TDM_RX_DI"),
+ MTK_FUNCTION(7, "DBG_MON_B15")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(109, "NRNB"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 109),
+ MTK_FUNCTION(0, "GPIO109"),
+ MTK_FUNCTION(1, "NRNB"),
+ MTK_FUNCTION(2, "TSF_IN"),
+ MTK_FUNCTION(7, "DBG_MON_B16")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(110, "PCM_CLK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 110),
+ MTK_FUNCTION(0, "GPIO110"),
+ MTK_FUNCTION(1, "PCM_CLK"),
+ MTK_FUNCTION(2, "I2S0_BCK"),
+ MTK_FUNCTION(3, "I2S3_BCK"),
+ MTK_FUNCTION(4, "SPDIF_IN"),
+ MTK_FUNCTION(5, "DPI_D15")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(111, "PCM_SYNC"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 111),
+ MTK_FUNCTION(0, "GPIO111"),
+ MTK_FUNCTION(1, "PCM_SYNC"),
+ MTK_FUNCTION(2, "I2S0_LRCK"),
+ MTK_FUNCTION(3, "I2S3_LRCK"),
+ MTK_FUNCTION(4, "SPDIF_OUT"),
+ MTK_FUNCTION(5, "DPI_D16")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(112, "PCM_RX"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 112),
+ MTK_FUNCTION(0, "GPIO112"),
+ MTK_FUNCTION(1, "PCM_RX"),
+ MTK_FUNCTION(2, "I2S0_DI"),
+ MTK_FUNCTION(3, "I2S3_MCK"),
+ MTK_FUNCTION(4, "IRRX"),
+ MTK_FUNCTION(5, "DPI_D17")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(113, "PCM_TX"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 113),
+ MTK_FUNCTION(0, "GPIO113"),
+ MTK_FUNCTION(1, "PCM_TX"),
+ MTK_FUNCTION(2, "I2S0_MCK"),
+ MTK_FUNCTION(3, "I2S3_DO"),
+ MTK_FUNCTION(4, "PWM_B"),
+ MTK_FUNCTION(5, "DPI_D18")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(114, "I2S_DATA_IN"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 114),
+ MTK_FUNCTION(0, "GPIO114"),
+ MTK_FUNCTION(1, "I2S0_DI"),
+ MTK_FUNCTION(2, "I2S1_DO"),
+ MTK_FUNCTION(3, "I2S2_DI"),
+ MTK_FUNCTION(4, "I2S3_DO"),
+ MTK_FUNCTION(5, "PWM_A"),
+ MTK_FUNCTION(6, "SPDIF_IN"),
+ MTK_FUNCTION(7, "DBG_MON_B17")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(115, "I2S_LRCK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 115),
+ MTK_FUNCTION(0, "GPIO115"),
+ MTK_FUNCTION(1, "I2S0_LRCK"),
+ MTK_FUNCTION(2, "I2S1_LRCK"),
+ MTK_FUNCTION(3, "I2S2_LRCK"),
+ MTK_FUNCTION(4, "I2S3_LRCK"),
+ MTK_FUNCTION(5, "PWM_B"),
+ MTK_FUNCTION(6, "SPDIF_OUT"),
+ MTK_FUNCTION(7, "DBG_MON_B18")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(116, "I2S_BCK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 116),
+ MTK_FUNCTION(0, "GPIO116"),
+ MTK_FUNCTION(1, "I2S0_BCK"),
+ MTK_FUNCTION(2, "I2S1_BCK"),
+ MTK_FUNCTION(3, "I2S2_BCK"),
+ MTK_FUNCTION(4, "I2S3_BCK"),
+ MTK_FUNCTION(5, "PWM_C"),
+ MTK_FUNCTION(6, "IRRX"),
+ MTK_FUNCTION(7, "DBG_MON_B19")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(117, "DMIC0_CLK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 117),
+ MTK_FUNCTION(0, "GPIO117"),
+ MTK_FUNCTION(1, "DMIC0_CLK"),
+ MTK_FUNCTION(2, "I2S2_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_B20")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(118, "DMIC0_DAT0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 118),
+ MTK_FUNCTION(0, "GPIO118"),
+ MTK_FUNCTION(1, "DMIC0_DAT0"),
+ MTK_FUNCTION(2, "I2S2_DI"),
+ MTK_FUNCTION(7, "DBG_MON_B21")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(119, "DMIC0_DAT1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 119),
+ MTK_FUNCTION(0, "GPIO119"),
+ MTK_FUNCTION(1, "DMIC0_DAT1"),
+ MTK_FUNCTION(2, "I2S2_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_B22")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(120, "DMIC1_CLK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 120),
+ MTK_FUNCTION(0, "GPIO120"),
+ MTK_FUNCTION(1, "DMIC1_CLK"),
+ MTK_FUNCTION(2, "I2S2_MCK"),
+ MTK_FUNCTION(7, "DBG_MON_B23")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(121, "DMIC1_DAT0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 121),
+ MTK_FUNCTION(0, "GPIO121"),
+ MTK_FUNCTION(1, "DMIC1_DAT0"),
+ MTK_FUNCTION(2, "I2S1_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_B24")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(122, "DMIC1_DAT1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 122),
+ MTK_FUNCTION(0, "GPIO122"),
+ MTK_FUNCTION(1, "DMIC1_DAT1"),
+ MTK_FUNCTION(2, "I2S1_LRCK"),
+ MTK_FUNCTION(7, "DBG_MON_B25")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(123, "DMIC2_CLK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 123),
+ MTK_FUNCTION(0, "GPIO123"),
+ MTK_FUNCTION(1, "DMIC2_CLK"),
+ MTK_FUNCTION(2, "I2S1_MCK"),
+ MTK_FUNCTION(7, "DBG_MON_B26")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(124, "DMIC2_DAT0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 124),
+ MTK_FUNCTION(0, "GPIO124"),
+ MTK_FUNCTION(1, "DMIC2_DAT0"),
+ MTK_FUNCTION(2, "I2S1_DO"),
+ MTK_FUNCTION(7, "DBG_MON_B27")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(125, "DMIC2_DAT1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 125),
+ MTK_FUNCTION(0, "GPIO125"),
+ MTK_FUNCTION(1, "DMIC2_DAT1"),
+ MTK_FUNCTION(2, "TDM_RX_BCK"),
+ MTK_FUNCTION(7, "DBG_MON_B28")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(126, "DMIC3_CLK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 126),
+ MTK_FUNCTION(0, "GPIO126"),
+ MTK_FUNCTION(1, "DMIC3_CLK"),
+ MTK_FUNCTION(2, "TDM_RX_LRCK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(127, "DMIC3_DAT0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 127),
+ MTK_FUNCTION(0, "GPIO127"),
+ MTK_FUNCTION(1, "DMIC3_DAT0"),
+ MTK_FUNCTION(2, "TDM_RX_DI")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(128, "DMIC3_DAT1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 128),
+ MTK_FUNCTION(0, "GPIO128"),
+ MTK_FUNCTION(1, "DMIC3_DAT1"),
+ MTK_FUNCTION(2, "TDM_RX_MCK"),
+ MTK_FUNCTION(3, "VAD_CLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(129, "TDM_TX_BCK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 129),
+ MTK_FUNCTION(0, "GPIO129"),
+ MTK_FUNCTION(1, "TDM_TX_BCK"),
+ MTK_FUNCTION(2, "I2S3_BCK"),
+ MTK_FUNCTION(3, "ckmon1_ck")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(130, "TDM_TX_LRCK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 130),
+ MTK_FUNCTION(0, "GPIO130"),
+ MTK_FUNCTION(1, "TDM_TX_LRCK"),
+ MTK_FUNCTION(2, "I2S3_LRCK"),
+ MTK_FUNCTION(3, "ckmon2_ck")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(131, "TDM_TX_MCK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 131),
+ MTK_FUNCTION(0, "GPIO131"),
+ MTK_FUNCTION(1, "TDM_TX_MCK"),
+ MTK_FUNCTION(2, "I2S3_MCK"),
+ MTK_FUNCTION(3, "ckmon3_ck")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(132, "TDM_TX_DATA0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 132),
+ MTK_FUNCTION(0, "GPIO132"),
+ MTK_FUNCTION(1, "TDM_TX_DATA0"),
+ MTK_FUNCTION(2, "I2S3_DO"),
+ MTK_FUNCTION(3, "ckmon4_ck"),
+ MTK_FUNCTION(7, "DBG_MON_B29")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(133, "TDM_TX_DATA1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 133),
+ MTK_FUNCTION(0, "GPIO133"),
+ MTK_FUNCTION(1, "TDM_TX_DATA1"),
+ MTK_FUNCTION(7, "DBG_MON_B30")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(134, "TDM_TX_DATA2"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 134),
+ MTK_FUNCTION(0, "GPIO134"),
+ MTK_FUNCTION(1, "TDM_TX_DATA2"),
+ MTK_FUNCTION(7, "DBG_MON_B31")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(135, "TDM_TX_DATA3"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 135),
+ MTK_FUNCTION(0, "GPIO135"),
+ MTK_FUNCTION(1, "TDM_TX_DATA3"),
+ MTK_FUNCTION(7, "DBG_MON_B32")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(136, "CONN_TOP_CLK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 136),
+ MTK_FUNCTION(0, "GPIO136"),
+ MTK_FUNCTION(1, "CONN_TOP_CLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(137, "CONN_TOP_DATA"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 137),
+ MTK_FUNCTION(0, "GPIO137"),
+ MTK_FUNCTION(1, "CONN_TOP_DATA")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(138, "CONN_HRST_B"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 138),
+ MTK_FUNCTION(0, "GPIO138"),
+ MTK_FUNCTION(1, "CONN_HRST_B")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(139, "CONN_WB_PTA"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 139),
+ MTK_FUNCTION(0, "GPIO139"),
+ MTK_FUNCTION(1, "CONN_WB_PTA")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(140, "CONN_BT_CLK"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 140),
+ MTK_FUNCTION(0, "GPIO140"),
+ MTK_FUNCTION(1, "CONN_BT_CLK")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(141, "CONN_BT_DATA"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 141),
+ MTK_FUNCTION(0, "GPIO141"),
+ MTK_FUNCTION(1, "CONN_BT_DATA")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(142, "CONN_WF_CTRL0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 142),
+ MTK_FUNCTION(0, "GPIO142"),
+ MTK_FUNCTION(1, "CONN_WF_CTRL0")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(143, "CONN_WF_CTRL1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 143),
+ MTK_FUNCTION(0, "GPIO143"),
+ MTK_FUNCTION(1, "CONN_WF_CTRL1")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(144, "CONN_WF_CTRL2"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 144),
+ MTK_FUNCTION(0, "GPIO144"),
+ MTK_FUNCTION(1, "CONN_WF_CTRL2")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(145, "TESTMODE"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 145),
+ MTK_FUNCTION(0, "GPIO145")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(146, "SYSRSTB"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 146),
+ MTK_FUNCTION(0, "GPIO146")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(147, "BIAS_MSDC0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 147),
+ MTK_FUNCTION(0, "GPIO147")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(148, "BIAS_IO0"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 148),
+ MTK_FUNCTION(0, "GPIO148")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(149, "BIAS1_IO1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 149),
+ MTK_FUNCTION(0, "GPIO149")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(150, "BIAS2_IO1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 150),
+ MTK_FUNCTION(0, "GPIO150")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(151, "BIAS_DPI"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 151),
+ MTK_FUNCTION(0, "GPIO151")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(152, "BIAS_MSDC2"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 152),
+ MTK_FUNCTION(0, "GPIO152")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(153, "BIAS_IO2"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 153),
+ MTK_FUNCTION(0, "GPIO153")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(154, "BIAS_IO3"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 154),
+ MTK_FUNCTION(0, "GPIO154")
+ ),
+ MTK_PIN(
+ PINCTRL_PIN(155, "BIAS1_MSDC1"),
+ NULL, "mt8365",
+ MTK_EINT_FUNCTION(0, 155),
+ MTK_FUNCTION(0, "GPIO155")
+ ),
+};
+
+#endif /* __PINCTRL_MTK_MT8365_H */
diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c
index 2535ca720668..bb1ea47ec4c6 100644
--- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c
+++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c
@@ -958,8 +958,8 @@ static const struct npcm7xx_pincfg pincfg[] = {
NPCM7XX_PINCFG(31, smb3, MFSEL1, 0, none, NONE, 0, none, NONE, 0, 0),
NPCM7XX_PINCFG(32, spi0cs1, MFSEL1, 3, none, NONE, 0, none, NONE, 0, 0),
- NPCM7XX_PINCFG(33, none, NONE, 0, none, NONE, 0, none, NONE, 0, SLEW),
- NPCM7XX_PINCFG(34, none, NONE, 0, none, NONE, 0, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(33, none, NONE, 0, none, NONE, 0, none, NONE, 0, SLEW),
+ NPCM7XX_PINCFG(34, none, NONE, 0, none, NONE, 0, none, NONE, 0, SLEW),
NPCM7XX_PINCFG(37, smb3c, I2CSEGSEL, 12, none, NONE, 0, none, NONE, 0, SLEW),
NPCM7XX_PINCFG(38, smb3c, I2CSEGSEL, 12, none, NONE, 0, none, NONE, 0, SLEW),
NPCM7XX_PINCFG(39, smb3b, I2CSEGSEL, 11, none, NONE, 0, none, NONE, 0, SLEW),
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 2d4acf21117c..a76be6cc26ee 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -438,6 +438,29 @@ static void amd_gpio_irq_unmask(struct irq_data *d)
raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
}
+static int amd_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ u32 pin_reg;
+ unsigned long flags;
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
+ u32 wake_mask = BIT(WAKE_CNTRL_OFF_S0I3) | BIT(WAKE_CNTRL_OFF_S3) |
+ BIT(WAKE_CNTRL_OFF_S4);
+
+ raw_spin_lock_irqsave(&gpio_dev->lock, flags);
+ pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
+
+ if (on)
+ pin_reg |= wake_mask;
+ else
+ pin_reg &= ~wake_mask;
+
+ writel(pin_reg, gpio_dev->base + (d->hwirq)*4);
+ raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
+
+ return 0;
+}
+
static void amd_gpio_irq_eoi(struct irq_data *d)
{
u32 reg;
@@ -552,9 +575,16 @@ static struct irq_chip amd_gpio_irqchip = {
.irq_disable = amd_gpio_irq_disable,
.irq_mask = amd_gpio_irq_mask,
.irq_unmask = amd_gpio_irq_unmask,
+ .irq_set_wake = amd_gpio_irq_set_wake,
.irq_eoi = amd_gpio_irq_eoi,
.irq_set_type = amd_gpio_irq_set_type,
- .flags = IRQCHIP_SKIP_SET_WAKE,
+ /*
+ * We need to set IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND so that a wake event
+ * also generates an IRQ. We need the IRQ so the irq_handler can clear
+ * the wake event. Otherwise the wake event will never clear and
+ * prevent the system from suspending.
+ */
+ .flags = IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND,
};
#define PIN_IRQ_PENDING (BIT(INTERRUPT_STS_OFF) | BIT(WAKE_STS_OFF))
@@ -991,6 +1021,7 @@ static int amd_gpio_remove(struct platform_device *pdev)
static const struct acpi_device_id amd_gpio_acpi_match[] = {
{ "AMD0030", 0 },
{ "AMDI0030", 0},
+ { "AMDI0031", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, amd_gpio_acpi_match);
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index fc61aaec34cc..72e6df7abe8c 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -42,7 +42,7 @@ struct at91_gpio_chip {
int pioc_idx; /* PIO bank index */
void __iomem *regbase; /* PIO bank virtual address */
struct clk *clock; /* associated clock */
- struct at91_pinctrl_mux_ops *ops; /* ops */
+ const struct at91_pinctrl_mux_ops *ops; /* ops */
};
static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS];
@@ -210,7 +210,7 @@ struct at91_pinctrl {
struct at91_pin_group *groups;
int ngroups;
- struct at91_pinctrl_mux_ops *ops;
+ const struct at91_pinctrl_mux_ops *ops;
};
static inline const struct at91_pin_group *at91_pinctrl_find_group_by_name(
@@ -688,7 +688,7 @@ static void at91_mux_sam9x60_set_slewrate(void __iomem *pio, unsigned pin,
writel_relaxed(tmp, pio + SAM9X60_PIO_SLEWR);
}
-static struct at91_pinctrl_mux_ops at91rm9200_ops = {
+static const struct at91_pinctrl_mux_ops at91rm9200_ops = {
.get_periph = at91_mux_get_periph,
.mux_A_periph = at91_mux_set_A_periph,
.mux_B_periph = at91_mux_set_B_periph,
@@ -697,7 +697,7 @@ static struct at91_pinctrl_mux_ops at91rm9200_ops = {
.irq_type = gpio_irq_type,
};
-static struct at91_pinctrl_mux_ops at91sam9x5_ops = {
+static const struct at91_pinctrl_mux_ops at91sam9x5_ops = {
.get_periph = at91_mux_pio3_get_periph,
.mux_A_periph = at91_mux_pio3_set_A_periph,
.mux_B_periph = at91_mux_pio3_set_B_periph,
@@ -737,7 +737,7 @@ static const struct at91_pinctrl_mux_ops sam9x60_ops = {
.irq_type = alt_gpio_irq_type,
};
-static struct at91_pinctrl_mux_ops sama5d3_ops = {
+static const struct at91_pinctrl_mux_ops sama5d3_ops = {
.get_periph = at91_mux_pio3_get_periph,
.mux_A_periph = at91_mux_pio3_set_A_periph,
.mux_B_periph = at91_mux_pio3_set_B_periph,
@@ -1284,7 +1284,7 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev,
return -ENODEV;
info->dev = &pdev->dev;
- info->ops = (struct at91_pinctrl_mux_ops *)
+ info->ops = (const struct at91_pinctrl_mux_ops *)
of_match_device(at91_pinctrl_of_match, &pdev->dev)->data;
at91_pinctrl_child_count(info, np);
@@ -1849,7 +1849,7 @@ static int at91_gpio_probe(struct platform_device *pdev)
goto err;
}
- at91_chip->ops = (struct at91_pinctrl_mux_ops *)
+ at91_chip->ops = (const struct at91_pinctrl_mux_ops *)
of_match_device(at91_gpio_of_match, &pdev->dev)->data;
at91_chip->pioc_virq = irq;
at91_chip->pioc_idx = alias_idx;
diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c
index a194d8089b6f..38cc20fa9d5a 100644
--- a/drivers/pinctrl/pinctrl-equilibrium.c
+++ b/drivers/pinctrl/pinctrl-equilibrium.c
@@ -939,6 +939,7 @@ static const struct of_device_id eqbr_pinctrl_dt_match[] = {
{ .compatible = "intel,lgm-io" },
{}
};
+MODULE_DEVICE_TABLE(of, eqbr_pinctrl_dt_match);
static struct platform_driver eqbr_pinctrl_driver = {
.probe = eqbr_pinctrl_probe,
diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c
index ce2d8014b7e0..bccebe43dd6a 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08.c
+++ b/drivers/pinctrl/pinctrl-mcp23s08.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/export.h>
#include <linux/gpio/driver.h>
+#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <asm/byteorder.h>
#include <linux/interrupt.h>
@@ -351,6 +352,11 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
if (mcp_read(mcp, MCP_INTF, &intf))
goto unlock;
+ if (intf == 0) {
+ /* There is no interrupt pending */
+ goto unlock;
+ }
+
if (mcp_read(mcp, MCP_INTCAP, &intcap))
goto unlock;
@@ -368,11 +374,6 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
mcp->cached_gpio = gpio;
mutex_unlock(&mcp->lock);
- if (intf == 0) {
- /* There is no interrupt pending */
- return IRQ_HANDLED;
- }
-
dev_dbg(mcp->chip.parent,
"intcap 0x%04X intf 0x%04X gpio_orig 0x%04X gpio 0x%04X\n",
intcap, intf, gpio_orig, gpio);
@@ -558,6 +559,8 @@ int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
mcp->chip.parent = dev;
mcp->chip.owner = THIS_MODULE;
+ mcp->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+
/* verify MCP_IOCON.SEQOP = 0, so sequential reads work,
* and MCP_IOCON.HAEN = 1, so we work with all chips.
*/
diff --git a/drivers/pinctrl/pinctrl-mcp23s08.h b/drivers/pinctrl/pinctrl-mcp23s08.h
index 90dc27081a3c..b8d15939e0c2 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08.h
+++ b/drivers/pinctrl/pinctrl-mcp23s08.h
@@ -43,6 +43,7 @@ struct mcp23s08 {
struct pinctrl_dev *pctldev;
struct pinctrl_desc pinctrl_desc;
+ struct gpio_desc *reset_gpio;
};
extern const struct regmap_config mcp23x08_regmap;
diff --git a/drivers/pinctrl/pinctrl-microchip-sgpio.c b/drivers/pinctrl/pinctrl-microchip-sgpio.c
index c12fa57ebd12..165cb7a59715 100644
--- a/drivers/pinctrl/pinctrl-microchip-sgpio.c
+++ b/drivers/pinctrl/pinctrl-microchip-sgpio.c
@@ -845,8 +845,10 @@ static int microchip_sgpio_probe(struct platform_device *pdev)
i = 0;
device_for_each_child_node(dev, fwnode) {
ret = microchip_sgpio_register_bank(dev, priv, fwnode, i++);
- if (ret)
+ if (ret) {
+ fwnode_handle_put(fwnode);
return ret;
+ }
}
if (priv->in.gpio.ngpio != priv->out.gpio.ngpio) {
diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c
index 2fd18e356d0c..e470c16718de 100644
--- a/drivers/pinctrl/pinctrl-ocelot.c
+++ b/drivers/pinctrl/pinctrl-ocelot.c
@@ -1362,10 +1362,8 @@ static int ocelot_pinctrl_probe(struct platform_device *pdev)
base = devm_ioremap_resource(dev,
platform_get_resource(pdev, IORESOURCE_MEM, 0));
- if (IS_ERR(base)) {
- dev_err(dev, "Failed to ioremap registers\n");
+ if (IS_ERR(base))
return PTR_ERR(base);
- }
info->stride = 1 + (info->desc->npins - 1) / 32;
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 2c9c9835f375..e3aa64798f7d 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -534,6 +534,7 @@ static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
case PIN_CONFIG_DRIVE_STRENGTH:
case PIN_CONFIG_SLEW_RATE:
case PIN_CONFIG_MODE_LOW_POWER:
+ case PIN_CONFIG_INPUT_ENABLE:
default:
*config = data;
break;
@@ -572,6 +573,7 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
case PIN_CONFIG_DRIVE_STRENGTH:
case PIN_CONFIG_SLEW_RATE:
case PIN_CONFIG_MODE_LOW_POWER:
+ case PIN_CONFIG_INPUT_ENABLE:
shift = ffs(func->conf[i].mask) - 1;
data &= ~func->conf[i].mask;
data |= (arg << shift) & func->conf[i].mask;
@@ -918,6 +920,7 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
static const struct pcs_conf_type prop2[] = {
{ "pinctrl-single,drive-strength", PIN_CONFIG_DRIVE_STRENGTH, },
{ "pinctrl-single,slew-rate", PIN_CONFIG_SLEW_RATE, },
+ { "pinctrl-single,input-enable", PIN_CONFIG_INPUT_ENABLE, },
{ "pinctrl-single,input-schmitt", PIN_CONFIG_INPUT_SCHMITT, },
{ "pinctrl-single,low-power-mode", PIN_CONFIG_MODE_LOW_POWER, },
};
@@ -1513,7 +1516,7 @@ static irqreturn_t pcs_irq_handler(int irq, void *d)
}
/**
- * pcs_irq_handle() - handler for the dedicated chained interrupt case
+ * pcs_irq_chain_handler() - handler for the dedicated chained interrupt case
* @desc: interrupt descriptor
*
* Use this if you have a separate interrupt for each
diff --git a/drivers/pinctrl/pinctrl-zynqmp.c b/drivers/pinctrl/pinctrl-zynqmp.c
index d5497003ce71..bbde676b7313 100644
--- a/drivers/pinctrl/pinctrl-zynqmp.c
+++ b/drivers/pinctrl/pinctrl-zynqmp.c
@@ -2,7 +2,7 @@
/*
* ZynqMP pin controller
*
- * Copyright (C) 2020 Xilinx, Inc.
+ * Copyright (C) 2020, 2021 Xilinx, Inc.
*
* Sai Krishna Potthuri <lakshmi.sai.krishna.potthuri@xilinx.com>
* Rajan Vaja <rajan.vaja@xilinx.com>
@@ -252,9 +252,6 @@ static int zynqmp_pinconf_cfg_get(struct pinctrl_dev *pctldev,
unsigned int arg, param = pinconf_to_config_param(*config);
int ret;
- if (pin >= zynqmp_desc.npins)
- return -EOPNOTSUPP;
-
switch (param) {
case PIN_CONFIG_SLEW_RATE:
param = PM_PINCTRL_CONFIG_SLEW_RATE;
@@ -317,7 +314,7 @@ static int zynqmp_pinconf_cfg_get(struct pinctrl_dev *pctldev,
}
break;
default:
- ret = -EOPNOTSUPP;
+ ret = -ENOTSUPP;
break;
}
@@ -348,9 +345,6 @@ static int zynqmp_pinconf_cfg_set(struct pinctrl_dev *pctldev,
{
int i, ret;
- if (pin >= zynqmp_desc.npins)
- return -EOPNOTSUPP;
-
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]);
@@ -428,7 +422,7 @@ static int zynqmp_pinconf_cfg_set(struct pinctrl_dev *pctldev,
dev_warn(pctldev->dev,
"unsupported configuration parameter '%u'\n",
param);
- ret = -EOPNOTSUPP;
+ ret = -ENOTSUPP;
break;
}
@@ -504,7 +498,7 @@ static int zynqmp_pinctrl_get_function_groups(u32 fid, u32 index, u16 *groups)
memcpy(groups, &payload[1], PINCTRL_GET_FUNC_GROUPS_RESP_LEN);
- return ret;
+ return 0;
}
static int zynqmp_pinctrl_get_func_num_groups(u32 fid, unsigned int *ngroups)
@@ -522,7 +516,7 @@ static int zynqmp_pinctrl_get_func_num_groups(u32 fid, unsigned int *ngroups)
*ngroups = payload[1];
- return ret;
+ return 0;
}
/**
@@ -533,16 +527,16 @@ static int zynqmp_pinctrl_get_func_num_groups(u32 fid, unsigned int *ngroups)
* @groups: Groups data.
*
* Query firmware to get group IDs for each function. Firmware returns
- * group IDs. Based on group index for the function, group names in
+ * group IDs. Based on the group index for the function, group names in
* the function are stored. For example, the first group in "eth0" function
- * is named as "eth0_0" and second group as "eth0_1" and so on.
+ * is named as "eth0_0" and the second group as "eth0_1" and so on.
*
* Based on the group ID received from the firmware, function stores name of
* the group for that group ID. For example, if "eth0" first group ID
* is x, groups[x] name will be stored as "eth0_0".
*
* Once done for each function, each function would have its group names
- * and each groups would also have their names.
+ * and each group would also have their names.
*
* Return: 0 on success else error code.
*/
@@ -552,7 +546,7 @@ static int zynqmp_pinctrl_prepare_func_groups(struct device *dev, u32 fid,
{
u16 resp[NUM_GROUPS_PER_RESP] = {0};
const char **fgroups;
- int ret = 0, index, i;
+ int ret, index, i;
fgroups = devm_kzalloc(dev, sizeof(*fgroups) * func->ngroups, GFP_KERNEL);
if (!fgroups)
@@ -588,7 +582,7 @@ static int zynqmp_pinctrl_prepare_func_groups(struct device *dev, u32 fid,
done:
func->groups = fgroups;
- return ret;
+ return 0;
}
static void zynqmp_pinctrl_get_function_name(u32 fid, char *name)
@@ -622,7 +616,7 @@ static int zynqmp_pinctrl_get_num_functions(unsigned int *nfuncs)
*nfuncs = payload[1];
- return ret;
+ return 0;
}
static int zynqmp_pinctrl_get_pin_groups(u32 pin, u32 index, u16 *groups)
@@ -641,7 +635,7 @@ static int zynqmp_pinctrl_get_pin_groups(u32 pin, u32 index, u16 *groups)
memcpy(groups, &payload[1], PINCTRL_GET_PIN_GROUPS_RESP_LEN);
- return ret;
+ return 0;
}
static void zynqmp_pinctrl_group_add_pin(struct zynqmp_pctrl_group *group,
@@ -660,7 +654,7 @@ static void zynqmp_pinctrl_group_add_pin(struct zynqmp_pctrl_group *group,
* Based on the firmware response(group IDs for the pin), add
* pin number to the respective group's pin array.
*
- * Once all pins are queries, each groups would have its number
+ * Once all pins are queries, each group would have its number
* of pins and pin numbers data.
*
* Return: 0 on success else error code.
@@ -689,7 +683,7 @@ static int zynqmp_pinctrl_create_pin_groups(struct device *dev,
index += NUM_GROUPS_PER_RESP;
} while (index <= MAX_PIN_GROUPS);
- return ret;
+ return 0;
}
/**
@@ -727,7 +721,7 @@ static int zynqmp_pinctrl_prepare_group_pins(struct device *dev,
* prepare pin control driver data.
*
* Query number of functions and number of function groups (number
- * of groups in given function) to allocate required memory buffers
+ * of groups in the given function) to allocate required memory buffers
* for functions and groups. Once buffers are allocated to store
* functions and groups data, query and store required information
* (number of groups and group names for each function, number of
@@ -778,7 +772,7 @@ static int zynqmp_pinctrl_prepare_function_info(struct device *dev,
pctrl->funcs = funcs;
pctrl->groups = groups;
- return ret;
+ return 0;
}
static int zynqmp_pinctrl_get_num_pins(unsigned int *npins)
@@ -795,7 +789,7 @@ static int zynqmp_pinctrl_get_num_pins(unsigned int *npins)
*npins = payload[1];
- return ret;
+ return 0;
}
/**
@@ -853,19 +847,17 @@ static int zynqmp_pinctrl_probe(struct platform_device *pdev)
&zynqmp_desc.pins,
&zynqmp_desc.npins);
if (ret) {
- dev_err(&pdev->dev, "pin desc prepare fail with %d\n",
- ret);
+ dev_err(&pdev->dev, "pin desc prepare fail with %d\n", ret);
return ret;
}
ret = zynqmp_pinctrl_prepare_function_info(&pdev->dev, pctrl);
if (ret) {
- dev_err(&pdev->dev, "function info prepare fail with %d\n",
- ret);
+ dev_err(&pdev->dev, "function info prepare fail with %d\n", ret);
return ret;
}
- pctrl->pctrl = pinctrl_register(&zynqmp_desc, &pdev->dev, pctrl);
+ pctrl->pctrl = devm_pinctrl_register(&pdev->dev, &zynqmp_desc, pctrl);
if (IS_ERR(pctrl->pctrl))
return PTR_ERR(pctrl->pctrl);
@@ -887,7 +879,6 @@ static const struct of_device_id zynqmp_pinctrl_of_match[] = {
{ .compatible = "xlnx,zynqmp-pinctrl" },
{ }
};
-
MODULE_DEVICE_TABLE(of, zynqmp_pinctrl_of_match);
static struct platform_driver zynqmp_pinctrl_driver = {
@@ -898,7 +889,6 @@ static struct platform_driver zynqmp_pinctrl_driver = {
.probe = zynqmp_pinctrl_probe,
.remove = zynqmp_pinctrl_remove,
};
-
module_platform_driver(zynqmp_pinctrl_driver);
MODULE_AUTHOR("Sai Krishna Potthuri <lakshmi.sai.krishna.potthuri@xilinx.com>");
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 11e967dbb44b..2f51b4f99393 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -256,6 +256,15 @@ config PINCTRL_SDX55
Qualcomm Technologies Inc TLMM block found on the Qualcomm
Technologies Inc SDX55 platform.
+config PINCTRL_SM6125
+ tristate "Qualcomm Technologies Inc SM6125 pin controller driver"
+ depends on GPIOLIB && OF
+ depends on 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 SM6125 platform.
+
config PINCTRL_SM8150
tristate "Qualcomm Technologies Inc SM8150 pin controller driver"
depends on GPIOLIB && OF
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index d4301fbb7274..d696fe2789bb 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_PINCTRL_SC8180X) += pinctrl-sc8180x.o
obj-$(CONFIG_PINCTRL_SDM660) += pinctrl-sdm660.o
obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o
obj-$(CONFIG_PINCTRL_SDX55) += pinctrl-sdx55.o
+obj-$(CONFIG_PINCTRL_SM6125) += pinctrl-sm6125.o
obj-$(CONFIG_PINCTRL_SM8150) += pinctrl-sm8150.o
obj-$(CONFIG_PINCTRL_SM8250) += pinctrl-sm8250.o
obj-$(CONFIG_PINCTRL_SM8350) += pinctrl-sm8350.o
diff --git a/drivers/pinctrl/qcom/pinctrl-sm6125.c b/drivers/pinctrl/qcom/pinctrl-sm6125.c
new file mode 100644
index 000000000000..724fa5a34465
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sm6125.c
@@ -0,0 +1,1277 @@
+//SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+
+#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 sm6125_tiles[] = {
+ "south",
+ "east",
+ "west"
+};
+
+enum {
+ 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 = 0x4 + 0x1000 * id, \
+ .intr_cfg_reg = 0x8 + 0x1000 * id, \
+ .intr_status_reg = 0xc + 0x1000 * id, \
+ .intr_target_reg = 0x8 + 0x1000 * id, \
+ .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, _tile, 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 = _tile, \
+ .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 = WEST, \
+ .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 sm6125_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, "UFS_RESET"),
+ PINCTRL_PIN(134, "SDC1_RCLK"),
+ PINCTRL_PIN(135, "SDC1_CLK"),
+ PINCTRL_PIN(136, "SDC1_CMD"),
+ PINCTRL_PIN(137, "SDC1_DATA"),
+ PINCTRL_PIN(138, "SDC2_CLK"),
+ PINCTRL_PIN(139, "SDC2_CMD"),
+ PINCTRL_PIN(140, "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);
+
+static const unsigned int ufs_reset_pins[] = { 133 };
+static const unsigned int sdc1_rclk_pins[] = { 134 };
+static const unsigned int sdc1_clk_pins[] = { 135 };
+static const unsigned int sdc1_cmd_pins[] = { 136 };
+static const unsigned int sdc1_data_pins[] = { 137 };
+static const unsigned int sdc2_clk_pins[] = { 138 };
+static const unsigned int sdc2_cmd_pins[] = { 139 };
+static const unsigned int sdc2_data_pins[] = { 140 };
+
+
+enum sm6125_functions {
+ msm_mux_qup00,
+ msm_mux_gpio,
+ msm_mux_qdss,
+ msm_mux_qup01,
+ msm_mux_qup02,
+ msm_mux_ddr_pxi0,
+ msm_mux_ddr_bist,
+ msm_mux_atest_tsens2,
+ msm_mux_vsense_trigger,
+ msm_mux_atest_usb1,
+ msm_mux_gp_pdm1,
+ msm_mux_phase_flag,
+ msm_mux_dbg_out,
+ msm_mux_qup14,
+ msm_mux_atest_usb11,
+ msm_mux_ddr_pxi2,
+ msm_mux_atest_usb10,
+ msm_mux_jitter_bist,
+ msm_mux_ddr_pxi3,
+ msm_mux_pll_bypassnl,
+ msm_mux_pll_bist,
+ msm_mux_qup03,
+ msm_mux_pll_reset,
+ msm_mux_agera_pll,
+ msm_mux_qdss_cti,
+ msm_mux_qup04,
+ msm_mux_wlan2_adc1,
+ msm_mux_wlan2_adc0,
+ msm_mux_wsa_clk,
+ msm_mux_qup13,
+ msm_mux_ter_mi2s,
+ msm_mux_wsa_data,
+ msm_mux_qup10,
+ msm_mux_gcc_gp3,
+ msm_mux_qup12,
+ msm_mux_sd_write,
+ msm_mux_qup11,
+ msm_mux_cam_mclk,
+ msm_mux_atest_tsens,
+ msm_mux_cci_i2c,
+ msm_mux_cci_timer2,
+ msm_mux_cci_timer1,
+ msm_mux_gcc_gp2,
+ msm_mux_cci_async,
+ msm_mux_cci_timer4,
+ msm_mux_cci_timer0,
+ msm_mux_gcc_gp1,
+ msm_mux_cci_timer3,
+ msm_mux_wlan1_adc1,
+ msm_mux_wlan1_adc0,
+ msm_mux_qlink_request,
+ msm_mux_qlink_enable,
+ msm_mux_pa_indicator,
+ msm_mux_nav_pps,
+ msm_mux_gps_tx,
+ msm_mux_gp_pdm0,
+ msm_mux_atest_usb13,
+ msm_mux_ddr_pxi1,
+ msm_mux_atest_usb12,
+ msm_mux_cri_trng0,
+ msm_mux_cri_trng,
+ msm_mux_cri_trng1,
+ msm_mux_gp_pdm2,
+ msm_mux_sp_cmu,
+ msm_mux_atest_usb2,
+ msm_mux_atest_usb23,
+ msm_mux_uim2_data,
+ msm_mux_uim2_clk,
+ msm_mux_uim2_reset,
+ msm_mux_atest_usb22,
+ msm_mux_uim2_present,
+ msm_mux_atest_usb21,
+ msm_mux_uim1_data,
+ msm_mux_atest_usb20,
+ msm_mux_uim1_clk,
+ msm_mux_uim1_reset,
+ msm_mux_uim1_present,
+ msm_mux_mdp_vsync,
+ msm_mux_copy_gp,
+ msm_mux_tsense_pwm,
+ msm_mux_mpm_pwr,
+ msm_mux_tgu_ch3,
+ msm_mux_mdp_vsync0,
+ msm_mux_mdp_vsync1,
+ msm_mux_mdp_vsync2,
+ msm_mux_mdp_vsync3,
+ msm_mux_mdp_vsync4,
+ msm_mux_mdp_vsync5,
+ msm_mux_tgu_ch0,
+ msm_mux_tgu_ch1,
+ msm_mux_atest_char1,
+ msm_mux_vfr_1,
+ msm_mux_tgu_ch2,
+ msm_mux_atest_char0,
+ msm_mux_atest_char2,
+ msm_mux_atest_char3,
+ msm_mux_ldo_en,
+ msm_mux_ldo_update,
+ msm_mux_prng_rosc,
+ msm_mux_dp_hot,
+ msm_mux_debug_hot,
+ msm_mux_copy_phase,
+ msm_mux_usb_phy,
+ msm_mux_atest_char,
+ msm_mux_unused1,
+ msm_mux_qua_mi2s,
+ msm_mux_mss_lte,
+ msm_mux_swr_tx,
+ msm_mux_aud_sb,
+ msm_mux_unused2,
+ msm_mux_swr_rx,
+ msm_mux_edp_hot,
+ msm_mux_audio_ref,
+ msm_mux_pri_mi2s,
+ msm_mux_pri_mi2s_ws,
+ msm_mux_adsp_ext,
+ msm_mux_edp_lcd,
+ msm_mux_mclk2,
+ msm_mux_m_voc,
+ msm_mux_mclk1,
+ msm_mux_qca_sb,
+ msm_mux_qui_mi2s,
+ msm_mux_dmic0_clk,
+ msm_mux_sec_mi2s,
+ msm_mux_dmic0_data,
+ msm_mux_dmic1_clk,
+ msm_mux_dmic1_data,
+ msm_mux__,
+};
+
+static const char * const qup00_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",
+};
+static const char * const qdss_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio20", "gpio21", "gpio34", "gpio35",
+ "gpio36", "gpio42", "gpio41", "gpio43", "gpio44", "gpio45", "gpio46",
+ "gpio47", "gpio48", "gpio49", "gpio80", "gpio81", "gpio82", "gpio83",
+ "gpio84", "gpio85", "gpio86", "gpio91", "gpio92", "gpio94", "gpio96",
+ "gpio100", "gpio102", "gpio114", "gpio115", "gpio116", "gpio117", "gpio118",
+};
+static const char * const qup01_groups[] = {
+ "gpio4", "gpio5",
+};
+static const char * const qup02_groups[] = {
+ "gpio6", "gpio7", "gpio8", "gpio9",
+};
+static const char * const ddr_pxi0_groups[] = {
+ "gpio6", "gpio7",
+};
+static const char * const ddr_bist_groups[] = {
+ "gpio7", "gpio8", "gpio9", "gpio10",
+};
+static const char * const atest_tsens2_groups[] = {
+ "gpio7",
+};
+static const char * const vsense_trigger_groups[] = {
+ "gpio7",
+};
+static const char * const atest_usb1_groups[] = {
+ "gpio7",
+};
+static const char * const gp_pdm1_groups[] = {
+ "gpio8", "gpio65",
+};
+static const char * const phase_flag_groups[] = {
+ "gpio8", "gpio9", "gpio23", "gpio24", "gpio25", "gpio26", "gpio28",
+ "gpio29", "gpio30", "gpio53", "gpio54", "gpio55", "gpio56", "gpio57",
+ "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio80", "gpio81",
+ "gpio82", "gpio83", "gpio84", "gpio88", "gpio89", "gpio91", "gpio93",
+ "gpio98", "gpio129", "gpio130", "gpio131",
+};
+static const char * const dbg_out_groups[] = {
+ "gpio9",
+};
+static const char * const qup14_groups[] = {
+ "gpio10", "gpio11", "gpio12", "gpio13",
+};
+static const char * const atest_usb11_groups[] = {
+ "gpio10",
+};
+static const char * const ddr_pxi2_groups[] = {
+ "gpio10", "gpio11",
+};
+static const char * const atest_usb10_groups[] = {
+ "gpio11",
+};
+static const char * const jitter_bist_groups[] = {
+ "gpio12", "gpio31",
+};
+static const char * const ddr_pxi3_groups[] = {
+ "gpio12", "gpio13",
+};
+static const char * const pll_bypassnl_groups[] = {
+ "gpio13",
+};
+static const char * const pll_bist_groups[] = {
+ "gpio13", "gpio32",
+};
+static const char * const qup03_groups[] = {
+ "gpio14", "gpio15",
+};
+static const char * const pll_reset_groups[] = {
+ "gpio14",
+};
+static const char * const agera_pll_groups[] = {
+ "gpio14", "gpio33",
+};
+static const char * const qdss_cti_groups[] = {
+ "gpio14", "gpio15", "gpio95", "gpio101", "gpio106", "gpio107",
+ "gpio110", "gpio111",
+};
+static const char * const qup04_groups[] = {
+ "gpio16", "gpio17",
+};
+static const char * const wlan2_adc1_groups[] = {
+ "gpio16",
+};
+static const char * const wlan2_adc0_groups[] = {
+ "gpio17",
+};
+static const char * const wsa_clk_groups[] = {
+ "gpio18",
+};
+static const char * const qup13_groups[] = {
+ "gpio18", "gpio19", "gpio20", "gpio21",
+};
+static const char * const ter_mi2s_groups[] = {
+ "gpio18", "gpio19", "gpio20", "gpio21",
+};
+static const char * const wsa_data_groups[] = {
+ "gpio19",
+};
+static const char * const qup10_groups[] = {
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27",
+};
+static const char * const gcc_gp3_groups[] = {
+ "gpio22", "gpio58",
+};
+static const char * const qup12_groups[] = {
+ "gpio28", "gpio29",
+};
+static const char * const sd_write_groups[] = {
+ "gpio29",
+};
+static const char * const qup11_groups[] = {
+ "gpio30", "gpio31", "gpio32", "gpio33",
+};
+static const char * const cam_mclk_groups[] = {
+ "gpio34", "gpio35", "gpio36", "gpio44",
+};
+static const char * const atest_tsens_groups[] = {
+ "gpio34",
+};
+static const char * const cci_i2c_groups[] = {
+ "gpio37", "gpio38", "gpio39", "gpio40",
+};
+static const char * const cci_timer2_groups[] = {
+ "gpio42",
+};
+static const char * const cci_timer1_groups[] = {
+ "gpio43",
+};
+static const char * const gcc_gp2_groups[] = {
+ "gpio43", "gpio44",
+};
+static const char * const cci_async_groups[] = {
+ "gpio44", "gpio47", "gpio48",
+};
+static const char * const cci_timer4_groups[] = {
+ "gpio44",
+};
+static const char * const cci_timer0_groups[] = {
+ "gpio45",
+};
+static const char * const gcc_gp1_groups[] = {
+ "gpio45", "gpio46",
+};
+static const char * const cci_timer3_groups[] = {
+ "gpio46",
+};
+static const char * const wlan1_adc1_groups[] = {
+ "gpio47",
+};
+static const char * const wlan1_adc0_groups[] = {
+ "gpio48",
+};
+static const char * const qlink_request_groups[] = {
+ "gpio50",
+};
+static const char * const qlink_enable_groups[] = {
+ "gpio51",
+};
+static const char * const pa_indicator_groups[] = {
+ "gpio52",
+};
+static const char * const nav_pps_groups[] = {
+ "gpio52", "gpio55", "gpio56", "gpio58",
+ "gpio59",
+};
+static const char * const gps_tx_groups[] = {
+ "gpio52", "gpio53", "gpio55", "gpio56", "gpio58", "gpio59",
+};
+static const char * const gp_pdm0_groups[] = {
+ "gpio53", "gpio94",
+};
+static const char * const atest_usb13_groups[] = {
+ "gpio53",
+};
+static const char * const ddr_pxi1_groups[] = {
+ "gpio53", "gpio54",
+};
+static const char * const atest_usb12_groups[] = {
+ "gpio54",
+};
+static const char * const cri_trng0_groups[] = {
+ "gpio59",
+};
+static const char * const cri_trng_groups[] = {
+ "gpio60",
+};
+static const char * const cri_trng1_groups[] = {
+ "gpio61",
+};
+static const char * const gp_pdm2_groups[] = {
+ "gpio62", "gpio78",
+};
+static const char * const sp_cmu_groups[] = {
+ "gpio63",
+};
+static const char * const atest_usb2_groups[] = {
+ "gpio66",
+};
+static const char * const atest_usb23_groups[] = {
+ "gpio67",
+};
+static const char * const uim2_data_groups[] = {
+ "gpio72",
+};
+static const char * const uim2_clk_groups[] = {
+ "gpio73",
+};
+static const char * const uim2_reset_groups[] = {
+ "gpio74",
+};
+static const char * const atest_usb22_groups[] = {
+ "gpio74",
+};
+static const char * const uim2_present_groups[] = {
+ "gpio75",
+};
+static const char * const atest_usb21_groups[] = {
+ "gpio75",
+};
+static const char * const uim1_data_groups[] = {
+ "gpio76",
+};
+static const char * const atest_usb20_groups[] = {
+ "gpio76",
+};
+static const char * const uim1_clk_groups[] = {
+ "gpio77",
+};
+static const char * const uim1_reset_groups[] = {
+ "gpio78",
+};
+static const char * const uim1_present_groups[] = {
+ "gpio79",
+};
+static const char * const mdp_vsync_groups[] = {
+ "gpio80", "gpio81", "gpio82", "gpio89", "gpio96", "gpio97",
+};
+static const char * const copy_gp_groups[] = {
+ "gpio85",
+};
+static const char * const tsense_pwm_groups[] = {
+ "gpio87",
+};
+static const char * const mpm_pwr_groups[] = {
+ "gpio88",
+};
+static const char * const tgu_ch3_groups[] = {
+ "gpio88",
+};
+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 mdp_vsync4_groups[] = {
+ "gpio89",
+};
+static const char * const mdp_vsync5_groups[] = {
+ "gpio89",
+};
+static const char * const tgu_ch0_groups[] = {
+ "gpio89",
+};
+static const char * const tgu_ch1_groups[] = {
+ "gpio90",
+};
+static const char * const atest_char1_groups[] = {
+ "gpio90",
+};
+static const char * const vfr_1_groups[] = {
+ "gpio91",
+};
+static const char * const tgu_ch2_groups[] = {
+ "gpio91",
+};
+static const char * const atest_char0_groups[] = {
+ "gpio92",
+};
+static const char * const atest_char2_groups[] = {
+ "gpio93",
+};
+static const char * const atest_char3_groups[] = {
+ "gpio94",
+};
+static const char * const ldo_en_groups[] = {
+ "gpio96",
+};
+static const char * const ldo_update_groups[] = {
+ "gpio97",
+};
+static const char * const prng_rosc_groups[] = {
+ "gpio98", "gpio100",
+};
+static const char * const dp_hot_groups[] = {
+ "gpio100",
+};
+static const char * const debug_hot_groups[] = {
+ "gpio101",
+};
+static const char * const copy_phase_groups[] = {
+ "gpio101",
+};
+static const char * const usb_phy_groups[] = {
+ "gpio102",
+};
+static const char * const atest_char_groups[] = {
+ "gpio102",
+};
+static const char * const unused1_groups[] = {
+ "gpio104",
+};
+static const char * const qua_mi2s_groups[] = {
+ "gpio104", "gpio106", "gpio107", "gpio108", "gpio110", "gpio111",
+};
+static const char * const mss_lte_groups[] = {
+ "gpio105", "gpio109",
+};
+static const char * const swr_tx_groups[] = {
+ "gpio106", "gpio107", "gpio108", "gpio109",
+};
+static const char * const aud_sb_groups[] = {
+ "gpio106", "gpio107", "gpio108", "gpio109",
+};
+static const char * const unused2_groups[] = {
+ "gpio109",
+};
+static const char * const swr_rx_groups[] = {
+ "gpio110", "gpio111", "gpio112",
+};
+static const char * const edp_hot_groups[] = {
+ "gpio111",
+};
+static const char * const audio_ref_groups[] = {
+ "gpio112",
+};
+static const char * const pri_mi2s_groups[] = {
+ "gpio113", "gpio115", "gpio116",
+};
+static const char * const pri_mi2s_ws_groups[] = {
+ "gpio114",
+};
+static const char * const adsp_ext_groups[] = {
+ "gpio116",
+};
+static const char * const edp_lcd_groups[] = {
+ "gpio117",
+};
+static const char * const mclk2_groups[] = {
+ "gpio118",
+};
+static const char * const m_voc_groups[] = {
+ "gpio118",
+};
+static const char * const mclk1_groups[] = {
+ "gpio119",
+};
+static const char * const qca_sb_groups[] = {
+ "gpio121", "gpio122",
+};
+static const char * const qui_mi2s_groups[] = {
+ "gpio121", "gpio122", "gpio123", "gpio124",
+};
+static const char * const dmic0_clk_groups[] = {
+ "gpio125",
+};
+static const char * const sec_mi2s_groups[] = {
+ "gpio125", "gpio126", "gpio127", "gpio128",
+};
+static const char * const dmic0_data_groups[] = {
+ "gpio126",
+};
+static const char * const dmic1_clk_groups[] = {
+ "gpio127",
+};
+static const char * const dmic1_data_groups[] = {
+ "gpio128",
+};
+
+static const struct msm_function sm6125_functions[] = {
+ FUNCTION(qup00),
+ FUNCTION(gpio),
+ FUNCTION(qdss),
+ FUNCTION(qup01),
+ FUNCTION(qup02),
+ FUNCTION(ddr_pxi0),
+ FUNCTION(ddr_bist),
+ FUNCTION(atest_tsens2),
+ FUNCTION(vsense_trigger),
+ FUNCTION(atest_usb1),
+ FUNCTION(gp_pdm1),
+ FUNCTION(phase_flag),
+ FUNCTION(dbg_out),
+ FUNCTION(qup14),
+ FUNCTION(atest_usb11),
+ FUNCTION(ddr_pxi2),
+ FUNCTION(atest_usb10),
+ FUNCTION(jitter_bist),
+ FUNCTION(ddr_pxi3),
+ FUNCTION(pll_bypassnl),
+ FUNCTION(pll_bist),
+ FUNCTION(qup03),
+ FUNCTION(pll_reset),
+ FUNCTION(agera_pll),
+ FUNCTION(qdss_cti),
+ FUNCTION(qup04),
+ FUNCTION(wlan2_adc1),
+ FUNCTION(wlan2_adc0),
+ FUNCTION(wsa_clk),
+ FUNCTION(qup13),
+ FUNCTION(ter_mi2s),
+ FUNCTION(wsa_data),
+ FUNCTION(qup10),
+ FUNCTION(gcc_gp3),
+ FUNCTION(qup12),
+ FUNCTION(sd_write),
+ FUNCTION(qup11),
+ FUNCTION(cam_mclk),
+ FUNCTION(atest_tsens),
+ FUNCTION(cci_i2c),
+ FUNCTION(cci_timer2),
+ FUNCTION(cci_timer1),
+ FUNCTION(gcc_gp2),
+ FUNCTION(cci_async),
+ FUNCTION(cci_timer4),
+ FUNCTION(cci_timer0),
+ FUNCTION(gcc_gp1),
+ FUNCTION(cci_timer3),
+ FUNCTION(wlan1_adc1),
+ FUNCTION(wlan1_adc0),
+ FUNCTION(qlink_request),
+ FUNCTION(qlink_enable),
+ FUNCTION(pa_indicator),
+ FUNCTION(nav_pps),
+ FUNCTION(gps_tx),
+ FUNCTION(gp_pdm0),
+ FUNCTION(atest_usb13),
+ FUNCTION(ddr_pxi1),
+ FUNCTION(atest_usb12),
+ FUNCTION(cri_trng0),
+ FUNCTION(cri_trng),
+ FUNCTION(cri_trng1),
+ FUNCTION(gp_pdm2),
+ FUNCTION(sp_cmu),
+ FUNCTION(atest_usb2),
+ FUNCTION(atest_usb23),
+ FUNCTION(uim2_data),
+ FUNCTION(uim2_clk),
+ FUNCTION(uim2_reset),
+ FUNCTION(atest_usb22),
+ FUNCTION(uim2_present),
+ FUNCTION(atest_usb21),
+ FUNCTION(uim1_data),
+ FUNCTION(atest_usb20),
+ FUNCTION(uim1_clk),
+ FUNCTION(uim1_reset),
+ FUNCTION(uim1_present),
+ FUNCTION(mdp_vsync),
+ FUNCTION(copy_gp),
+ FUNCTION(tsense_pwm),
+ FUNCTION(mpm_pwr),
+ FUNCTION(tgu_ch3),
+ FUNCTION(mdp_vsync0),
+ FUNCTION(mdp_vsync1),
+ FUNCTION(mdp_vsync2),
+ FUNCTION(mdp_vsync3),
+ FUNCTION(mdp_vsync4),
+ FUNCTION(mdp_vsync5),
+ FUNCTION(tgu_ch0),
+ FUNCTION(tgu_ch1),
+ FUNCTION(atest_char1),
+ FUNCTION(vfr_1),
+ FUNCTION(tgu_ch2),
+ FUNCTION(atest_char0),
+ FUNCTION(atest_char2),
+ FUNCTION(atest_char3),
+ FUNCTION(ldo_en),
+ FUNCTION(ldo_update),
+ FUNCTION(prng_rosc),
+ FUNCTION(dp_hot),
+ FUNCTION(debug_hot),
+ FUNCTION(copy_phase),
+ FUNCTION(usb_phy),
+ FUNCTION(atest_char),
+ FUNCTION(unused1),
+ FUNCTION(qua_mi2s),
+ FUNCTION(mss_lte),
+ FUNCTION(swr_tx),
+ FUNCTION(aud_sb),
+ FUNCTION(unused2),
+ FUNCTION(swr_rx),
+ FUNCTION(edp_hot),
+ FUNCTION(audio_ref),
+ FUNCTION(pri_mi2s),
+ FUNCTION(pri_mi2s_ws),
+ FUNCTION(adsp_ext),
+ FUNCTION(edp_lcd),
+ FUNCTION(mclk2),
+ FUNCTION(m_voc),
+ FUNCTION(mclk1),
+ FUNCTION(qca_sb),
+ FUNCTION(qui_mi2s),
+ FUNCTION(dmic0_clk),
+ FUNCTION(sec_mi2s),
+ FUNCTION(dmic0_data),
+ FUNCTION(dmic1_clk),
+ FUNCTION(dmic1_data),
+};
+
+ /*
+ * 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 sm6125_groups[] = {
+ [0] = PINGROUP(0, WEST, qup00, _, qdss, _, _, _, _, _, _),
+ [1] = PINGROUP(1, WEST, qup00, _, qdss, _, _, _, _, _, _),
+ [2] = PINGROUP(2, WEST, qup00, _, qdss, _, _, _, _, _, _),
+ [3] = PINGROUP(3, WEST, qup00, _, qdss, _, _, _, _, _, _),
+ [4] = PINGROUP(4, WEST, qup01, _, _, _, _, _, _, _, _),
+ [5] = PINGROUP(5, WEST, qup01, _, _, _, _, _, _, _, _),
+ [6] = PINGROUP(6, WEST, qup02, ddr_pxi0, _, _, _, _, _, _, _),
+ [7] = PINGROUP(7, WEST, qup02, ddr_bist, atest_tsens2, vsense_trigger, atest_usb1, ddr_pxi0, _, _, _),
+ [8] = PINGROUP(8, WEST, qup02, gp_pdm1, ddr_bist, _, phase_flag, _, _, _, _),
+ [9] = PINGROUP(9, WEST, qup02, ddr_bist, dbg_out, phase_flag, _, _, _, _, _),
+ [10] = PINGROUP(10, EAST, qup14, ddr_bist, atest_usb11, ddr_pxi2, _, _, _, _, _),
+ [11] = PINGROUP(11, EAST, qup14, atest_usb10, ddr_pxi2, _, _, _, _, _, _),
+ [12] = PINGROUP(12, EAST, qup14, jitter_bist, ddr_pxi3, _, _, _, _, _, _),
+ [13] = PINGROUP(13, EAST, qup14, pll_bypassnl, pll_bist, _, ddr_pxi3, _, _, _, _),
+ [14] = PINGROUP(14, WEST, qup03, qup03, pll_reset, agera_pll, _, qdss_cti, _, _, _),
+ [15] = PINGROUP(15, WEST, qup03, qup03, qdss_cti, _, _, _, _, _, _),
+ [16] = PINGROUP(16, WEST, qup04, qup04, _, wlan2_adc1, _, _, _, _, _),
+ [17] = PINGROUP(17, WEST, qup04, qup04, _, wlan2_adc0, _, _, _, _, _),
+ [18] = PINGROUP(18, EAST, wsa_clk, qup13, ter_mi2s, _, _, _, _, _, _),
+ [19] = PINGROUP(19, EAST, wsa_data, qup13, ter_mi2s, _, _, _, _, _, _),
+ [20] = PINGROUP(20, EAST, qup13, ter_mi2s, qdss, _, _, _, _, _, _),
+ [21] = PINGROUP(21, EAST, qup13, ter_mi2s, _, qdss, _, _, _, _, _),
+ [22] = PINGROUP(22, WEST, qup10, gcc_gp3, _, _, _, _, _, _, _),
+ [23] = PINGROUP(23, WEST, qup10, _, phase_flag, _, _, _, _, _, _),
+ [24] = PINGROUP(24, WEST, qup10, _, phase_flag, _, _, _, _, _, _),
+ [25] = PINGROUP(25, WEST, qup10, _, phase_flag, _, _, _, _, _, _),
+ [26] = PINGROUP(26, WEST, qup10, _, phase_flag, _, _, _, _, _, _),
+ [27] = PINGROUP(27, WEST, qup10, _, _, _, _, _, _, _, _),
+ [28] = PINGROUP(28, WEST, qup12, _, phase_flag, _, _, _, _, _, _),
+ [29] = PINGROUP(29, WEST, qup12, sd_write, _, phase_flag, _, _, _, _, _),
+ [30] = PINGROUP(30, WEST, qup11, _, phase_flag, _, _, _, _, _, _),
+ [31] = PINGROUP(31, WEST, qup11, jitter_bist, _, _, _, _, _, _, _),
+ [32] = PINGROUP(32, WEST, qup11, pll_bist, _, _, _, _, _, _, _),
+ [33] = PINGROUP(33, WEST, qup11, agera_pll, _, _, _, _, _, _, _),
+ [34] = PINGROUP(34, SOUTH, cam_mclk, _, qdss, atest_tsens, _, _, _, _, _),
+ [35] = PINGROUP(35, SOUTH, cam_mclk, _, qdss, _, _, _, _, _, _),
+ [36] = PINGROUP(36, SOUTH, cam_mclk, _, qdss, _, _, _, _, _, _),
+ [37] = PINGROUP(37, SOUTH, cci_i2c, _, _, _, _, _, _, _, _),
+ [38] = PINGROUP(38, EAST, cci_i2c, _, _, _, _, _, _, _, _),
+ [39] = PINGROUP(39, EAST, cci_i2c, _, _, _, _, _, _, _, _),
+ [40] = PINGROUP(40, EAST, cci_i2c, _, _, _, _, _, _, _, _),
+ [41] = PINGROUP(41, EAST, _, qdss, _, _, _, _, _, _, _),
+ [42] = PINGROUP(42, EAST, cci_timer2, _, qdss, _, _, _, _, _, _),
+ [43] = PINGROUP(43, EAST, cci_timer1, _, gcc_gp2, _, qdss, _, _, _, _),
+ [44] = PINGROUP(44, SOUTH, cci_async, cci_timer4, _, gcc_gp2, _, qdss, cam_mclk, _, _),
+ [45] = PINGROUP(45, SOUTH, cci_timer0, _, gcc_gp1, qdss, _, _, _, _, _),
+ [46] = PINGROUP(46, SOUTH, cci_timer3, _, gcc_gp1, _, qdss, _, _, _, _),
+ [47] = PINGROUP(47, SOUTH, cci_async, _, qdss, wlan1_adc1, _, _, _, _, _),
+ [48] = PINGROUP(48, SOUTH, cci_async, _, qdss, wlan1_adc0, _, _, _, _, _),
+ [49] = PINGROUP(49, SOUTH, qdss, _, _, _, _, _, _, _, _),
+ [50] = PINGROUP(50, SOUTH, qlink_request, _, _, _, _, _, _, _, _),
+ [51] = PINGROUP(51, SOUTH, qlink_enable, _, _, _, _, _, _, _, _),
+ [52] = PINGROUP(52, SOUTH, pa_indicator, nav_pps, nav_pps, gps_tx, _, _, _, _, _),
+ [53] = PINGROUP(53, SOUTH, _, gps_tx, gp_pdm0, _, phase_flag, atest_usb13, ddr_pxi1, _, _),
+ [54] = PINGROUP(54, SOUTH, _, _, phase_flag, atest_usb12, ddr_pxi1, _, _, _, _),
+ [55] = PINGROUP(55, SOUTH, _, nav_pps, nav_pps, gps_tx, _, phase_flag, _, _, _),
+ [56] = PINGROUP(56, SOUTH, _, nav_pps, gps_tx, nav_pps, phase_flag, _, _, _, _),
+ [57] = PINGROUP(57, SOUTH, _, phase_flag, _, _, _, _, _, _, _),
+ [58] = PINGROUP(58, SOUTH, _, nav_pps, nav_pps, gps_tx, gcc_gp3, _, phase_flag, _, _),
+ [59] = PINGROUP(59, SOUTH, _, nav_pps, nav_pps, gps_tx, cri_trng0, _, phase_flag, _, _),
+ [60] = PINGROUP(60, SOUTH, _, cri_trng, _, phase_flag, _, _, _, _, _),
+ [61] = PINGROUP(61, SOUTH, _, cri_trng1, _, phase_flag, _, _, _, _, _),
+ [62] = PINGROUP(62, SOUTH, _, _, gp_pdm2, _, phase_flag, _, _, _, _),
+ [63] = PINGROUP(63, SOUTH, _, sp_cmu, _, _, _, _, _, _, _),
+ [64] = PINGROUP(64, SOUTH, _, _, _, _, _, _, _, _, _),
+ [65] = PINGROUP(65, SOUTH, _, gp_pdm1, _, _, _, _, _, _, _),
+ [66] = PINGROUP(66, SOUTH, _, _, atest_usb2, _, _, _, _, _, _),
+ [67] = PINGROUP(67, SOUTH, _, _, atest_usb23, _, _, _, _, _, _),
+ [68] = PINGROUP(68, SOUTH, _, _, _, _, _, _, _, _, _),
+ [69] = PINGROUP(69, SOUTH, _, _, _, _, _, _, _, _, _),
+ [70] = PINGROUP(70, SOUTH, _, _, _, _, _, _, _, _, _),
+ [71] = PINGROUP(71, SOUTH, _, _, _, _, _, _, _, _, _),
+ [72] = PINGROUP(72, SOUTH, uim2_data, _, _, _, _, _, _, _, _),
+ [73] = PINGROUP(73, SOUTH, uim2_clk, _, _, _, _, _, _, _, _),
+ [74] = PINGROUP(74, SOUTH, uim2_reset, _, atest_usb22, _, _, _, _, _, _),
+ [75] = PINGROUP(75, SOUTH, uim2_present, _, atest_usb21, _, _, _, _, _, _),
+ [76] = PINGROUP(76, SOUTH, uim1_data, _, atest_usb20, _, _, _, _, _, _),
+ [77] = PINGROUP(77, SOUTH, uim1_clk, _, _, _, _, _, _, _, _),
+ [78] = PINGROUP(78, SOUTH, uim1_reset, gp_pdm2, _, _, _, _, _, _, _),
+ [79] = PINGROUP(79, SOUTH, uim1_present, _, _, _, _, _, _, _, _),
+ [80] = PINGROUP(80, SOUTH, mdp_vsync, _, phase_flag, qdss, _, _, _, _, _),
+ [81] = PINGROUP(81, SOUTH, mdp_vsync, _, phase_flag, qdss, _, _, _, _, _),
+ [82] = PINGROUP(82, SOUTH, mdp_vsync, _, phase_flag, qdss, _, _, _, _, _),
+ [83] = PINGROUP(83, SOUTH, _, phase_flag, qdss, _, _, _, _, _, _),
+ [84] = PINGROUP(84, SOUTH, _, phase_flag, qdss, _, _, _, _, _, _),
+ [85] = PINGROUP(85, SOUTH, copy_gp, _, qdss, _, _, _, _, _, _),
+ [86] = PINGROUP(86, SOUTH, _, qdss, _, _, _, _, _, _, _),
+ [87] = PINGROUP(87, WEST, tsense_pwm, _, _, _, _, _, _, _, _),
+ [88] = PINGROUP(88, WEST, mpm_pwr, tgu_ch3, _, phase_flag, _, _, _, _, _),
+ [89] = PINGROUP(89, WEST, mdp_vsync, mdp_vsync0, mdp_vsync1, mdp_vsync2, mdp_vsync3, mdp_vsync4, mdp_vsync5, tgu_ch0, _),
+ [90] = PINGROUP(90, WEST, tgu_ch1, atest_char1, _, _, _, _, _, _, _),
+ [91] = PINGROUP(91, WEST, vfr_1, tgu_ch2, _, phase_flag, qdss, _, _, _, _),
+ [92] = PINGROUP(92, WEST, qdss, atest_char0, _, _, _, _, _, _, _),
+ [93] = PINGROUP(93, WEST, _, phase_flag, atest_char2, _, _, _, _, _, _),
+ [94] = PINGROUP(94, SOUTH, gp_pdm0, _, qdss, atest_char3, _, _, _, _, _),
+ [95] = PINGROUP(95, SOUTH, qdss_cti, _, _, _, _, _, _, _, _),
+ [96] = PINGROUP(96, SOUTH, mdp_vsync, ldo_en, qdss, _, _, _, _, _, _),
+ [97] = PINGROUP(97, SOUTH, mdp_vsync, ldo_update, _, _, _, _, _, _, _),
+ [98] = PINGROUP(98, SOUTH, _, phase_flag, prng_rosc, _, _, _, _, _, _),
+ [99] = PINGROUP(99, SOUTH, _, _, _, _, _, _, _, _, _),
+ [100] = PINGROUP(100, SOUTH, dp_hot, prng_rosc, qdss, _, _, _, _, _, _),
+ [101] = PINGROUP(101, SOUTH, debug_hot, copy_phase, qdss_cti, _, _, _, _, _, _),
+ [102] = PINGROUP(102, SOUTH, usb_phy, _, qdss, atest_char, _, _, _, _, _),
+ [103] = PINGROUP(103, SOUTH, _, _, _, _, _, _, _, _, _),
+ [104] = PINGROUP(104, EAST, unused1, _, qua_mi2s, _, _, _, _, _, _),
+ [105] = PINGROUP(105, EAST, mss_lte, _, _, _, _, _, _, _, _),
+ [106] = PINGROUP(106, EAST, swr_tx, aud_sb, qua_mi2s, _, qdss_cti, _, _, _, _),
+ [107] = PINGROUP(107, EAST, swr_tx, aud_sb, qua_mi2s, _, qdss_cti, _, _, _, _),
+ [108] = PINGROUP(108, EAST, swr_tx, aud_sb, qua_mi2s, _, _, _, _, _, _),
+ [109] = PINGROUP(109, EAST, swr_tx, aud_sb, unused2, _, mss_lte, _, _, _, _),
+ [110] = PINGROUP(110, EAST, swr_rx, qua_mi2s, _, qdss_cti, _, _, _, _, _),
+ [111] = PINGROUP(111, EAST, swr_rx, qua_mi2s, edp_hot, _, qdss_cti, _, _, _, _),
+ [112] = PINGROUP(112, EAST, swr_rx, audio_ref, _, _, _, _, _, _, _),
+ [113] = PINGROUP(113, EAST, pri_mi2s, _, _, _, _, _, _, _, _),
+ [114] = PINGROUP(114, EAST, pri_mi2s_ws, qdss, _, _, _, _, _, _, _),
+ [115] = PINGROUP(115, EAST, pri_mi2s, qdss, _, _, _, _, _, _, _),
+ [116] = PINGROUP(116, EAST, pri_mi2s, adsp_ext, qdss, _, _, _, _, _, _),
+ [117] = PINGROUP(117, SOUTH, edp_lcd, qdss, _, _, _, _, _, _, _),
+ [118] = PINGROUP(118, SOUTH, mclk2, m_voc, qdss, _, _, _, _, _, _),
+ [119] = PINGROUP(119, SOUTH, mclk1, _, _, _, _, _, _, _, _),
+ [120] = PINGROUP(120, SOUTH, _, _, _, _, _, _, _, _, _),
+ [121] = PINGROUP(121, EAST, qca_sb, qui_mi2s, _, _, _, _, _, _, _),
+ [122] = PINGROUP(122, EAST, qca_sb, qui_mi2s, _, _, _, _, _, _, _),
+ [123] = PINGROUP(123, EAST, qui_mi2s, _, _, _, _, _, _, _, _),
+ [124] = PINGROUP(124, EAST, qui_mi2s, _, _, _, _, _, _, _, _),
+ [125] = PINGROUP(125, EAST, dmic0_clk, sec_mi2s, _, _, _, _, _, _, _),
+ [126] = PINGROUP(126, EAST, dmic0_data, sec_mi2s, _, _, _, _, _, _, _),
+ [127] = PINGROUP(127, EAST, dmic1_clk, sec_mi2s, _, _, _, _, _, _, _),
+ [128] = PINGROUP(128, EAST, dmic1_data, sec_mi2s, _, _, _, _, _, _, _),
+ [129] = PINGROUP(129, SOUTH, _, phase_flag, _, _, _, _, _, _, _),
+ [130] = PINGROUP(130, SOUTH, phase_flag, _, _, _, _, _, _, _, _),
+ [131] = PINGROUP(131, SOUTH, phase_flag, _, _, _, _, _, _, _, _),
+ [132] = PINGROUP(132, SOUTH, _, _, _, _, _, _, _, _, _),
+ [133] = UFS_RESET(ufs_reset, 0x190000),
+ [134] = SDC_QDSD_PINGROUP(sdc1_rclk, WEST, 0x18d000, 15, 0),
+ [135] = SDC_QDSD_PINGROUP(sdc1_clk, WEST, 0x18d000, 13, 6),
+ [136] = SDC_QDSD_PINGROUP(sdc1_cmd, WEST, 0x18d000, 11, 3),
+ [137] = SDC_QDSD_PINGROUP(sdc1_data, WEST, 0x18d000, 9, 0),
+ [138] = SDC_QDSD_PINGROUP(sdc2_clk, SOUTH, 0x58b000, 14, 6),
+ [139] = SDC_QDSD_PINGROUP(sdc2_cmd, SOUTH, 0x58b000, 11, 3),
+ [140] = SDC_QDSD_PINGROUP(sdc2_data, SOUTH, 0x58b000, 9, 0),
+};
+
+static const struct msm_pinctrl_soc_data sm6125_tlmm = {
+ .pins = sm6125_pins,
+ .npins = ARRAY_SIZE(sm6125_pins),
+ .functions = sm6125_functions,
+ .nfunctions = ARRAY_SIZE(sm6125_functions),
+ .groups = sm6125_groups,
+ .ngroups = ARRAY_SIZE(sm6125_groups),
+ .ngpios = 134,
+ .tiles = sm6125_tiles,
+ .ntiles = ARRAY_SIZE(sm6125_tiles),
+};
+
+static int sm6125_tlmm_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &sm6125_tlmm);
+}
+
+static const struct of_device_id sm6125_tlmm_of_match[] = {
+ { .compatible = "qcom,sm6125-tlmm", },
+ { },
+};
+
+static struct platform_driver sm6125_tlmm_driver = {
+ .driver = {
+ .name = "sm6125-tlmm",
+ .of_match_table = sm6125_tlmm_of_match,
+ },
+ .probe = sm6125_tlmm_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init sm6125_tlmm_init(void)
+{
+ return platform_driver_register(&sm6125_tlmm_driver);
+}
+arch_initcall(sm6125_tlmm_init);
+
+static void __exit sm6125_tlmm_exit(void)
+{
+ platform_driver_unregister(&sm6125_tlmm_driver);
+}
+module_exit(sm6125_tlmm_exit);
+
+MODULE_DESCRIPTION("QTI sm6125 TLMM driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, sm6125_tlmm_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index 00870da0c94e..a89d24a040af 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -1131,6 +1131,7 @@ static const struct of_device_id pmic_gpio_of_match[] = {
{ .compatible = "qcom,pm8350b-gpio", .data = (void *) 8 },
{ .compatible = "qcom,pm8350c-gpio", .data = (void *) 9 },
{ .compatible = "qcom,pmk8350-gpio", .data = (void *) 4 },
+ { .compatible = "qcom,pm7325-gpio", .data = (void *) 10 },
{ .compatible = "qcom,pmr735a-gpio", .data = (void *) 4 },
{ .compatible = "qcom,pmr735b-gpio", .data = (void *) 4 },
{ .compatible = "qcom,pm6150-gpio", .data = (void *) 10 },
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
index 3c213f799feb..2da9b5f68f3f 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
@@ -920,6 +920,7 @@ static const struct of_device_id pmic_mpp_of_match[] = {
{ .compatible = "qcom,pmi8950-mpp" }, /* 4 MPP's */
{ .compatible = "qcom,pm8994-mpp" }, /* 8 MPP's */
{ .compatible = "qcom,pma8084-mpp" }, /* 8 MPP's */
+ { .compatible = "qcom,pmi8994-mpp" }, /* 4 MPP's */
{ .compatible = "qcom,spmi-mpp" }, /* Generic */
{ },
};
diff --git a/drivers/pinctrl/ralink/Kconfig b/drivers/pinctrl/ralink/Kconfig
index 8c5f6341477f..a76ee3deb8c3 100644
--- a/drivers/pinctrl/ralink/Kconfig
+++ b/drivers/pinctrl/ralink/Kconfig
@@ -11,4 +11,29 @@ config PINCTRL_RT2880
select PINMUX
select GENERIC_PINCONF
+config PINCTRL_MT7620
+ bool "mt7620 pinctrl driver for RALINK/Mediatek SOCs"
+ depends on RALINK && SOC_MT7620
+ select PINCTRL_RT2880
+
+config PINCTRL_MT7621
+ bool "mt7621 pinctrl driver for RALINK/Mediatek SOCs"
+ depends on RALINK && SOC_MT7621
+ select PINCTRL_RT2880
+
+config PINCTRL_RT288X
+ bool "RT288X pinctrl driver for RALINK/Mediatek SOCs"
+ depends on RALINK && SOC_RT288X
+ select PINCTRL_RT2880
+
+config PINCTRL_RT305X
+ bool "RT305X pinctrl driver for RALINK/Mediatek SOCs"
+ depends on RALINK && SOC_RT305X
+ select PINCTRL_RT2880
+
+config PINCTRL_RT3883
+ bool "RT3883 pinctrl driver for RALINK/Mediatek SOCs"
+ depends on RALINK && SOC_RT3883
+ select PINCTRL_RT2880
+
endmenu
diff --git a/drivers/pinctrl/ralink/Makefile b/drivers/pinctrl/ralink/Makefile
index 242554298d07..a15610206ced 100644
--- a/drivers/pinctrl/ralink/Makefile
+++ b/drivers/pinctrl/ralink/Makefile
@@ -1,2 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PINCTRL_RT2880) += pinctrl-rt2880.o
+
+obj-$(CONFIG_PINCTRL_MT7620) += pinctrl-mt7620.o
+obj-$(CONFIG_PINCTRL_MT7621) += pinctrl-mt7621.o
+obj-$(CONFIG_PINCTRL_RT288X) += pinctrl-rt288x.o
+obj-$(CONFIG_PINCTRL_RT305X) += pinctrl-rt305x.o
+obj-$(CONFIG_PINCTRL_RT3883) += pinctrl-rt3883.o
diff --git a/drivers/pinctrl/ralink/pinctrl-mt7620.c b/drivers/pinctrl/ralink/pinctrl-mt7620.c
new file mode 100644
index 000000000000..425d55a2ee19
--- /dev/null
+++ b/drivers/pinctrl/ralink/pinctrl-mt7620.c
@@ -0,0 +1,390 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <asm/mach-ralink/mt7620.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include "pinmux.h"
+
+#define MT7620_GPIO_MODE_UART0_SHIFT 2
+#define MT7620_GPIO_MODE_UART0_MASK 0x7
+#define MT7620_GPIO_MODE_UART0(x) ((x) << MT7620_GPIO_MODE_UART0_SHIFT)
+#define MT7620_GPIO_MODE_UARTF 0x0
+#define MT7620_GPIO_MODE_PCM_UARTF 0x1
+#define MT7620_GPIO_MODE_PCM_I2S 0x2
+#define MT7620_GPIO_MODE_I2S_UARTF 0x3
+#define MT7620_GPIO_MODE_PCM_GPIO 0x4
+#define MT7620_GPIO_MODE_GPIO_UARTF 0x5
+#define MT7620_GPIO_MODE_GPIO_I2S 0x6
+#define MT7620_GPIO_MODE_GPIO 0x7
+
+#define MT7620_GPIO_MODE_NAND 0
+#define MT7620_GPIO_MODE_SD 1
+#define MT7620_GPIO_MODE_ND_SD_GPIO 2
+#define MT7620_GPIO_MODE_ND_SD_MASK 0x3
+#define MT7620_GPIO_MODE_ND_SD_SHIFT 18
+
+#define MT7620_GPIO_MODE_PCIE_RST 0
+#define MT7620_GPIO_MODE_PCIE_REF 1
+#define MT7620_GPIO_MODE_PCIE_GPIO 2
+#define MT7620_GPIO_MODE_PCIE_MASK 0x3
+#define MT7620_GPIO_MODE_PCIE_SHIFT 16
+
+#define MT7620_GPIO_MODE_WDT_RST 0
+#define MT7620_GPIO_MODE_WDT_REF 1
+#define MT7620_GPIO_MODE_WDT_GPIO 2
+#define MT7620_GPIO_MODE_WDT_MASK 0x3
+#define MT7620_GPIO_MODE_WDT_SHIFT 21
+
+#define MT7620_GPIO_MODE_MDIO 0
+#define MT7620_GPIO_MODE_MDIO_REFCLK 1
+#define MT7620_GPIO_MODE_MDIO_GPIO 2
+#define MT7620_GPIO_MODE_MDIO_MASK 0x3
+#define MT7620_GPIO_MODE_MDIO_SHIFT 7
+
+#define MT7620_GPIO_MODE_I2C 0
+#define MT7620_GPIO_MODE_UART1 5
+#define MT7620_GPIO_MODE_RGMII1 9
+#define MT7620_GPIO_MODE_RGMII2 10
+#define MT7620_GPIO_MODE_SPI 11
+#define MT7620_GPIO_MODE_SPI_REF_CLK 12
+#define MT7620_GPIO_MODE_WLED 13
+#define MT7620_GPIO_MODE_JTAG 15
+#define MT7620_GPIO_MODE_EPHY 15
+#define MT7620_GPIO_MODE_PA 20
+
+static struct rt2880_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) };
+static struct rt2880_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) };
+static struct rt2880_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) };
+static struct rt2880_pmx_func mdio_grp[] = {
+ FUNC("mdio", MT7620_GPIO_MODE_MDIO, 22, 2),
+ FUNC("refclk", MT7620_GPIO_MODE_MDIO_REFCLK, 22, 2),
+};
+static struct rt2880_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 24, 12) };
+static struct rt2880_pmx_func refclk_grp[] = { FUNC("spi refclk", 0, 37, 3) };
+static struct rt2880_pmx_func ephy_grp[] = { FUNC("ephy", 0, 40, 5) };
+static struct rt2880_pmx_func rgmii2_grp[] = { FUNC("rgmii2", 0, 60, 12) };
+static struct rt2880_pmx_func wled_grp[] = { FUNC("wled", 0, 72, 1) };
+static struct rt2880_pmx_func pa_grp[] = { FUNC("pa", 0, 18, 4) };
+static struct rt2880_pmx_func uartf_grp[] = {
+ FUNC("uartf", MT7620_GPIO_MODE_UARTF, 7, 8),
+ FUNC("pcm uartf", MT7620_GPIO_MODE_PCM_UARTF, 7, 8),
+ FUNC("pcm i2s", MT7620_GPIO_MODE_PCM_I2S, 7, 8),
+ FUNC("i2s uartf", MT7620_GPIO_MODE_I2S_UARTF, 7, 8),
+ FUNC("pcm gpio", MT7620_GPIO_MODE_PCM_GPIO, 11, 4),
+ FUNC("gpio uartf", MT7620_GPIO_MODE_GPIO_UARTF, 7, 4),
+ FUNC("gpio i2s", MT7620_GPIO_MODE_GPIO_I2S, 7, 4),
+};
+static struct rt2880_pmx_func wdt_grp[] = {
+ FUNC("wdt rst", 0, 17, 1),
+ FUNC("wdt refclk", 0, 17, 1),
+ };
+static struct rt2880_pmx_func pcie_rst_grp[] = {
+ FUNC("pcie rst", MT7620_GPIO_MODE_PCIE_RST, 36, 1),
+ FUNC("pcie refclk", MT7620_GPIO_MODE_PCIE_REF, 36, 1)
+};
+static struct rt2880_pmx_func nd_sd_grp[] = {
+ FUNC("nand", MT7620_GPIO_MODE_NAND, 45, 15),
+ FUNC("sd", MT7620_GPIO_MODE_SD, 47, 13)
+};
+
+static struct rt2880_pmx_group mt7620a_pinmux_data[] = {
+ GRP("i2c", i2c_grp, 1, MT7620_GPIO_MODE_I2C),
+ GRP("uartf", uartf_grp, MT7620_GPIO_MODE_UART0_MASK,
+ MT7620_GPIO_MODE_UART0_SHIFT),
+ GRP("spi", spi_grp, 1, MT7620_GPIO_MODE_SPI),
+ GRP("uartlite", uartlite_grp, 1, MT7620_GPIO_MODE_UART1),
+ GRP_G("wdt", wdt_grp, MT7620_GPIO_MODE_WDT_MASK,
+ MT7620_GPIO_MODE_WDT_GPIO, MT7620_GPIO_MODE_WDT_SHIFT),
+ GRP_G("mdio", mdio_grp, MT7620_GPIO_MODE_MDIO_MASK,
+ MT7620_GPIO_MODE_MDIO_GPIO, MT7620_GPIO_MODE_MDIO_SHIFT),
+ GRP("rgmii1", rgmii1_grp, 1, MT7620_GPIO_MODE_RGMII1),
+ GRP("spi refclk", refclk_grp, 1, MT7620_GPIO_MODE_SPI_REF_CLK),
+ GRP_G("pcie", pcie_rst_grp, MT7620_GPIO_MODE_PCIE_MASK,
+ MT7620_GPIO_MODE_PCIE_GPIO, MT7620_GPIO_MODE_PCIE_SHIFT),
+ GRP_G("nd_sd", nd_sd_grp, MT7620_GPIO_MODE_ND_SD_MASK,
+ MT7620_GPIO_MODE_ND_SD_GPIO, MT7620_GPIO_MODE_ND_SD_SHIFT),
+ GRP("rgmii2", rgmii2_grp, 1, MT7620_GPIO_MODE_RGMII2),
+ GRP("wled", wled_grp, 1, MT7620_GPIO_MODE_WLED),
+ GRP("ephy", ephy_grp, 1, MT7620_GPIO_MODE_EPHY),
+ GRP("pa", pa_grp, 1, MT7620_GPIO_MODE_PA),
+ { 0 }
+};
+
+static struct rt2880_pmx_func pwm1_grp_mt7628[] = {
+ FUNC("sdxc d6", 3, 19, 1),
+ FUNC("utif", 2, 19, 1),
+ FUNC("gpio", 1, 19, 1),
+ FUNC("pwm1", 0, 19, 1),
+};
+
+static struct rt2880_pmx_func pwm0_grp_mt7628[] = {
+ FUNC("sdxc d7", 3, 18, 1),
+ FUNC("utif", 2, 18, 1),
+ FUNC("gpio", 1, 18, 1),
+ FUNC("pwm0", 0, 18, 1),
+};
+
+static struct rt2880_pmx_func uart2_grp_mt7628[] = {
+ FUNC("sdxc d5 d4", 3, 20, 2),
+ FUNC("pwm", 2, 20, 2),
+ FUNC("gpio", 1, 20, 2),
+ FUNC("uart2", 0, 20, 2),
+};
+
+static struct rt2880_pmx_func uart1_grp_mt7628[] = {
+ FUNC("sw_r", 3, 45, 2),
+ FUNC("pwm", 2, 45, 2),
+ FUNC("gpio", 1, 45, 2),
+ FUNC("uart1", 0, 45, 2),
+};
+
+static struct rt2880_pmx_func i2c_grp_mt7628[] = {
+ FUNC("-", 3, 4, 2),
+ FUNC("debug", 2, 4, 2),
+ FUNC("gpio", 1, 4, 2),
+ FUNC("i2c", 0, 4, 2),
+};
+
+static struct rt2880_pmx_func refclk_grp_mt7628[] = { FUNC("refclk", 0, 37, 1) };
+static struct rt2880_pmx_func perst_grp_mt7628[] = { FUNC("perst", 0, 36, 1) };
+static struct rt2880_pmx_func wdt_grp_mt7628[] = { FUNC("wdt", 0, 38, 1) };
+static struct rt2880_pmx_func spi_grp_mt7628[] = { FUNC("spi", 0, 7, 4) };
+
+static struct rt2880_pmx_func sd_mode_grp_mt7628[] = {
+ FUNC("jtag", 3, 22, 8),
+ FUNC("utif", 2, 22, 8),
+ FUNC("gpio", 1, 22, 8),
+ FUNC("sdxc", 0, 22, 8),
+};
+
+static struct rt2880_pmx_func uart0_grp_mt7628[] = {
+ FUNC("-", 3, 12, 2),
+ FUNC("-", 2, 12, 2),
+ FUNC("gpio", 1, 12, 2),
+ FUNC("uart0", 0, 12, 2),
+};
+
+static struct rt2880_pmx_func i2s_grp_mt7628[] = {
+ FUNC("antenna", 3, 0, 4),
+ FUNC("pcm", 2, 0, 4),
+ FUNC("gpio", 1, 0, 4),
+ FUNC("i2s", 0, 0, 4),
+};
+
+static struct rt2880_pmx_func spi_cs1_grp_mt7628[] = {
+ FUNC("-", 3, 6, 1),
+ FUNC("refclk", 2, 6, 1),
+ FUNC("gpio", 1, 6, 1),
+ FUNC("spi cs1", 0, 6, 1),
+};
+
+static struct rt2880_pmx_func spis_grp_mt7628[] = {
+ FUNC("pwm_uart2", 3, 14, 4),
+ FUNC("utif", 2, 14, 4),
+ FUNC("gpio", 1, 14, 4),
+ FUNC("spis", 0, 14, 4),
+};
+
+static struct rt2880_pmx_func gpio_grp_mt7628[] = {
+ FUNC("pcie", 3, 11, 1),
+ FUNC("refclk", 2, 11, 1),
+ FUNC("gpio", 1, 11, 1),
+ FUNC("gpio", 0, 11, 1),
+};
+
+static struct rt2880_pmx_func p4led_kn_grp_mt7628[] = {
+ FUNC("jtag", 3, 30, 1),
+ FUNC("utif", 2, 30, 1),
+ FUNC("gpio", 1, 30, 1),
+ FUNC("p4led_kn", 0, 30, 1),
+};
+
+static struct rt2880_pmx_func p3led_kn_grp_mt7628[] = {
+ FUNC("jtag", 3, 31, 1),
+ FUNC("utif", 2, 31, 1),
+ FUNC("gpio", 1, 31, 1),
+ FUNC("p3led_kn", 0, 31, 1),
+};
+
+static struct rt2880_pmx_func p2led_kn_grp_mt7628[] = {
+ FUNC("jtag", 3, 32, 1),
+ FUNC("utif", 2, 32, 1),
+ FUNC("gpio", 1, 32, 1),
+ FUNC("p2led_kn", 0, 32, 1),
+};
+
+static struct rt2880_pmx_func p1led_kn_grp_mt7628[] = {
+ FUNC("jtag", 3, 33, 1),
+ FUNC("utif", 2, 33, 1),
+ FUNC("gpio", 1, 33, 1),
+ FUNC("p1led_kn", 0, 33, 1),
+};
+
+static struct rt2880_pmx_func p0led_kn_grp_mt7628[] = {
+ FUNC("jtag", 3, 34, 1),
+ FUNC("rsvd", 2, 34, 1),
+ FUNC("gpio", 1, 34, 1),
+ FUNC("p0led_kn", 0, 34, 1),
+};
+
+static struct rt2880_pmx_func wled_kn_grp_mt7628[] = {
+ FUNC("rsvd", 3, 35, 1),
+ FUNC("rsvd", 2, 35, 1),
+ FUNC("gpio", 1, 35, 1),
+ FUNC("wled_kn", 0, 35, 1),
+};
+
+static struct rt2880_pmx_func p4led_an_grp_mt7628[] = {
+ FUNC("jtag", 3, 39, 1),
+ FUNC("utif", 2, 39, 1),
+ FUNC("gpio", 1, 39, 1),
+ FUNC("p4led_an", 0, 39, 1),
+};
+
+static struct rt2880_pmx_func p3led_an_grp_mt7628[] = {
+ FUNC("jtag", 3, 40, 1),
+ FUNC("utif", 2, 40, 1),
+ FUNC("gpio", 1, 40, 1),
+ FUNC("p3led_an", 0, 40, 1),
+};
+
+static struct rt2880_pmx_func p2led_an_grp_mt7628[] = {
+ FUNC("jtag", 3, 41, 1),
+ FUNC("utif", 2, 41, 1),
+ FUNC("gpio", 1, 41, 1),
+ FUNC("p2led_an", 0, 41, 1),
+};
+
+static struct rt2880_pmx_func p1led_an_grp_mt7628[] = {
+ FUNC("jtag", 3, 42, 1),
+ FUNC("utif", 2, 42, 1),
+ FUNC("gpio", 1, 42, 1),
+ FUNC("p1led_an", 0, 42, 1),
+};
+
+static struct rt2880_pmx_func p0led_an_grp_mt7628[] = {
+ FUNC("jtag", 3, 43, 1),
+ FUNC("rsvd", 2, 43, 1),
+ FUNC("gpio", 1, 43, 1),
+ FUNC("p0led_an", 0, 43, 1),
+};
+
+static struct rt2880_pmx_func wled_an_grp_mt7628[] = {
+ FUNC("rsvd", 3, 44, 1),
+ FUNC("rsvd", 2, 44, 1),
+ FUNC("gpio", 1, 44, 1),
+ FUNC("wled_an", 0, 44, 1),
+};
+
+#define MT7628_GPIO_MODE_MASK 0x3
+
+#define MT7628_GPIO_MODE_P4LED_KN 58
+#define MT7628_GPIO_MODE_P3LED_KN 56
+#define MT7628_GPIO_MODE_P2LED_KN 54
+#define MT7628_GPIO_MODE_P1LED_KN 52
+#define MT7628_GPIO_MODE_P0LED_KN 50
+#define MT7628_GPIO_MODE_WLED_KN 48
+#define MT7628_GPIO_MODE_P4LED_AN 42
+#define MT7628_GPIO_MODE_P3LED_AN 40
+#define MT7628_GPIO_MODE_P2LED_AN 38
+#define MT7628_GPIO_MODE_P1LED_AN 36
+#define MT7628_GPIO_MODE_P0LED_AN 34
+#define MT7628_GPIO_MODE_WLED_AN 32
+#define MT7628_GPIO_MODE_PWM1 30
+#define MT7628_GPIO_MODE_PWM0 28
+#define MT7628_GPIO_MODE_UART2 26
+#define MT7628_GPIO_MODE_UART1 24
+#define MT7628_GPIO_MODE_I2C 20
+#define MT7628_GPIO_MODE_REFCLK 18
+#define MT7628_GPIO_MODE_PERST 16
+#define MT7628_GPIO_MODE_WDT 14
+#define MT7628_GPIO_MODE_SPI 12
+#define MT7628_GPIO_MODE_SDMODE 10
+#define MT7628_GPIO_MODE_UART0 8
+#define MT7628_GPIO_MODE_I2S 6
+#define MT7628_GPIO_MODE_CS1 4
+#define MT7628_GPIO_MODE_SPIS 2
+#define MT7628_GPIO_MODE_GPIO 0
+
+static struct rt2880_pmx_group mt7628an_pinmux_data[] = {
+ GRP_G("pwm1", pwm1_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_PWM1),
+ GRP_G("pwm0", pwm0_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_PWM0),
+ GRP_G("uart2", uart2_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_UART2),
+ GRP_G("uart1", uart1_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_UART1),
+ GRP_G("i2c", i2c_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_I2C),
+ GRP("refclk", refclk_grp_mt7628, 1, MT7628_GPIO_MODE_REFCLK),
+ GRP("perst", perst_grp_mt7628, 1, MT7628_GPIO_MODE_PERST),
+ GRP("wdt", wdt_grp_mt7628, 1, MT7628_GPIO_MODE_WDT),
+ GRP("spi", spi_grp_mt7628, 1, MT7628_GPIO_MODE_SPI),
+ GRP_G("sdmode", sd_mode_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_SDMODE),
+ GRP_G("uart0", uart0_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_UART0),
+ GRP_G("i2s", i2s_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_I2S),
+ GRP_G("spi cs1", spi_cs1_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_CS1),
+ GRP_G("spis", spis_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_SPIS),
+ GRP_G("gpio", gpio_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_GPIO),
+ GRP_G("wled_an", wled_an_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_WLED_AN),
+ GRP_G("p0led_an", p0led_an_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_P0LED_AN),
+ GRP_G("p1led_an", p1led_an_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_P1LED_AN),
+ GRP_G("p2led_an", p2led_an_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_P2LED_AN),
+ GRP_G("p3led_an", p3led_an_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_P3LED_AN),
+ GRP_G("p4led_an", p4led_an_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_P4LED_AN),
+ GRP_G("wled_kn", wled_kn_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_WLED_KN),
+ GRP_G("p0led_kn", p0led_kn_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_P0LED_KN),
+ GRP_G("p1led_kn", p1led_kn_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_P1LED_KN),
+ GRP_G("p2led_kn", p2led_kn_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_P2LED_KN),
+ GRP_G("p3led_kn", p3led_kn_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_P3LED_KN),
+ GRP_G("p4led_kn", p4led_kn_grp_mt7628, MT7628_GPIO_MODE_MASK,
+ 1, MT7628_GPIO_MODE_P4LED_KN),
+ { 0 }
+};
+
+static int mt7620_pinmux_probe(struct platform_device *pdev)
+{
+ if (is_mt76x8())
+ return rt2880_pinmux_init(pdev, mt7628an_pinmux_data);
+ else
+ return rt2880_pinmux_init(pdev, mt7620a_pinmux_data);
+}
+
+static const struct of_device_id mt7620_pinmux_match[] = {
+ { .compatible = "ralink,rt2880-pinmux" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mt7620_pinmux_match);
+
+static struct platform_driver mt7620_pinmux_driver = {
+ .probe = mt7620_pinmux_probe,
+ .driver = {
+ .name = "rt2880-pinmux",
+ .of_match_table = mt7620_pinmux_match,
+ },
+};
+
+static int __init mt7620_pinmux_init(void)
+{
+ return platform_driver_register(&mt7620_pinmux_driver);
+}
+core_initcall_sync(mt7620_pinmux_init);
diff --git a/drivers/pinctrl/ralink/pinctrl-mt7621.c b/drivers/pinctrl/ralink/pinctrl-mt7621.c
new file mode 100644
index 000000000000..7d96144c474e
--- /dev/null
+++ b/drivers/pinctrl/ralink/pinctrl-mt7621.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include "pinmux.h"
+
+#define MT7621_GPIO_MODE_UART1 1
+#define MT7621_GPIO_MODE_I2C 2
+#define MT7621_GPIO_MODE_UART3_MASK 0x3
+#define MT7621_GPIO_MODE_UART3_SHIFT 3
+#define MT7621_GPIO_MODE_UART3_GPIO 1
+#define MT7621_GPIO_MODE_UART2_MASK 0x3
+#define MT7621_GPIO_MODE_UART2_SHIFT 5
+#define MT7621_GPIO_MODE_UART2_GPIO 1
+#define MT7621_GPIO_MODE_JTAG 7
+#define MT7621_GPIO_MODE_WDT_MASK 0x3
+#define MT7621_GPIO_MODE_WDT_SHIFT 8
+#define MT7621_GPIO_MODE_WDT_GPIO 1
+#define MT7621_GPIO_MODE_PCIE_RST 0
+#define MT7621_GPIO_MODE_PCIE_REF 2
+#define MT7621_GPIO_MODE_PCIE_MASK 0x3
+#define MT7621_GPIO_MODE_PCIE_SHIFT 10
+#define MT7621_GPIO_MODE_PCIE_GPIO 1
+#define MT7621_GPIO_MODE_MDIO_MASK 0x3
+#define MT7621_GPIO_MODE_MDIO_SHIFT 12
+#define MT7621_GPIO_MODE_MDIO_GPIO 1
+#define MT7621_GPIO_MODE_RGMII1 14
+#define MT7621_GPIO_MODE_RGMII2 15
+#define MT7621_GPIO_MODE_SPI_MASK 0x3
+#define MT7621_GPIO_MODE_SPI_SHIFT 16
+#define MT7621_GPIO_MODE_SPI_GPIO 1
+#define MT7621_GPIO_MODE_SDHCI_MASK 0x3
+#define MT7621_GPIO_MODE_SDHCI_SHIFT 18
+#define MT7621_GPIO_MODE_SDHCI_GPIO 1
+
+static struct rt2880_pmx_func uart1_grp[] = { FUNC("uart1", 0, 1, 2) };
+static struct rt2880_pmx_func i2c_grp[] = { FUNC("i2c", 0, 3, 2) };
+static struct rt2880_pmx_func uart3_grp[] = {
+ FUNC("uart3", 0, 5, 4),
+ FUNC("i2s", 2, 5, 4),
+ FUNC("spdif3", 3, 5, 4),
+};
+static struct rt2880_pmx_func uart2_grp[] = {
+ FUNC("uart2", 0, 9, 4),
+ FUNC("pcm", 2, 9, 4),
+ FUNC("spdif2", 3, 9, 4),
+};
+static struct rt2880_pmx_func jtag_grp[] = { FUNC("jtag", 0, 13, 5) };
+static struct rt2880_pmx_func wdt_grp[] = {
+ FUNC("wdt rst", 0, 18, 1),
+ FUNC("wdt refclk", 2, 18, 1),
+};
+static struct rt2880_pmx_func pcie_rst_grp[] = {
+ FUNC("pcie rst", MT7621_GPIO_MODE_PCIE_RST, 19, 1),
+ FUNC("pcie refclk", MT7621_GPIO_MODE_PCIE_REF, 19, 1)
+};
+static struct rt2880_pmx_func mdio_grp[] = { FUNC("mdio", 0, 20, 2) };
+static struct rt2880_pmx_func rgmii2_grp[] = { FUNC("rgmii2", 0, 22, 12) };
+static struct rt2880_pmx_func spi_grp[] = {
+ FUNC("spi", 0, 34, 7),
+ FUNC("nand1", 2, 34, 7),
+};
+static struct rt2880_pmx_func sdhci_grp[] = {
+ FUNC("sdhci", 0, 41, 8),
+ FUNC("nand2", 2, 41, 8),
+};
+static struct rt2880_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 49, 12) };
+
+static struct rt2880_pmx_group mt7621_pinmux_data[] = {
+ GRP("uart1", uart1_grp, 1, MT7621_GPIO_MODE_UART1),
+ GRP("i2c", i2c_grp, 1, MT7621_GPIO_MODE_I2C),
+ GRP_G("uart3", uart3_grp, MT7621_GPIO_MODE_UART3_MASK,
+ MT7621_GPIO_MODE_UART3_GPIO, MT7621_GPIO_MODE_UART3_SHIFT),
+ GRP_G("uart2", uart2_grp, MT7621_GPIO_MODE_UART2_MASK,
+ MT7621_GPIO_MODE_UART2_GPIO, MT7621_GPIO_MODE_UART2_SHIFT),
+ GRP("jtag", jtag_grp, 1, MT7621_GPIO_MODE_JTAG),
+ GRP_G("wdt", wdt_grp, MT7621_GPIO_MODE_WDT_MASK,
+ MT7621_GPIO_MODE_WDT_GPIO, MT7621_GPIO_MODE_WDT_SHIFT),
+ GRP_G("pcie", pcie_rst_grp, MT7621_GPIO_MODE_PCIE_MASK,
+ MT7621_GPIO_MODE_PCIE_GPIO, MT7621_GPIO_MODE_PCIE_SHIFT),
+ GRP_G("mdio", mdio_grp, MT7621_GPIO_MODE_MDIO_MASK,
+ MT7621_GPIO_MODE_MDIO_GPIO, MT7621_GPIO_MODE_MDIO_SHIFT),
+ GRP("rgmii2", rgmii2_grp, 1, MT7621_GPIO_MODE_RGMII2),
+ GRP_G("spi", spi_grp, MT7621_GPIO_MODE_SPI_MASK,
+ MT7621_GPIO_MODE_SPI_GPIO, MT7621_GPIO_MODE_SPI_SHIFT),
+ GRP_G("sdhci", sdhci_grp, MT7621_GPIO_MODE_SDHCI_MASK,
+ MT7621_GPIO_MODE_SDHCI_GPIO, MT7621_GPIO_MODE_SDHCI_SHIFT),
+ GRP("rgmii1", rgmii1_grp, 1, MT7621_GPIO_MODE_RGMII1),
+ { 0 }
+};
+
+static int mt7621_pinmux_probe(struct platform_device *pdev)
+{
+ return rt2880_pinmux_init(pdev, mt7621_pinmux_data);
+}
+
+static const struct of_device_id mt7621_pinmux_match[] = {
+ { .compatible = "ralink,rt2880-pinmux" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mt7621_pinmux_match);
+
+static struct platform_driver mt7621_pinmux_driver = {
+ .probe = mt7621_pinmux_probe,
+ .driver = {
+ .name = "rt2880-pinmux",
+ .of_match_table = mt7621_pinmux_match,
+ },
+};
+
+static int __init mt7621_pinmux_init(void)
+{
+ return platform_driver_register(&mt7621_pinmux_driver);
+}
+core_initcall_sync(mt7621_pinmux_init);
diff --git a/drivers/pinctrl/ralink/pinctrl-rt2880.c b/drivers/pinctrl/ralink/pinctrl-rt2880.c
index a9b511c7e850..96fc06d1b8b9 100644
--- a/drivers/pinctrl/ralink/pinctrl-rt2880.c
+++ b/drivers/pinctrl/ralink/pinctrl-rt2880.c
@@ -17,9 +17,9 @@
#include <linux/pinctrl/machine.h>
#include <asm/mach-ralink/ralink_regs.h>
-#include <asm/mach-ralink/pinmux.h>
#include <asm/mach-ralink/mt7620.h>
+#include "pinmux.h"
#include "../core.h"
#include "../pinctrl-utils.h"
@@ -311,13 +311,14 @@ static int rt2880_pinmux_pins(struct rt2880_priv *p)
return 0;
}
-static int rt2880_pinmux_probe(struct platform_device *pdev)
+int rt2880_pinmux_init(struct platform_device *pdev,
+ struct rt2880_pmx_group *data)
{
struct rt2880_priv *p;
struct pinctrl_dev *dev;
int err;
- if (!rt2880_pinmux_data)
+ if (!data)
return -ENOTSUPP;
/* setup the private data */
@@ -327,7 +328,7 @@ static int rt2880_pinmux_probe(struct platform_device *pdev)
p->dev = &pdev->dev;
p->desc = &rt2880_pctrl_desc;
- p->groups = rt2880_pinmux_data;
+ p->groups = data;
platform_set_drvdata(pdev, p);
/* init the device */
@@ -346,24 +347,3 @@ static int rt2880_pinmux_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(dev);
}
-
-static const struct of_device_id rt2880_pinmux_match[] = {
- { .compatible = "ralink,rt2880-pinmux" },
- {},
-};
-MODULE_DEVICE_TABLE(of, rt2880_pinmux_match);
-
-static struct platform_driver rt2880_pinmux_driver = {
- .probe = rt2880_pinmux_probe,
- .driver = {
- .name = "rt2880-pinmux",
- .of_match_table = rt2880_pinmux_match,
- },
-};
-
-static int __init rt2880_pinmux_init(void)
-{
- return platform_driver_register(&rt2880_pinmux_driver);
-}
-
-core_initcall_sync(rt2880_pinmux_init);
diff --git a/drivers/pinctrl/ralink/pinctrl-rt288x.c b/drivers/pinctrl/ralink/pinctrl-rt288x.c
new file mode 100644
index 000000000000..0744aebbace5
--- /dev/null
+++ b/drivers/pinctrl/ralink/pinctrl-rt288x.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include "pinmux.h"
+
+#define RT2880_GPIO_MODE_I2C BIT(0)
+#define RT2880_GPIO_MODE_UART0 BIT(1)
+#define RT2880_GPIO_MODE_SPI BIT(2)
+#define RT2880_GPIO_MODE_UART1 BIT(3)
+#define RT2880_GPIO_MODE_JTAG BIT(4)
+#define RT2880_GPIO_MODE_MDIO BIT(5)
+#define RT2880_GPIO_MODE_SDRAM BIT(6)
+#define RT2880_GPIO_MODE_PCI BIT(7)
+
+static struct rt2880_pmx_func i2c_func[] = { FUNC("i2c", 0, 1, 2) };
+static struct rt2880_pmx_func spi_func[] = { FUNC("spi", 0, 3, 4) };
+static struct rt2880_pmx_func uartlite_func[] = { FUNC("uartlite", 0, 7, 8) };
+static struct rt2880_pmx_func jtag_func[] = { FUNC("jtag", 0, 17, 5) };
+static struct rt2880_pmx_func mdio_func[] = { FUNC("mdio", 0, 22, 2) };
+static struct rt2880_pmx_func sdram_func[] = { FUNC("sdram", 0, 24, 16) };
+static struct rt2880_pmx_func pci_func[] = { FUNC("pci", 0, 40, 32) };
+
+static struct rt2880_pmx_group rt2880_pinmux_data_act[] = {
+ GRP("i2c", i2c_func, 1, RT2880_GPIO_MODE_I2C),
+ GRP("spi", spi_func, 1, RT2880_GPIO_MODE_SPI),
+ GRP("uartlite", uartlite_func, 1, RT2880_GPIO_MODE_UART0),
+ GRP("jtag", jtag_func, 1, RT2880_GPIO_MODE_JTAG),
+ GRP("mdio", mdio_func, 1, RT2880_GPIO_MODE_MDIO),
+ GRP("sdram", sdram_func, 1, RT2880_GPIO_MODE_SDRAM),
+ GRP("pci", pci_func, 1, RT2880_GPIO_MODE_PCI),
+ { 0 }
+};
+
+static int rt288x_pinmux_probe(struct platform_device *pdev)
+{
+ return rt2880_pinmux_init(pdev, rt2880_pinmux_data_act);
+}
+
+static const struct of_device_id rt288x_pinmux_match[] = {
+ { .compatible = "ralink,rt2880-pinmux" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rt288x_pinmux_match);
+
+static struct platform_driver rt288x_pinmux_driver = {
+ .probe = rt288x_pinmux_probe,
+ .driver = {
+ .name = "rt2880-pinmux",
+ .of_match_table = rt288x_pinmux_match,
+ },
+};
+
+static int __init rt288x_pinmux_init(void)
+{
+ return platform_driver_register(&rt288x_pinmux_driver);
+}
+core_initcall_sync(rt288x_pinmux_init);
diff --git a/drivers/pinctrl/ralink/pinctrl-rt305x.c b/drivers/pinctrl/ralink/pinctrl-rt305x.c
new file mode 100644
index 000000000000..5d8fa156c003
--- /dev/null
+++ b/drivers/pinctrl/ralink/pinctrl-rt305x.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <asm/mach-ralink/ralink_regs.h>
+#include <asm/mach-ralink/rt305x.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include "pinmux.h"
+
+#define RT305X_GPIO_MODE_UART0_SHIFT 2
+#define RT305X_GPIO_MODE_UART0_MASK 0x7
+#define RT305X_GPIO_MODE_UART0(x) ((x) << RT305X_GPIO_MODE_UART0_SHIFT)
+#define RT305X_GPIO_MODE_UARTF 0
+#define RT305X_GPIO_MODE_PCM_UARTF 1
+#define RT305X_GPIO_MODE_PCM_I2S 2
+#define RT305X_GPIO_MODE_I2S_UARTF 3
+#define RT305X_GPIO_MODE_PCM_GPIO 4
+#define RT305X_GPIO_MODE_GPIO_UARTF 5
+#define RT305X_GPIO_MODE_GPIO_I2S 6
+#define RT305X_GPIO_MODE_GPIO 7
+
+#define RT305X_GPIO_MODE_I2C 0
+#define RT305X_GPIO_MODE_SPI 1
+#define RT305X_GPIO_MODE_UART1 5
+#define RT305X_GPIO_MODE_JTAG 6
+#define RT305X_GPIO_MODE_MDIO 7
+#define RT305X_GPIO_MODE_SDRAM 8
+#define RT305X_GPIO_MODE_RGMII 9
+#define RT5350_GPIO_MODE_PHY_LED 14
+#define RT5350_GPIO_MODE_SPI_CS1 21
+#define RT3352_GPIO_MODE_LNA 18
+#define RT3352_GPIO_MODE_PA 20
+
+static struct rt2880_pmx_func i2c_func[] = { FUNC("i2c", 0, 1, 2) };
+static struct rt2880_pmx_func spi_func[] = { FUNC("spi", 0, 3, 4) };
+static struct rt2880_pmx_func uartf_func[] = {
+ FUNC("uartf", RT305X_GPIO_MODE_UARTF, 7, 8),
+ FUNC("pcm uartf", RT305X_GPIO_MODE_PCM_UARTF, 7, 8),
+ FUNC("pcm i2s", RT305X_GPIO_MODE_PCM_I2S, 7, 8),
+ FUNC("i2s uartf", RT305X_GPIO_MODE_I2S_UARTF, 7, 8),
+ FUNC("pcm gpio", RT305X_GPIO_MODE_PCM_GPIO, 11, 4),
+ FUNC("gpio uartf", RT305X_GPIO_MODE_GPIO_UARTF, 7, 4),
+ FUNC("gpio i2s", RT305X_GPIO_MODE_GPIO_I2S, 7, 4),
+};
+static struct rt2880_pmx_func uartlite_func[] = { FUNC("uartlite", 0, 15, 2) };
+static struct rt2880_pmx_func jtag_func[] = { FUNC("jtag", 0, 17, 5) };
+static struct rt2880_pmx_func mdio_func[] = { FUNC("mdio", 0, 22, 2) };
+static struct rt2880_pmx_func rt5350_led_func[] = { FUNC("led", 0, 22, 5) };
+static struct rt2880_pmx_func rt5350_cs1_func[] = {
+ FUNC("spi_cs1", 0, 27, 1),
+ FUNC("wdg_cs1", 1, 27, 1),
+};
+static struct rt2880_pmx_func sdram_func[] = { FUNC("sdram", 0, 24, 16) };
+static struct rt2880_pmx_func rt3352_rgmii_func[] = {
+ FUNC("rgmii", 0, 24, 12)
+};
+static struct rt2880_pmx_func rgmii_func[] = { FUNC("rgmii", 0, 40, 12) };
+static struct rt2880_pmx_func rt3352_lna_func[] = { FUNC("lna", 0, 36, 2) };
+static struct rt2880_pmx_func rt3352_pa_func[] = { FUNC("pa", 0, 38, 2) };
+static struct rt2880_pmx_func rt3352_led_func[] = { FUNC("led", 0, 40, 5) };
+static struct rt2880_pmx_func rt3352_cs1_func[] = {
+ FUNC("spi_cs1", 0, 45, 1),
+ FUNC("wdg_cs1", 1, 45, 1),
+};
+
+static struct rt2880_pmx_group rt3050_pinmux_data[] = {
+ GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C),
+ GRP("spi", spi_func, 1, RT305X_GPIO_MODE_SPI),
+ GRP("uartf", uartf_func, RT305X_GPIO_MODE_UART0_MASK,
+ RT305X_GPIO_MODE_UART0_SHIFT),
+ GRP("uartlite", uartlite_func, 1, RT305X_GPIO_MODE_UART1),
+ GRP("jtag", jtag_func, 1, RT305X_GPIO_MODE_JTAG),
+ GRP("mdio", mdio_func, 1, RT305X_GPIO_MODE_MDIO),
+ GRP("rgmii", rgmii_func, 1, RT305X_GPIO_MODE_RGMII),
+ GRP("sdram", sdram_func, 1, RT305X_GPIO_MODE_SDRAM),
+ { 0 }
+};
+
+static struct rt2880_pmx_group rt3352_pinmux_data[] = {
+ GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C),
+ GRP("spi", spi_func, 1, RT305X_GPIO_MODE_SPI),
+ GRP("uartf", uartf_func, RT305X_GPIO_MODE_UART0_MASK,
+ RT305X_GPIO_MODE_UART0_SHIFT),
+ GRP("uartlite", uartlite_func, 1, RT305X_GPIO_MODE_UART1),
+ GRP("jtag", jtag_func, 1, RT305X_GPIO_MODE_JTAG),
+ GRP("mdio", mdio_func, 1, RT305X_GPIO_MODE_MDIO),
+ GRP("rgmii", rt3352_rgmii_func, 1, RT305X_GPIO_MODE_RGMII),
+ GRP("lna", rt3352_lna_func, 1, RT3352_GPIO_MODE_LNA),
+ GRP("pa", rt3352_pa_func, 1, RT3352_GPIO_MODE_PA),
+ GRP("led", rt3352_led_func, 1, RT5350_GPIO_MODE_PHY_LED),
+ GRP("spi_cs1", rt3352_cs1_func, 2, RT5350_GPIO_MODE_SPI_CS1),
+ { 0 }
+};
+
+static struct rt2880_pmx_group rt5350_pinmux_data[] = {
+ GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C),
+ GRP("spi", spi_func, 1, RT305X_GPIO_MODE_SPI),
+ GRP("uartf", uartf_func, RT305X_GPIO_MODE_UART0_MASK,
+ RT305X_GPIO_MODE_UART0_SHIFT),
+ GRP("uartlite", uartlite_func, 1, RT305X_GPIO_MODE_UART1),
+ GRP("jtag", jtag_func, 1, RT305X_GPIO_MODE_JTAG),
+ GRP("led", rt5350_led_func, 1, RT5350_GPIO_MODE_PHY_LED),
+ GRP("spi_cs1", rt5350_cs1_func, 2, RT5350_GPIO_MODE_SPI_CS1),
+ { 0 }
+};
+
+static int rt305x_pinmux_probe(struct platform_device *pdev)
+{
+ if (soc_is_rt5350())
+ return rt2880_pinmux_init(pdev, rt5350_pinmux_data);
+ else if (soc_is_rt305x() || soc_is_rt3350())
+ return rt2880_pinmux_init(pdev, rt3050_pinmux_data);
+ else if (soc_is_rt3352())
+ return rt2880_pinmux_init(pdev, rt3352_pinmux_data);
+ else
+ return -EINVAL;
+}
+
+static const struct of_device_id rt305x_pinmux_match[] = {
+ { .compatible = "ralink,rt2880-pinmux" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rt305x_pinmux_match);
+
+static struct platform_driver rt305x_pinmux_driver = {
+ .probe = rt305x_pinmux_probe,
+ .driver = {
+ .name = "rt2880-pinmux",
+ .of_match_table = rt305x_pinmux_match,
+ },
+};
+
+static int __init rt305x_pinmux_init(void)
+{
+ return platform_driver_register(&rt305x_pinmux_driver);
+}
+core_initcall_sync(rt305x_pinmux_init);
diff --git a/drivers/pinctrl/ralink/pinctrl-rt3883.c b/drivers/pinctrl/ralink/pinctrl-rt3883.c
new file mode 100644
index 000000000000..3e0e1b4caa64
--- /dev/null
+++ b/drivers/pinctrl/ralink/pinctrl-rt3883.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include "pinmux.h"
+
+#define RT3883_GPIO_MODE_UART0_SHIFT 2
+#define RT3883_GPIO_MODE_UART0_MASK 0x7
+#define RT3883_GPIO_MODE_UART0(x) ((x) << RT3883_GPIO_MODE_UART0_SHIFT)
+#define RT3883_GPIO_MODE_UARTF 0x0
+#define RT3883_GPIO_MODE_PCM_UARTF 0x1
+#define RT3883_GPIO_MODE_PCM_I2S 0x2
+#define RT3883_GPIO_MODE_I2S_UARTF 0x3
+#define RT3883_GPIO_MODE_PCM_GPIO 0x4
+#define RT3883_GPIO_MODE_GPIO_UARTF 0x5
+#define RT3883_GPIO_MODE_GPIO_I2S 0x6
+#define RT3883_GPIO_MODE_GPIO 0x7
+
+#define RT3883_GPIO_MODE_I2C 0
+#define RT3883_GPIO_MODE_SPI 1
+#define RT3883_GPIO_MODE_UART1 5
+#define RT3883_GPIO_MODE_JTAG 6
+#define RT3883_GPIO_MODE_MDIO 7
+#define RT3883_GPIO_MODE_GE1 9
+#define RT3883_GPIO_MODE_GE2 10
+
+#define RT3883_GPIO_MODE_PCI_SHIFT 11
+#define RT3883_GPIO_MODE_PCI_MASK 0x7
+#define RT3883_GPIO_MODE_PCI (RT3883_GPIO_MODE_PCI_MASK << RT3883_GPIO_MODE_PCI_SHIFT)
+#define RT3883_GPIO_MODE_LNA_A_SHIFT 16
+#define RT3883_GPIO_MODE_LNA_A_MASK 0x3
+#define _RT3883_GPIO_MODE_LNA_A(_x) ((_x) << RT3883_GPIO_MODE_LNA_A_SHIFT)
+#define RT3883_GPIO_MODE_LNA_A_GPIO 0x3
+#define RT3883_GPIO_MODE_LNA_A _RT3883_GPIO_MODE_LNA_A(RT3883_GPIO_MODE_LNA_A_MASK)
+#define RT3883_GPIO_MODE_LNA_G_SHIFT 18
+#define RT3883_GPIO_MODE_LNA_G_MASK 0x3
+#define _RT3883_GPIO_MODE_LNA_G(_x) ((_x) << RT3883_GPIO_MODE_LNA_G_SHIFT)
+#define RT3883_GPIO_MODE_LNA_G_GPIO 0x3
+#define RT3883_GPIO_MODE_LNA_G _RT3883_GPIO_MODE_LNA_G(RT3883_GPIO_MODE_LNA_G_MASK)
+
+static struct rt2880_pmx_func i2c_func[] = { FUNC("i2c", 0, 1, 2) };
+static struct rt2880_pmx_func spi_func[] = { FUNC("spi", 0, 3, 4) };
+static struct rt2880_pmx_func uartf_func[] = {
+ FUNC("uartf", RT3883_GPIO_MODE_UARTF, 7, 8),
+ FUNC("pcm uartf", RT3883_GPIO_MODE_PCM_UARTF, 7, 8),
+ FUNC("pcm i2s", RT3883_GPIO_MODE_PCM_I2S, 7, 8),
+ FUNC("i2s uartf", RT3883_GPIO_MODE_I2S_UARTF, 7, 8),
+ FUNC("pcm gpio", RT3883_GPIO_MODE_PCM_GPIO, 11, 4),
+ FUNC("gpio uartf", RT3883_GPIO_MODE_GPIO_UARTF, 7, 4),
+ FUNC("gpio i2s", RT3883_GPIO_MODE_GPIO_I2S, 7, 4),
+};
+static struct rt2880_pmx_func uartlite_func[] = { FUNC("uartlite", 0, 15, 2) };
+static struct rt2880_pmx_func jtag_func[] = { FUNC("jtag", 0, 17, 5) };
+static struct rt2880_pmx_func mdio_func[] = { FUNC("mdio", 0, 22, 2) };
+static struct rt2880_pmx_func lna_a_func[] = { FUNC("lna a", 0, 32, 3) };
+static struct rt2880_pmx_func lna_g_func[] = { FUNC("lna g", 0, 35, 3) };
+static struct rt2880_pmx_func pci_func[] = {
+ FUNC("pci-dev", 0, 40, 32),
+ FUNC("pci-host2", 1, 40, 32),
+ FUNC("pci-host1", 2, 40, 32),
+ FUNC("pci-fnc", 3, 40, 32)
+};
+static struct rt2880_pmx_func ge1_func[] = { FUNC("ge1", 0, 72, 12) };
+static struct rt2880_pmx_func ge2_func[] = { FUNC("ge2", 0, 84, 12) };
+
+static struct rt2880_pmx_group rt3883_pinmux_data[] = {
+ GRP("i2c", i2c_func, 1, RT3883_GPIO_MODE_I2C),
+ GRP("spi", spi_func, 1, RT3883_GPIO_MODE_SPI),
+ GRP("uartf", uartf_func, RT3883_GPIO_MODE_UART0_MASK,
+ RT3883_GPIO_MODE_UART0_SHIFT),
+ GRP("uartlite", uartlite_func, 1, RT3883_GPIO_MODE_UART1),
+ GRP("jtag", jtag_func, 1, RT3883_GPIO_MODE_JTAG),
+ GRP("mdio", mdio_func, 1, RT3883_GPIO_MODE_MDIO),
+ GRP("lna a", lna_a_func, 1, RT3883_GPIO_MODE_LNA_A),
+ GRP("lna g", lna_g_func, 1, RT3883_GPIO_MODE_LNA_G),
+ GRP("pci", pci_func, RT3883_GPIO_MODE_PCI_MASK,
+ RT3883_GPIO_MODE_PCI_SHIFT),
+ GRP("ge1", ge1_func, 1, RT3883_GPIO_MODE_GE1),
+ GRP("ge2", ge2_func, 1, RT3883_GPIO_MODE_GE2),
+ { 0 }
+};
+
+static int rt3883_pinmux_probe(struct platform_device *pdev)
+{
+ return rt2880_pinmux_init(pdev, rt3883_pinmux_data);
+}
+
+static const struct of_device_id rt3883_pinmux_match[] = {
+ { .compatible = "ralink,rt2880-pinmux" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rt3883_pinmux_match);
+
+static struct platform_driver rt3883_pinmux_driver = {
+ .probe = rt3883_pinmux_probe,
+ .driver = {
+ .name = "rt2880-pinmux",
+ .of_match_table = rt3883_pinmux_match,
+ },
+};
+
+static int __init rt3883_pinmux_init(void)
+{
+ return platform_driver_register(&rt3883_pinmux_driver);
+}
+core_initcall_sync(rt3883_pinmux_init);
diff --git a/drivers/pinctrl/ralink/pinmux.h b/drivers/pinctrl/ralink/pinmux.h
new file mode 100644
index 000000000000..0046abe3bcc7
--- /dev/null
+++ b/drivers/pinctrl/ralink/pinmux.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2012 John Crispin <john@phrozen.org>
+ */
+
+#ifndef _RT288X_PINMUX_H__
+#define _RT288X_PINMUX_H__
+
+#define FUNC(name, value, pin_first, pin_count) \
+ { name, value, pin_first, pin_count }
+
+#define GRP(_name, _func, _mask, _shift) \
+ { .name = _name, .mask = _mask, .shift = _shift, \
+ .func = _func, .gpio = _mask, \
+ .func_count = ARRAY_SIZE(_func) }
+
+#define GRP_G(_name, _func, _mask, _gpio, _shift) \
+ { .name = _name, .mask = _mask, .shift = _shift, \
+ .func = _func, .gpio = _gpio, \
+ .func_count = ARRAY_SIZE(_func) }
+
+struct rt2880_pmx_group;
+
+struct rt2880_pmx_func {
+ const char *name;
+ const char value;
+
+ int pin_first;
+ int pin_count;
+ int *pins;
+
+ int *groups;
+ int group_count;
+
+ int enabled;
+};
+
+struct rt2880_pmx_group {
+ const char *name;
+ int enabled;
+
+ const u32 shift;
+ const char mask;
+ const char gpio;
+
+ struct rt2880_pmx_func *func;
+ int func_count;
+};
+
+int rt2880_pinmux_init(struct platform_device *pdev,
+ struct rt2880_pmx_group *data);
+
+#endif
diff --git a/drivers/pinctrl/renesas/pfc-r8a77470.c b/drivers/pinctrl/renesas/pfc-r8a77470.c
index b3b116da1bb0..e6e5487691c1 100644
--- a/drivers/pinctrl/renesas/pfc-r8a77470.c
+++ b/drivers/pinctrl/renesas/pfc-r8a77470.c
@@ -11,46 +11,56 @@
#include "sh_pfc.h"
#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), \
- PORT_GP_CFG_1(0, 6, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(0, 7, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(0, 8, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(0, 9, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(0, 10, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_1(0, 11, fn, sfx), \
- PORT_GP_1(0, 12, fn, sfx), \
- PORT_GP_CFG_1(0, 13, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(0, 14, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(0, 15, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(0, 16, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(0, 17, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(0, 18, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(0, 19, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(0, 20, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(0, 21, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(0, 22, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_23(1, fn, sfx), \
- PORT_GP_32(2, fn, sfx), \
- PORT_GP_17(3, fn, sfx), \
- PORT_GP_1(3, 27, fn, sfx), \
- PORT_GP_1(3, 28, fn, sfx), \
- PORT_GP_1(3, 29, fn, sfx), \
- PORT_GP_14(4, fn, sfx), \
- PORT_GP_CFG_1(4, 14, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(4, 15, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(4, 16, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(4, 17, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(4, 18, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_CFG_1(4, 19, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_1(4, 20, fn, sfx), \
- PORT_GP_1(4, 21, fn, sfx), \
- PORT_GP_1(4, 22, fn, sfx), \
- PORT_GP_1(4, 23, fn, sfx), \
- PORT_GP_1(4, 24, fn, sfx), \
- PORT_GP_1(4, 25, fn, sfx), \
- PORT_GP_32(5, fn, sfx)
+ PORT_GP_CFG_4(0, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 5, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 6, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 7, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 8, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 9, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 10, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 11, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 12, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 13, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 14, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 15, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 16, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 17, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 18, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 19, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 20, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 21, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(0, 22, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_23(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_17(3, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(3, 27, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(3, 28, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(3, 29, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_14(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(4, 14, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(4, 15, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(4, 16, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(4, 17, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(4, 18, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(4, 19, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(4, 20, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(4, 21, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(4, 22, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(4, 23, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(4, 24, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(4, 25, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_32(5, fn, sfx, SH_PFC_PIN_CFG_PULL_UP)
+
+#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP_CFG(ASEBRK_N_ACK, "ASEBRK#/ACK", fn, SH_PFC_PIN_CFG_PULL_DOWN), \
+ PIN_NOGP_CFG(NMI, "NMI", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TDO, "TDO", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TMS, "TMS", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP)
enum {
PINMUX_RESERVED = 0,
@@ -1121,8 +1131,17 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_GPSR(IP17_27_24, VI0_VSYNC_N),
};
+/*
+ * 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(),
+ PINMUX_NOGP_ALL(),
};
/* - AVB -------------------------------------------------------------------- */
@@ -3420,8 +3439,254 @@ static int r8a77470_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin,
return bit;
}
+static const struct pinmux_bias_reg pinmux_bias_regs[] = {
+ { PINMUX_BIAS_REG("PUPR0", 0xe6060100, "N/A", 0) {
+ /* PUPR0 pull-up pins */
+ [ 0] = RCAR_GP_PIN(1, 0), /* D0 */
+ [ 1] = RCAR_GP_PIN(0, 22), /* MMC0_D7 */
+ [ 2] = RCAR_GP_PIN(0, 21), /* MMC0_D6 */
+ [ 3] = RCAR_GP_PIN(0, 20), /* MMC0_D5 */
+ [ 4] = RCAR_GP_PIN(0, 19), /* MMC0_D4 */
+ [ 5] = RCAR_GP_PIN(0, 18), /* MMC0_D3 */
+ [ 6] = RCAR_GP_PIN(0, 17), /* MMC0_D2 */
+ [ 7] = RCAR_GP_PIN(0, 16), /* MMC0_D1 */
+ [ 8] = RCAR_GP_PIN(0, 15), /* MMC0_D0 */
+ [ 9] = RCAR_GP_PIN(0, 14), /* MMC0_CMD */
+ [10] = RCAR_GP_PIN(0, 13), /* MMC0_CLK */
+ [11] = RCAR_GP_PIN(0, 12), /* SD0_WP */
+ [12] = RCAR_GP_PIN(0, 11), /* SD0_CD */
+ [13] = RCAR_GP_PIN(0, 10), /* SD0_DAT3 */
+ [14] = RCAR_GP_PIN(0, 9), /* SD0_DAT2 */
+ [15] = RCAR_GP_PIN(0, 8), /* SD0_DAT1 */
+ [16] = RCAR_GP_PIN(0, 7), /* SD0_DAT0 */
+ [17] = RCAR_GP_PIN(0, 6), /* SD0_CMD */
+ [18] = RCAR_GP_PIN(0, 5), /* SD0_CLK */
+ [19] = RCAR_GP_PIN(0, 4), /* CLKOUT */
+ [20] = PIN_NMI, /* NMI */
+ [21] = RCAR_GP_PIN(0, 3), /* USB1_OVC */
+ [22] = RCAR_GP_PIN(0, 2), /* USB1_PWEN */
+ [23] = RCAR_GP_PIN(0, 1), /* USB0_OVC */
+ [24] = RCAR_GP_PIN(0, 0), /* USB0_PWEN */
+ [25] = SH_PFC_PIN_NONE,
+ [26] = PIN_TDO, /* TDO */
+ [27] = PIN_TDI, /* TDI */
+ [28] = PIN_TMS, /* TMS */
+ [29] = PIN_TCK, /* TCK */
+ [30] = PIN_TRST_N, /* TRST# */
+ [31] = PIN_PRESETOUT_N, /* PRESETOUT# */
+ } },
+ { PINMUX_BIAS_REG("N/A", 0, "PUPR0", 0xe6060100) {
+ /* PUPR0 pull-down pins */
+ [ 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] = PIN_ASEBRK_N_ACK, /* ASEBRK#/ACK */
+ [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("PUPR1", 0xe6060104, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(2, 9), /* DU0_DG1 */
+ [ 1] = RCAR_GP_PIN(2, 8), /* DU0_DG0 */
+ [ 2] = RCAR_GP_PIN(2, 7), /* DU0_DR7 */
+ [ 3] = RCAR_GP_PIN(2, 6), /* DU0_DR6 */
+ [ 4] = RCAR_GP_PIN(2, 5), /* DU0_DR5 */
+ [ 5] = RCAR_GP_PIN(2, 4), /* DU0_DR4 */
+ [ 6] = RCAR_GP_PIN(2, 3), /* DU0_DR3 */
+ [ 7] = RCAR_GP_PIN(2, 2), /* DU0_DR2 */
+ [ 8] = RCAR_GP_PIN(2, 1), /* DU0_DR1 */
+ [ 9] = RCAR_GP_PIN(2, 0), /* DU0_DR0 */
+ [10] = RCAR_GP_PIN(1, 22), /* EX_WAIT0 */
+ [11] = RCAR_GP_PIN(1, 21), /* QSPI0_SSL */
+ [12] = RCAR_GP_PIN(1, 20), /* QSPI0_IO3 */
+ [13] = RCAR_GP_PIN(1, 19), /* QSPI0_IO2 */
+ [14] = RCAR_GP_PIN(1, 18), /* QSPI0_MISO/QSPI0_IO1 */
+ [15] = RCAR_GP_PIN(1, 17), /* QSPI0_MOSI/QSPI0_IO0 */
+ [16] = RCAR_GP_PIN(1, 16), /* QSPI0_SPCLK */
+ [17] = RCAR_GP_PIN(1, 15), /* D15 */
+ [18] = RCAR_GP_PIN(1, 14), /* D14 */
+ [19] = RCAR_GP_PIN(1, 13), /* D13 */
+ [20] = RCAR_GP_PIN(1, 12), /* D12 */
+ [21] = RCAR_GP_PIN(1, 11), /* D11 */
+ [22] = RCAR_GP_PIN(1, 10), /* D10 */
+ [23] = RCAR_GP_PIN(1, 9), /* D9 */
+ [24] = RCAR_GP_PIN(1, 8), /* D8 */
+ [25] = RCAR_GP_PIN(1, 7), /* D7 */
+ [26] = RCAR_GP_PIN(1, 6), /* D6 */
+ [27] = RCAR_GP_PIN(1, 5), /* D5 */
+ [28] = RCAR_GP_PIN(1, 4), /* D4 */
+ [29] = RCAR_GP_PIN(1, 3), /* D3 */
+ [30] = RCAR_GP_PIN(1, 2), /* D2 */
+ [31] = RCAR_GP_PIN(1, 1), /* D1 */
+ } },
+ { PINMUX_BIAS_REG("PUPR2", 0xe6060108, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(3, 9), /* VI1_CLKENB */
+ [ 1] = RCAR_GP_PIN(3, 8), /* VI1_DATA7 */
+ [ 2] = RCAR_GP_PIN(3, 7), /* VI1_DATA6 */
+ [ 3] = RCAR_GP_PIN(3, 6), /* VI1_DATA5 */
+ [ 4] = RCAR_GP_PIN(3, 5), /* VI1_DATA4 */
+ [ 5] = RCAR_GP_PIN(3, 4), /* VI1_DATA3 */
+ [ 6] = RCAR_GP_PIN(3, 3), /* VI1_DATA2 */
+ [ 7] = RCAR_GP_PIN(3, 2), /* VI1_DATA1 */
+ [ 8] = RCAR_GP_PIN(3, 1), /* VI1_DATA0 */
+ [ 9] = RCAR_GP_PIN(3, 0), /* VI1_CLK */
+ [10] = RCAR_GP_PIN(2, 31), /* DU0_CDE */
+ [11] = RCAR_GP_PIN(2, 30), /* DU0_DISP */
+ [12] = RCAR_GP_PIN(2, 29), /* DU0_EXODDF/DU0_ODDF_DISP_CDE */
+ [13] = RCAR_GP_PIN(2, 28), /* DU0_EXVSYNC/DU0_VSYNC */
+ [14] = RCAR_GP_PIN(2, 27), /* DU0_EXHSYNC/DU0_HSYNC */
+ [15] = RCAR_GP_PIN(2, 26), /* DU0_DOTCLKOUT1 */
+ [16] = RCAR_GP_PIN(2, 25), /* DU0_DOTCLKOUT0 */
+ [17] = RCAR_GP_PIN(2, 24), /* DU0_DOTCLKIN */
+ [18] = RCAR_GP_PIN(2, 23), /* DU0_DB7 */
+ [19] = RCAR_GP_PIN(2, 22), /* DU0_DB6 */
+ [20] = RCAR_GP_PIN(2, 21), /* DU0_DB5 */
+ [21] = RCAR_GP_PIN(2, 20), /* DU0_DB4 */
+ [22] = RCAR_GP_PIN(2, 19), /* DU0_DB3 */
+ [23] = RCAR_GP_PIN(2, 18), /* DU0_DB2 */
+ [24] = RCAR_GP_PIN(2, 17), /* DU0_DB1 */
+ [25] = RCAR_GP_PIN(2, 16), /* DU0_DB0 */
+ [26] = RCAR_GP_PIN(2, 15), /* DU0_DG7 */
+ [27] = RCAR_GP_PIN(2, 14), /* DU0_DG6 */
+ [28] = RCAR_GP_PIN(2, 13), /* DU0_DG5 */
+ [29] = RCAR_GP_PIN(2, 12), /* DU0_DG4 */
+ [30] = RCAR_GP_PIN(2, 11), /* DU0_DG3 */
+ [31] = RCAR_GP_PIN(2, 10), /* DU0_DG2 */
+ } },
+ { PINMUX_BIAS_REG("PUPR3", 0xe606010c, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(4, 21), /* SD2_WP */
+ [ 1] = RCAR_GP_PIN(4, 20), /* SD2_CD */
+ [ 2] = RCAR_GP_PIN(4, 19), /* SD2_DAT3 */
+ [ 3] = RCAR_GP_PIN(4, 18), /* SD2_DAT2 */
+ [ 4] = RCAR_GP_PIN(4, 17), /* SD2_DAT1 */
+ [ 5] = RCAR_GP_PIN(4, 16), /* SD2_DAT0 */
+ [ 6] = RCAR_GP_PIN(4, 15), /* SD2_CMD */
+ [ 7] = RCAR_GP_PIN(4, 14), /* SD2_CLK */
+ [ 8] = RCAR_GP_PIN(4, 13), /* HRTS1#_A */
+ [ 9] = RCAR_GP_PIN(4, 12), /* HCTS1#_A */
+ [10] = RCAR_GP_PIN(4, 11), /* HTX1_A */
+ [11] = RCAR_GP_PIN(4, 10), /* HRX1_A */
+ [12] = RCAR_GP_PIN(4, 9), /* MSIOF0_SS2_A */
+ [13] = RCAR_GP_PIN(4, 8), /* MSIOF0_SS1_A */
+ [14] = RCAR_GP_PIN(4, 7), /* MSIOF0_SYNC_A */
+ [15] = RCAR_GP_PIN(4, 6), /* MSIOF0_SCK_A */
+ [16] = RCAR_GP_PIN(4, 5), /* MSIOF0_TXD_A */
+ [17] = RCAR_GP_PIN(4, 4), /* MSIOF0_RXD_A */
+ [18] = RCAR_GP_PIN(4, 3), /* SDA1_A */
+ [19] = RCAR_GP_PIN(4, 2), /* SCL1_A */
+ [20] = RCAR_GP_PIN(4, 1), /* SDA0_A */
+ [21] = RCAR_GP_PIN(4, 0), /* SCL0_A */
+ [22] = RCAR_GP_PIN(3, 29), /* AVB_TXD5 */
+ [23] = RCAR_GP_PIN(3, 28), /* AVB_TXD4 */
+ [24] = RCAR_GP_PIN(3, 27), /* AVB_TXD3 */
+ [25] = RCAR_GP_PIN(3, 16), /* VI1_DATA11 */
+ [26] = RCAR_GP_PIN(3, 15), /* VI1_DATA10 */
+ [27] = RCAR_GP_PIN(3, 14), /* VI1_DATA9 */
+ [28] = RCAR_GP_PIN(3, 13), /* VI1_DATA8 */
+ [29] = RCAR_GP_PIN(3, 12), /* VI1_VSYNC# */
+ [30] = RCAR_GP_PIN(3, 11), /* VI1_HSYNC# */
+ [31] = RCAR_GP_PIN(3, 10), /* VI1_FIELD */
+ } },
+ { PINMUX_BIAS_REG("PUPR4", 0xe6060110, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(5, 27), /* SSI_SDATA9_A */
+ [ 1] = RCAR_GP_PIN(5, 26), /* SSI_WS9_A */
+ [ 2] = RCAR_GP_PIN(5, 25), /* SSI_SCK9_A */
+ [ 3] = RCAR_GP_PIN(5, 24), /* SSI_SDATA2_A */
+ [ 4] = RCAR_GP_PIN(5, 23), /* SSI_WS2_A */
+ [ 5] = RCAR_GP_PIN(5, 22), /* SSI_SCK2_A */
+ [ 6] = RCAR_GP_PIN(5, 21), /* SSI_SDATA1_A */
+ [ 7] = RCAR_GP_PIN(5, 20), /* SSI_WS1_A */
+ [ 8] = RCAR_GP_PIN(5, 19), /* SSI_SDATA8_A */
+ [ 9] = RCAR_GP_PIN(5, 18), /* SSI_SCK1_A */
+ [10] = RCAR_GP_PIN(5, 17), /* SSI_SDATA4_A */
+ [11] = RCAR_GP_PIN(5, 16), /* SSI_WS4_A */
+ [12] = RCAR_GP_PIN(5, 15), /* SSI_SCK4_A */
+ [13] = RCAR_GP_PIN(5, 14), /* SSI_SDATA3 */
+ [14] = RCAR_GP_PIN(5, 13), /* SSI_WS34 */
+ [15] = RCAR_GP_PIN(5, 12), /* SSI_SCK34 */
+ [16] = RCAR_GP_PIN(5, 11), /* SSI_SDATA0_A */
+ [17] = RCAR_GP_PIN(5, 10), /* SSI_WS0129_A */
+ [18] = RCAR_GP_PIN(5, 9), /* SSI_SCK0129_A */
+ [19] = RCAR_GP_PIN(5, 8), /* SSI_SDATA7_A */
+ [20] = RCAR_GP_PIN(5, 7), /* SSI_WS78_A */
+ [21] = RCAR_GP_PIN(5, 6), /* SSI_SCK78_A */
+ [22] = RCAR_GP_PIN(5, 5), /* SSI_SDATA6_A */
+ [23] = RCAR_GP_PIN(5, 4), /* SSI_WS6_A */
+ [24] = RCAR_GP_PIN(5, 3), /* SSI_SCK6_A */
+ [25] = RCAR_GP_PIN(5, 2), /* SSI_SDATA5_A */
+ [26] = RCAR_GP_PIN(5, 1), /* SSI_WS5_A */
+ [27] = RCAR_GP_PIN(5, 0), /* SSI_SCK5_A */
+ [28] = RCAR_GP_PIN(4, 25), /* SDA2_A */
+ [29] = RCAR_GP_PIN(4, 24), /* SCL2_A */
+ [30] = RCAR_GP_PIN(4, 23), /* TX3_A */
+ [31] = RCAR_GP_PIN(4, 22), /* RX3_A */
+ } },
+ { PINMUX_BIAS_REG("PUPR5", 0xe6060114, "N/A", 0) {
+ [ 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] = RCAR_GP_PIN(5, 31), /* AUDIO_CLKOUT_A */
+ [29] = RCAR_GP_PIN(5, 30), /* AUDIO_CLKC_A */
+ [30] = RCAR_GP_PIN(5, 29), /* AUDIO_CLKB_A */
+ [31] = RCAR_GP_PIN(5, 28), /* AUDIO_CLKA_A */
+ } },
+ { /* sentinel */ }
+};
+
static const struct sh_pfc_soc_operations r8a77470_pinmux_ops = {
.pin_to_pocctrl = r8a77470_pin_to_pocctrl,
+ .get_bias = rcar_pinmux_get_bias,
+ .set_bias = rcar_pinmux_set_bias,
};
#ifdef CONFIG_PINCTRL_PFC_R8A77470
@@ -3440,6 +3705,7 @@ const struct sh_pfc_soc_info r8a77470_pinmux_info = {
.nr_functions = ARRAY_SIZE(pinmux_functions),
.cfg_regs = pinmux_config_regs,
+ .bias_regs = pinmux_bias_regs,
.pinmux_data = pinmux_data,
.pinmux_data_size = ARRAY_SIZE(pinmux_data),
diff --git a/drivers/pinctrl/renesas/pfc-r8a7778.c b/drivers/pinctrl/renesas/pfc-r8a7778.c
index 6185af9c4990..d641e408f1bd 100644
--- a/drivers/pinctrl/renesas/pfc-r8a7778.c
+++ b/drivers/pinctrl/renesas/pfc-r8a7778.c
@@ -18,9 +18,6 @@
#include "sh_pfc.h"
-#define PORT_GP_PUP_1(bank, pin, fn, sfx) \
- PORT_GP_CFG_1(bank, pin, fn, sfx, SH_PFC_PIN_CFG_PULL_UP)
-
#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), \
diff --git a/drivers/pinctrl/renesas/pfc-r8a7790.c b/drivers/pinctrl/renesas/pfc-r8a7790.c
index e9a64e0e2734..08c0a23edf68 100644
--- a/drivers/pinctrl/renesas/pfc-r8a7790.c
+++ b/drivers/pinctrl/renesas/pfc-r8a7790.c
@@ -21,18 +21,23 @@
* which case they support both 3.3V and 1.8V signalling.
*/
#define CPU_ALL_GP(fn, sfx) \
- PORT_GP_32(0, fn, sfx), \
- PORT_GP_30(1, fn, sfx), \
- PORT_GP_30(2, fn, sfx), \
- PORT_GP_CFG_32(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_32(4, fn, sfx), \
- PORT_GP_32(5, fn, sfx)
+ PORT_GP_CFG_32(0, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_30(1, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_30(2, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_32(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_32(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_32(5, fn, sfx, SH_PFC_PIN_CFG_PULL_UP)
#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP_CFG(ASEBRK_N_ACK, "ASEBRK#/ACK", fn, SH_PFC_PIN_CFG_PULL_DOWN), \
PIN_NOGP(IIC0_SDA, "AF15", fn), \
PIN_NOGP(IIC0_SCL, "AG15", fn), \
PIN_NOGP(IIC3_SDA, "AH15", fn), \
- PIN_NOGP(IIC3_SCL, "AJ15", fn)
+ PIN_NOGP(IIC3_SCL, "AJ15", fn), \
+ PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TMS, "TMS", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP)
enum {
PINMUX_RESERVED = 0,
@@ -5992,6 +5997,284 @@ static int r8a7790_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *poc
return 31 - (pin & 0x1f);
}
+static const struct pinmux_bias_reg pinmux_bias_regs[] = {
+ { PINMUX_BIAS_REG("PUPR0", 0xe6060100, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(0, 16), /* A0 */
+ [ 1] = RCAR_GP_PIN(0, 17), /* A1 */
+ [ 2] = RCAR_GP_PIN(0, 18), /* A2 */
+ [ 3] = RCAR_GP_PIN(0, 19), /* A3 */
+ [ 4] = RCAR_GP_PIN(0, 20), /* A4 */
+ [ 5] = RCAR_GP_PIN(0, 21), /* A5 */
+ [ 6] = RCAR_GP_PIN(0, 22), /* A6 */
+ [ 7] = RCAR_GP_PIN(0, 23), /* A7 */
+ [ 8] = RCAR_GP_PIN(0, 24), /* A8 */
+ [ 9] = RCAR_GP_PIN(0, 25), /* A9 */
+ [10] = RCAR_GP_PIN(0, 26), /* A10 */
+ [11] = RCAR_GP_PIN(0, 27), /* A11 */
+ [12] = RCAR_GP_PIN(0, 28), /* A12 */
+ [13] = RCAR_GP_PIN(0, 29), /* A13 */
+ [14] = RCAR_GP_PIN(0, 30), /* A14 */
+ [15] = RCAR_GP_PIN(0, 31), /* A15 */
+ [16] = RCAR_GP_PIN(1, 0), /* A16 */
+ [17] = RCAR_GP_PIN(1, 1), /* A17 */
+ [18] = RCAR_GP_PIN(1, 2), /* A18 */
+ [19] = RCAR_GP_PIN(1, 3), /* A19 */
+ [20] = RCAR_GP_PIN(1, 4), /* A20 */
+ [21] = RCAR_GP_PIN(1, 5), /* A21 */
+ [22] = RCAR_GP_PIN(1, 6), /* A22 */
+ [23] = RCAR_GP_PIN(1, 7), /* A23 */
+ [24] = RCAR_GP_PIN(1, 8), /* A24 */
+ [25] = RCAR_GP_PIN(1, 9), /* A25 */
+ [26] = RCAR_GP_PIN(1, 12), /* EX_CS0# */
+ [27] = RCAR_GP_PIN(1, 13), /* EX_CS1# */
+ [28] = RCAR_GP_PIN(1, 14), /* EX_CS2# */
+ [29] = RCAR_GP_PIN(1, 15), /* EX_CS3# */
+ [30] = RCAR_GP_PIN(1, 16), /* EX_CS4# */
+ [31] = RCAR_GP_PIN(1, 17), /* EX_CS5# */
+ } },
+ { PINMUX_BIAS_REG("PUPR1", 0xe6060104, "N/A", 0) {
+ /* PUPR1 pull-up pins */
+ [ 0] = RCAR_GP_PIN(1, 18), /* BS# */
+ [ 1] = RCAR_GP_PIN(1, 19), /* RD# */
+ [ 2] = RCAR_GP_PIN(1, 20), /* RD/WR# */
+ [ 3] = RCAR_GP_PIN(1, 21), /* WE0# */
+ [ 4] = RCAR_GP_PIN(1, 22), /* WE1# */
+ [ 5] = RCAR_GP_PIN(1, 23), /* EX_WAIT0 */
+ [ 6] = RCAR_GP_PIN(5, 24), /* AVS1 */
+ [ 7] = RCAR_GP_PIN(5, 25), /* AVS2 */
+ [ 8] = RCAR_GP_PIN(1, 10), /* CS0# */
+ [ 9] = RCAR_GP_PIN(1, 11), /* CS1#/A26 */
+ [10] = PIN_TRST_N, /* TRST# */
+ [11] = PIN_TCK, /* TCK */
+ [12] = PIN_TMS, /* TMS */
+ [13] = PIN_TDI, /* TDI */
+ [14] = SH_PFC_PIN_NONE,
+ [15] = SH_PFC_PIN_NONE,
+ [16] = RCAR_GP_PIN(0, 0), /* D0 */
+ [17] = RCAR_GP_PIN(0, 1), /* D1 */
+ [18] = RCAR_GP_PIN(0, 2), /* D2 */
+ [19] = RCAR_GP_PIN(0, 3), /* D3 */
+ [20] = RCAR_GP_PIN(0, 4), /* D4 */
+ [21] = RCAR_GP_PIN(0, 5), /* D5 */
+ [22] = RCAR_GP_PIN(0, 6), /* D6 */
+ [23] = RCAR_GP_PIN(0, 7), /* D7 */
+ [24] = RCAR_GP_PIN(0, 8), /* D8 */
+ [25] = RCAR_GP_PIN(0, 9), /* D9 */
+ [26] = RCAR_GP_PIN(0, 10), /* D10 */
+ [27] = RCAR_GP_PIN(0, 11), /* D11 */
+ [28] = RCAR_GP_PIN(0, 12), /* D12 */
+ [29] = RCAR_GP_PIN(0, 13), /* D13 */
+ [30] = RCAR_GP_PIN(0, 14), /* D14 */
+ [31] = RCAR_GP_PIN(0, 15), /* D15 */
+ } },
+ { PINMUX_BIAS_REG("N/A", 0, "PUPR1", 0xe6060104) {
+ /* PUPR1 pull-down pins */
+ [ 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] = PIN_ASEBRK_N_ACK, /* ASEBRK#/ACK */
+ [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", 0xe6060108, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(5, 28), /* DU_DOTCLKIN2 */
+ [ 1] = SH_PFC_PIN_NONE,
+ [ 2] = SH_PFC_PIN_NONE,
+ [ 3] = SH_PFC_PIN_NONE,
+ [ 4] = SH_PFC_PIN_NONE,
+ [ 5] = RCAR_GP_PIN(2, 0), /* VI0_CLK */
+ [ 6] = RCAR_GP_PIN(2, 1), /* VI0_DATA0_VI0_B0 */
+ [ 7] = RCAR_GP_PIN(2, 2), /* VI0_DATA1_VI0_B1 */
+ [ 8] = RCAR_GP_PIN(2, 3), /* VI0_DATA2_VI0_B2 */
+ [ 9] = RCAR_GP_PIN(2, 4), /* VI0_DATA3_VI0_B3 */
+ [10] = RCAR_GP_PIN(2, 5), /* VI0_DATA4_VI0_B4 */
+ [11] = RCAR_GP_PIN(2, 6), /* VI0_DATA5_VI0_B5 */
+ [12] = RCAR_GP_PIN(2, 7), /* VI0_DATA6_VI0_B6 */
+ [13] = RCAR_GP_PIN(2, 8), /* VI0_DATA7_VI0_B7 */
+ [14] = RCAR_GP_PIN(2, 9), /* VI1_CLK */
+ [15] = RCAR_GP_PIN(2, 10), /* VI1_DATA0_VI1_B0 */
+ [16] = RCAR_GP_PIN(2, 11), /* VI1_DATA1_VI1_B1 */
+ [17] = RCAR_GP_PIN(2, 12), /* VI1_DATA2_VI1_B2 */
+ [18] = RCAR_GP_PIN(2, 13), /* VI1_DATA3_VI1_B3 */
+ [19] = RCAR_GP_PIN(2, 14), /* VI1_DATA4_VI1_B4 */
+ [20] = RCAR_GP_PIN(2, 15), /* VI1_DATA5_VI1_B5 */
+ [21] = RCAR_GP_PIN(2, 16), /* VI1_DATA6_VI1_B6 */
+ [22] = RCAR_GP_PIN(2, 17), /* VI1_DATA7_VI1_B7 */
+ [23] = RCAR_GP_PIN(5, 27), /* DU_DOTCLKIN1 */
+ [24] = SH_PFC_PIN_NONE,
+ [25] = SH_PFC_PIN_NONE,
+ [26] = SH_PFC_PIN_NONE,
+ [27] = RCAR_GP_PIN(4, 0), /* MLB_CLK */
+ [28] = RCAR_GP_PIN(4, 1), /* MLB_SIG */
+ [29] = RCAR_GP_PIN(4, 2), /* MLB_DAT */
+ [30] = SH_PFC_PIN_NONE,
+ [31] = RCAR_GP_PIN(5, 26), /* DU_DOTCLKIN0 */
+ } },
+ { PINMUX_BIAS_REG("PUPR3", 0xe606010c, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(3, 0), /* SD0_CLK */
+ [ 1] = RCAR_GP_PIN(3, 1), /* SD0_CMD */
+ [ 2] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */
+ [ 3] = RCAR_GP_PIN(3, 3), /* SD0_DAT1 */
+ [ 4] = RCAR_GP_PIN(3, 4), /* SD0_DAT2 */
+ [ 5] = RCAR_GP_PIN(3, 5), /* SD0_DAT3 */
+ [ 6] = RCAR_GP_PIN(3, 6), /* SD0_CD */
+ [ 7] = RCAR_GP_PIN(3, 7), /* SD0_WP */
+ [ 8] = RCAR_GP_PIN(3, 8), /* SD1_CLK */
+ [ 9] = RCAR_GP_PIN(3, 9), /* SD1_CMD */
+ [10] = RCAR_GP_PIN(3, 10), /* SD1_DAT0 */
+ [11] = RCAR_GP_PIN(3, 11), /* SD1_DAT1 */
+ [12] = RCAR_GP_PIN(3, 12), /* SD1_DAT2 */
+ [13] = RCAR_GP_PIN(3, 13), /* SD1_DAT3 */
+ [14] = RCAR_GP_PIN(3, 14), /* SD1_CD */
+ [15] = RCAR_GP_PIN(3, 15), /* SD1_WP */
+ [16] = RCAR_GP_PIN(3, 16), /* SD2_CLK */
+ [17] = RCAR_GP_PIN(3, 17), /* SD2_CMD */
+ [18] = RCAR_GP_PIN(3, 18), /* SD2_DAT0 */
+ [19] = RCAR_GP_PIN(3, 19), /* SD2_DAT1 */
+ [20] = RCAR_GP_PIN(3, 20), /* SD2_DAT2 */
+ [21] = RCAR_GP_PIN(3, 21), /* SD2_DAT3 */
+ [22] = RCAR_GP_PIN(3, 22), /* SD2_CD */
+ [23] = RCAR_GP_PIN(3, 23), /* SD2_WP */
+ [24] = RCAR_GP_PIN(3, 24), /* SD3_CLK */
+ [25] = RCAR_GP_PIN(3, 25), /* SD3_CMD */
+ [26] = RCAR_GP_PIN(3, 26), /* SD3_DAT0 */
+ [27] = RCAR_GP_PIN(3, 27), /* SD3_DAT1 */
+ [28] = RCAR_GP_PIN(3, 28), /* SD3_DAT2 */
+ [29] = RCAR_GP_PIN(3, 29), /* SD3_DAT3 */
+ [30] = RCAR_GP_PIN(3, 30), /* SD3_CD */
+ [31] = RCAR_GP_PIN(3, 31), /* SD3_WP */
+ } },
+ { PINMUX_BIAS_REG("PUPR4", 0xe6060110, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(4, 3), /* SSI_SCK0129 */
+ [ 1] = RCAR_GP_PIN(4, 4), /* SSI_WS0129 */
+ [ 2] = RCAR_GP_PIN(4, 5), /* SSI_SDATA0 */
+ [ 3] = RCAR_GP_PIN(4, 6), /* SSI_SDATA1 */
+ [ 4] = RCAR_GP_PIN(4, 7), /* SSI_SDATA2 */
+ [ 5] = RCAR_GP_PIN(4, 8), /* SSI_SCK34 */
+ [ 6] = RCAR_GP_PIN(4, 9), /* SSI_WS34 */
+ [ 7] = RCAR_GP_PIN(4, 10), /* SSI_SDATA3 */
+ [ 8] = RCAR_GP_PIN(4, 11), /* SSI_SCK4 */
+ [ 9] = RCAR_GP_PIN(4, 12), /* SSI_WS4 */
+ [10] = RCAR_GP_PIN(4, 13), /* SSI_SDATA4 */
+ [11] = RCAR_GP_PIN(4, 14), /* SSI_SCK5 */
+ [12] = RCAR_GP_PIN(4, 15), /* SSI_WS5 */
+ [13] = RCAR_GP_PIN(4, 16), /* SSI_SDATA5 */
+ [14] = RCAR_GP_PIN(4, 17), /* SSI_SCK6 */
+ [15] = RCAR_GP_PIN(4, 18), /* SSI_WS6 */
+ [16] = RCAR_GP_PIN(4, 19), /* SSI_SDATA6 */
+ [17] = RCAR_GP_PIN(4, 20), /* SSI_SCK78 */
+ [18] = RCAR_GP_PIN(4, 21), /* SSI_WS78 */
+ [19] = RCAR_GP_PIN(4, 22), /* SSI_SDATA7 */
+ [20] = RCAR_GP_PIN(4, 23), /* SSI_SDATA8 */
+ [21] = RCAR_GP_PIN(4, 24), /* SSI_SDATA9 */
+ [22] = RCAR_GP_PIN(4, 25), /* AUDIO_CLKA */
+ [23] = RCAR_GP_PIN(4, 26), /* AUDIO_CLKB */
+ [24] = RCAR_GP_PIN(1, 24), /* DREQ0 */
+ [25] = RCAR_GP_PIN(1, 25), /* DACK0 */
+ [26] = RCAR_GP_PIN(1, 26), /* DREQ1 */
+ [27] = RCAR_GP_PIN(1, 27), /* DACK1 */
+ [28] = RCAR_GP_PIN(1, 28), /* DREQ2 */
+ [29] = RCAR_GP_PIN(1, 29), /* DACK2 */
+ [30] = RCAR_GP_PIN(2, 18), /* ETH_CRS_DV */
+ [31] = RCAR_GP_PIN(2, 19), /* ETH_RX_ER */
+ } },
+ { PINMUX_BIAS_REG("PUPR5", 0xe6060114, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(4, 27), /* SCIFA0_SCK */
+ [ 1] = RCAR_GP_PIN(4, 28), /* SCIFA0_RXD */
+ [ 2] = RCAR_GP_PIN(4, 29), /* SCIFA0_TXD */
+ [ 3] = RCAR_GP_PIN(4, 30), /* SCIFA0_CTS# */
+ [ 4] = RCAR_GP_PIN(4, 31), /* SCIFA0_RTS# */
+ [ 5] = RCAR_GP_PIN(5, 0), /* SCIFA1_RXD */
+ [ 6] = RCAR_GP_PIN(5, 1), /* SCIFA1_TXD */
+ [ 7] = RCAR_GP_PIN(5, 2), /* SCIFA1_CTS# */
+ [ 8] = RCAR_GP_PIN(5, 3), /* SCIFA1_RTS# */
+ [ 9] = RCAR_GP_PIN(5, 4), /* SCIFA2_SCK */
+ [10] = RCAR_GP_PIN(5, 5), /* SCIFA2_RXD */
+ [11] = RCAR_GP_PIN(5, 6), /* SCIFA2_TXD */
+ [12] = RCAR_GP_PIN(5, 7), /* HSCK0 */
+ [13] = RCAR_GP_PIN(5, 8), /* HRX0 */
+ [14] = RCAR_GP_PIN(5, 9), /* HTX0 */
+ [15] = RCAR_GP_PIN(5, 10), /* HCTS0# */
+ [16] = RCAR_GP_PIN(5, 11), /* HRTS0# */
+ [17] = RCAR_GP_PIN(5, 12), /* MSIOF0_SCK */
+ [18] = RCAR_GP_PIN(5, 13), /* MSIOF0_SYNC */
+ [19] = RCAR_GP_PIN(5, 14), /* MSIOF0_SS1 */
+ [20] = RCAR_GP_PIN(5, 15), /* MSIOF0_TXD */
+ [21] = RCAR_GP_PIN(5, 16), /* MSIOF0_SS2 */
+ [22] = RCAR_GP_PIN(5, 17), /* MSIOF0_RXD */
+ [23] = RCAR_GP_PIN(5, 18), /* USB0_PWEN */
+ [24] = RCAR_GP_PIN(5, 19), /* USB0_OVC_VBUS */
+ [25] = RCAR_GP_PIN(5, 20), /* USB1_PWEN */
+ [26] = RCAR_GP_PIN(5, 21), /* USB1_OVC */
+ [27] = RCAR_GP_PIN(5, 22), /* USB2_PWEN */
+ [28] = RCAR_GP_PIN(5, 23), /* USB2_OVC */
+ [29] = RCAR_GP_PIN(2, 20), /* ETH_RXD0 */
+ [30] = RCAR_GP_PIN(2, 21), /* ETH_RXD1 */
+ [31] = RCAR_GP_PIN(2, 22), /* ETH_LINK */
+ } },
+ { PINMUX_BIAS_REG("PUPR6", 0xe6060118, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(2, 23), /* ETH_REF_CLK */
+ [ 1] = RCAR_GP_PIN(2, 24), /* ETH_MDIO */
+ [ 2] = RCAR_GP_PIN(2, 25), /* ETH_TXD1 */
+ [ 3] = RCAR_GP_PIN(2, 26), /* ETH_TX_EN */
+ [ 4] = RCAR_GP_PIN(2, 27), /* ETH_MAGIC */
+ [ 5] = RCAR_GP_PIN(2, 28), /* ETH_TXD0 */
+ [ 6] = RCAR_GP_PIN(2, 29), /* ETH_MDC */
+ [ 7] = RCAR_GP_PIN(5, 29), /* PWM0 */
+ [ 8] = RCAR_GP_PIN(5, 30), /* PWM1 */
+ [ 9] = RCAR_GP_PIN(5, 31), /* PWM2 */
+ [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 */ }
+};
+
static const struct soc_device_attribute r8a7790_tdsel[] = {
{ .soc_id = "r8a7790", .revision = "ES1.0" },
{ /* sentinel */ }
@@ -6009,6 +6292,8 @@ static int r8a7790_pinmux_soc_init(struct sh_pfc *pfc)
static const struct sh_pfc_soc_operations r8a7790_pinmux_ops = {
.init = r8a7790_pinmux_soc_init,
.pin_to_pocctrl = r8a7790_pin_to_pocctrl,
+ .get_bias = rcar_pinmux_get_bias,
+ .set_bias = rcar_pinmux_set_bias,
};
#ifdef CONFIG_PINCTRL_PFC_R8A7742
@@ -6027,6 +6312,7 @@ const struct sh_pfc_soc_info r8a7742_pinmux_info = {
.nr_functions = ARRAY_SIZE(pinmux_functions.common),
.cfg_regs = pinmux_config_regs,
+ .bias_regs = pinmux_bias_regs,
.pinmux_data = pinmux_data,
.pinmux_data_size = ARRAY_SIZE(pinmux_data),
@@ -6051,6 +6337,7 @@ const struct sh_pfc_soc_info r8a7790_pinmux_info = {
ARRAY_SIZE(pinmux_functions.automotive),
.cfg_regs = pinmux_config_regs,
+ .bias_regs = pinmux_bias_regs,
.pinmux_data = pinmux_data,
.pinmux_data_size = ARRAY_SIZE(pinmux_data),
diff --git a/drivers/pinctrl/renesas/pfc-r8a7792.c b/drivers/pinctrl/renesas/pfc-r8a7792.c
index f54a7c81005d..3ab56dc768de 100644
--- a/drivers/pinctrl/renesas/pfc-r8a7792.c
+++ b/drivers/pinctrl/renesas/pfc-r8a7792.c
@@ -11,18 +11,29 @@
#include "sh_pfc.h"
#define CPU_ALL_GP(fn, sfx) \
- PORT_GP_29(0, fn, sfx), \
- PORT_GP_23(1, fn, sfx), \
- PORT_GP_32(2, fn, sfx), \
- PORT_GP_28(3, fn, sfx), \
- PORT_GP_17(4, fn, sfx), \
- PORT_GP_17(5, fn, sfx), \
- PORT_GP_17(6, fn, sfx), \
- PORT_GP_17(7, fn, sfx), \
- PORT_GP_17(8, fn, sfx), \
- PORT_GP_17(9, fn, sfx), \
- PORT_GP_32(10, fn, sfx), \
- PORT_GP_30(11, fn, sfx)
+ PORT_GP_CFG_29(0, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_23(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_28(3, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_17(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_17(5, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_17(6, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_17(7, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_17(8, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_17(9, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_32(10, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_30(11, fn, sfx, SH_PFC_PIN_CFG_PULL_UP)
+
+#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP_CFG(DU0_DOTCLKIN, "DU0_DOTCLKIN", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(DU0_DOTCLKOUT, "DU0_DOTCLKOUT", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(DU1_DOTCLKIN, "DU1_DOTCLKIN", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(DU1_DOTCLKOUT, "DU1_DOTCLKOUT", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(EDBGREQ, "EDBGREQ", fn, SH_PFC_PIN_CFG_PULL_DOWN), \
+ PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TMS, "TMS", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP)
enum {
PINMUX_RESERVED = 0,
@@ -723,8 +734,17 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_GPSR(IP7_20, AUDIO_CLKB),
};
+/*
+ * 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(),
+ PINMUX_NOGP_ALL(),
};
/* - AVB -------------------------------------------------------------------- */
@@ -2779,8 +2799,496 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
{ },
};
+static const struct pinmux_bias_reg pinmux_bias_regs[] = {
+ { PINMUX_BIAS_REG("PUPR0", 0xe6060100, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(0, 0), /* DU0_DR0_DATA0 */
+ [ 1] = RCAR_GP_PIN(0, 1), /* DU0_DR1_DATA1 */
+ [ 2] = RCAR_GP_PIN(0, 2), /* DU0_DR2_Y4_DATA2 */
+ [ 3] = RCAR_GP_PIN(0, 3), /* DU0_DR3_Y5_DATA3 */
+ [ 4] = RCAR_GP_PIN(0, 4), /* DU0_DR4_Y6_DATA4 */
+ [ 5] = RCAR_GP_PIN(0, 5), /* DU0_DR5_Y7_DATA5 */
+ [ 6] = RCAR_GP_PIN(0, 6), /* DU0_DR6_Y8_DATA6 */
+ [ 7] = RCAR_GP_PIN(0, 7), /* DU0_DR7_Y9_DATA7 */
+ [ 8] = RCAR_GP_PIN(0, 8), /* DU0_DG0_DATA8 */
+ [ 9] = RCAR_GP_PIN(0, 9), /* DU0_DG1_DATA9 */
+ [10] = RCAR_GP_PIN(0, 10), /* DU0_DG2_C6_DATA10 */
+ [11] = RCAR_GP_PIN(0, 11), /* DU0_DG3_C7_DATA11 */
+ [12] = RCAR_GP_PIN(0, 12), /* DU0_DG4_Y0_DATA12 */
+ [13] = RCAR_GP_PIN(0, 13), /* DU0_DG5_Y1_DATA13 */
+ [14] = RCAR_GP_PIN(0, 14), /* DU0_DG6_Y2_DATA14 */
+ [15] = RCAR_GP_PIN(0, 15), /* DU0_DG7_Y3_DATA15 */
+ [16] = RCAR_GP_PIN(0, 16), /* DU0_DB0 */
+ [17] = RCAR_GP_PIN(0, 17), /* DU0_DB1 */
+ [18] = RCAR_GP_PIN(0, 18), /* DU0_DB2_C0 */
+ [19] = RCAR_GP_PIN(0, 19), /* DU0_DB3_C1 */
+ [20] = RCAR_GP_PIN(0, 20), /* DU0_DB4_C2 */
+ [21] = RCAR_GP_PIN(0, 21), /* DU0_DB5_C3 */
+ [22] = RCAR_GP_PIN(0, 22), /* DU0_DB6_C4 */
+ [23] = RCAR_GP_PIN(0, 23), /* DU0_DB7_C5 */
+ [24] = RCAR_GP_PIN(0, 24), /* DU0_EXHSYNC/DU0_HSYNC */
+ [25] = RCAR_GP_PIN(0, 25), /* DU0_EXVSYNC/DU0_VSYNC */
+ [26] = RCAR_GP_PIN(0, 26), /* DU0_EXODDF/DU0_ODDF_DISP_CDE */
+ [27] = RCAR_GP_PIN(0, 27), /* DU0_DISP */
+ [28] = RCAR_GP_PIN(0, 28), /* DU0_CDE */
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("PUPR1", 0xe6060104, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(1, 0), /* DU1_DR2_Y4_DATA0 */
+ [ 1] = RCAR_GP_PIN(1, 1), /* DU1_DR3_Y5_DATA1 */
+ [ 2] = RCAR_GP_PIN(1, 2), /* DU1_DR4_Y6_DATA2 */
+ [ 3] = RCAR_GP_PIN(1, 3), /* DU1_DR5_Y7_DATA3 */
+ [ 4] = RCAR_GP_PIN(1, 4), /* DU1_DR6_DATA4 */
+ [ 5] = RCAR_GP_PIN(1, 5), /* DU1_DR7_DATA5 */
+ [ 6] = RCAR_GP_PIN(1, 6), /* DU1_DG2_C6_DATA6 */
+ [ 7] = RCAR_GP_PIN(1, 7), /* DU1_DG3_C7_DATA7 */
+ [ 8] = RCAR_GP_PIN(1, 8), /* DU1_DG4_Y0_DATA8 */
+ [ 9] = RCAR_GP_PIN(1, 9), /* DU1_DG5_Y1_DATA9 */
+ [10] = RCAR_GP_PIN(1, 10), /* DU1_DG6_Y2_DATA10 */
+ [11] = RCAR_GP_PIN(1, 11), /* DU1_DG7_Y3_DATA11 */
+ [12] = RCAR_GP_PIN(1, 12), /* DU1_DB2_C0_DATA12 */
+ [13] = RCAR_GP_PIN(1, 13), /* DU1_DB3_C1_DATA13 */
+ [14] = RCAR_GP_PIN(1, 14), /* DU1_DB4_C2_DATA14 */
+ [15] = RCAR_GP_PIN(1, 15), /* DU1_DB5_C3_DATA15 */
+ [16] = RCAR_GP_PIN(1, 16), /* DU1_DB6_C4 */
+ [17] = RCAR_GP_PIN(1, 17), /* DU1_DB7_C5 */
+ [18] = RCAR_GP_PIN(1, 18), /* DU1_EXHSYNC/DU1_HSYNC */
+ [19] = RCAR_GP_PIN(1, 19), /* DU1_EXVSYNC/DU1_VSYNC */
+ [20] = RCAR_GP_PIN(1, 20), /* DU1_EXODDF/DU1_ODDF_DISP_CDE */
+ [21] = RCAR_GP_PIN(1, 21), /* DU1_DISP */
+ [22] = RCAR_GP_PIN(1, 22), /* DU1_CDE */
+ [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", 0xe6060108, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(2, 0), /* D0 */
+ [ 1] = RCAR_GP_PIN(2, 1), /* D1 */
+ [ 2] = RCAR_GP_PIN(2, 2), /* D2 */
+ [ 3] = RCAR_GP_PIN(2, 3), /* D3 */
+ [ 4] = RCAR_GP_PIN(2, 4), /* D4 */
+ [ 5] = RCAR_GP_PIN(2, 5), /* D5 */
+ [ 6] = RCAR_GP_PIN(2, 6), /* D6 */
+ [ 7] = RCAR_GP_PIN(2, 7), /* D7 */
+ [ 8] = RCAR_GP_PIN(2, 8), /* D8 */
+ [ 9] = RCAR_GP_PIN(2, 9), /* D9 */
+ [10] = RCAR_GP_PIN(2, 10), /* D10 */
+ [11] = RCAR_GP_PIN(2, 11), /* D11 */
+ [12] = RCAR_GP_PIN(2, 12), /* D12 */
+ [13] = RCAR_GP_PIN(2, 13), /* D13 */
+ [14] = RCAR_GP_PIN(2, 14), /* D14 */
+ [15] = RCAR_GP_PIN(2, 15), /* D15 */
+ [16] = RCAR_GP_PIN(2, 16), /* A0 */
+ [17] = RCAR_GP_PIN(2, 17), /* A1 */
+ [18] = RCAR_GP_PIN(2, 18), /* A2 */
+ [19] = RCAR_GP_PIN(2, 19), /* A3 */
+ [20] = RCAR_GP_PIN(2, 20), /* A4 */
+ [21] = RCAR_GP_PIN(2, 21), /* A5 */
+ [22] = RCAR_GP_PIN(2, 22), /* A6 */
+ [23] = RCAR_GP_PIN(2, 23), /* A7 */
+ [24] = RCAR_GP_PIN(2, 24), /* A8 */
+ [25] = RCAR_GP_PIN(2, 25), /* A9 */
+ [26] = RCAR_GP_PIN(2, 26), /* A10 */
+ [27] = RCAR_GP_PIN(2, 27), /* A11 */
+ [28] = RCAR_GP_PIN(2, 28), /* A12 */
+ [29] = RCAR_GP_PIN(2, 29), /* A13 */
+ [30] = RCAR_GP_PIN(2, 30), /* A14 */
+ [31] = RCAR_GP_PIN(2, 31), /* A15 */
+ } },
+ { PINMUX_BIAS_REG("PUPR3", 0xe606010c, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(3, 0), /* A16 */
+ [ 1] = RCAR_GP_PIN(3, 1), /* A17 */
+ [ 2] = RCAR_GP_PIN(3, 2), /* A18 */
+ [ 3] = RCAR_GP_PIN(3, 3), /* A19 */
+ [ 4] = RCAR_GP_PIN(3, 4), /* A20 */
+ [ 5] = RCAR_GP_PIN(3, 5), /* A21 */
+ [ 6] = RCAR_GP_PIN(3, 6), /* CS1#/A26 */
+ [ 7] = RCAR_GP_PIN(3, 7), /* EX_CS0# */
+ [ 8] = RCAR_GP_PIN(3, 8), /* EX_CS1# */
+ [ 9] = RCAR_GP_PIN(3, 9), /* EX_CS2# */
+ [10] = RCAR_GP_PIN(3, 10), /* EX_CS3# */
+ [11] = RCAR_GP_PIN(3, 11), /* EX_CS4# */
+ [12] = RCAR_GP_PIN(3, 12), /* EX_CS5# */
+ [13] = RCAR_GP_PIN(3, 13), /* BS# */
+ [14] = RCAR_GP_PIN(3, 14), /* RD# */
+ [15] = RCAR_GP_PIN(3, 15), /* RD/WR# */
+ [16] = RCAR_GP_PIN(3, 16), /* WE0# */
+ [17] = RCAR_GP_PIN(3, 17), /* WE1# */
+ [18] = RCAR_GP_PIN(3, 18), /* EX_WAIT0 */
+ [19] = RCAR_GP_PIN(3, 19), /* IRQ0 */
+ [20] = RCAR_GP_PIN(3, 20), /* IRQ1 */
+ [21] = RCAR_GP_PIN(3, 21), /* IRQ2 */
+ [22] = RCAR_GP_PIN(3, 22), /* IRQ3 */
+ [23] = RCAR_GP_PIN(3, 23), /* A22 */
+ [24] = RCAR_GP_PIN(3, 24), /* A23 */
+ [25] = RCAR_GP_PIN(3, 25), /* A24 */
+ [26] = RCAR_GP_PIN(3, 26), /* A25 */
+ [27] = RCAR_GP_PIN(3, 27), /* CS0# */
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("PUPR4", 0xe6060110, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(4, 0), /* VI0_CLK */
+ [ 1] = RCAR_GP_PIN(4, 1), /* VI0_CLKENB */
+ [ 2] = RCAR_GP_PIN(4, 2), /* VI0_HSYNC# */
+ [ 3] = RCAR_GP_PIN(4, 3), /* VI0_VSYNC# */
+ [ 4] = RCAR_GP_PIN(4, 4), /* VI0_D0_B0_C0 */
+ [ 5] = RCAR_GP_PIN(4, 5), /* VI0_D1_B1_C1 */
+ [ 6] = RCAR_GP_PIN(4, 6), /* VI0_D2_B2_C2 */
+ [ 7] = RCAR_GP_PIN(4, 7), /* VI0_D3_B3_C3 */
+ [ 8] = RCAR_GP_PIN(4, 8), /* VI0_D4_B4_C4 */
+ [ 9] = RCAR_GP_PIN(4, 9), /* VI0_D5_B5_C5 */
+ [10] = RCAR_GP_PIN(4, 10), /* VI0_D6_B6_C6 */
+ [11] = RCAR_GP_PIN(4, 11), /* VI0_D7_B7_C7 */
+ [12] = RCAR_GP_PIN(4, 12), /* VI0_D8_G0_Y0 */
+ [13] = RCAR_GP_PIN(4, 13), /* VI0_D9_G1_Y1 */
+ [14] = RCAR_GP_PIN(4, 14), /* VI0_D10_G2_Y2 */
+ [15] = RCAR_GP_PIN(4, 15), /* VI0_D11_G3_Y3 */
+ [16] = RCAR_GP_PIN(4, 16), /* VI0_FIELD */
+ [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("PUPR5", 0xe6060114, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(5, 0), /* VI1_CLK */
+ [ 1] = RCAR_GP_PIN(5, 1), /* VI1_CLKENB */
+ [ 2] = RCAR_GP_PIN(5, 2), /* VI1_HSYNC# */
+ [ 3] = RCAR_GP_PIN(5, 3), /* VI1_VSYNC# */
+ [ 4] = RCAR_GP_PIN(5, 4), /* VI1_D0_B0_C0 */
+ [ 5] = RCAR_GP_PIN(5, 5), /* VI1_D1_B1_C1 */
+ [ 6] = RCAR_GP_PIN(5, 6), /* VI1_D2_B2_C2 */
+ [ 7] = RCAR_GP_PIN(5, 7), /* VI1_D3_B3_C3 */
+ [ 8] = RCAR_GP_PIN(5, 8), /* VI1_D4_B4_C4 */
+ [ 9] = RCAR_GP_PIN(5, 9), /* VI1_D5_B5_C5 */
+ [10] = RCAR_GP_PIN(5, 10), /* VI1_D6_B6_C6 */
+ [11] = RCAR_GP_PIN(5, 11), /* VI1_D7_B7_C7 */
+ [12] = RCAR_GP_PIN(5, 12), /* VI1_D8_G0_Y0 */
+ [13] = RCAR_GP_PIN(5, 13), /* VI1_D9_G1_Y1 */
+ [14] = RCAR_GP_PIN(5, 14), /* VI1_D10_G2_Y2 */
+ [15] = RCAR_GP_PIN(5, 15), /* VI1_D11_G3_Y3 */
+ [16] = RCAR_GP_PIN(5, 16), /* VI1_FIELD */
+ [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("PUPR6", 0xe6060118, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(6, 0), /* VI2_CLK */
+ [ 1] = RCAR_GP_PIN(6, 1), /* VI2_CLKENB */
+ [ 2] = RCAR_GP_PIN(6, 2), /* VI2_HSYNC# */
+ [ 3] = RCAR_GP_PIN(6, 3), /* VI2_VSYNC# */
+ [ 4] = RCAR_GP_PIN(6, 4), /* VI2_D0_C0 */
+ [ 5] = RCAR_GP_PIN(6, 5), /* VI2_D1_C1 */
+ [ 6] = RCAR_GP_PIN(6, 6), /* VI2_D2_C2 */
+ [ 7] = RCAR_GP_PIN(6, 7), /* VI2_D3_C3 */
+ [ 8] = RCAR_GP_PIN(6, 8), /* VI2_D4_C4 */
+ [ 9] = RCAR_GP_PIN(6, 9), /* VI2_D5_C5 */
+ [10] = RCAR_GP_PIN(6, 10), /* VI2_D6_C6 */
+ [11] = RCAR_GP_PIN(6, 11), /* VI2_D7_C7 */
+ [12] = RCAR_GP_PIN(6, 12), /* VI2_D8_Y0 */
+ [13] = RCAR_GP_PIN(6, 13), /* VI2_D9_Y1 */
+ [14] = RCAR_GP_PIN(6, 14), /* VI2_D10_Y2 */
+ [15] = RCAR_GP_PIN(6, 15), /* VI2_D11_Y3 */
+ [16] = RCAR_GP_PIN(6, 16), /* VI2_FIELD */
+ [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("PUPR7", 0xe606011c, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(7, 0), /* VI3_CLK */
+ [ 1] = RCAR_GP_PIN(7, 1), /* VI3_CLKENB */
+ [ 2] = RCAR_GP_PIN(7, 2), /* VI3_HSYNC# */
+ [ 3] = RCAR_GP_PIN(7, 3), /* VI3_VSYNC# */
+ [ 4] = RCAR_GP_PIN(7, 4), /* VI3_D0_C0 */
+ [ 5] = RCAR_GP_PIN(7, 5), /* VI3_D1_C1 */
+ [ 6] = RCAR_GP_PIN(7, 6), /* VI3_D2_C2 */
+ [ 7] = RCAR_GP_PIN(7, 7), /* VI3_D3_C3 */
+ [ 8] = RCAR_GP_PIN(7, 8), /* VI3_D4_C4 */
+ [ 9] = RCAR_GP_PIN(7, 9), /* VI3_D5_C5 */
+ [10] = RCAR_GP_PIN(7, 10), /* VI3_D6_C6 */
+ [11] = RCAR_GP_PIN(7, 11), /* VI3_D7_C7 */
+ [12] = RCAR_GP_PIN(7, 12), /* VI3_D8_Y0 */
+ [13] = RCAR_GP_PIN(7, 13), /* VI3_D9_Y1 */
+ [14] = RCAR_GP_PIN(7, 14), /* VI3_D10_Y2 */
+ [15] = RCAR_GP_PIN(7, 15), /* VI3_D11_Y3 */
+ [16] = RCAR_GP_PIN(7, 16), /* VI3_FIELD */
+ [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("PUPR8", 0xe6060120, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(8, 0), /* VI4_CLK */
+ [ 1] = RCAR_GP_PIN(8, 1), /* VI4_CLKENB */
+ [ 2] = RCAR_GP_PIN(8, 2), /* VI4_HSYNC# */
+ [ 3] = RCAR_GP_PIN(8, 3), /* VI4_VSYNC# */
+ [ 4] = RCAR_GP_PIN(8, 4), /* VI4_D0_C0 */
+ [ 5] = RCAR_GP_PIN(8, 5), /* VI4_D1_C1 */
+ [ 6] = RCAR_GP_PIN(8, 6), /* VI4_D2_C2 */
+ [ 7] = RCAR_GP_PIN(8, 7), /* VI4_D3_C3 */
+ [ 8] = RCAR_GP_PIN(8, 8), /* VI4_D4_C4 */
+ [ 9] = RCAR_GP_PIN(8, 9), /* VI4_D5_C5 */
+ [10] = RCAR_GP_PIN(8, 10), /* VI4_D6_C6 */
+ [11] = RCAR_GP_PIN(8, 11), /* VI4_D7_C7 */
+ [12] = RCAR_GP_PIN(8, 12), /* VI4_D8_Y0 */
+ [13] = RCAR_GP_PIN(8, 13), /* VI4_D9_Y1 */
+ [14] = RCAR_GP_PIN(8, 14), /* VI4_D10_Y2 */
+ [15] = RCAR_GP_PIN(8, 15), /* VI4_D11_Y3 */
+ [16] = RCAR_GP_PIN(8, 16), /* VI4_FIELD */
+ [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("PUPR9", 0xe6060124, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(9, 0), /* VI5_CLK */
+ [ 1] = RCAR_GP_PIN(9, 1), /* VI5_CLKENB */
+ [ 2] = RCAR_GP_PIN(9, 2), /* VI5_HSYNC# */
+ [ 3] = RCAR_GP_PIN(9, 3), /* VI5_VSYNC# */
+ [ 4] = RCAR_GP_PIN(9, 4), /* VI5_D0_C0 */
+ [ 5] = RCAR_GP_PIN(9, 5), /* VI5_D1_C1 */
+ [ 6] = RCAR_GP_PIN(9, 6), /* VI5_D2_C2 */
+ [ 7] = RCAR_GP_PIN(9, 7), /* VI5_D3_C3 */
+ [ 8] = RCAR_GP_PIN(9, 8), /* VI5_D4_C4 */
+ [ 9] = RCAR_GP_PIN(9, 9), /* VI5_D5_C5 */
+ [10] = RCAR_GP_PIN(9, 10), /* VI5_D6_C6 */
+ [11] = RCAR_GP_PIN(9, 11), /* VI5_D7_C7 */
+ [12] = RCAR_GP_PIN(9, 12), /* VI5_D8_Y0 */
+ [13] = RCAR_GP_PIN(9, 13), /* VI5_D9_Y1 */
+ [14] = RCAR_GP_PIN(9, 14), /* VI5_D10_Y2 */
+ [15] = RCAR_GP_PIN(9, 15), /* VI5_D11_Y3 */
+ [16] = RCAR_GP_PIN(9, 16), /* VI5_FIELD */
+ [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("PUPR10", 0xe6060128, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(10, 0), /* HSCK0 */
+ [ 1] = RCAR_GP_PIN(10, 1), /* HCTS0# */
+ [ 2] = RCAR_GP_PIN(10, 2), /* HRTS0# */
+ [ 3] = RCAR_GP_PIN(10, 3), /* HTX0 */
+ [ 4] = RCAR_GP_PIN(10, 4), /* HRX0 */
+ [ 5] = RCAR_GP_PIN(10, 5), /* HSCK1 */
+ [ 6] = RCAR_GP_PIN(10, 6), /* HRTS1# */
+ [ 7] = RCAR_GP_PIN(10, 7), /* HCTS1# */
+ [ 8] = RCAR_GP_PIN(10, 8), /* HTX1 */
+ [ 9] = RCAR_GP_PIN(10, 9), /* HRX1 */
+ [10] = RCAR_GP_PIN(10, 10), /* SCK0 */
+ [11] = RCAR_GP_PIN(10, 11), /* CTS0# */
+ [12] = RCAR_GP_PIN(10, 12), /* RTS0# */
+ [13] = RCAR_GP_PIN(10, 13), /* TX0 */
+ [14] = RCAR_GP_PIN(10, 14), /* RX0 */
+ [15] = RCAR_GP_PIN(10, 15), /* SCK1 */
+ [16] = RCAR_GP_PIN(10, 16), /* CTS1# */
+ [17] = RCAR_GP_PIN(10, 17), /* RTS1# */
+ [18] = RCAR_GP_PIN(10, 18), /* TX1 */
+ [19] = RCAR_GP_PIN(10, 19), /* RX1 */
+ [20] = RCAR_GP_PIN(10, 20), /* SCK2 */
+ [21] = RCAR_GP_PIN(10, 21), /* TX2 */
+ [22] = RCAR_GP_PIN(10, 22), /* RX2 */
+ [23] = RCAR_GP_PIN(10, 23), /* SCK3 */
+ [24] = RCAR_GP_PIN(10, 24), /* TX3 */
+ [25] = RCAR_GP_PIN(10, 25), /* RX3 */
+ [26] = RCAR_GP_PIN(10, 26), /* SCIF_CLK */
+ [27] = RCAR_GP_PIN(10, 27), /* CAN0_TX */
+ [28] = RCAR_GP_PIN(10, 28), /* CAN0_RX */
+ [29] = RCAR_GP_PIN(10, 29), /* CAN_CLK */
+ [30] = RCAR_GP_PIN(10, 30), /* CAN1_TX */
+ [31] = RCAR_GP_PIN(10, 31), /* CAN1_RX */
+ } },
+ { PINMUX_BIAS_REG("PUPR11", 0xe606012c, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(11, 0), /* PWM0 */
+ [ 1] = RCAR_GP_PIN(11, 1), /* PWM1 */
+ [ 2] = RCAR_GP_PIN(11, 2), /* PWM2 */
+ [ 3] = RCAR_GP_PIN(11, 3), /* PWM3 */
+ [ 4] = RCAR_GP_PIN(11, 4), /* PWM4 */
+ [ 5] = RCAR_GP_PIN(11, 5), /* SD0_CLK */
+ [ 6] = RCAR_GP_PIN(11, 6), /* SD0_CMD */
+ [ 7] = RCAR_GP_PIN(11, 7), /* SD0_DAT0 */
+ [ 8] = RCAR_GP_PIN(11, 8), /* SD0_DAT1 */
+ [ 9] = RCAR_GP_PIN(11, 9), /* SD0_DAT2 */
+ [10] = RCAR_GP_PIN(11, 10), /* SD0_DAT3 */
+ [11] = RCAR_GP_PIN(11, 11), /* SD0_CD */
+ [12] = RCAR_GP_PIN(11, 12), /* SD0_WP */
+ [13] = RCAR_GP_PIN(11, 13), /* SSI_SCK3 */
+ [14] = RCAR_GP_PIN(11, 14), /* SSI_WS3 */
+ [15] = RCAR_GP_PIN(11, 15), /* SSI_SDATA3 */
+ [16] = RCAR_GP_PIN(11, 16), /* SSI_SCK4 */
+ [17] = RCAR_GP_PIN(11, 17), /* SSI_WS4 */
+ [18] = RCAR_GP_PIN(11, 18), /* SSI_SDATA4 */
+ [19] = RCAR_GP_PIN(11, 19), /* AUDIO_CLKOUT */
+ [20] = RCAR_GP_PIN(11, 20), /* AUDIO_CLKA */
+ [21] = RCAR_GP_PIN(11, 21), /* AUDIO_CLKB */
+ [22] = RCAR_GP_PIN(11, 22), /* ADICLK */
+ [23] = RCAR_GP_PIN(11, 23), /* ADICS_SAMP */
+ [24] = RCAR_GP_PIN(11, 24), /* ADIDATA */
+ [25] = RCAR_GP_PIN(11, 25), /* ADICHS0 */
+ [26] = RCAR_GP_PIN(11, 26), /* ADICHS1 */
+ [27] = RCAR_GP_PIN(11, 27), /* ADICHS2 */
+ [28] = RCAR_GP_PIN(11, 28), /* AVS1 */
+ [29] = RCAR_GP_PIN(11, 29), /* AVS2 */
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("PUPR12", 0xe6060130, "N/A", 0) {
+ /* PUPR12 pull-up pins */
+ [ 0] = PIN_DU0_DOTCLKIN, /* DU0_DOTCLKIN */
+ [ 1] = PIN_DU0_DOTCLKOUT, /* DU0_DOTCLKOUT */
+ [ 2] = PIN_DU1_DOTCLKIN, /* DU1_DOTCLKIN */
+ [ 3] = PIN_DU1_DOTCLKOUT, /* DU1_DOTCLKOUT */
+ [ 4] = PIN_TRST_N, /* TRST# */
+ [ 5] = PIN_TCK, /* TCK */
+ [ 6] = PIN_TMS, /* TMS */
+ [ 7] = PIN_TDI, /* TDI */
+ [ 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,
+ } },
+ { PINMUX_BIAS_REG("N/A", 0, "PUPR12", 0xe6060130) {
+ /* PUPR12 pull-down pins */
+ [ 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] = PIN_EDBGREQ, /* EDBGREQ */
+ [ 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 */ }
+};
+
+static const struct sh_pfc_soc_operations r8a7792_pinmux_ops = {
+ .get_bias = rcar_pinmux_get_bias,
+ .set_bias = rcar_pinmux_set_bias,
+};
+
const struct sh_pfc_soc_info r8a7792_pinmux_info = {
.name = "r8a77920_pfc",
+ .ops = &r8a7792_pinmux_ops,
.unlock_reg = 0xe6060000, /* PMMR */
.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
@@ -2793,6 +3301,7 @@ const struct sh_pfc_soc_info r8a7792_pinmux_info = {
.nr_functions = ARRAY_SIZE(pinmux_functions),
.cfg_regs = pinmux_config_regs,
+ .bias_regs = pinmux_bias_regs,
.pinmux_data = pinmux_data,
.pinmux_data_size = ARRAY_SIZE(pinmux_data),
diff --git a/drivers/pinctrl/renesas/pfc-r8a7794.c b/drivers/pinctrl/renesas/pfc-r8a7794.c
index 34481b6c4328..fbb5b3b68f34 100644
--- a/drivers/pinctrl/renesas/pfc-r8a7794.c
+++ b/drivers/pinctrl/renesas/pfc-r8a7794.c
@@ -15,15 +15,66 @@
#include "sh_pfc.h"
#define CPU_ALL_GP(fn, sfx) \
- PORT_GP_32(0, fn, sfx), \
- PORT_GP_26(1, fn, sfx), \
- PORT_GP_32(2, fn, sfx), \
- PORT_GP_32(3, fn, sfx), \
- PORT_GP_32(4, fn, sfx), \
- PORT_GP_28(5, fn, sfx), \
- PORT_GP_CFG_24(6, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_1(6, 24, fn, sfx), \
- PORT_GP_1(6, 25, fn, sfx)
+ PORT_GP_CFG_32(0, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_26(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_CFG_32(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_7(5, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_1(5, 7, fn, sfx), \
+ PORT_GP_1(5, 8, fn, sfx), \
+ PORT_GP_1(5, 9, fn, sfx), \
+ PORT_GP_CFG_1(5, 10, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(5, 11, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(5, 12, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(5, 13, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(5, 14, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(5, 15, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(5, 16, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(5, 17, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(5, 18, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(5, 19, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(5, 20, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(5, 21, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(5, 22, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(5, 23, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_1(5, 24, fn, sfx), \
+ PORT_GP_1(5, 25, fn, sfx), \
+ PORT_GP_1(5, 26, fn, sfx), \
+ PORT_GP_1(5, 27, fn, sfx), \
+ PORT_GP_CFG_1(6, 0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
+ PORT_GP_CFG_1(6, 1, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 4, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 5, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 6, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 7, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 8, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
+ PORT_GP_CFG_1(6, 9, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 10, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 11, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 12, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 13, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 14, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 15, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 16, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
+ PORT_GP_CFG_1(6, 17, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 18, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 19, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 20, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 21, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 22, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 23, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 24, fn, sfx, SH_PFC_PIN_CFG_PULL_UP), \
+ PORT_GP_CFG_1(6, 25, fn, sfx, SH_PFC_PIN_CFG_PULL_UP)
+
+#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP_CFG(ASEBRK_N_ACK, "ASEBRK#/ACK", fn, SH_PFC_PIN_CFG_PULL_DOWN), \
+ PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TMS, "TMS", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP)
enum {
PINMUX_RESERVED = 0,
@@ -1436,8 +1487,17 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP13_26_24, FMIN_E, SEL_DARC_4),
};
+/*
+ * 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(),
+ PINMUX_NOGP_ALL(),
};
/* - Audio Clock ------------------------------------------------------------ */
@@ -5580,6 +5640,284 @@ static int r8a7794_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *poc
return -EINVAL;
}
+static const struct pinmux_bias_reg pinmux_bias_regs[] = {
+ { PINMUX_BIAS_REG("PUPR0", 0xe6060100, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(0, 0), /* D0 */
+ [ 1] = RCAR_GP_PIN(0, 1), /* D1 */
+ [ 2] = RCAR_GP_PIN(0, 2), /* D2 */
+ [ 3] = RCAR_GP_PIN(0, 3), /* D3 */
+ [ 4] = RCAR_GP_PIN(0, 4), /* D4 */
+ [ 5] = RCAR_GP_PIN(0, 5), /* D5 */
+ [ 6] = RCAR_GP_PIN(0, 6), /* D6 */
+ [ 7] = RCAR_GP_PIN(0, 7), /* D7 */
+ [ 8] = RCAR_GP_PIN(0, 8), /* D8 */
+ [ 9] = RCAR_GP_PIN(0, 9), /* D9 */
+ [10] = RCAR_GP_PIN(0, 10), /* D10 */
+ [11] = RCAR_GP_PIN(0, 11), /* D11 */
+ [12] = RCAR_GP_PIN(0, 12), /* D12 */
+ [13] = RCAR_GP_PIN(0, 13), /* D13 */
+ [14] = RCAR_GP_PIN(0, 14), /* D14 */
+ [15] = RCAR_GP_PIN(0, 15), /* D15 */
+ [16] = RCAR_GP_PIN(0, 16), /* A0 */
+ [17] = RCAR_GP_PIN(0, 17), /* A1 */
+ [18] = RCAR_GP_PIN(0, 18), /* A2 */
+ [19] = RCAR_GP_PIN(0, 19), /* A3 */
+ [20] = RCAR_GP_PIN(0, 20), /* A4 */
+ [21] = RCAR_GP_PIN(0, 21), /* A5 */
+ [22] = RCAR_GP_PIN(0, 22), /* A6 */
+ [23] = RCAR_GP_PIN(0, 23), /* A7 */
+ [24] = RCAR_GP_PIN(0, 24), /* A8 */
+ [25] = RCAR_GP_PIN(0, 25), /* A9 */
+ [26] = RCAR_GP_PIN(0, 26), /* A10 */
+ [27] = RCAR_GP_PIN(0, 27), /* A11 */
+ [28] = RCAR_GP_PIN(0, 28), /* A12 */
+ [29] = RCAR_GP_PIN(0, 29), /* A13 */
+ [30] = RCAR_GP_PIN(0, 30), /* A14 */
+ [31] = RCAR_GP_PIN(0, 31), /* A15 */
+ } },
+ { PINMUX_BIAS_REG("PUPR1", 0xe6060104, "N/A", 0) {
+ /* PUPR1 pull-up pins */
+ [ 0] = RCAR_GP_PIN(1, 0), /* A16 */
+ [ 1] = RCAR_GP_PIN(1, 1), /* A17 */
+ [ 2] = RCAR_GP_PIN(1, 2), /* A18 */
+ [ 3] = RCAR_GP_PIN(1, 3), /* A19 */
+ [ 4] = RCAR_GP_PIN(1, 4), /* A20 */
+ [ 5] = RCAR_GP_PIN(1, 5), /* A21 */
+ [ 6] = RCAR_GP_PIN(1, 6), /* A22 */
+ [ 7] = RCAR_GP_PIN(1, 7), /* A23 */
+ [ 8] = RCAR_GP_PIN(1, 8), /* A24 */
+ [ 9] = RCAR_GP_PIN(1, 9), /* A25 */
+ [10] = RCAR_GP_PIN(1, 10), /* CS0# */
+ [11] = RCAR_GP_PIN(1, 12), /* EX_CS0# */
+ [12] = RCAR_GP_PIN(1, 14), /* EX_CS2# */
+ [13] = RCAR_GP_PIN(1, 16), /* EX_CS4# */
+ [14] = RCAR_GP_PIN(1, 18), /* BS# */
+ [15] = RCAR_GP_PIN(1, 19), /* RD# */
+ [16] = RCAR_GP_PIN(1, 20), /* RD/WR# */
+ [17] = RCAR_GP_PIN(1, 21), /* WE0# */
+ [18] = RCAR_GP_PIN(1, 22), /* WE1# */
+ [19] = RCAR_GP_PIN(1, 23), /* EX_WAIT0 */
+ [20] = RCAR_GP_PIN(1, 24), /* DREQ0# */
+ [21] = RCAR_GP_PIN(1, 25), /* DACK0 */
+ [22] = PIN_TRST_N, /* TRST# */
+ [23] = PIN_TCK, /* TCK */
+ [24] = PIN_TMS, /* TMS */
+ [25] = PIN_TDI, /* TDI */
+ [26] = RCAR_GP_PIN(1, 11), /* CS1#/A26 */
+ [27] = RCAR_GP_PIN(1, 13), /* EX_CS1# */
+ [28] = RCAR_GP_PIN(1, 15), /* EX_CS3# */
+ [29] = RCAR_GP_PIN(1, 17), /* EX_CS5# */
+ [30] = SH_PFC_PIN_NONE,
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("N/A", 0, "PUPR1", 0xe6060104) {
+ /* PUPR1 pull-down pins */
+ [ 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] = PIN_ASEBRK_N_ACK, /* ASEBRK#/ACK */
+ [31] = SH_PFC_PIN_NONE,
+ } },
+ { PINMUX_BIAS_REG("PUPR2", 0xe6060108, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(2, 0), /* DU0_DR0 */
+ [ 1] = RCAR_GP_PIN(2, 1), /* DU0_DR1 */
+ [ 2] = RCAR_GP_PIN(2, 2), /* DU0_DR2 */
+ [ 3] = RCAR_GP_PIN(2, 3), /* DU0_DR3 */
+ [ 4] = RCAR_GP_PIN(2, 4), /* DU0_DR4 */
+ [ 5] = RCAR_GP_PIN(2, 5), /* DU0_DR5 */
+ [ 6] = RCAR_GP_PIN(2, 6), /* DU0_DR6 */
+ [ 7] = RCAR_GP_PIN(2, 7), /* DU0_DR7 */
+ [ 8] = RCAR_GP_PIN(2, 8), /* DU0_DG0 */
+ [ 9] = RCAR_GP_PIN(2, 9), /* DU0_DG1 */
+ [10] = RCAR_GP_PIN(2, 10), /* DU0_DG2 */
+ [11] = RCAR_GP_PIN(2, 11), /* DU0_DG3 */
+ [12] = RCAR_GP_PIN(2, 12), /* DU0_DG4 */
+ [13] = RCAR_GP_PIN(2, 13), /* DU0_DG5 */
+ [14] = RCAR_GP_PIN(2, 14), /* DU0_DG6 */
+ [15] = RCAR_GP_PIN(2, 15), /* DU0_DG7 */
+ [16] = RCAR_GP_PIN(2, 16), /* DU0_DB0 */
+ [17] = RCAR_GP_PIN(2, 17), /* DU0_DB1 */
+ [18] = RCAR_GP_PIN(2, 18), /* DU0_DB2 */
+ [19] = RCAR_GP_PIN(2, 19), /* DU0_DB3 */
+ [20] = RCAR_GP_PIN(2, 20), /* DU0_DB4 */
+ [21] = RCAR_GP_PIN(2, 21), /* DU0_DB5 */
+ [22] = RCAR_GP_PIN(2, 22), /* DU0_DB6 */
+ [23] = RCAR_GP_PIN(2, 23), /* DU0_DB7 */
+ [24] = RCAR_GP_PIN(2, 24), /* DU0_DOTCLKIN */
+ [25] = RCAR_GP_PIN(2, 25), /* DU0_DOTCLKOUT0 */
+ [26] = RCAR_GP_PIN(2, 26), /* DU0_DOTCLKOUT1 */
+ [27] = RCAR_GP_PIN(2, 27), /* DU0_EXHSYNC/DU0_HSYNC */
+ [28] = RCAR_GP_PIN(2, 28), /* DU0_EXVSYNC/DU0_VSYNC */
+ [29] = RCAR_GP_PIN(2, 29), /* DU0_EXODDF/DU0_ODDF_DISP_CDE */
+ [30] = RCAR_GP_PIN(2, 30), /* DU0_DISP */
+ [31] = RCAR_GP_PIN(2, 31), /* DU0_CDE */
+ } },
+ { PINMUX_BIAS_REG("PUPR3", 0xe606010c, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(3, 2), /* VI0_DATA1_VI0_B1 */
+ [ 1] = RCAR_GP_PIN(3, 3), /* VI0_DATA2_VI0_B2 */
+ [ 2] = RCAR_GP_PIN(3, 4), /* VI0_DATA3_VI0_B3 */
+ [ 3] = RCAR_GP_PIN(3, 5), /* VI0_DATA4_VI0_B4 */
+ [ 4] = RCAR_GP_PIN(3, 6), /* VI0_DATA5_VI0_B5 */
+ [ 5] = RCAR_GP_PIN(3, 7), /* VI0_DATA6_VI0_B6 */
+ [ 6] = RCAR_GP_PIN(3, 8), /* VI0_DATA7_VI0_B7 */
+ [ 7] = RCAR_GP_PIN(3, 9), /* VI0_CLKENB */
+ [ 8] = RCAR_GP_PIN(3, 10), /* VI0_FIELD */
+ [ 9] = RCAR_GP_PIN(3, 11), /* VI0_HSYNC# */
+ [10] = RCAR_GP_PIN(3, 12), /* VI0_VSYNC# */
+ [11] = RCAR_GP_PIN(3, 13), /* ETH_MDIO */
+ [12] = RCAR_GP_PIN(3, 14), /* ETH_CRS_DV */
+ [13] = RCAR_GP_PIN(3, 15), /* ETH_RX_ER */
+ [14] = RCAR_GP_PIN(3, 16), /* ETH_RXD0 */
+ [15] = RCAR_GP_PIN(3, 17), /* ETH_RXD1 */
+ [16] = RCAR_GP_PIN(3, 18), /* ETH_LINK */
+ [17] = RCAR_GP_PIN(3, 19), /* ETH_REF_CLK */
+ [18] = RCAR_GP_PIN(3, 20), /* ETH_TXD1 */
+ [19] = RCAR_GP_PIN(3, 21), /* ETH_TX_EN */
+ [20] = RCAR_GP_PIN(3, 22), /* ETH_MAGIC */
+ [21] = RCAR_GP_PIN(3, 23), /* ETH_TXD0 */
+ [22] = RCAR_GP_PIN(3, 24), /* ETH_MDC */
+ [23] = RCAR_GP_PIN(3, 25), /* HSCIF0_HRX */
+ [24] = RCAR_GP_PIN(3, 26), /* HSCIF0_HTX */
+ [25] = RCAR_GP_PIN(3, 27), /* HSCIF0_HCTS# */
+ [26] = RCAR_GP_PIN(3, 28), /* HSCIF0_HRTS# */
+ [27] = RCAR_GP_PIN(3, 29), /* HSCIF0_HSCK */
+ [28] = RCAR_GP_PIN(3, 30), /* I2C0_SCL */
+ [29] = RCAR_GP_PIN(3, 31), /* I2C0_SDA */
+ [30] = RCAR_GP_PIN(4, 0), /* I2C1_SCL */
+ [31] = RCAR_GP_PIN(4, 1), /* I2C1_SDA */
+ } },
+ { PINMUX_BIAS_REG("PUPR4", 0xe6060110, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(4, 2), /* MSIOF0_RXD */
+ [ 1] = RCAR_GP_PIN(4, 3), /* MSIOF0_TXD */
+ [ 2] = RCAR_GP_PIN(4, 4), /* MSIOF0_SCK */
+ [ 3] = RCAR_GP_PIN(4, 5), /* MSIOF0_SYNC */
+ [ 4] = RCAR_GP_PIN(4, 6), /* MSIOF0_SS1 */
+ [ 5] = RCAR_GP_PIN(4, 7), /* MSIOF0_SS2 */
+ [ 6] = RCAR_GP_PIN(4, 8), /* HSCIF1_HRX */
+ [ 7] = RCAR_GP_PIN(4, 9), /* HSCIF1_HTX */
+ [ 8] = RCAR_GP_PIN(4, 10), /* HSCIF1_HSCK */
+ [ 9] = RCAR_GP_PIN(4, 11), /* HSCIF1_HCTS# */
+ [10] = RCAR_GP_PIN(4, 12), /* HSCIF1_HRTS# */
+ [11] = RCAR_GP_PIN(4, 13), /* SCIF1_SCK */
+ [12] = RCAR_GP_PIN(4, 14), /* SCIF1_RXD */
+ [13] = RCAR_GP_PIN(4, 15), /* SCIF1_TXD */
+ [14] = RCAR_GP_PIN(4, 16), /* SCIF2_RXD */
+ [15] = RCAR_GP_PIN(4, 17), /* SCIF2_TXD */
+ [16] = RCAR_GP_PIN(4, 18), /* SCIF2_SCK */
+ [17] = RCAR_GP_PIN(4, 19), /* SCIF3_SCK */
+ [18] = RCAR_GP_PIN(4, 20), /* SCIF3_RXD */
+ [19] = RCAR_GP_PIN(4, 21), /* SCIF3_TXD */
+ [20] = RCAR_GP_PIN(4, 22), /* I2C2_SCL */
+ [21] = RCAR_GP_PIN(4, 23), /* I2C2_SDA */
+ [22] = RCAR_GP_PIN(4, 24), /* SSI_SCK5 */
+ [23] = RCAR_GP_PIN(4, 25), /* SSI_WS5 */
+ [24] = RCAR_GP_PIN(4, 26), /* SSI_SDATA5 */
+ [25] = RCAR_GP_PIN(4, 27), /* SSI_SCK6 */
+ [26] = RCAR_GP_PIN(4, 28), /* SSI_WS6 */
+ [27] = RCAR_GP_PIN(4, 29), /* SSI_SDATA6 */
+ [28] = RCAR_GP_PIN(4, 30), /* SSI_SCK78 */
+ [29] = RCAR_GP_PIN(4, 31), /* SSI_WS78 */
+ [30] = RCAR_GP_PIN(5, 0), /* SSI_SDATA7 */
+ [31] = RCAR_GP_PIN(5, 1), /* SSI_SCK0129 */
+ } },
+ { PINMUX_BIAS_REG("PUPR5", 0xe6060114, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(5, 2), /* SSI_WS0129 */
+ [ 1] = RCAR_GP_PIN(5, 3), /* SSI_SDATA0 */
+ [ 2] = RCAR_GP_PIN(5, 4), /* SSI_SCK34 */
+ [ 3] = RCAR_GP_PIN(5, 5), /* SSI_WS34 */
+ [ 4] = RCAR_GP_PIN(5, 6), /* SSI_SDATA3 */
+ [ 5] = SH_PFC_PIN_NONE,
+ [ 6] = SH_PFC_PIN_NONE,
+ [ 7] = SH_PFC_PIN_NONE,
+ [ 8] = RCAR_GP_PIN(5, 10), /* SSI_SDATA8 */
+ [ 9] = RCAR_GP_PIN(5, 11), /* SSI_SCK1 */
+ [10] = RCAR_GP_PIN(5, 12), /* SSI_WS1 */
+ [11] = RCAR_GP_PIN(5, 13), /* SSI_SDATA1 */
+ [12] = RCAR_GP_PIN(5, 14), /* SSI_SCK2 */
+ [13] = RCAR_GP_PIN(5, 15), /* SSI_WS2 */
+ [14] = RCAR_GP_PIN(5, 16), /* SSI_SDATA2 */
+ [15] = RCAR_GP_PIN(5, 17), /* SSI_SCK9 */
+ [16] = RCAR_GP_PIN(5, 18), /* SSI_WS9 */
+ [17] = RCAR_GP_PIN(5, 19), /* SSI_SDATA9 */
+ [18] = RCAR_GP_PIN(5, 20), /* AUDIO_CLKA */
+ [19] = RCAR_GP_PIN(5, 21), /* AUDIO_CLKB */
+ [20] = RCAR_GP_PIN(5, 22), /* AUDIO_CLKC */
+ [21] = RCAR_GP_PIN(5, 23), /* AUDIO_CLKOUT */
+ [22] = RCAR_GP_PIN(3, 0), /* VI0_CLK */
+ [23] = RCAR_GP_PIN(3, 1), /* VI0_DATA0_VI0_B0 */
+ [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("PUPR6", 0xe6060118, "N/A", 0) {
+ [ 0] = RCAR_GP_PIN(6, 1), /* SD0_CMD */
+ [ 1] = RCAR_GP_PIN(6, 2), /* SD0_DATA0 */
+ [ 2] = RCAR_GP_PIN(6, 3), /* SD0_DATA1 */
+ [ 3] = RCAR_GP_PIN(6, 4), /* SD0_DATA2 */
+ [ 4] = RCAR_GP_PIN(6, 5), /* SD0_DATA3 */
+ [ 5] = RCAR_GP_PIN(6, 6), /* SD0_CD */
+ [ 6] = RCAR_GP_PIN(6, 7), /* SD0_WP */
+ [ 7] = RCAR_GP_PIN(6, 9), /* SD1_CMD */
+ [ 8] = RCAR_GP_PIN(6, 10), /* SD1_DATA0 */
+ [ 9] = RCAR_GP_PIN(6, 11), /* SD1_DATA1 */
+ [10] = RCAR_GP_PIN(6, 12), /* SD1_DATA2 */
+ [11] = RCAR_GP_PIN(6, 13), /* SD1_DATA3 */
+ [12] = RCAR_GP_PIN(6, 14), /* SD1_CD */
+ [13] = RCAR_GP_PIN(6, 15), /* SD1_WP */
+ [14] = SH_PFC_PIN_NONE,
+ [15] = RCAR_GP_PIN(6, 17), /* MMC_CMD */
+ [16] = RCAR_GP_PIN(6, 18), /* MMC_D0 */
+ [17] = RCAR_GP_PIN(6, 19), /* MMC_D1 */
+ [18] = RCAR_GP_PIN(6, 20), /* MMC_D2 */
+ [19] = RCAR_GP_PIN(6, 21), /* MMC_D3 */
+ [20] = RCAR_GP_PIN(6, 22), /* MMC_D4 */
+ [21] = RCAR_GP_PIN(6, 23), /* MMC_D5 */
+ [22] = RCAR_GP_PIN(6, 24), /* MMC_D6 */
+ [23] = RCAR_GP_PIN(6, 25), /* MMC_D7 */
+ [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 */ }
+};
+
static const struct soc_device_attribute r8a7794_tdsel[] = {
{ .soc_id = "r8a7794", .revision = "ES1.0" },
{ /* sentinel */ }
@@ -5597,6 +5935,8 @@ static int r8a7794_pinmux_soc_init(struct sh_pfc *pfc)
static const struct sh_pfc_soc_operations r8a7794_pinmux_ops = {
.init = r8a7794_pinmux_soc_init,
.pin_to_pocctrl = r8a7794_pin_to_pocctrl,
+ .get_bias = rcar_pinmux_get_bias,
+ .set_bias = rcar_pinmux_set_bias,
};
#ifdef CONFIG_PINCTRL_PFC_R8A7745
@@ -5615,6 +5955,7 @@ const struct sh_pfc_soc_info r8a7745_pinmux_info = {
.nr_functions = ARRAY_SIZE(pinmux_functions),
.cfg_regs = pinmux_config_regs,
+ .bias_regs = pinmux_bias_regs,
.pinmux_data = pinmux_data,
.pinmux_data_size = ARRAY_SIZE(pinmux_data),
@@ -5637,6 +5978,7 @@ const struct sh_pfc_soc_info r8a7794_pinmux_info = {
.nr_functions = ARRAY_SIZE(pinmux_functions),
.cfg_regs = pinmux_config_regs,
+ .bias_regs = pinmux_bias_regs,
.pinmux_data = pinmux_data,
.pinmux_data_size = ARRAY_SIZE(pinmux_data),
diff --git a/drivers/pinctrl/renesas/pfc-r8a77951.c b/drivers/pinctrl/renesas/pfc-r8a77951.c
index be4eee070842..84c0ea5d59c1 100644
--- a/drivers/pinctrl/renesas/pfc-r8a77951.c
+++ b/drivers/pinctrl/renesas/pfc-r8a77951.c
@@ -241,7 +241,7 @@
#define GPSR6_3 F_(SSI_SDATA1_A, IP15_3_0)
#define GPSR6_2 F_(SSI_SDATA0, IP14_31_28)
#define GPSR6_1 F_(SSI_WS01239, IP14_27_24)
-#define GPSR6_0 F_(SSI_SCK01239, IP14_23_20)
+#define GPSR6_0 F_(SSI_SCK01239, IP14_23_20)
/* GPSR7 */
#define GPSR7_3 FM(GP7_03)
@@ -668,7 +668,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_PHYS_MSEL(IP0_23_20, AVB_AVTP_CAPTURE_A, I2C_SEL_5_0, SEL_ETHERAVB_0),
PINMUX_IPSR_PHYS_MSEL(IP0_23_20, MSIOF2_TXD_C, I2C_SEL_5_0, SEL_MSIOF2_2),
PINMUX_IPSR_PHYS_MSEL(IP0_23_20, RTS4_N_A, I2C_SEL_5_0, SEL_SCIF4_0),
- PINMUX_IPSR_PHYS(IP0_23_20, SDA5, I2C_SEL_5_1),
+ PINMUX_IPSR_PHYS(IP0_23_20, SDA5, I2C_SEL_5_1),
PINMUX_IPSR_GPSR(IP0_27_24, IRQ0),
PINMUX_IPSR_GPSR(IP0_27_24, QPOLB),
diff --git a/drivers/pinctrl/renesas/pfc-r8a7796.c b/drivers/pinctrl/renesas/pfc-r8a7796.c
index 44e9d2eea484..a4d74df3d201 100644
--- a/drivers/pinctrl/renesas/pfc-r8a7796.c
+++ b/drivers/pinctrl/renesas/pfc-r8a7796.c
@@ -67,6 +67,7 @@
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(PRESET_N, "PRESET#", fn, SH_PFC_PIN_CFG_PULL_DOWN),\
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), \
@@ -1548,7 +1549,7 @@ static const u16 pinmux_data[] = {
* core will do the right thing and skip trying to mux the pin
* while still applying configuration to it.
*/
-#define FM(x) PINMUX_DATA(x##_MARK, 0),
+#define FM(x) PINMUX_DATA(x##_MARK, 0),
PINMUX_STATIC
#undef FM
};
@@ -4233,7 +4234,7 @@ static const struct {
SH_PFC_PIN_GROUP(avb_link),
SH_PFC_PIN_GROUP(avb_magic),
SH_PFC_PIN_GROUP(avb_phy_int),
- SH_PFC_PIN_GROUP_ALIAS(avb_mdc, avb_mdio), /* Deprecated */
+ SH_PFC_PIN_GROUP_ALIAS(avb_mdc, avb_mdio), /* Deprecated */
SH_PFC_PIN_GROUP(avb_mdio),
SH_PFC_PIN_GROUP(avb_mii),
SH_PFC_PIN_GROUP(avb_avtp_pps),
@@ -5990,7 +5991,8 @@ static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = {
{ /* sentinel */ },
};
-static int r8a7796_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *pocctrl)
+static int r8a7796_pin_to_pocctrl(struct sh_pfc *pfc,
+ unsigned int pin, u32 *pocctrl)
{
int bit = -EINVAL;
@@ -6218,7 +6220,7 @@ 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] = SH_PFC_PIN_NONE,
+ [ 7] = PIN_PRESET_N, /* PRESET# */
[ 8] = SH_PFC_PIN_NONE,
[ 9] = SH_PFC_PIN_NONE,
[10] = SH_PFC_PIN_NONE,
diff --git a/drivers/pinctrl/renesas/pfc-r8a77965.c b/drivers/pinctrl/renesas/pfc-r8a77965.c
index e69210cc6148..a7607a679886 100644
--- a/drivers/pinctrl/renesas/pfc-r8a77965.c
+++ b/drivers/pinctrl/renesas/pfc-r8a77965.c
@@ -666,14 +666,14 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP0_15_12, TX4_A, SEL_SCIF4_0),
PINMUX_IPSR_GPSR(IP0_19_16, FSCLKST2_N_A),
- PINMUX_IPSR_PHYS_MSEL(IP0_19_16, AVB_AVTP_MATCH_A, I2C_SEL_5_0, SEL_ETHERAVB_0),
- PINMUX_IPSR_PHYS_MSEL(IP0_19_16, MSIOF2_RXD_C, I2C_SEL_5_0, SEL_MSIOF2_2),
- PINMUX_IPSR_PHYS_MSEL(IP0_19_16, CTS4_N_A, I2C_SEL_5_0, SEL_SCIF4_0),
+ PINMUX_IPSR_PHYS_MSEL(IP0_19_16, AVB_AVTP_MATCH_A, I2C_SEL_5_0, SEL_ETHERAVB_0),
+ PINMUX_IPSR_PHYS_MSEL(IP0_19_16, MSIOF2_RXD_C, I2C_SEL_5_0, SEL_MSIOF2_2),
+ PINMUX_IPSR_PHYS_MSEL(IP0_19_16, CTS4_N_A, I2C_SEL_5_0, SEL_SCIF4_0),
PINMUX_IPSR_PHYS(IP0_19_16, SCL5, I2C_SEL_5_1),
- PINMUX_IPSR_PHYS_MSEL(IP0_23_20, AVB_AVTP_CAPTURE_A, I2C_SEL_5_0, SEL_ETHERAVB_0),
- PINMUX_IPSR_PHYS_MSEL(IP0_23_20, MSIOF2_TXD_C, I2C_SEL_5_0, SEL_MSIOF2_2),
- PINMUX_IPSR_PHYS_MSEL(IP0_23_20, RTS4_N_A, I2C_SEL_5_0, SEL_SCIF4_0),
+ PINMUX_IPSR_PHYS_MSEL(IP0_23_20, AVB_AVTP_CAPTURE_A, I2C_SEL_5_0, SEL_ETHERAVB_0),
+ PINMUX_IPSR_PHYS_MSEL(IP0_23_20, MSIOF2_TXD_C, I2C_SEL_5_0, SEL_MSIOF2_2),
+ PINMUX_IPSR_PHYS_MSEL(IP0_23_20, RTS4_N_A, I2C_SEL_5_0, SEL_SCIF4_0),
PINMUX_IPSR_PHYS(IP0_23_20, SDA5, I2C_SEL_5_1),
PINMUX_IPSR_GPSR(IP0_27_24, IRQ0),
@@ -727,16 +727,16 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP1_19_16, VI4_DATA6_B, SEL_VIN4_1),
PINMUX_IPSR_MSEL(IP1_19_16, IECLK_B, SEL_IEBUS_1),
- PINMUX_IPSR_PHYS_MSEL(IP1_23_20, PWM1_A, I2C_SEL_3_0, SEL_PWM1_0),
- PINMUX_IPSR_PHYS_MSEL(IP1_23_20, HRX3_D, I2C_SEL_3_0, SEL_HSCIF3_3),
- PINMUX_IPSR_PHYS_MSEL(IP1_23_20, VI4_DATA7_B, I2C_SEL_3_0, SEL_VIN4_1),
- PINMUX_IPSR_PHYS_MSEL(IP1_23_20, IERX_B, I2C_SEL_3_0, SEL_IEBUS_1),
- PINMUX_IPSR_PHYS(IP1_23_20, SCL3, I2C_SEL_3_1),
+ PINMUX_IPSR_PHYS_MSEL(IP1_23_20, PWM1_A, I2C_SEL_3_0, SEL_PWM1_0),
+ PINMUX_IPSR_PHYS_MSEL(IP1_23_20, HRX3_D, I2C_SEL_3_0, SEL_HSCIF3_3),
+ PINMUX_IPSR_PHYS_MSEL(IP1_23_20, VI4_DATA7_B, I2C_SEL_3_0, SEL_VIN4_1),
+ PINMUX_IPSR_PHYS_MSEL(IP1_23_20, IERX_B, I2C_SEL_3_0, SEL_IEBUS_1),
+ PINMUX_IPSR_PHYS(IP1_23_20, SCL3, I2C_SEL_3_1),
- PINMUX_IPSR_PHYS_MSEL(IP1_27_24, PWM2_A, I2C_SEL_3_0, SEL_PWM2_0),
- PINMUX_IPSR_PHYS_MSEL(IP1_27_24, HTX3_D, I2C_SEL_3_0, SEL_HSCIF3_3),
- PINMUX_IPSR_PHYS_MSEL(IP1_27_24, IETX_B, I2C_SEL_3_0, SEL_IEBUS_1),
- PINMUX_IPSR_PHYS(IP1_27_24, SDA3, I2C_SEL_3_1),
+ PINMUX_IPSR_PHYS_MSEL(IP1_27_24, PWM2_A, I2C_SEL_3_0, SEL_PWM2_0),
+ PINMUX_IPSR_PHYS_MSEL(IP1_27_24, HTX3_D, I2C_SEL_3_0, SEL_HSCIF3_3),
+ PINMUX_IPSR_PHYS_MSEL(IP1_27_24, IETX_B, I2C_SEL_3_0, SEL_IEBUS_1),
+ PINMUX_IPSR_PHYS(IP1_27_24, SDA3, I2C_SEL_3_1),
PINMUX_IPSR_GPSR(IP1_31_28, A0),
PINMUX_IPSR_GPSR(IP1_31_28, LCDOUT16),
@@ -1171,13 +1171,13 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MSEL(IP11_15_12, SDA2_B, SEL_I2C2_1),
PINMUX_IPSR_MSEL(IP11_19_16, SD1_CD, I2C_SEL_0_0),
- PINMUX_IPSR_PHYS_MSEL(IP11_19_16, NFRB_N_A, I2C_SEL_0_0, SEL_NDF_0),
- PINMUX_IPSR_PHYS_MSEL(IP11_19_16, SIM0_CLK_B, I2C_SEL_0_0, SEL_SIMCARD_1),
+ PINMUX_IPSR_PHYS_MSEL(IP11_19_16, NFRB_N_A, I2C_SEL_0_0, SEL_NDF_0),
+ PINMUX_IPSR_PHYS_MSEL(IP11_19_16, SIM0_CLK_B, I2C_SEL_0_0, SEL_SIMCARD_1),
PINMUX_IPSR_PHYS(IP11_19_16, SCL0, I2C_SEL_0_1),
PINMUX_IPSR_MSEL(IP11_23_20, SD1_WP, I2C_SEL_0_0),
- PINMUX_IPSR_PHYS_MSEL(IP11_23_20, NFCE_N_A, I2C_SEL_0_0, SEL_NDF_0),
- PINMUX_IPSR_PHYS_MSEL(IP11_23_20, SIM0_D_B, I2C_SEL_0_0, SEL_SIMCARD_1),
+ PINMUX_IPSR_PHYS_MSEL(IP11_23_20, NFCE_N_A, I2C_SEL_0_0, SEL_NDF_0),
+ PINMUX_IPSR_PHYS_MSEL(IP11_23_20, SIM0_D_B, I2C_SEL_0_0, SEL_SIMCARD_1),
PINMUX_IPSR_PHYS(IP11_23_20, SDA0, I2C_SEL_0_1),
PINMUX_IPSR_GPSR(IP11_27_24, SCK0),
@@ -1553,7 +1553,7 @@ static const u16 pinmux_data[] = {
* core will do the right thing and skip trying to mux the pin
* while still applying configuration to it.
*/
-#define FM(x) PINMUX_DATA(x##_MARK, 0),
+#define FM(x) PINMUX_DATA(x##_MARK, 0),
PINMUX_STATIC
#undef FM
};
@@ -4224,24 +4224,24 @@ static const unsigned int vin4_data18_a_pins[] = {
RCAR_GP_PIN(0, 10), RCAR_GP_PIN(0, 11),
RCAR_GP_PIN(0, 12), RCAR_GP_PIN(0, 13),
RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 15),
- RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3),
- RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 5),
- RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7),
- RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 3),
- RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5),
- RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 7),
+ RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3),
+ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 5),
+ RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7),
+ RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 3),
+ RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5),
+ RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 7),
};
static const unsigned int vin4_data18_a_mux[] = {
VI4_DATA2_A_MARK, VI4_DATA3_A_MARK,
VI4_DATA4_A_MARK, VI4_DATA5_A_MARK,
VI4_DATA6_A_MARK, VI4_DATA7_A_MARK,
- VI4_DATA10_MARK, VI4_DATA11_MARK,
- VI4_DATA12_MARK, VI4_DATA13_MARK,
- VI4_DATA14_MARK, VI4_DATA15_MARK,
- VI4_DATA18_MARK, VI4_DATA19_MARK,
- VI4_DATA20_MARK, VI4_DATA21_MARK,
- VI4_DATA22_MARK, VI4_DATA23_MARK,
+ VI4_DATA10_MARK, VI4_DATA11_MARK,
+ VI4_DATA12_MARK, VI4_DATA13_MARK,
+ VI4_DATA14_MARK, VI4_DATA15_MARK,
+ VI4_DATA18_MARK, VI4_DATA19_MARK,
+ VI4_DATA20_MARK, VI4_DATA21_MARK,
+ VI4_DATA22_MARK, VI4_DATA23_MARK,
};
static const union vin_data vin4_data_a_pins = {
@@ -4294,12 +4294,12 @@ static const unsigned int vin4_data18_b_mux[] = {
VI4_DATA2_B_MARK, VI4_DATA3_B_MARK,
VI4_DATA4_B_MARK, VI4_DATA5_B_MARK,
VI4_DATA6_B_MARK, VI4_DATA7_B_MARK,
- VI4_DATA10_MARK, VI4_DATA11_MARK,
- VI4_DATA12_MARK, VI4_DATA13_MARK,
- VI4_DATA14_MARK, VI4_DATA15_MARK,
- VI4_DATA18_MARK, VI4_DATA19_MARK,
- VI4_DATA20_MARK, VI4_DATA21_MARK,
- VI4_DATA22_MARK, VI4_DATA23_MARK,
+ VI4_DATA10_MARK, VI4_DATA11_MARK,
+ VI4_DATA12_MARK, VI4_DATA13_MARK,
+ VI4_DATA14_MARK, VI4_DATA15_MARK,
+ VI4_DATA18_MARK, VI4_DATA19_MARK,
+ VI4_DATA20_MARK, VI4_DATA21_MARK,
+ VI4_DATA22_MARK, VI4_DATA23_MARK,
};
static const union vin_data vin4_data_b_pins = {
@@ -6248,7 +6248,8 @@ static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = {
{ /* sentinel */ },
};
-static int r8a77965_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *pocctrl)
+static int r8a77965_pin_to_pocctrl(struct sh_pfc *pfc,
+ unsigned int pin, u32 *pocctrl)
{
int bit = -EINVAL;
diff --git a/drivers/pinctrl/renesas/pfc-r8a77970.c b/drivers/pinctrl/renesas/pfc-r8a77970.c
index 7935826cfae7..45b0b235c5cc 100644
--- a/drivers/pinctrl/renesas/pfc-r8a77970.c
+++ b/drivers/pinctrl/renesas/pfc-r8a77970.c
@@ -19,12 +19,23 @@
#include "sh_pfc.h"
#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), \
- PORT_GP_CFG_17(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_6(4, fn, sfx), \
- PORT_GP_15(5, fn, sfx)
+ PORT_GP_CFG_22(0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PORT_GP_CFG_28(1, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PORT_GP_CFG_17(2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PORT_GP_CFG_17(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PORT_GP_CFG_6(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PORT_GP_CFG_15(5, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN)
+
+#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP_CFG(DU_DOTCLKIN, "DU_DOTCLKIN", fn, SH_PFC_PIN_CFG_PULL_DOWN), \
+ PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_DOWN), \
+ PIN_NOGP_CFG(FSCLKST_N, "FSCLKST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TMS, "TMS", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TRST_N, "TRST#", fn, SH_PFC_PIN_CFG_PULL_UP)
+
/*
* F_() : just information
* FM() : macro for FN_xxx / xxx_MARK
@@ -718,8 +729,17 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_GPSR(IP8_27_24, DIGRF_CLKEN_OUT),
};
+/*
+ * 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(),
+ PINMUX_NOGP_ALL(),
};
/* - AVB0 ------------------------------------------------------------------- */
@@ -2496,8 +2516,150 @@ static int r8a77970_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin,
return -EINVAL;
}
+static const struct pinmux_bias_reg pinmux_bias_regs[] = {
+ { PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) {
+ [ 0] = RCAR_GP_PIN(0, 0), /* DU_DR2 */
+ [ 1] = RCAR_GP_PIN(0, 1), /* DU_DR3 */
+ [ 2] = RCAR_GP_PIN(0, 2), /* DU_DR4 */
+ [ 3] = RCAR_GP_PIN(0, 3), /* DU_DR5 */
+ [ 4] = RCAR_GP_PIN(0, 4), /* DU_DR6 */
+ [ 5] = RCAR_GP_PIN(0, 5), /* DU_DR7 */
+ [ 6] = RCAR_GP_PIN(0, 6), /* DU_DG2 */
+ [ 7] = RCAR_GP_PIN(0, 7), /* DU_DG3 */
+ [ 8] = RCAR_GP_PIN(0, 8), /* DU_DG4 */
+ [ 9] = RCAR_GP_PIN(0, 9), /* DU_DG5 */
+ [10] = RCAR_GP_PIN(0, 10), /* DU_DG6 */
+ [11] = RCAR_GP_PIN(0, 11), /* DU_DG7 */
+ [12] = RCAR_GP_PIN(0, 12), /* DU_DB2 */
+ [13] = RCAR_GP_PIN(0, 13), /* DU_DB3 */
+ [14] = RCAR_GP_PIN(0, 14), /* DU_DB4 */
+ [15] = RCAR_GP_PIN(0, 15), /* DU_DB5 */
+ [16] = RCAR_GP_PIN(0, 16), /* DU_DB6 */
+ [17] = RCAR_GP_PIN(0, 17), /* DU_DB7 */
+ [18] = RCAR_GP_PIN(0, 18), /* DU_DOTCLKOUT */
+ [19] = RCAR_GP_PIN(0, 19), /* DU_EXHSYNC/DU_HSYNC */
+ [20] = RCAR_GP_PIN(0, 20), /* DU_EXVSYNC/DU_VSYNC */
+ [21] = RCAR_GP_PIN(0, 21), /* DU_EXODDF/DU_ODDF/DISP/CDE */
+ [22] = PIN_DU_DOTCLKIN, /* DU_DOTCLKIN */
+ [23] = PIN_PRESETOUT_N, /* PRESETOUT# */
+ [24] = PIN_EXTALR, /* EXTALR */
+ [25] = PIN_FSCLKST_N, /* FSCLKST# */
+ [26] = RCAR_GP_PIN(1, 0), /* IRQ0 */
+ [27] = PIN_TRST_N, /* TRST# */
+ [28] = PIN_TCK, /* TCK */
+ [29] = PIN_TMS, /* TMS */
+ [30] = PIN_TDI, /* TDI */
+ [31] = RCAR_GP_PIN(2, 0), /* VI0_CLK */
+ } },
+ { PINMUX_BIAS_REG("PUEN1", 0xe6060404, "PUD1", 0xe6060444) {
+ [ 0] = RCAR_GP_PIN(2, 1), /* VI0_CLKENB */
+ [ 1] = RCAR_GP_PIN(2, 2), /* VI0_HSYNC# */
+ [ 2] = RCAR_GP_PIN(2, 3), /* VI0_VSYNC# */
+ [ 3] = RCAR_GP_PIN(2, 4), /* VI0_DATA0 */
+ [ 4] = RCAR_GP_PIN(2, 5), /* VI0_DATA1 */
+ [ 5] = RCAR_GP_PIN(2, 6), /* VI0_DATA2 */
+ [ 6] = RCAR_GP_PIN(2, 7), /* VI0_DATA3 */
+ [ 7] = RCAR_GP_PIN(2, 8), /* VI0_DATA4 */
+ [ 8] = RCAR_GP_PIN(2, 9), /* VI0_DATA5 */
+ [ 9] = RCAR_GP_PIN(2, 10), /* VI0_DATA6 */
+ [10] = RCAR_GP_PIN(2, 11), /* VI0_DATA7 */
+ [11] = RCAR_GP_PIN(2, 12), /* VI0_DATA8 */
+ [12] = RCAR_GP_PIN(2, 13), /* VI0_DATA9 */
+ [13] = RCAR_GP_PIN(2, 14), /* VI0_DATA10 */
+ [14] = RCAR_GP_PIN(2, 15), /* VI0_DATA11 */
+ [15] = RCAR_GP_PIN(2, 16), /* VI0_FIELD */
+ [16] = RCAR_GP_PIN(3, 0), /* VI1_CLK */
+ [17] = RCAR_GP_PIN(3, 1), /* VI1_CLKENB */
+ [18] = RCAR_GP_PIN(3, 2), /* VI1_HSYNC# */
+ [19] = RCAR_GP_PIN(3, 3), /* VI1_VSYNC# */
+ [20] = RCAR_GP_PIN(3, 4), /* VI1_DATA0 */
+ [21] = RCAR_GP_PIN(3, 5), /* VI1_DATA1 */
+ [22] = RCAR_GP_PIN(3, 6), /* VI1_DATA2 */
+ [23] = RCAR_GP_PIN(3, 7), /* VI1_DATA3 */
+ [24] = RCAR_GP_PIN(3, 8), /* VI1_DATA4 */
+ [25] = RCAR_GP_PIN(3, 9), /* VI1_DATA5 */
+ [26] = RCAR_GP_PIN(3, 10), /* VI1_DATA6 */
+ [27] = RCAR_GP_PIN(3, 11), /* VI1_DATA7 */
+ [28] = RCAR_GP_PIN(3, 12), /* VI1_DATA8 */
+ [29] = RCAR_GP_PIN(3, 13), /* VI1_DATA9 */
+ [30] = RCAR_GP_PIN(3, 14), /* VI1_DATA10 */
+ [31] = RCAR_GP_PIN(3, 15), /* VI1_DATA11 */
+ } },
+ { PINMUX_BIAS_REG("PUEN2", 0xe6060408, "PUD2", 0xe6060448) {
+ [ 0] = RCAR_GP_PIN(3, 16), /* VI1_FIELD */
+ [ 1] = RCAR_GP_PIN(4, 0), /* SCL0 */
+ [ 2] = RCAR_GP_PIN(4, 1), /* SDA0 */
+ [ 3] = RCAR_GP_PIN(4, 2), /* SCL1 */
+ [ 4] = RCAR_GP_PIN(4, 3), /* SDA1 */
+ [ 5] = RCAR_GP_PIN(4, 4), /* SCL2 */
+ [ 6] = RCAR_GP_PIN(4, 5), /* SDA2 */
+ [ 7] = RCAR_GP_PIN(1, 1), /* AVB0_RX_CTL */
+ [ 8] = RCAR_GP_PIN(1, 2), /* AVB0_RXC */
+ [ 9] = RCAR_GP_PIN(1, 3), /* AVB0_RD0 */
+ [10] = RCAR_GP_PIN(1, 4), /* AVB0_RD1 */
+ [11] = RCAR_GP_PIN(1, 5), /* AVB0_RD2 */
+ [12] = RCAR_GP_PIN(1, 6), /* AVB0_RD3 */
+ [13] = RCAR_GP_PIN(1, 7), /* AVB0_TX_CTL */
+ [14] = RCAR_GP_PIN(1, 8), /* AVB0_TXC */
+ [15] = RCAR_GP_PIN(1, 9), /* AVB0_TD0 */
+ [16] = RCAR_GP_PIN(1, 10), /* AVB0_TD1 */
+ [17] = RCAR_GP_PIN(1, 11), /* AVB0_TD2 */
+ [18] = RCAR_GP_PIN(1, 12), /* AVB0_TD3 */
+ [19] = RCAR_GP_PIN(1, 13), /* AVB0_TXCREFCLK */
+ [20] = RCAR_GP_PIN(1, 14), /* AVB0_MDIO */
+ [21] = RCAR_GP_PIN(1, 15), /* AVB0_MDC */
+ [22] = RCAR_GP_PIN(1, 16), /* AVB0_MAGIC */
+ [23] = RCAR_GP_PIN(1, 17), /* AVB0_PHY_INT */
+ [24] = RCAR_GP_PIN(1, 18), /* AVB0_LINK */
+ [25] = RCAR_GP_PIN(1, 19), /* AVB0_AVTP_MATCH */
+ [26] = RCAR_GP_PIN(1, 20), /* AVB0_AVTP_CAPTURE */
+ [27] = RCAR_GP_PIN(1, 21), /* CANFD0_TX_A */
+ [28] = RCAR_GP_PIN(1, 22), /* CANFD0_RX_A */
+ [29] = RCAR_GP_PIN(1, 23), /* CANFD1_TX */
+ [30] = RCAR_GP_PIN(1, 24), /* CANFD1_RX */
+ [31] = RCAR_GP_PIN(1, 25), /* CANFD_CLK */
+ } },
+ { PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) {
+ [ 0] = RCAR_GP_PIN(5, 0), /* QSPI0_SPCLK */
+ [ 1] = RCAR_GP_PIN(5, 1), /* QSPI0_MOSI_IO0 */
+ [ 2] = RCAR_GP_PIN(5, 2), /* QSPI0_MISO_IO1 */
+ [ 3] = RCAR_GP_PIN(5, 3), /* QSPI0_IO2 */
+ [ 4] = RCAR_GP_PIN(5, 4), /* QSPI0_IO3 */
+ [ 5] = RCAR_GP_PIN(5, 5), /* QSPI0_SSL */
+ [ 6] = RCAR_GP_PIN(5, 6), /* QSPI1_SPCLK */
+ [ 7] = RCAR_GP_PIN(5, 7), /* QSPI1_MOSI_IO0 */
+ [ 8] = RCAR_GP_PIN(5, 8), /* QSPI1_MISO_IO1 */
+ [ 9] = RCAR_GP_PIN(5, 9), /* QSPI1_IO2 */
+ [10] = RCAR_GP_PIN(5, 10), /* QSPI1_IO3 */
+ [11] = RCAR_GP_PIN(5, 11), /* QSPI1_SSL */
+ [12] = RCAR_GP_PIN(5, 12), /* RPC_RESET# */
+ [13] = RCAR_GP_PIN(5, 13), /* RPC_WP# */
+ [14] = RCAR_GP_PIN(5, 14), /* RPC_INT# */
+ [15] = RCAR_GP_PIN(1, 26), /* DIGRF_CLKIN */
+ [16] = RCAR_GP_PIN(1, 27), /* DIGRF_CLKOUT */
+ [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 */ }
+};
+
static const struct sh_pfc_soc_operations pinmux_ops = {
.pin_to_pocctrl = r8a77970_pin_to_pocctrl,
+ .get_bias = rcar_pinmux_get_bias,
+ .set_bias = rcar_pinmux_set_bias,
};
const struct sh_pfc_soc_info r8a77970_pinmux_info = {
@@ -2515,6 +2677,7 @@ const struct sh_pfc_soc_info r8a77970_pinmux_info = {
.nr_functions = ARRAY_SIZE(pinmux_functions),
.cfg_regs = pinmux_config_regs,
+ .bias_regs = pinmux_bias_regs,
.ioctrl_regs = pinmux_ioctrl_regs,
.pinmux_data = pinmux_data,
diff --git a/drivers/pinctrl/renesas/pfc-r8a77980.c b/drivers/pinctrl/renesas/pfc-r8a77980.c
index 20cff93a2a13..c4825b01449e 100644
--- a/drivers/pinctrl/renesas/pfc-r8a77980.c
+++ b/drivers/pinctrl/renesas/pfc-r8a77980.c
@@ -19,12 +19,23 @@
#include "sh_pfc.h"
#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), \
- PORT_GP_CFG_17(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE), \
- PORT_GP_25(4, fn, sfx), \
- PORT_GP_15(5, fn, sfx)
+ PORT_GP_CFG_22(0, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PORT_GP_CFG_28(1, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PORT_GP_CFG_30(2, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PORT_GP_CFG_17(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE | SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PORT_GP_CFG_25(4, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PORT_GP_CFG_15(5, fn, sfx, SH_PFC_PIN_CFG_PULL_UP_DOWN)
+
+#define CPU_ALL_NOGP(fn) \
+ PIN_NOGP_CFG(DCUTCK_LPDCLK, "DCUTCK_LPDCLK", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(DCUTDI_LPDI, "DCUTDI_LPDI", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(DCUTMS, "DCUTMS", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(DCUTRST_N, "DCUTRST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(DU_DOTCLKIN, "DU_DOTCLKIN", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(EXTALR, "EXTALR", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(FSCLKST, "FSCLKST", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(FSCLKST_N, "FSCLKST#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN), \
+ PIN_NOGP_CFG(PRESETOUT_N, "PRESETOUT#", fn, SH_PFC_PIN_CFG_PULL_UP_DOWN)
/*
* F_() : just information
@@ -830,8 +841,17 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_GPSR(IP10_19_16, FSO_TOE_N),
};
+/*
+ * 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(),
+ PINMUX_NOGP_ALL(),
};
/* - AVB -------------------------------------------------------------------- */
@@ -2945,8 +2965,184 @@ static int r8a77980_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin,
return -EINVAL;
}
+static const struct pinmux_bias_reg pinmux_bias_regs[] = {
+ { PINMUX_BIAS_REG("PUEN0", 0xe6060400, "PUD0", 0xe6060440) {
+ [ 0] = RCAR_GP_PIN(0, 0), /* DU_DR2 */
+ [ 1] = RCAR_GP_PIN(0, 1), /* DU_DR3 */
+ [ 2] = RCAR_GP_PIN(0, 2), /* DU_DR4 */
+ [ 3] = RCAR_GP_PIN(0, 3), /* DU_DR5 */
+ [ 4] = RCAR_GP_PIN(0, 4), /* DU_DR6 */
+ [ 5] = RCAR_GP_PIN(0, 5), /* DU_DR7 */
+ [ 6] = RCAR_GP_PIN(0, 6), /* DU_DG2 */
+ [ 7] = RCAR_GP_PIN(0, 7), /* DU_DG3 */
+ [ 8] = RCAR_GP_PIN(0, 8), /* DU_DG4 */
+ [ 9] = RCAR_GP_PIN(0, 9), /* DU_DG5 */
+ [10] = RCAR_GP_PIN(0, 10), /* DU_DG6 */
+ [11] = RCAR_GP_PIN(0, 11), /* DU_DG7 */
+ [12] = RCAR_GP_PIN(0, 12), /* DU_DB2 */
+ [13] = RCAR_GP_PIN(0, 13), /* DU_DB3 */
+ [14] = RCAR_GP_PIN(0, 14), /* DU_DB4 */
+ [15] = RCAR_GP_PIN(0, 15), /* DU_DB5 */
+ [16] = RCAR_GP_PIN(0, 16), /* DU_DB6 */
+ [17] = RCAR_GP_PIN(0, 17), /* DU_DB7 */
+ [18] = RCAR_GP_PIN(0, 18), /* DU_DOTCLKOUT */
+ [19] = RCAR_GP_PIN(0, 19), /* DU_EXHSYNC/DU_HSYNC */
+ [20] = RCAR_GP_PIN(0, 20), /* DU_EXVSYNC/DU_VSYNC */
+ [21] = RCAR_GP_PIN(0, 21), /* DU_EXODDF/DU_ODDF/DISP/CDE */
+ [22] = SH_PFC_PIN_NONE,
+ [23] = SH_PFC_PIN_NONE,
+ [24] = PIN_DU_DOTCLKIN, /* DU_DOTCLKIN */
+ [25] = SH_PFC_PIN_NONE,
+ [26] = PIN_PRESETOUT_N, /* PRESETOUT# */
+ [27] = SH_PFC_PIN_NONE,
+ [28] = SH_PFC_PIN_NONE,
+ [29] = SH_PFC_PIN_NONE,
+ [30] = PIN_EXTALR, /* EXTALR */
+ [31] = PIN_FSCLKST_N, /* FSCLKST# */
+ } },
+ { PINMUX_BIAS_REG("PUEN1", 0xe6060404, "PUD1", 0xe6060444) {
+ [ 0] = PIN_FSCLKST, /* FSCLKST */
+ [ 1] = SH_PFC_PIN_NONE,
+ [ 2] = RCAR_GP_PIN(1, 0), /* IRQ0 */
+ [ 3] = PIN_DCUTRST_N, /* DCUTRST# */
+ [ 4] = PIN_DCUTCK_LPDCLK, /* DCUTCK_LPDCLK */
+ [ 5] = PIN_DCUTMS, /* DCUTMS */
+ [ 6] = PIN_DCUTDI_LPDI, /* DCUTDI_LPDI */
+ [ 7] = SH_PFC_PIN_NONE,
+ [ 8] = RCAR_GP_PIN(2, 0), /* VI0_CLK */
+ [ 9] = RCAR_GP_PIN(2, 1), /* VI0_CLKENB */
+ [10] = RCAR_GP_PIN(2, 2), /* VI0_HSYNC# */
+ [11] = RCAR_GP_PIN(2, 3), /* VI0_VSYNC# */
+ [12] = RCAR_GP_PIN(2, 4), /* VI0_DATA0 */
+ [13] = RCAR_GP_PIN(2, 5), /* VI0_DATA1 */
+ [14] = RCAR_GP_PIN(2, 6), /* VI0_DATA2 */
+ [15] = RCAR_GP_PIN(2, 7), /* VI0_DATA3 */
+ [16] = RCAR_GP_PIN(2, 8), /* VI0_DATA4 */
+ [17] = RCAR_GP_PIN(2, 9), /* VI0_DATA5 */
+ [18] = RCAR_GP_PIN(2, 10), /* VI0_DATA6 */
+ [19] = RCAR_GP_PIN(2, 11), /* VI0_DATA7 */
+ [20] = RCAR_GP_PIN(2, 12), /* VI0_DATA8 */
+ [21] = RCAR_GP_PIN(2, 13), /* VI0_DATA9 */
+ [22] = RCAR_GP_PIN(2, 14), /* VI0_DATA10 */
+ [23] = RCAR_GP_PIN(2, 15), /* VI0_DATA11 */
+ [24] = RCAR_GP_PIN(2, 16), /* VI0_FIELD */
+ [25] = RCAR_GP_PIN(3, 0), /* VI1_CLK */
+ [26] = RCAR_GP_PIN(3, 1), /* VI1_CLKENB */
+ [27] = RCAR_GP_PIN(3, 2), /* VI1_HSYNC# */
+ [28] = RCAR_GP_PIN(3, 3), /* VI1_VSYNC# */
+ [29] = RCAR_GP_PIN(3, 4), /* VI1_DATA0 */
+ [30] = RCAR_GP_PIN(3, 5), /* VI1_DATA1 */
+ [31] = RCAR_GP_PIN(3, 6), /* VI1_DATA2 */
+ } },
+ { PINMUX_BIAS_REG("PUEN2", 0xe6060408, "PUD2", 0xe6060448) {
+ [ 0] = RCAR_GP_PIN(3, 7), /* VI1_DATA3 */
+ [ 1] = RCAR_GP_PIN(3, 8), /* VI1_DATA4 */
+ [ 2] = RCAR_GP_PIN(3, 9), /* VI1_DATA5 */
+ [ 3] = RCAR_GP_PIN(3, 10), /* VI1_DATA6 */
+ [ 4] = RCAR_GP_PIN(3, 11), /* VI1_DATA7 */
+ [ 5] = RCAR_GP_PIN(3, 12), /* VI1_DATA8 */
+ [ 6] = RCAR_GP_PIN(3, 13), /* VI1_DATA9 */
+ [ 7] = RCAR_GP_PIN(3, 14), /* VI1_DATA10 */
+ [ 8] = RCAR_GP_PIN(3, 15), /* VI1_DATA11 */
+ [ 9] = RCAR_GP_PIN(3, 16), /* VI1_FIELD */
+ [10] = RCAR_GP_PIN(4, 0), /* SCL0 */
+ [11] = RCAR_GP_PIN(4, 1), /* SDA0 */
+ [12] = RCAR_GP_PIN(4, 2), /* SCL1 */
+ [13] = RCAR_GP_PIN(4, 3), /* SDA1 */
+ [14] = RCAR_GP_PIN(4, 4), /* SCL2 */
+ [15] = RCAR_GP_PIN(4, 5), /* SDA2 */
+ [16] = RCAR_GP_PIN(1, 1), /* AVB_RX_CTL */
+ [17] = RCAR_GP_PIN(1, 2), /* AVB_RXC */
+ [18] = RCAR_GP_PIN(1, 3), /* AVB_RD0 */
+ [19] = RCAR_GP_PIN(1, 4), /* AVB_RD1 */
+ [20] = RCAR_GP_PIN(1, 5), /* AVB_RD2 */
+ [21] = RCAR_GP_PIN(1, 6), /* AVB_RD3 */
+ [22] = RCAR_GP_PIN(1, 7), /* AVB_TX_CTL */
+ [23] = RCAR_GP_PIN(1, 8), /* AVB_TXC */
+ [24] = RCAR_GP_PIN(1, 9), /* AVB_TD0 */
+ [25] = RCAR_GP_PIN(1, 10), /* AVB_TD1 */
+ [26] = RCAR_GP_PIN(1, 11), /* AVB_TD2 */
+ [27] = RCAR_GP_PIN(1, 12), /* AVB_TD3 */
+ [28] = RCAR_GP_PIN(1, 13), /* AVB_TXCREFCLK */
+ [29] = RCAR_GP_PIN(1, 14), /* AVB_MDIO */
+ [30] = RCAR_GP_PIN(1, 15), /* AVB_MDC */
+ [31] = RCAR_GP_PIN(1, 16), /* AVB_MAGIC */
+ } },
+ { PINMUX_BIAS_REG("PUEN3", 0xe606040c, "PUD3", 0xe606044c) {
+ [ 0] = RCAR_GP_PIN(1, 17), /* AVB_PHY_INT */
+ [ 1] = RCAR_GP_PIN(1, 18), /* AVB_LINK */
+ [ 2] = RCAR_GP_PIN(1, 19), /* AVB_AVTP_MATCH */
+ [ 3] = RCAR_GP_PIN(1, 20), /* AVTP_CAPTURE */
+ [ 4] = RCAR_GP_PIN(4, 6), /* GETHER_RX_CTL */
+ [ 5] = RCAR_GP_PIN(4, 7), /* GETHER_RXC */
+ [ 6] = RCAR_GP_PIN(4, 8), /* GETHER_RD0 */
+ [ 7] = RCAR_GP_PIN(4, 9), /* GETHER_RD1 */
+ [ 8] = RCAR_GP_PIN(4, 10), /* GETHER_RD2 */
+ [ 9] = RCAR_GP_PIN(4, 11), /* GETHER_RD3 */
+ [10] = RCAR_GP_PIN(4, 12), /* GETHER_TX_CTL */
+ [11] = RCAR_GP_PIN(4, 13), /* GETHER_TXC */
+ [12] = RCAR_GP_PIN(4, 14), /* GETHER_TD0 */
+ [13] = RCAR_GP_PIN(4, 15), /* GETHER_TD1 */
+ [14] = RCAR_GP_PIN(4, 16), /* GETHER_TD2 */
+ [15] = RCAR_GP_PIN(4, 17), /* GETHER_TD3 */
+ [16] = RCAR_GP_PIN(4, 18), /* GETHER_TXCREFCLK */
+ [17] = RCAR_GP_PIN(4, 19), /* GETHER_TXCREFCLK_MEGA */
+ [18] = RCAR_GP_PIN(4, 20), /* GETHER_MDIO_A */
+ [19] = RCAR_GP_PIN(4, 21), /* GETHER_MDC_A */
+ [20] = RCAR_GP_PIN(4, 22), /* GETHER_MAGIC */
+ [21] = RCAR_GP_PIN(4, 23), /* GETHER_PHY_INT_A */
+ [22] = RCAR_GP_PIN(4, 24), /* GETHER_LINK_A */
+ [23] = RCAR_GP_PIN(1, 21), /* CANFD0_TX_A */
+ [24] = RCAR_GP_PIN(1, 22), /* CANFD0_RX_A */
+ [25] = RCAR_GP_PIN(1, 23), /* CANFD1_TX */
+ [26] = RCAR_GP_PIN(1, 24), /* CANFD1_RX */
+ [27] = RCAR_GP_PIN(1, 25), /* CAN_CLK_A */
+ [28] = RCAR_GP_PIN(5, 0), /* QSPI0_SPCLK */
+ [29] = RCAR_GP_PIN(5, 1), /* QSPI0_MOSI_IO0 */
+ [30] = RCAR_GP_PIN(5, 2), /* QSPI0_MISO_IO1 */
+ [31] = RCAR_GP_PIN(5, 3), /* QSPI0_IO2 */
+ } },
+ { PINMUX_BIAS_REG("PUEN4", 0xe6060410, "PUD4", 0xe6060450) {
+ [ 0] = RCAR_GP_PIN(5, 4), /* QSPI0_IO3 */
+ [ 1] = RCAR_GP_PIN(5, 5), /* QSPI0_SSL */
+ [ 2] = RCAR_GP_PIN(5, 6), /* QSPI1_SPCLK */
+ [ 3] = RCAR_GP_PIN(5, 7), /* QSPI1_MOSI_IO0 */
+ [ 4] = RCAR_GP_PIN(5, 8), /* QSPI1_MISO_IO1 */
+ [ 5] = RCAR_GP_PIN(5, 9), /* QSPI1_IO2 */
+ [ 6] = RCAR_GP_PIN(5, 10), /* QSPI1_IO3 */
+ [ 7] = RCAR_GP_PIN(5, 11), /* QSPI1_SSL */
+ [ 8] = RCAR_GP_PIN(5, 12), /* RPC_RESET# */
+ [ 9] = RCAR_GP_PIN(5, 13), /* RPC_WP# */
+ [10] = RCAR_GP_PIN(5, 14), /* RPC_INT# */
+ [11] = RCAR_GP_PIN(1, 26), /* DIGRF_CLKIN */
+ [12] = RCAR_GP_PIN(1, 27), /* DIGRF_CLKOUT */
+ [13] = RCAR_GP_PIN(2, 17), /* IRQ4 */
+ [14] = RCAR_GP_PIN(2, 18), /* IRQ5 */
+ [15] = RCAR_GP_PIN(2, 25), /* SCL3 */
+ [16] = RCAR_GP_PIN(2, 26), /* SDA3 */
+ [17] = RCAR_GP_PIN(2, 19), /* MSIOF0_RXD */
+ [18] = RCAR_GP_PIN(2, 20), /* MSIOF0_TXD */
+ [19] = RCAR_GP_PIN(2, 21), /* MSIOF0_SCK */
+ [20] = RCAR_GP_PIN(2, 22), /* MSIOF0_SYNC */
+ [21] = RCAR_GP_PIN(2, 23), /* MSIOF0_SS1 */
+ [22] = RCAR_GP_PIN(2, 24), /* MSIOF0_SS2 */
+ [23] = RCAR_GP_PIN(2, 27), /* FSO_CFE_0# */
+ [24] = RCAR_GP_PIN(2, 28), /* FSO_CFE_1# */
+ [25] = RCAR_GP_PIN(2, 29), /* FSO_TOE# */
+ [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 */ }
+};
+
static const struct sh_pfc_soc_operations pinmux_ops = {
.pin_to_pocctrl = r8a77980_pin_to_pocctrl,
+ .get_bias = rcar_pinmux_get_bias,
+ .set_bias = rcar_pinmux_set_bias,
};
const struct sh_pfc_soc_info r8a77980_pinmux_info = {
@@ -2964,6 +3160,7 @@ const struct sh_pfc_soc_info r8a77980_pinmux_info = {
.nr_functions = ARRAY_SIZE(pinmux_functions),
.cfg_regs = pinmux_config_regs,
+ .bias_regs = pinmux_bias_regs,
.ioctrl_regs = pinmux_ioctrl_regs,
.pinmux_data = pinmux_data,
diff --git a/drivers/pinctrl/renesas/pfc-r8a77990.c b/drivers/pinctrl/renesas/pfc-r8a77990.c
index d040eb3e305d..f44c7da3ec16 100644
--- a/drivers/pinctrl/renesas/pfc-r8a77990.c
+++ b/drivers/pinctrl/renesas/pfc-r8a77990.c
@@ -53,10 +53,10 @@
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)
+ PIN_NOGP_CFG(TCK, "TCK", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TDI, "TDI", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TMS, "TMS", fn, SH_PFC_PIN_CFG_PULL_UP), \
+ PIN_NOGP_CFG(TRST_N, "TRST_N", fn, SH_PFC_PIN_CFG_PULL_UP)
/*
* F_() : just information
@@ -5197,8 +5197,8 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[27] = RCAR_GP_PIN(1, 0), /* A0 */
[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# */
+ [30] = RCAR_GP_PIN(2, 25), /* EX_WAIT0 */
+ [31] = RCAR_GP_PIN(2, 24), /* RD/WR# */
} },
{ PINMUX_BIAS_REG("PUEN2", 0xe6060408, "PUD2", 0xe6060448) {
[0] = RCAR_GP_PIN(3, 1), /* SD0_CMD */
@@ -5333,8 +5333,8 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = {
[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 */
+ [30] = RCAR_GP_PIN(6, 9), /* USB30_OVC */
+ [31] = RCAR_GP_PIN(6, 17), /* USB30_PWEN */
} },
{ /* sentinel */ },
};
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
index ad9eb5ed8e81..68b3886f9f0f 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32.c
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
@@ -414,57 +414,25 @@ 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_in_atomic(pctl->hwlock,
HWSPNLCK_TIMEOUT);
if (ret) {
dev_err(pctl->dev, "Can't get hwspinlock\n");
- goto unlock;
+ return ret;
}
}
- 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_in_atomic(pctl->hwlock);
- goto unlock;
- } else {
- pctl->irqmux_map |= BIT(irq_data->hwirq);
- }
-
regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr);
if (pctl->hwlock)
hwspin_unlock_in_atomic(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,
unsigned int virq,
unsigned int nr_irqs, void *data)
@@ -472,9 +440,28 @@ static int stm32_gpio_domain_alloc(struct irq_domain *d,
struct stm32_gpio_bank *bank = d->host_data;
struct irq_fwspec *fwspec = data;
struct irq_fwspec parent_fwspec;
- irq_hw_number_t hwirq;
+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
+ irq_hw_number_t hwirq = fwspec->param[0];
+ unsigned long flags;
+ int ret = 0;
+
+ /*
+ * Check first that the IRQ MUX of that line is free.
+ * gpio irq mux is shared between several banks, protect with a lock
+ */
+ spin_lock_irqsave(&pctl->irqmux_lock, flags);
+
+ if (pctl->irqmux_map & BIT(hwirq)) {
+ dev_err(pctl->dev, "irq line %ld already requested.\n", hwirq);
+ ret = -EBUSY;
+ } else {
+ pctl->irqmux_map |= BIT(hwirq);
+ }
+
+ spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
+ if (ret)
+ return ret;
- hwirq = fwspec->param[0];
parent_fwspec.fwnode = d->parent->fwnode;
parent_fwspec.param_count = 2;
parent_fwspec.param[0] = fwspec->param[0];
@@ -486,12 +473,26 @@ static int stm32_gpio_domain_alloc(struct irq_domain *d,
return irq_domain_alloc_irqs_parent(d, virq, nr_irqs, &parent_fwspec);
}
+static void stm32_gpio_domain_free(struct irq_domain *d, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct stm32_gpio_bank *bank = d->host_data;
+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
+ struct irq_data *irq_data = irq_domain_get_irq_data(d, virq);
+ unsigned long flags, hwirq = irq_data->hwirq;
+
+ irq_domain_free_irqs_common(d, virq, nr_irqs);
+
+ spin_lock_irqsave(&pctl->irqmux_lock, flags);
+ pctl->irqmux_map &= ~BIT(hwirq);
+ spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
+}
+
static const struct irq_domain_ops stm32_gpio_domain_ops = {
- .translate = stm32_gpio_domain_translate,
- .alloc = stm32_gpio_domain_alloc,
- .free = irq_domain_free_irqs_common,
+ .translate = stm32_gpio_domain_translate,
+ .alloc = stm32_gpio_domain_alloc,
+ .free = stm32_gpio_domain_free,
.activate = stm32_gpio_domain_activate,
- .deactivate = stm32_gpio_domain_deactivate,
};
/* Pinctrl functions */
@@ -1224,7 +1225,7 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl,
struct device *dev = pctl->dev;
struct resource res;
int npins = STM32_GPIO_PINS_PER_BANK;
- int bank_nr, err;
+ int bank_nr, err, i = 0;
if (!IS_ERR(bank->rstc))
reset_control_deassert(bank->rstc);
@@ -1246,9 +1247,14 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl,
of_property_read_string(np, "st,bank-name", &bank->gpio_chip.label);
- if (!of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args)) {
+ if (!of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, i, &args)) {
bank_nr = args.args[1] / STM32_GPIO_PINS_PER_BANK;
bank->gpio_chip.base = args.args[1];
+
+ npins = args.args[2];
+ while (!of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,
+ ++i, &args))
+ npins += args.args[2];
} else {
bank_nr = pctl->nbanks;
bank->gpio_chip.base = bank_nr * STM32_GPIO_PINS_PER_BANK;
diff --git a/drivers/platform/chrome/cros_ec_ishtp.c b/drivers/platform/chrome/cros_ec_ishtp.c
index f00107017318..9d1e7e03628e 100644
--- a/drivers/platform/chrome/cros_ec_ishtp.c
+++ b/drivers/platform/chrome/cros_ec_ishtp.c
@@ -703,7 +703,7 @@ end_ishtp_cl_alloc_error:
*
* Return: 0
*/
-static int cros_ec_ishtp_remove(struct ishtp_cl_device *cl_device)
+static void 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);
@@ -712,8 +712,6 @@ static int cros_ec_ishtp_remove(struct ishtp_cl_device *cl_device)
cancel_work_sync(&client_data->work_ec_evt);
cros_ish_deinit(cros_ish_cl);
ishtp_put_device(cl_device);
-
- return 0;
}
/**
diff --git a/drivers/platform/surface/aggregator/Kconfig b/drivers/platform/surface/aggregator/Kconfig
index 3aaeea9f0433..fd6dc452f3e8 100644
--- a/drivers/platform/surface/aggregator/Kconfig
+++ b/drivers/platform/surface/aggregator/Kconfig
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0+
-# Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+# Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
menuconfig SURFACE_AGGREGATOR
tristate "Microsoft Surface System Aggregator Module Subsystem and Drivers"
diff --git a/drivers/platform/surface/aggregator/Makefile b/drivers/platform/surface/aggregator/Makefile
index c112e2c7112b..c8498c41e758 100644
--- a/drivers/platform/surface/aggregator/Makefile
+++ b/drivers/platform/surface/aggregator/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0+
-# Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+# Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
# For include/trace/define_trace.h to include trace.h
CFLAGS_core.o = -I$(src)
diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c
index a9b660af0917..0169677c243e 100644
--- a/drivers/platform/surface/aggregator/bus.c
+++ b/drivers/platform/surface/aggregator/bus.c
@@ -2,7 +2,7 @@
/*
* Surface System Aggregator Module bus and device integration.
*
- * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+ * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#include <linux/device.h>
diff --git a/drivers/platform/surface/aggregator/bus.h b/drivers/platform/surface/aggregator/bus.h
index 7712baaed6a5..ed032c2cbdb2 100644
--- a/drivers/platform/surface/aggregator/bus.h
+++ b/drivers/platform/surface/aggregator/bus.h
@@ -2,7 +2,7 @@
/*
* Surface System Aggregator Module bus and device integration.
*
- * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+ * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#ifndef _SURFACE_AGGREGATOR_BUS_H
diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
index a06964aa96e7..b8c377b3f932 100644
--- a/drivers/platform/surface/aggregator/controller.c
+++ b/drivers/platform/surface/aggregator/controller.c
@@ -2,7 +2,7 @@
/*
* Main SSAM/SSH controller structure and functionality.
*
- * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+ * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#include <linux/acpi.h>
@@ -408,6 +408,31 @@ ssam_nf_refcount_dec(struct ssam_nf *nf, struct ssam_event_registry reg,
}
/**
+ * ssam_nf_refcount_dec_free() - Decrement reference-/activation-count of the
+ * given event and free its entry if the reference count reaches zero.
+ * @nf: The notifier system reference.
+ * @reg: The registry used to enable/disable the event.
+ * @id: The event ID.
+ *
+ * Decrements the reference-/activation-count of the specified event, freeing
+ * its entry if it reaches zero.
+ *
+ * Note: ``nf->lock`` must be held when calling this function.
+ */
+static void ssam_nf_refcount_dec_free(struct ssam_nf *nf,
+ struct ssam_event_registry reg,
+ struct ssam_event_id id)
+{
+ struct ssam_nf_refcount_entry *entry;
+
+ lockdep_assert_held(&nf->lock);
+
+ entry = ssam_nf_refcount_dec(nf, reg, id);
+ if (entry && entry->refcount == 0)
+ kfree(entry);
+}
+
+/**
* ssam_nf_refcount_empty() - Test if the notification system has any
* enabled/active events.
* @nf: The notification system.
@@ -2123,13 +2148,122 @@ int ssam_ctrl_notif_d0_entry(struct ssam_controller *ctrl)
/* -- Top-level event registry interface. ----------------------------------- */
/**
+ * ssam_nf_refcount_enable() - Enable event for reference count entry if it has
+ * not already been enabled.
+ * @ctrl: The controller to enable the event on.
+ * @entry: The reference count entry for the event to be enabled.
+ * @flags: The flags used for enabling the event on the EC.
+ *
+ * Enable the event associated with the given reference count entry if the
+ * reference count equals one, i.e. the event has not previously been enabled.
+ * If the event has already been enabled (i.e. reference count not equal to
+ * one), check that the flags used for enabling match and warn about this if
+ * they do not.
+ *
+ * This does not modify the reference count itself, which is done with
+ * ssam_nf_refcount_inc() / ssam_nf_refcount_dec().
+ *
+ * Note: ``nf->lock`` must be held when calling this function.
+ *
+ * Return: Returns zero on success. If the event is enabled by this call,
+ * returns the status of the event-enable EC command.
+ */
+static int ssam_nf_refcount_enable(struct ssam_controller *ctrl,
+ struct ssam_nf_refcount_entry *entry, u8 flags)
+{
+ const struct ssam_event_registry reg = entry->key.reg;
+ const struct ssam_event_id id = entry->key.id;
+ struct ssam_nf *nf = &ctrl->cplt.event.notif;
+ int status;
+
+ lockdep_assert_held(&nf->lock);
+
+ ssam_dbg(ctrl, "enabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n",
+ reg.target_category, id.target_category, id.instance, entry->refcount);
+
+ if (entry->refcount == 1) {
+ status = ssam_ssh_event_enable(ctrl, reg, id, flags);
+ if (status)
+ return status;
+
+ entry->flags = flags;
+
+ } else if (entry->flags != flags) {
+ ssam_warn(ctrl,
+ "inconsistent flags when enabling event: got %#04x, expected %#04x (reg: %#04x, tc: %#04x, iid: %#04x)\n",
+ flags, entry->flags, reg.target_category, id.target_category,
+ id.instance);
+ }
+
+ return 0;
+}
+
+/**
+ * ssam_nf_refcount_disable_free() - Disable event for reference count entry if it is
+ * no longer in use and free the corresponding entry.
+ * @ctrl: The controller to disable the event on.
+ * @entry: The reference count entry for the event to be disabled.
+ * @flags: The flags used for enabling the event on the EC.
+ *
+ * If the reference count equals zero, i.e. the event is no longer requested by
+ * any client, the event will be disabled and the corresponding reference count
+ * entry freed. The reference count entry must not be used any more after a
+ * call to this function.
+ *
+ * Also checks if the flags used for disabling the event match the flags used
+ * for enabling the event and warns if they do not (regardless of reference
+ * count).
+ *
+ * This does not modify the reference count itself, which is done with
+ * ssam_nf_refcount_inc() / ssam_nf_refcount_dec().
+ *
+ * Note: ``nf->lock`` must be held when calling this function.
+ *
+ * Return: Returns zero on success. If the event is disabled by this call,
+ * returns the status of the event-enable EC command.
+ */
+static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl,
+ struct ssam_nf_refcount_entry *entry, u8 flags)
+{
+ const struct ssam_event_registry reg = entry->key.reg;
+ const struct ssam_event_id id = entry->key.id;
+ struct ssam_nf *nf = &ctrl->cplt.event.notif;
+ int status = 0;
+
+ lockdep_assert_held(&nf->lock);
+
+ ssam_dbg(ctrl, "disabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n",
+ reg.target_category, id.target_category, id.instance, entry->refcount);
+
+ if (entry->flags != flags) {
+ ssam_warn(ctrl,
+ "inconsistent flags when disabling event: got %#04x, expected %#04x (reg: %#04x, tc: %#04x, iid: %#04x)\n",
+ flags, entry->flags, reg.target_category, id.target_category,
+ id.instance);
+ }
+
+ if (entry->refcount == 0) {
+ status = ssam_ssh_event_disable(ctrl, reg, id, flags);
+ kfree(entry);
+ }
+
+ return status;
+}
+
+/**
* ssam_notifier_register() - Register an event notifier.
* @ctrl: The controller to register the notifier on.
* @n: The event notifier to register.
*
- * Register an event notifier and increment the usage counter of the
- * associated SAM event. If the event was previously not enabled, it will be
- * enabled during this call.
+ * Register an event notifier. Increment the usage counter of the associated
+ * SAM event if the notifier is not marked as an observer. If the event is not
+ * marked as an observer and is currently not enabled, it will be enabled
+ * during this call. If the notifier is marked as an observer, no attempt will
+ * be made at enabling any event and no reference count will be modified.
+ *
+ * Notifiers marked as observers do not need to be associated with one specific
+ * event, i.e. as long as no event matching is performed, only the event target
+ * category needs to be set.
*
* Return: Returns zero on success, %-ENOSPC if there have already been
* %INT_MAX notifiers for the event ID/type associated with the notifier block
@@ -2138,11 +2272,10 @@ int ssam_ctrl_notif_d0_entry(struct ssam_controller *ctrl)
* for the specific associated event, returns the status of the event-enable
* EC-command.
*/
-int ssam_notifier_register(struct ssam_controller *ctrl,
- struct ssam_event_notifier *n)
+int ssam_notifier_register(struct ssam_controller *ctrl, struct ssam_event_notifier *n)
{
u16 rqid = ssh_tc_to_rqid(n->event.id.target_category);
- struct ssam_nf_refcount_entry *entry;
+ struct ssam_nf_refcount_entry *entry = NULL;
struct ssam_nf_head *nf_head;
struct ssam_nf *nf;
int status;
@@ -2155,44 +2288,32 @@ int ssam_notifier_register(struct ssam_controller *ctrl,
mutex_lock(&nf->lock);
- entry = ssam_nf_refcount_inc(nf, n->event.reg, n->event.id);
- if (IS_ERR(entry)) {
- mutex_unlock(&nf->lock);
- return PTR_ERR(entry);
+ if (!(n->flags & SSAM_EVENT_NOTIFIER_OBSERVER)) {
+ entry = ssam_nf_refcount_inc(nf, n->event.reg, n->event.id);
+ if (IS_ERR(entry)) {
+ mutex_unlock(&nf->lock);
+ return PTR_ERR(entry);
+ }
}
- ssam_dbg(ctrl, "enabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n",
- n->event.reg.target_category, n->event.id.target_category,
- n->event.id.instance, entry->refcount);
-
status = ssam_nfblk_insert(nf_head, &n->base);
if (status) {
- entry = ssam_nf_refcount_dec(nf, n->event.reg, n->event.id);
- if (entry->refcount == 0)
- kfree(entry);
+ if (entry)
+ ssam_nf_refcount_dec_free(nf, n->event.reg, n->event.id);
mutex_unlock(&nf->lock);
return status;
}
- if (entry->refcount == 1) {
- status = ssam_ssh_event_enable(ctrl, n->event.reg, n->event.id,
- n->event.flags);
+ if (entry) {
+ status = ssam_nf_refcount_enable(ctrl, entry, n->event.flags);
if (status) {
ssam_nfblk_remove(&n->base);
- kfree(ssam_nf_refcount_dec(nf, n->event.reg, n->event.id));
+ ssam_nf_refcount_dec_free(nf, n->event.reg, n->event.id);
mutex_unlock(&nf->lock);
synchronize_srcu(&nf_head->srcu);
return status;
}
-
- entry->flags = n->event.flags;
-
- } else if (entry->flags != n->event.flags) {
- ssam_warn(ctrl,
- "inconsistent flags when enabling event: got %#04x, expected %#04x (reg: %#04x, tc: %#04x, iid: %#04x)\n",
- n->event.flags, entry->flags, n->event.reg.target_category,
- n->event.id.target_category, n->event.id.instance);
}
mutex_unlock(&nf->lock);
@@ -2205,17 +2326,16 @@ EXPORT_SYMBOL_GPL(ssam_notifier_register);
* @ctrl: The controller the notifier has been registered on.
* @n: The event notifier to unregister.
*
- * Unregister an event notifier and decrement the usage counter of the
- * associated SAM event. If the usage counter reaches zero, the event will be
- * disabled.
+ * Unregister an event notifier. Decrement the usage counter of the associated
+ * SAM event if the notifier is not marked as an observer. If the usage counter
+ * reaches zero, the event will be disabled.
*
* Return: Returns zero on success, %-ENOENT if the given notifier block has
* not been registered on the controller. If the given notifier block was the
* last one associated with its specific event, returns the status of the
* event-disable EC-command.
*/
-int ssam_notifier_unregister(struct ssam_controller *ctrl,
- struct ssam_event_notifier *n)
+int ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_notifier *n)
{
u16 rqid = ssh_tc_to_rqid(n->event.id.target_category);
struct ssam_nf_refcount_entry *entry;
@@ -2236,33 +2356,24 @@ int ssam_notifier_unregister(struct ssam_controller *ctrl,
return -ENOENT;
}
- entry = ssam_nf_refcount_dec(nf, n->event.reg, n->event.id);
- if (WARN_ON(!entry)) {
- /*
- * If this does not return an entry, there's a logic error
- * somewhere: The notifier block is registered, but the event
- * refcount entry is not there. Remove the notifier block
- * anyways.
- */
- status = -ENOENT;
- goto remove;
- }
-
- ssam_dbg(ctrl, "disabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n",
- n->event.reg.target_category, n->event.id.target_category,
- n->event.id.instance, entry->refcount);
-
- if (entry->flags != n->event.flags) {
- ssam_warn(ctrl,
- "inconsistent flags when disabling event: got %#04x, expected %#04x (reg: %#04x, tc: %#04x, iid: %#04x)\n",
- n->event.flags, entry->flags, n->event.reg.target_category,
- n->event.id.target_category, n->event.id.instance);
- }
+ /*
+ * If this is an observer notifier, do not attempt to disable the
+ * event, just remove it.
+ */
+ if (!(n->flags & SSAM_EVENT_NOTIFIER_OBSERVER)) {
+ entry = ssam_nf_refcount_dec(nf, n->event.reg, n->event.id);
+ if (WARN_ON(!entry)) {
+ /*
+ * If this does not return an entry, there's a logic
+ * error somewhere: The notifier block is registered,
+ * but the event refcount entry is not there. Remove
+ * the notifier block anyways.
+ */
+ status = -ENOENT;
+ goto remove;
+ }
- if (entry->refcount == 0) {
- status = ssam_ssh_event_disable(ctrl, n->event.reg, n->event.id,
- n->event.flags);
- kfree(entry);
+ status = ssam_nf_refcount_disable_free(ctrl, entry, n->event.flags);
}
remove:
@@ -2275,6 +2386,105 @@ remove:
EXPORT_SYMBOL_GPL(ssam_notifier_unregister);
/**
+ * ssam_controller_event_enable() - Enable the specified event.
+ * @ctrl: The controller to enable the event for.
+ * @reg: The event registry to use for enabling the event.
+ * @id: The event ID specifying the event to be enabled.
+ * @flags: The SAM event flags used for enabling the event.
+ *
+ * Increment the event reference count of the specified event. If the event has
+ * not been enabled previously, it will be enabled by this call.
+ *
+ * Note: In general, ssam_notifier_register() with a non-observer notifier
+ * should be preferred for enabling/disabling events, as this will guarantee
+ * proper ordering and event forwarding in case of errors during event
+ * enabling/disabling.
+ *
+ * Return: Returns zero on success, %-ENOSPC if the reference count for the
+ * specified event has reached its maximum, %-ENOMEM if the corresponding event
+ * entry could not be allocated. If this is the first time that this event has
+ * been enabled (i.e. the reference count was incremented from zero to one by
+ * this call), returns the status of the event-enable EC-command.
+ */
+int ssam_controller_event_enable(struct ssam_controller *ctrl,
+ struct ssam_event_registry reg,
+ struct ssam_event_id id, u8 flags)
+{
+ u16 rqid = ssh_tc_to_rqid(id.target_category);
+ struct ssam_nf *nf = &ctrl->cplt.event.notif;
+ struct ssam_nf_refcount_entry *entry;
+ int status;
+
+ if (!ssh_rqid_is_event(rqid))
+ return -EINVAL;
+
+ mutex_lock(&nf->lock);
+
+ entry = ssam_nf_refcount_inc(nf, reg, id);
+ if (IS_ERR(entry)) {
+ mutex_unlock(&nf->lock);
+ return PTR_ERR(entry);
+ }
+
+ status = ssam_nf_refcount_enable(ctrl, entry, flags);
+ if (status) {
+ ssam_nf_refcount_dec_free(nf, reg, id);
+ mutex_unlock(&nf->lock);
+ return status;
+ }
+
+ mutex_unlock(&nf->lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ssam_controller_event_enable);
+
+/**
+ * ssam_controller_event_disable() - Disable the specified event.
+ * @ctrl: The controller to disable the event for.
+ * @reg: The event registry to use for disabling the event.
+ * @id: The event ID specifying the event to be disabled.
+ * @flags: The flags used when enabling the event.
+ *
+ * Decrement the reference count of the specified event. If the reference count
+ * reaches zero, the event will be disabled.
+ *
+ * Note: In general, ssam_notifier_register()/ssam_notifier_unregister() with a
+ * non-observer notifier should be preferred for enabling/disabling events, as
+ * this will guarantee proper ordering and event forwarding in case of errors
+ * during event enabling/disabling.
+ *
+ * Return: Returns zero on success, %-ENOENT if the given event has not been
+ * enabled on the controller. If the reference count of the event reaches zero
+ * during this call, returns the status of the event-disable EC-command.
+ */
+int ssam_controller_event_disable(struct ssam_controller *ctrl,
+ struct ssam_event_registry reg,
+ struct ssam_event_id id, u8 flags)
+{
+ u16 rqid = ssh_tc_to_rqid(id.target_category);
+ struct ssam_nf *nf = &ctrl->cplt.event.notif;
+ struct ssam_nf_refcount_entry *entry;
+ int status;
+
+ if (!ssh_rqid_is_event(rqid))
+ return -EINVAL;
+
+ mutex_lock(&nf->lock);
+
+ entry = ssam_nf_refcount_dec(nf, reg, id);
+ if (!entry) {
+ mutex_unlock(&nf->lock);
+ return -ENOENT;
+ }
+
+ status = ssam_nf_refcount_disable_free(ctrl, entry, flags);
+
+ mutex_unlock(&nf->lock);
+ return status;
+}
+EXPORT_SYMBOL_GPL(ssam_controller_event_disable);
+
+/**
* ssam_notifier_disable_registered() - Disable events for all registered
* notifiers.
* @ctrl: The controller for which to disable the notifiers/events.
diff --git a/drivers/platform/surface/aggregator/controller.h b/drivers/platform/surface/aggregator/controller.h
index 8297d34e7489..a0963c3562ff 100644
--- a/drivers/platform/surface/aggregator/controller.h
+++ b/drivers/platform/surface/aggregator/controller.h
@@ -2,7 +2,7 @@
/*
* Main SSAM/SSH controller structure and functionality.
*
- * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+ * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#ifndef _SURFACE_AGGREGATOR_CONTROLLER_H
diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
index 8dc2c267bcd6..279d9df19c01 100644
--- a/drivers/platform/surface/aggregator/core.c
+++ b/drivers/platform/surface/aggregator/core.c
@@ -7,7 +7,7 @@
* Handles communication via requests as well as enabling, disabling, and
* relaying of events.
*
- * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+ * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#include <linux/acpi.h>
@@ -621,8 +621,8 @@ static const struct acpi_gpio_mapping ssam_acpi_gpios[] = {
static int ssam_serial_hub_probe(struct serdev_device *serdev)
{
+ struct acpi_device *ssh = ACPI_COMPANION(&serdev->dev);
struct ssam_controller *ctrl;
- acpi_handle *ssh = ACPI_HANDLE(&serdev->dev);
acpi_status astatus;
int status;
@@ -652,7 +652,7 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
if (status)
goto err_devopen;
- astatus = ssam_serdev_setup_via_acpi(ssh, serdev);
+ astatus = ssam_serdev_setup_via_acpi(ssh->handle, serdev);
if (ACPI_FAILURE(astatus)) {
status = -ENXIO;
goto err_devinit;
@@ -706,7 +706,7 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
* For now let's thus default power/wakeup to false.
*/
device_set_wakeup_capable(&serdev->dev, true);
- acpi_walk_dep_device_list(ssh);
+ acpi_dev_clear_dependencies(ssh);
return 0;
diff --git a/drivers/platform/surface/aggregator/ssh_msgb.h b/drivers/platform/surface/aggregator/ssh_msgb.h
index 1221f642dda1..e562958ffdf0 100644
--- a/drivers/platform/surface/aggregator/ssh_msgb.h
+++ b/drivers/platform/surface/aggregator/ssh_msgb.h
@@ -2,7 +2,7 @@
/*
* SSH message builder functions.
*
- * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+ * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#ifndef _SURFACE_AGGREGATOR_SSH_MSGB_H
diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c
index 15d96eac6811..8a4451c1ffe5 100644
--- a/drivers/platform/surface/aggregator/ssh_packet_layer.c
+++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c
@@ -2,7 +2,7 @@
/*
* SSH packet transport layer.
*
- * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+ * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#include <asm/unaligned.h>
@@ -1567,9 +1567,7 @@ static void ssh_ptl_timeout_reap(struct work_struct *work)
clear_bit(SSH_PACKET_SF_PENDING_BIT, &p->state);
atomic_dec(&ptl->pending.count);
- list_del(&p->pending_node);
-
- list_add_tail(&p->pending_node, &claimed);
+ list_move_tail(&p->pending_node, &claimed);
}
spin_unlock(&ptl->pending.lock);
@@ -1957,8 +1955,7 @@ void ssh_ptl_shutdown(struct ssh_ptl *ptl)
smp_mb__before_atomic();
clear_bit(SSH_PACKET_SF_QUEUED_BIT, &p->state);
- list_del(&p->queue_node);
- list_add_tail(&p->queue_node, &complete_q);
+ list_move_tail(&p->queue_node, &complete_q);
}
spin_unlock(&ptl->queue.lock);
@@ -1970,8 +1967,7 @@ void ssh_ptl_shutdown(struct ssh_ptl *ptl)
smp_mb__before_atomic();
clear_bit(SSH_PACKET_SF_PENDING_BIT, &p->state);
- list_del(&p->pending_node);
- list_add_tail(&p->pending_node, &complete_q);
+ list_move_tail(&p->pending_node, &complete_q);
}
atomic_set(&ptl->pending.count, 0);
spin_unlock(&ptl->pending.lock);
diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.h b/drivers/platform/surface/aggregator/ssh_packet_layer.h
index e8757d03f279..2eb329f0b91a 100644
--- a/drivers/platform/surface/aggregator/ssh_packet_layer.h
+++ b/drivers/platform/surface/aggregator/ssh_packet_layer.h
@@ -2,7 +2,7 @@
/*
* SSH packet transport layer.
*
- * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+ * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#ifndef _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H
diff --git a/drivers/platform/surface/aggregator/ssh_parser.c b/drivers/platform/surface/aggregator/ssh_parser.c
index e2dead8de94a..b77912f8f13b 100644
--- a/drivers/platform/surface/aggregator/ssh_parser.c
+++ b/drivers/platform/surface/aggregator/ssh_parser.c
@@ -2,7 +2,7 @@
/*
* SSH message parser.
*
- * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+ * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#include <asm/unaligned.h>
diff --git a/drivers/platform/surface/aggregator/ssh_parser.h b/drivers/platform/surface/aggregator/ssh_parser.h
index 63c38d350988..3bd6e180fd16 100644
--- a/drivers/platform/surface/aggregator/ssh_parser.h
+++ b/drivers/platform/surface/aggregator/ssh_parser.h
@@ -2,7 +2,7 @@
/*
* SSH message parser.
*
- * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+ * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#ifndef _SURFACE_AGGREGATOR_SSH_PARSER_H
diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c
index 52a83a8fcf82..790f7f0eee98 100644
--- a/drivers/platform/surface/aggregator/ssh_request_layer.c
+++ b/drivers/platform/surface/aggregator/ssh_request_layer.c
@@ -2,7 +2,7 @@
/*
* SSH request transport layer.
*
- * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+ * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#include <asm/unaligned.h>
@@ -863,9 +863,7 @@ static void ssh_rtl_timeout_reap(struct work_struct *work)
clear_bit(SSH_REQUEST_SF_PENDING_BIT, &r->state);
atomic_dec(&rtl->pending.count);
- list_del(&r->node);
-
- list_add_tail(&r->node, &claimed);
+ list_move_tail(&r->node, &claimed);
}
spin_unlock(&rtl->pending.lock);
@@ -1204,8 +1202,7 @@ void ssh_rtl_shutdown(struct ssh_rtl *rtl)
smp_mb__before_atomic();
clear_bit(SSH_REQUEST_SF_QUEUED_BIT, &r->state);
- list_del(&r->node);
- list_add_tail(&r->node, &claimed);
+ list_move_tail(&r->node, &claimed);
}
spin_unlock(&rtl->queue.lock);
@@ -1238,8 +1235,7 @@ void ssh_rtl_shutdown(struct ssh_rtl *rtl)
smp_mb__before_atomic();
clear_bit(SSH_REQUEST_SF_PENDING_BIT, &r->state);
- list_del(&r->node);
- list_add_tail(&r->node, &claimed);
+ list_move_tail(&r->node, &claimed);
}
spin_unlock(&rtl->pending.lock);
}
diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.h b/drivers/platform/surface/aggregator/ssh_request_layer.h
index cb35815858d1..9c3cbae2d4bd 100644
--- a/drivers/platform/surface/aggregator/ssh_request_layer.h
+++ b/drivers/platform/surface/aggregator/ssh_request_layer.h
@@ -2,7 +2,7 @@
/*
* SSH request transport layer.
*
- * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+ * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#ifndef _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H
diff --git a/drivers/platform/surface/aggregator/trace.h b/drivers/platform/surface/aggregator/trace.h
index eb332bb53ae4..de64cf169060 100644
--- a/drivers/platform/surface/aggregator/trace.h
+++ b/drivers/platform/surface/aggregator/trace.h
@@ -2,7 +2,7 @@
/*
* Trace points for SSAM/SSH.
*
- * Copyright (C) 2020 Maximilian Luz <luzmaximilian@gmail.com>
+ * Copyright (C) 2020-2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#undef TRACE_SYSTEM
diff --git a/drivers/platform/surface/surface3_power.c b/drivers/platform/surface/surface3_power.c
index cc4f9cba6856..dea82aa1abd4 100644
--- a/drivers/platform/surface/surface3_power.c
+++ b/drivers/platform/surface/surface3_power.c
@@ -446,12 +446,12 @@ mshw0011_space_handler(u32 function, acpi_physical_address command,
static int mshw0011_install_space_handler(struct i2c_client *client)
{
- acpi_handle handle;
+ struct acpi_device *adev;
struct mshw0011_handler_data *data;
acpi_status status;
- handle = ACPI_HANDLE(&client->dev);
- if (!handle)
+ adev = ACPI_COMPANION(&client->dev);
+ if (!adev)
return -ENODEV;
data = kzalloc(sizeof(struct mshw0011_handler_data),
@@ -460,25 +460,25 @@ static int mshw0011_install_space_handler(struct i2c_client *client)
return -ENOMEM;
data->client = client;
- status = acpi_bus_attach_private_data(handle, (void *)data);
+ status = acpi_bus_attach_private_data(adev->handle, (void *)data);
if (ACPI_FAILURE(status)) {
kfree(data);
return -ENOMEM;
}
- status = acpi_install_address_space_handler(handle,
- ACPI_ADR_SPACE_GSBUS,
- &mshw0011_space_handler,
- NULL,
- data);
+ status = acpi_install_address_space_handler(adev->handle,
+ ACPI_ADR_SPACE_GSBUS,
+ &mshw0011_space_handler,
+ NULL,
+ data);
if (ACPI_FAILURE(status)) {
dev_err(&client->dev, "Error installing i2c space handler\n");
- acpi_bus_detach_private_data(handle);
+ acpi_bus_detach_private_data(adev->handle);
kfree(data);
return -ENOMEM;
}
- acpi_walk_dep_device_list(handle);
+ acpi_dev_clear_dependencies(adev);
return 0;
}
diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c
index ef9c1f8e8336..8339988d95c1 100644
--- a/drivers/platform/surface/surface_acpi_notify.c
+++ b/drivers/platform/surface/surface_acpi_notify.c
@@ -798,7 +798,7 @@ static int san_consumer_links_setup(struct platform_device *pdev)
static int san_probe(struct platform_device *pdev)
{
- acpi_handle san = ACPI_HANDLE(&pdev->dev);
+ struct acpi_device *san = ACPI_COMPANION(&pdev->dev);
struct ssam_controller *ctrl;
struct san_data *data;
acpi_status astatus;
@@ -821,7 +821,8 @@ static int san_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
- astatus = acpi_install_address_space_handler(san, ACPI_ADR_SPACE_GSBUS,
+ astatus = acpi_install_address_space_handler(san->handle,
+ ACPI_ADR_SPACE_GSBUS,
&san_opreg_handler, NULL,
&data->info);
if (ACPI_FAILURE(astatus))
@@ -835,7 +836,7 @@ static int san_probe(struct platform_device *pdev)
if (status)
goto err_install_dev;
- acpi_walk_dep_device_list(san);
+ acpi_dev_clear_dependencies(san);
return 0;
err_install_dev:
diff --git a/drivers/platform/surface/surface_aggregator_cdev.c b/drivers/platform/surface/surface_aggregator_cdev.c
index 79e28fab7e40..30fb50fde450 100644
--- a/drivers/platform/surface/surface_aggregator_cdev.c
+++ b/drivers/platform/surface/surface_aggregator_cdev.c
@@ -3,29 +3,69 @@
* Provides user-space access to the SSAM EC via the /dev/surface/aggregator
* misc device. Intended for debugging and development.
*
- * Copyright (C) 2020 Maximilian Luz <luzmaximilian@gmail.com>
+ * Copyright (C) 2020-2021 Maximilian Luz <luzmaximilian@gmail.com>
*/
#include <linux/fs.h>
+#include <linux/ioctl.h>
#include <linux/kernel.h>
+#include <linux/kfifo.h>
#include <linux/kref.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/poll.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
#include <linux/surface_aggregator/cdev.h>
#include <linux/surface_aggregator/controller.h>
+#include <linux/surface_aggregator/serial_hub.h>
#define SSAM_CDEV_DEVICE_NAME "surface_aggregator_cdev"
+
+/* -- Main structures. ------------------------------------------------------ */
+
+enum ssam_cdev_device_state {
+ SSAM_CDEV_DEVICE_SHUTDOWN_BIT = BIT(0),
+};
+
struct ssam_cdev {
struct kref kref;
struct rw_semaphore lock;
+
+ struct device *dev;
struct ssam_controller *ctrl;
struct miscdevice mdev;
+ unsigned long flags;
+
+ struct rw_semaphore client_lock; /* Guards client list. */
+ struct list_head client_list;
+};
+
+struct ssam_cdev_client;
+
+struct ssam_cdev_notifier {
+ struct ssam_cdev_client *client;
+ struct ssam_event_notifier nf;
+};
+
+struct ssam_cdev_client {
+ struct ssam_cdev *cdev;
+ struct list_head node;
+
+ struct mutex notifier_lock; /* Guards notifier access for registration */
+ struct ssam_cdev_notifier *notifier[SSH_NUM_EVENTS];
+
+ struct mutex read_lock; /* Guards FIFO buffer read access */
+ struct mutex write_lock; /* Guards FIFO buffer write access */
+ DECLARE_KFIFO(buffer, u8, 4096);
+
+ wait_queue_head_t waitq;
+ struct fasync_struct *fasync;
};
static void __ssam_cdev_release(struct kref *kref)
@@ -47,24 +87,173 @@ static void ssam_cdev_put(struct ssam_cdev *cdev)
kref_put(&cdev->kref, __ssam_cdev_release);
}
-static int ssam_cdev_device_open(struct inode *inode, struct file *filp)
+
+/* -- Notifier handling. ---------------------------------------------------- */
+
+static u32 ssam_cdev_notifier(struct ssam_event_notifier *nf, const struct ssam_event *in)
{
- struct miscdevice *mdev = filp->private_data;
- struct ssam_cdev *cdev = container_of(mdev, struct ssam_cdev, mdev);
+ struct ssam_cdev_notifier *cdev_nf = container_of(nf, struct ssam_cdev_notifier, nf);
+ struct ssam_cdev_client *client = cdev_nf->client;
+ struct ssam_cdev_event event;
+ size_t n = struct_size(&event, data, in->length);
+
+ /* Translate event. */
+ event.target_category = in->target_category;
+ event.target_id = in->target_id;
+ event.command_id = in->command_id;
+ event.instance_id = in->instance_id;
+ event.length = in->length;
+
+ mutex_lock(&client->write_lock);
+
+ /* Make sure we have enough space. */
+ if (kfifo_avail(&client->buffer) < n) {
+ dev_warn(client->cdev->dev,
+ "buffer full, dropping event (tc: %#04x, tid: %#04x, cid: %#04x, iid: %#04x)\n",
+ in->target_category, in->target_id, in->command_id, in->instance_id);
+ mutex_unlock(&client->write_lock);
+ return 0;
+ }
+
+ /* Copy event header and payload. */
+ kfifo_in(&client->buffer, (const u8 *)&event, struct_size(&event, data, 0));
+ kfifo_in(&client->buffer, &in->data[0], in->length);
+
+ mutex_unlock(&client->write_lock);
+
+ /* Notify waiting readers. */
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
+ wake_up_interruptible(&client->waitq);
- filp->private_data = ssam_cdev_get(cdev);
- return stream_open(inode, filp);
+ /*
+ * Don't mark events as handled, this is the job of a proper driver and
+ * not the debugging interface.
+ */
+ return 0;
}
-static int ssam_cdev_device_release(struct inode *inode, struct file *filp)
+static int ssam_cdev_notifier_register(struct ssam_cdev_client *client, u8 tc, int priority)
{
- ssam_cdev_put(filp->private_data);
- return 0;
+ const u16 rqid = ssh_tc_to_rqid(tc);
+ const u16 event = ssh_rqid_to_event(rqid);
+ struct ssam_cdev_notifier *nf;
+ int status;
+
+ lockdep_assert_held_read(&client->cdev->lock);
+
+ /* Validate notifier target category. */
+ if (!ssh_rqid_is_event(rqid))
+ return -EINVAL;
+
+ mutex_lock(&client->notifier_lock);
+
+ /* Check if the notifier has already been registered. */
+ if (client->notifier[event]) {
+ mutex_unlock(&client->notifier_lock);
+ return -EEXIST;
+ }
+
+ /* Allocate new notifier. */
+ nf = kzalloc(sizeof(*nf), GFP_KERNEL);
+ if (!nf) {
+ mutex_unlock(&client->notifier_lock);
+ return -ENOMEM;
+ }
+
+ /*
+ * Create a dummy notifier with the minimal required fields for
+ * observer registration. Note that we can skip fully specifying event
+ * and registry here as we do not need any matching and use silent
+ * registration, which does not enable the corresponding event.
+ */
+ nf->client = client;
+ nf->nf.base.fn = ssam_cdev_notifier;
+ nf->nf.base.priority = priority;
+ nf->nf.event.id.target_category = tc;
+ nf->nf.event.mask = 0; /* Do not do any matching. */
+ nf->nf.flags = SSAM_EVENT_NOTIFIER_OBSERVER;
+
+ /* Register notifier. */
+ status = ssam_notifier_register(client->cdev->ctrl, &nf->nf);
+ if (status)
+ kfree(nf);
+ else
+ client->notifier[event] = nf;
+
+ mutex_unlock(&client->notifier_lock);
+ return status;
+}
+
+static int ssam_cdev_notifier_unregister(struct ssam_cdev_client *client, u8 tc)
+{
+ const u16 rqid = ssh_tc_to_rqid(tc);
+ const u16 event = ssh_rqid_to_event(rqid);
+ int status;
+
+ lockdep_assert_held_read(&client->cdev->lock);
+
+ /* Validate notifier target category. */
+ if (!ssh_rqid_is_event(rqid))
+ return -EINVAL;
+
+ mutex_lock(&client->notifier_lock);
+
+ /* Check if the notifier is currently registered. */
+ if (!client->notifier[event]) {
+ mutex_unlock(&client->notifier_lock);
+ return -ENOENT;
+ }
+
+ /* Unregister and free notifier. */
+ status = ssam_notifier_unregister(client->cdev->ctrl, &client->notifier[event]->nf);
+ kfree(client->notifier[event]);
+ client->notifier[event] = NULL;
+
+ mutex_unlock(&client->notifier_lock);
+ return status;
+}
+
+static void ssam_cdev_notifier_unregister_all(struct ssam_cdev_client *client)
+{
+ int i;
+
+ down_read(&client->cdev->lock);
+
+ /*
+ * This function may be used during shutdown, thus we need to test for
+ * cdev->ctrl instead of the SSAM_CDEV_DEVICE_SHUTDOWN_BIT bit.
+ */
+ if (client->cdev->ctrl) {
+ for (i = 0; i < SSH_NUM_EVENTS; i++)
+ ssam_cdev_notifier_unregister(client, i + 1);
+
+ } else {
+ int count = 0;
+
+ /*
+ * Device has been shut down. Any notifier remaining is a bug,
+ * so warn about that as this would otherwise hardly be
+ * noticeable. Nevertheless, free them as well.
+ */
+ mutex_lock(&client->notifier_lock);
+ for (i = 0; i < SSH_NUM_EVENTS; i++) {
+ count += !!(client->notifier[i]);
+ kfree(client->notifier[i]);
+ client->notifier[i] = NULL;
+ }
+ mutex_unlock(&client->notifier_lock);
+
+ WARN_ON(count > 0);
+ }
+
+ up_read(&client->cdev->lock);
}
-static long ssam_cdev_request(struct ssam_cdev *cdev, unsigned long arg)
+
+/* -- IOCTL functions. ------------------------------------------------------ */
+
+static long ssam_cdev_request(struct ssam_cdev_client *client, struct ssam_cdev_request __user *r)
{
- struct ssam_cdev_request __user *r;
struct ssam_cdev_request rqst;
struct ssam_request spec = {};
struct ssam_response rsp = {};
@@ -72,7 +261,8 @@ static long ssam_cdev_request(struct ssam_cdev *cdev, unsigned long arg)
void __user *rspdata;
int status = 0, ret = 0, tmp;
- r = (struct ssam_cdev_request __user *)arg;
+ lockdep_assert_held_read(&client->cdev->lock);
+
ret = copy_struct_from_user(&rqst, sizeof(rqst), r, sizeof(*r));
if (ret)
goto out;
@@ -152,7 +342,7 @@ static long ssam_cdev_request(struct ssam_cdev *cdev, unsigned long arg)
}
/* Perform request. */
- status = ssam_request_sync(cdev->ctrl, &spec, &rsp);
+ status = ssam_request_sync(client->cdev->ctrl, &spec, &rsp);
if (status)
goto out;
@@ -177,48 +367,315 @@ out:
return ret;
}
-static long __ssam_cdev_device_ioctl(struct ssam_cdev *cdev, unsigned int cmd,
+static long ssam_cdev_notif_register(struct ssam_cdev_client *client,
+ const struct ssam_cdev_notifier_desc __user *d)
+{
+ struct ssam_cdev_notifier_desc desc;
+ long ret;
+
+ lockdep_assert_held_read(&client->cdev->lock);
+
+ ret = copy_struct_from_user(&desc, sizeof(desc), d, sizeof(*d));
+ if (ret)
+ return ret;
+
+ return ssam_cdev_notifier_register(client, desc.target_category, desc.priority);
+}
+
+static long ssam_cdev_notif_unregister(struct ssam_cdev_client *client,
+ const struct ssam_cdev_notifier_desc __user *d)
+{
+ struct ssam_cdev_notifier_desc desc;
+ long ret;
+
+ lockdep_assert_held_read(&client->cdev->lock);
+
+ ret = copy_struct_from_user(&desc, sizeof(desc), d, sizeof(*d));
+ if (ret)
+ return ret;
+
+ return ssam_cdev_notifier_unregister(client, desc.target_category);
+}
+
+static long ssam_cdev_event_enable(struct ssam_cdev_client *client,
+ const struct ssam_cdev_event_desc __user *d)
+{
+ struct ssam_cdev_event_desc desc;
+ struct ssam_event_registry reg;
+ struct ssam_event_id id;
+ long ret;
+
+ lockdep_assert_held_read(&client->cdev->lock);
+
+ /* Read descriptor from user-space. */
+ ret = copy_struct_from_user(&desc, sizeof(desc), d, sizeof(*d));
+ if (ret)
+ return ret;
+
+ /* Translate descriptor. */
+ reg.target_category = desc.reg.target_category;
+ reg.target_id = desc.reg.target_id;
+ reg.cid_enable = desc.reg.cid_enable;
+ reg.cid_disable = desc.reg.cid_disable;
+
+ id.target_category = desc.id.target_category;
+ id.instance = desc.id.instance;
+
+ /* Disable event. */
+ return ssam_controller_event_enable(client->cdev->ctrl, reg, id, desc.flags);
+}
+
+static long ssam_cdev_event_disable(struct ssam_cdev_client *client,
+ const struct ssam_cdev_event_desc __user *d)
+{
+ struct ssam_cdev_event_desc desc;
+ struct ssam_event_registry reg;
+ struct ssam_event_id id;
+ long ret;
+
+ lockdep_assert_held_read(&client->cdev->lock);
+
+ /* Read descriptor from user-space. */
+ ret = copy_struct_from_user(&desc, sizeof(desc), d, sizeof(*d));
+ if (ret)
+ return ret;
+
+ /* Translate descriptor. */
+ reg.target_category = desc.reg.target_category;
+ reg.target_id = desc.reg.target_id;
+ reg.cid_enable = desc.reg.cid_enable;
+ reg.cid_disable = desc.reg.cid_disable;
+
+ id.target_category = desc.id.target_category;
+ id.instance = desc.id.instance;
+
+ /* Disable event. */
+ return ssam_controller_event_disable(client->cdev->ctrl, reg, id, desc.flags);
+}
+
+
+/* -- File operations. ------------------------------------------------------ */
+
+static int ssam_cdev_device_open(struct inode *inode, struct file *filp)
+{
+ struct miscdevice *mdev = filp->private_data;
+ struct ssam_cdev_client *client;
+ struct ssam_cdev *cdev = container_of(mdev, struct ssam_cdev, mdev);
+
+ /* Initialize client */
+ client = vzalloc(sizeof(*client));
+ if (!client)
+ return -ENOMEM;
+
+ client->cdev = ssam_cdev_get(cdev);
+
+ INIT_LIST_HEAD(&client->node);
+
+ mutex_init(&client->notifier_lock);
+
+ mutex_init(&client->read_lock);
+ mutex_init(&client->write_lock);
+ INIT_KFIFO(client->buffer);
+ init_waitqueue_head(&client->waitq);
+
+ filp->private_data = client;
+
+ /* Attach client. */
+ down_write(&cdev->client_lock);
+
+ if (test_bit(SSAM_CDEV_DEVICE_SHUTDOWN_BIT, &cdev->flags)) {
+ up_write(&cdev->client_lock);
+ mutex_destroy(&client->write_lock);
+ mutex_destroy(&client->read_lock);
+ mutex_destroy(&client->notifier_lock);
+ ssam_cdev_put(client->cdev);
+ vfree(client);
+ return -ENODEV;
+ }
+ list_add_tail(&client->node, &cdev->client_list);
+
+ up_write(&cdev->client_lock);
+
+ stream_open(inode, filp);
+ return 0;
+}
+
+static int ssam_cdev_device_release(struct inode *inode, struct file *filp)
+{
+ struct ssam_cdev_client *client = filp->private_data;
+
+ /* Force-unregister all remaining notifiers of this client. */
+ ssam_cdev_notifier_unregister_all(client);
+
+ /* Detach client. */
+ down_write(&client->cdev->client_lock);
+ list_del(&client->node);
+ up_write(&client->cdev->client_lock);
+
+ /* Free client. */
+ mutex_destroy(&client->write_lock);
+ mutex_destroy(&client->read_lock);
+
+ mutex_destroy(&client->notifier_lock);
+
+ ssam_cdev_put(client->cdev);
+ vfree(client);
+
+ return 0;
+}
+
+static long __ssam_cdev_device_ioctl(struct ssam_cdev_client *client, unsigned int cmd,
unsigned long arg)
{
+ lockdep_assert_held_read(&client->cdev->lock);
+
switch (cmd) {
case SSAM_CDEV_REQUEST:
- return ssam_cdev_request(cdev, arg);
+ return ssam_cdev_request(client, (struct ssam_cdev_request __user *)arg);
+
+ case SSAM_CDEV_NOTIF_REGISTER:
+ return ssam_cdev_notif_register(client,
+ (struct ssam_cdev_notifier_desc __user *)arg);
+
+ case SSAM_CDEV_NOTIF_UNREGISTER:
+ return ssam_cdev_notif_unregister(client,
+ (struct ssam_cdev_notifier_desc __user *)arg);
+
+ case SSAM_CDEV_EVENT_ENABLE:
+ return ssam_cdev_event_enable(client, (struct ssam_cdev_event_desc __user *)arg);
+
+ case SSAM_CDEV_EVENT_DISABLE:
+ return ssam_cdev_event_disable(client, (struct ssam_cdev_event_desc __user *)arg);
default:
return -ENOTTY;
}
}
-static long ssam_cdev_device_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
+static long ssam_cdev_device_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct ssam_cdev *cdev = file->private_data;
+ struct ssam_cdev_client *client = file->private_data;
long status;
/* Ensure that controller is valid for as long as we need it. */
+ if (down_read_killable(&client->cdev->lock))
+ return -ERESTARTSYS;
+
+ if (test_bit(SSAM_CDEV_DEVICE_SHUTDOWN_BIT, &client->cdev->flags)) {
+ up_read(&client->cdev->lock);
+ return -ENODEV;
+ }
+
+ status = __ssam_cdev_device_ioctl(client, cmd, arg);
+
+ up_read(&client->cdev->lock);
+ return status;
+}
+
+static ssize_t ssam_cdev_read(struct file *file, char __user *buf, size_t count, loff_t *offs)
+{
+ struct ssam_cdev_client *client = file->private_data;
+ struct ssam_cdev *cdev = client->cdev;
+ unsigned int copied;
+ int status = 0;
+
if (down_read_killable(&cdev->lock))
return -ERESTARTSYS;
- if (!cdev->ctrl) {
+ /* Make sure we're not shut down. */
+ if (test_bit(SSAM_CDEV_DEVICE_SHUTDOWN_BIT, &cdev->flags)) {
up_read(&cdev->lock);
return -ENODEV;
}
- status = __ssam_cdev_device_ioctl(cdev, cmd, arg);
+ do {
+ /* Check availability, wait if necessary. */
+ if (kfifo_is_empty(&client->buffer)) {
+ up_read(&cdev->lock);
+
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ status = wait_event_interruptible(client->waitq,
+ !kfifo_is_empty(&client->buffer) ||
+ test_bit(SSAM_CDEV_DEVICE_SHUTDOWN_BIT,
+ &cdev->flags));
+ if (status < 0)
+ return status;
+
+ if (down_read_killable(&cdev->lock))
+ return -ERESTARTSYS;
+
+ /* Need to check that we're not shut down again. */
+ if (test_bit(SSAM_CDEV_DEVICE_SHUTDOWN_BIT, &cdev->flags)) {
+ up_read(&cdev->lock);
+ return -ENODEV;
+ }
+ }
+
+ /* Try to read from FIFO. */
+ if (mutex_lock_interruptible(&client->read_lock)) {
+ up_read(&cdev->lock);
+ return -ERESTARTSYS;
+ }
+
+ status = kfifo_to_user(&client->buffer, buf, count, &copied);
+ mutex_unlock(&client->read_lock);
+
+ if (status < 0) {
+ up_read(&cdev->lock);
+ return status;
+ }
+
+ /* We might not have gotten anything, check this here. */
+ if (copied == 0 && (file->f_flags & O_NONBLOCK)) {
+ up_read(&cdev->lock);
+ return -EAGAIN;
+ }
+ } while (copied == 0);
up_read(&cdev->lock);
- return status;
+ return copied;
+}
+
+static __poll_t ssam_cdev_poll(struct file *file, struct poll_table_struct *pt)
+{
+ struct ssam_cdev_client *client = file->private_data;
+ __poll_t events = 0;
+
+ if (test_bit(SSAM_CDEV_DEVICE_SHUTDOWN_BIT, &client->cdev->flags))
+ return EPOLLHUP | EPOLLERR;
+
+ poll_wait(file, &client->waitq, pt);
+
+ if (!kfifo_is_empty(&client->buffer))
+ events |= EPOLLIN | EPOLLRDNORM;
+
+ return events;
+}
+
+static int ssam_cdev_fasync(int fd, struct file *file, int on)
+{
+ struct ssam_cdev_client *client = file->private_data;
+
+ return fasync_helper(fd, file, on, &client->fasync);
}
static const struct file_operations ssam_controller_fops = {
.owner = THIS_MODULE,
.open = ssam_cdev_device_open,
.release = ssam_cdev_device_release,
+ .read = ssam_cdev_read,
+ .poll = ssam_cdev_poll,
+ .fasync = ssam_cdev_fasync,
.unlocked_ioctl = ssam_cdev_device_ioctl,
.compat_ioctl = ssam_cdev_device_ioctl,
- .llseek = noop_llseek,
+ .llseek = no_llseek,
};
+
+/* -- Device and driver setup ----------------------------------------------- */
+
static int ssam_dbg_device_probe(struct platform_device *pdev)
{
struct ssam_controller *ctrl;
@@ -236,6 +693,7 @@ static int ssam_dbg_device_probe(struct platform_device *pdev)
kref_init(&cdev->kref);
init_rwsem(&cdev->lock);
cdev->ctrl = ctrl;
+ cdev->dev = &pdev->dev;
cdev->mdev.parent = &pdev->dev;
cdev->mdev.minor = MISC_DYNAMIC_MINOR;
@@ -243,6 +701,9 @@ static int ssam_dbg_device_probe(struct platform_device *pdev)
cdev->mdev.nodename = "surface/aggregator";
cdev->mdev.fops = &ssam_controller_fops;
+ init_rwsem(&cdev->client_lock);
+ INIT_LIST_HEAD(&cdev->client_list);
+
status = misc_register(&cdev->mdev);
if (status) {
kfree(cdev);
@@ -256,8 +717,32 @@ static int ssam_dbg_device_probe(struct platform_device *pdev)
static int ssam_dbg_device_remove(struct platform_device *pdev)
{
struct ssam_cdev *cdev = platform_get_drvdata(pdev);
+ struct ssam_cdev_client *client;
- misc_deregister(&cdev->mdev);
+ /*
+ * Mark device as shut-down. Prevent new clients from being added and
+ * new operations from being executed.
+ */
+ set_bit(SSAM_CDEV_DEVICE_SHUTDOWN_BIT, &cdev->flags);
+
+ down_write(&cdev->client_lock);
+
+ /* Remove all notifiers registered by us. */
+ list_for_each_entry(client, &cdev->client_list, node) {
+ ssam_cdev_notifier_unregister_all(client);
+ }
+
+ /* Wake up async clients. */
+ list_for_each_entry(client, &cdev->client_list, node) {
+ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+ }
+
+ /* Wake up blocking clients. */
+ list_for_each_entry(client, &cdev->client_list, node) {
+ wake_up_interruptible(&client->waitq);
+ }
+
+ up_write(&cdev->client_lock);
/*
* The controller is only guaranteed to be valid for as long as the
@@ -266,8 +751,11 @@ static int ssam_dbg_device_remove(struct platform_device *pdev)
*/
down_write(&cdev->lock);
cdev->ctrl = NULL;
+ cdev->dev = NULL;
up_write(&cdev->lock);
+ misc_deregister(&cdev->mdev);
+
ssam_cdev_put(cdev);
return 0;
}
diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
index ef83461fa536..4428c4330229 100644
--- a/drivers/platform/surface/surface_aggregator_registry.c
+++ b/drivers/platform/surface/surface_aggregator_registry.c
@@ -119,8 +119,13 @@ static const struct software_node ssam_node_hid_base_iid6 = {
.parent = &ssam_node_hub_base,
};
-/* Devices for Surface Book 2. */
-static const struct software_node *ssam_node_group_sb2[] = {
+/*
+ * Devices for 5th- and 6th-generations models:
+ * - Surface Book 2,
+ * - Surface Laptop 1 and 2,
+ * - Surface Pro 5 and 6.
+ */
+static const struct software_node *ssam_node_group_gen5[] = {
&ssam_node_root,
&ssam_node_tmp_pprof,
NULL,
@@ -142,20 +147,6 @@ static const struct software_node *ssam_node_group_sb3[] = {
NULL,
};
-/* Devices for Surface Laptop 1. */
-static const struct software_node *ssam_node_group_sl1[] = {
- &ssam_node_root,
- &ssam_node_tmp_pprof,
- NULL,
-};
-
-/* Devices for Surface Laptop 2. */
-static const struct software_node *ssam_node_group_sl2[] = {
- &ssam_node_root,
- &ssam_node_tmp_pprof,
- NULL,
-};
-
/* Devices for Surface Laptop 3 and 4. */
static const struct software_node *ssam_node_group_sl3[] = {
&ssam_node_root,
@@ -177,20 +168,6 @@ static const struct software_node *ssam_node_group_slg1[] = {
NULL,
};
-/* Devices for Surface Pro 5. */
-static const struct software_node *ssam_node_group_sp5[] = {
- &ssam_node_root,
- &ssam_node_tmp_pprof,
- NULL,
-};
-
-/* Devices for Surface Pro 6. */
-static const struct software_node *ssam_node_group_sp6[] = {
- &ssam_node_root,
- &ssam_node_tmp_pprof,
- NULL,
-};
-
/* Devices for Surface Pro 7 and Surface Pro 7+. */
static const struct software_node *ssam_node_group_sp7[] = {
&ssam_node_root,
@@ -495,10 +472,10 @@ static struct ssam_device_driver ssam_base_hub_driver = {
static const struct acpi_device_id ssam_platform_hub_match[] = {
/* Surface Pro 4, 5, and 6 (OMBR < 0x10) */
- { "MSHW0081", (unsigned long)ssam_node_group_sp5 },
+ { "MSHW0081", (unsigned long)ssam_node_group_gen5 },
/* Surface Pro 6 (OMBR >= 0x10) */
- { "MSHW0111", (unsigned long)ssam_node_group_sp6 },
+ { "MSHW0111", (unsigned long)ssam_node_group_gen5 },
/* Surface Pro 7 */
{ "MSHW0116", (unsigned long)ssam_node_group_sp7 },
@@ -507,16 +484,16 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
{ "MSHW0119", (unsigned long)ssam_node_group_sp7 },
/* Surface Book 2 */
- { "MSHW0107", (unsigned long)ssam_node_group_sb2 },
+ { "MSHW0107", (unsigned long)ssam_node_group_gen5 },
/* Surface Book 3 */
{ "MSHW0117", (unsigned long)ssam_node_group_sb3 },
/* Surface Laptop 1 */
- { "MSHW0086", (unsigned long)ssam_node_group_sl1 },
+ { "MSHW0086", (unsigned long)ssam_node_group_gen5 },
/* Surface Laptop 2 */
- { "MSHW0112", (unsigned long)ssam_node_group_sl2 },
+ { "MSHW0112", (unsigned long)ssam_node_group_gen5 },
/* Surface Laptop 3 (13", Intel) */
{ "MSHW0114", (unsigned long)ssam_node_group_sl3 },
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 60592fb88e7a..7d385c3b2239 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -415,16 +415,17 @@ config HP_ACCEL
To compile this driver as a module, choose M here: the module will
be called hp_accel.
-config HP_WIRELESS
- tristate "HP wireless button"
+config WIRELESS_HOTKEY
+ tristate "Wireless hotkey button"
depends on ACPI
depends on INPUT
help
- This driver provides supports for new HP wireless button for Windows 8.
+ This driver provides supports for the wireless buttons found on some AMD,
+ HP, & Xioami laptops.
On such systems the driver should load automatically (via ACPI alias).
To compile this driver as a module, choose M here: the module will
- be called hp-wireless.
+ be called wireless-hotkey.
config HP_WMI
tristate "HP WMI extras"
@@ -639,6 +640,19 @@ config THINKPAD_ACPI_HOTKEY_POLL
If you are not sure, say Y here. The driver enables polling only if
it is strictly necessary to do so.
+config THINKPAD_LMI
+ tristate "Lenovo WMI-based systems management driver"
+ depends on ACPI_WMI
+ select FW_ATTR_CLASS
+ help
+ This driver allows changing BIOS settings on Lenovo machines whose
+ BIOS support the WMI interface.
+
+ To compile this driver as a module, choose M here: the module will
+ be called think-lmi.
+
+source "drivers/platform/x86/intel/Kconfig"
+
config INTEL_ATOMISP2_LED
tristate "Intel AtomISP2 camera LED driver"
depends on GPIOLIB && LEDS_GPIO
@@ -673,30 +687,6 @@ config INTEL_ATOMISP2_PM
To compile this driver as a module, choose M here: the module
will be called intel_atomisp2_pm.
-config INTEL_CHT_INT33FE
- tristate "Intel Cherry Trail ACPI INT33FE Driver"
- depends on X86 && ACPI && I2C && REGULATOR
- depends on CHARGER_BQ24190=y || (CHARGER_BQ24190=m && m)
- depends on USB_ROLES_INTEL_XHCI=y || (USB_ROLES_INTEL_XHCI=m && m)
- depends on TYPEC_MUX_PI3USB30532=y || (TYPEC_MUX_PI3USB30532=m && m)
- help
- This driver add support for the INT33FE ACPI device found on
- some Intel Cherry Trail devices.
-
- There are two kinds of INT33FE ACPI device possible: for hardware
- with USB Type-C and Micro-B connectors. This driver supports both.
-
- The INT33FE ACPI device has a CRS table with I2cSerialBusV2
- resources for Fuel Gauge Controller and (in the Type-C variant)
- FUSB302 USB Type-C Controller and PI3USB30532 USB switch.
- This driver instantiates i2c-clients for these, so that standard
- i2c drivers for these chips can bind to the them.
-
- If you enable this driver it is advised to also select
- CONFIG_BATTERY_BQ27XXX=m or CONFIG_BATTERY_BQ27XXX_I2C=m for Micro-B
- device and CONFIG_TYPEC_FUSB302=m and CONFIG_BATTERY_MAX17042=m
- for Type-C device.
-
config INTEL_HID_EVENT
tristate "INTEL HID Event"
depends on ACPI
@@ -1076,6 +1066,9 @@ config TOUCHSCREEN_DMI
the OS-image for the device. This option supplies the missing info.
Enable this for x86 tablets with Silead or Chipone touchscreens.
+config FW_ATTR_CLASS
+ tristate
+
config INTEL_IMR
bool "Intel Isolated Memory Region support"
depends on X86_INTEL_QUARK && IOSF_MBI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index dcc8cdb95b4d..7ee369aab10d 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -52,7 +52,6 @@ obj-$(CONFIG_GPD_POCKET_FAN) += gpd-pocket-fan.o
# Hewlett Packard
obj-$(CONFIG_HP_ACCEL) += hp_accel.o
-obj-$(CONFIG_HP_WIRELESS) += hp-wireless.o
obj-$(CONFIG_HP_WMI) += hp-wmi.o
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
@@ -64,14 +63,13 @@ obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
+obj-$(CONFIG_THINKPAD_LMI) += think-lmi.o
# Intel
+obj-$(CONFIG_X86_PLATFORM_DRIVERS_INTEL) += intel/
+
obj-$(CONFIG_INTEL_ATOMISP2_LED) += intel_atomisp2_led.o
obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o
-obj-$(CONFIG_INTEL_CHT_INT33FE) += intel_cht_int33fe.o
-intel_cht_int33fe-objs := intel_cht_int33fe_common.o \
- intel_cht_int33fe_typec.o \
- intel_cht_int33fe_microb.o
obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o
obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
@@ -112,9 +110,11 @@ obj-$(CONFIG_SYSTEM76_ACPI) += system76_acpi.o
obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
# Platform drivers
+obj-$(CONFIG_FW_ATTR_CLASS) += firmware_attributes_class.o
obj-$(CONFIG_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o
obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o
+obj-$(CONFIG_WIRELESS_HOTKEY) += wireless-hotkey.o
# Intel uncore drivers
obj-$(CONFIG_INTEL_IPS) += intel_ips.o
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index d41d7ad14be0..0cb927f0f301 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -110,11 +110,6 @@ static struct quirk_entry quirk_asus_forceals = {
.wmi_force_als_set = true,
};
-static struct quirk_entry quirk_asus_vendor_backlight = {
- .wmi_backlight_power = true,
- .wmi_backlight_set_devstate = true,
-};
-
static struct quirk_entry quirk_asus_use_kbd_dock_devid = {
.use_kbd_dock_devid = true,
};
@@ -427,78 +422,6 @@ static const struct dmi_system_id asus_quirks[] = {
},
{
.callback = dmi_matched,
- .ident = "ASUSTeK COMPUTER INC. GA401IH",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "GA401IH"),
- },
- .driver_data = &quirk_asus_vendor_backlight,
- },
- {
- .callback = dmi_matched,
- .ident = "ASUSTeK COMPUTER INC. GA401II",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "GA401II"),
- },
- .driver_data = &quirk_asus_vendor_backlight,
- },
- {
- .callback = dmi_matched,
- .ident = "ASUSTeK COMPUTER INC. GA401IU",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "GA401IU"),
- },
- .driver_data = &quirk_asus_vendor_backlight,
- },
- {
- .callback = dmi_matched,
- .ident = "ASUSTeK COMPUTER INC. GA401IV",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "GA401IV"),
- },
- .driver_data = &quirk_asus_vendor_backlight,
- },
- {
- .callback = dmi_matched,
- .ident = "ASUSTeK COMPUTER INC. GA401IVC",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "GA401IVC"),
- },
- .driver_data = &quirk_asus_vendor_backlight,
- },
- {
- .callback = dmi_matched,
- .ident = "ASUSTeK COMPUTER INC. GA502II",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "GA502II"),
- },
- .driver_data = &quirk_asus_vendor_backlight,
- },
- {
- .callback = dmi_matched,
- .ident = "ASUSTeK COMPUTER INC. GA502IU",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "GA502IU"),
- },
- .driver_data = &quirk_asus_vendor_backlight,
- },
- {
- .callback = dmi_matched,
- .ident = "ASUSTeK COMPUTER INC. GA502IV",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "GA502IV"),
- },
- .driver_data = &quirk_asus_vendor_backlight,
- },
- {
- .callback = dmi_matched,
.ident = "Asus Transformer T100TA / T100HA / T100CHI",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig
index e0a55337f51a..9e7314d90bea 100644
--- a/drivers/platform/x86/dell/Kconfig
+++ b/drivers/platform/x86/dell/Kconfig
@@ -5,7 +5,6 @@
menuconfig X86_PLATFORM_DRIVERS_DELL
bool "Dell X86 Platform Specific Device Drivers"
- default n
depends on X86_PLATFORM_DEVICES
help
Say Y here to get to see options for device drivers for various
@@ -53,6 +52,7 @@ config DELL_LAPTOP
depends on BACKLIGHT_CLASS_DEVICE
depends on ACPI_VIDEO || ACPI_VIDEO = n
depends on RFKILL || RFKILL = n
+ depends on DELL_WMI || DELL_WMI = n
depends on SERIO_I8042
depends on DELL_SMBIOS
select POWER_SUPPLY
@@ -164,6 +164,14 @@ config DELL_WMI
To compile this driver as a module, choose M here: the module will
be called dell-wmi.
+config DELL_WMI_PRIVACY
+ bool "Dell WMI Hardware Privacy Support"
+ depends on DELL_WMI
+ depends on LEDS_TRIGGER_AUDIO
+ help
+ This option adds integration with the "Dell Hardware Privacy"
+ feature of Dell laptops to the dell-wmi driver.
+
config DELL_WMI_AIO
tristate "WMI Hotkeys for Dell All-In-One series"
default m
@@ -197,6 +205,7 @@ config DELL_WMI_SYSMAN
depends on ACPI_WMI
depends on DMI
select NLS
+ select FW_ATTR_CLASS
help
This driver allows changing BIOS settings on many Dell machines from
2018 and newer without the use of any additional software.
diff --git a/drivers/platform/x86/dell/Makefile b/drivers/platform/x86/dell/Makefile
index d720a3e42ae3..ddba1df71e80 100644
--- a/drivers/platform/x86/dell/Makefile
+++ b/drivers/platform/x86/dell/Makefile
@@ -15,6 +15,8 @@ dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o
dell-smbios-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o
obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
obj-$(CONFIG_DELL_WMI) += dell-wmi.o
+dell-wmi-objs := dell-wmi-base.o
+dell-wmi-$(CONFIG_DELL_WMI_PRIVACY) += dell-wmi-privacy.o
obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o
obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
diff --git a/drivers/platform/x86/dell/dcdbas.c b/drivers/platform/x86/dell/dcdbas.c
index d513a59a5d47..28447c180be8 100644
--- a/drivers/platform/x86/dell/dcdbas.c
+++ b/drivers/platform/x86/dell/dcdbas.c
@@ -394,8 +394,7 @@ static int host_control_smi(void)
/* wait a few to see if it executed */
num_ticks = TIMEOUT_USEC_SHORT_SEMA_BLOCKING;
- while ((cmd_status = inb(PCAT_APM_STATUS_PORT))
- == ESM_STATUS_CMD_UNSUCCESSFUL) {
+ while ((s8)inb(PCAT_APM_STATUS_PORT) == ESM_STATUS_CMD_UNSUCCESSFUL) {
num_ticks--;
if (num_ticks == EXPIRED_TIMER)
return -ETIME;
diff --git a/drivers/platform/x86/dell/dell-laptop.c b/drivers/platform/x86/dell/dell-laptop.c
index 70edc5bb3a14..8230e7a68a5e 100644
--- a/drivers/platform/x86/dell/dell-laptop.c
+++ b/drivers/platform/x86/dell/dell-laptop.c
@@ -31,6 +31,8 @@
#include "dell-rbtn.h"
#include "dell-smbios.h"
+#include "dell-wmi-privacy.h"
+
struct quirk_entry {
bool touchpad_led;
bool kbd_led_not_present;
@@ -90,6 +92,7 @@ static struct rfkill *wifi_rfkill;
static struct rfkill *bluetooth_rfkill;
static struct rfkill *wwan_rfkill;
static bool force_rfkill;
+static bool micmute_led_registered;
module_param(force_rfkill, bool, 0444);
MODULE_PARM_DESC(force_rfkill, "enable rfkill on non whitelisted models");
@@ -2205,11 +2208,13 @@ static int __init dell_init(void)
dell_laptop_register_notifier(&dell_laptop_notifier);
if (dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE) &&
- dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE)) {
+ dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE) &&
+ !dell_privacy_has_mic_mute()) {
micmute_led_cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
ret = led_classdev_register(&platform_device->dev, &micmute_led_cdev);
if (ret < 0)
goto fail_led;
+ micmute_led_registered = true;
}
if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
@@ -2257,7 +2262,8 @@ static int __init dell_init(void)
fail_get_brightness:
backlight_device_unregister(dell_backlight_device);
fail_backlight:
- led_classdev_unregister(&micmute_led_cdev);
+ if (micmute_led_registered)
+ led_classdev_unregister(&micmute_led_cdev);
fail_led:
dell_cleanup_rfkill();
fail_rfkill:
@@ -2278,7 +2284,8 @@ static void __exit dell_exit(void)
touchpad_led_exit();
kbd_led_exit();
backlight_device_unregister(dell_backlight_device);
- led_classdev_unregister(&micmute_led_cdev);
+ if (micmute_led_registered)
+ led_classdev_unregister(&micmute_led_cdev);
dell_cleanup_rfkill();
if (platform_device) {
platform_device_unregister(platform_device);
diff --git a/drivers/platform/x86/dell/dell-wmi.c b/drivers/platform/x86/dell/dell-wmi-base.c
index 5e1b7f897df5..089c125e18f7 100644
--- a/drivers/platform/x86/dell/dell-wmi.c
+++ b/drivers/platform/x86/dell/dell-wmi-base.c
@@ -27,6 +27,7 @@
#include <acpi/video.h>
#include "dell-smbios.h"
#include "dell-wmi-descriptor.h"
+#include "dell-wmi-privacy.h"
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
@@ -427,7 +428,6 @@ static void dell_wmi_notify(struct wmi_device *wdev,
switch (buffer_entry[1]) {
case 0x0000: /* One key pressed or event occurred */
- case 0x0012: /* Event with extended data occurred */
if (len > 2)
dell_wmi_process_key(wdev, buffer_entry[1],
buffer_entry[2]);
@@ -439,6 +439,13 @@ static void dell_wmi_notify(struct wmi_device *wdev,
dell_wmi_process_key(wdev, buffer_entry[1],
buffer_entry[i]);
break;
+ case 0x0012:
+ if ((len > 4) && dell_privacy_process_event(buffer_entry[1], buffer_entry[3],
+ buffer_entry[4]))
+ /* dell_privacy_process_event has handled the event */;
+ else if (len > 2)
+ dell_wmi_process_key(wdev, buffer_entry[1], buffer_entry[2]);
+ break;
default: /* Unknown event */
pr_info("Unknown WMI event type 0x%x\n",
(int)buffer_entry[1]);
@@ -747,6 +754,10 @@ static int __init dell_wmi_init(void)
}
}
+ err = dell_privacy_register_driver();
+ if (err)
+ return err;
+
return wmi_driver_register(&dell_wmi_driver);
}
late_initcall(dell_wmi_init);
@@ -757,6 +768,7 @@ static void __exit dell_wmi_exit(void)
dell_wmi_events_set_enabled(false);
wmi_driver_unregister(&dell_wmi_driver);
+ dell_privacy_unregister_driver();
}
module_exit(dell_wmi_exit);
diff --git a/drivers/platform/x86/dell/dell-wmi-privacy.c b/drivers/platform/x86/dell/dell-wmi-privacy.c
new file mode 100644
index 000000000000..074b7e68c227
--- /dev/null
+++ b/drivers/platform/x86/dell/dell-wmi-privacy.c
@@ -0,0 +1,391 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Dell privacy notification driver
+ *
+ * Copyright (C) 2021 Dell Inc. All Rights Reserved.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/acpi.h>
+#include <linux/bitops.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/list.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/wmi.h>
+
+#include "dell-wmi-privacy.h"
+
+#define DELL_PRIVACY_GUID "6932965F-1671-4CEB-B988-D3AB0A901919"
+#define MICROPHONE_STATUS BIT(0)
+#define CAMERA_STATUS BIT(1)
+#define DELL_PRIVACY_AUDIO_EVENT 0x1
+#define DELL_PRIVACY_CAMERA_EVENT 0x2
+#define led_to_priv(c) container_of(c, struct privacy_wmi_data, cdev)
+
+/*
+ * The wmi_list is used to store the privacy_priv struct with mutex protecting
+ */
+static LIST_HEAD(wmi_list);
+static DEFINE_MUTEX(list_mutex);
+
+struct privacy_wmi_data {
+ struct input_dev *input_dev;
+ struct wmi_device *wdev;
+ struct list_head list;
+ struct led_classdev cdev;
+ u32 features_present;
+ u32 last_status;
+};
+
+/* DELL Privacy Type */
+enum dell_hardware_privacy_type {
+ DELL_PRIVACY_TYPE_AUDIO = 0,
+ DELL_PRIVACY_TYPE_CAMERA,
+ DELL_PRIVACY_TYPE_SCREEN,
+ DELL_PRIVACY_TYPE_MAX,
+};
+
+static const char * const privacy_types[DELL_PRIVACY_TYPE_MAX] = {
+ [DELL_PRIVACY_TYPE_AUDIO] = "Microphone",
+ [DELL_PRIVACY_TYPE_CAMERA] = "Camera Shutter",
+ [DELL_PRIVACY_TYPE_SCREEN] = "ePrivacy Screen",
+};
+
+/*
+ * Keymap for WMI privacy events of type 0x0012
+ */
+static const struct key_entry dell_wmi_keymap_type_0012[] = {
+ /* privacy mic mute */
+ { KE_KEY, 0x0001, { KEY_MICMUTE } },
+ /* privacy camera mute */
+ { KE_SW, 0x0002, { SW_CAMERA_LENS_COVER } },
+ { KE_END, 0},
+};
+
+bool dell_privacy_has_mic_mute(void)
+{
+ struct privacy_wmi_data *priv;
+
+ mutex_lock(&list_mutex);
+ priv = list_first_entry_or_null(&wmi_list,
+ struct privacy_wmi_data,
+ list);
+ mutex_unlock(&list_mutex);
+
+ return priv && (priv->features_present & BIT(DELL_PRIVACY_TYPE_AUDIO));
+}
+EXPORT_SYMBOL_GPL(dell_privacy_has_mic_mute);
+
+/*
+ * The flow of privacy event:
+ * 1) User presses key. HW does stuff with this key (timeout is started)
+ * 2) WMI event is emitted from BIOS
+ * 3) WMI event is received by dell-privacy
+ * 4) KEY_MICMUTE emitted from dell-privacy
+ * 5) Userland picks up key and modifies kcontrol for SW mute
+ * 6) Codec kernel driver catches and calls ledtrig_audio_set which will call
+ * led_set_brightness() on the LED registered by dell_privacy_leds_setup()
+ * 7) dell-privacy notifies EC, the timeout is cancelled and the HW mute activates.
+ * If the EC is not notified then the HW mic mute will activate when the timeout
+ * triggers, just a bit later than with the active ack.
+ */
+bool dell_privacy_process_event(int type, int code, int status)
+{
+ struct privacy_wmi_data *priv;
+ const struct key_entry *key;
+ bool ret = false;
+
+ mutex_lock(&list_mutex);
+ priv = list_first_entry_or_null(&wmi_list,
+ struct privacy_wmi_data,
+ list);
+ if (!priv)
+ goto error;
+
+ key = sparse_keymap_entry_from_scancode(priv->input_dev, (type << 16) | code);
+ if (!key) {
+ dev_warn(&priv->wdev->dev, "Unknown key with type 0x%04x and code 0x%04x pressed\n",
+ type, code);
+ goto error;
+ }
+ dev_dbg(&priv->wdev->dev, "Key with type 0x%04x and code 0x%04x pressed\n", type, code);
+
+ switch (code) {
+ case DELL_PRIVACY_AUDIO_EVENT: /* Mic mute */
+ case DELL_PRIVACY_CAMERA_EVENT: /* Camera mute */
+ priv->last_status = status;
+ sparse_keymap_report_entry(priv->input_dev, key, 1, true);
+ ret = true;
+ break;
+ default:
+ dev_dbg(&priv->wdev->dev, "unknown event type 0x%04x 0x%04x\n", type, code);
+ }
+
+error:
+ mutex_unlock(&list_mutex);
+ return ret;
+}
+
+static ssize_t dell_privacy_supported_type_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct privacy_wmi_data *priv = dev_get_drvdata(dev);
+ enum dell_hardware_privacy_type type;
+ u32 privacy_list;
+ int len = 0;
+
+ privacy_list = priv->features_present;
+ for (type = DELL_PRIVACY_TYPE_AUDIO; type < DELL_PRIVACY_TYPE_MAX; type++) {
+ if (privacy_list & BIT(type))
+ len += sysfs_emit_at(buf, len, "[%s] [supported]\n", privacy_types[type]);
+ else
+ len += sysfs_emit_at(buf, len, "[%s] [unsupported]\n", privacy_types[type]);
+ }
+
+ return len;
+}
+
+static ssize_t dell_privacy_current_state_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct privacy_wmi_data *priv = dev_get_drvdata(dev);
+ u32 privacy_supported = priv->features_present;
+ enum dell_hardware_privacy_type type;
+ u32 privacy_state = priv->last_status;
+ int len = 0;
+
+ for (type = DELL_PRIVACY_TYPE_AUDIO; type < DELL_PRIVACY_TYPE_MAX; type++) {
+ if (privacy_supported & BIT(type)) {
+ if (privacy_state & BIT(type))
+ len += sysfs_emit_at(buf, len, "[%s] [unmuted]\n", privacy_types[type]);
+ else
+ len += sysfs_emit_at(buf, len, "[%s] [muted]\n", privacy_types[type]);
+ }
+ }
+
+ return len;
+}
+
+static DEVICE_ATTR_RO(dell_privacy_supported_type);
+static DEVICE_ATTR_RO(dell_privacy_current_state);
+
+static struct attribute *privacy_attributes[] = {
+ &dev_attr_dell_privacy_supported_type.attr,
+ &dev_attr_dell_privacy_current_state.attr,
+ NULL,
+};
+
+static const struct attribute_group privacy_attribute_group = {
+ .attrs = privacy_attributes
+};
+
+/*
+ * Describes the Device State class exposed by BIOS which can be consumed by
+ * various applications interested in knowing the Privacy feature capabilities.
+ * class DeviceState
+ * {
+ * [key, read] string InstanceName;
+ * [read] boolean ReadOnly;
+ *
+ * [WmiDataId(1), read] uint32 DevicesSupported;
+ * 0 - None; 0x1 - Microphone; 0x2 - Camera; 0x4 - ePrivacy Screen
+ *
+ * [WmiDataId(2), read] uint32 CurrentState;
+ * 0 - Off; 1 - On; Bit0 - Microphone; Bit1 - Camera; Bit2 - ePrivacyScreen
+ * };
+ */
+static int get_current_status(struct wmi_device *wdev)
+{
+ struct privacy_wmi_data *priv = dev_get_drvdata(&wdev->dev);
+ union acpi_object *obj_present;
+ u32 *buffer;
+ int ret = 0;
+
+ if (!priv) {
+ dev_err(&wdev->dev, "dell privacy priv is NULL\n");
+ return -EINVAL;
+ }
+ /* check privacy support features and device states */
+ obj_present = wmidev_block_query(wdev, 0);
+ if (!obj_present) {
+ dev_err(&wdev->dev, "failed to read Binary MOF\n");
+ return -EIO;
+ }
+
+ if (obj_present->type != ACPI_TYPE_BUFFER) {
+ dev_err(&wdev->dev, "Binary MOF is not a buffer!\n");
+ ret = -EIO;
+ goto obj_free;
+ }
+ /* Although it's not technically a failure, this would lead to
+ * unexpected behavior
+ */
+ if (obj_present->buffer.length != 8) {
+ dev_err(&wdev->dev, "Dell privacy buffer has unexpected length (%d)!\n",
+ obj_present->buffer.length);
+ ret = -EINVAL;
+ goto obj_free;
+ }
+ buffer = (u32 *)obj_present->buffer.pointer;
+ priv->features_present = buffer[0];
+ priv->last_status = buffer[1];
+
+obj_free:
+ kfree(obj_present);
+ return ret;
+}
+
+static int dell_privacy_micmute_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct privacy_wmi_data *priv = led_to_priv(led_cdev);
+ static char *acpi_method = (char *)"ECAK";
+ acpi_status status;
+ acpi_handle handle;
+
+ handle = ec_get_handle();
+ if (!handle)
+ return -EIO;
+
+ if (!acpi_has_method(handle, acpi_method))
+ return -EIO;
+
+ status = acpi_evaluate_object(handle, acpi_method, NULL, NULL);
+ if (ACPI_FAILURE(status)) {
+ dev_err(&priv->wdev->dev, "Error setting privacy EC ack value: %s\n",
+ acpi_format_exception(status));
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * Pressing the mute key activates a time delayed circuit to physically cut
+ * off the mute. The LED is in the same circuit, so it reflects the true
+ * state of the HW mute. The reason for the EC "ack" is so that software
+ * can first invoke a SW mute before the HW circuit is cut off. Without SW
+ * cutting this off first does not affect the time delayed muting or status
+ * of the LED but there is a possibility of a "popping" noise.
+ *
+ * If the EC receives the SW ack, the circuit will be activated before the
+ * delay completed.
+ *
+ * Exposing as an LED device allows the codec drivers notification path to
+ * EC ACK to work
+ */
+static int dell_privacy_leds_setup(struct device *dev)
+{
+ struct privacy_wmi_data *priv = dev_get_drvdata(dev);
+
+ priv->cdev.name = "dell-privacy::micmute";
+ priv->cdev.max_brightness = 1;
+ priv->cdev.brightness_set_blocking = dell_privacy_micmute_led_set;
+ priv->cdev.default_trigger = "audio-micmute";
+ priv->cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
+ return devm_led_classdev_register(dev, &priv->cdev);
+}
+
+static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context)
+{
+ struct privacy_wmi_data *priv;
+ struct key_entry *keymap;
+ int ret, i;
+
+ ret = wmi_has_guid(DELL_PRIVACY_GUID);
+ if (!ret)
+ pr_debug("Unable to detect available Dell privacy devices!\n");
+
+ priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(&wdev->dev, priv);
+ priv->wdev = wdev;
+ /* create evdev passing interface */
+ priv->input_dev = devm_input_allocate_device(&wdev->dev);
+ if (!priv->input_dev)
+ return -ENOMEM;
+
+ /* remap the wmi keymap event to new keymap */
+ keymap = kcalloc(ARRAY_SIZE(dell_wmi_keymap_type_0012),
+ sizeof(struct key_entry), GFP_KERNEL);
+ if (!keymap)
+ return -ENOMEM;
+
+ /* remap the keymap code with Dell privacy key type 0x12 as prefix
+ * KEY_MICMUTE scancode will be reported as 0x120001
+ */
+ for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) {
+ keymap[i] = dell_wmi_keymap_type_0012[i];
+ keymap[i].code |= (0x0012 << 16);
+ }
+ ret = sparse_keymap_setup(priv->input_dev, keymap, NULL);
+ kfree(keymap);
+ if (ret)
+ return ret;
+
+ priv->input_dev->dev.parent = &wdev->dev;
+ priv->input_dev->name = "Dell Privacy Driver";
+ priv->input_dev->id.bustype = BUS_HOST;
+
+ ret = input_register_device(priv->input_dev);
+ if (ret)
+ return ret;
+
+ ret = get_current_status(priv->wdev);
+ if (ret)
+ return ret;
+
+ ret = devm_device_add_group(&wdev->dev, &privacy_attribute_group);
+ if (ret)
+ return ret;
+
+ if (priv->features_present & BIT(DELL_PRIVACY_TYPE_AUDIO)) {
+ ret = dell_privacy_leds_setup(&priv->wdev->dev);
+ if (ret)
+ return ret;
+ }
+ mutex_lock(&list_mutex);
+ list_add_tail(&priv->list, &wmi_list);
+ mutex_unlock(&list_mutex);
+ return 0;
+}
+
+static void dell_privacy_wmi_remove(struct wmi_device *wdev)
+{
+ struct privacy_wmi_data *priv = dev_get_drvdata(&wdev->dev);
+
+ mutex_lock(&list_mutex);
+ list_del(&priv->list);
+ mutex_unlock(&list_mutex);
+}
+
+static const struct wmi_device_id dell_wmi_privacy_wmi_id_table[] = {
+ { .guid_string = DELL_PRIVACY_GUID },
+ { },
+};
+
+static struct wmi_driver dell_privacy_wmi_driver = {
+ .driver = {
+ .name = "dell-privacy",
+ },
+ .probe = dell_privacy_wmi_probe,
+ .remove = dell_privacy_wmi_remove,
+ .id_table = dell_wmi_privacy_wmi_id_table,
+};
+
+int dell_privacy_register_driver(void)
+{
+ return wmi_driver_register(&dell_privacy_wmi_driver);
+}
+
+void dell_privacy_unregister_driver(void)
+{
+ wmi_driver_unregister(&dell_privacy_wmi_driver);
+}
diff --git a/drivers/platform/x86/dell/dell-wmi-privacy.h b/drivers/platform/x86/dell/dell-wmi-privacy.h
new file mode 100644
index 000000000000..50c9b943dd47
--- /dev/null
+++ b/drivers/platform/x86/dell/dell-wmi-privacy.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Dell privacy notification driver
+ *
+ * Copyright (C) 2021 Dell Inc. All Rights Reserved.
+ */
+
+#ifndef _DELL_PRIVACY_WMI_H_
+#define _DELL_PRIVACY_WMI_H_
+
+#if IS_ENABLED(CONFIG_DELL_WMI_PRIVACY)
+bool dell_privacy_has_mic_mute(void);
+bool dell_privacy_process_event(int type, int code, int status);
+int dell_privacy_register_driver(void);
+void dell_privacy_unregister_driver(void);
+#else /* CONFIG_DELL_PRIVACY */
+static inline bool dell_privacy_has_mic_mute(void)
+{
+ return false;
+}
+
+static inline bool dell_privacy_process_event(int type, int code, int status)
+{
+ return false;
+}
+
+static inline int dell_privacy_register_driver(void)
+{
+ return 0;
+}
+
+static inline void dell_privacy_unregister_driver(void)
+{
+}
+#endif /* CONFIG_DELL_PRIVACY */
+#endif
diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/dell-wmi-sysman.h b/drivers/platform/x86/dell/dell-wmi-sysman/dell-wmi-sysman.h
index b80f2a62ea3f..3ad33a094588 100644
--- a/drivers/platform/x86/dell/dell-wmi-sysman/dell-wmi-sysman.h
+++ b/drivers/platform/x86/dell/dell-wmi-sysman/dell-wmi-sysman.h
@@ -152,12 +152,15 @@ static ssize_t curr_val##_store(struct kobject *kobj, \
return ret ? ret : count; \
}
+#define check_property_type(attr, prop, valuetype) \
+ (attr##_obj[prop].type != valuetype)
+
union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string);
int get_instance_count(const char *guid_string);
void strlcpy_attr(char *dest, char *src);
int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
- struct kobject *attr_name_kobj);
+ struct kobject *attr_name_kobj, u32 enum_property_count);
int alloc_enum_data(void);
void exit_enum_attributes(void);
diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c
index 091e48c217ed..8cc212c85266 100644
--- a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c
+++ b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c
@@ -132,39 +132,68 @@ int alloc_enum_data(void)
* @enumeration_obj: ACPI object with enumeration data
* @instance_id: The instance to enumerate
* @attr_name_kobj: The parent kernel object
+ * @enum_property_count: Total properties count under enumeration type
*/
int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
- struct kobject *attr_name_kobj)
+ struct kobject *attr_name_kobj, u32 enum_property_count)
{
int i, next_obj, value_modifier_count, possible_values_count;
wmi_priv.enumeration_data[instance_id].attr_name_kobj = attr_name_kobj;
+ if (check_property_type(enumeration, ATTR_NAME, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.enumeration_data[instance_id].attribute_name,
enumeration_obj[ATTR_NAME].string.pointer);
+ if (check_property_type(enumeration, DISPL_NAME_LANG_CODE, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.enumeration_data[instance_id].display_name_language_code,
enumeration_obj[DISPL_NAME_LANG_CODE].string.pointer);
+ if (check_property_type(enumeration, DISPLAY_NAME, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.enumeration_data[instance_id].display_name,
enumeration_obj[DISPLAY_NAME].string.pointer);
+ if (check_property_type(enumeration, DEFAULT_VAL, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.enumeration_data[instance_id].default_value,
enumeration_obj[DEFAULT_VAL].string.pointer);
+ if (check_property_type(enumeration, MODIFIER, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.enumeration_data[instance_id].dell_modifier,
enumeration_obj[MODIFIER].string.pointer);
next_obj = MODIFIER + 1;
- value_modifier_count = (uintptr_t)enumeration_obj[next_obj].string.pointer;
+ if (next_obj >= enum_property_count)
+ return -EINVAL;
+
+ if (check_property_type(enumeration, next_obj, ACPI_TYPE_INTEGER))
+ return -EINVAL;
+ value_modifier_count = (uintptr_t)enumeration_obj[next_obj++].string.pointer;
for (i = 0; i < value_modifier_count; i++) {
+ if (next_obj >= enum_property_count)
+ return -EINVAL;
+ if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING))
+ return -EINVAL;
strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier,
- enumeration_obj[++next_obj].string.pointer);
+ enumeration_obj[next_obj++].string.pointer);
strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";");
}
- possible_values_count = (uintptr_t) enumeration_obj[++next_obj].string.pointer;
+ if (next_obj >= enum_property_count)
+ return -EINVAL;
+
+ if (check_property_type(enumeration, next_obj, ACPI_TYPE_INTEGER))
+ return -EINVAL;
+ possible_values_count = (uintptr_t) enumeration_obj[next_obj++].string.pointer;
for (i = 0; i < possible_values_count; i++) {
+ if (next_obj >= enum_property_count)
+ return -EINVAL;
+ if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING))
+ return -EINVAL;
strcat(wmi_priv.enumeration_data[instance_id].possible_values,
- enumeration_obj[++next_obj].string.pointer);
+ enumeration_obj[next_obj++].string.pointer);
strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";");
}
diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/int-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/int-attributes.c
index 8a49ba6e44f9..951e75b538fa 100644
--- a/drivers/platform/x86/dell/dell-wmi-sysman/int-attributes.c
+++ b/drivers/platform/x86/dell/dell-wmi-sysman/int-attributes.c
@@ -141,20 +141,36 @@ int populate_int_data(union acpi_object *integer_obj, int instance_id,
struct kobject *attr_name_kobj)
{
wmi_priv.integer_data[instance_id].attr_name_kobj = attr_name_kobj;
+ if (check_property_type(integer, ATTR_NAME, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.integer_data[instance_id].attribute_name,
integer_obj[ATTR_NAME].string.pointer);
+ if (check_property_type(integer, DISPL_NAME_LANG_CODE, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.integer_data[instance_id].display_name_language_code,
integer_obj[DISPL_NAME_LANG_CODE].string.pointer);
+ if (check_property_type(integer, DISPLAY_NAME, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.integer_data[instance_id].display_name,
integer_obj[DISPLAY_NAME].string.pointer);
+ if (check_property_type(integer, DEFAULT_VAL, ACPI_TYPE_INTEGER))
+ return -EINVAL;
wmi_priv.integer_data[instance_id].default_value =
(uintptr_t)integer_obj[DEFAULT_VAL].string.pointer;
+ if (check_property_type(integer, MODIFIER, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.integer_data[instance_id].dell_modifier,
integer_obj[MODIFIER].string.pointer);
+ if (check_property_type(integer, MIN_VALUE, ACPI_TYPE_INTEGER))
+ return -EINVAL;
wmi_priv.integer_data[instance_id].min_value =
(uintptr_t)integer_obj[MIN_VALUE].string.pointer;
+ if (check_property_type(integer, MAX_VALUE, ACPI_TYPE_INTEGER))
+ return -EINVAL;
wmi_priv.integer_data[instance_id].max_value =
(uintptr_t)integer_obj[MAX_VALUE].string.pointer;
+ if (check_property_type(integer, SCALAR_INCR, ACPI_TYPE_INTEGER))
+ return -EINVAL;
wmi_priv.integer_data[instance_id].scalar_increment =
(uintptr_t)integer_obj[SCALAR_INCR].string.pointer;
diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/passobj-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/passobj-attributes.c
index 834b3e82ad9f..230e6ee96636 100644
--- a/drivers/platform/x86/dell/dell-wmi-sysman/passobj-attributes.c
+++ b/drivers/platform/x86/dell/dell-wmi-sysman/passobj-attributes.c
@@ -159,10 +159,16 @@ int alloc_po_data(void)
int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject *attr_name_kobj)
{
wmi_priv.po_data[instance_id].attr_name_kobj = attr_name_kobj;
+ if (check_property_type(po, ATTR_NAME, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.po_data[instance_id].attribute_name,
po_obj[ATTR_NAME].string.pointer);
+ if (check_property_type(po, MIN_PASS_LEN, ACPI_TYPE_INTEGER))
+ return -EINVAL;
wmi_priv.po_data[instance_id].min_password_length =
(uintptr_t)po_obj[MIN_PASS_LEN].string.pointer;
+ if (check_property_type(po, MAX_PASS_LEN, ACPI_TYPE_INTEGER))
+ return -EINVAL;
wmi_priv.po_data[instance_id].max_password_length =
(uintptr_t) po_obj[MAX_PASS_LEN].string.pointer;
diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c b/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c
index 339a082d6c18..86ec962aace9 100644
--- a/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c
+++ b/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c
@@ -95,9 +95,9 @@ int set_new_password(const char *password_type, const char *new)
print_hex_dump_bytes("set new password data: ", DUMP_PREFIX_NONE, buffer, buffer_size);
ret = call_password_interface(wmi_priv.password_attr_wdev, buffer, buffer_size);
- /* clear current_password here and use user input from wmi_priv.current_password */
+ /* on success copy the new password to current password */
if (!ret)
- memset(current_password, 0, MAX_BUFF);
+ strscpy(current_password, new, MAX_BUFF);
/* explain to user the detailed failure reason */
else if (ret == -EOPNOTSUPP)
dev_err(&wmi_priv.password_attr_wdev->dev, "admin password must be configured\n");
diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/string-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/string-attributes.c
index 552537852459..c392f0ecf8b5 100644
--- a/drivers/platform/x86/dell/dell-wmi-sysman/string-attributes.c
+++ b/drivers/platform/x86/dell/dell-wmi-sysman/string-attributes.c
@@ -118,24 +118,38 @@ int alloc_str_data(void)
/**
* populate_str_data() - Populate all properties of an instance under string attribute
- * @str_obj: ACPI object with integer data
+ * @str_obj: ACPI object with string data
* @instance_id: The instance to enumerate
* @attr_name_kobj: The parent kernel object
*/
int populate_str_data(union acpi_object *str_obj, int instance_id, struct kobject *attr_name_kobj)
{
wmi_priv.str_data[instance_id].attr_name_kobj = attr_name_kobj;
+ if (check_property_type(str, ATTR_NAME, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.str_data[instance_id].attribute_name,
str_obj[ATTR_NAME].string.pointer);
+ if (check_property_type(str, DISPL_NAME_LANG_CODE, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.str_data[instance_id].display_name_language_code,
str_obj[DISPL_NAME_LANG_CODE].string.pointer);
+ if (check_property_type(str, DISPLAY_NAME, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.str_data[instance_id].display_name,
str_obj[DISPLAY_NAME].string.pointer);
+ if (check_property_type(str, DEFAULT_VAL, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.str_data[instance_id].default_value,
str_obj[DEFAULT_VAL].string.pointer);
+ if (check_property_type(str, MODIFIER, ACPI_TYPE_STRING))
+ return -EINVAL;
strlcpy_attr(wmi_priv.str_data[instance_id].dell_modifier,
str_obj[MODIFIER].string.pointer);
+ if (check_property_type(str, MIN_LEN, ACPI_TYPE_INTEGER))
+ return -EINVAL;
wmi_priv.str_data[instance_id].min_length = (uintptr_t)str_obj[MIN_LEN].string.pointer;
+ if (check_property_type(str, MAX_LEN, ACPI_TYPE_INTEGER))
+ return -EINVAL;
wmi_priv.str_data[instance_id].max_length = (uintptr_t) str_obj[MAX_LEN].string.pointer;
return sysfs_create_group(attr_name_kobj, &str_attr_group);
diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c
index c8d276d78e92..636bdfa83284 100644
--- a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c
+++ b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c
@@ -13,14 +13,11 @@
#include <linux/kernel.h>
#include <linux/wmi.h>
#include "dell-wmi-sysman.h"
+#include "../../firmware_attributes_class.h"
#define MAX_TYPES 4
#include <linux/nls.h>
-static struct class firmware_attributes_class = {
- .name = "firmware-attributes",
-};
-
struct wmi_sysman_priv wmi_priv = {
.mutex = __MUTEX_INITIALIZER(wmi_priv.mutex),
};
@@ -28,6 +25,7 @@ struct wmi_sysman_priv wmi_priv = {
/* reset bios to defaults */
static const char * const reset_types[] = {"builtinsafe", "lastknowngood", "factory", "custom"};
static int reset_option = -1;
+static struct class *fw_attr_class;
/**
@@ -481,7 +479,8 @@ static int init_bios_attributes(int attr_type, const char *guid)
/* enumerate all of this attribute */
switch (attr_type) {
case ENUM:
- retval = populate_enum_data(elements, instance_id, attr_name_kobj);
+ retval = populate_enum_data(elements, instance_id, attr_name_kobj,
+ obj->package.count);
break;
case INT:
retval = populate_int_data(elements, instance_id, attr_name_kobj);
@@ -541,11 +540,11 @@ static int __init sysman_init(void)
goto err_exit_bios_attr_pass_interface;
}
- ret = class_register(&firmware_attributes_class);
+ ret = fw_attributes_class_get(&fw_attr_class);
if (ret)
goto err_exit_bios_attr_pass_interface;
- wmi_priv.class_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0),
+ wmi_priv.class_dev = device_create(fw_attr_class, NULL, MKDEV(0, 0),
NULL, "%s", DRIVER_NAME);
if (IS_ERR(wmi_priv.class_dev)) {
ret = PTR_ERR(wmi_priv.class_dev);
@@ -602,10 +601,10 @@ err_release_attributes_data:
release_attributes_data();
err_destroy_classdev:
- device_destroy(&firmware_attributes_class, MKDEV(0, 0));
+ device_destroy(fw_attr_class, MKDEV(0, 0));
err_unregister_class:
- class_unregister(&firmware_attributes_class);
+ fw_attributes_class_put();
err_exit_bios_attr_pass_interface:
exit_bios_attr_pass_interface();
@@ -619,8 +618,8 @@ err_exit_bios_attr_set_interface:
static void __exit sysman_exit(void)
{
release_attributes_data();
- device_destroy(&firmware_attributes_class, MKDEV(0, 0));
- class_unregister(&firmware_attributes_class);
+ device_destroy(fw_attr_class, MKDEV(0, 0));
+ fw_attributes_class_put();
exit_bios_attr_set_interface();
exit_bios_attr_pass_interface();
}
diff --git a/drivers/platform/x86/dell/dell_rbu.c b/drivers/platform/x86/dell/dell_rbu.c
index 085ad0a0d22e..e9f4b30dcafa 100644
--- a/drivers/platform/x86/dell/dell_rbu.c
+++ b/drivers/platform/x86/dell/dell_rbu.c
@@ -573,7 +573,7 @@ static ssize_t image_type_write(struct file *filp, struct kobject *kobj,
if (!rbu_data.entry_created) {
spin_unlock(&rbu_data.lock);
req_firm_rc = request_firmware_nowait(THIS_MODULE,
- FW_ACTION_NOHOTPLUG, "dell_rbu",
+ FW_ACTION_NOUEVENT, "dell_rbu",
&rbu_device->dev, GFP_KERNEL, &context,
callbackfn_rbu);
if (req_firm_rc) {
diff --git a/drivers/platform/x86/firmware_attributes_class.c b/drivers/platform/x86/firmware_attributes_class.c
new file mode 100644
index 000000000000..fafe8eaf6e3e
--- /dev/null
+++ b/drivers/platform/x86/firmware_attributes_class.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/* Firmware attributes class helper module */
+
+#include <linux/mutex.h>
+#include <linux/device/class.h>
+#include <linux/module.h>
+#include "firmware_attributes_class.h"
+
+static DEFINE_MUTEX(fw_attr_lock);
+static int fw_attr_inuse;
+
+static struct class firmware_attributes_class = {
+ .name = "firmware-attributes",
+};
+
+int fw_attributes_class_get(struct class **fw_attr_class)
+{
+ int err;
+
+ mutex_lock(&fw_attr_lock);
+ if (!fw_attr_inuse) { /*first time class is being used*/
+ err = class_register(&firmware_attributes_class);
+ if (err) {
+ mutex_unlock(&fw_attr_lock);
+ return err;
+ }
+ }
+ fw_attr_inuse++;
+ *fw_attr_class = &firmware_attributes_class;
+ mutex_unlock(&fw_attr_lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fw_attributes_class_get);
+
+int fw_attributes_class_put(void)
+{
+ mutex_lock(&fw_attr_lock);
+ if (!fw_attr_inuse) {
+ mutex_unlock(&fw_attr_lock);
+ return -EINVAL;
+ }
+ fw_attr_inuse--;
+ if (!fw_attr_inuse) /* No more consumers */
+ class_unregister(&firmware_attributes_class);
+ mutex_unlock(&fw_attr_lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fw_attributes_class_put);
+
+MODULE_AUTHOR("Mark Pearson <markpearson@lenovo.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/firmware_attributes_class.h b/drivers/platform/x86/firmware_attributes_class.h
new file mode 100644
index 000000000000..486485cb1f54
--- /dev/null
+++ b/drivers/platform/x86/firmware_attributes_class.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* Firmware attributes class helper module */
+
+#ifndef FW_ATTR_CLASS_H
+#define FW_ATTR_CLASS_H
+
+int fw_attributes_class_get(struct class **fw_attr_class);
+int fw_attributes_class_put(void);
+
+#endif /* FW_ATTR_CLASS_H */
diff --git a/drivers/platform/x86/hdaps.c b/drivers/platform/x86/hdaps.c
index a72270932ec3..9996485f5295 100644
--- a/drivers/platform/x86/hdaps.c
+++ b/drivers/platform/x86/hdaps.c
@@ -462,7 +462,7 @@ static struct attribute *hdaps_attributes[] = {
NULL,
};
-static struct attribute_group hdaps_attribute_group = {
+static const struct attribute_group hdaps_attribute_group = {
.attrs = hdaps_attributes,
};
diff --git a/drivers/platform/x86/hp-wireless.c b/drivers/platform/x86/hp-wireless.c
deleted file mode 100644
index 0753ef18e721..000000000000
--- a/drivers/platform/x86/hp-wireless.c
+++ /dev/null
@@ -1,102 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Airplane mode button for HP & Xiaomi laptops
- *
- * Copyright (C) 2014-2017 Alex Hung <alex.hung@canonical.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/platform_device.h>
-#include <linux/acpi.h>
-#include <acpi/acpi_bus.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Alex Hung");
-MODULE_ALIAS("acpi*:HPQ6001:*");
-MODULE_ALIAS("acpi*:WSTADEF:*");
-MODULE_ALIAS("acpi*:AMDI0051:*");
-
-static struct input_dev *hpwl_input_dev;
-
-static const struct acpi_device_id hpwl_ids[] = {
- {"HPQ6001", 0},
- {"WSTADEF", 0},
- {"AMDI0051", 0},
- {"", 0},
-};
-
-static int hp_wireless_input_setup(void)
-{
- int err;
-
- hpwl_input_dev = input_allocate_device();
- if (!hpwl_input_dev)
- return -ENOMEM;
-
- hpwl_input_dev->name = "HP Wireless hotkeys";
- hpwl_input_dev->phys = "hpq6001/input0";
- hpwl_input_dev->id.bustype = BUS_HOST;
- hpwl_input_dev->evbit[0] = BIT(EV_KEY);
- set_bit(KEY_RFKILL, hpwl_input_dev->keybit);
-
- err = input_register_device(hpwl_input_dev);
- if (err)
- goto err_free_dev;
-
- return 0;
-
-err_free_dev:
- input_free_device(hpwl_input_dev);
- return err;
-}
-
-static void hp_wireless_input_destroy(void)
-{
- input_unregister_device(hpwl_input_dev);
-}
-
-static void hpwl_notify(struct acpi_device *acpi_dev, u32 event)
-{
- if (event != 0x80) {
- pr_info("Received unknown event (0x%x)\n", event);
- return;
- }
-
- input_report_key(hpwl_input_dev, KEY_RFKILL, 1);
- input_sync(hpwl_input_dev);
- input_report_key(hpwl_input_dev, KEY_RFKILL, 0);
- input_sync(hpwl_input_dev);
-}
-
-static int hpwl_add(struct acpi_device *device)
-{
- int err;
-
- err = hp_wireless_input_setup();
- if (err)
- pr_err("Failed to setup hp wireless hotkeys\n");
-
- return err;
-}
-
-static int hpwl_remove(struct acpi_device *device)
-{
- hp_wireless_input_destroy();
- return 0;
-}
-
-static struct acpi_driver hpwl_driver = {
- .name = "hp-wireless",
- .owner = THIS_MODULE,
- .ids = hpwl_ids,
- .ops = {
- .add = hpwl_add,
- .remove = hpwl_remove,
- .notify = hpwl_notify,
- },
-};
-
-module_acpi_driver(hpwl_driver);
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 387817290921..784326bd72f0 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -1408,6 +1408,18 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
case 6:
ideapad_input_report(priv, bit);
break;
+ case 10:
+ /*
+ * This event gets send on a Yoga 300-11IBR when the EC
+ * believes that the device has changed between laptop/
+ * tent/stand/tablet mode. The EC relies on getting
+ * angle info from 2 accelerometers through a special
+ * windows service calling a DSM on the DUAL250E ACPI-
+ * device. Linux does not do this, making the laptop/
+ * tent/stand/tablet mode info unreliable, so we simply
+ * ignore these events.
+ */
+ break;
case 9:
ideapad_sync_rfk_state(priv);
break;
diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig
new file mode 100644
index 000000000000..f2eef337eb98
--- /dev/null
+++ b/drivers/platform/x86/intel/Kconfig
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Intel x86 Platform Specific Drivers
+#
+
+menuconfig X86_PLATFORM_DRIVERS_INTEL
+ bool "Intel x86 Platform Specific Device Drivers"
+ default y
+ help
+ Say Y here to get to see options for device drivers for
+ various Intel x86 platforms, including vendor-specific
+ drivers. This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped
+ and disabled.
+
+if X86_PLATFORM_DRIVERS_INTEL
+
+source "drivers/platform/x86/intel/int33fe/Kconfig"
+source "drivers/platform/x86/intel/int3472/Kconfig"
+
+endif # X86_PLATFORM_DRIVERS_INTEL
diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile
new file mode 100644
index 000000000000..0653055942d5
--- /dev/null
+++ b/drivers/platform/x86/intel/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for drivers/platform/x86/intel
+# Intel x86 Platform-Specific Drivers
+#
+
+obj-$(CONFIG_INTEL_CHT_INT33FE) += int33fe/
+obj-$(CONFIG_INTEL_SKL_INT3472) += int3472/
diff --git a/drivers/platform/x86/intel/int33fe/Kconfig b/drivers/platform/x86/intel/int33fe/Kconfig
new file mode 100644
index 000000000000..2f7329a2e399
--- /dev/null
+++ b/drivers/platform/x86/intel/int33fe/Kconfig
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config INTEL_CHT_INT33FE
+ tristate "Intel Cherry Trail ACPI INT33FE Driver"
+ depends on X86 && ACPI && I2C && REGULATOR
+ depends on CHARGER_BQ24190=y || (CHARGER_BQ24190=m && m)
+ depends on USB_ROLES_INTEL_XHCI=y || (USB_ROLES_INTEL_XHCI=m && m)
+ depends on TYPEC_MUX_PI3USB30532=y || (TYPEC_MUX_PI3USB30532=m && m)
+ help
+ This driver add support for the INT33FE ACPI device found on
+ some Intel Cherry Trail devices.
+
+ There are two kinds of INT33FE ACPI device possible: for hardware
+ with USB Type-C and Micro-B connectors. This driver supports both.
+
+ The INT33FE ACPI device has a CRS table with I2cSerialBusV2
+ resources for Fuel Gauge Controller and (in the Type-C variant)
+ FUSB302 USB Type-C Controller and PI3USB30532 USB switch.
+ This driver instantiates i2c-clients for these, so that standard
+ i2c drivers for these chips can bind to the them.
+
+ If you enable this driver it is advised to also select
+ CONFIG_BATTERY_BQ27XXX=m or CONFIG_BATTERY_BQ27XXX_I2C=m for Micro-B
+ device and CONFIG_TYPEC_FUSB302=m and CONFIG_BATTERY_MAX17042=m
+ for Type-C device.
diff --git a/drivers/platform/x86/intel/int33fe/Makefile b/drivers/platform/x86/intel/int33fe/Makefile
new file mode 100644
index 000000000000..cc11183ce179
--- /dev/null
+++ b/drivers/platform/x86/intel/int33fe/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_INTEL_CHT_INT33FE) += intel_cht_int33fe.o
+intel_cht_int33fe-objs := intel_cht_int33fe_common.o \
+ intel_cht_int33fe_typec.o \
+ intel_cht_int33fe_microb.o
diff --git a/drivers/platform/x86/intel_cht_int33fe_common.c b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_common.c
index 251ed9bac789..251ed9bac789 100644
--- a/drivers/platform/x86/intel_cht_int33fe_common.c
+++ b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_common.c
diff --git a/drivers/platform/x86/intel_cht_int33fe_common.h b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_common.h
index 03cd45f4e8cb..03cd45f4e8cb 100644
--- a/drivers/platform/x86/intel_cht_int33fe_common.h
+++ b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_common.h
diff --git a/drivers/platform/x86/intel_cht_int33fe_microb.c b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_microb.c
index 673f41cd14b5..673f41cd14b5 100644
--- a/drivers/platform/x86/intel_cht_int33fe_microb.c
+++ b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_microb.c
diff --git a/drivers/platform/x86/intel_cht_int33fe_typec.c b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_typec.c
index b61bad9cc8d2..d59544167430 100644
--- a/drivers/platform/x86/intel_cht_int33fe_typec.c
+++ b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_typec.c
@@ -168,8 +168,8 @@ static int cht_int33fe_setup_dp(struct cht_int33fe_data *data)
return -ENODEV;
}
- /* Then the DP child device node */
- data->dp = device_get_named_child_node(&pdev->dev, "DD02");
+ /* Then the DP-2 child device node */
+ data->dp = device_get_named_child_node(&pdev->dev, "DD04");
pci_dev_put(pdev);
if (!data->dp)
return -ENODEV;
diff --git a/drivers/platform/x86/intel/int3472/Kconfig b/drivers/platform/x86/intel/int3472/Kconfig
new file mode 100644
index 000000000000..62e5d4cf9ee5
--- /dev/null
+++ b/drivers/platform/x86/intel/int3472/Kconfig
@@ -0,0 +1,30 @@
+config INTEL_SKL_INT3472
+ tristate "Intel SkyLake ACPI INT3472 Driver"
+ depends on ACPI
+ depends on COMMON_CLK
+ depends on I2C
+ depends on GPIOLIB
+ depends on REGULATOR
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ This driver adds power controller support for the Intel SkyCam
+ devices found on the Intel SkyLake platforms.
+
+ The INT3472 is a camera power controller, a logical device found on
+ Intel Skylake-based systems that can map to different hardware
+ devices depending on the platform. On machines designed for Chrome OS
+ it maps to a TPS68470 camera PMIC. On machines designed for Windows,
+ it maps to either a TP68470 camera PMIC, a uP6641Q sensor PMIC, or a
+ set of discrete GPIOs and power gates.
+
+ If your device was designed for Chrome OS, this driver will provide
+ an ACPI OpRegion, which must be available before any of the devices
+ using it are probed. For this reason, you should select Y if your
+ device was designed for ChromeOS. For the same reason the
+ I2C_DESIGNWARE_PLATFORM option must be set to Y too.
+
+ Say Y or M here if you have a SkyLake device designed for use
+ with Windows or ChromeOS. Say N here if you are not sure.
+
+ The module will be named "intel-skl-int3472".
diff --git a/drivers/platform/x86/intel/int3472/Makefile b/drivers/platform/x86/intel/int3472/Makefile
new file mode 100644
index 000000000000..48bd97f0a04e
--- /dev/null
+++ b/drivers/platform/x86/intel/int3472/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_INTEL_SKL_INT3472) += intel_skl_int3472.o
+intel_skl_int3472-objs := intel_skl_int3472_common.o \
+ intel_skl_int3472_discrete.o \
+ intel_skl_int3472_tps68470.o \
+ intel_skl_int3472_clk_and_regulator.o
diff --git a/drivers/platform/x86/intel/int3472/intel_skl_int3472_clk_and_regulator.c b/drivers/platform/x86/intel/int3472/intel_skl_int3472_clk_and_regulator.c
new file mode 100644
index 000000000000..1700e7557a82
--- /dev/null
+++ b/drivers/platform/x86/intel/int3472/intel_skl_int3472_clk_and_regulator.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#include <linux/acpi.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/slab.h>
+
+#include "intel_skl_int3472_common.h"
+
+/*
+ * The regulators have to have .ops to be valid, but the only ops we actually
+ * support are .enable and .disable which are handled via .ena_gpiod. Pass an
+ * empty struct to clear the check without lying about capabilities.
+ */
+static const struct regulator_ops int3472_gpio_regulator_ops;
+
+static int skl_int3472_clk_prepare(struct clk_hw *hw)
+{
+ struct int3472_gpio_clock *clk = to_int3472_clk(hw);
+
+ gpiod_set_value_cansleep(clk->ena_gpio, 1);
+ gpiod_set_value_cansleep(clk->led_gpio, 1);
+
+ return 0;
+}
+
+static void skl_int3472_clk_unprepare(struct clk_hw *hw)
+{
+ struct int3472_gpio_clock *clk = to_int3472_clk(hw);
+
+ gpiod_set_value_cansleep(clk->ena_gpio, 0);
+ gpiod_set_value_cansleep(clk->led_gpio, 0);
+}
+
+static int skl_int3472_clk_enable(struct clk_hw *hw)
+{
+ /*
+ * We're just turning a GPIO on to enable the clock, which operation
+ * has the potential to sleep. Given .enable() cannot sleep, but
+ * .prepare() can, we toggle the GPIO in .prepare() instead. Thus,
+ * nothing to do here.
+ */
+ return 0;
+}
+
+static void skl_int3472_clk_disable(struct clk_hw *hw)
+{
+ /* Likewise, nothing to do here... */
+}
+
+static unsigned int skl_int3472_get_clk_frequency(struct int3472_discrete_device *int3472)
+{
+ union acpi_object *obj;
+ unsigned int freq;
+
+ obj = skl_int3472_get_acpi_buffer(int3472->sensor, "SSDB");
+ if (IS_ERR(obj))
+ return 0; /* report rate as 0 on error */
+
+ if (obj->buffer.length < CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET + sizeof(u32)) {
+ dev_err(int3472->dev, "The buffer is too small\n");
+ kfree(obj);
+ return 0;
+ }
+
+ freq = *(u32 *)(obj->buffer.pointer + CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET);
+
+ kfree(obj);
+ return freq;
+}
+
+static unsigned long skl_int3472_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct int3472_gpio_clock *clk = to_int3472_clk(hw);
+
+ return clk->frequency;
+}
+
+static const struct clk_ops skl_int3472_clock_ops = {
+ .prepare = skl_int3472_clk_prepare,
+ .unprepare = skl_int3472_clk_unprepare,
+ .enable = skl_int3472_clk_enable,
+ .disable = skl_int3472_clk_disable,
+ .recalc_rate = skl_int3472_clk_recalc_rate,
+};
+
+int skl_int3472_register_clock(struct int3472_discrete_device *int3472)
+{
+ struct clk_init_data init = {
+ .ops = &skl_int3472_clock_ops,
+ .flags = CLK_GET_RATE_NOCACHE,
+ };
+ int ret;
+
+ init.name = kasprintf(GFP_KERNEL, "%s-clk",
+ acpi_dev_name(int3472->adev));
+ if (!init.name)
+ return -ENOMEM;
+
+ int3472->clock.frequency = skl_int3472_get_clk_frequency(int3472);
+
+ int3472->clock.clk_hw.init = &init;
+ int3472->clock.clk = clk_register(&int3472->adev->dev,
+ &int3472->clock.clk_hw);
+ if (IS_ERR(int3472->clock.clk)) {
+ ret = PTR_ERR(int3472->clock.clk);
+ goto out_free_init_name;
+ }
+
+ int3472->clock.cl = clkdev_create(int3472->clock.clk, NULL,
+ int3472->sensor_name);
+ if (!int3472->clock.cl) {
+ ret = -ENOMEM;
+ goto err_unregister_clk;
+ }
+
+ kfree(init.name);
+ return 0;
+
+err_unregister_clk:
+ clk_unregister(int3472->clock.clk);
+out_free_init_name:
+ kfree(init.name);
+
+ return ret;
+}
+
+void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472)
+{
+ clkdev_drop(int3472->clock.cl);
+ clk_unregister(int3472->clock.clk);
+}
+
+int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
+ struct acpi_resource_gpio *agpio)
+{
+ const struct int3472_sensor_config *sensor_config;
+ char *path = agpio->resource_source.string_ptr;
+ struct regulator_consumer_supply supply_map;
+ struct regulator_init_data init_data = { };
+ struct regulator_config cfg = { };
+ int ret;
+
+ sensor_config = int3472->sensor_config;
+ if (IS_ERR(sensor_config)) {
+ dev_err(int3472->dev, "No sensor module config\n");
+ return PTR_ERR(sensor_config);
+ }
+
+ if (!sensor_config->supply_map.supply) {
+ dev_err(int3472->dev, "No supply name defined\n");
+ return -ENODEV;
+ }
+
+ init_data.constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS;
+ init_data.num_consumer_supplies = 1;
+ supply_map = sensor_config->supply_map;
+ supply_map.dev_name = int3472->sensor_name;
+ init_data.consumer_supplies = &supply_map;
+
+ snprintf(int3472->regulator.regulator_name,
+ sizeof(int3472->regulator.regulator_name), "%s-regulator",
+ acpi_dev_name(int3472->adev));
+ snprintf(int3472->regulator.supply_name,
+ GPIO_REGULATOR_SUPPLY_NAME_LENGTH, "supply-0");
+
+ int3472->regulator.rdesc = INT3472_REGULATOR(
+ int3472->regulator.regulator_name,
+ int3472->regulator.supply_name,
+ &int3472_gpio_regulator_ops);
+
+ int3472->regulator.gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
+ "int3472,regulator");
+ if (IS_ERR(int3472->regulator.gpio)) {
+ dev_err(int3472->dev, "Failed to get regulator GPIO line\n");
+ return PTR_ERR(int3472->regulator.gpio);
+ }
+
+ cfg.dev = &int3472->adev->dev;
+ cfg.init_data = &init_data;
+ cfg.ena_gpiod = int3472->regulator.gpio;
+
+ int3472->regulator.rdev = regulator_register(&int3472->regulator.rdesc,
+ &cfg);
+ if (IS_ERR(int3472->regulator.rdev)) {
+ ret = PTR_ERR(int3472->regulator.rdev);
+ goto err_free_gpio;
+ }
+
+ return 0;
+
+err_free_gpio:
+ gpiod_put(int3472->regulator.gpio);
+
+ return ret;
+}
+
+void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472)
+{
+ regulator_unregister(int3472->regulator.rdev);
+ gpiod_put(int3472->regulator.gpio);
+}
diff --git a/drivers/platform/x86/intel/int3472/intel_skl_int3472_common.c b/drivers/platform/x86/intel/int3472/intel_skl_int3472_common.c
new file mode 100644
index 000000000000..497e74fba75f
--- /dev/null
+++ b/drivers/platform/x86/intel/int3472/intel_skl_int3472_common.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "intel_skl_int3472_common.h"
+
+union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev, char *id)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ acpi_handle handle = adev->handle;
+ union acpi_object *obj;
+ acpi_status status;
+
+ status = acpi_evaluate_object(handle, id, NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return ERR_PTR(-ENODEV);
+
+ obj = buffer.pointer;
+ if (!obj)
+ return ERR_PTR(-ENODEV);
+
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ acpi_handle_err(handle, "%s object is not an ACPI buffer\n", id);
+ kfree(obj);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return obj;
+}
+
+int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb)
+{
+ union acpi_object *obj;
+ int ret;
+
+ obj = skl_int3472_get_acpi_buffer(adev, "CLDB");
+ if (IS_ERR(obj))
+ return PTR_ERR(obj);
+
+ if (obj->buffer.length > sizeof(*cldb)) {
+ acpi_handle_err(adev->handle, "The CLDB buffer is too large\n");
+ ret = -EINVAL;
+ goto out_free_obj;
+ }
+
+ memcpy(cldb, obj->buffer.pointer, obj->buffer.length);
+ ret = 0;
+
+out_free_obj:
+ kfree(obj);
+ return ret;
+}
+
+static const struct acpi_device_id int3472_device_id[] = {
+ { "INT3472", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, int3472_device_id);
+
+static struct platform_driver int3472_discrete = {
+ .driver = {
+ .name = "int3472-discrete",
+ .acpi_match_table = int3472_device_id,
+ },
+ .probe = skl_int3472_discrete_probe,
+ .remove = skl_int3472_discrete_remove,
+};
+
+static struct i2c_driver int3472_tps68470 = {
+ .driver = {
+ .name = "int3472-tps68470",
+ .acpi_match_table = int3472_device_id,
+ },
+ .probe_new = skl_int3472_tps68470_probe,
+};
+
+static int skl_int3472_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&int3472_discrete);
+ if (ret)
+ return ret;
+
+ ret = i2c_register_driver(THIS_MODULE, &int3472_tps68470);
+ if (ret)
+ platform_driver_unregister(&int3472_discrete);
+
+ return ret;
+}
+module_init(skl_int3472_init);
+
+static void skl_int3472_exit(void)
+{
+ platform_driver_unregister(&int3472_discrete);
+ i2c_del_driver(&int3472_tps68470);
+}
+module_exit(skl_int3472_exit);
+
+MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI Device Driver");
+MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel/int3472/intel_skl_int3472_common.h b/drivers/platform/x86/intel/int3472/intel_skl_int3472_common.h
new file mode 100644
index 000000000000..714fde73b524
--- /dev/null
+++ b/drivers/platform/x86/intel/int3472/intel_skl_int3472_common.h
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#ifndef _INTEL_SKL_INT3472_H
+#define _INTEL_SKL_INT3472_H
+
+#include <linux/clk-provider.h>
+#include <linux/gpio/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/types.h>
+
+/* FIXME drop this once the I2C_DEV_NAME_FORMAT macro has been added to include/linux/i2c.h */
+#ifndef I2C_DEV_NAME_FORMAT
+#define I2C_DEV_NAME_FORMAT "i2c-%s"
+#endif
+
+/* PMIC GPIO Types */
+#define INT3472_GPIO_TYPE_RESET 0x00
+#define INT3472_GPIO_TYPE_POWERDOWN 0x01
+#define INT3472_GPIO_TYPE_POWER_ENABLE 0x0b
+#define INT3472_GPIO_TYPE_CLK_ENABLE 0x0c
+#define INT3472_GPIO_TYPE_PRIVACY_LED 0x0d
+
+#define INT3472_PDEV_MAX_NAME_LEN 23
+#define INT3472_MAX_SENSOR_GPIOS 3
+
+#define GPIO_REGULATOR_NAME_LENGTH 21
+#define GPIO_REGULATOR_SUPPLY_NAME_LENGTH 9
+
+#define CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET 86
+
+#define INT3472_REGULATOR(_name, _supply, _ops) \
+ (const struct regulator_desc) { \
+ .name = _name, \
+ .supply_name = _supply, \
+ .type = REGULATOR_VOLTAGE, \
+ .ops = _ops, \
+ .owner = THIS_MODULE, \
+ }
+
+#define to_int3472_clk(hw) \
+ container_of(hw, struct int3472_gpio_clock, clk_hw)
+
+#define to_int3472_device(clk) \
+ container_of(clk, struct int3472_discrete_device, clock)
+
+struct acpi_device;
+struct i2c_client;
+struct platform_device;
+
+struct int3472_cldb {
+ u8 version;
+ /*
+ * control logic type
+ * 0: UNKNOWN
+ * 1: DISCRETE(CRD-D)
+ * 2: PMIC TPS68470
+ * 3: PMIC uP6641
+ */
+ u8 control_logic_type;
+ u8 control_logic_id;
+ u8 sensor_card_sku;
+ u8 reserved[28];
+};
+
+struct int3472_gpio_function_remap {
+ const char *documented;
+ const char *actual;
+};
+
+struct int3472_sensor_config {
+ const char *sensor_module_name;
+ struct regulator_consumer_supply supply_map;
+ const struct int3472_gpio_function_remap *function_maps;
+};
+
+struct int3472_discrete_device {
+ struct acpi_device *adev;
+ struct device *dev;
+ struct acpi_device *sensor;
+ const char *sensor_name;
+
+ const struct int3472_sensor_config *sensor_config;
+
+ struct int3472_gpio_regulator {
+ char regulator_name[GPIO_REGULATOR_NAME_LENGTH];
+ char supply_name[GPIO_REGULATOR_SUPPLY_NAME_LENGTH];
+ struct gpio_desc *gpio;
+ struct regulator_dev *rdev;
+ struct regulator_desc rdesc;
+ } regulator;
+
+ struct int3472_gpio_clock {
+ struct clk *clk;
+ struct clk_hw clk_hw;
+ struct clk_lookup *cl;
+ struct gpio_desc *ena_gpio;
+ struct gpio_desc *led_gpio;
+ u32 frequency;
+ } clock;
+
+ unsigned int ngpios; /* how many GPIOs have we seen */
+ unsigned int n_sensor_gpios; /* how many have we mapped to sensor */
+ struct gpiod_lookup_table gpios;
+};
+
+int skl_int3472_discrete_probe(struct platform_device *pdev);
+int skl_int3472_discrete_remove(struct platform_device *pdev);
+int skl_int3472_tps68470_probe(struct i2c_client *client);
+union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev,
+ char *id);
+int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb);
+
+int skl_int3472_register_clock(struct int3472_discrete_device *int3472);
+void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472);
+
+int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
+ struct acpi_resource_gpio *agpio);
+void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472);
+
+#endif
diff --git a/drivers/platform/x86/intel/int3472/intel_skl_int3472_discrete.c b/drivers/platform/x86/intel/int3472/intel_skl_int3472_discrete.c
new file mode 100644
index 000000000000..9fe0a2527e1c
--- /dev/null
+++ b/drivers/platform/x86/intel/int3472/intel_skl_int3472_discrete.c
@@ -0,0 +1,413 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#include <linux/acpi.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/overflow.h>
+#include <linux/platform_device.h>
+#include <linux/uuid.h>
+
+#include "intel_skl_int3472_common.h"
+
+/*
+ * 79234640-9e10-4fea-a5c1-b5aa8b19756f
+ * This _DSM GUID returns information about the GPIO lines mapped to a
+ * discrete INT3472 device. Function number 1 returns a count of the GPIO
+ * lines that are mapped. Subsequent functions return 32 bit ints encoding
+ * information about the GPIO line, including its purpose.
+ */
+static const guid_t int3472_gpio_guid =
+ GUID_INIT(0x79234640, 0x9e10, 0x4fea,
+ 0xa5, 0xc1, 0xb5, 0xaa, 0x8b, 0x19, 0x75, 0x6f);
+
+/*
+ * 822ace8f-2814-4174-a56b-5f029fe079ee
+ * This _DSM GUID returns a string from the sensor device, which acts as a
+ * module identifier.
+ */
+static const guid_t cio2_sensor_module_guid =
+ GUID_INIT(0x822ace8f, 0x2814, 0x4174,
+ 0xa5, 0x6b, 0x5f, 0x02, 0x9f, 0xe0, 0x79, 0xee);
+
+/*
+ * Here follows platform specific mapping information that we can pass to
+ * the functions mapping resources to the sensors. Where the sensors have
+ * a power enable pin defined in DSDT we need to provide a supply name so
+ * the sensor drivers can find the regulator. The device name will be derived
+ * from the sensor's ACPI device within the code. Optionally, we can provide a
+ * NULL terminated array of function name mappings to deal with any platform
+ * specific deviations from the documented behaviour of GPIOs.
+ *
+ * Map a GPIO function name to NULL to prevent the driver from mapping that
+ * GPIO at all.
+ */
+
+static const struct int3472_gpio_function_remap ov2680_gpio_function_remaps[] = {
+ { "reset", NULL },
+ { "powerdown", "reset" },
+ { }
+};
+
+static const struct int3472_sensor_config int3472_sensor_configs[] = {
+ /* Lenovo Miix 510-12ISK - OV2680, Front */
+ { "GNDF140809R", { 0 }, ov2680_gpio_function_remaps },
+ /* Lenovo Miix 510-12ISK - OV5648, Rear */
+ { "GEFF150023R", REGULATOR_SUPPLY("avdd", NULL), NULL },
+ /* Surface Go 1&2 - OV5693, Front */
+ { "YHCU", REGULATOR_SUPPLY("avdd", NULL), NULL },
+};
+
+static const struct int3472_sensor_config *
+skl_int3472_get_sensor_module_config(struct int3472_discrete_device *int3472)
+{
+ union acpi_object *obj;
+ unsigned int i;
+
+ obj = acpi_evaluate_dsm_typed(int3472->sensor->handle,
+ &cio2_sensor_module_guid, 0x00,
+ 0x01, NULL, ACPI_TYPE_STRING);
+
+ if (!obj) {
+ dev_err(int3472->dev,
+ "Failed to get sensor module string from _DSM\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ if (obj->string.type != ACPI_TYPE_STRING) {
+ dev_err(int3472->dev,
+ "Sensor _DSM returned a non-string value\n");
+
+ ACPI_FREE(obj);
+ return ERR_PTR(-EINVAL);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(int3472_sensor_configs); i++) {
+ if (!strcmp(int3472_sensor_configs[i].sensor_module_name,
+ obj->string.pointer))
+ break;
+ }
+
+ ACPI_FREE(obj);
+
+ if (i >= ARRAY_SIZE(int3472_sensor_configs))
+ return ERR_PTR(-EINVAL);
+
+ return &int3472_sensor_configs[i];
+}
+
+static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472,
+ struct acpi_resource_gpio *agpio,
+ const char *func, u32 polarity)
+{
+ const struct int3472_sensor_config *sensor_config;
+ char *path = agpio->resource_source.string_ptr;
+ struct gpiod_lookup *table_entry;
+ struct acpi_device *adev;
+ acpi_handle handle;
+ acpi_status status;
+ int ret;
+
+ if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) {
+ dev_warn(int3472->dev, "Too many GPIOs mapped\n");
+ return -EINVAL;
+ }
+
+ sensor_config = int3472->sensor_config;
+ if (!IS_ERR(sensor_config) && sensor_config->function_maps) {
+ const struct int3472_gpio_function_remap *remap;
+
+ for (remap = sensor_config->function_maps; remap->documented; remap++) {
+ if (!strcmp(func, remap->documented)) {
+ func = remap->actual;
+ break;
+ }
+ }
+ }
+
+ /* Functions mapped to NULL should not be mapped to the sensor */
+ if (!func)
+ return 0;
+
+ status = acpi_get_handle(NULL, path, &handle);
+ if (ACPI_FAILURE(status))
+ return -EINVAL;
+
+ ret = acpi_bus_get_device(handle, &adev);
+ if (ret)
+ return -ENODEV;
+
+ table_entry = &int3472->gpios.table[int3472->n_sensor_gpios];
+ table_entry->key = acpi_dev_name(adev);
+ table_entry->chip_hwnum = agpio->pin_table[0];
+ table_entry->con_id = func;
+ table_entry->idx = 0;
+ table_entry->flags = polarity;
+
+ int3472->n_sensor_gpios++;
+
+ return 0;
+}
+
+static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472,
+ struct acpi_resource_gpio *agpio, u8 type)
+{
+ char *path = agpio->resource_source.string_ptr;
+ u16 pin = agpio->pin_table[0];
+ struct gpio_desc *gpio;
+
+ switch (type) {
+ case INT3472_GPIO_TYPE_CLK_ENABLE:
+ gpio = acpi_get_and_request_gpiod(path, pin, "int3472,clk-enable");
+ if (IS_ERR(gpio))
+ return (PTR_ERR(gpio));
+
+ int3472->clock.ena_gpio = gpio;
+ break;
+ case INT3472_GPIO_TYPE_PRIVACY_LED:
+ gpio = acpi_get_and_request_gpiod(path, pin, "int3472,privacy-led");
+ if (IS_ERR(gpio))
+ return (PTR_ERR(gpio));
+
+ int3472->clock.led_gpio = gpio;
+ break;
+ default:
+ dev_err(int3472->dev, "Invalid GPIO type 0x%02x for clock\n", type);
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * skl_int3472_handle_gpio_resources: Map PMIC resources to consuming sensor
+ * @ares: A pointer to a &struct acpi_resource
+ * @data: A pointer to a &struct int3472_discrete_device
+ *
+ * This function handles GPIO resources that are against an INT3472
+ * ACPI device, by checking the value of the corresponding _DSM entry.
+ * This will return a 32bit int, where the lowest byte represents the
+ * function of the GPIO pin:
+ *
+ * 0x00 Reset
+ * 0x01 Power down
+ * 0x0b Power enable
+ * 0x0c Clock enable
+ * 0x0d Privacy LED
+ *
+ * There are some known platform specific quirks where that does not quite
+ * hold up; for example where a pin with type 0x01 (Power down) is mapped to
+ * a sensor pin that performs a reset function or entries in _CRS and _DSM that
+ * do not actually correspond to a physical connection. These will be handled
+ * by the mapping sub-functions.
+ *
+ * GPIOs will either be mapped directly to the sensor device or else used
+ * to create clocks and regulators via the usual frameworks.
+ *
+ * Return:
+ * * 1 - To continue the loop
+ * * 0 - When all resources found are handled properly.
+ * * -EINVAL - If the resource is not a GPIO IO resource
+ * * -ENODEV - If the resource has no corresponding _DSM entry
+ * * -Other - Errors propagated from one of the sub-functions.
+ */
+static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
+ void *data)
+{
+ struct int3472_discrete_device *int3472 = data;
+ struct acpi_resource_gpio *agpio;
+ union acpi_object *obj;
+ const char *err_msg;
+ int ret;
+ u8 type;
+
+ if (!acpi_gpio_get_io_resource(ares, &agpio))
+ return 1;
+
+ /*
+ * ngpios + 2 because the index of this _DSM function is 1-based and
+ * the first function is just a count.
+ */
+ obj = acpi_evaluate_dsm_typed(int3472->adev->handle,
+ &int3472_gpio_guid, 0x00,
+ int3472->ngpios + 2,
+ NULL, ACPI_TYPE_INTEGER);
+
+ if (!obj) {
+ dev_warn(int3472->dev, "No _DSM entry for GPIO pin %u\n",
+ agpio->pin_table[0]);
+ return 1;
+ }
+
+ type = obj->integer.value & 0xff;
+
+ switch (type) {
+ case INT3472_GPIO_TYPE_RESET:
+ ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, "reset",
+ GPIO_ACTIVE_LOW);
+ if (ret)
+ err_msg = "Failed to map reset pin to sensor\n";
+
+ break;
+ case INT3472_GPIO_TYPE_POWERDOWN:
+ ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, "powerdown",
+ GPIO_ACTIVE_LOW);
+ if (ret)
+ err_msg = "Failed to map powerdown pin to sensor\n";
+
+ break;
+ case INT3472_GPIO_TYPE_CLK_ENABLE:
+ case INT3472_GPIO_TYPE_PRIVACY_LED:
+ ret = skl_int3472_map_gpio_to_clk(int3472, agpio, type);
+ if (ret)
+ err_msg = "Failed to map GPIO to clock\n";
+
+ break;
+ case INT3472_GPIO_TYPE_POWER_ENABLE:
+ ret = skl_int3472_register_regulator(int3472, agpio);
+ if (ret)
+ err_msg = "Failed to map regulator to sensor\n";
+
+ break;
+ default:
+ dev_warn(int3472->dev,
+ "GPIO type 0x%02x unknown; the sensor may not work\n",
+ type);
+ ret = 1;
+ break;
+ }
+
+ int3472->ngpios++;
+ ACPI_FREE(obj);
+
+ if (ret < 0)
+ return dev_err_probe(int3472->dev, ret, err_msg);
+
+ return ret;
+}
+
+static int skl_int3472_parse_crs(struct int3472_discrete_device *int3472)
+{
+ LIST_HEAD(resource_list);
+ int ret;
+
+ /*
+ * No error check, because not having a sensor config is not necessarily
+ * a failure mode.
+ */
+ int3472->sensor_config = skl_int3472_get_sensor_module_config(int3472);
+
+ ret = acpi_dev_get_resources(int3472->adev, &resource_list,
+ skl_int3472_handle_gpio_resources,
+ int3472);
+ if (ret < 0)
+ return ret;
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ /*
+ * If we find no clock enable GPIO pin then the privacy LED won't work.
+ * We've never seen that situation, but it's possible. Warn the user so
+ * it's clear what's happened.
+ */
+ if (int3472->clock.ena_gpio) {
+ ret = skl_int3472_register_clock(int3472);
+ if (ret)
+ return ret;
+ } else {
+ if (int3472->clock.led_gpio)
+ dev_warn(int3472->dev,
+ "No clk GPIO. The privacy LED won't work\n");
+ }
+
+ int3472->gpios.dev_id = int3472->sensor_name;
+ gpiod_add_lookup_table(&int3472->gpios);
+
+ return 0;
+}
+
+int skl_int3472_discrete_probe(struct platform_device *pdev)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
+ struct int3472_discrete_device *int3472;
+ struct int3472_cldb cldb;
+ int ret;
+
+ ret = skl_int3472_fill_cldb(adev, &cldb);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't fill CLDB structure\n");
+ return ret;
+ }
+
+ if (cldb.control_logic_type != 1) {
+ dev_err(&pdev->dev, "Unsupported control logic type %u\n",
+ cldb.control_logic_type);
+ return -EINVAL;
+ }
+
+ /* Max num GPIOs we've seen plus a terminator */
+ int3472 = devm_kzalloc(&pdev->dev, struct_size(int3472, gpios.table,
+ INT3472_MAX_SENSOR_GPIOS + 1), GFP_KERNEL);
+ if (!int3472)
+ return -ENOMEM;
+
+ int3472->adev = adev;
+ int3472->dev = &pdev->dev;
+ platform_set_drvdata(pdev, int3472);
+
+ int3472->sensor = acpi_dev_get_first_consumer_dev(adev);
+ if (!int3472->sensor) {
+ dev_err(&pdev->dev, "INT3472 seems to have no dependents.\n");
+ return -ENODEV;
+ }
+
+ int3472->sensor_name = devm_kasprintf(int3472->dev, GFP_KERNEL,
+ I2C_DEV_NAME_FORMAT,
+ acpi_dev_name(int3472->sensor));
+ if (!int3472->sensor_name) {
+ ret = -ENOMEM;
+ goto err_put_sensor;
+ }
+
+ /*
+ * Initialising this list means we can call gpiod_remove_lookup_table()
+ * in failure paths without issue.
+ */
+ INIT_LIST_HEAD(&int3472->gpios.list);
+
+ ret = skl_int3472_parse_crs(int3472);
+ if (ret) {
+ skl_int3472_discrete_remove(pdev);
+ return ret;
+ }
+
+ return 0;
+
+err_put_sensor:
+ acpi_dev_put(int3472->sensor);
+
+ return ret;
+}
+
+int skl_int3472_discrete_remove(struct platform_device *pdev)
+{
+ struct int3472_discrete_device *int3472 = platform_get_drvdata(pdev);
+
+ gpiod_remove_lookup_table(&int3472->gpios);
+
+ if (int3472->clock.ena_gpio)
+ skl_int3472_unregister_clock(int3472);
+
+ gpiod_put(int3472->clock.ena_gpio);
+ gpiod_put(int3472->clock.led_gpio);
+
+ skl_int3472_unregister_regulator(int3472);
+
+ return 0;
+}
diff --git a/drivers/platform/x86/intel/int3472/intel_skl_int3472_tps68470.c b/drivers/platform/x86/intel/int3472/intel_skl_int3472_tps68470.c
new file mode 100644
index 000000000000..c05b4cf502fe
--- /dev/null
+++ b/drivers/platform/x86/intel/int3472/intel_skl_int3472_tps68470.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps68470.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "intel_skl_int3472_common.h"
+
+#define DESIGNED_FOR_CHROMEOS 1
+#define DESIGNED_FOR_WINDOWS 2
+
+static const struct mfd_cell tps68470_cros[] = {
+ { .name = "tps68470-gpio" },
+ { .name = "tps68470_pmic_opregion" },
+};
+
+static const struct mfd_cell tps68470_win[] = {
+ { .name = "tps68470-gpio" },
+ { .name = "tps68470-clk" },
+ { .name = "tps68470-regulator" },
+};
+
+static const struct regmap_config tps68470_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = TPS68470_REG_MAX,
+};
+
+static int tps68470_chip_init(struct device *dev, struct regmap *regmap)
+{
+ unsigned int version;
+ int ret;
+
+ /* Force software reset */
+ ret = regmap_write(regmap, TPS68470_REG_RESET, TPS68470_REG_RESET_MASK);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(regmap, TPS68470_REG_REVID, &version);
+ if (ret) {
+ dev_err(dev, "Failed to read revision register: %d\n", ret);
+ return ret;
+ }
+
+ dev_info(dev, "TPS68470 REVID: 0x%02x\n", version);
+
+ return 0;
+}
+
+/** skl_int3472_tps68470_calc_type: Check what platform a device is designed for
+ * @adev: A pointer to a &struct acpi_device
+ *
+ * Check CLDB buffer against the PMIC's adev. If present, then we check
+ * the value of control_logic_type field and follow one of the
+ * following scenarios:
+ *
+ * 1. No CLDB - likely ACPI tables designed for ChromeOS. We
+ * create platform devices for the GPIOs and OpRegion drivers.
+ *
+ * 2. CLDB, with control_logic_type = 2 - probably ACPI tables
+ * made for Windows 2-in-1 platforms. Register pdevs for GPIO,
+ * Clock and Regulator drivers to bind to.
+ *
+ * 3. Any other value in control_logic_type, we should never have
+ * gotten to this point; fail probe and return.
+ *
+ * Return:
+ * * 1 Device intended for ChromeOS
+ * * 2 Device intended for Windows
+ * * -EINVAL Where @adev has an object named CLDB but it does not conform to
+ * our expectations
+ */
+static int skl_int3472_tps68470_calc_type(struct acpi_device *adev)
+{
+ struct int3472_cldb cldb = { 0 };
+ int ret;
+
+ /*
+ * A CLDB buffer that exists, but which does not match our expectations
+ * should trigger an error so we don't blindly continue.
+ */
+ ret = skl_int3472_fill_cldb(adev, &cldb);
+ if (ret && ret != -ENODEV)
+ return ret;
+
+ if (ret)
+ return DESIGNED_FOR_CHROMEOS;
+
+ if (cldb.control_logic_type != 2)
+ return -EINVAL;
+
+ return DESIGNED_FOR_WINDOWS;
+}
+
+int skl_int3472_tps68470_probe(struct i2c_client *client)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&client->dev);
+ struct regmap *regmap;
+ int device_type;
+ int ret;
+
+ regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "Failed to create regmap: %ld\n", PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ i2c_set_clientdata(client, regmap);
+
+ ret = tps68470_chip_init(&client->dev, regmap);
+ if (ret < 0) {
+ dev_err(&client->dev, "TPS68470 init error %d\n", ret);
+ return ret;
+ }
+
+ device_type = skl_int3472_tps68470_calc_type(adev);
+ switch (device_type) {
+ case DESIGNED_FOR_WINDOWS:
+ ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
+ tps68470_win, ARRAY_SIZE(tps68470_win),
+ NULL, 0, NULL);
+ break;
+ case DESIGNED_FOR_CHROMEOS:
+ ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
+ tps68470_cros, ARRAY_SIZE(tps68470_cros),
+ NULL, 0, NULL);
+ break;
+ default:
+ dev_err(&client->dev, "Failed to add MFD devices\n");
+ return device_type;
+ }
+
+ return ret;
+}
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
index bffe548187ee..4dfdbfca6841 100644
--- a/drivers/platform/x86/intel_ips.c
+++ b/drivers/platform/x86/intel_ips.c
@@ -829,7 +829,7 @@ static u16 calc_avg_temp(struct ips_driver *ips, u16 *array)
static u16 read_mgtv(struct ips_driver *ips)
{
- u16 ret;
+ u16 __maybe_unused ret;
u64 slope, offset;
u64 val;
diff --git a/drivers/platform/x86/intel_pmt_crashlog.c b/drivers/platform/x86/intel_pmt_crashlog.c
index 92d315a16cfd..56963ceb6345 100644
--- a/drivers/platform/x86/intel_pmt_crashlog.c
+++ b/drivers/platform/x86/intel_pmt_crashlog.c
@@ -218,7 +218,7 @@ static struct attribute *pmt_crashlog_attrs[] = {
NULL
};
-static struct attribute_group pmt_crashlog_group = {
+static const struct attribute_group pmt_crashlog_group = {
.attrs = pmt_crashlog_attrs,
};
diff --git a/drivers/platform/x86/intel_speed_select_if/isst_if_common.c b/drivers/platform/x86/intel_speed_select_if/isst_if_common.c
index 0c2aa22c7a12..6f0cc679c8e5 100644
--- a/drivers/platform/x86/intel_speed_select_if/isst_if_common.c
+++ b/drivers/platform/x86/intel_speed_select_if/isst_if_common.c
@@ -281,10 +281,69 @@ static int isst_if_get_platform_info(void __user *argp)
struct isst_if_cpu_info {
/* For BUS 0 and BUS 1 only, which we need for PUNIT interface */
int bus_info[2];
+ struct pci_dev *pci_dev[2];
int punit_cpu_id;
+ int numa_node;
};
static struct isst_if_cpu_info *isst_cpu_info;
+#define ISST_MAX_PCI_DOMAINS 8
+
+static struct pci_dev *_isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn)
+{
+ struct pci_dev *matched_pci_dev = NULL;
+ struct pci_dev *pci_dev = NULL;
+ int no_matches = 0;
+ int i, 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;
+
+ for (i = 0; i < ISST_MAX_PCI_DOMAINS; ++i) {
+ struct pci_dev *_pci_dev;
+ int node;
+
+ _pci_dev = pci_get_domain_bus_and_slot(i, bus_number, PCI_DEVFN(dev, fn));
+ if (!_pci_dev)
+ continue;
+
+ ++no_matches;
+ if (!matched_pci_dev)
+ matched_pci_dev = _pci_dev;
+
+ node = dev_to_node(&_pci_dev->dev);
+ if (node == NUMA_NO_NODE) {
+ pr_info("Fail to get numa node for CPU:%d bus:%d dev:%d fn:%d\n",
+ cpu, bus_no, dev, fn);
+ continue;
+ }
+
+ if (node == isst_cpu_info[cpu].numa_node) {
+ pci_dev = _pci_dev;
+ break;
+ }
+ }
+
+ /*
+ * If there is no numa matched pci_dev, then there can be following cases:
+ * 1. CONFIG_NUMA is not defined: In this case if there is only single device
+ * match, then we don't need numa information. Simply return last match.
+ * Othewise return NULL.
+ * 2. NUMA information is not exposed via _SEG method. In this case it is similar
+ * to case 1.
+ * 3. Numa information doesn't match with CPU numa node and more than one match
+ * return NULL.
+ */
+ if (!pci_dev && no_matches == 1)
+ pci_dev = matched_pci_dev;
+
+ return pci_dev;
+}
/**
* isst_if_get_pci_dev() - Get the PCI device instance for a CPU
@@ -300,17 +359,18 @@ static struct isst_if_cpu_info *isst_cpu_info;
*/
struct pci_dev *isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn)
{
- int bus_number;
+ struct pci_dev *pci_dev;
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;
+ pci_dev = isst_cpu_info[cpu].pci_dev[bus_no];
+
+ if (pci_dev && pci_dev->devfn == PCI_DEVFN(dev, fn))
+ return pci_dev;
- return pci_get_domain_bus_and_slot(0, bus_number, PCI_DEVFN(dev, fn));
+ return _isst_if_get_pci_dev(cpu, bus_no, dev, fn);
}
EXPORT_SYMBOL_GPL(isst_if_get_pci_dev);
@@ -327,6 +387,8 @@ static int isst_if_cpu_online(unsigned int cpu)
} else {
isst_cpu_info[cpu].bus_info[0] = data & 0xff;
isst_cpu_info[cpu].bus_info[1] = (data >> 8) & 0xff;
+ isst_cpu_info[cpu].pci_dev[0] = _isst_if_get_pci_dev(cpu, 0, 0, 1);
+ isst_cpu_info[cpu].pci_dev[1] = _isst_if_get_pci_dev(cpu, 1, 30, 1);
}
ret = rdmsrl_safe(MSR_THREAD_ID_INFO, &data);
@@ -335,6 +397,7 @@ static int isst_if_cpu_online(unsigned int cpu)
return ret;
}
isst_cpu_info[cpu].punit_cpu_id = data;
+ isst_cpu_info[cpu].numa_node = cpu_to_node(cpu);
isst_restore_msr_local(cpu);
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
index d5cec6e35bb8..7ee010aa740a 100644
--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -388,7 +388,7 @@ MODULE_PARM_DESC(force,
"Disable the DMI check and forces the driver to be loaded");
static bool debug;
-module_param(debug, bool, S_IRUGO | S_IWUSR);
+module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug enabled or not");
static int sabi_command(struct samsung_laptop *samsung, u16 command,
@@ -705,7 +705,7 @@ static ssize_t set_performance_level(struct device *dev,
return count;
}
-static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(performance_level, 0644,
get_performance_level, set_performance_level);
static int read_battery_life_extender(struct samsung_laptop *samsung)
@@ -774,7 +774,7 @@ static ssize_t set_battery_life_extender(struct device *dev,
return count;
}
-static DEVICE_ATTR(battery_life_extender, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(battery_life_extender, 0644,
get_battery_life_extender, set_battery_life_extender);
static int read_usb_charge(struct samsung_laptop *samsung)
@@ -843,7 +843,7 @@ static ssize_t set_usb_charge(struct device *dev,
return count;
}
-static DEVICE_ATTR(usb_charge, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(usb_charge, 0644,
get_usb_charge, set_usb_charge);
static int read_lid_handling(struct samsung_laptop *samsung)
@@ -908,7 +908,7 @@ static ssize_t set_lid_handling(struct device *dev,
return count;
}
-static DEVICE_ATTR(lid_handling, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(lid_handling, 0644,
get_lid_handling, set_lid_handling);
static struct attribute *platform_attributes[] = {
@@ -1291,24 +1291,17 @@ static void samsung_debugfs_init(struct samsung_laptop *samsung)
samsung->debug.sdiag_wrapper.data = samsung->sdiag;
samsung->debug.sdiag_wrapper.size = strlen(samsung->sdiag);
- 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,
+ debugfs_create_u16("command", 0644, root, &samsung->debug.command);
+ debugfs_create_u32("d0", 0644, root, &samsung->debug.data.d0);
+ debugfs_create_u32("d1", 0644, root, &samsung->debug.data.d1);
+ debugfs_create_u16("d2", 0644, root, &samsung->debug.data.d2);
+ debugfs_create_u8("d3", 0644, root, &samsung->debug.data.d3);
+ debugfs_create_blob("data", 0444, root, &samsung->debug.data_wrapper);
+ debugfs_create_blob("f0000_segment", 0400, root,
&samsung->debug.f0000_wrapper);
- debugfs_create_file("call", S_IFREG | S_IRUGO, root, samsung,
+ debugfs_create_file("call", 0444, root, samsung,
&samsung_laptop_call_fops);
- debugfs_create_blob("sdiag", S_IRUGO | S_IWUSR, root,
- &samsung->debug.sdiag_wrapper);
+ debugfs_create_blob("sdiag", 0444, root, &samsung->debug.sdiag_wrapper);
}
static void samsung_sabi_exit(struct samsung_laptop *samsung)
diff --git a/drivers/platform/x86/tc1100-wmi.c b/drivers/platform/x86/tc1100-wmi.c
index 803920b6f01d..9072eb302618 100644
--- a/drivers/platform/x86/tc1100-wmi.c
+++ b/drivers/platform/x86/tc1100-wmi.c
@@ -156,7 +156,7 @@ static struct attribute *tc1100_attributes[] = {
NULL
};
-static struct attribute_group tc1100_attribute_group = {
+static const struct attribute_group tc1100_attribute_group = {
.attrs = tc1100_attributes,
};
diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
new file mode 100644
index 000000000000..3671b5d20613
--- /dev/null
+++ b/drivers/platform/x86/think-lmi.c
@@ -0,0 +1,904 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Think LMI BIOS configuration driver
+ *
+ * Copyright(C) 2019-2021 Lenovo
+ *
+ * Original code from Thinkpad-wmi project https://github.com/iksaif/thinkpad-wmi
+ * Copyright(C) 2017 Corentin Chary <corentin.chary@gmail.com>
+ * Distributed under the GPL-2.0 license
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/acpi.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/wmi.h>
+#include "firmware_attributes_class.h"
+#include "think-lmi.h"
+
+/*
+ * Name:
+ * Lenovo_BiosSetting
+ * Description:
+ * Get item name and settings for current LMI instance.
+ * Type:
+ * Query
+ * Returns:
+ * "Item,Value"
+ * Example:
+ * "WakeOnLAN,Enable"
+ */
+#define LENOVO_BIOS_SETTING_GUID "51F5230E-9677-46CD-A1CF-C0B23EE34DB7"
+
+/*
+ * Name:
+ * Lenovo_SetBiosSetting
+ * Description:
+ * Change the BIOS setting to the desired value using the Lenovo_SetBiosSetting
+ * class. To save the settings, use the Lenovo_SaveBiosSetting class.
+ * BIOS settings and values are case sensitive.
+ * After making changes to the BIOS settings, you must reboot the computer
+ * before the changes will take effect.
+ * Type:
+ * Method
+ * Arguments:
+ * "Item,Value,Password,Encoding,KbdLang;"
+ * Example:
+ * "WakeOnLAN,Disable,pa55w0rd,ascii,us;"
+ */
+#define LENOVO_SET_BIOS_SETTINGS_GUID "98479A64-33F5-4E33-A707-8E251EBBC3A1"
+
+/*
+ * Name:
+ * Lenovo_SaveBiosSettings
+ * Description:
+ * Save any pending changes in settings.
+ * Type:
+ * Method
+ * Arguments:
+ * "Password,Encoding,KbdLang;"
+ * Example:
+ * "pa55w0rd,ascii,us;"
+ */
+#define LENOVO_SAVE_BIOS_SETTINGS_GUID "6A4B54EF-A5ED-4D33-9455-B0D9B48DF4B3"
+
+/*
+ * Name:
+ * Lenovo_BiosPasswordSettings
+ * Description:
+ * Return BIOS Password settings
+ * Type:
+ * Query
+ * Returns:
+ * PasswordMode, PasswordState, MinLength, MaxLength,
+ * SupportedEncoding, SupportedKeyboard
+ */
+#define LENOVO_BIOS_PASSWORD_SETTINGS_GUID "8ADB159E-1E32-455C-BC93-308A7ED98246"
+
+/*
+ * Name:
+ * Lenovo_SetBiosPassword
+ * Description:
+ * Change a specific password.
+ * - BIOS settings cannot be changed at the same boot as power-on
+ * passwords (POP) and hard disk passwords (HDP). If you want to change
+ * BIOS settings and POP or HDP, you must reboot the system after changing
+ * one of them.
+ * - A password cannot be set using this method when one does not already
+ * exist. Passwords can only be updated or cleared.
+ * Type:
+ * Method
+ * Arguments:
+ * "PasswordType,CurrentPassword,NewPassword,Encoding,KbdLang;"
+ * Example:
+ * "pop,pa55w0rd,newpa55w0rd,ascii,us;”
+ */
+#define LENOVO_SET_BIOS_PASSWORD_GUID "2651D9FD-911C-4B69-B94E-D0DED5963BD7"
+
+/*
+ * Name:
+ * Lenovo_GetBiosSelections
+ * Description:
+ * Return a list of valid settings for a given item.
+ * Type:
+ * Method
+ * Arguments:
+ * "Item"
+ * Returns:
+ * "Value1,Value2,Value3,..."
+ * Example:
+ * -> "FlashOverLAN"
+ * <- "Enabled,Disabled"
+ */
+#define LENOVO_GET_BIOS_SELECTIONS_GUID "7364651A-132F-4FE7-ADAA-40C6C7EE2E3B"
+
+#define TLMI_POP_PWD (1 << 0)
+#define TLMI_PAP_PWD (1 << 1)
+#define to_tlmi_pwd_setting(kobj) container_of(kobj, struct tlmi_pwd_setting, kobj)
+#define to_tlmi_attr_setting(kobj) container_of(kobj, struct tlmi_attr_setting, kobj)
+
+static const struct tlmi_err_codes tlmi_errs[] = {
+ {"Success", 0},
+ {"Not Supported", -EOPNOTSUPP},
+ {"Invalid Parameter", -EINVAL},
+ {"Access Denied", -EACCES},
+ {"System Busy", -EBUSY},
+};
+
+static const char * const encoding_options[] = {
+ [TLMI_ENCODING_ASCII] = "ascii",
+ [TLMI_ENCODING_SCANCODE] = "scancode",
+};
+static struct think_lmi tlmi_priv;
+static struct class *fw_attr_class;
+
+/* ------ Utility functions ------------*/
+/* Convert BIOS WMI error string to suitable error code */
+static int tlmi_errstr_to_err(const char *errstr)
+{
+ int i;
+
+ for (i = 0; i < sizeof(tlmi_errs)/sizeof(struct tlmi_err_codes); i++) {
+ if (!strcmp(tlmi_errs[i].err_str, errstr))
+ return tlmi_errs[i].err_code;
+ }
+ return -EPERM;
+}
+
+/* Extract error string from WMI return buffer */
+static int tlmi_extract_error(const struct acpi_buffer *output)
+{
+ const union acpi_object *obj;
+
+ obj = output->pointer;
+ if (!obj)
+ return -ENOMEM;
+ if (obj->type != ACPI_TYPE_STRING || !obj->string.pointer)
+ return -EIO;
+
+ return tlmi_errstr_to_err(obj->string.pointer);
+}
+
+/* Utility function to execute WMI call to BIOS */
+static int tlmi_simple_call(const char *guid, const char *arg)
+{
+ const struct acpi_buffer input = { strlen(arg), (char *)arg };
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ acpi_status status;
+ int i, err;
+
+ /*
+ * Duplicated call required to match BIOS workaround for behavior
+ * seen when WMI accessed via scripting on other OS.
+ */
+ for (i = 0; i < 2; i++) {
+ /* (re)initialize output buffer to default state */
+ output.length = ACPI_ALLOCATE_BUFFER;
+ output.pointer = NULL;
+
+ status = wmi_evaluate_method(guid, 0, 0, &input, &output);
+ if (ACPI_FAILURE(status)) {
+ kfree(output.pointer);
+ return -EIO;
+ }
+ err = tlmi_extract_error(&output);
+ kfree(output.pointer);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+/* Extract output string from WMI return buffer */
+static int tlmi_extract_output_string(const struct acpi_buffer *output,
+ char **string)
+{
+ const union acpi_object *obj;
+ char *s;
+
+ obj = output->pointer;
+ if (!obj)
+ return -ENOMEM;
+ if (obj->type != ACPI_TYPE_STRING || !obj->string.pointer)
+ return -EIO;
+
+ s = kstrdup(obj->string.pointer, GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
+ *string = s;
+ return 0;
+}
+
+/* ------ Core interface functions ------------*/
+
+/* Get password settings from BIOS */
+static int tlmi_get_pwd_settings(struct tlmi_pwdcfg *pwdcfg)
+{
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ const union acpi_object *obj;
+ acpi_status status;
+
+ if (!tlmi_priv.can_get_password_settings)
+ return -EOPNOTSUPP;
+
+ status = wmi_query_block(LENOVO_BIOS_PASSWORD_SETTINGS_GUID, 0,
+ &output);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ obj = output.pointer;
+ if (!obj)
+ return -ENOMEM;
+ if (obj->type != ACPI_TYPE_BUFFER || !obj->buffer.pointer) {
+ kfree(obj);
+ return -EIO;
+ }
+ /*
+ * The size of thinkpad_wmi_pcfg on ThinkStation is larger than ThinkPad.
+ * To make the driver compatible on different brands, we permit it to get
+ * the data in below case.
+ */
+ if (obj->buffer.length < sizeof(struct tlmi_pwdcfg)) {
+ pr_warn("Unknown pwdcfg buffer length %d\n", obj->buffer.length);
+ kfree(obj);
+ return -EIO;
+ }
+ memcpy(pwdcfg, obj->buffer.pointer, sizeof(struct tlmi_pwdcfg));
+ kfree(obj);
+ return 0;
+}
+
+static int tlmi_save_bios_settings(const char *password)
+{
+ return tlmi_simple_call(LENOVO_SAVE_BIOS_SETTINGS_GUID,
+ password);
+}
+
+static int tlmi_setting(int item, char **value, const char *guid_string)
+{
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ acpi_status status;
+ int ret;
+
+ status = wmi_query_block(guid_string, item, &output);
+ if (ACPI_FAILURE(status)) {
+ kfree(output.pointer);
+ return -EIO;
+ }
+
+ ret = tlmi_extract_output_string(&output, value);
+ kfree(output.pointer);
+ return ret;
+}
+
+static int tlmi_get_bios_selections(const char *item, char **value)
+{
+ const struct acpi_buffer input = { strlen(item), (char *)item };
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ acpi_status status;
+ int ret;
+
+ status = wmi_evaluate_method(LENOVO_GET_BIOS_SELECTIONS_GUID,
+ 0, 0, &input, &output);
+
+ if (ACPI_FAILURE(status)) {
+ kfree(output.pointer);
+ return -EIO;
+ }
+
+ ret = tlmi_extract_output_string(&output, value);
+ kfree(output.pointer);
+ return ret;
+}
+
+/* ---- Authentication sysfs --------------------------------------------------------- */
+static ssize_t is_enabled_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
+
+ return sysfs_emit(buf, "%d\n", setting->valid);
+}
+
+static struct kobj_attribute auth_is_pass_set = __ATTR_RO(is_enabled);
+
+static ssize_t current_password_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
+ size_t pwdlen;
+ char *p;
+
+ pwdlen = strlen(buf);
+ /* pwdlen == 0 is allowed to clear the password */
+ if (pwdlen && ((pwdlen < setting->minlen) || (pwdlen > setting->maxlen)))
+ return -EINVAL;
+
+ strscpy(setting->password, buf, setting->maxlen);
+ /* Strip out CR if one is present, setting password won't work if it is present */
+ p = strchrnul(setting->password, '\n');
+ *p = '\0';
+ return count;
+}
+
+static struct kobj_attribute auth_current_password = __ATTR_WO(current_password);
+
+static ssize_t new_password_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
+ char *auth_str, *new_pwd, *p;
+ size_t pwdlen;
+ int ret;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (!tlmi_priv.can_set_bios_password)
+ return -EOPNOTSUPP;
+
+ new_pwd = kstrdup(buf, GFP_KERNEL);
+ if (!new_pwd)
+ return -ENOMEM;
+
+ /* Strip out CR if one is present, setting password won't work if it is present */
+ p = strchrnul(new_pwd, '\n');
+ *p = '\0';
+
+ pwdlen = strlen(new_pwd);
+ /* pwdlen == 0 is allowed to clear the password */
+ if (pwdlen && ((pwdlen < setting->minlen) || (pwdlen > setting->maxlen))) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Format: 'PasswordType,CurrentPw,NewPw,Encoding,KbdLang;' */
+ auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s,%s,%s;",
+ setting->pwd_type, setting->password, new_pwd,
+ encoding_options[setting->encoding], setting->kbdlang);
+ if (!auth_str) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = tlmi_simple_call(LENOVO_SET_BIOS_PASSWORD_GUID, auth_str);
+ kfree(auth_str);
+out:
+ kfree(new_pwd);
+ return ret ?: count;
+}
+
+static struct kobj_attribute auth_new_password = __ATTR_WO(new_password);
+
+static ssize_t min_password_length_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
+
+ return sysfs_emit(buf, "%d\n", setting->minlen);
+}
+
+static struct kobj_attribute auth_min_pass_length = __ATTR_RO(min_password_length);
+
+static ssize_t max_password_length_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
+
+ return sysfs_emit(buf, "%d\n", setting->maxlen);
+}
+static struct kobj_attribute auth_max_pass_length = __ATTR_RO(max_password_length);
+
+static ssize_t mechanism_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "password\n");
+}
+static struct kobj_attribute auth_mechanism = __ATTR_RO(mechanism);
+
+static ssize_t encoding_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
+
+ return sysfs_emit(buf, "%s\n", encoding_options[setting->encoding]);
+}
+
+static ssize_t encoding_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
+ int i;
+
+ /* Scan for a matching profile */
+ i = sysfs_match_string(encoding_options, buf);
+ if (i < 0)
+ return -EINVAL;
+
+ setting->encoding = i;
+ return count;
+}
+
+static struct kobj_attribute auth_encoding = __ATTR_RW(encoding);
+
+static ssize_t kbdlang_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
+
+ return sysfs_emit(buf, "%s\n", setting->kbdlang);
+}
+
+static ssize_t kbdlang_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
+ int length;
+
+ /* Calculate length till '\n' or terminating 0 */
+ length = strchrnul(buf, '\n') - buf;
+ if (!length || length >= TLMI_LANG_MAXLEN)
+ return -EINVAL;
+
+ memcpy(setting->kbdlang, buf, length);
+ setting->kbdlang[length] = '\0';
+ return count;
+}
+
+static struct kobj_attribute auth_kbdlang = __ATTR_RW(kbdlang);
+
+static ssize_t role_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
+
+ return sysfs_emit(buf, "%s\n", setting->role);
+}
+static struct kobj_attribute auth_role = __ATTR_RO(role);
+
+static struct attribute *auth_attrs[] = {
+ &auth_is_pass_set.attr,
+ &auth_min_pass_length.attr,
+ &auth_max_pass_length.attr,
+ &auth_current_password.attr,
+ &auth_new_password.attr,
+ &auth_role.attr,
+ &auth_mechanism.attr,
+ &auth_encoding.attr,
+ &auth_kbdlang.attr,
+ NULL
+};
+
+static const struct attribute_group auth_attr_group = {
+ .attrs = auth_attrs,
+};
+
+/* ---- Attributes sysfs --------------------------------------------------------- */
+static ssize_t display_name_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
+
+ return sysfs_emit(buf, "%s\n", setting->display_name);
+}
+
+static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
+ char *item, *value;
+ int ret;
+
+ ret = tlmi_setting(setting->index, &item, LENOVO_BIOS_SETTING_GUID);
+ if (ret)
+ return ret;
+
+ /* validate and split from `item,value` -> `value` */
+ value = strpbrk(item, ",");
+ if (!value || value == item || !strlen(value + 1))
+ return -EINVAL;
+
+ ret = sysfs_emit(buf, "%s\n", value + 1);
+ kfree(item);
+ return ret;
+}
+
+static ssize_t possible_values_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
+
+ if (!tlmi_priv.can_get_bios_selections)
+ return -EOPNOTSUPP;
+
+ return sysfs_emit(buf, "%s\n", setting->possible_values);
+}
+
+static ssize_t current_value_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
+ char *set_str = NULL, *new_setting = NULL;
+ char *auth_str = NULL;
+ char *p;
+ int ret;
+
+ if (!tlmi_priv.can_set_bios_settings)
+ return -EOPNOTSUPP;
+
+ new_setting = kstrdup(buf, GFP_KERNEL);
+ if (!new_setting)
+ return -ENOMEM;
+
+ /* Strip out CR if one is present */
+ p = strchrnul(new_setting, '\n');
+ *p = '\0';
+
+ if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
+ auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
+ tlmi_priv.pwd_admin->password,
+ encoding_options[tlmi_priv.pwd_admin->encoding],
+ tlmi_priv.pwd_admin->kbdlang);
+ if (!auth_str) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+
+ if (auth_str)
+ set_str = kasprintf(GFP_KERNEL, "%s,%s,%s", setting->display_name,
+ new_setting, auth_str);
+ else
+ set_str = kasprintf(GFP_KERNEL, "%s,%s;", setting->display_name,
+ new_setting);
+ if (!set_str) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = tlmi_simple_call(LENOVO_SET_BIOS_SETTINGS_GUID, set_str);
+ if (ret)
+ goto out;
+
+ if (auth_str)
+ ret = tlmi_save_bios_settings(auth_str);
+ else
+ ret = tlmi_save_bios_settings("");
+
+out:
+ kfree(auth_str);
+ kfree(set_str);
+ kfree(new_setting);
+ return ret ?: count;
+}
+
+static struct kobj_attribute attr_displ_name = __ATTR_RO(display_name);
+
+static struct kobj_attribute attr_possible_values = __ATTR_RO(possible_values);
+
+static struct kobj_attribute attr_current_val = __ATTR_RW_MODE(current_value, 0600);
+
+static struct attribute *tlmi_attrs[] = {
+ &attr_displ_name.attr,
+ &attr_current_val.attr,
+ &attr_possible_values.attr,
+ NULL
+};
+
+static const struct attribute_group tlmi_attr_group = {
+ .attrs = tlmi_attrs,
+};
+
+static ssize_t tlmi_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct kobj_attribute *kattr;
+
+ kattr = container_of(attr, struct kobj_attribute, attr);
+ if (kattr->show)
+ return kattr->show(kobj, kattr, buf);
+ return -EIO;
+}
+
+static ssize_t tlmi_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct kobj_attribute *kattr;
+
+ kattr = container_of(attr, struct kobj_attribute, attr);
+ if (kattr->store)
+ return kattr->store(kobj, kattr, buf, count);
+ return -EIO;
+}
+
+static const struct sysfs_ops tlmi_kobj_sysfs_ops = {
+ .show = tlmi_attr_show,
+ .store = tlmi_attr_store,
+};
+
+static void tlmi_attr_setting_release(struct kobject *kobj)
+{
+ struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
+
+ kfree(setting->possible_values);
+ kfree(setting);
+}
+
+static void tlmi_pwd_setting_release(struct kobject *kobj)
+{
+ struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
+
+ kfree(setting);
+}
+
+static struct kobj_type tlmi_attr_setting_ktype = {
+ .release = &tlmi_attr_setting_release,
+ .sysfs_ops = &tlmi_kobj_sysfs_ops,
+};
+
+static struct kobj_type tlmi_pwd_setting_ktype = {
+ .release = &tlmi_pwd_setting_release,
+ .sysfs_ops = &tlmi_kobj_sysfs_ops,
+};
+
+/* ---- Initialisation --------------------------------------------------------- */
+static void tlmi_release_attr(void)
+{
+ int i;
+
+ /* Attribute structures */
+ for (i = 0; i < TLMI_SETTINGS_COUNT; i++) {
+ if (tlmi_priv.setting[i]) {
+ sysfs_remove_group(&tlmi_priv.setting[i]->kobj, &tlmi_attr_group);
+ kobject_put(&tlmi_priv.setting[i]->kobj);
+ }
+ }
+ kset_unregister(tlmi_priv.attribute_kset);
+
+ /* Authentication structures */
+ sysfs_remove_group(&tlmi_priv.pwd_admin->kobj, &auth_attr_group);
+ kobject_put(&tlmi_priv.pwd_admin->kobj);
+ sysfs_remove_group(&tlmi_priv.pwd_power->kobj, &auth_attr_group);
+ kobject_put(&tlmi_priv.pwd_power->kobj);
+ kset_unregister(tlmi_priv.authentication_kset);
+}
+
+static int tlmi_sysfs_init(void)
+{
+ int i, ret;
+
+ ret = fw_attributes_class_get(&fw_attr_class);
+ if (ret)
+ return ret;
+
+ tlmi_priv.class_dev = device_create(fw_attr_class, NULL, MKDEV(0, 0),
+ NULL, "%s", "thinklmi");
+ if (IS_ERR(tlmi_priv.class_dev)) {
+ ret = PTR_ERR(tlmi_priv.class_dev);
+ goto fail_class_created;
+ }
+
+ tlmi_priv.attribute_kset = kset_create_and_add("attributes", NULL,
+ &tlmi_priv.class_dev->kobj);
+ if (!tlmi_priv.attribute_kset) {
+ ret = -ENOMEM;
+ goto fail_device_created;
+ }
+
+ for (i = 0; i < TLMI_SETTINGS_COUNT; i++) {
+ /* Check if index is a valid setting - skip if it isn't */
+ if (!tlmi_priv.setting[i])
+ continue;
+
+ /* check for duplicate or reserved values */
+ if (kset_find_obj(tlmi_priv.attribute_kset, tlmi_priv.setting[i]->display_name) ||
+ !strcmp(tlmi_priv.setting[i]->display_name, "Reserved")) {
+ pr_debug("duplicate or reserved attribute name found - %s\n",
+ tlmi_priv.setting[i]->display_name);
+ kfree(tlmi_priv.setting[i]->possible_values);
+ kfree(tlmi_priv.setting[i]);
+ tlmi_priv.setting[i] = NULL;
+ continue;
+ }
+
+ /* Build attribute */
+ tlmi_priv.setting[i]->kobj.kset = tlmi_priv.attribute_kset;
+ ret = kobject_init_and_add(&tlmi_priv.setting[i]->kobj, &tlmi_attr_setting_ktype,
+ NULL, "%s", tlmi_priv.setting[i]->display_name);
+ if (ret)
+ goto fail_create_attr;
+
+ ret = sysfs_create_group(&tlmi_priv.setting[i]->kobj, &tlmi_attr_group);
+ if (ret)
+ goto fail_create_attr;
+ }
+
+ /* Create authentication entries */
+ tlmi_priv.authentication_kset = kset_create_and_add("authentication", NULL,
+ &tlmi_priv.class_dev->kobj);
+ if (!tlmi_priv.authentication_kset) {
+ ret = -ENOMEM;
+ goto fail_create_attr;
+ }
+ tlmi_priv.pwd_admin->kobj.kset = tlmi_priv.authentication_kset;
+ ret = kobject_init_and_add(&tlmi_priv.pwd_admin->kobj, &tlmi_pwd_setting_ktype,
+ NULL, "%s", "Admin");
+ if (ret)
+ goto fail_create_attr;
+
+ ret = sysfs_create_group(&tlmi_priv.pwd_admin->kobj, &auth_attr_group);
+ if (ret)
+ goto fail_create_attr;
+
+ tlmi_priv.pwd_power->kobj.kset = tlmi_priv.authentication_kset;
+ ret = kobject_init_and_add(&tlmi_priv.pwd_power->kobj, &tlmi_pwd_setting_ktype,
+ NULL, "%s", "System");
+ if (ret)
+ goto fail_create_attr;
+
+ ret = sysfs_create_group(&tlmi_priv.pwd_power->kobj, &auth_attr_group);
+ if (ret)
+ goto fail_create_attr;
+
+ return ret;
+
+fail_create_attr:
+ tlmi_release_attr();
+fail_device_created:
+ device_destroy(fw_attr_class, MKDEV(0, 0));
+fail_class_created:
+ fw_attributes_class_put();
+ return ret;
+}
+
+/* ---- Base Driver -------------------------------------------------------- */
+static int tlmi_analyze(void)
+{
+ struct tlmi_pwdcfg pwdcfg;
+ acpi_status status;
+ int i, ret;
+
+ if (wmi_has_guid(LENOVO_SET_BIOS_SETTINGS_GUID) &&
+ wmi_has_guid(LENOVO_SAVE_BIOS_SETTINGS_GUID))
+ tlmi_priv.can_set_bios_settings = true;
+
+ if (wmi_has_guid(LENOVO_GET_BIOS_SELECTIONS_GUID))
+ tlmi_priv.can_get_bios_selections = true;
+
+ if (wmi_has_guid(LENOVO_SET_BIOS_PASSWORD_GUID))
+ tlmi_priv.can_set_bios_password = true;
+
+ if (wmi_has_guid(LENOVO_BIOS_PASSWORD_SETTINGS_GUID))
+ tlmi_priv.can_get_password_settings = true;
+
+ /*
+ * Try to find the number of valid settings of this machine
+ * and use it to create sysfs attributes.
+ */
+ for (i = 0; i < TLMI_SETTINGS_COUNT; ++i) {
+ struct tlmi_attr_setting *setting;
+ char *item = NULL;
+ char *p;
+
+ tlmi_priv.setting[i] = NULL;
+ status = tlmi_setting(i, &item, LENOVO_BIOS_SETTING_GUID);
+ if (ACPI_FAILURE(status))
+ break;
+ if (!item)
+ break;
+ if (!*item)
+ continue;
+
+ /* It is not allowed to have '/' for file name. Convert it into '\'. */
+ strreplace(item, '/', '\\');
+
+ /* Remove the value part */
+ p = strchrnul(item, ',');
+ *p = '\0';
+
+ /* Create a setting entry */
+ setting = kzalloc(sizeof(*setting), GFP_KERNEL);
+ if (!setting) {
+ ret = -ENOMEM;
+ goto fail_clear_attr;
+ }
+ setting->index = i;
+ strscpy(setting->display_name, item, TLMI_SETTINGS_MAXLEN);
+ /* If BIOS selections supported, load those */
+ if (tlmi_priv.can_get_bios_selections) {
+ ret = tlmi_get_bios_selections(setting->display_name,
+ &setting->possible_values);
+ if (ret || !setting->possible_values)
+ pr_info("Error retrieving possible values for %d : %s\n",
+ i, setting->display_name);
+ }
+ tlmi_priv.setting[i] = setting;
+ tlmi_priv.settings_count++;
+ kfree(item);
+ }
+
+ /* Create password setting structure */
+ ret = tlmi_get_pwd_settings(&pwdcfg);
+ if (ret)
+ goto fail_clear_attr;
+
+ tlmi_priv.pwd_admin = kzalloc(sizeof(struct tlmi_pwd_setting), GFP_KERNEL);
+ if (!tlmi_priv.pwd_admin) {
+ ret = -ENOMEM;
+ goto fail_clear_attr;
+ }
+ strscpy(tlmi_priv.pwd_admin->kbdlang, "us", TLMI_LANG_MAXLEN);
+ tlmi_priv.pwd_admin->encoding = TLMI_ENCODING_ASCII;
+ tlmi_priv.pwd_admin->pwd_type = "pap";
+ tlmi_priv.pwd_admin->role = "bios-admin";
+ tlmi_priv.pwd_admin->minlen = pwdcfg.min_length;
+ if (WARN_ON(pwdcfg.max_length >= TLMI_PWD_BUFSIZE))
+ pwdcfg.max_length = TLMI_PWD_BUFSIZE - 1;
+ tlmi_priv.pwd_admin->maxlen = pwdcfg.max_length;
+ if (pwdcfg.password_state & TLMI_PAP_PWD)
+ tlmi_priv.pwd_admin->valid = true;
+
+ tlmi_priv.pwd_power = kzalloc(sizeof(struct tlmi_pwd_setting), GFP_KERNEL);
+ if (!tlmi_priv.pwd_power) {
+ ret = -ENOMEM;
+ goto fail_clear_attr;
+ }
+ strscpy(tlmi_priv.pwd_power->kbdlang, "us", TLMI_LANG_MAXLEN);
+ tlmi_priv.pwd_power->encoding = TLMI_ENCODING_ASCII;
+ tlmi_priv.pwd_power->pwd_type = "pop";
+ tlmi_priv.pwd_power->role = "power-on";
+ tlmi_priv.pwd_power->minlen = pwdcfg.min_length;
+ tlmi_priv.pwd_power->maxlen = pwdcfg.max_length;
+
+ if (pwdcfg.password_state & TLMI_POP_PWD)
+ tlmi_priv.pwd_power->valid = true;
+
+ return 0;
+
+fail_clear_attr:
+ for (i = 0; i < TLMI_SETTINGS_COUNT; ++i)
+ kfree(tlmi_priv.setting[i]);
+ return ret;
+}
+
+static void tlmi_remove(struct wmi_device *wdev)
+{
+ tlmi_release_attr();
+ device_destroy(fw_attr_class, MKDEV(0, 0));
+ fw_attributes_class_put();
+}
+
+static int tlmi_probe(struct wmi_device *wdev, const void *context)
+{
+ tlmi_analyze();
+ return tlmi_sysfs_init();
+}
+
+static const struct wmi_device_id tlmi_id_table[] = {
+ { .guid_string = LENOVO_BIOS_SETTING_GUID },
+ { }
+};
+MODULE_DEVICE_TABLE(wmi, tlmi_id_table);
+
+static struct wmi_driver tlmi_driver = {
+ .driver = {
+ .name = "think-lmi",
+ },
+ .id_table = tlmi_id_table,
+ .probe = tlmi_probe,
+ .remove = tlmi_remove,
+};
+
+MODULE_AUTHOR("Sugumaran L <slacshiminar@lenovo.com>");
+MODULE_AUTHOR("Mark Pearson <markpearson@lenovo.com>");
+MODULE_AUTHOR("Corentin Chary <corentin.chary@gmail.com>");
+MODULE_DESCRIPTION("ThinkLMI Driver");
+MODULE_LICENSE("GPL");
+
+module_wmi_driver(tlmi_driver);
diff --git a/drivers/platform/x86/think-lmi.h b/drivers/platform/x86/think-lmi.h
new file mode 100644
index 000000000000..6fa8da7af6c7
--- /dev/null
+++ b/drivers/platform/x86/think-lmi.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _THINK_LMI_H_
+#define _THINK_LMI_H_
+
+#include <linux/types.h>
+
+#define TLMI_SETTINGS_COUNT 256
+#define TLMI_SETTINGS_MAXLEN 512
+#define TLMI_PWD_BUFSIZE 129
+#define TLMI_LANG_MAXLEN 4
+
+/* Possible error values */
+struct tlmi_err_codes {
+ const char *err_str;
+ int err_code;
+};
+
+enum encoding_option {
+ TLMI_ENCODING_ASCII,
+ TLMI_ENCODING_SCANCODE,
+};
+
+/* password configuration details */
+struct tlmi_pwdcfg {
+ uint32_t password_mode;
+ uint32_t password_state;
+ uint32_t min_length;
+ uint32_t max_length;
+ uint32_t supported_encodings;
+ uint32_t supported_keyboard;
+};
+
+/* password setting details */
+struct tlmi_pwd_setting {
+ struct kobject kobj;
+ bool valid;
+ char password[TLMI_PWD_BUFSIZE];
+ const char *pwd_type;
+ const char *role;
+ int minlen;
+ int maxlen;
+ enum encoding_option encoding;
+ char kbdlang[TLMI_LANG_MAXLEN];
+};
+
+/* Attribute setting details */
+struct tlmi_attr_setting {
+ struct kobject kobj;
+ int index;
+ char display_name[TLMI_SETTINGS_MAXLEN];
+ char *possible_values;
+};
+
+struct think_lmi {
+ struct wmi_device *wmi_device;
+
+ int settings_count;
+ bool can_set_bios_settings;
+ bool can_get_bios_selections;
+ bool can_set_bios_password;
+ bool can_get_password_settings;
+
+ struct tlmi_attr_setting *setting[TLMI_SETTINGS_COUNT];
+ struct device *class_dev;
+ struct kset *attribute_kset;
+ struct kset *authentication_kset;
+ struct tlmi_pwd_setting *pwd_admin;
+ struct tlmi_pwd_setting *pwd_power;
+};
+
+#endif /* !_THINK_LMI_H_ */
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index edd71e744d27..603156a6e3ed 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -7938,7 +7938,7 @@ static int volume_write(char *buf)
continue;
} else if (sscanf(cmd, "level %u", &l) == 1 &&
l >= 0 && l <= TP_EC_VOLUME_MAX) {
- new_level = l;
+ new_level = l;
continue;
}
}
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index fa7232ad8c39..352508d30467 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -2831,6 +2831,7 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
if (!dev->info_supported && !dev->system_event_supported) {
pr_warn("No hotkey query interface found\n");
+ error = -EINVAL;
goto err_remove_filter;
}
diff --git a/drivers/platform/x86/toshiba_haps.c b/drivers/platform/x86/toshiba_haps.c
index b237bd6b1ee5..49e84095bb01 100644
--- a/drivers/platform/x86/toshiba_haps.c
+++ b/drivers/platform/x86/toshiba_haps.c
@@ -131,7 +131,7 @@ static const struct attribute_group haps_attr_group = {
*/
static void toshiba_haps_notify(struct acpi_device *device, u32 event)
{
- pr_debug("Received event: 0x%x", event);
+ pr_debug("Received event: 0x%x\n", event);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev),
diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c
index bde740d6120e..0e1451b1d9c6 100644
--- a/drivers/platform/x86/touchscreen_dmi.c
+++ b/drivers/platform/x86/touchscreen_dmi.c
@@ -299,6 +299,35 @@ static const struct ts_dmi_data estar_beauty_hd_data = {
.properties = estar_beauty_hd_props,
};
+/* Generic props + data for upside-down mounted GDIX1001 touchscreens */
+static const struct property_entry gdix1001_upside_down_props[] = {
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+ { }
+};
+
+static const struct ts_dmi_data gdix1001_00_upside_down_data = {
+ .acpi_name = "GDIX1001:00",
+ .properties = gdix1001_upside_down_props,
+};
+
+static const struct ts_dmi_data gdix1001_01_upside_down_data = {
+ .acpi_name = "GDIX1001:01",
+ .properties = gdix1001_upside_down_props,
+};
+
+static const struct property_entry glavey_tm800a550l_props[] = {
+ PROPERTY_ENTRY_STRING("firmware-name", "gt912-glavey-tm800a550l.fw"),
+ PROPERTY_ENTRY_STRING("goodix,config-name", "gt912-glavey-tm800a550l.cfg"),
+ PROPERTY_ENTRY_U32("goodix,main-clk", 54),
+ { }
+};
+
+static const struct ts_dmi_data glavey_tm800a550l_data = {
+ .acpi_name = "GDIX1001:00",
+ .properties = glavey_tm800a550l_props,
+};
+
static const struct property_entry gp_electronic_t701_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 960),
PROPERTY_ENTRY_U32("touchscreen-size-y", 640),
@@ -942,7 +971,7 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
},
},
{
- /* Chuwi Hi10 Prus (CWI597) */
+ /* Chuwi Hi10 Pro (CWI529) */
.driver_data = (void *)&chuwi_hi10_pro_data,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"),
@@ -1038,6 +1067,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "eSTAR BEAUTY HD Intel Quad core"),
},
},
+ { /* Glavey TM800A550L */
+ .driver_data = (void *)&glavey_tm800a550l_data,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
+ /* Above strings are too generic, also match on BIOS version */
+ DMI_MATCH(DMI_BIOS_VERSION, "ZY-8-BI-PX4S70VTR400-X423B-005-D"),
+ },
+ },
{
/* GP-electronic T701 */
.driver_data = (void *)&gp_electronic_t701_data,
@@ -1331,6 +1369,24 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
},
},
{
+ /* Teclast X89 (Android version / BIOS) */
+ .driver_data = (void *)&gdix1001_00_upside_down_data,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "WISKY"),
+ DMI_MATCH(DMI_BOARD_NAME, "3G062i"),
+ },
+ },
+ {
+ /* Teclast X89 (Windows version / BIOS) */
+ .driver_data = (void *)&gdix1001_01_upside_down_data,
+ .matches = {
+ /* tPAD is too generic, also match on bios date */
+ DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
+ DMI_MATCH(DMI_BOARD_NAME, "tPAD"),
+ DMI_MATCH(DMI_BIOS_DATE, "12/19/2014"),
+ },
+ },
+ {
/* Teclast X98 Plus II */
.driver_data = (void *)&teclast_x98plus2_data,
.matches = {
@@ -1339,6 +1395,19 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
},
},
{
+ /* Teclast X98 Pro */
+ .driver_data = (void *)&gdix1001_00_upside_down_data,
+ .matches = {
+ /*
+ * Only match BIOS date, because the manufacturers
+ * BIOS does not report the board name at all
+ * (sometimes)...
+ */
+ DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
+ DMI_MATCH(DMI_BIOS_DATE, "10/28/2015"),
+ },
+ },
+ {
/* Trekstor Primebook C11 */
.driver_data = (void *)&trekstor_primebook_c11_data,
.matches = {
@@ -1414,6 +1483,22 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
},
},
{
+ /* "WinBook TW100" */
+ .driver_data = (void *)&gdix1001_00_upside_down_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TW100")
+ }
+ },
+ {
+ /* WinBook TW700 */
+ .driver_data = (void *)&gdix1001_00_upside_down_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TW700")
+ },
+ },
+ {
/* Yours Y8W81, same case and touchscreen as Chuwi Vi8 */
.driver_data = (void *)&chuwi_vi8_data,
.matches = {
diff --git a/drivers/platform/x86/uv_sysfs.c b/drivers/platform/x86/uv_sysfs.c
index 7badcfa3f384..956a354b57c1 100644
--- a/drivers/platform/x86/uv_sysfs.c
+++ b/drivers/platform/x86/uv_sysfs.c
@@ -778,7 +778,7 @@ static struct attribute *base_attrs[] = {
NULL,
};
-static struct attribute_group base_attr_group = {
+static const struct attribute_group base_attr_group = {
.attrs = base_attrs
};
@@ -823,7 +823,7 @@ static struct attribute *hubless_base_attrs[] = {
NULL,
};
-static struct attribute_group hubless_base_attr_group = {
+static const struct attribute_group hubless_base_attr_group = {
.attrs = hubless_base_attrs
};
diff --git a/drivers/platform/x86/wireless-hotkey.c b/drivers/platform/x86/wireless-hotkey.c
new file mode 100644
index 000000000000..b010e4ca3383
--- /dev/null
+++ b/drivers/platform/x86/wireless-hotkey.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Airplane mode button for AMD, HP & Xiaomi laptops
+ *
+ * Copyright (C) 2014-2017 Alex Hung <alex.hung@canonical.com>
+ * Copyright (C) 2021 Advanced Micro Devices
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alex Hung");
+MODULE_ALIAS("acpi*:HPQ6001:*");
+MODULE_ALIAS("acpi*:WSTADEF:*");
+MODULE_ALIAS("acpi*:AMDI0051:*");
+
+static struct input_dev *wl_input_dev;
+
+static const struct acpi_device_id wl_ids[] = {
+ {"HPQ6001", 0},
+ {"WSTADEF", 0},
+ {"AMDI0051", 0},
+ {"", 0},
+};
+
+static int wireless_input_setup(void)
+{
+ int err;
+
+ wl_input_dev = input_allocate_device();
+ if (!wl_input_dev)
+ return -ENOMEM;
+
+ wl_input_dev->name = "Wireless hotkeys";
+ wl_input_dev->phys = "hpq6001/input0";
+ wl_input_dev->id.bustype = BUS_HOST;
+ wl_input_dev->evbit[0] = BIT(EV_KEY);
+ set_bit(KEY_RFKILL, wl_input_dev->keybit);
+
+ err = input_register_device(wl_input_dev);
+ if (err)
+ goto err_free_dev;
+
+ return 0;
+
+err_free_dev:
+ input_free_device(wl_input_dev);
+ return err;
+}
+
+static void wireless_input_destroy(void)
+{
+ input_unregister_device(wl_input_dev);
+}
+
+static void wl_notify(struct acpi_device *acpi_dev, u32 event)
+{
+ if (event != 0x80) {
+ pr_info("Received unknown event (0x%x)\n", event);
+ return;
+ }
+
+ input_report_key(wl_input_dev, KEY_RFKILL, 1);
+ input_sync(wl_input_dev);
+ input_report_key(wl_input_dev, KEY_RFKILL, 0);
+ input_sync(wl_input_dev);
+}
+
+static int wl_add(struct acpi_device *device)
+{
+ int err;
+
+ err = wireless_input_setup();
+ if (err)
+ pr_err("Failed to setup hp wireless hotkeys\n");
+
+ return err;
+}
+
+static int wl_remove(struct acpi_device *device)
+{
+ wireless_input_destroy();
+ return 0;
+}
+
+static struct acpi_driver wl_driver = {
+ .name = "wireless-hotkey",
+ .owner = THIS_MODULE,
+ .ids = wl_ids,
+ .ops = {
+ .add = wl_add,
+ .remove = wl_remove,
+ .notify = wl_notify,
+ },
+};
+
+module_acpi_driver(wl_driver);
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h
index cdcfa39cf167..e74a0f6a3157 100644
--- a/drivers/pnp/base.h
+++ b/drivers/pnp/base.h
@@ -6,7 +6,6 @@
extern struct mutex pnp_lock;
extern const struct attribute_group *pnp_dev_groups[];
-void *pnp_alloc(long size);
int pnp_register_protocol(struct pnp_protocol *protocol);
void pnp_unregister_protocol(struct pnp_protocol *protocol);
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index c2464ee08e4a..9610a9f08ff4 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -80,7 +80,7 @@ static int card_probe(struct pnp_card *card, struct pnp_card_driver *drv)
if (!id)
return 0;
- clink = pnp_alloc(sizeof(*clink));
+ clink = kzalloc(sizeof(*clink), GFP_KERNEL);
if (!clink)
return 0;
clink->card = card;
@@ -181,8 +181,8 @@ struct pnp_card *pnp_alloc_card(struct pnp_protocol *protocol, int id, char *pnp
return card;
}
-static ssize_t pnp_show_card_name(struct device *dmdev,
- struct device_attribute *attr, char *buf)
+static ssize_t name_show(struct device *dmdev,
+ struct device_attribute *attr, char *buf)
{
char *str = buf;
struct pnp_card *card = to_pnp_card(dmdev);
@@ -191,10 +191,10 @@ static ssize_t pnp_show_card_name(struct device *dmdev,
return (str - buf);
}
-static DEVICE_ATTR(name, S_IRUGO, pnp_show_card_name, NULL);
+static DEVICE_ATTR_RO(name);
-static ssize_t pnp_show_card_ids(struct device *dmdev,
- struct device_attribute *attr, char *buf)
+static ssize_t card_id_show(struct device *dmdev,
+ struct device_attribute *attr, char *buf)
{
char *str = buf;
struct pnp_card *card = to_pnp_card(dmdev);
@@ -207,7 +207,7 @@ static ssize_t pnp_show_card_ids(struct device *dmdev,
return (str - buf);
}
-static DEVICE_ATTR(card_id, S_IRUGO, pnp_show_card_ids, NULL);
+static DEVICE_ATTR_RO(card_id);
static int pnp_interface_attach_card(struct pnp_card *card)
{
@@ -369,6 +369,7 @@ err_out:
dev->card_link = NULL;
return NULL;
}
+EXPORT_SYMBOL(pnp_request_card_device);
/**
* pnp_release_card_device - call this when the driver no longer needs the device
@@ -382,6 +383,7 @@ void pnp_release_card_device(struct pnp_dev *dev)
device_release_driver(&dev->dev);
drv->link.remove = &card_remove_first;
}
+EXPORT_SYMBOL(pnp_release_card_device);
/*
* suspend/resume callbacks
@@ -439,6 +441,7 @@ int pnp_register_card_driver(struct pnp_card_driver *drv)
}
return 0;
}
+EXPORT_SYMBOL(pnp_register_card_driver);
/**
* pnp_unregister_card_driver - unregisters a PnP card driver from the PnP Layer
@@ -451,8 +454,4 @@ void pnp_unregister_card_driver(struct pnp_card_driver *drv)
mutex_unlock(&pnp_lock);
pnp_unregister_driver(&drv->link);
}
-
-EXPORT_SYMBOL(pnp_request_card_device);
-EXPORT_SYMBOL(pnp_release_card_device);
-EXPORT_SYMBOL(pnp_register_card_driver);
EXPORT_SYMBOL(pnp_unregister_card_driver);
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index a50ab002e9e4..4df5aa6a309c 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -31,18 +31,6 @@ DEFINE_MUTEX(pnp_lock);
int pnp_platform_devices;
EXPORT_SYMBOL(pnp_platform_devices);
-void *pnp_alloc(long size)
-{
- void *result;
-
- result = kzalloc(size, GFP_KERNEL);
- if (!result) {
- printk(KERN_ERR "pnp: Out of Memory\n");
- return NULL;
- }
- return result;
-}
-
static void pnp_remove_protocol(struct pnp_protocol *protocol)
{
mutex_lock(&pnp_lock);
@@ -227,9 +215,8 @@ int pnp_add_device(struct pnp_dev *dev)
for (id = dev->id; id; id = id->next)
len += scnprintf(buf + len, sizeof(buf) - len, " %s", id->id);
- dev_printk(KERN_DEBUG, &dev->dev, "%s device, IDs%s (%s)\n",
- dev->protocol->name, buf,
- dev->active ? "active" : "disabled");
+ dev_dbg(&dev->dev, "%s device, IDs%s (%s)\n", dev->protocol->name, buf,
+ dev->active ? "active" : "disabled");
return 0;
}
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index 93a30a8f88d1..c29d590c5e4f 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -68,6 +68,7 @@ int pnp_device_attach(struct pnp_dev *pnp_dev)
mutex_unlock(&pnp_lock);
return 0;
}
+EXPORT_SYMBOL(pnp_device_attach);
void pnp_device_detach(struct pnp_dev *pnp_dev)
{
@@ -76,6 +77,7 @@ void pnp_device_detach(struct pnp_dev *pnp_dev)
pnp_dev->status = PNP_READY;
mutex_unlock(&pnp_lock);
}
+EXPORT_SYMBOL(pnp_device_detach);
static int pnp_device_probe(struct device *dev)
{
@@ -271,11 +273,13 @@ int pnp_register_driver(struct pnp_driver *drv)
return driver_register(&drv->driver);
}
+EXPORT_SYMBOL(pnp_register_driver);
void pnp_unregister_driver(struct pnp_driver *drv)
{
driver_unregister(&drv->driver);
}
+EXPORT_SYMBOL(pnp_unregister_driver);
/**
* pnp_add_id - adds an EISA id to the specified device
@@ -310,8 +314,3 @@ struct pnp_id *pnp_add_id(struct pnp_dev *dev, const char *id)
return dev_id;
}
-
-EXPORT_SYMBOL(pnp_register_driver);
-EXPORT_SYMBOL(pnp_unregister_driver);
-EXPORT_SYMBOL(pnp_device_attach);
-EXPORT_SYMBOL(pnp_device_detach);
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index 602c46893e83..44efcdb87e6f 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -214,7 +214,7 @@ static ssize_t options_show(struct device *dmdev, struct device_attribute *attr,
int ret, dep = 0, set = 0;
char *indent;
- buffer = pnp_alloc(sizeof(pnp_info_buffer_t));
+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer)
return -ENOMEM;
@@ -257,7 +257,7 @@ static ssize_t resources_show(struct device *dmdev,
if (!dev)
return -EINVAL;
- buffer = pnp_alloc(sizeof(pnp_info_buffer_t));
+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer)
return -ENOMEM;
diff --git a/drivers/pnp/isapnp/compat.c b/drivers/pnp/isapnp/compat.c
index 035e95092489..d60d9e377da5 100644
--- a/drivers/pnp/isapnp/compat.c
+++ b/drivers/pnp/isapnp/compat.c
@@ -63,5 +63,4 @@ struct pnp_dev *pnp_find_dev(struct pnp_card *card, unsigned short vendor,
}
return NULL;
}
-
EXPORT_SYMBOL(pnp_find_dev);
diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c
index 785a796430fa..1ae458c02656 100644
--- a/drivers/pnp/isapnp/proc.c
+++ b/drivers/pnp/isapnp/proc.c
@@ -57,21 +57,20 @@ static const struct proc_ops isapnp_proc_bus_proc_ops = {
static int isapnp_proc_attach_device(struct pnp_dev *dev)
{
struct pnp_card *bus = dev->card;
- struct proc_dir_entry *de, *e;
char name[16];
- if (!(de = bus->procdir)) {
+ if (!bus->procdir) {
sprintf(name, "%02x", bus->number);
- de = bus->procdir = proc_mkdir(name, isapnp_proc_bus_dir);
- if (!de)
+ bus->procdir = proc_mkdir(name, isapnp_proc_bus_dir);
+ if (!bus->procdir)
return -ENOMEM;
}
sprintf(name, "%02x", dev->number);
- e = dev->procent = proc_create_data(name, S_IFREG | S_IRUGO, de,
+ dev->procent = proc_create_data(name, S_IFREG | S_IRUGO, bus->procdir,
&isapnp_proc_bus_proc_ops, dev);
- if (!e)
+ if (!dev->procent)
return -ENOMEM;
- proc_set_size(e, 256);
+ proc_set_size(dev->procent, 256);
return 0;
}
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index 144055593ec8..1765d6e60a8a 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -350,6 +350,7 @@ int pnp_start_dev(struct pnp_dev *dev)
dev_info(&dev->dev, "activated\n");
return 0;
}
+EXPORT_SYMBOL(pnp_start_dev);
/**
* pnp_stop_dev - low-level disable of the PnP device
@@ -371,6 +372,7 @@ int pnp_stop_dev(struct pnp_dev *dev)
dev_info(&dev->dev, "disabled\n");
return 0;
}
+EXPORT_SYMBOL(pnp_stop_dev);
/**
* pnp_activate_dev - activates a PnP device for use
@@ -396,6 +398,7 @@ int pnp_activate_dev(struct pnp_dev *dev)
dev->active = 1;
return 0;
}
+EXPORT_SYMBOL(pnp_activate_dev);
/**
* pnp_disable_dev - disables device
@@ -423,8 +426,4 @@ int pnp_disable_dev(struct pnp_dev *dev)
return 0;
}
-
-EXPORT_SYMBOL(pnp_start_dev);
-EXPORT_SYMBOL(pnp_stop_dev);
-EXPORT_SYMBOL(pnp_activate_dev);
EXPORT_SYMBOL(pnp_disable_dev);
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 9b760e73ee8f..669ef4700c1a 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -298,14 +298,12 @@ struct pnp_protocol pnpbios_protocol = {
static int __init insert_device(struct pnp_bios_node *node)
{
- struct list_head *pos;
struct pnp_dev *dev;
char id[8];
int error;
/* check if the device is already added */
- list_for_each(pos, &pnpbios_protocol.devices) {
- dev = list_entry(pos, struct pnp_dev, protocol_list);
+ list_for_each_entry(dev, &pnpbios_protocol.devices, protocol_list) {
if (dev->number == node->handle)
return -EEXIST;
}
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index 70d4ba95735a..2fa0f7d55259 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -540,7 +540,7 @@ struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
res->start = irq;
res->end = irq;
- dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res);
+ dev_dbg(&dev->dev, "%pR\n", res);
return pnp_res;
}
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
index e4f53d31191d..a6073db10ec6 100644
--- a/drivers/pnp/support.c
+++ b/drivers/pnp/support.c
@@ -30,7 +30,6 @@ int pnp_is_active(struct pnp_dev *dev)
else
return 1;
}
-
EXPORT_SYMBOL(pnp_is_active);
/*
diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c
index 125e592af445..d8ecffe72f16 100644
--- a/drivers/power/reset/at91-sama5d2_shdwc.c
+++ b/drivers/power/reset/at91-sama5d2_shdwc.c
@@ -351,10 +351,8 @@ static int __init at91_shdwc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
at91_shdwc->shdwc_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(at91_shdwc->shdwc_base)) {
- dev_err(&pdev->dev, "Could not map reset controller address\n");
+ if (IS_ERR(at91_shdwc->shdwc_base))
return PTR_ERR(at91_shdwc->shdwc_base);
- }
match = of_match_node(at91_shdwc_of_match, pdev->dev.of_node);
at91_shdwc->rcfg = match->data;
diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c
index c5067eb75370..1c5af2fef142 100644
--- a/drivers/power/reset/gpio-poweroff.c
+++ b/drivers/power/reset/gpio-poweroff.c
@@ -90,6 +90,7 @@ static const struct of_device_id of_gpio_poweroff_match[] = {
{ .compatible = "gpio-poweroff", },
{},
};
+MODULE_DEVICE_TABLE(of, of_gpio_poweroff_match);
static struct platform_driver gpio_poweroff_driver = {
.probe = gpio_poweroff_probe,
diff --git a/drivers/power/reset/keystone-reset.c b/drivers/power/reset/keystone-reset.c
index 211eeef0c81a..c720112db704 100644
--- a/drivers/power/reset/keystone-reset.c
+++ b/drivers/power/reset/keystone-reset.c
@@ -71,6 +71,7 @@ static const struct of_device_id rsctrl_of_match[] = {
{.compatible = "ti,keystone-reset", },
{},
};
+MODULE_DEVICE_TABLE(of, rsctrl_of_match);
static int rsctrl_probe(struct platform_device *pdev)
{
diff --git a/drivers/power/reset/ltc2952-poweroff.c b/drivers/power/reset/ltc2952-poweroff.c
index d1495af30081..8688c8ba8894 100644
--- a/drivers/power/reset/ltc2952-poweroff.c
+++ b/drivers/power/reset/ltc2952-poweroff.c
@@ -52,6 +52,7 @@
#include <linux/slab.h>
#include <linux/kmod.h>
#include <linux/module.h>
+#include <linux/panic_notifier.h>
#include <linux/mod_devicetable.h>
#include <linux/gpio/consumer.h>
#include <linux/reboot.h>
diff --git a/drivers/power/reset/regulator-poweroff.c b/drivers/power/reset/regulator-poweroff.c
index f697088e0ad1..20701203935f 100644
--- a/drivers/power/reset/regulator-poweroff.c
+++ b/drivers/power/reset/regulator-poweroff.c
@@ -64,6 +64,7 @@ static const struct of_device_id of_regulator_poweroff_match[] = {
{ .compatible = "regulator-poweroff", },
{},
};
+MODULE_DEVICE_TABLE(of, of_regulator_poweroff_match);
static struct platform_driver regulator_poweroff_driver = {
.probe = regulator_poweroff_probe,
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index e696364126f1..11f5368e810e 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -712,7 +712,8 @@ config BATTERY_GOLDFISH
config BATTERY_RT5033
tristate "RT5033 fuel gauge support"
- depends on MFD_RT5033
+ depends on I2C
+ select REGMAP_I2C
help
This adds support for battery fuel gauge in Richtek RT5033 PMIC.
The fuelgauge calculates and determines the battery state of charge
@@ -760,15 +761,6 @@ 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
- select LINEAR_RANGES
- 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_BD99954
tristate "ROHM bd99954 charger driver"
depends on I2C
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index a7309a3d1a47..33059a91f60c 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -60,7 +60,7 @@ obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o
-obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o pm2301_charger.o
+obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o
obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
@@ -96,7 +96,6 @@ 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_BD99954) += bd99954-charger.o
obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o
obj-$(CONFIG_RN5T618_POWER) += rn5t618_power.o
diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h
index 41c69a4f2a1f..0c940571e5b0 100644
--- a/drivers/power/supply/ab8500-bm.h
+++ b/drivers/power/supply/ab8500-bm.h
@@ -506,9 +506,6 @@ struct abx500_bm_data {
int usb_safety_tmr_h;
int bkup_bat_v;
int bkup_bat_i;
- bool autopower_cfg;
- bool ac_enabled;
- bool usb_enabled;
bool no_maintenance;
bool capacity_scaling;
bool chg_unknown_bat;
@@ -730,4 +727,8 @@ int ab8500_bm_of_probe(struct device *dev,
struct device_node *np,
struct abx500_bm_data *bm);
+extern struct platform_driver ab8500_fg_driver;
+extern struct platform_driver ab8500_btemp_driver;
+extern struct platform_driver abx500_chargalg_driver;
+
#endif /* _AB8500_CHARGER_H_ */
diff --git a/drivers/power/supply/ab8500-chargalg.h b/drivers/power/supply/ab8500-chargalg.h
index 94a6f9068bc5..07e6ff50084f 100644
--- a/drivers/power/supply/ab8500-chargalg.h
+++ b/drivers/power/supply/ab8500-chargalg.h
@@ -15,7 +15,7 @@
* - POWER_SUPPLY_TYPE_USB,
* because only them store as drv_data pointer to struct ux500_charger.
*/
-#define psy_to_ux500_charger(x) power_supply_get_drvdata(psy)
+#define psy_to_ux500_charger(x) power_supply_get_drvdata(x)
/* Forward declaration */
struct ux500_charger;
diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c
index fdfcd59fc43e..dbdcff32f353 100644
--- a/drivers/power/supply/ab8500_btemp.c
+++ b/drivers/power/supply/ab8500_btemp.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/component.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
@@ -932,26 +933,6 @@ static int __maybe_unused ab8500_btemp_suspend(struct device *dev)
return 0;
}
-static int ab8500_btemp_remove(struct platform_device *pdev)
-{
- struct ab8500_btemp *di = platform_get_drvdata(pdev);
- int i, irq;
-
- /* Disable interrupts */
- for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) {
- irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
- free_irq(irq, di);
- }
-
- /* Delete the work queue */
- destroy_workqueue(di->btemp_wq);
-
- flush_scheduled_work();
- power_supply_unregister(di->btemp_psy);
-
- return 0;
-}
-
static char *supply_interface[] = {
"ab8500_chargalg",
"ab8500_fg",
@@ -966,9 +947,42 @@ static const struct power_supply_desc ab8500_btemp_desc = {
.external_power_changed = ab8500_btemp_external_power_changed,
};
+static int ab8500_btemp_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct ab8500_btemp *di = dev_get_drvdata(dev);
+
+ /* Create a work queue for the btemp */
+ di->btemp_wq =
+ alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0);
+ if (di->btemp_wq == NULL) {
+ dev_err(dev, "failed to create work queue\n");
+ return -ENOMEM;
+ }
+
+ /* Kick off periodic temperature measurements */
+ ab8500_btemp_periodic(di, true);
+
+ return 0;
+}
+
+static void ab8500_btemp_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct ab8500_btemp *di = dev_get_drvdata(dev);
+
+ /* Delete the work queue */
+ destroy_workqueue(di->btemp_wq);
+ flush_scheduled_work();
+}
+
+static const struct component_ops ab8500_btemp_component_ops = {
+ .bind = ab8500_btemp_bind,
+ .unbind = ab8500_btemp_unbind,
+};
+
static int ab8500_btemp_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
struct power_supply_config psy_cfg = {};
struct device *dev = &pdev->dev;
struct ab8500_btemp *di;
@@ -981,12 +995,6 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
di->bm = &ab8500_bm_data;
- ret = ab8500_bm_of_probe(dev, np, di->bm);
- if (ret) {
- dev_err(dev, "failed to get battery information\n");
- return ret;
- }
-
/* get parent data */
di->dev = dev;
di->parent = dev_get_drvdata(pdev->dev.parent);
@@ -1011,14 +1019,6 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface);
psy_cfg.drv_data = di;
- /* Create a work queue for the btemp */
- di->btemp_wq =
- alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM, 0);
- if (di->btemp_wq == NULL) {
- dev_err(dev, "failed to create work queue\n");
- return -ENOMEM;
- }
-
/* Init work for measuring temperature periodically */
INIT_DEFERRABLE_WORK(&di->btemp_periodic_work,
ab8500_btemp_periodic_work);
@@ -1031,7 +1031,7 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
AB8500_BTEMP_HIGH_TH, &val);
if (ret < 0) {
dev_err(dev, "%s ab8500 read failed\n", __func__);
- goto free_btemp_wq;
+ return ret;
}
switch (val) {
case BTEMP_HIGH_TH_57_0:
@@ -1050,30 +1050,28 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
}
/* Register BTEMP power supply class */
- di->btemp_psy = power_supply_register(dev, &ab8500_btemp_desc,
- &psy_cfg);
+ di->btemp_psy = devm_power_supply_register(dev, &ab8500_btemp_desc,
+ &psy_cfg);
if (IS_ERR(di->btemp_psy)) {
dev_err(dev, "failed to register BTEMP psy\n");
- ret = PTR_ERR(di->btemp_psy);
- goto free_btemp_wq;
+ return PTR_ERR(di->btemp_psy);
}
/* Register interrupts */
for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) {
irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
- if (irq < 0) {
- ret = irq;
- goto free_irq;
- }
+ if (irq < 0)
+ return irq;
- ret = request_threaded_irq(irq, NULL, ab8500_btemp_irq[i].isr,
+ ret = devm_request_threaded_irq(dev, irq, NULL,
+ ab8500_btemp_irq[i].isr,
IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
ab8500_btemp_irq[i].name, di);
if (ret) {
dev_err(dev, "failed to request %s IRQ %d: %d\n"
, ab8500_btemp_irq[i].name, irq, ret);
- goto free_irq;
+ return ret;
}
dev_dbg(dev, "Requested %s IRQ %d: %d\n",
ab8500_btemp_irq[i].name, irq, ret);
@@ -1081,23 +1079,16 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, di);
- /* Kick off periodic temperature measurements */
- ab8500_btemp_periodic(di, true);
list_add_tail(&di->node, &ab8500_btemp_list);
- return ret;
+ return component_add(dev, &ab8500_btemp_component_ops);
+}
-free_irq:
- /* We also have to free all successfully registered irqs */
- for (i = i - 1; i >= 0; i--) {
- irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
- free_irq(irq, di);
- }
+static int ab8500_btemp_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &ab8500_btemp_component_ops);
- power_supply_unregister(di->btemp_psy);
-free_btemp_wq:
- destroy_workqueue(di->btemp_wq);
- return ret;
+ return 0;
}
static SIMPLE_DEV_PM_OPS(ab8500_btemp_pm_ops, ab8500_btemp_suspend, ab8500_btemp_resume);
@@ -1106,8 +1097,9 @@ static const struct of_device_id ab8500_btemp_match[] = {
{ .compatible = "stericsson,ab8500-btemp", },
{ },
};
+MODULE_DEVICE_TABLE(of, ab8500_btemp_match);
-static struct platform_driver ab8500_btemp_driver = {
+struct platform_driver ab8500_btemp_driver = {
.probe = ab8500_btemp_probe,
.remove = ab8500_btemp_remove,
.driver = {
@@ -1116,20 +1108,6 @@ static struct platform_driver ab8500_btemp_driver = {
.pm = &ab8500_btemp_pm_ops,
},
};
-
-static int __init ab8500_btemp_init(void)
-{
- return platform_driver_register(&ab8500_btemp_driver);
-}
-
-static void __exit ab8500_btemp_exit(void)
-{
- platform_driver_unregister(&ab8500_btemp_driver);
-}
-
-device_initcall(ab8500_btemp_init);
-module_exit(ab8500_btemp_exit);
-
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy");
MODULE_ALIAS("platform:ab8500-btemp");
diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c
index a9be10eb2c22..fa49e12e5a60 100644
--- a/drivers/power/supply/ab8500_charger.c
+++ b/drivers/power/supply/ab8500_charger.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/component.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/notifier.h>
@@ -414,6 +415,14 @@ disable_otp:
static void ab8500_power_supply_changed(struct ab8500_charger *di,
struct power_supply *psy)
{
+ /*
+ * This happens if we get notifications or interrupts and
+ * the platform has been configured not to support one or
+ * other type of charging.
+ */
+ if (!psy)
+ return;
+
if (di->autopower_cfg) {
if (!di->usb.charger_connected &&
!di->ac.charger_connected &&
@@ -440,7 +449,15 @@ static void ab8500_charger_set_usb_connected(struct ab8500_charger *di,
if (!connected)
di->flags.vbus_drop_end = false;
- sysfs_notify(&di->usb_chg.psy->dev.kobj, NULL, "present");
+ /*
+ * Sometimes the platform is configured not to support
+ * USB charging and no psy has been created, but we still
+ * will get these notifications.
+ */
+ if (di->usb_chg.psy) {
+ sysfs_notify(&di->usb_chg.psy->dev.kobj, NULL,
+ "present");
+ }
if (connected) {
mutex_lock(&di->charger_attached_mutex);
@@ -3171,9 +3188,6 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb,
enum ab8500_usb_state bm_usb_state;
unsigned mA = *((unsigned *)power);
- if (!di)
- return NOTIFY_DONE;
-
if (event != USB_EVENT_VBUS) {
dev_dbg(di->dev, "not a standard host, returning\n");
return NOTIFY_DONE;
@@ -3276,10 +3290,74 @@ static struct notifier_block charger_nb = {
.notifier_call = ab8500_external_charger_prepare,
};
-static int ab8500_charger_remove(struct platform_device *pdev)
+static char *supply_interface[] = {
+ "ab8500_chargalg",
+ "ab8500_fg",
+ "ab8500_btemp",
+};
+
+static const struct power_supply_desc ab8500_ac_chg_desc = {
+ .name = "ab8500_ac",
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .properties = ab8500_charger_ac_props,
+ .num_properties = ARRAY_SIZE(ab8500_charger_ac_props),
+ .get_property = ab8500_charger_ac_get_property,
+};
+
+static const struct power_supply_desc ab8500_usb_chg_desc = {
+ .name = "ab8500_usb",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .properties = ab8500_charger_usb_props,
+ .num_properties = ARRAY_SIZE(ab8500_charger_usb_props),
+ .get_property = ab8500_charger_usb_get_property,
+};
+
+static int ab8500_charger_bind(struct device *dev)
{
- struct ab8500_charger *di = platform_get_drvdata(pdev);
- int i, irq, ret;
+ struct ab8500_charger *di = dev_get_drvdata(dev);
+ int ch_stat;
+ int ret;
+
+ /* Create a work queue for the charger */
+ di->charger_wq = alloc_ordered_workqueue("ab8500_charger_wq",
+ WQ_MEM_RECLAIM);
+ if (di->charger_wq == NULL) {
+ dev_err(dev, "failed to create work queue\n");
+ return -ENOMEM;
+ }
+
+ ch_stat = ab8500_charger_detect_chargers(di, false);
+
+ if (ch_stat & AC_PW_CONN) {
+ if (is_ab8500(di->parent))
+ queue_delayed_work(di->charger_wq,
+ &di->ac_charger_attached_work,
+ HZ);
+ }
+ if (ch_stat & USB_PW_CONN) {
+ if (is_ab8500(di->parent))
+ queue_delayed_work(di->charger_wq,
+ &di->usb_charger_attached_work,
+ HZ);
+ di->vbus_detected = true;
+ di->vbus_detected_start = true;
+ queue_work(di->charger_wq,
+ &di->detect_usb_type_work);
+ }
+
+ ret = component_bind_all(dev, di);
+ if (ret) {
+ dev_err(dev, "can't bind component devices\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ab8500_charger_unbind(struct device *dev)
+{
+ struct ab8500_charger *di = dev_get_drvdata(dev);
+ int ret;
/* Disable AC charging */
ab8500_charger_ac_en(&di->ac_chg, false, 0, 0);
@@ -3287,68 +3365,47 @@ static int ab8500_charger_remove(struct platform_device *pdev)
/* Disable USB charging */
ab8500_charger_usb_en(&di->usb_chg, false, 0, 0);
- /* Disable interrupts */
- for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) {
- irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
- free_irq(irq, di);
- }
-
/* Backup battery voltage and current disable */
ret = abx500_mask_and_set_register_interruptible(di->dev,
AB8500_RTC, AB8500_RTC_CTRL_REG, RTC_BUP_CH_ENA, 0);
if (ret < 0)
dev_err(di->dev, "%s mask and set failed\n", __func__);
- usb_unregister_notifier(di->usb_phy, &di->nb);
- usb_put_phy(di->usb_phy);
-
/* Delete the work queue */
destroy_workqueue(di->charger_wq);
- /* Unregister external charger enable notifier */
- if (!di->ac_chg.enabled)
- blocking_notifier_chain_unregister(
- &charger_notifier_list, &charger_nb);
-
flush_scheduled_work();
- if (di->usb_chg.enabled)
- power_supply_unregister(di->usb_chg.psy);
- if (di->ac_chg.enabled && !di->ac_chg.external)
- power_supply_unregister(di->ac_chg.psy);
-
- return 0;
+ /* Unbind fg, btemp, algorithm */
+ component_unbind_all(dev, di);
}
-static char *supply_interface[] = {
- "ab8500_chargalg",
- "ab8500_fg",
- "ab8500_btemp",
+static const struct component_master_ops ab8500_charger_comp_ops = {
+ .bind = ab8500_charger_bind,
+ .unbind = ab8500_charger_unbind,
};
-static const struct power_supply_desc ab8500_ac_chg_desc = {
- .name = "ab8500_ac",
- .type = POWER_SUPPLY_TYPE_MAINS,
- .properties = ab8500_charger_ac_props,
- .num_properties = ARRAY_SIZE(ab8500_charger_ac_props),
- .get_property = ab8500_charger_ac_get_property,
+static struct platform_driver *const ab8500_charger_component_drivers[] = {
+ &ab8500_fg_driver,
+ &ab8500_btemp_driver,
+ &abx500_chargalg_driver,
};
-static const struct power_supply_desc ab8500_usb_chg_desc = {
- .name = "ab8500_usb",
- .type = POWER_SUPPLY_TYPE_USB,
- .properties = ab8500_charger_usb_props,
- .num_properties = ARRAY_SIZE(ab8500_charger_usb_props),
- .get_property = ab8500_charger_usb_get_property,
-};
+static int ab8500_charger_compare_dev(struct device *dev, void *data)
+{
+ return dev == data;
+}
static int ab8500_charger_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct component_match *match = NULL;
struct power_supply_config ac_psy_cfg = {}, usb_psy_cfg = {};
struct ab8500_charger *di;
- int irq, i, charger_status, ret = 0, ch_stat;
- struct device *dev = &pdev->dev;
+ int charger_status;
+ int i, irq;
+ int ret;
di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
if (!di)
@@ -3393,6 +3450,38 @@ static int ab8500_charger_probe(struct platform_device *pdev)
return ret;
}
+ /*
+ * VDD ADC supply needs to be enabled from this driver when there
+ * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
+ * interrupts during charging
+ */
+ di->regu = devm_regulator_get(dev, "vddadc");
+ if (IS_ERR(di->regu)) {
+ ret = PTR_ERR(di->regu);
+ dev_err(dev, "failed to get vddadc regulator\n");
+ return ret;
+ }
+
+ /* Request interrupts */
+ for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) {
+ irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_threaded_irq(dev,
+ irq, NULL, ab8500_charger_irq[i].isr,
+ IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
+ ab8500_charger_irq[i].name, di);
+
+ if (ret != 0) {
+ dev_err(dev, "failed to request %s IRQ %d: %d\n"
+ , ab8500_charger_irq[i].name, irq, ret);
+ return ret;
+ }
+ dev_dbg(dev, "Requested %s IRQ %d: %d\n",
+ ab8500_charger_irq[i].name, irq, ret);
+ }
+
/* initialize lock */
spin_lock_init(&di->usb_state.usb_lock);
mutex_init(&di->usb_ipt_crnt_lock);
@@ -3419,14 +3508,16 @@ static int ab8500_charger_probe(struct platform_device *pdev)
di->ac_chg.max_out_curr =
di->bm->chg_output_curr[di->bm->n_chg_out_curr - 1];
di->ac_chg.wdt_refresh = CHG_WD_INTERVAL;
- di->ac_chg.enabled = di->bm->ac_enabled;
+ /*
+ * The AB8505 only supports USB charging. If we are not the
+ * AB8505, register an AC charger.
+ *
+ * TODO: if this should be opt-in, add DT properties for this.
+ */
+ if (!is_ab8505(di->parent))
+ di->ac_chg.enabled = true;
di->ac_chg.external = false;
- /*notifier for external charger enabling*/
- if (!di->ac_chg.enabled)
- blocking_notifier_chain_register(
- &charger_notifier_list, &charger_nb);
-
/* USB supply */
/* ux500_charger sub-class */
di->usb_chg.ops.enable = &ab8500_charger_usb_en;
@@ -3438,18 +3529,9 @@ static int ab8500_charger_probe(struct platform_device *pdev)
di->usb_chg.max_out_curr =
di->bm->chg_output_curr[di->bm->n_chg_out_curr - 1];
di->usb_chg.wdt_refresh = CHG_WD_INTERVAL;
- di->usb_chg.enabled = di->bm->usb_enabled;
di->usb_chg.external = false;
di->usb_state.usb_current = -1;
- /* Create a work queue for the charger */
- di->charger_wq = alloc_ordered_workqueue("ab8500_charger_wq",
- WQ_MEM_RECLAIM);
- if (di->charger_wq == NULL) {
- dev_err(dev, "failed to create work queue\n");
- return -ENOMEM;
- }
-
mutex_init(&di->charger_attached_mutex);
/* Init work for HW failure check */
@@ -3500,61 +3582,32 @@ static int ab8500_charger_probe(struct platform_device *pdev)
INIT_WORK(&di->check_usb_thermal_prot_work,
ab8500_charger_check_usb_thermal_prot_work);
- /*
- * VDD ADC supply needs to be enabled from this driver when there
- * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
- * interrupts during charging
- */
- di->regu = devm_regulator_get(dev, "vddadc");
- if (IS_ERR(di->regu)) {
- ret = PTR_ERR(di->regu);
- dev_err(dev, "failed to get vddadc regulator\n");
- goto free_charger_wq;
- }
-
/* Initialize OVV, and other registers */
ret = ab8500_charger_init_hw_registers(di);
if (ret) {
dev_err(dev, "failed to initialize ABB registers\n");
- goto free_charger_wq;
+ return ret;
}
/* Register AC charger class */
if (di->ac_chg.enabled) {
- di->ac_chg.psy = power_supply_register(dev,
+ di->ac_chg.psy = devm_power_supply_register(dev,
&ab8500_ac_chg_desc,
&ac_psy_cfg);
if (IS_ERR(di->ac_chg.psy)) {
dev_err(dev, "failed to register AC charger\n");
- ret = PTR_ERR(di->ac_chg.psy);
- goto free_charger_wq;
+ return PTR_ERR(di->ac_chg.psy);
}
}
/* Register USB charger class */
- if (di->usb_chg.enabled) {
- di->usb_chg.psy = power_supply_register(dev,
- &ab8500_usb_chg_desc,
- &usb_psy_cfg);
- if (IS_ERR(di->usb_chg.psy)) {
- dev_err(dev, "failed to register USB charger\n");
- ret = PTR_ERR(di->usb_chg.psy);
- goto free_ac;
- }
- }
-
- di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(di->usb_phy)) {
- dev_err(dev, "failed to get usb transceiver\n");
- ret = -EINVAL;
- goto free_usb;
- }
- di->nb.notifier_call = ab8500_charger_usb_notifier_call;
- ret = usb_register_notifier(di->usb_phy, &di->nb);
- if (ret) {
- dev_err(dev, "failed to register usb notifier\n");
- goto put_usb_phy;
+ di->usb_chg.psy = devm_power_supply_register(dev,
+ &ab8500_usb_chg_desc,
+ &usb_psy_cfg);
+ if (IS_ERR(di->usb_chg.psy)) {
+ dev_err(dev, "failed to register USB charger\n");
+ return PTR_ERR(di->usb_chg.psy);
}
/* Identify the connected charger types during startup */
@@ -3566,84 +3619,93 @@ static int ab8500_charger_probe(struct platform_device *pdev)
sysfs_notify(&di->ac_chg.psy->dev.kobj, NULL, "present");
}
- if (charger_status & USB_PW_CONN) {
- di->vbus_detected = true;
- di->vbus_detected_start = true;
- queue_work(di->charger_wq,
- &di->detect_usb_type_work);
- }
-
- /* Register interrupts */
- for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) {
- irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
- if (irq < 0) {
- ret = irq;
- goto free_irq;
- }
+ platform_set_drvdata(pdev, di);
- ret = request_threaded_irq(irq, NULL, ab8500_charger_irq[i].isr,
- IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
- ab8500_charger_irq[i].name, di);
+ /* Create something that will match the subdrivers when we bind */
+ for (i = 0; i < ARRAY_SIZE(ab8500_charger_component_drivers); i++) {
+ struct device_driver *drv = &ab8500_charger_component_drivers[i]->driver;
+ struct device *p = NULL, *d;
- if (ret != 0) {
- dev_err(dev, "failed to request %s IRQ %d: %d\n"
- , ab8500_charger_irq[i].name, irq, ret);
- goto free_irq;
+ while ((d = platform_find_device_by_driver(p, drv))) {
+ put_device(p);
+ component_match_add(dev, &match,
+ ab8500_charger_compare_dev, d);
+ p = d;
}
- dev_dbg(dev, "Requested %s IRQ %d: %d\n",
- ab8500_charger_irq[i].name, irq, ret);
+ put_device(p);
+ }
+ if (!match) {
+ dev_err(dev, "no matching components\n");
+ return -ENODEV;
+ }
+ if (IS_ERR(match)) {
+ dev_err(dev, "could not create component match\n");
+ return PTR_ERR(match);
}
- platform_set_drvdata(pdev, di);
-
- mutex_lock(&di->charger_attached_mutex);
+ /* Notifier for external charger enabling */
+ if (!di->ac_chg.enabled)
+ blocking_notifier_chain_register(
+ &charger_notifier_list, &charger_nb);
- ch_stat = ab8500_charger_detect_chargers(di, false);
- if ((ch_stat & AC_PW_CONN) == AC_PW_CONN) {
- if (is_ab8500(di->parent))
- queue_delayed_work(di->charger_wq,
- &di->ac_charger_attached_work,
- HZ);
+ di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
+ if (IS_ERR_OR_NULL(di->usb_phy)) {
+ dev_err(dev, "failed to get usb transceiver\n");
+ ret = -EINVAL;
+ goto out_charger_notifier;
}
- if ((ch_stat & USB_PW_CONN) == USB_PW_CONN) {
- if (is_ab8500(di->parent))
- queue_delayed_work(di->charger_wq,
- &di->usb_charger_attached_work,
- HZ);
+ di->nb.notifier_call = ab8500_charger_usb_notifier_call;
+ ret = usb_register_notifier(di->usb_phy, &di->nb);
+ if (ret) {
+ dev_err(dev, "failed to register usb notifier\n");
+ goto put_usb_phy;
}
- mutex_unlock(&di->charger_attached_mutex);
- return ret;
+ ret = component_master_add_with_match(&pdev->dev,
+ &ab8500_charger_comp_ops,
+ match);
+ if (ret) {
+ dev_err(dev, "failed to add component master\n");
+ goto free_notifier;
+ }
-free_irq:
- usb_unregister_notifier(di->usb_phy, &di->nb);
+ return 0;
- /* We also have to free all successfully registered irqs */
- for (i = i - 1; i >= 0; i--) {
- irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
- free_irq(irq, di);
- }
+free_notifier:
+ usb_unregister_notifier(di->usb_phy, &di->nb);
put_usb_phy:
usb_put_phy(di->usb_phy);
-free_usb:
- if (di->usb_chg.enabled)
- power_supply_unregister(di->usb_chg.psy);
-free_ac:
- if (di->ac_chg.enabled)
- power_supply_unregister(di->ac_chg.psy);
-free_charger_wq:
- destroy_workqueue(di->charger_wq);
+out_charger_notifier:
+ if (!di->ac_chg.enabled)
+ blocking_notifier_chain_unregister(
+ &charger_notifier_list, &charger_nb);
return ret;
}
+static int ab8500_charger_remove(struct platform_device *pdev)
+{
+ struct ab8500_charger *di = platform_get_drvdata(pdev);
+
+ component_master_del(&pdev->dev, &ab8500_charger_comp_ops);
+
+ usb_unregister_notifier(di->usb_phy, &di->nb);
+ usb_put_phy(di->usb_phy);
+ if (!di->ac_chg.enabled)
+ blocking_notifier_chain_unregister(
+ &charger_notifier_list, &charger_nb);
+
+ return 0;
+}
+
static SIMPLE_DEV_PM_OPS(ab8500_charger_pm_ops, ab8500_charger_suspend, ab8500_charger_resume);
static const struct of_device_id ab8500_charger_match[] = {
{ .compatible = "stericsson,ab8500-charger", },
{ },
};
+MODULE_DEVICE_TABLE(of, ab8500_charger_match);
static struct platform_driver ab8500_charger_driver = {
.probe = ab8500_charger_probe,
@@ -3657,15 +3719,24 @@ static struct platform_driver ab8500_charger_driver = {
static int __init ab8500_charger_init(void)
{
+ int ret;
+
+ ret = platform_register_drivers(ab8500_charger_component_drivers,
+ ARRAY_SIZE(ab8500_charger_component_drivers));
+ if (ret)
+ return ret;
+
return platform_driver_register(&ab8500_charger_driver);
}
static void __exit ab8500_charger_exit(void)
{
+ platform_unregister_drivers(ab8500_charger_component_drivers,
+ ARRAY_SIZE(ab8500_charger_component_drivers));
platform_driver_unregister(&ab8500_charger_driver);
}
-subsys_initcall_sync(ab8500_charger_init);
+module_init(ab8500_charger_init);
module_exit(ab8500_charger_exit);
MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c
index 0c7c01a0d979..a6ebdb269fdd 100644
--- a/drivers/power/supply/ab8500_fg.c
+++ b/drivers/power/supply/ab8500_fg.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/component.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
@@ -59,7 +60,7 @@
((y1) + ((((y2) - (y1)) * ((x) - (x1))) / ((x2) - (x1))));
/**
- * struct ab8500_fg_interrupts - ab8500 fg interupts
+ * struct ab8500_fg_interrupts - ab8500 fg interrupts
* @name: name of the interrupt
* @isr function pointer to the isr
*/
@@ -1727,6 +1728,7 @@ static void ab8500_fg_algorithm_calibrate(struct ab8500_fg *di)
break;
case AB8500_FG_CALIB_WAIT:
dev_dbg(di->dev, "Calibration WFI\n");
+ break;
default:
break;
}
@@ -2223,6 +2225,7 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data)
queue_work(di->fg_wq, &di->fg_work);
break;
}
+ break;
default:
break;
}
@@ -2980,27 +2983,6 @@ static int __maybe_unused ab8500_fg_suspend(struct device *dev)
return 0;
}
-static int ab8500_fg_remove(struct platform_device *pdev)
-{
- int ret = 0;
- struct ab8500_fg *di = platform_get_drvdata(pdev);
-
- list_del(&di->node);
-
- /* Disable coulomb counter */
- ret = ab8500_fg_coulomb_counter(di, false);
- if (ret)
- dev_err(di->dev, "failed to disable coulomb counter\n");
-
- destroy_workqueue(di->fg_wq);
- ab8500_fg_sysfs_exit(di);
-
- flush_scheduled_work();
- ab8500_fg_sysfs_psy_remove_attrs(di);
- power_supply_unregister(di->fg_psy);
- return ret;
-}
-
/* ab8500 fg driver interrupts and their respective isr */
static struct ab8500_fg_interrupts ab8500_fg_irq[] = {
{"NCONV_ACCU", ab8500_fg_cc_convend_handler},
@@ -3024,11 +3006,50 @@ static const struct power_supply_desc ab8500_fg_desc = {
.external_power_changed = ab8500_fg_external_power_changed,
};
+static int ab8500_fg_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct ab8500_fg *di = dev_get_drvdata(dev);
+
+ /* Create a work queue for running the FG algorithm */
+ di->fg_wq = alloc_ordered_workqueue("ab8500_fg_wq", WQ_MEM_RECLAIM);
+ if (di->fg_wq == NULL) {
+ dev_err(dev, "failed to create work queue\n");
+ return -ENOMEM;
+ }
+
+ /* Start the coulomb counter */
+ ab8500_fg_coulomb_counter(di, true);
+ /* Run the FG algorithm */
+ queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
+
+ return 0;
+}
+
+static void ab8500_fg_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct ab8500_fg *di = dev_get_drvdata(dev);
+ int ret;
+
+ /* Disable coulomb counter */
+ ret = ab8500_fg_coulomb_counter(di, false);
+ if (ret)
+ dev_err(dev, "failed to disable coulomb counter\n");
+
+ destroy_workqueue(di->fg_wq);
+ flush_scheduled_work();
+}
+
+static const struct component_ops ab8500_fg_component_ops = {
+ .bind = ab8500_fg_bind,
+ .unbind = ab8500_fg_unbind,
+};
+
static int ab8500_fg_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
- struct power_supply_config psy_cfg = {};
struct device *dev = &pdev->dev;
+ struct power_supply_config psy_cfg = {};
struct ab8500_fg *di;
int i, irq;
int ret = 0;
@@ -3039,12 +3060,6 @@ static int ab8500_fg_probe(struct platform_device *pdev)
di->bm = &ab8500_bm_data;
- ret = ab8500_bm_of_probe(dev, np, di->bm);
- if (ret) {
- dev_err(dev, "failed to get battery information\n");
- return ret;
- }
-
mutex_init(&di->cc_lock);
/* get parent data */
@@ -3074,13 +3089,6 @@ static int ab8500_fg_probe(struct platform_device *pdev)
ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_INIT);
ab8500_fg_discharge_state_to(di, AB8500_FG_DISCHARGE_INIT);
- /* Create a work queue for running the FG algorithm */
- di->fg_wq = alloc_ordered_workqueue("ab8500_fg_wq", WQ_MEM_RECLAIM);
- if (di->fg_wq == NULL) {
- dev_err(dev, "failed to create work queue\n");
- return -ENOMEM;
- }
-
/* Init work for running the fg algorithm instantly */
INIT_WORK(&di->fg_work, ab8500_fg_instant_work);
@@ -3113,7 +3121,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
ret = ab8500_fg_init_hw_registers(di);
if (ret) {
dev_err(dev, "failed to initialize registers\n");
- goto free_inst_curr_wq;
+ return ret;
}
/* Consider battery unknown until we're informed otherwise */
@@ -3121,15 +3129,13 @@ static int ab8500_fg_probe(struct platform_device *pdev)
di->flags.batt_id_received = false;
/* Register FG power supply class */
- di->fg_psy = power_supply_register(dev, &ab8500_fg_desc, &psy_cfg);
+ di->fg_psy = devm_power_supply_register(dev, &ab8500_fg_desc, &psy_cfg);
if (IS_ERR(di->fg_psy)) {
dev_err(dev, "failed to register FG psy\n");
- ret = PTR_ERR(di->fg_psy);
- goto free_inst_curr_wq;
+ return PTR_ERR(di->fg_psy);
}
di->fg_samples = SEC_TO_SAMPLE(di->bm->fg_params->init_timer);
- ab8500_fg_coulomb_counter(di, true);
/*
* Initialize completion used to notify completion and start
@@ -3141,19 +3147,18 @@ static int ab8500_fg_probe(struct platform_device *pdev)
/* Register primary interrupt handlers */
for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq); i++) {
irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name);
- if (irq < 0) {
- ret = irq;
- goto free_irq;
- }
+ if (irq < 0)
+ return irq;
- ret = request_threaded_irq(irq, NULL, ab8500_fg_irq[i].isr,
+ ret = devm_request_threaded_irq(dev, irq, NULL,
+ ab8500_fg_irq[i].isr,
IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
ab8500_fg_irq[i].name, di);
if (ret != 0) {
dev_err(dev, "failed to request %s IRQ %d: %d\n",
ab8500_fg_irq[i].name, irq, ret);
- goto free_irq;
+ return ret;
}
dev_dbg(dev, "Requested %s IRQ %d: %d\n",
ab8500_fg_irq[i].name, irq, ret);
@@ -3168,14 +3173,14 @@ static int ab8500_fg_probe(struct platform_device *pdev)
ret = ab8500_fg_sysfs_init(di);
if (ret) {
dev_err(dev, "failed to create sysfs entry\n");
- goto free_irq;
+ return ret;
}
ret = ab8500_fg_sysfs_psy_create_attrs(di);
if (ret) {
dev_err(dev, "failed to create FG psy\n");
ab8500_fg_sysfs_exit(di);
- goto free_irq;
+ return ret;
}
/* Calibrate the fg first time */
@@ -3185,24 +3190,21 @@ static int ab8500_fg_probe(struct platform_device *pdev)
/* Use room temp as default value until we get an update from driver. */
di->bat_temp = 210;
- /* Run the FG algorithm */
- queue_delayed_work(di->fg_wq, &di->fg_periodic_work, 0);
-
list_add_tail(&di->node, &ab8500_fg_list);
- return ret;
+ return component_add(dev, &ab8500_fg_component_ops);
+}
-free_irq:
- /* We also have to free all registered irqs */
- while (--i >= 0) {
- /* Last assignment of i from primary interrupt handlers */
- irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name);
- free_irq(irq, di);
- }
+static int ab8500_fg_remove(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct ab8500_fg *di = platform_get_drvdata(pdev);
+
+ component_del(&pdev->dev, &ab8500_fg_component_ops);
+ list_del(&di->node);
+ ab8500_fg_sysfs_exit(di);
+ ab8500_fg_sysfs_psy_remove_attrs(di);
- power_supply_unregister(di->fg_psy);
-free_inst_curr_wq:
- destroy_workqueue(di->fg_wq);
return ret;
}
@@ -3212,8 +3214,9 @@ static const struct of_device_id ab8500_fg_match[] = {
{ .compatible = "stericsson,ab8500-fg", },
{ },
};
+MODULE_DEVICE_TABLE(of, ab8500_fg_match);
-static struct platform_driver ab8500_fg_driver = {
+struct platform_driver ab8500_fg_driver = {
.probe = ab8500_fg_probe,
.remove = ab8500_fg_remove,
.driver = {
@@ -3222,20 +3225,6 @@ static struct platform_driver ab8500_fg_driver = {
.pm = &ab8500_fg_pm_ops,
},
};
-
-static int __init ab8500_fg_init(void)
-{
- return platform_driver_register(&ab8500_fg_driver);
-}
-
-static void __exit ab8500_fg_exit(void)
-{
- platform_driver_unregister(&ab8500_fg_driver);
-}
-
-subsys_initcall_sync(ab8500_fg_init);
-module_exit(ab8500_fg_exit);
-
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Johan Palsson, Karl Komierowski");
MODULE_ALIAS("platform:ab8500-fg");
diff --git a/drivers/power/supply/abx500_chargalg.c b/drivers/power/supply/abx500_chargalg.c
index f5b792243727..b72826cf6794 100644
--- a/drivers/power/supply/abx500_chargalg.c
+++ b/drivers/power/supply/abx500_chargalg.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/component.h>
#include <linux/hrtimer.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -1149,6 +1150,7 @@ static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data)
default:
break;
}
+ break;
default:
break;
}
@@ -1943,13 +1945,44 @@ static int __maybe_unused abx500_chargalg_suspend(struct device *dev)
return 0;
}
-static int abx500_chargalg_remove(struct platform_device *pdev)
+static char *supply_interface[] = {
+ "ab8500_fg",
+};
+
+static const struct power_supply_desc abx500_chargalg_desc = {
+ .name = "abx500_chargalg",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = abx500_chargalg_props,
+ .num_properties = ARRAY_SIZE(abx500_chargalg_props),
+ .get_property = abx500_chargalg_get_property,
+ .external_power_changed = abx500_chargalg_external_power_changed,
+};
+
+static int abx500_chargalg_bind(struct device *dev, struct device *master,
+ void *data)
{
- struct abx500_chargalg *di = platform_get_drvdata(pdev);
+ struct abx500_chargalg *di = dev_get_drvdata(dev);
- /* sysfs interface to enable/disbale charging from user space */
- abx500_chargalg_sysfs_exit(di);
+ /* Create a work queue for the chargalg */
+ di->chargalg_wq = alloc_ordered_workqueue("abx500_chargalg_wq",
+ WQ_MEM_RECLAIM);
+ if (di->chargalg_wq == NULL) {
+ dev_err(di->dev, "failed to create work queue\n");
+ return -ENOMEM;
+ }
+
+ /* Run the charging algorithm */
+ queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0);
+
+ return 0;
+}
+static void abx500_chargalg_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct abx500_chargalg *di = dev_get_drvdata(dev);
+
+ /* Stop all timers and work */
hrtimer_cancel(&di->safety_timer);
hrtimer_cancel(&di->maintenance_timer);
@@ -1959,48 +1992,29 @@ static int abx500_chargalg_remove(struct platform_device *pdev)
/* Delete the work queue */
destroy_workqueue(di->chargalg_wq);
-
- power_supply_unregister(di->chargalg_psy);
-
- return 0;
+ flush_scheduled_work();
}
-static char *supply_interface[] = {
- "ab8500_fg",
-};
-
-static const struct power_supply_desc abx500_chargalg_desc = {
- .name = "abx500_chargalg",
- .type = POWER_SUPPLY_TYPE_BATTERY,
- .properties = abx500_chargalg_props,
- .num_properties = ARRAY_SIZE(abx500_chargalg_props),
- .get_property = abx500_chargalg_get_property,
- .external_power_changed = abx500_chargalg_external_power_changed,
+static const struct component_ops abx500_chargalg_component_ops = {
+ .bind = abx500_chargalg_bind,
+ .unbind = abx500_chargalg_unbind,
};
static int abx500_chargalg_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
struct power_supply_config psy_cfg = {};
struct abx500_chargalg *di;
int ret = 0;
- di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
- if (!di) {
- dev_err(&pdev->dev, "%s no mem for ab8500_chargalg\n", __func__);
+ di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
+ if (!di)
return -ENOMEM;
- }
di->bm = &ab8500_bm_data;
- ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
- if (ret) {
- dev_err(&pdev->dev, "failed to get battery information\n");
- return ret;
- }
-
/* get device struct and parent */
- di->dev = &pdev->dev;
+ di->dev = dev;
di->parent = dev_get_drvdata(pdev->dev.parent);
psy_cfg.supplied_to = supply_interface;
@@ -2016,14 +2030,6 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
di->maintenance_timer.function =
abx500_chargalg_maintenance_timer_expired;
- /* Create a work queue for the chargalg */
- di->chargalg_wq = alloc_ordered_workqueue("abx500_chargalg_wq",
- WQ_MEM_RECLAIM);
- if (di->chargalg_wq == NULL) {
- dev_err(di->dev, "failed to create work queue\n");
- return -ENOMEM;
- }
-
/* Init work for chargalg */
INIT_DEFERRABLE_WORK(&di->chargalg_periodic_work,
abx500_chargalg_periodic_work);
@@ -2037,12 +2043,12 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
di->chg_info.prev_conn_chg = -1;
/* Register chargalg power supply class */
- di->chargalg_psy = power_supply_register(di->dev, &abx500_chargalg_desc,
+ di->chargalg_psy = devm_power_supply_register(di->dev,
+ &abx500_chargalg_desc,
&psy_cfg);
if (IS_ERR(di->chargalg_psy)) {
dev_err(di->dev, "failed to register chargalg psy\n");
- ret = PTR_ERR(di->chargalg_psy);
- goto free_chargalg_wq;
+ return PTR_ERR(di->chargalg_psy);
}
platform_set_drvdata(pdev, di);
@@ -2051,21 +2057,24 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
ret = abx500_chargalg_sysfs_init(di);
if (ret) {
dev_err(di->dev, "failed to create sysfs entry\n");
- goto free_psy;
+ return ret;
}
di->curr_status.curr_step = CHARGALG_CURR_STEP_HIGH;
- /* Run the charging algorithm */
- queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0);
-
dev_info(di->dev, "probe success\n");
- return ret;
+ return component_add(dev, &abx500_chargalg_component_ops);
+}
-free_psy:
- power_supply_unregister(di->chargalg_psy);
-free_chargalg_wq:
- destroy_workqueue(di->chargalg_wq);
- return ret;
+static int abx500_chargalg_remove(struct platform_device *pdev)
+{
+ struct abx500_chargalg *di = platform_get_drvdata(pdev);
+
+ component_del(&pdev->dev, &abx500_chargalg_component_ops);
+
+ /* sysfs interface to enable/disable charging from user space */
+ abx500_chargalg_sysfs_exit(di);
+
+ return 0;
}
static SIMPLE_DEV_PM_OPS(abx500_chargalg_pm_ops, abx500_chargalg_suspend, abx500_chargalg_resume);
@@ -2075,7 +2084,7 @@ static const struct of_device_id ab8500_chargalg_match[] = {
{ },
};
-static struct platform_driver abx500_chargalg_driver = {
+struct platform_driver abx500_chargalg_driver = {
.probe = abx500_chargalg_probe,
.remove = abx500_chargalg_remove,
.driver = {
@@ -2084,9 +2093,6 @@ static struct platform_driver abx500_chargalg_driver = {
.pm = &abx500_chargalg_pm_ops,
},
};
-
-module_platform_driver(abx500_chargalg_driver);
-
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Johan Palsson, Karl Komierowski");
MODULE_ALIAS("platform:abx500-chargalg");
diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c
index e84b6e4da14a..18a9db0df4b1 100644
--- a/drivers/power/supply/axp20x_battery.c
+++ b/drivers/power/supply/axp20x_battery.c
@@ -40,6 +40,7 @@
#define AXP209_FG_PERCENT GENMASK(6, 0)
#define AXP22X_FG_VALID BIT(7)
+#define AXP20X_CHRG_CTRL1_ENABLE BIT(7)
#define AXP20X_CHRG_CTRL1_TGT_VOLT GENMASK(6, 5)
#define AXP20X_CHRG_CTRL1_TGT_4_1V (0 << 5)
#define AXP20X_CHRG_CTRL1_TGT_4_15V (1 << 5)
@@ -468,7 +469,18 @@ static int axp20x_battery_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
return axp20x_set_max_constant_charge_current(axp20x_batt,
val->intval);
-
+ case POWER_SUPPLY_PROP_STATUS:
+ switch (val->intval) {
+ case POWER_SUPPLY_STATUS_CHARGING:
+ return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,
+ AXP20X_CHRG_CTRL1_ENABLE, AXP20X_CHRG_CTRL1_ENABLE);
+
+ case POWER_SUPPLY_STATUS_DISCHARGING:
+ case POWER_SUPPLY_STATUS_NOT_CHARGING:
+ return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,
+ AXP20X_CHRG_CTRL1_ENABLE, 0);
+ }
+ fallthrough;
default:
return -EINVAL;
}
@@ -491,7 +503,8 @@ static enum power_supply_property axp20x_battery_props[] = {
static int axp20x_battery_prop_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
- return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ||
+ return psp == POWER_SUPPLY_PROP_STATUS ||
+ psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ||
psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN ||
psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT ||
psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c
index 39e16ecb7638..2ba2d8d6b8e6 100644
--- a/drivers/power/supply/axp288_fuel_gauge.c
+++ b/drivers/power/supply/axp288_fuel_gauge.c
@@ -142,9 +142,7 @@ static int fuel_gauge_reg_readb(struct axp288_fg_info *info, int reg)
for (i = 0; i < NR_RETRY_CNT; i++) {
ret = regmap_read(info->regmap, reg, &val);
- if (ret == -EBUSY)
- continue;
- else
+ if (ret != -EBUSY)
break;
}
@@ -676,7 +674,7 @@ intr_failed:
* detection reports one despite it not being there.
* Please keep this listed sorted alphabetically.
*/
-static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = {
+static const struct dmi_system_id axp288_no_battery_list[] = {
{
/* ACEPC T8 Cherry Trail Z8350 mini PC */
.matches = {
@@ -723,15 +721,6 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "MEEGOPAD T02"),
},
},
- {
- /* Meegopad T08 */
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Default string"),
- DMI_MATCH(DMI_BOARD_VENDOR, "To be filled by OEM."),
- DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"),
- DMI_MATCH(DMI_BOARD_VERSION, "V1.1"),
- },
- },
{ /* Mele PCG03 Mini PC */
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Mini PC"),
@@ -745,6 +734,15 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
}
},
+ {
+ /* Various Ace PC/Meegopad/MinisForum/Wintel Mini-PCs/HDMI-sticks */
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "3"),
+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+ DMI_MATCH(DMI_BIOS_VERSION, "5.11"),
+ },
+ },
{}
};
@@ -764,7 +762,7 @@ static int axp288_fuel_gauge_probe(struct platform_device *pdev)
};
unsigned int val;
- if (dmi_check_system(axp288_fuel_gauge_blacklist))
+ if (dmi_check_system(axp288_no_battery_list))
return -ENODEV;
/*
diff --git a/drivers/power/supply/bd70528-charger.c b/drivers/power/supply/bd70528-charger.c
deleted file mode 100644
index 7c1f0b99c71b..000000000000
--- a/drivers/power/supply/bd70528-charger.c
+++ /dev/null
@@ -1,710 +0,0 @@
-// 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>
-#include <linux/linear_range.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;
-}
-
-static const struct linear_range current_limit_ranges[] = {
- {
- .min = 5,
- .step = 1,
- .min_sel = 0,
- .max_sel = 0x22,
- },
- {
- .min = 40,
- .step = 5,
- .min_sel = 0x23,
- .max_sel = 0x26,
- },
- {
- .min = 60,
- .step = 20,
- .min_sel = 0x27,
- .max_sel = 0x2d,
- },
- {
- .min = 200,
- .step = 50,
- .min_sel = 0x2e,
- .max_sel = 0x34,
- },
- {
- .min = 500,
- .step = 0,
- .min_sel = 0x35,
- .max_sel = 0x3f,
- },
-};
-
-/*
- * 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,
- .min_sel = 0,
- .max_sel = 0x12,
- },
- {
- .min = 200,
- .step = 25,
- .min_sel = 0x13,
- .max_sel = 0x1f,
- },
-};
-
-/*
- * 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 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 = linear_range_get_value_array(&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 = linear_range_get_value_array(&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;
- }
-
-/*
- * 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?
- */
-
- ret = linear_range_get_selector_low_array(warm_charge_curr,
- ARRAY_SIZE(warm_charge_curr),
- ma, &reg, &found);
- if (ret) {
- dev_err(bdpsy->dev,
- "Unsupported charge current %u mA\n", ma);
- reg = MIN_CHG_CURR_SEL;
- goto set;
- }
- if (!found) {
- /*
- * There was a gap in supported values and we hit it.
- * Yet a smaller value was found so we use 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 = linear_range_get_selector_low_array(current_limit_ranges,
- ARRAY_SIZE(current_limit_ranges),
- ma, &reg, &found);
- if (ret) {
- dev_err(bdpsy->dev, "Unsupported current limit %umA\n", ma);
- reg = MIN_CURR_LIMIT_SEL;
- goto set;
- }
- if (!found) {
- /*
- * There was a gap in supported values and we hit it.
- * We found a smaller value from ranges and use it.
- * Warn user though.
- */
- 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");
-MODULE_ALIAS("platform:bd70528-power");
diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index 852e86bfe2fb..35ff0c8fe96f 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -5,11 +5,10 @@
* Author: Mark A. Greer <mgreer@animalcreek.com>
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <linux/of_irq.h>
-#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/power_supply.h>
#include <linux/power/bq24190_charger.h>
@@ -1959,7 +1958,6 @@ static const struct i2c_device_id bq24190_i2c_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids);
-#ifdef CONFIG_OF
static const struct of_device_id bq24190_of_match[] = {
{ .compatible = "ti,bq24190", },
{ .compatible = "ti,bq24192", },
@@ -1968,11 +1966,6 @@ static const struct of_device_id bq24190_of_match[] = {
{ },
};
MODULE_DEVICE_TABLE(of, bq24190_of_match);
-#else
-static const struct of_device_id bq24190_of_match[] = {
- { },
-};
-#endif
static struct i2c_driver bq24190_driver = {
.probe = bq24190_probe,
@@ -1981,7 +1974,7 @@ static struct i2c_driver bq24190_driver = {
.driver = {
.name = "bq24190-charger",
.pm = &bq24190_pm_ops,
- .of_match_table = of_match_ptr(bq24190_of_match),
+ .of_match_table = bq24190_of_match,
},
};
module_i2c_driver(bq24190_driver);
diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c
index 45da870aecca..d67edb760c94 100644
--- a/drivers/power/supply/charger-manager.c
+++ b/drivers/power/supply/charger-manager.c
@@ -1279,6 +1279,7 @@ static const struct of_device_id charger_manager_match[] = {
},
{},
};
+MODULE_DEVICE_TABLE(of, charger_manager_match);
static struct charger_desc *of_cm_parse_desc(struct device *dev)
{
diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c
index a3fc0084cda0..8d62d4241da3 100644
--- a/drivers/power/supply/cpcap-battery.c
+++ b/drivers/power/supply/cpcap-battery.c
@@ -667,10 +667,23 @@ static int cpcap_battery_get_property(struct power_supply *psy,
if (!empty->voltage)
return -ENODATA;
val->intval = empty->counter_uah - latest->counter_uah;
- if (val->intval < 0)
+ if (val->intval < 0) {
+ /* Assume invalid config if CHARGE_NOW is -20% */
+ if (ddata->charge_full && abs(val->intval) > ddata->charge_full/5) {
+ empty->voltage = 0;
+ ddata->charge_full = 0;
+ return -ENODATA;
+ }
val->intval = 0;
- else if (ddata->charge_full && ddata->charge_full < val->intval)
+ } else if (ddata->charge_full && ddata->charge_full < val->intval) {
+ /* Assume invalid config if CHARGE_NOW exceeds CHARGE_FULL by 20% */
+ if (val->intval > (6*ddata->charge_full)/5) {
+ empty->voltage = 0;
+ ddata->charge_full = 0;
+ return -ENODATA;
+ }
val->intval = ddata->charge_full;
+ }
break;
case POWER_SUPPLY_PROP_CHARGE_FULL:
if (!ddata->charge_full)
@@ -747,7 +760,7 @@ static int cpcap_battery_set_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_CHARGE_FULL:
if (val->intval < 0)
return -EINVAL;
- if (val->intval > ddata->config.info.charge_full_design)
+ if (val->intval > (6*ddata->config.info.charge_full_design)/5)
return -EINVAL;
ddata->charge_full = val->intval;
diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c
index df01abc49ce8..60e0ce105a29 100644
--- a/drivers/power/supply/cpcap-charger.c
+++ b/drivers/power/supply/cpcap-charger.c
@@ -173,23 +173,6 @@ static enum power_supply_property cpcap_charger_props[] = {
POWER_SUPPLY_PROP_CURRENT_NOW,
};
-/* No battery always shows temperature of -40000 */
-static bool cpcap_charger_battery_found(struct cpcap_charger_ddata *ddata)
-{
- struct iio_channel *channel;
- int error, temperature;
-
- channel = ddata->channels[CPCAP_CHARGER_IIO_BATTDET];
- error = iio_read_channel_processed(channel, &temperature);
- if (error < 0) {
- dev_warn(ddata->dev, "%s failed: %i\n", __func__, error);
-
- return false;
- }
-
- return temperature > -20000 && temperature < 60000;
-}
-
static int cpcap_charger_get_charge_voltage(struct cpcap_charger_ddata *ddata)
{
struct iio_channel *channel;
@@ -700,11 +683,29 @@ static void cpcap_usb_detect(struct work_struct *work)
if (!ddata->feeding_vbus && cpcap_charger_vbus_valid(ddata) &&
s.chrgcurr1) {
- int max_current = 532000;
+ int max_current;
int vchrg, ichrg;
+ union power_supply_propval val;
+ struct power_supply *battery;
- if (cpcap_charger_battery_found(ddata))
+ battery = power_supply_get_by_name("battery");
+ if (IS_ERR_OR_NULL(battery)) {
+ dev_err(ddata->dev, "battery power_supply not available %li\n",
+ PTR_ERR(battery));
+ return;
+ }
+
+ error = power_supply_get_property(battery, POWER_SUPPLY_PROP_PRESENT, &val);
+ power_supply_put(battery);
+ if (error)
+ goto out_err;
+
+ if (val.intval) {
max_current = 1596000;
+ } else {
+ dev_info(ddata->dev, "battery not inserted, charging disabled\n");
+ max_current = 0;
+ }
if (max_current > ddata->limit_current)
max_current = ddata->limit_current;
diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index 1aab868adabf..3cea92e28dc3 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -16,7 +16,6 @@
#include <linux/interrupt.h>
#include <linux/power_supply.h>
#include <linux/of_device.h>
-#include <linux/max17040_battery.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -142,13 +141,10 @@ struct max17040_chip {
struct regmap *regmap;
struct delayed_work work;
struct power_supply *battery;
- struct max17040_platform_data *pdata;
struct chip_data data;
/* battery capacity */
int soc;
- /* State Of Charge */
- int status;
/* Low alert threshold from 32% to 1% of the State of Charge */
u32 low_soc_alert;
/* some devices return twice the capacity */
@@ -221,26 +217,7 @@ static int max17040_get_version(struct max17040_chip *chip)
static int max17040_get_online(struct max17040_chip *chip)
{
- return chip->pdata && chip->pdata->battery_online ?
- chip->pdata->battery_online() : 1;
-}
-
-static int max17040_get_status(struct max17040_chip *chip)
-{
- if (!chip->pdata || !chip->pdata->charger_online
- || !chip->pdata->charger_enable)
- return POWER_SUPPLY_STATUS_UNKNOWN;
-
- if (max17040_get_soc(chip) > MAX17040_BATTERY_FULL)
- return POWER_SUPPLY_STATUS_FULL;
-
- if (chip->pdata->charger_online())
- if (chip->pdata->charger_enable())
- return POWER_SUPPLY_STATUS_CHARGING;
- else
- return POWER_SUPPLY_STATUS_NOT_CHARGING;
- else
- return POWER_SUPPLY_STATUS_DISCHARGING;
+ return 1;
}
static int max17040_get_of_data(struct max17040_chip *chip)
@@ -283,7 +260,6 @@ static int max17040_get_of_data(struct max17040_chip *chip)
static void max17040_check_changes(struct max17040_chip *chip)
{
chip->soc = max17040_get_soc(chip);
- chip->status = max17040_get_status(chip);
}
static void max17040_queue_work(struct max17040_chip *chip)
@@ -302,17 +278,16 @@ static void max17040_stop_work(void *data)
static void max17040_work(struct work_struct *work)
{
struct max17040_chip *chip;
- int last_soc, last_status;
+ int last_soc;
chip = container_of(work, struct max17040_chip, work.work);
- /* store SOC and status to check changes */
+ /* store SOC to check changes */
last_soc = chip->soc;
- last_status = chip->status;
max17040_check_changes(chip);
/* check changes and send uevent */
- if (last_soc != chip->soc || last_status != chip->status)
+ if (last_soc != chip->soc)
power_supply_changed(chip->battery);
max17040_queue_work(chip);
@@ -361,12 +336,10 @@ static irqreturn_t max17040_thread_handler(int id, void *dev)
static int max17040_enable_alert_irq(struct max17040_chip *chip)
{
struct i2c_client *client = chip->client;
- unsigned int flags;
int ret;
- flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
- max17040_thread_handler, flags,
+ max17040_thread_handler, IRQF_ONESHOT,
chip->battery->desc->name, chip);
return ret;
@@ -415,9 +388,6 @@ static int max17040_get_property(struct power_supply *psy,
struct max17040_chip *chip = power_supply_get_drvdata(psy);
switch (psp) {
- case POWER_SUPPLY_PROP_STATUS:
- val->intval = max17040_get_status(chip);
- break;
case POWER_SUPPLY_PROP_ONLINE:
val->intval = max17040_get_online(chip);
break;
@@ -444,7 +414,6 @@ static const struct regmap_config max17040_regmap = {
};
static enum power_supply_property max17040_battery_props[] = {
- POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CAPACITY,
@@ -480,7 +449,6 @@ static int max17040_probe(struct i2c_client *client,
chip->client = client;
chip->regmap = devm_regmap_init_i2c(client, &max17040_regmap);
- chip->pdata = client->dev.platform_data;
chip_id = (enum chip_id) id->driver_data;
if (client->dev.of_node) {
ret = max17040_get_of_data(chip);
diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c
index 1d7326cd8fc6..ce2041b30a06 100644
--- a/drivers/power/supply/max17042_battery.c
+++ b/drivers/power/supply/max17042_battery.c
@@ -1104,7 +1104,7 @@ static int max17042_probe(struct i2c_client *client,
}
if (client->irq) {
- unsigned int flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+ unsigned int flags = IRQF_ONESHOT;
/*
* On ACPI systems the IRQ may be handled by ACPI-event code,
diff --git a/drivers/power/supply/pm2301_charger.c b/drivers/power/supply/pm2301_charger.c
deleted file mode 100644
index f86bbbeaff6c..000000000000
--- a/drivers/power/supply/pm2301_charger.c
+++ /dev/null
@@ -1,1249 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright 2012 ST Ericsson.
- *
- * Power supply driver for ST Ericsson pm2xxx_charger charger
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/power_supply.h>
-#include <linux/regulator/consumer.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/workqueue.h>
-#include <linux/mfd/abx500/ab8500.h>
-#include <linux/pm2301_charger.h>
-#include <linux/gpio.h>
-#include <linux/pm_runtime.h>
-#include <linux/pm.h>
-
-#include "ab8500-bm.h"
-#include "ab8500-chargalg.h"
-#include "pm2301_charger.h"
-
-#define to_pm2xxx_charger_ac_device_info(x) container_of((x), \
- struct pm2xxx_charger, ac_chg)
-#define SLEEP_MIN 50
-#define SLEEP_MAX 100
-#define PM2XXX_AUTOSUSPEND_DELAY 500
-
-static int pm2xxx_interrupt_registers[] = {
- PM2XXX_REG_INT1,
- PM2XXX_REG_INT2,
- PM2XXX_REG_INT3,
- PM2XXX_REG_INT4,
- PM2XXX_REG_INT5,
- PM2XXX_REG_INT6,
-};
-
-static enum power_supply_property pm2xxx_charger_ac_props[] = {
- POWER_SUPPLY_PROP_HEALTH,
- POWER_SUPPLY_PROP_PRESENT,
- POWER_SUPPLY_PROP_ONLINE,
- POWER_SUPPLY_PROP_VOLTAGE_AVG,
-};
-
-static int pm2xxx_charger_voltage_map[] = {
- 3500,
- 3525,
- 3550,
- 3575,
- 3600,
- 3625,
- 3650,
- 3675,
- 3700,
- 3725,
- 3750,
- 3775,
- 3800,
- 3825,
- 3850,
- 3875,
- 3900,
- 3925,
- 3950,
- 3975,
- 4000,
- 4025,
- 4050,
- 4075,
- 4100,
- 4125,
- 4150,
- 4175,
- 4200,
- 4225,
- 4250,
- 4275,
- 4300,
-};
-
-static int pm2xxx_charger_current_map[] = {
- 200,
- 200,
- 400,
- 600,
- 800,
- 1000,
- 1200,
- 1400,
- 1600,
- 1800,
- 2000,
- 2200,
- 2400,
- 2600,
- 2800,
- 3000,
-};
-
-static void set_lpn_pin(struct pm2xxx_charger *pm2)
-{
- if (!pm2->ac.charger_connected && gpio_is_valid(pm2->lpn_pin)) {
- gpio_set_value(pm2->lpn_pin, 1);
- usleep_range(SLEEP_MIN, SLEEP_MAX);
- }
-}
-
-static void clear_lpn_pin(struct pm2xxx_charger *pm2)
-{
- if (!pm2->ac.charger_connected && gpio_is_valid(pm2->lpn_pin))
- gpio_set_value(pm2->lpn_pin, 0);
-}
-
-static int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val)
-{
- int ret;
-
- /* wake up the device */
- pm_runtime_get_sync(pm2->dev);
-
- ret = i2c_smbus_read_i2c_block_data(pm2->config.pm2xxx_i2c, reg,
- 1, val);
- if (ret < 0)
- dev_err(pm2->dev, "Error reading register at 0x%x\n", reg);
- else
- ret = 0;
-
- pm_runtime_put_sync(pm2->dev);
-
- return ret;
-}
-
-static int pm2xxx_reg_write(struct pm2xxx_charger *pm2, int reg, u8 val)
-{
- int ret;
-
- /* wake up the device */
- pm_runtime_get_sync(pm2->dev);
-
- ret = i2c_smbus_write_i2c_block_data(pm2->config.pm2xxx_i2c, reg,
- 1, &val);
- if (ret < 0)
- dev_err(pm2->dev, "Error writing register at 0x%x\n", reg);
- else
- ret = 0;
-
- pm_runtime_put_sync(pm2->dev);
-
- return ret;
-}
-
-static int pm2xxx_charging_enable_mngt(struct pm2xxx_charger *pm2)
-{
- int ret;
-
- /* Enable charging */
- ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG2,
- (PM2XXX_CH_AUTO_RESUME_EN | PM2XXX_CHARGER_ENA));
-
- return ret;
-}
-
-static int pm2xxx_charging_disable_mngt(struct pm2xxx_charger *pm2)
-{
- int ret;
-
- /* Disable SW EOC ctrl */
- ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG, PM2XXX_SWCTRL_HW);
- if (ret < 0) {
- dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
- return ret;
- }
-
- /* Disable charging */
- ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG2,
- (PM2XXX_CH_AUTO_RESUME_DIS | PM2XXX_CHARGER_DIS));
- if (ret < 0) {
- dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
- return ret;
- }
-
- return 0;
-}
-
-static int pm2xxx_charger_batt_therm_mngt(struct pm2xxx_charger *pm2, int val)
-{
- queue_work(pm2->charger_wq, &pm2->check_main_thermal_prot_work);
-
- return 0;
-}
-
-
-static int pm2xxx_charger_die_therm_mngt(struct pm2xxx_charger *pm2, int val)
-{
- queue_work(pm2->charger_wq, &pm2->check_main_thermal_prot_work);
-
- return 0;
-}
-
-static int pm2xxx_charger_ovv_mngt(struct pm2xxx_charger *pm2, int val)
-{
- dev_err(pm2->dev, "Overvoltage detected\n");
- pm2->flags.ovv = true;
- power_supply_changed(pm2->ac_chg.psy);
-
- /* Schedule a new HW failure check */
- queue_delayed_work(pm2->charger_wq, &pm2->check_hw_failure_work, 0);
-
- return 0;
-}
-
-static int pm2xxx_charger_wd_exp_mngt(struct pm2xxx_charger *pm2, int val)
-{
- dev_dbg(pm2->dev , "20 minutes watchdog expired\n");
-
- pm2->ac.wd_expired = true;
- power_supply_changed(pm2->ac_chg.psy);
-
- return 0;
-}
-
-static int pm2xxx_charger_vbat_lsig_mngt(struct pm2xxx_charger *pm2, int val)
-{
- int ret;
-
- switch (val) {
- case PM2XXX_INT1_ITVBATLOWR:
- dev_dbg(pm2->dev, "VBAT grows above VBAT_LOW level\n");
- /* Enable SW EOC ctrl */
- ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG,
- PM2XXX_SWCTRL_SW);
- if (ret < 0) {
- dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
- return ret;
- }
- break;
-
- case PM2XXX_INT1_ITVBATLOWF:
- dev_dbg(pm2->dev, "VBAT drops below VBAT_LOW level\n");
- /* Disable SW EOC ctrl */
- ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG,
- PM2XXX_SWCTRL_HW);
- if (ret < 0) {
- dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
- return ret;
- }
- break;
-
- default:
- dev_err(pm2->dev, "Unknown VBAT level\n");
- }
-
- return 0;
-}
-
-static int pm2xxx_charger_bat_disc_mngt(struct pm2xxx_charger *pm2, int val)
-{
- dev_dbg(pm2->dev, "battery disconnected\n");
-
- return 0;
-}
-
-static int pm2xxx_charger_detection(struct pm2xxx_charger *pm2, u8 *val)
-{
- int ret;
-
- ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT2, val);
-
- if (ret < 0) {
- dev_err(pm2->dev, "Charger detection failed\n");
- goto out;
- }
-
- *val &= (PM2XXX_INT2_S_ITVPWR1PLUG | PM2XXX_INT2_S_ITVPWR2PLUG);
-
-out:
- return ret;
-}
-
-static int pm2xxx_charger_itv_pwr_plug_mngt(struct pm2xxx_charger *pm2, int val)
-{
-
- int ret;
- u8 read_val;
-
- /*
- * Since we can't be sure that the events are received
- * synchronously, we have the check if the main charger is
- * connected by reading the interrupt source register.
- */
- ret = pm2xxx_charger_detection(pm2, &read_val);
-
- if ((ret == 0) && read_val) {
- pm2->ac.charger_connected = 1;
- pm2->ac_conn = true;
- queue_work(pm2->charger_wq, &pm2->ac_work);
- }
-
-
- return ret;
-}
-
-static int pm2xxx_charger_itv_pwr_unplug_mngt(struct pm2xxx_charger *pm2,
- int val)
-{
- pm2->ac.charger_connected = 0;
- queue_work(pm2->charger_wq, &pm2->ac_work);
-
- return 0;
-}
-
-static int pm2_int_reg0(void *pm2_data, int val)
-{
- struct pm2xxx_charger *pm2 = pm2_data;
- int ret = 0;
-
- if (val & PM2XXX_INT1_ITVBATLOWR) {
- ret = pm2xxx_charger_vbat_lsig_mngt(pm2,
- PM2XXX_INT1_ITVBATLOWR);
- if (ret < 0)
- goto out;
- }
-
- if (val & PM2XXX_INT1_ITVBATLOWF) {
- ret = pm2xxx_charger_vbat_lsig_mngt(pm2,
- PM2XXX_INT1_ITVBATLOWF);
- if (ret < 0)
- goto out;
- }
-
- if (val & PM2XXX_INT1_ITVBATDISCONNECT) {
- ret = pm2xxx_charger_bat_disc_mngt(pm2,
- PM2XXX_INT1_ITVBATDISCONNECT);
- if (ret < 0)
- goto out;
- }
-out:
- return ret;
-}
-
-static int pm2_int_reg1(void *pm2_data, int val)
-{
- struct pm2xxx_charger *pm2 = pm2_data;
- int ret = 0;
-
- if (val & (PM2XXX_INT2_ITVPWR1PLUG | PM2XXX_INT2_ITVPWR2PLUG)) {
- dev_dbg(pm2->dev , "Main charger plugged\n");
- ret = pm2xxx_charger_itv_pwr_plug_mngt(pm2, val &
- (PM2XXX_INT2_ITVPWR1PLUG | PM2XXX_INT2_ITVPWR2PLUG));
- }
-
- if (val &
- (PM2XXX_INT2_ITVPWR1UNPLUG | PM2XXX_INT2_ITVPWR2UNPLUG)) {
- dev_dbg(pm2->dev , "Main charger unplugged\n");
- ret = pm2xxx_charger_itv_pwr_unplug_mngt(pm2, val &
- (PM2XXX_INT2_ITVPWR1UNPLUG |
- PM2XXX_INT2_ITVPWR2UNPLUG));
- }
-
- return ret;
-}
-
-static int pm2_int_reg2(void *pm2_data, int val)
-{
- struct pm2xxx_charger *pm2 = pm2_data;
- int ret = 0;
-
- if (val & PM2XXX_INT3_ITAUTOTIMEOUTWD)
- ret = pm2xxx_charger_wd_exp_mngt(pm2, val);
-
- if (val & (PM2XXX_INT3_ITCHPRECHARGEWD |
- PM2XXX_INT3_ITCHCCWD | PM2XXX_INT3_ITCHCVWD)) {
- dev_dbg(pm2->dev,
- "Watchdog occurred for precharge, CC and CV charge\n");
- }
-
- return ret;
-}
-
-static int pm2_int_reg3(void *pm2_data, int val)
-{
- struct pm2xxx_charger *pm2 = pm2_data;
- int ret = 0;
-
- if (val & (PM2XXX_INT4_ITCHARGINGON)) {
- dev_dbg(pm2->dev ,
- "charging operation has started\n");
- }
-
- if (val & (PM2XXX_INT4_ITVRESUME)) {
- dev_dbg(pm2->dev,
- "battery discharged down to VResume threshold\n");
- }
-
- if (val & (PM2XXX_INT4_ITBATTFULL)) {
- dev_dbg(pm2->dev , "battery fully detected\n");
- }
-
- if (val & (PM2XXX_INT4_ITCVPHASE)) {
- dev_dbg(pm2->dev, "CV phase enter with 0.5C charging\n");
- }
-
- if (val & (PM2XXX_INT4_ITVPWR2OVV | PM2XXX_INT4_ITVPWR1OVV)) {
- pm2->failure_case = VPWR_OVV;
- ret = pm2xxx_charger_ovv_mngt(pm2, val &
- (PM2XXX_INT4_ITVPWR2OVV | PM2XXX_INT4_ITVPWR1OVV));
- dev_dbg(pm2->dev, "VPWR/VSYSTEM overvoltage detected\n");
- }
-
- if (val & (PM2XXX_INT4_S_ITBATTEMPCOLD |
- PM2XXX_INT4_S_ITBATTEMPHOT)) {
- ret = pm2xxx_charger_batt_therm_mngt(pm2, val &
- (PM2XXX_INT4_S_ITBATTEMPCOLD |
- PM2XXX_INT4_S_ITBATTEMPHOT));
- dev_dbg(pm2->dev, "BTEMP is too Low/High\n");
- }
-
- return ret;
-}
-
-static int pm2_int_reg4(void *pm2_data, int val)
-{
- struct pm2xxx_charger *pm2 = pm2_data;
- int ret = 0;
-
- if (val & PM2XXX_INT5_ITVSYSTEMOVV) {
- pm2->failure_case = VSYSTEM_OVV;
- ret = pm2xxx_charger_ovv_mngt(pm2, val &
- PM2XXX_INT5_ITVSYSTEMOVV);
- dev_dbg(pm2->dev, "VSYSTEM overvoltage detected\n");
- }
-
- if (val & (PM2XXX_INT5_ITTHERMALWARNINGFALL |
- PM2XXX_INT5_ITTHERMALWARNINGRISE |
- PM2XXX_INT5_ITTHERMALSHUTDOWNFALL |
- PM2XXX_INT5_ITTHERMALSHUTDOWNRISE)) {
- dev_dbg(pm2->dev, "BTEMP die temperature is too Low/High\n");
- ret = pm2xxx_charger_die_therm_mngt(pm2, val &
- (PM2XXX_INT5_ITTHERMALWARNINGFALL |
- PM2XXX_INT5_ITTHERMALWARNINGRISE |
- PM2XXX_INT5_ITTHERMALSHUTDOWNFALL |
- PM2XXX_INT5_ITTHERMALSHUTDOWNRISE));
- }
-
- return ret;
-}
-
-static int pm2_int_reg5(void *pm2_data, int val)
-{
- struct pm2xxx_charger *pm2 = pm2_data;
-
- if (val & (PM2XXX_INT6_ITVPWR2DROP | PM2XXX_INT6_ITVPWR1DROP)) {
- dev_dbg(pm2->dev, "VMPWR drop to VBAT level\n");
- }
-
- if (val & (PM2XXX_INT6_ITVPWR2VALIDRISE |
- PM2XXX_INT6_ITVPWR1VALIDRISE |
- PM2XXX_INT6_ITVPWR2VALIDFALL |
- PM2XXX_INT6_ITVPWR1VALIDFALL)) {
- dev_dbg(pm2->dev, "Falling/Rising edge on WPWR1/2\n");
- }
-
- return 0;
-}
-
-static irqreturn_t pm2xxx_irq_int(int irq, void *data)
-{
- struct pm2xxx_charger *pm2 = data;
- struct pm2xxx_interrupts *interrupt = pm2->pm2_int;
- int i;
-
- /* wake up the device */
- pm_runtime_get_sync(pm2->dev);
-
- do {
- for (i = 0; i < PM2XXX_NUM_INT_REG; i++) {
- pm2xxx_reg_read(pm2,
- pm2xxx_interrupt_registers[i],
- &(interrupt->reg[i]));
-
- if (interrupt->reg[i] > 0)
- interrupt->handler[i](pm2, interrupt->reg[i]);
- }
- } while (gpio_get_value(pm2->pdata->gpio_irq_number) == 0);
-
- pm_runtime_mark_last_busy(pm2->dev);
- pm_runtime_put_autosuspend(pm2->dev);
-
- return IRQ_HANDLED;
-}
-
-static int pm2xxx_charger_get_ac_cv(struct pm2xxx_charger *pm2)
-{
- int ret = 0;
- u8 val;
-
- if (pm2->ac.charger_connected && pm2->ac.charger_online) {
-
- ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT4, &val);
- if (ret < 0) {
- dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
- goto out;
- }
-
- if (val & PM2XXX_INT4_S_ITCVPHASE)
- ret = PM2XXX_CONST_VOLT;
- else
- ret = PM2XXX_CONST_CURR;
- }
-out:
- return ret;
-}
-
-static int pm2xxx_current_to_regval(int curr)
-{
- int i;
-
- if (curr < pm2xxx_charger_current_map[0])
- return 0;
-
- for (i = 1; i < ARRAY_SIZE(pm2xxx_charger_current_map); i++) {
- if (curr < pm2xxx_charger_current_map[i])
- return (i - 1);
- }
-
- i = ARRAY_SIZE(pm2xxx_charger_current_map) - 1;
- if (curr == pm2xxx_charger_current_map[i])
- return i;
- else
- return -EINVAL;
-}
-
-static int pm2xxx_voltage_to_regval(int curr)
-{
- int i;
-
- if (curr < pm2xxx_charger_voltage_map[0])
- return 0;
-
- for (i = 1; i < ARRAY_SIZE(pm2xxx_charger_voltage_map); i++) {
- if (curr < pm2xxx_charger_voltage_map[i])
- return i - 1;
- }
-
- i = ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1;
- if (curr == pm2xxx_charger_voltage_map[i])
- return i;
- else
- return -EINVAL;
-}
-
-static int pm2xxx_charger_update_charger_current(struct ux500_charger *charger,
- int ich_out)
-{
- int ret;
- int curr_index;
- struct pm2xxx_charger *pm2;
- u8 val;
-
- if (charger->psy->desc->type == POWER_SUPPLY_TYPE_MAINS)
- pm2 = to_pm2xxx_charger_ac_device_info(charger);
- else
- return -ENXIO;
-
- curr_index = pm2xxx_current_to_regval(ich_out);
- if (curr_index < 0) {
- dev_err(pm2->dev,
- "Charger current too high, charging not started\n");
- return -ENXIO;
- }
-
- ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val);
- if (ret >= 0) {
- val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK;
- val |= curr_index;
- ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val);
- if (ret < 0) {
- dev_err(pm2->dev,
- "%s write failed\n", __func__);
- }
- }
- else
- dev_err(pm2->dev, "%s read failed\n", __func__);
-
- return ret;
-}
-
-static int pm2xxx_charger_ac_get_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
-{
- struct pm2xxx_charger *pm2;
-
- pm2 = to_pm2xxx_charger_ac_device_info(psy_to_ux500_charger(psy));
-
- switch (psp) {
- case POWER_SUPPLY_PROP_HEALTH:
- if (pm2->flags.mainextchnotok)
- val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
- else if (pm2->ac.wd_expired)
- val->intval = POWER_SUPPLY_HEALTH_DEAD;
- else if (pm2->flags.main_thermal_prot)
- val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
- else if (pm2->flags.ovv)
- val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
- else
- val->intval = POWER_SUPPLY_HEALTH_GOOD;
- break;
- case POWER_SUPPLY_PROP_ONLINE:
- val->intval = pm2->ac.charger_online;
- break;
- case POWER_SUPPLY_PROP_PRESENT:
- val->intval = pm2->ac.charger_connected;
- break;
- case POWER_SUPPLY_PROP_VOLTAGE_AVG:
- pm2->ac.cv_active = pm2xxx_charger_get_ac_cv(pm2);
- val->intval = pm2->ac.cv_active;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int pm2xxx_charging_init(struct pm2xxx_charger *pm2)
-{
- int ret = 0;
-
- /* enable CC and CV watchdog */
- ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG3,
- (PM2XXX_CH_WD_CV_PHASE_60MIN | PM2XXX_CH_WD_CC_PHASE_60MIN));
- if( ret < 0)
- return ret;
-
- /* enable precharge watchdog */
- ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG4,
- PM2XXX_CH_WD_PRECH_PHASE_60MIN);
-
- /* Disable auto timeout */
- ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG5,
- PM2XXX_CH_WD_AUTO_TIMEOUT_20MIN);
-
- /*
- * EOC current level = 100mA
- * Precharge current level = 100mA
- * CC current level = 1000mA
- */
- ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6,
- (PM2XXX_DIR_CH_CC_CURRENT_1000MA |
- PM2XXX_CH_PRECH_CURRENT_100MA |
- PM2XXX_CH_EOC_CURRENT_100MA));
-
- /*
- * recharge threshold = 3.8V
- * Precharge to CC threshold = 2.9V
- */
- ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG7,
- (PM2XXX_CH_PRECH_VOL_2_9 | PM2XXX_CH_VRESUME_VOL_3_8));
-
- /* float voltage charger level = 4.2V */
- ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8,
- PM2XXX_CH_VOLT_4_2);
-
- /* Voltage drop between VBAT and VSYS in HW charging = 300mV */
- ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG9,
- (PM2XXX_CH_150MV_DROP_300MV | PM2XXX_CHARCHING_INFO_DIS |
- PM2XXX_CH_CC_REDUCED_CURRENT_IDENT |
- PM2XXX_CH_CC_MODEDROP_DIS));
-
- /* Input charger level of over voltage = 10V */
- ret = pm2xxx_reg_write(pm2, PM2XXX_INP_VOLT_VPWR2,
- PM2XXX_VPWR2_OVV_10);
- ret = pm2xxx_reg_write(pm2, PM2XXX_INP_VOLT_VPWR1,
- PM2XXX_VPWR1_OVV_10);
-
- /* Input charger drop */
- ret = pm2xxx_reg_write(pm2, PM2XXX_INP_DROP_VPWR2,
- (PM2XXX_VPWR2_HW_OPT_DIS | PM2XXX_VPWR2_VALID_DIS |
- PM2XXX_VPWR2_DROP_DIS));
- ret = pm2xxx_reg_write(pm2, PM2XXX_INP_DROP_VPWR1,
- (PM2XXX_VPWR1_HW_OPT_DIS | PM2XXX_VPWR1_VALID_DIS |
- PM2XXX_VPWR1_DROP_DIS));
-
- /* Disable battery low monitoring */
- ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_LOW_LEV_COMP_REG,
- PM2XXX_VBAT_LOW_MONITORING_ENA);
-
- return ret;
-}
-
-static int pm2xxx_charger_ac_en(struct ux500_charger *charger,
- int enable, int vset, int iset)
-{
- int ret;
- int volt_index;
- int curr_index;
- u8 val;
-
- struct pm2xxx_charger *pm2 = to_pm2xxx_charger_ac_device_info(charger);
-
- if (enable) {
- if (!pm2->ac.charger_connected) {
- dev_dbg(pm2->dev, "AC charger not connected\n");
- return -ENXIO;
- }
-
- dev_dbg(pm2->dev, "Enable AC: %dmV %dmA\n", vset, iset);
- if (!pm2->vddadc_en_ac) {
- ret = regulator_enable(pm2->regu);
- if (ret)
- dev_warn(pm2->dev,
- "Failed to enable vddadc regulator\n");
- else
- pm2->vddadc_en_ac = true;
- }
-
- ret = pm2xxx_charging_init(pm2);
- if (ret < 0) {
- dev_err(pm2->dev, "%s charging init failed\n",
- __func__);
- goto error_occured;
- }
-
- volt_index = pm2xxx_voltage_to_regval(vset);
- curr_index = pm2xxx_current_to_regval(iset);
-
- if (volt_index < 0 || curr_index < 0) {
- dev_err(pm2->dev,
- "Charger voltage or current too high, "
- "charging not started\n");
- return -ENXIO;
- }
-
- ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG8, &val);
- if (ret < 0) {
- dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
- goto error_occured;
- }
- val &= ~PM2XXX_CH_VOLT_MASK;
- val |= volt_index;
- ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8, val);
- if (ret < 0) {
- dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
- goto error_occured;
- }
-
- ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val);
- if (ret < 0) {
- dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
- goto error_occured;
- }
- val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK;
- val |= curr_index;
- ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val);
- if (ret < 0) {
- dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
- goto error_occured;
- }
-
- if (!pm2->bat->enable_overshoot) {
- ret = pm2xxx_reg_read(pm2, PM2XXX_LED_CTRL_REG, &val);
- if (ret < 0) {
- dev_err(pm2->dev, "%s pm2xxx read failed\n",
- __func__);
- goto error_occured;
- }
- val |= PM2XXX_ANTI_OVERSHOOT_EN;
- ret = pm2xxx_reg_write(pm2, PM2XXX_LED_CTRL_REG, val);
- if (ret < 0) {
- dev_err(pm2->dev, "%s pm2xxx write failed\n",
- __func__);
- goto error_occured;
- }
- }
-
- ret = pm2xxx_charging_enable_mngt(pm2);
- if (ret < 0) {
- dev_err(pm2->dev, "Failed to enable"
- "pm2xxx ac charger\n");
- goto error_occured;
- }
-
- pm2->ac.charger_online = 1;
- } else {
- pm2->ac.charger_online = 0;
- pm2->ac.wd_expired = false;
-
- /* Disable regulator if enabled */
- if (pm2->vddadc_en_ac) {
- regulator_disable(pm2->regu);
- pm2->vddadc_en_ac = false;
- }
-
- ret = pm2xxx_charging_disable_mngt(pm2);
- if (ret < 0) {
- dev_err(pm2->dev, "failed to disable"
- "pm2xxx ac charger\n");
- goto error_occured;
- }
-
- dev_dbg(pm2->dev, "PM2301: " "Disabled AC charging\n");
- }
- power_supply_changed(pm2->ac_chg.psy);
-
-error_occured:
- return ret;
-}
-
-static int pm2xxx_charger_watchdog_kick(struct ux500_charger *charger)
-{
- int ret;
- struct pm2xxx_charger *pm2;
-
- if (charger->psy->desc->type == POWER_SUPPLY_TYPE_MAINS)
- pm2 = to_pm2xxx_charger_ac_device_info(charger);
- else
- return -ENXIO;
-
- ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_WD_KICK, WD_TIMER);
- if (ret)
- dev_err(pm2->dev, "Failed to kick WD!\n");
-
- return ret;
-}
-
-static void pm2xxx_charger_ac_work(struct work_struct *work)
-{
- struct pm2xxx_charger *pm2 = container_of(work,
- struct pm2xxx_charger, ac_work);
-
-
- power_supply_changed(pm2->ac_chg.psy);
- sysfs_notify(&pm2->ac_chg.psy->dev.kobj, NULL, "present");
-};
-
-static void pm2xxx_charger_check_hw_failure_work(struct work_struct *work)
-{
- u8 reg_value;
-
- struct pm2xxx_charger *pm2 = container_of(work,
- struct pm2xxx_charger, check_hw_failure_work.work);
-
- if (pm2->flags.ovv) {
- pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT4, &reg_value);
-
- if (!(reg_value & (PM2XXX_INT4_S_ITVPWR1OVV |
- PM2XXX_INT4_S_ITVPWR2OVV))) {
- pm2->flags.ovv = false;
- power_supply_changed(pm2->ac_chg.psy);
- }
- }
-
- /* If we still have a failure, schedule a new check */
- if (pm2->flags.ovv) {
- queue_delayed_work(pm2->charger_wq,
- &pm2->check_hw_failure_work, round_jiffies(HZ));
- }
-}
-
-static void pm2xxx_charger_check_main_thermal_prot_work(
- struct work_struct *work)
-{
- int ret;
- u8 val;
-
- struct pm2xxx_charger *pm2 = container_of(work, struct pm2xxx_charger,
- check_main_thermal_prot_work);
-
- /* Check if die temp warning is still active */
- ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT5, &val);
- if (ret < 0) {
- dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
- return;
- }
- if (val & (PM2XXX_INT5_S_ITTHERMALWARNINGRISE
- | PM2XXX_INT5_S_ITTHERMALSHUTDOWNRISE))
- pm2->flags.main_thermal_prot = true;
- else if (val & (PM2XXX_INT5_S_ITTHERMALWARNINGFALL
- | PM2XXX_INT5_S_ITTHERMALSHUTDOWNFALL))
- pm2->flags.main_thermal_prot = false;
-
- power_supply_changed(pm2->ac_chg.psy);
-}
-
-static struct pm2xxx_interrupts pm2xxx_int = {
- .handler[0] = pm2_int_reg0,
- .handler[1] = pm2_int_reg1,
- .handler[2] = pm2_int_reg2,
- .handler[3] = pm2_int_reg3,
- .handler[4] = pm2_int_reg4,
- .handler[5] = pm2_int_reg5,
-};
-
-static struct pm2xxx_irq pm2xxx_charger_irq[] = {
- {"PM2XXX_IRQ_INT", pm2xxx_irq_int},
-};
-
-static int __maybe_unused pm2xxx_wall_charger_resume(struct device *dev)
-{
- struct i2c_client *i2c_client = to_i2c_client(dev);
- struct pm2xxx_charger *pm2;
-
- pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(i2c_client);
- set_lpn_pin(pm2);
-
- /* If we still have a HW failure, schedule a new check */
- if (pm2->flags.ovv)
- queue_delayed_work(pm2->charger_wq,
- &pm2->check_hw_failure_work, 0);
-
- return 0;
-}
-
-static int __maybe_unused pm2xxx_wall_charger_suspend(struct device *dev)
-{
- struct i2c_client *i2c_client = to_i2c_client(dev);
- struct pm2xxx_charger *pm2;
-
- pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(i2c_client);
- clear_lpn_pin(pm2);
-
- /* Cancel any pending HW failure check */
- if (delayed_work_pending(&pm2->check_hw_failure_work))
- cancel_delayed_work(&pm2->check_hw_failure_work);
-
- flush_work(&pm2->ac_work);
- flush_work(&pm2->check_main_thermal_prot_work);
-
- return 0;
-}
-
-static int __maybe_unused pm2xxx_runtime_suspend(struct device *dev)
-{
- struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev);
- struct pm2xxx_charger *pm2;
-
- pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(pm2xxx_i2c_client);
- clear_lpn_pin(pm2);
-
- return 0;
-}
-
-static int __maybe_unused pm2xxx_runtime_resume(struct device *dev)
-{
- struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev);
- struct pm2xxx_charger *pm2;
-
- pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(pm2xxx_i2c_client);
-
- if (gpio_is_valid(pm2->lpn_pin) && gpio_get_value(pm2->lpn_pin) == 0)
- set_lpn_pin(pm2);
-
- return 0;
-}
-
-static const struct dev_pm_ops pm2xxx_pm_ops __maybe_unused = {
- SET_SYSTEM_SLEEP_PM_OPS(pm2xxx_wall_charger_suspend,
- pm2xxx_wall_charger_resume)
- SET_RUNTIME_PM_OPS(pm2xxx_runtime_suspend, pm2xxx_runtime_resume, NULL)
-};
-
-static int pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
- const struct i2c_device_id *id)
-{
- struct pm2xxx_platform_data *pl_data = i2c_client->dev.platform_data;
- struct power_supply_config psy_cfg = {};
- struct pm2xxx_charger *pm2;
- int ret = 0;
- u8 val;
- int i;
-
- if (!pl_data) {
- dev_err(&i2c_client->dev, "No platform data supplied\n");
- return -EINVAL;
- }
-
- pm2 = kzalloc(sizeof(struct pm2xxx_charger), GFP_KERNEL);
- if (!pm2) {
- dev_err(&i2c_client->dev, "pm2xxx_charger allocation failed\n");
- return -ENOMEM;
- }
-
- /* get parent data */
- pm2->dev = &i2c_client->dev;
-
- pm2->pm2_int = &pm2xxx_int;
-
- /* get charger spcific platform data */
- if (!pl_data->wall_charger) {
- dev_err(pm2->dev, "no charger platform data supplied\n");
- ret = -EINVAL;
- goto free_device_info;
- }
-
- pm2->pdata = pl_data->wall_charger;
-
- /* get battery specific platform data */
- if (!pl_data->battery) {
- dev_err(pm2->dev, "no battery platform data supplied\n");
- ret = -EINVAL;
- goto free_device_info;
- }
-
- pm2->bat = pl_data->battery;
-
- if (!i2c_check_functionality(i2c_client->adapter,
- I2C_FUNC_SMBUS_BYTE_DATA |
- I2C_FUNC_SMBUS_READ_WORD_DATA)) {
- ret = -ENODEV;
- dev_info(pm2->dev, "pm2301 i2c_check_functionality failed\n");
- goto free_device_info;
- }
-
- pm2->config.pm2xxx_i2c = i2c_client;
- pm2->config.pm2xxx_id = (struct i2c_device_id *) id;
- i2c_set_clientdata(i2c_client, pm2);
-
- /* AC supply */
- /* power_supply base class */
- pm2->ac_chg_desc.name = pm2->pdata->label;
- pm2->ac_chg_desc.type = POWER_SUPPLY_TYPE_MAINS;
- pm2->ac_chg_desc.properties = pm2xxx_charger_ac_props;
- pm2->ac_chg_desc.num_properties = ARRAY_SIZE(pm2xxx_charger_ac_props);
- pm2->ac_chg_desc.get_property = pm2xxx_charger_ac_get_property;
-
- psy_cfg.supplied_to = pm2->pdata->supplied_to;
- psy_cfg.num_supplicants = pm2->pdata->num_supplicants;
- /* pm2xxx_charger sub-class */
- pm2->ac_chg.ops.enable = &pm2xxx_charger_ac_en;
- pm2->ac_chg.ops.kick_wd = &pm2xxx_charger_watchdog_kick;
- pm2->ac_chg.ops.update_curr = &pm2xxx_charger_update_charger_current;
- pm2->ac_chg.max_out_volt = pm2xxx_charger_voltage_map[
- ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1];
- pm2->ac_chg.max_out_curr = pm2xxx_charger_current_map[
- ARRAY_SIZE(pm2xxx_charger_current_map) - 1];
- pm2->ac_chg.wdt_refresh = WD_KICK_INTERVAL;
- pm2->ac_chg.enabled = true;
- pm2->ac_chg.external = true;
-
- /* Create a work queue for the charger */
- pm2->charger_wq = alloc_ordered_workqueue("pm2xxx_charger_wq",
- WQ_MEM_RECLAIM);
- if (pm2->charger_wq == NULL) {
- ret = -ENOMEM;
- dev_err(pm2->dev, "failed to create work queue\n");
- goto free_device_info;
- }
-
- /* Init work for charger detection */
- INIT_WORK(&pm2->ac_work, pm2xxx_charger_ac_work);
-
- /* Init work for checking HW status */
- INIT_WORK(&pm2->check_main_thermal_prot_work,
- pm2xxx_charger_check_main_thermal_prot_work);
-
- /* Init work for HW failure check */
- INIT_DEFERRABLE_WORK(&pm2->check_hw_failure_work,
- pm2xxx_charger_check_hw_failure_work);
-
- /*
- * VDD ADC supply needs to be enabled from this driver when there
- * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
- * interrupts during charging
- */
- pm2->regu = regulator_get(pm2->dev, "vddadc");
- if (IS_ERR(pm2->regu)) {
- ret = PTR_ERR(pm2->regu);
- dev_err(pm2->dev, "failed to get vddadc regulator\n");
- goto free_charger_wq;
- }
-
- /* Register AC charger class */
- pm2->ac_chg.psy = power_supply_register(pm2->dev, &pm2->ac_chg_desc,
- &psy_cfg);
- if (IS_ERR(pm2->ac_chg.psy)) {
- dev_err(pm2->dev, "failed to register AC charger\n");
- ret = PTR_ERR(pm2->ac_chg.psy);
- goto free_regulator;
- }
-
- /* Register interrupts */
- ret = request_threaded_irq(gpio_to_irq(pm2->pdata->gpio_irq_number),
- NULL,
- pm2xxx_charger_irq[0].isr,
- pm2->pdata->irq_type | IRQF_ONESHOT,
- pm2xxx_charger_irq[0].name, pm2);
-
- if (ret != 0) {
- dev_err(pm2->dev, "failed to request %s IRQ %d: %d\n",
- pm2xxx_charger_irq[0].name,
- gpio_to_irq(pm2->pdata->gpio_irq_number), ret);
- goto unregister_pm2xxx_charger;
- }
-
- ret = pm_runtime_set_active(pm2->dev);
- if (ret)
- dev_err(pm2->dev, "set active Error\n");
-
- pm_runtime_enable(pm2->dev);
- pm_runtime_set_autosuspend_delay(pm2->dev, PM2XXX_AUTOSUSPEND_DELAY);
- pm_runtime_use_autosuspend(pm2->dev);
- pm_runtime_resume(pm2->dev);
-
- /* pm interrupt can wake up system */
- ret = enable_irq_wake(gpio_to_irq(pm2->pdata->gpio_irq_number));
- if (ret) {
- dev_err(pm2->dev, "failed to set irq wake\n");
- goto unregister_pm2xxx_interrupt;
- }
-
- mutex_init(&pm2->lock);
-
- if (gpio_is_valid(pm2->pdata->lpn_gpio)) {
- /* get lpn GPIO from platform data */
- pm2->lpn_pin = pm2->pdata->lpn_gpio;
-
- /*
- * Charger detection mechanism requires pulling up the LPN pin
- * while i2c communication if Charger is not connected
- * LPN pin of PM2301 is GPIO60 of AB9540
- */
- ret = gpio_request(pm2->lpn_pin, "pm2301_lpm_gpio");
-
- if (ret < 0) {
- dev_err(pm2->dev, "pm2301_lpm_gpio request failed\n");
- goto disable_pm2_irq_wake;
- }
- ret = gpio_direction_output(pm2->lpn_pin, 0);
- if (ret < 0) {
- dev_err(pm2->dev, "pm2301_lpm_gpio direction failed\n");
- goto free_gpio;
- }
- set_lpn_pin(pm2);
- }
-
- /* read interrupt registers */
- for (i = 0; i < PM2XXX_NUM_INT_REG; i++)
- pm2xxx_reg_read(pm2,
- pm2xxx_interrupt_registers[i],
- &val);
-
- ret = pm2xxx_charger_detection(pm2, &val);
-
- if ((ret == 0) && val) {
- pm2->ac.charger_connected = 1;
- ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON,
- AB8500_MAIN_CH_DET);
- pm2->ac_conn = true;
- power_supply_changed(pm2->ac_chg.psy);
- sysfs_notify(&pm2->ac_chg.psy->dev.kobj, NULL, "present");
- }
-
- return 0;
-
-free_gpio:
- if (gpio_is_valid(pm2->lpn_pin))
- gpio_free(pm2->lpn_pin);
-disable_pm2_irq_wake:
- disable_irq_wake(gpio_to_irq(pm2->pdata->gpio_irq_number));
-unregister_pm2xxx_interrupt:
- /* disable interrupt */
- free_irq(gpio_to_irq(pm2->pdata->gpio_irq_number), pm2);
-unregister_pm2xxx_charger:
- /* unregister power supply */
- power_supply_unregister(pm2->ac_chg.psy);
-free_regulator:
- /* disable the regulator */
- regulator_put(pm2->regu);
-free_charger_wq:
- destroy_workqueue(pm2->charger_wq);
-free_device_info:
- kfree(pm2);
-
- return ret;
-}
-
-static int pm2xxx_wall_charger_remove(struct i2c_client *i2c_client)
-{
- struct pm2xxx_charger *pm2 = i2c_get_clientdata(i2c_client);
-
- /* Disable pm_runtime */
- pm_runtime_disable(pm2->dev);
- /* Disable AC charging */
- pm2xxx_charger_ac_en(&pm2->ac_chg, false, 0, 0);
-
- /* Disable wake by pm interrupt */
- disable_irq_wake(gpio_to_irq(pm2->pdata->gpio_irq_number));
-
- /* Disable interrupts */
- free_irq(gpio_to_irq(pm2->pdata->gpio_irq_number), pm2);
-
- /* Delete the work queue */
- destroy_workqueue(pm2->charger_wq);
-
- flush_scheduled_work();
-
- /* disable the regulator */
- regulator_put(pm2->regu);
-
- power_supply_unregister(pm2->ac_chg.psy);
-
- if (gpio_is_valid(pm2->lpn_pin))
- gpio_free(pm2->lpn_pin);
-
- kfree(pm2);
-
- return 0;
-}
-
-static const struct i2c_device_id pm2xxx_id[] = {
- { "pm2301", 0 },
- { }
-};
-
-MODULE_DEVICE_TABLE(i2c, pm2xxx_id);
-
-static struct i2c_driver pm2xxx_charger_driver = {
- .probe = pm2xxx_wall_charger_probe,
- .remove = pm2xxx_wall_charger_remove,
- .driver = {
- .name = "pm2xxx-wall_charger",
- .pm = IS_ENABLED(CONFIG_PM) ? &pm2xxx_pm_ops : NULL,
- },
- .id_table = pm2xxx_id,
-};
-
-static int __init pm2xxx_charger_init(void)
-{
- return i2c_add_driver(&pm2xxx_charger_driver);
-}
-
-static void __exit pm2xxx_charger_exit(void)
-{
- i2c_del_driver(&pm2xxx_charger_driver);
-}
-
-device_initcall_sync(pm2xxx_charger_init);
-module_exit(pm2xxx_charger_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Rajkumar kasirajan, Olivier Launay");
-MODULE_DESCRIPTION("PM2xxx charger management driver");
diff --git a/drivers/power/supply/rn5t618_power.c b/drivers/power/supply/rn5t618_power.c
index dee520f0fdf5..819061918b2a 100644
--- a/drivers/power/supply/rn5t618_power.c
+++ b/drivers/power/supply/rn5t618_power.c
@@ -37,8 +37,27 @@
#define CHG_STATE_NO_BAT2 13
#define CHG_STATE_CHG_READY_VUSB 14
+#define GCHGDET_TYPE_MASK 0x30
+#define GCHGDET_TYPE_SDP 0x00
+#define GCHGDET_TYPE_CDP 0x10
+#define GCHGDET_TYPE_DCP 0x20
+
#define FG_ENABLE 1
+/*
+ * Formula seems accurate for battery current, but for USB current around 70mA
+ * per step was seen on Kobo Clara HD but all sources show the same formula
+ * also fur USB current. To avoid accidentially unwanted high currents we stick
+ * to that formula
+ */
+#define TO_CUR_REG(x) ((x) / 100000 - 1)
+#define FROM_CUR_REG(x) ((((x) & 0x1f) + 1) * 100000)
+#define CHG_MIN_CUR 100000
+#define CHG_MAX_CUR 1800000
+#define ADP_MAX_CUR 2500000
+#define USB_MAX_CUR 1400000
+
+
struct rn5t618_power_info {
struct rn5t618 *rn5t618;
struct platform_device *pdev;
@@ -48,12 +67,24 @@ struct rn5t618_power_info {
int irq;
};
+static enum power_supply_usb_type rn5t618_usb_types[] = {
+ POWER_SUPPLY_USB_TYPE_SDP,
+ POWER_SUPPLY_USB_TYPE_DCP,
+ POWER_SUPPLY_USB_TYPE_CDP,
+ POWER_SUPPLY_USB_TYPE_UNKNOWN
+};
+
static enum power_supply_property rn5t618_usb_props[] = {
+ /* input current limit is not very accurate */
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_USB_TYPE,
POWER_SUPPLY_PROP_ONLINE,
};
static enum power_supply_property rn5t618_adp_props[] = {
+ /* input current limit is not very accurate */
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_ONLINE,
};
@@ -69,6 +100,7 @@ static enum power_supply_property rn5t618_battery_props[] = {
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_NOW,
};
@@ -258,6 +290,36 @@ static int rn5t618_battery_ttf(struct rn5t618_power_info *info,
return 0;
}
+static int rn5t618_battery_set_current_limit(struct rn5t618_power_info *info,
+ const union power_supply_propval *val)
+{
+ if (val->intval < CHG_MIN_CUR)
+ return -EINVAL;
+
+ if (val->intval >= CHG_MAX_CUR)
+ return -EINVAL;
+
+ return regmap_update_bits(info->rn5t618->regmap,
+ RN5T618_CHGISET,
+ 0x1F, TO_CUR_REG(val->intval));
+}
+
+static int rn5t618_battery_get_current_limit(struct rn5t618_power_info *info,
+ union power_supply_propval *val)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGISET,
+ &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = FROM_CUR_REG(regval);
+
+ return 0;
+}
+
static int rn5t618_battery_charge_full(struct rn5t618_power_info *info,
union power_supply_propval *val)
{
@@ -323,6 +385,9 @@ static int rn5t618_battery_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_TECHNOLOGY:
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
break;
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+ ret = rn5t618_battery_get_current_limit(info, val);
+ break;
case POWER_SUPPLY_PROP_CHARGE_FULL:
ret = rn5t618_battery_charge_full(info, val);
break;
@@ -336,12 +401,38 @@ static int rn5t618_battery_get_property(struct power_supply *psy,
return ret;
}
+static int rn5t618_battery_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+ return rn5t618_battery_set_current_limit(info, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rn5t618_battery_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
static int rn5t618_adp_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
unsigned int chgstate;
+ unsigned int regval;
bool online;
int ret;
@@ -365,6 +456,14 @@ static int rn5t618_adp_get_property(struct power_supply *psy,
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
break;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ ret = regmap_read(info->rn5t618->regmap,
+ RN5T618_REGISET1, &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = FROM_CUR_REG(regval);
+ break;
default:
return -EINVAL;
}
@@ -372,12 +471,79 @@ static int rn5t618_adp_get_property(struct power_supply *psy,
return 0;
}
+static int rn5t618_adp_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
+ int ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ if (val->intval > ADP_MAX_CUR)
+ return -EINVAL;
+
+ if (val->intval < CHG_MIN_CUR)
+ return -EINVAL;
+
+ ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET1,
+ TO_CUR_REG(val->intval));
+ if (ret < 0)
+ return ret;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rn5t618_adp_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int rc5t619_usb_get_type(struct rn5t618_power_info *info,
+ union power_supply_propval *val)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->rn5t618->regmap, RN5T618_GCHGDET, &regval);
+ if (ret < 0)
+ return ret;
+
+ switch (regval & GCHGDET_TYPE_MASK) {
+ case GCHGDET_TYPE_SDP:
+ val->intval = POWER_SUPPLY_USB_TYPE_SDP;
+ break;
+ case GCHGDET_TYPE_CDP:
+ val->intval = POWER_SUPPLY_USB_TYPE_CDP;
+ break;
+ case GCHGDET_TYPE_DCP:
+ val->intval = POWER_SUPPLY_USB_TYPE_DCP;
+ break;
+ default:
+ val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
+ }
+
+ return 0;
+}
+
static int rn5t618_usb_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
unsigned int chgstate;
+ unsigned int regval;
bool online;
int ret;
@@ -401,6 +567,28 @@ static int rn5t618_usb_get_property(struct power_supply *psy,
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
break;
+ case POWER_SUPPLY_PROP_USB_TYPE:
+ if (!online || (info->rn5t618->variant != RC5T619))
+ return -ENODATA;
+
+ return rc5t619_usb_get_type(info, val);
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGCTL1,
+ &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = 0;
+ if (regval & 2) {
+ ret = regmap_read(info->rn5t618->regmap,
+ RN5T618_REGISET2,
+ &regval);
+ if (ret < 0)
+ return ret;
+
+ val->intval = FROM_CUR_REG(regval);
+ }
+ break;
default:
return -EINVAL;
}
@@ -408,12 +596,53 @@ static int rn5t618_usb_get_property(struct power_supply *psy,
return 0;
}
+static int rn5t618_usb_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
+ int ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ if (val->intval > USB_MAX_CUR)
+ return -EINVAL;
+
+ if (val->intval < CHG_MIN_CUR)
+ return -EINVAL;
+
+ ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET2,
+ 0xE0 | TO_CUR_REG(val->intval));
+ if (ret < 0)
+ return ret;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rn5t618_usb_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
static const struct power_supply_desc rn5t618_battery_desc = {
.name = "rn5t618-battery",
.type = POWER_SUPPLY_TYPE_BATTERY,
.properties = rn5t618_battery_props,
.num_properties = ARRAY_SIZE(rn5t618_battery_props),
.get_property = rn5t618_battery_get_property,
+ .set_property = rn5t618_battery_set_property,
+ .property_is_writeable = rn5t618_battery_property_is_writeable,
};
static const struct power_supply_desc rn5t618_adp_desc = {
@@ -422,14 +651,20 @@ static const struct power_supply_desc rn5t618_adp_desc = {
.properties = rn5t618_adp_props,
.num_properties = ARRAY_SIZE(rn5t618_adp_props),
.get_property = rn5t618_adp_get_property,
+ .set_property = rn5t618_adp_set_property,
+ .property_is_writeable = rn5t618_adp_property_is_writeable,
};
static const struct power_supply_desc rn5t618_usb_desc = {
.name = "rn5t618-usb",
.type = POWER_SUPPLY_TYPE_USB,
+ .usb_types = rn5t618_usb_types,
+ .num_usb_types = ARRAY_SIZE(rn5t618_usb_types),
.properties = rn5t618_usb_props,
.num_properties = ARRAY_SIZE(rn5t618_usb_props),
.get_property = rn5t618_usb_get_property,
+ .set_property = rn5t618_usb_set_property,
+ .property_is_writeable = rn5t618_usb_property_is_writeable,
};
static irqreturn_t rn5t618_charger_irq(int irq, void *data)
diff --git a/drivers/power/supply/rt5033_battery.c b/drivers/power/supply/rt5033_battery.c
index f330452341f0..9ad0afe83d1b 100644
--- a/drivers/power/supply/rt5033_battery.c
+++ b/drivers/power/supply/rt5033_battery.c
@@ -164,9 +164,16 @@ static const struct i2c_device_id rt5033_battery_id[] = {
};
MODULE_DEVICE_TABLE(i2c, rt5033_battery_id);
+static const struct of_device_id rt5033_battery_of_match[] = {
+ { .compatible = "richtek,rt5033-battery", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, rt5033_battery_of_match);
+
static struct i2c_driver rt5033_battery_driver = {
.driver = {
.name = "rt5033-battery",
+ .of_match_table = rt5033_battery_of_match,
},
.probe = rt5033_battery_probe,
.remove = rt5033_battery_remove,
diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
index 8d7a10730e43..f84dbaab283a 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -189,6 +189,14 @@ static const enum power_supply_property sbs_properties[] = {
/* Supports special manufacturer commands from TI BQ20Z65 and BQ20Z75 IC. */
#define SBS_FLAGS_TI_BQ20ZX5 BIT(0)
+static const enum power_supply_property string_properties[] = {
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+};
+
+#define NR_STRING_BUFFERS ARRAY_SIZE(string_properties)
+
struct sbs_info {
struct i2c_client *client;
struct power_supply *power_supply;
@@ -202,11 +210,32 @@ struct sbs_info {
struct delayed_work work;
struct mutex mode_lock;
u32 flags;
+ int technology;
+ char strings[NR_STRING_BUFFERS][I2C_SMBUS_BLOCK_MAX + 1];
};
-static char model_name[I2C_SMBUS_BLOCK_MAX + 1];
-static char manufacturer[I2C_SMBUS_BLOCK_MAX + 1];
-static char chemistry[I2C_SMBUS_BLOCK_MAX + 1];
+static char *sbs_get_string_buf(struct sbs_info *chip,
+ enum power_supply_property psp)
+{
+ int i = 0;
+
+ for (i = 0; i < NR_STRING_BUFFERS; i++)
+ if (string_properties[i] == psp)
+ return chip->strings[i];
+
+ return ERR_PTR(-EINVAL);
+}
+
+static void sbs_invalidate_cached_props(struct sbs_info *chip)
+{
+ int i = 0;
+
+ chip->technology = -1;
+
+ for (i = 0; i < NR_STRING_BUFFERS; i++)
+ chip->strings[i][0] = 0;
+}
+
static bool force_load;
static int sbs_read_word_data(struct i2c_client *client, u8 address);
@@ -244,6 +273,7 @@ static int sbs_update_presence(struct sbs_info *chip, bool is_present)
chip->is_present = false;
/* Disable PEC when no device is present */
client->flags &= ~I2C_CLIENT_PEC;
+ sbs_invalidate_cached_props(chip);
return 0;
}
@@ -640,17 +670,45 @@ static int sbs_get_battery_property(struct i2c_client *client,
return 0;
}
-static int sbs_get_battery_string_property(struct i2c_client *client,
- int reg_offset, enum power_supply_property psp, char *val)
+static int sbs_get_property_index(struct i2c_client *client,
+ enum power_supply_property psp)
{
- s32 ret;
+ int count;
- ret = sbs_read_string_data(client, sbs_data[reg_offset].addr, val);
+ for (count = 0; count < ARRAY_SIZE(sbs_data); count++)
+ if (psp == sbs_data[count].psp)
+ return count;
- if (ret < 0)
- return ret;
+ dev_warn(&client->dev,
+ "%s: Invalid Property - %d\n", __func__, psp);
- return 0;
+ return -EINVAL;
+}
+
+static const char *sbs_get_constant_string(struct sbs_info *chip,
+ enum power_supply_property psp)
+{
+ int ret;
+ char *buf;
+ u8 addr;
+
+ buf = sbs_get_string_buf(chip, psp);
+ if (IS_ERR(buf))
+ return buf;
+
+ if (!buf[0]) {
+ ret = sbs_get_property_index(chip->client, psp);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ addr = sbs_data[ret].addr;
+
+ ret = sbs_read_string_data(chip->client, addr, buf);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ }
+
+ return buf;
}
static void sbs_unit_adjustment(struct i2c_client *client,
@@ -773,48 +831,36 @@ static int sbs_get_battery_serial_number(struct i2c_client *client,
return 0;
}
-static int sbs_get_property_index(struct i2c_client *client,
- enum power_supply_property psp)
-{
- int count;
- for (count = 0; count < ARRAY_SIZE(sbs_data); count++)
- if (psp == sbs_data[count].psp)
- return count;
-
- dev_warn(&client->dev,
- "%s: Invalid Property - %d\n", __func__, psp);
-
- return -EINVAL;
-}
-
-static int sbs_get_chemistry(struct i2c_client *client,
+static int sbs_get_chemistry(struct sbs_info *chip,
union power_supply_propval *val)
{
- enum power_supply_property psp = POWER_SUPPLY_PROP_TECHNOLOGY;
- int ret;
+ const char *chemistry;
- ret = sbs_get_property_index(client, psp);
- if (ret < 0)
- return ret;
+ if (chip->technology != -1) {
+ val->intval = chip->technology;
+ return 0;
+ }
- ret = sbs_get_battery_string_property(client, ret, psp,
- chemistry);
- if (ret < 0)
- return ret;
+ chemistry = sbs_get_constant_string(chip, POWER_SUPPLY_PROP_TECHNOLOGY);
+
+ if (IS_ERR(chemistry))
+ return PTR_ERR(chemistry);
if (!strncasecmp(chemistry, "LION", 4))
- val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+ chip->technology = POWER_SUPPLY_TECHNOLOGY_LION;
else if (!strncasecmp(chemistry, "LiP", 3))
- val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO;
+ chip->technology = POWER_SUPPLY_TECHNOLOGY_LIPO;
else if (!strncasecmp(chemistry, "NiCd", 4))
- val->intval = POWER_SUPPLY_TECHNOLOGY_NiCd;
+ chip->technology = POWER_SUPPLY_TECHNOLOGY_NiCd;
else if (!strncasecmp(chemistry, "NiMH", 4))
- val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH;
+ chip->technology = POWER_SUPPLY_TECHNOLOGY_NiMH;
else
- val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
+ chip->technology = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
+
+ if (chip->technology == POWER_SUPPLY_TECHNOLOGY_UNKNOWN)
+ dev_warn(&chip->client->dev, "Unknown chemistry: %s\n", chemistry);
- if (val->intval == POWER_SUPPLY_TECHNOLOGY_UNKNOWN)
- dev_warn(&client->dev, "Unknown chemistry: %s\n", chemistry);
+ val->intval = chip->technology;
return 0;
}
@@ -858,6 +904,7 @@ static int sbs_get_property(struct power_supply *psy,
int ret = 0;
struct sbs_info *chip = power_supply_get_drvdata(psy);
struct i2c_client *client = chip->client;
+ const char *str;
if (chip->gpio_detect) {
ret = gpiod_get_value_cansleep(chip->gpio_detect);
@@ -883,7 +930,7 @@ static int sbs_get_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
- ret = sbs_get_chemistry(client, val);
+ ret = sbs_get_chemistry(chip, val);
if (ret < 0)
break;
@@ -935,23 +982,12 @@ static int sbs_get_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_MODEL_NAME:
- ret = sbs_get_property_index(client, psp);
- if (ret < 0)
- break;
-
- ret = sbs_get_battery_string_property(client, ret, psp,
- model_name);
- val->strval = model_name;
- break;
-
case POWER_SUPPLY_PROP_MANUFACTURER:
- ret = sbs_get_property_index(client, psp);
- if (ret < 0)
- break;
-
- ret = sbs_get_battery_string_property(client, ret, psp,
- manufacturer);
- val->strval = manufacturer;
+ str = sbs_get_constant_string(chip, psp);
+ if (IS_ERR(str))
+ ret = PTR_ERR(str);
+ else
+ val->strval = str;
break;
case POWER_SUPPLY_PROP_MANUFACTURE_YEAR:
@@ -1098,6 +1134,7 @@ static int sbs_probe(struct i2c_client *client)
psy_cfg.of_node = client->dev.of_node;
psy_cfg.drv_data = chip;
chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
+ sbs_invalidate_cached_props(chip);
mutex_init(&chip->mode_lock);
/* use pdata if available, fall back to DT properties,
diff --git a/drivers/power/supply/sc2731_charger.c b/drivers/power/supply/sc2731_charger.c
index 335cb857ef30..288b79836c13 100644
--- a/drivers/power/supply/sc2731_charger.c
+++ b/drivers/power/supply/sc2731_charger.c
@@ -524,6 +524,7 @@ static const struct of_device_id sc2731_charger_of_match[] = {
{ .compatible = "sprd,sc2731-charger", },
{ }
};
+MODULE_DEVICE_TABLE(of, sc2731_charger_of_match);
static struct platform_driver sc2731_charger_driver = {
.driver = {
diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c
index 9c627618c224..1ae8374e1ceb 100644
--- a/drivers/power/supply/sc27xx_fuel_gauge.c
+++ b/drivers/power/supply/sc27xx_fuel_gauge.c
@@ -1342,6 +1342,7 @@ static const struct of_device_id sc27xx_fgu_of_match[] = {
{ .compatible = "sprd,sc2731-fgu", },
{ }
};
+MODULE_DEVICE_TABLE(of, sc27xx_fgu_of_match);
static struct platform_driver sc27xx_fgu_driver = {
.probe = sc27xx_fgu_probe,
diff --git a/drivers/power/supply/smb347-charger.c b/drivers/power/supply/smb347-charger.c
index 3376f42d46c3..df240420f2de 100644
--- a/drivers/power/supply/smb347-charger.c
+++ b/drivers/power/supply/smb347-charger.c
@@ -10,7 +10,6 @@
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/power/supply/surface_battery.c b/drivers/power/supply/surface_battery.c
index 7efa431a62b2..5ec2e6bb2465 100644
--- a/drivers/power/supply/surface_battery.c
+++ b/drivers/power/supply/surface_battery.c
@@ -345,6 +345,16 @@ static u32 spwr_notify_bat(struct ssam_event_notifier *nf, const struct ssam_eve
struct spwr_battery_device *bat = container_of(nf, struct spwr_battery_device, notif);
int status;
+ /*
+ * We cannot use strict matching when registering the notifier as the
+ * EC expects us to register it against instance ID 0. Strict matching
+ * would thus drop events, as those may have non-zero instance IDs in
+ * this subsystem. So we need to check the instance ID of the event
+ * here manually.
+ */
+ if (event->instance_id != bat->sdev->uid.instance)
+ return 0;
+
dev_dbg(&bat->sdev->dev, "power event (cid = %#04x, iid = %#04x, tid = %#04x)\n",
event->command_id, event->instance_id, event->target_id);
@@ -720,8 +730,8 @@ static void spwr_battery_init(struct spwr_battery_device *bat, struct ssam_devic
bat->notif.base.fn = spwr_notify_bat;
bat->notif.event.reg = registry;
bat->notif.event.id.target_category = sdev->uid.category;
- bat->notif.event.id.instance = 0;
- bat->notif.event.mask = SSAM_EVENT_MASK_STRICT;
+ bat->notif.event.id.instance = 0; /* need to register with instance 0 */
+ bat->notif.event.mask = SSAM_EVENT_MASK_TARGET;
bat->notif.event.flags = SSAM_EVENT_SEQUENCED;
bat->psy_desc.name = bat->name;
diff --git a/drivers/power/supply/surface_charger.c b/drivers/power/supply/surface_charger.c
index 81a5b79822c9..a060c36c7766 100644
--- a/drivers/power/supply/surface_charger.c
+++ b/drivers/power/supply/surface_charger.c
@@ -66,7 +66,7 @@ struct spwr_ac_device {
static int spwr_ac_update_unlocked(struct spwr_ac_device *ac)
{
- u32 old = ac->state;
+ __le32 old = ac->state;
int status;
lockdep_assert_held(&ac->lock);
diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c
index bf26cc56b863..d73c4c2ed4e1 100644
--- a/drivers/pps/clients/pps-ldisc.c
+++ b/drivers/pps/clients/pps-ldisc.c
@@ -112,12 +112,13 @@ static int __init pps_tty_init(void)
/* Init PPS_TTY data */
pps_ldisc_ops.owner = THIS_MODULE;
+ pps_ldisc_ops.num = N_PPS;
pps_ldisc_ops.name = "pps_tty";
pps_ldisc_ops.dcd_change = pps_tty_dcd_change;
pps_ldisc_ops.open = pps_tty_open;
pps_ldisc_ops.close = pps_tty_close;
- err = tty_register_ldisc(N_PPS, &pps_ldisc_ops);
+ err = tty_register_ldisc(&pps_ldisc_ops);
if (err)
pr_err("can't register PPS line discipline\n");
else
@@ -128,13 +129,7 @@ static int __init pps_tty_init(void)
static void __exit pps_tty_cleanup(void)
{
- int err;
-
- err = tty_unregister_ldisc(N_PPS);
- if (err)
- pr_err("can't unregister PPS line discipline\n");
- else
- pr_info("PPS line discipline removed\n");
+ tty_unregister_ldisc(&pps_ldisc_ops);
}
module_init(pps_tty_init);
diff --git a/drivers/ps3/ps3-vuart.c b/drivers/ps3/ps3-vuart.c
index e34ae6a442c7..6328abd51ffa 100644
--- a/drivers/ps3/ps3-vuart.c
+++ b/drivers/ps3/ps3-vuart.c
@@ -358,7 +358,7 @@ static int ps3_vuart_raw_write(struct ps3_system_bus_device *dev,
ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written);
if (result) {
- dev_dbg(&dev->core, "%s:%d: lv1_write_virtual_uart failed: "
+ dev_warn(&dev->core, "%s:%d: lv1_write_virtual_uart failed: "
"%s\n", __func__, __LINE__, ps3_result(result));
return result;
}
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index 9d66257e1da5..516e6d14d32e 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -217,9 +217,9 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
/* send pkt */
res = ps3av_vuart_write(ps3av->dev, send_buf, write_len);
if (res < 0) {
- dev_dbg(&ps3av->dev->core,
- "%s: ps3av_vuart_write() failed (result=%d)\n",
- __func__, res);
+ dev_warn(&ps3av->dev->core,
+ "%s:%d: ps3av_vuart_write() failed: %s\n", __func__,
+ __LINE__, ps3_result(res));
return res;
}
@@ -230,9 +230,9 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
res = ps3av_vuart_read(ps3av->dev, recv_buf, PS3AV_HDR_SIZE,
timeout);
if (res != PS3AV_HDR_SIZE) {
- dev_dbg(&ps3av->dev->core,
- "%s: ps3av_vuart_read() failed (result=%d)\n",
- __func__, res);
+ dev_warn(&ps3av->dev->core,
+ "%s:%d: ps3av_vuart_read() failed: %s\n", __func__,
+ __LINE__, ps3_result(res));
return res;
}
@@ -240,9 +240,9 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
res = ps3av_vuart_read(ps3av->dev, &recv_buf->cid,
recv_buf->size, timeout);
if (res < 0) {
- dev_dbg(&ps3av->dev->core,
- "%s: ps3av_vuart_read() failed (result=%d)\n",
- __func__, res);
+ dev_warn(&ps3av->dev->core,
+ "%s:%d: ps3av_vuart_read() failed: %s\n", __func__,
+ __LINE__, ps3_result(res));
return res;
}
res += PS3AV_HDR_SIZE; /* total len */
@@ -251,8 +251,8 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
} while (event);
if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) {
- dev_dbg(&ps3av->dev->core, "%s: reply err (result=%x)\n",
- __func__, recv_buf->cid);
+ dev_warn(&ps3av->dev->core, "%s:%d: reply err: %x\n", __func__,
+ __LINE__, recv_buf->cid);
return -EINVAL;
}
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
index 8673d1743faa..28a6fe342d3e 100644
--- a/drivers/ptp/Makefile
+++ b/drivers/ptp/Makefile
@@ -3,7 +3,7 @@
# Makefile for PTP 1588 clock support.
#
-ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o
+ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o ptp_vclock.o
ptp_kvm-$(CONFIG_X86) := ptp_kvm_x86.o ptp_kvm_common.o
ptp_kvm-$(CONFIG_HAVE_ARM_SMCCC) := ptp_kvm_arm.o ptp_kvm_common.o
obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index 21c4c34c52d8..4dfc52e06704 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -24,10 +24,11 @@
#define PTP_PPS_EVENT PPS_CAPTUREASSERT
#define PTP_PPS_MODE (PTP_PPS_DEFAULTS | PPS_CANWAIT | PPS_TSFMT_TSPEC)
+struct class *ptp_class;
+
/* private globals */
static dev_t ptp_devt;
-static struct class *ptp_class;
static DEFINE_IDA(ptp_clocks_map);
@@ -63,27 +64,6 @@ static void enqueue_external_timestamp(struct timestamp_event_queue *queue,
spin_unlock_irqrestore(&queue->lock, flags);
}
-long scaled_ppm_to_ppb(long ppm)
-{
- /*
- * The 'freq' field in the 'struct timex' is in parts per
- * million, but with a 16 bit binary fractional field.
- *
- * We want to calculate
- *
- * ppb = scaled_ppm * 1000 / 2^16
- *
- * which simplifies to
- *
- * ppb = scaled_ppm * 125 / 2^13
- */
- s64 ppb = 1 + ppm;
- ppb *= 125;
- ppb >>= 13;
- return (long) ppb;
-}
-EXPORT_SYMBOL(scaled_ppm_to_ppb);
-
/* posix clock implementation */
static int ptp_clock_getres(struct posix_clock *pc, struct timespec64 *tp)
@@ -97,6 +77,11 @@ static int ptp_clock_settime(struct posix_clock *pc, const struct timespec64 *tp
{
struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+ if (ptp_vclock_in_use(ptp)) {
+ pr_err("ptp: virtual clock in use\n");
+ return -EBUSY;
+ }
+
return ptp->info->settime64(ptp->info, tp);
}
@@ -118,6 +103,11 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx)
struct ptp_clock_info *ops;
int err = -EOPNOTSUPP;
+ if (ptp_vclock_in_use(ptp)) {
+ pr_err("ptp: virtual clock in use\n");
+ return -EBUSY;
+ }
+
ops = ptp->info;
if (tx->modes & ADJ_SETOFFSET) {
@@ -182,6 +172,7 @@ static void ptp_clock_release(struct device *dev)
ptp_cleanup_pin_groups(ptp);
mutex_destroy(&ptp->tsevq_mux);
mutex_destroy(&ptp->pincfg_mux);
+ mutex_destroy(&ptp->n_vclocks_mux);
ida_simple_remove(&ptp_clocks_map, ptp->index);
kfree(ptp);
}
@@ -206,6 +197,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
{
struct ptp_clock *ptp;
int err = 0, index, major = MAJOR(ptp_devt);
+ size_t size;
if (info->n_alarm > PTP_MAX_ALARMS)
return ERR_PTR(-EINVAL);
@@ -229,6 +221,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
spin_lock_init(&ptp->tsevq.lock);
mutex_init(&ptp->tsevq_mux);
mutex_init(&ptp->pincfg_mux);
+ mutex_init(&ptp->n_vclocks_mux);
init_waitqueue_head(&ptp->tsev_wq);
if (ptp->info->do_aux_work) {
@@ -241,6 +234,22 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
}
}
+ /* PTP virtual clock is being registered under physical clock */
+ if (parent && parent->class && parent->class->name &&
+ strcmp(parent->class->name, "ptp") == 0)
+ ptp->is_virtual_clock = true;
+
+ if (!ptp->is_virtual_clock) {
+ ptp->max_vclocks = PTP_DEFAULT_MAX_VCLOCKS;
+
+ size = sizeof(int) * ptp->max_vclocks;
+ ptp->vclock_index = kzalloc(size, GFP_KERNEL);
+ if (!ptp->vclock_index) {
+ err = -ENOMEM;
+ goto no_mem_for_vclocks;
+ }
+ }
+
err = ptp_populate_pin_groups(ptp);
if (err)
goto no_pin_groups;
@@ -258,6 +267,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
pr_err("failed to register pps source\n");
goto no_pps;
}
+ ptp->pps_source->lookup_cookie = ptp;
}
/* Initialize a new device of our class in our clock structure. */
@@ -285,11 +295,14 @@ no_clock:
no_pps:
ptp_cleanup_pin_groups(ptp);
no_pin_groups:
+ kfree(ptp->vclock_index);
+no_mem_for_vclocks:
if (ptp->kworker)
kthread_destroy_worker(ptp->kworker);
kworker_err:
mutex_destroy(&ptp->tsevq_mux);
mutex_destroy(&ptp->pincfg_mux);
+ mutex_destroy(&ptp->n_vclocks_mux);
ida_simple_remove(&ptp_clocks_map, index);
no_slot:
kfree(ptp);
@@ -300,9 +313,16 @@ EXPORT_SYMBOL(ptp_clock_register);
int ptp_clock_unregister(struct ptp_clock *ptp)
{
+ if (ptp_vclock_in_use(ptp)) {
+ pr_err("ptp: virtual clock in use\n");
+ return -EBUSY;
+ }
+
ptp->defunct = 1;
wake_up_interruptible(&ptp->tsev_wq);
+ kfree(ptp->vclock_index);
+
if (ptp->kworker) {
kthread_cancel_delayed_work_sync(&ptp->aux_work);
kthread_destroy_worker(ptp->kworker);
diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h
index 6b97155148f1..dba6be477067 100644
--- a/drivers/ptp/ptp_private.h
+++ b/drivers/ptp/ptp_private.h
@@ -18,6 +18,7 @@
#define PTP_MAX_TIMESTAMPS 128
#define PTP_BUF_TIMESTAMPS 30
+#define PTP_DEFAULT_MAX_VCLOCKS 20
struct timestamp_event_queue {
struct ptp_extts_event buf[PTP_MAX_TIMESTAMPS];
@@ -46,6 +47,24 @@ struct ptp_clock {
const struct attribute_group *pin_attr_groups[2];
struct kthread_worker *kworker;
struct kthread_delayed_work aux_work;
+ unsigned int max_vclocks;
+ unsigned int n_vclocks;
+ int *vclock_index;
+ struct mutex n_vclocks_mux; /* protect concurrent n_vclocks access */
+ bool is_virtual_clock;
+};
+
+#define info_to_vclock(d) container_of((d), struct ptp_vclock, info)
+#define cc_to_vclock(d) container_of((d), struct ptp_vclock, cc)
+#define dw_to_vclock(d) container_of((d), struct ptp_vclock, refresh_work)
+
+struct ptp_vclock {
+ struct ptp_clock *pclock;
+ struct ptp_clock_info info;
+ struct ptp_clock *clock;
+ struct cyclecounter cc;
+ struct timecounter tc;
+ spinlock_t lock; /* protects tc/cc */
};
/*
@@ -61,6 +80,24 @@ static inline int queue_cnt(struct timestamp_event_queue *q)
return cnt < 0 ? PTP_MAX_TIMESTAMPS + cnt : cnt;
}
+/* Check if ptp virtual clock is in use */
+static inline bool ptp_vclock_in_use(struct ptp_clock *ptp)
+{
+ bool in_use = false;
+
+ if (mutex_lock_interruptible(&ptp->n_vclocks_mux))
+ return true;
+
+ if (!ptp->is_virtual_clock && ptp->n_vclocks)
+ in_use = true;
+
+ mutex_unlock(&ptp->n_vclocks_mux);
+
+ return in_use;
+}
+
+extern struct class *ptp_class;
+
/*
* see ptp_chardev.c
*/
@@ -89,4 +126,6 @@ extern const struct attribute_group *ptp_groups[];
int ptp_populate_pin_groups(struct ptp_clock *ptp);
void ptp_cleanup_pin_groups(struct ptp_clock *ptp);
+struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock);
+void ptp_vclock_unregister(struct ptp_vclock *vclock);
#endif
diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c
index be076a91e20e..b3d96b747292 100644
--- a/drivers/ptp/ptp_sysfs.c
+++ b/drivers/ptp/ptp_sysfs.c
@@ -3,6 +3,7 @@
* PTP 1588 clock support - sysfs interface.
*
* Copyright (C) 2010 OMICRON electronics GmbH
+ * Copyright 2021 NXP
*/
#include <linux/capability.h>
#include <linux/slab.h>
@@ -148,6 +149,159 @@ out:
}
static DEVICE_ATTR(pps_enable, 0220, NULL, pps_enable_store);
+static int unregister_vclock(struct device *dev, void *data)
+{
+ struct ptp_clock *ptp = dev_get_drvdata(dev);
+ struct ptp_clock_info *info = ptp->info;
+ struct ptp_vclock *vclock;
+ u8 *num = data;
+
+ vclock = info_to_vclock(info);
+ dev_info(dev->parent, "delete virtual clock ptp%d\n",
+ vclock->clock->index);
+
+ ptp_vclock_unregister(vclock);
+ (*num)--;
+
+ /* For break. Not error. */
+ if (*num == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static ssize_t n_vclocks_show(struct device *dev,
+ struct device_attribute *attr, char *page)
+{
+ struct ptp_clock *ptp = dev_get_drvdata(dev);
+ ssize_t size;
+
+ if (mutex_lock_interruptible(&ptp->n_vclocks_mux))
+ return -ERESTARTSYS;
+
+ size = snprintf(page, PAGE_SIZE - 1, "%u\n", ptp->n_vclocks);
+
+ mutex_unlock(&ptp->n_vclocks_mux);
+
+ return size;
+}
+
+static ssize_t n_vclocks_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ptp_clock *ptp = dev_get_drvdata(dev);
+ struct ptp_vclock *vclock;
+ int err = -EINVAL;
+ u32 num, i;
+
+ if (kstrtou32(buf, 0, &num))
+ return err;
+
+ if (mutex_lock_interruptible(&ptp->n_vclocks_mux))
+ return -ERESTARTSYS;
+
+ if (num > ptp->max_vclocks) {
+ dev_err(dev, "max value is %d\n", ptp->max_vclocks);
+ goto out;
+ }
+
+ /* Need to create more vclocks */
+ if (num > ptp->n_vclocks) {
+ for (i = 0; i < num - ptp->n_vclocks; i++) {
+ vclock = ptp_vclock_register(ptp);
+ if (!vclock)
+ goto out;
+
+ *(ptp->vclock_index + ptp->n_vclocks + i) =
+ vclock->clock->index;
+
+ dev_info(dev, "new virtual clock ptp%d\n",
+ vclock->clock->index);
+ }
+ }
+
+ /* Need to delete vclocks */
+ if (num < ptp->n_vclocks) {
+ i = ptp->n_vclocks - num;
+ device_for_each_child_reverse(dev, &i,
+ unregister_vclock);
+
+ for (i = 1; i <= ptp->n_vclocks - num; i++)
+ *(ptp->vclock_index + ptp->n_vclocks - i) = -1;
+ }
+
+ if (num == 0)
+ dev_info(dev, "only physical clock in use now\n");
+ else
+ dev_info(dev, "guarantee physical clock free running\n");
+
+ ptp->n_vclocks = num;
+ mutex_unlock(&ptp->n_vclocks_mux);
+
+ return count;
+out:
+ mutex_unlock(&ptp->n_vclocks_mux);
+ return err;
+}
+static DEVICE_ATTR_RW(n_vclocks);
+
+static ssize_t max_vclocks_show(struct device *dev,
+ struct device_attribute *attr, char *page)
+{
+ struct ptp_clock *ptp = dev_get_drvdata(dev);
+ ssize_t size;
+
+ size = snprintf(page, PAGE_SIZE - 1, "%u\n", ptp->max_vclocks);
+
+ return size;
+}
+
+static ssize_t max_vclocks_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ptp_clock *ptp = dev_get_drvdata(dev);
+ unsigned int *vclock_index;
+ int err = -EINVAL;
+ size_t size;
+ u32 max;
+
+ if (kstrtou32(buf, 0, &max) || max == 0)
+ return -EINVAL;
+
+ if (max == ptp->max_vclocks)
+ return count;
+
+ if (mutex_lock_interruptible(&ptp->n_vclocks_mux))
+ return -ERESTARTSYS;
+
+ if (max < ptp->n_vclocks)
+ goto out;
+
+ size = sizeof(int) * max;
+ vclock_index = kzalloc(size, GFP_KERNEL);
+ if (!vclock_index) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ size = sizeof(int) * ptp->n_vclocks;
+ memcpy(vclock_index, ptp->vclock_index, size);
+
+ kfree(ptp->vclock_index);
+ ptp->vclock_index = vclock_index;
+ ptp->max_vclocks = max;
+
+ mutex_unlock(&ptp->n_vclocks_mux);
+
+ return count;
+out:
+ mutex_unlock(&ptp->n_vclocks_mux);
+ return err;
+}
+static DEVICE_ATTR_RW(max_vclocks);
+
static struct attribute *ptp_attrs[] = {
&dev_attr_clock_name.attr,
@@ -162,6 +316,8 @@ static struct attribute *ptp_attrs[] = {
&dev_attr_fifo.attr,
&dev_attr_period.attr,
&dev_attr_pps_enable.attr,
+ &dev_attr_n_vclocks.attr,
+ &dev_attr_max_vclocks.attr,
NULL
};
@@ -183,6 +339,10 @@ static umode_t ptp_is_attribute_visible(struct kobject *kobj,
} else if (attr == &dev_attr_pps_enable.attr) {
if (!info->pps)
mode = 0;
+ } else if (attr == &dev_attr_n_vclocks.attr ||
+ attr == &dev_attr_max_vclocks.attr) {
+ if (ptp->is_virtual_clock)
+ mode = 0;
}
return mode;
diff --git a/drivers/ptp/ptp_vclock.c b/drivers/ptp/ptp_vclock.c
new file mode 100644
index 000000000000..e0f87c57749a
--- /dev/null
+++ b/drivers/ptp/ptp_vclock.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * PTP virtual clock driver
+ *
+ * Copyright 2021 NXP
+ */
+#include <linux/slab.h>
+#include "ptp_private.h"
+
+#define PTP_VCLOCK_CC_SHIFT 31
+#define PTP_VCLOCK_CC_MULT (1 << PTP_VCLOCK_CC_SHIFT)
+#define PTP_VCLOCK_FADJ_SHIFT 9
+#define PTP_VCLOCK_FADJ_DENOMINATOR 15625ULL
+#define PTP_VCLOCK_REFRESH_INTERVAL (HZ * 2)
+
+static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
+{
+ struct ptp_vclock *vclock = info_to_vclock(ptp);
+ unsigned long flags;
+ s64 adj;
+
+ adj = (s64)scaled_ppm << PTP_VCLOCK_FADJ_SHIFT;
+ adj = div_s64(adj, PTP_VCLOCK_FADJ_DENOMINATOR);
+
+ spin_lock_irqsave(&vclock->lock, flags);
+ timecounter_read(&vclock->tc);
+ vclock->cc.mult = PTP_VCLOCK_CC_MULT + adj;
+ spin_unlock_irqrestore(&vclock->lock, flags);
+
+ return 0;
+}
+
+static int ptp_vclock_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct ptp_vclock *vclock = info_to_vclock(ptp);
+ unsigned long flags;
+
+ spin_lock_irqsave(&vclock->lock, flags);
+ timecounter_adjtime(&vclock->tc, delta);
+ spin_unlock_irqrestore(&vclock->lock, flags);
+
+ return 0;
+}
+
+static int ptp_vclock_gettime(struct ptp_clock_info *ptp,
+ struct timespec64 *ts)
+{
+ struct ptp_vclock *vclock = info_to_vclock(ptp);
+ unsigned long flags;
+ u64 ns;
+
+ spin_lock_irqsave(&vclock->lock, flags);
+ ns = timecounter_read(&vclock->tc);
+ spin_unlock_irqrestore(&vclock->lock, flags);
+ *ts = ns_to_timespec64(ns);
+
+ return 0;
+}
+
+static int ptp_vclock_settime(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct ptp_vclock *vclock = info_to_vclock(ptp);
+ u64 ns = timespec64_to_ns(ts);
+ unsigned long flags;
+
+ spin_lock_irqsave(&vclock->lock, flags);
+ timecounter_init(&vclock->tc, &vclock->cc, ns);
+ spin_unlock_irqrestore(&vclock->lock, flags);
+
+ return 0;
+}
+
+static long ptp_vclock_refresh(struct ptp_clock_info *ptp)
+{
+ struct ptp_vclock *vclock = info_to_vclock(ptp);
+ struct timespec64 ts;
+
+ ptp_vclock_gettime(&vclock->info, &ts);
+
+ return PTP_VCLOCK_REFRESH_INTERVAL;
+}
+
+static const struct ptp_clock_info ptp_vclock_info = {
+ .owner = THIS_MODULE,
+ .name = "ptp virtual clock",
+ /* The maximum ppb value that long scaled_ppm can support */
+ .max_adj = 32767999,
+ .adjfine = ptp_vclock_adjfine,
+ .adjtime = ptp_vclock_adjtime,
+ .gettime64 = ptp_vclock_gettime,
+ .settime64 = ptp_vclock_settime,
+ .do_aux_work = ptp_vclock_refresh,
+};
+
+static u64 ptp_vclock_read(const struct cyclecounter *cc)
+{
+ struct ptp_vclock *vclock = cc_to_vclock(cc);
+ struct ptp_clock *ptp = vclock->pclock;
+ struct timespec64 ts = {};
+
+ if (ptp->info->gettimex64)
+ ptp->info->gettimex64(ptp->info, &ts, NULL);
+ else
+ ptp->info->gettime64(ptp->info, &ts);
+
+ return timespec64_to_ns(&ts);
+}
+
+static const struct cyclecounter ptp_vclock_cc = {
+ .read = ptp_vclock_read,
+ .mask = CYCLECOUNTER_MASK(32),
+ .mult = PTP_VCLOCK_CC_MULT,
+ .shift = PTP_VCLOCK_CC_SHIFT,
+};
+
+struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock)
+{
+ struct ptp_vclock *vclock;
+
+ vclock = kzalloc(sizeof(*vclock), GFP_KERNEL);
+ if (!vclock)
+ return NULL;
+
+ vclock->pclock = pclock;
+ vclock->info = ptp_vclock_info;
+ vclock->cc = ptp_vclock_cc;
+
+ snprintf(vclock->info.name, PTP_CLOCK_NAME_LEN, "ptp%d_virt",
+ pclock->index);
+
+ spin_lock_init(&vclock->lock);
+
+ vclock->clock = ptp_clock_register(&vclock->info, &pclock->dev);
+ if (IS_ERR_OR_NULL(vclock->clock)) {
+ kfree(vclock);
+ return NULL;
+ }
+
+ timecounter_init(&vclock->tc, &vclock->cc, 0);
+ ptp_schedule_worker(vclock->clock, PTP_VCLOCK_REFRESH_INTERVAL);
+
+ return vclock;
+}
+
+void ptp_vclock_unregister(struct ptp_vclock *vclock)
+{
+ ptp_clock_unregister(vclock->clock);
+ kfree(vclock);
+}
+
+int ptp_get_vclocks_index(int pclock_index, int **vclock_index)
+{
+ char name[PTP_CLOCK_NAME_LEN] = "";
+ struct ptp_clock *ptp;
+ struct device *dev;
+ int num = 0;
+
+ if (pclock_index < 0)
+ return num;
+
+ snprintf(name, PTP_CLOCK_NAME_LEN, "ptp%d", pclock_index);
+ dev = class_find_device_by_name(ptp_class, name);
+ if (!dev)
+ return num;
+
+ ptp = dev_get_drvdata(dev);
+
+ if (mutex_lock_interruptible(&ptp->n_vclocks_mux)) {
+ put_device(dev);
+ return num;
+ }
+
+ *vclock_index = kzalloc(sizeof(int) * ptp->n_vclocks, GFP_KERNEL);
+ if (!(*vclock_index))
+ goto out;
+
+ memcpy(*vclock_index, ptp->vclock_index, sizeof(int) * ptp->n_vclocks);
+ num = ptp->n_vclocks;
+out:
+ mutex_unlock(&ptp->n_vclocks_mux);
+ put_device(dev);
+ return num;
+}
+EXPORT_SYMBOL(ptp_get_vclocks_index);
+
+void ptp_convert_timestamp(struct skb_shared_hwtstamps *hwtstamps,
+ int vclock_index)
+{
+ char name[PTP_CLOCK_NAME_LEN] = "";
+ struct ptp_vclock *vclock;
+ struct ptp_clock *ptp;
+ unsigned long flags;
+ struct device *dev;
+ u64 ns;
+
+ snprintf(name, PTP_CLOCK_NAME_LEN, "ptp%d", vclock_index);
+ dev = class_find_device_by_name(ptp_class, name);
+ if (!dev)
+ return;
+
+ ptp = dev_get_drvdata(dev);
+ if (!ptp->is_virtual_clock) {
+ put_device(dev);
+ return;
+ }
+
+ vclock = info_to_vclock(ptp->info);
+
+ ns = ktime_to_ns(hwtstamps->hwtstamp);
+
+ spin_lock_irqsave(&vclock->lock, flags);
+ ns = timecounter_cyc2time(&vclock->tc, ns);
+ spin_unlock_irqrestore(&vclock->lock, flags);
+
+ put_device(dev);
+ hwtstamps->hwtstamp = ns_to_ktime(ns);
+}
+EXPORT_SYMBOL(ptp_convert_timestamp);
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index c4d5c0667137..35e894f4a379 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -126,8 +126,7 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
{
struct pwm_device *pwm;
- /* check, whether the driver supports a third cell for flags */
- if (pc->of_pwm_n_cells < 3)
+ if (pc->of_pwm_n_cells < 2)
return ERR_PTR(-EINVAL);
/* flags in the third cell are optional */
@@ -144,46 +143,29 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
pwm->args.period = args->args[1];
pwm->args.polarity = PWM_POLARITY_NORMAL;
- if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
- pwm->args.polarity = PWM_POLARITY_INVERSED;
+ if (pc->of_pwm_n_cells >= 3) {
+ if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
+ pwm->args.polarity = PWM_POLARITY_INVERSED;
+ }
return pwm;
}
EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags);
-static struct pwm_device *
-of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
-{
- struct pwm_device *pwm;
-
- /* sanity check driver support */
- if (pc->of_pwm_n_cells < 2)
- return ERR_PTR(-EINVAL);
-
- /* all cells are required */
- if (args->args_count != pc->of_pwm_n_cells)
- return ERR_PTR(-EINVAL);
-
- if (args->args[0] >= pc->npwm)
- return ERR_PTR(-EINVAL);
-
- pwm = pwm_request_from_chip(pc, args->args[0], NULL);
- if (IS_ERR(pwm))
- return pwm;
-
- pwm->args.period = args->args[1];
-
- return pwm;
-}
-
static void of_pwmchip_add(struct pwm_chip *chip)
{
if (!chip->dev || !chip->dev->of_node)
return;
if (!chip->of_xlate) {
- chip->of_xlate = of_pwm_simple_xlate;
- chip->of_pwm_n_cells = 2;
+ u32 pwm_cells;
+
+ if (of_property_read_u32(chip->dev->of_node, "#pwm-cells",
+ &pwm_cells))
+ pwm_cells = 2;
+
+ chip->of_xlate = of_pwm_xlate_with_flags;
+ chip->of_pwm_n_cells = pwm_cells;
}
of_node_get(chip->dev->of_node);
@@ -324,22 +306,10 @@ EXPORT_SYMBOL_GPL(pwmchip_add);
*/
int pwmchip_remove(struct pwm_chip *chip)
{
- unsigned int i;
- int ret = 0;
-
pwmchip_sysfs_unexport(chip);
mutex_lock(&pwm_lock);
- for (i = 0; i < chip->npwm; i++) {
- struct pwm_device *pwm = &chip->pwms[i];
-
- if (test_bit(PWMF_REQUESTED, &pwm->flags)) {
- ret = -EBUSY;
- goto out;
- }
- }
-
list_del_init(&chip->list);
if (IS_ENABLED(CONFIG_OF))
@@ -347,12 +317,31 @@ int pwmchip_remove(struct pwm_chip *chip)
free_pwms(chip);
-out:
mutex_unlock(&pwm_lock);
- return ret;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(pwmchip_remove);
+static void devm_pwmchip_remove(void *data)
+{
+ struct pwm_chip *chip = data;
+
+ pwmchip_remove(chip);
+}
+
+int devm_pwmchip_add(struct device *dev, struct pwm_chip *chip)
+{
+ int ret;
+
+ ret = pwmchip_add(chip);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(dev, devm_pwmchip_remove, chip);
+}
+EXPORT_SYMBOL_GPL(devm_pwmchip_add);
+
/**
* pwm_request() - request a PWM device
* @pwm: global PWM device index
@@ -554,7 +543,8 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
if (state->period == pwm->state.period &&
state->duty_cycle == pwm->state.duty_cycle &&
state->polarity == pwm->state.polarity &&
- state->enabled == pwm->state.enabled)
+ state->enabled == pwm->state.enabled &&
+ state->usage_power == pwm->state.usage_power)
return 0;
if (chip->ops->apply) {
@@ -709,14 +699,14 @@ int pwm_adjust_config(struct pwm_device *pwm)
}
EXPORT_SYMBOL_GPL(pwm_adjust_config);
-static struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
+static struct pwm_chip *fwnode_to_pwmchip(struct fwnode_handle *fwnode)
{
struct pwm_chip *chip;
mutex_lock(&pwm_lock);
list_for_each_entry(chip, &pwm_chips, list)
- if (chip->dev && chip->dev->of_node == np) {
+ if (chip->dev && dev_fwnode(chip->dev) == fwnode) {
mutex_unlock(&pwm_lock);
return chip;
}
@@ -795,7 +785,7 @@ struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np,
return ERR_PTR(err);
}
- pc = of_node_to_pwmchip(args.np);
+ pc = fwnode_to_pwmchip(of_fwnode_handle(args.np));
if (IS_ERR(pc)) {
if (PTR_ERR(pc) != -EPROBE_DEFER)
pr_err("%s(): PWM chip not found\n", __func__);
@@ -837,31 +827,9 @@ 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
+ * @fwnode: firmware node to get the "pwms" property from
*
* Returns the PWM device parsed from the fwnode and index specified in the
* "pwms" property or a negative error-code on failure.
@@ -876,12 +844,10 @@ static struct pwm_chip *device_to_pwmchip(struct device *dev)
* 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)
+static struct pwm_device *acpi_pwm_get(const struct fwnode_handle *fwnode)
{
- struct pwm_device *pwm = ERR_PTR(-ENODEV);
-#if IS_ENABLED(CONFIG_ACPI)
+ struct pwm_device *pwm;
struct fwnode_reference_args args;
- struct acpi_device *acpi;
struct pwm_chip *chip;
int ret;
@@ -891,14 +857,10 @@ static struct pwm_device *acpi_pwm_get(struct fwnode_handle *fwnode)
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);
+ chip = fwnode_to_pwmchip(args.fwnode);
if (IS_ERR(chip))
return ERR_CAST(chip);
@@ -911,7 +873,6 @@ static struct pwm_device *acpi_pwm_get(struct fwnode_handle *fwnode)
if (args.nargs > 2 && args.args[2] & PWM_POLARITY_INVERTED)
pwm->args.polarity = PWM_POLARITY_INVERSED;
-#endif
return pwm;
}
@@ -967,6 +928,7 @@ void pwm_remove_table(struct pwm_lookup *table, size_t num)
*/
struct pwm_device *pwm_get(struct device *dev, const char *con_id)
{
+ const struct fwnode_handle *fwnode = dev ? dev_fwnode(dev) : NULL;
const char *dev_id = dev ? dev_name(dev) : NULL;
struct pwm_device *pwm;
struct pwm_chip *chip;
@@ -977,12 +939,12 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
int err;
/* look up via DT first */
- if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
- return of_pwm_get(dev, dev->of_node, con_id);
+ if (is_of_node(fwnode))
+ return of_pwm_get(dev, to_of_node(fwnode), con_id);
/* then lookup via ACPI */
- if (dev && is_acpi_node(dev->fwnode)) {
- pwm = acpi_pwm_get(dev->fwnode);
+ if (is_acpi_node(fwnode)) {
+ pwm = acpi_pwm_get(fwnode);
if (!IS_ERR(pwm) || PTR_ERR(pwm) != -ENOENT)
return pwm;
}
@@ -1103,9 +1065,9 @@ out:
}
EXPORT_SYMBOL_GPL(pwm_put);
-static void devm_pwm_release(struct device *dev, void *res)
+static void devm_pwm_release(void *pwm)
{
- pwm_put(*(struct pwm_device **)res);
+ pwm_put(pwm);
}
/**
@@ -1121,19 +1083,16 @@ static void devm_pwm_release(struct device *dev, void *res)
*/
struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id)
{
- struct pwm_device **ptr, *pwm;
-
- ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return ERR_PTR(-ENOMEM);
+ struct pwm_device *pwm;
+ int ret;
pwm = pwm_get(dev, con_id);
- if (!IS_ERR(pwm)) {
- *ptr = pwm;
- devres_add(dev, ptr);
- } else {
- devres_free(ptr);
- }
+ if (IS_ERR(pwm))
+ return pwm;
+
+ ret = devm_add_action_or_reset(dev, devm_pwm_release, pwm);
+ if (ret)
+ return ERR_PTR(ret);
return pwm;
}
@@ -1154,19 +1113,16 @@ EXPORT_SYMBOL_GPL(devm_pwm_get);
struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np,
const char *con_id)
{
- struct pwm_device **ptr, *pwm;
-
- ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return ERR_PTR(-ENOMEM);
+ struct pwm_device *pwm;
+ int ret;
pwm = of_pwm_get(dev, np, con_id);
- if (!IS_ERR(pwm)) {
- *ptr = pwm;
- devres_add(dev, ptr);
- } else {
- devres_free(ptr);
- }
+ if (IS_ERR(pwm))
+ return pwm;
+
+ ret = devm_add_action_or_reset(dev, devm_pwm_release, pwm);
+ if (ret)
+ return ERR_PTR(ret);
return pwm;
}
@@ -1188,53 +1144,24 @@ 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);
+ struct pwm_device *pwm = ERR_PTR(-ENODEV);
+ int ret;
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))
+ return pwm;
- if (!IS_ERR(pwm)) {
- *ptr = pwm;
- devres_add(dev, ptr);
- } else {
- devres_free(ptr);
- }
+ ret = devm_add_action_or_reset(dev, devm_pwm_release, pwm);
+ if (ret)
+ return ERR_PTR(ret);
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;
-
- if (WARN_ON(!p || !*p))
- return 0;
-
- return *p == data;
-}
-
-/**
- * devm_pwm_put() - resource managed pwm_put()
- * @dev: device for PWM consumer
- * @pwm: PWM device
- *
- * Release a PWM previously allocated using devm_pwm_get(). Calling this
- * function is usually not needed because devm-allocated resources are
- * automatically released on driver detach.
- */
-void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
-{
- WARN_ON(devres_release(dev, devm_pwm_release, devm_pwm_match, pwm));
-}
-EXPORT_SYMBOL_GPL(devm_pwm_put);
-
#ifdef CONFIG_DEBUG_FS
static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
{
@@ -1259,6 +1186,9 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
seq_printf(s, " polarity: %s",
state.polarity ? "inverse" : "normal");
+ if (state.usage_power)
+ seq_puts(s, " usage_power");
+
seq_puts(s, "\n");
}
}
diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c
index 6ab597e54005..4459325d3650 100644
--- a/drivers/pwm/pwm-atmel-hlcdc.c
+++ b/drivers/pwm/pwm-atmel-hlcdc.c
@@ -266,8 +266,6 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
chip->chip.ops = &atmel_hlcdc_pwm_ops;
chip->chip.dev = dev;
chip->chip.npwm = 1;
- chip->chip.of_xlate = of_pwm_xlate_with_flags;
- chip->chip.of_pwm_n_cells = 3;
ret = pwmchip_add(&chip->chip);
if (ret) {
diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c
index 8451d3e846be..bf398f21484d 100644
--- a/drivers/pwm/pwm-atmel-tcb.c
+++ b/drivers/pwm/pwm-atmel-tcb.c
@@ -469,8 +469,6 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
tcbpwm->chip.dev = &pdev->dev;
tcbpwm->chip.ops = &atmel_tcb_pwm_ops;
- tcbpwm->chip.of_xlate = of_pwm_xlate_with_flags;
- tcbpwm->chip.of_pwm_n_cells = 3;
tcbpwm->chip.npwm = NPWM;
tcbpwm->channel = channel;
tcbpwm->regmap = regmap;
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index 29b5ad03f715..a8162bae3e8a 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -436,8 +436,6 @@ static int atmel_pwm_probe(struct platform_device *pdev)
atmel_pwm->chip.dev = &pdev->dev;
atmel_pwm->chip.ops = &atmel_pwm_ops;
- atmel_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
- atmel_pwm->chip.of_pwm_n_cells = 3;
atmel_pwm->chip.npwm = 4;
ret = pwmchip_add(&atmel_pwm->chip);
diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c
index edd2ce1760ab..0226bf697f09 100644
--- a/drivers/pwm/pwm-bcm-iproc.c
+++ b/drivers/pwm/pwm-bcm-iproc.c
@@ -210,8 +210,6 @@ static int iproc_pwmc_probe(struct platform_device *pdev)
ip->chip.dev = &pdev->dev;
ip->chip.ops = &iproc_pwm_ops;
ip->chip.npwm = 4;
- ip->chip.of_xlate = of_pwm_xlate_with_flags;
- ip->chip.of_pwm_n_cells = 3;
ip->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ip->base))
diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index 800b9edf2e71..8c85c66ea5c9 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -272,8 +272,6 @@ static int kona_pwmc_probe(struct platform_device *pdev)
kp->chip.dev = &pdev->dev;
kp->chip.ops = &kona_pwm_ops;
kp->chip.npwm = 6;
- kp->chip.of_xlate = of_pwm_xlate_with_flags;
- kp->chip.of_pwm_n_cells = 3;
kp->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(kp->base))
diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c
index fc240d5b8121..50b8594be31d 100644
--- a/drivers/pwm/pwm-bcm2835.c
+++ b/drivers/pwm/pwm-bcm2835.c
@@ -159,8 +159,6 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
pc->chip.dev = &pdev->dev;
pc->chip.ops = &bcm2835_pwm_ops;
pc->chip.npwm = 2;
- pc->chip.of_xlate = of_pwm_xlate_with_flags;
- pc->chip.of_pwm_n_cells = 3;
platform_set_drvdata(pdev, pc);
diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c
index acb6fbc3cc32..e157273fd2f7 100644
--- a/drivers/pwm/pwm-berlin.c
+++ b/drivers/pwm/pwm-berlin.c
@@ -56,17 +56,17 @@ static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip)
return container_of(chip, struct berlin_pwm_chip, chip);
}
-static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip,
+static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *bpc,
unsigned int channel, unsigned long offset)
{
- return readl_relaxed(chip->base + channel * 0x10 + offset);
+ return readl_relaxed(bpc->base + channel * 0x10 + offset);
}
-static inline void berlin_pwm_writel(struct berlin_pwm_chip *chip,
+static inline void berlin_pwm_writel(struct berlin_pwm_chip *bpc,
unsigned int channel, u32 value,
unsigned long offset)
{
- writel_relaxed(value, chip->base + channel * 0x10 + offset);
+ writel_relaxed(value, bpc->base + channel * 0x10 + offset);
}
static int berlin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
@@ -87,15 +87,15 @@ static void berlin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
kfree(channel);
}
-static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev,
- int duty_ns, int period_ns)
+static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ u64 duty_ns, u64 period_ns)
{
- struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
+ struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip);
bool prescale_4096 = false;
u32 value, duty, period;
u64 cycles;
- cycles = clk_get_rate(pwm->clk);
+ cycles = clk_get_rate(bpc->clk);
cycles *= period_ns;
do_div(cycles, NSEC_PER_SEC);
@@ -112,68 +112,98 @@ static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev,
do_div(cycles, period_ns);
duty = cycles;
- value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL);
+ value = berlin_pwm_readl(bpc, pwm->hwpwm, BERLIN_PWM_CONTROL);
if (prescale_4096)
value |= BERLIN_PWM_PRESCALE_4096;
else
value &= ~BERLIN_PWM_PRESCALE_4096;
- berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL);
+ berlin_pwm_writel(bpc, pwm->hwpwm, value, BERLIN_PWM_CONTROL);
- berlin_pwm_writel(pwm, pwm_dev->hwpwm, duty, BERLIN_PWM_DUTY);
- berlin_pwm_writel(pwm, pwm_dev->hwpwm, period, BERLIN_PWM_TCNT);
+ berlin_pwm_writel(bpc, pwm->hwpwm, duty, BERLIN_PWM_DUTY);
+ berlin_pwm_writel(bpc, pwm->hwpwm, period, BERLIN_PWM_TCNT);
return 0;
}
static int berlin_pwm_set_polarity(struct pwm_chip *chip,
- struct pwm_device *pwm_dev,
+ struct pwm_device *pwm,
enum pwm_polarity polarity)
{
- struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
+ struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip);
u32 value;
- value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL);
+ value = berlin_pwm_readl(bpc, pwm->hwpwm, BERLIN_PWM_CONTROL);
if (polarity == PWM_POLARITY_NORMAL)
value &= ~BERLIN_PWM_INVERT_POLARITY;
else
value |= BERLIN_PWM_INVERT_POLARITY;
- berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL);
+ berlin_pwm_writel(bpc, pwm->hwpwm, value, BERLIN_PWM_CONTROL);
return 0;
}
-static int berlin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm_dev)
+static int berlin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
- struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
+ struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip);
u32 value;
- value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN);
+ value = berlin_pwm_readl(bpc, pwm->hwpwm, BERLIN_PWM_EN);
value |= BERLIN_PWM_ENABLE;
- berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN);
+ berlin_pwm_writel(bpc, pwm->hwpwm, value, BERLIN_PWM_EN);
return 0;
}
static void berlin_pwm_disable(struct pwm_chip *chip,
- struct pwm_device *pwm_dev)
+ struct pwm_device *pwm)
{
- struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
+ struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip);
u32 value;
- value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN);
+ value = berlin_pwm_readl(bpc, pwm->hwpwm, BERLIN_PWM_EN);
value &= ~BERLIN_PWM_ENABLE;
- berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN);
+ berlin_pwm_writel(bpc, pwm->hwpwm, value, BERLIN_PWM_EN);
+}
+
+static int berlin_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ int err;
+ bool enabled = pwm->state.enabled;
+
+ if (state->polarity != pwm->state.polarity) {
+ if (enabled) {
+ berlin_pwm_disable(chip, pwm);
+ enabled = false;
+ }
+
+ err = berlin_pwm_set_polarity(chip, pwm, state->polarity);
+ if (err)
+ return err;
+ }
+
+ if (!state->enabled) {
+ if (enabled)
+ berlin_pwm_disable(chip, pwm);
+ return 0;
+ }
+
+ err = berlin_pwm_config(chip, pwm, state->duty_cycle, state->period);
+ if (err)
+ return err;
+
+ if (!enabled)
+ return berlin_pwm_enable(chip, pwm);
+
+ return 0;
}
static const struct pwm_ops berlin_pwm_ops = {
.request = berlin_pwm_request,
.free = berlin_pwm_free,
- .config = berlin_pwm_config,
- .set_polarity = berlin_pwm_set_polarity,
- .enable = berlin_pwm_enable,
- .disable = berlin_pwm_disable,
+ .apply = berlin_pwm_apply,
.owner = THIS_MODULE,
};
@@ -185,99 +215,97 @@ MODULE_DEVICE_TABLE(of, berlin_pwm_match);
static int berlin_pwm_probe(struct platform_device *pdev)
{
- struct berlin_pwm_chip *pwm;
+ struct berlin_pwm_chip *bpc;
int ret;
- pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
- if (!pwm)
+ bpc = devm_kzalloc(&pdev->dev, sizeof(*bpc), GFP_KERNEL);
+ if (!bpc)
return -ENOMEM;
- pwm->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(pwm->base))
- return PTR_ERR(pwm->base);
+ bpc->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(bpc->base))
+ return PTR_ERR(bpc->base);
- pwm->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(pwm->clk))
- return PTR_ERR(pwm->clk);
+ bpc->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(bpc->clk))
+ return PTR_ERR(bpc->clk);
- ret = clk_prepare_enable(pwm->clk);
+ ret = clk_prepare_enable(bpc->clk);
if (ret)
return ret;
- pwm->chip.dev = &pdev->dev;
- pwm->chip.ops = &berlin_pwm_ops;
- pwm->chip.npwm = 4;
- pwm->chip.of_xlate = of_pwm_xlate_with_flags;
- pwm->chip.of_pwm_n_cells = 3;
+ bpc->chip.dev = &pdev->dev;
+ bpc->chip.ops = &berlin_pwm_ops;
+ bpc->chip.npwm = 4;
- ret = pwmchip_add(&pwm->chip);
+ ret = pwmchip_add(&bpc->chip);
if (ret < 0) {
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
- clk_disable_unprepare(pwm->clk);
+ clk_disable_unprepare(bpc->clk);
return ret;
}
- platform_set_drvdata(pdev, pwm);
+ platform_set_drvdata(pdev, bpc);
return 0;
}
static int berlin_pwm_remove(struct platform_device *pdev)
{
- struct berlin_pwm_chip *pwm = platform_get_drvdata(pdev);
- int ret;
+ struct berlin_pwm_chip *bpc = platform_get_drvdata(pdev);
+
+ pwmchip_remove(&bpc->chip);
- ret = pwmchip_remove(&pwm->chip);
- clk_disable_unprepare(pwm->clk);
+ clk_disable_unprepare(bpc->clk);
- return ret;
+ return 0;
}
#ifdef CONFIG_PM_SLEEP
static int berlin_pwm_suspend(struct device *dev)
{
- struct berlin_pwm_chip *pwm = dev_get_drvdata(dev);
+ struct berlin_pwm_chip *bpc = dev_get_drvdata(dev);
unsigned int i;
- for (i = 0; i < pwm->chip.npwm; i++) {
+ for (i = 0; i < bpc->chip.npwm; i++) {
struct berlin_pwm_channel *channel;
- channel = pwm_get_chip_data(&pwm->chip.pwms[i]);
+ channel = pwm_get_chip_data(&bpc->chip.pwms[i]);
if (!channel)
continue;
- channel->enable = berlin_pwm_readl(pwm, i, BERLIN_PWM_ENABLE);
- channel->ctrl = berlin_pwm_readl(pwm, i, BERLIN_PWM_CONTROL);
- channel->duty = berlin_pwm_readl(pwm, i, BERLIN_PWM_DUTY);
- channel->tcnt = berlin_pwm_readl(pwm, i, BERLIN_PWM_TCNT);
+ channel->enable = berlin_pwm_readl(bpc, i, BERLIN_PWM_ENABLE);
+ channel->ctrl = berlin_pwm_readl(bpc, i, BERLIN_PWM_CONTROL);
+ channel->duty = berlin_pwm_readl(bpc, i, BERLIN_PWM_DUTY);
+ channel->tcnt = berlin_pwm_readl(bpc, i, BERLIN_PWM_TCNT);
}
- clk_disable_unprepare(pwm->clk);
+ clk_disable_unprepare(bpc->clk);
return 0;
}
static int berlin_pwm_resume(struct device *dev)
{
- struct berlin_pwm_chip *pwm = dev_get_drvdata(dev);
+ struct berlin_pwm_chip *bpc = dev_get_drvdata(dev);
unsigned int i;
int ret;
- ret = clk_prepare_enable(pwm->clk);
+ ret = clk_prepare_enable(bpc->clk);
if (ret)
return ret;
- for (i = 0; i < pwm->chip.npwm; i++) {
+ for (i = 0; i < bpc->chip.npwm; i++) {
struct berlin_pwm_channel *channel;
- channel = pwm_get_chip_data(&pwm->chip.pwms[i]);
+ channel = pwm_get_chip_data(&bpc->chip.pwms[i]);
if (!channel)
continue;
- berlin_pwm_writel(pwm, i, channel->ctrl, BERLIN_PWM_CONTROL);
- berlin_pwm_writel(pwm, i, channel->duty, BERLIN_PWM_DUTY);
- berlin_pwm_writel(pwm, i, channel->tcnt, BERLIN_PWM_TCNT);
- berlin_pwm_writel(pwm, i, channel->enable, BERLIN_PWM_ENABLE);
+ berlin_pwm_writel(bpc, i, channel->ctrl, BERLIN_PWM_CONTROL);
+ berlin_pwm_writel(bpc, i, channel->duty, BERLIN_PWM_DUTY);
+ berlin_pwm_writel(bpc, i, channel->tcnt, BERLIN_PWM_TCNT);
+ berlin_pwm_writel(bpc, i, channel->enable, BERLIN_PWM_ENABLE);
}
return 0;
diff --git a/drivers/pwm/pwm-clps711x.c b/drivers/pwm/pwm-clps711x.c
index f3d17a590305..d7ad88685830 100644
--- a/drivers/pwm/pwm-clps711x.c
+++ b/drivers/pwm/pwm-clps711x.c
@@ -134,16 +134,7 @@ static int clps711x_pwm_probe(struct platform_device *pdev)
spin_lock_init(&priv->lock);
- platform_set_drvdata(pdev, priv);
-
- return pwmchip_add(&priv->chip);
-}
-
-static int clps711x_pwm_remove(struct platform_device *pdev)
-{
- struct clps711x_chip *priv = platform_get_drvdata(pdev);
-
- return pwmchip_remove(&priv->chip);
+ return devm_pwmchip_add(&pdev->dev, &priv->chip);
}
static const struct of_device_id __maybe_unused clps711x_pwm_dt_ids[] = {
@@ -158,7 +149,6 @@ static struct platform_driver clps711x_pwm_driver = {
.of_match_table = of_match_ptr(clps711x_pwm_dt_ids),
},
.probe = clps711x_pwm_probe,
- .remove = clps711x_pwm_remove,
};
module_platform_driver(clps711x_pwm_driver);
diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 02522a9a3073..7b357d1cf642 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -173,21 +173,11 @@ static int crystalcove_pwm_probe(struct platform_device *pdev)
/* get the PMIC regmap */
pwm->regmap = pmic->regmap;
- platform_set_drvdata(pdev, pwm);
-
- return pwmchip_add(&pwm->chip);
-}
-
-static int crystalcove_pwm_remove(struct platform_device *pdev)
-{
- struct crystalcove_pwm *pwm = platform_get_drvdata(pdev);
-
- return pwmchip_remove(&pwm->chip);
+ return devm_pwmchip_add(&pdev->dev, &pwm->chip);
}
static struct platform_driver crystalcove_pwm_driver = {
.probe = crystalcove_pwm_probe,
- .remove = crystalcove_pwm_remove,
.driver = {
.name = "crystal_cove_pwm",
},
diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c
index 4ca70794ad96..fc3cb7d669c6 100644
--- a/drivers/pwm/pwm-ep93xx.c
+++ b/drivers/pwm/pwm-ep93xx.c
@@ -58,35 +58,68 @@ static void ep93xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
ep93xx_pwm_release_gpio(pdev);
}
-static int ep93xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
- int duty_ns, int period_ns)
+static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
{
+ int ret;
struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
+ bool enabled = state->enabled;
void __iomem *base = ep93xx_pwm->base;
unsigned long long c;
unsigned long period_cycles;
unsigned long duty_cycles;
unsigned long term;
- int ret = 0;
+
+ if (state->polarity != pwm->state.polarity) {
+ if (enabled) {
+ writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_ENABLE);
+ clk_disable_unprepare(ep93xx_pwm->clk);
+ enabled = false;
+ }
+
+ /*
+ * The clock needs to be enabled to access the PWM registers.
+ * Polarity can only be changed when the PWM is disabled.
+ */
+ ret = clk_prepare_enable(ep93xx_pwm->clk);
+ if (ret)
+ return ret;
+
+ if (state->polarity == PWM_POLARITY_INVERSED)
+ writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_INVERT);
+ else
+ writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_INVERT);
+
+ clk_disable_unprepare(ep93xx_pwm->clk);
+ }
+
+ if (!state->enabled) {
+ if (enabled) {
+ writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_ENABLE);
+ clk_disable_unprepare(ep93xx_pwm->clk);
+ }
+
+ return 0;
+ }
/*
* The clock needs to be enabled to access the PWM registers.
* Configuration can be changed at any time.
*/
if (!pwm_is_enabled(pwm)) {
- ret = clk_enable(ep93xx_pwm->clk);
+ ret = clk_prepare_enable(ep93xx_pwm->clk);
if (ret)
return ret;
}
c = clk_get_rate(ep93xx_pwm->clk);
- c *= period_ns;
+ c *= state->period;
do_div(c, 1000000000);
period_cycles = c;
c = period_cycles;
- c *= duty_ns;
- do_div(c, period_ns);
+ c *= state->duty_cycle;
+ do_div(c, state->period);
duty_cycles = c;
if (period_cycles < 0x10000 && duty_cycles < 0x10000) {
@@ -100,69 +133,32 @@ static int ep93xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
writew(duty_cycles, base + EP93XX_PWMx_DUTY_CYCLE);
writew(period_cycles, base + EP93XX_PWMx_TERM_COUNT);
}
+ ret = 0;
} else {
ret = -EINVAL;
}
if (!pwm_is_enabled(pwm))
- clk_disable(ep93xx_pwm->clk);
-
- return ret;
-}
-
-static int ep93xx_pwm_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
- enum pwm_polarity polarity)
-{
- struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
- int ret;
+ clk_disable_unprepare(ep93xx_pwm->clk);
- /*
- * The clock needs to be enabled to access the PWM registers.
- * Polarity can only be changed when the PWM is disabled.
- */
- ret = clk_enable(ep93xx_pwm->clk);
if (ret)
return ret;
- if (polarity == PWM_POLARITY_INVERSED)
- writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_INVERT);
- else
- writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_INVERT);
-
- clk_disable(ep93xx_pwm->clk);
-
- return 0;
-}
-
-static int ep93xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
- struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
- int ret;
-
- ret = clk_enable(ep93xx_pwm->clk);
- if (ret)
- return ret;
+ if (!enabled) {
+ ret = clk_prepare_enable(ep93xx_pwm->clk);
+ if (ret)
+ return ret;
- writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_ENABLE);
+ writew(0x1, ep93xx_pwm->base + EP93XX_PWMx_ENABLE);
+ }
return 0;
}
-static void ep93xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
- struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
-
- writew(0x0, ep93xx_pwm->base + EP93XX_PWMx_ENABLE);
- clk_disable(ep93xx_pwm->clk);
-}
-
static const struct pwm_ops ep93xx_pwm_ops = {
.request = ep93xx_pwm_request,
.free = ep93xx_pwm_free,
- .config = ep93xx_pwm_config,
- .set_polarity = ep93xx_pwm_polarity,
- .enable = ep93xx_pwm_enable,
- .disable = ep93xx_pwm_disable,
+ .apply = ep93xx_pwm_apply,
.owner = THIS_MODULE,
};
diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c
index 0e1ae9469eda..96ccd772280c 100644
--- a/drivers/pwm/pwm-fsl-ftm.c
+++ b/drivers/pwm/pwm-fsl-ftm.c
@@ -451,8 +451,6 @@ static int fsl_pwm_probe(struct platform_device *pdev)
fpc->chip.ops = &fsl_pwm_ops;
- fpc->chip.of_xlate = of_pwm_xlate_with_flags;
- fpc->chip.of_pwm_n_cells = 3;
fpc->chip.npwm = 8;
ret = pwmchip_add(&fpc->chip);
diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c
index 82d17fc75c21..4a6e9ad3c0ff 100644
--- a/drivers/pwm/pwm-hibvt.c
+++ b/drivers/pwm/pwm-hibvt.c
@@ -206,8 +206,6 @@ static int hibvt_pwm_probe(struct platform_device *pdev)
pwm_chip->chip.ops = &hibvt_pwm_ops;
pwm_chip->chip.dev = &pdev->dev;
pwm_chip->chip.npwm = soc->num_pwms;
- pwm_chip->chip.of_xlate = of_pwm_xlate_with_flags;
- pwm_chip->chip.of_pwm_n_cells = 3;
pwm_chip->soc = soc;
pwm_chip->base = devm_platform_ioremap_resource(pdev, 0);
diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c
index cc37054589cc..11b16ecc4f96 100644
--- a/drivers/pwm/pwm-img.c
+++ b/drivers/pwm/pwm-img.c
@@ -156,7 +156,7 @@ static int img_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip);
int ret;
- ret = pm_runtime_get_sync(chip->dev);
+ ret = pm_runtime_resume_and_get(chip->dev);
if (ret < 0)
return ret;
diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c
index 97c9133b6876..dbb50493abdd 100644
--- a/drivers/pwm/pwm-imx-tpm.c
+++ b/drivers/pwm/pwm-imx-tpm.c
@@ -363,8 +363,6 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev)
tpm->chip.dev = &pdev->dev;
tpm->chip.ops = &imx_tpm_pwm_ops;
- tpm->chip.of_xlate = of_pwm_xlate_with_flags;
- tpm->chip.of_pwm_n_cells = 3;
/* get number of channels */
val = readl(tpm->base + PWM_IMX_TPM_PARAM);
diff --git a/drivers/pwm/pwm-imx1.c b/drivers/pwm/pwm-imx1.c
index c957b365448e..bcd849496f8d 100644
--- a/drivers/pwm/pwm-imx1.c
+++ b/drivers/pwm/pwm-imx1.c
@@ -141,8 +141,6 @@ static int pwm_imx1_probe(struct platform_device *pdev)
if (!imx)
return -ENOMEM;
- platform_set_drvdata(pdev, imx);
-
imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(imx->clk_ipg))
return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_ipg),
@@ -161,16 +159,7 @@ static int pwm_imx1_probe(struct platform_device *pdev)
if (IS_ERR(imx->mmio_base))
return PTR_ERR(imx->mmio_base);
- return pwmchip_add(&imx->chip);
-}
-
-static int pwm_imx1_remove(struct platform_device *pdev)
-{
- struct pwm_imx1_chip *imx = platform_get_drvdata(pdev);
-
- pwm_imx1_clk_disable_unprepare(&imx->chip);
-
- return pwmchip_remove(&imx->chip);
+ return devm_pwmchip_add(&pdev->dev, &imx->chip);
}
static struct platform_driver pwm_imx1_driver = {
@@ -179,7 +168,6 @@ static struct platform_driver pwm_imx1_driver = {
.of_match_table = pwm_imx1_dt_ids,
},
.probe = pwm_imx1_probe,
- .remove = pwm_imx1_remove,
};
module_platform_driver(pwm_imx1_driver);
diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c
index ba695115c160..f6588a96fbd9 100644
--- a/drivers/pwm/pwm-imx27.c
+++ b/drivers/pwm/pwm-imx27.c
@@ -329,9 +329,6 @@ static int pwm_imx27_probe(struct platform_device *pdev)
imx->chip.dev = &pdev->dev;
imx->chip.npwm = 1;
- imx->chip.of_xlate = of_pwm_xlate_with_flags;
- imx->chip.of_pwm_n_cells = 3;
-
imx->mmio_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(imx->mmio_base))
return PTR_ERR(imx->mmio_base);
diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
index 5b6bdcdcecf5..990e7904c7f1 100644
--- a/drivers/pwm/pwm-jz4740.c
+++ b/drivers/pwm/pwm-jz4740.c
@@ -244,8 +244,6 @@ static int jz4740_pwm_probe(struct platform_device *pdev)
jz4740->chip.dev = dev;
jz4740->chip.ops = &jz4740_pwm_ops;
jz4740->chip.npwm = info->num_pwms;
- jz4740->chip.of_xlate = of_pwm_xlate_with_flags;
- jz4740->chip.of_pwm_n_cells = 3;
platform_set_drvdata(pdev, jz4740);
diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c
index b643ac61a2e7..8e461f3baa05 100644
--- a/drivers/pwm/pwm-lpc18xx-sct.c
+++ b/drivers/pwm/pwm-lpc18xx-sct.c
@@ -371,8 +371,6 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
lpc18xx_pwm->chip.dev = &pdev->dev;
lpc18xx_pwm->chip.ops = &lpc18xx_pwm_ops;
lpc18xx_pwm->chip.npwm = 16;
- lpc18xx_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
- lpc18xx_pwm->chip.of_pwm_n_cells = 3;
/* SCT counter must be in unify (32 bit) mode */
lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CONFIG,
diff --git a/drivers/pwm/pwm-lpss-pci.c b/drivers/pwm/pwm-lpss-pci.c
index cf749ea0de9f..c893ec3d2fb4 100644
--- a/drivers/pwm/pwm-lpss-pci.c
+++ b/drivers/pwm/pwm-lpss-pci.c
@@ -69,12 +69,8 @@ static int pwm_lpss_probe_pci(struct pci_dev *pdev,
static void pwm_lpss_remove_pci(struct pci_dev *pdev)
{
- struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev);
-
pm_runtime_forbid(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
-
- pwm_lpss_remove(lpwm);
}
#ifdef CONFIG_PM
diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c
index 986786be1e49..928570430cef 100644
--- a/drivers/pwm/pwm-lpss-platform.c
+++ b/drivers/pwm/pwm-lpss-platform.c
@@ -85,10 +85,8 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev)
static int pwm_lpss_remove_platform(struct platform_device *pdev)
{
- struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev);
-
pm_runtime_disable(&pdev->dev);
- return pwm_lpss_remove(lpwm);
+ return 0;
}
static const struct acpi_device_id pwm_lpss_acpi_match[] = {
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 58b4031524af..36d4e83e6b79 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -236,7 +236,7 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
lpwm->chip.ops = &pwm_lpss_ops;
lpwm->chip.npwm = info->npwm;
- ret = pwmchip_add(&lpwm->chip);
+ ret = devm_pwmchip_add(dev, &lpwm->chip);
if (ret) {
dev_err(dev, "failed to add PWM chip: %d\n", ret);
return ERR_PTR(ret);
@@ -252,12 +252,6 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
}
EXPORT_SYMBOL_GPL(pwm_lpss_probe);
-int pwm_lpss_remove(struct pwm_lpss_chip *lpwm)
-{
- return pwmchip_remove(&lpwm->chip);
-}
-EXPORT_SYMBOL_GPL(pwm_lpss_remove);
-
MODULE_DESCRIPTION("PWM driver for Intel LPSS");
MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h
index 70db7e389d66..8b3476f25e06 100644
--- a/drivers/pwm/pwm-lpss.h
+++ b/drivers/pwm/pwm-lpss.h
@@ -35,6 +35,5 @@ struct pwm_lpss_boardinfo {
struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
const struct pwm_lpss_boardinfo *info);
-int pwm_lpss_remove(struct pwm_lpss_chip *lpwm);
#endif /* __PWM_LPSS_H */
diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
index 9eb060613cb4..3cf3bcf5ddfc 100644
--- a/drivers/pwm/pwm-meson.c
+++ b/drivers/pwm/pwm-meson.c
@@ -551,8 +551,6 @@ static int meson_pwm_probe(struct platform_device *pdev)
meson->chip.dev = &pdev->dev;
meson->chip.ops = &meson_pwm_ops;
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);
@@ -560,31 +558,21 @@ static int meson_pwm_probe(struct platform_device *pdev)
if (err < 0)
return err;
- err = pwmchip_add(&meson->chip);
+ err = devm_pwmchip_add(&pdev->dev, &meson->chip);
if (err < 0) {
dev_err(&pdev->dev, "failed to register PWM chip: %d\n", err);
return err;
}
- platform_set_drvdata(pdev, meson);
-
return 0;
}
-static int meson_pwm_remove(struct platform_device *pdev)
-{
- struct meson_pwm *meson = platform_get_drvdata(pdev);
-
- return pwmchip_remove(&meson->chip);
-}
-
static struct platform_driver meson_pwm_driver = {
.driver = {
.name = "meson-pwm",
.of_match_table = meson_pwm_matches,
},
.probe = meson_pwm_probe,
- .remove = meson_pwm_remove,
};
module_platform_driver(meson_pwm_driver);
diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c
index 0266e84e982c..a22180803bd7 100644
--- a/drivers/pwm/pwm-mxs.c
+++ b/drivers/pwm/pwm-mxs.c
@@ -138,8 +138,6 @@ static int mxs_pwm_probe(struct platform_device *pdev)
mxs->chip.dev = &pdev->dev;
mxs->chip.ops = &mxs_pwm_ops;
- mxs->chip.of_xlate = of_pwm_xlate_with_flags;
- mxs->chip.of_pwm_n_cells = 3;
ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm);
if (ret < 0) {
diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c
index 612b3c859295..507a2d945b90 100644
--- a/drivers/pwm/pwm-omap-dmtimer.c
+++ b/drivers/pwm/pwm-omap-dmtimer.c
@@ -404,8 +404,6 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
omap->chip.dev = &pdev->dev;
omap->chip.ops = &pwm_omap_dmtimer_ops;
omap->chip.npwm = 1;
- omap->chip.of_xlate = of_pwm_xlate_with_flags;
- omap->chip.of_pwm_n_cells = 3;
mutex_init(&omap->mutex);
diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 7c9f174de64e..42ed770b432c 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -23,11 +23,11 @@
#include <linux/bitmap.h>
/*
- * Because the PCA9685 has only one prescaler per chip, changing the period of
- * one channel affects the period of all 16 PWM outputs!
- * However, the ratio between each configured duty cycle and the chip-wide
- * period remains constant, because the OFF time is set in proportion to the
- * counter range.
+ * Because the PCA9685 has only one prescaler per chip, only the first channel
+ * that is enabled is allowed to change the prescale register.
+ * PWM channels requested afterwards must use a period that results in the same
+ * prescale setting as the one set by the first requested channel.
+ * GPIOs do not count as enabled PWMs as they are not using the prescaler.
*/
#define PCA9685_MODE1 0x00
@@ -78,8 +78,9 @@
struct pca9685 {
struct pwm_chip chip;
struct regmap *regmap;
-#if IS_ENABLED(CONFIG_GPIOLIB)
struct mutex lock;
+ DECLARE_BITMAP(pwms_enabled, PCA9685_MAXCHAN + 1);
+#if IS_ENABLED(CONFIG_GPIOLIB)
struct gpio_chip gpio;
DECLARE_BITMAP(pwms_inuse, PCA9685_MAXCHAN + 1);
#endif
@@ -90,51 +91,120 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
return container_of(chip, struct pca9685, chip);
}
+/* This function is supposed to be called with the lock mutex held */
+static bool pca9685_prescaler_can_change(struct pca9685 *pca, int channel)
+{
+ /* No PWM enabled: Change allowed */
+ if (bitmap_empty(pca->pwms_enabled, PCA9685_MAXCHAN + 1))
+ return true;
+ /* More than one PWM enabled: Change not allowed */
+ if (bitmap_weight(pca->pwms_enabled, PCA9685_MAXCHAN + 1) > 1)
+ return false;
+ /*
+ * Only one PWM enabled: Change allowed if the PWM about to
+ * be changed is the one that is already enabled
+ */
+ return test_bit(channel, pca->pwms_enabled);
+}
+
+static int pca9685_read_reg(struct pca9685 *pca, unsigned int reg, unsigned int *val)
+{
+ struct device *dev = pca->chip.dev;
+ int err;
+
+ err = regmap_read(pca->regmap, reg, val);
+ if (err)
+ dev_err(dev, "regmap_read of register 0x%x failed: %pe\n", reg, ERR_PTR(err));
+
+ return err;
+}
+
+static int pca9685_write_reg(struct pca9685 *pca, unsigned int reg, unsigned int val)
+{
+ struct device *dev = pca->chip.dev;
+ int err;
+
+ err = regmap_write(pca->regmap, reg, val);
+ if (err)
+ dev_err(dev, "regmap_write to register 0x%x failed: %pe\n", reg, ERR_PTR(err));
+
+ return err;
+}
+
/* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 50%) */
static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned int duty)
{
+ struct pwm_device *pwm = &pca->chip.pwms[channel];
+ unsigned int on, off;
+
if (duty == 0) {
/* Set the full OFF bit, which has the highest precedence */
- regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
+ pca9685_write_reg(pca, REG_OFF_H(channel), LED_FULL);
+ return;
} else if (duty >= PCA9685_COUNTER_RANGE) {
/* Set the full ON bit and clear the full OFF bit */
- regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
- regmap_write(pca->regmap, REG_OFF_H(channel), 0);
- } else {
- /* Set OFF time (clears the full OFF bit) */
- regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
- regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 0xf);
- /* Clear the full ON bit */
- regmap_write(pca->regmap, REG_ON_H(channel), 0);
+ pca9685_write_reg(pca, REG_ON_H(channel), LED_FULL);
+ pca9685_write_reg(pca, REG_OFF_H(channel), 0);
+ return;
}
+
+
+ if (pwm->state.usage_power && channel < PCA9685_MAXCHAN) {
+ /*
+ * If usage_power is set, the pca9685 driver will phase shift
+ * the individual channels relative to their channel number.
+ * This improves EMI because the enabled channels no longer
+ * turn on at the same time, while still maintaining the
+ * configured duty cycle / power output.
+ */
+ on = channel * PCA9685_COUNTER_RANGE / PCA9685_MAXCHAN;
+ } else
+ on = 0;
+
+ off = (on + duty) % PCA9685_COUNTER_RANGE;
+
+ /* Set ON time (clears full ON bit) */
+ pca9685_write_reg(pca, REG_ON_L(channel), on & 0xff);
+ pca9685_write_reg(pca, REG_ON_H(channel), (on >> 8) & 0xf);
+ /* Set OFF time (clears full OFF bit) */
+ pca9685_write_reg(pca, REG_OFF_L(channel), off & 0xff);
+ pca9685_write_reg(pca, REG_OFF_H(channel), (off >> 8) & 0xf);
}
static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
{
- unsigned int off_h = 0, val = 0;
+ struct pwm_device *pwm = &pca->chip.pwms[channel];
+ unsigned int off = 0, on = 0, val = 0;
if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
/* HW does not support reading state of "all LEDs" channel */
return 0;
}
- regmap_read(pca->regmap, LED_N_OFF_H(channel), &off_h);
- if (off_h & LED_FULL) {
+ pca9685_read_reg(pca, LED_N_OFF_H(channel), &off);
+ if (off & LED_FULL) {
/* Full OFF bit is set */
return 0;
}
- regmap_read(pca->regmap, LED_N_ON_H(channel), &val);
- if (val & LED_FULL) {
+ pca9685_read_reg(pca, LED_N_ON_H(channel), &on);
+ if (on & LED_FULL) {
/* Full ON bit is set */
return PCA9685_COUNTER_RANGE;
}
- if (regmap_read(pca->regmap, LED_N_OFF_L(channel), &val)) {
- /* Reset val to 0 in case reading LED_N_OFF_L failed */
+ pca9685_read_reg(pca, LED_N_OFF_L(channel), &val);
+ off = ((off & 0xf) << 8) | (val & 0xff);
+ if (!pwm->state.usage_power)
+ return off;
+
+ /* Read ON register to calculate duty cycle of staggered output */
+ if (pca9685_read_reg(pca, LED_N_ON_L(channel), &val)) {
+ /* Reset val to 0 in case reading LED_N_ON_L failed */
val = 0;
}
- return ((off_h & 0xf) << 8) | (val & 0xff);
+ on = ((on & 0xf) << 8) | (val & 0xff);
+ return (off - on) & (PCA9685_COUNTER_RANGE - 1);
}
#if IS_ENABLED(CONFIG_GPIOLIB)
@@ -240,8 +310,6 @@ static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
{
struct device *dev = pca->chip.dev;
- mutex_init(&pca->lock);
-
pca->gpio.label = dev_name(dev);
pca->gpio.parent = dev;
pca->gpio.request = pca9685_pwm_gpio_request;
@@ -277,16 +345,23 @@ static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca)
static void pca9685_set_sleep_mode(struct pca9685 *pca, bool enable)
{
- regmap_update_bits(pca->regmap, PCA9685_MODE1,
- MODE1_SLEEP, enable ? MODE1_SLEEP : 0);
+ struct device *dev = pca->chip.dev;
+ int err = regmap_update_bits(pca->regmap, PCA9685_MODE1,
+ MODE1_SLEEP, enable ? MODE1_SLEEP : 0);
+ if (err) {
+ dev_err(dev, "regmap_update_bits of register 0x%x failed: %pe\n",
+ PCA9685_MODE1, ERR_PTR(err));
+ return;
+ }
+
if (!enable) {
/* Wait 500us for the oscillator to be back up */
udelay(500);
}
}
-static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
- const struct pwm_state *state)
+static int __pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
{
struct pca9685 *pca = to_pca(chip);
unsigned long long duty, prescale;
@@ -307,8 +382,14 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
- regmap_read(pca->regmap, PCA9685_PRESCALE, &val);
+ pca9685_read_reg(pca, PCA9685_PRESCALE, &val);
if (prescale != val) {
+ if (!pca9685_prescaler_can_change(pca, pwm->hwpwm)) {
+ dev_err(chip->dev,
+ "pwm not changed: periods of enabled pwms must match!\n");
+ return -EBUSY;
+ }
+
/*
* Putting the chip briefly into SLEEP mode
* at this point won't interfere with the
@@ -319,7 +400,7 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
pca9685_set_sleep_mode(pca, true);
/* Change the chip-wide output frequency */
- regmap_write(pca->regmap, PCA9685_PRESCALE, prescale);
+ pca9685_write_reg(pca, PCA9685_PRESCALE, prescale);
/* Wake the chip up */
pca9685_set_sleep_mode(pca, false);
@@ -331,6 +412,25 @@ static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
+static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ struct pca9685 *pca = to_pca(chip);
+ int ret;
+
+ mutex_lock(&pca->lock);
+ ret = __pca9685_pwm_apply(chip, pwm, state);
+ if (ret == 0) {
+ if (state->enabled)
+ set_bit(pwm->hwpwm, pca->pwms_enabled);
+ else
+ clear_bit(pwm->hwpwm, pca->pwms_enabled);
+ }
+ mutex_unlock(&pca->lock);
+
+ return ret;
+}
+
static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
{
@@ -339,7 +439,7 @@ static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned int val = 0;
/* Calculate (chip-wide) period from prescale value */
- regmap_read(pca->regmap, PCA9685_PRESCALE, &val);
+ pca9685_read_reg(pca, PCA9685_PRESCALE, &val);
/*
* PCA9685_OSC_CLOCK_MHZ is 25, i.e. an integer divider of 1000.
* The following calculation is therefore only a multiplication
@@ -372,6 +472,14 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
if (pca9685_pwm_test_and_set_inuse(pca, pwm->hwpwm))
return -EBUSY;
+
+ if (pwm->hwpwm < PCA9685_MAXCHAN) {
+ /* PWMs - except the "all LEDs" channel - default to enabled */
+ mutex_lock(&pca->lock);
+ set_bit(pwm->hwpwm, pca->pwms_enabled);
+ mutex_unlock(&pca->lock);
+ }
+
pm_runtime_get_sync(chip->dev);
return 0;
@@ -381,7 +489,11 @@ static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct pca9685 *pca = to_pca(chip);
+ mutex_lock(&pca->lock);
pca9685_pwm_set_duty(pca, pwm->hwpwm, 0);
+ clear_bit(pwm->hwpwm, pca->pwms_enabled);
+ mutex_unlock(&pca->lock);
+
pm_runtime_put(chip->dev);
pca9685_pwm_clear_inuse(pca, pwm->hwpwm);
}
@@ -422,7 +534,11 @@ static int pca9685_pwm_probe(struct i2c_client *client,
i2c_set_clientdata(client, pca);
- regmap_read(pca->regmap, PCA9685_MODE2, &reg);
+ mutex_init(&pca->lock);
+
+ ret = pca9685_read_reg(pca, PCA9685_MODE2, &reg);
+ if (ret)
+ return ret;
if (device_property_read_bool(&client->dev, "invert"))
reg |= MODE2_INVRT;
@@ -434,16 +550,20 @@ static int pca9685_pwm_probe(struct i2c_client *client,
else
reg |= MODE2_OUTDRV;
- regmap_write(pca->regmap, PCA9685_MODE2, reg);
+ ret = pca9685_write_reg(pca, PCA9685_MODE2, reg);
+ if (ret)
+ return ret;
/* Disable all LED ALLCALL and SUBx addresses to avoid bus collisions */
- regmap_read(pca->regmap, PCA9685_MODE1, &reg);
+ pca9685_read_reg(pca, PCA9685_MODE1, &reg);
reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
- regmap_write(pca->regmap, PCA9685_MODE1, reg);
+ pca9685_write_reg(pca, PCA9685_MODE1, reg);
- /* Reset OFF registers to POR default */
- regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, LED_FULL);
- regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, LED_FULL);
+ /* Reset OFF/ON registers to POR default */
+ pca9685_write_reg(pca, PCA9685_ALL_LED_OFF_L, LED_FULL);
+ pca9685_write_reg(pca, PCA9685_ALL_LED_OFF_H, LED_FULL);
+ pca9685_write_reg(pca, PCA9685_ALL_LED_ON_L, 0);
+ pca9685_write_reg(pca, PCA9685_ALL_LED_ON_H, 0);
pca->chip.ops = &pca9685_pwm_ops;
/* Add an extra channel for ALL_LED */
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index cfb683827d32..e091a528e33c 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -165,7 +165,7 @@ pxa_pwm_of_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
static int pwm_probe(struct platform_device *pdev)
{
const struct platform_device_id *id = platform_get_device_id(pdev);
- struct pxa_pwm_chip *pwm;
+ struct pxa_pwm_chip *pc;
int ret = 0;
if (IS_ENABLED(CONFIG_OF) && id == NULL)
@@ -174,46 +174,44 @@ static int pwm_probe(struct platform_device *pdev)
if (id == NULL)
return -EINVAL;
- pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
- if (pwm == NULL)
+ pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
+ if (pc == NULL)
return -ENOMEM;
- pwm->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(pwm->clk))
- return PTR_ERR(pwm->clk);
+ pc->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pc->clk))
+ return PTR_ERR(pc->clk);
- pwm->chip.dev = &pdev->dev;
- pwm->chip.ops = &pxa_pwm_ops;
- pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
+ pc->chip.dev = &pdev->dev;
+ pc->chip.ops = &pxa_pwm_ops;
+ pc->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
if (IS_ENABLED(CONFIG_OF)) {
- pwm->chip.of_xlate = pxa_pwm_of_xlate;
- pwm->chip.of_pwm_n_cells = 1;
+ pc->chip.of_xlate = pxa_pwm_of_xlate;
+ pc->chip.of_pwm_n_cells = 1;
}
- pwm->mmio_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(pwm->mmio_base))
- return PTR_ERR(pwm->mmio_base);
+ pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(pc->mmio_base))
+ return PTR_ERR(pc->mmio_base);
- ret = pwmchip_add(&pwm->chip);
+ ret = pwmchip_add(&pc->chip);
if (ret < 0) {
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
return ret;
}
- platform_set_drvdata(pdev, pwm);
+ platform_set_drvdata(pdev, pc);
return 0;
}
static int pwm_remove(struct platform_device *pdev)
{
- struct pxa_pwm_chip *chip;
+ struct pxa_pwm_chip *pc;
- chip = platform_get_drvdata(pdev);
- if (chip == NULL)
- return -ENODEV;
+ pc = platform_get_drvdata(pdev);
- return pwmchip_remove(&chip->chip);
+ return pwmchip_remove(&pc->chip);
}
static struct platform_driver pwm_driver = {
diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c
index e2959fae0969..b853e7942605 100644
--- a/drivers/pwm/pwm-renesas-tpu.c
+++ b/drivers/pwm/pwm-renesas-tpu.c
@@ -408,8 +408,6 @@ static int tpu_probe(struct platform_device *pdev)
tpu->chip.dev = &pdev->dev;
tpu->chip.ops = &tpu_pwm_ops;
- tpu->chip.of_xlate = of_pwm_xlate_with_flags;
- tpu->chip.of_pwm_n_cells = 3;
tpu->chip.npwm = TPU_CHANNEL_MAX;
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index 301785fa293e..cbe900877724 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -354,11 +354,6 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
pc->chip.ops = &rockchip_pwm_ops;
pc->chip.npwm = 1;
- if (pc->data->supports_polarity) {
- pc->chip.of_xlate = of_pwm_xlate_with_flags;
- pc->chip.of_pwm_n_cells = 3;
- }
-
enable_conf = pc->data->enable_conf;
ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
enabled = (ctrl & enable_conf) == enable_conf;
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index 515489fa4f6d..f6c528f02d43 100644
--- a/drivers/pwm/pwm-samsung.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -526,9 +526,6 @@ static int pwm_samsung_probe(struct platform_device *pdev)
ret = pwm_samsung_parse_dt(chip);
if (ret)
return ret;
-
- chip->chip.of_xlate = of_pwm_xlate_with_flags;
- chip->chip.of_pwm_n_cells = 3;
} else {
if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "no platform data specified\n");
diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
index 688737f091ac..420edc4aa94a 100644
--- a/drivers/pwm/pwm-sifive.c
+++ b/drivers/pwm/pwm-sifive.c
@@ -242,8 +242,6 @@ static int pwm_sifive_probe(struct platform_device *pdev)
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->npwm = 4;
ddata->regs = devm_platform_ioremap_resource(pdev, 0);
diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c
index 1a1cedfd11ce..54c7990967dd 100644
--- a/drivers/pwm/pwm-spear.c
+++ b/drivers/pwm/pwm-spear.c
@@ -75,7 +75,7 @@ static inline void spear_pwm_writel(struct spear_pwm_chip *chip,
}
static int spear_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
- int duty_ns, int period_ns)
+ u64 duty_ns, u64 period_ns)
{
struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
u64 val, div, clk_rate;
@@ -163,10 +163,32 @@ static void spear_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
clk_disable(pc->clk);
}
+static int spear_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ int err;
+
+ if (state->polarity != PWM_POLARITY_NORMAL)
+ return -EINVAL;
+
+ if (!state->enabled) {
+ if (pwm->state.enabled)
+ spear_pwm_disable(chip, pwm);
+ return 0;
+ }
+
+ err = spear_pwm_config(chip, pwm, state->duty_cycle, state->period);
+ if (err)
+ return err;
+
+ if (!pwm->state.enabled)
+ return spear_pwm_enable(chip, pwm);
+
+ return 0;
+}
+
static const struct pwm_ops spear_pwm_ops = {
- .config = spear_pwm_config,
- .enable = spear_pwm_enable,
- .disable = spear_pwm_disable,
+ .apply = spear_pwm_apply,
.owner = THIS_MODULE,
};
@@ -228,14 +250,13 @@ static int spear_pwm_probe(struct platform_device *pdev)
static int spear_pwm_remove(struct platform_device *pdev)
{
struct spear_pwm_chip *pc = platform_get_drvdata(pdev);
- int i;
- for (i = 0; i < NUM_PWM; i++)
- pwm_disable(&pc->chip.pwms[i]);
+ pwmchip_remove(&pc->chip);
/* clk was prepared in probe, hence unprepare it here */
clk_unprepare(pc->clk);
- return pwmchip_remove(&pc->chip);
+
+ return 0;
}
static const struct of_device_id spear_pwm_of_match[] = {
diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c
index 98c479dfae31..7004f55bbf11 100644
--- a/drivers/pwm/pwm-sprd.c
+++ b/drivers/pwm/pwm-sprd.c
@@ -183,13 +183,10 @@ static int sprd_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
}
}
- if (state->period != cstate->period ||
- state->duty_cycle != cstate->duty_cycle) {
- ret = sprd_pwm_config(spc, pwm, state->duty_cycle,
- state->period);
- if (ret)
- return ret;
- }
+ ret = sprd_pwm_config(spc, pwm, state->duty_cycle,
+ state->period);
+ if (ret)
+ return ret;
sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_ENABLE, 1);
} else if (cstate->enabled) {
@@ -284,7 +281,9 @@ static int sprd_pwm_remove(struct platform_device *pdev)
{
struct sprd_pwm_chip *spc = platform_get_drvdata(pdev);
- return pwmchip_remove(&spc->chip);
+ pwmchip_remove(&spc->chip);
+
+ return 0;
}
static const struct of_device_id sprd_pwm_of_match[] = {
diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c
index af08f564ef1d..93dd03618465 100644
--- a/drivers/pwm/pwm-stm32-lp.c
+++ b/drivers/pwm/pwm-stm32-lp.c
@@ -208,8 +208,6 @@ static int stm32_pwm_lp_probe(struct platform_device *pdev)
priv->chip.dev = &pdev->dev;
priv->chip.ops = &stm32_pwm_lp_ops;
priv->chip.npwm = 1;
- priv->chip.of_xlate = of_pwm_xlate_with_flags;
- priv->chip.of_pwm_n_cells = 3;
ret = pwmchip_add(&priv->chip);
if (ret < 0)
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index c46fb90036ab..794ca5b02968 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -621,8 +621,6 @@ 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-sun4i.c b/drivers/pwm/pwm-sun4i.c
index e01becd102c0..c952604e91f3 100644
--- a/drivers/pwm/pwm-sun4i.c
+++ b/drivers/pwm/pwm-sun4i.c
@@ -460,8 +460,6 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
pwm->chip.dev = &pdev->dev;
pwm->chip.ops = &sun4i_pwm_ops;
pwm->chip.npwm = pwm->data->npwm;
- pwm->chip.of_xlate = of_pwm_xlate_with_flags;
- pwm->chip.of_pwm_n_cells = 3;
spin_lock_init(&pwm->ctrl_lock);
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
index c529a170bcdd..11a10b575ace 100644
--- a/drivers/pwm/pwm-tegra.c
+++ b/drivers/pwm/pwm-tegra.c
@@ -300,32 +300,12 @@ static int tegra_pwm_probe(struct platform_device *pdev)
static int tegra_pwm_remove(struct platform_device *pdev)
{
struct tegra_pwm_chip *pc = platform_get_drvdata(pdev);
- unsigned int i;
- int err;
-
- if (WARN_ON(!pc))
- return -ENODEV;
-
- err = clk_prepare_enable(pc->clk);
- if (err < 0)
- return err;
-
- for (i = 0; i < pc->chip.npwm; i++) {
- struct pwm_device *pwm = &pc->chip.pwms[i];
-
- if (!pwm_is_enabled(pwm))
- if (clk_prepare_enable(pc->clk) < 0)
- continue;
- pwm_writel(pc, i, 0);
-
- clk_disable_unprepare(pc->clk);
- }
+ pwmchip_remove(&pc->chip);
reset_control_assert(pc->rst);
- clk_disable_unprepare(pc->clk);
- return pwmchip_remove(&pc->chip);
+ return 0;
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index b9a17ab0c202..35eb19a5a0d1 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -48,16 +48,13 @@ static inline struct ecap_pwm_chip *to_ecap_pwm_chip(struct pwm_chip *chip)
* duty_ns = 10^9 * duty_cycles / PWM_CLK_RATE
*/
static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
- int duty_ns, int period_ns)
+ int duty_ns, int period_ns, int enabled)
{
struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
u32 period_cycles, duty_cycles;
unsigned long long c;
u16 value;
- if (period_ns > NSEC_PER_SEC)
- return -ERANGE;
-
c = pc->clk_rate;
c = c * period_ns;
do_div(c, NSEC_PER_SEC);
@@ -82,7 +79,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
writew(value, pc->mmio_base + ECCTL2);
- if (!pwm_is_enabled(pwm)) {
+ if (!enabled) {
/* Update active registers if not running */
writel(duty_cycles, pc->mmio_base + CAP2);
writel(period_cycles, pc->mmio_base + CAP1);
@@ -96,7 +93,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
writel(period_cycles, pc->mmio_base + CAP3);
}
- if (!pwm_is_enabled(pwm)) {
+ if (!enabled) {
value = readw(pc->mmio_base + ECCTL2);
/* Disable APWM mode to put APWM output Low */
value &= ~ECCTL2_APWM_MODE;
@@ -168,20 +165,46 @@ static void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
pm_runtime_put_sync(pc->chip.dev);
}
-static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+static int ecap_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
{
- if (pwm_is_enabled(pwm)) {
- dev_warn(chip->dev, "Removing PWM device without disabling\n");
- pm_runtime_put_sync(chip->dev);
+ int err;
+ int enabled = pwm->state.enabled;
+
+ if (state->polarity != pwm->state.polarity) {
+
+ if (enabled) {
+ ecap_pwm_disable(chip, pwm);
+ enabled = false;
+ }
+
+ err = ecap_pwm_set_polarity(chip, pwm, state->polarity);
+ if (err)
+ return err;
+ }
+
+ if (!state->enabled) {
+ if (enabled)
+ ecap_pwm_disable(chip, pwm);
+ return 0;
}
+
+ if (state->period > NSEC_PER_SEC)
+ return -ERANGE;
+
+ err = ecap_pwm_config(chip, pwm, state->duty_cycle,
+ state->period, enabled);
+ if (err)
+ return err;
+
+ if (!enabled)
+ return ecap_pwm_enable(chip, pwm);
+
+ return 0;
}
static const struct pwm_ops ecap_pwm_ops = {
- .free = ecap_pwm_free,
- .config = ecap_pwm_config,
- .set_polarity = ecap_pwm_set_polarity,
- .enable = ecap_pwm_enable,
- .disable = ecap_pwm_disable,
+ .apply = ecap_pwm_apply,
.owner = THIS_MODULE,
};
@@ -224,8 +247,6 @@ static int ecap_pwm_probe(struct platform_device *pdev)
pc->chip.dev = &pdev->dev;
pc->chip.ops = &ecap_pwm_ops;
- pc->chip.of_xlate = of_pwm_xlate_with_flags;
- pc->chip.of_pwm_n_cells = 3;
pc->chip.npwm = 1;
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index 90095a19bf2d..17909fa53211 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -447,8 +447,6 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
pc->chip.dev = &pdev->dev;
pc->chip.ops = &ehrpwm_pwm_ops;
- pc->chip.of_xlate = of_pwm_xlate_with_flags;
- pc->chip.of_pwm_n_cells = 3;
pc->chip.npwm = NUM_PWM_CHANNEL;
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
diff --git a/drivers/pwm/pwm-visconti.c b/drivers/pwm/pwm-visconti.c
index 46d903786366..af4e37d3e3a6 100644
--- a/drivers/pwm/pwm-visconti.c
+++ b/drivers/pwm/pwm-visconti.c
@@ -82,17 +82,14 @@ static int visconti_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return -ERANGE;
/*
- * PWMC controls a divider that divides the input clk by a
- * power of two between 1 and 8. As a smaller divider yields
- * higher precision, pick the smallest possible one.
+ * PWMC controls a divider that divides the input clk by a power of two
+ * between 1 and 8. As a smaller divider yields higher precision, pick
+ * the smallest possible one. As period is at most 0xffff << 3, pwmc0 is
+ * in the intended range [0..3].
*/
- if (period > 0xffff) {
- pwmc0 = ilog2(period >> 16);
- if (WARN_ON(pwmc0 > 3))
- return -EINVAL;
- } else {
- pwmc0 = 0;
- }
+ pwmc0 = fls(period >> 16);
+ if (WARN_ON(pwmc0 > 3))
+ return -EINVAL;
period >>= pwmc0;
duty_cycle >>= pwmc0;
diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c
index 52fe5d19473a..ea2aa151080a 100644
--- a/drivers/pwm/pwm-vt8500.c
+++ b/drivers/pwm/pwm-vt8500.c
@@ -207,8 +207,6 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
chip->chip.dev = &pdev->dev;
chip->chip.ops = &vt8500_pwm_ops;
- chip->chip.of_xlate = of_pwm_xlate_with_flags;
- chip->chip.of_pwm_n_cells = 3;
chip->chip.npwm = VT8500_NR_PWMS;
chip->clk = devm_clk_get(&pdev->dev, NULL);
@@ -240,15 +238,13 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
static int vt8500_pwm_remove(struct platform_device *pdev)
{
- struct vt8500_chip *chip;
+ struct vt8500_chip *chip = platform_get_drvdata(pdev);
- chip = platform_get_drvdata(pdev);
- if (chip == NULL)
- return -ENODEV;
+ pwmchip_remove(&chip->chip);
clk_unprepare(chip->clk);
- return pwmchip_remove(&chip->chip);
+ return 0;
}
static struct platform_driver vt8500_pwm_driver = {
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 3e7a38525cb3..24ce9a17ab4f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -193,20 +193,10 @@ config REGULATOR_BCM590XX
BCM590xx PMUs. This will enable support for the software
controllable LDO/Switching regulators.
-config REGULATOR_BD70528
- tristate "ROHM BD70528 Power Regulator"
- depends on MFD_ROHM_BD70528
- help
- This driver supports voltage regulators on ROHM BD70528 PMIC.
- This will enable support for the software controllable buck
- and LDO regulators.
-
- This driver can also be built as a module. If so, the module
- will be called bd70528-regulator.
-
config REGULATOR_BD71815
tristate "ROHM BD71815 Power Regulator"
depends on MFD_ROHM_BD71828
+ select REGULATOR_ROHM
help
This driver supports voltage regulators on ROHM BD71815 PMIC.
This will enable support for the software controllable buck
@@ -588,6 +578,14 @@ config REGULATOR_MAX8660
This driver controls a Maxim 8660/8661 voltage output
regulator via I2C bus.
+config REGULATOR_MAX8893
+ tristate "Maxim 8893 voltage regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver controls a Maxim 8893 voltage output
+ regulator via I2C bus.
+
config REGULATOR_MAX8907
tristate "Maxim 8907 voltage regulator"
depends on MFD_MAX8907 || COMPILE_TEST
@@ -779,6 +777,15 @@ config REGULATOR_MT6358
This driver supports the control of different power rails of device
through regulator interface.
+config REGULATOR_MT6359
+ tristate "MediaTek MT6359 PMIC"
+ depends on MFD_MT6397
+ help
+ Say y here to select this option to enable the power regulator of
+ MediaTek MT6359 PMIC.
+ This driver supports the control of different power rails of device
+ through regulator interface.
+
config REGULATOR_MT6360
tristate "MT6360 SubPMIC Regulator"
depends on MFD_MT6360
@@ -1030,6 +1037,26 @@ config REGULATOR_RT5033
RT5033 PMIC. The device supports multiple regulators like
current source, LDO and Buck.
+config REGULATOR_RT6160
+ tristate "Richtek RT6160 BuckBoost voltage regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This adds support for voltage regulator in Richtek RT6160.
+ This device automatically change voltage output mode from
+ Buck or Boost. The mode transistion depend on the input source voltage.
+ The wide output range is from 2025mV to 5200mV and can be used on most
+ common application scenario.
+
+config REGULATOR_RT6245
+ tristate "Richtek RT6245 voltage regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This adds supprot for Richtek RT6245 voltage regulator.
+ It can support up to 14A output current and adjustable output voltage
+ from 0.4375V to 1.3875V, per step 12.5mV.
+
config REGULATOR_RTMV20
tristate "Richtek RTMV20 Laser Diode Regulator"
depends on I2C
@@ -1150,6 +1177,12 @@ config REGULATOR_STW481X_VMMC
This driver supports the internal VMMC regulator in the STw481x
PMIC chips.
+config REGULATOR_SY7636A
+ tristate "Silergy SY7636A voltage regulator"
+ depends on MFD_SY7636A
+ help
+ This driver supports Silergy SY3686A voltage regulator.
+
config REGULATOR_SY8106A
tristate "Silergy SY8106A regulator"
depends on I2C && (OF || COMPILE_TEST)
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 580b015296ea..8c2f82206b94 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -4,7 +4,7 @@
#
-obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o
+obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o irq_helpers.o
obj-$(CONFIG_OF) += of_regulator.o
obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
@@ -29,7 +29,6 @@ obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
obj-$(CONFIG_REGULATOR_ATC260X) += atc260x-regulator.o
obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
-obj-$(CONFIG_REGULATOR_BD70528) += bd70528-regulator.o
obj-$(CONFIG_REGULATOR_BD71815) += bd71815-regulator.o
obj-$(CONFIG_REGULATOR_BD71828) += bd71828-regulator.o
obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o
@@ -72,6 +71,7 @@ obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o
obj-$(CONFIG_REGULATOR_MAX77650) += max77650-regulator.o
obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
+obj-$(CONFIG_REGULATOR_MAX8893) += max8893.o
obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o
obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
@@ -94,6 +94,7 @@ obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
obj-$(CONFIG_REGULATOR_MT6315) += mt6315-regulator.o
obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o
+obj-$(CONFIG_REGULATOR_MT6359) += mt6359-regulator.o
obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o
obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
@@ -124,6 +125,8 @@ obj-$(CONFIG_REGULATOR_ROHM) += rohm-regulator.o
obj-$(CONFIG_REGULATOR_RT4801) += rt4801-regulator.o
obj-$(CONFIG_REGULATOR_RT4831) += rt4831-regulator.o
obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o
+obj-$(CONFIG_REGULATOR_RT6160) += rt6160-regulator.o
+obj-$(CONFIG_REGULATOR_RT6245) += rt6245-regulator.o
obj-$(CONFIG_REGULATOR_RTMV20) += rtmv20-regulator.o
obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
@@ -136,6 +139,7 @@ obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o
obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o
obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
+obj-$(CONFIG_REGULATOR_SY7636A) += sy7636a-regulator.o
obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o
obj-$(CONFIG_REGULATOR_SY8824X) += sy8824x.o
obj-$(CONFIG_REGULATOR_SY8827N) += sy8827n.o
diff --git a/drivers/regulator/bd70528-regulator.c b/drivers/regulator/bd70528-regulator.c
deleted file mode 100644
index 1f5f9482b209..000000000000
--- a/drivers/regulator/bd70528-regulator.c
+++ /dev/null
@@ -1,283 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (C) 2018 ROHM Semiconductors
-// bd70528-regulator.c ROHM BD70528MWV regulator driver
-
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.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/regulator/driver.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/of_regulator.h>
-#include <linux/slab.h>
-
-#define BUCK_RAMPRATE_250MV 0
-#define BUCK_RAMPRATE_125MV 1
-#define BUCK_RAMP_MAX 250
-
-static const struct linear_range bd70528_buck1_volts[] = {
- REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x1, 600000),
- REGULATOR_LINEAR_RANGE(2750000, 0x2, 0xf, 50000),
-};
-static const struct linear_range bd70528_buck2_volts[] = {
- REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x1, 300000),
- REGULATOR_LINEAR_RANGE(1550000, 0x2, 0xd, 50000),
- REGULATOR_LINEAR_RANGE(3000000, 0xe, 0xf, 300000),
-};
-static const struct linear_range bd70528_buck3_volts[] = {
- REGULATOR_LINEAR_RANGE(800000, 0x00, 0xd, 50000),
- REGULATOR_LINEAR_RANGE(1800000, 0xe, 0xf, 0),
-};
-
-/* All LDOs have same voltage ranges */
-static const struct linear_range bd70528_ldo_volts[] = {
- REGULATOR_LINEAR_RANGE(1650000, 0x0, 0x07, 50000),
- REGULATOR_LINEAR_RANGE(2100000, 0x8, 0x0f, 100000),
- REGULATOR_LINEAR_RANGE(2850000, 0x10, 0x19, 50000),
- REGULATOR_LINEAR_RANGE(3300000, 0x19, 0x1f, 0),
-};
-
-/* Also both LEDs support same voltages */
-static const unsigned int led_volts[] = {
- 20000, 30000
-};
-
-static int bd70528_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
- if (ramp_delay > 0 && ramp_delay <= BUCK_RAMP_MAX) {
- unsigned int ramp_value = BUCK_RAMPRATE_250MV;
-
- if (ramp_delay <= 125)
- ramp_value = BUCK_RAMPRATE_125MV;
-
- return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
- BD70528_MASK_BUCK_RAMP,
- ramp_value << BD70528_SIFT_BUCK_RAMP);
- }
- dev_err(&rdev->dev, "%s: ramp_delay: %d not supported\n",
- rdev->desc->name, ramp_delay);
- return -EINVAL;
-}
-
-static int bd70528_led_set_voltage_sel(struct regulator_dev *rdev,
- unsigned int sel)
-{
- int ret;
-
- ret = regulator_is_enabled_regmap(rdev);
- if (ret < 0)
- return ret;
-
- if (ret == 0)
- return regulator_set_voltage_sel_regmap(rdev, sel);
-
- dev_err(&rdev->dev,
- "LED voltage change not allowed when led is enabled\n");
-
- return -EBUSY;
-}
-
-static const struct regulator_ops bd70528_buck_ops = {
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
- .is_enabled = regulator_is_enabled_regmap,
- .list_voltage = regulator_list_voltage_linear_range,
- .set_voltage_sel = regulator_set_voltage_sel_regmap,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage_time_sel = regulator_set_voltage_time_sel,
- .set_ramp_delay = bd70528_set_ramp_delay,
-};
-
-static const struct regulator_ops bd70528_ldo_ops = {
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
- .is_enabled = regulator_is_enabled_regmap,
- .list_voltage = regulator_list_voltage_linear_range,
- .set_voltage_sel = regulator_set_voltage_sel_regmap,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage_time_sel = regulator_set_voltage_time_sel,
-};
-
-static const struct regulator_ops bd70528_led_ops = {
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
- .is_enabled = regulator_is_enabled_regmap,
- .list_voltage = regulator_list_voltage_table,
- .set_voltage_sel = bd70528_led_set_voltage_sel,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
-};
-
-static const struct regulator_desc bd70528_desc[] = {
- {
- .name = "buck1",
- .of_match = of_match_ptr("BUCK1"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD70528_BUCK1,
- .ops = &bd70528_buck_ops,
- .type = REGULATOR_VOLTAGE,
- .linear_ranges = bd70528_buck1_volts,
- .n_linear_ranges = ARRAY_SIZE(bd70528_buck1_volts),
- .n_voltages = BD70528_BUCK_VOLTS,
- .enable_reg = BD70528_REG_BUCK1_EN,
- .enable_mask = BD70528_MASK_RUN_EN,
- .vsel_reg = BD70528_REG_BUCK1_VOLT,
- .vsel_mask = BD70528_MASK_BUCK_VOLT,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck2",
- .of_match = of_match_ptr("BUCK2"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD70528_BUCK2,
- .ops = &bd70528_buck_ops,
- .type = REGULATOR_VOLTAGE,
- .linear_ranges = bd70528_buck2_volts,
- .n_linear_ranges = ARRAY_SIZE(bd70528_buck2_volts),
- .n_voltages = BD70528_BUCK_VOLTS,
- .enable_reg = BD70528_REG_BUCK2_EN,
- .enable_mask = BD70528_MASK_RUN_EN,
- .vsel_reg = BD70528_REG_BUCK2_VOLT,
- .vsel_mask = BD70528_MASK_BUCK_VOLT,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck3",
- .of_match = of_match_ptr("BUCK3"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD70528_BUCK3,
- .ops = &bd70528_buck_ops,
- .type = REGULATOR_VOLTAGE,
- .linear_ranges = bd70528_buck3_volts,
- .n_linear_ranges = ARRAY_SIZE(bd70528_buck3_volts),
- .n_voltages = BD70528_BUCK_VOLTS,
- .enable_reg = BD70528_REG_BUCK3_EN,
- .enable_mask = BD70528_MASK_RUN_EN,
- .vsel_reg = BD70528_REG_BUCK3_VOLT,
- .vsel_mask = BD70528_MASK_BUCK_VOLT,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo1",
- .of_match = of_match_ptr("LDO1"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD70528_LDO1,
- .ops = &bd70528_ldo_ops,
- .type = REGULATOR_VOLTAGE,
- .linear_ranges = bd70528_ldo_volts,
- .n_linear_ranges = ARRAY_SIZE(bd70528_ldo_volts),
- .n_voltages = BD70528_LDO_VOLTS,
- .enable_reg = BD70528_REG_LDO1_EN,
- .enable_mask = BD70528_MASK_RUN_EN,
- .vsel_reg = BD70528_REG_LDO1_VOLT,
- .vsel_mask = BD70528_MASK_LDO_VOLT,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo2",
- .of_match = of_match_ptr("LDO2"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD70528_LDO2,
- .ops = &bd70528_ldo_ops,
- .type = REGULATOR_VOLTAGE,
- .linear_ranges = bd70528_ldo_volts,
- .n_linear_ranges = ARRAY_SIZE(bd70528_ldo_volts),
- .n_voltages = BD70528_LDO_VOLTS,
- .enable_reg = BD70528_REG_LDO2_EN,
- .enable_mask = BD70528_MASK_RUN_EN,
- .vsel_reg = BD70528_REG_LDO2_VOLT,
- .vsel_mask = BD70528_MASK_LDO_VOLT,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo3",
- .of_match = of_match_ptr("LDO3"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD70528_LDO3,
- .ops = &bd70528_ldo_ops,
- .type = REGULATOR_VOLTAGE,
- .linear_ranges = bd70528_ldo_volts,
- .n_linear_ranges = ARRAY_SIZE(bd70528_ldo_volts),
- .n_voltages = BD70528_LDO_VOLTS,
- .enable_reg = BD70528_REG_LDO3_EN,
- .enable_mask = BD70528_MASK_RUN_EN,
- .vsel_reg = BD70528_REG_LDO3_VOLT,
- .vsel_mask = BD70528_MASK_LDO_VOLT,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo_led1",
- .of_match = of_match_ptr("LDO_LED1"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD70528_LED1,
- .ops = &bd70528_led_ops,
- .type = REGULATOR_VOLTAGE,
- .volt_table = &led_volts[0],
- .n_voltages = ARRAY_SIZE(led_volts),
- .enable_reg = BD70528_REG_LED_EN,
- .enable_mask = BD70528_MASK_LED1_EN,
- .vsel_reg = BD70528_REG_LED_VOLT,
- .vsel_mask = BD70528_MASK_LED1_VOLT,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo_led2",
- .of_match = of_match_ptr("LDO_LED2"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD70528_LED2,
- .ops = &bd70528_led_ops,
- .type = REGULATOR_VOLTAGE,
- .volt_table = &led_volts[0],
- .n_voltages = ARRAY_SIZE(led_volts),
- .enable_reg = BD70528_REG_LED_EN,
- .enable_mask = BD70528_MASK_LED2_EN,
- .vsel_reg = BD70528_REG_LED_VOLT,
- .vsel_mask = BD70528_MASK_LED2_VOLT,
- .owner = THIS_MODULE,
- },
-
-};
-
-static int bd70528_probe(struct platform_device *pdev)
-{
- int i;
- struct regulator_config config = {
- .dev = pdev->dev.parent,
- };
-
- config.regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!config.regmap)
- return -ENODEV;
-
- for (i = 0; i < ARRAY_SIZE(bd70528_desc); i++) {
- struct regulator_dev *rdev;
-
- rdev = devm_regulator_register(&pdev->dev, &bd70528_desc[i],
- &config);
- if (IS_ERR(rdev)) {
- dev_err(&pdev->dev,
- "failed to register %s regulator\n",
- bd70528_desc[i].name);
- return PTR_ERR(rdev);
- }
- }
- return 0;
-}
-
-static struct platform_driver bd70528_regulator = {
- .driver = {
- .name = "bd70528-pmic"
- },
- .probe = bd70528_probe,
-};
-
-module_platform_driver(bd70528_regulator);
-
-MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("BD70528 voltage regulator driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:bd70528-pmic");
diff --git a/drivers/regulator/bd71815-regulator.c b/drivers/regulator/bd71815-regulator.c
index a4e8d5e36b40..16edd9062ca9 100644
--- a/drivers/regulator/bd71815-regulator.c
+++ b/drivers/regulator/bd71815-regulator.c
@@ -13,6 +13,8 @@
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/gpio/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/delay.h>
#include <linux/slab.h>
@@ -26,14 +28,6 @@ struct bd71815_regulator {
const struct rohm_dvs_config *dvs;
};
-struct bd71815_pmic {
- struct bd71815_regulator descs[BD71815_REGULATOR_CNT];
- struct regmap *regmap;
- struct device *dev;
- struct gpio_descs *gps;
- struct regulator_dev *rdev[BD71815_REGULATOR_CNT];
-};
-
static const int bd7181x_wled_currents[] = {
10, 20, 30, 50, 70, 100, 200, 300, 500, 700, 1000, 2000, 3000, 4000,
5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 13000, 14000, 15000,
@@ -300,14 +294,13 @@ static int bd7181x_led_set_current_limit(struct regulator_dev *rdev,
static int bd7181x_buck12_get_voltage_sel(struct regulator_dev *rdev)
{
- struct bd71815_pmic *pmic = rdev_get_drvdata(rdev);
int rid = rdev_get_id(rdev);
int ret, regh, regl, val;
regh = BD71815_REG_BUCK1_VOLT_H + rid * 0x2;
regl = BD71815_REG_BUCK1_VOLT_L + rid * 0x2;
- ret = regmap_read(pmic->regmap, regh, &val);
+ ret = regmap_read(rdev->regmap, regh, &val);
if (ret)
return ret;
@@ -319,7 +312,7 @@ static int bd7181x_buck12_get_voltage_sel(struct regulator_dev *rdev)
* by BD71815_BUCK_DVSSEL bit
*/
if ((!(val & BD71815_BUCK_STBY_DVS)) && (!(val & BD71815_BUCK_DVSSEL)))
- ret = regmap_read(pmic->regmap, regl, &val);
+ ret = regmap_read(rdev->regmap, regl, &val);
if (ret)
return ret;
@@ -333,14 +326,13 @@ static int bd7181x_buck12_get_voltage_sel(struct regulator_dev *rdev)
static int bd7181x_buck12_set_voltage_sel(struct regulator_dev *rdev,
unsigned int sel)
{
- struct bd71815_pmic *pmic = rdev_get_drvdata(rdev);
int rid = rdev_get_id(rdev);
int ret, val, reg, regh, regl;
regh = BD71815_REG_BUCK1_VOLT_H + rid*0x2;
regl = BD71815_REG_BUCK1_VOLT_L + rid*0x2;
- ret = regmap_read(pmic->regmap, regh, &val);
+ ret = regmap_read(rdev->regmap, regh, &val);
if (ret)
return ret;
@@ -350,7 +342,7 @@ static int bd7181x_buck12_set_voltage_sel(struct regulator_dev *rdev,
* voltages at runtime is not supported by this driver.
*/
if (((val & BD71815_BUCK_STBY_DVS))) {
- return regmap_update_bits(pmic->regmap, regh, BD71815_VOLT_MASK,
+ return regmap_update_bits(rdev->regmap, regh, BD71815_VOLT_MASK,
sel);
}
/* Update new voltage to the register which is not selected now */
@@ -359,12 +351,13 @@ static int bd7181x_buck12_set_voltage_sel(struct regulator_dev *rdev,
else
reg = regh;
- ret = regmap_update_bits(pmic->regmap, reg, BD71815_VOLT_MASK, sel);
+ ret = regmap_update_bits(rdev->regmap, reg, BD71815_VOLT_MASK, sel);
if (ret)
return ret;
/* Select the other DVS register to be used */
- return regmap_update_bits(pmic->regmap, regh, BD71815_BUCK_DVSSEL, ~val);
+ return regmap_update_bits(rdev->regmap, regh, BD71815_BUCK_DVSSEL,
+ ~val);
}
static const struct regulator_ops bd7181x_ldo_regulator_ops = {
@@ -522,7 +515,7 @@ static const struct regulator_ops bd7181x_led_regulator_ops = {
.dvs = (_dvs), \
}
-static struct bd71815_regulator bd71815_regulators[] = {
+static const struct bd71815_regulator bd71815_regulators[] = {
BD71815_BUCK12_REG(buck1, BD71815_BUCK1, BD71815_REG_BUCK1_VOLT_H,
BD71815_REG_BUCK1_MODE, 800000, 2000000, 25000,
&buck1_dvs),
@@ -568,24 +561,16 @@ static struct bd71815_regulator bd71815_regulators[] = {
static int bd7181x_probe(struct platform_device *pdev)
{
- struct bd71815_pmic *pmic;
struct regulator_config config = {};
int i, ret;
struct gpio_desc *ldo4_en;
+ struct regmap *regmap;
- pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
- if (!pmic)
- return -ENOMEM;
-
- memcpy(pmic->descs, bd71815_regulators, sizeof(pmic->descs));
-
- pmic->dev = &pdev->dev;
- pmic->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!pmic->regmap) {
- dev_err(pmic->dev, "No parent regmap\n");
+ regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!regmap) {
+ dev_err(&pdev->dev, "No parent regmap\n");
return -ENODEV;
}
- platform_set_drvdata(pdev, pmic);
ldo4_en = devm_gpiod_get_from_of_node(&pdev->dev,
pdev->dev.parent->of_node,
"rohm,vsel-gpios", 0,
@@ -599,23 +584,23 @@ static int bd7181x_probe(struct platform_device *pdev)
}
/* Disable to go to ship-mode */
- ret = regmap_update_bits(pmic->regmap, BD71815_REG_PWRCTRL,
- RESTARTEN, 0);
+ ret = regmap_update_bits(regmap, BD71815_REG_PWRCTRL, RESTARTEN, 0);
if (ret)
return ret;
config.dev = pdev->dev.parent;
- config.regmap = pmic->regmap;
+ config.regmap = regmap;
for (i = 0; i < BD71815_REGULATOR_CNT; i++) {
- struct regulator_desc *desc;
+ const struct regulator_desc *desc;
struct regulator_dev *rdev;
- desc = &pmic->descs[i].desc;
+ desc = &bd71815_regulators[i].desc;
+
if (i == BD71815_LDO4)
config.ena_gpiod = ldo4_en;
-
- config.driver_data = pmic;
+ else
+ config.ena_gpiod = NULL;
rdev = devm_regulator_register(&pdev->dev, desc, &config);
if (IS_ERR(rdev)) {
@@ -624,8 +609,6 @@ static int bd7181x_probe(struct platform_device *pdev)
desc->name);
return PTR_ERR(rdev);
}
- config.ena_gpiod = NULL;
- pmic->rdev[i] = rdev;
}
return 0;
}
@@ -639,7 +622,6 @@ MODULE_DEVICE_TABLE(platform, bd7181x_pmic_id);
static struct platform_driver bd7181x_regulator = {
.driver = {
.name = "bd7181x-pmic",
- .owner = THIS_MODULE,
},
.probe = bd7181x_probe,
.id_table = bd7181x_pmic_id,
diff --git a/drivers/regulator/bd9576-regulator.c b/drivers/regulator/bd9576-regulator.c
index 204a2da054f5..e16c3727db7a 100644
--- a/drivers/regulator/bd9576-regulator.c
+++ b/drivers/regulator/bd9576-regulator.c
@@ -2,10 +2,10 @@
// Copyright (C) 2020 ROHM Semiconductors
// ROHM BD9576MUF/BD9573MUF regulator driver
-#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
+#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/mfd/rohm-bd957x.h>
#include <linux/mfd/rohm-generic.h>
@@ -16,29 +16,118 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
#define BD957X_VOUTS1_VOLT 3300000
#define BD957X_VOUTS4_BASE_VOLT 1030000
#define BD957X_VOUTS34_NUM_VOLT 32
-static int vout1_volt_table[] = {5000000, 4900000, 4800000, 4700000, 4600000,
- 4500000, 4500000, 4500000, 5000000, 5100000,
- 5200000, 5300000, 5400000, 5500000, 5500000,
- 5500000};
+#define BD9576_THERM_IRQ_MASK_TW BIT(5)
+#define BD9576_xVD_IRQ_MASK_VOUTL1 BIT(5)
+#define BD9576_UVD_IRQ_MASK_VOUTS1_OCW BIT(6)
+#define BD9576_xVD_IRQ_MASK_VOUT1TO4 0x0F
-static int vout2_volt_table[] = {1800000, 1780000, 1760000, 1740000, 1720000,
- 1700000, 1680000, 1660000, 1800000, 1820000,
- 1840000, 1860000, 1880000, 1900000, 1920000,
- 1940000};
+static const unsigned int vout1_volt_table[] = {
+ 5000000, 4900000, 4800000, 4700000, 4600000,
+ 4500000, 4500000, 4500000, 5000000, 5100000,
+ 5200000, 5300000, 5400000, 5500000, 5500000,
+ 5500000
+};
+
+static const unsigned int vout2_volt_table[] = {
+ 1800000, 1780000, 1760000, 1740000, 1720000,
+ 1700000, 1680000, 1660000, 1800000, 1820000,
+ 1840000, 1860000, 1880000, 1900000, 1920000,
+ 1940000
+};
+
+static const unsigned int voutl1_volt_table[] = {
+ 2500000, 2540000, 2580000, 2620000, 2660000,
+ 2700000, 2740000, 2780000, 2500000, 2460000,
+ 2420000, 2380000, 2340000, 2300000, 2260000,
+ 2220000
+};
+
+static const struct linear_range vout1_xvd_ranges[] = {
+ REGULATOR_LINEAR_RANGE(225000, 0x01, 0x2b, 0),
+ REGULATOR_LINEAR_RANGE(225000, 0x2c, 0x54, 5000),
+ REGULATOR_LINEAR_RANGE(425000, 0x55, 0x7f, 0),
+};
+
+static const struct linear_range vout234_xvd_ranges[] = {
+ REGULATOR_LINEAR_RANGE(17000, 0x01, 0x0f, 0),
+ REGULATOR_LINEAR_RANGE(17000, 0x10, 0x6d, 1000),
+ REGULATOR_LINEAR_RANGE(110000, 0x6e, 0x7f, 0),
+};
+
+static const struct linear_range voutL1_xvd_ranges[] = {
+ REGULATOR_LINEAR_RANGE(34000, 0x01, 0x0f, 0),
+ REGULATOR_LINEAR_RANGE(34000, 0x10, 0x6d, 2000),
+ REGULATOR_LINEAR_RANGE(220000, 0x6e, 0x7f, 0),
+};
+
+static struct linear_range voutS1_ocw_ranges_internal[] = {
+ REGULATOR_LINEAR_RANGE(200000, 0x01, 0x04, 0),
+ REGULATOR_LINEAR_RANGE(250000, 0x05, 0x18, 50000),
+ REGULATOR_LINEAR_RANGE(1200000, 0x19, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocw_ranges[] = {
+ REGULATOR_LINEAR_RANGE(50000, 0x01, 0x04, 0),
+ REGULATOR_LINEAR_RANGE(60000, 0x05, 0x18, 10000),
+ REGULATOR_LINEAR_RANGE(250000, 0x19, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocp_ranges_internal[] = {
+ REGULATOR_LINEAR_RANGE(300000, 0x01, 0x06, 0),
+ REGULATOR_LINEAR_RANGE(350000, 0x7, 0x1b, 50000),
+ REGULATOR_LINEAR_RANGE(1350000, 0x1c, 0x3f, 0),
+};
-static int voutl1_volt_table[] = {2500000, 2540000, 2580000, 2620000, 2660000,
- 2700000, 2740000, 2780000, 2500000, 2460000,
- 2420000, 2380000, 2340000, 2300000, 2260000,
- 2220000};
+static struct linear_range voutS1_ocp_ranges[] = {
+ REGULATOR_LINEAR_RANGE(70000, 0x01, 0x06, 0),
+ REGULATOR_LINEAR_RANGE(80000, 0x7, 0x1b, 10000),
+ REGULATOR_LINEAR_RANGE(280000, 0x1c, 0x3f, 0),
+};
struct bd957x_regulator_data {
struct regulator_desc desc;
int base_voltage;
+ struct regulator_dev *rdev;
+ int ovd_notif;
+ int uvd_notif;
+ int temp_notif;
+ int ovd_err;
+ int uvd_err;
+ int temp_err;
+ const struct linear_range *xvd_ranges;
+ int num_xvd_ranges;
+ bool oc_supported;
+ unsigned int ovd_reg;
+ unsigned int uvd_reg;
+ unsigned int xvd_mask;
+ unsigned int ocp_reg;
+ unsigned int ocp_mask;
+ unsigned int ocw_reg;
+ unsigned int ocw_mask;
+ unsigned int ocw_rfet;
+};
+
+#define BD9576_NUM_REGULATORS 6
+#define BD9576_NUM_OVD_REGULATORS 5
+
+struct bd957x_data {
+ struct bd957x_regulator_data regulator_data[BD9576_NUM_REGULATORS];
+ struct regmap *regmap;
+ struct delayed_work therm_irq_suppress;
+ struct delayed_work ovd_irq_suppress;
+ struct delayed_work uvd_irq_suppress;
+ unsigned int therm_irq;
+ unsigned int ovd_irq;
+ unsigned int uvd_irq;
+ spinlock_t err_lock;
+ int regulator_global_err;
};
static int bd957x_vout34_list_voltage(struct regulator_dev *rdev,
@@ -72,151 +161,784 @@ static int bd957x_list_voltage(struct regulator_dev *rdev,
return desc->volt_table[index];
}
-static const struct regulator_ops bd957x_vout34_ops = {
+static void bd9576_fill_ovd_flags(struct bd957x_regulator_data *data,
+ bool warn)
+{
+ if (warn) {
+ data->ovd_notif = REGULATOR_EVENT_OVER_VOLTAGE_WARN;
+ data->ovd_err = REGULATOR_ERROR_OVER_VOLTAGE_WARN;
+ } else {
+ data->ovd_notif = REGULATOR_EVENT_REGULATION_OUT;
+ data->ovd_err = REGULATOR_ERROR_REGULATION_OUT;
+ }
+}
+
+static void bd9576_fill_ocp_flags(struct bd957x_regulator_data *data,
+ bool warn)
+{
+ if (warn) {
+ data->uvd_notif = REGULATOR_EVENT_OVER_CURRENT_WARN;
+ data->uvd_err = REGULATOR_ERROR_OVER_CURRENT_WARN;
+ } else {
+ data->uvd_notif = REGULATOR_EVENT_OVER_CURRENT;
+ data->uvd_err = REGULATOR_ERROR_OVER_CURRENT;
+ }
+}
+
+static void bd9576_fill_uvd_flags(struct bd957x_regulator_data *data,
+ bool warn)
+{
+ if (warn) {
+ data->uvd_notif = REGULATOR_EVENT_UNDER_VOLTAGE_WARN;
+ data->uvd_err = REGULATOR_ERROR_UNDER_VOLTAGE_WARN;
+ } else {
+ data->uvd_notif = REGULATOR_EVENT_UNDER_VOLTAGE;
+ data->uvd_err = REGULATOR_ERROR_UNDER_VOLTAGE;
+ }
+}
+
+static void bd9576_fill_temp_flags(struct bd957x_regulator_data *data,
+ bool enable, bool warn)
+{
+ if (!enable) {
+ data->temp_notif = 0;
+ data->temp_err = 0;
+ } else if (warn) {
+ data->temp_notif = REGULATOR_EVENT_OVER_TEMP_WARN;
+ data->temp_err = REGULATOR_ERROR_OVER_TEMP_WARN;
+ } else {
+ data->temp_notif = REGULATOR_EVENT_OVER_TEMP;
+ data->temp_err = REGULATOR_ERROR_OVER_TEMP;
+ }
+}
+
+static int bd9576_set_limit(const struct linear_range *r, int num_ranges,
+ struct regmap *regmap, int reg, int mask, int lim)
+{
+ int ret;
+ bool found;
+ int sel = 0;
+
+ if (lim) {
+
+ ret = linear_range_get_selector_low_array(r, num_ranges,
+ lim, &sel, &found);
+ if (ret)
+ return ret;
+
+ if (!found)
+ dev_warn(regmap_get_device(regmap),
+ "limit %d out of range. Setting lower\n",
+ lim);
+ }
+
+ return regmap_update_bits(regmap, reg, mask, sel);
+}
+
+static bool check_ocp_flag_mismatch(struct regulator_dev *rdev, int severity,
+ struct bd957x_regulator_data *r)
+{
+ if ((severity == REGULATOR_SEVERITY_ERR &&
+ r->uvd_notif != REGULATOR_EVENT_OVER_CURRENT) ||
+ (severity == REGULATOR_SEVERITY_WARN &&
+ r->uvd_notif != REGULATOR_EVENT_OVER_CURRENT_WARN)) {
+ dev_warn(rdev_get_dev(rdev),
+ "Can't support both OCP WARN and ERR\n");
+ /* Do not overwrite ERR config with WARN */
+ if (severity == REGULATOR_SEVERITY_WARN)
+ return true;
+
+ bd9576_fill_ocp_flags(r, 0);
+ }
+
+ return false;
+}
+
+static bool check_uvd_flag_mismatch(struct regulator_dev *rdev, int severity,
+ struct bd957x_regulator_data *r)
+{
+ if ((severity == REGULATOR_SEVERITY_ERR &&
+ r->uvd_notif != REGULATOR_EVENT_UNDER_VOLTAGE) ||
+ (severity == REGULATOR_SEVERITY_WARN &&
+ r->uvd_notif != REGULATOR_EVENT_UNDER_VOLTAGE_WARN)) {
+ dev_warn(rdev_get_dev(rdev),
+ "Can't support both UVD WARN and ERR\n");
+ if (severity == REGULATOR_SEVERITY_WARN)
+ return true;
+
+ bd9576_fill_uvd_flags(r, 0);
+ }
+
+ return false;
+}
+
+static bool check_ovd_flag_mismatch(struct regulator_dev *rdev, int severity,
+ struct bd957x_regulator_data *r)
+{
+ if ((severity == REGULATOR_SEVERITY_ERR &&
+ r->ovd_notif != REGULATOR_EVENT_REGULATION_OUT) ||
+ (severity == REGULATOR_SEVERITY_WARN &&
+ r->ovd_notif != REGULATOR_EVENT_OVER_VOLTAGE_WARN)) {
+ dev_warn(rdev_get_dev(rdev),
+ "Can't support both OVD WARN and ERR\n");
+ if (severity == REGULATOR_SEVERITY_WARN)
+ return true;
+
+ bd9576_fill_ovd_flags(r, 0);
+ }
+
+ return false;
+}
+
+static bool check_temp_flag_mismatch(struct regulator_dev *rdev, int severity,
+ struct bd957x_regulator_data *r)
+{
+ if ((severity == REGULATOR_SEVERITY_ERR &&
+ r->ovd_notif != REGULATOR_EVENT_OVER_TEMP) ||
+ (severity == REGULATOR_SEVERITY_WARN &&
+ r->ovd_notif != REGULATOR_EVENT_OVER_TEMP_WARN)) {
+ dev_warn(rdev_get_dev(rdev),
+ "Can't support both thermal WARN and ERR\n");
+ if (severity == REGULATOR_SEVERITY_WARN)
+ return true;
+ }
+
+ return false;
+}
+
+static int bd9576_set_ocp(struct regulator_dev *rdev, int lim_uA, int severity,
+ bool enable)
+{
+ struct bd957x_data *d;
+ struct bd957x_regulator_data *r;
+ int reg, mask;
+ int Vfet, rfet;
+ const struct linear_range *range;
+ int num_ranges;
+
+ if ((lim_uA && !enable) || (!lim_uA && enable))
+ return -EINVAL;
+
+ r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
+ if (!r->oc_supported)
+ return -EINVAL;
+
+ d = rdev_get_drvdata(rdev);
+
+ if (severity == REGULATOR_SEVERITY_PROT) {
+ reg = r->ocp_reg;
+ mask = r->ocp_mask;
+ if (r->ocw_rfet) {
+ range = voutS1_ocp_ranges;
+ num_ranges = ARRAY_SIZE(voutS1_ocp_ranges);
+ rfet = r->ocw_rfet / 1000;
+ } else {
+ range = voutS1_ocp_ranges_internal;
+ num_ranges = ARRAY_SIZE(voutS1_ocp_ranges_internal);
+ /* Internal values are already micro-amperes */
+ rfet = 1000;
+ }
+ } else {
+ reg = r->ocw_reg;
+ mask = r->ocw_mask;
+
+ if (r->ocw_rfet) {
+ range = voutS1_ocw_ranges;
+ num_ranges = ARRAY_SIZE(voutS1_ocw_ranges);
+ rfet = r->ocw_rfet / 1000;
+ } else {
+ range = voutS1_ocw_ranges_internal;
+ num_ranges = ARRAY_SIZE(voutS1_ocw_ranges_internal);
+ /* Internal values are already micro-amperes */
+ rfet = 1000;
+ }
+
+ /* We abuse uvd fields for OCW on VoutS1 */
+ if (r->uvd_notif) {
+ /*
+ * If both warning and error are requested, prioritize
+ * ERROR configuration
+ */
+ if (check_ocp_flag_mismatch(rdev, severity, r))
+ return 0;
+ } else {
+ bool warn = severity == REGULATOR_SEVERITY_WARN;
+
+ bd9576_fill_ocp_flags(r, warn);
+ }
+ }
+
+ /*
+ * limits are given in uA, rfet is mOhm
+ * Divide lim_uA by 1000 to get Vfet in uV.
+ * (We expect both Rfet and limit uA to be magnitude of hundreds of
+ * milli Amperes & milli Ohms => we should still have decent accuracy)
+ */
+ Vfet = lim_uA/1000 * rfet;
+
+ return bd9576_set_limit(range, num_ranges, d->regmap,
+ reg, mask, Vfet);
+}
+
+static int bd9576_set_uvp(struct regulator_dev *rdev, int lim_uV, int severity,
+ bool enable)
+{
+ struct bd957x_data *d;
+ struct bd957x_regulator_data *r;
+ int mask, reg;
+
+ if (severity == REGULATOR_SEVERITY_PROT) {
+ if (!enable || lim_uV)
+ return -EINVAL;
+ return 0;
+ }
+
+ /*
+ * BD9576 has enable control as a special value in limit reg. Can't
+ * set limit but keep feature disabled or enable W/O given limit.
+ */
+ if ((lim_uV && !enable) || (!lim_uV && enable))
+ return -EINVAL;
+
+ r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
+ d = rdev_get_drvdata(rdev);
+
+ mask = r->xvd_mask;
+ reg = r->uvd_reg;
+ /*
+ * Check that there is no mismatch for what the detection IRQs are to
+ * be used.
+ */
+ if (r->uvd_notif) {
+ if (check_uvd_flag_mismatch(rdev, severity, r))
+ return 0;
+ } else {
+ bd9576_fill_uvd_flags(r, severity == REGULATOR_SEVERITY_WARN);
+ }
+
+ return bd9576_set_limit(r->xvd_ranges, r->num_xvd_ranges, d->regmap,
+ reg, mask, lim_uV);
+}
+
+static int bd9576_set_ovp(struct regulator_dev *rdev, int lim_uV, int severity,
+ bool enable)
+{
+ struct bd957x_data *d;
+ struct bd957x_regulator_data *r;
+ int mask, reg;
+
+ if (severity == REGULATOR_SEVERITY_PROT) {
+ if (!enable || lim_uV)
+ return -EINVAL;
+ return 0;
+ }
+
+ /*
+ * BD9576 has enable control as a special value in limit reg. Can't
+ * set limit but keep feature disabled or enable W/O given limit.
+ */
+ if ((lim_uV && !enable) || (!lim_uV && enable))
+ return -EINVAL;
+
+ r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
+ d = rdev_get_drvdata(rdev);
+
+ mask = r->xvd_mask;
+ reg = r->ovd_reg;
+ /*
+ * Check that there is no mismatch for what the detection IRQs are to
+ * be used.
+ */
+ if (r->ovd_notif) {
+ if (check_ovd_flag_mismatch(rdev, severity, r))
+ return 0;
+ } else {
+ bd9576_fill_ovd_flags(r, severity == REGULATOR_SEVERITY_WARN);
+ }
+
+ return bd9576_set_limit(r->xvd_ranges, r->num_xvd_ranges, d->regmap,
+ reg, mask, lim_uV);
+}
+
+
+static int bd9576_set_tw(struct regulator_dev *rdev, int lim, int severity,
+ bool enable)
+{
+ struct bd957x_data *d;
+ struct bd957x_regulator_data *r;
+ int i;
+
+ /*
+ * BD9576MUF has fixed temperature limits
+ * The detection can only be enabled/disabled
+ */
+ if (lim)
+ return -EINVAL;
+
+ /* Protection can't be disabled */
+ if (severity == REGULATOR_SEVERITY_PROT) {
+ if (!enable)
+ return -EINVAL;
+ else
+ return 0;
+ }
+
+ r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
+ d = rdev_get_drvdata(rdev);
+
+ /*
+ * Check that there is no mismatch for what the detection IRQs are to
+ * be used.
+ */
+ if (r->temp_notif)
+ if (check_temp_flag_mismatch(rdev, severity, r))
+ return 0;
+
+ bd9576_fill_temp_flags(r, enable, severity == REGULATOR_SEVERITY_WARN);
+
+ if (enable)
+ return regmap_update_bits(d->regmap, BD957X_REG_INT_THERM_MASK,
+ BD9576_THERM_IRQ_MASK_TW, 0);
+
+ /*
+ * If any of the regulators is interested in thermal warning we keep IRQ
+ * enabled.
+ */
+ for (i = 0; i < BD9576_NUM_REGULATORS; i++)
+ if (d->regulator_data[i].temp_notif)
+ return 0;
+
+ return regmap_update_bits(d->regmap, BD957X_REG_INT_THERM_MASK,
+ BD9576_THERM_IRQ_MASK_TW,
+ BD9576_THERM_IRQ_MASK_TW);
+}
+
+static const struct regulator_ops bd9573_vout34_ops = {
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = bd957x_vout34_list_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
};
-static const struct regulator_ops bd957X_vouts1_regulator_ops = {
+static const struct regulator_ops bd9576_vout34_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = bd957x_vout34_list_voltage,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_over_voltage_protection = bd9576_set_ovp,
+ .set_under_voltage_protection = bd9576_set_uvp,
+ .set_thermal_protection = bd9576_set_tw,
+};
+
+static const struct regulator_ops bd9573_vouts1_regulator_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+static const struct regulator_ops bd9576_vouts1_regulator_ops = {
.is_enabled = regulator_is_enabled_regmap,
+ .set_over_current_protection = bd9576_set_ocp,
};
-static const struct regulator_ops bd957x_ops = {
+static const struct regulator_ops bd9573_ops = {
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = bd957x_list_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
};
-static struct bd957x_regulator_data bd9576_regulators[] = {
- {
- .desc = {
- .name = "VD50",
- .of_match = of_match_ptr("regulator-vd50"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD957X_VD50,
- .type = REGULATOR_VOLTAGE,
- .ops = &bd957x_ops,
- .volt_table = &vout1_volt_table[0],
- .n_voltages = ARRAY_SIZE(vout1_volt_table),
- .vsel_reg = BD957X_REG_VOUT1_TUNE,
- .vsel_mask = BD957X_MASK_VOUT1_TUNE,
- .enable_reg = BD957X_REG_POW_TRIGGER1,
- .enable_mask = BD957X_REGULATOR_EN_MASK,
- .enable_val = BD957X_REGULATOR_DIS_VAL,
- .enable_is_inverted = true,
- .owner = THIS_MODULE,
+static const struct regulator_ops bd9576_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = bd957x_list_voltage,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_over_voltage_protection = bd9576_set_ovp,
+ .set_under_voltage_protection = bd9576_set_uvp,
+ .set_thermal_protection = bd9576_set_tw,
+};
+
+static const struct regulator_ops *bd9573_ops_arr[] = {
+ [BD957X_VD50] = &bd9573_ops,
+ [BD957X_VD18] = &bd9573_ops,
+ [BD957X_VDDDR] = &bd9573_vout34_ops,
+ [BD957X_VD10] = &bd9573_vout34_ops,
+ [BD957X_VOUTL1] = &bd9573_ops,
+ [BD957X_VOUTS1] = &bd9573_vouts1_regulator_ops,
+};
+
+static const struct regulator_ops *bd9576_ops_arr[] = {
+ [BD957X_VD50] = &bd9576_ops,
+ [BD957X_VD18] = &bd9576_ops,
+ [BD957X_VDDDR] = &bd9576_vout34_ops,
+ [BD957X_VD10] = &bd9576_vout34_ops,
+ [BD957X_VOUTL1] = &bd9576_ops,
+ [BD957X_VOUTS1] = &bd9576_vouts1_regulator_ops,
+};
+
+static int vouts1_get_fet_res(struct device_node *np,
+ const struct regulator_desc *desc,
+ struct regulator_config *cfg)
+{
+ struct bd957x_regulator_data *data;
+ int ret;
+ u32 uohms;
+
+ data = container_of(desc, struct bd957x_regulator_data, desc);
+
+ ret = of_property_read_u32(np, "rohm,ocw-fet-ron-micro-ohms", &uohms);
+ if (ret) {
+ if (ret != -EINVAL)
+ return ret;
+
+ return 0;
+ }
+ data->ocw_rfet = uohms;
+ return 0;
+}
+
+static struct bd957x_data bd957x_regulators = {
+ .regulator_data = {
+ {
+ .desc = {
+ .name = "VD50",
+ .of_match = of_match_ptr("regulator-vd50"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD957X_VD50,
+ .type = REGULATOR_VOLTAGE,
+ .volt_table = &vout1_volt_table[0],
+ .n_voltages = ARRAY_SIZE(vout1_volt_table),
+ .vsel_reg = BD957X_REG_VOUT1_TUNE,
+ .vsel_mask = BD957X_MASK_VOUT1_TUNE,
+ .enable_reg = BD957X_REG_POW_TRIGGER1,
+ .enable_mask = BD957X_REGULATOR_EN_MASK,
+ .enable_val = BD957X_REGULATOR_DIS_VAL,
+ .enable_is_inverted = true,
+ .owner = THIS_MODULE,
+ },
+ .xvd_ranges = vout1_xvd_ranges,
+ .num_xvd_ranges = ARRAY_SIZE(vout1_xvd_ranges),
+ .ovd_reg = BD9576_REG_VOUT1_OVD,
+ .uvd_reg = BD9576_REG_VOUT1_UVD,
+ .xvd_mask = BD9576_MASK_XVD,
},
- },
- {
- .desc = {
- .name = "VD18",
- .of_match = of_match_ptr("regulator-vd18"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD957X_VD18,
- .type = REGULATOR_VOLTAGE,
- .ops = &bd957x_ops,
- .volt_table = &vout2_volt_table[0],
- .n_voltages = ARRAY_SIZE(vout2_volt_table),
- .vsel_reg = BD957X_REG_VOUT2_TUNE,
- .vsel_mask = BD957X_MASK_VOUT2_TUNE,
- .enable_reg = BD957X_REG_POW_TRIGGER2,
- .enable_mask = BD957X_REGULATOR_EN_MASK,
- .enable_val = BD957X_REGULATOR_DIS_VAL,
- .enable_is_inverted = true,
- .owner = THIS_MODULE,
+ {
+ .desc = {
+ .name = "VD18",
+ .of_match = of_match_ptr("regulator-vd18"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD957X_VD18,
+ .type = REGULATOR_VOLTAGE,
+ .volt_table = &vout2_volt_table[0],
+ .n_voltages = ARRAY_SIZE(vout2_volt_table),
+ .vsel_reg = BD957X_REG_VOUT2_TUNE,
+ .vsel_mask = BD957X_MASK_VOUT2_TUNE,
+ .enable_reg = BD957X_REG_POW_TRIGGER2,
+ .enable_mask = BD957X_REGULATOR_EN_MASK,
+ .enable_val = BD957X_REGULATOR_DIS_VAL,
+ .enable_is_inverted = true,
+ .owner = THIS_MODULE,
+ },
+ .xvd_ranges = vout234_xvd_ranges,
+ .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges),
+ .ovd_reg = BD9576_REG_VOUT2_OVD,
+ .uvd_reg = BD9576_REG_VOUT2_UVD,
+ .xvd_mask = BD9576_MASK_XVD,
},
- },
- {
- .desc = {
- .name = "VDDDR",
- .of_match = of_match_ptr("regulator-vdddr"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD957X_VDDDR,
- .ops = &bd957x_vout34_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD957X_VOUTS34_NUM_VOLT,
- .vsel_reg = BD957X_REG_VOUT3_TUNE,
- .vsel_mask = BD957X_MASK_VOUT3_TUNE,
- .enable_reg = BD957X_REG_POW_TRIGGER3,
- .enable_mask = BD957X_REGULATOR_EN_MASK,
- .enable_val = BD957X_REGULATOR_DIS_VAL,
- .enable_is_inverted = true,
- .owner = THIS_MODULE,
+ {
+ .desc = {
+ .name = "VDDDR",
+ .of_match = of_match_ptr("regulator-vdddr"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD957X_VDDDR,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD957X_VOUTS34_NUM_VOLT,
+ .vsel_reg = BD957X_REG_VOUT3_TUNE,
+ .vsel_mask = BD957X_MASK_VOUT3_TUNE,
+ .enable_reg = BD957X_REG_POW_TRIGGER3,
+ .enable_mask = BD957X_REGULATOR_EN_MASK,
+ .enable_val = BD957X_REGULATOR_DIS_VAL,
+ .enable_is_inverted = true,
+ .owner = THIS_MODULE,
+ },
+ .ovd_reg = BD9576_REG_VOUT3_OVD,
+ .uvd_reg = BD9576_REG_VOUT3_UVD,
+ .xvd_mask = BD9576_MASK_XVD,
+ .xvd_ranges = vout234_xvd_ranges,
+ .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges),
},
- },
- {
- .desc = {
- .name = "VD10",
- .of_match = of_match_ptr("regulator-vd10"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD957X_VD10,
- .ops = &bd957x_vout34_ops,
- .type = REGULATOR_VOLTAGE,
- .fixed_uV = BD957X_VOUTS4_BASE_VOLT,
- .n_voltages = BD957X_VOUTS34_NUM_VOLT,
- .vsel_reg = BD957X_REG_VOUT4_TUNE,
- .vsel_mask = BD957X_MASK_VOUT4_TUNE,
- .enable_reg = BD957X_REG_POW_TRIGGER4,
- .enable_mask = BD957X_REGULATOR_EN_MASK,
- .enable_val = BD957X_REGULATOR_DIS_VAL,
- .enable_is_inverted = true,
- .owner = THIS_MODULE,
+ {
+ .desc = {
+ .name = "VD10",
+ .of_match = of_match_ptr("regulator-vd10"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD957X_VD10,
+ .type = REGULATOR_VOLTAGE,
+ .fixed_uV = BD957X_VOUTS4_BASE_VOLT,
+ .n_voltages = BD957X_VOUTS34_NUM_VOLT,
+ .vsel_reg = BD957X_REG_VOUT4_TUNE,
+ .vsel_mask = BD957X_MASK_VOUT4_TUNE,
+ .enable_reg = BD957X_REG_POW_TRIGGER4,
+ .enable_mask = BD957X_REGULATOR_EN_MASK,
+ .enable_val = BD957X_REGULATOR_DIS_VAL,
+ .enable_is_inverted = true,
+ .owner = THIS_MODULE,
+ },
+ .xvd_ranges = vout234_xvd_ranges,
+ .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges),
+ .ovd_reg = BD9576_REG_VOUT4_OVD,
+ .uvd_reg = BD9576_REG_VOUT4_UVD,
+ .xvd_mask = BD9576_MASK_XVD,
},
- },
- {
- .desc = {
- .name = "VOUTL1",
- .of_match = of_match_ptr("regulator-voutl1"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD957X_VOUTL1,
- .ops = &bd957x_ops,
- .type = REGULATOR_VOLTAGE,
- .volt_table = &voutl1_volt_table[0],
- .n_voltages = ARRAY_SIZE(voutl1_volt_table),
- .vsel_reg = BD957X_REG_VOUTL1_TUNE,
- .vsel_mask = BD957X_MASK_VOUTL1_TUNE,
- .enable_reg = BD957X_REG_POW_TRIGGERL1,
- .enable_mask = BD957X_REGULATOR_EN_MASK,
- .enable_val = BD957X_REGULATOR_DIS_VAL,
- .enable_is_inverted = true,
- .owner = THIS_MODULE,
+ {
+ .desc = {
+ .name = "VOUTL1",
+ .of_match = of_match_ptr("regulator-voutl1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD957X_VOUTL1,
+ .type = REGULATOR_VOLTAGE,
+ .volt_table = &voutl1_volt_table[0],
+ .n_voltages = ARRAY_SIZE(voutl1_volt_table),
+ .vsel_reg = BD957X_REG_VOUTL1_TUNE,
+ .vsel_mask = BD957X_MASK_VOUTL1_TUNE,
+ .enable_reg = BD957X_REG_POW_TRIGGERL1,
+ .enable_mask = BD957X_REGULATOR_EN_MASK,
+ .enable_val = BD957X_REGULATOR_DIS_VAL,
+ .enable_is_inverted = true,
+ .owner = THIS_MODULE,
+ },
+ .xvd_ranges = voutL1_xvd_ranges,
+ .num_xvd_ranges = ARRAY_SIZE(voutL1_xvd_ranges),
+ .ovd_reg = BD9576_REG_VOUTL1_OVD,
+ .uvd_reg = BD9576_REG_VOUTL1_UVD,
+ .xvd_mask = BD9576_MASK_XVD,
},
- },
- {
- .desc = {
- .name = "VOUTS1",
- .of_match = of_match_ptr("regulator-vouts1"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD957X_VOUTS1,
- .ops = &bd957X_vouts1_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = 1,
- .fixed_uV = BD957X_VOUTS1_VOLT,
- .enable_reg = BD957X_REG_POW_TRIGGERS1,
- .enable_mask = BD957X_REGULATOR_EN_MASK,
- .enable_val = BD957X_REGULATOR_DIS_VAL,
- .enable_is_inverted = true,
- .owner = THIS_MODULE,
+ {
+ .desc = {
+ .name = "VOUTS1",
+ .of_match = of_match_ptr("regulator-vouts1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD957X_VOUTS1,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 1,
+ .fixed_uV = BD957X_VOUTS1_VOLT,
+ .enable_reg = BD957X_REG_POW_TRIGGERS1,
+ .enable_mask = BD957X_REGULATOR_EN_MASK,
+ .enable_val = BD957X_REGULATOR_DIS_VAL,
+ .enable_is_inverted = true,
+ .owner = THIS_MODULE,
+ .of_parse_cb = vouts1_get_fet_res,
+ },
+ .oc_supported = true,
+ .ocw_reg = BD9576_REG_VOUT1S_OCW,
+ .ocw_mask = BD9576_MASK_VOUT1S_OCW,
+ .ocp_reg = BD9576_REG_VOUT1S_OCP,
+ .ocp_mask = BD9576_MASK_VOUT1S_OCP,
},
},
};
+static int bd9576_renable(struct regulator_irq_data *rid, int reg, int mask)
+{
+ int val, ret;
+ struct bd957x_data *d = (struct bd957x_data *)rid->data;
+
+ ret = regmap_read(d->regmap, reg, &val);
+ if (ret)
+ return REGULATOR_FAILED_RETRY;
+
+ if (rid->opaque && rid->opaque == (val & mask)) {
+ /*
+ * It seems we stil have same status. Ack and return
+ * information that we are still out of limits and core
+ * should not enable IRQ
+ */
+ regmap_write(d->regmap, reg, mask & val);
+ return REGULATOR_ERROR_ON;
+ }
+ rid->opaque = 0;
+ /*
+ * Status was changed. Either prolem was solved or we have new issues.
+ * Let's re-enable IRQs and be prepared to report problems again
+ */
+ return REGULATOR_ERROR_CLEARED;
+}
+
+static int bd9576_uvd_renable(struct regulator_irq_data *rid)
+{
+ return bd9576_renable(rid, BD957X_REG_INT_UVD_STAT, UVD_IRQ_VALID_MASK);
+}
+
+static int bd9576_ovd_renable(struct regulator_irq_data *rid)
+{
+ return bd9576_renable(rid, BD957X_REG_INT_OVD_STAT, OVD_IRQ_VALID_MASK);
+}
+
+static int bd9576_temp_renable(struct regulator_irq_data *rid)
+{
+ return bd9576_renable(rid, BD957X_REG_INT_THERM_STAT,
+ BD9576_THERM_IRQ_MASK_TW);
+}
+
+static int bd9576_uvd_handler(int irq, struct regulator_irq_data *rid,
+ unsigned long *dev_mask)
+{
+ int val, ret, i;
+ struct bd957x_data *d = (struct bd957x_data *)rid->data;
+
+ ret = regmap_read(d->regmap, BD957X_REG_INT_UVD_STAT, &val);
+ if (ret)
+ return REGULATOR_FAILED_RETRY;
+
+ *dev_mask = 0;
+
+ rid->opaque = val & UVD_IRQ_VALID_MASK;
+
+ /*
+ * Go through the set status bits and report either error or warning
+ * to the notifier depending on what was flagged in DT
+ */
+ *dev_mask = val & BD9576_xVD_IRQ_MASK_VOUT1TO4;
+ /* There is 1 bit gap in register after Vout1 .. Vout4 statuses */
+ *dev_mask |= ((val & BD9576_xVD_IRQ_MASK_VOUTL1) >> 1);
+ /*
+ * We (ab)use the uvd for OCW notification. DT parsing should
+ * have added correct OCW flag to uvd_notif and uvd_err for S1
+ */
+ *dev_mask |= ((val & BD9576_UVD_IRQ_MASK_VOUTS1_OCW) >> 1);
+
+ for_each_set_bit(i, dev_mask, 6) {
+ struct bd957x_regulator_data *rdata;
+ struct regulator_err_state *stat;
+
+ rdata = &d->regulator_data[i];
+ stat = &rid->states[i];
+
+ stat->notifs = rdata->uvd_notif;
+ stat->errors = rdata->uvd_err;
+ }
+
+ ret = regmap_write(d->regmap, BD957X_REG_INT_UVD_STAT,
+ UVD_IRQ_VALID_MASK & val);
+
+ return 0;
+}
+
+static int bd9576_ovd_handler(int irq, struct regulator_irq_data *rid,
+ unsigned long *dev_mask)
+{
+ int val, ret, i;
+ struct bd957x_data *d = (struct bd957x_data *)rid->data;
+
+ ret = regmap_read(d->regmap, BD957X_REG_INT_OVD_STAT, &val);
+ if (ret)
+ return REGULATOR_FAILED_RETRY;
+
+ rid->opaque = val & OVD_IRQ_VALID_MASK;
+ *dev_mask = 0;
+
+ if (!(val & OVD_IRQ_VALID_MASK))
+ return 0;
+
+ *dev_mask = val & BD9576_xVD_IRQ_MASK_VOUT1TO4;
+ /* There is 1 bit gap in register after Vout1 .. Vout4 statuses */
+ *dev_mask |= ((val & BD9576_xVD_IRQ_MASK_VOUTL1) >> 1);
+
+ for_each_set_bit(i, dev_mask, 5) {
+ struct bd957x_regulator_data *rdata;
+ struct regulator_err_state *stat;
+
+ rdata = &d->regulator_data[i];
+ stat = &rid->states[i];
+
+ stat->notifs = rdata->ovd_notif;
+ stat->errors = rdata->ovd_err;
+ }
+
+ /* Clear the sub-IRQ status */
+ regmap_write(d->regmap, BD957X_REG_INT_OVD_STAT,
+ OVD_IRQ_VALID_MASK & val);
+
+ return 0;
+}
+
+#define BD9576_DEV_MASK_ALL_REGULATORS 0x3F
+
+static int bd9576_thermal_handler(int irq, struct regulator_irq_data *rid,
+ unsigned long *dev_mask)
+{
+ int val, ret, i;
+ struct bd957x_data *d = (struct bd957x_data *)rid->data;
+
+ ret = regmap_read(d->regmap, BD957X_REG_INT_THERM_STAT, &val);
+ if (ret)
+ return REGULATOR_FAILED_RETRY;
+
+ if (!(val & BD9576_THERM_IRQ_MASK_TW)) {
+ *dev_mask = 0;
+ return 0;
+ }
+
+ *dev_mask = BD9576_DEV_MASK_ALL_REGULATORS;
+
+ for (i = 0; i < BD9576_NUM_REGULATORS; i++) {
+ struct bd957x_regulator_data *rdata;
+ struct regulator_err_state *stat;
+
+ rdata = &d->regulator_data[i];
+ stat = &rid->states[i];
+
+ stat->notifs = rdata->temp_notif;
+ stat->errors = rdata->temp_err;
+ }
+
+ /* Clear the sub-IRQ status */
+ regmap_write(d->regmap, BD957X_REG_INT_THERM_STAT,
+ BD9576_THERM_IRQ_MASK_TW);
+
+ return 0;
+}
+
static int bd957x_probe(struct platform_device *pdev)
{
+ int i;
+ unsigned int num_reg_data;
+ bool vout_mode, ddr_sel, may_have_irqs = false;
struct regmap *regmap;
+ struct bd957x_data *ic_data;
struct regulator_config config = { 0 };
- int i;
- bool vout_mode, ddr_sel;
- const struct bd957x_regulator_data *reg_data = &bd9576_regulators[0];
- unsigned int num_reg_data = ARRAY_SIZE(bd9576_regulators);
+ /* All regulators are related to UVD and thermal IRQs... */
+ struct regulator_dev *rdevs[BD9576_NUM_REGULATORS];
+ /* ...But VoutS1 is not flagged by OVD IRQ */
+ struct regulator_dev *ovd_devs[BD9576_NUM_OVD_REGULATORS];
+ static const struct regulator_irq_desc bd9576_notif_uvd = {
+ .name = "bd9576-uvd",
+ .irq_off_ms = 1000,
+ .map_event = bd9576_uvd_handler,
+ .renable = bd9576_uvd_renable,
+ .data = &bd957x_regulators,
+ };
+ static const struct regulator_irq_desc bd9576_notif_ovd = {
+ .name = "bd9576-ovd",
+ .irq_off_ms = 1000,
+ .map_event = bd9576_ovd_handler,
+ .renable = bd9576_ovd_renable,
+ .data = &bd957x_regulators,
+ };
+ static const struct regulator_irq_desc bd9576_notif_temp = {
+ .name = "bd9576-temp",
+ .irq_off_ms = 1000,
+ .map_event = bd9576_thermal_handler,
+ .renable = bd9576_temp_renable,
+ .data = &bd957x_regulators,
+ };
enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
+ num_reg_data = ARRAY_SIZE(bd957x_regulators.regulator_data);
+
+ ic_data = &bd957x_regulators;
+
regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!regmap) {
dev_err(&pdev->dev, "No regmap\n");
return -EINVAL;
}
+
+ ic_data->regmap = regmap;
vout_mode = of_property_read_bool(pdev->dev.parent->of_node,
"rohm,vout1-en-low");
if (vout_mode) {
@@ -263,15 +985,17 @@ static int bd957x_probe(struct platform_device *pdev)
* bytes and use bd9576_regulators directly for non-constant configs
* like DDR voltage selection.
*/
+ platform_set_drvdata(pdev, ic_data);
ddr_sel = of_property_read_bool(pdev->dev.parent->of_node,
"rohm,ddr-sel-low");
if (ddr_sel)
- bd9576_regulators[2].desc.fixed_uV = 1350000;
+ ic_data->regulator_data[2].desc.fixed_uV = 1350000;
else
- bd9576_regulators[2].desc.fixed_uV = 1500000;
+ ic_data->regulator_data[2].desc.fixed_uV = 1500000;
switch (chip) {
case ROHM_CHIP_TYPE_BD9576:
+ may_have_irqs = true;
dev_dbg(&pdev->dev, "Found BD9576MUF\n");
break;
case ROHM_CHIP_TYPE_BD9573:
@@ -282,38 +1006,122 @@ static int bd957x_probe(struct platform_device *pdev)
return -EINVAL;
}
+ for (i = 0; i < num_reg_data; i++) {
+ struct regulator_desc *d;
+
+ d = &ic_data->regulator_data[i].desc;
+
+
+ if (may_have_irqs) {
+ if (d->id >= ARRAY_SIZE(bd9576_ops_arr))
+ return -EINVAL;
+
+ d->ops = bd9576_ops_arr[d->id];
+ } else {
+ if (d->id >= ARRAY_SIZE(bd9573_ops_arr))
+ return -EINVAL;
+
+ d->ops = bd9573_ops_arr[d->id];
+ }
+ }
+
config.dev = pdev->dev.parent;
config.regmap = regmap;
+ config.driver_data = ic_data;
for (i = 0; i < num_reg_data; i++) {
- const struct regulator_desc *desc;
- struct regulator_dev *rdev;
- const struct bd957x_regulator_data *r;
-
- r = &reg_data[i];
- desc = &r->desc;
+ struct bd957x_regulator_data *r = &ic_data->regulator_data[i];
+ const struct regulator_desc *desc = &r->desc;
- rdev = devm_regulator_register(&pdev->dev, desc, &config);
- if (IS_ERR(rdev)) {
+ r->rdev = devm_regulator_register(&pdev->dev, desc,
+ &config);
+ if (IS_ERR(r->rdev)) {
dev_err(&pdev->dev,
"failed to register %s regulator\n",
desc->name);
- return PTR_ERR(rdev);
+ return PTR_ERR(r->rdev);
}
/*
* Clear the VOUT1 GPIO setting - rest of the regulators do not
* support GPIO control
*/
config.ena_gpiod = NULL;
+
+ if (!may_have_irqs)
+ continue;
+
+ rdevs[i] = r->rdev;
+ if (i < BD957X_VOUTS1)
+ ovd_devs[i] = r->rdev;
}
+ if (may_have_irqs) {
+ void *ret;
+ /*
+ * We can add both the possible error and warning flags here
+ * because the core uses these only for status clearing and
+ * if we use warnings - errors are always clear and the other
+ * way around. We can also add CURRENT flag for all regulators
+ * because it is never set if it is not supported. Same applies
+ * to setting UVD for VoutS1 - it is not accidentally cleared
+ * as it is never set.
+ */
+ int uvd_errs = REGULATOR_ERROR_UNDER_VOLTAGE |
+ REGULATOR_ERROR_UNDER_VOLTAGE_WARN |
+ REGULATOR_ERROR_OVER_CURRENT |
+ REGULATOR_ERROR_OVER_CURRENT_WARN;
+ int ovd_errs = REGULATOR_ERROR_OVER_VOLTAGE_WARN |
+ REGULATOR_ERROR_REGULATION_OUT;
+ int temp_errs = REGULATOR_ERROR_OVER_TEMP |
+ REGULATOR_ERROR_OVER_TEMP_WARN;
+ int irq;
+
+ irq = platform_get_irq_byname(pdev, "bd9576-uvd");
+ /* Register notifiers - can fail if IRQ is not given */
+ ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_uvd,
+ irq, 0, uvd_errs, NULL,
+ &rdevs[0],
+ BD9576_NUM_REGULATORS);
+ if (IS_ERR(ret)) {
+ if (PTR_ERR(ret) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ dev_warn(&pdev->dev, "UVD disabled %pe\n", ret);
+ }
+
+ irq = platform_get_irq_byname(pdev, "bd9576-ovd");
+
+ ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_ovd,
+ irq, 0, ovd_errs, NULL,
+ &ovd_devs[0],
+ BD9576_NUM_OVD_REGULATORS);
+ if (IS_ERR(ret)) {
+ if (PTR_ERR(ret) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ dev_warn(&pdev->dev, "OVD disabled %pe\n", ret);
+ }
+ irq = platform_get_irq_byname(pdev, "bd9576-temp");
+
+ ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_temp,
+ irq, 0, temp_errs, NULL,
+ &rdevs[0],
+ BD9576_NUM_REGULATORS);
+ if (IS_ERR(ret)) {
+ if (PTR_ERR(ret) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ dev_warn(&pdev->dev, "Thermal warning disabled %pe\n",
+ ret);
+ }
+ }
return 0;
}
static const struct platform_device_id bd957x_pmic_id[] = {
- { "bd9573-pmic", ROHM_CHIP_TYPE_BD9573 },
- { "bd9576-pmic", ROHM_CHIP_TYPE_BD9576 },
+ { "bd9573-regulator", ROHM_CHIP_TYPE_BD9573 },
+ { "bd9576-regulator", ROHM_CHIP_TYPE_BD9576 },
{ },
};
MODULE_DEVICE_TABLE(platform, bd957x_pmic_id);
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index e20e77e4c159..ca6caba8a191 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -33,17 +33,6 @@
#include "dummy.h"
#include "internal.h"
-#define rdev_crit(rdev, fmt, ...) \
- pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
-#define rdev_err(rdev, fmt, ...) \
- pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
-#define rdev_warn(rdev, fmt, ...) \
- pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
-#define rdev_info(rdev, fmt, ...) \
- pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
-#define rdev_dbg(rdev, fmt, ...) \
- pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
-
static DEFINE_WW_CLASS(regulator_ww_class);
static DEFINE_MUTEX(regulator_nesting_mutex);
static DEFINE_MUTEX(regulator_list_mutex);
@@ -117,6 +106,7 @@ const char *rdev_get_name(struct regulator_dev *rdev)
else
return "";
}
+EXPORT_SYMBOL_GPL(rdev_get_name);
static bool have_full_constraints(void)
{
@@ -591,8 +581,8 @@ regulator_get_suspend_state_check(struct regulator_dev *rdev, suspend_state_t st
return rstate;
}
-static ssize_t regulator_uV_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t microvolts_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
int uV;
@@ -605,16 +595,16 @@ static ssize_t regulator_uV_show(struct device *dev,
return uV;
return sprintf(buf, "%d\n", uV);
}
-static DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL);
+static DEVICE_ATTR_RO(microvolts);
-static ssize_t regulator_uA_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t microamps_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev));
}
-static DEVICE_ATTR(microamps, 0444, regulator_uA_show, NULL);
+static DEVICE_ATTR_RO(microamps);
static ssize_t name_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -645,14 +635,14 @@ static ssize_t regulator_print_opmode(char *buf, int mode)
return sprintf(buf, "%s\n", regulator_opmode_to_str(mode));
}
-static ssize_t regulator_opmode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t opmode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
return regulator_print_opmode(buf, _regulator_get_mode(rdev));
}
-static DEVICE_ATTR(opmode, 0444, regulator_opmode_show, NULL);
+static DEVICE_ATTR_RO(opmode);
static ssize_t regulator_print_state(char *buf, int state)
{
@@ -664,8 +654,8 @@ static ssize_t regulator_print_state(char *buf, int state)
return sprintf(buf, "unknown\n");
}
-static ssize_t regulator_state_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
ssize_t ret;
@@ -676,10 +666,10 @@ static ssize_t regulator_state_show(struct device *dev,
return ret;
}
-static DEVICE_ATTR(state, 0444, regulator_state_show, NULL);
+static DEVICE_ATTR_RO(state);
-static ssize_t regulator_status_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
int status;
@@ -723,10 +713,10 @@ static ssize_t regulator_status_show(struct device *dev,
return sprintf(buf, "%s\n", label);
}
-static DEVICE_ATTR(status, 0444, regulator_status_show, NULL);
+static DEVICE_ATTR_RO(status);
-static ssize_t regulator_min_uA_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t min_microamps_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
@@ -735,10 +725,10 @@ static ssize_t regulator_min_uA_show(struct device *dev,
return sprintf(buf, "%d\n", rdev->constraints->min_uA);
}
-static DEVICE_ATTR(min_microamps, 0444, regulator_min_uA_show, NULL);
+static DEVICE_ATTR_RO(min_microamps);
-static ssize_t regulator_max_uA_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t max_microamps_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
@@ -747,10 +737,10 @@ static ssize_t regulator_max_uA_show(struct device *dev,
return sprintf(buf, "%d\n", rdev->constraints->max_uA);
}
-static DEVICE_ATTR(max_microamps, 0444, regulator_max_uA_show, NULL);
+static DEVICE_ATTR_RO(max_microamps);
-static ssize_t regulator_min_uV_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t min_microvolts_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
@@ -759,10 +749,10 @@ static ssize_t regulator_min_uV_show(struct device *dev,
return sprintf(buf, "%d\n", rdev->constraints->min_uV);
}
-static DEVICE_ATTR(min_microvolts, 0444, regulator_min_uV_show, NULL);
+static DEVICE_ATTR_RO(min_microvolts);
-static ssize_t regulator_max_uV_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t max_microvolts_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
@@ -771,10 +761,10 @@ static ssize_t regulator_max_uV_show(struct device *dev,
return sprintf(buf, "%d\n", rdev->constraints->max_uV);
}
-static DEVICE_ATTR(max_microvolts, 0444, regulator_max_uV_show, NULL);
+static DEVICE_ATTR_RO(max_microvolts);
-static ssize_t regulator_total_uA_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t requested_microamps_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
struct regulator *regulator;
@@ -788,7 +778,7 @@ static ssize_t regulator_total_uA_show(struct device *dev,
regulator_unlock(rdev);
return sprintf(buf, "%d\n", uA);
}
-static DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL);
+static DEVICE_ATTR_RO(requested_microamps);
static ssize_t num_users_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -813,104 +803,95 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(type);
-static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t suspend_mem_microvolts_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", rdev->constraints->state_mem.uV);
}
-static DEVICE_ATTR(suspend_mem_microvolts, 0444,
- regulator_suspend_mem_uV_show, NULL);
+static DEVICE_ATTR_RO(suspend_mem_microvolts);
-static ssize_t regulator_suspend_disk_uV_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t suspend_disk_microvolts_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", rdev->constraints->state_disk.uV);
}
-static DEVICE_ATTR(suspend_disk_microvolts, 0444,
- regulator_suspend_disk_uV_show, NULL);
+static DEVICE_ATTR_RO(suspend_disk_microvolts);
-static ssize_t regulator_suspend_standby_uV_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t suspend_standby_microvolts_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", rdev->constraints->state_standby.uV);
}
-static DEVICE_ATTR(suspend_standby_microvolts, 0444,
- regulator_suspend_standby_uV_show, NULL);
+static DEVICE_ATTR_RO(suspend_standby_microvolts);
-static ssize_t regulator_suspend_mem_mode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t suspend_mem_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
return regulator_print_opmode(buf,
rdev->constraints->state_mem.mode);
}
-static DEVICE_ATTR(suspend_mem_mode, 0444,
- regulator_suspend_mem_mode_show, NULL);
+static DEVICE_ATTR_RO(suspend_mem_mode);
-static ssize_t regulator_suspend_disk_mode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t suspend_disk_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
return regulator_print_opmode(buf,
rdev->constraints->state_disk.mode);
}
-static DEVICE_ATTR(suspend_disk_mode, 0444,
- regulator_suspend_disk_mode_show, NULL);
+static DEVICE_ATTR_RO(suspend_disk_mode);
-static ssize_t regulator_suspend_standby_mode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t suspend_standby_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
return regulator_print_opmode(buf,
rdev->constraints->state_standby.mode);
}
-static DEVICE_ATTR(suspend_standby_mode, 0444,
- regulator_suspend_standby_mode_show, NULL);
+static DEVICE_ATTR_RO(suspend_standby_mode);
-static ssize_t regulator_suspend_mem_state_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t suspend_mem_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
return regulator_print_state(buf,
rdev->constraints->state_mem.enabled);
}
-static DEVICE_ATTR(suspend_mem_state, 0444,
- regulator_suspend_mem_state_show, NULL);
+static DEVICE_ATTR_RO(suspend_mem_state);
-static ssize_t regulator_suspend_disk_state_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t suspend_disk_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
return regulator_print_state(buf,
rdev->constraints->state_disk.enabled);
}
-static DEVICE_ATTR(suspend_disk_state, 0444,
- regulator_suspend_disk_state_show, NULL);
+static DEVICE_ATTR_RO(suspend_disk_state);
-static ssize_t regulator_suspend_standby_state_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t suspend_standby_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
return regulator_print_state(buf,
rdev->constraints->state_standby.enabled);
}
-static DEVICE_ATTR(suspend_standby_state, 0444,
- regulator_suspend_standby_state_show, NULL);
+static DEVICE_ATTR_RO(suspend_standby_state);
-static ssize_t regulator_bypass_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t bypass_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
const char *report;
@@ -928,8 +909,7 @@ static ssize_t regulator_bypass_show(struct device *dev,
return sprintf(buf, "%s\n", report);
}
-static DEVICE_ATTR(bypass, 0444,
- regulator_bypass_show, NULL);
+static DEVICE_ATTR_RO(bypass);
/* Calculate the new optimum regulator operating mode based on the new total
* consumer load. All locks held by caller
@@ -1315,6 +1295,52 @@ static int machine_constraints_current(struct regulator_dev *rdev,
static int _regulator_do_enable(struct regulator_dev *rdev);
+static int notif_set_limit(struct regulator_dev *rdev,
+ int (*set)(struct regulator_dev *, int, int, bool),
+ int limit, int severity)
+{
+ bool enable;
+
+ if (limit == REGULATOR_NOTIF_LIMIT_DISABLE) {
+ enable = false;
+ limit = 0;
+ } else {
+ enable = true;
+ }
+
+ if (limit == REGULATOR_NOTIF_LIMIT_ENABLE)
+ limit = 0;
+
+ return set(rdev, limit, severity, enable);
+}
+
+static int handle_notify_limits(struct regulator_dev *rdev,
+ int (*set)(struct regulator_dev *, int, int, bool),
+ struct notification_limit *limits)
+{
+ int ret = 0;
+
+ if (!set)
+ return -EOPNOTSUPP;
+
+ if (limits->prot)
+ ret = notif_set_limit(rdev, set, limits->prot,
+ REGULATOR_SEVERITY_PROT);
+ if (ret)
+ return ret;
+
+ if (limits->err)
+ ret = notif_set_limit(rdev, set, limits->err,
+ REGULATOR_SEVERITY_ERR);
+ if (ret)
+ return ret;
+
+ if (limits->warn)
+ ret = notif_set_limit(rdev, set, limits->warn,
+ REGULATOR_SEVERITY_WARN);
+
+ return ret;
+}
/**
* set_machine_constraints - sets regulator constraints
* @rdev: regulator source
@@ -1400,9 +1426,27 @@ static int set_machine_constraints(struct regulator_dev *rdev)
}
}
+ /*
+ * Existing logic does not warn if over_current_protection is given as
+ * a constraint but driver does not support that. I think we should
+ * warn about this type of issues as it is possible someone changes
+ * PMIC on board to another type - and the another PMIC's driver does
+ * not support setting protection. Board composer may happily believe
+ * the DT limits are respected - especially if the new PMIC HW also
+ * supports protection but the driver does not. I won't change the logic
+ * without hearing more experienced opinion on this though.
+ *
+ * If warning is seen as a good idea then we can merge handling the
+ * over-curret protection and detection and get rid of this special
+ * handling.
+ */
if (rdev->constraints->over_current_protection
&& ops->set_over_current_protection) {
- ret = ops->set_over_current_protection(rdev);
+ int lim = rdev->constraints->over_curr_limits.prot;
+
+ ret = ops->set_over_current_protection(rdev, lim,
+ REGULATOR_SEVERITY_PROT,
+ true);
if (ret < 0) {
rdev_err(rdev, "failed to set over current protection: %pe\n",
ERR_PTR(ret));
@@ -1410,6 +1454,62 @@ static int set_machine_constraints(struct regulator_dev *rdev)
}
}
+ if (rdev->constraints->over_current_detection)
+ ret = handle_notify_limits(rdev,
+ ops->set_over_current_protection,
+ &rdev->constraints->over_curr_limits);
+ if (ret) {
+ if (ret != -EOPNOTSUPP) {
+ rdev_err(rdev, "failed to set over current limits: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+ rdev_warn(rdev,
+ "IC does not support requested over-current limits\n");
+ }
+
+ if (rdev->constraints->over_voltage_detection)
+ ret = handle_notify_limits(rdev,
+ ops->set_over_voltage_protection,
+ &rdev->constraints->over_voltage_limits);
+ if (ret) {
+ if (ret != -EOPNOTSUPP) {
+ rdev_err(rdev, "failed to set over voltage limits %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+ rdev_warn(rdev,
+ "IC does not support requested over voltage limits\n");
+ }
+
+ if (rdev->constraints->under_voltage_detection)
+ ret = handle_notify_limits(rdev,
+ ops->set_under_voltage_protection,
+ &rdev->constraints->under_voltage_limits);
+ if (ret) {
+ if (ret != -EOPNOTSUPP) {
+ rdev_err(rdev, "failed to set under voltage limits %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+ rdev_warn(rdev,
+ "IC does not support requested under voltage limits\n");
+ }
+
+ if (rdev->constraints->over_temp_detection)
+ ret = handle_notify_limits(rdev,
+ ops->set_thermal_protection,
+ &rdev->constraints->temp_limits);
+ if (ret) {
+ if (ret != -EOPNOTSUPP) {
+ rdev_err(rdev, "failed to set temperature limits %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+ rdev_warn(rdev,
+ "IC does not support requested temperature limits\n");
+ }
+
if (rdev->constraints->active_discharge && ops->set_active_discharge) {
bool ad_state = (rdev->constraints->active_discharge ==
REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false;
@@ -4111,6 +4211,29 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
}
EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel);
+int regulator_sync_voltage_rdev(struct regulator_dev *rdev)
+{
+ int ret;
+
+ regulator_lock(rdev);
+
+ if (!rdev->desc->ops->set_voltage &&
+ !rdev->desc->ops->set_voltage_sel) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* balance only, if regulator is coupled */
+ if (rdev->coupling_desc.n_coupled > 1)
+ ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+ else
+ ret = -EOPNOTSUPP;
+
+out:
+ regulator_unlock(rdev);
+ return ret;
+}
+
/**
* regulator_sync_voltage - re-apply last regulator output voltage
* @regulator: regulator source
@@ -4386,22 +4509,36 @@ unsigned int regulator_get_mode(struct regulator *regulator)
}
EXPORT_SYMBOL_GPL(regulator_get_mode);
+static int rdev_get_cached_err_flags(struct regulator_dev *rdev)
+{
+ int ret = 0;
+
+ if (rdev->use_cached_err) {
+ spin_lock(&rdev->err_lock);
+ ret = rdev->cached_err;
+ spin_unlock(&rdev->err_lock);
+ }
+ return ret;
+}
+
static int _regulator_get_error_flags(struct regulator_dev *rdev,
unsigned int *flags)
{
- int ret;
+ int cached_flags, ret = 0;
regulator_lock(rdev);
- /* sanity check */
- if (!rdev->desc->ops->get_error_flags) {
+ cached_flags = rdev_get_cached_err_flags(rdev);
+
+ if (rdev->desc->ops->get_error_flags)
+ ret = rdev->desc->ops->get_error_flags(rdev, flags);
+ else if (!rdev->use_cached_err)
ret = -EINVAL;
- goto out;
- }
- ret = rdev->desc->ops->get_error_flags(rdev, flags);
-out:
+ *flags |= cached_flags;
+
regulator_unlock(rdev);
+
return ret;
}
@@ -5234,6 +5371,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
goto rinse;
}
device_initialize(&rdev->dev);
+ spin_lock_init(&rdev->err_lock);
/*
* Duplicate the config so the driver could override it after
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index e18d291c7f21..23fa429ebe76 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -250,7 +250,8 @@ static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
case DA9052_ID_BUCK3:
case DA9052_ID_LDO2:
case DA9052_ID_LDO3:
- ret = (new_sel - old_sel) * info->step_uV / 6250;
+ ret = DIV_ROUND_UP(abs(new_sel - old_sel) * info->step_uV,
+ 6250);
break;
}
diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c
index 3091210889e3..a8de0aa88bad 100644
--- a/drivers/regulator/devres.c
+++ b/drivers/regulator/devres.c
@@ -481,3 +481,55 @@ void devm_regulator_unregister_notifier(struct regulator *regulator,
WARN_ON(rc);
}
EXPORT_SYMBOL_GPL(devm_regulator_unregister_notifier);
+
+static void regulator_irq_helper_drop(void *res)
+{
+ regulator_irq_helper_cancel(&res);
+}
+
+/**
+ * devm_regulator_irq_helper - resource managed registration of IRQ based
+ * regulator event/error notifier
+ *
+ * @dev: device to which lifetime the helper's lifetime is
+ * bound.
+ * @d: IRQ helper descriptor.
+ * @irq: IRQ used to inform events/errors to be notified.
+ * @irq_flags: Extra IRQ flags to be OR'ed with the default
+ * IRQF_ONESHOT when requesting the (threaded) irq.
+ * @common_errs: Errors which can be flagged by this IRQ for all rdevs.
+ * When IRQ is re-enabled these errors will be cleared
+ * from all associated regulators
+ * @per_rdev_errs: Optional error flag array describing errors specific
+ * for only some of the regulators. These errors will be
+ * or'ed with common errors. If this is given the array
+ * should contain rdev_amount flags. Can be set to NULL
+ * if there is no regulator specific error flags for this
+ * IRQ.
+ * @rdev: Array of pointers to regulators associated with this
+ * IRQ.
+ * @rdev_amount: Amount of regulators associated with this IRQ.
+ *
+ * Return: handle to irq_helper or an ERR_PTR() encoded error code.
+ */
+void *devm_regulator_irq_helper(struct device *dev,
+ const struct regulator_irq_desc *d, int irq,
+ int irq_flags, int common_errs,
+ int *per_rdev_errs,
+ struct regulator_dev **rdev, int rdev_amount)
+{
+ void *ptr;
+ int ret;
+
+ ptr = regulator_irq_helper(dev, d, irq, irq_flags, common_errs,
+ per_rdev_errs, rdev, rdev_amount);
+ if (IS_ERR(ptr))
+ return ptr;
+
+ ret = devm_add_action_or_reset(dev, regulator_irq_helper_drop, ptr);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return ptr;
+}
+EXPORT_SYMBOL_GPL(devm_regulator_irq_helper);
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
index 26f06f685b1b..dac1fb584fa3 100644
--- a/drivers/regulator/fan53555.c
+++ b/drivers/regulator/fan53555.c
@@ -56,7 +56,6 @@
#define FAN53555_NVOLTAGES 64 /* Numbers of voltages */
#define FAN53526_NVOLTAGES 128
-#define TCS_VSEL_NSEL_MASK 0x7f
#define TCS_VSEL0_MODE (1 << 7)
#define TCS_VSEL1_MODE (1 << 6)
@@ -67,7 +66,7 @@ enum fan53555_vendor {
FAN53526_VENDOR_FAIRCHILD = 0,
FAN53555_VENDOR_FAIRCHILD,
FAN53555_VENDOR_SILERGY,
- FAN53555_VENDOR_TCS,
+ FAN53526_VENDOR_TCS,
};
enum {
@@ -89,6 +88,14 @@ enum {
FAN53555_CHIP_ID_08 = 8,
};
+enum {
+ TCS4525_CHIP_ID_12 = 12,
+};
+
+enum {
+ TCS4526_CHIP_ID_00 = 0,
+};
+
/* IC mask revision */
enum {
FAN53555_CHIP_REV_00 = 0x3,
@@ -123,7 +130,8 @@ struct fan53555_device_info {
/* Slew rate */
unsigned int slew_reg;
unsigned int slew_mask;
- unsigned int slew_shift;
+ const unsigned int *ramp_delay_table;
+ unsigned int n_ramp_values;
unsigned int slew_rate;
};
@@ -197,7 +205,7 @@ static unsigned int fan53555_get_mode(struct regulator_dev *rdev)
return REGULATOR_MODE_NORMAL;
}
-static const int slew_rates[] = {
+static const unsigned int slew_rates[] = {
64000,
32000,
16000,
@@ -208,51 +216,13 @@ static const int slew_rates[] = {
500,
};
-static const int tcs_slew_rates[] = {
+static const unsigned int tcs_slew_rates[] = {
18700,
9300,
4600,
2300,
};
-static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp)
-{
- struct fan53555_device_info *di = rdev_get_drvdata(rdev);
- int regval = -1, i;
- const int *slew_rate_t;
- int slew_rate_n;
-
- switch (di->vendor) {
- case FAN53526_VENDOR_FAIRCHILD:
- case FAN53555_VENDOR_FAIRCHILD:
- case FAN53555_VENDOR_SILERGY:
- slew_rate_t = slew_rates;
- slew_rate_n = ARRAY_SIZE(slew_rates);
- break;
- case FAN53555_VENDOR_TCS:
- slew_rate_t = tcs_slew_rates;
- slew_rate_n = ARRAY_SIZE(tcs_slew_rates);
- break;
- default:
- return -EINVAL;
- }
-
- for (i = 0; i < slew_rate_n; i++) {
- if (ramp <= slew_rate_t[i])
- regval = i;
- else
- break;
- }
-
- if (regval < 0) {
- dev_err(di->dev, "unsupported ramp value %d\n", ramp);
- return -EINVAL;
- }
-
- return regmap_update_bits(rdev->regmap, di->slew_reg,
- di->slew_mask, regval << di->slew_shift);
-}
-
static const struct regulator_ops fan53555_regulator_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -265,7 +235,7 @@ static const struct regulator_ops fan53555_regulator_ops = {
.is_enabled = regulator_is_enabled_regmap,
.set_mode = fan53555_set_mode,
.get_mode = fan53555_get_mode,
- .set_ramp_delay = fan53555_set_ramp,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
.set_suspend_enable = fan53555_set_suspend_enable,
.set_suspend_disable = fan53555_set_suspend_disable,
};
@@ -293,6 +263,10 @@ static int fan53526_voltages_setup_fairchild(struct fan53555_device_info *di)
return -EINVAL;
}
+ di->slew_reg = FAN53555_CONTROL;
+ di->slew_mask = CTL_SLEW_MASK;
+ di->ramp_delay_table = slew_rates;
+ di->n_ramp_values = ARRAY_SIZE(slew_rates);
di->vsel_count = FAN53526_NVOLTAGES;
return 0;
@@ -337,7 +311,8 @@ static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)
}
di->slew_reg = FAN53555_CONTROL;
di->slew_mask = CTL_SLEW_MASK;
- di->slew_shift = CTL_SLEW_SHIFT;
+ di->ramp_delay_table = slew_rates;
+ di->n_ramp_values = ARRAY_SIZE(slew_rates);
di->vsel_count = FAN53555_NVOLTAGES;
return 0;
@@ -358,24 +333,33 @@ static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di)
return -EINVAL;
}
di->slew_reg = FAN53555_CONTROL;
- di->slew_reg = FAN53555_CONTROL;
di->slew_mask = CTL_SLEW_MASK;
- di->slew_shift = CTL_SLEW_SHIFT;
+ di->ramp_delay_table = slew_rates;
+ di->n_ramp_values = ARRAY_SIZE(slew_rates);
di->vsel_count = FAN53555_NVOLTAGES;
return 0;
}
-static int fan53555_voltages_setup_tcs(struct fan53555_device_info *di)
+static int fan53526_voltages_setup_tcs(struct fan53555_device_info *di)
{
- di->slew_reg = TCS4525_TIME;
- di->slew_mask = TCS_SLEW_MASK;
- di->slew_shift = TCS_SLEW_MASK;
-
- /* Init voltage range and step */
- di->vsel_min = 600000;
- di->vsel_step = 6250;
- di->vsel_count = FAN53526_NVOLTAGES;
+ switch (di->chip_id) {
+ case TCS4525_CHIP_ID_12:
+ case TCS4526_CHIP_ID_00:
+ di->slew_reg = TCS4525_TIME;
+ di->slew_mask = TCS_SLEW_MASK;
+ di->ramp_delay_table = tcs_slew_rates;
+ di->n_ramp_values = ARRAY_SIZE(tcs_slew_rates);
+
+ /* Init voltage range and step */
+ di->vsel_min = 600000;
+ di->vsel_step = 6250;
+ di->vsel_count = FAN53526_NVOLTAGES;
+ break;
+ default:
+ dev_err(di->dev, "Chip ID %d not supported!\n", di->chip_id);
+ return -EINVAL;
+ }
return 0;
}
@@ -409,7 +393,7 @@ static int fan53555_device_setup(struct fan53555_device_info *di,
return -EINVAL;
}
break;
- case FAN53555_VENDOR_TCS:
+ case FAN53526_VENDOR_TCS:
switch (pdata->sleep_vsel_id) {
case FAN53555_VSEL_ID_0:
di->sleep_reg = TCS4525_VSEL0;
@@ -448,7 +432,7 @@ static int fan53555_device_setup(struct fan53555_device_info *di,
di->mode_reg = di->vol_reg;
di->mode_mask = VSEL_MODE;
break;
- case FAN53555_VENDOR_TCS:
+ case FAN53526_VENDOR_TCS:
di->mode_reg = TCS4525_COMMAND;
switch (pdata->sleep_vsel_id) {
@@ -476,8 +460,8 @@ static int fan53555_device_setup(struct fan53555_device_info *di,
case FAN53555_VENDOR_SILERGY:
ret = fan53555_voltages_setup_silergy(di);
break;
- case FAN53555_VENDOR_TCS:
- ret = fan53555_voltages_setup_tcs(di);
+ case FAN53526_VENDOR_TCS:
+ ret = fan53526_voltages_setup_tcs(di);
break;
default:
dev_err(di->dev, "vendor %d not supported!\n", di->vendor);
@@ -504,6 +488,10 @@ static int fan53555_regulator_register(struct fan53555_device_info *di,
rdesc->uV_step = di->vsel_step;
rdesc->vsel_reg = di->vol_reg;
rdesc->vsel_mask = di->vsel_count - 1;
+ rdesc->ramp_reg = di->slew_reg;
+ rdesc->ramp_mask = di->slew_mask;
+ rdesc->ramp_delay_table = di->ramp_delay_table;
+ rdesc->n_ramp_values = di->n_ramp_values;
rdesc->owner = THIS_MODULE;
rdev = devm_regulator_register(di->dev, &di->desc, config);
@@ -552,7 +540,10 @@ static const struct of_device_id __maybe_unused fan53555_dt_ids[] = {
.data = (void *)FAN53555_VENDOR_SILERGY,
}, {
.compatible = "tcs,tcs4525",
- .data = (void *)FAN53555_VENDOR_TCS
+ .data = (void *)FAN53526_VENDOR_TCS
+ }, {
+ .compatible = "tcs,tcs4526",
+ .data = (void *)FAN53526_VENDOR_TCS
},
{ }
};
@@ -660,7 +651,10 @@ static const struct i2c_device_id fan53555_id[] = {
.driver_data = FAN53555_VENDOR_SILERGY
}, {
.name = "tcs4525",
- .driver_data = FAN53555_VENDOR_TCS
+ .driver_data = FAN53526_VENDOR_TCS
+ }, {
+ .name = "tcs4526",
+ .driver_data = FAN53526_VENDOR_TCS
},
{ },
};
diff --git a/drivers/regulator/fan53880.c b/drivers/regulator/fan53880.c
index 1684faf82ed2..8f25930d2769 100644
--- a/drivers/regulator/fan53880.c
+++ b/drivers/regulator/fan53880.c
@@ -79,7 +79,7 @@ static const struct regulator_desc fan53880_regulators[] = {
.n_linear_ranges = 2,
.n_voltages = 0xf8,
.vsel_reg = FAN53880_BUCKVOUT,
- .vsel_mask = 0x7f,
+ .vsel_mask = 0xff,
.enable_reg = FAN53880_ENABLE,
.enable_mask = 0x10,
.enable_time = 480,
@@ -114,8 +114,7 @@ static const struct regmap_config fan53880_regmap = {
.max_register = FAN53880_ENABLE_BOOST,
};
-static int fan53880_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int fan53880_i2c_probe(struct i2c_client *i2c)
{
struct regulator_config config = { };
struct regulator_dev *rdev;
@@ -177,7 +176,7 @@ static struct i2c_driver fan53880_regulator_driver = {
.name = "fan53880",
.of_match_table = of_match_ptr(fan53880_dt_ids),
},
- .probe = fan53880_i2c_probe,
+ .probe_new = fan53880_i2c_probe,
.id_table = fan53880_i2c_id,
};
module_i2c_driver(fan53880_regulator_driver);
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 34e255c235d4..39284610a536 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -276,7 +276,8 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
*/
cfg.ena_gpiod = gpiod_get_optional(&pdev->dev, NULL, gflags);
if (IS_ERR(cfg.ena_gpiod))
- return PTR_ERR(cfg.ena_gpiod);
+ return dev_err_probe(&pdev->dev, PTR_ERR(cfg.ena_gpiod),
+ "can't get GPIO\n");
cfg.dev = &pdev->dev;
cfg.init_data = config->init_data;
diff --git a/drivers/regulator/hi6421-regulator.c b/drivers/regulator/hi6421-regulator.c
index dc631c1a46b4..bff8c515dcde 100644
--- a/drivers/regulator/hi6421-regulator.c
+++ b/drivers/regulator/hi6421-regulator.c
@@ -386,7 +386,7 @@ static int hi6421_regulator_enable(struct regulator_dev *rdev)
static unsigned int hi6421_regulator_ldo_get_mode(struct regulator_dev *rdev)
{
struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
- u32 reg_val;
+ unsigned int reg_val;
regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
if (reg_val & info->mode_mask)
@@ -398,7 +398,7 @@ static unsigned int hi6421_regulator_ldo_get_mode(struct regulator_dev *rdev)
static unsigned int hi6421_regulator_buck_get_mode(struct regulator_dev *rdev)
{
struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
- u32 reg_val;
+ unsigned int reg_val;
regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
if (reg_val & info->mode_mask)
@@ -411,7 +411,7 @@ static int hi6421_regulator_ldo_set_mode(struct regulator_dev *rdev,
unsigned int mode)
{
struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
- u32 new_mode;
+ unsigned int new_mode;
switch (mode) {
case REGULATOR_MODE_NORMAL:
@@ -435,7 +435,7 @@ static int hi6421_regulator_buck_set_mode(struct regulator_dev *rdev,
unsigned int mode)
{
struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
- u32 new_mode;
+ unsigned int new_mode;
switch (mode) {
case REGULATOR_MODE_NORMAL:
diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
index d6340bb49296..9b162c0555c3 100644
--- a/drivers/regulator/hi6421v600-regulator.c
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -16,14 +16,15 @@
#include <linux/regulator/driver.h>
#include <linux/spmi.h>
+struct hi6421_spmi_reg_priv {
+ /* Serialize regulator enable logic */
+ struct mutex enable_mutex;
+};
+
struct hi6421_spmi_reg_info {
struct regulator_desc desc;
- struct hi6421_spmi_pmic *pmic;
u8 eco_mode_mask;
u32 eco_uA;
-
- /* Serialize regulator enable logic */
- struct mutex enable_mutex;
};
static const unsigned int ldo3_voltages[] = {
@@ -97,41 +98,31 @@ static const unsigned int ldo34_voltages[] = {
static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev)
{
- struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev);
- struct hi6421_spmi_pmic *pmic = sreg->pmic;
+ struct hi6421_spmi_reg_priv *priv;
int ret;
+ priv = dev_get_drvdata(rdev->dev.parent);
/* cannot enable more than one regulator at one time */
- mutex_lock(&sreg->enable_mutex);
+ mutex_lock(&priv->enable_mutex);
- ret = regmap_update_bits(pmic->regmap, rdev->desc->enable_reg,
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask,
rdev->desc->enable_mask);
/* Avoid powering up multiple devices at the same time */
usleep_range(rdev->desc->off_on_delay, rdev->desc->off_on_delay + 60);
- mutex_unlock(&sreg->enable_mutex);
+ mutex_unlock(&priv->enable_mutex);
return ret;
}
-static int hi6421_spmi_regulator_disable(struct regulator_dev *rdev)
-{
- struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev);
- struct hi6421_spmi_pmic *pmic = sreg->pmic;
-
- return regmap_update_bits(pmic->regmap, rdev->desc->enable_reg,
- rdev->desc->enable_mask, 0);
-}
-
static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev)
{
struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev);
- struct hi6421_spmi_pmic *pmic = sreg->pmic;
- u32 reg_val;
+ unsigned int reg_val;
- regmap_read(pmic->regmap, rdev->desc->enable_reg, &reg_val);
+ regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
if (reg_val & sreg->eco_mode_mask)
return REGULATOR_MODE_IDLE;
@@ -143,21 +134,23 @@ static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev,
unsigned int mode)
{
struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev);
- struct hi6421_spmi_pmic *pmic = sreg->pmic;
- u32 val;
+ unsigned int val;
switch (mode) {
case REGULATOR_MODE_NORMAL:
val = 0;
break;
case REGULATOR_MODE_IDLE:
- val = sreg->eco_mode_mask << (ffs(sreg->eco_mode_mask) - 1);
+ if (!sreg->eco_mode_mask)
+ return -EINVAL;
+
+ val = sreg->eco_mode_mask;
break;
default:
return -EINVAL;
}
- return regmap_update_bits(pmic->regmap, rdev->desc->enable_reg,
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
sreg->eco_mode_mask, val);
}
@@ -177,9 +170,9 @@ hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev *rdev,
static const struct regulator_ops hi6421_spmi_ldo_rops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = hi6421_spmi_regulator_enable,
- .disable = hi6421_spmi_regulator_disable,
+ .disable = regulator_disable_regmap,
.list_voltage = regulator_list_voltage_table,
- .map_voltage = regulator_map_voltage_iterate,
+ .map_voltage = regulator_map_voltage_ascend,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_mode = hi6421_spmi_regulator_get_mode,
@@ -238,7 +231,7 @@ static int hi6421_spmi_regulator_probe(struct platform_device *pdev)
{
struct device *pmic_dev = pdev->dev.parent;
struct regulator_config config = { };
- struct hi6421_spmi_reg_info *sreg;
+ struct hi6421_spmi_reg_priv *priv;
struct hi6421_spmi_reg_info *info;
struct device *dev = &pdev->dev;
struct hi6421_spmi_pmic *pmic;
@@ -254,18 +247,18 @@ static int hi6421_spmi_regulator_probe(struct platform_device *pdev)
if (WARN_ON(!pmic))
return -ENODEV;
- sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);
- if (!sreg)
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- sreg->pmic = pmic;
- mutex_init(&sreg->enable_mutex);
+ mutex_init(&priv->enable_mutex);
+ platform_set_drvdata(pdev, priv);
for (i = 0; i < ARRAY_SIZE(regulator_info); i++) {
info = &regulator_info[i];
config.dev = pdev->dev.parent;
- config.driver_data = sreg;
+ config.driver_data = info;
config.regmap = pmic->regmap;
rdev = devm_regulator_register(dev, &info->desc, &config);
diff --git a/drivers/regulator/hi655x-regulator.c b/drivers/regulator/hi655x-regulator.c
index 68cdb173196d..556bb73f3329 100644
--- a/drivers/regulator/hi655x-regulator.c
+++ b/drivers/regulator/hi655x-regulator.c
@@ -72,7 +72,7 @@ enum hi655x_regulator_id {
static int hi655x_is_enabled(struct regulator_dev *rdev)
{
unsigned int value = 0;
- struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
+ const struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
regmap_read(rdev->regmap, regulator->status_reg, &value);
return (value & rdev->desc->enable_mask);
@@ -80,7 +80,7 @@ static int hi655x_is_enabled(struct regulator_dev *rdev)
static int hi655x_disable(struct regulator_dev *rdev)
{
- struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
+ const struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
return regmap_write(rdev->regmap, regulator->disable_reg,
rdev->desc->enable_mask);
@@ -169,7 +169,6 @@ static const struct hi655x_regulator regulators[] = {
static int hi655x_regulator_probe(struct platform_device *pdev)
{
unsigned int i;
- struct hi655x_regulator *regulator;
struct hi655x_pmic *pmic;
struct regulator_config config = { };
struct regulator_dev *rdev;
@@ -180,22 +179,17 @@ static int hi655x_regulator_probe(struct platform_device *pdev)
return -ENODEV;
}
- regulator = devm_kzalloc(&pdev->dev, sizeof(*regulator), GFP_KERNEL);
- if (!regulator)
- return -ENOMEM;
-
- platform_set_drvdata(pdev, regulator);
-
config.dev = pdev->dev.parent;
config.regmap = pmic->regmap;
- config.driver_data = regulator;
for (i = 0; i < ARRAY_SIZE(regulators); i++) {
+ config.driver_data = (void *) &regulators[i];
+
rdev = devm_regulator_register(&pdev->dev,
&regulators[i].rdesc,
&config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
- regulator->rdesc.name);
+ regulators[i].rdesc.name);
return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h
index 2391b565ef11..1e9c71642143 100644
--- a/drivers/regulator/internal.h
+++ b/drivers/regulator/internal.h
@@ -15,6 +15,17 @@
#define REGULATOR_STATES_NUM (PM_SUSPEND_MAX + 1)
+#define rdev_crit(rdev, fmt, ...) \
+ pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_err(rdev, fmt, ...) \
+ pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_warn(rdev, fmt, ...) \
+ pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_info(rdev, fmt, ...) \
+ pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_dbg(rdev, fmt, ...) \
+ pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+
struct regulator_voltage {
int min_uV;
int max_uV;
diff --git a/drivers/regulator/irq_helpers.c b/drivers/regulator/irq_helpers.c
new file mode 100644
index 000000000000..fabe2e53093e
--- /dev/null
+++ b/drivers/regulator/irq_helpers.c
@@ -0,0 +1,397 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2021 ROHM Semiconductors
+// regulator IRQ based event notification helpers
+//
+// Logic has been partially adapted from qcom-labibb driver.
+//
+// Author: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/regulator/driver.h>
+
+#include "internal.h"
+
+#define REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS 10000
+
+struct regulator_irq {
+ struct regulator_irq_data rdata;
+ struct regulator_irq_desc desc;
+ int irq;
+ int retry_cnt;
+ struct delayed_work isr_work;
+};
+
+/*
+ * Should only be called from threaded handler to prevent potential deadlock
+ */
+static void rdev_flag_err(struct regulator_dev *rdev, int err)
+{
+ spin_lock(&rdev->err_lock);
+ rdev->cached_err |= err;
+ spin_unlock(&rdev->err_lock);
+}
+
+static void rdev_clear_err(struct regulator_dev *rdev, int err)
+{
+ spin_lock(&rdev->err_lock);
+ rdev->cached_err &= ~err;
+ spin_unlock(&rdev->err_lock);
+}
+
+static void regulator_notifier_isr_work(struct work_struct *work)
+{
+ struct regulator_irq *h;
+ struct regulator_irq_desc *d;
+ struct regulator_irq_data *rid;
+ int ret = 0;
+ int tmo, i;
+ int num_rdevs;
+
+ h = container_of(work, struct regulator_irq,
+ isr_work.work);
+ d = &h->desc;
+ rid = &h->rdata;
+ num_rdevs = rid->num_states;
+
+reread:
+ if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) {
+ if (!d->die)
+ return hw_protection_shutdown("Regulator HW failure? - no IC recovery",
+ REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
+ ret = d->die(rid);
+ /*
+ * If the 'last resort' IC recovery failed we will have
+ * nothing else left to do...
+ */
+ if (ret)
+ return hw_protection_shutdown("Regulator HW failure. IC recovery failed",
+ REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
+
+ /*
+ * If h->die() was implemented we assume recovery has been
+ * attempted (probably regulator was shut down) and we
+ * just enable IRQ and bail-out.
+ */
+ goto enable_out;
+ }
+ if (d->renable) {
+ ret = d->renable(rid);
+
+ if (ret == REGULATOR_FAILED_RETRY) {
+ /* Driver could not get current status */
+ h->retry_cnt++;
+ if (!d->reread_ms)
+ goto reread;
+
+ tmo = d->reread_ms;
+ goto reschedule;
+ }
+
+ if (ret) {
+ /*
+ * IC status reading succeeded. update error info
+ * just in case the renable changed it.
+ */
+ for (i = 0; i < num_rdevs; i++) {
+ struct regulator_err_state *stat;
+ struct regulator_dev *rdev;
+
+ stat = &rid->states[i];
+ rdev = stat->rdev;
+ rdev_clear_err(rdev, (~stat->errors) &
+ stat->possible_errs);
+ }
+ h->retry_cnt++;
+ /*
+ * The IC indicated problem is still ON - no point in
+ * re-enabling the IRQ. Retry later.
+ */
+ tmo = d->irq_off_ms;
+ goto reschedule;
+ }
+ }
+
+ /*
+ * Either IC reported problem cleared or no status checker was provided.
+ * If problems are gone - good. If not - then the IRQ will fire again
+ * and we'll have a new nice loop. In any case we should clear error
+ * flags here and re-enable IRQs.
+ */
+ for (i = 0; i < num_rdevs; i++) {
+ struct regulator_err_state *stat;
+ struct regulator_dev *rdev;
+
+ stat = &rid->states[i];
+ rdev = stat->rdev;
+ rdev_clear_err(rdev, stat->possible_errs);
+ }
+
+ /*
+ * Things have been seemingly successful => zero retry-counter.
+ */
+ h->retry_cnt = 0;
+
+enable_out:
+ enable_irq(h->irq);
+
+ return;
+
+reschedule:
+ if (!d->high_prio)
+ mod_delayed_work(system_wq, &h->isr_work,
+ msecs_to_jiffies(tmo));
+ else
+ mod_delayed_work(system_highpri_wq, &h->isr_work,
+ msecs_to_jiffies(tmo));
+}
+
+static irqreturn_t regulator_notifier_isr(int irq, void *data)
+{
+ struct regulator_irq *h = data;
+ struct regulator_irq_desc *d;
+ struct regulator_irq_data *rid;
+ unsigned long rdev_map = 0;
+ int num_rdevs;
+ int ret, i;
+
+ d = &h->desc;
+ rid = &h->rdata;
+ num_rdevs = rid->num_states;
+
+ if (d->fatal_cnt)
+ h->retry_cnt++;
+
+ /*
+ * we spare a few cycles by not clearing statuses prior to this call.
+ * The IC driver must initialize the status buffers for rdevs
+ * which it indicates having active events via rdev_map.
+ *
+ * Maybe we should just to be on a safer side(?)
+ */
+ ret = d->map_event(irq, rid, &rdev_map);
+
+ /*
+ * If status reading fails (which is unlikely) we don't ack/disable
+ * IRQ but just increase fail count and retry when IRQ fires again.
+ * If retry_count exceeds the given safety limit we call IC specific die
+ * handler which can try disabling regulator(s).
+ *
+ * If no die handler is given we will just bug() as a last resort.
+ *
+ * We could try disabling all associated rdevs - but we might shoot
+ * ourselves in the head and leave the problematic regulator enabled. So
+ * if IC has no die-handler populated we just assume the regulator
+ * can't be disabled.
+ */
+ if (unlikely(ret == REGULATOR_FAILED_RETRY))
+ goto fail_out;
+
+ h->retry_cnt = 0;
+ /*
+ * Let's not disable IRQ if there were no status bits for us. We'd
+ * better leave spurious IRQ handling to genirq
+ */
+ if (ret || !rdev_map)
+ return IRQ_NONE;
+
+ /*
+ * Some events are bogus if the regulator is disabled. Skip such events
+ * if all relevant regulators are disabled
+ */
+ if (d->skip_off) {
+ for_each_set_bit(i, &rdev_map, num_rdevs) {
+ struct regulator_dev *rdev;
+ const struct regulator_ops *ops;
+
+ rdev = rid->states[i].rdev;
+ ops = rdev->desc->ops;
+
+ /*
+ * If any of the flagged regulators is enabled we do
+ * handle this
+ */
+ if (ops->is_enabled(rdev))
+ break;
+ }
+ if (i == num_rdevs)
+ return IRQ_NONE;
+ }
+
+ /* Disable IRQ if HW keeps line asserted */
+ if (d->irq_off_ms)
+ disable_irq_nosync(irq);
+
+ /*
+ * IRQ seems to be for us. Let's fire correct notifiers / store error
+ * flags
+ */
+ for_each_set_bit(i, &rdev_map, num_rdevs) {
+ struct regulator_err_state *stat;
+ struct regulator_dev *rdev;
+
+ stat = &rid->states[i];
+ rdev = stat->rdev;
+
+ rdev_dbg(rdev, "Sending regulator notification EVT 0x%lx\n",
+ stat->notifs);
+
+ regulator_notifier_call_chain(rdev, stat->notifs, NULL);
+ rdev_flag_err(rdev, stat->errors);
+ }
+
+ if (d->irq_off_ms) {
+ if (!d->high_prio)
+ schedule_delayed_work(&h->isr_work,
+ msecs_to_jiffies(d->irq_off_ms));
+ else
+ mod_delayed_work(system_highpri_wq,
+ &h->isr_work,
+ msecs_to_jiffies(d->irq_off_ms));
+ }
+
+ return IRQ_HANDLED;
+
+fail_out:
+ if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) {
+ /* If we have no recovery, just try shut down straight away */
+ if (!d->die) {
+ hw_protection_shutdown("Regulator failure. Retry count exceeded",
+ REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
+ } else {
+ ret = d->die(rid);
+ /* If die() failed shut down as a last attempt to save the HW */
+ if (ret)
+ hw_protection_shutdown("Regulator failure. Recovery failed",
+ REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
+ }
+ }
+
+ return IRQ_NONE;
+}
+
+static int init_rdev_state(struct device *dev, struct regulator_irq *h,
+ struct regulator_dev **rdev, int common_err,
+ int *rdev_err, int rdev_amount)
+{
+ int i;
+
+ h->rdata.states = devm_kzalloc(dev, sizeof(*h->rdata.states) *
+ rdev_amount, GFP_KERNEL);
+ if (!h->rdata.states)
+ return -ENOMEM;
+
+ h->rdata.num_states = rdev_amount;
+ h->rdata.data = h->desc.data;
+
+ for (i = 0; i < rdev_amount; i++) {
+ h->rdata.states[i].possible_errs = common_err;
+ if (rdev_err)
+ h->rdata.states[i].possible_errs |= *rdev_err++;
+ h->rdata.states[i].rdev = *rdev++;
+ }
+
+ return 0;
+}
+
+static void init_rdev_errors(struct regulator_irq *h)
+{
+ int i;
+
+ for (i = 0; i < h->rdata.num_states; i++)
+ if (h->rdata.states[i].possible_errs)
+ h->rdata.states[i].rdev->use_cached_err = true;
+}
+
+/**
+ * regulator_irq_helper - register IRQ based regulator event/error notifier
+ *
+ * @dev: device providing the IRQs
+ * @d: IRQ helper descriptor.
+ * @irq: IRQ used to inform events/errors to be notified.
+ * @irq_flags: Extra IRQ flags to be OR'ed with the default
+ * IRQF_ONESHOT when requesting the (threaded) irq.
+ * @common_errs: Errors which can be flagged by this IRQ for all rdevs.
+ * When IRQ is re-enabled these errors will be cleared
+ * from all associated regulators
+ * @per_rdev_errs: Optional error flag array describing errors specific
+ * for only some of the regulators. These errors will be
+ * or'ed with common errors. If this is given the array
+ * should contain rdev_amount flags. Can be set to NULL
+ * if there is no regulator specific error flags for this
+ * IRQ.
+ * @rdev: Array of pointers to regulators associated with this
+ * IRQ.
+ * @rdev_amount: Amount of regulators associated with this IRQ.
+ *
+ * Return: handle to irq_helper or an ERR_PTR() encoded error code.
+ */
+void *regulator_irq_helper(struct device *dev,
+ const struct regulator_irq_desc *d, int irq,
+ int irq_flags, int common_errs, int *per_rdev_errs,
+ struct regulator_dev **rdev, int rdev_amount)
+{
+ struct regulator_irq *h;
+ int ret;
+
+ if (!rdev_amount || !d || !d->map_event || !d->name)
+ return ERR_PTR(-EINVAL);
+
+ h = devm_kzalloc(dev, sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return ERR_PTR(-ENOMEM);
+
+ h->irq = irq;
+ h->desc = *d;
+
+ ret = init_rdev_state(dev, h, rdev, common_errs, per_rdev_errs,
+ rdev_amount);
+ if (ret)
+ return ERR_PTR(ret);
+
+ init_rdev_errors(h);
+
+ if (h->desc.irq_off_ms)
+ INIT_DELAYED_WORK(&h->isr_work, regulator_notifier_isr_work);
+
+ ret = request_threaded_irq(h->irq, NULL, regulator_notifier_isr,
+ IRQF_ONESHOT | irq_flags, h->desc.name, h);
+ if (ret) {
+ dev_err(dev, "Failed to request IRQ %d\n", irq);
+
+ return ERR_PTR(ret);
+ }
+
+ return h;
+}
+EXPORT_SYMBOL_GPL(regulator_irq_helper);
+
+/**
+ * regulator_irq_helper_cancel - drop IRQ based regulator event/error notifier
+ *
+ * @handle: Pointer to handle returned by a successful call to
+ * regulator_irq_helper(). Will be NULLed upon return.
+ *
+ * The associated IRQ is released and work is cancelled when the function
+ * returns.
+ */
+void regulator_irq_helper_cancel(void **handle)
+{
+ if (handle && *handle) {
+ struct regulator_irq *h = *handle;
+
+ free_irq(h->irq, h);
+ if (h->desc.irq_off_ms)
+ cancel_delayed_work_sync(&h->isr_work);
+
+ h = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(regulator_irq_helper_cancel);
diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c
index 13c535711265..321bec6e3f8d 100644
--- a/drivers/regulator/lp8755.c
+++ b/drivers/regulator/lp8755.c
@@ -136,52 +136,9 @@ err_i2c:
return 0;
}
-static int lp8755_buck_set_ramp(struct regulator_dev *rdev, int ramp)
-{
- int ret;
- unsigned int regval = 0x00;
- enum lp8755_bucks id = rdev_get_id(rdev);
-
- /* uV/us */
- switch (ramp) {
- case 0 ... 230:
- regval = 0x07;
- break;
- case 231 ... 470:
- regval = 0x06;
- break;
- case 471 ... 940:
- regval = 0x05;
- break;
- case 941 ... 1900:
- regval = 0x04;
- break;
- case 1901 ... 3800:
- regval = 0x03;
- break;
- case 3801 ... 7500:
- regval = 0x02;
- break;
- case 7501 ... 15000:
- regval = 0x01;
- break;
- case 15001 ... 30000:
- regval = 0x00;
- break;
- default:
- dev_err(&rdev->dev,
- "Not supported ramp value %d %s\n", ramp, __func__);
- return -EINVAL;
- }
-
- ret = regmap_update_bits(rdev->regmap, 0x07 + id, 0x07, regval);
- if (ret < 0)
- goto err_i2c;
- return ret;
-err_i2c:
- dev_err(&rdev->dev, "i2c access error %s\n", __func__);
- return ret;
-}
+static const unsigned int lp8755_buck_ramp_table[] = {
+ 30000, 15000, 7500, 3800, 1900, 940, 470, 230
+};
static const struct regulator_ops lp8755_buck_ops = {
.map_voltage = regulator_map_voltage_linear,
@@ -194,7 +151,7 @@ static const struct regulator_ops lp8755_buck_ops = {
.enable_time = lp8755_buck_enable_time,
.set_mode = lp8755_buck_set_mode,
.get_mode = lp8755_buck_get_mode,
- .set_ramp_delay = lp8755_buck_set_ramp,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
};
#define lp8755_rail(_id) "lp8755_buck"#_id
@@ -269,6 +226,10 @@ out_i2c_error:
.enable_mask = LP8755_BUCK_EN_M,\
.vsel_reg = LP8755_REG_BUCK##_id,\
.vsel_mask = LP8755_BUCK_VOUT_M,\
+ .ramp_reg = (LP8755_BUCK##_id) + 0x7,\
+ .ramp_mask = 0x7,\
+ .ramp_delay_table = lp8755_buck_ramp_table,\
+ .n_ramp_values = ARRAY_SIZE(lp8755_buck_ramp_table),\
}
static const struct regulator_desc lp8755_regulators[] = {
diff --git a/drivers/regulator/lp87565-regulator.c b/drivers/regulator/lp87565-regulator.c
index eeab9d3c824b..d059ae85047a 100644
--- a/drivers/regulator/lp87565-regulator.c
+++ b/drivers/regulator/lp87565-regulator.c
@@ -11,6 +11,17 @@
#include <linux/mfd/lp87565.h>
+enum LP87565_regulator_id {
+ /* BUCK's */
+ LP87565_BUCK_0,
+ LP87565_BUCK_1,
+ LP87565_BUCK_2,
+ LP87565_BUCK_3,
+ LP87565_BUCK_10,
+ LP87565_BUCK_23,
+ LP87565_BUCK_3210,
+};
+
#define LP87565_REGULATOR(_name, _id, _of, _ops, _n, _vr, _vm, \
_er, _em, _ev, _delay, _lr, _cr) \
[_id] = { \
diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c
index 38f7ccb63b52..5e0b669c3a01 100644
--- a/drivers/regulator/ltc3589.c
+++ b/drivers/regulator/ltc3589.c
@@ -54,6 +54,11 @@
#define LTC3589_VCCR_SW3_GO BIT(4)
#define LTC3589_VCCR_LDO2_GO BIT(6)
+#define LTC3589_VRRCR_SW1_RAMP_MASK GENMASK(1, 0)
+#define LTC3589_VRRCR_SW2_RAMP_MASK GENMASK(3, 2)
+#define LTC3589_VRRCR_SW3_RAMP_MASK GENMASK(5, 4)
+#define LTC3589_VRRCR_LDO2_RAMP_MASK GENMASK(7, 6)
+
enum ltc3589_variant {
LTC3589,
LTC3589_1,
@@ -88,27 +93,9 @@ static const int ltc3589_12_ldo4[] = {
1200000, 1800000, 2500000, 3200000,
};
-static int ltc3589_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
- struct ltc3589 *ltc3589 = rdev_get_drvdata(rdev);
- int sel, shift;
-
- if (unlikely(ramp_delay <= 0))
- return -EINVAL;
-
- /* VRRCR slew rate offsets are the same as VCCR go bit offsets */
- shift = ffs(rdev->desc->apply_bit) - 1;
-
- /* The slew rate can be set to 0.88, 1.75, 3.5, or 7 mV/uS */
- for (sel = 0; sel < 4; sel++) {
- if ((880 << sel) >= ramp_delay) {
- return regmap_update_bits(ltc3589->regmap,
- LTC3589_VRRCR,
- 0x3 << shift, sel << shift);
- }
- }
- return -EINVAL;
-}
+static const unsigned int ltc3589_ramp_table[] = {
+ 880, 1750, 3500, 7000
+};
static int ltc3589_set_suspend_voltage(struct regulator_dev *rdev, int uV)
{
@@ -149,7 +136,7 @@ static const struct regulator_ops ltc3589_linear_regulator_ops = {
.list_voltage = regulator_list_voltage_linear,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_ramp_delay = ltc3589_set_ramp_delay,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_suspend_voltage = ltc3589_set_suspend_voltage,
.set_suspend_mode = ltc3589_set_suspend_mode,
@@ -218,16 +205,13 @@ static int ltc3589_of_parse_cb(struct device_node *np,
return 0;
}
-#define LTC3589_REG(_name, _of_name, _ops, en_bit, dtv1_reg, dtv_mask, go_bit)\
+#define LTC3589_REG(_name, _of_name, _ops, en_bit, dtv1_reg, dtv_mask) \
[LTC3589_ ## _name] = { \
.name = #_name, \
.of_match = of_match_ptr(#_of_name), \
.regulators_node = of_match_ptr("regulators"), \
.of_parse_cb = ltc3589_of_parse_cb, \
.n_voltages = (dtv_mask) + 1, \
- .min_uV = (go_bit) ? 362500 : 0, \
- .uV_step = (go_bit) ? 12500 : 0, \
- .ramp_delay = (go_bit) ? 1750 : 0, \
.fixed_uV = (dtv_mask) ? 0 : 800000, \
.ops = &ltc3589_ ## _ops ## _regulator_ops, \
.type = REGULATOR_VOLTAGE, \
@@ -235,30 +219,49 @@ static int ltc3589_of_parse_cb(struct device_node *np,
.owner = THIS_MODULE, \
.vsel_reg = (dtv1_reg), \
.vsel_mask = (dtv_mask), \
- .apply_reg = (go_bit) ? LTC3589_VCCR : 0, \
- .apply_bit = (go_bit), \
.enable_reg = (en_bit) ? LTC3589_OVEN : 0, \
.enable_mask = (en_bit), \
}
#define LTC3589_LINEAR_REG(_name, _of_name, _dtv1) \
- LTC3589_REG(_name, _of_name, linear, LTC3589_OVEN_ ## _name, \
- LTC3589_ ## _dtv1, 0x1f, \
- LTC3589_VCCR_ ## _name ## _GO)
+ [LTC3589_ ## _name] = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(#_of_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .of_parse_cb = ltc3589_of_parse_cb, \
+ .n_voltages = 32, \
+ .min_uV = 362500, \
+ .uV_step = 12500, \
+ .ramp_delay = 1750, \
+ .ops = &ltc3589_linear_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = LTC3589_ ## _name, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = LTC3589_ ## _dtv1, \
+ .vsel_mask = 0x1f, \
+ .apply_reg = LTC3589_VCCR, \
+ .apply_bit = LTC3589_VCCR_ ## _name ## _GO, \
+ .enable_reg = LTC3589_OVEN, \
+ .enable_mask = (LTC3589_OVEN_ ## _name), \
+ .ramp_reg = LTC3589_VRRCR, \
+ .ramp_mask = LTC3589_VRRCR_ ## _name ## _RAMP_MASK, \
+ .ramp_delay_table = ltc3589_ramp_table, \
+ .n_ramp_values = ARRAY_SIZE(ltc3589_ramp_table), \
+ }
+
#define LTC3589_FIXED_REG(_name, _of_name) \
- LTC3589_REG(_name, _of_name, fixed, LTC3589_OVEN_ ## _name, 0, 0, 0)
+ LTC3589_REG(_name, _of_name, fixed, LTC3589_OVEN_ ## _name, 0, 0)
static const struct regulator_desc ltc3589_regulators[] = {
LTC3589_LINEAR_REG(SW1, sw1, B1DTV1),
LTC3589_LINEAR_REG(SW2, sw2, B2DTV1),
LTC3589_LINEAR_REG(SW3, sw3, B3DTV1),
LTC3589_FIXED_REG(BB_OUT, bb-out),
- LTC3589_REG(LDO1, ldo1, fixed_standby, 0, 0, 0, 0),
+ LTC3589_REG(LDO1, ldo1, fixed_standby, 0, 0, 0),
LTC3589_LINEAR_REG(LDO2, ldo2, L2DTV1),
LTC3589_FIXED_REG(LDO3, ldo3),
- LTC3589_REG(LDO4, ldo4, table, LTC3589_OVEN_LDO4, LTC3589_L2DTV2,
- 0x60, 0),
+ LTC3589_REG(LDO4, ldo4, table, LTC3589_OVEN_LDO4, LTC3589_L2DTV2, 0x60),
};
static bool ltc3589_writeable_reg(struct device *dev, unsigned int reg)
diff --git a/drivers/regulator/max77686-regulator.c b/drivers/regulator/max77686-regulator.c
index 9089ec608fcc..55a07d3f3ee2 100644
--- a/drivers/regulator/max77686-regulator.c
+++ b/drivers/regulator/max77686-regulator.c
@@ -67,13 +67,6 @@
#define MAX77686_REGULATORS MAX77686_REG_MAX
#define MAX77686_LDOS 26
-enum max77686_ramp_rate {
- RAMP_RATE_13P75MV,
- RAMP_RATE_27P5MV,
- RAMP_RATE_55MV,
- RAMP_RATE_NO_CTRL, /* 100mV/us */
-};
-
struct max77686_data {
struct device *dev;
DECLARE_BITMAP(gpio_enabled, MAX77686_REGULATORS);
@@ -220,31 +213,6 @@ static int max77686_enable(struct regulator_dev *rdev)
max77686->opmode[id] << shift);
}
-static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
- unsigned int ramp_value = RAMP_RATE_NO_CTRL;
-
- switch (ramp_delay) {
- case 1 ... 13750:
- ramp_value = RAMP_RATE_13P75MV;
- break;
- case 13751 ... 27500:
- ramp_value = RAMP_RATE_27P5MV;
- break;
- case 27501 ... 55000:
- ramp_value = RAMP_RATE_55MV;
- break;
- case 55001 ... 100000:
- break;
- default:
- pr_warn("%s: ramp_delay: %d not supported, setting 100000\n",
- rdev->desc->name, ramp_delay);
- }
-
- return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- MAX77686_RAMP_RATE_MASK, ramp_value << 6);
-}
-
static int max77686_of_parse_cb(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *config)
@@ -284,6 +252,10 @@ static int max77686_of_parse_cb(struct device_node *np,
return 0;
}
+static const unsigned int max77686_buck_dvs_ramp_table[] = {
+ 13750, 27500, 55000, 100000
+};
+
static const struct regulator_ops max77686_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
@@ -330,7 +302,7 @@ static const struct regulator_ops max77686_buck_dvs_ops = {
.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_ramp_delay = max77686_set_ramp_delay,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
.set_suspend_disable = max77686_set_suspend_disable,
};
@@ -462,6 +434,10 @@ static const struct regulator_ops max77686_buck_dvs_ops = {
.enable_reg = MAX77686_REG_BUCK2CTRL1 + (num - 2) * 10, \
.enable_mask = MAX77686_OPMODE_MASK \
<< MAX77686_OPMODE_BUCK234_SHIFT, \
+ .ramp_reg = MAX77686_REG_BUCK2CTRL1 + (num - 2) * 10, \
+ .ramp_mask = MAX77686_RAMP_RATE_MASK, \
+ .ramp_delay_table = max77686_buck_dvs_ramp_table, \
+ .n_ramp_values = ARRAY_SIZE(max77686_buck_dvs_ramp_table), \
}
static const struct regulator_desc regulators[] = {
diff --git a/drivers/regulator/max77802-regulator.c b/drivers/regulator/max77802-regulator.c
index 7b8ec8c0bd15..21e0eb0f43f9 100644
--- a/drivers/regulator/max77802-regulator.c
+++ b/drivers/regulator/max77802-regulator.c
@@ -43,15 +43,14 @@
#define MAX77802_OFF_PWRREQ 0x1
#define MAX77802_LP_PWRREQ 0x2
-/* MAX77802 has two register formats: 2-bit and 4-bit */
-static const unsigned int ramp_table_77802_2bit[] = {
+static const unsigned int max77802_buck234_ramp_table[] = {
12500,
25000,
50000,
100000,
};
-static unsigned int ramp_table_77802_4bit[] = {
+static const unsigned int max77802_buck16_ramp_table[] = {
1000, 2000, 3030, 4000,
5000, 5880, 7140, 8330,
9090, 10000, 11110, 12500,
@@ -221,58 +220,6 @@ static int max77802_enable(struct regulator_dev *rdev)
max77802->opmode[id] << shift);
}
-static int max77802_find_ramp_value(struct regulator_dev *rdev,
- const unsigned int limits[], int size,
- unsigned int ramp_delay)
-{
- int i;
-
- for (i = 0; i < size; i++) {
- if (ramp_delay <= limits[i])
- return i;
- }
-
- /* Use maximum value for no ramp control */
- dev_warn(&rdev->dev, "%s: ramp_delay: %d not supported, setting 100000\n",
- rdev->desc->name, ramp_delay);
- return size - 1;
-}
-
-/* Used for BUCKs 2-4 */
-static int max77802_set_ramp_delay_2bit(struct regulator_dev *rdev,
- int ramp_delay)
-{
- int id = rdev_get_id(rdev);
- unsigned int ramp_value;
-
- if (id > MAX77802_BUCK4) {
- dev_warn(&rdev->dev,
- "%s: regulator: ramp delay not supported\n",
- rdev->desc->name);
- return -EINVAL;
- }
- ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_2bit,
- ARRAY_SIZE(ramp_table_77802_2bit), ramp_delay);
-
- return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- MAX77802_RAMP_RATE_MASK_2BIT,
- ramp_value << MAX77802_RAMP_RATE_SHIFT_2BIT);
-}
-
-/* For BUCK1, 6 */
-static int max77802_set_ramp_delay_4bit(struct regulator_dev *rdev,
- int ramp_delay)
-{
- unsigned int ramp_value;
-
- ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_4bit,
- ARRAY_SIZE(ramp_table_77802_4bit), ramp_delay);
-
- return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- MAX77802_RAMP_RATE_MASK_4BIT,
- ramp_value << MAX77802_RAMP_RATE_SHIFT_4BIT);
-}
-
/*
* LDOs 2, 4-19, 22-35
*/
@@ -316,7 +263,7 @@ static const struct regulator_ops max77802_buck_16_dvs_ops = {
.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_ramp_delay = max77802_set_ramp_delay_4bit,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
.set_suspend_disable = max77802_set_suspend_disable,
};
@@ -330,7 +277,7 @@ static const struct regulator_ops max77802_buck_234_ops = {
.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_ramp_delay = max77802_set_ramp_delay_2bit,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
.set_suspend_disable = max77802_set_suspend_disable,
.set_suspend_mode = max77802_set_suspend_mode,
};
@@ -345,7 +292,6 @@ static const struct regulator_ops max77802_buck_dvs_ops = {
.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_ramp_delay = max77802_set_ramp_delay_2bit,
.set_suspend_disable = max77802_set_suspend_disable,
};
@@ -409,6 +355,10 @@ static const struct regulator_ops max77802_buck_dvs_ops = {
.vsel_mask = MAX77802_DVS_VSEL_MASK, \
.enable_reg = MAX77802_REG_BUCK ## num ## CTRL, \
.enable_mask = MAX77802_OPMODE_MASK, \
+ .ramp_reg = MAX77802_REG_BUCK ## num ## CTRL, \
+ .ramp_mask = MAX77802_RAMP_RATE_MASK_4BIT, \
+ .ramp_delay_table = max77802_buck16_ramp_table, \
+ .n_ramp_values = ARRAY_SIZE(max77802_buck16_ramp_table), \
.of_map_mode = max77802_map_mode, \
}
@@ -431,6 +381,10 @@ static const struct regulator_ops max77802_buck_dvs_ops = {
.enable_reg = MAX77802_REG_BUCK ## num ## CTRL1, \
.enable_mask = MAX77802_OPMODE_MASK << \
MAX77802_OPMODE_BUCK234_SHIFT, \
+ .ramp_reg = MAX77802_REG_BUCK ## num ## CTRL1, \
+ .ramp_mask = MAX77802_RAMP_RATE_MASK_2BIT, \
+ .ramp_delay_table = max77802_buck234_ramp_table, \
+ .n_ramp_values = ARRAY_SIZE(max77802_buck234_ramp_table), \
.of_map_mode = max77802_map_mode, \
}
diff --git a/drivers/regulator/max8893.c b/drivers/regulator/max8893.c
new file mode 100644
index 000000000000..1519bf760da7
--- /dev/null
+++ b/drivers/regulator/max8893.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+
+static const struct regulator_ops max8893_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+};
+
+static const struct regulator_desc max8893_regulators[] = {
+ {
+ .name = "BUCK",
+ .supply_name = "in-buck",
+ .of_match = of_match_ptr("buck"),
+ .regulators_node = of_match_ptr("regulators"),
+ .n_voltages = 0x11,
+ .id = 6,
+ .ops = &max8893_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .min_uV = 800000,
+ .uV_step = 100000,
+ .vsel_reg = 0x4,
+ .vsel_mask = 0x1f,
+ .enable_reg = 0x0,
+ .enable_mask = BIT(7),
+ },
+ {
+ .name = "LDO1",
+ .supply_name = "in-ldo1",
+ .of_match = of_match_ptr("ldo1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .n_voltages = 0x12,
+ .id = 1,
+ .ops = &max8893_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .min_uV = 1600000,
+ .uV_step = 100000,
+ .vsel_reg = 0x5,
+ .vsel_mask = 0x1f,
+ .enable_reg = 0x0,
+ .enable_mask = BIT(5),
+ },
+ {
+ .name = "LDO2",
+ .supply_name = "in-ldo2",
+ .of_match = of_match_ptr("ldo2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .n_voltages = 0x16,
+ .id = 2,
+ .ops = &max8893_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .min_uV = 1200000,
+ .uV_step = 100000,
+ .vsel_reg = 0x6,
+ .vsel_mask = 0x1f,
+ .enable_reg = 0x0,
+ .enable_mask = BIT(4),
+ },
+ {
+ .name = "LDO3",
+ .supply_name = "in-ldo3",
+ .of_match = of_match_ptr("ldo3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .n_voltages = 0x12,
+ .id = 3,
+ .ops = &max8893_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .min_uV = 1600000,
+ .uV_step = 100000,
+ .vsel_reg = 0x7,
+ .vsel_mask = 0x1f,
+ .enable_reg = 0x0,
+ .enable_mask = BIT(3),
+ },
+ {
+ .name = "LDO4",
+ .supply_name = "in-ldo4",
+ .of_match = of_match_ptr("ldo4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .n_voltages = 0x1a,
+ .id = 4,
+ .ops = &max8893_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .min_uV = 800000,
+ .uV_step = 100000,
+ .vsel_reg = 0x8,
+ .vsel_mask = 0x1f,
+ .enable_reg = 0x0,
+ .enable_mask = BIT(2),
+ },
+ {
+ .name = "LDO5",
+ .supply_name = "in-ldo5",
+ .of_match = of_match_ptr("ldo5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .n_voltages = 0x1a,
+ .id = 5,
+ .ops = &max8893_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .min_uV = 800000,
+ .uV_step = 100000,
+ .vsel_reg = 0x9,
+ .vsel_mask = 0x1f,
+ .enable_reg = 0x0,
+ .enable_mask = BIT(1),
+ }
+};
+
+static const struct regmap_config max8893_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int max8893_probe_new(struct i2c_client *i2c)
+{
+ int id, ret;
+ struct regulator_config config = {.dev = &i2c->dev};
+ struct regmap *regmap = devm_regmap_init_i2c(i2c, &max8893_regmap);
+
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+ dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
+ return ret;
+ }
+
+ for (id = 0; id < ARRAY_SIZE(max8893_regulators); id++) {
+ struct regulator_dev *rdev;
+ rdev = devm_regulator_register(&i2c->dev,
+ &max8893_regulators[id],
+ &config);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(&i2c->dev, "failed to register %s: %d\n",
+ max8893_regulators[id].name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id max8893_dt_match[] = {
+ { .compatible = "maxim,max8893" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, max8893_dt_match);
+#endif
+
+static const struct i2c_device_id max8893_ids[] = {
+ { "max8893", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, max8893_ids);
+
+static struct i2c_driver max8893_driver = {
+ .probe_new = max8893_probe_new,
+ .driver = {
+ .name = "max8893",
+ .of_match_table = of_match_ptr(max8893_dt_match),
+ },
+ .id_table = max8893_ids,
+};
+
+module_i2c_driver(max8893_driver);
+
+MODULE_DESCRIPTION("Maxim MAX8893 PMIC driver");
+MODULE_AUTHOR("Sergey Larin <cerg2010cerg2010@mail.ru>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c
index 9aee1444181d..8da8f9b6c4fd 100644
--- a/drivers/regulator/max8973-regulator.c
+++ b/drivers/regulator/max8973-regulator.c
@@ -265,33 +265,6 @@ static unsigned int max8973_dcdc_get_mode(struct regulator_dev *rdev)
REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
}
-static int max8973_set_ramp_delay(struct regulator_dev *rdev,
- int ramp_delay)
-{
- struct max8973_chip *max = rdev_get_drvdata(rdev);
- unsigned int control;
- int ret;
-
- /* Set ramp delay */
- if (ramp_delay <= 12000)
- control = MAX8973_RAMP_12mV_PER_US;
- else if (ramp_delay <= 25000)
- control = MAX8973_RAMP_25mV_PER_US;
- else if (ramp_delay <= 50000)
- control = MAX8973_RAMP_50mV_PER_US;
- else if (ramp_delay <= 200000)
- control = MAX8973_RAMP_200mV_PER_US;
- else
- return -EINVAL;
-
- ret = regmap_update_bits(max->regmap, MAX8973_CONTROL1,
- MAX8973_RAMP_MASK, control);
- if (ret < 0)
- dev_err(max->dev, "register %d update failed, %d",
- MAX8973_CONTROL1, ret);
- return ret;
-}
-
static int max8973_set_current_limit(struct regulator_dev *rdev,
int min_ua, int max_ua)
{
@@ -341,6 +314,10 @@ static int max8973_get_current_limit(struct regulator_dev *rdev)
return 9000000;
}
+static const unsigned int max8973_buck_ramp_table[] = {
+ 12000, 25000, 50000, 200000
+};
+
static const struct regulator_ops max8973_dcdc_ops = {
.get_voltage_sel = max8973_dcdc_get_voltage_sel,
.set_voltage_sel = max8973_dcdc_set_voltage_sel,
@@ -348,7 +325,7 @@ static const struct regulator_ops max8973_dcdc_ops = {
.set_mode = max8973_dcdc_set_mode,
.get_mode = max8973_dcdc_get_mode,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
- .set_ramp_delay = max8973_set_ramp_delay,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
};
static int max8973_init_dcdc(struct max8973_chip *max,
@@ -694,6 +671,10 @@ static int max8973_probe(struct i2c_client *client,
max->desc.min_uV = MAX8973_MIN_VOLATGE;
max->desc.uV_step = MAX8973_VOLATGE_STEP;
max->desc.n_voltages = MAX8973_BUCK_N_VOLTAGE;
+ max->desc.ramp_reg = MAX8973_CONTROL1;
+ max->desc.ramp_mask = MAX8973_RAMP_MASK;
+ max->desc.ramp_delay_table = max8973_buck_ramp_table;
+ max->desc.n_ramp_values = ARRAY_SIZE(max8973_buck_ramp_table);
max->dvs_gpio = (pdata->dvs_gpio) ? pdata->dvs_gpio : -EINVAL;
max->enable_external_control = pdata->enable_ext_control;
diff --git a/drivers/regulator/mcp16502.c b/drivers/regulator/mcp16502.c
index 88c6bd5b6c78..042668385678 100644
--- a/drivers/regulator/mcp16502.c
+++ b/drivers/regulator/mcp16502.c
@@ -90,10 +90,14 @@ enum mcp16502_reg {
};
/* Ramp delay (uV/us) for buck1, ldo1, ldo2. */
-static const int mcp16502_ramp_b1l12[] = { 6250, 3125, 2083, 1563 };
+static const unsigned int mcp16502_ramp_b1l12[] = {
+ 6250, 3125, 2083, 1563
+};
/* Ramp delay (uV/us) for buck2, buck3, buck4. */
-static const int mcp16502_ramp_b234[] = { 3125, 1563, 1042, 781 };
+static const unsigned int mcp16502_ramp_b234[] = {
+ 3125, 1563, 1042, 781
+};
static unsigned int mcp16502_of_map_mode(unsigned int mode)
{
@@ -103,7 +107,7 @@ static unsigned int mcp16502_of_map_mode(unsigned int mode)
return REGULATOR_MODE_INVALID;
}
-#define MCP16502_REGULATOR(_name, _id, _ranges, _ops) \
+#define MCP16502_REGULATOR(_name, _id, _ranges, _ops, _ramp_table) \
[_id] = { \
.name = _name, \
.regulators_node = of_match_ptr("regulators"), \
@@ -121,6 +125,10 @@ static unsigned int mcp16502_of_map_mode(unsigned int mode)
.vsel_mask = MCP16502_VSEL, \
.enable_reg = (((_id) + 1) << 4), \
.enable_mask = MCP16502_EN, \
+ .ramp_reg = MCP16502_REG_BASE(_id, CFG), \
+ .ramp_mask = MCP16502_DVSR, \
+ .ramp_delay_table = _ramp_table, \
+ .n_ramp_values = ARRAY_SIZE(_ramp_table), \
}
enum {
@@ -314,42 +322,6 @@ static int mcp16502_set_voltage_time_sel(struct regulator_dev *rdev,
return ret;
}
-static int mcp16502_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
- const int *ramp;
- int id = rdev_get_id(rdev);
- unsigned int i, size;
-
- switch (id) {
- case BUCK1:
- case LDO1:
- case LDO2:
- ramp = mcp16502_ramp_b1l12;
- size = ARRAY_SIZE(mcp16502_ramp_b1l12);
- break;
-
- case BUCK2:
- case BUCK3:
- case BUCK4:
- ramp = mcp16502_ramp_b234;
- size = ARRAY_SIZE(mcp16502_ramp_b234);
- break;
-
- default:
- return -EINVAL;
- }
-
- for (i = 0; i < size; i++) {
- if (ramp[i] == ramp_delay)
- break;
- }
- if (i == size)
- return -EINVAL;
-
- return regmap_update_bits(rdev->regmap, MCP16502_REG_BASE(id, CFG),
- MCP16502_DVSR, (i << 2));
-}
-
#ifdef CONFIG_SUSPEND
/*
* mcp16502_suspend_get_target_reg() - get the reg of the target suspend PMIC
@@ -445,7 +417,7 @@ static const struct regulator_ops mcp16502_buck_ops = {
.is_enabled = regulator_is_enabled_regmap,
.get_status = mcp16502_get_status,
.set_voltage_time_sel = mcp16502_set_voltage_time_sel,
- .set_ramp_delay = mcp16502_set_ramp_delay,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
.set_mode = mcp16502_set_mode,
.get_mode = mcp16502_get_mode,
@@ -471,7 +443,7 @@ static const struct regulator_ops mcp16502_ldo_ops = {
.is_enabled = regulator_is_enabled_regmap,
.get_status = mcp16502_get_status,
.set_voltage_time_sel = mcp16502_set_voltage_time_sel,
- .set_ramp_delay = mcp16502_set_ramp_delay,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
#ifdef CONFIG_SUSPEND
.set_suspend_voltage = mcp16502_set_suspend_voltage,
@@ -495,13 +467,19 @@ static const struct linear_range b234_ranges[] = {
};
static const struct regulator_desc mcp16502_desc[] = {
- /* MCP16502_REGULATOR(_name, _id, ranges, regulator_ops) */
- MCP16502_REGULATOR("VDD_IO", BUCK1, b1l12_ranges, mcp16502_buck_ops),
- MCP16502_REGULATOR("VDD_DDR", BUCK2, b234_ranges, mcp16502_buck_ops),
- MCP16502_REGULATOR("VDD_CORE", BUCK3, b234_ranges, mcp16502_buck_ops),
- MCP16502_REGULATOR("VDD_OTHER", BUCK4, b234_ranges, mcp16502_buck_ops),
- MCP16502_REGULATOR("LDO1", LDO1, b1l12_ranges, mcp16502_ldo_ops),
- MCP16502_REGULATOR("LDO2", LDO2, b1l12_ranges, mcp16502_ldo_ops)
+ /* MCP16502_REGULATOR(_name, _id, ranges, regulator_ops, ramp_table) */
+ MCP16502_REGULATOR("VDD_IO", BUCK1, b1l12_ranges, mcp16502_buck_ops,
+ mcp16502_ramp_b1l12),
+ MCP16502_REGULATOR("VDD_DDR", BUCK2, b234_ranges, mcp16502_buck_ops,
+ mcp16502_ramp_b234),
+ MCP16502_REGULATOR("VDD_CORE", BUCK3, b234_ranges, mcp16502_buck_ops,
+ mcp16502_ramp_b234),
+ MCP16502_REGULATOR("VDD_OTHER", BUCK4, b234_ranges, mcp16502_buck_ops,
+ mcp16502_ramp_b234),
+ MCP16502_REGULATOR("LDO1", LDO1, b1l12_ranges, mcp16502_ldo_ops,
+ mcp16502_ramp_b1l12),
+ MCP16502_REGULATOR("LDO2", LDO2, b1l12_ranges, mcp16502_ldo_ops,
+ mcp16502_ramp_b1l12)
};
static const struct regmap_range mcp16502_ranges[] = {
@@ -522,8 +500,7 @@ static const struct regmap_config mcp16502_regmap_config = {
.wr_table = &mcp16502_yes_reg_table,
};
-static int mcp16502_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mcp16502_probe(struct i2c_client *client)
{
struct regulator_config config = { };
struct regulator_dev *rdev;
@@ -606,7 +583,7 @@ static const struct i2c_device_id mcp16502_i2c_id[] = {
MODULE_DEVICE_TABLE(i2c, mcp16502_i2c_id);
static struct i2c_driver mcp16502_drv = {
- .probe = mcp16502_probe,
+ .probe_new = mcp16502_probe,
.driver = {
.name = "mcp16502-regulator",
.of_match_table = of_match_ptr(mcp16502_ids),
diff --git a/drivers/regulator/mp5416.c b/drivers/regulator/mp5416.c
index 67ce1b52a1a1..39cebec0edb6 100644
--- a/drivers/regulator/mp5416.c
+++ b/drivers/regulator/mp5416.c
@@ -67,6 +67,10 @@
.vsel_mask = MP5416_MASK_VSET, \
.enable_reg = MP5416_REG_BUCK ## _id, \
.enable_mask = MP5416_REGULATOR_EN, \
+ .ramp_reg = MP5416_REG_CTL2, \
+ .ramp_mask = MP5416_MASK_DVS_SLEWRATE, \
+ .ramp_delay_table = mp5416_buck_ramp_table, \
+ .n_ramp_values = ARRAY_SIZE(mp5416_buck_ramp_table), \
.active_discharge_on = _dval, \
.active_discharge_reg = _dreg, \
.active_discharge_mask = _dval, \
@@ -123,7 +127,16 @@ static const unsigned int mp5416_I_limits2[] = {
2200000, 3200000, 4200000, 5200000
};
-static int mp5416_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay);
+/*
+ * DVS ramp rate BUCK1 to BUCK4
+ * 00: 32mV/us
+ * 01: 16mV/us
+ * 10: 8mV/us
+ * 11: 4mV/us
+ */
+static const unsigned int mp5416_buck_ramp_table[] = {
+ 32000, 16000, 8000, 4000
+};
static const struct regulator_ops mp5416_ldo_ops = {
.enable = regulator_enable_regmap,
@@ -147,7 +160,7 @@ static const struct regulator_ops mp5416_buck_ops = {
.set_active_discharge = regulator_set_active_discharge_regmap,
.get_current_limit = regulator_get_current_limit_regmap,
.set_current_limit = regulator_set_current_limit_regmap,
- .set_ramp_delay = mp5416_set_ramp_delay,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
};
static struct regulator_desc mp5416_regulators_desc[MP5416_MAX_REGULATORS] = {
@@ -161,33 +174,6 @@ static struct regulator_desc mp5416_regulators_desc[MP5416_MAX_REGULATORS] = {
MP5416LDO("ldo4", 4, BIT(1)),
};
-/*
- * DVS ramp rate BUCK1 to BUCK4
- * 00: 32mV/us
- * 01: 16mV/us
- * 10: 8mV/us
- * 11: 4mV/us
- */
-static int mp5416_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
- unsigned int ramp_val;
-
- if (ramp_delay > 32000 || ramp_delay < 0)
- return -EINVAL;
-
- if (ramp_delay <= 4000)
- ramp_val = 3;
- else if (ramp_delay <= 8000)
- ramp_val = 2;
- else if (ramp_delay <= 16000)
- ramp_val = 1;
- else
- ramp_val = 0;
-
- return regmap_update_bits(rdev->regmap, MP5416_REG_CTL2,
- MP5416_MASK_DVS_SLEWRATE, ramp_val << 6);
-}
-
static int mp5416_i2c_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
diff --git a/drivers/regulator/mp886x.c b/drivers/regulator/mp886x.c
index a84fd74081de..8ad4722eca4b 100644
--- a/drivers/regulator/mp886x.c
+++ b/drivers/regulator/mp886x.c
@@ -26,7 +26,7 @@
struct mp886x_cfg_info {
const struct regulator_ops *rops;
- const int slew_rates[8];
+ const unsigned int slew_rates[8];
const int switch_freq[4];
const u8 fs_reg;
const u8 fs_shift;
@@ -42,28 +42,6 @@ struct mp886x_device_info {
unsigned int sel;
};
-static int mp886x_set_ramp(struct regulator_dev *rdev, int ramp)
-{
- struct mp886x_device_info *di = rdev_get_drvdata(rdev);
- const struct mp886x_cfg_info *ci = di->ci;
- int reg = -1, i;
-
- for (i = 0; i < ARRAY_SIZE(ci->slew_rates); i++) {
- if (ramp <= ci->slew_rates[i])
- reg = i;
- else
- break;
- }
-
- if (reg < 0) {
- dev_err(di->dev, "unsupported ramp value %d\n", ramp);
- return -EINVAL;
- }
-
- return regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,
- MP886X_SLEW_MASK, reg << MP886X_SLEW_SHIFT);
-}
-
static void mp886x_set_switch_freq(struct mp886x_device_info *di,
struct regmap *regmap,
u32 freq)
@@ -169,7 +147,7 @@ static const struct regulator_ops mp8869_regulator_ops = {
.is_enabled = regulator_is_enabled_regmap,
.set_mode = mp886x_set_mode,
.get_mode = mp886x_get_mode,
- .set_ramp_delay = mp886x_set_ramp,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
};
static const struct mp886x_cfg_info mp8869_ci = {
@@ -248,7 +226,7 @@ static const struct regulator_ops mp8867_regulator_ops = {
.is_enabled = regulator_is_enabled_regmap,
.set_mode = mp886x_set_mode,
.get_mode = mp886x_get_mode,
- .set_ramp_delay = mp886x_set_ramp,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
};
static const struct mp886x_cfg_info mp8867_ci = {
@@ -290,6 +268,10 @@ static int mp886x_regulator_register(struct mp886x_device_info *di,
rdesc->uV_step = 10000;
rdesc->vsel_reg = MP886X_VSEL;
rdesc->vsel_mask = 0x3f;
+ rdesc->ramp_reg = MP886X_SYSCNTLREG1;
+ rdesc->ramp_mask = MP886X_SLEW_MASK;
+ rdesc->ramp_delay_table = di->ci->slew_rates;
+ rdesc->n_ramp_values = ARRAY_SIZE(di->ci->slew_rates);
rdesc->owner = THIS_MODULE;
rdev = devm_regulator_register(di->dev, &di->desc, config);
diff --git a/drivers/regulator/mt6315-regulator.c b/drivers/regulator/mt6315-regulator.c
index 6b8be52c3772..284c229e1aa4 100644
--- a/drivers/regulator/mt6315-regulator.c
+++ b/drivers/regulator/mt6315-regulator.c
@@ -84,7 +84,7 @@ static unsigned int mt6315_regulator_get_mode(struct regulator_dev *rdev)
modeset_mask = init->modeset_mask[rdev_get_id(rdev)];
ret = regmap_read(rdev->regmap, MT6315_BUCK_TOP_4PHASE_ANA_CON42, &regval);
if (ret != 0) {
- dev_notice(&rdev->dev, "Failed to get mode: %d\n", ret);
+ dev_err(&rdev->dev, "Failed to get mode: %d\n", ret);
return ret;
}
@@ -93,7 +93,7 @@ static unsigned int mt6315_regulator_get_mode(struct regulator_dev *rdev)
ret = regmap_read(rdev->regmap, MT6315_BUCK_TOP_CON1, &regval);
if (ret != 0) {
- dev_notice(&rdev->dev, "Failed to get lp mode: %d\n", ret);
+ dev_err(&rdev->dev, "Failed to get lp mode: %d\n", ret);
return ret;
}
@@ -147,12 +147,12 @@ static int mt6315_regulator_set_mode(struct regulator_dev *rdev,
break;
default:
ret = -EINVAL;
- dev_notice(&rdev->dev, "Unsupported mode: %d\n", mode);
+ dev_err(&rdev->dev, "Unsupported mode: %d\n", mode);
break;
}
if (ret != 0) {
- dev_notice(&rdev->dev, "Failed to set mode: %d\n", ret);
+ dev_err(&rdev->dev, "Failed to set mode: %d\n", ret);
return ret;
}
@@ -168,7 +168,7 @@ static int mt6315_get_status(struct regulator_dev *rdev)
info = container_of(rdev->desc, struct mt6315_regulator_info, desc);
ret = regmap_read(rdev->regmap, info->status_reg, &regval);
if (ret < 0) {
- dev_notice(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+ dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
return ret;
}
@@ -223,8 +223,8 @@ static int mt6315_regulator_probe(struct spmi_device *pdev)
int i;
regmap = devm_regmap_init_spmi_ext(pdev, &mt6315_regmap_config);
- if (!regmap)
- return -ENODEV;
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
chip = devm_kzalloc(dev, sizeof(struct mt6315_chip), GFP_KERNEL);
if (!chip)
@@ -260,8 +260,9 @@ static int mt6315_regulator_probe(struct spmi_device *pdev)
config.driver_data = init_data;
rdev = devm_regulator_register(dev, &mt6315_regulators[i].desc, &config);
if (IS_ERR(rdev)) {
- dev_notice(dev, "Failed to register %s\n", mt6315_regulators[i].desc.name);
- continue;
+ dev_err(dev, "Failed to register %s\n",
+ mt6315_regulators[i].desc.name);
+ return PTR_ERR(rdev);
}
}
@@ -279,7 +280,7 @@ static void mt6315_regulator_shutdown(struct spmi_device *pdev)
ret |= regmap_write(chip->regmap, MT6315_TOP_TMA_KEY, 0);
ret |= regmap_write(chip->regmap, MT6315_TOP_TMA_KEY_H, 0);
if (ret < 0)
- dev_notice(&pdev->dev, "[%#x] Failed to enable power off sequence. %d\n",
+ dev_err(&pdev->dev, "[%#x] Failed to enable power off sequence. %d\n",
pdev->usid, ret);
}
diff --git a/drivers/regulator/mt6358-regulator.c b/drivers/regulator/mt6358-regulator.c
index 13cb6ac9a892..0d35be4e0e5a 100644
--- a/drivers/regulator/mt6358-regulator.c
+++ b/drivers/regulator/mt6358-regulator.c
@@ -153,50 +153,50 @@ static const struct linear_range buck_volt_range4[] = {
REGULATOR_LINEAR_RANGE(1000000, 0, 0x7f, 12500),
};
-static const u32 vdram2_voltages[] = {
+static const unsigned int vdram2_voltages[] = {
600000, 1800000,
};
-static const u32 vsim_voltages[] = {
+static const unsigned int vsim_voltages[] = {
1700000, 1800000, 2700000, 3000000, 3100000,
};
-static const u32 vibr_voltages[] = {
+static const unsigned int vibr_voltages[] = {
1200000, 1300000, 1500000, 1800000,
2000000, 2800000, 3000000, 3300000,
};
-static const u32 vusb_voltages[] = {
+static const unsigned int vusb_voltages[] = {
3000000, 3100000,
};
-static const u32 vcamd_voltages[] = {
+static const unsigned int vcamd_voltages[] = {
900000, 1000000, 1100000, 1200000,
1300000, 1500000, 1800000,
};
-static const u32 vefuse_voltages[] = {
+static const unsigned int vefuse_voltages[] = {
1700000, 1800000, 1900000,
};
-static const u32 vmch_vemc_voltages[] = {
+static const unsigned int vmch_vemc_voltages[] = {
2900000, 3000000, 3300000,
};
-static const u32 vcama_voltages[] = {
+static const unsigned int vcama_voltages[] = {
1800000, 2500000, 2700000,
2800000, 2900000, 3000000,
};
-static const u32 vcn33_bt_wifi_voltages[] = {
+static const unsigned int vcn33_bt_wifi_voltages[] = {
3300000, 3400000, 3500000,
};
-static const u32 vmc_voltages[] = {
+static const unsigned int vmc_voltages[] = {
1800000, 2900000, 3000000, 3300000,
};
-static const u32 vldo28_voltages[] = {
+static const unsigned int vldo28_voltages[] = {
2800000, 3000000,
};
@@ -457,7 +457,7 @@ static struct mt6358_regulator_info mt6358_regulators[] = {
MT6358_REG_FIXED("ldo_vaud28", VAUD28,
MT6358_LDO_VAUD28_CON0, 0, 2800000),
MT6358_LDO("ldo_vdram2", VDRAM2, vdram2_voltages, vdram2_idx,
- MT6358_LDO_VDRAM2_CON0, 0, MT6358_LDO_VDRAM2_ELR0, 0x10, 0),
+ MT6358_LDO_VDRAM2_CON0, 0, MT6358_LDO_VDRAM2_ELR0, 0xf, 0),
MT6358_LDO("ldo_vsim1", VSIM1, vsim_voltages, vsim_idx,
MT6358_LDO_VSIM1_CON0, 0, MT6358_VSIM1_ANA_CON0, 0xf00, 8),
MT6358_LDO("ldo_vibr", VIBR, vibr_voltages, vibr_idx,
diff --git a/drivers/regulator/mt6359-regulator.c b/drivers/regulator/mt6359-regulator.c
new file mode 100644
index 000000000000..7ce0bd377a08
--- /dev/null
+++ b/drivers/regulator/mt6359-regulator.c
@@ -0,0 +1,997 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2021 MediaTek Inc.
+
+#include <linux/platform_device.h>
+#include <linux/mfd/mt6359/registers.h>
+#include <linux/mfd/mt6359p/registers.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6359-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6359_BUCK_MODE_AUTO 0
+#define MT6359_BUCK_MODE_FORCE_PWM 1
+#define MT6359_BUCK_MODE_NORMAL 0
+#define MT6359_BUCK_MODE_LP 2
+
+/*
+ * MT6359 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @status_reg: for query status of regulators.
+ * @qi: Mask for query enable signal status of regulators.
+ * @modeset_reg: for operating AUTO/PWM mode register.
+ * @modeset_mask: MASK for operating modeset register.
+ * @modeset_shift: SHIFT for operating modeset register.
+ */
+struct mt6359_regulator_info {
+ struct regulator_desc desc;
+ u32 status_reg;
+ u32 qi;
+ u32 modeset_reg;
+ u32 modeset_mask;
+ u32 modeset_shift;
+ u32 lp_mode_reg;
+ u32 lp_mode_mask;
+ u32 lp_mode_shift;
+};
+
+#define MT6359_BUCK(match, _name, min, max, step, \
+ _enable_reg, _status_reg, \
+ _vsel_reg, _vsel_mask, \
+ _lp_mode_reg, _lp_mode_shift, \
+ _modeset_reg, _modeset_shift) \
+[MT6359_ID_##_name] = { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &mt6359_volt_linear_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6359_ID_##_name, \
+ .owner = THIS_MODULE, \
+ .uV_step = (step), \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .min_uV = (min), \
+ .vsel_reg = _vsel_reg, \
+ .vsel_mask = _vsel_mask, \
+ .enable_reg = _enable_reg, \
+ .enable_mask = BIT(0), \
+ .of_map_mode = mt6359_map_mode, \
+ }, \
+ .status_reg = _status_reg, \
+ .qi = BIT(0), \
+ .lp_mode_reg = _lp_mode_reg, \
+ .lp_mode_mask = BIT(_lp_mode_shift), \
+ .lp_mode_shift = _lp_mode_shift, \
+ .modeset_reg = _modeset_reg, \
+ .modeset_mask = BIT(_modeset_shift), \
+ .modeset_shift = _modeset_shift \
+}
+
+#define MT6359_LDO_LINEAR(match, _name, min, max, step, \
+ _enable_reg, _status_reg, _vsel_reg, _vsel_mask) \
+[MT6359_ID_##_name] = { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &mt6359_volt_linear_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6359_ID_##_name, \
+ .owner = THIS_MODULE, \
+ .uV_step = (step), \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .min_uV = (min), \
+ .vsel_reg = _vsel_reg, \
+ .vsel_mask = _vsel_mask, \
+ .enable_reg = _enable_reg, \
+ .enable_mask = BIT(0), \
+ }, \
+ .status_reg = _status_reg, \
+ .qi = BIT(0), \
+}
+
+#define MT6359_LDO(match, _name, _volt_table, \
+ _enable_reg, _enable_mask, _status_reg, \
+ _vsel_reg, _vsel_mask, _en_delay) \
+[MT6359_ID_##_name] = { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &mt6359_volt_table_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6359_ID_##_name, \
+ .owner = THIS_MODULE, \
+ .n_voltages = ARRAY_SIZE(_volt_table), \
+ .volt_table = _volt_table, \
+ .vsel_reg = _vsel_reg, \
+ .vsel_mask = _vsel_mask, \
+ .enable_reg = _enable_reg, \
+ .enable_mask = BIT(_enable_mask), \
+ .enable_time = _en_delay, \
+ }, \
+ .status_reg = _status_reg, \
+ .qi = BIT(0), \
+}
+
+#define MT6359_REG_FIXED(match, _name, _enable_reg, \
+ _status_reg, _fixed_volt) \
+[MT6359_ID_##_name] = { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &mt6359_volt_fixed_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6359_ID_##_name, \
+ .owner = THIS_MODULE, \
+ .n_voltages = 1, \
+ .enable_reg = _enable_reg, \
+ .enable_mask = BIT(0), \
+ .fixed_uV = (_fixed_volt), \
+ }, \
+ .status_reg = _status_reg, \
+ .qi = BIT(0), \
+}
+
+#define MT6359P_LDO1(match, _name, _ops, _volt_table, \
+ _enable_reg, _enable_mask, _status_reg, \
+ _vsel_reg, _vsel_mask) \
+[MT6359_ID_##_name] = { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6359_ID_##_name, \
+ .owner = THIS_MODULE, \
+ .n_voltages = ARRAY_SIZE(_volt_table), \
+ .volt_table = _volt_table, \
+ .vsel_reg = _vsel_reg, \
+ .vsel_mask = _vsel_mask, \
+ .enable_reg = _enable_reg, \
+ .enable_mask = BIT(_enable_mask), \
+ }, \
+ .status_reg = _status_reg, \
+ .qi = BIT(0), \
+}
+
+static const unsigned int vsim1_voltages[] = {
+ 0, 0, 0, 1700000, 1800000, 0, 0, 0, 2700000, 0, 0, 3000000, 3100000,
+};
+
+static const unsigned int vibr_voltages[] = {
+ 1200000, 1300000, 1500000, 0, 1800000, 2000000, 0, 0, 2700000, 2800000,
+ 0, 3000000, 0, 3300000,
+};
+
+static const unsigned int vrf12_voltages[] = {
+ 0, 0, 1100000, 1200000, 1300000,
+};
+
+static const unsigned int volt18_voltages[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1700000, 1800000, 1900000,
+};
+
+static const unsigned int vcn13_voltages[] = {
+ 900000, 1000000, 0, 1200000, 1300000,
+};
+
+static const unsigned int vcn33_voltages[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2800000, 0, 0, 0, 3300000, 3400000, 3500000,
+};
+
+static const unsigned int vefuse_voltages[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1700000, 1800000, 1900000, 2000000,
+};
+
+static const unsigned int vxo22_voltages[] = {
+ 1800000, 0, 0, 0, 2200000,
+};
+
+static const unsigned int vrfck_voltages[] = {
+ 0, 0, 1500000, 0, 0, 0, 0, 1600000, 0, 0, 0, 0, 1700000,
+};
+
+static const unsigned int vrfck_voltages_1[] = {
+ 1240000, 1600000,
+};
+
+static const unsigned int vio28_voltages[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2800000, 2900000, 3000000, 3100000, 3300000,
+};
+
+static const unsigned int vemc_voltages[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2900000, 3000000, 0, 3300000,
+};
+
+static const unsigned int vemc_voltages_1[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 2500000, 2800000, 2900000, 3000000, 3100000,
+ 3300000,
+};
+
+static const unsigned int va12_voltages[] = {
+ 0, 0, 0, 0, 0, 0, 1200000, 1300000,
+};
+
+static const unsigned int va09_voltages[] = {
+ 0, 0, 800000, 900000, 0, 0, 1200000,
+};
+
+static const unsigned int vrf18_voltages[] = {
+ 0, 0, 0, 0, 0, 1700000, 1800000, 1810000,
+};
+
+static const unsigned int vbbck_voltages[] = {
+ 0, 0, 0, 0, 1100000, 0, 0, 0, 1150000, 0, 0, 0, 1200000,
+};
+
+static const unsigned int vsim2_voltages[] = {
+ 0, 0, 0, 1700000, 1800000, 0, 0, 0, 2700000, 0, 0, 3000000, 3100000,
+};
+
+static inline unsigned int mt6359_map_mode(unsigned int mode)
+{
+ switch (mode) {
+ case MT6359_BUCK_MODE_NORMAL:
+ return REGULATOR_MODE_NORMAL;
+ case MT6359_BUCK_MODE_FORCE_PWM:
+ return REGULATOR_MODE_FAST;
+ case MT6359_BUCK_MODE_LP:
+ return REGULATOR_MODE_IDLE;
+ default:
+ return REGULATOR_MODE_INVALID;
+ }
+}
+
+static int mt6359_get_status(struct regulator_dev *rdev)
+{
+ int ret;
+ u32 regval;
+ struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
+
+ ret = regmap_read(rdev->regmap, info->status_reg, &regval);
+ if (ret != 0) {
+ dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+ return ret;
+ }
+
+ if (regval & info->qi)
+ return REGULATOR_STATUS_ON;
+ else
+ return REGULATOR_STATUS_OFF;
+}
+
+static unsigned int mt6359_regulator_get_mode(struct regulator_dev *rdev)
+{
+ struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret, regval;
+
+ ret = regmap_read(rdev->regmap, info->modeset_reg, &regval);
+ if (ret != 0) {
+ dev_err(&rdev->dev,
+ "Failed to get mt6359 buck mode: %d\n", ret);
+ return ret;
+ }
+
+ if ((regval & info->modeset_mask) >> info->modeset_shift ==
+ MT6359_BUCK_MODE_FORCE_PWM)
+ return REGULATOR_MODE_FAST;
+
+ ret = regmap_read(rdev->regmap, info->lp_mode_reg, &regval);
+ if (ret != 0) {
+ dev_err(&rdev->dev,
+ "Failed to get mt6359 buck lp mode: %d\n", ret);
+ return ret;
+ }
+
+ if (regval & info->lp_mode_mask)
+ return REGULATOR_MODE_IDLE;
+ else
+ return REGULATOR_MODE_NORMAL;
+}
+
+static int mt6359_regulator_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret = 0, val;
+ int curr_mode;
+
+ curr_mode = mt6359_regulator_get_mode(rdev);
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ val = MT6359_BUCK_MODE_FORCE_PWM;
+ val <<= info->modeset_shift;
+ ret = regmap_update_bits(rdev->regmap,
+ info->modeset_reg,
+ info->modeset_mask,
+ val);
+ break;
+ case REGULATOR_MODE_NORMAL:
+ if (curr_mode == REGULATOR_MODE_FAST) {
+ val = MT6359_BUCK_MODE_AUTO;
+ val <<= info->modeset_shift;
+ ret = regmap_update_bits(rdev->regmap,
+ info->modeset_reg,
+ info->modeset_mask,
+ val);
+ } else if (curr_mode == REGULATOR_MODE_IDLE) {
+ val = MT6359_BUCK_MODE_NORMAL;
+ val <<= info->lp_mode_shift;
+ ret = regmap_update_bits(rdev->regmap,
+ info->lp_mode_reg,
+ info->lp_mode_mask,
+ val);
+ udelay(100);
+ }
+ break;
+ case REGULATOR_MODE_IDLE:
+ val = MT6359_BUCK_MODE_LP >> 1;
+ val <<= info->lp_mode_shift;
+ ret = regmap_update_bits(rdev->regmap,
+ info->lp_mode_reg,
+ info->lp_mode_mask,
+ val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (ret != 0) {
+ dev_err(&rdev->dev,
+ "Failed to set mt6359 buck mode: %d\n", ret);
+ }
+
+ return ret;
+}
+
+static int mt6359p_vemc_set_voltage_sel(struct regulator_dev *rdev,
+ u32 sel)
+{
+ struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+ u32 val = 0;
+
+ sel <<= ffs(info->desc.vsel_mask) - 1;
+ ret = regmap_write(rdev->regmap, MT6359P_TMA_KEY_ADDR, TMA_KEY);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(rdev->regmap, MT6359P_VM_MODE_ADDR, &val);
+ if (ret)
+ return ret;
+
+ switch (val) {
+ case 0:
+ /* If HW trapping is 0, use VEMC_VOSEL_0 */
+ ret = regmap_update_bits(rdev->regmap,
+ info->desc.vsel_reg,
+ info->desc.vsel_mask, sel);
+ break;
+ case 1:
+ /* If HW trapping is 1, use VEMC_VOSEL_1 */
+ ret = regmap_update_bits(rdev->regmap,
+ info->desc.vsel_reg + 0x2,
+ info->desc.vsel_mask, sel);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (ret)
+ return ret;
+
+ ret = regmap_write(rdev->regmap, MT6359P_TMA_KEY_ADDR, 0);
+ return ret;
+}
+
+static int mt6359p_vemc_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+ u32 val = 0;
+
+ ret = regmap_read(rdev->regmap, MT6359P_VM_MODE_ADDR, &val);
+ if (ret)
+ return ret;
+ switch (val) {
+ case 0:
+ /* If HW trapping is 0, use VEMC_VOSEL_0 */
+ ret = regmap_read(rdev->regmap,
+ info->desc.vsel_reg, &val);
+ break;
+ case 1:
+ /* If HW trapping is 1, use VEMC_VOSEL_1 */
+ ret = regmap_read(rdev->regmap,
+ info->desc.vsel_reg + 0x2, &val);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (ret)
+ return ret;
+
+ val &= info->desc.vsel_mask;
+ val >>= ffs(info->desc.vsel_mask) - 1;
+
+ return val;
+}
+
+static const struct regulator_ops mt6359_volt_linear_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_status = mt6359_get_status,
+ .set_mode = mt6359_regulator_set_mode,
+ .get_mode = mt6359_regulator_get_mode,
+};
+
+static const struct regulator_ops mt6359_volt_table_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_iterate,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_status = mt6359_get_status,
+};
+
+static const struct regulator_ops mt6359_volt_fixed_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_status = mt6359_get_status,
+};
+
+static const struct regulator_ops mt6359p_vemc_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_iterate,
+ .set_voltage_sel = mt6359p_vemc_set_voltage_sel,
+ .get_voltage_sel = mt6359p_vemc_get_voltage_sel,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_status = mt6359_get_status,
+};
+
+/* The array is indexed by id(MT6359_ID_XXX) */
+static struct mt6359_regulator_info mt6359_regulators[] = {
+ MT6359_BUCK("buck_vs1", VS1, 800000, 2200000, 12500,
+ MT6359_RG_BUCK_VS1_EN_ADDR,
+ MT6359_DA_VS1_EN_ADDR, MT6359_RG_BUCK_VS1_VOSEL_ADDR,
+ MT6359_RG_BUCK_VS1_VOSEL_MASK <<
+ MT6359_RG_BUCK_VS1_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VS1_LP_ADDR, MT6359_RG_BUCK_VS1_LP_SHIFT,
+ MT6359_RG_VS1_FPWM_ADDR, MT6359_RG_VS1_FPWM_SHIFT),
+ MT6359_BUCK("buck_vgpu11", VGPU11, 400000, 1193750, 6250,
+ MT6359_RG_BUCK_VGPU11_EN_ADDR,
+ MT6359_DA_VGPU11_EN_ADDR, MT6359_RG_BUCK_VGPU11_VOSEL_ADDR,
+ MT6359_RG_BUCK_VGPU11_VOSEL_MASK <<
+ MT6359_RG_BUCK_VGPU11_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VGPU11_LP_ADDR,
+ MT6359_RG_BUCK_VGPU11_LP_SHIFT,
+ MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT),
+ MT6359_BUCK("buck_vmodem", VMODEM, 400000, 1100000, 6250,
+ MT6359_RG_BUCK_VMODEM_EN_ADDR,
+ MT6359_DA_VMODEM_EN_ADDR, MT6359_RG_BUCK_VMODEM_VOSEL_ADDR,
+ MT6359_RG_BUCK_VMODEM_VOSEL_MASK <<
+ MT6359_RG_BUCK_VMODEM_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VMODEM_LP_ADDR,
+ MT6359_RG_BUCK_VMODEM_LP_SHIFT,
+ MT6359_RG_VMODEM_FCCM_ADDR, MT6359_RG_VMODEM_FCCM_SHIFT),
+ MT6359_BUCK("buck_vpu", VPU, 400000, 1193750, 6250,
+ MT6359_RG_BUCK_VPU_EN_ADDR,
+ MT6359_DA_VPU_EN_ADDR, MT6359_RG_BUCK_VPU_VOSEL_ADDR,
+ MT6359_RG_BUCK_VPU_VOSEL_MASK <<
+ MT6359_RG_BUCK_VPU_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VPU_LP_ADDR, MT6359_RG_BUCK_VPU_LP_SHIFT,
+ MT6359_RG_VPU_FCCM_ADDR, MT6359_RG_VPU_FCCM_SHIFT),
+ MT6359_BUCK("buck_vcore", VCORE, 400000, 1193750, 6250,
+ MT6359_RG_BUCK_VCORE_EN_ADDR,
+ MT6359_DA_VCORE_EN_ADDR, MT6359_RG_BUCK_VCORE_VOSEL_ADDR,
+ MT6359_RG_BUCK_VCORE_VOSEL_MASK <<
+ MT6359_RG_BUCK_VCORE_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT,
+ MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT),
+ MT6359_BUCK("buck_vs2", VS2, 800000, 1600000, 12500,
+ MT6359_RG_BUCK_VS2_EN_ADDR,
+ MT6359_DA_VS2_EN_ADDR, MT6359_RG_BUCK_VS2_VOSEL_ADDR,
+ MT6359_RG_BUCK_VS2_VOSEL_MASK <<
+ MT6359_RG_BUCK_VS2_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VS2_LP_ADDR, MT6359_RG_BUCK_VS2_LP_SHIFT,
+ MT6359_RG_VS2_FPWM_ADDR, MT6359_RG_VS2_FPWM_SHIFT),
+ MT6359_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
+ MT6359_RG_BUCK_VPA_EN_ADDR,
+ MT6359_DA_VPA_EN_ADDR, MT6359_RG_BUCK_VPA_VOSEL_ADDR,
+ MT6359_RG_BUCK_VPA_VOSEL_MASK <<
+ MT6359_RG_BUCK_VPA_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VPA_LP_ADDR, MT6359_RG_BUCK_VPA_LP_SHIFT,
+ MT6359_RG_VPA_MODESET_ADDR, MT6359_RG_VPA_MODESET_SHIFT),
+ MT6359_BUCK("buck_vproc2", VPROC2, 400000, 1193750, 6250,
+ MT6359_RG_BUCK_VPROC2_EN_ADDR,
+ MT6359_DA_VPROC2_EN_ADDR, MT6359_RG_BUCK_VPROC2_VOSEL_ADDR,
+ MT6359_RG_BUCK_VPROC2_VOSEL_MASK <<
+ MT6359_RG_BUCK_VPROC2_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VPROC2_LP_ADDR,
+ MT6359_RG_BUCK_VPROC2_LP_SHIFT,
+ MT6359_RG_VPROC2_FCCM_ADDR, MT6359_RG_VPROC2_FCCM_SHIFT),
+ MT6359_BUCK("buck_vproc1", VPROC1, 400000, 1193750, 6250,
+ MT6359_RG_BUCK_VPROC1_EN_ADDR,
+ MT6359_DA_VPROC1_EN_ADDR, MT6359_RG_BUCK_VPROC1_VOSEL_ADDR,
+ MT6359_RG_BUCK_VPROC1_VOSEL_MASK <<
+ MT6359_RG_BUCK_VPROC1_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VPROC1_LP_ADDR,
+ MT6359_RG_BUCK_VPROC1_LP_SHIFT,
+ MT6359_RG_VPROC1_FCCM_ADDR, MT6359_RG_VPROC1_FCCM_SHIFT),
+ MT6359_BUCK("buck_vcore_sshub", VCORE_SSHUB, 400000, 1193750, 6250,
+ MT6359_RG_BUCK_VCORE_SSHUB_EN_ADDR,
+ MT6359_DA_VCORE_EN_ADDR,
+ MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_ADDR,
+ MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_MASK <<
+ MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT,
+ MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT),
+ MT6359_REG_FIXED("ldo_vaud18", VAUD18, MT6359_RG_LDO_VAUD18_EN_ADDR,
+ MT6359_DA_VAUD18_B_EN_ADDR, 1800000),
+ MT6359_LDO("ldo_vsim1", VSIM1, vsim1_voltages,
+ MT6359_RG_LDO_VSIM1_EN_ADDR, MT6359_RG_LDO_VSIM1_EN_SHIFT,
+ MT6359_DA_VSIM1_B_EN_ADDR, MT6359_RG_VSIM1_VOSEL_ADDR,
+ MT6359_RG_VSIM1_VOSEL_MASK << MT6359_RG_VSIM1_VOSEL_SHIFT,
+ 480),
+ MT6359_LDO("ldo_vibr", VIBR, vibr_voltages,
+ MT6359_RG_LDO_VIBR_EN_ADDR, MT6359_RG_LDO_VIBR_EN_SHIFT,
+ MT6359_DA_VIBR_B_EN_ADDR, MT6359_RG_VIBR_VOSEL_ADDR,
+ MT6359_RG_VIBR_VOSEL_MASK << MT6359_RG_VIBR_VOSEL_SHIFT,
+ 240),
+ MT6359_LDO("ldo_vrf12", VRF12, vrf12_voltages,
+ MT6359_RG_LDO_VRF12_EN_ADDR, MT6359_RG_LDO_VRF12_EN_SHIFT,
+ MT6359_DA_VRF12_B_EN_ADDR, MT6359_RG_VRF12_VOSEL_ADDR,
+ MT6359_RG_VRF12_VOSEL_MASK << MT6359_RG_VRF12_VOSEL_SHIFT,
+ 120),
+ MT6359_REG_FIXED("ldo_vusb", VUSB, MT6359_RG_LDO_VUSB_EN_0_ADDR,
+ MT6359_DA_VUSB_B_EN_ADDR, 3000000),
+ MT6359_LDO_LINEAR("ldo_vsram_proc2", VSRAM_PROC2, 500000, 1293750, 6250,
+ MT6359_RG_LDO_VSRAM_PROC2_EN_ADDR,
+ MT6359_DA_VSRAM_PROC2_B_EN_ADDR,
+ MT6359_RG_LDO_VSRAM_PROC2_VOSEL_ADDR,
+ MT6359_RG_LDO_VSRAM_PROC2_VOSEL_MASK <<
+ MT6359_RG_LDO_VSRAM_PROC2_VOSEL_SHIFT),
+ MT6359_LDO("ldo_vio18", VIO18, volt18_voltages,
+ MT6359_RG_LDO_VIO18_EN_ADDR, MT6359_RG_LDO_VIO18_EN_SHIFT,
+ MT6359_DA_VIO18_B_EN_ADDR, MT6359_RG_VIO18_VOSEL_ADDR,
+ MT6359_RG_VIO18_VOSEL_MASK << MT6359_RG_VIO18_VOSEL_SHIFT,
+ 960),
+ MT6359_LDO("ldo_vcamio", VCAMIO, volt18_voltages,
+ MT6359_RG_LDO_VCAMIO_EN_ADDR, MT6359_RG_LDO_VCAMIO_EN_SHIFT,
+ MT6359_DA_VCAMIO_B_EN_ADDR, MT6359_RG_VCAMIO_VOSEL_ADDR,
+ MT6359_RG_VCAMIO_VOSEL_MASK << MT6359_RG_VCAMIO_VOSEL_SHIFT,
+ 1290),
+ MT6359_REG_FIXED("ldo_vcn18", VCN18, MT6359_RG_LDO_VCN18_EN_ADDR,
+ MT6359_DA_VCN18_B_EN_ADDR, 1800000),
+ MT6359_REG_FIXED("ldo_vfe28", VFE28, MT6359_RG_LDO_VFE28_EN_ADDR,
+ MT6359_DA_VFE28_B_EN_ADDR, 2800000),
+ MT6359_LDO("ldo_vcn13", VCN13, vcn13_voltages,
+ MT6359_RG_LDO_VCN13_EN_ADDR, MT6359_RG_LDO_VCN13_EN_SHIFT,
+ MT6359_DA_VCN13_B_EN_ADDR, MT6359_RG_VCN13_VOSEL_ADDR,
+ MT6359_RG_VCN13_VOSEL_MASK << MT6359_RG_VCN13_VOSEL_SHIFT,
+ 240),
+ MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, vcn33_voltages,
+ MT6359_RG_LDO_VCN33_1_EN_0_ADDR,
+ MT6359_RG_LDO_VCN33_1_EN_0_SHIFT,
+ MT6359_DA_VCN33_1_B_EN_ADDR, MT6359_RG_VCN33_1_VOSEL_ADDR,
+ MT6359_RG_VCN33_1_VOSEL_MASK <<
+ MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
+ MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, vcn33_voltages,
+ MT6359_RG_LDO_VCN33_1_EN_1_ADDR,
+ MT6359_RG_LDO_VCN33_1_EN_1_SHIFT,
+ MT6359_DA_VCN33_1_B_EN_ADDR, MT6359_RG_VCN33_1_VOSEL_ADDR,
+ MT6359_RG_VCN33_1_VOSEL_MASK <<
+ MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
+ MT6359_REG_FIXED("ldo_vaux18", VAUX18, MT6359_RG_LDO_VAUX18_EN_ADDR,
+ MT6359_DA_VAUX18_B_EN_ADDR, 1800000),
+ MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750,
+ 6250,
+ MT6359_RG_LDO_VSRAM_OTHERS_EN_ADDR,
+ MT6359_DA_VSRAM_OTHERS_B_EN_ADDR,
+ MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_ADDR,
+ MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_MASK <<
+ MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_SHIFT),
+ MT6359_LDO("ldo_vefuse", VEFUSE, vefuse_voltages,
+ MT6359_RG_LDO_VEFUSE_EN_ADDR, MT6359_RG_LDO_VEFUSE_EN_SHIFT,
+ MT6359_DA_VEFUSE_B_EN_ADDR, MT6359_RG_VEFUSE_VOSEL_ADDR,
+ MT6359_RG_VEFUSE_VOSEL_MASK << MT6359_RG_VEFUSE_VOSEL_SHIFT,
+ 240),
+ MT6359_LDO("ldo_vxo22", VXO22, vxo22_voltages,
+ MT6359_RG_LDO_VXO22_EN_ADDR, MT6359_RG_LDO_VXO22_EN_SHIFT,
+ MT6359_DA_VXO22_B_EN_ADDR, MT6359_RG_VXO22_VOSEL_ADDR,
+ MT6359_RG_VXO22_VOSEL_MASK << MT6359_RG_VXO22_VOSEL_SHIFT,
+ 120),
+ MT6359_LDO("ldo_vrfck", VRFCK, vrfck_voltages,
+ MT6359_RG_LDO_VRFCK_EN_ADDR, MT6359_RG_LDO_VRFCK_EN_SHIFT,
+ MT6359_DA_VRFCK_B_EN_ADDR, MT6359_RG_VRFCK_VOSEL_ADDR,
+ MT6359_RG_VRFCK_VOSEL_MASK << MT6359_RG_VRFCK_VOSEL_SHIFT,
+ 480),
+ MT6359_REG_FIXED("ldo_vbif28", VBIF28, MT6359_RG_LDO_VBIF28_EN_ADDR,
+ MT6359_DA_VBIF28_B_EN_ADDR, 2800000),
+ MT6359_LDO("ldo_vio28", VIO28, vio28_voltages,
+ MT6359_RG_LDO_VIO28_EN_ADDR, MT6359_RG_LDO_VIO28_EN_SHIFT,
+ MT6359_DA_VIO28_B_EN_ADDR, MT6359_RG_VIO28_VOSEL_ADDR,
+ MT6359_RG_VIO28_VOSEL_MASK << MT6359_RG_VIO28_VOSEL_SHIFT,
+ 240),
+ MT6359_LDO("ldo_vemc", VEMC, vemc_voltages,
+ MT6359_RG_LDO_VEMC_EN_ADDR, MT6359_RG_LDO_VEMC_EN_SHIFT,
+ MT6359_DA_VEMC_B_EN_ADDR, MT6359_RG_VEMC_VOSEL_ADDR,
+ MT6359_RG_VEMC_VOSEL_MASK << MT6359_RG_VEMC_VOSEL_SHIFT,
+ 240),
+ MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, vcn33_voltages,
+ MT6359_RG_LDO_VCN33_2_EN_0_ADDR,
+ MT6359_RG_LDO_VCN33_2_EN_0_SHIFT,
+ MT6359_DA_VCN33_2_B_EN_ADDR, MT6359_RG_VCN33_2_VOSEL_ADDR,
+ MT6359_RG_VCN33_2_VOSEL_MASK <<
+ MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
+ MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, vcn33_voltages,
+ MT6359_RG_LDO_VCN33_2_EN_1_ADDR,
+ MT6359_RG_LDO_VCN33_2_EN_1_SHIFT,
+ MT6359_DA_VCN33_2_B_EN_ADDR, MT6359_RG_VCN33_2_VOSEL_ADDR,
+ MT6359_RG_VCN33_2_VOSEL_MASK <<
+ MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
+ MT6359_LDO("ldo_va12", VA12, va12_voltages,
+ MT6359_RG_LDO_VA12_EN_ADDR, MT6359_RG_LDO_VA12_EN_SHIFT,
+ MT6359_DA_VA12_B_EN_ADDR, MT6359_RG_VA12_VOSEL_ADDR,
+ MT6359_RG_VA12_VOSEL_MASK << MT6359_RG_VA12_VOSEL_SHIFT,
+ 240),
+ MT6359_LDO("ldo_va09", VA09, va09_voltages,
+ MT6359_RG_LDO_VA09_EN_ADDR, MT6359_RG_LDO_VA09_EN_SHIFT,
+ MT6359_DA_VA09_B_EN_ADDR, MT6359_RG_VA09_VOSEL_ADDR,
+ MT6359_RG_VA09_VOSEL_MASK << MT6359_RG_VA09_VOSEL_SHIFT,
+ 240),
+ MT6359_LDO("ldo_vrf18", VRF18, vrf18_voltages,
+ MT6359_RG_LDO_VRF18_EN_ADDR, MT6359_RG_LDO_VRF18_EN_SHIFT,
+ MT6359_DA_VRF18_B_EN_ADDR, MT6359_RG_VRF18_VOSEL_ADDR,
+ MT6359_RG_VRF18_VOSEL_MASK << MT6359_RG_VRF18_VOSEL_SHIFT,
+ 120),
+ MT6359_LDO_LINEAR("ldo_vsram_md", VSRAM_MD, 500000, 1100000, 6250,
+ MT6359_RG_LDO_VSRAM_MD_EN_ADDR,
+ MT6359_DA_VSRAM_MD_B_EN_ADDR,
+ MT6359_RG_LDO_VSRAM_MD_VOSEL_ADDR,
+ MT6359_RG_LDO_VSRAM_MD_VOSEL_MASK <<
+ MT6359_RG_LDO_VSRAM_MD_VOSEL_SHIFT),
+ MT6359_LDO("ldo_vufs", VUFS, volt18_voltages,
+ MT6359_RG_LDO_VUFS_EN_ADDR, MT6359_RG_LDO_VUFS_EN_SHIFT,
+ MT6359_DA_VUFS_B_EN_ADDR, MT6359_RG_VUFS_VOSEL_ADDR,
+ MT6359_RG_VUFS_VOSEL_MASK << MT6359_RG_VUFS_VOSEL_SHIFT,
+ 1920),
+ MT6359_LDO("ldo_vm18", VM18, volt18_voltages,
+ MT6359_RG_LDO_VM18_EN_ADDR, MT6359_RG_LDO_VM18_EN_SHIFT,
+ MT6359_DA_VM18_B_EN_ADDR, MT6359_RG_VM18_VOSEL_ADDR,
+ MT6359_RG_VM18_VOSEL_MASK << MT6359_RG_VM18_VOSEL_SHIFT,
+ 1920),
+ MT6359_LDO("ldo_vbbck", VBBCK, vbbck_voltages,
+ MT6359_RG_LDO_VBBCK_EN_ADDR, MT6359_RG_LDO_VBBCK_EN_SHIFT,
+ MT6359_DA_VBBCK_B_EN_ADDR, MT6359_RG_VBBCK_VOSEL_ADDR,
+ MT6359_RG_VBBCK_VOSEL_MASK << MT6359_RG_VBBCK_VOSEL_SHIFT,
+ 240),
+ MT6359_LDO_LINEAR("ldo_vsram_proc1", VSRAM_PROC1, 500000, 1293750, 6250,
+ MT6359_RG_LDO_VSRAM_PROC1_EN_ADDR,
+ MT6359_DA_VSRAM_PROC1_B_EN_ADDR,
+ MT6359_RG_LDO_VSRAM_PROC1_VOSEL_ADDR,
+ MT6359_RG_LDO_VSRAM_PROC1_VOSEL_MASK <<
+ MT6359_RG_LDO_VSRAM_PROC1_VOSEL_SHIFT),
+ MT6359_LDO("ldo_vsim2", VSIM2, vsim2_voltages,
+ MT6359_RG_LDO_VSIM2_EN_ADDR, MT6359_RG_LDO_VSIM2_EN_SHIFT,
+ MT6359_DA_VSIM2_B_EN_ADDR, MT6359_RG_VSIM2_VOSEL_ADDR,
+ MT6359_RG_VSIM2_VOSEL_MASK << MT6359_RG_VSIM2_VOSEL_SHIFT,
+ 480),
+ MT6359_LDO_LINEAR("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB,
+ 500000, 1293750, 6250,
+ MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_EN_ADDR,
+ MT6359_DA_VSRAM_OTHERS_B_EN_ADDR,
+ MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_ADDR,
+ MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_MASK <<
+ MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_SHIFT),
+};
+
+static struct mt6359_regulator_info mt6359p_regulators[] = {
+ MT6359_BUCK("buck_vs1", VS1, 800000, 2200000, 12500,
+ MT6359_RG_BUCK_VS1_EN_ADDR,
+ MT6359_DA_VS1_EN_ADDR, MT6359_RG_BUCK_VS1_VOSEL_ADDR,
+ MT6359_RG_BUCK_VS1_VOSEL_MASK <<
+ MT6359_RG_BUCK_VS1_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VS1_LP_ADDR, MT6359_RG_BUCK_VS1_LP_SHIFT,
+ MT6359_RG_VS1_FPWM_ADDR, MT6359_RG_VS1_FPWM_SHIFT),
+ MT6359_BUCK("buck_vgpu11", VGPU11, 400000, 1193750, 6250,
+ MT6359_RG_BUCK_VGPU11_EN_ADDR,
+ MT6359_DA_VGPU11_EN_ADDR, MT6359P_RG_BUCK_VGPU11_VOSEL_ADDR,
+ MT6359_RG_BUCK_VGPU11_VOSEL_MASK <<
+ MT6359_RG_BUCK_VGPU11_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VGPU11_LP_ADDR,
+ MT6359_RG_BUCK_VGPU11_LP_SHIFT,
+ MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT),
+ MT6359_BUCK("buck_vmodem", VMODEM, 400000, 1100000, 6250,
+ MT6359_RG_BUCK_VMODEM_EN_ADDR,
+ MT6359_DA_VMODEM_EN_ADDR, MT6359_RG_BUCK_VMODEM_VOSEL_ADDR,
+ MT6359_RG_BUCK_VMODEM_VOSEL_MASK <<
+ MT6359_RG_BUCK_VMODEM_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VMODEM_LP_ADDR,
+ MT6359_RG_BUCK_VMODEM_LP_SHIFT,
+ MT6359_RG_VMODEM_FCCM_ADDR, MT6359_RG_VMODEM_FCCM_SHIFT),
+ MT6359_BUCK("buck_vpu", VPU, 400000, 1193750, 6250,
+ MT6359_RG_BUCK_VPU_EN_ADDR,
+ MT6359_DA_VPU_EN_ADDR, MT6359_RG_BUCK_VPU_VOSEL_ADDR,
+ MT6359_RG_BUCK_VPU_VOSEL_MASK <<
+ MT6359_RG_BUCK_VPU_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VPU_LP_ADDR, MT6359_RG_BUCK_VPU_LP_SHIFT,
+ MT6359_RG_VPU_FCCM_ADDR, MT6359_RG_VPU_FCCM_SHIFT),
+ MT6359_BUCK("buck_vcore", VCORE, 506250, 1300000, 6250,
+ MT6359_RG_BUCK_VCORE_EN_ADDR,
+ MT6359_DA_VCORE_EN_ADDR, MT6359P_RG_BUCK_VCORE_VOSEL_ADDR,
+ MT6359_RG_BUCK_VCORE_VOSEL_MASK <<
+ MT6359_RG_BUCK_VCORE_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT,
+ MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT),
+ MT6359_BUCK("buck_vs2", VS2, 800000, 1600000, 12500,
+ MT6359_RG_BUCK_VS2_EN_ADDR,
+ MT6359_DA_VS2_EN_ADDR, MT6359_RG_BUCK_VS2_VOSEL_ADDR,
+ MT6359_RG_BUCK_VS2_VOSEL_MASK <<
+ MT6359_RG_BUCK_VS2_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VS2_LP_ADDR, MT6359_RG_BUCK_VS2_LP_SHIFT,
+ MT6359_RG_VS2_FPWM_ADDR, MT6359_RG_VS2_FPWM_SHIFT),
+ MT6359_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
+ MT6359_RG_BUCK_VPA_EN_ADDR,
+ MT6359_DA_VPA_EN_ADDR, MT6359_RG_BUCK_VPA_VOSEL_ADDR,
+ MT6359_RG_BUCK_VPA_VOSEL_MASK <<
+ MT6359_RG_BUCK_VPA_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VPA_LP_ADDR, MT6359_RG_BUCK_VPA_LP_SHIFT,
+ MT6359_RG_VPA_MODESET_ADDR, MT6359_RG_VPA_MODESET_SHIFT),
+ MT6359_BUCK("buck_vproc2", VPROC2, 400000, 1193750, 6250,
+ MT6359_RG_BUCK_VPROC2_EN_ADDR,
+ MT6359_DA_VPROC2_EN_ADDR, MT6359_RG_BUCK_VPROC2_VOSEL_ADDR,
+ MT6359_RG_BUCK_VPROC2_VOSEL_MASK <<
+ MT6359_RG_BUCK_VPROC2_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VPROC2_LP_ADDR,
+ MT6359_RG_BUCK_VPROC2_LP_SHIFT,
+ MT6359_RG_VPROC2_FCCM_ADDR, MT6359_RG_VPROC2_FCCM_SHIFT),
+ MT6359_BUCK("buck_vproc1", VPROC1, 400000, 1193750, 6250,
+ MT6359_RG_BUCK_VPROC1_EN_ADDR,
+ MT6359_DA_VPROC1_EN_ADDR, MT6359_RG_BUCK_VPROC1_VOSEL_ADDR,
+ MT6359_RG_BUCK_VPROC1_VOSEL_MASK <<
+ MT6359_RG_BUCK_VPROC1_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VPROC1_LP_ADDR,
+ MT6359_RG_BUCK_VPROC1_LP_SHIFT,
+ MT6359_RG_VPROC1_FCCM_ADDR, MT6359_RG_VPROC1_FCCM_SHIFT),
+ MT6359_BUCK("buck_vgpu11_sshub", VGPU11_SSHUB, 400000, 1193750, 6250,
+ MT6359P_RG_BUCK_VGPU11_SSHUB_EN_ADDR,
+ MT6359_DA_VGPU11_EN_ADDR,
+ MT6359P_RG_BUCK_VGPU11_SSHUB_VOSEL_ADDR,
+ MT6359P_RG_BUCK_VGPU11_SSHUB_VOSEL_MASK <<
+ MT6359P_RG_BUCK_VGPU11_SSHUB_VOSEL_SHIFT,
+ MT6359_RG_BUCK_VGPU11_LP_ADDR,
+ MT6359_RG_BUCK_VGPU11_LP_SHIFT,
+ MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT),
+ MT6359_REG_FIXED("ldo_vaud18", VAUD18, MT6359P_RG_LDO_VAUD18_EN_ADDR,
+ MT6359P_DA_VAUD18_B_EN_ADDR, 1800000),
+ MT6359_LDO("ldo_vsim1", VSIM1, vsim1_voltages,
+ MT6359P_RG_LDO_VSIM1_EN_ADDR, MT6359P_RG_LDO_VSIM1_EN_SHIFT,
+ MT6359P_DA_VSIM1_B_EN_ADDR, MT6359P_RG_VSIM1_VOSEL_ADDR,
+ MT6359_RG_VSIM1_VOSEL_MASK << MT6359_RG_VSIM1_VOSEL_SHIFT,
+ 480),
+ MT6359_LDO("ldo_vibr", VIBR, vibr_voltages,
+ MT6359P_RG_LDO_VIBR_EN_ADDR, MT6359P_RG_LDO_VIBR_EN_SHIFT,
+ MT6359P_DA_VIBR_B_EN_ADDR, MT6359P_RG_VIBR_VOSEL_ADDR,
+ MT6359_RG_VIBR_VOSEL_MASK << MT6359_RG_VIBR_VOSEL_SHIFT,
+ 240),
+ MT6359_LDO("ldo_vrf12", VRF12, vrf12_voltages,
+ MT6359P_RG_LDO_VRF12_EN_ADDR, MT6359P_RG_LDO_VRF12_EN_SHIFT,
+ MT6359P_DA_VRF12_B_EN_ADDR, MT6359P_RG_VRF12_VOSEL_ADDR,
+ MT6359_RG_VRF12_VOSEL_MASK << MT6359_RG_VRF12_VOSEL_SHIFT,
+ 480),
+ MT6359_REG_FIXED("ldo_vusb", VUSB, MT6359P_RG_LDO_VUSB_EN_0_ADDR,
+ MT6359P_DA_VUSB_B_EN_ADDR, 3000000),
+ MT6359_LDO_LINEAR("ldo_vsram_proc2", VSRAM_PROC2, 500000, 1293750, 6250,
+ MT6359P_RG_LDO_VSRAM_PROC2_EN_ADDR,
+ MT6359P_DA_VSRAM_PROC2_B_EN_ADDR,
+ MT6359P_RG_LDO_VSRAM_PROC2_VOSEL_ADDR,
+ MT6359_RG_LDO_VSRAM_PROC2_VOSEL_MASK <<
+ MT6359_RG_LDO_VSRAM_PROC2_VOSEL_SHIFT),
+ MT6359_LDO("ldo_vio18", VIO18, volt18_voltages,
+ MT6359P_RG_LDO_VIO18_EN_ADDR, MT6359P_RG_LDO_VIO18_EN_SHIFT,
+ MT6359P_DA_VIO18_B_EN_ADDR, MT6359P_RG_VIO18_VOSEL_ADDR,
+ MT6359_RG_VIO18_VOSEL_MASK << MT6359_RG_VIO18_VOSEL_SHIFT,
+ 960),
+ MT6359_LDO("ldo_vcamio", VCAMIO, volt18_voltages,
+ MT6359P_RG_LDO_VCAMIO_EN_ADDR,
+ MT6359P_RG_LDO_VCAMIO_EN_SHIFT,
+ MT6359P_DA_VCAMIO_B_EN_ADDR, MT6359P_RG_VCAMIO_VOSEL_ADDR,
+ MT6359_RG_VCAMIO_VOSEL_MASK << MT6359_RG_VCAMIO_VOSEL_SHIFT,
+ 1290),
+ MT6359_REG_FIXED("ldo_vcn18", VCN18, MT6359P_RG_LDO_VCN18_EN_ADDR,
+ MT6359P_DA_VCN18_B_EN_ADDR, 1800000),
+ MT6359_REG_FIXED("ldo_vfe28", VFE28, MT6359P_RG_LDO_VFE28_EN_ADDR,
+ MT6359P_DA_VFE28_B_EN_ADDR, 2800000),
+ MT6359_LDO("ldo_vcn13", VCN13, vcn13_voltages,
+ MT6359P_RG_LDO_VCN13_EN_ADDR, MT6359P_RG_LDO_VCN13_EN_SHIFT,
+ MT6359P_DA_VCN13_B_EN_ADDR, MT6359P_RG_VCN13_VOSEL_ADDR,
+ MT6359_RG_VCN13_VOSEL_MASK << MT6359_RG_VCN13_VOSEL_SHIFT,
+ 240),
+ MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, vcn33_voltages,
+ MT6359P_RG_LDO_VCN33_1_EN_0_ADDR,
+ MT6359_RG_LDO_VCN33_1_EN_0_SHIFT,
+ MT6359P_DA_VCN33_1_B_EN_ADDR, MT6359P_RG_VCN33_1_VOSEL_ADDR,
+ MT6359_RG_VCN33_1_VOSEL_MASK <<
+ MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
+ MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, vcn33_voltages,
+ MT6359P_RG_LDO_VCN33_1_EN_1_ADDR,
+ MT6359P_RG_LDO_VCN33_1_EN_1_SHIFT,
+ MT6359P_DA_VCN33_1_B_EN_ADDR, MT6359P_RG_VCN33_1_VOSEL_ADDR,
+ MT6359_RG_VCN33_1_VOSEL_MASK <<
+ MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
+ MT6359_REG_FIXED("ldo_vaux18", VAUX18, MT6359P_RG_LDO_VAUX18_EN_ADDR,
+ MT6359P_DA_VAUX18_B_EN_ADDR, 1800000),
+ MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750,
+ 6250,
+ MT6359P_RG_LDO_VSRAM_OTHERS_EN_ADDR,
+ MT6359P_DA_VSRAM_OTHERS_B_EN_ADDR,
+ MT6359P_RG_LDO_VSRAM_OTHERS_VOSEL_ADDR,
+ MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_MASK <<
+ MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_SHIFT),
+ MT6359_LDO("ldo_vefuse", VEFUSE, vefuse_voltages,
+ MT6359P_RG_LDO_VEFUSE_EN_ADDR,
+ MT6359P_RG_LDO_VEFUSE_EN_SHIFT,
+ MT6359P_DA_VEFUSE_B_EN_ADDR, MT6359P_RG_VEFUSE_VOSEL_ADDR,
+ MT6359_RG_VEFUSE_VOSEL_MASK << MT6359_RG_VEFUSE_VOSEL_SHIFT,
+ 240),
+ MT6359_LDO("ldo_vxo22", VXO22, vxo22_voltages,
+ MT6359P_RG_LDO_VXO22_EN_ADDR, MT6359P_RG_LDO_VXO22_EN_SHIFT,
+ MT6359P_DA_VXO22_B_EN_ADDR, MT6359P_RG_VXO22_VOSEL_ADDR,
+ MT6359_RG_VXO22_VOSEL_MASK << MT6359_RG_VXO22_VOSEL_SHIFT,
+ 480),
+ MT6359_LDO("ldo_vrfck_1", VRFCK, vrfck_voltages_1,
+ MT6359P_RG_LDO_VRFCK_EN_ADDR, MT6359P_RG_LDO_VRFCK_EN_SHIFT,
+ MT6359P_DA_VRFCK_B_EN_ADDR, MT6359P_RG_VRFCK_VOSEL_ADDR,
+ MT6359_RG_VRFCK_VOSEL_MASK << MT6359_RG_VRFCK_VOSEL_SHIFT,
+ 480),
+ MT6359_REG_FIXED("ldo_vbif28", VBIF28, MT6359P_RG_LDO_VBIF28_EN_ADDR,
+ MT6359P_DA_VBIF28_B_EN_ADDR, 2800000),
+ MT6359_LDO("ldo_vio28", VIO28, vio28_voltages,
+ MT6359P_RG_LDO_VIO28_EN_ADDR, MT6359P_RG_LDO_VIO28_EN_SHIFT,
+ MT6359P_DA_VIO28_B_EN_ADDR, MT6359P_RG_VIO28_VOSEL_ADDR,
+ MT6359_RG_VIO28_VOSEL_MASK << MT6359_RG_VIO28_VOSEL_SHIFT,
+ 1920),
+ MT6359P_LDO1("ldo_vemc_1", VEMC, mt6359p_vemc_ops, vemc_voltages_1,
+ MT6359P_RG_LDO_VEMC_EN_ADDR, MT6359P_RG_LDO_VEMC_EN_SHIFT,
+ MT6359P_DA_VEMC_B_EN_ADDR,
+ MT6359P_RG_LDO_VEMC_VOSEL_0_ADDR,
+ MT6359P_RG_LDO_VEMC_VOSEL_0_MASK <<
+ MT6359P_RG_LDO_VEMC_VOSEL_0_SHIFT),
+ MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, vcn33_voltages,
+ MT6359P_RG_LDO_VCN33_2_EN_0_ADDR,
+ MT6359P_RG_LDO_VCN33_2_EN_0_SHIFT,
+ MT6359P_DA_VCN33_2_B_EN_ADDR, MT6359P_RG_VCN33_2_VOSEL_ADDR,
+ MT6359_RG_VCN33_2_VOSEL_MASK <<
+ MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
+ MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, vcn33_voltages,
+ MT6359P_RG_LDO_VCN33_2_EN_1_ADDR,
+ MT6359_RG_LDO_VCN33_2_EN_1_SHIFT,
+ MT6359P_DA_VCN33_2_B_EN_ADDR, MT6359P_RG_VCN33_2_VOSEL_ADDR,
+ MT6359_RG_VCN33_2_VOSEL_MASK <<
+ MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
+ MT6359_LDO("ldo_va12", VA12, va12_voltages,
+ MT6359P_RG_LDO_VA12_EN_ADDR, MT6359P_RG_LDO_VA12_EN_SHIFT,
+ MT6359P_DA_VA12_B_EN_ADDR, MT6359P_RG_VA12_VOSEL_ADDR,
+ MT6359_RG_VA12_VOSEL_MASK << MT6359_RG_VA12_VOSEL_SHIFT,
+ 960),
+ MT6359_LDO("ldo_va09", VA09, va09_voltages,
+ MT6359P_RG_LDO_VA09_EN_ADDR, MT6359P_RG_LDO_VA09_EN_SHIFT,
+ MT6359P_DA_VA09_B_EN_ADDR, MT6359P_RG_VA09_VOSEL_ADDR,
+ MT6359_RG_VA09_VOSEL_MASK << MT6359_RG_VA09_VOSEL_SHIFT,
+ 960),
+ MT6359_LDO("ldo_vrf18", VRF18, vrf18_voltages,
+ MT6359P_RG_LDO_VRF18_EN_ADDR, MT6359P_RG_LDO_VRF18_EN_SHIFT,
+ MT6359P_DA_VRF18_B_EN_ADDR, MT6359P_RG_VRF18_VOSEL_ADDR,
+ MT6359_RG_VRF18_VOSEL_MASK << MT6359_RG_VRF18_VOSEL_SHIFT,
+ 240),
+ MT6359_LDO_LINEAR("ldo_vsram_md", VSRAM_MD, 500000, 1293750, 6250,
+ MT6359P_RG_LDO_VSRAM_MD_EN_ADDR,
+ MT6359P_DA_VSRAM_MD_B_EN_ADDR,
+ MT6359P_RG_LDO_VSRAM_MD_VOSEL_ADDR,
+ MT6359_RG_LDO_VSRAM_MD_VOSEL_MASK <<
+ MT6359_RG_LDO_VSRAM_MD_VOSEL_SHIFT),
+ MT6359_LDO("ldo_vufs", VUFS, volt18_voltages,
+ MT6359P_RG_LDO_VUFS_EN_ADDR, MT6359P_RG_LDO_VUFS_EN_SHIFT,
+ MT6359P_DA_VUFS_B_EN_ADDR, MT6359P_RG_VUFS_VOSEL_ADDR,
+ MT6359_RG_VUFS_VOSEL_MASK << MT6359_RG_VUFS_VOSEL_SHIFT,
+ 1920),
+ MT6359_LDO("ldo_vm18", VM18, volt18_voltages,
+ MT6359P_RG_LDO_VM18_EN_ADDR, MT6359P_RG_LDO_VM18_EN_SHIFT,
+ MT6359P_DA_VM18_B_EN_ADDR, MT6359P_RG_VM18_VOSEL_ADDR,
+ MT6359_RG_VM18_VOSEL_MASK << MT6359_RG_VM18_VOSEL_SHIFT,
+ 1920),
+ MT6359_LDO("ldo_vbbck", VBBCK, vbbck_voltages,
+ MT6359P_RG_LDO_VBBCK_EN_ADDR, MT6359P_RG_LDO_VBBCK_EN_SHIFT,
+ MT6359P_DA_VBBCK_B_EN_ADDR, MT6359P_RG_VBBCK_VOSEL_ADDR,
+ MT6359P_RG_VBBCK_VOSEL_MASK << MT6359P_RG_VBBCK_VOSEL_SHIFT,
+ 480),
+ MT6359_LDO_LINEAR("ldo_vsram_proc1", VSRAM_PROC1, 500000, 1293750, 6250,
+ MT6359P_RG_LDO_VSRAM_PROC1_EN_ADDR,
+ MT6359P_DA_VSRAM_PROC1_B_EN_ADDR,
+ MT6359P_RG_LDO_VSRAM_PROC1_VOSEL_ADDR,
+ MT6359_RG_LDO_VSRAM_PROC1_VOSEL_MASK <<
+ MT6359_RG_LDO_VSRAM_PROC1_VOSEL_SHIFT),
+ MT6359_LDO("ldo_vsim2", VSIM2, vsim2_voltages,
+ MT6359P_RG_LDO_VSIM2_EN_ADDR, MT6359P_RG_LDO_VSIM2_EN_SHIFT,
+ MT6359P_DA_VSIM2_B_EN_ADDR, MT6359P_RG_VSIM2_VOSEL_ADDR,
+ MT6359_RG_VSIM2_VOSEL_MASK << MT6359_RG_VSIM2_VOSEL_SHIFT,
+ 480),
+ MT6359_LDO_LINEAR("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB,
+ 500000, 1293750, 6250,
+ MT6359P_RG_LDO_VSRAM_OTHERS_SSHUB_EN_ADDR,
+ MT6359P_DA_VSRAM_OTHERS_B_EN_ADDR,
+ MT6359P_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_ADDR,
+ MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_MASK <<
+ MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_SHIFT),
+};
+
+static int mt6359_regulator_probe(struct platform_device *pdev)
+{
+ struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = {};
+ struct regulator_dev *rdev;
+ struct mt6359_regulator_info *mt6359_info;
+ int i, hw_ver;
+
+ regmap_read(mt6397->regmap, MT6359P_HWCID, &hw_ver);
+ if (hw_ver >= MT6359P_CHIP_VER)
+ mt6359_info = mt6359p_regulators;
+ else
+ mt6359_info = mt6359_regulators;
+
+ config.dev = mt6397->dev;
+ config.regmap = mt6397->regmap;
+ for (i = 0; i < MT6359_MAX_REGULATOR; i++, mt6359_info++) {
+ config.driver_data = mt6359_info;
+ rdev = devm_regulator_register(&pdev->dev, &mt6359_info->desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register %s\n", mt6359_info->desc.name);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id mt6359_platform_ids[] = {
+ {"mt6359-regulator", 0},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6359_platform_ids);
+
+static struct platform_driver mt6359_regulator_driver = {
+ .driver = {
+ .name = "mt6359-regulator",
+ },
+ .probe = mt6359_regulator_probe,
+ .id_table = mt6359_platform_ids,
+};
+
+module_platform_driver(mt6359_regulator_driver);
+
+MODULE_AUTHOR("Wen Su <wen.su@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6359 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 49f6c05fee34..f54d4f176882 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -21,6 +21,62 @@ static const char *const regulator_states[PM_SUSPEND_MAX + 1] = {
[PM_SUSPEND_MAX] = "regulator-state-disk",
};
+static void fill_limit(int *limit, int val)
+{
+ if (val)
+ if (val == 1)
+ *limit = REGULATOR_NOTIF_LIMIT_ENABLE;
+ else
+ *limit = val;
+ else
+ *limit = REGULATOR_NOTIF_LIMIT_DISABLE;
+}
+
+static void of_get_regulator_prot_limits(struct device_node *np,
+ struct regulation_constraints *constraints)
+{
+ u32 pval;
+ int i;
+ static const char *const props[] = {
+ "regulator-oc-%s-microamp",
+ "regulator-ov-%s-microvolt",
+ "regulator-temp-%s-kelvin",
+ "regulator-uv-%s-microvolt",
+ };
+ struct notification_limit *limits[] = {
+ &constraints->over_curr_limits,
+ &constraints->over_voltage_limits,
+ &constraints->temp_limits,
+ &constraints->under_voltage_limits,
+ };
+ bool set[4] = {0};
+
+ /* Protection limits: */
+ for (i = 0; i < ARRAY_SIZE(props); i++) {
+ char prop[255];
+ bool found;
+ int j;
+ static const char *const lvl[] = {
+ "protection", "error", "warn"
+ };
+ int *l[] = {
+ &limits[i]->prot, &limits[i]->err, &limits[i]->warn,
+ };
+
+ for (j = 0; j < ARRAY_SIZE(lvl); j++) {
+ snprintf(prop, 255, props[i], lvl[j]);
+ found = !of_property_read_u32(np, prop, &pval);
+ if (found)
+ fill_limit(l[j], pval);
+ set[i] |= found;
+ }
+ }
+ constraints->over_current_detection = set[0];
+ constraints->over_voltage_detection = set[1];
+ constraints->over_temp_detection = set[2];
+ constraints->under_voltage_detection = set[3];
+}
+
static int of_get_regulation_constraints(struct device *dev,
struct device_node *np,
struct regulator_init_data **init_data,
@@ -188,6 +244,8 @@ static int of_get_regulation_constraints(struct device *dev,
constraints->over_current_protection = of_property_read_bool(np,
"regulator-over-current-protection");
+ of_get_regulator_prot_limits(np, constraints);
+
for (i = 0; i < ARRAY_SIZE(regulator_states); i++) {
switch (i) {
case PM_SUSPEND_MEM:
diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c
index 2f7ee212cb8c..64e5f5f0cc84 100644
--- a/drivers/regulator/pca9450-regulator.c
+++ b/drivers/regulator/pca9450-regulator.c
@@ -65,32 +65,9 @@ static const struct regmap_config pca9450_regmap_config = {
* 10: 25mV/4usec
* 11: 25mV/8usec
*/
-static int pca9450_dvs_set_ramp_delay(struct regulator_dev *rdev,
- int ramp_delay)
-{
- int id = rdev_get_id(rdev);
- unsigned int ramp_value;
-
- switch (ramp_delay) {
- case 1 ... 3125:
- ramp_value = BUCK1_RAMP_3P125MV;
- break;
- case 3126 ... 6250:
- ramp_value = BUCK1_RAMP_6P25MV;
- break;
- case 6251 ... 12500:
- ramp_value = BUCK1_RAMP_12P5MV;
- break;
- case 12501 ... 25000:
- ramp_value = BUCK1_RAMP_25MV;
- break;
- default:
- ramp_value = BUCK1_RAMP_25MV;
- }
-
- return regmap_update_bits(rdev->regmap, PCA9450_REG_BUCK1CTRL + id * 3,
- BUCK1_RAMP_MASK, ramp_value << 6);
-}
+static const unsigned int pca9450_dvs_buck_ramp_table[] = {
+ 25000, 12500, 6250, 3125
+};
static const struct regulator_ops pca9450_dvs_buck_regulator_ops = {
.enable = regulator_enable_regmap,
@@ -100,7 +77,7 @@ static const struct regulator_ops pca9450_dvs_buck_regulator_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
- .set_ramp_delay = pca9450_dvs_set_ramp_delay,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
};
static const struct regulator_ops pca9450_buck_regulator_ops = {
@@ -251,6 +228,10 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.vsel_mask = BUCK1OUT_DVS0_MASK,
.enable_reg = PCA9450_REG_BUCK1CTRL,
.enable_mask = BUCK1_ENMODE_MASK,
+ .ramp_reg = PCA9450_REG_BUCK1CTRL,
+ .ramp_mask = BUCK1_RAMP_MASK,
+ .ramp_delay_table = pca9450_dvs_buck_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
.owner = THIS_MODULE,
.of_parse_cb = pca9450_set_dvs_levels,
},
@@ -276,6 +257,10 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.vsel_mask = BUCK2OUT_DVS0_MASK,
.enable_reg = PCA9450_REG_BUCK2CTRL,
.enable_mask = BUCK1_ENMODE_MASK,
+ .ramp_reg = PCA9450_REG_BUCK2CTRL,
+ .ramp_mask = BUCK2_RAMP_MASK,
+ .ramp_delay_table = pca9450_dvs_buck_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
.owner = THIS_MODULE,
.of_parse_cb = pca9450_set_dvs_levels,
},
@@ -301,6 +286,10 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.vsel_mask = BUCK3OUT_DVS0_MASK,
.enable_reg = PCA9450_REG_BUCK3CTRL,
.enable_mask = BUCK3_ENMODE_MASK,
+ .ramp_reg = PCA9450_REG_BUCK3CTRL,
+ .ramp_mask = BUCK3_RAMP_MASK,
+ .ramp_delay_table = pca9450_dvs_buck_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
.owner = THIS_MODULE,
.of_parse_cb = pca9450_set_dvs_levels,
},
@@ -477,6 +466,10 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
.vsel_mask = BUCK1OUT_DVS0_MASK,
.enable_reg = PCA9450_REG_BUCK1CTRL,
.enable_mask = BUCK1_ENMODE_MASK,
+ .ramp_reg = PCA9450_REG_BUCK1CTRL,
+ .ramp_mask = BUCK1_RAMP_MASK,
+ .ramp_delay_table = pca9450_dvs_buck_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
.owner = THIS_MODULE,
.of_parse_cb = pca9450_set_dvs_levels,
},
@@ -502,6 +495,10 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
.vsel_mask = BUCK2OUT_DVS0_MASK,
.enable_reg = PCA9450_REG_BUCK2CTRL,
.enable_mask = BUCK1_ENMODE_MASK,
+ .ramp_reg = PCA9450_REG_BUCK2CTRL,
+ .ramp_mask = BUCK2_RAMP_MASK,
+ .ramp_delay_table = pca9450_dvs_buck_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
.owner = THIS_MODULE,
.of_parse_cb = pca9450_set_dvs_levels,
},
diff --git a/drivers/regulator/qcom-labibb-regulator.c b/drivers/regulator/qcom-labibb-regulator.c
index de25e3279b4b..b3da0dc58782 100644
--- a/drivers/regulator/qcom-labibb-regulator.c
+++ b/drivers/regulator/qcom-labibb-regulator.c
@@ -307,13 +307,21 @@ end:
return IRQ_HANDLED;
}
-static int qcom_labibb_set_ocp(struct regulator_dev *rdev)
+static int qcom_labibb_set_ocp(struct regulator_dev *rdev, int lim,
+ int severity, bool enable)
{
struct labibb_regulator *vreg = rdev_get_drvdata(rdev);
char *ocp_irq_name;
u32 irq_flags = IRQF_ONESHOT;
int irq_trig_low, ret;
+ /*
+ * labibb supports only protection - and does not support setting
+ * limit. Furthermore, we don't support disabling protection.
+ */
+ if (lim || severity != REGULATOR_SEVERITY_PROT || !enable)
+ return -EINVAL;
+
/* If there is no OCP interrupt, there's nothing to set */
if (vreg->ocp_irq <= 0)
return -EINVAL;
diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c
index 22fec370fa61..6cca910a76de 100644
--- a/drivers/regulator/qcom-rpmh-regulator.c
+++ b/drivers/regulator/qcom-rpmh-regulator.c
@@ -811,12 +811,12 @@ static const struct rpmh_vreg_init_data pm8998_vreg_data[] = {
RPMH_VREG("ldo28", "ldo%s28", &pmic4_pldo, "vdd-l16-l28"),
RPMH_VREG("lvs1", "vs%s1", &pmic4_lvs, "vin-lvs-1-2"),
RPMH_VREG("lvs2", "vs%s2", &pmic4_lvs, "vin-lvs-1-2"),
- {},
+ {}
};
static const struct rpmh_vreg_init_data pmi8998_vreg_data[] = {
RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"),
- {},
+ {}
};
static const struct rpmh_vreg_init_data pm8005_vreg_data[] = {
@@ -824,7 +824,7 @@ static const struct rpmh_vreg_init_data pm8005_vreg_data[] = {
RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3"),
RPMH_VREG("smps4", "smp%s4", &pmic4_ftsmps426, "vdd-s4"),
- {},
+ {}
};
static const struct rpmh_vreg_init_data pm8150_vreg_data[] = {
@@ -856,7 +856,7 @@ static const struct rpmh_vreg_init_data pm8150_vreg_data[] = {
RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16-l17"),
RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l13-l16-l17"),
RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
- {},
+ {}
};
static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = {
@@ -880,7 +880,39 @@ static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = {
RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"),
RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"),
RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"),
- {},
+ {}
+};
+
+static const struct rpmh_vreg_init_data pmm8155au_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"),
+ RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"),
+ RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l10"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l2-l10"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ {}
};
static const struct rpmh_vreg_init_data pm8350_vreg_data[] = {
@@ -906,7 +938,7 @@ static const struct rpmh_vreg_init_data pm8350_vreg_data[] = {
RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8"),
RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9-l10"),
RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l6-l9-l10"),
- {},
+ {}
};
static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = {
@@ -934,7 +966,7 @@ static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = {
RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l1-l12"),
RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"),
- {},
+ {}
};
static const struct rpmh_vreg_init_data pm8009_vreg_data[] = {
@@ -947,7 +979,7 @@ static const struct rpmh_vreg_init_data pm8009_vreg_data[] = {
RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"),
RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"),
RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7"),
- {},
+ {}
};
static const struct rpmh_vreg_init_data pm8009_1_vreg_data[] = {
@@ -960,7 +992,7 @@ static const struct rpmh_vreg_init_data pm8009_1_vreg_data[] = {
RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"),
RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"),
RPMH_VREG("ldo7", "ldo%s6", &pmic5_pldo_lv, "vdd-l7"),
- {},
+ {}
};
static const struct rpmh_vreg_init_data pm6150_vreg_data[] = {
@@ -988,7 +1020,7 @@ static const struct rpmh_vreg_init_data pm6150_vreg_data[] = {
RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
- {},
+ {}
};
static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = {
@@ -1012,7 +1044,7 @@ static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = {
RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"),
RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"),
RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"),
- {},
+ {}
};
static const struct rpmh_vreg_init_data pmx55_vreg_data[] = {
@@ -1039,7 +1071,7 @@ static const struct rpmh_vreg_init_data pmx55_vreg_data[] = {
RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14"),
RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l15"),
RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l16"),
- {},
+ {}
};
static const struct rpmh_vreg_init_data pm7325_vreg_data[] = {
@@ -1070,6 +1102,7 @@ static const struct rpmh_vreg_init_data pm7325_vreg_data[] = {
RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
+ {}
};
static const struct rpmh_vreg_init_data pmr735a_vreg_data[] = {
@@ -1083,6 +1116,7 @@ static const struct rpmh_vreg_init_data pmr735a_vreg_data[] = {
RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5-l6"),
RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l5-l6"),
RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-bob"),
+ {}
};
static int rpmh_regulator_probe(struct platform_device *pdev)
@@ -1176,6 +1210,10 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = {
.data = pm8150l_vreg_data,
},
{
+ .compatible = "qcom,pmm8155au-rpmh-regulators",
+ .data = pmm8155au_vreg_data,
+ },
+ {
.compatible = "qcom,pmx55-rpmh-regulators",
.data = pmx55_vreg_data,
},
diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c
index bb944ee5fe3b..198fcc6551f6 100644
--- a/drivers/regulator/qcom_smd-regulator.c
+++ b/drivers/regulator/qcom_smd-regulator.c
@@ -251,6 +251,50 @@ static const struct regulator_desc pma8084_switch = {
.ops = &rpm_switch_ops,
};
+static const struct regulator_desc pm8226_hfsmps = {
+ .linear_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(375000, 0, 95, 12500),
+ REGULATOR_LINEAR_RANGE(1575000, 96, 158, 25000),
+ },
+ .n_linear_ranges = 2,
+ .n_voltages = 159,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8226_ftsmps = {
+ .linear_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(350000, 0, 184, 5000),
+ REGULATOR_LINEAR_RANGE(1280000, 185, 261, 10000),
+ },
+ .n_linear_ranges = 2,
+ .n_voltages = 262,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8226_pldo = {
+ .linear_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(750000, 0, 63, 12500),
+ REGULATOR_LINEAR_RANGE(1550000, 64, 126, 25000),
+ REGULATOR_LINEAR_RANGE(3100000, 127, 163, 50000),
+ },
+ .n_linear_ranges = 3,
+ .n_voltages = 164,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8226_nldo = {
+ .linear_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(750000, 0, 63, 12500),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 64,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8226_switch = {
+ .ops = &rpm_switch_ops,
+};
+
static const struct regulator_desc pm8x41_hfsmps = {
.linear_ranges = (struct linear_range[]) {
REGULATOR_LINEAR_RANGE( 375000, 0, 95, 12500),
@@ -405,8 +449,8 @@ static const struct regulator_desc pm8950_pldo = {
static const struct regulator_desc pm8953_lnldo = {
.linear_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(1380000, 8, 15, 120000),
REGULATOR_LINEAR_RANGE(690000, 0, 7, 60000),
+ REGULATOR_LINEAR_RANGE(1380000, 8, 15, 120000),
},
.n_linear_ranges = 2,
.n_voltages = 16,
@@ -746,6 +790,44 @@ static const struct rpm_regulator_data rpm_pm8916_regulators[] = {
{}
};
+static const struct rpm_regulator_data rpm_pm8226_regulators[] = {
+ { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8226_hfsmps, "vdd_s1" },
+ { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8226_ftsmps, "vdd_s2" },
+ { "s3", QCOM_SMD_RPM_SMPA, 3, &pm8226_hfsmps, "vdd_s3" },
+ { "s4", QCOM_SMD_RPM_SMPA, 4, &pm8226_hfsmps, "vdd_s4" },
+ { "s5", QCOM_SMD_RPM_SMPA, 5, &pm8226_hfsmps, "vdd_s5" },
+ { "l1", QCOM_SMD_RPM_LDOA, 1, &pm8226_nldo, "vdd_l1_l2_l4_l5" },
+ { "l2", QCOM_SMD_RPM_LDOA, 2, &pm8226_nldo, "vdd_l1_l2_l4_l5" },
+ { "l3", QCOM_SMD_RPM_LDOA, 3, &pm8226_nldo, "vdd_l3_l24_l26" },
+ { "l4", QCOM_SMD_RPM_LDOA, 4, &pm8226_nldo, "vdd_l1_l2_l4_l5" },
+ { "l5", QCOM_SMD_RPM_LDOA, 5, &pm8226_nldo, "vdd_l1_l2_l4_l5" },
+ { "l6", QCOM_SMD_RPM_LDOA, 6, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" },
+ { "l7", QCOM_SMD_RPM_LDOA, 7, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" },
+ { "l8", QCOM_SMD_RPM_LDOA, 8, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" },
+ { "l9", QCOM_SMD_RPM_LDOA, 9, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" },
+ { "l10", QCOM_SMD_RPM_LDOA, 10, &pm8226_pldo, "vdd_l10_l11_l13" },
+ { "l11", QCOM_SMD_RPM_LDOA, 11, &pm8226_pldo, "vdd_l10_l11_l13" },
+ { "l12", QCOM_SMD_RPM_LDOA, 12, &pm8226_pldo, "vdd_l12_l14" },
+ { "l13", QCOM_SMD_RPM_LDOA, 13, &pm8226_pldo, "vdd_l10_l11_l13" },
+ { "l14", QCOM_SMD_RPM_LDOA, 14, &pm8226_pldo, "vdd_l12_l14" },
+ { "l15", QCOM_SMD_RPM_LDOA, 15, &pm8226_pldo, "vdd_l15_l16_l17_l18" },
+ { "l16", QCOM_SMD_RPM_LDOA, 16, &pm8226_pldo, "vdd_l15_l16_l17_l18" },
+ { "l17", QCOM_SMD_RPM_LDOA, 17, &pm8226_pldo, "vdd_l15_l16_l17_l18" },
+ { "l18", QCOM_SMD_RPM_LDOA, 18, &pm8226_pldo, "vdd_l15_l16_l17_l18" },
+ { "l19", QCOM_SMD_RPM_LDOA, 19, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" },
+ { "l20", QCOM_SMD_RPM_LDOA, 20, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" },
+ { "l21", QCOM_SMD_RPM_LDOA, 21, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" },
+ { "l22", QCOM_SMD_RPM_LDOA, 22, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" },
+ { "l23", QCOM_SMD_RPM_LDOA, 23, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" },
+ { "l24", QCOM_SMD_RPM_LDOA, 24, &pm8226_nldo, "vdd_l3_l24_l26" },
+ { "l25", QCOM_SMD_RPM_LDOA, 25, &pm8226_pldo, "vdd_l25" },
+ { "l26", QCOM_SMD_RPM_LDOA, 26, &pm8226_nldo, "vdd_l3_l24_l26" },
+ { "l27", QCOM_SMD_RPM_LDOA, 27, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" },
+ { "l28", QCOM_SMD_RPM_LDOA, 28, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" },
+ { "lvs1", QCOM_SMD_RPM_VSA, 1, &pm8226_switch, "vdd_lvs1" },
+ {}
+};
+
static const struct rpm_regulator_data rpm_pm8941_regulators[] = {
{ "s1", QCOM_SMD_RPM_SMPA, 1, &pm8x41_hfsmps, "vdd_s1" },
{ "s2", QCOM_SMD_RPM_SMPA, 2, &pm8x41_hfsmps, "vdd_s2" },
@@ -1092,6 +1174,7 @@ static const struct of_device_id rpm_of_match[] = {
{ .compatible = "qcom,rpm-mp5496-regulators", .data = &rpm_mp5496_regulators },
{ .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
{ .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators },
+ { .compatible = "qcom,rpm-pm8226-regulators", .data = &rpm_pm8226_regulators },
{ .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators },
{ .compatible = "qcom,rpm-pm8950-regulators", .data = &rpm_pm8950_regulators },
{ .compatible = "qcom,rpm-pm8953-regulators", .data = &rpm_pm8953_regulators },
diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c
index 95677c51c1fa..41424a3366d0 100644
--- a/drivers/regulator/qcom_spmi-regulator.c
+++ b/drivers/regulator/qcom_spmi-regulator.c
@@ -595,11 +595,15 @@ static int spmi_regulator_vs_enable(struct regulator_dev *rdev)
return regulator_enable_regmap(rdev);
}
-static int spmi_regulator_vs_ocp(struct regulator_dev *rdev)
+static int spmi_regulator_vs_ocp(struct regulator_dev *rdev, int lim_uA,
+ int severity, bool enable)
{
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
u8 reg = SPMI_VS_OCP_OVERRIDE;
+ if (lim_uA || !enable || severity != REGULATOR_SEVERITY_PROT)
+ return -EINVAL;
+
return spmi_vreg_write(vreg, SPMI_VS_REG_OCP, &reg, 1);
}
diff --git a/drivers/regulator/qcom_usb_vbus-regulator.c b/drivers/regulator/qcom_usb_vbus-regulator.c
index 457788b50572..2e627c2b6c51 100644
--- a/drivers/regulator/qcom_usb_vbus-regulator.c
+++ b/drivers/regulator/qcom_usb_vbus-regulator.c
@@ -16,13 +16,21 @@
#define CMD_OTG 0x40
#define OTG_EN BIT(0)
+#define OTG_CURRENT_LIMIT_CFG 0x52
+#define OTG_CURRENT_LIMIT_MASK GENMASK(2, 0)
#define OTG_CFG 0x53
#define OTG_EN_SRC_CFG BIT(1)
+static const unsigned int curr_table[] = {
+ 500000, 1000000, 1500000, 2000000, 2500000, 3000000,
+};
+
static const struct regulator_ops qcom_usb_vbus_reg_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
+ .get_current_limit = regulator_get_current_limit_regmap,
+ .set_current_limit = regulator_set_current_limit_regmap,
};
static struct regulator_desc qcom_usb_vbus_rdesc = {
@@ -30,6 +38,8 @@ static struct regulator_desc qcom_usb_vbus_rdesc = {
.ops = &qcom_usb_vbus_reg_ops,
.owner = THIS_MODULE,
.type = REGULATOR_VOLTAGE,
+ .curr_table = curr_table,
+ .n_current_limits = ARRAY_SIZE(curr_table),
};
static int qcom_usb_vbus_regulator_probe(struct platform_device *pdev)
@@ -61,6 +71,8 @@ static int qcom_usb_vbus_regulator_probe(struct platform_device *pdev)
qcom_usb_vbus_rdesc.enable_reg = base + CMD_OTG;
qcom_usb_vbus_rdesc.enable_mask = OTG_EN;
+ qcom_usb_vbus_rdesc.csel_reg = base + OTG_CURRENT_LIMIT_CFG;
+ qcom_usb_vbus_rdesc.csel_mask = OTG_CURRENT_LIMIT_MASK;
config.dev = dev;
config.init_data = init_data;
config.of_node = dev->of_node;
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index e926c1a85846..127dc2e2e690 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -158,13 +158,6 @@ struct rk808_regulator_data {
struct gpio_desc *dvs_gpio[2];
};
-static const int rk808_buck_config_regs[] = {
- RK808_BUCK1_CONFIG_REG,
- RK808_BUCK2_CONFIG_REG,
- RK808_BUCK3_CONFIG_REG,
- RK808_BUCK4_CONFIG_REG,
-};
-
static const struct linear_range rk808_ldo3_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(800000, 0, 13, 100000),
REGULATOR_LINEAR_RANGE(2500000, 15, 15, 0),
@@ -215,6 +208,15 @@ static const struct linear_range rk817_buck3_voltage_ranges[] = {
RK817_BUCK3_SEL_CNT, RK817_BUCK1_STP1),
};
+static const unsigned int rk808_buck1_2_ramp_table[] = {
+ 2000, 4000, 6000, 10000
+};
+
+/* RK817 RK809 */
+static const unsigned int rk817_buck1_4_ramp_table[] = {
+ 3000, 6300, 12500, 25000
+};
+
static int rk808_buck1_2_get_voltage_sel_regmap(struct regulator_dev *rdev)
{
struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev);
@@ -340,62 +342,6 @@ static int rk808_buck1_2_set_voltage_time_sel(struct regulator_dev *rdev,
return regulator_set_voltage_time_sel(rdev, old_selector, new_selector);
}
-static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
- unsigned int ramp_value = RK808_RAMP_RATE_10MV_PER_US;
- unsigned int reg = rk808_buck_config_regs[rdev_get_id(rdev)];
-
- switch (ramp_delay) {
- case 1 ... 2000:
- ramp_value = RK808_RAMP_RATE_2MV_PER_US;
- break;
- case 2001 ... 4000:
- ramp_value = RK808_RAMP_RATE_4MV_PER_US;
- break;
- case 4001 ... 6000:
- ramp_value = RK808_RAMP_RATE_6MV_PER_US;
- break;
- case 6001 ... 10000:
- break;
- default:
- pr_warn("%s ramp_delay: %d not supported, setting 10000\n",
- rdev->desc->name, ramp_delay);
- }
-
- return regmap_update_bits(rdev->regmap, reg,
- 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 25000\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;
@@ -625,7 +571,7 @@ static const struct regulator_ops rk808_buck1_2_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
- .set_ramp_delay = rk808_set_ramp_delay,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
.set_suspend_voltage = rk808_set_suspend_voltage,
.set_suspend_enable = rk808_set_suspend_enable,
.set_suspend_disable = rk808_set_suspend_disable,
@@ -722,7 +668,7 @@ static const struct regulator_ops rk817_buck_ops_range = {
.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_ramp_delay = regulator_set_ramp_delay_regmap,
.set_suspend_voltage = rk808_set_suspend_voltage_range,
.set_suspend_enable = rk817_set_suspend_enable,
.set_suspend_disable = rk817_set_suspend_disable,
@@ -814,6 +760,10 @@ static const struct regulator_desc rk808_reg[] = {
.vsel_mask = RK808_BUCK_VSEL_MASK,
.enable_reg = RK808_DCDC_EN_REG,
.enable_mask = BIT(0),
+ .ramp_reg = RK808_BUCK1_CONFIG_REG,
+ .ramp_mask = RK808_RAMP_RATE_MASK,
+ .ramp_delay_table = rk808_buck1_2_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(rk808_buck1_2_ramp_table),
.owner = THIS_MODULE,
}, {
.name = "DCDC_REG2",
@@ -830,6 +780,10 @@ static const struct regulator_desc rk808_reg[] = {
.vsel_mask = RK808_BUCK_VSEL_MASK,
.enable_reg = RK808_DCDC_EN_REG,
.enable_mask = BIT(1),
+ .ramp_reg = RK808_BUCK2_CONFIG_REG,
+ .ramp_mask = RK808_RAMP_RATE_MASK,
+ .ramp_delay_table = rk808_buck1_2_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(rk808_buck1_2_ramp_table),
.owner = THIS_MODULE,
}, {
.name = "DCDC_REG3",
@@ -910,6 +864,10 @@ static const struct regulator_desc rk809_reg[] = {
.enable_mask = ENABLE_MASK(RK817_ID_DCDC1),
.enable_val = ENABLE_MASK(RK817_ID_DCDC1),
.disable_val = DISABLE_VAL(RK817_ID_DCDC1),
+ .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC1),
+ .ramp_mask = RK817_RAMP_RATE_MASK,
+ .ramp_delay_table = rk817_buck1_4_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
.of_map_mode = rk8xx_regulator_of_map_mode,
.owner = THIS_MODULE,
}, {
@@ -929,6 +887,10 @@ static const struct regulator_desc rk809_reg[] = {
.enable_mask = ENABLE_MASK(RK817_ID_DCDC2),
.enable_val = ENABLE_MASK(RK817_ID_DCDC2),
.disable_val = DISABLE_VAL(RK817_ID_DCDC2),
+ .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC2),
+ .ramp_mask = RK817_RAMP_RATE_MASK,
+ .ramp_delay_table = rk817_buck1_4_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
.of_map_mode = rk8xx_regulator_of_map_mode,
.owner = THIS_MODULE,
}, {
@@ -948,6 +910,10 @@ static const struct regulator_desc rk809_reg[] = {
.enable_mask = ENABLE_MASK(RK817_ID_DCDC3),
.enable_val = ENABLE_MASK(RK817_ID_DCDC3),
.disable_val = DISABLE_VAL(RK817_ID_DCDC3),
+ .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC3),
+ .ramp_mask = RK817_RAMP_RATE_MASK,
+ .ramp_delay_table = rk817_buck1_4_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
.of_map_mode = rk8xx_regulator_of_map_mode,
.owner = THIS_MODULE,
}, {
@@ -967,6 +933,10 @@ static const struct regulator_desc rk809_reg[] = {
.enable_mask = ENABLE_MASK(RK817_ID_DCDC4),
.enable_val = ENABLE_MASK(RK817_ID_DCDC4),
.disable_val = DISABLE_VAL(RK817_ID_DCDC4),
+ .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC4),
+ .ramp_mask = RK817_RAMP_RATE_MASK,
+ .ramp_delay_table = rk817_buck1_4_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
.of_map_mode = rk8xx_regulator_of_map_mode,
.owner = THIS_MODULE,
},
@@ -1052,6 +1022,10 @@ static const struct regulator_desc rk817_reg[] = {
.enable_mask = ENABLE_MASK(RK817_ID_DCDC1),
.enable_val = ENABLE_MASK(RK817_ID_DCDC1),
.disable_val = DISABLE_VAL(RK817_ID_DCDC1),
+ .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC1),
+ .ramp_mask = RK817_RAMP_RATE_MASK,
+ .ramp_delay_table = rk817_buck1_4_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
.of_map_mode = rk8xx_regulator_of_map_mode,
.owner = THIS_MODULE,
}, {
@@ -1071,6 +1045,10 @@ static const struct regulator_desc rk817_reg[] = {
.enable_mask = ENABLE_MASK(RK817_ID_DCDC2),
.enable_val = ENABLE_MASK(RK817_ID_DCDC2),
.disable_val = DISABLE_VAL(RK817_ID_DCDC2),
+ .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC2),
+ .ramp_mask = RK817_RAMP_RATE_MASK,
+ .ramp_delay_table = rk817_buck1_4_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
.of_map_mode = rk8xx_regulator_of_map_mode,
.owner = THIS_MODULE,
}, {
@@ -1090,6 +1068,10 @@ static const struct regulator_desc rk817_reg[] = {
.enable_mask = ENABLE_MASK(RK817_ID_DCDC3),
.enable_val = ENABLE_MASK(RK817_ID_DCDC3),
.disable_val = DISABLE_VAL(RK817_ID_DCDC3),
+ .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC3),
+ .ramp_mask = RK817_RAMP_RATE_MASK,
+ .ramp_delay_table = rk817_buck1_4_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
.of_map_mode = rk8xx_regulator_of_map_mode,
.owner = THIS_MODULE,
}, {
@@ -1109,6 +1091,10 @@ static const struct regulator_desc rk817_reg[] = {
.enable_mask = ENABLE_MASK(RK817_ID_DCDC4),
.enable_val = ENABLE_MASK(RK817_ID_DCDC4),
.disable_val = DISABLE_VAL(RK817_ID_DCDC4),
+ .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC4),
+ .ramp_mask = RK817_RAMP_RATE_MASK,
+ .ramp_delay_table = rk817_buck1_4_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table),
.of_map_mode = rk8xx_regulator_of_map_mode,
.owner = THIS_MODULE,
},
diff --git a/drivers/regulator/rt4831-regulator.c b/drivers/regulator/rt4831-regulator.c
index e3aaac90d238..676b0419e48f 100644
--- a/drivers/regulator/rt4831-regulator.c
+++ b/drivers/regulator/rt4831-regulator.c
@@ -108,6 +108,7 @@ static const struct regulator_desc rt4831_regulator_descs[] = {
.bypass_reg = RT4831_REG_DSVEN,
.bypass_val_on = DSV_MODE_BYPASS,
.bypass_val_off = DSV_MODE_NORMAL,
+ .owner = THIS_MODULE,
},
{
.name = "DSVP",
@@ -125,6 +126,7 @@ static const struct regulator_desc rt4831_regulator_descs[] = {
.enable_mask = RT4831_POSEN_MASK,
.active_discharge_reg = RT4831_REG_DSVEN,
.active_discharge_mask = RT4831_POSADEN_MASK,
+ .owner = THIS_MODULE,
},
{
.name = "DSVN",
@@ -142,6 +144,7 @@ static const struct regulator_desc rt4831_regulator_descs[] = {
.enable_mask = RT4831_NEGEN_MASK,
.active_discharge_reg = RT4831_REG_DSVEN,
.active_discharge_mask = RT4831_NEGADEN_MASK,
+ .owner = THIS_MODULE,
}
};
diff --git a/drivers/regulator/rt6160-regulator.c b/drivers/regulator/rt6160-regulator.c
new file mode 100644
index 000000000000..5d7b0e7ad69a
--- /dev/null
+++ b/drivers/regulator/rt6160-regulator.c
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define RT6160_MODE_AUTO 0
+#define RT6160_MODE_FPWM 1
+
+#define RT6160_REG_CNTL 0x01
+#define RT6160_REG_STATUS 0x02
+#define RT6160_REG_DEVID 0x03
+#define RT6160_REG_VSELL 0x04
+#define RT6160_REG_VSELH 0x05
+#define RT6160_NUM_REGS (RT6160_REG_VSELH + 1)
+
+#define RT6160_FPWM_MASK BIT(3)
+#define RT6160_RAMPRATE_MASK GENMASK(1, 0)
+#define RT6160_VID_MASK GENMASK(7, 4)
+#define RT6160_VSEL_MASK GENMASK(6, 0)
+#define RT6160_HDSTAT_MASK BIT(4)
+#define RT6160_UVSTAT_MASK BIT(3)
+#define RT6160_OCSTAT_MASK BIT(2)
+#define RT6160_TSDSTAT_MASK BIT(1)
+#define RT6160_PGSTAT_MASK BIT(0)
+
+#define RT6160_VENDOR_ID 0xA0
+#define RT6160_VOUT_MINUV 2025000
+#define RT6160_VOUT_MAXUV 5200000
+#define RT6160_VOUT_STPUV 25000
+#define RT6160_N_VOUTS ((RT6160_VOUT_MAXUV - RT6160_VOUT_MINUV) / RT6160_VOUT_STPUV + 1)
+
+#define RT6160_I2CRDY_TIMEUS 100
+
+struct rt6160_priv {
+ struct regulator_desc desc;
+ struct gpio_desc *enable_gpio;
+ struct regmap *regmap;
+ bool enable_state;
+};
+
+static const unsigned int rt6160_ramp_tables[] = {
+ 1000, 2500, 5000, 10000
+};
+
+static int rt6160_enable(struct regulator_dev *rdev)
+{
+ struct rt6160_priv *priv = rdev_get_drvdata(rdev);
+
+ if (!priv->enable_gpio)
+ return 0;
+
+ gpiod_set_value_cansleep(priv->enable_gpio, 1);
+ priv->enable_state = true;
+
+ usleep_range(RT6160_I2CRDY_TIMEUS, RT6160_I2CRDY_TIMEUS + 100);
+
+ regcache_cache_only(priv->regmap, false);
+ return regcache_sync(priv->regmap);
+}
+
+static int rt6160_disable(struct regulator_dev *rdev)
+{
+ struct rt6160_priv *priv = rdev_get_drvdata(rdev);
+
+ if (!priv->enable_gpio)
+ return -EINVAL;
+
+ /* Mark regcache as dirty and cache only before HW disabled */
+ regcache_cache_only(priv->regmap, true);
+ regcache_mark_dirty(priv->regmap);
+
+ priv->enable_state = false;
+ gpiod_set_value_cansleep(priv->enable_gpio, 0);
+
+ return 0;
+}
+
+static int rt6160_is_enabled(struct regulator_dev *rdev)
+{
+ struct rt6160_priv *priv = rdev_get_drvdata(rdev);
+
+ return priv->enable_state ? 1 : 0;
+}
+
+static int rt6160_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct regmap *regmap = rdev_get_regmap(rdev);
+ unsigned int mode_val;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ mode_val = RT6160_FPWM_MASK;
+ break;
+ case REGULATOR_MODE_NORMAL:
+ mode_val = 0;
+ break;
+ default:
+ dev_err(&rdev->dev, "mode not supported\n");
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(regmap, RT6160_REG_CNTL, RT6160_FPWM_MASK, mode_val);
+}
+
+static unsigned int rt6160_get_mode(struct regulator_dev *rdev)
+{
+ struct regmap *regmap = rdev_get_regmap(rdev);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(regmap, RT6160_REG_CNTL, &val);
+ if (ret)
+ return ret;
+
+ if (val & RT6160_FPWM_MASK)
+ return REGULATOR_MODE_FAST;
+
+ return REGULATOR_MODE_NORMAL;
+}
+
+static int rt6160_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+ struct regmap *regmap = rdev_get_regmap(rdev);
+ unsigned int suspend_vsel_reg;
+ int vsel;
+
+ vsel = regulator_map_voltage_linear(rdev, uV, uV);
+ if (vsel < 0)
+ return vsel;
+
+ if (rdev->desc->vsel_reg == RT6160_REG_VSELL)
+ suspend_vsel_reg = RT6160_REG_VSELH;
+ else
+ suspend_vsel_reg = RT6160_REG_VSELL;
+
+ return regmap_update_bits(regmap, suspend_vsel_reg,
+ RT6160_VSEL_MASK, vsel);
+}
+
+static int rt6160_get_error_flags(struct regulator_dev *rdev, unsigned int *flags)
+{
+ struct regmap *regmap = rdev_get_regmap(rdev);
+ unsigned int val, events = 0;
+ int ret;
+
+ ret = regmap_read(regmap, RT6160_REG_STATUS, &val);
+ if (ret)
+ return ret;
+
+ if (val & (RT6160_HDSTAT_MASK | RT6160_TSDSTAT_MASK))
+ events |= REGULATOR_ERROR_OVER_TEMP;
+
+ if (val & RT6160_UVSTAT_MASK)
+ events |= REGULATOR_ERROR_UNDER_VOLTAGE;
+
+ if (val & RT6160_OCSTAT_MASK)
+ events |= REGULATOR_ERROR_OVER_CURRENT;
+
+ if (val & RT6160_PGSTAT_MASK)
+ events |= REGULATOR_ERROR_FAIL;
+
+ *flags = events;
+ return 0;
+}
+
+static const struct regulator_ops rt6160_regulator_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+
+ .enable = rt6160_enable,
+ .disable = rt6160_disable,
+ .is_enabled = rt6160_is_enabled,
+
+ .set_mode = rt6160_set_mode,
+ .get_mode = rt6160_get_mode,
+ .set_suspend_voltage = rt6160_set_suspend_voltage,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
+ .get_error_flags = rt6160_get_error_flags,
+};
+
+static unsigned int rt6160_of_map_mode(unsigned int mode)
+{
+ switch (mode) {
+ case RT6160_MODE_FPWM:
+ return REGULATOR_MODE_FAST;
+ case RT6160_MODE_AUTO:
+ return REGULATOR_MODE_NORMAL;
+ }
+
+ return REGULATOR_MODE_INVALID;
+}
+
+static bool rt6160_is_accessible_reg(struct device *dev, unsigned int reg)
+{
+ if (reg >= RT6160_REG_CNTL && reg <= RT6160_REG_VSELH)
+ return true;
+ return false;
+}
+
+static bool rt6160_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ if (reg == RT6160_REG_STATUS)
+ return true;
+ return false;
+}
+
+static const struct regmap_config rt6160_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RT6160_REG_VSELH,
+ .num_reg_defaults_raw = RT6160_NUM_REGS,
+ .cache_type = REGCACHE_FLAT,
+
+ .writeable_reg = rt6160_is_accessible_reg,
+ .readable_reg = rt6160_is_accessible_reg,
+ .volatile_reg = rt6160_is_volatile_reg,
+};
+
+static int rt6160_probe(struct i2c_client *i2c)
+{
+ struct rt6160_priv *priv;
+ struct regulator_config regulator_cfg = {};
+ struct regulator_dev *rdev;
+ bool vsel_active_low;
+ unsigned int devid;
+ int ret;
+
+ priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ vsel_active_low =
+ device_property_present(&i2c->dev, "richtek,vsel-active-low");
+
+ priv->enable_gpio = devm_gpiod_get_optional(&i2c->dev, "enable", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->enable_gpio)) {
+ dev_err(&i2c->dev, "Failed to get 'enable' gpio\n");
+ return PTR_ERR(priv->enable_gpio);
+ }
+ priv->enable_state = true;
+
+ usleep_range(RT6160_I2CRDY_TIMEUS, RT6160_I2CRDY_TIMEUS + 100);
+
+ priv->regmap = devm_regmap_init_i2c(i2c, &rt6160_regmap_config);
+ if (IS_ERR(priv->regmap)) {
+ ret = PTR_ERR(priv->regmap);
+ dev_err(&i2c->dev, "Failed to init regmap (%d)\n", ret);
+ return ret;
+ }
+
+ ret = regmap_read(priv->regmap, RT6160_REG_DEVID, &devid);
+ if (ret)
+ return ret;
+
+ if ((devid & RT6160_VID_MASK) != RT6160_VENDOR_ID) {
+ dev_err(&i2c->dev, "VID not correct [0x%02x]\n", devid);
+ return -ENODEV;
+ }
+
+ priv->desc.name = "rt6160-buckboost";
+ priv->desc.type = REGULATOR_VOLTAGE;
+ priv->desc.owner = THIS_MODULE;
+ priv->desc.min_uV = RT6160_VOUT_MINUV;
+ priv->desc.uV_step = RT6160_VOUT_STPUV;
+ if (vsel_active_low)
+ priv->desc.vsel_reg = RT6160_REG_VSELL;
+ else
+ priv->desc.vsel_reg = RT6160_REG_VSELH;
+ priv->desc.vsel_mask = RT6160_VSEL_MASK;
+ priv->desc.n_voltages = RT6160_N_VOUTS;
+ priv->desc.ramp_reg = RT6160_REG_CNTL;
+ priv->desc.ramp_mask = RT6160_RAMPRATE_MASK;
+ priv->desc.ramp_delay_table = rt6160_ramp_tables;
+ priv->desc.n_ramp_values = ARRAY_SIZE(rt6160_ramp_tables);
+ priv->desc.of_map_mode = rt6160_of_map_mode;
+ priv->desc.ops = &rt6160_regulator_ops;
+
+ regulator_cfg.dev = &i2c->dev;
+ regulator_cfg.of_node = i2c->dev.of_node;
+ regulator_cfg.regmap = priv->regmap;
+ regulator_cfg.driver_data = priv;
+ regulator_cfg.init_data = of_get_regulator_init_data(&i2c->dev, i2c->dev.of_node,
+ &priv->desc);
+
+ rdev = devm_regulator_register(&i2c->dev, &priv->desc, &regulator_cfg);
+ if (IS_ERR(rdev)) {
+ dev_err(&i2c->dev, "Failed to register regulator\n");
+ return PTR_ERR(rdev);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id __maybe_unused rt6160_of_match_table[] = {
+ { .compatible = "richtek,rt6160", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rt6160_of_match_table);
+
+static struct i2c_driver rt6160_driver = {
+ .driver = {
+ .name = "rt6160",
+ .of_match_table = rt6160_of_match_table,
+ },
+ .probe_new = rt6160_probe,
+};
+module_i2c_driver(rt6160_driver);
+
+MODULE_DESCRIPTION("Richtek RT6160 voltage regulator driver");
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/rt6245-regulator.c b/drivers/regulator/rt6245-regulator.c
new file mode 100644
index 000000000000..d3299a72fd10
--- /dev/null
+++ b/drivers/regulator/rt6245-regulator.c
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define RT6245_VIRT_OCLIMIT 0x00
+#define RT6245_VIRT_OTLEVEL 0x01
+#define RT6245_VIRT_PGDLYTIME 0x02
+#define RT6245_VIRT_SLEWRATE 0x03
+#define RT6245_VIRT_SWFREQ 0x04
+#define RT6245_VIRT_VOUT 0x05
+
+#define RT6245_VOUT_MASK GENMASK(6, 0)
+#define RT6245_SLEW_MASK GENMASK(2, 0)
+#define RT6245_CHKSUM_MASK BIT(7)
+#define RT6245_CODE_MASK GENMASK(6, 0)
+
+/* HW Enable + Soft start time */
+#define RT6245_ENTIME_IN_US 5000
+
+#define RT6245_VOUT_MINUV 437500
+#define RT6245_VOUT_MAXUV 1387500
+#define RT6245_VOUT_STEPUV 12500
+#define RT6245_NUM_VOUT ((RT6245_VOUT_MAXUV - RT6245_VOUT_MINUV) / RT6245_VOUT_STEPUV + 1)
+
+struct rt6245_priv {
+ struct gpio_desc *enable_gpio;
+ bool enable_state;
+};
+
+static int rt6245_enable(struct regulator_dev *rdev)
+{
+ struct rt6245_priv *priv = rdev_get_drvdata(rdev);
+ struct regmap *regmap = rdev_get_regmap(rdev);
+ int ret;
+
+ if (!priv->enable_gpio)
+ return 0;
+
+ gpiod_direction_output(priv->enable_gpio, 1);
+ usleep_range(RT6245_ENTIME_IN_US, RT6245_ENTIME_IN_US + 1000);
+
+ regcache_cache_only(regmap, false);
+ ret = regcache_sync(regmap);
+ if (ret)
+ return ret;
+
+ priv->enable_state = true;
+ return 0;
+}
+
+static int rt6245_disable(struct regulator_dev *rdev)
+{
+ struct rt6245_priv *priv = rdev_get_drvdata(rdev);
+ struct regmap *regmap = rdev_get_regmap(rdev);
+
+ if (!priv->enable_gpio)
+ return -EINVAL;
+
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+
+ gpiod_direction_output(priv->enable_gpio, 0);
+
+ priv->enable_state = false;
+ return 0;
+}
+
+static int rt6245_is_enabled(struct regulator_dev *rdev)
+{
+ struct rt6245_priv *priv = rdev_get_drvdata(rdev);
+
+ return priv->enable_state ? 1 : 0;
+}
+
+static const struct regulator_ops rt6245_regulator_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
+ .enable = rt6245_enable,
+ .disable = rt6245_disable,
+ .is_enabled = rt6245_is_enabled,
+};
+
+/* ramp delay dividend is 12500 uV/uS, and divisor from 1 to 8 */
+static const unsigned int rt6245_ramp_delay_table[] = {
+ 12500, 6250, 4167, 3125, 2500, 2083, 1786, 1562
+};
+
+static const struct regulator_desc rt6245_regulator_desc = {
+ .name = "rt6245-regulator",
+ .ops = &rt6245_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .min_uV = RT6245_VOUT_MINUV,
+ .uV_step = RT6245_VOUT_STEPUV,
+ .n_voltages = RT6245_NUM_VOUT,
+ .ramp_delay_table = rt6245_ramp_delay_table,
+ .n_ramp_values = ARRAY_SIZE(rt6245_ramp_delay_table),
+ .owner = THIS_MODULE,
+ .vsel_reg = RT6245_VIRT_VOUT,
+ .vsel_mask = RT6245_VOUT_MASK,
+ .ramp_reg = RT6245_VIRT_SLEWRATE,
+ .ramp_mask = RT6245_SLEW_MASK,
+};
+
+static int rt6245_init_device_properties(struct device *dev)
+{
+ const struct {
+ const char *name;
+ unsigned int reg;
+ } rt6245_props[] = {
+ { "richtek,oc-level-select", RT6245_VIRT_OCLIMIT },
+ { "richtek,ot-level-select", RT6245_VIRT_OTLEVEL },
+ { "richtek,pgdly-time-select", RT6245_VIRT_PGDLYTIME },
+ { "richtek,switch-freq-select", RT6245_VIRT_SWFREQ }
+ };
+ struct regmap *regmap = dev_get_regmap(dev, NULL);
+ u8 propval;
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(rt6245_props); i++) {
+ ret = device_property_read_u8(dev, rt6245_props[i].name, &propval);
+ if (ret)
+ continue;
+
+ ret = regmap_write(regmap, rt6245_props[i].reg, propval);
+ if (ret) {
+ dev_err(dev, "Fail to apply [%s:%d]\n", rt6245_props[i].name, propval);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int rt6245_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct i2c_client *i2c = context;
+ const u8 func_base[] = { 0x6F, 0x73, 0x78, 0x61, 0x7C, 0 };
+ unsigned int code, bit_count;
+
+ code = func_base[reg];
+ code += val;
+
+ /* xor checksum for bit 6 to 0 */
+ bit_count = hweight8(code & RT6245_CODE_MASK);
+ if (bit_count % 2)
+ code |= RT6245_CHKSUM_MASK;
+ else
+ code &= ~RT6245_CHKSUM_MASK;
+
+ return i2c_smbus_write_byte(i2c, code);
+}
+
+static const struct reg_default rt6245_reg_defaults[] = {
+ /* Default over current 14A */
+ { RT6245_VIRT_OCLIMIT, 2 },
+ /* Default over temperature 150'c */
+ { RT6245_VIRT_OTLEVEL, 0 },
+ /* Default power good delay time 10us */
+ { RT6245_VIRT_PGDLYTIME, 1 },
+ /* Default slewrate 12.5mV/uS */
+ { RT6245_VIRT_SLEWRATE, 0 },
+ /* Default switch frequency 800KHz */
+ { RT6245_VIRT_SWFREQ, 1 },
+ /* Default voltage 750mV */
+ { RT6245_VIRT_VOUT, 0x19 }
+};
+
+static const struct regmap_config rt6245_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RT6245_VIRT_VOUT,
+ .cache_type = REGCACHE_FLAT,
+ .reg_defaults = rt6245_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt6245_reg_defaults),
+ .reg_write = rt6245_reg_write,
+};
+
+static int rt6245_probe(struct i2c_client *i2c)
+{
+ struct rt6245_priv *priv;
+ struct regmap *regmap;
+ struct regulator_config regulator_cfg = {};
+ struct regulator_dev *rdev;
+ int ret;
+
+ priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->enable_state = true;
+
+ priv->enable_gpio = devm_gpiod_get_optional(&i2c->dev, "enable", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->enable_gpio)) {
+ dev_err(&i2c->dev, "Failed to get 'enable' gpio\n");
+ return PTR_ERR(priv->enable_gpio);
+ }
+
+ usleep_range(RT6245_ENTIME_IN_US, RT6245_ENTIME_IN_US + 1000);
+
+ regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt6245_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&i2c->dev, "Failed to initialize the regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ ret = rt6245_init_device_properties(&i2c->dev);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to initialize device properties\n");
+ return ret;
+ }
+
+ regulator_cfg.dev = &i2c->dev;
+ regulator_cfg.of_node = i2c->dev.of_node;
+ regulator_cfg.regmap = regmap;
+ regulator_cfg.driver_data = priv;
+ regulator_cfg.init_data = of_get_regulator_init_data(&i2c->dev, i2c->dev.of_node,
+ &rt6245_regulator_desc);
+ rdev = devm_regulator_register(&i2c->dev, &rt6245_regulator_desc, &regulator_cfg);
+ if (IS_ERR(rdev)) {
+ dev_err(&i2c->dev, "Failed to register regulator\n");
+ return PTR_ERR(rdev);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id __maybe_unused rt6245_of_match_table[] = {
+ { .compatible = "richtek,rt6245", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rt6245_of_match_table);
+
+static struct i2c_driver rt6245_driver = {
+ .driver = {
+ .name = "rt6245",
+ .of_match_table = rt6245_of_match_table,
+ },
+ .probe_new = rt6245_probe,
+};
+module_i2c_driver(rt6245_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("Richtek RT6245 Regulator Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c
index cf10fdb72e32..2d7597c76e4a 100644
--- a/drivers/regulator/stpmic1_regulator.c
+++ b/drivers/regulator/stpmic1_regulator.c
@@ -32,7 +32,8 @@ struct stpmic1_regulator_cfg {
static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode);
static unsigned int stpmic1_get_mode(struct regulator_dev *rdev);
-static int stpmic1_set_icc(struct regulator_dev *rdev);
+static int stpmic1_set_icc(struct regulator_dev *rdev, int lim, int severity,
+ bool enable);
static unsigned int stpmic1_map_mode(unsigned int mode);
enum {
@@ -491,11 +492,26 @@ static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode)
STPMIC1_BUCK_MODE_LP, value);
}
-static int stpmic1_set_icc(struct regulator_dev *rdev)
+static int stpmic1_set_icc(struct regulator_dev *rdev, int lim, int severity,
+ bool enable)
{
struct stpmic1_regulator_cfg *cfg = rdev_get_drvdata(rdev);
struct regmap *regmap = rdev_get_regmap(rdev);
+ /*
+ * The code seems like one bit in a register controls whether OCP is
+ * enabled. So we might be able to turn it off here is if that
+ * was requested. I won't support this because I don't have the HW.
+ * Feel free to try and implement if you have the HW and need kernel
+ * to disable this.
+ *
+ * Also, I don't know if limit can be configured or if we support
+ * error/warning instead of protect. So I just keep existing logic
+ * and assume no.
+ */
+ if (lim || severity != REGULATOR_SEVERITY_PROT || !enable)
+ return -EINVAL;
+
/* enable switch off in case of over current */
return regmap_update_bits(regmap, cfg->icc_reg, cfg->icc_mask,
cfg->icc_mask);
diff --git a/drivers/regulator/sy7636a-regulator.c b/drivers/regulator/sy7636a-regulator.c
new file mode 100644
index 000000000000..e021ae08cbaa
--- /dev/null
+++ b/drivers/regulator/sy7636a-regulator.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Functions to access SY3686A power management chip voltages
+//
+// Copyright (C) 2019 reMarkable AS - http://www.remarkable.com/
+//
+// Authors: Lars Ivar Miljeteig <lars.ivar.miljeteig@remarkable.com>
+// Alistair Francis <alistair@alistair23.me>
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mfd/sy7636a.h>
+
+#define SY7636A_POLL_ENABLED_TIME 500
+
+static int sy7636a_get_vcom_voltage_op(struct regulator_dev *rdev)
+{
+ int ret;
+ unsigned int val, val_h;
+
+ ret = regmap_read(rdev->regmap, SY7636A_REG_VCOM_ADJUST_CTRL_L, &val);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(rdev->regmap, SY7636A_REG_VCOM_ADJUST_CTRL_H, &val_h);
+ if (ret)
+ return ret;
+
+ val |= (val_h << VCOM_ADJUST_CTRL_SHIFT);
+
+ return (val & VCOM_ADJUST_CTRL_MASK) * VCOM_ADJUST_CTRL_SCAL;
+}
+
+static int sy7636a_get_status(struct regulator_dev *rdev)
+{
+ struct sy7636a *sy7636a = rdev_get_drvdata(rdev);
+ int ret = 0;
+
+ ret = gpiod_get_value_cansleep(sy7636a->pgood_gpio);
+ if (ret < 0)
+ dev_err(&rdev->dev, "Failed to read pgood gpio: %d\n", ret);
+
+ return ret;
+}
+
+static const struct regulator_ops sy7636a_vcom_volt_ops = {
+ .get_voltage = sy7636a_get_vcom_voltage_op,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_status = sy7636a_get_status,
+};
+
+static const struct regulator_desc desc = {
+ .name = "vcom",
+ .id = 0,
+ .ops = &sy7636a_vcom_volt_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = SY7636A_REG_OPERATION_MODE_CRL,
+ .enable_mask = SY7636A_OPERATION_MODE_CRL_ONOFF,
+ .poll_enabled_time = SY7636A_POLL_ENABLED_TIME,
+ .regulators_node = of_match_ptr("regulators"),
+ .of_match = of_match_ptr("vcom"),
+};
+
+static int sy7636a_regulator_probe(struct platform_device *pdev)
+{
+ struct sy7636a *sy7636a = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
+ struct regulator_dev *rdev;
+ struct gpio_desc *gdp;
+ int ret;
+
+ if (!sy7636a)
+ return -EPROBE_DEFER;
+
+ platform_set_drvdata(pdev, sy7636a);
+
+ gdp = devm_gpiod_get(sy7636a->dev, "epd-pwr-good", GPIOD_IN);
+ if (IS_ERR(gdp)) {
+ dev_err(sy7636a->dev, "Power good GPIO fault %ld\n", PTR_ERR(gdp));
+ return PTR_ERR(gdp);
+ }
+
+ sy7636a->pgood_gpio = gdp;
+
+ ret = regmap_write(sy7636a->regmap, SY7636A_REG_POWER_ON_DELAY_TIME, 0x0);
+ if (ret) {
+ dev_err(sy7636a->dev, "Failed to initialize regulator: %d\n", ret);
+ return ret;
+ }
+
+ config.dev = &pdev->dev;
+ config.dev->of_node = sy7636a->dev->of_node;
+ config.driver_data = sy7636a;
+ config.regmap = sy7636a->regmap;
+
+ rdev = devm_regulator_register(&pdev->dev, &desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(sy7636a->dev, "Failed to register %s regulator\n",
+ pdev->name);
+ return PTR_ERR(rdev);
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id sy7636a_regulator_id_table[] = {
+ { "sy7636a-regulator", },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, sy7636a_regulator_id_table);
+
+static struct platform_driver sy7636a_regulator_driver = {
+ .driver = {
+ .name = "sy7636a-regulator",
+ },
+ .probe = sy7636a_regulator_probe,
+ .id_table = sy7636a_regulator_id_table,
+};
+module_platform_driver(sy7636a_regulator_driver);
+
+MODULE_AUTHOR("Lars Ivar Miljeteig <lars.ivar.miljeteig@remarkable.com>");
+MODULE_DESCRIPTION("SY7636A voltage regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/uniphier-regulator.c b/drivers/regulator/uniphier-regulator.c
index 2e02e26b516c..e75b0973e325 100644
--- a/drivers/regulator/uniphier-regulator.c
+++ b/drivers/regulator/uniphier-regulator.c
@@ -201,6 +201,7 @@ static const struct of_device_id uniphier_regulator_match[] = {
},
{ /* Sentinel */ },
};
+MODULE_DEVICE_TABLE(of, uniphier_regulator_match);
static struct platform_driver uniphier_regulator_driver = {
.probe = uniphier_regulator_probe,
diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c
index 8e3b5a67cfd8..8ca28664776e 100644
--- a/drivers/regulator/userspace-consumer.c
+++ b/drivers/regulator/userspace-consumer.c
@@ -29,15 +29,15 @@ struct userspace_consumer_data {
struct regulator_bulk_data *supplies;
};
-static ssize_t reg_show_name(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct userspace_consumer_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", data->name);
}
-static ssize_t reg_show_state(struct device *dev,
+static ssize_t state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct userspace_consumer_data *data = dev_get_drvdata(dev);
@@ -48,8 +48,8 @@ static ssize_t reg_show_state(struct device *dev,
return sprintf(buf, "disabled\n");
}
-static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t state_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct userspace_consumer_data *data = dev_get_drvdata(dev);
bool enabled;
@@ -87,8 +87,8 @@ static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(name, 0444, reg_show_name, NULL);
-static DEVICE_ATTR(state, 0644, reg_show_state, reg_set_state);
+static DEVICE_ATTR_RO(name);
+static DEVICE_ATTR_RW(state);
static struct attribute *attributes[] = {
&dev_attr_name.attr,
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index e68fcedc999c..9a6eedc3994a 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -26,6 +26,7 @@ config REMOTEPROC_CDEV
config IMX_REMOTEPROC
tristate "i.MX remoteproc support"
depends on ARCH_MXC
+ depends on HAVE_ARM_SMCCC
select MAILBOX
help
Say y here to support iMX's remote processors via the remote
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index d6338872c6db..d88f76f5305e 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -3,6 +3,7 @@
* Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
*/
+#include <linux/arm-smccc.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/interrupt.h>
@@ -50,6 +51,11 @@
#define IMX_RPROC_MEM_MAX 32
+#define IMX_SIP_RPROC 0xC2000005
+#define IMX_SIP_RPROC_START 0x00
+#define IMX_SIP_RPROC_STARTED 0x01
+#define IMX_SIP_RPROC_STOP 0x02
+
/**
* struct imx_rproc_mem - slim internal memory structure
* @cpu_addr: MPU virtual address of the memory region
@@ -74,6 +80,15 @@ struct imx_rproc_att {
int flags;
};
+/* Remote core start/stop method */
+enum imx_rproc_method {
+ IMX_RPROC_NONE,
+ /* Through syscon regmap */
+ IMX_RPROC_MMIO,
+ /* Through ARM SMCCC */
+ IMX_RPROC_SMC,
+};
+
struct imx_rproc_dcfg {
u32 src_reg;
u32 src_mask;
@@ -81,6 +96,7 @@ struct imx_rproc_dcfg {
u32 src_stop;
const struct imx_rproc_att *att;
size_t att_size;
+ enum imx_rproc_method method;
};
struct imx_rproc {
@@ -98,6 +114,36 @@ struct imx_rproc {
void __iomem *rsc_table;
};
+static const struct imx_rproc_att imx_rproc_att_imx8mn[] = {
+ /* dev addr , sys addr , size , flags */
+ /* ITCM */
+ { 0x00000000, 0x007E0000, 0x00020000, ATT_OWN },
+ /* OCRAM_S */
+ { 0x00180000, 0x00180000, 0x00009000, 0 },
+ /* OCRAM */
+ { 0x00900000, 0x00900000, 0x00020000, 0 },
+ /* OCRAM */
+ { 0x00920000, 0x00920000, 0x00020000, 0 },
+ /* OCRAM */
+ { 0x00940000, 0x00940000, 0x00050000, 0 },
+ /* QSPI Code - alias */
+ { 0x08000000, 0x08000000, 0x08000000, 0 },
+ /* DDR (Code) - alias */
+ { 0x10000000, 0x40000000, 0x0FFE0000, 0 },
+ /* DTCM */
+ { 0x20000000, 0x00800000, 0x00020000, ATT_OWN },
+ /* OCRAM_S - alias */
+ { 0x20180000, 0x00180000, 0x00008000, ATT_OWN },
+ /* OCRAM */
+ { 0x20200000, 0x00900000, 0x00020000, ATT_OWN },
+ /* OCRAM */
+ { 0x20220000, 0x00920000, 0x00020000, ATT_OWN },
+ /* OCRAM */
+ { 0x20240000, 0x00940000, 0x00040000, ATT_OWN },
+ /* DDR (Data) */
+ { 0x40000000, 0x40000000, 0x80000000, 0 },
+};
+
static const struct imx_rproc_att imx_rproc_att_imx8mq[] = {
/* dev addr , sys addr , size , flags */
/* TCML - alias */
@@ -126,6 +172,20 @@ static const struct imx_rproc_att imx_rproc_att_imx8mq[] = {
{ 0x40000000, 0x40000000, 0x80000000, 0 },
};
+static const struct imx_rproc_att imx_rproc_att_imx8ulp[] = {
+ {0x1FFC0000, 0x1FFC0000, 0xC0000, ATT_OWN},
+ {0x21000000, 0x21000000, 0x10000, ATT_OWN},
+ {0x80000000, 0x80000000, 0x60000000, 0}
+};
+
+static const struct imx_rproc_att imx_rproc_att_imx7ulp[] = {
+ {0x1FFD0000, 0x1FFD0000, 0x30000, ATT_OWN},
+ {0x20000000, 0x20000000, 0x10000, ATT_OWN},
+ {0x2F000000, 0x2F000000, 0x20000, ATT_OWN},
+ {0x2F020000, 0x2F020000, 0x20000, ATT_OWN},
+ {0x60000000, 0x60000000, 0x40000000, 0}
+};
+
static const struct imx_rproc_att imx_rproc_att_imx7d[] = {
/* dev addr , sys addr , size , flags */
/* OCRAM_S (M4 Boot code) - alias */
@@ -176,6 +236,12 @@ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = {
{ 0x80000000, 0x80000000, 0x60000000, 0 },
};
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = {
+ .att = imx_rproc_att_imx8mn,
+ .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn),
+ .method = IMX_RPROC_SMC,
+};
+
static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = {
.src_reg = IMX7D_SRC_SCR,
.src_mask = IMX7D_M4_RST_MASK,
@@ -183,6 +249,19 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = {
.src_stop = IMX7D_M4_STOP,
.att = imx_rproc_att_imx8mq,
.att_size = ARRAY_SIZE(imx_rproc_att_imx8mq),
+ .method = IMX_RPROC_MMIO,
+};
+
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx8ulp = {
+ .att = imx_rproc_att_imx8ulp,
+ .att_size = ARRAY_SIZE(imx_rproc_att_imx8ulp),
+ .method = IMX_RPROC_NONE,
+};
+
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = {
+ .att = imx_rproc_att_imx7ulp,
+ .att_size = ARRAY_SIZE(imx_rproc_att_imx7ulp),
+ .method = IMX_RPROC_NONE,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = {
@@ -192,6 +271,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = {
.src_stop = IMX7D_M4_STOP,
.att = imx_rproc_att_imx7d,
.att_size = ARRAY_SIZE(imx_rproc_att_imx7d),
+ .method = IMX_RPROC_MMIO,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = {
@@ -201,6 +281,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = {
.src_stop = IMX6SX_M4_STOP,
.att = imx_rproc_att_imx6sx,
.att_size = ARRAY_SIZE(imx_rproc_att_imx6sx),
+ .method = IMX_RPROC_MMIO,
};
static int imx_rproc_start(struct rproc *rproc)
@@ -208,12 +289,24 @@ static int imx_rproc_start(struct rproc *rproc)
struct imx_rproc *priv = rproc->priv;
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
struct device *dev = priv->dev;
+ struct arm_smccc_res res;
int ret;
- ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
- dcfg->src_mask, dcfg->src_start);
+ switch (dcfg->method) {
+ case IMX_RPROC_MMIO:
+ ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask,
+ dcfg->src_start);
+ break;
+ case IMX_RPROC_SMC:
+ arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res);
+ ret = res.a0;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
if (ret)
- dev_err(dev, "Failed to enable M4!\n");
+ dev_err(dev, "Failed to enable remote core!\n");
return ret;
}
@@ -223,12 +316,26 @@ static int imx_rproc_stop(struct rproc *rproc)
struct imx_rproc *priv = rproc->priv;
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
struct device *dev = priv->dev;
+ struct arm_smccc_res res;
int ret;
- ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
- dcfg->src_mask, dcfg->src_stop);
+ switch (dcfg->method) {
+ case IMX_RPROC_MMIO:
+ ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask,
+ dcfg->src_stop);
+ break;
+ case IMX_RPROC_SMC:
+ arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res);
+ ret = res.a0;
+ if (res.a1)
+ dev_info(dev, "Not in wfi, force stopped\n");
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
if (ret)
- dev_err(dev, "Failed to stop M4!\n");
+ dev_err(dev, "Failed to stop remote core\n");
return ret;
}
@@ -560,12 +667,37 @@ static void imx_rproc_free_mbox(struct rproc *rproc)
static int imx_rproc_detect_mode(struct imx_rproc *priv)
{
+ struct regmap_config config = { .name = "imx-rproc" };
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
struct device *dev = priv->dev;
+ struct regmap *regmap;
+ struct arm_smccc_res res;
int ret;
u32 val;
- ret = regmap_read(priv->regmap, dcfg->src_reg, &val);
+ switch (dcfg->method) {
+ case IMX_RPROC_NONE:
+ priv->rproc->state = RPROC_DETACHED;
+ return 0;
+ case IMX_RPROC_SMC:
+ arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res);
+ if (res.a0)
+ priv->rproc->state = RPROC_DETACHED;
+ return 0;
+ default:
+ break;
+ }
+
+ regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "failed to find syscon\n");
+ return PTR_ERR(regmap);
+ }
+
+ priv->regmap = regmap;
+ regmap_attach_dev(dev, regmap, &config);
+
+ ret = regmap_read(regmap, dcfg->src_reg, &val);
if (ret) {
dev_err(dev, "Failed to read src\n");
return ret;
@@ -577,24 +709,44 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv)
return 0;
}
+static int imx_rproc_clk_enable(struct imx_rproc *priv)
+{
+ const struct imx_rproc_dcfg *dcfg = priv->dcfg;
+ struct device *dev = priv->dev;
+ int ret;
+
+ /* Remote core is not under control of Linux */
+ if (dcfg->method == IMX_RPROC_NONE)
+ return 0;
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(dev, "Failed to get clock\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ /*
+ * clk for M4 block including memory. Should be
+ * enabled before .start for FW transfer.
+ */
+ ret = clk_prepare_enable(priv->clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static int imx_rproc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct imx_rproc *priv;
struct rproc *rproc;
- struct regmap_config config = { .name = "imx-rproc" };
const struct imx_rproc_dcfg *dcfg;
- struct regmap *regmap;
int ret;
- regmap = syscon_regmap_lookup_by_phandle(np, "syscon");
- if (IS_ERR(regmap)) {
- dev_err(dev, "failed to find syscon\n");
- return PTR_ERR(regmap);
- }
- regmap_attach_dev(dev, regmap, &config);
-
/* set some other name then imx */
rproc = rproc_alloc(dev, "imx-rproc", &imx_rproc_ops,
NULL, sizeof(*priv));
@@ -609,7 +761,6 @@ static int imx_rproc_probe(struct platform_device *pdev)
priv = rproc->priv;
priv->rproc = rproc;
- priv->regmap = regmap;
priv->dcfg = dcfg;
priv->dev = dev;
@@ -635,25 +786,15 @@ static int imx_rproc_probe(struct platform_device *pdev)
if (ret)
goto err_put_mbox;
- priv->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(priv->clk)) {
- dev_err(dev, "Failed to get clock\n");
- ret = PTR_ERR(priv->clk);
- goto err_put_mbox;
- }
-
- /*
- * clk for M4 block including memory. Should be
- * enabled before .start for FW transfer.
- */
- ret = clk_prepare_enable(priv->clk);
- if (ret) {
- dev_err(&rproc->dev, "Failed to enable clock\n");
+ ret = imx_rproc_clk_enable(priv);
+ if (ret)
goto err_put_mbox;
- }
INIT_WORK(&priv->rproc_work, imx_rproc_vq_work);
+ if (rproc->state != RPROC_DETACHED)
+ rproc->auto_boot = of_property_read_bool(np, "fsl,auto-boot");
+
ret = rproc_add(rproc);
if (ret) {
dev_err(dev, "rproc_add failed\n");
@@ -688,10 +829,14 @@ static int imx_rproc_remove(struct platform_device *pdev)
}
static const struct of_device_id imx_rproc_of_match[] = {
+ { .compatible = "fsl,imx7ulp-cm4", .data = &imx_rproc_cfg_imx7ulp },
{ .compatible = "fsl,imx7d-cm4", .data = &imx_rproc_cfg_imx7d },
{ .compatible = "fsl,imx6sx-cm4", .data = &imx_rproc_cfg_imx6sx },
{ .compatible = "fsl,imx8mq-cm4", .data = &imx_rproc_cfg_imx8mq },
{ .compatible = "fsl,imx8mm-cm4", .data = &imx_rproc_cfg_imx8mq },
+ { .compatible = "fsl,imx8mn-cm7", .data = &imx_rproc_cfg_imx8mn },
+ { .compatible = "fsl,imx8mp-cm7", .data = &imx_rproc_cfg_imx8mn },
+ { .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp },
{},
};
MODULE_DEVICE_TABLE(of, imx_rproc_of_match);
diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
index e5778e476245..1777a01fa84e 100644
--- a/drivers/remoteproc/pru_rproc.c
+++ b/drivers/remoteproc/pru_rproc.c
@@ -887,6 +887,9 @@ static const struct of_device_id pru_rproc_match[] = {
{ .compatible = "ti,am3356-pru", .data = &pru_data },
{ .compatible = "ti,am4376-pru", .data = &pru_data },
{ .compatible = "ti,am5728-pru", .data = &pru_data },
+ { .compatible = "ti,am642-pru", .data = &k3_pru_data },
+ { .compatible = "ti,am642-rtu", .data = &k3_rtu_data },
+ { .compatible = "ti,am642-tx-pru", .data = &k3_tx_pru_data },
{ .compatible = "ti,k2g-pru", .data = &pru_data },
{ .compatible = "ti,am654-pru", .data = &k3_pru_data },
{ .compatible = "ti,am654-rtu", .data = &k3_rtu_data },
diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
index 9627a950928e..7e9244c748da 100644
--- a/drivers/remoteproc/qcom_q6v5.c
+++ b/drivers/remoteproc/qcom_q6v5.c
@@ -280,7 +280,7 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
return ret;
}
- q6v5->state = qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit);
+ q6v5->state = devm_qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit);
if (IS_ERR(q6v5->state)) {
dev_err(&pdev->dev, "failed to acquire stop state\n");
return PTR_ERR(q6v5->state);
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index b921fc26cd04..a79bee901e9b 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -689,6 +689,25 @@ static const struct adsp_data mpss_resource_init = {
.ssctl_id = 0x12,
};
+static const struct adsp_data sc8180x_mpss_resource = {
+ .crash_reason_smem = 421,
+ .firmware_name = "modem.mdt",
+ .pas_id = 4,
+ .has_aggre2_clk = false,
+ .auto_boot = false,
+ .active_pd_names = (char*[]){
+ "load_state",
+ NULL
+ },
+ .proxy_pd_names = (char*[]){
+ "cx",
+ NULL
+ },
+ .ssr_name = "mpss",
+ .sysmon_name = "modem",
+ .ssctl_id = 0x12,
+};
+
static const struct adsp_data slpi_resource_init = {
.crash_reason_smem = 424,
.firmware_name = "slpi.mdt",
@@ -811,6 +830,9 @@ static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init },
{ .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init },
{ .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init},
+ { .compatible = "qcom,sc8180x-adsp-pas", .data = &sm8150_adsp_resource},
+ { .compatible = "qcom,sc8180x-cdsp-pas", .data = &sm8150_cdsp_resource},
+ { .compatible = "qcom,sc8180x-mpss-pas", .data = &sc8180x_mpss_resource},
{ .compatible = "qcom,sdm845-adsp-pas", .data = &adsp_resource_init},
{ .compatible = "qcom,sdm845-cdsp-pas", .data = &cdsp_resource_init},
{ .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource},
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index 5f3455aa7e0e..f1cbc6b2edbb 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -624,8 +624,8 @@ static int wcnss_probe(struct platform_device *pdev)
wcnss->stop_ack_irq = ret;
if (wcnss->stop_ack_irq) {
- wcnss->state = qcom_smem_state_get(&pdev->dev, "stop",
- &wcnss->stop_bit);
+ wcnss->state = devm_qcom_smem_state_get(&pdev->dev, "stop",
+ &wcnss->stop_bit);
if (IS_ERR(wcnss->state)) {
ret = PTR_ERR(wcnss->state);
goto detach_pds;
@@ -659,7 +659,6 @@ static int wcnss_remove(struct platform_device *pdev)
of_platform_depopulate(&pdev->dev);
- qcom_smem_state_put(wcnss->state);
rproc_del(wcnss->rproc);
qcom_remove_sysmon_subdev(wcnss->sysmon);
diff --git a/drivers/remoteproc/remoteproc_cdev.c b/drivers/remoteproc/remoteproc_cdev.c
index 0b8a84c04f76..4ad98b0b8caa 100644
--- a/drivers/remoteproc/remoteproc_cdev.c
+++ b/drivers/remoteproc/remoteproc_cdev.c
@@ -124,7 +124,7 @@ int rproc_char_device_add(struct rproc *rproc)
void rproc_char_device_remove(struct rproc *rproc)
{
- __unregister_chrdev(MAJOR(rproc->dev.devt), rproc->index, 1, "remoteproc");
+ cdev_del(&rproc->cdev);
}
void __init rproc_init_cdev(void)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 626a6b90fba2..7de5905d276a 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/panic_notifier.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/dma-map-ops.h>
@@ -165,6 +166,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
* @rproc: handle of a remote processor
* @da: remoteproc device address to translate
* @len: length of the memory region @da is pointing to
+ * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory
*
* Some remote processors will ask us to allocate them physically contiguous
* memory regions (which we call "carveouts"), and map them to specific
@@ -182,12 +184,12 @@ EXPORT_SYMBOL(rproc_va_to_pa);
* translations on the internal remoteproc memory regions through a platform
* implementation specific da_to_va ops, if present.
*
- * The function returns a valid kernel address on success or NULL on failure.
- *
* Note: phys_to_virt(iommu_iova_to_phys(rproc->domain, da)) will work too,
* but only on kernel direct mapped RAM memory. Instead, we're just using
* here the output of the DMA API for the carveouts, which should be more
* correct.
+ *
+ * Return: a valid kernel address on success or NULL on failure
*/
void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
{
@@ -508,7 +510,7 @@ static int copy_dma_range_map(struct device *to, struct device *from)
* use RSC_DEVMEM resource entries to map their required @da to the physical
* address of their base CMA region (ouch, hacky!).
*
- * Returns 0 on success, or an appropriate error code otherwise
+ * Return: 0 on success, or an appropriate error code otherwise
*/
static int rproc_handle_vdev(struct rproc *rproc, void *ptr,
int offset, int avail)
@@ -643,7 +645,7 @@ void rproc_vdev_release(struct kref *ref)
* support dynamically allocating this address using the generic
* DMA API (but currently there isn't a use case for that).
*
- * Returns 0 on success, or an appropriate error code otherwise
+ * Return: 0 on success, or an appropriate error code otherwise
*/
static int rproc_handle_trace(struct rproc *rproc, void *ptr,
int offset, int avail)
@@ -720,6 +722,8 @@ static int rproc_handle_trace(struct rproc *rproc, void *ptr,
* tell us ranges of physical addresses the firmware is allowed to request,
* and not allow firmwares to request access to physical addresses that
* are outside those ranges.
+ *
+ * Return: 0 on success, or an appropriate error code otherwise
*/
static int rproc_handle_devmem(struct rproc *rproc, void *ptr,
int offset, int avail)
@@ -782,6 +786,8 @@ out:
*
* This function allocate specified memory entry @mem using
* dma_alloc_coherent() as default allocator
+ *
+ * Return: 0 on success, or an appropriate error code otherwise
*/
static int rproc_alloc_carveout(struct rproc *rproc,
struct rproc_mem_entry *mem)
@@ -888,6 +894,8 @@ dma_free:
*
* This function releases specified memory entry @mem allocated via
* rproc_alloc_carveout() function by @rproc.
+ *
+ * Return: 0 on success, or an appropriate error code otherwise
*/
static int rproc_release_carveout(struct rproc *rproc,
struct rproc_mem_entry *mem)
@@ -917,6 +925,8 @@ static int rproc_release_carveout(struct rproc *rproc,
* (e.g. CMA) more efficiently, and also minimizes the number of TLB entries
* needed to map it (in case @rproc is using an IOMMU). Reducing the TLB
* pressure is important; it may have a substantial impact on performance.
+ *
+ * Return: 0 on success, or an appropriate error code otherwise
*/
static int rproc_handle_carveout(struct rproc *rproc,
void *ptr, int offset, int avail)
@@ -1005,6 +1015,8 @@ EXPORT_SYMBOL(rproc_add_carveout);
*
* This function allocates a rproc_mem_entry struct and fill it with parameters
* provided by client.
+ *
+ * Return: a valid pointer on success, or NULL on failure
*/
__printf(8, 9)
struct rproc_mem_entry *
@@ -1049,6 +1061,8 @@ EXPORT_SYMBOL(rproc_mem_entry_init);
*
* This function allocates a rproc_mem_entry struct and fill it with parameters
* provided by client.
+ *
+ * Return: a valid pointer on success, or NULL on failure
*/
__printf(5, 6)
struct rproc_mem_entry *
@@ -1788,7 +1802,7 @@ static int rproc_trigger_auto_boot(struct rproc *rproc)
* We're initiating an asynchronous firmware loading, so we can
* be built-in kernel code, without hanging the boot process.
*/
- ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
rproc->firmware, &rproc->dev, GFP_KERNEL,
rproc, rproc_auto_boot_callback);
if (ret < 0)
@@ -1880,6 +1894,8 @@ static int __rproc_detach(struct rproc *rproc)
* remoteproc functional again.
*
* This function can sleep, so it cannot be called from atomic context.
+ *
+ * Return: 0 on success or a negative value upon failure
*/
int rproc_trigger_recovery(struct rproc *rproc)
{
@@ -1964,7 +1980,7 @@ static void rproc_crash_handler_work(struct work_struct *work)
* If the remote processor is already powered on, this function immediately
* returns (successfully).
*
- * Returns 0 on success, and an appropriate error value otherwise.
+ * Return: 0 on success, and an appropriate error value otherwise
*/
int rproc_boot(struct rproc *rproc)
{
@@ -2099,6 +2115,8 @@ EXPORT_SYMBOL(rproc_shutdown);
* no longer available. From there it should be possible to remove the
* platform driver and even power cycle the application processor (if the HW
* supports it) without needing to switch off the remote processor.
+ *
+ * Return: 0 on success, and an appropriate error value otherwise
*/
int rproc_detach(struct rproc *rproc)
{
@@ -2151,7 +2169,7 @@ EXPORT_SYMBOL(rproc_detach);
* This function increments the remote processor's refcount, so always
* use rproc_put() to decrement it back once rproc isn't needed anymore.
*
- * Returns the rproc handle on success, and NULL on failure.
+ * Return: rproc handle on success, and NULL on failure
*/
#ifdef CONFIG_OF
struct rproc *rproc_get_by_phandle(phandle phandle)
@@ -2301,8 +2319,6 @@ static int rproc_validate(struct rproc *rproc)
* This is called by the platform-specific rproc implementation, whenever
* a new remote processor device is probed.
*
- * Returns 0 on success and an appropriate error code otherwise.
- *
* Note: this function initiates an asynchronous firmware loading
* context, which will look for virtio devices supported by the rproc's
* firmware.
@@ -2310,35 +2326,39 @@ static int rproc_validate(struct rproc *rproc)
* If found, those virtio devices will be created and added, so as a result
* of registering this remote processor, additional virtio drivers might be
* probed.
+ *
+ * Return: 0 on success and an appropriate error code otherwise
*/
int rproc_add(struct rproc *rproc)
{
struct device *dev = &rproc->dev;
int ret;
- ret = device_add(dev);
+ ret = rproc_validate(rproc);
if (ret < 0)
return ret;
- ret = rproc_validate(rproc);
+ /* add char device for this remoteproc */
+ ret = rproc_char_device_add(rproc);
if (ret < 0)
return ret;
+ ret = device_add(dev);
+ if (ret < 0) {
+ put_device(dev);
+ goto rproc_remove_cdev;
+ }
+
dev_info(dev, "%s is available\n", rproc->name);
/* create debugfs entries */
rproc_create_debug_dir(rproc);
- /* add char device for this remoteproc */
- ret = rproc_char_device_add(rproc);
- if (ret < 0)
- return ret;
-
/* if rproc is marked always-on, request it to boot */
if (rproc->auto_boot) {
ret = rproc_trigger_auto_boot(rproc);
if (ret < 0)
- return ret;
+ goto rproc_remove_dev;
}
/* expose to rproc_get_by_phandle users */
@@ -2347,6 +2367,13 @@ int rproc_add(struct rproc *rproc)
mutex_unlock(&rproc_list_mutex);
return 0;
+
+rproc_remove_dev:
+ rproc_delete_debug_dir(rproc);
+ device_del(dev);
+rproc_remove_cdev:
+ rproc_char_device_remove(rproc);
+ return ret;
}
EXPORT_SYMBOL(rproc_add);
@@ -2363,7 +2390,7 @@ static void devm_rproc_remove(void *rproc)
* This function performs like rproc_add() but the registered rproc device will
* automatically be removed on driver detach.
*
- * Returns: 0 on success, negative errno on failure
+ * Return: 0 on success, negative errno on failure
*/
int devm_rproc_add(struct device *dev, struct rproc *rproc)
{
@@ -2471,10 +2498,10 @@ static int rproc_alloc_ops(struct rproc *rproc, const struct rproc_ops *ops)
* implementations should then call rproc_add() to complete
* the registration of the remote processor.
*
- * On success the new rproc is returned, and on failure, NULL.
- *
* Note: _never_ directly deallocate @rproc, even if it was not registered
* yet. Instead, when you need to unroll rproc_alloc(), use rproc_free().
+ *
+ * Return: new rproc pointer on success, and NULL on failure
*/
struct rproc *rproc_alloc(struct device *dev, const char *name,
const struct rproc_ops *ops,
@@ -2587,7 +2614,7 @@ EXPORT_SYMBOL(rproc_put);
* of the outstanding reference created by rproc_alloc. To decrement that
* one last refcount, one still needs to call rproc_free().
*
- * Returns 0 on success and -EINVAL if @rproc isn't valid.
+ * Return: 0 on success and -EINVAL if @rproc isn't valid
*/
int rproc_del(struct rproc *rproc)
{
@@ -2602,7 +2629,6 @@ int rproc_del(struct rproc *rproc)
mutex_unlock(&rproc->lock);
rproc_delete_debug_dir(rproc);
- rproc_char_device_remove(rproc);
/* the rproc is downref'ed as soon as it's removed from the klist */
mutex_lock(&rproc_list_mutex);
@@ -2613,6 +2639,7 @@ int rproc_del(struct rproc *rproc)
synchronize_rcu();
device_del(&rproc->dev);
+ rproc_char_device_remove(rproc);
return 0;
}
@@ -2634,7 +2661,7 @@ static void devm_rproc_free(struct device *dev, void *res)
* This function performs like rproc_alloc() but the acquired rproc device will
* automatically be released on driver detach.
*
- * Returns: new rproc instance, or NULL on failure
+ * Return: new rproc instance, or NULL on failure
*/
struct rproc *devm_rproc_alloc(struct device *dev, const char *name,
const struct rproc_ops *ops,
@@ -2686,7 +2713,7 @@ EXPORT_SYMBOL(rproc_remove_subdev);
* rproc_get_by_child() - acquire rproc handle of @dev's ancestor
* @dev: child device to find ancestor of
*
- * Returns the ancestor rproc instance, or NULL if not found.
+ * Return: the ancestor rproc instance, or NULL if not found
*/
struct rproc *rproc_get_by_child(struct device *dev)
{
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index 11423588965a..469c52e62faf 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -31,6 +31,8 @@
* @fw: the ELF firmware image
*
* Make sure this fw image is sane (ie a correct ELF32/ELF64 file).
+ *
+ * Return: 0 on success and -EINVAL upon any failure
*/
int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
{
@@ -117,11 +119,11 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
* @rproc: the remote processor handle
* @fw: the ELF firmware image
*
- * This function returns the entry point address of the ELF
- * image.
- *
* Note that the boot address is not a configurable property of all remote
* processors. Some will always boot at a specific hard-coded address.
+ *
+ * Return: entry point address of the ELF image
+ *
*/
u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
{
@@ -152,6 +154,8 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
* might be different: they might not have iommus, and would prefer to
* directly allocate memory for every segment/resource. This is not yet
* supported, though.
+ *
+ * Return: 0 on success and an appropriate error code otherwise
*/
int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
{
@@ -362,7 +366,7 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
* This function finds the location of the loaded resource table. Don't
* call this function if the table wasn't loaded yet - it's a bug if you do.
*
- * Returns the pointer to the resource table if it is found or NULL otherwise.
+ * Return: pointer to the resource table if it is found or NULL otherwise.
* If the table wasn't loaded yet the result is unspecified.
*/
struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index 0cc617f76068..cf4d54e98e6a 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -45,7 +45,7 @@ static bool rproc_virtio_notify(struct virtqueue *vq)
* when the remote processor signals that a specific virtqueue has pending
* messages available.
*
- * Returns IRQ_NONE if no message was found in the @notifyid virtqueue,
+ * Return: IRQ_NONE if no message was found in the @notifyid virtqueue,
* and otherwise returns IRQ_HANDLED.
*/
irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid)
@@ -325,7 +325,7 @@ static void rproc_virtio_dev_release(struct device *dev)
* This function registers a virtio device. This vdev's partent is
* the rproc device.
*
- * Returns 0 on success or an appropriate error value otherwise.
+ * Return: 0 on success or an appropriate error value otherwise
*/
int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
{
@@ -432,6 +432,8 @@ out:
* @data: must be null
*
* This function unregisters an existing virtio device.
+ *
+ * Return: 0
*/
int rproc_remove_virtio_dev(struct device *dev, void *data)
{
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
index 7353f9e7e7af..b643efcf995a 100644
--- a/drivers/remoteproc/stm32_rproc.c
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -474,14 +474,12 @@ static int stm32_rproc_attach(struct rproc *rproc)
static int stm32_rproc_detach(struct rproc *rproc)
{
struct stm32_rproc *ddata = rproc->priv;
- int err, dummy_data, idx;
+ int err, idx;
/* Inform the remote processor of the detach */
idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_DETACH);
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);
+ err = mbox_send_message(ddata->mb[idx].chan, "stop");
if (err < 0)
dev_warn(&rproc->dev, "warning: remote FW detach without ack\n");
}
@@ -493,15 +491,13 @@ static int stm32_rproc_detach(struct rproc *rproc)
static int stm32_rproc_stop(struct rproc *rproc)
{
struct stm32_rproc *ddata = rproc->priv;
- int err, dummy_data, idx;
+ int err, 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);
+ err = mbox_send_message(ddata->mb[idx].chan, "detach");
if (err < 0)
dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n");
}
@@ -556,7 +552,7 @@ static void stm32_rproc_kick(struct rproc *rproc, int vqid)
continue;
if (!ddata->mb[i].chan)
return;
- err = mbox_send_message(ddata->mb[i].chan, (void *)(long)vqid);
+ err = mbox_send_message(ddata->mb[i].chan, "kick");
if (err < 0)
dev_err(&rproc->dev, "%s: failed (%s, err:%d)\n",
__func__, ddata->mb[i].name, err);
@@ -580,7 +576,7 @@ static int stm32_rproc_da_to_pa(struct rproc *rproc,
continue;
*pa = da - p_mem->dev_addr + p_mem->bus_addr;
- dev_dbg(dev, "da %llx to pa %#x\n", da, *pa);
+ dev_dbg(dev, "da %llx to pa %pap\n", da, pa);
return 0;
}
diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c
index 5cf8d030a1f0..71615210df3e 100644
--- a/drivers/remoteproc/ti_k3_r5_remoteproc.c
+++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c
@@ -40,6 +40,8 @@
#define PROC_BOOT_CFG_FLAG_R5_ATCM_EN 0x00002000
/* Available from J7200 SoCs onwards */
#define PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS 0x00004000
+/* Applicable to only AM64x SoCs */
+#define PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE 0x00008000
/* R5 TI-SCI Processor Control Flags */
#define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT 0x00000001
@@ -49,6 +51,8 @@
#define PROC_BOOT_STATUS_FLAG_R5_WFI 0x00000002
#define PROC_BOOT_STATUS_FLAG_R5_CLK_GATED 0x00000004
#define PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED 0x00000100
+/* Applicable to only AM64x SoCs */
+#define PROC_BOOT_STATUS_FLAG_R5_SINGLECORE_ONLY 0x00000200
/**
* struct k3_r5_mem - internal memory structure
@@ -64,19 +68,29 @@ struct k3_r5_mem {
size_t size;
};
+/*
+ * All cluster mode values are not applicable on all SoCs. The following
+ * are the modes supported on various SoCs:
+ * Split mode : AM65x, J721E, J7200 and AM64x SoCs
+ * LockStep mode : AM65x, J721E and J7200 SoCs
+ * Single-CPU mode : AM64x SoCs only
+ */
enum cluster_mode {
CLUSTER_MODE_SPLIT = 0,
CLUSTER_MODE_LOCKSTEP,
+ CLUSTER_MODE_SINGLECPU,
};
/**
* struct k3_r5_soc_data - match data to handle SoC variations
* @tcm_is_double: flag to denote the larger unified TCMs in certain modes
* @tcm_ecc_autoinit: flag to denote the auto-initialization of TCMs for ECC
+ * @single_cpu_mode: flag to denote if SoC/IP supports Single-CPU mode
*/
struct k3_r5_soc_data {
bool tcm_is_double;
bool tcm_ecc_autoinit;
+ bool single_cpu_mode;
};
/**
@@ -369,6 +383,13 @@ static inline int k3_r5_core_run(struct k3_r5_core *core)
* applicable cores to allow loading into the TCMs. The .prepare() ops is
* invoked by remoteproc core before any firmware loading, and is followed
* by the .start() ops after loading to actually let the R5 cores run.
+ *
+ * The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to
+ * execute code, but combines the TCMs from both cores. The resets for both
+ * cores need to be released to make this possible, as the TCMs are in general
+ * private to each core. Only Core0 needs to be unhalted for running the
+ * cluster in this mode. The function uses the same reset logic as LockStep
+ * mode for this (though the behavior is agnostic of the reset release order).
*/
static int k3_r5_rproc_prepare(struct rproc *rproc)
{
@@ -386,7 +407,9 @@ static int k3_r5_rproc_prepare(struct rproc *rproc)
return ret;
mem_init_dis = !!(cfg & PROC_BOOT_CFG_FLAG_R5_MEM_INIT_DIS);
- ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ?
+ /* Re-use LockStep-mode reset logic for Single-CPU mode */
+ ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
+ cluster->mode == CLUSTER_MODE_SINGLECPU) ?
k3_r5_lockstep_release(cluster) : k3_r5_split_release(core);
if (ret) {
dev_err(dev, "unable to enable cores for TCM loading, ret = %d\n",
@@ -427,6 +450,12 @@ static int k3_r5_rproc_prepare(struct rproc *rproc)
* cores. The cores themselves are only halted in the .stop() ops, and the
* .unprepare() ops is invoked by the remoteproc core after the remoteproc is
* stopped.
+ *
+ * The Single-CPU mode on applicable SoCs (eg: AM64x) combines the TCMs from
+ * both cores. The access is made possible only with releasing the resets for
+ * both cores, but with only Core0 unhalted. This function re-uses the same
+ * reset assert logic as LockStep mode for this mode (though the behavior is
+ * agnostic of the reset assert order).
*/
static int k3_r5_rproc_unprepare(struct rproc *rproc)
{
@@ -436,7 +465,9 @@ static int k3_r5_rproc_unprepare(struct rproc *rproc)
struct device *dev = kproc->dev;
int ret;
- ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ?
+ /* Re-use LockStep-mode reset logic for Single-CPU mode */
+ ret = (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
+ cluster->mode == CLUSTER_MODE_SINGLECPU) ?
k3_r5_lockstep_reset(cluster) : k3_r5_split_reset(core);
if (ret)
dev_err(dev, "unable to disable cores, ret = %d\n", ret);
@@ -455,6 +486,10 @@ static int k3_r5_rproc_unprepare(struct rproc *rproc)
* first followed by Core0. The Split-mode requires that Core0 to be maintained
* always in a higher power state that Core1 (implying Core1 needs to be started
* always only after Core0 is started).
+ *
+ * The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to execute
+ * code, so only Core0 needs to be unhalted. The function uses the same logic
+ * flow as Split-mode for this.
*/
static int k3_r5_rproc_start(struct rproc *rproc)
{
@@ -539,6 +574,10 @@ put_mbox:
* Core0 to be maintained always in a higher power state that Core1 (implying
* Core1 needs to be stopped first before Core0).
*
+ * The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to execute
+ * code, so only Core0 needs to be halted. The function uses the same logic
+ * flow as Split-mode for this.
+ *
* Note that the R5F halt operation in general is not effective when the R5F
* core is running, but is needed to make sure the core won't run after
* deasserting the reset the subsequent time. The asserting of reset can
@@ -665,7 +704,9 @@ static const struct rproc_ops k3_r5_rproc_ops = {
*
* Each R5FSS has a cluster-level setting for configuring the processor
* subsystem either in a safety/fault-tolerant LockStep mode or a performance
- * oriented Split mode. Each R5F core has a number of settings to either
+ * oriented Split mode on most SoCs. A fewer SoCs support a non-safety mode
+ * as an alternate for LockStep mode that exercises only a single R5F core
+ * called Single-CPU mode. Each R5F core has a number of settings to either
* enable/disable each of the TCMs, control which TCM appears at the R5F core's
* address 0x0. These settings need to be configured before the resets for the
* corresponding core are released. These settings are all protected and managed
@@ -677,11 +718,13 @@ static const struct rproc_ops k3_r5_rproc_ops = {
* the cores are halted before the .prepare() step.
*
* The function is called from k3_r5_cluster_rproc_init() and is invoked either
- * once (in LockStep mode) or twice (in Split mode). Support for LockStep-mode
- * is dictated by an eFUSE register bit, and the config settings retrieved from
- * DT are adjusted accordingly as per the permitted cluster mode. All cluster
- * level settings like Cluster mode and TEINIT (exception handling state
- * dictating ARM or Thumb mode) can only be set and retrieved using Core0.
+ * once (in LockStep mode or Single-CPU modes) or twice (in Split mode). Support
+ * for LockStep-mode is dictated by an eFUSE register bit, and the config
+ * settings retrieved from DT are adjusted accordingly as per the permitted
+ * cluster mode. Another eFUSE register bit dictates if the R5F cluster only
+ * supports a Single-CPU mode. All cluster level settings like Cluster mode and
+ * TEINIT (exception handling state dictating ARM or Thumb mode) can only be set
+ * and retrieved using Core0.
*
* The function behavior is different based on the cluster mode. The R5F cores
* are configured independently as per their individual settings in Split mode.
@@ -700,10 +743,16 @@ static int k3_r5_rproc_configure(struct k3_r5_rproc *kproc)
u32 set_cfg = 0, clr_cfg = 0;
u64 boot_vec = 0;
bool lockstep_en;
+ bool single_cpu;
int ret;
core0 = list_first_entry(&cluster->cores, struct k3_r5_core, elem);
- core = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ? core0 : kproc->core;
+ if (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
+ cluster->mode == CLUSTER_MODE_SINGLECPU) {
+ core = core0;
+ } else {
+ core = kproc->core;
+ }
ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl,
&stat);
@@ -713,23 +762,48 @@ static int k3_r5_rproc_configure(struct k3_r5_rproc *kproc)
dev_dbg(dev, "boot_vector = 0x%llx, cfg = 0x%x ctrl = 0x%x stat = 0x%x\n",
boot_vec, cfg, ctrl, stat);
+ /* check if only Single-CPU mode is supported on applicable SoCs */
+ if (cluster->soc_data->single_cpu_mode) {
+ single_cpu =
+ !!(stat & PROC_BOOT_STATUS_FLAG_R5_SINGLECORE_ONLY);
+ if (single_cpu && cluster->mode == CLUSTER_MODE_SPLIT) {
+ dev_err(cluster->dev, "split-mode not permitted, force configuring for single-cpu mode\n");
+ cluster->mode = CLUSTER_MODE_SINGLECPU;
+ }
+ goto config;
+ }
+
+ /* check conventional LockStep vs Split mode configuration */
lockstep_en = !!(stat & PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED);
if (!lockstep_en && cluster->mode == CLUSTER_MODE_LOCKSTEP) {
dev_err(cluster->dev, "lockstep mode not permitted, force configuring for split-mode\n");
cluster->mode = CLUSTER_MODE_SPLIT;
}
+config:
/* always enable ARM mode and set boot vector to 0 */
boot_vec = 0x0;
if (core == core0) {
clr_cfg = PROC_BOOT_CFG_FLAG_R5_TEINIT;
- /*
- * LockStep configuration bit is Read-only on Split-mode _only_
- * devices and system firmware will NACK any requests with the
- * bit configured, so program it only on permitted devices
- */
- if (lockstep_en)
- clr_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP;
+ if (cluster->soc_data->single_cpu_mode) {
+ /*
+ * Single-CPU configuration bit can only be configured
+ * on Core0 and system firmware will NACK any requests
+ * with the bit configured, so program it only on
+ * permitted cores
+ */
+ if (cluster->mode == CLUSTER_MODE_SINGLECPU)
+ set_cfg = PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE;
+ } else {
+ /*
+ * LockStep configuration bit is Read-only on Split-mode
+ * _only_ devices and system firmware will NACK any
+ * requests with the bit configured, so program it only
+ * on permitted devices
+ */
+ if (lockstep_en)
+ clr_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP;
+ }
}
if (core->atcm_enable)
@@ -894,12 +968,12 @@ static void k3_r5_reserved_mem_exit(struct k3_r5_rproc *kproc)
* cores are usable in Split-mode, but only the Core0 TCMs can be used in
* LockStep-mode. The newer revisions of the R5FSS IP maximizes these TCMs by
* leveraging the Core1 TCMs as well in certain modes where they would have
- * otherwise been unusable (Eg: LockStep-mode on J7200 SoCs). This is done by
- * making a Core1 TCM visible immediately after the corresponding Core0 TCM.
- * The SoC memory map uses the larger 64 KB sizes for the Core0 TCMs, and the
- * dts representation reflects this increased size on supported SoCs. The Core0
- * TCM sizes therefore have to be adjusted to only half the original size in
- * Split mode.
+ * otherwise been unusable (Eg: LockStep-mode on J7200 SoCs, Single-CPU mode on
+ * AM64x SoCs). This is done by making a Core1 TCM visible immediately after the
+ * corresponding Core0 TCM. The SoC memory map uses the larger 64 KB sizes for
+ * the Core0 TCMs, and the dts representation reflects this increased size on
+ * supported SoCs. The Core0 TCM sizes therefore have to be adjusted to only
+ * half the original size in Split mode.
*/
static void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc)
{
@@ -909,6 +983,7 @@ static void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc)
struct k3_r5_core *core0;
if (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
+ cluster->mode == CLUSTER_MODE_SINGLECPU ||
!cluster->soc_data->tcm_is_double)
return;
@@ -987,8 +1062,9 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev)
goto err_add;
}
- /* create only one rproc in lockstep mode */
- if (cluster->mode == CLUSTER_MODE_LOCKSTEP)
+ /* create only one rproc in lockstep mode or single-cpu mode */
+ if (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
+ cluster->mode == CLUSTER_MODE_SINGLECPU)
break;
}
@@ -1020,11 +1096,12 @@ static void k3_r5_cluster_rproc_exit(void *data)
struct rproc *rproc;
/*
- * lockstep mode has only one rproc associated with first core, whereas
- * split-mode has two rprocs associated with each core, and requires
- * that core1 be powered down first
+ * lockstep mode and single-cpu modes have only one rproc associated
+ * with first core, whereas split-mode has two rprocs associated with
+ * each core, and requires that core1 be powered down first
*/
- core = (cluster->mode == CLUSTER_MODE_LOCKSTEP) ?
+ core = (cluster->mode == CLUSTER_MODE_LOCKSTEP ||
+ cluster->mode == CLUSTER_MODE_SINGLECPU) ?
list_first_entry(&cluster->cores, struct k3_r5_core, elem) :
list_last_entry(&cluster->cores, struct k3_r5_core, elem);
@@ -1272,9 +1349,9 @@ static int k3_r5_core_of_init(struct platform_device *pdev)
core->tsp = k3_r5_core_of_get_tsp(dev, core->ti_sci);
if (IS_ERR(core->tsp)) {
+ ret = PTR_ERR(core->tsp);
dev_err(dev, "failed to construct ti-sci proc control, ret = %d\n",
ret);
- ret = PTR_ERR(core->tsp);
goto err;
}
@@ -1396,7 +1473,12 @@ static int k3_r5_probe(struct platform_device *pdev)
return -ENOMEM;
cluster->dev = dev;
- cluster->mode = CLUSTER_MODE_LOCKSTEP;
+ /*
+ * default to most common efuse configurations - Split-mode on AM64x
+ * and LockStep-mode on all others
+ */
+ cluster->mode = data->single_cpu_mode ?
+ CLUSTER_MODE_SPLIT : CLUSTER_MODE_LOCKSTEP;
cluster->soc_data = data;
INIT_LIST_HEAD(&cluster->cores);
@@ -1450,17 +1532,26 @@ static int k3_r5_probe(struct platform_device *pdev)
static const struct k3_r5_soc_data am65_j721e_soc_data = {
.tcm_is_double = false,
.tcm_ecc_autoinit = false,
+ .single_cpu_mode = false,
};
static const struct k3_r5_soc_data j7200_soc_data = {
.tcm_is_double = true,
.tcm_ecc_autoinit = true,
+ .single_cpu_mode = false,
+};
+
+static const struct k3_r5_soc_data am64_soc_data = {
+ .tcm_is_double = true,
+ .tcm_ecc_autoinit = true,
+ .single_cpu_mode = true,
};
static const struct of_device_id k3_r5_of_match[] = {
{ .compatible = "ti,am654-r5fss", .data = &am65_j721e_soc_data, },
{ .compatible = "ti,j721e-r5fss", .data = &am65_j721e_soc_data, },
{ .compatible = "ti,j7200-r5fss", .data = &j7200_soc_data, },
+ { .compatible = "ti,am64-r5fss", .data = &am64_soc_data, },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, k3_r5_of_match);
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 3e7f55e44d84..328f70f633eb 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -43,8 +43,9 @@ config RESET_BCM6345
This enables the reset controller driver for BCM6345 SoCs.
config RESET_BERLIN
- bool "Berlin Reset Driver" if COMPILE_TEST
- default ARCH_BERLIN
+ tristate "Berlin Reset Driver"
+ depends on ARCH_BERLIN || COMPILE_TEST
+ default m if ARCH_BERLIN
help
This enables the reset controller driver for Marvell Berlin SoCs.
@@ -59,7 +60,8 @@ config RESET_BRCMSTB
config RESET_BRCMSTB_RESCAL
bool "Broadcom STB RESCAL reset controller"
depends on HAS_IOMEM
- default ARCH_BRCMSTB || COMPILE_TEST
+ depends on ARCH_BRCMSTB || COMPILE_TEST
+ default ARCH_BRCMSTB
help
This enables the RESCAL reset controller for SATA, PCIe0, or PCIe1 on
BCM7216.
@@ -82,6 +84,7 @@ config RESET_IMX7
config RESET_INTEL_GW
bool "Intel Reset Controller Driver"
+ depends on X86 || COMPILE_TEST
depends on OF && HAS_IOMEM
select REGMAP_MMIO
help
@@ -111,6 +114,14 @@ config RESET_LPC18XX
help
This enables the reset controller driver for NXP LPC18xx/43xx SoCs.
+config RESET_MCHP_SPARX5
+ bool "Microchip Sparx5 reset driver"
+ depends on HAS_IOMEM || COMPILE_TEST
+ default y if SPARX5_SWITCH
+ select MFD_SYSCON
+ help
+ This driver supports switch core reset for the Microchip Sparx5 SoC.
+
config RESET_MESON
tristate "Meson Reset Driver"
depends on ARCH_MESON || COMPILE_TEST
@@ -199,12 +210,6 @@ config RESET_SIMPLE
- ZTE's zx2967 family
- SiFive FU740 SoCs
-config RESET_STM32MP157
- bool "STM32MP157 Reset Driver" if COMPILE_TEST
- default MACH_STM32MP157
- help
- This enables the RCC reset controller driver for STM32 MPUs.
-
config RESET_SOCFPGA
bool "SoCFPGA Reset Driver" if COMPILE_TEST && (!ARM || !ARCH_INTEL_SOCFPGA)
default ARM && ARCH_INTEL_SOCFPGA
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 65a118a91b27..ea8b8d9ca565 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_RESET_INTEL_GW) += reset-intel-gw.o
obj-$(CONFIG_RESET_K210) += reset-k210.o
obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o
obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
+obj-$(CONFIG_RESET_MCHP_SPARX5) += reset-microchip-sparx5.o
obj-$(CONFIG_RESET_MESON) += reset-meson.o
obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
obj-$(CONFIG_RESET_NPCM) += reset-npcm.o
@@ -26,7 +27,6 @@ obj-$(CONFIG_RESET_QCOM_PDC) += reset-qcom-pdc.o
obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o
obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
-obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o
obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 71c1c8264b2d..61e688882643 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -84,7 +84,7 @@ static const char *rcdev_name(struct reset_controller_dev *rcdev)
* without gaps.
*/
static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
- const struct of_phandle_args *reset_spec)
+ const struct of_phandle_args *reset_spec)
{
if (reset_spec->args[0] >= rcdev->nr_resets)
return -EINVAL;
@@ -744,9 +744,9 @@ void reset_control_bulk_release(int num_rstcs,
}
EXPORT_SYMBOL_GPL(reset_control_bulk_release);
-static struct reset_control *__reset_control_get_internal(
- struct reset_controller_dev *rcdev,
- unsigned int index, bool shared, bool acquired)
+static struct reset_control *
+__reset_control_get_internal(struct reset_controller_dev *rcdev,
+ unsigned int index, bool shared, bool acquired)
{
struct reset_control *rstc;
@@ -774,7 +774,10 @@ static struct reset_control *__reset_control_get_internal(
if (!rstc)
return ERR_PTR(-ENOMEM);
- try_module_get(rcdev->owner);
+ if (!try_module_get(rcdev->owner)) {
+ kfree(rstc);
+ return ERR_PTR(-ENODEV);
+ }
rstc->rcdev = rcdev;
list_add(&rstc->list, &rcdev->reset_control_head);
@@ -806,9 +809,9 @@ static void __reset_control_put_internal(struct reset_control *rstc)
kref_put(&rstc->refcnt, __reset_control_release);
}
-struct reset_control *__of_reset_control_get(struct device_node *node,
- const char *id, int index, bool shared,
- bool optional, bool acquired)
+struct reset_control *
+__of_reset_control_get(struct device_node *node, const char *id, int index,
+ bool shared, bool optional, bool acquired)
{
struct reset_control *rstc;
struct reset_controller_dev *r, *rcdev;
@@ -1027,9 +1030,9 @@ static void devm_reset_control_release(struct device *dev, void *res)
reset_control_put(*(struct reset_control **)res);
}
-struct reset_control *__devm_reset_control_get(struct device *dev,
- const char *id, int index, bool shared,
- bool optional, bool acquired)
+struct reset_control *
+__devm_reset_control_get(struct device *dev, const char *id, int index,
+ bool shared, bool optional, bool acquired)
{
struct reset_control **ptr, *rstc;
diff --git a/drivers/reset/hisilicon/hi6220_reset.c b/drivers/reset/hisilicon/hi6220_reset.c
index 19926506d033..5ca145b64e63 100644
--- a/drivers/reset/hisilicon/hi6220_reset.c
+++ b/drivers/reset/hisilicon/hi6220_reset.c
@@ -3,7 +3,7 @@
* Hisilicon Hi6220 reset controller driver
*
* Copyright (c) 2016 Linaro Limited.
- * Copyright (c) 2015-2016 Hisilicon Limited.
+ * Copyright (c) 2015-2016 HiSilicon Limited.
*
* Author: Feng Chen <puck.chen@hisilicon.com>
*/
diff --git a/drivers/reset/reset-a10sr.c b/drivers/reset/reset-a10sr.c
index 7eacc89382f8..99b3bc8382f3 100644
--- a/drivers/reset/reset-a10sr.c
+++ b/drivers/reset/reset-a10sr.c
@@ -118,6 +118,7 @@ static struct platform_driver a10sr_reset_driver = {
.probe = a10sr_reset_probe,
.driver = {
.name = "altr_a10sr_reset",
+ .of_match_table = a10sr_reset_of_match,
},
};
module_platform_driver(a10sr_reset_driver);
diff --git a/drivers/reset/reset-bcm6345.c b/drivers/reset/reset-bcm6345.c
index 737e4e81f6b7..ac6c7ad1deda 100644
--- a/drivers/reset/reset-bcm6345.c
+++ b/drivers/reset/reset-bcm6345.c
@@ -86,7 +86,7 @@ static int bcm6345_reset_status(struct reset_controller_dev *rcdev,
return !(__raw_readl(bcm6345_reset->base) & BIT(id));
}
-static struct reset_control_ops bcm6345_reset_ops = {
+static const struct reset_control_ops bcm6345_reset_ops = {
.assert = bcm6345_reset_assert,
.deassert = bcm6345_reset_deassert,
.reset = bcm6345_reset_reset,
diff --git a/drivers/reset/reset-berlin.c b/drivers/reset/reset-berlin.c
index 371197bbd055..2537ec05ecee 100644
--- a/drivers/reset/reset-berlin.c
+++ b/drivers/reset/reset-berlin.c
@@ -14,7 +14,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
-#include <linux/init.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
@@ -55,7 +55,7 @@ static const struct reset_control_ops berlin_reset_ops = {
static int berlin_reset_xlate(struct reset_controller_dev *rcdev,
const struct of_phandle_args *reset_spec)
{
- unsigned offset, bit;
+ unsigned int offset, bit;
offset = reset_spec->args[0];
bit = reset_spec->args[1];
@@ -93,6 +93,7 @@ static const struct of_device_id berlin_reset_dt_match[] = {
{ .compatible = "marvell,berlin2-reset" },
{ },
};
+MODULE_DEVICE_TABLE(of, berlin_reset_dt_match);
static struct platform_driver berlin_reset_driver = {
.probe = berlin2_reset_probe,
@@ -101,4 +102,9 @@ static struct platform_driver berlin_reset_driver = {
.of_match_table = berlin_reset_dt_match,
},
};
-builtin_platform_driver(berlin_reset_driver);
+module_platform_driver(berlin_reset_driver);
+
+MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");
+MODULE_AUTHOR("Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>");
+MODULE_DESCRIPTION("Synaptics Berlin reset controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/reset/reset-brcmstb.c b/drivers/reset/reset-brcmstb.c
index f213264c8567..42c9d5241c53 100644
--- a/drivers/reset/reset-brcmstb.c
+++ b/drivers/reset/reset-brcmstb.c
@@ -111,6 +111,7 @@ static const struct of_device_id brcmstb_reset_of_match[] = {
{ .compatible = "brcm,brcmstb-reset" },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, brcmstb_reset_of_match);
static struct platform_driver brcmstb_reset_driver = {
.probe = brcmstb_reset_probe,
diff --git a/drivers/reset/reset-lantiq.c b/drivers/reset/reset-lantiq.c
index ac41d093de13..b936cfe85641 100644
--- a/drivers/reset/reset-lantiq.c
+++ b/drivers/reset/reset-lantiq.c
@@ -186,7 +186,7 @@ static int lantiq_rcu_reset_probe(struct platform_device *pdev)
priv->rcdev.of_xlate = lantiq_rcu_reset_xlate;
priv->rcdev.of_reset_n_cells = 2;
- return reset_controller_register(&priv->rcdev);
+ return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
}
static const struct of_device_id lantiq_rcu_reset_dt_ids[] = {
diff --git a/drivers/reset/reset-microchip-sparx5.c b/drivers/reset/reset-microchip-sparx5.c
new file mode 100644
index 000000000000..f01e7db8e83b
--- /dev/null
+++ b/drivers/reset/reset-microchip-sparx5.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip Sparx5 Switch Reset driver
+ *
+ * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
+ *
+ * The Sparx5 Chip Register Model can be browsed at this location:
+ * https://github.com/microchip-ung/sparx-5_reginfo
+ */
+#include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#define PROTECT_REG 0x84
+#define PROTECT_BIT BIT(10)
+#define SOFT_RESET_REG 0x00
+#define SOFT_RESET_BIT BIT(1)
+
+struct mchp_reset_context {
+ struct regmap *cpu_ctrl;
+ struct regmap *gcb_ctrl;
+ struct reset_controller_dev rcdev;
+};
+
+static struct regmap_config sparx5_reset_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static int sparx5_switch_reset(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct mchp_reset_context *ctx =
+ container_of(rcdev, struct mchp_reset_context, rcdev);
+ u32 val;
+
+ /* Make sure the core is PROTECTED from reset */
+ regmap_update_bits(ctx->cpu_ctrl, PROTECT_REG, PROTECT_BIT, PROTECT_BIT);
+
+ /* Start soft reset */
+ regmap_write(ctx->gcb_ctrl, SOFT_RESET_REG, SOFT_RESET_BIT);
+
+ /* Wait for soft reset done */
+ return regmap_read_poll_timeout(ctx->gcb_ctrl, SOFT_RESET_REG, val,
+ (val & SOFT_RESET_BIT) == 0,
+ 1, 100);
+}
+
+static const struct reset_control_ops sparx5_reset_ops = {
+ .reset = sparx5_switch_reset,
+};
+
+static int mchp_sparx5_map_syscon(struct platform_device *pdev, char *name,
+ struct regmap **target)
+{
+ struct device_node *syscon_np;
+ struct regmap *regmap;
+ int err;
+
+ syscon_np = of_parse_phandle(pdev->dev.of_node, name, 0);
+ if (!syscon_np)
+ return -ENODEV;
+ regmap = syscon_node_to_regmap(syscon_np);
+ of_node_put(syscon_np);
+ if (IS_ERR(regmap)) {
+ err = PTR_ERR(regmap);
+ dev_err(&pdev->dev, "No '%s' map: %d\n", name, err);
+ return err;
+ }
+ *target = regmap;
+ return 0;
+}
+
+static int mchp_sparx5_map_io(struct platform_device *pdev, int index,
+ struct regmap **target)
+{
+ struct resource *res;
+ struct regmap *map;
+ void __iomem *mem;
+
+ mem = devm_platform_get_and_ioremap_resource(pdev, index, &res);
+ if (IS_ERR(mem)) {
+ dev_err(&pdev->dev, "Could not map resource %d\n", index);
+ return PTR_ERR(mem);
+ }
+ sparx5_reset_regmap_config.name = res->name;
+ map = devm_regmap_init_mmio(&pdev->dev, mem, &sparx5_reset_regmap_config);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+ *target = map;
+ return 0;
+}
+
+static int mchp_sparx5_reset_probe(struct platform_device *pdev)
+{
+ struct device_node *dn = pdev->dev.of_node;
+ struct mchp_reset_context *ctx;
+ int err;
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ err = mchp_sparx5_map_syscon(pdev, "cpu-syscon", &ctx->cpu_ctrl);
+ if (err)
+ return err;
+ err = mchp_sparx5_map_io(pdev, 0, &ctx->gcb_ctrl);
+ if (err)
+ return err;
+
+ ctx->rcdev.owner = THIS_MODULE;
+ ctx->rcdev.nr_resets = 1;
+ ctx->rcdev.ops = &sparx5_reset_ops;
+ ctx->rcdev.of_node = dn;
+
+ return devm_reset_controller_register(&pdev->dev, &ctx->rcdev);
+}
+
+static const struct of_device_id mchp_sparx5_reset_of_match[] = {
+ {
+ .compatible = "microchip,sparx5-switch-reset",
+ },
+ { }
+};
+
+static struct platform_driver mchp_sparx5_reset_driver = {
+ .probe = mchp_sparx5_reset_probe,
+ .driver = {
+ .name = "sparx5-switch-reset",
+ .of_match_table = mchp_sparx5_reset_of_match,
+ },
+};
+
+static int __init mchp_sparx5_reset_init(void)
+{
+ return platform_driver_register(&mchp_sparx5_reset_driver);
+}
+
+postcore_initcall(mchp_sparx5_reset_init);
+
+MODULE_DESCRIPTION("Microchip Sparx5 switch reset driver");
+MODULE_AUTHOR("Steen Hegelund <steen.hegelund@microchip.com>");
+MODULE_LICENSE("Dual MIT/GPL");
diff --git a/drivers/reset/reset-oxnas.c b/drivers/reset/reset-oxnas.c
index c4013165bdda..8209f922dc16 100644
--- a/drivers/reset/reset-oxnas.c
+++ b/drivers/reset/reset-oxnas.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * drivers/reset/reset-oxnas.c
+ * Oxford Semiconductor Reset Controller driver
*
* Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
* Copyright (C) 2014 Ma Haijun <mahaijuns@gmail.com>
diff --git a/drivers/reset/reset-stm32mp1.c b/drivers/reset/reset-stm32mp1.c
deleted file mode 100644
index b221a28041fa..000000000000
--- a/drivers/reset/reset-stm32mp1.c
+++ /dev/null
@@ -1,115 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
- * Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics.
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/reset-controller.h>
-
-#define CLR_OFFSET 0x4
-
-struct stm32_reset_data {
- struct reset_controller_dev rcdev;
- void __iomem *membase;
-};
-
-static inline struct stm32_reset_data *
-to_stm32_reset_data(struct reset_controller_dev *rcdev)
-{
- return container_of(rcdev, struct stm32_reset_data, rcdev);
-}
-
-static int stm32_reset_update(struct reset_controller_dev *rcdev,
- unsigned long id, bool assert)
-{
- struct stm32_reset_data *data = to_stm32_reset_data(rcdev);
- int reg_width = sizeof(u32);
- int bank = id / (reg_width * BITS_PER_BYTE);
- int offset = id % (reg_width * BITS_PER_BYTE);
- void __iomem *addr;
-
- addr = data->membase + (bank * reg_width);
- if (!assert)
- addr += CLR_OFFSET;
-
- writel(BIT(offset), addr);
-
- return 0;
-}
-
-static int stm32_reset_assert(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- return stm32_reset_update(rcdev, id, true);
-}
-
-static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- return stm32_reset_update(rcdev, id, false);
-}
-
-static int stm32_reset_status(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- struct stm32_reset_data *data = to_stm32_reset_data(rcdev);
- int reg_width = sizeof(u32);
- int bank = id / (reg_width * BITS_PER_BYTE);
- int offset = id % (reg_width * BITS_PER_BYTE);
- u32 reg;
-
- reg = readl(data->membase + (bank * reg_width));
-
- return !!(reg & BIT(offset));
-}
-
-static const struct reset_control_ops stm32_reset_ops = {
- .assert = stm32_reset_assert,
- .deassert = stm32_reset_deassert,
- .status = stm32_reset_status,
-};
-
-static const struct of_device_id stm32_reset_dt_ids[] = {
- { .compatible = "st,stm32mp1-rcc"},
- { /* sentinel */ },
-};
-
-static int stm32_reset_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct stm32_reset_data *data;
- void __iomem *membase;
- struct resource *res;
-
- data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- membase = devm_ioremap_resource(dev, res);
- if (IS_ERR(membase))
- return PTR_ERR(membase);
-
- data->membase = membase;
- data->rcdev.owner = THIS_MODULE;
- data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE;
- data->rcdev.ops = &stm32_reset_ops;
- data->rcdev.of_node = dev->of_node;
-
- return devm_reset_controller_register(dev, &data->rcdev);
-}
-
-static struct platform_driver stm32_reset_driver = {
- .probe = stm32_reset_probe,
- .driver = {
- .name = "stm32mp1-reset",
- .of_match_table = stm32_reset_dt_ids,
- },
-};
-
-builtin_platform_driver(stm32_reset_driver);
diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c
index 218370faf37b..2b92775d58f0 100644
--- a/drivers/reset/reset-ti-syscon.c
+++ b/drivers/reset/reset-ti-syscon.c
@@ -58,8 +58,8 @@ struct ti_syscon_reset_data {
unsigned int nr_controls;
};
-#define to_ti_syscon_reset_data(rcdev) \
- container_of(rcdev, struct ti_syscon_reset_data, rcdev)
+#define to_ti_syscon_reset_data(_rcdev) \
+ container_of(_rcdev, struct ti_syscon_reset_data, rcdev)
/**
* ti_syscon_reset_assert() - assert device reset
diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c
index 279e535bf5d8..5f75783f9397 100644
--- a/drivers/reset/reset-uniphier.c
+++ b/drivers/reset/reset-uniphier.c
@@ -20,7 +20,7 @@ struct uniphier_reset_data {
#define UNIPHIER_RESET_ACTIVE_LOW BIT(0)
};
-#define UNIPHIER_RESET_ID_END (unsigned int)(-1)
+#define UNIPHIER_RESET_ID_END ((unsigned int)(-1))
#define UNIPHIER_RESET_END \
{ .id = UNIPHIER_RESET_ID_END }
diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c
index ebd433fa09dd..daa425e74c96 100644
--- a/drivers/reset/reset-zynqmp.c
+++ b/drivers/reset/reset-zynqmp.c
@@ -83,8 +83,8 @@ static const struct zynqmp_reset_soc_data zynqmp_reset_data = {
};
static const struct zynqmp_reset_soc_data versal_reset_data = {
- .reset_id = 0,
- .num_resets = VERSAL_NR_RESETS,
+ .reset_id = 0,
+ .num_resets = VERSAL_NR_RESETS,
};
static const struct reset_control_ops zynqmp_reset_ops = {
diff --git a/drivers/reset/sti/reset-syscfg.c b/drivers/reset/sti/reset-syscfg.c
index 99b63035fe72..b4b46e0f207e 100644
--- a/drivers/reset/sti/reset-syscfg.c
+++ b/drivers/reset/sti/reset-syscfg.c
@@ -153,7 +153,7 @@ static int syscfg_reset_controller_register(struct device *dev,
if (!rc->channels)
return -ENOMEM;
- rc->rst.ops = &syscfg_reset_ops,
+ rc->rst.ops = &syscfg_reset_ops;
rc->rst.of_node = dev->of_node;
rc->rst.nr_resets = data->nr_channels;
rc->active_low = data->active_low;
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
index e5daee4f9373..c1404d3dae2c 100644
--- a/drivers/rpmsg/rpmsg_core.c
+++ b/drivers/rpmsg/rpmsg_core.c
@@ -459,8 +459,10 @@ static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
if (ids)
for (i = 0; ids[i].name[0]; i++)
- if (rpmsg_id_match(rpdev, &ids[i]))
+ if (rpmsg_id_match(rpdev, &ids[i])) {
+ rpdev->id.driver_data = ids[i].driver_data;
return 1;
+ }
return of_driver_match_device(dev, drv);
}
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index d8c13fded164..12153d5801ce 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -501,11 +501,11 @@ config RTC_DRV_M41T80_WDT
watchdog timer in the ST M41T60 and M41T80 RTC chips series.
config RTC_DRV_BD70528
- tristate "ROHM BD70528, BD71815 and BD71828 PMIC RTC"
- depends on MFD_ROHM_BD71828 || MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG)
+ tristate "ROHM BD71815 and BD71828 PMIC RTC"
+ depends on MFD_ROHM_BD71828
help
If you say Y here you will get support for the RTC
- block on ROHM BD70528, BD71815 and BD71828 Power Management IC.
+ block on ROHM BD71815 and BD71828 Power Management IC.
This driver can also be built as a module. If so, the module
will be called rtc-bd70528.
diff --git a/drivers/rtc/proc.c b/drivers/rtc/proc.c
index 73344598fc1b..cbcdbb19d848 100644
--- a/drivers/rtc/proc.c
+++ b/drivers/rtc/proc.c
@@ -23,8 +23,8 @@ static bool is_rtc_hctosys(struct rtc_device *rtc)
int size;
char name[NAME_SIZE];
- size = scnprintf(name, NAME_SIZE, "rtc%d", rtc->id);
- if (size > NAME_SIZE)
+ size = snprintf(name, NAME_SIZE, "rtc%d", rtc->id);
+ if (size >= NAME_SIZE)
return false;
return !strncmp(name, CONFIG_RTC_HCTOSYS_DEVICE, NAME_SIZE);
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index 2216be429ab7..b7b5ea1a4e67 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -184,7 +184,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
return -EILSEQ;
memset(alrm, 0, sizeof(*alrm));
- if (alarm != ALARM_DISABLED && offset != 0) {
+ if (alarm != ALARM_DISABLED) {
rtc_time64_to_tm(offset + alarm, tm);
dev_dbg(dev, "%s: %ptR\n", __func__, tm);
diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c
index e6428b27b5d4..630ea5de6871 100644
--- a/drivers/rtc/rtc-au1xxx.c
+++ b/drivers/rtc/rtc-au1xxx.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Au1xxx counter0 (aka Time-Of-Year counter) RTC interface driver.
*
* Copyright (C) 2008 Manuel Lauss <mano@roarinelk.homelinux.net>
- *
- * 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.
*/
/* All current Au1xxx SoCs have 2 counters fed by an external 32.768 kHz
diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c
index 6454afca02a6..59b627fc1ecf 100644
--- a/drivers/rtc/rtc-bd70528.c
+++ b/drivers/rtc/rtc-bd70528.c
@@ -2,10 +2,9 @@
//
// Copyright (C) 2018 ROHM Semiconductors
//
-// RTC driver for ROHM BD70528 PMIC
+// RTC driver for ROHM BD71828 and BD71815 PMIC
#include <linux/bcd.h>
-#include <linux/mfd/rohm-bd70528.h>
#include <linux/mfd/rohm-bd71815.h>
#include <linux/mfd/rohm-bd71828.h>
#include <linux/module.h>
@@ -39,11 +38,6 @@ struct bd70528_rtc_data {
u8 year;
} __packed;
-struct bd70528_rtc_wake {
- struct bd70528_rtc_day time;
- u8 ctrl;
-} __packed;
-
struct bd71828_rtc_alm {
struct bd70528_rtc_data alm0;
struct bd70528_rtc_data alm1;
@@ -51,141 +45,14 @@ struct bd71828_rtc_alm {
u8 alm1_mask;
} __packed;
-struct bd70528_rtc_alm {
- struct bd70528_rtc_data data;
- u8 alm_mask;
- u8 alm_repeat;
-} __packed;
-
struct bd70528_rtc {
struct rohm_regmap_dev *parent;
struct regmap *regmap;
struct device *dev;
u8 reg_time_start;
u8 bd718xx_alm_block_start;
- bool has_rtc_timers;
};
-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->parent, 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->parent,
- 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->parent, 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)
-{
- if (!r->has_rtc_timers)
- return 0;
-
- return bd70528_set_rtc_based_timers(r, old_state, NULL);
-}
-
-static int bd70528_disable_rtc_based_timers(struct bd70528_rtc *r,
- int *old_state)
-{
- if (!r->has_rtc_timers)
- return 0;
-
- 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;
@@ -267,52 +134,6 @@ static int bd71828_set_alarm(struct device *dev, struct rtc_wkalrm *a)
}
-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);
-
- ret = regmap_bulk_read(r->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(r->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(r->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(r->regmap, BD70528_REG_RTC_ALM_START, &alm,
- sizeof(alm));
- if (ret)
- dev_err(dev, "Failed to set alarm time\n");
-
- return ret;
-}
-
static int bd71828_read_alarm(struct device *dev, struct rtc_wkalrm *a)
{
int ret;
@@ -336,78 +157,28 @@ static int bd71828_read_alarm(struct device *dev, struct rtc_wkalrm *a)
return 0;
}
-static int bd70528_read_alarm(struct device *dev, struct rtc_wkalrm *a)
+static int bd71828_set_time(struct device *dev, struct rtc_time *t)
{
- struct bd70528_rtc_alm alm;
int ret;
- struct bd70528_rtc *r = dev_get_drvdata(dev);
-
- ret = regmap_bulk_read(r->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);
- ret = bd70528_disable_rtc_based_timers(r, &old_states);
- if (ret)
- return ret;
-
- tmpret = regmap_bulk_read(r->regmap, r->reg_time_start, &rtc_data,
- sizeof(rtc_data));
- if (tmpret) {
+ ret = regmap_bulk_read(r->regmap, r->reg_time_start, &rtc_data,
+ sizeof(rtc_data));
+ if (ret) {
dev_err(dev, "Failed to read RTC time registers\n");
- goto renable_out;
+ return ret;
}
tm2rtc(t, &rtc_data);
- tmpret = regmap_bulk_write(r->regmap, r->reg_time_start, &rtc_data,
- sizeof(rtc_data));
- if (tmpret) {
+ ret = regmap_bulk_write(r->regmap, r->reg_time_start, &rtc_data,
+ sizeof(rtc_data));
+ if (ret)
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 bd71828_set_time(struct device *dev, struct rtc_time *t)
-{
- return bd70528_set_time_locked(dev, t);
-}
-
-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->parent);
- ret = bd70528_set_time_locked(dev, t);
- bd70528_wdt_unlock(r->parent);
- return ret;
-}
-
static int bd70528_get_time(struct device *dev, struct rtc_time *t)
{
struct bd70528_rtc *r = dev_get_drvdata(dev);
@@ -427,31 +198,6 @@ static int bd70528_get_time(struct device *dev, struct rtc_time *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->parent);
- ret = bd70528_set_wake(r->parent, enabled, NULL);
- if (ret) {
- dev_err(dev, "Failed to change wake state\n");
- goto out_unlock;
- }
- ret = regmap_update_bits(r->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->parent);
- return ret;
-}
-
static int bd71828_alm_enable(struct device *dev, unsigned int enabled)
{
int ret;
@@ -470,14 +216,6 @@ static int bd71828_alm_enable(struct device *dev, unsigned int enabled)
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 const struct rtc_class_ops bd71828_rtc_ops = {
.read_time = bd70528_get_time,
.set_time = bd71828_set_time,
@@ -503,7 +241,6 @@ static int bd70528_probe(struct platform_device *pdev)
struct rtc_device *rtc;
int irq;
unsigned int hr;
- bool enable_main_irq = false;
u8 hour_reg;
enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
@@ -518,21 +255,9 @@ static int bd70528_probe(struct platform_device *pdev)
}
bd_rtc->dev = &pdev->dev;
+ rtc_ops = &bd71828_rtc_ops;
switch (chip) {
- case ROHM_CHIP_TYPE_BD70528:
- bd_rtc->parent = dev_get_drvdata(pdev->dev.parent);
- if (!bd_rtc->parent) {
- dev_err(&pdev->dev, "No MFD data\n");
- return -EINVAL;
- }
- irq_name = "bd70528-rtc-alm";
- bd_rtc->has_rtc_timers = true;
- bd_rtc->reg_time_start = BD70528_REG_RTC_START;
- hour_reg = BD70528_REG_RTC_HOUR;
- enable_main_irq = true;
- rtc_ops = &bd70528_rtc_ops;
- break;
case ROHM_CHIP_TYPE_BD71815:
irq_name = "bd71815-rtc-alm-0";
bd_rtc->reg_time_start = BD71815_REG_RTC_START;
@@ -549,14 +274,12 @@ static int bd70528_probe(struct platform_device *pdev)
*/
bd_rtc->bd718xx_alm_block_start = BD71815_REG_RTC_ALM_START;
hour_reg = BD71815_REG_HOUR;
- rtc_ops = &bd71828_rtc_ops;
break;
case ROHM_CHIP_TYPE_BD71828:
irq_name = "bd71828-rtc-alm-0";
bd_rtc->reg_time_start = BD71828_REG_RTC_START;
bd_rtc->bd718xx_alm_block_start = BD71828_REG_RTC_ALM_START;
hour_reg = BD71828_REG_RTC_HOUR;
- rtc_ops = &bd71828_rtc_ops;
break;
default:
dev_err(&pdev->dev, "Unknown chip\n");
@@ -611,27 +334,10 @@ static int bd70528_probe(struct platform_device *pdev)
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.
- */
- if (enable_main_irq) {
- ret = regmap_update_bits(bd_rtc->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;
- }
- }
-
return devm_rtc_register_device(rtc);
}
static const struct platform_device_id bd718x7_rtc_id[] = {
- { "bd70528-rtc", ROHM_CHIP_TYPE_BD70528 },
{ "bd71828-rtc", ROHM_CHIP_TYPE_BD71828 },
{ "bd71815-rtc", ROHM_CHIP_TYPE_BD71815 },
{ },
@@ -649,6 +355,6 @@ static struct platform_driver bd70528_rtc = {
module_platform_driver(bd70528_rtc);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("ROHM BD70528 and BD71828 PMIC RTC driver");
+MODULE_DESCRIPTION("ROHM BD71828 and BD71815 PMIC RTC driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:bd70528-rtc");
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index fab79921a712..8db5a631bca8 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* RTC client/driver for the Maxim/Dallas DS1374 Real-Time Clock over I2C
*
@@ -6,11 +7,7 @@
*
* Copyright (C) 2014 Rose Technology
* Copyright (C) 2006-2007 Freescale Semiconductor
- *
- * 2005 (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.
+ * Copyright (c) 2005 MontaVista Software, Inc.
*/
/*
* It would be more efficient to use i2c msgs/i2c_transfer directly but, as
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index edb64debd173..138c5e0046c8 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -280,7 +280,6 @@ static struct platform_driver efi_rtc_driver = {
module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe);
-MODULE_ALIAS("platform:rtc-efi");
MODULE_AUTHOR("dann frazier <dannf@dannf.org>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EFI RTC driver");
diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c
index 47cd12db2356..16fdefafec5d 100644
--- a/drivers/rtc/rtc-hid-sensor-time.c
+++ b/drivers/rtc/rtc-hid-sensor-time.c
@@ -328,3 +328,4 @@ module_platform_driver(hid_time_platform_driver);
MODULE_DESCRIPTION("HID Sensor Time");
MODULE_AUTHOR("Alexander Holler <holler@ahsoftware.de>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HID);
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index c1806f4d68e7..4b712e5ab08a 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -24,6 +24,7 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
#include <linux/rtc.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
@@ -811,6 +812,9 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, imxdi);
+ device_init_wakeup(&pdev->dev, true);
+ dev_pm_set_wake_irq(&pdev->dev, norm_irq);
+
imxdi->rtc->ops = &dryice_rtc_ops;
imxdi->rtc->range_max = U32_MAX;
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 89128fc29ccc..f736f8c22e96 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -544,10 +544,22 @@ static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80)
{
struct i2c_client *client = m41t80->client;
struct device_node *node = client->dev.of_node;
+ struct device_node *fixed_clock;
struct clk *clk;
struct clk_init_data init;
int ret;
+ fixed_clock = of_get_child_by_name(node, "clock");
+ if (fixed_clock) {
+ /*
+ * skip registering square wave clock when a fixed
+ * clock has been registered. The fixed clock is
+ * registered automatically when being referenced.
+ */
+ of_node_put(fixed_clock);
+ return 0;
+ }
+
/* First disable the clock */
ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
if (ret < 0)
@@ -599,10 +611,8 @@ static unsigned long wdt_is_open;
static int boot_flag;
/**
- * wdt_ping:
- *
- * Reload counter one with the watchdog timeout. We don't bother reloading
- * the cascade counter.
+ * wdt_ping - Reload counter one with the watchdog timeout.
+ * We don't bother reloading the cascade counter.
*/
static void wdt_ping(void)
{
@@ -638,9 +648,7 @@ static void wdt_ping(void)
}
/**
- * wdt_disable:
- *
- * disables watchdog.
+ * wdt_disable - disables watchdog.
*/
static void wdt_disable(void)
{
@@ -677,7 +685,7 @@ static void wdt_disable(void)
}
/**
- * wdt_write:
+ * wdt_write - write to watchdog.
* @file: file handle to the watchdog
* @buf: buffer to write (unused as data does not matter here
* @count: count of bytes
@@ -703,7 +711,7 @@ static ssize_t wdt_read(struct file *file, char __user *buf,
}
/**
- * wdt_ioctl:
+ * wdt_ioctl - ioctl handler to set watchdog.
* @file: file handle to the device
* @cmd: watchdog command
* @arg: argument pointer
@@ -778,7 +786,7 @@ static long wdt_unlocked_ioctl(struct file *file, unsigned int cmd,
}
/**
- * wdt_open:
+ * wdt_open - open a watchdog.
* @inode: inode of device
* @file: file handle to device
*
@@ -802,7 +810,7 @@ static int wdt_open(struct inode *inode, struct file *file)
}
/**
- * wdt_close:
+ * wdt_release - release a watchdog.
* @inode: inode to board
* @file: file handle to board
*
@@ -815,7 +823,7 @@ static int wdt_release(struct inode *inode, struct file *file)
}
/**
- * notify_sys:
+ * wdt_notify_sys - notify to watchdog.
* @this: our notifier block
* @code: the event being reported
* @unused: unused
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index ab60f13fa3ef..4beadfa41644 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -1,14 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* rtc class driver for the Maxim MAX6900 chip
*
+ * Copyright (c) 2007 MontaVista, Software, Inc.
+ *
* Author: Dale Farnsworth <dale@farnsworth.org>
*
* based on previously existing rtc class drivers
- *
- * 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.
*/
#include <linux/module.h>
diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
index d51cc12114cb..eae7cb9faf1e 100644
--- a/drivers/rtc/rtc-max77686.c
+++ b/drivers/rtc/rtc-max77686.c
@@ -717,8 +717,8 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info)
add_rtc_irq:
ret = regmap_add_irq_chip(info->rtc_regmap, info->rtc_irq,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
- IRQF_SHARED, 0, info->drv_data->rtc_irq_chip,
+ IRQF_ONESHOT | IRQF_SHARED,
+ 0, info->drv_data->rtc_irq_chip,
&info->rtc_irq_data);
if (ret < 0) {
dev_err(info->dev, "Failed to add RTC irq chip: %d\n", ret);
diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c
index 6655035e5164..80dc479a6ff0 100644
--- a/drivers/rtc/rtc-mt6397.c
+++ b/drivers/rtc/rtc-mt6397.c
@@ -75,7 +75,7 @@ static int __mtk_rtc_read_time(struct mt6397_rtc *rtc,
tm->tm_min = data[RTC_OFFSET_MIN];
tm->tm_hour = data[RTC_OFFSET_HOUR];
tm->tm_mday = data[RTC_OFFSET_DOM];
- tm->tm_mon = data[RTC_OFFSET_MTH];
+ tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_TC_MTH_MASK;
tm->tm_year = data[RTC_OFFSET_YEAR];
ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_TC_SEC, sec);
diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
index a577a74aaf75..5e0383401629 100644
--- a/drivers/rtc/rtc-mxc_v2.c
+++ b/drivers/rtc/rtc-mxc_v2.c
@@ -372,6 +372,7 @@ static const struct of_device_id mxc_ids[] = {
{ .compatible = "fsl,imx53-rtc", },
{}
};
+MODULE_DEVICE_TABLE(of, mxc_ids);
static struct platform_driver mxc_rtc_driver = {
.driver = {
diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c
index 4bcfb88674d3..67571f7f0bbc 100644
--- a/drivers/rtc/rtc-palmas.c
+++ b/drivers/rtc/rtc-palmas.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* rtc-palmas.c -- Palmas Real Time Clock driver.
@@ -7,20 +8,6 @@
* Copyright (c) 2012, NVIDIA Corporation.
*
* 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 as
- * published by the Free Software Foundation version 2.
- *
- * 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.
- *
- * 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
*/
#include <linux/bcd.h>
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index d13c20a2adf7..56c58b055dff 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -10,7 +10,7 @@
*
* based on the other drivers in this same directory.
*
- * Datasheet: http://cache.nxp.com/documents/data_sheet/PCF2127.pdf
+ * Datasheet: https://www.nxp.com/docs/en/data-sheet/PCF2127.pdf
*/
#include <linux/i2c.h>
@@ -94,10 +94,20 @@
#define PCF2127_WD_VAL_MAX 255
#define PCF2127_WD_VAL_DEFAULT 60
+/* Mask for currently enabled interrupts */
+#define PCF2127_CTRL1_IRQ_MASK (PCF2127_BIT_CTRL1_TSF1)
+#define PCF2127_CTRL2_IRQ_MASK ( \
+ PCF2127_BIT_CTRL2_AF | \
+ PCF2127_BIT_CTRL2_WDTF | \
+ PCF2127_BIT_CTRL2_TSF2)
+
struct pcf2127 {
struct rtc_device *rtc;
struct watchdog_device wdd;
struct regmap *regmap;
+ time64_t ts;
+ bool ts_valid;
+ bool irq_enabled;
};
/*
@@ -434,23 +444,96 @@ static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
return pcf2127_rtc_alarm_irq_enable(dev, alrm->enabled);
}
+/*
+ * This function reads ctrl2 register, caller is responsible for calling
+ * pcf2127_wdt_active_ping()
+ */
+static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts)
+{
+ struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
+ struct rtc_time tm;
+ int ret;
+ unsigned char data[25];
+
+ ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, data,
+ sizeof(data));
+ if (ret) {
+ dev_err(dev, "%s: read error ret=%d\n", __func__, ret);
+ return ret;
+ }
+
+ dev_dbg(dev,
+ "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, ts_sc=%02x, ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n",
+ __func__, data[PCF2127_REG_CTRL1], data[PCF2127_REG_CTRL2],
+ data[PCF2127_REG_CTRL3], data[PCF2127_REG_TS_SC],
+ data[PCF2127_REG_TS_MN], data[PCF2127_REG_TS_HR],
+ data[PCF2127_REG_TS_DM], data[PCF2127_REG_TS_MO],
+ data[PCF2127_REG_TS_YR]);
+
+ tm.tm_sec = bcd2bin(data[PCF2127_REG_TS_SC] & 0x7F);
+ tm.tm_min = bcd2bin(data[PCF2127_REG_TS_MN] & 0x7F);
+ tm.tm_hour = bcd2bin(data[PCF2127_REG_TS_HR] & 0x3F);
+ tm.tm_mday = bcd2bin(data[PCF2127_REG_TS_DM] & 0x3F);
+ /* TS_MO register (month) value range: 1-12 */
+ tm.tm_mon = bcd2bin(data[PCF2127_REG_TS_MO] & 0x1F) - 1;
+ tm.tm_year = bcd2bin(data[PCF2127_REG_TS_YR]);
+ if (tm.tm_year < 70)
+ tm.tm_year += 100; /* assume we are in 1970...2069 */
+
+ ret = rtc_valid_tm(&tm);
+ if (ret) {
+ dev_err(dev, "Invalid timestamp. ret=%d\n", ret);
+ return ret;
+ }
+
+ *ts = rtc_tm_to_time64(&tm);
+ return 0;
+};
+
+static void pcf2127_rtc_ts_snapshot(struct device *dev)
+{
+ struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
+ int ret;
+
+ /* Let userspace read the first timestamp */
+ if (pcf2127->ts_valid)
+ return;
+
+ ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts);
+ if (!ret)
+ pcf2127->ts_valid = true;
+}
+
static irqreturn_t pcf2127_rtc_irq(int irq, void *dev)
{
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
- unsigned int ctrl2 = 0;
+ unsigned int ctrl1, ctrl2;
int ret = 0;
+ ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1);
+ if (ret)
+ return IRQ_NONE;
+
ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2);
if (ret)
return IRQ_NONE;
- if (!(ctrl2 & PCF2127_BIT_CTRL2_AF))
+ if (!(ctrl1 & PCF2127_CTRL1_IRQ_MASK || ctrl2 & PCF2127_CTRL2_IRQ_MASK))
return IRQ_NONE;
- regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2,
- ctrl2 & ~(PCF2127_BIT_CTRL2_AF | PCF2127_BIT_CTRL2_WDTF));
+ if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2)
+ pcf2127_rtc_ts_snapshot(dev);
+
+ if (ctrl1 & PCF2127_CTRL1_IRQ_MASK)
+ regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1,
+ ctrl1 & ~PCF2127_CTRL1_IRQ_MASK);
+
+ if (ctrl2 & PCF2127_CTRL2_IRQ_MASK)
+ regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2,
+ ctrl2 & ~PCF2127_CTRL2_IRQ_MASK);
- rtc_update_irq(pcf2127->rtc, 1, RTC_IRQF | RTC_AF);
+ if (ctrl2 & PCF2127_BIT_CTRL2_AF)
+ rtc_update_irq(pcf2127->rtc, 1, RTC_IRQF | RTC_AF);
pcf2127_wdt_active_ping(&pcf2127->wdd);
@@ -475,23 +558,27 @@ static ssize_t timestamp0_store(struct device *dev,
struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
int ret;
- ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1,
- PCF2127_BIT_CTRL1_TSF1, 0);
- if (ret) {
- dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret);
- return ret;
- }
+ if (pcf2127->irq_enabled) {
+ pcf2127->ts_valid = false;
+ } else {
+ ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1,
+ PCF2127_BIT_CTRL1_TSF1, 0);
+ if (ret) {
+ dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret);
+ return ret;
+ }
- ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
- PCF2127_BIT_CTRL2_TSF2, 0);
- if (ret) {
- dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret);
- return ret;
- }
+ ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
+ PCF2127_BIT_CTRL2_TSF2, 0);
+ if (ret) {
+ dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret);
+ return ret;
+ }
- ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
- if (ret)
- return ret;
+ ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
+ if (ret)
+ return ret;
+ }
return count;
};
@@ -500,50 +587,36 @@ static ssize_t timestamp0_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
- struct rtc_time tm;
+ unsigned int ctrl1, ctrl2;
int ret;
- unsigned char data[25];
-
- ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, data,
- sizeof(data));
- if (ret) {
- dev_err(dev, "%s: read error ret=%d\n", __func__, ret);
- return ret;
- }
-
- dev_dbg(dev,
- "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, ts_sc=%02x, "
- "ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n",
- __func__, data[PCF2127_REG_CTRL1], data[PCF2127_REG_CTRL2],
- data[PCF2127_REG_CTRL3], data[PCF2127_REG_TS_SC],
- data[PCF2127_REG_TS_MN], data[PCF2127_REG_TS_HR],
- data[PCF2127_REG_TS_DM], data[PCF2127_REG_TS_MO],
- data[PCF2127_REG_TS_YR]);
+ time64_t ts;
+
+ if (pcf2127->irq_enabled) {
+ if (!pcf2127->ts_valid)
+ return 0;
+ ts = pcf2127->ts;
+ } else {
+ ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1);
+ if (ret)
+ return 0;
- ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
- if (ret)
- return ret;
+ ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2);
+ if (ret)
+ return 0;
- if (!(data[PCF2127_REG_CTRL1] & PCF2127_BIT_CTRL1_TSF1) &&
- !(data[PCF2127_REG_CTRL2] & PCF2127_BIT_CTRL2_TSF2))
- return 0;
+ if (!(ctrl1 & PCF2127_BIT_CTRL1_TSF1) &&
+ !(ctrl2 & PCF2127_BIT_CTRL2_TSF2))
+ return 0;
- tm.tm_sec = bcd2bin(data[PCF2127_REG_TS_SC] & 0x7F);
- tm.tm_min = bcd2bin(data[PCF2127_REG_TS_MN] & 0x7F);
- tm.tm_hour = bcd2bin(data[PCF2127_REG_TS_HR] & 0x3F);
- tm.tm_mday = bcd2bin(data[PCF2127_REG_TS_DM] & 0x3F);
- /* TS_MO register (month) value range: 1-12 */
- tm.tm_mon = bcd2bin(data[PCF2127_REG_TS_MO] & 0x1F) - 1;
- tm.tm_year = bcd2bin(data[PCF2127_REG_TS_YR]);
- if (tm.tm_year < 70)
- tm.tm_year += 100; /* assume we are in 1970...2069 */
-
- ret = rtc_valid_tm(&tm);
- if (ret)
- return ret;
+ ret = pcf2127_rtc_ts_read(dev->parent, &ts);
+ if (ret)
+ return 0;
- return sprintf(buf, "%llu\n",
- (unsigned long long)rtc_tm_to_time64(&tm));
+ ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
+ if (ret)
+ return ret;
+ }
+ return sprintf(buf, "%llu\n", (unsigned long long)ts);
};
static DEVICE_ATTR_RW(timestamp0);
@@ -594,6 +667,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
dev_err(dev, "failed to request alarm irq\n");
return ret;
}
+ pcf2127->irq_enabled = true;
}
if (alarm_irq > 0 || device_property_read_bool(dev, "wakeup-source")) {
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 82becae14229..14da4ab30104 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -21,10 +21,10 @@
/*
* Information for this driver was pulled from the following datasheets.
*
- * https://www.nxp.com/documents/data_sheet/PCF85063A.pdf
- * https://www.nxp.com/documents/data_sheet/PCF85063TP.pdf
+ * https://www.nxp.com/docs/en/data-sheet/PCF85063A.pdf
+ * https://www.nxp.com/docs/en/data-sheet/PCF85063TP.pdf
*
- * PCF85063A -- Rev. 6 — 18 November 2015
+ * PCF85063A -- Rev. 7 — 30 March 2018
* PCF85063TP -- Rev. 4 — 6 May 2015
*
* https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-8263-C7_App-Manual.pdf
diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c
index 740e2136ca98..8b6fb20774bf 100644
--- a/drivers/rtc/rtc-pcf8523.c
+++ b/drivers/rtc/rtc-pcf8523.c
@@ -10,41 +10,41 @@
#include <linux/of.h>
#include <linux/pm_wakeirq.h>
-#define REG_CONTROL1 0x00
-#define REG_CONTROL1_CAP_SEL BIT(7)
-#define REG_CONTROL1_STOP BIT(5)
-#define REG_CONTROL1_AIE BIT(1)
-
-#define REG_CONTROL2 0x01
-#define REG_CONTROL2_AF BIT(3)
-
-#define REG_CONTROL3 0x02
-#define REG_CONTROL3_PM_BLD BIT(7) /* battery low detection disabled */
-#define REG_CONTROL3_PM_VDD BIT(6) /* switch-over disabled */
-#define REG_CONTROL3_PM_DSM BIT(5) /* direct switching mode */
-#define REG_CONTROL3_PM_MASK 0xe0
-#define REG_CONTROL3_BLF BIT(2) /* battery low bit, read-only */
-
-#define REG_SECONDS 0x03
-#define REG_SECONDS_OS BIT(7)
-
-#define REG_MINUTES 0x04
-#define REG_HOURS 0x05
-#define REG_DAYS 0x06
-#define REG_WEEKDAYS 0x07
-#define REG_MONTHS 0x08
-#define REG_YEARS 0x09
-
-#define REG_MINUTE_ALARM 0x0a
-#define REG_HOUR_ALARM 0x0b
-#define REG_DAY_ALARM 0x0c
-#define REG_WEEKDAY_ALARM 0x0d
+#define PCF8523_REG_CONTROL1 0x00
+#define PCF8523_CONTROL1_CAP_SEL BIT(7)
+#define PCF8523_CONTROL1_STOP BIT(5)
+#define PCF8523_CONTROL1_AIE BIT(1)
+
+#define PCF8523_REG_CONTROL2 0x01
+#define PCF8523_CONTROL2_AF BIT(3)
+
+#define PCF8523_REG_CONTROL3 0x02
+#define PCF8523_CONTROL3_PM_BLD BIT(7) /* battery low detection disabled */
+#define PCF8523_CONTROL3_PM_VDD BIT(6) /* switch-over disabled */
+#define PCF8523_CONTROL3_PM_DSM BIT(5) /* direct switching mode */
+#define PCF8523_CONTROL3_PM_MASK 0xe0
+#define PCF8523_CONTROL3_BLF BIT(2) /* battery low bit, read-only */
+
+#define PCF8523_REG_SECONDS 0x03
+#define PCF8523_SECONDS_OS BIT(7)
+
+#define PCF8523_REG_MINUTES 0x04
+#define PCF8523_REG_HOURS 0x05
+#define PCF8523_REG_DAYS 0x06
+#define PCF8523_REG_WEEKDAYS 0x07
+#define PCF8523_REG_MONTHS 0x08
+#define PCF8523_REG_YEARS 0x09
+
+#define PCF8523_REG_MINUTE_ALARM 0x0a
+#define PCF8523_REG_HOUR_ALARM 0x0b
+#define PCF8523_REG_DAY_ALARM 0x0c
+#define PCF8523_REG_WEEKDAY_ALARM 0x0d
#define ALARM_DIS BIT(7)
-#define REG_OFFSET 0x0e
-#define REG_OFFSET_MODE BIT(7)
+#define PCF8523_REG_OFFSET 0x0e
+#define PCF8523_OFFSET_MODE BIT(7)
-#define REG_TMR_CLKOUT_CTRL 0x0f
+#define PCF8523_TMR_CLKOUT_CTRL 0x0f
struct pcf8523 {
struct rtc_device *rtc;
@@ -99,11 +99,11 @@ static int pcf8523_voltage_low(struct i2c_client *client)
u8 value;
int err;
- err = pcf8523_read(client, REG_CONTROL3, &value);
+ err = pcf8523_read(client, PCF8523_REG_CONTROL3, &value);
if (err < 0)
return err;
- return !!(value & REG_CONTROL3_BLF);
+ return !!(value & PCF8523_CONTROL3_BLF);
}
static int pcf8523_load_capacitance(struct i2c_client *client)
@@ -112,7 +112,7 @@ static int pcf8523_load_capacitance(struct i2c_client *client)
u8 value;
int err;
- err = pcf8523_read(client, REG_CONTROL1, &value);
+ err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value);
if (err < 0)
return err;
@@ -126,14 +126,14 @@ static int pcf8523_load_capacitance(struct i2c_client *client)
load);
fallthrough;
case 12500:
- value |= REG_CONTROL1_CAP_SEL;
+ value |= PCF8523_CONTROL1_CAP_SEL;
break;
case 7000:
- value &= ~REG_CONTROL1_CAP_SEL;
+ value &= ~PCF8523_CONTROL1_CAP_SEL;
break;
}
- err = pcf8523_write(client, REG_CONTROL1, value);
+ err = pcf8523_write(client, PCF8523_REG_CONTROL1, value);
return err;
}
@@ -143,13 +143,13 @@ static int pcf8523_set_pm(struct i2c_client *client, u8 pm)
u8 value;
int err;
- err = pcf8523_read(client, REG_CONTROL3, &value);
+ err = pcf8523_read(client, PCF8523_REG_CONTROL3, &value);
if (err < 0)
return err;
- value = (value & ~REG_CONTROL3_PM_MASK) | pm;
+ value = (value & ~PCF8523_CONTROL3_PM_MASK) | pm;
- err = pcf8523_write(client, REG_CONTROL3, value);
+ err = pcf8523_write(client, PCF8523_REG_CONTROL3, value);
if (err < 0)
return err;
@@ -162,13 +162,13 @@ static irqreturn_t pcf8523_irq(int irq, void *dev_id)
u8 value;
int err;
- err = pcf8523_read(pcf8523->client, REG_CONTROL2, &value);
+ err = pcf8523_read(pcf8523->client, PCF8523_REG_CONTROL2, &value);
if (err < 0)
return IRQ_HANDLED;
- if (value & REG_CONTROL2_AF) {
- value &= ~REG_CONTROL2_AF;
- pcf8523_write(pcf8523->client, REG_CONTROL2, value);
+ if (value & PCF8523_CONTROL2_AF) {
+ value &= ~PCF8523_CONTROL2_AF;
+ pcf8523_write(pcf8523->client, PCF8523_REG_CONTROL2, value);
rtc_update_irq(pcf8523->rtc, 1, RTC_IRQF | RTC_AF);
return IRQ_HANDLED;
@@ -182,13 +182,13 @@ static int pcf8523_stop_rtc(struct i2c_client *client)
u8 value;
int err;
- err = pcf8523_read(client, REG_CONTROL1, &value);
+ err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value);
if (err < 0)
return err;
- value |= REG_CONTROL1_STOP;
+ value |= PCF8523_CONTROL1_STOP;
- err = pcf8523_write(client, REG_CONTROL1, value);
+ err = pcf8523_write(client, PCF8523_REG_CONTROL1, value);
if (err < 0)
return err;
@@ -200,13 +200,13 @@ static int pcf8523_start_rtc(struct i2c_client *client)
u8 value;
int err;
- err = pcf8523_read(client, REG_CONTROL1, &value);
+ err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value);
if (err < 0)
return err;
- value &= ~REG_CONTROL1_STOP;
+ value &= ~PCF8523_CONTROL1_STOP;
- err = pcf8523_write(client, REG_CONTROL1, value);
+ err = pcf8523_write(client, PCF8523_REG_CONTROL1, value);
if (err < 0)
return err;
@@ -216,7 +216,7 @@ static int pcf8523_start_rtc(struct i2c_client *client)
static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct i2c_client *client = to_i2c_client(dev);
- u8 start = REG_SECONDS, regs[7];
+ u8 start = PCF8523_REG_SECONDS, regs[7];
struct i2c_msg msgs[2];
int err;
@@ -242,7 +242,7 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm)
if (err < 0)
return err;
- if (regs[0] & REG_SECONDS_OS)
+ if (regs[0] & PCF8523_SECONDS_OS)
return -EINVAL;
tm->tm_sec = bcd2bin(regs[0] & 0x7f);
@@ -267,8 +267,8 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm)
if (err < 0)
return err;
- regs[0] = REG_SECONDS;
- /* This will purposely overwrite REG_SECONDS_OS */
+ regs[0] = PCF8523_REG_SECONDS;
+ /* This will purposely overwrite PCF8523_SECONDS_OS */
regs[1] = bin2bcd(tm->tm_sec);
regs[2] = bin2bcd(tm->tm_min);
regs[3] = bin2bcd(tm->tm_hour);
@@ -299,7 +299,7 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm)
static int pcf8523_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
{
struct i2c_client *client = to_i2c_client(dev);
- u8 start = REG_MINUTE_ALARM, regs[4];
+ u8 start = PCF8523_REG_MINUTE_ALARM, regs[4];
struct i2c_msg msgs[2];
u8 value;
int err;
@@ -324,15 +324,15 @@ static int pcf8523_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
tm->time.tm_mday = bcd2bin(regs[2] & 0x3F);
tm->time.tm_wday = bcd2bin(regs[3] & 0x7);
- err = pcf8523_read(client, REG_CONTROL1, &value);
+ err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value);
if (err < 0)
return err;
- tm->enabled = !!(value & REG_CONTROL1_AIE);
+ tm->enabled = !!(value & PCF8523_CONTROL1_AIE);
- err = pcf8523_read(client, REG_CONTROL2, &value);
+ err = pcf8523_read(client, PCF8523_REG_CONTROL2, &value);
if (err < 0)
return err;
- tm->pending = !!(value & REG_CONTROL2_AF);
+ tm->pending = !!(value & PCF8523_CONTROL2_AF);
return 0;
}
@@ -343,16 +343,16 @@ static int pcf8523_irq_enable(struct device *dev, unsigned int enabled)
u8 value;
int err;
- err = pcf8523_read(client, REG_CONTROL1, &value);
+ err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value);
if (err < 0)
return err;
- value &= REG_CONTROL1_AIE;
+ value &= PCF8523_CONTROL1_AIE;
if (enabled)
- value |= REG_CONTROL1_AIE;
+ value |= PCF8523_CONTROL1_AIE;
- err = pcf8523_write(client, REG_CONTROL1, value);
+ err = pcf8523_write(client, PCF8523_REG_CONTROL1, value);
if (err < 0)
return err;
@@ -370,7 +370,7 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
if (err)
return err;
- err = pcf8523_write(client, REG_CONTROL2, 0);
+ err = pcf8523_write(client, PCF8523_REG_CONTROL2, 0);
if (err < 0)
return err;
@@ -382,7 +382,7 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
rtc_time64_to_tm(alarm_time, &tm->time);
}
- regs[0] = REG_MINUTE_ALARM;
+ regs[0] = PCF8523_REG_MINUTE_ALARM;
regs[1] = bin2bcd(tm->time.tm_min);
regs[2] = bin2bcd(tm->time.tm_hour);
regs[3] = bin2bcd(tm->time.tm_mday);
@@ -418,11 +418,11 @@ static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd,
if (ret)
flags |= RTC_VL_BACKUP_LOW;
- ret = pcf8523_read(client, REG_SECONDS, &value);
+ ret = pcf8523_read(client, PCF8523_REG_SECONDS, &value);
if (ret < 0)
return ret;
- if (value & REG_SECONDS_OS)
+ if (value & PCF8523_SECONDS_OS)
flags |= RTC_VL_DATA_INVALID;
return put_user(flags, (unsigned int __user *)arg);
@@ -442,13 +442,13 @@ static int pcf8523_rtc_read_offset(struct device *dev, long *offset)
u8 value;
s8 val;
- err = pcf8523_read(client, REG_OFFSET, &value);
+ err = pcf8523_read(client, PCF8523_REG_OFFSET, &value);
if (err < 0)
return err;
/* sign extend the 7-bit offset value */
val = value << 1;
- *offset = (value & REG_OFFSET_MODE ? 4069 : 4340) * (val >> 1);
+ *offset = (value & PCF8523_OFFSET_MODE ? 4069 : 4340) * (val >> 1);
return 0;
}
@@ -465,9 +465,9 @@ static int pcf8523_rtc_set_offset(struct device *dev, long offset)
if (abs(reg_m0 * 4340 - offset) < abs(reg_m1 * 4069 - offset))
value = reg_m0 & 0x7f;
else
- value = (reg_m1 & 0x7f) | REG_OFFSET_MODE;
+ value = (reg_m1 & 0x7f) | PCF8523_OFFSET_MODE;
- return pcf8523_write(client, REG_OFFSET, value);
+ return pcf8523_write(client, PCF8523_REG_OFFSET, value);
}
static const struct rtc_class_ops pcf8523_rtc_ops = {
@@ -519,7 +519,7 @@ static int pcf8523_probe(struct i2c_client *client,
rtc->uie_unsupported = 1;
if (client->irq > 0) {
- err = pcf8523_write(client, REG_TMR_CLKOUT_CTRL, 0x38);
+ err = pcf8523_write(client, PCF8523_TMR_CLKOUT_CTRL, 0x38);
if (err < 0)
return err;
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 18f12f36eb2b..c8bddfb94129 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -8,7 +8,7 @@
*
* based on the other drivers in this same directory.
*
- * http://www.semiconductors.philips.com/acrobat/datasheets/PCF8563-04.pdf
+ * https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf
*/
#include <linux/clk-provider.h>
diff --git a/drivers/rtc/rtc-rtd119x.c b/drivers/rtc/rtc-rtd119x.c
index bb98f2d574a5..8f9abd65846c 100644
--- a/drivers/rtc/rtc-rtd119x.c
+++ b/drivers/rtc/rtc-rtd119x.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Realtek RTD129x RTC
*
* Copyright (c) 2017 Andreas Färber
- *
- * SPDX-License-Identifier: GPL-2.0+
*/
#include <linux/clk.h>
diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c
index 038269a6b08c..6b56f8eacba6 100644
--- a/drivers/rtc/rtc-s5m.c
+++ b/drivers/rtc/rtc-s5m.c
@@ -488,9 +488,7 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
dev_dbg(dev, "%s: %ptR(%d)\n", __func__, &alrm->time, alrm->time.tm_wday);
- ret = s5m_check_peding_alarm_interrupt(info, alrm);
-
- return 0;
+ return s5m_check_peding_alarm_interrupt(info, alrm);
}
static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info)
diff --git a/drivers/rtc/rtc-sc27xx.c b/drivers/rtc/rtc-sc27xx.c
index 187aa955b79c..ce7a2ddbbc16 100644
--- a/drivers/rtc/rtc-sc27xx.c
+++ b/drivers/rtc/rtc-sc27xx.c
@@ -1,7 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2017 Spreadtrum Communications Inc.
*
- * SPDX-License-Identifier: GPL-2.0
*/
#include <linux/bitops.h>
diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c
index ee721e53c155..b4a520056b1a 100644
--- a/drivers/rtc/rtc-spear.c
+++ b/drivers/rtc/rtc-spear.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/rtc/rtc-spear.c
*
* Copyright (C) 2010 ST Microelectronics
* Rajeev Kumar<rajeev-dlh.kumar@st.com>
- *
- * 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/bcd.h>
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
index 75a8924ba12b..ac9e228b56d0 100644
--- a/drivers/rtc/rtc-stm32.c
+++ b/drivers/rtc/rtc-stm32.c
@@ -754,7 +754,7 @@ static int stm32_rtc_probe(struct platform_device *pdev)
ret = clk_prepare_enable(rtc->rtc_ck);
if (ret)
- goto err;
+ goto err_no_rtc_ck;
if (rtc->data->need_dbp)
regmap_update_bits(rtc->dbp, rtc->dbp_reg,
@@ -830,10 +830,12 @@ static int stm32_rtc_probe(struct platform_device *pdev)
}
return 0;
+
err:
+ clk_disable_unprepare(rtc->rtc_ck);
+err_no_rtc_ck:
if (rtc->data->has_pclk)
clk_disable_unprepare(rtc->pclk);
- clk_disable_unprepare(rtc->rtc_ck);
if (rtc->data->need_dbp)
regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0);
diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c
index a980337c3065..52093e7ba22d 100644
--- a/drivers/rtc/rtc-tps6586x.c
+++ b/drivers/rtc/rtc-tps6586x.c
@@ -1,23 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* rtc-tps6586x.c: RTC driver for TI PMIC TPS6586X
*
* Copyright (c) 2012, NVIDIA Corporation.
*
* 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 as
- * published by the Free Software Foundation version 2.
- *
- * 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.
- *
- * 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
*/
#include <linux/device.h>
diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c
index 737f26eb284a..c77b8eab94a0 100644
--- a/drivers/rtc/rtc-tps80031.c
+++ b/drivers/rtc/rtc-tps80031.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* rtc-tps80031.c -- TI TPS80031/TPS80032 RTC driver
*
@@ -7,20 +8,6 @@
* Copyright (c) 2012, NVIDIA Corporation.
*
* 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 as
- * published by the Free Software Foundation version 2.
- *
- * 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.
- *
- * 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
*/
#include <linux/bcd.h>
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
index d2da92187d56..4e8341c49f51 100644
--- a/drivers/rtc/rtc-v3020.c
+++ b/drivers/rtc/rtc-v3020.c
@@ -282,7 +282,7 @@ static int rtc_probe(struct platform_device *pdev)
{
struct v3020_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct v3020 *chip;
- int retval = -EBUSY;
+ int retval;
int i;
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
diff --git a/drivers/rtc/sysfs.c b/drivers/rtc/sysfs.c
index 74026f67fdfb..00f1945bcb7e 100644
--- a/drivers/rtc/sysfs.c
+++ b/drivers/rtc/sysfs.c
@@ -102,7 +102,7 @@ max_user_freq_store(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RW(max_user_freq);
/**
- * rtc_sysfs_show_hctosys - indicate if the given RTC set the system time
+ * hctosys_show - indicate if the given RTC set the system time
* @dev: The device that the attribute belongs to.
* @attr: The attribute being read.
* @buf: The result buffer.
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index c8df75e99f4c..e34c6cc61983 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -621,7 +621,6 @@ void dasd_set_target_state(struct dasd_device *device, int target)
mutex_unlock(&device->state_mutex);
dasd_put_device(device);
}
-EXPORT_SYMBOL(dasd_set_target_state);
/*
* Enable devices with device numbers in [from..to].
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index fd42a5fffaed..6bb775236c16 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -69,25 +69,24 @@ static const u8 DASD_DIAG_CMS1[] = { 0xc3, 0xd4, 0xe2, 0xf1 };/* EBCDIC CMS1 */
* resulting condition code and DIAG return code. */
static inline int __dia250(void *iob, int cmd)
{
- register unsigned long reg2 asm ("2") = (unsigned long) iob;
+ union register_pair rx = { .even = (unsigned long)iob, };
typedef union {
struct dasd_diag_init_io init_io;
struct dasd_diag_rw_io rw_io;
} addr_type;
- int rc;
+ int cc;
- rc = 3;
+ cc = 3;
asm volatile(
- " diag 2,%2,0x250\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- " or %0,3\n"
+ " diag %[rx],%[cmd],0x250\n"
+ "0: ipm %[cc]\n"
+ " srl %[cc],28\n"
"1:\n"
EX_TABLE(0b,1b)
- : "+d" (rc), "=m" (*(addr_type *) iob)
- : "d" (cmd), "d" (reg2), "m" (*(addr_type *) iob)
- : "3", "cc");
- return rc;
+ : [cc] "+&d" (cc), [rx] "+&d" (rx.pair), "+m" (*(addr_type *)iob)
+ : [cmd] "d" (cmd)
+ : "cc");
+ return cc | rx.odd;
}
static inline int dia250(void *iob, int cmd)
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index a6ac505cbdd7..0de1a463c509 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -746,7 +746,7 @@ static void create_uid(struct dasd_eckd_private *private)
memcpy(uid->vendor, private->ned->HDA_manufacturer,
sizeof(uid->vendor) - 1);
EBCASC(uid->vendor, sizeof(uid->vendor) - 1);
- memcpy(uid->serial, private->ned->HDA_location,
+ memcpy(uid->serial, &private->ned->serial,
sizeof(uid->serial) - 1);
EBCASC(uid->serial, sizeof(uid->serial) - 1);
uid->ssid = private->gneq->subsystemID;
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 73651211789f..65e4630ad2ae 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -332,8 +332,10 @@ struct dasd_ned {
__u8 dev_type[6];
__u8 dev_model[3];
__u8 HDA_manufacturer[3];
- __u8 HDA_location[2];
- __u8 HDA_seqno[12];
+ struct {
+ __u8 HDA_location[2];
+ __u8 HDA_seqno[12];
+ } serial;
__u8 ID;
__u8 unit_addr;
} __attribute__ ((packed));
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index 8d6587ec73e2..493e8469893c 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -109,9 +109,9 @@ int dasd_scan_partitions(struct dasd_block *block)
return -ENODEV;
}
- mutex_lock(&bdev->bd_mutex);
- rc = bdev_disk_changed(bdev, false);
- mutex_unlock(&bdev->bd_mutex);
+ mutex_lock(&block->gdp->open_mutex);
+ rc = bdev_disk_changed(block->gdp, false);
+ mutex_unlock(&block->gdp->open_mutex);
if (rc)
DBF_DEV_EVENT(DBF_ERR, block->base,
"scan partitions error, rc %d", rc);
@@ -145,9 +145,9 @@ void dasd_destroy_partitions(struct dasd_block *block)
bdev = block->bdev;
block->bdev = NULL;
- mutex_lock(&bdev->bd_mutex);
- bdev_disk_changed(bdev, true);
- mutex_unlock(&bdev->bd_mutex);
+ mutex_lock(&bdev->bd_disk->open_mutex);
+ bdev_disk_changed(bdev->bd_disk, true);
+ mutex_unlock(&bdev->bd_disk->open_mutex);
/* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
blkdev_put(bdev, FMODE_READ);
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index da33cb4cba28..29180bdf0977 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -17,7 +17,6 @@
#include <linux/blkdev.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
-#include <linux/platform_device.h>
#include <linux/pfn_t.h>
#include <linux/uio.h>
#include <linux/dax.h>
@@ -90,7 +89,6 @@ struct dcssblk_dev_info {
int segment_type;
unsigned char save_pending;
unsigned char is_shared;
- struct request_queue *dcssblk_queue;
int num_of_segments;
struct list_head seg_list;
struct dax_device *dax_dev;
@@ -429,9 +427,7 @@ removeseg:
kill_dax(dev_info->dax_dev);
put_dax(dev_info->dax_dev);
del_gendisk(dev_info->gd);
- blk_cleanup_queue(dev_info->dcssblk_queue);
- dev_info->gd->queue = NULL;
- put_disk(dev_info->gd);
+ blk_cleanup_disk(dev_info->gd);
up_write(&dcssblk_devices_sem);
if (device_remove_file_self(dev, attr)) {
@@ -644,18 +640,17 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
dev_info->dev.release = dcssblk_release_segment;
dev_info->dev.groups = dcssblk_dev_attr_groups;
INIT_LIST_HEAD(&dev_info->lh);
- dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK);
+ dev_info->gd = blk_alloc_disk(NUMA_NO_NODE);
if (dev_info->gd == NULL) {
rc = -ENOMEM;
goto seg_list_del;
}
dev_info->gd->major = dcssblk_major;
+ dev_info->gd->minors = DCSSBLK_MINORS_PER_DISK;
dev_info->gd->fops = &dcssblk_devops;
- dev_info->dcssblk_queue = blk_alloc_queue(NUMA_NO_NODE);
- dev_info->gd->queue = dev_info->dcssblk_queue;
dev_info->gd->private_data = dev_info;
- blk_queue_logical_block_size(dev_info->dcssblk_queue, 4096);
- blk_queue_flag_set(QUEUE_FLAG_DAX, dev_info->dcssblk_queue);
+ blk_queue_logical_block_size(dev_info->gd->queue, 4096);
+ blk_queue_flag_set(QUEUE_FLAG_DAX, dev_info->gd->queue);
seg_byte_size = (dev_info->end - dev_info->start + 1);
set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors
@@ -719,9 +714,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
put_dev:
list_del(&dev_info->lh);
- blk_cleanup_queue(dev_info->dcssblk_queue);
- dev_info->gd->queue = NULL;
- put_disk(dev_info->gd);
+ blk_cleanup_disk(dev_info->gd);
list_for_each_entry(seg_info, &dev_info->seg_list, lh) {
segment_unload(seg_info->segment_name);
}
@@ -731,9 +724,7 @@ put_dev:
dev_list_del:
list_del(&dev_info->lh);
release_gd:
- blk_cleanup_queue(dev_info->dcssblk_queue);
- dev_info->gd->queue = NULL;
- put_disk(dev_info->gd);
+ blk_cleanup_disk(dev_info->gd);
up_write(&dcssblk_devices_sem);
seg_list_del:
if (dev_info == NULL)
@@ -801,9 +792,7 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch
kill_dax(dev_info->dax_dev);
put_dax(dev_info->dax_dev);
del_gendisk(dev_info->gd);
- blk_cleanup_queue(dev_info->dcssblk_queue);
- dev_info->gd->queue = NULL;
- put_disk(dev_info->gd);
+ blk_cleanup_disk(dev_info->gd);
/* unload all related segments */
list_for_each_entry(entry, &dev_info->seg_list, lh)
@@ -994,94 +983,11 @@ dcssblk_check_params(void)
}
/*
- * Suspend / Resume
- */
-static int dcssblk_freeze(struct device *dev)
-{
- struct dcssblk_dev_info *dev_info;
- int rc = 0;
-
- list_for_each_entry(dev_info, &dcssblk_devices, lh) {
- switch (dev_info->segment_type) {
- case SEG_TYPE_SR:
- case SEG_TYPE_ER:
- case SEG_TYPE_SC:
- if (!dev_info->is_shared)
- rc = -EINVAL;
- break;
- default:
- rc = -EINVAL;
- break;
- }
- if (rc)
- break;
- }
- if (rc)
- pr_err("Suspending the system failed because DCSS device %s "
- "is writable\n",
- dev_info->segment_name);
- return rc;
-}
-
-static int dcssblk_restore(struct device *dev)
-{
- struct dcssblk_dev_info *dev_info;
- struct segment_info *entry;
- unsigned long start, end;
- int rc = 0;
-
- list_for_each_entry(dev_info, &dcssblk_devices, lh) {
- list_for_each_entry(entry, &dev_info->seg_list, lh) {
- segment_unload(entry->segment_name);
- rc = segment_load(entry->segment_name, SEGMENT_SHARED,
- &start, &end);
- if (rc < 0) {
-// TODO in_use check ?
- segment_warning(rc, entry->segment_name);
- goto out_panic;
- }
- if (start != entry->start || end != entry->end) {
- pr_err("The address range of DCSS %s changed "
- "while the system was suspended\n",
- entry->segment_name);
- goto out_panic;
- }
- }
- }
- return 0;
-out_panic:
- panic("fatal dcssblk resume error\n");
-}
-
-static int dcssblk_thaw(struct device *dev)
-{
- return 0;
-}
-
-static const struct dev_pm_ops dcssblk_pm_ops = {
- .freeze = dcssblk_freeze,
- .thaw = dcssblk_thaw,
- .restore = dcssblk_restore,
-};
-
-static struct platform_driver dcssblk_pdrv = {
- .driver = {
- .name = "dcssblk",
- .pm = &dcssblk_pm_ops,
- },
-};
-
-static struct platform_device *dcssblk_pdev;
-
-
-/*
* The init/exit functions.
*/
static void __exit
dcssblk_exit(void)
{
- platform_device_unregister(dcssblk_pdev);
- platform_driver_unregister(&dcssblk_pdrv);
root_device_unregister(dcssblk_root_dev);
unregister_blkdev(dcssblk_major, DCSSBLK_NAME);
}
@@ -1091,22 +997,9 @@ dcssblk_init(void)
{
int rc;
- rc = platform_driver_register(&dcssblk_pdrv);
- if (rc)
- return rc;
-
- dcssblk_pdev = platform_device_register_simple("dcssblk", -1, NULL,
- 0);
- if (IS_ERR(dcssblk_pdev)) {
- rc = PTR_ERR(dcssblk_pdev);
- goto out_pdrv;
- }
-
dcssblk_root_dev = root_device_register("dcssblk");
- if (IS_ERR(dcssblk_root_dev)) {
- rc = PTR_ERR(dcssblk_root_dev);
- goto out_pdev;
- }
+ if (IS_ERR(dcssblk_root_dev))
+ return PTR_ERR(dcssblk_root_dev);
rc = device_create_file(dcssblk_root_dev, &dev_attr_add);
if (rc)
goto out_root;
@@ -1124,10 +1017,7 @@ dcssblk_init(void)
out_root:
root_device_unregister(dcssblk_root_dev);
-out_pdev:
- platform_device_unregister(dcssblk_pdev);
-out_pdrv:
- platform_driver_unregister(&dcssblk_pdrv);
+
return rc;
}
diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c
index a4f6f2e62b1d..88cba6212ee2 100644
--- a/drivers/s390/block/scm_blk.c
+++ b/drivers/s390/block/scm_blk.c
@@ -462,12 +462,12 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)
if (ret)
goto out;
- rq = blk_mq_init_queue(&bdev->tag_set);
- if (IS_ERR(rq)) {
- ret = PTR_ERR(rq);
+ bdev->gendisk = blk_mq_alloc_disk(&bdev->tag_set, scmdev);
+ if (IS_ERR(bdev->gendisk)) {
+ ret = PTR_ERR(bdev->gendisk);
goto out_tag;
}
- bdev->rq = rq;
+ rq = bdev->rq = bdev->gendisk->queue;
nr_max_blk = min(scmdev->nr_max_block,
(unsigned int) (PAGE_SIZE / sizeof(struct aidaw)));
@@ -477,17 +477,11 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)
blk_queue_flag_set(QUEUE_FLAG_NONROT, rq);
blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, rq);
- bdev->gendisk = alloc_disk(SCM_NR_PARTS);
- if (!bdev->gendisk) {
- ret = -ENOMEM;
- goto out_queue;
- }
- rq->queuedata = scmdev;
bdev->gendisk->private_data = scmdev;
bdev->gendisk->fops = &scm_blk_devops;
- bdev->gendisk->queue = rq;
bdev->gendisk->major = scm_major;
bdev->gendisk->first_minor = devindex * SCM_NR_PARTS;
+ bdev->gendisk->minors = SCM_NR_PARTS;
len = snprintf(bdev->gendisk->disk_name, DISK_NAME_LEN, "scm");
if (devindex > 25) {
@@ -504,8 +498,6 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)
device_add_disk(&scmdev->dev, bdev->gendisk, NULL);
return 0;
-out_queue:
- blk_cleanup_queue(rq);
out_tag:
blk_mq_free_tag_set(&bdev->tag_set);
out:
@@ -516,9 +508,8 @@ out:
void scm_blk_dev_cleanup(struct scm_blk_dev *bdev)
{
del_gendisk(bdev->gendisk);
- blk_cleanup_queue(bdev->gendisk->queue);
+ blk_cleanup_disk(bdev->gendisk);
blk_mq_free_tag_set(&bdev->tag_set);
- put_disk(bdev->gendisk);
}
void scm_blk_set_available(struct scm_blk_dev *bdev)
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index d1ed39162943..ce98fab4d43c 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -39,8 +39,6 @@
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/device.h>
#include <linux/bio.h>
-#include <linux/suspend.h>
-#include <linux/platform_device.h>
#include <linux/gfp.h>
#include <linux/uaccess.h>
@@ -56,7 +54,6 @@ typedef struct {
static xpram_device_t xpram_devices[XPRAM_MAX_DEVS];
static unsigned int xpram_sizes[XPRAM_MAX_DEVS];
static struct gendisk *xpram_disks[XPRAM_MAX_DEVS];
-static struct request_queue *xpram_queues[XPRAM_MAX_DEVS];
static unsigned int xpram_pages;
static int xpram_devs;
@@ -141,7 +138,7 @@ static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index)
/*
* Check if xpram is available.
*/
-static int xpram_present(void)
+static int __init xpram_present(void)
{
unsigned long mem_page;
int rc;
@@ -157,7 +154,7 @@ static int xpram_present(void)
/*
* Return index of the last available xpram page.
*/
-static unsigned long xpram_highest_page_index(void)
+static unsigned long __init xpram_highest_page_index(void)
{
unsigned int page_index, add_bit;
unsigned long mem_page;
@@ -341,17 +338,13 @@ static int __init xpram_setup_blkdev(void)
int i, rc = -ENOMEM;
for (i = 0; i < xpram_devs; i++) {
- xpram_disks[i] = alloc_disk(1);
+ xpram_disks[i] = blk_alloc_disk(NUMA_NO_NODE);
if (!xpram_disks[i])
goto out;
- xpram_queues[i] = blk_alloc_queue(NUMA_NO_NODE);
- if (!xpram_queues[i]) {
- put_disk(xpram_disks[i]);
- goto out;
- }
- blk_queue_flag_set(QUEUE_FLAG_NONROT, xpram_queues[i]);
- blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, xpram_queues[i]);
- blk_queue_logical_block_size(xpram_queues[i], 4096);
+ blk_queue_flag_set(QUEUE_FLAG_NONROT, xpram_disks[i]->queue);
+ blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM,
+ xpram_disks[i]->queue);
+ blk_queue_logical_block_size(xpram_disks[i]->queue, 4096);
}
/*
@@ -373,9 +366,9 @@ static int __init xpram_setup_blkdev(void)
offset += xpram_devices[i].size;
disk->major = XPRAM_MAJOR;
disk->first_minor = i;
+ disk->minors = 1;
disk->fops = &xpram_devops;
disk->private_data = &xpram_devices[i];
- disk->queue = xpram_queues[i];
sprintf(disk->disk_name, "slram%d", i);
set_capacity(disk, xpram_sizes[i] << 1);
add_disk(disk);
@@ -383,50 +376,12 @@ static int __init xpram_setup_blkdev(void)
return 0;
out:
- while (i--) {
- blk_cleanup_queue(xpram_queues[i]);
- put_disk(xpram_disks[i]);
- }
+ while (i--)
+ blk_cleanup_disk(xpram_disks[i]);
return rc;
}
/*
- * Resume failed: Print error message and call panic.
- */
-static void xpram_resume_error(const char *message)
-{
- pr_err("Resuming the system failed: %s\n", message);
- panic("xpram resume error\n");
-}
-
-/*
- * Check if xpram setup changed between suspend and resume.
- */
-static int xpram_restore(struct device *dev)
-{
- if (!xpram_pages)
- return 0;
- if (xpram_present() != 0)
- xpram_resume_error("xpram disappeared");
- if (xpram_pages != xpram_highest_page_index() + 1)
- xpram_resume_error("Size of xpram changed");
- return 0;
-}
-
-static const struct dev_pm_ops xpram_pm_ops = {
- .restore = xpram_restore,
-};
-
-static struct platform_driver xpram_pdrv = {
- .driver = {
- .name = XPRAM_NAME,
- .pm = &xpram_pm_ops,
- },
-};
-
-static struct platform_device *xpram_pdev;
-
-/*
* Finally, the init/exit functions.
*/
static void __exit xpram_exit(void)
@@ -434,12 +389,9 @@ static void __exit xpram_exit(void)
int i;
for (i = 0; i < xpram_devs; i++) {
del_gendisk(xpram_disks[i]);
- blk_cleanup_queue(xpram_queues[i]);
- put_disk(xpram_disks[i]);
+ blk_cleanup_disk(xpram_disks[i]);
}
unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
- platform_device_unregister(xpram_pdev);
- platform_driver_unregister(&xpram_pdrv);
}
static int __init xpram_init(void)
@@ -457,24 +409,7 @@ static int __init xpram_init(void)
rc = xpram_setup_sizes(xpram_pages);
if (rc)
return rc;
- rc = platform_driver_register(&xpram_pdrv);
- if (rc)
- return rc;
- xpram_pdev = platform_device_register_simple(XPRAM_NAME, -1, NULL, 0);
- if (IS_ERR(xpram_pdev)) {
- rc = PTR_ERR(xpram_pdev);
- goto fail_platform_driver_unregister;
- }
- rc = xpram_setup_blkdev();
- if (rc)
- goto fail_platform_device_unregister;
- return 0;
-
-fail_platform_device_unregister:
- platform_device_unregister(xpram_pdev);
-fail_platform_driver_unregister:
- platform_driver_unregister(&xpram_pdrv);
- return rc;
+ return xpram_setup_blkdev();
}
module_init(xpram_init);
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 1fd5bca9fa20..67c0009ca545 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -19,6 +19,7 @@
#include <linux/console.h>
#include <linux/interrupt.h>
#include <linux/err.h>
+#include <linux/panic_notifier.h>
#include <linux/reboot.h>
#include <linux/serial.h> /* ASYNC_* flags */
#include <linux/slab.h>
@@ -924,7 +925,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp)
/*
* Returns the amount of free space in the output buffer.
*/
-static int tty3215_write_room(struct tty_struct *tty)
+static unsigned int tty3215_write_room(struct tty_struct *tty)
{
struct raw3215_info *raw = tty->driver_data;
@@ -980,7 +981,7 @@ static void tty3215_flush_chars(struct tty_struct *tty)
/*
* Returns the number of characters in the output buffer
*/
-static int tty3215_chars_in_buffer(struct tty_struct *tty)
+static unsigned int tty3215_chars_in_buffer(struct tty_struct *tty)
{
struct raw3215_info *raw = tty->driver_data;
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index e21962c0fd94..87cdbace1453 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/list.h>
+#include <linux/panic_notifier.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/err.h>
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index 7bc616b253f1..9fa92e45e0ee 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -21,7 +21,6 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
-#include <linux/device.h>
#include <linux/slab.h>
#include <net/iucv/iucv.h>
#include <linux/uaccess.h>
@@ -79,8 +78,6 @@ static u8 user_data_sever[16] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
-static struct device *monreader_device;
-
/******************************************************************************
* helper functions *
*****************************************************************************/
@@ -319,7 +316,6 @@ static int mon_open(struct inode *inode, struct file *filp)
goto out_path;
}
filp->private_data = monpriv;
- dev_set_drvdata(monreader_device, monpriv);
return nonseekable_open(inode, filp);
out_path:
@@ -354,7 +350,6 @@ static int mon_close(struct inode *inode, struct file *filp)
atomic_set(&monpriv->msglim_count, 0);
monpriv->write_index = 0;
monpriv->read_index = 0;
- dev_set_drvdata(monreader_device, NULL);
for (i = 0; i < MON_MSGLIM; i++)
kfree(monpriv->msg_array[i]);
@@ -456,94 +451,6 @@ static struct miscdevice mon_dev = {
.minor = MISC_DYNAMIC_MINOR,
};
-
-/******************************************************************************
- * suspend / resume *
- *****************************************************************************/
-static int monreader_freeze(struct device *dev)
-{
- struct mon_private *monpriv = dev_get_drvdata(dev);
- int rc;
-
- if (!monpriv)
- return 0;
- if (monpriv->path) {
- rc = iucv_path_sever(monpriv->path, user_data_sever);
- if (rc)
- pr_warn("Disconnecting the z/VM *MONITOR system service failed with rc=%i\n",
- rc);
- iucv_path_free(monpriv->path);
- }
- atomic_set(&monpriv->iucv_severed, 0);
- atomic_set(&monpriv->iucv_connected, 0);
- atomic_set(&monpriv->read_ready, 0);
- atomic_set(&monpriv->msglim_count, 0);
- monpriv->write_index = 0;
- monpriv->read_index = 0;
- monpriv->path = NULL;
- return 0;
-}
-
-static int monreader_thaw(struct device *dev)
-{
- struct mon_private *monpriv = dev_get_drvdata(dev);
- int rc;
-
- if (!monpriv)
- return 0;
- rc = -ENOMEM;
- monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL);
- if (!monpriv->path)
- goto out;
- rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler,
- MON_SERVICE, NULL, user_data_connect, monpriv);
- if (rc) {
- pr_err("Connecting to the z/VM *MONITOR system service "
- "failed with rc=%i\n", rc);
- goto out_path;
- }
- wait_event(mon_conn_wait_queue,
- atomic_read(&monpriv->iucv_connected) ||
- atomic_read(&monpriv->iucv_severed));
- if (atomic_read(&monpriv->iucv_severed))
- goto out_path;
- return 0;
-out_path:
- rc = -EIO;
- iucv_path_free(monpriv->path);
- monpriv->path = NULL;
-out:
- atomic_set(&monpriv->iucv_severed, 1);
- return rc;
-}
-
-static int monreader_restore(struct device *dev)
-{
- int rc;
-
- segment_unload(mon_dcss_name);
- rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
- &mon_dcss_start, &mon_dcss_end);
- if (rc < 0) {
- segment_warning(rc, mon_dcss_name);
- panic("fatal monreader resume error: no monitor dcss\n");
- }
- return monreader_thaw(dev);
-}
-
-static const struct dev_pm_ops monreader_pm_ops = {
- .freeze = monreader_freeze,
- .thaw = monreader_thaw,
- .restore = monreader_restore,
-};
-
-static struct device_driver monreader_driver = {
- .name = "monreader",
- .bus = &iucv_bus,
- .pm = &monreader_pm_ops,
-};
-
-
/******************************************************************************
* module init/exit *
*****************************************************************************/
@@ -567,36 +474,16 @@ static int __init mon_init(void)
return rc;
}
- rc = driver_register(&monreader_driver);
- if (rc)
- goto out_iucv;
- monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL);
- if (!monreader_device) {
- rc = -ENOMEM;
- goto out_driver;
- }
-
- dev_set_name(monreader_device, "monreader-dev");
- monreader_device->bus = &iucv_bus;
- monreader_device->parent = iucv_root;
- monreader_device->driver = &monreader_driver;
- monreader_device->release = (void (*)(struct device *))kfree;
- rc = device_register(monreader_device);
- if (rc) {
- put_device(monreader_device);
- goto out_driver;
- }
-
rc = segment_type(mon_dcss_name);
if (rc < 0) {
segment_warning(rc, mon_dcss_name);
- goto out_device;
+ goto out_iucv;
}
if (rc != SEG_TYPE_SC) {
pr_err("The specified *MONITOR DCSS %s does not have the "
"required type SC\n", mon_dcss_name);
rc = -EINVAL;
- goto out_device;
+ goto out_iucv;
}
rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
@@ -604,7 +491,7 @@ static int __init mon_init(void)
if (rc < 0) {
segment_warning(rc, mon_dcss_name);
rc = -EINVAL;
- goto out_device;
+ goto out_iucv;
}
dcss_mkname(mon_dcss_name, &user_data_connect[8]);
@@ -619,10 +506,6 @@ static int __init mon_init(void)
out:
segment_unload(mon_dcss_name);
-out_device:
- device_unregister(monreader_device);
-out_driver:
- driver_unregister(&monreader_driver);
out_iucv:
iucv_unregister(&monreader_iucv_handler, 1);
return rc;
@@ -632,8 +515,6 @@ static void __exit mon_exit(void)
{
segment_unload(mon_dcss_name);
misc_deregister(&mon_dev);
- device_unregister(monreader_device);
- driver_unregister(&monreader_driver);
iucv_unregister(&monreader_iucv_handler, 1);
return;
}
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index fdc0c0b7a6f5..9cd1ea92d619 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -20,7 +20,6 @@
#include <linux/ctype.h>
#include <linux/poll.h>
#include <linux/mutex.h>
-#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <asm/ebcdic.h>
@@ -40,10 +39,7 @@ struct mon_buf {
char *data;
};
-static LIST_HEAD(mon_priv_list);
-
struct mon_private {
- struct list_head priv_list;
struct list_head list;
struct monwrite_hdr hdr;
size_t hdr_to_read;
@@ -199,7 +195,6 @@ static int monwrite_open(struct inode *inode, struct file *filp)
monpriv->hdr_to_read = sizeof(monpriv->hdr);
mutex_init(&monpriv->thread_mutex);
filp->private_data = monpriv;
- list_add_tail(&monpriv->priv_list, &mon_priv_list);
return nonseekable_open(inode, filp);
}
@@ -217,7 +212,6 @@ static int monwrite_close(struct inode *inode, struct file *filp)
kfree(entry->data);
kfree(entry);
}
- list_del(&monpriv->priv_list);
kfree(monpriv);
return 0;
}
@@ -294,105 +288,23 @@ static struct miscdevice mon_dev = {
};
/*
- * suspend/resume
- */
-
-static int monwriter_freeze(struct device *dev)
-{
- struct mon_private *monpriv;
- struct mon_buf *monbuf;
-
- list_for_each_entry(monpriv, &mon_priv_list, priv_list) {
- list_for_each_entry(monbuf, &monpriv->list, list) {
- if (monbuf->hdr.mon_function != MONWRITE_GEN_EVENT)
- monwrite_diag(&monbuf->hdr, monbuf->data,
- APPLDATA_STOP_REC);
- }
- }
- return 0;
-}
-
-static int monwriter_restore(struct device *dev)
-{
- struct mon_private *monpriv;
- struct mon_buf *monbuf;
-
- list_for_each_entry(monpriv, &mon_priv_list, priv_list) {
- list_for_each_entry(monbuf, &monpriv->list, list) {
- if (monbuf->hdr.mon_function == MONWRITE_START_INTERVAL)
- monwrite_diag(&monbuf->hdr, monbuf->data,
- APPLDATA_START_INTERVAL_REC);
- if (monbuf->hdr.mon_function == MONWRITE_START_CONFIG)
- monwrite_diag(&monbuf->hdr, monbuf->data,
- APPLDATA_START_CONFIG_REC);
- }
- }
- return 0;
-}
-
-static int monwriter_thaw(struct device *dev)
-{
- return monwriter_restore(dev);
-}
-
-static const struct dev_pm_ops monwriter_pm_ops = {
- .freeze = monwriter_freeze,
- .thaw = monwriter_thaw,
- .restore = monwriter_restore,
-};
-
-static struct platform_driver monwriter_pdrv = {
- .driver = {
- .name = "monwriter",
- .pm = &monwriter_pm_ops,
- },
-};
-
-static struct platform_device *monwriter_pdev;
-
-/*
* module init/exit
*/
static int __init mon_init(void)
{
- int rc;
-
if (!MACHINE_IS_VM)
return -ENODEV;
-
- rc = platform_driver_register(&monwriter_pdrv);
- if (rc)
- return rc;
-
- monwriter_pdev = platform_device_register_simple("monwriter", -1, NULL,
- 0);
- if (IS_ERR(monwriter_pdev)) {
- rc = PTR_ERR(monwriter_pdev);
- goto out_driver;
- }
-
/*
* misc_register() has to be the last action in module_init(), because
* file operations will be available right after this.
*/
- rc = misc_register(&mon_dev);
- if (rc)
- goto out_device;
- return 0;
-
-out_device:
- platform_device_unregister(monwriter_pdev);
-out_driver:
- platform_driver_unregister(&monwriter_pdrv);
- return rc;
+ return misc_register(&mon_dev);
}
static void __exit mon_exit(void)
{
misc_deregister(&mon_dev);
- platform_device_unregister(monwriter_pdev);
- platform_driver_unregister(&monwriter_pdrv);
}
module_init(mon_init);
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 986bbbc23d0a..792b4bfa6d9a 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -11,14 +11,13 @@
#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/err.h>
+#include <linux/panic_notifier.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/reboot.h>
#include <linux/jiffies.h>
#include <linux/init.h>
-#include <linux/suspend.h>
-#include <linux/completion.h>
#include <linux/platform_device.h>
#include <asm/types.h>
#include <asm/irq.h>
@@ -48,9 +47,6 @@ static struct sclp_req sclp_init_req;
static void *sclp_read_sccb;
static struct init_sccb *sclp_init_sccb;
-/* Suspend request */
-static DECLARE_COMPLETION(sclp_request_queue_flushed);
-
/* Number of console pages to allocate, used by sclp_con.c and sclp_vt220.c */
int sclp_console_pages = SCLP_CONSOLE_PAGES;
/* Flag to indicate if buffer pages are dropped on buffer full condition */
@@ -58,11 +54,6 @@ int sclp_console_drop = 1;
/* Number of times the console dropped buffer pages */
unsigned long sclp_console_full;
-static void sclp_suspend_req_cb(struct sclp_req *req, void *data)
-{
- complete(&sclp_request_queue_flushed);
-}
-
static int __init sclp_setup_console_pages(char *str)
{
int pages, rc;
@@ -87,8 +78,6 @@ static int __init sclp_setup_console_drop(char *str)
__setup("sclp_con_drop=", sclp_setup_console_drop);
-static struct sclp_req sclp_suspend_req;
-
/* Timer for request retries. */
static struct timer_list sclp_request_timer;
@@ -122,12 +111,6 @@ static volatile enum sclp_mask_state_t {
sclp_mask_state_initializing
} sclp_mask_state = sclp_mask_state_idle;
-/* Internal state: is the driver suspended? */
-static enum sclp_suspend_state_t {
- sclp_suspend_state_running,
- sclp_suspend_state_suspended,
-} sclp_suspend_state = sclp_suspend_state_running;
-
/* Maximum retry counts */
#define SCLP_INIT_RETRY 3
#define SCLP_MASK_RETRY 3
@@ -313,8 +296,6 @@ sclp_process_queue(void)
del_timer(&sclp_request_timer);
while (!list_empty(&sclp_req_queue)) {
req = list_entry(sclp_req_queue.next, struct sclp_req, list);
- if (!req->sccb)
- goto do_post;
rc = __sclp_start_request(req);
if (rc == 0)
break;
@@ -326,7 +307,6 @@ sclp_process_queue(void)
sclp_request_timeout_normal);
break;
}
-do_post:
/* Post-processing for aborted request */
list_del(&req->list);
if (req->callback) {
@@ -340,10 +320,8 @@ do_post:
static int __sclp_can_add_request(struct sclp_req *req)
{
- if (req == &sclp_suspend_req || req == &sclp_init_req)
+ if (req == &sclp_init_req)
return 1;
- if (sclp_suspend_state != sclp_suspend_state_running)
- return 0;
if (sclp_init_state != sclp_init_state_initialized)
return 0;
if (sclp_activation_state != sclp_activation_state_active)
@@ -377,16 +355,10 @@ sclp_add_request(struct sclp_req *req)
/* Start if request is first in list */
if (sclp_running_state == sclp_running_state_idle &&
req->list.prev == &sclp_req_queue) {
- if (!req->sccb) {
- list_del(&req->list);
- rc = -ENODATA;
- goto out;
- }
rc = __sclp_start_request(req);
if (rc)
list_del(&req->list);
}
-out:
spin_unlock_irqrestore(&sclp_lock, flags);
return rc;
}
@@ -692,7 +664,6 @@ sclp_register(struct sclp_register *reg)
/* Trigger initial state change callback */
reg->sclp_receive_mask = 0;
reg->sclp_send_mask = 0;
- reg->pm_event_posted = 0;
list_add(&reg->list, &sclp_reg_list);
spin_unlock_irqrestore(&sclp_lock, flags);
rc = sclp_init_mask(1);
@@ -1010,112 +981,6 @@ static struct notifier_block sclp_reboot_notifier = {
.notifier_call = sclp_reboot_event
};
-/*
- * Suspend/resume SCLP notifier implementation
- */
-
-static void sclp_pm_event(enum sclp_pm_event sclp_pm_event, int rollback)
-{
- struct sclp_register *reg;
- unsigned long flags;
-
- if (!rollback) {
- spin_lock_irqsave(&sclp_lock, flags);
- list_for_each_entry(reg, &sclp_reg_list, list)
- reg->pm_event_posted = 0;
- spin_unlock_irqrestore(&sclp_lock, flags);
- }
- do {
- spin_lock_irqsave(&sclp_lock, flags);
- list_for_each_entry(reg, &sclp_reg_list, list) {
- if (rollback && reg->pm_event_posted)
- goto found;
- if (!rollback && !reg->pm_event_posted)
- goto found;
- }
- spin_unlock_irqrestore(&sclp_lock, flags);
- return;
-found:
- spin_unlock_irqrestore(&sclp_lock, flags);
- if (reg->pm_event_fn)
- reg->pm_event_fn(reg, sclp_pm_event);
- reg->pm_event_posted = rollback ? 0 : 1;
- } while (1);
-}
-
-/*
- * Susend/resume callbacks for platform device
- */
-
-static int sclp_freeze(struct device *dev)
-{
- unsigned long flags;
- int rc;
-
- sclp_pm_event(SCLP_PM_EVENT_FREEZE, 0);
-
- spin_lock_irqsave(&sclp_lock, flags);
- sclp_suspend_state = sclp_suspend_state_suspended;
- spin_unlock_irqrestore(&sclp_lock, flags);
-
- /* Init supend data */
- memset(&sclp_suspend_req, 0, sizeof(sclp_suspend_req));
- sclp_suspend_req.callback = sclp_suspend_req_cb;
- sclp_suspend_req.status = SCLP_REQ_FILLED;
- init_completion(&sclp_request_queue_flushed);
-
- rc = sclp_add_request(&sclp_suspend_req);
- if (rc == 0)
- wait_for_completion(&sclp_request_queue_flushed);
- else if (rc != -ENODATA)
- goto fail_thaw;
-
- rc = sclp_deactivate();
- if (rc)
- goto fail_thaw;
- return 0;
-
-fail_thaw:
- spin_lock_irqsave(&sclp_lock, flags);
- sclp_suspend_state = sclp_suspend_state_running;
- spin_unlock_irqrestore(&sclp_lock, flags);
- sclp_pm_event(SCLP_PM_EVENT_THAW, 1);
- return rc;
-}
-
-static int sclp_undo_suspend(enum sclp_pm_event event)
-{
- unsigned long flags;
- int rc;
-
- rc = sclp_reactivate();
- if (rc)
- return rc;
-
- spin_lock_irqsave(&sclp_lock, flags);
- sclp_suspend_state = sclp_suspend_state_running;
- spin_unlock_irqrestore(&sclp_lock, flags);
-
- sclp_pm_event(event, 0);
- return 0;
-}
-
-static int sclp_thaw(struct device *dev)
-{
- return sclp_undo_suspend(SCLP_PM_EVENT_THAW);
-}
-
-static int sclp_restore(struct device *dev)
-{
- return sclp_undo_suspend(SCLP_PM_EVENT_RESTORE);
-}
-
-static const struct dev_pm_ops sclp_pm_ops = {
- .freeze = sclp_freeze,
- .thaw = sclp_thaw,
- .restore = sclp_restore,
-};
-
static ssize_t con_pages_show(struct device_driver *dev, char *buf)
{
return sprintf(buf, "%i\n", sclp_console_pages);
@@ -1154,13 +1019,10 @@ static const struct attribute_group *sclp_drv_attr_groups[] = {
static struct platform_driver sclp_pdrv = {
.driver = {
.name = "sclp",
- .pm = &sclp_pm_ops,
.groups = sclp_drv_attr_groups,
},
};
-static struct platform_device *sclp_pdev;
-
/* Initialize SCLP driver. Return zero if driver is operational, non-zero
* otherwise. */
static int
@@ -1214,23 +1076,6 @@ fail_unlock:
return rc;
}
-/*
- * SCLP panic notifier: If we are suspended, we thaw SCLP in order to be able
- * to print the panic message.
- */
-static int sclp_panic_notify(struct notifier_block *self,
- unsigned long event, void *data)
-{
- if (sclp_suspend_state == sclp_suspend_state_suspended)
- sclp_undo_suspend(SCLP_PM_EVENT_THAW);
- return NOTIFY_OK;
-}
-
-static struct notifier_block sclp_on_panic_nb = {
- .notifier_call = sclp_panic_notify,
- .priority = SCLP_PANIC_PRIO,
-};
-
static __init int sclp_initcall(void)
{
int rc;
@@ -1239,23 +1084,7 @@ static __init int sclp_initcall(void)
if (rc)
return rc;
- sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0);
- rc = PTR_ERR_OR_ZERO(sclp_pdev);
- if (rc)
- goto fail_platform_driver_unregister;
-
- rc = atomic_notifier_chain_register(&panic_notifier_list,
- &sclp_on_panic_nb);
- if (rc)
- goto fail_platform_device_unregister;
-
return sclp_init();
-
-fail_platform_device_unregister:
- platform_device_unregister(sclp_pdev);
-fail_platform_driver_unregister:
- platform_driver_unregister(&sclp_pdrv);
- return rc;
}
arch_initcall(sclp_initcall);
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index 6de919944a39..8dd8ad83b78b 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -81,15 +81,6 @@ typedef unsigned int sclp_cmdw_t;
#define GDS_KEY_SELFDEFTEXTMSG 0x31
-enum sclp_pm_event {
- SCLP_PM_EVENT_FREEZE,
- SCLP_PM_EVENT_THAW,
- SCLP_PM_EVENT_RESTORE,
-};
-
-#define SCLP_PANIC_PRIO 1
-#define SCLP_PANIC_PRIO_CLIENT 0
-
typedef u64 sccb_mask_t;
struct sccb_header {
@@ -293,10 +284,6 @@ struct sclp_register {
void (*state_change_fn)(struct sclp_register *);
/* called for events in cp_receive_mask/sclp_receive_mask */
void (*receiver_fn)(struct evbuf_header *);
- /* called for power management events */
- void (*pm_event_fn)(struct sclp_register *, enum sclp_pm_event);
- /* pm event posted flag */
- int pm_event_posted;
};
/* externals from sclp.c */
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index d41bc144c183..ab0518cfdcfe 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -20,7 +20,6 @@
#include <linux/mmzone.h>
#include <linux/memory.h>
#include <linux/module.h>
-#include <linux/platform_device.h>
#include <asm/ctl_reg.h>
#include <asm/chpid.h>
#include <asm/setup.h>
@@ -168,7 +167,6 @@ static DEFINE_MUTEX(sclp_mem_mutex);
static LIST_HEAD(sclp_mem_list);
static u8 sclp_max_storage_id;
static DECLARE_BITMAP(sclp_storage_ids, 256);
-static int sclp_mem_state_changed;
struct memory_increment {
struct list_head list;
@@ -359,8 +357,6 @@ static int sclp_mem_notifier(struct notifier_block *nb,
rc = -EINVAL;
break;
}
- if (!rc)
- sclp_mem_state_changed = 1;
mutex_unlock(&sclp_mem_mutex);
return rc ? NOTIFY_BAD : NOTIFY_OK;
}
@@ -456,28 +452,8 @@ static void __init insert_increment(u16 rn, int standby, int assigned)
list_add(&new_incr->list, prev);
}
-static int sclp_mem_freeze(struct device *dev)
-{
- if (!sclp_mem_state_changed)
- return 0;
- pr_err("Memory hotplug state changed, suspend refused.\n");
- return -EPERM;
-}
-
-static const struct dev_pm_ops sclp_mem_pm_ops = {
- .freeze = sclp_mem_freeze,
-};
-
-static struct platform_driver sclp_mem_pdrv = {
- .driver = {
- .name = "sclp_mem",
- .pm = &sclp_mem_pm_ops,
- },
-};
-
static int __init sclp_detect_standby_memory(void)
{
- struct platform_device *sclp_pdev;
struct read_storage_sccb *sccb;
int i, id, assigned, rc;
@@ -530,17 +506,7 @@ static int __init sclp_detect_standby_memory(void)
rc = register_memory_notifier(&sclp_mem_nb);
if (rc)
goto out;
- rc = platform_driver_register(&sclp_mem_pdrv);
- if (rc)
- goto out;
- sclp_pdev = platform_device_register_simple("sclp_mem", -1, NULL, 0);
- rc = PTR_ERR_OR_ZERO(sclp_pdev);
- if (rc)
- goto out_driver;
sclp_add_standby_memory();
- goto out;
-out_driver:
- platform_driver_unregister(&sclp_mem_pdrv);
out:
free_page((unsigned long) sccb);
return rc;
diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c
index 9b852a47ccc1..de028868c6f4 100644
--- a/drivers/s390/char/sclp_con.c
+++ b/drivers/s390/char/sclp_con.c
@@ -10,6 +10,7 @@
#include <linux/kmod.h>
#include <linux/console.h>
#include <linux/init.h>
+#include <linux/panic_notifier.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/termios.h>
@@ -35,8 +36,6 @@ static LIST_HEAD(sclp_con_outqueue);
static struct sclp_buffer *sclp_conbuf;
/* Timer for delayed output of console messages */
static struct timer_list sclp_con_timer;
-/* Suspend mode flag */
-static int sclp_con_suspended;
/* Flag that output queue is currently running */
static int sclp_con_queue_running;
@@ -63,7 +62,7 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc)
if (!list_empty(&sclp_con_outqueue))
buffer = list_first_entry(&sclp_con_outqueue,
struct sclp_buffer, list);
- if (!buffer || sclp_con_suspended) {
+ if (!buffer) {
sclp_con_queue_running = 0;
spin_unlock_irqrestore(&sclp_con_lock, flags);
break;
@@ -85,7 +84,7 @@ static void sclp_conbuf_emit(void)
if (sclp_conbuf)
list_add_tail(&sclp_conbuf->list, &sclp_con_outqueue);
sclp_conbuf = NULL;
- if (sclp_con_queue_running || sclp_con_suspended)
+ if (sclp_con_queue_running)
goto out_unlock;
if (list_empty(&sclp_con_outqueue))
goto out_unlock;
@@ -179,8 +178,6 @@ sclp_console_write(struct console *console, const char *message,
if (list_empty(&sclp_con_pages))
sclp_console_full++;
while (list_empty(&sclp_con_pages)) {
- if (sclp_con_suspended)
- goto out;
if (sclp_console_drop_buffer())
break;
spin_unlock_irqrestore(&sclp_con_lock, flags);
@@ -213,7 +210,6 @@ sclp_console_write(struct console *console, const char *message,
!timer_pending(&sclp_con_timer)) {
mod_timer(&sclp_con_timer, jiffies + HZ / 10);
}
-out:
spin_unlock_irqrestore(&sclp_con_lock, flags);
}
@@ -234,32 +230,6 @@ sclp_console_flush(void)
sclp_console_sync_queue();
}
-/*
- * Resume console: If there are cached messages, emit them.
- */
-static void sclp_console_resume(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sclp_con_lock, flags);
- sclp_con_suspended = 0;
- spin_unlock_irqrestore(&sclp_con_lock, flags);
- sclp_conbuf_emit();
-}
-
-/*
- * Suspend console: Set suspend flag and flush console
- */
-static void sclp_console_suspend(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sclp_con_lock, flags);
- sclp_con_suspended = 1;
- spin_unlock_irqrestore(&sclp_con_lock, flags);
- sclp_console_flush();
-}
-
static int sclp_console_notify(struct notifier_block *self,
unsigned long event, void *data)
{
@@ -269,7 +239,7 @@ static int sclp_console_notify(struct notifier_block *self,
static struct notifier_block on_panic_nb = {
.notifier_call = sclp_console_notify,
- .priority = SCLP_PANIC_PRIO_CLIENT,
+ .priority = 1,
};
static struct notifier_block on_reboot_nb = {
@@ -291,22 +261,6 @@ static struct console sclp_console =
};
/*
- * This function is called for SCLP suspend and resume events.
- */
-void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event)
-{
- switch (sclp_pm_event) {
- case SCLP_PM_EVENT_FREEZE:
- sclp_console_suspend();
- break;
- case SCLP_PM_EVENT_RESTORE:
- case SCLP_PM_EVENT_THAW:
- sclp_console_resume();
- break;
- }
-}
-
-/*
* called by console_init() in drivers/char/tty_io.c at boot-time.
*/
static int __init
diff --git a/drivers/s390/char/sclp_ftp.c b/drivers/s390/char/sclp_ftp.c
index dfdd6c8fd17e..1e9de99dcd02 100644
--- a/drivers/s390/char/sclp_ftp.c
+++ b/drivers/s390/char/sclp_ftp.c
@@ -231,7 +231,6 @@ static struct sclp_register sclp_ftp_event = {
.receive_mask = EVTYP_DIAG_TEST_MASK, /* want rx events */
.receiver_fn = sclp_ftp_rxcb, /* async callback (rx) */
.state_change_fn = NULL,
- .pm_event_fn = NULL,
};
/**
diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c
index 76956c2131cd..ade721467804 100644
--- a/drivers/s390/char/sclp_quiesce.c
+++ b/drivers/s390/char/sclp_quiesce.c
@@ -18,10 +18,6 @@
#include "sclp.h"
-static void (*old_machine_restart)(char *);
-static void (*old_machine_halt)(void);
-static void (*old_machine_power_off)(void);
-
/* Shutdown handler. Signal completion of shutdown by loading special PSW. */
static void do_machine_quiesce(void)
{
@@ -37,42 +33,15 @@ static void do_machine_quiesce(void)
/* Handler for quiesce event. Start shutdown procedure. */
static void sclp_quiesce_handler(struct evbuf_header *evbuf)
{
- if (_machine_restart != (void *) do_machine_quiesce) {
- old_machine_restart = _machine_restart;
- old_machine_halt = _machine_halt;
- old_machine_power_off = _machine_power_off;
- _machine_restart = (void *) do_machine_quiesce;
- _machine_halt = do_machine_quiesce;
- _machine_power_off = do_machine_quiesce;
- }
+ _machine_restart = (void *) do_machine_quiesce;
+ _machine_halt = do_machine_quiesce;
+ _machine_power_off = do_machine_quiesce;
ctrl_alt_del();
}
-/* Undo machine restart/halt/power_off modification on resume */
-static void sclp_quiesce_pm_event(struct sclp_register *reg,
- enum sclp_pm_event sclp_pm_event)
-{
- switch (sclp_pm_event) {
- case SCLP_PM_EVENT_RESTORE:
- if (old_machine_restart) {
- _machine_restart = old_machine_restart;
- _machine_halt = old_machine_halt;
- _machine_power_off = old_machine_power_off;
- old_machine_restart = NULL;
- old_machine_halt = NULL;
- old_machine_power_off = NULL;
- }
- break;
- case SCLP_PM_EVENT_FREEZE:
- case SCLP_PM_EVENT_THAW:
- break;
- }
-}
-
static struct sclp_register sclp_quiesce_event = {
.receive_mask = EVTYP_SIGQUIESCE_MASK,
.receiver_fn = sclp_quiesce_handler,
- .pm_event_fn = sclp_quiesce_pm_event
};
/* Initialize quiesce driver. */
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index d6c84e354df5..1690326553b1 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -26,16 +26,9 @@
*/
#define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer))
-static void sclp_rw_pm_event(struct sclp_register *reg,
- enum sclp_pm_event sclp_pm_event)
-{
- sclp_console_pm_event(sclp_pm_event);
-}
-
/* Event type structure for write message and write priority message */
static struct sclp_register sclp_rw_event = {
.send_mask = EVTYP_MSG_MASK,
- .pm_event_fn = sclp_rw_pm_event,
};
/*
@@ -325,10 +318,10 @@ sclp_buffer_space(struct sclp_buffer *buffer)
/*
* Return number of characters in buffer
*/
-int
+unsigned int
sclp_chars_in_buffer(struct sclp_buffer *buffer)
{
- int count;
+ unsigned int count;
count = buffer->char_sum;
if (buffer->current_line != NULL)
diff --git a/drivers/s390/char/sclp_rw.h b/drivers/s390/char/sclp_rw.h
index 93d706e4935c..9b779ee4f979 100644
--- a/drivers/s390/char/sclp_rw.h
+++ b/drivers/s390/char/sclp_rw.h
@@ -86,12 +86,6 @@ void *sclp_unmake_buffer(struct sclp_buffer *);
int sclp_buffer_space(struct sclp_buffer *);
int sclp_write(struct sclp_buffer *buffer, const unsigned char *, int);
int sclp_emit_buffer(struct sclp_buffer *,void (*)(struct sclp_buffer *,int));
-int sclp_chars_in_buffer(struct sclp_buffer *);
-
-#ifdef CONFIG_SCLP_CONSOLE
-void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event);
-#else
-static inline void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event) { }
-#endif
+unsigned int sclp_chars_in_buffer(struct sclp_buffer *);
#endif /* __SCLP_RW_H__ */
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 4456ceb23bd2..6be9de8ed37d 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -86,12 +86,12 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp)
* a string of newlines. Every newline creates a new message which
* needs 82 bytes.
*/
-static int
+static unsigned int
sclp_tty_write_room (struct tty_struct *tty)
{
unsigned long flags;
struct list_head *l;
- int count;
+ unsigned int count;
spin_lock_irqsave(&sclp_tty_lock, flags);
count = 0;
@@ -280,20 +280,17 @@ sclp_tty_flush_chars(struct tty_struct *tty)
* characters in the write buffer (will not be written as long as there is a
* final line feed missing).
*/
-static int
+static unsigned int
sclp_tty_chars_in_buffer(struct tty_struct *tty)
{
unsigned long flags;
- struct list_head *l;
struct sclp_buffer *t;
- int count;
+ unsigned int count = 0;
spin_lock_irqsave(&sclp_tty_lock, flags);
- count = 0;
if (sclp_ttybuf != NULL)
count = sclp_chars_in_buffer(sclp_ttybuf);
- list_for_each(l, &sclp_tty_outqueue) {
- t = list_entry(l, struct sclp_buffer, list);
+ list_for_each_entry(t, &sclp_tty_outqueue, list) {
count += sclp_chars_in_buffer(t);
}
spin_unlock_irqrestore(&sclp_tty_lock, flags);
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 7f4445b0f819..da2496306c04 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/panic_notifier.h>
#include <linux/list.h>
#include <linux/wait.h>
#include <linux/timer.h>
@@ -35,8 +36,8 @@
#define SCLP_VT220_MINOR 65
#define SCLP_VT220_DRIVER_NAME "sclp_vt220"
#define SCLP_VT220_DEVICE_NAME "ttysclp"
-#define SCLP_VT220_CONSOLE_NAME "ttyS"
-#define SCLP_VT220_CONSOLE_INDEX 1 /* console=ttyS1 */
+#define SCLP_VT220_CONSOLE_NAME "ttysclp"
+#define SCLP_VT220_CONSOLE_INDEX 0 /* console=ttysclp0 */
/* Representation of a single write request */
struct sclp_vt220_request {
@@ -69,9 +70,6 @@ static LIST_HEAD(sclp_vt220_empty);
/* List of pending requests */
static LIST_HEAD(sclp_vt220_outqueue);
-/* Suspend mode flag */
-static int sclp_vt220_suspended;
-
/* Flag that output queue is currently running */
static int sclp_vt220_queue_running;
@@ -95,15 +93,12 @@ static int __initdata sclp_vt220_init_count;
static int sclp_vt220_flush_later;
static void sclp_vt220_receiver_fn(struct evbuf_header *evbuf);
-static void sclp_vt220_pm_event_fn(struct sclp_register *reg,
- enum sclp_pm_event sclp_pm_event);
static int __sclp_vt220_emit(struct sclp_vt220_request *request);
static void sclp_vt220_emit_current(void);
/* Registration structure for SCLP output event buffers */
static struct sclp_register sclp_vt220_register = {
.send_mask = EVTYP_VT220MSG_MASK,
- .pm_event_fn = sclp_vt220_pm_event_fn,
};
/* Registration structure for SCLP input event buffers */
@@ -135,7 +130,7 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
if (!list_empty(&sclp_vt220_outqueue))
request = list_entry(sclp_vt220_outqueue.next,
struct sclp_vt220_request, list);
- if (!request || sclp_vt220_suspended) {
+ if (!request) {
sclp_vt220_queue_running = 0;
spin_unlock_irqrestore(&sclp_vt220_lock, flags);
break;
@@ -241,7 +236,7 @@ sclp_vt220_emit_current(void)
}
sclp_vt220_flush_later = 0;
}
- if (sclp_vt220_queue_running || sclp_vt220_suspended)
+ if (sclp_vt220_queue_running)
goto out_unlock;
if (list_empty(&sclp_vt220_outqueue))
goto out_unlock;
@@ -420,7 +415,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule,
if (list_empty(&sclp_vt220_empty))
sclp_console_full++;
while (list_empty(&sclp_vt220_empty)) {
- if (may_fail || sclp_vt220_suspended)
+ if (may_fail)
goto out;
if (sclp_vt220_drop_buffer())
break;
@@ -609,12 +604,12 @@ sclp_vt220_flush_chars(struct tty_struct *tty)
* to change as output buffers get emptied, or if the output flow
* control is acted.
*/
-static int
+static unsigned int
sclp_vt220_write_room(struct tty_struct *tty)
{
unsigned long flags;
struct list_head *l;
- int count;
+ unsigned int count;
spin_lock_irqsave(&sclp_vt220_lock, flags);
count = 0;
@@ -629,16 +624,15 @@ sclp_vt220_write_room(struct tty_struct *tty)
/*
* Return number of buffered chars.
*/
-static int
+static unsigned int
sclp_vt220_chars_in_buffer(struct tty_struct *tty)
{
unsigned long flags;
struct list_head *l;
struct sclp_vt220_request *r;
- int count;
+ unsigned int count = 0;
spin_lock_irqsave(&sclp_vt220_lock, flags);
- count = 0;
if (sclp_vt220_current_request != NULL)
count = sclp_vt220_chars_stored(sclp_vt220_current_request);
list_for_each(l, &sclp_vt220_outqueue) {
@@ -791,46 +785,6 @@ static void __sclp_vt220_flush_buffer(void)
spin_unlock_irqrestore(&sclp_vt220_lock, flags);
}
-/*
- * Resume console: If there are cached messages, emit them.
- */
-static void sclp_vt220_resume(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sclp_vt220_lock, flags);
- sclp_vt220_suspended = 0;
- spin_unlock_irqrestore(&sclp_vt220_lock, flags);
- sclp_vt220_emit_current();
-}
-
-/*
- * Suspend console: Set suspend flag and flush console
- */
-static void sclp_vt220_suspend(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sclp_vt220_lock, flags);
- sclp_vt220_suspended = 1;
- spin_unlock_irqrestore(&sclp_vt220_lock, flags);
- __sclp_vt220_flush_buffer();
-}
-
-static void sclp_vt220_pm_event_fn(struct sclp_register *reg,
- enum sclp_pm_event sclp_pm_event)
-{
- switch (sclp_pm_event) {
- case SCLP_PM_EVENT_FREEZE:
- sclp_vt220_suspend();
- break;
- case SCLP_PM_EVENT_RESTORE:
- case SCLP_PM_EVENT_THAW:
- sclp_vt220_resume();
- break;
- }
-}
-
#ifdef CONFIG_SCLP_VT220_CONSOLE
static void
diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
index 8abb42923307..cc8237afeffa 100644
--- a/drivers/s390/char/tape_char.c
+++ b/drivers/s390/char/tape_char.c
@@ -371,8 +371,6 @@ __tapechar_ioctl(struct tape_device *device,
case MTSEEK:
if (device->required_tapemarks)
tape_std_terminate_write(device);
- default:
- ;
}
rc = tape_mtop(device, op.mt_op, op.mt_count);
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 307a80f85c07..adc33846bf8e 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -1071,7 +1071,7 @@ static void tty3270_cleanup(struct tty_struct *tty)
/*
* We always have room.
*/
-static int
+static unsigned int
tty3270_write_room(struct tty_struct *tty)
{
return INT_MAX;
@@ -1640,7 +1640,7 @@ tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty,
int i_msg, i;
spin_lock_bh(&tp->view.lock);
- for (i_msg = 0; !tty->stopped && i_msg < count; i_msg++) {
+ for (i_msg = 0; !tty->flow.stopped && i_msg < count; i_msg++) {
if (tp->esc_state != 0) {
/* Continue escape sequence. */
tty3270_escape_sequence(tp, buf[i_msg]);
@@ -1757,22 +1757,6 @@ tty3270_flush_chars(struct tty_struct *tty)
}
/*
- * Returns the number of characters in the output buffer. This is
- * used in tty_wait_until_sent to wait until all characters have
- * appeared on the screen.
- */
-static int
-tty3270_chars_in_buffer(struct tty_struct *tty)
-{
- return 0;
-}
-
-static void
-tty3270_flush_buffer(struct tty_struct *tty)
-{
-}
-
-/*
* Check for visible/invisible input switches
*/
static void
@@ -1892,8 +1876,6 @@ static const struct tty_operations tty3270_ops = {
.put_char = tty3270_put_char,
.flush_chars = tty3270_flush_chars,
.write_room = tty3270_write_room,
- .chars_in_buffer = tty3270_chars_in_buffer,
- .flush_buffer = tty3270_flush_buffer,
.throttle = tty3270_throttle,
.unthrottle = tty3270_unthrottle,
.hangup = tty3270_hangup,
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index 58333cb4503f..ed970ecfafdf 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -679,34 +679,10 @@ static const struct attribute_group *vmlogrdr_attr_groups[] = {
NULL,
};
-static int vmlogrdr_pm_prepare(struct device *dev)
-{
- int rc;
- struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);
-
- rc = 0;
- if (priv) {
- spin_lock_bh(&priv->priv_lock);
- if (priv->dev_in_use)
- rc = -EBUSY;
- spin_unlock_bh(&priv->priv_lock);
- }
- if (rc)
- pr_err("vmlogrdr: device %s is busy. Refuse to suspend.\n",
- dev_name(dev));
- return rc;
-}
-
-
-static const struct dev_pm_ops vmlogrdr_pm_ops = {
- .prepare = vmlogrdr_pm_prepare,
-};
-
static struct class *vmlogrdr_class;
static struct device_driver vmlogrdr_driver = {
.name = "vmlogrdr",
.bus = &iucv_bus,
- .pm = &vmlogrdr_pm_ops,
.groups = vmlogrdr_drv_attr_groups,
};
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index bd3c724bf695..b5b0848da93b 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/debugfs.h>
+#include <linux/panic_notifier.h>
#include <linux/reboot.h>
#include <asm/asm-offsets.h>
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
index cb466ed7eb5e..e56535c99888 100644
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -93,7 +93,7 @@ static irqreturn_t do_airq_interrupt(int irq, void *dummy)
struct hlist_head *head;
set_cpu_flag(CIF_NOHZ_DELAY);
- tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
+ tpi_info = &get_irq_regs()->tpi_info;
trace_s390_cio_adapter_int(tpi_info);
head = &airq_lists[tpi_info->isc];
rcu_read_lock();
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 444385da5792..9748165e08e9 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -45,27 +45,6 @@ static void __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
}
}
-/*
- * Remove references from ccw devices to ccw group device and from
- * ccw group device to ccw devices.
- */
-static void __ccwgroup_remove_cdev_refs(struct ccwgroup_device *gdev)
-{
- struct ccw_device *cdev;
- int i;
-
- for (i = 0; i < gdev->count; i++) {
- cdev = gdev->cdev[i];
- if (!cdev)
- continue;
- spin_lock_irq(cdev->ccwlock);
- dev_set_drvdata(&cdev->dev, NULL);
- spin_unlock_irq(cdev->ccwlock);
- gdev->cdev[i] = NULL;
- put_device(&cdev->dev);
- }
-}
-
/**
* ccwgroup_set_online() - enable a ccwgroup device
* @gdev: target ccwgroup device
@@ -175,7 +154,6 @@ static void ccwgroup_ungroup(struct ccwgroup_device *gdev)
if (device_is_registered(&gdev->dev)) {
__ccwgroup_remove_symlinks(gdev);
device_unregister(&gdev->dev);
- __ccwgroup_remove_cdev_refs(gdev);
}
mutex_unlock(&gdev->reg_mutex);
}
@@ -228,7 +206,23 @@ static void ccwgroup_ungroup_workfn(struct work_struct *work)
static void ccwgroup_release(struct device *dev)
{
- kfree(to_ccwgroupdev(dev));
+ struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
+ unsigned int i;
+
+ for (i = 0; i < gdev->count; i++) {
+ struct ccw_device *cdev = gdev->cdev[i];
+ unsigned long flags;
+
+ if (cdev) {
+ spin_lock_irqsave(cdev->ccwlock, flags);
+ if (dev_get_drvdata(&cdev->dev) == gdev)
+ dev_set_drvdata(&cdev->dev, NULL);
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+ put_device(&cdev->dev);
+ }
+ }
+
+ kfree(gdev);
}
static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
@@ -396,15 +390,6 @@ int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv,
mutex_unlock(&gdev->reg_mutex);
return 0;
error:
- for (i = 0; i < num_devices; i++)
- if (gdev->cdev[i]) {
- spin_lock_irq(gdev->cdev[i]->ccwlock);
- if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
- dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
- spin_unlock_irq(gdev->cdev[i]->ccwlock);
- put_device(&gdev->cdev[i]->dev);
- gdev->cdev[i] = NULL;
- }
mutex_unlock(&gdev->reg_mutex);
put_device(&gdev->dev);
return rc;
@@ -416,7 +401,7 @@ static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
{
struct ccwgroup_device *gdev = to_ccwgroupdev(data);
- if (action == BUS_NOTIFY_UNBIND_DRIVER) {
+ if (action == BUS_NOTIFY_UNBOUND_DRIVER) {
get_device(&gdev->dev);
schedule_work(&gdev->ungroup_work);
}
@@ -514,15 +499,6 @@ EXPORT_SYMBOL(ccwgroup_driver_register);
*/
void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
{
- struct device *dev;
-
- /* We don't want ccwgroup devices to live longer than their driver. */
- while ((dev = driver_find_next_device(&cdriver->driver, NULL))) {
- struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
-
- ccwgroup_ungroup(gdev);
- put_device(dev);
- }
driver_unregister(&cdriver->driver);
}
EXPORT_SYMBOL(ccwgroup_driver_unregister);
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index e42113825415..1097e76982a5 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -255,6 +255,9 @@ static ssize_t chp_status_write(struct device *dev,
if (!num_args)
return count;
+ /* Wait until previous actions have settled. */
+ css_wait_for_slow_path();
+
if (!strncasecmp(cmd, "on", 2) || !strcmp(cmd, "1")) {
mutex_lock(&cp->lock);
error = s390_vary_chpid(cp->chpid, 1);
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index c22d9ee27ba1..297fb399363c 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -801,8 +801,6 @@ int chsc_chp_vary(struct chp_id chpid, int on)
{
struct channel_path *chp = chpid_to_chp(chpid);
- /* Wait until previous actions have settled. */
- css_wait_for_slow_path();
/*
* Redo PathVerification on the devices the chpid connects to
*/
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 6d716db2a46a..923f5ca4f5e6 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -536,7 +536,7 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy)
struct irb *irb;
set_cpu_flag(CIF_NOHZ_DELAY);
- tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
+ tpi_info = &get_irq_regs()->tpi_info;
trace_s390_cio_interrupt(tpi_info);
irb = this_cpu_ptr(&cio_irb);
sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index dcdaba689b20..1cb9daf9c645 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -9,6 +9,7 @@
#include <asm/cio.h>
#include <asm/fcx.h>
#include <asm/schid.h>
+#include <asm/tpi.h>
#include "chsc.h"
/*
@@ -46,18 +47,6 @@ struct pmcw {
/* ... in an operand exception. */
} __attribute__ ((packed));
-/* I/O-Interruption Code as stored by TEST PENDING INTERRUPTION (TPI). */
-struct tpi_info {
- struct subchannel_id schid;
- u32 intparm;
- u32 adapter_IO:1;
- u32 directed_irq:1;
- u32 isc:3;
- u32 :27;
- u32 type:3;
- u32 :12;
-} __packed __aligned(4);
-
/* Target SCHIB configuration. */
struct schib_config {
u64 mba;
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index b7b590646d58..5584aa46c94e 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -163,13 +163,14 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count)
*/
static inline void cmf_activate(void *area, unsigned int onoff)
{
- register void * __gpr2 asm("2");
- register long __gpr1 asm("1");
-
- __gpr2 = area;
- __gpr1 = onoff;
/* activate channel measurement */
- asm("schm" : : "d" (__gpr2), "d" (__gpr1) );
+ asm volatile(
+ " lgr 1,%[r1]\n"
+ " lgr 2,%[mbo]\n"
+ " schm\n"
+ :
+ : [r1] "d" ((unsigned long)onoff), [mbo] "d" (area)
+ : "1", "2");
}
static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
diff --git a/drivers/s390/cio/ioasm.c b/drivers/s390/cio/ioasm.c
index 4c5244d6052b..180913007824 100644
--- a/drivers/s390/cio/ioasm.c
+++ b/drivers/s390/cio/ioasm.c
@@ -16,18 +16,19 @@
static inline int __stsch(struct subchannel_id schid, struct schib *addr)
{
- register struct subchannel_id reg1 asm ("1") = schid;
+ unsigned long r1 = *(unsigned int *)&schid;
int ccode = -EIO;
asm volatile(
- " stsch 0(%3)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
+ " lgr 1,%[r1]\n"
+ " stsch %[addr]\n"
+ "0: ipm %[cc]\n"
+ " srl %[cc],28\n"
"1:\n"
EX_TABLE(0b, 1b)
- : "+d" (ccode), "=m" (*addr)
- : "d" (reg1), "a" (addr)
- : "cc");
+ : [cc] "+&d" (ccode), [addr] "=Q" (*addr)
+ : [r1] "d" (r1)
+ : "cc", "1");
return ccode;
}
@@ -44,18 +45,19 @@ EXPORT_SYMBOL(stsch);
static inline int __msch(struct subchannel_id schid, struct schib *addr)
{
- register struct subchannel_id reg1 asm ("1") = schid;
+ unsigned long r1 = *(unsigned int *)&schid;
int ccode = -EIO;
asm volatile(
- " msch 0(%2)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
+ " lgr 1,%[r1]\n"
+ " msch %[addr]\n"
+ "0: ipm %[cc]\n"
+ " srl %[cc],28\n"
"1:\n"
EX_TABLE(0b, 1b)
- : "+d" (ccode)
- : "d" (reg1), "a" (addr), "m" (*addr)
- : "cc");
+ : [cc] "+&d" (ccode)
+ : [r1] "d" (r1), [addr] "Q" (*addr)
+ : "cc", "1");
return ccode;
}
@@ -71,16 +73,17 @@ int msch(struct subchannel_id schid, struct schib *addr)
static inline int __tsch(struct subchannel_id schid, struct irb *addr)
{
- register struct subchannel_id reg1 asm ("1") = schid;
+ unsigned long r1 = *(unsigned int *)&schid;
int ccode;
asm volatile(
- " tsch 0(%3)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode), "=m" (*addr)
- : "d" (reg1), "a" (addr)
- : "cc");
+ " lgr 1,%[r1]\n"
+ " tsch %[addr]\n"
+ " ipm %[cc]\n"
+ " srl %[cc],28"
+ : [cc] "=&d" (ccode), [addr] "=Q" (*addr)
+ : [r1] "d" (r1)
+ : "cc", "1");
return ccode;
}
@@ -96,18 +99,19 @@ int tsch(struct subchannel_id schid, struct irb *addr)
static inline int __ssch(struct subchannel_id schid, union orb *addr)
{
- register struct subchannel_id reg1 asm("1") = schid;
+ unsigned long r1 = *(unsigned int *)&schid;
int ccode = -EIO;
asm volatile(
- " ssch 0(%2)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
+ " lgr 1,%[r1]\n"
+ " ssch %[addr]\n"
+ "0: ipm %[cc]\n"
+ " srl %[cc],28\n"
"1:\n"
EX_TABLE(0b, 1b)
- : "+d" (ccode)
- : "d" (reg1), "a" (addr), "m" (*addr)
- : "cc", "memory");
+ : [cc] "+&d" (ccode)
+ : [r1] "d" (r1), [addr] "Q" (*addr)
+ : "cc", "memory", "1");
return ccode;
}
@@ -124,16 +128,17 @@ EXPORT_SYMBOL(ssch);
static inline int __csch(struct subchannel_id schid)
{
- register struct subchannel_id reg1 asm("1") = schid;
+ unsigned long r1 = *(unsigned int *)&schid;
int ccode;
asm volatile(
+ " lgr 1,%[r1]\n"
" csch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc");
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "=&d" (ccode)
+ : [r1] "d" (r1)
+ : "cc", "1");
return ccode;
}
@@ -153,11 +158,11 @@ int tpi(struct tpi_info *addr)
int ccode;
asm volatile(
- " tpi 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode), "=m" (*addr)
- : "a" (addr)
+ " tpi %[addr]\n"
+ " ipm %[cc]\n"
+ " srl %[cc],28"
+ : [cc] "=&d" (ccode), [addr] "=Q" (*addr)
+ :
: "cc");
trace_s390_cio_tpi(addr, ccode);
@@ -170,13 +175,13 @@ int chsc(void *chsc_area)
int cc = -EIO;
asm volatile(
- " .insn rre,0xb25f0000,%2,0\n"
- "0: ipm %0\n"
- " srl %0,28\n"
+ " .insn rre,0xb25f0000,%[chsc_area],0\n"
+ "0: ipm %[cc]\n"
+ " srl %[cc],28\n"
"1:\n"
EX_TABLE(0b, 1b)
- : "+d" (cc), "=m" (*(addr_type *) chsc_area)
- : "d" (chsc_area), "m" (*(addr_type *) chsc_area)
+ : [cc] "+&d" (cc), "+m" (*(addr_type *)chsc_area)
+ : [chsc_area] "d" (chsc_area)
: "cc");
trace_s390_cio_chsc(chsc_area, cc);
@@ -186,17 +191,17 @@ EXPORT_SYMBOL(chsc);
static inline int __rsch(struct subchannel_id schid)
{
- register struct subchannel_id reg1 asm("1") = schid;
+ unsigned long r1 = *(unsigned int *)&schid;
int ccode;
asm volatile(
+ " lgr 1,%[r1]\n"
" rsch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc", "memory");
-
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "=&d" (ccode)
+ : [r1] "d" (r1)
+ : "cc", "memory", "1");
return ccode;
}
@@ -212,16 +217,17 @@ int rsch(struct subchannel_id schid)
static inline int __hsch(struct subchannel_id schid)
{
- register struct subchannel_id reg1 asm("1") = schid;
+ unsigned long r1 = *(unsigned int *)&schid;
int ccode;
asm volatile(
+ " lgr 1,%[r1]\n"
" hsch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc");
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "=&d" (ccode)
+ : [r1] "d" (r1)
+ : "cc", "1");
return ccode;
}
@@ -238,16 +244,17 @@ EXPORT_SYMBOL(hsch);
static inline int __xsch(struct subchannel_id schid)
{
- register struct subchannel_id reg1 asm("1") = schid;
+ unsigned long r1 = *(unsigned int *)&schid;
int ccode;
asm volatile(
+ " lgr 1,%[r1]\n"
" xsch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc");
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "=&d" (ccode)
+ : [r1] "d" (r1)
+ : "cc", "1");
return ccode;
}
@@ -266,11 +273,11 @@ static inline int __stcrw(struct crw *crw)
int ccode;
asm volatile(
- " stcrw 0(%2)\n"
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (ccode), "=m" (*crw)
- : "a" (crw)
+ " stcrw %[crw]\n"
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "=&d" (ccode), [crw] "=Q" (*crw)
+ :
: "cc");
return ccode;
}
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 0e0044d70844..f69ffbb8edc9 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -88,15 +88,15 @@ enum qdio_irq_states {
static inline int do_sqbs(u64 token, unsigned char state, int queue,
int *start, int *count)
{
- register unsigned long _ccq asm ("0") = *count;
- register unsigned long _token asm ("1") = token;
unsigned long _queuestart = ((unsigned long)queue << 32) | *start;
+ unsigned long _ccq = *count;
asm volatile(
- " .insn rsy,0xeb000000008A,%1,0,0(%2)"
- : "+d" (_ccq), "+d" (_queuestart)
- : "d" ((unsigned long)state), "d" (_token)
- : "memory", "cc");
+ " lgr 1,%[token]\n"
+ " .insn rsy,0xeb000000008a,%[qs],%[ccq],0(%[state])"
+ : [ccq] "+&d" (_ccq), [qs] "+&d" (_queuestart)
+ : [state] "d" ((unsigned long)state), [token] "d" (token)
+ : "memory", "cc", "1");
*count = _ccq & 0xff;
*start = _queuestart & 0xff;
@@ -106,16 +106,17 @@ static inline int do_sqbs(u64 token, unsigned char state, int queue,
static inline int do_eqbs(u64 token, unsigned char *state, int queue,
int *start, int *count, int ack)
{
- register unsigned long _ccq asm ("0") = *count;
- register unsigned long _token asm ("1") = token;
unsigned long _queuestart = ((unsigned long)queue << 32) | *start;
unsigned long _state = (unsigned long)ack << 63;
+ unsigned long _ccq = *count;
asm volatile(
- " .insn rrf,0xB99c0000,%1,%2,0,0"
- : "+d" (_ccq), "+d" (_queuestart), "+d" (_state)
- : "d" (_token)
- : "memory", "cc");
+ " lgr 1,%[token]\n"
+ " .insn rrf,0xb99c0000,%[qs],%[state],%[ccq],0"
+ : [ccq] "+&d" (_ccq), [qs] "+&d" (_queuestart),
+ [state] "+&d" (_state)
+ : [token] "d" (token)
+ : "memory", "cc", "1");
*count = _ccq & 0xff;
*start = _queuestart & 0xff;
*state = _state & 0xff;
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 307ce7ff5ca4..3052fab00597 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -31,38 +31,41 @@ MODULE_DESCRIPTION("QDIO base support");
MODULE_LICENSE("GPL");
static inline int do_siga_sync(unsigned long schid,
- unsigned int out_mask, unsigned int in_mask,
+ unsigned long out_mask, unsigned long in_mask,
unsigned int fc)
{
- register unsigned long __fc asm ("0") = fc;
- register unsigned long __schid asm ("1") = schid;
- register unsigned long out asm ("2") = out_mask;
- register unsigned long in asm ("3") = in_mask;
int cc;
asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[schid]\n"
+ " lgr 2,%[out]\n"
+ " lgr 3,%[in]\n"
" siga 0\n"
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (cc)
- : "d" (__fc), "d" (__schid), "d" (out), "d" (in) : "cc");
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "=&d" (cc)
+ : [fc] "d" (fc), [schid] "d" (schid),
+ [out] "d" (out_mask), [in] "d" (in_mask)
+ : "cc", "0", "1", "2", "3");
return cc;
}
-static inline int do_siga_input(unsigned long schid, unsigned int mask,
- unsigned int fc)
+static inline int do_siga_input(unsigned long schid, unsigned long mask,
+ unsigned long fc)
{
- register unsigned long __fc asm ("0") = fc;
- register unsigned long __schid asm ("1") = schid;
- register unsigned long __mask asm ("2") = mask;
int cc;
asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[schid]\n"
+ " lgr 2,%[mask]\n"
" siga 0\n"
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (cc)
- : "d" (__fc), "d" (__schid), "d" (__mask) : "cc");
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "=&d" (cc)
+ : [fc] "d" (fc), [schid] "d" (schid), [mask] "d" (mask)
+ : "cc", "0", "1", "2");
return cc;
}
@@ -78,23 +81,24 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask,
* Note: For IQDC unicast queues only the highest priority queue is processed.
*/
static inline int do_siga_output(unsigned long schid, unsigned long mask,
- unsigned int *bb, unsigned int fc,
+ unsigned int *bb, unsigned long fc,
unsigned long aob)
{
- register unsigned long __fc asm("0") = fc;
- register unsigned long __schid asm("1") = schid;
- register unsigned long __mask asm("2") = mask;
- register unsigned long __aob asm("3") = aob;
int cc;
asm volatile(
+ " lgr 0,%[fc]\n"
+ " lgr 1,%[schid]\n"
+ " lgr 2,%[mask]\n"
+ " lgr 3,%[aob]\n"
" siga 0\n"
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (cc), "+d" (__fc), "+d" (__aob)
- : "d" (__schid), "d" (__mask)
- : "cc");
- *bb = __fc >> 31;
+ " lgr %[fc],0\n"
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "=&d" (cc), [fc] "+&d" (fc)
+ : [schid] "d" (schid), [mask] "d" (mask), [aob] "d" (aob)
+ : "cc", "0", "1", "2", "3");
+ *bb = fc >> 31;
return cc;
}
diff --git a/drivers/s390/cio/trace.h b/drivers/s390/cio/trace.h
index 4803139bce14..86993de25345 100644
--- a/drivers/s390/cio/trace.h
+++ b/drivers/s390/cio/trace.h
@@ -168,10 +168,8 @@ TRACE_EVENT(s390_cio_tpi,
memset(&__entry->tpi_info, 0, sizeof(struct tpi_info));
else if (addr)
__entry->tpi_info = *addr;
- else {
- memcpy(&__entry->tpi_info, &S390_lowcore.subchannel_id,
- sizeof(struct tpi_info));
- }
+ else
+ __entry->tpi_info = S390_lowcore.tpi_info;
__entry->cssid = __entry->tpi_info.schid.cssid;
__entry->ssid = __entry->tpi_info.schid.ssid;
__entry->schno = __entry->tpi_info.schid.sch_no;
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 2758d05a802d..8d3a1d84a757 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright IBM Corp. 2006, 2020
+ * Copyright IBM Corp. 2006, 2021
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
* Ralph Wuerthner <rwuerthn@de.ibm.com>
@@ -61,6 +61,9 @@ static char *aqm_str;
module_param_named(aqmask, aqm_str, charp, 0440);
MODULE_PARM_DESC(aqmask, "AP bus domain mask.");
+atomic_t ap_max_msg_size = ATOMIC_INIT(AP_DEFAULT_MAX_MSG_SIZE);
+EXPORT_SYMBOL(ap_max_msg_size);
+
static struct device *ap_root_device;
/* Hashtable of all queue devices on the AP bus */
@@ -77,6 +80,9 @@ EXPORT_SYMBOL(ap_perms_mutex);
/* # of bus scans since init */
static atomic64_t ap_scan_bus_count;
+/* # of bindings complete since init */
+static atomic64_t ap_bindings_complete_count = ATOMIC64_INIT(0);
+
/* completion for initial APQN bindings complete */
static DECLARE_COMPLETION(ap_init_apqn_bindings_complete);
@@ -313,11 +319,24 @@ EXPORT_SYMBOL(ap_test_config_ctrl_domain);
* Returns true if TAPQ succeeded and the info is filled or
* false otherwise.
*/
-static bool ap_queue_info(ap_qid_t qid, int *q_type,
- unsigned int *q_fac, int *q_depth, bool *q_decfg)
+static bool ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac,
+ int *q_depth, int *q_ml, bool *q_decfg)
{
struct ap_queue_status status;
- unsigned long info = 0;
+ union {
+ unsigned long value;
+ struct {
+ unsigned int fac : 32; /* facility bits */
+ unsigned int at : 8; /* ap type */
+ unsigned int _res1 : 8;
+ unsigned int _res2 : 4;
+ unsigned int ml : 4; /* apxl ml */
+ unsigned int _res3 : 4;
+ unsigned int qd : 4; /* queue depth */
+ } tapq_gr2;
+ } tapq_info;
+
+ tapq_info.value = 0;
/* make sure we don't run into a specifiation exception */
if (AP_QID_CARD(qid) > ap_max_adapter_id ||
@@ -325,7 +344,7 @@ static bool ap_queue_info(ap_qid_t qid, int *q_type,
return false;
/* call TAPQ on this APQN */
- status = ap_test_queue(qid, ap_apft_available(), &info);
+ status = ap_test_queue(qid, ap_apft_available(), &tapq_info.value);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
case AP_RESPONSE_RESET_IN_PROGRESS:
@@ -337,11 +356,12 @@ static bool ap_queue_info(ap_qid_t qid, int *q_type,
* info should be filled. All bits 0 is not possible as
* there is at least one of the mode bits set.
*/
- if (WARN_ON_ONCE(!info))
+ if (WARN_ON_ONCE(!tapq_info.value))
return false;
- *q_type = (int)((info >> 24) & 0xff);
- *q_fac = (unsigned int)(info >> 32);
- *q_depth = (int)(info & 0xff);
+ *q_type = tapq_info.tapq_gr2.at;
+ *q_fac = tapq_info.tapq_gr2.fac;
+ *q_depth = tapq_info.tapq_gr2.qd;
+ *q_ml = tapq_info.tapq_gr2.ml;
*q_decfg = status.response_code == AP_RESPONSE_DECONFIGURED;
switch (*q_type) {
/* For CEX2 and CEX3 the available functions
@@ -584,22 +604,47 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv)
*/
static int ap_uevent(struct device *dev, struct kobj_uevent_env *env)
{
- int rc;
+ int rc = 0;
struct ap_device *ap_dev = to_ap_dev(dev);
/* Uevents from ap bus core don't need extensions to the env */
if (dev == ap_root_device)
return 0;
- /* Set up DEV_TYPE environment variable. */
- rc = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);
- if (rc)
- return rc;
+ if (is_card_dev(dev)) {
+ struct ap_card *ac = to_ap_card(&ap_dev->device);
- /* Add MODALIAS= */
- rc = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);
- if (rc)
- return rc;
+ /* Set up DEV_TYPE environment variable. */
+ rc = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);
+ if (rc)
+ return rc;
+ /* Add MODALIAS= */
+ rc = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);
+ if (rc)
+ return rc;
+
+ /* Add MODE=<accel|cca|ep11> */
+ if (ap_test_bit(&ac->functions, AP_FUNC_ACCEL))
+ rc = add_uevent_var(env, "MODE=accel");
+ else if (ap_test_bit(&ac->functions, AP_FUNC_COPRO))
+ rc = add_uevent_var(env, "MODE=cca");
+ else if (ap_test_bit(&ac->functions, AP_FUNC_EP11))
+ rc = add_uevent_var(env, "MODE=ep11");
+ if (rc)
+ return rc;
+ } else {
+ struct ap_queue *aq = to_ap_queue(&ap_dev->device);
+
+ /* Add MODE=<accel|cca|ep11> */
+ if (ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL))
+ rc = add_uevent_var(env, "MODE=accel");
+ else if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO))
+ rc = add_uevent_var(env, "MODE=cca");
+ else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11))
+ rc = add_uevent_var(env, "MODE=ep11");
+ if (rc)
+ return rc;
+ }
return 0;
}
@@ -613,11 +658,36 @@ static void ap_send_init_scan_done_uevent(void)
static void ap_send_bindings_complete_uevent(void)
{
- char *envp[] = { "BINDINGS=complete", NULL };
+ char buf[32];
+ char *envp[] = { "BINDINGS=complete", buf, NULL };
+ snprintf(buf, sizeof(buf), "COMPLETECOUNT=%llu",
+ atomic64_inc_return(&ap_bindings_complete_count));
kobject_uevent_env(&ap_root_device->kobj, KOBJ_CHANGE, envp);
}
+void ap_send_config_uevent(struct ap_device *ap_dev, bool cfg)
+{
+ char buf[16];
+ char *envp[] = { buf, NULL };
+
+ snprintf(buf, sizeof(buf), "CONFIG=%d", cfg ? 1 : 0);
+
+ kobject_uevent_env(&ap_dev->device.kobj, KOBJ_CHANGE, envp);
+}
+EXPORT_SYMBOL(ap_send_config_uevent);
+
+void ap_send_online_uevent(struct ap_device *ap_dev, int online)
+{
+ char buf[16];
+ char *envp[] = { buf, NULL };
+
+ snprintf(buf, sizeof(buf), "ONLINE=%d", online ? 1 : 0);
+
+ kobject_uevent_env(&ap_dev->device.kobj, KOBJ_CHANGE, envp);
+}
+EXPORT_SYMBOL(ap_send_online_uevent);
+
/*
* calc # of bound APQNs
*/
@@ -885,8 +955,6 @@ int ap_driver_register(struct ap_driver *ap_drv, struct module *owner,
struct device_driver *drv = &ap_drv->driver;
drv->bus = &ap_bus_type;
- drv->probe = ap_device_probe;
- drv->remove = ap_device_remove;
drv->owner = owner;
drv->name = name;
return driver_register(drv);
@@ -1319,6 +1387,8 @@ static struct bus_type ap_bus_type = {
.bus_groups = ap_bus_groups,
.match = &ap_bus_match,
.uevent = &ap_uevent,
+ .probe = ap_device_probe,
+ .remove = ap_device_remove,
};
/**
@@ -1463,7 +1533,7 @@ static inline void ap_scan_domains(struct ap_card *ac)
unsigned int func;
struct device *dev;
struct ap_queue *aq;
- int rc, dom, depth, type;
+ int rc, dom, depth, type, ml;
/*
* Go through the configuration for the domains and compare them
@@ -1487,7 +1557,7 @@ static inline void ap_scan_domains(struct ap_card *ac)
continue;
}
/* domain is valid, get info from this APQN */
- if (!ap_queue_info(qid, &type, &func, &depth, &decfg)) {
+ if (!ap_queue_info(qid, &type, &func, &depth, &ml, &decfg)) {
if (aq) {
AP_DBF_INFO(
"%s(%d,%d) ap_queue_info() not successful, rm queue device\n",
@@ -1540,6 +1610,7 @@ static inline void ap_scan_domains(struct ap_card *ac)
spin_unlock_bh(&aq->lock);
AP_DBF_INFO("%s(%d,%d) queue device config off\n",
__func__, ac->id, dom);
+ ap_send_config_uevent(&aq->ap_dev, aq->config);
/* 'receive' pending messages with -EAGAIN */
ap_flush_queue(aq);
goto put_dev_and_continue;
@@ -1554,6 +1625,7 @@ static inline void ap_scan_domains(struct ap_card *ac)
spin_unlock_bh(&aq->lock);
AP_DBF_INFO("%s(%d,%d) queue device config on\n",
__func__, ac->id, dom);
+ ap_send_config_uevent(&aq->ap_dev, aq->config);
goto put_dev_and_continue;
}
/* handle other error states */
@@ -1584,7 +1656,7 @@ static inline void ap_scan_adapter(int ap)
unsigned int func;
struct device *dev;
struct ap_card *ac;
- int rc, dom, depth, type, comp_type;
+ int rc, dom, depth, type, comp_type, ml;
/* Is there currently a card device for this adapter ? */
dev = bus_find_device(&ap_bus_type, NULL,
@@ -1613,7 +1685,8 @@ static inline void ap_scan_adapter(int ap)
for (dom = 0; dom <= ap_max_domain_id; dom++)
if (ap_test_config_usage_domain(dom)) {
qid = AP_MKQID(ap, dom);
- if (ap_queue_info(qid, &type, &func, &depth, &decfg))
+ if (ap_queue_info(qid, &type, &func,
+ &depth, &ml, &decfg))
break;
}
if (dom > ap_max_domain_id) {
@@ -1663,12 +1736,13 @@ static inline void ap_scan_adapter(int ap)
ac->config = false;
AP_DBF_INFO("%s(%d) card device config off\n",
__func__, ap);
-
+ ap_send_config_uevent(&ac->ap_dev, ac->config);
}
if (!decfg && !ac->config) {
ac->config = true;
AP_DBF_INFO("%s(%d) card device config on\n",
__func__, ap);
+ ap_send_config_uevent(&ac->ap_dev, ac->config);
}
}
}
@@ -1681,7 +1755,7 @@ static inline void ap_scan_adapter(int ap)
__func__, ap, type);
return;
}
- ac = ap_card_create(ap, depth, type, comp_type, func);
+ ac = ap_card_create(ap, depth, type, comp_type, func, ml);
if (!ac) {
AP_DBF_WARN("%s(%d) ap_card_create() failed\n",
__func__, ap);
@@ -1692,6 +1766,12 @@ static inline void ap_scan_adapter(int ap)
dev->bus = &ap_bus_type;
dev->parent = ap_root_device;
dev_set_name(dev, "card%02x", ap);
+ /* maybe enlarge ap_max_msg_size to support this card */
+ if (ac->maxmsgsize > atomic_read(&ap_max_msg_size)) {
+ atomic_set(&ap_max_msg_size, ac->maxmsgsize);
+ AP_DBF_INFO("%s(%d) ap_max_msg_size update to %d byte\n",
+ __func__, ap, atomic_read(&ap_max_msg_size));
+ }
/* Register the new card device with AP bus */
rc = device_register(dev);
if (rc) {
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 472efd3a755c..8f18abdbbc2b 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -25,8 +25,11 @@
#define AP_RESET_TIMEOUT (HZ*0.7) /* Time in ticks for reset timeouts. */
#define AP_CONFIG_TIME 30 /* Time in seconds between AP bus rescans. */
#define AP_POLL_TIME 1 /* Time in ticks between receive polls. */
+#define AP_DEFAULT_MAX_MSG_SIZE (12 * 1024)
+#define AP_TAPQ_ML_FIELD_CHUNK_SIZE (4096)
extern int ap_domain_index;
+extern atomic_t ap_max_msg_size;
extern DECLARE_HASHTABLE(ap_queues, 8);
extern spinlock_t ap_queues_lock;
@@ -167,6 +170,7 @@ struct ap_card {
unsigned int functions; /* AP device function bitfield. */
int queue_depth; /* AP queue depth.*/
int id; /* AP card number. */
+ unsigned int maxmsgsize; /* AP msg limit for this card */
bool config; /* configured state */
atomic64_t total_request_count; /* # requests ever for this AP device.*/
};
@@ -228,7 +232,8 @@ struct ap_message {
struct list_head list; /* Request queueing. */
unsigned long long psmid; /* Message id. */
void *msg; /* Pointer to message buffer. */
- unsigned int len; /* Message length. */
+ unsigned int len; /* actual msg len in msg buffer */
+ unsigned int bufsize; /* allocated msg buffer size */
u16 flags; /* Flags, see AP_MSG_FLAG_xxx */
struct ap_fi fi; /* Failure Injection cmd */
int rc; /* Return code for this message */
@@ -290,8 +295,8 @@ void ap_queue_prepare_remove(struct ap_queue *aq);
void ap_queue_remove(struct ap_queue *aq);
void ap_queue_init_state(struct ap_queue *aq);
-struct ap_card *ap_card_create(int id, int queue_depth, int raw_device_type,
- int comp_device_type, unsigned int functions);
+struct ap_card *ap_card_create(int id, int queue_depth, int raw_type,
+ int comp_type, unsigned int functions, int ml);
struct ap_perms {
unsigned long ioctlm[BITS_TO_LONGS(AP_IOCTLS)];
@@ -362,4 +367,7 @@ int ap_parse_mask_str(const char *str,
*/
int ap_wait_init_apqn_bindings_complete(unsigned long timeout);
+void ap_send_config_uevent(struct ap_device *ap_dev, bool cfg);
+void ap_send_online_uevent(struct ap_device *ap_dev, int online);
+
#endif /* _AP_BUS_H_ */
diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c
index d98bdd28d23e..196325a66662 100644
--- a/drivers/s390/crypto/ap_card.c
+++ b/drivers/s390/crypto/ap_card.c
@@ -167,11 +167,23 @@ static ssize_t config_store(struct device *dev,
ac->config = cfg ? true : false;
+ ap_send_config_uevent(&ac->ap_dev, ac->config);
+
return count;
}
static DEVICE_ATTR_RW(config);
+static ssize_t max_msg_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ap_card *ac = to_ap_card(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", ac->maxmsgsize);
+}
+
+static DEVICE_ATTR_RO(max_msg_size);
+
static struct attribute *ap_card_dev_attrs[] = {
&dev_attr_hwtype.attr,
&dev_attr_raw_hwtype.attr,
@@ -182,6 +194,7 @@ static struct attribute *ap_card_dev_attrs[] = {
&dev_attr_pendingq_count.attr,
&dev_attr_modalias.attr,
&dev_attr_config.attr,
+ &dev_attr_max_msg_size.attr,
NULL
};
@@ -207,7 +220,7 @@ static void ap_card_device_release(struct device *dev)
}
struct ap_card *ap_card_create(int id, int queue_depth, int raw_type,
- int comp_type, unsigned int functions)
+ int comp_type, unsigned int functions, int ml)
{
struct ap_card *ac;
@@ -221,5 +234,8 @@ struct ap_card *ap_card_create(int id, int queue_depth, int raw_type,
ac->queue_depth = queue_depth;
ac->functions = functions;
ac->id = id;
+ ac->maxmsgsize = ml > 0 ?
+ ml * AP_TAPQ_ML_FIELD_CHUNK_SIZE : AP_DEFAULT_MAX_MSG_SIZE;
+
return ac;
}
diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c
index 337353c9655e..669f96fddad6 100644
--- a/drivers/s390/crypto/ap_queue.c
+++ b/drivers/s390/crypto/ap_queue.c
@@ -101,7 +101,7 @@ int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
if (msg == NULL)
return -EINVAL;
- status = ap_dqap(qid, psmid, msg, length);
+ status = ap_dqap(qid, psmid, msg, length, NULL, NULL);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
return 0;
@@ -136,9 +136,24 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq)
struct ap_queue_status status;
struct ap_message *ap_msg;
bool found = false;
+ size_t reslen;
+ unsigned long resgr0 = 0;
+ int parts = 0;
+
+ /*
+ * DQAP loop until response code and resgr0 indicate that
+ * the msg is totally received. As we use the very same buffer
+ * the msg is overwritten with each invocation. That's intended
+ * and the receiver of the msg is informed with a msg rc code
+ * of EMSGSIZE in such a case.
+ */
+ do {
+ status = ap_dqap(aq->qid, &aq->reply->psmid,
+ aq->reply->msg, aq->reply->bufsize,
+ &reslen, &resgr0);
+ parts++;
+ } while (status.response_code == 0xFF && resgr0 != 0);
- status = ap_dqap(aq->qid, &aq->reply->psmid,
- aq->reply->msg, aq->reply->len);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
aq->queue_count = max_t(int, 0, aq->queue_count - 1);
@@ -150,7 +165,12 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq)
continue;
list_del_init(&ap_msg->list);
aq->pendingq_count--;
- ap_msg->receive(aq, ap_msg, aq->reply);
+ if (parts > 1) {
+ ap_msg->rc = -EMSGSIZE;
+ ap_msg->receive(aq, ap_msg, NULL);
+ } else {
+ ap_msg->receive(aq, ap_msg, aq->reply);
+ }
found = true;
break;
}
diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c
index 7dc72cb718b0..4d2556bc7fe5 100644
--- a/drivers/s390/crypto/vfio_ap_drv.c
+++ b/drivers/s390/crypto/vfio_ap_drv.c
@@ -22,8 +22,6 @@ MODULE_AUTHOR("IBM Corporation");
MODULE_DESCRIPTION("VFIO AP device driver, Copyright IBM Corp. 2018");
MODULE_LICENSE("GPL v2");
-static struct ap_driver vfio_ap_drv;
-
struct ap_matrix_dev *matrix_dev;
/* Only type 10 adapters (CEX4 and later) are supported
@@ -80,6 +78,12 @@ static void vfio_ap_queue_dev_remove(struct ap_device *apdev)
mutex_unlock(&matrix_dev->lock);
}
+static struct ap_driver vfio_ap_drv = {
+ .probe = vfio_ap_queue_dev_probe,
+ .remove = vfio_ap_queue_dev_remove,
+ .ids = ap_queue_ids,
+};
+
static void vfio_ap_matrix_dev_release(struct device *dev)
{
struct ap_matrix_dev *matrix_dev = dev_get_drvdata(dev);
@@ -181,11 +185,6 @@ static int __init vfio_ap_init(void)
if (ret)
return ret;
- memset(&vfio_ap_drv, 0, sizeof(vfio_ap_drv));
- vfio_ap_drv.probe = vfio_ap_queue_dev_probe;
- vfio_ap_drv.remove = vfio_ap_queue_dev_remove;
- vfio_ap_drv.ids = ap_queue_ids;
-
ret = ap_driver_register(&vfio_ap_drv, THIS_MODULE, VFIO_AP_DRV_NAME);
if (ret) {
vfio_ap_matrix_dev_destroy();
diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
index b2c7e10dfdcd..122c85c22469 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -366,16 +366,6 @@ static int vfio_ap_mdev_remove(struct mdev_device *mdev)
struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
mutex_lock(&matrix_dev->lock);
-
- /*
- * If the KVM pointer is in flux or the guest is running, disallow
- * un-assignment of control domain.
- */
- if (matrix_mdev->kvm_busy || matrix_mdev->kvm) {
- mutex_unlock(&matrix_dev->lock);
- return -EBUSY;
- }
-
vfio_ap_mdev_reset_queues(mdev);
list_del(&matrix_mdev->node);
kfree(matrix_mdev);
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 52eaf51c9bb6..529ffe26ea9d 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -59,7 +59,6 @@ MODULE_PARM_DESC(hwrng_seed, "Turn on/off hwrng auto seed, default is 1 (on).");
DEFINE_SPINLOCK(zcrypt_list_lock);
LIST_HEAD(zcrypt_card_list);
-int zcrypt_device_count;
static atomic_t zcrypt_open_count = ATOMIC_INIT(0);
static atomic_t zcrypt_rescan_count = ATOMIC_INIT(0);
@@ -901,6 +900,9 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
if (xcRB->user_defined != AUTOSELECT &&
xcRB->user_defined != zc->card->id)
continue;
+ /* check if request size exceeds card max msg size */
+ if (ap_msg.len > zc->card->maxmsgsize)
+ continue;
/* check if device node has admission for this card */
if (!zcrypt_check_card(perms, zc->card->id))
continue;
@@ -1069,6 +1071,9 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
if (targets &&
!is_desired_ep11_card(zc->card->id, target_num, targets))
continue;
+ /* check if request size exceeds card max msg size */
+ if (ap_msg.len > zc->card->maxmsgsize)
+ continue;
/* check if device node has admission for this card */
if (!zcrypt_check_card(perms, zc->card->id))
continue;
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h
index 16219efb2f61..93e77e83ad14 100644
--- a/drivers/s390/crypto/zcrypt_api.h
+++ b/drivers/s390/crypto/zcrypt_api.h
@@ -124,7 +124,6 @@ struct zcrypt_queue {
extern atomic_t zcrypt_rescan_req;
extern spinlock_t zcrypt_list_lock;
-extern int zcrypt_device_count;
extern struct list_head zcrypt_card_list;
#define for_each_zcrypt_card(_zc) \
@@ -146,7 +145,7 @@ void zcrypt_queue_get(struct zcrypt_queue *);
int zcrypt_queue_put(struct zcrypt_queue *);
int zcrypt_queue_register(struct zcrypt_queue *);
void zcrypt_queue_unregister(struct zcrypt_queue *);
-void zcrypt_queue_force_online(struct zcrypt_queue *, int);
+bool zcrypt_queue_force_online(struct zcrypt_queue *zq, int online);
int zcrypt_rng_device_add(void);
void zcrypt_rng_device_remove(void);
diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c
index 09fe6bb8880b..40fd5d37d26a 100644
--- a/drivers/s390/crypto/zcrypt_card.c
+++ b/drivers/s390/crypto/zcrypt_card.c
@@ -64,7 +64,8 @@ static ssize_t online_store(struct device *dev,
struct ap_card *ac = to_ap_card(dev);
struct zcrypt_card *zc = ac->private;
struct zcrypt_queue *zq;
- int online, id;
+ int online, id, i = 0, maxzqs = 0;
+ struct zcrypt_queue **zq_uelist = NULL;
if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
return -EINVAL;
@@ -77,10 +78,35 @@ static ssize_t online_store(struct device *dev,
ZCRYPT_DBF(DBF_INFO, "card=%02x online=%d\n", id, online);
+ ap_send_online_uevent(&ac->ap_dev, online);
+
spin_lock(&zcrypt_list_lock);
+ /*
+ * As we are in atomic context here, directly sending uevents
+ * does not work. So collect the zqueues in a dynamic array
+ * and process them after zcrypt_list_lock release. As we get/put
+ * the zqueue objects, we make sure they exist after lock release.
+ */
+ list_for_each_entry(zq, &zc->zqueues, list)
+ maxzqs++;
+ if (maxzqs > 0)
+ zq_uelist = kcalloc(maxzqs + 1, sizeof(zq), GFP_ATOMIC);
list_for_each_entry(zq, &zc->zqueues, list)
- zcrypt_queue_force_online(zq, online);
+ if (zcrypt_queue_force_online(zq, online))
+ if (zq_uelist) {
+ zcrypt_queue_get(zq);
+ zq_uelist[i++] = zq;
+ }
spin_unlock(&zcrypt_list_lock);
+ if (zq_uelist) {
+ for (i = 0; zq_uelist[i]; i++) {
+ zq = zq_uelist[i];
+ ap_send_online_uevent(&zq->queue->ap_dev, online);
+ zcrypt_queue_put(zq);
+ }
+ kfree(zq_uelist);
+ }
+
return count;
}
diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c
index d68c0ed5e0dd..bc34bedf9db8 100644
--- a/drivers/s390/crypto/zcrypt_ccamisc.c
+++ b/drivers/s390/crypto/zcrypt_ccamisc.c
@@ -295,7 +295,7 @@ static inline void prep_xcrb(struct ica_xcRB *pxcrb,
* Generate (random) CCA AES DATA secure key.
*/
int cca_genseckey(u16 cardnr, u16 domain,
- u32 keybitsize, u8 seckey[SECKEYBLOBSIZE])
+ u32 keybitsize, u8 *seckey)
{
int i, rc, keysize;
int seckeysize;
@@ -330,7 +330,7 @@ int cca_genseckey(u16 cardnr, u16 domain,
struct {
u16 toklen;
u16 tokattr;
- u8 tok[0];
+ u8 tok[];
/* ... some more data ... */
} keyblock;
} lv3;
@@ -438,7 +438,7 @@ EXPORT_SYMBOL(cca_genseckey);
* Generate an CCA AES DATA secure key with given key value.
*/
int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
- const u8 *clrkey, u8 seckey[SECKEYBLOBSIZE])
+ const u8 *clrkey, u8 *seckey)
{
int rc, keysize, seckeysize;
u8 *mem, *ptr;
@@ -471,7 +471,7 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
struct {
u16 toklen;
u16 tokattr;
- u8 tok[0];
+ u8 tok[];
/* ... some more data ... */
} keyblock;
} lv3;
@@ -577,8 +577,8 @@ EXPORT_SYMBOL(cca_clr2seckey);
* Derive proteced key from an CCA AES DATA secure key.
*/
int cca_sec2protkey(u16 cardnr, u16 domain,
- const u8 seckey[SECKEYBLOBSIZE],
- u8 *protkey, u32 *protkeylen, u32 *protkeytype)
+ const u8 *seckey, u8 *protkey, u32 *protkeylen,
+ u32 *protkeytype)
{
int rc;
u8 *mem, *ptr;
@@ -596,7 +596,7 @@ int cca_sec2protkey(u16 cardnr, u16 domain,
u16 len;
u16 attr_len;
u16 attr_flags;
- u8 token[0]; /* cca secure key token */
+ u8 token[]; /* cca secure key token */
} lv2;
} __packed * preqparm;
struct uskrepparm {
diff --git a/drivers/s390/crypto/zcrypt_ccamisc.h b/drivers/s390/crypto/zcrypt_ccamisc.h
index e7105443d5cb..3513cd8ab9bc 100644
--- a/drivers/s390/crypto/zcrypt_ccamisc.h
+++ b/drivers/s390/crypto/zcrypt_ccamisc.h
@@ -171,8 +171,8 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
* Derive proteced key from an CCA AES DATA secure key.
*/
int cca_sec2protkey(u16 cardnr, u16 domain,
- const u8 seckey[SECKEYBLOBSIZE],
- u8 *protkey, u32 *protkeylen, u32 *protkeytype);
+ const u8 *seckey, u8 *protkey, u32 *protkeylen,
+ u32 *protkeytype);
/*
* Generate (random) CCA AES CIPHER secure key.
diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c
index f4a6d3744241..f518b5fc7e5d 100644
--- a/drivers/s390/crypto/zcrypt_cex4.c
+++ b/drivers/s390/crypto/zcrypt_cex4.c
@@ -28,9 +28,6 @@
#define CEX4C_MIN_MOD_SIZE 16 /* 256 bits */
#define CEX4C_MAX_MOD_SIZE 512 /* 4096 bits */
-#define CEX4A_MAX_MESSAGE_SIZE MSGTYPE50_CRB3_MAX_MSG_SIZE
-#define CEX4C_MAX_MESSAGE_SIZE MSGTYPE06_MAX_MSG_SIZE
-
/* Waiting time for requests to be processed.
* Currently there are some types of request which are not deterministic.
* But the maximum time limit managed by the stomper code is set to 60sec.
@@ -605,19 +602,19 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev)
int rc;
if (ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL)) {
- zq = zcrypt_queue_alloc(CEX4A_MAX_MESSAGE_SIZE);
+ zq = zcrypt_queue_alloc(aq->card->maxmsgsize);
if (!zq)
return -ENOMEM;
zq->ops = zcrypt_msgtype(MSGTYPE50_NAME,
MSGTYPE50_VARIANT_DEFAULT);
} else if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) {
- zq = zcrypt_queue_alloc(CEX4C_MAX_MESSAGE_SIZE);
+ zq = zcrypt_queue_alloc(aq->card->maxmsgsize);
if (!zq)
return -ENOMEM;
zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_DEFAULT);
} else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11)) {
- zq = zcrypt_queue_alloc(CEX4C_MAX_MESSAGE_SIZE);
+ zq = zcrypt_queue_alloc(aq->card->maxmsgsize);
if (!zq)
return -ENOMEM;
zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c
index bf14ee445f89..99405472824d 100644
--- a/drivers/s390/crypto/zcrypt_msgtype50.c
+++ b/drivers/s390/crypto/zcrypt_msgtype50.c
@@ -375,6 +375,7 @@ static int convert_type80(struct zcrypt_queue *zq,
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
t80h->code);
+ ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
return -EAGAIN;
}
if (zq->zcard->user_space_type == ZCRYPT_CEX2A)
@@ -412,6 +413,7 @@ static int convert_response_cex2a(struct zcrypt_queue *zq,
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) rtype);
+ ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
return -EAGAIN;
}
}
@@ -440,11 +442,13 @@ static void zcrypt_cex2a_receive(struct ap_queue *aq,
goto out; /* ap_msg->rc indicates the error */
t80h = reply->msg;
if (t80h->type == TYPE80_RSP_CODE) {
- if (aq->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A)
- len = min_t(int, CEX2A_MAX_RESPONSE_SIZE, t80h->len);
- else
- len = min_t(int, CEX3A_MAX_RESPONSE_SIZE, t80h->len);
- memcpy(msg->msg, reply->msg, len);
+ len = t80h->len;
+ if (len > reply->bufsize || len > msg->bufsize) {
+ msg->rc = -EMSGSIZE;
+ } else {
+ memcpy(msg->msg, reply->msg, len);
+ msg->len = len;
+ }
} else
memcpy(msg->msg, reply->msg, sizeof(error_reply));
out:
@@ -467,10 +471,9 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq,
struct completion work;
int rc;
- if (zq->zcard->user_space_type == ZCRYPT_CEX2A)
- ap_msg->msg = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, GFP_KERNEL);
- else
- ap_msg->msg = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE, GFP_KERNEL);
+ ap_msg->bufsize = (zq->zcard->user_space_type == ZCRYPT_CEX2A) ?
+ MSGTYPE50_CRB2_MAX_MSG_SIZE : MSGTYPE50_CRB3_MAX_MSG_SIZE;
+ ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
if (!ap_msg->msg)
return -ENOMEM;
ap_msg->receive = zcrypt_cex2a_receive;
@@ -513,10 +516,9 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq,
struct completion work;
int rc;
- if (zq->zcard->user_space_type == ZCRYPT_CEX2A)
- ap_msg->msg = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, GFP_KERNEL);
- else
- ap_msg->msg = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE, GFP_KERNEL);
+ ap_msg->bufsize = (zq->zcard->user_space_type == ZCRYPT_CEX2A) ?
+ MSGTYPE50_CRB2_MAX_MSG_SIZE : MSGTYPE50_CRB3_MAX_MSG_SIZE;
+ ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
if (!ap_msg->msg)
return -ENOMEM;
ap_msg->receive = zcrypt_cex2a_receive;
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index 307f90657d1d..752c6398fcd6 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -403,7 +403,7 @@ static int XCRB_msg_to_type6CPRB_msgX(bool userspace, struct ap_message *ap_msg,
} __packed * msg = ap_msg->msg;
int rcblen = CEIL4(xcRB->request_control_blk_length);
- int replylen, req_sumlen, resp_sumlen;
+ int req_sumlen, resp_sumlen;
char *req_data = ap_msg->msg + sizeof(struct type6_hdr) + rcblen;
char *function_code;
@@ -415,7 +415,7 @@ static int XCRB_msg_to_type6CPRB_msgX(bool userspace, struct ap_message *ap_msg,
ap_msg->len = sizeof(struct type6_hdr) +
CEIL4(xcRB->request_control_blk_length) +
xcRB->request_data_length;
- if (ap_msg->len > MSGTYPE06_MAX_MSG_SIZE)
+ if (ap_msg->len > ap_msg->bufsize)
return -EINVAL;
/*
@@ -435,12 +435,6 @@ static int XCRB_msg_to_type6CPRB_msgX(bool userspace, struct ap_message *ap_msg,
xcRB->reply_control_blk_length)
return -EINVAL; /* overflow after alignment*/
- replylen = sizeof(struct type86_fmt2_msg) +
- CEIL4(xcRB->reply_control_blk_length) +
- xcRB->reply_data_length;
- if (replylen > MSGTYPE06_MAX_MSG_SIZE)
- return -EINVAL;
-
/*
* Overflow check
* sum must be greater (or equal) than the largest operand
@@ -530,18 +524,13 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap
return -EINVAL; /* overflow after alignment*/
/* length checks */
- ap_msg->len = sizeof(struct type6_hdr) + xcRB->req_len;
- if (CEIL4(xcRB->req_len) > MSGTYPE06_MAX_MSG_SIZE -
- (sizeof(struct type6_hdr)))
+ ap_msg->len = sizeof(struct type6_hdr) + CEIL4(xcRB->req_len);
+ if (ap_msg->len > ap_msg->bufsize)
return -EINVAL;
if (CEIL4(xcRB->resp_len) < xcRB->resp_len)
return -EINVAL; /* overflow after alignment*/
- if (CEIL4(xcRB->resp_len) > MSGTYPE06_MAX_MSG_SIZE -
- (sizeof(struct type86_fmt2_msg)))
- return -EINVAL;
-
/* prepare type6 header */
msg->hdr = static_type6_ep11_hdr;
msg->hdr.ToCardLen1 = xcRB->req_len;
@@ -675,6 +664,7 @@ static int convert_type86_ica(struct zcrypt_queue *zq,
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) service_rc, (int) service_rs);
+ ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
return -EAGAIN;
}
data = msg->text;
@@ -820,6 +810,7 @@ static int convert_response_ica(struct zcrypt_queue *zq,
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) msg->hdr.type);
+ ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
return -EAGAIN;
}
}
@@ -854,6 +845,7 @@ static int convert_response_xcrb(bool userspace, struct zcrypt_queue *zq,
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) msg->hdr.type);
+ ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
return -EAGAIN;
}
}
@@ -883,6 +875,7 @@ static int convert_response_ep11_xcrb(bool userspace, struct zcrypt_queue *zq,
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) msg->hdr.type);
+ ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
return -EAGAIN;
}
}
@@ -913,6 +906,7 @@ static int convert_response_rng(struct zcrypt_queue *zq,
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) msg->hdr.type);
+ ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
return -EAGAIN;
}
}
@@ -947,13 +941,21 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq,
switch (resp_type->type) {
case CEXXC_RESPONSE_TYPE_ICA:
len = sizeof(struct type86x_reply) + t86r->length - 2;
- len = min_t(int, CEXXC_MAX_ICA_RESPONSE_SIZE, len);
- memcpy(msg->msg, reply->msg, len);
+ if (len > reply->bufsize || len > msg->bufsize) {
+ msg->rc = -EMSGSIZE;
+ } else {
+ memcpy(msg->msg, reply->msg, len);
+ msg->len = len;
+ }
break;
case CEXXC_RESPONSE_TYPE_XCRB:
len = t86r->fmt2.offset2 + t86r->fmt2.count2;
- len = min_t(int, MSGTYPE06_MAX_MSG_SIZE, len);
- memcpy(msg->msg, reply->msg, len);
+ if (len > reply->bufsize || len > msg->bufsize) {
+ msg->rc = -EMSGSIZE;
+ } else {
+ memcpy(msg->msg, reply->msg, len);
+ msg->len = len;
+ }
break;
default:
memcpy(msg->msg, &error_reply, sizeof(error_reply));
@@ -994,8 +996,12 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq,
switch (resp_type->type) {
case CEXXC_RESPONSE_TYPE_EP11:
len = t86r->fmt2.offset1 + t86r->fmt2.count1;
- len = min_t(int, MSGTYPE06_MAX_MSG_SIZE, len);
- memcpy(msg->msg, reply->msg, len);
+ if (len > reply->bufsize || len > msg->bufsize) {
+ msg->rc = -EMSGSIZE;
+ } else {
+ memcpy(msg->msg, reply->msg, len);
+ msg->len = len;
+ }
break;
default:
memcpy(msg->msg, &error_reply, sizeof(error_reply));
@@ -1028,6 +1034,7 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
ap_msg->msg = (void *) get_zeroed_page(GFP_KERNEL);
if (!ap_msg->msg)
return -ENOMEM;
+ ap_msg->bufsize = PAGE_SIZE;
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
@@ -1075,6 +1082,7 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
ap_msg->msg = (void *) get_zeroed_page(GFP_KERNEL);
if (!ap_msg->msg)
return -ENOMEM;
+ ap_msg->bufsize = PAGE_SIZE;
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
@@ -1119,7 +1127,8 @@ unsigned int get_cprb_fc(bool userspace, struct ica_xcRB *xcRB,
.type = CEXXC_RESPONSE_TYPE_XCRB,
};
- ap_msg->msg = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
+ ap_msg->bufsize = atomic_read(&ap_max_msg_size);
+ ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
if (!ap_msg->msg)
return -ENOMEM;
ap_msg->receive = zcrypt_msgtype6_receive;
@@ -1176,7 +1185,8 @@ unsigned int get_ep11cprb_fc(bool userspace, struct ep11_urb *xcrb,
.type = CEXXC_RESPONSE_TYPE_EP11,
};
- ap_msg->msg = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
+ ap_msg->bufsize = atomic_read(&ap_max_msg_size);
+ ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
if (!ap_msg->msg)
return -ENOMEM;
ap_msg->receive = zcrypt_msgtype6_receive_ep11;
@@ -1272,7 +1282,8 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code,
.type = CEXXC_RESPONSE_TYPE_XCRB,
};
- ap_msg->msg = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
+ ap_msg->bufsize = AP_DEFAULT_MAX_MSG_SIZE;
+ ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
if (!ap_msg->msg)
return -ENOMEM;
ap_msg->receive = zcrypt_msgtype6_receive;
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h
index 0a0bf074206b..155c73514bac 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.h
+++ b/drivers/s390/crypto/zcrypt_msgtype6.h
@@ -19,8 +19,6 @@
#define MSGTYPE06_VARIANT_NORNG 1
#define MSGTYPE06_VARIANT_EP11 2
-#define MSGTYPE06_MAX_MSG_SIZE (12*1024)
-
/**
* The type 6 message family is associated with CEXxC/CEXxP cards.
*
diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c
index c3ffbd26b73f..20f12288a8c1 100644
--- a/drivers/s390/crypto/zcrypt_queue.c
+++ b/drivers/s390/crypto/zcrypt_queue.c
@@ -70,6 +70,8 @@ static ssize_t online_store(struct device *dev,
AP_QID_QUEUE(zq->queue->qid),
online);
+ ap_send_online_uevent(&aq->ap_dev, online);
+
if (!online)
ap_flush_queue(zq->queue);
return count;
@@ -98,24 +100,28 @@ static const struct attribute_group zcrypt_queue_attr_group = {
.attrs = zcrypt_queue_attrs,
};
-void zcrypt_queue_force_online(struct zcrypt_queue *zq, int online)
+bool zcrypt_queue_force_online(struct zcrypt_queue *zq, int online)
{
- zq->online = online;
- if (!online)
- ap_flush_queue(zq->queue);
+ if (!!zq->online != !!online) {
+ zq->online = online;
+ if (!online)
+ ap_flush_queue(zq->queue);
+ return true;
+ }
+ return false;
}
-struct zcrypt_queue *zcrypt_queue_alloc(size_t max_response_size)
+struct zcrypt_queue *zcrypt_queue_alloc(size_t reply_buf_size)
{
struct zcrypt_queue *zq;
zq = kzalloc(sizeof(struct zcrypt_queue), GFP_KERNEL);
if (!zq)
return NULL;
- zq->reply.msg = kmalloc(max_response_size, GFP_KERNEL);
+ zq->reply.msg = kmalloc(reply_buf_size, GFP_KERNEL);
if (!zq->reply.msg)
goto out_free;
- zq->reply.len = max_response_size;
+ zq->reply.bufsize = reply_buf_size;
INIT_LIST_HEAD(&zq->list);
kref_init(&zq->refcount);
return zq;
@@ -173,7 +179,6 @@ int zcrypt_queue_register(struct zcrypt_queue *zq)
AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid));
list_add_tail(&zq->list, &zc->zqueues);
- zcrypt_device_count++;
spin_unlock(&zcrypt_list_lock);
rc = sysfs_create_group(&zq->queue->ap_dev.device.kobj,
@@ -216,7 +221,6 @@ void zcrypt_queue_unregister(struct zcrypt_queue *zq)
zc = zq->zcard;
spin_lock(&zcrypt_list_lock);
list_del_init(&zq->list);
- zcrypt_device_count--;
spin_unlock(&zcrypt_list_lock);
if (zq->ops->rng)
zcrypt_rng_device_remove();
diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c
index b341075397d9..377e3689d1d4 100644
--- a/drivers/s390/net/ctcm_fsms.c
+++ b/drivers/s390/net/ctcm_fsms.c
@@ -1454,6 +1454,7 @@ again:
get_ccwdev_lock(ch->cdev), saveflags);
if (rc != 0)
ctcm_ccw_check_rc(ch, rc, "normal RX");
+ break;
default:
break;
}
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 260860cf3aa1..5a0c2f07a3a2 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -118,24 +118,6 @@ static struct device_driver netiucv_driver = {
.bus = &iucv_bus,
};
-static int netiucv_callback_connreq(struct iucv_path *, u8 *, u8 *);
-static void netiucv_callback_connack(struct iucv_path *, u8 *);
-static void netiucv_callback_connrej(struct iucv_path *, u8 *);
-static void netiucv_callback_connsusp(struct iucv_path *, u8 *);
-static void netiucv_callback_connres(struct iucv_path *, u8 *);
-static void netiucv_callback_rx(struct iucv_path *, struct iucv_message *);
-static void netiucv_callback_txdone(struct iucv_path *, struct iucv_message *);
-
-static struct iucv_handler netiucv_handler = {
- .path_pending = netiucv_callback_connreq,
- .path_complete = netiucv_callback_connack,
- .path_severed = netiucv_callback_connrej,
- .path_quiesced = netiucv_callback_connsusp,
- .path_resumed = netiucv_callback_connres,
- .message_pending = netiucv_callback_rx,
- .message_complete = netiucv_callback_txdone
-};
-
/**
* Per connection profiling data
*/
@@ -774,6 +756,16 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
}
}
+static struct iucv_handler netiucv_handler = {
+ .path_pending = netiucv_callback_connreq,
+ .path_complete = netiucv_callback_connack,
+ .path_severed = netiucv_callback_connrej,
+ .path_quiesced = netiucv_callback_connsusp,
+ .path_resumed = netiucv_callback_connres,
+ .message_pending = netiucv_callback_rx,
+ .message_complete = netiucv_callback_txdone,
+};
+
static void conn_action_connaccept(fsm_instance *fi, int event, void *arg)
{
struct iucv_event *ev = arg;
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index fd9b869d278e..f4d554ea0c93 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -417,13 +417,17 @@ enum qeth_qdio_out_buffer_state {
QETH_QDIO_BUF_EMPTY,
/* Filled by driver; owned by hardware in order to be sent. */
QETH_QDIO_BUF_PRIMED,
- /* Discovered by the TX completion code: */
- QETH_QDIO_BUF_PENDING,
- /* Finished by the TX completion code: */
- QETH_QDIO_BUF_NEED_QAOB,
- /* Received QAOB notification on CQ: */
- QETH_QDIO_BUF_QAOB_OK,
- QETH_QDIO_BUF_QAOB_ERROR,
+};
+
+enum qeth_qaob_state {
+ QETH_QAOB_ISSUED,
+ QETH_QAOB_PENDING,
+ QETH_QAOB_DONE,
+};
+
+struct qeth_qaob_priv1 {
+ unsigned int state;
+ u8 queue_no;
};
struct qeth_qdio_out_buffer {
@@ -433,9 +437,8 @@ struct qeth_qdio_out_buffer {
unsigned int frames;
unsigned int bytes;
struct sk_buff_head skb_list;
- int is_header[QDIO_MAX_ELEMENTS_PER_BUFFER];
+ DECLARE_BITMAP(from_kmem_cache, QDIO_MAX_ELEMENTS_PER_BUFFER);
- struct qeth_qdio_out_q *q;
struct list_head list_entry;
struct qaob *aob;
};
@@ -483,6 +486,7 @@ struct qeth_out_q_stats {
u64 stopped;
u64 doorbell;
u64 coal_frames;
+ u64 completion_irq;
u64 completion_yield;
u64 completion_timer;
@@ -526,6 +530,7 @@ struct qeth_qdio_out_q {
unsigned int coalesce_usecs;
unsigned int max_coalesced_frames;
+ unsigned int rescan_usecs;
};
#define qeth_for_each_output_queue(card, q, i) \
@@ -612,7 +617,6 @@ struct qeth_channel {
struct ccw_device *ccwdev;
struct qeth_cmd_buffer *active_cmd;
enum qeth_channel_states state;
- atomic_t irq_pending;
};
struct qeth_reply {
@@ -662,11 +666,6 @@ 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)
-{
- return atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0;
-}
-
/**
* OSA card related definitions
*/
@@ -886,13 +885,24 @@ static inline bool qeth_card_hw_is_reachable(struct qeth_card *card)
return card->state == CARD_STATE_SOFTSETUP;
}
+static inline bool qeth_use_tx_irqs(struct qeth_card *card)
+{
+ return !IS_IQD(card);
+}
+
static inline void qeth_unlock_channel(struct qeth_card *card,
struct qeth_channel *channel)
{
- atomic_set(&channel->irq_pending, 0);
+ xchg(&channel->active_cmd, NULL);
wake_up(&card->wait_q);
}
+static inline bool qeth_trylock_channel(struct qeth_channel *channel,
+ struct qeth_cmd_buffer *cmd)
+{
+ return cmpxchg(&channel->active_cmd, NULL, cmd) == NULL;
+}
+
struct qeth_trap_id {
__u16 lparnr;
char vmname[8];
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index a1f08e9aa064..62f88ccbd03f 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -70,9 +70,6 @@ static void qeth_issue_next_read_cb(struct qeth_card *card,
unsigned int data_length);
static int qeth_qdio_establish(struct qeth_card *);
static void qeth_free_qdio_queues(struct qeth_card *card);
-static void qeth_notify_skbs(struct qeth_qdio_out_q *queue,
- struct qeth_qdio_out_buffer *buf,
- enum iucv_tx_notify notification);
static void qeth_close_dev_handler(struct work_struct *work)
{
@@ -434,65 +431,6 @@ static enum iucv_tx_notify qeth_compute_cq_notification(int sbalf15,
return n;
}
-static void qeth_qdio_handle_aob(struct qeth_card *card,
- unsigned long phys_aob_addr)
-{
- enum qeth_qdio_out_buffer_state new_state = QETH_QDIO_BUF_QAOB_OK;
- struct qaob *aob;
- struct qeth_qdio_out_buffer *buffer;
- enum iucv_tx_notify notification;
- struct qeth_qdio_out_q *queue;
- unsigned int i;
-
- aob = (struct qaob *) phys_to_virt(phys_aob_addr);
- QETH_CARD_TEXT(card, 5, "haob");
- QETH_CARD_TEXT_(card, 5, "%lx", phys_aob_addr);
- buffer = (struct qeth_qdio_out_buffer *) aob->user1;
- QETH_CARD_TEXT_(card, 5, "%lx", aob->user1);
-
- if (aob->aorc) {
- QETH_CARD_TEXT_(card, 2, "aorc%02X", aob->aorc);
- new_state = QETH_QDIO_BUF_QAOB_ERROR;
- }
-
- switch (atomic_xchg(&buffer->state, new_state)) {
- case QETH_QDIO_BUF_PRIMED:
- /* Faster than TX completion code, let it handle the async
- * completion for us. It will also recycle the QAOB.
- */
- break;
- case QETH_QDIO_BUF_PENDING:
- /* TX completion code is active and will handle the async
- * completion for us. It will also recycle the QAOB.
- */
- break;
- case QETH_QDIO_BUF_NEED_QAOB:
- /* TX completion code is already finished. */
- notification = qeth_compute_cq_notification(aob->aorc, 1);
- qeth_notify_skbs(buffer->q, buffer, notification);
-
- /* Free dangling allocations. The attached skbs are handled by
- * qeth_tx_complete_pending_bufs(), and so is the QAOB.
- */
- for (i = 0;
- i < aob->sb_count && i < QETH_MAX_BUFFER_ELEMENTS(card);
- i++) {
- void *data = phys_to_virt(aob->sba[i]);
-
- if (data && buffer->is_header[i])
- kmem_cache_free(qeth_core_header_cache, data);
- buffer->is_header[i] = 0;
- }
-
- queue = buffer->q;
- atomic_set(&buffer->state, QETH_QDIO_BUF_EMPTY);
- napi_schedule(&queue->napi);
- break;
- default:
- WARN_ON_ONCE(1);
- }
-}
-
static void qeth_setup_ccw(struct ccw1 *ccw, u8 cmd_code, u8 flags, u32 len,
void *data)
{
@@ -1268,7 +1206,6 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
iob = (struct qeth_cmd_buffer *) (addr_t)intparm;
}
- channel->active_cmd = NULL;
qeth_unlock_channel(card, channel);
rc = qeth_check_irb_error(card, cdev, irb);
@@ -1353,10 +1290,10 @@ static void qeth_notify_skbs(struct qeth_qdio_out_q *q,
}
}
-static void qeth_tx_complete_buf(struct qeth_qdio_out_buffer *buf, bool error,
+static void qeth_tx_complete_buf(struct qeth_qdio_out_q *queue,
+ struct qeth_qdio_out_buffer *buf, bool error,
int budget)
{
- struct qeth_qdio_out_q *queue = buf->q;
struct sk_buff *skb;
/* Empty buffer? */
@@ -1400,17 +1337,18 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
int i;
/* is PCI flag set on buffer? */
- if (buf->buffer->element[0].sflags & SBAL_SFLAGS0_PCI_REQ)
+ if (buf->buffer->element[0].sflags & SBAL_SFLAGS0_PCI_REQ) {
atomic_dec(&queue->set_pci_flags_count);
+ QETH_TXQ_STAT_INC(queue, completion_irq);
+ }
- qeth_tx_complete_buf(buf, error, budget);
+ qeth_tx_complete_buf(queue, buf, error, budget);
for (i = 0; i < queue->max_elements; ++i) {
void *data = phys_to_virt(buf->buffer->element[i].addr);
- if (data && buf->is_header[i])
+ if (__test_and_clear_bit(i, buf->from_kmem_cache) && data)
kmem_cache_free(qeth_core_header_cache, data);
- buf->is_header[i] = 0;
}
qeth_scrub_qdio_buffer(buf->buffer, queue->max_elements);
@@ -1434,14 +1372,30 @@ static void qeth_tx_complete_pending_bufs(struct qeth_card *card,
struct qeth_qdio_out_buffer *buf, *tmp;
list_for_each_entry_safe(buf, tmp, &queue->pending_bufs, list_entry) {
- if (drain || atomic_read(&buf->state) == QETH_QDIO_BUF_EMPTY) {
+ struct qeth_qaob_priv1 *priv;
+ struct qaob *aob = buf->aob;
+ enum iucv_tx_notify notify;
+ unsigned int i;
+
+ priv = (struct qeth_qaob_priv1 *)&aob->user1;
+ if (drain || READ_ONCE(priv->state) == QETH_QAOB_DONE) {
QETH_CARD_TEXT(card, 5, "fp");
QETH_CARD_TEXT_(card, 5, "%lx", (long) buf);
- if (drain)
- qeth_notify_skbs(queue, buf,
- TX_NOTIFY_GENERALERROR);
- qeth_tx_complete_buf(buf, drain, budget);
+ notify = drain ? TX_NOTIFY_GENERALERROR :
+ qeth_compute_cq_notification(aob->aorc, 1);
+ qeth_notify_skbs(queue, buf, notify);
+ qeth_tx_complete_buf(queue, buf, drain, budget);
+
+ for (i = 0;
+ i < aob->sb_count && i < queue->max_elements;
+ i++) {
+ void *data = phys_to_virt(aob->sba[i]);
+
+ if (test_bit(i, buf->from_kmem_cache) && data)
+ kmem_cache_free(qeth_core_header_cache,
+ data);
+ }
list_del(&buf->list_entry);
qeth_free_out_buf(buf);
@@ -1713,11 +1667,10 @@ static int qeth_stop_channel(struct qeth_channel *channel)
rc = ccw_device_set_offline(cdev);
spin_lock_irq(get_ccwdev_lock(cdev));
- if (channel->active_cmd) {
+ if (channel->active_cmd)
dev_err(&cdev->dev, "Stopped channel while cmd %px was still active\n",
channel->active_cmd);
- channel->active_cmd = NULL;
- }
+
cdev->handler = NULL;
spin_unlock_irq(get_ccwdev_lock(cdev));
@@ -1730,7 +1683,7 @@ static int qeth_start_channel(struct qeth_channel *channel)
int rc;
channel->state = CH_STATE_DOWN;
- atomic_set(&channel->irq_pending, 0);
+ xchg(&channel->active_cmd, NULL);
spin_lock_irq(get_ccwdev_lock(cdev));
cdev->handler = qeth_irq;
@@ -2037,7 +1990,7 @@ static int qeth_send_control_data(struct qeth_card *card,
reply->param = reply_param;
timeout = wait_event_interruptible_timeout(card->wait_q,
- qeth_trylock_channel(channel),
+ qeth_trylock_channel(channel, iob),
timeout);
if (timeout <= 0) {
qeth_put_cmd(iob);
@@ -2057,8 +2010,6 @@ static int qeth_send_control_data(struct qeth_card *card,
spin_lock_irq(get_ccwdev_lock(channel->ccwdev));
rc = ccw_device_start_timeout(channel->ccwdev, __ccw_from_cmd(iob),
(addr_t) iob, 0, 0, timeout);
- if (!rc)
- channel->active_cmd = iob;
spin_unlock_irq(get_ccwdev_lock(channel->ccwdev));
if (rc) {
QETH_DBF_MESSAGE(2, "qeth_send_control_data on device %x: ccw_device_start rc = %i\n",
@@ -2578,7 +2529,6 @@ static int qeth_alloc_out_buf(struct qeth_qdio_out_q *q, unsigned int bidx,
newbuf->buffer = q->qdio_bufs[bidx];
skb_queue_head_init(&newbuf->skb_list);
lockdep_set_class(&newbuf->skb_list.lock, &qdio_out_skb_queue_key);
- newbuf->q = q;
atomic_set(&newbuf->state, QETH_QDIO_BUF_EMPTY);
q->bufs[bidx] = newbuf;
return 0;
@@ -2663,8 +2613,15 @@ static int qeth_alloc_qdio_queues(struct qeth_card *card)
INIT_LIST_HEAD(&queue->pending_bufs);
spin_lock_init(&queue->lock);
timer_setup(&queue->timer, qeth_tx_completion_timer, 0);
- queue->coalesce_usecs = QETH_TX_COALESCE_USECS;
- queue->max_coalesced_frames = QETH_TX_MAX_COALESCED_FRAMES;
+ if (IS_IQD(card)) {
+ queue->coalesce_usecs = QETH_TX_COALESCE_USECS;
+ queue->max_coalesced_frames = QETH_TX_MAX_COALESCED_FRAMES;
+ queue->rescan_usecs = QETH_TX_TIMER_USECS;
+ } else {
+ queue->coalesce_usecs = USEC_PER_SEC;
+ queue->max_coalesced_frames = 0;
+ queue->rescan_usecs = 10 * USEC_PER_SEC;
+ }
queue->priority = QETH_QIB_PQUE_PRIO_DEFAULT;
}
@@ -3601,8 +3558,8 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
int count)
{
struct qeth_qdio_out_buffer *buf = queue->bufs[index];
- unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
struct qeth_card *card = queue->card;
+ unsigned int frames, usecs;
struct qaob *aob = NULL;
int rc;
int i;
@@ -3629,8 +3586,12 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
if (!buf->aob)
buf->aob = qdio_allocate_aob();
if (buf->aob) {
+ struct qeth_qaob_priv1 *priv;
+
aob = buf->aob;
- aob->user1 = (u64) buf;
+ priv = (struct qeth_qaob_priv1 *)&aob->user1;
+ priv->state = QETH_QAOB_ISSUED;
+ priv->queue_no = queue->queue_no;
}
}
} else {
@@ -3658,14 +3619,11 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
buf->buffer->element[0].sflags |= SBAL_SFLAGS0_PCI_REQ;
}
}
-
- if (atomic_read(&queue->set_pci_flags_count))
- qdio_flags |= QDIO_FLAG_PCI_OUT;
}
QETH_TXQ_STAT_INC(queue, doorbell);
- rc = do_QDIO(CARD_DDEV(card), qdio_flags, queue->queue_no, index, count,
- aob);
+ rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_OUTPUT, queue->queue_no,
+ index, count, aob);
switch (rc) {
case 0:
@@ -3673,17 +3631,20 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
/* ignore temporary SIGA errors without busy condition */
/* Fake the TX completion interrupt: */
- if (IS_IQD(card)) {
- unsigned int frames = READ_ONCE(queue->max_coalesced_frames);
- unsigned int usecs = READ_ONCE(queue->coalesce_usecs);
+ frames = READ_ONCE(queue->max_coalesced_frames);
+ usecs = READ_ONCE(queue->coalesce_usecs);
- if (frames && queue->coalesced_frames >= frames) {
- napi_schedule(&queue->napi);
- queue->coalesced_frames = 0;
- QETH_TXQ_STAT_INC(queue, coal_frames);
- } else if (usecs) {
- qeth_tx_arm_timer(queue, usecs);
- }
+ if (frames && queue->coalesced_frames >= frames) {
+ napi_schedule(&queue->napi);
+ queue->coalesced_frames = 0;
+ QETH_TXQ_STAT_INC(queue, coal_frames);
+ } else if (qeth_use_tx_irqs(card) &&
+ atomic_read(&queue->used_buffers) >= 32) {
+ /* Old behaviour carried over from the qdio layer: */
+ napi_schedule(&queue->napi);
+ QETH_TXQ_STAT_INC(queue, coal_frames);
+ } else if (usecs) {
+ qeth_tx_arm_timer(queue, usecs);
}
break;
@@ -3769,6 +3730,18 @@ out:
}
EXPORT_SYMBOL_GPL(qeth_configure_cq);
+static void qeth_qdio_handle_aob(struct qeth_card *card, struct qaob *aob)
+{
+ struct qeth_qaob_priv1 *priv = (struct qeth_qaob_priv1 *)&aob->user1;
+ unsigned int queue_no = priv->queue_no;
+
+ BUILD_BUG_ON(sizeof(*priv) > ARRAY_SIZE(aob->user1));
+
+ if (xchg(&priv->state, QETH_QAOB_DONE) == QETH_QAOB_PENDING &&
+ queue_no < card->qdio.no_out_queues)
+ napi_schedule(&card->qdio.out_qs[queue_no]->napi);
+}
+
static void qeth_qdio_cq_handler(struct qeth_card *card, unsigned int qdio_err,
unsigned int queue, int first_element,
int count)
@@ -3795,7 +3768,7 @@ static void qeth_qdio_cq_handler(struct qeth_card *card, unsigned int qdio_err,
buffer->element[e].addr) {
unsigned long phys_aob_addr = buffer->element[e].addr;
- qeth_qdio_handle_aob(card, phys_aob_addr);
+ qeth_qdio_handle_aob(card, phys_to_virt(phys_aob_addr));
++e;
}
qeth_scrub_qdio_buffer(buffer, QDIO_MAX_ELEMENTS_PER_BUFFER);
@@ -3831,36 +3804,14 @@ static void qeth_qdio_output_handler(struct ccw_device *ccwdev,
unsigned long card_ptr)
{
struct qeth_card *card = (struct qeth_card *) card_ptr;
- struct qeth_qdio_out_q *queue = card->qdio.out_qs[__queue];
struct net_device *dev = card->dev;
- struct netdev_queue *txq;
- int i;
QETH_CARD_TEXT(card, 6, "qdouhdl");
if (qdio_error & QDIO_ERROR_FATAL) {
QETH_CARD_TEXT(card, 2, "achkcond");
netif_tx_stop_all_queues(dev);
qeth_schedule_recovery(card);
- return;
}
-
- for (i = first_element; i < (first_element + count); ++i) {
- struct qeth_qdio_out_buffer *buf = queue->bufs[QDIO_BUFNR(i)];
-
- qeth_handle_send_error(card, buf, qdio_error);
- qeth_clear_output_buffer(queue, buf, qdio_error, 0);
- }
-
- atomic_sub(count, &queue->used_buffers);
- qeth_check_outbound_queue(queue);
-
- txq = netdev_get_tx_queue(dev, __queue);
- /* xmit may have observed the full-condition, but not yet stopped the
- * txq. In which case the code below won't trigger. So before returning,
- * xmit will re-check the txq's fill level and wake it up if needed.
- */
- if (netif_tx_queue_stopped(txq) && !qeth_out_queue_is_full(queue))
- netif_tx_wake_queue(txq);
}
/**
@@ -4101,7 +4052,7 @@ static unsigned int qeth_fill_buffer(struct qeth_qdio_out_buffer *buf,
/* HW header is allocated from cache: */
if ((void *)hdr != skb->data)
- buf->is_header[element] = 1;
+ __set_bit(element, buf->from_kmem_cache);
/* HW header was pushed and is contiguous with linear part: */
else if (length > 0 && !PAGE_ALIGNED(data) &&
(data == (char *)hdr + hd_len))
@@ -5256,7 +5207,6 @@ static int qeth_qdio_establish(struct qeth_card *card)
init_data.int_parm = (unsigned long) card;
init_data.input_sbal_addr_array = in_sbal_ptrs;
init_data.output_sbal_addr_array = out_sbal_ptrs;
- init_data.scan_threshold = IS_IQD(card) ? 0 : 32;
if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED,
QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) {
@@ -5956,9 +5906,10 @@ static unsigned int qeth_rx_poll(struct qeth_card *card, int budget)
/* Fetch completed RX buffers: */
if (!card->rx.b_count) {
card->rx.qdio_err = 0;
- card->rx.b_count = qdio_get_next_buffers(
- card->data.ccwdev, 0, &card->rx.b_index,
- &card->rx.qdio_err);
+ card->rx.b_count = qdio_inspect_queue(CARD_DDEV(card),
+ 0, true,
+ &card->rx.b_index,
+ &card->rx.qdio_err);
if (card->rx.b_count <= 0) {
card->rx.b_count = 0;
break;
@@ -6022,6 +5973,16 @@ int qeth_poll(struct napi_struct *napi, int budget)
work_done = qeth_rx_poll(card, budget);
+ if (qeth_use_tx_irqs(card)) {
+ struct qeth_qdio_out_q *queue;
+ unsigned int i;
+
+ qeth_for_each_output_queue(card, queue, i) {
+ if (!qeth_out_queue_is_empty(queue))
+ napi_schedule(&queue->napi);
+ }
+ }
+
if (card->options.cq == QETH_CQ_ENABLED)
qeth_cq_poll(card);
@@ -6055,6 +6016,8 @@ static void qeth_iqd_tx_complete(struct qeth_qdio_out_q *queue,
if (qdio_error == QDIO_ERROR_SLSB_PENDING) {
struct qaob *aob = buffer->aob;
+ struct qeth_qaob_priv1 *priv;
+ enum iucv_tx_notify notify;
if (!aob) {
netdev_WARN_ONCE(card->dev,
@@ -6066,60 +6029,27 @@ static void qeth_iqd_tx_complete(struct qeth_qdio_out_q *queue,
QETH_CARD_TEXT_(card, 5, "pel%u", bidx);
- switch (atomic_cmpxchg(&buffer->state,
- QETH_QDIO_BUF_PRIMED,
- QETH_QDIO_BUF_PENDING)) {
- case QETH_QDIO_BUF_PRIMED:
- /* We have initial ownership, no QAOB (yet): */
+ priv = (struct qeth_qaob_priv1 *)&aob->user1;
+ /* QAOB hasn't completed yet: */
+ if (xchg(&priv->state, QETH_QAOB_PENDING) != QETH_QAOB_DONE) {
qeth_notify_skbs(queue, buffer, TX_NOTIFY_PENDING);
- /* Handle race with qeth_qdio_handle_aob(): */
- switch (atomic_xchg(&buffer->state,
- QETH_QDIO_BUF_NEED_QAOB)) {
- case QETH_QDIO_BUF_PENDING:
- /* No concurrent QAOB notification. */
-
- /* Prepare the queue slot for immediate re-use: */
- qeth_scrub_qdio_buffer(buffer->buffer, queue->max_elements);
- if (qeth_alloc_out_buf(queue, bidx,
- GFP_ATOMIC)) {
- QETH_CARD_TEXT(card, 2, "outofbuf");
- qeth_schedule_recovery(card);
- }
-
- list_add(&buffer->list_entry,
- &queue->pending_bufs);
- /* Skip clearing the buffer: */
- return;
- case QETH_QDIO_BUF_QAOB_OK:
- qeth_notify_skbs(queue, buffer,
- TX_NOTIFY_DELAYED_OK);
- error = false;
- break;
- case QETH_QDIO_BUF_QAOB_ERROR:
- qeth_notify_skbs(queue, buffer,
- TX_NOTIFY_DELAYED_GENERALERROR);
- error = true;
- break;
- default:
- WARN_ON_ONCE(1);
+ /* Prepare the queue slot for immediate re-use: */
+ qeth_scrub_qdio_buffer(buffer->buffer, queue->max_elements);
+ if (qeth_alloc_out_buf(queue, bidx, GFP_ATOMIC)) {
+ QETH_CARD_TEXT(card, 2, "outofbuf");
+ qeth_schedule_recovery(card);
}
- break;
- case QETH_QDIO_BUF_QAOB_OK:
- /* qeth_qdio_handle_aob() already received a QAOB: */
- qeth_notify_skbs(queue, buffer, TX_NOTIFY_OK);
- error = false;
- break;
- case QETH_QDIO_BUF_QAOB_ERROR:
- /* qeth_qdio_handle_aob() already received a QAOB: */
- qeth_notify_skbs(queue, buffer, TX_NOTIFY_GENERALERROR);
- error = true;
- break;
- default:
- WARN_ON_ONCE(1);
+ list_add(&buffer->list_entry, &queue->pending_bufs);
+ /* Skip clearing the buffer: */
+ return;
}
+ /* QAOB already completed: */
+ notify = qeth_compute_cq_notification(aob->aorc, 0);
+ qeth_notify_skbs(queue, buffer, notify);
+ error = !!aob->aorc;
memset(aob, 0, sizeof(*aob));
} else if (card->options.cq == QETH_CQ_ENABLED) {
qeth_notify_skbs(queue, buffer,
@@ -6138,7 +6068,10 @@ static int qeth_tx_poll(struct napi_struct *napi, int budget)
unsigned int work_done = 0;
struct netdev_queue *txq;
- txq = netdev_get_tx_queue(dev, qeth_iqd_translate_txq(dev, queue_no));
+ if (IS_IQD(card))
+ txq = netdev_get_tx_queue(dev, qeth_iqd_translate_txq(dev, queue_no));
+ else
+ txq = netdev_get_tx_queue(dev, queue_no);
while (1) {
unsigned int start, error, i;
@@ -6165,8 +6098,9 @@ static int qeth_tx_poll(struct napi_struct *napi, int budget)
&start, &error);
if (completed <= 0) {
/* Ensure we see TX completion for pending work: */
- if (napi_complete_done(napi, 0))
- qeth_tx_arm_timer(queue, QETH_TX_TIMER_USECS);
+ if (napi_complete_done(napi, 0) &&
+ !atomic_read(&queue->set_pci_flags_count))
+ qeth_tx_arm_timer(queue, queue->rescan_usecs);
return 0;
}
@@ -6179,12 +6113,19 @@ static int qeth_tx_poll(struct napi_struct *napi, int budget)
bytes += buffer->bytes;
qeth_handle_send_error(card, buffer, error);
- qeth_iqd_tx_complete(queue, bidx, error, budget);
+ if (IS_IQD(card))
+ qeth_iqd_tx_complete(queue, bidx, error, budget);
+ else
+ qeth_clear_output_buffer(queue, buffer, error,
+ budget);
}
- netdev_tx_completed_queue(txq, packets, bytes);
atomic_sub(completed, &queue->used_buffers);
work_done += completed;
+ if (IS_IQD(card))
+ netdev_tx_completed_queue(txq, packets, bytes);
+ else
+ qeth_check_outbound_queue(queue);
/* xmit may have observed the full-condition, but not yet
* stopped the txq. In which case the code below won't trigger.
@@ -7228,6 +7169,8 @@ EXPORT_SYMBOL_GPL(qeth_iqd_select_queue);
int qeth_open(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
+ struct qeth_qdio_out_q *queue;
+ unsigned int i;
QETH_CARD_TEXT(card, 4, "qethopen");
@@ -7235,16 +7178,11 @@ int qeth_open(struct net_device *dev)
netif_tx_start_all_queues(dev);
local_bh_disable();
- if (IS_IQD(card)) {
- struct qeth_qdio_out_q *queue;
- unsigned int i;
-
- qeth_for_each_output_queue(card, queue, i) {
- netif_tx_napi_add(dev, &queue->napi, qeth_tx_poll,
- QETH_NAPI_WEIGHT);
- napi_enable(&queue->napi);
- napi_schedule(&queue->napi);
- }
+ qeth_for_each_output_queue(card, queue, i) {
+ netif_tx_napi_add(dev, &queue->napi, qeth_tx_poll,
+ QETH_NAPI_WEIGHT);
+ napi_enable(&queue->napi);
+ napi_schedule(&queue->napi);
}
napi_enable(&card->napi);
@@ -7259,6 +7197,8 @@ EXPORT_SYMBOL_GPL(qeth_open);
int qeth_stop(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
+ struct qeth_qdio_out_q *queue;
+ unsigned int i;
QETH_CARD_TEXT(card, 4, "qethstop");
@@ -7266,24 +7206,17 @@ int qeth_stop(struct net_device *dev)
cancel_delayed_work_sync(&card->buffer_reclaim_work);
qdio_stop_irq(CARD_DDEV(card));
- if (IS_IQD(card)) {
- struct qeth_qdio_out_q *queue;
- unsigned int i;
-
- /* Quiesce the NAPI instances: */
- qeth_for_each_output_queue(card, queue, i)
- napi_disable(&queue->napi);
+ /* Quiesce the NAPI instances: */
+ qeth_for_each_output_queue(card, queue, i)
+ napi_disable(&queue->napi);
- /* Stop .ndo_start_xmit, might still access queue->napi. */
- netif_tx_disable(dev);
+ /* Stop .ndo_start_xmit, might still access queue->napi. */
+ netif_tx_disable(dev);
- qeth_for_each_output_queue(card, queue, i) {
- del_timer_sync(&queue->timer);
- /* Queues may get re-allocated, so remove the NAPIs. */
- netif_napi_del(&queue->napi);
- }
- } else {
- netif_tx_disable(dev);
+ qeth_for_each_output_queue(card, queue, i) {
+ del_timer_sync(&queue->timer);
+ /* Queues may get re-allocated, so remove the NAPIs. */
+ netif_napi_del(&queue->napi);
}
return 0;
diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c
index 3a51bbff0ffe..2c4cb300a8fc 100644
--- a/drivers/s390/net/qeth_ethtool.c
+++ b/drivers/s390/net/qeth_ethtool.c
@@ -41,6 +41,7 @@ static const struct qeth_stats txq_stats[] = {
QETH_TXQ_STAT("Queue stopped", stopped),
QETH_TXQ_STAT("Doorbell", doorbell),
QETH_TXQ_STAT("IRQ for frames", coal_frames),
+ QETH_TXQ_STAT("Completion IRQ", completion_irq),
QETH_TXQ_STAT("Completion yield", completion_yield),
QETH_TXQ_STAT("Completion timer", completion_timer),
};
@@ -79,10 +80,8 @@ static void qeth_add_stat_strings(u8 **data, const char *prefix,
{
unsigned int i;
- for (i = 0; i < size; i++) {
- snprintf(*data, ETH_GSTRING_LEN, "%s%s", prefix, stats[i].name);
- *data += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < size; i++)
+ ethtool_sprintf(data, "%s%s", prefix, stats[i].name);
}
static int qeth_get_sset_count(struct net_device *dev, int stringset)
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index ca44421a6d6e..2abf86c104d5 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -805,8 +805,6 @@ static int qeth_l2_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
if (!netif_device_present(dev))
return -ENODEV;
- if (!(priv->brport_hw_features))
- return -EOPNOTSUPP;
nlmsg_for_each_attr(attr, nlh, sizeof(struct ifinfomsg), rem1) {
if (nla_type(attr) == IFLA_PROTINFO) {
@@ -832,6 +830,16 @@ static int qeth_l2_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
return 0;
if (!bp_tb[IFLA_BRPORT_LEARNING_SYNC])
return -EINVAL;
+ if (!(priv->brport_hw_features & BR_LEARNING_SYNC)) {
+ NL_SET_ERR_MSG_ATTR(extack, bp_tb[IFLA_BRPORT_LEARNING_SYNC],
+ "Operation not supported by HW");
+ return -EOPNOTSUPP;
+ }
+ if (!IS_ENABLED(CONFIG_NET_SWITCHDEV)) {
+ NL_SET_ERR_MSG_ATTR(extack, bp_tb[IFLA_BRPORT_LEARNING_SYNC],
+ "Requires NET_SWITCHDEV");
+ return -EOPNOTSUPP;
+ }
enable = !!nla_get_u8(bp_tb[IFLA_BRPORT_LEARNING_SYNC]);
if (enable == !!(priv->brport_features & BR_LEARNING_SYNC))
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index d308ff744a29..f0d6f205c53c 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -434,6 +434,7 @@ static int qeth_l3_correct_routing_type(struct qeth_card *card,
if (qeth_is_ipafunc_supported(card, prot,
IPA_OSA_MC_ROUTER))
return 0;
+ goto out_inval;
default:
goto out_inval;
}
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index d58bf79892f2..9da9b2b2a580 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -856,10 +856,7 @@ void zfcp_scsi_set_prot(struct zfcp_adapter *adapter)
*/
void zfcp_scsi_dif_sense_error(struct scsi_cmnd *scmd, int ascq)
{
- scsi_build_sense_buffer(1, scmd->sense_buffer,
- ILLEGAL_REQUEST, 0x10, ascq);
- set_driver_byte(scmd, DRIVER_SENSE);
- scmd->result |= SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 1, ILLEGAL_REQUEST, 0x10, ascq);
set_host_byte(scmd, DID_SOFT_ERROR);
}
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index 544efd4c42f0..b8cd75a872ee 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -487,6 +487,7 @@ static ssize_t zfcp_sysfs_port_fc_security_show(struct device *dev,
if (0 == (status & ZFCP_STATUS_COMMON_OPEN) ||
0 == (status & ZFCP_STATUS_COMMON_UNBLOCKED) ||
0 == (status & ZFCP_STATUS_PORT_PHYS_OPEN) ||
+ 0 != (status & ZFCP_STATUS_PORT_LINK_TEST) ||
0 != (status & ZFCP_STATUS_COMMON_ERP_FAILED) ||
0 != (status & ZFCP_STATUS_COMMON_ACCESS_BOXED))
i = sprintf(buf, "unknown\n");
diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c
index 54e686dca6de..d35e7a3f7067 100644
--- a/drivers/s390/virtio/virtio_ccw.c
+++ b/drivers/s390/virtio/virtio_ccw.c
@@ -388,31 +388,6 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
ccw_device_dma_free(vcdev->cdev, thinint_area, sizeof(*thinint_area));
}
-static inline long __do_kvm_notify(struct subchannel_id schid,
- unsigned long queue_index,
- long cookie)
-{
- register unsigned long __nr asm("1") = KVM_S390_VIRTIO_CCW_NOTIFY;
- register struct subchannel_id __schid asm("2") = schid;
- register unsigned long __index asm("3") = queue_index;
- register long __rc asm("2");
- register long __cookie asm("4") = cookie;
-
- asm volatile ("diag 2,4,0x500\n"
- : "=d" (__rc) : "d" (__nr), "d" (__schid), "d" (__index),
- "d"(__cookie)
- : "memory", "cc");
- return __rc;
-}
-
-static inline long do_kvm_notify(struct subchannel_id schid,
- unsigned long queue_index,
- long cookie)
-{
- diag_stat_inc(DIAG_STAT_X500);
- return __do_kvm_notify(schid, queue_index, cookie);
-}
-
static bool virtio_ccw_kvm_notify(struct virtqueue *vq)
{
struct virtio_ccw_vq_info *info = vq->priv;
@@ -421,7 +396,10 @@ static bool virtio_ccw_kvm_notify(struct virtqueue *vq)
vcdev = to_vc_device(info->vq->vdev);
ccw_device_get_schid(vcdev->cdev, &schid);
- info->cookie = do_kvm_notify(schid, vq->index, info->cookie);
+ BUILD_BUG_ON(sizeof(struct subchannel_id) != sizeof(unsigned int));
+ info->cookie = kvm_hypercall3(KVM_S390_VIRTIO_CCW_NOTIFY,
+ *((unsigned int *)&schid),
+ vq->index, info->cookie);
if (info->cookie < 0)
return false;
return true;
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 47028f5e57ab..e41cc354cc8a 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -303,10 +303,10 @@ static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
/* Initialize sglist */
memset(&sglist, 0, sizeof(TW_SG_Entry));
- sglist[0].length = TW_SECTOR_SIZE;
- sglist[0].address = tw_dev->generic_buffer_phys[request_id];
+ sglist[0].length = cpu_to_le32(TW_SECTOR_SIZE);
+ sglist[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
- if (sglist[0].address & TW_ALIGNMENT_9000_SGL) {
+ if (tw_dev->generic_buffer_phys[request_id] & TW_ALIGNMENT_9000_SGL) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain");
goto out;
}
@@ -440,8 +440,8 @@ static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
/* Initialize sglist */
memset(&sglist, 0, sizeof(TW_SG_Entry));
- sglist[0].length = TW_SECTOR_SIZE;
- sglist[0].address = tw_dev->generic_buffer_phys[request_id];
+ sglist[0].length = cpu_to_le32(TW_SECTOR_SIZE);
+ sglist[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
/* Mark internal command */
tw_dev->srb[request_id] = NULL;
@@ -501,9 +501,8 @@ static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id)
Sunday 12:00AM */
local_time = (ktime_get_real_seconds() - (sys_tz.tz_minuteswest * 60));
div_u64_rem(local_time - (3 * 86400), 604800, &schedulertime);
- schedulertime = cpu_to_le32(schedulertime % 604800);
- memcpy(param->data, &schedulertime, sizeof(u32));
+ memcpy(param->data, &(__le32){cpu_to_le32(schedulertime)}, sizeof(__le32));
/* Mark internal command */
tw_dev->srb[request_id] = NULL;
@@ -676,7 +675,9 @@ static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long
data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;
/* Now allocate ioctl buf memory */
- cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle, GFP_KERNEL);
+ cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev,
+ sizeof(TW_Ioctl_Buf_Apache) + data_buffer_length_adjusted,
+ &dma_handle, GFP_KERNEL);
if (!cpu_addr) {
retval = TW_IOCTL_ERROR_OS_ENOMEM;
goto out2;
@@ -685,7 +686,7 @@ static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long
tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr;
/* Now copy down the entire ioctl */
- if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1))
+ if (copy_from_user(tw_ioctl, argp, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length))
goto out3;
/* See which ioctl we are doing */
@@ -867,11 +868,13 @@ static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long
}
/* Now copy the entire response to userspace */
- if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0)
+ if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length) == 0)
retval = 0;
out3:
/* Now free ioctl buf memory */
- dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
+ dma_free_coherent(&tw_dev->tw_pci_dev->dev,
+ sizeof(TW_Ioctl_Buf_Apache) + data_buffer_length_adjusted,
+ cpu_addr, dma_handle);
out2:
mutex_unlock(&tw_dev->ioctl_lock);
out:
@@ -1000,19 +1003,13 @@ static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_
if (print_host)
printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n",
tw_dev->host->host_no,
- TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
- full_command_packet->header.status_block.error,
- error_str[0] == '\0' ?
- twa_string_lookup(twa_error_table,
- full_command_packet->header.status_block.error) : error_str,
+ TW_MESSAGE_SOURCE_CONTROLLER_ERROR, error,
+ error_str[0] ? error_str : twa_string_lookup(twa_error_table, error),
full_command_packet->header.err_specific_desc);
else
printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n",
- TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
- full_command_packet->header.status_block.error,
- error_str[0] == '\0' ?
- twa_string_lookup(twa_error_table,
- full_command_packet->header.status_block.error) : error_str,
+ TW_MESSAGE_SOURCE_CONTROLLER_ERROR, error,
+ error_str[0] ? error_str : twa_string_lookup(twa_error_table, error),
full_command_packet->header.err_specific_desc);
}
@@ -1129,12 +1126,11 @@ static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION);
tw_initconnect->request_id = request_id;
tw_initconnect->message_credits = cpu_to_le16(message_credits);
- tw_initconnect->features = set_features;
/* Turn on 64-bit sgl support if we need to */
- tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0;
+ set_features |= sizeof(dma_addr_t) > 4 ? 1 : 0;
- tw_initconnect->features = cpu_to_le32(tw_initconnect->features);
+ tw_initconnect->features = cpu_to_le32(set_features);
if (set_features & TW_EXTENDED_INIT_CONNECT) {
tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;
@@ -1342,13 +1338,15 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance)
/* If error, command failed */
if (error == 1) {
/* Ask for a host reset */
- cmd->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+ cmd->result = (DID_OK << 16) | SAM_STAT_CHECK_CONDITION;
}
/* Report residual bytes for single sgl */
if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) {
- if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id]))
- scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length);
+ u32 length = le32_to_cpu(full_command_packet->command.newcommand.sg_list[0].length);
+
+ if (length < scsi_bufflen(cmd))
+ scsi_set_resid(cmd, scsi_bufflen(cmd) - length);
}
/* Now complete the io */
@@ -1390,13 +1388,13 @@ static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_comm
if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
newcommand = &full_command_packet->command.newcommand;
newcommand->request_id__lunl =
- cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id));
+ TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id);
if (length) {
- newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
+ newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache));
newcommand->sg_list[0].length = cpu_to_le32(length);
}
newcommand->sgl_entries__lunh =
- cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0));
+ TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0);
} else {
oldcommand = &full_command_packet->command.oldcommand;
oldcommand->request_id = request_id;
@@ -1407,7 +1405,7 @@ static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_comm
sgl = (TW_SG_Entry *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry)/4) + pae);
else
sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
- sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
+ sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache));
sgl->length = cpu_to_le32(length);
oldcommand->size += pae;
@@ -1831,10 +1829,10 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
if (srb) {
command_packet->unit = srb->device->id;
command_packet->request_id__lunl =
- cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id));
+ TW_REQ_LUN_IN(srb->device->lun, request_id);
} else {
command_packet->request_id__lunl =
- cpu_to_le16(TW_REQ_LUN_IN(0, request_id));
+ TW_REQ_LUN_IN(0, request_id);
command_packet->unit = 0;
}
@@ -1866,19 +1864,19 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
}
}
}
- command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id])));
+ command_packet->sgl_entries__lunh = TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id]));
}
} else {
/* Internal cdb post */
for (i = 0; i < use_sg; i++) {
- command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address);
- command_packet->sg_list[i].length = cpu_to_le32(sglistarg[i].length);
+ command_packet->sg_list[i].address = sglistarg[i].address;
+ command_packet->sg_list[i].length = sglistarg[i].length;
if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post");
goto out;
}
}
- command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg));
+ command_packet->sgl_entries__lunh = TW_REQ_LUN_IN(0, use_sg);
}
if (srb) {
@@ -2103,7 +2101,7 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH),
(char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE,
TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH),
- le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
+ le32_to_cpu(*(__le32 *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)));
/* Try to enable MSI */
diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h
index d3f479324527..0b23b0422e88 100644
--- a/drivers/scsi/3w-9xxx.h
+++ b/drivers/scsi/3w-9xxx.h
@@ -50,7 +50,7 @@
/* AEN string type */
typedef struct TAG_twa_message_type {
unsigned int code;
- char* text;
+ char *text;
} twa_message_type;
/* AEN strings */
@@ -435,8 +435,8 @@ static twa_message_type twa_error_table[] = {
/* request_id: 12, lun: 4 */
#define TW_REQ_LUN_IN(lun, request_id) \
- (((lun << 12) & 0xf000) | (request_id & 0xfff))
-#define TW_LUN_OUT(lun) ((lun >> 12) & 0xf)
+ cpu_to_le16(((lun << 12) & 0xf000) | (request_id & 0xfff))
+#define TW_LUN_OUT(lun) ((le16_to_cpu(lun) >> 12) & 0xf)
/* Macros */
#define TW_CONTROL_REG_ADDR(x) (x->base_addr)
@@ -483,70 +483,75 @@ printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s.\n",a,b,c); \
#define TW_APACHE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 72 : 109)
#define TW_ESCALADE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 41 : 62)
#define TW_PADDING_LENGTH (sizeof(dma_addr_t) > 4 ? 8 : 0)
-#define TW_CPU_TO_SGL(x) (sizeof(dma_addr_t) > 4 ? cpu_to_le64(x) : cpu_to_le32(x))
-#pragma pack(1)
+#if IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT)
+typedef __le64 twa_addr_t;
+#define TW_CPU_TO_SGL(x) cpu_to_le64(x)
+#else
+typedef __le32 twa_addr_t;
+#define TW_CPU_TO_SGL(x) cpu_to_le32(x)
+#endif
/* Scatter Gather List Entry */
typedef struct TAG_TW_SG_Entry {
- dma_addr_t address;
- u32 length;
-} TW_SG_Entry;
+ twa_addr_t address;
+ __le32 length;
+} __packed TW_SG_Entry;
/* Command Packet */
typedef struct TW_Command {
- unsigned char opcode__sgloffset;
- unsigned char size;
- unsigned char request_id;
- unsigned char unit__hostid;
+ u8 opcode__sgloffset;
+ u8 size;
+ u8 request_id;
+ u8 unit__hostid;
/* Second DWORD */
- unsigned char status;
- unsigned char flags;
+ u8 status;
+ u8 flags;
union {
- unsigned short block_count;
- unsigned short parameter_count;
+ __le16 block_count;
+ __le16 parameter_count;
} byte6_offset;
union {
struct {
- u32 lba;
- TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
- dma_addr_t padding;
+ __le32 lba;
+ TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
+ twa_addr_t padding;
} io;
struct {
- TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
- u32 padding;
- dma_addr_t padding2;
+ TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
+ __le32 padding;
+ twa_addr_t padding2;
} param;
} byte8_offset;
} TW_Command;
/* Command Packet for 9000+ controllers */
typedef struct TAG_TW_Command_Apache {
- unsigned char opcode__reserved;
- unsigned char unit;
- unsigned short request_id__lunl;
- unsigned char status;
- unsigned char sgl_offset;
- unsigned short sgl_entries__lunh;
- unsigned char cdb[16];
- TW_SG_Entry sg_list[TW_APACHE_MAX_SGL_LENGTH];
- unsigned char padding[TW_PADDING_LENGTH];
+ u8 opcode__reserved;
+ u8 unit;
+ __le16 request_id__lunl;
+ u8 status;
+ u8 sgl_offset;
+ __le16 sgl_entries__lunh;
+ u8 cdb[16];
+ TW_SG_Entry sg_list[TW_APACHE_MAX_SGL_LENGTH];
+ u8 padding[TW_PADDING_LENGTH];
} TW_Command_Apache;
/* New command packet header */
typedef struct TAG_TW_Command_Apache_Header {
unsigned char sense_data[TW_SENSE_DATA_LENGTH];
struct {
- char reserved[4];
- unsigned short error;
- unsigned char padding;
- unsigned char severity__reserved;
+ u8 reserved[4];
+ __le16 error;
+ u8 padding;
+ u8 severity__reserved;
} status_block;
unsigned char err_specific_desc[98];
struct {
- unsigned char size_header;
- unsigned short reserved;
- unsigned char size_sense;
+ u8 size_header;
+ u8 reserved[2];
+ u8 size_sense;
} header_desc;
} TW_Command_Apache_Header;
@@ -561,19 +566,19 @@ typedef struct TAG_TW_Command_Full {
/* Initconnection structure */
typedef struct TAG_TW_Initconnect {
- unsigned char opcode__reserved;
- unsigned char size;
- unsigned char request_id;
- unsigned char res2;
- unsigned char status;
- unsigned char flags;
- unsigned short message_credits;
- u32 features;
- unsigned short fw_srl;
- unsigned short fw_arch_id;
- unsigned short fw_branch;
- unsigned short fw_build;
- u32 result;
+ u8 opcode__reserved;
+ u8 size;
+ u8 request_id;
+ u8 res2;
+ u8 status;
+ u8 flags;
+ __le16 message_credits;
+ __le32 features;
+ __le16 fw_srl;
+ __le16 fw_arch_id;
+ __le16 fw_branch;
+ __le16 fw_build;
+ __le32 result;
} TW_Initconnect;
/* Event info structure */
@@ -602,7 +607,7 @@ typedef struct TAG_TW_Ioctl_Apache {
TW_Ioctl_Driver_Command driver_command;
char padding[488];
TW_Command_Full firmware_command;
- char data_buffer[1];
+ char data_buffer[];
} TW_Ioctl_Buf_Apache;
/* Lock structure for ioctl get/release lock */
@@ -614,11 +619,11 @@ typedef struct TAG_TW_Lock {
/* GetParam descriptor */
typedef struct {
- unsigned short table_id;
- unsigned short parameter_id;
- unsigned short parameter_size_bytes;
- unsigned short actual_parameter_size_bytes;
- unsigned char data[1];
+ __le16 table_id;
+ __le16 parameter_id;
+ __le16 parameter_size_bytes;
+ __le16 actual_parameter_size_bytes;
+ u8 data[];
} TW_Param_Apache, *PTW_Param_Apache;
/* Response queue */
@@ -645,8 +650,6 @@ typedef struct TAG_TW_Compatibility_Info
unsigned short fw_on_ctlr_build;
} TW_Compatibility_Info;
-#pragma pack()
-
typedef struct TAG_TW_Device_Extension {
u32 __iomem *base_addr;
unsigned long *generic_buffer_virt[TW_Q_LENGTH];
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index a7292883b72b..4ee485ab2714 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -429,7 +429,7 @@ static int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill
/* Additional sense code qualifier */
tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3];
- tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+ tw_dev->srb[request_id]->result = (DID_OK << 16) | SAM_STAT_CHECK_CONDITION;
return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */
}
}
@@ -1977,7 +1977,7 @@ static int tw_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_c
printk(KERN_NOTICE "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x\n", tw_dev->host->host_no, *command);
tw_dev->state[request_id] = TW_S_COMPLETED;
tw_state_request_finish(tw_dev, request_id);
- scsi_build_sense_buffer(1, SCpnt->sense_buffer, ILLEGAL_REQUEST, 0x20, 0);
+ scsi_build_sense(SCpnt, 1, ILLEGAL_REQUEST, 0x20, 0);
done(SCpnt);
retval = 0;
}
@@ -2159,7 +2159,7 @@ static irqreturn_t tw_interrupt(int irq, void *dev_instance)
/* If error, command failed */
if (error == 1) {
/* Ask for a host reset */
- tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+ tw_dev->srb[request_id]->result = (DID_OK << 16) | SAM_STAT_CHECK_CONDITION;
}
/* Now complete the io */
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index 77ccb96e5ed4..1c6b4e672687 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -978,10 +978,10 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
if (NCR_700_get_tag_neg_state(SCp->device) == NCR_700_DURING_TAG_NEGOTIATION)
NCR_700_set_tag_neg_state(SCp->device,
NCR_700_FINISHED_TAG_NEGOTIATION);
-
+
/* check for contingent allegiance conditions */
- if (hostdata->status[0] >> 1 == CHECK_CONDITION ||
- hostdata->status[0] >> 1 == COMMAND_TERMINATED) {
+ if (hostdata->status[0] == SAM_STAT_CHECK_CONDITION ||
+ hostdata->status[0] == SAM_STAT_COMMAND_TERMINATED) {
struct NCR_700_command_slot *slot =
(struct NCR_700_command_slot *)SCp->host_scribble;
if(slot->flags == NCR_700_FLAG_AUTOSENSE) {
diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c
index 0464e37c806a..90253208a72f 100644
--- a/drivers/scsi/FlashPoint.c
+++ b/drivers/scsi/FlashPoint.c
@@ -40,7 +40,7 @@ struct sccb_mgr_info {
u16 si_per_targ_ultra_nego;
u16 si_per_targ_no_disc;
u16 si_per_targ_wide_nego;
- u16 si_flags;
+ u16 si_mflags;
unsigned char si_card_family;
unsigned char si_bustype;
unsigned char si_card_model[3];
@@ -304,40 +304,12 @@ typedef struct SCCBscam_info {
} SCCBSCAM_INFO;
-#define SCSI_REQUEST_SENSE 0x03
-#define SCSI_READ 0x08
-#define SCSI_WRITE 0x0A
-#define SCSI_START_STOP_UNIT 0x1B
-#define SCSI_READ_EXTENDED 0x28
-#define SCSI_WRITE_EXTENDED 0x2A
-#define SCSI_WRITE_AND_VERIFY 0x2E
-
-#define SSGOOD 0x00
-#define SSCHECK 0x02
-#define SSQ_FULL 0x28
-
-#define SMCMD_COMP 0x00
-#define SMEXT 0x01
-#define SMSAVE_DATA_PTR 0x02
-#define SMREST_DATA_PTR 0x03
-#define SMDISC 0x04
-#define SMABORT 0x06
-#define SMREJECT 0x07
-#define SMNO_OP 0x08
-#define SMPARITY 0x09
-#define SMDEV_RESET 0x0C
-#define SMABORT_TAG 0x0D
-#define SMINIT_RECOVERY 0x0F
-#define SMREL_RECOVERY 0x10
#define SMIDENT 0x80
#define DISC_PRIV 0x40
-#define SMSYNC 0x01
-#define SMWDTR 0x03
#define SM8BIT 0x00
#define SM16BIT 0x01
-#define SMIGNORWR 0x23 /* Ignore Wide Residue */
#define SIX_BYTE_CMD 0x06
#define TWELVE_BYTE_CMD 0x0C
@@ -1073,22 +1045,22 @@ static int FlashPoint_ProbeHostAdapter(struct sccb_mgr_info *pCardInfo)
ScamFlg =
(unsigned char)FPT_utilEERead(ioport, SCAM_CONFIG / 2);
- pCardInfo->si_flags = 0x0000;
+ pCardInfo->si_mflags = 0x0000;
if (i & 0x01)
- pCardInfo->si_flags |= SCSI_PARITY_ENA;
+ pCardInfo->si_mflags |= SCSI_PARITY_ENA;
if (!(i & 0x02))
- pCardInfo->si_flags |= SOFT_RESET;
+ pCardInfo->si_mflags |= SOFT_RESET;
if (i & 0x10)
- pCardInfo->si_flags |= EXTENDED_TRANSLATION;
+ pCardInfo->si_mflags |= EXTENDED_TRANSLATION;
if (ScamFlg & SCAM_ENABLED)
- pCardInfo->si_flags |= FLAG_SCAM_ENABLED;
+ pCardInfo->si_mflags |= FLAG_SCAM_ENABLED;
if (ScamFlg & SCAM_LEVEL2)
- pCardInfo->si_flags |= FLAG_SCAM_LEVEL2;
+ pCardInfo->si_mflags |= FLAG_SCAM_LEVEL2;
j = (RD_HARPOON(ioport + hp_bm_ctrl) & ~SCSI_TERM_ENA_L);
if (i & 0x04) {
@@ -1104,7 +1076,7 @@ static int FlashPoint_ProbeHostAdapter(struct sccb_mgr_info *pCardInfo)
if (!(RD_HARPOON(ioport + hp_page_ctrl) & NARROW_SCSI_CARD))
- pCardInfo->si_flags |= SUPPORT_16TAR_32LUN;
+ pCardInfo->si_mflags |= SUPPORT_16TAR_32LUN;
pCardInfo->si_card_family = HARPOON_FAMILY;
pCardInfo->si_bustype = BUSTYPE_PCI;
@@ -1140,15 +1112,15 @@ static int FlashPoint_ProbeHostAdapter(struct sccb_mgr_info *pCardInfo)
if (pCardInfo->si_card_model[1] == '3') {
if (RD_HARPOON(ioport + hp_ee_ctrl) & BIT(7))
- pCardInfo->si_flags |= LOW_BYTE_TERM;
+ pCardInfo->si_mflags |= LOW_BYTE_TERM;
} else if (pCardInfo->si_card_model[2] == '0') {
temp = RD_HARPOON(ioport + hp_xfer_pad);
WR_HARPOON(ioport + hp_xfer_pad, (temp & ~BIT(4)));
if (RD_HARPOON(ioport + hp_ee_ctrl) & BIT(7))
- pCardInfo->si_flags |= LOW_BYTE_TERM;
+ pCardInfo->si_mflags |= LOW_BYTE_TERM;
WR_HARPOON(ioport + hp_xfer_pad, (temp | BIT(4)));
if (RD_HARPOON(ioport + hp_ee_ctrl) & BIT(7))
- pCardInfo->si_flags |= HIGH_BYTE_TERM;
+ pCardInfo->si_mflags |= HIGH_BYTE_TERM;
WR_HARPOON(ioport + hp_xfer_pad, temp);
} else {
temp = RD_HARPOON(ioport + hp_ee_ctrl);
@@ -1166,9 +1138,9 @@ static int FlashPoint_ProbeHostAdapter(struct sccb_mgr_info *pCardInfo)
WR_HARPOON(ioport + hp_ee_ctrl, temp);
WR_HARPOON(ioport + hp_xfer_pad, temp2);
if (!(temp3 & BIT(7)))
- pCardInfo->si_flags |= LOW_BYTE_TERM;
+ pCardInfo->si_mflags |= LOW_BYTE_TERM;
if (!(temp3 & BIT(6)))
- pCardInfo->si_flags |= HIGH_BYTE_TERM;
+ pCardInfo->si_mflags |= HIGH_BYTE_TERM;
}
ARAM_ACCESS(ioport);
@@ -1275,7 +1247,7 @@ static void *FlashPoint_HardwareResetHostAdapter(struct sccb_mgr_info
WR_HARPOON(ioport + hp_arb_id, pCardInfo->si_id);
CurrCard->ourId = pCardInfo->si_id;
- i = (unsigned char)pCardInfo->si_flags;
+ i = (unsigned char)pCardInfo->si_mflags;
if (i & SCSI_PARITY_ENA)
WR_HARPOON(ioport + hp_portctrl_1, (HOST_MODE8 | CHK_SCSI_P));
@@ -1289,14 +1261,14 @@ static void *FlashPoint_HardwareResetHostAdapter(struct sccb_mgr_info
j |= SCSI_TERM_ENA_H;
WR_HARPOON(ioport + hp_ee_ctrl, j);
- if (!(pCardInfo->si_flags & SOFT_RESET)) {
+ if (!(pCardInfo->si_mflags & SOFT_RESET)) {
FPT_sresb(ioport, thisCard);
FPT_scini(thisCard, pCardInfo->si_id, 0);
}
- if (pCardInfo->si_flags & POST_ALL_UNDERRRUNS)
+ if (pCardInfo->si_mflags & POST_ALL_UNDERRRUNS)
CurrCard->globalFlags |= F_NO_FILTER;
if (pCurrNvRam) {
@@ -1660,7 +1632,7 @@ static int FlashPoint_AbortCCB(void *pCurrCard, struct sccb *p_Sccb)
p_Sccb->Sccb_scsistat =
ABORT_ST;
p_Sccb->Sccb_scsimsg =
- SMABORT_TAG;
+ ABORT_TASK;
if (((struct sccb_card *)
pCurrCard)->currentSCCB ==
@@ -1812,7 +1784,7 @@ static int FlashPoint_HandleInterrupt(void *pcard)
FPT_phaseChkFifo(ioport, thisCard);
if (RD_HARPOON(ioport + hp_gp_reg_1) ==
- SMSAVE_DATA_PTR) {
+ SAVE_POINTERS) {
WR_HARPOON(ioport + hp_gp_reg_1, 0x00);
currSCCB->Sccb_XferState |= F_NO_DATA_YET;
@@ -1865,7 +1837,7 @@ static int FlashPoint_HandleInterrupt(void *pcard)
FPT_phaseChkFifo(ioport, thisCard);
if (RD_HARPOON(ioport + hp_gp_reg_1) ==
- SMSAVE_DATA_PTR) {
+ SAVE_POINTERS) {
WR_HARPOON(ioport + hp_gp_reg_1, 0x00);
currSCCB->Sccb_XferState |=
F_NO_DATA_YET;
@@ -2258,7 +2230,7 @@ static unsigned char FPT_sfm(u32 port, struct sccb *pCurrSCCB)
WR_HARPOON(port + hp_fiforead, 0);
WR_HARPOON(port + hp_fifowrite, 0);
if (pCurrSCCB != NULL) {
- pCurrSCCB->Sccb_scsimsg = SMPARITY;
+ pCurrSCCB->Sccb_scsimsg = MSG_PARITY_ERROR;
}
message = 0x00;
do {
@@ -2411,7 +2383,7 @@ static void FPT_ssel(u32 port, unsigned char p_card)
WRW_HARPOON((port + ID_MSG_STRT + 2), BRH_OP + ALWAYS + NP);
- currSCCB->Sccb_scsimsg = SMDEV_RESET;
+ currSCCB->Sccb_scsimsg = TARGET_RESET;
WR_HARPOON(port + hp_autostart_3, (SELECT + SELCHK_STRT));
auto_loaded = 1;
@@ -2758,9 +2730,9 @@ static void FPT_sres(u32 port, unsigned char p_card,
if (message == 0) {
msgRetryCount++;
if (msgRetryCount == 1) {
- FPT_SendMsg(port, SMPARITY);
+ FPT_SendMsg(port, MSG_PARITY_ERROR);
} else {
- FPT_SendMsg(port, SMDEV_RESET);
+ FPT_SendMsg(port, TARGET_RESET);
FPT_sssyncv(port, our_target, NARROW_SCSI,
currTar_Info);
@@ -2860,8 +2832,8 @@ static void FPT_SendMsg(u32 port, unsigned char message)
WR_HARPOON(port + hp_portctrl_0, 0x00);
- if ((message == SMABORT) || (message == SMDEV_RESET) ||
- (message == SMABORT_TAG)) {
+ if ((message == ABORT_TASK_SET) || (message == TARGET_RESET) ||
+ (message == ABORT_TASK)) {
while (!
(RDW_HARPOON((port + hp_intstat)) &
(BUS_FREE | PHASE))) {
@@ -2893,7 +2865,7 @@ static void FPT_sdecm(unsigned char message, u32 port, unsigned char p_card)
currTar_Info = &FPT_sccbMgrTbl[p_card][currSCCB->TargID];
- if (message == SMREST_DATA_PTR) {
+ if (message == RESTORE_POINTERS) {
if (!(currSCCB->Sccb_XferState & F_NO_DATA_YET)) {
currSCCB->Sccb_ATC = currSCCB->Sccb_savedATC;
@@ -2905,7 +2877,7 @@ static void FPT_sdecm(unsigned char message, u32 port, unsigned char p_card)
(AUTO_IMMED + DISCONNECT_START));
}
- else if (message == SMCMD_COMP) {
+ else if (message == COMMAND_COMPLETE) {
if (currSCCB->Sccb_scsistat == SELECT_Q_ST) {
currTar_Info->TarStatus &=
@@ -2917,15 +2889,16 @@ static void FPT_sdecm(unsigned char message, u32 port, unsigned char p_card)
}
- else if ((message == SMNO_OP) || (message >= SMIDENT)
- || (message == SMINIT_RECOVERY) || (message == SMREL_RECOVERY)) {
+ else if ((message == NOP) || (message >= IDENTIFY_BASE) ||
+ (message == INITIATE_RECOVERY) ||
+ (message == RELEASE_RECOVERY)) {
ACCEPT_MSG(port);
WR_HARPOON(port + hp_autostart_1,
(AUTO_IMMED + DISCONNECT_START));
}
- else if (message == SMREJECT) {
+ else if (message == MESSAGE_REJECT) {
if ((currSCCB->Sccb_scsistat == SELECT_SN_ST) ||
(currSCCB->Sccb_scsistat == SELECT_WN_ST) ||
@@ -3026,19 +2999,19 @@ static void FPT_sdecm(unsigned char message, u32 port, unsigned char p_card)
}
}
- else if (message == SMEXT) {
+ else if (message == EXTENDED_MESSAGE) {
ACCEPT_MSG(port);
FPT_shandem(port, p_card, currSCCB);
}
- else if (message == SMIGNORWR) {
+ else if (message == IGNORE_WIDE_RESIDUE) {
ACCEPT_MSG(port); /* ACK the RESIDUE MSG */
message = FPT_sfm(port, currSCCB);
- if (currSCCB->Sccb_scsimsg != SMPARITY)
+ if (currSCCB->Sccb_scsimsg != MSG_PARITY_ERROR)
ACCEPT_MSG(port);
WR_HARPOON(port + hp_autostart_1,
(AUTO_IMMED + DISCONNECT_START));
@@ -3047,7 +3020,7 @@ static void FPT_sdecm(unsigned char message, u32 port, unsigned char p_card)
else {
currSCCB->HostStatus = SCCB_PHASE_SEQUENCE_FAIL;
- currSCCB->Sccb_scsimsg = SMREJECT;
+ currSCCB->Sccb_scsimsg = MESSAGE_REJECT;
ACCEPT_MSG_ATN(port);
WR_HARPOON(port + hp_autostart_1,
@@ -3073,7 +3046,7 @@ static void FPT_shandem(u32 port, unsigned char p_card, struct sccb *pCurrSCCB)
message = FPT_sfm(port, pCurrSCCB);
if (message) {
- if (message == SMSYNC) {
+ if (message == EXTENDED_SDTR) {
if (length == 0x03) {
@@ -3081,10 +3054,10 @@ static void FPT_shandem(u32 port, unsigned char p_card, struct sccb *pCurrSCCB)
FPT_stsyncn(port, p_card);
} else {
- pCurrSCCB->Sccb_scsimsg = SMREJECT;
+ pCurrSCCB->Sccb_scsimsg = MESSAGE_REJECT;
ACCEPT_MSG_ATN(port);
}
- } else if (message == SMWDTR) {
+ } else if (message == EXTENDED_WDTR) {
if (length == 0x02) {
@@ -3092,7 +3065,7 @@ static void FPT_shandem(u32 port, unsigned char p_card, struct sccb *pCurrSCCB)
FPT_stwidn(port, p_card);
} else {
- pCurrSCCB->Sccb_scsimsg = SMREJECT;
+ pCurrSCCB->Sccb_scsimsg = MESSAGE_REJECT;
ACCEPT_MSG_ATN(port);
WR_HARPOON(port + hp_autostart_1,
@@ -3101,20 +3074,20 @@ static void FPT_shandem(u32 port, unsigned char p_card, struct sccb *pCurrSCCB)
}
} else {
- pCurrSCCB->Sccb_scsimsg = SMREJECT;
+ pCurrSCCB->Sccb_scsimsg = MESSAGE_REJECT;
ACCEPT_MSG_ATN(port);
WR_HARPOON(port + hp_autostart_1,
(AUTO_IMMED + DISCONNECT_START));
}
} else {
- if (pCurrSCCB->Sccb_scsimsg != SMPARITY)
+ if (pCurrSCCB->Sccb_scsimsg != MSG_PARITY_ERROR)
ACCEPT_MSG(port);
WR_HARPOON(port + hp_autostart_1,
(AUTO_IMMED + DISCONNECT_START));
}
} else {
- if (pCurrSCCB->Sccb_scsimsg == SMPARITY)
+ if (pCurrSCCB->Sccb_scsimsg == MSG_PARITY_ERROR)
WR_HARPOON(port + hp_autostart_1,
(AUTO_IMMED + DISCONNECT_START));
}
@@ -3148,10 +3121,10 @@ static unsigned char FPT_sisyncn(u32 port, unsigned char p_card,
WRW_HARPOON((port + ID_MSG_STRT + 2), BRH_OP + ALWAYS + CMDPZ);
WRW_HARPOON((port + SYNC_MSGS + 0),
- (MPM_OP + AMSG_OUT + SMEXT));
+ (MPM_OP + AMSG_OUT + EXTENDED_MESSAGE));
WRW_HARPOON((port + SYNC_MSGS + 2), (MPM_OP + AMSG_OUT + 0x03));
WRW_HARPOON((port + SYNC_MSGS + 4),
- (MPM_OP + AMSG_OUT + SMSYNC));
+ (MPM_OP + AMSG_OUT + EXTENDED_SDTR));
if ((currTar_Info->TarEEValue & EE_SYNC_MASK) == EE_SYNC_20MB)
@@ -3221,7 +3194,7 @@ static void FPT_stsyncn(u32 port, unsigned char p_card)
sync_msg = FPT_sfm(port, currSCCB);
- if ((sync_msg == 0x00) && (currSCCB->Sccb_scsimsg == SMPARITY)) {
+ if ((sync_msg == 0x00) && (currSCCB->Sccb_scsimsg == MSG_PARITY_ERROR)) {
WR_HARPOON(port + hp_autostart_1,
(AUTO_IMMED + DISCONNECT_START));
return;
@@ -3231,7 +3204,7 @@ static void FPT_stsyncn(u32 port, unsigned char p_card)
offset = FPT_sfm(port, currSCCB);
- if ((offset == 0x00) && (currSCCB->Sccb_scsimsg == SMPARITY)) {
+ if ((offset == 0x00) && (currSCCB->Sccb_scsimsg == MSG_PARITY_ERROR)) {
WR_HARPOON(port + hp_autostart_1,
(AUTO_IMMED + DISCONNECT_START));
return;
@@ -3343,9 +3316,11 @@ static void FPT_sisyncr(u32 port, unsigned char sync_pulse,
unsigned char offset)
{
ARAM_ACCESS(port);
- WRW_HARPOON((port + SYNC_MSGS + 0), (MPM_OP + AMSG_OUT + SMEXT));
+ WRW_HARPOON((port + SYNC_MSGS + 0),
+ (MPM_OP + AMSG_OUT + EXTENDED_MESSAGE));
WRW_HARPOON((port + SYNC_MSGS + 2), (MPM_OP + AMSG_OUT + 0x03));
- WRW_HARPOON((port + SYNC_MSGS + 4), (MPM_OP + AMSG_OUT + SMSYNC));
+ WRW_HARPOON((port + SYNC_MSGS + 4),
+ (MPM_OP + AMSG_OUT + EXTENDED_SDTR));
WRW_HARPOON((port + SYNC_MSGS + 6), (MPM_OP + AMSG_OUT + sync_pulse));
WRW_HARPOON((port + SYNC_MSGS + 8), (RAT_OP));
WRW_HARPOON((port + SYNC_MSGS + 10), (MPM_OP + AMSG_OUT + offset));
@@ -3388,10 +3363,10 @@ static unsigned char FPT_siwidn(u32 port, unsigned char p_card)
WRW_HARPOON((port + ID_MSG_STRT + 2), BRH_OP + ALWAYS + CMDPZ);
WRW_HARPOON((port + SYNC_MSGS + 0),
- (MPM_OP + AMSG_OUT + SMEXT));
+ (MPM_OP + AMSG_OUT + EXTENDED_MESSAGE));
WRW_HARPOON((port + SYNC_MSGS + 2), (MPM_OP + AMSG_OUT + 0x02));
WRW_HARPOON((port + SYNC_MSGS + 4),
- (MPM_OP + AMSG_OUT + SMWDTR));
+ (MPM_OP + AMSG_OUT + EXTENDED_WDTR));
WRW_HARPOON((port + SYNC_MSGS + 6), (RAT_OP));
WRW_HARPOON((port + SYNC_MSGS + 8),
(MPM_OP + AMSG_OUT + SM16BIT));
@@ -3436,7 +3411,7 @@ static void FPT_stwidn(u32 port, unsigned char p_card)
width = FPT_sfm(port, currSCCB);
- if ((width == 0x00) && (currSCCB->Sccb_scsimsg == SMPARITY)) {
+ if ((width == 0x00) && (currSCCB->Sccb_scsimsg == MSG_PARITY_ERROR)) {
WR_HARPOON(port + hp_autostart_1,
(AUTO_IMMED + DISCONNECT_START));
return;
@@ -3499,9 +3474,11 @@ static void FPT_stwidn(u32 port, unsigned char p_card)
static void FPT_siwidr(u32 port, unsigned char width)
{
ARAM_ACCESS(port);
- WRW_HARPOON((port + SYNC_MSGS + 0), (MPM_OP + AMSG_OUT + SMEXT));
+ WRW_HARPOON((port + SYNC_MSGS + 0),
+ (MPM_OP + AMSG_OUT + EXTENDED_MESSAGE));
WRW_HARPOON((port + SYNC_MSGS + 2), (MPM_OP + AMSG_OUT + 0x02));
- WRW_HARPOON((port + SYNC_MSGS + 4), (MPM_OP + AMSG_OUT + SMWDTR));
+ WRW_HARPOON((port + SYNC_MSGS + 4),
+ (MPM_OP + AMSG_OUT + EXTENDED_WDTR));
WRW_HARPOON((port + SYNC_MSGS + 6), (RAT_OP));
WRW_HARPOON((port + SYNC_MSGS + 8), (MPM_OP + AMSG_OUT + width));
WRW_HARPOON((port + SYNC_MSGS + 10), (BRH_OP + ALWAYS + NP));
@@ -3682,7 +3659,7 @@ static void FPT_ssenss(struct sccb_card *pCurrCard)
}
currSCCB->CdbLength = SIX_BYTE_CMD;
- currSCCB->Cdb[0] = SCSI_REQUEST_SENSE;
+ currSCCB->Cdb[0] = REQUEST_SENSE;
currSCCB->Cdb[1] = currSCCB->Cdb[1] & (unsigned char)0xE0; /*Keep LUN. */
currSCCB->Cdb[2] = 0x00;
currSCCB->Cdb[3] = 0x00;
@@ -3939,13 +3916,9 @@ static void FPT_sinits(struct sccb *p_sccb, unsigned char p_card)
*/
if ((currTar_Info->TarStatus & TAR_ALLOW_DISC) ||
(currTar_Info->TarStatus & TAG_Q_TRYING)) {
- p_sccb->Sccb_idmsg =
- (unsigned char)(SMIDENT | DISC_PRIV) | p_sccb->Lun;
- }
-
- else {
-
- p_sccb->Sccb_idmsg = (unsigned char)SMIDENT | p_sccb->Lun;
+ p_sccb->Sccb_idmsg = IDENTIFY(true, p_sccb->Lun);
+ } else {
+ p_sccb->Sccb_idmsg = IDENTIFY(false, p_sccb->Lun);
}
p_sccb->HostStatus = 0x00;
@@ -3962,7 +3935,7 @@ static void FPT_sinits(struct sccb *p_sccb, unsigned char p_card)
*/
p_sccb->Sccb_scsistat = BUS_FREE_ST;
p_sccb->SccbStatus = SCCB_IN_PROCESS;
- p_sccb->Sccb_scsimsg = SMNO_OP;
+ p_sccb->Sccb_scsimsg = NOP;
}
@@ -4167,7 +4140,7 @@ static void FPT_phaseMsgOut(u32 port, unsigned char p_card)
message = currSCCB->Sccb_scsimsg;
scsiID = currSCCB->TargID;
- if (message == SMDEV_RESET) {
+ if (message == TARGET_RESET) {
currTar_Info = &FPT_sccbMgrTbl[p_card][scsiID];
currTar_Info->TarSyncCtrl = 0;
@@ -4203,7 +4176,7 @@ static void FPT_phaseMsgOut(u32 port, unsigned char p_card)
else if (currSCCB->Sccb_scsistat < COMMAND_ST) {
- if (message == SMNO_OP) {
+ if (message == NOP) {
currSCCB->Sccb_MGRFlags |= F_DEV_SELECTED;
FPT_ssel(port, p_card);
@@ -4211,13 +4184,13 @@ static void FPT_phaseMsgOut(u32 port, unsigned char p_card)
}
} else {
- if (message == SMABORT)
+ if (message == ABORT_TASK_SET)
FPT_queueFlushSccb(p_card, SCCB_COMPLETE);
}
} else {
- message = SMABORT;
+ message = ABORT_TASK_SET;
}
WRW_HARPOON((port + hp_intstat), (BUS_FREE | PHASE | XFER_CNT_0));
@@ -4232,8 +4205,8 @@ static void FPT_phaseMsgOut(u32 port, unsigned char p_card)
WR_HARPOON(port + hp_portctrl_0, 0x00);
- if ((message == SMABORT) || (message == SMDEV_RESET) ||
- (message == SMABORT_TAG)) {
+ if ((message == ABORT_TASK_SET) || (message == TARGET_RESET) ||
+ (message == ABORT_TASK)) {
while (!(RDW_HARPOON((port + hp_intstat)) & (BUS_FREE | PHASE))) {
}
@@ -4275,8 +4248,8 @@ static void FPT_phaseMsgOut(u32 port, unsigned char p_card)
else {
- if (message == SMPARITY) {
- currSCCB->Sccb_scsimsg = SMNO_OP;
+ if (message == MSG_PARITY_ERROR) {
+ currSCCB->Sccb_scsimsg = NOP;
WR_HARPOON(port + hp_autostart_1,
(AUTO_IMMED + DISCONNECT_START));
} else {
@@ -4306,7 +4279,7 @@ static void FPT_phaseMsgIn(u32 port, unsigned char p_card)
}
message = RD_HARPOON(port + hp_scsidata_0);
- if ((message == SMDISC) || (message == SMSAVE_DATA_PTR)) {
+ if ((message == DISCONNECT) || (message == SAVE_POINTERS)) {
WR_HARPOON(port + hp_autostart_1,
(AUTO_IMMED + END_DATA_START));
@@ -4321,7 +4294,7 @@ static void FPT_phaseMsgIn(u32 port, unsigned char p_card)
FPT_sdecm(message, port, p_card);
} else {
- if (currSCCB->Sccb_scsimsg != SMPARITY)
+ if (currSCCB->Sccb_scsimsg != MSG_PARITY_ERROR)
ACCEPT_MSG(port);
WR_HARPOON(port + hp_autostart_1,
(AUTO_IMMED + DISCONNECT_START));
@@ -4351,7 +4324,7 @@ static void FPT_phaseIllegal(u32 port, unsigned char p_card)
currSCCB->HostStatus = SCCB_PHASE_SEQUENCE_FAIL;
currSCCB->Sccb_scsistat = ABORT_ST;
- currSCCB->Sccb_scsimsg = SMABORT;
+ currSCCB->Sccb_scsimsg = ABORT_TASK_SET;
}
ACCEPT_MSG_ATN(port);
@@ -4650,9 +4623,9 @@ static void FPT_autoCmdCmplt(u32 p_port, unsigned char p_card)
FPT_sccbMgrTbl[p_card][currSCCB->TargID].TarLUN_CA = 0;
- if (status_byte != SSGOOD) {
+ if (status_byte != SAM_STAT_GOOD) {
- if (status_byte == SSQ_FULL) {
+ if (status_byte == SAM_STAT_TASK_SET_FULL) {
if (((FPT_BL_Card[p_card].globalFlags & F_CONLUN_IO) &&
((FPT_sccbMgrTbl[p_card][currSCCB->TargID].
@@ -4784,7 +4757,7 @@ static void FPT_autoCmdCmplt(u32 p_port, unsigned char p_card)
}
- if (status_byte == SSCHECK) {
+ if (status_byte == SAM_STAT_CHECK_CONDITION) {
if (FPT_BL_Card[p_card].globalFlags & F_DO_RENEGO) {
if (FPT_sccbMgrTbl[p_card][currSCCB->TargID].
TarEEValue & EE_SYNC_MASK) {
@@ -4806,7 +4779,7 @@ static void FPT_autoCmdCmplt(u32 p_port, unsigned char p_card)
currSCCB->SccbStatus = SCCB_ERROR;
currSCCB->TargetStatus = status_byte;
- if (status_byte == SSCHECK) {
+ if (status_byte == SAM_STAT_CHECK_CONDITION) {
FPT_sccbMgrTbl[p_card][currSCCB->TargID].
TarLUN_CA = 1;
@@ -6868,14 +6841,14 @@ static void FPT_queueCmdComplete(struct sccb_card *pCurrCard,
if ((p_sccb->
ControlByte & (SCCB_DATA_XFER_OUT | SCCB_DATA_XFER_IN))
&& (p_sccb->HostStatus == SCCB_COMPLETE)
- && (p_sccb->TargetStatus != SSCHECK))
-
- if ((SCSIcmd == SCSI_READ) ||
- (SCSIcmd == SCSI_WRITE) ||
- (SCSIcmd == SCSI_READ_EXTENDED) ||
- (SCSIcmd == SCSI_WRITE_EXTENDED) ||
- (SCSIcmd == SCSI_WRITE_AND_VERIFY) ||
- (SCSIcmd == SCSI_START_STOP_UNIT) ||
+ && (p_sccb->TargetStatus != SAM_STAT_CHECK_CONDITION))
+
+ if ((SCSIcmd == READ_6) ||
+ (SCSIcmd == WRITE_6) ||
+ (SCSIcmd == READ_10) ||
+ (SCSIcmd == WRITE_10) ||
+ (SCSIcmd == WRITE_VERIFY) ||
+ (SCSIcmd == START_STOP) ||
(pCurrCard->globalFlags & F_NO_FILTER)
)
p_sccb->HostStatus = SCCB_DATA_UNDER_RUN;
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 3d114be5b662..8f44d433e06e 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -311,7 +311,7 @@ source "drivers/scsi/cxlflash/Kconfig"
config SGIWD93_SCSI
tristate "SGI WD93C93 SCSI Driver"
depends on SGI_HAS_WD93 && SCSI
- help
+ help
If you have a Western Digital WD93 SCSI controller on
an SGI MIPS system, say Y. Otherwise, say N.
@@ -482,6 +482,7 @@ config SCSI_ARCMSR
source "drivers/scsi/esas2r/Kconfig"
source "drivers/scsi/megaraid/Kconfig.megaraid"
source "drivers/scsi/mpt3sas/Kconfig"
+source "drivers/scsi/mpi3mr/Kconfig"
source "drivers/scsi/smartpqi/Kconfig"
source "drivers/scsi/ufs/Kconfig"
@@ -1157,6 +1158,8 @@ config SCSI_LPFC_DEBUG_FS
This makes debugging information from the lpfc driver
available via the debugfs filesystem.
+source "drivers/scsi/elx/Kconfig"
+
config SCSI_SIM710
tristate "Simple 53c710 SCSI support (Compaq, NCR machines)"
depends on EISA && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index bc3882f5cc69..1748d1ec1338 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/
obj-$(CONFIG_SCSI_QLA_ISCSI) += libiscsi.o qla4xxx/
obj-$(CONFIG_SCSI_LPFC) += lpfc/
+obj-$(CONFIG_SCSI_EFCT) += elx/
obj-$(CONFIG_SCSI_BFA_FC) += bfa/
obj-$(CONFIG_SCSI_CHELSIO_FCOE) += csiostor/
obj-$(CONFIG_SCSI_DMX3191D) += dmx3191d.o
@@ -99,6 +100,7 @@ obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o
obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/
obj-$(CONFIG_MEGARAID_SAS) += megaraid/
obj-$(CONFIG_SCSI_MPT3SAS) += mpt3sas/
+obj-$(CONFIG_SCSI_MPI3MR) += mpi3mr/
obj-$(CONFIG_SCSI_UFSHCD) += ufs/
obj-$(CONFIG_SCSI_ACARD) += atp870u.o
obj-$(CONFIG_SCSI_SUNESP) += esp_scsi.o sun_esp.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 2ddbcaa667d1..3baadd068768 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -538,11 +538,11 @@ static void complete_cmd(struct Scsi_Host *instance,
if (hostdata->sensing == cmd) {
/* Autosense processing ends here */
- if (status_byte(cmd->result) != GOOD) {
+ if (get_status_byte(cmd) != SAM_STAT_GOOD) {
scsi_eh_restore_cmnd(cmd, &hostdata->ses);
} else {
scsi_eh_restore_cmnd(cmd, &hostdata->ses);
- set_driver_byte(cmd, DRIVER_SENSE);
+ set_status_byte(cmd, SAM_STAT_CHECK_CONDITION);
}
hostdata->sensing = NULL;
}
@@ -1815,6 +1815,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
switch (tmp) {
case ABORT:
+ set_host_byte(cmd, DID_ABORT);
+ fallthrough;
case COMMAND_COMPLETE:
/* Accept message by clearing ACK */
sink = 1;
@@ -1826,9 +1828,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
hostdata->connected = NULL;
hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
- cmd->result &= ~0xffff;
- cmd->result |= cmd->SCp.Status;
- cmd->result |= cmd->SCp.Message << 8;
+ set_status_byte(cmd, cmd->SCp.Status);
set_resid_from_SCp(cmd);
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index f1f62b5da8b7..46b8dffce2dd 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -1235,8 +1235,8 @@ static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3
if (ret < 0)
return ret;
command = ContainerRawIo2;
- fibsize = sizeof(struct aac_raw_io2) +
- ((le32_to_cpu(readcmd2->sgeCnt)-1) * sizeof(struct sge_ieee1212));
+ fibsize = struct_size(readcmd2, sge,
+ le32_to_cpu(readcmd2->sgeCnt));
} else {
struct aac_raw_io *readcmd;
readcmd = (struct aac_raw_io *) fib_data(fib);
@@ -1366,8 +1366,8 @@ static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u
if (ret < 0)
return ret;
command = ContainerRawIo2;
- fibsize = sizeof(struct aac_raw_io2) +
- ((le32_to_cpu(writecmd2->sgeCnt)-1) * sizeof(struct sge_ieee1212));
+ fibsize = struct_size(writecmd2, sge,
+ le32_to_cpu(writecmd2->sgeCnt));
} else {
struct aac_raw_io *writecmd;
writecmd = (struct aac_raw_io *) fib_data(fib);
@@ -3998,7 +3998,7 @@ static int aac_convert_sgraw2(struct aac_raw_io2 *rio2, int pages, int nseg, int
if (aac_convert_sgl == 0)
return 0;
- sge = kmalloc_array(nseg_new, sizeof(struct sge_ieee1212), GFP_ATOMIC);
+ sge = kmalloc_array(nseg_new, sizeof(*sge), GFP_ATOMIC);
if (sge == NULL)
return -ENOMEM;
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index e3e4ecbea726..3733df77bc65 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -1929,7 +1929,7 @@ struct aac_raw_io2 {
u8 bpComplete; /* reserved for F/W use */
u8 sgeFirstIndex; /* reserved for F/W use */
u8 unused[4];
- struct sge_ieee1212 sge[1];
+ struct sge_ieee1212 sge[];
};
#define CT_FLUSH_CACHE 129
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 800052f10699..f3377e2ef5fb 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -5964,7 +5964,6 @@ static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
SCSI_SENSE_BUFFERSIZE);
- set_driver_byte(scp, DRIVER_SENSE);
}
break;
@@ -6715,7 +6714,6 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
SCSI_SENSE_BUFFERSIZE);
- set_driver_byte(scp, DRIVER_SENSE);
}
break;
@@ -6730,14 +6728,12 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
case QD_ABORTED_BY_HOST:
ASC_DBG(1, "QD_ABORTED_BY_HOST\n");
set_status_byte(scp, qdonep->d3.scsi_stat);
- set_msg_byte(scp, qdonep->d3.scsi_msg);
set_host_byte(scp, DID_ABORT);
break;
default:
ASC_DBG(1, "done_stat 0x%x\n", qdonep->d3.done_stat);
set_status_byte(scp, qdonep->d3.scsi_stat);
- set_msg_byte(scp, qdonep->d3.scsi_msg);
set_host_byte(scp, DID_ERROR);
break;
}
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index d8e19afa7a14..b13b5c85f3de 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -619,7 +619,8 @@ static struct {
static irqreturn_t intr(int irq, void *dev_id);
static void reset_ports(struct Scsi_Host *shpnt);
static void aha152x_error(struct Scsi_Host *shpnt, char *msg);
-static void done(struct Scsi_Host *shpnt, int error);
+static void done(struct Scsi_Host *shpnt, unsigned char status_byte,
+ unsigned char host_byte);
/* diagnostics */
static void show_command(struct scsi_cmnd * ptr);
@@ -1271,7 +1272,8 @@ static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev
* Internal done function
*
*/
-static void done(struct Scsi_Host *shpnt, int error)
+static void done(struct Scsi_Host *shpnt, unsigned char status_byte,
+ unsigned char host_byte)
{
if (CURRENT_SC) {
if(DONE_SC)
@@ -1281,7 +1283,8 @@ static void done(struct Scsi_Host *shpnt, int error)
DONE_SC = CURRENT_SC;
CURRENT_SC = NULL;
- DONE_SC->result = error;
+ set_status_byte(DONE_SC, status_byte);
+ set_host_byte(DONE_SC, host_byte);
} else
printk(KERN_ERR "aha152x: done() called outside of command\n");
}
@@ -1376,13 +1379,13 @@ static void busfree_run(struct Scsi_Host *shpnt)
if(CURRENT_SC->SCp.phase & completed) {
/* target sent COMMAND COMPLETE */
- done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
+ done(shpnt, CURRENT_SC->SCp.Status, DID_OK);
} else if(CURRENT_SC->SCp.phase & aborted) {
- done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16));
+ done(shpnt, CURRENT_SC->SCp.Status, DID_ABORT);
} else if(CURRENT_SC->SCp.phase & resetted) {
- done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16));
+ done(shpnt, CURRENT_SC->SCp.Status, DID_RESET);
} else if(CURRENT_SC->SCp.phase & disconnected) {
/* target sent DISCONNECT */
@@ -1394,7 +1397,7 @@ static void busfree_run(struct Scsi_Host *shpnt)
CURRENT_SC = NULL;
} else {
- done(shpnt, DID_ERROR << 16);
+ done(shpnt, SAM_STAT_GOOD, DID_ERROR);
}
#if defined(AHA152X_STAT)
} else {
@@ -1515,7 +1518,7 @@ static void seldo_run(struct Scsi_Host *shpnt)
if (TESTLO(SSTAT0, SELDO)) {
scmd_printk(KERN_ERR, CURRENT_SC,
"aha152x: passing bus free condition\n");
- done(shpnt, DID_NO_CONNECT << 16);
+ done(shpnt, SAM_STAT_GOOD, DID_NO_CONNECT);
return;
}
@@ -1552,12 +1555,12 @@ static void selto_run(struct Scsi_Host *shpnt)
CURRENT_SC->SCp.phase &= ~selecting;
if (CURRENT_SC->SCp.phase & aborted)
- done(shpnt, DID_ABORT << 16);
+ done(shpnt, SAM_STAT_GOOD, DID_ABORT);
else if (TESTLO(SSTAT0, SELINGO))
- done(shpnt, DID_BUS_BUSY << 16);
+ done(shpnt, SAM_STAT_GOOD, DID_BUS_BUSY);
else
/* ARBITRATION won, but SELECTION failed */
- done(shpnt, DID_NO_CONNECT << 16);
+ done(shpnt, SAM_STAT_GOOD, DID_NO_CONNECT);
}
/*
@@ -1891,7 +1894,7 @@ static void cmd_init(struct Scsi_Host *shpnt)
if (CURRENT_SC->SCp.sent_command) {
scmd_printk(KERN_ERR, CURRENT_SC,
"command already sent\n");
- done(shpnt, DID_ERROR << 16);
+ done(shpnt, SAM_STAT_GOOD, DID_ERROR);
return;
}
@@ -2231,7 +2234,7 @@ static int update_state(struct Scsi_Host *shpnt)
static void parerr_run(struct Scsi_Host *shpnt)
{
scmd_printk(KERN_ERR, CURRENT_SC, "parity error\n");
- done(shpnt, DID_PARITY << 16);
+ done(shpnt, SAM_STAT_GOOD, DID_PARITY);
}
/*
@@ -2254,7 +2257,7 @@ static void rsti_run(struct Scsi_Host *shpnt)
kfree(ptr->host_scribble);
ptr->host_scribble=NULL;
- ptr->result = DID_RESET << 16;
+ set_host_byte(ptr, DID_RESET);
ptr->scsi_done(ptr);
}
@@ -2262,7 +2265,7 @@ static void rsti_run(struct Scsi_Host *shpnt)
}
if(CURRENT_SC && !CURRENT_SC->device->soft_reset)
- done(shpnt, DID_RESET << 16 );
+ done(shpnt, SAM_STAT_GOOD, DID_RESET);
}
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index 0dc831026e9e..39d8759fe558 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -267,8 +267,11 @@ static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
guarantee that we will still have it in the
cdb when we come back */
if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) {
- memcpy(SCtmp->sense_buffer, ecbptr->sense,
- SCSI_SENSE_BUFFERSIZE);
+ memcpy_and_pad(SCtmp->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE,
+ ecbptr->sense,
+ sizeof(ecbptr->sense),
+ 0);
errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
} else
errstatus = 0;
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 4f7102f8eeb0..92ea24a075b8 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -1928,7 +1928,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
memcpy(cmd->sense_buffer,
ahd_get_sense_buf(ahd, scb)
+ sense_offset, sense_size);
- cmd->result |= (DRIVER_SENSE << 24);
+ set_status_byte(cmd, SAM_STAT_CHECK_CONDITION);
#ifdef AHD_DEBUG
if (ahd_debug & AHD_SHOW_SENSE) {
@@ -2018,6 +2018,7 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd)
int new_status = DID_OK;
int do_fallback = 0;
int scsi_status;
+ struct scsi_sense_data *sense;
/*
* Map CAM error codes into Linux Error codes. We
@@ -2041,18 +2042,12 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd)
switch(scsi_status) {
case SAM_STAT_COMMAND_TERMINATED:
case SAM_STAT_CHECK_CONDITION:
- if ((cmd->result >> 24) != DRIVER_SENSE) {
+ sense = (struct scsi_sense_data *)
+ cmd->sense_buffer;
+ if (sense->extra_len >= 5 &&
+ (sense->add_sense_code == 0x47
+ || sense->add_sense_code == 0x48))
do_fallback = 1;
- } else {
- struct scsi_sense_data *sense;
-
- sense = (struct scsi_sense_data *)
- cmd->sense_buffer;
- if (sense->extra_len >= 5 &&
- (sense->add_sense_code == 0x47
- || sense->add_sense_code == 0x48))
- do_fallback = 1;
- }
break;
default:
break;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 4b04ab8908f8..a396f048a031 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -493,7 +493,7 @@ ahc_inq(struct ahc_softc *ahc, u_int port)
return ((ahc_inb(ahc, port))
| (ahc_inb(ahc, port+1) << 8)
| (ahc_inb(ahc, port+2) << 16)
- | (ahc_inb(ahc, port+3) << 24)
+ | (((uint64_t)ahc_inb(ahc, port+3)) << 24)
| (((uint64_t)ahc_inb(ahc, port+4)) << 32)
| (((uint64_t)ahc_inb(ahc, port+5)) << 40)
| (((uint64_t)ahc_inb(ahc, port+6)) << 48)
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index d33f5a00bf0b..8b3d472aa3cc 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -1838,7 +1838,6 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
if (sense_size < SCSI_SENSE_BUFFERSIZE)
memset(&cmd->sense_buffer[sense_size], 0,
SCSI_SENSE_BUFFERSIZE - sense_size);
- cmd->result |= (DRIVER_SENSE << 24);
#ifdef AHC_DEBUG
if (ahc_debug & AHC_SHOW_SENSE) {
int i;
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index a195bfe9eccc..7a78606598c4 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -53,6 +53,7 @@ static struct scsi_host_template aic94xx_sht = {
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_target_reset_handler = sas_eh_target_reset_handler,
+ .slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
#ifdef CONFIG_COMPAT
diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c
index 297a66770260..46815e65f7a4 100644
--- a/drivers/scsi/aic94xx/aic94xx_sds.c
+++ b/drivers/scsi/aic94xx/aic94xx_sds.c
@@ -718,10 +718,12 @@ static void *asd_find_ll_by_id(void * const start, const u8 id0, const u8 id1)
do {
switch (id1) {
default:
- if (el->id1 == id1)
+ if (el->id1 == id1) {
+ fallthrough;
case 0xFF:
if (el->id0 == id0)
return el;
+ }
}
el = start + le16_to_cpu(el->next);
} while (el != start);
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index 71d18f607dae..c6b63eae28f5 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -205,7 +205,7 @@ Again:
switch (opcode) {
case TC_NO_ERROR:
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
break;
case TC_UNDERRUN:
ts->resp = SAS_TASK_COMPLETE;
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index 0f6abd233614..6ce57f031df5 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -49,7 +49,7 @@ struct device_attribute;
#define ARCMSR_MAX_OUTSTANDING_CMD 1024
#define ARCMSR_DEFAULT_OUTSTANDING_CMD 128
#define ARCMSR_MIN_OUTSTANDING_CMD 32
-#define ARCMSR_DRIVER_VERSION "v1.50.00.02-20200819"
+#define ARCMSR_DRIVER_VERSION "v1.50.00.05-20210429"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
#define ARCMSR_MAX_XFER_SECTORS_B 4096
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 4b79661275c9..ec1a834c922d 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -1323,19 +1323,21 @@ static void arcmsr_ccb_complete(struct CommandControlBlock *ccb)
static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
{
-
struct scsi_cmnd *pcmd = ccb->pcmd;
- struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
- pcmd->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
- if (sensebuffer) {
- int sense_data_length =
- sizeof(struct SENSE_DATA) < SCSI_SENSE_BUFFERSIZE
- ? sizeof(struct SENSE_DATA) : SCSI_SENSE_BUFFERSIZE;
- memset(sensebuffer, 0, SCSI_SENSE_BUFFERSIZE);
- memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
+
+ pcmd->result = (DID_OK << 16) | SAM_STAT_CHECK_CONDITION;
+ if (pcmd->sense_buffer) {
+ struct SENSE_DATA *sensebuffer;
+
+ memcpy_and_pad(pcmd->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE,
+ ccb->arcmsr_cdb.SenseData,
+ sizeof(ccb->arcmsr_cdb.SenseData),
+ 0);
+
+ sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
sensebuffer->Valid = 1;
- pcmd->result |= (DRIVER_SENSE << 24);
}
}
@@ -1923,8 +1925,12 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr
if (ccb->arc_cdb_size <= 0x300)
arc_cdb_size = (ccb->arc_cdb_size - 1) >> 6 | 1;
- else
- arc_cdb_size = (((ccb->arc_cdb_size + 0xff) >> 8) + 2) << 1 | 1;
+ else {
+ arc_cdb_size = ((ccb->arc_cdb_size + 0xff) >> 8) + 2;
+ if (arc_cdb_size > 0xF)
+ arc_cdb_size = 0xF;
+ arc_cdb_size = (arc_cdb_size << 1) | 1;
+ }
ccb_post_stamp = (ccb->smid | arc_cdb_size);
writel(0, &pmu->inbound_queueport_high);
writel(ccb_post_stamp, &pmu->inbound_queueport_low);
@@ -2415,10 +2421,17 @@ static void arcmsr_hbaD_doorbell_isr(struct AdapterControlBlock *pACB)
static void arcmsr_hbaE_doorbell_isr(struct AdapterControlBlock *pACB)
{
- uint32_t outbound_doorbell, in_doorbell, tmp;
+ uint32_t outbound_doorbell, in_doorbell, tmp, i;
struct MessageUnit_E __iomem *reg = pACB->pmuE;
- in_doorbell = readl(&reg->iobound_doorbell);
+ if (pACB->adapter_type == ACB_ADAPTER_TYPE_F) {
+ for (i = 0; i < 5; i++) {
+ in_doorbell = readl(&reg->iobound_doorbell);
+ if (in_doorbell != 0)
+ break;
+ }
+ } else
+ in_doorbell = readl(&reg->iobound_doorbell);
outbound_doorbell = in_doorbell ^ pACB->in_doorbell;
do {
writel(0, &reg->host_int_status); /* clear interrupt */
@@ -3243,7 +3256,7 @@ static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd,
if (!ccb)
return SCSI_MLQUEUE_HOST_BUSY;
if (arcmsr_build_ccb( acb, ccb, cmd ) == FAILED) {
- cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1);
+ cmd->result = (DID_ERROR << 16) | SAM_STAT_RESERVATION_CONFLICT;
cmd->scsi_done(cmd);
return 0;
}
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index 248a5bfad153..84fc7a0c6ff4 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -794,7 +794,10 @@ static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp,
acornscsi_dma_cleanup(host);
- SCpnt->result = result << 16 | host->scsi.SCp.Message << 8 | host->scsi.SCp.Status;
+ set_host_byte(SCpnt, result);
+ if (result == DID_OK)
+ scsi_msg_to_host_byte(SCpnt, host->scsi.SCp.Message);
+ set_status_byte(SCpnt, host->scsi.SCp.Status);
/*
* In theory, this should not happen. In practice, it seems to.
@@ -833,12 +836,12 @@ static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp,
xfer_warn = 0;
if (xfer_warn) {
- switch (status_byte(SCpnt->result)) {
- case CHECK_CONDITION:
- case COMMAND_TERMINATED:
- case BUSY:
- case QUEUE_FULL:
- case RESERVATION_CONFLICT:
+ switch (get_status_byte(SCpnt)) {
+ case SAM_STAT_CHECK_CONDITION:
+ case SAM_STAT_COMMAND_TERMINATED:
+ case SAM_STAT_BUSY:
+ case SAM_STAT_TASK_SET_FULL:
+ case SAM_STAT_RESERVATION_CONFLICT:
break;
default:
@@ -2470,7 +2473,7 @@ static int acornscsi_queuecmd_lck(struct scsi_cmnd *SCpnt,
if (acornscsi_cmdtype(SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->device->id))) {
printk(KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n",
host->host->host_no, '0' + SCpnt->device->id);
- SCpnt->result = DID_NO_CONNECT << 16;
+ set_host_byte(SCpnt, DID_NO_CONNECT);
done(SCpnt);
return 0;
}
@@ -2492,7 +2495,7 @@ static int acornscsi_queuecmd_lck(struct scsi_cmnd *SCpnt,
unsigned long flags;
if (!queue_add_cmd_ordered(&host->queues.issue, SCpnt)) {
- SCpnt->result = DID_ERROR << 16;
+ set_host_byte(SCpnt, DID_ERROR);
done(SCpnt);
return 0;
}
@@ -2506,31 +2509,6 @@ static int acornscsi_queuecmd_lck(struct scsi_cmnd *SCpnt,
DEF_SCSI_QCMD(acornscsi_queuecmd)
-/*
- * Prototype: void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1, struct scsi_cmnd **SCpntp2, int result)
- * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
- * Params : SCpntp1 - pointer to command to return
- * SCpntp2 - pointer to command to check
- * result - result to pass back to mid-level done function
- * Returns : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2.
- */
-static inline void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1,
- struct scsi_cmnd **SCpntp2,
- int result)
-{
- struct scsi_cmnd *SCpnt = *SCpntp1;
-
- if (SCpnt) {
- *SCpntp1 = NULL;
-
- SCpnt->result = result;
- SCpnt->scsi_done(SCpnt);
- }
-
- if (SCpnt == *SCpntp2)
- *SCpntp2 = NULL;
-}
-
enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
/*
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 2e687ce60753..6baa9b36367d 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -1479,7 +1479,7 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne
if (msgqueue_msglength(&info->scsi.msgs) > 1)
fas216_cmd(info, CMD_SETATN);
- /*FALLTHROUGH*/
+ fallthrough;
/*
* Any -> Message Out
@@ -2010,7 +2010,7 @@ static void fas216_rq_sns_done(FAS216_Info *info, struct scsi_cmnd *SCpnt,
"request sense complete, result=0x%04x%02x%02x",
result, SCpnt->SCp.Message, SCpnt->SCp.Status);
- if (result != DID_OK || SCpnt->SCp.Status != GOOD)
+ if (result != DID_OK || SCpnt->SCp.Status != SAM_STAT_GOOD)
/*
* Something went wrong. Make sure that we don't
* have valid data in the sense buffer that could
@@ -2042,8 +2042,10 @@ fas216_std_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, unsigned int result)
{
info->stats.fins += 1;
- SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 |
- info->scsi.SCp.Status;
+ set_host_byte(SCpnt, result);
+ if (result == DID_OK)
+ scsi_msg_to_host_byte(SCpnt, info->scsi.SCp.Message);
+ set_status_byte(SCpnt, info->scsi.SCp.Status);
fas216_log_command(info, LOG_CONNECT, SCpnt,
"command complete, result=0x%08x", SCpnt->result);
@@ -2051,23 +2053,22 @@ fas216_std_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, unsigned int result)
/*
* If the driver detected an error, we're all done.
*/
- if (host_byte(SCpnt->result) != DID_OK ||
- msg_byte(SCpnt->result) != COMMAND_COMPLETE)
+ if (get_host_byte(SCpnt) != DID_OK)
goto done;
/*
* If the command returned CHECK_CONDITION or COMMAND_TERMINATED
* status, request the sense information.
*/
- if (status_byte(SCpnt->result) == CHECK_CONDITION ||
- status_byte(SCpnt->result) == COMMAND_TERMINATED)
+ if (get_status_byte(SCpnt) == SAM_STAT_CHECK_CONDITION ||
+ get_status_byte(SCpnt) == SAM_STAT_COMMAND_TERMINATED)
goto request_sense;
/*
* If the command did not complete with GOOD status,
* we are all done here.
*/
- if (status_byte(SCpnt->result) != GOOD)
+ if (get_status_byte(SCpnt) != SAM_STAT_GOOD)
goto done;
/*
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index 0e935c49b57b..8aeaddc93b16 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -182,6 +182,7 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
struct beiscsi_endpoint *beiscsi_ep;
struct iscsi_endpoint *ep;
uint16_t cri_index;
+ int rc = 0;
ep = iscsi_lookup_endpoint(transport_fd);
if (!ep)
@@ -189,15 +190,17 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
beiscsi_ep = ep->dd_data;
- if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
- return -EINVAL;
+ if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) {
+ rc = -EINVAL;
+ goto put_ep;
+ }
if (beiscsi_ep->phba != phba) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
"BS_%d : beiscsi_ep->hba=%p not equal to phba=%p\n",
beiscsi_ep->phba, phba);
-
- return -EEXIST;
+ rc = -EEXIST;
+ goto put_ep;
}
cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid);
if (phba->conn_table[cri_index]) {
@@ -209,7 +212,8 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
beiscsi_ep->ep_cid,
beiscsi_conn,
phba->conn_table[cri_index]);
- return -EINVAL;
+ rc = -EINVAL;
+ goto put_ep;
}
}
@@ -226,7 +230,10 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
"BS_%d : cid %d phba->conn_table[%u]=%p\n",
beiscsi_ep->ep_cid, cri_index, beiscsi_conn);
phba->conn_table[cri_index] = beiscsi_conn;
- return 0;
+
+put_ep:
+ iscsi_put_endpoint(ep);
+ return rc;
}
static int beiscsi_iface_create_ipv4(struct beiscsi_hba *phba)
@@ -1293,7 +1300,6 @@ static int beiscsi_conn_close(struct beiscsi_endpoint *beiscsi_ep)
void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
{
struct beiscsi_endpoint *beiscsi_ep;
- struct beiscsi_conn *beiscsi_conn;
struct beiscsi_hba *phba;
uint16_t cri_index;
@@ -1312,11 +1318,6 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
return;
}
- if (beiscsi_ep->conn) {
- beiscsi_conn = beiscsi_ep->conn;
- iscsi_suspend_queue(beiscsi_conn->conn);
- }
-
if (!beiscsi_hba_is_online(phba)) {
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
"BS_%d : HBA in error 0x%lx\n", phba->state);
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 22cf7f4b8d8c..e70f69f791db 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -143,8 +143,7 @@ DEVICE_ATTR(beiscsi_##_name, S_IRUGO | S_IWUSR,\
beiscsi_##_name##_disp, beiscsi_##_name##_store)
/*
- * When new log level added update the
- * the MAX allowed value for log_enable
+ * When new log level added update MAX allowed value for log_enable
*/
BEISCSI_RW_ATTR(log_enable, 0x00,
0xFF, 0x00, "Enable logging Bit Mask\n"
@@ -416,7 +415,7 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev)
"beiscsi_hba_alloc - iscsi_host_alloc failed\n");
return NULL;
}
- shost->max_id = BE2_MAX_SESSIONS;
+ shost->max_id = BE2_MAX_SESSIONS - 1;
shost->max_channel = 0;
shost->max_cmd_len = BEISCSI_MAX_CMD_LEN;
shost->max_lun = BEISCSI_NUM_MAX_LUN;
@@ -825,9 +824,8 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba)
&phwi_context->be_eq[i]);
if (ret) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : beiscsi_init_irqs-Failed to"
- "register msix for i = %d\n",
- i);
+ "BM_%d : %s-Failed to register msix for i = %d\n",
+ __func__, i);
kfree(phba->msi_name[i]);
goto free_msix_irqs;
}
@@ -841,9 +839,9 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba)
ret = request_irq(pci_irq_vector(pcidev, i), be_isr_mcc, 0,
phba->msi_name[i], &phwi_context->be_eq[i]);
if (ret) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT ,
- "BM_%d : beiscsi_init_irqs-"
- "Failed to register beiscsi_msix_mcc\n");
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BM_%d : %s-Failed to register beiscsi_msix_mcc\n",
+ __func__);
kfree(phba->msi_name[i]);
goto free_msix_irqs;
}
@@ -853,8 +851,8 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba)
"beiscsi", phba);
if (ret) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : beiscsi_init_irqs-"
- "Failed to register irq\\n");
+ "BM_%d : %s-Failed to register irq\n",
+ __func__);
return ret;
}
}
@@ -1030,7 +1028,7 @@ free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context,
phba->params.wrbs_per_cxn);
beiscsi_log(phba, KERN_INFO,
BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
- "BM_%d : FREE WRB: pwrb_handle=%p free_index=0x%x"
+ "BM_%d : FREE WRB: pwrb_handle=%p free_index=0x%x "
"wrb_handles_available=%d\n",
pwrb_handle, pwrb_context->free_index,
pwrb_context->wrb_handles_available);
@@ -1374,7 +1372,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
"BM_%d :\t\t No HWH_TYPE_LOGIN Expected in"
- " hwi_complete_cmd- Solicited path\n");
+ " %s- Solicited path\n", __func__);
break;
case HWH_TYPE_NOP:
@@ -1384,8 +1382,8 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
default:
beiscsi_log(phba, KERN_WARNING,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
- "BM_%d : In hwi_complete_cmd, unknown type = %d"
- "wrb_index 0x%x CID 0x%x\n", type,
+ "BM_%d : In %s, unknown type = %d "
+ "wrb_index 0x%x CID 0x%x\n", __func__, type,
csol_cqe.wrb_index,
csol_cqe.cid);
break;
@@ -1883,9 +1881,9 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget)
cid = AMAP_GET_BITS(
struct amap_i_t_dpdu_cqe_v2,
cid, sol);
- else
- cid = AMAP_GET_BITS(struct amap_sol_cqe_v2,
- cid, sol);
+ else
+ cid = AMAP_GET_BITS(struct amap_sol_cqe_v2,
+ cid, sol);
}
cri_index = BE_GET_CRI_FROM_CID(cid);
@@ -2010,8 +2008,7 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget)
default:
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
- "BM_%d : Invalid CQE Event Received Code : %d"
- "CID 0x%x...\n",
+ "BM_%d : Invalid CQE Event Received Code : %d CID 0x%x...\n",
code, cid);
break;
}
@@ -3001,7 +2998,7 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba,
void *eq_vaddress;
dma_addr_t paddr;
- num_eq_pages = PAGES_REQUIRED(phba->params.num_eq_entries * \
+ num_eq_pages = PAGES_REQUIRED(phba->params.num_eq_entries *
sizeof(struct be_eq_entry));
if (phba->pcidev->msix_enabled)
@@ -3034,8 +3031,7 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba,
BEISCSI_EQ_DELAY_DEF);
if (ret) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : beiscsi_cmd_eq_create"
- "Failed for EQ\n");
+ "BM_%d : beiscsi_cmd_eq_create Failed for EQ\n");
goto create_eq_error;
}
@@ -3068,7 +3064,7 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba,
int ret = -ENOMEM;
dma_addr_t paddr;
- num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \
+ num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries *
sizeof(struct sol_cqe));
for (i = 0; i < phba->num_cpus; i++) {
@@ -3090,8 +3086,7 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba,
sizeof(struct sol_cqe), cq_vaddress);
if (ret) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : be_fill_queue Failed "
- "for ISCSI CQ\n");
+ "BM_%d : be_fill_queue Failed for ISCSI CQ\n");
goto create_cq_error;
}
@@ -3100,8 +3095,7 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba,
false, 0);
if (ret) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : beiscsi_cmd_eq_create"
- "Failed for ISCSI CQ\n");
+ "BM_%d : beiscsi_cmd_eq_create Failed for ISCSI CQ\n");
goto create_cq_error;
}
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
@@ -3226,8 +3220,8 @@ beiscsi_create_def_data(struct beiscsi_hba *phba,
phwi_context->be_def_dataq[ulp_num].id);
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
- "BM_%d : DEFAULT PDU DATA RING CREATED"
- "on ULP : %d\n", ulp_num);
+ "BM_%d : DEFAULT PDU DATA RING CREATED on ULP : %d\n",
+ ulp_num);
return 0;
}
@@ -3253,13 +3247,13 @@ beiscsi_post_template_hdr(struct beiscsi_hba *phba)
if (status != 0) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : Post Template HDR Failed for"
+ "BM_%d : Post Template HDR Failed for "
"ULP_%d\n", ulp_num);
return status;
}
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
- "BM_%d : Template HDR Pages Posted for"
+ "BM_%d : Template HDR Pages Posted for "
"ULP_%d\n", ulp_num);
}
}
@@ -3374,18 +3368,17 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba,
} else {
idx++;
wrb_vaddr = mem_descr->mem_array[idx].virtual_address;
- pa_addr_lo = mem_descr->mem_array[idx].\
+ pa_addr_lo = mem_descr->mem_array[idx].
bus_address.u.a64.address;
num_wrb_rings = mem_descr->mem_array[idx].size /
(phba->params.wrbs_per_cxn *
sizeof(struct iscsi_wrb));
pwrb_arr[num].virtual_address = wrb_vaddr;
- pwrb_arr[num].bus_address.u.a64.address\
- = pa_addr_lo;
+ pwrb_arr[num].bus_address.u.a64.address = pa_addr_lo;
pwrb_arr[num].size = phba->params.wrbs_per_cxn *
sizeof(struct iscsi_wrb);
wrb_vaddr += pwrb_arr[num].size;
- pa_addr_lo += pwrb_arr[num].size;
+ pa_addr_lo += pwrb_arr[num].size;
num_wrb_rings--;
}
}
@@ -3858,8 +3851,6 @@ static void beiscsi_free_mem(struct beiscsi_hba *phba)
int i, j;
mem_descr = phba->init_mem;
- i = 0;
- j = 0;
for (i = 0; i < SE_MEM_MAX; i++) {
for (j = mem_descr->num_elements; j > 0; j--) {
dma_free_coherent(&phba->pcidev->dev,
@@ -3939,7 +3930,7 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba)
idx++;
}
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
- "BM_%d : phba->io_sgl_hndl_avbl=%d"
+ "BM_%d : phba->io_sgl_hndl_avbl=%d "
"phba->eh_sgl_hndl_avbl=%d\n",
phba->io_sgl_hndl_avbl,
phba->eh_sgl_hndl_avbl);
@@ -3997,13 +3988,8 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba)
GFP_KERNEL);
if (!ptr_cid_info) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : Failed to allocate memory"
- "for ULP_CID_INFO for ULP : %d\n",
- ulp_num);
ret = -ENOMEM;
goto free_memory;
-
}
/* Allocate memory for CID array */
@@ -4012,10 +3998,6 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba)
sizeof(*ptr_cid_info->cid_array),
GFP_KERNEL);
if (!ptr_cid_info->cid_array) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : Failed to allocate memory"
- "for CID_ARRAY for ULP : %d\n",
- ulp_num);
kfree(ptr_cid_info);
ptr_cid_info = NULL;
ret = -ENOMEM;
@@ -4033,9 +4015,6 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba)
sizeof(struct iscsi_endpoint *),
GFP_KERNEL);
if (!phba->ep_array) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : Failed to allocate memory in "
- "hba_setup_cid_tbls\n");
ret = -ENOMEM;
goto free_memory;
@@ -4045,10 +4024,6 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba)
sizeof(struct beiscsi_conn *),
GFP_KERNEL);
if (!phba->conn_table) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BM_%d : Failed to allocate memory in"
- "hba_setup_cid_tbls\n");
-
kfree(phba->ep_array);
phba->ep_array = NULL;
ret = -ENOMEM;
@@ -4401,7 +4376,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
if (!io_task->psgl_handle) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
- "BM_%d : Alloc of IO_SGL_ICD Failed"
+ "BM_%d : Alloc of IO_SGL_ICD Failed "
"for the CID : %d\n",
beiscsi_conn->beiscsi_conn_cid);
goto free_hndls;
@@ -4412,7 +4387,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
if (!io_task->pwrb_handle) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
- "BM_%d : Alloc of WRB_HANDLE Failed"
+ "BM_%d : Alloc of WRB_HANDLE Failed "
"for the CID : %d\n",
beiscsi_conn->beiscsi_conn_cid);
goto free_io_hndls;
@@ -4428,10 +4403,9 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO |
BEISCSI_LOG_CONFIG,
- "BM_%d : Alloc of MGMT_SGL_ICD Failed"
+ "BM_%d : Alloc of MGMT_SGL_ICD Failed "
"for the CID : %d\n",
- beiscsi_conn->
- beiscsi_conn_cid);
+ beiscsi_conn->beiscsi_conn_cid);
goto free_hndls;
}
@@ -4446,10 +4420,9 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO |
BEISCSI_LOG_CONFIG,
- "BM_%d : Alloc of WRB_HANDLE Failed"
+ "BM_%d : Alloc of WRB_HANDLE Failed "
"for the CID : %d\n",
- beiscsi_conn->
- beiscsi_conn_cid);
+ beiscsi_conn->beiscsi_conn_cid);
goto free_mgmt_hndls;
}
beiscsi_conn->plogin_wrb_handle =
@@ -4467,10 +4440,9 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO |
BEISCSI_LOG_CONFIG,
- "BM_%d : Alloc of MGMT_SGL_ICD Failed"
+ "BM_%d : Alloc of MGMT_SGL_ICD Failed "
"for the CID : %d\n",
- beiscsi_conn->
- beiscsi_conn_cid);
+ beiscsi_conn->beiscsi_conn_cid);
goto free_hndls;
}
io_task->pwrb_handle =
@@ -4480,7 +4452,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
if (!io_task->pwrb_handle) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
- "BM_%d : Alloc of WRB_HANDLE Failed"
+ "BM_%d : Alloc of WRB_HANDLE Failed "
"for the CID : %d\n",
beiscsi_conn->beiscsi_conn_cid);
goto free_mgmt_hndls;
@@ -5318,7 +5290,7 @@ static int beiscsi_enable_port(struct beiscsi_hba *phba)
/* Re-enable UER. If different TPE occurs then it is recoverable. */
beiscsi_set_uer_feature(phba);
- phba->shost->max_id = phba->params.cxns_per_ctrl;
+ phba->shost->max_id = phba->params.cxns_per_ctrl - 1;
phba->shost->can_queue = phba->params.ios_per_ctrl;
ret = beiscsi_init_port(phba);
if (ret < 0) {
@@ -5745,6 +5717,7 @@ free_hba:
pci_disable_msix(phba->pcidev);
pci_dev_put(phba->pcidev);
iscsi_host_free(phba->shost);
+ pci_disable_pcie_error_reporting(pcidev);
pci_set_drvdata(pcidev, NULL);
disable_pci:
pci_release_regions(pcidev);
@@ -5809,6 +5782,7 @@ struct iscsi_transport beiscsi_iscsi_transport = {
.destroy_session = beiscsi_session_destroy,
.create_conn = beiscsi_conn_create,
.bind_conn = beiscsi_conn_bind,
+ .unbind_conn = iscsi_conn_unbind,
.destroy_conn = iscsi_conn_teardown,
.attr_is_visible = beiscsi_attr_is_visible,
.set_iface_param = beiscsi_iface_set_param,
diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h
index 8439951d95ac..f2c49f0e5c8b 100644
--- a/drivers/scsi/bfa/bfa_defs_svc.h
+++ b/drivers/scsi/bfa/bfa_defs_svc.h
@@ -871,7 +871,7 @@ enum bfa_port_linkstate_rsn {
/*
* Initially flash content may be fff. On making LUN mask enable and disable
- * state chnage. when report lun command is being processed it goes from
+ * state change. when report lun command is being processed it goes from
* BFA_LUN_MASK_ACTIVE to BFA_LUN_MASK_FETCH and comes back to
* BFA_LUN_MASK_ACTIVE.
*/
diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c
index 11c0c3e6f014..4e3cef02f10f 100644
--- a/drivers/scsi/bfa/bfa_svc.c
+++ b/drivers/scsi/bfa/bfa_svc.c
@@ -369,13 +369,10 @@ bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
enum bfa_plog_eid event,
u16 misc, struct fchs_s *fchdr)
{
- struct bfa_plog_rec_s lp;
u32 *tmp_int = (u32 *) fchdr;
u32 ints[BFA_PL_INT_LOG_SZ];
if (plog->plog_enabled) {
- memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
-
ints[0] = tmp_int[0];
ints[1] = tmp_int[1];
ints[2] = tmp_int[4];
@@ -389,13 +386,10 @@ bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
enum bfa_plog_eid event, u16 misc, struct fchs_s *fchdr,
u32 pld_w0)
{
- struct bfa_plog_rec_s lp;
u32 *tmp_int = (u32 *) fchdr;
u32 ints[BFA_PL_INT_LOG_SZ];
if (plog->plog_enabled) {
- memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
-
ints[0] = tmp_int[0];
ints[1] = tmp_int[1];
ints[2] = tmp_int[4];
@@ -3173,7 +3167,7 @@ bfa_fcport_send_enable(struct bfa_fcport_s *fcport)
m->port_cfg = fcport->cfg;
m->msgtag = fcport->msgtag;
m->port_cfg.maxfrsize = cpu_to_be16(fcport->cfg.maxfrsize);
- m->use_flash_cfg = fcport->use_flash_cfg;
+ m->use_flash_cfg = fcport->use_flash_cfg;
bfa_dma_be_addr_set(m->stats_dma_addr, fcport->stats_pa);
bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_lo);
bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_hi);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index ed300a279a38..f2996a9b2f63 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -1213,7 +1213,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
* cleanup the command and return that I/O was successfully
* aborted.
*/
- rc = bnx2fc_abts_cleanup(io_req);
+ bnx2fc_abts_cleanup(io_req);
/* This only occurs when an task abort was requested while ABTS
is in progress. Setting the IO_CLEANUP flag will skip the
RRQ process in the case when the fw generated SCSI_CMD cmpl
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 1e6d8f62ea3c..1b5f3e143f07 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -791,7 +791,7 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
return NULL;
shost->dma_boundary = cnic->pcidev->dma_mask;
shost->transportt = bnx2i_scsi_xport_template;
- shost->max_id = ISCSI_MAX_CONNS_PER_HBA;
+ shost->max_id = ISCSI_MAX_CONNS_PER_HBA - 1;
shost->max_channel = 0;
shost->max_lun = 512;
shost->max_cmd_len = 16;
@@ -1420,17 +1420,23 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
* Forcefully terminate all in progress connection recovery at the
* earliest, either in bind(), send_pdu(LOGIN), or conn_start()
*/
- if (bnx2i_adapter_ready(hba))
- return -EIO;
+ if (bnx2i_adapter_ready(hba)) {
+ ret_code = -EIO;
+ goto put_ep;
+ }
bnx2i_ep = ep->dd_data;
if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) ||
- (bnx2i_ep->state == EP_STATE_TCP_RST_RCVD))
+ (bnx2i_ep->state == EP_STATE_TCP_RST_RCVD)) {
/* Peer disconnect via' FIN or RST */
- return -EINVAL;
+ ret_code = -EINVAL;
+ goto put_ep;
+ }
- if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
- return -EINVAL;
+ if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) {
+ ret_code = -EINVAL;
+ goto put_ep;
+ }
if (bnx2i_ep->hba != hba) {
/* Error - TCP connection does not belong to this device
@@ -1441,7 +1447,8 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data,
"belong to hba (%s)\n",
hba->netdev->name);
- return -EEXIST;
+ ret_code = -EEXIST;
+ goto put_ep;
}
bnx2i_ep->conn = bnx2i_conn;
bnx2i_conn->ep = bnx2i_ep;
@@ -1458,6 +1465,8 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
bnx2i_put_rq_buf(bnx2i_conn, 0);
bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE);
+put_ep:
+ iscsi_put_endpoint(ep);
return ret_code;
}
@@ -2113,7 +2122,6 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep)
{
struct bnx2i_endpoint *bnx2i_ep;
struct bnx2i_conn *bnx2i_conn = NULL;
- struct iscsi_conn *conn = NULL;
struct bnx2i_hba *hba;
bnx2i_ep = ep->dd_data;
@@ -2126,11 +2134,8 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep)
!time_after(jiffies, bnx2i_ep->timestamp + (12 * HZ)))
msleep(250);
- if (bnx2i_ep->conn) {
+ if (bnx2i_ep->conn)
bnx2i_conn = bnx2i_ep->conn;
- conn = bnx2i_conn->cls_conn->dd_data;
- iscsi_suspend_queue(conn);
- }
hba = bnx2i_ep->hba;
mutex_lock(&hba->net_dev_lock);
@@ -2276,6 +2281,7 @@ struct iscsi_transport bnx2i_iscsi_transport = {
.destroy_session = bnx2i_session_destroy,
.create_conn = bnx2i_conn_create,
.bind_conn = bnx2i_conn_bind,
+ .unbind_conn = iscsi_conn_unbind,
.destroy_conn = bnx2i_conn_destroy,
.attr_is_visible = bnx2i_attr_is_visible,
.set_param = iscsi_set_param,
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 9b89c26ccfdb..fc7197abfcdf 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -198,8 +198,9 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, int cmd_len,
result = scsi_execute_req(ch->device, cmd, direction, buffer,
buflength, &sshdr, timeout * HZ,
MAX_RETRIES, NULL);
-
- if (driver_byte(result) == DRIVER_SENSE) {
+ if (result < 0)
+ return result;
+ if (scsi_sense_valid(&sshdr)) {
if (debug)
scsi_print_sense_hdr(ch->device, ch->name, &sshdr);
errno = ch_find_errno(&sshdr);
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 84d73f57292b..340785536998 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -406,14 +406,10 @@ static const char * const hostbyte_table[]={
"DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST", "DID_TARGET_FAILURE",
"DID_NEXUS_FAILURE", "DID_ALLOC_FAILURE", "DID_MEDIUM_ERROR" };
-static const char * const driverbyte_table[]={
-"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR",
-"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"};
-
const char *scsi_hostbyte_string(int result)
{
+ enum scsi_host_status hb = host_byte(result);
const char *hb_string = NULL;
- int hb = host_byte(result);
if (hb < ARRAY_SIZE(hostbyte_table))
hb_string = hostbyte_table[hb];
@@ -421,17 +417,6 @@ const char *scsi_hostbyte_string(int result)
}
EXPORT_SYMBOL(scsi_hostbyte_string);
-const char *scsi_driverbyte_string(int result)
-{
- const char *db_string = NULL;
- int db = driver_byte(result);
-
- if (db < ARRAY_SIZE(driverbyte_table))
- db_string = driverbyte_table[db];
- return db_string;
-}
-EXPORT_SYMBOL(scsi_driverbyte_string);
-
#define scsi_mlreturn_name(result) { result, #result }
static const struct value_name_pair scsi_mlreturn_arr[] = {
scsi_mlreturn_name(NEEDS_RETRY),
diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
index 203f938fca7e..f949a4e00783 100644
--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
+++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
@@ -117,6 +117,7 @@ static struct iscsi_transport cxgb3i_iscsi_transport = {
/* connection management */
.create_conn = cxgbi_create_conn,
.bind_conn = cxgbi_bind_conn,
+ .unbind_conn = iscsi_conn_unbind,
.destroy_conn = iscsi_tcp_conn_teardown,
.start_conn = iscsi_conn_start,
.stop_conn = iscsi_conn_stop,
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index 2c3491528d42..efb3e2b3398e 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -134,6 +134,7 @@ static struct iscsi_transport cxgb4i_iscsi_transport = {
/* connection management */
.create_conn = cxgbi_create_conn,
.bind_conn = cxgbi_bind_conn,
+ .unbind_conn = iscsi_conn_unbind,
.destroy_conn = iscsi_tcp_conn_teardown,
.start_conn = iscsi_conn_start,
.stop_conn = iscsi_conn_stop,
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index f078b3c4e083..8c7d4dda4cf2 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -337,7 +337,7 @@ void cxgbi_hbas_remove(struct cxgbi_device *cdev)
EXPORT_SYMBOL_GPL(cxgbi_hbas_remove);
int cxgbi_hbas_add(struct cxgbi_device *cdev, u64 max_lun,
- unsigned int max_id, struct scsi_host_template *sht,
+ unsigned int max_conns, struct scsi_host_template *sht,
struct scsi_transport_template *stt)
{
struct cxgbi_hba *chba;
@@ -357,7 +357,7 @@ int cxgbi_hbas_add(struct cxgbi_device *cdev, u64 max_lun,
shost->transportt = stt;
shost->max_lun = max_lun;
- shost->max_id = max_id;
+ shost->max_id = max_conns - 1;
shost->max_channel = 0;
shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE;
@@ -2690,11 +2690,13 @@ int cxgbi_bind_conn(struct iscsi_cls_session *cls_session,
err = csk->cdev->csk_ddp_setup_pgidx(csk, csk->tid,
ppm->tformat.pgsz_idx_dflt);
if (err < 0)
- return err;
+ goto put_ep;
err = iscsi_conn_bind(cls_session, cls_conn, is_leading);
- if (err)
- return -EINVAL;
+ if (err) {
+ err = -EINVAL;
+ goto put_ep;
+ }
/* calculate the tag idx bits needed for this conn based on cmds_max */
cconn->task_idx_bits = (__ilog2_u32(conn->session->cmds_max - 1)) + 1;
@@ -2715,7 +2717,9 @@ int cxgbi_bind_conn(struct iscsi_cls_session *cls_session,
/* init recv engine */
iscsi_tcp_hdr_recv_prep(tcp_conn);
- return 0;
+put_ep:
+ iscsi_put_endpoint(ep);
+ return err;
}
EXPORT_SYMBOL_GPL(cxgbi_bind_conn);
@@ -2968,7 +2972,6 @@ void cxgbi_ep_disconnect(struct iscsi_endpoint *ep)
ep, cep, cconn, csk, csk->state, csk->flags);
if (cconn && cconn->iconn) {
- iscsi_suspend_tx(cconn->iconn);
write_lock_bh(&csk->callback_lock);
cep->csk->user_data = NULL;
cconn->cep = NULL;
diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c
index ee11ec340654..df0ebabbf387 100644
--- a/drivers/scsi/cxlflash/superpipe.c
+++ b/drivers/scsi/cxlflash/superpipe.c
@@ -369,8 +369,7 @@ retry:
goto out;
}
- if (driver_byte(result) == DRIVER_SENSE) {
- result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */
+ if (result > 0 && scsi_sense_valid(&sshdr)) {
if (result & SAM_STAT_CHECK_CONDITION) {
switch (sshdr.sense_key) {
case NO_SENSE:
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index be87d5a7583d..24c7cefb0b78 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -160,22 +160,6 @@
#define DC395x_write16(acb,address,value) outw((value), acb->io_port_base + (address))
#define DC395x_write32(acb,address,value) outl((value), acb->io_port_base + (address))
-/* cmd->result */
-#define RES_TARGET 0x000000FF /* Target State */
-#define RES_TARGET_LNX STATUS_MASK /* Only official ... */
-#define RES_ENDMSG 0x0000FF00 /* End Message */
-#define RES_DID 0x00FF0000 /* DID_ codes */
-#define RES_DRV 0xFF000000 /* DRIVER_ codes */
-
-#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt))
-#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)<<1)
-
-#define SET_RES_TARGET(who,tgt) { who &= ~RES_TARGET; who |= (int)(tgt); }
-#define SET_RES_TARGET_LNX(who,tgt) { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; }
-#define SET_RES_MSG(who,msg) { who &= ~RES_ENDMSG; who |= (int)(msg) << 8; }
-#define SET_RES_DID(who,did) { who &= ~RES_DID; who |= (int)(did) << 16; }
-#define SET_RES_DRV(who,drv) { who &= ~RES_DRV; who |= (int)(drv) << 24; }
-
#define TAG_NONE 255
/*
@@ -986,7 +970,7 @@ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct s
cmd, cmd->device->id, (u8)cmd->device->lun, cmd->cmnd[0]);
/* Assume BAD_TARGET; will be cleared later */
- cmd->result = DID_BAD_TARGET << 16;
+ set_host_byte(cmd, DID_BAD_TARGET);
/* ignore invalid targets */
if (cmd->device->id >= acb->scsi_host->max_id ||
@@ -1013,7 +997,8 @@ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct s
/* set callback and clear result in the command */
cmd->scsi_done = done;
- cmd->result = 0;
+ set_host_byte(cmd, DID_OK);
+ set_status_byte(cmd, SAM_STAT_GOOD);
srb = list_first_entry_or_null(&acb->srb_free_list,
struct ScsiReqBlk, list);
@@ -1250,7 +1235,7 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd)
free_tag(dcb, srb);
list_add_tail(&srb->list, &acb->srb_free_list);
dprintkl(KERN_DEBUG, "eh_abort: Command was waiting\n");
- cmd->result = DID_ABORT << 16;
+ set_host_byte(cmd, DID_ABORT);
return SUCCESS;
}
srb = find_cmd(cmd, &dcb->srb_going_list);
@@ -3178,6 +3163,8 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count,
scsi_sgtalbe(cmd));
status = srb->target_status;
+ set_host_byte(cmd, DID_OK);
+ set_status_byte(cmd, SAM_STAT_GOOD);
if (srb->flag & AUTO_REQSENSE) {
dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n");
pci_unmap_srb_sense(acb, srb);
@@ -3186,7 +3173,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
*/
srb->flag &= ~AUTO_REQSENSE;
srb->adapter_status = 0;
- srb->target_status = CHECK_CONDITION << 1;
+ srb->target_status = SAM_STAT_CHECK_CONDITION;
if (debug_enabled(DBG_1)) {
switch (cmd->sense_buffer[2] & 0x0f) {
case NOT_READY:
@@ -3233,22 +3220,13 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
*((unsigned int *)(cmd->sense_buffer + 3)));
}
- if (status == (CHECK_CONDITION << 1)) {
- cmd->result = DID_BAD_TARGET << 16;
+ if (status == SAM_STAT_CHECK_CONDITION) {
+ set_host_byte(cmd, DID_BAD_TARGET);
goto ckc_e;
}
dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE2\n");
- if (srb->total_xfer_length
- && srb->total_xfer_length >= cmd->underflow)
- cmd->result =
- MK_RES_LNX(DRIVER_SENSE, DID_OK,
- srb->end_message, CHECK_CONDITION);
- /*SET_RES_DID(cmd->result,DID_OK) */
- else
- cmd->result =
- MK_RES_LNX(DRIVER_SENSE, DID_OK,
- srb->end_message, CHECK_CONDITION);
+ set_status_byte(cmd, SAM_STAT_CHECK_CONDITION);
goto ckc_e;
}
@@ -3258,10 +3236,10 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
/*
* target status..........................
*/
- if (status >> 1 == CHECK_CONDITION) {
+ if (status == SAM_STAT_CHECK_CONDITION) {
request_sense(acb, dcb, srb);
return;
- } else if (status >> 1 == QUEUE_FULL) {
+ } else if (status == SAM_STAT_TASK_SET_FULL) {
tempcnt = (u8)list_size(&dcb->srb_going_list);
dprintkl(KERN_INFO, "QUEUE_FULL for dev <%02i-%i> with %i cmnds\n",
dcb->target_id, dcb->target_lun, tempcnt);
@@ -3277,13 +3255,11 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
} else if (status == SCSI_STAT_SEL_TIMEOUT) {
srb->adapter_status = H_SEL_TIMEOUT;
srb->target_status = 0;
- cmd->result = DID_NO_CONNECT << 16;
+ set_host_byte(cmd, DID_NO_CONNECT);
} else {
srb->adapter_status = 0;
- SET_RES_DID(cmd->result, DID_ERROR);
- SET_RES_MSG(cmd->result, srb->end_message);
- SET_RES_TARGET(cmd->result, status);
-
+ set_host_byte(cmd, DID_ERROR);
+ set_status_byte(cmd, status);
}
} else {
/*
@@ -3292,16 +3268,13 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
status = srb->adapter_status;
if (status & H_OVER_UNDER_RUN) {
srb->target_status = 0;
- SET_RES_DID(cmd->result, DID_OK);
- SET_RES_MSG(cmd->result, srb->end_message);
+ scsi_msg_to_host_byte(cmd, srb->end_message);
} else if (srb->status & PARITY_ERROR) {
- SET_RES_DID(cmd->result, DID_PARITY);
- SET_RES_MSG(cmd->result, srb->end_message);
+ set_host_byte(cmd, DID_PARITY);
} else { /* No error */
srb->adapter_status = 0;
srb->target_status = 0;
- SET_RES_DID(cmd->result, DID_OK);
}
}
@@ -3322,15 +3295,15 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
base = scsi_kmap_atomic_sg(sg, scsi_sg_count(cmd), &offset, &len);
ptr = (struct ScsiInqData *)(base + offset);
- if (!ckc_only && (cmd->result & RES_DID) == 0
+ if (!ckc_only && get_host_byte(cmd) == DID_OK
&& cmd->cmnd[2] == 0 && scsi_bufflen(cmd) >= 8
&& dir != DMA_NONE && ptr && (ptr->Vers & 0x07) >= 2)
dcb->inquiry7 = ptr->Flags;
/*if( srb->cmd->cmnd[0] == INQUIRY && */
/* (host_byte(cmd->result) == DID_OK || status_byte(cmd->result) & CHECK_CONDITION) ) */
- if ((cmd->result == (DID_OK << 16) ||
- status_byte(cmd->result) == CHECK_CONDITION)) {
+ if ((get_host_byte(cmd) == DID_OK) ||
+ (get_status_byte(cmd) == SAM_STAT_CHECK_CONDITION)) {
if (!dcb->init_tcq_flag) {
add_dev(acb, dcb, ptr);
dcb->init_tcq_flag = 1;
@@ -3357,7 +3330,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
if (srb != acb->tmp_srb) {
/* Add to free list */
dprintkdbg(DBG_0, "srb_done: (0x%p) done result=0x%08x\n",
- cmd, cmd->result);
+ cmd, cmd->result);
list_move_tail(&srb->list, &acb->srb_free_list);
} else {
dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n");
@@ -3381,16 +3354,14 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
struct scsi_cmnd *p;
list_for_each_entry_safe(srb, tmp, &dcb->srb_going_list, list) {
- int result;
-
p = srb->cmd;
- result = MK_RES(0, did_flag, 0, 0);
printk("G:%p(%02i-%i) ", p,
p->device->id, (u8)p->device->lun);
list_del(&srb->list);
free_tag(dcb, srb);
list_add_tail(&srb->list, &acb->srb_free_list);
- p->result = result;
+ set_host_byte(p, did_flag);
+ set_status_byte(p, SAM_STAT_GOOD);
pci_unmap_srb_sense(acb, srb);
pci_unmap_srb(acb, srb);
if (force) {
@@ -3411,14 +3382,13 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
/* Waiting queue */
list_for_each_entry_safe(srb, tmp, &dcb->srb_waiting_list, list) {
- int result;
p = srb->cmd;
- result = MK_RES(0, did_flag, 0, 0);
printk("W:%p<%02i-%i>", p, p->device->id,
(u8)p->device->lun);
list_move_tail(&srb->list, &acb->srb_free_list);
- p->result = result;
+ set_host_byte(p, did_flag);
+ set_status_byte(p, SAM_STAT_GOOD);
pci_unmap_srb_sense(acb, srb);
pci_unmap_srb(acb, srb);
if (force) {
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index efa8c0381476..37d06f993b76 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -88,6 +88,7 @@ struct alua_dh_data {
struct scsi_device *sdev;
int init_error;
struct mutex init_mutex;
+ bool disabled;
};
struct alua_queue_data {
@@ -517,7 +518,8 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
int len, k, off, bufflen = ALUA_RTPG_SIZE;
int group_id_old, state_old, pref_old, valid_states_old;
unsigned char *desc, *buff;
- unsigned err, retval;
+ unsigned err;
+ int retval;
unsigned int tpg_desc_tbl_off;
unsigned char orig_transition_tmo;
unsigned long flags;
@@ -562,13 +564,15 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
kfree(buff);
return SCSI_DH_OK;
}
- if (!scsi_sense_valid(&sense_hdr)) {
+ if (retval < 0 || !scsi_sense_valid(&sense_hdr)) {
sdev_printk(KERN_INFO, sdev,
"%s: rtpg failed, result %d\n",
ALUA_DH_NAME, retval);
kfree(buff);
- if (driver_byte(retval) == DRIVER_ERROR)
+ if (retval < 0)
return SCSI_DH_DEV_TEMP_BUSY;
+ if (host_byte(retval) == DID_NO_CONNECT)
+ return SCSI_DH_RES_TEMP_UNAVAIL;
return SCSI_DH_IO;
}
@@ -791,11 +795,11 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
retval = submit_stpg(sdev, pg->group_id, &sense_hdr);
if (retval) {
- if (!scsi_sense_valid(&sense_hdr)) {
+ if (retval < 0 || !scsi_sense_valid(&sense_hdr)) {
sdev_printk(KERN_INFO, sdev,
"%s: stpg failed, result %d",
ALUA_DH_NAME, retval);
- if (driver_byte(retval) == DRIVER_ERROR)
+ if (retval < 0)
return SCSI_DH_DEV_TEMP_BUSY;
} else {
sdev_printk(KERN_INFO, sdev, "%s: stpg failed\n",
@@ -807,6 +811,51 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
return SCSI_DH_RETRY;
}
+static bool alua_rtpg_select_sdev(struct alua_port_group *pg)
+{
+ struct alua_dh_data *h;
+ struct scsi_device *sdev = NULL;
+
+ lockdep_assert_held(&pg->lock);
+ if (WARN_ON(!pg->rtpg_sdev))
+ return false;
+
+ /*
+ * RCU protection isn't necessary for dh_list here
+ * as we hold pg->lock, but for access to h->pg.
+ */
+ rcu_read_lock();
+ list_for_each_entry_rcu(h, &pg->dh_list, node) {
+ if (!h->sdev)
+ continue;
+ if (h->sdev == pg->rtpg_sdev) {
+ h->disabled = true;
+ continue;
+ }
+ if (rcu_dereference(h->pg) == pg &&
+ !h->disabled &&
+ !scsi_device_get(h->sdev)) {
+ sdev = h->sdev;
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ if (!sdev) {
+ pr_warn("%s: no device found for rtpg\n",
+ (pg->device_id_len ?
+ (char *)pg->device_id_str : "(nameless PG)"));
+ return false;
+ }
+
+ sdev_printk(KERN_INFO, sdev, "rtpg retry on different device\n");
+
+ scsi_device_put(pg->rtpg_sdev);
+ pg->rtpg_sdev = sdev;
+
+ return true;
+}
+
static void alua_rtpg_work(struct work_struct *work)
{
struct alua_port_group *pg =
@@ -815,6 +864,7 @@ static void alua_rtpg_work(struct work_struct *work)
LIST_HEAD(qdata_list);
int err = SCSI_DH_OK;
struct alua_queue_data *qdata, *tmp;
+ struct alua_dh_data *h;
unsigned long flags;
spin_lock_irqsave(&pg->lock, flags);
@@ -848,9 +898,18 @@ static void alua_rtpg_work(struct work_struct *work)
}
err = alua_rtpg(sdev, pg);
spin_lock_irqsave(&pg->lock, flags);
- if (err == SCSI_DH_RETRY || pg->flags & ALUA_PG_RUN_RTPG) {
+
+ /* If RTPG failed on the current device, try using another */
+ if (err == SCSI_DH_RES_TEMP_UNAVAIL &&
+ alua_rtpg_select_sdev(pg))
+ err = SCSI_DH_IMM_RETRY;
+
+ if (err == SCSI_DH_RETRY || err == SCSI_DH_IMM_RETRY ||
+ pg->flags & ALUA_PG_RUN_RTPG) {
pg->flags &= ~ALUA_PG_RUNNING;
- if (!pg->interval && !(pg->flags & ALUA_PG_RUN_RTPG))
+ if (err == SCSI_DH_IMM_RETRY)
+ pg->interval = 0;
+ else if (!pg->interval && !(pg->flags & ALUA_PG_RUN_RTPG))
pg->interval = ALUA_RTPG_RETRY_DELAY;
pg->flags |= ALUA_PG_RUN_RTPG;
spin_unlock_irqrestore(&pg->lock, flags);
@@ -878,6 +937,12 @@ static void alua_rtpg_work(struct work_struct *work)
}
list_splice_init(&pg->rtpg_list, &qdata_list);
+ /*
+ * We went through an RTPG, for good or bad.
+ * Re-enable all devices for the next attempt.
+ */
+ list_for_each_entry(h, &pg->dh_list, node)
+ h->disabled = false;
pg->rtpg_sdev = NULL;
spin_unlock_irqrestore(&pg->lock, flags);
@@ -962,6 +1027,7 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
int err = SCSI_DH_DEV_UNSUPP, tpgs;
mutex_lock(&h->init_mutex);
+ h->disabled = false;
tpgs = alua_check_tpgs(sdev);
if (tpgs != TPGS_MODE_NONE)
err = alua_check_vpd(sdev, h, tpgs);
@@ -1080,7 +1146,6 @@ static void alua_check(struct scsi_device *sdev, bool force)
return;
}
rcu_read_unlock();
-
alua_rtpg_queue(pg, sdev, NULL, force);
kref_put(&pg->kref, release_port_group);
}
diff --git a/drivers/scsi/elx/Kconfig b/drivers/scsi/elx/Kconfig
new file mode 100644
index 000000000000..831daea7a951
--- /dev/null
+++ b/drivers/scsi/elx/Kconfig
@@ -0,0 +1,9 @@
+config SCSI_EFCT
+ tristate "Emulex Fibre Channel Target"
+ depends on PCI && SCSI
+ depends on TARGET_CORE
+ depends on SCSI_FC_ATTRS
+ select CRC_T10DIF
+ help
+ The efct driver provides enhanced SCSI Target Mode
+ support for specific SLI-4 adapters.
diff --git a/drivers/scsi/elx/Makefile b/drivers/scsi/elx/Makefile
new file mode 100644
index 000000000000..a8537d7a2a6e
--- /dev/null
+++ b/drivers/scsi/elx/Makefile
@@ -0,0 +1,18 @@
+#// SPDX-License-Identifier: GPL-2.0
+#/*
+# * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+# * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+# */
+
+
+obj-$(CONFIG_SCSI_EFCT) := efct.o
+
+efct-objs := efct/efct_driver.o efct/efct_io.o efct/efct_scsi.o \
+ efct/efct_xport.o efct/efct_hw.o efct/efct_hw_queues.o \
+ efct/efct_lio.o efct/efct_unsol.o
+
+efct-objs += libefc/efc_cmds.o libefc/efc_domain.o libefc/efc_fabric.o \
+ libefc/efc_node.o libefc/efc_nport.o libefc/efc_device.o \
+ libefc/efclib.o libefc/efc_sm.o libefc/efc_els.o
+
+efct-objs += libefc_sli/sli4.o
diff --git a/drivers/scsi/elx/efct/efct_driver.c b/drivers/scsi/elx/efct/efct_driver.c
new file mode 100644
index 000000000000..eab68fd9337a
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_driver.c
@@ -0,0 +1,786 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#include "efct_driver.h"
+
+#include "efct_hw.h"
+#include "efct_unsol.h"
+#include "efct_scsi.h"
+
+LIST_HEAD(efct_devices);
+
+static int logmask;
+module_param(logmask, int, 0444);
+MODULE_PARM_DESC(logmask, "logging bitmask (default 0)");
+
+static struct libefc_function_template efct_libefc_templ = {
+ .issue_mbox_rqst = efct_issue_mbox_rqst,
+ .send_els = efct_els_hw_srrs_send,
+ .send_bls = efct_efc_bls_send,
+
+ .new_nport = efct_scsi_tgt_new_nport,
+ .del_nport = efct_scsi_tgt_del_nport,
+ .scsi_new_node = efct_scsi_new_initiator,
+ .scsi_del_node = efct_scsi_del_initiator,
+ .hw_seq_free = efct_efc_hw_sequence_free,
+};
+
+static int
+efct_device_init(void)
+{
+ int rc;
+
+ /* driver-wide init for target-server */
+ rc = efct_scsi_tgt_driver_init();
+ if (rc) {
+ pr_err("efct_scsi_tgt_init failed rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = efct_scsi_reg_fc_transport();
+ if (rc) {
+ pr_err("failed to register to FC host\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static void
+efct_device_shutdown(void)
+{
+ efct_scsi_release_fc_transport();
+
+ efct_scsi_tgt_driver_exit();
+}
+
+static void *
+efct_device_alloc(u32 nid)
+{
+ struct efct *efct = NULL;
+
+ efct = kzalloc_node(sizeof(*efct), GFP_KERNEL, nid);
+ if (!efct)
+ return efct;
+
+ INIT_LIST_HEAD(&efct->list_entry);
+ list_add_tail(&efct->list_entry, &efct_devices);
+
+ return efct;
+}
+
+static void
+efct_teardown_msix(struct efct *efct)
+{
+ u32 i;
+
+ for (i = 0; i < efct->n_msix_vec; i++) {
+ free_irq(pci_irq_vector(efct->pci, i),
+ &efct->intr_context[i]);
+ }
+
+ pci_free_irq_vectors(efct->pci);
+}
+
+static int
+efct_efclib_config(struct efct *efct, struct libefc_function_template *tt)
+{
+ struct efc *efc;
+ struct sli4 *sli;
+ int rc = 0;
+
+ efc = kzalloc(sizeof(*efc), GFP_KERNEL);
+ if (!efc)
+ return -ENOMEM;
+
+ efct->efcport = efc;
+
+ memcpy(&efc->tt, tt, sizeof(*tt));
+ efc->base = efct;
+ efc->pci = efct->pci;
+
+ efc->def_wwnn = efct_get_wwnn(&efct->hw);
+ efc->def_wwpn = efct_get_wwpn(&efct->hw);
+ efc->enable_tgt = 1;
+ efc->log_level = EFC_LOG_LIB;
+
+ sli = &efct->hw.sli;
+ efc->max_xfer_size = sli->sge_supported_length *
+ sli_get_max_sgl(&efct->hw.sli);
+ efc->sli = sli;
+ efc->fcfi = efct->hw.fcf_indicator;
+
+ rc = efcport_init(efc);
+ if (rc)
+ efc_log_err(efc, "efcport_init failed\n");
+
+ return rc;
+}
+
+static int efct_request_firmware_update(struct efct *efct);
+
+static const char*
+efct_pci_model(u16 device)
+{
+ switch (device) {
+ case EFCT_DEVICE_LANCER_G6: return "LPE31004";
+ case EFCT_DEVICE_LANCER_G7: return "LPE36000";
+ default: return "unknown";
+ }
+}
+
+static int
+efct_device_attach(struct efct *efct)
+{
+ u32 rc = 0, i = 0;
+
+ if (efct->attached) {
+ efc_log_err(efct, "Device is already attached\n");
+ return -EIO;
+ }
+
+ snprintf(efct->name, sizeof(efct->name), "[%s%d] ", "fc",
+ efct->instance_index);
+
+ efct->logmask = logmask;
+ efct->filter_def = EFCT_DEFAULT_FILTER;
+ efct->max_isr_time_msec = EFCT_OS_MAX_ISR_TIME_MSEC;
+
+ efct->model = efct_pci_model(efct->pci->device);
+
+ efct->efct_req_fw_upgrade = true;
+
+ /* Allocate transport object and bring online */
+ efct->xport = efct_xport_alloc(efct);
+ if (!efct->xport) {
+ efc_log_err(efct, "failed to allocate transport object\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = efct_xport_attach(efct->xport);
+ if (rc) {
+ efc_log_err(efct, "failed to attach transport object\n");
+ goto xport_out;
+ }
+
+ rc = efct_xport_initialize(efct->xport);
+ if (rc) {
+ efc_log_err(efct, "failed to initialize transport object\n");
+ goto xport_out;
+ }
+
+ rc = efct_efclib_config(efct, &efct_libefc_templ);
+ if (rc) {
+ efc_log_err(efct, "failed to init efclib\n");
+ goto efclib_out;
+ }
+
+ for (i = 0; i < efct->n_msix_vec; i++) {
+ efc_log_debug(efct, "irq %d enabled\n", i);
+ enable_irq(pci_irq_vector(efct->pci, i));
+ }
+
+ efct->attached = true;
+
+ if (efct->efct_req_fw_upgrade)
+ efct_request_firmware_update(efct);
+
+ return rc;
+
+efclib_out:
+ efct_xport_detach(efct->xport);
+xport_out:
+ efct_xport_free(efct->xport);
+ efct->xport = NULL;
+out:
+ return rc;
+}
+
+static int
+efct_device_detach(struct efct *efct)
+{
+ int i;
+
+ if (!efct || !efct->attached) {
+ pr_err("Device is not attached\n");
+ return -EIO;
+ }
+
+ if (efct_xport_control(efct->xport, EFCT_XPORT_SHUTDOWN))
+ efc_log_err(efct, "Transport Shutdown timed out\n");
+
+ for (i = 0; i < efct->n_msix_vec; i++)
+ disable_irq(pci_irq_vector(efct->pci, i));
+
+ efct_xport_detach(efct->xport);
+
+ efct_xport_free(efct->xport);
+ efct->xport = NULL;
+
+ efcport_destroy(efct->efcport);
+ kfree(efct->efcport);
+
+ efct->attached = false;
+
+ return 0;
+}
+
+static void
+efct_fw_write_cb(int status, u32 actual_write_length,
+ u32 change_status, void *arg)
+{
+ struct efct_fw_write_result *result = arg;
+
+ result->status = status;
+ result->actual_xfer = actual_write_length;
+ result->change_status = change_status;
+
+ complete(&result->done);
+}
+
+static int
+efct_firmware_write(struct efct *efct, const u8 *buf, size_t buf_len,
+ u8 *change_status)
+{
+ int rc = 0;
+ u32 bytes_left;
+ u32 xfer_size;
+ u32 offset;
+ struct efc_dma dma;
+ int last = 0;
+ struct efct_fw_write_result result;
+
+ init_completion(&result.done);
+
+ bytes_left = buf_len;
+ offset = 0;
+
+ dma.size = FW_WRITE_BUFSIZE;
+ dma.virt = dma_alloc_coherent(&efct->pci->dev,
+ dma.size, &dma.phys, GFP_DMA);
+ if (!dma.virt)
+ return -ENOMEM;
+
+ while (bytes_left > 0) {
+ if (bytes_left > FW_WRITE_BUFSIZE)
+ xfer_size = FW_WRITE_BUFSIZE;
+ else
+ xfer_size = bytes_left;
+
+ memcpy(dma.virt, buf + offset, xfer_size);
+
+ if (bytes_left == xfer_size)
+ last = 1;
+
+ efct_hw_firmware_write(&efct->hw, &dma, xfer_size, offset,
+ last, efct_fw_write_cb, &result);
+
+ if (wait_for_completion_interruptible(&result.done) != 0) {
+ rc = -ENXIO;
+ break;
+ }
+
+ if (result.actual_xfer == 0 || result.status != 0) {
+ rc = -EFAULT;
+ break;
+ }
+
+ if (last)
+ *change_status = result.change_status;
+
+ bytes_left -= result.actual_xfer;
+ offset += result.actual_xfer;
+ }
+
+ dma_free_coherent(&efct->pci->dev, dma.size, dma.virt, dma.phys);
+ return rc;
+}
+
+static int
+efct_fw_reset(struct efct *efct)
+{
+ /*
+ * Firmware reset to activate the new firmware.
+ * Function 0 will update and load the new firmware
+ * during attach.
+ */
+ if (timer_pending(&efct->xport->stats_timer))
+ del_timer(&efct->xport->stats_timer);
+
+ if (efct_hw_reset(&efct->hw, EFCT_HW_RESET_FIRMWARE)) {
+ efc_log_info(efct, "failed to reset firmware\n");
+ return -EIO;
+ }
+
+ efc_log_info(efct, "successfully reset firmware.Now resetting port\n");
+
+ efct_device_detach(efct);
+ return efct_device_attach(efct);
+}
+
+static int
+efct_request_firmware_update(struct efct *efct)
+{
+ int rc = 0;
+ u8 file_name[256], fw_change_status = 0;
+ const struct firmware *fw;
+ struct efct_hw_grp_hdr *fw_image;
+
+ snprintf(file_name, 256, "%s.grp", efct->model);
+
+ rc = request_firmware(&fw, file_name, &efct->pci->dev);
+ if (rc) {
+ efc_log_debug(efct, "Firmware file(%s) not found.\n", file_name);
+ return rc;
+ }
+
+ fw_image = (struct efct_hw_grp_hdr *)fw->data;
+
+ if (!strncmp(efct->hw.sli.fw_name[0], fw_image->revision,
+ strnlen(fw_image->revision, 16))) {
+ efc_log_debug(efct,
+ "Skip update. Firmware is already up to date.\n");
+ goto exit;
+ }
+
+ efc_log_info(efct, "Firmware update is initiated. %s -> %s\n",
+ efct->hw.sli.fw_name[0], fw_image->revision);
+
+ rc = efct_firmware_write(efct, fw->data, fw->size, &fw_change_status);
+ if (rc) {
+ efc_log_err(efct, "Firmware update failed. rc = %d\n", rc);
+ goto exit;
+ }
+
+ efc_log_info(efct, "Firmware updated successfully\n");
+ switch (fw_change_status) {
+ case 0x00:
+ efc_log_info(efct, "New firmware is active.\n");
+ break;
+ case 0x01:
+ efc_log_info(efct,
+ "System reboot needed to activate the new firmware\n");
+ break;
+ case 0x02:
+ case 0x03:
+ efc_log_info(efct,
+ "firmware reset to activate the new firmware\n");
+ efct_fw_reset(efct);
+ break;
+ default:
+ efc_log_info(efct, "Unexpected value change_status:%d\n",
+ fw_change_status);
+ break;
+ }
+
+exit:
+ release_firmware(fw);
+
+ return rc;
+}
+
+static void
+efct_device_free(struct efct *efct)
+{
+ if (efct) {
+ list_del(&efct->list_entry);
+ kfree(efct);
+ }
+}
+
+static int
+efct_device_interrupts_required(struct efct *efct)
+{
+ int rc;
+
+ rc = efct_hw_setup(&efct->hw, efct, efct->pci);
+ if (rc < 0)
+ return rc;
+
+ return efct->hw.config.n_eq;
+}
+
+static irqreturn_t
+efct_intr_thread(int irq, void *handle)
+{
+ struct efct_intr_context *intr_ctx = handle;
+ struct efct *efct = intr_ctx->efct;
+
+ efct_hw_process(&efct->hw, intr_ctx->index, efct->max_isr_time_msec);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+efct_intr_msix(int irq, void *handle)
+{
+ return IRQ_WAKE_THREAD;
+}
+
+static int
+efct_setup_msix(struct efct *efct, u32 num_intrs)
+{
+ int rc = 0, i;
+
+ if (!pci_find_capability(efct->pci, PCI_CAP_ID_MSIX)) {
+ dev_err(&efct->pci->dev,
+ "%s : MSI-X not available\n", __func__);
+ return -EIO;
+ }
+
+ efct->n_msix_vec = num_intrs;
+
+ rc = pci_alloc_irq_vectors(efct->pci, num_intrs, num_intrs,
+ PCI_IRQ_MSIX | PCI_IRQ_AFFINITY);
+
+ if (rc < 0) {
+ dev_err(&efct->pci->dev, "Failed to alloc irq : %d\n", rc);
+ return rc;
+ }
+
+ for (i = 0; i < num_intrs; i++) {
+ struct efct_intr_context *intr_ctx = NULL;
+
+ intr_ctx = &efct->intr_context[i];
+ intr_ctx->efct = efct;
+ intr_ctx->index = i;
+
+ rc = request_threaded_irq(pci_irq_vector(efct->pci, i),
+ efct_intr_msix, efct_intr_thread, 0,
+ EFCT_DRIVER_NAME, intr_ctx);
+ if (rc) {
+ dev_err(&efct->pci->dev,
+ "Failed to register %d vector: %d\n", i, rc);
+ goto out;
+ }
+ }
+
+ return rc;
+
+out:
+ while (--i >= 0)
+ free_irq(pci_irq_vector(efct->pci, i),
+ &efct->intr_context[i]);
+
+ pci_free_irq_vectors(efct->pci);
+ return rc;
+}
+
+static struct pci_device_id efct_pci_table[] = {
+ {PCI_DEVICE(EFCT_VENDOR_ID, EFCT_DEVICE_LANCER_G6), 0},
+ {PCI_DEVICE(EFCT_VENDOR_ID, EFCT_DEVICE_LANCER_G7), 0},
+ {} /* terminate list */
+};
+
+static int
+efct_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct efct *efct = NULL;
+ int rc;
+ u32 i, r;
+ int num_interrupts = 0;
+ int nid;
+
+ dev_info(&pdev->dev, "%s\n", EFCT_DRIVER_NAME);
+
+ rc = pci_enable_device_mem(pdev);
+ if (rc)
+ return rc;
+
+ pci_set_master(pdev);
+
+ rc = pci_set_mwi(pdev);
+ if (rc) {
+ dev_info(&pdev->dev, "pci_set_mwi returned %d\n", rc);
+ goto mwi_out;
+ }
+
+ rc = pci_request_regions(pdev, EFCT_DRIVER_NAME);
+ if (rc) {
+ dev_err(&pdev->dev, "pci_request_regions failed %d\n", rc);
+ goto req_regions_out;
+ }
+
+ /* Fetch the Numa node id for this device */
+ nid = dev_to_node(&pdev->dev);
+ if (nid < 0) {
+ dev_err(&pdev->dev, "Warning Numa node ID is %d\n", nid);
+ nid = 0;
+ }
+
+ /* Allocate efct */
+ efct = efct_device_alloc(nid);
+ if (!efct) {
+ dev_err(&pdev->dev, "Failed to allocate efct\n");
+ rc = -ENOMEM;
+ goto alloc_out;
+ }
+
+ efct->pci = pdev;
+ efct->numa_node = nid;
+
+ /* Map all memory BARs */
+ for (i = 0, r = 0; i < EFCT_PCI_MAX_REGS; i++) {
+ if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
+ efct->reg[r] = ioremap(pci_resource_start(pdev, i),
+ pci_resource_len(pdev, i));
+ r++;
+ }
+
+ /*
+ * If the 64-bit attribute is set, both this BAR and the
+ * next form the complete address. Skip processing the
+ * next BAR.
+ */
+ if (pci_resource_flags(pdev, i) & IORESOURCE_MEM_64)
+ i++;
+ }
+
+ pci_set_drvdata(pdev, efct);
+
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0 ||
+ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) {
+ dev_warn(&pdev->dev, "trying DMA_BIT_MASK(32)\n");
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0 ||
+ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
+ dev_err(&pdev->dev, "setting DMA_BIT_MASK failed\n");
+ rc = -1;
+ goto dma_mask_out;
+ }
+ }
+
+ num_interrupts = efct_device_interrupts_required(efct);
+ if (num_interrupts < 0) {
+ efc_log_err(efct, "efct_device_interrupts_required failed\n");
+ rc = -1;
+ goto dma_mask_out;
+ }
+
+ /*
+ * Initialize MSIX interrupts, note,
+ * efct_setup_msix() enables the interrupt
+ */
+ rc = efct_setup_msix(efct, num_interrupts);
+ if (rc) {
+ dev_err(&pdev->dev, "Can't setup msix\n");
+ goto dma_mask_out;
+ }
+ /* Disable interrupt for now */
+ for (i = 0; i < efct->n_msix_vec; i++) {
+ efc_log_debug(efct, "irq %d disabled\n", i);
+ disable_irq(pci_irq_vector(efct->pci, i));
+ }
+
+ rc = efct_device_attach(efct);
+ if (rc)
+ goto attach_out;
+
+ return 0;
+
+attach_out:
+ efct_teardown_msix(efct);
+dma_mask_out:
+ pci_set_drvdata(pdev, NULL);
+
+ for (i = 0; i < EFCT_PCI_MAX_REGS; i++) {
+ if (efct->reg[i])
+ iounmap(efct->reg[i]);
+ }
+ efct_device_free(efct);
+alloc_out:
+ pci_release_regions(pdev);
+req_regions_out:
+ pci_clear_mwi(pdev);
+mwi_out:
+ pci_disable_device(pdev);
+ return rc;
+}
+
+static void
+efct_pci_remove(struct pci_dev *pdev)
+{
+ struct efct *efct = pci_get_drvdata(pdev);
+ u32 i;
+
+ if (!efct)
+ return;
+
+ efct_device_detach(efct);
+
+ efct_teardown_msix(efct);
+
+ for (i = 0; i < EFCT_PCI_MAX_REGS; i++) {
+ if (efct->reg[i])
+ iounmap(efct->reg[i]);
+ }
+
+ pci_set_drvdata(pdev, NULL);
+
+ efct_device_free(efct);
+
+ pci_release_regions(pdev);
+
+ pci_disable_device(pdev);
+}
+
+static void
+efct_device_prep_for_reset(struct efct *efct, struct pci_dev *pdev)
+{
+ if (efct) {
+ efc_log_debug(efct,
+ "PCI channel disable preparing for reset\n");
+ efct_device_detach(efct);
+ /* Disable interrupt and pci device */
+ efct_teardown_msix(efct);
+ }
+ pci_disable_device(pdev);
+}
+
+static void
+efct_device_prep_for_recover(struct efct *efct)
+{
+ if (efct) {
+ efc_log_debug(efct, "PCI channel preparing for recovery\n");
+ efct_hw_io_abort_all(&efct->hw);
+ }
+}
+
+/**
+ * efct_pci_io_error_detected - method for handling PCI I/O error
+ * @pdev: pointer to PCI device.
+ * @state: the current PCI connection state.
+ *
+ * This routine is registered to the PCI subsystem for error handling. This
+ * function is called by the PCI subsystem after a PCI bus error affecting
+ * this device has been detected. When this routine is invoked, it dispatches
+ * device error detected handling routine, which will perform the proper
+ * error detected operation.
+ *
+ * Return codes
+ * PCI_ERS_RESULT_NEED_RESET - need to reset before recovery
+ * PCI_ERS_RESULT_DISCONNECT - device could not be recovered
+ */
+static pci_ers_result_t
+efct_pci_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+ struct efct *efct = pci_get_drvdata(pdev);
+ pci_ers_result_t rc;
+
+ switch (state) {
+ case pci_channel_io_normal:
+ efct_device_prep_for_recover(efct);
+ rc = PCI_ERS_RESULT_CAN_RECOVER;
+ break;
+ case pci_channel_io_frozen:
+ efct_device_prep_for_reset(efct, pdev);
+ rc = PCI_ERS_RESULT_NEED_RESET;
+ break;
+ case pci_channel_io_perm_failure:
+ efct_device_detach(efct);
+ rc = PCI_ERS_RESULT_DISCONNECT;
+ break;
+ default:
+ efc_log_debug(efct, "Unknown PCI error state:0x%x\n", state);
+ efct_device_prep_for_reset(efct, pdev);
+ rc = PCI_ERS_RESULT_NEED_RESET;
+ break;
+ }
+
+ return rc;
+}
+
+static pci_ers_result_t
+efct_pci_io_slot_reset(struct pci_dev *pdev)
+{
+ int rc;
+ struct efct *efct = pci_get_drvdata(pdev);
+
+ rc = pci_enable_device_mem(pdev);
+ if (rc) {
+ efc_log_err(efct, "failed to enable PCI device after reset\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ /*
+ * As the new kernel behavior of pci_restore_state() API call clears
+ * device saved_state flag, need to save the restored state again.
+ */
+
+ pci_save_state(pdev);
+
+ pci_set_master(pdev);
+
+ rc = efct_setup_msix(efct, efct->n_msix_vec);
+ if (rc)
+ efc_log_err(efct, "rc %d returned, IRQ allocation failed\n",
+ rc);
+
+ /* Perform device reset */
+ efct_device_detach(efct);
+ /* Bring device to online*/
+ efct_device_attach(efct);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void
+efct_pci_io_resume(struct pci_dev *pdev)
+{
+ struct efct *efct = pci_get_drvdata(pdev);
+
+ /* Perform device reset */
+ efct_device_detach(efct);
+ /* Bring device to online*/
+ efct_device_attach(efct);
+}
+
+MODULE_DEVICE_TABLE(pci, efct_pci_table);
+
+static struct pci_error_handlers efct_pci_err_handler = {
+ .error_detected = efct_pci_io_error_detected,
+ .slot_reset = efct_pci_io_slot_reset,
+ .resume = efct_pci_io_resume,
+};
+
+static struct pci_driver efct_pci_driver = {
+ .name = EFCT_DRIVER_NAME,
+ .id_table = efct_pci_table,
+ .probe = efct_pci_probe,
+ .remove = efct_pci_remove,
+ .err_handler = &efct_pci_err_handler,
+};
+
+static
+int __init efct_init(void)
+{
+ int rc;
+
+ rc = efct_device_init();
+ if (rc) {
+ pr_err("efct_device_init failed rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = pci_register_driver(&efct_pci_driver);
+ if (rc) {
+ pr_err("pci_register_driver failed rc=%d\n", rc);
+ efct_device_shutdown();
+ }
+
+ return rc;
+}
+
+static void __exit efct_exit(void)
+{
+ pci_unregister_driver(&efct_pci_driver);
+ efct_device_shutdown();
+}
+
+module_init(efct_init);
+module_exit(efct_exit);
+MODULE_VERSION(EFCT_DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Broadcom");
diff --git a/drivers/scsi/elx/efct/efct_driver.h b/drivers/scsi/elx/efct/efct_driver.h
new file mode 100644
index 000000000000..dab8eac4f243
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_driver.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#if !defined(__EFCT_DRIVER_H__)
+#define __EFCT_DRIVER_H__
+
+/***************************************************************************
+ * OS specific includes
+ */
+#include <stdarg.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/firmware.h>
+#include "../include/efc_common.h"
+#include "../libefc/efclib.h"
+#include "efct_hw.h"
+#include "efct_io.h"
+#include "efct_xport.h"
+
+#define EFCT_DRIVER_NAME "efct"
+#define EFCT_DRIVER_VERSION "1.0.0.0"
+
+/* EFCT_DEFAULT_FILTER-
+ * MRQ filter to segregate the IO flow.
+ */
+#define EFCT_DEFAULT_FILTER "0x01ff22ff,0,0,0"
+
+/* EFCT_OS_MAX_ISR_TIME_MSEC -
+ * maximum time driver code should spend in an interrupt
+ * or kernel thread context without yielding
+ */
+#define EFCT_OS_MAX_ISR_TIME_MSEC 1000
+
+#define EFCT_FC_MAX_SGL 64
+#define EFCT_FC_DIF_SEED 0
+
+/* Watermark */
+#define EFCT_WATERMARK_HIGH_PCT 90
+#define EFCT_WATERMARK_LOW_PCT 80
+#define EFCT_IO_WATERMARK_PER_INITIATOR 8
+
+#define EFCT_PCI_MAX_REGS 6
+#define MAX_PCI_INTERRUPTS 16
+
+struct efct_intr_context {
+ struct efct *efct;
+ u32 index;
+};
+
+struct efct {
+ struct pci_dev *pci;
+ void __iomem *reg[EFCT_PCI_MAX_REGS];
+
+ u32 n_msix_vec;
+ bool attached;
+ bool soft_wwn_enable;
+ u8 efct_req_fw_upgrade;
+ struct efct_intr_context intr_context[MAX_PCI_INTERRUPTS];
+ u32 numa_node;
+
+ char name[EFC_NAME_LENGTH];
+ u32 instance_index;
+ struct list_head list_entry;
+ struct efct_scsi_tgt tgt_efct;
+ struct efct_xport *xport;
+ struct efc *efcport;
+ struct Scsi_Host *shost;
+ int logmask;
+ u32 max_isr_time_msec;
+
+ const char *desc;
+
+ const char *model;
+
+ struct efct_hw hw;
+
+ u32 rq_selection_policy;
+ char *filter_def;
+ int topology;
+
+ /* Look up for target node */
+ struct xarray lookup;
+
+ /*
+ * Target IO timer value:
+ * Zero: target command timeout disabled.
+ * Non-zero: Timeout value, in seconds, for target commands
+ */
+ u32 target_io_timer_sec;
+
+ int speed;
+ struct dentry *sess_debugfs_dir;
+};
+
+#define FW_WRITE_BUFSIZE (64 * 1024)
+
+struct efct_fw_write_result {
+ struct completion done;
+ int status;
+ u32 actual_xfer;
+ u32 change_status;
+};
+
+extern struct list_head efct_devices;
+
+#endif /* __EFCT_DRIVER_H__ */
diff --git a/drivers/scsi/elx/efct/efct_hw.c b/drivers/scsi/elx/efct/efct_hw.c
new file mode 100644
index 000000000000..ba8256b4c782
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_hw.c
@@ -0,0 +1,3581 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#include "efct_driver.h"
+#include "efct_hw.h"
+#include "efct_unsol.h"
+
+struct efct_hw_link_stat_cb_arg {
+ void (*cb)(int status, u32 num_counters,
+ struct efct_hw_link_stat_counts *counters, void *arg);
+ void *arg;
+};
+
+struct efct_hw_host_stat_cb_arg {
+ void (*cb)(int status, u32 num_counters,
+ struct efct_hw_host_stat_counts *counters, void *arg);
+ void *arg;
+};
+
+struct efct_hw_fw_wr_cb_arg {
+ void (*cb)(int status, u32 bytes_written, u32 change_status, void *arg);
+ void *arg;
+};
+
+struct efct_mbox_rqst_ctx {
+ int (*callback)(struct efc *efc, int status, u8 *mqe, void *arg);
+ void *arg;
+};
+
+static int
+efct_hw_link_event_init(struct efct_hw *hw)
+{
+ hw->link.status = SLI4_LINK_STATUS_MAX;
+ hw->link.topology = SLI4_LINK_TOPO_NONE;
+ hw->link.medium = SLI4_LINK_MEDIUM_MAX;
+ hw->link.speed = 0;
+ hw->link.loop_map = NULL;
+ hw->link.fc_id = U32_MAX;
+
+ return 0;
+}
+
+static int
+efct_hw_read_max_dump_size(struct efct_hw *hw)
+{
+ u8 buf[SLI4_BMBX_SIZE];
+ struct efct *efct = hw->os;
+ int rc = 0;
+ struct sli4_rsp_cmn_set_dump_location *rsp;
+
+ /* attempt to detemine the dump size for function 0 only. */
+ if (PCI_FUNC(efct->pci->devfn) != 0)
+ return rc;
+
+ if (sli_cmd_common_set_dump_location(&hw->sli, buf, 1, 0, NULL, 0))
+ return -EIO;
+
+ rsp = (struct sli4_rsp_cmn_set_dump_location *)
+ (buf + offsetof(struct sli4_cmd_sli_config, payload.embed));
+
+ rc = efct_hw_command(hw, buf, EFCT_CMD_POLL, NULL, NULL);
+ if (rc != 0) {
+ efc_log_debug(hw->os, "set dump location cmd failed\n");
+ return rc;
+ }
+
+ hw->dump_size =
+ le32_to_cpu(rsp->buffer_length_dword) & SLI4_CMN_SET_DUMP_BUFFER_LEN;
+
+ efc_log_debug(hw->os, "Dump size %x\n", hw->dump_size);
+
+ return rc;
+}
+
+static int
+__efct_read_topology_cb(struct efct_hw *hw, int status, u8 *mqe, void *arg)
+{
+ struct sli4_cmd_read_topology *read_topo =
+ (struct sli4_cmd_read_topology *)mqe;
+ u8 speed;
+ struct efc_domain_record drec = {0};
+ struct efct *efct = hw->os;
+
+ if (status || le16_to_cpu(read_topo->hdr.status)) {
+ efc_log_debug(hw->os, "bad status cqe=%#x mqe=%#x\n", status,
+ le16_to_cpu(read_topo->hdr.status));
+ return -EIO;
+ }
+
+ switch (le32_to_cpu(read_topo->dw2_attentype) &
+ SLI4_READTOPO_ATTEN_TYPE) {
+ case SLI4_READ_TOPOLOGY_LINK_UP:
+ hw->link.status = SLI4_LINK_STATUS_UP;
+ break;
+ case SLI4_READ_TOPOLOGY_LINK_DOWN:
+ hw->link.status = SLI4_LINK_STATUS_DOWN;
+ break;
+ case SLI4_READ_TOPOLOGY_LINK_NO_ALPA:
+ hw->link.status = SLI4_LINK_STATUS_NO_ALPA;
+ break;
+ default:
+ hw->link.status = SLI4_LINK_STATUS_MAX;
+ break;
+ }
+
+ switch (read_topo->topology) {
+ case SLI4_READ_TOPO_NON_FC_AL:
+ hw->link.topology = SLI4_LINK_TOPO_NON_FC_AL;
+ break;
+ case SLI4_READ_TOPO_FC_AL:
+ hw->link.topology = SLI4_LINK_TOPO_FC_AL;
+ if (hw->link.status == SLI4_LINK_STATUS_UP)
+ hw->link.loop_map = hw->loop_map.virt;
+ hw->link.fc_id = read_topo->acquired_al_pa;
+ break;
+ default:
+ hw->link.topology = SLI4_LINK_TOPO_MAX;
+ break;
+ }
+
+ hw->link.medium = SLI4_LINK_MEDIUM_FC;
+
+ speed = (le32_to_cpu(read_topo->currlink_state) &
+ SLI4_READTOPO_LINKSTATE_SPEED) >> 8;
+ switch (speed) {
+ case SLI4_READ_TOPOLOGY_SPEED_1G:
+ hw->link.speed = 1 * 1000;
+ break;
+ case SLI4_READ_TOPOLOGY_SPEED_2G:
+ hw->link.speed = 2 * 1000;
+ break;
+ case SLI4_READ_TOPOLOGY_SPEED_4G:
+ hw->link.speed = 4 * 1000;
+ break;
+ case SLI4_READ_TOPOLOGY_SPEED_8G:
+ hw->link.speed = 8 * 1000;
+ break;
+ case SLI4_READ_TOPOLOGY_SPEED_16G:
+ hw->link.speed = 16 * 1000;
+ break;
+ case SLI4_READ_TOPOLOGY_SPEED_32G:
+ hw->link.speed = 32 * 1000;
+ break;
+ case SLI4_READ_TOPOLOGY_SPEED_64G:
+ hw->link.speed = 64 * 1000;
+ break;
+ case SLI4_READ_TOPOLOGY_SPEED_128G:
+ hw->link.speed = 128 * 1000;
+ break;
+ }
+
+ drec.speed = hw->link.speed;
+ drec.fc_id = hw->link.fc_id;
+ drec.is_nport = true;
+ efc_domain_cb(efct->efcport, EFC_HW_DOMAIN_FOUND, &drec);
+
+ return 0;
+}
+
+static int
+efct_hw_cb_link(void *ctx, void *e)
+{
+ struct efct_hw *hw = ctx;
+ struct sli4_link_event *event = e;
+ struct efc_domain *d = NULL;
+ int rc = 0;
+ struct efct *efct = hw->os;
+
+ efct_hw_link_event_init(hw);
+
+ switch (event->status) {
+ case SLI4_LINK_STATUS_UP:
+
+ hw->link = *event;
+ efct->efcport->link_status = EFC_LINK_STATUS_UP;
+
+ if (event->topology == SLI4_LINK_TOPO_NON_FC_AL) {
+ struct efc_domain_record drec = {0};
+
+ efc_log_info(hw->os, "Link Up, NPORT, speed is %d\n",
+ event->speed);
+ drec.speed = event->speed;
+ drec.fc_id = event->fc_id;
+ drec.is_nport = true;
+ efc_domain_cb(efct->efcport, EFC_HW_DOMAIN_FOUND,
+ &drec);
+ } else if (event->topology == SLI4_LINK_TOPO_FC_AL) {
+ u8 buf[SLI4_BMBX_SIZE];
+
+ efc_log_info(hw->os, "Link Up, LOOP, speed is %d\n",
+ event->speed);
+
+ if (!sli_cmd_read_topology(&hw->sli, buf,
+ &hw->loop_map)) {
+ rc = efct_hw_command(hw, buf, EFCT_CMD_NOWAIT,
+ __efct_read_topology_cb, NULL);
+ }
+
+ if (rc)
+ efc_log_debug(hw->os, "READ_TOPOLOGY failed\n");
+ } else {
+ efc_log_info(hw->os, "%s(%#x), speed is %d\n",
+ "Link Up, unsupported topology ",
+ event->topology, event->speed);
+ }
+ break;
+ case SLI4_LINK_STATUS_DOWN:
+ efc_log_info(hw->os, "Link down\n");
+
+ hw->link.status = event->status;
+ efct->efcport->link_status = EFC_LINK_STATUS_DOWN;
+
+ d = efct->efcport->domain;
+ if (d)
+ efc_domain_cb(efct->efcport, EFC_HW_DOMAIN_LOST, d);
+ break;
+ default:
+ efc_log_debug(hw->os, "unhandled link status %#x\n",
+ event->status);
+ break;
+ }
+
+ return 0;
+}
+
+int
+efct_hw_setup(struct efct_hw *hw, void *os, struct pci_dev *pdev)
+{
+ u32 i, max_sgl, cpus;
+
+ if (hw->hw_setup_called)
+ return 0;
+
+ /*
+ * efct_hw_init() relies on NULL pointers indicating that a structure
+ * needs allocation. If a structure is non-NULL, efct_hw_init() won't
+ * free/realloc that memory
+ */
+ memset(hw, 0, sizeof(struct efct_hw));
+
+ hw->hw_setup_called = true;
+
+ hw->os = os;
+
+ mutex_init(&hw->bmbx_lock);
+ spin_lock_init(&hw->cmd_lock);
+ INIT_LIST_HEAD(&hw->cmd_head);
+ INIT_LIST_HEAD(&hw->cmd_pending);
+ hw->cmd_head_count = 0;
+
+ /* Create mailbox command ctx pool */
+ hw->cmd_ctx_pool = mempool_create_kmalloc_pool(EFCT_CMD_CTX_POOL_SZ,
+ sizeof(struct efct_command_ctx));
+ if (!hw->cmd_ctx_pool) {
+ efc_log_err(hw->os, "failed to allocate mailbox buffer pool\n");
+ return -EIO;
+ }
+
+ /* Create mailbox request ctx pool for library callback */
+ hw->mbox_rqst_pool = mempool_create_kmalloc_pool(EFCT_CMD_CTX_POOL_SZ,
+ sizeof(struct efct_mbox_rqst_ctx));
+ if (!hw->mbox_rqst_pool) {
+ efc_log_err(hw->os, "failed to allocate mbox request pool\n");
+ return -EIO;
+ }
+
+ spin_lock_init(&hw->io_lock);
+ INIT_LIST_HEAD(&hw->io_inuse);
+ INIT_LIST_HEAD(&hw->io_free);
+ INIT_LIST_HEAD(&hw->io_wait_free);
+
+ atomic_set(&hw->io_alloc_failed_count, 0);
+
+ hw->config.speed = SLI4_LINK_SPEED_AUTO_16_8_4;
+ if (sli_setup(&hw->sli, hw->os, pdev, ((struct efct *)os)->reg)) {
+ efc_log_err(hw->os, "SLI setup failed\n");
+ return -EIO;
+ }
+
+ efct_hw_link_event_init(hw);
+
+ sli_callback(&hw->sli, SLI4_CB_LINK, efct_hw_cb_link, hw);
+
+ /*
+ * Set all the queue sizes to the maximum allowed.
+ */
+ for (i = 0; i < ARRAY_SIZE(hw->num_qentries); i++)
+ hw->num_qentries[i] = hw->sli.qinfo.max_qentries[i];
+ /*
+ * Adjust the size of the WQs so that the CQ is twice as big as
+ * the WQ to allow for 2 completions per IO. This allows us to
+ * handle multi-phase as well as aborts.
+ */
+ hw->num_qentries[SLI4_QTYPE_WQ] = hw->num_qentries[SLI4_QTYPE_CQ] / 2;
+
+ /*
+ * The RQ assignment for RQ pair mode.
+ */
+
+ hw->config.rq_default_buffer_size = EFCT_HW_RQ_SIZE_PAYLOAD;
+ hw->config.n_io = hw->sli.ext[SLI4_RSRC_XRI].size;
+
+ cpus = num_possible_cpus();
+ hw->config.n_eq = cpus > EFCT_HW_MAX_NUM_EQ ? EFCT_HW_MAX_NUM_EQ : cpus;
+
+ max_sgl = sli_get_max_sgl(&hw->sli) - SLI4_SGE_MAX_RESERVED;
+ max_sgl = (max_sgl > EFCT_FC_MAX_SGL) ? EFCT_FC_MAX_SGL : max_sgl;
+ hw->config.n_sgl = max_sgl;
+
+ (void)efct_hw_read_max_dump_size(hw);
+
+ return 0;
+}
+
+static void
+efct_logfcfi(struct efct_hw *hw, u32 j, u32 i, u32 id)
+{
+ efc_log_info(hw->os,
+ "REG_FCFI: filter[%d] %08X -> RQ[%d] id=%d\n",
+ j, hw->config.filter_def[j], i, id);
+}
+
+static inline void
+efct_hw_init_free_io(struct efct_hw_io *io)
+{
+ /*
+ * Set io->done to NULL, to avoid any callbacks, should
+ * a completion be received for one of these IOs
+ */
+ io->done = NULL;
+ io->abort_done = NULL;
+ io->status_saved = false;
+ io->abort_in_progress = false;
+ io->type = 0xFFFF;
+ io->wq = NULL;
+}
+
+static bool efct_hw_iotype_is_originator(u16 io_type)
+{
+ switch (io_type) {
+ case EFCT_HW_FC_CT:
+ case EFCT_HW_ELS_REQ:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void
+efct_hw_io_restore_sgl(struct efct_hw *hw, struct efct_hw_io *io)
+{
+ /* Restore the default */
+ io->sgl = &io->def_sgl;
+ io->sgl_count = io->def_sgl_count;
+}
+
+static void
+efct_hw_wq_process_io(void *arg, u8 *cqe, int status)
+{
+ struct efct_hw_io *io = arg;
+ struct efct_hw *hw = io->hw;
+ struct sli4_fc_wcqe *wcqe = (void *)cqe;
+ u32 len = 0;
+ u32 ext = 0;
+
+ /* clear xbusy flag if WCQE[XB] is clear */
+ if (io->xbusy && (wcqe->flags & SLI4_WCQE_XB) == 0)
+ io->xbusy = false;
+
+ /* get extended CQE status */
+ switch (io->type) {
+ case EFCT_HW_BLS_ACC:
+ case EFCT_HW_BLS_RJT:
+ break;
+ case EFCT_HW_ELS_REQ:
+ sli_fc_els_did(&hw->sli, cqe, &ext);
+ len = sli_fc_response_length(&hw->sli, cqe);
+ break;
+ case EFCT_HW_ELS_RSP:
+ case EFCT_HW_FC_CT_RSP:
+ break;
+ case EFCT_HW_FC_CT:
+ len = sli_fc_response_length(&hw->sli, cqe);
+ break;
+ case EFCT_HW_IO_TARGET_WRITE:
+ len = sli_fc_io_length(&hw->sli, cqe);
+ break;
+ case EFCT_HW_IO_TARGET_READ:
+ len = sli_fc_io_length(&hw->sli, cqe);
+ break;
+ case EFCT_HW_IO_TARGET_RSP:
+ break;
+ case EFCT_HW_IO_DNRX_REQUEUE:
+ /* release the count for re-posting the buffer */
+ /* efct_hw_io_free(hw, io); */
+ break;
+ default:
+ efc_log_err(hw->os, "unhandled io type %#x for XRI 0x%x\n",
+ io->type, io->indicator);
+ break;
+ }
+ if (status) {
+ ext = sli_fc_ext_status(&hw->sli, cqe);
+ /*
+ * If we're not an originator IO, and XB is set, then issue
+ * abort for the IO from within the HW
+ */
+ if (efct_hw_iotype_is_originator(io->type) &&
+ wcqe->flags & SLI4_WCQE_XB) {
+ int rc;
+
+ efc_log_debug(hw->os, "aborting xri=%#x tag=%#x\n",
+ io->indicator, io->reqtag);
+
+ /*
+ * Because targets may send a response when the IO
+ * completes using the same XRI, we must wait for the
+ * XRI_ABORTED CQE to issue the IO callback
+ */
+ rc = efct_hw_io_abort(hw, io, false, NULL, NULL);
+ if (rc == 0) {
+ /*
+ * latch status to return after abort is
+ * complete
+ */
+ io->status_saved = true;
+ io->saved_status = status;
+ io->saved_ext = ext;
+ io->saved_len = len;
+ goto exit_efct_hw_wq_process_io;
+ } else if (rc == -EINPROGRESS) {
+ /*
+ * Already being aborted by someone else (ABTS
+ * perhaps). Just return original
+ * error.
+ */
+ efc_log_debug(hw->os, "%s%#x tag=%#x\n",
+ "abort in progress xri=",
+ io->indicator, io->reqtag);
+
+ } else {
+ /* Failed to abort for some other reason, log
+ * error
+ */
+ efc_log_debug(hw->os, "%s%#x tag=%#x rc=%d\n",
+ "Failed to abort xri=",
+ io->indicator, io->reqtag, rc);
+ }
+ }
+ }
+
+ if (io->done) {
+ efct_hw_done_t done = io->done;
+
+ io->done = NULL;
+
+ if (io->status_saved) {
+ /* use latched status if exists */
+ status = io->saved_status;
+ len = io->saved_len;
+ ext = io->saved_ext;
+ io->status_saved = false;
+ }
+
+ /* Restore default SGL */
+ efct_hw_io_restore_sgl(hw, io);
+ done(io, len, status, ext, io->arg);
+ }
+
+exit_efct_hw_wq_process_io:
+ return;
+}
+
+static int
+efct_hw_setup_io(struct efct_hw *hw)
+{
+ u32 i = 0;
+ struct efct_hw_io *io = NULL;
+ uintptr_t xfer_virt = 0;
+ uintptr_t xfer_phys = 0;
+ u32 index;
+ bool new_alloc = true;
+ struct efc_dma *dma;
+ struct efct *efct = hw->os;
+
+ if (!hw->io) {
+ hw->io = kmalloc_array(hw->config.n_io, sizeof(io), GFP_KERNEL);
+ if (!hw->io)
+ return -ENOMEM;
+
+ memset(hw->io, 0, hw->config.n_io * sizeof(io));
+
+ for (i = 0; i < hw->config.n_io; i++) {
+ hw->io[i] = kzalloc(sizeof(*io), GFP_KERNEL);
+ if (!hw->io[i])
+ goto error;
+ }
+
+ /* Create WQE buffs for IO */
+ hw->wqe_buffs = kzalloc((hw->config.n_io * hw->sli.wqe_size),
+ GFP_KERNEL);
+ if (!hw->wqe_buffs) {
+ kfree(hw->io);
+ return -ENOMEM;
+ }
+
+ } else {
+ /* re-use existing IOs, including SGLs */
+ new_alloc = false;
+ }
+
+ if (new_alloc) {
+ dma = &hw->xfer_rdy;
+ dma->size = sizeof(struct fcp_txrdy) * hw->config.n_io;
+ dma->virt = dma_alloc_coherent(&efct->pci->dev,
+ dma->size, &dma->phys, GFP_DMA);
+ if (!dma->virt)
+ return -ENOMEM;
+ }
+ xfer_virt = (uintptr_t)hw->xfer_rdy.virt;
+ xfer_phys = hw->xfer_rdy.phys;
+
+ /* Initialize the pool of HW IO objects */
+ for (i = 0; i < hw->config.n_io; i++) {
+ struct hw_wq_callback *wqcb;
+
+ io = hw->io[i];
+
+ /* initialize IO fields */
+ io->hw = hw;
+
+ /* Assign a WQE buff */
+ io->wqe.wqebuf = &hw->wqe_buffs[i * hw->sli.wqe_size];
+
+ /* Allocate the request tag for this IO */
+ wqcb = efct_hw_reqtag_alloc(hw, efct_hw_wq_process_io, io);
+ if (!wqcb) {
+ efc_log_err(hw->os, "can't allocate request tag\n");
+ return -ENOSPC;
+ }
+ io->reqtag = wqcb->instance_index;
+
+ /* Now for the fields that are initialized on each free */
+ efct_hw_init_free_io(io);
+
+ /* The XB flag isn't cleared on IO free, so init to zero */
+ io->xbusy = 0;
+
+ if (sli_resource_alloc(&hw->sli, SLI4_RSRC_XRI,
+ &io->indicator, &index)) {
+ efc_log_err(hw->os,
+ "sli_resource_alloc failed @ %d\n", i);
+ return -ENOMEM;
+ }
+
+ if (new_alloc) {
+ dma = &io->def_sgl;
+ dma->size = hw->config.n_sgl *
+ sizeof(struct sli4_sge);
+ dma->virt = dma_alloc_coherent(&efct->pci->dev,
+ dma->size, &dma->phys,
+ GFP_DMA);
+ if (!dma->virt) {
+ efc_log_err(hw->os, "dma_alloc fail %d\n", i);
+ memset(&io->def_sgl, 0,
+ sizeof(struct efc_dma));
+ return -ENOMEM;
+ }
+ }
+ io->def_sgl_count = hw->config.n_sgl;
+ io->sgl = &io->def_sgl;
+ io->sgl_count = io->def_sgl_count;
+
+ if (hw->xfer_rdy.size) {
+ io->xfer_rdy.virt = (void *)xfer_virt;
+ io->xfer_rdy.phys = xfer_phys;
+ io->xfer_rdy.size = sizeof(struct fcp_txrdy);
+
+ xfer_virt += sizeof(struct fcp_txrdy);
+ xfer_phys += sizeof(struct fcp_txrdy);
+ }
+ }
+
+ return 0;
+error:
+ for (i = 0; i < hw->config.n_io && hw->io[i]; i++) {
+ kfree(hw->io[i]);
+ hw->io[i] = NULL;
+ }
+
+ kfree(hw->io);
+ hw->io = NULL;
+
+ return -ENOMEM;
+}
+
+static int
+efct_hw_init_prereg_io(struct efct_hw *hw)
+{
+ u32 i, idx = 0;
+ struct efct_hw_io *io = NULL;
+ u8 cmd[SLI4_BMBX_SIZE];
+ int rc = 0;
+ u32 n_rem;
+ u32 n = 0;
+ u32 sgls_per_request = 256;
+ struct efc_dma **sgls = NULL;
+ struct efc_dma req;
+ struct efct *efct = hw->os;
+
+ sgls = kmalloc_array(sgls_per_request, sizeof(*sgls), GFP_KERNEL);
+ if (!sgls)
+ return -ENOMEM;
+
+ memset(&req, 0, sizeof(struct efc_dma));
+ req.size = 32 + sgls_per_request * 16;
+ req.virt = dma_alloc_coherent(&efct->pci->dev, req.size, &req.phys,
+ GFP_DMA);
+ if (!req.virt) {
+ kfree(sgls);
+ return -ENOMEM;
+ }
+
+ for (n_rem = hw->config.n_io; n_rem; n_rem -= n) {
+ /* Copy address of SGL's into local sgls[] array, break
+ * out if the xri is not contiguous.
+ */
+ u32 min = (sgls_per_request < n_rem) ? sgls_per_request : n_rem;
+
+ for (n = 0; n < min; n++) {
+ /* Check that we have contiguous xri values */
+ if (n > 0) {
+ if (hw->io[idx + n]->indicator !=
+ hw->io[idx + n - 1]->indicator + 1)
+ break;
+ }
+
+ sgls[n] = hw->io[idx + n]->sgl;
+ }
+
+ if (sli_cmd_post_sgl_pages(&hw->sli, cmd,
+ hw->io[idx]->indicator, n, sgls, NULL, &req)) {
+ rc = -EIO;
+ break;
+ }
+
+ rc = efct_hw_command(hw, cmd, EFCT_CMD_POLL, NULL, NULL);
+ if (rc) {
+ efc_log_err(hw->os, "SGL post failed, rc=%d\n", rc);
+ break;
+ }
+
+ /* Add to tail if successful */
+ for (i = 0; i < n; i++, idx++) {
+ io = hw->io[idx];
+ io->state = EFCT_HW_IO_STATE_FREE;
+ INIT_LIST_HEAD(&io->list_entry);
+ list_add_tail(&io->list_entry, &hw->io_free);
+ }
+ }
+
+ dma_free_coherent(&efct->pci->dev, req.size, req.virt, req.phys);
+ memset(&req, 0, sizeof(struct efc_dma));
+ kfree(sgls);
+
+ return rc;
+}
+
+static int
+efct_hw_init_io(struct efct_hw *hw)
+{
+ u32 i, idx = 0;
+ bool prereg = false;
+ struct efct_hw_io *io = NULL;
+ int rc = 0;
+
+ prereg = hw->sli.params.sgl_pre_registered;
+
+ if (prereg)
+ return efct_hw_init_prereg_io(hw);
+
+ for (i = 0; i < hw->config.n_io; i++, idx++) {
+ io = hw->io[idx];
+ io->state = EFCT_HW_IO_STATE_FREE;
+ INIT_LIST_HEAD(&io->list_entry);
+ list_add_tail(&io->list_entry, &hw->io_free);
+ }
+
+ return rc;
+}
+
+static int
+efct_hw_config_set_fdt_xfer_hint(struct efct_hw *hw, u32 fdt_xfer_hint)
+{
+ int rc = 0;
+ u8 buf[SLI4_BMBX_SIZE];
+ struct sli4_rqst_cmn_set_features_set_fdt_xfer_hint param;
+
+ memset(&param, 0, sizeof(param));
+ param.fdt_xfer_hint = cpu_to_le32(fdt_xfer_hint);
+ /* build the set_features command */
+ sli_cmd_common_set_features(&hw->sli, buf,
+ SLI4_SET_FEATURES_SET_FTD_XFER_HINT, sizeof(param), &param);
+
+ rc = efct_hw_command(hw, buf, EFCT_CMD_POLL, NULL, NULL);
+ if (rc)
+ efc_log_warn(hw->os, "set FDT hint %d failed: %d\n",
+ fdt_xfer_hint, rc);
+ else
+ efc_log_info(hw->os, "Set FTD transfer hint to %d\n",
+ le32_to_cpu(param.fdt_xfer_hint));
+
+ return rc;
+}
+
+static int
+efct_hw_config_rq(struct efct_hw *hw)
+{
+ u32 min_rq_count, i, rc;
+ struct sli4_cmd_rq_cfg rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG];
+ u8 buf[SLI4_BMBX_SIZE];
+
+ efc_log_info(hw->os, "using REG_FCFI standard\n");
+
+ /*
+ * Set the filter match/mask values from hw's
+ * filter_def values
+ */
+ for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) {
+ rq_cfg[i].rq_id = cpu_to_le16(0xffff);
+ rq_cfg[i].r_ctl_mask = (u8)hw->config.filter_def[i];
+ rq_cfg[i].r_ctl_match = (u8)(hw->config.filter_def[i] >> 8);
+ rq_cfg[i].type_mask = (u8)(hw->config.filter_def[i] >> 16);
+ rq_cfg[i].type_match = (u8)(hw->config.filter_def[i] >> 24);
+ }
+
+ /*
+ * Update the rq_id's of the FCF configuration
+ * (don't update more than the number of rq_cfg
+ * elements)
+ */
+ min_rq_count = (hw->hw_rq_count < SLI4_CMD_REG_FCFI_NUM_RQ_CFG) ?
+ hw->hw_rq_count : SLI4_CMD_REG_FCFI_NUM_RQ_CFG;
+ for (i = 0; i < min_rq_count; i++) {
+ struct hw_rq *rq = hw->hw_rq[i];
+ u32 j;
+
+ for (j = 0; j < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; j++) {
+ u32 mask = (rq->filter_mask != 0) ?
+ rq->filter_mask : 1;
+
+ if (!(mask & (1U << j)))
+ continue;
+
+ rq_cfg[i].rq_id = cpu_to_le16(rq->hdr->id);
+ efct_logfcfi(hw, j, i, rq->hdr->id);
+ }
+ }
+
+ rc = -EIO;
+ if (!sli_cmd_reg_fcfi(&hw->sli, buf, 0, rq_cfg))
+ rc = efct_hw_command(hw, buf, EFCT_CMD_POLL, NULL, NULL);
+
+ if (rc != 0) {
+ efc_log_err(hw->os, "FCFI registration failed\n");
+ return rc;
+ }
+ hw->fcf_indicator =
+ le16_to_cpu(((struct sli4_cmd_reg_fcfi *)buf)->fcfi);
+
+ return rc;
+}
+
+static int
+efct_hw_config_mrq(struct efct_hw *hw, u8 mode, u16 fcf_index)
+{
+ u8 buf[SLI4_BMBX_SIZE], mrq_bitmask = 0;
+ struct hw_rq *rq;
+ struct sli4_cmd_reg_fcfi_mrq *rsp = NULL;
+ struct sli4_cmd_rq_cfg rq_filter[SLI4_CMD_REG_FCFI_MRQ_NUM_RQ_CFG];
+ u32 rc, i;
+
+ if (mode == SLI4_CMD_REG_FCFI_SET_FCFI_MODE)
+ goto issue_cmd;
+
+ /* Set the filter match/mask values from hw's filter_def values */
+ for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) {
+ rq_filter[i].rq_id = cpu_to_le16(0xffff);
+ rq_filter[i].type_mask = (u8)hw->config.filter_def[i];
+ rq_filter[i].type_match = (u8)(hw->config.filter_def[i] >> 8);
+ rq_filter[i].r_ctl_mask = (u8)(hw->config.filter_def[i] >> 16);
+ rq_filter[i].r_ctl_match = (u8)(hw->config.filter_def[i] >> 24);
+ }
+
+ rq = hw->hw_rq[0];
+ rq_filter[0].rq_id = cpu_to_le16(rq->hdr->id);
+ rq_filter[1].rq_id = cpu_to_le16(rq->hdr->id);
+
+ mrq_bitmask = 0x2;
+issue_cmd:
+ efc_log_debug(hw->os, "Issue reg_fcfi_mrq count:%d policy:%d mode:%d\n",
+ hw->hw_rq_count, hw->config.rq_selection_policy, mode);
+ /* Invoke REG_FCFI_MRQ */
+ rc = sli_cmd_reg_fcfi_mrq(&hw->sli, buf, mode, fcf_index,
+ hw->config.rq_selection_policy, mrq_bitmask,
+ hw->hw_mrq_count, rq_filter);
+ if (rc) {
+ efc_log_err(hw->os, "sli_cmd_reg_fcfi_mrq() failed\n");
+ return -EIO;
+ }
+
+ rc = efct_hw_command(hw, buf, EFCT_CMD_POLL, NULL, NULL);
+
+ rsp = (struct sli4_cmd_reg_fcfi_mrq *)buf;
+
+ if ((rc) || (le16_to_cpu(rsp->hdr.status))) {
+ efc_log_err(hw->os, "FCFI MRQ reg failed. cmd=%x status=%x\n",
+ rsp->hdr.command, le16_to_cpu(rsp->hdr.status));
+ return -EIO;
+ }
+
+ if (mode == SLI4_CMD_REG_FCFI_SET_FCFI_MODE)
+ hw->fcf_indicator = le16_to_cpu(rsp->fcfi);
+
+ return 0;
+}
+
+static void
+efct_hw_queue_hash_add(struct efct_queue_hash *hash,
+ u16 id, u16 index)
+{
+ u32 hash_index = id & (EFCT_HW_Q_HASH_SIZE - 1);
+
+ /*
+ * Since the hash is always bigger than the number of queues, then we
+ * never have to worry about an infinite loop.
+ */
+ while (hash[hash_index].in_use)
+ hash_index = (hash_index + 1) & (EFCT_HW_Q_HASH_SIZE - 1);
+
+ /* not used, claim the entry */
+ hash[hash_index].id = id;
+ hash[hash_index].in_use = true;
+ hash[hash_index].index = index;
+}
+
+static int
+efct_hw_config_sli_port_health_check(struct efct_hw *hw, u8 query, u8 enable)
+{
+ int rc = 0;
+ u8 buf[SLI4_BMBX_SIZE];
+ struct sli4_rqst_cmn_set_features_health_check param;
+ u32 health_check_flag = 0;
+
+ memset(&param, 0, sizeof(param));
+
+ if (enable)
+ health_check_flag |= SLI4_RQ_HEALTH_CHECK_ENABLE;
+
+ if (query)
+ health_check_flag |= SLI4_RQ_HEALTH_CHECK_QUERY;
+
+ param.health_check_dword = cpu_to_le32(health_check_flag);
+
+ /* build the set_features command */
+ sli_cmd_common_set_features(&hw->sli, buf,
+ SLI4_SET_FEATURES_SLI_PORT_HEALTH_CHECK, sizeof(param), &param);
+
+ rc = efct_hw_command(hw, buf, EFCT_CMD_POLL, NULL, NULL);
+ if (rc)
+ efc_log_err(hw->os, "efct_hw_command returns %d\n", rc);
+ else
+ efc_log_debug(hw->os, "SLI Port Health Check is enabled\n");
+
+ return rc;
+}
+
+int
+efct_hw_init(struct efct_hw *hw)
+{
+ int rc;
+ u32 i = 0;
+ int rem_count;
+ unsigned long flags = 0;
+ struct efct_hw_io *temp;
+ struct efc_dma *dma;
+
+ /*
+ * Make sure the command lists are empty. If this is start-of-day,
+ * they'll be empty since they were just initialized in efct_hw_setup.
+ * If we've just gone through a reset, the command and command pending
+ * lists should have been cleaned up as part of the reset
+ * (efct_hw_reset()).
+ */
+ spin_lock_irqsave(&hw->cmd_lock, flags);
+ if (!list_empty(&hw->cmd_head)) {
+ spin_unlock_irqrestore(&hw->cmd_lock, flags);
+ efc_log_err(hw->os, "command found on cmd list\n");
+ return -EIO;
+ }
+ if (!list_empty(&hw->cmd_pending)) {
+ spin_unlock_irqrestore(&hw->cmd_lock, flags);
+ efc_log_err(hw->os, "command found on pending list\n");
+ return -EIO;
+ }
+ spin_unlock_irqrestore(&hw->cmd_lock, flags);
+
+ /* Free RQ buffers if prevously allocated */
+ efct_hw_rx_free(hw);
+
+ /*
+ * The IO queues must be initialized here for the reset case. The
+ * efct_hw_init_io() function will re-add the IOs to the free list.
+ * The cmd_head list should be OK since we free all entries in
+ * efct_hw_command_cancel() that is called in the efct_hw_reset().
+ */
+
+ /* If we are in this function due to a reset, there may be stale items
+ * on lists that need to be removed. Clean them up.
+ */
+ rem_count = 0;
+ while ((!list_empty(&hw->io_wait_free))) {
+ rem_count++;
+ temp = list_first_entry(&hw->io_wait_free, struct efct_hw_io,
+ list_entry);
+ list_del_init(&temp->list_entry);
+ }
+ if (rem_count > 0)
+ efc_log_debug(hw->os, "rmvd %d items from io_wait_free list\n",
+ rem_count);
+
+ rem_count = 0;
+ while ((!list_empty(&hw->io_inuse))) {
+ rem_count++;
+ temp = list_first_entry(&hw->io_inuse, struct efct_hw_io,
+ list_entry);
+ list_del_init(&temp->list_entry);
+ }
+ if (rem_count > 0)
+ efc_log_debug(hw->os, "rmvd %d items from io_inuse list\n",
+ rem_count);
+
+ rem_count = 0;
+ while ((!list_empty(&hw->io_free))) {
+ rem_count++;
+ temp = list_first_entry(&hw->io_free, struct efct_hw_io,
+ list_entry);
+ list_del_init(&temp->list_entry);
+ }
+ if (rem_count > 0)
+ efc_log_debug(hw->os, "rmvd %d items from io_free list\n",
+ rem_count);
+
+ /* If MRQ not required, Make sure we dont request feature. */
+ if (hw->config.n_rq == 1)
+ hw->sli.features &= (~SLI4_REQFEAT_MRQP);
+
+ if (sli_init(&hw->sli)) {
+ efc_log_err(hw->os, "SLI failed to initialize\n");
+ return -EIO;
+ }
+
+ if (hw->sliport_healthcheck) {
+ rc = efct_hw_config_sli_port_health_check(hw, 0, 1);
+ if (rc != 0) {
+ efc_log_err(hw->os, "Enable port Health check fail\n");
+ return rc;
+ }
+ }
+
+ /*
+ * Set FDT transfer hint, only works on Lancer
+ */
+ if (hw->sli.if_type == SLI4_INTF_IF_TYPE_2) {
+ /*
+ * Non-fatal error. In particular, we can disregard failure to
+ * set EFCT_HW_FDT_XFER_HINT on devices with legacy firmware
+ * that do not support EFCT_HW_FDT_XFER_HINT feature.
+ */
+ efct_hw_config_set_fdt_xfer_hint(hw, EFCT_HW_FDT_XFER_HINT);
+ }
+
+ /* zero the hashes */
+ memset(hw->cq_hash, 0, sizeof(hw->cq_hash));
+ efc_log_debug(hw->os, "Max CQs %d, hash size = %d\n",
+ EFCT_HW_MAX_NUM_CQ, EFCT_HW_Q_HASH_SIZE);
+
+ memset(hw->rq_hash, 0, sizeof(hw->rq_hash));
+ efc_log_debug(hw->os, "Max RQs %d, hash size = %d\n",
+ EFCT_HW_MAX_NUM_RQ, EFCT_HW_Q_HASH_SIZE);
+
+ memset(hw->wq_hash, 0, sizeof(hw->wq_hash));
+ efc_log_debug(hw->os, "Max WQs %d, hash size = %d\n",
+ EFCT_HW_MAX_NUM_WQ, EFCT_HW_Q_HASH_SIZE);
+
+ rc = efct_hw_init_queues(hw);
+ if (rc)
+ return rc;
+
+ rc = efct_hw_map_wq_cpu(hw);
+ if (rc)
+ return rc;
+
+ /* Allocate and p_st RQ buffers */
+ rc = efct_hw_rx_allocate(hw);
+ if (rc) {
+ efc_log_err(hw->os, "rx_allocate failed\n");
+ return rc;
+ }
+
+ rc = efct_hw_rx_post(hw);
+ if (rc) {
+ efc_log_err(hw->os, "WARNING - error posting RQ buffers\n");
+ return rc;
+ }
+
+ if (hw->config.n_eq == 1) {
+ rc = efct_hw_config_rq(hw);
+ if (rc) {
+ efc_log_err(hw->os, "config rq failed %d\n", rc);
+ return rc;
+ }
+ } else {
+ rc = efct_hw_config_mrq(hw, SLI4_CMD_REG_FCFI_SET_FCFI_MODE, 0);
+ if (rc != 0) {
+ efc_log_err(hw->os, "REG_FCFI_MRQ FCFI reg failed\n");
+ return rc;
+ }
+
+ rc = efct_hw_config_mrq(hw, SLI4_CMD_REG_FCFI_SET_MRQ_MODE, 0);
+ if (rc != 0) {
+ efc_log_err(hw->os, "REG_FCFI_MRQ MRQ reg failed\n");
+ return rc;
+ }
+ }
+
+ /*
+ * Allocate the WQ request tag pool, if not previously allocated
+ * (the request tag value is 16 bits, thus the pool allocation size
+ * of 64k)
+ */
+ hw->wq_reqtag_pool = efct_hw_reqtag_pool_alloc(hw);
+ if (!hw->wq_reqtag_pool) {
+ efc_log_err(hw->os, "efct_hw_reqtag_pool_alloc failed\n");
+ return -ENOMEM;
+ }
+
+ rc = efct_hw_setup_io(hw);
+ if (rc) {
+ efc_log_err(hw->os, "IO allocation failure\n");
+ return rc;
+ }
+
+ rc = efct_hw_init_io(hw);
+ if (rc) {
+ efc_log_err(hw->os, "IO initialization failure\n");
+ return rc;
+ }
+
+ dma = &hw->loop_map;
+ dma->size = SLI4_MIN_LOOP_MAP_BYTES;
+ dma->virt = dma_alloc_coherent(&hw->os->pci->dev, dma->size, &dma->phys,
+ GFP_DMA);
+ if (!dma->virt)
+ return -EIO;
+
+ /*
+ * Arming the EQ allows (e.g.) interrupts when CQ completions write EQ
+ * entries
+ */
+ for (i = 0; i < hw->eq_count; i++)
+ sli_queue_arm(&hw->sli, &hw->eq[i], true);
+
+ /*
+ * Initialize RQ hash
+ */
+ for (i = 0; i < hw->rq_count; i++)
+ efct_hw_queue_hash_add(hw->rq_hash, hw->rq[i].id, i);
+
+ /*
+ * Initialize WQ hash
+ */
+ for (i = 0; i < hw->wq_count; i++)
+ efct_hw_queue_hash_add(hw->wq_hash, hw->wq[i].id, i);
+
+ /*
+ * Arming the CQ allows (e.g.) MQ completions to write CQ entries
+ */
+ for (i = 0; i < hw->cq_count; i++) {
+ efct_hw_queue_hash_add(hw->cq_hash, hw->cq[i].id, i);
+ sli_queue_arm(&hw->sli, &hw->cq[i], true);
+ }
+
+ /* Set RQ process limit*/
+ for (i = 0; i < hw->hw_rq_count; i++) {
+ struct hw_rq *rq = hw->hw_rq[i];
+
+ hw->cq[rq->cq->instance].proc_limit = hw->config.n_io / 2;
+ }
+
+ /* record the fact that the queues are functional */
+ hw->state = EFCT_HW_STATE_ACTIVE;
+ /*
+ * Allocate a HW IOs for send frame.
+ */
+ hw->hw_wq[0]->send_frame_io = efct_hw_io_alloc(hw);
+ if (!hw->hw_wq[0]->send_frame_io)
+ efc_log_err(hw->os, "alloc for send_frame_io failed\n");
+
+ /* Initialize send frame sequence id */
+ atomic_set(&hw->send_frame_seq_id, 0);
+
+ return 0;
+}
+
+int
+efct_hw_parse_filter(struct efct_hw *hw, void *value)
+{
+ int rc = 0;
+ char *p = NULL;
+ char *token;
+ u32 idx = 0;
+
+ for (idx = 0; idx < ARRAY_SIZE(hw->config.filter_def); idx++)
+ hw->config.filter_def[idx] = 0;
+
+ p = kstrdup(value, GFP_KERNEL);
+ if (!p || !*p) {
+ efc_log_err(hw->os, "p is NULL\n");
+ return -ENOMEM;
+ }
+
+ idx = 0;
+ while ((token = strsep(&p, ",")) && *token) {
+ if (kstrtou32(token, 0, &hw->config.filter_def[idx++]))
+ efc_log_err(hw->os, "kstrtoint failed\n");
+
+ if (!p || !*p)
+ break;
+
+ if (idx == ARRAY_SIZE(hw->config.filter_def))
+ break;
+ }
+ kfree(p);
+
+ return rc;
+}
+
+u64
+efct_get_wwnn(struct efct_hw *hw)
+{
+ struct sli4 *sli = &hw->sli;
+ u8 p[8];
+
+ memcpy(p, sli->wwnn, sizeof(p));
+ return get_unaligned_be64(p);
+}
+
+u64
+efct_get_wwpn(struct efct_hw *hw)
+{
+ struct sli4 *sli = &hw->sli;
+ u8 p[8];
+
+ memcpy(p, sli->wwpn, sizeof(p));
+ return get_unaligned_be64(p);
+}
+
+static struct efc_hw_rq_buffer *
+efct_hw_rx_buffer_alloc(struct efct_hw *hw, u32 rqindex, u32 count,
+ u32 size)
+{
+ struct efct *efct = hw->os;
+ struct efc_hw_rq_buffer *rq_buf = NULL;
+ struct efc_hw_rq_buffer *prq;
+ u32 i;
+
+ if (!count)
+ return NULL;
+
+ rq_buf = kmalloc_array(count, sizeof(*rq_buf), GFP_KERNEL);
+ if (!rq_buf)
+ return NULL;
+ memset(rq_buf, 0, sizeof(*rq_buf) * count);
+
+ for (i = 0, prq = rq_buf; i < count; i ++, prq++) {
+ prq->rqindex = rqindex;
+ prq->dma.size = size;
+ prq->dma.virt = dma_alloc_coherent(&efct->pci->dev,
+ prq->dma.size,
+ &prq->dma.phys,
+ GFP_DMA);
+ if (!prq->dma.virt) {
+ efc_log_err(hw->os, "DMA allocation failed\n");
+ kfree(rq_buf);
+ return NULL;
+ }
+ }
+ return rq_buf;
+}
+
+static void
+efct_hw_rx_buffer_free(struct efct_hw *hw,
+ struct efc_hw_rq_buffer *rq_buf,
+ u32 count)
+{
+ struct efct *efct = hw->os;
+ u32 i;
+ struct efc_hw_rq_buffer *prq;
+
+ if (rq_buf) {
+ for (i = 0, prq = rq_buf; i < count; i++, prq++) {
+ dma_free_coherent(&efct->pci->dev,
+ prq->dma.size, prq->dma.virt,
+ prq->dma.phys);
+ memset(&prq->dma, 0, sizeof(struct efc_dma));
+ }
+
+ kfree(rq_buf);
+ }
+}
+
+int
+efct_hw_rx_allocate(struct efct_hw *hw)
+{
+ struct efct *efct = hw->os;
+ u32 i;
+ int rc = 0;
+ u32 rqindex = 0;
+ u32 hdr_size = EFCT_HW_RQ_SIZE_HDR;
+ u32 payload_size = hw->config.rq_default_buffer_size;
+
+ rqindex = 0;
+
+ for (i = 0; i < hw->hw_rq_count; i++) {
+ struct hw_rq *rq = hw->hw_rq[i];
+
+ /* Allocate header buffers */
+ rq->hdr_buf = efct_hw_rx_buffer_alloc(hw, rqindex,
+ rq->entry_count,
+ hdr_size);
+ if (!rq->hdr_buf) {
+ efc_log_err(efct, "rx_buffer_alloc hdr_buf failed\n");
+ rc = -EIO;
+ break;
+ }
+
+ efc_log_debug(hw->os,
+ "rq[%2d] rq_id %02d header %4d by %4d bytes\n",
+ i, rq->hdr->id, rq->entry_count, hdr_size);
+
+ rqindex++;
+
+ /* Allocate payload buffers */
+ rq->payload_buf = efct_hw_rx_buffer_alloc(hw, rqindex,
+ rq->entry_count,
+ payload_size);
+ if (!rq->payload_buf) {
+ efc_log_err(efct, "rx_buffer_alloc fb_buf failed\n");
+ rc = -EIO;
+ break;
+ }
+ efc_log_debug(hw->os,
+ "rq[%2d] rq_id %02d default %4d by %4d bytes\n",
+ i, rq->data->id, rq->entry_count, payload_size);
+ rqindex++;
+ }
+
+ return rc ? -EIO : 0;
+}
+
+int
+efct_hw_rx_post(struct efct_hw *hw)
+{
+ u32 i;
+ u32 idx;
+ u32 rq_idx;
+ int rc = 0;
+
+ if (!hw->seq_pool) {
+ u32 count = 0;
+
+ for (i = 0; i < hw->hw_rq_count; i++)
+ count += hw->hw_rq[i]->entry_count;
+
+ hw->seq_pool = kmalloc_array(count,
+ sizeof(struct efc_hw_sequence), GFP_KERNEL);
+ if (!hw->seq_pool)
+ return -ENOMEM;
+ }
+
+ /*
+ * In RQ pair mode, we MUST post the header and payload buffer at the
+ * same time.
+ */
+ for (rq_idx = 0, idx = 0; rq_idx < hw->hw_rq_count; rq_idx++) {
+ struct hw_rq *rq = hw->hw_rq[rq_idx];
+
+ for (i = 0; i < rq->entry_count - 1; i++) {
+ struct efc_hw_sequence *seq;
+
+ seq = hw->seq_pool + idx;
+ idx++;
+ seq->header = &rq->hdr_buf[i];
+ seq->payload = &rq->payload_buf[i];
+ rc = efct_hw_sequence_free(hw, seq);
+ if (rc)
+ break;
+ }
+ if (rc)
+ break;
+ }
+
+ if (rc && hw->seq_pool)
+ kfree(hw->seq_pool);
+
+ return rc;
+}
+
+void
+efct_hw_rx_free(struct efct_hw *hw)
+{
+ u32 i;
+
+ /* Free hw_rq buffers */
+ for (i = 0; i < hw->hw_rq_count; i++) {
+ struct hw_rq *rq = hw->hw_rq[i];
+
+ if (rq) {
+ efct_hw_rx_buffer_free(hw, rq->hdr_buf,
+ rq->entry_count);
+ rq->hdr_buf = NULL;
+ efct_hw_rx_buffer_free(hw, rq->payload_buf,
+ rq->entry_count);
+ rq->payload_buf = NULL;
+ }
+ }
+}
+
+static int
+efct_hw_cmd_submit_pending(struct efct_hw *hw)
+{
+ int rc = 0;
+
+ /* Assumes lock held */
+
+ /* Only submit MQE if there's room */
+ while (hw->cmd_head_count < (EFCT_HW_MQ_DEPTH - 1) &&
+ !list_empty(&hw->cmd_pending)) {
+ struct efct_command_ctx *ctx;
+
+ ctx = list_first_entry(&hw->cmd_pending,
+ struct efct_command_ctx, list_entry);
+ if (!ctx)
+ break;
+
+ list_del_init(&ctx->list_entry);
+
+ list_add_tail(&ctx->list_entry, &hw->cmd_head);
+ hw->cmd_head_count++;
+ if (sli_mq_write(&hw->sli, hw->mq, ctx->buf) < 0) {
+ efc_log_debug(hw->os,
+ "sli_queue_write failed: %d\n", rc);
+ rc = -EIO;
+ break;
+ }
+ }
+ return rc;
+}
+
+int
+efct_hw_command(struct efct_hw *hw, u8 *cmd, u32 opts, void *cb, void *arg)
+{
+ int rc = -EIO;
+ unsigned long flags = 0;
+ void *bmbx = NULL;
+
+ /*
+ * If the chip is in an error state (UE'd) then reject this mailbox
+ * command.
+ */
+ if (sli_fw_error_status(&hw->sli) > 0) {
+ efc_log_crit(hw->os, "Chip in an error state - reset needed\n");
+ efc_log_crit(hw->os, "status=%#x error1=%#x error2=%#x\n",
+ sli_reg_read_status(&hw->sli),
+ sli_reg_read_err1(&hw->sli),
+ sli_reg_read_err2(&hw->sli));
+
+ return -EIO;
+ }
+
+ /*
+ * Send a mailbox command to the hardware, and either wait for
+ * a completion (EFCT_CMD_POLL) or get an optional asynchronous
+ * completion (EFCT_CMD_NOWAIT).
+ */
+
+ if (opts == EFCT_CMD_POLL) {
+ mutex_lock(&hw->bmbx_lock);
+ bmbx = hw->sli.bmbx.virt;
+
+ memset(bmbx, 0, SLI4_BMBX_SIZE);
+ memcpy(bmbx, cmd, SLI4_BMBX_SIZE);
+
+ if (sli_bmbx_command(&hw->sli) == 0) {
+ rc = 0;
+ memcpy(cmd, bmbx, SLI4_BMBX_SIZE);
+ }
+ mutex_unlock(&hw->bmbx_lock);
+ } else if (opts == EFCT_CMD_NOWAIT) {
+ struct efct_command_ctx *ctx = NULL;
+
+ if (hw->state != EFCT_HW_STATE_ACTIVE) {
+ efc_log_err(hw->os, "Can't send command, HW state=%d\n",
+ hw->state);
+ return -EIO;
+ }
+
+ ctx = mempool_alloc(hw->cmd_ctx_pool, GFP_ATOMIC);
+ if (!ctx)
+ return -ENOSPC;
+
+ memset(ctx, 0, sizeof(struct efct_command_ctx));
+
+ if (cb) {
+ ctx->cb = cb;
+ ctx->arg = arg;
+ }
+
+ memcpy(ctx->buf, cmd, SLI4_BMBX_SIZE);
+ ctx->ctx = hw;
+
+ spin_lock_irqsave(&hw->cmd_lock, flags);
+
+ /* Add to pending list */
+ INIT_LIST_HEAD(&ctx->list_entry);
+ list_add_tail(&ctx->list_entry, &hw->cmd_pending);
+
+ /* Submit as much of the pending list as we can */
+ rc = efct_hw_cmd_submit_pending(hw);
+
+ spin_unlock_irqrestore(&hw->cmd_lock, flags);
+ }
+
+ return rc;
+}
+
+static int
+efct_hw_command_process(struct efct_hw *hw, int status, u8 *mqe,
+ size_t size)
+{
+ struct efct_command_ctx *ctx = NULL;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&hw->cmd_lock, flags);
+ if (!list_empty(&hw->cmd_head)) {
+ ctx = list_first_entry(&hw->cmd_head,
+ struct efct_command_ctx, list_entry);
+ list_del_init(&ctx->list_entry);
+ }
+ if (!ctx) {
+ efc_log_err(hw->os, "no command context\n");
+ spin_unlock_irqrestore(&hw->cmd_lock, flags);
+ return -EIO;
+ }
+
+ hw->cmd_head_count--;
+
+ /* Post any pending requests */
+ efct_hw_cmd_submit_pending(hw);
+
+ spin_unlock_irqrestore(&hw->cmd_lock, flags);
+
+ if (ctx->cb) {
+ memcpy(ctx->buf, mqe, size);
+ ctx->cb(hw, status, ctx->buf, ctx->arg);
+ }
+
+ mempool_free(ctx, hw->cmd_ctx_pool);
+
+ return 0;
+}
+
+static int
+efct_hw_mq_process(struct efct_hw *hw,
+ int status, struct sli4_queue *mq)
+{
+ u8 mqe[SLI4_BMBX_SIZE];
+ int rc;
+
+ rc = sli_mq_read(&hw->sli, mq, mqe);
+ if (!rc)
+ rc = efct_hw_command_process(hw, status, mqe, mq->size);
+
+ return rc;
+}
+
+static int
+efct_hw_command_cancel(struct efct_hw *hw)
+{
+ unsigned long flags = 0;
+ int rc = 0;
+
+ spin_lock_irqsave(&hw->cmd_lock, flags);
+
+ /*
+ * Manually clean up remaining commands. Note: since this calls
+ * efct_hw_command_process(), we'll also process the cmd_pending
+ * list, so no need to manually clean that out.
+ */
+ while (!list_empty(&hw->cmd_head)) {
+ u8 mqe[SLI4_BMBX_SIZE] = { 0 };
+ struct efct_command_ctx *ctx;
+
+ ctx = list_first_entry(&hw->cmd_head,
+ struct efct_command_ctx, list_entry);
+
+ efc_log_debug(hw->os, "hung command %08x\n",
+ !ctx ? U32_MAX : *((u32 *)ctx->buf));
+ spin_unlock_irqrestore(&hw->cmd_lock, flags);
+ rc = efct_hw_command_process(hw, -1, mqe, SLI4_BMBX_SIZE);
+ spin_lock_irqsave(&hw->cmd_lock, flags);
+ }
+
+ spin_unlock_irqrestore(&hw->cmd_lock, flags);
+
+ return rc;
+}
+
+static void
+efct_mbox_rsp_cb(struct efct_hw *hw, int status, u8 *mqe, void *arg)
+{
+ struct efct_mbox_rqst_ctx *ctx = arg;
+
+ if (ctx) {
+ if (ctx->callback)
+ (*ctx->callback)(hw->os->efcport, status, mqe,
+ ctx->arg);
+
+ mempool_free(ctx, hw->mbox_rqst_pool);
+ }
+}
+
+int
+efct_issue_mbox_rqst(void *base, void *cmd, void *cb, void *arg)
+{
+ struct efct_mbox_rqst_ctx *ctx;
+ struct efct *efct = base;
+ struct efct_hw *hw = &efct->hw;
+ int rc;
+
+ /*
+ * Allocate a callback context (which includes the mbox cmd buffer),
+ * we need this to be persistent as the mbox cmd submission may be
+ * queued and executed later execution.
+ */
+ ctx = mempool_alloc(hw->mbox_rqst_pool, GFP_ATOMIC);
+ if (!ctx)
+ return -EIO;
+
+ ctx->callback = cb;
+ ctx->arg = arg;
+
+ rc = efct_hw_command(hw, cmd, EFCT_CMD_NOWAIT, efct_mbox_rsp_cb, ctx);
+ if (rc) {
+ efc_log_err(efct, "issue mbox rqst failure rc:%d\n", rc);
+ mempool_free(ctx, hw->mbox_rqst_pool);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static inline struct efct_hw_io *
+_efct_hw_io_alloc(struct efct_hw *hw)
+{
+ struct efct_hw_io *io = NULL;
+
+ if (!list_empty(&hw->io_free)) {
+ io = list_first_entry(&hw->io_free, struct efct_hw_io,
+ list_entry);
+ list_del(&io->list_entry);
+ }
+ if (io) {
+ INIT_LIST_HEAD(&io->list_entry);
+ list_add_tail(&io->list_entry, &hw->io_inuse);
+ io->state = EFCT_HW_IO_STATE_INUSE;
+ io->abort_reqtag = U32_MAX;
+ io->wq = hw->wq_cpu_array[raw_smp_processor_id()];
+ if (!io->wq) {
+ efc_log_err(hw->os, "WQ not assigned for cpu:%d\n",
+ raw_smp_processor_id());
+ io->wq = hw->hw_wq[0];
+ }
+ kref_init(&io->ref);
+ io->release = efct_hw_io_free_internal;
+ } else {
+ atomic_add(1, &hw->io_alloc_failed_count);
+ }
+
+ return io;
+}
+
+struct efct_hw_io *
+efct_hw_io_alloc(struct efct_hw *hw)
+{
+ struct efct_hw_io *io = NULL;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&hw->io_lock, flags);
+ io = _efct_hw_io_alloc(hw);
+ spin_unlock_irqrestore(&hw->io_lock, flags);
+
+ return io;
+}
+
+static void
+efct_hw_io_free_move_correct_list(struct efct_hw *hw,
+ struct efct_hw_io *io)
+{
+ /*
+ * When an IO is freed, depending on the exchange busy flag,
+ * move it to the correct list.
+ */
+ if (io->xbusy) {
+ /*
+ * add to wait_free list and wait for XRI_ABORTED CQEs to clean
+ * up
+ */
+ INIT_LIST_HEAD(&io->list_entry);
+ list_add_tail(&io->list_entry, &hw->io_wait_free);
+ io->state = EFCT_HW_IO_STATE_WAIT_FREE;
+ } else {
+ /* IO not busy, add to free list */
+ INIT_LIST_HEAD(&io->list_entry);
+ list_add_tail(&io->list_entry, &hw->io_free);
+ io->state = EFCT_HW_IO_STATE_FREE;
+ }
+}
+
+static inline void
+efct_hw_io_free_common(struct efct_hw *hw, struct efct_hw_io *io)
+{
+ /* initialize IO fields */
+ efct_hw_init_free_io(io);
+
+ /* Restore default SGL */
+ efct_hw_io_restore_sgl(hw, io);
+}
+
+void
+efct_hw_io_free_internal(struct kref *arg)
+{
+ unsigned long flags = 0;
+ struct efct_hw_io *io = container_of(arg, struct efct_hw_io, ref);
+ struct efct_hw *hw = io->hw;
+
+ /* perform common cleanup */
+ efct_hw_io_free_common(hw, io);
+
+ spin_lock_irqsave(&hw->io_lock, flags);
+ /* remove from in-use list */
+ if (!list_empty(&io->list_entry) && !list_empty(&hw->io_inuse)) {
+ list_del_init(&io->list_entry);
+ efct_hw_io_free_move_correct_list(hw, io);
+ }
+ spin_unlock_irqrestore(&hw->io_lock, flags);
+}
+
+int
+efct_hw_io_free(struct efct_hw *hw, struct efct_hw_io *io)
+{
+ return kref_put(&io->ref, io->release);
+}
+
+struct efct_hw_io *
+efct_hw_io_lookup(struct efct_hw *hw, u32 xri)
+{
+ u32 ioindex;
+
+ ioindex = xri - hw->sli.ext[SLI4_RSRC_XRI].base[0];
+ return hw->io[ioindex];
+}
+
+int
+efct_hw_io_init_sges(struct efct_hw *hw, struct efct_hw_io *io,
+ enum efct_hw_io_type type)
+{
+ struct sli4_sge *data = NULL;
+ u32 i = 0;
+ u32 skips = 0;
+ u32 sge_flags = 0;
+
+ if (!io) {
+ efc_log_err(hw->os, "bad parameter hw=%p io=%p\n", hw, io);
+ return -EIO;
+ }
+
+ /* Clear / reset the scatter-gather list */
+ io->sgl = &io->def_sgl;
+ io->sgl_count = io->def_sgl_count;
+ io->first_data_sge = 0;
+
+ memset(io->sgl->virt, 0, 2 * sizeof(struct sli4_sge));
+ io->n_sge = 0;
+ io->sge_offset = 0;
+
+ io->type = type;
+
+ data = io->sgl->virt;
+
+ /*
+ * Some IO types have underlying hardware requirements on the order
+ * of SGEs. Process all special entries here.
+ */
+ switch (type) {
+ case EFCT_HW_IO_TARGET_WRITE:
+
+ /* populate host resident XFER_RDY buffer */
+ sge_flags = le32_to_cpu(data->dw2_flags);
+ sge_flags &= (~SLI4_SGE_TYPE_MASK);
+ sge_flags |= (SLI4_SGE_TYPE_DATA << SLI4_SGE_TYPE_SHIFT);
+ data->buffer_address_high =
+ cpu_to_le32(upper_32_bits(io->xfer_rdy.phys));
+ data->buffer_address_low =
+ cpu_to_le32(lower_32_bits(io->xfer_rdy.phys));
+ data->buffer_length = cpu_to_le32(io->xfer_rdy.size);
+ data->dw2_flags = cpu_to_le32(sge_flags);
+ data++;
+
+ skips = EFCT_TARGET_WRITE_SKIPS;
+
+ io->n_sge = 1;
+ break;
+ case EFCT_HW_IO_TARGET_READ:
+ /*
+ * For FCP_TSEND64, the first 2 entries are SKIP SGE's
+ */
+ skips = EFCT_TARGET_READ_SKIPS;
+ break;
+ case EFCT_HW_IO_TARGET_RSP:
+ /*
+ * No skips, etc. for FCP_TRSP64
+ */
+ break;
+ default:
+ efc_log_err(hw->os, "unsupported IO type %#x\n", type);
+ return -EIO;
+ }
+
+ /*
+ * Write skip entries
+ */
+ for (i = 0; i < skips; i++) {
+ sge_flags = le32_to_cpu(data->dw2_flags);
+ sge_flags &= (~SLI4_SGE_TYPE_MASK);
+ sge_flags |= (SLI4_SGE_TYPE_SKIP << SLI4_SGE_TYPE_SHIFT);
+ data->dw2_flags = cpu_to_le32(sge_flags);
+ data++;
+ }
+
+ io->n_sge += skips;
+
+ /*
+ * Set last
+ */
+ sge_flags = le32_to_cpu(data->dw2_flags);
+ sge_flags |= SLI4_SGE_LAST;
+ data->dw2_flags = cpu_to_le32(sge_flags);
+
+ return 0;
+}
+
+int
+efct_hw_io_add_sge(struct efct_hw *hw, struct efct_hw_io *io,
+ uintptr_t addr, u32 length)
+{
+ struct sli4_sge *data = NULL;
+ u32 sge_flags = 0;
+
+ if (!io || !addr || !length) {
+ efc_log_err(hw->os,
+ "bad parameter hw=%p io=%p addr=%lx length=%u\n",
+ hw, io, addr, length);
+ return -EIO;
+ }
+
+ if (length > hw->sli.sge_supported_length) {
+ efc_log_err(hw->os,
+ "length of SGE %d bigger than allowed %d\n",
+ length, hw->sli.sge_supported_length);
+ return -EIO;
+ }
+
+ data = io->sgl->virt;
+ data += io->n_sge;
+
+ sge_flags = le32_to_cpu(data->dw2_flags);
+ sge_flags &= ~SLI4_SGE_TYPE_MASK;
+ sge_flags |= SLI4_SGE_TYPE_DATA << SLI4_SGE_TYPE_SHIFT;
+ sge_flags &= ~SLI4_SGE_DATA_OFFSET_MASK;
+ sge_flags |= SLI4_SGE_DATA_OFFSET_MASK & io->sge_offset;
+
+ data->buffer_address_high = cpu_to_le32(upper_32_bits(addr));
+ data->buffer_address_low = cpu_to_le32(lower_32_bits(addr));
+ data->buffer_length = cpu_to_le32(length);
+
+ /*
+ * Always assume this is the last entry and mark as such.
+ * If this is not the first entry unset the "last SGE"
+ * indication for the previous entry
+ */
+ sge_flags |= SLI4_SGE_LAST;
+ data->dw2_flags = cpu_to_le32(sge_flags);
+
+ if (io->n_sge) {
+ sge_flags = le32_to_cpu(data[-1].dw2_flags);
+ sge_flags &= ~SLI4_SGE_LAST;
+ data[-1].dw2_flags = cpu_to_le32(sge_flags);
+ }
+
+ /* Set first_data_bde if not previously set */
+ if (io->first_data_sge == 0)
+ io->first_data_sge = io->n_sge;
+
+ io->sge_offset += length;
+ io->n_sge++;
+
+ return 0;
+}
+
+void
+efct_hw_io_abort_all(struct efct_hw *hw)
+{
+ struct efct_hw_io *io_to_abort = NULL;
+ struct efct_hw_io *next_io = NULL;
+
+ list_for_each_entry_safe(io_to_abort, next_io,
+ &hw->io_inuse, list_entry) {
+ efct_hw_io_abort(hw, io_to_abort, true, NULL, NULL);
+ }
+}
+
+static void
+efct_hw_wq_process_abort(void *arg, u8 *cqe, int status)
+{
+ struct efct_hw_io *io = arg;
+ struct efct_hw *hw = io->hw;
+ u32 ext = 0;
+ u32 len = 0;
+ struct hw_wq_callback *wqcb;
+
+ /*
+ * For IOs that were aborted internally, we may need to issue the
+ * callback here depending on whether a XRI_ABORTED CQE is expected ot
+ * not. If the status is Local Reject/No XRI, then
+ * issue the callback now.
+ */
+ ext = sli_fc_ext_status(&hw->sli, cqe);
+ if (status == SLI4_FC_WCQE_STATUS_LOCAL_REJECT &&
+ ext == SLI4_FC_LOCAL_REJECT_NO_XRI && io->done) {
+ efct_hw_done_t done = io->done;
+
+ io->done = NULL;
+
+ /*
+ * Use latched status as this is always saved for an internal
+ * abort Note: We won't have both a done and abort_done
+ * function, so don't worry about
+ * clobbering the len, status and ext fields.
+ */
+ status = io->saved_status;
+ len = io->saved_len;
+ ext = io->saved_ext;
+ io->status_saved = false;
+ done(io, len, status, ext, io->arg);
+ }
+
+ if (io->abort_done) {
+ efct_hw_done_t done = io->abort_done;
+
+ io->abort_done = NULL;
+ done(io, len, status, ext, io->abort_arg);
+ }
+
+ /* clear abort bit to indicate abort is complete */
+ io->abort_in_progress = false;
+
+ /* Free the WQ callback */
+ if (io->abort_reqtag == U32_MAX) {
+ efc_log_err(hw->os, "HW IO already freed\n");
+ return;
+ }
+
+ wqcb = efct_hw_reqtag_get_instance(hw, io->abort_reqtag);
+ efct_hw_reqtag_free(hw, wqcb);
+
+ /*
+ * Call efct_hw_io_free() because this releases the WQ reservation as
+ * well as doing the refcount put. Don't duplicate the code here.
+ */
+ (void)efct_hw_io_free(hw, io);
+}
+
+static void
+efct_hw_fill_abort_wqe(struct efct_hw *hw, struct efct_hw_wqe *wqe)
+{
+ struct sli4_abort_wqe *abort = (void *)wqe->wqebuf;
+
+ memset(abort, 0, hw->sli.wqe_size);
+
+ abort->criteria = SLI4_ABORT_CRITERIA_XRI_TAG;
+ abort->ia_ir_byte |= wqe->send_abts ? 0 : 1;
+
+ /* Suppress ABTS retries */
+ abort->ia_ir_byte |= SLI4_ABRT_WQE_IR;
+
+ abort->t_tag = cpu_to_le32(wqe->id);
+ abort->command = SLI4_WQE_ABORT;
+ abort->request_tag = cpu_to_le16(wqe->abort_reqtag);
+
+ abort->dw10w0_flags = cpu_to_le16(SLI4_ABRT_WQE_QOSD);
+
+ abort->cq_id = cpu_to_le16(SLI4_CQ_DEFAULT);
+}
+
+int
+efct_hw_io_abort(struct efct_hw *hw, struct efct_hw_io *io_to_abort,
+ bool send_abts, void *cb, void *arg)
+{
+ struct hw_wq_callback *wqcb;
+ unsigned long flags = 0;
+
+ if (!io_to_abort) {
+ efc_log_err(hw->os, "bad parameter hw=%p io=%p\n",
+ hw, io_to_abort);
+ return -EIO;
+ }
+
+ if (hw->state != EFCT_HW_STATE_ACTIVE) {
+ efc_log_err(hw->os, "cannot send IO abort, HW state=%d\n",
+ hw->state);
+ return -EIO;
+ }
+
+ /* take a reference on IO being aborted */
+ if (kref_get_unless_zero(&io_to_abort->ref) == 0) {
+ /* command no longer active */
+ efc_log_debug(hw->os,
+ "io not active xri=0x%x tag=0x%x\n",
+ io_to_abort->indicator, io_to_abort->reqtag);
+ return -ENOENT;
+ }
+
+ /* Must have a valid WQ reference */
+ if (!io_to_abort->wq) {
+ efc_log_debug(hw->os, "io_to_abort xri=0x%x not active on WQ\n",
+ io_to_abort->indicator);
+ /* efct_ref_get(): same function */
+ kref_put(&io_to_abort->ref, io_to_abort->release);
+ return -ENOENT;
+ }
+
+ /*
+ * Validation checks complete; now check to see if already being
+ * aborted, if not set the flag.
+ */
+ if (cmpxchg(&io_to_abort->abort_in_progress, false, true)) {
+ /* efct_ref_get(): same function */
+ kref_put(&io_to_abort->ref, io_to_abort->release);
+ efc_log_debug(hw->os,
+ "io already being aborted xri=0x%x tag=0x%x\n",
+ io_to_abort->indicator, io_to_abort->reqtag);
+ return -EINPROGRESS;
+ }
+
+ /*
+ * If we got here, the possibilities are:
+ * - host owned xri
+ * - io_to_abort->wq_index != U32_MAX
+ * - submit ABORT_WQE to same WQ
+ * - port owned xri:
+ * - rxri: io_to_abort->wq_index == U32_MAX
+ * - submit ABORT_WQE to any WQ
+ * - non-rxri
+ * - io_to_abort->index != U32_MAX
+ * - submit ABORT_WQE to same WQ
+ * - io_to_abort->index == U32_MAX
+ * - submit ABORT_WQE to any WQ
+ */
+ io_to_abort->abort_done = cb;
+ io_to_abort->abort_arg = arg;
+
+ /* Allocate a request tag for the abort portion of this IO */
+ wqcb = efct_hw_reqtag_alloc(hw, efct_hw_wq_process_abort, io_to_abort);
+ if (!wqcb) {
+ efc_log_err(hw->os, "can't allocate request tag\n");
+ return -ENOSPC;
+ }
+
+ io_to_abort->abort_reqtag = wqcb->instance_index;
+ io_to_abort->wqe.send_abts = send_abts;
+ io_to_abort->wqe.id = io_to_abort->indicator;
+ io_to_abort->wqe.abort_reqtag = io_to_abort->abort_reqtag;
+
+ /*
+ * If the wqe is on the pending list, then set this wqe to be
+ * aborted when the IO's wqe is removed from the list.
+ */
+ if (io_to_abort->wq) {
+ spin_lock_irqsave(&io_to_abort->wq->queue->lock, flags);
+ if (io_to_abort->wqe.list_entry.next) {
+ io_to_abort->wqe.abort_wqe_submit_needed = true;
+ spin_unlock_irqrestore(&io_to_abort->wq->queue->lock,
+ flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&io_to_abort->wq->queue->lock, flags);
+ }
+
+ efct_hw_fill_abort_wqe(hw, &io_to_abort->wqe);
+
+ /* ABORT_WQE does not actually utilize an XRI on the Port,
+ * therefore, keep xbusy as-is to track the exchange's state,
+ * not the ABORT_WQE's state
+ */
+ if (efct_hw_wq_write(io_to_abort->wq, &io_to_abort->wqe)) {
+ io_to_abort->abort_in_progress = false;
+ /* efct_ref_get(): same function */
+ kref_put(&io_to_abort->ref, io_to_abort->release);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+void
+efct_hw_reqtag_pool_free(struct efct_hw *hw)
+{
+ u32 i;
+ struct reqtag_pool *reqtag_pool = hw->wq_reqtag_pool;
+ struct hw_wq_callback *wqcb = NULL;
+
+ if (reqtag_pool) {
+ for (i = 0; i < U16_MAX; i++) {
+ wqcb = reqtag_pool->tags[i];
+ if (!wqcb)
+ continue;
+
+ kfree(wqcb);
+ }
+ kfree(reqtag_pool);
+ hw->wq_reqtag_pool = NULL;
+ }
+}
+
+struct reqtag_pool *
+efct_hw_reqtag_pool_alloc(struct efct_hw *hw)
+{
+ u32 i = 0;
+ struct reqtag_pool *reqtag_pool;
+ struct hw_wq_callback *wqcb;
+
+ reqtag_pool = kzalloc(sizeof(*reqtag_pool), GFP_KERNEL);
+ if (!reqtag_pool)
+ return NULL;
+
+ INIT_LIST_HEAD(&reqtag_pool->freelist);
+ /* initialize reqtag pool lock */
+ spin_lock_init(&reqtag_pool->lock);
+ for (i = 0; i < U16_MAX; i++) {
+ wqcb = kmalloc(sizeof(*wqcb), GFP_KERNEL);
+ if (!wqcb)
+ break;
+
+ reqtag_pool->tags[i] = wqcb;
+ wqcb->instance_index = i;
+ wqcb->callback = NULL;
+ wqcb->arg = NULL;
+ INIT_LIST_HEAD(&wqcb->list_entry);
+ list_add_tail(&wqcb->list_entry, &reqtag_pool->freelist);
+ }
+
+ return reqtag_pool;
+}
+
+struct hw_wq_callback *
+efct_hw_reqtag_alloc(struct efct_hw *hw,
+ void (*callback)(void *arg, u8 *cqe, int status),
+ void *arg)
+{
+ struct hw_wq_callback *wqcb = NULL;
+ struct reqtag_pool *reqtag_pool = hw->wq_reqtag_pool;
+ unsigned long flags = 0;
+
+ if (!callback)
+ return wqcb;
+
+ spin_lock_irqsave(&reqtag_pool->lock, flags);
+
+ if (!list_empty(&reqtag_pool->freelist)) {
+ wqcb = list_first_entry(&reqtag_pool->freelist,
+ struct hw_wq_callback, list_entry);
+ }
+
+ if (wqcb) {
+ list_del_init(&wqcb->list_entry);
+ spin_unlock_irqrestore(&reqtag_pool->lock, flags);
+ wqcb->callback = callback;
+ wqcb->arg = arg;
+ } else {
+ spin_unlock_irqrestore(&reqtag_pool->lock, flags);
+ }
+
+ return wqcb;
+}
+
+void
+efct_hw_reqtag_free(struct efct_hw *hw, struct hw_wq_callback *wqcb)
+{
+ unsigned long flags = 0;
+ struct reqtag_pool *reqtag_pool = hw->wq_reqtag_pool;
+
+ if (!wqcb->callback)
+ efc_log_err(hw->os, "WQCB is already freed\n");
+
+ spin_lock_irqsave(&reqtag_pool->lock, flags);
+ wqcb->callback = NULL;
+ wqcb->arg = NULL;
+ INIT_LIST_HEAD(&wqcb->list_entry);
+ list_add(&wqcb->list_entry, &hw->wq_reqtag_pool->freelist);
+ spin_unlock_irqrestore(&reqtag_pool->lock, flags);
+}
+
+struct hw_wq_callback *
+efct_hw_reqtag_get_instance(struct efct_hw *hw, u32 instance_index)
+{
+ struct hw_wq_callback *wqcb;
+
+ wqcb = hw->wq_reqtag_pool->tags[instance_index];
+ if (!wqcb)
+ efc_log_err(hw->os, "wqcb for instance %d is null\n",
+ instance_index);
+
+ return wqcb;
+}
+
+int
+efct_hw_queue_hash_find(struct efct_queue_hash *hash, u16 id)
+{
+ int index = -1;
+ int i = id & (EFCT_HW_Q_HASH_SIZE - 1);
+
+ /*
+ * Since the hash is always bigger than the maximum number of Qs, then
+ * we never have to worry about an infinite loop. We will always find
+ * an unused entry.
+ */
+ do {
+ if (hash[i].in_use && hash[i].id == id)
+ index = hash[i].index;
+ else
+ i = (i + 1) & (EFCT_HW_Q_HASH_SIZE - 1);
+ } while (index == -1 && hash[i].in_use);
+
+ return index;
+}
+
+int
+efct_hw_process(struct efct_hw *hw, u32 vector,
+ u32 max_isr_time_msec)
+{
+ struct hw_eq *eq;
+
+ /*
+ * The caller should disable interrupts if they wish to prevent us
+ * from processing during a shutdown. The following states are defined:
+ * EFCT_HW_STATE_UNINITIALIZED - No queues allocated
+ * EFCT_HW_STATE_QUEUES_ALLOCATED - The state after a chip reset,
+ * queues are cleared.
+ * EFCT_HW_STATE_ACTIVE - Chip and queues are operational
+ * EFCT_HW_STATE_RESET_IN_PROGRESS - reset, we still want completions
+ * EFCT_HW_STATE_TEARDOWN_IN_PROGRESS - We still want mailbox
+ * completions.
+ */
+ if (hw->state == EFCT_HW_STATE_UNINITIALIZED)
+ return 0;
+
+ /* Get pointer to struct hw_eq */
+ eq = hw->hw_eq[vector];
+ if (!eq)
+ return 0;
+
+ eq->use_count++;
+
+ return efct_hw_eq_process(hw, eq, max_isr_time_msec);
+}
+
+int
+efct_hw_eq_process(struct efct_hw *hw, struct hw_eq *eq,
+ u32 max_isr_time_msec)
+{
+ u8 eqe[sizeof(struct sli4_eqe)] = { 0 };
+ u32 tcheck_count;
+ u64 tstart;
+ u64 telapsed;
+ bool done = false;
+
+ tcheck_count = EFCT_HW_TIMECHECK_ITERATIONS;
+ tstart = jiffies_to_msecs(jiffies);
+
+ while (!done && !sli_eq_read(&hw->sli, eq->queue, eqe)) {
+ u16 cq_id = 0;
+ int rc;
+
+ rc = sli_eq_parse(&hw->sli, eqe, &cq_id);
+ if (unlikely(rc)) {
+ if (rc == SLI4_EQE_STATUS_EQ_FULL) {
+ u32 i;
+
+ /*
+ * Received a sentinel EQE indicating the
+ * EQ is full. Process all CQs
+ */
+ for (i = 0; i < hw->cq_count; i++)
+ efct_hw_cq_process(hw, hw->hw_cq[i]);
+ continue;
+ } else {
+ return rc;
+ }
+ } else {
+ int index;
+
+ index = efct_hw_queue_hash_find(hw->cq_hash, cq_id);
+
+ if (likely(index >= 0))
+ efct_hw_cq_process(hw, hw->hw_cq[index]);
+ else
+ efc_log_err(hw->os, "bad CQ_ID %#06x\n", cq_id);
+ }
+
+ if (eq->queue->n_posted > eq->queue->posted_limit)
+ sli_queue_arm(&hw->sli, eq->queue, false);
+
+ if (tcheck_count && (--tcheck_count == 0)) {
+ tcheck_count = EFCT_HW_TIMECHECK_ITERATIONS;
+ telapsed = jiffies_to_msecs(jiffies) - tstart;
+ if (telapsed >= max_isr_time_msec)
+ done = true;
+ }
+ }
+ sli_queue_eq_arm(&hw->sli, eq->queue, true);
+
+ return 0;
+}
+
+static int
+_efct_hw_wq_write(struct hw_wq *wq, struct efct_hw_wqe *wqe)
+{
+ int queue_rc;
+
+ /* Every so often, set the wqec bit to generate comsummed completions */
+ if (wq->wqec_count)
+ wq->wqec_count--;
+
+ if (wq->wqec_count == 0) {
+ struct sli4_generic_wqe *genwqe = (void *)wqe->wqebuf;
+
+ genwqe->cmdtype_wqec_byte |= SLI4_GEN_WQE_WQEC;
+ wq->wqec_count = wq->wqec_set_count;
+ }
+
+ /* Decrement WQ free count */
+ wq->free_count--;
+
+ queue_rc = sli_wq_write(&wq->hw->sli, wq->queue, wqe->wqebuf);
+
+ return (queue_rc < 0) ? -EIO : 0;
+}
+
+static void
+hw_wq_submit_pending(struct hw_wq *wq, u32 update_free_count)
+{
+ struct efct_hw_wqe *wqe;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&wq->queue->lock, flags);
+
+ /* Update free count with value passed in */
+ wq->free_count += update_free_count;
+
+ while ((wq->free_count > 0) && (!list_empty(&wq->pending_list))) {
+ wqe = list_first_entry(&wq->pending_list,
+ struct efct_hw_wqe, list_entry);
+ list_del_init(&wqe->list_entry);
+ _efct_hw_wq_write(wq, wqe);
+
+ if (wqe->abort_wqe_submit_needed) {
+ wqe->abort_wqe_submit_needed = false;
+ efct_hw_fill_abort_wqe(wq->hw, wqe);
+ INIT_LIST_HEAD(&wqe->list_entry);
+ list_add_tail(&wqe->list_entry, &wq->pending_list);
+ wq->wq_pending_count++;
+ }
+ }
+
+ spin_unlock_irqrestore(&wq->queue->lock, flags);
+}
+
+void
+efct_hw_cq_process(struct efct_hw *hw, struct hw_cq *cq)
+{
+ u8 cqe[sizeof(struct sli4_mcqe)];
+ u16 rid = U16_MAX;
+ /* completion type */
+ enum sli4_qentry ctype;
+ u32 n_processed = 0;
+ u32 tstart, telapsed;
+
+ tstart = jiffies_to_msecs(jiffies);
+
+ while (!sli_cq_read(&hw->sli, cq->queue, cqe)) {
+ int status;
+
+ status = sli_cq_parse(&hw->sli, cq->queue, cqe, &ctype, &rid);
+ /*
+ * The sign of status is significant. If status is:
+ * == 0 : call completed correctly and
+ * the CQE indicated success
+ * > 0 : call completed correctly and
+ * the CQE indicated an error
+ * < 0 : call failed and no information is available about the
+ * CQE
+ */
+ if (status < 0) {
+ if (status == SLI4_MCQE_STATUS_NOT_COMPLETED)
+ /*
+ * Notification that an entry was consumed,
+ * but not completed
+ */
+ continue;
+
+ break;
+ }
+
+ switch (ctype) {
+ case SLI4_QENTRY_ASYNC:
+ sli_cqe_async(&hw->sli, cqe);
+ break;
+ case SLI4_QENTRY_MQ:
+ /*
+ * Process MQ entry. Note there is no way to determine
+ * the MQ_ID from the completion entry.
+ */
+ efct_hw_mq_process(hw, status, hw->mq);
+ break;
+ case SLI4_QENTRY_WQ:
+ efct_hw_wq_process(hw, cq, cqe, status, rid);
+ break;
+ case SLI4_QENTRY_WQ_RELEASE: {
+ u32 wq_id = rid;
+ int index;
+ struct hw_wq *wq = NULL;
+
+ index = efct_hw_queue_hash_find(hw->wq_hash, wq_id);
+
+ if (likely(index >= 0)) {
+ wq = hw->hw_wq[index];
+ } else {
+ efc_log_err(hw->os, "bad WQ_ID %#06x\n", wq_id);
+ break;
+ }
+ /* Submit any HW IOs that are on the WQ pending list */
+ hw_wq_submit_pending(wq, wq->wqec_set_count);
+
+ break;
+ }
+
+ case SLI4_QENTRY_RQ:
+ efct_hw_rqpair_process_rq(hw, cq, cqe);
+ break;
+ case SLI4_QENTRY_XABT: {
+ efct_hw_xabt_process(hw, cq, cqe, rid);
+ break;
+ }
+ default:
+ efc_log_debug(hw->os, "unhandled ctype=%#x rid=%#x\n",
+ ctype, rid);
+ break;
+ }
+
+ n_processed++;
+ if (n_processed == cq->queue->proc_limit)
+ break;
+
+ if (cq->queue->n_posted >= cq->queue->posted_limit)
+ sli_queue_arm(&hw->sli, cq->queue, false);
+ }
+
+ sli_queue_arm(&hw->sli, cq->queue, true);
+
+ if (n_processed > cq->queue->max_num_processed)
+ cq->queue->max_num_processed = n_processed;
+ telapsed = jiffies_to_msecs(jiffies) - tstart;
+ if (telapsed > cq->queue->max_process_time)
+ cq->queue->max_process_time = telapsed;
+}
+
+void
+efct_hw_wq_process(struct efct_hw *hw, struct hw_cq *cq,
+ u8 *cqe, int status, u16 rid)
+{
+ struct hw_wq_callback *wqcb;
+
+ if (rid == EFCT_HW_REQUE_XRI_REGTAG) {
+ if (status)
+ efc_log_err(hw->os, "reque xri failed, status = %d\n",
+ status);
+ return;
+ }
+
+ wqcb = efct_hw_reqtag_get_instance(hw, rid);
+ if (!wqcb) {
+ efc_log_err(hw->os, "invalid request tag: x%x\n", rid);
+ return;
+ }
+
+ if (!wqcb->callback) {
+ efc_log_err(hw->os, "wqcb callback is NULL\n");
+ return;
+ }
+
+ (*wqcb->callback)(wqcb->arg, cqe, status);
+}
+
+void
+efct_hw_xabt_process(struct efct_hw *hw, struct hw_cq *cq,
+ u8 *cqe, u16 rid)
+{
+ /* search IOs wait free list */
+ struct efct_hw_io *io = NULL;
+ unsigned long flags = 0;
+
+ io = efct_hw_io_lookup(hw, rid);
+ if (!io) {
+ /* IO lookup failure should never happen */
+ efc_log_err(hw->os, "xabt io lookup failed rid=%#x\n", rid);
+ return;
+ }
+
+ if (!io->xbusy)
+ efc_log_debug(hw->os, "xabt io not busy rid=%#x\n", rid);
+ else
+ /* mark IO as no longer busy */
+ io->xbusy = false;
+
+ /*
+ * For IOs that were aborted internally, we need to issue any pending
+ * callback here.
+ */
+ if (io->done) {
+ efct_hw_done_t done = io->done;
+ void *arg = io->arg;
+
+ /*
+ * Use latched status as this is always saved for an internal
+ * abort
+ */
+ int status = io->saved_status;
+ u32 len = io->saved_len;
+ u32 ext = io->saved_ext;
+
+ io->done = NULL;
+ io->status_saved = false;
+
+ done(io, len, status, ext, arg);
+ }
+
+ spin_lock_irqsave(&hw->io_lock, flags);
+ if (io->state == EFCT_HW_IO_STATE_INUSE ||
+ io->state == EFCT_HW_IO_STATE_WAIT_FREE) {
+ /* if on wait_free list, caller has already freed IO;
+ * remove from wait_free list and add to free list.
+ * if on in-use list, already marked as no longer busy;
+ * just leave there and wait for caller to free.
+ */
+ if (io->state == EFCT_HW_IO_STATE_WAIT_FREE) {
+ io->state = EFCT_HW_IO_STATE_FREE;
+ list_del_init(&io->list_entry);
+ efct_hw_io_free_move_correct_list(hw, io);
+ }
+ }
+ spin_unlock_irqrestore(&hw->io_lock, flags);
+}
+
+static int
+efct_hw_flush(struct efct_hw *hw)
+{
+ u32 i = 0;
+
+ /* Process any remaining completions */
+ for (i = 0; i < hw->eq_count; i++)
+ efct_hw_process(hw, i, ~0);
+
+ return 0;
+}
+
+int
+efct_hw_wq_write(struct hw_wq *wq, struct efct_hw_wqe *wqe)
+{
+ int rc = 0;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&wq->queue->lock, flags);
+ if (list_empty(&wq->pending_list)) {
+ if (wq->free_count > 0) {
+ rc = _efct_hw_wq_write(wq, wqe);
+ } else {
+ INIT_LIST_HEAD(&wqe->list_entry);
+ list_add_tail(&wqe->list_entry, &wq->pending_list);
+ wq->wq_pending_count++;
+ }
+
+ spin_unlock_irqrestore(&wq->queue->lock, flags);
+ return rc;
+ }
+
+ INIT_LIST_HEAD(&wqe->list_entry);
+ list_add_tail(&wqe->list_entry, &wq->pending_list);
+ wq->wq_pending_count++;
+ while (wq->free_count > 0) {
+ wqe = list_first_entry(&wq->pending_list, struct efct_hw_wqe,
+ list_entry);
+ if (!wqe)
+ break;
+
+ list_del_init(&wqe->list_entry);
+ rc = _efct_hw_wq_write(wq, wqe);
+ if (rc)
+ break;
+
+ if (wqe->abort_wqe_submit_needed) {
+ wqe->abort_wqe_submit_needed = false;
+ efct_hw_fill_abort_wqe(wq->hw, wqe);
+
+ INIT_LIST_HEAD(&wqe->list_entry);
+ list_add_tail(&wqe->list_entry, &wq->pending_list);
+ wq->wq_pending_count++;
+ }
+ }
+
+ spin_unlock_irqrestore(&wq->queue->lock, flags);
+
+ return rc;
+}
+
+int
+efct_efc_bls_send(struct efc *efc, u32 type, struct sli_bls_params *bls)
+{
+ struct efct *efct = efc->base;
+
+ return efct_hw_bls_send(efct, type, bls, NULL, NULL);
+}
+
+int
+efct_hw_bls_send(struct efct *efct, u32 type, struct sli_bls_params *bls_params,
+ void *cb, void *arg)
+{
+ struct efct_hw *hw = &efct->hw;
+ struct efct_hw_io *hio;
+ struct sli_bls_payload bls;
+ int rc;
+
+ if (hw->state != EFCT_HW_STATE_ACTIVE) {
+ efc_log_err(hw->os,
+ "cannot send BLS, HW state=%d\n", hw->state);
+ return -EIO;
+ }
+
+ hio = efct_hw_io_alloc(hw);
+ if (!hio) {
+ efc_log_err(hw->os, "HIO allocation failed\n");
+ return -EIO;
+ }
+
+ hio->done = cb;
+ hio->arg = arg;
+
+ bls_params->xri = hio->indicator;
+ bls_params->tag = hio->reqtag;
+
+ if (type == FC_RCTL_BA_ACC) {
+ hio->type = EFCT_HW_BLS_ACC;
+ bls.type = SLI4_SLI_BLS_ACC;
+ memcpy(&bls.u.acc, bls_params->payload, sizeof(bls.u.acc));
+ } else {
+ hio->type = EFCT_HW_BLS_RJT;
+ bls.type = SLI4_SLI_BLS_RJT;
+ memcpy(&bls.u.rjt, bls_params->payload, sizeof(bls.u.rjt));
+ }
+
+ bls.ox_id = cpu_to_le16(bls_params->ox_id);
+ bls.rx_id = cpu_to_le16(bls_params->rx_id);
+
+ if (sli_xmit_bls_rsp64_wqe(&hw->sli, hio->wqe.wqebuf,
+ &bls, bls_params)) {
+ efc_log_err(hw->os, "XMIT_BLS_RSP64 WQE error\n");
+ return -EIO;
+ }
+
+ hio->xbusy = true;
+
+ /*
+ * Add IO to active io wqe list before submitting, in case the
+ * wcqe processing preempts this thread.
+ */
+ hio->wq->use_count++;
+ rc = efct_hw_wq_write(hio->wq, &hio->wqe);
+ if (rc >= 0) {
+ /* non-negative return is success */
+ rc = 0;
+ } else {
+ /* failed to write wqe, remove from active wqe list */
+ efc_log_err(hw->os,
+ "sli_queue_write failed: %d\n", rc);
+ hio->xbusy = false;
+ }
+
+ return rc;
+}
+
+static int
+efct_els_ssrs_send_cb(struct efct_hw_io *hio, u32 length, int status,
+ u32 ext_status, void *arg)
+{
+ struct efc_disc_io *io = arg;
+
+ efc_disc_io_complete(io, length, status, ext_status);
+ return 0;
+}
+
+static inline void
+efct_fill_els_params(struct efc_disc_io *io, struct sli_els_params *params)
+{
+ u8 *cmd = io->req.virt;
+
+ params->cmd = *cmd;
+ params->s_id = io->s_id;
+ params->d_id = io->d_id;
+ params->ox_id = io->iparam.els.ox_id;
+ params->rpi = io->rpi;
+ params->vpi = io->vpi;
+ params->rpi_registered = io->rpi_registered;
+ params->xmit_len = io->xmit_len;
+ params->rsp_len = io->rsp_len;
+ params->timeout = io->iparam.els.timeout;
+}
+
+static inline void
+efct_fill_ct_params(struct efc_disc_io *io, struct sli_ct_params *params)
+{
+ params->r_ctl = io->iparam.ct.r_ctl;
+ params->type = io->iparam.ct.type;
+ params->df_ctl = io->iparam.ct.df_ctl;
+ params->d_id = io->d_id;
+ params->ox_id = io->iparam.ct.ox_id;
+ params->rpi = io->rpi;
+ params->vpi = io->vpi;
+ params->rpi_registered = io->rpi_registered;
+ params->xmit_len = io->xmit_len;
+ params->rsp_len = io->rsp_len;
+ params->timeout = io->iparam.ct.timeout;
+}
+
+/**
+ * efct_els_hw_srrs_send() - Send a single request and response cmd.
+ * @efc: efc library structure
+ * @io: Discovery IO used to hold els and ct cmd context.
+ *
+ * This routine supports communication sequences consisting of a single
+ * request and single response between two endpoints. Examples include:
+ * - Sending an ELS request.
+ * - Sending an ELS response - To send an ELS response, the caller must provide
+ * the OX_ID from the received request.
+ * - Sending a FC Common Transport (FC-CT) request - To send a FC-CT request,
+ * the caller must provide the R_CTL, TYPE, and DF_CTL
+ * values to place in the FC frame header.
+ *
+ * Return: Status of the request.
+ */
+int
+efct_els_hw_srrs_send(struct efc *efc, struct efc_disc_io *io)
+{
+ struct efct *efct = efc->base;
+ struct efct_hw_io *hio;
+ struct efct_hw *hw = &efct->hw;
+ struct efc_dma *send = &io->req;
+ struct efc_dma *receive = &io->rsp;
+ struct sli4_sge *sge = NULL;
+ int rc = 0;
+ u32 len = io->xmit_len;
+ u32 sge0_flags;
+ u32 sge1_flags;
+
+ hio = efct_hw_io_alloc(hw);
+ if (!hio) {
+ pr_err("HIO alloc failed\n");
+ return -EIO;
+ }
+
+ if (hw->state != EFCT_HW_STATE_ACTIVE) {
+ efc_log_debug(hw->os,
+ "cannot send SRRS, HW state=%d\n", hw->state);
+ return -EIO;
+ }
+
+ hio->done = efct_els_ssrs_send_cb;
+ hio->arg = io;
+
+ sge = hio->sgl->virt;
+
+ /* clear both SGE */
+ memset(hio->sgl->virt, 0, 2 * sizeof(struct sli4_sge));
+
+ sge0_flags = le32_to_cpu(sge[0].dw2_flags);
+ sge1_flags = le32_to_cpu(sge[1].dw2_flags);
+ if (send->size) {
+ sge[0].buffer_address_high =
+ cpu_to_le32(upper_32_bits(send->phys));
+ sge[0].buffer_address_low =
+ cpu_to_le32(lower_32_bits(send->phys));
+
+ sge0_flags |= (SLI4_SGE_TYPE_DATA << SLI4_SGE_TYPE_SHIFT);
+
+ sge[0].buffer_length = cpu_to_le32(len);
+ }
+
+ if (io->io_type == EFC_DISC_IO_ELS_REQ ||
+ io->io_type == EFC_DISC_IO_CT_REQ) {
+ sge[1].buffer_address_high =
+ cpu_to_le32(upper_32_bits(receive->phys));
+ sge[1].buffer_address_low =
+ cpu_to_le32(lower_32_bits(receive->phys));
+
+ sge1_flags |= (SLI4_SGE_TYPE_DATA << SLI4_SGE_TYPE_SHIFT);
+ sge1_flags |= SLI4_SGE_LAST;
+
+ sge[1].buffer_length = cpu_to_le32(receive->size);
+ } else {
+ sge0_flags |= SLI4_SGE_LAST;
+ }
+
+ sge[0].dw2_flags = cpu_to_le32(sge0_flags);
+ sge[1].dw2_flags = cpu_to_le32(sge1_flags);
+
+ switch (io->io_type) {
+ case EFC_DISC_IO_ELS_REQ: {
+ struct sli_els_params els_params;
+
+ hio->type = EFCT_HW_ELS_REQ;
+ efct_fill_els_params(io, &els_params);
+ els_params.xri = hio->indicator;
+ els_params.tag = hio->reqtag;
+
+ if (sli_els_request64_wqe(&hw->sli, hio->wqe.wqebuf, hio->sgl,
+ &els_params)) {
+ efc_log_err(hw->os, "REQ WQE error\n");
+ rc = -EIO;
+ }
+ break;
+ }
+ case EFC_DISC_IO_ELS_RESP: {
+ struct sli_els_params els_params;
+
+ hio->type = EFCT_HW_ELS_RSP;
+ efct_fill_els_params(io, &els_params);
+ els_params.xri = hio->indicator;
+ els_params.tag = hio->reqtag;
+ if (sli_xmit_els_rsp64_wqe(&hw->sli, hio->wqe.wqebuf, send,
+ &els_params)){
+ efc_log_err(hw->os, "RSP WQE error\n");
+ rc = -EIO;
+ }
+ break;
+ }
+ case EFC_DISC_IO_CT_REQ: {
+ struct sli_ct_params ct_params;
+
+ hio->type = EFCT_HW_FC_CT;
+ efct_fill_ct_params(io, &ct_params);
+ ct_params.xri = hio->indicator;
+ ct_params.tag = hio->reqtag;
+ if (sli_gen_request64_wqe(&hw->sli, hio->wqe.wqebuf, hio->sgl,
+ &ct_params)){
+ efc_log_err(hw->os, "GEN WQE error\n");
+ rc = -EIO;
+ }
+ break;
+ }
+ case EFC_DISC_IO_CT_RESP: {
+ struct sli_ct_params ct_params;
+
+ hio->type = EFCT_HW_FC_CT_RSP;
+ efct_fill_ct_params(io, &ct_params);
+ ct_params.xri = hio->indicator;
+ ct_params.tag = hio->reqtag;
+ if (sli_xmit_sequence64_wqe(&hw->sli, hio->wqe.wqebuf, hio->sgl,
+ &ct_params)){
+ efc_log_err(hw->os, "XMIT SEQ WQE error\n");
+ rc = -EIO;
+ }
+ break;
+ }
+ default:
+ efc_log_err(hw->os, "bad SRRS type %#x\n", io->io_type);
+ rc = -EIO;
+ }
+
+ if (rc == 0) {
+ hio->xbusy = true;
+
+ /*
+ * Add IO to active io wqe list before submitting, in case the
+ * wcqe processing preempts this thread.
+ */
+ hio->wq->use_count++;
+ rc = efct_hw_wq_write(hio->wq, &hio->wqe);
+ if (rc >= 0) {
+ /* non-negative return is success */
+ rc = 0;
+ } else {
+ /* failed to write wqe, remove from active wqe list */
+ efc_log_err(hw->os,
+ "sli_queue_write failed: %d\n", rc);
+ hio->xbusy = false;
+ }
+ }
+
+ return rc;
+}
+
+int
+efct_hw_io_send(struct efct_hw *hw, enum efct_hw_io_type type,
+ struct efct_hw_io *io, union efct_hw_io_param_u *iparam,
+ void *cb, void *arg)
+{
+ int rc = 0;
+ bool send_wqe = true;
+
+ if (!io) {
+ pr_err("bad parm hw=%p io=%p\n", hw, io);
+ return -EIO;
+ }
+
+ if (hw->state != EFCT_HW_STATE_ACTIVE) {
+ efc_log_err(hw->os, "cannot send IO, HW state=%d\n", hw->state);
+ return -EIO;
+ }
+
+ /*
+ * Save state needed during later stages
+ */
+ io->type = type;
+ io->done = cb;
+ io->arg = arg;
+
+ /*
+ * Format the work queue entry used to send the IO
+ */
+ switch (type) {
+ case EFCT_HW_IO_TARGET_WRITE: {
+ u16 *flags = &iparam->fcp_tgt.flags;
+ struct fcp_txrdy *xfer = io->xfer_rdy.virt;
+
+ /*
+ * Fill in the XFER_RDY for IF_TYPE 0 devices
+ */
+ xfer->ft_data_ro = cpu_to_be32(iparam->fcp_tgt.offset);
+ xfer->ft_burst_len = cpu_to_be32(iparam->fcp_tgt.xmit_len);
+
+ if (io->xbusy)
+ *flags |= SLI4_IO_CONTINUATION;
+ else
+ *flags &= ~SLI4_IO_CONTINUATION;
+ iparam->fcp_tgt.xri = io->indicator;
+ iparam->fcp_tgt.tag = io->reqtag;
+
+ if (sli_fcp_treceive64_wqe(&hw->sli, io->wqe.wqebuf,
+ &io->def_sgl, io->first_data_sge,
+ SLI4_CQ_DEFAULT,
+ 0, 0, &iparam->fcp_tgt)) {
+ efc_log_err(hw->os, "TRECEIVE WQE error\n");
+ rc = -EIO;
+ }
+ break;
+ }
+ case EFCT_HW_IO_TARGET_READ: {
+ u16 *flags = &iparam->fcp_tgt.flags;
+
+ if (io->xbusy)
+ *flags |= SLI4_IO_CONTINUATION;
+ else
+ *flags &= ~SLI4_IO_CONTINUATION;
+
+ iparam->fcp_tgt.xri = io->indicator;
+ iparam->fcp_tgt.tag = io->reqtag;
+
+ if (sli_fcp_tsend64_wqe(&hw->sli, io->wqe.wqebuf,
+ &io->def_sgl, io->first_data_sge,
+ SLI4_CQ_DEFAULT,
+ 0, 0, &iparam->fcp_tgt)) {
+ efc_log_err(hw->os, "TSEND WQE error\n");
+ rc = -EIO;
+ }
+ break;
+ }
+ case EFCT_HW_IO_TARGET_RSP: {
+ u16 *flags = &iparam->fcp_tgt.flags;
+
+ if (io->xbusy)
+ *flags |= SLI4_IO_CONTINUATION;
+ else
+ *flags &= ~SLI4_IO_CONTINUATION;
+
+ iparam->fcp_tgt.xri = io->indicator;
+ iparam->fcp_tgt.tag = io->reqtag;
+
+ if (sli_fcp_trsp64_wqe(&hw->sli, io->wqe.wqebuf,
+ &io->def_sgl, SLI4_CQ_DEFAULT,
+ 0, &iparam->fcp_tgt)) {
+ efc_log_err(hw->os, "TRSP WQE error\n");
+ rc = -EIO;
+ }
+
+ break;
+ }
+ default:
+ efc_log_err(hw->os, "unsupported IO type %#x\n", type);
+ rc = -EIO;
+ }
+
+ if (send_wqe && rc == 0) {
+ io->xbusy = true;
+
+ /*
+ * Add IO to active io wqe list before submitting, in case the
+ * wcqe processing preempts this thread.
+ */
+ hw->tcmd_wq_submit[io->wq->instance]++;
+ io->wq->use_count++;
+ rc = efct_hw_wq_write(io->wq, &io->wqe);
+ if (rc >= 0) {
+ /* non-negative return is success */
+ rc = 0;
+ } else {
+ /* failed to write wqe, remove from active wqe list */
+ efc_log_err(hw->os,
+ "sli_queue_write failed: %d\n", rc);
+ io->xbusy = false;
+ }
+ }
+
+ return rc;
+}
+
+int
+efct_hw_send_frame(struct efct_hw *hw, struct fc_frame_header *hdr,
+ u8 sof, u8 eof, struct efc_dma *payload,
+ struct efct_hw_send_frame_context *ctx,
+ void (*callback)(void *arg, u8 *cqe, int status),
+ void *arg)
+{
+ int rc;
+ struct efct_hw_wqe *wqe;
+ u32 xri;
+ struct hw_wq *wq;
+
+ wqe = &ctx->wqe;
+
+ /* populate the callback object */
+ ctx->hw = hw;
+
+ /* Fetch and populate request tag */
+ ctx->wqcb = efct_hw_reqtag_alloc(hw, callback, arg);
+ if (!ctx->wqcb) {
+ efc_log_err(hw->os, "can't allocate request tag\n");
+ return -ENOSPC;
+ }
+
+ wq = hw->hw_wq[0];
+
+ /* Set XRI and RX_ID in the header based on which WQ, and which
+ * send_frame_io we are using
+ */
+ xri = wq->send_frame_io->indicator;
+
+ /* Build the send frame WQE */
+ rc = sli_send_frame_wqe(&hw->sli, wqe->wqebuf,
+ sof, eof, (u32 *)hdr, payload, payload->len,
+ EFCT_HW_SEND_FRAME_TIMEOUT, xri,
+ ctx->wqcb->instance_index);
+ if (rc) {
+ efc_log_err(hw->os, "sli_send_frame_wqe failed: %d\n", rc);
+ return -EIO;
+ }
+
+ /* Write to WQ */
+ rc = efct_hw_wq_write(wq, wqe);
+ if (rc) {
+ efc_log_err(hw->os, "efct_hw_wq_write failed: %d\n", rc);
+ return -EIO;
+ }
+
+ wq->use_count++;
+
+ return 0;
+}
+
+static int
+efct_hw_cb_link_stat(struct efct_hw *hw, int status,
+ u8 *mqe, void *arg)
+{
+ struct sli4_cmd_read_link_stats *mbox_rsp;
+ struct efct_hw_link_stat_cb_arg *cb_arg = arg;
+ struct efct_hw_link_stat_counts counts[EFCT_HW_LINK_STAT_MAX];
+ u32 num_counters, i;
+ u32 mbox_rsp_flags = 0;
+
+ mbox_rsp = (struct sli4_cmd_read_link_stats *)mqe;
+ mbox_rsp_flags = le32_to_cpu(mbox_rsp->dw1_flags);
+ num_counters = (mbox_rsp_flags & SLI4_READ_LNKSTAT_GEC) ? 20 : 13;
+ memset(counts, 0, sizeof(struct efct_hw_link_stat_counts) *
+ EFCT_HW_LINK_STAT_MAX);
+
+ /* Fill overflow counts, mask starts from SLI4_READ_LNKSTAT_W02OF*/
+ for (i = 0; i < EFCT_HW_LINK_STAT_MAX; i++)
+ counts[i].overflow = (mbox_rsp_flags & (1 << (i + 2)));
+
+ counts[EFCT_HW_LINK_STAT_LINK_FAILURE_COUNT].counter =
+ le32_to_cpu(mbox_rsp->linkfail_errcnt);
+ counts[EFCT_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].counter =
+ le32_to_cpu(mbox_rsp->losssync_errcnt);
+ counts[EFCT_HW_LINK_STAT_LOSS_OF_SIGNAL_COUNT].counter =
+ le32_to_cpu(mbox_rsp->losssignal_errcnt);
+ counts[EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].counter =
+ le32_to_cpu(mbox_rsp->primseq_errcnt);
+ counts[EFCT_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].counter =
+ le32_to_cpu(mbox_rsp->inval_txword_errcnt);
+ counts[EFCT_HW_LINK_STAT_CRC_COUNT].counter =
+ le32_to_cpu(mbox_rsp->crc_errcnt);
+ counts[EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_TIMEOUT_COUNT].counter =
+ le32_to_cpu(mbox_rsp->primseq_eventtimeout_cnt);
+ counts[EFCT_HW_LINK_STAT_ELASTIC_BUFFER_OVERRUN_COUNT].counter =
+ le32_to_cpu(mbox_rsp->elastic_bufoverrun_errcnt);
+ counts[EFCT_HW_LINK_STAT_ARB_TIMEOUT_COUNT].counter =
+ le32_to_cpu(mbox_rsp->arbit_fc_al_timeout_cnt);
+ counts[EFCT_HW_LINK_STAT_ADVERTISED_RCV_B2B_CREDIT].counter =
+ le32_to_cpu(mbox_rsp->adv_rx_buftor_to_buf_credit);
+ counts[EFCT_HW_LINK_STAT_CURR_RCV_B2B_CREDIT].counter =
+ le32_to_cpu(mbox_rsp->curr_rx_buf_to_buf_credit);
+ counts[EFCT_HW_LINK_STAT_ADVERTISED_XMIT_B2B_CREDIT].counter =
+ le32_to_cpu(mbox_rsp->adv_tx_buf_to_buf_credit);
+ counts[EFCT_HW_LINK_STAT_CURR_XMIT_B2B_CREDIT].counter =
+ le32_to_cpu(mbox_rsp->curr_tx_buf_to_buf_credit);
+ counts[EFCT_HW_LINK_STAT_RCV_EOFA_COUNT].counter =
+ le32_to_cpu(mbox_rsp->rx_eofa_cnt);
+ counts[EFCT_HW_LINK_STAT_RCV_EOFDTI_COUNT].counter =
+ le32_to_cpu(mbox_rsp->rx_eofdti_cnt);
+ counts[EFCT_HW_LINK_STAT_RCV_EOFNI_COUNT].counter =
+ le32_to_cpu(mbox_rsp->rx_eofni_cnt);
+ counts[EFCT_HW_LINK_STAT_RCV_SOFF_COUNT].counter =
+ le32_to_cpu(mbox_rsp->rx_soff_cnt);
+ counts[EFCT_HW_LINK_STAT_RCV_DROPPED_NO_AER_COUNT].counter =
+ le32_to_cpu(mbox_rsp->rx_dropped_no_aer_cnt);
+ counts[EFCT_HW_LINK_STAT_RCV_DROPPED_NO_RPI_COUNT].counter =
+ le32_to_cpu(mbox_rsp->rx_dropped_no_avail_rpi_rescnt);
+ counts[EFCT_HW_LINK_STAT_RCV_DROPPED_NO_XRI_COUNT].counter =
+ le32_to_cpu(mbox_rsp->rx_dropped_no_avail_xri_rescnt);
+
+ if (cb_arg) {
+ if (cb_arg->cb) {
+ if (status == 0 && le16_to_cpu(mbox_rsp->hdr.status))
+ status = le16_to_cpu(mbox_rsp->hdr.status);
+ cb_arg->cb(status, num_counters, counts, cb_arg->arg);
+ }
+
+ kfree(cb_arg);
+ }
+
+ return 0;
+}
+
+int
+efct_hw_get_link_stats(struct efct_hw *hw, u8 req_ext_counters,
+ u8 clear_overflow_flags, u8 clear_all_counters,
+ void (*cb)(int status, u32 num_counters,
+ struct efct_hw_link_stat_counts *counters,
+ void *arg),
+ void *arg)
+{
+ int rc = -EIO;
+ struct efct_hw_link_stat_cb_arg *cb_arg;
+ u8 mbxdata[SLI4_BMBX_SIZE];
+
+ cb_arg = kzalloc(sizeof(*cb_arg), GFP_ATOMIC);
+ if (!cb_arg)
+ return -ENOMEM;
+
+ cb_arg->cb = cb;
+ cb_arg->arg = arg;
+
+ /* Send the HW command */
+ if (!sli_cmd_read_link_stats(&hw->sli, mbxdata, req_ext_counters,
+ clear_overflow_flags, clear_all_counters))
+ rc = efct_hw_command(hw, mbxdata, EFCT_CMD_NOWAIT,
+ efct_hw_cb_link_stat, cb_arg);
+
+ if (rc)
+ kfree(cb_arg);
+
+ return rc;
+}
+
+static int
+efct_hw_cb_host_stat(struct efct_hw *hw, int status, u8 *mqe, void *arg)
+{
+ struct sli4_cmd_read_status *mbox_rsp =
+ (struct sli4_cmd_read_status *)mqe;
+ struct efct_hw_host_stat_cb_arg *cb_arg = arg;
+ struct efct_hw_host_stat_counts counts[EFCT_HW_HOST_STAT_MAX];
+ u32 num_counters = EFCT_HW_HOST_STAT_MAX;
+
+ memset(counts, 0, sizeof(struct efct_hw_host_stat_counts) *
+ EFCT_HW_HOST_STAT_MAX);
+
+ counts[EFCT_HW_HOST_STAT_TX_KBYTE_COUNT].counter =
+ le32_to_cpu(mbox_rsp->trans_kbyte_cnt);
+ counts[EFCT_HW_HOST_STAT_RX_KBYTE_COUNT].counter =
+ le32_to_cpu(mbox_rsp->recv_kbyte_cnt);
+ counts[EFCT_HW_HOST_STAT_TX_FRAME_COUNT].counter =
+ le32_to_cpu(mbox_rsp->trans_frame_cnt);
+ counts[EFCT_HW_HOST_STAT_RX_FRAME_COUNT].counter =
+ le32_to_cpu(mbox_rsp->recv_frame_cnt);
+ counts[EFCT_HW_HOST_STAT_TX_SEQ_COUNT].counter =
+ le32_to_cpu(mbox_rsp->trans_seq_cnt);
+ counts[EFCT_HW_HOST_STAT_RX_SEQ_COUNT].counter =
+ le32_to_cpu(mbox_rsp->recv_seq_cnt);
+ counts[EFCT_HW_HOST_STAT_TOTAL_EXCH_ORIG].counter =
+ le32_to_cpu(mbox_rsp->tot_exchanges_orig);
+ counts[EFCT_HW_HOST_STAT_TOTAL_EXCH_RESP].counter =
+ le32_to_cpu(mbox_rsp->tot_exchanges_resp);
+ counts[EFCT_HW_HOSY_STAT_RX_P_BSY_COUNT].counter =
+ le32_to_cpu(mbox_rsp->recv_p_bsy_cnt);
+ counts[EFCT_HW_HOST_STAT_RX_F_BSY_COUNT].counter =
+ le32_to_cpu(mbox_rsp->recv_f_bsy_cnt);
+ counts[EFCT_HW_HOST_STAT_DROP_FRM_DUE_TO_NO_RQ_BUF_COUNT].counter =
+ le32_to_cpu(mbox_rsp->no_rq_buf_dropped_frames_cnt);
+ counts[EFCT_HW_HOST_STAT_EMPTY_RQ_TIMEOUT_COUNT].counter =
+ le32_to_cpu(mbox_rsp->empty_rq_timeout_cnt);
+ counts[EFCT_HW_HOST_STAT_DROP_FRM_DUE_TO_NO_XRI_COUNT].counter =
+ le32_to_cpu(mbox_rsp->no_xri_dropped_frames_cnt);
+ counts[EFCT_HW_HOST_STAT_EMPTY_XRI_POOL_COUNT].counter =
+ le32_to_cpu(mbox_rsp->empty_xri_pool_cnt);
+
+ if (cb_arg) {
+ if (cb_arg->cb) {
+ if (status == 0 && le16_to_cpu(mbox_rsp->hdr.status))
+ status = le16_to_cpu(mbox_rsp->hdr.status);
+ cb_arg->cb(status, num_counters, counts, cb_arg->arg);
+ }
+
+ kfree(cb_arg);
+ }
+
+ return 0;
+}
+
+int
+efct_hw_get_host_stats(struct efct_hw *hw, u8 cc,
+ void (*cb)(int status, u32 num_counters,
+ struct efct_hw_host_stat_counts *counters,
+ void *arg),
+ void *arg)
+{
+ int rc = -EIO;
+ struct efct_hw_host_stat_cb_arg *cb_arg;
+ u8 mbxdata[SLI4_BMBX_SIZE];
+
+ cb_arg = kmalloc(sizeof(*cb_arg), GFP_ATOMIC);
+ if (!cb_arg)
+ return -ENOMEM;
+
+ cb_arg->cb = cb;
+ cb_arg->arg = arg;
+
+ /* Send the HW command to get the host stats */
+ if (!sli_cmd_read_status(&hw->sli, mbxdata, cc))
+ rc = efct_hw_command(hw, mbxdata, EFCT_CMD_NOWAIT,
+ efct_hw_cb_host_stat, cb_arg);
+
+ if (rc) {
+ efc_log_debug(hw->os, "READ_HOST_STATS failed\n");
+ kfree(cb_arg);
+ }
+
+ return rc;
+}
+
+struct efct_hw_async_call_ctx {
+ efct_hw_async_cb_t callback;
+ void *arg;
+ u8 cmd[SLI4_BMBX_SIZE];
+};
+
+static void
+efct_hw_async_cb(struct efct_hw *hw, int status, u8 *mqe, void *arg)
+{
+ struct efct_hw_async_call_ctx *ctx = arg;
+
+ if (ctx) {
+ if (ctx->callback)
+ (*ctx->callback)(hw, status, mqe, ctx->arg);
+
+ kfree(ctx);
+ }
+}
+
+int
+efct_hw_async_call(struct efct_hw *hw, efct_hw_async_cb_t callback, void *arg)
+{
+ struct efct_hw_async_call_ctx *ctx;
+ int rc;
+
+ /*
+ * Allocate a callback context (which includes the mbox cmd buffer),
+ * we need this to be persistent as the mbox cmd submission may be
+ * queued and executed later execution.
+ */
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->callback = callback;
+ ctx->arg = arg;
+
+ /* Build and send a NOP mailbox command */
+ if (sli_cmd_common_nop(&hw->sli, ctx->cmd, 0)) {
+ efc_log_err(hw->os, "COMMON_NOP format failure\n");
+ kfree(ctx);
+ return -EIO;
+ }
+
+ rc = efct_hw_command(hw, ctx->cmd, EFCT_CMD_NOWAIT, efct_hw_async_cb,
+ ctx);
+ if (rc) {
+ efc_log_err(hw->os, "COMMON_NOP command failure, rc=%d\n", rc);
+ kfree(ctx);
+ return -EIO;
+ }
+ return 0;
+}
+
+static int
+efct_hw_cb_fw_write(struct efct_hw *hw, int status, u8 *mqe, void *arg)
+{
+ struct sli4_cmd_sli_config *mbox_rsp =
+ (struct sli4_cmd_sli_config *)mqe;
+ struct sli4_rsp_cmn_write_object *wr_obj_rsp;
+ struct efct_hw_fw_wr_cb_arg *cb_arg = arg;
+ u32 bytes_written;
+ u16 mbox_status;
+ u32 change_status;
+
+ wr_obj_rsp = (struct sli4_rsp_cmn_write_object *)
+ &mbox_rsp->payload.embed;
+ bytes_written = le32_to_cpu(wr_obj_rsp->actual_write_length);
+ mbox_status = le16_to_cpu(mbox_rsp->hdr.status);
+ change_status = (le32_to_cpu(wr_obj_rsp->change_status_dword) &
+ RSP_CHANGE_STATUS);
+
+ if (cb_arg) {
+ if (cb_arg->cb) {
+ if (!status && mbox_status)
+ status = mbox_status;
+ cb_arg->cb(status, bytes_written, change_status,
+ cb_arg->arg);
+ }
+
+ kfree(cb_arg);
+ }
+
+ return 0;
+}
+
+int
+efct_hw_firmware_write(struct efct_hw *hw, struct efc_dma *dma, u32 size,
+ u32 offset, int last,
+ void (*cb)(int status, u32 bytes_written,
+ u32 change_status, void *arg),
+ void *arg)
+{
+ int rc = -EIO;
+ u8 mbxdata[SLI4_BMBX_SIZE];
+ struct efct_hw_fw_wr_cb_arg *cb_arg;
+ int noc = 0;
+
+ cb_arg = kzalloc(sizeof(*cb_arg), GFP_KERNEL);
+ if (!cb_arg)
+ return -ENOMEM;
+
+ cb_arg->cb = cb;
+ cb_arg->arg = arg;
+
+ /* Write a portion of a firmware image to the device */
+ if (!sli_cmd_common_write_object(&hw->sli, mbxdata,
+ noc, last, size, offset, "/prg/",
+ dma))
+ rc = efct_hw_command(hw, mbxdata, EFCT_CMD_NOWAIT,
+ efct_hw_cb_fw_write, cb_arg);
+
+ if (rc != 0) {
+ efc_log_debug(hw->os, "COMMON_WRITE_OBJECT failed\n");
+ kfree(cb_arg);
+ }
+
+ return rc;
+}
+
+static int
+efct_hw_cb_port_control(struct efct_hw *hw, int status, u8 *mqe,
+ void *arg)
+{
+ return 0;
+}
+
+int
+efct_hw_port_control(struct efct_hw *hw, enum efct_hw_port ctrl,
+ uintptr_t value,
+ void (*cb)(int status, uintptr_t value, void *arg),
+ void *arg)
+{
+ int rc = -EIO;
+ u8 link[SLI4_BMBX_SIZE];
+ u32 speed = 0;
+ u8 reset_alpa = 0;
+
+ switch (ctrl) {
+ case EFCT_HW_PORT_INIT:
+ if (!sli_cmd_config_link(&hw->sli, link))
+ rc = efct_hw_command(hw, link, EFCT_CMD_NOWAIT,
+ efct_hw_cb_port_control, NULL);
+
+ if (rc != 0) {
+ efc_log_err(hw->os, "CONFIG_LINK failed\n");
+ break;
+ }
+ speed = hw->config.speed;
+ reset_alpa = (u8)(value & 0xff);
+
+ rc = -EIO;
+ if (!sli_cmd_init_link(&hw->sli, link, speed, reset_alpa))
+ rc = efct_hw_command(hw, link, EFCT_CMD_NOWAIT,
+ efct_hw_cb_port_control, NULL);
+ /* Free buffer on error, since no callback is coming */
+ if (rc)
+ efc_log_err(hw->os, "INIT_LINK failed\n");
+ break;
+
+ case EFCT_HW_PORT_SHUTDOWN:
+ if (!sli_cmd_down_link(&hw->sli, link))
+ rc = efct_hw_command(hw, link, EFCT_CMD_NOWAIT,
+ efct_hw_cb_port_control, NULL);
+ /* Free buffer on error, since no callback is coming */
+ if (rc)
+ efc_log_err(hw->os, "DOWN_LINK failed\n");
+ break;
+
+ default:
+ efc_log_debug(hw->os, "unhandled control %#x\n", ctrl);
+ break;
+ }
+
+ return rc;
+}
+
+void
+efct_hw_teardown(struct efct_hw *hw)
+{
+ u32 i = 0;
+ u32 destroy_queues;
+ u32 free_memory;
+ struct efc_dma *dma;
+ struct efct *efct = hw->os;
+
+ destroy_queues = (hw->state == EFCT_HW_STATE_ACTIVE);
+ free_memory = (hw->state != EFCT_HW_STATE_UNINITIALIZED);
+
+ /* Cancel Sliport Healthcheck */
+ if (hw->sliport_healthcheck) {
+ hw->sliport_healthcheck = 0;
+ efct_hw_config_sli_port_health_check(hw, 0, 0);
+ }
+
+ if (hw->state != EFCT_HW_STATE_QUEUES_ALLOCATED) {
+ hw->state = EFCT_HW_STATE_TEARDOWN_IN_PROGRESS;
+
+ efct_hw_flush(hw);
+
+ if (list_empty(&hw->cmd_head))
+ efc_log_debug(hw->os,
+ "All commands completed on MQ queue\n");
+ else
+ efc_log_debug(hw->os,
+ "Some cmds still pending on MQ queue\n");
+
+ /* Cancel any remaining commands */
+ efct_hw_command_cancel(hw);
+ } else {
+ hw->state = EFCT_HW_STATE_TEARDOWN_IN_PROGRESS;
+ }
+
+ dma_free_coherent(&efct->pci->dev,
+ hw->rnode_mem.size, hw->rnode_mem.virt,
+ hw->rnode_mem.phys);
+ memset(&hw->rnode_mem, 0, sizeof(struct efc_dma));
+
+ if (hw->io) {
+ for (i = 0; i < hw->config.n_io; i++) {
+ if (hw->io[i] && hw->io[i]->sgl &&
+ hw->io[i]->sgl->virt) {
+ dma_free_coherent(&efct->pci->dev,
+ hw->io[i]->sgl->size,
+ hw->io[i]->sgl->virt,
+ hw->io[i]->sgl->phys);
+ }
+ kfree(hw->io[i]);
+ hw->io[i] = NULL;
+ }
+ kfree(hw->io);
+ hw->io = NULL;
+ kfree(hw->wqe_buffs);
+ hw->wqe_buffs = NULL;
+ }
+
+ dma = &hw->xfer_rdy;
+ dma_free_coherent(&efct->pci->dev,
+ dma->size, dma->virt, dma->phys);
+ memset(dma, 0, sizeof(struct efc_dma));
+
+ dma = &hw->loop_map;
+ dma_free_coherent(&efct->pci->dev,
+ dma->size, dma->virt, dma->phys);
+ memset(dma, 0, sizeof(struct efc_dma));
+
+ for (i = 0; i < hw->wq_count; i++)
+ sli_queue_free(&hw->sli, &hw->wq[i], destroy_queues,
+ free_memory);
+
+ for (i = 0; i < hw->rq_count; i++)
+ sli_queue_free(&hw->sli, &hw->rq[i], destroy_queues,
+ free_memory);
+
+ for (i = 0; i < hw->mq_count; i++)
+ sli_queue_free(&hw->sli, &hw->mq[i], destroy_queues,
+ free_memory);
+
+ for (i = 0; i < hw->cq_count; i++)
+ sli_queue_free(&hw->sli, &hw->cq[i], destroy_queues,
+ free_memory);
+
+ for (i = 0; i < hw->eq_count; i++)
+ sli_queue_free(&hw->sli, &hw->eq[i], destroy_queues,
+ free_memory);
+
+ /* Free rq buffers */
+ efct_hw_rx_free(hw);
+
+ efct_hw_queue_teardown(hw);
+
+ kfree(hw->wq_cpu_array);
+
+ sli_teardown(&hw->sli);
+
+ /* record the fact that the queues are non-functional */
+ hw->state = EFCT_HW_STATE_UNINITIALIZED;
+
+ /* free sequence free pool */
+ kfree(hw->seq_pool);
+ hw->seq_pool = NULL;
+
+ /* free hw_wq_callback pool */
+ efct_hw_reqtag_pool_free(hw);
+
+ mempool_destroy(hw->cmd_ctx_pool);
+ mempool_destroy(hw->mbox_rqst_pool);
+
+ /* Mark HW setup as not having been called */
+ hw->hw_setup_called = false;
+}
+
+static int
+efct_hw_sli_reset(struct efct_hw *hw, enum efct_hw_reset reset,
+ enum efct_hw_state prev_state)
+{
+ int rc = 0;
+
+ switch (reset) {
+ case EFCT_HW_RESET_FUNCTION:
+ efc_log_debug(hw->os, "issuing function level reset\n");
+ if (sli_reset(&hw->sli)) {
+ efc_log_err(hw->os, "sli_reset failed\n");
+ rc = -EIO;
+ }
+ break;
+ case EFCT_HW_RESET_FIRMWARE:
+ efc_log_debug(hw->os, "issuing firmware reset\n");
+ if (sli_fw_reset(&hw->sli)) {
+ efc_log_err(hw->os, "sli_soft_reset failed\n");
+ rc = -EIO;
+ }
+ /*
+ * Because the FW reset leaves the FW in a non-running state,
+ * follow that with a regular reset.
+ */
+ efc_log_debug(hw->os, "issuing function level reset\n");
+ if (sli_reset(&hw->sli)) {
+ efc_log_err(hw->os, "sli_reset failed\n");
+ rc = -EIO;
+ }
+ break;
+ default:
+ efc_log_err(hw->os, "unknown type - no reset performed\n");
+ hw->state = prev_state;
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+int
+efct_hw_reset(struct efct_hw *hw, enum efct_hw_reset reset)
+{
+ int rc = 0;
+ enum efct_hw_state prev_state = hw->state;
+
+ if (hw->state != EFCT_HW_STATE_ACTIVE)
+ efc_log_debug(hw->os,
+ "HW state %d is not active\n", hw->state);
+
+ hw->state = EFCT_HW_STATE_RESET_IN_PROGRESS;
+
+ /*
+ * If the prev_state is already reset/teardown in progress,
+ * don't continue further
+ */
+ if (prev_state == EFCT_HW_STATE_RESET_IN_PROGRESS ||
+ prev_state == EFCT_HW_STATE_TEARDOWN_IN_PROGRESS)
+ return efct_hw_sli_reset(hw, reset, prev_state);
+
+ if (prev_state != EFCT_HW_STATE_UNINITIALIZED) {
+ efct_hw_flush(hw);
+
+ if (list_empty(&hw->cmd_head))
+ efc_log_debug(hw->os,
+ "All commands completed on MQ queue\n");
+ else
+ efc_log_err(hw->os,
+ "Some commands still pending on MQ queue\n");
+ }
+
+ /* Reset the chip */
+ rc = efct_hw_sli_reset(hw, reset, prev_state);
+ if (rc == -EINVAL)
+ return -EIO;
+
+ return rc;
+}
diff --git a/drivers/scsi/elx/efct/efct_hw.h b/drivers/scsi/elx/efct/efct_hw.h
new file mode 100644
index 000000000000..f3f4aa78dce9
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_hw.h
@@ -0,0 +1,764 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#ifndef _EFCT_HW_H
+#define _EFCT_HW_H
+
+#include "../libefc_sli/sli4.h"
+
+/*
+ * EFCT PCI IDs
+ */
+#define EFCT_VENDOR_ID 0x10df
+/* LightPulse 16Gb x 4 FC (lancer-g6) */
+#define EFCT_DEVICE_LANCER_G6 0xe307
+/* LightPulse 32Gb x 4 FC (lancer-g7) */
+#define EFCT_DEVICE_LANCER_G7 0xf407
+
+/*Default RQ entries len used by driver*/
+#define EFCT_HW_RQ_ENTRIES_MIN 512
+#define EFCT_HW_RQ_ENTRIES_DEF 1024
+#define EFCT_HW_RQ_ENTRIES_MAX 4096
+
+/*Defines the size of the RQ buffers used for each RQ*/
+#define EFCT_HW_RQ_SIZE_HDR 128
+#define EFCT_HW_RQ_SIZE_PAYLOAD 1024
+
+/*Define the maximum number of multi-receive queues*/
+#define EFCT_HW_MAX_MRQS 8
+
+/*
+ * Define count of when to set the WQEC bit in a submitted
+ * WQE, causing a consummed/released completion to be posted.
+ */
+#define EFCT_HW_WQEC_SET_COUNT 32
+
+/*Send frame timeout in seconds*/
+#define EFCT_HW_SEND_FRAME_TIMEOUT 10
+
+/*
+ * FDT Transfer Hint value, reads greater than this value
+ * will be segmented to implement fairness. A value of zero disables
+ * the feature.
+ */
+#define EFCT_HW_FDT_XFER_HINT 8192
+
+#define EFCT_HW_TIMECHECK_ITERATIONS 100
+#define EFCT_HW_MAX_NUM_MQ 1
+#define EFCT_HW_MAX_NUM_RQ 32
+#define EFCT_HW_MAX_NUM_EQ 16
+#define EFCT_HW_MAX_NUM_WQ 32
+#define EFCT_HW_DEF_NUM_EQ 1
+
+#define OCE_HW_MAX_NUM_MRQ_PAIRS 16
+
+#define EFCT_HW_MQ_DEPTH 128
+#define EFCT_HW_EQ_DEPTH 1024
+
+/*
+ * A CQ will be assinged to each WQ
+ * (CQ must have 2X entries of the WQ for abort
+ * processing), plus a separate one for each RQ PAIR and one for MQ
+ */
+#define EFCT_HW_MAX_NUM_CQ \
+ ((EFCT_HW_MAX_NUM_WQ * 2) + 1 + (OCE_HW_MAX_NUM_MRQ_PAIRS * 2))
+
+#define EFCT_HW_Q_HASH_SIZE 128
+#define EFCT_HW_RQ_HEADER_SIZE 128
+#define EFCT_HW_RQ_HEADER_INDEX 0
+
+#define EFCT_HW_REQUE_XRI_REGTAG 65534
+
+/* Options for efct_hw_command() */
+enum efct_cmd_opts {
+ /* command executes synchronously and busy-waits for completion */
+ EFCT_CMD_POLL,
+ /* command executes asynchronously. Uses callback */
+ EFCT_CMD_NOWAIT,
+};
+
+enum efct_hw_reset {
+ EFCT_HW_RESET_FUNCTION,
+ EFCT_HW_RESET_FIRMWARE,
+ EFCT_HW_RESET_MAX
+};
+
+enum efct_hw_topo {
+ EFCT_HW_TOPOLOGY_AUTO,
+ EFCT_HW_TOPOLOGY_NPORT,
+ EFCT_HW_TOPOLOGY_LOOP,
+ EFCT_HW_TOPOLOGY_NONE,
+ EFCT_HW_TOPOLOGY_MAX
+};
+
+/* pack fw revision values into a single uint64_t */
+#define HW_FWREV(a, b, c, d) (((uint64_t)(a) << 48) | ((uint64_t)(b) << 32) \
+ | ((uint64_t)(c) << 16) | ((uint64_t)(d)))
+
+#define EFCT_FW_VER_STR(a, b, c, d) (#a "." #b "." #c "." #d)
+
+enum efct_hw_io_type {
+ EFCT_HW_ELS_REQ,
+ EFCT_HW_ELS_RSP,
+ EFCT_HW_FC_CT,
+ EFCT_HW_FC_CT_RSP,
+ EFCT_HW_BLS_ACC,
+ EFCT_HW_BLS_RJT,
+ EFCT_HW_IO_TARGET_READ,
+ EFCT_HW_IO_TARGET_WRITE,
+ EFCT_HW_IO_TARGET_RSP,
+ EFCT_HW_IO_DNRX_REQUEUE,
+ EFCT_HW_IO_MAX,
+};
+
+enum efct_hw_io_state {
+ EFCT_HW_IO_STATE_FREE,
+ EFCT_HW_IO_STATE_INUSE,
+ EFCT_HW_IO_STATE_WAIT_FREE,
+ EFCT_HW_IO_STATE_WAIT_SEC_HIO,
+};
+
+#define EFCT_TARGET_WRITE_SKIPS 1
+#define EFCT_TARGET_READ_SKIPS 2
+
+struct efct_hw;
+struct efct_io;
+
+#define EFCT_CMD_CTX_POOL_SZ 32
+/**
+ * HW command context.
+ * Stores the state for the asynchronous commands sent to the hardware.
+ */
+struct efct_command_ctx {
+ struct list_head list_entry;
+ int (*cb)(struct efct_hw *hw, int status, u8 *mqe, void *arg);
+ void *arg; /* Argument for callback */
+ /* buffer holding command / results */
+ u8 buf[SLI4_BMBX_SIZE];
+ void *ctx; /* upper layer context */
+};
+
+struct efct_hw_sgl {
+ uintptr_t addr;
+ size_t len;
+};
+
+union efct_hw_io_param_u {
+ struct sli_bls_params bls;
+ struct sli_els_params els;
+ struct sli_ct_params fc_ct;
+ struct sli_fcp_tgt_params fcp_tgt;
+};
+
+/* WQ steering mode */
+enum efct_hw_wq_steering {
+ EFCT_HW_WQ_STEERING_CLASS,
+ EFCT_HW_WQ_STEERING_REQUEST,
+ EFCT_HW_WQ_STEERING_CPU,
+};
+
+/* HW wqe object */
+struct efct_hw_wqe {
+ struct list_head list_entry;
+ bool abort_wqe_submit_needed;
+ bool send_abts;
+ u32 id;
+ u32 abort_reqtag;
+ u8 *wqebuf;
+};
+
+struct efct_hw_io;
+/* Typedef for HW "done" callback */
+typedef int (*efct_hw_done_t)(struct efct_hw_io *, u32 len, int status,
+ u32 ext, void *ul_arg);
+
+/**
+ * HW IO object.
+ *
+ * Stores the per-IO information necessary
+ * for both SLI and efct.
+ * @ref: reference counter for hw io object
+ * @state: state of IO: free, busy, wait_free
+ * @list_entry used for busy, wait_free, free lists
+ * @wqe Work queue object, with link for pending
+ * @hw pointer back to hardware context
+ * @xfer_rdy transfer ready data
+ * @type IO type
+ * @xbusy Exchange is active in FW
+ * @abort_in_progress if TRUE, abort is in progress
+ * @status_saved if TRUE, latched status should be returned
+ * @wq_class WQ class if steering mode is Class
+ * @reqtag request tag for this HW IO
+ * @wq WQ assigned to the exchange
+ * @done Function called on IO completion
+ * @arg argument passed to IO done callback
+ * @abort_done Function called on abort completion
+ * @abort_arg argument passed to abort done callback
+ * @wq_steering WQ steering mode request
+ * @saved_status Saved status
+ * @saved_len Status length
+ * @saved_ext Saved extended status
+ * @eq EQ on which this HIO came up
+ * @sge_offset SGE data offset
+ * @def_sgl_count Count of SGEs in default SGL
+ * @abort_reqtag request tag for an abort of this HW IO
+ * @indicator Exchange indicator
+ * @def_sgl default SGL
+ * @sgl pointer to current active SGL
+ * @sgl_count count of SGEs in io->sgl
+ * @first_data_sge index of first data SGE
+ * @n_sge number of active SGEs
+ */
+struct efct_hw_io {
+ struct kref ref;
+ enum efct_hw_io_state state;
+ void (*release)(struct kref *arg);
+ struct list_head list_entry;
+ struct efct_hw_wqe wqe;
+
+ struct efct_hw *hw;
+ struct efc_dma xfer_rdy;
+ u16 type;
+ bool xbusy;
+ int abort_in_progress;
+ bool status_saved;
+ u8 wq_class;
+ u16 reqtag;
+
+ struct hw_wq *wq;
+ efct_hw_done_t done;
+ void *arg;
+ efct_hw_done_t abort_done;
+ void *abort_arg;
+
+ enum efct_hw_wq_steering wq_steering;
+
+ u32 saved_status;
+ u32 saved_len;
+ u32 saved_ext;
+
+ struct hw_eq *eq;
+ u32 sge_offset;
+ u32 def_sgl_count;
+ u32 abort_reqtag;
+ u32 indicator;
+ struct efc_dma def_sgl;
+ struct efc_dma *sgl;
+ u32 sgl_count;
+ u32 first_data_sge;
+ u32 n_sge;
+};
+
+enum efct_hw_port {
+ EFCT_HW_PORT_INIT,
+ EFCT_HW_PORT_SHUTDOWN,
+};
+
+/* Node group rpi reference */
+struct efct_hw_rpi_ref {
+ atomic_t rpi_count;
+ atomic_t rpi_attached;
+};
+
+enum efct_hw_link_stat {
+ EFCT_HW_LINK_STAT_LINK_FAILURE_COUNT,
+ EFCT_HW_LINK_STAT_LOSS_OF_SYNC_COUNT,
+ EFCT_HW_LINK_STAT_LOSS_OF_SIGNAL_COUNT,
+ EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT,
+ EFCT_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT,
+ EFCT_HW_LINK_STAT_CRC_COUNT,
+ EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_TIMEOUT_COUNT,
+ EFCT_HW_LINK_STAT_ELASTIC_BUFFER_OVERRUN_COUNT,
+ EFCT_HW_LINK_STAT_ARB_TIMEOUT_COUNT,
+ EFCT_HW_LINK_STAT_ADVERTISED_RCV_B2B_CREDIT,
+ EFCT_HW_LINK_STAT_CURR_RCV_B2B_CREDIT,
+ EFCT_HW_LINK_STAT_ADVERTISED_XMIT_B2B_CREDIT,
+ EFCT_HW_LINK_STAT_CURR_XMIT_B2B_CREDIT,
+ EFCT_HW_LINK_STAT_RCV_EOFA_COUNT,
+ EFCT_HW_LINK_STAT_RCV_EOFDTI_COUNT,
+ EFCT_HW_LINK_STAT_RCV_EOFNI_COUNT,
+ EFCT_HW_LINK_STAT_RCV_SOFF_COUNT,
+ EFCT_HW_LINK_STAT_RCV_DROPPED_NO_AER_COUNT,
+ EFCT_HW_LINK_STAT_RCV_DROPPED_NO_RPI_COUNT,
+ EFCT_HW_LINK_STAT_RCV_DROPPED_NO_XRI_COUNT,
+ EFCT_HW_LINK_STAT_MAX,
+};
+
+enum efct_hw_host_stat {
+ EFCT_HW_HOST_STAT_TX_KBYTE_COUNT,
+ EFCT_HW_HOST_STAT_RX_KBYTE_COUNT,
+ EFCT_HW_HOST_STAT_TX_FRAME_COUNT,
+ EFCT_HW_HOST_STAT_RX_FRAME_COUNT,
+ EFCT_HW_HOST_STAT_TX_SEQ_COUNT,
+ EFCT_HW_HOST_STAT_RX_SEQ_COUNT,
+ EFCT_HW_HOST_STAT_TOTAL_EXCH_ORIG,
+ EFCT_HW_HOST_STAT_TOTAL_EXCH_RESP,
+ EFCT_HW_HOSY_STAT_RX_P_BSY_COUNT,
+ EFCT_HW_HOST_STAT_RX_F_BSY_COUNT,
+ EFCT_HW_HOST_STAT_DROP_FRM_DUE_TO_NO_RQ_BUF_COUNT,
+ EFCT_HW_HOST_STAT_EMPTY_RQ_TIMEOUT_COUNT,
+ EFCT_HW_HOST_STAT_DROP_FRM_DUE_TO_NO_XRI_COUNT,
+ EFCT_HW_HOST_STAT_EMPTY_XRI_POOL_COUNT,
+ EFCT_HW_HOST_STAT_MAX,
+};
+
+enum efct_hw_state {
+ EFCT_HW_STATE_UNINITIALIZED,
+ EFCT_HW_STATE_QUEUES_ALLOCATED,
+ EFCT_HW_STATE_ACTIVE,
+ EFCT_HW_STATE_RESET_IN_PROGRESS,
+ EFCT_HW_STATE_TEARDOWN_IN_PROGRESS,
+};
+
+struct efct_hw_link_stat_counts {
+ u8 overflow;
+ u32 counter;
+};
+
+struct efct_hw_host_stat_counts {
+ u32 counter;
+};
+
+/* Structure used for the hash lookup of queue IDs */
+struct efct_queue_hash {
+ bool in_use;
+ u16 id;
+ u16 index;
+};
+
+/* WQ callback object */
+struct hw_wq_callback {
+ u16 instance_index; /* use for request tag */
+ void (*callback)(void *arg, u8 *cqe, int status);
+ void *arg;
+ struct list_head list_entry;
+};
+
+struct reqtag_pool {
+ spinlock_t lock; /* pool lock */
+ struct hw_wq_callback *tags[U16_MAX];
+ struct list_head freelist;
+};
+
+struct efct_hw_config {
+ u32 n_eq;
+ u32 n_cq;
+ u32 n_mq;
+ u32 n_rq;
+ u32 n_wq;
+ u32 n_io;
+ u32 n_sgl;
+ u32 speed;
+ u32 topology;
+ /* size of the buffers for first burst */
+ u32 rq_default_buffer_size;
+ u8 esoc;
+ /* MRQ RQ selection policy */
+ u8 rq_selection_policy;
+ /* RQ quanta if rq_selection_policy == 2 */
+ u8 rr_quanta;
+ u32 filter_def[SLI4_CMD_REG_FCFI_NUM_RQ_CFG];
+};
+
+struct efct_hw {
+ struct efct *os;
+ struct sli4 sli;
+ u16 ulp_start;
+ u16 ulp_max;
+ u32 dump_size;
+ enum efct_hw_state state;
+ bool hw_setup_called;
+ u8 sliport_healthcheck;
+ u16 fcf_indicator;
+
+ /* HW configuration */
+ struct efct_hw_config config;
+
+ /* calculated queue sizes for each type */
+ u32 num_qentries[SLI4_QTYPE_MAX];
+
+ /* Storage for SLI queue objects */
+ struct sli4_queue wq[EFCT_HW_MAX_NUM_WQ];
+ struct sli4_queue rq[EFCT_HW_MAX_NUM_RQ];
+ u16 hw_rq_lookup[EFCT_HW_MAX_NUM_RQ];
+ struct sli4_queue mq[EFCT_HW_MAX_NUM_MQ];
+ struct sli4_queue cq[EFCT_HW_MAX_NUM_CQ];
+ struct sli4_queue eq[EFCT_HW_MAX_NUM_EQ];
+
+ /* HW queue */
+ u32 eq_count;
+ u32 cq_count;
+ u32 mq_count;
+ u32 wq_count;
+ u32 rq_count;
+ u32 cmd_head_count;
+ struct list_head eq_list;
+
+ struct efct_queue_hash cq_hash[EFCT_HW_Q_HASH_SIZE];
+ struct efct_queue_hash rq_hash[EFCT_HW_Q_HASH_SIZE];
+ struct efct_queue_hash wq_hash[EFCT_HW_Q_HASH_SIZE];
+
+ /* Storage for HW queue objects */
+ struct hw_wq *hw_wq[EFCT_HW_MAX_NUM_WQ];
+ struct hw_rq *hw_rq[EFCT_HW_MAX_NUM_RQ];
+ struct hw_mq *hw_mq[EFCT_HW_MAX_NUM_MQ];
+ struct hw_cq *hw_cq[EFCT_HW_MAX_NUM_CQ];
+ struct hw_eq *hw_eq[EFCT_HW_MAX_NUM_EQ];
+ /* count of hw_rq[] entries */
+ u32 hw_rq_count;
+ /* count of multirq RQs */
+ u32 hw_mrq_count;
+
+ struct hw_wq **wq_cpu_array;
+
+ /* Sequence objects used in incoming frame processing */
+ struct efc_hw_sequence *seq_pool;
+
+ /* Maintain an ordered, linked list of outstanding HW commands. */
+ struct mutex bmbx_lock;
+ spinlock_t cmd_lock;
+ struct list_head cmd_head;
+ struct list_head cmd_pending;
+ mempool_t *cmd_ctx_pool;
+ mempool_t *mbox_rqst_pool;
+
+ struct sli4_link_event link;
+
+ /* pointer array of IO objects */
+ struct efct_hw_io **io;
+ /* array of WQE buffs mapped to IO objects */
+ u8 *wqe_buffs;
+
+ /* IO lock to synchronize list access */
+ spinlock_t io_lock;
+ /* List of IO objects in use */
+ struct list_head io_inuse;
+ /* List of IO objects waiting to be freed */
+ struct list_head io_wait_free;
+ /* List of IO objects available for allocation */
+ struct list_head io_free;
+
+ struct efc_dma loop_map;
+
+ struct efc_dma xfer_rdy;
+
+ struct efc_dma rnode_mem;
+
+ atomic_t io_alloc_failed_count;
+
+ /* stat: wq sumbit count */
+ u32 tcmd_wq_submit[EFCT_HW_MAX_NUM_WQ];
+ /* stat: wq complete count */
+ u32 tcmd_wq_complete[EFCT_HW_MAX_NUM_WQ];
+
+ atomic_t send_frame_seq_id;
+ struct reqtag_pool *wq_reqtag_pool;
+};
+
+enum efct_hw_io_count_type {
+ EFCT_HW_IO_INUSE_COUNT,
+ EFCT_HW_IO_FREE_COUNT,
+ EFCT_HW_IO_WAIT_FREE_COUNT,
+ EFCT_HW_IO_N_TOTAL_IO_COUNT,
+};
+
+/* HW queue data structures */
+struct hw_eq {
+ struct list_head list_entry;
+ enum sli4_qtype type;
+ u32 instance;
+ u32 entry_count;
+ u32 entry_size;
+ struct efct_hw *hw;
+ struct sli4_queue *queue;
+ struct list_head cq_list;
+ u32 use_count;
+};
+
+struct hw_cq {
+ struct list_head list_entry;
+ enum sli4_qtype type;
+ u32 instance;
+ u32 entry_count;
+ u32 entry_size;
+ struct hw_eq *eq;
+ struct sli4_queue *queue;
+ struct list_head q_list;
+ u32 use_count;
+};
+
+struct hw_q {
+ struct list_head list_entry;
+ enum sli4_qtype type;
+};
+
+struct hw_mq {
+ struct list_head list_entry;
+ enum sli4_qtype type;
+ u32 instance;
+
+ u32 entry_count;
+ u32 entry_size;
+ struct hw_cq *cq;
+ struct sli4_queue *queue;
+
+ u32 use_count;
+};
+
+struct hw_wq {
+ struct list_head list_entry;
+ enum sli4_qtype type;
+ u32 instance;
+ struct efct_hw *hw;
+
+ u32 entry_count;
+ u32 entry_size;
+ struct hw_cq *cq;
+ struct sli4_queue *queue;
+ u32 class;
+
+ /* WQ consumed */
+ u32 wqec_set_count;
+ u32 wqec_count;
+ u32 free_count;
+ u32 total_submit_count;
+ struct list_head pending_list;
+
+ /* HW IO allocated for use with Send Frame */
+ struct efct_hw_io *send_frame_io;
+
+ /* Stats */
+ u32 use_count;
+ u32 wq_pending_count;
+};
+
+struct hw_rq {
+ struct list_head list_entry;
+ enum sli4_qtype type;
+ u32 instance;
+
+ u32 entry_count;
+ u32 use_count;
+ u32 hdr_entry_size;
+ u32 first_burst_entry_size;
+ u32 data_entry_size;
+ bool is_mrq;
+ u32 base_mrq_id;
+
+ struct hw_cq *cq;
+
+ u8 filter_mask;
+ struct sli4_queue *hdr;
+ struct sli4_queue *first_burst;
+ struct sli4_queue *data;
+
+ struct efc_hw_rq_buffer *hdr_buf;
+ struct efc_hw_rq_buffer *fb_buf;
+ struct efc_hw_rq_buffer *payload_buf;
+ /* RQ tracker for this RQ */
+ struct efc_hw_sequence **rq_tracker;
+};
+
+struct efct_hw_send_frame_context {
+ struct efct_hw *hw;
+ struct hw_wq_callback *wqcb;
+ struct efct_hw_wqe wqe;
+ void (*callback)(int status, void *arg);
+ void *arg;
+
+ /* General purpose elements */
+ struct efc_hw_sequence *seq;
+ struct efc_dma payload;
+};
+
+struct efct_hw_grp_hdr {
+ u32 size;
+ __be32 magic_number;
+ u32 word2;
+ u8 rev_name[128];
+ u8 date[12];
+ u8 revision[32];
+};
+
+static inline int
+efct_hw_get_link_speed(struct efct_hw *hw) {
+ return hw->link.speed;
+}
+
+int
+efct_hw_setup(struct efct_hw *hw, void *os, struct pci_dev *pdev);
+int efct_hw_init(struct efct_hw *hw);
+int
+efct_hw_parse_filter(struct efct_hw *hw, void *value);
+int
+efct_hw_init_queues(struct efct_hw *hw);
+int
+efct_hw_map_wq_cpu(struct efct_hw *hw);
+uint64_t
+efct_get_wwnn(struct efct_hw *hw);
+uint64_t
+efct_get_wwpn(struct efct_hw *hw);
+
+int efct_hw_rx_allocate(struct efct_hw *hw);
+int efct_hw_rx_post(struct efct_hw *hw);
+void efct_hw_rx_free(struct efct_hw *hw);
+int
+efct_hw_command(struct efct_hw *hw, u8 *cmd, u32 opts, void *cb,
+ void *arg);
+int
+efct_issue_mbox_rqst(void *base, void *cmd, void *cb, void *arg);
+
+struct efct_hw_io *efct_hw_io_alloc(struct efct_hw *hw);
+int efct_hw_io_free(struct efct_hw *hw, struct efct_hw_io *io);
+u8 efct_hw_io_inuse(struct efct_hw *hw, struct efct_hw_io *io);
+int
+efct_hw_io_send(struct efct_hw *hw, enum efct_hw_io_type type,
+ struct efct_hw_io *io, union efct_hw_io_param_u *iparam,
+ void *cb, void *arg);
+int
+efct_hw_io_register_sgl(struct efct_hw *hw, struct efct_hw_io *io,
+ struct efc_dma *sgl,
+ u32 sgl_count);
+int
+efct_hw_io_init_sges(struct efct_hw *hw,
+ struct efct_hw_io *io, enum efct_hw_io_type type);
+
+int
+efct_hw_io_add_sge(struct efct_hw *hw, struct efct_hw_io *io,
+ uintptr_t addr, u32 length);
+int
+efct_hw_io_abort(struct efct_hw *hw, struct efct_hw_io *io_to_abort,
+ bool send_abts, void *cb, void *arg);
+u32
+efct_hw_io_get_count(struct efct_hw *hw,
+ enum efct_hw_io_count_type io_count_type);
+struct efct_hw_io
+*efct_hw_io_lookup(struct efct_hw *hw, u32 indicator);
+void efct_hw_io_abort_all(struct efct_hw *hw);
+void efct_hw_io_free_internal(struct kref *arg);
+
+/* HW WQ request tag API */
+struct reqtag_pool *efct_hw_reqtag_pool_alloc(struct efct_hw *hw);
+void efct_hw_reqtag_pool_free(struct efct_hw *hw);
+struct hw_wq_callback
+*efct_hw_reqtag_alloc(struct efct_hw *hw,
+ void (*callback)(void *arg, u8 *cqe,
+ int status), void *arg);
+void
+efct_hw_reqtag_free(struct efct_hw *hw, struct hw_wq_callback *wqcb);
+struct hw_wq_callback
+*efct_hw_reqtag_get_instance(struct efct_hw *hw, u32 instance_index);
+
+/* RQ completion handlers for RQ pair mode */
+int
+efct_hw_rqpair_process_rq(struct efct_hw *hw,
+ struct hw_cq *cq, u8 *cqe);
+int
+efct_hw_rqpair_sequence_free(struct efct_hw *hw, struct efc_hw_sequence *seq);
+static inline void
+efct_hw_sequence_copy(struct efc_hw_sequence *dst,
+ struct efc_hw_sequence *src)
+{
+ /* Copy src to dst, then zero out the linked list link */
+ *dst = *src;
+}
+
+int
+efct_efc_hw_sequence_free(struct efc *efc, struct efc_hw_sequence *seq);
+
+static inline int
+efct_hw_sequence_free(struct efct_hw *hw, struct efc_hw_sequence *seq)
+{
+ /* Only RQ pair mode is supported */
+ return efct_hw_rqpair_sequence_free(hw, seq);
+}
+
+int
+efct_hw_eq_process(struct efct_hw *hw, struct hw_eq *eq,
+ u32 max_isr_time_msec);
+void efct_hw_cq_process(struct efct_hw *hw, struct hw_cq *cq);
+void
+efct_hw_wq_process(struct efct_hw *hw, struct hw_cq *cq,
+ u8 *cqe, int status, u16 rid);
+void
+efct_hw_xabt_process(struct efct_hw *hw, struct hw_cq *cq,
+ u8 *cqe, u16 rid);
+int
+efct_hw_process(struct efct_hw *hw, u32 vector, u32 max_isr_time_msec);
+int
+efct_hw_queue_hash_find(struct efct_queue_hash *hash, u16 id);
+int efct_hw_wq_write(struct hw_wq *wq, struct efct_hw_wqe *wqe);
+int
+efct_hw_send_frame(struct efct_hw *hw, struct fc_frame_header *hdr,
+ u8 sof, u8 eof, struct efc_dma *payload,
+ struct efct_hw_send_frame_context *ctx,
+ void (*callback)(void *arg, u8 *cqe, int status),
+ void *arg);
+int
+efct_els_hw_srrs_send(struct efc *efc, struct efc_disc_io *io);
+int
+efct_efc_bls_send(struct efc *efc, u32 type, struct sli_bls_params *bls);
+int
+efct_hw_bls_send(struct efct *efct, u32 type, struct sli_bls_params *bls_params,
+ void *cb, void *arg);
+
+/* Function for retrieving link statistics */
+int
+efct_hw_get_link_stats(struct efct_hw *hw,
+ u8 req_ext_counters,
+ u8 clear_overflow_flags,
+ u8 clear_all_counters,
+ void (*efct_hw_link_stat_cb_t)(int status,
+ u32 num_counters,
+ struct efct_hw_link_stat_counts *counters, void *arg),
+ void *arg);
+/* Function for retrieving host statistics */
+int
+efct_hw_get_host_stats(struct efct_hw *hw,
+ u8 cc,
+ void (*efct_hw_host_stat_cb_t)(int status,
+ u32 num_counters,
+ struct efct_hw_host_stat_counts *counters, void *arg),
+ void *arg);
+int
+efct_hw_firmware_write(struct efct_hw *hw, struct efc_dma *dma,
+ u32 size, u32 offset, int last,
+ void (*cb)(int status, u32 bytes_written,
+ u32 change_status, void *arg),
+ void *arg);
+typedef void (*efct_hw_async_cb_t)(struct efct_hw *hw, int status,
+ u8 *mqe, void *arg);
+int
+efct_hw_async_call(struct efct_hw *hw, efct_hw_async_cb_t callback, void *arg);
+
+struct hw_eq *efct_hw_new_eq(struct efct_hw *hw, u32 entry_count);
+struct hw_cq *efct_hw_new_cq(struct hw_eq *eq, u32 entry_count);
+u32
+efct_hw_new_cq_set(struct hw_eq *eqs[], struct hw_cq *cqs[],
+ u32 num_cqs, u32 entry_count);
+struct hw_mq *efct_hw_new_mq(struct hw_cq *cq, u32 entry_count);
+struct hw_wq
+*efct_hw_new_wq(struct hw_cq *cq, u32 entry_count);
+u32
+efct_hw_new_rq_set(struct hw_cq *cqs[], struct hw_rq *rqs[],
+ u32 num_rq_pairs, u32 entry_count);
+void efct_hw_del_eq(struct hw_eq *eq);
+void efct_hw_del_cq(struct hw_cq *cq);
+void efct_hw_del_mq(struct hw_mq *mq);
+void efct_hw_del_wq(struct hw_wq *wq);
+void efct_hw_del_rq(struct hw_rq *rq);
+void efct_hw_queue_teardown(struct efct_hw *hw);
+void efct_hw_teardown(struct efct_hw *hw);
+int
+efct_hw_reset(struct efct_hw *hw, enum efct_hw_reset reset);
+
+int
+efct_hw_port_control(struct efct_hw *hw, enum efct_hw_port ctrl,
+ uintptr_t value,
+ void (*cb)(int status, uintptr_t value, void *arg),
+ void *arg);
+
+#endif /* __EFCT_H__ */
diff --git a/drivers/scsi/elx/efct/efct_hw_queues.c b/drivers/scsi/elx/efct/efct_hw_queues.c
new file mode 100644
index 000000000000..3a1d1a5864a3
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_hw_queues.c
@@ -0,0 +1,677 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#include "efct_driver.h"
+#include "efct_hw.h"
+#include "efct_unsol.h"
+
+int
+efct_hw_init_queues(struct efct_hw *hw)
+{
+ struct hw_eq *eq = NULL;
+ struct hw_cq *cq = NULL;
+ struct hw_wq *wq = NULL;
+ struct hw_mq *mq = NULL;
+
+ struct hw_eq *eqs[EFCT_HW_MAX_NUM_EQ];
+ struct hw_cq *cqs[EFCT_HW_MAX_NUM_EQ];
+ struct hw_rq *rqs[EFCT_HW_MAX_NUM_EQ];
+ u32 i = 0, j;
+
+ hw->eq_count = 0;
+ hw->cq_count = 0;
+ hw->mq_count = 0;
+ hw->wq_count = 0;
+ hw->rq_count = 0;
+ hw->hw_rq_count = 0;
+ INIT_LIST_HEAD(&hw->eq_list);
+
+ for (i = 0; i < hw->config.n_eq; i++) {
+ /* Create EQ */
+ eq = efct_hw_new_eq(hw, EFCT_HW_EQ_DEPTH);
+ if (!eq) {
+ efct_hw_queue_teardown(hw);
+ return -ENOMEM;
+ }
+
+ eqs[i] = eq;
+
+ /* Create one MQ */
+ if (!i) {
+ cq = efct_hw_new_cq(eq,
+ hw->num_qentries[SLI4_QTYPE_CQ]);
+ if (!cq) {
+ efct_hw_queue_teardown(hw);
+ return -ENOMEM;
+ }
+
+ mq = efct_hw_new_mq(cq, EFCT_HW_MQ_DEPTH);
+ if (!mq) {
+ efct_hw_queue_teardown(hw);
+ return -ENOMEM;
+ }
+ }
+
+ /* Create WQ */
+ cq = efct_hw_new_cq(eq, hw->num_qentries[SLI4_QTYPE_CQ]);
+ if (!cq) {
+ efct_hw_queue_teardown(hw);
+ return -ENOMEM;
+ }
+
+ wq = efct_hw_new_wq(cq, hw->num_qentries[SLI4_QTYPE_WQ]);
+ if (!wq) {
+ efct_hw_queue_teardown(hw);
+ return -ENOMEM;
+ }
+ }
+
+ /* Create CQ set */
+ if (efct_hw_new_cq_set(eqs, cqs, i, hw->num_qentries[SLI4_QTYPE_CQ])) {
+ efct_hw_queue_teardown(hw);
+ return -EIO;
+ }
+
+ /* Create RQ set */
+ if (efct_hw_new_rq_set(cqs, rqs, i, EFCT_HW_RQ_ENTRIES_DEF)) {
+ efct_hw_queue_teardown(hw);
+ return -EIO;
+ }
+
+ for (j = 0; j < i ; j++) {
+ rqs[j]->filter_mask = 0;
+ rqs[j]->is_mrq = true;
+ rqs[j]->base_mrq_id = rqs[0]->hdr->id;
+ }
+
+ hw->hw_mrq_count = i;
+
+ return 0;
+}
+
+int
+efct_hw_map_wq_cpu(struct efct_hw *hw)
+{
+ struct efct *efct = hw->os;
+ u32 cpu = 0, i;
+
+ /* Init cpu_map array */
+ hw->wq_cpu_array = kcalloc(num_possible_cpus(), sizeof(void *),
+ GFP_KERNEL);
+ if (!hw->wq_cpu_array)
+ return -ENOMEM;
+
+ for (i = 0; i < hw->config.n_eq; i++) {
+ const struct cpumask *maskp;
+
+ /* Get a CPU mask for all CPUs affinitized to this vector */
+ maskp = pci_irq_get_affinity(efct->pci, i);
+ if (!maskp) {
+ efc_log_debug(efct, "maskp null for vector:%d\n", i);
+ continue;
+ }
+
+ /* Loop through all CPUs associated with vector idx */
+ for_each_cpu_and(cpu, maskp, cpu_present_mask) {
+ efc_log_debug(efct, "CPU:%d irq vector:%d\n", cpu, i);
+ hw->wq_cpu_array[cpu] = hw->hw_wq[i];
+ }
+ }
+
+ return 0;
+}
+
+struct hw_eq *
+efct_hw_new_eq(struct efct_hw *hw, u32 entry_count)
+{
+ struct hw_eq *eq = kzalloc(sizeof(*eq), GFP_KERNEL);
+
+ if (!eq)
+ return NULL;
+
+ eq->type = SLI4_QTYPE_EQ;
+ eq->hw = hw;
+ eq->entry_count = entry_count;
+ eq->instance = hw->eq_count++;
+ eq->queue = &hw->eq[eq->instance];
+ INIT_LIST_HEAD(&eq->cq_list);
+
+ if (sli_queue_alloc(&hw->sli, SLI4_QTYPE_EQ, eq->queue, entry_count,
+ NULL)) {
+ efc_log_err(hw->os, "EQ[%d] alloc failure\n", eq->instance);
+ kfree(eq);
+ return NULL;
+ }
+
+ sli_eq_modify_delay(&hw->sli, eq->queue, 1, 0, 8);
+ hw->hw_eq[eq->instance] = eq;
+ INIT_LIST_HEAD(&eq->list_entry);
+ list_add_tail(&eq->list_entry, &hw->eq_list);
+ efc_log_debug(hw->os, "create eq[%2d] id %3d len %4d\n", eq->instance,
+ eq->queue->id, eq->entry_count);
+ return eq;
+}
+
+struct hw_cq *
+efct_hw_new_cq(struct hw_eq *eq, u32 entry_count)
+{
+ struct efct_hw *hw = eq->hw;
+ struct hw_cq *cq = kzalloc(sizeof(*cq), GFP_KERNEL);
+
+ if (!cq)
+ return NULL;
+
+ cq->eq = eq;
+ cq->type = SLI4_QTYPE_CQ;
+ cq->instance = eq->hw->cq_count++;
+ cq->entry_count = entry_count;
+ cq->queue = &hw->cq[cq->instance];
+
+ INIT_LIST_HEAD(&cq->q_list);
+
+ if (sli_queue_alloc(&hw->sli, SLI4_QTYPE_CQ, cq->queue,
+ cq->entry_count, eq->queue)) {
+ efc_log_err(hw->os, "CQ[%d] allocation failure len=%d\n",
+ eq->instance, eq->entry_count);
+ kfree(cq);
+ return NULL;
+ }
+
+ hw->hw_cq[cq->instance] = cq;
+ INIT_LIST_HEAD(&cq->list_entry);
+ list_add_tail(&cq->list_entry, &eq->cq_list);
+ efc_log_debug(hw->os, "create cq[%2d] id %3d len %4d\n", cq->instance,
+ cq->queue->id, cq->entry_count);
+ return cq;
+}
+
+u32
+efct_hw_new_cq_set(struct hw_eq *eqs[], struct hw_cq *cqs[],
+ u32 num_cqs, u32 entry_count)
+{
+ u32 i;
+ struct efct_hw *hw = eqs[0]->hw;
+ struct sli4 *sli4 = &hw->sli;
+ struct hw_cq *cq = NULL;
+ struct sli4_queue *qs[SLI4_MAX_CQ_SET_COUNT];
+ struct sli4_queue *assefct[SLI4_MAX_CQ_SET_COUNT];
+
+ /* Initialise CQS pointers to NULL */
+ for (i = 0; i < num_cqs; i++)
+ cqs[i] = NULL;
+
+ for (i = 0; i < num_cqs; i++) {
+ cq = kzalloc(sizeof(*cq), GFP_KERNEL);
+ if (!cq)
+ goto error;
+
+ cqs[i] = cq;
+ cq->eq = eqs[i];
+ cq->type = SLI4_QTYPE_CQ;
+ cq->instance = hw->cq_count++;
+ cq->entry_count = entry_count;
+ cq->queue = &hw->cq[cq->instance];
+ qs[i] = cq->queue;
+ assefct[i] = eqs[i]->queue;
+ INIT_LIST_HEAD(&cq->q_list);
+ }
+
+ if (sli_cq_alloc_set(sli4, qs, num_cqs, entry_count, assefct)) {
+ efc_log_err(hw->os, "Failed to create CQ Set.\n");
+ goto error;
+ }
+
+ for (i = 0; i < num_cqs; i++) {
+ hw->hw_cq[cqs[i]->instance] = cqs[i];
+ INIT_LIST_HEAD(&cqs[i]->list_entry);
+ list_add_tail(&cqs[i]->list_entry, &cqs[i]->eq->cq_list);
+ }
+
+ return 0;
+
+error:
+ for (i = 0; i < num_cqs; i++) {
+ kfree(cqs[i]);
+ cqs[i] = NULL;
+ }
+ return -EIO;
+}
+
+struct hw_mq *
+efct_hw_new_mq(struct hw_cq *cq, u32 entry_count)
+{
+ struct efct_hw *hw = cq->eq->hw;
+ struct hw_mq *mq = kzalloc(sizeof(*mq), GFP_KERNEL);
+
+ if (!mq)
+ return NULL;
+
+ mq->cq = cq;
+ mq->type = SLI4_QTYPE_MQ;
+ mq->instance = cq->eq->hw->mq_count++;
+ mq->entry_count = entry_count;
+ mq->entry_size = EFCT_HW_MQ_DEPTH;
+ mq->queue = &hw->mq[mq->instance];
+
+ if (sli_queue_alloc(&hw->sli, SLI4_QTYPE_MQ, mq->queue, mq->entry_size,
+ cq->queue)) {
+ efc_log_err(hw->os, "MQ allocation failure\n");
+ kfree(mq);
+ return NULL;
+ }
+
+ hw->hw_mq[mq->instance] = mq;
+ INIT_LIST_HEAD(&mq->list_entry);
+ list_add_tail(&mq->list_entry, &cq->q_list);
+ efc_log_debug(hw->os, "create mq[%2d] id %3d len %4d\n", mq->instance,
+ mq->queue->id, mq->entry_count);
+ return mq;
+}
+
+struct hw_wq *
+efct_hw_new_wq(struct hw_cq *cq, u32 entry_count)
+{
+ struct efct_hw *hw = cq->eq->hw;
+ struct hw_wq *wq = kzalloc(sizeof(*wq), GFP_KERNEL);
+
+ if (!wq)
+ return NULL;
+
+ wq->hw = cq->eq->hw;
+ wq->cq = cq;
+ wq->type = SLI4_QTYPE_WQ;
+ wq->instance = cq->eq->hw->wq_count++;
+ wq->entry_count = entry_count;
+ wq->queue = &hw->wq[wq->instance];
+ wq->wqec_set_count = EFCT_HW_WQEC_SET_COUNT;
+ wq->wqec_count = wq->wqec_set_count;
+ wq->free_count = wq->entry_count - 1;
+ INIT_LIST_HEAD(&wq->pending_list);
+
+ if (sli_queue_alloc(&hw->sli, SLI4_QTYPE_WQ, wq->queue,
+ wq->entry_count, cq->queue)) {
+ efc_log_err(hw->os, "WQ allocation failure\n");
+ kfree(wq);
+ return NULL;
+ }
+
+ hw->hw_wq[wq->instance] = wq;
+ INIT_LIST_HEAD(&wq->list_entry);
+ list_add_tail(&wq->list_entry, &cq->q_list);
+ efc_log_debug(hw->os, "create wq[%2d] id %3d len %4d cls %d\n",
+ wq->instance, wq->queue->id, wq->entry_count, wq->class);
+ return wq;
+}
+
+u32
+efct_hw_new_rq_set(struct hw_cq *cqs[], struct hw_rq *rqs[],
+ u32 num_rq_pairs, u32 entry_count)
+{
+ struct efct_hw *hw = cqs[0]->eq->hw;
+ struct hw_rq *rq = NULL;
+ struct sli4_queue *qs[SLI4_MAX_RQ_SET_COUNT * 2] = { NULL };
+ u32 i, q_count, size;
+
+ /* Initialise RQS pointers */
+ for (i = 0; i < num_rq_pairs; i++)
+ rqs[i] = NULL;
+
+ /*
+ * Allocate an RQ object SET, where each element in set
+ * encapsulates 2 SLI queues (for rq pair)
+ */
+ for (i = 0, q_count = 0; i < num_rq_pairs; i++, q_count += 2) {
+ rq = kzalloc(sizeof(*rq), GFP_KERNEL);
+ if (!rq)
+ goto error;
+
+ rqs[i] = rq;
+ rq->instance = hw->hw_rq_count++;
+ rq->cq = cqs[i];
+ rq->type = SLI4_QTYPE_RQ;
+ rq->entry_count = entry_count;
+
+ /* Header RQ */
+ rq->hdr = &hw->rq[hw->rq_count];
+ rq->hdr_entry_size = EFCT_HW_RQ_HEADER_SIZE;
+ hw->hw_rq_lookup[hw->rq_count] = rq->instance;
+ hw->rq_count++;
+ qs[q_count] = rq->hdr;
+
+ /* Data RQ */
+ rq->data = &hw->rq[hw->rq_count];
+ rq->data_entry_size = hw->config.rq_default_buffer_size;
+ hw->hw_rq_lookup[hw->rq_count] = rq->instance;
+ hw->rq_count++;
+ qs[q_count + 1] = rq->data;
+
+ rq->rq_tracker = NULL;
+ }
+
+ if (sli_fc_rq_set_alloc(&hw->sli, num_rq_pairs, qs,
+ cqs[0]->queue->id,
+ rqs[0]->entry_count,
+ rqs[0]->hdr_entry_size,
+ rqs[0]->data_entry_size)) {
+ efc_log_err(hw->os, "RQ Set alloc failure for base CQ=%d\n",
+ cqs[0]->queue->id);
+ goto error;
+ }
+
+ for (i = 0; i < num_rq_pairs; i++) {
+ hw->hw_rq[rqs[i]->instance] = rqs[i];
+ INIT_LIST_HEAD(&rqs[i]->list_entry);
+ list_add_tail(&rqs[i]->list_entry, &cqs[i]->q_list);
+ size = sizeof(struct efc_hw_sequence *) * rqs[i]->entry_count;
+ rqs[i]->rq_tracker = kzalloc(size, GFP_KERNEL);
+ if (!rqs[i]->rq_tracker)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ for (i = 0; i < num_rq_pairs; i++) {
+ if (rqs[i]) {
+ kfree(rqs[i]->rq_tracker);
+ kfree(rqs[i]);
+ }
+ }
+
+ return -EIO;
+}
+
+void
+efct_hw_del_eq(struct hw_eq *eq)
+{
+ struct hw_cq *cq;
+ struct hw_cq *cq_next;
+
+ if (!eq)
+ return;
+
+ list_for_each_entry_safe(cq, cq_next, &eq->cq_list, list_entry)
+ efct_hw_del_cq(cq);
+ list_del(&eq->list_entry);
+ eq->hw->hw_eq[eq->instance] = NULL;
+ kfree(eq);
+}
+
+void
+efct_hw_del_cq(struct hw_cq *cq)
+{
+ struct hw_q *q;
+ struct hw_q *q_next;
+
+ if (!cq)
+ return;
+
+ list_for_each_entry_safe(q, q_next, &cq->q_list, list_entry) {
+ switch (q->type) {
+ case SLI4_QTYPE_MQ:
+ efct_hw_del_mq((struct hw_mq *)q);
+ break;
+ case SLI4_QTYPE_WQ:
+ efct_hw_del_wq((struct hw_wq *)q);
+ break;
+ case SLI4_QTYPE_RQ:
+ efct_hw_del_rq((struct hw_rq *)q);
+ break;
+ default:
+ break;
+ }
+ }
+ list_del(&cq->list_entry);
+ cq->eq->hw->hw_cq[cq->instance] = NULL;
+ kfree(cq);
+}
+
+void
+efct_hw_del_mq(struct hw_mq *mq)
+{
+ if (!mq)
+ return;
+
+ list_del(&mq->list_entry);
+ mq->cq->eq->hw->hw_mq[mq->instance] = NULL;
+ kfree(mq);
+}
+
+void
+efct_hw_del_wq(struct hw_wq *wq)
+{
+ if (!wq)
+ return;
+
+ list_del(&wq->list_entry);
+ wq->cq->eq->hw->hw_wq[wq->instance] = NULL;
+ kfree(wq);
+}
+
+void
+efct_hw_del_rq(struct hw_rq *rq)
+{
+ struct efct_hw *hw = NULL;
+
+ if (!rq)
+ return;
+ /* Free RQ tracker */
+ kfree(rq->rq_tracker);
+ rq->rq_tracker = NULL;
+ list_del(&rq->list_entry);
+ hw = rq->cq->eq->hw;
+ hw->hw_rq[rq->instance] = NULL;
+ kfree(rq);
+}
+
+void
+efct_hw_queue_teardown(struct efct_hw *hw)
+{
+ struct hw_eq *eq;
+ struct hw_eq *eq_next;
+
+ if (!hw->eq_list.next)
+ return;
+
+ list_for_each_entry_safe(eq, eq_next, &hw->eq_list, list_entry)
+ efct_hw_del_eq(eq);
+}
+
+static inline int
+efct_hw_rqpair_find(struct efct_hw *hw, u16 rq_id)
+{
+ return efct_hw_queue_hash_find(hw->rq_hash, rq_id);
+}
+
+static struct efc_hw_sequence *
+efct_hw_rqpair_get(struct efct_hw *hw, u16 rqindex, u16 bufindex)
+{
+ struct sli4_queue *rq_hdr = &hw->rq[rqindex];
+ struct efc_hw_sequence *seq = NULL;
+ struct hw_rq *rq = hw->hw_rq[hw->hw_rq_lookup[rqindex]];
+ unsigned long flags = 0;
+
+ if (bufindex >= rq_hdr->length) {
+ efc_log_err(hw->os,
+ "RQidx %d bufidx %d exceed ring len %d for id %d\n",
+ rqindex, bufindex, rq_hdr->length, rq_hdr->id);
+ return NULL;
+ }
+
+ /* rq_hdr lock also covers rqindex+1 queue */
+ spin_lock_irqsave(&rq_hdr->lock, flags);
+
+ seq = rq->rq_tracker[bufindex];
+ rq->rq_tracker[bufindex] = NULL;
+
+ if (!seq) {
+ efc_log_err(hw->os,
+ "RQbuf NULL, rqidx %d, bufidx %d, cur q idx = %d\n",
+ rqindex, bufindex, rq_hdr->index);
+ }
+
+ spin_unlock_irqrestore(&rq_hdr->lock, flags);
+ return seq;
+}
+
+int
+efct_hw_rqpair_process_rq(struct efct_hw *hw, struct hw_cq *cq,
+ u8 *cqe)
+{
+ u16 rq_id;
+ u32 index;
+ int rqindex;
+ int rq_status;
+ u32 h_len;
+ u32 p_len;
+ struct efc_hw_sequence *seq;
+ struct hw_rq *rq;
+
+ rq_status = sli_fc_rqe_rqid_and_index(&hw->sli, cqe,
+ &rq_id, &index);
+ if (rq_status != 0) {
+ switch (rq_status) {
+ case SLI4_FC_ASYNC_RQ_BUF_LEN_EXCEEDED:
+ case SLI4_FC_ASYNC_RQ_DMA_FAILURE:
+ /* just get RQ buffer then return to chip */
+ rqindex = efct_hw_rqpair_find(hw, rq_id);
+ if (rqindex < 0) {
+ efc_log_debug(hw->os,
+ "status=%#x: lookup fail id=%#x\n",
+ rq_status, rq_id);
+ break;
+ }
+
+ /* get RQ buffer */
+ seq = efct_hw_rqpair_get(hw, rqindex, index);
+
+ /* return to chip */
+ if (efct_hw_rqpair_sequence_free(hw, seq)) {
+ efc_log_debug(hw->os,
+ "status=%#x,fail rtrn buf to RQ\n",
+ rq_status);
+ break;
+ }
+ break;
+ case SLI4_FC_ASYNC_RQ_INSUFF_BUF_NEEDED:
+ case SLI4_FC_ASYNC_RQ_INSUFF_BUF_FRM_DISC:
+ /*
+ * since RQ buffers were not consumed, cannot return
+ * them to chip
+ */
+ efc_log_debug(hw->os, "Warning: RCQE status=%#x,\n",
+ rq_status);
+ fallthrough;
+ default:
+ break;
+ }
+ return -EIO;
+ }
+
+ rqindex = efct_hw_rqpair_find(hw, rq_id);
+ if (rqindex < 0) {
+ efc_log_debug(hw->os, "Error: rq_id lookup failed for id=%#x\n",
+ rq_id);
+ return -EIO;
+ }
+
+ rq = hw->hw_rq[hw->hw_rq_lookup[rqindex]];
+ rq->use_count++;
+
+ seq = efct_hw_rqpair_get(hw, rqindex, index);
+ if (WARN_ON(!seq))
+ return -EIO;
+
+ seq->hw = hw;
+
+ sli_fc_rqe_length(&hw->sli, cqe, &h_len, &p_len);
+ seq->header->dma.len = h_len;
+ seq->payload->dma.len = p_len;
+ seq->fcfi = sli_fc_rqe_fcfi(&hw->sli, cqe);
+ seq->hw_priv = cq->eq;
+
+ efct_unsolicited_cb(hw->os, seq);
+
+ return 0;
+}
+
+static int
+efct_hw_rqpair_put(struct efct_hw *hw, struct efc_hw_sequence *seq)
+{
+ struct sli4_queue *rq_hdr = &hw->rq[seq->header->rqindex];
+ struct sli4_queue *rq_payload = &hw->rq[seq->payload->rqindex];
+ u32 hw_rq_index = hw->hw_rq_lookup[seq->header->rqindex];
+ struct hw_rq *rq = hw->hw_rq[hw_rq_index];
+ u32 phys_hdr[2];
+ u32 phys_payload[2];
+ int qindex_hdr;
+ int qindex_payload;
+ unsigned long flags = 0;
+
+ /* Update the RQ verification lookup tables */
+ phys_hdr[0] = upper_32_bits(seq->header->dma.phys);
+ phys_hdr[1] = lower_32_bits(seq->header->dma.phys);
+ phys_payload[0] = upper_32_bits(seq->payload->dma.phys);
+ phys_payload[1] = lower_32_bits(seq->payload->dma.phys);
+
+ /* rq_hdr lock also covers payload / header->rqindex+1 queue */
+ spin_lock_irqsave(&rq_hdr->lock, flags);
+
+ /*
+ * Note: The header must be posted last for buffer pair mode because
+ * posting on the header queue posts the payload queue as well.
+ * We do not ring the payload queue independently in RQ pair mode.
+ */
+ qindex_payload = sli_rq_write(&hw->sli, rq_payload,
+ (void *)phys_payload);
+ qindex_hdr = sli_rq_write(&hw->sli, rq_hdr, (void *)phys_hdr);
+ if (qindex_hdr < 0 ||
+ qindex_payload < 0) {
+ efc_log_err(hw->os, "RQ_ID=%#x write failed\n", rq_hdr->id);
+ spin_unlock_irqrestore(&rq_hdr->lock, flags);
+ return -EIO;
+ }
+
+ /* ensure the indexes are the same */
+ WARN_ON(qindex_hdr != qindex_payload);
+
+ /* Update the lookup table */
+ if (!rq->rq_tracker[qindex_hdr]) {
+ rq->rq_tracker[qindex_hdr] = seq;
+ } else {
+ efc_log_debug(hw->os,
+ "expected rq_tracker[%d][%d] buffer to be NULL\n",
+ hw_rq_index, qindex_hdr);
+ }
+
+ spin_unlock_irqrestore(&rq_hdr->lock, flags);
+ return 0;
+}
+
+int
+efct_hw_rqpair_sequence_free(struct efct_hw *hw, struct efc_hw_sequence *seq)
+{
+ int rc = 0;
+
+ /*
+ * Post the data buffer first. Because in RQ pair mode, ringing the
+ * doorbell of the header ring will post the data buffer as well.
+ */
+ if (efct_hw_rqpair_put(hw, seq)) {
+ efc_log_err(hw->os, "error writing buffers\n");
+ return -EIO;
+ }
+
+ return rc;
+}
+
+int
+efct_efc_hw_sequence_free(struct efc *efc, struct efc_hw_sequence *seq)
+{
+ struct efct *efct = efc->base;
+
+ return efct_hw_rqpair_sequence_free(&efct->hw, seq);
+}
diff --git a/drivers/scsi/elx/efct/efct_io.c b/drivers/scsi/elx/efct/efct_io.c
new file mode 100644
index 000000000000..71e21655916a
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_io.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#include "efct_driver.h"
+#include "efct_hw.h"
+#include "efct_io.h"
+
+struct efct_io_pool {
+ struct efct *efct;
+ spinlock_t lock; /* IO pool lock */
+ u32 io_num_ios; /* Total IOs allocated */
+ struct efct_io *ios[EFCT_NUM_SCSI_IOS];
+ struct list_head freelist;
+
+};
+
+struct efct_io_pool *
+efct_io_pool_create(struct efct *efct, u32 num_sgl)
+{
+ u32 i = 0;
+ struct efct_io_pool *io_pool;
+ struct efct_io *io;
+
+ /* Allocate the IO pool */
+ io_pool = kzalloc(sizeof(*io_pool), GFP_KERNEL);
+ if (!io_pool)
+ return NULL;
+
+ io_pool->efct = efct;
+ INIT_LIST_HEAD(&io_pool->freelist);
+ /* initialize IO pool lock */
+ spin_lock_init(&io_pool->lock);
+
+ for (i = 0; i < EFCT_NUM_SCSI_IOS; i++) {
+ io = kzalloc(sizeof(*io), GFP_KERNEL);
+ if (!io)
+ break;
+
+ io_pool->io_num_ios++;
+ io_pool->ios[i] = io;
+ io->tag = i;
+ io->instance_index = i;
+
+ /* Allocate a response buffer */
+ io->rspbuf.size = SCSI_RSP_BUF_LENGTH;
+ io->rspbuf.virt = dma_alloc_coherent(&efct->pci->dev,
+ io->rspbuf.size,
+ &io->rspbuf.phys, GFP_DMA);
+ if (!io->rspbuf.virt) {
+ efc_log_err(efct, "dma_alloc rspbuf failed\n");
+ efct_io_pool_free(io_pool);
+ return NULL;
+ }
+
+ /* Allocate SGL */
+ io->sgl = kzalloc(sizeof(*io->sgl) * num_sgl, GFP_KERNEL);
+ if (!io->sgl) {
+ efct_io_pool_free(io_pool);
+ return NULL;
+ }
+
+ memset(io->sgl, 0, sizeof(*io->sgl) * num_sgl);
+ io->sgl_allocated = num_sgl;
+ io->sgl_count = 0;
+
+ INIT_LIST_HEAD(&io->list_entry);
+ list_add_tail(&io->list_entry, &io_pool->freelist);
+ }
+
+ return io_pool;
+}
+
+int
+efct_io_pool_free(struct efct_io_pool *io_pool)
+{
+ struct efct *efct;
+ u32 i;
+ struct efct_io *io;
+
+ if (io_pool) {
+ efct = io_pool->efct;
+
+ for (i = 0; i < io_pool->io_num_ios; i++) {
+ io = io_pool->ios[i];
+ if (!io)
+ continue;
+
+ kfree(io->sgl);
+ dma_free_coherent(&efct->pci->dev,
+ io->rspbuf.size, io->rspbuf.virt,
+ io->rspbuf.phys);
+ memset(&io->rspbuf, 0, sizeof(struct efc_dma));
+ }
+
+ kfree(io_pool);
+ efct->xport->io_pool = NULL;
+ }
+
+ return 0;
+}
+
+struct efct_io *
+efct_io_pool_io_alloc(struct efct_io_pool *io_pool)
+{
+ struct efct_io *io = NULL;
+ struct efct *efct;
+ unsigned long flags = 0;
+
+ efct = io_pool->efct;
+
+ spin_lock_irqsave(&io_pool->lock, flags);
+
+ if (!list_empty(&io_pool->freelist)) {
+ io = list_first_entry(&io_pool->freelist, struct efct_io,
+ list_entry);
+ list_del_init(&io->list_entry);
+ }
+
+ spin_unlock_irqrestore(&io_pool->lock, flags);
+
+ if (!io)
+ return NULL;
+
+ io->io_type = EFCT_IO_TYPE_MAX;
+ io->hio_type = EFCT_HW_IO_MAX;
+ io->hio = NULL;
+ io->transferred = 0;
+ io->efct = efct;
+ io->timeout = 0;
+ io->sgl_count = 0;
+ io->tgt_task_tag = 0;
+ io->init_task_tag = 0;
+ io->hw_tag = 0;
+ io->display_name = "pending";
+ io->seq_init = 0;
+ io->io_free = 0;
+ io->release = NULL;
+ atomic_add_return(1, &efct->xport->io_active_count);
+ atomic_add_return(1, &efct->xport->io_total_alloc);
+ return io;
+}
+
+/* Free an object used to track an IO */
+void
+efct_io_pool_io_free(struct efct_io_pool *io_pool, struct efct_io *io)
+{
+ struct efct *efct;
+ struct efct_hw_io *hio = NULL;
+ unsigned long flags = 0;
+
+ efct = io_pool->efct;
+
+ spin_lock_irqsave(&io_pool->lock, flags);
+ hio = io->hio;
+ io->hio = NULL;
+ io->io_free = 1;
+ INIT_LIST_HEAD(&io->list_entry);
+ list_add(&io->list_entry, &io_pool->freelist);
+ spin_unlock_irqrestore(&io_pool->lock, flags);
+
+ if (hio)
+ efct_hw_io_free(&efct->hw, hio);
+
+ atomic_sub_return(1, &efct->xport->io_active_count);
+ atomic_add_return(1, &efct->xport->io_total_free);
+}
+
+/* Find an I/O given it's node and ox_id */
+struct efct_io *
+efct_io_find_tgt_io(struct efct *efct, struct efct_node *node,
+ u16 ox_id, u16 rx_id)
+{
+ struct efct_io *io = NULL;
+ unsigned long flags = 0;
+ u8 found = false;
+
+ spin_lock_irqsave(&node->active_ios_lock, flags);
+ list_for_each_entry(io, &node->active_ios, list_entry) {
+ if ((io->cmd_tgt && io->init_task_tag == ox_id) &&
+ (rx_id == 0xffff || io->tgt_task_tag == rx_id)) {
+ if (kref_get_unless_zero(&io->ref))
+ found = true;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&node->active_ios_lock, flags);
+ return found ? io : NULL;
+}
diff --git a/drivers/scsi/elx/efct/efct_io.h b/drivers/scsi/elx/efct/efct_io.h
new file mode 100644
index 000000000000..bb0f51811a7c
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_io.h
@@ -0,0 +1,174 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#if !defined(__EFCT_IO_H__)
+#define __EFCT_IO_H__
+
+#include "efct_lio.h"
+
+#define EFCT_LOG_ENABLE_IO_ERRORS(efct) \
+ (((efct) != NULL) ? (((efct)->logmask & (1U << 6)) != 0) : 0)
+
+#define io_error_log(io, fmt, ...) \
+ do { \
+ if (EFCT_LOG_ENABLE_IO_ERRORS(io->efct)) \
+ efc_log_warn(io->efct, fmt, ##__VA_ARGS__); \
+ } while (0)
+
+#define SCSI_CMD_BUF_LENGTH 48
+#define SCSI_RSP_BUF_LENGTH (FCP_RESP_WITH_EXT + SCSI_SENSE_BUFFERSIZE)
+#define EFCT_NUM_SCSI_IOS 8192
+
+enum efct_io_type {
+ EFCT_IO_TYPE_IO = 0,
+ EFCT_IO_TYPE_ELS,
+ EFCT_IO_TYPE_CT,
+ EFCT_IO_TYPE_CT_RESP,
+ EFCT_IO_TYPE_BLS_RESP,
+ EFCT_IO_TYPE_ABORT,
+
+ EFCT_IO_TYPE_MAX,
+};
+
+enum efct_els_state {
+ EFCT_ELS_REQUEST = 0,
+ EFCT_ELS_REQUEST_DELAYED,
+ EFCT_ELS_REQUEST_DELAY_ABORT,
+ EFCT_ELS_REQ_ABORT,
+ EFCT_ELS_REQ_ABORTED,
+ EFCT_ELS_ABORT_IO_COMPL,
+};
+
+/**
+ * Scsi target IO object
+ * @efct: pointer back to efct
+ * @instance_index: unique instance index value
+ * @io: IO display name
+ * @node: pointer to node
+ * @list_entry: io list entry
+ * @io_pending_link: io pending list entry
+ * @ref: reference counter
+ * @release: release callback function
+ * @init_task_tag: initiator task tag (OX_ID) for back-end and SCSI logging
+ * @tgt_task_tag: target task tag (RX_ID) for back-end and SCSI logging
+ * @hw_tag: HW layer unique IO id
+ * @tag: unique IO identifier
+ * @sgl: SGL
+ * @sgl_allocated: Number of allocated SGEs
+ * @sgl_count: Number of SGEs in this SGL
+ * @tgt_io: backend target private IO data
+ * @exp_xfer_len: expected data transfer length, based on FC header
+ * @hw_priv: Declarations private to HW/SLI
+ * @io_type: indicates what this struct efct_io structure is used for
+ * @hio: hw io object
+ * @transferred: Number of bytes transferred
+ * @auto_resp: set if auto_trsp was set
+ * @low_latency: set if low latency request
+ * @wq_steering: selected WQ steering request
+ * @wq_class: selected WQ class if steering is class
+ * @xfer_req: transfer size for current request
+ * @scsi_tgt_cb: target callback function
+ * @scsi_tgt_cb_arg: target callback function argument
+ * @abort_cb: abort callback function
+ * @abort_cb_arg: abort callback function argument
+ * @bls_cb: BLS callback function
+ * @bls_cb_arg: BLS callback function argument
+ * @tmf_cmd: TMF command being processed
+ * @abort_rx_id: rx_id from the ABTS that initiated the command abort
+ * @cmd_tgt: True if this is a Target command
+ * @send_abts: when aborting, indicates ABTS is to be sent
+ * @cmd_ini: True if this is an Initiator command
+ * @seq_init: True if local node has sequence initiative
+ * @iparam: iparams for hw io send call
+ * @hio_type: HW IO type
+ * @wire_len: wire length
+ * @hw_cb: saved HW callback
+ * @io_to_abort: for abort handling, pointer to IO to abort
+ * @rspbuf: SCSI Response buffer
+ * @timeout: Timeout value in seconds for this IO
+ * @cs_ctl: CS_CTL priority for this IO
+ * @io_free: Is io object in freelist
+ * @app_id: application id
+ */
+struct efct_io {
+ struct efct *efct;
+ u32 instance_index;
+ const char *display_name;
+ struct efct_node *node;
+
+ struct list_head list_entry;
+ struct list_head io_pending_link;
+ struct kref ref;
+ void (*release)(struct kref *arg);
+ u32 init_task_tag;
+ u32 tgt_task_tag;
+ u32 hw_tag;
+ u32 tag;
+ struct efct_scsi_sgl *sgl;
+ u32 sgl_allocated;
+ u32 sgl_count;
+ struct efct_scsi_tgt_io tgt_io;
+ u32 exp_xfer_len;
+
+ void *hw_priv;
+
+ enum efct_io_type io_type;
+ struct efct_hw_io *hio;
+ size_t transferred;
+
+ bool auto_resp;
+ bool low_latency;
+ u8 wq_steering;
+ u8 wq_class;
+ u64 xfer_req;
+ efct_scsi_io_cb_t scsi_tgt_cb;
+ void *scsi_tgt_cb_arg;
+ efct_scsi_io_cb_t abort_cb;
+ void *abort_cb_arg;
+ efct_scsi_io_cb_t bls_cb;
+ void *bls_cb_arg;
+ enum efct_scsi_tmf_cmd tmf_cmd;
+ u16 abort_rx_id;
+
+ bool cmd_tgt;
+ bool send_abts;
+ bool cmd_ini;
+ bool seq_init;
+ union efct_hw_io_param_u iparam;
+ enum efct_hw_io_type hio_type;
+ u64 wire_len;
+ void *hw_cb;
+
+ struct efct_io *io_to_abort;
+
+ struct efc_dma rspbuf;
+ u32 timeout;
+ u8 cs_ctl;
+ u8 io_free;
+ u32 app_id;
+};
+
+struct efct_io_cb_arg {
+ int status;
+ int ext_status;
+ void *app;
+};
+
+struct efct_io_pool *
+efct_io_pool_create(struct efct *efct, u32 num_sgl);
+int
+efct_io_pool_free(struct efct_io_pool *io_pool);
+u32
+efct_io_pool_allocated(struct efct_io_pool *io_pool);
+
+struct efct_io *
+efct_io_pool_io_alloc(struct efct_io_pool *io_pool);
+void
+efct_io_pool_io_free(struct efct_io_pool *io_pool, struct efct_io *io);
+struct efct_io *
+efct_io_find_tgt_io(struct efct *efct, struct efct_node *node,
+ u16 ox_id, u16 rx_id);
+#endif /* __EFCT_IO_H__ */
diff --git a/drivers/scsi/elx/efct/efct_lio.c b/drivers/scsi/elx/efct/efct_lio.c
new file mode 100644
index 000000000000..e0d798d6baee
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_lio.c
@@ -0,0 +1,1698 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include "efct_driver.h"
+#include "efct_lio.h"
+
+/*
+ * lio_wq is used to call the LIO backed during creation or deletion of
+ * sessions. This brings serialization to the session management as we create
+ * single threaded work queue.
+ */
+static struct workqueue_struct *lio_wq;
+
+static int
+efct_format_wwn(char *str, size_t len, const char *pre, u64 wwn)
+{
+ u8 a[8];
+
+ put_unaligned_be64(wwn, a);
+ return snprintf(str, len, "%s%8phC", pre, a);
+}
+
+static int
+efct_lio_parse_wwn(const char *name, u64 *wwp, u8 npiv)
+{
+ int num;
+ u8 b[8];
+
+ if (npiv) {
+ num = sscanf(name,
+ "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
+ &b[0], &b[1], &b[2], &b[3], &b[4], &b[5], &b[6],
+ &b[7]);
+ } else {
+ num = sscanf(name,
+ "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+ &b[0], &b[1], &b[2], &b[3], &b[4], &b[5], &b[6],
+ &b[7]);
+ }
+
+ if (num != 8)
+ return -EINVAL;
+
+ *wwp = get_unaligned_be64(b);
+ return 0;
+}
+
+static int
+efct_lio_parse_npiv_wwn(const char *name, size_t size, u64 *wwpn, u64 *wwnn)
+{
+ unsigned int cnt = size;
+ int rc;
+
+ *wwpn = *wwnn = 0;
+ if (name[cnt - 1] == '\n' || name[cnt - 1] == 0)
+ cnt--;
+
+ /* validate we have enough characters for WWPN */
+ if ((cnt != (16 + 1 + 16)) || (name[16] != ':'))
+ return -EINVAL;
+
+ rc = efct_lio_parse_wwn(&name[0], wwpn, 1);
+ if (rc)
+ return rc;
+
+ rc = efct_lio_parse_wwn(&name[17], wwnn, 1);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static ssize_t
+efct_lio_tpg_enable_show(struct config_item *item, char *page)
+{
+ struct se_portal_group *se_tpg = to_tpg(item);
+ struct efct_lio_tpg *tpg =
+ container_of(se_tpg, struct efct_lio_tpg, tpg);
+
+ return snprintf(page, PAGE_SIZE, "%d\n", tpg->enabled);
+}
+
+static ssize_t
+efct_lio_tpg_enable_store(struct config_item *item, const char *page,
+ size_t count)
+{
+ struct se_portal_group *se_tpg = to_tpg(item);
+ struct efct_lio_tpg *tpg =
+ container_of(se_tpg, struct efct_lio_tpg, tpg);
+ struct efct *efct;
+ struct efc *efc;
+ unsigned long op;
+
+ if (!tpg->nport || !tpg->nport->efct) {
+ pr_err("%s: Unable to find EFCT device\n", __func__);
+ return -EINVAL;
+ }
+
+ efct = tpg->nport->efct;
+ efc = efct->efcport;
+
+ if (kstrtoul(page, 0, &op) < 0)
+ return -EINVAL;
+
+ if (op == 1) {
+ int ret;
+
+ tpg->enabled = true;
+ efc_log_debug(efct, "enable portal group %d\n", tpg->tpgt);
+
+ ret = efct_xport_control(efct->xport, EFCT_XPORT_PORT_ONLINE);
+ if (ret) {
+ efct->tgt_efct.lio_nport = NULL;
+ efc_log_debug(efct, "cannot bring port online\n");
+ return ret;
+ }
+ } else if (op == 0) {
+ efc_log_debug(efct, "disable portal group %d\n", tpg->tpgt);
+
+ if (efc->domain && efc->domain->nport)
+ efct_scsi_tgt_del_nport(efc, efc->domain->nport);
+
+ tpg->enabled = false;
+ } else {
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static ssize_t
+efct_lio_npiv_tpg_enable_show(struct config_item *item, char *page)
+{
+ struct se_portal_group *se_tpg = to_tpg(item);
+ struct efct_lio_tpg *tpg =
+ container_of(se_tpg, struct efct_lio_tpg, tpg);
+
+ return snprintf(page, PAGE_SIZE, "%d\n", tpg->enabled);
+}
+
+static ssize_t
+efct_lio_npiv_tpg_enable_store(struct config_item *item, const char *page,
+ size_t count)
+{
+ struct se_portal_group *se_tpg = to_tpg(item);
+ struct efct_lio_tpg *tpg =
+ container_of(se_tpg, struct efct_lio_tpg, tpg);
+ struct efct_lio_vport *lio_vport = tpg->vport;
+ struct efct *efct;
+ struct efc *efc;
+ unsigned long op;
+
+ if (kstrtoul(page, 0, &op) < 0)
+ return -EINVAL;
+
+ if (!lio_vport) {
+ pr_err("Unable to find vport\n");
+ return -EINVAL;
+ }
+
+ efct = lio_vport->efct;
+ efc = efct->efcport;
+
+ if (op == 1) {
+ tpg->enabled = true;
+ efc_log_debug(efct, "enable portal group %d\n", tpg->tpgt);
+
+ if (efc->domain) {
+ int ret;
+
+ ret = efc_nport_vport_new(efc->domain,
+ lio_vport->npiv_wwpn,
+ lio_vport->npiv_wwnn,
+ U32_MAX, false, true,
+ NULL, NULL);
+ if (ret != 0) {
+ efc_log_err(efct, "Failed to create Vport\n");
+ return ret;
+ }
+ return count;
+ }
+
+ if (!(efc_vport_create_spec(efc, lio_vport->npiv_wwnn,
+ lio_vport->npiv_wwpn, U32_MAX,
+ false, true, NULL, NULL)))
+ return -ENOMEM;
+
+ } else if (op == 0) {
+ efc_log_debug(efct, "disable portal group %d\n", tpg->tpgt);
+
+ tpg->enabled = false;
+ /* only physical nport should exist, free lio_nport
+ * allocated in efct_lio_make_nport
+ */
+ if (efc->domain) {
+ efc_nport_vport_del(efct->efcport, efc->domain,
+ lio_vport->npiv_wwpn,
+ lio_vport->npiv_wwnn);
+ return count;
+ }
+ } else {
+ return -EINVAL;
+ }
+ return count;
+}
+
+static char *efct_lio_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+ struct efct_lio_tpg *tpg =
+ container_of(se_tpg, struct efct_lio_tpg, tpg);
+
+ return tpg->nport->wwpn_str;
+}
+
+static char *efct_lio_get_npiv_fabric_wwn(struct se_portal_group *se_tpg)
+{
+ struct efct_lio_tpg *tpg =
+ container_of(se_tpg, struct efct_lio_tpg, tpg);
+
+ return tpg->vport->wwpn_str;
+}
+
+static u16 efct_lio_get_tag(struct se_portal_group *se_tpg)
+{
+ struct efct_lio_tpg *tpg =
+ container_of(se_tpg, struct efct_lio_tpg, tpg);
+
+ return tpg->tpgt;
+}
+
+static u16 efct_lio_get_npiv_tag(struct se_portal_group *se_tpg)
+{
+ struct efct_lio_tpg *tpg =
+ container_of(se_tpg, struct efct_lio_tpg, tpg);
+
+ return tpg->tpgt;
+}
+
+static int efct_lio_check_demo_mode(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int efct_lio_check_demo_mode_cache(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int efct_lio_check_demo_write_protect(struct se_portal_group *se_tpg)
+{
+ struct efct_lio_tpg *tpg =
+ container_of(se_tpg, struct efct_lio_tpg, tpg);
+
+ return tpg->tpg_attrib.demo_mode_write_protect;
+}
+
+static int
+efct_lio_npiv_check_demo_write_protect(struct se_portal_group *se_tpg)
+{
+ struct efct_lio_tpg *tpg =
+ container_of(se_tpg, struct efct_lio_tpg, tpg);
+
+ return tpg->tpg_attrib.demo_mode_write_protect;
+}
+
+static int efct_lio_check_prod_write_protect(struct se_portal_group *se_tpg)
+{
+ struct efct_lio_tpg *tpg =
+ container_of(se_tpg, struct efct_lio_tpg, tpg);
+
+ return tpg->tpg_attrib.prod_mode_write_protect;
+}
+
+static int
+efct_lio_npiv_check_prod_write_protect(struct se_portal_group *se_tpg)
+{
+ struct efct_lio_tpg *tpg =
+ container_of(se_tpg, struct efct_lio_tpg, tpg);
+
+ return tpg->tpg_attrib.prod_mode_write_protect;
+}
+
+static u32 efct_lio_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int efct_lio_check_stop_free(struct se_cmd *se_cmd)
+{
+ struct efct_scsi_tgt_io *ocp =
+ container_of(se_cmd, struct efct_scsi_tgt_io, cmd);
+ struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
+
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_CHK_STOP_FREE);
+ return target_put_sess_cmd(se_cmd);
+}
+
+static int
+efct_lio_abort_tgt_cb(struct efct_io *io,
+ enum efct_scsi_io_status scsi_status,
+ u32 flags, void *arg)
+{
+ efct_lio_io_printf(io, "Abort done, status:%d\n", scsi_status);
+ return 0;
+}
+
+static void
+efct_lio_aborted_task(struct se_cmd *se_cmd)
+{
+ struct efct_scsi_tgt_io *ocp =
+ container_of(se_cmd, struct efct_scsi_tgt_io, cmd);
+ struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
+
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_ABORTED_TASK);
+
+ if (ocp->rsp_sent)
+ return;
+
+ /* command has been aborted, cleanup here */
+ ocp->aborting = true;
+ ocp->err = EFCT_SCSI_STATUS_ABORTED;
+ /* terminate the exchange */
+ efct_scsi_tgt_abort_io(io, efct_lio_abort_tgt_cb, NULL);
+}
+
+static void efct_lio_release_cmd(struct se_cmd *se_cmd)
+{
+ struct efct_scsi_tgt_io *ocp =
+ container_of(se_cmd, struct efct_scsi_tgt_io, cmd);
+ struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
+ struct efct *efct = io->efct;
+
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_RELEASE_CMD);
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_CMPL_CMD);
+ efct_scsi_io_complete(io);
+ atomic_sub_return(1, &efct->tgt_efct.ios_in_use);
+}
+
+static void efct_lio_close_session(struct se_session *se_sess)
+{
+ struct efc_node *node = se_sess->fabric_sess_ptr;
+
+ pr_debug("se_sess=%p node=%p", se_sess, node);
+
+ if (!node) {
+ pr_debug("node is NULL");
+ return;
+ }
+
+ efc_node_post_shutdown(node, NULL);
+}
+
+static u32 efct_lio_sess_get_index(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static void efct_lio_set_default_node_attrs(struct se_node_acl *nacl)
+{
+}
+
+static int efct_lio_get_cmd_state(struct se_cmd *cmd)
+{
+ struct efct_scsi_tgt_io *ocp =
+ container_of(cmd, struct efct_scsi_tgt_io, cmd);
+ struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
+
+ if (!io)
+ return 0;
+
+ return io->tgt_io.state;
+}
+
+static int
+efct_lio_sg_map(struct efct_io *io)
+{
+ struct efct_scsi_tgt_io *ocp = &io->tgt_io;
+ struct se_cmd *cmd = &ocp->cmd;
+
+ ocp->seg_map_cnt = pci_map_sg(io->efct->pci, cmd->t_data_sg,
+ cmd->t_data_nents, cmd->data_direction);
+ if (ocp->seg_map_cnt == 0)
+ return -EFAULT;
+ return 0;
+}
+
+static void
+efct_lio_sg_unmap(struct efct_io *io)
+{
+ struct efct_scsi_tgt_io *ocp = &io->tgt_io;
+ struct se_cmd *cmd = &ocp->cmd;
+
+ if (WARN_ON(!ocp->seg_map_cnt || !cmd->t_data_sg))
+ return;
+
+ pci_unmap_sg(io->efct->pci, cmd->t_data_sg,
+ ocp->seg_map_cnt, cmd->data_direction);
+ ocp->seg_map_cnt = 0;
+}
+
+static int
+efct_lio_status_done(struct efct_io *io,
+ enum efct_scsi_io_status scsi_status,
+ u32 flags, void *arg)
+{
+ struct efct_scsi_tgt_io *ocp = &io->tgt_io;
+
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_RSP_DONE);
+ if (scsi_status != EFCT_SCSI_STATUS_GOOD) {
+ efct_lio_io_printf(io, "callback completed with error=%d\n",
+ scsi_status);
+ ocp->err = scsi_status;
+ }
+ if (ocp->seg_map_cnt)
+ efct_lio_sg_unmap(io);
+
+ efct_lio_io_printf(io, "status=%d, err=%d flags=0x%x, dir=%d\n",
+ scsi_status, ocp->err, flags, ocp->ddir);
+
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_GENERIC_FREE);
+ transport_generic_free_cmd(&io->tgt_io.cmd, 0);
+ return 0;
+}
+
+static int
+efct_lio_datamove_done(struct efct_io *io, enum efct_scsi_io_status scsi_status,
+ u32 flags, void *arg);
+
+static int
+efct_lio_write_pending(struct se_cmd *cmd)
+{
+ struct efct_scsi_tgt_io *ocp =
+ container_of(cmd, struct efct_scsi_tgt_io, cmd);
+ struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
+ struct efct_scsi_sgl *sgl = io->sgl;
+ struct scatterlist *sg;
+ u32 flags = 0, cnt, curcnt;
+ u64 length = 0;
+
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_WRITE_PENDING);
+ efct_lio_io_printf(io, "trans_state=0x%x se_cmd_flags=0x%x\n",
+ cmd->transport_state, cmd->se_cmd_flags);
+
+ if (ocp->seg_cnt == 0) {
+ ocp->seg_cnt = cmd->t_data_nents;
+ ocp->cur_seg = 0;
+ if (efct_lio_sg_map(io)) {
+ efct_lio_io_printf(io, "efct_lio_sg_map failed\n");
+ return -EFAULT;
+ }
+ }
+ curcnt = (ocp->seg_map_cnt - ocp->cur_seg);
+ curcnt = (curcnt < io->sgl_allocated) ? curcnt : io->sgl_allocated;
+ /* find current sg */
+ for (cnt = 0, sg = cmd->t_data_sg; cnt < ocp->cur_seg; cnt++,
+ sg = sg_next(sg))
+ ;/* do nothing */
+
+ for (cnt = 0; cnt < curcnt; cnt++, sg = sg_next(sg)) {
+ sgl[cnt].addr = sg_dma_address(sg);
+ sgl[cnt].dif_addr = 0;
+ sgl[cnt].len = sg_dma_len(sg);
+ length += sgl[cnt].len;
+ ocp->cur_seg++;
+ }
+
+ if (ocp->cur_seg == ocp->seg_cnt)
+ flags = EFCT_SCSI_LAST_DATAPHASE;
+
+ return efct_scsi_recv_wr_data(io, flags, sgl, curcnt, length,
+ efct_lio_datamove_done, NULL);
+}
+
+static int
+efct_lio_queue_data_in(struct se_cmd *cmd)
+{
+ struct efct_scsi_tgt_io *ocp =
+ container_of(cmd, struct efct_scsi_tgt_io, cmd);
+ struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
+ struct efct_scsi_sgl *sgl = io->sgl;
+ struct scatterlist *sg = NULL;
+ uint flags = 0, cnt = 0, curcnt = 0;
+ u64 length = 0;
+
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_QUEUE_DATA_IN);
+
+ if (ocp->seg_cnt == 0) {
+ if (cmd->data_length) {
+ ocp->seg_cnt = cmd->t_data_nents;
+ ocp->cur_seg = 0;
+ if (efct_lio_sg_map(io)) {
+ efct_lio_io_printf(io,
+ "efct_lio_sg_map failed\n");
+ return -EAGAIN;
+ }
+ } else {
+ /* If command length is 0, send the response status */
+ struct efct_scsi_cmd_resp rsp;
+
+ memset(&rsp, 0, sizeof(rsp));
+ efct_lio_io_printf(io,
+ "cmd : %p length 0, send status\n",
+ cmd);
+ return efct_scsi_send_resp(io, 0, &rsp,
+ efct_lio_status_done, NULL);
+ }
+ }
+ curcnt = min(ocp->seg_map_cnt - ocp->cur_seg, io->sgl_allocated);
+
+ while (cnt < curcnt) {
+ sg = &cmd->t_data_sg[ocp->cur_seg];
+ sgl[cnt].addr = sg_dma_address(sg);
+ sgl[cnt].dif_addr = 0;
+ if (ocp->transferred_len + sg_dma_len(sg) >= cmd->data_length)
+ sgl[cnt].len = cmd->data_length - ocp->transferred_len;
+ else
+ sgl[cnt].len = sg_dma_len(sg);
+
+ ocp->transferred_len += sgl[cnt].len;
+ length += sgl[cnt].len;
+ ocp->cur_seg++;
+ cnt++;
+ if (ocp->transferred_len == cmd->data_length)
+ break;
+ }
+
+ if (ocp->transferred_len == cmd->data_length) {
+ flags = EFCT_SCSI_LAST_DATAPHASE;
+ ocp->seg_cnt = ocp->cur_seg;
+ }
+
+ /* If there is residual, disable Auto Good Response */
+ if (cmd->residual_count)
+ flags |= EFCT_SCSI_NO_AUTO_RESPONSE;
+
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_SEND_RD_DATA);
+
+ return efct_scsi_send_rd_data(io, flags, sgl, curcnt, length,
+ efct_lio_datamove_done, NULL);
+}
+
+static void
+efct_lio_send_resp(struct efct_io *io, enum efct_scsi_io_status scsi_status,
+ u32 flags)
+{
+ struct efct_scsi_cmd_resp rsp;
+ struct efct_scsi_tgt_io *ocp = &io->tgt_io;
+ struct se_cmd *cmd = &io->tgt_io.cmd;
+ int rc;
+
+ if (flags & EFCT_SCSI_IO_CMPL_RSP_SENT) {
+ ocp->rsp_sent = true;
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_GENERIC_FREE);
+ transport_generic_free_cmd(&io->tgt_io.cmd, 0);
+ return;
+ }
+
+ /* send check condition if an error occurred */
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.scsi_status = cmd->scsi_status;
+ rsp.sense_data = (uint8_t *)io->tgt_io.sense_buffer;
+ rsp.sense_data_length = cmd->scsi_sense_length;
+
+ /* Check for residual underrun or overrun */
+ if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
+ rsp.residual = -cmd->residual_count;
+ else if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT)
+ rsp.residual = cmd->residual_count;
+
+ rc = efct_scsi_send_resp(io, 0, &rsp, efct_lio_status_done, NULL);
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_SEND_RSP);
+ if (rc != 0) {
+ efct_lio_io_printf(io, "Read done, send rsp failed %d\n", rc);
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_GENERIC_FREE);
+ transport_generic_free_cmd(&io->tgt_io.cmd, 0);
+ } else {
+ ocp->rsp_sent = true;
+ }
+}
+
+static int
+efct_lio_datamove_done(struct efct_io *io, enum efct_scsi_io_status scsi_status,
+ u32 flags, void *arg)
+{
+ struct efct_scsi_tgt_io *ocp = &io->tgt_io;
+
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_DATA_DONE);
+ if (scsi_status != EFCT_SCSI_STATUS_GOOD) {
+ efct_lio_io_printf(io, "callback completed with error=%d\n",
+ scsi_status);
+ ocp->err = scsi_status;
+ }
+ efct_lio_io_printf(io, "seg_map_cnt=%d\n", ocp->seg_map_cnt);
+ if (ocp->seg_map_cnt) {
+ if (ocp->err == EFCT_SCSI_STATUS_GOOD &&
+ ocp->cur_seg < ocp->seg_cnt) {
+ int rc;
+
+ efct_lio_io_printf(io, "continuing cmd at segm=%d\n",
+ ocp->cur_seg);
+ if (ocp->ddir == DMA_TO_DEVICE)
+ rc = efct_lio_write_pending(&ocp->cmd);
+ else
+ rc = efct_lio_queue_data_in(&ocp->cmd);
+ if (!rc)
+ return 0;
+
+ ocp->err = EFCT_SCSI_STATUS_ERROR;
+ efct_lio_io_printf(io, "could not continue command\n");
+ }
+ efct_lio_sg_unmap(io);
+ }
+
+ if (io->tgt_io.aborting) {
+ efct_lio_io_printf(io, "IO done aborted\n");
+ return 0;
+ }
+
+ if (ocp->ddir == DMA_TO_DEVICE) {
+ efct_lio_io_printf(io, "Write done, trans_state=0x%x\n",
+ io->tgt_io.cmd.transport_state);
+ if (scsi_status != EFCT_SCSI_STATUS_GOOD) {
+ transport_generic_request_failure(&io->tgt_io.cmd,
+ TCM_CHECK_CONDITION_ABORT_CMD);
+ efct_set_lio_io_state(io,
+ EFCT_LIO_STATE_TGT_GENERIC_REQ_FAILURE);
+ } else {
+ efct_set_lio_io_state(io,
+ EFCT_LIO_STATE_TGT_EXECUTE_CMD);
+ target_execute_cmd(&io->tgt_io.cmd);
+ }
+ } else {
+ efct_lio_send_resp(io, scsi_status, flags);
+ }
+ return 0;
+}
+
+static int
+efct_lio_tmf_done(struct efct_io *io, enum efct_scsi_io_status scsi_status,
+ u32 flags, void *arg)
+{
+ efct_lio_tmfio_printf(io, "cmd=%p status=%d, flags=0x%x\n",
+ &io->tgt_io.cmd, scsi_status, flags);
+
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_GENERIC_FREE);
+ transport_generic_free_cmd(&io->tgt_io.cmd, 0);
+ return 0;
+}
+
+static int
+efct_lio_null_tmf_done(struct efct_io *tmfio,
+ enum efct_scsi_io_status scsi_status,
+ u32 flags, void *arg)
+{
+ efct_lio_tmfio_printf(tmfio, "cmd=%p status=%d, flags=0x%x\n",
+ &tmfio->tgt_io.cmd, scsi_status, flags);
+
+ /* free struct efct_io only, no active se_cmd */
+ efct_scsi_io_complete(tmfio);
+ return 0;
+}
+
+static int
+efct_lio_queue_status(struct se_cmd *cmd)
+{
+ struct efct_scsi_cmd_resp rsp;
+ struct efct_scsi_tgt_io *ocp =
+ container_of(cmd, struct efct_scsi_tgt_io, cmd);
+ struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
+ int rc = 0;
+
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_QUEUE_STATUS);
+ efct_lio_io_printf(io,
+ "status=0x%x trans_state=0x%x se_cmd_flags=0x%x sns_len=%d\n",
+ cmd->scsi_status, cmd->transport_state, cmd->se_cmd_flags,
+ cmd->scsi_sense_length);
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.scsi_status = cmd->scsi_status;
+ rsp.sense_data = (u8 *)io->tgt_io.sense_buffer;
+ rsp.sense_data_length = cmd->scsi_sense_length;
+
+ /* Check for residual underrun or overrun, mark negitive value for
+ * underrun to recognize in HW
+ */
+ if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
+ rsp.residual = -cmd->residual_count;
+ else if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT)
+ rsp.residual = cmd->residual_count;
+
+ rc = efct_scsi_send_resp(io, 0, &rsp, efct_lio_status_done, NULL);
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_SEND_RSP);
+ if (rc == 0)
+ ocp->rsp_sent = true;
+ return rc;
+}
+
+static void efct_lio_queue_tm_rsp(struct se_cmd *cmd)
+{
+ struct efct_scsi_tgt_io *ocp =
+ container_of(cmd, struct efct_scsi_tgt_io, cmd);
+ struct efct_io *tmfio = container_of(ocp, struct efct_io, tgt_io);
+ struct se_tmr_req *se_tmr = cmd->se_tmr_req;
+ u8 rspcode;
+
+ efct_lio_tmfio_printf(tmfio, "cmd=%p function=0x%x tmr->response=%d\n",
+ cmd, se_tmr->function, se_tmr->response);
+ switch (se_tmr->response) {
+ case TMR_FUNCTION_COMPLETE:
+ rspcode = EFCT_SCSI_TMF_FUNCTION_COMPLETE;
+ break;
+ case TMR_TASK_DOES_NOT_EXIST:
+ rspcode = EFCT_SCSI_TMF_FUNCTION_IO_NOT_FOUND;
+ break;
+ case TMR_LUN_DOES_NOT_EXIST:
+ rspcode = EFCT_SCSI_TMF_INCORRECT_LOGICAL_UNIT_NUMBER;
+ break;
+ case TMR_FUNCTION_REJECTED:
+ default:
+ rspcode = EFCT_SCSI_TMF_FUNCTION_REJECTED;
+ break;
+ }
+ efct_scsi_send_tmf_resp(tmfio, rspcode, NULL, efct_lio_tmf_done, NULL);
+}
+
+static struct efct *efct_find_wwpn(u64 wwpn)
+{
+ struct efct *efct;
+
+ /* Search for the HBA that has this WWPN */
+ list_for_each_entry(efct, &efct_devices, list_entry) {
+
+ if (wwpn == efct_get_wwpn(&efct->hw))
+ return efct;
+ }
+
+ return NULL;
+}
+
+static struct se_wwn *
+efct_lio_make_nport(struct target_fabric_configfs *tf,
+ struct config_group *group, const char *name)
+{
+ struct efct_lio_nport *lio_nport;
+ struct efct *efct;
+ int ret;
+ u64 wwpn;
+
+ ret = efct_lio_parse_wwn(name, &wwpn, 0);
+ if (ret)
+ return ERR_PTR(ret);
+
+ efct = efct_find_wwpn(wwpn);
+ if (!efct) {
+ pr_err("cannot find EFCT for base wwpn %s\n", name);
+ return ERR_PTR(-ENXIO);
+ }
+
+ lio_nport = kzalloc(sizeof(*lio_nport), GFP_KERNEL);
+ if (!lio_nport)
+ return ERR_PTR(-ENOMEM);
+
+ lio_nport->efct = efct;
+ lio_nport->wwpn = wwpn;
+ efct_format_wwn(lio_nport->wwpn_str, sizeof(lio_nport->wwpn_str),
+ "naa.", wwpn);
+ efct->tgt_efct.lio_nport = lio_nport;
+
+ return &lio_nport->nport_wwn;
+}
+
+static struct se_wwn *
+efct_lio_npiv_make_nport(struct target_fabric_configfs *tf,
+ struct config_group *group, const char *name)
+{
+ struct efct_lio_vport *lio_vport;
+ struct efct *efct;
+ int ret = -1;
+ u64 p_wwpn, npiv_wwpn, npiv_wwnn;
+ char *p, *pbuf, tmp[128];
+ struct efct_lio_vport_list_t *vport_list;
+ struct fc_vport *new_fc_vport;
+ struct fc_vport_identifiers vport_id;
+ unsigned long flags = 0;
+
+ snprintf(tmp, sizeof(tmp), "%s", name);
+ pbuf = &tmp[0];
+
+ p = strsep(&pbuf, "@");
+
+ if (!p || !pbuf) {
+ pr_err("Unable to find separator operator(@)\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ ret = efct_lio_parse_wwn(p, &p_wwpn, 0);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = efct_lio_parse_npiv_wwn(pbuf, strlen(pbuf), &npiv_wwpn,
+ &npiv_wwnn);
+ if (ret)
+ return ERR_PTR(ret);
+
+ efct = efct_find_wwpn(p_wwpn);
+ if (!efct) {
+ pr_err("cannot find EFCT for base wwpn %s\n", name);
+ return ERR_PTR(-ENXIO);
+ }
+
+ lio_vport = kzalloc(sizeof(*lio_vport), GFP_KERNEL);
+ if (!lio_vport)
+ return ERR_PTR(-ENOMEM);
+
+ lio_vport->efct = efct;
+ lio_vport->wwpn = p_wwpn;
+ lio_vport->npiv_wwpn = npiv_wwpn;
+ lio_vport->npiv_wwnn = npiv_wwnn;
+
+ efct_format_wwn(lio_vport->wwpn_str, sizeof(lio_vport->wwpn_str),
+ "naa.", npiv_wwpn);
+
+ vport_list = kzalloc(sizeof(*vport_list), GFP_KERNEL);
+ if (!vport_list) {
+ kfree(lio_vport);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ vport_list->lio_vport = lio_vport;
+
+ memset(&vport_id, 0, sizeof(vport_id));
+ vport_id.port_name = npiv_wwpn;
+ vport_id.node_name = npiv_wwnn;
+ vport_id.roles = FC_PORT_ROLE_FCP_INITIATOR;
+ vport_id.vport_type = FC_PORTTYPE_NPIV;
+ vport_id.disable = false;
+
+ new_fc_vport = fc_vport_create(efct->shost, 0, &vport_id);
+ if (!new_fc_vport) {
+ efc_log_err(efct, "fc_vport_create failed\n");
+ kfree(lio_vport);
+ kfree(vport_list);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ lio_vport->fc_vport = new_fc_vport;
+ spin_lock_irqsave(&efct->tgt_efct.efct_lio_lock, flags);
+ INIT_LIST_HEAD(&vport_list->list_entry);
+ list_add_tail(&vport_list->list_entry, &efct->tgt_efct.vport_list);
+ spin_unlock_irqrestore(&efct->tgt_efct.efct_lio_lock, flags);
+
+ return &lio_vport->vport_wwn;
+}
+
+static void
+efct_lio_drop_nport(struct se_wwn *wwn)
+{
+ struct efct_lio_nport *lio_nport =
+ container_of(wwn, struct efct_lio_nport, nport_wwn);
+ struct efct *efct = lio_nport->efct;
+
+ /* only physical nport should exist, free lio_nport allocated
+ * in efct_lio_make_nport.
+ */
+ kfree(efct->tgt_efct.lio_nport);
+ efct->tgt_efct.lio_nport = NULL;
+}
+
+static void
+efct_lio_npiv_drop_nport(struct se_wwn *wwn)
+{
+ struct efct_lio_vport *lio_vport =
+ container_of(wwn, struct efct_lio_vport, vport_wwn);
+ struct efct_lio_vport_list_t *vport, *next_vport;
+ struct efct *efct = lio_vport->efct;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&efct->tgt_efct.efct_lio_lock, flags);
+
+ if (lio_vport->fc_vport)
+ fc_vport_terminate(lio_vport->fc_vport);
+
+ list_for_each_entry_safe(vport, next_vport, &efct->tgt_efct.vport_list,
+ list_entry) {
+ if (vport->lio_vport == lio_vport) {
+ list_del(&vport->list_entry);
+ kfree(vport->lio_vport);
+ kfree(vport);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&efct->tgt_efct.efct_lio_lock, flags);
+}
+
+static struct se_portal_group *
+efct_lio_make_tpg(struct se_wwn *wwn, const char *name)
+{
+ struct efct_lio_nport *lio_nport =
+ container_of(wwn, struct efct_lio_nport, nport_wwn);
+ struct efct_lio_tpg *tpg;
+ struct efct *efct;
+ unsigned long n;
+ int ret;
+
+ if (strstr(name, "tpgt_") != name)
+ return ERR_PTR(-EINVAL);
+ if (kstrtoul(name + 5, 10, &n) || n > USHRT_MAX)
+ return ERR_PTR(-EINVAL);
+
+ tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
+ if (!tpg)
+ return ERR_PTR(-ENOMEM);
+
+ tpg->nport = lio_nport;
+ tpg->tpgt = n;
+ tpg->enabled = false;
+
+ tpg->tpg_attrib.generate_node_acls = 1;
+ tpg->tpg_attrib.demo_mode_write_protect = 1;
+ tpg->tpg_attrib.cache_dynamic_acls = 1;
+ tpg->tpg_attrib.demo_mode_login_only = 1;
+ tpg->tpg_attrib.session_deletion_wait = 1;
+
+ ret = core_tpg_register(wwn, &tpg->tpg, SCSI_PROTOCOL_FCP);
+ if (ret < 0) {
+ kfree(tpg);
+ return NULL;
+ }
+ efct = lio_nport->efct;
+ efct->tgt_efct.tpg = tpg;
+ efc_log_debug(efct, "create portal group %d\n", tpg->tpgt);
+
+ xa_init(&efct->lookup);
+ return &tpg->tpg;
+}
+
+static void
+efct_lio_drop_tpg(struct se_portal_group *se_tpg)
+{
+ struct efct_lio_tpg *tpg =
+ container_of(se_tpg, struct efct_lio_tpg, tpg);
+
+ struct efct *efct = tpg->nport->efct;
+
+ efc_log_debug(efct, "drop portal group %d\n", tpg->tpgt);
+ tpg->nport->efct->tgt_efct.tpg = NULL;
+ core_tpg_deregister(se_tpg);
+ xa_destroy(&efct->lookup);
+ kfree(tpg);
+}
+
+static struct se_portal_group *
+efct_lio_npiv_make_tpg(struct se_wwn *wwn, const char *name)
+{
+ struct efct_lio_vport *lio_vport =
+ container_of(wwn, struct efct_lio_vport, vport_wwn);
+ struct efct_lio_tpg *tpg;
+ struct efct *efct;
+ unsigned long n;
+ int ret;
+
+ efct = lio_vport->efct;
+ if (strstr(name, "tpgt_") != name)
+ return ERR_PTR(-EINVAL);
+ if (kstrtoul(name + 5, 10, &n) || n > USHRT_MAX)
+ return ERR_PTR(-EINVAL);
+
+ if (n != 1) {
+ efc_log_err(efct, "Invalid tpgt index: %ld provided\n", n);
+ return ERR_PTR(-EINVAL);
+ }
+
+ tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
+ if (!tpg)
+ return ERR_PTR(-ENOMEM);
+
+ tpg->vport = lio_vport;
+ tpg->tpgt = n;
+ tpg->enabled = false;
+
+ tpg->tpg_attrib.generate_node_acls = 1;
+ tpg->tpg_attrib.demo_mode_write_protect = 1;
+ tpg->tpg_attrib.cache_dynamic_acls = 1;
+ tpg->tpg_attrib.demo_mode_login_only = 1;
+ tpg->tpg_attrib.session_deletion_wait = 1;
+
+ ret = core_tpg_register(wwn, &tpg->tpg, SCSI_PROTOCOL_FCP);
+
+ if (ret < 0) {
+ kfree(tpg);
+ return NULL;
+ }
+ lio_vport->tpg = tpg;
+ efc_log_debug(efct, "create vport portal group %d\n", tpg->tpgt);
+
+ return &tpg->tpg;
+}
+
+static void
+efct_lio_npiv_drop_tpg(struct se_portal_group *se_tpg)
+{
+ struct efct_lio_tpg *tpg =
+ container_of(se_tpg, struct efct_lio_tpg, tpg);
+
+ efc_log_debug(tpg->vport->efct, "drop npiv portal group %d\n",
+ tpg->tpgt);
+ core_tpg_deregister(se_tpg);
+ kfree(tpg);
+}
+
+static int
+efct_lio_init_nodeacl(struct se_node_acl *se_nacl, const char *name)
+{
+ struct efct_lio_nacl *nacl;
+ u64 wwnn;
+
+ if (efct_lio_parse_wwn(name, &wwnn, 0) < 0)
+ return -EINVAL;
+
+ nacl = container_of(se_nacl, struct efct_lio_nacl, se_node_acl);
+ nacl->nport_wwnn = wwnn;
+
+ efct_format_wwn(nacl->nport_name, sizeof(nacl->nport_name), "", wwnn);
+ return 0;
+}
+
+static int efct_lio_check_demo_mode_login_only(struct se_portal_group *stpg)
+{
+ struct efct_lio_tpg *tpg = container_of(stpg, struct efct_lio_tpg, tpg);
+
+ return tpg->tpg_attrib.demo_mode_login_only;
+}
+
+static int
+efct_lio_npiv_check_demo_mode_login_only(struct se_portal_group *stpg)
+{
+ struct efct_lio_tpg *tpg = container_of(stpg, struct efct_lio_tpg, tpg);
+
+ return tpg->tpg_attrib.demo_mode_login_only;
+}
+
+static struct efct_lio_tpg *
+efct_get_vport_tpg(struct efc_node *node)
+{
+ struct efct *efct;
+ u64 wwpn = node->nport->wwpn;
+ struct efct_lio_vport_list_t *vport, *next;
+ struct efct_lio_vport *lio_vport = NULL;
+ struct efct_lio_tpg *tpg = NULL;
+ unsigned long flags = 0;
+
+ efct = node->efc->base;
+ spin_lock_irqsave(&efct->tgt_efct.efct_lio_lock, flags);
+ list_for_each_entry_safe(vport, next, &efct->tgt_efct.vport_list,
+ list_entry) {
+ lio_vport = vport->lio_vport;
+ if (wwpn && lio_vport && lio_vport->npiv_wwpn == wwpn) {
+ efc_log_debug(efct, "found tpg on vport\n");
+ tpg = lio_vport->tpg;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&efct->tgt_efct.efct_lio_lock, flags);
+ return tpg;
+}
+
+static void
+_efct_tgt_node_free(struct kref *arg)
+{
+ struct efct_node *tgt_node = container_of(arg, struct efct_node, ref);
+ struct efc_node *node = tgt_node->node;
+
+ efc_scsi_del_initiator_complete(node->efc, node);
+ kfree(tgt_node);
+}
+
+static int efct_session_cb(struct se_portal_group *se_tpg,
+ struct se_session *se_sess, void *private)
+{
+ struct efc_node *node = private;
+ struct efct_node *tgt_node;
+ struct efct *efct = node->efc->base;
+
+ tgt_node = kzalloc(sizeof(*tgt_node), GFP_KERNEL);
+ if (!tgt_node)
+ return -ENOMEM;
+
+ kref_init(&tgt_node->ref);
+ tgt_node->release = _efct_tgt_node_free;
+
+ tgt_node->session = se_sess;
+ node->tgt_node = tgt_node;
+ tgt_node->efct = efct;
+
+ tgt_node->node = node;
+
+ tgt_node->node_fc_id = node->rnode.fc_id;
+ tgt_node->port_fc_id = node->nport->fc_id;
+ tgt_node->vpi = node->nport->indicator;
+ tgt_node->rpi = node->rnode.indicator;
+
+ spin_lock_init(&tgt_node->active_ios_lock);
+ INIT_LIST_HEAD(&tgt_node->active_ios);
+
+ return 0;
+}
+
+int efct_scsi_tgt_new_device(struct efct *efct)
+{
+ u32 total_ios;
+
+ /* Get the max settings */
+ efct->tgt_efct.max_sge = sli_get_max_sge(&efct->hw.sli);
+ efct->tgt_efct.max_sgl = sli_get_max_sgl(&efct->hw.sli);
+
+ /* initialize IO watermark fields */
+ atomic_set(&efct->tgt_efct.ios_in_use, 0);
+ total_ios = efct->hw.config.n_io;
+ efc_log_debug(efct, "total_ios=%d\n", total_ios);
+ efct->tgt_efct.watermark_min =
+ (total_ios * EFCT_WATERMARK_LOW_PCT) / 100;
+ efct->tgt_efct.watermark_max =
+ (total_ios * EFCT_WATERMARK_HIGH_PCT) / 100;
+ atomic_set(&efct->tgt_efct.io_high_watermark,
+ efct->tgt_efct.watermark_max);
+ atomic_set(&efct->tgt_efct.watermark_hit, 0);
+ atomic_set(&efct->tgt_efct.initiator_count, 0);
+
+ lio_wq = create_singlethread_workqueue("efct_lio_worker");
+ if (!lio_wq) {
+ efc_log_err(efct, "workqueue create failed\n");
+ return -EIO;
+ }
+
+ spin_lock_init(&efct->tgt_efct.efct_lio_lock);
+ INIT_LIST_HEAD(&efct->tgt_efct.vport_list);
+
+ return 0;
+}
+
+int efct_scsi_tgt_del_device(struct efct *efct)
+{
+ flush_workqueue(lio_wq);
+
+ return 0;
+}
+
+int
+efct_scsi_tgt_new_nport(struct efc *efc, struct efc_nport *nport)
+{
+ struct efct *efct = nport->efc->base;
+
+ efc_log_debug(efct, "New SPORT: %s bound to %s\n", nport->display_name,
+ efct->tgt_efct.lio_nport->wwpn_str);
+
+ return 0;
+}
+
+void
+efct_scsi_tgt_del_nport(struct efc *efc, struct efc_nport *nport)
+{
+ efc_log_debug(efc, "Del SPORT: %s\n", nport->display_name);
+}
+
+static void efct_lio_setup_session(struct work_struct *work)
+{
+ struct efct_lio_wq_data *wq_data =
+ container_of(work, struct efct_lio_wq_data, work);
+ struct efct *efct = wq_data->efct;
+ struct efc_node *node = wq_data->ptr;
+ char wwpn[WWN_NAME_LEN];
+ struct efct_lio_tpg *tpg;
+ struct efct_node *tgt_node;
+ struct se_portal_group *se_tpg;
+ struct se_session *se_sess;
+ int watermark;
+ int ini_count;
+ u64 id;
+
+ /* Check to see if it's belongs to vport,
+ * if not get physical port
+ */
+ tpg = efct_get_vport_tpg(node);
+ if (tpg) {
+ se_tpg = &tpg->tpg;
+ } else if (efct->tgt_efct.tpg) {
+ tpg = efct->tgt_efct.tpg;
+ se_tpg = &tpg->tpg;
+ } else {
+ efc_log_err(efct, "failed to init session\n");
+ return;
+ }
+
+ /*
+ * Format the FCP Initiator port_name into colon
+ * separated values to match the format by our explicit
+ * ConfigFS NodeACLs.
+ */
+ efct_format_wwn(wwpn, sizeof(wwpn), "", efc_node_get_wwpn(node));
+
+ se_sess = target_setup_session(se_tpg, 0, 0, TARGET_PROT_NORMAL, wwpn,
+ node, efct_session_cb);
+ if (IS_ERR(se_sess)) {
+ efc_log_err(efct, "failed to setup session\n");
+ kfree(wq_data);
+ efc_scsi_sess_reg_complete(node, -EIO);
+ return;
+ }
+
+ tgt_node = node->tgt_node;
+ id = (u64) tgt_node->port_fc_id << 32 | tgt_node->node_fc_id;
+
+ efc_log_debug(efct, "new initiator sess=%p node=%p id: %llx\n",
+ se_sess, node, id);
+
+ if (xa_err(xa_store(&efct->lookup, id, tgt_node, GFP_KERNEL)))
+ efc_log_err(efct, "Node lookup store failed\n");
+
+ efc_scsi_sess_reg_complete(node, 0);
+
+ /* update IO watermark: increment initiator count */
+ ini_count = atomic_add_return(1, &efct->tgt_efct.initiator_count);
+ watermark = efct->tgt_efct.watermark_max -
+ ini_count * EFCT_IO_WATERMARK_PER_INITIATOR;
+ watermark = (efct->tgt_efct.watermark_min > watermark) ?
+ efct->tgt_efct.watermark_min : watermark;
+ atomic_set(&efct->tgt_efct.io_high_watermark, watermark);
+
+ kfree(wq_data);
+}
+
+int efct_scsi_new_initiator(struct efc *efc, struct efc_node *node)
+{
+ struct efct *efct = node->efc->base;
+ struct efct_lio_wq_data *wq_data;
+
+ /*
+ * Since LIO only supports initiator validation at thread level,
+ * we are open minded and accept all callers.
+ */
+ wq_data = kzalloc(sizeof(*wq_data), GFP_ATOMIC);
+ if (!wq_data)
+ return -ENOMEM;
+
+ wq_data->ptr = node;
+ wq_data->efct = efct;
+ INIT_WORK(&wq_data->work, efct_lio_setup_session);
+ queue_work(lio_wq, &wq_data->work);
+ return EFC_SCSI_CALL_ASYNC;
+}
+
+static void efct_lio_remove_session(struct work_struct *work)
+{
+ struct efct_lio_wq_data *wq_data =
+ container_of(work, struct efct_lio_wq_data, work);
+ struct efct *efct = wq_data->efct;
+ struct efc_node *node = wq_data->ptr;
+ struct efct_node *tgt_node;
+ struct se_session *se_sess;
+
+ tgt_node = node->tgt_node;
+ if (!tgt_node) {
+ /* base driver has sent back-to-back requests
+ * to unreg session with no intervening
+ * register
+ */
+ efc_log_err(efct, "unreg session for NULL session\n");
+ efc_scsi_del_initiator_complete(node->efc, node);
+ return;
+ }
+
+ se_sess = tgt_node->session;
+ efc_log_debug(efct, "unreg session se_sess=%p node=%p\n",
+ se_sess, node);
+
+ /* first flag all session commands to complete */
+ target_stop_session(se_sess);
+
+ /* now wait for session commands to complete */
+ target_wait_for_sess_cmds(se_sess);
+ target_remove_session(se_sess);
+ tgt_node->session = NULL;
+ node->tgt_node = NULL;
+ kref_put(&tgt_node->ref, tgt_node->release);
+
+ kfree(wq_data);
+}
+
+int efct_scsi_del_initiator(struct efc *efc, struct efc_node *node, int reason)
+{
+ struct efct *efct = node->efc->base;
+ struct efct_node *tgt_node = node->tgt_node;
+ struct efct_lio_wq_data *wq_data;
+ int watermark;
+ int ini_count;
+ u64 id;
+
+ if (reason == EFCT_SCSI_INITIATOR_MISSING)
+ return EFC_SCSI_CALL_COMPLETE;
+
+ if (!tgt_node) {
+ efc_log_err(efct, "tgt_node is NULL\n");
+ return -EIO;
+ }
+
+ wq_data = kzalloc(sizeof(*wq_data), GFP_ATOMIC);
+ if (!wq_data)
+ return -ENOMEM;
+
+ id = (u64) tgt_node->port_fc_id << 32 | tgt_node->node_fc_id;
+ xa_erase(&efct->lookup, id);
+
+ wq_data->ptr = node;
+ wq_data->efct = efct;
+ INIT_WORK(&wq_data->work, efct_lio_remove_session);
+ queue_work(lio_wq, &wq_data->work);
+
+ /*
+ * update IO watermark: decrement initiator count
+ */
+ ini_count = atomic_sub_return(1, &efct->tgt_efct.initiator_count);
+
+ watermark = efct->tgt_efct.watermark_max -
+ ini_count * EFCT_IO_WATERMARK_PER_INITIATOR;
+ watermark = (efct->tgt_efct.watermark_min > watermark) ?
+ efct->tgt_efct.watermark_min : watermark;
+ atomic_set(&efct->tgt_efct.io_high_watermark, watermark);
+
+ return EFC_SCSI_CALL_ASYNC;
+}
+
+void efct_scsi_recv_cmd(struct efct_io *io, uint64_t lun, u8 *cdb,
+ u32 cdb_len, u32 flags)
+{
+ struct efct_scsi_tgt_io *ocp = &io->tgt_io;
+ struct se_cmd *se_cmd = &io->tgt_io.cmd;
+ struct efct *efct = io->efct;
+ char *ddir;
+ struct efct_node *tgt_node;
+ struct se_session *se_sess;
+ int rc = 0;
+
+ memset(ocp, 0, sizeof(struct efct_scsi_tgt_io));
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_RECV_CMD);
+ atomic_add_return(1, &efct->tgt_efct.ios_in_use);
+
+ /* set target timeout */
+ io->timeout = efct->target_io_timer_sec;
+
+ if (flags & EFCT_SCSI_CMD_SIMPLE)
+ ocp->task_attr = TCM_SIMPLE_TAG;
+ else if (flags & EFCT_SCSI_CMD_HEAD_OF_QUEUE)
+ ocp->task_attr = TCM_HEAD_TAG;
+ else if (flags & EFCT_SCSI_CMD_ORDERED)
+ ocp->task_attr = TCM_ORDERED_TAG;
+ else if (flags & EFCT_SCSI_CMD_ACA)
+ ocp->task_attr = TCM_ACA_TAG;
+
+ switch (flags & (EFCT_SCSI_CMD_DIR_IN | EFCT_SCSI_CMD_DIR_OUT)) {
+ case EFCT_SCSI_CMD_DIR_IN:
+ ddir = "FROM_INITIATOR";
+ ocp->ddir = DMA_TO_DEVICE;
+ break;
+ case EFCT_SCSI_CMD_DIR_OUT:
+ ddir = "TO_INITIATOR";
+ ocp->ddir = DMA_FROM_DEVICE;
+ break;
+ case EFCT_SCSI_CMD_DIR_IN | EFCT_SCSI_CMD_DIR_OUT:
+ ddir = "BIDIR";
+ ocp->ddir = DMA_BIDIRECTIONAL;
+ break;
+ default:
+ ddir = "NONE";
+ ocp->ddir = DMA_NONE;
+ break;
+ }
+
+ ocp->lun = lun;
+ efct_lio_io_printf(io, "new cmd=0x%x ddir=%s dl=%u\n",
+ cdb[0], ddir, io->exp_xfer_len);
+
+ tgt_node = io->node;
+ se_sess = tgt_node->session;
+ if (!se_sess) {
+ efc_log_err(efct, "No session found to submit IO se_cmd: %p\n",
+ &ocp->cmd);
+ efct_scsi_io_free(io);
+ return;
+ }
+
+ efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_SUBMIT_CMD);
+ rc = target_init_cmd(se_cmd, se_sess, &io->tgt_io.sense_buffer[0],
+ ocp->lun, io->exp_xfer_len, ocp->task_attr,
+ ocp->ddir, TARGET_SCF_ACK_KREF);
+ if (rc) {
+ efc_log_err(efct, "failed to init cmd se_cmd: %p\n", se_cmd);
+ efct_scsi_io_free(io);
+ return;
+ }
+
+ if (target_submit_prep(se_cmd, cdb, NULL, 0, NULL, 0,
+ NULL, 0, GFP_ATOMIC))
+ return;
+
+ target_submit(se_cmd);
+}
+
+int
+efct_scsi_recv_tmf(struct efct_io *tmfio, u32 lun, enum efct_scsi_tmf_cmd cmd,
+ struct efct_io *io_to_abort, u32 flags)
+{
+ unsigned char tmr_func;
+ struct efct *efct = tmfio->efct;
+ struct efct_scsi_tgt_io *ocp = &tmfio->tgt_io;
+ struct efct_node *tgt_node;
+ struct se_session *se_sess;
+ int rc;
+
+ memset(ocp, 0, sizeof(struct efct_scsi_tgt_io));
+ efct_set_lio_io_state(tmfio, EFCT_LIO_STATE_SCSI_RECV_TMF);
+ atomic_add_return(1, &efct->tgt_efct.ios_in_use);
+ efct_lio_tmfio_printf(tmfio, "%s: new tmf %x lun=%u\n",
+ tmfio->display_name, cmd, lun);
+
+ switch (cmd) {
+ case EFCT_SCSI_TMF_ABORT_TASK:
+ tmr_func = TMR_ABORT_TASK;
+ break;
+ case EFCT_SCSI_TMF_ABORT_TASK_SET:
+ tmr_func = TMR_ABORT_TASK_SET;
+ break;
+ case EFCT_SCSI_TMF_CLEAR_TASK_SET:
+ tmr_func = TMR_CLEAR_TASK_SET;
+ break;
+ case EFCT_SCSI_TMF_LOGICAL_UNIT_RESET:
+ tmr_func = TMR_LUN_RESET;
+ break;
+ case EFCT_SCSI_TMF_CLEAR_ACA:
+ tmr_func = TMR_CLEAR_ACA;
+ break;
+ case EFCT_SCSI_TMF_TARGET_RESET:
+ tmr_func = TMR_TARGET_WARM_RESET;
+ break;
+ case EFCT_SCSI_TMF_QUERY_ASYNCHRONOUS_EVENT:
+ case EFCT_SCSI_TMF_QUERY_TASK_SET:
+ default:
+ goto tmf_fail;
+ }
+
+ tmfio->tgt_io.tmf = tmr_func;
+ tmfio->tgt_io.lun = lun;
+ tmfio->tgt_io.io_to_abort = io_to_abort;
+
+ tgt_node = tmfio->node;
+
+ se_sess = tgt_node->session;
+ if (!se_sess)
+ return 0;
+
+ rc = target_submit_tmr(&ocp->cmd, se_sess, NULL, lun, ocp, tmr_func,
+ GFP_ATOMIC, tmfio->init_task_tag, TARGET_SCF_ACK_KREF);
+
+ efct_set_lio_io_state(tmfio, EFCT_LIO_STATE_TGT_SUBMIT_TMR);
+ if (rc)
+ goto tmf_fail;
+
+ return 0;
+
+tmf_fail:
+ efct_scsi_send_tmf_resp(tmfio, EFCT_SCSI_TMF_FUNCTION_REJECTED,
+ NULL, efct_lio_null_tmf_done, NULL);
+ return 0;
+}
+
+/* Start items for efct_lio_tpg_attrib_cit */
+
+#define DEF_EFCT_TPG_ATTRIB(name) \
+ \
+static ssize_t efct_lio_tpg_attrib_##name##_show( \
+ struct config_item *item, char *page) \
+{ \
+ struct se_portal_group *se_tpg = to_tpg(item); \
+ struct efct_lio_tpg *tpg = container_of(se_tpg, \
+ struct efct_lio_tpg, tpg); \
+ \
+ return sprintf(page, "%u\n", tpg->tpg_attrib.name); \
+} \
+ \
+static ssize_t efct_lio_tpg_attrib_##name##_store( \
+ struct config_item *item, const char *page, size_t count) \
+{ \
+ struct se_portal_group *se_tpg = to_tpg(item); \
+ struct efct_lio_tpg *tpg = container_of(se_tpg, \
+ struct efct_lio_tpg, tpg); \
+ struct efct_lio_tpg_attrib *a = &tpg->tpg_attrib; \
+ unsigned long val; \
+ int ret; \
+ \
+ ret = kstrtoul(page, 0, &val); \
+ if (ret < 0) { \
+ pr_err("kstrtoul() failed with ret: %d\n", ret); \
+ return ret; \
+ } \
+ \
+ if (val != 0 && val != 1) { \
+ pr_err("Illegal boolean value %lu\n", val); \
+ return -EINVAL; \
+ } \
+ \
+ a->name = val; \
+ \
+ return count; \
+} \
+CONFIGFS_ATTR(efct_lio_tpg_attrib_, name)
+
+DEF_EFCT_TPG_ATTRIB(generate_node_acls);
+DEF_EFCT_TPG_ATTRIB(cache_dynamic_acls);
+DEF_EFCT_TPG_ATTRIB(demo_mode_write_protect);
+DEF_EFCT_TPG_ATTRIB(prod_mode_write_protect);
+DEF_EFCT_TPG_ATTRIB(demo_mode_login_only);
+DEF_EFCT_TPG_ATTRIB(session_deletion_wait);
+
+static struct configfs_attribute *efct_lio_tpg_attrib_attrs[] = {
+ &efct_lio_tpg_attrib_attr_generate_node_acls,
+ &efct_lio_tpg_attrib_attr_cache_dynamic_acls,
+ &efct_lio_tpg_attrib_attr_demo_mode_write_protect,
+ &efct_lio_tpg_attrib_attr_prod_mode_write_protect,
+ &efct_lio_tpg_attrib_attr_demo_mode_login_only,
+ &efct_lio_tpg_attrib_attr_session_deletion_wait,
+ NULL,
+};
+
+#define DEF_EFCT_NPIV_TPG_ATTRIB(name) \
+ \
+static ssize_t efct_lio_npiv_tpg_attrib_##name##_show( \
+ struct config_item *item, char *page) \
+{ \
+ struct se_portal_group *se_tpg = to_tpg(item); \
+ struct efct_lio_tpg *tpg = container_of(se_tpg, \
+ struct efct_lio_tpg, tpg); \
+ \
+ return sprintf(page, "%u\n", tpg->tpg_attrib.name); \
+} \
+ \
+static ssize_t efct_lio_npiv_tpg_attrib_##name##_store( \
+ struct config_item *item, const char *page, size_t count) \
+{ \
+ struct se_portal_group *se_tpg = to_tpg(item); \
+ struct efct_lio_tpg *tpg = container_of(se_tpg, \
+ struct efct_lio_tpg, tpg); \
+ struct efct_lio_tpg_attrib *a = &tpg->tpg_attrib; \
+ unsigned long val; \
+ int ret; \
+ \
+ ret = kstrtoul(page, 0, &val); \
+ if (ret < 0) { \
+ pr_err("kstrtoul() failed with ret: %d\n", ret); \
+ return ret; \
+ } \
+ \
+ if (val != 0 && val != 1) { \
+ pr_err("Illegal boolean value %lu\n", val); \
+ return -EINVAL; \
+ } \
+ \
+ a->name = val; \
+ \
+ return count; \
+} \
+CONFIGFS_ATTR(efct_lio_npiv_tpg_attrib_, name)
+
+DEF_EFCT_NPIV_TPG_ATTRIB(generate_node_acls);
+DEF_EFCT_NPIV_TPG_ATTRIB(cache_dynamic_acls);
+DEF_EFCT_NPIV_TPG_ATTRIB(demo_mode_write_protect);
+DEF_EFCT_NPIV_TPG_ATTRIB(prod_mode_write_protect);
+DEF_EFCT_NPIV_TPG_ATTRIB(demo_mode_login_only);
+DEF_EFCT_NPIV_TPG_ATTRIB(session_deletion_wait);
+
+static struct configfs_attribute *efct_lio_npiv_tpg_attrib_attrs[] = {
+ &efct_lio_npiv_tpg_attrib_attr_generate_node_acls,
+ &efct_lio_npiv_tpg_attrib_attr_cache_dynamic_acls,
+ &efct_lio_npiv_tpg_attrib_attr_demo_mode_write_protect,
+ &efct_lio_npiv_tpg_attrib_attr_prod_mode_write_protect,
+ &efct_lio_npiv_tpg_attrib_attr_demo_mode_login_only,
+ &efct_lio_npiv_tpg_attrib_attr_session_deletion_wait,
+ NULL,
+};
+
+CONFIGFS_ATTR(efct_lio_tpg_, enable);
+static struct configfs_attribute *efct_lio_tpg_attrs[] = {
+ &efct_lio_tpg_attr_enable, NULL };
+CONFIGFS_ATTR(efct_lio_npiv_tpg_, enable);
+static struct configfs_attribute *efct_lio_npiv_tpg_attrs[] = {
+ &efct_lio_npiv_tpg_attr_enable, NULL };
+
+static const struct target_core_fabric_ops efct_lio_ops = {
+ .module = THIS_MODULE,
+ .fabric_name = "efct",
+ .node_acl_size = sizeof(struct efct_lio_nacl),
+ .max_data_sg_nents = 65535,
+ .tpg_get_wwn = efct_lio_get_fabric_wwn,
+ .tpg_get_tag = efct_lio_get_tag,
+ .fabric_init_nodeacl = efct_lio_init_nodeacl,
+ .tpg_check_demo_mode = efct_lio_check_demo_mode,
+ .tpg_check_demo_mode_cache = efct_lio_check_demo_mode_cache,
+ .tpg_check_demo_mode_write_protect = efct_lio_check_demo_write_protect,
+ .tpg_check_prod_mode_write_protect = efct_lio_check_prod_write_protect,
+ .tpg_get_inst_index = efct_lio_tpg_get_inst_index,
+ .check_stop_free = efct_lio_check_stop_free,
+ .aborted_task = efct_lio_aborted_task,
+ .release_cmd = efct_lio_release_cmd,
+ .close_session = efct_lio_close_session,
+ .sess_get_index = efct_lio_sess_get_index,
+ .write_pending = efct_lio_write_pending,
+ .set_default_node_attributes = efct_lio_set_default_node_attrs,
+ .get_cmd_state = efct_lio_get_cmd_state,
+ .queue_data_in = efct_lio_queue_data_in,
+ .queue_status = efct_lio_queue_status,
+ .queue_tm_rsp = efct_lio_queue_tm_rsp,
+ .fabric_make_wwn = efct_lio_make_nport,
+ .fabric_drop_wwn = efct_lio_drop_nport,
+ .fabric_make_tpg = efct_lio_make_tpg,
+ .fabric_drop_tpg = efct_lio_drop_tpg,
+ .tpg_check_demo_mode_login_only = efct_lio_check_demo_mode_login_only,
+ .tpg_check_prot_fabric_only = NULL,
+ .sess_get_initiator_sid = NULL,
+ .tfc_tpg_base_attrs = efct_lio_tpg_attrs,
+ .tfc_tpg_attrib_attrs = efct_lio_tpg_attrib_attrs,
+};
+
+static const struct target_core_fabric_ops efct_lio_npiv_ops = {
+ .module = THIS_MODULE,
+ .fabric_name = "efct_npiv",
+ .node_acl_size = sizeof(struct efct_lio_nacl),
+ .max_data_sg_nents = 65535,
+ .tpg_get_wwn = efct_lio_get_npiv_fabric_wwn,
+ .tpg_get_tag = efct_lio_get_npiv_tag,
+ .fabric_init_nodeacl = efct_lio_init_nodeacl,
+ .tpg_check_demo_mode = efct_lio_check_demo_mode,
+ .tpg_check_demo_mode_cache = efct_lio_check_demo_mode_cache,
+ .tpg_check_demo_mode_write_protect =
+ efct_lio_npiv_check_demo_write_protect,
+ .tpg_check_prod_mode_write_protect =
+ efct_lio_npiv_check_prod_write_protect,
+ .tpg_get_inst_index = efct_lio_tpg_get_inst_index,
+ .check_stop_free = efct_lio_check_stop_free,
+ .aborted_task = efct_lio_aborted_task,
+ .release_cmd = efct_lio_release_cmd,
+ .close_session = efct_lio_close_session,
+ .sess_get_index = efct_lio_sess_get_index,
+ .write_pending = efct_lio_write_pending,
+ .set_default_node_attributes = efct_lio_set_default_node_attrs,
+ .get_cmd_state = efct_lio_get_cmd_state,
+ .queue_data_in = efct_lio_queue_data_in,
+ .queue_status = efct_lio_queue_status,
+ .queue_tm_rsp = efct_lio_queue_tm_rsp,
+ .fabric_make_wwn = efct_lio_npiv_make_nport,
+ .fabric_drop_wwn = efct_lio_npiv_drop_nport,
+ .fabric_make_tpg = efct_lio_npiv_make_tpg,
+ .fabric_drop_tpg = efct_lio_npiv_drop_tpg,
+ .tpg_check_demo_mode_login_only =
+ efct_lio_npiv_check_demo_mode_login_only,
+ .tpg_check_prot_fabric_only = NULL,
+ .sess_get_initiator_sid = NULL,
+ .tfc_tpg_base_attrs = efct_lio_npiv_tpg_attrs,
+ .tfc_tpg_attrib_attrs = efct_lio_npiv_tpg_attrib_attrs,
+};
+
+int efct_scsi_tgt_driver_init(void)
+{
+ int rc;
+
+ /* Register the top level struct config_item_type with TCM core */
+ rc = target_register_template(&efct_lio_ops);
+ if (rc < 0) {
+ pr_err("target_fabric_configfs_register failed with %d\n", rc);
+ return rc;
+ }
+ rc = target_register_template(&efct_lio_npiv_ops);
+ if (rc < 0) {
+ pr_err("target_fabric_configfs_register failed with %d\n", rc);
+ target_unregister_template(&efct_lio_ops);
+ return rc;
+ }
+ return 0;
+}
+
+int efct_scsi_tgt_driver_exit(void)
+{
+ target_unregister_template(&efct_lio_ops);
+ target_unregister_template(&efct_lio_npiv_ops);
+ return 0;
+}
diff --git a/drivers/scsi/elx/efct/efct_lio.h b/drivers/scsi/elx/efct/efct_lio.h
new file mode 100644
index 000000000000..569a0d4b1894
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_lio.h
@@ -0,0 +1,189 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#ifndef __EFCT_LIO_H__
+#define __EFCT_LIO_H__
+
+#include "efct_scsi.h"
+#include <target/target_core_base.h>
+
+#define efct_lio_io_printf(io, fmt, ...) \
+ efc_log_debug(io->efct, \
+ "[%s] [%04x][i:%04x t:%04x h:%04x]" fmt,\
+ io->node->display_name, io->instance_index, \
+ io->init_task_tag, io->tgt_task_tag, io->hw_tag,\
+ ##__VA_ARGS__)
+
+#define efct_lio_tmfio_printf(io, fmt, ...) \
+ efc_log_debug(io->efct, \
+ "[%s] [%04x][i:%04x t:%04x h:%04x][f:%02x]" fmt,\
+ io->node->display_name, io->instance_index, \
+ io->init_task_tag, io->tgt_task_tag, io->hw_tag,\
+ io->tgt_io.tmf, ##__VA_ARGS__)
+
+#define efct_set_lio_io_state(io, value) (io->tgt_io.state |= value)
+
+struct efct_lio_wq_data {
+ struct efct *efct;
+ void *ptr;
+ struct work_struct work;
+};
+
+/* Target private efct structure */
+struct efct_scsi_tgt {
+ u32 max_sge;
+ u32 max_sgl;
+
+ /*
+ * Variables used to send task set full. We are using a high watermark
+ * method to send task set full. We will reserve a fixed number of IOs
+ * per initiator plus a fudge factor. Once we reach this number,
+ * then the target will start sending task set full/busy responses.
+ */
+ atomic_t initiator_count;
+ atomic_t ios_in_use;
+ atomic_t io_high_watermark;
+
+ atomic_t watermark_hit;
+ int watermark_min;
+ int watermark_max;
+
+ struct efct_lio_nport *lio_nport;
+ struct efct_lio_tpg *tpg;
+
+ struct list_head vport_list;
+ /* Protects vport list*/
+ spinlock_t efct_lio_lock;
+
+ u64 wwnn;
+};
+
+struct efct_scsi_tgt_nport {
+ struct efct_lio_nport *lio_nport;
+};
+
+struct efct_node {
+ struct list_head list_entry;
+ struct kref ref;
+ void (*release)(struct kref *arg);
+ struct efct *efct;
+ struct efc_node *node;
+ struct se_session *session;
+ spinlock_t active_ios_lock;
+ struct list_head active_ios;
+ char display_name[EFC_NAME_LENGTH];
+ u32 port_fc_id;
+ u32 node_fc_id;
+ u32 vpi;
+ u32 rpi;
+ u32 abort_cnt;
+};
+
+#define EFCT_LIO_STATE_SCSI_RECV_CMD (1 << 0)
+#define EFCT_LIO_STATE_TGT_SUBMIT_CMD (1 << 1)
+#define EFCT_LIO_STATE_TFO_QUEUE_DATA_IN (1 << 2)
+#define EFCT_LIO_STATE_TFO_WRITE_PENDING (1 << 3)
+#define EFCT_LIO_STATE_TGT_EXECUTE_CMD (1 << 4)
+#define EFCT_LIO_STATE_SCSI_SEND_RD_DATA (1 << 5)
+#define EFCT_LIO_STATE_TFO_CHK_STOP_FREE (1 << 6)
+#define EFCT_LIO_STATE_SCSI_DATA_DONE (1 << 7)
+#define EFCT_LIO_STATE_TFO_QUEUE_STATUS (1 << 8)
+#define EFCT_LIO_STATE_SCSI_SEND_RSP (1 << 9)
+#define EFCT_LIO_STATE_SCSI_RSP_DONE (1 << 10)
+#define EFCT_LIO_STATE_TGT_GENERIC_FREE (1 << 11)
+#define EFCT_LIO_STATE_SCSI_RECV_TMF (1 << 12)
+#define EFCT_LIO_STATE_TGT_SUBMIT_TMR (1 << 13)
+#define EFCT_LIO_STATE_TFO_WRITE_PEND_STATUS (1 << 14)
+#define EFCT_LIO_STATE_TGT_GENERIC_REQ_FAILURE (1 << 15)
+
+#define EFCT_LIO_STATE_TFO_ABORTED_TASK (1 << 29)
+#define EFCT_LIO_STATE_TFO_RELEASE_CMD (1 << 30)
+#define EFCT_LIO_STATE_SCSI_CMPL_CMD (1u << 31)
+
+struct efct_scsi_tgt_io {
+ struct se_cmd cmd;
+ unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER];
+ enum dma_data_direction ddir;
+ int task_attr;
+ u64 lun;
+
+ u32 state;
+ u8 tmf;
+ struct efct_io *io_to_abort;
+ u32 seg_map_cnt;
+ u32 seg_cnt;
+ u32 cur_seg;
+ enum efct_scsi_io_status err;
+ bool aborting;
+ bool rsp_sent;
+ u32 transferred_len;
+};
+
+/* Handler return codes */
+enum {
+ SCSI_HANDLER_DATAPHASE_STARTED = 1,
+ SCSI_HANDLER_RESP_STARTED,
+ SCSI_HANDLER_VALIDATED_DATAPHASE_STARTED,
+ SCSI_CMD_NOT_SUPPORTED,
+};
+
+#define WWN_NAME_LEN 32
+struct efct_lio_vport {
+ u64 wwpn;
+ u64 npiv_wwpn;
+ u64 npiv_wwnn;
+ unsigned char wwpn_str[WWN_NAME_LEN];
+ struct se_wwn vport_wwn;
+ struct efct_lio_tpg *tpg;
+ struct efct *efct;
+ struct Scsi_Host *shost;
+ struct fc_vport *fc_vport;
+ atomic_t enable;
+};
+
+struct efct_lio_nport {
+ u64 wwpn;
+ unsigned char wwpn_str[WWN_NAME_LEN];
+ struct se_wwn nport_wwn;
+ struct efct_lio_tpg *tpg;
+ struct efct *efct;
+ atomic_t enable;
+};
+
+struct efct_lio_tpg_attrib {
+ u32 generate_node_acls;
+ u32 cache_dynamic_acls;
+ u32 demo_mode_write_protect;
+ u32 prod_mode_write_protect;
+ u32 demo_mode_login_only;
+ bool session_deletion_wait;
+};
+
+struct efct_lio_tpg {
+ struct se_portal_group tpg;
+ struct efct_lio_nport *nport;
+ struct efct_lio_vport *vport;
+ struct efct_lio_tpg_attrib tpg_attrib;
+ unsigned short tpgt;
+ bool enabled;
+};
+
+struct efct_lio_nacl {
+ u64 nport_wwnn;
+ char nport_name[WWN_NAME_LEN];
+ struct se_session *session;
+ struct se_node_acl se_node_acl;
+};
+
+struct efct_lio_vport_list_t {
+ struct list_head list_entry;
+ struct efct_lio_vport *lio_vport;
+};
+
+int efct_scsi_tgt_driver_init(void);
+int efct_scsi_tgt_driver_exit(void);
+
+#endif /*__EFCT_LIO_H__ */
diff --git a/drivers/scsi/elx/efct/efct_scsi.c b/drivers/scsi/elx/efct/efct_scsi.c
new file mode 100644
index 000000000000..40fb3a724c76
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_scsi.c
@@ -0,0 +1,1159 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#include "efct_driver.h"
+#include "efct_hw.h"
+
+#define enable_tsend_auto_resp(efct) 1
+#define enable_treceive_auto_resp(efct) 0
+
+#define SCSI_IOFMT "[%04x][i:%04x t:%04x h:%04x]"
+
+#define scsi_io_printf(io, fmt, ...) \
+ efc_log_debug(io->efct, "[%s]" SCSI_IOFMT fmt, \
+ io->node->display_name, io->instance_index,\
+ io->init_task_tag, io->tgt_task_tag, io->hw_tag, ##__VA_ARGS__)
+
+#define EFCT_LOG_ENABLE_SCSI_TRACE(efct) \
+ (((efct) != NULL) ? (((efct)->logmask & (1U << 2)) != 0) : 0)
+
+#define scsi_io_trace(io, fmt, ...) \
+ do { \
+ if (EFCT_LOG_ENABLE_SCSI_TRACE(io->efct)) \
+ scsi_io_printf(io, fmt, ##__VA_ARGS__); \
+ } while (0)
+
+struct efct_io *
+efct_scsi_io_alloc(struct efct_node *node)
+{
+ struct efct *efct;
+ struct efct_xport *xport;
+ struct efct_io *io;
+ unsigned long flags = 0;
+
+ efct = node->efct;
+
+ xport = efct->xport;
+
+ spin_lock_irqsave(&node->active_ios_lock, flags);
+
+ io = efct_io_pool_io_alloc(efct->xport->io_pool);
+ if (!io) {
+ efc_log_err(efct, "IO alloc Failed\n");
+ atomic_add_return(1, &xport->io_alloc_failed_count);
+ spin_unlock_irqrestore(&node->active_ios_lock, flags);
+ return NULL;
+ }
+
+ /* initialize refcount */
+ kref_init(&io->ref);
+ io->release = _efct_scsi_io_free;
+
+ /* set generic fields */
+ io->efct = efct;
+ io->node = node;
+ kref_get(&node->ref);
+
+ /* set type and name */
+ io->io_type = EFCT_IO_TYPE_IO;
+ io->display_name = "scsi_io";
+
+ io->cmd_ini = false;
+ io->cmd_tgt = true;
+
+ /* Add to node's active_ios list */
+ INIT_LIST_HEAD(&io->list_entry);
+ list_add(&io->list_entry, &node->active_ios);
+
+ spin_unlock_irqrestore(&node->active_ios_lock, flags);
+
+ return io;
+}
+
+void
+_efct_scsi_io_free(struct kref *arg)
+{
+ struct efct_io *io = container_of(arg, struct efct_io, ref);
+ struct efct *efct = io->efct;
+ struct efct_node *node = io->node;
+ unsigned long flags = 0;
+
+ scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
+
+ if (io->io_free) {
+ efc_log_err(efct, "IO already freed.\n");
+ return;
+ }
+
+ spin_lock_irqsave(&node->active_ios_lock, flags);
+ list_del_init(&io->list_entry);
+ spin_unlock_irqrestore(&node->active_ios_lock, flags);
+
+ kref_put(&node->ref, node->release);
+ io->node = NULL;
+ efct_io_pool_io_free(efct->xport->io_pool, io);
+}
+
+void
+efct_scsi_io_free(struct efct_io *io)
+{
+ scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
+ WARN_ON(!refcount_read(&io->ref.refcount));
+ kref_put(&io->ref, io->release);
+}
+
+static void
+efct_target_io_cb(struct efct_hw_io *hio, u32 length, int status,
+ u32 ext_status, void *app)
+{
+ u32 flags = 0;
+ struct efct_io *io = app;
+ struct efct *efct;
+ enum efct_scsi_io_status scsi_stat = EFCT_SCSI_STATUS_GOOD;
+ efct_scsi_io_cb_t cb;
+
+ if (!io || !io->efct) {
+ pr_err("%s: IO can not be NULL\n", __func__);
+ return;
+ }
+
+ scsi_io_trace(io, "status x%x ext_status x%x\n", status, ext_status);
+
+ efct = io->efct;
+
+ io->transferred += length;
+
+ if (!io->scsi_tgt_cb) {
+ efct_scsi_check_pending(efct);
+ return;
+ }
+
+ /* Call target server completion */
+ cb = io->scsi_tgt_cb;
+
+ /* Clear the callback before invoking the callback */
+ io->scsi_tgt_cb = NULL;
+
+ /* if status was good, and auto-good-response was set,
+ * then callback target-server with IO_CMPL_RSP_SENT,
+ * otherwise send IO_CMPL
+ */
+ if (status == 0 && io->auto_resp)
+ flags |= EFCT_SCSI_IO_CMPL_RSP_SENT;
+ else
+ flags |= EFCT_SCSI_IO_CMPL;
+
+ switch (status) {
+ case SLI4_FC_WCQE_STATUS_SUCCESS:
+ scsi_stat = EFCT_SCSI_STATUS_GOOD;
+ break;
+ case SLI4_FC_WCQE_STATUS_DI_ERROR:
+ if (ext_status & SLI4_FC_DI_ERROR_GE)
+ scsi_stat = EFCT_SCSI_STATUS_DIF_GUARD_ERR;
+ else if (ext_status & SLI4_FC_DI_ERROR_AE)
+ scsi_stat = EFCT_SCSI_STATUS_DIF_APP_TAG_ERROR;
+ else if (ext_status & SLI4_FC_DI_ERROR_RE)
+ scsi_stat = EFCT_SCSI_STATUS_DIF_REF_TAG_ERROR;
+ else
+ scsi_stat = EFCT_SCSI_STATUS_DIF_UNKNOWN_ERROR;
+ break;
+ case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
+ switch (ext_status) {
+ case SLI4_FC_LOCAL_REJECT_INVALID_RELOFFSET:
+ case SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED:
+ scsi_stat = EFCT_SCSI_STATUS_ABORTED;
+ break;
+ case SLI4_FC_LOCAL_REJECT_INVALID_RPI:
+ scsi_stat = EFCT_SCSI_STATUS_NEXUS_LOST;
+ break;
+ case SLI4_FC_LOCAL_REJECT_NO_XRI:
+ scsi_stat = EFCT_SCSI_STATUS_NO_IO;
+ break;
+ default:
+ /*we have seen 0x0d(TX_DMA_FAILED err)*/
+ scsi_stat = EFCT_SCSI_STATUS_ERROR;
+ break;
+ }
+ break;
+
+ case SLI4_FC_WCQE_STATUS_TARGET_WQE_TIMEOUT:
+ /* target IO timed out */
+ scsi_stat = EFCT_SCSI_STATUS_TIMEDOUT_AND_ABORTED;
+ break;
+
+ case SLI4_FC_WCQE_STATUS_SHUTDOWN:
+ /* Target IO cancelled by HW */
+ scsi_stat = EFCT_SCSI_STATUS_SHUTDOWN;
+ break;
+
+ default:
+ scsi_stat = EFCT_SCSI_STATUS_ERROR;
+ break;
+ }
+
+ cb(io, scsi_stat, flags, io->scsi_tgt_cb_arg);
+
+ efct_scsi_check_pending(efct);
+}
+
+static int
+efct_scsi_build_sgls(struct efct_hw *hw, struct efct_hw_io *hio,
+ struct efct_scsi_sgl *sgl, u32 sgl_count,
+ enum efct_hw_io_type type)
+{
+ int rc;
+ u32 i;
+ struct efct *efct = hw->os;
+
+ /* Initialize HW SGL */
+ rc = efct_hw_io_init_sges(hw, hio, type);
+ if (rc) {
+ efc_log_err(efct, "efct_hw_io_init_sges failed: %d\n", rc);
+ return -EIO;
+ }
+
+ for (i = 0; i < sgl_count; i++) {
+ /* Add data SGE */
+ rc = efct_hw_io_add_sge(hw, hio, sgl[i].addr, sgl[i].len);
+ if (rc) {
+ efc_log_err(efct, "add sge failed cnt=%d rc=%d\n",
+ sgl_count, rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static void efc_log_sgl(struct efct_io *io)
+{
+ struct efct_hw_io *hio = io->hio;
+ struct sli4_sge *data = NULL;
+ u32 *dword = NULL;
+ u32 i;
+ u32 n_sge;
+
+ scsi_io_trace(io, "def_sgl at 0x%x 0x%08x\n",
+ upper_32_bits(hio->def_sgl.phys),
+ lower_32_bits(hio->def_sgl.phys));
+ n_sge = (hio->sgl == &hio->def_sgl) ? hio->n_sge : hio->def_sgl_count;
+ for (i = 0, data = hio->def_sgl.virt; i < n_sge; i++, data++) {
+ dword = (u32 *)data;
+
+ scsi_io_trace(io, "SGL %2d 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ i, dword[0], dword[1], dword[2], dword[3]);
+
+ if (dword[2] & (1U << 31))
+ break;
+ }
+}
+
+static void
+efct_scsi_check_pending_async_cb(struct efct_hw *hw, int status,
+ u8 *mqe, void *arg)
+{
+ struct efct_io *io = arg;
+
+ if (io) {
+ efct_hw_done_t cb = io->hw_cb;
+
+ if (!io->hw_cb)
+ return;
+
+ io->hw_cb = NULL;
+ (cb)(io->hio, 0, SLI4_FC_WCQE_STATUS_DISPATCH_ERROR, 0, io);
+ }
+}
+
+static int
+efct_scsi_io_dispatch_hw_io(struct efct_io *io, struct efct_hw_io *hio)
+{
+ int rc = 0;
+ struct efct *efct = io->efct;
+
+ /* Got a HW IO;
+ * update ini/tgt_task_tag with HW IO info and dispatch
+ */
+ io->hio = hio;
+ if (io->cmd_tgt)
+ io->tgt_task_tag = hio->indicator;
+ else if (io->cmd_ini)
+ io->init_task_tag = hio->indicator;
+ io->hw_tag = hio->reqtag;
+
+ hio->eq = io->hw_priv;
+
+ /* Copy WQ steering */
+ switch (io->wq_steering) {
+ case EFCT_SCSI_WQ_STEERING_CLASS >> EFCT_SCSI_WQ_STEERING_SHIFT:
+ hio->wq_steering = EFCT_HW_WQ_STEERING_CLASS;
+ break;
+ case EFCT_SCSI_WQ_STEERING_REQUEST >> EFCT_SCSI_WQ_STEERING_SHIFT:
+ hio->wq_steering = EFCT_HW_WQ_STEERING_REQUEST;
+ break;
+ case EFCT_SCSI_WQ_STEERING_CPU >> EFCT_SCSI_WQ_STEERING_SHIFT:
+ hio->wq_steering = EFCT_HW_WQ_STEERING_CPU;
+ break;
+ }
+
+ switch (io->io_type) {
+ case EFCT_IO_TYPE_IO:
+ rc = efct_scsi_build_sgls(&efct->hw, io->hio,
+ io->sgl, io->sgl_count, io->hio_type);
+ if (rc)
+ break;
+
+ if (EFCT_LOG_ENABLE_SCSI_TRACE(efct))
+ efc_log_sgl(io);
+
+ if (io->app_id)
+ io->iparam.fcp_tgt.app_id = io->app_id;
+
+ io->iparam.fcp_tgt.vpi = io->node->vpi;
+ io->iparam.fcp_tgt.rpi = io->node->rpi;
+ io->iparam.fcp_tgt.s_id = io->node->port_fc_id;
+ io->iparam.fcp_tgt.d_id = io->node->node_fc_id;
+ io->iparam.fcp_tgt.xmit_len = io->wire_len;
+
+ rc = efct_hw_io_send(&io->efct->hw, io->hio_type, io->hio,
+ &io->iparam, io->hw_cb, io);
+ break;
+ default:
+ scsi_io_printf(io, "Unknown IO type=%d\n", io->io_type);
+ rc = -EIO;
+ break;
+ }
+ return rc;
+}
+
+static int
+efct_scsi_io_dispatch_no_hw_io(struct efct_io *io)
+{
+ int rc;
+
+ switch (io->io_type) {
+ case EFCT_IO_TYPE_ABORT: {
+ struct efct_hw_io *hio_to_abort = NULL;
+
+ hio_to_abort = io->io_to_abort->hio;
+
+ if (!hio_to_abort) {
+ /*
+ * If "IO to abort" does not have an
+ * associated HW IO, immediately make callback with
+ * success. The command must have been sent to
+ * the backend, but the data phase has not yet
+ * started, so we don't have a HW IO.
+ *
+ * Note: since the backend shims should be
+ * taking a reference on io_to_abort, it should not
+ * be possible to have been completed and freed by
+ * the backend before the abort got here.
+ */
+ scsi_io_printf(io, "IO: not active\n");
+ ((efct_hw_done_t)io->hw_cb)(io->hio, 0,
+ SLI4_FC_WCQE_STATUS_SUCCESS, 0, io);
+ rc = 0;
+ break;
+ }
+
+ /* HW IO is valid, abort it */
+ scsi_io_printf(io, "aborting\n");
+ rc = efct_hw_io_abort(&io->efct->hw, hio_to_abort,
+ io->send_abts, io->hw_cb, io);
+ if (rc) {
+ int status = SLI4_FC_WCQE_STATUS_SUCCESS;
+ efct_hw_done_t cb = io->hw_cb;
+
+ if (rc != -ENOENT && rc != -EINPROGRESS) {
+ status = -1;
+ scsi_io_printf(io, "Failed to abort IO rc=%d\n",
+ rc);
+ }
+ cb(io->hio, 0, status, 0, io);
+ rc = 0;
+ }
+
+ break;
+ }
+ default:
+ scsi_io_printf(io, "Unknown IO type=%d\n", io->io_type);
+ rc = -EIO;
+ break;
+ }
+ return rc;
+}
+
+static struct efct_io *
+efct_scsi_dispatch_pending(struct efct *efct)
+{
+ struct efct_xport *xport = efct->xport;
+ struct efct_io *io = NULL;
+ struct efct_hw_io *hio;
+ unsigned long flags = 0;
+ int status;
+
+ spin_lock_irqsave(&xport->io_pending_lock, flags);
+
+ if (!list_empty(&xport->io_pending_list)) {
+ io = list_first_entry(&xport->io_pending_list, struct efct_io,
+ io_pending_link);
+ list_del_init(&io->io_pending_link);
+ }
+
+ if (!io) {
+ spin_unlock_irqrestore(&xport->io_pending_lock, flags);
+ return NULL;
+ }
+
+ if (io->io_type == EFCT_IO_TYPE_ABORT) {
+ hio = NULL;
+ } else {
+ hio = efct_hw_io_alloc(&efct->hw);
+ if (!hio) {
+ /*
+ * No HW IO available.Put IO back on
+ * the front of pending list
+ */
+ list_add(&xport->io_pending_list, &io->io_pending_link);
+ io = NULL;
+ } else {
+ hio->eq = io->hw_priv;
+ }
+ }
+
+ /* Must drop the lock before dispatching the IO */
+ spin_unlock_irqrestore(&xport->io_pending_lock, flags);
+
+ if (!io)
+ return NULL;
+
+ /*
+ * We pulled an IO off the pending list,
+ * and either got an HW IO or don't need one
+ */
+ atomic_sub_return(1, &xport->io_pending_count);
+ if (!hio)
+ status = efct_scsi_io_dispatch_no_hw_io(io);
+ else
+ status = efct_scsi_io_dispatch_hw_io(io, hio);
+ if (status) {
+ /*
+ * Invoke the HW callback, but do so in the
+ * separate execution context,provided by the
+ * NOP mailbox completion processing context
+ * by using efct_hw_async_call()
+ */
+ if (efct_hw_async_call(&efct->hw,
+ efct_scsi_check_pending_async_cb, io)) {
+ efc_log_debug(efct, "call hw async failed\n");
+ }
+ }
+
+ return io;
+}
+
+void
+efct_scsi_check_pending(struct efct *efct)
+{
+ struct efct_xport *xport = efct->xport;
+ struct efct_io *io = NULL;
+ int count = 0;
+ unsigned long flags = 0;
+ int dispatch = 0;
+
+ /* Guard against recursion */
+ if (atomic_add_return(1, &xport->io_pending_recursing)) {
+ /* This function is already running. Decrement and return. */
+ atomic_sub_return(1, &xport->io_pending_recursing);
+ return;
+ }
+
+ while (efct_scsi_dispatch_pending(efct))
+ count++;
+
+ if (count) {
+ atomic_sub_return(1, &xport->io_pending_recursing);
+ return;
+ }
+
+ /*
+ * If nothing was removed from the list,
+ * we might be in a case where we need to abort an
+ * active IO and the abort is on the pending list.
+ * Look for an abort we can dispatch.
+ */
+
+ spin_lock_irqsave(&xport->io_pending_lock, flags);
+
+ list_for_each_entry(io, &xport->io_pending_list, io_pending_link) {
+ if (io->io_type == EFCT_IO_TYPE_ABORT && io->io_to_abort->hio) {
+ /* This IO has a HW IO, so it is
+ * active. Dispatch the abort.
+ */
+ dispatch = 1;
+ list_del_init(&io->io_pending_link);
+ atomic_sub_return(1, &xport->io_pending_count);
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&xport->io_pending_lock, flags);
+
+ if (dispatch) {
+ if (efct_scsi_io_dispatch_no_hw_io(io)) {
+ if (efct_hw_async_call(&efct->hw,
+ efct_scsi_check_pending_async_cb, io)) {
+ efc_log_debug(efct, "hw async failed\n");
+ }
+ }
+ }
+
+ atomic_sub_return(1, &xport->io_pending_recursing);
+}
+
+int
+efct_scsi_io_dispatch(struct efct_io *io, void *cb)
+{
+ struct efct_hw_io *hio;
+ struct efct *efct = io->efct;
+ struct efct_xport *xport = efct->xport;
+ unsigned long flags = 0;
+
+ io->hw_cb = cb;
+
+ /*
+ * if this IO already has a HW IO, then this is either
+ * not the first phase of the IO. Send it to the HW.
+ */
+ if (io->hio)
+ return efct_scsi_io_dispatch_hw_io(io, io->hio);
+
+ /*
+ * We don't already have a HW IO associated with the IO. First check
+ * the pending list. If not empty, add IO to the tail and process the
+ * pending list.
+ */
+ spin_lock_irqsave(&xport->io_pending_lock, flags);
+ if (!list_empty(&xport->io_pending_list)) {
+ /*
+ * If this is a low latency request,
+ * the put at the front of the IO pending
+ * queue, otherwise put it at the end of the queue.
+ */
+ if (io->low_latency) {
+ INIT_LIST_HEAD(&io->io_pending_link);
+ list_add(&xport->io_pending_list, &io->io_pending_link);
+ } else {
+ INIT_LIST_HEAD(&io->io_pending_link);
+ list_add_tail(&io->io_pending_link,
+ &xport->io_pending_list);
+ }
+ spin_unlock_irqrestore(&xport->io_pending_lock, flags);
+ atomic_add_return(1, &xport->io_pending_count);
+ atomic_add_return(1, &xport->io_total_pending);
+
+ /* process pending list */
+ efct_scsi_check_pending(efct);
+ return 0;
+ }
+ spin_unlock_irqrestore(&xport->io_pending_lock, flags);
+
+ /*
+ * We don't have a HW IO associated with the IO and there's nothing
+ * on the pending list. Attempt to allocate a HW IO and dispatch it.
+ */
+ hio = efct_hw_io_alloc(&io->efct->hw);
+ if (!hio) {
+ /* Couldn't get a HW IO. Save this IO on the pending list */
+ spin_lock_irqsave(&xport->io_pending_lock, flags);
+ INIT_LIST_HEAD(&io->io_pending_link);
+ list_add_tail(&io->io_pending_link, &xport->io_pending_list);
+ spin_unlock_irqrestore(&xport->io_pending_lock, flags);
+
+ atomic_add_return(1, &xport->io_total_pending);
+ atomic_add_return(1, &xport->io_pending_count);
+ return 0;
+ }
+
+ /* We successfully allocated a HW IO; dispatch to HW */
+ return efct_scsi_io_dispatch_hw_io(io, hio);
+}
+
+int
+efct_scsi_io_dispatch_abort(struct efct_io *io, void *cb)
+{
+ struct efct *efct = io->efct;
+ struct efct_xport *xport = efct->xport;
+ unsigned long flags = 0;
+
+ io->hw_cb = cb;
+
+ /*
+ * For aborts, we don't need a HW IO, but we still want
+ * to pass through the pending list to preserve ordering.
+ * Thus, if the pending list is not empty, add this abort
+ * to the pending list and process the pending list.
+ */
+ spin_lock_irqsave(&xport->io_pending_lock, flags);
+ if (!list_empty(&xport->io_pending_list)) {
+ INIT_LIST_HEAD(&io->io_pending_link);
+ list_add_tail(&io->io_pending_link, &xport->io_pending_list);
+ spin_unlock_irqrestore(&xport->io_pending_lock, flags);
+ atomic_add_return(1, &xport->io_pending_count);
+ atomic_add_return(1, &xport->io_total_pending);
+
+ /* process pending list */
+ efct_scsi_check_pending(efct);
+ return 0;
+ }
+ spin_unlock_irqrestore(&xport->io_pending_lock, flags);
+
+ /* nothing on pending list, dispatch abort */
+ return efct_scsi_io_dispatch_no_hw_io(io);
+}
+
+static inline int
+efct_scsi_xfer_data(struct efct_io *io, u32 flags,
+ struct efct_scsi_sgl *sgl, u32 sgl_count, u64 xwire_len,
+ enum efct_hw_io_type type, int enable_ar,
+ efct_scsi_io_cb_t cb, void *arg)
+{
+ struct efct *efct;
+ size_t residual = 0;
+
+ io->sgl_count = sgl_count;
+
+ efct = io->efct;
+
+ scsi_io_trace(io, "%s wire_len %llu\n",
+ (type == EFCT_HW_IO_TARGET_READ) ? "send" : "recv",
+ xwire_len);
+
+ io->hio_type = type;
+
+ io->scsi_tgt_cb = cb;
+ io->scsi_tgt_cb_arg = arg;
+
+ residual = io->exp_xfer_len - io->transferred;
+ io->wire_len = (xwire_len < residual) ? xwire_len : residual;
+ residual = (xwire_len - io->wire_len);
+
+ memset(&io->iparam, 0, sizeof(io->iparam));
+ io->iparam.fcp_tgt.ox_id = io->init_task_tag;
+ io->iparam.fcp_tgt.offset = io->transferred;
+ io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
+ io->iparam.fcp_tgt.timeout = io->timeout;
+
+ /* if this is the last data phase and there is no residual, enable
+ * auto-good-response
+ */
+ if (enable_ar && (flags & EFCT_SCSI_LAST_DATAPHASE) && residual == 0 &&
+ ((io->transferred + io->wire_len) == io->exp_xfer_len) &&
+ (!(flags & EFCT_SCSI_NO_AUTO_RESPONSE))) {
+ io->iparam.fcp_tgt.flags |= SLI4_IO_AUTO_GOOD_RESPONSE;
+ io->auto_resp = true;
+ } else {
+ io->auto_resp = false;
+ }
+
+ /* save this transfer length */
+ io->xfer_req = io->wire_len;
+
+ /* Adjust the transferred count to account for overrun
+ * when the residual is calculated in efct_scsi_send_resp
+ */
+ io->transferred += residual;
+
+ /* Adjust the SGL size if there is overrun */
+
+ if (residual) {
+ struct efct_scsi_sgl *sgl_ptr = &io->sgl[sgl_count - 1];
+
+ while (residual) {
+ size_t len = sgl_ptr->len;
+
+ if (len > residual) {
+ sgl_ptr->len = len - residual;
+ residual = 0;
+ } else {
+ sgl_ptr->len = 0;
+ residual -= len;
+ io->sgl_count--;
+ }
+ sgl_ptr--;
+ }
+ }
+
+ /* Set latency and WQ steering */
+ io->low_latency = (flags & EFCT_SCSI_LOW_LATENCY) != 0;
+ io->wq_steering = (flags & EFCT_SCSI_WQ_STEERING_MASK) >>
+ EFCT_SCSI_WQ_STEERING_SHIFT;
+ io->wq_class = (flags & EFCT_SCSI_WQ_CLASS_MASK) >>
+ EFCT_SCSI_WQ_CLASS_SHIFT;
+
+ if (efct->xport) {
+ struct efct_xport *xport = efct->xport;
+
+ if (type == EFCT_HW_IO_TARGET_READ) {
+ xport->fcp_stats.input_requests++;
+ xport->fcp_stats.input_bytes += xwire_len;
+ } else if (type == EFCT_HW_IO_TARGET_WRITE) {
+ xport->fcp_stats.output_requests++;
+ xport->fcp_stats.output_bytes += xwire_len;
+ }
+ }
+ return efct_scsi_io_dispatch(io, efct_target_io_cb);
+}
+
+int
+efct_scsi_send_rd_data(struct efct_io *io, u32 flags,
+ struct efct_scsi_sgl *sgl, u32 sgl_count, u64 len,
+ efct_scsi_io_cb_t cb, void *arg)
+{
+ return efct_scsi_xfer_data(io, flags, sgl, sgl_count,
+ len, EFCT_HW_IO_TARGET_READ,
+ enable_tsend_auto_resp(io->efct), cb, arg);
+}
+
+int
+efct_scsi_recv_wr_data(struct efct_io *io, u32 flags,
+ struct efct_scsi_sgl *sgl, u32 sgl_count, u64 len,
+ efct_scsi_io_cb_t cb, void *arg)
+{
+ return efct_scsi_xfer_data(io, flags, sgl, sgl_count, len,
+ EFCT_HW_IO_TARGET_WRITE,
+ enable_treceive_auto_resp(io->efct), cb, arg);
+}
+
+int
+efct_scsi_send_resp(struct efct_io *io, u32 flags,
+ struct efct_scsi_cmd_resp *rsp,
+ efct_scsi_io_cb_t cb, void *arg)
+{
+ struct efct *efct;
+ int residual;
+ /* Always try auto resp */
+ bool auto_resp = true;
+ u8 scsi_status = 0;
+ u16 scsi_status_qualifier = 0;
+ u8 *sense_data = NULL;
+ u32 sense_data_length = 0;
+
+ efct = io->efct;
+
+ if (rsp) {
+ scsi_status = rsp->scsi_status;
+ scsi_status_qualifier = rsp->scsi_status_qualifier;
+ sense_data = rsp->sense_data;
+ sense_data_length = rsp->sense_data_length;
+ residual = rsp->residual;
+ } else {
+ residual = io->exp_xfer_len - io->transferred;
+ }
+
+ io->wire_len = 0;
+ io->hio_type = EFCT_HW_IO_TARGET_RSP;
+
+ io->scsi_tgt_cb = cb;
+ io->scsi_tgt_cb_arg = arg;
+
+ memset(&io->iparam, 0, sizeof(io->iparam));
+ io->iparam.fcp_tgt.ox_id = io->init_task_tag;
+ io->iparam.fcp_tgt.offset = 0;
+ io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
+ io->iparam.fcp_tgt.timeout = io->timeout;
+
+ /* Set low latency queueing request */
+ io->low_latency = (flags & EFCT_SCSI_LOW_LATENCY) != 0;
+ io->wq_steering = (flags & EFCT_SCSI_WQ_STEERING_MASK) >>
+ EFCT_SCSI_WQ_STEERING_SHIFT;
+ io->wq_class = (flags & EFCT_SCSI_WQ_CLASS_MASK) >>
+ EFCT_SCSI_WQ_CLASS_SHIFT;
+
+ if (scsi_status != 0 || residual || sense_data_length) {
+ struct fcp_resp_with_ext *fcprsp = io->rspbuf.virt;
+ u8 *sns_data;
+
+ if (!fcprsp) {
+ efc_log_err(efct, "NULL response buffer\n");
+ return -EIO;
+ }
+
+ sns_data = (u8 *)io->rspbuf.virt + sizeof(*fcprsp);
+
+ auto_resp = false;
+
+ memset(fcprsp, 0, sizeof(*fcprsp));
+
+ io->wire_len += sizeof(*fcprsp);
+
+ fcprsp->resp.fr_status = scsi_status;
+ fcprsp->resp.fr_retry_delay =
+ cpu_to_be16(scsi_status_qualifier);
+
+ /* set residual status if necessary */
+ if (residual != 0) {
+ /* FCP: if data transferred is less than the
+ * amount expected, then this is an underflow.
+ * If data transferred would have been greater
+ * than the amount expected this is an overflow
+ */
+ if (residual > 0) {
+ fcprsp->resp.fr_flags |= FCP_RESID_UNDER;
+ fcprsp->ext.fr_resid = cpu_to_be32(residual);
+ } else {
+ fcprsp->resp.fr_flags |= FCP_RESID_OVER;
+ fcprsp->ext.fr_resid = cpu_to_be32(-residual);
+ }
+ }
+
+ if (EFCT_SCSI_SNS_BUF_VALID(sense_data) && sense_data_length) {
+ if (sense_data_length > SCSI_SENSE_BUFFERSIZE) {
+ efc_log_err(efct, "Sense exceeds max size.\n");
+ return -EIO;
+ }
+
+ fcprsp->resp.fr_flags |= FCP_SNS_LEN_VAL;
+ memcpy(sns_data, sense_data, sense_data_length);
+ fcprsp->ext.fr_sns_len = cpu_to_be32(sense_data_length);
+ io->wire_len += sense_data_length;
+ }
+
+ io->sgl[0].addr = io->rspbuf.phys;
+ io->sgl[0].dif_addr = 0;
+ io->sgl[0].len = io->wire_len;
+ io->sgl_count = 1;
+ }
+
+ if (auto_resp)
+ io->iparam.fcp_tgt.flags |= SLI4_IO_AUTO_GOOD_RESPONSE;
+
+ return efct_scsi_io_dispatch(io, efct_target_io_cb);
+}
+
+static int
+efct_target_bls_resp_cb(struct efct_hw_io *hio, u32 length, int status,
+ u32 ext_status, void *app)
+{
+ struct efct_io *io = app;
+ struct efct *efct;
+ enum efct_scsi_io_status bls_status;
+
+ efct = io->efct;
+
+ /* BLS isn't really a "SCSI" concept, but use SCSI status */
+ if (status) {
+ io_error_log(io, "s=%#x x=%#x\n", status, ext_status);
+ bls_status = EFCT_SCSI_STATUS_ERROR;
+ } else {
+ bls_status = EFCT_SCSI_STATUS_GOOD;
+ }
+
+ if (io->bls_cb) {
+ efct_scsi_io_cb_t bls_cb = io->bls_cb;
+ void *bls_cb_arg = io->bls_cb_arg;
+
+ io->bls_cb = NULL;
+ io->bls_cb_arg = NULL;
+
+ /* invoke callback */
+ bls_cb(io, bls_status, 0, bls_cb_arg);
+ }
+
+ efct_scsi_check_pending(efct);
+ return 0;
+}
+
+static int
+efct_target_send_bls_resp(struct efct_io *io,
+ efct_scsi_io_cb_t cb, void *arg)
+{
+ struct efct_node *node = io->node;
+ struct sli_bls_params *bls = &io->iparam.bls;
+ struct efct *efct = node->efct;
+ struct fc_ba_acc *acc;
+ int rc;
+
+ /* fill out IO structure with everything needed to send BA_ACC */
+ memset(&io->iparam, 0, sizeof(io->iparam));
+ bls->ox_id = io->init_task_tag;
+ bls->rx_id = io->abort_rx_id;
+ bls->vpi = io->node->vpi;
+ bls->rpi = io->node->rpi;
+ bls->s_id = U32_MAX;
+ bls->d_id = io->node->node_fc_id;
+ bls->rpi_registered = true;
+
+ acc = (void *)bls->payload;
+ acc->ba_ox_id = cpu_to_be16(bls->ox_id);
+ acc->ba_rx_id = cpu_to_be16(bls->rx_id);
+ acc->ba_high_seq_cnt = cpu_to_be16(U16_MAX);
+
+ /* generic io fields have already been populated */
+
+ /* set type and BLS-specific fields */
+ io->io_type = EFCT_IO_TYPE_BLS_RESP;
+ io->display_name = "bls_rsp";
+ io->hio_type = EFCT_HW_BLS_ACC;
+ io->bls_cb = cb;
+ io->bls_cb_arg = arg;
+
+ /* dispatch IO */
+ rc = efct_hw_bls_send(efct, FC_RCTL_BA_ACC, bls,
+ efct_target_bls_resp_cb, io);
+ return rc;
+}
+
+static int efct_bls_send_rjt_cb(struct efct_hw_io *hio, u32 length, int status,
+ u32 ext_status, void *app)
+{
+ struct efct_io *io = app;
+
+ efct_scsi_io_free(io);
+ return 0;
+}
+
+struct efct_io *
+efct_bls_send_rjt(struct efct_io *io, struct fc_frame_header *hdr)
+{
+ struct efct_node *node = io->node;
+ struct sli_bls_params *bls = &io->iparam.bls;
+ struct efct *efct = node->efct;
+ struct fc_ba_rjt *acc;
+ int rc;
+
+ /* fill out BLS Response-specific fields */
+ io->io_type = EFCT_IO_TYPE_BLS_RESP;
+ io->display_name = "ba_rjt";
+ io->hio_type = EFCT_HW_BLS_RJT;
+ io->init_task_tag = be16_to_cpu(hdr->fh_ox_id);
+
+ /* fill out iparam fields */
+ memset(&io->iparam, 0, sizeof(io->iparam));
+ bls->ox_id = be16_to_cpu(hdr->fh_ox_id);
+ bls->rx_id = be16_to_cpu(hdr->fh_rx_id);
+ bls->vpi = io->node->vpi;
+ bls->rpi = io->node->rpi;
+ bls->s_id = U32_MAX;
+ bls->d_id = io->node->node_fc_id;
+ bls->rpi_registered = true;
+
+ acc = (void *)bls->payload;
+ acc->br_reason = ELS_RJT_UNAB;
+ acc->br_explan = ELS_EXPL_NONE;
+
+ rc = efct_hw_bls_send(efct, FC_RCTL_BA_RJT, bls, efct_bls_send_rjt_cb,
+ io);
+ if (rc) {
+ efc_log_err(efct, "efct_scsi_io_dispatch() failed: %d\n", rc);
+ efct_scsi_io_free(io);
+ io = NULL;
+ }
+ return io;
+}
+
+int
+efct_scsi_send_tmf_resp(struct efct_io *io,
+ enum efct_scsi_tmf_resp rspcode,
+ u8 addl_rsp_info[3],
+ efct_scsi_io_cb_t cb, void *arg)
+{
+ int rc;
+ struct {
+ struct fcp_resp_with_ext rsp_ext;
+ struct fcp_resp_rsp_info info;
+ } *fcprsp;
+ u8 fcp_rspcode;
+
+ io->wire_len = 0;
+
+ switch (rspcode) {
+ case EFCT_SCSI_TMF_FUNCTION_COMPLETE:
+ fcp_rspcode = FCP_TMF_CMPL;
+ break;
+ case EFCT_SCSI_TMF_FUNCTION_SUCCEEDED:
+ case EFCT_SCSI_TMF_FUNCTION_IO_NOT_FOUND:
+ fcp_rspcode = FCP_TMF_CMPL;
+ break;
+ case EFCT_SCSI_TMF_FUNCTION_REJECTED:
+ fcp_rspcode = FCP_TMF_REJECTED;
+ break;
+ case EFCT_SCSI_TMF_INCORRECT_LOGICAL_UNIT_NUMBER:
+ fcp_rspcode = FCP_TMF_INVALID_LUN;
+ break;
+ case EFCT_SCSI_TMF_SERVICE_DELIVERY:
+ fcp_rspcode = FCP_TMF_FAILED;
+ break;
+ default:
+ fcp_rspcode = FCP_TMF_REJECTED;
+ break;
+ }
+
+ io->hio_type = EFCT_HW_IO_TARGET_RSP;
+
+ io->scsi_tgt_cb = cb;
+ io->scsi_tgt_cb_arg = arg;
+
+ if (io->tmf_cmd == EFCT_SCSI_TMF_ABORT_TASK) {
+ rc = efct_target_send_bls_resp(io, cb, arg);
+ return rc;
+ }
+
+ /* populate the FCP TMF response */
+ fcprsp = io->rspbuf.virt;
+ memset(fcprsp, 0, sizeof(*fcprsp));
+
+ fcprsp->rsp_ext.resp.fr_flags |= FCP_SNS_LEN_VAL;
+
+ if (addl_rsp_info) {
+ memcpy(fcprsp->info._fr_resvd, addl_rsp_info,
+ sizeof(fcprsp->info._fr_resvd));
+ }
+ fcprsp->info.rsp_code = fcp_rspcode;
+
+ io->wire_len = sizeof(*fcprsp);
+
+ fcprsp->rsp_ext.ext.fr_rsp_len =
+ cpu_to_be32(sizeof(struct fcp_resp_rsp_info));
+
+ io->sgl[0].addr = io->rspbuf.phys;
+ io->sgl[0].dif_addr = 0;
+ io->sgl[0].len = io->wire_len;
+ io->sgl_count = 1;
+
+ memset(&io->iparam, 0, sizeof(io->iparam));
+ io->iparam.fcp_tgt.ox_id = io->init_task_tag;
+ io->iparam.fcp_tgt.offset = 0;
+ io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
+ io->iparam.fcp_tgt.timeout = io->timeout;
+
+ rc = efct_scsi_io_dispatch(io, efct_target_io_cb);
+
+ return rc;
+}
+
+static int
+efct_target_abort_cb(struct efct_hw_io *hio, u32 length, int status,
+ u32 ext_status, void *app)
+{
+ struct efct_io *io = app;
+ struct efct *efct;
+ enum efct_scsi_io_status scsi_status;
+ efct_scsi_io_cb_t abort_cb;
+ void *abort_cb_arg;
+
+ efct = io->efct;
+
+ if (!io->abort_cb)
+ goto done;
+
+ abort_cb = io->abort_cb;
+ abort_cb_arg = io->abort_cb_arg;
+
+ io->abort_cb = NULL;
+ io->abort_cb_arg = NULL;
+
+ switch (status) {
+ case SLI4_FC_WCQE_STATUS_SUCCESS:
+ scsi_status = EFCT_SCSI_STATUS_GOOD;
+ break;
+ case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
+ switch (ext_status) {
+ case SLI4_FC_LOCAL_REJECT_NO_XRI:
+ scsi_status = EFCT_SCSI_STATUS_NO_IO;
+ break;
+ case SLI4_FC_LOCAL_REJECT_ABORT_IN_PROGRESS:
+ scsi_status = EFCT_SCSI_STATUS_ABORT_IN_PROGRESS;
+ break;
+ default:
+ /*we have seen 0x15 (abort in progress)*/
+ scsi_status = EFCT_SCSI_STATUS_ERROR;
+ break;
+ }
+ break;
+ case SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE:
+ scsi_status = EFCT_SCSI_STATUS_CHECK_RESPONSE;
+ break;
+ default:
+ scsi_status = EFCT_SCSI_STATUS_ERROR;
+ break;
+ }
+ /* invoke callback */
+ abort_cb(io->io_to_abort, scsi_status, 0, abort_cb_arg);
+
+done:
+ /* done with IO to abort,efct_ref_get(): efct_scsi_tgt_abort_io() */
+ kref_put(&io->io_to_abort->ref, io->io_to_abort->release);
+
+ efct_io_pool_io_free(efct->xport->io_pool, io);
+
+ efct_scsi_check_pending(efct);
+ return 0;
+}
+
+int
+efct_scsi_tgt_abort_io(struct efct_io *io, efct_scsi_io_cb_t cb, void *arg)
+{
+ struct efct *efct;
+ struct efct_xport *xport;
+ int rc;
+ struct efct_io *abort_io = NULL;
+
+ efct = io->efct;
+ xport = efct->xport;
+
+ /* take a reference on IO being aborted */
+ if (kref_get_unless_zero(&io->ref) == 0) {
+ /* command no longer active */
+ scsi_io_printf(io, "command no longer active\n");
+ return -EIO;
+ }
+
+ /*
+ * allocate a new IO to send the abort request. Use efct_io_alloc()
+ * directly, as we need an IO object that will not fail allocation
+ * due to allocations being disabled (in efct_scsi_io_alloc())
+ */
+ abort_io = efct_io_pool_io_alloc(efct->xport->io_pool);
+ if (!abort_io) {
+ atomic_add_return(1, &xport->io_alloc_failed_count);
+ kref_put(&io->ref, io->release);
+ return -EIO;
+ }
+
+ /* Save the target server callback and argument */
+ /* set generic fields */
+ abort_io->cmd_tgt = true;
+ abort_io->node = io->node;
+
+ /* set type and abort-specific fields */
+ abort_io->io_type = EFCT_IO_TYPE_ABORT;
+ abort_io->display_name = "tgt_abort";
+ abort_io->io_to_abort = io;
+ abort_io->send_abts = false;
+ abort_io->abort_cb = cb;
+ abort_io->abort_cb_arg = arg;
+
+ /* now dispatch IO */
+ rc = efct_scsi_io_dispatch_abort(abort_io, efct_target_abort_cb);
+ if (rc)
+ kref_put(&io->ref, io->release);
+ return rc;
+}
+
+void
+efct_scsi_io_complete(struct efct_io *io)
+{
+ if (io->io_free) {
+ efc_log_debug(io->efct, "completion for non-busy io tag 0x%x\n",
+ io->tag);
+ return;
+ }
+
+ scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
+ kref_put(&io->ref, io->release);
+}
diff --git a/drivers/scsi/elx/efct/efct_scsi.h b/drivers/scsi/elx/efct/efct_scsi.h
new file mode 100644
index 000000000000..b04faffa3984
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_scsi.h
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#if !defined(__EFCT_SCSI_H__)
+#define __EFCT_SCSI_H__
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+
+/* efct_scsi_rcv_cmd() efct_scsi_rcv_tmf() flags */
+#define EFCT_SCSI_CMD_DIR_IN (1 << 0)
+#define EFCT_SCSI_CMD_DIR_OUT (1 << 1)
+#define EFCT_SCSI_CMD_SIMPLE (1 << 2)
+#define EFCT_SCSI_CMD_HEAD_OF_QUEUE (1 << 3)
+#define EFCT_SCSI_CMD_ORDERED (1 << 4)
+#define EFCT_SCSI_CMD_UNTAGGED (1 << 5)
+#define EFCT_SCSI_CMD_ACA (1 << 6)
+#define EFCT_SCSI_FIRST_BURST_ERR (1 << 7)
+#define EFCT_SCSI_FIRST_BURST_ABORTED (1 << 8)
+
+/* efct_scsi_send_rd_data/recv_wr_data/send_resp flags */
+#define EFCT_SCSI_LAST_DATAPHASE (1 << 0)
+#define EFCT_SCSI_NO_AUTO_RESPONSE (1 << 1)
+#define EFCT_SCSI_LOW_LATENCY (1 << 2)
+
+#define EFCT_SCSI_SNS_BUF_VALID(sense) ((sense) && \
+ (0x70 == (((const u8 *)(sense))[0] & 0x70)))
+
+#define EFCT_SCSI_WQ_STEERING_SHIFT 16
+#define EFCT_SCSI_WQ_STEERING_MASK (0xf << EFCT_SCSI_WQ_STEERING_SHIFT)
+#define EFCT_SCSI_WQ_STEERING_CLASS (0 << EFCT_SCSI_WQ_STEERING_SHIFT)
+#define EFCT_SCSI_WQ_STEERING_REQUEST (1 << EFCT_SCSI_WQ_STEERING_SHIFT)
+#define EFCT_SCSI_WQ_STEERING_CPU (2 << EFCT_SCSI_WQ_STEERING_SHIFT)
+
+#define EFCT_SCSI_WQ_CLASS_SHIFT (20)
+#define EFCT_SCSI_WQ_CLASS_MASK (0xf << EFCT_SCSI_WQ_CLASS_SHIFT)
+#define EFCT_SCSI_WQ_CLASS(x) ((x & EFCT_SCSI_WQ_CLASS_MASK) << \
+ EFCT_SCSI_WQ_CLASS_SHIFT)
+
+#define EFCT_SCSI_WQ_CLASS_LOW_LATENCY 1
+
+struct efct_scsi_cmd_resp {
+ u8 scsi_status;
+ u16 scsi_status_qualifier;
+ u8 *response_data;
+ u32 response_data_length;
+ u8 *sense_data;
+ u32 sense_data_length;
+ int residual;
+ u32 response_wire_length;
+};
+
+struct efct_vport {
+ struct efct *efct;
+ bool is_vport;
+ struct fc_host_statistics fc_host_stats;
+ struct Scsi_Host *shost;
+ struct fc_vport *fc_vport;
+ u64 npiv_wwpn;
+ u64 npiv_wwnn;
+};
+
+/* Status values returned by IO callbacks */
+enum efct_scsi_io_status {
+ EFCT_SCSI_STATUS_GOOD = 0,
+ EFCT_SCSI_STATUS_ABORTED,
+ EFCT_SCSI_STATUS_ERROR,
+ EFCT_SCSI_STATUS_DIF_GUARD_ERR,
+ EFCT_SCSI_STATUS_DIF_REF_TAG_ERROR,
+ EFCT_SCSI_STATUS_DIF_APP_TAG_ERROR,
+ EFCT_SCSI_STATUS_DIF_UNKNOWN_ERROR,
+ EFCT_SCSI_STATUS_PROTOCOL_CRC_ERROR,
+ EFCT_SCSI_STATUS_NO_IO,
+ EFCT_SCSI_STATUS_ABORT_IN_PROGRESS,
+ EFCT_SCSI_STATUS_CHECK_RESPONSE,
+ EFCT_SCSI_STATUS_COMMAND_TIMEOUT,
+ EFCT_SCSI_STATUS_TIMEDOUT_AND_ABORTED,
+ EFCT_SCSI_STATUS_SHUTDOWN,
+ EFCT_SCSI_STATUS_NEXUS_LOST,
+};
+
+struct efct_node;
+struct efct_io;
+struct efc_node;
+struct efc_nport;
+
+/* Callback used by send_rd_data(), recv_wr_data(), send_resp() */
+typedef int (*efct_scsi_io_cb_t)(struct efct_io *io,
+ enum efct_scsi_io_status status,
+ u32 flags, void *arg);
+
+/* Callback used by send_rd_io(), send_wr_io() */
+typedef int (*efct_scsi_rsp_io_cb_t)(struct efct_io *io,
+ enum efct_scsi_io_status status,
+ struct efct_scsi_cmd_resp *rsp,
+ u32 flags, void *arg);
+
+/* efct_scsi_cb_t flags */
+#define EFCT_SCSI_IO_CMPL (1 << 0)
+/* IO completed, response sent */
+#define EFCT_SCSI_IO_CMPL_RSP_SENT (1 << 1)
+#define EFCT_SCSI_IO_ABORTED (1 << 2)
+
+/* efct_scsi_recv_tmf() request values */
+enum efct_scsi_tmf_cmd {
+ EFCT_SCSI_TMF_ABORT_TASK = 1,
+ EFCT_SCSI_TMF_QUERY_TASK_SET,
+ EFCT_SCSI_TMF_ABORT_TASK_SET,
+ EFCT_SCSI_TMF_CLEAR_TASK_SET,
+ EFCT_SCSI_TMF_QUERY_ASYNCHRONOUS_EVENT,
+ EFCT_SCSI_TMF_LOGICAL_UNIT_RESET,
+ EFCT_SCSI_TMF_CLEAR_ACA,
+ EFCT_SCSI_TMF_TARGET_RESET,
+};
+
+/* efct_scsi_send_tmf_resp() response values */
+enum efct_scsi_tmf_resp {
+ EFCT_SCSI_TMF_FUNCTION_COMPLETE = 1,
+ EFCT_SCSI_TMF_FUNCTION_SUCCEEDED,
+ EFCT_SCSI_TMF_FUNCTION_IO_NOT_FOUND,
+ EFCT_SCSI_TMF_FUNCTION_REJECTED,
+ EFCT_SCSI_TMF_INCORRECT_LOGICAL_UNIT_NUMBER,
+ EFCT_SCSI_TMF_SERVICE_DELIVERY,
+};
+
+struct efct_scsi_sgl {
+ uintptr_t addr;
+ uintptr_t dif_addr;
+ size_t len;
+};
+
+enum efct_scsi_io_role {
+ EFCT_SCSI_IO_ROLE_ORIGINATOR,
+ EFCT_SCSI_IO_ROLE_RESPONDER,
+};
+
+struct efct_io *
+efct_scsi_io_alloc(struct efct_node *node);
+void efct_scsi_io_free(struct efct_io *io);
+struct efct_io *efct_io_get_instance(struct efct *efct, u32 index);
+
+int efct_scsi_tgt_driver_init(void);
+int efct_scsi_tgt_driver_exit(void);
+int efct_scsi_tgt_new_device(struct efct *efct);
+int efct_scsi_tgt_del_device(struct efct *efct);
+int
+efct_scsi_tgt_new_nport(struct efc *efc, struct efc_nport *nport);
+void
+efct_scsi_tgt_del_nport(struct efc *efc, struct efc_nport *nport);
+
+int
+efct_scsi_new_initiator(struct efc *efc, struct efc_node *node);
+
+enum efct_scsi_del_initiator_reason {
+ EFCT_SCSI_INITIATOR_DELETED,
+ EFCT_SCSI_INITIATOR_MISSING,
+};
+
+int
+efct_scsi_del_initiator(struct efc *efc, struct efc_node *node, int reason);
+void
+efct_scsi_recv_cmd(struct efct_io *io, uint64_t lun, u8 *cdb, u32 cdb_len,
+ u32 flags);
+int
+efct_scsi_recv_tmf(struct efct_io *tmfio, u32 lun, enum efct_scsi_tmf_cmd cmd,
+ struct efct_io *abortio, u32 flags);
+int
+efct_scsi_send_rd_data(struct efct_io *io, u32 flags, struct efct_scsi_sgl *sgl,
+ u32 sgl_count, u64 wire_len, efct_scsi_io_cb_t cb, void *arg);
+int
+efct_scsi_recv_wr_data(struct efct_io *io, u32 flags, struct efct_scsi_sgl *sgl,
+ u32 sgl_count, u64 wire_len, efct_scsi_io_cb_t cb, void *arg);
+int
+efct_scsi_send_resp(struct efct_io *io, u32 flags,
+ struct efct_scsi_cmd_resp *rsp, efct_scsi_io_cb_t cb, void *arg);
+int
+efct_scsi_send_tmf_resp(struct efct_io *io, enum efct_scsi_tmf_resp rspcode,
+ u8 addl_rsp_info[3], efct_scsi_io_cb_t cb, void *arg);
+int
+efct_scsi_tgt_abort_io(struct efct_io *io, efct_scsi_io_cb_t cb, void *arg);
+
+void efct_scsi_io_complete(struct efct_io *io);
+
+int efct_scsi_reg_fc_transport(void);
+void efct_scsi_release_fc_transport(void);
+int efct_scsi_new_device(struct efct *efct);
+void efct_scsi_del_device(struct efct *efct);
+void _efct_scsi_io_free(struct kref *arg);
+
+int
+efct_scsi_del_vport(struct efct *efct, struct Scsi_Host *shost);
+struct efct_vport *
+efct_scsi_new_vport(struct efct *efct, struct device *dev);
+
+int efct_scsi_io_dispatch(struct efct_io *io, void *cb);
+int efct_scsi_io_dispatch_abort(struct efct_io *io, void *cb);
+void efct_scsi_check_pending(struct efct *efct);
+struct efct_io *
+efct_bls_send_rjt(struct efct_io *io, struct fc_frame_header *hdr);
+
+#endif /* __EFCT_SCSI_H__ */
diff --git a/drivers/scsi/elx/efct/efct_unsol.c b/drivers/scsi/elx/efct/efct_unsol.c
new file mode 100644
index 000000000000..e6addab66a60
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_unsol.c
@@ -0,0 +1,492 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#include "efct_driver.h"
+#include "efct_unsol.h"
+
+#define frame_printf(efct, hdr, fmt, ...) \
+ do { \
+ char s_id_text[16]; \
+ efc_node_fcid_display(ntoh24((hdr)->fh_s_id), \
+ s_id_text, sizeof(s_id_text)); \
+ efc_log_debug(efct, "[%06x.%s] %02x/%04x/%04x: " fmt, \
+ ntoh24((hdr)->fh_d_id), s_id_text, \
+ (hdr)->fh_r_ctl, be16_to_cpu((hdr)->fh_ox_id), \
+ be16_to_cpu((hdr)->fh_rx_id), ##__VA_ARGS__); \
+ } while (0)
+
+static struct efct_node *
+efct_node_find(struct efct *efct, u32 port_id, u32 node_id)
+{
+ struct efct_node *node;
+ u64 id = (u64)port_id << 32 | node_id;
+
+ /*
+ * During node shutdown, Lookup will be removed first,
+ * before announcing to backend. So, no new IOs will be allowed
+ */
+ /* Find a target node, given s_id and d_id */
+ node = xa_load(&efct->lookup, id);
+ if (node)
+ kref_get(&node->ref);
+
+ return node;
+}
+
+static int
+efct_dispatch_frame(struct efct *efct, struct efc_hw_sequence *seq)
+{
+ struct efct_node *node;
+ struct fc_frame_header *hdr;
+ u32 s_id, d_id;
+
+ hdr = seq->header->dma.virt;
+
+ /* extract the s_id and d_id */
+ s_id = ntoh24(hdr->fh_s_id);
+ d_id = ntoh24(hdr->fh_d_id);
+
+ if (!(hdr->fh_type == FC_TYPE_FCP || hdr->fh_type == FC_TYPE_BLS))
+ return -EIO;
+
+ if (hdr->fh_type == FC_TYPE_FCP) {
+ node = efct_node_find(efct, d_id, s_id);
+ if (!node) {
+ efc_log_err(efct,
+ "Node not found, drop cmd d_id:%x s_id:%x\n",
+ d_id, s_id);
+ efct_hw_sequence_free(&efct->hw, seq);
+ return 0;
+ }
+
+ efct_dispatch_fcp_cmd(node, seq);
+ } else {
+ node = efct_node_find(efct, d_id, s_id);
+ if (!node) {
+ efc_log_err(efct, "ABTS: Node not found, d_id:%x s_id:%x\n",
+ d_id, s_id);
+ return -EIO;
+ }
+
+ efc_log_err(efct, "Received ABTS for Node:%p\n", node);
+ efct_node_recv_abts_frame(node, seq);
+ }
+
+ kref_put(&node->ref, node->release);
+ efct_hw_sequence_free(&efct->hw, seq);
+ return 0;
+}
+
+int
+efct_unsolicited_cb(void *arg, struct efc_hw_sequence *seq)
+{
+ struct efct *efct = arg;
+
+ /* Process FCP command */
+ if (!efct_dispatch_frame(efct, seq))
+ return 0;
+
+ /* Forward frame to discovery lib */
+ efc_dispatch_frame(efct->efcport, seq);
+ return 0;
+}
+
+static int
+efct_fc_tmf_rejected_cb(struct efct_io *io,
+ enum efct_scsi_io_status scsi_status,
+ u32 flags, void *arg)
+{
+ efct_scsi_io_free(io);
+ return 0;
+}
+
+static void
+efct_dispatch_unsol_tmf(struct efct_io *io, u8 tm_flags, u32 lun)
+{
+ u32 i;
+ struct {
+ u32 mask;
+ enum efct_scsi_tmf_cmd cmd;
+ } tmflist[] = {
+ {FCP_TMF_ABT_TASK_SET, EFCT_SCSI_TMF_ABORT_TASK_SET},
+ {FCP_TMF_CLR_TASK_SET, EFCT_SCSI_TMF_CLEAR_TASK_SET},
+ {FCP_TMF_LUN_RESET, EFCT_SCSI_TMF_LOGICAL_UNIT_RESET},
+ {FCP_TMF_TGT_RESET, EFCT_SCSI_TMF_TARGET_RESET},
+ {FCP_TMF_CLR_ACA, EFCT_SCSI_TMF_CLEAR_ACA} };
+
+ io->exp_xfer_len = 0;
+
+ for (i = 0; i < ARRAY_SIZE(tmflist); i++) {
+ if (tmflist[i].mask & tm_flags) {
+ io->tmf_cmd = tmflist[i].cmd;
+ efct_scsi_recv_tmf(io, lun, tmflist[i].cmd, NULL, 0);
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(tmflist)) {
+ /* Not handled */
+ efc_log_err(io->node->efct, "TMF x%x rejected\n", tm_flags);
+ efct_scsi_send_tmf_resp(io, EFCT_SCSI_TMF_FUNCTION_REJECTED,
+ NULL, efct_fc_tmf_rejected_cb, NULL);
+ }
+}
+
+static int
+efct_validate_fcp_cmd(struct efct *efct, struct efc_hw_sequence *seq)
+{
+ /*
+ * If we received less than FCP_CMND_IU bytes, assume that the frame is
+ * corrupted in some way and drop it.
+ * This was seen when jamming the FCTL
+ * fill bytes field.
+ */
+ if (seq->payload->dma.len < sizeof(struct fcp_cmnd)) {
+ struct fc_frame_header *fchdr = seq->header->dma.virt;
+
+ efc_log_debug(efct,
+ "drop ox_id %04x payload (%zd) less than (%zd)\n",
+ be16_to_cpu(fchdr->fh_ox_id),
+ seq->payload->dma.len, sizeof(struct fcp_cmnd));
+ return -EIO;
+ }
+ return 0;
+}
+
+static void
+efct_populate_io_fcp_cmd(struct efct_io *io, struct fcp_cmnd *cmnd,
+ struct fc_frame_header *fchdr, bool sit)
+{
+ io->init_task_tag = be16_to_cpu(fchdr->fh_ox_id);
+ /* note, tgt_task_tag, hw_tag set when HW io is allocated */
+ io->exp_xfer_len = be32_to_cpu(cmnd->fc_dl);
+ io->transferred = 0;
+
+ /* The upper 7 bits of CS_CTL is the frame priority thru the SAN.
+ * Our assertion here is, the priority given to a frame containing
+ * the FCP cmd should be the priority given to ALL frames contained
+ * in that IO. Thus we need to save the incoming CS_CTL here.
+ */
+ if (ntoh24(fchdr->fh_f_ctl) & FC_FC_RES_B17)
+ io->cs_ctl = fchdr->fh_cs_ctl;
+ else
+ io->cs_ctl = 0;
+
+ io->seq_init = sit;
+}
+
+static u32
+efct_get_flags_fcp_cmd(struct fcp_cmnd *cmnd)
+{
+ u32 flags = 0;
+
+ switch (cmnd->fc_pri_ta & FCP_PTA_MASK) {
+ case FCP_PTA_SIMPLE:
+ flags |= EFCT_SCSI_CMD_SIMPLE;
+ break;
+ case FCP_PTA_HEADQ:
+ flags |= EFCT_SCSI_CMD_HEAD_OF_QUEUE;
+ break;
+ case FCP_PTA_ORDERED:
+ flags |= EFCT_SCSI_CMD_ORDERED;
+ break;
+ case FCP_PTA_ACA:
+ flags |= EFCT_SCSI_CMD_ACA;
+ break;
+ }
+ if (cmnd->fc_flags & FCP_CFL_WRDATA)
+ flags |= EFCT_SCSI_CMD_DIR_IN;
+ if (cmnd->fc_flags & FCP_CFL_RDDATA)
+ flags |= EFCT_SCSI_CMD_DIR_OUT;
+
+ return flags;
+}
+
+static void
+efct_sframe_common_send_cb(void *arg, u8 *cqe, int status)
+{
+ struct efct_hw_send_frame_context *ctx = arg;
+ struct efct_hw *hw = ctx->hw;
+
+ /* Free WQ completion callback */
+ efct_hw_reqtag_free(hw, ctx->wqcb);
+
+ /* Free sequence */
+ efct_hw_sequence_free(hw, ctx->seq);
+}
+
+static int
+efct_sframe_common_send(struct efct_node *node,
+ struct efc_hw_sequence *seq,
+ enum fc_rctl r_ctl, u32 f_ctl,
+ u8 type, void *payload, u32 payload_len)
+{
+ struct efct *efct = node->efct;
+ struct efct_hw *hw = &efct->hw;
+ int rc = 0;
+ struct fc_frame_header *req_hdr = seq->header->dma.virt;
+ struct fc_frame_header hdr;
+ struct efct_hw_send_frame_context *ctx;
+
+ u32 heap_size = seq->payload->dma.size;
+ uintptr_t heap_phys_base = seq->payload->dma.phys;
+ u8 *heap_virt_base = seq->payload->dma.virt;
+ u32 heap_offset = 0;
+
+ /* Build the FC header reusing the RQ header DMA buffer */
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.fh_r_ctl = r_ctl;
+ /* send it back to whomever sent it to us */
+ memcpy(hdr.fh_d_id, req_hdr->fh_s_id, sizeof(hdr.fh_d_id));
+ memcpy(hdr.fh_s_id, req_hdr->fh_d_id, sizeof(hdr.fh_s_id));
+ hdr.fh_type = type;
+ hton24(hdr.fh_f_ctl, f_ctl);
+ hdr.fh_ox_id = req_hdr->fh_ox_id;
+ hdr.fh_rx_id = req_hdr->fh_rx_id;
+ hdr.fh_cs_ctl = 0;
+ hdr.fh_df_ctl = 0;
+ hdr.fh_seq_cnt = 0;
+ hdr.fh_parm_offset = 0;
+
+ /*
+ * send_frame_seq_id is an atomic, we just let it increment,
+ * while storing only the low 8 bits to hdr->seq_id
+ */
+ hdr.fh_seq_id = (u8)atomic_add_return(1, &hw->send_frame_seq_id);
+ hdr.fh_seq_id--;
+
+ /* Allocate and fill in the send frame request context */
+ ctx = (void *)(heap_virt_base + heap_offset);
+ heap_offset += sizeof(*ctx);
+ if (heap_offset > heap_size) {
+ efc_log_err(efct, "Fill send frame failed offset %d size %d\n",
+ heap_offset, heap_size);
+ return -EIO;
+ }
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ /* Save sequence */
+ ctx->seq = seq;
+
+ /* Allocate a response payload DMA buffer from the heap */
+ ctx->payload.phys = heap_phys_base + heap_offset;
+ ctx->payload.virt = heap_virt_base + heap_offset;
+ ctx->payload.size = payload_len;
+ ctx->payload.len = payload_len;
+ heap_offset += payload_len;
+ if (heap_offset > heap_size) {
+ efc_log_err(efct, "Fill send frame failed offset %d size %d\n",
+ heap_offset, heap_size);
+ return -EIO;
+ }
+
+ /* Copy the payload in */
+ memcpy(ctx->payload.virt, payload, payload_len);
+
+ /* Send */
+ rc = efct_hw_send_frame(&efct->hw, (void *)&hdr, FC_SOF_N3,
+ FC_EOF_T, &ctx->payload, ctx,
+ efct_sframe_common_send_cb, ctx);
+ if (rc)
+ efc_log_debug(efct, "efct_hw_send_frame failed: %d\n", rc);
+
+ return rc;
+}
+
+static int
+efct_sframe_send_fcp_rsp(struct efct_node *node, struct efc_hw_sequence *seq,
+ void *rsp, u32 rsp_len)
+{
+ return efct_sframe_common_send(node, seq, FC_RCTL_DD_CMD_STATUS,
+ FC_FC_EX_CTX |
+ FC_FC_LAST_SEQ |
+ FC_FC_END_SEQ |
+ FC_FC_SEQ_INIT,
+ FC_TYPE_FCP,
+ rsp, rsp_len);
+}
+
+static int
+efct_sframe_send_task_set_full_or_busy(struct efct_node *node,
+ struct efc_hw_sequence *seq)
+{
+ struct fcp_resp_with_ext fcprsp;
+ struct fcp_cmnd *fcpcmd = seq->payload->dma.virt;
+ int rc = 0;
+ unsigned long flags = 0;
+ struct efct *efct = node->efct;
+
+ /* construct task set full or busy response */
+ memset(&fcprsp, 0, sizeof(fcprsp));
+ spin_lock_irqsave(&node->active_ios_lock, flags);
+ fcprsp.resp.fr_status = list_empty(&node->active_ios) ?
+ SAM_STAT_BUSY : SAM_STAT_TASK_SET_FULL;
+ spin_unlock_irqrestore(&node->active_ios_lock, flags);
+ *((u32 *)&fcprsp.ext.fr_resid) = be32_to_cpu(fcpcmd->fc_dl);
+
+ /* send it using send_frame */
+ rc = efct_sframe_send_fcp_rsp(node, seq, &fcprsp, sizeof(fcprsp));
+ if (rc)
+ efc_log_debug(efct, "efct_sframe_send_fcp_rsp failed %d\n", rc);
+
+ return rc;
+}
+
+int
+efct_dispatch_fcp_cmd(struct efct_node *node, struct efc_hw_sequence *seq)
+{
+ struct efct *efct = node->efct;
+ struct fc_frame_header *fchdr = seq->header->dma.virt;
+ struct fcp_cmnd *cmnd = NULL;
+ struct efct_io *io = NULL;
+ u32 lun;
+
+ if (!seq->payload) {
+ efc_log_err(efct, "Sequence payload is NULL.\n");
+ return -EIO;
+ }
+
+ cmnd = seq->payload->dma.virt;
+
+ /* perform FCP_CMND validation check(s) */
+ if (efct_validate_fcp_cmd(efct, seq))
+ return -EIO;
+
+ lun = scsilun_to_int(&cmnd->fc_lun);
+ if (lun == U32_MAX)
+ return -EIO;
+
+ io = efct_scsi_io_alloc(node);
+ if (!io) {
+ int rc;
+
+ /* Use SEND_FRAME to send task set full or busy */
+ rc = efct_sframe_send_task_set_full_or_busy(node, seq);
+ if (rc)
+ efc_log_err(efct, "Failed to send busy task: %d\n", rc);
+
+ return rc;
+ }
+
+ io->hw_priv = seq->hw_priv;
+
+ io->app_id = 0;
+
+ /* RQ pair, if we got here, SIT=1 */
+ efct_populate_io_fcp_cmd(io, cmnd, fchdr, true);
+
+ if (cmnd->fc_tm_flags) {
+ efct_dispatch_unsol_tmf(io, cmnd->fc_tm_flags, lun);
+ } else {
+ u32 flags = efct_get_flags_fcp_cmd(cmnd);
+
+ if (cmnd->fc_flags & FCP_CFL_LEN_MASK) {
+ efc_log_err(efct, "Additional CDB not supported\n");
+ return -EIO;
+ }
+ /*
+ * Can return failure for things like task set full and UAs,
+ * no need to treat as a dropped frame if rc != 0
+ */
+ efct_scsi_recv_cmd(io, lun, cmnd->fc_cdb,
+ sizeof(cmnd->fc_cdb), flags);
+ }
+
+ return 0;
+}
+
+static int
+efct_process_abts(struct efct_io *io, struct fc_frame_header *hdr)
+{
+ struct efct_node *node = io->node;
+ struct efct *efct = io->efct;
+ u16 ox_id = be16_to_cpu(hdr->fh_ox_id);
+ u16 rx_id = be16_to_cpu(hdr->fh_rx_id);
+ struct efct_io *abortio;
+
+ /* Find IO and attempt to take a reference on it */
+ abortio = efct_io_find_tgt_io(efct, node, ox_id, rx_id);
+
+ if (abortio) {
+ /* Got a reference on the IO. Hold it until backend
+ * is notified below
+ */
+ efc_log_info(node->efct, "Abort ox_id [%04x] rx_id [%04x]\n",
+ ox_id, rx_id);
+
+ /*
+ * Save the ox_id for the ABTS as the init_task_tag in our
+ * manufactured
+ * TMF IO object
+ */
+ io->display_name = "abts";
+ io->init_task_tag = ox_id;
+ /* don't set tgt_task_tag, don't want to confuse with XRI */
+
+ /*
+ * Save the rx_id from the ABTS as it is
+ * needed for the BLS response,
+ * regardless of the IO context's rx_id
+ */
+ io->abort_rx_id = rx_id;
+
+ /* Call target server command abort */
+ io->tmf_cmd = EFCT_SCSI_TMF_ABORT_TASK;
+ efct_scsi_recv_tmf(io, abortio->tgt_io.lun,
+ EFCT_SCSI_TMF_ABORT_TASK, abortio, 0);
+
+ /*
+ * Backend will have taken an additional
+ * reference on the IO if needed;
+ * done with current reference.
+ */
+ kref_put(&abortio->ref, abortio->release);
+ } else {
+ /*
+ * Either IO was not found or it has been
+ * freed between finding it
+ * and attempting to get the reference,
+ */
+ efc_log_info(node->efct, "Abort: ox_id [%04x], IO not found\n",
+ ox_id);
+
+ /* Send a BA_RJT */
+ efct_bls_send_rjt(io, hdr);
+ }
+ return 0;
+}
+
+int
+efct_node_recv_abts_frame(struct efct_node *node, struct efc_hw_sequence *seq)
+{
+ struct efct *efct = node->efct;
+ struct fc_frame_header *hdr = seq->header->dma.virt;
+ struct efct_io *io = NULL;
+
+ node->abort_cnt++;
+ io = efct_scsi_io_alloc(node);
+ if (io) {
+ io->hw_priv = seq->hw_priv;
+ /* If we got this far, SIT=1 */
+ io->seq_init = 1;
+
+ /* fill out generic fields */
+ io->efct = efct;
+ io->node = node;
+ io->cmd_tgt = true;
+
+ efct_process_abts(io, seq->header->dma.virt);
+ } else {
+ efc_log_err(efct,
+ "SCSI IO allocation failed for ABTS received ");
+ efc_log_err(efct, "s_id %06x d_id %06x ox_id %04x rx_id %04x\n",
+ ntoh24(hdr->fh_s_id), ntoh24(hdr->fh_d_id),
+ be16_to_cpu(hdr->fh_ox_id),
+ be16_to_cpu(hdr->fh_rx_id));
+ }
+
+ return 0;
+}
diff --git a/drivers/scsi/elx/efct/efct_unsol.h b/drivers/scsi/elx/efct/efct_unsol.h
new file mode 100644
index 000000000000..16d1e3ba1833
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_unsol.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#if !defined(__OSC_UNSOL_H__)
+#define __OSC_UNSOL_H__
+
+int
+efct_unsolicited_cb(void *arg, struct efc_hw_sequence *seq);
+int
+efct_dispatch_fcp_cmd(struct efct_node *node, struct efc_hw_sequence *seq);
+int
+efct_node_recv_abts_frame(struct efct_node *node, struct efc_hw_sequence *seq);
+
+#endif /* __OSC_UNSOL_H__ */
diff --git a/drivers/scsi/elx/efct/efct_xport.c b/drivers/scsi/elx/efct/efct_xport.c
new file mode 100644
index 000000000000..9495cedcc0b9
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_xport.c
@@ -0,0 +1,1111 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#include "efct_driver.h"
+#include "efct_unsol.h"
+
+static struct dentry *efct_debugfs_root;
+static atomic_t efct_debugfs_count;
+
+static struct scsi_host_template efct_template = {
+ .module = THIS_MODULE,
+ .name = EFCT_DRIVER_NAME,
+ .supported_mode = MODE_TARGET,
+};
+
+/* globals */
+static struct fc_function_template efct_xport_functions;
+static struct fc_function_template efct_vport_functions;
+
+static struct scsi_transport_template *efct_xport_fc_tt;
+static struct scsi_transport_template *efct_vport_fc_tt;
+
+struct efct_xport *
+efct_xport_alloc(struct efct *efct)
+{
+ struct efct_xport *xport;
+
+ xport = kzalloc(sizeof(*xport), GFP_KERNEL);
+ if (!xport)
+ return xport;
+
+ xport->efct = efct;
+ return xport;
+}
+
+static int
+efct_xport_init_debugfs(struct efct *efct)
+{
+ /* Setup efct debugfs root directory */
+ if (!efct_debugfs_root) {
+ efct_debugfs_root = debugfs_create_dir("efct", NULL);
+ atomic_set(&efct_debugfs_count, 0);
+ }
+
+ /* Create a directory for sessions in root */
+ if (!efct->sess_debugfs_dir) {
+ efct->sess_debugfs_dir = debugfs_create_dir("sessions",
+ efct_debugfs_root);
+ if (IS_ERR(efct->sess_debugfs_dir)) {
+ efc_log_err(efct,
+ "failed to create debugfs entry for sessions\n");
+ goto debugfs_fail;
+ }
+ atomic_inc(&efct_debugfs_count);
+ }
+
+ return 0;
+
+debugfs_fail:
+ return -EIO;
+}
+
+static void efct_xport_delete_debugfs(struct efct *efct)
+{
+ /* Remove session debugfs directory */
+ debugfs_remove(efct->sess_debugfs_dir);
+ efct->sess_debugfs_dir = NULL;
+ atomic_dec(&efct_debugfs_count);
+
+ if (atomic_read(&efct_debugfs_count) == 0) {
+ /* remove root debugfs directory */
+ debugfs_remove(efct_debugfs_root);
+ efct_debugfs_root = NULL;
+ }
+}
+
+int
+efct_xport_attach(struct efct_xport *xport)
+{
+ struct efct *efct = xport->efct;
+ int rc;
+
+ rc = efct_hw_setup(&efct->hw, efct, efct->pci);
+ if (rc) {
+ efc_log_err(efct, "%s: Can't setup hardware\n", efct->desc);
+ return rc;
+ }
+
+ efct_hw_parse_filter(&efct->hw, (void *)efct->filter_def);
+
+ xport->io_pool = efct_io_pool_create(efct, efct->hw.config.n_sgl);
+ if (!xport->io_pool) {
+ efc_log_err(efct, "Can't allocate IO pool\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void
+efct_xport_link_stats_cb(int status, u32 num_counters,
+ struct efct_hw_link_stat_counts *counters, void *arg)
+{
+ union efct_xport_stats_u *result = arg;
+
+ result->stats.link_stats.link_failure_error_count =
+ counters[EFCT_HW_LINK_STAT_LINK_FAILURE_COUNT].counter;
+ result->stats.link_stats.loss_of_sync_error_count =
+ counters[EFCT_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].counter;
+ result->stats.link_stats.primitive_sequence_error_count =
+ counters[EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].counter;
+ result->stats.link_stats.invalid_transmission_word_error_count =
+ counters[EFCT_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].counter;
+ result->stats.link_stats.crc_error_count =
+ counters[EFCT_HW_LINK_STAT_CRC_COUNT].counter;
+
+ complete(&result->stats.done);
+}
+
+static void
+efct_xport_host_stats_cb(int status, u32 num_counters,
+ struct efct_hw_host_stat_counts *counters, void *arg)
+{
+ union efct_xport_stats_u *result = arg;
+
+ result->stats.host_stats.transmit_kbyte_count =
+ counters[EFCT_HW_HOST_STAT_TX_KBYTE_COUNT].counter;
+ result->stats.host_stats.receive_kbyte_count =
+ counters[EFCT_HW_HOST_STAT_RX_KBYTE_COUNT].counter;
+ result->stats.host_stats.transmit_frame_count =
+ counters[EFCT_HW_HOST_STAT_TX_FRAME_COUNT].counter;
+ result->stats.host_stats.receive_frame_count =
+ counters[EFCT_HW_HOST_STAT_RX_FRAME_COUNT].counter;
+
+ complete(&result->stats.done);
+}
+
+static void
+efct_xport_async_link_stats_cb(int status, u32 num_counters,
+ struct efct_hw_link_stat_counts *counters,
+ void *arg)
+{
+ union efct_xport_stats_u *result = arg;
+
+ result->stats.link_stats.link_failure_error_count =
+ counters[EFCT_HW_LINK_STAT_LINK_FAILURE_COUNT].counter;
+ result->stats.link_stats.loss_of_sync_error_count =
+ counters[EFCT_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].counter;
+ result->stats.link_stats.primitive_sequence_error_count =
+ counters[EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].counter;
+ result->stats.link_stats.invalid_transmission_word_error_count =
+ counters[EFCT_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].counter;
+ result->stats.link_stats.crc_error_count =
+ counters[EFCT_HW_LINK_STAT_CRC_COUNT].counter;
+}
+
+static void
+efct_xport_async_host_stats_cb(int status, u32 num_counters,
+ struct efct_hw_host_stat_counts *counters,
+ void *arg)
+{
+ union efct_xport_stats_u *result = arg;
+
+ result->stats.host_stats.transmit_kbyte_count =
+ counters[EFCT_HW_HOST_STAT_TX_KBYTE_COUNT].counter;
+ result->stats.host_stats.receive_kbyte_count =
+ counters[EFCT_HW_HOST_STAT_RX_KBYTE_COUNT].counter;
+ result->stats.host_stats.transmit_frame_count =
+ counters[EFCT_HW_HOST_STAT_TX_FRAME_COUNT].counter;
+ result->stats.host_stats.receive_frame_count =
+ counters[EFCT_HW_HOST_STAT_RX_FRAME_COUNT].counter;
+}
+
+static void
+efct_xport_config_stats_timer(struct efct *efct);
+
+static void
+efct_xport_stats_timer_cb(struct timer_list *t)
+{
+ struct efct_xport *xport = from_timer(xport, t, stats_timer);
+ struct efct *efct = xport->efct;
+
+ efct_xport_config_stats_timer(efct);
+}
+
+static void
+efct_xport_config_stats_timer(struct efct *efct)
+{
+ u32 timeout = 3 * 1000;
+ struct efct_xport *xport = NULL;
+
+ if (!efct) {
+ pr_err("%s: failed to locate EFCT device\n", __func__);
+ return;
+ }
+
+ xport = efct->xport;
+ efct_hw_get_link_stats(&efct->hw, 0, 0, 0,
+ efct_xport_async_link_stats_cb,
+ &xport->fc_xport_stats);
+ efct_hw_get_host_stats(&efct->hw, 0, efct_xport_async_host_stats_cb,
+ &xport->fc_xport_stats);
+
+ timer_setup(&xport->stats_timer,
+ &efct_xport_stats_timer_cb, 0);
+ mod_timer(&xport->stats_timer,
+ jiffies + msecs_to_jiffies(timeout));
+}
+
+int
+efct_xport_initialize(struct efct_xport *xport)
+{
+ struct efct *efct = xport->efct;
+ int rc = 0;
+
+ /* Initialize io lists */
+ spin_lock_init(&xport->io_pending_lock);
+ INIT_LIST_HEAD(&xport->io_pending_list);
+ atomic_set(&xport->io_active_count, 0);
+ atomic_set(&xport->io_pending_count, 0);
+ atomic_set(&xport->io_total_free, 0);
+ atomic_set(&xport->io_total_pending, 0);
+ atomic_set(&xport->io_alloc_failed_count, 0);
+ atomic_set(&xport->io_pending_recursing, 0);
+
+ rc = efct_hw_init(&efct->hw);
+ if (rc) {
+ efc_log_err(efct, "efct_hw_init failure\n");
+ goto out;
+ }
+
+ rc = efct_scsi_tgt_new_device(efct);
+ if (rc) {
+ efc_log_err(efct, "failed to initialize target\n");
+ goto hw_init_out;
+ }
+
+ rc = efct_scsi_new_device(efct);
+ if (rc) {
+ efc_log_err(efct, "failed to initialize initiator\n");
+ goto tgt_dev_out;
+ }
+
+ /* Get FC link and host statistics perodically*/
+ efct_xport_config_stats_timer(efct);
+
+ efct_xport_init_debugfs(efct);
+
+ return rc;
+
+tgt_dev_out:
+ efct_scsi_tgt_del_device(efct);
+
+hw_init_out:
+ efct_hw_teardown(&efct->hw);
+out:
+ return rc;
+}
+
+int
+efct_xport_status(struct efct_xport *xport, enum efct_xport_status cmd,
+ union efct_xport_stats_u *result)
+{
+ int rc = 0;
+ struct efct *efct = NULL;
+ union efct_xport_stats_u value;
+
+ efct = xport->efct;
+
+ switch (cmd) {
+ case EFCT_XPORT_CONFIG_PORT_STATUS:
+ if (xport->configured_link_state == 0) {
+ /*
+ * Initial state is offline. configured_link_state is
+ * set to online explicitly when port is brought online
+ */
+ xport->configured_link_state = EFCT_XPORT_PORT_OFFLINE;
+ }
+ result->value = xport->configured_link_state;
+ break;
+
+ case EFCT_XPORT_PORT_STATUS:
+ /* Determine port status based on link speed. */
+ value.value = efct_hw_get_link_speed(&efct->hw);
+ if (value.value == 0)
+ result->value = EFCT_XPORT_PORT_OFFLINE;
+ else
+ result->value = EFCT_XPORT_PORT_ONLINE;
+ break;
+
+ case EFCT_XPORT_LINK_SPEED:
+ result->value = efct_hw_get_link_speed(&efct->hw);
+ break;
+
+ case EFCT_XPORT_LINK_STATISTICS:
+ memcpy((void *)result, &efct->xport->fc_xport_stats,
+ sizeof(union efct_xport_stats_u));
+ break;
+ case EFCT_XPORT_LINK_STAT_RESET: {
+ /* Create a completion to synchronize the stat reset process */
+ init_completion(&result->stats.done);
+
+ /* First reset the link stats */
+ rc = efct_hw_get_link_stats(&efct->hw, 0, 1, 1,
+ efct_xport_link_stats_cb, result);
+ if (rc)
+ break;
+
+ /* Wait for completion to be signaled when the cmd completes */
+ if (wait_for_completion_interruptible(&result->stats.done)) {
+ /* Undefined failure */
+ efc_log_debug(efct, "sem wait failed\n");
+ rc = -EIO;
+ break;
+ }
+
+ /* Next reset the host stats */
+ rc = efct_hw_get_host_stats(&efct->hw, 1,
+ efct_xport_host_stats_cb, result);
+
+ if (rc)
+ break;
+
+ /* Wait for completion to be signaled when the cmd completes */
+ if (wait_for_completion_interruptible(&result->stats.done)) {
+ /* Undefined failure */
+ efc_log_debug(efct, "sem wait failed\n");
+ rc = -EIO;
+ break;
+ }
+ break;
+ }
+ default:
+ rc = -EIO;
+ break;
+ }
+
+ return rc;
+}
+
+static int
+efct_get_link_supported_speeds(struct efct *efct)
+{
+ u32 supported_speeds = 0;
+ u32 link_module_type, i;
+ struct {
+ u32 lmt_speed;
+ u32 speed;
+ } supported_speed_list[] = {
+ {SLI4_LINK_MODULE_TYPE_1GB, FC_PORTSPEED_1GBIT},
+ {SLI4_LINK_MODULE_TYPE_2GB, FC_PORTSPEED_2GBIT},
+ {SLI4_LINK_MODULE_TYPE_4GB, FC_PORTSPEED_4GBIT},
+ {SLI4_LINK_MODULE_TYPE_8GB, FC_PORTSPEED_8GBIT},
+ {SLI4_LINK_MODULE_TYPE_16GB, FC_PORTSPEED_16GBIT},
+ {SLI4_LINK_MODULE_TYPE_32GB, FC_PORTSPEED_32GBIT},
+ {SLI4_LINK_MODULE_TYPE_64GB, FC_PORTSPEED_64GBIT},
+ {SLI4_LINK_MODULE_TYPE_128GB, FC_PORTSPEED_128GBIT},
+ };
+
+ link_module_type = sli_get_lmt(&efct->hw.sli);
+
+ /* populate link supported speeds */
+ for (i = 0; i < ARRAY_SIZE(supported_speed_list); i++) {
+ if (link_module_type & supported_speed_list[i].lmt_speed)
+ supported_speeds |= supported_speed_list[i].speed;
+ }
+
+ return supported_speeds;
+}
+
+int
+efct_scsi_new_device(struct efct *efct)
+{
+ struct Scsi_Host *shost = NULL;
+ int error = 0;
+ struct efct_vport *vport = NULL;
+
+ shost = scsi_host_alloc(&efct_template, sizeof(*vport));
+ if (!shost) {
+ efc_log_err(efct, "failed to allocate Scsi_Host struct\n");
+ return -ENOMEM;
+ }
+
+ /* save shost to initiator-client context */
+ efct->shost = shost;
+
+ /* save efct information to shost LLD-specific space */
+ vport = (struct efct_vport *)shost->hostdata;
+ vport->efct = efct;
+
+ /*
+ * Set initial can_queue value to the max SCSI IOs. This is the maximum
+ * global queue depth (as opposed to the per-LUN queue depth --
+ * .cmd_per_lun This may need to be adjusted for I+T mode.
+ */
+ shost->can_queue = efct->hw.config.n_io;
+ shost->max_cmd_len = 16; /* 16-byte CDBs */
+ shost->max_id = 0xffff;
+ shost->max_lun = 0xffffffff;
+
+ /*
+ * can only accept (from mid-layer) as many SGEs as we've
+ * pre-registered
+ */
+ shost->sg_tablesize = sli_get_max_sgl(&efct->hw.sli);
+
+ /* attach FC Transport template to shost */
+ shost->transportt = efct_xport_fc_tt;
+ efc_log_debug(efct, "transport template=%p\n", efct_xport_fc_tt);
+
+ /* get pci_dev structure and add host to SCSI ML */
+ error = scsi_add_host_with_dma(shost, &efct->pci->dev,
+ &efct->pci->dev);
+ if (error) {
+ efc_log_debug(efct, "failed scsi_add_host_with_dma\n");
+ return -EIO;
+ }
+
+ /* Set symbolic name for host port */
+ snprintf(fc_host_symbolic_name(shost),
+ sizeof(fc_host_symbolic_name(shost)),
+ "Emulex %s FV%s DV%s", efct->model,
+ efct->hw.sli.fw_name[0], EFCT_DRIVER_VERSION);
+
+ /* Set host port supported classes */
+ fc_host_supported_classes(shost) = FC_COS_CLASS3;
+
+ fc_host_supported_speeds(shost) = efct_get_link_supported_speeds(efct);
+
+ fc_host_node_name(shost) = efct_get_wwnn(&efct->hw);
+ fc_host_port_name(shost) = efct_get_wwpn(&efct->hw);
+ fc_host_max_npiv_vports(shost) = 128;
+
+ return 0;
+}
+
+struct scsi_transport_template *
+efct_attach_fc_transport(void)
+{
+ struct scsi_transport_template *efct_fc_template = NULL;
+
+ efct_fc_template = fc_attach_transport(&efct_xport_functions);
+
+ if (!efct_fc_template)
+ pr_err("failed to attach EFCT with fc transport\n");
+
+ return efct_fc_template;
+}
+
+struct scsi_transport_template *
+efct_attach_vport_fc_transport(void)
+{
+ struct scsi_transport_template *efct_fc_template = NULL;
+
+ efct_fc_template = fc_attach_transport(&efct_vport_functions);
+
+ if (!efct_fc_template)
+ pr_err("failed to attach EFCT with fc transport\n");
+
+ return efct_fc_template;
+}
+
+int
+efct_scsi_reg_fc_transport(void)
+{
+ /* attach to appropriate scsi_tranport_* module */
+ efct_xport_fc_tt = efct_attach_fc_transport();
+ if (!efct_xport_fc_tt) {
+ pr_err("%s: failed to attach to scsi_transport_*", __func__);
+ return -EIO;
+ }
+
+ efct_vport_fc_tt = efct_attach_vport_fc_transport();
+ if (!efct_vport_fc_tt) {
+ pr_err("%s: failed to attach to scsi_transport_*", __func__);
+ efct_release_fc_transport(efct_xport_fc_tt);
+ efct_xport_fc_tt = NULL;
+ return -EIO;
+ }
+
+ return 0;
+}
+
+void
+efct_scsi_release_fc_transport(void)
+{
+ /* detach from scsi_transport_* */
+ efct_release_fc_transport(efct_xport_fc_tt);
+ efct_xport_fc_tt = NULL;
+ if (efct_vport_fc_tt)
+ efct_release_fc_transport(efct_vport_fc_tt);
+
+ efct_vport_fc_tt = NULL;
+}
+
+void
+efct_xport_detach(struct efct_xport *xport)
+{
+ struct efct *efct = xport->efct;
+
+ /* free resources associated with target-server and initiator-client */
+ efct_scsi_tgt_del_device(efct);
+
+ efct_scsi_del_device(efct);
+
+ /*Shutdown FC Statistics timer*/
+ if (timer_pending(&xport->stats_timer))
+ del_timer(&xport->stats_timer);
+
+ efct_hw_teardown(&efct->hw);
+
+ efct_xport_delete_debugfs(efct);
+}
+
+static void
+efct_xport_domain_free_cb(struct efc *efc, void *arg)
+{
+ struct completion *done = arg;
+
+ complete(done);
+}
+
+int
+efct_xport_control(struct efct_xport *xport, enum efct_xport_ctrl cmd, ...)
+{
+ u32 rc = 0;
+ struct efct *efct = NULL;
+ va_list argp;
+
+ efct = xport->efct;
+
+ switch (cmd) {
+ case EFCT_XPORT_PORT_ONLINE: {
+ /* Bring the port on-line */
+ rc = efct_hw_port_control(&efct->hw, EFCT_HW_PORT_INIT, 0,
+ NULL, NULL);
+ if (rc)
+ efc_log_err(efct,
+ "%s: Can't init port\n", efct->desc);
+ else
+ xport->configured_link_state = cmd;
+ break;
+ }
+ case EFCT_XPORT_PORT_OFFLINE: {
+ if (efct_hw_port_control(&efct->hw, EFCT_HW_PORT_SHUTDOWN, 0,
+ NULL, NULL))
+ efc_log_err(efct, "port shutdown failed\n");
+ else
+ xport->configured_link_state = cmd;
+ break;
+ }
+
+ case EFCT_XPORT_SHUTDOWN: {
+ struct completion done;
+ unsigned long timeout;
+
+ /* if a PHYSDEV reset was performed (e.g. hw dump), will affect
+ * all PCI functions; orderly shutdown won't work,
+ * just force free
+ */
+ if (sli_reset_required(&efct->hw.sli)) {
+ struct efc_domain *domain = efct->efcport->domain;
+
+ if (domain)
+ efc_domain_cb(efct->efcport, EFC_HW_DOMAIN_LOST,
+ domain);
+ } else {
+ efct_hw_port_control(&efct->hw, EFCT_HW_PORT_SHUTDOWN,
+ 0, NULL, NULL);
+ }
+
+ init_completion(&done);
+
+ efc_register_domain_free_cb(efct->efcport,
+ efct_xport_domain_free_cb, &done);
+
+ efc_log_debug(efct, "Waiting %d seconds for domain shutdown\n",
+ (EFC_SHUTDOWN_TIMEOUT_USEC / 1000000));
+
+ timeout = usecs_to_jiffies(EFC_SHUTDOWN_TIMEOUT_USEC);
+ if (!wait_for_completion_timeout(&done, timeout)) {
+ efc_log_err(efct, "Domain shutdown timed out!!\n");
+ WARN_ON(1);
+ }
+
+ efc_register_domain_free_cb(efct->efcport, NULL, NULL);
+
+ /* Free up any saved virtual ports */
+ efc_vport_del_all(efct->efcport);
+ break;
+ }
+
+ /*
+ * Set wwnn for the port. This will be used instead of the default
+ * provided by FW.
+ */
+ case EFCT_XPORT_WWNN_SET: {
+ u64 wwnn;
+
+ /* Retrieve arguments */
+ va_start(argp, cmd);
+ wwnn = va_arg(argp, uint64_t);
+ va_end(argp);
+
+ efc_log_debug(efct, " WWNN %016llx\n", wwnn);
+ xport->req_wwnn = wwnn;
+
+ break;
+ }
+ /*
+ * Set wwpn for the port. This will be used instead of the default
+ * provided by FW.
+ */
+ case EFCT_XPORT_WWPN_SET: {
+ u64 wwpn;
+
+ /* Retrieve arguments */
+ va_start(argp, cmd);
+ wwpn = va_arg(argp, uint64_t);
+ va_end(argp);
+
+ efc_log_debug(efct, " WWPN %016llx\n", wwpn);
+ xport->req_wwpn = wwpn;
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ return rc;
+}
+
+void
+efct_xport_free(struct efct_xport *xport)
+{
+ if (xport) {
+ efct_io_pool_free(xport->io_pool);
+
+ kfree(xport);
+ }
+}
+
+void
+efct_release_fc_transport(struct scsi_transport_template *transport_template)
+{
+ if (transport_template)
+ pr_err("releasing transport layer\n");
+
+ /* Releasing FC transport */
+ fc_release_transport(transport_template);
+}
+
+static void
+efct_xport_remove_host(struct Scsi_Host *shost)
+{
+ fc_remove_host(shost);
+}
+
+void
+efct_scsi_del_device(struct efct *efct)
+{
+ if (!efct->shost)
+ return;
+
+ efc_log_debug(efct, "Unregistering with Transport Layer\n");
+ efct_xport_remove_host(efct->shost);
+ efc_log_debug(efct, "Unregistering with SCSI Midlayer\n");
+ scsi_remove_host(efct->shost);
+ scsi_host_put(efct->shost);
+ efct->shost = NULL;
+}
+
+static void
+efct_get_host_port_id(struct Scsi_Host *shost)
+{
+ struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
+ struct efct *efct = vport->efct;
+ struct efc *efc = efct->efcport;
+ struct efc_nport *nport;
+
+ if (efc->domain && efc->domain->nport) {
+ nport = efc->domain->nport;
+ fc_host_port_id(shost) = nport->fc_id;
+ }
+}
+
+static void
+efct_get_host_port_type(struct Scsi_Host *shost)
+{
+ struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
+ struct efct *efct = vport->efct;
+ struct efc *efc = efct->efcport;
+ int type = FC_PORTTYPE_UNKNOWN;
+
+ if (efc->domain && efc->domain->nport) {
+ if (efc->domain->is_loop) {
+ type = FC_PORTTYPE_LPORT;
+ } else {
+ struct efc_nport *nport = efc->domain->nport;
+
+ if (nport->is_vport)
+ type = FC_PORTTYPE_NPIV;
+ else if (nport->topology == EFC_NPORT_TOPO_P2P)
+ type = FC_PORTTYPE_PTP;
+ else if (nport->topology == EFC_NPORT_TOPO_UNKNOWN)
+ type = FC_PORTTYPE_UNKNOWN;
+ else
+ type = FC_PORTTYPE_NPORT;
+ }
+ }
+ fc_host_port_type(shost) = type;
+}
+
+static void
+efct_get_host_vport_type(struct Scsi_Host *shost)
+{
+ fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
+}
+
+static void
+efct_get_host_port_state(struct Scsi_Host *shost)
+{
+ struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
+ struct efct *efct = vport->efct;
+ union efct_xport_stats_u status;
+ int rc;
+
+ rc = efct_xport_status(efct->xport, EFCT_XPORT_PORT_STATUS, &status);
+ if ((!rc) && (status.value == EFCT_XPORT_PORT_ONLINE))
+ fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
+ else
+ fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
+}
+
+static void
+efct_get_host_speed(struct Scsi_Host *shost)
+{
+ struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
+ struct efct *efct = vport->efct;
+ struct efc *efc = efct->efcport;
+ union efct_xport_stats_u speed;
+ u32 fc_speed = FC_PORTSPEED_UNKNOWN;
+ int rc;
+
+ if (!efc->domain || !efc->domain->nport) {
+ fc_host_speed(shost) = fc_speed;
+ return;
+ }
+
+ rc = efct_xport_status(efct->xport, EFCT_XPORT_LINK_SPEED, &speed);
+ if (!rc) {
+ switch (speed.value) {
+ case 1000:
+ fc_speed = FC_PORTSPEED_1GBIT;
+ break;
+ case 2000:
+ fc_speed = FC_PORTSPEED_2GBIT;
+ break;
+ case 4000:
+ fc_speed = FC_PORTSPEED_4GBIT;
+ break;
+ case 8000:
+ fc_speed = FC_PORTSPEED_8GBIT;
+ break;
+ case 10000:
+ fc_speed = FC_PORTSPEED_10GBIT;
+ break;
+ case 16000:
+ fc_speed = FC_PORTSPEED_16GBIT;
+ break;
+ case 32000:
+ fc_speed = FC_PORTSPEED_32GBIT;
+ break;
+ case 64000:
+ fc_speed = FC_PORTSPEED_64GBIT;
+ break;
+ case 128000:
+ fc_speed = FC_PORTSPEED_128GBIT;
+ break;
+ }
+ }
+
+ fc_host_speed(shost) = fc_speed;
+}
+
+static void
+efct_get_host_fabric_name(struct Scsi_Host *shost)
+{
+ struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
+ struct efct *efct = vport->efct;
+ struct efc *efc = efct->efcport;
+
+ if (efc->domain) {
+ struct fc_els_flogi *sp =
+ (struct fc_els_flogi *)
+ efc->domain->flogi_service_params;
+
+ fc_host_fabric_name(shost) = be64_to_cpu(sp->fl_wwnn);
+ }
+}
+
+static struct fc_host_statistics *
+efct_get_stats(struct Scsi_Host *shost)
+{
+ struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
+ struct efct *efct = vport->efct;
+ union efct_xport_stats_u stats;
+ struct efct_xport *xport = efct->xport;
+ int rc = 0;
+
+ rc = efct_xport_status(xport, EFCT_XPORT_LINK_STATISTICS, &stats);
+ if (rc) {
+ pr_err("efct_xport_status returned non 0 - %d\n", rc);
+ return NULL;
+ }
+
+ vport->fc_host_stats.loss_of_sync_count =
+ stats.stats.link_stats.loss_of_sync_error_count;
+ vport->fc_host_stats.link_failure_count =
+ stats.stats.link_stats.link_failure_error_count;
+ vport->fc_host_stats.prim_seq_protocol_err_count =
+ stats.stats.link_stats.primitive_sequence_error_count;
+ vport->fc_host_stats.invalid_tx_word_count =
+ stats.stats.link_stats.invalid_transmission_word_error_count;
+ vport->fc_host_stats.invalid_crc_count =
+ stats.stats.link_stats.crc_error_count;
+ /* mbox returns kbyte count so we need to convert to words */
+ vport->fc_host_stats.tx_words =
+ stats.stats.host_stats.transmit_kbyte_count * 256;
+ /* mbox returns kbyte count so we need to convert to words */
+ vport->fc_host_stats.rx_words =
+ stats.stats.host_stats.receive_kbyte_count * 256;
+ vport->fc_host_stats.tx_frames =
+ stats.stats.host_stats.transmit_frame_count;
+ vport->fc_host_stats.rx_frames =
+ stats.stats.host_stats.receive_frame_count;
+
+ vport->fc_host_stats.fcp_input_requests =
+ xport->fcp_stats.input_requests;
+ vport->fc_host_stats.fcp_output_requests =
+ xport->fcp_stats.output_requests;
+ vport->fc_host_stats.fcp_output_megabytes =
+ xport->fcp_stats.output_bytes >> 20;
+ vport->fc_host_stats.fcp_input_megabytes =
+ xport->fcp_stats.input_bytes >> 20;
+ vport->fc_host_stats.fcp_control_requests =
+ xport->fcp_stats.control_requests;
+
+ return &vport->fc_host_stats;
+}
+
+static void
+efct_reset_stats(struct Scsi_Host *shost)
+{
+ struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
+ struct efct *efct = vport->efct;
+ /* argument has no purpose for this action */
+ union efct_xport_stats_u dummy;
+ int rc;
+
+ rc = efct_xport_status(efct->xport, EFCT_XPORT_LINK_STAT_RESET, &dummy);
+ if (rc)
+ pr_err("efct_xport_status returned non 0 - %d\n", rc);
+}
+
+static int
+efct_issue_lip(struct Scsi_Host *shost)
+{
+ struct efct_vport *vport =
+ shost ? (struct efct_vport *)shost->hostdata : NULL;
+ struct efct *efct = vport ? vport->efct : NULL;
+
+ if (!shost || !vport || !efct) {
+ pr_err("%s: shost=%p vport=%p efct=%p\n", __func__,
+ shost, vport, efct);
+ return -EPERM;
+ }
+
+ /*
+ * Bring the link down gracefully then re-init the link.
+ * The firmware will re-initialize the Fibre Channel interface as
+ * required. It does not issue a LIP.
+ */
+
+ if (efct_xport_control(efct->xport, EFCT_XPORT_PORT_OFFLINE))
+ efc_log_debug(efct, "EFCT_XPORT_PORT_OFFLINE failed\n");
+
+ if (efct_xport_control(efct->xport, EFCT_XPORT_PORT_ONLINE))
+ efc_log_debug(efct, "EFCT_XPORT_PORT_ONLINE failed\n");
+
+ return 0;
+}
+
+struct efct_vport *
+efct_scsi_new_vport(struct efct *efct, struct device *dev)
+{
+ struct Scsi_Host *shost = NULL;
+ int error = 0;
+ struct efct_vport *vport = NULL;
+
+ shost = scsi_host_alloc(&efct_template, sizeof(*vport));
+ if (!shost) {
+ efc_log_err(efct, "failed to allocate Scsi_Host struct\n");
+ return NULL;
+ }
+
+ /* save efct information to shost LLD-specific space */
+ vport = (struct efct_vport *)shost->hostdata;
+ vport->efct = efct;
+ vport->is_vport = true;
+
+ shost->can_queue = efct->hw.config.n_io;
+ shost->max_cmd_len = 16; /* 16-byte CDBs */
+ shost->max_id = 0xffff;
+ shost->max_lun = 0xffffffff;
+
+ /* can only accept (from mid-layer) as many SGEs as we've pre-regited*/
+ shost->sg_tablesize = sli_get_max_sgl(&efct->hw.sli);
+
+ /* attach FC Transport template to shost */
+ shost->transportt = efct_vport_fc_tt;
+ efc_log_debug(efct, "vport transport template=%p\n",
+ efct_vport_fc_tt);
+
+ /* get pci_dev structure and add host to SCSI ML */
+ error = scsi_add_host_with_dma(shost, dev, &efct->pci->dev);
+ if (error) {
+ efc_log_debug(efct, "failed scsi_add_host_with_dma\n");
+ return NULL;
+ }
+
+ /* Set symbolic name for host port */
+ snprintf(fc_host_symbolic_name(shost),
+ sizeof(fc_host_symbolic_name(shost)),
+ "Emulex %s FV%s DV%s", efct->model, efct->hw.sli.fw_name[0],
+ EFCT_DRIVER_VERSION);
+
+ /* Set host port supported classes */
+ fc_host_supported_classes(shost) = FC_COS_CLASS3;
+
+ fc_host_supported_speeds(shost) = efct_get_link_supported_speeds(efct);
+ vport->shost = shost;
+
+ return vport;
+}
+
+int efct_scsi_del_vport(struct efct *efct, struct Scsi_Host *shost)
+{
+ if (shost) {
+ efc_log_debug(efct,
+ "Unregistering vport with Transport Layer\n");
+ efct_xport_remove_host(shost);
+ efc_log_debug(efct, "Unregistering vport with SCSI Midlayer\n");
+ scsi_remove_host(shost);
+ scsi_host_put(shost);
+ return 0;
+ }
+ return -EIO;
+}
+
+static int
+efct_vport_create(struct fc_vport *fc_vport, bool disable)
+{
+ struct Scsi_Host *shost = fc_vport ? fc_vport->shost : NULL;
+ struct efct_vport *pport = shost ?
+ (struct efct_vport *)shost->hostdata :
+ NULL;
+ struct efct *efct = pport ? pport->efct : NULL;
+ struct efct_vport *vport = NULL;
+
+ if (!fc_vport || !shost || !efct)
+ goto fail;
+
+ vport = efct_scsi_new_vport(efct, &fc_vport->dev);
+ if (!vport) {
+ efc_log_err(efct, "failed to create vport\n");
+ goto fail;
+ }
+
+ vport->fc_vport = fc_vport;
+ vport->npiv_wwpn = fc_vport->port_name;
+ vport->npiv_wwnn = fc_vport->node_name;
+ fc_host_node_name(vport->shost) = vport->npiv_wwnn;
+ fc_host_port_name(vport->shost) = vport->npiv_wwpn;
+ *(struct efct_vport **)fc_vport->dd_data = vport;
+
+ return 0;
+
+fail:
+ return -EIO;
+}
+
+static int
+efct_vport_delete(struct fc_vport *fc_vport)
+{
+ struct efct_vport *vport = *(struct efct_vport **)fc_vport->dd_data;
+ struct Scsi_Host *shost = vport ? vport->shost : NULL;
+ struct efct *efct = vport ? vport->efct : NULL;
+ int rc;
+
+ rc = efct_scsi_del_vport(efct, shost);
+
+ if (rc)
+ pr_err("%s: vport delete failed\n", __func__);
+
+ return rc;
+}
+
+static int
+efct_vport_disable(struct fc_vport *fc_vport, bool disable)
+{
+ return 0;
+}
+
+static struct fc_function_template efct_xport_functions = {
+ .get_host_port_id = efct_get_host_port_id,
+ .get_host_port_type = efct_get_host_port_type,
+ .get_host_port_state = efct_get_host_port_state,
+ .get_host_speed = efct_get_host_speed,
+ .get_host_fabric_name = efct_get_host_fabric_name,
+
+ .get_fc_host_stats = efct_get_stats,
+ .reset_fc_host_stats = efct_reset_stats,
+
+ .issue_fc_host_lip = efct_issue_lip,
+
+ .vport_disable = efct_vport_disable,
+
+ /* allocation lengths for host-specific data */
+ .dd_fcrport_size = sizeof(struct efct_rport_data),
+ .dd_fcvport_size = 128, /* should be sizeof(...) */
+
+ /* remote port fixed attributes */
+ .show_rport_maxframe_size = 1,
+ .show_rport_supported_classes = 1,
+ .show_rport_dev_loss_tmo = 1,
+
+ /* target dynamic attributes */
+ .show_starget_node_name = 1,
+ .show_starget_port_name = 1,
+ .show_starget_port_id = 1,
+
+ /* host fixed attributes */
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+ .show_host_supported_fc4s = 1,
+ .show_host_supported_speeds = 1,
+ .show_host_maxframe_size = 1,
+
+ /* host dynamic attributes */
+ .show_host_port_id = 1,
+ .show_host_port_type = 1,
+ .show_host_port_state = 1,
+ /* active_fc4s is shown but doesn't change (thus no get function) */
+ .show_host_active_fc4s = 1,
+ .show_host_speed = 1,
+ .show_host_fabric_name = 1,
+ .show_host_symbolic_name = 1,
+ .vport_create = efct_vport_create,
+ .vport_delete = efct_vport_delete,
+};
+
+static struct fc_function_template efct_vport_functions = {
+ .get_host_port_id = efct_get_host_port_id,
+ .get_host_port_type = efct_get_host_vport_type,
+ .get_host_port_state = efct_get_host_port_state,
+ .get_host_speed = efct_get_host_speed,
+ .get_host_fabric_name = efct_get_host_fabric_name,
+
+ .get_fc_host_stats = efct_get_stats,
+ .reset_fc_host_stats = efct_reset_stats,
+
+ .issue_fc_host_lip = efct_issue_lip,
+
+ /* allocation lengths for host-specific data */
+ .dd_fcrport_size = sizeof(struct efct_rport_data),
+ .dd_fcvport_size = 128, /* should be sizeof(...) */
+
+ /* remote port fixed attributes */
+ .show_rport_maxframe_size = 1,
+ .show_rport_supported_classes = 1,
+ .show_rport_dev_loss_tmo = 1,
+
+ /* target dynamic attributes */
+ .show_starget_node_name = 1,
+ .show_starget_port_name = 1,
+ .show_starget_port_id = 1,
+
+ /* host fixed attributes */
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+ .show_host_supported_fc4s = 1,
+ .show_host_supported_speeds = 1,
+ .show_host_maxframe_size = 1,
+
+ /* host dynamic attributes */
+ .show_host_port_id = 1,
+ .show_host_port_type = 1,
+ .show_host_port_state = 1,
+ /* active_fc4s is shown but doesn't change (thus no get function) */
+ .show_host_active_fc4s = 1,
+ .show_host_speed = 1,
+ .show_host_fabric_name = 1,
+ .show_host_symbolic_name = 1,
+};
diff --git a/drivers/scsi/elx/efct/efct_xport.h b/drivers/scsi/elx/efct/efct_xport.h
new file mode 100644
index 000000000000..89f3c20ecb59
--- /dev/null
+++ b/drivers/scsi/elx/efct/efct_xport.h
@@ -0,0 +1,186 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#if !defined(__EFCT_XPORT_H__)
+#define __EFCT_XPORT_H__
+
+enum efct_xport_ctrl {
+ EFCT_XPORT_PORT_ONLINE = 1,
+ EFCT_XPORT_PORT_OFFLINE,
+ EFCT_XPORT_SHUTDOWN,
+ EFCT_XPORT_POST_NODE_EVENT,
+ EFCT_XPORT_WWNN_SET,
+ EFCT_XPORT_WWPN_SET,
+};
+
+enum efct_xport_status {
+ EFCT_XPORT_PORT_STATUS,
+ EFCT_XPORT_CONFIG_PORT_STATUS,
+ EFCT_XPORT_LINK_SPEED,
+ EFCT_XPORT_IS_SUPPORTED_LINK_SPEED,
+ EFCT_XPORT_LINK_STATISTICS,
+ EFCT_XPORT_LINK_STAT_RESET,
+ EFCT_XPORT_IS_QUIESCED
+};
+
+struct efct_xport_link_stats {
+ bool rec;
+ bool gec;
+ bool w02of;
+ bool w03of;
+ bool w04of;
+ bool w05of;
+ bool w06of;
+ bool w07of;
+ bool w08of;
+ bool w09of;
+ bool w10of;
+ bool w11of;
+ bool w12of;
+ bool w13of;
+ bool w14of;
+ bool w15of;
+ bool w16of;
+ bool w17of;
+ bool w18of;
+ bool w19of;
+ bool w20of;
+ bool w21of;
+ bool clrc;
+ bool clof1;
+ u32 link_failure_error_count;
+ u32 loss_of_sync_error_count;
+ u32 loss_of_signal_error_count;
+ u32 primitive_sequence_error_count;
+ u32 invalid_transmission_word_error_count;
+ u32 crc_error_count;
+ u32 primitive_sequence_event_timeout_count;
+ u32 elastic_buffer_overrun_error_count;
+ u32 arbitration_fc_al_timeout_count;
+ u32 advertised_receive_bufftor_to_buffer_credit;
+ u32 current_receive_buffer_to_buffer_credit;
+ u32 advertised_transmit_buffer_to_buffer_credit;
+ u32 current_transmit_buffer_to_buffer_credit;
+ u32 received_eofa_count;
+ u32 received_eofdti_count;
+ u32 received_eofni_count;
+ u32 received_soff_count;
+ u32 received_dropped_no_aer_count;
+ u32 received_dropped_no_available_rpi_resources_count;
+ u32 received_dropped_no_available_xri_resources_count;
+};
+
+struct efct_xport_host_stats {
+ bool cc;
+ u32 transmit_kbyte_count;
+ u32 receive_kbyte_count;
+ u32 transmit_frame_count;
+ u32 receive_frame_count;
+ u32 transmit_sequence_count;
+ u32 receive_sequence_count;
+ u32 total_exchanges_originator;
+ u32 total_exchanges_responder;
+ u32 receive_p_bsy_count;
+ u32 receive_f_bsy_count;
+ u32 dropped_frames_due_to_no_rq_buffer_count;
+ u32 empty_rq_timeout_count;
+ u32 dropped_frames_due_to_no_xri_count;
+ u32 empty_xri_pool_count;
+};
+
+struct efct_xport_host_statistics {
+ struct completion done;
+ struct efct_xport_link_stats link_stats;
+ struct efct_xport_host_stats host_stats;
+};
+
+union efct_xport_stats_u {
+ u32 value;
+ struct efct_xport_host_statistics stats;
+};
+
+struct efct_xport_fcp_stats {
+ u64 input_bytes;
+ u64 output_bytes;
+ u64 input_requests;
+ u64 output_requests;
+ u64 control_requests;
+};
+
+struct efct_xport {
+ struct efct *efct;
+ /* wwpn requested by user for primary nport */
+ u64 req_wwpn;
+ /* wwnn requested by user for primary nport */
+ u64 req_wwnn;
+
+ /* Nodes */
+ /* number of allocated nodes */
+ u32 nodes_count;
+ /* used to track how often IO pool is empty */
+ atomic_t io_alloc_failed_count;
+ /* array of pointers to nodes */
+ struct efc_node **nodes;
+
+ /* Io pool and counts */
+ /* pointer to IO pool */
+ struct efct_io_pool *io_pool;
+ /* lock for io_pending_list */
+ spinlock_t io_pending_lock;
+ /* list of IOs waiting for HW resources
+ * lock: xport->io_pending_lock
+ * link: efct_io_s->io_pending_link
+ */
+ struct list_head io_pending_list;
+ /* count of totals IOS allocated */
+ atomic_t io_total_alloc;
+ /* count of totals IOS free'd */
+ atomic_t io_total_free;
+ /* count of totals IOS that were pended */
+ atomic_t io_total_pending;
+ /* count of active IOS */
+ atomic_t io_active_count;
+ /* count of pending IOS */
+ atomic_t io_pending_count;
+ /* non-zero if efct_scsi_check_pending is executing */
+ atomic_t io_pending_recursing;
+
+ /* Port */
+ /* requested link state */
+ u32 configured_link_state;
+
+ /* Timer for Statistics */
+ struct timer_list stats_timer;
+ union efct_xport_stats_u fc_xport_stats;
+ struct efct_xport_fcp_stats fcp_stats;
+};
+
+struct efct_rport_data {
+ struct efc_node *node;
+};
+
+struct efct_xport *
+efct_xport_alloc(struct efct *efct);
+int
+efct_xport_attach(struct efct_xport *xport);
+int
+efct_xport_initialize(struct efct_xport *xport);
+void
+efct_xport_detach(struct efct_xport *xport);
+int
+efct_xport_control(struct efct_xport *xport, enum efct_xport_ctrl cmd, ...);
+int
+efct_xport_status(struct efct_xport *xport, enum efct_xport_status cmd,
+ union efct_xport_stats_u *result);
+void
+efct_xport_free(struct efct_xport *xport);
+
+struct scsi_transport_template *efct_attach_fc_transport(void);
+struct scsi_transport_template *efct_attach_vport_fc_transport(void);
+void
+efct_release_fc_transport(struct scsi_transport_template *transport_template);
+
+#endif /* __EFCT_XPORT_H__ */
diff --git a/drivers/scsi/elx/include/efc_common.h b/drivers/scsi/elx/include/efc_common.h
new file mode 100644
index 000000000000..8d57f69ace0a
--- /dev/null
+++ b/drivers/scsi/elx/include/efc_common.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#ifndef __EFC_COMMON_H__
+#define __EFC_COMMON_H__
+
+#include <linux/pci.h>
+
+struct efc_dma {
+ void *virt;
+ void *alloc;
+ dma_addr_t phys;
+
+ size_t size;
+ size_t len;
+ struct pci_dev *pdev;
+};
+
+#define efc_log_crit(efc, fmt, args...) \
+ dev_crit(&((efc)->pci)->dev, fmt, ##args)
+
+#define efc_log_err(efc, fmt, args...) \
+ dev_err(&((efc)->pci)->dev, fmt, ##args)
+
+#define efc_log_warn(efc, fmt, args...) \
+ dev_warn(&((efc)->pci)->dev, fmt, ##args)
+
+#define efc_log_info(efc, fmt, args...) \
+ dev_info(&((efc)->pci)->dev, fmt, ##args)
+
+#define efc_log_debug(efc, fmt, args...) \
+ dev_dbg(&((efc)->pci)->dev, fmt, ##args)
+
+#endif /* __EFC_COMMON_H__ */
diff --git a/drivers/scsi/elx/libefc/efc.h b/drivers/scsi/elx/libefc/efc.h
new file mode 100644
index 000000000000..927016283f41
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#ifndef __EFC_H__
+#define __EFC_H__
+
+#include "../include/efc_common.h"
+#include "efclib.h"
+#include "efc_sm.h"
+#include "efc_cmds.h"
+#include "efc_domain.h"
+#include "efc_nport.h"
+#include "efc_node.h"
+#include "efc_fabric.h"
+#include "efc_device.h"
+#include "efc_els.h"
+
+#define EFC_MAX_REMOTE_NODES 2048
+#define NODE_SPARAMS_SIZE 256
+
+enum efc_scsi_del_initiator_reason {
+ EFC_SCSI_INITIATOR_DELETED,
+ EFC_SCSI_INITIATOR_MISSING,
+};
+
+enum efc_scsi_del_target_reason {
+ EFC_SCSI_TARGET_DELETED,
+ EFC_SCSI_TARGET_MISSING,
+};
+
+#define EFC_FC_ELS_DEFAULT_RETRIES 3
+
+#define domain_sm_trace(domain) \
+ efc_log_debug(domain->efc, "[domain:%s] %-20s %-20s\n", \
+ domain->display_name, __func__, efc_sm_event_name(evt)) \
+
+#define domain_trace(domain, fmt, ...) \
+ efc_log_debug(domain->efc, \
+ "[%s]" fmt, domain->display_name, ##__VA_ARGS__) \
+
+#define node_sm_trace() \
+ efc_log_debug(node->efc, "[%s] %-20s %-20s\n", \
+ node->display_name, __func__, efc_sm_event_name(evt)) \
+
+#define nport_sm_trace(nport) \
+ efc_log_debug(nport->efc, \
+ "[%s] %-20s\n", nport->display_name, efc_sm_event_name(evt)) \
+
+#endif /* __EFC_H__ */
diff --git a/drivers/scsi/elx/libefc/efc_cmds.c b/drivers/scsi/elx/libefc/efc_cmds.c
new file mode 100644
index 000000000000..37e6697d86b8
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_cmds.c
@@ -0,0 +1,777 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#include "efclib.h"
+#include "../libefc_sli/sli4.h"
+#include "efc_cmds.h"
+#include "efc_sm.h"
+
+static void
+efc_nport_free_resources(struct efc_nport *nport, int evt, void *data)
+{
+ struct efc *efc = nport->efc;
+
+ /* Clear the nport attached flag */
+ nport->attached = false;
+
+ /* Free the service parameters buffer */
+ if (nport->dma.virt) {
+ dma_free_coherent(&efc->pci->dev, nport->dma.size,
+ nport->dma.virt, nport->dma.phys);
+ memset(&nport->dma, 0, sizeof(struct efc_dma));
+ }
+
+ /* Free the SLI resources */
+ sli_resource_free(efc->sli, SLI4_RSRC_VPI, nport->indicator);
+
+ efc_nport_cb(efc, evt, nport);
+}
+
+static int
+efc_nport_get_mbox_status(struct efc_nport *nport, u8 *mqe, int status)
+{
+ struct efc *efc = nport->efc;
+ struct sli4_mbox_command_header *hdr =
+ (struct sli4_mbox_command_header *)mqe;
+
+ if (status || le16_to_cpu(hdr->status)) {
+ efc_log_debug(efc, "bad status vpi=%#x st=%x hdr=%x\n",
+ nport->indicator, status, le16_to_cpu(hdr->status));
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int
+efc_nport_free_unreg_vpi_cb(struct efc *efc, int status, u8 *mqe, void *arg)
+{
+ struct efc_nport *nport = arg;
+ int evt = EFC_EVT_NPORT_FREE_OK;
+ int rc;
+
+ rc = efc_nport_get_mbox_status(nport, mqe, status);
+ if (rc)
+ evt = EFC_EVT_NPORT_FREE_FAIL;
+
+ efc_nport_free_resources(nport, evt, mqe);
+ return rc;
+}
+
+static void
+efc_nport_free_unreg_vpi(struct efc_nport *nport)
+{
+ struct efc *efc = nport->efc;
+ int rc;
+ u8 data[SLI4_BMBX_SIZE];
+
+ rc = sli_cmd_unreg_vpi(efc->sli, data, nport->indicator,
+ SLI4_UNREG_TYPE_PORT);
+ if (rc) {
+ efc_log_err(efc, "UNREG_VPI format failure\n");
+ efc_nport_free_resources(nport, EFC_EVT_NPORT_FREE_FAIL, data);
+ return;
+ }
+
+ rc = efc->tt.issue_mbox_rqst(efc->base, data,
+ efc_nport_free_unreg_vpi_cb, nport);
+ if (rc) {
+ efc_log_err(efc, "UNREG_VPI command failure\n");
+ efc_nport_free_resources(nport, EFC_EVT_NPORT_FREE_FAIL, data);
+ }
+}
+
+static void
+efc_nport_send_evt(struct efc_nport *nport, int evt, void *data)
+{
+ struct efc *efc = nport->efc;
+
+ /* Now inform the registered callbacks */
+ efc_nport_cb(efc, evt, nport);
+
+ /* Set the nport attached flag */
+ if (evt == EFC_EVT_NPORT_ATTACH_OK)
+ nport->attached = true;
+
+ /* If there is a pending free request, then handle it now */
+ if (nport->free_req_pending)
+ efc_nport_free_unreg_vpi(nport);
+}
+
+static int
+efc_nport_alloc_init_vpi_cb(struct efc *efc, int status, u8 *mqe, void *arg)
+{
+ struct efc_nport *nport = arg;
+
+ if (efc_nport_get_mbox_status(nport, mqe, status)) {
+ efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, mqe);
+ return -EIO;
+ }
+
+ efc_nport_send_evt(nport, EFC_EVT_NPORT_ALLOC_OK, mqe);
+ return 0;
+}
+
+static void
+efc_nport_alloc_init_vpi(struct efc_nport *nport)
+{
+ struct efc *efc = nport->efc;
+ u8 data[SLI4_BMBX_SIZE];
+ int rc;
+
+ /* If there is a pending free request, then handle it now */
+ if (nport->free_req_pending) {
+ efc_nport_free_resources(nport, EFC_EVT_NPORT_FREE_OK, data);
+ return;
+ }
+
+ rc = sli_cmd_init_vpi(efc->sli, data,
+ nport->indicator, nport->domain->indicator);
+ if (rc) {
+ efc_log_err(efc, "INIT_VPI format failure\n");
+ efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, data);
+ return;
+ }
+
+ rc = efc->tt.issue_mbox_rqst(efc->base, data,
+ efc_nport_alloc_init_vpi_cb, nport);
+ if (rc) {
+ efc_log_err(efc, "INIT_VPI command failure\n");
+ efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, data);
+ }
+}
+
+static int
+efc_nport_alloc_read_sparm64_cb(struct efc *efc, int status, u8 *mqe, void *arg)
+{
+ struct efc_nport *nport = arg;
+ u8 *payload = NULL;
+
+ if (efc_nport_get_mbox_status(nport, mqe, status)) {
+ efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, mqe);
+ return -EIO;
+ }
+
+ payload = nport->dma.virt;
+
+ memcpy(&nport->sli_wwpn, payload + SLI4_READ_SPARM64_WWPN_OFFSET,
+ sizeof(nport->sli_wwpn));
+ memcpy(&nport->sli_wwnn, payload + SLI4_READ_SPARM64_WWNN_OFFSET,
+ sizeof(nport->sli_wwnn));
+
+ dma_free_coherent(&efc->pci->dev, nport->dma.size, nport->dma.virt,
+ nport->dma.phys);
+ memset(&nport->dma, 0, sizeof(struct efc_dma));
+ efc_nport_alloc_init_vpi(nport);
+ return 0;
+}
+
+static void
+efc_nport_alloc_read_sparm64(struct efc *efc, struct efc_nport *nport)
+{
+ u8 data[SLI4_BMBX_SIZE];
+ int rc;
+
+ /* Allocate memory for the service parameters */
+ nport->dma.size = EFC_SPARAM_DMA_SZ;
+ nport->dma.virt = dma_alloc_coherent(&efc->pci->dev,
+ nport->dma.size, &nport->dma.phys,
+ GFP_DMA);
+ if (!nport->dma.virt) {
+ efc_log_err(efc, "Failed to allocate DMA memory\n");
+ efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, data);
+ return;
+ }
+
+ rc = sli_cmd_read_sparm64(efc->sli, data,
+ &nport->dma, nport->indicator);
+ if (rc) {
+ efc_log_err(efc, "READ_SPARM64 format failure\n");
+ efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, data);
+ return;
+ }
+
+ rc = efc->tt.issue_mbox_rqst(efc->base, data,
+ efc_nport_alloc_read_sparm64_cb, nport);
+ if (rc) {
+ efc_log_err(efc, "READ_SPARM64 command failure\n");
+ efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, data);
+ }
+}
+
+int
+efc_cmd_nport_alloc(struct efc *efc, struct efc_nport *nport,
+ struct efc_domain *domain, u8 *wwpn)
+{
+ u32 index;
+
+ nport->indicator = U32_MAX;
+ nport->free_req_pending = false;
+
+ if (wwpn)
+ memcpy(&nport->sli_wwpn, wwpn, sizeof(nport->sli_wwpn));
+
+ /*
+ * allocate a VPI object for the port and stores it in the
+ * indicator field of the port object.
+ */
+ if (sli_resource_alloc(efc->sli, SLI4_RSRC_VPI,
+ &nport->indicator, &index)) {
+ efc_log_err(efc, "VPI allocation failure\n");
+ return -EIO;
+ }
+
+ if (domain) {
+ /*
+ * If the WWPN is NULL, fetch the default
+ * WWPN and WWNN before initializing the VPI
+ */
+ if (!wwpn)
+ efc_nport_alloc_read_sparm64(efc, nport);
+ else
+ efc_nport_alloc_init_vpi(nport);
+ } else if (!wwpn) {
+ /* domain NULL and wwpn non-NULL */
+ efc_log_err(efc, "need WWN for physical port\n");
+ sli_resource_free(efc->sli, SLI4_RSRC_VPI, nport->indicator);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int
+efc_nport_attach_reg_vpi_cb(struct efc *efc, int status, u8 *mqe,
+ void *arg)
+{
+ struct efc_nport *nport = arg;
+
+ if (efc_nport_get_mbox_status(nport, mqe, status)) {
+ efc_nport_free_resources(nport, EFC_EVT_NPORT_ATTACH_FAIL, mqe);
+ return -EIO;
+ }
+
+ efc_nport_send_evt(nport, EFC_EVT_NPORT_ATTACH_OK, mqe);
+ return 0;
+}
+
+int
+efc_cmd_nport_attach(struct efc *efc, struct efc_nport *nport, u32 fc_id)
+{
+ u8 buf[SLI4_BMBX_SIZE];
+ int rc = 0;
+
+ if (!nport) {
+ efc_log_err(efc, "bad param(s) nport=%p\n", nport);
+ return -EIO;
+ }
+
+ nport->fc_id = fc_id;
+
+ /* register previously-allocated VPI with the device */
+ rc = sli_cmd_reg_vpi(efc->sli, buf, nport->fc_id,
+ nport->sli_wwpn, nport->indicator,
+ nport->domain->indicator, false);
+ if (rc) {
+ efc_log_err(efc, "REG_VPI format failure\n");
+ efc_nport_free_resources(nport, EFC_EVT_NPORT_ATTACH_FAIL, buf);
+ return rc;
+ }
+
+ rc = efc->tt.issue_mbox_rqst(efc->base, buf,
+ efc_nport_attach_reg_vpi_cb, nport);
+ if (rc) {
+ efc_log_err(efc, "REG_VPI command failure\n");
+ efc_nport_free_resources(nport, EFC_EVT_NPORT_ATTACH_FAIL, buf);
+ }
+
+ return rc;
+}
+
+int
+efc_cmd_nport_free(struct efc *efc, struct efc_nport *nport)
+{
+ if (!nport) {
+ efc_log_err(efc, "bad parameter(s) nport=%p\n", nport);
+ return -EIO;
+ }
+
+ /* Issue the UNREG_VPI command to free the assigned VPI context */
+ if (nport->attached)
+ efc_nport_free_unreg_vpi(nport);
+ else
+ nport->free_req_pending = true;
+
+ return 0;
+}
+
+static int
+efc_domain_get_mbox_status(struct efc_domain *domain, u8 *mqe, int status)
+{
+ struct efc *efc = domain->efc;
+ struct sli4_mbox_command_header *hdr =
+ (struct sli4_mbox_command_header *)mqe;
+
+ if (status || le16_to_cpu(hdr->status)) {
+ efc_log_debug(efc, "bad status vfi=%#x st=%x hdr=%x\n",
+ domain->indicator, status,
+ le16_to_cpu(hdr->status));
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void
+efc_domain_free_resources(struct efc_domain *domain, int evt, void *data)
+{
+ struct efc *efc = domain->efc;
+
+ /* Free the service parameters buffer */
+ if (domain->dma.virt) {
+ dma_free_coherent(&efc->pci->dev,
+ domain->dma.size, domain->dma.virt,
+ domain->dma.phys);
+ memset(&domain->dma, 0, sizeof(struct efc_dma));
+ }
+
+ /* Free the SLI resources */
+ sli_resource_free(efc->sli, SLI4_RSRC_VFI, domain->indicator);
+
+ efc_domain_cb(efc, evt, domain);
+}
+
+static void
+efc_domain_send_nport_evt(struct efc_domain *domain,
+ int port_evt, int domain_evt, void *data)
+{
+ struct efc *efc = domain->efc;
+
+ /* Send alloc/attach ok to the physical nport */
+ efc_nport_send_evt(domain->nport, port_evt, NULL);
+
+ /* Now inform the registered callbacks */
+ efc_domain_cb(efc, domain_evt, domain);
+}
+
+static int
+efc_domain_alloc_read_sparm64_cb(struct efc *efc, int status, u8 *mqe,
+ void *arg)
+{
+ struct efc_domain *domain = arg;
+
+ if (efc_domain_get_mbox_status(domain, mqe, status)) {
+ efc_domain_free_resources(domain,
+ EFC_HW_DOMAIN_ALLOC_FAIL, mqe);
+ return -EIO;
+ }
+
+ efc_domain_send_nport_evt(domain, EFC_EVT_NPORT_ALLOC_OK,
+ EFC_HW_DOMAIN_ALLOC_OK, mqe);
+ return 0;
+}
+
+static void
+efc_domain_alloc_read_sparm64(struct efc_domain *domain)
+{
+ struct efc *efc = domain->efc;
+ u8 data[SLI4_BMBX_SIZE];
+ int rc;
+
+ rc = sli_cmd_read_sparm64(efc->sli, data, &domain->dma, 0);
+ if (rc) {
+ efc_log_err(efc, "READ_SPARM64 format failure\n");
+ efc_domain_free_resources(domain,
+ EFC_HW_DOMAIN_ALLOC_FAIL, data);
+ return;
+ }
+
+ rc = efc->tt.issue_mbox_rqst(efc->base, data,
+ efc_domain_alloc_read_sparm64_cb, domain);
+ if (rc) {
+ efc_log_err(efc, "READ_SPARM64 command failure\n");
+ efc_domain_free_resources(domain,
+ EFC_HW_DOMAIN_ALLOC_FAIL, data);
+ }
+}
+
+static int
+efc_domain_alloc_init_vfi_cb(struct efc *efc, int status, u8 *mqe,
+ void *arg)
+{
+ struct efc_domain *domain = arg;
+
+ if (efc_domain_get_mbox_status(domain, mqe, status)) {
+ efc_domain_free_resources(domain,
+ EFC_HW_DOMAIN_ALLOC_FAIL, mqe);
+ return -EIO;
+ }
+
+ efc_domain_alloc_read_sparm64(domain);
+ return 0;
+}
+
+static void
+efc_domain_alloc_init_vfi(struct efc_domain *domain)
+{
+ struct efc *efc = domain->efc;
+ struct efc_nport *nport = domain->nport;
+ u8 data[SLI4_BMBX_SIZE];
+ int rc;
+
+ /*
+ * For FC, the HW alread registered an FCFI.
+ * Copy FCF information into the domain and jump to INIT_VFI.
+ */
+ domain->fcf_indicator = efc->fcfi;
+ rc = sli_cmd_init_vfi(efc->sli, data, domain->indicator,
+ domain->fcf_indicator, nport->indicator);
+ if (rc) {
+ efc_log_err(efc, "INIT_VFI format failure\n");
+ efc_domain_free_resources(domain,
+ EFC_HW_DOMAIN_ALLOC_FAIL, data);
+ return;
+ }
+
+ efc_log_err(efc, "%s issue mbox\n", __func__);
+ rc = efc->tt.issue_mbox_rqst(efc->base, data,
+ efc_domain_alloc_init_vfi_cb, domain);
+ if (rc) {
+ efc_log_err(efc, "INIT_VFI command failure\n");
+ efc_domain_free_resources(domain,
+ EFC_HW_DOMAIN_ALLOC_FAIL, data);
+ }
+}
+
+int
+efc_cmd_domain_alloc(struct efc *efc, struct efc_domain *domain, u32 fcf)
+{
+ u32 index;
+
+ if (!domain || !domain->nport) {
+ efc_log_err(efc, "bad parameter(s) domain=%p nport=%p\n",
+ domain, domain ? domain->nport : NULL);
+ return -EIO;
+ }
+
+ /* allocate memory for the service parameters */
+ domain->dma.size = EFC_SPARAM_DMA_SZ;
+ domain->dma.virt = dma_alloc_coherent(&efc->pci->dev,
+ domain->dma.size,
+ &domain->dma.phys, GFP_DMA);
+ if (!domain->dma.virt) {
+ efc_log_err(efc, "Failed to allocate DMA memory\n");
+ return -EIO;
+ }
+
+ domain->fcf = fcf;
+ domain->fcf_indicator = U32_MAX;
+ domain->indicator = U32_MAX;
+
+ if (sli_resource_alloc(efc->sli, SLI4_RSRC_VFI, &domain->indicator,
+ &index)) {
+ efc_log_err(efc, "VFI allocation failure\n");
+
+ dma_free_coherent(&efc->pci->dev,
+ domain->dma.size, domain->dma.virt,
+ domain->dma.phys);
+ memset(&domain->dma, 0, sizeof(struct efc_dma));
+
+ return -EIO;
+ }
+
+ efc_domain_alloc_init_vfi(domain);
+ return 0;
+}
+
+static int
+efc_domain_attach_reg_vfi_cb(struct efc *efc, int status, u8 *mqe,
+ void *arg)
+{
+ struct efc_domain *domain = arg;
+
+ if (efc_domain_get_mbox_status(domain, mqe, status)) {
+ efc_domain_free_resources(domain,
+ EFC_HW_DOMAIN_ATTACH_FAIL, mqe);
+ return -EIO;
+ }
+
+ efc_domain_send_nport_evt(domain, EFC_EVT_NPORT_ATTACH_OK,
+ EFC_HW_DOMAIN_ATTACH_OK, mqe);
+ return 0;
+}
+
+int
+efc_cmd_domain_attach(struct efc *efc, struct efc_domain *domain, u32 fc_id)
+{
+ u8 buf[SLI4_BMBX_SIZE];
+ int rc = 0;
+
+ if (!domain) {
+ efc_log_err(efc, "bad param(s) domain=%p\n", domain);
+ return -EIO;
+ }
+
+ domain->nport->fc_id = fc_id;
+
+ rc = sli_cmd_reg_vfi(efc->sli, buf, SLI4_BMBX_SIZE, domain->indicator,
+ domain->fcf_indicator, domain->dma,
+ domain->nport->indicator, domain->nport->sli_wwpn,
+ domain->nport->fc_id);
+ if (rc) {
+ efc_log_err(efc, "REG_VFI format failure\n");
+ goto cleanup;
+ }
+
+ rc = efc->tt.issue_mbox_rqst(efc->base, buf,
+ efc_domain_attach_reg_vfi_cb, domain);
+ if (rc) {
+ efc_log_err(efc, "REG_VFI command failure\n");
+ goto cleanup;
+ }
+
+ return rc;
+
+cleanup:
+ efc_domain_free_resources(domain, EFC_HW_DOMAIN_ATTACH_FAIL, buf);
+
+ return rc;
+}
+
+static int
+efc_domain_free_unreg_vfi_cb(struct efc *efc, int status, u8 *mqe, void *arg)
+{
+ struct efc_domain *domain = arg;
+ int evt = EFC_HW_DOMAIN_FREE_OK;
+ int rc;
+
+ rc = efc_domain_get_mbox_status(domain, mqe, status);
+ if (rc) {
+ evt = EFC_HW_DOMAIN_FREE_FAIL;
+ rc = -EIO;
+ }
+
+ efc_domain_free_resources(domain, evt, mqe);
+ return rc;
+}
+
+static void
+efc_domain_free_unreg_vfi(struct efc_domain *domain)
+{
+ struct efc *efc = domain->efc;
+ int rc;
+ u8 data[SLI4_BMBX_SIZE];
+
+ rc = sli_cmd_unreg_vfi(efc->sli, data, domain->indicator,
+ SLI4_UNREG_TYPE_DOMAIN);
+ if (rc) {
+ efc_log_err(efc, "UNREG_VFI format failure\n");
+ goto cleanup;
+ }
+
+ rc = efc->tt.issue_mbox_rqst(efc->base, data,
+ efc_domain_free_unreg_vfi_cb, domain);
+ if (rc) {
+ efc_log_err(efc, "UNREG_VFI command failure\n");
+ goto cleanup;
+ }
+
+ return;
+
+cleanup:
+ efc_domain_free_resources(domain, EFC_HW_DOMAIN_FREE_FAIL, data);
+}
+
+int
+efc_cmd_domain_free(struct efc *efc, struct efc_domain *domain)
+{
+ if (!domain) {
+ efc_log_err(efc, "bad parameter(s) domain=%p\n", domain);
+ return -EIO;
+ }
+
+ efc_domain_free_unreg_vfi(domain);
+ return 0;
+}
+
+int
+efc_cmd_node_alloc(struct efc *efc, struct efc_remote_node *rnode, u32 fc_addr,
+ struct efc_nport *nport)
+{
+ /* Check for invalid indicator */
+ if (rnode->indicator != U32_MAX) {
+ efc_log_err(efc,
+ "RPI allocation failure addr=%#x rpi=%#x\n",
+ fc_addr, rnode->indicator);
+ return -EIO;
+ }
+
+ /* NULL SLI port indicates an unallocated remote node */
+ rnode->nport = NULL;
+
+ if (sli_resource_alloc(efc->sli, SLI4_RSRC_RPI,
+ &rnode->indicator, &rnode->index)) {
+ efc_log_err(efc, "RPI allocation failure addr=%#x\n",
+ fc_addr);
+ return -EIO;
+ }
+
+ rnode->fc_id = fc_addr;
+ rnode->nport = nport;
+
+ return 0;
+}
+
+static int
+efc_cmd_node_attach_cb(struct efc *efc, int status, u8 *mqe, void *arg)
+{
+ struct efc_remote_node *rnode = arg;
+ struct sli4_mbox_command_header *hdr =
+ (struct sli4_mbox_command_header *)mqe;
+ int evt = 0;
+
+ if (status || le16_to_cpu(hdr->status)) {
+ efc_log_debug(efc, "bad status cqe=%#x mqe=%#x\n", status,
+ le16_to_cpu(hdr->status));
+ rnode->attached = false;
+ evt = EFC_EVT_NODE_ATTACH_FAIL;
+ } else {
+ rnode->attached = true;
+ evt = EFC_EVT_NODE_ATTACH_OK;
+ }
+
+ efc_remote_node_cb(efc, evt, rnode);
+
+ return 0;
+}
+
+int
+efc_cmd_node_attach(struct efc *efc, struct efc_remote_node *rnode,
+ struct efc_dma *sparms)
+{
+ int rc = -EIO;
+ u8 buf[SLI4_BMBX_SIZE];
+
+ if (!rnode || !sparms) {
+ efc_log_err(efc, "bad parameter(s) rnode=%p sparms=%p\n",
+ rnode, sparms);
+ return -EIO;
+ }
+
+ /*
+ * If the attach count is non-zero, this RPI has already been reg'd.
+ * Otherwise, register the RPI
+ */
+ if (rnode->index == U32_MAX) {
+ efc_log_err(efc, "bad parameter rnode->index invalid\n");
+ return -EIO;
+ }
+
+ /* Update a remote node object with the remote port's service params */
+ if (!sli_cmd_reg_rpi(efc->sli, buf, rnode->indicator,
+ rnode->nport->indicator, rnode->fc_id, sparms, 0, 0))
+ rc = efc->tt.issue_mbox_rqst(efc->base, buf,
+ efc_cmd_node_attach_cb, rnode);
+
+ return rc;
+}
+
+int
+efc_node_free_resources(struct efc *efc, struct efc_remote_node *rnode)
+{
+ int rc = 0;
+
+ if (!rnode) {
+ efc_log_err(efc, "bad parameter rnode=%p\n", rnode);
+ return -EIO;
+ }
+
+ if (rnode->nport) {
+ if (rnode->attached) {
+ efc_log_err(efc, "rnode is still attached\n");
+ return -EIO;
+ }
+ if (rnode->indicator != U32_MAX) {
+ if (sli_resource_free(efc->sli, SLI4_RSRC_RPI,
+ rnode->indicator)) {
+ efc_log_err(efc,
+ "RPI free fail RPI %d addr=%#x\n",
+ rnode->indicator, rnode->fc_id);
+ rc = -EIO;
+ } else {
+ rnode->indicator = U32_MAX;
+ rnode->index = U32_MAX;
+ }
+ }
+ }
+
+ return rc;
+}
+
+static int
+efc_cmd_node_free_cb(struct efc *efc, int status, u8 *mqe, void *arg)
+{
+ struct efc_remote_node *rnode = arg;
+ struct sli4_mbox_command_header *hdr =
+ (struct sli4_mbox_command_header *)mqe;
+ int evt = EFC_EVT_NODE_FREE_FAIL;
+ int rc = 0;
+
+ if (status || le16_to_cpu(hdr->status)) {
+ efc_log_debug(efc, "bad status cqe=%#x mqe=%#x\n", status,
+ le16_to_cpu(hdr->status));
+
+ /*
+ * In certain cases, a non-zero MQE status is OK (all must be
+ * true):
+ * - node is attached
+ * - status is 0x1400
+ */
+ if (!rnode->attached ||
+ (le16_to_cpu(hdr->status) != SLI4_MBX_STATUS_RPI_NOT_REG))
+ rc = -EIO;
+ }
+
+ if (!rc) {
+ rnode->attached = false;
+ evt = EFC_EVT_NODE_FREE_OK;
+ }
+
+ efc_remote_node_cb(efc, evt, rnode);
+
+ return rc;
+}
+
+int
+efc_cmd_node_detach(struct efc *efc, struct efc_remote_node *rnode)
+{
+ u8 buf[SLI4_BMBX_SIZE];
+ int rc = -EIO;
+
+ if (!rnode) {
+ efc_log_err(efc, "bad parameter rnode=%p\n", rnode);
+ return -EIO;
+ }
+
+ if (rnode->nport) {
+ if (!rnode->attached)
+ return -EIO;
+
+ rc = -EIO;
+
+ if (!sli_cmd_unreg_rpi(efc->sli, buf, rnode->indicator,
+ SLI4_RSRC_RPI, U32_MAX))
+ rc = efc->tt.issue_mbox_rqst(efc->base, buf,
+ efc_cmd_node_free_cb, rnode);
+
+ if (rc != 0) {
+ efc_log_err(efc, "UNREG_RPI failed\n");
+ rc = -EIO;
+ }
+ }
+
+ return rc;
+}
diff --git a/drivers/scsi/elx/libefc/efc_cmds.h b/drivers/scsi/elx/libefc/efc_cmds.h
new file mode 100644
index 000000000000..4d353ab04dc3
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_cmds.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#ifndef __EFC_CMDS_H__
+#define __EFC_CMDS_H__
+
+#define EFC_SPARAM_DMA_SZ 112
+int
+efc_cmd_nport_alloc(struct efc *efc, struct efc_nport *nport,
+ struct efc_domain *domain, u8 *wwpn);
+int
+efc_cmd_nport_attach(struct efc *efc, struct efc_nport *nport, u32 fc_id);
+int
+efc_cmd_nport_free(struct efc *efc, struct efc_nport *nport);
+int
+efc_cmd_domain_alloc(struct efc *efc, struct efc_domain *domain, u32 fcf);
+int
+efc_cmd_domain_attach(struct efc *efc, struct efc_domain *domain, u32 fc_id);
+int
+efc_cmd_domain_free(struct efc *efc, struct efc_domain *domain);
+int
+efc_cmd_node_detach(struct efc *efc, struct efc_remote_node *rnode);
+int
+efc_node_free_resources(struct efc *efc, struct efc_remote_node *rnode);
+int
+efc_cmd_node_attach(struct efc *efc, struct efc_remote_node *rnode,
+ struct efc_dma *sparms);
+int
+efc_cmd_node_alloc(struct efc *efc, struct efc_remote_node *rnode, u32 fc_addr,
+ struct efc_nport *nport);
+
+#endif /* __EFC_CMDS_H */
diff --git a/drivers/scsi/elx/libefc/efc_device.c b/drivers/scsi/elx/libefc/efc_device.c
new file mode 100644
index 000000000000..725ca2a23fb2
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_device.c
@@ -0,0 +1,1603 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+/*
+ * device_sm Node State Machine: Remote Device States
+ */
+
+#include "efc.h"
+#include "efc_device.h"
+#include "efc_fabric.h"
+
+void
+efc_d_send_prli_rsp(struct efc_node *node, u16 ox_id)
+{
+ int rc = EFC_SCSI_CALL_COMPLETE;
+ struct efc *efc = node->efc;
+
+ node->ls_acc_oxid = ox_id;
+ node->send_ls_acc = EFC_NODE_SEND_LS_ACC_PRLI;
+
+ /*
+ * Wait for backend session registration
+ * to complete before sending PRLI resp
+ */
+
+ if (node->init) {
+ efc_log_info(efc, "[%s] found(initiator) WWPN:%s WWNN:%s\n",
+ node->display_name, node->wwpn, node->wwnn);
+ if (node->nport->enable_tgt)
+ rc = efc->tt.scsi_new_node(efc, node);
+ }
+
+ if (rc < 0)
+ efc_node_post_event(node, EFC_EVT_NODE_SESS_REG_FAIL, NULL);
+
+ if (rc == EFC_SCSI_CALL_COMPLETE)
+ efc_node_post_event(node, EFC_EVT_NODE_SESS_REG_OK, NULL);
+}
+
+static void
+__efc_d_common(const char *funcname, struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = NULL;
+ struct efc *efc = NULL;
+
+ node = ctx->app;
+ efc = node->efc;
+
+ switch (evt) {
+ /* Handle shutdown events */
+ case EFC_EVT_SHUTDOWN:
+ efc_log_debug(efc, "[%s] %-20s %-20s\n", node->display_name,
+ funcname, efc_sm_event_name(evt));
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
+ break;
+ case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
+ efc_log_debug(efc, "[%s] %-20s %-20s\n",
+ node->display_name, funcname,
+ efc_sm_event_name(evt));
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_EXPLICIT_LOGO;
+ efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
+ break;
+ case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
+ efc_log_debug(efc, "[%s] %-20s %-20s\n", node->display_name,
+ funcname, efc_sm_event_name(evt));
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_IMPLICIT_LOGO;
+ efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
+ break;
+
+ default:
+ /* call default event handler common to all nodes */
+ __efc_node_common(funcname, ctx, evt, arg);
+ }
+}
+
+static void
+__efc_d_wait_del_node(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ /*
+ * State is entered when a node sends a delete initiator/target call
+ * to the target-server/initiator-client and needs to wait for that
+ * work to complete.
+ */
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ fallthrough;
+
+ case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
+ case EFC_EVT_ALL_CHILD_NODES_FREE:
+ /* These are expected events. */
+ break;
+
+ case EFC_EVT_NODE_DEL_INI_COMPLETE:
+ case EFC_EVT_NODE_DEL_TGT_COMPLETE:
+ /*
+ * node has either been detached or is in the process
+ * of being detached,
+ * call common node's initiate cleanup function
+ */
+ efc_node_initiate_cleanup(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_SRRS_ELS_REQ_FAIL:
+ /* Can happen as ELS IO IO's complete */
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ break;
+
+ /* ignore shutdown events as we're already in shutdown path */
+ case EFC_EVT_SHUTDOWN:
+ /* have default shutdown event take precedence */
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ fallthrough;
+
+ case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
+ case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
+ node_printf(node, "%s received\n", efc_sm_event_name(evt));
+ break;
+ case EFC_EVT_DOMAIN_ATTACH_OK:
+ /* don't care about domain_attach_ok */
+ break;
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+static void
+__efc_d_wait_del_ini_tgt(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ fallthrough;
+
+ case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
+ case EFC_EVT_ALL_CHILD_NODES_FREE:
+ /* These are expected events. */
+ break;
+
+ case EFC_EVT_NODE_DEL_INI_COMPLETE:
+ case EFC_EVT_NODE_DEL_TGT_COMPLETE:
+ efc_node_transition(node, __efc_d_wait_del_node, NULL);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_SRRS_ELS_REQ_FAIL:
+ /* Can happen as ELS IO IO's complete */
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ break;
+
+ /* ignore shutdown events as we're already in shutdown path */
+ case EFC_EVT_SHUTDOWN:
+ /* have default shutdown event take precedence */
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ fallthrough;
+
+ case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
+ case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
+ node_printf(node, "%s received\n", efc_sm_event_name(evt));
+ break;
+ case EFC_EVT_DOMAIN_ATTACH_OK:
+ /* don't care about domain_attach_ok */
+ break;
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_d_initiate_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+ struct efc *efc = node->efc;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER: {
+ int rc = EFC_SCSI_CALL_COMPLETE;
+
+ /* assume no wait needed */
+ node->els_io_enabled = false;
+
+ /* make necessary delete upcall(s) */
+ if (node->init && !node->targ) {
+ efc_log_info(node->efc,
+ "[%s] delete (initiator) WWPN %s WWNN %s\n",
+ node->display_name,
+ node->wwpn, node->wwnn);
+ efc_node_transition(node,
+ __efc_d_wait_del_node,
+ NULL);
+ if (node->nport->enable_tgt)
+ rc = efc->tt.scsi_del_node(efc, node,
+ EFC_SCSI_INITIATOR_DELETED);
+
+ if (rc == EFC_SCSI_CALL_COMPLETE || rc < 0)
+ efc_node_post_event(node,
+ EFC_EVT_NODE_DEL_INI_COMPLETE, NULL);
+
+ } else if (node->targ && !node->init) {
+ efc_log_info(node->efc,
+ "[%s] delete (target) WWPN %s WWNN %s\n",
+ node->display_name,
+ node->wwpn, node->wwnn);
+ efc_node_transition(node,
+ __efc_d_wait_del_node,
+ NULL);
+ if (node->nport->enable_ini)
+ rc = efc->tt.scsi_del_node(efc, node,
+ EFC_SCSI_TARGET_DELETED);
+
+ if (rc == EFC_SCSI_CALL_COMPLETE)
+ efc_node_post_event(node,
+ EFC_EVT_NODE_DEL_TGT_COMPLETE, NULL);
+
+ } else if (node->init && node->targ) {
+ efc_log_info(node->efc,
+ "[%s] delete (I+T) WWPN %s WWNN %s\n",
+ node->display_name, node->wwpn, node->wwnn);
+ efc_node_transition(node, __efc_d_wait_del_ini_tgt,
+ NULL);
+ if (node->nport->enable_tgt)
+ rc = efc->tt.scsi_del_node(efc, node,
+ EFC_SCSI_INITIATOR_DELETED);
+
+ if (rc == EFC_SCSI_CALL_COMPLETE)
+ efc_node_post_event(node,
+ EFC_EVT_NODE_DEL_INI_COMPLETE, NULL);
+ /* assume no wait needed */
+ rc = EFC_SCSI_CALL_COMPLETE;
+ if (node->nport->enable_ini)
+ rc = efc->tt.scsi_del_node(efc, node,
+ EFC_SCSI_TARGET_DELETED);
+
+ if (rc == EFC_SCSI_CALL_COMPLETE)
+ efc_node_post_event(node,
+ EFC_EVT_NODE_DEL_TGT_COMPLETE, NULL);
+ }
+
+ /* we've initiated the upcalls as needed, now kick off the node
+ * detach to precipitate the aborting of outstanding exchanges
+ * associated with said node
+ *
+ * Beware: if we've made upcall(s), we've already transitioned
+ * to a new state by the time we execute this.
+ * consider doing this before the upcalls?
+ */
+ if (node->attached) {
+ /* issue hw node free; don't care if succeeds right
+ * away or sometime later, will check node->attached
+ * later in shutdown process
+ */
+ rc = efc_cmd_node_detach(efc, &node->rnode);
+ if (rc < 0)
+ node_printf(node,
+ "Failed freeing HW node, rc=%d\n",
+ rc);
+ }
+
+ /* if neither initiator nor target, proceed to cleanup */
+ if (!node->init && !node->targ) {
+ /*
+ * node has either been detached or is in
+ * the process of being detached,
+ * call common node's initiate cleanup function
+ */
+ efc_node_initiate_cleanup(node);
+ }
+ break;
+ }
+ case EFC_EVT_ALL_CHILD_NODES_FREE:
+ /* Ignore, this can happen if an ELS is
+ * aborted while in a delay/retry state
+ */
+ break;
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_d_wait_loop(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_DOMAIN_ATTACH_OK: {
+ /* send PLOGI automatically if initiator */
+ efc_node_init_device(node, true);
+ break;
+ }
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+efc_send_ls_acc_after_attach(struct efc_node *node,
+ struct fc_frame_header *hdr,
+ enum efc_node_send_ls_acc ls)
+{
+ u16 ox_id = be16_to_cpu(hdr->fh_ox_id);
+
+ /* Save the OX_ID for sending LS_ACC sometime later */
+ WARN_ON(node->send_ls_acc != EFC_NODE_SEND_LS_ACC_NONE);
+
+ node->ls_acc_oxid = ox_id;
+ node->send_ls_acc = ls;
+ node->ls_acc_did = ntoh24(hdr->fh_d_id);
+}
+
+void
+efc_process_prli_payload(struct efc_node *node, void *prli)
+{
+ struct {
+ struct fc_els_prli prli;
+ struct fc_els_spp sp;
+ } *pp;
+
+ pp = prli;
+ node->init = (pp->sp.spp_flags & FCP_SPPF_INIT_FCN) != 0;
+ node->targ = (pp->sp.spp_flags & FCP_SPPF_TARG_FCN) != 0;
+}
+
+void
+__efc_d_wait_plogi_acc_cmpl(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_SRRS_ELS_CMPL_FAIL:
+ WARN_ON(!node->els_cmpl_cnt);
+ node->els_cmpl_cnt--;
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
+ break;
+
+ case EFC_EVT_SRRS_ELS_CMPL_OK: /* PLOGI ACC completions */
+ WARN_ON(!node->els_cmpl_cnt);
+ node->els_cmpl_cnt--;
+ efc_node_transition(node, __efc_d_port_logged_in, NULL);
+ break;
+
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_d_wait_logo_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_SRRS_ELS_REQ_OK:
+ case EFC_EVT_SRRS_ELS_REQ_RJT:
+ case EFC_EVT_SRRS_ELS_REQ_FAIL:
+ /* LOGO response received, sent shutdown */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_LOGO,
+ __efc_d_common, __func__))
+ return;
+
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ node_printf(node,
+ "LOGO sent (evt=%s), shutdown node\n",
+ efc_sm_event_name(evt));
+ /* sm: / post explicit logout */
+ efc_node_post_event(node, EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
+ NULL);
+ break;
+
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+efc_node_init_device(struct efc_node *node, bool send_plogi)
+{
+ node->send_plogi = send_plogi;
+ if ((node->efc->nodedb_mask & EFC_NODEDB_PAUSE_NEW_NODES) &&
+ (node->rnode.fc_id != FC_FID_DOM_MGR)) {
+ node->nodedb_state = __efc_d_init;
+ efc_node_transition(node, __efc_node_paused, NULL);
+ } else {
+ efc_node_transition(node, __efc_d_init, NULL);
+ }
+}
+
+static void
+efc_d_check_plogi_topology(struct efc_node *node, u32 d_id)
+{
+ switch (node->nport->topology) {
+ case EFC_NPORT_TOPO_P2P:
+ /* we're not attached and nport is p2p,
+ * need to attach
+ */
+ efc_domain_attach(node->nport->domain, d_id);
+ efc_node_transition(node, __efc_d_wait_domain_attach, NULL);
+ break;
+ case EFC_NPORT_TOPO_FABRIC:
+ /* we're not attached and nport is fabric, domain
+ * attach should have already been requested as part
+ * of the fabric state machine, wait for it
+ */
+ efc_node_transition(node, __efc_d_wait_domain_attach, NULL);
+ break;
+ case EFC_NPORT_TOPO_UNKNOWN:
+ /* Two possibilities:
+ * 1. received a PLOGI before our FLOGI has completed
+ * (possible since completion comes in on another
+ * CQ), thus we don't know what we're connected to
+ * yet; transition to a state to wait for the
+ * fabric node to tell us;
+ * 2. PLOGI received before link went down and we
+ * haven't performed domain attach yet.
+ * Note: we cannot distinguish between 1. and 2.
+ * so have to assume PLOGI
+ * was received after link back up.
+ */
+ node_printf(node, "received PLOGI, unknown topology did=0x%x\n",
+ d_id);
+ efc_node_transition(node, __efc_d_wait_topology_notify, NULL);
+ break;
+ default:
+ node_printf(node, "received PLOGI, unexpected topology %d\n",
+ node->nport->topology);
+ }
+}
+
+void
+__efc_d_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ /*
+ * This state is entered when a node is instantiated,
+ * either having been discovered from a name services query,
+ * or having received a PLOGI/FLOGI.
+ */
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ if (!node->send_plogi)
+ break;
+ /* only send if we have initiator capability,
+ * and domain is attached
+ */
+ if (node->nport->enable_ini &&
+ node->nport->domain->attached) {
+ efc_send_plogi(node);
+
+ efc_node_transition(node, __efc_d_wait_plogi_rsp, NULL);
+ } else {
+ node_printf(node, "not sending plogi nport.ini=%d,",
+ node->nport->enable_ini);
+ node_printf(node, "domain attached=%d\n",
+ node->nport->domain->attached);
+ }
+ break;
+ case EFC_EVT_PLOGI_RCVD: {
+ /* T, or I+T */
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+ int rc;
+
+ efc_node_save_sparms(node, cbdata->payload->dma.virt);
+ efc_send_ls_acc_after_attach(node,
+ cbdata->header->dma.virt,
+ EFC_NODE_SEND_LS_ACC_PLOGI);
+
+ /* domain not attached; several possibilities: */
+ if (!node->nport->domain->attached) {
+ efc_d_check_plogi_topology(node, ntoh24(hdr->fh_d_id));
+ break;
+ }
+
+ /* domain already attached */
+ rc = efc_node_attach(node);
+ efc_node_transition(node, __efc_d_wait_node_attach, NULL);
+ if (rc < 0)
+ efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL, NULL);
+
+ break;
+ }
+
+ case EFC_EVT_FDISC_RCVD: {
+ __efc_d_common(__func__, ctx, evt, arg);
+ break;
+ }
+
+ case EFC_EVT_FLOGI_RCVD: {
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+ u32 d_id = ntoh24(hdr->fh_d_id);
+
+ /* sm: / save sparams, send FLOGI acc */
+ memcpy(node->nport->domain->flogi_service_params,
+ cbdata->payload->dma.virt,
+ sizeof(struct fc_els_flogi));
+
+ /* send FC LS_ACC response, override s_id */
+ efc_fabric_set_topology(node, EFC_NPORT_TOPO_P2P);
+
+ efc_send_flogi_p2p_acc(node, be16_to_cpu(hdr->fh_ox_id), d_id);
+
+ if (efc_p2p_setup(node->nport)) {
+ node_printf(node, "p2p failed, shutting down node\n");
+ efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
+ break;
+ }
+
+ efc_node_transition(node, __efc_p2p_wait_flogi_acc_cmpl, NULL);
+ break;
+ }
+
+ case EFC_EVT_LOGO_RCVD: {
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+
+ if (!node->nport->domain->attached) {
+ /* most likely a frame left over from before a link
+ * down; drop and
+ * shut node down w/ "explicit logout" so pending
+ * frames are processed
+ */
+ node_printf(node, "%s domain not attached, dropping\n",
+ efc_sm_event_name(evt));
+ efc_node_post_event(node,
+ EFC_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
+ break;
+ }
+
+ efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
+ efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
+ break;
+ }
+
+ case EFC_EVT_PRLI_RCVD:
+ case EFC_EVT_PRLO_RCVD:
+ case EFC_EVT_PDISC_RCVD:
+ case EFC_EVT_ADISC_RCVD:
+ case EFC_EVT_RSCN_RCVD: {
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+
+ if (!node->nport->domain->attached) {
+ /* most likely a frame left over from before a link
+ * down; drop and shut node down w/ "explicit logout"
+ * so pending frames are processed
+ */
+ node_printf(node, "%s domain not attached, dropping\n",
+ efc_sm_event_name(evt));
+
+ efc_node_post_event(node,
+ EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
+ NULL);
+ break;
+ }
+ node_printf(node, "%s received, sending reject\n",
+ efc_sm_event_name(evt));
+
+ efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
+ ELS_RJT_UNAB, ELS_EXPL_PLOGI_REQD, 0);
+
+ break;
+ }
+
+ case EFC_EVT_FCP_CMD_RCVD: {
+ /* note: problem, we're now expecting an ELS REQ completion
+ * from both the LOGO and PLOGI
+ */
+ if (!node->nport->domain->attached) {
+ /* most likely a frame left over from before a
+ * link down; drop and
+ * shut node down w/ "explicit logout" so pending
+ * frames are processed
+ */
+ node_printf(node, "%s domain not attached, dropping\n",
+ efc_sm_event_name(evt));
+ efc_node_post_event(node,
+ EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
+ NULL);
+ break;
+ }
+
+ /* Send LOGO */
+ node_printf(node, "FCP_CMND received, send LOGO\n");
+ if (efc_send_logo(node)) {
+ /*
+ * failed to send LOGO, go ahead and cleanup node
+ * anyways
+ */
+ node_printf(node, "Failed to send LOGO\n");
+ efc_node_post_event(node,
+ EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
+ NULL);
+ } else {
+ /* sent LOGO, wait for response */
+ efc_node_transition(node,
+ __efc_d_wait_logo_rsp, NULL);
+ }
+ break;
+ }
+ case EFC_EVT_DOMAIN_ATTACH_OK:
+ /* don't care about domain_attach_ok */
+ break;
+
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_d_wait_plogi_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ int rc;
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_PLOGI_RCVD: {
+ /* T, or I+T */
+ /* received PLOGI with svc parms, go ahead and attach node
+ * when PLOGI that was sent ultimately completes, it'll be a
+ * no-op
+ *
+ * If there is an outstanding PLOGI sent, can we set a flag
+ * to indicate that we don't want to retry it if it times out?
+ */
+ efc_node_save_sparms(node, cbdata->payload->dma.virt);
+ efc_send_ls_acc_after_attach(node,
+ cbdata->header->dma.virt,
+ EFC_NODE_SEND_LS_ACC_PLOGI);
+ /* sm: domain->attached / efc_node_attach */
+ rc = efc_node_attach(node);
+ efc_node_transition(node, __efc_d_wait_node_attach, NULL);
+ if (rc < 0)
+ efc_node_post_event(node,
+ EFC_EVT_NODE_ATTACH_FAIL, NULL);
+
+ break;
+ }
+
+ case EFC_EVT_PRLI_RCVD:
+ /* I, or I+T */
+ /* sent PLOGI and before completion was seen, received the
+ * PRLI from the remote node (WCQEs and RCQEs come in on
+ * different queues and order of processing cannot be assumed)
+ * Save OXID so PRLI can be sent after the attach and continue
+ * to wait for PLOGI response
+ */
+ efc_process_prli_payload(node, cbdata->payload->dma.virt);
+ efc_send_ls_acc_after_attach(node,
+ cbdata->header->dma.virt,
+ EFC_NODE_SEND_LS_ACC_PRLI);
+ efc_node_transition(node, __efc_d_wait_plogi_rsp_recvd_prli,
+ NULL);
+ break;
+
+ case EFC_EVT_LOGO_RCVD: /* why don't we do a shutdown here?? */
+ case EFC_EVT_PRLO_RCVD:
+ case EFC_EVT_PDISC_RCVD:
+ case EFC_EVT_FDISC_RCVD:
+ case EFC_EVT_ADISC_RCVD:
+ case EFC_EVT_RSCN_RCVD:
+ case EFC_EVT_SCR_RCVD: {
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+
+ node_printf(node, "%s received, sending reject\n",
+ efc_sm_event_name(evt));
+
+ efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
+ ELS_RJT_UNAB, ELS_EXPL_PLOGI_REQD, 0);
+
+ break;
+ }
+
+ case EFC_EVT_SRRS_ELS_REQ_OK: /* PLOGI response received */
+ /* Completion from PLOGI sent */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
+ __efc_d_common, __func__))
+ return;
+
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ /* sm: / save sparams, efc_node_attach */
+ efc_node_save_sparms(node, cbdata->els_rsp.virt);
+ rc = efc_node_attach(node);
+ efc_node_transition(node, __efc_d_wait_node_attach, NULL);
+ if (rc < 0)
+ efc_node_post_event(node,
+ EFC_EVT_NODE_ATTACH_FAIL, NULL);
+
+ break;
+
+ case EFC_EVT_SRRS_ELS_REQ_FAIL: /* PLOGI response received */
+ /* PLOGI failed, shutdown the node */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
+ __efc_d_common, __func__))
+ return;
+
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
+ break;
+
+ case EFC_EVT_SRRS_ELS_REQ_RJT:
+ /* Our PLOGI was rejected, this is ok in some cases */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
+ __efc_d_common, __func__))
+ return;
+
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ break;
+
+ case EFC_EVT_FCP_CMD_RCVD: {
+ /* not logged in yet and outstanding PLOGI so don't send LOGO,
+ * just drop
+ */
+ node_printf(node, "FCP_CMND received, drop\n");
+ break;
+ }
+
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_d_wait_plogi_rsp_recvd_prli(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ int rc;
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ /*
+ * Since we've received a PRLI, we have a port login and will
+ * just need to wait for the PLOGI response to do the node
+ * attach and then we can send the LS_ACC for the PRLI. If,
+ * during this time, we receive FCP_CMNDs (which is possible
+ * since we've already sent a PRLI and our peer may have
+ * accepted). At this time, we are not waiting on any other
+ * unsolicited frames to continue with the login process. Thus,
+ * it will not hurt to hold frames here.
+ */
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_SRRS_ELS_REQ_OK: /* PLOGI response received */
+ /* Completion from PLOGI sent */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
+ __efc_d_common, __func__))
+ return;
+
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ /* sm: / save sparams, efc_node_attach */
+ efc_node_save_sparms(node, cbdata->els_rsp.virt);
+ rc = efc_node_attach(node);
+ efc_node_transition(node, __efc_d_wait_node_attach, NULL);
+ if (rc < 0)
+ efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,
+ NULL);
+
+ break;
+
+ case EFC_EVT_SRRS_ELS_REQ_FAIL: /* PLOGI response received */
+ case EFC_EVT_SRRS_ELS_REQ_RJT:
+ /* PLOGI failed, shutdown the node */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
+ __efc_d_common, __func__))
+ return;
+
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
+ break;
+
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_d_wait_domain_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ int rc;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_DOMAIN_ATTACH_OK:
+ WARN_ON(!node->nport->domain->attached);
+ /* sm: / efc_node_attach */
+ rc = efc_node_attach(node);
+ efc_node_transition(node, __efc_d_wait_node_attach, NULL);
+ if (rc < 0)
+ efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,
+ NULL);
+
+ break;
+
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_d_wait_topology_notify(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ int rc;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_NPORT_TOPOLOGY_NOTIFY: {
+ enum efc_nport_topology topology =
+ (enum efc_nport_topology)arg;
+
+ WARN_ON(node->nport->domain->attached);
+
+ WARN_ON(node->send_ls_acc != EFC_NODE_SEND_LS_ACC_PLOGI);
+
+ node_printf(node, "topology notification, topology=%d\n",
+ topology);
+
+ /* At the time the PLOGI was received, the topology was unknown,
+ * so we didn't know which node would perform the domain attach:
+ * 1. The node from which the PLOGI was sent (p2p) or
+ * 2. The node to which the FLOGI was sent (fabric).
+ */
+ if (topology == EFC_NPORT_TOPO_P2P) {
+ /* if this is p2p, need to attach to the domain using
+ * the d_id from the PLOGI received
+ */
+ efc_domain_attach(node->nport->domain,
+ node->ls_acc_did);
+ }
+ /* else, if this is fabric, the domain attach
+ * should be performed by the fabric node (node sending FLOGI);
+ * just wait for attach to complete
+ */
+
+ efc_node_transition(node, __efc_d_wait_domain_attach, NULL);
+ break;
+ }
+ case EFC_EVT_DOMAIN_ATTACH_OK:
+ WARN_ON(!node->nport->domain->attached);
+ node_printf(node, "domain attach ok\n");
+ /* sm: / efc_node_attach */
+ rc = efc_node_attach(node);
+ efc_node_transition(node, __efc_d_wait_node_attach, NULL);
+ if (rc < 0)
+ efc_node_post_event(node,
+ EFC_EVT_NODE_ATTACH_FAIL, NULL);
+
+ break;
+
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_d_wait_node_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_NODE_ATTACH_OK:
+ node->attached = true;
+ switch (node->send_ls_acc) {
+ case EFC_NODE_SEND_LS_ACC_PLOGI: {
+ /* sm: send_plogi_acc is set / send PLOGI acc */
+ /* Normal case for T, or I+T */
+ efc_send_plogi_acc(node, node->ls_acc_oxid);
+ efc_node_transition(node, __efc_d_wait_plogi_acc_cmpl,
+ NULL);
+ node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
+ node->ls_acc_io = NULL;
+ break;
+ }
+ case EFC_NODE_SEND_LS_ACC_PRLI: {
+ efc_d_send_prli_rsp(node, node->ls_acc_oxid);
+ node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
+ node->ls_acc_io = NULL;
+ break;
+ }
+ case EFC_NODE_SEND_LS_ACC_NONE:
+ default:
+ /* Normal case for I */
+ /* sm: send_plogi_acc is not set / send PLOGI acc */
+ efc_node_transition(node,
+ __efc_d_port_logged_in, NULL);
+ break;
+ }
+ break;
+
+ case EFC_EVT_NODE_ATTACH_FAIL:
+ /* node attach failed, shutdown the node */
+ node->attached = false;
+ node_printf(node, "node attach failed\n");
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
+ break;
+
+ /* Handle shutdown events */
+ case EFC_EVT_SHUTDOWN:
+ node_printf(node, "%s received\n", efc_sm_event_name(evt));
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_node_transition(node, __efc_d_wait_attach_evt_shutdown,
+ NULL);
+ break;
+ case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
+ node_printf(node, "%s received\n", efc_sm_event_name(evt));
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_EXPLICIT_LOGO;
+ efc_node_transition(node, __efc_d_wait_attach_evt_shutdown,
+ NULL);
+ break;
+ case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
+ node_printf(node, "%s received\n", efc_sm_event_name(evt));
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_IMPLICIT_LOGO;
+ efc_node_transition(node,
+ __efc_d_wait_attach_evt_shutdown, NULL);
+ break;
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_d_wait_attach_evt_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ /* wait for any of these attach events and then shutdown */
+ case EFC_EVT_NODE_ATTACH_OK:
+ node->attached = true;
+ node_printf(node, "Attach evt=%s, proceed to shutdown\n",
+ efc_sm_event_name(evt));
+ efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
+ break;
+
+ case EFC_EVT_NODE_ATTACH_FAIL:
+ /* node attach failed, shutdown the node */
+ node->attached = false;
+ node_printf(node, "Attach evt=%s, proceed to shutdown\n",
+ efc_sm_event_name(evt));
+ efc_node_transition(node, __efc_d_initiate_shutdown, NULL);
+ break;
+
+ /* ignore shutdown events as we're already in shutdown path */
+ case EFC_EVT_SHUTDOWN:
+ /* have default shutdown event take precedence */
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ fallthrough;
+
+ case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
+ case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
+ node_printf(node, "%s received\n", efc_sm_event_name(evt));
+ break;
+
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_d_port_logged_in(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ /* Normal case for I or I+T */
+ if (node->nport->enable_ini &&
+ !(node->rnode.fc_id != FC_FID_DOM_MGR)) {
+ /* sm: if enable_ini / send PRLI */
+ efc_send_prli(node);
+ /* can now expect ELS_REQ_OK/FAIL/RJT */
+ }
+ break;
+
+ case EFC_EVT_FCP_CMD_RCVD: {
+ break;
+ }
+
+ case EFC_EVT_PRLI_RCVD: {
+ /* Normal case for T or I+T */
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+ struct {
+ struct fc_els_prli prli;
+ struct fc_els_spp sp;
+ } *pp;
+
+ pp = cbdata->payload->dma.virt;
+ if (pp->sp.spp_type != FC_TYPE_FCP) {
+ /*Only FCP is supported*/
+ efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
+ ELS_RJT_UNAB, ELS_EXPL_UNSUPR, 0);
+ break;
+ }
+
+ efc_process_prli_payload(node, cbdata->payload->dma.virt);
+ efc_d_send_prli_rsp(node, be16_to_cpu(hdr->fh_ox_id));
+ break;
+ }
+
+ case EFC_EVT_NODE_SESS_REG_OK:
+ if (node->send_ls_acc == EFC_NODE_SEND_LS_ACC_PRLI)
+ efc_send_prli_acc(node, node->ls_acc_oxid);
+
+ node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
+ efc_node_transition(node, __efc_d_device_ready, NULL);
+ break;
+
+ case EFC_EVT_NODE_SESS_REG_FAIL:
+ efc_send_ls_rjt(node, node->ls_acc_oxid, ELS_RJT_UNAB,
+ ELS_EXPL_UNSUPR, 0);
+ node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
+ break;
+
+ case EFC_EVT_SRRS_ELS_REQ_OK: { /* PRLI response */
+ /* Normal case for I or I+T */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_PRLI,
+ __efc_d_common, __func__))
+ return;
+
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ /* sm: / process PRLI payload */
+ efc_process_prli_payload(node, cbdata->els_rsp.virt);
+ efc_node_transition(node, __efc_d_device_ready, NULL);
+ break;
+ }
+
+ case EFC_EVT_SRRS_ELS_REQ_FAIL: { /* PRLI response failed */
+ /* I, I+T, assume some link failure, shutdown node */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_PRLI,
+ __efc_d_common, __func__))
+ return;
+
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
+ break;
+ }
+
+ case EFC_EVT_SRRS_ELS_REQ_RJT: {
+ /* PRLI rejected by remote
+ * Normal for I, I+T (connected to an I)
+ * Node doesn't want to be a target, stay here and wait for a
+ * PRLI from the remote node
+ * if it really wants to connect to us as target
+ */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_PRLI,
+ __efc_d_common, __func__))
+ return;
+
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ break;
+ }
+
+ case EFC_EVT_SRRS_ELS_CMPL_OK: {
+ /* Normal T, I+T, target-server rejected the process login */
+ /* This would be received only in the case where we sent
+ * LS_RJT for the PRLI, so
+ * do nothing. (note: as T only we could shutdown the node)
+ */
+ WARN_ON(!node->els_cmpl_cnt);
+ node->els_cmpl_cnt--;
+ break;
+ }
+
+ case EFC_EVT_PLOGI_RCVD: {
+ /*sm: / save sparams, set send_plogi_acc,
+ *post implicit logout
+ * Save plogi parameters
+ */
+ efc_node_save_sparms(node, cbdata->payload->dma.virt);
+ efc_send_ls_acc_after_attach(node,
+ cbdata->header->dma.virt,
+ EFC_NODE_SEND_LS_ACC_PLOGI);
+
+ /* Restart node attach with new service parameters,
+ * and send ACC
+ */
+ efc_node_post_event(node, EFC_EVT_SHUTDOWN_IMPLICIT_LOGO,
+ NULL);
+ break;
+ }
+
+ case EFC_EVT_LOGO_RCVD: {
+ /* I, T, I+T */
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+
+ node_printf(node, "%s received attached=%d\n",
+ efc_sm_event_name(evt),
+ node->attached);
+ /* sm: / send LOGO acc */
+ efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
+ efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
+ break;
+ }
+
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_d_wait_logo_acc_cmpl(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_SRRS_ELS_CMPL_OK:
+ case EFC_EVT_SRRS_ELS_CMPL_FAIL:
+ /* sm: / post explicit logout */
+ WARN_ON(!node->els_cmpl_cnt);
+ node->els_cmpl_cnt--;
+ efc_node_post_event(node,
+ EFC_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
+ break;
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_d_device_ready(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+ struct efc *efc = node->efc;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ if (evt != EFC_EVT_FCP_CMD_RCVD)
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ node->fcp_enabled = true;
+ if (node->targ) {
+ efc_log_info(efc,
+ "[%s] found (target) WWPN %s WWNN %s\n",
+ node->display_name,
+ node->wwpn, node->wwnn);
+ if (node->nport->enable_ini)
+ efc->tt.scsi_new_node(efc, node);
+ }
+ break;
+
+ case EFC_EVT_EXIT:
+ node->fcp_enabled = false;
+ break;
+
+ case EFC_EVT_PLOGI_RCVD: {
+ /* sm: / save sparams, set send_plogi_acc, post implicit
+ * logout
+ * Save plogi parameters
+ */
+ efc_node_save_sparms(node, cbdata->payload->dma.virt);
+ efc_send_ls_acc_after_attach(node,
+ cbdata->header->dma.virt,
+ EFC_NODE_SEND_LS_ACC_PLOGI);
+
+ /*
+ * Restart node attach with new service parameters,
+ * and send ACC
+ */
+ efc_node_post_event(node,
+ EFC_EVT_SHUTDOWN_IMPLICIT_LOGO, NULL);
+ break;
+ }
+
+ case EFC_EVT_PRLI_RCVD: {
+ /* T, I+T: remote initiator is slow to get started */
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+ struct {
+ struct fc_els_prli prli;
+ struct fc_els_spp sp;
+ } *pp;
+
+ pp = cbdata->payload->dma.virt;
+ if (pp->sp.spp_type != FC_TYPE_FCP) {
+ /*Only FCP is supported*/
+ efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
+ ELS_RJT_UNAB, ELS_EXPL_UNSUPR, 0);
+ break;
+ }
+
+ efc_process_prli_payload(node, cbdata->payload->dma.virt);
+ efc_send_prli_acc(node, be16_to_cpu(hdr->fh_ox_id));
+ break;
+ }
+
+ case EFC_EVT_PRLO_RCVD: {
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+ /* sm: / send PRLO acc */
+ efc_send_prlo_acc(node, be16_to_cpu(hdr->fh_ox_id));
+ /* need implicit logout? */
+ break;
+ }
+
+ case EFC_EVT_LOGO_RCVD: {
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+
+ node_printf(node, "%s received attached=%d\n",
+ efc_sm_event_name(evt), node->attached);
+ /* sm: / send LOGO acc */
+ efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
+ efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
+ break;
+ }
+
+ case EFC_EVT_ADISC_RCVD: {
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+ /* sm: / send ADISC acc */
+ efc_send_adisc_acc(node, be16_to_cpu(hdr->fh_ox_id));
+ break;
+ }
+
+ case EFC_EVT_ABTS_RCVD:
+ /* sm: / process ABTS */
+ efc_log_err(efc, "Unexpected event:%s\n",
+ efc_sm_event_name(evt));
+ break;
+
+ case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
+ break;
+
+ case EFC_EVT_NODE_REFOUND:
+ break;
+
+ case EFC_EVT_NODE_MISSING:
+ if (node->nport->enable_rscn)
+ efc_node_transition(node, __efc_d_device_gone, NULL);
+
+ break;
+
+ case EFC_EVT_SRRS_ELS_CMPL_OK:
+ /* T, or I+T, PRLI accept completed ok */
+ WARN_ON(!node->els_cmpl_cnt);
+ node->els_cmpl_cnt--;
+ break;
+
+ case EFC_EVT_SRRS_ELS_CMPL_FAIL:
+ /* T, or I+T, PRLI accept failed to complete */
+ WARN_ON(!node->els_cmpl_cnt);
+ node->els_cmpl_cnt--;
+ node_printf(node, "Failed to send PRLI LS_ACC\n");
+ break;
+
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_d_device_gone(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+ struct efc *efc = node->efc;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER: {
+ int rc = EFC_SCSI_CALL_COMPLETE;
+ int rc_2 = EFC_SCSI_CALL_COMPLETE;
+ static const char * const labels[] = {
+ "none", "initiator", "target", "initiator+target"
+ };
+
+ efc_log_info(efc, "[%s] missing (%s) WWPN %s WWNN %s\n",
+ node->display_name,
+ labels[(node->targ << 1) | (node->init)],
+ node->wwpn, node->wwnn);
+
+ switch (efc_node_get_enable(node)) {
+ case EFC_NODE_ENABLE_T_TO_T:
+ case EFC_NODE_ENABLE_I_TO_T:
+ case EFC_NODE_ENABLE_IT_TO_T:
+ rc = efc->tt.scsi_del_node(efc, node,
+ EFC_SCSI_TARGET_MISSING);
+ break;
+
+ case EFC_NODE_ENABLE_T_TO_I:
+ case EFC_NODE_ENABLE_I_TO_I:
+ case EFC_NODE_ENABLE_IT_TO_I:
+ rc = efc->tt.scsi_del_node(efc, node,
+ EFC_SCSI_INITIATOR_MISSING);
+ break;
+
+ case EFC_NODE_ENABLE_T_TO_IT:
+ rc = efc->tt.scsi_del_node(efc, node,
+ EFC_SCSI_INITIATOR_MISSING);
+ break;
+
+ case EFC_NODE_ENABLE_I_TO_IT:
+ rc = efc->tt.scsi_del_node(efc, node,
+ EFC_SCSI_TARGET_MISSING);
+ break;
+
+ case EFC_NODE_ENABLE_IT_TO_IT:
+ rc = efc->tt.scsi_del_node(efc, node,
+ EFC_SCSI_INITIATOR_MISSING);
+ rc_2 = efc->tt.scsi_del_node(efc, node,
+ EFC_SCSI_TARGET_MISSING);
+ break;
+
+ default:
+ rc = EFC_SCSI_CALL_COMPLETE;
+ break;
+ }
+
+ if (rc == EFC_SCSI_CALL_COMPLETE &&
+ rc_2 == EFC_SCSI_CALL_COMPLETE)
+ efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
+
+ break;
+ }
+ case EFC_EVT_NODE_REFOUND:
+ /* two approaches, reauthenticate with PLOGI/PRLI, or ADISC */
+
+ /* reauthenticate with PLOGI/PRLI */
+ /* efc_node_transition(node, __efc_d_discovered, NULL); */
+
+ /* reauthenticate with ADISC */
+ /* sm: / send ADISC */
+ efc_send_adisc(node);
+ efc_node_transition(node, __efc_d_wait_adisc_rsp, NULL);
+ break;
+
+ case EFC_EVT_PLOGI_RCVD: {
+ /* sm: / save sparams, set send_plogi_acc, post implicit
+ * logout
+ * Save plogi parameters
+ */
+ efc_node_save_sparms(node, cbdata->payload->dma.virt);
+ efc_send_ls_acc_after_attach(node,
+ cbdata->header->dma.virt,
+ EFC_NODE_SEND_LS_ACC_PLOGI);
+
+ /*
+ * Restart node attach with new service parameters, and send
+ * ACC
+ */
+ efc_node_post_event(node, EFC_EVT_SHUTDOWN_IMPLICIT_LOGO,
+ NULL);
+ break;
+ }
+
+ case EFC_EVT_FCP_CMD_RCVD: {
+ /* most likely a stale frame (received prior to link down),
+ * if attempt to send LOGO, will probably timeout and eat
+ * up 20s; thus, drop FCP_CMND
+ */
+ node_printf(node, "FCP_CMND received, drop\n");
+ break;
+ }
+ case EFC_EVT_LOGO_RCVD: {
+ /* I, T, I+T */
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+
+ node_printf(node, "%s received attached=%d\n",
+ efc_sm_event_name(evt), node->attached);
+ /* sm: / send LOGO acc */
+ efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
+ efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
+ break;
+ }
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_d_wait_adisc_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_SRRS_ELS_REQ_OK:
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_ADISC,
+ __efc_d_common, __func__))
+ return;
+
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ efc_node_transition(node, __efc_d_device_ready, NULL);
+ break;
+
+ case EFC_EVT_SRRS_ELS_REQ_RJT:
+ /* received an LS_RJT, in this case, send shutdown
+ * (explicit logo) event which will unregister the node,
+ * and start over with PLOGI
+ */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_ADISC,
+ __efc_d_common, __func__))
+ return;
+
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ /* sm: / post explicit logout */
+ efc_node_post_event(node,
+ EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
+ NULL);
+ break;
+
+ case EFC_EVT_LOGO_RCVD: {
+ /* In this case, we have the equivalent of an LS_RJT for
+ * the ADISC, so we need to abort the ADISC, and re-login
+ * with PLOGI
+ */
+ /* sm: / request abort, send LOGO acc */
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+
+ node_printf(node, "%s received attached=%d\n",
+ efc_sm_event_name(evt), node->attached);
+
+ efc_send_logo_acc(node, be16_to_cpu(hdr->fh_ox_id));
+ efc_node_transition(node, __efc_d_wait_logo_acc_cmpl, NULL);
+ break;
+ }
+ default:
+ __efc_d_common(__func__, ctx, evt, arg);
+ }
+}
diff --git a/drivers/scsi/elx/libefc/efc_device.h b/drivers/scsi/elx/libefc/efc_device.h
new file mode 100644
index 000000000000..3cf1d8c6698f
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_device.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+/*
+ * Node state machine functions for remote device node sm
+ */
+
+#ifndef __EFCT_DEVICE_H__
+#define __EFCT_DEVICE_H__
+void
+efc_node_init_device(struct efc_node *node, bool send_plogi);
+void
+efc_process_prli_payload(struct efc_node *node,
+ void *prli);
+void
+efc_d_send_prli_rsp(struct efc_node *node, uint16_t ox_id);
+void
+efc_send_ls_acc_after_attach(struct efc_node *node,
+ struct fc_frame_header *hdr,
+ enum efc_node_send_ls_acc ls);
+void
+__efc_d_wait_loop(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_d_wait_plogi_acc_cmpl(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_d_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg);
+void
+__efc_d_wait_plogi_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_d_wait_plogi_rsp_recvd_prli(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_d_wait_domain_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_d_wait_topology_notify(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_d_wait_node_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_d_wait_attach_evt_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_d_initiate_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_d_port_logged_in(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_d_wait_logo_acc_cmpl(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_d_device_ready(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_d_device_gone(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_d_wait_adisc_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_d_wait_logo_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+
+#endif /* __EFCT_DEVICE_H__ */
diff --git a/drivers/scsi/elx/libefc/efc_domain.c b/drivers/scsi/elx/libefc/efc_domain.c
new file mode 100644
index 000000000000..ca9d7ff2c0d2
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_domain.c
@@ -0,0 +1,1088 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+/*
+ * domain_sm Domain State Machine: States
+ */
+
+#include "efc.h"
+
+int
+efc_domain_cb(void *arg, int event, void *data)
+{
+ struct efc *efc = arg;
+ struct efc_domain *domain = NULL;
+ int rc = 0;
+ unsigned long flags = 0;
+
+ if (event != EFC_HW_DOMAIN_FOUND)
+ domain = data;
+
+ /* Accept domain callback events from the user driver */
+ spin_lock_irqsave(&efc->lock, flags);
+ switch (event) {
+ case EFC_HW_DOMAIN_FOUND: {
+ u64 fcf_wwn = 0;
+ struct efc_domain_record *drec = data;
+
+ /* extract the fcf_wwn */
+ fcf_wwn = be64_to_cpu(*((__be64 *)drec->wwn));
+
+ efc_log_debug(efc, "Domain found: wwn %016llX\n", fcf_wwn);
+
+ /* lookup domain, or allocate a new one */
+ domain = efc->domain;
+ if (!domain) {
+ domain = efc_domain_alloc(efc, fcf_wwn);
+ if (!domain) {
+ efc_log_err(efc, "efc_domain_alloc() failed\n");
+ rc = -1;
+ break;
+ }
+ efc_sm_transition(&domain->drvsm, __efc_domain_init,
+ NULL);
+ }
+ efc_domain_post_event(domain, EFC_EVT_DOMAIN_FOUND, drec);
+ break;
+ }
+
+ case EFC_HW_DOMAIN_LOST:
+ domain_trace(domain, "EFC_HW_DOMAIN_LOST:\n");
+ efc->hold_frames = true;
+ efc_domain_post_event(domain, EFC_EVT_DOMAIN_LOST, NULL);
+ break;
+
+ case EFC_HW_DOMAIN_ALLOC_OK:
+ domain_trace(domain, "EFC_HW_DOMAIN_ALLOC_OK:\n");
+ efc_domain_post_event(domain, EFC_EVT_DOMAIN_ALLOC_OK, NULL);
+ break;
+
+ case EFC_HW_DOMAIN_ALLOC_FAIL:
+ domain_trace(domain, "EFC_HW_DOMAIN_ALLOC_FAIL:\n");
+ efc_domain_post_event(domain, EFC_EVT_DOMAIN_ALLOC_FAIL,
+ NULL);
+ break;
+
+ case EFC_HW_DOMAIN_ATTACH_OK:
+ domain_trace(domain, "EFC_HW_DOMAIN_ATTACH_OK:\n");
+ efc_domain_post_event(domain, EFC_EVT_DOMAIN_ATTACH_OK, NULL);
+ break;
+
+ case EFC_HW_DOMAIN_ATTACH_FAIL:
+ domain_trace(domain, "EFC_HW_DOMAIN_ATTACH_FAIL:\n");
+ efc_domain_post_event(domain,
+ EFC_EVT_DOMAIN_ATTACH_FAIL, NULL);
+ break;
+
+ case EFC_HW_DOMAIN_FREE_OK:
+ domain_trace(domain, "EFC_HW_DOMAIN_FREE_OK:\n");
+ efc_domain_post_event(domain, EFC_EVT_DOMAIN_FREE_OK, NULL);
+ break;
+
+ case EFC_HW_DOMAIN_FREE_FAIL:
+ domain_trace(domain, "EFC_HW_DOMAIN_FREE_FAIL:\n");
+ efc_domain_post_event(domain, EFC_EVT_DOMAIN_FREE_FAIL, NULL);
+ break;
+
+ default:
+ efc_log_warn(efc, "unsupported event %#x\n", event);
+ }
+ spin_unlock_irqrestore(&efc->lock, flags);
+
+ if (efc->domain && domain->req_accept_frames) {
+ domain->req_accept_frames = false;
+ efc->hold_frames = false;
+ }
+
+ return rc;
+}
+
+static void
+_efc_domain_free(struct kref *arg)
+{
+ struct efc_domain *domain = container_of(arg, struct efc_domain, ref);
+ struct efc *efc = domain->efc;
+
+ if (efc->domain_free_cb)
+ (*efc->domain_free_cb)(efc, efc->domain_free_cb_arg);
+
+ kfree(domain);
+}
+
+void
+efc_domain_free(struct efc_domain *domain)
+{
+ struct efc *efc;
+
+ efc = domain->efc;
+
+ /* Hold frames to clear the domain pointer from the xport lookup */
+ efc->hold_frames = false;
+
+ efc_log_debug(efc, "Domain free: wwn %016llX\n", domain->fcf_wwn);
+
+ xa_destroy(&domain->lookup);
+ efc->domain = NULL;
+ kref_put(&domain->ref, domain->release);
+}
+
+struct efc_domain *
+efc_domain_alloc(struct efc *efc, uint64_t fcf_wwn)
+{
+ struct efc_domain *domain;
+
+ domain = kzalloc(sizeof(*domain), GFP_ATOMIC);
+ if (!domain)
+ return NULL;
+
+ domain->efc = efc;
+ domain->drvsm.app = domain;
+
+ /* initialize refcount */
+ kref_init(&domain->ref);
+ domain->release = _efc_domain_free;
+
+ xa_init(&domain->lookup);
+
+ INIT_LIST_HEAD(&domain->nport_list);
+ efc->domain = domain;
+ domain->fcf_wwn = fcf_wwn;
+ efc_log_debug(efc, "Domain allocated: wwn %016llX\n", domain->fcf_wwn);
+
+ return domain;
+}
+
+void
+efc_register_domain_free_cb(struct efc *efc,
+ void (*callback)(struct efc *efc, void *arg),
+ void *arg)
+{
+ /* Register a callback to be called when the domain is freed */
+ efc->domain_free_cb = callback;
+ efc->domain_free_cb_arg = arg;
+ if (!efc->domain && callback)
+ (*callback)(efc, arg);
+}
+
+static void
+__efc_domain_common(const char *funcname, struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_domain *domain = ctx->app;
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ case EFC_EVT_REENTER:
+ case EFC_EVT_EXIT:
+ case EFC_EVT_ALL_CHILD_NODES_FREE:
+ /*
+ * this can arise if an FLOGI fails on the NPORT,
+ * and the NPORT is shutdown
+ */
+ break;
+ default:
+ efc_log_warn(domain->efc, "%-20s %-20s not handled\n",
+ funcname, efc_sm_event_name(evt));
+ }
+}
+
+static void
+__efc_domain_common_shutdown(const char *funcname, struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_domain *domain = ctx->app;
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ case EFC_EVT_REENTER:
+ case EFC_EVT_EXIT:
+ break;
+ case EFC_EVT_DOMAIN_FOUND:
+ /* save drec, mark domain_found_pending */
+ memcpy(&domain->pending_drec, arg,
+ sizeof(domain->pending_drec));
+ domain->domain_found_pending = true;
+ break;
+ case EFC_EVT_DOMAIN_LOST:
+ /* unmark domain_found_pending */
+ domain->domain_found_pending = false;
+ break;
+
+ default:
+ efc_log_warn(domain->efc, "%-20s %-20s not handled\n",
+ funcname, efc_sm_event_name(evt));
+ }
+}
+
+#define std_domain_state_decl(...)\
+ struct efc_domain *domain = NULL;\
+ struct efc *efc = NULL;\
+ \
+ WARN_ON(!ctx || !ctx->app);\
+ domain = ctx->app;\
+ WARN_ON(!domain->efc);\
+ efc = domain->efc
+
+void
+__efc_domain_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
+ void *arg)
+{
+ std_domain_state_decl();
+
+ domain_sm_trace(domain);
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ domain->attached = false;
+ break;
+
+ case EFC_EVT_DOMAIN_FOUND: {
+ u32 i;
+ struct efc_domain_record *drec = arg;
+ struct efc_nport *nport;
+
+ u64 my_wwnn = efc->req_wwnn;
+ u64 my_wwpn = efc->req_wwpn;
+ __be64 bewwpn;
+
+ if (my_wwpn == 0 || my_wwnn == 0) {
+ efc_log_debug(efc, "using default hardware WWN config\n");
+ my_wwpn = efc->def_wwpn;
+ my_wwnn = efc->def_wwnn;
+ }
+
+ efc_log_debug(efc, "Create nport WWPN %016llX WWNN %016llX\n",
+ my_wwpn, my_wwnn);
+
+ /* Allocate a nport and transition to __efc_nport_allocated */
+ nport = efc_nport_alloc(domain, my_wwpn, my_wwnn, U32_MAX,
+ efc->enable_ini, efc->enable_tgt);
+
+ if (!nport) {
+ efc_log_err(efc, "efc_nport_alloc() failed\n");
+ break;
+ }
+ efc_sm_transition(&nport->sm, __efc_nport_allocated, NULL);
+
+ bewwpn = cpu_to_be64(nport->wwpn);
+
+ /* allocate struct efc_nport object for local port
+ * Note: drec->fc_id is ALPA from read_topology only if loop
+ */
+ if (efc_cmd_nport_alloc(efc, nport, NULL, (uint8_t *)&bewwpn)) {
+ efc_log_err(efc, "Can't allocate port\n");
+ efc_nport_free(nport);
+ break;
+ }
+
+ domain->is_loop = drec->is_loop;
+
+ /*
+ * If the loop position map includes ALPA == 0,
+ * then we are in a public loop (NL_PORT)
+ * Note that the first element of the loopmap[]
+ * contains the count of elements, and if
+ * ALPA == 0 is present, it will occupy the first
+ * location after the count.
+ */
+ domain->is_nlport = drec->map.loop[1] == 0x00;
+
+ if (!domain->is_loop) {
+ /* Initiate HW domain alloc */
+ if (efc_cmd_domain_alloc(efc, domain, drec->index)) {
+ efc_log_err(efc,
+ "Failed to initiate HW domain allocation\n");
+ break;
+ }
+ efc_sm_transition(ctx, __efc_domain_wait_alloc, arg);
+ break;
+ }
+
+ efc_log_debug(efc, "%s fc_id=%#x speed=%d\n",
+ drec->is_loop ?
+ (domain->is_nlport ?
+ "public-loop" : "loop") : "other",
+ drec->fc_id, drec->speed);
+
+ nport->fc_id = drec->fc_id;
+ nport->topology = EFC_NPORT_TOPO_FC_AL;
+ snprintf(nport->display_name, sizeof(nport->display_name),
+ "s%06x", drec->fc_id);
+
+ if (efc->enable_ini) {
+ u32 count = drec->map.loop[0];
+
+ efc_log_debug(efc, "%d position map entries\n",
+ count);
+ for (i = 1; i <= count; i++) {
+ if (drec->map.loop[i] != drec->fc_id) {
+ struct efc_node *node;
+
+ efc_log_debug(efc, "%#x -> %#x\n",
+ drec->fc_id,
+ drec->map.loop[i]);
+ node = efc_node_alloc(nport,
+ drec->map.loop[i],
+ false, true);
+ if (!node) {
+ efc_log_err(efc,
+ "efc_node_alloc() failed\n");
+ break;
+ }
+ efc_node_transition(node,
+ __efc_d_wait_loop,
+ NULL);
+ }
+ }
+ }
+
+ /* Initiate HW domain alloc */
+ if (efc_cmd_domain_alloc(efc, domain, drec->index)) {
+ efc_log_err(efc,
+ "Failed to initiate HW domain allocation\n");
+ break;
+ }
+ efc_sm_transition(ctx, __efc_domain_wait_alloc, arg);
+ break;
+ }
+ default:
+ __efc_domain_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_domain_wait_alloc(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ std_domain_state_decl();
+
+ domain_sm_trace(domain);
+
+ switch (evt) {
+ case EFC_EVT_DOMAIN_ALLOC_OK: {
+ struct fc_els_flogi *sp;
+ struct efc_nport *nport;
+
+ nport = domain->nport;
+ if (WARN_ON(!nport))
+ return;
+
+ sp = (struct fc_els_flogi *)nport->service_params;
+
+ /* Save the domain service parameters */
+ memcpy(domain->service_params + 4, domain->dma.virt,
+ sizeof(struct fc_els_flogi) - 4);
+ memcpy(nport->service_params + 4, domain->dma.virt,
+ sizeof(struct fc_els_flogi) - 4);
+
+ /*
+ * Update the nport's service parameters,
+ * user might have specified non-default names
+ */
+ sp->fl_wwpn = cpu_to_be64(nport->wwpn);
+ sp->fl_wwnn = cpu_to_be64(nport->wwnn);
+
+ /*
+ * Take the loop topology path,
+ * unless we are an NL_PORT (public loop)
+ */
+ if (domain->is_loop && !domain->is_nlport) {
+ /*
+ * For loop, we already have our FC ID
+ * and don't need fabric login.
+ * Transition to the allocated state and
+ * post an event to attach to
+ * the domain. Note that this breaks the
+ * normal action/transition
+ * pattern here to avoid a race with the
+ * domain attach callback.
+ */
+ /* sm: is_loop / domain_attach */
+ efc_sm_transition(ctx, __efc_domain_allocated, NULL);
+ __efc_domain_attach_internal(domain, nport->fc_id);
+ break;
+ }
+ {
+ struct efc_node *node;
+
+ /* alloc fabric node, send FLOGI */
+ node = efc_node_find(nport, FC_FID_FLOGI);
+ if (node) {
+ efc_log_err(efc,
+ "Fabric Controller node already exists\n");
+ break;
+ }
+ node = efc_node_alloc(nport, FC_FID_FLOGI,
+ false, false);
+ if (!node) {
+ efc_log_err(efc,
+ "Error: efc_node_alloc() failed\n");
+ } else {
+ efc_node_transition(node,
+ __efc_fabric_init, NULL);
+ }
+ /* Accept frames */
+ domain->req_accept_frames = true;
+ }
+ /* sm: / start fabric logins */
+ efc_sm_transition(ctx, __efc_domain_allocated, NULL);
+ break;
+ }
+
+ case EFC_EVT_DOMAIN_ALLOC_FAIL:
+ efc_log_err(efc, "%s recv'd waiting for DOMAIN_ALLOC_OK;",
+ efc_sm_event_name(evt));
+ efc_log_err(efc, "shutting down domain\n");
+ domain->req_domain_free = true;
+ break;
+
+ case EFC_EVT_DOMAIN_FOUND:
+ /* Should not happen */
+ break;
+
+ case EFC_EVT_DOMAIN_LOST:
+ efc_log_debug(efc,
+ "%s received while waiting for hw_domain_alloc()\n",
+ efc_sm_event_name(evt));
+ efc_sm_transition(ctx, __efc_domain_wait_domain_lost, NULL);
+ break;
+
+ default:
+ __efc_domain_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_domain_allocated(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ std_domain_state_decl();
+
+ domain_sm_trace(domain);
+
+ switch (evt) {
+ case EFC_EVT_DOMAIN_REQ_ATTACH: {
+ int rc = 0;
+ u32 fc_id;
+
+ if (WARN_ON(!arg))
+ return;
+
+ fc_id = *((u32 *)arg);
+ efc_log_debug(efc, "Requesting hw domain attach fc_id x%x\n",
+ fc_id);
+ /* Update nport lookup */
+ rc = xa_err(xa_store(&domain->lookup, fc_id, domain->nport,
+ GFP_ATOMIC));
+ if (rc) {
+ efc_log_err(efc, "Sport lookup store failed: %d\n", rc);
+ return;
+ }
+
+ /* Update display name for the nport */
+ efc_node_fcid_display(fc_id, domain->nport->display_name,
+ sizeof(domain->nport->display_name));
+
+ /* Issue domain attach call */
+ rc = efc_cmd_domain_attach(efc, domain, fc_id);
+ if (rc) {
+ efc_log_err(efc, "efc_hw_domain_attach failed: %d\n",
+ rc);
+ return;
+ }
+ /* sm: / domain_attach */
+ efc_sm_transition(ctx, __efc_domain_wait_attach, NULL);
+ break;
+ }
+
+ case EFC_EVT_DOMAIN_FOUND:
+ /* Should not happen */
+ efc_log_err(efc, "%s: evt: %d should not happen\n",
+ __func__, evt);
+ break;
+
+ case EFC_EVT_DOMAIN_LOST: {
+ efc_log_debug(efc,
+ "%s received while in EFC_EVT_DOMAIN_REQ_ATTACH\n",
+ efc_sm_event_name(evt));
+ if (!list_empty(&domain->nport_list)) {
+ /*
+ * if there are nports, transition to
+ * wait state and send shutdown to each
+ * nport
+ */
+ struct efc_nport *nport = NULL, *nport_next = NULL;
+
+ efc_sm_transition(ctx, __efc_domain_wait_nports_free,
+ NULL);
+ list_for_each_entry_safe(nport, nport_next,
+ &domain->nport_list,
+ list_entry) {
+ efc_sm_post_event(&nport->sm,
+ EFC_EVT_SHUTDOWN, NULL);
+ }
+ } else {
+ /* no nports exist, free domain */
+ efc_sm_transition(ctx, __efc_domain_wait_shutdown,
+ NULL);
+ if (efc_cmd_domain_free(efc, domain))
+ efc_log_err(efc, "hw_domain_free failed\n");
+ }
+
+ break;
+ }
+
+ default:
+ __efc_domain_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_domain_wait_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ std_domain_state_decl();
+
+ domain_sm_trace(domain);
+
+ switch (evt) {
+ case EFC_EVT_DOMAIN_ATTACH_OK: {
+ struct efc_node *node = NULL;
+ struct efc_nport *nport, *next_nport;
+ unsigned long index;
+
+ /*
+ * Set domain notify pending state to avoid
+ * duplicate domain event post
+ */
+ domain->domain_notify_pend = true;
+
+ /* Mark as attached */
+ domain->attached = true;
+
+ /* Transition to ready */
+ /* sm: / forward event to all nports and nodes */
+ efc_sm_transition(ctx, __efc_domain_ready, NULL);
+
+ /* We have an FCFI, so we can accept frames */
+ domain->req_accept_frames = true;
+
+ /*
+ * Notify all nodes that the domain attach request
+ * has completed
+ * Note: nport will have already received notification
+ * of nport attached as a result of the HW's port attach.
+ */
+ list_for_each_entry_safe(nport, next_nport,
+ &domain->nport_list, list_entry) {
+ xa_for_each(&nport->lookup, index, node) {
+ efc_node_post_event(node,
+ EFC_EVT_DOMAIN_ATTACH_OK,
+ NULL);
+ }
+ }
+ domain->domain_notify_pend = false;
+ break;
+ }
+
+ case EFC_EVT_DOMAIN_ATTACH_FAIL:
+ efc_log_debug(efc,
+ "%s received while waiting for hw attach\n",
+ efc_sm_event_name(evt));
+ break;
+
+ case EFC_EVT_DOMAIN_FOUND:
+ /* Should not happen */
+ efc_log_err(efc, "%s: evt: %d should not happen\n",
+ __func__, evt);
+ break;
+
+ case EFC_EVT_DOMAIN_LOST:
+ /*
+ * Domain lost while waiting for an attach to complete,
+ * go to a state that waits for the domain attach to
+ * complete, then handle domain lost
+ */
+ efc_sm_transition(ctx, __efc_domain_wait_domain_lost, NULL);
+ break;
+
+ case EFC_EVT_DOMAIN_REQ_ATTACH:
+ /*
+ * In P2P we can get an attach request from
+ * the other FLOGI path, so drop this one
+ */
+ break;
+
+ default:
+ __efc_domain_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_domain_ready(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg)
+{
+ std_domain_state_decl();
+
+ domain_sm_trace(domain);
+
+ switch (evt) {
+ case EFC_EVT_ENTER: {
+ /* start any pending vports */
+ if (efc_vport_start(domain)) {
+ efc_log_debug(domain->efc,
+ "efc_vport_start didn't start vports\n");
+ }
+ break;
+ }
+ case EFC_EVT_DOMAIN_LOST: {
+ if (!list_empty(&domain->nport_list)) {
+ /*
+ * if there are nports, transition to wait state
+ * and send shutdown to each nport
+ */
+ struct efc_nport *nport = NULL, *nport_next = NULL;
+
+ efc_sm_transition(ctx, __efc_domain_wait_nports_free,
+ NULL);
+ list_for_each_entry_safe(nport, nport_next,
+ &domain->nport_list,
+ list_entry) {
+ efc_sm_post_event(&nport->sm,
+ EFC_EVT_SHUTDOWN, NULL);
+ }
+ } else {
+ /* no nports exist, free domain */
+ efc_sm_transition(ctx, __efc_domain_wait_shutdown,
+ NULL);
+ if (efc_cmd_domain_free(efc, domain))
+ efc_log_err(efc, "hw_domain_free failed\n");
+ }
+ break;
+ }
+
+ case EFC_EVT_DOMAIN_FOUND:
+ /* Should not happen */
+ efc_log_err(efc, "%s: evt: %d should not happen\n",
+ __func__, evt);
+ break;
+
+ case EFC_EVT_DOMAIN_REQ_ATTACH: {
+ /* can happen during p2p */
+ u32 fc_id;
+
+ fc_id = *((u32 *)arg);
+
+ /* Assume that the domain is attached */
+ WARN_ON(!domain->attached);
+
+ /*
+ * Verify that the requested FC_ID
+ * is the same as the one we're working with
+ */
+ WARN_ON(domain->nport->fc_id != fc_id);
+ break;
+ }
+
+ default:
+ __efc_domain_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_domain_wait_nports_free(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
+ void *arg)
+{
+ std_domain_state_decl();
+
+ domain_sm_trace(domain);
+
+ /* Wait for nodes to free prior to the domain shutdown */
+ switch (evt) {
+ case EFC_EVT_ALL_CHILD_NODES_FREE: {
+ int rc;
+
+ /* sm: / efc_hw_domain_free */
+ efc_sm_transition(ctx, __efc_domain_wait_shutdown, NULL);
+
+ /* Request efc_hw_domain_free and wait for completion */
+ rc = efc_cmd_domain_free(efc, domain);
+ if (rc) {
+ efc_log_err(efc, "efc_hw_domain_free() failed: %d\n",
+ rc);
+ }
+ break;
+ }
+ default:
+ __efc_domain_common_shutdown(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_domain_wait_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ std_domain_state_decl();
+
+ domain_sm_trace(domain);
+
+ switch (evt) {
+ case EFC_EVT_DOMAIN_FREE_OK:
+ /* sm: / domain_free */
+ if (domain->domain_found_pending) {
+ /*
+ * save fcf_wwn and drec from this domain,
+ * free current domain and allocate
+ * a new one with the same fcf_wwn
+ * could use a SLI-4 "re-register VPI"
+ * operation here?
+ */
+ u64 fcf_wwn = domain->fcf_wwn;
+ struct efc_domain_record drec = domain->pending_drec;
+
+ efc_log_debug(efc, "Reallocating domain\n");
+ domain->req_domain_free = true;
+ domain = efc_domain_alloc(efc, fcf_wwn);
+
+ if (!domain) {
+ efc_log_err(efc,
+ "efc_domain_alloc() failed\n");
+ return;
+ }
+ /*
+ * got a new domain; at this point,
+ * there are at least two domains
+ * once the req_domain_free flag is processed,
+ * the associated domain will be removed.
+ */
+ efc_sm_transition(&domain->drvsm, __efc_domain_init,
+ NULL);
+ efc_sm_post_event(&domain->drvsm,
+ EFC_EVT_DOMAIN_FOUND, &drec);
+ } else {
+ domain->req_domain_free = true;
+ }
+ break;
+ default:
+ __efc_domain_common_shutdown(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_domain_wait_domain_lost(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ std_domain_state_decl();
+
+ domain_sm_trace(domain);
+
+ /*
+ * Wait for the domain alloc/attach completion
+ * after receiving a domain lost.
+ */
+ switch (evt) {
+ case EFC_EVT_DOMAIN_ALLOC_OK:
+ case EFC_EVT_DOMAIN_ATTACH_OK: {
+ if (!list_empty(&domain->nport_list)) {
+ /*
+ * if there are nports, transition to
+ * wait state and send shutdown to each nport
+ */
+ struct efc_nport *nport = NULL, *nport_next = NULL;
+
+ efc_sm_transition(ctx, __efc_domain_wait_nports_free,
+ NULL);
+ list_for_each_entry_safe(nport, nport_next,
+ &domain->nport_list,
+ list_entry) {
+ efc_sm_post_event(&nport->sm,
+ EFC_EVT_SHUTDOWN, NULL);
+ }
+ } else {
+ /* no nports exist, free domain */
+ efc_sm_transition(ctx, __efc_domain_wait_shutdown,
+ NULL);
+ if (efc_cmd_domain_free(efc, domain))
+ efc_log_err(efc, "hw_domain_free() failed\n");
+ }
+ break;
+ }
+ case EFC_EVT_DOMAIN_ALLOC_FAIL:
+ case EFC_EVT_DOMAIN_ATTACH_FAIL:
+ efc_log_err(efc, "[domain] %-20s: failed\n",
+ efc_sm_event_name(evt));
+ break;
+
+ default:
+ __efc_domain_common_shutdown(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_domain_attach_internal(struct efc_domain *domain, u32 s_id)
+{
+ memcpy(domain->dma.virt,
+ ((uint8_t *)domain->flogi_service_params) + 4,
+ sizeof(struct fc_els_flogi) - 4);
+ (void)efc_sm_post_event(&domain->drvsm, EFC_EVT_DOMAIN_REQ_ATTACH,
+ &s_id);
+}
+
+void
+efc_domain_attach(struct efc_domain *domain, u32 s_id)
+{
+ __efc_domain_attach_internal(domain, s_id);
+}
+
+int
+efc_domain_post_event(struct efc_domain *domain,
+ enum efc_sm_event event, void *arg)
+{
+ int rc;
+ bool req_domain_free;
+
+ rc = efc_sm_post_event(&domain->drvsm, event, arg);
+
+ req_domain_free = domain->req_domain_free;
+ domain->req_domain_free = false;
+
+ if (req_domain_free)
+ efc_domain_free(domain);
+
+ return rc;
+}
+
+static void
+efct_domain_process_pending(struct efc_domain *domain)
+{
+ struct efc *efc = domain->efc;
+ struct efc_hw_sequence *seq = NULL;
+ u32 processed = 0;
+ unsigned long flags = 0;
+
+ for (;;) {
+ /* need to check for hold frames condition after each frame
+ * processed because any given frame could cause a transition
+ * to a state that holds frames
+ */
+ if (efc->hold_frames)
+ break;
+
+ /* Get next frame/sequence */
+ spin_lock_irqsave(&efc->pend_frames_lock, flags);
+
+ if (!list_empty(&efc->pend_frames)) {
+ seq = list_first_entry(&efc->pend_frames,
+ struct efc_hw_sequence, list_entry);
+ list_del(&seq->list_entry);
+ }
+
+ if (!seq) {
+ processed = efc->pend_frames_processed;
+ efc->pend_frames_processed = 0;
+ spin_unlock_irqrestore(&efc->pend_frames_lock, flags);
+ break;
+ }
+ efc->pend_frames_processed++;
+
+ spin_unlock_irqrestore(&efc->pend_frames_lock, flags);
+
+ /* now dispatch frame(s) to dispatch function */
+ if (efc_domain_dispatch_frame(domain, seq))
+ efc->tt.hw_seq_free(efc, seq);
+
+ seq = NULL;
+ }
+
+ if (processed != 0)
+ efc_log_debug(efc, "%u domain frames held and processed\n",
+ processed);
+}
+
+void
+efc_dispatch_frame(struct efc *efc, struct efc_hw_sequence *seq)
+{
+ struct efc_domain *domain = efc->domain;
+
+ /*
+ * If we are holding frames or the domain is not yet registered or
+ * there's already frames on the pending list,
+ * then add the new frame to pending list
+ */
+ if (!domain || efc->hold_frames || !list_empty(&efc->pend_frames)) {
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&efc->pend_frames_lock, flags);
+ INIT_LIST_HEAD(&seq->list_entry);
+ list_add_tail(&seq->list_entry, &efc->pend_frames);
+ spin_unlock_irqrestore(&efc->pend_frames_lock, flags);
+
+ if (domain) {
+ /* immediately process pending frames */
+ efct_domain_process_pending(domain);
+ }
+ } else {
+ /*
+ * We are not holding frames and pending list is empty,
+ * just process frame. A non-zero return means the frame
+ * was not handled - so cleanup
+ */
+ if (efc_domain_dispatch_frame(domain, seq))
+ efc->tt.hw_seq_free(efc, seq);
+ }
+}
+
+int
+efc_domain_dispatch_frame(void *arg, struct efc_hw_sequence *seq)
+{
+ struct efc_domain *domain = (struct efc_domain *)arg;
+ struct efc *efc = domain->efc;
+ struct fc_frame_header *hdr;
+ struct efc_node *node = NULL;
+ struct efc_nport *nport = NULL;
+ unsigned long flags = 0;
+ u32 s_id, d_id, rc = EFC_HW_SEQ_FREE;
+
+ if (!seq->header || !seq->header->dma.virt || !seq->payload->dma.virt) {
+ efc_log_err(efc, "Sequence header or payload is null\n");
+ return rc;
+ }
+
+ hdr = seq->header->dma.virt;
+
+ /* extract the s_id and d_id */
+ s_id = ntoh24(hdr->fh_s_id);
+ d_id = ntoh24(hdr->fh_d_id);
+
+ spin_lock_irqsave(&efc->lock, flags);
+
+ nport = efc_nport_find(domain, d_id);
+ if (!nport) {
+ if (hdr->fh_type == FC_TYPE_FCP) {
+ /* Drop frame */
+ efc_log_warn(efc, "FCP frame with invalid d_id x%x\n",
+ d_id);
+ goto out;
+ }
+
+ /* p2p will use this case */
+ nport = domain->nport;
+ if (!nport || !kref_get_unless_zero(&nport->ref)) {
+ efc_log_err(efc, "Physical nport is NULL\n");
+ goto out;
+ }
+ }
+
+ /* Lookup the node given the remote s_id */
+ node = efc_node_find(nport, s_id);
+
+ /* If not found, then create a new node */
+ if (!node) {
+ /*
+ * If this is solicited data or control based on R_CTL and
+ * there is no node context, then we can drop the frame
+ */
+ if ((hdr->fh_r_ctl == FC_RCTL_DD_SOL_DATA) ||
+ (hdr->fh_r_ctl == FC_RCTL_DD_SOL_CTL)) {
+ efc_log_debug(efc, "sol data/ctrl frame without node\n");
+ goto out_release;
+ }
+
+ node = efc_node_alloc(nport, s_id, false, false);
+ if (!node) {
+ efc_log_err(efc, "efc_node_alloc() failed\n");
+ goto out_release;
+ }
+ /* don't send PLOGI on efc_d_init entry */
+ efc_node_init_device(node, false);
+ }
+
+ if (node->hold_frames || !list_empty(&node->pend_frames)) {
+ /* add frame to node's pending list */
+ spin_lock(&node->pend_frames_lock);
+ INIT_LIST_HEAD(&seq->list_entry);
+ list_add_tail(&seq->list_entry, &node->pend_frames);
+ spin_unlock(&node->pend_frames_lock);
+ rc = EFC_HW_SEQ_HOLD;
+ goto out_release;
+ }
+
+ /* now dispatch frame to the node frame handler */
+ efc_node_dispatch_frame(node, seq);
+
+out_release:
+ kref_put(&nport->ref, nport->release);
+out:
+ spin_unlock_irqrestore(&efc->lock, flags);
+ return rc;
+}
+
+void
+efc_node_dispatch_frame(void *arg, struct efc_hw_sequence *seq)
+{
+ struct fc_frame_header *hdr = seq->header->dma.virt;
+ u32 port_id;
+ struct efc_node *node = (struct efc_node *)arg;
+ struct efc *efc = node->efc;
+
+ port_id = ntoh24(hdr->fh_s_id);
+
+ if (WARN_ON(port_id != node->rnode.fc_id))
+ return;
+
+ if ((!(ntoh24(hdr->fh_f_ctl) & FC_FC_END_SEQ)) ||
+ !(ntoh24(hdr->fh_f_ctl) & FC_FC_SEQ_INIT)) {
+ node_printf(node,
+ "Drop frame hdr = %08x %08x %08x %08x %08x %08x\n",
+ cpu_to_be32(((u32 *)hdr)[0]),
+ cpu_to_be32(((u32 *)hdr)[1]),
+ cpu_to_be32(((u32 *)hdr)[2]),
+ cpu_to_be32(((u32 *)hdr)[3]),
+ cpu_to_be32(((u32 *)hdr)[4]),
+ cpu_to_be32(((u32 *)hdr)[5]));
+ return;
+ }
+
+ switch (hdr->fh_r_ctl) {
+ case FC_RCTL_ELS_REQ:
+ case FC_RCTL_ELS_REP:
+ efc_node_recv_els_frame(node, seq);
+ break;
+
+ case FC_RCTL_BA_ABTS:
+ case FC_RCTL_BA_ACC:
+ case FC_RCTL_BA_RJT:
+ case FC_RCTL_BA_NOP:
+ efc_log_err(efc, "Received ABTS:\n");
+ break;
+
+ case FC_RCTL_DD_UNSOL_CMD:
+ case FC_RCTL_DD_UNSOL_CTL:
+ switch (hdr->fh_type) {
+ case FC_TYPE_FCP:
+ if ((hdr->fh_r_ctl & 0xf) == FC_RCTL_DD_UNSOL_CMD) {
+ if (!node->fcp_enabled) {
+ efc_node_recv_fcp_cmd(node, seq);
+ break;
+ }
+ efc_log_err(efc, "Recvd FCP CMD. Drop IO\n");
+ } else if ((hdr->fh_r_ctl & 0xf) ==
+ FC_RCTL_DD_SOL_DATA) {
+ node_printf(node,
+ "solicited data recvd. Drop IO\n");
+ }
+ break;
+
+ case FC_TYPE_CT:
+ efc_node_recv_ct_frame(node, seq);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ efc_log_err(efc, "Unhandled frame rctl: %02x\n", hdr->fh_r_ctl);
+ }
+}
diff --git a/drivers/scsi/elx/libefc/efc_domain.h b/drivers/scsi/elx/libefc/efc_domain.h
new file mode 100644
index 000000000000..5468ea7ab19b
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_domain.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+/*
+ * Declare driver's domain handler exported interface
+ */
+
+#ifndef __EFCT_DOMAIN_H__
+#define __EFCT_DOMAIN_H__
+
+struct efc_domain *
+efc_domain_alloc(struct efc *efc, uint64_t fcf_wwn);
+void
+efc_domain_free(struct efc_domain *domain);
+
+void
+__efc_domain_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg);
+void
+__efc_domain_wait_alloc(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
+ void *arg);
+void
+__efc_domain_allocated(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
+ void *arg);
+void
+__efc_domain_wait_attach(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
+ void *arg);
+void
+__efc_domain_ready(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg);
+void
+__efc_domain_wait_nports_free(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
+ void *arg);
+void
+__efc_domain_wait_shutdown(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
+ void *arg);
+void
+__efc_domain_wait_domain_lost(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
+ void *arg);
+void
+efc_domain_attach(struct efc_domain *domain, u32 s_id);
+int
+efc_domain_post_event(struct efc_domain *domain, enum efc_sm_event event,
+ void *arg);
+void
+__efc_domain_attach_internal(struct efc_domain *domain, u32 s_id);
+
+int
+efc_domain_dispatch_frame(void *arg, struct efc_hw_sequence *seq);
+void
+efc_node_dispatch_frame(void *arg, struct efc_hw_sequence *seq);
+
+#endif /* __EFCT_DOMAIN_H__ */
diff --git a/drivers/scsi/elx/libefc/efc_els.c b/drivers/scsi/elx/libefc/efc_els.c
new file mode 100644
index 000000000000..24db0accb256
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_els.c
@@ -0,0 +1,1098 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+/*
+ * Functions to build and send ELS/CT/BLS commands and responses.
+ */
+
+#include "efc.h"
+#include "efc_els.h"
+#include "../libefc_sli/sli4.h"
+
+#define EFC_LOG_ENABLE_ELS_TRACE(efc) \
+ (((efc) != NULL) ? (((efc)->logmask & (1U << 1)) != 0) : 0)
+
+#define node_els_trace() \
+ do { \
+ if (EFC_LOG_ENABLE_ELS_TRACE(efc)) \
+ efc_log_info(efc, "[%s] %-20s\n", \
+ node->display_name, __func__); \
+ } while (0)
+
+#define els_io_printf(els, fmt, ...) \
+ efc_log_err((struct efc *)els->node->efc,\
+ "[%s] %-8s " fmt, \
+ els->node->display_name,\
+ els->display_name, ##__VA_ARGS__)
+
+#define EFC_ELS_RSP_LEN 1024
+#define EFC_ELS_GID_PT_RSP_LEN 8096
+
+struct efc_els_io_req *
+efc_els_io_alloc(struct efc_node *node, u32 reqlen)
+{
+ return efc_els_io_alloc_size(node, reqlen, EFC_ELS_RSP_LEN);
+}
+
+struct efc_els_io_req *
+efc_els_io_alloc_size(struct efc_node *node, u32 reqlen, u32 rsplen)
+{
+ struct efc *efc;
+ struct efc_els_io_req *els;
+ unsigned long flags = 0;
+
+ efc = node->efc;
+
+ spin_lock_irqsave(&node->els_ios_lock, flags);
+
+ if (!node->els_io_enabled) {
+ efc_log_err(efc, "els io alloc disabled\n");
+ spin_unlock_irqrestore(&node->els_ios_lock, flags);
+ return NULL;
+ }
+
+ els = mempool_alloc(efc->els_io_pool, GFP_ATOMIC);
+ if (!els) {
+ atomic_add_return(1, &efc->els_io_alloc_failed_count);
+ spin_unlock_irqrestore(&node->els_ios_lock, flags);
+ return NULL;
+ }
+
+ /* initialize refcount */
+ kref_init(&els->ref);
+ els->release = _efc_els_io_free;
+
+ /* populate generic io fields */
+ els->node = node;
+
+ /* now allocate DMA for request and response */
+ els->io.req.size = reqlen;
+ els->io.req.virt = dma_alloc_coherent(&efc->pci->dev, els->io.req.size,
+ &els->io.req.phys, GFP_DMA);
+ if (!els->io.req.virt) {
+ mempool_free(els, efc->els_io_pool);
+ spin_unlock_irqrestore(&node->els_ios_lock, flags);
+ return NULL;
+ }
+
+ els->io.rsp.size = rsplen;
+ els->io.rsp.virt = dma_alloc_coherent(&efc->pci->dev, els->io.rsp.size,
+ &els->io.rsp.phys, GFP_DMA);
+ if (!els->io.rsp.virt) {
+ dma_free_coherent(&efc->pci->dev, els->io.req.size,
+ els->io.req.virt, els->io.req.phys);
+ mempool_free(els, efc->els_io_pool);
+ els = NULL;
+ }
+
+ if (els) {
+ /* initialize fields */
+ els->els_retries_remaining = EFC_FC_ELS_DEFAULT_RETRIES;
+
+ /* add els structure to ELS IO list */
+ INIT_LIST_HEAD(&els->list_entry);
+ list_add_tail(&els->list_entry, &node->els_ios_list);
+ }
+
+ spin_unlock_irqrestore(&node->els_ios_lock, flags);
+ return els;
+}
+
+void
+efc_els_io_free(struct efc_els_io_req *els)
+{
+ kref_put(&els->ref, els->release);
+}
+
+void
+_efc_els_io_free(struct kref *arg)
+{
+ struct efc_els_io_req *els =
+ container_of(arg, struct efc_els_io_req, ref);
+ struct efc *efc;
+ struct efc_node *node;
+ int send_empty_event = false;
+ unsigned long flags = 0;
+
+ node = els->node;
+ efc = node->efc;
+
+ spin_lock_irqsave(&node->els_ios_lock, flags);
+
+ list_del(&els->list_entry);
+ /* Send list empty event if the IO allocator
+ * is disabled, and the list is empty
+ * If node->els_io_enabled was not checked,
+ * the event would be posted continually
+ */
+ send_empty_event = (!node->els_io_enabled &&
+ list_empty(&node->els_ios_list));
+
+ spin_unlock_irqrestore(&node->els_ios_lock, flags);
+
+ /* free ELS request and response buffers */
+ dma_free_coherent(&efc->pci->dev, els->io.rsp.size,
+ els->io.rsp.virt, els->io.rsp.phys);
+ dma_free_coherent(&efc->pci->dev, els->io.req.size,
+ els->io.req.virt, els->io.req.phys);
+
+ mempool_free(els, efc->els_io_pool);
+
+ if (send_empty_event)
+ efc_scsi_io_list_empty(node->efc, node);
+}
+
+static void
+efc_els_retry(struct efc_els_io_req *els);
+
+static void
+efc_els_delay_timer_cb(struct timer_list *t)
+{
+ struct efc_els_io_req *els = from_timer(els, t, delay_timer);
+
+ /* Retry delay timer expired, retry the ELS request */
+ efc_els_retry(els);
+}
+
+static int
+efc_els_req_cb(void *arg, u32 length, int status, u32 ext_status)
+{
+ struct efc_els_io_req *els;
+ struct efc_node *node;
+ struct efc *efc;
+ struct efc_node_cb cbdata;
+ u32 reason_code;
+
+ els = arg;
+ node = els->node;
+ efc = node->efc;
+
+ if (status)
+ els_io_printf(els, "status x%x ext x%x\n", status, ext_status);
+
+ /* set the response len element of els->rsp */
+ els->io.rsp.len = length;
+
+ cbdata.status = status;
+ cbdata.ext_status = ext_status;
+ cbdata.header = NULL;
+ cbdata.els_rsp = els->io.rsp;
+
+ /* set the response len element of els->rsp */
+ cbdata.rsp_len = length;
+
+ /* FW returns the number of bytes received on the link in
+ * the WCQE, not the amount placed in the buffer; use this info to
+ * check if there was an overrun.
+ */
+ if (length > els->io.rsp.size) {
+ efc_log_warn(efc,
+ "ELS response returned len=%d > buflen=%zu\n",
+ length, els->io.rsp.size);
+ efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_REQ_FAIL, &cbdata);
+ return 0;
+ }
+
+ /* Post event to ELS IO object */
+ switch (status) {
+ case SLI4_FC_WCQE_STATUS_SUCCESS:
+ efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_REQ_OK, &cbdata);
+ break;
+
+ case SLI4_FC_WCQE_STATUS_LS_RJT:
+ reason_code = (ext_status >> 16) & 0xff;
+
+ /* delay and retry if reason code is Logical Busy */
+ switch (reason_code) {
+ case ELS_RJT_BUSY:
+ els->node->els_req_cnt--;
+ els_io_printf(els,
+ "LS_RJT Logical Busy, delay and retry\n");
+ timer_setup(&els->delay_timer,
+ efc_els_delay_timer_cb, 0);
+ mod_timer(&els->delay_timer,
+ jiffies + msecs_to_jiffies(5000));
+ break;
+ default:
+ efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_REQ_RJT,
+ &cbdata);
+ break;
+ }
+ break;
+
+ case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
+ switch (ext_status) {
+ case SLI4_FC_LOCAL_REJECT_SEQUENCE_TIMEOUT:
+ efc_els_retry(els);
+ break;
+ default:
+ efc_log_err(efc, "LOCAL_REJECT with ext status:%x\n",
+ ext_status);
+ efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_REQ_FAIL,
+ &cbdata);
+ break;
+ }
+ break;
+ default: /* Other error */
+ efc_log_warn(efc, "els req failed status x%x, ext_status x%x\n",
+ status, ext_status);
+ efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_REQ_FAIL, &cbdata);
+ break;
+ }
+
+ return 0;
+}
+
+void efc_disc_io_complete(struct efc_disc_io *io, u32 len, u32 status,
+ u32 ext_status)
+{
+ struct efc_els_io_req *els =
+ container_of(io, struct efc_els_io_req, io);
+
+ WARN_ON_ONCE(!els->cb);
+
+ ((efc_hw_srrs_cb_t)els->cb) (els, len, status, ext_status);
+}
+
+static int efc_els_send_req(struct efc_node *node, struct efc_els_io_req *els,
+ enum efc_disc_io_type io_type)
+{
+ int rc = 0;
+ struct efc *efc = node->efc;
+ struct efc_node_cb cbdata;
+
+ /* update ELS request counter */
+ els->node->els_req_cnt++;
+
+ /* Prepare the IO request details */
+ els->io.io_type = io_type;
+ els->io.xmit_len = els->io.req.size;
+ els->io.rsp_len = els->io.rsp.size;
+ els->io.rpi = node->rnode.indicator;
+ els->io.vpi = node->nport->indicator;
+ els->io.s_id = node->nport->fc_id;
+ els->io.d_id = node->rnode.fc_id;
+
+ if (node->rnode.attached)
+ els->io.rpi_registered = true;
+
+ els->cb = efc_els_req_cb;
+
+ rc = efc->tt.send_els(efc, &els->io);
+ if (!rc)
+ return rc;
+
+ cbdata.status = EFC_STATUS_INVALID;
+ cbdata.ext_status = EFC_STATUS_INVALID;
+ cbdata.els_rsp = els->io.rsp;
+ efc_log_err(efc, "efc_els_send failed: %d\n", rc);
+ efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_REQ_FAIL, &cbdata);
+
+ return rc;
+}
+
+static void
+efc_els_retry(struct efc_els_io_req *els)
+{
+ struct efc *efc;
+ struct efc_node_cb cbdata;
+ u32 rc;
+
+ efc = els->node->efc;
+ cbdata.status = EFC_STATUS_INVALID;
+ cbdata.ext_status = EFC_STATUS_INVALID;
+ cbdata.els_rsp = els->io.rsp;
+
+ if (els->els_retries_remaining) {
+ els->els_retries_remaining--;
+ rc = efc->tt.send_els(efc, &els->io);
+ } else {
+ rc = -EIO;
+ }
+
+ if (rc) {
+ efc_log_err(efc, "ELS retries exhausted\n");
+ efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_REQ_FAIL, &cbdata);
+ }
+}
+
+static int
+efc_els_acc_cb(void *arg, u32 length, int status, u32 ext_status)
+{
+ struct efc_els_io_req *els;
+ struct efc_node *node;
+ struct efc *efc;
+ struct efc_node_cb cbdata;
+
+ els = arg;
+ node = els->node;
+ efc = node->efc;
+
+ cbdata.status = status;
+ cbdata.ext_status = ext_status;
+ cbdata.header = NULL;
+ cbdata.els_rsp = els->io.rsp;
+
+ /* Post node event */
+ switch (status) {
+ case SLI4_FC_WCQE_STATUS_SUCCESS:
+ efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_CMPL_OK, &cbdata);
+ break;
+
+ default: /* Other error */
+ efc_log_warn(efc, "[%s] %-8s failed status x%x, ext x%x\n",
+ node->display_name, els->display_name,
+ status, ext_status);
+ efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_CMPL_FAIL, &cbdata);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+efc_els_send_rsp(struct efc_els_io_req *els, u32 rsplen)
+{
+ int rc = 0;
+ struct efc_node_cb cbdata;
+ struct efc_node *node = els->node;
+ struct efc *efc = node->efc;
+
+ /* increment ELS completion counter */
+ node->els_cmpl_cnt++;
+
+ els->io.io_type = EFC_DISC_IO_ELS_RESP;
+ els->cb = efc_els_acc_cb;
+
+ /* Prepare the IO request details */
+ els->io.xmit_len = rsplen;
+ els->io.rsp_len = els->io.rsp.size;
+ els->io.rpi = node->rnode.indicator;
+ els->io.vpi = node->nport->indicator;
+ if (node->nport->fc_id != U32_MAX)
+ els->io.s_id = node->nport->fc_id;
+ else
+ els->io.s_id = els->io.iparam.els.s_id;
+ els->io.d_id = node->rnode.fc_id;
+
+ if (node->attached)
+ els->io.rpi_registered = true;
+
+ rc = efc->tt.send_els(efc, &els->io);
+ if (!rc)
+ return rc;
+
+ cbdata.status = EFC_STATUS_INVALID;
+ cbdata.ext_status = EFC_STATUS_INVALID;
+ cbdata.els_rsp = els->io.rsp;
+ efc_els_io_cleanup(els, EFC_EVT_SRRS_ELS_CMPL_FAIL, &cbdata);
+
+ return rc;
+}
+
+int
+efc_send_plogi(struct efc_node *node)
+{
+ struct efc_els_io_req *els;
+ struct efc *efc = node->efc;
+ struct fc_els_flogi *plogi;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc(node, sizeof(*plogi));
+ if (!els) {
+ efc_log_err(efc, "IO alloc failed\n");
+ return -EIO;
+ }
+ els->display_name = "plogi";
+
+ /* Build PLOGI request */
+ plogi = els->io.req.virt;
+
+ memcpy(plogi, node->nport->service_params, sizeof(*plogi));
+
+ plogi->fl_cmd = ELS_PLOGI;
+ memset(plogi->_fl_resvd, 0, sizeof(plogi->_fl_resvd));
+
+ return efc_els_send_req(node, els, EFC_DISC_IO_ELS_REQ);
+}
+
+int
+efc_send_flogi(struct efc_node *node)
+{
+ struct efc_els_io_req *els;
+ struct efc *efc;
+ struct fc_els_flogi *flogi;
+
+ efc = node->efc;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc(node, sizeof(*flogi));
+ if (!els) {
+ efc_log_err(efc, "IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->display_name = "flogi";
+
+ /* Build FLOGI request */
+ flogi = els->io.req.virt;
+
+ memcpy(flogi, node->nport->service_params, sizeof(*flogi));
+ flogi->fl_cmd = ELS_FLOGI;
+ memset(flogi->_fl_resvd, 0, sizeof(flogi->_fl_resvd));
+
+ return efc_els_send_req(node, els, EFC_DISC_IO_ELS_REQ);
+}
+
+int
+efc_send_fdisc(struct efc_node *node)
+{
+ struct efc_els_io_req *els;
+ struct efc *efc;
+ struct fc_els_flogi *fdisc;
+
+ efc = node->efc;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc(node, sizeof(*fdisc));
+ if (!els) {
+ efc_log_err(efc, "IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->display_name = "fdisc";
+
+ /* Build FDISC request */
+ fdisc = els->io.req.virt;
+
+ memcpy(fdisc, node->nport->service_params, sizeof(*fdisc));
+ fdisc->fl_cmd = ELS_FDISC;
+ memset(fdisc->_fl_resvd, 0, sizeof(fdisc->_fl_resvd));
+
+ return efc_els_send_req(node, els, EFC_DISC_IO_ELS_REQ);
+}
+
+int
+efc_send_prli(struct efc_node *node)
+{
+ struct efc *efc = node->efc;
+ struct efc_els_io_req *els;
+ struct {
+ struct fc_els_prli prli;
+ struct fc_els_spp spp;
+ } *pp;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc(node, sizeof(*pp));
+ if (!els) {
+ efc_log_err(efc, "IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->display_name = "prli";
+
+ /* Build PRLI request */
+ pp = els->io.req.virt;
+
+ memset(pp, 0, sizeof(*pp));
+
+ pp->prli.prli_cmd = ELS_PRLI;
+ pp->prli.prli_spp_len = 16;
+ pp->prli.prli_len = cpu_to_be16(sizeof(*pp));
+ pp->spp.spp_type = FC_TYPE_FCP;
+ pp->spp.spp_type_ext = 0;
+ pp->spp.spp_flags = FC_SPP_EST_IMG_PAIR;
+ pp->spp.spp_params = cpu_to_be32(FCP_SPPF_RD_XRDY_DIS |
+ (node->nport->enable_ini ?
+ FCP_SPPF_INIT_FCN : 0) |
+ (node->nport->enable_tgt ?
+ FCP_SPPF_TARG_FCN : 0));
+
+ return efc_els_send_req(node, els, EFC_DISC_IO_ELS_REQ);
+}
+
+int
+efc_send_logo(struct efc_node *node)
+{
+ struct efc *efc = node->efc;
+ struct efc_els_io_req *els;
+ struct fc_els_logo *logo;
+ struct fc_els_flogi *sparams;
+
+ node_els_trace();
+
+ sparams = (struct fc_els_flogi *)node->nport->service_params;
+
+ els = efc_els_io_alloc(node, sizeof(*logo));
+ if (!els) {
+ efc_log_err(efc, "IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->display_name = "logo";
+
+ /* Build LOGO request */
+
+ logo = els->io.req.virt;
+
+ memset(logo, 0, sizeof(*logo));
+ logo->fl_cmd = ELS_LOGO;
+ hton24(logo->fl_n_port_id, node->rnode.nport->fc_id);
+ logo->fl_n_port_wwn = sparams->fl_wwpn;
+
+ return efc_els_send_req(node, els, EFC_DISC_IO_ELS_REQ);
+}
+
+int
+efc_send_adisc(struct efc_node *node)
+{
+ struct efc *efc = node->efc;
+ struct efc_els_io_req *els;
+ struct fc_els_adisc *adisc;
+ struct fc_els_flogi *sparams;
+ struct efc_nport *nport = node->nport;
+
+ node_els_trace();
+
+ sparams = (struct fc_els_flogi *)node->nport->service_params;
+
+ els = efc_els_io_alloc(node, sizeof(*adisc));
+ if (!els) {
+ efc_log_err(efc, "IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->display_name = "adisc";
+
+ /* Build ADISC request */
+
+ adisc = els->io.req.virt;
+
+ memset(adisc, 0, sizeof(*adisc));
+ adisc->adisc_cmd = ELS_ADISC;
+ hton24(adisc->adisc_hard_addr, nport->fc_id);
+ adisc->adisc_wwpn = sparams->fl_wwpn;
+ adisc->adisc_wwnn = sparams->fl_wwnn;
+ hton24(adisc->adisc_port_id, node->rnode.nport->fc_id);
+
+ return efc_els_send_req(node, els, EFC_DISC_IO_ELS_REQ);
+}
+
+int
+efc_send_scr(struct efc_node *node)
+{
+ struct efc_els_io_req *els;
+ struct efc *efc = node->efc;
+ struct fc_els_scr *req;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc(node, sizeof(*req));
+ if (!els) {
+ efc_log_err(efc, "IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->display_name = "scr";
+
+ req = els->io.req.virt;
+
+ memset(req, 0, sizeof(*req));
+ req->scr_cmd = ELS_SCR;
+ req->scr_reg_func = ELS_SCRF_FULL;
+
+ return efc_els_send_req(node, els, EFC_DISC_IO_ELS_REQ);
+}
+
+int
+efc_send_ls_rjt(struct efc_node *node, u32 ox_id, u32 reason_code,
+ u32 reason_code_expl, u32 vendor_unique)
+{
+ struct efc *efc = node->efc;
+ struct efc_els_io_req *els = NULL;
+ struct fc_els_ls_rjt *rjt;
+
+ els = efc_els_io_alloc(node, sizeof(*rjt));
+ if (!els) {
+ efc_log_err(efc, "els IO alloc failed\n");
+ return -EIO;
+ }
+
+ node_els_trace();
+
+ els->display_name = "ls_rjt";
+
+ memset(&els->io.iparam, 0, sizeof(els->io.iparam));
+ els->io.iparam.els.ox_id = ox_id;
+
+ rjt = els->io.req.virt;
+ memset(rjt, 0, sizeof(*rjt));
+
+ rjt->er_cmd = ELS_LS_RJT;
+ rjt->er_reason = reason_code;
+ rjt->er_explan = reason_code_expl;
+
+ return efc_els_send_rsp(els, sizeof(*rjt));
+}
+
+int
+efc_send_plogi_acc(struct efc_node *node, u32 ox_id)
+{
+ struct efc *efc = node->efc;
+ struct efc_els_io_req *els = NULL;
+ struct fc_els_flogi *plogi;
+ struct fc_els_flogi *req = (struct fc_els_flogi *)node->service_params;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc(node, sizeof(*plogi));
+ if (!els) {
+ efc_log_err(efc, "els IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->display_name = "plogi_acc";
+
+ memset(&els->io.iparam, 0, sizeof(els->io.iparam));
+ els->io.iparam.els.ox_id = ox_id;
+
+ plogi = els->io.req.virt;
+
+ /* copy our port's service parameters to payload */
+ memcpy(plogi, node->nport->service_params, sizeof(*plogi));
+ plogi->fl_cmd = ELS_LS_ACC;
+ memset(plogi->_fl_resvd, 0, sizeof(plogi->_fl_resvd));
+
+ /* Set Application header support bit if requested */
+ if (req->fl_csp.sp_features & cpu_to_be16(FC_SP_FT_BCAST))
+ plogi->fl_csp.sp_features |= cpu_to_be16(FC_SP_FT_BCAST);
+
+ return efc_els_send_rsp(els, sizeof(*plogi));
+}
+
+int
+efc_send_flogi_p2p_acc(struct efc_node *node, u32 ox_id, u32 s_id)
+{
+ struct efc *efc = node->efc;
+ struct efc_els_io_req *els = NULL;
+ struct fc_els_flogi *flogi;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc(node, sizeof(*flogi));
+ if (!els) {
+ efc_log_err(efc, "els IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->display_name = "flogi_p2p_acc";
+
+ memset(&els->io.iparam, 0, sizeof(els->io.iparam));
+ els->io.iparam.els.ox_id = ox_id;
+ els->io.iparam.els.s_id = s_id;
+
+ flogi = els->io.req.virt;
+
+ /* copy our port's service parameters to payload */
+ memcpy(flogi, node->nport->service_params, sizeof(*flogi));
+ flogi->fl_cmd = ELS_LS_ACC;
+ memset(flogi->_fl_resvd, 0, sizeof(flogi->_fl_resvd));
+
+ memset(flogi->fl_cssp, 0, sizeof(flogi->fl_cssp));
+
+ return efc_els_send_rsp(els, sizeof(*flogi));
+}
+
+int
+efc_send_prli_acc(struct efc_node *node, u32 ox_id)
+{
+ struct efc *efc = node->efc;
+ struct efc_els_io_req *els = NULL;
+ struct {
+ struct fc_els_prli prli;
+ struct fc_els_spp spp;
+ } *pp;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc(node, sizeof(*pp));
+ if (!els) {
+ efc_log_err(efc, "els IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->display_name = "prli_acc";
+
+ memset(&els->io.iparam, 0, sizeof(els->io.iparam));
+ els->io.iparam.els.ox_id = ox_id;
+
+ pp = els->io.req.virt;
+ memset(pp, 0, sizeof(*pp));
+
+ pp->prli.prli_cmd = ELS_LS_ACC;
+ pp->prli.prli_spp_len = 0x10;
+ pp->prli.prli_len = cpu_to_be16(sizeof(*pp));
+ pp->spp.spp_type = FC_TYPE_FCP;
+ pp->spp.spp_type_ext = 0;
+ pp->spp.spp_flags = FC_SPP_EST_IMG_PAIR | FC_SPP_RESP_ACK;
+
+ pp->spp.spp_params = cpu_to_be32(FCP_SPPF_RD_XRDY_DIS |
+ (node->nport->enable_ini ?
+ FCP_SPPF_INIT_FCN : 0) |
+ (node->nport->enable_tgt ?
+ FCP_SPPF_TARG_FCN : 0));
+
+ return efc_els_send_rsp(els, sizeof(*pp));
+}
+
+int
+efc_send_prlo_acc(struct efc_node *node, u32 ox_id)
+{
+ struct efc *efc = node->efc;
+ struct efc_els_io_req *els = NULL;
+ struct {
+ struct fc_els_prlo prlo;
+ struct fc_els_spp spp;
+ } *pp;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc(node, sizeof(*pp));
+ if (!els) {
+ efc_log_err(efc, "els IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->display_name = "prlo_acc";
+
+ memset(&els->io.iparam, 0, sizeof(els->io.iparam));
+ els->io.iparam.els.ox_id = ox_id;
+
+ pp = els->io.req.virt;
+ memset(pp, 0, sizeof(*pp));
+ pp->prlo.prlo_cmd = ELS_LS_ACC;
+ pp->prlo.prlo_obs = 0x10;
+ pp->prlo.prlo_len = cpu_to_be16(sizeof(*pp));
+
+ pp->spp.spp_type = FC_TYPE_FCP;
+ pp->spp.spp_type_ext = 0;
+ pp->spp.spp_flags = FC_SPP_RESP_ACK;
+
+ return efc_els_send_rsp(els, sizeof(*pp));
+}
+
+int
+efc_send_ls_acc(struct efc_node *node, u32 ox_id)
+{
+ struct efc *efc = node->efc;
+ struct efc_els_io_req *els = NULL;
+ struct fc_els_ls_acc *acc;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc(node, sizeof(*acc));
+ if (!els) {
+ efc_log_err(efc, "els IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->display_name = "ls_acc";
+
+ memset(&els->io.iparam, 0, sizeof(els->io.iparam));
+ els->io.iparam.els.ox_id = ox_id;
+
+ acc = els->io.req.virt;
+ memset(acc, 0, sizeof(*acc));
+
+ acc->la_cmd = ELS_LS_ACC;
+
+ return efc_els_send_rsp(els, sizeof(*acc));
+}
+
+int
+efc_send_logo_acc(struct efc_node *node, u32 ox_id)
+{
+ struct efc_els_io_req *els = NULL;
+ struct efc *efc = node->efc;
+ struct fc_els_ls_acc *logo;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc(node, sizeof(*logo));
+ if (!els) {
+ efc_log_err(efc, "els IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->display_name = "logo_acc";
+
+ memset(&els->io.iparam, 0, sizeof(els->io.iparam));
+ els->io.iparam.els.ox_id = ox_id;
+
+ logo = els->io.req.virt;
+ memset(logo, 0, sizeof(*logo));
+
+ logo->la_cmd = ELS_LS_ACC;
+
+ return efc_els_send_rsp(els, sizeof(*logo));
+}
+
+int
+efc_send_adisc_acc(struct efc_node *node, u32 ox_id)
+{
+ struct efc *efc = node->efc;
+ struct efc_els_io_req *els = NULL;
+ struct fc_els_adisc *adisc;
+ struct fc_els_flogi *sparams;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc(node, sizeof(*adisc));
+ if (!els) {
+ efc_log_err(efc, "els IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->display_name = "adisc_acc";
+
+ /* Go ahead and send the ELS_ACC */
+ memset(&els->io.iparam, 0, sizeof(els->io.iparam));
+ els->io.iparam.els.ox_id = ox_id;
+
+ sparams = (struct fc_els_flogi *)node->nport->service_params;
+ adisc = els->io.req.virt;
+ memset(adisc, 0, sizeof(*adisc));
+ adisc->adisc_cmd = ELS_LS_ACC;
+ adisc->adisc_wwpn = sparams->fl_wwpn;
+ adisc->adisc_wwnn = sparams->fl_wwnn;
+ hton24(adisc->adisc_port_id, node->rnode.nport->fc_id);
+
+ return efc_els_send_rsp(els, sizeof(*adisc));
+}
+
+static inline void
+fcct_build_req_header(struct fc_ct_hdr *hdr, u16 cmd, u16 max_size)
+{
+ hdr->ct_rev = FC_CT_REV;
+ hdr->ct_fs_type = FC_FST_DIR;
+ hdr->ct_fs_subtype = FC_NS_SUBTYPE;
+ hdr->ct_options = 0;
+ hdr->ct_cmd = cpu_to_be16(cmd);
+ /* words */
+ hdr->ct_mr_size = cpu_to_be16(max_size / (sizeof(u32)));
+ hdr->ct_reason = 0;
+ hdr->ct_explan = 0;
+ hdr->ct_vendor = 0;
+}
+
+int
+efc_ns_send_rftid(struct efc_node *node)
+{
+ struct efc *efc = node->efc;
+ struct efc_els_io_req *els;
+ struct {
+ struct fc_ct_hdr hdr;
+ struct fc_ns_rft_id rftid;
+ } *ct;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc(node, sizeof(*ct));
+ if (!els) {
+ efc_log_err(efc, "IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->io.iparam.ct.r_ctl = FC_RCTL_ELS_REQ;
+ els->io.iparam.ct.type = FC_TYPE_CT;
+ els->io.iparam.ct.df_ctl = 0;
+ els->io.iparam.ct.timeout = EFC_FC_ELS_SEND_DEFAULT_TIMEOUT;
+
+ els->display_name = "rftid";
+
+ ct = els->io.req.virt;
+ memset(ct, 0, sizeof(*ct));
+ fcct_build_req_header(&ct->hdr, FC_NS_RFT_ID,
+ sizeof(struct fc_ns_rft_id));
+
+ hton24(ct->rftid.fr_fid.fp_fid, node->rnode.nport->fc_id);
+ ct->rftid.fr_fts.ff_type_map[FC_TYPE_FCP / FC_NS_BPW] =
+ cpu_to_be32(1 << (FC_TYPE_FCP % FC_NS_BPW));
+
+ return efc_els_send_req(node, els, EFC_DISC_IO_CT_REQ);
+}
+
+int
+efc_ns_send_rffid(struct efc_node *node)
+{
+ struct efc *efc = node->efc;
+ struct efc_els_io_req *els;
+ struct {
+ struct fc_ct_hdr hdr;
+ struct fc_ns_rff_id rffid;
+ } *ct;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc(node, sizeof(*ct));
+ if (!els) {
+ efc_log_err(efc, "IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->io.iparam.ct.r_ctl = FC_RCTL_ELS_REQ;
+ els->io.iparam.ct.type = FC_TYPE_CT;
+ els->io.iparam.ct.df_ctl = 0;
+ els->io.iparam.ct.timeout = EFC_FC_ELS_SEND_DEFAULT_TIMEOUT;
+
+ els->display_name = "rffid";
+ ct = els->io.req.virt;
+
+ memset(ct, 0, sizeof(*ct));
+ fcct_build_req_header(&ct->hdr, FC_NS_RFF_ID,
+ sizeof(struct fc_ns_rff_id));
+
+ hton24(ct->rffid.fr_fid.fp_fid, node->rnode.nport->fc_id);
+ if (node->nport->enable_ini)
+ ct->rffid.fr_feat |= FCP_FEAT_INIT;
+ if (node->nport->enable_tgt)
+ ct->rffid.fr_feat |= FCP_FEAT_TARG;
+ ct->rffid.fr_type = FC_TYPE_FCP;
+
+ return efc_els_send_req(node, els, EFC_DISC_IO_CT_REQ);
+}
+
+int
+efc_ns_send_gidpt(struct efc_node *node)
+{
+ struct efc_els_io_req *els = NULL;
+ struct efc *efc = node->efc;
+ struct {
+ struct fc_ct_hdr hdr;
+ struct fc_ns_gid_pt gidpt;
+ } *ct;
+
+ node_els_trace();
+
+ els = efc_els_io_alloc_size(node, sizeof(*ct), EFC_ELS_GID_PT_RSP_LEN);
+ if (!els) {
+ efc_log_err(efc, "IO alloc failed\n");
+ return -EIO;
+ }
+
+ els->io.iparam.ct.r_ctl = FC_RCTL_ELS_REQ;
+ els->io.iparam.ct.type = FC_TYPE_CT;
+ els->io.iparam.ct.df_ctl = 0;
+ els->io.iparam.ct.timeout = EFC_FC_ELS_SEND_DEFAULT_TIMEOUT;
+
+ els->display_name = "gidpt";
+
+ ct = els->io.req.virt;
+
+ memset(ct, 0, sizeof(*ct));
+ fcct_build_req_header(&ct->hdr, FC_NS_GID_PT,
+ sizeof(struct fc_ns_gid_pt));
+
+ ct->gidpt.fn_pt_type = FC_TYPE_FCP;
+
+ return efc_els_send_req(node, els, EFC_DISC_IO_CT_REQ);
+}
+
+void
+efc_els_io_cleanup(struct efc_els_io_req *els, int evt, void *arg)
+{
+ /* don't want further events that could come; e.g. abort requests
+ * from the node state machine; thus, disable state machine
+ */
+ els->els_req_free = true;
+ efc_node_post_els_resp(els->node, evt, arg);
+
+ efc_els_io_free(els);
+}
+
+static int
+efc_ct_acc_cb(void *arg, u32 length, int status, u32 ext_status)
+{
+ struct efc_els_io_req *els = arg;
+
+ efc_els_io_free(els);
+
+ return 0;
+}
+
+int
+efc_send_ct_rsp(struct efc *efc, struct efc_node *node, u16 ox_id,
+ struct fc_ct_hdr *ct_hdr, u32 cmd_rsp_code,
+ u32 reason_code, u32 reason_code_explanation)
+{
+ struct efc_els_io_req *els = NULL;
+ struct fc_ct_hdr *rsp = NULL;
+
+ els = efc_els_io_alloc(node, 256);
+ if (!els) {
+ efc_log_err(efc, "IO alloc failed\n");
+ return -EIO;
+ }
+
+ rsp = els->io.rsp.virt;
+
+ *rsp = *ct_hdr;
+
+ fcct_build_req_header(rsp, cmd_rsp_code, 0);
+ rsp->ct_reason = reason_code;
+ rsp->ct_explan = reason_code_explanation;
+
+ els->display_name = "ct_rsp";
+ els->cb = efc_ct_acc_cb;
+
+ /* Prepare the IO request details */
+ els->io.io_type = EFC_DISC_IO_CT_RESP;
+ els->io.xmit_len = sizeof(*rsp);
+
+ els->io.rpi = node->rnode.indicator;
+ els->io.d_id = node->rnode.fc_id;
+
+ memset(&els->io.iparam, 0, sizeof(els->io.iparam));
+
+ els->io.iparam.ct.ox_id = ox_id;
+ els->io.iparam.ct.r_ctl = 3;
+ els->io.iparam.ct.type = FC_TYPE_CT;
+ els->io.iparam.ct.df_ctl = 0;
+ els->io.iparam.ct.timeout = 5;
+
+ if (efc->tt.send_els(efc, &els->io)) {
+ efc_els_io_free(els);
+ return -EIO;
+ }
+ return 0;
+}
+
+int
+efc_send_bls_acc(struct efc_node *node, struct fc_frame_header *hdr)
+{
+ struct sli_bls_params bls;
+ struct fc_ba_acc *acc;
+ struct efc *efc = node->efc;
+
+ memset(&bls, 0, sizeof(bls));
+ bls.ox_id = be16_to_cpu(hdr->fh_ox_id);
+ bls.rx_id = be16_to_cpu(hdr->fh_rx_id);
+ bls.s_id = ntoh24(hdr->fh_d_id);
+ bls.d_id = node->rnode.fc_id;
+ bls.rpi = node->rnode.indicator;
+ bls.vpi = node->nport->indicator;
+
+ acc = (void *)bls.payload;
+ acc->ba_ox_id = cpu_to_be16(bls.ox_id);
+ acc->ba_rx_id = cpu_to_be16(bls.rx_id);
+ acc->ba_high_seq_cnt = cpu_to_be16(U16_MAX);
+
+ return efc->tt.send_bls(efc, FC_RCTL_BA_ACC, &bls);
+}
diff --git a/drivers/scsi/elx/libefc/efc_els.h b/drivers/scsi/elx/libefc/efc_els.h
new file mode 100644
index 000000000000..3c4f820f602e
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_els.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#ifndef __EFC_ELS_H__
+#define __EFC_ELS_H__
+
+#define EFC_STATUS_INVALID INT_MAX
+#define EFC_ELS_IO_POOL_SZ 1024
+
+struct efc_els_io_req {
+ struct list_head list_entry;
+ struct kref ref;
+ void (*release)(struct kref *arg);
+ struct efc_node *node;
+ void *cb;
+ u32 els_retries_remaining;
+ bool els_req_free;
+ struct timer_list delay_timer;
+
+ const char *display_name;
+
+ struct efc_disc_io io;
+};
+
+typedef int(*efc_hw_srrs_cb_t)(void *arg, u32 length, int status,
+ u32 ext_status);
+
+void _efc_els_io_free(struct kref *arg);
+struct efc_els_io_req *
+efc_els_io_alloc(struct efc_node *node, u32 reqlen);
+struct efc_els_io_req *
+efc_els_io_alloc_size(struct efc_node *node, u32 reqlen, u32 rsplen);
+void efc_els_io_free(struct efc_els_io_req *els);
+
+/* ELS command send */
+typedef void (*els_cb_t)(struct efc_node *node,
+ struct efc_node_cb *cbdata, void *arg);
+int
+efc_send_plogi(struct efc_node *node);
+int
+efc_send_flogi(struct efc_node *node);
+int
+efc_send_fdisc(struct efc_node *node);
+int
+efc_send_prli(struct efc_node *node);
+int
+efc_send_prlo(struct efc_node *node);
+int
+efc_send_logo(struct efc_node *node);
+int
+efc_send_adisc(struct efc_node *node);
+int
+efc_send_pdisc(struct efc_node *node);
+int
+efc_send_scr(struct efc_node *node);
+int
+efc_ns_send_rftid(struct efc_node *node);
+int
+efc_ns_send_rffid(struct efc_node *node);
+int
+efc_ns_send_gidpt(struct efc_node *node);
+void
+efc_els_io_cleanup(struct efc_els_io_req *els, int evt, void *arg);
+
+/* ELS acc send */
+int
+efc_send_ls_acc(struct efc_node *node, u32 ox_id);
+int
+efc_send_ls_rjt(struct efc_node *node, u32 ox_id, u32 reason_cod,
+ u32 reason_code_expl, u32 vendor_unique);
+int
+efc_send_flogi_p2p_acc(struct efc_node *node, u32 ox_id, u32 s_id);
+int
+efc_send_flogi_acc(struct efc_node *node, u32 ox_id, u32 is_fport);
+int
+efc_send_plogi_acc(struct efc_node *node, u32 ox_id);
+int
+efc_send_prli_acc(struct efc_node *node, u32 ox_id);
+int
+efc_send_logo_acc(struct efc_node *node, u32 ox_id);
+int
+efc_send_prlo_acc(struct efc_node *node, u32 ox_id);
+int
+efc_send_adisc_acc(struct efc_node *node, u32 ox_id);
+
+int
+efc_bls_send_acc_hdr(struct efc *efc, struct efc_node *node,
+ struct fc_frame_header *hdr);
+int
+efc_bls_send_rjt_hdr(struct efc_els_io_req *io, struct fc_frame_header *hdr);
+
+int
+efc_els_io_list_empty(struct efc_node *node, struct list_head *list);
+
+/* CT */
+int
+efc_send_ct_rsp(struct efc *efc, struct efc_node *node, u16 ox_id,
+ struct fc_ct_hdr *ct_hdr, u32 cmd_rsp_code, u32 reason_code,
+ u32 reason_code_explanation);
+
+int
+efc_send_bls_acc(struct efc_node *node, struct fc_frame_header *hdr);
+
+#endif /* __EFC_ELS_H__ */
diff --git a/drivers/scsi/elx/libefc/efc_fabric.c b/drivers/scsi/elx/libefc/efc_fabric.c
new file mode 100644
index 000000000000..d397220d9e54
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_fabric.c
@@ -0,0 +1,1564 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+/*
+ * This file implements remote node state machines for:
+ * - Fabric logins.
+ * - Fabric controller events.
+ * - Name/directory services interaction.
+ * - Point-to-point logins.
+ */
+
+/*
+ * fabric_sm Node State Machine: Fabric States
+ * ns_sm Node State Machine: Name/Directory Services States
+ * p2p_sm Node State Machine: Point-to-Point Node States
+ */
+
+#include "efc.h"
+
+static void
+efc_fabric_initiate_shutdown(struct efc_node *node)
+{
+ struct efc *efc = node->efc;
+
+ node->els_io_enabled = false;
+
+ if (node->attached) {
+ int rc;
+
+ /* issue hw node free; don't care if succeeds right away
+ * or sometime later, will check node->attached later in
+ * shutdown process
+ */
+ rc = efc_cmd_node_detach(efc, &node->rnode);
+ if (rc < 0) {
+ node_printf(node, "Failed freeing HW node, rc=%d\n",
+ rc);
+ }
+ }
+ /*
+ * node has either been detached or is in the process of being detached,
+ * call common node's initiate cleanup function
+ */
+ efc_node_initiate_cleanup(node);
+}
+
+static void
+__efc_fabric_common(const char *funcname, struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = NULL;
+
+ node = ctx->app;
+
+ switch (evt) {
+ case EFC_EVT_DOMAIN_ATTACH_OK:
+ break;
+ case EFC_EVT_SHUTDOWN:
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_fabric_initiate_shutdown(node);
+ break;
+
+ default:
+ /* call default event handler common to all nodes */
+ __efc_node_common(funcname, ctx, evt, arg);
+ }
+}
+
+void
+__efc_fabric_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
+ void *arg)
+{
+ struct efc_node *node = ctx->app;
+ struct efc *efc = node->efc;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_REENTER:
+ efc_log_debug(efc, ">>> reenter !!\n");
+ fallthrough;
+
+ case EFC_EVT_ENTER:
+ /* send FLOGI */
+ efc_send_flogi(node);
+ efc_node_transition(node, __efc_fabric_flogi_wait_rsp, NULL);
+ break;
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+efc_fabric_set_topology(struct efc_node *node,
+ enum efc_nport_topology topology)
+{
+ node->nport->topology = topology;
+}
+
+void
+efc_fabric_notify_topology(struct efc_node *node)
+{
+ struct efc_node *tmp_node;
+ enum efc_nport_topology topology = node->nport->topology;
+ unsigned long index;
+
+ /*
+ * now loop through the nodes in the nport
+ * and send topology notification
+ */
+ xa_for_each(&node->nport->lookup, index, tmp_node) {
+ if (tmp_node != node) {
+ efc_node_post_event(tmp_node,
+ EFC_EVT_NPORT_TOPOLOGY_NOTIFY,
+ (void *)topology);
+ }
+ }
+}
+
+static bool efc_rnode_is_nport(struct fc_els_flogi *rsp)
+{
+ return !(ntohs(rsp->fl_csp.sp_features) & FC_SP_FT_FPORT);
+}
+
+void
+__efc_fabric_flogi_wait_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_SRRS_ELS_REQ_OK: {
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_FLOGI,
+ __efc_fabric_common, __func__)) {
+ return;
+ }
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+
+ memcpy(node->nport->domain->flogi_service_params,
+ cbdata->els_rsp.virt,
+ sizeof(struct fc_els_flogi));
+
+ /* Check to see if the fabric is an F_PORT or and N_PORT */
+ if (!efc_rnode_is_nport(cbdata->els_rsp.virt)) {
+ /* sm: if not nport / efc_domain_attach */
+ /* ext_status has the fc_id, attach domain */
+ efc_fabric_set_topology(node, EFC_NPORT_TOPO_FABRIC);
+ efc_fabric_notify_topology(node);
+ WARN_ON(node->nport->domain->attached);
+ efc_domain_attach(node->nport->domain,
+ cbdata->ext_status);
+ efc_node_transition(node,
+ __efc_fabric_wait_domain_attach,
+ NULL);
+ break;
+ }
+
+ /* sm: if nport and p2p_winner / efc_domain_attach */
+ efc_fabric_set_topology(node, EFC_NPORT_TOPO_P2P);
+ if (efc_p2p_setup(node->nport)) {
+ node_printf(node,
+ "p2p setup failed, shutting down node\n");
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_fabric_initiate_shutdown(node);
+ break;
+ }
+
+ if (node->nport->p2p_winner) {
+ efc_node_transition(node,
+ __efc_p2p_wait_domain_attach,
+ NULL);
+ if (node->nport->domain->attached &&
+ !node->nport->domain->domain_notify_pend) {
+ /*
+ * already attached,
+ * just send ATTACH_OK
+ */
+ node_printf(node,
+ "p2p winner, domain already attached\n");
+ efc_node_post_event(node,
+ EFC_EVT_DOMAIN_ATTACH_OK,
+ NULL);
+ }
+ } else {
+ /*
+ * peer is p2p winner;
+ * PLOGI will be received on the
+ * remote SID=1 node;
+ * this node has served its purpose
+ */
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_fabric_initiate_shutdown(node);
+ }
+
+ break;
+ }
+
+ case EFC_EVT_ELS_REQ_ABORTED:
+ case EFC_EVT_SRRS_ELS_REQ_RJT:
+ case EFC_EVT_SRRS_ELS_REQ_FAIL: {
+ struct efc_nport *nport = node->nport;
+ /*
+ * with these errors, we have no recovery,
+ * so shutdown the nport, leave the link
+ * up and the domain ready
+ */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_FLOGI,
+ __efc_fabric_common, __func__)) {
+ return;
+ }
+ node_printf(node,
+ "FLOGI failed evt=%s, shutting down nport [%s]\n",
+ efc_sm_event_name(evt), nport->display_name);
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ efc_sm_post_event(&nport->sm, EFC_EVT_SHUTDOWN, NULL);
+ break;
+ }
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_vport_fabric_init(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ /* sm: / send FDISC */
+ efc_send_fdisc(node);
+ efc_node_transition(node, __efc_fabric_fdisc_wait_rsp, NULL);
+ break;
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_fabric_fdisc_wait_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_SRRS_ELS_REQ_OK: {
+ /* fc_id is in ext_status */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_FDISC,
+ __efc_fabric_common, __func__)) {
+ return;
+ }
+
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ /* sm: / efc_nport_attach */
+ efc_nport_attach(node->nport, cbdata->ext_status);
+ efc_node_transition(node, __efc_fabric_wait_domain_attach,
+ NULL);
+ break;
+ }
+
+ case EFC_EVT_SRRS_ELS_REQ_RJT:
+ case EFC_EVT_SRRS_ELS_REQ_FAIL: {
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_FDISC,
+ __efc_fabric_common, __func__)) {
+ return;
+ }
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ efc_log_err(node->efc, "FDISC failed, shutting down nport\n");
+ /* sm: / shutdown nport */
+ efc_sm_post_event(&node->nport->sm, EFC_EVT_SHUTDOWN, NULL);
+ break;
+ }
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+static int
+efc_start_ns_node(struct efc_nport *nport)
+{
+ struct efc_node *ns;
+
+ /* Instantiate a name services node */
+ ns = efc_node_find(nport, FC_FID_DIR_SERV);
+ if (!ns) {
+ ns = efc_node_alloc(nport, FC_FID_DIR_SERV, false, false);
+ if (!ns)
+ return -EIO;
+ }
+ /*
+ * for found ns, should we be transitioning from here?
+ * breaks transition only
+ * 1. from within state machine or
+ * 2. if after alloc
+ */
+ if (ns->efc->nodedb_mask & EFC_NODEDB_PAUSE_NAMESERVER)
+ efc_node_pause(ns, __efc_ns_init);
+ else
+ efc_node_transition(ns, __efc_ns_init, NULL);
+ return 0;
+}
+
+static int
+efc_start_fabctl_node(struct efc_nport *nport)
+{
+ struct efc_node *fabctl;
+
+ fabctl = efc_node_find(nport, FC_FID_FCTRL);
+ if (!fabctl) {
+ fabctl = efc_node_alloc(nport, FC_FID_FCTRL,
+ false, false);
+ if (!fabctl)
+ return -EIO;
+ }
+ /*
+ * for found ns, should we be transitioning from here?
+ * breaks transition only
+ * 1. from within state machine or
+ * 2. if after alloc
+ */
+ efc_node_transition(fabctl, __efc_fabctl_init, NULL);
+ return 0;
+}
+
+void
+__efc_fabric_wait_domain_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+ case EFC_EVT_DOMAIN_ATTACH_OK:
+ case EFC_EVT_NPORT_ATTACH_OK: {
+ int rc;
+
+ rc = efc_start_ns_node(node->nport);
+ if (rc)
+ return;
+
+ /* sm: if enable_ini / start fabctl node */
+ /* Instantiate the fabric controller (sends SCR) */
+ if (node->nport->enable_rscn) {
+ rc = efc_start_fabctl_node(node->nport);
+ if (rc)
+ return;
+ }
+ efc_node_transition(node, __efc_fabric_idle, NULL);
+ break;
+ }
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_fabric_idle(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
+ void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_DOMAIN_ATTACH_OK:
+ break;
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_ns_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ /* sm: / send PLOGI */
+ efc_send_plogi(node);
+ efc_node_transition(node, __efc_ns_plogi_wait_rsp, NULL);
+ break;
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_ns_plogi_wait_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_SRRS_ELS_REQ_OK: {
+ int rc;
+
+ /* Save service parameters */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
+ __efc_fabric_common, __func__)) {
+ return;
+ }
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ /* sm: / save sparams, efc_node_attach */
+ efc_node_save_sparms(node, cbdata->els_rsp.virt);
+ rc = efc_node_attach(node);
+ efc_node_transition(node, __efc_ns_wait_node_attach, NULL);
+ if (rc < 0)
+ efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,
+ NULL);
+ break;
+ }
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_ns_wait_node_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_NODE_ATTACH_OK:
+ node->attached = true;
+ /* sm: / send RFTID */
+ efc_ns_send_rftid(node);
+ efc_node_transition(node, __efc_ns_rftid_wait_rsp, NULL);
+ break;
+
+ case EFC_EVT_NODE_ATTACH_FAIL:
+ /* node attach failed, shutdown the node */
+ node->attached = false;
+ node_printf(node, "Node attach failed\n");
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_fabric_initiate_shutdown(node);
+ break;
+
+ case EFC_EVT_SHUTDOWN:
+ node_printf(node, "Shutdown event received\n");
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_node_transition(node,
+ __efc_fabric_wait_attach_evt_shutdown,
+ NULL);
+ break;
+
+ /*
+ * if receive RSCN just ignore,
+ * we haven't sent GID_PT yet (ACC sent by fabctl node)
+ */
+ case EFC_EVT_RSCN_RCVD:
+ break;
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_fabric_wait_attach_evt_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ /* wait for any of these attach events and then shutdown */
+ case EFC_EVT_NODE_ATTACH_OK:
+ node->attached = true;
+ node_printf(node, "Attach evt=%s, proceed to shutdown\n",
+ efc_sm_event_name(evt));
+ efc_fabric_initiate_shutdown(node);
+ break;
+
+ case EFC_EVT_NODE_ATTACH_FAIL:
+ node->attached = false;
+ node_printf(node, "Attach evt=%s, proceed to shutdown\n",
+ efc_sm_event_name(evt));
+ efc_fabric_initiate_shutdown(node);
+ break;
+
+ /* ignore shutdown event as we're already in shutdown path */
+ case EFC_EVT_SHUTDOWN:
+ node_printf(node, "Shutdown event received\n");
+ break;
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_ns_rftid_wait_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_SRRS_ELS_REQ_OK:
+ if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_RFT_ID,
+ __efc_fabric_common, __func__)) {
+ return;
+ }
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ /* sm: / send RFFID */
+ efc_ns_send_rffid(node);
+ efc_node_transition(node, __efc_ns_rffid_wait_rsp, NULL);
+ break;
+
+ /*
+ * if receive RSCN just ignore,
+ * we haven't sent GID_PT yet (ACC sent by fabctl node)
+ */
+ case EFC_EVT_RSCN_RCVD:
+ break;
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_ns_rffid_wait_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ /*
+ * Waits for an RFFID response event;
+ * if rscn enabled, a GIDPT name services request is issued.
+ */
+ switch (evt) {
+ case EFC_EVT_SRRS_ELS_REQ_OK: {
+ if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_RFF_ID,
+ __efc_fabric_common, __func__)) {
+ return;
+ }
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ if (node->nport->enable_rscn) {
+ /* sm: if enable_rscn / send GIDPT */
+ efc_ns_send_gidpt(node);
+
+ efc_node_transition(node, __efc_ns_gidpt_wait_rsp,
+ NULL);
+ } else {
+ /* if 'T' only, we're done, go to idle */
+ efc_node_transition(node, __efc_ns_idle, NULL);
+ }
+ break;
+ }
+ /*
+ * if receive RSCN just ignore,
+ * we haven't sent GID_PT yet (ACC sent by fabctl node)
+ */
+ case EFC_EVT_RSCN_RCVD:
+ break;
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+static int
+efc_process_gidpt_payload(struct efc_node *node,
+ void *data, u32 gidpt_len)
+{
+ u32 i, j;
+ struct efc_node *newnode;
+ struct efc_nport *nport = node->nport;
+ struct efc *efc = node->efc;
+ u32 port_id = 0, port_count, plist_count;
+ struct efc_node *n;
+ struct efc_node **active_nodes;
+ int residual;
+ struct {
+ struct fc_ct_hdr hdr;
+ struct fc_gid_pn_resp pn_rsp;
+ } *rsp;
+ struct fc_gid_pn_resp *gidpt;
+ unsigned long index;
+
+ rsp = data;
+ gidpt = &rsp->pn_rsp;
+ residual = be16_to_cpu(rsp->hdr.ct_mr_size);
+
+ if (residual != 0)
+ efc_log_debug(node->efc, "residual is %u words\n", residual);
+
+ if (be16_to_cpu(rsp->hdr.ct_cmd) == FC_FS_RJT) {
+ node_printf(node,
+ "GIDPT request failed: rsn x%x rsn_expl x%x\n",
+ rsp->hdr.ct_reason, rsp->hdr.ct_explan);
+ return -EIO;
+ }
+
+ plist_count = (gidpt_len - sizeof(struct fc_ct_hdr)) / sizeof(*gidpt);
+
+ /* Count the number of nodes */
+ port_count = 0;
+ xa_for_each(&nport->lookup, index, n) {
+ port_count++;
+ }
+
+ /* Allocate a buffer for all nodes */
+ active_nodes = kzalloc(port_count * sizeof(*active_nodes), GFP_ATOMIC);
+ if (!active_nodes) {
+ node_printf(node, "efc_malloc failed\n");
+ return -EIO;
+ }
+
+ /* Fill buffer with fc_id of active nodes */
+ i = 0;
+ xa_for_each(&nport->lookup, index, n) {
+ port_id = n->rnode.fc_id;
+ switch (port_id) {
+ case FC_FID_FLOGI:
+ case FC_FID_FCTRL:
+ case FC_FID_DIR_SERV:
+ break;
+ default:
+ if (port_id != FC_FID_DOM_MGR)
+ active_nodes[i++] = n;
+ break;
+ }
+ }
+
+ /* update the active nodes buffer */
+ for (i = 0; i < plist_count; i++) {
+ hton24(gidpt[i].fp_fid, port_id);
+
+ for (j = 0; j < port_count; j++) {
+ if (active_nodes[j] &&
+ port_id == active_nodes[j]->rnode.fc_id) {
+ active_nodes[j] = NULL;
+ }
+ }
+
+ if (gidpt[i].fp_resvd & FC_NS_FID_LAST)
+ break;
+ }
+
+ /* Those remaining in the active_nodes[] are now gone ! */
+ for (i = 0; i < port_count; i++) {
+ /*
+ * if we're an initiator and the remote node
+ * is a target, then post the node missing event.
+ * if we're target and we have enabled
+ * target RSCN, then post the node missing event.
+ */
+ if (!active_nodes[i])
+ continue;
+
+ if ((node->nport->enable_ini && active_nodes[i]->targ) ||
+ (node->nport->enable_tgt && enable_target_rscn(efc))) {
+ efc_node_post_event(active_nodes[i],
+ EFC_EVT_NODE_MISSING, NULL);
+ } else {
+ node_printf(node,
+ "GID_PT: skipping non-tgt port_id x%06x\n",
+ active_nodes[i]->rnode.fc_id);
+ }
+ }
+ kfree(active_nodes);
+
+ for (i = 0; i < plist_count; i++) {
+ hton24(gidpt[i].fp_fid, port_id);
+
+ /* Don't create node for ourselves */
+ if (port_id == node->rnode.nport->fc_id) {
+ if (gidpt[i].fp_resvd & FC_NS_FID_LAST)
+ break;
+ continue;
+ }
+
+ newnode = efc_node_find(nport, port_id);
+ if (!newnode) {
+ if (!node->nport->enable_ini)
+ continue;
+
+ newnode = efc_node_alloc(nport, port_id, false, false);
+ if (!newnode) {
+ efc_log_err(efc, "efc_node_alloc() failed\n");
+ return -EIO;
+ }
+ /*
+ * send PLOGI automatically
+ * if initiator
+ */
+ efc_node_init_device(newnode, true);
+ }
+
+ if (node->nport->enable_ini && newnode->targ) {
+ efc_node_post_event(newnode, EFC_EVT_NODE_REFOUND,
+ NULL);
+ }
+
+ if (gidpt[i].fp_resvd & FC_NS_FID_LAST)
+ break;
+ }
+ return 0;
+}
+
+void
+__efc_ns_gidpt_wait_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+ /*
+ * Wait for a GIDPT response from the name server. Process the FC_IDs
+ * that are reported by creating new remote ports, as needed.
+ */
+
+ switch (evt) {
+ case EFC_EVT_SRRS_ELS_REQ_OK: {
+ if (efc_node_check_ns_req(ctx, evt, arg, FC_NS_GID_PT,
+ __efc_fabric_common, __func__)) {
+ return;
+ }
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ /* sm: / process GIDPT payload */
+ efc_process_gidpt_payload(node, cbdata->els_rsp.virt,
+ cbdata->els_rsp.len);
+ efc_node_transition(node, __efc_ns_idle, NULL);
+ break;
+ }
+
+ case EFC_EVT_SRRS_ELS_REQ_FAIL: {
+ /* not much we can do; will retry with the next RSCN */
+ node_printf(node, "GID_PT failed to complete\n");
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ efc_node_transition(node, __efc_ns_idle, NULL);
+ break;
+ }
+
+ /* if receive RSCN here, queue up another discovery processing */
+ case EFC_EVT_RSCN_RCVD: {
+ node_printf(node, "RSCN received during GID_PT processing\n");
+ node->rscn_pending = true;
+ break;
+ }
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_ns_idle(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+ struct efc *efc = node->efc;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ /*
+ * Wait for RSCN received events (posted from the fabric controller)
+ * and restart the GIDPT name services query and processing.
+ */
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ if (!node->rscn_pending)
+ break;
+
+ node_printf(node, "RSCN pending, restart discovery\n");
+ node->rscn_pending = false;
+ fallthrough;
+
+ case EFC_EVT_RSCN_RCVD: {
+ /* sm: / send GIDPT */
+ /*
+ * If target RSCN processing is enabled,
+ * and this is target only (not initiator),
+ * and tgt_rscn_delay is non-zero,
+ * then we delay issuing the GID_PT
+ */
+ if (efc->tgt_rscn_delay_msec != 0 &&
+ !node->nport->enable_ini && node->nport->enable_tgt &&
+ enable_target_rscn(efc)) {
+ efc_node_transition(node, __efc_ns_gidpt_delay, NULL);
+ } else {
+ efc_ns_send_gidpt(node);
+ efc_node_transition(node, __efc_ns_gidpt_wait_rsp,
+ NULL);
+ }
+ break;
+ }
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+static void
+gidpt_delay_timer_cb(struct timer_list *t)
+{
+ struct efc_node *node = from_timer(node, t, gidpt_delay_timer);
+
+ del_timer(&node->gidpt_delay_timer);
+
+ efc_node_post_event(node, EFC_EVT_GIDPT_DELAY_EXPIRED, NULL);
+}
+
+void
+__efc_ns_gidpt_delay(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+ struct efc *efc = node->efc;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER: {
+ u64 delay_msec, tmp;
+
+ /*
+ * Compute the delay time.
+ * Set to tgt_rscn_delay, if the time since last GIDPT
+ * is less than tgt_rscn_period, then use tgt_rscn_period.
+ */
+ delay_msec = efc->tgt_rscn_delay_msec;
+ tmp = jiffies_to_msecs(jiffies) - node->time_last_gidpt_msec;
+ if (tmp < efc->tgt_rscn_period_msec)
+ delay_msec = efc->tgt_rscn_period_msec;
+
+ timer_setup(&node->gidpt_delay_timer, &gidpt_delay_timer_cb,
+ 0);
+ mod_timer(&node->gidpt_delay_timer,
+ jiffies + msecs_to_jiffies(delay_msec));
+
+ break;
+ }
+
+ case EFC_EVT_GIDPT_DELAY_EXPIRED:
+ node->time_last_gidpt_msec = jiffies_to_msecs(jiffies);
+
+ efc_ns_send_gidpt(node);
+ efc_node_transition(node, __efc_ns_gidpt_wait_rsp, NULL);
+ break;
+
+ case EFC_EVT_RSCN_RCVD: {
+ efc_log_debug(efc,
+ "RSCN received while in GIDPT delay - no action\n");
+ break;
+ }
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_fabctl_init(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ /* no need to login to fabric controller, just send SCR */
+ efc_send_scr(node);
+ efc_node_transition(node, __efc_fabctl_wait_scr_rsp, NULL);
+ break;
+
+ case EFC_EVT_NODE_ATTACH_OK:
+ node->attached = true;
+ break;
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_fabctl_wait_scr_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ /*
+ * Fabric controller node state machine:
+ * Wait for an SCR response from the fabric controller.
+ */
+ switch (evt) {
+ case EFC_EVT_SRRS_ELS_REQ_OK:
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_SCR,
+ __efc_fabric_common, __func__)) {
+ return;
+ }
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ efc_node_transition(node, __efc_fabctl_ready, NULL);
+ break;
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+static void
+efc_process_rscn(struct efc_node *node, struct efc_node_cb *cbdata)
+{
+ struct efc *efc = node->efc;
+ struct efc_nport *nport = node->nport;
+ struct efc_node *ns;
+
+ /* Forward this event to the name-services node */
+ ns = efc_node_find(nport, FC_FID_DIR_SERV);
+ if (ns)
+ efc_node_post_event(ns, EFC_EVT_RSCN_RCVD, cbdata);
+ else
+ efc_log_warn(efc, "can't find name server node\n");
+}
+
+void
+__efc_fabctl_ready(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ /*
+ * Fabric controller node state machine: Ready.
+ * In this state, the fabric controller sends a RSCN, which is received
+ * by this node and is forwarded to the name services node object; and
+ * the RSCN LS_ACC is sent.
+ */
+ switch (evt) {
+ case EFC_EVT_RSCN_RCVD: {
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+
+ /*
+ * sm: / process RSCN (forward to name services node),
+ * send LS_ACC
+ */
+ efc_process_rscn(node, cbdata);
+ efc_send_ls_acc(node, be16_to_cpu(hdr->fh_ox_id));
+ efc_node_transition(node, __efc_fabctl_wait_ls_acc_cmpl,
+ NULL);
+ break;
+ }
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_fabctl_wait_ls_acc_cmpl(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_SRRS_ELS_CMPL_OK:
+ WARN_ON(!node->els_cmpl_cnt);
+ node->els_cmpl_cnt--;
+ efc_node_transition(node, __efc_fabctl_ready, NULL);
+ break;
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+static uint64_t
+efc_get_wwpn(struct fc_els_flogi *sp)
+{
+ return be64_to_cpu(sp->fl_wwnn);
+}
+
+static int
+efc_rnode_is_winner(struct efc_nport *nport)
+{
+ struct fc_els_flogi *remote_sp;
+ u64 remote_wwpn;
+ u64 local_wwpn = nport->wwpn;
+ u64 wwn_bump = 0;
+
+ remote_sp = (struct fc_els_flogi *)nport->domain->flogi_service_params;
+ remote_wwpn = efc_get_wwpn(remote_sp);
+
+ local_wwpn ^= wwn_bump;
+
+ efc_log_debug(nport->efc, "r: %llx\n",
+ be64_to_cpu(remote_sp->fl_wwpn));
+ efc_log_debug(nport->efc, "l: %llx\n", local_wwpn);
+
+ if (remote_wwpn == local_wwpn) {
+ efc_log_warn(nport->efc,
+ "WWPN of remote node [%08x %08x] matches local WWPN\n",
+ (u32)(local_wwpn >> 32ll),
+ (u32)local_wwpn);
+ return -1;
+ }
+
+ return (remote_wwpn > local_wwpn);
+}
+
+void
+__efc_p2p_wait_domain_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+ struct efc *efc = node->efc;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_DOMAIN_ATTACH_OK: {
+ struct efc_nport *nport = node->nport;
+ struct efc_node *rnode;
+
+ /*
+ * this transient node (SID=0 (recv'd FLOGI)
+ * or DID=fabric (sent FLOGI))
+ * is the p2p winner, will use a separate node
+ * to send PLOGI to peer
+ */
+ WARN_ON(!node->nport->p2p_winner);
+
+ rnode = efc_node_find(nport, node->nport->p2p_remote_port_id);
+ if (rnode) {
+ /*
+ * the "other" transient p2p node has
+ * already kicked off the
+ * new node from which PLOGI is sent
+ */
+ node_printf(node,
+ "Node with fc_id x%x already exists\n",
+ rnode->rnode.fc_id);
+ } else {
+ /*
+ * create new node (SID=1, DID=2)
+ * from which to send PLOGI
+ */
+ rnode = efc_node_alloc(nport,
+ nport->p2p_remote_port_id,
+ false, false);
+ if (!rnode) {
+ efc_log_err(efc, "node alloc failed\n");
+ return;
+ }
+
+ efc_fabric_notify_topology(node);
+ /* sm: / allocate p2p remote node */
+ efc_node_transition(rnode, __efc_p2p_rnode_init,
+ NULL);
+ }
+
+ /*
+ * the transient node (SID=0 or DID=fabric)
+ * has served its purpose
+ */
+ if (node->rnode.fc_id == 0) {
+ /*
+ * if this is the SID=0 node,
+ * move to the init state in case peer
+ * has restarted FLOGI discovery and FLOGI is pending
+ */
+ /* don't send PLOGI on efc_d_init entry */
+ efc_node_init_device(node, false);
+ } else {
+ /*
+ * if this is the DID=fabric node
+ * (we initiated FLOGI), shut it down
+ */
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_fabric_initiate_shutdown(node);
+ }
+ break;
+ }
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_p2p_rnode_init(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ /* sm: / send PLOGI */
+ efc_send_plogi(node);
+ efc_node_transition(node, __efc_p2p_wait_plogi_rsp, NULL);
+ break;
+
+ case EFC_EVT_ABTS_RCVD:
+ /* sm: send BA_ACC */
+ efc_send_bls_acc(node, cbdata->header->dma.virt);
+
+ break;
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_p2p_wait_flogi_acc_cmpl(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_SRRS_ELS_CMPL_OK:
+ WARN_ON(!node->els_cmpl_cnt);
+ node->els_cmpl_cnt--;
+
+ /* sm: if p2p_winner / domain_attach */
+ if (node->nport->p2p_winner) {
+ efc_node_transition(node,
+ __efc_p2p_wait_domain_attach,
+ NULL);
+ if (!node->nport->domain->attached) {
+ node_printf(node, "Domain not attached\n");
+ efc_domain_attach(node->nport->domain,
+ node->nport->p2p_port_id);
+ } else {
+ node_printf(node, "Domain already attached\n");
+ efc_node_post_event(node,
+ EFC_EVT_DOMAIN_ATTACH_OK,
+ NULL);
+ }
+ } else {
+ /* this node has served its purpose;
+ * we'll expect a PLOGI on a separate
+ * node (remote SID=0x1); return this node
+ * to init state in case peer
+ * restarts discovery -- it may already
+ * have (pending frames may exist).
+ */
+ /* don't send PLOGI on efc_d_init entry */
+ efc_node_init_device(node, false);
+ }
+ break;
+
+ case EFC_EVT_SRRS_ELS_CMPL_FAIL:
+ /*
+ * LS_ACC failed, possibly due to link down;
+ * shutdown node and wait
+ * for FLOGI discovery to restart
+ */
+ node_printf(node, "FLOGI LS_ACC failed, shutting down\n");
+ WARN_ON(!node->els_cmpl_cnt);
+ node->els_cmpl_cnt--;
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_fabric_initiate_shutdown(node);
+ break;
+
+ case EFC_EVT_ABTS_RCVD: {
+ /* sm: / send BA_ACC */
+ efc_send_bls_acc(node, cbdata->header->dma.virt);
+ break;
+ }
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_p2p_wait_plogi_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_SRRS_ELS_REQ_OK: {
+ int rc;
+
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
+ __efc_fabric_common, __func__)) {
+ return;
+ }
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ /* sm: / save sparams, efc_node_attach */
+ efc_node_save_sparms(node, cbdata->els_rsp.virt);
+ rc = efc_node_attach(node);
+ efc_node_transition(node, __efc_p2p_wait_node_attach, NULL);
+ if (rc < 0)
+ efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,
+ NULL);
+ break;
+ }
+ case EFC_EVT_SRRS_ELS_REQ_FAIL: {
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
+ __efc_fabric_common, __func__)) {
+ return;
+ }
+ node_printf(node, "PLOGI failed, shutting down\n");
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_fabric_initiate_shutdown(node);
+ break;
+ }
+
+ case EFC_EVT_PLOGI_RCVD: {
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+ /* if we're in external loopback mode, just send LS_ACC */
+ if (node->efc->external_loopback) {
+ efc_send_plogi_acc(node, be16_to_cpu(hdr->fh_ox_id));
+ } else {
+ /*
+ * if this isn't external loopback,
+ * pass to default handler
+ */
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+ break;
+ }
+ case EFC_EVT_PRLI_RCVD:
+ /* I, or I+T */
+ /* sent PLOGI and before completion was seen, received the
+ * PRLI from the remote node (WCQEs and RCQEs come in on
+ * different queues and order of processing cannot be assumed)
+ * Save OXID so PRLI can be sent after the attach and continue
+ * to wait for PLOGI response
+ */
+ efc_process_prli_payload(node, cbdata->payload->dma.virt);
+ efc_send_ls_acc_after_attach(node,
+ cbdata->header->dma.virt,
+ EFC_NODE_SEND_LS_ACC_PRLI);
+ efc_node_transition(node, __efc_p2p_wait_plogi_rsp_recvd_prli,
+ NULL);
+ break;
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_p2p_wait_plogi_rsp_recvd_prli(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ /*
+ * Since we've received a PRLI, we have a port login and will
+ * just need to wait for the PLOGI response to do the node
+ * attach and then we can send the LS_ACC for the PRLI. If,
+ * during this time, we receive FCP_CMNDs (which is possible
+ * since we've already sent a PRLI and our peer may have
+ * accepted).
+ * At this time, we are not waiting on any other unsolicited
+ * frames to continue with the login process. Thus, it will not
+ * hurt to hold frames here.
+ */
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_SRRS_ELS_REQ_OK: { /* PLOGI response received */
+ int rc;
+
+ /* Completion from PLOGI sent */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
+ __efc_fabric_common, __func__)) {
+ return;
+ }
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ /* sm: / save sparams, efc_node_attach */
+ efc_node_save_sparms(node, cbdata->els_rsp.virt);
+ rc = efc_node_attach(node);
+ efc_node_transition(node, __efc_p2p_wait_node_attach, NULL);
+ if (rc < 0)
+ efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL,
+ NULL);
+ break;
+ }
+ case EFC_EVT_SRRS_ELS_REQ_FAIL: /* PLOGI response received */
+ case EFC_EVT_SRRS_ELS_REQ_RJT:
+ /* PLOGI failed, shutdown the node */
+ if (efc_node_check_els_req(ctx, evt, arg, ELS_PLOGI,
+ __efc_fabric_common, __func__)) {
+ return;
+ }
+ WARN_ON(!node->els_req_cnt);
+ node->els_req_cnt--;
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_fabric_initiate_shutdown(node);
+ break;
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_p2p_wait_node_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node_cb *cbdata = arg;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_NODE_ATTACH_OK:
+ node->attached = true;
+ switch (node->send_ls_acc) {
+ case EFC_NODE_SEND_LS_ACC_PRLI: {
+ efc_d_send_prli_rsp(node->ls_acc_io,
+ node->ls_acc_oxid);
+ node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
+ node->ls_acc_io = NULL;
+ break;
+ }
+ case EFC_NODE_SEND_LS_ACC_PLOGI: /* Can't happen in P2P */
+ case EFC_NODE_SEND_LS_ACC_NONE:
+ default:
+ /* Normal case for I */
+ /* sm: send_plogi_acc is not set / send PLOGI acc */
+ efc_node_transition(node, __efc_d_port_logged_in,
+ NULL);
+ break;
+ }
+ break;
+
+ case EFC_EVT_NODE_ATTACH_FAIL:
+ /* node attach failed, shutdown the node */
+ node->attached = false;
+ node_printf(node, "Node attach failed\n");
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_fabric_initiate_shutdown(node);
+ break;
+
+ case EFC_EVT_SHUTDOWN:
+ node_printf(node, "%s received\n", efc_sm_event_name(evt));
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ efc_node_transition(node,
+ __efc_fabric_wait_attach_evt_shutdown,
+ NULL);
+ break;
+ case EFC_EVT_PRLI_RCVD:
+ node_printf(node, "%s: PRLI received before node is attached\n",
+ efc_sm_event_name(evt));
+ efc_process_prli_payload(node, cbdata->payload->dma.virt);
+ efc_send_ls_acc_after_attach(node,
+ cbdata->header->dma.virt,
+ EFC_NODE_SEND_LS_ACC_PRLI);
+ break;
+
+ default:
+ __efc_fabric_common(__func__, ctx, evt, arg);
+ }
+}
+
+int
+efc_p2p_setup(struct efc_nport *nport)
+{
+ struct efc *efc = nport->efc;
+ int rnode_winner;
+
+ rnode_winner = efc_rnode_is_winner(nport);
+
+ /* set nport flags to indicate p2p "winner" */
+ if (rnode_winner == 1) {
+ nport->p2p_remote_port_id = 0;
+ nport->p2p_port_id = 0;
+ nport->p2p_winner = false;
+ } else if (rnode_winner == 0) {
+ nport->p2p_remote_port_id = 2;
+ nport->p2p_port_id = 1;
+ nport->p2p_winner = true;
+ } else {
+ /* no winner; only okay if external loopback enabled */
+ if (nport->efc->external_loopback) {
+ /*
+ * External loopback mode enabled;
+ * local nport and remote node
+ * will be registered with an NPortID = 1;
+ */
+ efc_log_debug(efc,
+ "External loopback mode enabled\n");
+ nport->p2p_remote_port_id = 1;
+ nport->p2p_port_id = 1;
+ nport->p2p_winner = true;
+ } else {
+ efc_log_warn(efc,
+ "failed to determine p2p winner\n");
+ return rnode_winner;
+ }
+ }
+ return 0;
+}
diff --git a/drivers/scsi/elx/libefc/efc_fabric.h b/drivers/scsi/elx/libefc/efc_fabric.h
new file mode 100644
index 000000000000..b0947ae6fdca
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_fabric.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+/*
+ * Declarations for the interface exported by efc_fabric
+ */
+
+#ifndef __EFCT_FABRIC_H__
+#define __EFCT_FABRIC_H__
+#include "scsi/fc/fc_els.h"
+#include "scsi/fc/fc_fs.h"
+#include "scsi/fc/fc_ns.h"
+
+void
+__efc_fabric_init(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_fabric_flogi_wait_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_fabric_domain_attach_wait(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_fabric_wait_domain_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+
+void
+__efc_vport_fabric_init(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_fabric_fdisc_wait_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_fabric_wait_nport_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+
+void
+__efc_ns_init(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg);
+void
+__efc_ns_plogi_wait_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_ns_rftid_wait_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_ns_rffid_wait_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_ns_wait_node_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_fabric_wait_attach_evt_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_ns_logo_wait_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event, void *arg);
+void
+__efc_ns_gidpt_wait_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_ns_idle(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg);
+void
+__efc_ns_gidpt_delay(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_fabctl_init(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_fabctl_wait_node_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_fabctl_wait_scr_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_fabctl_ready(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_fabctl_wait_ls_acc_cmpl(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_fabric_idle(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+
+void
+__efc_p2p_rnode_init(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_p2p_domain_attach_wait(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_p2p_wait_flogi_acc_cmpl(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_p2p_wait_plogi_rsp(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_p2p_wait_plogi_rsp_recvd_prli(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_p2p_wait_domain_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_p2p_wait_node_attach(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+
+int
+efc_p2p_setup(struct efc_nport *nport);
+void
+efc_fabric_set_topology(struct efc_node *node,
+ enum efc_nport_topology topology);
+void efc_fabric_notify_topology(struct efc_node *node);
+
+#endif /* __EFCT_FABRIC_H__ */
diff --git a/drivers/scsi/elx/libefc/efc_node.c b/drivers/scsi/elx/libefc/efc_node.c
new file mode 100644
index 000000000000..a1b4ce6a27b4
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_node.c
@@ -0,0 +1,1102 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#include "efc.h"
+
+int
+efc_remote_node_cb(void *arg, int event, void *data)
+{
+ struct efc *efc = arg;
+ struct efc_remote_node *rnode = data;
+ struct efc_node *node = rnode->node;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&efc->lock, flags);
+ efc_node_post_event(node, event, NULL);
+ spin_unlock_irqrestore(&efc->lock, flags);
+
+ return 0;
+}
+
+struct efc_node *
+efc_node_find(struct efc_nport *nport, u32 port_id)
+{
+ /* Find an FC node structure given the FC port ID */
+ return xa_load(&nport->lookup, port_id);
+}
+
+static void
+_efc_node_free(struct kref *arg)
+{
+ struct efc_node *node = container_of(arg, struct efc_node, ref);
+ struct efc *efc = node->efc;
+ struct efc_dma *dma;
+
+ dma = &node->sparm_dma_buf;
+ dma_pool_free(efc->node_dma_pool, dma->virt, dma->phys);
+ memset(dma, 0, sizeof(struct efc_dma));
+ mempool_free(node, efc->node_pool);
+}
+
+struct efc_node *efc_node_alloc(struct efc_nport *nport,
+ u32 port_id, bool init, bool targ)
+{
+ int rc;
+ struct efc_node *node = NULL;
+ struct efc *efc = nport->efc;
+ struct efc_dma *dma;
+
+ if (nport->shutting_down) {
+ efc_log_debug(efc, "node allocation when shutting down %06x",
+ port_id);
+ return NULL;
+ }
+
+ node = mempool_alloc(efc->node_pool, GFP_ATOMIC);
+ if (!node) {
+ efc_log_err(efc, "node allocation failed %06x", port_id);
+ return NULL;
+ }
+ memset(node, 0, sizeof(*node));
+
+ dma = &node->sparm_dma_buf;
+ dma->size = NODE_SPARAMS_SIZE;
+ dma->virt = dma_pool_zalloc(efc->node_dma_pool, GFP_ATOMIC, &dma->phys);
+ if (!dma->virt) {
+ efc_log_err(efc, "node dma alloc failed\n");
+ goto dma_fail;
+ }
+ node->rnode.indicator = U32_MAX;
+ node->nport = nport;
+
+ node->efc = efc;
+ node->init = init;
+ node->targ = targ;
+
+ spin_lock_init(&node->pend_frames_lock);
+ INIT_LIST_HEAD(&node->pend_frames);
+ spin_lock_init(&node->els_ios_lock);
+ INIT_LIST_HEAD(&node->els_ios_list);
+ node->els_io_enabled = true;
+
+ rc = efc_cmd_node_alloc(efc, &node->rnode, port_id, nport);
+ if (rc) {
+ efc_log_err(efc, "efc_hw_node_alloc failed: %d\n", rc);
+ goto hw_alloc_fail;
+ }
+
+ node->rnode.node = node;
+ node->sm.app = node;
+ node->evtdepth = 0;
+
+ efc_node_update_display_name(node);
+
+ rc = xa_err(xa_store(&nport->lookup, port_id, node, GFP_ATOMIC));
+ if (rc) {
+ efc_log_err(efc, "Node lookup store failed: %d\n", rc);
+ goto xa_fail;
+ }
+
+ /* initialize refcount */
+ kref_init(&node->ref);
+ node->release = _efc_node_free;
+ kref_get(&nport->ref);
+
+ return node;
+
+xa_fail:
+ efc_node_free_resources(efc, &node->rnode);
+hw_alloc_fail:
+ dma_pool_free(efc->node_dma_pool, dma->virt, dma->phys);
+dma_fail:
+ mempool_free(node, efc->node_pool);
+ return NULL;
+}
+
+void
+efc_node_free(struct efc_node *node)
+{
+ struct efc_nport *nport;
+ struct efc *efc;
+ int rc = 0;
+ struct efc_node *ns = NULL;
+
+ nport = node->nport;
+ efc = node->efc;
+
+ node_printf(node, "Free'd\n");
+
+ if (node->refound) {
+ /*
+ * Save the name server node. We will send fake RSCN event at
+ * the end to handle ignored RSCN event during node deletion
+ */
+ ns = efc_node_find(node->nport, FC_FID_DIR_SERV);
+ }
+
+ if (!node->nport) {
+ efc_log_err(efc, "Node already Freed\n");
+ return;
+ }
+
+ /* Free HW resources */
+ rc = efc_node_free_resources(efc, &node->rnode);
+ if (rc < 0)
+ efc_log_err(efc, "efc_hw_node_free failed: %d\n", rc);
+
+ /* if the gidpt_delay_timer is still running, then delete it */
+ if (timer_pending(&node->gidpt_delay_timer))
+ del_timer(&node->gidpt_delay_timer);
+
+ xa_erase(&nport->lookup, node->rnode.fc_id);
+
+ /*
+ * If the node_list is empty,
+ * then post a ALL_CHILD_NODES_FREE event to the nport,
+ * after the lock is released.
+ * The nport may be free'd as a result of the event.
+ */
+ if (xa_empty(&nport->lookup))
+ efc_sm_post_event(&nport->sm, EFC_EVT_ALL_CHILD_NODES_FREE,
+ NULL);
+
+ node->nport = NULL;
+ node->sm.current_state = NULL;
+
+ kref_put(&nport->ref, nport->release);
+ kref_put(&node->ref, node->release);
+
+ if (ns) {
+ /* sending fake RSCN event to name server node */
+ efc_node_post_event(ns, EFC_EVT_RSCN_RCVD, NULL);
+ }
+}
+
+static void
+efc_dma_copy_in(struct efc_dma *dma, void *buffer, u32 buffer_length)
+{
+ if (!dma || !buffer || !buffer_length)
+ return;
+
+ if (buffer_length > dma->size)
+ buffer_length = dma->size;
+
+ memcpy(dma->virt, buffer, buffer_length);
+ dma->len = buffer_length;
+}
+
+int
+efc_node_attach(struct efc_node *node)
+{
+ int rc = 0;
+ struct efc_nport *nport = node->nport;
+ struct efc_domain *domain = nport->domain;
+ struct efc *efc = node->efc;
+
+ if (!domain->attached) {
+ efc_log_err(efc, "Warning: unattached domain\n");
+ return -EIO;
+ }
+ /* Update node->wwpn/wwnn */
+
+ efc_node_build_eui_name(node->wwpn, sizeof(node->wwpn),
+ efc_node_get_wwpn(node));
+ efc_node_build_eui_name(node->wwnn, sizeof(node->wwnn),
+ efc_node_get_wwnn(node));
+
+ efc_dma_copy_in(&node->sparm_dma_buf, node->service_params + 4,
+ sizeof(node->service_params) - 4);
+
+ /* take lock to protect node->rnode.attached */
+ rc = efc_cmd_node_attach(efc, &node->rnode, &node->sparm_dma_buf);
+ if (rc < 0)
+ efc_log_debug(efc, "efc_hw_node_attach failed: %d\n", rc);
+
+ return rc;
+}
+
+void
+efc_node_fcid_display(u32 fc_id, char *buffer, u32 buffer_length)
+{
+ switch (fc_id) {
+ case FC_FID_FLOGI:
+ snprintf(buffer, buffer_length, "fabric");
+ break;
+ case FC_FID_FCTRL:
+ snprintf(buffer, buffer_length, "fabctl");
+ break;
+ case FC_FID_DIR_SERV:
+ snprintf(buffer, buffer_length, "nserve");
+ break;
+ default:
+ if (fc_id == FC_FID_DOM_MGR) {
+ snprintf(buffer, buffer_length, "dctl%02x",
+ (fc_id & 0x0000ff));
+ } else {
+ snprintf(buffer, buffer_length, "%06x", fc_id);
+ }
+ break;
+ }
+}
+
+void
+efc_node_update_display_name(struct efc_node *node)
+{
+ u32 port_id = node->rnode.fc_id;
+ struct efc_nport *nport = node->nport;
+ char portid_display[16];
+
+ efc_node_fcid_display(port_id, portid_display, sizeof(portid_display));
+
+ snprintf(node->display_name, sizeof(node->display_name), "%s.%s",
+ nport->display_name, portid_display);
+}
+
+void
+efc_node_send_ls_io_cleanup(struct efc_node *node)
+{
+ if (node->send_ls_acc != EFC_NODE_SEND_LS_ACC_NONE) {
+ efc_log_debug(node->efc, "[%s] cleaning up LS_ACC oxid=0x%x\n",
+ node->display_name, node->ls_acc_oxid);
+
+ node->send_ls_acc = EFC_NODE_SEND_LS_ACC_NONE;
+ node->ls_acc_io = NULL;
+ }
+}
+
+static void efc_node_handle_implicit_logo(struct efc_node *node)
+{
+ int rc;
+
+ /*
+ * currently, only case for implicit logo is PLOGI
+ * recvd. Thus, node's ELS IO pending list won't be
+ * empty (PLOGI will be on it)
+ */
+ WARN_ON(node->send_ls_acc != EFC_NODE_SEND_LS_ACC_PLOGI);
+ node_printf(node, "Reason: implicit logout, re-authenticate\n");
+
+ /* Re-attach node with the same HW node resources */
+ node->req_free = false;
+ rc = efc_node_attach(node);
+ efc_node_transition(node, __efc_d_wait_node_attach, NULL);
+ node->els_io_enabled = true;
+
+ if (rc < 0)
+ efc_node_post_event(node, EFC_EVT_NODE_ATTACH_FAIL, NULL);
+}
+
+static void efc_node_handle_explicit_logo(struct efc_node *node)
+{
+ s8 pend_frames_empty;
+ unsigned long flags = 0;
+
+ /* cleanup any pending LS_ACC ELSs */
+ efc_node_send_ls_io_cleanup(node);
+
+ spin_lock_irqsave(&node->pend_frames_lock, flags);
+ pend_frames_empty = list_empty(&node->pend_frames);
+ spin_unlock_irqrestore(&node->pend_frames_lock, flags);
+
+ /*
+ * there are two scenarios where we want to keep
+ * this node alive:
+ * 1. there are pending frames that need to be
+ * processed or
+ * 2. we're an initiator and the remote node is
+ * a target and we need to re-authenticate
+ */
+ node_printf(node, "Shutdown: explicit logo pend=%d ", !pend_frames_empty);
+ node_printf(node, "nport.ini=%d node.tgt=%d\n",
+ node->nport->enable_ini, node->targ);
+ if (!pend_frames_empty || (node->nport->enable_ini && node->targ)) {
+ u8 send_plogi = false;
+
+ if (node->nport->enable_ini && node->targ) {
+ /*
+ * we're an initiator and
+ * node shutting down is a target;
+ * we'll need to re-authenticate in
+ * initial state
+ */
+ send_plogi = true;
+ }
+
+ /*
+ * transition to __efc_d_init
+ * (will retain HW node resources)
+ */
+ node->els_io_enabled = true;
+ node->req_free = false;
+
+ /*
+ * either pending frames exist or we are re-authenticating
+ * with PLOGI (or both); in either case, return to initial
+ * state
+ */
+ efc_node_init_device(node, send_plogi);
+ }
+ /* else: let node shutdown occur */
+}
+
+static void
+efc_node_purge_pending(struct efc_node *node)
+{
+ struct efc *efc = node->efc;
+ struct efc_hw_sequence *frame, *next;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&node->pend_frames_lock, flags);
+
+ list_for_each_entry_safe(frame, next, &node->pend_frames, list_entry) {
+ list_del(&frame->list_entry);
+ efc->tt.hw_seq_free(efc, frame);
+ }
+
+ spin_unlock_irqrestore(&node->pend_frames_lock, flags);
+}
+
+void
+__efc_node_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER: {
+ efc_node_hold_frames(node);
+ WARN_ON(!efc_els_io_list_empty(node, &node->els_ios_list));
+ /* by default, we will be freeing node after we unwind */
+ node->req_free = true;
+
+ switch (node->shutdown_reason) {
+ case EFC_NODE_SHUTDOWN_IMPLICIT_LOGO:
+ /* Node shutdown b/c of PLOGI received when node
+ * already logged in. We have PLOGI service
+ * parameters, so submit node attach; we won't be
+ * freeing this node
+ */
+
+ efc_node_handle_implicit_logo(node);
+ break;
+
+ case EFC_NODE_SHUTDOWN_EXPLICIT_LOGO:
+ efc_node_handle_explicit_logo(node);
+ break;
+
+ case EFC_NODE_SHUTDOWN_DEFAULT:
+ default: {
+ /*
+ * shutdown due to link down,
+ * node going away (xport event) or
+ * nport shutdown, purge pending and
+ * proceed to cleanup node
+ */
+
+ /* cleanup any pending LS_ACC ELSs */
+ efc_node_send_ls_io_cleanup(node);
+
+ node_printf(node,
+ "Shutdown reason: default, purge pending\n");
+ efc_node_purge_pending(node);
+ break;
+ }
+ }
+
+ break;
+ }
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ default:
+ __efc_node_common(__func__, ctx, evt, arg);
+ }
+}
+
+static bool
+efc_node_check_els_quiesced(struct efc_node *node)
+{
+ /* check to see if ELS requests, completions are quiesced */
+ if (node->els_req_cnt == 0 && node->els_cmpl_cnt == 0 &&
+ efc_els_io_list_empty(node, &node->els_ios_list)) {
+ if (!node->attached) {
+ /* hw node detach already completed, proceed */
+ node_printf(node, "HW node not attached\n");
+ efc_node_transition(node,
+ __efc_node_wait_ios_shutdown,
+ NULL);
+ } else {
+ /*
+ * hw node detach hasn't completed,
+ * transition and wait
+ */
+ node_printf(node, "HW node still attached\n");
+ efc_node_transition(node, __efc_node_wait_node_free,
+ NULL);
+ }
+ return true;
+ }
+ return false;
+}
+
+void
+efc_node_initiate_cleanup(struct efc_node *node)
+{
+ /*
+ * if ELS's have already been quiesced, will move to next state
+ * if ELS's have not been quiesced, abort them
+ */
+ if (!efc_node_check_els_quiesced(node)) {
+ efc_node_hold_frames(node);
+ efc_node_transition(node, __efc_node_wait_els_shutdown, NULL);
+ }
+}
+
+void
+__efc_node_wait_els_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ bool check_quiesce = false;
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+ /* Node state machine: Wait for all ELSs to complete */
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ if (efc_els_io_list_empty(node, &node->els_ios_list)) {
+ node_printf(node, "All ELS IOs complete\n");
+ check_quiesce = true;
+ }
+ break;
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_SRRS_ELS_REQ_OK:
+ case EFC_EVT_SRRS_ELS_REQ_FAIL:
+ case EFC_EVT_SRRS_ELS_REQ_RJT:
+ case EFC_EVT_ELS_REQ_ABORTED:
+ if (WARN_ON(!node->els_req_cnt))
+ break;
+ node->els_req_cnt--;
+ check_quiesce = true;
+ break;
+
+ case EFC_EVT_SRRS_ELS_CMPL_OK:
+ case EFC_EVT_SRRS_ELS_CMPL_FAIL:
+ if (WARN_ON(!node->els_cmpl_cnt))
+ break;
+ node->els_cmpl_cnt--;
+ check_quiesce = true;
+ break;
+
+ case EFC_EVT_ALL_CHILD_NODES_FREE:
+ /* all ELS IO's complete */
+ node_printf(node, "All ELS IOs complete\n");
+ WARN_ON(!efc_els_io_list_empty(node, &node->els_ios_list));
+ check_quiesce = true;
+ break;
+
+ case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
+ check_quiesce = true;
+ break;
+
+ case EFC_EVT_DOMAIN_ATTACH_OK:
+ /* don't care about domain_attach_ok */
+ break;
+
+ /* ignore shutdown events as we're already in shutdown path */
+ case EFC_EVT_SHUTDOWN:
+ /* have default shutdown event take precedence */
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ fallthrough;
+
+ case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
+ case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
+ node_printf(node, "%s received\n", efc_sm_event_name(evt));
+ break;
+
+ default:
+ __efc_node_common(__func__, ctx, evt, arg);
+ }
+
+ if (check_quiesce)
+ efc_node_check_els_quiesced(node);
+}
+
+void
+__efc_node_wait_node_free(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_NODE_FREE_OK:
+ /* node is officially no longer attached */
+ node->attached = false;
+ efc_node_transition(node, __efc_node_wait_ios_shutdown, NULL);
+ break;
+
+ case EFC_EVT_ALL_CHILD_NODES_FREE:
+ case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
+ /* As IOs and ELS IO's complete we expect to get these events */
+ break;
+
+ case EFC_EVT_DOMAIN_ATTACH_OK:
+ /* don't care about domain_attach_ok */
+ break;
+
+ /* ignore shutdown events as we're already in shutdown path */
+ case EFC_EVT_SHUTDOWN:
+ /* have default shutdown event take precedence */
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ fallthrough;
+
+ case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
+ case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
+ node_printf(node, "%s received\n", efc_sm_event_name(evt));
+ break;
+ default:
+ __efc_node_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_node_wait_ios_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+ struct efc *efc = node->efc;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ efc_node_hold_frames(node);
+
+ /* first check to see if no ELS IOs are outstanding */
+ if (efc_els_io_list_empty(node, &node->els_ios_list))
+ /* If there are any active IOS, Free them. */
+ efc_node_transition(node, __efc_node_shutdown, NULL);
+ break;
+
+ case EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY:
+ case EFC_EVT_ALL_CHILD_NODES_FREE:
+ if (efc_els_io_list_empty(node, &node->els_ios_list))
+ efc_node_transition(node, __efc_node_shutdown, NULL);
+ break;
+
+ case EFC_EVT_EXIT:
+ efc_node_accept_frames(node);
+ break;
+
+ case EFC_EVT_SRRS_ELS_REQ_FAIL:
+ /* Can happen as ELS IO IO's complete */
+ if (WARN_ON(!node->els_req_cnt))
+ break;
+ node->els_req_cnt--;
+ break;
+
+ /* ignore shutdown events as we're already in shutdown path */
+ case EFC_EVT_SHUTDOWN:
+ /* have default shutdown event take precedence */
+ node->shutdown_reason = EFC_NODE_SHUTDOWN_DEFAULT;
+ fallthrough;
+
+ case EFC_EVT_SHUTDOWN_EXPLICIT_LOGO:
+ case EFC_EVT_SHUTDOWN_IMPLICIT_LOGO:
+ efc_log_debug(efc, "[%s] %-20s\n", node->display_name,
+ efc_sm_event_name(evt));
+ break;
+ case EFC_EVT_DOMAIN_ATTACH_OK:
+ /* don't care about domain_attach_ok */
+ break;
+ default:
+ __efc_node_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_node_common(const char *funcname, struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = NULL;
+ struct efc *efc = NULL;
+ struct efc_node_cb *cbdata = arg;
+
+ node = ctx->app;
+ efc = node->efc;
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ case EFC_EVT_REENTER:
+ case EFC_EVT_EXIT:
+ case EFC_EVT_NPORT_TOPOLOGY_NOTIFY:
+ case EFC_EVT_NODE_MISSING:
+ case EFC_EVT_FCP_CMD_RCVD:
+ break;
+
+ case EFC_EVT_NODE_REFOUND:
+ node->refound = true;
+ break;
+
+ /*
+ * node->attached must be set appropriately
+ * for all node attach/detach events
+ */
+ case EFC_EVT_NODE_ATTACH_OK:
+ node->attached = true;
+ break;
+
+ case EFC_EVT_NODE_FREE_OK:
+ case EFC_EVT_NODE_ATTACH_FAIL:
+ node->attached = false;
+ break;
+
+ /*
+ * handle any ELS completions that
+ * other states either didn't care about
+ * or forgot about
+ */
+ case EFC_EVT_SRRS_ELS_CMPL_OK:
+ case EFC_EVT_SRRS_ELS_CMPL_FAIL:
+ if (WARN_ON(!node->els_cmpl_cnt))
+ break;
+ node->els_cmpl_cnt--;
+ break;
+
+ /*
+ * handle any ELS request completions that
+ * other states either didn't care about
+ * or forgot about
+ */
+ case EFC_EVT_SRRS_ELS_REQ_OK:
+ case EFC_EVT_SRRS_ELS_REQ_FAIL:
+ case EFC_EVT_SRRS_ELS_REQ_RJT:
+ case EFC_EVT_ELS_REQ_ABORTED:
+ if (WARN_ON(!node->els_req_cnt))
+ break;
+ node->els_req_cnt--;
+ break;
+
+ case EFC_EVT_ELS_RCVD: {
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+
+ /*
+ * Unsupported ELS was received,
+ * send LS_RJT, command not supported
+ */
+ efc_log_debug(efc,
+ "[%s] (%s) ELS x%02x, LS_RJT not supported\n",
+ node->display_name, funcname,
+ ((u8 *)cbdata->payload->dma.virt)[0]);
+
+ efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
+ ELS_RJT_UNSUP, ELS_EXPL_NONE, 0);
+ break;
+ }
+
+ case EFC_EVT_PLOGI_RCVD:
+ case EFC_EVT_FLOGI_RCVD:
+ case EFC_EVT_LOGO_RCVD:
+ case EFC_EVT_PRLI_RCVD:
+ case EFC_EVT_PRLO_RCVD:
+ case EFC_EVT_PDISC_RCVD:
+ case EFC_EVT_FDISC_RCVD:
+ case EFC_EVT_ADISC_RCVD:
+ case EFC_EVT_RSCN_RCVD:
+ case EFC_EVT_SCR_RCVD: {
+ struct fc_frame_header *hdr = cbdata->header->dma.virt;
+
+ /* sm: / send ELS_RJT */
+ efc_log_debug(efc, "[%s] (%s) %s sending ELS_RJT\n",
+ node->display_name, funcname,
+ efc_sm_event_name(evt));
+ /* if we didn't catch this in a state, send generic LS_RJT */
+ efc_send_ls_rjt(node, be16_to_cpu(hdr->fh_ox_id),
+ ELS_RJT_UNAB, ELS_EXPL_NONE, 0);
+ break;
+ }
+ case EFC_EVT_ABTS_RCVD: {
+ efc_log_debug(efc, "[%s] (%s) %s sending BA_ACC\n",
+ node->display_name, funcname,
+ efc_sm_event_name(evt));
+
+ /* sm: / send BA_ACC */
+ efc_send_bls_acc(node, cbdata->header->dma.virt);
+ break;
+ }
+
+ default:
+ efc_log_debug(node->efc, "[%s] %-20s %-20s not handled\n",
+ node->display_name, funcname,
+ efc_sm_event_name(evt));
+ }
+}
+
+void
+efc_node_save_sparms(struct efc_node *node, void *payload)
+{
+ memcpy(node->service_params, payload, sizeof(node->service_params));
+}
+
+void
+efc_node_post_event(struct efc_node *node,
+ enum efc_sm_event evt, void *arg)
+{
+ bool free_node = false;
+
+ node->evtdepth++;
+
+ efc_sm_post_event(&node->sm, evt, arg);
+
+ /* If our event call depth is one and
+ * we're not holding frames
+ * then we can dispatch any pending frames.
+ * We don't want to allow the efc_process_node_pending()
+ * call to recurse.
+ */
+ if (!node->hold_frames && node->evtdepth == 1)
+ efc_process_node_pending(node);
+
+ node->evtdepth--;
+
+ /*
+ * Free the node object if so requested,
+ * and we're at an event call depth of zero
+ */
+ if (node->evtdepth == 0 && node->req_free)
+ free_node = true;
+
+ if (free_node)
+ efc_node_free(node);
+}
+
+void
+efc_node_transition(struct efc_node *node,
+ void (*state)(struct efc_sm_ctx *,
+ enum efc_sm_event, void *), void *data)
+{
+ struct efc_sm_ctx *ctx = &node->sm;
+
+ if (ctx->current_state == state) {
+ efc_node_post_event(node, EFC_EVT_REENTER, data);
+ } else {
+ efc_node_post_event(node, EFC_EVT_EXIT, data);
+ ctx->current_state = state;
+ efc_node_post_event(node, EFC_EVT_ENTER, data);
+ }
+}
+
+void
+efc_node_build_eui_name(char *buf, u32 buf_len, uint64_t eui_name)
+{
+ memset(buf, 0, buf_len);
+
+ snprintf(buf, buf_len, "eui.%016llX", (unsigned long long)eui_name);
+}
+
+u64
+efc_node_get_wwpn(struct efc_node *node)
+{
+ struct fc_els_flogi *sp =
+ (struct fc_els_flogi *)node->service_params;
+
+ return be64_to_cpu(sp->fl_wwpn);
+}
+
+u64
+efc_node_get_wwnn(struct efc_node *node)
+{
+ struct fc_els_flogi *sp =
+ (struct fc_els_flogi *)node->service_params;
+
+ return be64_to_cpu(sp->fl_wwnn);
+}
+
+int
+efc_node_check_els_req(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg,
+ u8 cmd, void (*efc_node_common_func)(const char *,
+ struct efc_sm_ctx *, enum efc_sm_event, void *),
+ const char *funcname)
+{
+ return 0;
+}
+
+int
+efc_node_check_ns_req(struct efc_sm_ctx *ctx, enum efc_sm_event evt, void *arg,
+ u16 cmd, void (*efc_node_common_func)(const char *,
+ struct efc_sm_ctx *, enum efc_sm_event, void *),
+ const char *funcname)
+{
+ return 0;
+}
+
+int
+efc_els_io_list_empty(struct efc_node *node, struct list_head *list)
+{
+ int empty;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&node->els_ios_lock, flags);
+ empty = list_empty(list);
+ spin_unlock_irqrestore(&node->els_ios_lock, flags);
+ return empty;
+}
+
+void
+efc_node_pause(struct efc_node *node,
+ void (*state)(struct efc_sm_ctx *,
+ enum efc_sm_event, void *))
+
+{
+ node->nodedb_state = state;
+ efc_node_transition(node, __efc_node_paused, NULL);
+}
+
+void
+__efc_node_paused(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_node *node = ctx->app;
+
+ efc_node_evt_set(ctx, evt, __func__);
+
+ node_sm_trace();
+
+ /*
+ * This state is entered when a state is "paused". When resumed, the
+ * node is transitioned to a previously saved state (node->ndoedb_state)
+ */
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ node_printf(node, "Paused\n");
+ break;
+
+ case EFC_EVT_RESUME: {
+ void (*pf)(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+
+ pf = node->nodedb_state;
+
+ node->nodedb_state = NULL;
+ efc_node_transition(node, pf, NULL);
+ break;
+ }
+
+ case EFC_EVT_DOMAIN_ATTACH_OK:
+ break;
+
+ case EFC_EVT_SHUTDOWN:
+ node->req_free = true;
+ break;
+
+ default:
+ __efc_node_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+efc_node_recv_els_frame(struct efc_node *node,
+ struct efc_hw_sequence *seq)
+{
+ u32 prli_size = sizeof(struct fc_els_prli) + sizeof(struct fc_els_spp);
+ struct {
+ u32 cmd;
+ enum efc_sm_event evt;
+ u32 payload_size;
+ } els_cmd_list[] = {
+ {ELS_PLOGI, EFC_EVT_PLOGI_RCVD, sizeof(struct fc_els_flogi)},
+ {ELS_FLOGI, EFC_EVT_FLOGI_RCVD, sizeof(struct fc_els_flogi)},
+ {ELS_LOGO, EFC_EVT_LOGO_RCVD, sizeof(struct fc_els_ls_acc)},
+ {ELS_PRLI, EFC_EVT_PRLI_RCVD, prli_size},
+ {ELS_PRLO, EFC_EVT_PRLO_RCVD, prli_size},
+ {ELS_PDISC, EFC_EVT_PDISC_RCVD, MAX_ACC_REJECT_PAYLOAD},
+ {ELS_FDISC, EFC_EVT_FDISC_RCVD, MAX_ACC_REJECT_PAYLOAD},
+ {ELS_ADISC, EFC_EVT_ADISC_RCVD, sizeof(struct fc_els_adisc)},
+ {ELS_RSCN, EFC_EVT_RSCN_RCVD, MAX_ACC_REJECT_PAYLOAD},
+ {ELS_SCR, EFC_EVT_SCR_RCVD, MAX_ACC_REJECT_PAYLOAD},
+ };
+ struct efc_node_cb cbdata;
+ u8 *buf = seq->payload->dma.virt;
+ enum efc_sm_event evt = EFC_EVT_ELS_RCVD;
+ u32 i;
+
+ memset(&cbdata, 0, sizeof(cbdata));
+ cbdata.header = seq->header;
+ cbdata.payload = seq->payload;
+
+ /* find a matching event for the ELS command */
+ for (i = 0; i < ARRAY_SIZE(els_cmd_list); i++) {
+ if (els_cmd_list[i].cmd == buf[0]) {
+ evt = els_cmd_list[i].evt;
+ break;
+ }
+ }
+
+ efc_node_post_event(node, evt, &cbdata);
+}
+
+void
+efc_node_recv_ct_frame(struct efc_node *node,
+ struct efc_hw_sequence *seq)
+{
+ struct fc_ct_hdr *iu = seq->payload->dma.virt;
+ struct fc_frame_header *hdr = seq->header->dma.virt;
+ struct efc *efc = node->efc;
+ u16 gscmd = be16_to_cpu(iu->ct_cmd);
+
+ efc_log_err(efc, "[%s] Received cmd :%x sending CT_REJECT\n",
+ node->display_name, gscmd);
+ efc_send_ct_rsp(efc, node, be16_to_cpu(hdr->fh_ox_id), iu,
+ FC_FS_RJT, FC_FS_RJT_UNSUP, 0);
+}
+
+void
+efc_node_recv_fcp_cmd(struct efc_node *node, struct efc_hw_sequence *seq)
+{
+ struct efc_node_cb cbdata;
+
+ memset(&cbdata, 0, sizeof(cbdata));
+ cbdata.header = seq->header;
+ cbdata.payload = seq->payload;
+
+ efc_node_post_event(node, EFC_EVT_FCP_CMD_RCVD, &cbdata);
+}
+
+void
+efc_process_node_pending(struct efc_node *node)
+{
+ struct efc *efc = node->efc;
+ struct efc_hw_sequence *seq = NULL;
+ u32 pend_frames_processed = 0;
+ unsigned long flags = 0;
+
+ for (;;) {
+ /* need to check for hold frames condition after each frame
+ * processed because any given frame could cause a transition
+ * to a state that holds frames
+ */
+ if (node->hold_frames)
+ break;
+
+ seq = NULL;
+ /* Get next frame/sequence */
+ spin_lock_irqsave(&node->pend_frames_lock, flags);
+
+ if (!list_empty(&node->pend_frames)) {
+ seq = list_first_entry(&node->pend_frames,
+ struct efc_hw_sequence, list_entry);
+ list_del(&seq->list_entry);
+ }
+ spin_unlock_irqrestore(&node->pend_frames_lock, flags);
+
+ if (!seq) {
+ pend_frames_processed = node->pend_frames_processed;
+ node->pend_frames_processed = 0;
+ break;
+ }
+ node->pend_frames_processed++;
+
+ /* now dispatch frame(s) to dispatch function */
+ efc_node_dispatch_frame(node, seq);
+ efc->tt.hw_seq_free(efc, seq);
+ }
+
+ if (pend_frames_processed != 0)
+ efc_log_debug(efc, "%u node frames held and processed\n",
+ pend_frames_processed);
+}
+
+void
+efc_scsi_sess_reg_complete(struct efc_node *node, u32 status)
+{
+ unsigned long flags = 0;
+ enum efc_sm_event evt = EFC_EVT_NODE_SESS_REG_OK;
+ struct efc *efc = node->efc;
+
+ if (status)
+ evt = EFC_EVT_NODE_SESS_REG_FAIL;
+
+ spin_lock_irqsave(&efc->lock, flags);
+ /* Notify the node to resume */
+ efc_node_post_event(node, evt, NULL);
+ spin_unlock_irqrestore(&efc->lock, flags);
+}
+
+void
+efc_scsi_del_initiator_complete(struct efc *efc, struct efc_node *node)
+{
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&efc->lock, flags);
+ /* Notify the node to resume */
+ efc_node_post_event(node, EFC_EVT_NODE_DEL_INI_COMPLETE, NULL);
+ spin_unlock_irqrestore(&efc->lock, flags);
+}
+
+void
+efc_scsi_del_target_complete(struct efc *efc, struct efc_node *node)
+{
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&efc->lock, flags);
+ /* Notify the node to resume */
+ efc_node_post_event(node, EFC_EVT_NODE_DEL_TGT_COMPLETE, NULL);
+ spin_unlock_irqrestore(&efc->lock, flags);
+}
+
+void
+efc_scsi_io_list_empty(struct efc *efc, struct efc_node *node)
+{
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&efc->lock, flags);
+ efc_node_post_event(node, EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY, NULL);
+ spin_unlock_irqrestore(&efc->lock, flags);
+}
+
+void efc_node_post_els_resp(struct efc_node *node, u32 evt, void *arg)
+{
+ struct efc *efc = node->efc;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&efc->lock, flags);
+ efc_node_post_event(node, evt, arg);
+ spin_unlock_irqrestore(&efc->lock, flags);
+}
+
+void efc_node_post_shutdown(struct efc_node *node, void *arg)
+{
+ unsigned long flags = 0;
+ struct efc *efc = node->efc;
+
+ spin_lock_irqsave(&efc->lock, flags);
+ efc_node_post_event(node, EFC_EVT_SHUTDOWN, arg);
+ spin_unlock_irqrestore(&efc->lock, flags);
+}
diff --git a/drivers/scsi/elx/libefc/efc_node.h b/drivers/scsi/elx/libefc/efc_node.h
new file mode 100644
index 000000000000..e9c600ac45d5
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_node.h
@@ -0,0 +1,191 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#if !defined(__EFC_NODE_H__)
+#define __EFC_NODE_H__
+#include "scsi/fc/fc_ns.h"
+
+#define EFC_NODEDB_PAUSE_FABRIC_LOGIN (1 << 0)
+#define EFC_NODEDB_PAUSE_NAMESERVER (1 << 1)
+#define EFC_NODEDB_PAUSE_NEW_NODES (1 << 2)
+
+#define MAX_ACC_REJECT_PAYLOAD sizeof(struct fc_els_ls_rjt)
+
+#define scsi_io_printf(io, fmt, ...) \
+ efc_log_debug(io->efc, "[%s] [%04x][i:%04x t:%04x h:%04x]" fmt, \
+ io->node->display_name, io->instance_index, io->init_task_tag, \
+ io->tgt_task_tag, io->hw_tag, ##__VA_ARGS__)
+
+static inline void
+efc_node_evt_set(struct efc_sm_ctx *ctx, enum efc_sm_event evt,
+ const char *handler)
+{
+ struct efc_node *node = ctx->app;
+
+ if (evt == EFC_EVT_ENTER) {
+ strncpy(node->current_state_name, handler,
+ sizeof(node->current_state_name));
+ } else if (evt == EFC_EVT_EXIT) {
+ strncpy(node->prev_state_name, node->current_state_name,
+ sizeof(node->prev_state_name));
+ strncpy(node->current_state_name, "invalid",
+ sizeof(node->current_state_name));
+ }
+ node->prev_evt = node->current_evt;
+ node->current_evt = evt;
+}
+
+/**
+ * hold frames in pending frame list
+ *
+ * Unsolicited receive frames are held on the node pending frame list,
+ * rather than being processed.
+ */
+
+static inline void
+efc_node_hold_frames(struct efc_node *node)
+{
+ node->hold_frames = true;
+}
+
+/**
+ * accept frames
+ *
+ * Unsolicited receive frames processed rather than being held on the node
+ * pending frame list.
+ */
+
+static inline void
+efc_node_accept_frames(struct efc_node *node)
+{
+ node->hold_frames = false;
+}
+
+/*
+ * Node initiator/target enable defines
+ * All combinations of the SLI port (nport) initiator/target enable,
+ * and remote node initiator/target enable are enumerated.
+ * ex: EFC_NODE_ENABLE_T_TO_IT decodes to target mode is enabled on SLI port
+ * and I+T is enabled on remote node.
+ */
+enum efc_node_enable {
+ EFC_NODE_ENABLE_x_TO_x,
+ EFC_NODE_ENABLE_x_TO_T,
+ EFC_NODE_ENABLE_x_TO_I,
+ EFC_NODE_ENABLE_x_TO_IT,
+ EFC_NODE_ENABLE_T_TO_x,
+ EFC_NODE_ENABLE_T_TO_T,
+ EFC_NODE_ENABLE_T_TO_I,
+ EFC_NODE_ENABLE_T_TO_IT,
+ EFC_NODE_ENABLE_I_TO_x,
+ EFC_NODE_ENABLE_I_TO_T,
+ EFC_NODE_ENABLE_I_TO_I,
+ EFC_NODE_ENABLE_I_TO_IT,
+ EFC_NODE_ENABLE_IT_TO_x,
+ EFC_NODE_ENABLE_IT_TO_T,
+ EFC_NODE_ENABLE_IT_TO_I,
+ EFC_NODE_ENABLE_IT_TO_IT,
+};
+
+static inline enum efc_node_enable
+efc_node_get_enable(struct efc_node *node)
+{
+ u32 retval = 0;
+
+ if (node->nport->enable_ini)
+ retval |= (1U << 3);
+ if (node->nport->enable_tgt)
+ retval |= (1U << 2);
+ if (node->init)
+ retval |= (1U << 1);
+ if (node->targ)
+ retval |= (1U << 0);
+ return (enum efc_node_enable)retval;
+}
+
+int
+efc_node_check_els_req(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg,
+ u8 cmd, void (*efc_node_common_func)(const char *,
+ struct efc_sm_ctx *, enum efc_sm_event, void *),
+ const char *funcname);
+int
+efc_node_check_ns_req(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg,
+ u16 cmd, void (*efc_node_common_func)(const char *,
+ struct efc_sm_ctx *, enum efc_sm_event, void *),
+ const char *funcname);
+int
+efc_node_attach(struct efc_node *node);
+struct efc_node *
+efc_node_alloc(struct efc_nport *nport, u32 port_id,
+ bool init, bool targ);
+void
+efc_node_free(struct efc_node *efc);
+void
+efc_node_update_display_name(struct efc_node *node);
+void efc_node_post_event(struct efc_node *node, enum efc_sm_event evt,
+ void *arg);
+
+void
+__efc_node_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_node_wait_node_free(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_node_wait_els_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_node_wait_ios_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+efc_node_save_sparms(struct efc_node *node, void *payload);
+void
+efc_node_transition(struct efc_node *node,
+ void (*state)(struct efc_sm_ctx *, enum efc_sm_event,
+ void *), void *data);
+void
+__efc_node_common(const char *funcname, struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+
+void
+efc_node_initiate_cleanup(struct efc_node *node);
+
+void
+efc_node_build_eui_name(char *buf, u32 buf_len, uint64_t eui_name);
+
+void
+efc_node_pause(struct efc_node *node,
+ void (*state)(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg));
+void
+__efc_node_paused(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+int
+efc_node_active_ios_empty(struct efc_node *node);
+void
+efc_node_send_ls_io_cleanup(struct efc_node *node);
+
+int
+efc_els_io_list_empty(struct efc_node *node, struct list_head *list);
+
+void
+efc_process_node_pending(struct efc_node *domain);
+
+u64 efc_node_get_wwnn(struct efc_node *node);
+struct efc_node *
+efc_node_find(struct efc_nport *nport, u32 id);
+void
+efc_node_post_els_resp(struct efc_node *node, u32 evt, void *arg);
+void
+efc_node_recv_els_frame(struct efc_node *node, struct efc_hw_sequence *s);
+void
+efc_node_recv_ct_frame(struct efc_node *node, struct efc_hw_sequence *seq);
+void
+efc_node_recv_fcp_cmd(struct efc_node *node, struct efc_hw_sequence *seq);
+
+#endif /* __EFC_NODE_H__ */
diff --git a/drivers/scsi/elx/libefc/efc_nport.c b/drivers/scsi/elx/libefc/efc_nport.c
new file mode 100644
index 000000000000..2e83a667901f
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_nport.c
@@ -0,0 +1,777 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+/*
+ * NPORT
+ *
+ * Port object for physical port and NPIV ports.
+ */
+
+/*
+ * NPORT REFERENCE COUNTING
+ *
+ * A nport reference should be taken when:
+ * - an nport is allocated
+ * - a vport populates associated nport
+ * - a remote node is allocated
+ * - a unsolicited frame is processed
+ * The reference should be dropped when:
+ * - the unsolicited frame processesing is done
+ * - the remote node is removed
+ * - the vport is removed
+ * - the nport is removed
+ */
+
+#include "efc.h"
+
+void
+efc_nport_cb(void *arg, int event, void *data)
+{
+ struct efc *efc = arg;
+ struct efc_nport *nport = data;
+ unsigned long flags = 0;
+
+ efc_log_debug(efc, "nport event: %s\n", efc_sm_event_name(event));
+
+ spin_lock_irqsave(&efc->lock, flags);
+ efc_sm_post_event(&nport->sm, event, NULL);
+ spin_unlock_irqrestore(&efc->lock, flags);
+}
+
+static struct efc_nport *
+efc_nport_find_wwn(struct efc_domain *domain, uint64_t wwnn, uint64_t wwpn)
+{
+ struct efc_nport *nport = NULL;
+
+ /* Find a nport, given the WWNN and WWPN */
+ list_for_each_entry(nport, &domain->nport_list, list_entry) {
+ if (nport->wwnn == wwnn && nport->wwpn == wwpn)
+ return nport;
+ }
+ return NULL;
+}
+
+static void
+_efc_nport_free(struct kref *arg)
+{
+ struct efc_nport *nport = container_of(arg, struct efc_nport, ref);
+
+ kfree(nport);
+}
+
+struct efc_nport *
+efc_nport_alloc(struct efc_domain *domain, uint64_t wwpn, uint64_t wwnn,
+ u32 fc_id, bool enable_ini, bool enable_tgt)
+{
+ struct efc_nport *nport;
+
+ if (domain->efc->enable_ini)
+ enable_ini = 0;
+
+ /* Return a failure if this nport has already been allocated */
+ if ((wwpn != 0) || (wwnn != 0)) {
+ nport = efc_nport_find_wwn(domain, wwnn, wwpn);
+ if (nport) {
+ efc_log_err(domain->efc,
+ "NPORT %016llX %016llX already allocated\n",
+ wwnn, wwpn);
+ return NULL;
+ }
+ }
+
+ nport = kzalloc(sizeof(*nport), GFP_ATOMIC);
+ if (!nport)
+ return nport;
+
+ /* initialize refcount */
+ kref_init(&nport->ref);
+ nport->release = _efc_nport_free;
+
+ nport->efc = domain->efc;
+ snprintf(nport->display_name, sizeof(nport->display_name), "------");
+ nport->domain = domain;
+ xa_init(&nport->lookup);
+ nport->instance_index = domain->nport_count++;
+ nport->sm.app = nport;
+ nport->enable_ini = enable_ini;
+ nport->enable_tgt = enable_tgt;
+ nport->enable_rscn = (nport->enable_ini ||
+ (nport->enable_tgt && enable_target_rscn(nport->efc)));
+
+ /* Copy service parameters from domain */
+ memcpy(nport->service_params, domain->service_params,
+ sizeof(struct fc_els_flogi));
+
+ /* Update requested fc_id */
+ nport->fc_id = fc_id;
+
+ /* Update the nport's service parameters for the new wwn's */
+ nport->wwpn = wwpn;
+ nport->wwnn = wwnn;
+ snprintf(nport->wwnn_str, sizeof(nport->wwnn_str), "%016llX",
+ (unsigned long long)wwnn);
+
+ /*
+ * if this is the "first" nport of the domain,
+ * then make it the "phys" nport
+ */
+ if (list_empty(&domain->nport_list))
+ domain->nport = nport;
+
+ INIT_LIST_HEAD(&nport->list_entry);
+ list_add_tail(&nport->list_entry, &domain->nport_list);
+
+ kref_get(&domain->ref);
+
+ efc_log_debug(domain->efc, "New Nport [%s]\n", nport->display_name);
+
+ return nport;
+}
+
+void
+efc_nport_free(struct efc_nport *nport)
+{
+ struct efc_domain *domain;
+
+ if (!nport)
+ return;
+
+ domain = nport->domain;
+ efc_log_debug(domain->efc, "[%s] free nport\n", nport->display_name);
+ list_del(&nport->list_entry);
+ /*
+ * if this is the physical nport,
+ * then clear it out of the domain
+ */
+ if (nport == domain->nport)
+ domain->nport = NULL;
+
+ xa_destroy(&nport->lookup);
+ xa_erase(&domain->lookup, nport->fc_id);
+
+ if (list_empty(&domain->nport_list))
+ efc_domain_post_event(domain, EFC_EVT_ALL_CHILD_NODES_FREE,
+ NULL);
+
+ kref_put(&domain->ref, domain->release);
+ kref_put(&nport->ref, nport->release);
+}
+
+struct efc_nport *
+efc_nport_find(struct efc_domain *domain, u32 d_id)
+{
+ struct efc_nport *nport;
+
+ /* Find a nport object, given an FC_ID */
+ nport = xa_load(&domain->lookup, d_id);
+ if (!nport || !kref_get_unless_zero(&nport->ref))
+ return NULL;
+
+ return nport;
+}
+
+int
+efc_nport_attach(struct efc_nport *nport, u32 fc_id)
+{
+ int rc;
+ struct efc_node *node;
+ struct efc *efc = nport->efc;
+ unsigned long index;
+
+ /* Set our lookup */
+ rc = xa_err(xa_store(&nport->domain->lookup, fc_id, nport, GFP_ATOMIC));
+ if (rc) {
+ efc_log_err(efc, "Sport lookup store failed: %d\n", rc);
+ return rc;
+ }
+
+ /* Update our display_name */
+ efc_node_fcid_display(fc_id, nport->display_name,
+ sizeof(nport->display_name));
+
+ xa_for_each(&nport->lookup, index, node) {
+ efc_node_update_display_name(node);
+ }
+
+ efc_log_debug(nport->efc, "[%s] attach nport: fc_id x%06x\n",
+ nport->display_name, fc_id);
+
+ /* Register a nport, given an FC_ID */
+ rc = efc_cmd_nport_attach(efc, nport, fc_id);
+ if (rc < 0) {
+ efc_log_err(nport->efc,
+ "efc_hw_port_attach failed: %d\n", rc);
+ return -EIO;
+ }
+ return 0;
+}
+
+static void
+efc_nport_shutdown(struct efc_nport *nport)
+{
+ struct efc *efc = nport->efc;
+ struct efc_node *node;
+ unsigned long index;
+
+ xa_for_each(&nport->lookup, index, node) {
+ if (!(node->rnode.fc_id == FC_FID_FLOGI && nport->is_vport)) {
+ efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
+ continue;
+ }
+
+ /*
+ * If this is a vport, logout of the fabric
+ * controller so that it deletes the vport
+ * on the switch.
+ */
+ /* if link is down, don't send logo */
+ if (efc->link_status == EFC_LINK_STATUS_DOWN) {
+ efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
+ continue;
+ }
+
+ efc_log_debug(efc, "[%s] nport shutdown vport, send logo\n",
+ node->display_name);
+
+ if (!efc_send_logo(node)) {
+ /* sent LOGO, wait for response */
+ efc_node_transition(node, __efc_d_wait_logo_rsp, NULL);
+ continue;
+ }
+
+ /*
+ * failed to send LOGO,
+ * go ahead and cleanup node anyways
+ */
+ node_printf(node, "Failed to send LOGO\n");
+ efc_node_post_event(node, EFC_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
+ }
+}
+
+static void
+efc_vport_link_down(struct efc_nport *nport)
+{
+ struct efc *efc = nport->efc;
+ struct efc_vport *vport;
+
+ /* Clear the nport reference in the vport specification */
+ list_for_each_entry(vport, &efc->vport_list, list_entry) {
+ if (vport->nport == nport) {
+ kref_put(&nport->ref, nport->release);
+ vport->nport = NULL;
+ break;
+ }
+ }
+}
+
+static void
+__efc_nport_common(const char *funcname, struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_nport *nport = ctx->app;
+ struct efc_domain *domain = nport->domain;
+ struct efc *efc = nport->efc;
+
+ switch (evt) {
+ case EFC_EVT_ENTER:
+ case EFC_EVT_REENTER:
+ case EFC_EVT_EXIT:
+ case EFC_EVT_ALL_CHILD_NODES_FREE:
+ break;
+ case EFC_EVT_NPORT_ATTACH_OK:
+ efc_sm_transition(ctx, __efc_nport_attached, NULL);
+ break;
+ case EFC_EVT_SHUTDOWN:
+ /* Flag this nport as shutting down */
+ nport->shutting_down = true;
+
+ if (nport->is_vport)
+ efc_vport_link_down(nport);
+
+ if (xa_empty(&nport->lookup)) {
+ /* Remove the nport from the domain's lookup table */
+ xa_erase(&domain->lookup, nport->fc_id);
+ efc_sm_transition(ctx, __efc_nport_wait_port_free,
+ NULL);
+ if (efc_cmd_nport_free(efc, nport)) {
+ efc_log_debug(nport->efc,
+ "efc_hw_port_free failed\n");
+ /* Not much we can do, free the nport anyways */
+ efc_nport_free(nport);
+ }
+ } else {
+ /* sm: node list is not empty / shutdown nodes */
+ efc_sm_transition(ctx,
+ __efc_nport_wait_shutdown, NULL);
+ efc_nport_shutdown(nport);
+ }
+ break;
+ default:
+ efc_log_debug(nport->efc, "[%s] %-20s %-20s not handled\n",
+ nport->display_name, funcname,
+ efc_sm_event_name(evt));
+ }
+}
+
+void
+__efc_nport_allocated(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_nport *nport = ctx->app;
+ struct efc_domain *domain = nport->domain;
+
+ nport_sm_trace(nport);
+
+ switch (evt) {
+ /* the physical nport is attached */
+ case EFC_EVT_NPORT_ATTACH_OK:
+ WARN_ON(nport != domain->nport);
+ efc_sm_transition(ctx, __efc_nport_attached, NULL);
+ break;
+
+ case EFC_EVT_NPORT_ALLOC_OK:
+ /* ignore */
+ break;
+ default:
+ __efc_nport_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_nport_vport_init(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_nport *nport = ctx->app;
+ struct efc *efc = nport->efc;
+
+ nport_sm_trace(nport);
+
+ switch (evt) {
+ case EFC_EVT_ENTER: {
+ __be64 be_wwpn = cpu_to_be64(nport->wwpn);
+
+ if (nport->wwpn == 0)
+ efc_log_debug(efc, "vport: letting f/w select WWN\n");
+
+ if (nport->fc_id != U32_MAX) {
+ efc_log_debug(efc, "vport: hard coding port id: %x\n",
+ nport->fc_id);
+ }
+
+ efc_sm_transition(ctx, __efc_nport_vport_wait_alloc, NULL);
+ /* If wwpn is zero, then we'll let the f/w assign wwpn*/
+ if (efc_cmd_nport_alloc(efc, nport, nport->domain,
+ nport->wwpn == 0 ? NULL :
+ (uint8_t *)&be_wwpn)) {
+ efc_log_err(efc, "Can't allocate port\n");
+ break;
+ }
+
+ break;
+ }
+ default:
+ __efc_nport_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_nport_vport_wait_alloc(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_nport *nport = ctx->app;
+ struct efc *efc = nport->efc;
+
+ nport_sm_trace(nport);
+
+ switch (evt) {
+ case EFC_EVT_NPORT_ALLOC_OK: {
+ struct fc_els_flogi *sp;
+
+ sp = (struct fc_els_flogi *)nport->service_params;
+
+ if (nport->wwnn == 0) {
+ nport->wwnn = be64_to_cpu(nport->sli_wwnn);
+ nport->wwpn = be64_to_cpu(nport->sli_wwpn);
+ snprintf(nport->wwnn_str, sizeof(nport->wwnn_str),
+ "%016llX", nport->wwpn);
+ }
+
+ /* Update the nport's service parameters */
+ sp->fl_wwpn = cpu_to_be64(nport->wwpn);
+ sp->fl_wwnn = cpu_to_be64(nport->wwnn);
+
+ /*
+ * if nport->fc_id is uninitialized,
+ * then request that the fabric node use FDISC
+ * to find an fc_id.
+ * Otherwise we're restoring vports, or we're in
+ * fabric emulation mode, so attach the fc_id
+ */
+ if (nport->fc_id == U32_MAX) {
+ struct efc_node *fabric;
+
+ fabric = efc_node_alloc(nport, FC_FID_FLOGI, false,
+ false);
+ if (!fabric) {
+ efc_log_err(efc, "efc_node_alloc() failed\n");
+ return;
+ }
+ efc_node_transition(fabric, __efc_vport_fabric_init,
+ NULL);
+ } else {
+ snprintf(nport->wwnn_str, sizeof(nport->wwnn_str),
+ "%016llX", nport->wwpn);
+ efc_nport_attach(nport, nport->fc_id);
+ }
+ efc_sm_transition(ctx, __efc_nport_vport_allocated, NULL);
+ break;
+ }
+ default:
+ __efc_nport_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_nport_vport_allocated(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_nport *nport = ctx->app;
+ struct efc *efc = nport->efc;
+
+ nport_sm_trace(nport);
+
+ /*
+ * This state is entered after the nport is allocated;
+ * it then waits for a fabric node
+ * FDISC to complete, which requests a nport attach.
+ * The nport attach complete is handled in this state.
+ */
+ switch (evt) {
+ case EFC_EVT_NPORT_ATTACH_OK: {
+ struct efc_node *node;
+
+ /* Find our fabric node, and forward this event */
+ node = efc_node_find(nport, FC_FID_FLOGI);
+ if (!node) {
+ efc_log_debug(efc, "can't find node %06x\n", FC_FID_FLOGI);
+ break;
+ }
+ /* sm: / forward nport attach to fabric node */
+ efc_node_post_event(node, evt, NULL);
+ efc_sm_transition(ctx, __efc_nport_attached, NULL);
+ break;
+ }
+ default:
+ __efc_nport_common(__func__, ctx, evt, arg);
+ }
+}
+
+static void
+efc_vport_update_spec(struct efc_nport *nport)
+{
+ struct efc *efc = nport->efc;
+ struct efc_vport *vport;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&efc->vport_lock, flags);
+ list_for_each_entry(vport, &efc->vport_list, list_entry) {
+ if (vport->nport == nport) {
+ vport->wwnn = nport->wwnn;
+ vport->wwpn = nport->wwpn;
+ vport->tgt_data = nport->tgt_data;
+ vport->ini_data = nport->ini_data;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&efc->vport_lock, flags);
+}
+
+void
+__efc_nport_attached(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_nport *nport = ctx->app;
+ struct efc *efc = nport->efc;
+
+ nport_sm_trace(nport);
+
+ switch (evt) {
+ case EFC_EVT_ENTER: {
+ struct efc_node *node;
+ unsigned long index;
+
+ efc_log_debug(efc,
+ "[%s] NPORT attached WWPN %016llX WWNN %016llX\n",
+ nport->display_name,
+ nport->wwpn, nport->wwnn);
+
+ xa_for_each(&nport->lookup, index, node)
+ efc_node_update_display_name(node);
+
+ efc->tt.new_nport(efc, nport);
+
+ /*
+ * Update the vport (if its not the physical nport)
+ * parameters
+ */
+ if (nport->is_vport)
+ efc_vport_update_spec(nport);
+ break;
+ }
+
+ case EFC_EVT_EXIT:
+ efc_log_debug(efc,
+ "[%s] NPORT deattached WWPN %016llX WWNN %016llX\n",
+ nport->display_name,
+ nport->wwpn, nport->wwnn);
+
+ efc->tt.del_nport(efc, nport);
+ break;
+ default:
+ __efc_nport_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_nport_wait_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_nport *nport = ctx->app;
+ struct efc_domain *domain = nport->domain;
+ struct efc *efc = nport->efc;
+
+ nport_sm_trace(nport);
+
+ switch (evt) {
+ case EFC_EVT_NPORT_ALLOC_OK:
+ case EFC_EVT_NPORT_ALLOC_FAIL:
+ case EFC_EVT_NPORT_ATTACH_OK:
+ case EFC_EVT_NPORT_ATTACH_FAIL:
+ /* ignore these events - just wait for the all free event */
+ break;
+
+ case EFC_EVT_ALL_CHILD_NODES_FREE: {
+ /*
+ * Remove the nport from the domain's
+ * sparse vector lookup table
+ */
+ xa_erase(&domain->lookup, nport->fc_id);
+ efc_sm_transition(ctx, __efc_nport_wait_port_free, NULL);
+ if (efc_cmd_nport_free(efc, nport)) {
+ efc_log_err(nport->efc, "efc_hw_port_free failed\n");
+ /* Not much we can do, free the nport anyways */
+ efc_nport_free(nport);
+ }
+ break;
+ }
+ default:
+ __efc_nport_common(__func__, ctx, evt, arg);
+ }
+}
+
+void
+__efc_nport_wait_port_free(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg)
+{
+ struct efc_nport *nport = ctx->app;
+
+ nport_sm_trace(nport);
+
+ switch (evt) {
+ case EFC_EVT_NPORT_ATTACH_OK:
+ /* Ignore as we are waiting for the free CB */
+ break;
+ case EFC_EVT_NPORT_FREE_OK: {
+ /* All done, free myself */
+ efc_nport_free(nport);
+ break;
+ }
+ default:
+ __efc_nport_common(__func__, ctx, evt, arg);
+ }
+}
+
+static int
+efc_vport_nport_alloc(struct efc_domain *domain, struct efc_vport *vport)
+{
+ struct efc_nport *nport;
+
+ lockdep_assert_held(&domain->efc->lock);
+
+ nport = efc_nport_alloc(domain, vport->wwpn, vport->wwnn, vport->fc_id,
+ vport->enable_ini, vport->enable_tgt);
+ vport->nport = nport;
+ if (!nport)
+ return -EIO;
+
+ kref_get(&nport->ref);
+ nport->is_vport = true;
+ nport->tgt_data = vport->tgt_data;
+ nport->ini_data = vport->ini_data;
+
+ efc_sm_transition(&nport->sm, __efc_nport_vport_init, NULL);
+
+ return 0;
+}
+
+int
+efc_vport_start(struct efc_domain *domain)
+{
+ struct efc *efc = domain->efc;
+ struct efc_vport *vport;
+ struct efc_vport *next;
+ int rc = 0;
+ unsigned long flags = 0;
+
+ /* Use the vport spec to find the associated vports and start them */
+ spin_lock_irqsave(&efc->vport_lock, flags);
+ list_for_each_entry_safe(vport, next, &efc->vport_list, list_entry) {
+ if (!vport->nport) {
+ if (efc_vport_nport_alloc(domain, vport))
+ rc = -EIO;
+ }
+ }
+ spin_unlock_irqrestore(&efc->vport_lock, flags);
+
+ return rc;
+}
+
+int
+efc_nport_vport_new(struct efc_domain *domain, uint64_t wwpn, uint64_t wwnn,
+ u32 fc_id, bool ini, bool tgt, void *tgt_data,
+ void *ini_data)
+{
+ struct efc *efc = domain->efc;
+ struct efc_vport *vport;
+ int rc = 0;
+ unsigned long flags = 0;
+
+ if (ini && domain->efc->enable_ini == 0) {
+ efc_log_debug(efc, "driver initiator mode not enabled\n");
+ return -EIO;
+ }
+
+ if (tgt && domain->efc->enable_tgt == 0) {
+ efc_log_debug(efc, "driver target mode not enabled\n");
+ return -EIO;
+ }
+
+ /*
+ * Create a vport spec if we need to recreate
+ * this vport after a link up event
+ */
+ vport = efc_vport_create_spec(domain->efc, wwnn, wwpn, fc_id, ini, tgt,
+ tgt_data, ini_data);
+ if (!vport) {
+ efc_log_err(efc, "failed to create vport object entry\n");
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&efc->lock, flags);
+ rc = efc_vport_nport_alloc(domain, vport);
+ spin_unlock_irqrestore(&efc->lock, flags);
+
+ return rc;
+}
+
+int
+efc_nport_vport_del(struct efc *efc, struct efc_domain *domain,
+ u64 wwpn, uint64_t wwnn)
+{
+ struct efc_nport *nport;
+ struct efc_vport *vport;
+ struct efc_vport *next;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&efc->vport_lock, flags);
+ /* walk the efc_vport_list and remove from there */
+ list_for_each_entry_safe(vport, next, &efc->vport_list, list_entry) {
+ if (vport->wwpn == wwpn && vport->wwnn == wwnn) {
+ list_del(&vport->list_entry);
+ kfree(vport);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&efc->vport_lock, flags);
+
+ if (!domain) {
+ /* No domain means no nport to look for */
+ return 0;
+ }
+
+ spin_lock_irqsave(&efc->lock, flags);
+ list_for_each_entry(nport, &domain->nport_list, list_entry) {
+ if (nport->wwpn == wwpn && nport->wwnn == wwnn) {
+ kref_put(&nport->ref, nport->release);
+ /* Shutdown this NPORT */
+ efc_sm_post_event(&nport->sm, EFC_EVT_SHUTDOWN, NULL);
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&efc->lock, flags);
+ return 0;
+}
+
+void
+efc_vport_del_all(struct efc *efc)
+{
+ struct efc_vport *vport;
+ struct efc_vport *next;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&efc->vport_lock, flags);
+ list_for_each_entry_safe(vport, next, &efc->vport_list, list_entry) {
+ list_del(&vport->list_entry);
+ kfree(vport);
+ }
+ spin_unlock_irqrestore(&efc->vport_lock, flags);
+}
+
+struct efc_vport *
+efc_vport_create_spec(struct efc *efc, uint64_t wwnn, uint64_t wwpn,
+ u32 fc_id, bool enable_ini,
+ bool enable_tgt, void *tgt_data, void *ini_data)
+{
+ struct efc_vport *vport;
+ unsigned long flags = 0;
+
+ /*
+ * walk the efc_vport_list and return failure
+ * if a valid(vport with non zero WWPN and WWNN) vport entry
+ * is already created
+ */
+ spin_lock_irqsave(&efc->vport_lock, flags);
+ list_for_each_entry(vport, &efc->vport_list, list_entry) {
+ if ((wwpn && vport->wwpn == wwpn) &&
+ (wwnn && vport->wwnn == wwnn)) {
+ efc_log_err(efc,
+ "VPORT %016llX %016llX already allocated\n",
+ wwnn, wwpn);
+ spin_unlock_irqrestore(&efc->vport_lock, flags);
+ return NULL;
+ }
+ }
+
+ vport = kzalloc(sizeof(*vport), GFP_ATOMIC);
+ if (!vport) {
+ spin_unlock_irqrestore(&efc->vport_lock, flags);
+ return NULL;
+ }
+
+ vport->wwnn = wwnn;
+ vport->wwpn = wwpn;
+ vport->fc_id = fc_id;
+ vport->enable_tgt = enable_tgt;
+ vport->enable_ini = enable_ini;
+ vport->tgt_data = tgt_data;
+ vport->ini_data = ini_data;
+
+ INIT_LIST_HEAD(&vport->list_entry);
+ list_add_tail(&vport->list_entry, &efc->vport_list);
+ spin_unlock_irqrestore(&efc->vport_lock, flags);
+ return vport;
+}
diff --git a/drivers/scsi/elx/libefc/efc_nport.h b/drivers/scsi/elx/libefc/efc_nport.h
new file mode 100644
index 000000000000..b575ea205bbf
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_nport.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+/**
+ * EFC FC port (NPORT) exported declarations
+ *
+ */
+
+#ifndef __EFC_NPORT_H__
+#define __EFC_NPORT_H__
+
+struct efc_nport *
+efc_nport_find(struct efc_domain *domain, u32 d_id);
+struct efc_nport *
+efc_nport_alloc(struct efc_domain *domain, uint64_t wwpn, uint64_t wwnn,
+ u32 fc_id, bool enable_ini, bool enable_tgt);
+void
+efc_nport_free(struct efc_nport *nport);
+int
+efc_nport_attach(struct efc_nport *nport, u32 fc_id);
+
+void
+__efc_nport_allocated(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_nport_wait_shutdown(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_nport_wait_port_free(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_nport_vport_init(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_nport_vport_wait_alloc(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_nport_vport_allocated(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+void
+__efc_nport_attached(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg);
+
+int
+efc_vport_start(struct efc_domain *domain);
+
+#endif /* __EFC_NPORT_H__ */
diff --git a/drivers/scsi/elx/libefc/efc_sm.c b/drivers/scsi/elx/libefc/efc_sm.c
new file mode 100644
index 000000000000..afd963782c1c
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_sm.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+/*
+ * Generic state machine framework.
+ */
+#include "efc.h"
+#include "efc_sm.h"
+
+/**
+ * efc_sm_post_event() - Post an event to a context.
+ *
+ * @ctx: State machine context
+ * @evt: Event to post
+ * @data: Event-specific data (if any)
+ */
+int
+efc_sm_post_event(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *data)
+{
+ if (!ctx->current_state)
+ return -EIO;
+
+ ctx->current_state(ctx, evt, data);
+ return 0;
+}
+
+void
+efc_sm_transition(struct efc_sm_ctx *ctx,
+ void (*state)(struct efc_sm_ctx *,
+ enum efc_sm_event, void *), void *data)
+
+{
+ if (ctx->current_state == state) {
+ efc_sm_post_event(ctx, EFC_EVT_REENTER, data);
+ } else {
+ efc_sm_post_event(ctx, EFC_EVT_EXIT, data);
+ ctx->current_state = state;
+ efc_sm_post_event(ctx, EFC_EVT_ENTER, data);
+ }
+}
+
+static char *event_name[] = EFC_SM_EVENT_NAME;
+
+const char *efc_sm_event_name(enum efc_sm_event evt)
+{
+ if (evt > EFC_EVT_LAST)
+ return "unknown";
+
+ return event_name[evt];
+}
diff --git a/drivers/scsi/elx/libefc/efc_sm.h b/drivers/scsi/elx/libefc/efc_sm.h
new file mode 100644
index 000000000000..e26867b4db24
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efc_sm.h
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ *
+ */
+
+/**
+ * Generic state machine framework declarations.
+ */
+
+#ifndef _EFC_SM_H
+#define _EFC_SM_H
+
+struct efc_sm_ctx;
+
+/* State Machine events */
+enum efc_sm_event {
+ /* Common Events */
+ EFC_EVT_ENTER,
+ EFC_EVT_REENTER,
+ EFC_EVT_EXIT,
+ EFC_EVT_SHUTDOWN,
+ EFC_EVT_ALL_CHILD_NODES_FREE,
+ EFC_EVT_RESUME,
+ EFC_EVT_TIMER_EXPIRED,
+
+ /* Domain Events */
+ EFC_EVT_RESPONSE,
+ EFC_EVT_ERROR,
+
+ EFC_EVT_DOMAIN_FOUND,
+ EFC_EVT_DOMAIN_ALLOC_OK,
+ EFC_EVT_DOMAIN_ALLOC_FAIL,
+ EFC_EVT_DOMAIN_REQ_ATTACH,
+ EFC_EVT_DOMAIN_ATTACH_OK,
+ EFC_EVT_DOMAIN_ATTACH_FAIL,
+ EFC_EVT_DOMAIN_LOST,
+ EFC_EVT_DOMAIN_FREE_OK,
+ EFC_EVT_DOMAIN_FREE_FAIL,
+ EFC_EVT_HW_DOMAIN_REQ_ATTACH,
+ EFC_EVT_HW_DOMAIN_REQ_FREE,
+
+ /* Sport Events */
+ EFC_EVT_NPORT_ALLOC_OK,
+ EFC_EVT_NPORT_ALLOC_FAIL,
+ EFC_EVT_NPORT_ATTACH_OK,
+ EFC_EVT_NPORT_ATTACH_FAIL,
+ EFC_EVT_NPORT_FREE_OK,
+ EFC_EVT_NPORT_FREE_FAIL,
+ EFC_EVT_NPORT_TOPOLOGY_NOTIFY,
+ EFC_EVT_HW_PORT_ALLOC_OK,
+ EFC_EVT_HW_PORT_ALLOC_FAIL,
+ EFC_EVT_HW_PORT_ATTACH_OK,
+ EFC_EVT_HW_PORT_REQ_ATTACH,
+ EFC_EVT_HW_PORT_REQ_FREE,
+ EFC_EVT_HW_PORT_FREE_OK,
+
+ /* Login Events */
+ EFC_EVT_SRRS_ELS_REQ_OK,
+ EFC_EVT_SRRS_ELS_CMPL_OK,
+ EFC_EVT_SRRS_ELS_REQ_FAIL,
+ EFC_EVT_SRRS_ELS_CMPL_FAIL,
+ EFC_EVT_SRRS_ELS_REQ_RJT,
+ EFC_EVT_NODE_ATTACH_OK,
+ EFC_EVT_NODE_ATTACH_FAIL,
+ EFC_EVT_NODE_FREE_OK,
+ EFC_EVT_NODE_FREE_FAIL,
+ EFC_EVT_ELS_FRAME,
+ EFC_EVT_ELS_REQ_TIMEOUT,
+ EFC_EVT_ELS_REQ_ABORTED,
+ /* request an ELS IO be aborted */
+ EFC_EVT_ABORT_ELS,
+ /* ELS abort process complete */
+ EFC_EVT_ELS_ABORT_CMPL,
+
+ EFC_EVT_ABTS_RCVD,
+
+ /* node is not in the GID_PT payload */
+ EFC_EVT_NODE_MISSING,
+ /* node is allocated and in the GID_PT payload */
+ EFC_EVT_NODE_REFOUND,
+ /* node shutting down due to PLOGI recvd (implicit logo) */
+ EFC_EVT_SHUTDOWN_IMPLICIT_LOGO,
+ /* node shutting down due to LOGO recvd/sent (explicit logo) */
+ EFC_EVT_SHUTDOWN_EXPLICIT_LOGO,
+
+ EFC_EVT_PLOGI_RCVD,
+ EFC_EVT_FLOGI_RCVD,
+ EFC_EVT_LOGO_RCVD,
+ EFC_EVT_PRLI_RCVD,
+ EFC_EVT_PRLO_RCVD,
+ EFC_EVT_PDISC_RCVD,
+ EFC_EVT_FDISC_RCVD,
+ EFC_EVT_ADISC_RCVD,
+ EFC_EVT_RSCN_RCVD,
+ EFC_EVT_SCR_RCVD,
+ EFC_EVT_ELS_RCVD,
+
+ EFC_EVT_FCP_CMD_RCVD,
+
+ EFC_EVT_GIDPT_DELAY_EXPIRED,
+
+ /* SCSI Target Server events */
+ EFC_EVT_NODE_ACTIVE_IO_LIST_EMPTY,
+ EFC_EVT_NODE_DEL_INI_COMPLETE,
+ EFC_EVT_NODE_DEL_TGT_COMPLETE,
+ EFC_EVT_NODE_SESS_REG_OK,
+ EFC_EVT_NODE_SESS_REG_FAIL,
+
+ /* Must be last */
+ EFC_EVT_LAST
+};
+
+/* State Machine event name lookup array */
+#define EFC_SM_EVENT_NAME { \
+ [EFC_EVT_ENTER] = "EFC_EVT_ENTER", \
+ [EFC_EVT_REENTER] = "EFC_EVT_REENTER", \
+ [EFC_EVT_EXIT] = "EFC_EVT_EXIT", \
+ [EFC_EVT_SHUTDOWN] = "EFC_EVT_SHUTDOWN", \
+ [EFC_EVT_ALL_CHILD_NODES_FREE] = "EFC_EVT_ALL_CHILD_NODES_FREE",\
+ [EFC_EVT_RESUME] = "EFC_EVT_RESUME", \
+ [EFC_EVT_TIMER_EXPIRED] = "EFC_EVT_TIMER_EXPIRED", \
+ [EFC_EVT_RESPONSE] = "EFC_EVT_RESPONSE", \
+ [EFC_EVT_ERROR] = "EFC_EVT_ERROR", \
+ [EFC_EVT_DOMAIN_FOUND] = "EFC_EVT_DOMAIN_FOUND", \
+ [EFC_EVT_DOMAIN_ALLOC_OK] = "EFC_EVT_DOMAIN_ALLOC_OK", \
+ [EFC_EVT_DOMAIN_ALLOC_FAIL] = "EFC_EVT_DOMAIN_ALLOC_FAIL", \
+ [EFC_EVT_DOMAIN_REQ_ATTACH] = "EFC_EVT_DOMAIN_REQ_ATTACH", \
+ [EFC_EVT_DOMAIN_ATTACH_OK] = "EFC_EVT_DOMAIN_ATTACH_OK", \
+ [EFC_EVT_DOMAIN_ATTACH_FAIL] = "EFC_EVT_DOMAIN_ATTACH_FAIL", \
+ [EFC_EVT_DOMAIN_LOST] = "EFC_EVT_DOMAIN_LOST", \
+ [EFC_EVT_DOMAIN_FREE_OK] = "EFC_EVT_DOMAIN_FREE_OK", \
+ [EFC_EVT_DOMAIN_FREE_FAIL] = "EFC_EVT_DOMAIN_FREE_FAIL", \
+ [EFC_EVT_HW_DOMAIN_REQ_ATTACH] = "EFC_EVT_HW_DOMAIN_REQ_ATTACH",\
+ [EFC_EVT_HW_DOMAIN_REQ_FREE] = "EFC_EVT_HW_DOMAIN_REQ_FREE", \
+ [EFC_EVT_NPORT_ALLOC_OK] = "EFC_EVT_NPORT_ALLOC_OK", \
+ [EFC_EVT_NPORT_ALLOC_FAIL] = "EFC_EVT_NPORT_ALLOC_FAIL", \
+ [EFC_EVT_NPORT_ATTACH_OK] = "EFC_EVT_NPORT_ATTACH_OK", \
+ [EFC_EVT_NPORT_ATTACH_FAIL] = "EFC_EVT_NPORT_ATTACH_FAIL", \
+ [EFC_EVT_NPORT_FREE_OK] = "EFC_EVT_NPORT_FREE_OK", \
+ [EFC_EVT_NPORT_FREE_FAIL] = "EFC_EVT_NPORT_FREE_FAIL", \
+ [EFC_EVT_NPORT_TOPOLOGY_NOTIFY] = "EFC_EVT_NPORT_TOPOLOGY_NOTIFY",\
+ [EFC_EVT_HW_PORT_ALLOC_OK] = "EFC_EVT_HW_PORT_ALLOC_OK", \
+ [EFC_EVT_HW_PORT_ALLOC_FAIL] = "EFC_EVT_HW_PORT_ALLOC_FAIL", \
+ [EFC_EVT_HW_PORT_ATTACH_OK] = "EFC_EVT_HW_PORT_ATTACH_OK", \
+ [EFC_EVT_HW_PORT_REQ_ATTACH] = "EFC_EVT_HW_PORT_REQ_ATTACH", \
+ [EFC_EVT_HW_PORT_REQ_FREE] = "EFC_EVT_HW_PORT_REQ_FREE", \
+ [EFC_EVT_HW_PORT_FREE_OK] = "EFC_EVT_HW_PORT_FREE_OK", \
+ [EFC_EVT_SRRS_ELS_REQ_OK] = "EFC_EVT_SRRS_ELS_REQ_OK", \
+ [EFC_EVT_SRRS_ELS_CMPL_OK] = "EFC_EVT_SRRS_ELS_CMPL_OK", \
+ [EFC_EVT_SRRS_ELS_REQ_FAIL] = "EFC_EVT_SRRS_ELS_REQ_FAIL", \
+ [EFC_EVT_SRRS_ELS_CMPL_FAIL] = "EFC_EVT_SRRS_ELS_CMPL_FAIL", \
+ [EFC_EVT_SRRS_ELS_REQ_RJT] = "EFC_EVT_SRRS_ELS_REQ_RJT", \
+ [EFC_EVT_NODE_ATTACH_OK] = "EFC_EVT_NODE_ATTACH_OK", \
+ [EFC_EVT_NODE_ATTACH_FAIL] = "EFC_EVT_NODE_ATTACH_FAIL", \
+ [EFC_EVT_NODE_FREE_OK] = "EFC_EVT_NODE_FREE_OK", \
+ [EFC_EVT_NODE_FREE_FAIL] = "EFC_EVT_NODE_FREE_FAIL", \
+ [EFC_EVT_ELS_FRAME] = "EFC_EVT_ELS_FRAME", \
+ [EFC_EVT_ELS_REQ_TIMEOUT] = "EFC_EVT_ELS_REQ_TIMEOUT", \
+ [EFC_EVT_ELS_REQ_ABORTED] = "EFC_EVT_ELS_REQ_ABORTED", \
+ [EFC_EVT_ABORT_ELS] = "EFC_EVT_ABORT_ELS", \
+ [EFC_EVT_ELS_ABORT_CMPL] = "EFC_EVT_ELS_ABORT_CMPL", \
+ [EFC_EVT_ABTS_RCVD] = "EFC_EVT_ABTS_RCVD", \
+ [EFC_EVT_NODE_MISSING] = "EFC_EVT_NODE_MISSING", \
+ [EFC_EVT_NODE_REFOUND] = "EFC_EVT_NODE_REFOUND", \
+ [EFC_EVT_SHUTDOWN_IMPLICIT_LOGO] = "EFC_EVT_SHUTDOWN_IMPLICIT_LOGO",\
+ [EFC_EVT_SHUTDOWN_EXPLICIT_LOGO] = "EFC_EVT_SHUTDOWN_EXPLICIT_LOGO",\
+ [EFC_EVT_PLOGI_RCVD] = "EFC_EVT_PLOGI_RCVD", \
+ [EFC_EVT_FLOGI_RCVD] = "EFC_EVT_FLOGI_RCVD", \
+ [EFC_EVT_LOGO_RCVD] = "EFC_EVT_LOGO_RCVD", \
+ [EFC_EVT_PRLI_RCVD] = "EFC_EVT_PRLI_RCVD", \
+ [EFC_EVT_PRLO_RCVD] = "EFC_EVT_PRLO_RCVD", \
+ [EFC_EVT_PDISC_RCVD] = "EFC_EVT_PDISC_RCVD", \
+ [EFC_EVT_FDISC_RCVD] = "EFC_EVT_FDISC_RCVD", \
+ [EFC_EVT_ADISC_RCVD] = "EFC_EVT_ADISC_RCVD", \
+ [EFC_EVT_RSCN_RCVD] = "EFC_EVT_RSCN_RCVD", \
+ [EFC_EVT_SCR_RCVD] = "EFC_EVT_SCR_RCVD", \
+ [EFC_EVT_ELS_RCVD] = "EFC_EVT_ELS_RCVD", \
+ [EFC_EVT_FCP_CMD_RCVD] = "EFC_EVT_FCP_CMD_RCVD", \
+ [EFC_EVT_NODE_DEL_INI_COMPLETE] = "EFC_EVT_NODE_DEL_INI_COMPLETE",\
+ [EFC_EVT_NODE_DEL_TGT_COMPLETE] = "EFC_EVT_NODE_DEL_TGT_COMPLETE",\
+ [EFC_EVT_LAST] = "EFC_EVT_LAST", \
+}
+
+int
+efc_sm_post_event(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *data);
+void
+efc_sm_transition(struct efc_sm_ctx *ctx,
+ void (*state)(struct efc_sm_ctx *ctx,
+ enum efc_sm_event evt, void *arg),
+ void *data);
+void efc_sm_disable(struct efc_sm_ctx *ctx);
+const char *efc_sm_event_name(enum efc_sm_event evt);
+
+#endif /* ! _EFC_SM_H */
diff --git a/drivers/scsi/elx/libefc/efclib.c b/drivers/scsi/elx/libefc/efclib.c
new file mode 100644
index 000000000000..dd3e3d0a4761
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efclib.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+/*
+ * LIBEFC LOCKING
+ *
+ * The critical sections protected by the efc's spinlock are quite broad and
+ * may be improved upon in the future. The libefc code and its locking doesn't
+ * influence the I/O path, so excessive locking doesn't impact I/O performance.
+ *
+ * The strategy is to lock whenever processing a request from user driver. This
+ * means that the entry points into the libefc library are protected by efc
+ * lock. So all the state machine transitions are protected.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include "efc.h"
+
+int efcport_init(struct efc *efc)
+{
+ u32 rc = 0;
+
+ spin_lock_init(&efc->lock);
+ INIT_LIST_HEAD(&efc->vport_list);
+ efc->hold_frames = false;
+ spin_lock_init(&efc->pend_frames_lock);
+ INIT_LIST_HEAD(&efc->pend_frames);
+
+ /* Create Node pool */
+ efc->node_pool = mempool_create_kmalloc_pool(EFC_MAX_REMOTE_NODES,
+ sizeof(struct efc_node));
+ if (!efc->node_pool) {
+ efc_log_err(efc, "Can't allocate node pool\n");
+ return -ENOMEM;
+ }
+
+ efc->node_dma_pool = dma_pool_create("node_dma_pool", &efc->pci->dev,
+ NODE_SPARAMS_SIZE, 0, 0);
+ if (!efc->node_dma_pool) {
+ efc_log_err(efc, "Can't allocate node dma pool\n");
+ mempool_destroy(efc->node_pool);
+ return -ENOMEM;
+ }
+
+ efc->els_io_pool = mempool_create_kmalloc_pool(EFC_ELS_IO_POOL_SZ,
+ sizeof(struct efc_els_io_req));
+ if (!efc->els_io_pool) {
+ efc_log_err(efc, "Can't allocate els io pool\n");
+ return -ENOMEM;
+ }
+
+ return rc;
+}
+
+static void
+efc_purge_pending(struct efc *efc)
+{
+ struct efc_hw_sequence *frame, *next;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&efc->pend_frames_lock, flags);
+
+ list_for_each_entry_safe(frame, next, &efc->pend_frames, list_entry) {
+ list_del(&frame->list_entry);
+ efc->tt.hw_seq_free(efc, frame);
+ }
+
+ spin_unlock_irqrestore(&efc->pend_frames_lock, flags);
+}
+
+void efcport_destroy(struct efc *efc)
+{
+ efc_purge_pending(efc);
+ mempool_destroy(efc->els_io_pool);
+ mempool_destroy(efc->node_pool);
+ dma_pool_destroy(efc->node_dma_pool);
+}
diff --git a/drivers/scsi/elx/libefc/efclib.h b/drivers/scsi/elx/libefc/efclib.h
new file mode 100644
index 000000000000..ee291cabf7e0
--- /dev/null
+++ b/drivers/scsi/elx/libefc/efclib.h
@@ -0,0 +1,620 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+#ifndef __EFCLIB_H__
+#define __EFCLIB_H__
+
+#include "scsi/fc/fc_els.h"
+#include "scsi/fc/fc_fs.h"
+#include "scsi/fc/fc_ns.h"
+#include "scsi/fc/fc_gs.h"
+#include "scsi/fc_frame.h"
+#include "../include/efc_common.h"
+#include "../libefc_sli/sli4.h"
+
+#define EFC_SERVICE_PARMS_LENGTH 120
+#define EFC_NAME_LENGTH 32
+#define EFC_SM_NAME_LENGTH 64
+#define EFC_DISPLAY_BUS_INFO_LENGTH 16
+
+#define EFC_WWN_LENGTH 32
+
+#define EFC_FC_ELS_DEFAULT_RETRIES 3
+
+/* Timeouts */
+#define EFC_FC_ELS_SEND_DEFAULT_TIMEOUT 0
+#define EFC_FC_FLOGI_TIMEOUT_SEC 5
+#define EFC_SHUTDOWN_TIMEOUT_USEC 30000000
+
+/* Return values for calls from base driver to libefc */
+#define EFC_SCSI_CALL_COMPLETE 0
+#define EFC_SCSI_CALL_ASYNC 1
+
+/* Local port topology */
+enum efc_nport_topology {
+ EFC_NPORT_TOPO_UNKNOWN = 0,
+ EFC_NPORT_TOPO_FABRIC,
+ EFC_NPORT_TOPO_P2P,
+ EFC_NPORT_TOPO_FC_AL,
+};
+
+#define enable_target_rscn(efc) 1
+
+enum efc_node_shutd_rsn {
+ EFC_NODE_SHUTDOWN_DEFAULT = 0,
+ EFC_NODE_SHUTDOWN_EXPLICIT_LOGO,
+ EFC_NODE_SHUTDOWN_IMPLICIT_LOGO,
+};
+
+enum efc_node_send_ls_acc {
+ EFC_NODE_SEND_LS_ACC_NONE = 0,
+ EFC_NODE_SEND_LS_ACC_PLOGI,
+ EFC_NODE_SEND_LS_ACC_PRLI,
+};
+
+#define EFC_LINK_STATUS_UP 0
+#define EFC_LINK_STATUS_DOWN 1
+
+/* State machine context header */
+struct efc_sm_ctx {
+ void (*current_state)(struct efc_sm_ctx *ctx,
+ u32 evt, void *arg);
+
+ const char *description;
+ void *app;
+};
+
+/* Description of discovered Fabric Domain */
+struct efc_domain_record {
+ u32 index;
+ u32 priority;
+ u8 address[6];
+ u8 wwn[8];
+ union {
+ u8 vlan[512];
+ u8 loop[128];
+ } map;
+ u32 speed;
+ u32 fc_id;
+ bool is_loop;
+ bool is_nport;
+};
+
+/* Domain events */
+enum efc_hw_domain_event {
+ EFC_HW_DOMAIN_ALLOC_OK,
+ EFC_HW_DOMAIN_ALLOC_FAIL,
+ EFC_HW_DOMAIN_ATTACH_OK,
+ EFC_HW_DOMAIN_ATTACH_FAIL,
+ EFC_HW_DOMAIN_FREE_OK,
+ EFC_HW_DOMAIN_FREE_FAIL,
+ EFC_HW_DOMAIN_LOST,
+ EFC_HW_DOMAIN_FOUND,
+ EFC_HW_DOMAIN_CHANGED,
+};
+
+/**
+ * Fibre Channel port object
+ *
+ * @list_entry: nport list entry
+ * @ref: reference count, each node takes a reference
+ * @release: function to free nport object
+ * @efc: pointer back to efc
+ * @instance_index: unique instance index value
+ * @display_name: port display name
+ * @is_vport: Is NPIV port
+ * @free_req_pending: pending request to free resources
+ * @attached: mark attached if reg VPI succeeds
+ * @p2p_winner: TRUE if we're the point-to-point winner
+ * @domain: pointer back to domain
+ * @wwpn: port wwpn
+ * @wwnn: port wwnn
+ * @tgt_data: target backend private port data
+ * @ini_data: initiator backend private port data
+ * @indicator: VPI
+ * @fc_id: port FC address
+ * @dma: memory for Service Parameters
+ * @wwnn_str: wwpn string
+ * @sli_wwpn: SLI provided wwpn
+ * @sli_wwnn: SLI provided wwnn
+ * @sm: nport state machine context
+ * @lookup: fc_id to node lookup object
+ * @enable_ini: SCSI initiator enabled for this port
+ * @enable_tgt: SCSI target enabled for this port
+ * @enable_rscn: port will be expecting RSCN
+ * @shutting_down: nport in process of shutting down
+ * @p2p_port_id: our port id for point-to-point
+ * @topology: topology: fabric/p2p/unknown
+ * @service_params: login parameters
+ * @p2p_remote_port_id: remote node's port id for point-to-point
+ */
+
+struct efc_nport {
+ struct list_head list_entry;
+ struct kref ref;
+ void (*release)(struct kref *arg);
+ struct efc *efc;
+ u32 instance_index;
+ char display_name[EFC_NAME_LENGTH];
+ bool is_vport;
+ bool free_req_pending;
+ bool attached;
+ bool p2p_winner;
+ struct efc_domain *domain;
+ u64 wwpn;
+ u64 wwnn;
+ void *tgt_data;
+ void *ini_data;
+
+ u32 indicator;
+ u32 fc_id;
+ struct efc_dma dma;
+
+ u8 wwnn_str[EFC_WWN_LENGTH];
+ __be64 sli_wwpn;
+ __be64 sli_wwnn;
+
+ struct efc_sm_ctx sm;
+ struct xarray lookup;
+ bool enable_ini;
+ bool enable_tgt;
+ bool enable_rscn;
+ bool shutting_down;
+ u32 p2p_port_id;
+ enum efc_nport_topology topology;
+ u8 service_params[EFC_SERVICE_PARMS_LENGTH];
+ u32 p2p_remote_port_id;
+};
+
+/**
+ * Fibre Channel domain object
+ *
+ * This object is a container for the various SLI components needed
+ * to connect to the domain of a FC or FCoE switch
+ * @efc: pointer back to efc
+ * @instance_index: unique instance index value
+ * @display_name: Node display name
+ * @nport_list: linked list of nports associated with this domain
+ * @ref: Reference count, each nport takes a reference
+ * @release: Function to free domain object
+ * @ini_domain: initiator backend private domain data
+ * @tgt_domain: target backend private domain data
+ * @sm: state machine context
+ * @fcf: FC Forwarder table index
+ * @fcf_indicator: FCFI
+ * @indicator: VFI
+ * @nport_count: Number of nports allocated
+ * @dma: memory for Service Parameters
+ * @fcf_wwn: WWN for FCF/switch
+ * @drvsm: driver domain sm context
+ * @attached: set true after attach completes
+ * @is_fc: is FC
+ * @is_loop: is loop topology
+ * @is_nlport: is public loop
+ * @domain_found_pending:A domain found is pending, drec is updated
+ * @req_domain_free: True if domain object should be free'd
+ * @req_accept_frames: set in domain state machine to enable frames
+ * @domain_notify_pend: Set in domain SM to avoid duplicate node event post
+ * @pending_drec: Pending drec if a domain found is pending
+ * @service_params: any nports service parameters
+ * @flogi_service_params:Fabric/P2p service parameters from FLOGI
+ * @lookup: d_id to node lookup object
+ * @nport: Pointer to first (physical) SLI port
+ */
+struct efc_domain {
+ struct efc *efc;
+ char display_name[EFC_NAME_LENGTH];
+ struct list_head nport_list;
+ struct kref ref;
+ void (*release)(struct kref *arg);
+ void *ini_domain;
+ void *tgt_domain;
+
+ /* Declarations private to HW/SLI */
+ u32 fcf;
+ u32 fcf_indicator;
+ u32 indicator;
+ u32 nport_count;
+ struct efc_dma dma;
+
+ /* Declarations private to FC trannport */
+ u64 fcf_wwn;
+ struct efc_sm_ctx drvsm;
+ bool attached;
+ bool is_fc;
+ bool is_loop;
+ bool is_nlport;
+ bool domain_found_pending;
+ bool req_domain_free;
+ bool req_accept_frames;
+ bool domain_notify_pend;
+
+ struct efc_domain_record pending_drec;
+ u8 service_params[EFC_SERVICE_PARMS_LENGTH];
+ u8 flogi_service_params[EFC_SERVICE_PARMS_LENGTH];
+
+ struct xarray lookup;
+
+ struct efc_nport *nport;
+};
+
+/**
+ * Remote Node object
+ *
+ * This object represents a connection between the SLI port and another
+ * Nx_Port on the fabric. Note this can be either a well known port such
+ * as a F_Port (i.e. ff:ff:fe) or another N_Port.
+ * @indicator: RPI
+ * @fc_id: FC address
+ * @attached: true if attached
+ * @nport: associated SLI port
+ * @node: associated node
+ */
+struct efc_remote_node {
+ u32 indicator;
+ u32 index;
+ u32 fc_id;
+
+ bool attached;
+
+ struct efc_nport *nport;
+ void *node;
+};
+
+/**
+ * FC Node object
+ * @efc: pointer back to efc structure
+ * @display_name: Node display name
+ * @nort: Assosiated nport pointer.
+ * @hold_frames: hold incoming frames if true
+ * @els_io_enabled: Enable allocating els ios for this node
+ * @els_ios_lock: lock to protect the els ios list
+ * @els_ios_list: ELS I/O's for this node
+ * @ini_node: backend initiator private node data
+ * @tgt_node: backend target private node data
+ * @rnode: Remote node
+ * @sm: state machine context
+ * @evtdepth: current event posting nesting depth
+ * @req_free: this node is to be free'd
+ * @attached: node is attached (REGLOGIN complete)
+ * @fcp_enabled: node is enabled to handle FCP
+ * @rscn_pending: for name server node RSCN is pending
+ * @send_plogi: send PLOGI accept, upon completion of node attach
+ * @send_plogi_acc: TRUE if io_alloc() is enabled.
+ * @send_ls_acc: type of LS acc to send
+ * @ls_acc_io: SCSI IO for LS acc
+ * @ls_acc_oxid: OX_ID for pending accept
+ * @ls_acc_did: D_ID for pending accept
+ * @shutdown_reason: reason for node shutdown
+ * @sparm_dma_buf: service parameters buffer
+ * @service_params: plogi/acc frame from remote device
+ * @pend_frames_lock: lock for inbound pending frames list
+ * @pend_frames: inbound pending frames list
+ * @pend_frames_processed:count of frames processed in hold frames interval
+ * @ox_id_in_use: used to verify one at a time us of ox_id
+ * @els_retries_remaining:for ELS, number of retries remaining
+ * @els_req_cnt: number of outstanding ELS requests
+ * @els_cmpl_cnt: number of outstanding ELS completions
+ * @abort_cnt: Abort counter for debugging purpos
+ * @current_state_name: current node state
+ * @prev_state_name: previous node state
+ * @current_evt: current event
+ * @prev_evt: previous event
+ * @targ: node is target capable
+ * @init: node is init capable
+ * @refound: Handle node refound case when node is being deleted
+ * @els_io_pend_list: list of pending (not yet processed) ELS IOs
+ * @els_io_active_list: list of active (processed) ELS IOs
+ * @nodedb_state: Node debugging, saved state
+ * @gidpt_delay_timer: GIDPT delay timer
+ * @time_last_gidpt_msec:Start time of last target RSCN GIDPT
+ * @wwnn: remote port WWNN
+ * @wwpn: remote port WWPN
+ */
+struct efc_node {
+ struct efc *efc;
+ char display_name[EFC_NAME_LENGTH];
+ struct efc_nport *nport;
+ struct kref ref;
+ void (*release)(struct kref *arg);
+ bool hold_frames;
+ bool els_io_enabled;
+ bool send_plogi_acc;
+ bool send_plogi;
+ bool rscn_pending;
+ bool fcp_enabled;
+ bool attached;
+ bool req_free;
+
+ spinlock_t els_ios_lock;
+ struct list_head els_ios_list;
+ void *ini_node;
+ void *tgt_node;
+
+ struct efc_remote_node rnode;
+ /* Declarations private to FC trannport */
+ struct efc_sm_ctx sm;
+ u32 evtdepth;
+
+ enum efc_node_send_ls_acc send_ls_acc;
+ void *ls_acc_io;
+ u32 ls_acc_oxid;
+ u32 ls_acc_did;
+ enum efc_node_shutd_rsn shutdown_reason;
+ bool targ;
+ bool init;
+ bool refound;
+ struct efc_dma sparm_dma_buf;
+ u8 service_params[EFC_SERVICE_PARMS_LENGTH];
+ spinlock_t pend_frames_lock;
+ struct list_head pend_frames;
+ u32 pend_frames_processed;
+ u32 ox_id_in_use;
+ u32 els_retries_remaining;
+ u32 els_req_cnt;
+ u32 els_cmpl_cnt;
+ u32 abort_cnt;
+
+ char current_state_name[EFC_SM_NAME_LENGTH];
+ char prev_state_name[EFC_SM_NAME_LENGTH];
+ int current_evt;
+ int prev_evt;
+
+ void (*nodedb_state)(struct efc_sm_ctx *ctx,
+ u32 evt, void *arg);
+ struct timer_list gidpt_delay_timer;
+ u64 time_last_gidpt_msec;
+
+ char wwnn[EFC_WWN_LENGTH];
+ char wwpn[EFC_WWN_LENGTH];
+};
+
+/**
+ * NPIV port
+ *
+ * Collection of the information required to restore a virtual port across
+ * link events
+ * @wwnn: node name
+ * @wwpn: port name
+ * @fc_id: port id
+ * @tgt_data: target backend pointer
+ * @ini_data: initiator backend pointe
+ * @nport: Used to match record after attaching for update
+ *
+ */
+
+struct efc_vport {
+ struct list_head list_entry;
+ u64 wwnn;
+ u64 wwpn;
+ u32 fc_id;
+ bool enable_tgt;
+ bool enable_ini;
+ void *tgt_data;
+ void *ini_data;
+ struct efc_nport *nport;
+};
+
+#define node_printf(node, fmt, args...) \
+ efc_log_info(node->efc, "[%s] " fmt, node->display_name, ##args)
+
+/* Node SM IO Context Callback structure */
+struct efc_node_cb {
+ int status;
+ int ext_status;
+ struct efc_hw_rq_buffer *header;
+ struct efc_hw_rq_buffer *payload;
+ struct efc_dma els_rsp;
+
+ /* Actual length of data received */
+ int rsp_len;
+};
+
+struct efc_hw_rq_buffer {
+ u16 rqindex;
+ struct efc_dma dma;
+};
+
+/**
+ * FC sequence object
+ *
+ * Defines a general FC sequence object
+ * @hw: HW that owns this sequence
+ * @fcfi: FCFI associated with sequence
+ * @header: Received frame header
+ * @payload: Received frame header
+ * @hw_priv: HW private context
+ */
+struct efc_hw_sequence {
+ struct list_head list_entry;
+ void *hw;
+ u8 fcfi;
+ struct efc_hw_rq_buffer *header;
+ struct efc_hw_rq_buffer *payload;
+ void *hw_priv;
+};
+
+enum efc_disc_io_type {
+ EFC_DISC_IO_ELS_REQ,
+ EFC_DISC_IO_ELS_RESP,
+ EFC_DISC_IO_CT_REQ,
+ EFC_DISC_IO_CT_RESP
+};
+
+struct efc_io_els_params {
+ u32 s_id;
+ u16 ox_id;
+ u8 timeout;
+};
+
+struct efc_io_ct_params {
+ u8 r_ctl;
+ u8 type;
+ u8 df_ctl;
+ u8 timeout;
+ u16 ox_id;
+};
+
+union efc_disc_io_param {
+ struct efc_io_els_params els;
+ struct efc_io_ct_params ct;
+};
+
+struct efc_disc_io {
+ struct efc_dma req; /* send buffer */
+ struct efc_dma rsp; /* receive buffer */
+ enum efc_disc_io_type io_type; /* EFC_DISC_IO_TYPE enum*/
+ u16 xmit_len; /* Length of els request*/
+ u16 rsp_len; /* Max length of rsps to be rcvd */
+ u32 rpi; /* Registered RPI */
+ u32 vpi; /* VPI for this nport */
+ u32 s_id;
+ u32 d_id;
+ bool rpi_registered; /* if false, use tmp RPI */
+ union efc_disc_io_param iparam;
+};
+
+/* Return value indiacating the sequence can not be freed */
+#define EFC_HW_SEQ_HOLD 0
+/* Return value indiacating the sequence can be freed */
+#define EFC_HW_SEQ_FREE 1
+
+struct libefc_function_template {
+ /*Sport*/
+ int (*new_nport)(struct efc *efc, struct efc_nport *sp);
+ void (*del_nport)(struct efc *efc, struct efc_nport *sp);
+
+ /*Scsi Node*/
+ int (*scsi_new_node)(struct efc *efc, struct efc_node *n);
+ int (*scsi_del_node)(struct efc *efc, struct efc_node *n, int reason);
+
+ int (*issue_mbox_rqst)(void *efct, void *buf, void *cb, void *arg);
+ /*Send ELS IO*/
+ int (*send_els)(struct efc *efc, struct efc_disc_io *io);
+ /*Send BLS IO*/
+ int (*send_bls)(struct efc *efc, u32 type, struct sli_bls_params *bls);
+ /*Free HW frame*/
+ int (*hw_seq_free)(struct efc *efc, struct efc_hw_sequence *seq);
+};
+
+#define EFC_LOG_LIB 0x01
+#define EFC_LOG_NODE 0x02
+#define EFC_LOG_PORT 0x04
+#define EFC_LOG_DOMAIN 0x08
+#define EFC_LOG_ELS 0x10
+#define EFC_LOG_DOMAIN_SM 0x20
+#define EFC_LOG_SM 0x40
+
+/* efc library port structure */
+struct efc {
+ void *base;
+ struct pci_dev *pci;
+ struct sli4 *sli;
+ u32 fcfi;
+ u64 req_wwpn;
+ u64 req_wwnn;
+
+ u64 def_wwpn;
+ u64 def_wwnn;
+ u64 max_xfer_size;
+ mempool_t *node_pool;
+ struct dma_pool *node_dma_pool;
+ u32 nodes_count;
+
+ u32 link_status;
+
+ struct list_head vport_list;
+ /* lock to protect the vport list */
+ spinlock_t vport_lock;
+
+ struct libefc_function_template tt;
+ /* lock to protect the discovery library.
+ * Refer to efclib.c for more details.
+ */
+ spinlock_t lock;
+
+ bool enable_ini;
+ bool enable_tgt;
+
+ u32 log_level;
+
+ struct efc_domain *domain;
+ void (*domain_free_cb)(struct efc *efc, void *arg);
+ void *domain_free_cb_arg;
+
+ u64 tgt_rscn_delay_msec;
+ u64 tgt_rscn_period_msec;
+
+ bool external_loopback;
+ u32 nodedb_mask;
+ u32 logmask;
+ mempool_t *els_io_pool;
+ atomic_t els_io_alloc_failed_count;
+
+ /* hold pending frames */
+ bool hold_frames;
+ /* lock to protect pending frames list access */
+ spinlock_t pend_frames_lock;
+ struct list_head pend_frames;
+ /* count of pending frames that were processed */
+ u32 pend_frames_processed;
+
+};
+
+/*
+ * EFC library registration
+ * **********************************/
+int efcport_init(struct efc *efc);
+void efcport_destroy(struct efc *efc);
+/*
+ * EFC Domain
+ * **********************************/
+int efc_domain_cb(void *arg, int event, void *data);
+void
+efc_register_domain_free_cb(struct efc *efc,
+ void (*callback)(struct efc *efc, void *arg),
+ void *arg);
+
+/*
+ * EFC nport
+ * **********************************/
+void efc_nport_cb(void *arg, int event, void *data);
+struct efc_vport *
+efc_vport_create_spec(struct efc *efc, u64 wwnn, u64 wwpn, u32 fc_id,
+ bool enable_ini, bool enable_tgt,
+ void *tgt_data, void *ini_data);
+int efc_nport_vport_new(struct efc_domain *domain, u64 wwpn,
+ u64 wwnn, u32 fc_id, bool ini, bool tgt,
+ void *tgt_data, void *ini_data);
+int efc_nport_vport_del(struct efc *efc, struct efc_domain *domain,
+ u64 wwpn, u64 wwnn);
+
+void efc_vport_del_all(struct efc *efc);
+
+/*
+ * EFC Node
+ * **********************************/
+int efc_remote_node_cb(void *arg, int event, void *data);
+void efc_node_fcid_display(u32 fc_id, char *buffer, u32 buf_len);
+void efc_node_post_shutdown(struct efc_node *node, void *arg);
+u64 efc_node_get_wwpn(struct efc_node *node);
+
+/*
+ * EFC FCP/ELS/CT interface
+ * **********************************/
+void efc_dispatch_frame(struct efc *efc, struct efc_hw_sequence *seq);
+void efc_disc_io_complete(struct efc_disc_io *io, u32 len, u32 status,
+ u32 ext_status);
+
+/*
+ * EFC SCSI INTERACTION LAYER
+ * **********************************/
+void efc_scsi_sess_reg_complete(struct efc_node *node, u32 status);
+void efc_scsi_del_initiator_complete(struct efc *efc, struct efc_node *node);
+void efc_scsi_del_target_complete(struct efc *efc, struct efc_node *node);
+void efc_scsi_io_list_empty(struct efc *efc, struct efc_node *node);
+
+#endif /* __EFCLIB_H__ */
diff --git a/drivers/scsi/elx/libefc_sli/sli4.c b/drivers/scsi/elx/libefc_sli/sli4.c
new file mode 100644
index 000000000000..6c6c04e1b74d
--- /dev/null
+++ b/drivers/scsi/elx/libefc_sli/sli4.c
@@ -0,0 +1,5160 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ */
+
+/**
+ * All common (i.e. transport-independent) SLI-4 functions are implemented
+ * in this file.
+ */
+#include "sli4.h"
+
+static struct sli4_asic_entry_t sli4_asic_table[] = {
+ { SLI4_ASIC_REV_B0, SLI4_ASIC_GEN_5},
+ { SLI4_ASIC_REV_D0, SLI4_ASIC_GEN_5},
+ { SLI4_ASIC_REV_A3, SLI4_ASIC_GEN_6},
+ { SLI4_ASIC_REV_A0, SLI4_ASIC_GEN_6},
+ { SLI4_ASIC_REV_A1, SLI4_ASIC_GEN_6},
+ { SLI4_ASIC_REV_A3, SLI4_ASIC_GEN_6},
+ { SLI4_ASIC_REV_A1, SLI4_ASIC_GEN_7},
+ { SLI4_ASIC_REV_A0, SLI4_ASIC_GEN_7},
+};
+
+/* Convert queue type enum (SLI_QTYPE_*) into a string */
+static char *SLI4_QNAME[] = {
+ "Event Queue",
+ "Completion Queue",
+ "Mailbox Queue",
+ "Work Queue",
+ "Receive Queue",
+ "Undefined"
+};
+
+/**
+ * sli_config_cmd_init() - Write a SLI_CONFIG command to the provided buffer.
+ *
+ * @sli4: SLI context pointer.
+ * @buf: Destination buffer for the command.
+ * @length: Length in bytes of attached command.
+ * @dma: DMA buffer for non-embedded commands.
+ * Return: Command payload buffer.
+ */
+static void *
+sli_config_cmd_init(struct sli4 *sli4, void *buf, u32 length,
+ struct efc_dma *dma)
+{
+ struct sli4_cmd_sli_config *config;
+ u32 flags;
+
+ if (length > sizeof(config->payload.embed) && !dma) {
+ efc_log_err(sli4, "Too big for an embedded cmd with len(%d)\n",
+ length);
+ return NULL;
+ }
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ config = buf;
+
+ config->hdr.command = SLI4_MBX_CMD_SLI_CONFIG;
+ if (!dma) {
+ flags = SLI4_SLICONF_EMB;
+ config->dw1_flags = cpu_to_le32(flags);
+ config->payload_len = cpu_to_le32(length);
+ return config->payload.embed;
+ }
+
+ flags = SLI4_SLICONF_PMDCMD_VAL_1;
+ flags &= ~SLI4_SLICONF_EMB;
+ config->dw1_flags = cpu_to_le32(flags);
+
+ config->payload.mem.addr.low = cpu_to_le32(lower_32_bits(dma->phys));
+ config->payload.mem.addr.high = cpu_to_le32(upper_32_bits(dma->phys));
+ config->payload.mem.length =
+ cpu_to_le32(dma->size & SLI4_SLICONF_PMD_LEN);
+ config->payload_len = cpu_to_le32(dma->size);
+ /* save pointer to DMA for BMBX dumping purposes */
+ sli4->bmbx_non_emb_pmd = dma;
+ return dma->virt;
+}
+
+/**
+ * sli_cmd_common_create_cq() - Write a COMMON_CREATE_CQ V2 command.
+ *
+ * @sli4: SLI context pointer.
+ * @buf: Destination buffer for the command.
+ * @qmem: DMA memory for queue.
+ * @eq_id: EQ id assosiated with this cq.
+ * Return: status -EIO/0.
+ */
+static int
+sli_cmd_common_create_cq(struct sli4 *sli4, void *buf, struct efc_dma *qmem,
+ u16 eq_id)
+{
+ struct sli4_rqst_cmn_create_cq_v2 *cqv2 = NULL;
+ u32 p;
+ uintptr_t addr;
+ u32 num_pages = 0;
+ size_t cmd_size = 0;
+ u32 page_size = 0;
+ u32 n_cqe = 0;
+ u32 dw5_flags = 0;
+ u16 dw6w1_arm = 0;
+ __le32 len;
+
+ /* First calculate number of pages and the mailbox cmd length */
+ n_cqe = qmem->size / SLI4_CQE_BYTES;
+ switch (n_cqe) {
+ case 256:
+ case 512:
+ case 1024:
+ case 2048:
+ page_size = SZ_4K;
+ break;
+ case 4096:
+ page_size = SZ_8K;
+ break;
+ default:
+ return -EIO;
+ }
+ num_pages = sli_page_count(qmem->size, page_size);
+
+ cmd_size = SLI4_RQST_CMDSZ(cmn_create_cq_v2)
+ + SZ_DMAADDR * num_pages;
+
+ cqv2 = sli_config_cmd_init(sli4, buf, cmd_size, NULL);
+ if (!cqv2)
+ return -EIO;
+
+ len = SLI4_RQST_PYLD_LEN_VAR(cmn_create_cq_v2, SZ_DMAADDR * num_pages);
+ sli_cmd_fill_hdr(&cqv2->hdr, SLI4_CMN_CREATE_CQ, SLI4_SUBSYSTEM_COMMON,
+ CMD_V2, len);
+ cqv2->page_size = page_size / SLI_PAGE_SIZE;
+
+ /* valid values for number of pages: 1, 2, 4, 8 (sec 4.4.3) */
+ cqv2->num_pages = cpu_to_le16(num_pages);
+ if (!num_pages || num_pages > SLI4_CREATE_CQV2_MAX_PAGES)
+ return -EIO;
+
+ switch (num_pages) {
+ case 1:
+ dw5_flags |= SLI4_CQ_CNT_VAL(256);
+ break;
+ case 2:
+ dw5_flags |= SLI4_CQ_CNT_VAL(512);
+ break;
+ case 4:
+ dw5_flags |= SLI4_CQ_CNT_VAL(1024);
+ break;
+ case 8:
+ dw5_flags |= SLI4_CQ_CNT_VAL(LARGE);
+ cqv2->cqe_count = cpu_to_le16(n_cqe);
+ break;
+ default:
+ efc_log_err(sli4, "num_pages %d not valid\n", num_pages);
+ return -EIO;
+ }
+
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ dw5_flags |= SLI4_CREATE_CQV2_AUTOVALID;
+
+ dw5_flags |= SLI4_CREATE_CQV2_EVT;
+ dw5_flags |= SLI4_CREATE_CQV2_VALID;
+
+ cqv2->dw5_flags = cpu_to_le32(dw5_flags);
+ cqv2->dw6w1_arm = cpu_to_le16(dw6w1_arm);
+ cqv2->eq_id = cpu_to_le16(eq_id);
+
+ for (p = 0, addr = qmem->phys; p < num_pages; p++, addr += page_size) {
+ cqv2->page_phys_addr[p].low = cpu_to_le32(lower_32_bits(addr));
+ cqv2->page_phys_addr[p].high = cpu_to_le32(upper_32_bits(addr));
+ }
+
+ return 0;
+}
+
+static int
+sli_cmd_common_create_eq(struct sli4 *sli4, void *buf, struct efc_dma *qmem)
+{
+ struct sli4_rqst_cmn_create_eq *eq;
+ u32 p;
+ uintptr_t addr;
+ u16 num_pages;
+ u32 dw5_flags = 0;
+ u32 dw6_flags = 0, ver;
+
+ eq = sli_config_cmd_init(sli4, buf, SLI4_CFG_PYLD_LENGTH(cmn_create_eq),
+ NULL);
+ if (!eq)
+ return -EIO;
+
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ ver = CMD_V2;
+ else
+ ver = CMD_V0;
+
+ sli_cmd_fill_hdr(&eq->hdr, SLI4_CMN_CREATE_EQ, SLI4_SUBSYSTEM_COMMON,
+ ver, SLI4_RQST_PYLD_LEN(cmn_create_eq));
+
+ /* valid values for number of pages: 1, 2, 4 (sec 4.4.3) */
+ num_pages = qmem->size / SLI_PAGE_SIZE;
+ eq->num_pages = cpu_to_le16(num_pages);
+
+ switch (num_pages) {
+ case 1:
+ dw5_flags |= SLI4_EQE_SIZE_4;
+ dw6_flags |= SLI4_EQ_CNT_VAL(1024);
+ break;
+ case 2:
+ dw5_flags |= SLI4_EQE_SIZE_4;
+ dw6_flags |= SLI4_EQ_CNT_VAL(2048);
+ break;
+ case 4:
+ dw5_flags |= SLI4_EQE_SIZE_4;
+ dw6_flags |= SLI4_EQ_CNT_VAL(4096);
+ break;
+ default:
+ efc_log_err(sli4, "num_pages %d not valid\n", num_pages);
+ return -EIO;
+ }
+
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ dw5_flags |= SLI4_CREATE_EQ_AUTOVALID;
+
+ dw5_flags |= SLI4_CREATE_EQ_VALID;
+ dw6_flags &= (~SLI4_CREATE_EQ_ARM);
+ eq->dw5_flags = cpu_to_le32(dw5_flags);
+ eq->dw6_flags = cpu_to_le32(dw6_flags);
+ eq->dw7_delaymulti = cpu_to_le32(SLI4_CREATE_EQ_DELAYMULTI);
+
+ for (p = 0, addr = qmem->phys; p < num_pages;
+ p++, addr += SLI_PAGE_SIZE) {
+ eq->page_address[p].low = cpu_to_le32(lower_32_bits(addr));
+ eq->page_address[p].high = cpu_to_le32(upper_32_bits(addr));
+ }
+
+ return 0;
+}
+
+static int
+sli_cmd_common_create_mq_ext(struct sli4 *sli4, void *buf, struct efc_dma *qmem,
+ u16 cq_id)
+{
+ struct sli4_rqst_cmn_create_mq_ext *mq;
+ u32 p;
+ uintptr_t addr;
+ u32 num_pages;
+ u16 dw6w1_flags = 0;
+
+ mq = sli_config_cmd_init(sli4, buf,
+ SLI4_CFG_PYLD_LENGTH(cmn_create_mq_ext), NULL);
+ if (!mq)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&mq->hdr, SLI4_CMN_CREATE_MQ_EXT,
+ SLI4_SUBSYSTEM_COMMON, CMD_V0,
+ SLI4_RQST_PYLD_LEN(cmn_create_mq_ext));
+
+ /* valid values for number of pages: 1, 2, 4, 8 (sec 4.4.12) */
+ num_pages = qmem->size / SLI_PAGE_SIZE;
+ mq->num_pages = cpu_to_le16(num_pages);
+ switch (num_pages) {
+ case 1:
+ dw6w1_flags |= SLI4_MQE_SIZE_16;
+ break;
+ case 2:
+ dw6w1_flags |= SLI4_MQE_SIZE_32;
+ break;
+ case 4:
+ dw6w1_flags |= SLI4_MQE_SIZE_64;
+ break;
+ case 8:
+ dw6w1_flags |= SLI4_MQE_SIZE_128;
+ break;
+ default:
+ efc_log_info(sli4, "num_pages %d not valid\n", num_pages);
+ return -EIO;
+ }
+
+ mq->async_event_bitmap = cpu_to_le32(SLI4_ASYNC_EVT_FC_ALL);
+
+ if (sli4->params.mq_create_version) {
+ mq->cq_id_v1 = cpu_to_le16(cq_id);
+ mq->hdr.dw3_version = cpu_to_le32(CMD_V1);
+ } else {
+ dw6w1_flags |= (cq_id << SLI4_CREATE_MQEXT_CQID_SHIFT);
+ }
+ mq->dw7_val = cpu_to_le32(SLI4_CREATE_MQEXT_VAL);
+
+ mq->dw6w1_flags = cpu_to_le16(dw6w1_flags);
+ for (p = 0, addr = qmem->phys; p < num_pages;
+ p++, addr += SLI_PAGE_SIZE) {
+ mq->page_phys_addr[p].low = cpu_to_le32(lower_32_bits(addr));
+ mq->page_phys_addr[p].high = cpu_to_le32(upper_32_bits(addr));
+ }
+
+ return 0;
+}
+
+int
+sli_cmd_wq_create(struct sli4 *sli4, void *buf, struct efc_dma *qmem, u16 cq_id)
+{
+ struct sli4_rqst_wq_create *wq;
+ u32 p;
+ uintptr_t addr;
+ u32 page_size = 0;
+ u32 n_wqe = 0;
+ u16 num_pages;
+
+ wq = sli_config_cmd_init(sli4, buf, SLI4_CFG_PYLD_LENGTH(wq_create),
+ NULL);
+ if (!wq)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&wq->hdr, SLI4_OPC_WQ_CREATE, SLI4_SUBSYSTEM_FC,
+ CMD_V1, SLI4_RQST_PYLD_LEN(wq_create));
+ n_wqe = qmem->size / sli4->wqe_size;
+
+ switch (qmem->size) {
+ case 4096:
+ case 8192:
+ case 16384:
+ case 32768:
+ page_size = SZ_4K;
+ break;
+ case 65536:
+ page_size = SZ_8K;
+ break;
+ case 131072:
+ page_size = SZ_16K;
+ break;
+ case 262144:
+ page_size = SZ_32K;
+ break;
+ case 524288:
+ page_size = SZ_64K;
+ break;
+ default:
+ return -EIO;
+ }
+
+ /* valid values for number of pages(num_pages): 1-8 */
+ num_pages = sli_page_count(qmem->size, page_size);
+ wq->num_pages = cpu_to_le16(num_pages);
+ if (!num_pages || num_pages > SLI4_WQ_CREATE_MAX_PAGES)
+ return -EIO;
+
+ wq->cq_id = cpu_to_le16(cq_id);
+
+ wq->page_size = page_size / SLI_PAGE_SIZE;
+
+ if (sli4->wqe_size == SLI4_WQE_EXT_BYTES)
+ wq->wqe_size_byte |= SLI4_WQE_EXT_SIZE;
+ else
+ wq->wqe_size_byte |= SLI4_WQE_SIZE;
+
+ wq->wqe_count = cpu_to_le16(n_wqe);
+
+ for (p = 0, addr = qmem->phys; p < num_pages; p++, addr += page_size) {
+ wq->page_phys_addr[p].low = cpu_to_le32(lower_32_bits(addr));
+ wq->page_phys_addr[p].high = cpu_to_le32(upper_32_bits(addr));
+ }
+
+ return 0;
+}
+
+static int
+sli_cmd_rq_create_v1(struct sli4 *sli4, void *buf, struct efc_dma *qmem,
+ u16 cq_id, u16 buffer_size)
+{
+ struct sli4_rqst_rq_create_v1 *rq;
+ u32 p;
+ uintptr_t addr;
+ u32 num_pages;
+
+ rq = sli_config_cmd_init(sli4, buf, SLI4_CFG_PYLD_LENGTH(rq_create_v1),
+ NULL);
+ if (!rq)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&rq->hdr, SLI4_OPC_RQ_CREATE, SLI4_SUBSYSTEM_FC,
+ CMD_V1, SLI4_RQST_PYLD_LEN(rq_create_v1));
+ /* Disable "no buffer warnings" to avoid Lancer bug */
+ rq->dim_dfd_dnb |= SLI4_RQ_CREATE_V1_DNB;
+
+ /* valid values for number of pages: 1-8 (sec 4.5.6) */
+ num_pages = sli_page_count(qmem->size, SLI_PAGE_SIZE);
+ rq->num_pages = cpu_to_le16(num_pages);
+ if (!num_pages ||
+ num_pages > SLI4_RQ_CREATE_V1_MAX_PAGES) {
+ efc_log_info(sli4, "num_pages %d not valid, max %d\n",
+ num_pages, SLI4_RQ_CREATE_V1_MAX_PAGES);
+ return -EIO;
+ }
+
+ /*
+ * RQE count is the total number of entries (note not lg2(# entries))
+ */
+ rq->rqe_count = cpu_to_le16(qmem->size / SLI4_RQE_SIZE);
+
+ rq->rqe_size_byte |= SLI4_RQE_SIZE_8;
+
+ rq->page_size = SLI4_RQ_PAGE_SIZE_4096;
+
+ if (buffer_size < sli4->rq_min_buf_size ||
+ buffer_size > sli4->rq_max_buf_size) {
+ efc_log_err(sli4, "buffer_size %d out of range (%d-%d)\n",
+ buffer_size, sli4->rq_min_buf_size,
+ sli4->rq_max_buf_size);
+ return -EIO;
+ }
+ rq->buffer_size = cpu_to_le32(buffer_size);
+
+ rq->cq_id = cpu_to_le16(cq_id);
+
+ for (p = 0, addr = qmem->phys;
+ p < num_pages;
+ p++, addr += SLI_PAGE_SIZE) {
+ rq->page_phys_addr[p].low = cpu_to_le32(lower_32_bits(addr));
+ rq->page_phys_addr[p].high = cpu_to_le32(upper_32_bits(addr));
+ }
+
+ return 0;
+}
+
+static int
+sli_cmd_rq_create_v2(struct sli4 *sli4, u32 num_rqs,
+ struct sli4_queue *qs[], u32 base_cq_id,
+ u32 header_buffer_size,
+ u32 payload_buffer_size, struct efc_dma *dma)
+{
+ struct sli4_rqst_rq_create_v2 *req = NULL;
+ u32 i, p, offset = 0;
+ u32 payload_size, page_count;
+ uintptr_t addr;
+ u32 num_pages;
+ __le32 len;
+
+ page_count = sli_page_count(qs[0]->dma.size, SLI_PAGE_SIZE) * num_rqs;
+
+ /* Payload length must accommodate both request and response */
+ payload_size = max(SLI4_RQST_CMDSZ(rq_create_v2) +
+ SZ_DMAADDR * page_count,
+ sizeof(struct sli4_rsp_cmn_create_queue_set));
+
+ dma->size = payload_size;
+ dma->virt = dma_alloc_coherent(&sli4->pci->dev, dma->size,
+ &dma->phys, GFP_DMA);
+ if (!dma->virt)
+ return -EIO;
+
+ memset(dma->virt, 0, payload_size);
+
+ req = sli_config_cmd_init(sli4, sli4->bmbx.virt, payload_size, dma);
+ if (!req)
+ return -EIO;
+
+ len = SLI4_RQST_PYLD_LEN_VAR(rq_create_v2, SZ_DMAADDR * page_count);
+ sli_cmd_fill_hdr(&req->hdr, SLI4_OPC_RQ_CREATE, SLI4_SUBSYSTEM_FC,
+ CMD_V2, len);
+ /* Fill Payload fields */
+ req->dim_dfd_dnb |= SLI4_RQCREATEV2_DNB;
+ num_pages = sli_page_count(qs[0]->dma.size, SLI_PAGE_SIZE);
+ req->num_pages = cpu_to_le16(num_pages);
+ req->rqe_count = cpu_to_le16(qs[0]->dma.size / SLI4_RQE_SIZE);
+ req->rqe_size_byte |= SLI4_RQE_SIZE_8;
+ req->page_size = SLI4_RQ_PAGE_SIZE_4096;
+ req->rq_count = num_rqs;
+ req->base_cq_id = cpu_to_le16(base_cq_id);
+ req->hdr_buffer_size = cpu_to_le16(header_buffer_size);
+ req->payload_buffer_size = cpu_to_le16(payload_buffer_size);
+
+ for (i = 0; i < num_rqs; i++) {
+ for (p = 0, addr = qs[i]->dma.phys; p < num_pages;
+ p++, addr += SLI_PAGE_SIZE) {
+ req->page_phys_addr[offset].low =
+ cpu_to_le32(lower_32_bits(addr));
+ req->page_phys_addr[offset].high =
+ cpu_to_le32(upper_32_bits(addr));
+ offset++;
+ }
+ }
+
+ return 0;
+}
+
+static void
+__sli_queue_destroy(struct sli4 *sli4, struct sli4_queue *q)
+{
+ if (!q->dma.size)
+ return;
+
+ dma_free_coherent(&sli4->pci->dev, q->dma.size,
+ q->dma.virt, q->dma.phys);
+ memset(&q->dma, 0, sizeof(struct efc_dma));
+}
+
+int
+__sli_queue_init(struct sli4 *sli4, struct sli4_queue *q, u32 qtype,
+ size_t size, u32 n_entries, u32 align)
+{
+ if (q->dma.virt) {
+ efc_log_err(sli4, "%s failed\n", __func__);
+ return -EIO;
+ }
+
+ memset(q, 0, sizeof(struct sli4_queue));
+
+ q->dma.size = size * n_entries;
+ q->dma.virt = dma_alloc_coherent(&sli4->pci->dev, q->dma.size,
+ &q->dma.phys, GFP_DMA);
+ if (!q->dma.virt) {
+ memset(&q->dma, 0, sizeof(struct efc_dma));
+ efc_log_err(sli4, "%s allocation failed\n", SLI4_QNAME[qtype]);
+ return -EIO;
+ }
+
+ memset(q->dma.virt, 0, size * n_entries);
+
+ spin_lock_init(&q->lock);
+
+ q->type = qtype;
+ q->size = size;
+ q->length = n_entries;
+
+ if (q->type == SLI4_QTYPE_EQ || q->type == SLI4_QTYPE_CQ) {
+ /* For prism, phase will be flipped after
+ * a sweep through eq and cq
+ */
+ q->phase = 1;
+ }
+
+ /* Limit to hwf the queue size per interrupt */
+ q->proc_limit = n_entries / 2;
+
+ if (q->type == SLI4_QTYPE_EQ)
+ q->posted_limit = q->length / 2;
+ else
+ q->posted_limit = 64;
+
+ return 0;
+}
+
+int
+sli_fc_rq_alloc(struct sli4 *sli4, struct sli4_queue *q,
+ u32 n_entries, u32 buffer_size,
+ struct sli4_queue *cq, bool is_hdr)
+{
+ if (__sli_queue_init(sli4, q, SLI4_QTYPE_RQ, SLI4_RQE_SIZE,
+ n_entries, SLI_PAGE_SIZE))
+ return -EIO;
+
+ if (sli_cmd_rq_create_v1(sli4, sli4->bmbx.virt, &q->dma, cq->id,
+ buffer_size))
+ goto error;
+
+ if (__sli_create_queue(sli4, q))
+ goto error;
+
+ if (is_hdr && q->id & 1) {
+ efc_log_info(sli4, "bad header RQ_ID %d\n", q->id);
+ goto error;
+ } else if (!is_hdr && (q->id & 1) == 0) {
+ efc_log_info(sli4, "bad data RQ_ID %d\n", q->id);
+ goto error;
+ }
+
+ if (is_hdr)
+ q->u.flag |= SLI4_QUEUE_FLAG_HDR;
+ else
+ q->u.flag &= ~SLI4_QUEUE_FLAG_HDR;
+
+ return 0;
+
+error:
+ __sli_queue_destroy(sli4, q);
+ return -EIO;
+}
+
+int
+sli_fc_rq_set_alloc(struct sli4 *sli4, u32 num_rq_pairs,
+ struct sli4_queue *qs[], u32 base_cq_id,
+ u32 n_entries, u32 header_buffer_size,
+ u32 payload_buffer_size)
+{
+ u32 i;
+ struct efc_dma dma = {0};
+ struct sli4_rsp_cmn_create_queue_set *rsp = NULL;
+ void __iomem *db_regaddr = NULL;
+ u32 num_rqs = num_rq_pairs * 2;
+
+ for (i = 0; i < num_rqs; i++) {
+ if (__sli_queue_init(sli4, qs[i], SLI4_QTYPE_RQ,
+ SLI4_RQE_SIZE, n_entries,
+ SLI_PAGE_SIZE)) {
+ goto error;
+ }
+ }
+
+ if (sli_cmd_rq_create_v2(sli4, num_rqs, qs, base_cq_id,
+ header_buffer_size, payload_buffer_size,
+ &dma)) {
+ goto error;
+ }
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_err(sli4, "bootstrap mailbox write failed RQSet\n");
+ goto error;
+ }
+
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ db_regaddr = sli4->reg[1] + SLI4_IF6_RQ_DB_REG;
+ else
+ db_regaddr = sli4->reg[0] + SLI4_RQ_DB_REG;
+
+ rsp = dma.virt;
+ if (rsp->hdr.status) {
+ efc_log_err(sli4, "bad create RQSet status=%#x addl=%#x\n",
+ rsp->hdr.status, rsp->hdr.additional_status);
+ goto error;
+ }
+
+ for (i = 0; i < num_rqs; i++) {
+ qs[i]->id = i + le16_to_cpu(rsp->q_id);
+ if ((qs[i]->id & 1) == 0)
+ qs[i]->u.flag |= SLI4_QUEUE_FLAG_HDR;
+ else
+ qs[i]->u.flag &= ~SLI4_QUEUE_FLAG_HDR;
+
+ qs[i]->db_regaddr = db_regaddr;
+ }
+
+ dma_free_coherent(&sli4->pci->dev, dma.size, dma.virt, dma.phys);
+
+ return 0;
+
+error:
+ for (i = 0; i < num_rqs; i++)
+ __sli_queue_destroy(sli4, qs[i]);
+
+ if (dma.virt)
+ dma_free_coherent(&sli4->pci->dev, dma.size, dma.virt,
+ dma.phys);
+
+ return -EIO;
+}
+
+static int
+sli_res_sli_config(struct sli4 *sli4, void *buf)
+{
+ struct sli4_cmd_sli_config *sli_config = buf;
+
+ /* sanity check */
+ if (!buf || sli_config->hdr.command !=
+ SLI4_MBX_CMD_SLI_CONFIG) {
+ efc_log_err(sli4, "bad parameter buf=%p cmd=%#x\n", buf,
+ buf ? sli_config->hdr.command : -1);
+ return -EIO;
+ }
+
+ if (le16_to_cpu(sli_config->hdr.status))
+ return le16_to_cpu(sli_config->hdr.status);
+
+ if (le32_to_cpu(sli_config->dw1_flags) & SLI4_SLICONF_EMB)
+ return sli_config->payload.embed[4];
+
+ efc_log_info(sli4, "external buffers not supported\n");
+ return -EIO;
+}
+
+int
+__sli_create_queue(struct sli4 *sli4, struct sli4_queue *q)
+{
+ struct sli4_rsp_cmn_create_queue *res_q = NULL;
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_crit(sli4, "bootstrap mailbox write fail %s\n",
+ SLI4_QNAME[q->type]);
+ return -EIO;
+ }
+ if (sli_res_sli_config(sli4, sli4->bmbx.virt)) {
+ efc_log_err(sli4, "bad status create %s\n",
+ SLI4_QNAME[q->type]);
+ return -EIO;
+ }
+ res_q = (void *)((u8 *)sli4->bmbx.virt +
+ offsetof(struct sli4_cmd_sli_config, payload));
+
+ if (res_q->hdr.status) {
+ efc_log_err(sli4, "bad create %s status=%#x addl=%#x\n",
+ SLI4_QNAME[q->type], res_q->hdr.status,
+ res_q->hdr.additional_status);
+ return -EIO;
+ }
+ q->id = le16_to_cpu(res_q->q_id);
+ switch (q->type) {
+ case SLI4_QTYPE_EQ:
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ q->db_regaddr = sli4->reg[1] + SLI4_IF6_EQ_DB_REG;
+ else
+ q->db_regaddr = sli4->reg[0] + SLI4_EQCQ_DB_REG;
+ break;
+ case SLI4_QTYPE_CQ:
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ q->db_regaddr = sli4->reg[1] + SLI4_IF6_CQ_DB_REG;
+ else
+ q->db_regaddr = sli4->reg[0] + SLI4_EQCQ_DB_REG;
+ break;
+ case SLI4_QTYPE_MQ:
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ q->db_regaddr = sli4->reg[1] + SLI4_IF6_MQ_DB_REG;
+ else
+ q->db_regaddr = sli4->reg[0] + SLI4_MQ_DB_REG;
+ break;
+ case SLI4_QTYPE_RQ:
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ q->db_regaddr = sli4->reg[1] + SLI4_IF6_RQ_DB_REG;
+ else
+ q->db_regaddr = sli4->reg[0] + SLI4_RQ_DB_REG;
+ break;
+ case SLI4_QTYPE_WQ:
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ q->db_regaddr = sli4->reg[1] + SLI4_IF6_WQ_DB_REG;
+ else
+ q->db_regaddr = sli4->reg[0] + SLI4_IO_WQ_DB_REG;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int
+sli_get_queue_entry_size(struct sli4 *sli4, u32 qtype)
+{
+ u32 size = 0;
+
+ switch (qtype) {
+ case SLI4_QTYPE_EQ:
+ size = sizeof(u32);
+ break;
+ case SLI4_QTYPE_CQ:
+ size = 16;
+ break;
+ case SLI4_QTYPE_MQ:
+ size = 256;
+ break;
+ case SLI4_QTYPE_WQ:
+ size = sli4->wqe_size;
+ break;
+ case SLI4_QTYPE_RQ:
+ size = SLI4_RQE_SIZE;
+ break;
+ default:
+ efc_log_info(sli4, "unknown queue type %d\n", qtype);
+ return -1;
+ }
+ return size;
+}
+
+int
+sli_queue_alloc(struct sli4 *sli4, u32 qtype,
+ struct sli4_queue *q, u32 n_entries,
+ struct sli4_queue *assoc)
+{
+ int size;
+ u32 align = 0;
+
+ /* get queue size */
+ size = sli_get_queue_entry_size(sli4, qtype);
+ if (size < 0)
+ return -EIO;
+ align = SLI_PAGE_SIZE;
+
+ if (__sli_queue_init(sli4, q, qtype, size, n_entries, align))
+ return -EIO;
+
+ switch (qtype) {
+ case SLI4_QTYPE_EQ:
+ if (!sli_cmd_common_create_eq(sli4, sli4->bmbx.virt, &q->dma) &&
+ !__sli_create_queue(sli4, q))
+ return 0;
+
+ break;
+ case SLI4_QTYPE_CQ:
+ if (!sli_cmd_common_create_cq(sli4, sli4->bmbx.virt, &q->dma,
+ assoc ? assoc->id : 0) &&
+ !__sli_create_queue(sli4, q))
+ return 0;
+
+ break;
+ case SLI4_QTYPE_MQ:
+ assoc->u.flag |= SLI4_QUEUE_FLAG_MQ;
+ if (!sli_cmd_common_create_mq_ext(sli4, sli4->bmbx.virt,
+ &q->dma, assoc->id) &&
+ !__sli_create_queue(sli4, q))
+ return 0;
+
+ break;
+ case SLI4_QTYPE_WQ:
+ if (!sli_cmd_wq_create(sli4, sli4->bmbx.virt, &q->dma,
+ assoc ? assoc->id : 0) &&
+ !__sli_create_queue(sli4, q))
+ return 0;
+
+ break;
+ default:
+ efc_log_info(sli4, "unknown queue type %d\n", qtype);
+ }
+
+ __sli_queue_destroy(sli4, q);
+ return -EIO;
+}
+
+static int sli_cmd_cq_set_create(struct sli4 *sli4,
+ struct sli4_queue *qs[], u32 num_cqs,
+ struct sli4_queue *eqs[],
+ struct efc_dma *dma)
+{
+ struct sli4_rqst_cmn_create_cq_set_v0 *req = NULL;
+ uintptr_t addr;
+ u32 i, offset = 0, page_bytes = 0, payload_size;
+ u32 p = 0, page_size = 0, n_cqe = 0, num_pages_cq;
+ u32 dw5_flags = 0;
+ u16 dw6w1_flags = 0;
+ __le32 req_len;
+
+ n_cqe = qs[0]->dma.size / SLI4_CQE_BYTES;
+ switch (n_cqe) {
+ case 256:
+ case 512:
+ case 1024:
+ case 2048:
+ page_size = 1;
+ break;
+ case 4096:
+ page_size = 2;
+ break;
+ default:
+ return -EIO;
+ }
+
+ page_bytes = page_size * SLI_PAGE_SIZE;
+ num_pages_cq = sli_page_count(qs[0]->dma.size, page_bytes);
+ payload_size = max(SLI4_RQST_CMDSZ(cmn_create_cq_set_v0) +
+ (SZ_DMAADDR * num_pages_cq * num_cqs),
+ sizeof(struct sli4_rsp_cmn_create_queue_set));
+
+ dma->size = payload_size;
+ dma->virt = dma_alloc_coherent(&sli4->pci->dev, dma->size,
+ &dma->phys, GFP_DMA);
+ if (!dma->virt)
+ return -EIO;
+
+ memset(dma->virt, 0, payload_size);
+
+ req = sli_config_cmd_init(sli4, sli4->bmbx.virt, payload_size, dma);
+ if (!req)
+ return -EIO;
+
+ req_len = SLI4_RQST_PYLD_LEN_VAR(cmn_create_cq_set_v0,
+ SZ_DMAADDR * num_pages_cq * num_cqs);
+ sli_cmd_fill_hdr(&req->hdr, SLI4_CMN_CREATE_CQ_SET, SLI4_SUBSYSTEM_FC,
+ CMD_V0, req_len);
+ req->page_size = page_size;
+
+ req->num_pages = cpu_to_le16(num_pages_cq);
+ switch (num_pages_cq) {
+ case 1:
+ dw5_flags |= SLI4_CQ_CNT_VAL(256);
+ break;
+ case 2:
+ dw5_flags |= SLI4_CQ_CNT_VAL(512);
+ break;
+ case 4:
+ dw5_flags |= SLI4_CQ_CNT_VAL(1024);
+ break;
+ case 8:
+ dw5_flags |= SLI4_CQ_CNT_VAL(LARGE);
+ dw6w1_flags |= (n_cqe & SLI4_CREATE_CQSETV0_CQE_COUNT);
+ break;
+ default:
+ efc_log_info(sli4, "num_pages %d not valid\n", num_pages_cq);
+ return -EIO;
+ }
+
+ dw5_flags |= SLI4_CREATE_CQSETV0_EVT;
+ dw5_flags |= SLI4_CREATE_CQSETV0_VALID;
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ dw5_flags |= SLI4_CREATE_CQSETV0_AUTOVALID;
+
+ dw6w1_flags &= ~SLI4_CREATE_CQSETV0_ARM;
+
+ req->dw5_flags = cpu_to_le32(dw5_flags);
+ req->dw6w1_flags = cpu_to_le16(dw6w1_flags);
+
+ req->num_cq_req = cpu_to_le16(num_cqs);
+
+ /* Fill page addresses of all the CQs. */
+ for (i = 0; i < num_cqs; i++) {
+ req->eq_id[i] = cpu_to_le16(eqs[i]->id);
+ for (p = 0, addr = qs[i]->dma.phys; p < num_pages_cq;
+ p++, addr += page_bytes) {
+ req->page_phys_addr[offset].low =
+ cpu_to_le32(lower_32_bits(addr));
+ req->page_phys_addr[offset].high =
+ cpu_to_le32(upper_32_bits(addr));
+ offset++;
+ }
+ }
+
+ return 0;
+}
+
+int
+sli_cq_alloc_set(struct sli4 *sli4, struct sli4_queue *qs[],
+ u32 num_cqs, u32 n_entries, struct sli4_queue *eqs[])
+{
+ u32 i;
+ struct efc_dma dma = {0};
+ struct sli4_rsp_cmn_create_queue_set *res;
+ void __iomem *db_regaddr;
+
+ /* Align the queue DMA memory */
+ for (i = 0; i < num_cqs; i++) {
+ if (__sli_queue_init(sli4, qs[i], SLI4_QTYPE_CQ, SLI4_CQE_BYTES,
+ n_entries, SLI_PAGE_SIZE))
+ goto error;
+ }
+
+ if (sli_cmd_cq_set_create(sli4, qs, num_cqs, eqs, &dma))
+ goto error;
+
+ if (sli_bmbx_command(sli4))
+ goto error;
+
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ db_regaddr = sli4->reg[1] + SLI4_IF6_CQ_DB_REG;
+ else
+ db_regaddr = sli4->reg[0] + SLI4_EQCQ_DB_REG;
+
+ res = dma.virt;
+ if (res->hdr.status) {
+ efc_log_err(sli4, "bad create CQSet status=%#x addl=%#x\n",
+ res->hdr.status, res->hdr.additional_status);
+ goto error;
+ }
+
+ /* Check if we got all requested CQs. */
+ if (le16_to_cpu(res->num_q_allocated) != num_cqs) {
+ efc_log_crit(sli4, "Requested count CQs doesn't match.\n");
+ goto error;
+ }
+ /* Fill the resp cq ids. */
+ for (i = 0; i < num_cqs; i++) {
+ qs[i]->id = le16_to_cpu(res->q_id) + i;
+ qs[i]->db_regaddr = db_regaddr;
+ }
+
+ dma_free_coherent(&sli4->pci->dev, dma.size, dma.virt, dma.phys);
+
+ return 0;
+
+error:
+ for (i = 0; i < num_cqs; i++)
+ __sli_queue_destroy(sli4, qs[i]);
+
+ if (dma.virt)
+ dma_free_coherent(&sli4->pci->dev, dma.size, dma.virt,
+ dma.phys);
+
+ return -EIO;
+}
+
+static int
+sli_cmd_common_destroy_q(struct sli4 *sli4, u8 opc, u8 subsystem, u16 q_id)
+{
+ struct sli4_rqst_cmn_destroy_q *req;
+
+ /* Payload length must accommodate both request and response */
+ req = sli_config_cmd_init(sli4, sli4->bmbx.virt,
+ SLI4_CFG_PYLD_LENGTH(cmn_destroy_q), NULL);
+ if (!req)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&req->hdr, opc, subsystem,
+ CMD_V0, SLI4_RQST_PYLD_LEN(cmn_destroy_q));
+ req->q_id = cpu_to_le16(q_id);
+
+ return 0;
+}
+
+int
+sli_queue_free(struct sli4 *sli4, struct sli4_queue *q,
+ u32 destroy_queues, u32 free_memory)
+{
+ int rc = 0;
+ u8 opcode, subsystem;
+ struct sli4_rsp_hdr *res;
+
+ if (!q) {
+ efc_log_err(sli4, "bad parameter sli4=%p q=%p\n", sli4, q);
+ return -EIO;
+ }
+
+ if (!destroy_queues)
+ goto free_mem;
+
+ switch (q->type) {
+ case SLI4_QTYPE_EQ:
+ opcode = SLI4_CMN_DESTROY_EQ;
+ subsystem = SLI4_SUBSYSTEM_COMMON;
+ break;
+ case SLI4_QTYPE_CQ:
+ opcode = SLI4_CMN_DESTROY_CQ;
+ subsystem = SLI4_SUBSYSTEM_COMMON;
+ break;
+ case SLI4_QTYPE_MQ:
+ opcode = SLI4_CMN_DESTROY_MQ;
+ subsystem = SLI4_SUBSYSTEM_COMMON;
+ break;
+ case SLI4_QTYPE_WQ:
+ opcode = SLI4_OPC_WQ_DESTROY;
+ subsystem = SLI4_SUBSYSTEM_FC;
+ break;
+ case SLI4_QTYPE_RQ:
+ opcode = SLI4_OPC_RQ_DESTROY;
+ subsystem = SLI4_SUBSYSTEM_FC;
+ break;
+ default:
+ efc_log_info(sli4, "bad queue type %d\n", q->type);
+ rc = -EIO;
+ goto free_mem;
+ }
+
+ rc = sli_cmd_common_destroy_q(sli4, opcode, subsystem, q->id);
+ if (rc)
+ goto free_mem;
+
+ rc = sli_bmbx_command(sli4);
+ if (rc)
+ goto free_mem;
+
+ rc = sli_res_sli_config(sli4, sli4->bmbx.virt);
+ if (rc)
+ goto free_mem;
+
+ res = (void *)((u8 *)sli4->bmbx.virt +
+ offsetof(struct sli4_cmd_sli_config, payload));
+ if (res->status) {
+ efc_log_err(sli4, "destroy %s st=%#x addl=%#x\n",
+ SLI4_QNAME[q->type], res->status,
+ res->additional_status);
+ rc = -EIO;
+ goto free_mem;
+ }
+
+free_mem:
+ if (free_memory)
+ __sli_queue_destroy(sli4, q);
+
+ return rc;
+}
+
+int
+sli_queue_eq_arm(struct sli4 *sli4, struct sli4_queue *q, bool arm)
+{
+ u32 val;
+ unsigned long flags = 0;
+ u32 a = arm ? SLI4_EQCQ_ARM : SLI4_EQCQ_UNARM;
+
+ spin_lock_irqsave(&q->lock, flags);
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ val = sli_format_if6_eq_db_data(q->n_posted, q->id, a);
+ else
+ val = sli_format_eq_db_data(q->n_posted, q->id, a);
+
+ writel(val, q->db_regaddr);
+ q->n_posted = 0;
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return 0;
+}
+
+int
+sli_queue_arm(struct sli4 *sli4, struct sli4_queue *q, bool arm)
+{
+ u32 val = 0;
+ unsigned long flags = 0;
+ u32 a = arm ? SLI4_EQCQ_ARM : SLI4_EQCQ_UNARM;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ switch (q->type) {
+ case SLI4_QTYPE_EQ:
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ val = sli_format_if6_eq_db_data(q->n_posted, q->id, a);
+ else
+ val = sli_format_eq_db_data(q->n_posted, q->id, a);
+
+ writel(val, q->db_regaddr);
+ q->n_posted = 0;
+ break;
+ case SLI4_QTYPE_CQ:
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ val = sli_format_if6_cq_db_data(q->n_posted, q->id, a);
+ else
+ val = sli_format_cq_db_data(q->n_posted, q->id, a);
+
+ writel(val, q->db_regaddr);
+ q->n_posted = 0;
+ break;
+ default:
+ efc_log_info(sli4, "should only be used for EQ/CQ, not %s\n",
+ SLI4_QNAME[q->type]);
+ }
+
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return 0;
+}
+
+int
+sli_wq_write(struct sli4 *sli4, struct sli4_queue *q, u8 *entry)
+{
+ u8 *qe = q->dma.virt;
+ u32 qindex;
+ u32 val = 0;
+
+ qindex = q->index;
+ qe += q->index * q->size;
+
+ if (sli4->params.perf_wq_id_association)
+ sli_set_wq_id_association(entry, q->id);
+
+ memcpy(qe, entry, q->size);
+ val = sli_format_wq_db_data(q->id);
+
+ writel(val, q->db_regaddr);
+ q->index = (q->index + 1) & (q->length - 1);
+
+ return qindex;
+}
+
+int
+sli_mq_write(struct sli4 *sli4, struct sli4_queue *q, u8 *entry)
+{
+ u8 *qe = q->dma.virt;
+ u32 qindex;
+ u32 val = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ qindex = q->index;
+ qe += q->index * q->size;
+
+ memcpy(qe, entry, q->size);
+ val = sli_format_mq_db_data(q->id);
+ writel(val, q->db_regaddr);
+ q->index = (q->index + 1) & (q->length - 1);
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return qindex;
+}
+
+int
+sli_rq_write(struct sli4 *sli4, struct sli4_queue *q, u8 *entry)
+{
+ u8 *qe = q->dma.virt;
+ u32 qindex;
+ u32 val = 0;
+
+ qindex = q->index;
+ qe += q->index * q->size;
+
+ memcpy(qe, entry, q->size);
+
+ /*
+ * In RQ-pair, an RQ either contains the FC header
+ * (i.e. is_hdr == TRUE) or the payload.
+ *
+ * Don't ring doorbell for payload RQ
+ */
+ if (!(q->u.flag & SLI4_QUEUE_FLAG_HDR))
+ goto skip;
+
+ val = sli_format_rq_db_data(q->id);
+ writel(val, q->db_regaddr);
+skip:
+ q->index = (q->index + 1) & (q->length - 1);
+
+ return qindex;
+}
+
+int
+sli_eq_read(struct sli4 *sli4, struct sli4_queue *q, u8 *entry)
+{
+ u8 *qe = q->dma.virt;
+ unsigned long flags = 0;
+ u16 wflags = 0;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ qe += q->index * q->size;
+
+ /* Check if eqe is valid */
+ wflags = le16_to_cpu(((struct sli4_eqe *)qe)->dw0w0_flags);
+
+ if ((wflags & SLI4_EQE_VALID) != q->phase) {
+ spin_unlock_irqrestore(&q->lock, flags);
+ return -EIO;
+ }
+
+ if (sli4->if_type != SLI4_INTF_IF_TYPE_6) {
+ wflags &= ~SLI4_EQE_VALID;
+ ((struct sli4_eqe *)qe)->dw0w0_flags = cpu_to_le16(wflags);
+ }
+
+ memcpy(entry, qe, q->size);
+ q->index = (q->index + 1) & (q->length - 1);
+ q->n_posted++;
+ /*
+ * For prism, the phase value will be used
+ * to check the validity of eq/cq entries.
+ * The value toggles after a complete sweep
+ * through the queue.
+ */
+
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6 && q->index == 0)
+ q->phase ^= (u16)0x1;
+
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return 0;
+}
+
+int
+sli_cq_read(struct sli4 *sli4, struct sli4_queue *q, u8 *entry)
+{
+ u8 *qe = q->dma.virt;
+ unsigned long flags = 0;
+ u32 dwflags = 0;
+ bool valid_bit_set;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ qe += q->index * q->size;
+
+ /* Check if cqe is valid */
+ dwflags = le32_to_cpu(((struct sli4_mcqe *)qe)->dw3_flags);
+ valid_bit_set = (dwflags & SLI4_MCQE_VALID) != 0;
+
+ if (valid_bit_set != q->phase) {
+ spin_unlock_irqrestore(&q->lock, flags);
+ return -EIO;
+ }
+
+ if (sli4->if_type != SLI4_INTF_IF_TYPE_6) {
+ dwflags &= ~SLI4_MCQE_VALID;
+ ((struct sli4_mcqe *)qe)->dw3_flags = cpu_to_le32(dwflags);
+ }
+
+ memcpy(entry, qe, q->size);
+ q->index = (q->index + 1) & (q->length - 1);
+ q->n_posted++;
+ /*
+ * For prism, the phase value will be used
+ * to check the validity of eq/cq entries.
+ * The value toggles after a complete sweep
+ * through the queue.
+ */
+
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6 && q->index == 0)
+ q->phase ^= (u16)0x1;
+
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return 0;
+}
+
+int
+sli_mq_read(struct sli4 *sli4, struct sli4_queue *q, u8 *entry)
+{
+ u8 *qe = q->dma.virt;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ qe += q->u.r_idx * q->size;
+
+ /* Check if mqe is valid */
+ if (q->index == q->u.r_idx) {
+ spin_unlock_irqrestore(&q->lock, flags);
+ return -EIO;
+ }
+
+ memcpy(entry, qe, q->size);
+ q->u.r_idx = (q->u.r_idx + 1) & (q->length - 1);
+
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return 0;
+}
+
+int
+sli_eq_parse(struct sli4 *sli4, u8 *buf, u16 *cq_id)
+{
+ struct sli4_eqe *eqe = (void *)buf;
+ int rc = 0;
+ u16 flags = 0;
+ u16 majorcode;
+ u16 minorcode;
+
+ if (!buf || !cq_id) {
+ efc_log_err(sli4, "bad parameters sli4=%p buf=%p cq_id=%p\n",
+ sli4, buf, cq_id);
+ return -EIO;
+ }
+
+ flags = le16_to_cpu(eqe->dw0w0_flags);
+ majorcode = (flags & SLI4_EQE_MJCODE) >> 1;
+ minorcode = (flags & SLI4_EQE_MNCODE) >> 4;
+ switch (majorcode) {
+ case SLI4_MAJOR_CODE_STANDARD:
+ *cq_id = le16_to_cpu(eqe->resource_id);
+ break;
+ case SLI4_MAJOR_CODE_SENTINEL:
+ efc_log_info(sli4, "sentinel EQE\n");
+ rc = SLI4_EQE_STATUS_EQ_FULL;
+ break;
+ default:
+ efc_log_info(sli4, "Unsupported EQE: major %x minor %x\n",
+ majorcode, minorcode);
+ rc = -EIO;
+ }
+
+ return rc;
+}
+
+int
+sli_cq_parse(struct sli4 *sli4, struct sli4_queue *cq, u8 *cqe,
+ enum sli4_qentry *etype, u16 *q_id)
+{
+ int rc = 0;
+
+ if (!cq || !cqe || !etype) {
+ efc_log_err(sli4, "bad params sli4=%p cq=%p cqe=%p etype=%p q_id=%p\n",
+ sli4, cq, cqe, etype, q_id);
+ return -EINVAL;
+ }
+
+ /* Parse a CQ entry to retrieve the event type and the queue id */
+ if (cq->u.flag & SLI4_QUEUE_FLAG_MQ) {
+ struct sli4_mcqe *mcqe = (void *)cqe;
+
+ if (le32_to_cpu(mcqe->dw3_flags) & SLI4_MCQE_AE) {
+ *etype = SLI4_QENTRY_ASYNC;
+ } else {
+ *etype = SLI4_QENTRY_MQ;
+ rc = sli_cqe_mq(sli4, mcqe);
+ }
+ *q_id = -1;
+ } else {
+ rc = sli_fc_cqe_parse(sli4, cq, cqe, etype, q_id);
+ }
+
+ return rc;
+}
+
+int
+sli_abort_wqe(struct sli4 *sli, void *buf, enum sli4_abort_type type,
+ bool send_abts, u32 ids, u32 mask, u16 tag, u16 cq_id)
+{
+ struct sli4_abort_wqe *abort = buf;
+
+ memset(buf, 0, sli->wqe_size);
+
+ switch (type) {
+ case SLI4_ABORT_XRI:
+ abort->criteria = SLI4_ABORT_CRITERIA_XRI_TAG;
+ if (mask) {
+ efc_log_warn(sli, "%#x aborting XRI %#x warning non-zero mask",
+ mask, ids);
+ mask = 0;
+ }
+ break;
+ case SLI4_ABORT_ABORT_ID:
+ abort->criteria = SLI4_ABORT_CRITERIA_ABORT_TAG;
+ break;
+ case SLI4_ABORT_REQUEST_ID:
+ abort->criteria = SLI4_ABORT_CRITERIA_REQUEST_TAG;
+ break;
+ default:
+ efc_log_info(sli, "unsupported type %#x\n", type);
+ return -EIO;
+ }
+
+ abort->ia_ir_byte |= send_abts ? 0 : 1;
+
+ /* Suppress ABTS retries */
+ abort->ia_ir_byte |= SLI4_ABRT_WQE_IR;
+
+ abort->t_mask = cpu_to_le32(mask);
+ abort->t_tag = cpu_to_le32(ids);
+ abort->command = SLI4_WQE_ABORT;
+ abort->request_tag = cpu_to_le16(tag);
+
+ abort->dw10w0_flags = cpu_to_le16(SLI4_ABRT_WQE_QOSD);
+
+ abort->cq_id = cpu_to_le16(cq_id);
+ abort->cmdtype_wqec_byte |= SLI4_CMD_ABORT_WQE;
+
+ return 0;
+}
+
+int
+sli_els_request64_wqe(struct sli4 *sli, void *buf, struct efc_dma *sgl,
+ struct sli_els_params *params)
+{
+ struct sli4_els_request64_wqe *els = buf;
+ struct sli4_sge *sge = sgl->virt;
+ bool is_fabric = false;
+ struct sli4_bde *bptr;
+
+ memset(buf, 0, sli->wqe_size);
+
+ bptr = &els->els_request_payload;
+ if (sli->params.sgl_pre_registered) {
+ els->qosd_xbl_hlm_iod_dbde_wqes &= ~SLI4_REQ_WQE_XBL;
+
+ els->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_REQ_WQE_DBDE;
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (params->xmit_len & SLI4_BDE_LEN_MASK));
+
+ bptr->u.data.low = sge[0].buffer_address_low;
+ bptr->u.data.high = sge[0].buffer_address_high;
+ } else {
+ els->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_REQ_WQE_XBL;
+
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(BLP)) |
+ ((2 * sizeof(struct sli4_sge)) &
+ SLI4_BDE_LEN_MASK));
+ bptr->u.blp.low = cpu_to_le32(lower_32_bits(sgl->phys));
+ bptr->u.blp.high = cpu_to_le32(upper_32_bits(sgl->phys));
+ }
+
+ els->els_request_payload_length = cpu_to_le32(params->xmit_len);
+ els->max_response_payload_length = cpu_to_le32(params->rsp_len);
+
+ els->xri_tag = cpu_to_le16(params->xri);
+ els->timer = params->timeout;
+ els->class_byte |= SLI4_GENERIC_CLASS_CLASS_3;
+
+ els->command = SLI4_WQE_ELS_REQUEST64;
+
+ els->request_tag = cpu_to_le16(params->tag);
+
+ els->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_REQ_WQE_IOD;
+
+ els->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_REQ_WQE_QOSD;
+
+ /* figure out the ELS_ID value from the request buffer */
+
+ switch (params->cmd) {
+ case ELS_LOGO:
+ els->cmdtype_elsid_byte |=
+ SLI4_ELS_REQUEST64_LOGO << SLI4_REQ_WQE_ELSID_SHFT;
+ if (params->rpi_registered) {
+ els->ct_byte |=
+ SLI4_GENERIC_CONTEXT_RPI << SLI4_REQ_WQE_CT_SHFT;
+ els->context_tag = cpu_to_le16(params->rpi);
+ } else {
+ els->ct_byte |=
+ SLI4_GENERIC_CONTEXT_VPI << SLI4_REQ_WQE_CT_SHFT;
+ els->context_tag = cpu_to_le16(params->vpi);
+ }
+ if (params->d_id == FC_FID_FLOGI)
+ is_fabric = true;
+ break;
+ case ELS_FDISC:
+ if (params->d_id == FC_FID_FLOGI)
+ is_fabric = true;
+ if (params->s_id == 0) {
+ els->cmdtype_elsid_byte |=
+ SLI4_ELS_REQUEST64_FDISC << SLI4_REQ_WQE_ELSID_SHFT;
+ is_fabric = true;
+ } else {
+ els->cmdtype_elsid_byte |=
+ SLI4_ELS_REQUEST64_OTHER << SLI4_REQ_WQE_ELSID_SHFT;
+ }
+ els->ct_byte |=
+ SLI4_GENERIC_CONTEXT_VPI << SLI4_REQ_WQE_CT_SHFT;
+ els->context_tag = cpu_to_le16(params->vpi);
+ els->sid_sp_dword |= cpu_to_le32(1 << SLI4_REQ_WQE_SP_SHFT);
+ break;
+ case ELS_FLOGI:
+ els->ct_byte |=
+ SLI4_GENERIC_CONTEXT_VPI << SLI4_REQ_WQE_CT_SHFT;
+ els->context_tag = cpu_to_le16(params->vpi);
+ /*
+ * Set SP here ... we haven't done a REG_VPI yet
+ * need to maybe not set this when we have
+ * completed VFI/VPI registrations ...
+ *
+ * Use the FC_ID of the SPORT if it has been allocated,
+ * otherwise use an S_ID of zero.
+ */
+ els->sid_sp_dword |= cpu_to_le32(1 << SLI4_REQ_WQE_SP_SHFT);
+ if (params->s_id != U32_MAX)
+ els->sid_sp_dword |= cpu_to_le32(params->s_id);
+ break;
+ case ELS_PLOGI:
+ els->cmdtype_elsid_byte |=
+ SLI4_ELS_REQUEST64_PLOGI << SLI4_REQ_WQE_ELSID_SHFT;
+ els->ct_byte |=
+ SLI4_GENERIC_CONTEXT_VPI << SLI4_REQ_WQE_CT_SHFT;
+ els->context_tag = cpu_to_le16(params->vpi);
+ break;
+ case ELS_SCR:
+ els->cmdtype_elsid_byte |=
+ SLI4_ELS_REQUEST64_OTHER << SLI4_REQ_WQE_ELSID_SHFT;
+ els->ct_byte |=
+ SLI4_GENERIC_CONTEXT_VPI << SLI4_REQ_WQE_CT_SHFT;
+ els->context_tag = cpu_to_le16(params->vpi);
+ break;
+ default:
+ els->cmdtype_elsid_byte |=
+ SLI4_ELS_REQUEST64_OTHER << SLI4_REQ_WQE_ELSID_SHFT;
+ if (params->rpi_registered) {
+ els->ct_byte |= (SLI4_GENERIC_CONTEXT_RPI <<
+ SLI4_REQ_WQE_CT_SHFT);
+ els->context_tag = cpu_to_le16(params->vpi);
+ } else {
+ els->ct_byte |=
+ SLI4_GENERIC_CONTEXT_VPI << SLI4_REQ_WQE_CT_SHFT;
+ els->context_tag = cpu_to_le16(params->vpi);
+ }
+ break;
+ }
+
+ if (is_fabric)
+ els->cmdtype_elsid_byte |= SLI4_ELS_REQUEST64_CMD_FABRIC;
+ else
+ els->cmdtype_elsid_byte |= SLI4_ELS_REQUEST64_CMD_NON_FABRIC;
+
+ els->cq_id = cpu_to_le16(SLI4_CQ_DEFAULT);
+
+ if (((els->ct_byte & SLI4_REQ_WQE_CT) >> SLI4_REQ_WQE_CT_SHFT) !=
+ SLI4_GENERIC_CONTEXT_RPI)
+ els->remote_id_dword = cpu_to_le32(params->d_id);
+
+ if (((els->ct_byte & SLI4_REQ_WQE_CT) >> SLI4_REQ_WQE_CT_SHFT) ==
+ SLI4_GENERIC_CONTEXT_VPI)
+ els->temporary_rpi = cpu_to_le16(params->rpi);
+
+ return 0;
+}
+
+int
+sli_fcp_icmnd64_wqe(struct sli4 *sli, void *buf, struct efc_dma *sgl, u16 xri,
+ u16 tag, u16 cq_id, u32 rpi, u32 rnode_fcid, u8 timeout)
+{
+ struct sli4_fcp_icmnd64_wqe *icmnd = buf;
+ struct sli4_sge *sge = NULL;
+ struct sli4_bde *bptr;
+ u32 len;
+
+ memset(buf, 0, sli->wqe_size);
+
+ if (!sgl || !sgl->virt) {
+ efc_log_err(sli, "bad parameter sgl=%p virt=%p\n",
+ sgl, sgl ? sgl->virt : NULL);
+ return -EIO;
+ }
+ sge = sgl->virt;
+ bptr = &icmnd->bde;
+ if (sli->params.sgl_pre_registered) {
+ icmnd->qosd_xbl_hlm_iod_dbde_wqes &= ~SLI4_ICMD_WQE_XBL;
+
+ icmnd->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_ICMD_WQE_DBDE;
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (le32_to_cpu(sge[0].buffer_length) &
+ SLI4_BDE_LEN_MASK));
+
+ bptr->u.data.low = sge[0].buffer_address_low;
+ bptr->u.data.high = sge[0].buffer_address_high;
+ } else {
+ icmnd->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_ICMD_WQE_XBL;
+
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(BLP)) |
+ (sgl->size & SLI4_BDE_LEN_MASK));
+
+ bptr->u.blp.low = cpu_to_le32(lower_32_bits(sgl->phys));
+ bptr->u.blp.high = cpu_to_le32(upper_32_bits(sgl->phys));
+ }
+
+ len = le32_to_cpu(sge[0].buffer_length) +
+ le32_to_cpu(sge[1].buffer_length);
+ icmnd->payload_offset_length = cpu_to_le16(len);
+ icmnd->xri_tag = cpu_to_le16(xri);
+ icmnd->context_tag = cpu_to_le16(rpi);
+ icmnd->timer = timeout;
+
+ /* WQE word 4 contains read transfer length */
+ icmnd->class_pu_byte |= 2 << SLI4_ICMD_WQE_PU_SHFT;
+ icmnd->class_pu_byte |= SLI4_GENERIC_CLASS_CLASS_3;
+ icmnd->command = SLI4_WQE_FCP_ICMND64;
+ icmnd->dif_ct_bs_byte |=
+ SLI4_GENERIC_CONTEXT_RPI << SLI4_ICMD_WQE_CT_SHFT;
+
+ icmnd->abort_tag = cpu_to_le32(xri);
+
+ icmnd->request_tag = cpu_to_le16(tag);
+ icmnd->len_loc1_byte |= SLI4_ICMD_WQE_LEN_LOC_BIT1;
+ icmnd->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_ICMD_WQE_LEN_LOC_BIT2;
+ icmnd->cmd_type_byte |= SLI4_CMD_FCP_ICMND64_WQE;
+ icmnd->cq_id = cpu_to_le16(cq_id);
+
+ return 0;
+}
+
+int
+sli_fcp_iread64_wqe(struct sli4 *sli, void *buf, struct efc_dma *sgl,
+ u32 first_data_sge, u32 xfer_len, u16 xri, u16 tag,
+ u16 cq_id, u32 rpi, u32 rnode_fcid,
+ u8 dif, u8 bs, u8 timeout)
+{
+ struct sli4_fcp_iread64_wqe *iread = buf;
+ struct sli4_sge *sge = NULL;
+ struct sli4_bde *bptr;
+ u32 sge_flags, len;
+
+ memset(buf, 0, sli->wqe_size);
+
+ if (!sgl || !sgl->virt) {
+ efc_log_err(sli, "bad parameter sgl=%p virt=%p\n",
+ sgl, sgl ? sgl->virt : NULL);
+ return -EIO;
+ }
+
+ sge = sgl->virt;
+ bptr = &iread->bde;
+ if (sli->params.sgl_pre_registered) {
+ iread->qosd_xbl_hlm_iod_dbde_wqes &= ~SLI4_IR_WQE_XBL;
+
+ iread->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_IR_WQE_DBDE;
+
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (le32_to_cpu(sge[0].buffer_length) &
+ SLI4_BDE_LEN_MASK));
+
+ bptr->u.blp.low = sge[0].buffer_address_low;
+ bptr->u.blp.high = sge[0].buffer_address_high;
+ } else {
+ iread->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_IR_WQE_XBL;
+
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(BLP)) |
+ (sgl->size & SLI4_BDE_LEN_MASK));
+
+ bptr->u.blp.low =
+ cpu_to_le32(lower_32_bits(sgl->phys));
+ bptr->u.blp.high =
+ cpu_to_le32(upper_32_bits(sgl->phys));
+
+ /*
+ * fill out fcp_cmnd buffer len and change resp buffer to be of
+ * type "skip" (note: response will still be written to sge[1]
+ * if necessary)
+ */
+ len = le32_to_cpu(sge[0].buffer_length);
+ iread->fcp_cmd_buffer_length = cpu_to_le16(len);
+
+ sge_flags = le32_to_cpu(sge[1].dw2_flags);
+ sge_flags &= (~SLI4_SGE_TYPE_MASK);
+ sge_flags |= (SLI4_SGE_TYPE_SKIP << SLI4_SGE_TYPE_SHIFT);
+ sge[1].dw2_flags = cpu_to_le32(sge_flags);
+ }
+
+ len = le32_to_cpu(sge[0].buffer_length) +
+ le32_to_cpu(sge[1].buffer_length);
+ iread->payload_offset_length = cpu_to_le16(len);
+ iread->total_transfer_length = cpu_to_le32(xfer_len);
+
+ iread->xri_tag = cpu_to_le16(xri);
+ iread->context_tag = cpu_to_le16(rpi);
+
+ iread->timer = timeout;
+
+ /* WQE word 4 contains read transfer length */
+ iread->class_pu_byte |= 2 << SLI4_IR_WQE_PU_SHFT;
+ iread->class_pu_byte |= SLI4_GENERIC_CLASS_CLASS_3;
+ iread->command = SLI4_WQE_FCP_IREAD64;
+ iread->dif_ct_bs_byte |=
+ SLI4_GENERIC_CONTEXT_RPI << SLI4_IR_WQE_CT_SHFT;
+ iread->dif_ct_bs_byte |= dif;
+ iread->dif_ct_bs_byte |= bs << SLI4_IR_WQE_BS_SHFT;
+
+ iread->abort_tag = cpu_to_le32(xri);
+
+ iread->request_tag = cpu_to_le16(tag);
+ iread->len_loc1_byte |= SLI4_IR_WQE_LEN_LOC_BIT1;
+ iread->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_IR_WQE_LEN_LOC_BIT2;
+ iread->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_IR_WQE_IOD;
+ iread->cmd_type_byte |= SLI4_CMD_FCP_IREAD64_WQE;
+ iread->cq_id = cpu_to_le16(cq_id);
+
+ if (sli->params.perf_hint) {
+ bptr = &iread->first_data_bde;
+ bptr->bde_type_buflen = cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (le32_to_cpu(sge[first_data_sge].buffer_length) &
+ SLI4_BDE_LEN_MASK));
+ bptr->u.data.low =
+ sge[first_data_sge].buffer_address_low;
+ bptr->u.data.high =
+ sge[first_data_sge].buffer_address_high;
+ }
+
+ return 0;
+}
+
+int
+sli_fcp_iwrite64_wqe(struct sli4 *sli, void *buf, struct efc_dma *sgl,
+ u32 first_data_sge, u32 xfer_len,
+ u32 first_burst, u16 xri, u16 tag,
+ u16 cq_id, u32 rpi,
+ u32 rnode_fcid,
+ u8 dif, u8 bs, u8 timeout)
+{
+ struct sli4_fcp_iwrite64_wqe *iwrite = buf;
+ struct sli4_sge *sge = NULL;
+ struct sli4_bde *bptr;
+ u32 sge_flags, min, len;
+
+ memset(buf, 0, sli->wqe_size);
+
+ if (!sgl || !sgl->virt) {
+ efc_log_err(sli, "bad parameter sgl=%p virt=%p\n",
+ sgl, sgl ? sgl->virt : NULL);
+ return -EIO;
+ }
+ sge = sgl->virt;
+ bptr = &iwrite->bde;
+ if (sli->params.sgl_pre_registered) {
+ iwrite->qosd_xbl_hlm_iod_dbde_wqes &= ~SLI4_IWR_WQE_XBL;
+
+ iwrite->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_IWR_WQE_DBDE;
+ bptr->bde_type_buflen = cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (le32_to_cpu(sge[0].buffer_length) & SLI4_BDE_LEN_MASK));
+ bptr->u.data.low = sge[0].buffer_address_low;
+ bptr->u.data.high = sge[0].buffer_address_high;
+ } else {
+ iwrite->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_IWR_WQE_XBL;
+
+ bptr->bde_type_buflen = cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (sgl->size & SLI4_BDE_LEN_MASK));
+
+ bptr->u.blp.low = cpu_to_le32(lower_32_bits(sgl->phys));
+ bptr->u.blp.high = cpu_to_le32(upper_32_bits(sgl->phys));
+
+ /*
+ * fill out fcp_cmnd buffer len and change resp buffer to be of
+ * type "skip" (note: response will still be written to sge[1]
+ * if necessary)
+ */
+ len = le32_to_cpu(sge[0].buffer_length);
+ iwrite->fcp_cmd_buffer_length = cpu_to_le16(len);
+ sge_flags = le32_to_cpu(sge[1].dw2_flags);
+ sge_flags &= ~SLI4_SGE_TYPE_MASK;
+ sge_flags |= (SLI4_SGE_TYPE_SKIP << SLI4_SGE_TYPE_SHIFT);
+ sge[1].dw2_flags = cpu_to_le32(sge_flags);
+ }
+
+ len = le32_to_cpu(sge[0].buffer_length) +
+ le32_to_cpu(sge[1].buffer_length);
+ iwrite->payload_offset_length = cpu_to_le16(len);
+ iwrite->total_transfer_length = cpu_to_le16(xfer_len);
+ min = (xfer_len < first_burst) ? xfer_len : first_burst;
+ iwrite->initial_transfer_length = cpu_to_le16(min);
+
+ iwrite->xri_tag = cpu_to_le16(xri);
+ iwrite->context_tag = cpu_to_le16(rpi);
+
+ iwrite->timer = timeout;
+ /* WQE word 4 contains read transfer length */
+ iwrite->class_pu_byte |= 2 << SLI4_IWR_WQE_PU_SHFT;
+ iwrite->class_pu_byte |= SLI4_GENERIC_CLASS_CLASS_3;
+ iwrite->command = SLI4_WQE_FCP_IWRITE64;
+ iwrite->dif_ct_bs_byte |=
+ SLI4_GENERIC_CONTEXT_RPI << SLI4_IWR_WQE_CT_SHFT;
+ iwrite->dif_ct_bs_byte |= dif;
+ iwrite->dif_ct_bs_byte |= bs << SLI4_IWR_WQE_BS_SHFT;
+
+ iwrite->abort_tag = cpu_to_le32(xri);
+
+ iwrite->request_tag = cpu_to_le16(tag);
+ iwrite->len_loc1_byte |= SLI4_IWR_WQE_LEN_LOC_BIT1;
+ iwrite->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_IWR_WQE_LEN_LOC_BIT2;
+ iwrite->cmd_type_byte |= SLI4_CMD_FCP_IWRITE64_WQE;
+ iwrite->cq_id = cpu_to_le16(cq_id);
+
+ if (sli->params.perf_hint) {
+ bptr = &iwrite->first_data_bde;
+
+ bptr->bde_type_buflen = cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (le32_to_cpu(sge[first_data_sge].buffer_length) &
+ SLI4_BDE_LEN_MASK));
+
+ bptr->u.data.low = sge[first_data_sge].buffer_address_low;
+ bptr->u.data.high = sge[first_data_sge].buffer_address_high;
+ }
+
+ return 0;
+}
+
+int
+sli_fcp_treceive64_wqe(struct sli4 *sli, void *buf, struct efc_dma *sgl,
+ u32 first_data_sge, u16 cq_id, u8 dif, u8 bs,
+ struct sli_fcp_tgt_params *params)
+{
+ struct sli4_fcp_treceive64_wqe *trecv = buf;
+ struct sli4_fcp_128byte_wqe *trecv_128 = buf;
+ struct sli4_sge *sge = NULL;
+ struct sli4_bde *bptr;
+
+ memset(buf, 0, sli->wqe_size);
+
+ if (!sgl || !sgl->virt) {
+ efc_log_err(sli, "bad parameter sgl=%p virt=%p\n",
+ sgl, sgl ? sgl->virt : NULL);
+ return -EIO;
+ }
+ sge = sgl->virt;
+ bptr = &trecv->bde;
+ if (sli->params.sgl_pre_registered) {
+ trecv->qosd_xbl_hlm_iod_dbde_wqes &= ~SLI4_TRCV_WQE_XBL;
+
+ trecv->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_TRCV_WQE_DBDE;
+
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (le32_to_cpu(sge[0].buffer_length)
+ & SLI4_BDE_LEN_MASK));
+
+ bptr->u.data.low = sge[0].buffer_address_low;
+ bptr->u.data.high = sge[0].buffer_address_high;
+
+ trecv->payload_offset_length = sge[0].buffer_length;
+ } else {
+ trecv->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_TRCV_WQE_XBL;
+
+ /* if data is a single physical address, use a BDE */
+ if (!dif &&
+ params->xmit_len <= le32_to_cpu(sge[2].buffer_length)) {
+ trecv->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_TRCV_WQE_DBDE;
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (le32_to_cpu(sge[2].buffer_length)
+ & SLI4_BDE_LEN_MASK));
+
+ bptr->u.data.low = sge[2].buffer_address_low;
+ bptr->u.data.high = sge[2].buffer_address_high;
+ } else {
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(BLP)) |
+ (sgl->size & SLI4_BDE_LEN_MASK));
+ bptr->u.blp.low = cpu_to_le32(lower_32_bits(sgl->phys));
+ bptr->u.blp.high =
+ cpu_to_le32(upper_32_bits(sgl->phys));
+ }
+ }
+
+ trecv->relative_offset = cpu_to_le32(params->offset);
+
+ if (params->flags & SLI4_IO_CONTINUATION)
+ trecv->eat_xc_ccpe |= SLI4_TRCV_WQE_XC;
+
+ trecv->xri_tag = cpu_to_le16(params->xri);
+
+ trecv->context_tag = cpu_to_le16(params->rpi);
+
+ /* WQE uses relative offset */
+ trecv->class_ar_pu_byte |= 1 << SLI4_TRCV_WQE_PU_SHFT;
+
+ if (params->flags & SLI4_IO_AUTO_GOOD_RESPONSE)
+ trecv->class_ar_pu_byte |= SLI4_TRCV_WQE_AR;
+
+ trecv->command = SLI4_WQE_FCP_TRECEIVE64;
+ trecv->class_ar_pu_byte |= SLI4_GENERIC_CLASS_CLASS_3;
+ trecv->dif_ct_bs_byte |=
+ SLI4_GENERIC_CONTEXT_RPI << SLI4_TRCV_WQE_CT_SHFT;
+ trecv->dif_ct_bs_byte |= bs << SLI4_TRCV_WQE_BS_SHFT;
+
+ trecv->remote_xid = cpu_to_le16(params->ox_id);
+
+ trecv->request_tag = cpu_to_le16(params->tag);
+
+ trecv->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_TRCV_WQE_IOD;
+
+ trecv->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_TRCV_WQE_LEN_LOC_BIT2;
+
+ trecv->cmd_type_byte |= SLI4_CMD_FCP_TRECEIVE64_WQE;
+
+ trecv->cq_id = cpu_to_le16(cq_id);
+
+ trecv->fcp_data_receive_length = cpu_to_le32(params->xmit_len);
+
+ if (sli->params.perf_hint) {
+ bptr = &trecv->first_data_bde;
+
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (le32_to_cpu(sge[first_data_sge].buffer_length) &
+ SLI4_BDE_LEN_MASK));
+ bptr->u.data.low = sge[first_data_sge].buffer_address_low;
+ bptr->u.data.high = sge[first_data_sge].buffer_address_high;
+ }
+
+ /* The upper 7 bits of csctl is the priority */
+ if (params->cs_ctl & SLI4_MASK_CCP) {
+ trecv->eat_xc_ccpe |= SLI4_TRCV_WQE_CCPE;
+ trecv->ccp = (params->cs_ctl & SLI4_MASK_CCP);
+ }
+
+ if (params->app_id && sli->wqe_size == SLI4_WQE_EXT_BYTES &&
+ !(trecv->eat_xc_ccpe & SLI4_TRSP_WQE_EAT)) {
+ trecv->lloc1_appid |= SLI4_TRCV_WQE_APPID;
+ trecv->qosd_xbl_hlm_iod_dbde_wqes |= SLI4_TRCV_WQE_WQES;
+ trecv_128->dw[31] = params->app_id;
+ }
+ return 0;
+}
+
+int
+sli_fcp_cont_treceive64_wqe(struct sli4 *sli, void *buf,
+ struct efc_dma *sgl, u32 first_data_sge,
+ u16 sec_xri, u16 cq_id, u8 dif, u8 bs,
+ struct sli_fcp_tgt_params *params)
+{
+ int rc;
+
+ rc = sli_fcp_treceive64_wqe(sli, buf, sgl, first_data_sge,
+ cq_id, dif, bs, params);
+ if (!rc) {
+ struct sli4_fcp_treceive64_wqe *trecv = buf;
+
+ trecv->command = SLI4_WQE_FCP_CONT_TRECEIVE64;
+ trecv->dword5.sec_xri_tag = cpu_to_le16(sec_xri);
+ }
+ return rc;
+}
+
+int
+sli_fcp_trsp64_wqe(struct sli4 *sli4, void *buf, struct efc_dma *sgl,
+ u16 cq_id, u8 port_owned, struct sli_fcp_tgt_params *params)
+{
+ struct sli4_fcp_trsp64_wqe *trsp = buf;
+ struct sli4_fcp_128byte_wqe *trsp_128 = buf;
+
+ memset(buf, 0, sli4->wqe_size);
+
+ if (params->flags & SLI4_IO_AUTO_GOOD_RESPONSE) {
+ trsp->class_ag_byte |= SLI4_TRSP_WQE_AG;
+ } else {
+ struct sli4_sge *sge = sgl->virt;
+ struct sli4_bde *bptr;
+
+ if (sli4->params.sgl_pre_registered || port_owned)
+ trsp->qosd_xbl_hlm_dbde_wqes |= SLI4_TRSP_WQE_DBDE;
+ else
+ trsp->qosd_xbl_hlm_dbde_wqes |= SLI4_TRSP_WQE_XBL;
+ bptr = &trsp->bde;
+
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (le32_to_cpu(sge[0].buffer_length) &
+ SLI4_BDE_LEN_MASK));
+ bptr->u.data.low = sge[0].buffer_address_low;
+ bptr->u.data.high = sge[0].buffer_address_high;
+
+ trsp->fcp_response_length = cpu_to_le32(params->xmit_len);
+ }
+
+ if (params->flags & SLI4_IO_CONTINUATION)
+ trsp->eat_xc_ccpe |= SLI4_TRSP_WQE_XC;
+
+ trsp->xri_tag = cpu_to_le16(params->xri);
+ trsp->rpi = cpu_to_le16(params->rpi);
+
+ trsp->command = SLI4_WQE_FCP_TRSP64;
+ trsp->class_ag_byte |= SLI4_GENERIC_CLASS_CLASS_3;
+
+ trsp->remote_xid = cpu_to_le16(params->ox_id);
+ trsp->request_tag = cpu_to_le16(params->tag);
+ if (params->flags & SLI4_IO_DNRX)
+ trsp->ct_dnrx_byte |= SLI4_TRSP_WQE_DNRX;
+ else
+ trsp->ct_dnrx_byte &= ~SLI4_TRSP_WQE_DNRX;
+
+ trsp->lloc1_appid |= 0x1;
+ trsp->cq_id = cpu_to_le16(cq_id);
+ trsp->cmd_type_byte = SLI4_CMD_FCP_TRSP64_WQE;
+
+ /* The upper 7 bits of csctl is the priority */
+ if (params->cs_ctl & SLI4_MASK_CCP) {
+ trsp->eat_xc_ccpe |= SLI4_TRSP_WQE_CCPE;
+ trsp->ccp = (params->cs_ctl & SLI4_MASK_CCP);
+ }
+
+ if (params->app_id && sli4->wqe_size == SLI4_WQE_EXT_BYTES &&
+ !(trsp->eat_xc_ccpe & SLI4_TRSP_WQE_EAT)) {
+ trsp->lloc1_appid |= SLI4_TRSP_WQE_APPID;
+ trsp->qosd_xbl_hlm_dbde_wqes |= SLI4_TRSP_WQE_WQES;
+ trsp_128->dw[31] = params->app_id;
+ }
+ return 0;
+}
+
+int
+sli_fcp_tsend64_wqe(struct sli4 *sli4, void *buf, struct efc_dma *sgl,
+ u32 first_data_sge, u16 cq_id, u8 dif, u8 bs,
+ struct sli_fcp_tgt_params *params)
+{
+ struct sli4_fcp_tsend64_wqe *tsend = buf;
+ struct sli4_fcp_128byte_wqe *tsend_128 = buf;
+ struct sli4_sge *sge = NULL;
+ struct sli4_bde *bptr;
+
+ memset(buf, 0, sli4->wqe_size);
+
+ if (!sgl || !sgl->virt) {
+ efc_log_err(sli4, "bad parameter sgl=%p virt=%p\n",
+ sgl, sgl ? sgl->virt : NULL);
+ return -EIO;
+ }
+ sge = sgl->virt;
+
+ bptr = &tsend->bde;
+ if (sli4->params.sgl_pre_registered) {
+ tsend->ll_qd_xbl_hlm_iod_dbde &= ~SLI4_TSEND_WQE_XBL;
+
+ tsend->ll_qd_xbl_hlm_iod_dbde |= SLI4_TSEND_WQE_DBDE;
+
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (le32_to_cpu(sge[2].buffer_length) &
+ SLI4_BDE_LEN_MASK));
+
+ /* TSEND64_WQE specifies first two SGE are skipped (3rd is
+ * valid)
+ */
+ bptr->u.data.low = sge[2].buffer_address_low;
+ bptr->u.data.high = sge[2].buffer_address_high;
+ } else {
+ tsend->ll_qd_xbl_hlm_iod_dbde |= SLI4_TSEND_WQE_XBL;
+
+ /* if data is a single physical address, use a BDE */
+ if (!dif &&
+ params->xmit_len <= le32_to_cpu(sge[2].buffer_length)) {
+ tsend->ll_qd_xbl_hlm_iod_dbde |= SLI4_TSEND_WQE_DBDE;
+
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (le32_to_cpu(sge[2].buffer_length) &
+ SLI4_BDE_LEN_MASK));
+ /*
+ * TSEND64_WQE specifies first two SGE are skipped
+ * (i.e. 3rd is valid)
+ */
+ bptr->u.data.low =
+ sge[2].buffer_address_low;
+ bptr->u.data.high =
+ sge[2].buffer_address_high;
+ } else {
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(BLP)) |
+ (sgl->size &
+ SLI4_BDE_LEN_MASK));
+ bptr->u.blp.low =
+ cpu_to_le32(lower_32_bits(sgl->phys));
+ bptr->u.blp.high =
+ cpu_to_le32(upper_32_bits(sgl->phys));
+ }
+ }
+
+ tsend->relative_offset = cpu_to_le32(params->offset);
+
+ if (params->flags & SLI4_IO_CONTINUATION)
+ tsend->dw10byte2 |= SLI4_TSEND_XC;
+
+ tsend->xri_tag = cpu_to_le16(params->xri);
+
+ tsend->rpi = cpu_to_le16(params->rpi);
+ /* WQE uses relative offset */
+ tsend->class_pu_ar_byte |= 1 << SLI4_TSEND_WQE_PU_SHFT;
+
+ if (params->flags & SLI4_IO_AUTO_GOOD_RESPONSE)
+ tsend->class_pu_ar_byte |= SLI4_TSEND_WQE_AR;
+
+ tsend->command = SLI4_WQE_FCP_TSEND64;
+ tsend->class_pu_ar_byte |= SLI4_GENERIC_CLASS_CLASS_3;
+ tsend->ct_byte |= SLI4_GENERIC_CONTEXT_RPI << SLI4_TSEND_CT_SHFT;
+ tsend->ct_byte |= dif;
+ tsend->ct_byte |= bs << SLI4_TSEND_BS_SHFT;
+
+ tsend->remote_xid = cpu_to_le16(params->ox_id);
+
+ tsend->request_tag = cpu_to_le16(params->tag);
+
+ tsend->ll_qd_xbl_hlm_iod_dbde |= SLI4_TSEND_LEN_LOC_BIT2;
+
+ tsend->cq_id = cpu_to_le16(cq_id);
+
+ tsend->cmd_type_byte |= SLI4_CMD_FCP_TSEND64_WQE;
+
+ tsend->fcp_data_transmit_length = cpu_to_le32(params->xmit_len);
+
+ if (sli4->params.perf_hint) {
+ bptr = &tsend->first_data_bde;
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (le32_to_cpu(sge[first_data_sge].buffer_length) &
+ SLI4_BDE_LEN_MASK));
+ bptr->u.data.low =
+ sge[first_data_sge].buffer_address_low;
+ bptr->u.data.high =
+ sge[first_data_sge].buffer_address_high;
+ }
+
+ /* The upper 7 bits of csctl is the priority */
+ if (params->cs_ctl & SLI4_MASK_CCP) {
+ tsend->dw10byte2 |= SLI4_TSEND_CCPE;
+ tsend->ccp = (params->cs_ctl & SLI4_MASK_CCP);
+ }
+
+ if (params->app_id && sli4->wqe_size == SLI4_WQE_EXT_BYTES &&
+ !(tsend->dw10byte2 & SLI4_TSEND_EAT)) {
+ tsend->dw10byte0 |= SLI4_TSEND_APPID_VALID;
+ tsend->ll_qd_xbl_hlm_iod_dbde |= SLI4_TSEND_WQES;
+ tsend_128->dw[31] = params->app_id;
+ }
+ return 0;
+}
+
+int
+sli_gen_request64_wqe(struct sli4 *sli4, void *buf, struct efc_dma *sgl,
+ struct sli_ct_params *params)
+{
+ struct sli4_gen_request64_wqe *gen = buf;
+ struct sli4_sge *sge = NULL;
+ struct sli4_bde *bptr;
+
+ memset(buf, 0, sli4->wqe_size);
+
+ if (!sgl || !sgl->virt) {
+ efc_log_err(sli4, "bad parameter sgl=%p virt=%p\n",
+ sgl, sgl ? sgl->virt : NULL);
+ return -EIO;
+ }
+ sge = sgl->virt;
+ bptr = &gen->bde;
+
+ if (sli4->params.sgl_pre_registered) {
+ gen->dw10flags1 &= ~SLI4_GEN_REQ64_WQE_XBL;
+
+ gen->dw10flags1 |= SLI4_GEN_REQ64_WQE_DBDE;
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (params->xmit_len & SLI4_BDE_LEN_MASK));
+
+ bptr->u.data.low = sge[0].buffer_address_low;
+ bptr->u.data.high = sge[0].buffer_address_high;
+ } else {
+ gen->dw10flags1 |= SLI4_GEN_REQ64_WQE_XBL;
+
+ bptr->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(BLP)) |
+ ((2 * sizeof(struct sli4_sge)) &
+ SLI4_BDE_LEN_MASK));
+
+ bptr->u.blp.low =
+ cpu_to_le32(lower_32_bits(sgl->phys));
+ bptr->u.blp.high =
+ cpu_to_le32(upper_32_bits(sgl->phys));
+ }
+
+ gen->request_payload_length = cpu_to_le32(params->xmit_len);
+ gen->max_response_payload_length = cpu_to_le32(params->rsp_len);
+
+ gen->df_ctl = params->df_ctl;
+ gen->type = params->type;
+ gen->r_ctl = params->r_ctl;
+
+ gen->xri_tag = cpu_to_le16(params->xri);
+
+ gen->ct_byte = SLI4_GENERIC_CONTEXT_RPI << SLI4_GEN_REQ64_CT_SHFT;
+ gen->context_tag = cpu_to_le16(params->rpi);
+
+ gen->class_byte = SLI4_GENERIC_CLASS_CLASS_3;
+
+ gen->command = SLI4_WQE_GEN_REQUEST64;
+
+ gen->timer = params->timeout;
+
+ gen->request_tag = cpu_to_le16(params->tag);
+
+ gen->dw10flags1 |= SLI4_GEN_REQ64_WQE_IOD;
+
+ gen->dw10flags0 |= SLI4_GEN_REQ64_WQE_QOSD;
+
+ gen->cmd_type_byte = SLI4_CMD_GEN_REQUEST64_WQE;
+
+ gen->cq_id = cpu_to_le16(SLI4_CQ_DEFAULT);
+
+ return 0;
+}
+
+int
+sli_send_frame_wqe(struct sli4 *sli, void *buf, u8 sof, u8 eof, u32 *hdr,
+ struct efc_dma *payload, u32 req_len, u8 timeout, u16 xri,
+ u16 req_tag)
+{
+ struct sli4_send_frame_wqe *sf = buf;
+
+ memset(buf, 0, sli->wqe_size);
+
+ sf->dw10flags1 |= SLI4_SF_WQE_DBDE;
+ sf->bde.bde_type_buflen = cpu_to_le32(req_len &
+ SLI4_BDE_LEN_MASK);
+ sf->bde.u.data.low = cpu_to_le32(lower_32_bits(payload->phys));
+ sf->bde.u.data.high = cpu_to_le32(upper_32_bits(payload->phys));
+
+ /* Copy FC header */
+ sf->fc_header_0_1[0] = cpu_to_le32(hdr[0]);
+ sf->fc_header_0_1[1] = cpu_to_le32(hdr[1]);
+ sf->fc_header_2_5[0] = cpu_to_le32(hdr[2]);
+ sf->fc_header_2_5[1] = cpu_to_le32(hdr[3]);
+ sf->fc_header_2_5[2] = cpu_to_le32(hdr[4]);
+ sf->fc_header_2_5[3] = cpu_to_le32(hdr[5]);
+
+ sf->frame_length = cpu_to_le32(req_len);
+
+ sf->xri_tag = cpu_to_le16(xri);
+ sf->dw7flags0 &= ~SLI4_SF_PU;
+ sf->context_tag = 0;
+
+ sf->ct_byte &= ~SLI4_SF_CT;
+ sf->command = SLI4_WQE_SEND_FRAME;
+ sf->dw7flags0 |= SLI4_GENERIC_CLASS_CLASS_3;
+ sf->timer = timeout;
+
+ sf->request_tag = cpu_to_le16(req_tag);
+ sf->eof = eof;
+ sf->sof = sof;
+
+ sf->dw10flags1 &= ~SLI4_SF_QOSD;
+ sf->dw10flags0 |= SLI4_SF_LEN_LOC_BIT1;
+ sf->dw10flags2 &= ~SLI4_SF_XC;
+
+ sf->dw10flags1 |= SLI4_SF_XBL;
+
+ sf->cmd_type_byte |= SLI4_CMD_SEND_FRAME_WQE;
+ sf->cq_id = cpu_to_le16(0xffff);
+
+ return 0;
+}
+
+int
+sli_xmit_bls_rsp64_wqe(struct sli4 *sli, void *buf,
+ struct sli_bls_payload *payload,
+ struct sli_bls_params *params)
+{
+ struct sli4_xmit_bls_rsp_wqe *bls = buf;
+ u32 dw_ridflags = 0;
+
+ /*
+ * Callers can either specify RPI or S_ID, but not both
+ */
+ if (params->rpi_registered && params->s_id != U32_MAX) {
+ efc_log_info(sli, "S_ID specified for attached remote node %d\n",
+ params->rpi);
+ return -EIO;
+ }
+
+ memset(buf, 0, sli->wqe_size);
+
+ if (payload->type == SLI4_SLI_BLS_ACC) {
+ bls->payload_word0 =
+ cpu_to_le32((payload->u.acc.seq_id_last << 16) |
+ (payload->u.acc.seq_id_validity << 24));
+ bls->high_seq_cnt = payload->u.acc.high_seq_cnt;
+ bls->low_seq_cnt = payload->u.acc.low_seq_cnt;
+ } else if (payload->type == SLI4_SLI_BLS_RJT) {
+ bls->payload_word0 =
+ cpu_to_le32(*((u32 *)&payload->u.rjt));
+ dw_ridflags |= SLI4_BLS_RSP_WQE_AR;
+ } else {
+ efc_log_info(sli, "bad BLS type %#x\n", payload->type);
+ return -EIO;
+ }
+
+ bls->ox_id = payload->ox_id;
+ bls->rx_id = payload->rx_id;
+
+ if (params->rpi_registered) {
+ bls->dw8flags0 |=
+ SLI4_GENERIC_CONTEXT_RPI << SLI4_BLS_RSP_WQE_CT_SHFT;
+ bls->context_tag = cpu_to_le16(params->rpi);
+ } else {
+ bls->dw8flags0 |=
+ SLI4_GENERIC_CONTEXT_VPI << SLI4_BLS_RSP_WQE_CT_SHFT;
+ bls->context_tag = cpu_to_le16(params->vpi);
+
+ if (params->s_id != U32_MAX)
+ bls->local_n_port_id_dword |=
+ cpu_to_le32(params->s_id & 0x00ffffff);
+ else
+ bls->local_n_port_id_dword |=
+ cpu_to_le32(params->s_id & 0x00ffffff);
+
+ dw_ridflags = (dw_ridflags & ~SLI4_BLS_RSP_RID) |
+ (params->d_id & SLI4_BLS_RSP_RID);
+
+ bls->temporary_rpi = cpu_to_le16(params->rpi);
+ }
+
+ bls->xri_tag = cpu_to_le16(params->xri);
+
+ bls->dw8flags1 |= SLI4_GENERIC_CLASS_CLASS_3;
+
+ bls->command = SLI4_WQE_XMIT_BLS_RSP;
+
+ bls->request_tag = cpu_to_le16(params->tag);
+
+ bls->dw11flags1 |= SLI4_BLS_RSP_WQE_QOSD;
+
+ bls->remote_id_dword = cpu_to_le32(dw_ridflags);
+ bls->cq_id = cpu_to_le16(SLI4_CQ_DEFAULT);
+
+ bls->dw12flags0 |= SLI4_CMD_XMIT_BLS_RSP64_WQE;
+
+ return 0;
+}
+
+int
+sli_xmit_els_rsp64_wqe(struct sli4 *sli, void *buf, struct efc_dma *rsp,
+ struct sli_els_params *params)
+{
+ struct sli4_xmit_els_rsp64_wqe *els = buf;
+
+ memset(buf, 0, sli->wqe_size);
+
+ if (sli->params.sgl_pre_registered)
+ els->flags2 |= SLI4_ELS_DBDE;
+ else
+ els->flags2 |= SLI4_ELS_XBL;
+
+ els->els_response_payload.bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (params->rsp_len & SLI4_BDE_LEN_MASK));
+ els->els_response_payload.u.data.low =
+ cpu_to_le32(lower_32_bits(rsp->phys));
+ els->els_response_payload.u.data.high =
+ cpu_to_le32(upper_32_bits(rsp->phys));
+
+ els->els_response_payload_length = cpu_to_le32(params->rsp_len);
+
+ els->xri_tag = cpu_to_le16(params->xri);
+
+ els->class_byte |= SLI4_GENERIC_CLASS_CLASS_3;
+
+ els->command = SLI4_WQE_ELS_RSP64;
+
+ els->request_tag = cpu_to_le16(params->tag);
+
+ els->ox_id = cpu_to_le16(params->ox_id);
+
+ els->flags2 |= SLI4_ELS_QOSD;
+
+ els->cmd_type_wqec = SLI4_ELS_REQUEST64_CMD_GEN;
+
+ els->cq_id = cpu_to_le16(SLI4_CQ_DEFAULT);
+
+ if (params->rpi_registered) {
+ els->ct_byte |=
+ SLI4_GENERIC_CONTEXT_RPI << SLI4_ELS_CT_OFFSET;
+ els->context_tag = cpu_to_le16(params->rpi);
+ return 0;
+ }
+
+ els->ct_byte |= SLI4_GENERIC_CONTEXT_VPI << SLI4_ELS_CT_OFFSET;
+ els->context_tag = cpu_to_le16(params->vpi);
+ els->rid_dw = cpu_to_le32(params->d_id & SLI4_ELS_RID);
+ els->temporary_rpi = cpu_to_le16(params->rpi);
+ if (params->s_id != U32_MAX) {
+ els->sid_dw |=
+ cpu_to_le32(SLI4_ELS_SP | (params->s_id & SLI4_ELS_SID));
+ }
+
+ return 0;
+}
+
+int
+sli_xmit_sequence64_wqe(struct sli4 *sli4, void *buf, struct efc_dma *payload,
+ struct sli_ct_params *params)
+{
+ struct sli4_xmit_sequence64_wqe *xmit = buf;
+
+ memset(buf, 0, sli4->wqe_size);
+
+ if (!payload || !payload->virt) {
+ efc_log_err(sli4, "bad parameter sgl=%p virt=%p\n",
+ payload, payload ? payload->virt : NULL);
+ return -EIO;
+ }
+
+ if (sli4->params.sgl_pre_registered)
+ xmit->dw10w0 |= cpu_to_le16(SLI4_SEQ_WQE_DBDE);
+ else
+ xmit->dw10w0 |= cpu_to_le16(SLI4_SEQ_WQE_XBL);
+
+ xmit->bde.bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (params->rsp_len & SLI4_BDE_LEN_MASK));
+ xmit->bde.u.data.low =
+ cpu_to_le32(lower_32_bits(payload->phys));
+ xmit->bde.u.data.high =
+ cpu_to_le32(upper_32_bits(payload->phys));
+ xmit->sequence_payload_len = cpu_to_le32(params->rsp_len);
+
+ xmit->remote_n_port_id_dword |= cpu_to_le32(params->d_id & 0x00ffffff);
+
+ xmit->relative_offset = 0;
+
+ /* sequence initiative - this matches what is seen from
+ * FC switches in response to FCGS commands
+ */
+ xmit->dw5flags0 &= (~SLI4_SEQ_WQE_SI);
+ xmit->dw5flags0 &= (~SLI4_SEQ_WQE_FT);/* force transmit */
+ xmit->dw5flags0 &= (~SLI4_SEQ_WQE_XO);/* exchange responder */
+ xmit->dw5flags0 |= SLI4_SEQ_WQE_LS;/* last in seqence */
+ xmit->df_ctl = params->df_ctl;
+ xmit->type = params->type;
+ xmit->r_ctl = params->r_ctl;
+
+ xmit->xri_tag = cpu_to_le16(params->xri);
+ xmit->context_tag = cpu_to_le16(params->rpi);
+
+ xmit->dw7flags0 &= ~SLI4_SEQ_WQE_DIF;
+ xmit->dw7flags0 |=
+ SLI4_GENERIC_CONTEXT_RPI << SLI4_SEQ_WQE_CT_SHIFT;
+ xmit->dw7flags0 &= ~SLI4_SEQ_WQE_BS;
+
+ xmit->command = SLI4_WQE_XMIT_SEQUENCE64;
+ xmit->dw7flags1 |= SLI4_GENERIC_CLASS_CLASS_3;
+ xmit->dw7flags1 &= ~SLI4_SEQ_WQE_PU;
+ xmit->timer = params->timeout;
+
+ xmit->abort_tag = 0;
+ xmit->request_tag = cpu_to_le16(params->tag);
+ xmit->remote_xid = cpu_to_le16(params->ox_id);
+
+ xmit->dw10w0 |=
+ cpu_to_le16(SLI4_ELS_REQUEST64_DIR_READ << SLI4_SEQ_WQE_IOD_SHIFT);
+
+ xmit->cmd_type_wqec_byte |= SLI4_CMD_XMIT_SEQUENCE64_WQE;
+
+ xmit->dw10w0 |= cpu_to_le16(2 << SLI4_SEQ_WQE_LEN_LOC_SHIFT);
+
+ xmit->cq_id = cpu_to_le16(0xFFFF);
+
+ return 0;
+}
+
+int
+sli_requeue_xri_wqe(struct sli4 *sli4, void *buf, u16 xri, u16 tag, u16 cq_id)
+{
+ struct sli4_requeue_xri_wqe *requeue = buf;
+
+ memset(buf, 0, sli4->wqe_size);
+
+ requeue->command = SLI4_WQE_REQUEUE_XRI;
+ requeue->xri_tag = cpu_to_le16(xri);
+ requeue->request_tag = cpu_to_le16(tag);
+ requeue->flags2 |= cpu_to_le16(SLI4_REQU_XRI_WQE_XC);
+ requeue->flags1 |= cpu_to_le16(SLI4_REQU_XRI_WQE_QOSD);
+ requeue->cq_id = cpu_to_le16(cq_id);
+ requeue->cmd_type_wqec_byte = SLI4_CMD_REQUEUE_XRI_WQE;
+ return 0;
+}
+
+int
+sli_fc_process_link_attention(struct sli4 *sli4, void *acqe)
+{
+ struct sli4_link_attention *link_attn = acqe;
+ struct sli4_link_event event = { 0 };
+
+ efc_log_info(sli4, "link=%d attn_type=%#x top=%#x speed=%#x pfault=%#x\n",
+ link_attn->link_number, link_attn->attn_type,
+ link_attn->topology, link_attn->port_speed,
+ link_attn->port_fault);
+ efc_log_info(sli4, "shared_lnk_status=%#x logl_lnk_speed=%#x evttag=%#x\n",
+ link_attn->shared_link_status,
+ le16_to_cpu(link_attn->logical_link_speed),
+ le32_to_cpu(link_attn->event_tag));
+
+ if (!sli4->link)
+ return -EIO;
+
+ event.medium = SLI4_LINK_MEDIUM_FC;
+
+ switch (link_attn->attn_type) {
+ case SLI4_LNK_ATTN_TYPE_LINK_UP:
+ event.status = SLI4_LINK_STATUS_UP;
+ break;
+ case SLI4_LNK_ATTN_TYPE_LINK_DOWN:
+ event.status = SLI4_LINK_STATUS_DOWN;
+ break;
+ case SLI4_LNK_ATTN_TYPE_NO_HARD_ALPA:
+ efc_log_info(sli4, "attn_type: no hard alpa\n");
+ event.status = SLI4_LINK_STATUS_NO_ALPA;
+ break;
+ default:
+ efc_log_info(sli4, "attn_type: unknown\n");
+ break;
+ }
+
+ switch (link_attn->event_type) {
+ case SLI4_EVENT_LINK_ATTENTION:
+ break;
+ case SLI4_EVENT_SHARED_LINK_ATTENTION:
+ efc_log_info(sli4, "event_type: FC shared link event\n");
+ break;
+ default:
+ efc_log_info(sli4, "event_type: unknown\n");
+ break;
+ }
+
+ switch (link_attn->topology) {
+ case SLI4_LNK_ATTN_P2P:
+ event.topology = SLI4_LINK_TOPO_NON_FC_AL;
+ break;
+ case SLI4_LNK_ATTN_FC_AL:
+ event.topology = SLI4_LINK_TOPO_FC_AL;
+ break;
+ case SLI4_LNK_ATTN_INTERNAL_LOOPBACK:
+ efc_log_info(sli4, "topology Internal loopback\n");
+ event.topology = SLI4_LINK_TOPO_LOOPBACK_INTERNAL;
+ break;
+ case SLI4_LNK_ATTN_SERDES_LOOPBACK:
+ efc_log_info(sli4, "topology serdes loopback\n");
+ event.topology = SLI4_LINK_TOPO_LOOPBACK_EXTERNAL;
+ break;
+ default:
+ efc_log_info(sli4, "topology: unknown\n");
+ break;
+ }
+
+ event.speed = link_attn->port_speed * 1000;
+
+ sli4->link(sli4->link_arg, (void *)&event);
+
+ return 0;
+}
+
+int
+sli_fc_cqe_parse(struct sli4 *sli4, struct sli4_queue *cq,
+ u8 *cqe, enum sli4_qentry *etype, u16 *r_id)
+{
+ u8 code = cqe[SLI4_CQE_CODE_OFFSET];
+ int rc;
+
+ switch (code) {
+ case SLI4_CQE_CODE_WORK_REQUEST_COMPLETION:
+ {
+ struct sli4_fc_wcqe *wcqe = (void *)cqe;
+
+ *etype = SLI4_QENTRY_WQ;
+ *r_id = le16_to_cpu(wcqe->request_tag);
+ rc = wcqe->status;
+
+ /* Flag errors except for FCP_RSP_FAILURE */
+ if (rc && rc != SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE) {
+ efc_log_info(sli4, "WCQE: status=%#x hw_status=%#x tag=%#x\n",
+ wcqe->status, wcqe->hw_status,
+ le16_to_cpu(wcqe->request_tag));
+ efc_log_info(sli4, "w1=%#x w2=%#x xb=%d\n",
+ le32_to_cpu(wcqe->wqe_specific_1),
+ le32_to_cpu(wcqe->wqe_specific_2),
+ (wcqe->flags & SLI4_WCQE_XB));
+ efc_log_info(sli4, " %08X %08X %08X %08X\n",
+ ((u32 *)cqe)[0], ((u32 *)cqe)[1],
+ ((u32 *)cqe)[2], ((u32 *)cqe)[3]);
+ }
+
+ break;
+ }
+ case SLI4_CQE_CODE_RQ_ASYNC:
+ {
+ struct sli4_fc_async_rcqe *rcqe = (void *)cqe;
+
+ *etype = SLI4_QENTRY_RQ;
+ *r_id = le16_to_cpu(rcqe->fcfi_rq_id_word) & SLI4_RACQE_RQ_ID;
+ rc = rcqe->status;
+ break;
+ }
+ case SLI4_CQE_CODE_RQ_ASYNC_V1:
+ {
+ struct sli4_fc_async_rcqe_v1 *rcqe = (void *)cqe;
+
+ *etype = SLI4_QENTRY_RQ;
+ *r_id = le16_to_cpu(rcqe->rq_id);
+ rc = rcqe->status;
+ break;
+ }
+ case SLI4_CQE_CODE_OPTIMIZED_WRITE_CMD:
+ {
+ struct sli4_fc_optimized_write_cmd_cqe *optcqe = (void *)cqe;
+
+ *etype = SLI4_QENTRY_OPT_WRITE_CMD;
+ *r_id = le16_to_cpu(optcqe->rq_id);
+ rc = optcqe->status;
+ break;
+ }
+ case SLI4_CQE_CODE_OPTIMIZED_WRITE_DATA:
+ {
+ struct sli4_fc_optimized_write_data_cqe *dcqe = (void *)cqe;
+
+ *etype = SLI4_QENTRY_OPT_WRITE_DATA;
+ *r_id = le16_to_cpu(dcqe->xri);
+ rc = dcqe->status;
+
+ /* Flag errors */
+ if (rc != SLI4_FC_WCQE_STATUS_SUCCESS) {
+ efc_log_info(sli4, "Optimized DATA CQE: status=%#x\n",
+ dcqe->status);
+ efc_log_info(sli4, "hstat=%#x xri=%#x dpl=%#x w3=%#x xb=%d\n",
+ dcqe->hw_status, le16_to_cpu(dcqe->xri),
+ le32_to_cpu(dcqe->total_data_placed),
+ ((u32 *)cqe)[3],
+ (dcqe->flags & SLI4_OCQE_XB));
+ }
+ break;
+ }
+ case SLI4_CQE_CODE_RQ_COALESCING:
+ {
+ struct sli4_fc_coalescing_rcqe *rcqe = (void *)cqe;
+
+ *etype = SLI4_QENTRY_RQ;
+ *r_id = le16_to_cpu(rcqe->rq_id);
+ rc = rcqe->status;
+ break;
+ }
+ case SLI4_CQE_CODE_XRI_ABORTED:
+ {
+ struct sli4_fc_xri_aborted_cqe *xa = (void *)cqe;
+
+ *etype = SLI4_QENTRY_XABT;
+ *r_id = le16_to_cpu(xa->xri);
+ rc = 0;
+ break;
+ }
+ case SLI4_CQE_CODE_RELEASE_WQE:
+ {
+ struct sli4_fc_wqec *wqec = (void *)cqe;
+
+ *etype = SLI4_QENTRY_WQ_RELEASE;
+ *r_id = le16_to_cpu(wqec->wq_id);
+ rc = 0;
+ break;
+ }
+ default:
+ efc_log_info(sli4, "CQE completion code %d not handled\n",
+ code);
+ *etype = SLI4_QENTRY_MAX;
+ *r_id = U16_MAX;
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+u32
+sli_fc_response_length(struct sli4 *sli4, u8 *cqe)
+{
+ struct sli4_fc_wcqe *wcqe = (void *)cqe;
+
+ return le32_to_cpu(wcqe->wqe_specific_1);
+}
+
+u32
+sli_fc_io_length(struct sli4 *sli4, u8 *cqe)
+{
+ struct sli4_fc_wcqe *wcqe = (void *)cqe;
+
+ return le32_to_cpu(wcqe->wqe_specific_1);
+}
+
+int
+sli_fc_els_did(struct sli4 *sli4, u8 *cqe, u32 *d_id)
+{
+ struct sli4_fc_wcqe *wcqe = (void *)cqe;
+
+ *d_id = 0;
+
+ if (wcqe->status)
+ return -EIO;
+ *d_id = le32_to_cpu(wcqe->wqe_specific_2) & 0x00ffffff;
+ return 0;
+}
+
+u32
+sli_fc_ext_status(struct sli4 *sli4, u8 *cqe)
+{
+ struct sli4_fc_wcqe *wcqe = (void *)cqe;
+ u32 mask;
+
+ switch (wcqe->status) {
+ case SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE:
+ mask = U32_MAX;
+ break;
+ case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
+ case SLI4_FC_WCQE_STATUS_CMD_REJECT:
+ mask = 0xff;
+ break;
+ case SLI4_FC_WCQE_STATUS_NPORT_RJT:
+ case SLI4_FC_WCQE_STATUS_FABRIC_RJT:
+ case SLI4_FC_WCQE_STATUS_NPORT_BSY:
+ case SLI4_FC_WCQE_STATUS_FABRIC_BSY:
+ case SLI4_FC_WCQE_STATUS_LS_RJT:
+ mask = U32_MAX;
+ break;
+ case SLI4_FC_WCQE_STATUS_DI_ERROR:
+ mask = U32_MAX;
+ break;
+ default:
+ mask = 0;
+ }
+
+ return le32_to_cpu(wcqe->wqe_specific_2) & mask;
+}
+
+int
+sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, u16 *rq_id, u32 *index)
+{
+ int rc = -EIO;
+ u8 code = 0;
+ u16 rq_element_index;
+
+ *rq_id = 0;
+ *index = U32_MAX;
+
+ code = cqe[SLI4_CQE_CODE_OFFSET];
+
+ /* Retrieve the RQ index from the completion */
+ if (code == SLI4_CQE_CODE_RQ_ASYNC) {
+ struct sli4_fc_async_rcqe *rcqe = (void *)cqe;
+
+ *rq_id = le16_to_cpu(rcqe->fcfi_rq_id_word) & SLI4_RACQE_RQ_ID;
+ rq_element_index =
+ le16_to_cpu(rcqe->rq_elmt_indx_word) & SLI4_RACQE_RQ_EL_INDX;
+ *index = rq_element_index;
+ if (rcqe->status == SLI4_FC_ASYNC_RQ_SUCCESS) {
+ rc = 0;
+ } else {
+ rc = rcqe->status;
+ efc_log_info(sli4, "status=%02x (%s) rq_id=%d\n",
+ rcqe->status,
+ sli_fc_get_status_string(rcqe->status),
+ le16_to_cpu(rcqe->fcfi_rq_id_word) &
+ SLI4_RACQE_RQ_ID);
+
+ efc_log_info(sli4, "pdpl=%x sof=%02x eof=%02x hdpl=%x\n",
+ le16_to_cpu(rcqe->data_placement_length),
+ rcqe->sof_byte, rcqe->eof_byte,
+ rcqe->hdpl_byte & SLI4_RACQE_HDPL);
+ }
+ } else if (code == SLI4_CQE_CODE_RQ_ASYNC_V1) {
+ struct sli4_fc_async_rcqe_v1 *rcqe_v1 = (void *)cqe;
+
+ *rq_id = le16_to_cpu(rcqe_v1->rq_id);
+ rq_element_index =
+ (le16_to_cpu(rcqe_v1->rq_elmt_indx_word) &
+ SLI4_RACQE_RQ_EL_INDX);
+ *index = rq_element_index;
+ if (rcqe_v1->status == SLI4_FC_ASYNC_RQ_SUCCESS) {
+ rc = 0;
+ } else {
+ rc = rcqe_v1->status;
+ efc_log_info(sli4, "status=%02x (%s) rq_id=%d, index=%x\n",
+ rcqe_v1->status,
+ sli_fc_get_status_string(rcqe_v1->status),
+ le16_to_cpu(rcqe_v1->rq_id), rq_element_index);
+
+ efc_log_info(sli4, "pdpl=%x sof=%02x eof=%02x hdpl=%x\n",
+ le16_to_cpu(rcqe_v1->data_placement_length),
+ rcqe_v1->sof_byte, rcqe_v1->eof_byte,
+ rcqe_v1->hdpl_byte & SLI4_RACQE_HDPL);
+ }
+ } else if (code == SLI4_CQE_CODE_OPTIMIZED_WRITE_CMD) {
+ struct sli4_fc_optimized_write_cmd_cqe *optcqe = (void *)cqe;
+
+ *rq_id = le16_to_cpu(optcqe->rq_id);
+ *index = le16_to_cpu(optcqe->w1) & SLI4_OCQE_RQ_EL_INDX;
+ if (optcqe->status == SLI4_FC_ASYNC_RQ_SUCCESS) {
+ rc = 0;
+ } else {
+ rc = optcqe->status;
+ efc_log_info(sli4, "stat=%02x (%s) rqid=%d, idx=%x pdpl=%x\n",
+ optcqe->status,
+ sli_fc_get_status_string(optcqe->status),
+ le16_to_cpu(optcqe->rq_id), *index,
+ le16_to_cpu(optcqe->data_placement_length));
+
+ efc_log_info(sli4, "hdpl=%x oox=%d agxr=%d xri=0x%x rpi=%x\n",
+ (optcqe->hdpl_vld & SLI4_OCQE_HDPL),
+ (optcqe->flags1 & SLI4_OCQE_OOX),
+ (optcqe->flags1 & SLI4_OCQE_AGXR),
+ optcqe->xri, le16_to_cpu(optcqe->rpi));
+ }
+ } else if (code == SLI4_CQE_CODE_RQ_COALESCING) {
+ struct sli4_fc_coalescing_rcqe *rcqe = (void *)cqe;
+
+ rq_element_index = (le16_to_cpu(rcqe->rq_elmt_indx_word) &
+ SLI4_RCQE_RQ_EL_INDX);
+
+ *rq_id = le16_to_cpu(rcqe->rq_id);
+ if (rcqe->status == SLI4_FC_COALESCE_RQ_SUCCESS) {
+ *index = rq_element_index;
+ rc = 0;
+ } else {
+ *index = U32_MAX;
+ rc = rcqe->status;
+
+ efc_log_info(sli4, "stat=%02x (%s) rq_id=%d, idx=%x\n",
+ rcqe->status,
+ sli_fc_get_status_string(rcqe->status),
+ le16_to_cpu(rcqe->rq_id), rq_element_index);
+ efc_log_info(sli4, "rq_id=%#x sdpl=%x\n",
+ le16_to_cpu(rcqe->rq_id),
+ le16_to_cpu(rcqe->seq_placement_length));
+ }
+ } else {
+ struct sli4_fc_async_rcqe *rcqe = (void *)cqe;
+
+ *index = U32_MAX;
+ rc = rcqe->status;
+
+ efc_log_info(sli4, "status=%02x rq_id=%d, index=%x pdpl=%x\n",
+ rcqe->status,
+ le16_to_cpu(rcqe->fcfi_rq_id_word) & SLI4_RACQE_RQ_ID,
+ (le16_to_cpu(rcqe->rq_elmt_indx_word) & SLI4_RACQE_RQ_EL_INDX),
+ le16_to_cpu(rcqe->data_placement_length));
+ efc_log_info(sli4, "sof=%02x eof=%02x hdpl=%x\n",
+ rcqe->sof_byte, rcqe->eof_byte,
+ rcqe->hdpl_byte & SLI4_RACQE_HDPL);
+ }
+
+ return rc;
+}
+
+static int
+sli_bmbx_wait(struct sli4 *sli4, u32 msec)
+{
+ u32 val;
+ unsigned long end;
+
+ /* Wait for the bootstrap mailbox to report "ready" */
+ end = jiffies + msecs_to_jiffies(msec);
+ do {
+ val = readl(sli4->reg[0] + SLI4_BMBX_REG);
+ if (val & SLI4_BMBX_RDY)
+ return 0;
+
+ usleep_range(1000, 2000);
+ } while (time_before(jiffies, end));
+
+ return -EIO;
+}
+
+static int
+sli_bmbx_write(struct sli4 *sli4)
+{
+ u32 val;
+
+ /* write buffer location to bootstrap mailbox register */
+ val = sli_bmbx_write_hi(sli4->bmbx.phys);
+ writel(val, (sli4->reg[0] + SLI4_BMBX_REG));
+
+ if (sli_bmbx_wait(sli4, SLI4_BMBX_DELAY_US)) {
+ efc_log_crit(sli4, "BMBX WRITE_HI failed\n");
+ return -EIO;
+ }
+ val = sli_bmbx_write_lo(sli4->bmbx.phys);
+ writel(val, (sli4->reg[0] + SLI4_BMBX_REG));
+
+ /* wait for SLI Port to set ready bit */
+ return sli_bmbx_wait(sli4, SLI4_BMBX_TIMEOUT_MSEC);
+}
+
+int
+sli_bmbx_command(struct sli4 *sli4)
+{
+ void *cqe = (u8 *)sli4->bmbx.virt + SLI4_BMBX_SIZE;
+
+ if (sli_fw_error_status(sli4) > 0) {
+ efc_log_crit(sli4, "Chip is in an error state -Mailbox command rejected");
+ efc_log_crit(sli4, " status=%#x error1=%#x error2=%#x\n",
+ sli_reg_read_status(sli4),
+ sli_reg_read_err1(sli4),
+ sli_reg_read_err2(sli4));
+ return -EIO;
+ }
+
+ /* Submit a command to the bootstrap mailbox and check the status */
+ if (sli_bmbx_write(sli4)) {
+ efc_log_crit(sli4, "bmbx write fail phys=%pad reg=%#x\n",
+ &sli4->bmbx.phys, readl(sli4->reg[0] + SLI4_BMBX_REG));
+ return -EIO;
+ }
+
+ /* check completion queue entry status */
+ if (le32_to_cpu(((struct sli4_mcqe *)cqe)->dw3_flags) &
+ SLI4_MCQE_VALID) {
+ return sli_cqe_mq(sli4, cqe);
+ }
+ efc_log_crit(sli4, "invalid or wrong type\n");
+ return -EIO;
+}
+
+int
+sli_cmd_config_link(struct sli4 *sli4, void *buf)
+{
+ struct sli4_cmd_config_link *config_link = buf;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ config_link->hdr.command = SLI4_MBX_CMD_CONFIG_LINK;
+
+ /* Port interprets zero in a field as "use default value" */
+
+ return 0;
+}
+
+int
+sli_cmd_down_link(struct sli4 *sli4, void *buf)
+{
+ struct sli4_mbox_command_header *hdr = buf;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ hdr->command = SLI4_MBX_CMD_DOWN_LINK;
+
+ /* Port interprets zero in a field as "use default value" */
+
+ return 0;
+}
+
+int
+sli_cmd_dump_type4(struct sli4 *sli4, void *buf, u16 wki)
+{
+ struct sli4_cmd_dump4 *cmd = buf;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ cmd->hdr.command = SLI4_MBX_CMD_DUMP;
+ cmd->type_dword = cpu_to_le32(0x4);
+ cmd->wki_selection = cpu_to_le16(wki);
+ return 0;
+}
+
+int
+sli_cmd_common_read_transceiver_data(struct sli4 *sli4, void *buf, u32 page_num,
+ struct efc_dma *dma)
+{
+ struct sli4_rqst_cmn_read_transceiver_data *req = NULL;
+ u32 psize;
+
+ if (!dma)
+ psize = SLI4_CFG_PYLD_LENGTH(cmn_read_transceiver_data);
+ else
+ psize = dma->size;
+
+ req = sli_config_cmd_init(sli4, buf, psize, dma);
+ if (!req)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&req->hdr, SLI4_CMN_READ_TRANS_DATA,
+ SLI4_SUBSYSTEM_COMMON, CMD_V0,
+ SLI4_RQST_PYLD_LEN(cmn_read_transceiver_data));
+
+ req->page_number = cpu_to_le32(page_num);
+ req->port = cpu_to_le32(sli4->port_number);
+
+ return 0;
+}
+
+int
+sli_cmd_read_link_stats(struct sli4 *sli4, void *buf, u8 req_ext_counters,
+ u8 clear_overflow_flags,
+ u8 clear_all_counters)
+{
+ struct sli4_cmd_read_link_stats *cmd = buf;
+ u32 flags;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ cmd->hdr.command = SLI4_MBX_CMD_READ_LNK_STAT;
+
+ flags = 0;
+ if (req_ext_counters)
+ flags |= SLI4_READ_LNKSTAT_REC;
+ if (clear_all_counters)
+ flags |= SLI4_READ_LNKSTAT_CLRC;
+ if (clear_overflow_flags)
+ flags |= SLI4_READ_LNKSTAT_CLOF;
+
+ cmd->dw1_flags = cpu_to_le32(flags);
+ return 0;
+}
+
+int
+sli_cmd_read_status(struct sli4 *sli4, void *buf, u8 clear_counters)
+{
+ struct sli4_cmd_read_status *cmd = buf;
+ u32 flags = 0;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ cmd->hdr.command = SLI4_MBX_CMD_READ_STATUS;
+ if (clear_counters)
+ flags |= SLI4_READSTATUS_CLEAR_COUNTERS;
+ else
+ flags &= ~SLI4_READSTATUS_CLEAR_COUNTERS;
+
+ cmd->dw1_flags = cpu_to_le32(flags);
+ return 0;
+}
+
+int
+sli_cmd_init_link(struct sli4 *sli4, void *buf, u32 speed, u8 reset_alpa)
+{
+ struct sli4_cmd_init_link *init_link = buf;
+ u32 flags = 0;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ init_link->hdr.command = SLI4_MBX_CMD_INIT_LINK;
+
+ init_link->sel_reset_al_pa_dword =
+ cpu_to_le32(reset_alpa);
+ flags &= ~SLI4_INIT_LINK_F_LOOPBACK;
+
+ init_link->link_speed_sel_code = cpu_to_le32(speed);
+ switch (speed) {
+ case SLI4_LINK_SPEED_1G:
+ case SLI4_LINK_SPEED_2G:
+ case SLI4_LINK_SPEED_4G:
+ case SLI4_LINK_SPEED_8G:
+ case SLI4_LINK_SPEED_16G:
+ case SLI4_LINK_SPEED_32G:
+ case SLI4_LINK_SPEED_64G:
+ flags |= SLI4_INIT_LINK_F_FIXED_SPEED;
+ break;
+ case SLI4_LINK_SPEED_10G:
+ efc_log_info(sli4, "unsupported FC speed %d\n", speed);
+ init_link->flags0 = cpu_to_le32(flags);
+ return -EIO;
+ }
+
+ switch (sli4->topology) {
+ case SLI4_READ_CFG_TOPO_FC:
+ /* Attempt P2P but failover to FC-AL */
+ flags |= SLI4_INIT_LINK_F_FAIL_OVER;
+ flags |= SLI4_INIT_LINK_F_P2P_FAIL_OVER;
+ break;
+ case SLI4_READ_CFG_TOPO_FC_AL:
+ flags |= SLI4_INIT_LINK_F_FCAL_ONLY;
+ if (speed == SLI4_LINK_SPEED_16G ||
+ speed == SLI4_LINK_SPEED_32G) {
+ efc_log_info(sli4, "unsupported FC-AL speed %d\n",
+ speed);
+ init_link->flags0 = cpu_to_le32(flags);
+ return -EIO;
+ }
+ break;
+ case SLI4_READ_CFG_TOPO_NON_FC_AL:
+ flags |= SLI4_INIT_LINK_F_P2P_ONLY;
+ break;
+ default:
+
+ efc_log_info(sli4, "unsupported topology %#x\n", sli4->topology);
+
+ init_link->flags0 = cpu_to_le32(flags);
+ return -EIO;
+ }
+
+ flags &= ~SLI4_INIT_LINK_F_UNFAIR;
+ flags &= ~SLI4_INIT_LINK_F_NO_LIRP;
+ flags &= ~SLI4_INIT_LINK_F_LOOP_VALID_CHK;
+ flags &= ~SLI4_INIT_LINK_F_NO_LISA;
+ flags &= ~SLI4_INIT_LINK_F_PICK_HI_ALPA;
+ init_link->flags0 = cpu_to_le32(flags);
+
+ return 0;
+}
+
+int
+sli_cmd_init_vfi(struct sli4 *sli4, void *buf, u16 vfi, u16 fcfi, u16 vpi)
+{
+ struct sli4_cmd_init_vfi *init_vfi = buf;
+ u16 flags = 0;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ init_vfi->hdr.command = SLI4_MBX_CMD_INIT_VFI;
+ init_vfi->vfi = cpu_to_le16(vfi);
+ init_vfi->fcfi = cpu_to_le16(fcfi);
+
+ /*
+ * If the VPI is valid, initialize it at the same time as
+ * the VFI
+ */
+ if (vpi != U16_MAX) {
+ flags |= SLI4_INIT_VFI_FLAG_VP;
+ init_vfi->flags0_word = cpu_to_le16(flags);
+ init_vfi->vpi = cpu_to_le16(vpi);
+ }
+
+ return 0;
+}
+
+int
+sli_cmd_init_vpi(struct sli4 *sli4, void *buf, u16 vpi, u16 vfi)
+{
+ struct sli4_cmd_init_vpi *init_vpi = buf;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ init_vpi->hdr.command = SLI4_MBX_CMD_INIT_VPI;
+ init_vpi->vpi = cpu_to_le16(vpi);
+ init_vpi->vfi = cpu_to_le16(vfi);
+
+ return 0;
+}
+
+int
+sli_cmd_post_xri(struct sli4 *sli4, void *buf, u16 xri_base, u16 xri_count)
+{
+ struct sli4_cmd_post_xri *post_xri = buf;
+ u16 xri_count_flags = 0;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ post_xri->hdr.command = SLI4_MBX_CMD_POST_XRI;
+ post_xri->xri_base = cpu_to_le16(xri_base);
+ xri_count_flags = xri_count & SLI4_POST_XRI_COUNT;
+ xri_count_flags |= SLI4_POST_XRI_FLAG_ENX;
+ xri_count_flags |= SLI4_POST_XRI_FLAG_VAL;
+ post_xri->xri_count_flags = cpu_to_le16(xri_count_flags);
+
+ return 0;
+}
+
+int
+sli_cmd_release_xri(struct sli4 *sli4, void *buf, u8 num_xri)
+{
+ struct sli4_cmd_release_xri *release_xri = buf;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ release_xri->hdr.command = SLI4_MBX_CMD_RELEASE_XRI;
+ release_xri->xri_count_word = cpu_to_le16(num_xri &
+ SLI4_RELEASE_XRI_COUNT);
+
+ return 0;
+}
+
+static int
+sli_cmd_read_config(struct sli4 *sli4, void *buf)
+{
+ struct sli4_cmd_read_config *read_config = buf;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ read_config->hdr.command = SLI4_MBX_CMD_READ_CONFIG;
+
+ return 0;
+}
+
+int
+sli_cmd_read_nvparms(struct sli4 *sli4, void *buf)
+{
+ struct sli4_cmd_read_nvparms *read_nvparms = buf;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ read_nvparms->hdr.command = SLI4_MBX_CMD_READ_NVPARMS;
+
+ return 0;
+}
+
+int
+sli_cmd_write_nvparms(struct sli4 *sli4, void *buf, u8 *wwpn, u8 *wwnn,
+ u8 hard_alpa, u32 preferred_d_id)
+{
+ struct sli4_cmd_write_nvparms *write_nvparms = buf;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ write_nvparms->hdr.command = SLI4_MBX_CMD_WRITE_NVPARMS;
+ memcpy(write_nvparms->wwpn, wwpn, 8);
+ memcpy(write_nvparms->wwnn, wwnn, 8);
+
+ write_nvparms->hard_alpa_d_id =
+ cpu_to_le32((preferred_d_id << 8) | hard_alpa);
+ return 0;
+}
+
+static int
+sli_cmd_read_rev(struct sli4 *sli4, void *buf, struct efc_dma *vpd)
+{
+ struct sli4_cmd_read_rev *read_rev = buf;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ read_rev->hdr.command = SLI4_MBX_CMD_READ_REV;
+
+ if (vpd && vpd->size) {
+ read_rev->flags0_word |= cpu_to_le16(SLI4_READ_REV_FLAG_VPD);
+
+ read_rev->available_length_dword =
+ cpu_to_le32(vpd->size &
+ SLI4_READ_REV_AVAILABLE_LENGTH);
+
+ read_rev->hostbuf.low =
+ cpu_to_le32(lower_32_bits(vpd->phys));
+ read_rev->hostbuf.high =
+ cpu_to_le32(upper_32_bits(vpd->phys));
+ }
+
+ return 0;
+}
+
+int
+sli_cmd_read_sparm64(struct sli4 *sli4, void *buf, struct efc_dma *dma, u16 vpi)
+{
+ struct sli4_cmd_read_sparm64 *read_sparm64 = buf;
+
+ if (vpi == U16_MAX) {
+ efc_log_err(sli4, "special VPI not supported!!!\n");
+ return -EIO;
+ }
+
+ if (!dma || !dma->phys) {
+ efc_log_err(sli4, "bad DMA buffer\n");
+ return -EIO;
+ }
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ read_sparm64->hdr.command = SLI4_MBX_CMD_READ_SPARM64;
+
+ read_sparm64->bde_64.bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (dma->size & SLI4_BDE_LEN_MASK));
+ read_sparm64->bde_64.u.data.low =
+ cpu_to_le32(lower_32_bits(dma->phys));
+ read_sparm64->bde_64.u.data.high =
+ cpu_to_le32(upper_32_bits(dma->phys));
+
+ read_sparm64->vpi = cpu_to_le16(vpi);
+
+ return 0;
+}
+
+int
+sli_cmd_read_topology(struct sli4 *sli4, void *buf, struct efc_dma *dma)
+{
+ struct sli4_cmd_read_topology *read_topo = buf;
+
+ if (!dma || !dma->size)
+ return -EIO;
+
+ if (dma->size < SLI4_MIN_LOOP_MAP_BYTES) {
+ efc_log_err(sli4, "loop map buffer too small %zx\n", dma->size);
+ return -EIO;
+ }
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ read_topo->hdr.command = SLI4_MBX_CMD_READ_TOPOLOGY;
+
+ memset(dma->virt, 0, dma->size);
+
+ read_topo->bde_loop_map.bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (dma->size & SLI4_BDE_LEN_MASK));
+ read_topo->bde_loop_map.u.data.low =
+ cpu_to_le32(lower_32_bits(dma->phys));
+ read_topo->bde_loop_map.u.data.high =
+ cpu_to_le32(upper_32_bits(dma->phys));
+
+ return 0;
+}
+
+int
+sli_cmd_reg_fcfi(struct sli4 *sli4, void *buf, u16 index,
+ struct sli4_cmd_rq_cfg *rq_cfg)
+{
+ struct sli4_cmd_reg_fcfi *reg_fcfi = buf;
+ u32 i;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ reg_fcfi->hdr.command = SLI4_MBX_CMD_REG_FCFI;
+
+ reg_fcfi->fcf_index = cpu_to_le16(index);
+
+ for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) {
+ switch (i) {
+ case 0:
+ reg_fcfi->rqid0 = rq_cfg[0].rq_id;
+ break;
+ case 1:
+ reg_fcfi->rqid1 = rq_cfg[1].rq_id;
+ break;
+ case 2:
+ reg_fcfi->rqid2 = rq_cfg[2].rq_id;
+ break;
+ case 3:
+ reg_fcfi->rqid3 = rq_cfg[3].rq_id;
+ break;
+ }
+ reg_fcfi->rq_cfg[i].r_ctl_mask = rq_cfg[i].r_ctl_mask;
+ reg_fcfi->rq_cfg[i].r_ctl_match = rq_cfg[i].r_ctl_match;
+ reg_fcfi->rq_cfg[i].type_mask = rq_cfg[i].type_mask;
+ reg_fcfi->rq_cfg[i].type_match = rq_cfg[i].type_match;
+ }
+
+ return 0;
+}
+
+int
+sli_cmd_reg_fcfi_mrq(struct sli4 *sli4, void *buf, u8 mode, u16 fcf_index,
+ u8 rq_selection_policy, u8 mrq_bit_mask, u16 num_mrqs,
+ struct sli4_cmd_rq_cfg *rq_cfg)
+{
+ struct sli4_cmd_reg_fcfi_mrq *reg_fcfi_mrq = buf;
+ u32 i;
+ u32 mrq_flags = 0;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ reg_fcfi_mrq->hdr.command = SLI4_MBX_CMD_REG_FCFI_MRQ;
+ if (mode == SLI4_CMD_REG_FCFI_SET_FCFI_MODE) {
+ reg_fcfi_mrq->fcf_index = cpu_to_le16(fcf_index);
+ goto done;
+ }
+
+ reg_fcfi_mrq->dw8_vlan = cpu_to_le32(SLI4_REGFCFI_MRQ_MODE);
+
+ for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) {
+ reg_fcfi_mrq->rq_cfg[i].r_ctl_mask = rq_cfg[i].r_ctl_mask;
+ reg_fcfi_mrq->rq_cfg[i].r_ctl_match = rq_cfg[i].r_ctl_match;
+ reg_fcfi_mrq->rq_cfg[i].type_mask = rq_cfg[i].type_mask;
+ reg_fcfi_mrq->rq_cfg[i].type_match = rq_cfg[i].type_match;
+
+ switch (i) {
+ case 3:
+ reg_fcfi_mrq->rqid3 = rq_cfg[i].rq_id;
+ break;
+ case 2:
+ reg_fcfi_mrq->rqid2 = rq_cfg[i].rq_id;
+ break;
+ case 1:
+ reg_fcfi_mrq->rqid1 = rq_cfg[i].rq_id;
+ break;
+ case 0:
+ reg_fcfi_mrq->rqid0 = rq_cfg[i].rq_id;
+ break;
+ }
+ }
+
+ mrq_flags = num_mrqs & SLI4_REGFCFI_MRQ_MASK_NUM_PAIRS;
+ mrq_flags |= (mrq_bit_mask << 8);
+ mrq_flags |= (rq_selection_policy << 12);
+ reg_fcfi_mrq->dw9_mrqflags = cpu_to_le32(mrq_flags);
+done:
+ return 0;
+}
+
+int
+sli_cmd_reg_rpi(struct sli4 *sli4, void *buf, u32 rpi, u32 vpi, u32 fc_id,
+ struct efc_dma *dma, u8 update, u8 enable_t10_pi)
+{
+ struct sli4_cmd_reg_rpi *reg_rpi = buf;
+ u32 rportid_flags = 0;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ reg_rpi->hdr.command = SLI4_MBX_CMD_REG_RPI;
+
+ reg_rpi->rpi = cpu_to_le16(rpi);
+
+ rportid_flags = fc_id & SLI4_REGRPI_REMOTE_N_PORTID;
+
+ if (update)
+ rportid_flags |= SLI4_REGRPI_UPD;
+ else
+ rportid_flags &= ~SLI4_REGRPI_UPD;
+
+ if (enable_t10_pi)
+ rportid_flags |= SLI4_REGRPI_ETOW;
+ else
+ rportid_flags &= ~SLI4_REGRPI_ETOW;
+
+ reg_rpi->dw2_rportid_flags = cpu_to_le32(rportid_flags);
+
+ reg_rpi->bde_64.bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (SLI4_REG_RPI_BUF_LEN & SLI4_BDE_LEN_MASK));
+ reg_rpi->bde_64.u.data.low =
+ cpu_to_le32(lower_32_bits(dma->phys));
+ reg_rpi->bde_64.u.data.high =
+ cpu_to_le32(upper_32_bits(dma->phys));
+
+ reg_rpi->vpi = cpu_to_le16(vpi);
+
+ return 0;
+}
+
+int
+sli_cmd_reg_vfi(struct sli4 *sli4, void *buf, size_t size,
+ u16 vfi, u16 fcfi, struct efc_dma dma,
+ u16 vpi, __be64 sli_wwpn, u32 fc_id)
+{
+ struct sli4_cmd_reg_vfi *reg_vfi = buf;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ reg_vfi->hdr.command = SLI4_MBX_CMD_REG_VFI;
+
+ reg_vfi->vfi = cpu_to_le16(vfi);
+
+ reg_vfi->fcfi = cpu_to_le16(fcfi);
+
+ reg_vfi->sparm.bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (SLI4_REG_RPI_BUF_LEN & SLI4_BDE_LEN_MASK));
+ reg_vfi->sparm.u.data.low =
+ cpu_to_le32(lower_32_bits(dma.phys));
+ reg_vfi->sparm.u.data.high =
+ cpu_to_le32(upper_32_bits(dma.phys));
+
+ reg_vfi->e_d_tov = cpu_to_le32(sli4->e_d_tov);
+ reg_vfi->r_a_tov = cpu_to_le32(sli4->r_a_tov);
+
+ reg_vfi->dw0w1_flags |= cpu_to_le16(SLI4_REGVFI_VP);
+ reg_vfi->vpi = cpu_to_le16(vpi);
+ memcpy(reg_vfi->wwpn, &sli_wwpn, sizeof(reg_vfi->wwpn));
+ reg_vfi->dw10_lportid_flags = cpu_to_le32(fc_id);
+
+ return 0;
+}
+
+int
+sli_cmd_reg_vpi(struct sli4 *sli4, void *buf, u32 fc_id, __be64 sli_wwpn,
+ u16 vpi, u16 vfi, bool update)
+{
+ struct sli4_cmd_reg_vpi *reg_vpi = buf;
+ u32 flags = 0;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ reg_vpi->hdr.command = SLI4_MBX_CMD_REG_VPI;
+
+ flags = (fc_id & SLI4_REGVPI_LOCAL_N_PORTID);
+ if (update)
+ flags |= SLI4_REGVPI_UPD;
+ else
+ flags &= ~SLI4_REGVPI_UPD;
+
+ reg_vpi->dw2_lportid_flags = cpu_to_le32(flags);
+ memcpy(reg_vpi->wwpn, &sli_wwpn, sizeof(reg_vpi->wwpn));
+ reg_vpi->vpi = cpu_to_le16(vpi);
+ reg_vpi->vfi = cpu_to_le16(vfi);
+
+ return 0;
+}
+
+static int
+sli_cmd_request_features(struct sli4 *sli4, void *buf, u32 features_mask,
+ bool query)
+{
+ struct sli4_cmd_request_features *req_features = buf;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ req_features->hdr.command = SLI4_MBX_CMD_RQST_FEATURES;
+
+ if (query)
+ req_features->dw1_qry = cpu_to_le32(SLI4_REQFEAT_QRY);
+
+ req_features->cmd = cpu_to_le32(features_mask);
+
+ return 0;
+}
+
+int
+sli_cmd_unreg_fcfi(struct sli4 *sli4, void *buf, u16 indicator)
+{
+ struct sli4_cmd_unreg_fcfi *unreg_fcfi = buf;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ unreg_fcfi->hdr.command = SLI4_MBX_CMD_UNREG_FCFI;
+ unreg_fcfi->fcfi = cpu_to_le16(indicator);
+
+ return 0;
+}
+
+int
+sli_cmd_unreg_rpi(struct sli4 *sli4, void *buf, u16 indicator,
+ enum sli4_resource which, u32 fc_id)
+{
+ struct sli4_cmd_unreg_rpi *unreg_rpi = buf;
+ u32 flags = 0;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ unreg_rpi->hdr.command = SLI4_MBX_CMD_UNREG_RPI;
+ switch (which) {
+ case SLI4_RSRC_RPI:
+ flags |= SLI4_UNREG_RPI_II_RPI;
+ if (fc_id == U32_MAX)
+ break;
+
+ flags |= SLI4_UNREG_RPI_DP;
+ unreg_rpi->dw2_dest_n_portid =
+ cpu_to_le32(fc_id & SLI4_UNREG_RPI_DEST_N_PORTID_MASK);
+ break;
+ case SLI4_RSRC_VPI:
+ flags |= SLI4_UNREG_RPI_II_VPI;
+ break;
+ case SLI4_RSRC_VFI:
+ flags |= SLI4_UNREG_RPI_II_VFI;
+ break;
+ case SLI4_RSRC_FCFI:
+ flags |= SLI4_UNREG_RPI_II_FCFI;
+ break;
+ default:
+ efc_log_info(sli4, "unknown type %#x\n", which);
+ return -EIO;
+ }
+
+ unreg_rpi->dw1w1_flags = cpu_to_le16(flags);
+ unreg_rpi->index = cpu_to_le16(indicator);
+
+ return 0;
+}
+
+int
+sli_cmd_unreg_vfi(struct sli4 *sli4, void *buf, u16 index, u32 which)
+{
+ struct sli4_cmd_unreg_vfi *unreg_vfi = buf;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ unreg_vfi->hdr.command = SLI4_MBX_CMD_UNREG_VFI;
+ switch (which) {
+ case SLI4_UNREG_TYPE_DOMAIN:
+ unreg_vfi->index = cpu_to_le16(index);
+ break;
+ case SLI4_UNREG_TYPE_FCF:
+ unreg_vfi->index = cpu_to_le16(index);
+ break;
+ case SLI4_UNREG_TYPE_ALL:
+ unreg_vfi->index = cpu_to_le16(U32_MAX);
+ break;
+ default:
+ return -EIO;
+ }
+
+ if (which != SLI4_UNREG_TYPE_DOMAIN)
+ unreg_vfi->dw2_flags = cpu_to_le16(SLI4_UNREG_VFI_II_FCFI);
+
+ return 0;
+}
+
+int
+sli_cmd_unreg_vpi(struct sli4 *sli4, void *buf, u16 indicator, u32 which)
+{
+ struct sli4_cmd_unreg_vpi *unreg_vpi = buf;
+ u32 flags = 0;
+
+ memset(buf, 0, SLI4_BMBX_SIZE);
+
+ unreg_vpi->hdr.command = SLI4_MBX_CMD_UNREG_VPI;
+ unreg_vpi->index = cpu_to_le16(indicator);
+ switch (which) {
+ case SLI4_UNREG_TYPE_PORT:
+ flags |= SLI4_UNREG_VPI_II_VPI;
+ break;
+ case SLI4_UNREG_TYPE_DOMAIN:
+ flags |= SLI4_UNREG_VPI_II_VFI;
+ break;
+ case SLI4_UNREG_TYPE_FCF:
+ flags |= SLI4_UNREG_VPI_II_FCFI;
+ break;
+ case SLI4_UNREG_TYPE_ALL:
+ /* override indicator */
+ unreg_vpi->index = cpu_to_le16(U32_MAX);
+ flags |= SLI4_UNREG_VPI_II_FCFI;
+ break;
+ default:
+ return -EIO;
+ }
+
+ unreg_vpi->dw2w0_flags = cpu_to_le16(flags);
+ return 0;
+}
+
+static int
+sli_cmd_common_modify_eq_delay(struct sli4 *sli4, void *buf,
+ struct sli4_queue *q, int num_q, u32 shift,
+ u32 delay_mult)
+{
+ struct sli4_rqst_cmn_modify_eq_delay *req = NULL;
+ int i;
+
+ req = sli_config_cmd_init(sli4, buf,
+ SLI4_CFG_PYLD_LENGTH(cmn_modify_eq_delay), NULL);
+ if (!req)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&req->hdr, SLI4_CMN_MODIFY_EQ_DELAY,
+ SLI4_SUBSYSTEM_COMMON, CMD_V0,
+ SLI4_RQST_PYLD_LEN(cmn_modify_eq_delay));
+ req->num_eq = cpu_to_le32(num_q);
+
+ for (i = 0; i < num_q; i++) {
+ req->eq_delay_record[i].eq_id = cpu_to_le32(q[i].id);
+ req->eq_delay_record[i].phase = cpu_to_le32(shift);
+ req->eq_delay_record[i].delay_multiplier =
+ cpu_to_le32(delay_mult);
+ }
+
+ return 0;
+}
+
+void
+sli4_cmd_lowlevel_set_watchdog(struct sli4 *sli4, void *buf,
+ size_t size, u16 timeout)
+{
+ struct sli4_rqst_lowlevel_set_watchdog *req = NULL;
+
+ req = sli_config_cmd_init(sli4, buf,
+ SLI4_CFG_PYLD_LENGTH(lowlevel_set_watchdog), NULL);
+ if (!req)
+ return;
+
+ sli_cmd_fill_hdr(&req->hdr, SLI4_OPC_LOWLEVEL_SET_WATCHDOG,
+ SLI4_SUBSYSTEM_LOWLEVEL, CMD_V0,
+ SLI4_RQST_PYLD_LEN(lowlevel_set_watchdog));
+ req->watchdog_timeout = cpu_to_le16(timeout);
+}
+
+static int
+sli_cmd_common_get_cntl_attributes(struct sli4 *sli4, void *buf,
+ struct efc_dma *dma)
+{
+ struct sli4_rqst_hdr *hdr = NULL;
+
+ hdr = sli_config_cmd_init(sli4, buf, SLI4_RQST_CMDSZ(hdr), dma);
+ if (!hdr)
+ return -EIO;
+
+ hdr->opcode = SLI4_CMN_GET_CNTL_ATTRIBUTES;
+ hdr->subsystem = SLI4_SUBSYSTEM_COMMON;
+ hdr->request_length = cpu_to_le32(dma->size);
+
+ return 0;
+}
+
+static int
+sli_cmd_common_get_cntl_addl_attributes(struct sli4 *sli4, void *buf,
+ struct efc_dma *dma)
+{
+ struct sli4_rqst_hdr *hdr = NULL;
+
+ hdr = sli_config_cmd_init(sli4, buf, SLI4_RQST_CMDSZ(hdr), dma);
+ if (!hdr)
+ return -EIO;
+
+ hdr->opcode = SLI4_CMN_GET_CNTL_ADDL_ATTRS;
+ hdr->subsystem = SLI4_SUBSYSTEM_COMMON;
+ hdr->request_length = cpu_to_le32(dma->size);
+
+ return 0;
+}
+
+int
+sli_cmd_common_nop(struct sli4 *sli4, void *buf, uint64_t context)
+{
+ struct sli4_rqst_cmn_nop *nop = NULL;
+
+ nop = sli_config_cmd_init(sli4, buf, SLI4_CFG_PYLD_LENGTH(cmn_nop),
+ NULL);
+ if (!nop)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&nop->hdr, SLI4_CMN_NOP, SLI4_SUBSYSTEM_COMMON,
+ CMD_V0, SLI4_RQST_PYLD_LEN(cmn_nop));
+
+ memcpy(&nop->context, &context, sizeof(context));
+
+ return 0;
+}
+
+int
+sli_cmd_common_get_resource_extent_info(struct sli4 *sli4, void *buf, u16 rtype)
+{
+ struct sli4_rqst_cmn_get_resource_extent_info *ext = NULL;
+
+ ext = sli_config_cmd_init(sli4, buf,
+ SLI4_RQST_CMDSZ(cmn_get_resource_extent_info), NULL);
+ if (!ext)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&ext->hdr, SLI4_CMN_GET_RSC_EXTENT_INFO,
+ SLI4_SUBSYSTEM_COMMON, CMD_V0,
+ SLI4_RQST_PYLD_LEN(cmn_get_resource_extent_info));
+
+ ext->resource_type = cpu_to_le16(rtype);
+
+ return 0;
+}
+
+int
+sli_cmd_common_get_sli4_parameters(struct sli4 *sli4, void *buf)
+{
+ struct sli4_rqst_hdr *hdr = NULL;
+
+ hdr = sli_config_cmd_init(sli4, buf,
+ SLI4_CFG_PYLD_LENGTH(cmn_get_sli4_params), NULL);
+ if (!hdr)
+ return -EIO;
+
+ hdr->opcode = SLI4_CMN_GET_SLI4_PARAMS;
+ hdr->subsystem = SLI4_SUBSYSTEM_COMMON;
+ hdr->request_length = SLI4_RQST_PYLD_LEN(cmn_get_sli4_params);
+
+ return 0;
+}
+
+static int
+sli_cmd_common_get_port_name(struct sli4 *sli4, void *buf)
+{
+ struct sli4_rqst_cmn_get_port_name *pname;
+
+ pname = sli_config_cmd_init(sli4, buf,
+ SLI4_CFG_PYLD_LENGTH(cmn_get_port_name), NULL);
+ if (!pname)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&pname->hdr, SLI4_CMN_GET_PORT_NAME,
+ SLI4_SUBSYSTEM_COMMON, CMD_V1,
+ SLI4_RQST_PYLD_LEN(cmn_get_port_name));
+
+ /* Set the port type value (ethernet=0, FC=1) for V1 commands */
+ pname->port_type = SLI4_PORT_TYPE_FC;
+
+ return 0;
+}
+
+int
+sli_cmd_common_write_object(struct sli4 *sli4, void *buf, u16 noc,
+ u16 eof, u32 desired_write_length,
+ u32 offset, char *obj_name,
+ struct efc_dma *dma)
+{
+ struct sli4_rqst_cmn_write_object *wr_obj = NULL;
+ struct sli4_bde *bde;
+ u32 dwflags = 0;
+
+ wr_obj = sli_config_cmd_init(sli4, buf,
+ SLI4_RQST_CMDSZ(cmn_write_object) + sizeof(*bde), NULL);
+ if (!wr_obj)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&wr_obj->hdr, SLI4_CMN_WRITE_OBJECT,
+ SLI4_SUBSYSTEM_COMMON, CMD_V0,
+ SLI4_RQST_PYLD_LEN_VAR(cmn_write_object, sizeof(*bde)));
+
+ if (noc)
+ dwflags |= SLI4_RQ_DES_WRITE_LEN_NOC;
+ if (eof)
+ dwflags |= SLI4_RQ_DES_WRITE_LEN_EOF;
+ dwflags |= (desired_write_length & SLI4_RQ_DES_WRITE_LEN);
+
+ wr_obj->desired_write_len_dword = cpu_to_le32(dwflags);
+
+ wr_obj->write_offset = cpu_to_le32(offset);
+ strncpy(wr_obj->object_name, obj_name, sizeof(wr_obj->object_name) - 1);
+ wr_obj->host_buffer_descriptor_count = cpu_to_le32(1);
+
+ bde = (struct sli4_bde *)wr_obj->host_buffer_descriptor;
+
+ /* Setup to transfer xfer_size bytes to device */
+ bde->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (desired_write_length & SLI4_BDE_LEN_MASK));
+ bde->u.data.low = cpu_to_le32(lower_32_bits(dma->phys));
+ bde->u.data.high = cpu_to_le32(upper_32_bits(dma->phys));
+
+ return 0;
+}
+
+int
+sli_cmd_common_delete_object(struct sli4 *sli4, void *buf, char *obj_name)
+{
+ struct sli4_rqst_cmn_delete_object *req = NULL;
+
+ req = sli_config_cmd_init(sli4, buf,
+ SLI4_RQST_CMDSZ(cmn_delete_object), NULL);
+ if (!req)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&req->hdr, SLI4_CMN_DELETE_OBJECT,
+ SLI4_SUBSYSTEM_COMMON, CMD_V0,
+ SLI4_RQST_PYLD_LEN(cmn_delete_object));
+
+ strncpy(req->object_name, obj_name, sizeof(req->object_name) - 1);
+ return 0;
+}
+
+int
+sli_cmd_common_read_object(struct sli4 *sli4, void *buf, u32 desired_read_len,
+ u32 offset, char *obj_name, struct efc_dma *dma)
+{
+ struct sli4_rqst_cmn_read_object *rd_obj = NULL;
+ struct sli4_bde *bde;
+
+ rd_obj = sli_config_cmd_init(sli4, buf,
+ SLI4_RQST_CMDSZ(cmn_read_object) + sizeof(*bde), NULL);
+ if (!rd_obj)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&rd_obj->hdr, SLI4_CMN_READ_OBJECT,
+ SLI4_SUBSYSTEM_COMMON, CMD_V0,
+ SLI4_RQST_PYLD_LEN_VAR(cmn_read_object, sizeof(*bde)));
+ rd_obj->desired_read_length_dword =
+ cpu_to_le32(desired_read_len & SLI4_REQ_DESIRE_READLEN);
+
+ rd_obj->read_offset = cpu_to_le32(offset);
+ strncpy(rd_obj->object_name, obj_name, sizeof(rd_obj->object_name) - 1);
+ rd_obj->host_buffer_descriptor_count = cpu_to_le32(1);
+
+ bde = (struct sli4_bde *)rd_obj->host_buffer_descriptor;
+
+ /* Setup to transfer xfer_size bytes to device */
+ bde->bde_type_buflen =
+ cpu_to_le32((SLI4_BDE_TYPE_VAL(64)) |
+ (desired_read_len & SLI4_BDE_LEN_MASK));
+ if (dma) {
+ bde->u.data.low = cpu_to_le32(lower_32_bits(dma->phys));
+ bde->u.data.high = cpu_to_le32(upper_32_bits(dma->phys));
+ } else {
+ bde->u.data.low = 0;
+ bde->u.data.high = 0;
+ }
+
+ return 0;
+}
+
+int
+sli_cmd_dmtf_exec_clp_cmd(struct sli4 *sli4, void *buf, struct efc_dma *cmd,
+ struct efc_dma *resp)
+{
+ struct sli4_rqst_dmtf_exec_clp_cmd *clp_cmd = NULL;
+
+ clp_cmd = sli_config_cmd_init(sli4, buf,
+ SLI4_RQST_CMDSZ(dmtf_exec_clp_cmd), NULL);
+ if (!clp_cmd)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&clp_cmd->hdr, DMTF_EXEC_CLP_CMD, SLI4_SUBSYSTEM_DMTF,
+ CMD_V0, SLI4_RQST_PYLD_LEN(dmtf_exec_clp_cmd));
+
+ clp_cmd->cmd_buf_length = cpu_to_le32(cmd->size);
+ clp_cmd->cmd_buf_addr_low = cpu_to_le32(lower_32_bits(cmd->phys));
+ clp_cmd->cmd_buf_addr_high = cpu_to_le32(upper_32_bits(cmd->phys));
+ clp_cmd->resp_buf_length = cpu_to_le32(resp->size);
+ clp_cmd->resp_buf_addr_low = cpu_to_le32(lower_32_bits(resp->phys));
+ clp_cmd->resp_buf_addr_high = cpu_to_le32(upper_32_bits(resp->phys));
+ return 0;
+}
+
+int
+sli_cmd_common_set_dump_location(struct sli4 *sli4, void *buf, bool query,
+ bool is_buffer_list,
+ struct efc_dma *buffer, u8 fdb)
+{
+ struct sli4_rqst_cmn_set_dump_location *set_dump_loc = NULL;
+ u32 buffer_length_flag = 0;
+
+ set_dump_loc = sli_config_cmd_init(sli4, buf,
+ SLI4_RQST_CMDSZ(cmn_set_dump_location), NULL);
+ if (!set_dump_loc)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&set_dump_loc->hdr, SLI4_CMN_SET_DUMP_LOCATION,
+ SLI4_SUBSYSTEM_COMMON, CMD_V0,
+ SLI4_RQST_PYLD_LEN(cmn_set_dump_location));
+
+ if (is_buffer_list)
+ buffer_length_flag |= SLI4_CMN_SET_DUMP_BLP;
+
+ if (query)
+ buffer_length_flag |= SLI4_CMN_SET_DUMP_QRY;
+
+ if (fdb)
+ buffer_length_flag |= SLI4_CMN_SET_DUMP_FDB;
+
+ if (buffer) {
+ set_dump_loc->buf_addr_low =
+ cpu_to_le32(lower_32_bits(buffer->phys));
+ set_dump_loc->buf_addr_high =
+ cpu_to_le32(upper_32_bits(buffer->phys));
+
+ buffer_length_flag |=
+ buffer->len & SLI4_CMN_SET_DUMP_BUFFER_LEN;
+ } else {
+ set_dump_loc->buf_addr_low = 0;
+ set_dump_loc->buf_addr_high = 0;
+ set_dump_loc->buffer_length_dword = 0;
+ }
+ set_dump_loc->buffer_length_dword = cpu_to_le32(buffer_length_flag);
+ return 0;
+}
+
+int
+sli_cmd_common_set_features(struct sli4 *sli4, void *buf, u32 feature,
+ u32 param_len, void *parameter)
+{
+ struct sli4_rqst_cmn_set_features *cmd = NULL;
+
+ cmd = sli_config_cmd_init(sli4, buf,
+ SLI4_RQST_CMDSZ(cmn_set_features), NULL);
+ if (!cmd)
+ return -EIO;
+
+ sli_cmd_fill_hdr(&cmd->hdr, SLI4_CMN_SET_FEATURES,
+ SLI4_SUBSYSTEM_COMMON, CMD_V0,
+ SLI4_RQST_PYLD_LEN(cmn_set_features));
+
+ cmd->feature = cpu_to_le32(feature);
+ cmd->param_len = cpu_to_le32(param_len);
+ memcpy(cmd->params, parameter, param_len);
+
+ return 0;
+}
+
+int
+sli_cqe_mq(struct sli4 *sli4, void *buf)
+{
+ struct sli4_mcqe *mcqe = buf;
+ u32 dwflags = le32_to_cpu(mcqe->dw3_flags);
+ /*
+ * Firmware can split mbx completions into two MCQEs: first with only
+ * the "consumed" bit set and a second with the "complete" bit set.
+ * Thus, ignore MCQE unless "complete" is set.
+ */
+ if (!(dwflags & SLI4_MCQE_COMPLETED))
+ return SLI4_MCQE_STATUS_NOT_COMPLETED;
+
+ if (le16_to_cpu(mcqe->completion_status)) {
+ efc_log_info(sli4, "status(st=%#x ext=%#x con=%d cmp=%d ae=%d val=%d)\n",
+ le16_to_cpu(mcqe->completion_status),
+ le16_to_cpu(mcqe->extended_status),
+ (dwflags & SLI4_MCQE_CONSUMED),
+ (dwflags & SLI4_MCQE_COMPLETED),
+ (dwflags & SLI4_MCQE_AE),
+ (dwflags & SLI4_MCQE_VALID));
+ }
+
+ return le16_to_cpu(mcqe->completion_status);
+}
+
+int
+sli_cqe_async(struct sli4 *sli4, void *buf)
+{
+ struct sli4_acqe *acqe = buf;
+ int rc = -EIO;
+
+ if (!buf) {
+ efc_log_err(sli4, "bad parameter sli4=%p buf=%p\n", sli4, buf);
+ return -EIO;
+ }
+
+ switch (acqe->event_code) {
+ case SLI4_ACQE_EVENT_CODE_LINK_STATE:
+ efc_log_info(sli4, "Unsupported by FC link, evt code:%#x\n",
+ acqe->event_code);
+ break;
+ case SLI4_ACQE_EVENT_CODE_GRP_5:
+ efc_log_info(sli4, "ACQE GRP5\n");
+ break;
+ case SLI4_ACQE_EVENT_CODE_SLI_PORT_EVENT:
+ efc_log_info(sli4, "ACQE SLI Port, type=0x%x, data1,2=0x%08x,0x%08x\n",
+ acqe->event_type,
+ le32_to_cpu(acqe->event_data[0]),
+ le32_to_cpu(acqe->event_data[1]));
+ break;
+ case SLI4_ACQE_EVENT_CODE_FC_LINK_EVENT:
+ rc = sli_fc_process_link_attention(sli4, buf);
+ break;
+ default:
+ efc_log_info(sli4, "ACQE unknown=%#x\n", acqe->event_code);
+ }
+
+ return rc;
+}
+
+bool
+sli_fw_ready(struct sli4 *sli4)
+{
+ u32 val;
+
+ /* Determine if the chip FW is in a ready state */
+ val = sli_reg_read_status(sli4);
+ return (val & SLI4_PORT_STATUS_RDY) ? 1 : 0;
+}
+
+static bool
+sli_wait_for_fw_ready(struct sli4 *sli4, u32 timeout_ms)
+{
+ unsigned long end;
+
+ end = jiffies + msecs_to_jiffies(timeout_ms);
+
+ do {
+ if (sli_fw_ready(sli4))
+ return true;
+
+ usleep_range(1000, 2000);
+ } while (time_before(jiffies, end));
+
+ return false;
+}
+
+static bool
+sli_sliport_reset(struct sli4 *sli4)
+{
+ bool rc;
+ u32 val;
+
+ val = SLI4_PORT_CTRL_IP;
+ /* Initialize port, endian */
+ writel(val, (sli4->reg[0] + SLI4_PORT_CTRL_REG));
+
+ rc = sli_wait_for_fw_ready(sli4, SLI4_FW_READY_TIMEOUT_MSEC);
+ if (!rc)
+ efc_log_crit(sli4, "port failed to become ready after initialization\n");
+
+ return rc;
+}
+
+static bool
+sli_fw_init(struct sli4 *sli4)
+{
+ /*
+ * Is firmware ready for operation?
+ */
+ if (!sli_wait_for_fw_ready(sli4, SLI4_FW_READY_TIMEOUT_MSEC)) {
+ efc_log_crit(sli4, "FW status is NOT ready\n");
+ return false;
+ }
+
+ /*
+ * Reset port to a known state
+ */
+ return sli_sliport_reset(sli4);
+}
+
+static int
+sli_request_features(struct sli4 *sli4, u32 *features, bool query)
+{
+ struct sli4_cmd_request_features *req_features = sli4->bmbx.virt;
+
+ if (sli_cmd_request_features(sli4, sli4->bmbx.virt, *features, query)) {
+ efc_log_err(sli4, "bad REQUEST_FEATURES write\n");
+ return -EIO;
+ }
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_crit(sli4, "bootstrap mailbox write fail\n");
+ return -EIO;
+ }
+
+ if (le16_to_cpu(req_features->hdr.status)) {
+ efc_log_err(sli4, "REQUEST_FEATURES bad status %#x\n",
+ le16_to_cpu(req_features->hdr.status));
+ return -EIO;
+ }
+
+ *features = le32_to_cpu(req_features->resp);
+ return 0;
+}
+
+void
+sli_calc_max_qentries(struct sli4 *sli4)
+{
+ enum sli4_qtype q;
+ u32 qentries;
+
+ for (q = SLI4_QTYPE_EQ; q < SLI4_QTYPE_MAX; q++) {
+ sli4->qinfo.max_qentries[q] =
+ sli_convert_mask_to_count(sli4->qinfo.count_method[q],
+ sli4->qinfo.count_mask[q]);
+ }
+
+ /* single, continguous DMA allocations will be called for each queue
+ * of size (max_qentries * queue entry size); since these can be large,
+ * check against the OS max DMA allocation size
+ */
+ for (q = SLI4_QTYPE_EQ; q < SLI4_QTYPE_MAX; q++) {
+ qentries = sli4->qinfo.max_qentries[q];
+
+ efc_log_info(sli4, "[%s]: max_qentries from %d to %d\n",
+ SLI4_QNAME[q],
+ sli4->qinfo.max_qentries[q], qentries);
+ sli4->qinfo.max_qentries[q] = qentries;
+ }
+}
+
+static int
+sli_get_read_config(struct sli4 *sli4)
+{
+ struct sli4_rsp_read_config *conf = sli4->bmbx.virt;
+ u32 i, total, total_size;
+ u32 *base;
+
+ if (sli_cmd_read_config(sli4, sli4->bmbx.virt)) {
+ efc_log_err(sli4, "bad READ_CONFIG write\n");
+ return -EIO;
+ }
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_crit(sli4, "bootstrap mailbox fail (READ_CONFIG)\n");
+ return -EIO;
+ }
+
+ if (le16_to_cpu(conf->hdr.status)) {
+ efc_log_err(sli4, "READ_CONFIG bad status %#x\n",
+ le16_to_cpu(conf->hdr.status));
+ return -EIO;
+ }
+
+ sli4->params.has_extents =
+ le32_to_cpu(conf->ext_dword) & SLI4_READ_CFG_RESP_RESOURCE_EXT;
+ if (sli4->params.has_extents) {
+ efc_log_err(sli4, "extents not supported\n");
+ return -EIO;
+ }
+
+ base = sli4->ext[0].base;
+ if (!base) {
+ int size = SLI4_RSRC_MAX * sizeof(u32);
+
+ base = kzalloc(size, GFP_KERNEL);
+ if (!base)
+ return -EIO;
+ }
+
+ for (i = 0; i < SLI4_RSRC_MAX; i++) {
+ sli4->ext[i].number = 1;
+ sli4->ext[i].n_alloc = 0;
+ sli4->ext[i].base = &base[i];
+ }
+
+ sli4->ext[SLI4_RSRC_VFI].base[0] = le16_to_cpu(conf->vfi_base);
+ sli4->ext[SLI4_RSRC_VFI].size = le16_to_cpu(conf->vfi_count);
+
+ sli4->ext[SLI4_RSRC_VPI].base[0] = le16_to_cpu(conf->vpi_base);
+ sli4->ext[SLI4_RSRC_VPI].size = le16_to_cpu(conf->vpi_count);
+
+ sli4->ext[SLI4_RSRC_RPI].base[0] = le16_to_cpu(conf->rpi_base);
+ sli4->ext[SLI4_RSRC_RPI].size = le16_to_cpu(conf->rpi_count);
+
+ sli4->ext[SLI4_RSRC_XRI].base[0] = le16_to_cpu(conf->xri_base);
+ sli4->ext[SLI4_RSRC_XRI].size = le16_to_cpu(conf->xri_count);
+
+ sli4->ext[SLI4_RSRC_FCFI].base[0] = 0;
+ sli4->ext[SLI4_RSRC_FCFI].size = le16_to_cpu(conf->fcfi_count);
+
+ for (i = 0; i < SLI4_RSRC_MAX; i++) {
+ total = sli4->ext[i].number * sli4->ext[i].size;
+ total_size = BITS_TO_LONGS(total) * sizeof(long);
+ sli4->ext[i].use_map = kzalloc(total_size, GFP_KERNEL);
+ if (!sli4->ext[i].use_map) {
+ efc_log_err(sli4, "bitmap memory allocation failed %d\n",
+ i);
+ return -EIO;
+ }
+ sli4->ext[i].map_size = total;
+ }
+
+ sli4->topology = (le32_to_cpu(conf->topology_dword) &
+ SLI4_READ_CFG_RESP_TOPOLOGY) >> 24;
+ switch (sli4->topology) {
+ case SLI4_READ_CFG_TOPO_FC:
+ efc_log_info(sli4, "FC (unknown)\n");
+ break;
+ case SLI4_READ_CFG_TOPO_NON_FC_AL:
+ efc_log_info(sli4, "FC (direct attach)\n");
+ break;
+ case SLI4_READ_CFG_TOPO_FC_AL:
+ efc_log_info(sli4, "FC (arbitrated loop)\n");
+ break;
+ default:
+ efc_log_info(sli4, "bad topology %#x\n", sli4->topology);
+ }
+
+ sli4->e_d_tov = le16_to_cpu(conf->e_d_tov);
+ sli4->r_a_tov = le16_to_cpu(conf->r_a_tov);
+
+ sli4->link_module_type = le16_to_cpu(conf->lmt);
+
+ sli4->qinfo.max_qcount[SLI4_QTYPE_EQ] = le16_to_cpu(conf->eq_count);
+ sli4->qinfo.max_qcount[SLI4_QTYPE_CQ] = le16_to_cpu(conf->cq_count);
+ sli4->qinfo.max_qcount[SLI4_QTYPE_WQ] = le16_to_cpu(conf->wq_count);
+ sli4->qinfo.max_qcount[SLI4_QTYPE_RQ] = le16_to_cpu(conf->rq_count);
+
+ /*
+ * READ_CONFIG doesn't give the max number of MQ. Applications
+ * will typically want 1, but we may need another at some future
+ * date. Dummy up a "max" MQ count here.
+ */
+ sli4->qinfo.max_qcount[SLI4_QTYPE_MQ] = SLI4_USER_MQ_COUNT;
+ return 0;
+}
+
+static int
+sli_get_sli4_parameters(struct sli4 *sli4)
+{
+ struct sli4_rsp_cmn_get_sli4_params *parms;
+ u32 dw_loopback;
+ u32 dw_eq_pg_cnt;
+ u32 dw_cq_pg_cnt;
+ u32 dw_mq_pg_cnt;
+ u32 dw_wq_pg_cnt;
+ u32 dw_rq_pg_cnt;
+ u32 dw_sgl_pg_cnt;
+
+ if (sli_cmd_common_get_sli4_parameters(sli4, sli4->bmbx.virt))
+ return -EIO;
+
+ parms = (struct sli4_rsp_cmn_get_sli4_params *)
+ (((u8 *)sli4->bmbx.virt) +
+ offsetof(struct sli4_cmd_sli_config, payload.embed));
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_crit(sli4, "bootstrap mailbox write fail\n");
+ return -EIO;
+ }
+
+ if (parms->hdr.status) {
+ efc_log_err(sli4, "COMMON_GET_SLI4_PARAMETERS bad status %#x",
+ parms->hdr.status);
+ efc_log_err(sli4, "additional status %#x\n",
+ parms->hdr.additional_status);
+ return -EIO;
+ }
+
+ dw_loopback = le32_to_cpu(parms->dw16_loopback_scope);
+ dw_eq_pg_cnt = le32_to_cpu(parms->dw6_eq_page_cnt);
+ dw_cq_pg_cnt = le32_to_cpu(parms->dw8_cq_page_cnt);
+ dw_mq_pg_cnt = le32_to_cpu(parms->dw10_mq_page_cnt);
+ dw_wq_pg_cnt = le32_to_cpu(parms->dw12_wq_page_cnt);
+ dw_rq_pg_cnt = le32_to_cpu(parms->dw14_rq_page_cnt);
+
+ sli4->params.auto_reg = (dw_loopback & SLI4_PARAM_AREG);
+ sli4->params.auto_xfer_rdy = (dw_loopback & SLI4_PARAM_AGXF);
+ sli4->params.hdr_template_req = (dw_loopback & SLI4_PARAM_HDRR);
+ sli4->params.t10_dif_inline_capable = (dw_loopback & SLI4_PARAM_TIMM);
+ sli4->params.t10_dif_separate_capable = (dw_loopback & SLI4_PARAM_TSMM);
+
+ sli4->params.mq_create_version = GET_Q_CREATE_VERSION(dw_mq_pg_cnt);
+ sli4->params.cq_create_version = GET_Q_CREATE_VERSION(dw_cq_pg_cnt);
+
+ sli4->rq_min_buf_size = le16_to_cpu(parms->min_rq_buffer_size);
+ sli4->rq_max_buf_size = le32_to_cpu(parms->max_rq_buffer_size);
+
+ sli4->qinfo.qpage_count[SLI4_QTYPE_EQ] =
+ (dw_eq_pg_cnt & SLI4_PARAM_EQ_PAGE_CNT_MASK);
+ sli4->qinfo.qpage_count[SLI4_QTYPE_CQ] =
+ (dw_cq_pg_cnt & SLI4_PARAM_CQ_PAGE_CNT_MASK);
+ sli4->qinfo.qpage_count[SLI4_QTYPE_MQ] =
+ (dw_mq_pg_cnt & SLI4_PARAM_MQ_PAGE_CNT_MASK);
+ sli4->qinfo.qpage_count[SLI4_QTYPE_WQ] =
+ (dw_wq_pg_cnt & SLI4_PARAM_WQ_PAGE_CNT_MASK);
+ sli4->qinfo.qpage_count[SLI4_QTYPE_RQ] =
+ (dw_rq_pg_cnt & SLI4_PARAM_RQ_PAGE_CNT_MASK);
+
+ /* save count methods and masks for each queue type */
+
+ sli4->qinfo.count_mask[SLI4_QTYPE_EQ] =
+ le16_to_cpu(parms->eqe_count_mask);
+ sli4->qinfo.count_method[SLI4_QTYPE_EQ] =
+ GET_Q_CNT_METHOD(dw_eq_pg_cnt);
+
+ sli4->qinfo.count_mask[SLI4_QTYPE_CQ] =
+ le16_to_cpu(parms->cqe_count_mask);
+ sli4->qinfo.count_method[SLI4_QTYPE_CQ] =
+ GET_Q_CNT_METHOD(dw_cq_pg_cnt);
+
+ sli4->qinfo.count_mask[SLI4_QTYPE_MQ] =
+ le16_to_cpu(parms->mqe_count_mask);
+ sli4->qinfo.count_method[SLI4_QTYPE_MQ] =
+ GET_Q_CNT_METHOD(dw_mq_pg_cnt);
+
+ sli4->qinfo.count_mask[SLI4_QTYPE_WQ] =
+ le16_to_cpu(parms->wqe_count_mask);
+ sli4->qinfo.count_method[SLI4_QTYPE_WQ] =
+ GET_Q_CNT_METHOD(dw_wq_pg_cnt);
+
+ sli4->qinfo.count_mask[SLI4_QTYPE_RQ] =
+ le16_to_cpu(parms->rqe_count_mask);
+ sli4->qinfo.count_method[SLI4_QTYPE_RQ] =
+ GET_Q_CNT_METHOD(dw_rq_pg_cnt);
+
+ /* now calculate max queue entries */
+ sli_calc_max_qentries(sli4);
+
+ dw_sgl_pg_cnt = le32_to_cpu(parms->dw18_sgl_page_cnt);
+
+ /* max # of pages */
+ sli4->max_sgl_pages = (dw_sgl_pg_cnt & SLI4_PARAM_SGL_PAGE_CNT_MASK);
+
+ /* bit map of available sizes */
+ sli4->sgl_page_sizes = (dw_sgl_pg_cnt &
+ SLI4_PARAM_SGL_PAGE_SZS_MASK) >> 8;
+ /* ignore HLM here. Use value from REQUEST_FEATURES */
+ sli4->sge_supported_length = le32_to_cpu(parms->sge_supported_length);
+ sli4->params.sgl_pre_reg_required = (dw_loopback & SLI4_PARAM_SGLR);
+ /* default to using pre-registered SGL's */
+ sli4->params.sgl_pre_registered = true;
+
+ sli4->params.perf_hint = dw_loopback & SLI4_PARAM_PHON;
+ sli4->params.perf_wq_id_association = (dw_loopback & SLI4_PARAM_PHWQ);
+
+ sli4->rq_batch = (le16_to_cpu(parms->dw15w1_rq_db_window) &
+ SLI4_PARAM_RQ_DB_WINDOW_MASK) >> 12;
+
+ /* Use the highest available WQE size. */
+ if (((dw_wq_pg_cnt & SLI4_PARAM_WQE_SZS_MASK) >> 8) &
+ SLI4_128BYTE_WQE_SUPPORT)
+ sli4->wqe_size = SLI4_WQE_EXT_BYTES;
+ else
+ sli4->wqe_size = SLI4_WQE_BYTES;
+
+ return 0;
+}
+
+static int
+sli_get_ctrl_attributes(struct sli4 *sli4)
+{
+ struct sli4_rsp_cmn_get_cntl_attributes *attr;
+ struct sli4_rsp_cmn_get_cntl_addl_attributes *add_attr;
+ struct efc_dma data;
+ u32 psize;
+
+ /*
+ * Issue COMMON_GET_CNTL_ATTRIBUTES to get port_number. Temporarily
+ * uses VPD DMA buffer as the response won't fit in the embedded
+ * buffer.
+ */
+ memset(sli4->vpd_data.virt, 0, sli4->vpd_data.size);
+ if (sli_cmd_common_get_cntl_attributes(sli4, sli4->bmbx.virt,
+ &sli4->vpd_data)) {
+ efc_log_err(sli4, "bad COMMON_GET_CNTL_ATTRIBUTES write\n");
+ return -EIO;
+ }
+
+ attr = sli4->vpd_data.virt;
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_crit(sli4, "bootstrap mailbox write fail\n");
+ return -EIO;
+ }
+
+ if (attr->hdr.status) {
+ efc_log_err(sli4, "COMMON_GET_CNTL_ATTRIBUTES bad status %#x",
+ attr->hdr.status);
+ efc_log_err(sli4, "additional status %#x\n",
+ attr->hdr.additional_status);
+ return -EIO;
+ }
+
+ sli4->port_number = attr->port_num_type_flags & SLI4_CNTL_ATTR_PORTNUM;
+
+ memcpy(sli4->bios_version_string, attr->bios_version_str,
+ sizeof(sli4->bios_version_string));
+
+ /* get additional attributes */
+ psize = sizeof(struct sli4_rsp_cmn_get_cntl_addl_attributes);
+ data.size = psize;
+ data.virt = dma_alloc_coherent(&sli4->pci->dev, data.size,
+ &data.phys, GFP_DMA);
+ if (!data.virt) {
+ memset(&data, 0, sizeof(struct efc_dma));
+ efc_log_err(sli4, "Failed to allocate memory for GET_CNTL_ADDL_ATTR\n");
+ return -EIO;
+ }
+
+ if (sli_cmd_common_get_cntl_addl_attributes(sli4, sli4->bmbx.virt,
+ &data)) {
+ efc_log_err(sli4, "bad GET_CNTL_ADDL_ATTR write\n");
+ dma_free_coherent(&sli4->pci->dev, data.size,
+ data.virt, data.phys);
+ return -EIO;
+ }
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_crit(sli4, "mailbox fail (GET_CNTL_ADDL_ATTR)\n");
+ dma_free_coherent(&sli4->pci->dev, data.size,
+ data.virt, data.phys);
+ return -EIO;
+ }
+
+ add_attr = data.virt;
+ if (add_attr->hdr.status) {
+ efc_log_err(sli4, "GET_CNTL_ADDL_ATTR bad status %#x\n",
+ add_attr->hdr.status);
+ dma_free_coherent(&sli4->pci->dev, data.size,
+ data.virt, data.phys);
+ return -EIO;
+ }
+
+ memcpy(sli4->ipl_name, add_attr->ipl_file_name, sizeof(sli4->ipl_name));
+
+ efc_log_info(sli4, "IPL:%s\n", (char *)sli4->ipl_name);
+
+ dma_free_coherent(&sli4->pci->dev, data.size, data.virt,
+ data.phys);
+ memset(&data, 0, sizeof(struct efc_dma));
+ return 0;
+}
+
+static int
+sli_get_fw_rev(struct sli4 *sli4)
+{
+ struct sli4_cmd_read_rev *read_rev = sli4->bmbx.virt;
+
+ if (sli_cmd_read_rev(sli4, sli4->bmbx.virt, &sli4->vpd_data))
+ return -EIO;
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_crit(sli4, "bootstrap mailbox write fail (READ_REV)\n");
+ return -EIO;
+ }
+
+ if (le16_to_cpu(read_rev->hdr.status)) {
+ efc_log_err(sli4, "READ_REV bad status %#x\n",
+ le16_to_cpu(read_rev->hdr.status));
+ return -EIO;
+ }
+
+ sli4->fw_rev[0] = le32_to_cpu(read_rev->first_fw_id);
+ memcpy(sli4->fw_name[0], read_rev->first_fw_name,
+ sizeof(sli4->fw_name[0]));
+
+ sli4->fw_rev[1] = le32_to_cpu(read_rev->second_fw_id);
+ memcpy(sli4->fw_name[1], read_rev->second_fw_name,
+ sizeof(sli4->fw_name[1]));
+
+ sli4->hw_rev[0] = le32_to_cpu(read_rev->first_hw_rev);
+ sli4->hw_rev[1] = le32_to_cpu(read_rev->second_hw_rev);
+ sli4->hw_rev[2] = le32_to_cpu(read_rev->third_hw_rev);
+
+ efc_log_info(sli4, "FW1:%s (%08x) / FW2:%s (%08x)\n",
+ read_rev->first_fw_name, le32_to_cpu(read_rev->first_fw_id),
+ read_rev->second_fw_name, le32_to_cpu(read_rev->second_fw_id));
+
+ efc_log_info(sli4, "HW1: %08x / HW2: %08x\n",
+ le32_to_cpu(read_rev->first_hw_rev),
+ le32_to_cpu(read_rev->second_hw_rev));
+
+ /* Check that all VPD data was returned */
+ if (le32_to_cpu(read_rev->returned_vpd_length) !=
+ le32_to_cpu(read_rev->actual_vpd_length)) {
+ efc_log_info(sli4, "VPD length: avail=%d return=%d actual=%d\n",
+ le32_to_cpu(read_rev->available_length_dword) &
+ SLI4_READ_REV_AVAILABLE_LENGTH,
+ le32_to_cpu(read_rev->returned_vpd_length),
+ le32_to_cpu(read_rev->actual_vpd_length));
+ }
+ sli4->vpd_length = le32_to_cpu(read_rev->returned_vpd_length);
+ return 0;
+}
+
+static int
+sli_get_config(struct sli4 *sli4)
+{
+ struct sli4_rsp_cmn_get_port_name *port_name;
+ struct sli4_cmd_read_nvparms *read_nvparms;
+
+ /*
+ * Read the device configuration
+ */
+ if (sli_get_read_config(sli4))
+ return -EIO;
+
+ if (sli_get_sli4_parameters(sli4))
+ return -EIO;
+
+ if (sli_get_ctrl_attributes(sli4))
+ return -EIO;
+
+ if (sli_cmd_common_get_port_name(sli4, sli4->bmbx.virt))
+ return -EIO;
+
+ port_name = (struct sli4_rsp_cmn_get_port_name *)
+ (((u8 *)sli4->bmbx.virt) +
+ offsetof(struct sli4_cmd_sli_config, payload.embed));
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_crit(sli4, "bootstrap mailbox fail (GET_PORT_NAME)\n");
+ return -EIO;
+ }
+
+ sli4->port_name[0] = port_name->port_name[sli4->port_number];
+ sli4->port_name[1] = '\0';
+
+ if (sli_get_fw_rev(sli4))
+ return -EIO;
+
+ if (sli_cmd_read_nvparms(sli4, sli4->bmbx.virt)) {
+ efc_log_err(sli4, "bad READ_NVPARMS write\n");
+ return -EIO;
+ }
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_crit(sli4, "bootstrap mailbox fail (READ_NVPARMS)\n");
+ return -EIO;
+ }
+
+ read_nvparms = sli4->bmbx.virt;
+ if (le16_to_cpu(read_nvparms->hdr.status)) {
+ efc_log_err(sli4, "READ_NVPARMS bad status %#x\n",
+ le16_to_cpu(read_nvparms->hdr.status));
+ return -EIO;
+ }
+
+ memcpy(sli4->wwpn, read_nvparms->wwpn, sizeof(sli4->wwpn));
+ memcpy(sli4->wwnn, read_nvparms->wwnn, sizeof(sli4->wwnn));
+
+ efc_log_info(sli4, "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ sli4->wwpn[0], sli4->wwpn[1], sli4->wwpn[2], sli4->wwpn[3],
+ sli4->wwpn[4], sli4->wwpn[5], sli4->wwpn[6], sli4->wwpn[7]);
+ efc_log_info(sli4, "WWNN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ sli4->wwnn[0], sli4->wwnn[1], sli4->wwnn[2], sli4->wwnn[3],
+ sli4->wwnn[4], sli4->wwnn[5], sli4->wwnn[6], sli4->wwnn[7]);
+
+ return 0;
+}
+
+int
+sli_setup(struct sli4 *sli4, void *os, struct pci_dev *pdev,
+ void __iomem *reg[])
+{
+ u32 intf = U32_MAX;
+ u32 pci_class_rev = 0;
+ u32 rev_id = 0;
+ u32 family = 0;
+ u32 asic_id = 0;
+ u32 i;
+ struct sli4_asic_entry_t *asic;
+
+ memset(sli4, 0, sizeof(struct sli4));
+
+ sli4->os = os;
+ sli4->pci = pdev;
+
+ for (i = 0; i < 6; i++)
+ sli4->reg[i] = reg[i];
+ /*
+ * Read the SLI_INTF register to discover the register layout
+ * and other capability information
+ */
+ if (pci_read_config_dword(pdev, SLI4_INTF_REG, &intf))
+ return -EIO;
+
+ if ((intf & SLI4_INTF_VALID_MASK) != (u32)SLI4_INTF_VALID_VALUE) {
+ efc_log_err(sli4, "SLI_INTF is not valid\n");
+ return -EIO;
+ }
+
+ /* driver only support SLI-4 */
+ if ((intf & SLI4_INTF_REV_MASK) != SLI4_INTF_REV_S4) {
+ efc_log_err(sli4, "Unsupported SLI revision (intf=%#x)\n", intf);
+ return -EIO;
+ }
+
+ sli4->sli_family = intf & SLI4_INTF_FAMILY_MASK;
+
+ sli4->if_type = intf & SLI4_INTF_IF_TYPE_MASK;
+ efc_log_info(sli4, "status=%#x error1=%#x error2=%#x\n",
+ sli_reg_read_status(sli4),
+ sli_reg_read_err1(sli4),
+ sli_reg_read_err2(sli4));
+
+ /*
+ * set the ASIC type and revision
+ */
+ if (pci_read_config_dword(pdev, PCI_CLASS_REVISION, &pci_class_rev))
+ return -EIO;
+
+ rev_id = pci_class_rev & 0xff;
+ family = sli4->sli_family;
+ if (family == SLI4_FAMILY_CHECK_ASIC_TYPE) {
+ if (!pci_read_config_dword(pdev, SLI4_ASIC_ID_REG, &asic_id))
+ family = asic_id & SLI4_ASIC_GEN_MASK;
+ }
+
+ for (i = 0, asic = sli4_asic_table; i < ARRAY_SIZE(sli4_asic_table);
+ i++, asic++) {
+ if (rev_id == asic->rev_id && family == asic->family) {
+ sli4->asic_type = family;
+ sli4->asic_rev = rev_id;
+ break;
+ }
+ }
+ /* Fail if no matching asic type/rev was found */
+ if (!sli4->asic_type) {
+ efc_log_err(sli4, "no matching asic family/rev found: %02x/%02x\n",
+ family, rev_id);
+ return -EIO;
+ }
+
+ /*
+ * The bootstrap mailbox is equivalent to a MQ with a single 256 byte
+ * entry, a CQ with a single 16 byte entry, and no event queue.
+ * Alignment must be 16 bytes as the low order address bits in the
+ * address register are also control / status.
+ */
+ sli4->bmbx.size = SLI4_BMBX_SIZE + sizeof(struct sli4_mcqe);
+ sli4->bmbx.virt = dma_alloc_coherent(&pdev->dev, sli4->bmbx.size,
+ &sli4->bmbx.phys, GFP_DMA);
+ if (!sli4->bmbx.virt) {
+ memset(&sli4->bmbx, 0, sizeof(struct efc_dma));
+ efc_log_err(sli4, "bootstrap mailbox allocation failed\n");
+ return -EIO;
+ }
+
+ if (sli4->bmbx.phys & SLI4_BMBX_MASK_LO) {
+ efc_log_err(sli4, "bad alignment for bootstrap mailbox\n");
+ return -EIO;
+ }
+
+ efc_log_info(sli4, "bmbx v=%p p=0x%x %08x s=%zd\n", sli4->bmbx.virt,
+ upper_32_bits(sli4->bmbx.phys),
+ lower_32_bits(sli4->bmbx.phys), sli4->bmbx.size);
+
+ /* 4096 is arbitrary. What should this value actually be? */
+ sli4->vpd_data.size = 4096;
+ sli4->vpd_data.virt = dma_alloc_coherent(&pdev->dev,
+ sli4->vpd_data.size,
+ &sli4->vpd_data.phys,
+ GFP_DMA);
+ if (!sli4->vpd_data.virt) {
+ memset(&sli4->vpd_data, 0, sizeof(struct efc_dma));
+ /* Note that failure isn't fatal in this specific case */
+ efc_log_info(sli4, "VPD buffer allocation failed\n");
+ }
+
+ if (!sli_fw_init(sli4)) {
+ efc_log_err(sli4, "FW initialization failed\n");
+ return -EIO;
+ }
+
+ /*
+ * Set one of fcpi(initiator), fcpt(target), fcpc(combined) to true
+ * in addition to any other desired features
+ */
+ sli4->features = (SLI4_REQFEAT_IAAB | SLI4_REQFEAT_NPIV |
+ SLI4_REQFEAT_DIF | SLI4_REQFEAT_VF |
+ SLI4_REQFEAT_FCPC | SLI4_REQFEAT_IAAR |
+ SLI4_REQFEAT_HLM | SLI4_REQFEAT_PERFH |
+ SLI4_REQFEAT_RXSEQ | SLI4_REQFEAT_RXRI |
+ SLI4_REQFEAT_MRQP);
+
+ /* use performance hints if available */
+ if (sli4->params.perf_hint)
+ sli4->features |= SLI4_REQFEAT_PERFH;
+
+ if (sli_request_features(sli4, &sli4->features, true))
+ return -EIO;
+
+ if (sli_get_config(sli4))
+ return -EIO;
+
+ return 0;
+}
+
+int
+sli_init(struct sli4 *sli4)
+{
+ if (sli4->params.has_extents) {
+ efc_log_info(sli4, "extend allocation not supported\n");
+ return -EIO;
+ }
+
+ sli4->features &= (~SLI4_REQFEAT_HLM);
+ sli4->features &= (~SLI4_REQFEAT_RXSEQ);
+ sli4->features &= (~SLI4_REQFEAT_RXRI);
+
+ if (sli_request_features(sli4, &sli4->features, false))
+ return -EIO;
+
+ return 0;
+}
+
+int
+sli_reset(struct sli4 *sli4)
+{
+ u32 i;
+
+ if (!sli_fw_init(sli4)) {
+ efc_log_crit(sli4, "FW initialization failed\n");
+ return -EIO;
+ }
+
+ kfree(sli4->ext[0].base);
+ sli4->ext[0].base = NULL;
+
+ for (i = 0; i < SLI4_RSRC_MAX; i++) {
+ kfree(sli4->ext[i].use_map);
+ sli4->ext[i].use_map = NULL;
+ sli4->ext[i].base = NULL;
+ }
+
+ return sli_get_config(sli4);
+}
+
+int
+sli_fw_reset(struct sli4 *sli4)
+{
+ /*
+ * Firmware must be ready before issuing the reset.
+ */
+ if (!sli_wait_for_fw_ready(sli4, SLI4_FW_READY_TIMEOUT_MSEC)) {
+ efc_log_crit(sli4, "FW status is NOT ready\n");
+ return -EIO;
+ }
+
+ /* Lancer uses PHYDEV_CONTROL */
+ writel(SLI4_PHYDEV_CTRL_FRST, (sli4->reg[0] + SLI4_PHYDEV_CTRL_REG));
+
+ /* wait for the FW to become ready after the reset */
+ if (!sli_wait_for_fw_ready(sli4, SLI4_FW_READY_TIMEOUT_MSEC)) {
+ efc_log_crit(sli4, "Failed to be ready after firmware reset\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+void
+sli_teardown(struct sli4 *sli4)
+{
+ u32 i;
+
+ kfree(sli4->ext[0].base);
+ sli4->ext[0].base = NULL;
+
+ for (i = 0; i < SLI4_RSRC_MAX; i++) {
+ sli4->ext[i].base = NULL;
+
+ kfree(sli4->ext[i].use_map);
+ sli4->ext[i].use_map = NULL;
+ }
+
+ if (!sli_sliport_reset(sli4))
+ efc_log_err(sli4, "FW deinitialization failed\n");
+
+ dma_free_coherent(&sli4->pci->dev, sli4->vpd_data.size,
+ sli4->vpd_data.virt, sli4->vpd_data.phys);
+ memset(&sli4->vpd_data, 0, sizeof(struct efc_dma));
+
+ dma_free_coherent(&sli4->pci->dev, sli4->bmbx.size,
+ sli4->bmbx.virt, sli4->bmbx.phys);
+ memset(&sli4->bmbx, 0, sizeof(struct efc_dma));
+}
+
+int
+sli_callback(struct sli4 *sli4, enum sli4_callback which,
+ void *func, void *arg)
+{
+ if (!func) {
+ efc_log_err(sli4, "bad parameter sli4=%p which=%#x func=%p\n",
+ sli4, which, func);
+ return -EIO;
+ }
+
+ switch (which) {
+ case SLI4_CB_LINK:
+ sli4->link = func;
+ sli4->link_arg = arg;
+ break;
+ default:
+ efc_log_info(sli4, "unknown callback %#x\n", which);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int
+sli_eq_modify_delay(struct sli4 *sli4, struct sli4_queue *eq,
+ u32 num_eq, u32 shift, u32 delay_mult)
+{
+ sli_cmd_common_modify_eq_delay(sli4, sli4->bmbx.virt, eq, num_eq,
+ shift, delay_mult);
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_crit(sli4, "bootstrap mailbox write fail (MODIFY EQ DELAY)\n");
+ return -EIO;
+ }
+ if (sli_res_sli_config(sli4, sli4->bmbx.virt)) {
+ efc_log_err(sli4, "bad status MODIFY EQ DELAY\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int
+sli_resource_alloc(struct sli4 *sli4, enum sli4_resource rtype,
+ u32 *rid, u32 *index)
+{
+ int rc = 0;
+ u32 size;
+ u32 ext_idx;
+ u32 item_idx;
+ u32 position;
+
+ *rid = U32_MAX;
+ *index = U32_MAX;
+
+ switch (rtype) {
+ case SLI4_RSRC_VFI:
+ case SLI4_RSRC_VPI:
+ case SLI4_RSRC_RPI:
+ case SLI4_RSRC_XRI:
+ position =
+ find_first_zero_bit(sli4->ext[rtype].use_map,
+ sli4->ext[rtype].map_size);
+ if (position >= sli4->ext[rtype].map_size) {
+ efc_log_err(sli4, "out of resource %d (alloc=%d)\n",
+ rtype, sli4->ext[rtype].n_alloc);
+ rc = -EIO;
+ break;
+ }
+ set_bit(position, sli4->ext[rtype].use_map);
+ *index = position;
+
+ size = sli4->ext[rtype].size;
+
+ ext_idx = *index / size;
+ item_idx = *index % size;
+
+ *rid = sli4->ext[rtype].base[ext_idx] + item_idx;
+
+ sli4->ext[rtype].n_alloc++;
+ break;
+ default:
+ rc = -EIO;
+ }
+
+ return rc;
+}
+
+int
+sli_resource_free(struct sli4 *sli4, enum sli4_resource rtype, u32 rid)
+{
+ int rc = -EIO;
+ u32 x;
+ u32 size, *base;
+
+ switch (rtype) {
+ case SLI4_RSRC_VFI:
+ case SLI4_RSRC_VPI:
+ case SLI4_RSRC_RPI:
+ case SLI4_RSRC_XRI:
+ /*
+ * Figure out which extent contains the resource ID. I.e. find
+ * the extent such that
+ * extent->base <= resource ID < extent->base + extent->size
+ */
+ base = sli4->ext[rtype].base;
+ size = sli4->ext[rtype].size;
+
+ /*
+ * In the case of FW reset, this may be cleared
+ * but the force_free path will still attempt to
+ * free the resource. Prevent a NULL pointer access.
+ */
+ if (!base)
+ break;
+
+ for (x = 0; x < sli4->ext[rtype].number; x++) {
+ if ((rid < base[x] || (rid >= (base[x] + size))))
+ continue;
+
+ rid -= base[x];
+ clear_bit((x * size) + rid, sli4->ext[rtype].use_map);
+ rc = 0;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+int
+sli_resource_reset(struct sli4 *sli4, enum sli4_resource rtype)
+{
+ int rc = -EIO;
+ u32 i;
+
+ switch (rtype) {
+ case SLI4_RSRC_VFI:
+ case SLI4_RSRC_VPI:
+ case SLI4_RSRC_RPI:
+ case SLI4_RSRC_XRI:
+ for (i = 0; i < sli4->ext[rtype].map_size; i++)
+ clear_bit(i, sli4->ext[rtype].use_map);
+ rc = 0;
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+int sli_raise_ue(struct sli4 *sli4, u8 dump)
+{
+ u32 val = 0;
+
+ if (dump == SLI4_FUNC_DESC_DUMP) {
+ val = SLI4_PORT_CTRL_FDD | SLI4_PORT_CTRL_IP;
+ writel(val, (sli4->reg[0] + SLI4_PORT_CTRL_REG));
+ } else {
+ val = SLI4_PHYDEV_CTRL_FRST;
+
+ if (dump == SLI4_CHIP_LEVEL_DUMP)
+ val |= SLI4_PHYDEV_CTRL_DD;
+ writel(val, (sli4->reg[0] + SLI4_PHYDEV_CTRL_REG));
+ }
+
+ return 0;
+}
+
+int sli_dump_is_ready(struct sli4 *sli4)
+{
+ int rc = SLI4_DUMP_READY_STATUS_NOT_READY;
+ u32 port_val;
+ u32 bmbx_val;
+
+ /*
+ * Ensure that the port is ready AND the mailbox is
+ * ready before signaling that the dump is ready to go.
+ */
+ port_val = sli_reg_read_status(sli4);
+ bmbx_val = readl(sli4->reg[0] + SLI4_BMBX_REG);
+
+ if ((bmbx_val & SLI4_BMBX_RDY) &&
+ (port_val & SLI4_PORT_STATUS_RDY)) {
+ if (port_val & SLI4_PORT_STATUS_DIP)
+ rc = SLI4_DUMP_READY_STATUS_DD_PRESENT;
+ else if (port_val & SLI4_PORT_STATUS_FDP)
+ rc = SLI4_DUMP_READY_STATUS_FDB_PRESENT;
+ }
+
+ return rc;
+}
+
+bool sli_reset_required(struct sli4 *sli4)
+{
+ u32 val;
+
+ val = sli_reg_read_status(sli4);
+ return (val & SLI4_PORT_STATUS_RN);
+}
+
+int
+sli_cmd_post_sgl_pages(struct sli4 *sli4, void *buf, u16 xri,
+ u32 xri_count, struct efc_dma *page0[],
+ struct efc_dma *page1[], struct efc_dma *dma)
+{
+ struct sli4_rqst_post_sgl_pages *post = NULL;
+ u32 i;
+ __le32 req_len;
+
+ post = sli_config_cmd_init(sli4, buf,
+ SLI4_CFG_PYLD_LENGTH(post_sgl_pages), dma);
+ if (!post)
+ return -EIO;
+
+ /* payload size calculation */
+ /* 4 = xri_start + xri_count */
+ /* xri_count = # of XRI's registered */
+ /* sizeof(uint64_t) = physical address size */
+ /* 2 = # of physical addresses per page set */
+ req_len = cpu_to_le32(4 + (xri_count * (sizeof(uint64_t) * 2)));
+ sli_cmd_fill_hdr(&post->hdr, SLI4_OPC_POST_SGL_PAGES, SLI4_SUBSYSTEM_FC,
+ CMD_V0, req_len);
+ post->xri_start = cpu_to_le16(xri);
+ post->xri_count = cpu_to_le16(xri_count);
+
+ for (i = 0; i < xri_count; i++) {
+ post->page_set[i].page0_low =
+ cpu_to_le32(lower_32_bits(page0[i]->phys));
+ post->page_set[i].page0_high =
+ cpu_to_le32(upper_32_bits(page0[i]->phys));
+ }
+
+ if (page1) {
+ for (i = 0; i < xri_count; i++) {
+ post->page_set[i].page1_low =
+ cpu_to_le32(lower_32_bits(page1[i]->phys));
+ post->page_set[i].page1_high =
+ cpu_to_le32(upper_32_bits(page1[i]->phys));
+ }
+ }
+
+ return 0;
+}
+
+int
+sli_cmd_post_hdr_templates(struct sli4 *sli4, void *buf, struct efc_dma *dma,
+ u16 rpi, struct efc_dma *payload_dma)
+{
+ struct sli4_rqst_post_hdr_templates *req = NULL;
+ uintptr_t phys = 0;
+ u32 i = 0;
+ u32 page_count, payload_size;
+
+ page_count = sli_page_count(dma->size, SLI_PAGE_SIZE);
+
+ payload_size = ((sizeof(struct sli4_rqst_post_hdr_templates) +
+ (page_count * SZ_DMAADDR)) - sizeof(struct sli4_rqst_hdr));
+
+ if (page_count > 16) {
+ /*
+ * We can't fit more than 16 descriptors into an embedded mbox
+ * command, it has to be non-embedded
+ */
+ payload_dma->size = payload_size;
+ payload_dma->virt = dma_alloc_coherent(&sli4->pci->dev,
+ payload_dma->size,
+ &payload_dma->phys, GFP_DMA);
+ if (!payload_dma->virt) {
+ memset(payload_dma, 0, sizeof(struct efc_dma));
+ efc_log_err(sli4, "mbox payload memory allocation fail\n");
+ return -EIO;
+ }
+ req = sli_config_cmd_init(sli4, buf, payload_size, payload_dma);
+ } else {
+ req = sli_config_cmd_init(sli4, buf, payload_size, NULL);
+ }
+
+ if (!req)
+ return -EIO;
+
+ if (rpi == U16_MAX)
+ rpi = sli4->ext[SLI4_RSRC_RPI].base[0];
+
+ sli_cmd_fill_hdr(&req->hdr, SLI4_OPC_POST_HDR_TEMPLATES,
+ SLI4_SUBSYSTEM_FC, CMD_V0,
+ SLI4_RQST_PYLD_LEN(post_hdr_templates));
+
+ req->rpi_offset = cpu_to_le16(rpi);
+ req->page_count = cpu_to_le16(page_count);
+ phys = dma->phys;
+ for (i = 0; i < page_count; i++) {
+ req->page_descriptor[i].low = cpu_to_le32(lower_32_bits(phys));
+ req->page_descriptor[i].high = cpu_to_le32(upper_32_bits(phys));
+
+ phys += SLI_PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+u32
+sli_fc_get_rpi_requirements(struct sli4 *sli4, u32 n_rpi)
+{
+ u32 bytes = 0;
+
+ /* Check if header templates needed */
+ if (sli4->params.hdr_template_req)
+ /* round up to a page */
+ bytes = round_up(n_rpi * SLI4_HDR_TEMPLATE_SIZE, SLI_PAGE_SIZE);
+
+ return bytes;
+}
+
+const char *
+sli_fc_get_status_string(u32 status)
+{
+ static struct {
+ u32 code;
+ const char *label;
+ } lookup[] = {
+ {SLI4_FC_WCQE_STATUS_SUCCESS, "SUCCESS"},
+ {SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE, "FCP_RSP_FAILURE"},
+ {SLI4_FC_WCQE_STATUS_REMOTE_STOP, "REMOTE_STOP"},
+ {SLI4_FC_WCQE_STATUS_LOCAL_REJECT, "LOCAL_REJECT"},
+ {SLI4_FC_WCQE_STATUS_NPORT_RJT, "NPORT_RJT"},
+ {SLI4_FC_WCQE_STATUS_FABRIC_RJT, "FABRIC_RJT"},
+ {SLI4_FC_WCQE_STATUS_NPORT_BSY, "NPORT_BSY"},
+ {SLI4_FC_WCQE_STATUS_FABRIC_BSY, "FABRIC_BSY"},
+ {SLI4_FC_WCQE_STATUS_LS_RJT, "LS_RJT"},
+ {SLI4_FC_WCQE_STATUS_CMD_REJECT, "CMD_REJECT"},
+ {SLI4_FC_WCQE_STATUS_FCP_TGT_LENCHECK, "FCP_TGT_LENCHECK"},
+ {SLI4_FC_WCQE_STATUS_RQ_BUF_LEN_EXCEEDED, "BUF_LEN_EXCEEDED"},
+ {SLI4_FC_WCQE_STATUS_RQ_INSUFF_BUF_NEEDED,
+ "RQ_INSUFF_BUF_NEEDED"},
+ {SLI4_FC_WCQE_STATUS_RQ_INSUFF_FRM_DISC, "RQ_INSUFF_FRM_DESC"},
+ {SLI4_FC_WCQE_STATUS_RQ_DMA_FAILURE, "RQ_DMA_FAILURE"},
+ {SLI4_FC_WCQE_STATUS_FCP_RSP_TRUNCATE, "FCP_RSP_TRUNCATE"},
+ {SLI4_FC_WCQE_STATUS_DI_ERROR, "DI_ERROR"},
+ {SLI4_FC_WCQE_STATUS_BA_RJT, "BA_RJT"},
+ {SLI4_FC_WCQE_STATUS_RQ_INSUFF_XRI_NEEDED,
+ "RQ_INSUFF_XRI_NEEDED"},
+ {SLI4_FC_WCQE_STATUS_RQ_INSUFF_XRI_DISC, "INSUFF_XRI_DISC"},
+ {SLI4_FC_WCQE_STATUS_RX_ERROR_DETECT, "RX_ERROR_DETECT"},
+ {SLI4_FC_WCQE_STATUS_RX_ABORT_REQUEST, "RX_ABORT_REQUEST"},
+ };
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(lookup); i++) {
+ if (status == lookup[i].code)
+ return lookup[i].label;
+ }
+ return "unknown";
+}
diff --git a/drivers/scsi/elx/libefc_sli/sli4.h b/drivers/scsi/elx/libefc_sli/sli4.h
new file mode 100644
index 000000000000..ee2a9e65a88d
--- /dev/null
+++ b/drivers/scsi/elx/libefc_sli/sli4.h
@@ -0,0 +1,4132 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
+ * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
+ *
+ */
+
+/*
+ * All common SLI-4 structures and function prototypes.
+ */
+
+#ifndef _SLI4_H
+#define _SLI4_H
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include "scsi/fc/fc_els.h"
+#include "scsi/fc/fc_fs.h"
+#include "../include/efc_common.h"
+
+/*************************************************************************
+ * Common SLI-4 register offsets and field definitions
+ */
+
+/* SLI_INTF - SLI Interface Definition Register */
+#define SLI4_INTF_REG 0x0058
+enum sli4_intf {
+ SLI4_INTF_REV_SHIFT = 4,
+ SLI4_INTF_REV_MASK = 0xf0,
+
+ SLI4_INTF_REV_S3 = 0x30,
+ SLI4_INTF_REV_S4 = 0x40,
+
+ SLI4_INTF_FAMILY_SHIFT = 8,
+ SLI4_INTF_FAMILY_MASK = 0x0f00,
+
+ SLI4_FAMILY_CHECK_ASIC_TYPE = 0x0f00,
+
+ SLI4_INTF_IF_TYPE_SHIFT = 12,
+ SLI4_INTF_IF_TYPE_MASK = 0xf000,
+
+ SLI4_INTF_IF_TYPE_2 = 0x2000,
+ SLI4_INTF_IF_TYPE_6 = 0x6000,
+
+ SLI4_INTF_VALID_SHIFT = 29,
+ SLI4_INTF_VALID_MASK = 0xe0000000,
+
+ SLI4_INTF_VALID_VALUE = 0xc0000000,
+};
+
+/* ASIC_ID - SLI ASIC Type and Revision Register */
+#define SLI4_ASIC_ID_REG 0x009c
+enum sli4_asic {
+ SLI4_ASIC_GEN_SHIFT = 8,
+ SLI4_ASIC_GEN_MASK = 0xff00,
+ SLI4_ASIC_GEN_5 = 0x0b00,
+ SLI4_ASIC_GEN_6 = 0x0c00,
+ SLI4_ASIC_GEN_7 = 0x0d00,
+};
+
+enum sli4_acic_revisions {
+ SLI4_ASIC_REV_A0 = 0x00,
+ SLI4_ASIC_REV_A1 = 0x01,
+ SLI4_ASIC_REV_A2 = 0x02,
+ SLI4_ASIC_REV_A3 = 0x03,
+ SLI4_ASIC_REV_B0 = 0x10,
+ SLI4_ASIC_REV_B1 = 0x11,
+ SLI4_ASIC_REV_B2 = 0x12,
+ SLI4_ASIC_REV_C0 = 0x20,
+ SLI4_ASIC_REV_C1 = 0x21,
+ SLI4_ASIC_REV_C2 = 0x22,
+ SLI4_ASIC_REV_D0 = 0x30,
+};
+
+struct sli4_asic_entry_t {
+ u32 rev_id;
+ u32 family;
+};
+
+/* BMBX - Bootstrap Mailbox Register */
+#define SLI4_BMBX_REG 0x0160
+enum sli4_bmbx {
+ SLI4_BMBX_MASK_HI = 0x3,
+ SLI4_BMBX_MASK_LO = 0xf,
+ SLI4_BMBX_RDY = 1 << 0,
+ SLI4_BMBX_HI = 1 << 1,
+ SLI4_BMBX_SIZE = 256,
+};
+
+static inline u32
+sli_bmbx_write_hi(u64 addr) {
+ u32 val;
+
+ val = upper_32_bits(addr) & ~SLI4_BMBX_MASK_HI;
+ val |= SLI4_BMBX_HI;
+
+ return val;
+}
+
+static inline u32
+sli_bmbx_write_lo(u64 addr) {
+ u32 val;
+
+ val = (upper_32_bits(addr) & SLI4_BMBX_MASK_HI) << 30;
+ val |= ((addr) & ~SLI4_BMBX_MASK_LO) >> 2;
+
+ return val;
+}
+
+/* SLIPORT_CONTROL - SLI Port Control Register */
+#define SLI4_PORT_CTRL_REG 0x0408
+enum sli4_port_ctrl {
+ SLI4_PORT_CTRL_IP = 1u << 27,
+ SLI4_PORT_CTRL_IDIS = 1u << 22,
+ SLI4_PORT_CTRL_FDD = 1u << 31,
+};
+
+/* SLI4_SLIPORT_ERROR - SLI Port Error Register */
+#define SLI4_PORT_ERROR1 0x040c
+#define SLI4_PORT_ERROR2 0x0410
+
+/* EQCQ_DOORBELL - EQ and CQ Doorbell Register */
+#define SLI4_EQCQ_DB_REG 0x120
+enum sli4_eqcq_e {
+ SLI4_EQ_ID_LO_MASK = 0x01ff,
+
+ SLI4_CQ_ID_LO_MASK = 0x03ff,
+
+ SLI4_EQCQ_CI_EQ = 0x0200,
+
+ SLI4_EQCQ_QT_EQ = 0x00000400,
+ SLI4_EQCQ_QT_CQ = 0x00000000,
+
+ SLI4_EQCQ_ID_HI_SHIFT = 11,
+ SLI4_EQCQ_ID_HI_MASK = 0xf800,
+
+ SLI4_EQCQ_NUM_SHIFT = 16,
+ SLI4_EQCQ_NUM_MASK = 0x1fff0000,
+
+ SLI4_EQCQ_ARM = 0x20000000,
+ SLI4_EQCQ_UNARM = 0x00000000,
+};
+
+static inline u32
+sli_format_eq_db_data(u16 num_popped, u16 id, u32 arm) {
+ u32 reg;
+
+ reg = (id & SLI4_EQ_ID_LO_MASK) | SLI4_EQCQ_QT_EQ;
+ reg |= (((id) >> 9) << SLI4_EQCQ_ID_HI_SHIFT) & SLI4_EQCQ_ID_HI_MASK;
+ reg |= ((num_popped) << SLI4_EQCQ_NUM_SHIFT) & SLI4_EQCQ_NUM_MASK;
+ reg |= arm | SLI4_EQCQ_CI_EQ;
+
+ return reg;
+}
+
+static inline u32
+sli_format_cq_db_data(u16 num_popped, u16 id, u32 arm) {
+ u32 reg;
+
+ reg = ((id) & SLI4_CQ_ID_LO_MASK) | SLI4_EQCQ_QT_CQ;
+ reg |= (((id) >> 10) << SLI4_EQCQ_ID_HI_SHIFT) & SLI4_EQCQ_ID_HI_MASK;
+ reg |= ((num_popped) << SLI4_EQCQ_NUM_SHIFT) & SLI4_EQCQ_NUM_MASK;
+ reg |= arm;
+
+ return reg;
+}
+
+/* EQ_DOORBELL - EQ Doorbell Register for IF_TYPE = 6*/
+#define SLI4_IF6_EQ_DB_REG 0x120
+enum sli4_eq_e {
+ SLI4_IF6_EQ_ID_MASK = 0x0fff,
+
+ SLI4_IF6_EQ_NUM_SHIFT = 16,
+ SLI4_IF6_EQ_NUM_MASK = 0x1fff0000,
+};
+
+static inline u32
+sli_format_if6_eq_db_data(u16 num_popped, u16 id, u32 arm) {
+ u32 reg;
+
+ reg = id & SLI4_IF6_EQ_ID_MASK;
+ reg |= (num_popped << SLI4_IF6_EQ_NUM_SHIFT) & SLI4_IF6_EQ_NUM_MASK;
+ reg |= arm;
+
+ return reg;
+}
+
+/* CQ_DOORBELL - CQ Doorbell Register for IF_TYPE = 6 */
+#define SLI4_IF6_CQ_DB_REG 0xc0
+enum sli4_cq_e {
+ SLI4_IF6_CQ_ID_MASK = 0xffff,
+
+ SLI4_IF6_CQ_NUM_SHIFT = 16,
+ SLI4_IF6_CQ_NUM_MASK = 0x1fff0000,
+};
+
+static inline u32
+sli_format_if6_cq_db_data(u16 num_popped, u16 id, u32 arm) {
+ u32 reg;
+
+ reg = id & SLI4_IF6_CQ_ID_MASK;
+ reg |= ((num_popped) << SLI4_IF6_CQ_NUM_SHIFT) & SLI4_IF6_CQ_NUM_MASK;
+ reg |= arm;
+
+ return reg;
+}
+
+/* MQ_DOORBELL - MQ Doorbell Register */
+#define SLI4_MQ_DB_REG 0x0140
+#define SLI4_IF6_MQ_DB_REG 0x0160
+enum sli4_mq_e {
+ SLI4_MQ_ID_MASK = 0xffff,
+
+ SLI4_MQ_NUM_SHIFT = 16,
+ SLI4_MQ_NUM_MASK = 0x3fff0000,
+};
+
+static inline u32
+sli_format_mq_db_data(u16 id) {
+ u32 reg;
+
+ reg = id & SLI4_MQ_ID_MASK;
+ reg |= (1 << SLI4_MQ_NUM_SHIFT) & SLI4_MQ_NUM_MASK;
+
+ return reg;
+}
+
+/* RQ_DOORBELL - RQ Doorbell Register */
+#define SLI4_RQ_DB_REG 0x0a0
+#define SLI4_IF6_RQ_DB_REG 0x0080
+enum sli4_rq_e {
+ SLI4_RQ_DB_ID_MASK = 0xffff,
+
+ SLI4_RQ_DB_NUM_SHIFT = 16,
+ SLI4_RQ_DB_NUM_MASK = 0x3fff0000,
+};
+
+static inline u32
+sli_format_rq_db_data(u16 id) {
+ u32 reg;
+
+ reg = id & SLI4_RQ_DB_ID_MASK;
+ reg |= (1 << SLI4_RQ_DB_NUM_SHIFT) & SLI4_RQ_DB_NUM_MASK;
+
+ return reg;
+}
+
+/* WQ_DOORBELL - WQ Doorbell Register */
+#define SLI4_IO_WQ_DB_REG 0x040
+#define SLI4_IF6_WQ_DB_REG 0x040
+enum sli4_wq_e {
+ SLI4_WQ_ID_MASK = 0xffff,
+
+ SLI4_WQ_IDX_SHIFT = 16,
+ SLI4_WQ_IDX_MASK = 0xff0000,
+
+ SLI4_WQ_NUM_SHIFT = 24,
+ SLI4_WQ_NUM_MASK = 0x0ff00000,
+};
+
+static inline u32
+sli_format_wq_db_data(u16 id) {
+ u32 reg;
+
+ reg = id & SLI4_WQ_ID_MASK;
+ reg |= (1 << SLI4_WQ_NUM_SHIFT) & SLI4_WQ_NUM_MASK;
+
+ return reg;
+}
+
+/* SLIPORT_STATUS - SLI Port Status Register */
+#define SLI4_PORT_STATUS_REGOFF 0x0404
+enum sli4_port_status {
+ SLI4_PORT_STATUS_FDP = 1u << 21,
+ SLI4_PORT_STATUS_RDY = 1u << 23,
+ SLI4_PORT_STATUS_RN = 1u << 24,
+ SLI4_PORT_STATUS_DIP = 1u << 25,
+ SLI4_PORT_STATUS_OTI = 1u << 29,
+ SLI4_PORT_STATUS_ERR = 1u << 31,
+};
+
+#define SLI4_PHYDEV_CTRL_REG 0x0414
+#define SLI4_PHYDEV_CTRL_FRST (1 << 1)
+#define SLI4_PHYDEV_CTRL_DD (1 << 2)
+
+/* Register name enums */
+enum sli4_regname_en {
+ SLI4_REG_BMBX,
+ SLI4_REG_EQ_DOORBELL,
+ SLI4_REG_CQ_DOORBELL,
+ SLI4_REG_RQ_DOORBELL,
+ SLI4_REG_IO_WQ_DOORBELL,
+ SLI4_REG_MQ_DOORBELL,
+ SLI4_REG_PHYSDEV_CONTROL,
+ SLI4_REG_PORT_CONTROL,
+ SLI4_REG_PORT_ERROR1,
+ SLI4_REG_PORT_ERROR2,
+ SLI4_REG_PORT_SEMAPHORE,
+ SLI4_REG_PORT_STATUS,
+ SLI4_REG_UNKWOWN /* must be last */
+};
+
+struct sli4_reg {
+ u32 rset;
+ u32 off;
+};
+
+struct sli4_dmaaddr {
+ __le32 low;
+ __le32 high;
+};
+
+/*
+ * a 3-word Buffer Descriptor Entry with
+ * address 1st 2 words, length last word
+ */
+struct sli4_bufptr {
+ struct sli4_dmaaddr addr;
+ __le32 length;
+};
+
+/* Buffer Descriptor Entry (BDE) */
+enum sli4_bde_e {
+ SLI4_BDE_LEN_MASK = 0x00ffffff,
+ SLI4_BDE_TYPE_MASK = 0xff000000,
+};
+
+struct sli4_bde {
+ __le32 bde_type_buflen;
+ union {
+ struct sli4_dmaaddr data;
+ struct {
+ __le32 offset;
+ __le32 rsvd2;
+ } imm;
+ struct sli4_dmaaddr blp;
+ } u;
+};
+
+/* Buffer Descriptors */
+enum sli4_bde_type {
+ SLI4_BDE_TYPE_SHIFT = 24,
+ SLI4_BDE_TYPE_64 = 0x00, /* Generic 64-bit data */
+ SLI4_BDE_TYPE_IMM = 0x01, /* Immediate data */
+ SLI4_BDE_TYPE_BLP = 0x40, /* Buffer List Pointer */
+};
+
+#define SLI4_BDE_TYPE_VAL(type) \
+ (SLI4_BDE_TYPE_##type << SLI4_BDE_TYPE_SHIFT)
+
+/* Scatter-Gather Entry (SGE) */
+#define SLI4_SGE_MAX_RESERVED 3
+
+enum sli4_sge_type {
+ /* DW2 */
+ SLI4_SGE_DATA_OFFSET_MASK = 0x07ffffff,
+ /*DW2W1*/
+ SLI4_SGE_TYPE_SHIFT = 27,
+ SLI4_SGE_TYPE_MASK = 0x78000000,
+ /*SGE Types*/
+ SLI4_SGE_TYPE_DATA = 0x00,
+ SLI4_SGE_TYPE_DIF = 0x04, /* Data Integrity Field */
+ SLI4_SGE_TYPE_LSP = 0x05, /* List Segment Pointer */
+ SLI4_SGE_TYPE_PEDIF = 0x06, /* Post Encryption Engine DIF */
+ SLI4_SGE_TYPE_PESEED = 0x07, /* Post Encryption DIF Seed */
+ SLI4_SGE_TYPE_DISEED = 0x08, /* DIF Seed */
+ SLI4_SGE_TYPE_ENC = 0x09, /* Encryption */
+ SLI4_SGE_TYPE_ATM = 0x0a, /* DIF Application Tag Mask */
+ SLI4_SGE_TYPE_SKIP = 0x0c, /* SKIP */
+
+ SLI4_SGE_LAST = 1u << 31,
+};
+
+struct sli4_sge {
+ __le32 buffer_address_high;
+ __le32 buffer_address_low;
+ __le32 dw2_flags;
+ __le32 buffer_length;
+};
+
+/* T10 DIF Scatter-Gather Entry (SGE) */
+struct sli4_dif_sge {
+ __le32 buffer_address_high;
+ __le32 buffer_address_low;
+ __le32 dw2_flags;
+ __le32 rsvd12;
+};
+
+/* Data Integrity Seed (DISEED) SGE */
+enum sli4_diseed_sge_flags {
+ /* DW2W1 */
+ SLI4_DISEED_SGE_HS = 1 << 2,
+ SLI4_DISEED_SGE_WS = 1 << 3,
+ SLI4_DISEED_SGE_IC = 1 << 4,
+ SLI4_DISEED_SGE_ICS = 1 << 5,
+ SLI4_DISEED_SGE_ATRT = 1 << 6,
+ SLI4_DISEED_SGE_AT = 1 << 7,
+ SLI4_DISEED_SGE_FAT = 1 << 8,
+ SLI4_DISEED_SGE_NA = 1 << 9,
+ SLI4_DISEED_SGE_HI = 1 << 10,
+
+ /* DW3W1 */
+ SLI4_DISEED_SGE_BS_MASK = 0x0007,
+ SLI4_DISEED_SGE_AI = 1 << 3,
+ SLI4_DISEED_SGE_ME = 1 << 4,
+ SLI4_DISEED_SGE_RE = 1 << 5,
+ SLI4_DISEED_SGE_CE = 1 << 6,
+ SLI4_DISEED_SGE_NR = 1 << 7,
+
+ SLI4_DISEED_SGE_OP_RX_SHIFT = 8,
+ SLI4_DISEED_SGE_OP_RX_MASK = 0x0f00,
+ SLI4_DISEED_SGE_OP_TX_SHIFT = 12,
+ SLI4_DISEED_SGE_OP_TX_MASK = 0xf000,
+};
+
+/* Opcode values */
+enum sli4_diseed_sge_opcodes {
+ SLI4_DISEED_SGE_OP_IN_NODIF_OUT_CRC,
+ SLI4_DISEED_SGE_OP_IN_CRC_OUT_NODIF,
+ SLI4_DISEED_SGE_OP_IN_NODIF_OUT_CSUM,
+ SLI4_DISEED_SGE_OP_IN_CSUM_OUT_NODIF,
+ SLI4_DISEED_SGE_OP_IN_CRC_OUT_CRC,
+ SLI4_DISEED_SGE_OP_IN_CSUM_OUT_CSUM,
+ SLI4_DISEED_SGE_OP_IN_CRC_OUT_CSUM,
+ SLI4_DISEED_SGE_OP_IN_CSUM_OUT_CRC,
+ SLI4_DISEED_SGE_OP_IN_RAW_OUT_RAW,
+};
+
+#define SLI4_DISEED_SGE_OP_RX_VALUE(stype) \
+ (SLI4_DISEED_SGE_OP_##stype << SLI4_DISEED_SGE_OP_RX_SHIFT)
+#define SLI4_DISEED_SGE_OP_TX_VALUE(stype) \
+ (SLI4_DISEED_SGE_OP_##stype << SLI4_DISEED_SGE_OP_TX_SHIFT)
+
+struct sli4_diseed_sge {
+ __le32 ref_tag_cmp;
+ __le32 ref_tag_repl;
+ __le16 app_tag_repl;
+ __le16 dw2w1_flags;
+ __le16 app_tag_cmp;
+ __le16 dw3w1_flags;
+};
+
+/* List Segment Pointer Scatter-Gather Entry (SGE) */
+#define SLI4_LSP_SGE_SEGLEN 0x00ffffff
+
+struct sli4_lsp_sge {
+ __le32 buffer_address_high;
+ __le32 buffer_address_low;
+ __le32 dw2_flags;
+ __le32 dw3_seglen;
+};
+
+enum sli4_eqe_e {
+ SLI4_EQE_VALID = 1,
+ SLI4_EQE_MJCODE = 0xe,
+ SLI4_EQE_MNCODE = 0xfff0,
+};
+
+struct sli4_eqe {
+ __le16 dw0w0_flags;
+ __le16 resource_id;
+};
+
+#define SLI4_MAJOR_CODE_STANDARD 0
+#define SLI4_MAJOR_CODE_SENTINEL 1
+
+/* Sentinel EQE indicating the EQ is full */
+#define SLI4_EQE_STATUS_EQ_FULL 2
+
+enum sli4_mcqe_e {
+ SLI4_MCQE_CONSUMED = 1u << 27,
+ SLI4_MCQE_COMPLETED = 1u << 28,
+ SLI4_MCQE_AE = 1u << 30,
+ SLI4_MCQE_VALID = 1u << 31,
+};
+
+/* Entry was consumed but not completed */
+#define SLI4_MCQE_STATUS_NOT_COMPLETED -2
+
+struct sli4_mcqe {
+ __le16 completion_status;
+ __le16 extended_status;
+ __le32 mqe_tag_low;
+ __le32 mqe_tag_high;
+ __le32 dw3_flags;
+};
+
+enum sli4_acqe_e {
+ SLI4_ACQE_AE = 1 << 6, /* async event - this is an ACQE */
+ SLI4_ACQE_VAL = 1 << 7, /* valid - contents of CQE are valid */
+};
+
+struct sli4_acqe {
+ __le32 event_data[3];
+ u8 rsvd12;
+ u8 event_code;
+ u8 event_type;
+ u8 ae_val;
+};
+
+enum sli4_acqe_event_code {
+ SLI4_ACQE_EVENT_CODE_LINK_STATE = 0x01,
+ SLI4_ACQE_EVENT_CODE_FIP = 0x02,
+ SLI4_ACQE_EVENT_CODE_DCBX = 0x03,
+ SLI4_ACQE_EVENT_CODE_ISCSI = 0x04,
+ SLI4_ACQE_EVENT_CODE_GRP_5 = 0x05,
+ SLI4_ACQE_EVENT_CODE_FC_LINK_EVENT = 0x10,
+ SLI4_ACQE_EVENT_CODE_SLI_PORT_EVENT = 0x11,
+ SLI4_ACQE_EVENT_CODE_VF_EVENT = 0x12,
+ SLI4_ACQE_EVENT_CODE_MR_EVENT = 0x13,
+};
+
+enum sli4_qtype {
+ SLI4_QTYPE_EQ,
+ SLI4_QTYPE_CQ,
+ SLI4_QTYPE_MQ,
+ SLI4_QTYPE_WQ,
+ SLI4_QTYPE_RQ,
+ SLI4_QTYPE_MAX, /* must be last */
+};
+
+#define SLI4_USER_MQ_COUNT 1
+#define SLI4_MAX_CQ_SET_COUNT 16
+#define SLI4_MAX_RQ_SET_COUNT 16
+
+enum sli4_qentry {
+ SLI4_QENTRY_ASYNC,
+ SLI4_QENTRY_MQ,
+ SLI4_QENTRY_RQ,
+ SLI4_QENTRY_WQ,
+ SLI4_QENTRY_WQ_RELEASE,
+ SLI4_QENTRY_OPT_WRITE_CMD,
+ SLI4_QENTRY_OPT_WRITE_DATA,
+ SLI4_QENTRY_XABT,
+ SLI4_QENTRY_MAX /* must be last */
+};
+
+enum sli4_queue_flags {
+ SLI4_QUEUE_FLAG_MQ = 1 << 0, /* CQ has MQ/Async completion */
+ SLI4_QUEUE_FLAG_HDR = 1 << 1, /* RQ for packet headers */
+ SLI4_QUEUE_FLAG_RQBATCH = 1 << 2, /* RQ index increment by 8 */
+};
+
+/* Generic Command Request header */
+enum sli4_cmd_version {
+ CMD_V0,
+ CMD_V1,
+ CMD_V2,
+};
+
+struct sli4_rqst_hdr {
+ u8 opcode;
+ u8 subsystem;
+ __le16 rsvd2;
+ __le32 timeout;
+ __le32 request_length;
+ __le32 dw3_version;
+};
+
+/* Generic Command Response header */
+struct sli4_rsp_hdr {
+ u8 opcode;
+ u8 subsystem;
+ __le16 rsvd2;
+ u8 status;
+ u8 additional_status;
+ __le16 rsvd6;
+ __le32 response_length;
+ __le32 actual_response_length;
+};
+
+#define SLI4_QUEUE_RQ_BATCH 8
+
+#define SZ_DMAADDR sizeof(struct sli4_dmaaddr)
+#define SLI4_RQST_CMDSZ(stype) sizeof(struct sli4_rqst_##stype)
+
+#define SLI4_RQST_PYLD_LEN(stype) \
+ cpu_to_le32(sizeof(struct sli4_rqst_##stype) - \
+ sizeof(struct sli4_rqst_hdr))
+
+#define SLI4_RQST_PYLD_LEN_VAR(stype, varpyld) \
+ cpu_to_le32((sizeof(struct sli4_rqst_##stype) + \
+ varpyld) - sizeof(struct sli4_rqst_hdr))
+
+#define SLI4_CFG_PYLD_LENGTH(stype) \
+ max(sizeof(struct sli4_rqst_##stype), \
+ sizeof(struct sli4_rsp_##stype))
+
+enum sli4_create_cqv2_e {
+ /* DW5_flags values*/
+ SLI4_CREATE_CQV2_CLSWM_MASK = 0x00003000,
+ SLI4_CREATE_CQV2_NODELAY = 0x00004000,
+ SLI4_CREATE_CQV2_AUTOVALID = 0x00008000,
+ SLI4_CREATE_CQV2_CQECNT_MASK = 0x18000000,
+ SLI4_CREATE_CQV2_VALID = 0x20000000,
+ SLI4_CREATE_CQV2_EVT = 0x80000000,
+ /* DW6W1_flags values*/
+ SLI4_CREATE_CQV2_ARM = 0x8000,
+};
+
+struct sli4_rqst_cmn_create_cq_v2 {
+ struct sli4_rqst_hdr hdr;
+ __le16 num_pages;
+ u8 page_size;
+ u8 rsvd19;
+ __le32 dw5_flags;
+ __le16 eq_id;
+ __le16 dw6w1_arm;
+ __le16 cqe_count;
+ __le16 rsvd30;
+ __le32 rsvd32;
+ struct sli4_dmaaddr page_phys_addr[0];
+};
+
+enum sli4_create_cqset_e {
+ /* DW5_flags values*/
+ SLI4_CREATE_CQSETV0_CLSWM_MASK = 0x00003000,
+ SLI4_CREATE_CQSETV0_NODELAY = 0x00004000,
+ SLI4_CREATE_CQSETV0_AUTOVALID = 0x00008000,
+ SLI4_CREATE_CQSETV0_CQECNT_MASK = 0x18000000,
+ SLI4_CREATE_CQSETV0_VALID = 0x20000000,
+ SLI4_CREATE_CQSETV0_EVT = 0x80000000,
+ /* DW5W1_flags values */
+ SLI4_CREATE_CQSETV0_CQE_COUNT = 0x7fff,
+ SLI4_CREATE_CQSETV0_ARM = 0x8000,
+};
+
+struct sli4_rqst_cmn_create_cq_set_v0 {
+ struct sli4_rqst_hdr hdr;
+ __le16 num_pages;
+ u8 page_size;
+ u8 rsvd19;
+ __le32 dw5_flags;
+ __le16 num_cq_req;
+ __le16 dw6w1_flags;
+ __le16 eq_id[16];
+ struct sli4_dmaaddr page_phys_addr[0];
+};
+
+/* CQE count */
+enum sli4_cq_cnt {
+ SLI4_CQ_CNT_256,
+ SLI4_CQ_CNT_512,
+ SLI4_CQ_CNT_1024,
+ SLI4_CQ_CNT_LARGE,
+};
+
+#define SLI4_CQ_CNT_SHIFT 27
+#define SLI4_CQ_CNT_VAL(type) (SLI4_CQ_CNT_##type << SLI4_CQ_CNT_SHIFT)
+
+#define SLI4_CQE_BYTES (4 * sizeof(u32))
+
+#define SLI4_CREATE_CQV2_MAX_PAGES 8
+
+/* Generic Common Create EQ/CQ/MQ/WQ/RQ Queue completion */
+struct sli4_rsp_cmn_create_queue {
+ struct sli4_rsp_hdr hdr;
+ __le16 q_id;
+ u8 rsvd18;
+ u8 ulp;
+ __le32 db_offset;
+ __le16 db_rs;
+ __le16 db_fmt;
+};
+
+struct sli4_rsp_cmn_create_queue_set {
+ struct sli4_rsp_hdr hdr;
+ __le16 q_id;
+ __le16 num_q_allocated;
+};
+
+/* Common Destroy Queue */
+struct sli4_rqst_cmn_destroy_q {
+ struct sli4_rqst_hdr hdr;
+ __le16 q_id;
+ __le16 rsvd;
+};
+
+struct sli4_rsp_cmn_destroy_q {
+ struct sli4_rsp_hdr hdr;
+};
+
+/* Modify the delay multiplier for EQs */
+struct sli4_eqdelay_rec {
+ __le32 eq_id;
+ __le32 phase;
+ __le32 delay_multiplier;
+};
+
+struct sli4_rqst_cmn_modify_eq_delay {
+ struct sli4_rqst_hdr hdr;
+ __le32 num_eq;
+ struct sli4_eqdelay_rec eq_delay_record[8];
+};
+
+struct sli4_rsp_cmn_modify_eq_delay {
+ struct sli4_rsp_hdr hdr;
+};
+
+enum sli4_create_cq_e {
+ /* DW5 */
+ SLI4_CREATE_EQ_AUTOVALID = 1u << 28,
+ SLI4_CREATE_EQ_VALID = 1u << 29,
+ SLI4_CREATE_EQ_EQESZ = 1u << 31,
+ /* DW6 */
+ SLI4_CREATE_EQ_COUNT = 7 << 26,
+ SLI4_CREATE_EQ_ARM = 1u << 31,
+ /* DW7 */
+ SLI4_CREATE_EQ_DELAYMULTI_SHIFT = 13,
+ SLI4_CREATE_EQ_DELAYMULTI_MASK = 0x007fe000,
+ SLI4_CREATE_EQ_DELAYMULTI = 0x00040000,
+};
+
+struct sli4_rqst_cmn_create_eq {
+ struct sli4_rqst_hdr hdr;
+ __le16 num_pages;
+ __le16 rsvd18;
+ __le32 dw5_flags;
+ __le32 dw6_flags;
+ __le32 dw7_delaymulti;
+ __le32 rsvd32;
+ struct sli4_dmaaddr page_address[8];
+};
+
+struct sli4_rsp_cmn_create_eq {
+ struct sli4_rsp_cmn_create_queue q_rsp;
+};
+
+/* EQ count */
+enum sli4_eq_cnt {
+ SLI4_EQ_CNT_256,
+ SLI4_EQ_CNT_512,
+ SLI4_EQ_CNT_1024,
+ SLI4_EQ_CNT_2048,
+ SLI4_EQ_CNT_4096 = 3,
+};
+
+#define SLI4_EQ_CNT_SHIFT 26
+#define SLI4_EQ_CNT_VAL(type) (SLI4_EQ_CNT_##type << SLI4_EQ_CNT_SHIFT)
+
+#define SLI4_EQE_SIZE_4 0
+#define SLI4_EQE_SIZE_16 1
+
+/* Create a Mailbox Queue; accommodate v0 and v1 forms. */
+enum sli4_create_mq_flags {
+ /* DW6W1 */
+ SLI4_CREATE_MQEXT_RINGSIZE = 0xf,
+ SLI4_CREATE_MQEXT_CQID_SHIFT = 6,
+ SLI4_CREATE_MQEXT_CQIDV0_MASK = 0xffc0,
+ /* DW7 */
+ SLI4_CREATE_MQEXT_VAL = 1u << 31,
+ /* DW8 */
+ SLI4_CREATE_MQEXT_ACQV = 1u << 0,
+ SLI4_CREATE_MQEXT_ASYNC_CQIDV0 = 0x7fe,
+};
+
+struct sli4_rqst_cmn_create_mq_ext {
+ struct sli4_rqst_hdr hdr;
+ __le16 num_pages;
+ __le16 cq_id_v1;
+ __le32 async_event_bitmap;
+ __le16 async_cq_id_v1;
+ __le16 dw6w1_flags;
+ __le32 dw7_val;
+ __le32 dw8_flags;
+ __le32 rsvd36;
+ struct sli4_dmaaddr page_phys_addr[0];
+};
+
+struct sli4_rsp_cmn_create_mq_ext {
+ struct sli4_rsp_cmn_create_queue q_rsp;
+};
+
+enum sli4_mqe_size {
+ SLI4_MQE_SIZE_16 = 0x05,
+ SLI4_MQE_SIZE_32,
+ SLI4_MQE_SIZE_64,
+ SLI4_MQE_SIZE_128,
+};
+
+enum sli4_async_evt {
+ SLI4_ASYNC_EVT_LINK_STATE = 1 << 1,
+ SLI4_ASYNC_EVT_FIP = 1 << 2,
+ SLI4_ASYNC_EVT_GRP5 = 1 << 5,
+ SLI4_ASYNC_EVT_FC = 1 << 16,
+ SLI4_ASYNC_EVT_SLI_PORT = 1 << 17,
+};
+
+#define SLI4_ASYNC_EVT_FC_ALL \
+ (SLI4_ASYNC_EVT_LINK_STATE | \
+ SLI4_ASYNC_EVT_FIP | \
+ SLI4_ASYNC_EVT_GRP5 | \
+ SLI4_ASYNC_EVT_FC | \
+ SLI4_ASYNC_EVT_SLI_PORT)
+
+/* Create a Completion Queue. */
+struct sli4_rqst_cmn_create_cq_v0 {
+ struct sli4_rqst_hdr hdr;
+ __le16 num_pages;
+ __le16 rsvd18;
+ __le32 dw5_flags;
+ __le32 dw6_flags;
+ __le32 rsvd28;
+ __le32 rsvd32;
+ struct sli4_dmaaddr page_phys_addr[0];
+};
+
+enum sli4_create_rq_e {
+ SLI4_RQ_CREATE_DUA = 0x1,
+ SLI4_RQ_CREATE_BQU = 0x2,
+
+ SLI4_RQE_SIZE = 8,
+ SLI4_RQE_SIZE_8 = 0x2,
+ SLI4_RQE_SIZE_16 = 0x3,
+ SLI4_RQE_SIZE_32 = 0x4,
+ SLI4_RQE_SIZE_64 = 0x5,
+ SLI4_RQE_SIZE_128 = 0x6,
+
+ SLI4_RQ_PAGE_SIZE_4096 = 0x1,
+ SLI4_RQ_PAGE_SIZE_8192 = 0x2,
+ SLI4_RQ_PAGE_SIZE_16384 = 0x4,
+ SLI4_RQ_PAGE_SIZE_32768 = 0x8,
+ SLI4_RQ_PAGE_SIZE_64536 = 0x10,
+
+ SLI4_RQ_CREATE_V0_MAX_PAGES = 8,
+ SLI4_RQ_CREATE_V0_MIN_BUF_SIZE = 128,
+ SLI4_RQ_CREATE_V0_MAX_BUF_SIZE = 2048,
+};
+
+struct sli4_rqst_rq_create {
+ struct sli4_rqst_hdr hdr;
+ __le16 num_pages;
+ u8 dua_bqu_byte;
+ u8 ulp;
+ __le16 rsvd16;
+ u8 rqe_count_byte;
+ u8 rsvd19;
+ __le32 rsvd20;
+ __le16 buffer_size;
+ __le16 cq_id;
+ __le32 rsvd28;
+ struct sli4_dmaaddr page_phys_addr[SLI4_RQ_CREATE_V0_MAX_PAGES];
+};
+
+struct sli4_rsp_rq_create {
+ struct sli4_rsp_cmn_create_queue rsp;
+};
+
+enum sli4_create_rqv1_e {
+ SLI4_RQ_CREATE_V1_DNB = 0x80,
+ SLI4_RQ_CREATE_V1_MAX_PAGES = 8,
+ SLI4_RQ_CREATE_V1_MIN_BUF_SIZE = 64,
+ SLI4_RQ_CREATE_V1_MAX_BUF_SIZE = 2048,
+};
+
+struct sli4_rqst_rq_create_v1 {
+ struct sli4_rqst_hdr hdr;
+ __le16 num_pages;
+ u8 rsvd14;
+ u8 dim_dfd_dnb;
+ u8 page_size;
+ u8 rqe_size_byte;
+ __le16 rqe_count;
+ __le32 rsvd20;
+ __le16 rsvd24;
+ __le16 cq_id;
+ __le32 buffer_size;
+ struct sli4_dmaaddr page_phys_addr[SLI4_RQ_CREATE_V1_MAX_PAGES];
+};
+
+struct sli4_rsp_rq_create_v1 {
+ struct sli4_rsp_cmn_create_queue rsp;
+};
+
+#define SLI4_RQCREATEV2_DNB 0x80
+
+struct sli4_rqst_rq_create_v2 {
+ struct sli4_rqst_hdr hdr;
+ __le16 num_pages;
+ u8 rq_count;
+ u8 dim_dfd_dnb;
+ u8 page_size;
+ u8 rqe_size_byte;
+ __le16 rqe_count;
+ __le16 hdr_buffer_size;
+ __le16 payload_buffer_size;
+ __le16 base_cq_id;
+ __le16 rsvd26;
+ __le32 rsvd42;
+ struct sli4_dmaaddr page_phys_addr[0];
+};
+
+struct sli4_rsp_rq_create_v2 {
+ struct sli4_rsp_cmn_create_queue rsp;
+};
+
+#define SLI4_CQE_CODE_OFFSET 14
+
+enum sli4_cqe_code {
+ SLI4_CQE_CODE_WORK_REQUEST_COMPLETION = 0x01,
+ SLI4_CQE_CODE_RELEASE_WQE,
+ SLI4_CQE_CODE_RSVD,
+ SLI4_CQE_CODE_RQ_ASYNC,
+ SLI4_CQE_CODE_XRI_ABORTED,
+ SLI4_CQE_CODE_RQ_COALESCING,
+ SLI4_CQE_CODE_RQ_CONSUMPTION,
+ SLI4_CQE_CODE_MEASUREMENT_REPORTING,
+ SLI4_CQE_CODE_RQ_ASYNC_V1,
+ SLI4_CQE_CODE_RQ_COALESCING_V1,
+ SLI4_CQE_CODE_OPTIMIZED_WRITE_CMD,
+ SLI4_CQE_CODE_OPTIMIZED_WRITE_DATA,
+};
+
+#define SLI4_WQ_CREATE_MAX_PAGES 8
+
+struct sli4_rqst_wq_create {
+ struct sli4_rqst_hdr hdr;
+ __le16 num_pages;
+ __le16 cq_id;
+ u8 page_size;
+ u8 wqe_size_byte;
+ __le16 wqe_count;
+ __le32 rsvd;
+ struct sli4_dmaaddr page_phys_addr[SLI4_WQ_CREATE_MAX_PAGES];
+};
+
+struct sli4_rsp_wq_create {
+ struct sli4_rsp_cmn_create_queue rsp;
+};
+
+enum sli4_link_attention_flags {
+ SLI4_LNK_ATTN_TYPE_LINK_UP = 0x01,
+ SLI4_LNK_ATTN_TYPE_LINK_DOWN = 0x02,
+ SLI4_LNK_ATTN_TYPE_NO_HARD_ALPA = 0x03,
+
+ SLI4_LNK_ATTN_P2P = 0x01,
+ SLI4_LNK_ATTN_FC_AL = 0x02,
+ SLI4_LNK_ATTN_INTERNAL_LOOPBACK = 0x03,
+ SLI4_LNK_ATTN_SERDES_LOOPBACK = 0x04,
+};
+
+struct sli4_link_attention {
+ u8 link_number;
+ u8 attn_type;
+ u8 topology;
+ u8 port_speed;
+ u8 port_fault;
+ u8 shared_link_status;
+ __le16 logical_link_speed;
+ __le32 event_tag;
+ u8 rsvd12;
+ u8 event_code;
+ u8 event_type;
+ u8 flags;
+};
+
+enum sli4_link_event_type {
+ SLI4_EVENT_LINK_ATTENTION = 0x01,
+ SLI4_EVENT_SHARED_LINK_ATTENTION = 0x02,
+};
+
+enum sli4_wcqe_flags {
+ SLI4_WCQE_XB = 0x10,
+ SLI4_WCQE_QX = 0x80,
+};
+
+struct sli4_fc_wcqe {
+ u8 hw_status;
+ u8 status;
+ __le16 request_tag;
+ __le32 wqe_specific_1;
+ __le32 wqe_specific_2;
+ u8 rsvd12;
+ u8 qx_byte;
+ u8 code;
+ u8 flags;
+};
+
+/* FC WQ consumed CQ queue entry */
+struct sli4_fc_wqec {
+ __le32 rsvd0;
+ __le32 rsvd1;
+ __le16 wqe_index;
+ __le16 wq_id;
+ __le16 rsvd12;
+ u8 code;
+ u8 vld_byte;
+};
+
+/* FC Completion Status Codes. */
+enum sli4_wcqe_status {
+ SLI4_FC_WCQE_STATUS_SUCCESS,
+ SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE,
+ SLI4_FC_WCQE_STATUS_REMOTE_STOP,
+ SLI4_FC_WCQE_STATUS_LOCAL_REJECT,
+ SLI4_FC_WCQE_STATUS_NPORT_RJT,
+ SLI4_FC_WCQE_STATUS_FABRIC_RJT,
+ SLI4_FC_WCQE_STATUS_NPORT_BSY,
+ SLI4_FC_WCQE_STATUS_FABRIC_BSY,
+ SLI4_FC_WCQE_STATUS_RSVD,
+ SLI4_FC_WCQE_STATUS_LS_RJT,
+ SLI4_FC_WCQE_STATUS_RX_BUF_OVERRUN,
+ SLI4_FC_WCQE_STATUS_CMD_REJECT,
+ SLI4_FC_WCQE_STATUS_FCP_TGT_LENCHECK,
+ SLI4_FC_WCQE_STATUS_RSVD1,
+ SLI4_FC_WCQE_STATUS_ELS_CMPLT_NO_AUTOREG,
+ SLI4_FC_WCQE_STATUS_RSVD2,
+ SLI4_FC_WCQE_STATUS_RQ_SUCCESS,
+ SLI4_FC_WCQE_STATUS_RQ_BUF_LEN_EXCEEDED,
+ SLI4_FC_WCQE_STATUS_RQ_INSUFF_BUF_NEEDED,
+ SLI4_FC_WCQE_STATUS_RQ_INSUFF_FRM_DISC,
+ SLI4_FC_WCQE_STATUS_RQ_DMA_FAILURE,
+ SLI4_FC_WCQE_STATUS_FCP_RSP_TRUNCATE,
+ SLI4_FC_WCQE_STATUS_DI_ERROR,
+ SLI4_FC_WCQE_STATUS_BA_RJT,
+ SLI4_FC_WCQE_STATUS_RQ_INSUFF_XRI_NEEDED,
+ SLI4_FC_WCQE_STATUS_RQ_INSUFF_XRI_DISC,
+ SLI4_FC_WCQE_STATUS_RX_ERROR_DETECT,
+ SLI4_FC_WCQE_STATUS_RX_ABORT_REQUEST,
+
+ /* driver generated status codes */
+ SLI4_FC_WCQE_STATUS_DISPATCH_ERROR = 0xfd,
+ SLI4_FC_WCQE_STATUS_SHUTDOWN = 0xfe,
+ SLI4_FC_WCQE_STATUS_TARGET_WQE_TIMEOUT = 0xff,
+};
+
+/* DI_ERROR Extended Status */
+enum sli4_fc_di_error_status {
+ SLI4_FC_DI_ERROR_GE = 1 << 0,
+ SLI4_FC_DI_ERROR_AE = 1 << 1,
+ SLI4_FC_DI_ERROR_RE = 1 << 2,
+ SLI4_FC_DI_ERROR_TDPV = 1 << 3,
+ SLI4_FC_DI_ERROR_UDB = 1 << 4,
+ SLI4_FC_DI_ERROR_EDIR = 1 << 5,
+};
+
+/* WQE DIF field contents */
+enum sli4_dif_fields {
+ SLI4_DIF_DISABLED,
+ SLI4_DIF_PASS_THROUGH,
+ SLI4_DIF_STRIP,
+ SLI4_DIF_INSERT,
+};
+
+/* Work Queue Entry (WQE) types */
+enum sli4_wqe_types {
+ SLI4_WQE_ABORT = 0x0f,
+ SLI4_WQE_ELS_REQUEST64 = 0x8a,
+ SLI4_WQE_FCP_IBIDIR64 = 0xac,
+ SLI4_WQE_FCP_IREAD64 = 0x9a,
+ SLI4_WQE_FCP_IWRITE64 = 0x98,
+ SLI4_WQE_FCP_ICMND64 = 0x9c,
+ SLI4_WQE_FCP_TRECEIVE64 = 0xa1,
+ SLI4_WQE_FCP_CONT_TRECEIVE64 = 0xe5,
+ SLI4_WQE_FCP_TRSP64 = 0xa3,
+ SLI4_WQE_FCP_TSEND64 = 0x9f,
+ SLI4_WQE_GEN_REQUEST64 = 0xc2,
+ SLI4_WQE_SEND_FRAME = 0xe1,
+ SLI4_WQE_XMIT_BCAST64 = 0x84,
+ SLI4_WQE_XMIT_BLS_RSP = 0x97,
+ SLI4_WQE_ELS_RSP64 = 0x95,
+ SLI4_WQE_XMIT_SEQUENCE64 = 0x82,
+ SLI4_WQE_REQUEUE_XRI = 0x93,
+};
+
+/* WQE command types */
+enum sli4_wqe_cmds {
+ SLI4_CMD_FCP_IREAD64_WQE = 0x00,
+ SLI4_CMD_FCP_ICMND64_WQE = 0x00,
+ SLI4_CMD_FCP_IWRITE64_WQE = 0x01,
+ SLI4_CMD_FCP_TRECEIVE64_WQE = 0x02,
+ SLI4_CMD_FCP_TRSP64_WQE = 0x03,
+ SLI4_CMD_FCP_TSEND64_WQE = 0x07,
+ SLI4_CMD_GEN_REQUEST64_WQE = 0x08,
+ SLI4_CMD_XMIT_BCAST64_WQE = 0x08,
+ SLI4_CMD_XMIT_BLS_RSP64_WQE = 0x08,
+ SLI4_CMD_ABORT_WQE = 0x08,
+ SLI4_CMD_XMIT_SEQUENCE64_WQE = 0x08,
+ SLI4_CMD_REQUEUE_XRI_WQE = 0x0a,
+ SLI4_CMD_SEND_FRAME_WQE = 0x0a,
+};
+
+#define SLI4_WQE_SIZE 0x05
+#define SLI4_WQE_EXT_SIZE 0x06
+
+#define SLI4_WQE_BYTES (16 * sizeof(u32))
+#define SLI4_WQE_EXT_BYTES (32 * sizeof(u32))
+
+/* Mask for ccp (CS_CTL) */
+#define SLI4_MASK_CCP 0xfe
+
+/* Generic WQE */
+enum sli4_gen_wqe_flags {
+ SLI4_GEN_WQE_EBDECNT = 0xf,
+ SLI4_GEN_WQE_LEN_LOC = 0x3 << 7,
+ SLI4_GEN_WQE_QOSD = 1 << 9,
+ SLI4_GEN_WQE_XBL = 1 << 11,
+ SLI4_GEN_WQE_HLM = 1 << 12,
+ SLI4_GEN_WQE_IOD = 1 << 13,
+ SLI4_GEN_WQE_DBDE = 1 << 14,
+ SLI4_GEN_WQE_WQES = 1 << 15,
+
+ SLI4_GEN_WQE_PRI = 0x7,
+ SLI4_GEN_WQE_PV = 1 << 3,
+ SLI4_GEN_WQE_EAT = 1 << 4,
+ SLI4_GEN_WQE_XC = 1 << 5,
+ SLI4_GEN_WQE_CCPE = 1 << 7,
+
+ SLI4_GEN_WQE_CMDTYPE = 0xf,
+ SLI4_GEN_WQE_WQEC = 1 << 7,
+};
+
+struct sli4_generic_wqe {
+ __le32 cmd_spec0_5[6];
+ __le16 xri_tag;
+ __le16 context_tag;
+ u8 ct_byte;
+ u8 command;
+ u8 class_byte;
+ u8 timer;
+ __le32 abort_tag;
+ __le16 request_tag;
+ __le16 rsvd34;
+ __le16 dw10w0_flags;
+ u8 eat_xc_ccpe;
+ u8 ccp;
+ u8 cmdtype_wqec_byte;
+ u8 rsvd41;
+ __le16 cq_id;
+};
+
+/* WQE used to abort exchanges. */
+enum sli4_abort_wqe_flags {
+ SLI4_ABRT_WQE_IR = 0x02,
+
+ SLI4_ABRT_WQE_EBDECNT = 0xf,
+ SLI4_ABRT_WQE_LEN_LOC = 0x3 << 7,
+ SLI4_ABRT_WQE_QOSD = 1 << 9,
+ SLI4_ABRT_WQE_XBL = 1 << 11,
+ SLI4_ABRT_WQE_IOD = 1 << 13,
+ SLI4_ABRT_WQE_DBDE = 1 << 14,
+ SLI4_ABRT_WQE_WQES = 1 << 15,
+
+ SLI4_ABRT_WQE_PRI = 0x7,
+ SLI4_ABRT_WQE_PV = 1 << 3,
+ SLI4_ABRT_WQE_EAT = 1 << 4,
+ SLI4_ABRT_WQE_XC = 1 << 5,
+ SLI4_ABRT_WQE_CCPE = 1 << 7,
+
+ SLI4_ABRT_WQE_CMDTYPE = 0xf,
+ SLI4_ABRT_WQE_WQEC = 1 << 7,
+};
+
+struct sli4_abort_wqe {
+ __le32 rsvd0;
+ __le32 rsvd4;
+ __le32 ext_t_tag;
+ u8 ia_ir_byte;
+ u8 criteria;
+ __le16 rsvd10;
+ __le32 ext_t_mask;
+ __le32 t_mask;
+ __le16 xri_tag;
+ __le16 context_tag;
+ u8 ct_byte;
+ u8 command;
+ u8 class_byte;
+ u8 timer;
+ __le32 t_tag;
+ __le16 request_tag;
+ __le16 rsvd34;
+ __le16 dw10w0_flags;
+ u8 eat_xc_ccpe;
+ u8 ccp;
+ u8 cmdtype_wqec_byte;
+ u8 rsvd41;
+ __le16 cq_id;
+};
+
+enum sli4_abort_criteria {
+ SLI4_ABORT_CRITERIA_XRI_TAG = 0x01,
+ SLI4_ABORT_CRITERIA_ABORT_TAG,
+ SLI4_ABORT_CRITERIA_REQUEST_TAG,
+ SLI4_ABORT_CRITERIA_EXT_ABORT_TAG,
+};
+
+enum sli4_abort_type {
+ SLI4_ABORT_XRI,
+ SLI4_ABORT_ABORT_ID,
+ SLI4_ABORT_REQUEST_ID,
+ SLI4_ABORT_MAX, /* must be last */
+};
+
+/* WQE used to create an ELS request. */
+enum sli4_els_req_wqe_flags {
+ SLI4_REQ_WQE_QOSD = 0x2,
+ SLI4_REQ_WQE_DBDE = 0x40,
+ SLI4_REQ_WQE_XBL = 0x8,
+ SLI4_REQ_WQE_XC = 0x20,
+ SLI4_REQ_WQE_IOD = 0x20,
+ SLI4_REQ_WQE_HLM = 0x10,
+ SLI4_REQ_WQE_CCPE = 0x80,
+ SLI4_REQ_WQE_EAT = 0x10,
+ SLI4_REQ_WQE_WQES = 0x80,
+ SLI4_REQ_WQE_PU_SHFT = 4,
+ SLI4_REQ_WQE_CT_SHFT = 2,
+ SLI4_REQ_WQE_CT = 0xc,
+ SLI4_REQ_WQE_ELSID_SHFT = 4,
+ SLI4_REQ_WQE_SP_SHFT = 24,
+ SLI4_REQ_WQE_LEN_LOC_BIT1 = 0x80,
+ SLI4_REQ_WQE_LEN_LOC_BIT2 = 0x1,
+};
+
+struct sli4_els_request64_wqe {
+ struct sli4_bde els_request_payload;
+ __le32 els_request_payload_length;
+ __le32 sid_sp_dword;
+ __le32 remote_id_dword;
+ __le16 xri_tag;
+ __le16 context_tag;
+ u8 ct_byte;
+ u8 command;
+ u8 class_byte;
+ u8 timer;
+ __le32 abort_tag;
+ __le16 request_tag;
+ __le16 temporary_rpi;
+ u8 len_loc1_byte;
+ u8 qosd_xbl_hlm_iod_dbde_wqes;
+ u8 eat_xc_ccpe;
+ u8 ccp;
+ u8 cmdtype_elsid_byte;
+ u8 rsvd41;
+ __le16 cq_id;
+ struct sli4_bde els_response_payload_bde;
+ __le32 max_response_payload_length;
+};
+
+/* WQE used to create an FCP initiator no data command. */
+enum sli4_icmd_wqe_flags {
+ SLI4_ICMD_WQE_DBDE = 0x40,
+ SLI4_ICMD_WQE_XBL = 0x8,
+ SLI4_ICMD_WQE_XC = 0x20,
+ SLI4_ICMD_WQE_IOD = 0x20,
+ SLI4_ICMD_WQE_HLM = 0x10,
+ SLI4_ICMD_WQE_CCPE = 0x80,
+ SLI4_ICMD_WQE_EAT = 0x10,
+ SLI4_ICMD_WQE_APPID = 0x10,
+ SLI4_ICMD_WQE_WQES = 0x80,
+ SLI4_ICMD_WQE_PU_SHFT = 4,
+ SLI4_ICMD_WQE_CT_SHFT = 2,
+ SLI4_ICMD_WQE_BS_SHFT = 4,
+ SLI4_ICMD_WQE_LEN_LOC_BIT1 = 0x80,
+ SLI4_ICMD_WQE_LEN_LOC_BIT2 = 0x1,
+};
+
+struct sli4_fcp_icmnd64_wqe {
+ struct sli4_bde bde;
+ __le16 payload_offset_length;
+ __le16 fcp_cmd_buffer_length;
+ __le32 rsvd12;
+ __le32 remote_n_port_id_dword;
+ __le16 xri_tag;
+ __le16 context_tag;
+ u8 dif_ct_bs_byte;
+ u8 command;
+ u8 class_pu_byte;
+ u8 timer;
+ __le32 abort_tag;
+ __le16 request_tag;
+ __le16 rsvd34;
+ u8 len_loc1_byte;
+ u8 qosd_xbl_hlm_iod_dbde_wqes;
+ u8 eat_xc_ccpe;
+ u8 ccp;
+ u8 cmd_type_byte;
+ u8 rsvd41;
+ __le16 cq_id;
+ __le32 rsvd44;
+ __le32 rsvd48;
+ __le32 rsvd52;
+ __le32 rsvd56;
+};
+
+/* WQE used to create an FCP initiator read. */
+enum sli4_ir_wqe_flags {
+ SLI4_IR_WQE_DBDE = 0x40,
+ SLI4_IR_WQE_XBL = 0x8,
+ SLI4_IR_WQE_XC = 0x20,
+ SLI4_IR_WQE_IOD = 0x20,
+ SLI4_IR_WQE_HLM = 0x10,
+ SLI4_IR_WQE_CCPE = 0x80,
+ SLI4_IR_WQE_EAT = 0x10,
+ SLI4_IR_WQE_APPID = 0x10,
+ SLI4_IR_WQE_WQES = 0x80,
+ SLI4_IR_WQE_PU_SHFT = 4,
+ SLI4_IR_WQE_CT_SHFT = 2,
+ SLI4_IR_WQE_BS_SHFT = 4,
+ SLI4_IR_WQE_LEN_LOC_BIT1 = 0x80,
+ SLI4_IR_WQE_LEN_LOC_BIT2 = 0x1,
+};
+
+struct sli4_fcp_iread64_wqe {
+ struct sli4_bde bde;
+ __le16 payload_offset_length;
+ __le16 fcp_cmd_buffer_length;
+
+ __le32 total_transfer_length;
+
+ __le32 remote_n_port_id_dword;
+
+ __le16 xri_tag;
+ __le16 context_tag;
+
+ u8 dif_ct_bs_byte;
+ u8 command;
+ u8 class_pu_byte;
+ u8 timer;
+
+ __le32 abort_tag;
+
+ __le16 request_tag;
+ __le16 rsvd34;
+
+ u8 len_loc1_byte;
+ u8 qosd_xbl_hlm_iod_dbde_wqes;
+ u8 eat_xc_ccpe;
+ u8 ccp;
+
+ u8 cmd_type_byte;
+ u8 rsvd41;
+ __le16 cq_id;
+
+ __le32 rsvd44;
+ struct sli4_bde first_data_bde;
+};
+
+/* WQE used to create an FCP initiator write. */
+enum sli4_iwr_wqe_flags {
+ SLI4_IWR_WQE_DBDE = 0x40,
+ SLI4_IWR_WQE_XBL = 0x8,
+ SLI4_IWR_WQE_XC = 0x20,
+ SLI4_IWR_WQE_IOD = 0x20,
+ SLI4_IWR_WQE_HLM = 0x10,
+ SLI4_IWR_WQE_DNRX = 0x10,
+ SLI4_IWR_WQE_CCPE = 0x80,
+ SLI4_IWR_WQE_EAT = 0x10,
+ SLI4_IWR_WQE_APPID = 0x10,
+ SLI4_IWR_WQE_WQES = 0x80,
+ SLI4_IWR_WQE_PU_SHFT = 4,
+ SLI4_IWR_WQE_CT_SHFT = 2,
+ SLI4_IWR_WQE_BS_SHFT = 4,
+ SLI4_IWR_WQE_LEN_LOC_BIT1 = 0x80,
+ SLI4_IWR_WQE_LEN_LOC_BIT2 = 0x1,
+};
+
+struct sli4_fcp_iwrite64_wqe {
+ struct sli4_bde bde;
+ __le16 payload_offset_length;
+ __le16 fcp_cmd_buffer_length;
+ __le16 total_transfer_length;
+ __le16 initial_transfer_length;
+ __le16 xri_tag;
+ __le16 context_tag;
+ u8 dif_ct_bs_byte;
+ u8 command;
+ u8 class_pu_byte;
+ u8 timer;
+ __le32 abort_tag;
+ __le16 request_tag;
+ __le16 rsvd34;
+ u8 len_loc1_byte;
+ u8 qosd_xbl_hlm_iod_dbde_wqes;
+ u8 eat_xc_ccpe;
+ u8 ccp;
+ u8 cmd_type_byte;
+ u8 rsvd41;
+ __le16 cq_id;
+ __le32 remote_n_port_id_dword;
+ struct sli4_bde first_data_bde;
+};
+
+struct sli4_fcp_128byte_wqe {
+ u32 dw[32];
+};
+
+/* WQE used to create an FCP target receive */
+enum sli4_trcv_wqe_flags {
+ SLI4_TRCV_WQE_DBDE = 0x40,
+ SLI4_TRCV_WQE_XBL = 0x8,
+ SLI4_TRCV_WQE_AR = 0x8,
+ SLI4_TRCV_WQE_XC = 0x20,
+ SLI4_TRCV_WQE_IOD = 0x20,
+ SLI4_TRCV_WQE_HLM = 0x10,
+ SLI4_TRCV_WQE_DNRX = 0x10,
+ SLI4_TRCV_WQE_CCPE = 0x80,
+ SLI4_TRCV_WQE_EAT = 0x10,
+ SLI4_TRCV_WQE_APPID = 0x10,
+ SLI4_TRCV_WQE_WQES = 0x80,
+ SLI4_TRCV_WQE_PU_SHFT = 4,
+ SLI4_TRCV_WQE_CT_SHFT = 2,
+ SLI4_TRCV_WQE_BS_SHFT = 4,
+ SLI4_TRCV_WQE_LEN_LOC_BIT2 = 0x1,
+};
+
+struct sli4_fcp_treceive64_wqe {
+ struct sli4_bde bde;
+ __le32 payload_offset_length;
+ __le32 relative_offset;
+ union {
+ __le16 sec_xri_tag;
+ __le16 rsvd;
+ __le32 dword;
+ } dword5;
+ __le16 xri_tag;
+ __le16 context_tag;
+ u8 dif_ct_bs_byte;
+ u8 command;
+ u8 class_ar_pu_byte;
+ u8 timer;
+ __le32 abort_tag;
+ __le16 request_tag;
+ __le16 remote_xid;
+ u8 lloc1_appid;
+ u8 qosd_xbl_hlm_iod_dbde_wqes;
+ u8 eat_xc_ccpe;
+ u8 ccp;
+ u8 cmd_type_byte;
+ u8 rsvd41;
+ __le16 cq_id;
+ __le32 fcp_data_receive_length;
+ struct sli4_bde first_data_bde;
+};
+
+/* WQE used to create an FCP target response */
+enum sli4_trsp_wqe_flags {
+ SLI4_TRSP_WQE_AG = 0x8,
+ SLI4_TRSP_WQE_DBDE = 0x40,
+ SLI4_TRSP_WQE_XBL = 0x8,
+ SLI4_TRSP_WQE_XC = 0x20,
+ SLI4_TRSP_WQE_HLM = 0x10,
+ SLI4_TRSP_WQE_DNRX = 0x10,
+ SLI4_TRSP_WQE_CCPE = 0x80,
+ SLI4_TRSP_WQE_EAT = 0x10,
+ SLI4_TRSP_WQE_APPID = 0x10,
+ SLI4_TRSP_WQE_WQES = 0x80,
+};
+
+struct sli4_fcp_trsp64_wqe {
+ struct sli4_bde bde;
+ __le32 fcp_response_length;
+ __le32 rsvd12;
+ __le32 dword5;
+ __le16 xri_tag;
+ __le16 rpi;
+ u8 ct_dnrx_byte;
+ u8 command;
+ u8 class_ag_byte;
+ u8 timer;
+ __le32 abort_tag;
+ __le16 request_tag;
+ __le16 remote_xid;
+ u8 lloc1_appid;
+ u8 qosd_xbl_hlm_dbde_wqes;
+ u8 eat_xc_ccpe;
+ u8 ccp;
+ u8 cmd_type_byte;
+ u8 rsvd41;
+ __le16 cq_id;
+ __le32 rsvd44;
+ __le32 rsvd48;
+ __le32 rsvd52;
+ __le32 rsvd56;
+};
+
+/* WQE used to create an FCP target send (DATA IN). */
+enum sli4_tsend_wqe_flags {
+ SLI4_TSEND_WQE_XBL = 0x8,
+ SLI4_TSEND_WQE_DBDE = 0x40,
+ SLI4_TSEND_WQE_IOD = 0x20,
+ SLI4_TSEND_WQE_QOSD = 0x2,
+ SLI4_TSEND_WQE_HLM = 0x10,
+ SLI4_TSEND_WQE_PU_SHFT = 4,
+ SLI4_TSEND_WQE_AR = 0x8,
+ SLI4_TSEND_CT_SHFT = 2,
+ SLI4_TSEND_BS_SHFT = 4,
+ SLI4_TSEND_LEN_LOC_BIT2 = 0x1,
+ SLI4_TSEND_CCPE = 0x80,
+ SLI4_TSEND_APPID_VALID = 0x20,
+ SLI4_TSEND_WQES = 0x80,
+ SLI4_TSEND_XC = 0x20,
+ SLI4_TSEND_EAT = 0x10,
+};
+
+struct sli4_fcp_tsend64_wqe {
+ struct sli4_bde bde;
+ __le32 payload_offset_length;
+ __le32 relative_offset;
+ __le32 dword5;
+ __le16 xri_tag;
+ __le16 rpi;
+ u8 ct_byte;
+ u8 command;
+ u8 class_pu_ar_byte;
+ u8 timer;
+ __le32 abort_tag;
+ __le16 request_tag;
+ __le16 remote_xid;
+ u8 dw10byte0;
+ u8 ll_qd_xbl_hlm_iod_dbde;
+ u8 dw10byte2;
+ u8 ccp;
+ u8 cmd_type_byte;
+ u8 rsvd45;
+ __le16 cq_id;
+ __le32 fcp_data_transmit_length;
+ struct sli4_bde first_data_bde;
+};
+
+/* WQE used to create a general request. */
+enum sli4_gen_req_wqe_flags {
+ SLI4_GEN_REQ64_WQE_XBL = 0x8,
+ SLI4_GEN_REQ64_WQE_DBDE = 0x40,
+ SLI4_GEN_REQ64_WQE_IOD = 0x20,
+ SLI4_GEN_REQ64_WQE_QOSD = 0x2,
+ SLI4_GEN_REQ64_WQE_HLM = 0x10,
+ SLI4_GEN_REQ64_CT_SHFT = 2,
+};
+
+struct sli4_gen_request64_wqe {
+ struct sli4_bde bde;
+ __le32 request_payload_length;
+ __le32 relative_offset;
+ u8 rsvd17;
+ u8 df_ctl;
+ u8 type;
+ u8 r_ctl;
+ __le16 xri_tag;
+ __le16 context_tag;
+ u8 ct_byte;
+ u8 command;
+ u8 class_byte;
+ u8 timer;
+ __le32 abort_tag;
+ __le16 request_tag;
+ __le16 rsvd34;
+ u8 dw10flags0;
+ u8 dw10flags1;
+ u8 dw10flags2;
+ u8 ccp;
+ u8 cmd_type_byte;
+ u8 rsvd41;
+ __le16 cq_id;
+ __le32 remote_n_port_id_dword;
+ __le32 rsvd48;
+ __le32 rsvd52;
+ __le32 max_response_payload_length;
+};
+
+/* WQE used to create a send frame request */
+enum sli4_sf_wqe_flags {
+ SLI4_SF_WQE_DBDE = 0x40,
+ SLI4_SF_PU = 0x30,
+ SLI4_SF_CT = 0xc,
+ SLI4_SF_QOSD = 0x2,
+ SLI4_SF_LEN_LOC_BIT1 = 0x80,
+ SLI4_SF_LEN_LOC_BIT2 = 0x1,
+ SLI4_SF_XC = 0x20,
+ SLI4_SF_XBL = 0x8,
+};
+
+struct sli4_send_frame_wqe {
+ struct sli4_bde bde;
+ __le32 frame_length;
+ __le32 fc_header_0_1[2];
+ __le16 xri_tag;
+ __le16 context_tag;
+ u8 ct_byte;
+ u8 command;
+ u8 dw7flags0;
+ u8 timer;
+ __le32 abort_tag;
+ __le16 request_tag;
+ u8 eof;
+ u8 sof;
+ u8 dw10flags0;
+ u8 dw10flags1;
+ u8 dw10flags2;
+ u8 ccp;
+ u8 cmd_type_byte;
+ u8 rsvd41;
+ __le16 cq_id;
+ __le32 fc_header_2_5[4];
+};
+
+/* WQE used to create a transmit sequence */
+enum sli4_seq_wqe_flags {
+ SLI4_SEQ_WQE_DBDE = 0x4000,
+ SLI4_SEQ_WQE_XBL = 0x800,
+ SLI4_SEQ_WQE_SI = 0x4,
+ SLI4_SEQ_WQE_FT = 0x8,
+ SLI4_SEQ_WQE_XO = 0x40,
+ SLI4_SEQ_WQE_LS = 0x80,
+ SLI4_SEQ_WQE_DIF = 0x3,
+ SLI4_SEQ_WQE_BS = 0x70,
+ SLI4_SEQ_WQE_PU = 0x30,
+ SLI4_SEQ_WQE_HLM = 0x1000,
+ SLI4_SEQ_WQE_IOD_SHIFT = 13,
+ SLI4_SEQ_WQE_CT_SHIFT = 2,
+ SLI4_SEQ_WQE_LEN_LOC_SHIFT = 7,
+};
+
+struct sli4_xmit_sequence64_wqe {
+ struct sli4_bde bde;
+ __le32 remote_n_port_id_dword;
+ __le32 relative_offset;
+ u8 dw5flags0;
+ u8 df_ctl;
+ u8 type;
+ u8 r_ctl;
+ __le16 xri_tag;
+ __le16 context_tag;
+ u8 dw7flags0;
+ u8 command;
+ u8 dw7flags1;
+ u8 timer;
+ __le32 abort_tag;
+ __le16 request_tag;
+ __le16 remote_xid;
+ __le16 dw10w0;
+ u8 dw10flags0;
+ u8 ccp;
+ u8 cmd_type_wqec_byte;
+ u8 rsvd45;
+ __le16 cq_id;
+ __le32 sequence_payload_len;
+ __le32 rsvd48;
+ __le32 rsvd52;
+ __le32 rsvd56;
+};
+
+/*
+ * WQE used unblock the specified XRI and to release
+ * it to the SLI Port's free pool.
+ */
+enum sli4_requeue_wqe_flags {
+ SLI4_REQU_XRI_WQE_XC = 0x20,
+ SLI4_REQU_XRI_WQE_QOSD = 0x2,
+};
+
+struct sli4_requeue_xri_wqe {
+ __le32 rsvd0;
+ __le32 rsvd4;
+ __le32 rsvd8;
+ __le32 rsvd12;
+ __le32 rsvd16;
+ __le32 rsvd20;
+ __le16 xri_tag;
+ __le16 context_tag;
+ u8 ct_byte;
+ u8 command;
+ u8 class_byte;
+ u8 timer;
+ __le32 rsvd32;
+ __le16 request_tag;
+ __le16 rsvd34;
+ __le16 flags0;
+ __le16 flags1;
+ __le16 flags2;
+ u8 ccp;
+ u8 cmd_type_wqec_byte;
+ u8 rsvd42;
+ __le16 cq_id;
+ __le32 rsvd44;
+ __le32 rsvd48;
+ __le32 rsvd52;
+ __le32 rsvd56;
+};
+
+/* WQE used to create a BLS response */
+enum sli4_bls_rsp_wqe_flags {
+ SLI4_BLS_RSP_RID = 0xffffff,
+ SLI4_BLS_RSP_WQE_AR = 0x40000000,
+ SLI4_BLS_RSP_WQE_CT_SHFT = 2,
+ SLI4_BLS_RSP_WQE_QOSD = 0x2,
+ SLI4_BLS_RSP_WQE_HLM = 0x10,
+};
+
+struct sli4_xmit_bls_rsp_wqe {
+ __le32 payload_word0;
+ __le16 rx_id;
+ __le16 ox_id;
+ __le16 high_seq_cnt;
+ __le16 low_seq_cnt;
+ __le32 rsvd12;
+ __le32 local_n_port_id_dword;
+ __le32 remote_id_dword;
+ __le16 xri_tag;
+ __le16 context_tag;
+ u8 dw8flags0;
+ u8 command;
+ u8 dw8flags1;
+ u8 timer;
+ __le32 abort_tag;
+ __le16 request_tag;
+ __le16 rsvd38;
+ u8 dw11flags0;
+ u8 dw11flags1;
+ u8 dw11flags2;
+ u8 ccp;
+ u8 dw12flags0;
+ u8 rsvd45;
+ __le16 cq_id;
+ __le16 temporary_rpi;
+ u8 rsvd50;
+ u8 rsvd51;
+ __le32 rsvd52;
+ __le32 rsvd56;
+ __le32 rsvd60;
+};
+
+enum sli_bls_type {
+ SLI4_SLI_BLS_ACC,
+ SLI4_SLI_BLS_RJT,
+ SLI4_SLI_BLS_MAX
+};
+
+struct sli_bls_payload {
+ enum sli_bls_type type;
+ __le16 ox_id;
+ __le16 rx_id;
+ union {
+ struct {
+ u8 seq_id_validity;
+ u8 seq_id_last;
+ u8 rsvd2;
+ u8 rsvd3;
+ u16 ox_id;
+ u16 rx_id;
+ __le16 low_seq_cnt;
+ __le16 high_seq_cnt;
+ } acc;
+ struct {
+ u8 vendor_unique;
+ u8 reason_explanation;
+ u8 reason_code;
+ u8 rsvd3;
+ } rjt;
+ } u;
+};
+
+/* WQE used to create an ELS response */
+
+enum sli4_els_rsp_flags {
+ SLI4_ELS_SID = 0xffffff,
+ SLI4_ELS_RID = 0xffffff,
+ SLI4_ELS_DBDE = 0x40,
+ SLI4_ELS_XBL = 0x8,
+ SLI4_ELS_IOD = 0x20,
+ SLI4_ELS_QOSD = 0x2,
+ SLI4_ELS_XC = 0x20,
+ SLI4_ELS_CT_OFFSET = 0X2,
+ SLI4_ELS_SP = 0X1000000,
+ SLI4_ELS_HLM = 0X10,
+};
+
+struct sli4_xmit_els_rsp64_wqe {
+ struct sli4_bde els_response_payload;
+ __le32 els_response_payload_length;
+ __le32 sid_dw;
+ __le32 rid_dw;
+ __le16 xri_tag;
+ __le16 context_tag;
+ u8 ct_byte;
+ u8 command;
+ u8 class_byte;
+ u8 timer;
+ __le32 abort_tag;
+ __le16 request_tag;
+ __le16 ox_id;
+ u8 flags1;
+ u8 flags2;
+ u8 flags3;
+ u8 flags4;
+ u8 cmd_type_wqec;
+ u8 rsvd34;
+ __le16 cq_id;
+ __le16 temporary_rpi;
+ __le16 rsvd38;
+ u32 rsvd40;
+ u32 rsvd44;
+ u32 rsvd48;
+};
+
+/* Local Reject Reason Codes */
+enum sli4_fc_local_rej_codes {
+ SLI4_FC_LOCAL_REJECT_UNKNOWN,
+ SLI4_FC_LOCAL_REJECT_MISSING_CONTINUE,
+ SLI4_FC_LOCAL_REJECT_SEQUENCE_TIMEOUT,
+ SLI4_FC_LOCAL_REJECT_INTERNAL_ERROR,
+ SLI4_FC_LOCAL_REJECT_INVALID_RPI,
+ SLI4_FC_LOCAL_REJECT_NO_XRI,
+ SLI4_FC_LOCAL_REJECT_ILLEGAL_COMMAND,
+ SLI4_FC_LOCAL_REJECT_XCHG_DROPPED,
+ SLI4_FC_LOCAL_REJECT_ILLEGAL_FIELD,
+ SLI4_FC_LOCAL_REJECT_RPI_SUSPENDED,
+ SLI4_FC_LOCAL_REJECT_RSVD,
+ SLI4_FC_LOCAL_REJECT_RSVD1,
+ SLI4_FC_LOCAL_REJECT_NO_ABORT_MATCH,
+ SLI4_FC_LOCAL_REJECT_TX_DMA_FAILED,
+ SLI4_FC_LOCAL_REJECT_RX_DMA_FAILED,
+ SLI4_FC_LOCAL_REJECT_ILLEGAL_FRAME,
+ SLI4_FC_LOCAL_REJECT_RSVD2,
+ SLI4_FC_LOCAL_REJECT_NO_RESOURCES, //0x11
+ SLI4_FC_LOCAL_REJECT_FCP_CONF_FAILURE,
+ SLI4_FC_LOCAL_REJECT_ILLEGAL_LENGTH,
+ SLI4_FC_LOCAL_REJECT_UNSUPPORTED_FEATURE,
+ SLI4_FC_LOCAL_REJECT_ABORT_IN_PROGRESS,
+ SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED,
+ SLI4_FC_LOCAL_REJECT_RCV_BUFFER_TIMEOUT,
+ SLI4_FC_LOCAL_REJECT_LOOP_OPEN_FAILURE,
+ SLI4_FC_LOCAL_REJECT_RSVD3,
+ SLI4_FC_LOCAL_REJECT_LINK_DOWN,
+ SLI4_FC_LOCAL_REJECT_CORRUPTED_DATA,
+ SLI4_FC_LOCAL_REJECT_CORRUPTED_RPI,
+ SLI4_FC_LOCAL_REJECT_OUTOFORDER_DATA,
+ SLI4_FC_LOCAL_REJECT_OUTOFORDER_ACK,
+ SLI4_FC_LOCAL_REJECT_DUP_FRAME,
+ SLI4_FC_LOCAL_REJECT_LINK_CONTROL_FRAME, //0x20
+ SLI4_FC_LOCAL_REJECT_BAD_HOST_ADDRESS,
+ SLI4_FC_LOCAL_REJECT_RSVD4,
+ SLI4_FC_LOCAL_REJECT_MISSING_HDR_BUFFER,
+ SLI4_FC_LOCAL_REJECT_MSEQ_CHAIN_CORRUPTED,
+ SLI4_FC_LOCAL_REJECT_ABORTMULT_REQUESTED,
+ SLI4_FC_LOCAL_REJECT_BUFFER_SHORTAGE = 0x28,
+ SLI4_FC_LOCAL_REJECT_RCV_XRIBUF_WAITING,
+ SLI4_FC_LOCAL_REJECT_INVALID_VPI = 0x2e,
+ SLI4_FC_LOCAL_REJECT_NO_FPORT_DETECTED,
+ SLI4_FC_LOCAL_REJECT_MISSING_XRIBUF,
+ SLI4_FC_LOCAL_REJECT_RSVD5,
+ SLI4_FC_LOCAL_REJECT_INVALID_XRI,
+ SLI4_FC_LOCAL_REJECT_INVALID_RELOFFSET = 0x40,
+ SLI4_FC_LOCAL_REJECT_MISSING_RELOFFSET,
+ SLI4_FC_LOCAL_REJECT_INSUFF_BUFFERSPACE,
+ SLI4_FC_LOCAL_REJECT_MISSING_SI,
+ SLI4_FC_LOCAL_REJECT_MISSING_ES,
+ SLI4_FC_LOCAL_REJECT_INCOMPLETE_XFER,
+ SLI4_FC_LOCAL_REJECT_SLER_FAILURE,
+ SLI4_FC_LOCAL_REJECT_SLER_CMD_RCV_FAILURE,
+ SLI4_FC_LOCAL_REJECT_SLER_REC_RJT_ERR,
+ SLI4_FC_LOCAL_REJECT_SLER_REC_SRR_RETRY_ERR,
+ SLI4_FC_LOCAL_REJECT_SLER_SRR_RJT_ERR,
+ SLI4_FC_LOCAL_REJECT_RSVD6,
+ SLI4_FC_LOCAL_REJECT_SLER_RRQ_RJT_ERR,
+ SLI4_FC_LOCAL_REJECT_SLER_RRQ_RETRY_ERR,
+ SLI4_FC_LOCAL_REJECT_SLER_ABTS_ERR,
+};
+
+enum sli4_async_rcqe_flags {
+ SLI4_RACQE_RQ_EL_INDX = 0xfff,
+ SLI4_RACQE_FCFI = 0x3f,
+ SLI4_RACQE_HDPL = 0x3f,
+ SLI4_RACQE_RQ_ID = 0xffc0,
+};
+
+struct sli4_fc_async_rcqe {
+ u8 rsvd0;
+ u8 status;
+ __le16 rq_elmt_indx_word;
+ __le32 rsvd4;
+ __le16 fcfi_rq_id_word;
+ __le16 data_placement_length;
+ u8 sof_byte;
+ u8 eof_byte;
+ u8 code;
+ u8 hdpl_byte;
+};
+
+struct sli4_fc_async_rcqe_v1 {
+ u8 rsvd0;
+ u8 status;
+ __le16 rq_elmt_indx_word;
+ u8 fcfi_byte;
+ u8 rsvd5;
+ __le16 rsvd6;
+ __le16 rq_id;
+ __le16 data_placement_length;
+ u8 sof_byte;
+ u8 eof_byte;
+ u8 code;
+ u8 hdpl_byte;
+};
+
+enum sli4_fc_async_rq_status {
+ SLI4_FC_ASYNC_RQ_SUCCESS = 0x10,
+ SLI4_FC_ASYNC_RQ_BUF_LEN_EXCEEDED,
+ SLI4_FC_ASYNC_RQ_INSUFF_BUF_NEEDED,
+ SLI4_FC_ASYNC_RQ_INSUFF_BUF_FRM_DISC,
+ SLI4_FC_ASYNC_RQ_DMA_FAILURE,
+};
+
+#define SLI4_RCQE_RQ_EL_INDX 0xfff
+
+struct sli4_fc_coalescing_rcqe {
+ u8 rsvd0;
+ u8 status;
+ __le16 rq_elmt_indx_word;
+ __le32 rsvd4;
+ __le16 rq_id;
+ __le16 seq_placement_length;
+ __le16 rsvd14;
+ u8 code;
+ u8 vld_byte;
+};
+
+#define SLI4_FC_COALESCE_RQ_SUCCESS 0x10
+#define SLI4_FC_COALESCE_RQ_INSUFF_XRI_NEEDED 0x18
+
+enum sli4_optimized_write_cmd_cqe_flags {
+ SLI4_OCQE_RQ_EL_INDX = 0x7f, /* DW0 bits 16:30 */
+ SLI4_OCQE_FCFI = 0x3f, /* DW1 bits 0:6 */
+ SLI4_OCQE_OOX = 1 << 6, /* DW1 bit 15 */
+ SLI4_OCQE_AGXR = 1 << 7, /* DW1 bit 16 */
+ SLI4_OCQE_HDPL = 0x3f, /* DW3 bits 24:29*/
+};
+
+struct sli4_fc_optimized_write_cmd_cqe {
+ u8 rsvd0;
+ u8 status;
+ __le16 w1;
+ u8 flags0;
+ u8 flags1;
+ __le16 xri;
+ __le16 rq_id;
+ __le16 data_placement_length;
+ __le16 rpi;
+ u8 code;
+ u8 hdpl_vld;
+};
+
+#define SLI4_OCQE_XB 0x10
+
+struct sli4_fc_optimized_write_data_cqe {
+ u8 hw_status;
+ u8 status;
+ __le16 xri;
+ __le32 total_data_placed;
+ __le32 extended_status;
+ __le16 rsvd12;
+ u8 code;
+ u8 flags;
+};
+
+struct sli4_fc_xri_aborted_cqe {
+ u8 rsvd0;
+ u8 status;
+ __le16 rsvd2;
+ __le32 extended_status;
+ __le16 xri;
+ __le16 remote_xid;
+ __le16 rsvd12;
+ u8 code;
+ u8 flags;
+};
+
+enum sli4_generic_ctx {
+ SLI4_GENERIC_CONTEXT_RPI,
+ SLI4_GENERIC_CONTEXT_VPI,
+ SLI4_GENERIC_CONTEXT_VFI,
+ SLI4_GENERIC_CONTEXT_FCFI,
+};
+
+#define SLI4_GENERIC_CLASS_CLASS_2 0x1
+#define SLI4_GENERIC_CLASS_CLASS_3 0x2
+
+#define SLI4_ELS_REQUEST64_DIR_WRITE 0x0
+#define SLI4_ELS_REQUEST64_DIR_READ 0x1
+
+enum sli4_els_request {
+ SLI4_ELS_REQUEST64_OTHER,
+ SLI4_ELS_REQUEST64_LOGO,
+ SLI4_ELS_REQUEST64_FDISC,
+ SLI4_ELS_REQUEST64_FLOGIN,
+ SLI4_ELS_REQUEST64_PLOGI,
+};
+
+enum sli4_els_cmd_type {
+ SLI4_ELS_REQUEST64_CMD_GEN = 0x08,
+ SLI4_ELS_REQUEST64_CMD_NON_FABRIC = 0x0c,
+ SLI4_ELS_REQUEST64_CMD_FABRIC = 0x0d,
+};
+
+#define SLI_PAGE_SIZE SZ_4K
+
+#define SLI4_BMBX_TIMEOUT_MSEC 30000
+#define SLI4_FW_READY_TIMEOUT_MSEC 30000
+
+#define SLI4_BMBX_DELAY_US 1000 /* 1 ms */
+#define SLI4_INIT_PORT_DELAY_US 10000 /* 10 ms */
+
+static inline u32
+sli_page_count(size_t bytes, u32 page_size)
+{
+ if (!page_size)
+ return 0;
+
+ return (bytes + (page_size - 1)) >> __ffs(page_size);
+}
+
+/*************************************************************************
+ * SLI-4 mailbox command formats and definitions
+ */
+
+struct sli4_mbox_command_header {
+ u8 resvd0;
+ u8 command;
+ __le16 status; /* Port writes to indicate success/fail */
+};
+
+enum sli4_mbx_cmd_value {
+ SLI4_MBX_CMD_CONFIG_LINK = 0x07,
+ SLI4_MBX_CMD_DUMP = 0x17,
+ SLI4_MBX_CMD_DOWN_LINK = 0x06,
+ SLI4_MBX_CMD_INIT_LINK = 0x05,
+ SLI4_MBX_CMD_INIT_VFI = 0xa3,
+ SLI4_MBX_CMD_INIT_VPI = 0xa4,
+ SLI4_MBX_CMD_POST_XRI = 0xa7,
+ SLI4_MBX_CMD_RELEASE_XRI = 0xac,
+ SLI4_MBX_CMD_READ_CONFIG = 0x0b,
+ SLI4_MBX_CMD_READ_STATUS = 0x0e,
+ SLI4_MBX_CMD_READ_NVPARMS = 0x02,
+ SLI4_MBX_CMD_READ_REV = 0x11,
+ SLI4_MBX_CMD_READ_LNK_STAT = 0x12,
+ SLI4_MBX_CMD_READ_SPARM64 = 0x8d,
+ SLI4_MBX_CMD_READ_TOPOLOGY = 0x95,
+ SLI4_MBX_CMD_REG_FCFI = 0xa0,
+ SLI4_MBX_CMD_REG_FCFI_MRQ = 0xaf,
+ SLI4_MBX_CMD_REG_RPI = 0x93,
+ SLI4_MBX_CMD_REG_RX_RQ = 0xa6,
+ SLI4_MBX_CMD_REG_VFI = 0x9f,
+ SLI4_MBX_CMD_REG_VPI = 0x96,
+ SLI4_MBX_CMD_RQST_FEATURES = 0x9d,
+ SLI4_MBX_CMD_SLI_CONFIG = 0x9b,
+ SLI4_MBX_CMD_UNREG_FCFI = 0xa2,
+ SLI4_MBX_CMD_UNREG_RPI = 0x14,
+ SLI4_MBX_CMD_UNREG_VFI = 0xa1,
+ SLI4_MBX_CMD_UNREG_VPI = 0x97,
+ SLI4_MBX_CMD_WRITE_NVPARMS = 0x03,
+ SLI4_MBX_CMD_CFG_AUTO_XFER_RDY = 0xad,
+};
+
+enum sli4_mbx_status {
+ SLI4_MBX_STATUS_SUCCESS = 0x0000,
+ SLI4_MBX_STATUS_FAILURE = 0x0001,
+ SLI4_MBX_STATUS_RPI_NOT_REG = 0x1400,
+};
+
+/* CONFIG_LINK - configure link-oriented parameters,
+ * such as default N_Port_ID address and various timers
+ */
+enum sli4_cmd_config_link_flags {
+ SLI4_CFG_LINK_BBSCN = 0xf00,
+ SLI4_CFG_LINK_CSCN = 0x1000,
+};
+
+struct sli4_cmd_config_link {
+ struct sli4_mbox_command_header hdr;
+ u8 maxbbc;
+ u8 rsvd5;
+ u8 rsvd6;
+ u8 rsvd7;
+ u8 alpa;
+ __le16 n_port_id;
+ u8 rsvd11;
+ __le32 rsvd12;
+ __le32 e_d_tov;
+ __le32 lp_tov;
+ __le32 r_a_tov;
+ __le32 r_t_tov;
+ __le32 al_tov;
+ __le32 rsvd36;
+ __le32 bbscn_dword;
+};
+
+#define SLI4_DUMP4_TYPE 0xf
+
+#define SLI4_WKI_TAG_SAT_TEM 0x1040
+
+struct sli4_cmd_dump4 {
+ struct sli4_mbox_command_header hdr;
+ __le32 type_dword;
+ __le16 wki_selection;
+ __le16 rsvd10;
+ __le32 rsvd12;
+ __le32 returned_byte_cnt;
+ __le32 resp_data[59];
+};
+
+/* INIT_LINK - initialize the link for a FC port */
+enum sli4_init_link_flags {
+ SLI4_INIT_LINK_F_LOOPBACK = 1 << 0,
+
+ SLI4_INIT_LINK_F_P2P_ONLY = 1 << 1,
+ SLI4_INIT_LINK_F_FCAL_ONLY = 2 << 1,
+ SLI4_INIT_LINK_F_FCAL_FAIL_OVER = 0 << 1,
+ SLI4_INIT_LINK_F_P2P_FAIL_OVER = 1 << 1,
+
+ SLI4_INIT_LINK_F_UNFAIR = 1 << 6,
+ SLI4_INIT_LINK_F_NO_LIRP = 1 << 7,
+ SLI4_INIT_LINK_F_LOOP_VALID_CHK = 1 << 8,
+ SLI4_INIT_LINK_F_NO_LISA = 1 << 9,
+ SLI4_INIT_LINK_F_FAIL_OVER = 1 << 10,
+ SLI4_INIT_LINK_F_FIXED_SPEED = 1 << 11,
+ SLI4_INIT_LINK_F_PICK_HI_ALPA = 1 << 15,
+
+};
+
+enum sli4_fc_link_speed {
+ SLI4_LINK_SPEED_1G = 1,
+ SLI4_LINK_SPEED_2G,
+ SLI4_LINK_SPEED_AUTO_1_2,
+ SLI4_LINK_SPEED_4G,
+ SLI4_LINK_SPEED_AUTO_4_1,
+ SLI4_LINK_SPEED_AUTO_4_2,
+ SLI4_LINK_SPEED_AUTO_4_2_1,
+ SLI4_LINK_SPEED_8G,
+ SLI4_LINK_SPEED_AUTO_8_1,
+ SLI4_LINK_SPEED_AUTO_8_2,
+ SLI4_LINK_SPEED_AUTO_8_2_1,
+ SLI4_LINK_SPEED_AUTO_8_4,
+ SLI4_LINK_SPEED_AUTO_8_4_1,
+ SLI4_LINK_SPEED_AUTO_8_4_2,
+ SLI4_LINK_SPEED_10G,
+ SLI4_LINK_SPEED_16G,
+ SLI4_LINK_SPEED_AUTO_16_8_4,
+ SLI4_LINK_SPEED_AUTO_16_8,
+ SLI4_LINK_SPEED_32G,
+ SLI4_LINK_SPEED_AUTO_32_16_8,
+ SLI4_LINK_SPEED_AUTO_32_16,
+ SLI4_LINK_SPEED_64G,
+ SLI4_LINK_SPEED_AUTO_64_32_16,
+ SLI4_LINK_SPEED_AUTO_64_32,
+ SLI4_LINK_SPEED_128G,
+ SLI4_LINK_SPEED_AUTO_128_64_32,
+ SLI4_LINK_SPEED_AUTO_128_64,
+};
+
+struct sli4_cmd_init_link {
+ struct sli4_mbox_command_header hdr;
+ __le32 sel_reset_al_pa_dword;
+ __le32 flags0;
+ __le32 link_speed_sel_code;
+};
+
+/* INIT_VFI - initialize the VFI resource */
+enum sli4_init_vfi_flags {
+ SLI4_INIT_VFI_FLAG_VP = 0x1000,
+ SLI4_INIT_VFI_FLAG_VF = 0x2000,
+ SLI4_INIT_VFI_FLAG_VT = 0x4000,
+ SLI4_INIT_VFI_FLAG_VR = 0x8000,
+
+ SLI4_INIT_VFI_VFID = 0x1fff,
+ SLI4_INIT_VFI_PRI = 0xe000,
+
+ SLI4_INIT_VFI_HOP_COUNT = 0xff000000,
+};
+
+struct sli4_cmd_init_vfi {
+ struct sli4_mbox_command_header hdr;
+ __le16 vfi;
+ __le16 flags0_word;
+ __le16 fcfi;
+ __le16 vpi;
+ __le32 vf_id_pri_dword;
+ __le32 hop_cnt_dword;
+};
+
+/* INIT_VPI - initialize the VPI resource */
+struct sli4_cmd_init_vpi {
+ struct sli4_mbox_command_header hdr;
+ __le16 vpi;
+ __le16 vfi;
+};
+
+/* POST_XRI - post XRI resources to the SLI Port */
+enum sli4_post_xri_flags {
+ SLI4_POST_XRI_COUNT = 0xfff,
+ SLI4_POST_XRI_FLAG_ENX = 0x1000,
+ SLI4_POST_XRI_FLAG_DL = 0x2000,
+ SLI4_POST_XRI_FLAG_DI = 0x4000,
+ SLI4_POST_XRI_FLAG_VAL = 0x8000,
+};
+
+struct sli4_cmd_post_xri {
+ struct sli4_mbox_command_header hdr;
+ __le16 xri_base;
+ __le16 xri_count_flags;
+};
+
+/* RELEASE_XRI - Release XRI resources from the SLI Port */
+enum sli4_release_xri_flags {
+ SLI4_RELEASE_XRI_REL_XRI_CNT = 0x1f,
+ SLI4_RELEASE_XRI_COUNT = 0x1f,
+};
+
+struct sli4_cmd_release_xri {
+ struct sli4_mbox_command_header hdr;
+ __le16 rel_xri_count_word;
+ __le16 xri_count_word;
+
+ struct {
+ __le16 xri_tag0;
+ __le16 xri_tag1;
+ } xri_tbl[62];
+};
+
+/* READ_CONFIG - read SLI port configuration parameters */
+struct sli4_cmd_read_config {
+ struct sli4_mbox_command_header hdr;
+};
+
+enum sli4_read_cfg_resp_flags {
+ SLI4_READ_CFG_RESP_RESOURCE_EXT = 0x80000000, /* DW1 */
+ SLI4_READ_CFG_RESP_TOPOLOGY = 0xff000000, /* DW2 */
+};
+
+enum sli4_read_cfg_topo {
+ SLI4_READ_CFG_TOPO_FC = 0x1, /* FC topology unknown */
+ SLI4_READ_CFG_TOPO_NON_FC_AL = 0x2, /* FC point-to-point or fabric */
+ SLI4_READ_CFG_TOPO_FC_AL = 0x3, /* FC-AL topology */
+};
+
+/* Link Module Type */
+enum sli4_read_cfg_lmt {
+ SLI4_LINK_MODULE_TYPE_1GB = 0x0004,
+ SLI4_LINK_MODULE_TYPE_2GB = 0x0008,
+ SLI4_LINK_MODULE_TYPE_4GB = 0x0040,
+ SLI4_LINK_MODULE_TYPE_8GB = 0x0080,
+ SLI4_LINK_MODULE_TYPE_16GB = 0x0200,
+ SLI4_LINK_MODULE_TYPE_32GB = 0x0400,
+ SLI4_LINK_MODULE_TYPE_64GB = 0x0800,
+ SLI4_LINK_MODULE_TYPE_128GB = 0x1000,
+};
+
+struct sli4_rsp_read_config {
+ struct sli4_mbox_command_header hdr;
+ __le32 ext_dword;
+ __le32 topology_dword;
+ __le32 resvd8;
+ __le16 e_d_tov;
+ __le16 resvd14;
+ __le32 resvd16;
+ __le16 r_a_tov;
+ __le16 resvd22;
+ __le32 resvd24;
+ __le32 resvd28;
+ __le16 lmt;
+ __le16 resvd34;
+ __le32 resvd36;
+ __le32 resvd40;
+ __le16 xri_base;
+ __le16 xri_count;
+ __le16 rpi_base;
+ __le16 rpi_count;
+ __le16 vpi_base;
+ __le16 vpi_count;
+ __le16 vfi_base;
+ __le16 vfi_count;
+ __le16 resvd60;
+ __le16 fcfi_count;
+ __le16 rq_count;
+ __le16 eq_count;
+ __le16 wq_count;
+ __le16 cq_count;
+ __le32 pad[45];
+};
+
+/* READ_NVPARMS - read SLI port configuration parameters */
+enum sli4_read_nvparms_flags {
+ SLI4_READ_NVPARAMS_HARD_ALPA = 0xff,
+ SLI4_READ_NVPARAMS_PREFERRED_D_ID = 0xffffff00,
+};
+
+struct sli4_cmd_read_nvparms {
+ struct sli4_mbox_command_header hdr;
+ __le32 resvd0;
+ __le32 resvd4;
+ __le32 resvd8;
+ __le32 resvd12;
+ u8 wwpn[8];
+ u8 wwnn[8];
+ __le32 hard_alpa_d_id;
+};
+
+/* WRITE_NVPARMS - write SLI port configuration parameters */
+struct sli4_cmd_write_nvparms {
+ struct sli4_mbox_command_header hdr;
+ __le32 resvd0;
+ __le32 resvd4;
+ __le32 resvd8;
+ __le32 resvd12;
+ u8 wwpn[8];
+ u8 wwnn[8];
+ __le32 hard_alpa_d_id;
+};
+
+/* READ_REV - read the Port revision levels */
+enum {
+ SLI4_READ_REV_FLAG_SLI_LEVEL = 0xf,
+ SLI4_READ_REV_FLAG_FCOEM = 0x10,
+ SLI4_READ_REV_FLAG_CEEV = 0x60,
+ SLI4_READ_REV_FLAG_VPD = 0x2000,
+
+ SLI4_READ_REV_AVAILABLE_LENGTH = 0xffffff,
+};
+
+struct sli4_cmd_read_rev {
+ struct sli4_mbox_command_header hdr;
+ __le16 resvd0;
+ __le16 flags0_word;
+ __le32 first_hw_rev;
+ __le32 second_hw_rev;
+ __le32 resvd12;
+ __le32 third_hw_rev;
+ u8 fc_ph_low;
+ u8 fc_ph_high;
+ u8 feature_level_low;
+ u8 feature_level_high;
+ __le32 resvd24;
+ __le32 first_fw_id;
+ u8 first_fw_name[16];
+ __le32 second_fw_id;
+ u8 second_fw_name[16];
+ __le32 rsvd18[30];
+ __le32 available_length_dword;
+ struct sli4_dmaaddr hostbuf;
+ __le32 returned_vpd_length;
+ __le32 actual_vpd_length;
+};
+
+/* READ_SPARM64 - read the Port service parameters */
+#define SLI4_READ_SPARM64_WWPN_OFFSET (4 * sizeof(u32))
+#define SLI4_READ_SPARM64_WWNN_OFFSET (6 * sizeof(u32))
+
+struct sli4_cmd_read_sparm64 {
+ struct sli4_mbox_command_header hdr;
+ __le32 resvd0;
+ __le32 resvd4;
+ struct sli4_bde bde_64;
+ __le16 vpi;
+ __le16 resvd22;
+ __le16 port_name_start;
+ __le16 port_name_len;
+ __le16 node_name_start;
+ __le16 node_name_len;
+};
+
+/* READ_TOPOLOGY - read the link event information */
+enum sli4_read_topo_e {
+ SLI4_READTOPO_ATTEN_TYPE = 0xff,
+ SLI4_READTOPO_FLAG_IL = 0x100,
+ SLI4_READTOPO_FLAG_PB_RECVD = 0x200,
+
+ SLI4_READTOPO_LINKSTATE_RECV = 0x3,
+ SLI4_READTOPO_LINKSTATE_TRANS = 0xc,
+ SLI4_READTOPO_LINKSTATE_MACHINE = 0xf0,
+ SLI4_READTOPO_LINKSTATE_SPEED = 0xff00,
+ SLI4_READTOPO_LINKSTATE_TF = 0x40000000,
+ SLI4_READTOPO_LINKSTATE_LU = 0x80000000,
+
+ SLI4_READTOPO_SCN_BBSCN = 0xf,
+ SLI4_READTOPO_SCN_CBBSCN = 0xf0,
+
+ SLI4_READTOPO_R_T_TOV = 0x1ff,
+ SLI4_READTOPO_AL_TOV = 0xf000,
+
+ SLI4_READTOPO_PB_FLAG = 0x80,
+
+ SLI4_READTOPO_INIT_N_PORTID = 0xffffff,
+};
+
+#define SLI4_MIN_LOOP_MAP_BYTES 128
+
+struct sli4_cmd_read_topology {
+ struct sli4_mbox_command_header hdr;
+ __le32 event_tag;
+ __le32 dw2_attentype;
+ u8 topology;
+ u8 lip_type;
+ u8 lip_al_ps;
+ u8 al_pa_granted;
+ struct sli4_bde bde_loop_map;
+ __le32 linkdown_state;
+ __le32 currlink_state;
+ u8 max_bbc;
+ u8 init_bbc;
+ u8 scn_flags;
+ u8 rsvd39;
+ __le16 dw10w0_al_rt_tov;
+ __le16 lp_tov;
+ u8 acquired_al_pa;
+ u8 pb_flags;
+ __le16 specified_al_pa;
+ __le32 dw12_init_n_port_id;
+};
+
+enum sli4_read_topo_link {
+ SLI4_READ_TOPOLOGY_LINK_UP = 0x1,
+ SLI4_READ_TOPOLOGY_LINK_DOWN,
+ SLI4_READ_TOPOLOGY_LINK_NO_ALPA,
+};
+
+enum sli4_read_topo {
+ SLI4_READ_TOPO_UNKNOWN = 0x0,
+ SLI4_READ_TOPO_NON_FC_AL,
+ SLI4_READ_TOPO_FC_AL,
+};
+
+enum sli4_read_topo_speed {
+ SLI4_READ_TOPOLOGY_SPEED_NONE = 0x00,
+ SLI4_READ_TOPOLOGY_SPEED_1G = 0x04,
+ SLI4_READ_TOPOLOGY_SPEED_2G = 0x08,
+ SLI4_READ_TOPOLOGY_SPEED_4G = 0x10,
+ SLI4_READ_TOPOLOGY_SPEED_8G = 0x20,
+ SLI4_READ_TOPOLOGY_SPEED_10G = 0x40,
+ SLI4_READ_TOPOLOGY_SPEED_16G = 0x80,
+ SLI4_READ_TOPOLOGY_SPEED_32G = 0x90,
+ SLI4_READ_TOPOLOGY_SPEED_64G = 0xa0,
+ SLI4_READ_TOPOLOGY_SPEED_128G = 0xb0,
+};
+
+/* REG_FCFI - activate a FC Forwarder */
+struct sli4_cmd_reg_fcfi_rq_cfg {
+ u8 r_ctl_mask;
+ u8 r_ctl_match;
+ u8 type_mask;
+ u8 type_match;
+};
+
+enum sli4_regfcfi_tag {
+ SLI4_REGFCFI_VLAN_TAG = 0xfff,
+ SLI4_REGFCFI_VLANTAG_VALID = 0x1000,
+};
+
+#define SLI4_CMD_REG_FCFI_NUM_RQ_CFG 4
+struct sli4_cmd_reg_fcfi {
+ struct sli4_mbox_command_header hdr;
+ __le16 fcf_index;
+ __le16 fcfi;
+ __le16 rqid1;
+ __le16 rqid0;
+ __le16 rqid3;
+ __le16 rqid2;
+ struct sli4_cmd_reg_fcfi_rq_cfg
+ rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG];
+ __le32 dw8_vlan;
+};
+
+#define SLI4_CMD_REG_FCFI_MRQ_NUM_RQ_CFG 4
+#define SLI4_CMD_REG_FCFI_MRQ_MAX_NUM_RQ 32
+#define SLI4_CMD_REG_FCFI_SET_FCFI_MODE 0
+#define SLI4_CMD_REG_FCFI_SET_MRQ_MODE 1
+
+enum sli4_reg_fcfi_mrq {
+ SLI4_REGFCFI_MRQ_VLAN_TAG = 0xfff,
+ SLI4_REGFCFI_MRQ_VLANTAG_VALID = 0x1000,
+ SLI4_REGFCFI_MRQ_MODE = 0x2000,
+
+ SLI4_REGFCFI_MRQ_MASK_NUM_PAIRS = 0xff,
+ SLI4_REGFCFI_MRQ_FILTER_BITMASK = 0xf00,
+ SLI4_REGFCFI_MRQ_RQ_SEL_POLICY = 0xf000,
+};
+
+struct sli4_cmd_reg_fcfi_mrq {
+ struct sli4_mbox_command_header hdr;
+ __le16 fcf_index;
+ __le16 fcfi;
+ __le16 rqid1;
+ __le16 rqid0;
+ __le16 rqid3;
+ __le16 rqid2;
+ struct sli4_cmd_reg_fcfi_rq_cfg
+ rq_cfg[SLI4_CMD_REG_FCFI_MRQ_NUM_RQ_CFG];
+ __le32 dw8_vlan;
+ __le32 dw9_mrqflags;
+};
+
+struct sli4_cmd_rq_cfg {
+ __le16 rq_id;
+ u8 r_ctl_mask;
+ u8 r_ctl_match;
+ u8 type_mask;
+ u8 type_match;
+};
+
+/* REG_RPI - register a Remote Port Indicator */
+enum sli4_reg_rpi {
+ SLI4_REGRPI_REMOTE_N_PORTID = 0xffffff, /* DW2 */
+ SLI4_REGRPI_UPD = 0x1000000,
+ SLI4_REGRPI_ETOW = 0x8000000,
+ SLI4_REGRPI_TERP = 0x20000000,
+ SLI4_REGRPI_CI = 0x80000000,
+};
+
+struct sli4_cmd_reg_rpi {
+ struct sli4_mbox_command_header hdr;
+ __le16 rpi;
+ __le16 rsvd2;
+ __le32 dw2_rportid_flags;
+ struct sli4_bde bde_64;
+ __le16 vpi;
+ __le16 rsvd26;
+};
+
+#define SLI4_REG_RPI_BUF_LEN 0x70
+
+/* REG_VFI - register a Virtual Fabric Indicator */
+enum sli_reg_vfi {
+ SLI4_REGVFI_VP = 0x1000, /* DW1 */
+ SLI4_REGVFI_UPD = 0x2000,
+
+ SLI4_REGVFI_LOCAL_N_PORTID = 0xffffff, /* DW10 */
+};
+
+struct sli4_cmd_reg_vfi {
+ struct sli4_mbox_command_header hdr;
+ __le16 vfi;
+ __le16 dw0w1_flags;
+ __le16 fcfi;
+ __le16 vpi;
+ u8 wwpn[8];
+ struct sli4_bde sparm;
+ __le32 e_d_tov;
+ __le32 r_a_tov;
+ __le32 dw10_lportid_flags;
+};
+
+/* REG_VPI - register a Virtual Port Indicator */
+enum sli4_reg_vpi {
+ SLI4_REGVPI_LOCAL_N_PORTID = 0xffffff,
+ SLI4_REGVPI_UPD = 0x1000000,
+};
+
+struct sli4_cmd_reg_vpi {
+ struct sli4_mbox_command_header hdr;
+ __le32 rsvd0;
+ __le32 dw2_lportid_flags;
+ u8 wwpn[8];
+ __le32 rsvd12;
+ __le16 vpi;
+ __le16 vfi;
+};
+
+/* REQUEST_FEATURES - request / query SLI features */
+enum sli4_req_features_flags {
+ SLI4_REQFEAT_QRY = 0x1, /* Dw1 */
+
+ SLI4_REQFEAT_IAAB = 1 << 0, /* DW2 & DW3 */
+ SLI4_REQFEAT_NPIV = 1 << 1,
+ SLI4_REQFEAT_DIF = 1 << 2,
+ SLI4_REQFEAT_VF = 1 << 3,
+ SLI4_REQFEAT_FCPI = 1 << 4,
+ SLI4_REQFEAT_FCPT = 1 << 5,
+ SLI4_REQFEAT_FCPC = 1 << 6,
+ SLI4_REQFEAT_RSVD = 1 << 7,
+ SLI4_REQFEAT_RQD = 1 << 8,
+ SLI4_REQFEAT_IAAR = 1 << 9,
+ SLI4_REQFEAT_HLM = 1 << 10,
+ SLI4_REQFEAT_PERFH = 1 << 11,
+ SLI4_REQFEAT_RXSEQ = 1 << 12,
+ SLI4_REQFEAT_RXRI = 1 << 13,
+ SLI4_REQFEAT_DCL2 = 1 << 14,
+ SLI4_REQFEAT_RSCO = 1 << 15,
+ SLI4_REQFEAT_MRQP = 1 << 16,
+};
+
+struct sli4_cmd_request_features {
+ struct sli4_mbox_command_header hdr;
+ __le32 dw1_qry;
+ __le32 cmd;
+ __le32 resp;
+};
+
+/*
+ * SLI_CONFIG - submit a configuration command to Port
+ *
+ * Command is either embedded as part of the payload (embed) or located
+ * in a separate memory buffer (mem)
+ */
+enum sli4_sli_config {
+ SLI4_SLICONF_EMB = 0x1, /* DW1 */
+ SLI4_SLICONF_PMDCMD_SHIFT = 3,
+ SLI4_SLICONF_PMDCMD_MASK = 0xf8,
+ SLI4_SLICONF_PMDCMD_VAL_1 = 8,
+ SLI4_SLICONF_PMDCNT = 0xf8,
+
+ SLI4_SLICONF_PMD_LEN = 0x00ffffff,
+};
+
+struct sli4_cmd_sli_config {
+ struct sli4_mbox_command_header hdr;
+ __le32 dw1_flags;
+ __le32 payload_len;
+ __le32 rsvd12[3];
+ union {
+ u8 embed[58 * sizeof(u32)];
+ struct sli4_bufptr mem;
+ } payload;
+};
+
+/* READ_STATUS - read tx/rx status of a particular port */
+#define SLI4_READSTATUS_CLEAR_COUNTERS 0x1
+
+struct sli4_cmd_read_status {
+ struct sli4_mbox_command_header hdr;
+ __le32 dw1_flags;
+ __le32 rsvd4;
+ __le32 trans_kbyte_cnt;
+ __le32 recv_kbyte_cnt;
+ __le32 trans_frame_cnt;
+ __le32 recv_frame_cnt;
+ __le32 trans_seq_cnt;
+ __le32 recv_seq_cnt;
+ __le32 tot_exchanges_orig;
+ __le32 tot_exchanges_resp;
+ __le32 recv_p_bsy_cnt;
+ __le32 recv_f_bsy_cnt;
+ __le32 no_rq_buf_dropped_frames_cnt;
+ __le32 empty_rq_timeout_cnt;
+ __le32 no_xri_dropped_frames_cnt;
+ __le32 empty_xri_pool_cnt;
+};
+
+/* READ_LNK_STAT - read link status of a particular port */
+enum sli4_read_link_stats_flags {
+ SLI4_READ_LNKSTAT_REC = 1u << 0,
+ SLI4_READ_LNKSTAT_GEC = 1u << 1,
+ SLI4_READ_LNKSTAT_W02OF = 1u << 2,
+ SLI4_READ_LNKSTAT_W03OF = 1u << 3,
+ SLI4_READ_LNKSTAT_W04OF = 1u << 4,
+ SLI4_READ_LNKSTAT_W05OF = 1u << 5,
+ SLI4_READ_LNKSTAT_W06OF = 1u << 6,
+ SLI4_READ_LNKSTAT_W07OF = 1u << 7,
+ SLI4_READ_LNKSTAT_W08OF = 1u << 8,
+ SLI4_READ_LNKSTAT_W09OF = 1u << 9,
+ SLI4_READ_LNKSTAT_W10OF = 1u << 10,
+ SLI4_READ_LNKSTAT_W11OF = 1u << 11,
+ SLI4_READ_LNKSTAT_W12OF = 1u << 12,
+ SLI4_READ_LNKSTAT_W13OF = 1u << 13,
+ SLI4_READ_LNKSTAT_W14OF = 1u << 14,
+ SLI4_READ_LNKSTAT_W15OF = 1u << 15,
+ SLI4_READ_LNKSTAT_W16OF = 1u << 16,
+ SLI4_READ_LNKSTAT_W17OF = 1u << 17,
+ SLI4_READ_LNKSTAT_W18OF = 1u << 18,
+ SLI4_READ_LNKSTAT_W19OF = 1u << 19,
+ SLI4_READ_LNKSTAT_W20OF = 1u << 20,
+ SLI4_READ_LNKSTAT_W21OF = 1u << 21,
+ SLI4_READ_LNKSTAT_CLRC = 1u << 30,
+ SLI4_READ_LNKSTAT_CLOF = 1u << 31,
+};
+
+struct sli4_cmd_read_link_stats {
+ struct sli4_mbox_command_header hdr;
+ __le32 dw1_flags;
+ __le32 linkfail_errcnt;
+ __le32 losssync_errcnt;
+ __le32 losssignal_errcnt;
+ __le32 primseq_errcnt;
+ __le32 inval_txword_errcnt;
+ __le32 crc_errcnt;
+ __le32 primseq_eventtimeout_cnt;
+ __le32 elastic_bufoverrun_errcnt;
+ __le32 arbit_fc_al_timeout_cnt;
+ __le32 adv_rx_buftor_to_buf_credit;
+ __le32 curr_rx_buf_to_buf_credit;
+ __le32 adv_tx_buf_to_buf_credit;
+ __le32 curr_tx_buf_to_buf_credit;
+ __le32 rx_eofa_cnt;
+ __le32 rx_eofdti_cnt;
+ __le32 rx_eofni_cnt;
+ __le32 rx_soff_cnt;
+ __le32 rx_dropped_no_aer_cnt;
+ __le32 rx_dropped_no_avail_rpi_rescnt;
+ __le32 rx_dropped_no_avail_xri_rescnt;
+};
+
+/* Format a WQE with WQ_ID Association performance hint */
+static inline void
+sli_set_wq_id_association(void *entry, u16 q_id)
+{
+ u32 *wqe = entry;
+
+ /*
+ * Set Word 10, bit 0 to zero
+ * Set Word 10, bits 15:1 to the WQ ID
+ */
+ wqe[10] &= ~0xffff;
+ wqe[10] |= q_id << 1;
+}
+
+/* UNREG_FCFI - unregister a FCFI */
+struct sli4_cmd_unreg_fcfi {
+ struct sli4_mbox_command_header hdr;
+ __le32 rsvd0;
+ __le16 fcfi;
+ __le16 rsvd6;
+};
+
+/* UNREG_RPI - unregister one or more RPI */
+enum sli4_unreg_rpi {
+ SLI4_UNREG_RPI_DP = 0x2000,
+ SLI4_UNREG_RPI_II_SHIFT = 14,
+ SLI4_UNREG_RPI_II_MASK = 0xc000,
+ SLI4_UNREG_RPI_II_RPI = 0x0000,
+ SLI4_UNREG_RPI_II_VPI = 0x4000,
+ SLI4_UNREG_RPI_II_VFI = 0x8000,
+ SLI4_UNREG_RPI_II_FCFI = 0xc000,
+
+ SLI4_UNREG_RPI_DEST_N_PORTID_MASK = 0x00ffffff,
+};
+
+struct sli4_cmd_unreg_rpi {
+ struct sli4_mbox_command_header hdr;
+ __le16 index;
+ __le16 dw1w1_flags;
+ __le32 dw2_dest_n_portid;
+};
+
+/* UNREG_VFI - unregister one or more VFI */
+enum sli4_unreg_vfi {
+ SLI4_UNREG_VFI_II_SHIFT = 14,
+ SLI4_UNREG_VFI_II_MASK = 0xc000,
+ SLI4_UNREG_VFI_II_VFI = 0x0000,
+ SLI4_UNREG_VFI_II_FCFI = 0xc000,
+};
+
+struct sli4_cmd_unreg_vfi {
+ struct sli4_mbox_command_header hdr;
+ __le32 rsvd0;
+ __le16 index;
+ __le16 dw2_flags;
+};
+
+enum sli4_unreg_type {
+ SLI4_UNREG_TYPE_PORT,
+ SLI4_UNREG_TYPE_DOMAIN,
+ SLI4_UNREG_TYPE_FCF,
+ SLI4_UNREG_TYPE_ALL
+};
+
+/* UNREG_VPI - unregister one or more VPI */
+enum sli4_unreg_vpi {
+ SLI4_UNREG_VPI_II_SHIFT = 14,
+ SLI4_UNREG_VPI_II_MASK = 0xc000,
+ SLI4_UNREG_VPI_II_VPI = 0x0000,
+ SLI4_UNREG_VPI_II_VFI = 0x8000,
+ SLI4_UNREG_VPI_II_FCFI = 0xc000,
+};
+
+struct sli4_cmd_unreg_vpi {
+ struct sli4_mbox_command_header hdr;
+ __le32 rsvd0;
+ __le16 index;
+ __le16 dw2w0_flags;
+};
+
+/* AUTO_XFER_RDY - Configure the auto-generate XFER-RDY feature */
+struct sli4_cmd_config_auto_xfer_rdy {
+ struct sli4_mbox_command_header hdr;
+ __le32 rsvd0;
+ __le32 max_burst_len;
+};
+
+#define SLI4_CONFIG_AUTO_XFERRDY_BLKSIZE 0xffff
+
+struct sli4_cmd_config_auto_xfer_rdy_hp {
+ struct sli4_mbox_command_header hdr;
+ __le32 rsvd0;
+ __le32 max_burst_len;
+ __le32 dw3_esoc_flags;
+ __le16 block_size;
+ __le16 rsvd14;
+};
+
+/*************************************************************************
+ * SLI-4 common configuration command formats and definitions
+ */
+
+/*
+ * Subsystem values.
+ */
+enum sli4_subsystem {
+ SLI4_SUBSYSTEM_COMMON = 0x01,
+ SLI4_SUBSYSTEM_LOWLEVEL = 0x0b,
+ SLI4_SUBSYSTEM_FC = 0x0c,
+ SLI4_SUBSYSTEM_DMTF = 0x11,
+};
+
+#define SLI4_OPC_LOWLEVEL_SET_WATCHDOG 0X36
+
+/*
+ * Common opcode (OPC) values.
+ */
+enum sli4_cmn_opcode {
+ SLI4_CMN_FUNCTION_RESET = 0x3d,
+ SLI4_CMN_CREATE_CQ = 0x0c,
+ SLI4_CMN_CREATE_CQ_SET = 0x1d,
+ SLI4_CMN_DESTROY_CQ = 0x36,
+ SLI4_CMN_MODIFY_EQ_DELAY = 0x29,
+ SLI4_CMN_CREATE_EQ = 0x0d,
+ SLI4_CMN_DESTROY_EQ = 0x37,
+ SLI4_CMN_CREATE_MQ_EXT = 0x5a,
+ SLI4_CMN_DESTROY_MQ = 0x35,
+ SLI4_CMN_GET_CNTL_ATTRIBUTES = 0x20,
+ SLI4_CMN_NOP = 0x21,
+ SLI4_CMN_GET_RSC_EXTENT_INFO = 0x9a,
+ SLI4_CMN_GET_SLI4_PARAMS = 0xb5,
+ SLI4_CMN_QUERY_FW_CONFIG = 0x3a,
+ SLI4_CMN_GET_PORT_NAME = 0x4d,
+
+ SLI4_CMN_WRITE_FLASHROM = 0x07,
+ /* TRANSCEIVER Data */
+ SLI4_CMN_READ_TRANS_DATA = 0x49,
+ SLI4_CMN_GET_CNTL_ADDL_ATTRS = 0x79,
+ SLI4_CMN_GET_FUNCTION_CFG = 0xa0,
+ SLI4_CMN_GET_PROFILE_CFG = 0xa4,
+ SLI4_CMN_SET_PROFILE_CFG = 0xa5,
+ SLI4_CMN_GET_PROFILE_LIST = 0xa6,
+ SLI4_CMN_GET_ACTIVE_PROFILE = 0xa7,
+ SLI4_CMN_SET_ACTIVE_PROFILE = 0xa8,
+ SLI4_CMN_READ_OBJECT = 0xab,
+ SLI4_CMN_WRITE_OBJECT = 0xac,
+ SLI4_CMN_DELETE_OBJECT = 0xae,
+ SLI4_CMN_READ_OBJECT_LIST = 0xad,
+ SLI4_CMN_SET_DUMP_LOCATION = 0xb8,
+ SLI4_CMN_SET_FEATURES = 0xbf,
+ SLI4_CMN_GET_RECFG_LINK_INFO = 0xc9,
+ SLI4_CMN_SET_RECNG_LINK_ID = 0xca,
+};
+
+/* DMTF opcode (OPC) values */
+#define DMTF_EXEC_CLP_CMD 0x01
+
+/*
+ * COMMON_FUNCTION_RESET
+ *
+ * Resets the Port, returning it to a power-on state. This configuration
+ * command does not have a payload and should set/expect the lengths to
+ * be zero.
+ */
+struct sli4_rqst_cmn_function_reset {
+ struct sli4_rqst_hdr hdr;
+};
+
+struct sli4_rsp_cmn_function_reset {
+ struct sli4_rsp_hdr hdr;
+};
+
+/*
+ * COMMON_GET_CNTL_ATTRIBUTES
+ *
+ * Query for information about the SLI Port
+ */
+enum sli4_cntrl_attr_flags {
+ SLI4_CNTL_ATTR_PORTNUM = 0x3f,
+ SLI4_CNTL_ATTR_PORTTYPE = 0xc0,
+};
+
+struct sli4_rsp_cmn_get_cntl_attributes {
+ struct sli4_rsp_hdr hdr;
+ u8 version_str[32];
+ u8 manufacturer_name[32];
+ __le32 supported_modes;
+ u8 eprom_version_lo;
+ u8 eprom_version_hi;
+ __le16 rsvd17;
+ __le32 mbx_ds_version;
+ __le32 ep_fw_ds_version;
+ u8 ncsi_version_str[12];
+ __le32 def_extended_timeout;
+ u8 model_number[32];
+ u8 description[64];
+ u8 serial_number[32];
+ u8 ip_version_str[32];
+ u8 fw_version_str[32];
+ u8 bios_version_str[32];
+ u8 redboot_version_str[32];
+ u8 driver_version_str[32];
+ u8 fw_on_flash_version_str[32];
+ __le32 functionalities_supported;
+ __le16 max_cdb_length;
+ u8 asic_revision;
+ u8 generational_guid0;
+ __le32 generational_guid1_12[3];
+ __le16 generational_guid13_14;
+ u8 generational_guid15;
+ u8 hba_port_count;
+ __le16 default_link_down_timeout;
+ u8 iscsi_version_min_max;
+ u8 multifunctional_device;
+ u8 cache_valid;
+ u8 hba_status;
+ u8 max_domains_supported;
+ u8 port_num_type_flags;
+ __le32 firmware_post_status;
+ __le32 hba_mtu;
+ u8 iscsi_features;
+ u8 rsvd121[3];
+ __le16 pci_vendor_id;
+ __le16 pci_device_id;
+ __le16 pci_sub_vendor_id;
+ __le16 pci_sub_system_id;
+ u8 pci_bus_number;
+ u8 pci_device_number;
+ u8 pci_function_number;
+ u8 interface_type;
+ __le64 unique_identifier;
+ u8 number_of_netfilters;
+ u8 rsvd122[3];
+};
+
+/*
+ * COMMON_GET_CNTL_ATTRIBUTES
+ *
+ * This command queries the controller information from the Flash ROM.
+ */
+struct sli4_rqst_cmn_get_cntl_addl_attributes {
+ struct sli4_rqst_hdr hdr;
+};
+
+struct sli4_rsp_cmn_get_cntl_addl_attributes {
+ struct sli4_rsp_hdr hdr;
+ __le16 ipl_file_number;
+ u8 ipl_file_version;
+ u8 rsvd4;
+ u8 on_die_temperature;
+ u8 rsvd5[3];
+ __le32 driver_advanced_features_supported;
+ __le32 rsvd7[4];
+ char universal_bios_version[32];
+ char x86_bios_version[32];
+ char efi_bios_version[32];
+ char fcode_version[32];
+ char uefi_bios_version[32];
+ char uefi_nic_version[32];
+ char uefi_fcode_version[32];
+ char uefi_iscsi_version[32];
+ char iscsi_x86_bios_version[32];
+ char pxe_x86_bios_version[32];
+ u8 default_wwpn[8];
+ u8 ext_phy_version[32];
+ u8 fc_universal_bios_version[32];
+ u8 fc_x86_bios_version[32];
+ u8 fc_efi_bios_version[32];
+ u8 fc_fcode_version[32];
+ u8 ext_phy_crc_label[8];
+ u8 ipl_file_name[16];
+ u8 rsvd139[72];
+};
+
+/*
+ * COMMON_NOP
+ *
+ * This command does not do anything; it only returns
+ * the payload in the completion.
+ */
+struct sli4_rqst_cmn_nop {
+ struct sli4_rqst_hdr hdr;
+ __le32 context[2];
+};
+
+struct sli4_rsp_cmn_nop {
+ struct sli4_rsp_hdr hdr;
+ __le32 context[2];
+};
+
+struct sli4_rqst_cmn_get_resource_extent_info {
+ struct sli4_rqst_hdr hdr;
+ __le16 resource_type;
+ __le16 rsvd16;
+};
+
+enum sli4_rsc_type {
+ SLI4_RSC_TYPE_VFI = 0x20,
+ SLI4_RSC_TYPE_VPI = 0x21,
+ SLI4_RSC_TYPE_RPI = 0x22,
+ SLI4_RSC_TYPE_XRI = 0x23,
+};
+
+struct sli4_rsp_cmn_get_resource_extent_info {
+ struct sli4_rsp_hdr hdr;
+ __le16 resource_extent_count;
+ __le16 resource_extent_size;
+};
+
+#define SLI4_128BYTE_WQE_SUPPORT 0x02
+
+#define GET_Q_CNT_METHOD(m) \
+ (((m) & SLI4_PARAM_Q_CNT_MTHD_MASK) >> SLI4_PARAM_Q_CNT_MTHD_SHFT)
+#define GET_Q_CREATE_VERSION(v) \
+ (((v) & SLI4_PARAM_QV_MASK) >> SLI4_PARAM_QV_SHIFT)
+
+enum sli4_rsp_get_params_e {
+ /*GENERIC*/
+ SLI4_PARAM_Q_CNT_MTHD_SHFT = 24,
+ SLI4_PARAM_Q_CNT_MTHD_MASK = 0xf << 24,
+ SLI4_PARAM_QV_SHIFT = 14,
+ SLI4_PARAM_QV_MASK = 3 << 14,
+
+ /* DW4 */
+ SLI4_PARAM_PROTO_TYPE_MASK = 0xff,
+ /* DW5 */
+ SLI4_PARAM_FT = 1 << 0,
+ SLI4_PARAM_SLI_REV_MASK = 0xf << 4,
+ SLI4_PARAM_SLI_FAM_MASK = 0xf << 8,
+ SLI4_PARAM_IF_TYPE_MASK = 0xf << 12,
+ SLI4_PARAM_SLI_HINT1_MASK = 0xff << 16,
+ SLI4_PARAM_SLI_HINT2_MASK = 0x1f << 24,
+ /* DW6 */
+ SLI4_PARAM_EQ_PAGE_CNT_MASK = 0xf << 0,
+ SLI4_PARAM_EQE_SZS_MASK = 0xf << 8,
+ SLI4_PARAM_EQ_PAGE_SZS_MASK = 0xff << 16,
+ /* DW8 */
+ SLI4_PARAM_CQ_PAGE_CNT_MASK = 0xf << 0,
+ SLI4_PARAM_CQE_SZS_MASK = 0xf << 8,
+ SLI4_PARAM_CQ_PAGE_SZS_MASK = 0xff << 16,
+ /* DW10 */
+ SLI4_PARAM_MQ_PAGE_CNT_MASK = 0xf << 0,
+ SLI4_PARAM_MQ_PAGE_SZS_MASK = 0xff << 16,
+ /* DW12 */
+ SLI4_PARAM_WQ_PAGE_CNT_MASK = 0xf << 0,
+ SLI4_PARAM_WQE_SZS_MASK = 0xf << 8,
+ SLI4_PARAM_WQ_PAGE_SZS_MASK = 0xff << 16,
+ /* DW14 */
+ SLI4_PARAM_RQ_PAGE_CNT_MASK = 0xf << 0,
+ SLI4_PARAM_RQE_SZS_MASK = 0xf << 8,
+ SLI4_PARAM_RQ_PAGE_SZS_MASK = 0xff << 16,
+ /* DW15W1*/
+ SLI4_PARAM_RQ_DB_WINDOW_MASK = 0xf000,
+ /* DW16 */
+ SLI4_PARAM_FC = 1 << 0,
+ SLI4_PARAM_EXT = 1 << 1,
+ SLI4_PARAM_HDRR = 1 << 2,
+ SLI4_PARAM_SGLR = 1 << 3,
+ SLI4_PARAM_FBRR = 1 << 4,
+ SLI4_PARAM_AREG = 1 << 5,
+ SLI4_PARAM_TGT = 1 << 6,
+ SLI4_PARAM_TERP = 1 << 7,
+ SLI4_PARAM_ASSI = 1 << 8,
+ SLI4_PARAM_WCHN = 1 << 9,
+ SLI4_PARAM_TCCA = 1 << 10,
+ SLI4_PARAM_TRTY = 1 << 11,
+ SLI4_PARAM_TRIR = 1 << 12,
+ SLI4_PARAM_PHOFF = 1 << 13,
+ SLI4_PARAM_PHON = 1 << 14,
+ SLI4_PARAM_PHWQ = 1 << 15,
+ SLI4_PARAM_BOUND_4GA = 1 << 16,
+ SLI4_PARAM_RXC = 1 << 17,
+ SLI4_PARAM_HLM = 1 << 18,
+ SLI4_PARAM_IPR = 1 << 19,
+ SLI4_PARAM_RXRI = 1 << 20,
+ SLI4_PARAM_SGLC = 1 << 21,
+ SLI4_PARAM_TIMM = 1 << 22,
+ SLI4_PARAM_TSMM = 1 << 23,
+ SLI4_PARAM_OAS = 1 << 25,
+ SLI4_PARAM_LC = 1 << 26,
+ SLI4_PARAM_AGXF = 1 << 27,
+ SLI4_PARAM_LOOPBACK_MASK = 0xf << 28,
+ /* DW18 */
+ SLI4_PARAM_SGL_PAGE_CNT_MASK = 0xf << 0,
+ SLI4_PARAM_SGL_PAGE_SZS_MASK = 0xff << 8,
+ SLI4_PARAM_SGL_PP_ALIGN_MASK = 0xff << 16,
+};
+
+struct sli4_rqst_cmn_get_sli4_params {
+ struct sli4_rqst_hdr hdr;
+};
+
+struct sli4_rsp_cmn_get_sli4_params {
+ struct sli4_rsp_hdr hdr;
+ __le32 dw4_protocol_type;
+ __le32 dw5_sli;
+ __le32 dw6_eq_page_cnt;
+ __le16 eqe_count_mask;
+ __le16 rsvd26;
+ __le32 dw8_cq_page_cnt;
+ __le16 cqe_count_mask;
+ __le16 rsvd34;
+ __le32 dw10_mq_page_cnt;
+ __le16 mqe_count_mask;
+ __le16 rsvd42;
+ __le32 dw12_wq_page_cnt;
+ __le16 wqe_count_mask;
+ __le16 rsvd50;
+ __le32 dw14_rq_page_cnt;
+ __le16 rqe_count_mask;
+ __le16 dw15w1_rq_db_window;
+ __le32 dw16_loopback_scope;
+ __le32 sge_supported_length;
+ __le32 dw18_sgl_page_cnt;
+ __le16 min_rq_buffer_size;
+ __le16 rsvd75;
+ __le32 max_rq_buffer_size;
+ __le16 physical_xri_max;
+ __le16 physical_rpi_max;
+ __le16 physical_vpi_max;
+ __le16 physical_vfi_max;
+ __le32 rsvd88;
+ __le16 frag_num_field_offset;
+ __le16 frag_num_field_size;
+ __le16 sgl_index_field_offset;
+ __le16 sgl_index_field_size;
+ __le32 chain_sge_initial_value_lo;
+ __le32 chain_sge_initial_value_hi;
+};
+
+/*Port Types*/
+enum sli4_port_types {
+ SLI4_PORT_TYPE_ETH = 0,
+ SLI4_PORT_TYPE_FC = 1,
+};
+
+struct sli4_rqst_cmn_get_port_name {
+ struct sli4_rqst_hdr hdr;
+ u8 port_type;
+ u8 rsvd4[3];
+};
+
+struct sli4_rsp_cmn_get_port_name {
+ struct sli4_rsp_hdr hdr;
+ char port_name[4];
+};
+
+struct sli4_rqst_cmn_write_flashrom {
+ struct sli4_rqst_hdr hdr;
+ __le32 flash_rom_access_opcode;
+ __le32 flash_rom_access_operation_type;
+ __le32 data_buffer_size;
+ __le32 offset;
+ u8 data_buffer[4];
+};
+
+/*
+ * COMMON_READ_TRANSCEIVER_DATA
+ *
+ * This command reads SFF transceiver data(Format is defined
+ * by the SFF-8472 specification).
+ */
+struct sli4_rqst_cmn_read_transceiver_data {
+ struct sli4_rqst_hdr hdr;
+ __le32 page_number;
+ __le32 port;
+};
+
+struct sli4_rsp_cmn_read_transceiver_data {
+ struct sli4_rsp_hdr hdr;
+ __le32 page_number;
+ __le32 port;
+ u8 page_data[128];
+ u8 page_data_2[128];
+};
+
+#define SLI4_REQ_DESIRE_READLEN 0xffffff
+
+struct sli4_rqst_cmn_read_object {
+ struct sli4_rqst_hdr hdr;
+ __le32 desired_read_length_dword;
+ __le32 read_offset;
+ u8 object_name[104];
+ __le32 host_buffer_descriptor_count;
+ struct sli4_bde host_buffer_descriptor[0];
+};
+
+#define RSP_COM_READ_OBJ_EOF 0x80000000
+
+struct sli4_rsp_cmn_read_object {
+ struct sli4_rsp_hdr hdr;
+ __le32 actual_read_length;
+ __le32 eof_dword;
+};
+
+enum sli4_rqst_write_object_flags {
+ SLI4_RQ_DES_WRITE_LEN = 0xffffff,
+ SLI4_RQ_DES_WRITE_LEN_NOC = 0x40000000,
+ SLI4_RQ_DES_WRITE_LEN_EOF = 0x80000000,
+};
+
+struct sli4_rqst_cmn_write_object {
+ struct sli4_rqst_hdr hdr;
+ __le32 desired_write_len_dword;
+ __le32 write_offset;
+ u8 object_name[104];
+ __le32 host_buffer_descriptor_count;
+ struct sli4_bde host_buffer_descriptor[0];
+};
+
+#define RSP_CHANGE_STATUS 0xff
+
+struct sli4_rsp_cmn_write_object {
+ struct sli4_rsp_hdr hdr;
+ __le32 actual_write_length;
+ __le32 change_status_dword;
+};
+
+struct sli4_rqst_cmn_delete_object {
+ struct sli4_rqst_hdr hdr;
+ __le32 rsvd4;
+ __le32 rsvd5;
+ u8 object_name[104];
+};
+
+#define SLI4_RQ_OBJ_LIST_READ_LEN 0xffffff
+
+struct sli4_rqst_cmn_read_object_list {
+ struct sli4_rqst_hdr hdr;
+ __le32 desired_read_length_dword;
+ __le32 read_offset;
+ u8 object_name[104];
+ __le32 host_buffer_descriptor_count;
+ struct sli4_bde host_buffer_descriptor[0];
+};
+
+enum sli4_rqst_set_dump_flags {
+ SLI4_CMN_SET_DUMP_BUFFER_LEN = 0xffffff,
+ SLI4_CMN_SET_DUMP_FDB = 0x20000000,
+ SLI4_CMN_SET_DUMP_BLP = 0x40000000,
+ SLI4_CMN_SET_DUMP_QRY = 0x80000000,
+};
+
+struct sli4_rqst_cmn_set_dump_location {
+ struct sli4_rqst_hdr hdr;
+ __le32 buffer_length_dword;
+ __le32 buf_addr_low;
+ __le32 buf_addr_high;
+};
+
+struct sli4_rsp_cmn_set_dump_location {
+ struct sli4_rsp_hdr hdr;
+ __le32 buffer_length_dword;
+};
+
+enum sli4_dump_level {
+ SLI4_DUMP_LEVEL_NONE,
+ SLI4_CHIP_LEVEL_DUMP,
+ SLI4_FUNC_DESC_DUMP,
+};
+
+enum sli4_dump_state {
+ SLI4_DUMP_STATE_NONE,
+ SLI4_CHIP_DUMP_STATE_VALID,
+ SLI4_FUNC_DUMP_STATE_VALID,
+};
+
+enum sli4_dump_status {
+ SLI4_DUMP_READY_STATUS_NOT_READY,
+ SLI4_DUMP_READY_STATUS_DD_PRESENT,
+ SLI4_DUMP_READY_STATUS_FDB_PRESENT,
+ SLI4_DUMP_READY_STATUS_SKIP_DUMP,
+ SLI4_DUMP_READY_STATUS_FAILED = -1,
+};
+
+enum sli4_set_features {
+ SLI4_SET_FEATURES_DIF_SEED = 0x01,
+ SLI4_SET_FEATURES_XRI_TIMER = 0x03,
+ SLI4_SET_FEATURES_MAX_PCIE_SPEED = 0x04,
+ SLI4_SET_FEATURES_FCTL_CHECK = 0x05,
+ SLI4_SET_FEATURES_FEC = 0x06,
+ SLI4_SET_FEATURES_PCIE_RECV_DETECT = 0x07,
+ SLI4_SET_FEATURES_DIF_MEMORY_MODE = 0x08,
+ SLI4_SET_FEATURES_DISABLE_SLI_PORT_PAUSE_STATE = 0x09,
+ SLI4_SET_FEATURES_ENABLE_PCIE_OPTIONS = 0x0a,
+ SLI4_SET_FEAT_CFG_AUTO_XFER_RDY_T10PI = 0x0c,
+ SLI4_SET_FEATURES_ENABLE_MULTI_RECEIVE_QUEUE = 0x0d,
+ SLI4_SET_FEATURES_SET_FTD_XFER_HINT = 0x0f,
+ SLI4_SET_FEATURES_SLI_PORT_HEALTH_CHECK = 0x11,
+};
+
+struct sli4_rqst_cmn_set_features {
+ struct sli4_rqst_hdr hdr;
+ __le32 feature;
+ __le32 param_len;
+ __le32 params[8];
+};
+
+struct sli4_rqst_cmn_set_features_dif_seed {
+ __le16 seed;
+ __le16 rsvd16;
+};
+
+enum sli4_rqst_set_mrq_features {
+ SLI4_RQ_MULTIRQ_ISR = 0x1,
+ SLI4_RQ_MULTIRQ_AUTOGEN_XFER_RDY = 0x2,
+
+ SLI4_RQ_MULTIRQ_NUM_RQS = 0xff,
+ SLI4_RQ_MULTIRQ_RQ_SELECT = 0xf00,
+};
+
+struct sli4_rqst_cmn_set_features_multirq {
+ __le32 auto_gen_xfer_dword;
+ __le32 num_rqs_dword;
+};
+
+enum sli4_rqst_health_check_flags {
+ SLI4_RQ_HEALTH_CHECK_ENABLE = 0x1,
+ SLI4_RQ_HEALTH_CHECK_QUERY = 0x2,
+};
+
+struct sli4_rqst_cmn_set_features_health_check {
+ __le32 health_check_dword;
+};
+
+struct sli4_rqst_cmn_set_features_set_fdt_xfer_hint {
+ __le32 fdt_xfer_hint;
+};
+
+struct sli4_rqst_dmtf_exec_clp_cmd {
+ struct sli4_rqst_hdr hdr;
+ __le32 cmd_buf_length;
+ __le32 resp_buf_length;
+ __le32 cmd_buf_addr_low;
+ __le32 cmd_buf_addr_high;
+ __le32 resp_buf_addr_low;
+ __le32 resp_buf_addr_high;
+};
+
+struct sli4_rsp_dmtf_exec_clp_cmd {
+ struct sli4_rsp_hdr hdr;
+ __le32 rsvd4;
+ __le32 resp_length;
+ __le32 rsvd6;
+ __le32 rsvd7;
+ __le32 rsvd8;
+ __le32 rsvd9;
+ __le32 clp_status;
+ __le32 clp_detailed_status;
+};
+
+#define SLI4_PROTOCOL_FC 0x10
+#define SLI4_PROTOCOL_DEFAULT 0xff
+
+struct sli4_rspource_descriptor_v1 {
+ u8 descriptor_type;
+ u8 descriptor_length;
+ __le16 rsvd16;
+ __le32 type_specific[0];
+};
+
+enum sli4_pcie_desc_flags {
+ SLI4_PCIE_DESC_IMM = 0x4000,
+ SLI4_PCIE_DESC_NOSV = 0x8000,
+
+ SLI4_PCIE_DESC_PF_NO = 0x3ff0000,
+
+ SLI4_PCIE_DESC_MISSN_ROLE = 0xff,
+ SLI4_PCIE_DESC_PCHG = 0x8000000,
+ SLI4_PCIE_DESC_SCHG = 0x10000000,
+ SLI4_PCIE_DESC_XCHG = 0x20000000,
+ SLI4_PCIE_DESC_XROM = 0xc0000000
+};
+
+struct sli4_pcie_resource_descriptor_v1 {
+ u8 descriptor_type;
+ u8 descriptor_length;
+ __le16 imm_nosv_dword;
+ __le32 pf_number_dword;
+ __le32 rsvd3;
+ u8 sriov_state;
+ u8 pf_state;
+ u8 pf_type;
+ u8 rsvd4;
+ __le16 number_of_vfs;
+ __le16 rsvd5;
+ __le32 mission_roles_dword;
+ __le32 rsvd7[16];
+};
+
+struct sli4_rqst_cmn_get_function_config {
+ struct sli4_rqst_hdr hdr;
+};
+
+struct sli4_rsp_cmn_get_function_config {
+ struct sli4_rsp_hdr hdr;
+ __le32 desc_count;
+ __le32 desc[54];
+};
+
+/* Link Config Descriptor for link config functions */
+struct sli4_link_config_descriptor {
+ u8 link_config_id;
+ u8 rsvd1[3];
+ __le32 config_description[8];
+};
+
+#define MAX_LINK_DES 10
+
+struct sli4_rqst_cmn_get_reconfig_link_info {
+ struct sli4_rqst_hdr hdr;
+};
+
+struct sli4_rsp_cmn_get_reconfig_link_info {
+ struct sli4_rsp_hdr hdr;
+ u8 active_link_config_id;
+ u8 rsvd17;
+ u8 next_link_config_id;
+ u8 rsvd19;
+ __le32 link_configuration_descriptor_count;
+ struct sli4_link_config_descriptor
+ desc[MAX_LINK_DES];
+};
+
+enum sli4_set_reconfig_link_flags {
+ SLI4_SET_RECONFIG_LINKID_NEXT = 0xff,
+ SLI4_SET_RECONFIG_LINKID_FD = 1u << 31,
+};
+
+struct sli4_rqst_cmn_set_reconfig_link_id {
+ struct sli4_rqst_hdr hdr;
+ __le32 dw4_flags;
+};
+
+struct sli4_rsp_cmn_set_reconfig_link_id {
+ struct sli4_rsp_hdr hdr;
+};
+
+struct sli4_rqst_lowlevel_set_watchdog {
+ struct sli4_rqst_hdr hdr;
+ __le16 watchdog_timeout;
+ __le16 rsvd18;
+};
+
+struct sli4_rsp_lowlevel_set_watchdog {
+ struct sli4_rsp_hdr hdr;
+ __le32 rsvd;
+};
+
+/* FC opcode (OPC) values */
+enum sli4_fc_opcodes {
+ SLI4_OPC_WQ_CREATE = 0x1,
+ SLI4_OPC_WQ_DESTROY = 0x2,
+ SLI4_OPC_POST_SGL_PAGES = 0x3,
+ SLI4_OPC_RQ_CREATE = 0x5,
+ SLI4_OPC_RQ_DESTROY = 0x6,
+ SLI4_OPC_READ_FCF_TABLE = 0x8,
+ SLI4_OPC_POST_HDR_TEMPLATES = 0xb,
+ SLI4_OPC_REDISCOVER_FCF = 0x10,
+};
+
+/* Use the default CQ associated with the WQ */
+#define SLI4_CQ_DEFAULT 0xffff
+
+/*
+ * POST_SGL_PAGES
+ *
+ * Register the scatter gather list (SGL) memory and
+ * associate it with an XRI.
+ */
+struct sli4_rqst_post_sgl_pages {
+ struct sli4_rqst_hdr hdr;
+ __le16 xri_start;
+ __le16 xri_count;
+ struct {
+ __le32 page0_low;
+ __le32 page0_high;
+ __le32 page1_low;
+ __le32 page1_high;
+ } page_set[10];
+};
+
+struct sli4_rsp_post_sgl_pages {
+ struct sli4_rsp_hdr hdr;
+};
+
+struct sli4_rqst_post_hdr_templates {
+ struct sli4_rqst_hdr hdr;
+ __le16 rpi_offset;
+ __le16 page_count;
+ struct sli4_dmaaddr page_descriptor[0];
+};
+
+#define SLI4_HDR_TEMPLATE_SIZE 64
+
+enum sli4_io_flags {
+/* The XRI associated with this IO is already active */
+ SLI4_IO_CONTINUATION = 1 << 0,
+/* Automatically generate a good RSP frame */
+ SLI4_IO_AUTO_GOOD_RESPONSE = 1 << 1,
+ SLI4_IO_NO_ABORT = 1 << 2,
+/* Set the DNRX bit because no auto xref rdy buffer is posted */
+ SLI4_IO_DNRX = 1 << 3,
+};
+
+enum sli4_callback {
+ SLI4_CB_LINK,
+ SLI4_CB_MAX,
+};
+
+enum sli4_link_status {
+ SLI4_LINK_STATUS_UP,
+ SLI4_LINK_STATUS_DOWN,
+ SLI4_LINK_STATUS_NO_ALPA,
+ SLI4_LINK_STATUS_MAX,
+};
+
+enum sli4_link_topology {
+ SLI4_LINK_TOPO_NON_FC_AL = 1,
+ SLI4_LINK_TOPO_FC_AL,
+ SLI4_LINK_TOPO_LOOPBACK_INTERNAL,
+ SLI4_LINK_TOPO_LOOPBACK_EXTERNAL,
+ SLI4_LINK_TOPO_NONE,
+ SLI4_LINK_TOPO_MAX,
+};
+
+enum sli4_link_medium {
+ SLI4_LINK_MEDIUM_ETHERNET,
+ SLI4_LINK_MEDIUM_FC,
+ SLI4_LINK_MEDIUM_MAX,
+};
+/******Driver specific structures******/
+
+struct sli4_queue {
+ /* Common to all queue types */
+ struct efc_dma dma;
+ spinlock_t lock; /* Lock to protect the doorbell register
+ * writes and queue reads
+ */
+ u32 index; /* current host entry index */
+ u16 size; /* entry size */
+ u16 length; /* number of entries */
+ u16 n_posted; /* number entries posted for CQ, EQ */
+ u16 id; /* Port assigned xQ_ID */
+ u8 type; /* queue type ie EQ, CQ, ... */
+ void __iomem *db_regaddr; /* register address for the doorbell */
+ u16 phase; /* For if_type = 6, this value toggle
+ * for each iteration of the queue,
+ * a queue entry is valid when a cqe
+ * valid bit matches this value
+ */
+ u32 proc_limit; /* limit CQE processed per iteration */
+ u32 posted_limit; /* CQE/EQE process before ring db */
+ u32 max_num_processed;
+ u64 max_process_time;
+ union {
+ u32 r_idx; /* "read" index (MQ only) */
+ u32 flag;
+ } u;
+};
+
+/* Parameters used to populate WQE*/
+struct sli_bls_params {
+ u32 s_id;
+ u32 d_id;
+ u16 ox_id;
+ u16 rx_id;
+ u32 rpi;
+ u32 vpi;
+ bool rpi_registered;
+ u8 payload[12];
+ u16 xri;
+ u16 tag;
+};
+
+struct sli_els_params {
+ u32 s_id;
+ u32 d_id;
+ u16 ox_id;
+ u32 rpi;
+ u32 vpi;
+ bool rpi_registered;
+ u32 xmit_len;
+ u32 rsp_len;
+ u8 timeout;
+ u8 cmd;
+ u16 xri;
+ u16 tag;
+};
+
+struct sli_ct_params {
+ u8 r_ctl;
+ u8 type;
+ u8 df_ctl;
+ u8 timeout;
+ u16 ox_id;
+ u32 d_id;
+ u32 rpi;
+ u32 vpi;
+ bool rpi_registered;
+ u32 xmit_len;
+ u32 rsp_len;
+ u16 xri;
+ u16 tag;
+};
+
+struct sli_fcp_tgt_params {
+ u32 s_id;
+ u32 d_id;
+ u32 rpi;
+ u32 vpi;
+ u32 offset;
+ u16 ox_id;
+ u16 flags;
+ u8 cs_ctl;
+ u8 timeout;
+ u32 app_id;
+ u32 xmit_len;
+ u16 xri;
+ u16 tag;
+};
+
+struct sli4_link_event {
+ enum sli4_link_status status;
+ enum sli4_link_topology topology;
+ enum sli4_link_medium medium;
+ u32 speed;
+ u8 *loop_map;
+ u32 fc_id;
+};
+
+enum sli4_resource {
+ SLI4_RSRC_VFI,
+ SLI4_RSRC_VPI,
+ SLI4_RSRC_RPI,
+ SLI4_RSRC_XRI,
+ SLI4_RSRC_FCFI,
+ SLI4_RSRC_MAX,
+};
+
+struct sli4_extent {
+ u32 number;
+ u32 size;
+ u32 n_alloc;
+ u32 *base;
+ unsigned long *use_map;
+ u32 map_size;
+};
+
+struct sli4_queue_info {
+ u16 max_qcount[SLI4_QTYPE_MAX];
+ u32 max_qentries[SLI4_QTYPE_MAX];
+ u16 count_mask[SLI4_QTYPE_MAX];
+ u16 count_method[SLI4_QTYPE_MAX];
+ u32 qpage_count[SLI4_QTYPE_MAX];
+};
+
+struct sli4_params {
+ u8 has_extents;
+ u8 auto_reg;
+ u8 auto_xfer_rdy;
+ u8 hdr_template_req;
+ u8 perf_hint;
+ u8 perf_wq_id_association;
+ u8 cq_create_version;
+ u8 mq_create_version;
+ u8 high_login_mode;
+ u8 sgl_pre_registered;
+ u8 sgl_pre_reg_required;
+ u8 t10_dif_inline_capable;
+ u8 t10_dif_separate_capable;
+};
+
+struct sli4 {
+ void *os;
+ struct pci_dev *pci;
+ void __iomem *reg[PCI_STD_NUM_BARS];
+
+ u32 sli_rev;
+ u32 sli_family;
+ u32 if_type;
+
+ u16 asic_type;
+ u16 asic_rev;
+
+ u16 e_d_tov;
+ u16 r_a_tov;
+ struct sli4_queue_info qinfo;
+ u16 link_module_type;
+ u8 rq_batch;
+ u8 port_number;
+ char port_name[2];
+ u16 rq_min_buf_size;
+ u32 rq_max_buf_size;
+ u8 topology;
+ u8 wwpn[8];
+ u8 wwnn[8];
+ u32 fw_rev[2];
+ u8 fw_name[2][16];
+ char ipl_name[16];
+ u32 hw_rev[3];
+ char modeldesc[64];
+ char bios_version_string[32];
+ u32 wqe_size;
+ u32 vpd_length;
+ /*
+ * Tracks the port resources using extents metaphor. For
+ * devices that don't implement extents (i.e.
+ * has_extents == FALSE), the code models each resource as
+ * a single large extent.
+ */
+ struct sli4_extent ext[SLI4_RSRC_MAX];
+ u32 features;
+ struct sli4_params params;
+ u32 sge_supported_length;
+ u32 sgl_page_sizes;
+ u32 max_sgl_pages;
+
+ /*
+ * Callback functions
+ */
+ int (*link)(void *ctx, void *event);
+ void *link_arg;
+
+ struct efc_dma bmbx;
+
+ /* Save pointer to physical memory descriptor for non-embedded
+ * SLI_CONFIG commands for BMBX dumping purposes
+ */
+ struct efc_dma *bmbx_non_emb_pmd;
+
+ struct efc_dma vpd_data;
+};
+
+static inline void
+sli_cmd_fill_hdr(struct sli4_rqst_hdr *hdr, u8 opc, u8 sub, u32 ver, __le32 len)
+{
+ hdr->opcode = opc;
+ hdr->subsystem = sub;
+ hdr->dw3_version = cpu_to_le32(ver);
+ hdr->request_length = len;
+}
+
+/**
+ * Get / set parameter functions
+ */
+
+static inline u32
+sli_get_max_sge(struct sli4 *sli4)
+{
+ return sli4->sge_supported_length;
+}
+
+static inline u32
+sli_get_max_sgl(struct sli4 *sli4)
+{
+ if (sli4->sgl_page_sizes != 1) {
+ efc_log_err(sli4, "unsupported SGL page sizes %#x\n",
+ sli4->sgl_page_sizes);
+ return 0;
+ }
+
+ return (sli4->max_sgl_pages * SLI_PAGE_SIZE) / sizeof(struct sli4_sge);
+}
+
+static inline enum sli4_link_medium
+sli_get_medium(struct sli4 *sli4)
+{
+ switch (sli4->topology) {
+ case SLI4_READ_CFG_TOPO_FC:
+ case SLI4_READ_CFG_TOPO_FC_AL:
+ case SLI4_READ_CFG_TOPO_NON_FC_AL:
+ return SLI4_LINK_MEDIUM_FC;
+ default:
+ return SLI4_LINK_MEDIUM_MAX;
+ }
+}
+
+static inline u32
+sli_get_lmt(struct sli4 *sli4)
+{
+ return sli4->link_module_type;
+}
+
+static inline int
+sli_set_topology(struct sli4 *sli4, u32 value)
+{
+ int rc = 0;
+
+ switch (value) {
+ case SLI4_READ_CFG_TOPO_FC:
+ case SLI4_READ_CFG_TOPO_FC_AL:
+ case SLI4_READ_CFG_TOPO_NON_FC_AL:
+ sli4->topology = value;
+ break;
+ default:
+ efc_log_err(sli4, "unsupported topology %#x\n", value);
+ rc = -1;
+ }
+
+ return rc;
+}
+
+static inline u32
+sli_convert_mask_to_count(u32 method, u32 mask)
+{
+ u32 count = 0;
+
+ if (method) {
+ count = 1 << (31 - __builtin_clz(mask));
+ count *= 16;
+ } else {
+ count = mask;
+ }
+
+ return count;
+}
+
+static inline u32
+sli_reg_read_status(struct sli4 *sli)
+{
+ return readl(sli->reg[0] + SLI4_PORT_STATUS_REGOFF);
+}
+
+static inline int
+sli_fw_error_status(struct sli4 *sli4)
+{
+ return (sli_reg_read_status(sli4) & SLI4_PORT_STATUS_ERR) ? 1 : 0;
+}
+
+static inline u32
+sli_reg_read_err1(struct sli4 *sli)
+{
+ return readl(sli->reg[0] + SLI4_PORT_ERROR1);
+}
+
+static inline u32
+sli_reg_read_err2(struct sli4 *sli)
+{
+ return readl(sli->reg[0] + SLI4_PORT_ERROR2);
+}
+
+static inline int
+sli_fc_rqe_length(struct sli4 *sli4, void *cqe, u32 *len_hdr,
+ u32 *len_data)
+{
+ struct sli4_fc_async_rcqe *rcqe = cqe;
+
+ *len_hdr = *len_data = 0;
+
+ if (rcqe->status == SLI4_FC_ASYNC_RQ_SUCCESS) {
+ *len_hdr = rcqe->hdpl_byte & SLI4_RACQE_HDPL;
+ *len_data = le16_to_cpu(rcqe->data_placement_length);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+static inline u8
+sli_fc_rqe_fcfi(struct sli4 *sli4, void *cqe)
+{
+ u8 code = ((u8 *)cqe)[SLI4_CQE_CODE_OFFSET];
+ u8 fcfi = U8_MAX;
+
+ switch (code) {
+ case SLI4_CQE_CODE_RQ_ASYNC: {
+ struct sli4_fc_async_rcqe *rcqe = cqe;
+
+ fcfi = le16_to_cpu(rcqe->fcfi_rq_id_word) & SLI4_RACQE_FCFI;
+ break;
+ }
+ case SLI4_CQE_CODE_RQ_ASYNC_V1: {
+ struct sli4_fc_async_rcqe_v1 *rcqev1 = cqe;
+
+ fcfi = rcqev1->fcfi_byte & SLI4_RACQE_FCFI;
+ break;
+ }
+ case SLI4_CQE_CODE_OPTIMIZED_WRITE_CMD: {
+ struct sli4_fc_optimized_write_cmd_cqe *opt_wr = cqe;
+
+ fcfi = opt_wr->flags0 & SLI4_OCQE_FCFI;
+ break;
+ }
+ }
+
+ return fcfi;
+}
+
+/****************************************************************************
+ * Function prototypes
+ */
+int
+sli_cmd_config_link(struct sli4 *sli4, void *buf);
+int
+sli_cmd_down_link(struct sli4 *sli4, void *buf);
+int
+sli_cmd_dump_type4(struct sli4 *sli4, void *buf, u16 wki);
+int
+sli_cmd_common_read_transceiver_data(struct sli4 *sli4, void *buf,
+ u32 page_num, struct efc_dma *dma);
+int
+sli_cmd_read_link_stats(struct sli4 *sli4, void *buf, u8 req_stats,
+ u8 clear_overflow_flags, u8 clear_all_counters);
+int
+sli_cmd_read_status(struct sli4 *sli4, void *buf, u8 clear);
+int
+sli_cmd_init_link(struct sli4 *sli4, void *buf, u32 speed,
+ u8 reset_alpa);
+int
+sli_cmd_init_vfi(struct sli4 *sli4, void *buf, u16 vfi, u16 fcfi,
+ u16 vpi);
+int
+sli_cmd_init_vpi(struct sli4 *sli4, void *buf, u16 vpi, u16 vfi);
+int
+sli_cmd_post_xri(struct sli4 *sli4, void *buf, u16 base, u16 cnt);
+int
+sli_cmd_release_xri(struct sli4 *sli4, void *buf, u8 num_xri);
+int
+sli_cmd_read_sparm64(struct sli4 *sli4, void *buf,
+ struct efc_dma *dma, u16 vpi);
+int
+sli_cmd_read_topology(struct sli4 *sli4, void *buf, struct efc_dma *dma);
+int
+sli_cmd_read_nvparms(struct sli4 *sli4, void *buf);
+int
+sli_cmd_write_nvparms(struct sli4 *sli4, void *buf, u8 *wwpn,
+ u8 *wwnn, u8 hard_alpa, u32 preferred_d_id);
+int
+sli_cmd_reg_fcfi(struct sli4 *sli4, void *buf, u16 index,
+ struct sli4_cmd_rq_cfg *rq_cfg);
+int
+sli_cmd_reg_fcfi_mrq(struct sli4 *sli4, void *buf, u8 mode, u16 index,
+ u8 rq_selection_policy, u8 mrq_bit_mask, u16 num_mrqs,
+ struct sli4_cmd_rq_cfg *rq_cfg);
+int
+sli_cmd_reg_rpi(struct sli4 *sli4, void *buf, u32 rpi, u32 vpi, u32 fc_id,
+ struct efc_dma *dma, u8 update, u8 enable_t10_pi);
+int
+sli_cmd_unreg_fcfi(struct sli4 *sli4, void *buf, u16 indicator);
+int
+sli_cmd_unreg_rpi(struct sli4 *sli4, void *buf, u16 indicator,
+ enum sli4_resource which, u32 fc_id);
+int
+sli_cmd_reg_vpi(struct sli4 *sli4, void *buf, u32 fc_id,
+ __be64 sli_wwpn, u16 vpi, u16 vfi, bool update);
+int
+sli_cmd_reg_vfi(struct sli4 *sli4, void *buf, size_t size,
+ u16 vfi, u16 fcfi, struct efc_dma dma,
+ u16 vpi, __be64 sli_wwpn, u32 fc_id);
+int
+sli_cmd_unreg_vpi(struct sli4 *sli4, void *buf, u16 id, u32 type);
+int
+sli_cmd_unreg_vfi(struct sli4 *sli4, void *buf, u16 idx, u32 type);
+int
+sli_cmd_common_nop(struct sli4 *sli4, void *buf, uint64_t context);
+int
+sli_cmd_common_get_resource_extent_info(struct sli4 *sli4, void *buf,
+ u16 rtype);
+int
+sli_cmd_common_get_sli4_parameters(struct sli4 *sli4, void *buf);
+int
+sli_cmd_common_write_object(struct sli4 *sli4, void *buf, u16 noc,
+ u16 eof, u32 len, u32 offset, char *name, struct efc_dma *dma);
+int
+sli_cmd_common_delete_object(struct sli4 *sli4, void *buf, char *object_name);
+int
+sli_cmd_common_read_object(struct sli4 *sli4, void *buf,
+ u32 length, u32 offset, char *name, struct efc_dma *dma);
+int
+sli_cmd_dmtf_exec_clp_cmd(struct sli4 *sli4, void *buf,
+ struct efc_dma *cmd, struct efc_dma *resp);
+int
+sli_cmd_common_set_dump_location(struct sli4 *sli4, void *buf,
+ bool query, bool is_buffer_list, struct efc_dma *dma, u8 fdb);
+int
+sli_cmd_common_set_features(struct sli4 *sli4, void *buf,
+ u32 feature, u32 param_len, void *parameter);
+
+int sli_cqe_mq(struct sli4 *sli4, void *buf);
+int sli_cqe_async(struct sli4 *sli4, void *buf);
+
+int
+sli_setup(struct sli4 *sli4, void *os, struct pci_dev *pdev, void __iomem *r[]);
+void sli_calc_max_qentries(struct sli4 *sli4);
+int sli_init(struct sli4 *sli4);
+int sli_reset(struct sli4 *sli4);
+int sli_fw_reset(struct sli4 *sli4);
+void sli_teardown(struct sli4 *sli4);
+int
+sli_callback(struct sli4 *sli4, enum sli4_callback cb, void *func, void *arg);
+int
+sli_bmbx_command(struct sli4 *sli4);
+int
+__sli_queue_init(struct sli4 *sli4, struct sli4_queue *q, u32 qtype,
+ size_t size, u32 n_entries, u32 align);
+int
+__sli_create_queue(struct sli4 *sli4, struct sli4_queue *q);
+int
+sli_eq_modify_delay(struct sli4 *sli4, struct sli4_queue *eq, u32 num_eq,
+ u32 shift, u32 delay_mult);
+int
+sli_queue_alloc(struct sli4 *sli4, u32 qtype, struct sli4_queue *q,
+ u32 n_entries, struct sli4_queue *assoc);
+int
+sli_cq_alloc_set(struct sli4 *sli4, struct sli4_queue *qs[], u32 num_cqs,
+ u32 n_entries, struct sli4_queue *eqs[]);
+int
+sli_get_queue_entry_size(struct sli4 *sli4, u32 qtype);
+int
+sli_queue_free(struct sli4 *sli4, struct sli4_queue *q, u32 destroy_queues,
+ u32 free_memory);
+int
+sli_queue_eq_arm(struct sli4 *sli4, struct sli4_queue *q, bool arm);
+int
+sli_queue_arm(struct sli4 *sli4, struct sli4_queue *q, bool arm);
+
+int
+sli_wq_write(struct sli4 *sli4, struct sli4_queue *q, u8 *entry);
+int
+sli_mq_write(struct sli4 *sli4, struct sli4_queue *q, u8 *entry);
+int
+sli_rq_write(struct sli4 *sli4, struct sli4_queue *q, u8 *entry);
+int
+sli_eq_read(struct sli4 *sli4, struct sli4_queue *q, u8 *entry);
+int
+sli_cq_read(struct sli4 *sli4, struct sli4_queue *q, u8 *entry);
+int
+sli_mq_read(struct sli4 *sli4, struct sli4_queue *q, u8 *entry);
+int
+sli_resource_alloc(struct sli4 *sli4, enum sli4_resource rtype, u32 *rid,
+ u32 *index);
+int
+sli_resource_free(struct sli4 *sli4, enum sli4_resource rtype, u32 rid);
+int
+sli_resource_reset(struct sli4 *sli4, enum sli4_resource rtype);
+int
+sli_eq_parse(struct sli4 *sli4, u8 *buf, u16 *cq_id);
+int
+sli_cq_parse(struct sli4 *sli4, struct sli4_queue *cq, u8 *cqe,
+ enum sli4_qentry *etype, u16 *q_id);
+
+int sli_raise_ue(struct sli4 *sli4, u8 dump);
+int sli_dump_is_ready(struct sli4 *sli4);
+bool sli_reset_required(struct sli4 *sli4);
+bool sli_fw_ready(struct sli4 *sli4);
+
+int
+sli_fc_process_link_attention(struct sli4 *sli4, void *acqe);
+int
+sli_fc_cqe_parse(struct sli4 *sli4, struct sli4_queue *cq,
+ u8 *cqe, enum sli4_qentry *etype,
+ u16 *rid);
+u32 sli_fc_response_length(struct sli4 *sli4, u8 *cqe);
+u32 sli_fc_io_length(struct sli4 *sli4, u8 *cqe);
+int sli_fc_els_did(struct sli4 *sli4, u8 *cqe, u32 *d_id);
+u32 sli_fc_ext_status(struct sli4 *sli4, u8 *cqe);
+int
+sli_fc_rqe_rqid_and_index(struct sli4 *sli4, u8 *cqe, u16 *rq_id, u32 *index);
+int
+sli_cmd_wq_create(struct sli4 *sli4, void *buf,
+ struct efc_dma *qmem, u16 cq_id);
+int sli_cmd_post_sgl_pages(struct sli4 *sli4, void *buf, u16 xri,
+ u32 xri_count, struct efc_dma *page0[], struct efc_dma *page1[],
+ struct efc_dma *dma);
+int
+sli_cmd_post_hdr_templates(struct sli4 *sli4, void *buf,
+ struct efc_dma *dma, u16 rpi, struct efc_dma *payload_dma);
+int
+sli_fc_rq_alloc(struct sli4 *sli4, struct sli4_queue *q, u32 n_entries,
+ u32 buffer_size, struct sli4_queue *cq, bool is_hdr);
+int
+sli_fc_rq_set_alloc(struct sli4 *sli4, u32 num_rq_pairs, struct sli4_queue *q[],
+ u32 base_cq_id, u32 num, u32 hdr_buf_size, u32 data_buf_size);
+u32 sli_fc_get_rpi_requirements(struct sli4 *sli4, u32 n_rpi);
+int
+sli_abort_wqe(struct sli4 *sli4, void *buf, enum sli4_abort_type type,
+ bool send_abts, u32 ids, u32 mask, u16 tag, u16 cq_id);
+
+int
+sli_send_frame_wqe(struct sli4 *sli4, void *buf, u8 sof, u8 eof,
+ u32 *hdr, struct efc_dma *payload, u32 req_len, u8 timeout,
+ u16 xri, u16 req_tag);
+
+int
+sli_xmit_els_rsp64_wqe(struct sli4 *sli4, void *buf, struct efc_dma *rsp,
+ struct sli_els_params *params);
+
+int
+sli_els_request64_wqe(struct sli4 *sli4, void *buf, struct efc_dma *sgl,
+ struct sli_els_params *params);
+
+int
+sli_fcp_icmnd64_wqe(struct sli4 *sli4, void *buf, struct efc_dma *sgl, u16 xri,
+ u16 tag, u16 cq_id, u32 rpi, u32 rnode_fcid, u8 timeout);
+
+int
+sli_fcp_iread64_wqe(struct sli4 *sli4, void *buf, struct efc_dma *sgl,
+ u32 first_data_sge, u32 xfer_len, u16 xri,
+ u16 tag, u16 cq_id, u32 rpi, u32 rnode_fcid, u8 dif, u8 bs,
+ u8 timeout);
+
+int
+sli_fcp_iwrite64_wqe(struct sli4 *sli4, void *buf, struct efc_dma *sgl,
+ u32 first_data_sge, u32 xfer_len,
+ u32 first_burst, u16 xri, u16 tag, u16 cq_id, u32 rpi,
+ u32 rnode_fcid, u8 dif, u8 bs, u8 timeout);
+
+int
+sli_fcp_treceive64_wqe(struct sli4 *sli, void *buf, struct efc_dma *sgl,
+ u32 first_data_sge, u16 cq_id, u8 dif, u8 bs,
+ struct sli_fcp_tgt_params *params);
+int
+sli_fcp_cont_treceive64_wqe(struct sli4 *sli, void *buf, struct efc_dma *sgl,
+ u32 first_data_sge, u16 sec_xri, u16 cq_id, u8 dif,
+ u8 bs, struct sli_fcp_tgt_params *params);
+
+int
+sli_fcp_trsp64_wqe(struct sli4 *sli4, void *buf, struct efc_dma *sgl,
+ u16 cq_id, u8 port_owned, struct sli_fcp_tgt_params *params);
+
+int
+sli_fcp_tsend64_wqe(struct sli4 *sli4, void *buf, struct efc_dma *sgl,
+ u32 first_data_sge, u16 cq_id, u8 dif, u8 bs,
+ struct sli_fcp_tgt_params *params);
+int
+sli_gen_request64_wqe(struct sli4 *sli4, void *buf, struct efc_dma *sgl,
+ struct sli_ct_params *params);
+
+int
+sli_xmit_bls_rsp64_wqe(struct sli4 *sli4, void *buf,
+ struct sli_bls_payload *payload, struct sli_bls_params *params);
+
+int
+sli_xmit_sequence64_wqe(struct sli4 *sli4, void *buf, struct efc_dma *payload,
+ struct sli_ct_params *params);
+
+int
+sli_requeue_xri_wqe(struct sli4 *sli4, void *buf, u16 xri, u16 tag, u16 cq_id);
+void
+sli4_cmd_lowlevel_set_watchdog(struct sli4 *sli4, void *buf, size_t size,
+ u16 timeout);
+
+const char *sli_fc_get_status_string(u32 status);
+
+#endif /* !_SLI4_H */
diff --git a/drivers/scsi/esas2r/atioctl.h b/drivers/scsi/esas2r/atioctl.h
index 4aca3d52c851..ff2ad9b38575 100644
--- a/drivers/scsi/esas2r/atioctl.h
+++ b/drivers/scsi/esas2r/atioctl.h
@@ -1141,7 +1141,7 @@ struct __packed atto_ioctl_vda_gsv_cmd {
u8 rsp_len;
u8 reserved[7];
- u8 version_info[1];
+ u8 version_info[];
#define ATTO_VDA_VER_UNSUPPORTED 0xFF
};
diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c
index 45ec9f16c085..647f82898b6e 100644
--- a/drivers/scsi/esas2r/esas2r_main.c
+++ b/drivers/scsi/esas2r/esas2r_main.c
@@ -1525,7 +1525,7 @@ void esas2r_complete_request_cb(struct esas2r_adapter *a,
rq->cmd->result =
((esas2r_req_status_to_error(rq->req_stat) << 16)
- | (rq->func_rsp.scsi_rsp.scsi_stat & STATUS_MASK));
+ | rq->func_rsp.scsi_rsp.scsi_stat);
if (rq->req_stat == RS_UNDERRUN)
scsi_set_resid(rq->cmd,
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 342535ac0570..9a8c037a2f21 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -922,9 +922,7 @@ static void esp_cmd_is_done(struct esp *esp, struct esp_cmd_entry *ent,
* saw originally. Also, report that we are providing
* the sense data.
*/
- cmd->result = ((DRIVER_SENSE << 24) |
- (DID_OK << 16) |
- (SAM_STAT_CHECK_CONDITION << 0));
+ cmd->result = SAM_STAT_CHECK_CONDITION;
ent->flags &= ~ESP_CMD_FLAG_AUTOSENSE;
if (esp_debug & ESP_DEBUG_AUTOSENSE) {
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 89ec735929c3..5ae6c207d3ac 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -293,7 +293,7 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe);
struct netdev_hw_addr *ha;
struct net_device *real_dev;
- u8 flogi_maddr[ETH_ALEN];
+ static const u8 flogi_maddr[ETH_ALEN] = FC_FCOE_FLOGI_MAC;
const struct net_device_ops *ops;
fcoe->netdev = netdev;
@@ -336,7 +336,6 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
* or enter promiscuous mode if not capable of listening
* for multiple unicast MACs.
*/
- memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
dev_uc_add(netdev, flogi_maddr);
if (fip->spma)
dev_uc_add(netdev, fip->ctl_src_addr);
@@ -442,7 +441,7 @@ static void fcoe_interface_remove(struct fcoe_interface *fcoe)
{
struct net_device *netdev = fcoe->netdev;
struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe);
- u8 flogi_maddr[ETH_ALEN];
+ static const u8 flogi_maddr[ETH_ALEN] = FC_FCOE_FLOGI_MAC;
const struct net_device_ops *ops;
/*
@@ -458,7 +457,6 @@ static void fcoe_interface_remove(struct fcoe_interface *fcoe)
synchronize_net();
/* Delete secondary MAC addresses */
- memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
dev_uc_del(netdev, flogi_maddr);
if (fip->spma)
dev_uc_del(netdev, fip->ctl_src_addr);
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index 772bdc93930a..eda2be534aa7 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -202,11 +202,10 @@ static int fdomain_select(struct Scsi_Host *sh, int target)
return 1;
}
-static void fdomain_finish_cmd(struct fdomain *fd, int result)
+static void fdomain_finish_cmd(struct fdomain *fd)
{
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;
}
@@ -273,7 +272,8 @@ static void fdomain_work(struct work_struct *work)
if (cmd->SCp.phase & in_arbitration) {
status = inb(fd->base + REG_ASTAT);
if (!(status & ASTAT_ARB)) {
- fdomain_finish_cmd(fd, DID_BUS_BUSY << 16);
+ set_host_byte(cmd, DID_BUS_BUSY);
+ fdomain_finish_cmd(fd);
goto out;
}
cmd->SCp.phase = in_selection;
@@ -290,7 +290,8 @@ static void fdomain_work(struct work_struct *work)
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);
+ set_host_byte(cmd, DID_NO_CONNECT);
+ fdomain_finish_cmd(fd);
goto out;
}
/* Stop arbitration and enable parity */
@@ -333,7 +334,7 @@ static void fdomain_work(struct work_struct *work)
break;
case BSTAT_MSG | BSTAT_CMD | BSTAT_IO: /* MESSAGE IN */
cmd->SCp.Message = inb(fd->base + REG_SCSI_DATA);
- if (!cmd->SCp.Message)
+ if (cmd->SCp.Message == COMMAND_COMPLETE)
++done;
break;
}
@@ -359,9 +360,10 @@ static void fdomain_work(struct work_struct *work)
fdomain_read_data(cmd);
if (done) {
- fdomain_finish_cmd(fd, (cmd->SCp.Status & 0xff) |
- ((cmd->SCp.Message & 0xff) << 8) |
- (DID_OK << 16));
+ set_status_byte(cmd, cmd->SCp.Status);
+ set_host_byte(cmd, DID_OK);
+ scsi_msg_to_host_byte(cmd, cmd->SCp.Message);
+ fdomain_finish_cmd(fd);
} else {
if (cmd->SCp.phase & disconnect) {
outb(ICTL_FIFO | ICTL_SEL | ICTL_REQ | FIFO_COUNT,
@@ -439,10 +441,10 @@ static int fdomain_abort(struct scsi_cmnd *cmd)
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);
+ set_host_byte(fd->cur_cmd, DID_ABORT);
+ fdomain_finish_cmd(fd);
spin_unlock_irqrestore(sh->host_lock, flags);
return SUCCESS;
}
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index cf879cc59e4c..436d174f2194 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -8,6 +8,7 @@
#define _HISI_SAS_H_
#include <linux/acpi.h>
+#include <linux/async.h>
#include <linux/blk-mq.h>
#include <linux/blk-mq-pci.h>
#include <linux/clk.h>
@@ -37,6 +38,7 @@
#define HISI_SAS_RESET_BIT 0
#define HISI_SAS_REJECT_CMD_BIT 1
#define HISI_SAS_PM_BIT 2
+#define HISI_SAS_HW_FAULT_BIT 3
#define HISI_SAS_MAX_COMMANDS (HISI_SAS_QUEUE_SLOTS)
#define HISI_SAS_RESERVED_IPTT 96
#define HISI_SAS_UNRESERVED_IPTT \
@@ -90,8 +92,8 @@
#define HISI_SAS_PROT_MASK (HISI_SAS_DIF_PROT_MASK | HISI_SAS_DIX_PROT_MASK)
-#define HISI_SAS_WAIT_PHYUP_TIMEOUT 20
-#define CLEAR_ITCT_TIMEOUT 20
+#define HISI_SAS_WAIT_PHYUP_TIMEOUT (20 * HZ)
+#define HISI_SAS_CLEAR_ITCT_TIMEOUT (20 * HZ)
struct hisi_hba;
@@ -185,6 +187,7 @@ struct hisi_sas_phy {
enum sas_linkrate minimum_linkrate;
enum sas_linkrate maximum_linkrate;
int enable;
+ int wait_phyup_cnt;
atomic_t down_cnt;
/* Trace FIFO */
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 5a204074099c..3a903e8e0384 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -15,7 +15,7 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
static int
hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
struct domain_device *device,
- int abort_flag, int tag);
+ int abort_flag, int tag, bool rst_to_recover);
static int hisi_sas_softreset_ata_disk(struct domain_device *device);
static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
void *funcdata);
@@ -857,6 +857,7 @@ static void hisi_sas_phyup_work(struct work_struct *work)
struct asd_sas_phy *sas_phy = &phy->sas_phy;
int phy_no = sas_phy->id;
+ phy->wait_phyup_cnt = 0;
if (phy->identify.target_port_protocols == SAS_PROTOCOL_SSP)
hisi_hba->hw->sl_notify_ssp(hisi_hba, phy_no);
hisi_sas_bytes_dmaed(hisi_hba, phy_no, GFP_KERNEL);
@@ -899,6 +900,8 @@ static void hisi_sas_wait_phyup_timedout(struct timer_list *t)
hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET);
}
+#define HISI_SAS_WAIT_PHYUP_RETRIES 10
+
void hisi_sas_phy_oob_ready(struct hisi_hba *hisi_hba, int phy_no)
{
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
@@ -909,8 +912,16 @@ void hisi_sas_phy_oob_ready(struct hisi_hba *hisi_hba, int phy_no)
return;
if (!timer_pending(&phy->timer)) {
- phy->timer.expires = jiffies + HISI_SAS_WAIT_PHYUP_TIMEOUT * HZ;
- add_timer(&phy->timer);
+ if (phy->wait_phyup_cnt < HISI_SAS_WAIT_PHYUP_RETRIES) {
+ phy->wait_phyup_cnt++;
+ phy->timer.expires = jiffies +
+ HISI_SAS_WAIT_PHYUP_TIMEOUT;
+ add_timer(&phy->timer);
+ } else {
+ dev_warn(dev, "phy%d failed to come up %d times, giving up\n",
+ phy_no, phy->wait_phyup_cnt);
+ phy->wait_phyup_cnt = 0;
+ }
}
}
EXPORT_SYMBOL_GPL(hisi_sas_phy_oob_ready);
@@ -1063,7 +1074,7 @@ static void hisi_sas_dev_gone(struct domain_device *device)
down(&hisi_hba->sem);
if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
hisi_sas_internal_task_abort(hisi_hba, device,
- HISI_SAS_INT_ABT_DEV, 0);
+ HISI_SAS_INT_ABT_DEV, 0, true);
hisi_sas_dereg_device(hisi_hba, device);
@@ -1182,9 +1193,9 @@ static void hisi_sas_tmf_timedout(struct timer_list *t)
complete(&task->slow_task->completion);
}
-#define TASK_TIMEOUT 20
-#define TASK_RETRY 3
-#define INTERNAL_ABORT_TIMEOUT 6
+#define TASK_TIMEOUT (20 * HZ)
+#define TASK_RETRY 3
+#define INTERNAL_ABORT_TIMEOUT (6 * HZ)
static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
void *parameter, u32 para_len,
struct hisi_sas_tmf_task *tmf)
@@ -1212,7 +1223,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
task->task_done = hisi_sas_task_done;
task->slow_task->timer.function = hisi_sas_tmf_timedout;
- task->slow_task->timer.expires = jiffies + TASK_TIMEOUT * HZ;
+ task->slow_task->timer.expires = jiffies + TASK_TIMEOUT;
add_timer(&task->slow_task->timer);
res = hisi_sas_task_exec(task, GFP_KERNEL, 1, tmf);
@@ -1505,7 +1516,8 @@ static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba)
continue;
rc = hisi_sas_internal_task_abort(hisi_hba, device,
- HISI_SAS_INT_ABT_DEV, 0);
+ HISI_SAS_INT_ABT_DEV, 0,
+ false);
if (rc < 0)
dev_err(dev, "STP reject: abort dev failed %d\n", rc);
}
@@ -1604,6 +1616,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
}
hisi_sas_controller_reset_done(hisi_hba);
+ clear_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags);
dev_info(dev, "controller reset complete\n");
return 0;
@@ -1660,7 +1673,8 @@ static int hisi_sas_abort_task(struct sas_task *task)
&tmf_task);
rc2 = hisi_sas_internal_task_abort(hisi_hba, device,
- HISI_SAS_INT_ABT_CMD, tag);
+ HISI_SAS_INT_ABT_CMD, tag,
+ false);
if (rc2 < 0) {
dev_err(dev, "abort task: internal abort (%d)\n", rc2);
return TMF_RESP_FUNC_FAILED;
@@ -1682,7 +1696,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
if (task->dev->dev_type == SAS_SATA_DEV) {
rc = hisi_sas_internal_task_abort(hisi_hba, device,
HISI_SAS_INT_ABT_DEV,
- 0);
+ 0, false);
if (rc < 0) {
dev_err(dev, "abort task: internal abort failed\n");
goto out;
@@ -1697,7 +1711,8 @@ static int hisi_sas_abort_task(struct sas_task *task)
struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue];
rc = hisi_sas_internal_task_abort(hisi_hba, device,
- HISI_SAS_INT_ABT_CMD, tag);
+ HISI_SAS_INT_ABT_CMD, tag,
+ false);
if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) &&
task->lldd_task) {
/*
@@ -1723,7 +1738,7 @@ static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun)
int rc;
rc = hisi_sas_internal_task_abort(hisi_hba, device,
- HISI_SAS_INT_ABT_DEV, 0);
+ HISI_SAS_INT_ABT_DEV, 0, false);
if (rc < 0) {
dev_err(dev, "abort task set: internal abort rc=%d\n", rc);
return TMF_RESP_FUNC_FAILED;
@@ -1750,6 +1765,8 @@ static int hisi_sas_clear_aca(struct domain_device *device, u8 *lun)
return rc;
}
+#define I_T_NEXUS_RESET_PHYUP_TIMEOUT (2 * HZ)
+
static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
{
struct sas_phy *local_phy = sas_get_local_phy(device);
@@ -1784,7 +1801,8 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
sas_ha->sas_phy[local_phy->number];
struct hisi_sas_phy *phy =
container_of(sas_phy, struct hisi_sas_phy, sas_phy);
- int ret = wait_for_completion_timeout(&phyreset, 2 * HZ);
+ int ret = wait_for_completion_timeout(&phyreset,
+ I_T_NEXUS_RESET_PHYUP_TIMEOUT);
unsigned long flags;
spin_lock_irqsave(&phy->lock, flags);
@@ -1814,7 +1832,7 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
int rc;
rc = hisi_sas_internal_task_abort(hisi_hba, device,
- HISI_SAS_INT_ABT_DEV, 0);
+ HISI_SAS_INT_ABT_DEV, 0, false);
if (rc < 0) {
dev_err(dev, "I_T nexus reset: internal abort (%d)\n", rc);
return TMF_RESP_FUNC_FAILED;
@@ -1844,7 +1862,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
/* Clear internal IO and then lu reset */
rc = hisi_sas_internal_task_abort(hisi_hba, device,
- HISI_SAS_INT_ABT_DEV, 0);
+ HISI_SAS_INT_ABT_DEV, 0, false);
if (rc < 0) {
dev_err(dev, "lu_reset: internal abort failed\n");
goto out;
@@ -1875,12 +1893,24 @@ out:
return rc;
}
+static void hisi_sas_async_I_T_nexus_reset(void *data, async_cookie_t cookie)
+{
+ struct domain_device *device = data;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ int rc;
+
+ rc = hisi_sas_debug_I_T_nexus_reset(device);
+ if (rc != TMF_RESP_FUNC_COMPLETE)
+ dev_info(hisi_hba->dev, "I_T_nexus reset fail for dev:%016llx rc=%d\n",
+ SAS_ADDR(device->sas_addr), rc);
+}
+
static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha)
{
struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
- struct device *dev = hisi_hba->dev;
HISI_SAS_DECLARE_RST_WORK_ON_STACK(r);
- int rc, i;
+ ASYNC_DOMAIN_EXCLUSIVE(async);
+ int i;
queue_work(hisi_hba->wq, &r.work);
wait_for_completion(r.completion);
@@ -1895,12 +1925,11 @@ static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha)
dev_is_expander(device->dev_type))
continue;
- rc = hisi_sas_debug_I_T_nexus_reset(device);
- if (rc != TMF_RESP_FUNC_COMPLETE)
- dev_info(dev, "clear nexus ha: for device[%d] rc=%d\n",
- sas_dev->device_id, rc);
+ async_schedule_domain(hisi_sas_async_I_T_nexus_reset,
+ device, &async);
}
+ async_synchronize_full_domain(&async);
hisi_sas_release_tasks(hisi_hba);
return TMF_RESP_FUNC_COMPLETE;
@@ -2029,11 +2058,13 @@ err_out:
* @tag: tag of IO to be aborted (only relevant to single
* IO mode)
* @dq: delivery queue for this internal abort command
+ * @rst_to_recover: If rst_to_recover set, queue a controller
+ * reset if an internal abort times out.
*/
static int
_hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
struct domain_device *device, int abort_flag,
- int tag, struct hisi_sas_dq *dq)
+ int tag, struct hisi_sas_dq *dq, bool rst_to_recover)
{
struct sas_task *task;
struct hisi_sas_device *sas_dev = device->lldd_dev;
@@ -2049,6 +2080,9 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
if (!hisi_hba->hw->prep_abort)
return TMF_RESP_FUNC_FAILED;
+ if (test_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags))
+ return -EIO;
+
task = sas_alloc_slow_task(GFP_KERNEL);
if (!task)
return -ENOMEM;
@@ -2057,7 +2091,7 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
task->task_proto = device->tproto;
task->task_done = hisi_sas_task_done;
task->slow_task->timer.function = hisi_sas_tmf_timedout;
- task->slow_task->timer.expires = jiffies + INTERNAL_ABORT_TIMEOUT * HZ;
+ task->slow_task->timer.expires = jiffies + INTERNAL_ABORT_TIMEOUT;
add_timer(&task->slow_task->timer);
res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id,
@@ -2079,6 +2113,8 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
struct hisi_sas_slot *slot = task->lldd_task;
+ set_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags);
+
if (slot) {
struct hisi_sas_cq *cq =
&hisi_hba->cq[slot->dlvry_queue];
@@ -2089,7 +2125,13 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
synchronize_irq(cq->irq_no);
slot->task = NULL;
}
- dev_err(dev, "internal task abort: timeout and not done.\n");
+
+ if (rst_to_recover) {
+ dev_err(dev, "internal task abort: timeout and not done. Queuing reset.\n");
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+ } else {
+ dev_err(dev, "internal task abort: timeout and not done.\n");
+ }
res = -EIO;
goto exit;
@@ -2122,7 +2164,7 @@ exit:
static int
hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
struct domain_device *device,
- int abort_flag, int tag)
+ int abort_flag, int tag, bool rst_to_recover)
{
struct hisi_sas_slot *slot;
struct device *dev = hisi_hba->dev;
@@ -2134,7 +2176,8 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
slot = &hisi_hba->slot_info[tag];
dq = &hisi_hba->dq[slot->dlvry_queue];
return _hisi_sas_internal_task_abort(hisi_hba, device,
- abort_flag, tag, dq);
+ abort_flag, tag, dq,
+ rst_to_recover);
case HISI_SAS_INT_ABT_DEV:
for (i = 0; i < hisi_hba->cq_nvecs; i++) {
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
@@ -2145,7 +2188,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
dq = &hisi_hba->dq[i];
rc = _hisi_sas_internal_task_abort(hisi_hba, device,
abort_flag, tag,
- dq);
+ dq, rst_to_recover);
if (rc)
return rc;
}
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index 3e359ac752fd..afe639994f3d 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -1152,14 +1152,14 @@ static void slot_err_v1_hw(struct hisi_hba *hisi_hba,
}
default:
{
- ts->stat = SAM_STAT_CHECK_CONDITION;
+ ts->stat = SAS_SAM_STAT_CHECK_CONDITION;
break;
}
}
}
break;
case SAS_PROTOCOL_SMP:
- ts->stat = SAM_STAT_CHECK_CONDITION;
+ ts->stat = SAS_SAM_STAT_CHECK_CONDITION;
break;
case SAS_PROTOCOL_SATA:
@@ -1281,7 +1281,7 @@ static void slot_complete_v1_hw(struct hisi_hba *hisi_hba,
struct scatterlist *sg_resp = &task->smp_task.smp_resp;
void *to = page_address(sg_page(sg_resp));
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
DMA_TO_DEVICE);
@@ -1298,7 +1298,7 @@ static void slot_complete_v1_hw(struct hisi_hba *hisi_hba,
break;
default:
- ts->stat = SAM_STAT_CHECK_CONDITION;
+ ts->stat = SAS_SAM_STAT_CHECK_CONDITION;
break;
}
@@ -1649,7 +1649,7 @@ static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba)
if (irq < 0) {
dev_err(dev, "irq init: fail map phy interrupt %d\n",
idx);
- return -ENOENT;
+ return irq;
}
rc = devm_request_irq(dev, irq, phy_interrupts[j], 0,
@@ -1657,7 +1657,7 @@ static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba)
if (rc) {
dev_err(dev, "irq init: could not request phy interrupt %d, rc=%d\n",
irq, rc);
- return -ENOENT;
+ return rc;
}
}
}
@@ -1668,7 +1668,7 @@ static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba)
if (irq < 0) {
dev_err(dev, "irq init: could not map cq interrupt %d\n",
idx);
- return -ENOENT;
+ return irq;
}
rc = devm_request_irq(dev, irq, cq_interrupt_v1_hw, 0,
@@ -1676,7 +1676,7 @@ static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba)
if (rc) {
dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n",
irq, rc);
- return -ENOENT;
+ return rc;
}
}
@@ -1686,7 +1686,7 @@ static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba)
if (irq < 0) {
dev_err(dev, "irq init: could not map fatal interrupt %d\n",
idx);
- return -ENOENT;
+ return irq;
}
rc = devm_request_irq(dev, irq, fatal_interrupts[i], 0,
@@ -1694,7 +1694,7 @@ static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba)
if (rc) {
dev_err(dev, "irq init: could not request fatal interrupt %d, rc=%d\n",
irq, rc);
- return -ENOENT;
+ return rc;
}
}
@@ -1771,6 +1771,7 @@ static struct scsi_host_template sht_v1_hw = {
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_target_reset_handler = sas_eh_target_reset_handler,
+ .slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
#ifdef CONFIG_COMPAT
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 46f60fc2a069..b0b2361e63fe 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -994,7 +994,7 @@ static int clear_itct_v2_hw(struct hisi_hba *hisi_hba,
reg_val = ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val);
if (!wait_for_completion_timeout(sas_dev->completion,
- CLEAR_ITCT_TIMEOUT * HZ)) {
+ HISI_SAS_CLEAR_ITCT_TIMEOUT)) {
dev_warn(dev, "failed to clear ITCT\n");
return -ETIMEDOUT;
}
@@ -2168,7 +2168,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
}
break;
case SAS_PROTOCOL_SMP:
- ts->stat = SAM_STAT_CHECK_CONDITION;
+ ts->stat = SAS_SAM_STAT_CHECK_CONDITION;
break;
case SAS_PROTOCOL_SATA:
@@ -2427,7 +2427,7 @@ static void slot_complete_v2_hw(struct hisi_hba *hisi_hba,
struct scatterlist *sg_resp = &task->smp_task.smp_resp;
void *to = page_address(sg_page(sg_resp));
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
DMA_TO_DEVICE);
@@ -2441,12 +2441,12 @@ static void slot_complete_v2_hw(struct hisi_hba *hisi_hba,
case SAS_PROTOCOL_STP:
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
{
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
hisi_sas_sata_done(task, slot);
break;
}
default:
- ts->stat = SAM_STAT_CHECK_CONDITION;
+ ts->stat = SAS_SAM_STAT_CHECK_CONDITION;
break;
}
@@ -3584,6 +3584,7 @@ static struct scsi_host_template sht_v2_hw = {
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_target_reset_handler = sas_eh_target_reset_handler,
+ .slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
#ifdef CONFIG_COMPAT
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index e95408314078..a4885d03afe2 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -843,7 +843,7 @@ static int clear_itct_v3_hw(struct hisi_hba *hisi_hba,
hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val);
if (!wait_for_completion_timeout(sas_dev->completion,
- CLEAR_ITCT_TIMEOUT * HZ)) {
+ HISI_SAS_CLEAR_ITCT_TIMEOUT)) {
dev_warn(dev, "failed to clear ITCT\n");
return -ETIMEDOUT;
}
@@ -2178,7 +2178,7 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
hisi_sas_sata_done(task, slot);
break;
case SAS_PROTOCOL_SMP:
- ts->stat = SAM_STAT_CHECK_CONDITION;
+ ts->stat = SAS_SAM_STAT_CHECK_CONDITION;
break;
default:
break;
@@ -2285,7 +2285,7 @@ static void slot_complete_v3_hw(struct hisi_hba *hisi_hba,
struct scatterlist *sg_resp = &task->smp_task.smp_resp;
void *to = page_address(sg_page(sg_resp));
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
DMA_TO_DEVICE);
@@ -2298,11 +2298,11 @@ static void slot_complete_v3_hw(struct hisi_hba *hisi_hba,
case SAS_PROTOCOL_SATA:
case SAS_PROTOCOL_STP:
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
hisi_sas_sata_done(task, slot);
break;
default:
- ts->stat = SAM_STAT_CHECK_CONDITION;
+ ts->stat = SAS_SAM_STAT_CHECK_CONDITION;
break;
}
@@ -3155,6 +3155,7 @@ static struct scsi_host_template sht_v3_hw = {
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_target_reset_handler = sas_eh_target_reset_handler,
+ .slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
#ifdef CONFIG_COMPAT
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index cd52664920e1..3f6f14f0cafb 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -220,6 +220,9 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
goto fail;
}
+ shost->cmd_per_lun = min_t(short, shost->cmd_per_lun,
+ shost->can_queue);
+
error = scsi_init_sense_cache(shost);
if (error)
goto fail;
@@ -319,7 +322,7 @@ static void scsi_host_dev_release(struct device *dev)
scsi_proc_hostdir_rm(shost->hostt);
- /* Wait for functions invoked through call_rcu(&shost->rcu, ...) */
+ /* Wait for functions invoked through call_rcu(&scmd->rcu, ...) */
rcu_barrier();
if (shost->tmf_work_q)
@@ -485,6 +488,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
shost_printk(KERN_WARNING, shost,
"error handler thread failed to spawn, error = %ld\n",
PTR_ERR(shost->ehandler));
+ shost->ehandler = NULL;
goto fail;
}
@@ -657,10 +661,11 @@ EXPORT_SYMBOL_GPL(scsi_flush_work);
static bool complete_all_cmds_iter(struct request *rq, void *data, bool rsvd)
{
struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
- int status = *(int *)data;
+ enum scsi_host_status status = *(enum scsi_host_status *)data;
scsi_dma_unmap(scmd);
- scmd->result = status << 16;
+ scmd->result = 0;
+ set_host_byte(scmd, status);
scmd->scsi_done(scmd);
return true;
}
@@ -675,7 +680,8 @@ static bool complete_all_cmds_iter(struct request *rq, void *data, bool rsvd)
* caller to ensure that concurrent I/O submission and/or
* completion is stopped when calling this function.
*/
-void scsi_host_complete_all_commands(struct Scsi_Host *shost, int status)
+void scsi_host_complete_all_commands(struct Scsi_Host *shost,
+ enum scsi_host_status status)
{
blk_mq_tagset_busy_iter(&shost->tag_set, complete_all_cmds_iter,
&status);
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index db4c7a7ff4dd..61cda7b7624f 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -760,7 +760,7 @@ static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
goto skip_resid;
default:
- scp->result = DRIVER_INVALID << 24 | DID_ABORT << 16;
+ scp->result = DID_ABORT << 16;
break;
}
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 6540d48eb0e8..bee1bec49c09 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -13,6 +13,7 @@
#include <linux/dmapool.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/of.h>
@@ -654,8 +655,10 @@ static void ibmvfc_reinit_host(struct ibmvfc_host *vhost)
**/
static void ibmvfc_del_tgt(struct ibmvfc_target *tgt)
{
- if (!ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_RPORT))
+ if (!ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_RPORT)) {
tgt->job_step = ibmvfc_tgt_implicit_logout_and_del;
+ tgt->init_retries = 0;
+ }
wake_up(&tgt->vhost->work_wait_q);
}
@@ -4299,9 +4302,10 @@ static void ibmvfc_tgt_move_login_done(struct ibmvfc_event *evt)
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
switch (status) {
case IBMVFC_MAD_SUCCESS:
- tgt_dbg(tgt, "Move Login succeeded for old scsi_id: %llX\n", tgt->old_scsi_id);
+ tgt_dbg(tgt, "Move Login succeeded for new scsi_id: %llX\n", tgt->new_scsi_id);
tgt->ids.node_name = wwn_to_u64(rsp->service_parms.node_name);
tgt->ids.port_name = wwn_to_u64(rsp->service_parms.port_name);
+ tgt->scsi_id = tgt->new_scsi_id;
tgt->ids.port_id = tgt->scsi_id;
memcpy(&tgt->service_parms, &rsp->service_parms,
sizeof(tgt->service_parms));
@@ -4319,8 +4323,8 @@ static void ibmvfc_tgt_move_login_done(struct ibmvfc_event *evt)
level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_move_login);
tgt_log(tgt, level,
- "Move Login failed: old scsi_id: %llX, flags:%x, vios_flags:%x, rc=0x%02X\n",
- tgt->old_scsi_id, be32_to_cpu(rsp->flags), be16_to_cpu(rsp->vios_flags),
+ "Move Login failed: new scsi_id: %llX, flags:%x, vios_flags:%x, rc=0x%02X\n",
+ tgt->new_scsi_id, be32_to_cpu(rsp->flags), be16_to_cpu(rsp->vios_flags),
status);
break;
}
@@ -4357,8 +4361,8 @@ static void ibmvfc_tgt_move_login(struct ibmvfc_target *tgt)
move->common.opcode = cpu_to_be32(IBMVFC_MOVE_LOGIN);
move->common.length = cpu_to_be16(sizeof(*move));
- move->old_scsi_id = cpu_to_be64(tgt->old_scsi_id);
- move->new_scsi_id = cpu_to_be64(tgt->scsi_id);
+ move->old_scsi_id = cpu_to_be64(tgt->scsi_id);
+ move->new_scsi_id = cpu_to_be64(tgt->new_scsi_id);
move->wwpn = cpu_to_be64(tgt->wwpn);
move->node_name = cpu_to_be64(tgt->ids.node_name);
@@ -4367,7 +4371,7 @@ static void ibmvfc_tgt_move_login(struct ibmvfc_target *tgt)
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
kref_put(&tgt->kref, ibmvfc_release_tgt);
} else
- tgt_dbg(tgt, "Sent Move Login for old scsi_id: %llX\n", tgt->old_scsi_id);
+ tgt_dbg(tgt, "Sent Move Login for new scsi_id: %llX\n", tgt->new_scsi_id);
}
/**
@@ -4727,20 +4731,25 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost,
* and it failed for some reason, such as there being I/O
* pending to the target. In this case, we will have already
* deleted the rport from the FC transport so we do a move
- * login, which works even with I/O pending, as it will cancel
- * any active commands.
+ * login, which works even with I/O pending, however, if
+ * there is still I/O pending, it will stay outstanding, so
+ * we only do this if fast fail is disabled for the rport,
+ * otherwise we let terminate_rport_io clean up the port
+ * before we login at the new location.
*/
if (wtgt->action == IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT) {
- /*
- * Do a move login here. The old target is no longer
- * known to the transport layer We don't use the
- * normal ibmvfc_set_tgt_action to set this, as we
- * don't normally want to allow this state change.
- */
- wtgt->old_scsi_id = wtgt->scsi_id;
- wtgt->scsi_id = scsi_id;
- wtgt->action = IBMVFC_TGT_ACTION_INIT;
- ibmvfc_init_tgt(wtgt, ibmvfc_tgt_move_login);
+ if (wtgt->move_login) {
+ /*
+ * Do a move login here. The old target is no longer
+ * known to the transport layer We don't use the
+ * normal ibmvfc_set_tgt_action to set this, as we
+ * don't normally want to allow this state change.
+ */
+ wtgt->new_scsi_id = scsi_id;
+ wtgt->action = IBMVFC_TGT_ACTION_INIT;
+ wtgt->init_retries = 0;
+ ibmvfc_init_tgt(wtgt, ibmvfc_tgt_move_login);
+ }
goto unlock_out;
} else {
tgt_err(wtgt, "Unexpected target state: %d, %p\n",
@@ -5331,6 +5340,7 @@ static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
tgt_dbg(tgt, "Deleting rport with outstanding I/O\n");
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT);
tgt->rport = NULL;
+ tgt->init_retries = 0;
spin_unlock_irqrestore(vhost->host->host_lock, flags);
fc_remote_port_delete(rport);
return;
@@ -5485,7 +5495,20 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
tgt_dbg(tgt, "Deleting rport with I/O outstanding\n");
rport = tgt->rport;
tgt->rport = NULL;
+ tgt->init_retries = 0;
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT);
+
+ /*
+ * If fast fail is enabled, we wait for it to fire and then clean up
+ * the old port, since we expect the fast fail timer to clean up the
+ * outstanding I/O faster than waiting for normal command timeouts.
+ * However, if fast fail is disabled, any I/O outstanding to the
+ * rport LUNs will stay outstanding indefinitely, since the EH handlers
+ * won't get invoked for I/O's timing out. If this is a NPIV failover
+ * scenario, the better alternative is to use the move login.
+ */
+ if (rport && rport->fast_io_fail_tmo == -1)
+ tgt->move_login = 1;
spin_unlock_irqrestore(vhost->host->host_lock, flags);
if (rport)
fc_remote_port_delete(rport);
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index 19dcec3ae9ba..4f0f3baefae4 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -718,7 +718,7 @@ struct ibmvfc_target {
struct ibmvfc_host *vhost;
u64 scsi_id;
u64 wwpn;
- u64 old_scsi_id;
+ u64 new_scsi_id;
struct fc_rport *rport;
int target_id;
enum ibmvfc_target_action action;
@@ -726,6 +726,7 @@ struct ibmvfc_target {
int add_rport;
int init_retries;
int logo_rcvd;
+ int move_login;
u32 cancel_key;
struct ibmvfc_service_parms service_parms;
struct ibmvfc_service_parms service_parms_change;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index e75b0068ad84..e6a3eaaa57d9 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -1005,7 +1005,7 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
if (cmnd) {
cmnd->result |= rsp->status;
- if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
+ if (scsi_status_is_check_condition(cmnd->result))
memcpy(cmnd->sense_buffer,
rsp->data,
be32_to_cpu(rsp->sense_data_len));
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
index 41ac9477df7a..10b6c6daaacd 100644
--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
@@ -22,6 +22,7 @@
#include <linux/list.h>
#include <linux/string.h>
#include <linux/delay.h>
+#include <linux/of.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index 862d35a098cf..943c9102a7eb 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -1283,19 +1283,6 @@ static struct parport_driver imm_driver = {
.detach = imm_detach,
.devmodel = true,
};
-
-static int __init imm_driver_init(void)
-{
- printk("imm: Version %s\n", IMM_VERSION);
- return parport_register_driver(&imm_driver);
-}
-
-static void __exit imm_driver_exit(void)
-{
- parport_unregister_driver(&imm_driver);
-}
-
-module_init(imm_driver_init);
-module_exit(imm_driver_exit);
+module_parport_driver(imm_driver);
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 30c30a1db5b1..5d78f7e939a3 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -1300,7 +1300,7 @@ static char *__ipr_format_res_path(u8 *res_path, char *buffer, int len)
*p = '\0';
p += scnprintf(p, buffer + len - p, "%02X", res_path[0]);
- for (i = 1; res_path[i] != 0xff && ((i * 3) < len); i++)
+ for (i = 1; res_path[i] != 0xff && i < IPR_RES_PATH_BYTES; i++)
p += scnprintf(p, buffer + len - p, "-%02X", res_path[i]);
return buffer;
@@ -1323,7 +1323,7 @@ static char *ipr_format_res_path(struct ipr_ioa_cfg *ioa_cfg,
*p = '\0';
p += scnprintf(p, buffer + len - p, "%d/", ioa_cfg->host->host_no);
- __ipr_format_res_path(res_path, p, len - (buffer - p));
+ __ipr_format_res_path(res_path, p, len - (p - buffer));
return buffer;
}
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 783ee03ad9ea..69444d21fca1 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -428,6 +428,7 @@ struct ipr_config_table_entry64 {
__be64 lun;
__be64 lun_wwn[2];
#define IPR_MAX_RES_PATH_LENGTH 48
+#define IPR_RES_PATH_BYTES 8
__be64 res_path;
struct ipr_std_inq_data std_inq_data;
u8 reserved2[4];
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index bc33d54a4011..8b33c9871484 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -3344,13 +3344,15 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
IPS_CMD_EXTENDED_DCDB_SG)) {
tapeDCDB =
(IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
- memcpy(scb->scsi_cmd->sense_buffer,
+ memcpy_and_pad(scb->scsi_cmd->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE,
tapeDCDB->sense_info,
- SCSI_SENSE_BUFFERSIZE);
+ sizeof(tapeDCDB->sense_info), 0);
} else {
- memcpy(scb->scsi_cmd->sense_buffer,
+ memcpy_and_pad(scb->scsi_cmd->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE,
scb->dcdb.sense_info,
- SCSI_SENSE_BUFFERSIZE);
+ sizeof(scb->dcdb.sense_info), 0);
}
device_error = 2; /* check condition */
}
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index c452849e7bb4..ffd33e5decae 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -167,6 +167,7 @@ static struct scsi_host_template isci_sht = {
.eh_abort_handler = sas_eh_abort_handler,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_target_reset_handler = sas_eh_target_reset_handler,
+ .slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
#ifdef CONFIG_COMPAT
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index e7c6cb4c1556..e1ff79464131 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2566,7 +2566,7 @@ static void isci_request_handle_controller_specific_errors(
if (!idev)
*status_ptr = SAS_DEVICE_UNKNOWN;
else
- *status_ptr = SAM_STAT_TASK_ABORTED;
+ *status_ptr = SAS_SAM_STAT_TASK_ABORTED;
clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
}
@@ -2696,7 +2696,7 @@ static void isci_request_handle_controller_specific_errors(
default:
/* Task in the target is not done. */
*response_ptr = SAS_TASK_UNDELIVERED;
- *status_ptr = SAM_STAT_TASK_ABORTED;
+ *status_ptr = SAS_SAM_STAT_TASK_ABORTED;
if (task->task_proto == SAS_PROTOCOL_SMP)
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
@@ -2719,7 +2719,7 @@ static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_
if (ac_err_mask(fis->status))
ts->stat = SAS_PROTO_RESPONSE;
else
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
ts->resp = SAS_TASK_COMPLETE;
}
@@ -2782,7 +2782,7 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
case SCI_IO_SUCCESS_IO_DONE_EARLY:
response = SAS_TASK_COMPLETE;
- status = SAM_STAT_GOOD;
+ status = SAS_SAM_STAT_GOOD;
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) {
@@ -2852,7 +2852,7 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
/* Fail the I/O. */
response = SAS_TASK_UNDELIVERED;
- status = SAM_STAT_TASK_ABORTED;
+ status = SAS_SAM_STAT_TASK_ABORTED;
clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
break;
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 62062ed6cd9a..3fd88d72a0c0 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -160,7 +160,7 @@ int isci_task_execute_task(struct sas_task *task, gfp_t gfp_flags)
isci_task_refuse(ihost, task,
SAS_TASK_UNDELIVERED,
- SAM_STAT_TASK_ABORTED);
+ SAS_SAM_STAT_TASK_ABORTED);
} else {
task->task_state_flags |= SAS_TASK_AT_INITIATOR;
spin_unlock_irqrestore(&task->task_state_lock, flags);
@@ -709,8 +709,8 @@ isci_task_request_complete(struct isci_host *ihost,
tmf->status = completion_status;
if (tmf->proto == SAS_PROTOCOL_SSP) {
- memcpy(&tmf->resp.resp_iu,
- &ireq->ssp.rsp,
+ memcpy(tmf->resp.rsp_buf,
+ ireq->ssp.rsp_buf,
SSP_RESP_IU_MAX_SIZE);
} else if (tmf->proto == SAS_PROTOCOL_SATA) {
memcpy(&tmf->resp.d2h_fis,
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index dd33ce0e3737..1bc37593c88f 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -600,6 +600,12 @@ static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn)
if (!sock)
return;
+ /*
+ * Make sure we start socket shutdown now in case userspace is up
+ * but delayed in releasing the socket.
+ */
+ kernel_sock_shutdown(sock, SHUT_RDWR);
+
sock_hold(sock->sk);
iscsi_sw_tcp_conn_restore_callbacks(conn);
sock_put(sock->sk);
@@ -689,6 +695,7 @@ iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session,
sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */
sk->sk_allocation = GFP_ATOMIC;
sk_set_memalloc(sk);
+ sock_no_linger(sk);
iscsi_sw_tcp_conn_set_callbacks(conn);
tcp_sw_conn->sendpage = tcp_sw_conn->sock->ops->sendpage;
diff --git a/drivers/scsi/libfc/fc_encode.h b/drivers/scsi/libfc/fc_encode.h
index 602c97a651bc..74ae7fd15d8d 100644
--- a/drivers/scsi/libfc/fc_encode.h
+++ b/drivers/scsi/libfc/fc_encode.h
@@ -166,9 +166,11 @@ static inline int fc_ct_ns_fill(struct fc_lport *lport,
static inline void fc_ct_ms_fill_attr(struct fc_fdmi_attr_entry *entry,
const char *in, size_t len)
{
- int copied = strscpy(entry->value, in, len);
- if (copied > 0)
- memset(entry->value, copied, len - copied);
+ int copied;
+
+ copied = strscpy(entry->value, in, len);
+ if (copied > 0 && copied + 1 < len)
+ memset(entry->value + copied + 1, 0, len - copied - 1);
}
/**
@@ -190,10 +192,11 @@ static inline int fc_ct_ms_fill(struct fc_lport *lport,
struct fc_fdmi_attr_entry *entry;
struct fs_fdmi_attrs *hba_attrs;
int numattrs = 0;
+ struct fc_host_attrs *fc_host = shost_to_fc_host(lport->host);
switch (op) {
case FC_FDMI_RHBA:
- numattrs = 10;
+ numattrs = 11;
len = sizeof(struct fc_fdmi_rhba);
len -= sizeof(struct fc_fdmi_attr_entry);
len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
@@ -207,8 +210,21 @@ static inline int fc_ct_ms_fill(struct fc_lport *lport,
len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN;
len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN;
len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN;
+ len += FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN;
+
+ if (fc_host->fdmi_version == FDMI_V2) {
+ numattrs += 7;
+ len += FC_FDMI_HBA_ATTR_NODESYMBLNAME_LEN;
+ len += FC_FDMI_HBA_ATTR_VENDORSPECIFICINFO_LEN;
+ len += FC_FDMI_HBA_ATTR_NUMBEROFPORTS_LEN;
+ len += FC_FDMI_HBA_ATTR_FABRICNAME_LEN;
+ len += FC_FDMI_HBA_ATTR_BIOSVERSION_LEN;
+ len += FC_FDMI_HBA_ATTR_BIOSSTATE_LEN;
+ len += FC_FDMI_HBA_ATTR_VENDORIDENTIFIER_LEN;
+ }
+
ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT,
- FC_FDMI_SUBTYPE);
+ FC_FDMI_SUBTYPE);
/* HBA Identifier */
put_unaligned_be64(lport->wwpn, &ct->payload.rhba.hbaid.id);
@@ -313,7 +329,7 @@ static inline int fc_ct_ms_fill(struct fc_lport *lport,
&entry->type);
put_unaligned_be16(len, &entry->len);
fc_ct_ms_fill_attr(entry,
- fc_host_optionrom_version(lport->host),
+ "unknown",
FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN);
/* Firmware Version */
@@ -341,6 +357,100 @@ static inline int fc_ct_ms_fill(struct fc_lport *lport,
"%s v%s",
init_utsname()->sysname,
init_utsname()->release);
+
+ /* Max CT payload */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN;
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_MAXCTPAYLOAD,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ put_unaligned_be32(fc_host_max_ct_payload(lport->host),
+ &entry->value);
+
+ if (fc_host->fdmi_version == FDMI_V2) {
+ /* Node symbolic name */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_HBA_ATTR_NODESYMBLNAME_LEN;
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_NODESYMBLNAME,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ fc_ct_ms_fill_attr(entry,
+ fc_host_symbolic_name(lport->host),
+ FC_FDMI_HBA_ATTR_NODESYMBLNAME_LEN);
+
+ /* Vendor specific info */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_HBA_ATTR_NODESYMBLNAME_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_HBA_ATTR_VENDORSPECIFICINFO_LEN;
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_VENDORSPECIFICINFO,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ put_unaligned_be32(0,
+ &entry->value);
+
+ /* Number of ports */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_HBA_ATTR_VENDORSPECIFICINFO_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_HBA_ATTR_NUMBEROFPORTS_LEN;
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_NUMBEROFPORTS,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ put_unaligned_be32(fc_host_num_ports(lport->host),
+ &entry->value);
+
+ /* Fabric name */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_HBA_ATTR_NUMBEROFPORTS_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_HBA_ATTR_FABRICNAME_LEN;
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_FABRICNAME,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ put_unaligned_be64(fc_host_fabric_name(lport->host),
+ &entry->value);
+
+ /* BIOS version */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_HBA_ATTR_FABRICNAME_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_HBA_ATTR_BIOSVERSION_LEN;
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_BIOSVERSION,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ fc_ct_ms_fill_attr(entry,
+ fc_host_bootbios_version(lport->host),
+ FC_FDMI_HBA_ATTR_BIOSVERSION_LEN);
+
+ /* BIOS state */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_HBA_ATTR_BIOSVERSION_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_HBA_ATTR_BIOSSTATE_LEN;
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_BIOSSTATE,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ put_unaligned_be32(fc_host_bootbios_state(lport->host),
+ &entry->value);
+
+ /* Vendor identifier */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_HBA_ATTR_BIOSSTATE_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_HBA_ATTR_VENDORIDENTIFIER_LEN;
+ put_unaligned_be16(FC_FDMI_HBA_ATTR_VENDORIDENTIFIER,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ fc_ct_ms_fill_attr(entry,
+ fc_host_vendor_identifier(lport->host),
+ FC_FDMI_HBA_ATTR_VENDORIDENTIFIER_LEN);
+ }
+
break;
case FC_FDMI_RPA:
numattrs = 6;
@@ -353,6 +463,24 @@ static inline int fc_ct_ms_fill(struct fc_lport *lport,
len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN;
len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN;
len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN;
+
+
+ if (fc_host->fdmi_version == FDMI_V2) {
+ numattrs += 10;
+
+ len += FC_FDMI_PORT_ATTR_NODENAME_LEN;
+ len += FC_FDMI_PORT_ATTR_PORTNAME_LEN;
+ len += FC_FDMI_PORT_ATTR_SYMBOLICNAME_LEN;
+ len += FC_FDMI_PORT_ATTR_PORTTYPE_LEN;
+ len += FC_FDMI_PORT_ATTR_SUPPORTEDCLASSSRVC_LEN;
+ len += FC_FDMI_PORT_ATTR_FABRICNAME_LEN;
+ len += FC_FDMI_PORT_ATTR_CURRENTFC4TYPE_LEN;
+ len += FC_FDMI_PORT_ATTR_PORTSTATE_LEN;
+ len += FC_FDMI_PORT_ATTR_DISCOVEREDPORTS_LEN;
+ len += FC_FDMI_PORT_ATTR_PORTID_LEN;
+
+ }
+
ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT,
FC_FDMI_SUBTYPE);
@@ -441,6 +569,122 @@ static inline int fc_ct_ms_fill(struct fc_lport *lport,
fc_ct_ms_fill_attr(entry,
init_utsname()->nodename,
FC_FDMI_PORT_ATTR_HOSTNAME_LEN);
+
+
+ if (fc_host->fdmi_version == FDMI_V2) {
+
+ /* Node name */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_PORT_ATTR_HOSTNAME_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_PORT_ATTR_NODENAME_LEN;
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_NODENAME,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ put_unaligned_be64(fc_host_node_name(lport->host),
+ &entry->value);
+
+ /* Port name */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_PORT_ATTR_NODENAME_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_PORT_ATTR_PORTNAME_LEN;
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_PORTNAME,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ put_unaligned_be64(lport->wwpn,
+ &entry->value);
+
+ /* Port symbolic name */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_PORT_ATTR_PORTNAME_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_PORT_ATTR_SYMBOLICNAME_LEN;
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_SYMBOLICNAME,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ fc_ct_ms_fill_attr(entry,
+ fc_host_symbolic_name(lport->host),
+ FC_FDMI_PORT_ATTR_SYMBOLICNAME_LEN);
+
+ /* Port type */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_PORT_ATTR_SYMBOLICNAME_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_PORT_ATTR_PORTTYPE_LEN;
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_PORTTYPE,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ put_unaligned_be32(fc_host_port_type(lport->host),
+ &entry->value);
+
+ /* Supported class of service */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_PORT_ATTR_PORTTYPE_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_PORT_ATTR_SUPPORTEDCLASSSRVC_LEN;
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_SUPPORTEDCLASSSRVC,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ put_unaligned_be32(fc_host_supported_classes(lport->host),
+ &entry->value);
+
+ /* Port Fabric name */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_PORT_ATTR_SUPPORTEDCLASSSRVC_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_PORT_ATTR_FABRICNAME_LEN;
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_FABRICNAME,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ put_unaligned_be64(fc_host_fabric_name(lport->host),
+ &entry->value);
+
+ /* Port active FC-4 */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_PORT_ATTR_FABRICNAME_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_PORT_ATTR_CURRENTFC4TYPE_LEN;
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_CURRENTFC4TYPE,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ memcpy(&entry->value, fc_host_active_fc4s(lport->host),
+ FC_FDMI_PORT_ATTR_CURRENTFC4TYPE_LEN);
+
+ /* Port state */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_PORT_ATTR_CURRENTFC4TYPE_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_PORT_ATTR_PORTSTATE_LEN;
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_PORTSTATE,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ put_unaligned_be32(fc_host_port_state(lport->host),
+ &entry->value);
+
+ /* Discovered ports */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_PORT_ATTR_PORTSTATE_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_PORT_ATTR_DISCOVEREDPORTS_LEN;
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_DISCOVEREDPORTS,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ put_unaligned_be32(fc_host_num_discovered_ports(lport->host),
+ &entry->value);
+
+ /* Port ID */
+ entry = (struct fc_fdmi_attr_entry *)((char *)entry->value +
+ FC_FDMI_PORT_ATTR_DISCOVEREDPORTS_LEN);
+ len = FC_FDMI_ATTR_ENTRY_HEADER_LEN;
+ len += FC_FDMI_PORT_ATTR_PORTID_LEN;
+ put_unaligned_be16(FC_FDMI_PORT_ATTR_PORTID,
+ &entry->type);
+ put_unaligned_be16(len, &entry->len);
+ put_unaligned_be32(fc_host_port_id(lport->host),
+ &entry->value);
+ }
+
break;
case FC_FDMI_DPRT:
len = sizeof(struct fc_fdmi_dprt);
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index cf36c8cb5493..19cd4a95d354 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -93,7 +93,10 @@
#define FC_LOCAL_PTP_FID_LO 0x010101
#define FC_LOCAL_PTP_FID_HI 0x010102
-#define DNS_DELAY 3 /* Discovery delay after RSCN (in seconds)*/
+#define DNS_DELAY 3 /* Discovery delay after RSCN (in seconds)*/
+#define MAX_CT_PAYLOAD 2048
+#define DISCOVERED_PORTS 4
+#define NUMBER_OF_PORTS 1
static void fc_lport_error(struct fc_lport *, struct fc_frame *);
@@ -1185,7 +1188,7 @@ static void fc_lport_ms_resp(struct fc_seq *sp, struct fc_frame *fp,
struct fc_lport *lport = lp_arg;
struct fc_frame_header *fh;
struct fc_ct_hdr *ct;
-
+ struct fc_host_attrs *fc_host = shost_to_fc_host(lport->host);
FC_LPORT_DBG(lport, "Received a ms %s\n", fc_els_resp_type(fp));
if (fp == ERR_PTR(-FC_EX_CLOSED))
@@ -1219,7 +1222,13 @@ static void fc_lport_ms_resp(struct fc_seq *sp, struct fc_frame *fp,
switch (lport->state) {
case LPORT_ST_RHBA:
- if (ntohs(ct->ct_cmd) == FC_FS_ACC)
+ if ((ntohs(ct->ct_cmd) == FC_FS_RJT) && fc_host->fdmi_version == FDMI_V2) {
+ FC_LPORT_DBG(lport, "Error for FDMI-V2, fall back to FDMI-V1\n");
+ fc_host->fdmi_version = FDMI_V1;
+
+ fc_lport_enter_ms(lport, LPORT_ST_RHBA);
+
+ } else if (ntohs(ct->ct_cmd) == FC_FS_ACC)
fc_lport_enter_ms(lport, LPORT_ST_RPA);
else /* Error Skip RPA */
fc_lport_enter_scr(lport);
@@ -1433,7 +1442,7 @@ static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state)
int size = sizeof(struct fc_ct_hdr);
size_t len;
int numattrs;
-
+ struct fc_host_attrs *fc_host = shost_to_fc_host(lport->host);
lockdep_assert_held(&lport->lp_mutex);
FC_LPORT_DBG(lport, "Entered %s state from %s state\n",
@@ -1446,10 +1455,10 @@ static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state)
case LPORT_ST_RHBA:
cmd = FC_FDMI_RHBA;
/* Number of HBA Attributes */
- numattrs = 10;
+ numattrs = 11;
len = sizeof(struct fc_fdmi_rhba);
len -= sizeof(struct fc_fdmi_attr_entry);
- len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
+
len += FC_FDMI_HBA_ATTR_NODENAME_LEN;
len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN;
len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN;
@@ -1460,6 +1469,21 @@ static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state)
len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN;
len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN;
len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN;
+ len += FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN;
+
+
+ if (fc_host->fdmi_version == FDMI_V2) {
+ numattrs += 7;
+ len += FC_FDMI_HBA_ATTR_NODESYMBLNAME_LEN;
+ len += FC_FDMI_HBA_ATTR_VENDORSPECIFICINFO_LEN;
+ len += FC_FDMI_HBA_ATTR_NUMBEROFPORTS_LEN;
+ len += FC_FDMI_HBA_ATTR_FABRICNAME_LEN;
+ len += FC_FDMI_HBA_ATTR_BIOSVERSION_LEN;
+ len += FC_FDMI_HBA_ATTR_BIOSSTATE_LEN;
+ len += FC_FDMI_HBA_ATTR_VENDORIDENTIFIER_LEN;
+ }
+
+ len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
size += len;
break;
@@ -1469,7 +1493,6 @@ static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state)
numattrs = 6;
len = sizeof(struct fc_fdmi_rpa);
len -= sizeof(struct fc_fdmi_attr_entry);
- len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN;
len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN;
len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN;
@@ -1477,6 +1500,22 @@ static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state)
len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN;
len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN;
+ if (fc_host->fdmi_version == FDMI_V2) {
+ numattrs += 10;
+ len += FC_FDMI_PORT_ATTR_NODENAME_LEN;
+ len += FC_FDMI_PORT_ATTR_PORTNAME_LEN;
+ len += FC_FDMI_PORT_ATTR_SYMBOLICNAME_LEN;
+ len += FC_FDMI_PORT_ATTR_PORTTYPE_LEN;
+ len += FC_FDMI_PORT_ATTR_SUPPORTEDCLASSSRVC_LEN;
+ len += FC_FDMI_PORT_ATTR_FABRICNAME_LEN;
+ len += FC_FDMI_PORT_ATTR_CURRENTFC4TYPE_LEN;
+ len += FC_FDMI_PORT_ATTR_PORTSTATE_LEN;
+ len += FC_FDMI_PORT_ATTR_DISCOVEREDPORTS_LEN;
+ len += FC_FDMI_PORT_ATTR_PORTID_LEN;
+ }
+
+ len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
+
size += len;
break;
case LPORT_ST_DPRT:
@@ -1546,6 +1585,7 @@ static void fc_lport_timeout(struct work_struct *work)
struct fc_lport *lport =
container_of(work, struct fc_lport,
retry_work.work);
+ struct fc_host_attrs *fc_host = shost_to_fc_host(lport->host);
mutex_lock(&lport->lp_mutex);
@@ -1573,6 +1613,13 @@ static void fc_lport_timeout(struct work_struct *work)
fc_lport_enter_fdmi(lport);
break;
case LPORT_ST_RHBA:
+ if (fc_host->fdmi_version == FDMI_V2) {
+ FC_LPORT_DBG(lport, "timeout for FDMI-V2 RHBA,fall back to FDMI-V1\n");
+ fc_host->fdmi_version = FDMI_V1;
+ fc_lport_enter_ms(lport, LPORT_ST_RHBA);
+ break;
+ }
+ fallthrough;
case LPORT_ST_RPA:
case LPORT_ST_DHBA:
case LPORT_ST_DPRT:
@@ -1839,6 +1886,13 @@ EXPORT_SYMBOL(fc_lport_config);
*/
int fc_lport_init(struct fc_lport *lport)
{
+ struct fc_host_attrs *fc_host;
+
+ fc_host = shost_to_fc_host(lport->host);
+
+ /* Set FDMI version to FDMI-2 specification*/
+ fc_host->fdmi_version = FDMI_V2;
+
fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT;
fc_host_node_name(lport->host) = lport->wwnn;
fc_host_port_name(lport->host) = lport->wwpn;
@@ -1847,6 +1901,7 @@ int fc_lport_init(struct fc_lport *lport)
sizeof(fc_host_supported_fc4s(lport->host)));
fc_host_supported_fc4s(lport->host)[2] = 1;
fc_host_supported_fc4s(lport->host)[7] = 1;
+ fc_host_num_discovered_ports(lport->host) = 4;
/* This value is also unchanging */
memset(fc_host_active_fc4s(lport->host), 0,
@@ -1859,8 +1914,27 @@ int fc_lport_init(struct fc_lport *lport)
fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_1GBIT;
if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT)
fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT;
+ if (lport->link_supported_speeds & FC_PORTSPEED_40GBIT)
+ fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_40GBIT;
+ if (lport->link_supported_speeds & FC_PORTSPEED_100GBIT)
+ fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_100GBIT;
+ if (lport->link_supported_speeds & FC_PORTSPEED_25GBIT)
+ fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_25GBIT;
+ if (lport->link_supported_speeds & FC_PORTSPEED_50GBIT)
+ fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_50GBIT;
+ if (lport->link_supported_speeds & FC_PORTSPEED_100GBIT)
+ fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_100GBIT;
+
fc_fc4_add_lport(lport);
+ fc_host_num_discovered_ports(lport->host) = DISCOVERED_PORTS;
+ fc_host_port_state(lport->host) = FC_PORTSTATE_ONLINE;
+ fc_host_max_ct_payload(lport->host) = MAX_CT_PAYLOAD;
+ fc_host_num_ports(lport->host) = NUMBER_OF_PORTS;
+ fc_host_bootbios_state(lport->host) = 0X00000000;
+ snprintf(fc_host_bootbios_version(lport->host),
+ FC_SYMBOLIC_NAME_SIZE, "%s", "Unknown");
+
return 0;
}
EXPORT_SYMBOL(fc_lport_init);
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index cd0fb8ca2425..33da3c1085f0 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -1162,6 +1162,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK);
FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x spp_type 0x%x\n",
pp->spp.spp_flags, pp->spp.spp_type);
+
rdata->spp_type = pp->spp.spp_type;
if (resp_code != FC_SPP_RESP_ACK) {
if (resp_code == FC_SPP_RESP_CONF)
@@ -1184,11 +1185,13 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
/*
* Call prli provider if we should act as a target
*/
- prov = fc_passive_prov[rdata->spp_type];
- if (prov) {
- memset(&temp_spp, 0, sizeof(temp_spp));
- prov->prli(rdata, pp->prli.prli_spp_len,
- &pp->spp, &temp_spp);
+ if (rdata->spp_type < FC_FC4_PROV_SIZE) {
+ prov = fc_passive_prov[rdata->spp_type];
+ if (prov) {
+ memset(&temp_spp, 0, sizeof(temp_spp));
+ prov->prli(rdata, pp->prli.prli_spp_len,
+ &pp->spp, &temp_spp);
+ }
}
/*
* Check if the image pair could be established
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 4834219497ee..4683c183e9d4 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -230,11 +230,11 @@ static int iscsi_prep_ecdb_ahs(struct iscsi_task *task)
*/
static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode)
{
- struct iscsi_conn *conn = task->conn;
- struct iscsi_tm *tmf = &conn->tmhdr;
+ struct iscsi_session *session = task->conn->session;
+ struct iscsi_tm *tmf = &session->tmhdr;
u64 hdr_lun;
- if (conn->tmf_state == TMF_INITIAL)
+ if (session->tmf_state == TMF_INITIAL)
return 0;
if ((tmf->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_SCSI_TMFUNC)
@@ -254,24 +254,19 @@ static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode)
* Fail all SCSI cmd PDUs
*/
if (opcode != ISCSI_OP_SCSI_DATA_OUT) {
- iscsi_conn_printk(KERN_INFO, conn,
- "task [op %x itt "
- "0x%x/0x%x] "
- "rejected.\n",
- opcode, task->itt,
- task->hdr_itt);
+ iscsi_session_printk(KERN_INFO, session,
+ "task [op %x itt 0x%x/0x%x] rejected.\n",
+ opcode, task->itt, task->hdr_itt);
return -EACCES;
}
/*
* And also all data-out PDUs in response to R2T
* if fast_abort is set.
*/
- if (conn->session->fast_abort) {
- iscsi_conn_printk(KERN_INFO, conn,
- "task [op %x itt "
- "0x%x/0x%x] fast abort.\n",
- opcode, task->itt,
- task->hdr_itt);
+ if (session->fast_abort) {
+ iscsi_session_printk(KERN_INFO, session,
+ "task [op %x itt 0x%x/0x%x] fast abort.\n",
+ opcode, task->itt, task->hdr_itt);
return -EACCES;
}
break;
@@ -284,7 +279,7 @@ static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode)
*/
if (opcode == ISCSI_OP_SCSI_DATA_OUT &&
task->hdr_itt == tmf->rtt) {
- ISCSI_DBG_SESSION(conn->session,
+ ISCSI_DBG_SESSION(session,
"Preventing task %x/%x from sending "
"data-out due to abort task in "
"progress\n", task->itt,
@@ -578,6 +573,11 @@ static bool cleanup_queued_task(struct iscsi_task *task)
__iscsi_put_task(task);
}
+ if (conn->session->running_aborted_task == task) {
+ conn->session->running_aborted_task = NULL;
+ __iscsi_put_task(task);
+ }
+
if (conn->task == task) {
conn->task = NULL;
__iscsi_put_task(task);
@@ -829,10 +829,7 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
ascq = session->tt->check_protection(task, &sector);
if (ascq) {
- sc->result = DRIVER_SENSE << 24 |
- SAM_STAT_CHECK_CONDITION;
- scsi_build_sense_buffer(1, sc->sense_buffer,
- ILLEGAL_REQUEST, 0x10, ascq);
+ scsi_build_sense(sc, 1, ILLEGAL_REQUEST, 0x10, ascq);
scsi_set_sense_information(sc->sense_buffer,
SCSI_SENSE_BUFFERSIZE,
sector);
@@ -936,20 +933,21 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
{
struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr;
+ struct iscsi_session *session = conn->session;
conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
conn->tmfrsp_pdus_cnt++;
- if (conn->tmf_state != TMF_QUEUED)
+ if (session->tmf_state != TMF_QUEUED)
return;
if (tmf->response == ISCSI_TMF_RSP_COMPLETE)
- conn->tmf_state = TMF_SUCCESS;
+ session->tmf_state = TMF_SUCCESS;
else if (tmf->response == ISCSI_TMF_RSP_NO_TASK)
- conn->tmf_state = TMF_NOT_FOUND;
+ session->tmf_state = TMF_NOT_FOUND;
else
- conn->tmf_state = TMF_FAILED;
- wake_up(&conn->ehwait);
+ session->tmf_state = TMF_FAILED;
+ wake_up(&session->ehwait);
}
static int iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
@@ -1361,7 +1359,6 @@ void iscsi_session_failure(struct iscsi_session *session,
enum iscsi_err err)
{
struct iscsi_conn *conn;
- struct device *dev;
spin_lock_bh(&session->frwd_lock);
conn = session->leadconn;
@@ -1370,10 +1367,8 @@ void iscsi_session_failure(struct iscsi_session *session,
return;
}
- dev = get_device(&conn->cls_conn->dev);
+ iscsi_get_conn(conn->cls_conn);
spin_unlock_bh(&session->frwd_lock);
- if (!dev)
- return;
/*
* if the host is being removed bypass the connection
* recovery initialization because we are going to kill
@@ -1383,27 +1378,36 @@ void iscsi_session_failure(struct iscsi_session *session,
iscsi_conn_error_event(conn->cls_conn, err);
else
iscsi_conn_failure(conn, err);
- put_device(dev);
+ iscsi_put_conn(conn->cls_conn);
}
EXPORT_SYMBOL_GPL(iscsi_session_failure);
-void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
+static bool iscsi_set_conn_failed(struct iscsi_conn *conn)
{
struct iscsi_session *session = conn->session;
- spin_lock_bh(&session->frwd_lock);
- if (session->state == ISCSI_STATE_FAILED) {
- spin_unlock_bh(&session->frwd_lock);
- return;
- }
+ if (session->state == ISCSI_STATE_FAILED)
+ return false;
if (conn->stop_stage == 0)
session->state = ISCSI_STATE_FAILED;
- spin_unlock_bh(&session->frwd_lock);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
- iscsi_conn_error_event(conn->cls_conn, err);
+ return true;
+}
+
+void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
+{
+ struct iscsi_session *session = conn->session;
+ bool needs_evt;
+
+ spin_lock_bh(&session->frwd_lock);
+ needs_evt = iscsi_set_conn_failed(conn);
+ spin_unlock_bh(&session->frwd_lock);
+
+ if (needs_evt)
+ iscsi_conn_error_event(conn->cls_conn, err);
}
EXPORT_SYMBOL_GPL(iscsi_conn_failure);
@@ -1820,15 +1824,14 @@ EXPORT_SYMBOL_GPL(iscsi_target_alloc);
static void iscsi_tmf_timedout(struct timer_list *t)
{
- struct iscsi_conn *conn = from_timer(conn, t, tmf_timer);
- struct iscsi_session *session = conn->session;
+ struct iscsi_session *session = from_timer(session, t, tmf_timer);
spin_lock(&session->frwd_lock);
- if (conn->tmf_state == TMF_QUEUED) {
- conn->tmf_state = TMF_TIMEDOUT;
+ if (session->tmf_state == TMF_QUEUED) {
+ session->tmf_state = TMF_TIMEDOUT;
ISCSI_DBG_EH(session, "tmf timedout\n");
/* unblock eh_abort() */
- wake_up(&conn->ehwait);
+ wake_up(&session->ehwait);
}
spin_unlock(&session->frwd_lock);
}
@@ -1851,8 +1854,8 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
return -EPERM;
}
conn->tmfcmd_pdus_cnt++;
- conn->tmf_timer.expires = timeout * HZ + jiffies;
- add_timer(&conn->tmf_timer);
+ session->tmf_timer.expires = timeout * HZ + jiffies;
+ add_timer(&session->tmf_timer);
ISCSI_DBG_EH(session, "tmf set timeout\n");
spin_unlock_bh(&session->frwd_lock);
@@ -1866,12 +1869,12 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
* 3) session is terminated or restarted or userspace has
* given up on recovery
*/
- wait_event_interruptible(conn->ehwait, age != session->age ||
+ wait_event_interruptible(session->ehwait, age != session->age ||
session->state != ISCSI_STATE_LOGGED_IN ||
- conn->tmf_state != TMF_QUEUED);
+ session->tmf_state != TMF_QUEUED);
if (signal_pending(current))
flush_signals(current);
- del_timer_sync(&conn->tmf_timer);
+ del_timer_sync(&session->tmf_timer);
mutex_lock(&session->eh_mutex);
spin_lock_bh(&session->frwd_lock);
@@ -2180,6 +2183,51 @@ done:
spin_unlock(&session->frwd_lock);
}
+/**
+ * iscsi_conn_unbind - prevent queueing to conn.
+ * @cls_conn: iscsi conn ep is bound to.
+ * @is_active: is the conn in use for boot or is this for EH/termination
+ *
+ * This must be called by drivers implementing the ep_disconnect callout.
+ * It disables queueing to the connection from libiscsi in preparation for
+ * an ep_disconnect call.
+ */
+void iscsi_conn_unbind(struct iscsi_cls_conn *cls_conn, bool is_active)
+{
+ struct iscsi_session *session;
+ struct iscsi_conn *conn;
+
+ if (!cls_conn)
+ return;
+
+ conn = cls_conn->dd_data;
+ session = conn->session;
+ /*
+ * Wait for iscsi_eh calls to exit. We don't wait for the tmf to
+ * complete or timeout. The caller just wants to know what's running
+ * is everything that needs to be cleaned up, and no cmds will be
+ * queued.
+ */
+ mutex_lock(&session->eh_mutex);
+
+ iscsi_suspend_queue(conn);
+ iscsi_suspend_tx(conn);
+
+ spin_lock_bh(&session->frwd_lock);
+ if (!is_active) {
+ /*
+ * if logout timed out before userspace could even send a PDU
+ * the state might still be in ISCSI_STATE_LOGGED_IN and
+ * allowing new cmds and TMFs.
+ */
+ if (session->state == ISCSI_STATE_LOGGED_IN)
+ iscsi_set_conn_failed(conn);
+ }
+ spin_unlock_bh(&session->frwd_lock);
+ mutex_unlock(&session->eh_mutex);
+}
+EXPORT_SYMBOL_GPL(iscsi_conn_unbind);
+
static void iscsi_prep_abort_task_pdu(struct iscsi_task *task,
struct iscsi_tm *hdr)
{
@@ -2234,6 +2282,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
}
conn = session->leadconn;
+ iscsi_get_conn(conn->cls_conn);
conn->eh_abort_cnt++;
age = session->age;
@@ -2244,9 +2293,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
ISCSI_DBG_EH(session, "sc completed while abort in progress\n");
spin_unlock(&session->back_lock);
- spin_unlock_bh(&session->frwd_lock);
- mutex_unlock(&session->eh_mutex);
- return SUCCESS;
+ goto success;
}
ISCSI_DBG_EH(session, "aborting [sc %p itt 0x%x]\n", sc, task->itt);
__iscsi_get_task(task);
@@ -2258,17 +2305,17 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
}
/* only have one tmf outstanding at a time */
- if (conn->tmf_state != TMF_INITIAL)
+ if (session->tmf_state != TMF_INITIAL)
goto failed;
- conn->tmf_state = TMF_QUEUED;
+ session->tmf_state = TMF_QUEUED;
- hdr = &conn->tmhdr;
+ hdr = &session->tmhdr;
iscsi_prep_abort_task_pdu(task, hdr);
if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout))
goto failed;
- switch (conn->tmf_state) {
+ switch (session->tmf_state) {
case TMF_SUCCESS:
spin_unlock_bh(&session->frwd_lock);
/*
@@ -2283,18 +2330,19 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
*/
spin_lock_bh(&session->frwd_lock);
fail_scsi_task(task, DID_ABORT);
- conn->tmf_state = TMF_INITIAL;
+ session->tmf_state = TMF_INITIAL;
memset(hdr, 0, sizeof(*hdr));
spin_unlock_bh(&session->frwd_lock);
iscsi_start_tx(conn);
goto success_unlocked;
case TMF_TIMEDOUT:
+ session->running_aborted_task = task;
spin_unlock_bh(&session->frwd_lock);
iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
goto failed_unlocked;
case TMF_NOT_FOUND:
- if (!sc->SCp.ptr) {
- conn->tmf_state = TMF_INITIAL;
+ if (iscsi_task_is_completed(task)) {
+ session->tmf_state = TMF_INITIAL;
memset(hdr, 0, sizeof(*hdr));
/* task completed before tmf abort response */
ISCSI_DBG_EH(session, "sc completed while abort in "
@@ -2303,7 +2351,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
}
fallthrough;
default:
- conn->tmf_state = TMF_INITIAL;
+ session->tmf_state = TMF_INITIAL;
goto failed;
}
@@ -2313,6 +2361,7 @@ success_unlocked:
ISCSI_DBG_EH(session, "abort success [sc %p itt 0x%x]\n",
sc, task->itt);
iscsi_put_task(task);
+ iscsi_put_conn(conn->cls_conn);
mutex_unlock(&session->eh_mutex);
return SUCCESS;
@@ -2321,7 +2370,15 @@ failed:
failed_unlocked:
ISCSI_DBG_EH(session, "abort failed [sc %p itt 0x%x]\n", sc,
task ? task->itt : 0);
- iscsi_put_task(task);
+ /*
+ * The driver might be accessing the task so hold the ref. The conn
+ * stop cleanup will drop the ref after ep_disconnect so we know the
+ * driver's no longer touching the task.
+ */
+ if (!session->running_aborted_task)
+ iscsi_put_task(task);
+
+ iscsi_put_conn(conn->cls_conn);
mutex_unlock(&session->eh_mutex);
return FAILED;
}
@@ -2362,11 +2419,11 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
conn = session->leadconn;
/* only have one tmf outstanding at a time */
- if (conn->tmf_state != TMF_INITIAL)
+ if (session->tmf_state != TMF_INITIAL)
goto unlock;
- conn->tmf_state = TMF_QUEUED;
+ session->tmf_state = TMF_QUEUED;
- hdr = &conn->tmhdr;
+ hdr = &session->tmhdr;
iscsi_prep_lun_reset_pdu(sc, hdr);
if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age,
@@ -2375,7 +2432,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
goto unlock;
}
- switch (conn->tmf_state) {
+ switch (session->tmf_state) {
case TMF_SUCCESS:
break;
case TMF_TIMEDOUT:
@@ -2383,7 +2440,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
goto done;
default:
- conn->tmf_state = TMF_INITIAL;
+ session->tmf_state = TMF_INITIAL;
goto unlock;
}
@@ -2395,7 +2452,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
spin_lock_bh(&session->frwd_lock);
memset(hdr, 0, sizeof(*hdr));
fail_scsi_tasks(conn, sc->device->lun, DID_ERROR);
- conn->tmf_state = TMF_INITIAL;
+ session->tmf_state = TMF_INITIAL;
spin_unlock_bh(&session->frwd_lock);
iscsi_start_tx(conn);
@@ -2418,8 +2475,7 @@ void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
spin_lock_bh(&session->frwd_lock);
if (session->state != ISCSI_STATE_LOGGED_IN) {
session->state = ISCSI_STATE_RECOVERY_FAILED;
- if (session->leadconn)
- wake_up(&session->leadconn->ehwait);
+ wake_up(&session->ehwait);
}
spin_unlock_bh(&session->frwd_lock);
}
@@ -2440,7 +2496,6 @@ int iscsi_eh_session_reset(struct scsi_cmnd *sc)
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
- conn = session->leadconn;
mutex_lock(&session->eh_mutex);
spin_lock_bh(&session->frwd_lock);
@@ -2455,16 +2510,17 @@ failed:
return FAILED;
}
+ conn = session->leadconn;
+ iscsi_get_conn(conn->cls_conn);
+
spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
- /*
- * we drop the lock here but the leadconn cannot be destoyed while
- * we are in the scsi eh
- */
+
iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
+ iscsi_put_conn(conn->cls_conn);
ISCSI_DBG_EH(session, "wait for relogin\n");
- wait_event_interruptible(conn->ehwait,
+ wait_event_interruptible(session->ehwait,
session->state == ISCSI_STATE_TERMINATE ||
session->state == ISCSI_STATE_LOGGED_IN ||
session->state == ISCSI_STATE_RECOVERY_FAILED);
@@ -2525,11 +2581,11 @@ static int iscsi_eh_target_reset(struct scsi_cmnd *sc)
conn = session->leadconn;
/* only have one tmf outstanding at a time */
- if (conn->tmf_state != TMF_INITIAL)
+ if (session->tmf_state != TMF_INITIAL)
goto unlock;
- conn->tmf_state = TMF_QUEUED;
+ session->tmf_state = TMF_QUEUED;
- hdr = &conn->tmhdr;
+ hdr = &session->tmhdr;
iscsi_prep_tgt_reset_pdu(sc, hdr);
if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age,
@@ -2538,7 +2594,7 @@ static int iscsi_eh_target_reset(struct scsi_cmnd *sc)
goto unlock;
}
- switch (conn->tmf_state) {
+ switch (session->tmf_state) {
case TMF_SUCCESS:
break;
case TMF_TIMEDOUT:
@@ -2546,7 +2602,7 @@ static int iscsi_eh_target_reset(struct scsi_cmnd *sc)
iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
goto done;
default:
- conn->tmf_state = TMF_INITIAL;
+ session->tmf_state = TMF_INITIAL;
goto unlock;
}
@@ -2558,7 +2614,7 @@ static int iscsi_eh_target_reset(struct scsi_cmnd *sc)
spin_lock_bh(&session->frwd_lock);
memset(hdr, 0, sizeof(*hdr));
fail_scsi_tasks(conn, -1, DID_ERROR);
- conn->tmf_state = TMF_INITIAL;
+ session->tmf_state = TMF_INITIAL;
spin_unlock_bh(&session->frwd_lock);
iscsi_start_tx(conn);
@@ -2888,7 +2944,10 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
session->tt = iscsit;
session->dd_data = cls_session->dd_data + sizeof(*session);
+ session->tmf_state = TMF_INITIAL;
+ timer_setup(&session->tmf_timer, iscsi_tmf_timedout, 0);
mutex_init(&session->eh_mutex);
+
spin_lock_init(&session->frwd_lock);
spin_lock_init(&session->back_lock);
@@ -2939,10 +2998,9 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
struct module *owner = cls_session->transport->owner;
struct Scsi_Host *shost = session->host;
- iscsi_pool_free(&session->cmdpool);
-
iscsi_remove_session(cls_session);
+ iscsi_pool_free(&session->cmdpool);
kfree(session->password);
kfree(session->password_in);
kfree(session->username);
@@ -2992,7 +3050,6 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
conn->id = conn_idx;
conn->exp_statsn = 0;
- conn->tmf_state = TMF_INITIAL;
timer_setup(&conn->transport_timer, iscsi_check_transport_timeouts, 0);
@@ -3017,8 +3074,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
goto login_task_data_alloc_fail;
conn->login_task->data = conn->data = data;
- timer_setup(&conn->tmf_timer, iscsi_tmf_timedout, 0);
- init_waitqueue_head(&conn->ehwait);
+ init_waitqueue_head(&session->ehwait);
return cls_conn;
@@ -3053,7 +3109,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
* leading connection? then give up on recovery.
*/
session->state = ISCSI_STATE_TERMINATE;
- wake_up(&conn->ehwait);
+ wake_up(&session->ehwait);
}
spin_unlock_bh(&session->frwd_lock);
@@ -3128,7 +3184,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
* commands after successful recovery
*/
conn->stop_stage = 0;
- conn->tmf_state = TMF_INITIAL;
+ session->tmf_state = TMF_INITIAL;
session->age++;
if (session->age == 16)
session->age = 0;
@@ -3142,7 +3198,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
spin_unlock_bh(&session->frwd_lock);
iscsi_unblock_session(session->cls_session);
- wake_up(&conn->ehwait);
+ wake_up(&session->ehwait);
return 0;
}
EXPORT_SYMBOL_GPL(iscsi_conn_start);
@@ -3236,7 +3292,7 @@ void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
spin_lock_bh(&session->frwd_lock);
fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED);
fail_mgmt_tasks(session, conn);
- memset(&conn->tmhdr, 0, sizeof(conn->tmhdr));
+ memset(&session->tmhdr, 0, sizeof(session->tmhdr));
spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
}
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index e9a86128f1f1..4aa1fda95f35 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -116,9 +116,10 @@ static void sas_ata_task_done(struct sas_task *task)
}
}
- if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD ||
- ((stat->stat == SAM_STAT_CHECK_CONDITION &&
- dev->sata_dev.class == ATA_DEV_ATAPI))) {
+ if (stat->stat == SAS_PROTO_RESPONSE ||
+ stat->stat == SAS_SAM_STAT_GOOD ||
+ (stat->stat == SAS_SAM_STAT_CHECK_CONDITION &&
+ dev->sata_dev.class == ATA_DEV_ATAPI)) {
memcpy(dev->sata_dev.fis, resp->ending_fis, ATA_RESP_FIS_SIZE);
if (!link->sactive) {
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 9f5068f3bcfb..dd205414e505 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -461,7 +461,7 @@ static void sas_discover_domain(struct work_struct *work)
break;
#else
pr_notice("ATA device seen but CONFIG_SCSI_SAS_ATA=N so cannot attach\n");
- /* Fall through */
+ fallthrough;
#endif
/* Fall through - only for the #else condition above. */
default:
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 6d583e8c403a..e00688540219 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -101,7 +101,7 @@ static int smp_execute_task_sg(struct domain_device *dev,
}
}
if (task->task_status.resp == SAS_TASK_COMPLETE &&
- task->task_status.stat == SAM_STAT_GOOD) {
+ task->task_status.stat == SAS_SAM_STAT_GOOD) {
res = 0;
break;
}
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 1bf939818c98..ee44a0d7730b 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -911,6 +911,14 @@ void sas_task_abort(struct sas_task *task)
blk_abort_request(sc->request);
}
+int sas_slave_alloc(struct scsi_device *sdev)
+{
+ if (dev_is_sata(sdev_to_domain_dev(sdev)) && sdev->lun)
+ return -ENXIO;
+
+ return 0;
+}
+
void sas_target_destroy(struct scsi_target *starget)
{
struct domain_device *found_dev = starget->hostdata;
@@ -957,5 +965,6 @@ EXPORT_SYMBOL_GPL(sas_task_abort);
EXPORT_SYMBOL_GPL(sas_phy_reset);
EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler);
EXPORT_SYMBOL_GPL(sas_eh_target_reset_handler);
+EXPORT_SYMBOL_GPL(sas_slave_alloc);
EXPORT_SYMBOL_GPL(sas_target_destroy);
EXPORT_SYMBOL_GPL(sas_ioctl);
diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c
index e2d42593ce52..2966ead1d421 100644
--- a/drivers/scsi/libsas/sas_task.c
+++ b/drivers/scsi/libsas/sas_task.c
@@ -20,7 +20,7 @@ void sas_ssp_task_response(struct device *dev, struct sas_task *task,
else if (iu->datapres == 1)
tstat->stat = iu->resp_data[3];
else if (iu->datapres == 2) {
- tstat->stat = SAM_STAT_CHECK_CONDITION;
+ tstat->stat = SAS_SAM_STAT_CHECK_CONDITION;
tstat->buf_valid_size =
min_t(int, SAS_STATUS_BUF_SIZE,
be32_to_cpu(iu->sense_data_len));
@@ -32,7 +32,7 @@ void sas_ssp_task_response(struct device *dev, struct sas_task *task,
}
else
/* when datapres contains corrupt/unknown value... */
- tstat->stat = SAM_STAT_CHECK_CONDITION;
+ tstat->stat = SAS_SAM_STAT_CHECK_CONDITION;
}
EXPORT_SYMBOL_GPL(sas_ssp_task_response);
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index f8de0d10620b..17028861234b 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -266,6 +266,7 @@ struct lpfc_stats {
uint32_t elsRcvECHO;
uint32_t elsRcvLCB;
uint32_t elsRcvRDP;
+ uint32_t elsRcvRDF;
uint32_t elsXmitFLOGI;
uint32_t elsXmitFDISC;
uint32_t elsXmitPLOGI;
@@ -303,6 +304,64 @@ struct lpfc_stats {
struct lpfc_hba;
+#define LPFC_VMID_TIMER 300 /* timer interval in seconds */
+
+#define LPFC_MAX_VMID_SIZE 256
+#define LPFC_COMPRESS_VMID_SIZE 16
+
+union lpfc_vmid_io_tag {
+ u32 app_id; /* App Id vmid */
+ u8 cs_ctl_vmid; /* Priority tag vmid */
+};
+
+#define JIFFIES_PER_HR (HZ * 60 * 60)
+
+struct lpfc_vmid {
+ u8 flag;
+#define LPFC_VMID_SLOT_FREE 0x0
+#define LPFC_VMID_SLOT_USED 0x1
+#define LPFC_VMID_REQ_REGISTER 0x2
+#define LPFC_VMID_REGISTERED 0x4
+#define LPFC_VMID_DE_REGISTER 0x8
+ char host_vmid[LPFC_MAX_VMID_SIZE];
+ union lpfc_vmid_io_tag un;
+ struct hlist_node hnode;
+ u64 io_rd_cnt;
+ u64 io_wr_cnt;
+ u8 vmid_len;
+ u8 delete_inactive; /* Delete if inactive flag 0 = no, 1 = yes */
+ u32 hash_index;
+ u64 __percpu *last_io_time;
+};
+
+#define lpfc_vmid_is_type_priority_tag(vport)\
+ (vport->vmid_priority_tagging ? 1 : 0)
+
+#define LPFC_VMID_HASH_SIZE 256
+#define LPFC_VMID_HASH_MASK 255
+#define LPFC_VMID_HASH_SHIFT 6
+
+struct lpfc_vmid_context {
+ struct lpfc_vmid *vmp;
+ struct lpfc_nodelist *nlp;
+ bool instantiated;
+};
+
+struct lpfc_vmid_priority_range {
+ u8 low;
+ u8 high;
+ u8 qos;
+};
+
+struct lpfc_vmid_priority_info {
+ u32 num_descriptors;
+ struct lpfc_vmid_priority_range *vmid_range;
+};
+
+#define QFPA_EVEN_ONLY 0x01
+#define QFPA_ODD_ONLY 0x02
+#define QFPA_EVEN_ODD 0x03
+
enum discovery_state {
LPFC_VPORT_UNKNOWN = 0, /* vport state is unknown */
LPFC_VPORT_FAILED = 1, /* vport has failed */
@@ -442,6 +501,9 @@ struct lpfc_vport {
#define WORKER_RAMP_DOWN_QUEUE 0x800 /* hba: Decrease Q depth */
#define WORKER_RAMP_UP_QUEUE 0x1000 /* hba: Increase Q depth */
#define WORKER_SERVICE_TXQ 0x2000 /* hba: IOCBs on the txq */
+#define WORKER_CHECK_INACTIVE_VMID 0x4000 /* hba: check inactive vmids */
+#define WORKER_CHECK_VMID_ISSUE_QFPA 0x8000 /* vport: Check if qfpa needs
+ * to be issued */
struct timer_list els_tmofunc;
struct timer_list delayed_disc_tmo;
@@ -452,6 +514,8 @@ struct lpfc_vport {
#define FC_LOADING 0x1 /* HBA in process of loading drvr */
#define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */
#define FC_ALLOW_FDMI 0x4 /* port is ready for FDMI requests */
+#define FC_ALLOW_VMID 0x8 /* Allow VMID I/Os */
+#define FC_DEREGISTER_ALL_APP_ID 0x10 /* Deregister all VMIDs */
/* Vport Config Parameters */
uint32_t cfg_scan_down;
uint32_t cfg_lun_queue_depth;
@@ -470,9 +534,36 @@ struct lpfc_vport {
uint32_t cfg_tgt_queue_depth;
uint32_t cfg_first_burst_size;
uint32_t dev_loss_tmo_changed;
+ /* VMID parameters */
+ u8 lpfc_vmid_host_uuid[LPFC_COMPRESS_VMID_SIZE];
+ u32 max_vmid; /* maximum VMIDs allowed per port */
+ u32 cur_vmid_cnt; /* Current VMID count */
+#define LPFC_MIN_VMID 4
+#define LPFC_MAX_VMID 255
+ u32 vmid_inactivity_timeout; /* Time after which the VMID */
+ /* deregisters from switch */
+ u32 vmid_priority_tagging;
+#define LPFC_VMID_PRIO_TAG_DISABLE 0 /* Disable */
+#define LPFC_VMID_PRIO_TAG_SUP_TARGETS 1 /* Allow supported targets only */
+#define LPFC_VMID_PRIO_TAG_ALL_TARGETS 2 /* Allow all targets */
+ unsigned long *vmid_priority_range;
+#define LPFC_VMID_MAX_PRIORITY_RANGE 256
+#define LPFC_VMID_PRIORITY_BITMAP_SIZE 32
+ u8 vmid_flag;
+#define LPFC_VMID_IN_USE 0x1
+#define LPFC_VMID_ISSUE_QFPA 0x2
+#define LPFC_VMID_QFPA_CMPL 0x4
+#define LPFC_VMID_QOS_ENABLED 0x8
+#define LPFC_VMID_TIMER_ENBLD 0x10
+ struct fc_qfpa_res *qfpa_res;
struct fc_vport *fc_vport;
+ struct lpfc_vmid *vmid;
+ DECLARE_HASHTABLE(hash_table, 8);
+ rwlock_t vmid_lock;
+ struct lpfc_vmid_priority_info vmid_priority;
+
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
struct dentry *debug_disc_trc;
struct dentry *debug_nodelist;
@@ -915,6 +1006,7 @@ struct lpfc_hba {
uint32_t cfg_request_firmware_upgrade;
uint32_t cfg_suppress_link_up;
uint32_t cfg_rrq_xri_bitmap_sz;
+ u32 cfg_fcp_wait_abts_rsp;
uint32_t cfg_delay_discovery;
uint32_t cfg_sli_mode;
#define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */
@@ -938,6 +1030,13 @@ struct lpfc_hba {
struct nvmet_fc_target_port *targetport;
lpfc_vpd_t vpd; /* vital product data */
+ u32 cfg_max_vmid; /* maximum VMIDs allowed per port */
+ u32 cfg_vmid_app_header;
+#define LPFC_VMID_APP_HEADER_DISABLE 0
+#define LPFC_VMID_APP_HEADER_ENABLE 1
+ u32 cfg_vmid_priority_tagging;
+ u32 cfg_vmid_inactivity_timeout; /* Time after which the VMID */
+ /* deregisters from switch */
struct pci_dev *pcidev;
struct list_head work_list;
uint32_t work_ha; /* Host Attention Bits for WT */
@@ -1178,6 +1277,7 @@ struct lpfc_hba {
struct list_head ct_ev_waiters;
struct unsol_rcv_ct_ctx ct_ctx[LPFC_CT_CTX_MAX];
uint32_t ctx_idx;
+ struct timer_list inactive_vmid_poll;
/* RAS Support */
struct lpfc_ras_fwlog ras_fwlog;
@@ -1419,3 +1519,27 @@ static const char *routine(enum enum_name table_key) \
} \
return name; \
}
+
+/**
+ * lpfc_is_vmid_enabled - returns if VMID is enabled for either switch types
+ * @phba: Pointer to HBA context object.
+ *
+ * Relationship between the enable, target support and if vmid tag is required
+ * for the particular combination
+ * ---------------------------------------------------
+ * Switch Enable Flag Target Support VMID Needed
+ * ---------------------------------------------------
+ * App Id 0 NA N
+ * App Id 1 0 N
+ * App Id 1 1 Y
+ * Pr Tag 0 NA N
+ * Pr Tag 1 0 N
+ * Pr Tag 1 1 Y
+ * Pr Tag 2 * Y
+ ---------------------------------------------------
+ *
+ **/
+static inline int lpfc_is_vmid_enabled(struct lpfc_hba *phba)
+{
+ return phba->cfg_vmid_app_header || phba->cfg_vmid_priority_tagging;
+}
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 0975a8b252a0..eb88aaaf36eb 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -3449,6 +3449,15 @@ LPFC_ATTR_R(fcf_failover_policy, 1, 1, 2,
"FCF Fast failover=1 Priority failover=2");
/*
+ * lpfc_fcp_wait_abts_rsp: Modifies criteria for reporting completion of
+ * aborted IO.
+ * The range is [0,1]. Default value is 0
+ * 0, IO completes after ABTS issued (default).
+ * 1, IO completes after receipt of ABTS response or timeout.
+ */
+LPFC_ATTR_R(fcp_wait_abts_rsp, 0, 0, 1, "Wait for FCP ABTS completion");
+
+/*
# lpfc_enable_rrq: Track XRI/OXID reuse after IO failures
# 0x0 = disabled, XRI/OXID use not tracked.
# 0x1 = XRI/OXID reuse is timed with ratov, RRQ sent.
@@ -6153,6 +6162,45 @@ LPFC_ATTR_RW(enable_dpp, 1, 0, 1, "Enable Direct Packet Push");
*/
LPFC_ATTR_R(enable_mi, 1, 0, 1, "Enable MI");
+/*
+ * lpfc_max_vmid: Maximum number of VMs to be tagged. This is valid only if
+ * either vmid_app_header or vmid_priority_tagging is enabled.
+ * 4 - 255 = vmid support enabled for 4-255 VMs
+ * Value range is [4,255].
+ */
+LPFC_ATTR_RW(max_vmid, LPFC_MIN_VMID, LPFC_MIN_VMID, LPFC_MAX_VMID,
+ "Maximum number of VMs supported");
+
+/*
+ * lpfc_vmid_inactivity_timeout: Inactivity timeout duration in hours
+ * 0 = Timeout is disabled
+ * Value range is [0,24].
+ */
+LPFC_ATTR_RW(vmid_inactivity_timeout, 4, 0, 24,
+ "Inactivity timeout in hours");
+
+/*
+ * lpfc_vmid_app_header: Enable App Header VMID support
+ * 0 = Support is disabled (default)
+ * 1 = Support is enabled
+ * Value range is [0,1].
+ */
+LPFC_ATTR_RW(vmid_app_header, LPFC_VMID_APP_HEADER_DISABLE,
+ LPFC_VMID_APP_HEADER_DISABLE, LPFC_VMID_APP_HEADER_ENABLE,
+ "Enable App Header VMID support");
+
+/*
+ * lpfc_vmid_priority_tagging: Enable Priority Tagging VMID support
+ * 0 = Support is disabled (default)
+ * 1 = Allow supported targets only
+ * 2 = Allow all targets
+ * Value range is [0,2].
+ */
+LPFC_ATTR_RW(vmid_priority_tagging, LPFC_VMID_PRIO_TAG_DISABLE,
+ LPFC_VMID_PRIO_TAG_DISABLE,
+ LPFC_VMID_PRIO_TAG_ALL_TARGETS,
+ "Enable Priority Tagging VMID support");
+
struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_nvme_info,
&dev_attr_scsi_stat,
@@ -6205,6 +6253,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_enable_npiv,
&dev_attr_lpfc_fcf_failover_policy,
&dev_attr_lpfc_enable_rrq,
+ &dev_attr_lpfc_fcp_wait_abts_rsp,
&dev_attr_nport_evt_cnt,
&dev_attr_board_mode,
&dev_attr_max_vpi,
@@ -6271,6 +6320,10 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_enable_bbcr,
&dev_attr_lpfc_enable_dpp,
&dev_attr_lpfc_enable_mi,
+ &dev_attr_lpfc_max_vmid,
+ &dev_attr_lpfc_vmid_inactivity_timeout,
+ &dev_attr_lpfc_vmid_app_header,
+ &dev_attr_lpfc_vmid_priority_tagging,
NULL,
};
@@ -7332,6 +7385,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy);
lpfc_enable_rrq_init(phba, lpfc_enable_rrq);
+ lpfc_fcp_wait_abts_rsp_init(phba, lpfc_fcp_wait_abts_rsp);
lpfc_fdmi_on_init(phba, lpfc_fdmi_on);
lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN);
lpfc_use_msi_init(phba, lpfc_use_msi);
@@ -7346,6 +7400,11 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
lpfc_EnableXLane_init(phba, lpfc_EnableXLane);
+ /* VMID Inits */
+ lpfc_max_vmid_init(phba, lpfc_max_vmid);
+ lpfc_vmid_inactivity_timeout_init(phba, lpfc_vmid_inactivity_timeout);
+ lpfc_vmid_app_header_init(phba, lpfc_vmid_app_header);
+ lpfc_vmid_priority_tagging_init(phba, lpfc_vmid_priority_tagging);
if (phba->sli_rev != LPFC_SLI_REV4)
phba->cfg_EnableXLane = 0;
lpfc_XLanePriority_init(phba, lpfc_XLanePriority);
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 383abf46fd29..737483c3f01d 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -80,6 +80,7 @@ void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbx_cmpl_fc_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb);
void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_unregister_vfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -607,3 +608,14 @@ extern unsigned long lpfc_no_hba_reset[];
extern union lpfc_wqe128 lpfc_iread_cmd_template;
extern union lpfc_wqe128 lpfc_iwrite_cmd_template;
extern union lpfc_wqe128 lpfc_icmnd_cmd_template;
+
+/* vmid interface */
+int lpfc_vmid_uvem(struct lpfc_vport *vport, struct lpfc_vmid *vmid, bool ins);
+uint32_t lpfc_vmid_get_cs_ctl(struct lpfc_vport *vport);
+int lpfc_vmid_cmd(struct lpfc_vport *vport,
+ int cmdcode, struct lpfc_vmid *vmid);
+int lpfc_vmid_hash_fn(const char *vmid, int len);
+struct lpfc_vmid *lpfc_get_vmid_from_hashtable(struct lpfc_vport *vport,
+ uint32_t hash, uint8_t *buf);
+void lpfc_vmid_vport_cleanup(struct lpfc_vport *vport);
+int lpfc_issue_els_qfpa(struct lpfc_vport *vport);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 3bbefa225484..610b6dabb3b5 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -75,6 +75,9 @@
static char *lpfc_release_version = LPFC_DRIVER_VERSION;
+static void
+lpfc_cmpl_ct_cmd_vmid(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb);
static void
lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
@@ -587,7 +590,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *),
- struct lpfc_nodelist *ndlp, uint32_t usr_flg, uint32_t num_entry,
+ struct lpfc_nodelist *ndlp, uint32_t event_tag, uint32_t num_entry,
uint32_t tmo, uint8_t retry)
{
struct lpfc_hba *phba = vport->phba;
@@ -608,15 +611,14 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64));
- if (usr_flg)
- geniocb->context3 = NULL;
- else
- geniocb->context3 = (uint8_t *) bmp;
+ geniocb->context3 = (uint8_t *) bmp;
/* Save for completion so we can release these resources */
geniocb->context1 = (uint8_t *) inp;
geniocb->context2 = (uint8_t *) outp;
+ geniocb->event_tag = event_tag;
+
/* Fill in payload, bp points to frame payload */
icmd->ulpCommand = CMD_GEN_REQUEST64_CR;
@@ -707,8 +709,8 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
* lpfc_alloc_ct_rsp.
*/
cnt += 1;
- status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, 0,
- cnt, 0, retry);
+ status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp,
+ phba->fc_eventTag, cnt, 0, retry);
if (status) {
lpfc_free_ct_rsp(phba, outmp);
return -ENOMEM;
@@ -957,6 +959,13 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
"GID_FT cmpl: status:x%x/x%x rtry:%d",
irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_ns_retry);
+ /* Ignore response if link flipped after this request was made */
+ if (cmdiocb->event_tag != phba->fc_eventTag) {
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "9043 Event tag mismatch. Ignoring NS rsp\n");
+ goto out;
+ }
+
/* Don't bother processing response if vport is being torn down. */
if (vport->load_flag & FC_UNLOADING) {
if (vport->fc_flag & FC_RSCN_MODE)
@@ -1167,6 +1176,13 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
irsp->ulpStatus, irsp->un.ulpWord[4],
vport->fc_ns_retry);
+ /* Ignore response if link flipped after this request was made */
+ if (cmdiocb->event_tag != phba->fc_eventTag) {
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "9044 Event tag mismatch. Ignoring NS rsp\n");
+ goto out;
+ }
+
/* Don't bother processing response if vport is being torn down. */
if (vport->load_flag & FC_UNLOADING) {
if (vport->fc_flag & FC_RSCN_MODE)
@@ -1366,6 +1382,13 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
"GFF_ID cmpl: status:x%x/x%x did:x%x",
irsp->ulpStatus, irsp->un.ulpWord[4], did);
+ /* Ignore response if link flipped after this request was made */
+ if (cmdiocb->event_tag != phba->fc_eventTag) {
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "9045 Event tag mismatch. Ignoring NS rsp\n");
+ goto iocb_free;
+ }
+
if (irsp->ulpStatus == IOSTAT_SUCCESS) {
/* Good status, continue checking */
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
@@ -1479,6 +1502,7 @@ out:
lpfc_disc_start(vport);
}
+iocb_free:
free_ndlp = cmdiocb->context_un.ndlp;
lpfc_ct_free_iocb(phba, cmdiocb);
lpfc_nlp_put(free_ndlp);
@@ -1506,6 +1530,13 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
"GFT_ID cmpl: status:x%x/x%x did:x%x",
irsp->ulpStatus, irsp->un.ulpWord[4], did);
+ /* Ignore response if link flipped after this request was made */
+ if ((uint32_t) cmdiocb->event_tag != phba->fc_eventTag) {
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "9046 Event tag mismatch. Ignoring NS rsp\n");
+ goto out;
+ }
+
/* Preserve the nameserver node to release the reference. */
ns_ndlp = cmdiocb->context_un.ndlp;
@@ -1572,6 +1603,7 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
"3065 GFT_ID failed x%08x\n", irsp->ulpStatus);
+out:
lpfc_ct_free_iocb(phba, cmdiocb);
lpfc_nlp_put(ns_ndlp);
}
@@ -3748,3 +3780,255 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
}
return;
}
+
+static void
+lpfc_cmpl_ct_cmd_vmid(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct lpfc_dmabuf *inp = cmdiocb->context1;
+ struct lpfc_dmabuf *outp = cmdiocb->context2;
+ struct lpfc_sli_ct_request *ctcmd = inp->virt;
+ struct lpfc_sli_ct_request *ctrsp = outp->virt;
+ u16 rsp = ctrsp->CommandResponse.bits.CmdRsp;
+ struct app_id_object *app;
+ u32 cmd, hash, bucket;
+ struct lpfc_vmid *vmp, *cur;
+ u8 *data = outp->virt;
+ int i;
+
+ cmd = be16_to_cpu(ctcmd->CommandResponse.bits.CmdRsp);
+ if (cmd == SLI_CTAS_DALLAPP_ID)
+ lpfc_ct_free_iocb(phba, cmdiocb);
+
+ if (lpfc_els_chk_latt(vport) || rspiocb->iocb.ulpStatus) {
+ if (cmd != SLI_CTAS_DALLAPP_ID)
+ return;
+ }
+ /* Check for a CT LS_RJT response */
+ if (rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
+ if (cmd != SLI_CTAS_DALLAPP_ID)
+ lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+ "3306 VMID FS_RJT Data: x%x x%x x%x\n",
+ cmd, ctrsp->ReasonCode,
+ ctrsp->Explanation);
+ if ((cmd != SLI_CTAS_DALLAPP_ID) ||
+ (ctrsp->ReasonCode != SLI_CT_UNABLE_TO_PERFORM_REQ) ||
+ (ctrsp->Explanation != SLI_CT_APP_ID_NOT_AVAILABLE)) {
+ /* If DALLAPP_ID failed retry later */
+ if (cmd == SLI_CTAS_DALLAPP_ID)
+ vport->load_flag |= FC_DEREGISTER_ALL_APP_ID;
+ return;
+ }
+ }
+
+ switch (cmd) {
+ case SLI_CTAS_RAPP_IDENT:
+ app = (struct app_id_object *)(RAPP_IDENT_OFFSET + data);
+ lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+ "6712 RAPP_IDENT app id %d port id x%x id "
+ "len %d\n", be32_to_cpu(app->app_id),
+ be32_to_cpu(app->port_id),
+ app->obj.entity_id_len);
+
+ if (app->obj.entity_id_len == 0 || app->port_id == 0)
+ return;
+
+ hash = lpfc_vmid_hash_fn(app->obj.entity_id,
+ app->obj.entity_id_len);
+ vmp = lpfc_get_vmid_from_hashtable(vport, hash,
+ app->obj.entity_id);
+ if (vmp) {
+ write_lock(&vport->vmid_lock);
+ vmp->un.app_id = be32_to_cpu(app->app_id);
+ vmp->flag |= LPFC_VMID_REGISTERED;
+ vmp->flag &= ~LPFC_VMID_REQ_REGISTER;
+ write_unlock(&vport->vmid_lock);
+ /* Set IN USE flag */
+ vport->vmid_flag |= LPFC_VMID_IN_USE;
+ } else {
+ lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+ "6901 No entry found %s hash %d\n",
+ app->obj.entity_id, hash);
+ }
+ break;
+ case SLI_CTAS_DAPP_IDENT:
+ app = (struct app_id_object *)(DAPP_IDENT_OFFSET + data);
+ lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+ "6713 DAPP_IDENT app id %d port id x%x\n",
+ be32_to_cpu(app->app_id),
+ be32_to_cpu(app->port_id));
+ break;
+ case SLI_CTAS_DALLAPP_ID:
+ lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+ "8856 Deregistered all app ids\n");
+ read_lock(&vport->vmid_lock);
+ for (i = 0; i < phba->cfg_max_vmid; i++) {
+ vmp = &vport->vmid[i];
+ if (vmp->flag != LPFC_VMID_SLOT_FREE)
+ memset(vmp, 0, sizeof(struct lpfc_vmid));
+ }
+ read_unlock(&vport->vmid_lock);
+ /* for all elements in the hash table */
+ if (!hash_empty(vport->hash_table))
+ hash_for_each(vport->hash_table, bucket, cur, hnode)
+ hash_del(&cur->hnode);
+ vport->load_flag |= FC_ALLOW_VMID;
+ break;
+ default:
+ lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+ "8857 Invalid command code\n");
+ }
+}
+
+/**
+ * lpfc_vmid_cmd - Build and send a FDMI cmd to the specified NPort
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @ndlp: ndlp to send FDMI cmd to (if NULL use FDMI_DID)
+ * cmdcode: FDMI command to send
+ * mask: Mask of HBA or PORT Attributes to send
+ *
+ * Builds and sends a FDMI command using the CT subsystem.
+ */
+int
+lpfc_vmid_cmd(struct lpfc_vport *vport,
+ int cmdcode, struct lpfc_vmid *vmid)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_dmabuf *mp, *bmp;
+ struct lpfc_sli_ct_request *ctreq;
+ struct ulp_bde64 *bpl;
+ u32 size;
+ u32 rsp_size;
+ u8 *data;
+ struct lpfc_vmid_rapp_ident_list *rap;
+ struct lpfc_vmid_dapp_ident_list *dap;
+ u8 retry = 0;
+ struct lpfc_nodelist *ndlp;
+
+ void (*cmpl)(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb);
+
+ ndlp = lpfc_findnode_did(vport, FDMI_DID);
+ if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
+ return 0;
+
+ cmpl = lpfc_cmpl_ct_cmd_vmid;
+
+ /* fill in BDEs for command */
+ /* Allocate buffer for command payload */
+ mp = kmalloc(sizeof(*mp), GFP_KERNEL);
+ if (!mp)
+ goto vmid_free_mp_exit;
+
+ mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+ if (!mp->virt)
+ goto vmid_free_mp_virt_exit;
+
+ /* Allocate buffer for Buffer ptr list */
+ bmp = kmalloc(sizeof(*bmp), GFP_KERNEL);
+ if (!bmp)
+ goto vmid_free_bmp_exit;
+
+ bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
+ if (!bmp->virt)
+ goto vmid_free_bmp_virt_exit;
+
+ INIT_LIST_HEAD(&mp->list);
+ INIT_LIST_HEAD(&bmp->list);
+
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ "3275 VMID Request Data: x%x x%x x%x\n",
+ vport->fc_flag, vport->port_state, cmdcode);
+ ctreq = (struct lpfc_sli_ct_request *)mp->virt;
+ data = mp->virt;
+ /* First populate the CT_IU preamble */
+ memset(data, 0, LPFC_BPL_SIZE);
+ ctreq->RevisionId.bits.Revision = SLI_CT_REVISION;
+ ctreq->RevisionId.bits.InId = 0;
+
+ ctreq->FsType = SLI_CT_MANAGEMENT_SERVICE;
+ ctreq->FsSubType = SLI_CT_APP_SEV_Subtypes;
+
+ ctreq->CommandResponse.bits.CmdRsp = cpu_to_be16(cmdcode);
+ rsp_size = LPFC_BPL_SIZE;
+ size = 0;
+
+ switch (cmdcode) {
+ case SLI_CTAS_RAPP_IDENT:
+ lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+ "1329 RAPP_IDENT for %s\n", vmid->host_vmid);
+ ctreq->un.PortID = cpu_to_be32(vport->fc_myDID);
+ rap = (struct lpfc_vmid_rapp_ident_list *)
+ (DAPP_IDENT_OFFSET + data);
+ rap->no_of_objects = cpu_to_be32(1);
+ rap->obj[0].entity_id_len = vmid->vmid_len;
+ memcpy(rap->obj[0].entity_id, vmid->host_vmid, vmid->vmid_len);
+ size = RAPP_IDENT_OFFSET +
+ sizeof(struct lpfc_vmid_rapp_ident_list);
+ retry = 1;
+ break;
+
+ case SLI_CTAS_GALLAPPIA_ID:
+ ctreq->un.PortID = cpu_to_be32(vport->fc_myDID);
+ size = GALLAPPIA_ID_SIZE;
+ break;
+
+ case SLI_CTAS_DAPP_IDENT:
+ lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+ "1469 DAPP_IDENT for %s\n", vmid->host_vmid);
+ ctreq->un.PortID = cpu_to_be32(vport->fc_myDID);
+ dap = (struct lpfc_vmid_dapp_ident_list *)
+ (DAPP_IDENT_OFFSET + data);
+ dap->no_of_objects = cpu_to_be32(1);
+ dap->obj[0].entity_id_len = vmid->vmid_len;
+ memcpy(dap->obj[0].entity_id, vmid->host_vmid, vmid->vmid_len);
+ size = DAPP_IDENT_OFFSET +
+ sizeof(struct lpfc_vmid_dapp_ident_list);
+ write_lock(&vport->vmid_lock);
+ vmid->flag &= ~LPFC_VMID_REGISTERED;
+ write_unlock(&vport->vmid_lock);
+ retry = 1;
+ break;
+
+ case SLI_CTAS_DALLAPP_ID:
+ ctreq->un.PortID = cpu_to_be32(vport->fc_myDID);
+ size = DALLAPP_ID_SIZE;
+ break;
+
+ default:
+ lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+ "7062 VMID cmdcode x%x not supported\n",
+ cmdcode);
+ goto vmid_free_all_mem;
+ }
+
+ ctreq->CommandResponse.bits.Size = cpu_to_be16(rsp_size);
+
+ bpl = (struct ulp_bde64 *)bmp->virt;
+ bpl->addrHigh = putPaddrHigh(mp->phys);
+ bpl->addrLow = putPaddrLow(mp->phys);
+ bpl->tus.f.bdeFlags = 0;
+ bpl->tus.f.bdeSize = size;
+
+ /* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count
+ * to hold ndlp reference for the corresponding callback function.
+ */
+ if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry))
+ return 0;
+
+ vmid_free_all_mem:
+ lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+ vmid_free_bmp_virt_exit:
+ kfree(bmp);
+ vmid_free_bmp_exit:
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ vmid_free_mp_virt_exit:
+ kfree(mp);
+ vmid_free_mp_exit:
+
+ /* Issue CT request failed */
+ lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+ "3276 VMID CT request failed Data: x%x\n", cmdcode);
+ return -EIO;
+}
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 658a962832b3..6ff85ae57e79 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -863,16 +863,13 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
len += scnprintf(buf+len, size-len, "%s DID:x%06x ",
statep, ndlp->nlp_DID);
len += scnprintf(buf+len, size-len,
- "WWPN x%llx ",
+ "WWPN x%016llx ",
wwn_to_u64(ndlp->nlp_portname.u.wwn));
len += scnprintf(buf+len, size-len,
- "WWNN x%llx ",
+ "WWNN x%016llx ",
wwn_to_u64(ndlp->nlp_nodename.u.wwn));
- if (ndlp->nlp_flag & NLP_RPI_REGISTERED)
- len += scnprintf(buf+len, size-len, "RPI:%04d ",
- ndlp->nlp_rpi);
- else
- len += scnprintf(buf+len, size-len, "RPI:none ");
+ len += scnprintf(buf+len, size-len, "RPI:x%04x ",
+ ndlp->nlp_rpi);
len += scnprintf(buf+len, size-len, "flag:x%08x ",
ndlp->nlp_flag);
if (!ndlp->nlp_type)
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 08999aad6a10..131374a61d7e 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -86,6 +86,7 @@ enum lpfc_fc4_xpt_flags {
struct lpfc_nodelist {
struct list_head nlp_listp;
+ struct serv_parm fc_sparam; /* buffer for service params */
struct lpfc_name nlp_portname;
struct lpfc_name nlp_nodename;
@@ -124,6 +125,7 @@ struct lpfc_nodelist {
uint8_t nlp_fcp_info; /* class info, bits 0-3 */
#define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */
u8 nlp_nvme_info; /* NVME NSLER Support */
+ uint8_t vmid_support; /* destination VMID support */
#define NLP_NVME_NSLER 0x1 /* NVME NSLER device */
struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 21108f322c99..e481f5fe29d7 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -25,6 +25,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
@@ -55,9 +56,15 @@ static int lpfc_issue_els_fdisc(struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp, uint8_t retry);
static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba,
struct lpfc_iocbq *iocb);
+static void lpfc_cmpl_els_uvem(struct lpfc_hba *, struct lpfc_iocbq *,
+ struct lpfc_iocbq *);
static int lpfc_max_els_tries = 3;
+static void lpfc_init_cs_ctl_bitmap(struct lpfc_vport *vport);
+static void lpfc_vmid_set_cs_ctl_range(struct lpfc_vport *vport, u32 min, u32 max);
+static void lpfc_vmid_put_cs_ctl(struct lpfc_vport *vport, u32 ctcl_vmid);
+
/**
* lpfc_els_chk_latt - Check host link attention event for a vport
* @vport: pointer to a host virtual N_Port data structure.
@@ -314,10 +321,10 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0116 Xmit ELS command x%x to remote "
"NPORT x%x I/O tag: x%x, port state:x%x "
- "rpi x%x fc_flag:x%x\n",
+ "rpi x%x fc_flag:x%x nlp_flag:x%x vport:x%p\n",
elscmd, did, elsiocb->iotag,
vport->port_state, ndlp->nlp_rpi,
- vport->fc_flag);
+ vport->fc_flag, ndlp->nlp_flag, vport);
} else {
/* Xmit ELS response <elsCmd> to remote NPORT <did> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
@@ -1112,11 +1119,15 @@ stop_rr_fcf_flogi:
/* FLOGI completes successfully */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0101 FLOGI completes successfully, I/O tag:x%x, "
- "xri x%x Data: x%x x%x x%x x%x x%x %x\n",
+ "xri x%x Data: x%x x%x x%x x%x x%x x%x x%x\n",
cmdiocb->iotag, cmdiocb->sli4_xritag,
irsp->un.ulpWord[4], sp->cmn.e_d_tov,
sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution,
- vport->port_state, vport->fc_flag);
+ vport->port_state, vport->fc_flag,
+ sp->cmn.priority_tagging);
+
+ if (sp->cmn.priority_tagging)
+ vport->vmid_flag |= LPFC_VMID_ISSUE_QFPA;
if (vport->port_state == LPFC_FLOGI) {
/*
@@ -1175,6 +1186,15 @@ stop_rr_fcf_flogi:
phba->fcf.fcf_redisc_attempted = 0; /* reset */
goto out;
}
+ } else if (vport->port_state > LPFC_FLOGI &&
+ vport->fc_flag & FC_PT2PT) {
+ /*
+ * In a p2p topology, it is possible that discovery has
+ * already progressed, and this completion can be ignored.
+ * Recheck the indicated topology.
+ */
+ if (!sp->cmn.fPort)
+ goto out;
}
flogifail:
@@ -1299,6 +1319,18 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (sp->cmn.fcphHigh < FC_PH3)
sp->cmn.fcphHigh = FC_PH3;
+ /* Determine if switch supports priority tagging */
+ if (phba->cfg_vmid_priority_tagging) {
+ sp->cmn.priority_tagging = 1;
+ /* lpfc_vmid_host_uuid is combination of wwpn and wwnn */
+ if (uuid_is_null((uuid_t *)vport->lpfc_vmid_host_uuid)) {
+ memcpy(vport->lpfc_vmid_host_uuid, phba->wwpn,
+ sizeof(phba->wwpn));
+ memcpy(&vport->lpfc_vmid_host_uuid[8], phba->wwnn,
+ sizeof(phba->wwnn));
+ }
+ }
+
if (phba->sli_rev == LPFC_SLI_REV4) {
if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
LPFC_SLI_INTF_IF_TYPE_0) {
@@ -1925,6 +1957,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_nodelist *ndlp, *free_ndlp;
struct lpfc_dmabuf *prsp;
int disc;
+ struct serv_parm *sp = NULL;
/* we pass cmdiocb to state machine which needs rspiocb as well */
cmdiocb->context_un.rsp_iocb = rspiocb;
@@ -1998,9 +2031,20 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_disc_state_machine(vport, ndlp, cmdiocb,
NLP_EVT_CMPL_PLOGI);
- /* As long as this node is not registered with the scsi or nvme
- * transport, it is no longer an active node. Otherwise
- * devloss handles the final cleanup.
+ /* If a PLOGI collision occurred, the node needs to continue
+ * with the reglogin process.
+ */
+ spin_lock_irq(&ndlp->lock);
+ if ((ndlp->nlp_flag & (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI)) &&
+ ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE) {
+ spin_unlock_irq(&ndlp->lock);
+ goto out;
+ }
+ spin_unlock_irq(&ndlp->lock);
+
+ /* No PLOGI collision and the node is not registered with the
+ * scsi or nvme transport. It is no longer an active node. Just
+ * start the device remove process.
*/
if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) {
spin_lock_irq(&ndlp->lock);
@@ -2015,6 +2059,23 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
cmdiocb->context2)->list.next,
struct lpfc_dmabuf, list);
ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp);
+
+ sp = (struct serv_parm *)((u8 *)prsp->virt +
+ sizeof(u32));
+
+ ndlp->vmid_support = 0;
+ if ((phba->cfg_vmid_app_header && sp->cmn.app_hdr_support) ||
+ (phba->cfg_vmid_priority_tagging &&
+ sp->cmn.priority_tagging)) {
+ lpfc_printf_log(phba, KERN_DEBUG, LOG_ELS,
+ "4018 app_hdr_support %d tagging %d DID x%x\n",
+ sp->cmn.app_hdr_support,
+ sp->cmn.priority_tagging,
+ ndlp->nlp_DID);
+ /* if the dest port supports VMID, mark it in ndlp */
+ ndlp->vmid_support = 1;
+ }
+
lpfc_disc_state_machine(vport, ndlp, cmdiocb,
NLP_EVT_CMPL_PLOGI);
}
@@ -2137,6 +2198,14 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
memset(sp->un.vendorVersion, 0, sizeof(sp->un.vendorVersion));
sp->cmn.bbRcvSizeMsb &= 0xF;
+ /* Check if the destination port supports VMID */
+ ndlp->vmid_support = 0;
+ if (vport->vmid_priority_tagging)
+ sp->cmn.priority_tagging = 1;
+ else if (phba->cfg_vmid_app_header &&
+ bf_get(lpfc_ftr_ashdr, &phba->sli4_hba.sli4_flags))
+ sp->cmn.app_hdr_support = 1;
+
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
"Issue PLOGI: did:x%x",
did, 0, 0);
@@ -2869,6 +2938,11 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* log into the remote port.
*/
if (ndlp->nlp_flag & NLP_TARGET_REMOVE) {
+ spin_lock_irq(&ndlp->lock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ ndlp->nlp_flag |= NLP_RELEASE_RPI;
+ ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+ spin_unlock_irq(&ndlp->lock);
lpfc_disc_state_machine(vport, ndlp, cmdiocb,
NLP_EVT_DEVICE_RM);
lpfc_els_free_iocb(phba, cmdiocb);
@@ -3061,6 +3135,95 @@ lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
/**
+ * lpfc_reg_fab_ctrl_node - RPI register the fabric controller node.
+ * @vport: pointer to lpfc_vport data structure.
+ * @fc_ndlp: pointer to the fabric controller (0xfffffd) node.
+ *
+ * This routine registers the rpi assigned to the fabric controller
+ * NPort_ID (0xfffffd) with the port and moves the node to UNMAPPED
+ * state triggering a registration with the SCSI transport.
+ *
+ * This routine is single out because the fabric controller node
+ * does not receive a PLOGI. This routine is consumed by the
+ * SCR and RDF ELS commands. Callers are expected to qualify
+ * with SLI4 first.
+ **/
+static int
+lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp)
+{
+ int rc = 0;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *ns_ndlp;
+ LPFC_MBOXQ_t *mbox;
+ struct lpfc_dmabuf *mp;
+
+ if (fc_ndlp->nlp_flag & NLP_RPI_REGISTERED)
+ return rc;
+
+ ns_ndlp = lpfc_findnode_did(vport, NameServer_DID);
+ if (!ns_ndlp)
+ return -ENODEV;
+
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+ "0935 %s: Reg FC RPI x%x on FC DID x%x NSSte: x%x\n",
+ __func__, fc_ndlp->nlp_rpi, fc_ndlp->nlp_DID,
+ ns_ndlp->nlp_state);
+ if (ns_ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
+ return -ENODEV;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
+ "0936 %s: no memory for reg_login "
+ "Data: x%x x%x x%x x%x\n", __func__,
+ fc_ndlp->nlp_DID, fc_ndlp->nlp_state,
+ fc_ndlp->nlp_flag, fc_ndlp->nlp_rpi);
+ return -ENOMEM;
+ }
+ rc = lpfc_reg_rpi(phba, vport->vpi, fc_ndlp->nlp_DID,
+ (u8 *)&vport->fc_sparam, mbox, fc_ndlp->nlp_rpi);
+ if (rc) {
+ rc = -EACCES;
+ goto out;
+ }
+
+ fc_ndlp->nlp_flag |= NLP_REG_LOGIN_SEND;
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_fc_reg_login;
+ mbox->ctx_ndlp = lpfc_nlp_get(fc_ndlp);
+ if (!mbox->ctx_ndlp) {
+ rc = -ENOMEM;
+ goto out_mem;
+ }
+
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ rc = -ENODEV;
+ lpfc_nlp_put(fc_ndlp);
+ goto out_mem;
+ }
+ /* Success path. Exit. */
+ lpfc_nlp_set_state(vport, fc_ndlp,
+ NLP_STE_REG_LOGIN_ISSUE);
+ return 0;
+
+ out_mem:
+ fc_ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
+ mp = (struct lpfc_dmabuf *)mbox->ctx_buf;
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+
+ out:
+ mempool_free(mbox, phba->mbox_mem_pool);
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
+ "0938 %s: failed to format reg_login "
+ "Data: x%x x%x x%x x%x\n", __func__,
+ fc_ndlp->nlp_DID, fc_ndlp->nlp_state,
+ fc_ndlp->nlp_flag, fc_ndlp->nlp_rpi);
+ return rc;
+}
+
+/**
* lpfc_cmpl_els_disc_cmd - Completion callback function for Discovery ELS cmd
* @phba: pointer to lpfc hba data structure.
* @cmdiocb: pointer to lpfc command iocb data structure.
@@ -3206,10 +3369,18 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry)
elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
ndlp->nlp_DID, ELS_CMD_SCR);
-
if (!elsiocb)
return 1;
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ rc = lpfc_reg_fab_ctrl_node(vport, ndlp);
+ if (rc) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
+ "0937 %s: Failed to reg fc node, rc %d\n",
+ __func__, rc);
+ return 1;
+ }
+ }
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_SCR;
@@ -3497,6 +3668,17 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
if (!elsiocb)
return -ENOMEM;
+ if (phba->sli_rev == LPFC_SLI_REV4 &&
+ !(ndlp->nlp_flag & NLP_RPI_REGISTERED)) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
+ "0939 %s: FC_NODE x%x RPI x%x flag x%x "
+ "ste x%x type x%x Not registered\n",
+ __func__, ndlp->nlp_DID, ndlp->nlp_rpi,
+ ndlp->nlp_flag, ndlp->nlp_state,
+ ndlp->nlp_type);
+ return -ENODEV;
+ }
+
/* Configure the payload for the supported FPIN events. */
prdf = (struct lpfc_els_rdf_req *)
(((struct lpfc_dmabuf *)elsiocb->context2)->virt);
@@ -3537,6 +3719,43 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
return 0;
}
+ /**
+ * lpfc_els_rcv_rdf - Receive RDF ELS request from the fabric.
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @cmdiocb: pointer to lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * A received RDF implies a possible change to fabric supported diagnostic
+ * functions. This routine sends LS_ACC and then has the Nx_Port issue a new
+ * RDF request to reregister for supported diagnostic functions.
+ *
+ * Return code
+ * 0 - Success
+ * -EIO - Failed to process received RDF
+ **/
+static int
+lpfc_els_rcv_rdf(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
+{
+ /* Send LS_ACC */
+ if (lpfc_els_rsp_acc(vport, ELS_CMD_RDF, cmdiocb, ndlp, NULL)) {
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "1623 Failed to RDF_ACC from x%x for x%x\n",
+ ndlp->nlp_DID, vport->fc_myDID);
+ return -EIO;
+ }
+
+ /* Issue new RDF for reregistering */
+ if (lpfc_issue_els_rdf(vport, 0)) {
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "2623 Failed to re register RDF for x%x\n",
+ vport->fc_myDID);
+ return -EIO;
+ }
+
+ return 0;
+}
+
/**
* lpfc_cancel_retry_delay_tmo - Cancel the timer with delayed iocb-cmd retry
* @vport: pointer to a host virtual N_Port data structure.
@@ -4383,12 +4602,27 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp->nlp_flag,
ndlp->nlp_state, ndlp->nlp_rpi);
+ /* This clause allows the LOGO ACC to complete and free resources
+ * for the Fabric Domain Controller. It does deliberately skip
+ * the unreg_rpi and release rpi because some fabrics send RDP
+ * requests after logging out from the initiator.
+ */
+ if (ndlp->nlp_type & NLP_FABRIC &&
+ ((ndlp->nlp_DID & WELL_KNOWN_DID_MASK) != WELL_KNOWN_DID_MASK))
+ goto out;
+
if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
/* NPort Recovery mode or node is just allocated */
if (!lpfc_nlp_not_used(ndlp)) {
- /* If the ndlp is being used by another discovery
- * thread, just unregister the RPI.
+ /* A LOGO is completing and the node is in NPR state.
+ * If this a fabric node that cleared its transport
+ * registration, release the rpi.
*/
+ spin_lock_irq(&ndlp->lock);
+ ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ ndlp->nlp_flag |= NLP_RELEASE_RPI;
+ spin_unlock_irq(&ndlp->lock);
lpfc_unreg_rpi(vport, ndlp);
} else {
/* Indicate the node has already released, should
@@ -4397,7 +4631,7 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
cmdiocb->context1 = NULL;
}
}
-
+ out:
/*
* The driver received a LOGO from the rport and has ACK'd it.
* At this point, the driver is done so release the IOCB
@@ -4424,28 +4658,37 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
+ u32 mbx_flag = pmb->mbox_flag;
+ u32 mbx_cmd = pmb->u.mb.mbxCommand;
pmb->ctx_buf = NULL;
pmb->ctx_ndlp = NULL;
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(pmb, phba->mbox_mem_pool);
if (ndlp) {
lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE,
- "0006 rpi x%x DID:%x flg:%x %d x%px\n",
+ "0006 rpi x%x DID:%x flg:%x %d x%px "
+ "mbx_cmd x%x mbx_flag x%x x%px\n",
ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag,
- kref_read(&ndlp->kref),
- ndlp);
- /* This is the end of the default RPI cleanup logic for
- * this ndlp and it could get released. Clear the nlp_flags to
- * prevent any further processing.
+ kref_read(&ndlp->kref), ndlp, mbx_cmd,
+ mbx_flag, pmb);
+
+ /* This ends the default/temporary RPI cleanup logic for this
+ * ndlp and the node and rpi needs to be released. Free the rpi
+ * first on an UNREG_LOGIN and then release the final
+ * references.
*/
+ spin_lock_irq(&ndlp->lock);
ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
+ if (mbx_cmd == MBX_UNREG_LOGIN)
+ ndlp->nlp_flag &= ~NLP_UNREG_INP;
+ spin_unlock_irq(&ndlp->lock);
lpfc_nlp_put(ndlp);
- lpfc_nlp_not_used(ndlp);
+ lpfc_drop_node(ndlp->vport, ndlp);
}
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
}
@@ -4503,11 +4746,11 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* ELS response tag <ulpIoTag> completes */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0110 ELS response tag x%x completes "
- "Data: x%x x%x x%x x%x x%x x%x x%x\n",
+ "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%px\n",
cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
- ndlp->nlp_rpi);
+ ndlp->nlp_rpi, kref_read(&ndlp->kref), mbox);
if (mbox) {
if ((rspiocb->iocb.ulpStatus == 0) &&
(ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
@@ -4587,6 +4830,20 @@ out:
spin_unlock_irq(&ndlp->lock);
}
+ /* An SLI4 NPIV instance wants to drop the node at this point under
+ * these conditions and release the RPI.
+ */
+ if (phba->sli_rev == LPFC_SLI_REV4 &&
+ (vport && vport->port_type == LPFC_NPIV_PORT) &&
+ ndlp->nlp_flag & NLP_RELEASE_RPI) {
+ lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi);
+ spin_lock_irq(&ndlp->lock);
+ ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
+ ndlp->nlp_flag &= ~NLP_RELEASE_RPI;
+ spin_unlock_irq(&ndlp->lock);
+ lpfc_drop_node(vport, ndlp);
+ }
+
/* Release the originating I/O reference. */
lpfc_els_free_iocb(phba, cmdiocb);
lpfc_nlp_put(ndlp);
@@ -4632,6 +4889,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
uint16_t cmdsize;
int rc;
ELS_PKT *els_pkt_ptr;
+ struct fc_els_rdf_resp *rdf_resp;
oldcmd = &oldiocb->iocb;
@@ -4743,6 +5001,29 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
"Issue ACC PRLO: did:x%x flg:x%x",
ndlp->nlp_DID, ndlp->nlp_flag, 0);
break;
+ case ELS_CMD_RDF:
+ cmdsize = sizeof(*rdf_resp);
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
+ ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
+ if (!elsiocb)
+ return 1;
+
+ icmd = &elsiocb->iocb;
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
+ pcmd = (((struct lpfc_dmabuf *)elsiocb->context2)->virt);
+ rdf_resp = (struct fc_els_rdf_resp *)pcmd;
+ memset(rdf_resp, 0, sizeof(*rdf_resp));
+ rdf_resp->acc_hdr.la_cmd = ELS_LS_ACC;
+
+ /* FC-LS-5 specifies desc_list_len shall be set to 12 */
+ rdf_resp->desc_list_len = cpu_to_be32(12);
+
+ /* FC-LS-5 specifies LS REQ Information descriptor */
+ rdf_resp->lsri.desc_tag = cpu_to_be32(1);
+ rdf_resp->lsri.desc_len = cpu_to_be32(sizeof(u32));
+ rdf_resp->lsri.rqst_w0.cmd = ELS_RDF;
+ break;
default:
return 1;
}
@@ -4775,10 +5056,10 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0128 Xmit ELS ACC response Status: x%x, IoTag: x%x, "
"XRI: x%x, DID: x%x, nlp_flag: x%x nlp_state: x%x "
- "RPI: x%x, fc_flag x%x\n",
+ "RPI: x%x, fc_flag x%x refcnt %d\n",
rc, elsiocb->iotag, elsiocb->sli4_xritag,
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
- ndlp->nlp_rpi, vport->fc_flag);
+ ndlp->nlp_rpi, vport->fc_flag, kref_read(&ndlp->kref));
return 0;
}
@@ -4856,6 +5137,17 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
return 1;
}
+ /* The NPIV instance is rejecting this unsolicited ELS. Make sure the
+ * node's assigned RPI needs to be released as this node will get
+ * freed.
+ */
+ if (phba->sli_rev == LPFC_SLI_REV4 &&
+ vport->port_type == LPFC_NPIV_PORT) {
+ spin_lock_irq(&ndlp->lock);
+ ndlp->nlp_flag |= NLP_RELEASE_RPI;
+ spin_unlock_irq(&ndlp->lock);
+ }
+
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
@@ -8845,6 +9137,20 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
/* There are no replies, so no rjt codes */
break;
+ case ELS_CMD_RDF:
+ phba->fc_stat.elsRcvRDF++;
+ /* Accept RDF only from fabric controller */
+ if (did != Fabric_Cntl_DID) {
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS,
+ "1115 Received RDF from invalid DID "
+ "x%x\n", did);
+ rjt_err = LSRJT_PROTOCOL_ERR;
+ rjt_exp = LSEXP_NOTHING_MORE;
+ goto lsrjt;
+ }
+
+ lpfc_els_rcv_rdf(vport, elsiocb, ndlp);
+ break;
default:
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
"RCV ELS cmd: cmd:x%x did:x%x/ste:x%x",
@@ -10208,3 +10514,312 @@ lpfc_sli_abts_recover_port(struct lpfc_vport *vport,
lpfc_unreg_rpi(vport, ndlp);
}
+static void lpfc_init_cs_ctl_bitmap(struct lpfc_vport *vport)
+{
+ bitmap_zero(vport->vmid_priority_range, LPFC_VMID_MAX_PRIORITY_RANGE);
+}
+
+static void
+lpfc_vmid_set_cs_ctl_range(struct lpfc_vport *vport, u32 min, u32 max)
+{
+ u32 i;
+
+ if ((min > max) || (max > LPFC_VMID_MAX_PRIORITY_RANGE))
+ return;
+
+ for (i = min; i <= max; i++)
+ set_bit(i, vport->vmid_priority_range);
+}
+
+static void lpfc_vmid_put_cs_ctl(struct lpfc_vport *vport, u32 ctcl_vmid)
+{
+ set_bit(ctcl_vmid, vport->vmid_priority_range);
+}
+
+u32 lpfc_vmid_get_cs_ctl(struct lpfc_vport *vport)
+{
+ u32 i;
+
+ i = find_first_bit(vport->vmid_priority_range,
+ LPFC_VMID_MAX_PRIORITY_RANGE);
+
+ if (i == LPFC_VMID_MAX_PRIORITY_RANGE)
+ return 0;
+
+ clear_bit(i, vport->vmid_priority_range);
+ return i;
+}
+
+#define MAX_PRIORITY_DESC 255
+
+static void
+lpfc_cmpl_els_qfpa(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct priority_range_desc *desc;
+ struct lpfc_dmabuf *prsp = NULL;
+ struct lpfc_vmid_priority_range *vmid_range = NULL;
+ u32 *data;
+ struct lpfc_dmabuf *dmabuf = cmdiocb->context2;
+ IOCB_t *irsp = &rspiocb->iocb;
+ u8 *pcmd, max_desc;
+ u32 len, i;
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)cmdiocb->context1;
+
+ prsp = list_get_first(&dmabuf->list, struct lpfc_dmabuf, list);
+ if (!prsp)
+ goto out;
+
+ pcmd = prsp->virt;
+ data = (u32 *)pcmd;
+ if (data[0] == ELS_CMD_LS_RJT) {
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_SLI,
+ "3277 QFPA LS_RJT x%x x%x\n",
+ data[0], data[1]);
+ goto out;
+ }
+ if (irsp->ulpStatus) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI,
+ "6529 QFPA failed with status x%x x%x\n",
+ irsp->ulpStatus, irsp->un.ulpWord[4]);
+ goto out;
+ }
+
+ if (!vport->qfpa_res) {
+ max_desc = FCELSSIZE / sizeof(*vport->qfpa_res);
+ vport->qfpa_res = kcalloc(max_desc, sizeof(*vport->qfpa_res),
+ GFP_KERNEL);
+ if (!vport->qfpa_res)
+ goto out;
+ }
+
+ len = *((u32 *)(pcmd + 4));
+ len = be32_to_cpu(len);
+ memcpy(vport->qfpa_res, pcmd, len + 8);
+ len = len / LPFC_PRIORITY_RANGE_DESC_SIZE;
+
+ desc = (struct priority_range_desc *)(pcmd + 8);
+ vmid_range = vport->vmid_priority.vmid_range;
+ if (!vmid_range) {
+ vmid_range = kcalloc(MAX_PRIORITY_DESC, sizeof(*vmid_range),
+ GFP_KERNEL);
+ if (!vmid_range) {
+ kfree(vport->qfpa_res);
+ goto out;
+ }
+ vport->vmid_priority.vmid_range = vmid_range;
+ }
+ vport->vmid_priority.num_descriptors = len;
+
+ for (i = 0; i < len; i++, vmid_range++, desc++) {
+ lpfc_printf_vlog(vport, KERN_DEBUG, LOG_ELS,
+ "6539 vmid values low=%d, high=%d, qos=%d, "
+ "local ve id=%d\n", desc->lo_range,
+ desc->hi_range, desc->qos_priority,
+ desc->local_ve_id);
+
+ vmid_range->low = desc->lo_range << 1;
+ if (desc->local_ve_id == QFPA_ODD_ONLY)
+ vmid_range->low++;
+ if (desc->qos_priority)
+ vport->vmid_flag |= LPFC_VMID_QOS_ENABLED;
+ vmid_range->qos = desc->qos_priority;
+
+ vmid_range->high = desc->hi_range << 1;
+ if ((desc->local_ve_id == QFPA_ODD_ONLY) ||
+ (desc->local_ve_id == QFPA_EVEN_ODD))
+ vmid_range->high++;
+ }
+ lpfc_init_cs_ctl_bitmap(vport);
+ for (i = 0; i < vport->vmid_priority.num_descriptors; i++) {
+ lpfc_vmid_set_cs_ctl_range(vport,
+ vport->vmid_priority.vmid_range[i].low,
+ vport->vmid_priority.vmid_range[i].high);
+ }
+
+ vport->vmid_flag |= LPFC_VMID_QFPA_CMPL;
+ out:
+ lpfc_els_free_iocb(phba, cmdiocb);
+ lpfc_nlp_put(ndlp);
+}
+
+int lpfc_issue_els_qfpa(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *ndlp;
+ struct lpfc_iocbq *elsiocb;
+ u8 *pcmd;
+ int ret;
+
+ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+ if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
+ return -ENXIO;
+
+ elsiocb = lpfc_prep_els_iocb(vport, 1, LPFC_QFPA_SIZE, 2, ndlp,
+ ndlp->nlp_DID, ELS_CMD_QFPA);
+ if (!elsiocb)
+ return -ENOMEM;
+
+ pcmd = (u8 *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt);
+
+ *((u32 *)(pcmd)) = ELS_CMD_QFPA;
+ pcmd += 4;
+
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_qfpa;
+
+ elsiocb->context1 = lpfc_nlp_get(ndlp);
+ if (!elsiocb->context1) {
+ lpfc_els_free_iocb(vport->phba, elsiocb);
+ return -ENXIO;
+ }
+
+ ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 2);
+ if (ret != IOCB_SUCCESS) {
+ lpfc_els_free_iocb(phba, elsiocb);
+ lpfc_nlp_put(ndlp);
+ return -EIO;
+ }
+ vport->vmid_flag &= ~LPFC_VMID_QOS_ENABLED;
+ return 0;
+}
+
+int
+lpfc_vmid_uvem(struct lpfc_vport *vport,
+ struct lpfc_vmid *vmid, bool instantiated)
+{
+ struct lpfc_vem_id_desc *vem_id_desc;
+ struct lpfc_nodelist *ndlp;
+ struct lpfc_iocbq *elsiocb;
+ struct instantiated_ve_desc *inst_desc;
+ struct lpfc_vmid_context *vmid_context;
+ u8 *pcmd;
+ u32 *len;
+ int ret = 0;
+
+ ndlp = lpfc_findnode_did(vport, Fabric_DID);
+ if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
+ return -ENXIO;
+
+ vmid_context = kmalloc(sizeof(*vmid_context), GFP_KERNEL);
+ if (!vmid_context)
+ return -ENOMEM;
+ elsiocb = lpfc_prep_els_iocb(vport, 1, LPFC_UVEM_SIZE, 2,
+ ndlp, Fabric_DID, ELS_CMD_UVEM);
+ if (!elsiocb)
+ goto out;
+
+ lpfc_printf_vlog(vport, KERN_DEBUG, LOG_ELS,
+ "3427 Host vmid %s %d\n",
+ vmid->host_vmid, instantiated);
+ vmid_context->vmp = vmid;
+ vmid_context->nlp = ndlp;
+ vmid_context->instantiated = instantiated;
+ elsiocb->vmid_tag.vmid_context = vmid_context;
+ pcmd = (u8 *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt);
+
+ if (uuid_is_null((uuid_t *)vport->lpfc_vmid_host_uuid))
+ memcpy(vport->lpfc_vmid_host_uuid, vmid->host_vmid,
+ LPFC_COMPRESS_VMID_SIZE);
+
+ *((u32 *)(pcmd)) = ELS_CMD_UVEM;
+ len = (u32 *)(pcmd + 4);
+ *len = cpu_to_be32(LPFC_UVEM_SIZE - 8);
+
+ vem_id_desc = (struct lpfc_vem_id_desc *)(pcmd + 8);
+ vem_id_desc->tag = be32_to_cpu(VEM_ID_DESC_TAG);
+ vem_id_desc->length = be32_to_cpu(LPFC_UVEM_VEM_ID_DESC_SIZE);
+ memcpy(vem_id_desc->vem_id, vport->lpfc_vmid_host_uuid,
+ LPFC_COMPRESS_VMID_SIZE);
+
+ inst_desc = (struct instantiated_ve_desc *)(pcmd + 32);
+ inst_desc->tag = be32_to_cpu(INSTANTIATED_VE_DESC_TAG);
+ inst_desc->length = be32_to_cpu(LPFC_UVEM_VE_MAP_DESC_SIZE);
+ memcpy(inst_desc->global_vem_id, vmid->host_vmid,
+ LPFC_COMPRESS_VMID_SIZE);
+
+ bf_set(lpfc_instantiated_nport_id, inst_desc, vport->fc_myDID);
+ bf_set(lpfc_instantiated_local_id, inst_desc,
+ vmid->un.cs_ctl_vmid);
+ if (instantiated) {
+ inst_desc->tag = be32_to_cpu(INSTANTIATED_VE_DESC_TAG);
+ } else {
+ inst_desc->tag = be32_to_cpu(DEINSTANTIATED_VE_DESC_TAG);
+ lpfc_vmid_put_cs_ctl(vport, vmid->un.cs_ctl_vmid);
+ }
+ inst_desc->word6 = cpu_to_be32(inst_desc->word6);
+
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_uvem;
+
+ elsiocb->context1 = lpfc_nlp_get(ndlp);
+ if (!elsiocb->context1) {
+ lpfc_els_free_iocb(vport->phba, elsiocb);
+ goto out;
+ }
+
+ ret = lpfc_sli_issue_iocb(vport->phba, LPFC_ELS_RING, elsiocb, 0);
+ if (ret != IOCB_SUCCESS) {
+ lpfc_els_free_iocb(vport->phba, elsiocb);
+ lpfc_nlp_put(ndlp);
+ goto out;
+ }
+
+ return 0;
+ out:
+ kfree(vmid_context);
+ return -EIO;
+}
+
+static void
+lpfc_cmpl_els_uvem(struct lpfc_hba *phba, struct lpfc_iocbq *icmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct lpfc_vport *vport = icmdiocb->vport;
+ struct lpfc_dmabuf *prsp = NULL;
+ struct lpfc_vmid_context *vmid_context =
+ icmdiocb->vmid_tag.vmid_context;
+ struct lpfc_nodelist *ndlp = icmdiocb->context1;
+ u8 *pcmd;
+ u32 *data;
+ IOCB_t *irsp = &rspiocb->iocb;
+ struct lpfc_dmabuf *dmabuf = icmdiocb->context2;
+ struct lpfc_vmid *vmid;
+
+ vmid = vmid_context->vmp;
+ if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
+ ndlp = NULL;
+
+ prsp = list_get_first(&dmabuf->list, struct lpfc_dmabuf, list);
+ if (!prsp)
+ goto out;
+ pcmd = prsp->virt;
+ data = (u32 *)pcmd;
+ if (data[0] == ELS_CMD_LS_RJT) {
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_SLI,
+ "4532 UVEM LS_RJT %x %x\n", data[0], data[1]);
+ goto out;
+ }
+ if (irsp->ulpStatus) {
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_SLI,
+ "4533 UVEM error status %x: %x\n",
+ irsp->ulpStatus, irsp->un.ulpWord[4]);
+ goto out;
+ }
+ spin_lock(&phba->hbalock);
+ /* Set IN USE flag */
+ vport->vmid_flag |= LPFC_VMID_IN_USE;
+ phba->pport->vmid_flag |= LPFC_VMID_IN_USE;
+ spin_unlock(&phba->hbalock);
+
+ if (vmid_context->instantiated) {
+ write_lock(&vport->vmid_lock);
+ vmid->flag |= LPFC_VMID_REGISTERED;
+ vmid->flag &= ~LPFC_VMID_REQ_REGISTER;
+ write_unlock(&vport->vmid_lock);
+ }
+
+ out:
+ kfree(vmid_context);
+ lpfc_els_free_iocb(phba, icmdiocb);
+ lpfc_nlp_put(ndlp);
+}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index f5a898c2c904..7cc5920979f8 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -72,14 +72,14 @@ static void lpfc_disc_flush_list(struct lpfc_vport *vport);
static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
static int lpfc_fcf_inuse(struct lpfc_hba *);
static void lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *);
+static void lpfc_check_inactive_vmid(struct lpfc_hba *phba);
+static void lpfc_check_vmid_qfpa_issue(struct lpfc_hba *phba);
static int
lpfc_valid_xpt_node(struct lpfc_nodelist *ndlp)
{
if (ndlp->nlp_fc4_type ||
- ndlp->nlp_DID == Fabric_DID ||
- ndlp->nlp_DID == NameServer_DID ||
- ndlp->nlp_DID == FDMI_DID)
+ ndlp->nlp_type & NLP_FABRIC)
return 1;
return 0;
}
@@ -237,6 +237,110 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
}
/**
+ * lpfc_check_inactive_vmid_one - VMID inactivity checker for a vport
+ * @vport: Pointer to vport context object.
+ *
+ * This function checks for idle VMID entries related to a particular vport. If
+ * found unused/idle, free them accordingly.
+ **/
+static void lpfc_check_inactive_vmid_one(struct lpfc_vport *vport)
+{
+ u16 keep;
+ u32 difftime = 0, r, bucket;
+ u64 *lta;
+ int cpu;
+ struct lpfc_vmid *vmp;
+
+ write_lock(&vport->vmid_lock);
+
+ if (!vport->cur_vmid_cnt)
+ goto out;
+
+ /* iterate through the table */
+ hash_for_each(vport->hash_table, bucket, vmp, hnode) {
+ keep = 0;
+ if (vmp->flag & LPFC_VMID_REGISTERED) {
+ /* check if the particular VMID is in use */
+ /* for all available per cpu variable */
+ for_each_possible_cpu(cpu) {
+ /* if last access time is less than timeout */
+ lta = per_cpu_ptr(vmp->last_io_time, cpu);
+ if (!lta)
+ continue;
+ difftime = (jiffies) - (*lta);
+ if ((vport->vmid_inactivity_timeout *
+ JIFFIES_PER_HR) > difftime) {
+ keep = 1;
+ break;
+ }
+ }
+
+ /* if none of the cpus have been used by the vm, */
+ /* remove the entry if already registered */
+ if (!keep) {
+ /* mark the entry for deregistration */
+ vmp->flag = LPFC_VMID_DE_REGISTER;
+ write_unlock(&vport->vmid_lock);
+ if (vport->vmid_priority_tagging)
+ r = lpfc_vmid_uvem(vport, vmp, false);
+ else
+ r = lpfc_vmid_cmd(vport,
+ SLI_CTAS_DAPP_IDENT,
+ vmp);
+
+ /* decrement number of active vms and mark */
+ /* entry in slot as free */
+ write_lock(&vport->vmid_lock);
+ if (!r) {
+ struct lpfc_vmid *ht = vmp;
+
+ vport->cur_vmid_cnt--;
+ ht->flag = LPFC_VMID_SLOT_FREE;
+ free_percpu(ht->last_io_time);
+ ht->last_io_time = NULL;
+ hash_del(&ht->hnode);
+ }
+ }
+ }
+ }
+ out:
+ write_unlock(&vport->vmid_lock);
+}
+
+/**
+ * lpfc_check_inactive_vmid - VMID inactivity checker
+ * @phba: Pointer to hba context object.
+ *
+ * This function is called from the worker thread to determine if an entry in
+ * the VMID table can be released since there was no I/O activity seen from that
+ * particular VM for the specified time. When this happens, the entry in the
+ * table is released and also the resources on the switch cleared.
+ **/
+
+static void lpfc_check_inactive_vmid(struct lpfc_hba *phba)
+{
+ struct lpfc_vport *vport;
+ struct lpfc_vport **vports;
+ int i;
+
+ vports = lpfc_create_vport_work_array(phba);
+ if (!vports)
+ return;
+
+ for (i = 0; i <= phba->max_vports; i++) {
+ if ((!vports[i]) && (i == 0))
+ vport = phba->pport;
+ else
+ vport = vports[i];
+ if (!vport)
+ break;
+
+ lpfc_check_inactive_vmid_one(vport);
+ }
+ lpfc_destroy_vport_work_array(phba, vports);
+}
+
+/**
* lpfc_dev_loss_tmo_handler - Remote node devloss timeout handler
* @ndlp: Pointer to remote node object.
*
@@ -325,6 +429,32 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
return fcf_inuse;
}
+static void lpfc_check_vmid_qfpa_issue(struct lpfc_hba *phba)
+{
+ struct lpfc_vport *vport;
+ struct lpfc_vport **vports;
+ int i;
+
+ vports = lpfc_create_vport_work_array(phba);
+ if (!vports)
+ return;
+
+ for (i = 0; i <= phba->max_vports; i++) {
+ if ((!vports[i]) && (i == 0))
+ vport = phba->pport;
+ else
+ vport = vports[i];
+ if (!vport)
+ break;
+
+ if (vport->vmid_flag & LPFC_VMID_ISSUE_QFPA) {
+ if (!lpfc_issue_els_qfpa(vport))
+ vport->vmid_flag &= ~LPFC_VMID_ISSUE_QFPA;
+ }
+ }
+ lpfc_destroy_vport_work_array(phba, vports);
+}
+
/**
* lpfc_sli4_post_dev_loss_tmo_handler - SLI4 post devloss timeout handler
* @phba: Pointer to hba context object.
@@ -645,6 +775,22 @@ lpfc_work_done(struct lpfc_hba *phba)
if (ha_copy & HA_LATT)
lpfc_handle_latt(phba);
+ /* Handle VMID Events */
+ if (lpfc_is_vmid_enabled(phba)) {
+ if (phba->pport->work_port_events &
+ WORKER_CHECK_VMID_ISSUE_QFPA) {
+ lpfc_check_vmid_qfpa_issue(phba);
+ phba->pport->work_port_events &=
+ ~WORKER_CHECK_VMID_ISSUE_QFPA;
+ }
+ if (phba->pport->work_port_events &
+ WORKER_CHECK_INACTIVE_VMID) {
+ lpfc_check_inactive_vmid(phba);
+ phba->pport->work_port_events &=
+ ~WORKER_CHECK_INACTIVE_VMID;
+ }
+ }
+
/* Process SLI4 events */
if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
if (phba->hba_flag & HBA_RRQ_ACTIVE)
@@ -826,7 +972,8 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) ||
((vport->port_type == LPFC_NPIV_PORT) &&
((ndlp->nlp_DID == NameServer_DID) ||
- (ndlp->nlp_DID == FDMI_DID))))
+ (ndlp->nlp_DID == FDMI_DID) ||
+ (ndlp->nlp_DID == Fabric_Cntl_DID))))
lpfc_unreg_rpi(vport, ndlp);
/* Leave Fabric nodes alone on link down */
@@ -4160,6 +4307,53 @@ out:
return;
}
+/*
+ * This routine handles processing a Fabric Controller REG_LOGIN mailbox
+ * command upon completion. It is setup in the LPFC_MBOXQ
+ * as the completion routine when the command is handed off to the SLI layer.
+ */
+void
+lpfc_mbx_cmpl_fc_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ struct lpfc_vport *vport = pmb->vport;
+ MAILBOX_t *mb = &pmb->u.mb;
+ struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
+ struct lpfc_nodelist *ndlp;
+
+ ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
+ pmb->ctx_ndlp = NULL;
+ pmb->ctx_buf = NULL;
+
+ if (mb->mbxStatus) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
+ "0933 %s: Register FC login error: 0x%x\n",
+ __func__, mb->mbxStatus);
+ goto out;
+ }
+
+ if (phba->sli_rev < LPFC_SLI_REV4)
+ ndlp->nlp_rpi = mb->un.varWords[0];
+
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+ "0934 %s: Complete FC x%x RegLogin rpi x%x ste x%x\n",
+ __func__, ndlp->nlp_DID, ndlp->nlp_rpi,
+ ndlp->nlp_state);
+
+ ndlp->nlp_flag |= NLP_RPI_REGISTERED;
+ ndlp->nlp_type |= NLP_FABRIC;
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
+
+ out:
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ mempool_free(pmb, phba->mbox_mem_pool);
+
+ /* Drop the reference count from the mbox at the end after
+ * all the current reference to the ndlp have been done.
+ */
+ lpfc_nlp_put(ndlp);
+}
+
static void
lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
@@ -4789,12 +4983,17 @@ lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING;
lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
} else {
+ /* NLP_RELEASE_RPI is only set for SLI4 ports. */
if (ndlp->nlp_flag & NLP_RELEASE_RPI) {
lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi);
+ spin_lock_irq(&ndlp->lock);
ndlp->nlp_flag &= ~NLP_RELEASE_RPI;
ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
+ spin_unlock_irq(&ndlp->lock);
}
+ spin_lock_irq(&ndlp->lock);
ndlp->nlp_flag &= ~NLP_UNREG_INP;
+ spin_unlock_irq(&ndlp->lock);
}
}
@@ -5129,8 +5328,10 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
list_del_init(&ndlp->dev_loss_evt.evt_listp);
list_del_init(&ndlp->recovery_evt.evt_listp);
lpfc_cleanup_vports_rrqs(vport, ndlp);
+
if (phba->sli_rev == LPFC_SLI_REV4)
ndlp->nlp_flag |= NLP_RELEASE_RPI;
+
return 0;
}
@@ -6176,8 +6377,23 @@ lpfc_nlp_release(struct kref *kref)
lpfc_cancel_retry_delay_tmo(vport, ndlp);
lpfc_cleanup_node(vport, ndlp);
- /* Clear Node key fields to give other threads notice
- * that this node memory is not valid anymore.
+ /* Not all ELS transactions have registered the RPI with the port.
+ * In these cases the rpi usage is temporary and the node is
+ * released when the WQE is completed. Catch this case to free the
+ * RPI to the pool. Because this node is in the release path, a lock
+ * is unnecessary. All references are gone and the node has been
+ * dequeued.
+ */
+ if (ndlp->nlp_flag & NLP_RELEASE_RPI) {
+ if (ndlp->nlp_rpi != LPFC_RPI_ALLOC_ERROR &&
+ !(ndlp->nlp_flag & (NLP_RPI_REGISTERED | NLP_UNREG_INP))) {
+ lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi);
+ ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
+ }
+ }
+
+ /* The node is not freed back to memory, it is released to a pool so
+ * the node fields need to be cleaned up.
*/
ndlp->vport = NULL;
ndlp->nlp_state = NLP_STE_FREED_NODE;
@@ -6257,6 +6473,7 @@ lpfc_nlp_not_used(struct lpfc_nodelist *ndlp)
"node not used: did:x%x flg:x%x refcnt:x%x",
ndlp->nlp_DID, ndlp->nlp_flag,
kref_read(&ndlp->kref));
+
if (kref_read(&ndlp->kref) == 1)
if (lpfc_nlp_put(ndlp))
return 1;
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 42682d95af52..4a5a85ed42ec 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -275,6 +275,7 @@ struct lpfc_sli_ct_request {
#define SLI_CT_ACCESS_DENIED 0x10
#define SLI_CT_INVALID_PORT_ID 0x11
#define SLI_CT_DATABASE_EMPTY 0x12
+#define SLI_CT_APP_ID_NOT_AVAILABLE 0x40
/*
* Name Server Command Codes
@@ -400,16 +401,16 @@ struct csp {
uint16_t altBbCredit:1; /* FC Word 1, bit 27 */
uint16_t edtovResolution:1; /* FC Word 1, bit 26 */
uint16_t multicast:1; /* FC Word 1, bit 25 */
- uint16_t broadcast:1; /* FC Word 1, bit 24 */
+ uint16_t app_hdr_support:1; /* FC Word 1, bit 24 */
- uint16_t huntgroup:1; /* FC Word 1, bit 23 */
+ uint16_t priority_tagging:1; /* FC Word 1, bit 23 */
uint16_t simplex:1; /* FC Word 1, bit 22 */
uint16_t word1Reserved1:3; /* FC Word 1, bit 21:19 */
uint16_t dhd:1; /* FC Word 1, bit 18 */
uint16_t contIncSeqCnt:1; /* FC Word 1, bit 17 */
uint16_t payloadlength:1; /* FC Word 1, bit 16 */
#else /* __LITTLE_ENDIAN_BITFIELD */
- uint16_t broadcast:1; /* FC Word 1, bit 24 */
+ uint16_t app_hdr_support:1; /* FC Word 1, bit 24 */
uint16_t multicast:1; /* FC Word 1, bit 25 */
uint16_t edtovResolution:1; /* FC Word 1, bit 26 */
uint16_t altBbCredit:1; /* FC Word 1, bit 27 */
@@ -423,7 +424,7 @@ struct csp {
uint16_t dhd:1; /* FC Word 1, bit 18 */
uint16_t word1Reserved1:3; /* FC Word 1, bit 21:19 */
uint16_t simplex:1; /* FC Word 1, bit 22 */
- uint16_t huntgroup:1; /* FC Word 1, bit 23 */
+ uint16_t priority_tagging:1; /* FC Word 1, bit 23 */
#endif
uint8_t bbRcvSizeMsb; /* Upper nibble is reserved */
@@ -607,6 +608,8 @@ struct fc_vft_header {
#define ELS_CMD_LIRR 0x7A000000
#define ELS_CMD_LCB 0x81000000
#define ELS_CMD_FPIN 0x16000000
+#define ELS_CMD_QFPA 0xB0000000
+#define ELS_CMD_UVEM 0xB1000000
#else /* __LITTLE_ENDIAN_BITFIELD */
#define ELS_CMD_MASK 0xffff
#define ELS_RSP_MASK 0xff
@@ -649,6 +652,8 @@ struct fc_vft_header {
#define ELS_CMD_LIRR 0x7A
#define ELS_CMD_LCB 0x81
#define ELS_CMD_FPIN ELS_FPIN
+#define ELS_CMD_QFPA 0xB0
+#define ELS_CMD_UVEM 0xB1
#endif
/*
@@ -1317,6 +1322,117 @@ struct fc_rdp_res_frame {
};
+/* UVEM */
+
+#define LPFC_UVEM_SIZE 60
+#define LPFC_UVEM_VEM_ID_DESC_SIZE 16
+#define LPFC_UVEM_VE_MAP_DESC_SIZE 20
+
+#define VEM_ID_DESC_TAG 0x0001000A
+struct lpfc_vem_id_desc {
+ uint32_t tag;
+ uint32_t length;
+ uint8_t vem_id[16];
+};
+
+#define LPFC_QFPA_SIZE 4
+
+#define INSTANTIATED_VE_DESC_TAG 0x0001000B
+struct instantiated_ve_desc {
+ uint32_t tag;
+ uint32_t length;
+ uint8_t global_vem_id[16];
+ uint32_t word6;
+#define lpfc_instantiated_local_id_SHIFT 0
+#define lpfc_instantiated_local_id_MASK 0x000000ff
+#define lpfc_instantiated_local_id_WORD word6
+#define lpfc_instantiated_nport_id_SHIFT 8
+#define lpfc_instantiated_nport_id_MASK 0x00ffffff
+#define lpfc_instantiated_nport_id_WORD word6
+};
+
+#define DEINSTANTIATED_VE_DESC_TAG 0x0001000C
+struct deinstantiated_ve_desc {
+ uint32_t tag;
+ uint32_t length;
+ uint8_t global_vem_id[16];
+ uint32_t word6;
+#define lpfc_deinstantiated_nport_id_SHIFT 0
+#define lpfc_deinstantiated_nport_id_MASK 0x000000ff
+#define lpfc_deinstantiated_nport_id_WORD word6
+#define lpfc_deinstantiated_local_id_SHIFT 24
+#define lpfc_deinstantiated_local_id_MASK 0x00ffffff
+#define lpfc_deinstantiated_local_id_WORD word6
+};
+
+/* Query Fabric Priority Allocation Response */
+#define LPFC_PRIORITY_RANGE_DESC_SIZE 12
+
+struct priority_range_desc {
+ uint32_t tag;
+ uint32_t length;
+ uint8_t lo_range;
+ uint8_t hi_range;
+ uint8_t qos_priority;
+ uint8_t local_ve_id;
+};
+
+struct fc_qfpa_res {
+ uint32_t reply_sequence; /* LS_ACC or LS_RJT */
+ uint32_t length; /* FC Word 1 */
+ struct priority_range_desc desc[1];
+};
+
+/* Application Server command code */
+/* VMID */
+
+#define SLI_CT_APP_SEV_Subtypes 0x20 /* Application Server subtype */
+
+#define SLI_CTAS_GAPPIA_ENT 0x0100 /* Get Application Identifier */
+#define SLI_CTAS_GALLAPPIA 0x0101 /* Get All Application Identifier */
+#define SLI_CTAS_GALLAPPIA_ID 0x0102 /* Get All Application Identifier */
+ /* for Nport */
+#define SLI_CTAS_GAPPIA_IDAPP 0x0103 /* Get Application Identifier */
+ /* for Nport */
+#define SLI_CTAS_RAPP_IDENT 0x0200 /* Register Application Identifier */
+#define SLI_CTAS_DAPP_IDENT 0x0300 /* Deregister Application */
+ /* Identifier */
+#define SLI_CTAS_DALLAPP_ID 0x0301 /* Deregister All Application */
+ /* Identifier */
+
+struct entity_id_object {
+ uint8_t entity_id_len;
+ uint8_t entity_id[255]; /* VM UUID */
+};
+
+struct app_id_object {
+ uint32_t port_id;
+ uint32_t app_id;
+ struct entity_id_object obj;
+};
+
+struct lpfc_vmid_rapp_ident_list {
+ uint32_t no_of_objects;
+ struct entity_id_object obj[1];
+};
+
+struct lpfc_vmid_dapp_ident_list {
+ uint32_t no_of_objects;
+ struct entity_id_object obj[1];
+};
+
+#define GALLAPPIA_ID_LAST 0x80
+struct lpfc_vmid_gallapp_ident_list {
+ uint8_t control;
+ uint8_t reserved[3];
+ struct app_id_object app_id;
+};
+
+#define RAPP_IDENT_OFFSET (offsetof(struct lpfc_sli_ct_request, un) + 4)
+#define DAPP_IDENT_OFFSET (offsetof(struct lpfc_sli_ct_request, un) + 4)
+#define GALLAPPIA_ID_SIZE (offsetof(struct lpfc_sli_ct_request, un) + 4)
+#define DALLAPP_ID_SIZE (offsetof(struct lpfc_sli_ct_request, un) + 4)
+
/******** FDMI ********/
/* lpfc_sli_ct_request defines the CT_IU preamble for FDMI commands */
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index f77e71e6dbbd..eb8c735a243b 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -273,6 +273,9 @@ struct lpfc_sli4_flags {
#define lpfc_vfi_rsrc_rdy_MASK 0x00000001
#define lpfc_vfi_rsrc_rdy_WORD word0
#define LPFC_VFI_RSRC_RDY 1
+#define lpfc_ftr_ashdr_SHIFT 4
+#define lpfc_ftr_ashdr_MASK 0x00000001
+#define lpfc_ftr_ashdr_WORD word0
};
struct sli4_bls_rsp {
@@ -2944,6 +2947,9 @@ struct lpfc_mbx_request_features {
#define lpfc_mbx_rq_ftr_rq_mrqp_SHIFT 16
#define lpfc_mbx_rq_ftr_rq_mrqp_MASK 0x00000001
#define lpfc_mbx_rq_ftr_rq_mrqp_WORD word2
+#define lpfc_mbx_rq_ftr_rq_ashdr_SHIFT 17
+#define lpfc_mbx_rq_ftr_rq_ashdr_MASK 0x00000001
+#define lpfc_mbx_rq_ftr_rq_ashdr_WORD word2
uint32_t word3;
#define lpfc_mbx_rq_ftr_rsp_iaab_SHIFT 0
#define lpfc_mbx_rq_ftr_rsp_iaab_MASK 0x00000001
@@ -2975,6 +2981,9 @@ struct lpfc_mbx_request_features {
#define lpfc_mbx_rq_ftr_rsp_mrqp_SHIFT 16
#define lpfc_mbx_rq_ftr_rsp_mrqp_MASK 0x00000001
#define lpfc_mbx_rq_ftr_rsp_mrqp_WORD word3
+#define lpfc_mbx_rq_ftr_rsp_ashdr_SHIFT 17
+#define lpfc_mbx_rq_ftr_rsp_ashdr_MASK 0x00000001
+#define lpfc_mbx_rq_ftr_rsp_ashdr_WORD word3
};
struct lpfc_mbx_memory_dump_type3 {
@@ -4219,6 +4228,9 @@ struct wqe_common {
#define wqe_xchg_WORD word10
#define LPFC_SCSI_XCHG 0x0
#define LPFC_NVME_XCHG 0x1
+#define wqe_appid_SHIFT 5
+#define wqe_appid_MASK 0x00000001
+#define wqe_appid_WORD word10
#define wqe_oas_SHIFT 6
#define wqe_oas_MASK 0x00000001
#define wqe_oas_WORD word10
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 5f018d02bf56..5983e05b648f 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -98,6 +98,7 @@ static struct scsi_transport_template *lpfc_transport_template = NULL;
static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
static DEFINE_IDR(lpfc_hba_index);
#define LPFC_NVMET_BUF_POST 254
+static int lpfc_vmid_res_alloc(struct lpfc_hba *phba, struct lpfc_vport *vport);
/**
* lpfc_config_port_prep - Perform lpfc initialization prior to config port
@@ -2888,6 +2889,10 @@ lpfc_cleanup(struct lpfc_vport *vport)
if (phba->link_state > LPFC_LINK_DOWN)
lpfc_port_link_failure(vport);
+ /* Clean up VMID resources */
+ if (lpfc_is_vmid_enabled(phba))
+ lpfc_vmid_vport_cleanup(vport);
+
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
if (vport->port_type != LPFC_PHYSICAL_PORT &&
ndlp->nlp_DID == Fabric_DID) {
@@ -3532,13 +3537,6 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action)
list_for_each_entry_safe(ndlp, next_ndlp,
&vports[i]->fc_nodes,
nlp_listp) {
- if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
- /* Driver must assume RPI is invalid for
- * any unused or inactive node.
- */
- ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
- continue;
- }
spin_lock_irq(&ndlp->lock);
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
@@ -4315,6 +4313,55 @@ lpfc_get_wwpn(struct lpfc_hba *phba)
}
/**
+ * lpfc_vmid_res_alloc - Allocates resources for VMID
+ * @phba: pointer to lpfc hba data structure.
+ * @vport: pointer to vport data structure
+ *
+ * This routine allocated the resources needed for the VMID.
+ *
+ * Return codes
+ * 0 on Success
+ * Non-0 on Failure
+ */
+static int
+lpfc_vmid_res_alloc(struct lpfc_hba *phba, struct lpfc_vport *vport)
+{
+ /* VMID feature is supported only on SLI4 */
+ if (phba->sli_rev == LPFC_SLI_REV3) {
+ phba->cfg_vmid_app_header = 0;
+ phba->cfg_vmid_priority_tagging = 0;
+ }
+
+ if (lpfc_is_vmid_enabled(phba)) {
+ vport->vmid =
+ kcalloc(phba->cfg_max_vmid, sizeof(struct lpfc_vmid),
+ GFP_KERNEL);
+ if (!vport->vmid)
+ return -ENOMEM;
+
+ rwlock_init(&vport->vmid_lock);
+
+ /* Set the VMID parameters for the vport */
+ vport->vmid_priority_tagging = phba->cfg_vmid_priority_tagging;
+ vport->vmid_inactivity_timeout =
+ phba->cfg_vmid_inactivity_timeout;
+ vport->max_vmid = phba->cfg_max_vmid;
+ vport->cur_vmid_cnt = 0;
+
+ vport->vmid_priority_range = bitmap_zalloc
+ (LPFC_VMID_MAX_PRIORITY_RANGE, GFP_KERNEL);
+
+ if (!vport->vmid_priority_range) {
+ kfree(vport->vmid);
+ return -ENOMEM;
+ }
+
+ hash_init(vport->hash_table);
+ }
+ return 0;
+}
+
+/**
* lpfc_create_port - Create an FC port
* @phba: pointer to lpfc hba data structure.
* @instance: a unique integer ID to this FC port.
@@ -4466,6 +4513,12 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
vport->port_type, shost->sg_tablesize,
phba->cfg_scsi_seg_cnt, phba->cfg_sg_seg_cnt);
+ /* Allocate the resources for VMID */
+ rc = lpfc_vmid_res_alloc(phba, vport);
+
+ if (rc)
+ goto out;
+
/* Initialize all internally managed lists. */
INIT_LIST_HEAD(&vport->fc_nodes);
INIT_LIST_HEAD(&vport->rcv_buffer_list);
@@ -4490,6 +4543,8 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
return vport;
out_put_shost:
+ kfree(vport->vmid);
+ bitmap_free(vport->vmid_priority_range);
scsi_host_put(shost);
out:
return NULL;
@@ -4789,6 +4844,42 @@ lpfc_sli4_fcf_redisc_wait_tmo(struct timer_list *t)
}
/**
+ * lpfc_vmid_poll - VMID timeout detection
+ * @ptr: Map to lpfc_hba data structure pointer.
+ *
+ * This routine is invoked when there is no I/O on by a VM for the specified
+ * amount of time. When this situation is detected, the VMID has to be
+ * deregistered from the switch and all the local resources freed. The VMID
+ * will be reassigned to the VM once the I/O begins.
+ **/
+static void
+lpfc_vmid_poll(struct timer_list *t)
+{
+ struct lpfc_hba *phba = from_timer(phba, t, inactive_vmid_poll);
+ u32 wake_up = 0;
+
+ /* check if there is a need to issue QFPA */
+ if (phba->pport->vmid_priority_tagging) {
+ wake_up = 1;
+ phba->pport->work_port_events |= WORKER_CHECK_VMID_ISSUE_QFPA;
+ }
+
+ /* Is the vmid inactivity timer enabled */
+ if (phba->pport->vmid_inactivity_timeout ||
+ phba->pport->load_flag & FC_DEREGISTER_ALL_APP_ID) {
+ wake_up = 1;
+ phba->pport->work_port_events |= WORKER_CHECK_INACTIVE_VMID;
+ }
+
+ if (wake_up)
+ lpfc_worker_wake_up(phba);
+
+ /* restart the timer for the next iteration */
+ mod_timer(&phba->inactive_vmid_poll, jiffies + msecs_to_jiffies(1000 *
+ LPFC_VMID_TIMER));
+}
+
+/**
* lpfc_sli4_parse_latt_fault - Parse sli4 link-attention link fault code
* @phba: pointer to lpfc hba data structure.
* @acqe_link: pointer to the async link completion queue entry.
@@ -6636,6 +6727,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_sli4_rb_alloc;
phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_sli4_rb_free;
+ /* for VMID idle timeout if VMID is enabled */
+ if (lpfc_is_vmid_enabled(phba))
+ timer_setup(&phba->inactive_vmid_poll, lpfc_vmid_poll, 0);
+
/*
* Initialize the SLI Layer to run with lpfc SLI4 HBAs.
*/
@@ -13051,7 +13146,7 @@ lpfc_sli4_request_firmware_update(struct lpfc_hba *phba, uint8_t fw_upgrade)
snprintf(file_name, ELX_MODEL_NAME_SIZE, "%s.grp", phba->ModelName);
if (fw_upgrade == INT_FW_UPGRADE) {
- ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
file_name, &phba->pcidev->dev,
GFP_KERNEL, (void *)phba,
lpfc_write_firmware);
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 1b40a3bbd1cd..84bc373190d8 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -522,7 +522,8 @@ lpfc_init_link(struct lpfc_hba * phba,
}
/* Enable asynchronous ABTS responses from firmware */
- mb->un.varInitLnk.link_flags |= FLAGS_IMED_ABORT;
+ if (phba->sli_rev == LPFC_SLI_REV3 && !phba->cfg_fcp_wait_abts_rsp)
+ mb->un.varInitLnk.link_flags |= FLAGS_IMED_ABORT;
/* NEW_FEATURE
* Setting up the link speed
@@ -2100,6 +2101,12 @@ lpfc_request_features(struct lpfc_hba *phba, struct lpfcMboxq *mboxq)
bf_set(lpfc_mbx_rq_ftr_rq_iaab, &mboxq->u.mqe.un.req_ftrs, 0);
bf_set(lpfc_mbx_rq_ftr_rq_iaar, &mboxq->u.mqe.un.req_ftrs, 0);
}
+
+ /* Enable Application Services Header for appheader VMID */
+ if (phba->cfg_vmid_app_header) {
+ bf_set(lpfc_mbx_rq_ftr_rq_ashdr, &mboxq->u.mqe.un.req_ftrs, 1);
+ bf_set(lpfc_ftr_ashdr, &phba->sli4_hba.sli4_flags, 1);
+ }
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index bb4e65a32ecc..e12f83fb795c 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -567,15 +567,24 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* no deferred ACC */
kfree(save_iocb);
- /* In order to preserve RPIs, we want to cleanup
- * the default RPI the firmware created to rcv
- * this ELS request. The only way to do this is
- * to register, then unregister the RPI.
+ /* This is an NPIV SLI4 instance that does not need to register
+ * a default RPI.
*/
- spin_lock_irq(&ndlp->lock);
- ndlp->nlp_flag |= (NLP_RM_DFLT_RPI | NLP_ACC_REGLOGIN |
- NLP_RCV_PLOGI);
- spin_unlock_irq(&ndlp->lock);
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ mempool_free(login_mbox, phba->mbox_mem_pool);
+ login_mbox = NULL;
+ } else {
+ /* In order to preserve RPIs, we want to cleanup
+ * the default RPI the firmware created to rcv
+ * this ELS request. The only way to do this is
+ * to register, then unregister the RPI.
+ */
+ spin_lock_irq(&ndlp->lock);
+ ndlp->nlp_flag |= (NLP_RM_DFLT_RPI | NLP_ACC_REGLOGIN |
+ NLP_RCV_PLOGI);
+ spin_unlock_irq(&ndlp->lock);
+ }
+
stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD;
stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
rc = lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
@@ -653,6 +662,10 @@ lpfc_mbx_cmpl_resume_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, elsiocb,
ndlp, NULL);
}
+
+ /* This nlp_put pairs with lpfc_sli4_resume_rpi */
+ lpfc_nlp_put(ndlp);
+
kfree(elsiocb);
mempool_free(mboxq, phba->mbox_mem_pool);
}
@@ -772,6 +785,15 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
else
lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
+ /* This clause allows the initiator to ACC the LOGO back to the
+ * Fabric Domain Controller. It does deliberately skip all other
+ * steps because some fabrics send RDP requests after logging out
+ * from the initiator.
+ */
+ if (ndlp->nlp_type & NLP_FABRIC &&
+ ((ndlp->nlp_DID & WELL_KNOWN_DID_MASK) != WELL_KNOWN_DID_MASK))
+ return 0;
+
/* Notify transport of connectivity loss to trigger cleanup. */
if (phba->nvmet_support &&
ndlp->nlp_state == NLP_STE_UNMAPPED_NODE)
@@ -1410,6 +1432,8 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
switch (ndlp->nlp_DID) {
case NameServer_DID:
mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login;
+ /* Fabric Controller Node needs these parameters. */
+ memcpy(&ndlp->fc_sparam, sp, sizeof(struct serv_parm));
break;
case FDMI_DID:
mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login;
diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c
index 41e49f61fac2..bcc804cefd30 100644
--- a/drivers/scsi/lpfc/lpfc_nvme.c
+++ b/drivers/scsi/lpfc/lpfc_nvme.c
@@ -1049,9 +1049,19 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
nCmd->transferred_length = wcqe->total_data_placed;
nCmd->rcv_rsplen = wcqe->parameter;
nCmd->status = 0;
- /* Sanity check */
- if (nCmd->rcv_rsplen == LPFC_NVME_ERSP_LEN)
+
+ /* Check if this is really an ERSP */
+ if (nCmd->rcv_rsplen == LPFC_NVME_ERSP_LEN) {
+ lpfc_ncmd->status = IOSTAT_SUCCESS;
+ lpfc_ncmd->result = 0;
+
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME,
+ "6084 NVME Completion ERSP: "
+ "xri %x placed x%x\n",
+ lpfc_ncmd->cur_iocbq.sli4_xritag,
+ wcqe->total_data_placed);
break;
+ }
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
"6081 NVME Completion Protocol Error: "
"xri %x status x%x result x%x "
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index eefbb9b22798..1b248c237be1 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -28,6 +28,7 @@
#include <asm/unaligned.h>
#include <linux/t10-pi.h>
#include <linux/crc-t10dif.h>
+#include <linux/blk-cgroup.h>
#include <net/checksum.h>
#include <scsi/scsi.h>
@@ -86,6 +87,14 @@ static void
lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *psb);
static int
lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc);
+static void
+lpfc_put_vmid_in_hashtable(struct lpfc_vport *vport, u32 hash,
+ struct lpfc_vmid *vmp);
+static void lpfc_vmid_update_entry(struct lpfc_vport *vport, struct scsi_cmnd
+ *cmd, struct lpfc_vmid *vmp,
+ union lpfc_vmid_io_tag *tag);
+static void lpfc_vmid_assign_cs_ctl(struct lpfc_vport *vport,
+ struct lpfc_vmid *vmid);
static inline unsigned
lpfc_cmd_blksize(struct scsi_cmnd *sc)
@@ -518,6 +527,7 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba,
struct lpfc_nodelist *ndlp;
int rrq_empty = 0;
struct lpfc_sli_ring *pring = phba->sli4_hba.els_wq->pring;
+ struct scsi_cmnd *cmd;
if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP))
return;
@@ -553,6 +563,31 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba,
psb->cur_iocbq.sli4_lxritag, rxid, 1);
lpfc_sli4_abts_err_handler(phba, ndlp, axri);
}
+
+ if (phba->cfg_fcp_wait_abts_rsp) {
+ spin_lock_irqsave(&psb->buf_lock, iflag);
+ cmd = psb->pCmd;
+ psb->pCmd = NULL;
+ spin_unlock_irqrestore(&psb->buf_lock, iflag);
+
+ /* The sdev is not guaranteed to be valid post
+ * scsi_done upcall.
+ */
+ if (cmd)
+ cmd->scsi_done(cmd);
+
+ /*
+ * We expect there is an abort thread waiting
+ * for command completion wake up the thread.
+ */
+ spin_lock_irqsave(&psb->buf_lock, iflag);
+ psb->cur_iocbq.iocb_flag &=
+ ~LPFC_DRIVER_ABORTED;
+ if (psb->waitq)
+ wake_up(psb->waitq);
+ spin_unlock_irqrestore(&psb->buf_lock, iflag);
+ }
+
lpfc_release_scsi_buf_s4(phba, psb);
if (rrq_empty)
lpfc_worker_wake_up(phba);
@@ -780,7 +815,8 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *psb)
qp = psb->hdwq;
if (psb->flags & LPFC_SBUF_XBUSY) {
spin_lock_irqsave(&qp->abts_io_buf_list_lock, iflag);
- psb->pCmd = NULL;
+ if (!phba->cfg_fcp_wait_abts_rsp)
+ psb->pCmd = NULL;
list_add_tail(&psb->list, &qp->lpfc_abts_io_buf_list);
qp->abts_scsi_io_bufs++;
spin_unlock_irqrestore(&qp->abts_io_buf_list_lock, iflag);
@@ -2869,10 +2905,8 @@ skipit:
}
out:
if (err_type == BGS_GUARD_ERR_MASK) {
- scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x1);
- cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x1);
+ set_host_byte(cmd, DID_ABORT);
phba->bg_guard_err_cnt++;
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
"9069 BLKGRD: reftag %x grd_tag err %x != %x\n",
@@ -2880,10 +2914,8 @@ out:
sum, guard_tag);
} else if (err_type == BGS_REFTAG_ERR_MASK) {
- scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x3);
- cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x3);
+ set_host_byte(cmd, DID_ABORT);
phba->bg_reftag_err_cnt++;
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
@@ -2892,10 +2924,8 @@ out:
ref_tag, start_ref_tag);
} else if (err_type == BGS_APPTAG_ERR_MASK) {
- scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x2);
- cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x2);
+ set_host_byte(cmd, DID_ABORT);
phba->bg_apptag_err_cnt++;
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
@@ -2954,10 +2984,8 @@ lpfc_sli4_parse_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd,
if (lpfc_bgs_get_guard_err(bgstat)) {
ret = 1;
- scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x1);
- cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x1);
+ set_host_byte(cmd, DID_ABORT);
phba->bg_guard_err_cnt++;
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
"9059 BLKGRD: Guard Tag error in cmd"
@@ -2970,10 +2998,8 @@ lpfc_sli4_parse_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd,
if (lpfc_bgs_get_reftag_err(bgstat)) {
ret = 1;
- scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x3);
- cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x3);
+ set_host_byte(cmd, DID_ABORT);
phba->bg_reftag_err_cnt++;
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
@@ -2987,10 +3013,8 @@ lpfc_sli4_parse_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd,
if (lpfc_bgs_get_apptag_err(bgstat)) {
ret = 1;
- scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x2);
- cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x2);
+ set_host_byte(cmd, DID_ABORT);
phba->bg_apptag_err_cnt++;
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
@@ -3100,10 +3124,8 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd,
if (lpfc_bgs_get_guard_err(bgstat)) {
ret = 1;
- scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x1);
- cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x1);
+ set_host_byte(cmd, DID_ABORT);
phba->bg_guard_err_cnt++;
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
"9055 BLKGRD: Guard Tag error in cmd "
@@ -3116,10 +3138,8 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd,
if (lpfc_bgs_get_reftag_err(bgstat)) {
ret = 1;
- scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x3);
- cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x3);
+ set_host_byte(cmd, DID_ABORT);
phba->bg_reftag_err_cnt++;
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
@@ -3133,10 +3153,8 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd,
if (lpfc_bgs_get_apptag_err(bgstat)) {
ret = 1;
- scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x2);
- cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x2);
+ set_host_byte(cmd, DID_ABORT);
phba->bg_apptag_err_cnt++;
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
@@ -4045,6 +4063,7 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
u32 logit = LOG_FCP;
u32 status, idx;
unsigned long iflags = 0;
+ u8 wait_xb_clr = 0;
/* Sanity check on return of outstanding command */
if (!lpfc_cmd) {
@@ -4096,8 +4115,11 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
lpfc_cmd->result = (wcqe->parameter & IOERR_PARAM_MASK);
lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY;
- if (bf_get(lpfc_wcqe_c_xb, wcqe))
+ if (bf_get(lpfc_wcqe_c_xb, wcqe)) {
lpfc_cmd->flags |= LPFC_SBUF_XBUSY;
+ if (phba->cfg_fcp_wait_abts_rsp)
+ wait_xb_clr = 1;
+ }
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
if (lpfc_cmd->prot_data_type) {
@@ -4329,6 +4351,8 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
lpfc_io_ktime(phba, lpfc_cmd);
}
#endif
+ if (wait_xb_clr)
+ goto out;
lpfc_cmd->pCmd = NULL;
spin_unlock(&lpfc_cmd->buf_lock);
@@ -4343,8 +4367,8 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
lpfc_cmd->cur_iocbq.iocb_flag &= ~LPFC_DRIVER_ABORTED;
if (lpfc_cmd->waitq)
wake_up(lpfc_cmd->waitq);
+out:
spin_unlock(&lpfc_cmd->buf_lock);
-
lpfc_release_scsi_buf(phba, lpfc_cmd);
}
@@ -4398,11 +4422,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
lpfc_cmd->result = (pIocbOut->iocb.un.ulpWord[4] & IOERR_PARAM_MASK);
lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
- /* pick up SLI4 exhange busy status from HBA */
+ /* pick up SLI4 exchange busy status from HBA */
+ lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY;
if (pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY)
lpfc_cmd->flags |= LPFC_SBUF_XBUSY;
- else
- lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY;
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
if (lpfc_cmd->prot_data_type) {
@@ -4601,6 +4624,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
lpfc_io_ktime(phba, lpfc_cmd);
}
#endif
+
/* The sdev is not guaranteed to be valid post scsi_done upcall. */
cmd->scsi_done(cmd);
@@ -5145,6 +5169,269 @@ void lpfc_poll_timeout(struct timer_list *t)
}
}
+/*
+ * lpfc_get_vmid_from_hashtable - search the UUID in the hash table
+ * @vport: The virtual port for which this call is being executed.
+ * @hash: calculated hash value
+ * @buf: uuid associated with the VE
+ * Return the VMID entry associated with the UUID
+ * Make sure to acquire the appropriate lock before invoking this routine.
+ */
+struct lpfc_vmid *lpfc_get_vmid_from_hashtable(struct lpfc_vport *vport,
+ u32 hash, u8 *buf)
+{
+ struct lpfc_vmid *vmp;
+
+ hash_for_each_possible(vport->hash_table, vmp, hnode, hash) {
+ if (memcmp(&vmp->host_vmid[0], buf, 16) == 0)
+ return vmp;
+ }
+ return NULL;
+}
+
+/*
+ * lpfc_put_vmid_in_hashtable - put the VMID in the hash table
+ * @vport: The virtual port for which this call is being executed.
+ * @hash - calculated hash value
+ * @vmp: Pointer to a VMID entry representing a VM sending I/O
+ *
+ * This routine will insert the newly acquired VMID entity in the hash table.
+ * Make sure to acquire the appropriate lock before invoking this routine.
+ */
+static void
+lpfc_put_vmid_in_hashtable(struct lpfc_vport *vport, u32 hash,
+ struct lpfc_vmid *vmp)
+{
+ hash_add(vport->hash_table, &vmp->hnode, hash);
+}
+
+/*
+ * lpfc_vmid_hash_fn - create a hash value of the UUID
+ * @vmid: uuid associated with the VE
+ * @len: length of the VMID string
+ * Returns the calculated hash value
+ */
+int lpfc_vmid_hash_fn(const char *vmid, int len)
+{
+ int c;
+ int hash = 0;
+
+ if (len == 0)
+ return 0;
+ while (len--) {
+ c = *vmid++;
+ if (c >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+
+ hash = (hash + (c << LPFC_VMID_HASH_SHIFT) +
+ (c >> LPFC_VMID_HASH_SHIFT)) * 19;
+ }
+
+ return hash & LPFC_VMID_HASH_MASK;
+}
+
+/*
+ * lpfc_vmid_update_entry - update the vmid entry in the hash table
+ * @vport: The virtual port for which this call is being executed.
+ * @cmd: address of scsi cmd descriptor
+ * @vmp: Pointer to a VMID entry representing a VM sending I/O
+ * @tag: VMID tag
+ */
+static void lpfc_vmid_update_entry(struct lpfc_vport *vport, struct scsi_cmnd
+ *cmd, struct lpfc_vmid *vmp,
+ union lpfc_vmid_io_tag *tag)
+{
+ u64 *lta;
+
+ if (vport->vmid_priority_tagging)
+ tag->cs_ctl_vmid = vmp->un.cs_ctl_vmid;
+ else
+ tag->app_id = vmp->un.app_id;
+
+ if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ vmp->io_wr_cnt++;
+ else
+ vmp->io_rd_cnt++;
+
+ /* update the last access timestamp in the table */
+ lta = per_cpu_ptr(vmp->last_io_time, raw_smp_processor_id());
+ *lta = jiffies;
+}
+
+static void lpfc_vmid_assign_cs_ctl(struct lpfc_vport *vport,
+ struct lpfc_vmid *vmid)
+{
+ u32 hash;
+ struct lpfc_vmid *pvmid;
+
+ if (vport->port_type == LPFC_PHYSICAL_PORT) {
+ vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport);
+ } else {
+ hash = lpfc_vmid_hash_fn(vmid->host_vmid, vmid->vmid_len);
+ pvmid =
+ lpfc_get_vmid_from_hashtable(vport->phba->pport, hash,
+ vmid->host_vmid);
+ if (pvmid)
+ vmid->un.cs_ctl_vmid = pvmid->un.cs_ctl_vmid;
+ else
+ vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport);
+ }
+}
+
+/*
+ * lpfc_vmid_get_appid - get the VMID associated with the UUID
+ * @vport: The virtual port for which this call is being executed.
+ * @uuid: UUID associated with the VE
+ * @cmd: address of scsi_cmd descriptor
+ * @tag: VMID tag
+ * Returns status of the function
+ */
+static int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid, struct
+ scsi_cmnd * cmd, union lpfc_vmid_io_tag *tag)
+{
+ struct lpfc_vmid *vmp = NULL;
+ int hash, len, rc, i;
+
+ /* check if QFPA is complete */
+ if (lpfc_vmid_is_type_priority_tag(vport) && !(vport->vmid_flag &
+ LPFC_VMID_QFPA_CMPL)) {
+ vport->work_port_events |= WORKER_CHECK_VMID_ISSUE_QFPA;
+ return -EAGAIN;
+ }
+
+ /* search if the UUID has already been mapped to the VMID */
+ len = strlen(uuid);
+ hash = lpfc_vmid_hash_fn(uuid, len);
+
+ /* search for the VMID in the table */
+ read_lock(&vport->vmid_lock);
+ vmp = lpfc_get_vmid_from_hashtable(vport, hash, uuid);
+
+ /* if found, check if its already registered */
+ if (vmp && vmp->flag & LPFC_VMID_REGISTERED) {
+ read_unlock(&vport->vmid_lock);
+ lpfc_vmid_update_entry(vport, cmd, vmp, tag);
+ rc = 0;
+ } else if (vmp && (vmp->flag & LPFC_VMID_REQ_REGISTER ||
+ vmp->flag & LPFC_VMID_DE_REGISTER)) {
+ /* else if register or dereg request has already been sent */
+ /* Hence VMID tag will not be added for this I/O */
+ read_unlock(&vport->vmid_lock);
+ rc = -EBUSY;
+ } else {
+ /* The VMID was not found in the hashtable. At this point, */
+ /* drop the read lock first before proceeding further */
+ read_unlock(&vport->vmid_lock);
+ /* start the process to obtain one as per the */
+ /* type of the VMID indicated */
+ write_lock(&vport->vmid_lock);
+ vmp = lpfc_get_vmid_from_hashtable(vport, hash, uuid);
+
+ /* while the read lock was released, in case the entry was */
+ /* added by other context or is in process of being added */
+ if (vmp && vmp->flag & LPFC_VMID_REGISTERED) {
+ lpfc_vmid_update_entry(vport, cmd, vmp, tag);
+ write_unlock(&vport->vmid_lock);
+ return 0;
+ } else if (vmp && vmp->flag & LPFC_VMID_REQ_REGISTER) {
+ write_unlock(&vport->vmid_lock);
+ return -EBUSY;
+ }
+
+ /* else search and allocate a free slot in the hash table */
+ if (vport->cur_vmid_cnt < vport->max_vmid) {
+ for (i = 0; i < vport->max_vmid; i++) {
+ vmp = vport->vmid + i;
+ if (vmp->flag == LPFC_VMID_SLOT_FREE)
+ break;
+ }
+ if (i == vport->max_vmid)
+ vmp = NULL;
+ } else {
+ vmp = NULL;
+ }
+
+ if (!vmp) {
+ write_unlock(&vport->vmid_lock);
+ return -ENOMEM;
+ }
+
+ /* Add the vmid and register */
+ lpfc_put_vmid_in_hashtable(vport, hash, vmp);
+ vmp->vmid_len = len;
+ memcpy(vmp->host_vmid, uuid, vmp->vmid_len);
+ vmp->io_rd_cnt = 0;
+ vmp->io_wr_cnt = 0;
+ vmp->flag = LPFC_VMID_SLOT_USED;
+
+ vmp->delete_inactive =
+ vport->vmid_inactivity_timeout ? 1 : 0;
+
+ /* if type priority tag, get next available VMID */
+ if (lpfc_vmid_is_type_priority_tag(vport))
+ lpfc_vmid_assign_cs_ctl(vport, vmp);
+
+ /* allocate the per cpu variable for holding */
+ /* the last access time stamp only if VMID is enabled */
+ if (!vmp->last_io_time)
+ vmp->last_io_time = __alloc_percpu(sizeof(u64),
+ __alignof__(struct
+ lpfc_vmid));
+ if (!vmp->last_io_time) {
+ hash_del(&vmp->hnode);
+ vmp->flag = LPFC_VMID_SLOT_FREE;
+ write_unlock(&vport->vmid_lock);
+ return -EIO;
+ }
+
+ write_unlock(&vport->vmid_lock);
+
+ /* complete transaction with switch */
+ if (lpfc_vmid_is_type_priority_tag(vport))
+ rc = lpfc_vmid_uvem(vport, vmp, true);
+ else
+ rc = lpfc_vmid_cmd(vport, SLI_CTAS_RAPP_IDENT, vmp);
+ if (!rc) {
+ write_lock(&vport->vmid_lock);
+ vport->cur_vmid_cnt++;
+ vmp->flag |= LPFC_VMID_REQ_REGISTER;
+ write_unlock(&vport->vmid_lock);
+ } else {
+ write_lock(&vport->vmid_lock);
+ hash_del(&vmp->hnode);
+ vmp->flag = LPFC_VMID_SLOT_FREE;
+ free_percpu(vmp->last_io_time);
+ write_unlock(&vport->vmid_lock);
+ return -EIO;
+ }
+
+ /* finally, enable the idle timer once */
+ if (!(vport->phba->pport->vmid_flag & LPFC_VMID_TIMER_ENBLD)) {
+ mod_timer(&vport->phba->inactive_vmid_poll,
+ jiffies +
+ msecs_to_jiffies(1000 * LPFC_VMID_TIMER));
+ vport->phba->pport->vmid_flag |= LPFC_VMID_TIMER_ENBLD;
+ }
+ }
+ return rc;
+}
+
+/*
+ * lpfc_is_command_vm_io - get the UUID from blk cgroup
+ * @cmd: Pointer to scsi_cmnd data structure
+ * Returns UUID if present, otherwise NULL
+ */
+static char *lpfc_is_command_vm_io(struct scsi_cmnd *cmd)
+{
+ char *uuid = NULL;
+
+ if (cmd->request) {
+ if (cmd->request->bio)
+ uuid = blkcg_get_fc_appid(cmd->request->bio);
+ }
+ return uuid;
+}
+
/**
* lpfc_queuecommand - scsi_host_template queuecommand entry point
* @shost: kernel scsi host pointer.
@@ -5168,6 +5455,7 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
struct lpfc_io_buf *lpfc_cmd;
struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
int err, idx;
+ u8 *uuid = NULL;
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
uint64_t start = 0L;
@@ -5297,6 +5585,25 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
}
+ /* check the necessary and sufficient condition to support VMID */
+ if (lpfc_is_vmid_enabled(phba) &&
+ (ndlp->vmid_support ||
+ phba->pport->vmid_priority_tagging ==
+ LPFC_VMID_PRIO_TAG_ALL_TARGETS)) {
+ /* is the I/O generated by a VM, get the associated virtual */
+ /* entity id */
+ uuid = lpfc_is_command_vm_io(cmnd);
+
+ if (uuid) {
+ err = lpfc_vmid_get_appid(vport, uuid, cmnd,
+ (union lpfc_vmid_io_tag *)
+ &lpfc_cmd->cur_iocbq.vmid_tag);
+ if (!err)
+ lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_VMID;
+ }
+ }
+
+ atomic_inc(&ndlp->cmd_pending);
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
if (unlikely(phba->hdwqstat_on & LPFC_CHECK_SCSI_IO))
this_cpu_inc(phba->sli4_hba.c_stat->xmt_io);
@@ -5384,6 +5691,31 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
return 0;
}
+/*
+ * lpfc_vmid_vport_cleanup - cleans up the resources associated with a vport
+ * @vport: The virtual port for which this call is being executed.
+ */
+void lpfc_vmid_vport_cleanup(struct lpfc_vport *vport)
+{
+ u32 bucket;
+ struct lpfc_vmid *cur;
+
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ del_timer_sync(&vport->phba->inactive_vmid_poll);
+
+ kfree(vport->qfpa_res);
+ kfree(vport->vmid_priority.vmid_range);
+ kfree(vport->vmid);
+
+ if (!hash_empty(vport->hash_table))
+ hash_for_each(vport->hash_table, bucket, cur, hnode)
+ hash_del(&cur->hnode);
+
+ vport->qfpa_res = NULL;
+ vport->vmid_priority.vmid_range = NULL;
+ vport->vmid = NULL;
+ vport->cur_vmid_cnt = 0;
+}
/**
* lpfc_abort_handler - scsi_host_template eh_abort_handler entry point
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index fc3682f15f50..f530d8fe7a8c 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -2679,6 +2679,12 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
}
}
+ /* This nlp_put pairs with lpfc_sli4_resume_rpi */
+ if (pmb->u.mb.mbxCommand == MBX_RESUME_RPI) {
+ ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
+ lpfc_nlp_put(ndlp);
+ }
+
/* Check security permission status on INIT_LINK mailbox command */
if ((pmb->u.mb.mbxCommand == MBX_INIT_LINK) &&
(pmb->u.mb.mbxStatus == MBXERR_SEC_NO_PERMISSION))
@@ -2749,7 +2755,6 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
} else {
__lpfc_sli_rpi_release(vport, ndlp);
}
-
lpfc_nlp_put(ndlp);
}
}
@@ -7694,6 +7699,15 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
goto out_free_mbox;
}
+ /* Disable VMID if app header is not supported */
+ if (phba->cfg_vmid_app_header && !(bf_get(lpfc_mbx_rq_ftr_rsp_ashdr,
+ &mqe->un.req_ftrs))) {
+ bf_set(lpfc_ftr_ashdr, &phba->sli4_hba.sli4_flags, 0);
+ phba->cfg_vmid_app_header = 0;
+ lpfc_printf_log(phba, KERN_DEBUG, LOG_SLI,
+ "1242 vmid feature not supported\n");
+ }
+
/*
* The port must support FCP initiator mode as this is the
* only mode running in the host.
@@ -7959,7 +7973,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
"0393 Error %d during rpi post operation\n",
rc);
rc = -ENODEV;
- goto out_destroy_queue;
+ goto out_free_iocblist;
}
lpfc_sli4_node_prep(phba);
@@ -8125,8 +8139,9 @@ out_io_buff_free:
out_unset_queue:
/* Unset all the queues set up in this routine when error out */
lpfc_sli4_queue_unset(phba);
-out_destroy_queue:
+out_free_iocblist:
lpfc_free_iocb_list(phba);
+out_destroy_queue:
lpfc_sli4_queue_destroy(phba);
out_stop_timers:
lpfc_stop_hba_timers(phba);
@@ -9751,6 +9766,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
*pcmd == ELS_CMD_RSCN_XMT ||
*pcmd == ELS_CMD_FDISC ||
*pcmd == ELS_CMD_LOGO ||
+ *pcmd == ELS_CMD_QFPA ||
+ *pcmd == ELS_CMD_UVEM ||
*pcmd == ELS_CMD_PLOGI)) {
bf_set(els_req64_sp, &wqe->els_req, 1);
bf_set(els_req64_sid, &wqe->els_req,
@@ -10313,6 +10330,18 @@ __lpfc_sli_issue_fcp_io_s4(struct lpfc_hba *phba, uint32_t ring_number,
bf_set(wqe_wqes, &wqe->generic.wqe_com, 0);
}
+ /* add the VMID tags as per switch response */
+ if (unlikely(piocb->iocb_flag & LPFC_IO_VMID)) {
+ if (phba->pport->vmid_priority_tagging) {
+ bf_set(wqe_ccpe, &wqe->fcp_iwrite.wqe_com, 1);
+ bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com,
+ (piocb->vmid_tag.cs_ctl_vmid));
+ } else {
+ bf_set(wqe_appid, &wqe->fcp_iwrite.wqe_com, 1);
+ bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1);
+ wqe->words[31] = piocb->vmid_tag.app_id;
+ }
+ }
rc = lpfc_sli4_issue_wqe(phba, lpfc_cmd->hdwq, piocb);
return rc;
}
@@ -13625,9 +13654,15 @@ lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe)
if (mcqe_status == MB_CQE_STATUS_SUCCESS) {
mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
- /* Reg_LOGIN of dflt RPI was successful. Now lets get
- * RID of the PPI using the same mbox buffer.
+
+ /* Reg_LOGIN of dflt RPI was successful. Mark the
+ * node as having an UNREG_LOGIN in progress to stop
+ * an unsolicited PLOGI from the same NPortId from
+ * starting another mailbox transaction.
*/
+ spin_lock_irqsave(&ndlp->lock, iflags);
+ ndlp->nlp_flag |= NLP_UNREG_INP;
+ spin_unlock_irqrestore(&ndlp->lock, iflags);
lpfc_unreg_login(phba, vport->vpi,
pmbox->un.varWords[0], pmb);
pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
@@ -17943,7 +17978,6 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
seq_dmabuf->time_stamp = jiffies;
lpfc_update_rcv_time_stamp(vport);
if (list_empty(&seq_dmabuf->dbuf.list)) {
- temp_hdr = dmabuf->hbuf.virt;
list_add_tail(&dmabuf->dbuf.list, &seq_dmabuf->dbuf.list);
return seq_dmabuf;
}
@@ -19032,14 +19066,28 @@ lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp,
if (!mboxq)
return -ENOMEM;
+ /* If cmpl assigned, then this nlp_get pairs with
+ * lpfc_mbx_cmpl_resume_rpi.
+ *
+ * Else cmpl is NULL, then this nlp_get pairs with
+ * lpfc_sli_def_mbox_cmpl.
+ */
+ if (!lpfc_nlp_get(ndlp)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
+ "2122 %s: Failed to get nlp ref\n",
+ __func__);
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ return -EIO;
+ }
+
/* Post all rpi memory regions to the port. */
lpfc_resume_rpi(mboxq, ndlp);
if (cmpl) {
mboxq->mbox_cmpl = cmpl;
mboxq->ctx_buf = arg;
- mboxq->ctx_ndlp = ndlp;
} else
mboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mboxq->ctx_ndlp = ndlp;
mboxq->vport = ndlp->vport;
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
@@ -19047,6 +19095,7 @@ lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp,
"2010 Resume RPI Mailbox failed "
"status %d, mbxStatus x%x\n", rc,
bf_get(lpfc_mqe_status, &mboxq->u.mqe));
+ lpfc_nlp_put(ndlp);
mempool_free(mboxq, phba->mbox_mem_pool);
return -EIO;
}
@@ -20136,8 +20185,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
(mb->u.mb.mbxCommand != MBX_REG_VPI))
continue;
- list_del(&mb->list);
- list_add_tail(&mb->list, &mbox_cmd_list);
+ list_move_tail(&mb->list, &mbox_cmd_list);
}
/* Clean up active mailbox command with the vport */
mb = phba->sli.mbox_active;
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 4f6936014ff5..dde8eb9d796d 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2021 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -35,6 +35,12 @@ typedef enum _lpfc_ctx_cmd {
LPFC_CTX_HOST
} lpfc_ctx_cmd;
+union lpfc_vmid_iocb_tag {
+ uint32_t app_id;
+ uint8_t cs_ctl_vmid;
+ struct lpfc_vmid_context *vmid_context; /* UVEM context information */
+};
+
struct lpfc_cq_event {
struct list_head list;
uint16_t hdwq;
@@ -100,12 +106,14 @@ struct lpfc_iocbq {
#define LPFC_IO_NVME 0x200000 /* NVME FCP command */
#define LPFC_IO_NVME_LS 0x400000 /* NVME LS command */
#define LPFC_IO_NVMET 0x800000 /* NVMET command */
+#define LPFC_IO_VMID 0x1000000 /* VMID tagged IO */
uint32_t drvrTimeout; /* driver timeout in seconds */
struct lpfc_vport *vport;/* virtual port pointer */
void *context1; /* caller context information */
void *context2; /* caller context information */
void *context3; /* caller context information */
+ uint32_t event_tag; /* LA Event tag */
union {
wait_queue_head_t *wait_queue;
struct lpfc_iocbq *rsp_iocb;
@@ -114,6 +122,7 @@ struct lpfc_iocbq {
struct lpfc_node_rrq *rrq;
} context_un;
+ union lpfc_vmid_iocb_tag vmid_tag;
void (*fabric_iocb_cmpl)(struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *);
void (*wait_iocb_cmpl)(struct lpfc_hba *, struct lpfc_iocbq *,
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 4b8e89375644..2d62fd2a9824 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.8.0.9"
+#define LPFC_DRIVER_VERSION "12.8.0.10"
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 80f546976c7e..56910e94dbf2 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -1583,9 +1583,7 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
memcpy(cmd->sense_buffer, pthru->reqsensearea,
14);
- cmd->result = (DRIVER_SENSE << 24) |
- (DID_OK << 16) |
- (CHECK_CONDITION << 1);
+ cmd->result = SAM_STAT_CHECK_CONDITION;
}
else {
if (mbox->m_out.cmd == MEGA_MBOXCMD_EXTPTHRU) {
@@ -1593,14 +1591,10 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
memcpy(cmd->sense_buffer,
epthru->reqsensearea, 14);
- cmd->result = (DRIVER_SENSE << 24) |
- (DID_OK << 16) |
- (CHECK_CONDITION << 1);
- } else {
- cmd->sense_buffer[0] = 0x70;
- cmd->sense_buffer[2] = ABORTED_COMMAND;
- cmd->result |= (CHECK_CONDITION << 1);
- }
+ cmd->result = SAM_STAT_CHECK_CONDITION;
+ } else
+ scsi_build_sense(cmd, 0,
+ ABORTED_COMMAND, 0, 0);
}
break;
@@ -1617,7 +1611,7 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
*/
if( cmd->cmnd[0] == TEST_UNIT_READY ) {
cmd->result |= (DID_ERROR << 16) |
- (RESERVATION_CONFLICT << 1);
+ SAM_STAT_RESERVATION_CONFLICT;
}
else
/*
@@ -1629,7 +1623,7 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
cmd->cmnd[0] == RELEASE) ) {
cmd->result |= (DID_ERROR << 16) |
- (RESERVATION_CONFLICT << 1);
+ SAM_STAT_RESERVATION_CONFLICT;
}
else
#endif
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 145fde302d7d..d20c2e4ee793 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -121,8 +121,8 @@ static irqreturn_t megaraid_isr(int, void *);
static void megaraid_mbox_dpc(unsigned long);
-static ssize_t megaraid_sysfs_show_app_hndl(struct device *, struct device_attribute *attr, char *);
-static ssize_t megaraid_sysfs_show_ldnum(struct device *, struct device_attribute *attr, char *);
+static ssize_t megaraid_mbox_app_hndl_show(struct device *, struct device_attribute *attr, char *);
+static ssize_t megaraid_mbox_ld_show(struct device *, struct device_attribute *attr, char *);
static int megaraid_cmm_register(adapter_t *);
static int megaraid_cmm_unregister(adapter_t *);
@@ -302,8 +302,7 @@ static struct pci_driver megaraid_pci_driver = {
// definitions for the device attributes for exporting logical drive number
// for a scsi address (Host, Channel, Id, Lun)
-static DEVICE_ATTR(megaraid_mbox_app_hndl, S_IRUSR, megaraid_sysfs_show_app_hndl,
- NULL);
+static DEVICE_ATTR_ADMIN_RO(megaraid_mbox_app_hndl);
// Host template initializer for megaraid mbox sysfs device attributes
static struct device_attribute *megaraid_shost_attrs[] = {
@@ -312,7 +311,7 @@ static struct device_attribute *megaraid_shost_attrs[] = {
};
-static DEVICE_ATTR(megaraid_mbox_ld, S_IRUSR, megaraid_sysfs_show_ldnum, NULL);
+static DEVICE_ATTR_ADMIN_RO(megaraid_mbox_ld);
// Host template initializer for megaraid mbox sysfs device attributes
static struct device_attribute *megaraid_sdev_attrs[] = {
@@ -1574,10 +1573,8 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
}
if (scp->cmnd[1] & MEGA_SCSI_INQ_EVPD) {
- scp->sense_buffer[0] = 0x70;
- scp->sense_buffer[2] = ILLEGAL_REQUEST;
- scp->sense_buffer[12] = MEGA_INVALID_FIELD_IN_CDB;
- scp->result = CHECK_CONDITION << 1;
+ scsi_build_sense(scp, 0, ILLEGAL_REQUEST,
+ MEGA_INVALID_FIELD_IN_CDB, 0);
return NULL;
}
@@ -2301,8 +2298,7 @@ megaraid_mbox_dpc(unsigned long devp)
memcpy(scp->sense_buffer, pthru->reqsensearea,
14);
- scp->result = DRIVER_SENSE << 24 |
- DID_OK << 16 | CHECK_CONDITION << 1;
+ scp->result = SAM_STAT_CHECK_CONDITION;
}
else {
if (mbox->cmd == MBOXCMD_EXTPTHRU) {
@@ -2310,14 +2306,10 @@ megaraid_mbox_dpc(unsigned long devp)
memcpy(scp->sense_buffer,
epthru->reqsensearea, 14);
- scp->result = DRIVER_SENSE << 24 |
- DID_OK << 16 |
- CHECK_CONDITION << 1;
- } else {
- scp->sense_buffer[0] = 0x70;
- scp->sense_buffer[2] = ABORTED_COMMAND;
- scp->result = CHECK_CONDITION << 1;
- }
+ scp->result = SAM_STAT_CHECK_CONDITION;
+ } else
+ scsi_build_sense(scp, 0,
+ ABORTED_COMMAND, 0, 0);
}
break;
@@ -2334,7 +2326,7 @@ megaraid_mbox_dpc(unsigned long devp)
*/
if (scp->cmnd[0] == TEST_UNIT_READY) {
scp->result = DID_ERROR << 16 |
- RESERVATION_CONFLICT << 1;
+ SAM_STAT_RESERVATION_CONFLICT;
}
else
/*
@@ -2345,7 +2337,7 @@ megaraid_mbox_dpc(unsigned long devp)
scp->cmnd[0] == RELEASE)) {
scp->result = DID_ERROR << 16 |
- RESERVATION_CONFLICT << 1;
+ SAM_STAT_RESERVATION_CONFLICT;
}
else {
scp->result = DID_BAD_TARGET << 16 | status;
@@ -3240,8 +3232,6 @@ megaraid_mbox_fire_sync_cmd(adapter_t *adapter)
int i;
uint32_t dword;
- mbox = (mbox_t *)raw_mbox;
-
memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
raw_mbox[0] = 0xFF;
@@ -3970,7 +3960,7 @@ megaraid_sysfs_get_ldmap(adapter_t *adapter)
/**
- * megaraid_sysfs_show_app_hndl - display application handle for this adapter
+ * megaraid_mbox_app_hndl_show - display application handle for this adapter
* @dev : class device object representation for the host
* @attr : device attribute (unused)
* @buf : buffer to send data to
@@ -3980,8 +3970,7 @@ megaraid_sysfs_get_ldmap(adapter_t *adapter)
* handle, since we do not interface with applications directly.
*/
static ssize_t
-megaraid_sysfs_show_app_hndl(struct device *dev, struct device_attribute *attr,
- char *buf)
+megaraid_mbox_app_hndl_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(dev);
adapter_t *adapter = (adapter_t *)SCSIHOST2ADAP(shost);
@@ -3994,7 +3983,7 @@ megaraid_sysfs_show_app_hndl(struct device *dev, struct device_attribute *attr,
/**
- * megaraid_sysfs_show_ldnum - display the logical drive number for this device
+ * megaraid_mbox_ld_show - display the logical drive number for this device
* @dev : device object representation for the scsi device
* @attr : device attribute to show
* @buf : buffer to send data to
@@ -4009,7 +3998,7 @@ megaraid_sysfs_show_app_hndl(struct device *dev, struct device_attribute *attr,
* <int> <int> <int> <int>
*/
static ssize_t
-megaraid_sysfs_show_ldnum(struct device *dev, struct device_attribute *attr, char *buf)
+megaraid_mbox_ld_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
adapter_t *adapter = (adapter_t *)SCSIHOST2ADAP(sdev->host);
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index b5a765b73c76..7af2c23652b0 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.714.04.00-rc1"
-#define MEGASAS_RELDATE "Apr 14, 2020"
+#define MEGASAS_VERSION "07.717.02.00-rc1"
+#define MEGASAS_RELDATE "May 19, 2021"
#define MEGASAS_MSIX_NAME_LEN 32
@@ -2262,6 +2262,15 @@ enum MR_PERF_MODE {
(mode) == MR_LATENCY_PERF_MODE ? "Latency" : \
"Unknown")
+enum MEGASAS_LD_TARGET_ID_STATUS {
+ LD_TARGET_ID_INITIAL,
+ LD_TARGET_ID_ACTIVE,
+ LD_TARGET_ID_DELETED,
+};
+
+#define MEGASAS_TARGET_ID(sdev) \
+ (((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id)
+
struct megasas_instance {
unsigned int *reply_map;
@@ -2326,6 +2335,9 @@ struct megasas_instance {
struct megasas_pd_list pd_list[MEGASAS_MAX_PD];
struct megasas_pd_list local_pd_list[MEGASAS_MAX_PD];
u8 ld_ids[MEGASAS_MAX_LD_IDS];
+ u8 ld_tgtid_status[MEGASAS_MAX_LD_IDS];
+ u8 ld_ids_prev[MEGASAS_MAX_LD_IDS];
+ u8 ld_ids_from_raidmap[MEGASAS_MAX_LD_IDS];
s8 init_id;
u16 max_num_sge;
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 4d4e9dbe5193..ec10b2497310 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -141,6 +141,8 @@ static int megasas_register_aen(struct megasas_instance *instance,
u32 seq_num, u32 class_locale_word);
static void megasas_get_pd_info(struct megasas_instance *instance,
struct scsi_device *sdev);
+static void
+megasas_set_ld_removed_by_fw(struct megasas_instance *instance);
/*
* PCI ID table for all supported controllers
@@ -213,7 +215,7 @@ static bool support_nvme_encapsulation;
static bool support_pci_lane_margining;
/* define lock for aen poll */
-static spinlock_t poll_aen_lock;
+static DEFINE_SPINLOCK(poll_aen_lock);
extern struct dentry *megasas_debugfs_root;
extern int megasas_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num);
@@ -436,6 +438,12 @@ megasas_decode_evt(struct megasas_instance *instance)
(class_locale.members.locale),
format_class(class_locale.members.class),
evt_detail->description);
+
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "evt_detail.args.ld.target_id/index %d/%d\n",
+ evt_detail->args.ld.target_id, evt_detail->args.ld.ld_index);
+
}
/*
@@ -1779,6 +1787,7 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
{
struct megasas_instance *instance;
struct MR_PRIV_DEVICE *mr_device_priv_data;
+ u32 ld_tgt_id;
instance = (struct megasas_instance *)
scmd->device->host->hostdata;
@@ -1805,17 +1814,21 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
}
}
- if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
+ mr_device_priv_data = scmd->device->hostdata;
+ if (!mr_device_priv_data ||
+ (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)) {
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
return 0;
}
- mr_device_priv_data = scmd->device->hostdata;
- if (!mr_device_priv_data) {
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- return 0;
+ if (MEGASAS_IS_LOGICAL(scmd->device)) {
+ ld_tgt_id = MEGASAS_TARGET_ID(scmd->device);
+ if (instance->ld_tgtid_status[ld_tgt_id] == LD_TARGET_ID_DELETED) {
+ scmd->result = DID_NO_CONNECT << 16;
+ scmd->scsi_done(scmd);
+ return 0;
+ }
}
if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
@@ -2095,7 +2108,7 @@ static int megasas_slave_configure(struct scsi_device *sdev)
static int megasas_slave_alloc(struct scsi_device *sdev)
{
- u16 pd_index = 0;
+ u16 pd_index = 0, ld_tgt_id;
struct megasas_instance *instance ;
struct MR_PRIV_DEVICE *mr_device_priv_data;
@@ -2120,6 +2133,14 @@ scan_target:
GFP_KERNEL);
if (!mr_device_priv_data)
return -ENOMEM;
+
+ if (MEGASAS_IS_LOGICAL(sdev)) {
+ ld_tgt_id = MEGASAS_TARGET_ID(sdev);
+ instance->ld_tgtid_status[ld_tgt_id] = LD_TARGET_ID_ACTIVE;
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ sdev_printk(KERN_INFO, sdev, "LD target ID %d created.\n", ld_tgt_id);
+ }
+
sdev->hostdata = mr_device_priv_data;
atomic_set(&mr_device_priv_data->r1_ldio_hint,
@@ -2129,6 +2150,19 @@ scan_target:
static void megasas_slave_destroy(struct scsi_device *sdev)
{
+ u16 ld_tgt_id;
+ struct megasas_instance *instance;
+
+ instance = megasas_lookup_instance(sdev->host->host_no);
+
+ if (MEGASAS_IS_LOGICAL(sdev)) {
+ ld_tgt_id = MEGASAS_TARGET_ID(sdev);
+ instance->ld_tgtid_status[ld_tgt_id] = LD_TARGET_ID_DELETED;
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ sdev_printk(KERN_INFO, sdev,
+ "LD target ID %d removed from OS stack\n", ld_tgt_id);
+ }
+
kfree(sdev->hostdata);
sdev->hostdata = NULL;
}
@@ -3525,6 +3559,22 @@ megasas_complete_abort(struct megasas_instance *instance,
}
}
+static void
+megasas_set_ld_removed_by_fw(struct megasas_instance *instance)
+{
+ uint i;
+
+ for (i = 0; (i < MEGASAS_MAX_LD_IDS); i++) {
+ if (instance->ld_ids_prev[i] != 0xff &&
+ instance->ld_ids_from_raidmap[i] == 0xff) {
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "LD target ID %d removed from RAID map\n", i);
+ instance->ld_tgtid_status[i] = LD_TARGET_ID_DELETED;
+ }
+ }
+}
+
/**
* megasas_complete_cmd - Completes a command
* @instance: Adapter soft state
@@ -3617,8 +3667,6 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
SCSI_SENSE_BUFFERSIZE);
memcpy(cmd->scmd->sense_buffer, cmd->sense,
hdr->sense_len);
-
- cmd->scmd->result |= DRIVER_SENSE << 24;
}
break;
@@ -3687,9 +3735,13 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
fusion->fast_path_io = 0;
}
+ if (instance->adapter_type >= INVADER_SERIES)
+ megasas_set_ld_removed_by_fw(instance);
+
megasas_sync_map_info(instance);
spin_unlock_irqrestore(instance->host->host_lock,
flags);
+
break;
}
if (opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
@@ -7545,11 +7597,16 @@ static int megasas_probe_one(struct pci_dev *pdev,
return 0;
fail_start_aen:
+ instance->unload = 1;
+ scsi_remove_host(instance->host);
fail_io_attach:
megasas_mgmt_info.count--;
megasas_mgmt_info.max_index--;
megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = NULL;
+ if (instance->requestorId && !instance->skip_heartbeat_timer_del)
+ del_timer_sync(&instance->sriov_heartbeat_timer);
+
instance->instancet->disable_intr(instance);
megasas_destroy_irqs(instance);
@@ -7557,8 +7614,16 @@ fail_io_attach:
megasas_release_fusion(instance);
else
megasas_release_mfi(instance);
+
if (instance->msix_vectors)
pci_free_irq_vectors(instance->pdev);
+ instance->msix_vectors = 0;
+
+ if (instance->fw_crash_state != UNAVAILABLE)
+ megasas_free_host_crash_buffer(instance);
+
+ if (instance->adapter_type != MFI_SERIES)
+ megasas_fusion_stop_watchdog(instance);
fail_init_mfi:
scsi_host_put(host);
fail_alloc_instance:
@@ -8818,8 +8883,10 @@ megasas_aen_polling(struct work_struct *work)
union megasas_evt_class_locale class_locale;
int event_type = 0;
u32 seq_num;
+ u16 ld_target_id;
int error;
u8 dcmd_ret = DCMD_SUCCESS;
+ struct scsi_device *sdev1;
if (!instance) {
printk(KERN_ERR "invalid instance!\n");
@@ -8842,12 +8909,23 @@ megasas_aen_polling(struct work_struct *work)
break;
case MR_EVT_LD_OFFLINE:
- case MR_EVT_CFG_CLEARED:
case MR_EVT_LD_DELETED:
+ ld_target_id = instance->evt_detail->args.ld.target_id;
+ sdev1 = scsi_device_lookup(instance->host,
+ MEGASAS_MAX_PD_CHANNELS +
+ (ld_target_id / MEGASAS_MAX_DEV_PER_CHANNEL),
+ (ld_target_id - MEGASAS_MAX_DEV_PER_CHANNEL),
+ 0);
+ if (sdev1)
+ megasas_remove_scsi_device(sdev1);
+
+ event_type = SCAN_VD_CHANNEL;
+ break;
case MR_EVT_LD_CREATED:
event_type = SCAN_VD_CHANNEL;
break;
+ case MR_EVT_CFG_CLEARED:
case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
case MR_EVT_FOREIGN_CFG_IMPORTED:
case MR_EVT_LD_STATE_CHANGE:
@@ -8934,8 +9012,6 @@ static int __init megasas_init(void)
*/
pr_info("megasas: %s\n", MEGASAS_VERSION);
- spin_lock_init(&poll_aen_lock);
-
support_poll_for_event = 2;
support_device_change = 1;
support_nvme_encapsulation = true;
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index b6c08d620033..83f69c33b01a 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -349,6 +349,10 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance, u64 map_id)
num_lds = le16_to_cpu(drv_map->raidMap.ldCount);
+ memcpy(instance->ld_ids_prev,
+ instance->ld_ids_from_raidmap,
+ sizeof(instance->ld_ids_from_raidmap));
+ memset(instance->ld_ids_from_raidmap, 0xff, MEGASAS_MAX_LD_IDS);
/*Convert Raid capability values to CPU arch */
for (i = 0; (num_lds > 0) && (i < MAX_LOGICAL_DRIVES_EXT); i++) {
ld = MR_TargetIdToLdGet(i, drv_map);
@@ -359,7 +363,7 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance, u64 map_id)
raid = MR_LdRaidGet(ld, drv_map);
le32_to_cpus((u32 *)&raid->capability);
-
+ instance->ld_ids_from_raidmap[i] = i;
num_lds--;
}
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 2221175ae051..06399c026a8d 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -2051,7 +2051,6 @@ map_cmd_status(struct fusion_context *fusion,
SCSI_SENSE_BUFFERSIZE);
memcpy(scmd->sense_buffer, sense,
SCSI_SENSE_BUFFERSIZE);
- scmd->result |= DRIVER_SENSE << 24;
}
/*
@@ -3203,6 +3202,8 @@ megasas_build_io_fusion(struct megasas_instance *instance,
{
int sge_count;
u8 cmd_type;
+ u16 pd_index = 0;
+ u8 drive_type = 0;
struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request;
struct MR_PRIV_DEVICE *mr_device_priv_data;
mr_device_priv_data = scp->device->hostdata;
@@ -3237,8 +3238,12 @@ megasas_build_io_fusion(struct megasas_instance *instance,
megasas_build_syspd_fusion(instance, scp, cmd, true);
break;
case NON_READ_WRITE_SYSPDIO:
- if (instance->secure_jbod_support ||
- mr_device_priv_data->is_tm_capable)
+ pd_index = MEGASAS_PD_INDEX(scp);
+ drive_type = instance->pd_list[pd_index].driveType;
+ if ((instance->secure_jbod_support ||
+ mr_device_priv_data->is_tm_capable) ||
+ (instance->adapter_type >= VENTURA_SERIES &&
+ drive_type == TYPE_ENCLOSURE))
megasas_build_syspd_fusion(instance, scp, cmd, false);
else
megasas_build_syspd_fusion(instance, scp, cmd, true);
@@ -3739,6 +3744,7 @@ static void megasas_sync_irqs(unsigned long instance_addr)
if (irq_ctx->irq_poll_scheduled) {
irq_ctx->irq_poll_scheduled = false;
enable_irq(irq_ctx->os_irq);
+ complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx);
}
}
}
@@ -3770,6 +3776,7 @@ int megasas_irqpoll(struct irq_poll *irqpoll, int budget)
irq_poll_complete(irqpoll);
irq_ctx->irq_poll_scheduled = false;
enable_irq(irq_ctx->os_irq);
+ complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx);
}
return num_entries;
@@ -3786,6 +3793,7 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
{
struct megasas_instance *instance =
(struct megasas_instance *)instance_addr;
+ struct megasas_irq_context *irq_ctx = NULL;
u32 count, MSIxIndex;
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
@@ -3794,8 +3802,10 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
return;
- for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++)
- complete_cmd_fusion(instance, MSIxIndex, NULL);
+ for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++) {
+ irq_ctx = &instance->irq_context[MSIxIndex];
+ complete_cmd_fusion(instance, MSIxIndex, irq_ctx);
+ }
}
/**
@@ -5266,6 +5276,7 @@ megasas_alloc_fusion_context(struct megasas_instance *instance)
if (!fusion->log_to_span) {
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
__func__, __LINE__);
+ kfree(instance->ctrl_context);
return -ENOMEM;
}
}
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 0a9f4e44ab2c..78b72bcf58fe 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -595,9 +595,10 @@ static void mesh_done(struct mesh_state *ms, int start_next)
ms->current_req = NULL;
tp->current_req = NULL;
if (cmd) {
- cmd->result = (ms->stat << 16) | cmd->SCp.Status;
+ set_host_byte(cmd, ms->stat);
+ set_status_byte(cmd, cmd->SCp.Status);
if (ms->stat == DID_OK)
- cmd->result |= cmd->SCp.Message << 8;
+ scsi_msg_to_host_byte(cmd, cmd->SCp.Message);
if (DEBUG_TARGET(cmd)) {
printk(KERN_DEBUG "mesh_done: result = %x, data_ptr=%d, buflen=%d\n",
cmd->result, ms->data_ptr, scsi_bufflen(cmd));
@@ -993,7 +994,7 @@ static void handle_reset(struct mesh_state *ms)
for (tgt = 0; tgt < 8; ++tgt) {
tp = &ms->tgts[tgt];
if ((cmd = tp->current_req) != NULL) {
- cmd->result = DID_RESET << 16;
+ set_host_byte(cmd, DID_RESET);
tp->current_req = NULL;
mesh_completed(ms, cmd);
}
@@ -1003,7 +1004,7 @@ static void handle_reset(struct mesh_state *ms)
ms->current_req = NULL;
while ((cmd = ms->request_q) != NULL) {
ms->request_q = (struct scsi_cmnd *) cmd->host_scribble;
- cmd->result = DID_RESET << 16;
+ set_host_byte(cmd, DID_RESET);
mesh_completed(ms, cmd);
}
ms->phase = idle;
diff --git a/drivers/scsi/mpi3mr/Kconfig b/drivers/scsi/mpi3mr/Kconfig
new file mode 100644
index 000000000000..f7882375e74f
--- /dev/null
+++ b/drivers/scsi/mpi3mr/Kconfig
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+config SCSI_MPI3MR
+ tristate "Broadcom MPI3 Storage Controller Device Driver"
+ depends on PCI && SCSI
+ help
+ MPI3 based Storage & RAID Controllers Driver.
diff --git a/drivers/scsi/mpi3mr/Makefile b/drivers/scsi/mpi3mr/Makefile
new file mode 100644
index 000000000000..7c2063e04c81
--- /dev/null
+++ b/drivers/scsi/mpi3mr/Makefile
@@ -0,0 +1,4 @@
+# mpi3mr makefile
+obj-m += mpi3mr.o
+mpi3mr-y += mpi3mr_os.o \
+ mpi3mr_fw.o \
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h
new file mode 100644
index 000000000000..d43bbecef651
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h
@@ -0,0 +1,1880 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2017-2021 Broadcom Inc. All rights reserved.
+ *
+ */
+#ifndef MPI30_CNFG_H
+#define MPI30_CNFG_H 1
+#define MPI3_CONFIG_PAGETYPE_IO_UNIT (0x00)
+#define MPI3_CONFIG_PAGETYPE_MANUFACTURING (0x01)
+#define MPI3_CONFIG_PAGETYPE_IOC (0x02)
+#define MPI3_CONFIG_PAGETYPE_UEFI_BSD (0x03)
+#define MPI3_CONFIG_PAGETYPE_SECURITY (0x04)
+#define MPI3_CONFIG_PAGETYPE_ENCLOSURE (0x11)
+#define MPI3_CONFIG_PAGETYPE_DEVICE (0x12)
+#define MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT (0x20)
+#define MPI3_CONFIG_PAGETYPE_SAS_EXPANDER (0x21)
+#define MPI3_CONFIG_PAGETYPE_SAS_PHY (0x23)
+#define MPI3_CONFIG_PAGETYPE_SAS_PORT (0x24)
+#define MPI3_CONFIG_PAGETYPE_PCIE_IO_UNIT (0x30)
+#define MPI3_CONFIG_PAGETYPE_PCIE_SWITCH (0x31)
+#define MPI3_CONFIG_PAGETYPE_PCIE_LINK (0x33)
+#define MPI3_CONFIG_PAGEATTR_MASK (0xf0)
+#define MPI3_CONFIG_PAGEATTR_READ_ONLY (0x00)
+#define MPI3_CONFIG_PAGEATTR_CHANGEABLE (0x10)
+#define MPI3_CONFIG_PAGEATTR_PERSISTENT (0x20)
+#define MPI3_CONFIG_ACTION_PAGE_HEADER (0x00)
+#define MPI3_CONFIG_ACTION_READ_DEFAULT (0x01)
+#define MPI3_CONFIG_ACTION_READ_CURRENT (0x02)
+#define MPI3_CONFIG_ACTION_WRITE_CURRENT (0x03)
+#define MPI3_CONFIG_ACTION_READ_PERSISTENT (0x04)
+#define MPI3_CONFIG_ACTION_WRITE_PERSISTENT (0x05)
+#define MPI3_DEVICE_PGAD_FORM_MASK (0xf0000000)
+#define MPI3_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
+#define MPI3_DEVICE_PGAD_FORM_HANDLE (0x20000000)
+#define MPI3_DEVICE_PGAD_HANDLE_MASK (0x0000ffff)
+#define MPI3_SAS_EXPAND_PGAD_FORM_MASK (0xf0000000)
+#define MPI3_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
+#define MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM (0x10000000)
+#define MPI3_SAS_EXPAND_PGAD_FORM_HANDLE (0x20000000)
+#define MPI3_SAS_EXPAND_PGAD_PHYNUM_MASK (0x00ff0000)
+#define MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT (16)
+#define MPI3_SAS_EXPAND_PGAD_HANDLE_MASK (0x0000ffff)
+#define MPI3_SAS_PHY_PGAD_FORM_MASK (0xf0000000)
+#define MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER (0x00000000)
+#define MPI3_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x000000ff)
+#define MPI3_SASPORT_PGAD_FORM_MASK (0xf0000000)
+#define MPI3_SASPORT_PGAD_FORM_GET_NEXT_PORT (0x00000000)
+#define MPI3_SASPORT_PGAD_FORM_PORT_NUM (0x10000000)
+#define MPI3_SASPORT_PGAD_PORT_NUMBER_MASK (0x000000ff)
+#define MPI3_ENCLOS_PGAD_FORM_MASK (0xf0000000)
+#define MPI3_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
+#define MPI3_ENCLOS_PGAD_FORM_HANDLE (0x10000000)
+#define MPI3_ENCLOS_PGAD_HANDLE_MASK (0x0000ffff)
+#define MPI3_PCIE_SWITCH_PGAD_FORM_MASK (0xf0000000)
+#define MPI3_PCIE_SWITCH_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
+#define MPI3_PCIE_SWITCH_PGAD_FORM_HANDLE_PORT_NUM (0x10000000)
+#define MPI3_PCIE_SWITCH_PGAD_FORM_HANDLE (0x20000000)
+#define MPI3_PCIE_SWITCH_PGAD_PORTNUM_MASK (0x00ff0000)
+#define MPI3_PCIE_SWITCH_PGAD_PORTNUM_SHIFT (16)
+#define MPI3_PCIE_SWITCH_PGAD_HANDLE_MASK (0x0000ffff)
+#define MPI3_PCIE_LINK_PGAD_FORM_MASK (0xf0000000)
+#define MPI3_PCIE_LINK_PGAD_FORM_GET_NEXT_LINK (0x00000000)
+#define MPI3_PCIE_LINK_PGAD_FORM_LINK_NUM (0x10000000)
+#define MPI3_PCIE_LINK_PGAD_LINKNUM_MASK (0x000000ff)
+#define MPI3_SECURITY_PGAD_FORM_MASK (0xf0000000)
+#define MPI3_SECURITY_PGAD_FORM_GET_NEXT_SLOT (0x00000000)
+#define MPI3_SECURITY_PGAD_FORM_SOT_NUM (0x10000000)
+#define MPI3_SECURITY_PGAD_SLOT_GROUP_MASK (0x0000ff00)
+#define MPI3_SECURITY_PGAD_SLOT_MASK (0x000000ff)
+struct mpi3_config_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 reserved0a;
+ u8 page_version;
+ u8 page_number;
+ u8 page_type;
+ u8 action;
+ __le32 page_address;
+ __le16 page_length;
+ __le16 reserved16;
+ __le32 reserved18[2];
+ union mpi3_sge_union sgl;
+};
+
+struct mpi3_config_page_header {
+ u8 page_version;
+ u8 reserved01;
+ u8 page_number;
+ u8 page_attribute;
+ __le16 page_length;
+ u8 page_type;
+ u8 reserved07;
+};
+
+#define MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK (0xf0)
+#define MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT (4)
+#define MPI3_SAS_NEG_LINK_RATE_PHYSICAL_MASK (0x0f)
+#define MPI3_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE (0x00)
+#define MPI3_SAS_NEG_LINK_RATE_PHY_DISABLED (0x01)
+#define MPI3_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED (0x02)
+#define MPI3_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03)
+#define MPI3_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04)
+#define MPI3_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05)
+#define MPI3_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY (0x06)
+#define MPI3_SAS_NEG_LINK_RATE_1_5 (0x08)
+#define MPI3_SAS_NEG_LINK_RATE_3_0 (0x09)
+#define MPI3_SAS_NEG_LINK_RATE_6_0 (0x0a)
+#define MPI3_SAS_NEG_LINK_RATE_12_0 (0x0b)
+#define MPI3_SAS_NEG_LINK_RATE_22_5 (0x0c)
+#define MPI3_SAS_APHYINFO_INSIDE_ZPSDS_PERSISTENT (0x00000040)
+#define MPI3_SAS_APHYINFO_REQUESTED_INSIDE_ZPSDS (0x00000020)
+#define MPI3_SAS_APHYINFO_BREAK_REPLY_CAPABLE (0x00000010)
+#define MPI3_SAS_APHYINFO_REASON_MASK (0x0000000f)
+#define MPI3_SAS_APHYINFO_REASON_UNKNOWN (0x00000000)
+#define MPI3_SAS_APHYINFO_REASON_POWER_ON (0x00000001)
+#define MPI3_SAS_APHYINFO_REASON_HARD_RESET (0x00000002)
+#define MPI3_SAS_APHYINFO_REASON_SMP_PHY_CONTROL (0x00000003)
+#define MPI3_SAS_APHYINFO_REASON_LOSS_OF_SYNC (0x00000004)
+#define MPI3_SAS_APHYINFO_REASON_MULTIPLEXING_SEQ (0x00000005)
+#define MPI3_SAS_APHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00000006)
+#define MPI3_SAS_APHYINFO_REASON_BREAK_TIMEOUT (0x00000007)
+#define MPI3_SAS_APHYINFO_REASON_PHY_TEST_STOPPED (0x00000008)
+#define MPI3_SAS_APHYINFO_REASON_EXP_REDUCED_FUNC (0x00000009)
+#define MPI3_SAS_PHYINFO_STATUS_MASK (0xc0000000)
+#define MPI3_SAS_PHYINFO_STATUS_SHIFT (30)
+#define MPI3_SAS_PHYINFO_STATUS_ACCESSIBLE (0x00000000)
+#define MPI3_SAS_PHYINFO_STATUS_NOT_EXIST (0x40000000)
+#define MPI3_SAS_PHYINFO_STATUS_VACANT (0x80000000)
+#define MPI3_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000)
+#define MPI3_SAS_PHYINFO_PHY_POWER_CONDITION_ACTIVE (0x00000000)
+#define MPI3_SAS_PHYINFO_PHY_POWER_CONDITION_PARTIAL (0x08000000)
+#define MPI3_SAS_PHYINFO_PHY_POWER_CONDITION_SLUMBER (0x10000000)
+#define MPI3_SAS_PHYINFO_REASON_MASK (0x000f0000)
+#define MPI3_SAS_PHYINFO_REASON_UNKNOWN (0x00000000)
+#define MPI3_SAS_PHYINFO_REASON_POWER_ON (0x00010000)
+#define MPI3_SAS_PHYINFO_REASON_HARD_RESET (0x00020000)
+#define MPI3_SAS_PHYINFO_REASON_SMP_PHY_CONTROL (0x00030000)
+#define MPI3_SAS_PHYINFO_REASON_LOSS_OF_SYNC (0x00040000)
+#define MPI3_SAS_PHYINFO_REASON_MULTIPLEXING_SEQ (0x00050000)
+#define MPI3_SAS_PHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00060000)
+#define MPI3_SAS_PHYINFO_REASON_BREAK_TIMEOUT (0x00070000)
+#define MPI3_SAS_PHYINFO_REASON_PHY_TEST_STOPPED (0x00080000)
+#define MPI3_SAS_PHYINFO_REASON_EXP_REDUCED_FUNC (0x00090000)
+#define MPI3_SAS_PHYINFO_SATA_PORT_ACTIVE (0x00004000)
+#define MPI3_SAS_PHYINFO_SATA_PORT_SELECTOR_PRESENT (0x00002000)
+#define MPI3_SAS_PHYINFO_VIRTUAL_PHY (0x00001000)
+#define MPI3_SAS_PHYINFO_PARTIAL_PATHWAY_TIME_MASK (0x00000f00)
+#define MPI3_SAS_PHYINFO_PARTIAL_PATHWAY_TIME_SHIFT (8)
+#define MPI3_SAS_PHYINFO_ROUTING_ATTRIBUTE_MASK (0x000000f0)
+#define MPI3_SAS_PHYINFO_ROUTING_ATTRIBUTE_DIRECT (0x00000000)
+#define MPI3_SAS_PHYINFO_ROUTING_ATTRIBUTE_SUBTRACTIVE (0x00000010)
+#define MPI3_SAS_PHYINFO_ROUTING_ATTRIBUTE_TABLE (0x00000020)
+#define MPI3_SAS_PRATE_MAX_RATE_MASK (0xf0)
+#define MPI3_SAS_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00)
+#define MPI3_SAS_PRATE_MAX_RATE_1_5 (0x80)
+#define MPI3_SAS_PRATE_MAX_RATE_3_0 (0x90)
+#define MPI3_SAS_PRATE_MAX_RATE_6_0 (0xa0)
+#define MPI3_SAS_PRATE_MAX_RATE_12_0 (0xb0)
+#define MPI3_SAS_PRATE_MAX_RATE_22_5 (0xc0)
+#define MPI3_SAS_PRATE_MIN_RATE_MASK (0x0f)
+#define MPI3_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00)
+#define MPI3_SAS_PRATE_MIN_RATE_1_5 (0x08)
+#define MPI3_SAS_PRATE_MIN_RATE_3_0 (0x09)
+#define MPI3_SAS_PRATE_MIN_RATE_6_0 (0x0a)
+#define MPI3_SAS_PRATE_MIN_RATE_12_0 (0x0b)
+#define MPI3_SAS_PRATE_MIN_RATE_22_5 (0x0c)
+#define MPI3_SAS_HWRATE_MAX_RATE_MASK (0xf0)
+#define MPI3_SAS_HWRATE_MAX_RATE_1_5 (0x80)
+#define MPI3_SAS_HWRATE_MAX_RATE_3_0 (0x90)
+#define MPI3_SAS_HWRATE_MAX_RATE_6_0 (0xa0)
+#define MPI3_SAS_HWRATE_MAX_RATE_12_0 (0xb0)
+#define MPI3_SAS_HWRATE_MAX_RATE_22_5 (0xc0)
+#define MPI3_SAS_HWRATE_MIN_RATE_MASK (0x0f)
+#define MPI3_SAS_HWRATE_MIN_RATE_1_5 (0x08)
+#define MPI3_SAS_HWRATE_MIN_RATE_3_0 (0x09)
+#define MPI3_SAS_HWRATE_MIN_RATE_6_0 (0x0a)
+#define MPI3_SAS_HWRATE_MIN_RATE_12_0 (0x0b)
+#define MPI3_SAS_HWRATE_MIN_RATE_22_5 (0x0c)
+#define MPI3_SLOT_INVALID (0xffff)
+#define MPI3_SLOT_INDEX_INVALID (0xffff)
+struct mpi3_man_page0 {
+ struct mpi3_config_page_header header;
+ u8 chip_revision[8];
+ u8 chip_name[32];
+ u8 board_name[32];
+ u8 board_assembly[32];
+ u8 board_tracer_number[32];
+ __le32 board_power;
+ __le32 reserved94;
+ __le32 reserved98;
+ u8 oem;
+ u8 sub_oem;
+ __le16 reserved9e;
+ u8 board_mfg_day;
+ u8 board_mfg_month;
+ __le16 board_mfg_year;
+ u8 board_rework_day;
+ u8 board_rework_month;
+ __le16 board_rework_year;
+ __le64 board_revision;
+ u8 e_pack_fru[16];
+ u8 product_name[256];
+};
+
+#define MPI3_MAN0_PAGEVERSION (0x00)
+#define MPI3_MAN1_VPD_SIZE (512)
+struct mpi3_man_page1 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08[2];
+ u8 vpd[MPI3_MAN1_VPD_SIZE];
+};
+
+#define MPI3_MAN1_PAGEVERSION (0x00)
+struct mpi3_man5_phy_entry {
+ __le64 ioc_wwid;
+ __le64 device_name;
+ __le64 sata_wwid;
+};
+
+#ifndef MPI3_MAN5_PHY_MAX
+#define MPI3_MAN5_PHY_MAX (1)
+#endif
+struct mpi3_man_page5 {
+ struct mpi3_config_page_header header;
+ u8 num_phys;
+ u8 reserved09[3];
+ __le32 reserved0c;
+ struct mpi3_man5_phy_entry phy[MPI3_MAN5_PHY_MAX];
+};
+
+#define MPI3_MAN5_PAGEVERSION (0x00)
+struct mpi3_man6_gpio_entry {
+ u8 function_code;
+ u8 reserved01;
+ __le16 flags;
+ u8 param1;
+ u8 param2;
+ __le16 reserved06;
+ __le32 param3;
+};
+
+#define MPI3_MAN6_GPIO_FUNCTION_GENERIC (0x00)
+#define MPI3_MAN6_GPIO_FUNCTION_ALTERNATE (0x01)
+#define MPI3_MAN6_GPIO_FUNCTION_EXT_INTERRUPT (0x02)
+#define MPI3_MAN6_GPIO_FUNCTION_GLOBAL_ACTIVITY (0x03)
+#define MPI3_MAN6_GPIO_FUNCTION_OVER_TEMPERATURE (0x04)
+#define MPI3_MAN6_GPIO_FUNCTION_PORT_STATUS_GREEN (0x05)
+#define MPI3_MAN6_GPIO_FUNCTION_PORT_STATUS_YELLOW (0x06)
+#define MPI3_MAN6_GPIO_FUNCTION_CABLE_MANAGEMENT (0x07)
+#define MPI3_MAN6_GPIO_FUNCTION_BKPLANE_MGMT_TYPE (0x08)
+#define MPI3_MAN6_GPIO_FUNCTION_ISTWI_MUX_RESET (0x09)
+#define MPI3_MAN6_GPIO_FUNCTION_ISTWI_RESET (0x0a)
+#define MPI3_MAN6_GPIO_FUNCTION_BACKEND_PCIE_RESET (0x0b)
+#define MPI3_MAN6_GPIO_FUNCTION_GLOBAL_FAULT (0x0c)
+#define MPI3_MAN6_GPIO_FUNCTION_EPACK_ATTN (0x0d)
+#define MPI3_MAN6_GPIO_FUNCTION_EPACK_ONLINE (0x0e)
+#define MPI3_MAN6_GPIO_FUNCTION_EPACK_FAULT (0x0f)
+#define MPI3_MAN6_GPIO_FUNCTION_CTRL_TYPE (0x10)
+#define MPI3_MAN6_GPIO_FUNCTION_LICENSE (0x11)
+#define MPI3_MAN6_GPIO_FUNCTION_REFCLK_CONTROL (0x12)
+#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_SOURCE_MASK (0xf0)
+#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_SOURCE_GENERIC (0x00)
+#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_SOURCE_CABLE_MGMT (0x10)
+#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_SOURCE_ACTIVE_CABLE_OVERCURRENT (0x20)
+#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_TRIGGER_MASK (0x01)
+#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_TRIGGER_EDGE (0x00)
+#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_TRIGGER_LEVEL (0x01)
+#define MPI3_MAN6_GPIO_PORT_GREEN_PARAM1_PHY_STATUS_ALL_UP (0x00)
+#define MPI3_MAN6_GPIO_PORT_GREEN_PARAM1_PHY_STATUS_ONE_OR_MORE_UP (0x01)
+#define MPI3_MAN6_GPIO_CABLE_MGMT_PARAM1_INTERFACE_MODULE_PRESENT (0x00)
+#define MPI3_MAN6_GPIO_CABLE_MGMT_PARAM1_INTERFACE_ACTIVE_CABLE_ENABLE (0x01)
+#define MPI3_MAN6_GPIO_CABLE_MGMT_PARAM1_INTERFACE_CABLE_MGMT_ENABLE (0x02)
+#define MPI3_MAN6_GPIO_ISTWI_MUX_RESET_PARAM2_SPEC_MUX (0x00)
+#define MPI3_MAN6_GPIO_ISTWI_MUX_RESET_PARAM2_ALL_MUXES (0x01)
+#define MPI3_MAN6_GPIO_LICENSE_PARAM1_TYPE_IBUTTON (0x00)
+#define MPI3_MAN6_GPIO_FLAGS_SLEW_RATE_MASK (0x0100)
+#define MPI3_MAN6_GPIO_FLAGS_SLEW_RATE_FAST_EDGE (0x0100)
+#define MPI3_MAN6_GPIO_FLAGS_SLEW_RATE_SLOW_EDGE (0x0000)
+#define MPI3_MAN6_GPIO_FLAGS_DRIVE_STRENGTH_MASK (0x00c0)
+#define MPI3_MAN6_GPIO_FLAGS_DRIVE_STRENGTH_100OHM (0x0000)
+#define MPI3_MAN6_GPIO_FLAGS_DRIVE_STRENGTH_66OHM (0x0040)
+#define MPI3_MAN6_GPIO_FLAGS_DRIVE_STRENGTH_50OHM (0x0080)
+#define MPI3_MAN6_GPIO_FLAGS_DRIVE_STRENGTH_33OHM (0x00c0)
+#define MPI3_MAN6_GPIO_FLAGS_ALT_DATA_SEL_MASK (0x0030)
+#define MPI3_MAN6_GPIO_FLAGS_ALT_DATA_SEL_SHIFT (4)
+#define MPI3_MAN6_GPIO_FLAGS_ACTIVE_HIGH (0x0008)
+#define MPI3_MAN6_GPIO_FLAGS_BI_DIR_ENABLED (0x0004)
+#define MPI3_MAN6_GPIO_FLAGS_DIRECTION_MASK (0x0003)
+#define MPI3_MAN6_GPIO_FLAGS_DIRECTION_INPUT (0x0000)
+#define MPI3_MAN6_GPIO_FLAGS_DIRECTION_OPEN_DRAIN_OUTPUT (0x0001)
+#define MPI3_MAN6_GPIO_FLAGS_DIRECTION_OPEN_SOURCE_OUTPUT (0x0002)
+#define MPI3_MAN6_GPIO_FLAGS_DIRECTION_PUSH_PULL_OUTPUT (0x0003)
+#ifndef MPI3_MAN6_GPIO_MAX
+#define MPI3_MAN6_GPIO_MAX (1)
+#endif
+struct mpi3_man_page6 {
+ struct mpi3_config_page_header header;
+ __le16 flags;
+ __le16 reserved0a;
+ u8 num_gpio;
+ u8 reserved0d[3];
+ struct mpi3_man6_gpio_entry gpio[MPI3_MAN6_GPIO_MAX];
+};
+
+#define MPI3_MAN6_PAGEVERSION (0x00)
+#define MPI3_MAN6_FLAGS_HEARTBEAT_LED_DISABLED (0x0001)
+struct mpi3_man7_receptacle_info {
+ __le32 name[4];
+ u8 location;
+ u8 connector_type;
+ u8 ped_clk;
+ u8 connector_id;
+ __le32 reserved14;
+};
+
+#define MPI3_MAN7_LOCATION_UNKNOWN (0x00)
+#define MPI3_MAN7_LOCATION_INTERNAL (0x01)
+#define MPI3_MAN7_LOCATION_EXTERNAL (0x02)
+#define MPI3_MAN7_LOCATION_VIRTUAL (0x03)
+#define MPI3_MAN7_PEDCLK_ROUTING_MASK (0x10)
+#define MPI3_MAN7_PEDCLK_ROUTING_DIRECT (0x00)
+#define MPI3_MAN7_PEDCLK_ROUTING_CLOCK_BUFFER (0x10)
+#define MPI3_MAN7_PEDCLK_ID_MASK (0x0f)
+#ifndef MPI3_MAN7_RECEPTACLE_INFO_MAX
+#define MPI3_MAN7_RECEPTACLE_INFO_MAX (1)
+#endif
+struct mpi3_man_page7 {
+ struct mpi3_config_page_header header;
+ __le32 flags;
+ u8 num_receptacles;
+ u8 reserved0d[3];
+ __le32 enclosure_name[4];
+ struct mpi3_man7_receptacle_info receptacle_info[MPI3_MAN7_RECEPTACLE_INFO_MAX];
+};
+
+#define MPI3_MAN7_PAGEVERSION (0x00)
+#define MPI3_MAN7_FLAGS_BASE_ENCLOSURE_LEVEL_MASK (0x01)
+#define MPI3_MAN7_FLAGS_BASE_ENCLOSURE_LEVEL_0 (0x00)
+#define MPI3_MAN7_FLAGS_BASE_ENCLOSURE_LEVEL_1 (0x01)
+struct mpi3_man8_phy_info {
+ u8 receptacle_id;
+ u8 connector_lane;
+ __le16 reserved02;
+ __le16 slotx1;
+ __le16 slotx2;
+ __le16 slotx4;
+ __le16 reserved0a;
+ __le32 reserved0c;
+};
+
+#ifndef MPI3_MAN8_PHY_INFO_MAX
+#define MPI3_MAN8_PHY_INFO_MAX (1)
+#endif
+struct mpi3_man_page8 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ u8 num_phys;
+ u8 reserved0d[3];
+ struct mpi3_man8_phy_info phy_info[MPI3_MAN8_PHY_INFO_MAX];
+};
+
+#define MPI3_MAN8_PAGEVERSION (0x00)
+struct mpi3_man9_rsrc_entry {
+ __le32 maximum;
+ __le32 decrement;
+ __le32 minimum;
+ __le32 actual;
+};
+
+enum mpi3_man9_resources {
+ MPI3_MAN9_RSRC_OUTSTANDING_REQS = 0,
+ MPI3_MAN9_RSRC_TARGET_CMDS = 1,
+ MPI3_MAN9_RSRC_SAS_TARGETS = 2,
+ MPI3_MAN9_RSRC_PCIE_TARGETS = 3,
+ MPI3_MAN9_RSRC_INITIATORS = 4,
+ MPI3_MAN9_RSRC_VDS = 5,
+ MPI3_MAN9_RSRC_ENCLOSURES = 6,
+ MPI3_MAN9_RSRC_ENCLOSURE_PHYS = 7,
+ MPI3_MAN9_RSRC_EXPANDERS = 8,
+ MPI3_MAN9_RSRC_PCIE_SWITCHES = 9,
+ MPI3_MAN9_RSRC_PDS = 10,
+ MPI3_MAN9_RSRC_HOST_PDS = 11,
+ MPI3_MAN9_RSRC_ADV_HOST_PDS = 12,
+ MPI3_MAN9_RSRC_RAID_PDS = 13,
+ MPI3_MAN9_RSRC_NUM_RESOURCES
+};
+
+#define MPI3_MAN9_MIN_OUTSTANDING_REQS (1)
+#define MPI3_MAN9_MAX_OUTSTANDING_REQS (65000)
+#define MPI3_MAN9_MIN_TARGET_CMDS (0)
+#define MPI3_MAN9_MAX_TARGET_CMDS (65535)
+#define MPI3_MAN9_MIN_SAS_TARGETS (0)
+#define MPI3_MAN9_MAX_SAS_TARGETS (65535)
+#define MPI3_MAN9_MIN_PCIE_TARGETS (0)
+#define MPI3_MAN9_MIN_INITIATORS (0)
+#define MPI3_MAN9_MAX_INITIATORS (65535)
+#define MPI3_MAN9_MIN_ENCLOSURES (0)
+#define MPI3_MAN9_MAX_ENCLOSURES (65535)
+#define MPI3_MAN9_MIN_ENCLOSURE_PHYS (0)
+#define MPI3_MAN9_MIN_EXPANDERS (0)
+#define MPI3_MAN9_MAX_EXPANDERS (65535)
+#define MPI3_MAN9_MIN_PCIE_SWITCHES (0)
+struct mpi3_man_page9 {
+ struct mpi3_config_page_header header;
+ u8 num_resources;
+ u8 reserved09;
+ __le16 reserved0a;
+ __le32 reserved0c;
+ __le32 reserved10;
+ __le32 reserved14;
+ __le32 reserved18;
+ __le32 reserved1c;
+ struct mpi3_man9_rsrc_entry resource[MPI3_MAN9_RSRC_NUM_RESOURCES];
+};
+
+#define MPI3_MAN9_PAGEVERSION (0x00)
+struct mpi3_man10_istwi_ctrlr_entry {
+ __le16 slave_address;
+ __le16 flags;
+ __le32 reserved04;
+};
+
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_SLAVE_ENABLED (0x0002)
+#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_MASTER_ENABLED (0x0001)
+#ifndef MPI3_MAN10_ISTWI_CTRLR_MAX
+#define MPI3_MAN10_ISTWI_CTRLR_MAX (1)
+#endif
+struct mpi3_man_page10 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ u8 num_istwi_ctrl;
+ u8 reserved0d[3];
+ struct mpi3_man10_istwi_ctrlr_entry istwi_controller[MPI3_MAN10_ISTWI_CTRLR_MAX];
+};
+
+#define MPI3_MAN10_PAGEVERSION (0x00)
+struct mpi3_man11_mux_device_format {
+ u8 max_channel;
+ u8 reserved01[3];
+ __le32 reserved04;
+};
+
+struct mpi3_man11_temp_sensor_device_format {
+ u8 type;
+ u8 reserved01[3];
+ u8 temp_channel[4];
+};
+
+#define MPI3_MAN11_TEMP_SENSOR_TYPE_MAX6654 (0x00)
+#define MPI3_MAN11_TEMP_SENSOR_TYPE_EMC1442 (0x01)
+#define MPI3_MAN11_TEMP_SENSOR_TYPE_ADT7476 (0x02)
+#define MPI3_MAN11_TEMP_SENSOR_CHANNEL_ENABLED (0x01)
+struct mpi3_man11_seeprom_device_format {
+ u8 size;
+ u8 page_write_size;
+ __le16 reserved02;
+ __le32 reserved04;
+};
+
+#define MPI3_MAN11_SEEPROM_SIZE_1KBITS (0x01)
+#define MPI3_MAN11_SEEPROM_SIZE_2KBITS (0x02)
+#define MPI3_MAN11_SEEPROM_SIZE_4KBITS (0x03)
+#define MPI3_MAN11_SEEPROM_SIZE_8KBITS (0x04)
+#define MPI3_MAN11_SEEPROM_SIZE_16KBITS (0x05)
+#define MPI3_MAN11_SEEPROM_SIZE_32KBITS (0x06)
+#define MPI3_MAN11_SEEPROM_SIZE_64KBITS (0x07)
+#define MPI3_MAN11_SEEPROM_SIZE_128KBITS (0x08)
+struct mpi3_man11_ddr_spd_device_format {
+ u8 channel;
+ u8 reserved01[3];
+ __le32 reserved04;
+};
+
+struct mpi3_man11_cable_mgmt_device_format {
+ u8 type;
+ u8 receptacle_id;
+ __le16 reserved02;
+ __le32 reserved04;
+};
+
+#define MPI3_MAN11_CABLE_MGMT_TYPE_SFF_8636 (0x00)
+struct mpi3_man11_bkplane_spec_ubm_format {
+ __le16 flags;
+ __le16 reserved02;
+};
+
+#define MPI3_MAN11_BKPLANE_UBM_FLAGS_REFCLK_POLICY_ALWAYS_ENABLED (0x0200)
+#define MPI3_MAN11_BKPLANE_UBM_FLAGS_FORCE_POLLING (0x0100)
+#define MPI3_MAN11_BKPLANE_UBM_FLAGS_MAX_FRU_MASK (0x00f0)
+#define MPI3_MAN11_BKPLANE_UBM_FLAGS_MAX_FRU_SHIFT (4)
+#define MPI3_MAN11_BKPLANE_UBM_FLAGS_POLL_INTERVAL_MASK (0x000f)
+#define MPI3_MAN11_BKPLANE_UBM_FLAGS_POLL_INTERVAL_SHIFT (0)
+struct mpi3_man11_bkplane_spec_vpp_format {
+ __le16 flags;
+ __le16 reserved02;
+};
+
+#define MPI3_MAN11_BKPLANE_VPP_FLAGS_REFCLK_POLICY_ALWAYS_ENABLED (0x0040)
+#define MPI3_MAN11_BKPLANE_VPP_FLAGS_PRESENCE_DETECT_MASK (0x0030)
+#define MPI3_MAN11_BKPLANE_VPP_FLAGS_PRESENCE_DETECT_GPIO (0x0000)
+#define MPI3_MAN11_BKPLANE_VPP_FLAGS_PRESENCE_DETECT_REG (0x0010)
+#define MPI3_MAN11_BKPLANE_VPP_FLAGS_POLL_INTERVAL_MASK (0x000f)
+#define MPI3_MAN11_BKPLANE_VPP_FLAGS_POLL_INTERVAL_SHIFT (0)
+union mpi3_man11_bkplane_spec_format {
+ struct mpi3_man11_bkplane_spec_ubm_format ubm;
+ struct mpi3_man11_bkplane_spec_vpp_format vpp;
+};
+
+struct mpi3_man11_bkplane_mgmt_device_format {
+ u8 type;
+ u8 receptacle_id;
+ __le16 reserved02;
+ union mpi3_man11_bkplane_spec_format backplane_mgmt_specific;
+};
+
+#define MPI3_MAN11_BKPLANE_MGMT_TYPE_UBM (0x00)
+#define MPI3_MAN11_BKPLANE_MGMT_TYPE_VPP (0x01)
+struct mpi3_man11_gas_gauge_device_format {
+ u8 type;
+ u8 reserved01[3];
+ __le32 reserved04;
+};
+
+#define MPI3_MAN11_GAS_GAUGE_TYPE_STANDARD (0x00)
+union mpi3_man11_device_specific_format {
+ struct mpi3_man11_mux_device_format mux;
+ struct mpi3_man11_temp_sensor_device_format temp_sensor;
+ struct mpi3_man11_seeprom_device_format seeprom;
+ struct mpi3_man11_ddr_spd_device_format ddr_spd;
+ struct mpi3_man11_cable_mgmt_device_format cable_mgmt;
+ struct mpi3_man11_bkplane_mgmt_device_format bkplane_mgmt;
+ struct mpi3_man11_gas_gauge_device_format gas_gauge;
+ __le32 words[2];
+};
+
+struct mpi3_man11_istwi_device_format {
+ u8 device_type;
+ u8 controller;
+ u8 reserved02;
+ u8 flags;
+ __le16 device_address;
+ u8 mux_channel;
+ u8 mux_index;
+ union mpi3_man11_device_specific_format device_specific;
+};
+
+#define MPI3_MAN11_ISTWI_DEVTYPE_MUX (0x00)
+#define MPI3_MAN11_ISTWI_DEVTYPE_TEMP_SENSOR (0x01)
+#define MPI3_MAN11_ISTWI_DEVTYPE_SEEPROM (0x02)
+#define MPI3_MAN11_ISTWI_DEVTYPE_DDR_SPD (0x03)
+#define MPI3_MAN11_ISTWI_DEVTYPE_CABLE_MGMT (0x04)
+#define MPI3_MAN11_ISTWI_DEVTYPE_BACKPLANE_MGMT (0x05)
+#define MPI3_MAN11_ISTWI_DEVTYPE_GAS_GAUGE (0x06)
+#define MPI3_MAN11_ISTWI_FLAGS_MUX_PRESENT (0x01)
+#define MPI3_MAN11_ISTWI_FLAGS_BUS_SPEED_MASK (0x06)
+#define MPI3_MAN11_ISTWI_FLAGS_BUS_SPEED_100KHZ (0x00)
+#define MPI3_MAN11_ISTWI_FLAGS_BUS_SPEED_400KHZ (0x02)
+#ifndef MPI3_MAN11_ISTWI_DEVICE_MAX
+#define MPI3_MAN11_ISTWI_DEVICE_MAX (1)
+#endif
+struct mpi3_man_page11 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ u8 num_istwi_dev;
+ u8 reserved0d[3];
+ struct mpi3_man11_istwi_device_format istwi_device[MPI3_MAN11_ISTWI_DEVICE_MAX];
+};
+
+#define MPI3_MAN11_PAGEVERSION (0x00)
+#ifndef MPI3_MAN12_NUM_SGPIO_MAX
+#define MPI3_MAN12_NUM_SGPIO_MAX (1)
+#endif
+struct mpi3_man12_sgpio_info {
+ u8 slot_count;
+ u8 reserved01[3];
+ __le32 reserved04;
+ u8 phy_order[32];
+};
+
+struct mpi3_man_page12 {
+ struct mpi3_config_page_header header;
+ __le32 flags;
+ __le32 s_clock_freq;
+ __le32 activity_modulation;
+ u8 num_sgpio;
+ u8 reserved15[3];
+ __le32 reserved18;
+ __le32 reserved1c;
+ __le32 pattern[8];
+ struct mpi3_man12_sgpio_info sgpio_info[MPI3_MAN12_NUM_SGPIO_MAX];
+};
+
+#define MPI3_MAN12_PAGEVERSION (0x00)
+#define MPI3_MAN12_FLAGS_ERROR_PRESENCE_ENABLED (0x0400)
+#define MPI3_MAN12_FLAGS_ACTIVITY_INVERT_ENABLED (0x0200)
+#define MPI3_MAN12_FLAGS_GROUP_ID_DISABLED (0x0100)
+#define MPI3_MAN12_FLAGS_SIO_CLK_FILTER_ENABLED (0x0004)
+#define MPI3_MAN12_FLAGS_SCLOCK_SLOAD_TYPE_MASK (0x0002)
+#define MPI3_MAN12_FLAGS_SCLOCK_SLOAD_TYPE_PUSH_PULL (0x0000)
+#define MPI3_MAN12_FLAGS_SCLOCK_SLOAD_TYPE_OPEN_DRAIN (0x0002)
+#define MPI3_MAN12_FLAGS_SDATAOUT_TYPE_MASK (0x0001)
+#define MPI3_MAN12_FLAGS_SDATAOUT_TYPE_PUSH_PULL (0x0000)
+#define MPI3_MAN12_FLAGS_SDATAOUT_TYPE_OPEN_DRAIN (0x0001)
+#define MPI3_MAN12_SIO_CLK_FREQ_MIN (32)
+#define MPI3_MAN12_SIO_CLK_FREQ_MAX (100000)
+#define MPI3_MAN12_ACTIVITY_MODULATION_FORCE_OFF_MASK (0x0000f000)
+#define MPI3_MAN12_ACTIVITY_MODULATION_FORCE_OFF_SHIFT (12)
+#define MPI3_MAN12_ACTIVITY_MODULATION_MAX_ON_MASK (0x00000f00)
+#define MPI3_MAN12_ACTIVITY_MODULATION_MAX_ON_SHIFT (8)
+#define MPI3_MAN12_ACTIVITY_MODULATION_STRETCH_OFF_MASK (0x000000f0)
+#define MPI3_MAN12_ACTIVITY_MODULATION_STRETCH_OFF_SHIFT (4)
+#define MPI3_MAN12_ACTIVITY_MODULATION_STRETCH_ON_MASK (0x0000000f)
+#define MPI3_MAN12_ACTIVITY_MODULATION_STRETCH_ON_SHIFT (0)
+#define MPI3_MAN12_PATTERN_RATE_MASK (0xe0000000)
+#define MPI3_MAN12_PATTERN_RATE_2_HZ (0x00000000)
+#define MPI3_MAN12_PATTERN_RATE_4_HZ (0x20000000)
+#define MPI3_MAN12_PATTERN_RATE_8_HZ (0x40000000)
+#define MPI3_MAN12_PATTERN_RATE_16_HZ (0x60000000)
+#define MPI3_MAN12_PATTERN_RATE_10_HZ (0x80000000)
+#define MPI3_MAN12_PATTERN_RATE_20_HZ (0xa0000000)
+#define MPI3_MAN12_PATTERN_RATE_40_HZ (0xc0000000)
+#define MPI3_MAN12_PATTERN_LENGTH_MASK (0x1f000000)
+#define MPI3_MAN12_PATTERN_LENGTH_SHIFT (24)
+#define MPI3_MAN12_PATTERN_BIT_PATTERN_MASK (0x00ffffff)
+#define MPI3_MAN12_PATTERN_BIT_PATTERN_SHIFT (0)
+#ifndef MPI3_MAN13_NUM_TRANSLATION_MAX
+#define MPI3_MAN13_NUM_TRANSLATION_MAX (1)
+#endif
+struct mpi3_man13_translation_info {
+ __le32 slot_status;
+ __le32 mask;
+ u8 activity;
+ u8 locate;
+ u8 error;
+ u8 reserved0b;
+};
+
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_FAULT (0x20000000)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_DEVICE_OFF (0x10000000)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_DEVICE_ACTIVITY (0x00800000)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_DO_NOT_REMOVE (0x00400000)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_DEVICE_MISSING (0x00100000)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_INSERT (0x00080000)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_REMOVAL (0x00040000)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_IDENTIFY (0x00020000)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_OK (0x00008000)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_RESERVED_DEVICE (0x00004000)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_HOT_SPARE (0x00002000)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_CONSISTENCY_CHECK (0x00001000)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000800)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_IN_FAILED_ARRAY (0x00000400)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_REBUILD_REMAP (0x00000200)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_REBUILD_REMAP_ABORT (0x00000100)
+#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_PREDICTED_FAILURE (0x00000040)
+#define MPI3_MAN13_BLINK_PATTERN_FORCE_OFF (0x00)
+#define MPI3_MAN13_BLINK_PATTERN_FORCE_ON (0x01)
+#define MPI3_MAN13_BLINK_PATTERN_PATTERN_0 (0x02)
+#define MPI3_MAN13_BLINK_PATTERN_PATTERN_1 (0x03)
+#define MPI3_MAN13_BLINK_PATTERN_PATTERN_2 (0x04)
+#define MPI3_MAN13_BLINK_PATTERN_PATTERN_3 (0x05)
+#define MPI3_MAN13_BLINK_PATTERN_PATTERN_4 (0x06)
+#define MPI3_MAN13_BLINK_PATTERN_PATTERN_5 (0x07)
+#define MPI3_MAN13_BLINK_PATTERN_PATTERN_6 (0x08)
+#define MPI3_MAN13_BLINK_PATTERN_PATTERN_7 (0x09)
+#define MPI3_MAN13_BLINK_PATTERN_ACTIVITY (0x0a)
+#define MPI3_MAN13_BLINK_PATTERN_ACTIVITY_TRAIL (0x0b)
+struct mpi3_man_page13 {
+ struct mpi3_config_page_header header;
+ u8 num_trans;
+ u8 reserved09[3];
+ __le32 reserved0c;
+ struct mpi3_man13_translation_info translation[MPI3_MAN13_NUM_TRANSLATION_MAX];
+};
+
+#define MPI3_MAN13_PAGEVERSION (0x00)
+struct mpi3_man_page14 {
+ struct mpi3_config_page_header header;
+ __le16 flags;
+ __le16 reserved0a;
+ u8 num_slot_groups;
+ u8 num_slots;
+ __le16 max_cert_chain_length;
+ __le32 sealed_slots;
+};
+
+#define MPI3_MAN14_PAGEVERSION (0x00)
+#define MPI3_MAN14_FLAGS_AUTH_SESSION_REQ (0x01)
+#define MPI3_MAN14_FLAGS_AUTH_API_MASK (0x0e)
+#define MPI3_MAN14_FLAGS_AUTH_API_NONE (0x00)
+#define MPI3_MAN14_FLAGS_AUTH_API_CEREBUS (0x02)
+#define MPI3_MAN14_FLAGS_AUTH_API_DMTF_PMCI (0x04)
+#ifndef MPI3_MAN15_VERSION_RECORD_MAX
+#define MPI3_MAN15_VERSION_RECORD_MAX 1
+#endif
+struct mpi3_man15_version_record {
+ __le16 spdm_version;
+ __le16 reserved02;
+};
+
+struct mpi3_man_page15 {
+ struct mpi3_config_page_header header;
+ u8 num_version_records;
+ u8 reserved09[3];
+ __le32 reserved0c;
+ struct mpi3_man15_version_record version_record[MPI3_MAN15_VERSION_RECORD_MAX];
+};
+
+#define MPI3_MAN15_PAGEVERSION (0x00)
+#ifndef MPI3_MAN16_CERT_ALGO_MAX
+#define MPI3_MAN16_CERT_ALGO_MAX 1
+#endif
+struct mpi3_man16_certificate_algorithm {
+ u8 slot_group;
+ u8 reserved01[3];
+ __le32 base_asym_algo;
+ __le32 base_hash_algo;
+ __le32 reserved0c[3];
+};
+
+struct mpi3_man_page16 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ u8 num_cert_algos;
+ u8 reserved0d[3];
+ struct mpi3_man16_certificate_algorithm certificate_algorithm[MPI3_MAN16_CERT_ALGO_MAX];
+};
+
+#define MPI3_MAN16_PAGEVERSION (0x00)
+#ifndef MPI3_MAN17_HASH_ALGORITHM_MAX
+#define MPI3_MAN17_HASH_ALGORITHM_MAX 1
+#endif
+struct mpi3_man17_hash_algorithm {
+ u8 meas_specification;
+ u8 reserved01[3];
+ __le32 measurement_hash_algo;
+ __le32 reserved08[2];
+};
+
+struct mpi3_man_page17 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ u8 num_hash_algos;
+ u8 reserved0d[3];
+ struct mpi3_man17_hash_algorithm hash_algorithm[MPI3_MAN17_HASH_ALGORITHM_MAX];
+};
+
+#define MPI3_MAN17_PAGEVERSION (0x00)
+struct mpi3_man_page20 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ __le32 nonpremium_features;
+ u8 allowed_personalities;
+ u8 reserved11[3];
+};
+
+#define MPI3_MAN20_PAGEVERSION (0x00)
+#define MPI3_MAN20_ALLOWEDPERSON_RAID_MASK (0x02)
+#define MPI3_MAN20_ALLOWEDPERSON_RAID_ALLOWED (0x02)
+#define MPI3_MAN20_ALLOWEDPERSON_RAID_NOT_ALLOWED (0x00)
+#define MPI3_MAN20_ALLOWEDPERSON_EHBA_MASK (0x01)
+#define MPI3_MAN20_ALLOWEDPERSON_EHBA_ALLOWED (0x01)
+#define MPI3_MAN20_ALLOWEDPERSON_EHBA_NOT_ALLOWED (0x00)
+#define MPI3_MAN20_NONPREMUIM_DISABLE_PD_DEGRADED_MASK (0x01)
+#define MPI3_MAN20_NONPREMUIM_DISABLE_PD_DEGRADED_ENABLED (0x00)
+#define MPI3_MAN20_NONPREMUIM_DISABLE_PD_DEGRADED_DISABLED (0x01)
+struct mpi3_man_page21 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ __le32 flags;
+};
+
+#define MPI3_MAN21_PAGEVERSION (0x00)
+#define MPI3_MAN21_FLAGS_HOST_METADATA_CAPABILITY_MASK (0x80)
+#define MPI3_MAN21_FLAGS_HOST_METADATA_CAPABILITY_ENABLED (0x80)
+#define MPI3_MAN21_FLAGS_HOST_METADATA_CAPABILITY_DISABLED (0x00)
+#define MPI3_MAN21_FLAGS_UNCERTIFIED_DRIVES_MASK (0x60)
+#define MPI3_MAN21_FLAGS_UNCERTIFIED_DRIVES_BLOCK (0x00)
+#define MPI3_MAN21_FLAGS_UNCERTIFIED_DRIVES_ALLOW (0x20)
+#define MPI3_MAN21_FLAGS_UNCERTIFIED_DRIVES_WARN (0x40)
+#define MPI3_MAN21_FLAGS_BLOCK_SSD_WR_CACHE_CHANGE_MASK (0x08)
+#define MPI3_MAN21_FLAGS_BLOCK_SSD_WR_CACHE_CHANGE_ALLOW (0x00)
+#define MPI3_MAN21_FLAGS_BLOCK_SSD_WR_CACHE_CHANGE_PREVENT (0x08)
+#define MPI3_MAN21_FLAGS_SES_VPD_ASSOC_MASK (0x01)
+#define MPI3_MAN21_FLAGS_SES_VPD_ASSOC_DEFAULT (0x00)
+#define MPI3_MAN21_FLAGS_SES_VPD_ASSOC_OEM_SPECIFIC (0x01)
+#ifndef MPI3_MAN_PROD_SPECIFIC_MAX
+#define MPI3_MAN_PROD_SPECIFIC_MAX (1)
+#endif
+struct mpi3_man_page_product_specific {
+ struct mpi3_config_page_header header;
+ __le32 product_specific_info[MPI3_MAN_PROD_SPECIFIC_MAX];
+};
+
+struct mpi3_io_unit_page0 {
+ struct mpi3_config_page_header header;
+ __le64 unique_value;
+ __le32 nvdata_version_default;
+ __le32 nvdata_version_persistent;
+};
+
+#define MPI3_IOUNIT0_PAGEVERSION (0x00)
+struct mpi3_io_unit_page1 {
+ struct mpi3_config_page_header header;
+ __le32 flags;
+ u8 dmd_io_delay;
+ u8 dmd_report_pc_ie;
+ u8 dmd_report_sata;
+ u8 dmd_report_sas;
+};
+
+#define MPI3_IOUNIT1_PAGEVERSION (0x00)
+#define MPI3_IOUNIT1_FLAGS_NVME_WRITE_CACHE_MASK (0x00000030)
+#define MPI3_IOUNIT1_FLAGS_NVME_WRITE_CACHE_ENABLE (0x00000000)
+#define MPI3_IOUNIT1_FLAGS_NVME_WRITE_CACHE_DISABLE (0x00000010)
+#define MPI3_IOUNIT1_FLAGS_NVME_WRITE_CACHE_NO_MODIFY (0x00000020)
+#define MPI3_IOUNIT1_FLAGS_ATA_SECURITY_FREEZE_LOCK (0x00000008)
+#define MPI3_IOUNIT1_FLAGS_WRITE_SAME_BUFFER (0x00000004)
+#define MPI3_IOUNIT1_FLAGS_SATA_WRITE_CACHE_MASK (0x00000003)
+#define MPI3_IOUNIT1_FLAGS_SATA_WRITE_CACHE_ENABLE (0x00000000)
+#define MPI3_IOUNIT1_FLAGS_SATA_WRITE_CACHE_DISABLE (0x00000001)
+#define MPI3_IOUNIT1_FLAGS_SATA_WRITE_CACHE_UNCHANGED (0x00000002)
+#define MPI3_IOUNIT1_DMD_REPORT_DELAY_TIME_MASK (0x7f)
+#define MPI3_IOUNIT1_DMD_REPORT_UNIT_16_SEC (0x80)
+#ifndef MPI3_IO_UNIT2_GPIO_VAL_MAX
+#define MPI3_IO_UNIT2_GPIO_VAL_MAX (1)
+#endif
+struct mpi3_io_unit_page2 {
+ struct mpi3_config_page_header header;
+ u8 gpio_count;
+ u8 reserved09[3];
+ __le16 gpio_val[MPI3_IO_UNIT2_GPIO_VAL_MAX];
+};
+
+#define MPI3_IOUNIT2_PAGEVERSION (0x00)
+#define MPI3_IOUNIT2_GPIO_FUNCTION_MASK (0xfffc)
+#define MPI3_IOUNIT2_GPIO_FUNCTION_SHIFT (2)
+#define MPI3_IOUNIT2_GPIO_SETTING_MASK (0x0001)
+#define MPI3_IOUNIT2_GPIO_SETTING_OFF (0x0000)
+#define MPI3_IOUNIT2_GPIO_SETTING_ON (0x0001)
+struct mpi3_io_unit3_sensor {
+ __le16 flags;
+ __le16 reserved02;
+ __le16 threshold[4];
+ __le32 reserved0c;
+ __le32 reserved10;
+ __le32 reserved14;
+};
+
+#define MPI3_IOUNIT3_SENSOR_FLAGS_T3_ENABLE (0x0008)
+#define MPI3_IOUNIT3_SENSOR_FLAGS_T2_ENABLE (0x0004)
+#define MPI3_IOUNIT3_SENSOR_FLAGS_T1_ENABLE (0x0002)
+#define MPI3_IOUNIT3_SENSOR_FLAGS_T0_ENABLE (0x0001)
+#ifndef MPI3_IO_UNIT3_SENSOR_MAX
+#define MPI3_IO_UNIT3_SENSOR_MAX (1)
+#endif
+struct mpi3_io_unit_page3 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ u8 num_sensors;
+ u8 polling_interval;
+ __le16 reserved0e;
+ struct mpi3_io_unit3_sensor sensor[MPI3_IO_UNIT3_SENSOR_MAX];
+};
+
+#define MPI3_IOUNIT3_PAGEVERSION (0x00)
+struct mpi3_io_unit4_sensor {
+ __le16 current_temperature;
+ __le16 reserved02;
+ u8 flags;
+ u8 reserved05[3];
+ __le32 reserved08;
+ __le32 reserved0c;
+};
+
+#define MPI3_IOUNIT4_SENSOR_FLAGS_TEMP_VALID (0x01)
+#ifndef MPI3_IO_UNIT4_SENSOR_MAX
+#define MPI3_IO_UNIT4_SENSOR_MAX (1)
+#endif
+struct mpi3_io_unit_page4 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ u8 num_sensors;
+ u8 reserved0d[3];
+ struct mpi3_io_unit4_sensor sensor[MPI3_IO_UNIT4_SENSOR_MAX];
+};
+
+#define MPI3_IOUNIT4_PAGEVERSION (0x00)
+struct mpi3_io_unit5_spinup_group {
+ u8 max_target_spinup;
+ u8 spinup_delay;
+ u8 spinup_flags;
+ u8 reserved03;
+};
+
+#define MPI3_IOUNIT5_SPINUP_FLAGS_DISABLE (0x01)
+#ifndef MPI3_IO_UNIT5_PHY_MAX
+#define MPI3_IO_UNIT5_PHY_MAX (4)
+#endif
+struct mpi3_io_unit_page5 {
+ struct mpi3_config_page_header header;
+ struct mpi3_io_unit5_spinup_group spinup_group_parameters[4];
+ __le32 reserved18;
+ __le32 reserved1c;
+ __le32 reserved20;
+ u8 reserved24;
+ u8 sata_device_wait_time;
+ u8 spinup_encl_drive_count;
+ u8 spinup_encl_delay;
+ u8 num_phys;
+ u8 pe_initial_spinup_delay;
+ u8 topology_stable_time;
+ u8 flags;
+ u8 phy[MPI3_IO_UNIT5_PHY_MAX];
+};
+
+#define MPI3_IOUNIT5_PAGEVERSION (0x00)
+#define MPI3_IOUNIT5_FLAGS_POWER_CAPABLE_SPINUP (0x02)
+#define MPI3_IOUNIT5_FLAGS_AUTO_PORT_ENABLE (0x01)
+#define MPI3_IOUNIT5_PHY_SPINUP_GROUP_MASK (0x03)
+struct mpi3_io_unit_page6 {
+ struct mpi3_config_page_header header;
+ __le32 board_power_requirement;
+ __le32 pci_slot_power_allocation;
+ u8 flags;
+ u8 reserved11[3];
+};
+
+#define MPI3_IOUNIT6_PAGEVERSION (0x00)
+#define MPI3_IOUNIT6_FLAGS_ACT_CABLE_PWR_EXC (0x01)
+struct mpi3_io_unit_page7 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+};
+
+#define MPI3_IOUNIT7_PAGEVERSION (0x00)
+#ifndef MPI3_IOUNIT8_DIGEST_MAX
+#define MPI3_IOUNIT8_DIGEST_MAX (1)
+#endif
+union mpi3_iounit8_digest {
+ __le32 dword[16];
+ __le16 word[32];
+ u8 byte[64];
+};
+
+struct mpi3_io_unit_page8 {
+ struct mpi3_config_page_header header;
+ u8 sb_mode;
+ u8 sb_state;
+ __le16 reserved0a;
+ u8 num_slots;
+ u8 slots_available;
+ u8 current_key_encryption_algo;
+ u8 key_digest_hash_algo;
+ __le32 reserved10[2];
+ __le32 current_key[128];
+ union mpi3_iounit8_digest digest[MPI3_IOUNIT8_DIGEST_MAX];
+};
+
+#define MPI3_IOUNIT8_PAGEVERSION (0x00)
+#define MPI3_IOUNIT8_SBMODE_SECURE_DEBUG (0x04)
+#define MPI3_IOUNIT8_SBMODE_HARD_SECURE (0x02)
+#define MPI3_IOUNIT8_SBMODE_CONFIG_SECURE (0x01)
+#define MPI3_IOUNIT8_SBSTATE_KEY_UPDATE_PENDING (0x02)
+#define MPI3_IOUNIT8_SBSTATE_SECURE_BOOT_ENABLED (0x01)
+struct mpi3_io_unit_page9 {
+ struct mpi3_config_page_header header;
+ __le32 flags;
+ __le16 first_device;
+ __le16 reserved0e;
+};
+
+#define MPI3_IOUNIT9_PAGEVERSION (0x00)
+#define MPI3_IOUNIT9_FLAGS_VDFIRST_ENABLED (0x01)
+#define MPI3_IOUNIT9_FIRSTDEVICE_UNKNOWN (0xffff)
+struct mpi3_ioc_page0 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ __le16 vendor_id;
+ __le16 device_id;
+ u8 revision_id;
+ u8 reserved11[3];
+ __le32 class_code;
+ __le16 subsystem_vendor_id;
+ __le16 subsystem_id;
+};
+
+#define MPI3_IOC0_PAGEVERSION (0x00)
+struct mpi3_ioc_page1 {
+ struct mpi3_config_page_header header;
+ __le32 coalescing_timeout;
+ u8 coalescing_depth;
+ u8 pci_slot_num;
+ __le16 reserved0e;
+};
+
+#define MPI3_IOC1_PAGEVERSION (0x00)
+#define MPI3_IOC1_PCISLOTNUM_UNKNOWN (0xff)
+#ifndef MPI3_IOC2_EVENTMASK_WORDS
+#define MPI3_IOC2_EVENTMASK_WORDS (4)
+#endif
+struct mpi3_ioc_page2 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ __le16 sas_broadcast_primitive_masks;
+ __le16 sas_notify_primitive_masks;
+ __le32 event_masks[MPI3_IOC2_EVENTMASK_WORDS];
+};
+
+#define MPI3_IOC2_PAGEVERSION (0x00)
+struct mpi3_uefibsd_page0 {
+ struct mpi3_config_page_header header;
+ __le32 bsd_options;
+ u8 ssu_timeout;
+ u8 io_timeout;
+ u8 tur_retries;
+ u8 tur_interval;
+ u8 reserved10;
+ u8 security_key_timeout;
+ __le16 reserved12;
+ __le32 reserved14;
+ __le32 reserved18;
+};
+
+#define MPI3_UEFIBSD_PAGEVERSION (0x00)
+#define MPI3_UEFIBSD_BSDOPTS_REGISTRATION_MASK (0x00000003)
+#define MPI3_UEFIBSD_BSDOPTS_REGISTRATION_IOC_AND_DEVS (0x00000000)
+#define MPI3_UEFIBSD_BSDOPTS_REGISTRATION_IOC_ONLY (0x00000001)
+#define MPI3_UEFIBSD_BSDOPTS_REGISTRATION_NONE (0x00000002)
+#define MPI3_UEFIBSD_BSDOPTS_DIS_HII_CONFIG_UTIL (0x00000004)
+#define MPI3_UEFIBSD_BSDOPTS_EN_ADV_ADAPTER_CONFIG (0x00000008)
+union mpi3_security_mac {
+ __le32 dword[16];
+ __le16 word[32];
+ u8 byte[64];
+};
+
+union mpi3_security_nonce {
+ __le32 dword[16];
+ __le16 word[32];
+ u8 byte[64];
+};
+
+union mpi3_security0_cert_chain {
+ __le32 dword[1024];
+ __le16 word[2048];
+ u8 byte[4096];
+};
+
+struct mpi3_security_page0 {
+ struct mpi3_config_page_header header;
+ u8 slot_num_group;
+ u8 slot_num;
+ __le16 cert_chain_length;
+ u8 cert_chain_flags;
+ u8 reserved0d[3];
+ __le32 base_asym_algo;
+ __le32 base_hash_algo;
+ __le32 reserved18[4];
+ union mpi3_security_mac mac;
+ union mpi3_security_nonce nonce;
+ union mpi3_security0_cert_chain certificate_chain;
+};
+
+#define MPI3_SECURITY0_PAGEVERSION (0x00)
+#define MPI3_SECURITY0_CERTCHAIN_FLAGS_AUTH_API_MASK (0x0e)
+#define MPI3_SECURITY0_CERTCHAIN_FLAGS_AUTH_API_UNUSED (0x00)
+#define MPI3_SECURITY0_CERTCHAIN_FLAGS_AUTH_API_CERBERUS (0x02)
+#define MPI3_SECURITY0_CERTCHAIN_FLAGS_AUTH_API_SPDM (0x04)
+#define MPI3_SECURITY0_CERTCHAIN_FLAGS_SEALED (0x01)
+#ifndef MPI3_SECURITY1_KEY_RECORD_MAX
+#define MPI3_SECURITY1_KEY_RECORD_MAX 1
+#endif
+#ifndef MPI3_SECURITY1_PAD_MAX
+#define MPI3_SECURITY1_PAD_MAX 1
+#endif
+union mpi3_security1_key_data {
+ __le32 dword[128];
+ __le16 word[256];
+ u8 byte[512];
+};
+
+struct mpi3_security1_key_record {
+ u8 flags;
+ u8 consumer;
+ __le16 key_data_size;
+ __le32 additional_key_data;
+ __le32 reserved08[2];
+ union mpi3_security1_key_data key_data;
+};
+
+#define MPI3_SECURITY1_KEY_RECORD_FLAGS_TYPE_MASK (0x1f)
+#define MPI3_SECURITY1_KEY_RECORD_FLAGS_TYPE_NOT_VALID (0x00)
+#define MPI3_SECURITY1_KEY_RECORD_FLAGS_TYPE_HMAC (0x01)
+#define MPI3_SECURITY1_KEY_RECORD_FLAGS_TYPE_AES (0x02)
+#define MPI3_SECURITY1_KEY_RECORD_FLAGS_TYPE_ECDSA_PRIVATE (0x03)
+#define MPI3_SECURITY1_KEY_RECORD_FLAGS_TYPE_ECDSA_PUBLIC (0x04)
+#define MPI3_SECURITY1_KEY_RECORD_CONSUMER_NOT_VALID (0x00)
+#define MPI3_SECURITY1_KEY_RECORD_CONSUMER_SAFESTORE (0x01)
+#define MPI3_SECURITY1_KEY_RECORD_CONSUMER_CERT_CHAIN (0x02)
+#define MPI3_SECURITY1_KEY_RECORD_CONSUMER_AUTH_DEV_KEY (0x03)
+#define MPI3_SECURITY1_KEY_RECORD_CONSUMER_CACHE_OFFLOAD (0x04)
+struct mpi3_security_page1 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08[2];
+ union mpi3_security_mac mac;
+ union mpi3_security_nonce nonce;
+ u8 num_keys;
+ u8 reserved91[3];
+ __le32 reserved94[3];
+ struct mpi3_security1_key_record key_record[MPI3_SECURITY1_KEY_RECORD_MAX];
+ u8 pad[MPI3_SECURITY1_PAD_MAX];
+};
+
+#define MPI3_SECURITY1_PAGEVERSION (0x00)
+struct mpi3_sas_io_unit0_phy_data {
+ u8 io_unit_port;
+ u8 port_flags;
+ u8 phy_flags;
+ u8 negotiated_link_rate;
+ __le16 controller_phy_device_info;
+ __le16 reserved06;
+ __le16 attached_dev_handle;
+ __le16 controller_dev_handle;
+ __le32 discovery_status;
+ __le32 reserved10;
+};
+
+#ifndef MPI3_SAS_IO_UNIT0_PHY_MAX
+#define MPI3_SAS_IO_UNIT0_PHY_MAX (1)
+#endif
+struct mpi3_sas_io_unit_page0 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ u8 num_phys;
+ u8 reserved0d[3];
+ struct mpi3_sas_io_unit0_phy_data phy_data[MPI3_SAS_IO_UNIT0_PHY_MAX];
+};
+
+#define MPI3_SASIOUNIT0_PAGEVERSION (0x00)
+#define MPI3_SASIOUNIT0_PORTFLAGS_DISC_IN_PROGRESS (0x08)
+#define MPI3_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG (0x01)
+#define MPI3_SASIOUNIT0_PHYFLAGS_INIT_PERSIST_CONNECT (0x40)
+#define MPI3_SASIOUNIT0_PHYFLAGS_TARG_PERSIST_CONNECT (0x20)
+#define MPI3_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08)
+struct mpi3_sas_io_unit1_phy_data {
+ u8 io_unit_port;
+ u8 port_flags;
+ u8 phy_flags;
+ u8 max_min_link_rate;
+ __le16 controller_phy_device_info;
+ __le16 max_target_port_connect_time;
+ __le32 reserved08;
+};
+
+#ifndef MPI3_SAS_IO_UNIT1_PHY_MAX
+#define MPI3_SAS_IO_UNIT1_PHY_MAX (1)
+#endif
+struct mpi3_sas_io_unit_page1 {
+ struct mpi3_config_page_header header;
+ __le16 control_flags;
+ __le16 sas_narrow_max_queue_depth;
+ __le16 additional_control_flags;
+ __le16 sas_wide_max_queue_depth;
+ u8 num_phys;
+ u8 sata_max_q_depth;
+ __le16 reserved12;
+ struct mpi3_sas_io_unit1_phy_data phy_data[MPI3_SAS_IO_UNIT1_PHY_MAX];
+};
+
+#define MPI3_SASIOUNIT1_PAGEVERSION (0x00)
+#define MPI3_SASIOUNIT1_CONTROL_CONTROLLER_DEVICE_SELF_TEST (0x8000)
+#define MPI3_SASIOUNIT1_CONTROL_SATA_SW_PRESERVE (0x1000)
+#define MPI3_SASIOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080)
+#define MPI3_SASIOUNIT1_CONTROL_SATA_SMART_REQUIRED (0x0040)
+#define MPI3_SASIOUNIT1_CONTROL_SATA_NCQ_REQUIRED (0x0020)
+#define MPI3_SASIOUNIT1_CONTROL_SATA_FUA_REQUIRED (0x0010)
+#define MPI3_SASIOUNIT1_CONTROL_TABLE_SUBTRACTIVE_ILLEGAL (0x0008)
+#define MPI3_SASIOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL (0x0004)
+#define MPI3_SASIOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002)
+#define MPI3_SASIOUNIT1_CONTROL_HARD_RESET_MASK (0x0001)
+#define MPI3_SASIOUNIT1_CONTROL_HARD_RESET_DEVICE_NAME (0x0000)
+#define MPI3_SASIOUNIT1_CONTROL_HARD_RESET_SAS_ADDRESS (0x0001)
+#define MPI3_SASIOUNIT1_ACONTROL_DA_PERSIST_CONNECT (0x0100)
+#define MPI3_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080)
+#define MPI3_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040)
+#define MPI3_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION (0x0020)
+#define MPI3_SASIOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010)
+#define MPI3_SASIOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET (0x0008)
+#define MPI3_SASIOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET (0x0004)
+#define MPI3_SASIOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET (0x0002)
+#define MPI3_SASIOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001)
+#define MPI3_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01)
+#define MPI3_SASIOUNIT1_PHYFLAGS_INIT_PERSIST_CONNECT (0x40)
+#define MPI3_SASIOUNIT1_PHYFLAGS_TARG_PERSIST_CONNECT (0x20)
+#define MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08)
+#define MPI3_SASIOUNIT1_MMLR_MAX_RATE_MASK (0xf0)
+#define MPI3_SASIOUNIT1_MMLR_MAX_RATE_SHIFT (4)
+#define MPI3_SASIOUNIT1_MMLR_MAX_RATE_6_0 (0xa0)
+#define MPI3_SASIOUNIT1_MMLR_MAX_RATE_12_0 (0xb0)
+#define MPI3_SASIOUNIT1_MMLR_MAX_RATE_22_5 (0xc0)
+#define MPI3_SASIOUNIT1_MMLR_MIN_RATE_MASK (0x0f)
+#define MPI3_SASIOUNIT1_MMLR_MIN_RATE_6_0 (0x0a)
+#define MPI3_SASIOUNIT1_MMLR_MIN_RATE_12_0 (0x0b)
+#define MPI3_SASIOUNIT1_MMLR_MIN_RATE_22_5 (0x0c)
+struct mpi3_sas_io_unit2_phy_pm_settings {
+ u8 control_flags;
+ u8 reserved01;
+ __le16 inactivity_timer_exponent;
+ u8 sata_partial_timeout;
+ u8 reserved05;
+ u8 sata_slumber_timeout;
+ u8 reserved07;
+ u8 sas_partial_timeout;
+ u8 reserved09;
+ u8 sas_slumber_timeout;
+ u8 reserved0b;
+};
+
+#ifndef MPI3_SAS_IO_UNIT2_PHY_MAX
+#define MPI3_SAS_IO_UNIT2_PHY_MAX (1)
+#endif
+struct mpi3_sas_io_unit_page2 {
+ struct mpi3_config_page_header header;
+ u8 num_phys;
+ u8 reserved09[3];
+ __le32 reserved0c;
+ struct mpi3_sas_io_unit2_phy_pm_settings sas_phy_power_management_settings[MPI3_SAS_IO_UNIT2_PHY_MAX];
+};
+
+#define MPI3_SASIOUNIT2_PAGEVERSION (0x00)
+#define MPI3_SASIOUNIT2_CONTROL_SAS_SLUMBER_ENABLE (0x08)
+#define MPI3_SASIOUNIT2_CONTROL_SAS_PARTIAL_ENABLE (0x04)
+#define MPI3_SASIOUNIT2_CONTROL_SATA_SLUMBER_ENABLE (0x02)
+#define MPI3_SASIOUNIT2_CONTROL_SATA_PARTIAL_ENABLE (0x01)
+#define MPI3_SASIOUNIT2_ITE_SAS_SLUMBER_MASK (0x7000)
+#define MPI3_SASIOUNIT2_ITE_SAS_SLUMBER_SHIFT (12)
+#define MPI3_SASIOUNIT2_ITE_SAS_PARTIAL_MASK (0x0700)
+#define MPI3_SASIOUNIT2_ITE_SAS_PARTIAL_SHIFT (8)
+#define MPI3_SASIOUNIT2_ITE_SATA_SLUMBER_MASK (0x0070)
+#define MPI3_SASIOUNIT2_ITE_SATA_SLUMBER_SHIFT (4)
+#define MPI3_SASIOUNIT2_ITE_SATA_PARTIAL_MASK (0x0007)
+#define MPI3_SASIOUNIT2_ITE_SATA_PARTIAL_SHIFT (0)
+#define MPI3_SASIOUNIT2_ITE_EXP_TEN_SECONDS (7)
+#define MPI3_SASIOUNIT2_ITE_EXP_ONE_SECOND (6)
+#define MPI3_SASIOUNIT2_ITE_EXP_HUNDRED_MILLISECONDS (5)
+#define MPI3_SASIOUNIT2_ITE_EXP_TEN_MILLISECONDS (4)
+#define MPI3_SASIOUNIT2_ITE_EXP_ONE_MILLISECOND (3)
+#define MPI3_SASIOUNIT2_ITE_EXP_HUNDRED_MICROSECONDS (2)
+#define MPI3_SASIOUNIT2_ITE_EXP_TEN_MICROSECONDS (1)
+#define MPI3_SASIOUNIT2_ITE_EXP_ONE_MICROSECOND (0)
+struct mpi3_sas_io_unit_page3 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ __le32 power_management_capabilities;
+};
+
+#define MPI3_SASIOUNIT3_PAGEVERSION (0x00)
+#define MPI3_SASIOUNIT3_PM_HOST_SAS_SLUMBER_MODE (0x00000800)
+#define MPI3_SASIOUNIT3_PM_HOST_SAS_PARTIAL_MODE (0x00000400)
+#define MPI3_SASIOUNIT3_PM_HOST_SATA_SLUMBER_MODE (0x00000200)
+#define MPI3_SASIOUNIT3_PM_HOST_SATA_PARTIAL_MODE (0x00000100)
+#define MPI3_SASIOUNIT3_PM_IOUNIT_SAS_SLUMBER_MODE (0x00000008)
+#define MPI3_SASIOUNIT3_PM_IOUNIT_SAS_PARTIAL_MODE (0x00000004)
+#define MPI3_SASIOUNIT3_PM_IOUNIT_SATA_SLUMBER_MODE (0x00000002)
+#define MPI3_SASIOUNIT3_PM_IOUNIT_SATA_PARTIAL_MODE (0x00000001)
+struct mpi3_sas_expander_page0 {
+ struct mpi3_config_page_header header;
+ u8 io_unit_port;
+ u8 report_gen_length;
+ __le16 enclosure_handle;
+ __le32 reserved0c;
+ __le64 sas_address;
+ __le32 discovery_status;
+ __le16 dev_handle;
+ __le16 parent_dev_handle;
+ __le16 expander_change_count;
+ __le16 expander_route_indexes;
+ u8 num_phys;
+ u8 sas_level;
+ __le16 flags;
+ __le16 stp_bus_inactivity_time_limit;
+ __le16 stp_max_connect_time_limit;
+ __le16 stp_smp_nexus_loss_time;
+ __le16 max_num_routed_sas_addresses;
+ __le64 active_zone_manager_sas_address;
+ __le16 zone_lock_inactivity_limit;
+ __le16 reserved3a;
+ u8 time_to_reduced_func;
+ u8 initial_time_to_reduced_func;
+ u8 max_reduced_func_time;
+ u8 exp_status;
+};
+
+#define MPI3_SASEXPANDER0_PAGEVERSION (0x00)
+#define MPI3_SASEXPANDER0_FLAGS_REDUCED_FUNCTIONALITY (0x2000)
+#define MPI3_SASEXPANDER0_FLAGS_ZONE_LOCKED (0x1000)
+#define MPI3_SASEXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES (0x0800)
+#define MPI3_SASEXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES (0x0400)
+#define MPI3_SASEXPANDER0_FLAGS_ZONING_SUPPORT (0x0200)
+#define MPI3_SASEXPANDER0_FLAGS_ENABLED_ZONING (0x0100)
+#define MPI3_SASEXPANDER0_FLAGS_TABLE_TO_TABLE_SUPPORT (0x0080)
+#define MPI3_SASEXPANDER0_FLAGS_CONNECTOR_END_DEVICE (0x0010)
+#define MPI3_SASEXPANDER0_FLAGS_OTHERS_CONFIG (0x0004)
+#define MPI3_SASEXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x0002)
+#define MPI3_SASEXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x0001)
+#define MPI3_SASEXPANDER0_ES_NOT_RESPONDING (0x02)
+#define MPI3_SASEXPANDER0_ES_RESPONDING (0x03)
+#define MPI3_SASEXPANDER0_ES_DELAY_NOT_RESPONDING (0x04)
+struct mpi3_sas_expander_page1 {
+ struct mpi3_config_page_header header;
+ u8 io_unit_port;
+ u8 reserved09[3];
+ u8 num_phys;
+ u8 phy;
+ __le16 num_table_entries_programmed;
+ u8 programmed_link_rate;
+ u8 hw_link_rate;
+ __le16 attached_dev_handle;
+ __le32 phy_info;
+ __le16 attached_device_info;
+ __le16 reserved1a;
+ __le16 expander_dev_handle;
+ u8 change_count;
+ u8 negotiated_link_rate;
+ u8 phy_identifier;
+ u8 attached_phy_identifier;
+ u8 reserved22;
+ u8 discovery_info;
+ __le32 attached_phy_info;
+ u8 zone_group;
+ u8 self_config_status;
+ __le16 reserved2a;
+ __le16 slot;
+ __le16 slot_index;
+};
+
+#define MPI3_SASEXPANDER1_PAGEVERSION (0x00)
+#define MPI3_SASEXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04)
+#define MPI3_SASEXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02)
+#define MPI3_SASEXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01)
+struct mpi3_sas_port_page0 {
+ struct mpi3_config_page_header header;
+ u8 port_number;
+ u8 reserved09;
+ u8 port_width;
+ u8 reserved0b;
+ u8 zone_group;
+ u8 reserved0d[3];
+ __le64 sas_address;
+ __le16 device_info;
+ __le16 reserved1a;
+ __le32 reserved1c;
+};
+
+#define MPI3_SASPORT0_PAGEVERSION (0x00)
+struct mpi3_sas_phy_page0 {
+ struct mpi3_config_page_header header;
+ __le16 owner_dev_handle;
+ __le16 reserved0a;
+ __le16 attached_dev_handle;
+ u8 attached_phy_identifier;
+ u8 reserved0f;
+ __le32 attached_phy_info;
+ u8 programmed_link_rate;
+ u8 hw_link_rate;
+ u8 change_count;
+ u8 flags;
+ __le32 phy_info;
+ u8 negotiated_link_rate;
+ u8 reserved1d[3];
+ __le16 slot;
+ __le16 slot_index;
+};
+
+#define MPI3_SASPHY0_PAGEVERSION (0x00)
+#define MPI3_SASPHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01)
+struct mpi3_sas_phy_page1 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ __le32 invalid_dword_count;
+ __le32 running_disparity_error_count;
+ __le32 loss_dword_synch_count;
+ __le32 phy_reset_problem_count;
+};
+
+#define MPI3_SASPHY1_PAGEVERSION (0x00)
+struct mpi3_sas_phy2_phy_event {
+ u8 phy_event_code;
+ u8 reserved01[3];
+ __le32 phy_event_info;
+};
+
+#ifndef MPI3_SAS_PHY2_PHY_EVENT_MAX
+#define MPI3_SAS_PHY2_PHY_EVENT_MAX (1)
+#endif
+struct mpi3_sas_phy_page2 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ u8 num_phy_events;
+ u8 reserved0d[3];
+ struct mpi3_sas_phy2_phy_event phy_event[MPI3_SAS_PHY2_PHY_EVENT_MAX];
+};
+
+#define MPI3_SASPHY2_PAGEVERSION (0x00)
+struct mpi3_sas_phy3_phy_event_config {
+ u8 phy_event_code;
+ u8 reserved01[3];
+ u8 counter_type;
+ u8 threshold_window;
+ u8 time_units;
+ u8 reserved07;
+ __le32 event_threshold;
+ __le16 threshold_flags;
+ __le16 reserved0e;
+};
+
+#define MPI3_SASPHY3_EVENT_CODE_NO_EVENT (0x00)
+#define MPI3_SASPHY3_EVENT_CODE_INVALID_DWORD (0x01)
+#define MPI3_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR (0x02)
+#define MPI3_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC (0x03)
+#define MPI3_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM (0x04)
+#define MPI3_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW (0x05)
+#define MPI3_SASPHY3_EVENT_CODE_RX_ERROR (0x06)
+#define MPI3_SASPHY3_EVENT_CODE_INV_SPL_PACKETS (0x07)
+#define MPI3_SASPHY3_EVENT_CODE_LOSS_SPL_PACKET_SYNC (0x08)
+#define MPI3_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR (0x20)
+#define MPI3_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT (0x21)
+#define MPI3_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT (0x22)
+#define MPI3_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT (0x23)
+#define MPI3_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT (0x24)
+#define MPI3_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON (0x25)
+#define MPI3_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON (0x26)
+#define MPI3_SASPHY3_EVENT_CODE_TX_BREAK (0x27)
+#define MPI3_SASPHY3_EVENT_CODE_RX_BREAK (0x28)
+#define MPI3_SASPHY3_EVENT_CODE_BREAK_TIMEOUT (0x29)
+#define MPI3_SASPHY3_EVENT_CODE_CONNECTION (0x2a)
+#define MPI3_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED (0x2b)
+#define MPI3_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME (0x2c)
+#define MPI3_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME (0x2d)
+#define MPI3_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME (0x2e)
+#define MPI3_SASPHY3_EVENT_CODE_PERSIST_CONN (0x2f)
+#define MPI3_SASPHY3_EVENT_CODE_TX_SSP_FRAMES (0x40)
+#define MPI3_SASPHY3_EVENT_CODE_RX_SSP_FRAMES (0x41)
+#define MPI3_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES (0x42)
+#define MPI3_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES (0x43)
+#define MPI3_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED (0x44)
+#define MPI3_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED (0x45)
+#define MPI3_SASPHY3_EVENT_CODE_TX_SATA_FRAMES (0x50)
+#define MPI3_SASPHY3_EVENT_CODE_RX_SATA_FRAMES (0x51)
+#define MPI3_SASPHY3_EVENT_CODE_SATA_OVERFLOW (0x52)
+#define MPI3_SASPHY3_EVENT_CODE_TX_SMP_FRAMES (0x60)
+#define MPI3_SASPHY3_EVENT_CODE_RX_SMP_FRAMES (0x61)
+#define MPI3_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES (0x63)
+#define MPI3_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xd0)
+#define MPI3_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xd1)
+#define MPI3_SASPHY3_EVENT_CODE_RX_AIP (0xd2)
+#define MPI3_SASPHY3_EVENT_CODE_LCARB_WAIT_TIME (0xd3)
+#define MPI3_SASPHY3_EVENT_CODE_RCVD_CONN_RESP_WAIT_TIME (0xd4)
+#define MPI3_SASPHY3_EVENT_CODE_LCCONN_TIME (0xd5)
+#define MPI3_SASPHY3_EVENT_CODE_SSP_TX_START_TRANSMIT (0xd6)
+#define MPI3_SASPHY3_EVENT_CODE_SATA_TX_START (0xd7)
+#define MPI3_SASPHY3_EVENT_CODE_SMP_TX_START_TRANSMT (0xd8)
+#define MPI3_SASPHY3_EVENT_CODE_TX_SMP_BREAK_CONN (0xd9)
+#define MPI3_SASPHY3_EVENT_CODE_SSP_RX_START_RECEIVE (0xda)
+#define MPI3_SASPHY3_EVENT_CODE_SATA_RX_START_RECEIVE (0xdb)
+#define MPI3_SASPHY3_EVENT_CODE_SMP_RX_START_RECEIVE (0xdc)
+#define MPI3_SASPHY3_COUNTER_TYPE_WRAPPING (0x00)
+#define MPI3_SASPHY3_COUNTER_TYPE_SATURATING (0x01)
+#define MPI3_SASPHY3_COUNTER_TYPE_PEAK_VALUE (0x02)
+#define MPI3_SASPHY3_TIME_UNITS_10_MICROSECONDS (0x00)
+#define MPI3_SASPHY3_TIME_UNITS_100_MICROSECONDS (0x01)
+#define MPI3_SASPHY3_TIME_UNITS_1_MILLISECOND (0x02)
+#define MPI3_SASPHY3_TIME_UNITS_10_MILLISECONDS (0x03)
+#define MPI3_SASPHY3_TFLAGS_PHY_RESET (0x0002)
+#define MPI3_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001)
+#ifndef MPI3_SAS_PHY3_PHY_EVENT_MAX
+#define MPI3_SAS_PHY3_PHY_EVENT_MAX (1)
+#endif
+struct mpi3_sas_phy_page3 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ u8 num_phy_events;
+ u8 reserved0d[3];
+ struct mpi3_sas_phy3_phy_event_config phy_event_config[MPI3_SAS_PHY3_PHY_EVENT_MAX];
+};
+
+#define MPI3_SASPHY3_PAGEVERSION (0x00)
+struct mpi3_sas_phy_page4 {
+ struct mpi3_config_page_header header;
+ u8 reserved08[3];
+ u8 flags;
+ u8 initial_frame[28];
+};
+
+#define MPI3_SASPHY4_PAGEVERSION (0x00)
+#define MPI3_SASPHY4_FLAGS_FRAME_VALID (0x02)
+#define MPI3_SASPHY4_FLAGS_SATA_FRAME (0x01)
+#define MPI3_PCIE_LINK_RETIMERS_MASK (0x30)
+#define MPI3_PCIE_LINK_RETIMERS_SHIFT (4)
+#define MPI3_PCIE_NEG_LINK_RATE_MASK (0x0f)
+#define MPI3_PCIE_NEG_LINK_RATE_UNKNOWN (0x00)
+#define MPI3_PCIE_NEG_LINK_RATE_PHY_DISABLED (0x01)
+#define MPI3_PCIE_NEG_LINK_RATE_2_5 (0x02)
+#define MPI3_PCIE_NEG_LINK_RATE_5_0 (0x03)
+#define MPI3_PCIE_NEG_LINK_RATE_8_0 (0x04)
+#define MPI3_PCIE_NEG_LINK_RATE_16_0 (0x05)
+#define MPI3_PCIE_NEG_LINK_RATE_32_0 (0x06)
+struct mpi3_pcie_io_unit0_phy_data {
+ u8 link;
+ u8 link_flags;
+ u8 phy_flags;
+ u8 negotiated_link_rate;
+ __le16 attached_dev_handle;
+ __le16 controller_dev_handle;
+ __le32 enumeration_status;
+ u8 io_unit_port;
+ u8 reserved0d[3];
+};
+
+#define MPI3_PCIEIOUNIT0_LINKFLAGS_CONFIG_SOURCE_MASK (0x10)
+#define MPI3_PCIEIOUNIT0_LINKFLAGS_CONFIG_SOURCE_IOUNIT1 (0x00)
+#define MPI3_PCIEIOUNIT0_LINKFLAGS_CONFIG_SOURCE_BKPLANE (0x10)
+#define MPI3_PCIEIOUNIT0_LINKFLAGS_ENUM_IN_PROGRESS (0x08)
+#define MPI3_PCIEIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08)
+#define MPI3_PCIEIOUNIT0_PHYFLAGS_HOST_PHY (0x01)
+#define MPI3_PCIEIOUNIT0_ES_MAX_SWITCH_DEPTH_EXCEEDED (0x80000000)
+#define MPI3_PCIEIOUNIT0_ES_MAX_SWITCHES_EXCEEDED (0x40000000)
+#define MPI3_PCIEIOUNIT0_ES_MAX_ENDPOINTS_EXCEEDED (0x20000000)
+#define MPI3_PCIEIOUNIT0_ES_INSUFFICIENT_RESOURCES (0x10000000)
+#ifndef MPI3_PCIE_IO_UNIT0_PHY_MAX
+#define MPI3_PCIE_IO_UNIT0_PHY_MAX (1)
+#endif
+struct mpi3_pcie_io_unit_page0 {
+ struct mpi3_config_page_header header;
+ __le32 reserved08;
+ u8 num_phys;
+ u8 init_status;
+ __le16 reserved0e;
+ struct mpi3_pcie_io_unit0_phy_data phy_data[MPI3_PCIE_IO_UNIT0_PHY_MAX];
+};
+
+#define MPI3_PCIEIOUNIT0_PAGEVERSION (0x00)
+#define MPI3_PCIEIOUNIT0_INITSTATUS_NO_ERRORS (0x00)
+#define MPI3_PCIEIOUNIT0_INITSTATUS_NEEDS_INITIALIZATION (0x01)
+#define MPI3_PCIEIOUNIT0_INITSTATUS_NO_TARGETS_ALLOCATED (0x02)
+#define MPI3_PCIEIOUNIT0_INITSTATUS_RESOURCE_ALLOC_FAILED (0x03)
+#define MPI3_PCIEIOUNIT0_INITSTATUS_BAD_NUM_PHYS (0x04)
+#define MPI3_PCIEIOUNIT0_INITSTATUS_UNSUPPORTED_CONFIG (0x05)
+#define MPI3_PCIEIOUNIT0_INITSTATUS_HOST_PORT_MISMATCH (0x06)
+#define MPI3_PCIEIOUNIT0_INITSTATUS_PHYS_NOT_CONSECUTIVE (0x07)
+#define MPI3_PCIEIOUNIT0_INITSTATUS_BAD_CLOCKING_MODE (0x08)
+#define MPI3_PCIEIOUNIT0_INITSTATUS_PROD_SPEC_START (0xf0)
+#define MPI3_PCIEIOUNIT0_INITSTATUS_PROD_SPEC_END (0xff)
+struct mpi3_pcie_io_unit1_phy_data {
+ u8 link;
+ u8 link_flags;
+ u8 phy_flags;
+ u8 max_min_link_rate;
+ __le32 reserved04;
+ __le32 reserved08;
+};
+
+#define MPI3_PCIEIOUNIT1_LINKFLAGS_PCIE_CLK_MODE_MASK (0x03)
+#define MPI3_PCIEIOUNIT1_LINKFLAGS_PCIE_CLK_MODE_DIS_SEPARATE_REFCLK (0x00)
+#define MPI3_PCIEIOUNIT1_LINKFLAGS_PCIE_CLK_MODE_EN_SRIS (0x01)
+#define MPI3_PCIEIOUNIT1_LINKFLAGS_PCIE_CLK_MODE_EN_SRNS (0x02)
+#define MPI3_PCIEIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08)
+#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_MASK (0xf0)
+#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_SHIFT (4)
+#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_2_5 (0x20)
+#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_5_0 (0x30)
+#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_8_0 (0x40)
+#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_16_0 (0x50)
+#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_32_0 (0x60)
+#ifndef MPI3_PCIE_IO_UNIT1_PHY_MAX
+#define MPI3_PCIE_IO_UNIT1_PHY_MAX (1)
+#endif
+struct mpi3_pcie_io_unit_page1 {
+ struct mpi3_config_page_header header;
+ __le32 control_flags;
+ __le32 reserved0c;
+ u8 num_phys;
+ u8 reserved11;
+ __le16 reserved12;
+ struct mpi3_pcie_io_unit1_phy_data phy_data[MPI3_PCIE_IO_UNIT1_PHY_MAX];
+};
+
+#define MPI3_PCIEIOUNIT1_PAGEVERSION (0x00)
+struct mpi3_pcie_io_unit_page2 {
+ struct mpi3_config_page_header header;
+ __le16 nv_me_max_queue_depth;
+ __le16 reserved0a;
+ u8 nv_me_abort_to;
+ u8 reserved0d;
+ __le16 reserved0e;
+};
+
+#define MPI3_PCIEIOUNIT2_PAGEVERSION (0x00)
+struct mpi3_pcie_switch_page0 {
+ struct mpi3_config_page_header header;
+ u8 io_unit_port;
+ u8 switch_status;
+ u8 reserved0a[2];
+ __le16 dev_handle;
+ __le16 parent_dev_handle;
+ u8 num_ports;
+ u8 pc_ie_level;
+ __le16 reserved12;
+ __le32 reserved14;
+ __le32 reserved18;
+ __le32 reserved1c;
+};
+
+#define MPI3_PCIESWITCH0_PAGEVERSION (0x00)
+#define MPI3_PCIESWITCH0_SS_NOT_RESPONDING (0x02)
+#define MPI3_PCIESWITCH0_SS_RESPONDING (0x03)
+#define MPI3_PCIESWITCH0_SS_DELAY_NOT_RESPONDING (0x04)
+struct mpi3_pcie_switch_page1 {
+ struct mpi3_config_page_header header;
+ u8 io_unit_port;
+ u8 reserved09[3];
+ u8 num_ports;
+ u8 port_num;
+ __le16 attached_dev_handle;
+ __le16 switch_dev_handle;
+ u8 negotiated_port_width;
+ u8 negotiated_link_rate;
+ __le16 slot;
+ __le16 slot_index;
+ __le32 reserved18;
+};
+
+#define MPI3_PCIESWITCH1_PAGEVERSION (0x00)
+struct mpi3_pcie_link_page0 {
+ struct mpi3_config_page_header header;
+ u8 link;
+ u8 reserved09[3];
+ __le32 correctable_error_count;
+ __le16 n_fatal_error_count;
+ __le16 reserved12;
+ __le16 fatal_error_count;
+ __le16 reserved16;
+};
+
+#define MPI3_PCIELINK0_PAGEVERSION (0x00)
+struct mpi3_enclosure_page0 {
+ struct mpi3_config_page_header header;
+ __le64 enclosure_logical_id;
+ __le16 flags;
+ __le16 enclosure_handle;
+ __le16 num_slots;
+ __le16 start_slot;
+ u8 io_unit_port;
+ u8 enclosure_level;
+ __le16 sep_dev_handle;
+ __le32 reserved1c;
+};
+
+#define MPI3_ENCLOSURE0_PAGEVERSION (0x00)
+#define MPI3_ENCLS0_FLAGS_ENCL_TYPE_MASK (0xc000)
+#define MPI3_ENCLS0_FLAGS_ENCL_TYPE_VIRTUAL (0x0000)
+#define MPI3_ENCLS0_FLAGS_ENCL_TYPE_SAS (0x4000)
+#define MPI3_ENCLS0_FLAGS_ENCL_TYPE_PCIE (0x8000)
+#define MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK (0x0010)
+#define MPI3_ENCLS0_FLAGS_ENCL_DEV_NOT_FOUND (0x0000)
+#define MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT (0x0010)
+#define MPI3_ENCLS0_FLAGS_MNG_MASK (0x000f)
+#define MPI3_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000)
+#define MPI3_ENCLS0_FLAGS_MNG_IOC_SES (0x0001)
+#define MPI3_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0002)
+#define MPI3_DEVICE_DEVFORM_SAS_SATA (0x00)
+#define MPI3_DEVICE_DEVFORM_PCIE (0x01)
+#define MPI3_DEVICE_DEVFORM_VD (0x02)
+struct mpi3_device0_sas_sata_format {
+ __le64 sas_address;
+ __le16 flags;
+ __le16 device_info;
+ u8 phy_num;
+ u8 attached_phy_identifier;
+ u8 max_port_connections;
+ u8 zone_group;
+};
+
+#define MPI3_DEVICE0_SASSATA_FLAGS_SLUMBER_CAP (0x0200)
+#define MPI3_DEVICE0_SASSATA_FLAGS_PARTIAL_CAP (0x0100)
+#define MPI3_DEVICE0_SASSATA_FLAGS_ASYNC_NOTIFY (0x0080)
+#define MPI3_DEVICE0_SASSATA_FLAGS_SW_PRESERVE (0x0040)
+#define MPI3_DEVICE0_SASSATA_FLAGS_UNSUPP_DEV (0x0020)
+#define MPI3_DEVICE0_SASSATA_FLAGS_48BIT_LBA (0x0010)
+#define MPI3_DEVICE0_SASSATA_FLAGS_SMART_SUPP (0x0008)
+#define MPI3_DEVICE0_SASSATA_FLAGS_NCQ_SUPP (0x0004)
+#define MPI3_DEVICE0_SASSATA_FLAGS_FUA_SUPP (0x0002)
+#define MPI3_DEVICE0_SASSATA_FLAGS_PERSIST_CAP (0x0001)
+struct mpi3_device0_pcie_format {
+ u8 supported_link_rates;
+ u8 max_port_width;
+ u8 negotiated_port_width;
+ u8 negotiated_link_rate;
+ u8 port_num;
+ u8 controller_reset_to;
+ __le16 device_info;
+ __le32 maximum_data_transfer_size;
+ __le32 capabilities;
+ __le16 noiob;
+ u8 nv_me_abort_to;
+ u8 page_size;
+ __le16 shutdown_latency;
+ __le16 reserved16;
+};
+
+#define MPI3_DEVICE0_PCIE_LINK_RATE_32_0_SUPP (0x10)
+#define MPI3_DEVICE0_PCIE_LINK_RATE_16_0_SUPP (0x08)
+#define MPI3_DEVICE0_PCIE_LINK_RATE_8_0_SUPP (0x04)
+#define MPI3_DEVICE0_PCIE_LINK_RATE_5_0_SUPP (0x02)
+#define MPI3_DEVICE0_PCIE_LINK_RATE_2_5_SUPP (0x01)
+#define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK (0x0003)
+#define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NO_DEVICE (0x0000)
+#define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE (0x0001)
+#define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SWITCH_DEVICE (0x0002)
+#define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SCSI_DEVICE (0x0003)
+#define MPI3_DEVICE0_PCIE_CAP_METADATA_SEPARATED (0x00000010)
+#define MPI3_DEVICE0_PCIE_CAP_SGL_DWORD_ALIGN_REQUIRED (0x00000008)
+#define MPI3_DEVICE0_PCIE_CAP_NVME_SGL_ENABLED (0x00000004)
+#define MPI3_DEVICE0_PCIE_CAP_BIT_BUCKET_SGL_SUPP (0x00000002)
+#define MPI3_DEVICE0_PCIE_CAP_SGL_SUPP (0x00000001)
+struct mpi3_device0_vd_format {
+ u8 vd_state;
+ u8 raid_level;
+ __le16 device_info;
+ __le16 flags;
+ __le16 reserved06;
+ __le32 reserved08[2];
+};
+
+#define MPI3_DEVICE0_VD_STATE_OFFLINE (0x00)
+#define MPI3_DEVICE0_VD_STATE_PARTIALLY_DEGRADED (0x01)
+#define MPI3_DEVICE0_VD_STATE_DEGRADED (0x02)
+#define MPI3_DEVICE0_VD_STATE_OPTIMAL (0x03)
+#define MPI3_DEVICE0_VD_RAIDLEVEL_RAID_0 (0)
+#define MPI3_DEVICE0_VD_RAIDLEVEL_RAID_1 (1)
+#define MPI3_DEVICE0_VD_RAIDLEVEL_RAID_5 (5)
+#define MPI3_DEVICE0_VD_RAIDLEVEL_RAID_6 (6)
+#define MPI3_DEVICE0_VD_RAIDLEVEL_RAID_10 (10)
+#define MPI3_DEVICE0_VD_RAIDLEVEL_RAID_50 (50)
+#define MPI3_DEVICE0_VD_RAIDLEVEL_RAID_60 (60)
+#define MPI3_DEVICE0_VD_DEVICE_INFO_HDD (0x0010)
+#define MPI3_DEVICE0_VD_DEVICE_INFO_SSD (0x0008)
+#define MPI3_DEVICE0_VD_DEVICE_INFO_NVME (0x0004)
+#define MPI3_DEVICE0_VD_DEVICE_INFO_SATA (0x0002)
+#define MPI3_DEVICE0_VD_DEVICE_INFO_SAS (0x0001)
+#define MPI3_DEVICE0_VD_FLAGS_METADATA_MODE_MASK (0x0003)
+#define MPI3_DEVICE0_VD_FLAGS_METADATA_MODE_NONE (0x0000)
+#define MPI3_DEVICE0_VD_FLAGS_METADATA_MODE_HOST (0x0001)
+#define MPI3_DEVICE0_VD_FLAGS_METADATA_MODE_IOC (0x0002)
+union mpi3_device0_dev_spec_format {
+ struct mpi3_device0_sas_sata_format sas_sata_format;
+ struct mpi3_device0_pcie_format pcie_format;
+ struct mpi3_device0_vd_format vd_format;
+};
+
+struct mpi3_device_page0 {
+ struct mpi3_config_page_header header;
+ __le16 dev_handle;
+ __le16 parent_dev_handle;
+ __le16 slot;
+ __le16 enclosure_handle;
+ __le64 wwid;
+ __le16 persistent_id;
+ u8 io_unit_port;
+ u8 access_status;
+ __le16 flags;
+ __le16 reserved1e;
+ __le16 slot_index;
+ __le16 queue_depth;
+ u8 reserved24[3];
+ u8 device_form;
+ union mpi3_device0_dev_spec_format device_specific;
+};
+
+#define MPI3_DEVICE0_PAGEVERSION (0x00)
+#define MPI3_DEVICE0_WWID_INVALID (0xffffffffffffffff)
+#define MPI3_DEVICE0_PERSISTENTID_INVALID (0xffff)
+#define MPI3_DEVICE0_IOUNITPORT_INVALID (0xff)
+#define MPI3_DEVICE0_ASTATUS_NO_ERRORS (0x00)
+#define MPI3_DEVICE0_ASTATUS_NEEDS_INITIALIZATION (0x01)
+#define MPI3_DEVICE0_ASTATUS_CAP_UNSUPPORTED (0x02)
+#define MPI3_DEVICE0_ASTATUS_DEVICE_BLOCKED (0x03)
+#define MPI3_DEVICE0_ASTATUS_UNAUTHORIZED (0x04)
+#define MPI3_DEVICE0_ASTATUS_DEVICE_MISSING_DELAY (0x05)
+#define MPI3_DEVICE0_ASTATUS_SAS_UNKNOWN (0x10)
+#define MPI3_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE (0x11)
+#define MPI3_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE (0x12)
+#define MPI3_DEVICE0_ASTATUS_SIF_UNKNOWN (0x20)
+#define MPI3_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x21)
+#define MPI3_DEVICE0_ASTATUS_SIF_DIAG (0x22)
+#define MPI3_DEVICE0_ASTATUS_SIF_IDENTIFICATION (0x23)
+#define MPI3_DEVICE0_ASTATUS_SIF_CHECK_POWER (0x24)
+#define MPI3_DEVICE0_ASTATUS_SIF_PIO_SN (0x25)
+#define MPI3_DEVICE0_ASTATUS_SIF_MDMA_SN (0x26)
+#define MPI3_DEVICE0_ASTATUS_SIF_UDMA_SN (0x27)
+#define MPI3_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION (0x28)
+#define MPI3_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE (0x29)
+#define MPI3_DEVICE0_ASTATUS_SIF_MAX (0x2f)
+#define MPI3_DEVICE0_ASTATUS_PCIE_UNKNOWN (0x30)
+#define MPI3_DEVICE0_ASTATUS_PCIE_MEM_SPACE_ACCESS (0x31)
+#define MPI3_DEVICE0_ASTATUS_PCIE_UNSUPPORTED (0x32)
+#define MPI3_DEVICE0_ASTATUS_PCIE_MSIX_REQUIRED (0x33)
+#define MPI3_DEVICE0_ASTATUS_NVME_UNKNOWN (0x40)
+#define MPI3_DEVICE0_ASTATUS_NVME_READY_TIMEOUT (0x41)
+#define MPI3_DEVICE0_ASTATUS_NVME_DEVCFG_UNSUPPORTED (0x42)
+#define MPI3_DEVICE0_ASTATUS_NVME_IDENTIFY_FAILED (0x43)
+#define MPI3_DEVICE0_ASTATUS_NVME_QCONFIG_FAILED (0x44)
+#define MPI3_DEVICE0_ASTATUS_NVME_QCREATION_FAILED (0x45)
+#define MPI3_DEVICE0_ASTATUS_NVME_EVENTCFG_FAILED (0x46)
+#define MPI3_DEVICE0_ASTATUS_NVME_GET_FEATURE_STAT_FAILED (0x47)
+#define MPI3_DEVICE0_ASTATUS_NVME_IDLE_TIMEOUT (0x48)
+#define MPI3_DEVICE0_ASTATUS_NVME_CTRL_FAILURE_STATUS (0x49)
+#define MPI3_DEVICE0_ASTATUS_VD_UNKNOWN (0x50)
+#define MPI3_DEVICE0_FLAGS_CONTROLLER_DEV_HANDLE (0x0080)
+#define MPI3_DEVICE0_FLAGS_HIDDEN (0x0008)
+#define MPI3_DEVICE0_FLAGS_ATT_METHOD_MASK (0x0006)
+#define MPI3_DEVICE0_FLAGS_ATT_METHOD_NOT_DIR_ATTACHED (0x0000)
+#define MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED (0x0002)
+#define MPI3_DEVICE0_FLAGS_ATT_METHOD_VIRTUAL (0x0004)
+#define MPI3_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001)
+#define MPI3_DEVICE0_QUEUE_DEPTH_NOT_APPLICABLE (0x0000)
+struct mpi3_device1_sas_sata_format {
+ __le32 reserved00;
+};
+
+struct mpi3_device1_pcie_format {
+ __le16 vendor_id;
+ __le16 device_id;
+ __le16 subsystem_vendor_id;
+ __le16 subsystem_id;
+ __le32 reserved08;
+ u8 revision_id;
+ u8 reserved0d;
+ __le16 pci_parameters;
+};
+
+#define MPI3_DEVICE1_PCIE_PARAMS_DATA_SIZE_128B (0x0)
+#define MPI3_DEVICE1_PCIE_PARAMS_DATA_SIZE_256B (0x1)
+#define MPI3_DEVICE1_PCIE_PARAMS_DATA_SIZE_512B (0x2)
+#define MPI3_DEVICE1_PCIE_PARAMS_DATA_SIZE_1024B (0x3)
+#define MPI3_DEVICE1_PCIE_PARAMS_DATA_SIZE_2048B (0x4)
+#define MPI3_DEVICE1_PCIE_PARAMS_DATA_SIZE_4096B (0x5)
+#define MPI3_DEVICE1_PCIE_PARAMS_MAX_READ_REQ_MASK (0x01c0)
+#define MPI3_DEVICE1_PCIE_PARAMS_MAX_READ_REQ_SHIFT (6)
+#define MPI3_DEVICE1_PCIE_PARAMS_CURR_MAX_PAYLOAD_MASK (0x0038)
+#define MPI3_DEVICE1_PCIE_PARAMS_CURR_MAX_PAYLOAD_SHIFT (3)
+#define MPI3_DEVICE1_PCIE_PARAMS_SUPP_MAX_PAYLOAD_MASK (0x0007)
+#define MPI3_DEVICE1_PCIE_PARAMS_SUPP_MAX_PAYLOAD_SHIFT (0)
+struct mpi3_device1_vd_format {
+ __le32 reserved00;
+};
+
+union mpi3_device1_dev_spec_format {
+ struct mpi3_device1_sas_sata_format sas_sata_format;
+ struct mpi3_device1_pcie_format pcie_format;
+ struct mpi3_device1_vd_format vd_format;
+};
+
+struct mpi3_device_page1 {
+ struct mpi3_config_page_header header;
+ __le16 dev_handle;
+ __le16 reserved0a;
+ __le32 reserved0c[12];
+ u8 reserved3c[3];
+ u8 device_form;
+ union mpi3_device1_dev_spec_format device_specific;
+};
+
+#define MPI3_DEVICE1_PAGEVERSION (0x00)
+#endif
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_image.h b/drivers/scsi/mpi3mr/mpi/mpi30_image.h
new file mode 100644
index 000000000000..169e4f9b7b7c
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_image.h
@@ -0,0 +1,216 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2018-2021 Broadcom Inc. All rights reserved.
+ *
+ */
+#ifndef MPI30_IMAGE_H
+#define MPI30_IMAGE_H 1
+struct mpi3_comp_image_version {
+ __le16 build_num;
+ __le16 customer_id;
+ u8 phase_minor;
+ u8 phase_major;
+ u8 gen_minor;
+ u8 gen_major;
+};
+
+struct mpi3_hash_exclusion_format {
+ __le32 offset;
+ __le32 size;
+};
+
+#define MPI3_IMAGE_HASH_EXCUSION_NUM (4)
+struct mpi3_component_image_header {
+ __le32 signature0;
+ __le32 load_address;
+ __le32 data_size;
+ __le32 start_offset;
+ __le32 signature1;
+ __le32 flash_offset;
+ __le32 image_size;
+ __le32 version_string_offset;
+ __le32 build_date_string_offset;
+ __le32 build_time_string_offset;
+ __le32 environment_variable_offset;
+ __le32 application_specific;
+ __le32 signature2;
+ __le32 header_size;
+ __le32 crc;
+ __le32 flags;
+ __le32 secondary_flash_offset;
+ __le32 etp_offset;
+ __le32 etp_size;
+ union mpi3_version_union rmc_interface_version;
+ union mpi3_version_union etp_interface_version;
+ struct mpi3_comp_image_version component_image_version;
+ struct mpi3_hash_exclusion_format hash_exclusion[MPI3_IMAGE_HASH_EXCUSION_NUM];
+ __le32 next_image_header_offset;
+ union mpi3_version_union security_version;
+ __le32 reserved84[31];
+};
+
+#define MPI3_IMAGE_HEADER_SIGNATURE0_MPI3 (0xeb00003e)
+#define MPI3_IMAGE_HEADER_LOAD_ADDRESS_INVALID (0x00000000)
+#define MPI3_IMAGE_HEADER_SIGNATURE1_APPLICATION (0x20505041)
+#define MPI3_IMAGE_HEADER_SIGNATURE1_FIRST_MUTABLE (0x20434d46)
+#define MPI3_IMAGE_HEADER_SIGNATURE1_BSP (0x20505342)
+#define MPI3_IMAGE_HEADER_SIGNATURE1_ROM_BIOS (0x534f4942)
+#define MPI3_IMAGE_HEADER_SIGNATURE1_HII_X64 (0x4d494948)
+#define MPI3_IMAGE_HEADER_SIGNATURE1_HII_ARM (0x41494948)
+#define MPI3_IMAGE_HEADER_SIGNATURE1_CPLD (0x444c5043)
+#define MPI3_IMAGE_HEADER_SIGNATURE1_SPD (0x20445053)
+#define MPI3_IMAGE_HEADER_SIGNATURE1_GAS_GAUGE (0x20534147)
+#define MPI3_IMAGE_HEADER_SIGNATURE1_PBLP (0x504c4250)
+#define MPI3_IMAGE_HEADER_SIGNATURE2_VALUE (0x50584546)
+#define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_MASK (0x00000030)
+#define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_CDI (0x00000000)
+#define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_DI (0x00000010)
+#define MPI3_IMAGE_HEADER_FLAGS_SIGNED_NVDATA (0x00000008)
+#define MPI3_IMAGE_HEADER_FLAGS_REQUIRES_ACTIVATION (0x00000004)
+#define MPI3_IMAGE_HEADER_FLAGS_COMPRESSED (0x00000002)
+#define MPI3_IMAGE_HEADER_FLAGS_FLASH (0x00000001)
+#define MPI3_IMAGE_HEADER_SIGNATURE0_OFFSET (0x00)
+#define MPI3_IMAGE_HEADER_LOAD_ADDRESS_OFFSET (0x04)
+#define MPI3_IMAGE_HEADER_DATA_SIZE_OFFSET (0x08)
+#define MPI3_IMAGE_HEADER_START_OFFSET_OFFSET (0x0c)
+#define MPI3_IMAGE_HEADER_SIGNATURE1_OFFSET (0x10)
+#define MPI3_IMAGE_HEADER_FLASH_OFFSET_OFFSET (0x14)
+#define MPI3_IMAGE_HEADER_FLASH_SIZE_OFFSET (0x18)
+#define MPI3_IMAGE_HEADER_VERSION_STRING_OFFSET_OFFSET (0x1c)
+#define MPI3_IMAGE_HEADER_BUILD_DATE_STRING_OFFSET_OFFSET (0x20)
+#define MPI3_IMAGE_HEADER_BUILD_TIME_OFFSET_OFFSET (0x24)
+#define MPI3_IMAGE_HEADER_ENVIROMENT_VAR_OFFSET_OFFSET (0x28)
+#define MPI3_IMAGE_HEADER_APPLICATION_SPECIFIC_OFFSET (0x2c)
+#define MPI3_IMAGE_HEADER_SIGNATURE2_OFFSET (0x30)
+#define MPI3_IMAGE_HEADER_HEADER_SIZE_OFFSET (0x34)
+#define MPI3_IMAGE_HEADER_CRC_OFFSET (0x38)
+#define MPI3_IMAGE_HEADER_FLAGS_OFFSET (0x3c)
+#define MPI3_IMAGE_HEADER_SECONDARY_FLASH_OFFSET_OFFSET (0x40)
+#define MPI3_IMAGE_HEADER_ETP_OFFSET_OFFSET (0x44)
+#define MPI3_IMAGE_HEADER_ETP_SIZE_OFFSET (0x48)
+#define MPI3_IMAGE_HEADER_RMC_INTERFACE_VER_OFFSET (0x4c)
+#define MPI3_IMAGE_HEADER_ETP_INTERFACE_VER_OFFSET (0x50)
+#define MPI3_IMAGE_HEADER_COMPONENT_IMAGE_VER_OFFSET (0x54)
+#define MPI3_IMAGE_HEADER_HASH_EXCLUSION_OFFSET (0x5c)
+#define MPI3_IMAGE_HEADER_NEXT_IMAGE_HEADER_OFFSET_OFFSET (0x7c)
+#define MPI3_IMAGE_HEADER_SIZE (0x100)
+struct mpi3_extended_image_header {
+ u8 image_type;
+ u8 reserved01[3];
+ __le32 checksum;
+ __le32 image_size;
+ __le32 next_image_header_offset;
+ __le32 reserved10[4];
+ __le32 identify_string[8];
+};
+
+#define MPI3_EXT_IMAGE_IMAGETYPE_OFFSET (0x00)
+#define MPI3_EXT_IMAGE_IMAGESIZE_OFFSET (0x08)
+#define MPI3_EXT_IMAGE_NEXTIMAGE_OFFSET (0x0c)
+#define MPI3_EXT_IMAGE_HEADER_SIZE (0x40)
+#define MPI3_EXT_IMAGE_TYPE_UNSPECIFIED (0x00)
+#define MPI3_EXT_IMAGE_TYPE_NVDATA (0x03)
+#define MPI3_EXT_IMAGE_TYPE_SUPPORTED_DEVICES (0x07)
+#define MPI3_EXT_IMAGE_TYPE_ENCRYPTED_HASH (0x09)
+#define MPI3_EXT_IMAGE_TYPE_RDE (0x0a)
+#define MPI3_EXT_IMAGE_TYPE_AUXILIARY_PROCESSOR (0x0b)
+#define MPI3_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC (0x80)
+#define MPI3_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC (0xff)
+struct mpi3_supported_device {
+ __le16 device_id;
+ __le16 vendor_id;
+ __le16 device_id_mask;
+ __le16 reserved06;
+ u8 low_pci_rev;
+ u8 high_pci_rev;
+ __le16 reserved0a;
+ __le32 reserved0c;
+};
+
+#ifndef MPI3_SUPPORTED_DEVICE_MAX
+#define MPI3_SUPPORTED_DEVICE_MAX (1)
+#endif
+struct mpi3_supported_devices_data {
+ u8 image_version;
+ u8 reserved01;
+ u8 num_devices;
+ u8 reserved03;
+ __le32 reserved04;
+ struct mpi3_supported_device supported_device[MPI3_SUPPORTED_DEVICE_MAX];
+};
+
+#ifndef MPI3_ENCRYPTED_HASH_MAX
+#define MPI3_ENCRYPTED_HASH_MAX (1)
+#endif
+struct mpi3_encrypted_hash_entry {
+ u8 hash_image_type;
+ u8 hash_algorithm;
+ u8 encryption_algorithm;
+ u8 reserved03;
+ __le32 reserved04;
+ __le32 encrypted_hash[MPI3_ENCRYPTED_HASH_MAX];
+};
+
+#define MPI3_HASH_IMAGE_TYPE_KEY_WITH_SIGNATURE (0x03)
+#define MPI3_HASH_ALGORITHM_VERSION_MASK (0xe0)
+#define MPI3_HASH_ALGORITHM_VERSION_NONE (0x00)
+#define MPI3_HASH_ALGORITHM_VERSION_SHA1 (0x20)
+#define MPI3_HASH_ALGORITHM_VERSION_SHA2 (0x40)
+#define MPI3_HASH_ALGORITHM_VERSION_SHA3 (0x60)
+#define MPI3_HASH_ALGORITHM_SIZE_MASK (0x1f)
+#define MPI3_HASH_ALGORITHM_SIZE_UNUSED (0x00)
+#define MPI3_HASH_ALGORITHM_SIZE_SHA256 (0x01)
+#define MPI3_HASH_ALGORITHM_SIZE_SHA512 (0x02)
+#define MPI3_ENCRYPTION_ALGORITHM_UNUSED (0x00)
+#define MPI3_ENCRYPTION_ALGORITHM_RSA256 (0x01)
+#define MPI3_ENCRYPTION_ALGORITHM_RSA512 (0x02)
+#define MPI3_ENCRYPTION_ALGORITHM_RSA1024 (0x03)
+#define MPI3_ENCRYPTION_ALGORITHM_RSA2048 (0x04)
+#define MPI3_ENCRYPTION_ALGORITHM_RSA4096 (0x05)
+#define MPI3_ENCRYPTION_ALGORITHM_RSA3072 (0x06)
+#ifndef MPI3_PUBLIC_KEY_MAX
+#define MPI3_PUBLIC_KEY_MAX (1)
+#endif
+struct mpi3_encrypted_key_with_hash_entry {
+ u8 hash_image_type;
+ u8 hash_algorithm;
+ u8 encryption_algorithm;
+ u8 reserved03;
+ __le32 reserved04;
+ __le32 public_key[MPI3_PUBLIC_KEY_MAX];
+ __le32 encrypted_hash[MPI3_ENCRYPTED_HASH_MAX];
+};
+
+#ifndef MPI3_ENCRYPTED_HASH_ENTRY_MAX
+#define MPI3_ENCRYPTED_HASH_ENTRY_MAX (1)
+#endif
+struct mpi3_encrypted_hash_data {
+ u8 image_version;
+ u8 num_hash;
+ __le16 reserved02;
+ __le32 reserved04;
+ struct mpi3_encrypted_hash_entry encrypted_hash_entry[MPI3_ENCRYPTED_HASH_ENTRY_MAX];
+};
+
+#ifndef MPI3_AUX_PROC_DATA_MAX
+#define MPI3_AUX_PROC_DATA_MAX (1)
+#endif
+struct mpi3_aux_processor_data {
+ u8 boot_method;
+ u8 num_load_addr;
+ u8 reserved02;
+ u8 type;
+ __le32 version;
+ __le32 load_address[8];
+ __le32 reserved28[22];
+ __le32 aux_processor_data[MPI3_AUX_PROC_DATA_MAX];
+};
+
+#define MPI3_AUX_PROC_DATA_OFFSET (0x80)
+#define MPI3_AUXPROCESSOR_BOOT_METHOD_MO_MSG (0x00)
+#define MPI3_AUXPROCESSOR_BOOT_METHOD_MO_DOORBELL (0x01)
+#define MPI3_AUXPROCESSOR_BOOT_METHOD_COMPONENT (0x02)
+#define MPI3_AUXPROCESSOR_TYPE_ARM_A15 (0x00)
+#define MPI3_AUXPROCESSOR_TYPE_ARM_M0 (0x01)
+#define MPI3_AUXPROCESSOR_TYPE_ARM_R4 (0x02)
+#endif
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_init.h b/drivers/scsi/mpi3mr/mpi/mpi30_init.h
new file mode 100644
index 000000000000..e02b6d3cfba2
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_init.h
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2016-2021 Broadcom Inc. All rights reserved.
+ *
+ */
+#ifndef MPI30_INIT_H
+#define MPI30_INIT_H 1
+struct mpi3_scsi_io_cdb_eedp32 {
+ u8 cdb[20];
+ __be32 primary_reference_tag;
+ __le16 primary_application_tag;
+ __le16 primary_application_tag_mask;
+ __le32 transfer_length;
+};
+
+union mpi3_scso_io_cdb_union {
+ u8 cdb32[32];
+ struct mpi3_scsi_io_cdb_eedp32 eedp32;
+ struct mpi3_sge_common sge;
+};
+
+struct mpi3_scsi_io_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 dev_handle;
+ __le32 flags;
+ __le32 skip_count;
+ __le32 data_length;
+ u8 lun[8];
+ union mpi3_scso_io_cdb_union cdb;
+ union mpi3_sge_union sgl[4];
+};
+
+#define MPI3_SCSIIO_MSGFLAGS_METASGL_VALID (0x80)
+#define MPI3_SCSIIO_FLAGS_LARGE_CDB (0x60000000)
+#define MPI3_SCSIIO_FLAGS_CDB_16_OR_LESS (0x00000000)
+#define MPI3_SCSIIO_FLAGS_CDB_GREATER_THAN_16 (0x20000000)
+#define MPI3_SCSIIO_FLAGS_CDB_IN_SEPARATE_BUFFER (0x40000000)
+#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_MASK (0x07000000)
+#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SIMPLEQ (0x00000000)
+#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_HEADOFQ (0x01000000)
+#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ORDEREDQ (0x02000000)
+#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ACAQ (0x04000000)
+#define MPI3_SCSIIO_FLAGS_CMDPRI_MASK (0x00f00000)
+#define MPI3_SCSIIO_FLAGS_CMDPRI_SHIFT (20)
+#define MPI3_SCSIIO_FLAGS_DATADIRECTION_MASK (0x000c0000)
+#define MPI3_SCSIIO_FLAGS_DATADIRECTION_NO_DATA_TRANSFER (0x00000000)
+#define MPI3_SCSIIO_FLAGS_DATADIRECTION_WRITE (0x00040000)
+#define MPI3_SCSIIO_FLAGS_DATADIRECTION_READ (0x00080000)
+#define MPI3_SCSIIO_FLAGS_DMAOPERATION_MASK (0x00030000)
+#define MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI (0x00010000)
+#define MPI3_SCSIIO_METASGL_INDEX (3)
+struct mpi3_scsi_io_reply {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 ioc_use_only08;
+ __le16 ioc_status;
+ __le32 ioc_log_info;
+ u8 scsi_status;
+ u8 scsi_state;
+ __le16 dev_handle;
+ __le32 transfer_count;
+ __le32 sense_count;
+ __le32 response_data;
+ __le16 task_tag;
+ __le16 scsi_status_qualifier;
+ __le32 eedp_error_offset;
+ __le16 eedp_observed_app_tag;
+ __le16 eedp_observed_guard;
+ __le32 eedp_observed_ref_tag;
+ __le64 sense_data_buffer_address;
+};
+
+#define MPI3_SCSIIO_REPLY_MSGFLAGS_REFTAG_OBSERVED_VALID (0x01)
+#define MPI3_SCSIIO_REPLY_MSGFLAGS_APPTAG_OBSERVED_VALID (0x02)
+#define MPI3_SCSIIO_REPLY_MSGFLAGS_GUARD_OBSERVED_VALID (0x04)
+#define MPI3_SCSI_STATUS_GOOD (0x00)
+#define MPI3_SCSI_STATUS_CHECK_CONDITION (0x02)
+#define MPI3_SCSI_STATUS_CONDITION_MET (0x04)
+#define MPI3_SCSI_STATUS_BUSY (0x08)
+#define MPI3_SCSI_STATUS_INTERMEDIATE (0x10)
+#define MPI3_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14)
+#define MPI3_SCSI_STATUS_RESERVATION_CONFLICT (0x18)
+#define MPI3_SCSI_STATUS_COMMAND_TERMINATED (0x22)
+#define MPI3_SCSI_STATUS_TASK_SET_FULL (0x28)
+#define MPI3_SCSI_STATUS_ACA_ACTIVE (0x30)
+#define MPI3_SCSI_STATUS_TASK_ABORTED (0x40)
+#define MPI3_SCSI_STATE_SENSE_MASK (0x03)
+#define MPI3_SCSI_STATE_SENSE_VALID (0x00)
+#define MPI3_SCSI_STATE_SENSE_FAILED (0x01)
+#define MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY (0x02)
+#define MPI3_SCSI_STATE_SENSE_NOT_AVAILABLE (0x03)
+#define MPI3_SCSI_STATE_NO_SCSI_STATUS (0x04)
+#define MPI3_SCSI_STATE_TERMINATED (0x08)
+#define MPI3_SCSI_STATE_RESPONSE_DATA_VALID (0x10)
+#define MPI3_SCSI_RSP_RESPONSECODE_MASK (0x000000ff)
+#define MPI3_SCSI_RSP_RESPONSECODE_SHIFT (0)
+#define MPI3_SCSI_RSP_ARI2_MASK (0x0000ff00)
+#define MPI3_SCSI_RSP_ARI2_SHIFT (8)
+#define MPI3_SCSI_RSP_ARI1_MASK (0x00ff0000)
+#define MPI3_SCSI_RSP_ARI1_SHIFT (16)
+#define MPI3_SCSI_RSP_ARI0_MASK (0xff000000)
+#define MPI3_SCSI_RSP_ARI0_SHIFT (24)
+#define MPI3_SCSI_TASKTAG_UNKNOWN (0xffff)
+struct mpi3_scsi_task_mgmt_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 dev_handle;
+ __le16 task_host_tag;
+ u8 task_type;
+ u8 reserved0f;
+ __le16 task_request_queue_id;
+ __le16 reserved12;
+ __le32 reserved14;
+ u8 lun[8];
+};
+
+#define MPI3_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x08)
+#define MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01)
+#define MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK_SET (0x02)
+#define MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03)
+#define MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05)
+#define MPI3_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06)
+#define MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07)
+#define MPI3_SCSITASKMGMT_TASKTYPE_CLEAR_ACA (0x08)
+#define MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK_SET (0x09)
+#define MPI3_SCSITASKMGMT_TASKTYPE_QUERY_ASYNC_EVENT (0x0a)
+#define MPI3_SCSITASKMGMT_TASKTYPE_I_T_NEXUS_RESET (0x0b)
+struct mpi3_scsi_task_mgmt_reply {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 ioc_use_only08;
+ __le16 ioc_status;
+ __le32 ioc_log_info;
+ __le32 termination_count;
+ __le32 response_data;
+ __le32 reserved18;
+};
+
+#define MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC (0x80)
+#endif
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h
new file mode 100644
index 000000000000..1af99a5382d5
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h
@@ -0,0 +1,1004 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2016-2021 Broadcom Inc. All rights reserved.
+ *
+ */
+#ifndef MPI30_IOC_H
+#define MPI30_IOC_H 1
+struct mpi3_ioc_init_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 reserved0a;
+ union mpi3_version_union mpi_version;
+ __le64 time_stamp;
+ u8 reserved18;
+ u8 who_init;
+ __le16 reserved1a;
+ __le16 reply_free_queue_depth;
+ __le16 reserved1e;
+ __le64 reply_free_queue_address;
+ __le32 reserved28;
+ __le16 sense_buffer_free_queue_depth;
+ __le16 sense_buffer_length;
+ __le64 sense_buffer_free_queue_address;
+ __le64 driver_information_address;
+};
+
+#define MPI3_WHOINIT_NOT_INITIALIZED (0x00)
+#define MPI3_WHOINIT_ROM_BIOS (0x02)
+#define MPI3_WHOINIT_HOST_DRIVER (0x03)
+#define MPI3_WHOINIT_MANUFACTURER (0x04)
+struct mpi3_driver_info_layout {
+ __le32 information_length;
+ u8 driver_signature[12];
+ u8 os_name[16];
+ u8 os_version[12];
+ u8 driver_name[20];
+ u8 driver_version[32];
+ u8 driver_release_date[20];
+ __le32 driver_capabilities;
+};
+
+struct mpi3_ioc_facts_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 reserved0a;
+ __le32 reserved0c;
+ union mpi3_sge_union sgl;
+};
+
+struct mpi3_ioc_facts_data {
+ __le16 ioc_facts_data_length;
+ __le16 reserved02;
+ union mpi3_version_union mpi_version;
+ struct mpi3_comp_image_version fw_version;
+ __le32 ioc_capabilities;
+ u8 ioc_number;
+ u8 who_init;
+ __le16 max_msix_vectors;
+ __le16 max_outstanding_request;
+ __le16 product_id;
+ __le16 ioc_request_frame_size;
+ __le16 reply_frame_size;
+ __le16 ioc_exceptions;
+ __le16 max_persistent_id;
+ u8 sge_modifier_mask;
+ u8 sge_modifier_value;
+ u8 sge_modifier_shift;
+ u8 protocol_flags;
+ __le16 max_sas_initiators;
+ __le16 max_sas_targets;
+ __le16 max_sas_expanders;
+ __le16 max_enclosures;
+ __le16 min_dev_handle;
+ __le16 max_dev_handle;
+ __le16 max_pc_ie_switches;
+ __le16 max_nvme;
+ __le16 max_pds;
+ __le16 max_vds;
+ __le16 max_host_pds;
+ __le16 max_advanced_host_pds;
+ __le16 max_raid_pds;
+ __le16 max_posted_cmd_buffers;
+ __le32 flags;
+ __le16 max_operational_request_queues;
+ __le16 max_operational_reply_queues;
+ __le16 shutdown_timeout;
+ __le16 reserved4e;
+ __le32 diag_trace_size;
+ __le32 diag_fw_size;
+};
+
+#define MPI3_IOCFACTS_CAPABILITY_ADVANCED_HOST_PD (0x00000010)
+#define MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE (0x00000008)
+#define MPI3_IOCFACTS_CAPABILITY_COALESCE_CTRL_GRAN_MASK (0x00000001)
+#define MPI3_IOCFACTS_CAPABILITY_COALESCE_CTRL_IOC_GRAN (0x00000000)
+#define MPI3_IOCFACTS_CAPABILITY_COALESCE_CTRL_REPLY_Q_GRAN (0x00000001)
+#define MPI3_IOCFACTS_PID_TYPE_MASK (0xf000)
+#define MPI3_IOCFACTS_PID_TYPE_SHIFT (12)
+#define MPI3_IOCFACTS_PID_PRODUCT_MASK (0x0f00)
+#define MPI3_IOCFACTS_PID_PRODUCT_SHIFT (8)
+#define MPI3_IOCFACTS_PID_FAMILY_MASK (0x00ff)
+#define MPI3_IOCFACTS_PID_FAMILY_SHIFT (0)
+#define MPI3_IOCFACTS_EXCEPT_SAFE_MODE (0x0800)
+#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_MASK (0x0700)
+#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_NONE (0x0000)
+#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_LOCAL_VIA_RAID (0x0100)
+#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_LOCAL_VIA_OOB (0x0200)
+#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_EXT_VIA_RAID (0x0300)
+#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_EXT_VIA_OOB (0x0400)
+#define MPI3_IOCFACTS_EXCEPT_PCIE_DISABLED (0x0080)
+#define MPI3_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE (0x0040)
+#define MPI3_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (0x0020)
+#define MPI3_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0010)
+#define MPI3_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0008)
+#define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x0001)
+#define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_PRIMARY (0x0000)
+#define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_SECONDARY (0x0001)
+#define MPI3_IOCFACTS_PROTOCOL_SAS (0x0010)
+#define MPI3_IOCFACTS_PROTOCOL_SATA (0x0008)
+#define MPI3_IOCFACTS_PROTOCOL_NVME (0x0004)
+#define MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002)
+#define MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001)
+#define MPI3_IOCFACTS_FLAGS_SIGNED_NVDATA_REQUIRED (0x00010000)
+#define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK (0x0000ff00)
+#define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT (8)
+#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK (0x00000030)
+#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_NOT_STARTED (0x00000000)
+#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_IN_PROGRESS (0x00000010)
+#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_COMPLETE (0x00000020)
+#define MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK (0x0000000f)
+#define MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA (0x00000000)
+#define MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR (0x00000002)
+struct mpi3_mgmt_passthrough_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 reserved0a;
+ __le32 reserved0c[5];
+ union mpi3_sge_union command_sgl;
+ union mpi3_sge_union response_sgl;
+};
+
+struct mpi3_create_request_queue_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ u8 flags;
+ u8 burst;
+ __le16 size;
+ __le16 queue_id;
+ __le16 reply_queue_id;
+ __le16 reserved12;
+ __le32 reserved14;
+ __le64 base_address;
+};
+
+#define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_MASK (0x80)
+#define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED (0x80)
+#define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_CONTIGUOUS (0x00)
+struct mpi3_delete_request_queue_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 queue_id;
+};
+
+struct mpi3_create_reply_queue_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ u8 flags;
+ u8 reserved0b;
+ __le16 size;
+ __le16 queue_id;
+ __le16 msix_index;
+ __le16 reserved12;
+ __le32 reserved14;
+ __le64 base_address;
+};
+
+#define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_MASK (0x80)
+#define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_SEGMENTED (0x80)
+#define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_CONTIGUOUS (0x00)
+#define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_MASK (0x01)
+#define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_DISABLE (0x00)
+#define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE (0x01)
+struct mpi3_delete_reply_queue_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 queue_id;
+};
+
+struct mpi3_port_enable_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 reserved0a;
+};
+
+#define MPI3_EVENT_LOG_DATA (0x01)
+#define MPI3_EVENT_CHANGE (0x02)
+#define MPI3_EVENT_GPIO_INTERRUPT (0x04)
+#define MPI3_EVENT_TEMP_THRESHOLD (0x05)
+#define MPI3_EVENT_CABLE_MGMT (0x06)
+#define MPI3_EVENT_DEVICE_ADDED (0x07)
+#define MPI3_EVENT_DEVICE_INFO_CHANGED (0x08)
+#define MPI3_EVENT_PREPARE_FOR_RESET (0x09)
+#define MPI3_EVENT_COMP_IMAGE_ACT_START (0x0a)
+#define MPI3_EVENT_ENCL_DEVICE_ADDED (0x0b)
+#define MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE (0x0c)
+#define MPI3_EVENT_DEVICE_STATUS_CHANGE (0x0d)
+#define MPI3_EVENT_ENERGY_PACK_CHANGE (0x0e)
+#define MPI3_EVENT_SAS_DISCOVERY (0x11)
+#define MPI3_EVENT_SAS_BROADCAST_PRIMITIVE (0x12)
+#define MPI3_EVENT_SAS_NOTIFY_PRIMITIVE (0x13)
+#define MPI3_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x14)
+#define MPI3_EVENT_SAS_INIT_TABLE_OVERFLOW (0x15)
+#define MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST (0x16)
+#define MPI3_EVENT_SAS_PHY_COUNTER (0x18)
+#define MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR (0x19)
+#define MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST (0x20)
+#define MPI3_EVENT_PCIE_ENUMERATION (0x22)
+#define MPI3_EVENT_HARD_RESET_RECEIVED (0x40)
+#define MPI3_EVENT_MIN_PRODUCT_SPECIFIC (0x60)
+#define MPI3_EVENT_MAX_PRODUCT_SPECIFIC (0x7f)
+#define MPI3_EVENT_NOTIFY_EVENTMASK_WORDS (4)
+struct mpi3_event_notification_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 reserved0a;
+ __le16 sas_broadcast_primitive_masks;
+ __le16 sas_notify_primitive_masks;
+ __le32 event_masks[MPI3_EVENT_NOTIFY_EVENTMASK_WORDS];
+};
+
+struct mpi3_event_notification_reply {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 ioc_use_only08;
+ __le16 ioc_status;
+ __le32 ioc_log_info;
+ u8 event_data_length;
+ u8 event;
+ __le16 ioc_change_count;
+ __le32 event_context;
+ __le32 event_data[1];
+};
+
+#define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK (0x01)
+#define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED (0x01)
+#define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_NOT_REQUIRED (0x00)
+#define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_MASK (0x02)
+#define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_ORIGINAL (0x00)
+#define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_REPLAY (0x02)
+struct mpi3_event_data_gpio_interrupt {
+ u8 gpio_num;
+ u8 reserved01[3];
+};
+
+struct mpi3_event_data_temp_threshold {
+ __le16 status;
+ u8 sensor_num;
+ u8 reserved03;
+ __le16 current_temperature;
+ __le16 reserved06;
+ __le32 reserved08;
+ __le32 reserved0c;
+};
+
+#define MPI3_EVENT_TEMP_THRESHOLD_STATUS_THRESHOLD3_EXCEEDED (0x0008)
+#define MPI3_EVENT_TEMP_THRESHOLD_STATUS_THRESHOLD2_EXCEEDED (0x0004)
+#define MPI3_EVENT_TEMP_THRESHOLD_STATUS_THRESHOLD1_EXCEEDED (0x0002)
+#define MPI3_EVENT_TEMP_THRESHOLD_STATUS_THRESHOLD0_EXCEEDED (0x0001)
+struct mpi3_event_data_cable_management {
+ __le32 active_cable_power_requirement;
+ u8 status;
+ u8 receptacle_id;
+ __le16 reserved06;
+};
+
+#define MPI3_EVENT_CABLE_MGMT_ACT_CABLE_PWR_INVALID (0xffffffff)
+#define MPI3_EVENT_CABLE_MGMT_STATUS_INSUFFICIENT_POWER (0x00)
+#define MPI3_EVENT_CABLE_MGMT_STATUS_PRESENT (0x01)
+#define MPI3_EVENT_CABLE_MGMT_STATUS_DEGRADED (0x02)
+struct mpi3_event_ack_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 reserved0a;
+ u8 event;
+ u8 reserved0d[3];
+ __le32 event_context;
+};
+
+struct mpi3_event_data_prepare_for_reset {
+ u8 reason_code;
+ u8 reserved01;
+ __le16 reserved02;
+};
+
+#define MPI3_EVENT_PREPARE_RESET_RC_START (0x01)
+#define MPI3_EVENT_PREPARE_RESET_RC_ABORT (0x02)
+struct mpi3_event_data_comp_image_activation {
+ __le32 reserved00;
+};
+
+struct mpi3_event_data_device_status_change {
+ __le16 task_tag;
+ u8 reason_code;
+ u8 io_unit_port;
+ __le16 parent_dev_handle;
+ __le16 dev_handle;
+ __le64 wwid;
+ u8 lun[8];
+};
+
+#define MPI3_EVENT_DEV_STAT_RC_MOVED (0x01)
+#define MPI3_EVENT_DEV_STAT_RC_HIDDEN (0x02)
+#define MPI3_EVENT_DEV_STAT_RC_NOT_HIDDEN (0x03)
+#define MPI3_EVENT_DEV_STAT_RC_ASYNC_NOTIFICATION (0x04)
+#define MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_STRT (0x20)
+#define MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_CMP (0x21)
+#define MPI3_EVENT_DEV_STAT_RC_INT_TASK_ABORT_STRT (0x22)
+#define MPI3_EVENT_DEV_STAT_RC_INT_TASK_ABORT_CMP (0x23)
+#define MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_STRT (0x24)
+#define MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_CMP (0x25)
+#define MPI3_EVENT_DEV_STAT_RC_PCIE_HOT_RESET_FAILED (0x30)
+#define MPI3_EVENT_DEV_STAT_RC_EXPANDER_REDUCED_FUNC_STRT (0x40)
+#define MPI3_EVENT_DEV_STAT_RC_EXPANDER_REDUCED_FUNC_CMP (0x41)
+#define MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING (0x50)
+struct mpi3_event_data_energy_pack_change {
+ __le32 reserved00;
+ __le16 shutdown_timeout;
+ __le16 reserved06;
+};
+
+struct mpi3_event_data_sas_discovery {
+ u8 flags;
+ u8 reason_code;
+ u8 io_unit_port;
+ u8 reserved03;
+ __le32 discovery_status;
+};
+
+#define MPI3_EVENT_SAS_DISC_FLAGS_DEVICE_CHANGE (0x02)
+#define MPI3_EVENT_SAS_DISC_FLAGS_IN_PROGRESS (0x01)
+#define MPI3_EVENT_SAS_DISC_RC_STARTED (0x01)
+#define MPI3_EVENT_SAS_DISC_RC_COMPLETED (0x02)
+#define MPI3_SAS_DISC_STATUS_MAX_ENCLOSURES_EXCEED (0x80000000)
+#define MPI3_SAS_DISC_STATUS_MAX_EXPANDERS_EXCEED (0x40000000)
+#define MPI3_SAS_DISC_STATUS_MAX_DEVICES_EXCEED (0x20000000)
+#define MPI3_SAS_DISC_STATUS_MAX_TOPO_PHYS_EXCEED (0x10000000)
+#define MPI3_SAS_DISC_STATUS_MULTIPLE_DEVICES_IN_SLOT (0x00004000)
+#define MPI3_SAS_DISC_STATUS_SLOT_COUNT_MISMATCH (0x00002000)
+#define MPI3_SAS_DISC_STATUS_TOO_MANY_SLOTS (0x00001000)
+#define MPI3_SAS_DISC_STATUS_EXP_MULTI_SUBTRACTIVE (0x00000800)
+#define MPI3_SAS_DISC_STATUS_MULTI_PORT_DOMAIN (0x00000400)
+#define MPI3_SAS_DISC_STATUS_TABLE_TO_SUBTRACTIVE_LINK (0x00000200)
+#define MPI3_SAS_DISC_STATUS_UNSUPPORTED_DEVICE (0x00000100)
+#define MPI3_SAS_DISC_STATUS_TABLE_LINK (0x00000080)
+#define MPI3_SAS_DISC_STATUS_SUBTRACTIVE_LINK (0x00000040)
+#define MPI3_SAS_DISC_STATUS_SMP_CRC_ERROR (0x00000020)
+#define MPI3_SAS_DISC_STATUS_SMP_FUNCTION_FAILED (0x00000010)
+#define MPI3_SAS_DISC_STATUS_SMP_TIMEOUT (0x00000008)
+#define MPI3_SAS_DISC_STATUS_MULTIPLE_PORTS (0x00000004)
+#define MPI3_SAS_DISC_STATUS_INVALID_SAS_ADDRESS (0x00000002)
+#define MPI3_SAS_DISC_STATUS_LOOP_DETECTED (0x00000001)
+struct mpi3_event_data_sas_broadcast_primitive {
+ u8 phy_num;
+ u8 io_unit_port;
+ u8 port_width;
+ u8 primitive;
+};
+
+#define MPI3_EVENT_BROADCAST_PRIMITIVE_CHANGE (0x01)
+#define MPI3_EVENT_BROADCAST_PRIMITIVE_SES (0x02)
+#define MPI3_EVENT_BROADCAST_PRIMITIVE_EXPANDER (0x03)
+#define MPI3_EVENT_BROADCAST_PRIMITIVE_ASYNCHRONOUS_EVENT (0x04)
+#define MPI3_EVENT_BROADCAST_PRIMITIVE_RESERVED3 (0x05)
+#define MPI3_EVENT_BROADCAST_PRIMITIVE_RESERVED4 (0x06)
+#define MPI3_EVENT_BROADCAST_PRIMITIVE_CHANGE0_RESERVED (0x07)
+#define MPI3_EVENT_BROADCAST_PRIMITIVE_CHANGE1_RESERVED (0x08)
+struct mpi3_event_data_sas_notify_primitive {
+ u8 phy_num;
+ u8 io_unit_port;
+ u8 reserved02;
+ u8 primitive;
+};
+
+#define MPI3_EVENT_NOTIFY_PRIMITIVE_ENABLE_SPINUP (0x01)
+#define MPI3_EVENT_NOTIFY_PRIMITIVE_POWER_LOSS_EXPECTED (0x02)
+#define MPI3_EVENT_NOTIFY_PRIMITIVE_RESERVED1 (0x03)
+#define MPI3_EVENT_NOTIFY_PRIMITIVE_RESERVED2 (0x04)
+#ifndef MPI3_EVENT_SAS_TOPO_PHY_COUNT
+#define MPI3_EVENT_SAS_TOPO_PHY_COUNT (1)
+#endif
+struct mpi3_event_sas_topo_phy_entry {
+ __le16 attached_dev_handle;
+ u8 link_rate;
+ u8 status;
+};
+
+#define MPI3_EVENT_SAS_TOPO_LR_CURRENT_MASK (0xf0)
+#define MPI3_EVENT_SAS_TOPO_LR_CURRENT_SHIFT (4)
+#define MPI3_EVENT_SAS_TOPO_LR_PREV_MASK (0x0f)
+#define MPI3_EVENT_SAS_TOPO_LR_PREV_SHIFT (0)
+#define MPI3_EVENT_SAS_TOPO_LR_UNKNOWN_LINK_RATE (0x00)
+#define MPI3_EVENT_SAS_TOPO_LR_PHY_DISABLED (0x01)
+#define MPI3_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED (0x02)
+#define MPI3_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03)
+#define MPI3_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04)
+#define MPI3_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05)
+#define MPI3_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY (0x06)
+#define MPI3_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0a)
+#define MPI3_EVENT_SAS_TOPO_LR_RATE_12_0 (0x0b)
+#define MPI3_EVENT_SAS_TOPO_LR_RATE_22_5 (0x0c)
+#define MPI3_EVENT_SAS_TOPO_PHY_STATUS_MASK (0xc0)
+#define MPI3_EVENT_SAS_TOPO_PHY_STATUS_SHIFT (6)
+#define MPI3_EVENT_SAS_TOPO_PHY_STATUS_ACCESSIBLE (0x00)
+#define MPI3_EVENT_SAS_TOPO_PHY_STATUS_NO_EXIST (0x40)
+#define MPI3_EVENT_SAS_TOPO_PHY_STATUS_VACANT (0x80)
+#define MPI3_EVENT_SAS_TOPO_PHY_RC_MASK (0x0f)
+#define MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING (0x02)
+#define MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED (0x03)
+#define MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE (0x04)
+#define MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING (0x05)
+#define MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING (0x06)
+struct mpi3_event_data_sas_topology_change_list {
+ __le16 enclosure_handle;
+ __le16 expander_dev_handle;
+ u8 num_phys;
+ u8 reserved05[3];
+ u8 num_entries;
+ u8 start_phy_num;
+ u8 exp_status;
+ u8 io_unit_port;
+ struct mpi3_event_sas_topo_phy_entry phy_entry[MPI3_EVENT_SAS_TOPO_PHY_COUNT];
+};
+
+#define MPI3_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00)
+#define MPI3_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02)
+#define MPI3_EVENT_SAS_TOPO_ES_RESPONDING (0x03)
+#define MPI3_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING (0x04)
+struct mpi3_event_data_sas_phy_counter {
+ __le64 time_stamp;
+ __le32 reserved08;
+ u8 phy_event_code;
+ u8 phy_num;
+ __le16 reserved0e;
+ __le32 phy_event_info;
+ u8 counter_type;
+ u8 threshold_window;
+ u8 time_units;
+ u8 reserved17;
+ __le32 event_threshold;
+ __le16 threshold_flags;
+ __le16 reserved1e;
+};
+
+struct mpi3_event_data_sas_device_disc_err {
+ __le16 dev_handle;
+ u8 reason_code;
+ u8 io_unit_port;
+ __le32 reserved04;
+ __le64 sas_address;
+};
+
+#define MPI3_EVENT_SAS_DISC_ERR_RC_SMP_FAILED (0x01)
+#define MPI3_EVENT_SAS_DISC_ERR_RC_SMP_TIMEOUT (0x02)
+struct mpi3_event_data_pcie_enumeration {
+ u8 flags;
+ u8 reason_code;
+ u8 io_unit_port;
+ u8 reserved03;
+ __le32 enumeration_status;
+};
+
+#define MPI3_EVENT_PCIE_ENUM_FLAGS_DEVICE_CHANGE (0x02)
+#define MPI3_EVENT_PCIE_ENUM_FLAGS_IN_PROGRESS (0x01)
+#define MPI3_EVENT_PCIE_ENUM_RC_STARTED (0x01)
+#define MPI3_EVENT_PCIE_ENUM_RC_COMPLETED (0x02)
+#define MPI3_EVENT_PCIE_ENUM_ES_MAX_SWITCH_DEPTH_EXCEED (0x80000000)
+#define MPI3_EVENT_PCIE_ENUM_ES_MAX_SWITCHES_EXCEED (0x40000000)
+#define MPI3_EVENT_PCIE_ENUM_ES_MAX_DEVICES_EXCEED (0x20000000)
+#define MPI3_EVENT_PCIE_ENUM_ES_RESOURCES_EXHAUSTED (0x10000000)
+#ifndef MPI3_EVENT_PCIE_TOPO_PORT_COUNT
+#define MPI3_EVENT_PCIE_TOPO_PORT_COUNT (1)
+#endif
+struct mpi3_event_pcie_topo_port_entry {
+ __le16 attached_dev_handle;
+ u8 port_status;
+ u8 reserved03;
+ u8 current_port_info;
+ u8 reserved05;
+ u8 previous_port_info;
+ u8 reserved07;
+};
+
+#define MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING (0x02)
+#define MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED (0x03)
+#define MPI3_EVENT_PCIE_TOPO_PS_NO_CHANGE (0x04)
+#define MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING (0x05)
+#define MPI3_EVENT_PCIE_TOPO_PS_RESPONDING (0x06)
+#define MPI3_EVENT_PCIE_TOPO_PI_LANES_MASK (0xf0)
+#define MPI3_EVENT_PCIE_TOPO_PI_LANES_UNKNOWN (0x00)
+#define MPI3_EVENT_PCIE_TOPO_PI_LANES_1 (0x10)
+#define MPI3_EVENT_PCIE_TOPO_PI_LANES_2 (0x20)
+#define MPI3_EVENT_PCIE_TOPO_PI_LANES_4 (0x30)
+#define MPI3_EVENT_PCIE_TOPO_PI_LANES_8 (0x40)
+#define MPI3_EVENT_PCIE_TOPO_PI_LANES_16 (0x50)
+#define MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK (0x0f)
+#define MPI3_EVENT_PCIE_TOPO_PI_RATE_UNKNOWN (0x00)
+#define MPI3_EVENT_PCIE_TOPO_PI_RATE_DISABLED (0x01)
+#define MPI3_EVENT_PCIE_TOPO_PI_RATE_2_5 (0x02)
+#define MPI3_EVENT_PCIE_TOPO_PI_RATE_5_0 (0x03)
+#define MPI3_EVENT_PCIE_TOPO_PI_RATE_8_0 (0x04)
+#define MPI3_EVENT_PCIE_TOPO_PI_RATE_16_0 (0x05)
+#define MPI3_EVENT_PCIE_TOPO_PI_RATE_32_0 (0x06)
+struct mpi3_event_data_pcie_topology_change_list {
+ __le16 enclosure_handle;
+ __le16 switch_dev_handle;
+ u8 num_ports;
+ u8 reserved05[3];
+ u8 num_entries;
+ u8 start_port_num;
+ u8 switch_status;
+ u8 io_unit_port;
+ __le32 reserved0c;
+ struct mpi3_event_pcie_topo_port_entry port_entry[MPI3_EVENT_PCIE_TOPO_PORT_COUNT];
+};
+
+#define MPI3_EVENT_PCIE_TOPO_SS_NO_PCIE_SWITCH (0x00)
+#define MPI3_EVENT_PCIE_TOPO_SS_NOT_RESPONDING (0x02)
+#define MPI3_EVENT_PCIE_TOPO_SS_RESPONDING (0x03)
+#define MPI3_EVENT_PCIE_TOPO_SS_DELAY_NOT_RESPONDING (0x04)
+struct mpi3_event_data_sas_init_dev_status_change {
+ u8 reason_code;
+ u8 io_unit_port;
+ __le16 dev_handle;
+ __le32 reserved04;
+ __le64 sas_address;
+};
+
+#define MPI3_EVENT_SAS_INIT_RC_ADDED (0x01)
+#define MPI3_EVENT_SAS_INIT_RC_NOT_RESPONDING (0x02)
+struct mpi3_event_data_sas_init_table_overflow {
+ __le16 max_init;
+ __le16 current_init;
+ __le32 reserved04;
+ __le64 sas_address;
+};
+
+struct mpi3_event_data_hard_reset_received {
+ u8 reserved00;
+ u8 io_unit_port;
+ __le16 reserved02;
+};
+
+#define MPI3_PEL_LOCALE_FLAGS_NON_BLOCKING_BOOT_EVENT (0x0200)
+#define MPI3_PEL_LOCALE_FLAGS_BLOCKING_BOOT_EVENT (0x0100)
+#define MPI3_PEL_LOCALE_FLAGS_PCIE (0x0080)
+#define MPI3_PEL_LOCALE_FLAGS_CONFIGURATION (0x0040)
+#define MPI3_PEL_LOCALE_FLAGS_CONTROLER (0x0020)
+#define MPI3_PEL_LOCALE_FLAGS_SAS (0x0010)
+#define MPI3_PEL_LOCALE_FLAGS_EPACK (0x0008)
+#define MPI3_PEL_LOCALE_FLAGS_ENCLOSURE (0x0004)
+#define MPI3_PEL_LOCALE_FLAGS_PD (0x0002)
+#define MPI3_PEL_LOCALE_FLAGS_VD (0x0001)
+#define MPI3_PEL_CLASS_DEBUG (0x00)
+#define MPI3_PEL_CLASS_PROGRESS (0x01)
+#define MPI3_PEL_CLASS_INFORMATIONAL (0x02)
+#define MPI3_PEL_CLASS_WARNING (0x03)
+#define MPI3_PEL_CLASS_CRITICAL (0x04)
+#define MPI3_PEL_CLASS_FATAL (0x05)
+#define MPI3_PEL_CLASS_FAULT (0x06)
+#define MPI3_PEL_CLEARTYPE_CLEAR (0x00)
+#define MPI3_PEL_WAITTIME_INFINITE_WAIT (0x00)
+#define MPI3_PEL_ACTION_GET_SEQNUM (0x01)
+#define MPI3_PEL_ACTION_MARK_CLEAR (0x02)
+#define MPI3_PEL_ACTION_GET_LOG (0x03)
+#define MPI3_PEL_ACTION_GET_COUNT (0x04)
+#define MPI3_PEL_ACTION_WAIT (0x05)
+#define MPI3_PEL_ACTION_ABORT (0x06)
+#define MPI3_PEL_ACTION_GET_PRINT_STRINGS (0x07)
+#define MPI3_PEL_ACTION_ACKNOWLEDGE (0x08)
+#define MPI3_PEL_STATUS_SUCCESS (0x00)
+#define MPI3_PEL_STATUS_NOT_FOUND (0x01)
+#define MPI3_PEL_STATUS_ABORTED (0x02)
+#define MPI3_PEL_STATUS_NOT_READY (0x03)
+struct mpi3_pel_seq {
+ __le32 newest;
+ __le32 oldest;
+ __le32 clear;
+ __le32 shutdown;
+ __le32 boot;
+ __le32 last_acknowledged;
+};
+
+struct mpi3_pel_entry {
+ __le32 sequence_number;
+ __le32 time_stamp[2];
+ __le16 log_code;
+ __le16 arg_type;
+ __le16 locale;
+ u8 class;
+ u8 reserved13;
+ u8 ext_num;
+ u8 num_exts;
+ u8 arg_data_size;
+ u8 fixed_format_size;
+ __le32 reserved18[2];
+ __le32 pel_info[24];
+};
+
+struct mpi3_pel_list {
+ __le32 log_count;
+ __le32 reserved04;
+ struct mpi3_pel_entry entry[1];
+};
+
+struct mpi3_pel_arg_map {
+ u8 arg_type;
+ u8 length;
+ __le16 start_location;
+};
+
+#define MPI3_PEL_ARG_MAP_ARG_TYPE_APPEND_STRING (0x00)
+#define MPI3_PEL_ARG_MAP_ARG_TYPE_INTEGER (0x01)
+#define MPI3_PEL_ARG_MAP_ARG_TYPE_STRING (0x02)
+#define MPI3_PEL_ARG_MAP_ARG_TYPE_BIT_FIELD (0x03)
+struct mpi3_pel_print_string {
+ __le16 log_code;
+ __le16 string_length;
+ u8 num_arg_map;
+ u8 reserved05[3];
+ struct mpi3_pel_arg_map arg_map[1];
+};
+
+struct mpi3_pel_print_string_list {
+ __le32 num_print_strings;
+ __le32 residual_bytes_remain;
+ __le32 reserved08[2];
+ struct mpi3_pel_print_string print_string[1];
+};
+
+#ifndef MPI3_PEL_ACTION_SPECIFIC_MAX
+#define MPI3_PEL_ACTION_SPECIFIC_MAX (1)
+#endif
+struct mpi3_pel_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ u8 action;
+ u8 reserved0b;
+ __le32 action_specific[MPI3_PEL_ACTION_SPECIFIC_MAX];
+};
+
+struct mpi3_pel_req_action_get_sequence_numbers {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ u8 action;
+ u8 reserved0b;
+ __le32 reserved0c[5];
+ union mpi3_sge_union sgl;
+};
+
+struct mpi3_pel_req_action_clear_log_marker {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ u8 action;
+ u8 reserved0b;
+ u8 clear_type;
+ u8 reserved0d[3];
+};
+
+struct mpi3_pel_req_action_get_log {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ u8 action;
+ u8 reserved0b;
+ __le32 starting_sequence_number;
+ __le16 locale;
+ u8 class;
+ u8 reserved13;
+ __le32 reserved14[3];
+ union mpi3_sge_union sgl;
+};
+
+struct mpi3_pel_req_action_get_count {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ u8 action;
+ u8 reserved0b;
+ __le32 starting_sequence_number;
+ __le16 locale;
+ u8 class;
+ u8 reserved13;
+ __le32 reserved14[3];
+ union mpi3_sge_union sgl;
+};
+
+struct mpi3_pel_req_action_wait {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ u8 action;
+ u8 reserved0b;
+ __le32 starting_sequence_number;
+ __le16 locale;
+ u8 class;
+ u8 reserved13;
+ __le16 wait_time;
+ __le16 reserved16;
+ __le32 reserved18[2];
+};
+
+struct mpi3_pel_req_action_abort {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ u8 action;
+ u8 reserved0b;
+ __le32 reserved0c;
+ __le16 abort_host_tag;
+ __le16 reserved12;
+ __le32 reserved14;
+};
+
+struct mpi3_pel_req_action_get_print_strings {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ u8 action;
+ u8 reserved0b;
+ __le32 reserved0c;
+ __le16 start_log_code;
+ __le16 reserved12;
+ __le32 reserved14[3];
+ union mpi3_sge_union sgl;
+};
+
+struct mpi3_pel_req_action_acknowledge {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ u8 action;
+ u8 reserved0b;
+ __le32 sequence_number;
+ __le32 reserved10;
+};
+
+#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT (0x01)
+struct mpi3_pel_reply {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 ioc_use_only08;
+ __le16 ioc_status;
+ __le32 ioc_log_info;
+ u8 action;
+ u8 reserved11;
+ __le16 reserved12;
+ __le16 pe_log_status;
+ __le16 reserved16;
+ __le32 transfer_length;
+};
+
+struct mpi3_ci_download_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ u8 action;
+ u8 reserved0b;
+ __le32 signature1;
+ __le32 total_image_size;
+ __le32 image_offset;
+ __le32 segment_size;
+ __le32 reserved1c;
+ union mpi3_sge_union sgl;
+};
+
+#define MPI3_CI_DOWNLOAD_MSGFLAGS_LAST_SEGMENT (0x80)
+#define MPI3_CI_DOWNLOAD_MSGFLAGS_FORCE_FMC_ENABLE (0x40)
+#define MPI3_CI_DOWNLOAD_MSGFLAGS_SIGNED_NVDATA (0x20)
+#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_MASK (0x03)
+#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_FAST (0x00)
+#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_MEDIUM (0x01)
+#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_SLOW (0x02)
+#define MPI3_CI_DOWNLOAD_ACTION_DOWNLOAD (0x01)
+#define MPI3_CI_DOWNLOAD_ACTION_ONLINE_ACTIVATION (0x02)
+#define MPI3_CI_DOWNLOAD_ACTION_OFFLINE_ACTIVATION (0x03)
+#define MPI3_CI_DOWNLOAD_ACTION_GET_STATUS (0x04)
+struct mpi3_ci_download_reply {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 ioc_use_only08;
+ __le16 ioc_status;
+ __le32 ioc_log_info;
+ u8 flags;
+ u8 cache_dirty;
+ u8 pending_count;
+ u8 reserved13;
+};
+
+#define MPI3_CI_DOWNLOAD_FLAGS_DOWNLOAD_IN_PROGRESS (0x80)
+#define MPI3_CI_DOWNLOAD_FLAGS_KEY_UPDATE_PENDING (0x10)
+#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_MASK (0x0e)
+#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_NOT_NEEDED (0x00)
+#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_AWAITING (0x02)
+#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_ONLINE_PENDING (0x04)
+#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_OFFLINE_PENDING (0x06)
+#define MPI3_CI_DOWNLOAD_FLAGS_COMPATIBLE (0x01)
+struct mpi3_ci_upload_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 reserved0a;
+ __le32 signature1;
+ __le32 reserved10;
+ __le32 image_offset;
+ __le32 segment_size;
+ __le32 reserved1c;
+ union mpi3_sge_union sgl;
+};
+
+#define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_MASK (0x01)
+#define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY (0x00)
+#define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_SECONDARY (0x01)
+#define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_MASK (0x02)
+#define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_FLASH (0x00)
+#define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_EXECUTABLE (0x02)
+#define MPI3_CTRL_OP_FORCE_FULL_DISCOVERY (0x01)
+#define MPI3_CTRL_OP_LOOKUP_MAPPING (0x02)
+#define MPI3_CTRL_OP_UPDATE_TIMESTAMP (0x04)
+#define MPI3_CTRL_OP_GET_TIMESTAMP (0x05)
+#define MPI3_CTRL_OP_REMOVE_DEVICE (0x10)
+#define MPI3_CTRL_OP_CLOSE_PERSISTENT_CONNECTION (0x11)
+#define MPI3_CTRL_OP_HIDDEN_ACK (0x12)
+#define MPI3_CTRL_OP_SAS_SEND_PRIMITIVE (0x20)
+#define MPI3_CTRL_OP_SAS_CLEAR_ERROR_LOG (0x21)
+#define MPI3_CTRL_OP_PCIE_CLEAR_ERROR_LOG (0x22)
+#define MPI3_CTRL_OP_LOOKUP_MAPPING_PARAM8_LOOKUP_METHOD_INDEX (0x00)
+#define MPI3_CTRL_OP_UPDATE_TIMESTAMP_PARAM64_TIMESTAMP_INDEX (0x00)
+#define MPI3_CTRL_OP_REMOVE_DEVICE_PARAM16_DEVHANDLE_INDEX (0x00)
+#define MPI3_CTRL_OP_CLOSE_PERSIST_CONN_PARAM16_DEVHANDLE_INDEX (0x00)
+#define MPI3_CTRL_OP_HIDDEN_ACK_PARAM16_DEVHANDLE_INDEX (0x00)
+#define MPI3_CTRL_OP_SAS_SEND_PRIM_PARAM8_PHY_INDEX (0x00)
+#define MPI3_CTRL_OP_SAS_SEND_PRIM_PARAM8_PRIMSEQ_INDEX (0x01)
+#define MPI3_CTRL_OP_SAS_SEND_PRIM_PARAM32_PRIMITIVE_INDEX (0x00)
+#define MPI3_CTRL_OP_SAS_CLEAR_ERR_LOG_PARAM8_PHY_INDEX (0x00)
+#define MPI3_CTRL_OP_PCIE_CLEAR_ERR_LOG_PARAM8_PHY_INDEX (0x00)
+#define MPI3_CTRL_LOOKUP_METHOD_WWID_ADDRESS (0x01)
+#define MPI3_CTRL_LOOKUP_METHOD_ENCLOSURE_SLOT (0x02)
+#define MPI3_CTRL_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03)
+#define MPI3_CTRL_LOOKUP_METHOD_PERSISTENT_ID (0x04)
+#define MPI3_CTRL_LOOKUP_METHOD_WWIDADDR_PARAM16_DEVH_INDEX (0)
+#define MPI3_CTRL_LOOKUP_METHOD_WWIDADDR_PARAM64_WWID_INDEX (0)
+#define MPI3_CTRL_LOOKUP_METHOD_ENCLSLOT_PARAM16_SLOTNUM_INDEX (0)
+#define MPI3_CTRL_LOOKUP_METHOD_ENCLSLOT_PARAM64_ENCLOSURELID_INDEX (0)
+#define MPI3_CTRL_LOOKUP_METHOD_SASDEVNAME_PARAM16_DEVH_INDEX (0)
+#define MPI3_CTRL_LOOKUP_METHOD_SASDEVNAME_PARAM64_DEVNAME_INDEX (0)
+#define MPI3_CTRL_LOOKUP_METHOD_PERSISTID_PARAM16_DEVH_INDEX (0)
+#define MPI3_CTRL_LOOKUP_METHOD_PERSISTID_PARAM16_PERSISTENT_ID_INDEX (1)
+#define MPI3_CTRL_LOOKUP_METHOD_VALUE16_DEVH_INDEX (0)
+#define MPI3_CTRL_GET_TIMESTAMP_VALUE64_TIMESTAMP_INDEX (0)
+#define MPI3_CTRL_PRIMFLAGS_SINGLE (0x01)
+#define MPI3_CTRL_PRIMFLAGS_TRIPLE (0x03)
+#define MPI3_CTRL_PRIMFLAGS_REDUNDANT (0x06)
+struct mpi3_iounit_control_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ u8 reserved0a;
+ u8 operation;
+ __le32 reserved0c;
+ __le64 param64[2];
+ __le32 param32[4];
+ __le16 param16[4];
+ u8 param8[8];
+};
+
+struct mpi3_iounit_control_reply {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 ioc_use_only08;
+ __le16 ioc_status;
+ __le32 ioc_log_info;
+ __le64 value64[2];
+ __le32 value32[4];
+ __le16 value16[4];
+ u8 value8[8];
+};
+#endif
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_sas.h b/drivers/scsi/mpi3mr/mpi/mpi30_sas.h
new file mode 100644
index 000000000000..ba5018702960
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_sas.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2016-2021 Broadcom Inc. All rights reserved.
+ *
+ */
+#ifndef MPI30_SAS_H
+#define MPI30_SAS_H 1
+#define MPI3_SAS_DEVICE_INFO_SSP_TARGET (0x00000100)
+#define MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET (0x00000080)
+#define MPI3_SAS_DEVICE_INFO_SMP_TARGET (0x00000040)
+#define MPI3_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000020)
+#define MPI3_SAS_DEVICE_INFO_STP_INITIATOR (0x00000010)
+#define MPI3_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000008)
+#define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK (0x00000007)
+#define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_NO_DEVICE (0x00000000)
+#define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE (0x00000001)
+#define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER (0x00000002)
+struct mpi3_smp_passthrough_request {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ u8 reserved0a;
+ u8 io_unit_port;
+ __le32 reserved0c[3];
+ __le64 sas_address;
+ struct mpi3_sge_common request_sge;
+ struct mpi3_sge_common response_sge;
+};
+#endif
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h
new file mode 100644
index 000000000000..63e4e81d5397
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h
@@ -0,0 +1,463 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2016-2021 Broadcom Inc. All rights reserved.
+ *
+ */
+#ifndef MPI30_TRANSPORT_H
+#define MPI30_TRANSPORT_H 1
+struct mpi3_version_struct {
+ u8 dev;
+ u8 unit;
+ u8 minor;
+ u8 major;
+};
+
+union mpi3_version_union {
+ struct mpi3_version_struct mpi3_version;
+ __le32 word;
+};
+
+#define MPI3_VERSION_MAJOR (3)
+#define MPI3_VERSION_MINOR (0)
+#define MPI3_VERSION_UNIT (0)
+#define MPI3_VERSION_DEV (18)
+struct mpi3_sysif_oper_queue_indexes {
+ __le16 producer_index;
+ __le16 reserved02;
+ __le16 consumer_index;
+ __le16 reserved06;
+};
+
+struct mpi3_sysif_registers {
+ __le64 ioc_information;
+ union mpi3_version_union version;
+ __le32 reserved0c[2];
+ __le32 ioc_configuration;
+ __le32 reserved18;
+ __le32 ioc_status;
+ __le32 reserved20;
+ __le32 admin_queue_num_entries;
+ __le64 admin_request_queue_address;
+ __le64 admin_reply_queue_address;
+ __le32 reserved38[2];
+ __le32 coalesce_control;
+ __le32 reserved44[1007];
+ __le16 admin_request_queue_pi;
+ __le16 reserved1002;
+ __le16 admin_reply_queue_ci;
+ __le16 reserved1006;
+ struct mpi3_sysif_oper_queue_indexes oper_queue_indexes[383];
+ __le32 reserved1c00;
+ __le32 write_sequence;
+ __le32 host_diagnostic;
+ __le32 reserved1c0c;
+ __le32 fault;
+ __le32 fault_info[3];
+ __le32 reserved1c20[4];
+ __le64 hcb_address;
+ __le32 hcb_size;
+ __le32 reserved1c3c;
+ __le32 reply_free_host_index;
+ __le32 sense_buffer_free_host_index;
+ __le32 reserved1c48[2];
+ __le64 diag_rw_data;
+ __le64 diag_rw_address;
+ __le16 diag_rw_control;
+ __le16 diag_rw_status;
+ __le32 reserved1c64[35];
+ __le32 scratchpad[4];
+ __le32 reserved1d00[192];
+ __le32 device_assigned_registers[2048];
+};
+
+#define MPI3_SYSIF_IOC_INFO_LOW_OFFSET (0x00000000)
+#define MPI3_SYSIF_IOC_INFO_HIGH_OFFSET (0x00000004)
+#define MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK (0xff000000)
+#define MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT (24)
+#define MPI3_SYSIF_IOC_CONFIG_OFFSET (0x00000014)
+#define MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ (0x00f00000)
+#define MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT (20)
+#define MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ (0x000f0000)
+#define MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT (16)
+#define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_MASK (0x0000c000)
+#define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NO (0x00000000)
+#define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL (0x00004000)
+#define MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN (0x00002000)
+#define MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE (0x00000010)
+#define MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC (0x00000001)
+#define MPI3_SYSIF_IOC_STATUS_OFFSET (0x0000001c)
+#define MPI3_SYSIF_IOC_STATUS_RESET_HISTORY (0x00000010)
+#define MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK (0x0000000c)
+#define MPI3_SYSIF_IOC_STATUS_SHUTDOWN_NONE (0x00000000)
+#define MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS (0x00000004)
+#define MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE (0x00000008)
+#define MPI3_SYSIF_IOC_STATUS_FAULT (0x00000002)
+#define MPI3_SYSIF_IOC_STATUS_READY (0x00000001)
+#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_OFFSET (0x00000024)
+#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REQ_MASK (0x0fff)
+#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_OFFSET (0x00000026)
+#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_MASK (0x0fff0000)
+#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_SHIFT (16)
+#define MPI3_SYSIF_ADMIN_REQ_Q_ADDR_LOW_OFFSET (0x00000028)
+#define MPI3_SYSIF_ADMIN_REQ_Q_ADDR_HIGH_OFFSET (0x0000002c)
+#define MPI3_SYSIF_ADMIN_REPLY_Q_ADDR_LOW_OFFSET (0x00000030)
+#define MPI3_SYSIF_ADMIN_REPLY_Q_ADDR_HIGH_OFFSET (0x00000034)
+#define MPI3_SYSIF_COALESCE_CONTROL_OFFSET (0x00000040)
+#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_MASK (0xc0000000)
+#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_NO_CHANGE (0x00000000)
+#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_DISABLE (0x40000000)
+#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_ENABLE (0xc0000000)
+#define MPI3_SYSIF_COALESCE_CONTROL_VALID (0x30000000)
+#define MPI3_SYSIF_COALESCE_CONTROL_QUEUE_ID_MASK (0x00ff0000)
+#define MPI3_SYSIF_COALESCE_CONTROL_QUEUE_ID_SHIFT (16)
+#define MPI3_SYSIF_COALESCE_CONTROL_TIMEOUT_MASK (0x0000ff00)
+#define MPI3_SYSIF_COALESCE_CONTROL_TIMEOUT_SHIFT (8)
+#define MPI3_SYSIF_COALESCE_CONTROL_DEPTH_MASK (0x000000ff)
+#define MPI3_SYSIF_COALESCE_CONTROL_DEPTH_SHIFT (0)
+#define MPI3_SYSIF_ADMIN_REQ_Q_PI_OFFSET (0x00001000)
+#define MPI3_SYSIF_ADMIN_REPLY_Q_CI_OFFSET (0x00001004)
+#define MPI3_SYSIF_OPER_REQ_Q_PI_OFFSET (0x00001008)
+#define MPI3_SYSIF_OPER_REQ_Q_N_PI_OFFSET(n) (MPI3_SYSIF_OPER_REQ_Q_PI_OFFSET + (((n) - 1) * 8))
+#define MPI3_SYSIF_OPER_REPLY_Q_CI_OFFSET (0x0000100c)
+#define MPI3_SYSIF_OPER_REPLY_Q_N_CI_OFFSET(n) (MPI3_SYSIF_OPER_REPLY_Q_CI_OFFSET + (((n) - 1) * 8))
+#define MPI3_SYSIF_WRITE_SEQUENCE_OFFSET (0x00001c04)
+#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_MASK (0x0000000f)
+#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH (0x0)
+#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST (0xf)
+#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND (0x4)
+#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_3RD (0xb)
+#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_4TH (0x2)
+#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_5TH (0x7)
+#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH (0xd)
+#define MPI3_SYSIF_HOST_DIAG_OFFSET (0x00001c08)
+#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_MASK (0x00000700)
+#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_NO_RESET (0x00000000)
+#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET (0x00000100)
+#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_FLASH_RCVRY_RESET (0x00000200)
+#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_COMPLETE_RESET (0x00000300)
+#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT (0x00000700)
+#define MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS (0x00000080)
+#define MPI3_SYSIF_HOST_DIAG_SECURE_BOOT (0x00000040)
+#define MPI3_SYSIF_HOST_DIAG_CLEAR_INVALID_FW_IMAGE (0x00000020)
+#define MPI3_SYSIF_HOST_DIAG_INVALID_FW_IMAGE (0x00000010)
+#define MPI3_SYSIF_HOST_DIAG_HCBENABLE (0x00000008)
+#define MPI3_SYSIF_HOST_DIAG_HCBMODE (0x00000004)
+#define MPI3_SYSIF_HOST_DIAG_DIAG_RW_ENABLE (0x00000002)
+#define MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE (0x00000001)
+#define MPI3_SYSIF_FAULT_OFFSET (0x00001c10)
+#define MPI3_SYSIF_FAULT_FUNC_AREA_MASK (0xff000000)
+#define MPI3_SYSIF_FAULT_FUNC_AREA_SHIFT (24)
+#define MPI3_SYSIF_FAULT_FUNC_AREA_MPI_DEFINED (0x00000000)
+#define MPI3_SYSIF_FAULT_CODE_MASK (0x0000ffff)
+#define MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET (0x0000f000)
+#define MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET (0x0000f001)
+#define MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS (0x0000f002)
+#define MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED (0x0000f003)
+#define MPI3_SYSIF_FAULT_CODE_SAFE_MODE_EXIT (0x0000f004)
+#define MPI3_SYSIF_FAULT_CODE_FACTORY_RESET (0x0000f005)
+#define MPI3_SYSIF_FAULT_INFO0_OFFSET (0x00001c14)
+#define MPI3_SYSIF_FAULT_INFO1_OFFSET (0x00001c18)
+#define MPI3_SYSIF_FAULT_INFO2_OFFSET (0x00001c1c)
+#define MPI3_SYSIF_HCB_ADDRESS_LOW_OFFSET (0x00001c30)
+#define MPI3_SYSIF_HCB_ADDRESS_HIGH_OFFSET (0x00001c34)
+#define MPI3_SYSIF_HCB_SIZE_OFFSET (0x00001c38)
+#define MPI3_SYSIF_HCB_SIZE_SIZE_MASK (0xfffff000)
+#define MPI3_SYSIF_HCB_SIZE_SIZE_SHIFT (12)
+#define MPI3_SYSIF_HCB_SIZE_HCDW_ENABLE (0x00000001)
+#define MPI3_SYSIF_REPLY_FREE_HOST_INDEX_OFFSET (0x00001c40)
+#define MPI3_SYSIF_SENSE_BUF_FREE_HOST_INDEX_OFFSET (0x00001c44)
+#define MPI3_SYSIF_DIAG_RW_DATA_LOW_OFFSET (0x00001c50)
+#define MPI3_SYSIF_DIAG_RW_DATA_HIGH_OFFSET (0x00001c54)
+#define MPI3_SYSIF_DIAG_RW_ADDRESS_LOW_OFFSET (0x00001c58)
+#define MPI3_SYSIF_DIAG_RW_ADDRESS_HIGH_OFFSET (0x00001c5c)
+#define MPI3_SYSIF_DIAG_RW_CONTROL_OFFSET (0x00001c60)
+#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_MASK (0x00000030)
+#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_1BYTE (0x00000000)
+#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_2BYTES (0x00000010)
+#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_4BYTES (0x00000020)
+#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_8BYTES (0x00000030)
+#define MPI3_SYSIF_DIAG_RW_CONTROL_RESET (0x00000004)
+#define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_MASK (0x00000002)
+#define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_READ (0x00000000)
+#define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_WRITE (0x00000002)
+#define MPI3_SYSIF_DIAG_RW_CONTROL_START (0x00000001)
+#define MPI3_SYSIF_DIAG_RW_STATUS_OFFSET (0x00001c62)
+#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_MASK (0x0000000e)
+#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_SUCCESS (0x00000000)
+#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_INV_ADDR (0x00000002)
+#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_ACC_ERR (0x00000004)
+#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_PAR_ERR (0x00000006)
+#define MPI3_SYSIF_DIAG_RW_STATUS_BUSY (0x00000001)
+#define MPI3_SYSIF_SCRATCHPAD0_OFFSET (0x00001cf0)
+#define MPI3_SYSIF_SCRATCHPAD1_OFFSET (0x00001cf4)
+#define MPI3_SYSIF_SCRATCHPAD2_OFFSET (0x00001cf8)
+#define MPI3_SYSIF_SCRATCHPAD3_OFFSET (0x00001cfc)
+#define MPI3_SYSIF_DEVICE_ASSIGNED_REGS_OFFSET (0x00002000)
+#define MPI3_SYSIF_DIAG_SAVE_TIMEOUT (60)
+struct mpi3_default_reply_descriptor {
+ __le32 descriptor_type_dependent1[2];
+ __le16 request_queue_ci;
+ __le16 request_queue_id;
+ __le16 descriptor_type_dependent2;
+ __le16 reply_flags;
+};
+
+#define MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK (0x0001)
+#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK (0xf000)
+#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY (0x0000)
+#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS (0x1000)
+#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_TARGET_COMMAND_BUFFER (0x2000)
+#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS (0x3000)
+struct mpi3_address_reply_descriptor {
+ __le64 reply_frame_address;
+ __le16 request_queue_ci;
+ __le16 request_queue_id;
+ __le16 reserved0c;
+ __le16 reply_flags;
+};
+
+struct mpi3_success_reply_descriptor {
+ __le32 reserved00[2];
+ __le16 request_queue_ci;
+ __le16 request_queue_id;
+ __le16 host_tag;
+ __le16 reply_flags;
+};
+
+struct mpi3_target_command_buffer_reply_descriptor {
+ __le32 reserved00;
+ __le16 initiator_dev_handle;
+ u8 phy_num;
+ u8 reserved07;
+ __le16 request_queue_ci;
+ __le16 request_queue_id;
+ __le16 io_index;
+ __le16 reply_flags;
+};
+
+struct mpi3_status_reply_descriptor {
+ __le16 ioc_status;
+ __le16 reserved02;
+ __le32 ioc_log_info;
+ __le16 request_queue_ci;
+ __le16 request_queue_id;
+ __le16 host_tag;
+ __le16 reply_flags;
+};
+
+#define MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL (0x8000)
+#define MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK (0x7fff)
+#define MPI3_REPLY_DESCRIPT_STATUS_IOCLOGINFO_TYPE_MASK (0xf0000000)
+#define MPI3_REPLY_DESCRIPT_STATUS_IOCLOGINFO_TYPE_NO_INFO (0x00000000)
+#define MPI3_REPLY_DESCRIPT_STATUS_IOCLOGINFO_TYPE_SAS (0x30000000)
+#define MPI3_REPLY_DESCRIPT_STATUS_IOCLOGINFO_DATA_MASK (0x0fffffff)
+union mpi3_reply_descriptors_union {
+ struct mpi3_default_reply_descriptor default_reply;
+ struct mpi3_address_reply_descriptor address_reply;
+ struct mpi3_success_reply_descriptor success;
+ struct mpi3_target_command_buffer_reply_descriptor target_command_buffer;
+ struct mpi3_status_reply_descriptor status;
+ __le32 words[4];
+};
+
+struct mpi3_sge_common {
+ __le64 address;
+ __le32 length;
+ u8 reserved0c[3];
+ u8 flags;
+};
+
+struct mpi3_sge_bit_bucket {
+ __le64 reserved00;
+ __le32 length;
+ u8 reserved0c[3];
+ u8 flags;
+};
+
+struct mpi3_sge_extended_eedp {
+ u8 user_data_size;
+ u8 reserved01;
+ __le16 eedp_flags;
+ __le32 secondary_reference_tag;
+ __le16 secondary_application_tag;
+ __le16 application_tag_translation_mask;
+ __le16 reserved0c;
+ u8 extended_operation;
+ u8 flags;
+};
+
+union mpi3_sge_union {
+ struct mpi3_sge_common simple;
+ struct mpi3_sge_common chain;
+ struct mpi3_sge_common last_chain;
+ struct mpi3_sge_bit_bucket bit_bucket;
+ struct mpi3_sge_extended_eedp eedp;
+ __le32 words[4];
+};
+
+#define MPI3_SGE_FLAGS_ELEMENT_TYPE_MASK (0xf0)
+#define MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE (0x00)
+#define MPI3_SGE_FLAGS_ELEMENT_TYPE_BIT_BUCKET (0x10)
+#define MPI3_SGE_FLAGS_ELEMENT_TYPE_CHAIN (0x20)
+#define MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN (0x30)
+#define MPI3_SGE_FLAGS_ELEMENT_TYPE_EXTENDED (0xf0)
+#define MPI3_SGE_FLAGS_END_OF_LIST (0x08)
+#define MPI3_SGE_FLAGS_END_OF_BUFFER (0x04)
+#define MPI3_SGE_FLAGS_DLAS_MASK (0x03)
+#define MPI3_SGE_FLAGS_DLAS_SYSTEM (0x00)
+#define MPI3_SGE_FLAGS_DLAS_IOC_DDR (0x01)
+#define MPI3_SGE_FLAGS_DLAS_IOC_CTL (0x02)
+#define MPI3_SGE_EXT_OPER_EEDP (0x00)
+#define MPI3_EEDPFLAGS_INCR_PRI_REF_TAG (0x8000)
+#define MPI3_EEDPFLAGS_INCR_SEC_REF_TAG (0x4000)
+#define MPI3_EEDPFLAGS_INCR_PRI_APP_TAG (0x2000)
+#define MPI3_EEDPFLAGS_INCR_SEC_APP_TAG (0x1000)
+#define MPI3_EEDPFLAGS_ESC_PASSTHROUGH (0x0800)
+#define MPI3_EEDPFLAGS_CHK_REF_TAG (0x0400)
+#define MPI3_EEDPFLAGS_CHK_APP_TAG (0x0200)
+#define MPI3_EEDPFLAGS_CHK_GUARD (0x0100)
+#define MPI3_EEDPFLAGS_ESC_MODE_MASK (0x00c0)
+#define MPI3_EEDPFLAGS_ESC_MODE_DO_NOT_DISABLE (0x0040)
+#define MPI3_EEDPFLAGS_ESC_MODE_APPTAG_DISABLE (0x0080)
+#define MPI3_EEDPFLAGS_ESC_MODE_APPTAG_REFTAG_DISABLE (0x00c0)
+#define MPI3_EEDPFLAGS_HOST_GUARD_MASK (0x0030)
+#define MPI3_EEDPFLAGS_HOST_GUARD_T10_CRC (0x0000)
+#define MPI3_EEDPFLAGS_HOST_GUARD_IP_CHKSUM (0x0010)
+#define MPI3_EEDPFLAGS_HOST_GUARD_OEM_SPECIFIC (0x0020)
+#define MPI3_EEDPFLAGS_PT_REF_TAG (0x0008)
+#define MPI3_EEDPFLAGS_EEDP_OP_MASK (0x0007)
+#define MPI3_EEDPFLAGS_EEDP_OP_NOOP (0x0000)
+#define MPI3_EEDPFLAGS_EEDP_OP_CHECK (0x0001)
+#define MPI3_EEDPFLAGS_EEDP_OP_STRIP (0x0002)
+#define MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE (0x0003)
+#define MPI3_EEDPFLAGS_EEDP_OP_INSERT (0x0004)
+#define MPI3_EEDPFLAGS_EEDP_OP_REPLACE (0x0006)
+#define MPI3_EEDPFLAGS_EEDP_OP_CHECK_REGEN (0x0007)
+#define MPI3_EEDP_UDS_512 (0x01)
+#define MPI3_EEDP_UDS_520 (0x02)
+#define MPI3_EEDP_UDS_4080 (0x03)
+#define MPI3_EEDP_UDS_4088 (0x04)
+#define MPI3_EEDP_UDS_4096 (0x05)
+#define MPI3_EEDP_UDS_4104 (0x06)
+#define MPI3_EEDP_UDS_4160 (0x07)
+struct mpi3_request_header {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 change_count;
+ __le16 function_dependent;
+};
+
+struct mpi3_default_reply {
+ __le16 host_tag;
+ u8 ioc_use_only02;
+ u8 function;
+ __le16 ioc_use_only04;
+ u8 ioc_use_only06;
+ u8 msg_flags;
+ __le16 ioc_use_only08;
+ __le16 ioc_status;
+ __le32 ioc_log_info;
+};
+
+#define MPI3_HOST_TAG_INVALID (0xffff)
+#define MPI3_FUNCTION_IOC_FACTS (0x01)
+#define MPI3_FUNCTION_IOC_INIT (0x02)
+#define MPI3_FUNCTION_PORT_ENABLE (0x03)
+#define MPI3_FUNCTION_EVENT_NOTIFICATION (0x04)
+#define MPI3_FUNCTION_EVENT_ACK (0x05)
+#define MPI3_FUNCTION_CI_DOWNLOAD (0x06)
+#define MPI3_FUNCTION_CI_UPLOAD (0x07)
+#define MPI3_FUNCTION_IO_UNIT_CONTROL (0x08)
+#define MPI3_FUNCTION_PERSISTENT_EVENT_LOG (0x09)
+#define MPI3_FUNCTION_MGMT_PASSTHROUGH (0x0a)
+#define MPI3_FUNCTION_CONFIG (0x10)
+#define MPI3_FUNCTION_SCSI_IO (0x20)
+#define MPI3_FUNCTION_SCSI_TASK_MGMT (0x21)
+#define MPI3_FUNCTION_SMP_PASSTHROUGH (0x22)
+#define MPI3_FUNCTION_NVME_ENCAPSULATED (0x24)
+#define MPI3_FUNCTION_TARGET_ASSIST (0x30)
+#define MPI3_FUNCTION_TARGET_STATUS_SEND (0x31)
+#define MPI3_FUNCTION_TARGET_MODE_ABORT (0x32)
+#define MPI3_FUNCTION_TARGET_CMD_BUF_POST_BASE (0x33)
+#define MPI3_FUNCTION_TARGET_CMD_BUF_POST_LIST (0x34)
+#define MPI3_FUNCTION_CREATE_REQUEST_QUEUE (0x70)
+#define MPI3_FUNCTION_DELETE_REQUEST_QUEUE (0x71)
+#define MPI3_FUNCTION_CREATE_REPLY_QUEUE (0x72)
+#define MPI3_FUNCTION_DELETE_REPLY_QUEUE (0x73)
+#define MPI3_FUNCTION_TOOLBOX (0x80)
+#define MPI3_FUNCTION_DIAG_BUFFER_POST (0x81)
+#define MPI3_FUNCTION_DIAG_BUFFER_MANAGE (0x82)
+#define MPI3_FUNCTION_DIAG_BUFFER_UPLOAD (0x83)
+#define MPI3_FUNCTION_MIN_IOC_USE_ONLY (0xc0)
+#define MPI3_FUNCTION_MAX_IOC_USE_ONLY (0xef)
+#define MPI3_FUNCTION_MIN_PRODUCT_SPECIFIC (0xf0)
+#define MPI3_FUNCTION_MAX_PRODUCT_SPECIFIC (0xff)
+#define MPI3_IOCSTATUS_LOG_INFO_AVAIL_MASK (0x8000)
+#define MPI3_IOCSTATUS_LOG_INFO_AVAILABLE (0x8000)
+#define MPI3_IOCSTATUS_STATUS_MASK (0x7fff)
+#define MPI3_IOCSTATUS_SUCCESS (0x0000)
+#define MPI3_IOCSTATUS_INVALID_FUNCTION (0x0001)
+#define MPI3_IOCSTATUS_BUSY (0x0002)
+#define MPI3_IOCSTATUS_INVALID_SGL (0x0003)
+#define MPI3_IOCSTATUS_INTERNAL_ERROR (0x0004)
+#define MPI3_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006)
+#define MPI3_IOCSTATUS_INVALID_FIELD (0x0007)
+#define MPI3_IOCSTATUS_INVALID_STATE (0x0008)
+#define MPI3_IOCSTATUS_INSUFFICIENT_POWER (0x000a)
+#define MPI3_IOCSTATUS_INVALID_CHANGE_COUNT (0x000b)
+#define MPI3_IOCSTATUS_FAILURE (0x001f)
+#define MPI3_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020)
+#define MPI3_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021)
+#define MPI3_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022)
+#define MPI3_IOCSTATUS_CONFIG_INVALID_DATA (0x0023)
+#define MPI3_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024)
+#define MPI3_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025)
+#define MPI3_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040)
+#define MPI3_IOCSTATUS_SCSI_TM_NOT_SUPPORTED (0x0041)
+#define MPI3_IOCSTATUS_SCSI_INVALID_DEVHANDLE (0x0042)
+#define MPI3_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043)
+#define MPI3_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044)
+#define MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045)
+#define MPI3_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046)
+#define MPI3_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047)
+#define MPI3_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048)
+#define MPI3_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049)
+#define MPI3_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004a)
+#define MPI3_IOCSTATUS_SCSI_IOC_TERMINATED (0x004b)
+#define MPI3_IOCSTATUS_SCSI_EXT_TERMINATED (0x004c)
+#define MPI3_IOCSTATUS_EEDP_GUARD_ERROR (0x004d)
+#define MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004e)
+#define MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004f)
+#define MPI3_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062)
+#define MPI3_IOCSTATUS_TARGET_ABORTED (0x0063)
+#define MPI3_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064)
+#define MPI3_IOCSTATUS_TARGET_NO_CONNECTION (0x0065)
+#define MPI3_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006a)
+#define MPI3_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006d)
+#define MPI3_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006e)
+#define MPI3_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006f)
+#define MPI3_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT (0x0070)
+#define MPI3_IOCSTATUS_TARGET_NAK_RECEIVED (0x0071)
+#define MPI3_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090)
+#define MPI3_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091)
+#define MPI3_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00a0)
+#define MPI3_IOCSTATUS_CI_UNSUPPORTED (0x00b0)
+#define MPI3_IOCSTATUS_CI_UPDATE_SEQUENCE (0x00b1)
+#define MPI3_IOCSTATUS_CI_VALIDATION_FAILED (0x00b2)
+#define MPI3_IOCSTATUS_CI_UPDATE_PENDING (0x00b3)
+#define MPI3_IOCSTATUS_SECURITY_KEY_REQUIRED (0x00c0)
+#define MPI3_IOCSTATUS_INVALID_QUEUE_ID (0x0f00)
+#define MPI3_IOCSTATUS_INVALID_QUEUE_SIZE (0x0f01)
+#define MPI3_IOCSTATUS_INVALID_MSIX_VECTOR (0x0f02)
+#define MPI3_IOCSTATUS_INVALID_REPLY_QUEUE_ID (0x0f03)
+#define MPI3_IOCSTATUS_INVALID_QUEUE_DELETION (0x0f04)
+#define MPI3_IOCLOGINFO_TYPE_MASK (0xf0000000)
+#define MPI3_IOCLOGINFO_TYPE_SHIFT (28)
+#define MPI3_IOCLOGINFO_TYPE_NONE (0x0)
+#define MPI3_IOCLOGINFO_TYPE_SAS (0x3)
+#define MPI3_IOCLOGINFO_LOG_DATA_MASK (0x0fffffff)
+#endif
diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
new file mode 100644
index 000000000000..6f5dc9e78553
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -0,0 +1,901 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Driver for Broadcom MPI3 Storage Controllers
+ *
+ * Copyright (C) 2017-2021 Broadcom Inc.
+ * (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
+ *
+ */
+
+#ifndef MPI3MR_H_INCLUDED
+#define MPI3MR_H_INCLUDED
+
+#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
+#include <linux/blk-mq-pci.h>
+#include <linux/delay.h>
+#include <linux/dmapool.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/utsname.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+
+#include "mpi/mpi30_transport.h"
+#include "mpi/mpi30_cnfg.h"
+#include "mpi/mpi30_image.h"
+#include "mpi/mpi30_init.h"
+#include "mpi/mpi30_ioc.h"
+#include "mpi/mpi30_sas.h"
+#include "mpi3mr_debug.h"
+
+/* Global list and lock for storing multiple adapters managed by the driver */
+extern spinlock_t mrioc_list_lock;
+extern struct list_head mrioc_list;
+extern int prot_mask;
+
+#define MPI3MR_DRIVER_VERSION "00.255.45.01"
+#define MPI3MR_DRIVER_RELDATE "12-December-2020"
+
+#define MPI3MR_DRIVER_NAME "mpi3mr"
+#define MPI3MR_DRIVER_LICENSE "GPL"
+#define MPI3MR_DRIVER_AUTHOR "Broadcom Inc. <mpi3mr-linuxdrv.pdl@broadcom.com>"
+#define MPI3MR_DRIVER_DESC "MPI3 Storage Controller Device Driver"
+
+#define MPI3MR_NAME_LENGTH 32
+#define IOCNAME "%s: "
+
+/* Definitions for internal SGL and Chain SGL buffers */
+#define MPI3MR_PAGE_SIZE_4K 4096
+#define MPI3MR_SG_DEPTH (MPI3MR_PAGE_SIZE_4K / sizeof(struct mpi3_sge_common))
+
+/* Definitions for MAX values for shost */
+#define MPI3MR_MAX_CMDS_LUN 7
+#define MPI3MR_MAX_CDB_LENGTH 32
+
+/* Admin queue management definitions */
+#define MPI3MR_ADMIN_REQ_Q_SIZE (2 * MPI3MR_PAGE_SIZE_4K)
+#define MPI3MR_ADMIN_REPLY_Q_SIZE (4 * MPI3MR_PAGE_SIZE_4K)
+#define MPI3MR_ADMIN_REQ_FRAME_SZ 128
+#define MPI3MR_ADMIN_REPLY_FRAME_SZ 16
+
+/* Operational queue management definitions */
+#define MPI3MR_OP_REQ_Q_QD 512
+#define MPI3MR_OP_REP_Q_QD 4096
+#define MPI3MR_OP_REQ_Q_SEG_SIZE 4096
+#define MPI3MR_OP_REP_Q_SEG_SIZE 4096
+#define MPI3MR_MAX_SEG_LIST_SIZE 4096
+
+/* Reserved Host Tag definitions */
+#define MPI3MR_HOSTTAG_INVALID 0xFFFF
+#define MPI3MR_HOSTTAG_INITCMDS 1
+#define MPI3MR_HOSTTAG_IOCTLCMDS 2
+#define MPI3MR_HOSTTAG_BLK_TMS 5
+
+#define MPI3MR_NUM_DEVRMCMD 1
+#define MPI3MR_HOSTTAG_DEVRMCMD_MIN (MPI3MR_HOSTTAG_BLK_TMS + 1)
+#define MPI3MR_HOSTTAG_DEVRMCMD_MAX (MPI3MR_HOSTTAG_DEVRMCMD_MIN + \
+ MPI3MR_NUM_DEVRMCMD - 1)
+
+#define MPI3MR_INTERNAL_CMDS_RESVD MPI3MR_HOSTTAG_DEVRMCMD_MAX
+
+/* Reduced resource count definition for crash kernel */
+#define MPI3MR_HOST_IOS_KDUMP 128
+
+/* command/controller interaction timeout definitions in seconds */
+#define MPI3MR_INTADMCMD_TIMEOUT 10
+#define MPI3MR_PORTENABLE_TIMEOUT 300
+#define MPI3MR_ABORTTM_TIMEOUT 30
+#define MPI3MR_RESETTM_TIMEOUT 30
+#define MPI3MR_RESET_HOST_IOWAIT_TIMEOUT 5
+#define MPI3MR_TSUPDATE_INTERVAL 900
+#define MPI3MR_DEFAULT_SHUTDOWN_TIME 120
+#define MPI3MR_RAID_ERRREC_RESET_TIMEOUT 180
+
+#define MPI3MR_WATCHDOG_INTERVAL 1000 /* in milli seconds */
+
+/* Internal admin command state definitions*/
+#define MPI3MR_CMD_NOTUSED 0x8000
+#define MPI3MR_CMD_COMPLETE 0x0001
+#define MPI3MR_CMD_PENDING 0x0002
+#define MPI3MR_CMD_REPLY_VALID 0x0004
+#define MPI3MR_CMD_RESET 0x0008
+
+/* Definitions for Event replies and sense buffer allocated per controller */
+#define MPI3MR_NUM_EVT_REPLIES 64
+#define MPI3MR_SENSEBUF_SZ 256
+#define MPI3MR_SENSEBUF_FACTOR 3
+#define MPI3MR_CHAINBUF_FACTOR 3
+#define MPI3MR_CHAINBUFDIX_FACTOR 2
+
+/* Invalid target device handle */
+#define MPI3MR_INVALID_DEV_HANDLE 0xFFFF
+
+/* Controller Reset related definitions */
+#define MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT 5
+#define MPI3MR_MAX_RESET_RETRY_COUNT 3
+
+/* ResponseCode definitions */
+#define MPI3MR_RI_MASK_RESPCODE (0x000000FF)
+#define MPI3MR_RSP_TM_COMPLETE 0x00
+#define MPI3MR_RSP_INVALID_FRAME 0x02
+#define MPI3MR_RSP_TM_NOT_SUPPORTED 0x04
+#define MPI3MR_RSP_TM_FAILED 0x05
+#define MPI3MR_RSP_TM_SUCCEEDED 0x08
+#define MPI3MR_RSP_TM_INVALID_LUN 0x09
+#define MPI3MR_RSP_TM_OVERLAPPED_TAG 0x0A
+#define MPI3MR_RSP_IO_QUEUED_ON_IOC \
+ MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC
+
+#define MPI3MR_DEFAULT_MDTS (128 * 1024)
+/* Command retry count definitions */
+#define MPI3MR_DEV_RMHS_RETRY_COUNT 3
+
+/* Default target device queue depth */
+#define MPI3MR_DEFAULT_SDEV_QD 32
+
+/* Definitions for Threaded IRQ poll*/
+#define MPI3MR_IRQ_POLL_SLEEP 2
+#define MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT 8
+
+/* Definitions for the controller security status*/
+#define MPI3MR_CTLR_SECURITY_STATUS_MASK 0x0C
+#define MPI3MR_CTLR_SECURE_DBG_STATUS_MASK 0x02
+
+#define MPI3MR_INVALID_DEVICE 0x00
+#define MPI3MR_CONFIG_SECURE_DEVICE 0x04
+#define MPI3MR_HARD_SECURE_DEVICE 0x08
+#define MPI3MR_TAMPERED_DEVICE 0x0C
+
+/* SGE Flag definition */
+#define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \
+ (MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | MPI3_SGE_FLAGS_DLAS_SYSTEM | \
+ MPI3_SGE_FLAGS_END_OF_LIST)
+
+/* MSI Index from Reply Queue Index */
+#define REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, offset) (qidx + offset)
+
+/* IOC State definitions */
+enum mpi3mr_iocstate {
+ MRIOC_STATE_READY = 1,
+ MRIOC_STATE_RESET,
+ MRIOC_STATE_FAULT,
+ MRIOC_STATE_BECOMING_READY,
+ MRIOC_STATE_RESET_REQUESTED,
+ MRIOC_STATE_UNRECOVERABLE,
+};
+
+/* Reset reason code definitions*/
+enum mpi3mr_reset_reason {
+ MPI3MR_RESET_FROM_BRINGUP = 1,
+ MPI3MR_RESET_FROM_FAULT_WATCH = 2,
+ MPI3MR_RESET_FROM_IOCTL = 3,
+ MPI3MR_RESET_FROM_EH_HOS = 4,
+ MPI3MR_RESET_FROM_TM_TIMEOUT = 5,
+ MPI3MR_RESET_FROM_IOCTL_TIMEOUT = 6,
+ MPI3MR_RESET_FROM_MUR_FAILURE = 7,
+ MPI3MR_RESET_FROM_CTLR_CLEANUP = 8,
+ MPI3MR_RESET_FROM_CIACTIV_FAULT = 9,
+ MPI3MR_RESET_FROM_PE_TIMEOUT = 10,
+ MPI3MR_RESET_FROM_TSU_TIMEOUT = 11,
+ MPI3MR_RESET_FROM_DELREQQ_TIMEOUT = 12,
+ MPI3MR_RESET_FROM_DELREPQ_TIMEOUT = 13,
+ MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT = 14,
+ MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT = 15,
+ MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT = 16,
+ MPI3MR_RESET_FROM_IOCINIT_TIMEOUT = 17,
+ MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT = 18,
+ MPI3MR_RESET_FROM_EVTACK_TIMEOUT = 19,
+ MPI3MR_RESET_FROM_CIACTVRST_TIMER = 20,
+ MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT = 21,
+ MPI3MR_RESET_FROM_PELABORT_TIMEOUT = 22,
+ MPI3MR_RESET_FROM_SYSFS = 23,
+ MPI3MR_RESET_FROM_SYSFS_TIMEOUT = 24
+};
+
+/**
+ * struct mpi3mr_compimg_ver - replica of component image
+ * version defined in mpi30_image.h in host endianness
+ *
+ */
+struct mpi3mr_compimg_ver {
+ u16 build_num;
+ u16 cust_id;
+ u8 ph_minor;
+ u8 ph_major;
+ u8 gen_minor;
+ u8 gen_major;
+};
+
+/**
+ * struct mpi3mr_ioc_facs - replica of component image version
+ * defined in mpi30_ioc.h in host endianness
+ *
+ */
+struct mpi3mr_ioc_facts {
+ u32 ioc_capabilities;
+ struct mpi3mr_compimg_ver fw_ver;
+ u32 mpi_version;
+ u16 max_reqs;
+ u16 product_id;
+ u16 op_req_sz;
+ u16 reply_sz;
+ u16 exceptions;
+ u16 max_perids;
+ u16 max_pds;
+ u16 max_sasexpanders;
+ u16 max_sasinitiators;
+ u16 max_enclosures;
+ u16 max_pcie_switches;
+ u16 max_nvme;
+ u16 max_vds;
+ u16 max_hpds;
+ u16 max_advhpds;
+ u16 max_raidpds;
+ u16 min_devhandle;
+ u16 max_devhandle;
+ u16 max_op_req_q;
+ u16 max_op_reply_q;
+ u16 shutdown_timeout;
+ u8 ioc_num;
+ u8 who_init;
+ u16 max_msix_vectors;
+ u8 personality;
+ u8 dma_mask;
+ u8 protocol_flags;
+ u8 sge_mod_mask;
+ u8 sge_mod_value;
+ u8 sge_mod_shift;
+};
+
+/**
+ * struct segments - memory descriptor structure to store
+ * virtual and dma addresses for operational queue segments.
+ *
+ * @segment: virtual address
+ * @segment_dma: dma address
+ */
+struct segments {
+ void *segment;
+ dma_addr_t segment_dma;
+};
+
+/**
+ * struct op_req_qinfo - Operational Request Queue Information
+ *
+ * @ci: consumer index
+ * @pi: producer index
+ * @num_request: Maximum number of entries in the queue
+ * @qid: Queue Id starting from 1
+ * @reply_qid: Associated reply queue Id
+ * @num_segments: Number of discontiguous memory segments
+ * @segment_qd: Depth of each segments
+ * @q_lock: Concurrent queue access lock
+ * @q_segments: Segment descriptor pointer
+ * @q_segment_list: Segment list base virtual address
+ * @q_segment_list_dma: Segment list base DMA address
+ */
+struct op_req_qinfo {
+ u16 ci;
+ u16 pi;
+ u16 num_requests;
+ u16 qid;
+ u16 reply_qid;
+ u16 num_segments;
+ u16 segment_qd;
+ spinlock_t q_lock;
+ struct segments *q_segments;
+ void *q_segment_list;
+ dma_addr_t q_segment_list_dma;
+};
+
+/**
+ * struct op_reply_qinfo - Operational Reply Queue Information
+ *
+ * @ci: consumer index
+ * @qid: Queue Id starting from 1
+ * @num_replies: Maximum number of entries in the queue
+ * @num_segments: Number of discontiguous memory segments
+ * @segment_qd: Depth of each segments
+ * @q_segments: Segment descriptor pointer
+ * @q_segment_list: Segment list base virtual address
+ * @q_segment_list_dma: Segment list base DMA address
+ * @ephase: Expected phased identifier for the reply queue
+ * @pend_ios: Number of IOs pending in HW for this queue
+ * @enable_irq_poll: Flag to indicate polling is enabled
+ * @in_use: Queue is handled by poll/ISR
+ */
+struct op_reply_qinfo {
+ u16 ci;
+ u16 qid;
+ u16 num_replies;
+ u16 num_segments;
+ u16 segment_qd;
+ struct segments *q_segments;
+ void *q_segment_list;
+ dma_addr_t q_segment_list_dma;
+ u8 ephase;
+ atomic_t pend_ios;
+ bool enable_irq_poll;
+ atomic_t in_use;
+};
+
+/**
+ * struct mpi3mr_intr_info - Interrupt cookie information
+ *
+ * @mrioc: Adapter instance reference
+ * @msix_index: MSIx index
+ * @op_reply_q: Associated operational reply queue
+ * @name: Dev name for the irq claiming device
+ */
+struct mpi3mr_intr_info {
+ struct mpi3mr_ioc *mrioc;
+ u16 msix_index;
+ struct op_reply_qinfo *op_reply_q;
+ char name[MPI3MR_NAME_LENGTH];
+};
+
+/**
+ * struct tgt_dev_sas_sata - SAS/SATA device specific
+ * information cached from firmware given data
+ *
+ * @sas_address: World wide unique SAS address
+ * @dev_info: Device information bits
+ */
+struct tgt_dev_sas_sata {
+ u64 sas_address;
+ u16 dev_info;
+};
+
+/**
+ * struct tgt_dev_pcie - PCIe device specific information cached
+ * from firmware given data
+ *
+ * @mdts: Maximum data transfer size
+ * @capb: Device capabilities
+ * @pgsz: Device page size
+ * @abort_to: Timeout for abort TM
+ * @reset_to: Timeout for Target/LUN reset TM
+ */
+struct tgt_dev_pcie {
+ u32 mdts;
+ u16 capb;
+ u8 pgsz;
+ u8 abort_to;
+ u8 reset_to;
+};
+
+/**
+ * struct tgt_dev_volume - virtual device specific information
+ * cached from firmware given data
+ *
+ * @state: State of the VD
+ */
+struct tgt_dev_volume {
+ u8 state;
+};
+
+/**
+ * union _form_spec_inf - union of device specific information
+ */
+union _form_spec_inf {
+ struct tgt_dev_sas_sata sas_sata_inf;
+ struct tgt_dev_pcie pcie_inf;
+ struct tgt_dev_volume vol_inf;
+};
+
+
+
+/**
+ * struct mpi3mr_tgt_dev - target device data structure
+ *
+ * @list: List pointer
+ * @starget: Scsi_target pointer
+ * @dev_handle: FW device handle
+ * @parent_handle: FW parent device handle
+ * @slot: Slot number
+ * @encl_handle: FW enclosure handle
+ * @perst_id: FW assigned Persistent ID
+ * @dev_type: SAS/SATA/PCIE device type
+ * @is_hidden: Should be exposed to upper layers or not
+ * @host_exposed: Already exposed to host or not
+ * @q_depth: Device specific Queue Depth
+ * @wwid: World wide ID
+ * @dev_spec: Device type specific information
+ * @ref_count: Reference count
+ */
+struct mpi3mr_tgt_dev {
+ struct list_head list;
+ struct scsi_target *starget;
+ u16 dev_handle;
+ u16 parent_handle;
+ u16 slot;
+ u16 encl_handle;
+ u16 perst_id;
+ u8 dev_type;
+ u8 is_hidden;
+ u8 host_exposed;
+ u16 q_depth;
+ u64 wwid;
+ union _form_spec_inf dev_spec;
+ struct kref ref_count;
+};
+
+/**
+ * mpi3mr_tgtdev_get - k reference incrementor
+ * @s: Target device reference
+ *
+ * Increment target device reference count.
+ */
+static inline void mpi3mr_tgtdev_get(struct mpi3mr_tgt_dev *s)
+{
+ kref_get(&s->ref_count);
+}
+
+/**
+ * mpi3mr_free_tgtdev - target device memory dealloctor
+ * @r: k reference pointer of the target device
+ *
+ * Free target device memory when no reference.
+ */
+static inline void mpi3mr_free_tgtdev(struct kref *r)
+{
+ kfree(container_of(r, struct mpi3mr_tgt_dev, ref_count));
+}
+
+/**
+ * mpi3mr_tgtdev_put - k reference decrementor
+ * @s: Target device reference
+ *
+ * Decrement target device reference count.
+ */
+static inline void mpi3mr_tgtdev_put(struct mpi3mr_tgt_dev *s)
+{
+ kref_put(&s->ref_count, mpi3mr_free_tgtdev);
+}
+
+
+/**
+ * struct mpi3mr_stgt_priv_data - SCSI target private structure
+ *
+ * @starget: Scsi_target pointer
+ * @dev_handle: FW device handle
+ * @perst_id: FW assigned Persistent ID
+ * @num_luns: Number of Logical Units
+ * @block_io: I/O blocked to the device or not
+ * @dev_removed: Device removed in the Firmware
+ * @dev_removedelay: Device is waiting to be removed in FW
+ * @dev_type: Device type
+ * @tgt_dev: Internal target device pointer
+ */
+struct mpi3mr_stgt_priv_data {
+ struct scsi_target *starget;
+ u16 dev_handle;
+ u16 perst_id;
+ u32 num_luns;
+ atomic_t block_io;
+ u8 dev_removed;
+ u8 dev_removedelay;
+ u8 dev_type;
+ struct mpi3mr_tgt_dev *tgt_dev;
+};
+
+/**
+ * struct mpi3mr_stgt_priv_data - SCSI device private structure
+ *
+ * @tgt_priv_data: Scsi_target private data pointer
+ * @lun_id: LUN ID of the device
+ * @ncq_prio_enable: NCQ priority enable for SATA device
+ */
+struct mpi3mr_sdev_priv_data {
+ struct mpi3mr_stgt_priv_data *tgt_priv_data;
+ u32 lun_id;
+ u8 ncq_prio_enable;
+};
+
+/**
+ * struct mpi3mr_drv_cmd - Internal command tracker
+ *
+ * @mutex: Command mutex
+ * @done: Completeor for wakeup
+ * @reply: Firmware reply for internal commands
+ * @sensebuf: Sensebuf for SCSI IO commands
+ * @iou_rc: IO Unit control reason code
+ * @state: Command State
+ * @dev_handle: Firmware handle for device specific commands
+ * @ioc_status: IOC status from the firmware
+ * @ioc_loginfo:IOC log info from the firmware
+ * @is_waiting: Is the command issued in block mode
+ * @retry_count: Retry count for retriable commands
+ * @host_tag: Host tag used by the command
+ * @callback: Callback for non blocking commands
+ */
+struct mpi3mr_drv_cmd {
+ struct mutex mutex;
+ struct completion done;
+ void *reply;
+ u8 *sensebuf;
+ u8 iou_rc;
+ u16 state;
+ u16 dev_handle;
+ u16 ioc_status;
+ u32 ioc_loginfo;
+ u8 is_waiting;
+ u8 retry_count;
+ u16 host_tag;
+
+ void (*callback)(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_drv_cmd *drv_cmd);
+};
+
+
+/**
+ * struct chain_element - memory descriptor structure to store
+ * virtual and dma addresses for chain elements.
+ *
+ * @addr: virtual address
+ * @dma_addr: dma address
+ */
+struct chain_element {
+ void *addr;
+ dma_addr_t dma_addr;
+};
+
+/**
+ * struct scmd_priv - SCSI command private data
+ *
+ * @host_tag: Host tag specific to operational queue
+ * @in_lld_scope: Command in LLD scope or not
+ * @meta_sg_valid: DIX command with meta data SGL or not
+ * @scmd: SCSI Command pointer
+ * @req_q_idx: Operational request queue index
+ * @chain_idx: Chain frame index
+ * @meta_chain_idx: Chain frame index of meta data SGL
+ * @mpi3mr_scsiio_req: MPI SCSI IO request
+ */
+struct scmd_priv {
+ u16 host_tag;
+ u8 in_lld_scope;
+ u8 meta_sg_valid;
+ struct scsi_cmnd *scmd;
+ u16 req_q_idx;
+ int chain_idx;
+ int meta_chain_idx;
+ u8 mpi3mr_scsiio_req[MPI3MR_ADMIN_REQ_FRAME_SZ];
+};
+
+/**
+ * struct mpi3mr_ioc - Adapter anchor structure stored in shost
+ * private data
+ *
+ * @list: List pointer
+ * @pdev: PCI device pointer
+ * @shost: Scsi_Host pointer
+ * @id: Controller ID
+ * @cpu_count: Number of online CPUs
+ * @irqpoll_sleep: usleep unit used in threaded isr irqpoll
+ * @name: Controller ASCII name
+ * @driver_name: Driver ASCII name
+ * @sysif_regs: System interface registers virtual address
+ * @sysif_regs_phys: System interface registers physical address
+ * @bars: PCI BARS
+ * @dma_mask: DMA mask
+ * @msix_count: Number of MSIX vectors used
+ * @intr_enabled: Is interrupts enabled
+ * @num_admin_req: Number of admin requests
+ * @admin_req_q_sz: Admin request queue size
+ * @admin_req_pi: Admin request queue producer index
+ * @admin_req_ci: Admin request queue consumer index
+ * @admin_req_base: Admin request queue base virtual address
+ * @admin_req_dma: Admin request queue base dma address
+ * @admin_req_lock: Admin queue access lock
+ * @num_admin_replies: Number of admin replies
+ * @admin_reply_q_sz: Admin reply queue size
+ * @admin_reply_ci: Admin reply queue consumer index
+ * @admin_reply_ephase:Admin reply queue expected phase
+ * @admin_reply_base: Admin reply queue base virtual address
+ * @admin_reply_dma: Admin reply queue base dma address
+ * @ready_timeout: Controller ready timeout
+ * @intr_info: Interrupt cookie pointer
+ * @intr_info_count: Number of interrupt cookies
+ * @num_queues: Number of operational queues
+ * @num_op_req_q: Number of operational request queues
+ * @req_qinfo: Operational request queue info pointer
+ * @num_op_reply_q: Number of operational reply queues
+ * @op_reply_qinfo: Operational reply queue info pointer
+ * @init_cmds: Command tracker for initialization commands
+ * @facts: Cached IOC facts data
+ * @op_reply_desc_sz: Operational reply descriptor size
+ * @num_reply_bufs: Number of reply buffers allocated
+ * @reply_buf_pool: Reply buffer pool
+ * @reply_buf: Reply buffer base virtual address
+ * @reply_buf_dma: Reply buffer DMA address
+ * @reply_buf_dma_max_address: Reply DMA address max limit
+ * @reply_free_qsz: Reply free queue size
+ * @reply_free_q_pool: Reply free queue pool
+ * @reply_free_q: Reply free queue base virtual address
+ * @reply_free_q_dma: Reply free queue base DMA address
+ * @reply_free_queue_lock: Reply free queue lock
+ * @reply_free_queue_host_index: Reply free queue host index
+ * @num_sense_bufs: Number of sense buffers
+ * @sense_buf_pool: Sense buffer pool
+ * @sense_buf: Sense buffer base virtual address
+ * @sense_buf_dma: Sense buffer base DMA address
+ * @sense_buf_q_sz: Sense buffer queue size
+ * @sense_buf_q_pool: Sense buffer queue pool
+ * @sense_buf_q: Sense buffer queue virtual address
+ * @sense_buf_q_dma: Sense buffer queue DMA address
+ * @sbq_lock: Sense buffer queue lock
+ * @sbq_host_index: Sense buffer queuehost index
+ * @event_masks: Event mask bitmap
+ * @fwevt_worker_name: Firmware event worker thread name
+ * @fwevt_worker_thread: Firmware event worker thread
+ * @fwevt_lock: Firmware event lock
+ * @fwevt_list: Firmware event list
+ * @watchdog_work_q_name: Fault watchdog worker thread name
+ * @watchdog_work_q: Fault watchdog worker thread
+ * @watchdog_work: Fault watchdog work
+ * @watchdog_lock: Fault watchdog lock
+ * @is_driver_loading: Is driver still loading
+ * @scan_started: Async scan started
+ * @scan_failed: Asycn scan failed
+ * @stop_drv_processing: Stop all command processing
+ * @max_host_ios: Maximum host I/O count
+ * @chain_buf_count: Chain buffer count
+ * @chain_buf_pool: Chain buffer pool
+ * @chain_sgl_list: Chain SGL list
+ * @chain_bitmap_sz: Chain buffer allocator bitmap size
+ * @chain_bitmap: Chain buffer allocator bitmap
+ * @chain_buf_lock: Chain buffer list lock
+ * @host_tm_cmds: Command tracker for task management commands
+ * @dev_rmhs_cmds: Command tracker for device removal commands
+ * @devrem_bitmap_sz: Device removal bitmap size
+ * @devrem_bitmap: Device removal bitmap
+ * @dev_handle_bitmap_sz: Device handle bitmap size
+ * @removepend_bitmap: Remove pending bitmap
+ * @delayed_rmhs_list: Delayed device removal list
+ * @ts_update_counter: Timestamp update counter
+ * @fault_dbg: Fault debug flag
+ * @reset_in_progress: Reset in progress flag
+ * @unrecoverable: Controller unrecoverable flag
+ * @reset_mutex: Controller reset mutex
+ * @reset_waitq: Controller reset wait queue
+ * @diagsave_timeout: Diagnostic information save timeout
+ * @logging_level: Controller debug logging level
+ * @flush_io_count: I/O count to flush after reset
+ * @current_event: Firmware event currently in process
+ * @driver_info: Driver, Kernel, OS information to firmware
+ * @change_count: Topology change count
+ * @op_reply_q_offset: Operational reply queue offset with MSIx
+ */
+struct mpi3mr_ioc {
+ struct list_head list;
+ struct pci_dev *pdev;
+ struct Scsi_Host *shost;
+ u8 id;
+ int cpu_count;
+ bool enable_segqueue;
+ u32 irqpoll_sleep;
+
+ char name[MPI3MR_NAME_LENGTH];
+ char driver_name[MPI3MR_NAME_LENGTH];
+
+ volatile struct mpi3_sysif_registers __iomem *sysif_regs;
+ resource_size_t sysif_regs_phys;
+ int bars;
+ u64 dma_mask;
+
+ u16 msix_count;
+ u8 intr_enabled;
+
+ u16 num_admin_req;
+ u32 admin_req_q_sz;
+ u16 admin_req_pi;
+ u16 admin_req_ci;
+ void *admin_req_base;
+ dma_addr_t admin_req_dma;
+ spinlock_t admin_req_lock;
+
+ u16 num_admin_replies;
+ u32 admin_reply_q_sz;
+ u16 admin_reply_ci;
+ u8 admin_reply_ephase;
+ void *admin_reply_base;
+ dma_addr_t admin_reply_dma;
+
+ u32 ready_timeout;
+
+ struct mpi3mr_intr_info *intr_info;
+ u16 intr_info_count;
+
+ u16 num_queues;
+ u16 num_op_req_q;
+ struct op_req_qinfo *req_qinfo;
+
+ u16 num_op_reply_q;
+ struct op_reply_qinfo *op_reply_qinfo;
+
+ struct mpi3mr_drv_cmd init_cmds;
+ struct mpi3mr_ioc_facts facts;
+ u16 op_reply_desc_sz;
+
+ u32 num_reply_bufs;
+ struct dma_pool *reply_buf_pool;
+ u8 *reply_buf;
+ dma_addr_t reply_buf_dma;
+ dma_addr_t reply_buf_dma_max_address;
+
+ u16 reply_free_qsz;
+ struct dma_pool *reply_free_q_pool;
+ __le64 *reply_free_q;
+ dma_addr_t reply_free_q_dma;
+ spinlock_t reply_free_queue_lock;
+ u32 reply_free_queue_host_index;
+
+ u32 num_sense_bufs;
+ struct dma_pool *sense_buf_pool;
+ u8 *sense_buf;
+ dma_addr_t sense_buf_dma;
+
+ u16 sense_buf_q_sz;
+ struct dma_pool *sense_buf_q_pool;
+ __le64 *sense_buf_q;
+ dma_addr_t sense_buf_q_dma;
+ spinlock_t sbq_lock;
+ u32 sbq_host_index;
+ u32 event_masks[MPI3_EVENT_NOTIFY_EVENTMASK_WORDS];
+
+ char fwevt_worker_name[MPI3MR_NAME_LENGTH];
+ struct workqueue_struct *fwevt_worker_thread;
+ spinlock_t fwevt_lock;
+ struct list_head fwevt_list;
+
+ char watchdog_work_q_name[20];
+ struct workqueue_struct *watchdog_work_q;
+ struct delayed_work watchdog_work;
+ spinlock_t watchdog_lock;
+
+ u8 is_driver_loading;
+ u8 scan_started;
+ u16 scan_failed;
+ u8 stop_drv_processing;
+
+ u16 max_host_ios;
+ spinlock_t tgtdev_lock;
+ struct list_head tgtdev_list;
+
+ u32 chain_buf_count;
+ struct dma_pool *chain_buf_pool;
+ struct chain_element *chain_sgl_list;
+ u16 chain_bitmap_sz;
+ void *chain_bitmap;
+ spinlock_t chain_buf_lock;
+
+ struct mpi3mr_drv_cmd host_tm_cmds;
+ struct mpi3mr_drv_cmd dev_rmhs_cmds[MPI3MR_NUM_DEVRMCMD];
+ u16 devrem_bitmap_sz;
+ void *devrem_bitmap;
+ u16 dev_handle_bitmap_sz;
+ void *removepend_bitmap;
+ struct list_head delayed_rmhs_list;
+
+ u32 ts_update_counter;
+ u8 fault_dbg;
+ u8 reset_in_progress;
+ u8 unrecoverable;
+ struct mutex reset_mutex;
+ wait_queue_head_t reset_waitq;
+
+ u16 diagsave_timeout;
+ int logging_level;
+ u16 flush_io_count;
+
+ struct mpi3mr_fwevt *current_event;
+ struct mpi3_driver_info_layout driver_info;
+ u16 change_count;
+ u16 op_reply_q_offset;
+};
+
+/**
+ * struct mpi3mr_fwevt - Firmware event structure.
+ *
+ * @list: list head
+ * @work: Work structure
+ * @mrioc: Adapter instance reference
+ * @event_id: MPI3 firmware event ID
+ * @send_ack: Event acknowledgment required or not
+ * @process_evt: Bottomhalf processing required or not
+ * @evt_ctx: Event context to send in Ack
+ * @ref_count: kref count
+ * @event_data: Actual MPI3 event data
+ */
+struct mpi3mr_fwevt {
+ struct list_head list;
+ struct work_struct work;
+ struct mpi3mr_ioc *mrioc;
+ u16 event_id;
+ bool send_ack;
+ bool process_evt;
+ u32 evt_ctx;
+ struct kref ref_count;
+ char event_data[0] __aligned(4);
+};
+
+
+/**
+ * struct delayed_dev_rmhs_node - Delayed device removal node
+ *
+ * @list: list head
+ * @handle: Device handle
+ * @iou_rc: IO Unit Control Reason Code
+ */
+struct delayed_dev_rmhs_node {
+ struct list_head list;
+ u16 handle;
+ u8 iou_rc;
+};
+
+int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc);
+void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc);
+int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 re_init);
+void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc, u8 re_init);
+int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async);
+int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
+u16 admin_req_sz, u8 ignore_reset);
+int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
+ struct op_req_qinfo *opreqq, u8 *req);
+void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length,
+ dma_addr_t dma_addr);
+void mpi3mr_build_zero_len_sge(void *paddr);
+void *mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc,
+ dma_addr_t phys_addr);
+void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc,
+ dma_addr_t phys_addr);
+void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc,
+ u64 sense_buf_dma);
+
+void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
+ struct mpi3_event_notification_reply *event_reply);
+void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc,
+ struct mpi3_default_reply_descriptor *reply_desc,
+ u64 *reply_dma, u16 qidx);
+void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc);
+void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc);
+
+int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
+ u32 reset_reason, u8 snapdump);
+int mpi3mr_diagfault_reset_handler(struct mpi3mr_ioc *mrioc,
+ u32 reset_reason);
+void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc);
+void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc);
+
+enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc);
+int mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
+ u32 event_ctx);
+
+void mpi3mr_wait_for_host_io(struct mpi3mr_ioc *mrioc, u32 timeout);
+void mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc *mrioc);
+void mpi3mr_flush_host_io(struct mpi3mr_ioc *mrioc);
+void mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc);
+void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc);
+void mpi3mr_flush_delayed_rmhs_list(struct mpi3mr_ioc *mrioc);
+
+#endif /*MPI3MR_H_INCLUDED*/
diff --git a/drivers/scsi/mpi3mr/mpi3mr_debug.h b/drivers/scsi/mpi3mr/mpi3mr_debug.h
new file mode 100644
index 000000000000..c085bb048d41
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi3mr_debug.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Driver for Broadcom MPI3 Storage Controllers
+ *
+ * Copyright (C) 2017-2021 Broadcom Inc.
+ * (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
+ *
+ */
+
+#ifndef MPI3SAS_DEBUG_H_INCLUDED
+
+#define MPI3SAS_DEBUG_H_INCLUDED
+
+/*
+ * debug levels
+ */
+#define MPI3_DEBUG 0x00000001
+#define MPI3_DEBUG_MSG_FRAME 0x00000002
+#define MPI3_DEBUG_SG 0x00000004
+#define MPI3_DEBUG_EVENTS 0x00000008
+#define MPI3_DEBUG_EVENT_WORK_TASK 0x00000010
+#define MPI3_DEBUG_INIT 0x00000020
+#define MPI3_DEBUG_EXIT 0x00000040
+#define MPI3_DEBUG_FAIL 0x00000080
+#define MPI3_DEBUG_TM 0x00000100
+#define MPI3_DEBUG_REPLY 0x00000200
+#define MPI3_DEBUG_HANDSHAKE 0x00000400
+#define MPI3_DEBUG_CONFIG 0x00000800
+#define MPI3_DEBUG_DL 0x00001000
+#define MPI3_DEBUG_RESET 0x00002000
+#define MPI3_DEBUG_SCSI 0x00004000
+#define MPI3_DEBUG_IOCTL 0x00008000
+#define MPI3_DEBUG_CSMISAS 0x00010000
+#define MPI3_DEBUG_SAS 0x00020000
+#define MPI3_DEBUG_TRANSPORT 0x00040000
+#define MPI3_DEBUG_TASK_SET_FULL 0x00080000
+#define MPI3_DEBUG_TRIGGER_DIAG 0x00200000
+
+
+/*
+ * debug macros
+ */
+
+#define ioc_err(ioc, fmt, ...) \
+ pr_err("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
+#define ioc_notice(ioc, fmt, ...) \
+ pr_notice("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
+#define ioc_warn(ioc, fmt, ...) \
+ pr_warn("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
+#define ioc_info(ioc, fmt, ...) \
+ pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__)
+
+
+#define dbgprint(IOC, FMT, ...) \
+ do { \
+ if (IOC->logging_level & MPI3_DEBUG) \
+ pr_info("%s: " FMT, (IOC)->name, ##__VA_ARGS__); \
+ } while (0)
+
+#endif /* MPT3SAS_DEBUG_H_INCLUDED */
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
new file mode 100644
index 000000000000..2dba2b0af166
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -0,0 +1,3957 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Broadcom MPI3 Storage Controllers
+ *
+ * Copyright (C) 2017-2021 Broadcom Inc.
+ * (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
+ *
+ */
+
+#include "mpi3mr.h"
+#include <linux/io-64-nonatomic-lo-hi.h>
+
+#if defined(writeq) && defined(CONFIG_64BIT)
+static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
+{
+ writeq(b, addr);
+}
+#else
+static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
+{
+ __u64 data_out = b;
+
+ writel((u32)(data_out), addr);
+ writel((u32)(data_out >> 32), (addr + 4));
+}
+#endif
+
+static inline bool
+mpi3mr_check_req_qfull(struct op_req_qinfo *op_req_q)
+{
+ u16 pi, ci, max_entries;
+ bool is_qfull = false;
+
+ pi = op_req_q->pi;
+ ci = READ_ONCE(op_req_q->ci);
+ max_entries = op_req_q->num_requests;
+
+ if ((ci == (pi + 1)) || ((!ci) && (pi == (max_entries - 1))))
+ is_qfull = true;
+
+ return is_qfull;
+}
+
+static void mpi3mr_sync_irqs(struct mpi3mr_ioc *mrioc)
+{
+ u16 i, max_vectors;
+
+ max_vectors = mrioc->intr_info_count;
+
+ for (i = 0; i < max_vectors; i++)
+ synchronize_irq(pci_irq_vector(mrioc->pdev, i));
+}
+
+void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc)
+{
+ mrioc->intr_enabled = 0;
+ mpi3mr_sync_irqs(mrioc);
+}
+
+void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc)
+{
+ mrioc->intr_enabled = 1;
+}
+
+static void mpi3mr_cleanup_isr(struct mpi3mr_ioc *mrioc)
+{
+ u16 i;
+
+ mpi3mr_ioc_disable_intr(mrioc);
+
+ if (!mrioc->intr_info)
+ return;
+
+ for (i = 0; i < mrioc->intr_info_count; i++)
+ free_irq(pci_irq_vector(mrioc->pdev, i),
+ (mrioc->intr_info + i));
+
+ kfree(mrioc->intr_info);
+ mrioc->intr_info = NULL;
+ mrioc->intr_info_count = 0;
+ pci_free_irq_vectors(mrioc->pdev);
+}
+
+void mpi3mr_add_sg_single(void *paddr, u8 flags, u32 length,
+ dma_addr_t dma_addr)
+{
+ struct mpi3_sge_common *sgel = paddr;
+
+ sgel->flags = flags;
+ sgel->length = cpu_to_le32(length);
+ sgel->address = cpu_to_le64(dma_addr);
+}
+
+void mpi3mr_build_zero_len_sge(void *paddr)
+{
+ u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
+
+ mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1);
+}
+
+void *mpi3mr_get_reply_virt_addr(struct mpi3mr_ioc *mrioc,
+ dma_addr_t phys_addr)
+{
+ if (!phys_addr)
+ return NULL;
+
+ if ((phys_addr < mrioc->reply_buf_dma) ||
+ (phys_addr > mrioc->reply_buf_dma_max_address))
+ return NULL;
+
+ return mrioc->reply_buf + (phys_addr - mrioc->reply_buf_dma);
+}
+
+void *mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_ioc *mrioc,
+ dma_addr_t phys_addr)
+{
+ if (!phys_addr)
+ return NULL;
+
+ return mrioc->sense_buf + (phys_addr - mrioc->sense_buf_dma);
+}
+
+static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc,
+ u64 reply_dma)
+{
+ u32 old_idx = 0;
+
+ spin_lock(&mrioc->reply_free_queue_lock);
+ old_idx = mrioc->reply_free_queue_host_index;
+ mrioc->reply_free_queue_host_index = (
+ (mrioc->reply_free_queue_host_index ==
+ (mrioc->reply_free_qsz - 1)) ? 0 :
+ (mrioc->reply_free_queue_host_index + 1));
+ mrioc->reply_free_q[old_idx] = cpu_to_le64(reply_dma);
+ writel(mrioc->reply_free_queue_host_index,
+ &mrioc->sysif_regs->reply_free_host_index);
+ spin_unlock(&mrioc->reply_free_queue_lock);
+}
+
+void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc,
+ u64 sense_buf_dma)
+{
+ u32 old_idx = 0;
+
+ spin_lock(&mrioc->sbq_lock);
+ old_idx = mrioc->sbq_host_index;
+ mrioc->sbq_host_index = ((mrioc->sbq_host_index ==
+ (mrioc->sense_buf_q_sz - 1)) ? 0 :
+ (mrioc->sbq_host_index + 1));
+ mrioc->sense_buf_q[old_idx] = cpu_to_le64(sense_buf_dma);
+ writel(mrioc->sbq_host_index,
+ &mrioc->sysif_regs->sense_buffer_free_host_index);
+ spin_unlock(&mrioc->sbq_lock);
+}
+
+static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc,
+ struct mpi3_event_notification_reply *event_reply)
+{
+ char *desc = NULL;
+ u16 event;
+
+ event = event_reply->event;
+
+ switch (event) {
+ case MPI3_EVENT_LOG_DATA:
+ desc = "Log Data";
+ break;
+ case MPI3_EVENT_CHANGE:
+ desc = "Event Change";
+ break;
+ case MPI3_EVENT_GPIO_INTERRUPT:
+ desc = "GPIO Interrupt";
+ break;
+ case MPI3_EVENT_TEMP_THRESHOLD:
+ desc = "Temperature Threshold";
+ break;
+ case MPI3_EVENT_CABLE_MGMT:
+ desc = "Cable Management";
+ break;
+ case MPI3_EVENT_ENERGY_PACK_CHANGE:
+ desc = "Energy Pack Change";
+ break;
+ case MPI3_EVENT_DEVICE_ADDED:
+ {
+ struct mpi3_device_page0 *event_data =
+ (struct mpi3_device_page0 *)event_reply->event_data;
+ ioc_info(mrioc, "Device Added: dev=0x%04x Form=0x%x\n",
+ event_data->dev_handle, event_data->device_form);
+ return;
+ }
+ case MPI3_EVENT_DEVICE_INFO_CHANGED:
+ {
+ struct mpi3_device_page0 *event_data =
+ (struct mpi3_device_page0 *)event_reply->event_data;
+ ioc_info(mrioc, "Device Info Changed: dev=0x%04x Form=0x%x\n",
+ event_data->dev_handle, event_data->device_form);
+ return;
+ }
+ case MPI3_EVENT_DEVICE_STATUS_CHANGE:
+ {
+ struct mpi3_event_data_device_status_change *event_data =
+ (struct mpi3_event_data_device_status_change *)event_reply->event_data;
+ ioc_info(mrioc, "Device status Change: dev=0x%04x RC=0x%x\n",
+ event_data->dev_handle, event_data->reason_code);
+ return;
+ }
+ case MPI3_EVENT_SAS_DISCOVERY:
+ {
+ struct mpi3_event_data_sas_discovery *event_data =
+ (struct mpi3_event_data_sas_discovery *)event_reply->event_data;
+ ioc_info(mrioc, "SAS Discovery: (%s) status (0x%08x)\n",
+ (event_data->reason_code == MPI3_EVENT_SAS_DISC_RC_STARTED) ?
+ "start" : "stop",
+ le32_to_cpu(event_data->discovery_status));
+ return;
+ }
+ case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
+ desc = "SAS Broadcast Primitive";
+ break;
+ case MPI3_EVENT_SAS_NOTIFY_PRIMITIVE:
+ desc = "SAS Notify Primitive";
+ break;
+ case MPI3_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
+ desc = "SAS Init Device Status Change";
+ break;
+ case MPI3_EVENT_SAS_INIT_TABLE_OVERFLOW:
+ desc = "SAS Init Table Overflow";
+ break;
+ case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
+ desc = "SAS Topology Change List";
+ break;
+ case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
+ desc = "Enclosure Device Status Change";
+ break;
+ case MPI3_EVENT_HARD_RESET_RECEIVED:
+ desc = "Hard Reset Received";
+ break;
+ case MPI3_EVENT_SAS_PHY_COUNTER:
+ desc = "SAS PHY Counter";
+ break;
+ case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
+ desc = "SAS Device Discovery Error";
+ break;
+ case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
+ desc = "PCIE Topology Change List";
+ break;
+ case MPI3_EVENT_PCIE_ENUMERATION:
+ {
+ struct mpi3_event_data_pcie_enumeration *event_data =
+ (struct mpi3_event_data_pcie_enumeration *)event_reply->event_data;
+ ioc_info(mrioc, "PCIE Enumeration: (%s)",
+ (event_data->reason_code ==
+ MPI3_EVENT_PCIE_ENUM_RC_STARTED) ? "start" : "stop");
+ if (event_data->enumeration_status)
+ ioc_info(mrioc, "enumeration_status(0x%08x)\n",
+ le32_to_cpu(event_data->enumeration_status));
+ return;
+ }
+ case MPI3_EVENT_PREPARE_FOR_RESET:
+ desc = "Prepare For Reset";
+ break;
+ }
+
+ if (!desc)
+ return;
+
+ ioc_info(mrioc, "%s\n", desc);
+}
+
+static void mpi3mr_handle_events(struct mpi3mr_ioc *mrioc,
+ struct mpi3_default_reply *def_reply)
+{
+ struct mpi3_event_notification_reply *event_reply =
+ (struct mpi3_event_notification_reply *)def_reply;
+
+ mrioc->change_count = le16_to_cpu(event_reply->ioc_change_count);
+ mpi3mr_print_event_data(mrioc, event_reply);
+ mpi3mr_os_handle_events(mrioc, event_reply);
+}
+
+static struct mpi3mr_drv_cmd *
+mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
+ struct mpi3_default_reply *def_reply)
+{
+ u16 idx;
+
+ switch (host_tag) {
+ case MPI3MR_HOSTTAG_INITCMDS:
+ return &mrioc->init_cmds;
+ case MPI3MR_HOSTTAG_BLK_TMS:
+ return &mrioc->host_tm_cmds;
+ case MPI3MR_HOSTTAG_INVALID:
+ if (def_reply && def_reply->function ==
+ MPI3_FUNCTION_EVENT_NOTIFICATION)
+ mpi3mr_handle_events(mrioc, def_reply);
+ return NULL;
+ default:
+ break;
+ }
+ if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN &&
+ host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX) {
+ idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
+ return &mrioc->dev_rmhs_cmds[idx];
+ }
+
+ return NULL;
+}
+
+static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
+ struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma)
+{
+ u16 reply_desc_type, host_tag = 0;
+ u16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
+ u32 ioc_loginfo = 0;
+ struct mpi3_status_reply_descriptor *status_desc;
+ struct mpi3_address_reply_descriptor *addr_desc;
+ struct mpi3_success_reply_descriptor *success_desc;
+ struct mpi3_default_reply *def_reply = NULL;
+ struct mpi3mr_drv_cmd *cmdptr = NULL;
+ struct mpi3_scsi_io_reply *scsi_reply;
+ u8 *sense_buf = NULL;
+
+ *reply_dma = 0;
+ reply_desc_type = le16_to_cpu(reply_desc->reply_flags) &
+ MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
+ switch (reply_desc_type) {
+ case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
+ status_desc = (struct mpi3_status_reply_descriptor *)reply_desc;
+ host_tag = le16_to_cpu(status_desc->host_tag);
+ ioc_status = le16_to_cpu(status_desc->ioc_status);
+ if (ioc_status &
+ MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
+ ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info);
+ ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
+ break;
+ case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
+ addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc;
+ *reply_dma = le64_to_cpu(addr_desc->reply_frame_address);
+ def_reply = mpi3mr_get_reply_virt_addr(mrioc, *reply_dma);
+ if (!def_reply)
+ goto out;
+ host_tag = le16_to_cpu(def_reply->host_tag);
+ ioc_status = le16_to_cpu(def_reply->ioc_status);
+ if (ioc_status &
+ MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
+ ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info);
+ ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
+ if (def_reply->function == MPI3_FUNCTION_SCSI_IO) {
+ scsi_reply = (struct mpi3_scsi_io_reply *)def_reply;
+ sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc,
+ le64_to_cpu(scsi_reply->sense_data_buffer_address));
+ }
+ break;
+ case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
+ success_desc = (struct mpi3_success_reply_descriptor *)reply_desc;
+ host_tag = le16_to_cpu(success_desc->host_tag);
+ break;
+ default:
+ break;
+ }
+
+ cmdptr = mpi3mr_get_drv_cmd(mrioc, host_tag, def_reply);
+ if (cmdptr) {
+ if (cmdptr->state & MPI3MR_CMD_PENDING) {
+ cmdptr->state |= MPI3MR_CMD_COMPLETE;
+ cmdptr->ioc_loginfo = ioc_loginfo;
+ cmdptr->ioc_status = ioc_status;
+ cmdptr->state &= ~MPI3MR_CMD_PENDING;
+ if (def_reply) {
+ cmdptr->state |= MPI3MR_CMD_REPLY_VALID;
+ memcpy((u8 *)cmdptr->reply, (u8 *)def_reply,
+ mrioc->facts.reply_sz);
+ }
+ if (cmdptr->is_waiting) {
+ complete(&cmdptr->done);
+ cmdptr->is_waiting = 0;
+ } else if (cmdptr->callback)
+ cmdptr->callback(mrioc, cmdptr);
+ }
+ }
+out:
+ if (sense_buf)
+ mpi3mr_repost_sense_buf(mrioc,
+ le64_to_cpu(scsi_reply->sense_data_buffer_address));
+}
+
+static int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
+{
+ u32 exp_phase = mrioc->admin_reply_ephase;
+ u32 admin_reply_ci = mrioc->admin_reply_ci;
+ u32 num_admin_replies = 0;
+ u64 reply_dma = 0;
+ struct mpi3_default_reply_descriptor *reply_desc;
+
+ reply_desc = (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
+ admin_reply_ci;
+
+ if ((le16_to_cpu(reply_desc->reply_flags) &
+ MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
+ return 0;
+
+ do {
+ mrioc->admin_req_ci = le16_to_cpu(reply_desc->request_queue_ci);
+ mpi3mr_process_admin_reply_desc(mrioc, reply_desc, &reply_dma);
+ if (reply_dma)
+ mpi3mr_repost_reply_buf(mrioc, reply_dma);
+ num_admin_replies++;
+ if (++admin_reply_ci == mrioc->num_admin_replies) {
+ admin_reply_ci = 0;
+ exp_phase ^= 1;
+ }
+ reply_desc =
+ (struct mpi3_default_reply_descriptor *)mrioc->admin_reply_base +
+ admin_reply_ci;
+ if ((le16_to_cpu(reply_desc->reply_flags) &
+ MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
+ break;
+ } while (1);
+
+ writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
+ mrioc->admin_reply_ci = admin_reply_ci;
+ mrioc->admin_reply_ephase = exp_phase;
+
+ return num_admin_replies;
+}
+
+/**
+ * mpi3mr_get_reply_desc - get reply descriptor frame corresponding to
+ * queue's consumer index from operational reply descriptor queue.
+ * @op_reply_q: op_reply_qinfo object
+ * @reply_ci: operational reply descriptor's queue consumer index
+ *
+ * Returns reply descriptor frame address
+ */
+static inline struct mpi3_default_reply_descriptor *
+mpi3mr_get_reply_desc(struct op_reply_qinfo *op_reply_q, u32 reply_ci)
+{
+ void *segment_base_addr;
+ struct segments *segments = op_reply_q->q_segments;
+ struct mpi3_default_reply_descriptor *reply_desc = NULL;
+
+ segment_base_addr =
+ segments[reply_ci / op_reply_q->segment_qd].segment;
+ reply_desc = (struct mpi3_default_reply_descriptor *)segment_base_addr +
+ (reply_ci % op_reply_q->segment_qd);
+ return reply_desc;
+}
+
+static int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_intr_info *intr_info)
+{
+ struct op_reply_qinfo *op_reply_q = intr_info->op_reply_q;
+ struct op_req_qinfo *op_req_q;
+ u32 exp_phase;
+ u32 reply_ci;
+ u32 num_op_reply = 0;
+ u64 reply_dma = 0;
+ struct mpi3_default_reply_descriptor *reply_desc;
+ u16 req_q_idx = 0, reply_qidx;
+
+ reply_qidx = op_reply_q->qid - 1;
+
+ if (!atomic_add_unless(&op_reply_q->in_use, 1, 1))
+ return 0;
+
+ exp_phase = op_reply_q->ephase;
+ reply_ci = op_reply_q->ci;
+
+ reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
+ if ((le16_to_cpu(reply_desc->reply_flags) &
+ MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) {
+ atomic_dec(&op_reply_q->in_use);
+ return 0;
+ }
+
+ do {
+ req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1;
+ op_req_q = &mrioc->req_qinfo[req_q_idx];
+
+ WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci));
+ mpi3mr_process_op_reply_desc(mrioc, reply_desc, &reply_dma,
+ reply_qidx);
+ atomic_dec(&op_reply_q->pend_ios);
+ if (reply_dma)
+ mpi3mr_repost_reply_buf(mrioc, reply_dma);
+ num_op_reply++;
+
+ if (++reply_ci == op_reply_q->num_replies) {
+ reply_ci = 0;
+ exp_phase ^= 1;
+ }
+
+ reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
+
+ if ((le16_to_cpu(reply_desc->reply_flags) &
+ MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
+ break;
+ /*
+ * Exit completion loop to avoid CPU lockup
+ * Ensure remaining completion happens from threaded ISR.
+ */
+ if (num_op_reply > mrioc->max_host_ios) {
+ intr_info->op_reply_q->enable_irq_poll = true;
+ break;
+ }
+
+ } while (1);
+
+ writel(reply_ci,
+ &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index);
+ op_reply_q->ci = reply_ci;
+ op_reply_q->ephase = exp_phase;
+
+ atomic_dec(&op_reply_q->in_use);
+ return num_op_reply;
+}
+
+static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata)
+{
+ struct mpi3mr_intr_info *intr_info = privdata;
+ struct mpi3mr_ioc *mrioc;
+ u16 midx;
+ u32 num_admin_replies = 0, num_op_reply = 0;
+
+ if (!intr_info)
+ return IRQ_NONE;
+
+ mrioc = intr_info->mrioc;
+
+ if (!mrioc->intr_enabled)
+ return IRQ_NONE;
+
+ midx = intr_info->msix_index;
+
+ if (!midx)
+ num_admin_replies = mpi3mr_process_admin_reply_q(mrioc);
+ if (intr_info->op_reply_q)
+ num_op_reply = mpi3mr_process_op_reply_q(mrioc, intr_info);
+
+ if (num_admin_replies || num_op_reply)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
+}
+
+static irqreturn_t mpi3mr_isr(int irq, void *privdata)
+{
+ struct mpi3mr_intr_info *intr_info = privdata;
+ struct mpi3mr_ioc *mrioc;
+ u16 midx;
+ int ret;
+
+ if (!intr_info)
+ return IRQ_NONE;
+
+ mrioc = intr_info->mrioc;
+ midx = intr_info->msix_index;
+ /* Call primary ISR routine */
+ ret = mpi3mr_isr_primary(irq, privdata);
+
+ /*
+ * If more IOs are expected, schedule IRQ polling thread.
+ * Otherwise exit from ISR.
+ */
+ if (!intr_info->op_reply_q)
+ return ret;
+
+ if (!intr_info->op_reply_q->enable_irq_poll ||
+ !atomic_read(&intr_info->op_reply_q->pend_ios))
+ return ret;
+
+ disable_irq_nosync(pci_irq_vector(mrioc->pdev, midx));
+
+ return IRQ_WAKE_THREAD;
+}
+
+/**
+ * mpi3mr_isr_poll - Reply queue polling routine
+ * @irq: IRQ
+ * @privdata: Interrupt info
+ *
+ * poll for pending I/O completions in a loop until pending I/Os
+ * present or controller queue depth I/Os are processed.
+ *
+ * Return: IRQ_NONE or IRQ_HANDLED
+ */
+static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata)
+{
+ struct mpi3mr_intr_info *intr_info = privdata;
+ struct mpi3mr_ioc *mrioc;
+ u16 midx;
+ u32 num_op_reply = 0;
+
+ if (!intr_info || !intr_info->op_reply_q)
+ return IRQ_NONE;
+
+ mrioc = intr_info->mrioc;
+ midx = intr_info->msix_index;
+
+ /* Poll for pending IOs completions */
+ do {
+ if (!mrioc->intr_enabled)
+ break;
+
+ if (!midx)
+ mpi3mr_process_admin_reply_q(mrioc);
+ if (intr_info->op_reply_q)
+ num_op_reply +=
+ mpi3mr_process_op_reply_q(mrioc, intr_info);
+
+ usleep_range(mrioc->irqpoll_sleep, 10 * mrioc->irqpoll_sleep);
+
+ } while (atomic_read(&intr_info->op_reply_q->pend_ios) &&
+ (num_op_reply < mrioc->max_host_ios));
+
+ intr_info->op_reply_q->enable_irq_poll = false;
+ enable_irq(pci_irq_vector(mrioc->pdev, midx));
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * mpi3mr_request_irq - Request IRQ and register ISR
+ * @mrioc: Adapter instance reference
+ * @index: IRQ vector index
+ *
+ * Request threaded ISR with primary ISR and secondary
+ *
+ * Return: 0 on success and non zero on failures.
+ */
+static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index)
+{
+ struct pci_dev *pdev = mrioc->pdev;
+ struct mpi3mr_intr_info *intr_info = mrioc->intr_info + index;
+ int retval = 0;
+
+ intr_info->mrioc = mrioc;
+ intr_info->msix_index = index;
+ intr_info->op_reply_q = NULL;
+
+ snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d",
+ mrioc->driver_name, mrioc->id, index);
+
+ retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr,
+ mpi3mr_isr_poll, IRQF_SHARED, intr_info->name, intr_info);
+ if (retval) {
+ ioc_err(mrioc, "%s: Unable to allocate interrupt %d!\n",
+ intr_info->name, pci_irq_vector(pdev, index));
+ return retval;
+ }
+
+ return retval;
+}
+
+/**
+ * mpi3mr_setup_isr - Setup ISR for the controller
+ * @mrioc: Adapter instance reference
+ * @setup_one: Request one IRQ or more
+ *
+ * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR
+ *
+ * Return: 0 on success and non zero on failures.
+ */
+static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one)
+{
+ unsigned int irq_flags = PCI_IRQ_MSIX;
+ int max_vectors;
+ int retval;
+ int i;
+ struct irq_affinity desc = { .pre_vectors = 1};
+
+ mpi3mr_cleanup_isr(mrioc);
+
+ if (setup_one || reset_devices)
+ max_vectors = 1;
+ else {
+ max_vectors =
+ min_t(int, mrioc->cpu_count + 1, mrioc->msix_count);
+
+ ioc_info(mrioc,
+ "MSI-X vectors supported: %d, no of cores: %d,",
+ mrioc->msix_count, mrioc->cpu_count);
+ ioc_info(mrioc,
+ "MSI-x vectors requested: %d\n", max_vectors);
+ }
+
+ irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES;
+
+ mrioc->op_reply_q_offset = (max_vectors > 1) ? 1 : 0;
+ retval = pci_alloc_irq_vectors_affinity(mrioc->pdev,
+ 1, max_vectors, irq_flags, &desc);
+ if (retval < 0) {
+ ioc_err(mrioc, "Cannot alloc irq vectors\n");
+ goto out_failed;
+ }
+ if (retval != max_vectors) {
+ ioc_info(mrioc,
+ "allocated vectors (%d) are less than configured (%d)\n",
+ retval, max_vectors);
+ /*
+ * If only one MSI-x is allocated, then MSI-x 0 will be shared
+ * between Admin queue and operational queue
+ */
+ if (retval == 1)
+ mrioc->op_reply_q_offset = 0;
+
+ max_vectors = retval;
+ }
+ mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info) * max_vectors,
+ GFP_KERNEL);
+ if (!mrioc->intr_info) {
+ retval = -ENOMEM;
+ pci_free_irq_vectors(mrioc->pdev);
+ goto out_failed;
+ }
+ for (i = 0; i < max_vectors; i++) {
+ retval = mpi3mr_request_irq(mrioc, i);
+ if (retval) {
+ mrioc->intr_info_count = i;
+ goto out_failed;
+ }
+ }
+ mrioc->intr_info_count = max_vectors;
+ mpi3mr_ioc_enable_intr(mrioc);
+ return 0;
+
+out_failed:
+ mpi3mr_cleanup_isr(mrioc);
+
+ return retval;
+}
+
+static const struct {
+ enum mpi3mr_iocstate value;
+ char *name;
+} mrioc_states[] = {
+ { MRIOC_STATE_READY, "ready" },
+ { MRIOC_STATE_FAULT, "fault" },
+ { MRIOC_STATE_RESET, "reset" },
+ { MRIOC_STATE_BECOMING_READY, "becoming ready" },
+ { MRIOC_STATE_RESET_REQUESTED, "reset requested" },
+ { MRIOC_STATE_UNRECOVERABLE, "unrecoverable error" },
+};
+
+static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state)
+{
+ int i;
+ char *name = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(mrioc_states); i++) {
+ if (mrioc_states[i].value == mrioc_state) {
+ name = mrioc_states[i].name;
+ break;
+ }
+ }
+ return name;
+}
+
+/* Reset reason to name mapper structure*/
+static const struct {
+ enum mpi3mr_reset_reason value;
+ char *name;
+} mpi3mr_reset_reason_codes[] = {
+ { MPI3MR_RESET_FROM_BRINGUP, "timeout in bringup" },
+ { MPI3MR_RESET_FROM_FAULT_WATCH, "fault" },
+ { MPI3MR_RESET_FROM_IOCTL, "application invocation" },
+ { MPI3MR_RESET_FROM_EH_HOS, "error handling" },
+ { MPI3MR_RESET_FROM_TM_TIMEOUT, "TM timeout" },
+ { MPI3MR_RESET_FROM_IOCTL_TIMEOUT, "IOCTL timeout" },
+ { MPI3MR_RESET_FROM_MUR_FAILURE, "MUR failure" },
+ { MPI3MR_RESET_FROM_CTLR_CLEANUP, "timeout in controller cleanup" },
+ { MPI3MR_RESET_FROM_CIACTIV_FAULT, "component image activation fault" },
+ { MPI3MR_RESET_FROM_PE_TIMEOUT, "port enable timeout" },
+ { MPI3MR_RESET_FROM_TSU_TIMEOUT, "time stamp update timeout" },
+ { MPI3MR_RESET_FROM_DELREQQ_TIMEOUT, "delete request queue timeout" },
+ { MPI3MR_RESET_FROM_DELREPQ_TIMEOUT, "delete reply queue timeout" },
+ {
+ MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT,
+ "create request queue timeout"
+ },
+ {
+ MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT,
+ "create reply queue timeout"
+ },
+ { MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT, "IOC facts timeout" },
+ { MPI3MR_RESET_FROM_IOCINIT_TIMEOUT, "IOC init timeout" },
+ { MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT, "event notify timeout" },
+ { MPI3MR_RESET_FROM_EVTACK_TIMEOUT, "event acknowledgment timeout" },
+ {
+ MPI3MR_RESET_FROM_CIACTVRST_TIMER,
+ "component image activation timeout"
+ },
+ {
+ MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT,
+ "get package version timeout"
+ },
+ { MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" },
+ { MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" },
+};
+
+/**
+ * mpi3mr_reset_rc_name - get reset reason code name
+ * @reason_code: reset reason code value
+ *
+ * Map reset reason to an NULL terminated ASCII string
+ *
+ * Return: name corresponding to reset reason value or NULL.
+ */
+static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code)
+{
+ int i;
+ char *name = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_reason_codes); i++) {
+ if (mpi3mr_reset_reason_codes[i].value == reason_code) {
+ name = mpi3mr_reset_reason_codes[i].name;
+ break;
+ }
+ }
+ return name;
+}
+
+/* Reset type to name mapper structure*/
+static const struct {
+ u16 reset_type;
+ char *name;
+} mpi3mr_reset_types[] = {
+ { MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, "soft" },
+ { MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, "diag fault" },
+};
+
+/**
+ * mpi3mr_reset_type_name - get reset type name
+ * @reset_type: reset type value
+ *
+ * Map reset type to an NULL terminated ASCII string
+ *
+ * Return: name corresponding to reset type value or NULL.
+ */
+static const char *mpi3mr_reset_type_name(u16 reset_type)
+{
+ int i;
+ char *name = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_types); i++) {
+ if (mpi3mr_reset_types[i].reset_type == reset_type) {
+ name = mpi3mr_reset_types[i].name;
+ break;
+ }
+ }
+ return name;
+}
+
+/**
+ * mpi3mr_print_fault_info - Display fault information
+ * @mrioc: Adapter instance reference
+ *
+ * Display the controller fault information if there is a
+ * controller fault.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc)
+{
+ u32 ioc_status, code, code1, code2, code3;
+
+ ioc_status = readl(&mrioc->sysif_regs->ioc_status);
+
+ if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
+ code = readl(&mrioc->sysif_regs->fault);
+ code1 = readl(&mrioc->sysif_regs->fault_info[0]);
+ code2 = readl(&mrioc->sysif_regs->fault_info[1]);
+ code3 = readl(&mrioc->sysif_regs->fault_info[2]);
+
+ ioc_info(mrioc,
+ "fault code(0x%08X): Additional code: (0x%08X:0x%08X:0x%08X)\n",
+ code, code1, code2, code3);
+ }
+}
+
+/**
+ * mpi3mr_get_iocstate - Get IOC State
+ * @mrioc: Adapter instance reference
+ *
+ * Return a proper IOC state enum based on the IOC status and
+ * IOC configuration and unrcoverable state of the controller.
+ *
+ * Return: Current IOC state.
+ */
+enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc)
+{
+ u32 ioc_status, ioc_config;
+ u8 ready, enabled;
+
+ ioc_status = readl(&mrioc->sysif_regs->ioc_status);
+ ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
+
+ if (mrioc->unrecoverable)
+ return MRIOC_STATE_UNRECOVERABLE;
+ if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)
+ return MRIOC_STATE_FAULT;
+
+ ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY);
+ enabled = (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC);
+
+ if (ready && enabled)
+ return MRIOC_STATE_READY;
+ if ((!ready) && (!enabled))
+ return MRIOC_STATE_RESET;
+ if ((!ready) && (enabled))
+ return MRIOC_STATE_BECOMING_READY;
+
+ return MRIOC_STATE_RESET_REQUESTED;
+}
+
+/**
+ * mpi3mr_clear_reset_history - clear reset history
+ * @mrioc: Adapter instance reference
+ *
+ * Write the reset history bit in IOC status to clear the bit,
+ * if it is already set.
+ *
+ * Return: Nothing.
+ */
+static inline void mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc)
+{
+ u32 ioc_status;
+
+ ioc_status = readl(&mrioc->sysif_regs->ioc_status);
+ if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
+ writel(ioc_status, &mrioc->sysif_regs->ioc_status);
+}
+
+/**
+ * mpi3mr_issue_and_process_mur - Message unit Reset handler
+ * @mrioc: Adapter instance reference
+ * @reset_reason: Reset reason code
+ *
+ * Issue Message unit Reset to the controller and wait for it to
+ * be complete.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
+ u32 reset_reason)
+{
+ u32 ioc_config, timeout, ioc_status;
+ int retval = -1;
+
+ ioc_info(mrioc, "Issuing Message unit Reset(MUR)\n");
+ if (mrioc->unrecoverable) {
+ ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n");
+ return retval;
+ }
+ mpi3mr_clear_reset_history(mrioc);
+ writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]);
+ ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
+ ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
+ writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
+
+ timeout = mrioc->ready_timeout * 10;
+ do {
+ ioc_status = readl(&mrioc->sysif_regs->ioc_status);
+ if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) {
+ mpi3mr_clear_reset_history(mrioc);
+ ioc_config =
+ readl(&mrioc->sysif_regs->ioc_configuration);
+ if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
+ (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) ||
+ (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) {
+ retval = 0;
+ break;
+ }
+ }
+ msleep(100);
+ } while (--timeout);
+
+ ioc_status = readl(&mrioc->sysif_regs->ioc_status);
+ ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
+
+ ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n",
+ (!retval) ? "successful" : "failed", ioc_status, ioc_config);
+ return retval;
+}
+
+/**
+ * mpi3mr_bring_ioc_ready - Bring controller to ready state
+ * @mrioc: Adapter instance reference
+ *
+ * Set Enable IOC bit in IOC configuration register and wait for
+ * the controller to become ready.
+ *
+ * Return: 0 on success, -1 on failure.
+ */
+static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
+{
+ u32 ioc_config, timeout;
+ enum mpi3mr_iocstate current_state;
+
+ ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
+ ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
+ writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
+
+ timeout = mrioc->ready_timeout * 10;
+ do {
+ current_state = mpi3mr_get_iocstate(mrioc);
+ if (current_state == MRIOC_STATE_READY)
+ return 0;
+ msleep(100);
+ } while (--timeout);
+
+ return -1;
+}
+
+/**
+ * mpi3mr_soft_reset_success - Check softreset is success or not
+ * @ioc_status: IOC status register value
+ * @ioc_config: IOC config register value
+ *
+ * Check whether the soft reset is successful or not based on
+ * IOC status and IOC config register values.
+ *
+ * Return: True when the soft reset is success, false otherwise.
+ */
+static inline bool
+mpi3mr_soft_reset_success(u32 ioc_status, u32 ioc_config)
+{
+ if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
+ (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) ||
+ (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC)))
+ return true;
+ return false;
+}
+
+/**
+ * mpi3mr_diagfault_success - Check diag fault is success or not
+ * @mrioc: Adapter reference
+ * @ioc_status: IOC status register value
+ *
+ * Check whether the controller hit diag reset fault code.
+ *
+ * Return: True when there is diag fault, false otherwise.
+ */
+static inline bool mpi3mr_diagfault_success(struct mpi3mr_ioc *mrioc,
+ u32 ioc_status)
+{
+ u32 fault;
+
+ if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT))
+ return false;
+ fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK;
+ if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET)
+ return true;
+ return false;
+}
+
+/**
+ * mpi3mr_set_diagsave - Set diag save bit for snapdump
+ * @mrioc: Adapter reference
+ *
+ * Set diag save bit in IOC configuration register to enable
+ * snapdump.
+ *
+ * Return: Nothing.
+ */
+static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc)
+{
+ u32 ioc_config;
+
+ ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
+ ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE;
+ writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
+}
+
+/**
+ * mpi3mr_issue_reset - Issue reset to the controller
+ * @mrioc: Adapter reference
+ * @reset_type: Reset type
+ * @reset_reason: Reset reason code
+ *
+ * Unlock the host diagnostic registers and write the specific
+ * reset type to that, wait for reset acknowledgment from the
+ * controller, if the reset is not successful retry for the
+ * predefined number of times.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type,
+ u32 reset_reason)
+{
+ int retval = -1;
+ u8 unlock_retry_count, reset_retry_count = 0;
+ u32 host_diagnostic, timeout, ioc_status, ioc_config;
+
+ pci_cfg_access_lock(mrioc->pdev);
+ if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) &&
+ (reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT))
+ goto out;
+ if (mrioc->unrecoverable)
+ goto out;
+retry_reset:
+ unlock_retry_count = 0;
+ mpi3mr_clear_reset_history(mrioc);
+ do {
+ ioc_info(mrioc,
+ "Write magic sequence to unlock host diag register (retry=%d)\n",
+ ++unlock_retry_count);
+ if (unlock_retry_count >= MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT) {
+ writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]);
+ mrioc->unrecoverable = 1;
+ goto out;
+ }
+
+ writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH,
+ &mrioc->sysif_regs->write_sequence);
+ writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST,
+ &mrioc->sysif_regs->write_sequence);
+ writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND,
+ &mrioc->sysif_regs->write_sequence);
+ writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_3RD,
+ &mrioc->sysif_regs->write_sequence);
+ writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_4TH,
+ &mrioc->sysif_regs->write_sequence);
+ writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_5TH,
+ &mrioc->sysif_regs->write_sequence);
+ writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH,
+ &mrioc->sysif_regs->write_sequence);
+ usleep_range(1000, 1100);
+ host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
+ ioc_info(mrioc,
+ "wrote magic sequence: retry_count(%d), host_diagnostic(0x%08x)\n",
+ unlock_retry_count, host_diagnostic);
+ } while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE));
+
+ writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]);
+ ioc_info(mrioc, "%s reset due to %s(0x%x)\n",
+ mpi3mr_reset_type_name(reset_type),
+ mpi3mr_reset_rc_name(reset_reason), reset_reason);
+ writel(host_diagnostic | reset_type,
+ &mrioc->sysif_regs->host_diagnostic);
+ timeout = mrioc->ready_timeout * 10;
+ if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) {
+ do {
+ ioc_status = readl(&mrioc->sysif_regs->ioc_status);
+ if (ioc_status &
+ MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) {
+ mpi3mr_clear_reset_history(mrioc);
+ ioc_config =
+ readl(&mrioc->sysif_regs->ioc_configuration);
+ if (mpi3mr_soft_reset_success(ioc_status,
+ ioc_config)) {
+ retval = 0;
+ break;
+ }
+ }
+ msleep(100);
+ } while (--timeout);
+ writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND,
+ &mrioc->sysif_regs->write_sequence);
+ } else if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT) {
+ do {
+ ioc_status = readl(&mrioc->sysif_regs->ioc_status);
+ if (mpi3mr_diagfault_success(mrioc, ioc_status)) {
+ retval = 0;
+ break;
+ }
+ msleep(100);
+ } while (--timeout);
+ mpi3mr_clear_reset_history(mrioc);
+ writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND,
+ &mrioc->sysif_regs->write_sequence);
+ }
+ if (retval && ((++reset_retry_count) < MPI3MR_MAX_RESET_RETRY_COUNT)) {
+ ioc_status = readl(&mrioc->sysif_regs->ioc_status);
+ ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
+ ioc_info(mrioc,
+ "Base IOC Sts/Config after reset try %d is (0x%x)/(0x%x)\n",
+ reset_retry_count, ioc_status, ioc_config);
+ goto retry_reset;
+ }
+
+out:
+ pci_cfg_access_unlock(mrioc->pdev);
+ ioc_status = readl(&mrioc->sysif_regs->ioc_status);
+ ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
+
+ ioc_info(mrioc,
+ "Base IOC Sts/Config after %s reset is (0x%x)/(0x%x)\n",
+ (!retval) ? "successful" : "failed", ioc_status,
+ ioc_config);
+ return retval;
+}
+
+/**
+ * mpi3mr_admin_request_post - Post request to admin queue
+ * @mrioc: Adapter reference
+ * @admin_req: MPI3 request
+ * @admin_req_sz: Request size
+ * @ignore_reset: Ignore reset in process
+ *
+ * Post the MPI3 request into admin request queue and
+ * inform the controller, if the queue is full return
+ * appropriate error.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
+ u16 admin_req_sz, u8 ignore_reset)
+{
+ u16 areq_pi = 0, areq_ci = 0, max_entries = 0;
+ int retval = 0;
+ unsigned long flags;
+ u8 *areq_entry;
+
+ if (mrioc->unrecoverable) {
+ ioc_err(mrioc, "%s : Unrecoverable controller\n", __func__);
+ return -EFAULT;
+ }
+
+ spin_lock_irqsave(&mrioc->admin_req_lock, flags);
+ areq_pi = mrioc->admin_req_pi;
+ areq_ci = mrioc->admin_req_ci;
+ max_entries = mrioc->num_admin_req;
+ if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) &&
+ (areq_pi == (max_entries - 1)))) {
+ ioc_err(mrioc, "AdminReqQ full condition detected\n");
+ retval = -EAGAIN;
+ goto out;
+ }
+ if (!ignore_reset && mrioc->reset_in_progress) {
+ ioc_err(mrioc, "AdminReqQ submit reset in progress\n");
+ retval = -EAGAIN;
+ goto out;
+ }
+ areq_entry = (u8 *)mrioc->admin_req_base +
+ (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ);
+ memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
+ memcpy(areq_entry, (u8 *)admin_req, admin_req_sz);
+
+ if (++areq_pi == max_entries)
+ areq_pi = 0;
+ mrioc->admin_req_pi = areq_pi;
+
+ writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
+
+out:
+ spin_unlock_irqrestore(&mrioc->admin_req_lock, flags);
+
+ return retval;
+}
+
+/**
+ * mpi3mr_free_op_req_q_segments - free request memory segments
+ * @mrioc: Adapter instance reference
+ * @q_idx: operational request queue index
+ *
+ * Free memory segments allocated for operational request queue
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
+{
+ u16 j;
+ int size;
+ struct segments *segments;
+
+ segments = mrioc->req_qinfo[q_idx].q_segments;
+ if (!segments)
+ return;
+
+ if (mrioc->enable_segqueue) {
+ size = MPI3MR_OP_REQ_Q_SEG_SIZE;
+ if (mrioc->req_qinfo[q_idx].q_segment_list) {
+ dma_free_coherent(&mrioc->pdev->dev,
+ MPI3MR_MAX_SEG_LIST_SIZE,
+ mrioc->req_qinfo[q_idx].q_segment_list,
+ mrioc->req_qinfo[q_idx].q_segment_list_dma);
+ mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL;
+ }
+ } else
+ size = mrioc->req_qinfo[q_idx].num_requests *
+ mrioc->facts.op_req_sz;
+
+ for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) {
+ if (!segments[j].segment)
+ continue;
+ dma_free_coherent(&mrioc->pdev->dev,
+ size, segments[j].segment, segments[j].segment_dma);
+ segments[j].segment = NULL;
+ }
+ kfree(mrioc->req_qinfo[q_idx].q_segments);
+ mrioc->req_qinfo[q_idx].q_segments = NULL;
+ mrioc->req_qinfo[q_idx].qid = 0;
+}
+
+/**
+ * mpi3mr_free_op_reply_q_segments - free reply memory segments
+ * @mrioc: Adapter instance reference
+ * @q_idx: operational reply queue index
+ *
+ * Free memory segments allocated for operational reply queue
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
+{
+ u16 j;
+ int size;
+ struct segments *segments;
+
+ segments = mrioc->op_reply_qinfo[q_idx].q_segments;
+ if (!segments)
+ return;
+
+ if (mrioc->enable_segqueue) {
+ size = MPI3MR_OP_REP_Q_SEG_SIZE;
+ if (mrioc->op_reply_qinfo[q_idx].q_segment_list) {
+ dma_free_coherent(&mrioc->pdev->dev,
+ MPI3MR_MAX_SEG_LIST_SIZE,
+ mrioc->op_reply_qinfo[q_idx].q_segment_list,
+ mrioc->op_reply_qinfo[q_idx].q_segment_list_dma);
+ mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL;
+ }
+ } else
+ size = mrioc->op_reply_qinfo[q_idx].segment_qd *
+ mrioc->op_reply_desc_sz;
+
+ for (j = 0; j < mrioc->op_reply_qinfo[q_idx].num_segments; j++) {
+ if (!segments[j].segment)
+ continue;
+ dma_free_coherent(&mrioc->pdev->dev,
+ size, segments[j].segment, segments[j].segment_dma);
+ segments[j].segment = NULL;
+ }
+
+ kfree(mrioc->op_reply_qinfo[q_idx].q_segments);
+ mrioc->op_reply_qinfo[q_idx].q_segments = NULL;
+ mrioc->op_reply_qinfo[q_idx].qid = 0;
+}
+
+/**
+ * mpi3mr_delete_op_reply_q - delete operational reply queue
+ * @mrioc: Adapter instance reference
+ * @qidx: operational reply queue index
+ *
+ * Delete operatinal reply queue by issuing MPI request
+ * through admin queue.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
+{
+ struct mpi3_delete_reply_queue_request delq_req;
+ int retval = 0;
+ u16 reply_qid = 0, midx;
+
+ reply_qid = mrioc->op_reply_qinfo[qidx].qid;
+
+ midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset);
+
+ if (!reply_qid) {
+ retval = -1;
+ ioc_err(mrioc, "Issue DelRepQ: called with invalid ReqQID\n");
+ goto out;
+ }
+
+ memset(&delq_req, 0, sizeof(delq_req));
+ mutex_lock(&mrioc->init_cmds.mutex);
+ if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
+ retval = -1;
+ ioc_err(mrioc, "Issue DelRepQ: Init command is in use\n");
+ mutex_unlock(&mrioc->init_cmds.mutex);
+ goto out;
+ }
+ mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
+ mrioc->init_cmds.is_waiting = 1;
+ mrioc->init_cmds.callback = NULL;
+ delq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
+ delq_req.function = MPI3_FUNCTION_DELETE_REPLY_QUEUE;
+ delq_req.queue_id = cpu_to_le16(reply_qid);
+
+ init_completion(&mrioc->init_cmds.done);
+ retval = mpi3mr_admin_request_post(mrioc, &delq_req, sizeof(delq_req),
+ 1);
+ if (retval) {
+ ioc_err(mrioc, "Issue DelRepQ: Admin Post failed\n");
+ goto out_unlock;
+ }
+ wait_for_completion_timeout(&mrioc->init_cmds.done,
+ (MPI3MR_INTADMCMD_TIMEOUT * HZ));
+ if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
+ ioc_err(mrioc, "Issue DelRepQ: command timed out\n");
+ mpi3mr_set_diagsave(mrioc);
+ mpi3mr_issue_reset(mrioc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
+ MPI3MR_RESET_FROM_DELREPQ_TIMEOUT);
+ mrioc->unrecoverable = 1;
+
+ retval = -1;
+ goto out_unlock;
+ }
+ if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
+ != MPI3_IOCSTATUS_SUCCESS) {
+ ioc_err(mrioc,
+ "Issue DelRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
+ (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
+ mrioc->init_cmds.ioc_loginfo);
+ retval = -1;
+ goto out_unlock;
+ }
+ mrioc->intr_info[midx].op_reply_q = NULL;
+
+ mpi3mr_free_op_reply_q_segments(mrioc, qidx);
+out_unlock:
+ mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
+ mutex_unlock(&mrioc->init_cmds.mutex);
+out:
+
+ return retval;
+}
+
+/**
+ * mpi3mr_alloc_op_reply_q_segments -Alloc segmented reply pool
+ * @mrioc: Adapter instance reference
+ * @qidx: request queue index
+ *
+ * Allocate segmented memory pools for operational reply
+ * queue.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int mpi3mr_alloc_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx)
+{
+ struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
+ int i, size;
+ u64 *q_segment_list_entry = NULL;
+ struct segments *segments;
+
+ if (mrioc->enable_segqueue) {
+ op_reply_q->segment_qd =
+ MPI3MR_OP_REP_Q_SEG_SIZE / mrioc->op_reply_desc_sz;
+
+ size = MPI3MR_OP_REP_Q_SEG_SIZE;
+
+ op_reply_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev,
+ MPI3MR_MAX_SEG_LIST_SIZE, &op_reply_q->q_segment_list_dma,
+ GFP_KERNEL);
+ if (!op_reply_q->q_segment_list)
+ return -ENOMEM;
+ q_segment_list_entry = (u64 *)op_reply_q->q_segment_list;
+ } else {
+ op_reply_q->segment_qd = op_reply_q->num_replies;
+ size = op_reply_q->num_replies * mrioc->op_reply_desc_sz;
+ }
+
+ op_reply_q->num_segments = DIV_ROUND_UP(op_reply_q->num_replies,
+ op_reply_q->segment_qd);
+
+ op_reply_q->q_segments = kcalloc(op_reply_q->num_segments,
+ sizeof(struct segments), GFP_KERNEL);
+ if (!op_reply_q->q_segments)
+ return -ENOMEM;
+
+ segments = op_reply_q->q_segments;
+ for (i = 0; i < op_reply_q->num_segments; i++) {
+ segments[i].segment =
+ dma_alloc_coherent(&mrioc->pdev->dev,
+ size, &segments[i].segment_dma, GFP_KERNEL);
+ if (!segments[i].segment)
+ return -ENOMEM;
+ if (mrioc->enable_segqueue)
+ q_segment_list_entry[i] =
+ (unsigned long)segments[i].segment_dma;
+ }
+
+ return 0;
+}
+
+/**
+ * mpi3mr_alloc_op_req_q_segments - Alloc segmented req pool.
+ * @mrioc: Adapter instance reference
+ * @qidx: request queue index
+ *
+ * Allocate segmented memory pools for operational request
+ * queue.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int mpi3mr_alloc_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 qidx)
+{
+ struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx;
+ int i, size;
+ u64 *q_segment_list_entry = NULL;
+ struct segments *segments;
+
+ if (mrioc->enable_segqueue) {
+ op_req_q->segment_qd =
+ MPI3MR_OP_REQ_Q_SEG_SIZE / mrioc->facts.op_req_sz;
+
+ size = MPI3MR_OP_REQ_Q_SEG_SIZE;
+
+ op_req_q->q_segment_list = dma_alloc_coherent(&mrioc->pdev->dev,
+ MPI3MR_MAX_SEG_LIST_SIZE, &op_req_q->q_segment_list_dma,
+ GFP_KERNEL);
+ if (!op_req_q->q_segment_list)
+ return -ENOMEM;
+ q_segment_list_entry = (u64 *)op_req_q->q_segment_list;
+
+ } else {
+ op_req_q->segment_qd = op_req_q->num_requests;
+ size = op_req_q->num_requests * mrioc->facts.op_req_sz;
+ }
+
+ op_req_q->num_segments = DIV_ROUND_UP(op_req_q->num_requests,
+ op_req_q->segment_qd);
+
+ op_req_q->q_segments = kcalloc(op_req_q->num_segments,
+ sizeof(struct segments), GFP_KERNEL);
+ if (!op_req_q->q_segments)
+ return -ENOMEM;
+
+ segments = op_req_q->q_segments;
+ for (i = 0; i < op_req_q->num_segments; i++) {
+ segments[i].segment =
+ dma_alloc_coherent(&mrioc->pdev->dev,
+ size, &segments[i].segment_dma, GFP_KERNEL);
+ if (!segments[i].segment)
+ return -ENOMEM;
+ if (mrioc->enable_segqueue)
+ q_segment_list_entry[i] =
+ (unsigned long)segments[i].segment_dma;
+ }
+
+ return 0;
+}
+
+/**
+ * mpi3mr_create_op_reply_q - create operational reply queue
+ * @mrioc: Adapter instance reference
+ * @qidx: operational reply queue index
+ *
+ * Create operatinal reply queue by issuing MPI request
+ * through admin queue.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
+{
+ struct mpi3_create_reply_queue_request create_req;
+ struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
+ int retval = 0;
+ u16 reply_qid = 0, midx;
+
+ reply_qid = op_reply_q->qid;
+
+ midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset);
+
+ if (reply_qid) {
+ retval = -1;
+ ioc_err(mrioc, "CreateRepQ: called for duplicate qid %d\n",
+ reply_qid);
+
+ return retval;
+ }
+
+ reply_qid = qidx + 1;
+ op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD;
+ op_reply_q->ci = 0;
+ op_reply_q->ephase = 1;
+ atomic_set(&op_reply_q->pend_ios, 0);
+ atomic_set(&op_reply_q->in_use, 0);
+ op_reply_q->enable_irq_poll = false;
+
+ if (!op_reply_q->q_segments) {
+ retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx);
+ if (retval) {
+ mpi3mr_free_op_reply_q_segments(mrioc, qidx);
+ goto out;
+ }
+ }
+
+ memset(&create_req, 0, sizeof(create_req));
+ mutex_lock(&mrioc->init_cmds.mutex);
+ if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
+ retval = -1;
+ ioc_err(mrioc, "CreateRepQ: Init command is in use\n");
+ goto out_unlock;
+ }
+ mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
+ mrioc->init_cmds.is_waiting = 1;
+ mrioc->init_cmds.callback = NULL;
+ create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
+ create_req.function = MPI3_FUNCTION_CREATE_REPLY_QUEUE;
+ create_req.queue_id = cpu_to_le16(reply_qid);
+ create_req.flags = MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE;
+ create_req.msix_index = cpu_to_le16(mrioc->intr_info[midx].msix_index);
+ if (mrioc->enable_segqueue) {
+ create_req.flags |=
+ MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED;
+ create_req.base_address = cpu_to_le64(
+ op_reply_q->q_segment_list_dma);
+ } else
+ create_req.base_address = cpu_to_le64(
+ op_reply_q->q_segments[0].segment_dma);
+
+ create_req.size = cpu_to_le16(op_reply_q->num_replies);
+
+ init_completion(&mrioc->init_cmds.done);
+ retval = mpi3mr_admin_request_post(mrioc, &create_req,
+ sizeof(create_req), 1);
+ if (retval) {
+ ioc_err(mrioc, "CreateRepQ: Admin Post failed\n");
+ goto out_unlock;
+ }
+ wait_for_completion_timeout(&mrioc->init_cmds.done,
+ (MPI3MR_INTADMCMD_TIMEOUT * HZ));
+ if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
+ ioc_err(mrioc, "CreateRepQ: command timed out\n");
+ mpi3mr_set_diagsave(mrioc);
+ mpi3mr_issue_reset(mrioc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
+ MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT);
+ mrioc->unrecoverable = 1;
+ retval = -1;
+ goto out_unlock;
+ }
+ if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
+ != MPI3_IOCSTATUS_SUCCESS) {
+ ioc_err(mrioc,
+ "CreateRepQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
+ (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
+ mrioc->init_cmds.ioc_loginfo);
+ retval = -1;
+ goto out_unlock;
+ }
+ op_reply_q->qid = reply_qid;
+ mrioc->intr_info[midx].op_reply_q = op_reply_q;
+
+out_unlock:
+ mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
+ mutex_unlock(&mrioc->init_cmds.mutex);
+out:
+
+ return retval;
+}
+
+/**
+ * mpi3mr_create_op_req_q - create operational request queue
+ * @mrioc: Adapter instance reference
+ * @idx: operational request queue index
+ * @reply_qid: Reply queue ID
+ *
+ * Create operatinal request queue by issuing MPI request
+ * through admin queue.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx,
+ u16 reply_qid)
+{
+ struct mpi3_create_request_queue_request create_req;
+ struct op_req_qinfo *op_req_q = mrioc->req_qinfo + idx;
+ int retval = 0;
+ u16 req_qid = 0;
+
+ req_qid = op_req_q->qid;
+
+ if (req_qid) {
+ retval = -1;
+ ioc_err(mrioc, "CreateReqQ: called for duplicate qid %d\n",
+ req_qid);
+
+ return retval;
+ }
+ req_qid = idx + 1;
+
+ op_req_q->num_requests = MPI3MR_OP_REQ_Q_QD;
+ op_req_q->ci = 0;
+ op_req_q->pi = 0;
+ op_req_q->reply_qid = reply_qid;
+ spin_lock_init(&op_req_q->q_lock);
+
+ if (!op_req_q->q_segments) {
+ retval = mpi3mr_alloc_op_req_q_segments(mrioc, idx);
+ if (retval) {
+ mpi3mr_free_op_req_q_segments(mrioc, idx);
+ goto out;
+ }
+ }
+
+ memset(&create_req, 0, sizeof(create_req));
+ mutex_lock(&mrioc->init_cmds.mutex);
+ if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
+ retval = -1;
+ ioc_err(mrioc, "CreateReqQ: Init command is in use\n");
+ goto out_unlock;
+ }
+ mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
+ mrioc->init_cmds.is_waiting = 1;
+ mrioc->init_cmds.callback = NULL;
+ create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
+ create_req.function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE;
+ create_req.queue_id = cpu_to_le16(req_qid);
+ if (mrioc->enable_segqueue) {
+ create_req.flags =
+ MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED;
+ create_req.base_address = cpu_to_le64(
+ op_req_q->q_segment_list_dma);
+ } else
+ create_req.base_address = cpu_to_le64(
+ op_req_q->q_segments[0].segment_dma);
+ create_req.reply_queue_id = cpu_to_le16(reply_qid);
+ create_req.size = cpu_to_le16(op_req_q->num_requests);
+
+ init_completion(&mrioc->init_cmds.done);
+ retval = mpi3mr_admin_request_post(mrioc, &create_req,
+ sizeof(create_req), 1);
+ if (retval) {
+ ioc_err(mrioc, "CreateReqQ: Admin Post failed\n");
+ goto out_unlock;
+ }
+ wait_for_completion_timeout(&mrioc->init_cmds.done,
+ (MPI3MR_INTADMCMD_TIMEOUT * HZ));
+ if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
+ ioc_err(mrioc, "CreateReqQ: command timed out\n");
+ mpi3mr_set_diagsave(mrioc);
+ if (mpi3mr_issue_reset(mrioc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
+ MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT))
+ mrioc->unrecoverable = 1;
+ retval = -1;
+ goto out_unlock;
+ }
+ if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
+ != MPI3_IOCSTATUS_SUCCESS) {
+ ioc_err(mrioc,
+ "CreateReqQ: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
+ (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
+ mrioc->init_cmds.ioc_loginfo);
+ retval = -1;
+ goto out_unlock;
+ }
+ op_req_q->qid = req_qid;
+
+out_unlock:
+ mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
+ mutex_unlock(&mrioc->init_cmds.mutex);
+out:
+
+ return retval;
+}
+
+/**
+ * mpi3mr_create_op_queues - create operational queue pairs
+ * @mrioc: Adapter instance reference
+ *
+ * Allocate memory for operational queue meta data and call
+ * create request and reply queue functions.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc)
+{
+ int retval = 0;
+ u16 num_queues = 0, i = 0, msix_count_op_q = 1;
+
+ num_queues = min_t(int, mrioc->facts.max_op_reply_q,
+ mrioc->facts.max_op_req_q);
+
+ msix_count_op_q =
+ mrioc->intr_info_count - mrioc->op_reply_q_offset;
+ if (!mrioc->num_queues)
+ mrioc->num_queues = min_t(int, num_queues, msix_count_op_q);
+ num_queues = mrioc->num_queues;
+ ioc_info(mrioc, "Trying to create %d Operational Q pairs\n",
+ num_queues);
+
+ if (!mrioc->req_qinfo) {
+ mrioc->req_qinfo = kcalloc(num_queues,
+ sizeof(struct op_req_qinfo), GFP_KERNEL);
+ if (!mrioc->req_qinfo) {
+ retval = -1;
+ goto out_failed;
+ }
+
+ mrioc->op_reply_qinfo = kzalloc(sizeof(struct op_reply_qinfo) *
+ num_queues, GFP_KERNEL);
+ if (!mrioc->op_reply_qinfo) {
+ retval = -1;
+ goto out_failed;
+ }
+ }
+
+ if (mrioc->enable_segqueue)
+ ioc_info(mrioc,
+ "allocating operational queues through segmented queues\n");
+
+ for (i = 0; i < num_queues; i++) {
+ if (mpi3mr_create_op_reply_q(mrioc, i)) {
+ ioc_err(mrioc, "Cannot create OP RepQ %d\n", i);
+ break;
+ }
+ if (mpi3mr_create_op_req_q(mrioc, i,
+ mrioc->op_reply_qinfo[i].qid)) {
+ ioc_err(mrioc, "Cannot create OP ReqQ %d\n", i);
+ mpi3mr_delete_op_reply_q(mrioc, i);
+ break;
+ }
+ }
+
+ if (i == 0) {
+ /* Not even one queue is created successfully*/
+ retval = -1;
+ goto out_failed;
+ }
+ mrioc->num_op_reply_q = mrioc->num_op_req_q = i;
+ ioc_info(mrioc, "Successfully created %d Operational Q pairs\n",
+ mrioc->num_op_reply_q);
+
+ return retval;
+out_failed:
+ kfree(mrioc->req_qinfo);
+ mrioc->req_qinfo = NULL;
+
+ kfree(mrioc->op_reply_qinfo);
+ mrioc->op_reply_qinfo = NULL;
+
+ return retval;
+}
+
+/**
+ * mpi3mr_op_request_post - Post request to operational queue
+ * @mrioc: Adapter reference
+ * @op_req_q: Operational request queue info
+ * @req: MPI3 request
+ *
+ * Post the MPI3 request into operational request queue and
+ * inform the controller, if the queue is full return
+ * appropriate error.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
+ struct op_req_qinfo *op_req_q, u8 *req)
+{
+ u16 pi = 0, max_entries, reply_qidx = 0, midx;
+ int retval = 0;
+ unsigned long flags;
+ u8 *req_entry;
+ void *segment_base_addr;
+ u16 req_sz = mrioc->facts.op_req_sz;
+ struct segments *segments = op_req_q->q_segments;
+
+ reply_qidx = op_req_q->reply_qid - 1;
+
+ if (mrioc->unrecoverable)
+ return -EFAULT;
+
+ spin_lock_irqsave(&op_req_q->q_lock, flags);
+ pi = op_req_q->pi;
+ max_entries = op_req_q->num_requests;
+
+ if (mpi3mr_check_req_qfull(op_req_q)) {
+ midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(
+ reply_qidx, mrioc->op_reply_q_offset);
+ mpi3mr_process_op_reply_q(mrioc, &mrioc->intr_info[midx]);
+
+ if (mpi3mr_check_req_qfull(op_req_q)) {
+ retval = -EAGAIN;
+ goto out;
+ }
+ }
+
+ if (mrioc->reset_in_progress) {
+ ioc_err(mrioc, "OpReqQ submit reset in progress\n");
+ retval = -EAGAIN;
+ goto out;
+ }
+
+ segment_base_addr = segments[pi / op_req_q->segment_qd].segment;
+ req_entry = (u8 *)segment_base_addr +
+ ((pi % op_req_q->segment_qd) * req_sz);
+
+ memset(req_entry, 0, req_sz);
+ memcpy(req_entry, req, MPI3MR_ADMIN_REQ_FRAME_SZ);
+
+ if (++pi == max_entries)
+ pi = 0;
+ op_req_q->pi = pi;
+
+ if (atomic_inc_return(&mrioc->op_reply_qinfo[reply_qidx].pend_ios)
+ > MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT)
+ mrioc->op_reply_qinfo[reply_qidx].enable_irq_poll = true;
+
+ writel(op_req_q->pi,
+ &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].producer_index);
+
+out:
+ spin_unlock_irqrestore(&op_req_q->q_lock, flags);
+ return retval;
+}
+
+/**
+ * mpi3mr_sync_timestamp - Issue time stamp sync request
+ * @mrioc: Adapter reference
+ *
+ * Issue IO unit control MPI request to synchornize firmware
+ * timestamp with host time.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int mpi3mr_sync_timestamp(struct mpi3mr_ioc *mrioc)
+{
+ ktime_t current_time;
+ struct mpi3_iounit_control_request iou_ctrl;
+ int retval = 0;
+
+ memset(&iou_ctrl, 0, sizeof(iou_ctrl));
+ mutex_lock(&mrioc->init_cmds.mutex);
+ if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
+ retval = -1;
+ ioc_err(mrioc, "Issue IOUCTL time_stamp: command is in use\n");
+ mutex_unlock(&mrioc->init_cmds.mutex);
+ goto out;
+ }
+ mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
+ mrioc->init_cmds.is_waiting = 1;
+ mrioc->init_cmds.callback = NULL;
+ iou_ctrl.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
+ iou_ctrl.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
+ iou_ctrl.operation = MPI3_CTRL_OP_UPDATE_TIMESTAMP;
+ current_time = ktime_get_real();
+ iou_ctrl.param64[0] = cpu_to_le64(ktime_to_ms(current_time));
+
+ init_completion(&mrioc->init_cmds.done);
+ retval = mpi3mr_admin_request_post(mrioc, &iou_ctrl,
+ sizeof(iou_ctrl), 0);
+ if (retval) {
+ ioc_err(mrioc, "Issue IOUCTL time_stamp: Admin Post failed\n");
+ goto out_unlock;
+ }
+
+ wait_for_completion_timeout(&mrioc->init_cmds.done,
+ (MPI3MR_INTADMCMD_TIMEOUT * HZ));
+ if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
+ ioc_err(mrioc, "Issue IOUCTL time_stamp: command timed out\n");
+ mrioc->init_cmds.is_waiting = 0;
+ mpi3mr_soft_reset_handler(mrioc,
+ MPI3MR_RESET_FROM_TSU_TIMEOUT, 1);
+ retval = -1;
+ goto out_unlock;
+ }
+ if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
+ != MPI3_IOCSTATUS_SUCCESS) {
+ ioc_err(mrioc,
+ "Issue IOUCTL time_stamp: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
+ (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
+ mrioc->init_cmds.ioc_loginfo);
+ retval = -1;
+ goto out_unlock;
+ }
+
+out_unlock:
+ mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
+ mutex_unlock(&mrioc->init_cmds.mutex);
+
+out:
+ return retval;
+}
+
+/**
+ * mpi3mr_watchdog_work - watchdog thread to monitor faults
+ * @work: work struct
+ *
+ * Watch dog work periodically executed (1 second interval) to
+ * monitor firmware fault and to issue periodic timer sync to
+ * the firmware.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_watchdog_work(struct work_struct *work)
+{
+ struct mpi3mr_ioc *mrioc =
+ container_of(work, struct mpi3mr_ioc, watchdog_work.work);
+ unsigned long flags;
+ enum mpi3mr_iocstate ioc_state;
+ u32 fault, host_diagnostic;
+
+ if (mrioc->ts_update_counter++ >= MPI3MR_TSUPDATE_INTERVAL) {
+ mrioc->ts_update_counter = 0;
+ mpi3mr_sync_timestamp(mrioc);
+ }
+
+ /*Check for fault state every one second and issue Soft reset*/
+ ioc_state = mpi3mr_get_iocstate(mrioc);
+ if (ioc_state == MRIOC_STATE_FAULT) {
+ fault = readl(&mrioc->sysif_regs->fault) &
+ MPI3_SYSIF_FAULT_CODE_MASK;
+ host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
+ if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) {
+ if (!mrioc->diagsave_timeout) {
+ mpi3mr_print_fault_info(mrioc);
+ ioc_warn(mrioc, "Diag save in progress\n");
+ }
+ if ((mrioc->diagsave_timeout++) <=
+ MPI3_SYSIF_DIAG_SAVE_TIMEOUT)
+ goto schedule_work;
+ } else
+ mpi3mr_print_fault_info(mrioc);
+ mrioc->diagsave_timeout = 0;
+
+ if (fault == MPI3_SYSIF_FAULT_CODE_FACTORY_RESET) {
+ ioc_info(mrioc,
+ "Factory Reset fault occurred marking controller as unrecoverable"
+ );
+ mrioc->unrecoverable = 1;
+ goto out;
+ }
+
+ if ((fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) ||
+ (fault == MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS) ||
+ (mrioc->reset_in_progress))
+ goto out;
+ if (fault == MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET)
+ mpi3mr_soft_reset_handler(mrioc,
+ MPI3MR_RESET_FROM_CIACTIV_FAULT, 0);
+ else
+ mpi3mr_soft_reset_handler(mrioc,
+ MPI3MR_RESET_FROM_FAULT_WATCH, 0);
+ }
+
+schedule_work:
+ spin_lock_irqsave(&mrioc->watchdog_lock, flags);
+ if (mrioc->watchdog_work_q)
+ queue_delayed_work(mrioc->watchdog_work_q,
+ &mrioc->watchdog_work,
+ msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
+ spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
+out:
+ return;
+}
+
+/**
+ * mpi3mr_start_watchdog - Start watchdog
+ * @mrioc: Adapter instance reference
+ *
+ * Create and start the watchdog thread to monitor controller
+ * faults.
+ *
+ * Return: Nothing.
+ */
+void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc)
+{
+ if (mrioc->watchdog_work_q)
+ return;
+
+ INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work);
+ snprintf(mrioc->watchdog_work_q_name,
+ sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name,
+ mrioc->id);
+ mrioc->watchdog_work_q =
+ create_singlethread_workqueue(mrioc->watchdog_work_q_name);
+ if (!mrioc->watchdog_work_q) {
+ ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__);
+ return;
+ }
+
+ if (mrioc->watchdog_work_q)
+ queue_delayed_work(mrioc->watchdog_work_q,
+ &mrioc->watchdog_work,
+ msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
+}
+
+/**
+ * mpi3mr_stop_watchdog - Stop watchdog
+ * @mrioc: Adapter instance reference
+ *
+ * Stop the watchdog thread created to monitor controller
+ * faults.
+ *
+ * Return: Nothing.
+ */
+void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc)
+{
+ unsigned long flags;
+ struct workqueue_struct *wq;
+
+ spin_lock_irqsave(&mrioc->watchdog_lock, flags);
+ wq = mrioc->watchdog_work_q;
+ mrioc->watchdog_work_q = NULL;
+ spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
+ if (wq) {
+ if (!cancel_delayed_work_sync(&mrioc->watchdog_work))
+ flush_workqueue(wq);
+ destroy_workqueue(wq);
+ }
+}
+
+/**
+ * mpi3mr_kill_ioc - Kill the controller
+ * @mrioc: Adapter instance reference
+ * @reason: reason for the failure.
+ *
+ * If fault debug is enabled, display the fault info else issue
+ * diag fault and freeze the system for controller debug
+ * purpose.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_kill_ioc(struct mpi3mr_ioc *mrioc, u32 reason)
+{
+ enum mpi3mr_iocstate ioc_state;
+
+ if (!mrioc->fault_dbg)
+ return;
+
+ dump_stack();
+
+ ioc_state = mpi3mr_get_iocstate(mrioc);
+ if (ioc_state == MRIOC_STATE_FAULT)
+ mpi3mr_print_fault_info(mrioc);
+ else {
+ ioc_err(mrioc, "Firmware is halted due to the reason %d\n",
+ reason);
+ mpi3mr_diagfault_reset_handler(mrioc, reason);
+ }
+ if (mrioc->fault_dbg == 2)
+ for (;;)
+ ;
+ else
+ panic("panic in %s\n", __func__);
+}
+
+/**
+ * mpi3mr_setup_admin_qpair - Setup admin queue pair
+ * @mrioc: Adapter instance reference
+ *
+ * Allocate memory for admin queue pair if required and register
+ * the admin queue with the controller.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc)
+{
+ int retval = 0;
+ u32 num_admin_entries = 0;
+
+ mrioc->admin_req_q_sz = MPI3MR_ADMIN_REQ_Q_SIZE;
+ mrioc->num_admin_req = mrioc->admin_req_q_sz /
+ MPI3MR_ADMIN_REQ_FRAME_SZ;
+ mrioc->admin_req_ci = mrioc->admin_req_pi = 0;
+ mrioc->admin_req_base = NULL;
+
+ mrioc->admin_reply_q_sz = MPI3MR_ADMIN_REPLY_Q_SIZE;
+ mrioc->num_admin_replies = mrioc->admin_reply_q_sz /
+ MPI3MR_ADMIN_REPLY_FRAME_SZ;
+ mrioc->admin_reply_ci = 0;
+ mrioc->admin_reply_ephase = 1;
+ mrioc->admin_reply_base = NULL;
+
+ if (!mrioc->admin_req_base) {
+ mrioc->admin_req_base = dma_alloc_coherent(&mrioc->pdev->dev,
+ mrioc->admin_req_q_sz, &mrioc->admin_req_dma, GFP_KERNEL);
+
+ if (!mrioc->admin_req_base) {
+ retval = -1;
+ goto out_failed;
+ }
+
+ mrioc->admin_reply_base = dma_alloc_coherent(&mrioc->pdev->dev,
+ mrioc->admin_reply_q_sz, &mrioc->admin_reply_dma,
+ GFP_KERNEL);
+
+ if (!mrioc->admin_reply_base) {
+ retval = -1;
+ goto out_failed;
+ }
+ }
+
+ num_admin_entries = (mrioc->num_admin_replies << 16) |
+ (mrioc->num_admin_req);
+ writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries);
+ mpi3mr_writeq(mrioc->admin_req_dma,
+ &mrioc->sysif_regs->admin_request_queue_address);
+ mpi3mr_writeq(mrioc->admin_reply_dma,
+ &mrioc->sysif_regs->admin_reply_queue_address);
+ writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
+ writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
+ return retval;
+
+out_failed:
+
+ if (mrioc->admin_reply_base) {
+ dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
+ mrioc->admin_reply_base, mrioc->admin_reply_dma);
+ mrioc->admin_reply_base = NULL;
+ }
+ if (mrioc->admin_req_base) {
+ dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
+ mrioc->admin_req_base, mrioc->admin_req_dma);
+ mrioc->admin_req_base = NULL;
+ }
+ return retval;
+}
+
+/**
+ * mpi3mr_issue_iocfacts - Send IOC Facts
+ * @mrioc: Adapter instance reference
+ * @facts_data: Cached IOC facts data
+ *
+ * Issue IOC Facts MPI request through admin queue and wait for
+ * the completion of it or time out.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc,
+ struct mpi3_ioc_facts_data *facts_data)
+{
+ struct mpi3_ioc_facts_request iocfacts_req;
+ void *data = NULL;
+ dma_addr_t data_dma;
+ u32 data_len = sizeof(*facts_data);
+ int retval = 0;
+ u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
+
+ data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
+ GFP_KERNEL);
+
+ if (!data) {
+ retval = -1;
+ goto out;
+ }
+
+ memset(&iocfacts_req, 0, sizeof(iocfacts_req));
+ mutex_lock(&mrioc->init_cmds.mutex);
+ if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
+ retval = -1;
+ ioc_err(mrioc, "Issue IOCFacts: Init command is in use\n");
+ mutex_unlock(&mrioc->init_cmds.mutex);
+ goto out;
+ }
+ mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
+ mrioc->init_cmds.is_waiting = 1;
+ mrioc->init_cmds.callback = NULL;
+ iocfacts_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
+ iocfacts_req.function = MPI3_FUNCTION_IOC_FACTS;
+
+ mpi3mr_add_sg_single(&iocfacts_req.sgl, sgl_flags, data_len,
+ data_dma);
+
+ init_completion(&mrioc->init_cmds.done);
+ retval = mpi3mr_admin_request_post(mrioc, &iocfacts_req,
+ sizeof(iocfacts_req), 1);
+ if (retval) {
+ ioc_err(mrioc, "Issue IOCFacts: Admin Post failed\n");
+ goto out_unlock;
+ }
+ wait_for_completion_timeout(&mrioc->init_cmds.done,
+ (MPI3MR_INTADMCMD_TIMEOUT * HZ));
+ if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
+ ioc_err(mrioc, "Issue IOCFacts: command timed out\n");
+ mpi3mr_set_diagsave(mrioc);
+ mpi3mr_issue_reset(mrioc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
+ MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT);
+ mrioc->unrecoverable = 1;
+ retval = -1;
+ goto out_unlock;
+ }
+ if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
+ != MPI3_IOCSTATUS_SUCCESS) {
+ ioc_err(mrioc,
+ "Issue IOCFacts: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
+ (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
+ mrioc->init_cmds.ioc_loginfo);
+ retval = -1;
+ goto out_unlock;
+ }
+ memcpy(facts_data, (u8 *)data, data_len);
+out_unlock:
+ mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
+ mutex_unlock(&mrioc->init_cmds.mutex);
+
+out:
+ if (data)
+ dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma);
+
+ return retval;
+}
+
+/**
+ * mpi3mr_check_reset_dma_mask - Process IOC facts data
+ * @mrioc: Adapter instance reference
+ *
+ * Check whether the new DMA mask requested through IOCFacts by
+ * firmware needs to be set, if so set it .
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static inline int mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc)
+{
+ struct pci_dev *pdev = mrioc->pdev;
+ int r;
+ u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask);
+
+ if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask))
+ return 0;
+
+ ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n",
+ mrioc->dma_mask, facts_dma_mask);
+
+ r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask);
+ if (r) {
+ ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n",
+ facts_dma_mask, r);
+ return r;
+ }
+ mrioc->dma_mask = facts_dma_mask;
+ return r;
+}
+
+/**
+ * mpi3mr_process_factsdata - Process IOC facts data
+ * @mrioc: Adapter instance reference
+ * @facts_data: Cached IOC facts data
+ *
+ * Convert IOC facts data into cpu endianness and cache it in
+ * the driver .
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
+ struct mpi3_ioc_facts_data *facts_data)
+{
+ u32 ioc_config, req_sz, facts_flags;
+
+ if ((le16_to_cpu(facts_data->ioc_facts_data_length)) !=
+ (sizeof(*facts_data) / 4)) {
+ ioc_warn(mrioc,
+ "IOCFactsdata length mismatch driver_sz(%zu) firmware_sz(%d)\n",
+ sizeof(*facts_data),
+ le16_to_cpu(facts_data->ioc_facts_data_length) * 4);
+ }
+
+ ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
+ req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >>
+ MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT);
+ if (le16_to_cpu(facts_data->ioc_request_frame_size) != (req_sz / 4)) {
+ ioc_err(mrioc,
+ "IOCFacts data reqFrameSize mismatch hw_size(%d) firmware_sz(%d)\n",
+ req_sz / 4, le16_to_cpu(facts_data->ioc_request_frame_size));
+ }
+
+ memset(&mrioc->facts, 0, sizeof(mrioc->facts));
+
+ facts_flags = le32_to_cpu(facts_data->flags);
+ mrioc->facts.op_req_sz = req_sz;
+ mrioc->op_reply_desc_sz = 1 << ((ioc_config &
+ MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >>
+ MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT);
+
+ mrioc->facts.ioc_num = facts_data->ioc_number;
+ mrioc->facts.who_init = facts_data->who_init;
+ mrioc->facts.max_msix_vectors = le16_to_cpu(facts_data->max_msix_vectors);
+ mrioc->facts.personality = (facts_flags &
+ MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK);
+ mrioc->facts.dma_mask = (facts_flags &
+ MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
+ MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
+ mrioc->facts.protocol_flags = facts_data->protocol_flags;
+ mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word);
+ mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_request);
+ mrioc->facts.product_id = le16_to_cpu(facts_data->product_id);
+ mrioc->facts.reply_sz = le16_to_cpu(facts_data->reply_frame_size) * 4;
+ mrioc->facts.exceptions = le16_to_cpu(facts_data->ioc_exceptions);
+ mrioc->facts.max_perids = le16_to_cpu(facts_data->max_persistent_id);
+ mrioc->facts.max_pds = le16_to_cpu(facts_data->max_pds);
+ mrioc->facts.max_vds = le16_to_cpu(facts_data->max_vds);
+ mrioc->facts.max_hpds = le16_to_cpu(facts_data->max_host_pds);
+ mrioc->facts.max_advhpds = le16_to_cpu(facts_data->max_advanced_host_pds);
+ mrioc->facts.max_raidpds = le16_to_cpu(facts_data->max_raid_pds);
+ mrioc->facts.max_nvme = le16_to_cpu(facts_data->max_nvme);
+ mrioc->facts.max_pcie_switches =
+ le16_to_cpu(facts_data->max_pc_ie_switches);
+ mrioc->facts.max_sasexpanders =
+ le16_to_cpu(facts_data->max_sas_expanders);
+ mrioc->facts.max_sasinitiators =
+ le16_to_cpu(facts_data->max_sas_initiators);
+ mrioc->facts.max_enclosures = le16_to_cpu(facts_data->max_enclosures);
+ mrioc->facts.min_devhandle = le16_to_cpu(facts_data->min_dev_handle);
+ mrioc->facts.max_devhandle = le16_to_cpu(facts_data->max_dev_handle);
+ mrioc->facts.max_op_req_q =
+ le16_to_cpu(facts_data->max_operational_request_queues);
+ mrioc->facts.max_op_reply_q =
+ le16_to_cpu(facts_data->max_operational_reply_queues);
+ mrioc->facts.ioc_capabilities =
+ le32_to_cpu(facts_data->ioc_capabilities);
+ mrioc->facts.fw_ver.build_num =
+ le16_to_cpu(facts_data->fw_version.build_num);
+ mrioc->facts.fw_ver.cust_id =
+ le16_to_cpu(facts_data->fw_version.customer_id);
+ mrioc->facts.fw_ver.ph_minor = facts_data->fw_version.phase_minor;
+ mrioc->facts.fw_ver.ph_major = facts_data->fw_version.phase_major;
+ mrioc->facts.fw_ver.gen_minor = facts_data->fw_version.gen_minor;
+ mrioc->facts.fw_ver.gen_major = facts_data->fw_version.gen_major;
+ mrioc->msix_count = min_t(int, mrioc->msix_count,
+ mrioc->facts.max_msix_vectors);
+ mrioc->facts.sge_mod_mask = facts_data->sge_modifier_mask;
+ mrioc->facts.sge_mod_value = facts_data->sge_modifier_value;
+ mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift;
+ mrioc->facts.shutdown_timeout =
+ le16_to_cpu(facts_data->shutdown_timeout);
+
+ ioc_info(mrioc, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d),",
+ mrioc->facts.ioc_num, mrioc->facts.max_op_req_q,
+ mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle);
+ ioc_info(mrioc,
+ "maxreqs(%d), mindh(%d) maxPDs(%d) maxvectors(%d) maxperids(%d)\n",
+ mrioc->facts.max_reqs, mrioc->facts.min_devhandle,
+ mrioc->facts.max_pds, mrioc->facts.max_msix_vectors,
+ mrioc->facts.max_perids);
+ ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ",
+ mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value,
+ mrioc->facts.sge_mod_shift);
+ ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x\n",
+ mrioc->facts.dma_mask, (facts_flags &
+ MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK));
+
+ mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD;
+
+ if (reset_devices)
+ mrioc->max_host_ios = min_t(int, mrioc->max_host_ios,
+ MPI3MR_HOST_IOS_KDUMP);
+}
+
+/**
+ * mpi3mr_alloc_reply_sense_bufs - Send IOC Init
+ * @mrioc: Adapter instance reference
+ *
+ * Allocate and initialize the reply free buffers, sense
+ * buffers, reply free queue and sense buffer queue.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
+{
+ int retval = 0;
+ u32 sz, i;
+ dma_addr_t phy_addr;
+
+ if (mrioc->init_cmds.reply)
+ goto post_reply_sbuf;
+
+ mrioc->init_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL);
+ if (!mrioc->init_cmds.reply)
+ goto out_failed;
+
+ for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
+ mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->facts.reply_sz,
+ GFP_KERNEL);
+ if (!mrioc->dev_rmhs_cmds[i].reply)
+ goto out_failed;
+ }
+
+ mrioc->host_tm_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL);
+ if (!mrioc->host_tm_cmds.reply)
+ goto out_failed;
+
+ mrioc->dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8;
+ if (mrioc->facts.max_devhandle % 8)
+ mrioc->dev_handle_bitmap_sz++;
+ mrioc->removepend_bitmap = kzalloc(mrioc->dev_handle_bitmap_sz,
+ GFP_KERNEL);
+ if (!mrioc->removepend_bitmap)
+ goto out_failed;
+
+ mrioc->devrem_bitmap_sz = MPI3MR_NUM_DEVRMCMD / 8;
+ if (MPI3MR_NUM_DEVRMCMD % 8)
+ mrioc->devrem_bitmap_sz++;
+ mrioc->devrem_bitmap = kzalloc(mrioc->devrem_bitmap_sz,
+ GFP_KERNEL);
+ if (!mrioc->devrem_bitmap)
+ goto out_failed;
+
+ mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES;
+ mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1;
+ mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR;
+ mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1;
+
+ /* reply buffer pool, 16 byte align */
+ sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz;
+ mrioc->reply_buf_pool = dma_pool_create("reply_buf pool",
+ &mrioc->pdev->dev, sz, 16, 0);
+ if (!mrioc->reply_buf_pool) {
+ ioc_err(mrioc, "reply buf pool: dma_pool_create failed\n");
+ goto out_failed;
+ }
+
+ mrioc->reply_buf = dma_pool_zalloc(mrioc->reply_buf_pool, GFP_KERNEL,
+ &mrioc->reply_buf_dma);
+ if (!mrioc->reply_buf)
+ goto out_failed;
+
+ mrioc->reply_buf_dma_max_address = mrioc->reply_buf_dma + sz;
+
+ /* reply free queue, 8 byte align */
+ sz = mrioc->reply_free_qsz * 8;
+ mrioc->reply_free_q_pool = dma_pool_create("reply_free_q pool",
+ &mrioc->pdev->dev, sz, 8, 0);
+ if (!mrioc->reply_free_q_pool) {
+ ioc_err(mrioc, "reply_free_q pool: dma_pool_create failed\n");
+ goto out_failed;
+ }
+ mrioc->reply_free_q = dma_pool_zalloc(mrioc->reply_free_q_pool,
+ GFP_KERNEL, &mrioc->reply_free_q_dma);
+ if (!mrioc->reply_free_q)
+ goto out_failed;
+
+ /* sense buffer pool, 4 byte align */
+ sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ;
+ mrioc->sense_buf_pool = dma_pool_create("sense_buf pool",
+ &mrioc->pdev->dev, sz, 4, 0);
+ if (!mrioc->sense_buf_pool) {
+ ioc_err(mrioc, "sense_buf pool: dma_pool_create failed\n");
+ goto out_failed;
+ }
+ mrioc->sense_buf = dma_pool_zalloc(mrioc->sense_buf_pool, GFP_KERNEL,
+ &mrioc->sense_buf_dma);
+ if (!mrioc->sense_buf)
+ goto out_failed;
+
+ /* sense buffer queue, 8 byte align */
+ sz = mrioc->sense_buf_q_sz * 8;
+ mrioc->sense_buf_q_pool = dma_pool_create("sense_buf_q pool",
+ &mrioc->pdev->dev, sz, 8, 0);
+ if (!mrioc->sense_buf_q_pool) {
+ ioc_err(mrioc, "sense_buf_q pool: dma_pool_create failed\n");
+ goto out_failed;
+ }
+ mrioc->sense_buf_q = dma_pool_zalloc(mrioc->sense_buf_q_pool,
+ GFP_KERNEL, &mrioc->sense_buf_q_dma);
+ if (!mrioc->sense_buf_q)
+ goto out_failed;
+
+post_reply_sbuf:
+ sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz;
+ ioc_info(mrioc,
+ "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
+ mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->facts.reply_sz,
+ (sz / 1024), (unsigned long long)mrioc->reply_buf_dma);
+ sz = mrioc->reply_free_qsz * 8;
+ ioc_info(mrioc,
+ "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
+ mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024),
+ (unsigned long long)mrioc->reply_free_q_dma);
+ sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ;
+ ioc_info(mrioc,
+ "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
+ mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSEBUF_SZ,
+ (sz / 1024), (unsigned long long)mrioc->sense_buf_dma);
+ sz = mrioc->sense_buf_q_sz * 8;
+ ioc_info(mrioc,
+ "sense_buf_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n",
+ mrioc->sense_buf_q, mrioc->sense_buf_q_sz, 8, (sz / 1024),
+ (unsigned long long)mrioc->sense_buf_q_dma);
+
+ /* initialize Reply buffer Queue */
+ for (i = 0, phy_addr = mrioc->reply_buf_dma;
+ i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->facts.reply_sz)
+ mrioc->reply_free_q[i] = cpu_to_le64(phy_addr);
+ mrioc->reply_free_q[i] = cpu_to_le64(0);
+
+ /* initialize Sense Buffer Queue */
+ for (i = 0, phy_addr = mrioc->sense_buf_dma;
+ i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSEBUF_SZ)
+ mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr);
+ mrioc->sense_buf_q[i] = cpu_to_le64(0);
+ return retval;
+
+out_failed:
+ retval = -1;
+ return retval;
+}
+
+/**
+ * mpi3mr_issue_iocinit - Send IOC Init
+ * @mrioc: Adapter instance reference
+ *
+ * Issue IOC Init MPI request through admin queue and wait for
+ * the completion of it or time out.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc)
+{
+ struct mpi3_ioc_init_request iocinit_req;
+ struct mpi3_driver_info_layout *drv_info;
+ dma_addr_t data_dma;
+ u32 data_len = sizeof(*drv_info);
+ int retval = 0;
+ ktime_t current_time;
+
+ drv_info = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma,
+ GFP_KERNEL);
+ if (!drv_info) {
+ retval = -1;
+ goto out;
+ }
+ drv_info->information_length = cpu_to_le32(data_len);
+ strscpy(drv_info->driver_signature, "Broadcom", sizeof(drv_info->driver_signature));
+ strscpy(drv_info->os_name, utsname()->sysname, sizeof(drv_info->os_name));
+ strscpy(drv_info->os_version, utsname()->release, sizeof(drv_info->os_version));
+ strscpy(drv_info->driver_name, MPI3MR_DRIVER_NAME, sizeof(drv_info->driver_name));
+ strscpy(drv_info->driver_version, MPI3MR_DRIVER_VERSION, sizeof(drv_info->driver_version));
+ strscpy(drv_info->driver_release_date, MPI3MR_DRIVER_RELDATE,
+ sizeof(drv_info->driver_release_date));
+ drv_info->driver_capabilities = 0;
+ memcpy((u8 *)&mrioc->driver_info, (u8 *)drv_info,
+ sizeof(mrioc->driver_info));
+
+ memset(&iocinit_req, 0, sizeof(iocinit_req));
+ mutex_lock(&mrioc->init_cmds.mutex);
+ if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
+ retval = -1;
+ ioc_err(mrioc, "Issue IOCInit: Init command is in use\n");
+ mutex_unlock(&mrioc->init_cmds.mutex);
+ goto out;
+ }
+ mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
+ mrioc->init_cmds.is_waiting = 1;
+ mrioc->init_cmds.callback = NULL;
+ iocinit_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
+ iocinit_req.function = MPI3_FUNCTION_IOC_INIT;
+ iocinit_req.mpi_version.mpi3_version.dev = MPI3_VERSION_DEV;
+ iocinit_req.mpi_version.mpi3_version.unit = MPI3_VERSION_UNIT;
+ iocinit_req.mpi_version.mpi3_version.major = MPI3_VERSION_MAJOR;
+ iocinit_req.mpi_version.mpi3_version.minor = MPI3_VERSION_MINOR;
+ iocinit_req.who_init = MPI3_WHOINIT_HOST_DRIVER;
+ iocinit_req.reply_free_queue_depth = cpu_to_le16(mrioc->reply_free_qsz);
+ iocinit_req.reply_free_queue_address =
+ cpu_to_le64(mrioc->reply_free_q_dma);
+ iocinit_req.sense_buffer_length = cpu_to_le16(MPI3MR_SENSEBUF_SZ);
+ iocinit_req.sense_buffer_free_queue_depth =
+ cpu_to_le16(mrioc->sense_buf_q_sz);
+ iocinit_req.sense_buffer_free_queue_address =
+ cpu_to_le64(mrioc->sense_buf_q_dma);
+ iocinit_req.driver_information_address = cpu_to_le64(data_dma);
+
+ current_time = ktime_get_real();
+ iocinit_req.time_stamp = cpu_to_le64(ktime_to_ms(current_time));
+
+ init_completion(&mrioc->init_cmds.done);
+ retval = mpi3mr_admin_request_post(mrioc, &iocinit_req,
+ sizeof(iocinit_req), 1);
+ if (retval) {
+ ioc_err(mrioc, "Issue IOCInit: Admin Post failed\n");
+ goto out_unlock;
+ }
+ wait_for_completion_timeout(&mrioc->init_cmds.done,
+ (MPI3MR_INTADMCMD_TIMEOUT * HZ));
+ if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
+ mpi3mr_set_diagsave(mrioc);
+ mpi3mr_issue_reset(mrioc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
+ MPI3MR_RESET_FROM_IOCINIT_TIMEOUT);
+ mrioc->unrecoverable = 1;
+ ioc_err(mrioc, "Issue IOCInit: command timed out\n");
+ retval = -1;
+ goto out_unlock;
+ }
+ if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
+ != MPI3_IOCSTATUS_SUCCESS) {
+ ioc_err(mrioc,
+ "Issue IOCInit: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
+ (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
+ mrioc->init_cmds.ioc_loginfo);
+ retval = -1;
+ goto out_unlock;
+ }
+
+out_unlock:
+ mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
+ mutex_unlock(&mrioc->init_cmds.mutex);
+
+out:
+ if (drv_info)
+ dma_free_coherent(&mrioc->pdev->dev, data_len, drv_info,
+ data_dma);
+
+ return retval;
+}
+
+/**
+ * mpi3mr_unmask_events - Unmask events in event mask bitmap
+ * @mrioc: Adapter instance reference
+ * @event: MPI event ID
+ *
+ * Un mask the specific event by resetting the event_mask
+ * bitmap.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+static void mpi3mr_unmask_events(struct mpi3mr_ioc *mrioc, u16 event)
+{
+ u32 desired_event;
+ u8 word;
+
+ if (event >= 128)
+ return;
+
+ desired_event = (1 << (event % 32));
+ word = event / 32;
+
+ mrioc->event_masks[word] &= ~desired_event;
+}
+
+/**
+ * mpi3mr_issue_event_notification - Send event notification
+ * @mrioc: Adapter instance reference
+ *
+ * Issue event notification MPI request through admin queue and
+ * wait for the completion of it or time out.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc)
+{
+ struct mpi3_event_notification_request evtnotify_req;
+ int retval = 0;
+ u8 i;
+
+ memset(&evtnotify_req, 0, sizeof(evtnotify_req));
+ mutex_lock(&mrioc->init_cmds.mutex);
+ if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
+ retval = -1;
+ ioc_err(mrioc, "Issue EvtNotify: Init command is in use\n");
+ mutex_unlock(&mrioc->init_cmds.mutex);
+ goto out;
+ }
+ mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
+ mrioc->init_cmds.is_waiting = 1;
+ mrioc->init_cmds.callback = NULL;
+ evtnotify_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
+ evtnotify_req.function = MPI3_FUNCTION_EVENT_NOTIFICATION;
+ for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
+ evtnotify_req.event_masks[i] =
+ cpu_to_le32(mrioc->event_masks[i]);
+ init_completion(&mrioc->init_cmds.done);
+ retval = mpi3mr_admin_request_post(mrioc, &evtnotify_req,
+ sizeof(evtnotify_req), 1);
+ if (retval) {
+ ioc_err(mrioc, "Issue EvtNotify: Admin Post failed\n");
+ goto out_unlock;
+ }
+ wait_for_completion_timeout(&mrioc->init_cmds.done,
+ (MPI3MR_INTADMCMD_TIMEOUT * HZ));
+ if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
+ ioc_err(mrioc, "Issue EvtNotify: command timed out\n");
+ mpi3mr_set_diagsave(mrioc);
+ mpi3mr_issue_reset(mrioc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
+ MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT);
+ mrioc->unrecoverable = 1;
+ retval = -1;
+ goto out_unlock;
+ }
+ if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
+ != MPI3_IOCSTATUS_SUCCESS) {
+ ioc_err(mrioc,
+ "Issue EvtNotify: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
+ (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
+ mrioc->init_cmds.ioc_loginfo);
+ retval = -1;
+ goto out_unlock;
+ }
+
+out_unlock:
+ mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
+ mutex_unlock(&mrioc->init_cmds.mutex);
+out:
+ return retval;
+}
+
+/**
+ * mpi3mr_send_event_ack - Send event acknowledgment
+ * @mrioc: Adapter instance reference
+ * @event: MPI3 event ID
+ * @event_ctx: Event context
+ *
+ * Send event acknowledgment through admin queue and wait for
+ * it to complete.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+int mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
+ u32 event_ctx)
+{
+ struct mpi3_event_ack_request evtack_req;
+ int retval = 0;
+
+ memset(&evtack_req, 0, sizeof(evtack_req));
+ mutex_lock(&mrioc->init_cmds.mutex);
+ if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
+ retval = -1;
+ ioc_err(mrioc, "Send EvtAck: Init command is in use\n");
+ mutex_unlock(&mrioc->init_cmds.mutex);
+ goto out;
+ }
+ mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
+ mrioc->init_cmds.is_waiting = 1;
+ mrioc->init_cmds.callback = NULL;
+ evtack_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
+ evtack_req.function = MPI3_FUNCTION_EVENT_ACK;
+ evtack_req.event = event;
+ evtack_req.event_context = cpu_to_le32(event_ctx);
+
+ init_completion(&mrioc->init_cmds.done);
+ retval = mpi3mr_admin_request_post(mrioc, &evtack_req,
+ sizeof(evtack_req), 1);
+ if (retval) {
+ ioc_err(mrioc, "Send EvtAck: Admin Post failed\n");
+ goto out_unlock;
+ }
+ wait_for_completion_timeout(&mrioc->init_cmds.done,
+ (MPI3MR_INTADMCMD_TIMEOUT * HZ));
+ if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
+ ioc_err(mrioc, "Issue EvtNotify: command timed out\n");
+ mpi3mr_soft_reset_handler(mrioc,
+ MPI3MR_RESET_FROM_EVTACK_TIMEOUT, 1);
+ retval = -1;
+ goto out_unlock;
+ }
+ if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
+ != MPI3_IOCSTATUS_SUCCESS) {
+ ioc_err(mrioc,
+ "Send EvtAck: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
+ (mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
+ mrioc->init_cmds.ioc_loginfo);
+ retval = -1;
+ goto out_unlock;
+ }
+
+out_unlock:
+ mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
+ mutex_unlock(&mrioc->init_cmds.mutex);
+out:
+ return retval;
+}
+
+/**
+ * mpi3mr_alloc_chain_bufs - Allocate chain buffers
+ * @mrioc: Adapter instance reference
+ *
+ * Allocate chain buffers and set a bitmap to indicate free
+ * chain buffers. Chain buffers are used to pass the SGE
+ * information along with MPI3 SCSI IO requests for host I/O.
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc)
+{
+ int retval = 0;
+ u32 sz, i;
+ u16 num_chains;
+
+ num_chains = mrioc->max_host_ios / MPI3MR_CHAINBUF_FACTOR;
+
+ if (prot_mask & (SHOST_DIX_TYPE0_PROTECTION
+ | SHOST_DIX_TYPE1_PROTECTION
+ | SHOST_DIX_TYPE2_PROTECTION
+ | SHOST_DIX_TYPE3_PROTECTION))
+ num_chains += (num_chains / MPI3MR_CHAINBUFDIX_FACTOR);
+
+ mrioc->chain_buf_count = num_chains;
+ sz = sizeof(struct chain_element) * num_chains;
+ mrioc->chain_sgl_list = kzalloc(sz, GFP_KERNEL);
+ if (!mrioc->chain_sgl_list)
+ goto out_failed;
+
+ sz = MPI3MR_PAGE_SIZE_4K;
+ mrioc->chain_buf_pool = dma_pool_create("chain_buf pool",
+ &mrioc->pdev->dev, sz, 16, 0);
+ if (!mrioc->chain_buf_pool) {
+ ioc_err(mrioc, "chain buf pool: dma_pool_create failed\n");
+ goto out_failed;
+ }
+
+ for (i = 0; i < num_chains; i++) {
+ mrioc->chain_sgl_list[i].addr =
+ dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL,
+ &mrioc->chain_sgl_list[i].dma_addr);
+
+ if (!mrioc->chain_sgl_list[i].addr)
+ goto out_failed;
+ }
+ mrioc->chain_bitmap_sz = num_chains / 8;
+ if (num_chains % 8)
+ mrioc->chain_bitmap_sz++;
+ mrioc->chain_bitmap = kzalloc(mrioc->chain_bitmap_sz, GFP_KERNEL);
+ if (!mrioc->chain_bitmap)
+ goto out_failed;
+ return retval;
+out_failed:
+ retval = -1;
+ return retval;
+}
+
+/**
+ * mpi3mr_port_enable_complete - Mark port enable complete
+ * @mrioc: Adapter instance reference
+ * @drv_cmd: Internal command tracker
+ *
+ * Call back for asynchronous port enable request sets the
+ * driver command to indicate port enable request is complete.
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_port_enable_complete(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_drv_cmd *drv_cmd)
+{
+ drv_cmd->state = MPI3MR_CMD_NOTUSED;
+ drv_cmd->callback = NULL;
+ mrioc->scan_failed = drv_cmd->ioc_status;
+ mrioc->scan_started = 0;
+}
+
+/**
+ * mpi3mr_issue_port_enable - Issue Port Enable
+ * @mrioc: Adapter instance reference
+ * @async: Flag to wait for completion or not
+ *
+ * Issue Port Enable MPI request through admin queue and if the
+ * async flag is not set wait for the completion of the port
+ * enable or time out.
+ *
+ * Return: 0 on success, non-zero on failures.
+ */
+int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async)
+{
+ struct mpi3_port_enable_request pe_req;
+ int retval = 0;
+ u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT;
+
+ memset(&pe_req, 0, sizeof(pe_req));
+ mutex_lock(&mrioc->init_cmds.mutex);
+ if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) {
+ retval = -1;
+ ioc_err(mrioc, "Issue PortEnable: Init command is in use\n");
+ mutex_unlock(&mrioc->init_cmds.mutex);
+ goto out;
+ }
+ mrioc->init_cmds.state = MPI3MR_CMD_PENDING;
+ if (async) {
+ mrioc->init_cmds.is_waiting = 0;
+ mrioc->init_cmds.callback = mpi3mr_port_enable_complete;
+ } else {
+ mrioc->init_cmds.is_waiting = 1;
+ mrioc->init_cmds.callback = NULL;
+ init_completion(&mrioc->init_cmds.done);
+ }
+ pe_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS);
+ pe_req.function = MPI3_FUNCTION_PORT_ENABLE;
+
+ retval = mpi3mr_admin_request_post(mrioc, &pe_req, sizeof(pe_req), 1);
+ if (retval) {
+ ioc_err(mrioc, "Issue PortEnable: Admin Post failed\n");
+ goto out_unlock;
+ }
+ if (!async) {
+ wait_for_completion_timeout(&mrioc->init_cmds.done,
+ (pe_timeout * HZ));
+ if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
+ ioc_err(mrioc, "Issue PortEnable: command timed out\n");
+ retval = -1;
+ mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR;
+ mpi3mr_set_diagsave(mrioc);
+ mpi3mr_issue_reset(mrioc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
+ MPI3MR_RESET_FROM_PE_TIMEOUT);
+ mrioc->unrecoverable = 1;
+ goto out_unlock;
+ }
+ mpi3mr_port_enable_complete(mrioc, &mrioc->init_cmds);
+ }
+out_unlock:
+ mutex_unlock(&mrioc->init_cmds.mutex);
+out:
+ return retval;
+}
+
+/* Protocol type to name mapper structure*/
+static const struct {
+ u8 protocol;
+ char *name;
+} mpi3mr_protocols[] = {
+ { MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR, "Initiator" },
+ { MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET, "Target" },
+ { MPI3_IOCFACTS_PROTOCOL_NVME, "NVMe attachment" },
+};
+
+/* Capability to name mapper structure*/
+static const struct {
+ u32 capability;
+ char *name;
+} mpi3mr_capabilities[] = {
+ { MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE, "RAID" },
+};
+
+/**
+ * mpi3mr_print_ioc_info - Display controller information
+ * @mrioc: Adapter instance reference
+ *
+ * Display controller personalit, capability, supported
+ * protocols etc.
+ *
+ * Return: Nothing
+ */
+static void
+mpi3mr_print_ioc_info(struct mpi3mr_ioc *mrioc)
+{
+ int i = 0, bytes_wrote = 0;
+ char personality[16];
+ char protocol[50] = {0};
+ char capabilities[100] = {0};
+ bool is_string_nonempty = false;
+ struct mpi3mr_compimg_ver *fwver = &mrioc->facts.fw_ver;
+
+ switch (mrioc->facts.personality) {
+ case MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA:
+ strncpy(personality, "Enhanced HBA", sizeof(personality));
+ break;
+ case MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR:
+ strncpy(personality, "RAID", sizeof(personality));
+ break;
+ default:
+ strncpy(personality, "Unknown", sizeof(personality));
+ break;
+ }
+
+ ioc_info(mrioc, "Running in %s Personality", personality);
+
+ ioc_info(mrioc, "FW version(%d.%d.%d.%d.%d.%d)\n",
+ fwver->gen_major, fwver->gen_minor, fwver->ph_major,
+ fwver->ph_minor, fwver->cust_id, fwver->build_num);
+
+ for (i = 0; i < ARRAY_SIZE(mpi3mr_protocols); i++) {
+ if (mrioc->facts.protocol_flags &
+ mpi3mr_protocols[i].protocol) {
+ if (is_string_nonempty &&
+ (bytes_wrote < sizeof(protocol)))
+ bytes_wrote += snprintf(protocol + bytes_wrote,
+ (sizeof(protocol) - bytes_wrote), ",");
+
+ if (bytes_wrote < sizeof(protocol))
+ bytes_wrote += snprintf(protocol + bytes_wrote,
+ (sizeof(protocol) - bytes_wrote), "%s",
+ mpi3mr_protocols[i].name);
+ is_string_nonempty = true;
+ }
+ }
+
+ bytes_wrote = 0;
+ is_string_nonempty = false;
+ for (i = 0; i < ARRAY_SIZE(mpi3mr_capabilities); i++) {
+ if (mrioc->facts.protocol_flags &
+ mpi3mr_capabilities[i].capability) {
+ if (is_string_nonempty &&
+ (bytes_wrote < sizeof(capabilities)))
+ bytes_wrote += snprintf(capabilities + bytes_wrote,
+ (sizeof(capabilities) - bytes_wrote), ",");
+
+ if (bytes_wrote < sizeof(capabilities))
+ bytes_wrote += snprintf(capabilities + bytes_wrote,
+ (sizeof(capabilities) - bytes_wrote), "%s",
+ mpi3mr_capabilities[i].name);
+ is_string_nonempty = true;
+ }
+ }
+
+ ioc_info(mrioc, "Protocol=(%s), Capabilities=(%s)\n",
+ protocol, capabilities);
+}
+
+/**
+ * mpi3mr_cleanup_resources - Free PCI resources
+ * @mrioc: Adapter instance reference
+ *
+ * Unmap PCI device memory and disable PCI device.
+ *
+ * Return: 0 on success and non-zero on failure.
+ */
+void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc)
+{
+ struct pci_dev *pdev = mrioc->pdev;
+
+ mpi3mr_cleanup_isr(mrioc);
+
+ if (mrioc->sysif_regs) {
+ iounmap((void __iomem *)mrioc->sysif_regs);
+ mrioc->sysif_regs = NULL;
+ }
+
+ if (pci_is_enabled(pdev)) {
+ if (mrioc->bars)
+ pci_release_selected_regions(pdev, mrioc->bars);
+ pci_disable_device(pdev);
+ }
+}
+
+/**
+ * mpi3mr_setup_resources - Enable PCI resources
+ * @mrioc: Adapter instance reference
+ *
+ * Enable PCI device memory, MSI-x registers and set DMA mask.
+ *
+ * Return: 0 on success and non-zero on failure.
+ */
+int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc)
+{
+ struct pci_dev *pdev = mrioc->pdev;
+ u32 memap_sz = 0;
+ int i, retval = 0, capb = 0;
+ u16 message_control;
+ u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask :
+ (((dma_get_required_mask(&pdev->dev) > DMA_BIT_MASK(32)) &&
+ (sizeof(dma_addr_t) > 4)) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
+
+ if (pci_enable_device_mem(pdev)) {
+ ioc_err(mrioc, "pci_enable_device_mem: failed\n");
+ retval = -ENODEV;
+ goto out_failed;
+ }
+
+ capb = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+ if (!capb) {
+ ioc_err(mrioc, "Unable to find MSI-X Capabilities\n");
+ retval = -ENODEV;
+ goto out_failed;
+ }
+ mrioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
+
+ if (pci_request_selected_regions(pdev, mrioc->bars,
+ mrioc->driver_name)) {
+ ioc_err(mrioc, "pci_request_selected_regions: failed\n");
+ retval = -ENODEV;
+ goto out_failed;
+ }
+
+ for (i = 0; (i < DEVICE_COUNT_RESOURCE); i++) {
+ if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
+ mrioc->sysif_regs_phys = pci_resource_start(pdev, i);
+ memap_sz = pci_resource_len(pdev, i);
+ mrioc->sysif_regs =
+ ioremap(mrioc->sysif_regs_phys, memap_sz);
+ break;
+ }
+ }
+
+ pci_set_master(pdev);
+
+ retval = dma_set_mask_and_coherent(&pdev->dev, dma_mask);
+ if (retval) {
+ if (dma_mask != DMA_BIT_MASK(32)) {
+ ioc_warn(mrioc, "Setting 64 bit DMA mask failed\n");
+ dma_mask = DMA_BIT_MASK(32);
+ retval = dma_set_mask_and_coherent(&pdev->dev,
+ dma_mask);
+ }
+ if (retval) {
+ mrioc->dma_mask = 0;
+ ioc_err(mrioc, "Setting 32 bit DMA mask also failed\n");
+ goto out_failed;
+ }
+ }
+ mrioc->dma_mask = dma_mask;
+
+ if (!mrioc->sysif_regs) {
+ ioc_err(mrioc,
+ "Unable to map adapter memory or resource not found\n");
+ retval = -EINVAL;
+ goto out_failed;
+ }
+
+ pci_read_config_word(pdev, capb + 2, &message_control);
+ mrioc->msix_count = (message_control & 0x3FF) + 1;
+
+ pci_save_state(pdev);
+
+ pci_set_drvdata(pdev, mrioc->shost);
+
+ mpi3mr_ioc_disable_intr(mrioc);
+
+ ioc_info(mrioc, "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
+ (unsigned long long)mrioc->sysif_regs_phys,
+ mrioc->sysif_regs, memap_sz);
+ ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n",
+ mrioc->msix_count);
+ return retval;
+
+out_failed:
+ mpi3mr_cleanup_resources(mrioc);
+ return retval;
+}
+
+/**
+ * mpi3mr_init_ioc - Initialize the controller
+ * @mrioc: Adapter instance reference
+ * @re_init: Flag to indicate is this fresh init or re-init
+ *
+ * This the controller initialization routine, executed either
+ * after soft reset or from pci probe callback.
+ * Setup the required resources, memory map the controller
+ * registers, create admin and operational reply queue pairs,
+ * allocate required memory for reply pool, sense buffer pool,
+ * issue IOC init request to the firmware, unmask the events and
+ * issue port enable to discover SAS/SATA/NVMe devies and RAID
+ * volumes.
+ *
+ * Return: 0 on success and non-zero on failure.
+ */
+int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 re_init)
+{
+ int retval = 0;
+ enum mpi3mr_iocstate ioc_state;
+ u64 base_info;
+ u32 timeout;
+ u32 ioc_status, ioc_config, i;
+ struct mpi3_ioc_facts_data facts_data;
+
+ mrioc->irqpoll_sleep = MPI3MR_IRQ_POLL_SLEEP;
+ mrioc->change_count = 0;
+ if (!re_init) {
+ mrioc->cpu_count = num_online_cpus();
+ retval = mpi3mr_setup_resources(mrioc);
+ if (retval) {
+ ioc_err(mrioc, "Failed to setup resources:error %d\n",
+ retval);
+ goto out_nocleanup;
+ }
+ }
+
+ ioc_status = readl(&mrioc->sysif_regs->ioc_status);
+ ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
+
+ ioc_info(mrioc, "SOD status %x configuration %x\n",
+ ioc_status, ioc_config);
+
+ base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information);
+ ioc_info(mrioc, "SOD base_info %llx\n", base_info);
+
+ /*The timeout value is in 2sec unit, changing it to seconds*/
+ mrioc->ready_timeout =
+ ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
+ MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2;
+
+ ioc_info(mrioc, "IOC ready timeout %d\n", mrioc->ready_timeout);
+
+ ioc_state = mpi3mr_get_iocstate(mrioc);
+ ioc_info(mrioc, "IOC in %s state during detection\n",
+ mpi3mr_iocstate_name(ioc_state));
+
+ if (ioc_state == MRIOC_STATE_BECOMING_READY ||
+ ioc_state == MRIOC_STATE_RESET_REQUESTED) {
+ timeout = mrioc->ready_timeout * 10;
+ do {
+ msleep(100);
+ } while (--timeout);
+
+ ioc_state = mpi3mr_get_iocstate(mrioc);
+ ioc_info(mrioc,
+ "IOC in %s state after waiting for reset time\n",
+ mpi3mr_iocstate_name(ioc_state));
+ }
+
+ if (ioc_state == MRIOC_STATE_READY) {
+ retval = mpi3mr_issue_and_process_mur(mrioc,
+ MPI3MR_RESET_FROM_BRINGUP);
+ if (retval) {
+ ioc_err(mrioc, "Failed to MU reset IOC error %d\n",
+ retval);
+ }
+ ioc_state = mpi3mr_get_iocstate(mrioc);
+ }
+ if (ioc_state != MRIOC_STATE_RESET) {
+ mpi3mr_print_fault_info(mrioc);
+ retval = mpi3mr_issue_reset(mrioc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
+ MPI3MR_RESET_FROM_BRINGUP);
+ if (retval) {
+ ioc_err(mrioc,
+ "%s :Failed to soft reset IOC error %d\n",
+ __func__, retval);
+ goto out_failed;
+ }
+ }
+ ioc_state = mpi3mr_get_iocstate(mrioc);
+ if (ioc_state != MRIOC_STATE_RESET) {
+ retval = -1;
+ ioc_err(mrioc, "Cannot bring IOC to reset state\n");
+ goto out_failed;
+ }
+
+ retval = mpi3mr_setup_admin_qpair(mrioc);
+ if (retval) {
+ ioc_err(mrioc, "Failed to setup admin Qs: error %d\n",
+ retval);
+ goto out_failed;
+ }
+
+ retval = mpi3mr_bring_ioc_ready(mrioc);
+ if (retval) {
+ ioc_err(mrioc, "Failed to bring ioc ready: error %d\n",
+ retval);
+ goto out_failed;
+ }
+
+ if (!re_init) {
+ retval = mpi3mr_setup_isr(mrioc, 1);
+ if (retval) {
+ ioc_err(mrioc, "Failed to setup ISR error %d\n",
+ retval);
+ goto out_failed;
+ }
+ } else
+ mpi3mr_ioc_enable_intr(mrioc);
+
+ retval = mpi3mr_issue_iocfacts(mrioc, &facts_data);
+ if (retval) {
+ ioc_err(mrioc, "Failed to Issue IOC Facts %d\n",
+ retval);
+ goto out_failed;
+ }
+
+ mpi3mr_process_factsdata(mrioc, &facts_data);
+ if (!re_init) {
+ retval = mpi3mr_check_reset_dma_mask(mrioc);
+ if (retval) {
+ ioc_err(mrioc, "Resetting dma mask failed %d\n",
+ retval);
+ goto out_failed;
+ }
+ }
+
+ mpi3mr_print_ioc_info(mrioc);
+
+ retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
+ if (retval) {
+ ioc_err(mrioc,
+ "%s :Failed to allocated reply sense buffers %d\n",
+ __func__, retval);
+ goto out_failed;
+ }
+
+ if (!re_init) {
+ retval = mpi3mr_alloc_chain_bufs(mrioc);
+ if (retval) {
+ ioc_err(mrioc, "Failed to allocated chain buffers %d\n",
+ retval);
+ goto out_failed;
+ }
+ }
+
+ retval = mpi3mr_issue_iocinit(mrioc);
+ if (retval) {
+ ioc_err(mrioc, "Failed to Issue IOC Init %d\n",
+ retval);
+ goto out_failed;
+ }
+ mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs;
+ writel(mrioc->reply_free_queue_host_index,
+ &mrioc->sysif_regs->reply_free_host_index);
+
+ mrioc->sbq_host_index = mrioc->num_sense_bufs;
+ writel(mrioc->sbq_host_index,
+ &mrioc->sysif_regs->sense_buffer_free_host_index);
+
+ if (!re_init) {
+ retval = mpi3mr_setup_isr(mrioc, 0);
+ if (retval) {
+ ioc_err(mrioc, "Failed to re-setup ISR, error %d\n",
+ retval);
+ goto out_failed;
+ }
+ }
+
+ retval = mpi3mr_create_op_queues(mrioc);
+ if (retval) {
+ ioc_err(mrioc, "Failed to create OpQueues error %d\n",
+ retval);
+ goto out_failed;
+ }
+
+ if (re_init &&
+ (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q)) {
+ retval = -1;
+ ioc_err(mrioc,
+ "Cannot create minimum number of OpQueues expected:%d created:%d\n",
+ mrioc->shost->nr_hw_queues, mrioc->num_op_reply_q);
+ goto out_failed;
+ }
+
+ for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
+ mrioc->event_masks[i] = -1;
+
+ mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED);
+ mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED);
+ mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE);
+ mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE);
+ mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
+ mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY);
+ mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR);
+ mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE);
+ mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST);
+ mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION);
+ mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT);
+ mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE);
+
+ retval = mpi3mr_issue_event_notification(mrioc);
+ if (retval) {
+ ioc_err(mrioc, "Failed to issue event notification %d\n",
+ retval);
+ goto out_failed;
+ }
+
+ if (re_init) {
+ ioc_info(mrioc, "Issuing Port Enable\n");
+ retval = mpi3mr_issue_port_enable(mrioc, 0);
+ if (retval) {
+ ioc_err(mrioc, "Failed to issue port enable %d\n",
+ retval);
+ goto out_failed;
+ }
+ }
+ return retval;
+
+out_failed:
+ mpi3mr_cleanup_ioc(mrioc, re_init);
+out_nocleanup:
+ return retval;
+}
+
+/**
+ * mpi3mr_memset_op_reply_q_buffers - memset the operational reply queue's
+ * segments
+ * @mrioc: Adapter instance reference
+ * @qidx: Operational reply queue index
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_memset_op_reply_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx)
+{
+ struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx;
+ struct segments *segments;
+ int i, size;
+
+ if (!op_reply_q->q_segments)
+ return;
+
+ size = op_reply_q->segment_qd * mrioc->op_reply_desc_sz;
+ segments = op_reply_q->q_segments;
+ for (i = 0; i < op_reply_q->num_segments; i++)
+ memset(segments[i].segment, 0, size);
+}
+
+/**
+ * mpi3mr_memset_op_req_q_buffers - memset the operational request queue's
+ * segments
+ * @mrioc: Adapter instance reference
+ * @qidx: Operational request queue index
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_memset_op_req_q_buffers(struct mpi3mr_ioc *mrioc, u16 qidx)
+{
+ struct op_req_qinfo *op_req_q = mrioc->req_qinfo + qidx;
+ struct segments *segments;
+ int i, size;
+
+ if (!op_req_q->q_segments)
+ return;
+
+ size = op_req_q->segment_qd * mrioc->facts.op_req_sz;
+ segments = op_req_q->q_segments;
+ for (i = 0; i < op_req_q->num_segments; i++)
+ memset(segments[i].segment, 0, size);
+}
+
+/**
+ * mpi3mr_memset_buffers - memset memory for a controller
+ * @mrioc: Adapter instance reference
+ *
+ * clear all the memory allocated for a controller, typically
+ * called post reset to reuse the memory allocated during the
+ * controller init.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
+{
+ u16 i;
+
+ memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz);
+ memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz);
+
+ memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply));
+ memset(mrioc->host_tm_cmds.reply, 0,
+ sizeof(*mrioc->host_tm_cmds.reply));
+ for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
+ memset(mrioc->dev_rmhs_cmds[i].reply, 0,
+ sizeof(*mrioc->dev_rmhs_cmds[i].reply));
+ memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz);
+ memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz);
+
+ for (i = 0; i < mrioc->num_queues; i++) {
+ mrioc->op_reply_qinfo[i].qid = 0;
+ mrioc->op_reply_qinfo[i].ci = 0;
+ mrioc->op_reply_qinfo[i].num_replies = 0;
+ mrioc->op_reply_qinfo[i].ephase = 0;
+ atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0);
+ atomic_set(&mrioc->op_reply_qinfo[i].in_use, 0);
+ mpi3mr_memset_op_reply_q_buffers(mrioc, i);
+
+ mrioc->req_qinfo[i].ci = 0;
+ mrioc->req_qinfo[i].pi = 0;
+ mrioc->req_qinfo[i].num_requests = 0;
+ mrioc->req_qinfo[i].qid = 0;
+ mrioc->req_qinfo[i].reply_qid = 0;
+ spin_lock_init(&mrioc->req_qinfo[i].q_lock);
+ mpi3mr_memset_op_req_q_buffers(mrioc, i);
+ }
+}
+
+/**
+ * mpi3mr_free_mem - Free memory allocated for a controller
+ * @mrioc: Adapter instance reference
+ *
+ * Free all the memory allocated for a controller.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
+{
+ u16 i;
+ struct mpi3mr_intr_info *intr_info;
+
+ if (mrioc->sense_buf_pool) {
+ if (mrioc->sense_buf)
+ dma_pool_free(mrioc->sense_buf_pool, mrioc->sense_buf,
+ mrioc->sense_buf_dma);
+ dma_pool_destroy(mrioc->sense_buf_pool);
+ mrioc->sense_buf = NULL;
+ mrioc->sense_buf_pool = NULL;
+ }
+ if (mrioc->sense_buf_q_pool) {
+ if (mrioc->sense_buf_q)
+ dma_pool_free(mrioc->sense_buf_q_pool,
+ mrioc->sense_buf_q, mrioc->sense_buf_q_dma);
+ dma_pool_destroy(mrioc->sense_buf_q_pool);
+ mrioc->sense_buf_q = NULL;
+ mrioc->sense_buf_q_pool = NULL;
+ }
+
+ if (mrioc->reply_buf_pool) {
+ if (mrioc->reply_buf)
+ dma_pool_free(mrioc->reply_buf_pool, mrioc->reply_buf,
+ mrioc->reply_buf_dma);
+ dma_pool_destroy(mrioc->reply_buf_pool);
+ mrioc->reply_buf = NULL;
+ mrioc->reply_buf_pool = NULL;
+ }
+ if (mrioc->reply_free_q_pool) {
+ if (mrioc->reply_free_q)
+ dma_pool_free(mrioc->reply_free_q_pool,
+ mrioc->reply_free_q, mrioc->reply_free_q_dma);
+ dma_pool_destroy(mrioc->reply_free_q_pool);
+ mrioc->reply_free_q = NULL;
+ mrioc->reply_free_q_pool = NULL;
+ }
+
+ for (i = 0; i < mrioc->num_op_req_q; i++)
+ mpi3mr_free_op_req_q_segments(mrioc, i);
+
+ for (i = 0; i < mrioc->num_op_reply_q; i++)
+ mpi3mr_free_op_reply_q_segments(mrioc, i);
+
+ for (i = 0; i < mrioc->intr_info_count; i++) {
+ intr_info = mrioc->intr_info + i;
+ intr_info->op_reply_q = NULL;
+ }
+
+ kfree(mrioc->req_qinfo);
+ mrioc->req_qinfo = NULL;
+ mrioc->num_op_req_q = 0;
+
+ kfree(mrioc->op_reply_qinfo);
+ mrioc->op_reply_qinfo = NULL;
+ mrioc->num_op_reply_q = 0;
+
+ kfree(mrioc->init_cmds.reply);
+ mrioc->init_cmds.reply = NULL;
+
+ kfree(mrioc->host_tm_cmds.reply);
+ mrioc->host_tm_cmds.reply = NULL;
+
+ kfree(mrioc->removepend_bitmap);
+ mrioc->removepend_bitmap = NULL;
+
+ kfree(mrioc->devrem_bitmap);
+ mrioc->devrem_bitmap = NULL;
+
+ kfree(mrioc->chain_bitmap);
+ mrioc->chain_bitmap = NULL;
+
+ for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
+ kfree(mrioc->dev_rmhs_cmds[i].reply);
+ mrioc->dev_rmhs_cmds[i].reply = NULL;
+ }
+
+ if (mrioc->chain_buf_pool) {
+ for (i = 0; i < mrioc->chain_buf_count; i++) {
+ if (mrioc->chain_sgl_list[i].addr) {
+ dma_pool_free(mrioc->chain_buf_pool,
+ mrioc->chain_sgl_list[i].addr,
+ mrioc->chain_sgl_list[i].dma_addr);
+ mrioc->chain_sgl_list[i].addr = NULL;
+ }
+ }
+ dma_pool_destroy(mrioc->chain_buf_pool);
+ mrioc->chain_buf_pool = NULL;
+ }
+
+ kfree(mrioc->chain_sgl_list);
+ mrioc->chain_sgl_list = NULL;
+
+ if (mrioc->admin_reply_base) {
+ dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_reply_q_sz,
+ mrioc->admin_reply_base, mrioc->admin_reply_dma);
+ mrioc->admin_reply_base = NULL;
+ }
+ if (mrioc->admin_req_base) {
+ dma_free_coherent(&mrioc->pdev->dev, mrioc->admin_req_q_sz,
+ mrioc->admin_req_base, mrioc->admin_req_dma);
+ mrioc->admin_req_base = NULL;
+ }
+}
+
+/**
+ * mpi3mr_issue_ioc_shutdown - shutdown controller
+ * @mrioc: Adapter instance reference
+ *
+ * Send shutodwn notification to the controller and wait for the
+ * shutdown_timeout for it to be completed.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc)
+{
+ u32 ioc_config, ioc_status;
+ u8 retval = 1;
+ u32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10;
+
+ ioc_info(mrioc, "Issuing shutdown Notification\n");
+ if (mrioc->unrecoverable) {
+ ioc_warn(mrioc,
+ "IOC is unrecoverable shutdown is not issued\n");
+ return;
+ }
+ ioc_status = readl(&mrioc->sysif_regs->ioc_status);
+ if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
+ == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) {
+ ioc_info(mrioc, "shutdown already in progress\n");
+ return;
+ }
+
+ ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
+ ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
+ ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN;
+
+ writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
+
+ if (mrioc->facts.shutdown_timeout)
+ timeout = mrioc->facts.shutdown_timeout * 10;
+
+ do {
+ ioc_status = readl(&mrioc->sysif_regs->ioc_status);
+ if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
+ == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) {
+ retval = 0;
+ break;
+ }
+ msleep(100);
+ } while (--timeout);
+
+ ioc_status = readl(&mrioc->sysif_regs->ioc_status);
+ ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
+
+ if (retval) {
+ if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
+ == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS)
+ ioc_warn(mrioc,
+ "shutdown still in progress after timeout\n");
+ }
+
+ ioc_info(mrioc,
+ "Base IOC Sts/Config after %s shutdown is (0x%x)/(0x%x)\n",
+ (!retval) ? "successful" : "failed", ioc_status,
+ ioc_config);
+}
+
+/**
+ * mpi3mr_cleanup_ioc - Cleanup controller
+ * @mrioc: Adapter instance reference
+ * @re_init: Cleanup due to a reinit or not
+ *
+ * controller cleanup handler, Message unit reset or soft reset
+ * and shutdown notification is issued to the controller and the
+ * associated memory resources are freed.
+ *
+ * Return: Nothing.
+ */
+void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc, u8 re_init)
+{
+ enum mpi3mr_iocstate ioc_state;
+
+ if (!re_init)
+ mpi3mr_stop_watchdog(mrioc);
+
+ mpi3mr_ioc_disable_intr(mrioc);
+
+ ioc_state = mpi3mr_get_iocstate(mrioc);
+
+ if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) &&
+ (ioc_state == MRIOC_STATE_READY)) {
+ if (mpi3mr_issue_and_process_mur(mrioc,
+ MPI3MR_RESET_FROM_CTLR_CLEANUP))
+ mpi3mr_issue_reset(mrioc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
+ MPI3MR_RESET_FROM_MUR_FAILURE);
+
+ if (!re_init)
+ mpi3mr_issue_ioc_shutdown(mrioc);
+ }
+
+ if (!re_init) {
+ mpi3mr_free_mem(mrioc);
+ mpi3mr_cleanup_resources(mrioc);
+ }
+}
+
+/**
+ * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command
+ * @mrioc: Adapter instance reference
+ * @cmdptr: Internal command tracker
+ *
+ * Complete an internal driver commands with state indicating it
+ * is completed due to reset.
+ *
+ * Return: Nothing.
+ */
+static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_drv_cmd *cmdptr)
+{
+ if (cmdptr->state & MPI3MR_CMD_PENDING) {
+ cmdptr->state |= MPI3MR_CMD_RESET;
+ cmdptr->state &= ~MPI3MR_CMD_PENDING;
+ if (cmdptr->is_waiting) {
+ complete(&cmdptr->done);
+ cmdptr->is_waiting = 0;
+ } else if (cmdptr->callback)
+ cmdptr->callback(mrioc, cmdptr);
+ }
+}
+
+/**
+ * mpi3mr_flush_drv_cmds - Flush internaldriver commands
+ * @mrioc: Adapter instance reference
+ *
+ * Flush all internal driver commands post reset
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
+{
+ struct mpi3mr_drv_cmd *cmdptr;
+ u8 i;
+
+ cmdptr = &mrioc->init_cmds;
+ mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
+ cmdptr = &mrioc->host_tm_cmds;
+ mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
+
+ for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
+ cmdptr = &mrioc->dev_rmhs_cmds[i];
+ mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
+ }
+}
+
+/**
+ * mpi3mr_diagfault_reset_handler - Diag fault reset handler
+ * @mrioc: Adapter instance reference
+ * @reset_reason: Reset reason code
+ *
+ * This is an handler for issuing diag fault reset from the
+ * applications through IOCTL path to stop the execution of the
+ * controller
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_diagfault_reset_handler(struct mpi3mr_ioc *mrioc,
+ u32 reset_reason)
+{
+ int retval = 0;
+
+ ioc_info(mrioc, "Entry: reason code: %s\n",
+ mpi3mr_reset_rc_name(reset_reason));
+ mrioc->reset_in_progress = 1;
+
+ mpi3mr_ioc_disable_intr(mrioc);
+
+ retval = mpi3mr_issue_reset(mrioc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
+
+ if (retval) {
+ ioc_err(mrioc, "The diag fault reset failed: reason %d\n",
+ reset_reason);
+ mpi3mr_ioc_enable_intr(mrioc);
+ }
+ ioc_info(mrioc, "%s\n", ((retval == 0) ? "SUCCESS" : "FAILED"));
+ mrioc->reset_in_progress = 0;
+ return retval;
+}
+
+/**
+ * mpi3mr_soft_reset_handler - Reset the controller
+ * @mrioc: Adapter instance reference
+ * @reset_reason: Reset reason code
+ * @snapdump: Flag to generate snapdump in firmware or not
+ *
+ * This is an handler for recovering controller by issuing soft
+ * reset are diag fault reset. This is a blocking function and
+ * when one reset is executed if any other resets they will be
+ * blocked. All IOCTLs/IO will be blocked during the reset. If
+ * controller reset is successful then the controller will be
+ * reinitalized, otherwise the controller will be marked as not
+ * recoverable
+ *
+ * In snapdump bit is set, the controller is issued with diag
+ * fault reset so that the firmware can create a snap dump and
+ * post that the firmware will result in F000 fault and the
+ * driver will issue soft reset to recover from that.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
+ u32 reset_reason, u8 snapdump)
+{
+ int retval = 0, i;
+ unsigned long flags;
+ u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
+
+ if (mrioc->fault_dbg) {
+ if (snapdump)
+ mpi3mr_set_diagsave(mrioc);
+ mpi3mr_kill_ioc(mrioc, reset_reason);
+ }
+
+ /*
+ * Block new resets until the currently executing one is finished and
+ * return the status of the existing reset for all blocked resets
+ */
+ if (!mutex_trylock(&mrioc->reset_mutex)) {
+ ioc_info(mrioc, "Another reset in progress\n");
+ return -1;
+ }
+ mrioc->reset_in_progress = 1;
+
+ if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) &&
+ (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) {
+ for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
+ mrioc->event_masks[i] = -1;
+
+ retval = mpi3mr_issue_event_notification(mrioc);
+
+ if (retval) {
+ ioc_err(mrioc,
+ "Failed to turn off events prior to reset %d\n",
+ retval);
+ }
+ }
+
+ mpi3mr_wait_for_host_io(mrioc, MPI3MR_RESET_HOST_IOWAIT_TIMEOUT);
+
+ mpi3mr_ioc_disable_intr(mrioc);
+
+ if (snapdump) {
+ mpi3mr_set_diagsave(mrioc);
+ retval = mpi3mr_issue_reset(mrioc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
+ if (!retval) {
+ do {
+ host_diagnostic =
+ readl(&mrioc->sysif_regs->host_diagnostic);
+ if (!(host_diagnostic &
+ MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
+ break;
+ msleep(100);
+ } while (--timeout);
+ }
+ }
+
+ retval = mpi3mr_issue_reset(mrioc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason);
+ if (retval) {
+ ioc_err(mrioc, "Failed to issue soft reset to the ioc\n");
+ goto out;
+ }
+
+ mpi3mr_flush_delayed_rmhs_list(mrioc);
+ mpi3mr_flush_drv_cmds(mrioc);
+ memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz);
+ memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz);
+ mpi3mr_cleanup_fwevt_list(mrioc);
+ mpi3mr_flush_host_io(mrioc);
+ mpi3mr_invalidate_devhandles(mrioc);
+ mpi3mr_memset_buffers(mrioc);
+ retval = mpi3mr_init_ioc(mrioc, 1);
+ if (retval) {
+ pr_err(IOCNAME "reinit after soft reset failed: reason %d\n",
+ mrioc->name, reset_reason);
+ goto out;
+ }
+ ssleep(10);
+
+out:
+ if (!retval) {
+ mrioc->reset_in_progress = 0;
+ scsi_unblock_requests(mrioc->shost);
+ mpi3mr_rfresh_tgtdevs(mrioc);
+ mrioc->ts_update_counter = 0;
+ spin_lock_irqsave(&mrioc->watchdog_lock, flags);
+ if (mrioc->watchdog_work_q)
+ queue_delayed_work(mrioc->watchdog_work_q,
+ &mrioc->watchdog_work,
+ msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
+ spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
+ } else {
+ mpi3mr_issue_reset(mrioc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
+ mrioc->unrecoverable = 1;
+ mrioc->reset_in_progress = 0;
+ retval = -1;
+ }
+
+ mutex_unlock(&mrioc->reset_mutex);
+ ioc_info(mrioc, "%s\n", ((retval == 0) ? "SUCCESS" : "FAILED"));
+ return retval;
+}
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
new file mode 100644
index 000000000000..24ac7ddec749
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -0,0 +1,4046 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Broadcom MPI3 Storage Controllers
+ *
+ * Copyright (C) 2017-2021 Broadcom Inc.
+ * (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
+ *
+ */
+
+#include "mpi3mr.h"
+
+/* global driver scop variables */
+LIST_HEAD(mrioc_list);
+DEFINE_SPINLOCK(mrioc_list_lock);
+static int mrioc_ids;
+static int warn_non_secure_ctlr;
+
+MODULE_AUTHOR(MPI3MR_DRIVER_AUTHOR);
+MODULE_DESCRIPTION(MPI3MR_DRIVER_DESC);
+MODULE_LICENSE(MPI3MR_DRIVER_LICENSE);
+MODULE_VERSION(MPI3MR_DRIVER_VERSION);
+
+/* Module parameters*/
+int prot_mask = -1;
+module_param(prot_mask, int, 0);
+MODULE_PARM_DESC(prot_mask, "Host protection capabilities mask, def=0x07");
+
+static int prot_guard_mask = 3;
+module_param(prot_guard_mask, int, 0);
+MODULE_PARM_DESC(prot_guard_mask, " Host protection guard mask, def=3");
+static int logging_level;
+module_param(logging_level, int, 0);
+MODULE_PARM_DESC(logging_level,
+ " bits for enabling additional logging info (default=0)");
+
+/* Forward declarations*/
+/**
+ * mpi3mr_host_tag_for_scmd - Get host tag for a scmd
+ * @mrioc: Adapter instance reference
+ * @scmd: SCSI command reference
+ *
+ * Calculate the host tag based on block tag for a given scmd.
+ *
+ * Return: Valid host tag or MPI3MR_HOSTTAG_INVALID.
+ */
+static u16 mpi3mr_host_tag_for_scmd(struct mpi3mr_ioc *mrioc,
+ struct scsi_cmnd *scmd)
+{
+ struct scmd_priv *priv = NULL;
+ u32 unique_tag;
+ u16 host_tag, hw_queue;
+
+ unique_tag = blk_mq_unique_tag(scmd->request);
+
+ hw_queue = blk_mq_unique_tag_to_hwq(unique_tag);
+ if (hw_queue >= mrioc->num_op_reply_q)
+ return MPI3MR_HOSTTAG_INVALID;
+ host_tag = blk_mq_unique_tag_to_tag(unique_tag);
+
+ if (WARN_ON(host_tag >= mrioc->max_host_ios))
+ return MPI3MR_HOSTTAG_INVALID;
+
+ priv = scsi_cmd_priv(scmd);
+ /*host_tag 0 is invalid hence incrementing by 1*/
+ priv->host_tag = host_tag + 1;
+ priv->scmd = scmd;
+ priv->in_lld_scope = 1;
+ priv->req_q_idx = hw_queue;
+ priv->meta_chain_idx = -1;
+ priv->chain_idx = -1;
+ priv->meta_sg_valid = 0;
+ return priv->host_tag;
+}
+
+/**
+ * mpi3mr_scmd_from_host_tag - Get SCSI command from host tag
+ * @mrioc: Adapter instance reference
+ * @host_tag: Host tag
+ * @qidx: Operational queue index
+ *
+ * Identify the block tag from the host tag and queue index and
+ * retrieve associated scsi command using scsi_host_find_tag().
+ *
+ * Return: SCSI command reference or NULL.
+ */
+static struct scsi_cmnd *mpi3mr_scmd_from_host_tag(
+ struct mpi3mr_ioc *mrioc, u16 host_tag, u16 qidx)
+{
+ struct scsi_cmnd *scmd = NULL;
+ struct scmd_priv *priv = NULL;
+ u32 unique_tag = host_tag - 1;
+
+ if (WARN_ON(host_tag > mrioc->max_host_ios))
+ goto out;
+
+ unique_tag |= (qidx << BLK_MQ_UNIQUE_TAG_BITS);
+
+ scmd = scsi_host_find_tag(mrioc->shost, unique_tag);
+ if (scmd) {
+ priv = scsi_cmd_priv(scmd);
+ if (!priv->in_lld_scope)
+ scmd = NULL;
+ }
+out:
+ return scmd;
+}
+
+/**
+ * mpi3mr_clear_scmd_priv - Cleanup SCSI command private date
+ * @mrioc: Adapter instance reference
+ * @scmd: SCSI command reference
+ *
+ * Invalidate the SCSI command private data to mark the command
+ * is not in LLD scope anymore.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_clear_scmd_priv(struct mpi3mr_ioc *mrioc,
+ struct scsi_cmnd *scmd)
+{
+ struct scmd_priv *priv = NULL;
+
+ priv = scsi_cmd_priv(scmd);
+
+ if (WARN_ON(priv->in_lld_scope == 0))
+ return;
+ priv->host_tag = MPI3MR_HOSTTAG_INVALID;
+ priv->req_q_idx = 0xFFFF;
+ priv->scmd = NULL;
+ priv->in_lld_scope = 0;
+ priv->meta_sg_valid = 0;
+ if (priv->chain_idx >= 0) {
+ clear_bit(priv->chain_idx, mrioc->chain_bitmap);
+ priv->chain_idx = -1;
+ }
+ if (priv->meta_chain_idx >= 0) {
+ clear_bit(priv->meta_chain_idx, mrioc->chain_bitmap);
+ priv->meta_chain_idx = -1;
+ }
+}
+
+static void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_ioc *mrioc, u16 handle,
+ struct mpi3mr_drv_cmd *cmdparam, u8 iou_rc);
+static void mpi3mr_fwevt_worker(struct work_struct *work);
+
+/**
+ * mpi3mr_fwevt_free - firmware event memory dealloctor
+ * @r: k reference pointer of the firmware event
+ *
+ * Free firmware event memory when no reference.
+ */
+static void mpi3mr_fwevt_free(struct kref *r)
+{
+ kfree(container_of(r, struct mpi3mr_fwevt, ref_count));
+}
+
+/**
+ * mpi3mr_fwevt_get - k reference incrementor
+ * @fwevt: Firmware event reference
+ *
+ * Increment firmware event reference count.
+ */
+static void mpi3mr_fwevt_get(struct mpi3mr_fwevt *fwevt)
+{
+ kref_get(&fwevt->ref_count);
+}
+
+/**
+ * mpi3mr_fwevt_put - k reference decrementor
+ * @fwevt: Firmware event reference
+ *
+ * decrement firmware event reference count.
+ */
+static void mpi3mr_fwevt_put(struct mpi3mr_fwevt *fwevt)
+{
+ kref_put(&fwevt->ref_count, mpi3mr_fwevt_free);
+}
+
+/**
+ * mpi3mr_alloc_fwevt - Allocate firmware event
+ * @len: length of firmware event data to allocate
+ *
+ * Allocate firmware event with required length and initialize
+ * the reference counter.
+ *
+ * Return: firmware event reference.
+ */
+static struct mpi3mr_fwevt *mpi3mr_alloc_fwevt(int len)
+{
+ struct mpi3mr_fwevt *fwevt;
+
+ fwevt = kzalloc(sizeof(*fwevt) + len, GFP_ATOMIC);
+ if (!fwevt)
+ return NULL;
+
+ kref_init(&fwevt->ref_count);
+ return fwevt;
+}
+
+/**
+ * mpi3mr_fwevt_add_to_list - Add firmware event to the list
+ * @mrioc: Adapter instance reference
+ * @fwevt: Firmware event reference
+ *
+ * Add the given firmware event to the firmware event list.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_fwevt_add_to_list(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_fwevt *fwevt)
+{
+ unsigned long flags;
+
+ if (!mrioc->fwevt_worker_thread)
+ return;
+
+ spin_lock_irqsave(&mrioc->fwevt_lock, flags);
+ /* get fwevt reference count while adding it to fwevt_list */
+ mpi3mr_fwevt_get(fwevt);
+ INIT_LIST_HEAD(&fwevt->list);
+ list_add_tail(&fwevt->list, &mrioc->fwevt_list);
+ INIT_WORK(&fwevt->work, mpi3mr_fwevt_worker);
+ /* get fwevt reference count while enqueueing it to worker queue */
+ mpi3mr_fwevt_get(fwevt);
+ queue_work(mrioc->fwevt_worker_thread, &fwevt->work);
+ spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
+}
+
+/**
+ * mpi3mr_fwevt_del_from_list - Delete firmware event from list
+ * @mrioc: Adapter instance reference
+ * @fwevt: Firmware event reference
+ *
+ * Delete the given firmware event from the firmware event list.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_fwevt_del_from_list(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_fwevt *fwevt)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mrioc->fwevt_lock, flags);
+ if (!list_empty(&fwevt->list)) {
+ list_del_init(&fwevt->list);
+ /*
+ * Put fwevt reference count after
+ * removing it from fwevt_list
+ */
+ mpi3mr_fwevt_put(fwevt);
+ }
+ spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
+}
+
+/**
+ * mpi3mr_dequeue_fwevt - Dequeue firmware event from the list
+ * @mrioc: Adapter instance reference
+ *
+ * Dequeue a firmware event from the firmware event list.
+ *
+ * Return: firmware event.
+ */
+static struct mpi3mr_fwevt *mpi3mr_dequeue_fwevt(
+ struct mpi3mr_ioc *mrioc)
+{
+ unsigned long flags;
+ struct mpi3mr_fwevt *fwevt = NULL;
+
+ spin_lock_irqsave(&mrioc->fwevt_lock, flags);
+ if (!list_empty(&mrioc->fwevt_list)) {
+ fwevt = list_first_entry(&mrioc->fwevt_list,
+ struct mpi3mr_fwevt, list);
+ list_del_init(&fwevt->list);
+ /*
+ * Put fwevt reference count after
+ * removing it from fwevt_list
+ */
+ mpi3mr_fwevt_put(fwevt);
+ }
+ spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
+
+ return fwevt;
+}
+
+/**
+ * mpi3mr_cleanup_fwevt_list - Cleanup firmware event list
+ * @mrioc: Adapter instance reference
+ *
+ * Flush all pending firmware events from the firmware event
+ * list.
+ *
+ * Return: Nothing.
+ */
+void mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc *mrioc)
+{
+ struct mpi3mr_fwevt *fwevt = NULL;
+
+ if ((list_empty(&mrioc->fwevt_list) && !mrioc->current_event) ||
+ !mrioc->fwevt_worker_thread)
+ return;
+
+ while ((fwevt = mpi3mr_dequeue_fwevt(mrioc)) ||
+ (fwevt = mrioc->current_event)) {
+ /*
+ * Wait on the fwevt to complete. If this returns 1, then
+ * the event was never executed, and we need a put for the
+ * reference the work had on the fwevt.
+ *
+ * If it did execute, we wait for it to finish, and the put will
+ * happen from mpi3mr_process_fwevt()
+ */
+ if (cancel_work_sync(&fwevt->work)) {
+ /*
+ * Put fwevt reference count after
+ * dequeuing it from worker queue
+ */
+ mpi3mr_fwevt_put(fwevt);
+ /*
+ * Put fwevt reference count to neutralize
+ * kref_init increment
+ */
+ mpi3mr_fwevt_put(fwevt);
+ }
+ }
+}
+
+/**
+ * mpi3mr_invalidate_devhandles -Invalidate device handles
+ * @mrioc: Adapter instance reference
+ *
+ * Invalidate the device handles in the target device structures
+ * . Called post reset prior to reinitializing the controller.
+ *
+ * Return: Nothing.
+ */
+void mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc)
+{
+ struct mpi3mr_tgt_dev *tgtdev;
+ struct mpi3mr_stgt_priv_data *tgt_priv;
+
+ list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) {
+ tgtdev->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
+ if (tgtdev->starget && tgtdev->starget->hostdata) {
+ tgt_priv = tgtdev->starget->hostdata;
+ tgt_priv->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
+ }
+ }
+}
+
+/**
+ * mpi3mr_print_scmd - print individual SCSI command
+ * @rq: Block request
+ * @data: Adapter instance reference
+ * @reserved: N/A. Currently not used
+ *
+ * Print the SCSI command details if it is in LLD scope.
+ *
+ * Return: true always.
+ */
+static bool mpi3mr_print_scmd(struct request *rq,
+ void *data, bool reserved)
+{
+ struct mpi3mr_ioc *mrioc = (struct mpi3mr_ioc *)data;
+ struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
+ struct scmd_priv *priv = NULL;
+
+ if (scmd) {
+ priv = scsi_cmd_priv(scmd);
+ if (!priv->in_lld_scope)
+ goto out;
+
+ ioc_info(mrioc, "%s :Host Tag = %d, qid = %d\n",
+ __func__, priv->host_tag, priv->req_q_idx + 1);
+ scsi_print_command(scmd);
+ }
+
+out:
+ return(true);
+}
+
+/**
+ * mpi3mr_flush_scmd - Flush individual SCSI command
+ * @rq: Block request
+ * @data: Adapter instance reference
+ * @reserved: N/A. Currently not used
+ *
+ * Return the SCSI command to the upper layers if it is in LLD
+ * scope.
+ *
+ * Return: true always.
+ */
+
+static bool mpi3mr_flush_scmd(struct request *rq,
+ void *data, bool reserved)
+{
+ struct mpi3mr_ioc *mrioc = (struct mpi3mr_ioc *)data;
+ struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
+ struct scmd_priv *priv = NULL;
+
+ if (scmd) {
+ priv = scsi_cmd_priv(scmd);
+ if (!priv->in_lld_scope)
+ goto out;
+
+ if (priv->meta_sg_valid)
+ dma_unmap_sg(&mrioc->pdev->dev, scsi_prot_sglist(scmd),
+ scsi_prot_sg_count(scmd), scmd->sc_data_direction);
+ mpi3mr_clear_scmd_priv(mrioc, scmd);
+ scsi_dma_unmap(scmd);
+ scmd->result = DID_RESET << 16;
+ scsi_print_command(scmd);
+ scmd->scsi_done(scmd);
+ mrioc->flush_io_count++;
+ }
+
+out:
+ return(true);
+}
+
+/**
+ * mpi3mr_flush_host_io - Flush host I/Os
+ * @mrioc: Adapter instance reference
+ *
+ * Flush all of the pending I/Os by calling
+ * blk_mq_tagset_busy_iter() for each possible tag. This is
+ * executed post controller reset
+ *
+ * Return: Nothing.
+ */
+void mpi3mr_flush_host_io(struct mpi3mr_ioc *mrioc)
+{
+ struct Scsi_Host *shost = mrioc->shost;
+
+ mrioc->flush_io_count = 0;
+ ioc_info(mrioc, "%s :Flushing Host I/O cmds post reset\n", __func__);
+ blk_mq_tagset_busy_iter(&shost->tag_set,
+ mpi3mr_flush_scmd, (void *)mrioc);
+ ioc_info(mrioc, "%s :Flushed %d Host I/O cmds\n", __func__,
+ mrioc->flush_io_count);
+}
+
+/**
+ * mpi3mr_alloc_tgtdev - target device allocator
+ *
+ * Allocate target device instance and initialize the reference
+ * count
+ *
+ * Return: target device instance.
+ */
+static struct mpi3mr_tgt_dev *mpi3mr_alloc_tgtdev(void)
+{
+ struct mpi3mr_tgt_dev *tgtdev;
+
+ tgtdev = kzalloc(sizeof(*tgtdev), GFP_ATOMIC);
+ if (!tgtdev)
+ return NULL;
+ kref_init(&tgtdev->ref_count);
+ return tgtdev;
+}
+
+/**
+ * mpi3mr_tgtdev_add_to_list -Add tgtdevice to the list
+ * @mrioc: Adapter instance reference
+ * @tgtdev: Target device
+ *
+ * Add the target device to the target device list
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_tgtdev_add_to_list(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_tgt_dev *tgtdev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+ mpi3mr_tgtdev_get(tgtdev);
+ INIT_LIST_HEAD(&tgtdev->list);
+ list_add_tail(&tgtdev->list, &mrioc->tgtdev_list);
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+}
+
+/**
+ * mpi3mr_tgtdev_del_from_list -Delete tgtdevice from the list
+ * @mrioc: Adapter instance reference
+ * @tgtdev: Target device
+ *
+ * Remove the target device from the target device list
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_tgtdev_del_from_list(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_tgt_dev *tgtdev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+ if (!list_empty(&tgtdev->list)) {
+ list_del_init(&tgtdev->list);
+ mpi3mr_tgtdev_put(tgtdev);
+ }
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+}
+
+/**
+ * __mpi3mr_get_tgtdev_by_handle -Get tgtdev from device handle
+ * @mrioc: Adapter instance reference
+ * @handle: Device handle
+ *
+ * Accessor to retrieve target device from the device handle.
+ * Non Lock version
+ *
+ * Return: Target device reference.
+ */
+static struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_handle(
+ struct mpi3mr_ioc *mrioc, u16 handle)
+{
+ struct mpi3mr_tgt_dev *tgtdev;
+
+ assert_spin_locked(&mrioc->tgtdev_lock);
+ list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
+ if (tgtdev->dev_handle == handle)
+ goto found_tgtdev;
+ return NULL;
+
+found_tgtdev:
+ mpi3mr_tgtdev_get(tgtdev);
+ return tgtdev;
+}
+
+/**
+ * mpi3mr_get_tgtdev_by_handle -Get tgtdev from device handle
+ * @mrioc: Adapter instance reference
+ * @handle: Device handle
+ *
+ * Accessor to retrieve target device from the device handle.
+ * Lock version
+ *
+ * Return: Target device reference.
+ */
+static struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_handle(
+ struct mpi3mr_ioc *mrioc, u16 handle)
+{
+ struct mpi3mr_tgt_dev *tgtdev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+ tgtdev = __mpi3mr_get_tgtdev_by_handle(mrioc, handle);
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+ return tgtdev;
+}
+
+/**
+ * __mpi3mr_get_tgtdev_by_perst_id -Get tgtdev from persist ID
+ * @mrioc: Adapter instance reference
+ * @persist_id: Persistent ID
+ *
+ * Accessor to retrieve target device from the Persistent ID.
+ * Non Lock version
+ *
+ * Return: Target device reference.
+ */
+static struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_perst_id(
+ struct mpi3mr_ioc *mrioc, u16 persist_id)
+{
+ struct mpi3mr_tgt_dev *tgtdev;
+
+ assert_spin_locked(&mrioc->tgtdev_lock);
+ list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
+ if (tgtdev->perst_id == persist_id)
+ goto found_tgtdev;
+ return NULL;
+
+found_tgtdev:
+ mpi3mr_tgtdev_get(tgtdev);
+ return tgtdev;
+}
+
+/**
+ * mpi3mr_get_tgtdev_by_perst_id -Get tgtdev from persistent ID
+ * @mrioc: Adapter instance reference
+ * @persist_id: Persistent ID
+ *
+ * Accessor to retrieve target device from the Persistent ID.
+ * Lock version
+ *
+ * Return: Target device reference.
+ */
+static struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_perst_id(
+ struct mpi3mr_ioc *mrioc, u16 persist_id)
+{
+ struct mpi3mr_tgt_dev *tgtdev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+ tgtdev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, persist_id);
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+ return tgtdev;
+}
+
+/**
+ * __mpi3mr_get_tgtdev_from_tgtpriv -Get tgtdev from tgt private
+ * @mrioc: Adapter instance reference
+ * @tgt_priv: Target private data
+ *
+ * Accessor to return target device from the target private
+ * data. Non Lock version
+ *
+ * Return: Target device reference.
+ */
+static struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_from_tgtpriv(
+ struct mpi3mr_ioc *mrioc, struct mpi3mr_stgt_priv_data *tgt_priv)
+{
+ struct mpi3mr_tgt_dev *tgtdev;
+
+ assert_spin_locked(&mrioc->tgtdev_lock);
+ tgtdev = tgt_priv->tgt_dev;
+ if (tgtdev)
+ mpi3mr_tgtdev_get(tgtdev);
+ return tgtdev;
+}
+
+/**
+ * mpi3mr_remove_tgtdev_from_host - Remove dev from upper layers
+ * @mrioc: Adapter instance reference
+ * @tgtdev: Target device structure
+ *
+ * Checks whether the device is exposed to upper layers and if it
+ * is then remove the device from upper layers by calling
+ * scsi_remove_target().
+ *
+ * Return: 0 on success, non zero on failure.
+ */
+static void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_tgt_dev *tgtdev)
+{
+ struct mpi3mr_stgt_priv_data *tgt_priv;
+
+ ioc_info(mrioc, "%s :Removing handle(0x%04x), wwid(0x%016llx)\n",
+ __func__, tgtdev->dev_handle, (unsigned long long)tgtdev->wwid);
+ if (tgtdev->starget && tgtdev->starget->hostdata) {
+ tgt_priv = tgtdev->starget->hostdata;
+ tgt_priv->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
+ }
+
+ if (tgtdev->starget) {
+ scsi_remove_target(&tgtdev->starget->dev);
+ tgtdev->host_exposed = 0;
+ }
+ ioc_info(mrioc, "%s :Removed handle(0x%04x), wwid(0x%016llx)\n",
+ __func__, tgtdev->dev_handle, (unsigned long long)tgtdev->wwid);
+}
+
+/**
+ * mpi3mr_report_tgtdev_to_host - Expose device to upper layers
+ * @mrioc: Adapter instance reference
+ * @perst_id: Persistent ID of the device
+ *
+ * Checks whether the device can be exposed to upper layers and
+ * if it is not then expose the device to upper layers by
+ * calling scsi_scan_target().
+ *
+ * Return: 0 on success, non zero on failure.
+ */
+static int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc,
+ u16 perst_id)
+{
+ int retval = 0;
+ struct mpi3mr_tgt_dev *tgtdev;
+
+ tgtdev = mpi3mr_get_tgtdev_by_perst_id(mrioc, perst_id);
+ if (!tgtdev) {
+ retval = -1;
+ goto out;
+ }
+ if (tgtdev->is_hidden) {
+ retval = -1;
+ goto out;
+ }
+ if (!tgtdev->host_exposed && !mrioc->reset_in_progress) {
+ tgtdev->host_exposed = 1;
+ scsi_scan_target(&mrioc->shost->shost_gendev, 0,
+ tgtdev->perst_id,
+ SCAN_WILD_CARD, SCSI_SCAN_INITIAL);
+ if (!tgtdev->starget)
+ tgtdev->host_exposed = 0;
+ }
+out:
+ if (tgtdev)
+ mpi3mr_tgtdev_put(tgtdev);
+
+ return retval;
+}
+
+/**
+ * mpi3mr_change_queue_depth- Change QD callback handler
+ * @sdev: SCSI device reference
+ * @q_depth: Queue depth
+ *
+ * Validate and limit QD and call scsi_change_queue_depth.
+ *
+ * Return: return value of scsi_change_queue_depth
+ */
+static int mpi3mr_change_queue_depth(struct scsi_device *sdev,
+ int q_depth)
+{
+ struct scsi_target *starget = scsi_target(sdev);
+ struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+ int retval = 0;
+
+ if (!sdev->tagged_supported)
+ q_depth = 1;
+ if (q_depth > shost->can_queue)
+ q_depth = shost->can_queue;
+ else if (!q_depth)
+ q_depth = MPI3MR_DEFAULT_SDEV_QD;
+ retval = scsi_change_queue_depth(sdev, q_depth);
+
+ return retval;
+}
+
+/**
+ * mpi3mr_update_sdev - Update SCSI device information
+ * @sdev: SCSI device reference
+ * @data: target device reference
+ *
+ * This is an iterator function called for each SCSI device in a
+ * target to update the target specific information into each
+ * SCSI device.
+ *
+ * Return: Nothing.
+ */
+static void
+mpi3mr_update_sdev(struct scsi_device *sdev, void *data)
+{
+ struct mpi3mr_tgt_dev *tgtdev;
+
+ tgtdev = (struct mpi3mr_tgt_dev *)data;
+ if (!tgtdev)
+ return;
+
+ mpi3mr_change_queue_depth(sdev, tgtdev->q_depth);
+ switch (tgtdev->dev_type) {
+ case MPI3_DEVICE_DEVFORM_PCIE:
+ /*The block layer hw sector size = 512*/
+ blk_queue_max_hw_sectors(sdev->request_queue,
+ tgtdev->dev_spec.pcie_inf.mdts / 512);
+ blk_queue_virt_boundary(sdev->request_queue,
+ ((1 << tgtdev->dev_spec.pcie_inf.pgsz) - 1));
+
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * mpi3mr_rfresh_tgtdevs - Refresh target device exposure
+ * @mrioc: Adapter instance reference
+ *
+ * This is executed post controller reset to identify any
+ * missing devices during reset and remove from the upper layers
+ * or expose any newly detected device to the upper layers.
+ *
+ * Return: Nothing.
+ */
+
+void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc)
+{
+ struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next;
+
+ list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list,
+ list) {
+ if ((tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) &&
+ tgtdev->host_exposed) {
+ mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
+ mpi3mr_tgtdev_del_from_list(mrioc, tgtdev);
+ mpi3mr_tgtdev_put(tgtdev);
+ }
+ }
+
+ tgtdev = NULL;
+ list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) {
+ if ((tgtdev->dev_handle != MPI3MR_INVALID_DEV_HANDLE) &&
+ !tgtdev->is_hidden && !tgtdev->host_exposed)
+ mpi3mr_report_tgtdev_to_host(mrioc, tgtdev->perst_id);
+ }
+}
+
+/**
+ * mpi3mr_update_tgtdev - DevStatusChange evt bottomhalf
+ * @mrioc: Adapter instance reference
+ * @tgtdev: Target device internal structure
+ * @dev_pg0: New device page0
+ *
+ * Update the information from the device page0 into the driver
+ * cached target device structure.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_tgt_dev *tgtdev, struct mpi3_device_page0 *dev_pg0)
+{
+ u16 flags = 0;
+ struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
+ u8 prot_mask = 0;
+
+ tgtdev->perst_id = le16_to_cpu(dev_pg0->persistent_id);
+ tgtdev->dev_handle = le16_to_cpu(dev_pg0->dev_handle);
+ tgtdev->dev_type = dev_pg0->device_form;
+ tgtdev->encl_handle = le16_to_cpu(dev_pg0->enclosure_handle);
+ tgtdev->parent_handle = le16_to_cpu(dev_pg0->parent_dev_handle);
+ tgtdev->slot = le16_to_cpu(dev_pg0->slot);
+ tgtdev->q_depth = le16_to_cpu(dev_pg0->queue_depth);
+ tgtdev->wwid = le64_to_cpu(dev_pg0->wwid);
+
+ flags = le16_to_cpu(dev_pg0->flags);
+ tgtdev->is_hidden = (flags & MPI3_DEVICE0_FLAGS_HIDDEN);
+
+ if (tgtdev->starget && tgtdev->starget->hostdata) {
+ scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
+ tgtdev->starget->hostdata;
+ scsi_tgt_priv_data->perst_id = tgtdev->perst_id;
+ scsi_tgt_priv_data->dev_handle = tgtdev->dev_handle;
+ scsi_tgt_priv_data->dev_type = tgtdev->dev_type;
+ }
+
+ switch (tgtdev->dev_type) {
+ case MPI3_DEVICE_DEVFORM_SAS_SATA:
+ {
+ struct mpi3_device0_sas_sata_format *sasinf =
+ &dev_pg0->device_specific.sas_sata_format;
+ u16 dev_info = le16_to_cpu(sasinf->device_info);
+
+ tgtdev->dev_spec.sas_sata_inf.dev_info = dev_info;
+ tgtdev->dev_spec.sas_sata_inf.sas_address =
+ le64_to_cpu(sasinf->sas_address);
+ if ((dev_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) !=
+ MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE)
+ tgtdev->is_hidden = 1;
+ else if (!(dev_info & (MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET |
+ MPI3_SAS_DEVICE_INFO_SSP_TARGET)))
+ tgtdev->is_hidden = 1;
+ break;
+ }
+ case MPI3_DEVICE_DEVFORM_PCIE:
+ {
+ struct mpi3_device0_pcie_format *pcieinf =
+ &dev_pg0->device_specific.pcie_format;
+ u16 dev_info = le16_to_cpu(pcieinf->device_info);
+
+ tgtdev->dev_spec.pcie_inf.capb =
+ le32_to_cpu(pcieinf->capabilities);
+ tgtdev->dev_spec.pcie_inf.mdts = MPI3MR_DEFAULT_MDTS;
+ /* 2^12 = 4096 */
+ tgtdev->dev_spec.pcie_inf.pgsz = 12;
+ if (dev_pg0->access_status == MPI3_DEVICE0_ASTATUS_NO_ERRORS) {
+ tgtdev->dev_spec.pcie_inf.mdts =
+ le32_to_cpu(pcieinf->maximum_data_transfer_size);
+ tgtdev->dev_spec.pcie_inf.pgsz = pcieinf->page_size;
+ tgtdev->dev_spec.pcie_inf.reset_to =
+ pcieinf->controller_reset_to;
+ tgtdev->dev_spec.pcie_inf.abort_to =
+ pcieinf->nv_me_abort_to;
+ }
+ if (tgtdev->dev_spec.pcie_inf.mdts > (1024 * 1024))
+ tgtdev->dev_spec.pcie_inf.mdts = (1024 * 1024);
+ if ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) !=
+ MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE)
+ tgtdev->is_hidden = 1;
+ if (!mrioc->shost)
+ break;
+ prot_mask = scsi_host_get_prot(mrioc->shost);
+ if (prot_mask & SHOST_DIX_TYPE0_PROTECTION) {
+ scsi_host_set_prot(mrioc->shost, prot_mask & 0x77);
+ ioc_info(mrioc,
+ "%s : Disabling DIX0 prot capability\n", __func__);
+ ioc_info(mrioc,
+ "because HBA does not support DIX0 operation on NVME drives\n");
+ }
+ break;
+ }
+ case MPI3_DEVICE_DEVFORM_VD:
+ {
+ struct mpi3_device0_vd_format *vdinf =
+ &dev_pg0->device_specific.vd_format;
+
+ tgtdev->dev_spec.vol_inf.state = vdinf->vd_state;
+ if (vdinf->vd_state == MPI3_DEVICE0_VD_STATE_OFFLINE)
+ tgtdev->is_hidden = 1;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/**
+ * mpi3mr_devstatuschg_evt_bh - DevStatusChange evt bottomhalf
+ * @mrioc: Adapter instance reference
+ * @fwevt: Firmware event information.
+ *
+ * Process Device status Change event and based on device's new
+ * information, either expose the device to the upper layers, or
+ * remove the device from upper layers.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_fwevt *fwevt)
+{
+ u16 dev_handle = 0;
+ u8 uhide = 0, delete = 0, cleanup = 0;
+ struct mpi3mr_tgt_dev *tgtdev = NULL;
+ struct mpi3_event_data_device_status_change *evtdata =
+ (struct mpi3_event_data_device_status_change *)fwevt->event_data;
+
+ dev_handle = le16_to_cpu(evtdata->dev_handle);
+ ioc_info(mrioc,
+ "%s :device status change: handle(0x%04x): reason code(0x%x)\n",
+ __func__, dev_handle, evtdata->reason_code);
+ switch (evtdata->reason_code) {
+ case MPI3_EVENT_DEV_STAT_RC_HIDDEN:
+ delete = 1;
+ break;
+ case MPI3_EVENT_DEV_STAT_RC_NOT_HIDDEN:
+ uhide = 1;
+ break;
+ case MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING:
+ delete = 1;
+ cleanup = 1;
+ break;
+ default:
+ ioc_info(mrioc, "%s :Unhandled reason code(0x%x)\n", __func__,
+ evtdata->reason_code);
+ break;
+ }
+
+ tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
+ if (!tgtdev)
+ goto out;
+ if (uhide) {
+ tgtdev->is_hidden = 0;
+ if (!tgtdev->host_exposed)
+ mpi3mr_report_tgtdev_to_host(mrioc, tgtdev->perst_id);
+ }
+ if (tgtdev->starget && tgtdev->starget->hostdata) {
+ if (delete)
+ mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
+ }
+ if (cleanup) {
+ mpi3mr_tgtdev_del_from_list(mrioc, tgtdev);
+ mpi3mr_tgtdev_put(tgtdev);
+ }
+
+out:
+ if (tgtdev)
+ mpi3mr_tgtdev_put(tgtdev);
+}
+
+/**
+ * mpi3mr_devinfochg_evt_bh - DeviceInfoChange evt bottomhalf
+ * @mrioc: Adapter instance reference
+ * @dev_pg0: New device page0
+ *
+ * Process Device Info Change event and based on device's new
+ * information, either expose the device to the upper layers, or
+ * remove the device from upper layers or update the details of
+ * the device.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_devinfochg_evt_bh(struct mpi3mr_ioc *mrioc,
+ struct mpi3_device_page0 *dev_pg0)
+{
+ struct mpi3mr_tgt_dev *tgtdev = NULL;
+ u16 dev_handle = 0, perst_id = 0;
+
+ perst_id = le16_to_cpu(dev_pg0->persistent_id);
+ dev_handle = le16_to_cpu(dev_pg0->dev_handle);
+ ioc_info(mrioc,
+ "%s :Device info change: handle(0x%04x): persist_id(0x%x)\n",
+ __func__, dev_handle, perst_id);
+ tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
+ if (!tgtdev)
+ goto out;
+ mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0);
+ if (!tgtdev->is_hidden && !tgtdev->host_exposed)
+ mpi3mr_report_tgtdev_to_host(mrioc, perst_id);
+ if (tgtdev->is_hidden && tgtdev->host_exposed)
+ mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
+ if (!tgtdev->is_hidden && tgtdev->host_exposed && tgtdev->starget)
+ starget_for_each_device(tgtdev->starget, (void *)tgtdev,
+ mpi3mr_update_sdev);
+out:
+ if (tgtdev)
+ mpi3mr_tgtdev_put(tgtdev);
+}
+
+/**
+ * mpi3mr_sastopochg_evt_debug - SASTopoChange details
+ * @mrioc: Adapter instance reference
+ * @event_data: SAS topology change list event data
+ *
+ * Prints information about the SAS topology change event.
+ *
+ * Return: Nothing.
+ */
+static void
+mpi3mr_sastopochg_evt_debug(struct mpi3mr_ioc *mrioc,
+ struct mpi3_event_data_sas_topology_change_list *event_data)
+{
+ int i;
+ u16 handle;
+ u8 reason_code, phy_number;
+ char *status_str = NULL;
+ u8 link_rate, prev_link_rate;
+
+ switch (event_data->exp_status) {
+ case MPI3_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
+ status_str = "remove";
+ break;
+ case MPI3_EVENT_SAS_TOPO_ES_RESPONDING:
+ status_str = "responding";
+ break;
+ case MPI3_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
+ status_str = "remove delay";
+ break;
+ case MPI3_EVENT_SAS_TOPO_ES_NO_EXPANDER:
+ status_str = "direct attached";
+ break;
+ default:
+ status_str = "unknown status";
+ break;
+ }
+ ioc_info(mrioc, "%s :sas topology change: (%s)\n",
+ __func__, status_str);
+ ioc_info(mrioc,
+ "%s :\texpander_handle(0x%04x), enclosure_handle(0x%04x) start_phy(%02d), num_entries(%d)\n",
+ __func__, le16_to_cpu(event_data->expander_dev_handle),
+ le16_to_cpu(event_data->enclosure_handle),
+ event_data->start_phy_num, event_data->num_entries);
+ for (i = 0; i < event_data->num_entries; i++) {
+ handle = le16_to_cpu(event_data->phy_entry[i].attached_dev_handle);
+ if (!handle)
+ continue;
+ phy_number = event_data->start_phy_num + i;
+ reason_code = event_data->phy_entry[i].status &
+ MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
+ switch (reason_code) {
+ case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING:
+ status_str = "target remove";
+ break;
+ case MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING:
+ status_str = "delay target remove";
+ break;
+ case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED:
+ status_str = "link status change";
+ break;
+ case MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE:
+ status_str = "link status no change";
+ break;
+ case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING:
+ status_str = "target responding";
+ break;
+ default:
+ status_str = "unknown";
+ break;
+ }
+ link_rate = event_data->phy_entry[i].link_rate >> 4;
+ prev_link_rate = event_data->phy_entry[i].link_rate & 0xF;
+ ioc_info(mrioc,
+ "%s :\tphy(%02d), attached_handle(0x%04x): %s: link rate: new(0x%02x), old(0x%02x)\n",
+ __func__, phy_number, handle, status_str, link_rate,
+ prev_link_rate);
+ }
+}
+
+/**
+ * mpi3mr_sastopochg_evt_bh - SASTopologyChange evt bottomhalf
+ * @mrioc: Adapter instance reference
+ * @fwevt: Firmware event reference
+ *
+ * Prints information about the SAS topology change event and
+ * for "not responding" event code, removes the device from the
+ * upper layers.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_sastopochg_evt_bh(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_fwevt *fwevt)
+{
+ struct mpi3_event_data_sas_topology_change_list *event_data =
+ (struct mpi3_event_data_sas_topology_change_list *)fwevt->event_data;
+ int i;
+ u16 handle;
+ u8 reason_code;
+ struct mpi3mr_tgt_dev *tgtdev = NULL;
+
+ mpi3mr_sastopochg_evt_debug(mrioc, event_data);
+
+ for (i = 0; i < event_data->num_entries; i++) {
+ handle = le16_to_cpu(event_data->phy_entry[i].attached_dev_handle);
+ if (!handle)
+ continue;
+ tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
+ if (!tgtdev)
+ continue;
+
+ reason_code = event_data->phy_entry[i].status &
+ MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
+
+ switch (reason_code) {
+ case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING:
+ if (tgtdev->host_exposed)
+ mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
+ mpi3mr_tgtdev_del_from_list(mrioc, tgtdev);
+ mpi3mr_tgtdev_put(tgtdev);
+ break;
+ default:
+ break;
+ }
+ if (tgtdev)
+ mpi3mr_tgtdev_put(tgtdev);
+ }
+}
+
+/**
+ * mpi3mr_pcietopochg_evt_debug - PCIeTopoChange details
+ * @mrioc: Adapter instance reference
+ * @event_data: PCIe topology change list event data
+ *
+ * Prints information about the PCIe topology change event.
+ *
+ * Return: Nothing.
+ */
+static void
+mpi3mr_pcietopochg_evt_debug(struct mpi3mr_ioc *mrioc,
+ struct mpi3_event_data_pcie_topology_change_list *event_data)
+{
+ int i;
+ u16 handle;
+ u16 reason_code;
+ u8 port_number;
+ char *status_str = NULL;
+ u8 link_rate, prev_link_rate;
+
+ switch (event_data->switch_status) {
+ case MPI3_EVENT_PCIE_TOPO_SS_NOT_RESPONDING:
+ status_str = "remove";
+ break;
+ case MPI3_EVENT_PCIE_TOPO_SS_RESPONDING:
+ status_str = "responding";
+ break;
+ case MPI3_EVENT_PCIE_TOPO_SS_DELAY_NOT_RESPONDING:
+ status_str = "remove delay";
+ break;
+ case MPI3_EVENT_PCIE_TOPO_SS_NO_PCIE_SWITCH:
+ status_str = "direct attached";
+ break;
+ default:
+ status_str = "unknown status";
+ break;
+ }
+ ioc_info(mrioc, "%s :pcie topology change: (%s)\n",
+ __func__, status_str);
+ ioc_info(mrioc,
+ "%s :\tswitch_handle(0x%04x), enclosure_handle(0x%04x) start_port(%02d), num_entries(%d)\n",
+ __func__, le16_to_cpu(event_data->switch_dev_handle),
+ le16_to_cpu(event_data->enclosure_handle),
+ event_data->start_port_num, event_data->num_entries);
+ for (i = 0; i < event_data->num_entries; i++) {
+ handle =
+ le16_to_cpu(event_data->port_entry[i].attached_dev_handle);
+ if (!handle)
+ continue;
+ port_number = event_data->start_port_num + i;
+ reason_code = event_data->port_entry[i].port_status;
+ switch (reason_code) {
+ case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
+ status_str = "target remove";
+ break;
+ case MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING:
+ status_str = "delay target remove";
+ break;
+ case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED:
+ status_str = "link status change";
+ break;
+ case MPI3_EVENT_PCIE_TOPO_PS_NO_CHANGE:
+ status_str = "link status no change";
+ break;
+ case MPI3_EVENT_PCIE_TOPO_PS_RESPONDING:
+ status_str = "target responding";
+ break;
+ default:
+ status_str = "unknown";
+ break;
+ }
+ link_rate = event_data->port_entry[i].current_port_info &
+ MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK;
+ prev_link_rate = event_data->port_entry[i].previous_port_info &
+ MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK;
+ ioc_info(mrioc,
+ "%s :\tport(%02d), attached_handle(0x%04x): %s: link rate: new(0x%02x), old(0x%02x)\n",
+ __func__, port_number, handle, status_str, link_rate,
+ prev_link_rate);
+ }
+}
+
+/**
+ * mpi3mr_pcietopochg_evt_bh - PCIeTopologyChange evt bottomhalf
+ * @mrioc: Adapter instance reference
+ * @fwevt: Firmware event reference
+ *
+ * Prints information about the PCIe topology change event and
+ * for "not responding" event code, removes the device from the
+ * upper layers.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_pcietopochg_evt_bh(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_fwevt *fwevt)
+{
+ struct mpi3_event_data_pcie_topology_change_list *event_data =
+ (struct mpi3_event_data_pcie_topology_change_list *)fwevt->event_data;
+ int i;
+ u16 handle;
+ u8 reason_code;
+ struct mpi3mr_tgt_dev *tgtdev = NULL;
+
+ mpi3mr_pcietopochg_evt_debug(mrioc, event_data);
+
+ for (i = 0; i < event_data->num_entries; i++) {
+ handle =
+ le16_to_cpu(event_data->port_entry[i].attached_dev_handle);
+ if (!handle)
+ continue;
+ tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
+ if (!tgtdev)
+ continue;
+
+ reason_code = event_data->port_entry[i].port_status;
+
+ switch (reason_code) {
+ case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
+ if (tgtdev->host_exposed)
+ mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
+ mpi3mr_tgtdev_del_from_list(mrioc, tgtdev);
+ mpi3mr_tgtdev_put(tgtdev);
+ break;
+ default:
+ break;
+ }
+ if (tgtdev)
+ mpi3mr_tgtdev_put(tgtdev);
+ }
+}
+
+/**
+ * mpi3mr_fwevt_bh - Firmware event bottomhalf handler
+ * @mrioc: Adapter instance reference
+ * @fwevt: Firmware event reference
+ *
+ * Identifies the firmware event and calls corresponding bottomg
+ * half handler and sends event acknowledgment if required.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_fwevt *fwevt)
+{
+ mrioc->current_event = fwevt;
+ mpi3mr_fwevt_del_from_list(mrioc, fwevt);
+
+ if (mrioc->stop_drv_processing)
+ goto out;
+
+ if (!fwevt->process_evt)
+ goto evt_ack;
+
+ switch (fwevt->event_id) {
+ case MPI3_EVENT_DEVICE_ADDED:
+ {
+ struct mpi3_device_page0 *dev_pg0 =
+ (struct mpi3_device_page0 *)fwevt->event_data;
+ mpi3mr_report_tgtdev_to_host(mrioc,
+ le16_to_cpu(dev_pg0->persistent_id));
+ break;
+ }
+ case MPI3_EVENT_DEVICE_INFO_CHANGED:
+ {
+ mpi3mr_devinfochg_evt_bh(mrioc,
+ (struct mpi3_device_page0 *)fwevt->event_data);
+ break;
+ }
+ case MPI3_EVENT_DEVICE_STATUS_CHANGE:
+ {
+ mpi3mr_devstatuschg_evt_bh(mrioc, fwevt);
+ break;
+ }
+ case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
+ {
+ mpi3mr_sastopochg_evt_bh(mrioc, fwevt);
+ break;
+ }
+ case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
+ {
+ mpi3mr_pcietopochg_evt_bh(mrioc, fwevt);
+ break;
+ }
+ default:
+ break;
+ }
+
+evt_ack:
+ if (fwevt->send_ack)
+ mpi3mr_send_event_ack(mrioc, fwevt->event_id,
+ fwevt->evt_ctx);
+out:
+ /* Put fwevt reference count to neutralize kref_init increment */
+ mpi3mr_fwevt_put(fwevt);
+ mrioc->current_event = NULL;
+}
+
+/**
+ * mpi3mr_fwevt_worker - Firmware event worker
+ * @work: Work struct containing firmware event
+ *
+ * Extracts the firmware event and calls mpi3mr_fwevt_bh.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_fwevt_worker(struct work_struct *work)
+{
+ struct mpi3mr_fwevt *fwevt = container_of(work, struct mpi3mr_fwevt,
+ work);
+ mpi3mr_fwevt_bh(fwevt->mrioc, fwevt);
+ /*
+ * Put fwevt reference count after
+ * dequeuing it from worker queue
+ */
+ mpi3mr_fwevt_put(fwevt);
+}
+
+/**
+ * mpi3mr_create_tgtdev - Create and add a target device
+ * @mrioc: Adapter instance reference
+ * @dev_pg0: Device Page 0 data
+ *
+ * If the device specified by the device page 0 data is not
+ * present in the driver's internal list, allocate the memory
+ * for the device, populate the data and add to the list, else
+ * update the device data. The key is persistent ID.
+ *
+ * Return: 0 on success, -ENOMEM on memory allocation failure
+ */
+static int mpi3mr_create_tgtdev(struct mpi3mr_ioc *mrioc,
+ struct mpi3_device_page0 *dev_pg0)
+{
+ int retval = 0;
+ struct mpi3mr_tgt_dev *tgtdev = NULL;
+ u16 perst_id = 0;
+
+ perst_id = le16_to_cpu(dev_pg0->persistent_id);
+ tgtdev = mpi3mr_get_tgtdev_by_perst_id(mrioc, perst_id);
+ if (tgtdev) {
+ mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0);
+ mpi3mr_tgtdev_put(tgtdev);
+ } else {
+ tgtdev = mpi3mr_alloc_tgtdev();
+ if (!tgtdev)
+ return -ENOMEM;
+ mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0);
+ mpi3mr_tgtdev_add_to_list(mrioc, tgtdev);
+ }
+
+ return retval;
+}
+
+/**
+ * mpi3mr_flush_delayed_rmhs_list - Flush pending commands
+ * @mrioc: Adapter instance reference
+ *
+ * Flush pending commands in the delayed removal handshake list
+ * due to a controller reset or driver removal as a cleanup.
+ *
+ * Return: Nothing
+ */
+void mpi3mr_flush_delayed_rmhs_list(struct mpi3mr_ioc *mrioc)
+{
+ struct delayed_dev_rmhs_node *_rmhs_node;
+
+ while (!list_empty(&mrioc->delayed_rmhs_list)) {
+ _rmhs_node = list_entry(mrioc->delayed_rmhs_list.next,
+ struct delayed_dev_rmhs_node, list);
+ list_del(&_rmhs_node->list);
+ kfree(_rmhs_node);
+ }
+}
+
+/**
+ * mpi3mr_dev_rmhs_complete_iou - Device removal IOUC completion
+ * @mrioc: Adapter instance reference
+ * @drv_cmd: Internal command tracker
+ *
+ * Issues a target reset TM to the firmware from the device
+ * removal TM pend list or retry the removal handshake sequence
+ * based on the IOU control request IOC status.
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_dev_rmhs_complete_iou(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_drv_cmd *drv_cmd)
+{
+ u16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
+ struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL;
+
+ ioc_info(mrioc,
+ "%s :dev_rmhs_iouctrl_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x)\n",
+ __func__, drv_cmd->dev_handle, drv_cmd->ioc_status,
+ drv_cmd->ioc_loginfo);
+ if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+ if (drv_cmd->retry_count < MPI3MR_DEV_RMHS_RETRY_COUNT) {
+ drv_cmd->retry_count++;
+ ioc_info(mrioc,
+ "%s :dev_rmhs_iouctrl_complete: handle(0x%04x)retrying handshake retry=%d\n",
+ __func__, drv_cmd->dev_handle,
+ drv_cmd->retry_count);
+ mpi3mr_dev_rmhs_send_tm(mrioc, drv_cmd->dev_handle,
+ drv_cmd, drv_cmd->iou_rc);
+ return;
+ }
+ ioc_err(mrioc,
+ "%s :dev removal handshake failed after all retries: handle(0x%04x)\n",
+ __func__, drv_cmd->dev_handle);
+ } else {
+ ioc_info(mrioc,
+ "%s :dev removal handshake completed successfully: handle(0x%04x)\n",
+ __func__, drv_cmd->dev_handle);
+ clear_bit(drv_cmd->dev_handle, mrioc->removepend_bitmap);
+ }
+
+ if (!list_empty(&mrioc->delayed_rmhs_list)) {
+ delayed_dev_rmhs = list_entry(mrioc->delayed_rmhs_list.next,
+ struct delayed_dev_rmhs_node, list);
+ drv_cmd->dev_handle = delayed_dev_rmhs->handle;
+ drv_cmd->retry_count = 0;
+ drv_cmd->iou_rc = delayed_dev_rmhs->iou_rc;
+ ioc_info(mrioc,
+ "%s :dev_rmhs_iouctrl_complete: processing delayed TM: handle(0x%04x)\n",
+ __func__, drv_cmd->dev_handle);
+ mpi3mr_dev_rmhs_send_tm(mrioc, drv_cmd->dev_handle, drv_cmd,
+ drv_cmd->iou_rc);
+ list_del(&delayed_dev_rmhs->list);
+ kfree(delayed_dev_rmhs);
+ return;
+ }
+ drv_cmd->state = MPI3MR_CMD_NOTUSED;
+ drv_cmd->callback = NULL;
+ drv_cmd->retry_count = 0;
+ drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
+ clear_bit(cmd_idx, mrioc->devrem_bitmap);
+}
+
+/**
+ * mpi3mr_dev_rmhs_complete_tm - Device removal TM completion
+ * @mrioc: Adapter instance reference
+ * @drv_cmd: Internal command tracker
+ *
+ * Issues a target reset TM to the firmware from the device
+ * removal TM pend list or issue IO unit control request as
+ * part of device removal or hidden acknowledgment handshake.
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_dev_rmhs_complete_tm(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_drv_cmd *drv_cmd)
+{
+ struct mpi3_iounit_control_request iou_ctrl;
+ u16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
+ struct mpi3_scsi_task_mgmt_reply *tm_reply = NULL;
+ int retval;
+
+ if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID)
+ tm_reply = (struct mpi3_scsi_task_mgmt_reply *)drv_cmd->reply;
+
+ if (tm_reply)
+ pr_info(IOCNAME
+ "dev_rmhs_tr_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x), term_count(%d)\n",
+ mrioc->name, drv_cmd->dev_handle, drv_cmd->ioc_status,
+ drv_cmd->ioc_loginfo,
+ le32_to_cpu(tm_reply->termination_count));
+
+ pr_info(IOCNAME "Issuing IOU CTL: handle(0x%04x) dev_rmhs idx(%d)\n",
+ mrioc->name, drv_cmd->dev_handle, cmd_idx);
+
+ memset(&iou_ctrl, 0, sizeof(iou_ctrl));
+
+ drv_cmd->state = MPI3MR_CMD_PENDING;
+ drv_cmd->is_waiting = 0;
+ drv_cmd->callback = mpi3mr_dev_rmhs_complete_iou;
+ iou_ctrl.operation = drv_cmd->iou_rc;
+ iou_ctrl.param16[0] = cpu_to_le16(drv_cmd->dev_handle);
+ iou_ctrl.host_tag = cpu_to_le16(drv_cmd->host_tag);
+ iou_ctrl.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
+
+ retval = mpi3mr_admin_request_post(mrioc, &iou_ctrl, sizeof(iou_ctrl),
+ 1);
+ if (retval) {
+ pr_err(IOCNAME "Issue DevRmHsTMIOUCTL: Admin post failed\n",
+ mrioc->name);
+ goto out_failed;
+ }
+
+ return;
+out_failed:
+ drv_cmd->state = MPI3MR_CMD_NOTUSED;
+ drv_cmd->callback = NULL;
+ drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
+ drv_cmd->retry_count = 0;
+ clear_bit(cmd_idx, mrioc->devrem_bitmap);
+}
+
+/**
+ * mpi3mr_dev_rmhs_send_tm - Issue TM for device removal
+ * @mrioc: Adapter instance reference
+ * @handle: Device handle
+ * @cmdparam: Internal command tracker
+ * @iou_rc: IO unit reason code
+ *
+ * Issues a target reset TM to the firmware or add it to a pend
+ * list as part of device removal or hidden acknowledgment
+ * handshake.
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_ioc *mrioc, u16 handle,
+ struct mpi3mr_drv_cmd *cmdparam, u8 iou_rc)
+{
+ struct mpi3_scsi_task_mgmt_request tm_req;
+ int retval = 0;
+ u16 cmd_idx = MPI3MR_NUM_DEVRMCMD;
+ u8 retrycount = 5;
+ struct mpi3mr_drv_cmd *drv_cmd = cmdparam;
+ struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL;
+
+ if (drv_cmd)
+ goto issue_cmd;
+ do {
+ cmd_idx = find_first_zero_bit(mrioc->devrem_bitmap,
+ MPI3MR_NUM_DEVRMCMD);
+ if (cmd_idx < MPI3MR_NUM_DEVRMCMD) {
+ if (!test_and_set_bit(cmd_idx, mrioc->devrem_bitmap))
+ break;
+ cmd_idx = MPI3MR_NUM_DEVRMCMD;
+ }
+ } while (retrycount--);
+
+ if (cmd_idx >= MPI3MR_NUM_DEVRMCMD) {
+ delayed_dev_rmhs = kzalloc(sizeof(*delayed_dev_rmhs),
+ GFP_ATOMIC);
+ if (!delayed_dev_rmhs)
+ return;
+ INIT_LIST_HEAD(&delayed_dev_rmhs->list);
+ delayed_dev_rmhs->handle = handle;
+ delayed_dev_rmhs->iou_rc = iou_rc;
+ list_add_tail(&delayed_dev_rmhs->list,
+ &mrioc->delayed_rmhs_list);
+ ioc_info(mrioc, "%s :DevRmHs: tr:handle(0x%04x) is postponed\n",
+ __func__, handle);
+ return;
+ }
+ drv_cmd = &mrioc->dev_rmhs_cmds[cmd_idx];
+
+issue_cmd:
+ cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
+ ioc_info(mrioc,
+ "%s :Issuing TR TM: for devhandle 0x%04x with dev_rmhs %d\n",
+ __func__, handle, cmd_idx);
+
+ memset(&tm_req, 0, sizeof(tm_req));
+ if (drv_cmd->state & MPI3MR_CMD_PENDING) {
+ ioc_err(mrioc, "%s :Issue TM: Command is in use\n", __func__);
+ goto out;
+ }
+ drv_cmd->state = MPI3MR_CMD_PENDING;
+ drv_cmd->is_waiting = 0;
+ drv_cmd->callback = mpi3mr_dev_rmhs_complete_tm;
+ drv_cmd->dev_handle = handle;
+ drv_cmd->iou_rc = iou_rc;
+ tm_req.dev_handle = cpu_to_le16(handle);
+ tm_req.task_type = MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+ tm_req.host_tag = cpu_to_le16(drv_cmd->host_tag);
+ tm_req.task_host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INVALID);
+ tm_req.function = MPI3_FUNCTION_SCSI_TASK_MGMT;
+
+ set_bit(handle, mrioc->removepend_bitmap);
+ retval = mpi3mr_admin_request_post(mrioc, &tm_req, sizeof(tm_req), 1);
+ if (retval) {
+ ioc_err(mrioc, "%s :Issue DevRmHsTM: Admin Post failed\n",
+ __func__);
+ goto out_failed;
+ }
+out:
+ return;
+out_failed:
+ drv_cmd->state = MPI3MR_CMD_NOTUSED;
+ drv_cmd->callback = NULL;
+ drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
+ drv_cmd->retry_count = 0;
+ clear_bit(cmd_idx, mrioc->devrem_bitmap);
+}
+
+/**
+ * mpi3mr_pcietopochg_evt_th - PCIETopologyChange evt tophalf
+ * @mrioc: Adapter instance reference
+ * @event_reply: event data
+ *
+ * Checks for the reason code and based on that either block I/O
+ * to device, or unblock I/O to the device, or start the device
+ * removal handshake with reason as remove with the firmware for
+ * PCIe devices.
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_pcietopochg_evt_th(struct mpi3mr_ioc *mrioc,
+ struct mpi3_event_notification_reply *event_reply)
+{
+ struct mpi3_event_data_pcie_topology_change_list *topo_evt =
+ (struct mpi3_event_data_pcie_topology_change_list *)event_reply->event_data;
+ int i;
+ u16 handle;
+ u8 reason_code;
+ struct mpi3mr_tgt_dev *tgtdev = NULL;
+ struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
+
+ for (i = 0; i < topo_evt->num_entries; i++) {
+ handle = le16_to_cpu(topo_evt->port_entry[i].attached_dev_handle);
+ if (!handle)
+ continue;
+ reason_code = topo_evt->port_entry[i].port_status;
+ scsi_tgt_priv_data = NULL;
+ tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
+ if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata)
+ scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
+ tgtdev->starget->hostdata;
+ switch (reason_code) {
+ case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
+ if (scsi_tgt_priv_data) {
+ scsi_tgt_priv_data->dev_removed = 1;
+ scsi_tgt_priv_data->dev_removedelay = 0;
+ atomic_set(&scsi_tgt_priv_data->block_io, 0);
+ }
+ mpi3mr_dev_rmhs_send_tm(mrioc, handle, NULL,
+ MPI3_CTRL_OP_REMOVE_DEVICE);
+ break;
+ case MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING:
+ if (scsi_tgt_priv_data) {
+ scsi_tgt_priv_data->dev_removedelay = 1;
+ atomic_inc(&scsi_tgt_priv_data->block_io);
+ }
+ break;
+ case MPI3_EVENT_PCIE_TOPO_PS_RESPONDING:
+ if (scsi_tgt_priv_data &&
+ scsi_tgt_priv_data->dev_removedelay) {
+ scsi_tgt_priv_data->dev_removedelay = 0;
+ atomic_dec_if_positive
+ (&scsi_tgt_priv_data->block_io);
+ }
+ break;
+ case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED:
+ default:
+ break;
+ }
+ if (tgtdev)
+ mpi3mr_tgtdev_put(tgtdev);
+ }
+}
+
+/**
+ * mpi3mr_sastopochg_evt_th - SASTopologyChange evt tophalf
+ * @mrioc: Adapter instance reference
+ * @event_reply: event data
+ *
+ * Checks for the reason code and based on that either block I/O
+ * to device, or unblock I/O to the device, or start the device
+ * removal handshake with reason as remove with the firmware for
+ * SAS/SATA devices.
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_sastopochg_evt_th(struct mpi3mr_ioc *mrioc,
+ struct mpi3_event_notification_reply *event_reply)
+{
+ struct mpi3_event_data_sas_topology_change_list *topo_evt =
+ (struct mpi3_event_data_sas_topology_change_list *)event_reply->event_data;
+ int i;
+ u16 handle;
+ u8 reason_code;
+ struct mpi3mr_tgt_dev *tgtdev = NULL;
+ struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
+
+ for (i = 0; i < topo_evt->num_entries; i++) {
+ handle = le16_to_cpu(topo_evt->phy_entry[i].attached_dev_handle);
+ if (!handle)
+ continue;
+ reason_code = topo_evt->phy_entry[i].status &
+ MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
+ scsi_tgt_priv_data = NULL;
+ tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
+ if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata)
+ scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
+ tgtdev->starget->hostdata;
+ switch (reason_code) {
+ case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING:
+ if (scsi_tgt_priv_data) {
+ scsi_tgt_priv_data->dev_removed = 1;
+ scsi_tgt_priv_data->dev_removedelay = 0;
+ atomic_set(&scsi_tgt_priv_data->block_io, 0);
+ }
+ mpi3mr_dev_rmhs_send_tm(mrioc, handle, NULL,
+ MPI3_CTRL_OP_REMOVE_DEVICE);
+ break;
+ case MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING:
+ if (scsi_tgt_priv_data) {
+ scsi_tgt_priv_data->dev_removedelay = 1;
+ atomic_inc(&scsi_tgt_priv_data->block_io);
+ }
+ break;
+ case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING:
+ if (scsi_tgt_priv_data &&
+ scsi_tgt_priv_data->dev_removedelay) {
+ scsi_tgt_priv_data->dev_removedelay = 0;
+ atomic_dec_if_positive
+ (&scsi_tgt_priv_data->block_io);
+ }
+ break;
+ case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED:
+ default:
+ break;
+ }
+ if (tgtdev)
+ mpi3mr_tgtdev_put(tgtdev);
+ }
+}
+
+/**
+ * mpi3mr_devstatuschg_evt_th - DeviceStatusChange evt tophalf
+ * @mrioc: Adapter instance reference
+ * @event_reply: event data
+ *
+ * Checks for the reason code and based on that either block I/O
+ * to device, or unblock I/O to the device, or start the device
+ * removal handshake with reason as remove/hide acknowledgment
+ * with the firmware.
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_devstatuschg_evt_th(struct mpi3mr_ioc *mrioc,
+ struct mpi3_event_notification_reply *event_reply)
+{
+ u16 dev_handle = 0;
+ u8 ublock = 0, block = 0, hide = 0, delete = 0, remove = 0;
+ struct mpi3mr_tgt_dev *tgtdev = NULL;
+ struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
+ struct mpi3_event_data_device_status_change *evtdata =
+ (struct mpi3_event_data_device_status_change *)event_reply->event_data;
+
+ if (mrioc->stop_drv_processing)
+ goto out;
+
+ dev_handle = le16_to_cpu(evtdata->dev_handle);
+
+ switch (evtdata->reason_code) {
+ case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_STRT:
+ case MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_STRT:
+ block = 1;
+ break;
+ case MPI3_EVENT_DEV_STAT_RC_HIDDEN:
+ delete = 1;
+ hide = 1;
+ break;
+ case MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING:
+ delete = 1;
+ remove = 1;
+ break;
+ case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_CMP:
+ case MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_CMP:
+ ublock = 1;
+ break;
+ default:
+ break;
+ }
+
+ tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
+ if (!tgtdev)
+ goto out;
+ if (hide)
+ tgtdev->is_hidden = hide;
+ if (tgtdev->starget && tgtdev->starget->hostdata) {
+ scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
+ tgtdev->starget->hostdata;
+ if (block)
+ atomic_inc(&scsi_tgt_priv_data->block_io);
+ if (delete)
+ scsi_tgt_priv_data->dev_removed = 1;
+ if (ublock)
+ atomic_dec_if_positive(&scsi_tgt_priv_data->block_io);
+ }
+ if (remove)
+ mpi3mr_dev_rmhs_send_tm(mrioc, dev_handle, NULL,
+ MPI3_CTRL_OP_REMOVE_DEVICE);
+ if (hide)
+ mpi3mr_dev_rmhs_send_tm(mrioc, dev_handle, NULL,
+ MPI3_CTRL_OP_HIDDEN_ACK);
+
+out:
+ if (tgtdev)
+ mpi3mr_tgtdev_put(tgtdev);
+}
+
+/**
+ * mpi3mr_energypackchg_evt_th - Energy pack change evt tophalf
+ * @mrioc: Adapter instance reference
+ * @event_reply: event data
+ *
+ * Identifies the new shutdown timeout value and update.
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_energypackchg_evt_th(struct mpi3mr_ioc *mrioc,
+ struct mpi3_event_notification_reply *event_reply)
+{
+ struct mpi3_event_data_energy_pack_change *evtdata =
+ (struct mpi3_event_data_energy_pack_change *)event_reply->event_data;
+ u16 shutdown_timeout = le16_to_cpu(evtdata->shutdown_timeout);
+
+ if (shutdown_timeout <= 0) {
+ ioc_warn(mrioc,
+ "%s :Invalid Shutdown Timeout received = %d\n",
+ __func__, shutdown_timeout);
+ return;
+ }
+
+ ioc_info(mrioc,
+ "%s :Previous Shutdown Timeout Value = %d New Shutdown Timeout Value = %d\n",
+ __func__, mrioc->facts.shutdown_timeout, shutdown_timeout);
+ mrioc->facts.shutdown_timeout = shutdown_timeout;
+}
+
+/**
+ * mpi3mr_os_handle_events - Firmware event handler
+ * @mrioc: Adapter instance reference
+ * @event_reply: event data
+ *
+ * Identify whteher the event has to handled and acknowledged
+ * and either process the event in the tophalf and/or schedule a
+ * bottom half through mpi3mr_fwevt_worker.
+ *
+ * Return: Nothing
+ */
+void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
+ struct mpi3_event_notification_reply *event_reply)
+{
+ u16 evt_type, sz;
+ struct mpi3mr_fwevt *fwevt = NULL;
+ bool ack_req = 0, process_evt_bh = 0;
+
+ if (mrioc->stop_drv_processing)
+ return;
+
+ if ((event_reply->msg_flags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK)
+ == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED)
+ ack_req = 1;
+
+ evt_type = event_reply->event;
+
+ switch (evt_type) {
+ case MPI3_EVENT_DEVICE_ADDED:
+ {
+ struct mpi3_device_page0 *dev_pg0 =
+ (struct mpi3_device_page0 *)event_reply->event_data;
+ if (mpi3mr_create_tgtdev(mrioc, dev_pg0))
+ ioc_err(mrioc,
+ "%s :Failed to add device in the device add event\n",
+ __func__);
+ else
+ process_evt_bh = 1;
+ break;
+ }
+ case MPI3_EVENT_DEVICE_STATUS_CHANGE:
+ {
+ process_evt_bh = 1;
+ mpi3mr_devstatuschg_evt_th(mrioc, event_reply);
+ break;
+ }
+ case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
+ {
+ process_evt_bh = 1;
+ mpi3mr_sastopochg_evt_th(mrioc, event_reply);
+ break;
+ }
+ case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
+ {
+ process_evt_bh = 1;
+ mpi3mr_pcietopochg_evt_th(mrioc, event_reply);
+ break;
+ }
+ case MPI3_EVENT_DEVICE_INFO_CHANGED:
+ {
+ process_evt_bh = 1;
+ break;
+ }
+ case MPI3_EVENT_ENERGY_PACK_CHANGE:
+ {
+ mpi3mr_energypackchg_evt_th(mrioc, event_reply);
+ break;
+ }
+ case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
+ case MPI3_EVENT_SAS_DISCOVERY:
+ case MPI3_EVENT_CABLE_MGMT:
+ case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
+ case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
+ case MPI3_EVENT_PCIE_ENUMERATION:
+ break;
+ default:
+ ioc_info(mrioc, "%s :event 0x%02x is not handled\n",
+ __func__, evt_type);
+ break;
+ }
+ if (process_evt_bh || ack_req) {
+ sz = event_reply->event_data_length * 4;
+ fwevt = mpi3mr_alloc_fwevt(sz);
+ if (!fwevt) {
+ ioc_info(mrioc, "%s :failure at %s:%d/%s()!\n",
+ __func__, __FILE__, __LINE__, __func__);
+ return;
+ }
+
+ memcpy(fwevt->event_data, event_reply->event_data, sz);
+ fwevt->mrioc = mrioc;
+ fwevt->event_id = evt_type;
+ fwevt->send_ack = ack_req;
+ fwevt->process_evt = process_evt_bh;
+ fwevt->evt_ctx = le32_to_cpu(event_reply->event_context);
+ mpi3mr_fwevt_add_to_list(mrioc, fwevt);
+ }
+}
+
+/**
+ * mpi3mr_setup_eedp - Setup EEDP information in MPI3 SCSI IO
+ * @mrioc: Adapter instance reference
+ * @scmd: SCSI command reference
+ * @scsiio_req: MPI3 SCSI IO request
+ *
+ * Identifies the protection information flags from the SCSI
+ * command and set appropriate flags in the MPI3 SCSI IO
+ * request.
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_setup_eedp(struct mpi3mr_ioc *mrioc,
+ struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req)
+{
+ u16 eedp_flags = 0;
+ unsigned char prot_op = scsi_get_prot_op(scmd);
+ unsigned char prot_type = scsi_get_prot_type(scmd);
+
+ switch (prot_op) {
+ case SCSI_PROT_NORMAL:
+ return;
+ case SCSI_PROT_READ_STRIP:
+ eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE;
+ break;
+ case SCSI_PROT_WRITE_INSERT:
+ eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_INSERT;
+ break;
+ case SCSI_PROT_READ_INSERT:
+ eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_INSERT;
+ scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID;
+ break;
+ case SCSI_PROT_WRITE_STRIP:
+ eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE;
+ scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID;
+ break;
+ case SCSI_PROT_READ_PASS:
+ eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK |
+ MPI3_EEDPFLAGS_CHK_REF_TAG | MPI3_EEDPFLAGS_CHK_APP_TAG |
+ MPI3_EEDPFLAGS_CHK_GUARD;
+ scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID;
+ break;
+ case SCSI_PROT_WRITE_PASS:
+ if (scsi_host_get_guard(scmd->device->host)
+ & SHOST_DIX_GUARD_IP) {
+ eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REGEN |
+ MPI3_EEDPFLAGS_CHK_APP_TAG |
+ MPI3_EEDPFLAGS_CHK_GUARD |
+ MPI3_EEDPFLAGS_INCR_PRI_REF_TAG;
+ scsiio_req->sgl[0].eedp.application_tag_translation_mask =
+ 0xffff;
+ } else {
+ eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK |
+ MPI3_EEDPFLAGS_CHK_REF_TAG |
+ MPI3_EEDPFLAGS_CHK_APP_TAG |
+ MPI3_EEDPFLAGS_CHK_GUARD;
+ }
+ scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID;
+ break;
+ default:
+ return;
+ }
+
+ if (scsi_host_get_guard(scmd->device->host) & SHOST_DIX_GUARD_IP)
+ eedp_flags |= MPI3_EEDPFLAGS_HOST_GUARD_IP_CHKSUM;
+
+ switch (prot_type) {
+ case SCSI_PROT_DIF_TYPE0:
+ eedp_flags |= MPI3_EEDPFLAGS_INCR_PRI_REF_TAG;
+ scsiio_req->cdb.eedp32.primary_reference_tag =
+ cpu_to_be32(t10_pi_ref_tag(scmd->request));
+ break;
+ case SCSI_PROT_DIF_TYPE1:
+ case SCSI_PROT_DIF_TYPE2:
+ eedp_flags |= MPI3_EEDPFLAGS_INCR_PRI_REF_TAG |
+ MPI3_EEDPFLAGS_ESC_MODE_APPTAG_DISABLE |
+ MPI3_EEDPFLAGS_CHK_GUARD;
+ scsiio_req->cdb.eedp32.primary_reference_tag =
+ cpu_to_be32(t10_pi_ref_tag(scmd->request));
+ break;
+ case SCSI_PROT_DIF_TYPE3:
+ eedp_flags |= MPI3_EEDPFLAGS_CHK_GUARD |
+ MPI3_EEDPFLAGS_ESC_MODE_APPTAG_DISABLE;
+ break;
+
+ default:
+ scsiio_req->msg_flags &= ~(MPI3_SCSIIO_MSGFLAGS_METASGL_VALID);
+ return;
+ }
+
+ switch (scmd->device->sector_size) {
+ case 512:
+ scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_512;
+ break;
+ case 520:
+ scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_520;
+ break;
+ case 4080:
+ scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4080;
+ break;
+ case 4088:
+ scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4088;
+ break;
+ case 4096:
+ scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4096;
+ break;
+ case 4104:
+ scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4104;
+ break;
+ case 4160:
+ scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4160;
+ break;
+ default:
+ break;
+ }
+
+ scsiio_req->sgl[0].eedp.eedp_flags = cpu_to_le16(eedp_flags);
+ scsiio_req->sgl[0].eedp.flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_EXTENDED;
+}
+
+/**
+ * mpi3mr_build_sense_buffer - Map sense information
+ * @desc: Sense type
+ * @buf: Sense buffer to populate
+ * @key: Sense key
+ * @asc: Additional sense code
+ * @ascq: Additional sense code qualifier
+ *
+ * Maps the given sense information into either descriptor or
+ * fixed format sense data.
+ *
+ * Return: Nothing
+ */
+static inline void mpi3mr_build_sense_buffer(int desc, u8 *buf, u8 key,
+ u8 asc, u8 ascq)
+{
+ if (desc) {
+ buf[0] = 0x72; /* descriptor, current */
+ buf[1] = key;
+ buf[2] = asc;
+ buf[3] = ascq;
+ buf[7] = 0;
+ } else {
+ buf[0] = 0x70; /* fixed, current */
+ buf[2] = key;
+ buf[7] = 0xa;
+ buf[12] = asc;
+ buf[13] = ascq;
+ }
+}
+
+/**
+ * mpi3mr_map_eedp_error - Map EEDP errors from IOC status
+ * @scmd: SCSI command reference
+ * @ioc_status: status of MPI3 request
+ *
+ * Maps the EEDP error status of the SCSI IO request to sense
+ * data.
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_map_eedp_error(struct scsi_cmnd *scmd,
+ u16 ioc_status)
+{
+ u8 ascq = 0;
+
+ switch (ioc_status) {
+ case MPI3_IOCSTATUS_EEDP_GUARD_ERROR:
+ ascq = 0x01;
+ break;
+ case MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR:
+ ascq = 0x02;
+ break;
+ case MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR:
+ ascq = 0x03;
+ break;
+ default:
+ ascq = 0x00;
+ break;
+ }
+
+ mpi3mr_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
+ 0x10, ascq);
+ scmd->result = (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
+}
+
+/**
+ * mpi3mr_process_op_reply_desc - reply descriptor handler
+ * @mrioc: Adapter instance reference
+ * @reply_desc: Operational reply descriptor
+ * @reply_dma: place holder for reply DMA address
+ * @qidx: Operational queue index
+ *
+ * Process the operational reply descriptor and identifies the
+ * descriptor type. Based on the descriptor map the MPI3 request
+ * status to a SCSI command status and calls scsi_done call
+ * back.
+ *
+ * Return: Nothing
+ */
+void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc,
+ struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma, u16 qidx)
+{
+ u16 reply_desc_type, host_tag = 0;
+ u16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
+ u32 ioc_loginfo = 0;
+ struct mpi3_status_reply_descriptor *status_desc = NULL;
+ struct mpi3_address_reply_descriptor *addr_desc = NULL;
+ struct mpi3_success_reply_descriptor *success_desc = NULL;
+ struct mpi3_scsi_io_reply *scsi_reply = NULL;
+ struct scsi_cmnd *scmd = NULL;
+ struct scmd_priv *priv = NULL;
+ u8 *sense_buf = NULL;
+ u8 scsi_state = 0, scsi_status = 0, sense_state = 0;
+ u32 xfer_count = 0, sense_count = 0, resp_data = 0;
+ u16 dev_handle = 0xFFFF;
+ struct scsi_sense_hdr sshdr;
+
+ *reply_dma = 0;
+ reply_desc_type = le16_to_cpu(reply_desc->reply_flags) &
+ MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK;
+ switch (reply_desc_type) {
+ case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS:
+ status_desc = (struct mpi3_status_reply_descriptor *)reply_desc;
+ host_tag = le16_to_cpu(status_desc->host_tag);
+ ioc_status = le16_to_cpu(status_desc->ioc_status);
+ if (ioc_status &
+ MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
+ ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info);
+ ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
+ break;
+ case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
+ addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc;
+ *reply_dma = le64_to_cpu(addr_desc->reply_frame_address);
+ scsi_reply = mpi3mr_get_reply_virt_addr(mrioc,
+ *reply_dma);
+ if (!scsi_reply) {
+ panic("%s: scsi_reply is NULL, this shouldn't happen\n",
+ mrioc->name);
+ goto out;
+ }
+ host_tag = le16_to_cpu(scsi_reply->host_tag);
+ ioc_status = le16_to_cpu(scsi_reply->ioc_status);
+ scsi_status = scsi_reply->scsi_status;
+ scsi_state = scsi_reply->scsi_state;
+ dev_handle = le16_to_cpu(scsi_reply->dev_handle);
+ sense_state = (scsi_state & MPI3_SCSI_STATE_SENSE_MASK);
+ xfer_count = le32_to_cpu(scsi_reply->transfer_count);
+ sense_count = le32_to_cpu(scsi_reply->sense_count);
+ resp_data = le32_to_cpu(scsi_reply->response_data);
+ sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc,
+ le64_to_cpu(scsi_reply->sense_data_buffer_address));
+ if (ioc_status &
+ MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
+ ioc_loginfo = le32_to_cpu(scsi_reply->ioc_log_info);
+ ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
+ if (sense_state == MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY)
+ panic("%s: Ran out of sense buffers\n", mrioc->name);
+ break;
+ case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
+ success_desc = (struct mpi3_success_reply_descriptor *)reply_desc;
+ host_tag = le16_to_cpu(success_desc->host_tag);
+ break;
+ default:
+ break;
+ }
+ scmd = mpi3mr_scmd_from_host_tag(mrioc, host_tag, qidx);
+ if (!scmd) {
+ panic("%s: Cannot Identify scmd for host_tag 0x%x\n",
+ mrioc->name, host_tag);
+ goto out;
+ }
+ priv = scsi_cmd_priv(scmd);
+ if (success_desc) {
+ scmd->result = DID_OK << 16;
+ goto out_success;
+ }
+ if (ioc_status == MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN &&
+ xfer_count == 0 && (scsi_status == MPI3_SCSI_STATUS_BUSY ||
+ scsi_status == MPI3_SCSI_STATUS_RESERVATION_CONFLICT ||
+ scsi_status == MPI3_SCSI_STATUS_TASK_SET_FULL))
+ ioc_status = MPI3_IOCSTATUS_SUCCESS;
+
+ if ((sense_state == MPI3_SCSI_STATE_SENSE_VALID) && sense_count &&
+ sense_buf) {
+ u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, sense_count);
+
+ memcpy(scmd->sense_buffer, sense_buf, sz);
+ }
+
+ switch (ioc_status) {
+ case MPI3_IOCSTATUS_BUSY:
+ case MPI3_IOCSTATUS_INSUFFICIENT_RESOURCES:
+ scmd->result = SAM_STAT_BUSY;
+ break;
+ case MPI3_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
+ scmd->result = DID_NO_CONNECT << 16;
+ break;
+ case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED:
+ scmd->result = DID_SOFT_ERROR << 16;
+ break;
+ case MPI3_IOCSTATUS_SCSI_TASK_TERMINATED:
+ case MPI3_IOCSTATUS_SCSI_EXT_TERMINATED:
+ scmd->result = DID_RESET << 16;
+ break;
+ case MPI3_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
+ if ((xfer_count == 0) || (scmd->underflow > xfer_count))
+ scmd->result = DID_SOFT_ERROR << 16;
+ else
+ scmd->result = (DID_OK << 16) | scsi_status;
+ break;
+ case MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN:
+ scmd->result = (DID_OK << 16) | scsi_status;
+ if (sense_state == MPI3_SCSI_STATE_SENSE_VALID)
+ break;
+ if (xfer_count < scmd->underflow) {
+ if (scsi_status == SAM_STAT_BUSY)
+ scmd->result = SAM_STAT_BUSY;
+ else
+ scmd->result = DID_SOFT_ERROR << 16;
+ } else if ((scsi_state & (MPI3_SCSI_STATE_NO_SCSI_STATUS)) ||
+ (sense_state != MPI3_SCSI_STATE_SENSE_NOT_AVAILABLE))
+ scmd->result = DID_SOFT_ERROR << 16;
+ else if (scsi_state & MPI3_SCSI_STATE_TERMINATED)
+ scmd->result = DID_RESET << 16;
+ break;
+ case MPI3_IOCSTATUS_SCSI_DATA_OVERRUN:
+ scsi_set_resid(scmd, 0);
+ fallthrough;
+ case MPI3_IOCSTATUS_SCSI_RECOVERED_ERROR:
+ case MPI3_IOCSTATUS_SUCCESS:
+ scmd->result = (DID_OK << 16) | scsi_status;
+ if ((scsi_state & (MPI3_SCSI_STATE_NO_SCSI_STATUS)) ||
+ (sense_state == MPI3_SCSI_STATE_SENSE_FAILED) ||
+ (sense_state == MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY))
+ scmd->result = DID_SOFT_ERROR << 16;
+ else if (scsi_state & MPI3_SCSI_STATE_TERMINATED)
+ scmd->result = DID_RESET << 16;
+ break;
+ case MPI3_IOCSTATUS_EEDP_GUARD_ERROR:
+ case MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR:
+ case MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR:
+ mpi3mr_map_eedp_error(scmd, ioc_status);
+ break;
+ case MPI3_IOCSTATUS_SCSI_PROTOCOL_ERROR:
+ case MPI3_IOCSTATUS_INVALID_FUNCTION:
+ case MPI3_IOCSTATUS_INVALID_SGL:
+ case MPI3_IOCSTATUS_INTERNAL_ERROR:
+ case MPI3_IOCSTATUS_INVALID_FIELD:
+ case MPI3_IOCSTATUS_INVALID_STATE:
+ case MPI3_IOCSTATUS_SCSI_IO_DATA_ERROR:
+ case MPI3_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
+ case MPI3_IOCSTATUS_INSUFFICIENT_POWER:
+ default:
+ scmd->result = DID_SOFT_ERROR << 16;
+ break;
+ }
+
+ if (scmd->result != (DID_OK << 16) && (scmd->cmnd[0] != ATA_12) &&
+ (scmd->cmnd[0] != ATA_16)) {
+ ioc_info(mrioc, "%s :scmd->result 0x%x\n", __func__,
+ scmd->result);
+ scsi_print_command(scmd);
+ ioc_info(mrioc,
+ "%s :Command issued to handle 0x%02x returned with error 0x%04x loginfo 0x%08x, qid %d\n",
+ __func__, dev_handle, ioc_status, ioc_loginfo,
+ priv->req_q_idx + 1);
+ ioc_info(mrioc,
+ " host_tag %d scsi_state 0x%02x scsi_status 0x%02x, xfer_cnt %d resp_data 0x%x\n",
+ host_tag, scsi_state, scsi_status, xfer_count, resp_data);
+ if (sense_buf) {
+ scsi_normalize_sense(sense_buf, sense_count, &sshdr);
+ ioc_info(mrioc,
+ "%s :sense_count 0x%x, sense_key 0x%x ASC 0x%x, ASCQ 0x%x\n",
+ __func__, sense_count, sshdr.sense_key,
+ sshdr.asc, sshdr.ascq);
+ }
+ }
+out_success:
+ if (priv->meta_sg_valid) {
+ dma_unmap_sg(&mrioc->pdev->dev, scsi_prot_sglist(scmd),
+ scsi_prot_sg_count(scmd), scmd->sc_data_direction);
+ }
+ mpi3mr_clear_scmd_priv(mrioc, scmd);
+ scsi_dma_unmap(scmd);
+ scmd->scsi_done(scmd);
+out:
+ if (sense_buf)
+ mpi3mr_repost_sense_buf(mrioc,
+ le64_to_cpu(scsi_reply->sense_data_buffer_address));
+}
+
+/**
+ * mpi3mr_get_chain_idx - get free chain buffer index
+ * @mrioc: Adapter instance reference
+ *
+ * Try to get a free chain buffer index from the free pool.
+ *
+ * Return: -1 on failure or the free chain buffer index
+ */
+static int mpi3mr_get_chain_idx(struct mpi3mr_ioc *mrioc)
+{
+ u8 retry_count = 5;
+ int cmd_idx = -1;
+
+ do {
+ spin_lock(&mrioc->chain_buf_lock);
+ cmd_idx = find_first_zero_bit(mrioc->chain_bitmap,
+ mrioc->chain_buf_count);
+ if (cmd_idx < mrioc->chain_buf_count) {
+ set_bit(cmd_idx, mrioc->chain_bitmap);
+ spin_unlock(&mrioc->chain_buf_lock);
+ break;
+ }
+ spin_unlock(&mrioc->chain_buf_lock);
+ cmd_idx = -1;
+ } while (retry_count--);
+ return cmd_idx;
+}
+
+/**
+ * mpi3mr_prepare_sg_scmd - build scatter gather list
+ * @mrioc: Adapter instance reference
+ * @scmd: SCSI command reference
+ * @scsiio_req: MPI3 SCSI IO request
+ *
+ * This function maps SCSI command's data and protection SGEs to
+ * MPI request SGEs. If required additional 4K chain buffer is
+ * used to send the SGEs.
+ *
+ * Return: 0 on success, -ENOMEM on dma_map_sg failure
+ */
+static int mpi3mr_prepare_sg_scmd(struct mpi3mr_ioc *mrioc,
+ struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req)
+{
+ dma_addr_t chain_dma;
+ struct scatterlist *sg_scmd;
+ void *sg_local, *chain;
+ u32 chain_length;
+ int sges_left, chain_idx;
+ u32 sges_in_segment;
+ u8 simple_sgl_flags;
+ u8 simple_sgl_flags_last;
+ u8 last_chain_sgl_flags;
+ struct chain_element *chain_req;
+ struct scmd_priv *priv = NULL;
+ u32 meta_sg = le32_to_cpu(scsiio_req->flags) &
+ MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI;
+
+ priv = scsi_cmd_priv(scmd);
+
+ simple_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE |
+ MPI3_SGE_FLAGS_DLAS_SYSTEM;
+ simple_sgl_flags_last = simple_sgl_flags |
+ MPI3_SGE_FLAGS_END_OF_LIST;
+ last_chain_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN |
+ MPI3_SGE_FLAGS_DLAS_SYSTEM;
+
+ if (meta_sg)
+ sg_local = &scsiio_req->sgl[MPI3_SCSIIO_METASGL_INDEX];
+ else
+ sg_local = &scsiio_req->sgl;
+
+ if (!scsiio_req->data_length && !meta_sg) {
+ mpi3mr_build_zero_len_sge(sg_local);
+ return 0;
+ }
+
+ if (meta_sg) {
+ sg_scmd = scsi_prot_sglist(scmd);
+ sges_left = dma_map_sg(&mrioc->pdev->dev,
+ scsi_prot_sglist(scmd),
+ scsi_prot_sg_count(scmd),
+ scmd->sc_data_direction);
+ priv->meta_sg_valid = 1; /* To unmap meta sg DMA */
+ } else {
+ sg_scmd = scsi_sglist(scmd);
+ sges_left = scsi_dma_map(scmd);
+ }
+
+ if (sges_left < 0) {
+ sdev_printk(KERN_ERR, scmd->device,
+ "scsi_dma_map failed: request for %d bytes!\n",
+ scsi_bufflen(scmd));
+ return -ENOMEM;
+ }
+ if (sges_left > MPI3MR_SG_DEPTH) {
+ sdev_printk(KERN_ERR, scmd->device,
+ "scsi_dma_map returned unsupported sge count %d!\n",
+ sges_left);
+ return -ENOMEM;
+ }
+
+ sges_in_segment = (mrioc->facts.op_req_sz -
+ offsetof(struct mpi3_scsi_io_request, sgl)) / sizeof(struct mpi3_sge_common);
+
+ if (scsiio_req->sgl[0].eedp.flags ==
+ MPI3_SGE_FLAGS_ELEMENT_TYPE_EXTENDED && !meta_sg) {
+ sg_local += sizeof(struct mpi3_sge_common);
+ sges_in_segment--;
+ /* Reserve 1st segment (scsiio_req->sgl[0]) for eedp */
+ }
+
+ if (scsiio_req->msg_flags ==
+ MPI3_SCSIIO_MSGFLAGS_METASGL_VALID && !meta_sg) {
+ sges_in_segment--;
+ /* Reserve last segment (scsiio_req->sgl[3]) for meta sg */
+ }
+
+ if (meta_sg)
+ sges_in_segment = 1;
+
+ if (sges_left <= sges_in_segment)
+ goto fill_in_last_segment;
+
+ /* fill in main message segment when there is a chain following */
+ while (sges_in_segment > 1) {
+ mpi3mr_add_sg_single(sg_local, simple_sgl_flags,
+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
+ sg_scmd = sg_next(sg_scmd);
+ sg_local += sizeof(struct mpi3_sge_common);
+ sges_left--;
+ sges_in_segment--;
+ }
+
+ chain_idx = mpi3mr_get_chain_idx(mrioc);
+ if (chain_idx < 0)
+ return -1;
+ chain_req = &mrioc->chain_sgl_list[chain_idx];
+ if (meta_sg)
+ priv->meta_chain_idx = chain_idx;
+ else
+ priv->chain_idx = chain_idx;
+
+ chain = chain_req->addr;
+ chain_dma = chain_req->dma_addr;
+ sges_in_segment = sges_left;
+ chain_length = sges_in_segment * sizeof(struct mpi3_sge_common);
+
+ mpi3mr_add_sg_single(sg_local, last_chain_sgl_flags,
+ chain_length, chain_dma);
+
+ sg_local = chain;
+
+fill_in_last_segment:
+ while (sges_left > 0) {
+ if (sges_left == 1)
+ mpi3mr_add_sg_single(sg_local,
+ simple_sgl_flags_last, sg_dma_len(sg_scmd),
+ sg_dma_address(sg_scmd));
+ else
+ mpi3mr_add_sg_single(sg_local, simple_sgl_flags,
+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
+ sg_scmd = sg_next(sg_scmd);
+ sg_local += sizeof(struct mpi3_sge_common);
+ sges_left--;
+ }
+
+ return 0;
+}
+
+/**
+ * mpi3mr_build_sg_scmd - build scatter gather list for SCSI IO
+ * @mrioc: Adapter instance reference
+ * @scmd: SCSI command reference
+ * @scsiio_req: MPI3 SCSI IO request
+ *
+ * This function calls mpi3mr_prepare_sg_scmd for constructing
+ * both data SGEs and protection information SGEs in the MPI
+ * format from the SCSI Command as appropriate .
+ *
+ * Return: return value of mpi3mr_prepare_sg_scmd.
+ */
+static int mpi3mr_build_sg_scmd(struct mpi3mr_ioc *mrioc,
+ struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req)
+{
+ int ret;
+
+ ret = mpi3mr_prepare_sg_scmd(mrioc, scmd, scsiio_req);
+ if (ret)
+ return ret;
+
+ if (scsiio_req->msg_flags == MPI3_SCSIIO_MSGFLAGS_METASGL_VALID) {
+ /* There is a valid meta sg */
+ scsiio_req->flags |=
+ cpu_to_le32(MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI);
+ ret = mpi3mr_prepare_sg_scmd(mrioc, scmd, scsiio_req);
+ }
+
+ return ret;
+}
+
+/**
+ * mpi3mr_print_response_code - print TM response as a string
+ * @mrioc: Adapter instance reference
+ * @resp_code: TM response code
+ *
+ * Print TM response code as a readable string.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_print_response_code(struct mpi3mr_ioc *mrioc, u8 resp_code)
+{
+ char *desc;
+
+ switch (resp_code) {
+ case MPI3MR_RSP_TM_COMPLETE:
+ desc = "task management request completed";
+ break;
+ case MPI3MR_RSP_INVALID_FRAME:
+ desc = "invalid frame";
+ break;
+ case MPI3MR_RSP_TM_NOT_SUPPORTED:
+ desc = "task management request not supported";
+ break;
+ case MPI3MR_RSP_TM_FAILED:
+ desc = "task management request failed";
+ break;
+ case MPI3MR_RSP_TM_SUCCEEDED:
+ desc = "task management request succeeded";
+ break;
+ case MPI3MR_RSP_TM_INVALID_LUN:
+ desc = "invalid lun";
+ break;
+ case MPI3MR_RSP_TM_OVERLAPPED_TAG:
+ desc = "overlapped tag attempted";
+ break;
+ case MPI3MR_RSP_IO_QUEUED_ON_IOC:
+ desc = "task queued, however not sent to target";
+ break;
+ default:
+ desc = "unknown";
+ break;
+ }
+ ioc_info(mrioc, "%s :response_code(0x%01x): %s\n", __func__,
+ resp_code, desc);
+}
+
+/**
+ * mpi3mr_issue_tm - Issue Task Management request
+ * @mrioc: Adapter instance reference
+ * @tm_type: Task Management type
+ * @handle: Device handle
+ * @lun: lun ID
+ * @htag: Host tag of the TM request
+ * @drv_cmd: Internal command tracker
+ * @resp_code: Response code place holder
+ * @cmd_priv: SCSI command private data
+ *
+ * Issues a Task Management Request to the controller for a
+ * specified target, lun and command and wait for its completion
+ * and check TM response. Recover the TM if it timed out by
+ * issuing controller reset.
+ *
+ * Return: 0 on success, non-zero on errors
+ */
+static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
+ u16 handle, uint lun, u16 htag, ulong timeout,
+ struct mpi3mr_drv_cmd *drv_cmd,
+ u8 *resp_code, struct scmd_priv *cmd_priv)
+{
+ struct mpi3_scsi_task_mgmt_request tm_req;
+ struct mpi3_scsi_task_mgmt_reply *tm_reply = NULL;
+ int retval = 0;
+ struct mpi3mr_tgt_dev *tgtdev = NULL;
+ struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
+ struct op_req_qinfo *op_req_q = NULL;
+
+ ioc_info(mrioc, "%s :Issue TM: TM type (0x%x) for devhandle 0x%04x\n",
+ __func__, tm_type, handle);
+ if (mrioc->unrecoverable) {
+ retval = -1;
+ ioc_err(mrioc, "%s :Issue TM: Unrecoverable controller\n",
+ __func__);
+ goto out;
+ }
+
+ memset(&tm_req, 0, sizeof(tm_req));
+ mutex_lock(&drv_cmd->mutex);
+ if (drv_cmd->state & MPI3MR_CMD_PENDING) {
+ retval = -1;
+ ioc_err(mrioc, "%s :Issue TM: Command is in use\n", __func__);
+ mutex_unlock(&drv_cmd->mutex);
+ goto out;
+ }
+ if (mrioc->reset_in_progress) {
+ retval = -1;
+ ioc_err(mrioc, "%s :Issue TM: Reset in progress\n", __func__);
+ mutex_unlock(&drv_cmd->mutex);
+ goto out;
+ }
+
+ drv_cmd->state = MPI3MR_CMD_PENDING;
+ drv_cmd->is_waiting = 1;
+ drv_cmd->callback = NULL;
+ tm_req.dev_handle = cpu_to_le16(handle);
+ tm_req.task_type = tm_type;
+ tm_req.host_tag = cpu_to_le16(htag);
+
+ int_to_scsilun(lun, (struct scsi_lun *)tm_req.lun);
+ tm_req.function = MPI3_FUNCTION_SCSI_TASK_MGMT;
+
+ tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
+ if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata) {
+ scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
+ tgtdev->starget->hostdata;
+ atomic_inc(&scsi_tgt_priv_data->block_io);
+ }
+ if (cmd_priv) {
+ op_req_q = &mrioc->req_qinfo[cmd_priv->req_q_idx];
+ tm_req.task_host_tag = cpu_to_le16(cmd_priv->host_tag);
+ tm_req.task_request_queue_id = cpu_to_le16(op_req_q->qid);
+ }
+ if (tgtdev && (tgtdev->dev_type == MPI3_DEVICE_DEVFORM_PCIE)) {
+ if (cmd_priv && tgtdev->dev_spec.pcie_inf.abort_to)
+ timeout = tgtdev->dev_spec.pcie_inf.abort_to;
+ else if (!cmd_priv && tgtdev->dev_spec.pcie_inf.reset_to)
+ timeout = tgtdev->dev_spec.pcie_inf.reset_to;
+ }
+
+ init_completion(&drv_cmd->done);
+ retval = mpi3mr_admin_request_post(mrioc, &tm_req, sizeof(tm_req), 1);
+ if (retval) {
+ ioc_err(mrioc, "%s :Issue TM: Admin Post failed\n", __func__);
+ goto out_unlock;
+ }
+ wait_for_completion_timeout(&drv_cmd->done, (timeout * HZ));
+
+ if (!(drv_cmd->state & MPI3MR_CMD_COMPLETE)) {
+ ioc_err(mrioc, "%s :Issue TM: command timed out\n", __func__);
+ drv_cmd->is_waiting = 0;
+ retval = -1;
+ mpi3mr_soft_reset_handler(mrioc,
+ MPI3MR_RESET_FROM_TM_TIMEOUT, 1);
+ goto out_unlock;
+ }
+
+ if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID)
+ tm_reply = (struct mpi3_scsi_task_mgmt_reply *)drv_cmd->reply;
+
+ if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+ ioc_err(mrioc,
+ "%s :Issue TM: handle(0x%04x) Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
+ __func__, handle, drv_cmd->ioc_status,
+ drv_cmd->ioc_loginfo);
+ retval = -1;
+ goto out_unlock;
+ }
+
+ if (!tm_reply) {
+ ioc_err(mrioc, "%s :Issue TM: No TM Reply message\n", __func__);
+ retval = -1;
+ goto out_unlock;
+ }
+
+ *resp_code = le32_to_cpu(tm_reply->response_data) &
+ MPI3MR_RI_MASK_RESPCODE;
+ switch (*resp_code) {
+ case MPI3MR_RSP_TM_SUCCEEDED:
+ case MPI3MR_RSP_TM_COMPLETE:
+ break;
+ case MPI3MR_RSP_IO_QUEUED_ON_IOC:
+ if (tm_type != MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK)
+ retval = -1;
+ break;
+ default:
+ retval = -1;
+ break;
+ }
+
+ ioc_info(mrioc,
+ "%s :Issue TM: Completed TM type (0x%x) handle(0x%04x) ",
+ __func__, tm_type, handle);
+ ioc_info(mrioc,
+ "with ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
+ drv_cmd->ioc_status, drv_cmd->ioc_loginfo,
+ le32_to_cpu(tm_reply->termination_count));
+ mpi3mr_print_response_code(mrioc, *resp_code);
+
+out_unlock:
+ drv_cmd->state = MPI3MR_CMD_NOTUSED;
+ mutex_unlock(&drv_cmd->mutex);
+ if (scsi_tgt_priv_data)
+ atomic_dec_if_positive(&scsi_tgt_priv_data->block_io);
+ if (tgtdev)
+ mpi3mr_tgtdev_put(tgtdev);
+ if (!retval) {
+ /*
+ * Flush all IRQ handlers by calling synchronize_irq().
+ * mpi3mr_ioc_disable_intr() takes care of it.
+ */
+ mpi3mr_ioc_disable_intr(mrioc);
+ mpi3mr_ioc_enable_intr(mrioc);
+ }
+out:
+ return retval;
+}
+
+/**
+ * mpi3mr_bios_param - BIOS param callback
+ * @sdev: SCSI device reference
+ * @bdev: Block device reference
+ * @capacity: Capacity in logical sectors
+ * @params: Parameter array
+ *
+ * Just the parameters with heads/secots/cylinders.
+ *
+ * Return: 0 always
+ */
+static int mpi3mr_bios_param(struct scsi_device *sdev,
+ struct block_device *bdev, sector_t capacity, int params[])
+{
+ int heads;
+ int sectors;
+ sector_t cylinders;
+ ulong dummy;
+
+ heads = 64;
+ sectors = 32;
+
+ dummy = heads * sectors;
+ cylinders = capacity;
+ sector_div(cylinders, dummy);
+
+ if ((ulong)capacity >= 0x200000) {
+ heads = 255;
+ sectors = 63;
+ dummy = heads * sectors;
+ cylinders = capacity;
+ sector_div(cylinders, dummy);
+ }
+
+ params[0] = heads;
+ params[1] = sectors;
+ params[2] = cylinders;
+ return 0;
+}
+
+/**
+ * mpi3mr_map_queues - Map queues callback handler
+ * @shost: SCSI host reference
+ *
+ * Call the blk_mq_pci_map_queues with from which operational
+ * queue the mapping has to be done
+ *
+ * Return: return of blk_mq_pci_map_queues
+ */
+static int mpi3mr_map_queues(struct Scsi_Host *shost)
+{
+ struct mpi3mr_ioc *mrioc = shost_priv(shost);
+
+ return blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT],
+ mrioc->pdev, mrioc->op_reply_q_offset);
+}
+
+/**
+ * mpi3mr_get_fw_pending_ios - Calculate pending I/O count
+ * @mrioc: Adapter instance reference
+ *
+ * Calculate the pending I/Os for the controller and return.
+ *
+ * Return: Number of pending I/Os
+ */
+static inline int mpi3mr_get_fw_pending_ios(struct mpi3mr_ioc *mrioc)
+{
+ u16 i;
+ uint pend_ios = 0;
+
+ for (i = 0; i < mrioc->num_op_reply_q; i++)
+ pend_ios += atomic_read(&mrioc->op_reply_qinfo[i].pend_ios);
+ return pend_ios;
+}
+
+/**
+ * mpi3mr_print_pending_host_io - print pending I/Os
+ * @mrioc: Adapter instance reference
+ *
+ * Print number of pending I/Os and each I/O details prior to
+ * reset for debug purpose.
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_print_pending_host_io(struct mpi3mr_ioc *mrioc)
+{
+ struct Scsi_Host *shost = mrioc->shost;
+
+ ioc_info(mrioc, "%s :Pending commands prior to reset: %d\n",
+ __func__, mpi3mr_get_fw_pending_ios(mrioc));
+ blk_mq_tagset_busy_iter(&shost->tag_set,
+ mpi3mr_print_scmd, (void *)mrioc);
+}
+
+/**
+ * mpi3mr_wait_for_host_io - block for I/Os to complete
+ * @mrioc: Adapter instance reference
+ * @timeout: time out in seconds
+ * Waits for pending I/Os for the given adapter to complete or
+ * to hit the timeout.
+ *
+ * Return: Nothing
+ */
+void mpi3mr_wait_for_host_io(struct mpi3mr_ioc *mrioc, u32 timeout)
+{
+ enum mpi3mr_iocstate iocstate;
+ int i = 0;
+
+ iocstate = mpi3mr_get_iocstate(mrioc);
+ if (iocstate != MRIOC_STATE_READY)
+ return;
+
+ if (!mpi3mr_get_fw_pending_ios(mrioc))
+ return;
+ ioc_info(mrioc,
+ "%s :Waiting for %d seconds prior to reset for %d I/O\n",
+ __func__, timeout, mpi3mr_get_fw_pending_ios(mrioc));
+
+ for (i = 0; i < timeout; i++) {
+ if (!mpi3mr_get_fw_pending_ios(mrioc))
+ break;
+ iocstate = mpi3mr_get_iocstate(mrioc);
+ if (iocstate != MRIOC_STATE_READY)
+ break;
+ msleep(1000);
+ }
+
+ ioc_info(mrioc, "%s :Pending I/Os after wait is: %d\n", __func__,
+ mpi3mr_get_fw_pending_ios(mrioc));
+}
+
+/**
+ * mpi3mr_eh_host_reset - Host reset error handling callback
+ * @scmd: SCSI command reference
+ *
+ * Issue controller reset if the scmd is for a Physical Device,
+ * if the scmd is for RAID volume, then wait for
+ * MPI3MR_RAID_ERRREC_RESET_TIMEOUT and checke whether any
+ * pending I/Os prior to issuing reset to the controller.
+ *
+ * Return: SUCCESS of successful reset else FAILED
+ */
+static int mpi3mr_eh_host_reset(struct scsi_cmnd *scmd)
+{
+ struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host);
+ struct mpi3mr_stgt_priv_data *stgt_priv_data;
+ struct mpi3mr_sdev_priv_data *sdev_priv_data;
+ u8 dev_type = MPI3_DEVICE_DEVFORM_VD;
+ int retval = FAILED, ret;
+
+ sdev_priv_data = scmd->device->hostdata;
+ if (sdev_priv_data && sdev_priv_data->tgt_priv_data) {
+ stgt_priv_data = sdev_priv_data->tgt_priv_data;
+ dev_type = stgt_priv_data->dev_type;
+ }
+
+ if (dev_type == MPI3_DEVICE_DEVFORM_VD) {
+ mpi3mr_wait_for_host_io(mrioc,
+ MPI3MR_RAID_ERRREC_RESET_TIMEOUT);
+ if (!mpi3mr_get_fw_pending_ios(mrioc)) {
+ retval = SUCCESS;
+ goto out;
+ }
+ }
+
+ mpi3mr_print_pending_host_io(mrioc);
+ ret = mpi3mr_soft_reset_handler(mrioc,
+ MPI3MR_RESET_FROM_EH_HOS, 1);
+ if (ret)
+ goto out;
+
+ retval = SUCCESS;
+out:
+ sdev_printk(KERN_INFO, scmd->device,
+ "Host reset is %s for scmd(%p)\n",
+ ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+
+ return retval;
+}
+
+/**
+ * mpi3mr_eh_target_reset - Target reset error handling callback
+ * @scmd: SCSI command reference
+ *
+ * Issue Target reset Task Management and verify the scmd is
+ * terminated successfully and return status accordingly.
+ *
+ * Return: SUCCESS of successful termination of the scmd else
+ * FAILED
+ */
+static int mpi3mr_eh_target_reset(struct scsi_cmnd *scmd)
+{
+ struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host);
+ struct mpi3mr_stgt_priv_data *stgt_priv_data;
+ struct mpi3mr_sdev_priv_data *sdev_priv_data;
+ u16 dev_handle;
+ u8 resp_code = 0;
+ int retval = FAILED, ret = 0;
+
+ sdev_printk(KERN_INFO, scmd->device,
+ "Attempting Target Reset! scmd(%p)\n", scmd);
+ scsi_print_command(scmd);
+
+ sdev_priv_data = scmd->device->hostdata;
+ if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) {
+ sdev_printk(KERN_INFO, scmd->device,
+ "SCSI device is not available\n");
+ retval = SUCCESS;
+ goto out;
+ }
+
+ stgt_priv_data = sdev_priv_data->tgt_priv_data;
+ dev_handle = stgt_priv_data->dev_handle;
+ sdev_printk(KERN_INFO, scmd->device,
+ "Target Reset is issued to handle(0x%04x)\n",
+ dev_handle);
+
+ ret = mpi3mr_issue_tm(mrioc,
+ MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET, dev_handle,
+ sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS,
+ MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, NULL);
+
+ if (ret)
+ goto out;
+
+ retval = SUCCESS;
+out:
+ sdev_printk(KERN_INFO, scmd->device,
+ "Target reset is %s for scmd(%p)\n",
+ ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+
+ return retval;
+}
+
+/**
+ * mpi3mr_eh_dev_reset- Device reset error handling callback
+ * @scmd: SCSI command reference
+ *
+ * Issue lun reset Task Management and verify the scmd is
+ * terminated successfully and return status accordingly.
+ *
+ * Return: SUCCESS of successful termination of the scmd else
+ * FAILED
+ */
+static int mpi3mr_eh_dev_reset(struct scsi_cmnd *scmd)
+{
+ struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host);
+ struct mpi3mr_stgt_priv_data *stgt_priv_data;
+ struct mpi3mr_sdev_priv_data *sdev_priv_data;
+ u16 dev_handle;
+ u8 resp_code = 0;
+ int retval = FAILED, ret = 0;
+
+ sdev_printk(KERN_INFO, scmd->device,
+ "Attempting Device(lun) Reset! scmd(%p)\n", scmd);
+ scsi_print_command(scmd);
+
+ sdev_priv_data = scmd->device->hostdata;
+ if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) {
+ sdev_printk(KERN_INFO, scmd->device,
+ "SCSI device is not available\n");
+ retval = SUCCESS;
+ goto out;
+ }
+
+ stgt_priv_data = sdev_priv_data->tgt_priv_data;
+ dev_handle = stgt_priv_data->dev_handle;
+ sdev_printk(KERN_INFO, scmd->device,
+ "Device(lun) Reset is issued to handle(0x%04x)\n", dev_handle);
+
+ ret = mpi3mr_issue_tm(mrioc,
+ MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, dev_handle,
+ sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS,
+ MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, NULL);
+
+ if (ret)
+ goto out;
+
+ retval = SUCCESS;
+out:
+ sdev_printk(KERN_INFO, scmd->device,
+ "Device(lun) reset is %s for scmd(%p)\n",
+ ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+
+ return retval;
+}
+
+/**
+ * mpi3mr_scan_start - Scan start callback handler
+ * @shost: SCSI host reference
+ *
+ * Issue port enable request asynchronously.
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_scan_start(struct Scsi_Host *shost)
+{
+ struct mpi3mr_ioc *mrioc = shost_priv(shost);
+
+ mrioc->scan_started = 1;
+ ioc_info(mrioc, "%s :Issuing Port Enable\n", __func__);
+ if (mpi3mr_issue_port_enable(mrioc, 1)) {
+ ioc_err(mrioc, "%s :Issuing port enable failed\n", __func__);
+ mrioc->scan_started = 0;
+ mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR;
+ }
+}
+
+/**
+ * mpi3mr_scan_finished - Scan finished callback handler
+ * @shost: SCSI host reference
+ * @time: Jiffies from the scan start
+ *
+ * Checks whether the port enable is completed or timedout or
+ * failed and set the scan status accordingly after taking any
+ * recovery if required.
+ *
+ * Return: 1 on scan finished or timed out, 0 for in progress
+ */
+static int mpi3mr_scan_finished(struct Scsi_Host *shost,
+ unsigned long time)
+{
+ struct mpi3mr_ioc *mrioc = shost_priv(shost);
+ u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT;
+
+ if (time >= (pe_timeout * HZ)) {
+ mrioc->init_cmds.is_waiting = 0;
+ mrioc->init_cmds.callback = NULL;
+ mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
+ ioc_err(mrioc, "%s :port enable request timed out\n", __func__);
+ mrioc->is_driver_loading = 0;
+ mpi3mr_soft_reset_handler(mrioc,
+ MPI3MR_RESET_FROM_PE_TIMEOUT, 1);
+ }
+
+ if (mrioc->scan_failed) {
+ ioc_err(mrioc,
+ "%s :port enable failed with (ioc_status=0x%08x)\n",
+ __func__, mrioc->scan_failed);
+ mrioc->is_driver_loading = 0;
+ mrioc->stop_drv_processing = 1;
+ return 1;
+ }
+
+ if (mrioc->scan_started)
+ return 0;
+ ioc_info(mrioc, "%s :port enable: SUCCESS\n", __func__);
+ mpi3mr_start_watchdog(mrioc);
+ mrioc->is_driver_loading = 0;
+
+ return 1;
+}
+
+/**
+ * mpi3mr_slave_destroy - Slave destroy callback handler
+ * @sdev: SCSI device reference
+ *
+ * Cleanup and free per device(lun) private data.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_slave_destroy(struct scsi_device *sdev)
+{
+ struct Scsi_Host *shost;
+ struct mpi3mr_ioc *mrioc;
+ struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
+ struct mpi3mr_tgt_dev *tgt_dev;
+ unsigned long flags;
+ struct scsi_target *starget;
+
+ if (!sdev->hostdata)
+ return;
+
+ starget = scsi_target(sdev);
+ shost = dev_to_shost(&starget->dev);
+ mrioc = shost_priv(shost);
+ scsi_tgt_priv_data = starget->hostdata;
+
+ scsi_tgt_priv_data->num_luns--;
+
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+ tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
+ if (tgt_dev && (!scsi_tgt_priv_data->num_luns))
+ tgt_dev->starget = NULL;
+ if (tgt_dev)
+ mpi3mr_tgtdev_put(tgt_dev);
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+
+ kfree(sdev->hostdata);
+ sdev->hostdata = NULL;
+}
+
+/**
+ * mpi3mr_target_destroy - Target destroy callback handler
+ * @starget: SCSI target reference
+ *
+ * Cleanup and free per target private data.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_target_destroy(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost;
+ struct mpi3mr_ioc *mrioc;
+ struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
+ struct mpi3mr_tgt_dev *tgt_dev;
+ unsigned long flags;
+
+ if (!starget->hostdata)
+ return;
+
+ shost = dev_to_shost(&starget->dev);
+ mrioc = shost_priv(shost);
+ scsi_tgt_priv_data = starget->hostdata;
+
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+ tgt_dev = __mpi3mr_get_tgtdev_from_tgtpriv(mrioc, scsi_tgt_priv_data);
+ if (tgt_dev && (tgt_dev->starget == starget) &&
+ (tgt_dev->perst_id == starget->id))
+ tgt_dev->starget = NULL;
+ if (tgt_dev) {
+ scsi_tgt_priv_data->tgt_dev = NULL;
+ scsi_tgt_priv_data->perst_id = 0;
+ mpi3mr_tgtdev_put(tgt_dev);
+ mpi3mr_tgtdev_put(tgt_dev);
+ }
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+
+ kfree(starget->hostdata);
+ starget->hostdata = NULL;
+}
+
+/**
+ * mpi3mr_slave_configure - Slave configure callback handler
+ * @sdev: SCSI device reference
+ *
+ * Configure queue depth, max hardware sectors and virt boundary
+ * as required
+ *
+ * Return: 0 always.
+ */
+static int mpi3mr_slave_configure(struct scsi_device *sdev)
+{
+ struct scsi_target *starget;
+ struct Scsi_Host *shost;
+ struct mpi3mr_ioc *mrioc;
+ struct mpi3mr_tgt_dev *tgt_dev;
+ unsigned long flags;
+ int retval = 0;
+
+ starget = scsi_target(sdev);
+ shost = dev_to_shost(&starget->dev);
+ mrioc = shost_priv(shost);
+
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+ tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+ if (!tgt_dev)
+ return -ENXIO;
+
+ mpi3mr_change_queue_depth(sdev, tgt_dev->q_depth);
+ switch (tgt_dev->dev_type) {
+ case MPI3_DEVICE_DEVFORM_PCIE:
+ /*The block layer hw sector size = 512*/
+ blk_queue_max_hw_sectors(sdev->request_queue,
+ tgt_dev->dev_spec.pcie_inf.mdts / 512);
+ blk_queue_virt_boundary(sdev->request_queue,
+ ((1 << tgt_dev->dev_spec.pcie_inf.pgsz) - 1));
+ break;
+ default:
+ break;
+ }
+
+ mpi3mr_tgtdev_put(tgt_dev);
+
+ return retval;
+}
+
+/**
+ * mpi3mr_slave_alloc -Slave alloc callback handler
+ * @sdev: SCSI device reference
+ *
+ * Allocate per device(lun) private data and initialize it.
+ *
+ * Return: 0 on success -ENOMEM on memory allocation failure.
+ */
+static int mpi3mr_slave_alloc(struct scsi_device *sdev)
+{
+ struct Scsi_Host *shost;
+ struct mpi3mr_ioc *mrioc;
+ struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
+ struct mpi3mr_tgt_dev *tgt_dev;
+ struct mpi3mr_sdev_priv_data *scsi_dev_priv_data;
+ unsigned long flags;
+ struct scsi_target *starget;
+ int retval = 0;
+
+ starget = scsi_target(sdev);
+ shost = dev_to_shost(&starget->dev);
+ mrioc = shost_priv(shost);
+ scsi_tgt_priv_data = starget->hostdata;
+
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+ tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
+
+ if (tgt_dev) {
+ if (tgt_dev->starget == NULL)
+ tgt_dev->starget = starget;
+ mpi3mr_tgtdev_put(tgt_dev);
+ retval = 0;
+ } else {
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+ return -ENXIO;
+ }
+
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+
+ scsi_dev_priv_data = kzalloc(sizeof(*scsi_dev_priv_data), GFP_KERNEL);
+ if (!scsi_dev_priv_data)
+ return -ENOMEM;
+
+ scsi_dev_priv_data->lun_id = sdev->lun;
+ scsi_dev_priv_data->tgt_priv_data = scsi_tgt_priv_data;
+ sdev->hostdata = scsi_dev_priv_data;
+
+ scsi_tgt_priv_data->num_luns++;
+
+ return retval;
+}
+
+/**
+ * mpi3mr_target_alloc - Target alloc callback handler
+ * @starget: SCSI target reference
+ *
+ * Allocate per target private data and initialize it.
+ *
+ * Return: 0 on success -ENOMEM on memory allocation failure.
+ */
+static int mpi3mr_target_alloc(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+ struct mpi3mr_ioc *mrioc = shost_priv(shost);
+ struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
+ struct mpi3mr_tgt_dev *tgt_dev;
+ unsigned long flags;
+ int retval = 0;
+
+ scsi_tgt_priv_data = kzalloc(sizeof(*scsi_tgt_priv_data), GFP_KERNEL);
+ if (!scsi_tgt_priv_data)
+ return -ENOMEM;
+
+ starget->hostdata = scsi_tgt_priv_data;
+
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+ tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
+ if (tgt_dev && !tgt_dev->is_hidden) {
+ scsi_tgt_priv_data->starget = starget;
+ scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle;
+ scsi_tgt_priv_data->perst_id = tgt_dev->perst_id;
+ scsi_tgt_priv_data->dev_type = tgt_dev->dev_type;
+ scsi_tgt_priv_data->tgt_dev = tgt_dev;
+ tgt_dev->starget = starget;
+ atomic_set(&scsi_tgt_priv_data->block_io, 0);
+ retval = 0;
+ } else
+ retval = -ENXIO;
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+
+ return retval;
+}
+
+/**
+ * mpi3mr_check_return_unmap - Whether an unmap is allowed
+ * @mrioc: Adapter instance reference
+ * @scmd: SCSI Command reference
+ *
+ * The controller hardware cannot handle certain unmap commands
+ * for NVMe drives, this routine checks those and return true
+ * and completes the SCSI command with proper status and sense
+ * data.
+ *
+ * Return: TRUE for not allowed unmap, FALSE otherwise.
+ */
+static bool mpi3mr_check_return_unmap(struct mpi3mr_ioc *mrioc,
+ struct scsi_cmnd *scmd)
+{
+ unsigned char *buf;
+ u16 param_len, desc_len;
+
+ param_len = get_unaligned_be16(scmd->cmnd + 7);
+
+ if (!param_len) {
+ ioc_warn(mrioc,
+ "%s: cdb received with zero parameter length\n",
+ __func__);
+ scsi_print_command(scmd);
+ scmd->result = DID_OK << 16;
+ scmd->scsi_done(scmd);
+ return true;
+ }
+
+ if (param_len < 24) {
+ ioc_warn(mrioc,
+ "%s: cdb received with invalid param_len: %d\n",
+ __func__, param_len);
+ scsi_print_command(scmd);
+ scmd->result = SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
+ 0x1A, 0);
+ scmd->scsi_done(scmd);
+ return true;
+ }
+ if (param_len != scsi_bufflen(scmd)) {
+ ioc_warn(mrioc,
+ "%s: cdb received with param_len: %d bufflen: %d\n",
+ __func__, param_len, scsi_bufflen(scmd));
+ scsi_print_command(scmd);
+ scmd->result = SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
+ 0x1A, 0);
+ scmd->scsi_done(scmd);
+ return true;
+ }
+ buf = kzalloc(scsi_bufflen(scmd), GFP_ATOMIC);
+ if (!buf) {
+ scsi_print_command(scmd);
+ scmd->result = SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
+ 0x55, 0x03);
+ scmd->scsi_done(scmd);
+ return true;
+ }
+ scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
+ desc_len = get_unaligned_be16(&buf[2]);
+
+ if (desc_len < 16) {
+ ioc_warn(mrioc,
+ "%s: Invalid descriptor length in param list: %d\n",
+ __func__, desc_len);
+ scsi_print_command(scmd);
+ scmd->result = SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
+ 0x26, 0);
+ scmd->scsi_done(scmd);
+ kfree(buf);
+ return true;
+ }
+
+ if (param_len > (desc_len + 8)) {
+ scsi_print_command(scmd);
+ ioc_warn(mrioc,
+ "%s: Truncating param_len(%d) to desc_len+8(%d)\n",
+ __func__, param_len, (desc_len + 8));
+ param_len = desc_len + 8;
+ put_unaligned_be16(param_len, scmd->cmnd + 7);
+ scsi_print_command(scmd);
+ }
+
+ kfree(buf);
+ return false;
+}
+
+/**
+ * mpi3mr_allow_scmd_to_fw - Command is allowed during shutdown
+ * @scmd: SCSI Command reference
+ *
+ * Checks whether a cdb is allowed during shutdown or not.
+ *
+ * Return: TRUE for allowed commands, FALSE otherwise.
+ */
+
+inline bool mpi3mr_allow_scmd_to_fw(struct scsi_cmnd *scmd)
+{
+ switch (scmd->cmnd[0]) {
+ case SYNCHRONIZE_CACHE:
+ case START_STOP:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * mpi3mr_qcmd - I/O request despatcher
+ * @shost: SCSI Host reference
+ * @scmd: SCSI Command reference
+ *
+ * Issues the SCSI Command as an MPI3 request.
+ *
+ * Return: 0 on successful queueing of the request or if the
+ * request is completed with failure.
+ * SCSI_MLQUEUE_DEVICE_BUSY when the device is busy.
+ * SCSI_MLQUEUE_HOST_BUSY when the host queue is full.
+ */
+static int mpi3mr_qcmd(struct Scsi_Host *shost,
+ struct scsi_cmnd *scmd)
+{
+ struct mpi3mr_ioc *mrioc = shost_priv(shost);
+ struct mpi3mr_stgt_priv_data *stgt_priv_data;
+ struct mpi3mr_sdev_priv_data *sdev_priv_data;
+ struct scmd_priv *scmd_priv_data = NULL;
+ struct mpi3_scsi_io_request *scsiio_req = NULL;
+ struct op_req_qinfo *op_req_q = NULL;
+ int retval = 0;
+ u16 dev_handle;
+ u16 host_tag;
+ u32 scsiio_flags = 0;
+ struct request *rq = scmd->request;
+ int iprio_class;
+
+ sdev_priv_data = scmd->device->hostdata;
+ if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) {
+ scmd->result = DID_NO_CONNECT << 16;
+ scmd->scsi_done(scmd);
+ goto out;
+ }
+
+ if (mrioc->stop_drv_processing &&
+ !(mpi3mr_allow_scmd_to_fw(scmd))) {
+ scmd->result = DID_NO_CONNECT << 16;
+ scmd->scsi_done(scmd);
+ goto out;
+ }
+
+ if (mrioc->reset_in_progress) {
+ retval = SCSI_MLQUEUE_HOST_BUSY;
+ goto out;
+ }
+
+ stgt_priv_data = sdev_priv_data->tgt_priv_data;
+
+ dev_handle = stgt_priv_data->dev_handle;
+ if (dev_handle == MPI3MR_INVALID_DEV_HANDLE) {
+ scmd->result = DID_NO_CONNECT << 16;
+ scmd->scsi_done(scmd);
+ goto out;
+ }
+ if (stgt_priv_data->dev_removed) {
+ scmd->result = DID_NO_CONNECT << 16;
+ scmd->scsi_done(scmd);
+ goto out;
+ }
+
+ if (atomic_read(&stgt_priv_data->block_io)) {
+ if (mrioc->stop_drv_processing) {
+ scmd->result = DID_NO_CONNECT << 16;
+ scmd->scsi_done(scmd);
+ goto out;
+ }
+ retval = SCSI_MLQUEUE_DEVICE_BUSY;
+ goto out;
+ }
+
+ if ((scmd->cmnd[0] == UNMAP) &&
+ (stgt_priv_data->dev_type == MPI3_DEVICE_DEVFORM_PCIE) &&
+ mpi3mr_check_return_unmap(mrioc, scmd))
+ goto out;
+
+ host_tag = mpi3mr_host_tag_for_scmd(mrioc, scmd);
+ if (host_tag == MPI3MR_HOSTTAG_INVALID) {
+ scmd->result = DID_ERROR << 16;
+ scmd->scsi_done(scmd);
+ goto out;
+ }
+
+ if (scmd->sc_data_direction == DMA_FROM_DEVICE)
+ scsiio_flags = MPI3_SCSIIO_FLAGS_DATADIRECTION_READ;
+ else if (scmd->sc_data_direction == DMA_TO_DEVICE)
+ scsiio_flags = MPI3_SCSIIO_FLAGS_DATADIRECTION_WRITE;
+ else
+ scsiio_flags = MPI3_SCSIIO_FLAGS_DATADIRECTION_NO_DATA_TRANSFER;
+
+ scsiio_flags |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SIMPLEQ;
+
+ if (sdev_priv_data->ncq_prio_enable) {
+ iprio_class = IOPRIO_PRIO_CLASS(req_get_ioprio(rq));
+ if (iprio_class == IOPRIO_CLASS_RT)
+ scsiio_flags |= 1 << MPI3_SCSIIO_FLAGS_CMDPRI_SHIFT;
+ }
+
+ if (scmd->cmd_len > 16)
+ scsiio_flags |= MPI3_SCSIIO_FLAGS_CDB_GREATER_THAN_16;
+
+ scmd_priv_data = scsi_cmd_priv(scmd);
+ memset(scmd_priv_data->mpi3mr_scsiio_req, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
+ scsiio_req = (struct mpi3_scsi_io_request *)scmd_priv_data->mpi3mr_scsiio_req;
+ scsiio_req->function = MPI3_FUNCTION_SCSI_IO;
+ scsiio_req->host_tag = cpu_to_le16(host_tag);
+
+ mpi3mr_setup_eedp(mrioc, scmd, scsiio_req);
+
+ memcpy(scsiio_req->cdb.cdb32, scmd->cmnd, scmd->cmd_len);
+ scsiio_req->data_length = cpu_to_le32(scsi_bufflen(scmd));
+ scsiio_req->dev_handle = cpu_to_le16(dev_handle);
+ scsiio_req->flags = cpu_to_le32(scsiio_flags);
+ int_to_scsilun(sdev_priv_data->lun_id,
+ (struct scsi_lun *)scsiio_req->lun);
+
+ if (mpi3mr_build_sg_scmd(mrioc, scmd, scsiio_req)) {
+ mpi3mr_clear_scmd_priv(mrioc, scmd);
+ retval = SCSI_MLQUEUE_HOST_BUSY;
+ goto out;
+ }
+ op_req_q = &mrioc->req_qinfo[scmd_priv_data->req_q_idx];
+
+ if (mpi3mr_op_request_post(mrioc, op_req_q,
+ scmd_priv_data->mpi3mr_scsiio_req)) {
+ mpi3mr_clear_scmd_priv(mrioc, scmd);
+ retval = SCSI_MLQUEUE_HOST_BUSY;
+ goto out;
+ }
+
+out:
+ return retval;
+}
+
+static struct scsi_host_template mpi3mr_driver_template = {
+ .module = THIS_MODULE,
+ .name = "MPI3 Storage Controller",
+ .proc_name = MPI3MR_DRIVER_NAME,
+ .queuecommand = mpi3mr_qcmd,
+ .target_alloc = mpi3mr_target_alloc,
+ .slave_alloc = mpi3mr_slave_alloc,
+ .slave_configure = mpi3mr_slave_configure,
+ .target_destroy = mpi3mr_target_destroy,
+ .slave_destroy = mpi3mr_slave_destroy,
+ .scan_finished = mpi3mr_scan_finished,
+ .scan_start = mpi3mr_scan_start,
+ .change_queue_depth = mpi3mr_change_queue_depth,
+ .eh_device_reset_handler = mpi3mr_eh_dev_reset,
+ .eh_target_reset_handler = mpi3mr_eh_target_reset,
+ .eh_host_reset_handler = mpi3mr_eh_host_reset,
+ .bios_param = mpi3mr_bios_param,
+ .map_queues = mpi3mr_map_queues,
+ .no_write_same = 1,
+ .can_queue = 1,
+ .this_id = -1,
+ .sg_tablesize = MPI3MR_SG_DEPTH,
+ /* max xfer supported is 1M (2K in 512 byte sized sectors)
+ */
+ .max_sectors = 2048,
+ .cmd_per_lun = MPI3MR_MAX_CMDS_LUN,
+ .track_queue_depth = 1,
+ .cmd_size = sizeof(struct scmd_priv),
+};
+
+/**
+ * mpi3mr_init_drv_cmd - Initialize internal command tracker
+ * @cmdptr: Internal command tracker
+ * @host_tag: Host tag used for the specific command
+ *
+ * Initialize the internal command tracker structure with
+ * specified host tag.
+ *
+ * Return: Nothing.
+ */
+static inline void mpi3mr_init_drv_cmd(struct mpi3mr_drv_cmd *cmdptr,
+ u16 host_tag)
+{
+ mutex_init(&cmdptr->mutex);
+ cmdptr->reply = NULL;
+ cmdptr->state = MPI3MR_CMD_NOTUSED;
+ cmdptr->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
+ cmdptr->host_tag = host_tag;
+}
+
+/**
+ * osintfc_mrioc_security_status -Check controller secure status
+ * @pdev: PCI device instance
+ *
+ * Read the Device Serial Number capability from PCI config
+ * space and decide whether the controller is secure or not.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int
+osintfc_mrioc_security_status(struct pci_dev *pdev)
+{
+ u32 cap_data;
+ int base;
+ u32 ctlr_status;
+ u32 debug_status;
+ int retval = 0;
+
+ base = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DSN);
+ if (!base) {
+ dev_err(&pdev->dev,
+ "%s: PCI_EXT_CAP_ID_DSN is not supported\n", __func__);
+ return -1;
+ }
+
+ pci_read_config_dword(pdev, base + 4, &cap_data);
+
+ debug_status = cap_data & MPI3MR_CTLR_SECURE_DBG_STATUS_MASK;
+ ctlr_status = cap_data & MPI3MR_CTLR_SECURITY_STATUS_MASK;
+
+ switch (ctlr_status) {
+ case MPI3MR_INVALID_DEVICE:
+ dev_err(&pdev->dev,
+ "%s: Non secure ctlr (Invalid) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
+ __func__, pdev->device, pdev->subsystem_vendor,
+ pdev->subsystem_device);
+ retval = -1;
+ break;
+ case MPI3MR_CONFIG_SECURE_DEVICE:
+ if (!debug_status)
+ dev_info(&pdev->dev,
+ "%s: Config secure ctlr is detected\n",
+ __func__);
+ break;
+ case MPI3MR_HARD_SECURE_DEVICE:
+ break;
+ case MPI3MR_TAMPERED_DEVICE:
+ dev_err(&pdev->dev,
+ "%s: Non secure ctlr (Tampered) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
+ __func__, pdev->device, pdev->subsystem_vendor,
+ pdev->subsystem_device);
+ retval = -1;
+ break;
+ default:
+ retval = -1;
+ break;
+ }
+
+ if (!retval && debug_status) {
+ dev_err(&pdev->dev,
+ "%s: Non secure ctlr (Secure Dbg) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n",
+ __func__, pdev->device, pdev->subsystem_vendor,
+ pdev->subsystem_device);
+ retval = -1;
+ }
+
+ return retval;
+}
+
+/**
+ * mpi3mr_probe - PCI probe callback
+ * @pdev: PCI device instance
+ * @id: PCI device ID details
+ *
+ * controller initialization routine. Checks the security status
+ * of the controller and if it is invalid or tampered return the
+ * probe without initializing the controller. Otherwise,
+ * allocate per adapter instance through shost_priv and
+ * initialize controller specific data structures, initializae
+ * the controller hardware, add shost to the SCSI subsystem.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+
+static int
+mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct mpi3mr_ioc *mrioc = NULL;
+ struct Scsi_Host *shost = NULL;
+ int retval = 0, i;
+
+ if (osintfc_mrioc_security_status(pdev)) {
+ warn_non_secure_ctlr = 1;
+ return 1; /* For Invalid and Tampered device */
+ }
+
+ shost = scsi_host_alloc(&mpi3mr_driver_template,
+ sizeof(struct mpi3mr_ioc));
+ if (!shost) {
+ retval = -ENODEV;
+ goto shost_failed;
+ }
+
+ mrioc = shost_priv(shost);
+ mrioc->id = mrioc_ids++;
+ sprintf(mrioc->driver_name, "%s", MPI3MR_DRIVER_NAME);
+ sprintf(mrioc->name, "%s%d", mrioc->driver_name, mrioc->id);
+ INIT_LIST_HEAD(&mrioc->list);
+ spin_lock(&mrioc_list_lock);
+ list_add_tail(&mrioc->list, &mrioc_list);
+ spin_unlock(&mrioc_list_lock);
+
+ spin_lock_init(&mrioc->admin_req_lock);
+ spin_lock_init(&mrioc->reply_free_queue_lock);
+ spin_lock_init(&mrioc->sbq_lock);
+ spin_lock_init(&mrioc->fwevt_lock);
+ spin_lock_init(&mrioc->tgtdev_lock);
+ spin_lock_init(&mrioc->watchdog_lock);
+ spin_lock_init(&mrioc->chain_buf_lock);
+
+ INIT_LIST_HEAD(&mrioc->fwevt_list);
+ INIT_LIST_HEAD(&mrioc->tgtdev_list);
+ INIT_LIST_HEAD(&mrioc->delayed_rmhs_list);
+
+ mutex_init(&mrioc->reset_mutex);
+ mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);
+ mpi3mr_init_drv_cmd(&mrioc->host_tm_cmds, MPI3MR_HOSTTAG_BLK_TMS);
+
+ for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
+ mpi3mr_init_drv_cmd(&mrioc->dev_rmhs_cmds[i],
+ MPI3MR_HOSTTAG_DEVRMCMD_MIN + i);
+
+ if (pdev->revision)
+ mrioc->enable_segqueue = true;
+
+ init_waitqueue_head(&mrioc->reset_waitq);
+ mrioc->logging_level = logging_level;
+ mrioc->shost = shost;
+ mrioc->pdev = pdev;
+
+ /* init shost parameters */
+ shost->max_cmd_len = MPI3MR_MAX_CDB_LENGTH;
+ shost->max_lun = -1;
+ shost->unique_id = mrioc->id;
+
+ shost->max_channel = 1;
+ shost->max_id = 0xFFFFFFFF;
+
+ if (prot_mask >= 0)
+ scsi_host_set_prot(shost, prot_mask);
+ else {
+ prot_mask = SHOST_DIF_TYPE1_PROTECTION
+ | SHOST_DIF_TYPE2_PROTECTION
+ | SHOST_DIF_TYPE3_PROTECTION;
+ scsi_host_set_prot(shost, prot_mask);
+ }
+
+ ioc_info(mrioc,
+ "%s :host protection capabilities enabled %s%s%s%s%s%s%s\n",
+ __func__,
+ (prot_mask & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
+ (prot_mask & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
+ (prot_mask & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
+ (prot_mask & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
+ (prot_mask & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
+ (prot_mask & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
+ (prot_mask & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
+
+ if (prot_guard_mask)
+ scsi_host_set_guard(shost, (prot_guard_mask & 3));
+ else
+ scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
+
+ snprintf(mrioc->fwevt_worker_name, sizeof(mrioc->fwevt_worker_name),
+ "%s%d_fwevt_wrkr", mrioc->driver_name, mrioc->id);
+ mrioc->fwevt_worker_thread = alloc_ordered_workqueue(
+ mrioc->fwevt_worker_name, WQ_MEM_RECLAIM);
+ if (!mrioc->fwevt_worker_thread) {
+ ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
+ retval = -ENODEV;
+ goto out_fwevtthread_failed;
+ }
+
+ mrioc->is_driver_loading = 1;
+ if (mpi3mr_init_ioc(mrioc, 0)) {
+ ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
+ retval = -ENODEV;
+ goto out_iocinit_failed;
+ }
+
+ shost->nr_hw_queues = mrioc->num_op_reply_q;
+ shost->can_queue = mrioc->max_host_ios;
+ shost->sg_tablesize = MPI3MR_SG_DEPTH;
+ shost->max_id = mrioc->facts.max_perids;
+
+ retval = scsi_add_host(shost, &pdev->dev);
+ if (retval) {
+ ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
+ goto addhost_failed;
+ }
+
+ scsi_scan_host(shost);
+ return retval;
+
+addhost_failed:
+ mpi3mr_cleanup_ioc(mrioc, 0);
+out_iocinit_failed:
+ destroy_workqueue(mrioc->fwevt_worker_thread);
+out_fwevtthread_failed:
+ spin_lock(&mrioc_list_lock);
+ list_del(&mrioc->list);
+ spin_unlock(&mrioc_list_lock);
+ scsi_host_put(shost);
+shost_failed:
+ return retval;
+}
+
+/**
+ * mpi3mr_remove - PCI remove callback
+ * @pdev: PCI device instance
+ *
+ * Free up all memory and resources associated with the
+ * controllerand target devices, unregister the shost.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_remove(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct mpi3mr_ioc *mrioc;
+ struct workqueue_struct *wq;
+ unsigned long flags;
+ struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next;
+
+ if (!shost)
+ return;
+
+ mrioc = shost_priv(shost);
+ while (mrioc->reset_in_progress || mrioc->is_driver_loading)
+ ssleep(1);
+
+ mrioc->stop_drv_processing = 1;
+ mpi3mr_cleanup_fwevt_list(mrioc);
+ spin_lock_irqsave(&mrioc->fwevt_lock, flags);
+ wq = mrioc->fwevt_worker_thread;
+ mrioc->fwevt_worker_thread = NULL;
+ spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
+ if (wq)
+ destroy_workqueue(wq);
+ scsi_remove_host(shost);
+
+ list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list,
+ list) {
+ mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
+ mpi3mr_tgtdev_del_from_list(mrioc, tgtdev);
+ mpi3mr_tgtdev_put(tgtdev);
+ }
+ mpi3mr_cleanup_ioc(mrioc, 0);
+
+ spin_lock(&mrioc_list_lock);
+ list_del(&mrioc->list);
+ spin_unlock(&mrioc_list_lock);
+
+ scsi_host_put(shost);
+}
+
+/**
+ * mpi3mr_shutdown - PCI shutdown callback
+ * @pdev: PCI device instance
+ *
+ * Free up all memory and resources associated with the
+ * controller
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_shutdown(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct mpi3mr_ioc *mrioc;
+ struct workqueue_struct *wq;
+ unsigned long flags;
+
+ if (!shost)
+ return;
+
+ mrioc = shost_priv(shost);
+ while (mrioc->reset_in_progress || mrioc->is_driver_loading)
+ ssleep(1);
+
+ mrioc->stop_drv_processing = 1;
+ mpi3mr_cleanup_fwevt_list(mrioc);
+ spin_lock_irqsave(&mrioc->fwevt_lock, flags);
+ wq = mrioc->fwevt_worker_thread;
+ mrioc->fwevt_worker_thread = NULL;
+ spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
+ if (wq)
+ destroy_workqueue(wq);
+ mpi3mr_cleanup_ioc(mrioc, 0);
+}
+
+#ifdef CONFIG_PM
+/**
+ * mpi3mr_suspend - PCI power management suspend callback
+ * @pdev: PCI device instance
+ * @state: New power state
+ *
+ * Change the power state to the given value and cleanup the IOC
+ * by issuing MUR and shutdown notification
+ *
+ * Return: 0 always.
+ */
+static int mpi3mr_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct mpi3mr_ioc *mrioc;
+ pci_power_t device_state;
+
+ if (!shost)
+ return 0;
+
+ mrioc = shost_priv(shost);
+ while (mrioc->reset_in_progress || mrioc->is_driver_loading)
+ ssleep(1);
+ mrioc->stop_drv_processing = 1;
+ mpi3mr_cleanup_fwevt_list(mrioc);
+ scsi_block_requests(shost);
+ mpi3mr_stop_watchdog(mrioc);
+ mpi3mr_cleanup_ioc(mrioc, 1);
+
+ device_state = pci_choose_state(pdev, state);
+ ioc_info(mrioc, "pdev=0x%p, slot=%s, entering operating state [D%d]\n",
+ pdev, pci_name(pdev), device_state);
+ pci_save_state(pdev);
+ pci_set_power_state(pdev, device_state);
+ mpi3mr_cleanup_resources(mrioc);
+
+ return 0;
+}
+
+/**
+ * mpi3mr_resume - PCI power management resume callback
+ * @pdev: PCI device instance
+ *
+ * Restore the power state to D0 and reinitialize the controller
+ * and resume I/O operations to the target devices
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+static int mpi3mr_resume(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct mpi3mr_ioc *mrioc;
+ pci_power_t device_state = pdev->current_state;
+ int r;
+
+ if (!shost)
+ return 0;
+
+ mrioc = shost_priv(shost);
+
+ ioc_info(mrioc, "pdev=0x%p, slot=%s, previous operating state [D%d]\n",
+ pdev, pci_name(pdev), device_state);
+ pci_set_power_state(pdev, PCI_D0);
+ pci_enable_wake(pdev, PCI_D0, 0);
+ pci_restore_state(pdev);
+ mrioc->pdev = pdev;
+ mrioc->cpu_count = num_online_cpus();
+ r = mpi3mr_setup_resources(mrioc);
+ if (r) {
+ ioc_info(mrioc, "%s: Setup resources failed[%d]\n",
+ __func__, r);
+ return r;
+ }
+
+ mrioc->stop_drv_processing = 0;
+ mpi3mr_init_ioc(mrioc, 1);
+ scsi_unblock_requests(shost);
+ mpi3mr_start_watchdog(mrioc);
+
+ return 0;
+}
+#endif
+
+static const struct pci_device_id mpi3mr_pci_id_table[] = {
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_LSI_LOGIC, 0x00A5,
+ PCI_ANY_ID, PCI_ANY_ID)
+ },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table);
+
+static struct pci_driver mpi3mr_pci_driver = {
+ .name = MPI3MR_DRIVER_NAME,
+ .id_table = mpi3mr_pci_id_table,
+ .probe = mpi3mr_probe,
+ .remove = mpi3mr_remove,
+ .shutdown = mpi3mr_shutdown,
+#ifdef CONFIG_PM
+ .suspend = mpi3mr_suspend,
+ .resume = mpi3mr_resume,
+#endif
+};
+
+static int __init mpi3mr_init(void)
+{
+ int ret_val;
+
+ pr_info("Loading %s version %s\n", MPI3MR_DRIVER_NAME,
+ MPI3MR_DRIVER_VERSION);
+
+ ret_val = pci_register_driver(&mpi3mr_pci_driver);
+
+ return ret_val;
+}
+
+static void __exit mpi3mr_exit(void)
+{
+ if (warn_non_secure_ctlr)
+ pr_warn(
+ "Unloading %s version %s while managing a non secure controller\n",
+ MPI3MR_DRIVER_NAME, MPI3MR_DRIVER_VERSION);
+ else
+ pr_info("Unloading %s version %s\n", MPI3MR_DRIVER_NAME,
+ MPI3MR_DRIVER_VERSION);
+
+ pci_unregister_driver(&mpi3mr_pci_driver);
+}
+
+module_init(mpi3mr_init);
+module_exit(mpi3mr_exit);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 5779f313f6f8..c39955239d1c 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -141,7 +141,7 @@ _base_clear_outstanding_commands(struct MPT3SAS_ADAPTER *ioc);
* @mpi_request:mf request pointer.
* @sz: size of buffer.
*
- * @Returns - 1/0 Reset to be done or Not
+ * Return: 1/0 Reset to be done or Not
*/
u8
mpt3sas_base_check_cmd_timeout(struct MPT3SAS_ADAPTER *ioc,
@@ -440,7 +440,7 @@ static void _clone_sg_entries(struct MPT3SAS_ADAPTER *ioc,
return;
/* From smid we can get scsi_cmd, once we have sg_scmd,
- * we just need to get sg_virt and sg_next to get virual
+ * we just need to get sg_virt and sg_next to get virtual
* address associated with sgel->Address.
*/
@@ -600,7 +600,7 @@ static int mpt3sas_remove_dead_ioc_func(void *arg)
* _base_sync_drv_fw_timestamp - Sync Drive-Fw TimeStamp.
* @ioc: Per Adapter Object
*
- * Return nothing.
+ * Return: nothing.
*/
static void _base_sync_drv_fw_timestamp(struct MPT3SAS_ADAPTER *ioc)
{
@@ -704,7 +704,7 @@ _base_fault_reset_work(struct work_struct *work)
/*
* Call _scsih_flush_pending_cmds callback so that we flush all
- * pending commands back to OS. This call is required to aovid
+ * pending commands back to OS. This call is required to avoid
* deadlock at block layer. Dead IOC will fail to do diag reset,
* and this call is safe since dead ioc will never return any
* command back from HW.
@@ -873,7 +873,7 @@ mpt3sas_base_fault_info(struct MPT3SAS_ADAPTER *ioc , u16 fault_code)
* @ioc: per adapter object
* @fault_code: fault code
*
- * Return nothing.
+ * Return: nothing.
*/
void
mpt3sas_base_coredump_info(struct MPT3SAS_ADAPTER *ioc, u16 fault_code)
@@ -887,7 +887,7 @@ mpt3sas_base_coredump_info(struct MPT3SAS_ADAPTER *ioc, u16 fault_code)
* @ioc: per adapter object
* @caller: caller function name
*
- * Returns 0 for success, non-zero for failure.
+ * Return: 0 for success, non-zero for failure.
*/
int
mpt3sas_base_wait_for_coredump_completion(struct MPT3SAS_ADAPTER *ioc,
@@ -1359,11 +1359,11 @@ _base_sas_log_info(struct MPT3SAS_ADAPTER *ioc , u32 log_info)
}
/**
- * _base_display_reply_info -
+ * _base_display_reply_info - handle reply descriptors depending on IOC Status
* @ioc: per adapter object
* @smid: system request message index
* @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
+ * @reply: reply message frame (lower 32bit addr)
*/
static void
_base_display_reply_info(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
@@ -1804,7 +1804,7 @@ _base_interrupt(int irq, void *bus_id)
* @irqpoll: irq_poll object
* @budget: irq poll weight
*
- * returns number of reply descriptors processed
+ * Return: number of reply descriptors processed
*/
static int
_base_irqpoll(struct irq_poll *irqpoll, int budget)
@@ -1826,7 +1826,7 @@ _base_irqpoll(struct irq_poll *irqpoll, int budget)
enable_irq(reply_q->os_irq);
/*
* Go for one more round of processing the
- * reply descriptor post queue incase if HBA
+ * reply descriptor post queue in case the HBA
* Firmware has posted some reply descriptors
* while reenabling the IRQ.
*/
@@ -1840,7 +1840,7 @@ _base_irqpoll(struct irq_poll *irqpoll, int budget)
* _base_init_irqpolls - initliaze IRQ polls
* @ioc: per adapter object
*
- * returns nothing
+ * Return: nothing
*/
static void
_base_init_irqpolls(struct MPT3SAS_ADAPTER *ioc)
@@ -1878,7 +1878,7 @@ _base_is_controller_msix_enabled(struct MPT3SAS_ADAPTER *ioc)
* @ioc: per adapter object
* @poll: poll over reply descriptor pools incase interrupt for
* timed-out SCSI command got delayed
- * Context: non ISR conext
+ * Context: non-ISR context
*
* Called when a Task Management request has completed.
*/
@@ -2104,7 +2104,16 @@ _base_build_sg(struct MPT3SAS_ADAPTER *ioc, void *psge,
/**
* _base_build_nvme_prp - This function is called for NVMe end devices to build
- * a native SGL (NVMe PRP). The native SGL is built starting in the first PRP
+ * a native SGL (NVMe PRP).
+ * @ioc: per adapter object
+ * @smid: system request message index for getting asscociated SGL
+ * @nvme_encap_request: the NVMe request msg frame pointer
+ * @data_out_dma: physical address for WRITES
+ * @data_out_sz: data xfer size for WRITES
+ * @data_in_dma: physical address for READS
+ * @data_in_sz: data xfer size for READS
+ *
+ * The native SGL is built starting in the first PRP
* entry of the NVMe message (PRP1). If the data buffer is small enough to be
* described entirely using PRP1, then PRP2 is not used. If needed, PRP2 is
* used to describe a larger data buffer. If the data buffer is too large to
@@ -2133,7 +2142,7 @@ _base_build_sg(struct MPT3SAS_ADAPTER *ioc, void *psge,
* Each 64-bit PRP entry comprises an address and an offset field. The address
* always points at the beginning of a 4KB physical memory page, and the offset
* describes where within that 4KB page the memory segment begins. Only the
- * first element in a PRP list may contain a non-zero offest, implying that all
+ * first element in a PRP list may contain a non-zero offset, implying that all
* memory segments following the first begin at the start of a 4KB page.
*
* Each PRP element normally describes 4KB of physical memory, with exceptions
@@ -2147,14 +2156,6 @@ _base_build_sg(struct MPT3SAS_ADAPTER *ioc, void *psge,
* Since PRP entries lack any indication of size, the overall data buffer length
* is used to determine where the end of the data memory buffer is located, and
* how many PRP entries are required to describe it.
- *
- * @ioc: per adapter object
- * @smid: system request message index for getting asscociated SGL
- * @nvme_encap_request: the NVMe request msg frame pointer
- * @data_out_dma: physical address for WRITES
- * @data_out_sz: data xfer size for WRITES
- * @data_in_dma: physical address for READS
- * @data_in_sz: data xfer size for READS
*/
static void
_base_build_nvme_prp(struct MPT3SAS_ADAPTER *ioc, u16 smid,
@@ -2311,8 +2312,8 @@ _base_build_nvme_prp(struct MPT3SAS_ADAPTER *ioc, u16 smid,
}
/**
- * base_make_prp_nvme -
- * Prepare PRPs(Physical Region Page)- SGLs specific to NVMe drives only
+ * base_make_prp_nvme - Prepare PRPs (Physical Region Page) -
+ * SGLs specific to NVMe drives only
*
* @ioc: per adapter object
* @scmd: SCSI command from the mid-layer
@@ -3155,7 +3156,7 @@ fall_back:
* - loaded driver with default max_msix_vectors module parameter and
* - system booted in non kdump mode
*
- * returns nothing.
+ * Return: nothing.
*/
static void
_base_check_and_enable_high_iops_queues(struct MPT3SAS_ADAPTER *ioc,
@@ -3364,14 +3365,14 @@ static int
_base_diag_reset(struct MPT3SAS_ADAPTER *ioc);
/**
- * _base_check_for_fault_and_issue_reset - check if IOC is in fault state
+ * mpt3sas_base_check_for_fault_and_issue_reset - check if IOC is in fault state
* and if it is in fault state then issue diag reset.
* @ioc: per adapter object
*
- * Returns: 0 for success, non-zero for failure.
+ * Return: 0 for success, non-zero for failure.
*/
-static int
-_base_check_for_fault_and_issue_reset(struct MPT3SAS_ADAPTER *ioc)
+int
+mpt3sas_base_check_for_fault_and_issue_reset(struct MPT3SAS_ADAPTER *ioc)
{
u32 ioc_state;
int rc = -EFAULT;
@@ -3385,12 +3386,14 @@ _base_check_for_fault_and_issue_reset(struct MPT3SAS_ADAPTER *ioc)
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
mpt3sas_print_fault_code(ioc, ioc_state &
MPI2_DOORBELL_DATA_MASK);
+ mpt3sas_base_mask_interrupts(ioc);
rc = _base_diag_reset(ioc);
} else if ((ioc_state & MPI2_IOC_STATE_MASK) ==
MPI2_IOC_STATE_COREDUMP) {
mpt3sas_print_coredump_info(ioc, ioc_state &
MPI2_DOORBELL_DATA_MASK);
mpt3sas_base_wait_for_coredump_completion(ioc, __func__);
+ mpt3sas_base_mask_interrupts(ioc);
rc = _base_diag_reset(ioc);
}
@@ -3472,7 +3475,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
r = _base_get_ioc_facts(ioc);
if (r) {
- rc = _base_check_for_fault_and_issue_reset(ioc);
+ rc = mpt3sas_base_check_for_fault_and_issue_reset(ioc);
if (rc || (_base_get_ioc_facts(ioc)))
goto out_fail;
}
@@ -3633,7 +3636,7 @@ mpt3sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, u32 phys_addr)
* @ioc: per adapter object
* @scmd: scsi_cmnd object
*
- * returns msix index of general reply queues,
+ * Return: msix index of general reply queues,
* i.e. reply queue on which IO request's reply
* should be posted by the HBA firmware.
*/
@@ -3663,7 +3666,7 @@ _base_get_msix_index(struct MPT3SAS_ADAPTER *ioc,
* @ioc: per adapter object
* @scmd: scsi_cmnd object
*
- * Returns: msix index of high iops reply queues.
+ * Return: 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.
*/
@@ -3910,7 +3913,7 @@ _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock)
* @ioc: per adapter object
* @smid: system request message index
*
- * returns msix index.
+ * Return: msix index.
*/
static u8
_base_set_and_get_msix_index(struct MPT3SAS_ADAPTER *ioc, u16 smid)
@@ -4005,7 +4008,7 @@ _base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
* _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.
+ * @msix_task: msix_task will be same as msix of IO in case of task abort else 0
*/
static void
_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
@@ -4109,7 +4112,7 @@ _base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
* @smid: system request message index
* @handle: device handle, unused in this function, for function type match
*
- * Return nothing.
+ * Return: nothing.
*/
static void
_base_put_smid_scsi_io_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
@@ -4131,7 +4134,7 @@ _base_put_smid_scsi_io_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
* @ioc: per adapter object
* @smid: system request message index
* @handle: device handle, unused in this function, for function type match
- * Return nothing
+ * Return: nothing
*/
static void
_base_put_smid_fast_path_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
@@ -4152,9 +4155,9 @@ _base_put_smid_fast_path_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
* 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
+ * @msix_task: msix_task will be same as msix of IO in case of task abort else 0
*
- * Return nothing.
+ * Return: nothing.
*/
static void
_base_put_smid_hi_priority_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
@@ -4176,7 +4179,7 @@ _base_put_smid_hi_priority_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
* @ioc: per adapter object
* @smid: system request message index
*
- * Return nothing.
+ * Return: nothing.
*/
static void
_base_put_smid_default_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid)
@@ -4434,6 +4437,7 @@ _base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc)
ioc->pdev->subsystem_device);
break;
}
+ break;
default:
break;
}
@@ -4453,7 +4457,7 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc)
Mpi26ComponentImageHeader_t *cmp_img_hdr;
Mpi25FWUploadRequest_t *mpi_request;
Mpi2FWUploadReply_t mpi_reply;
- int r = 0;
+ int r = 0, issue_diag_reset = 0;
u32 package_version = 0;
void *fwpkg_data = NULL;
dma_addr_t fwpkg_data_dma;
@@ -4503,7 +4507,7 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc)
ioc_err(ioc, "%s: timeout\n", __func__);
_debug_dump_mf(mpi_request,
sizeof(Mpi25FWUploadRequest_t)/4);
- r = -ETIME;
+ issue_diag_reset = 1;
} else {
memset(&mpi_reply, 0, sizeof(Mpi2FWUploadReply_t));
if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID) {
@@ -4543,11 +4547,18 @@ out:
if (fwpkg_data)
dma_free_coherent(&ioc->pdev->dev, data_length, fwpkg_data,
fwpkg_data_dma);
+ if (issue_diag_reset) {
+ if (ioc->drv_internal_flags & MPT_DRV_INTERNAL_FIRST_PE_ISSUED)
+ return -EFAULT;
+ if (mpt3sas_base_check_for_fault_and_issue_reset(ioc))
+ return -EFAULT;
+ r = -EAGAIN;
+ }
return r;
}
/**
- * _base_display_ioc_capabilities - Disply IOC's capabilities.
+ * _base_display_ioc_capabilities - Display IOC's capabilities.
* @ioc: per adapter object
*/
static void
@@ -4750,15 +4761,19 @@ out:
* according to performance mode.
* @ioc : per adapter object
*
- * Return nothing.
+ * Return: zero on success; otherwise return EAGAIN error code asking the
+ * caller to retry.
*/
-static void
+static int
_base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc)
{
Mpi2IOCPage1_t ioc_pg1;
Mpi2ConfigReply_t mpi_reply;
+ int rc;
- mpt3sas_config_get_ioc_pg1(ioc, &mpi_reply, &ioc->ioc_pg1_copy);
+ rc = mpt3sas_config_get_ioc_pg1(ioc, &mpi_reply, &ioc->ioc_pg1_copy);
+ if (rc)
+ return rc;
memcpy(&ioc_pg1, &ioc->ioc_pg1_copy, sizeof(Mpi2IOCPage1_t));
switch (perf_mode) {
@@ -4780,9 +4795,11 @@ _base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc)
*/
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);
+ rc = mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
+ if (rc)
+ return rc;
ioc_info(ioc, "performance mode: balanced\n");
- return;
+ return 0;
}
fallthrough;
case MPT_PERF_MODE_LATENCY:
@@ -4793,7 +4810,9 @@ _base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc)
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);
+ rc = mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
+ if (rc)
+ return rc;
ioc_info(ioc, "performance mode: latency\n");
break;
case MPT_PERF_MODE_IOPS:
@@ -4805,9 +4824,12 @@ _base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc)
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);
+ rc = mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
+ if (rc)
+ return rc;
break;
}
+ return 0;
}
/**
@@ -4815,9 +4837,9 @@ _base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc)
* persistent pages
* @ioc : per adapter object
*
- * Return nothing.
+ * Return: nothing.
*/
-static void
+static int
_base_get_event_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
{
Mpi26DriverTriggerPage2_t trigger_pg2;
@@ -4831,7 +4853,7 @@ _base_get_event_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
r = mpt3sas_config_get_driver_trigger_pg2(ioc, &mpi_reply,
&trigger_pg2);
if (r)
- return;
+ return r;
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
@@ -4840,7 +4862,7 @@ _base_get_event_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
ioc_err(ioc,
"%s: Failed to get trigger pg2, ioc_status(0x%04x)\n",
__func__, ioc_status));
- return;
+ return 0;
}
if (le16_to_cpu(trigger_pg2.NumMPIEventTrigger)) {
@@ -4859,6 +4881,7 @@ _base_get_event_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
mpi_event_tg++;
}
}
+ return 0;
}
/**
@@ -4866,9 +4889,9 @@ _base_get_event_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
* persistent pages
* @ioc : per adapter object
*
- * Return nothing.
+ * Return: 0 on success; otherwise return failure status.
*/
-static void
+static int
_base_get_scsi_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
{
Mpi26DriverTriggerPage3_t trigger_pg3;
@@ -4882,7 +4905,7 @@ _base_get_scsi_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
r = mpt3sas_config_get_driver_trigger_pg3(ioc, &mpi_reply,
&trigger_pg3);
if (r)
- return;
+ return r;
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
@@ -4891,7 +4914,7 @@ _base_get_scsi_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
ioc_err(ioc,
"%s: Failed to get trigger pg3, ioc_status(0x%04x)\n",
__func__, ioc_status));
- return;
+ return 0;
}
if (le16_to_cpu(trigger_pg3.NumSCSISenseTrigger)) {
@@ -4910,6 +4933,7 @@ _base_get_scsi_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
mpi_scsi_tg++;
}
}
+ return 0;
}
/**
@@ -4917,9 +4941,9 @@ _base_get_scsi_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
* persistent pages
* @ioc : per adapter object
*
- * Return nothing.
+ * Return: 0 on success; otherwise return failure status.
*/
-static void
+static int
_base_get_mpi_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
{
Mpi26DriverTriggerPage4_t trigger_pg4;
@@ -4933,7 +4957,7 @@ _base_get_mpi_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
r = mpt3sas_config_get_driver_trigger_pg4(ioc, &mpi_reply,
&trigger_pg4);
if (r)
- return;
+ return r;
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
@@ -4942,7 +4966,7 @@ _base_get_mpi_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
ioc_err(ioc,
"%s: Failed to get trigger pg4, ioc_status(0x%04x)\n",
__func__, ioc_status));
- return;
+ return 0;
}
if (le16_to_cpu(trigger_pg4.NumIOCStatusLogInfoTrigger)) {
@@ -4963,6 +4987,7 @@ _base_get_mpi_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
mpi_status_tg++;
}
}
+ return 0;
}
/**
@@ -4970,9 +4995,9 @@ _base_get_mpi_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
* persistent pages
* @ioc : per adapter object
*
- * Return nothing.
+ * Return: nothing.
*/
-static void
+static int
_base_get_master_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
{
Mpi26DriverTriggerPage1_t trigger_pg1;
@@ -4983,7 +5008,7 @@ _base_get_master_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
r = mpt3sas_config_get_driver_trigger_pg1(ioc, &mpi_reply,
&trigger_pg1);
if (r)
- return;
+ return r;
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
@@ -4992,25 +5017,30 @@ _base_get_master_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
ioc_err(ioc,
"%s: Failed to get trigger pg1, ioc_status(0x%04x)\n",
__func__, ioc_status));
- return;
+ return 0;
}
if (le16_to_cpu(trigger_pg1.NumMasterTrigger))
ioc->diag_trigger_master.MasterData |=
le32_to_cpu(
trigger_pg1.MasterTriggers[0].MasterTriggerFlags);
+ return 0;
}
/**
* _base_check_for_trigger_pages_support - checks whether HBA FW supports
* driver trigger pages or not
* @ioc : per adapter object
+ * @trigger_flags : address where trigger page0's TriggerFlags value is copied
+ *
+ * Return: trigger flags mask if HBA FW supports driver trigger pages;
+ * otherwise returns %-EFAULT if driver trigger pages are not supported by FW or
+ * return EAGAIN if diag reset occurred due to FW fault and asking the
+ * caller to retry the command.
*
- * Returns trigger flags mask if HBA FW supports driver trigger pages,
- * otherwise returns EFAULT.
*/
static int
-_base_check_for_trigger_pages_support(struct MPT3SAS_ADAPTER *ioc)
+_base_check_for_trigger_pages_support(struct MPT3SAS_ADAPTER *ioc, u32 *trigger_flags)
{
Mpi26DriverTriggerPage0_t trigger_pg0;
int r = 0;
@@ -5020,14 +5050,15 @@ _base_check_for_trigger_pages_support(struct MPT3SAS_ADAPTER *ioc)
r = mpt3sas_config_get_driver_trigger_pg0(ioc, &mpi_reply,
&trigger_pg0);
if (r)
- return -EFAULT;
+ return r;
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
return -EFAULT;
- return le16_to_cpu(trigger_pg0.TriggerFlags);
+ *trigger_flags = le16_to_cpu(trigger_pg0.TriggerFlags);
+ return 0;
}
/**
@@ -5035,12 +5066,14 @@ _base_check_for_trigger_pages_support(struct MPT3SAS_ADAPTER *ioc)
* persistent pages.
* @ioc : per adapter object
*
- * Return nothing.
+ * Return: zero on success; otherwise return EAGAIN error codes
+ * asking the caller to retry.
*/
-static void
+static int
_base_get_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
{
int trigger_flags;
+ int r;
/*
* Default setting of master trigger.
@@ -5048,9 +5081,16 @@ _base_get_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
ioc->diag_trigger_master.MasterData =
(MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET);
- trigger_flags = _base_check_for_trigger_pages_support(ioc);
- if (trigger_flags < 0)
- return;
+ r = _base_check_for_trigger_pages_support(ioc, &trigger_flags);
+ if (r) {
+ if (r == -EAGAIN)
+ return r;
+ /*
+ * Don't go for error handling when FW doesn't support
+ * driver trigger pages.
+ */
+ return 0;
+ }
ioc->supports_trigger_pages = 1;
@@ -5059,40 +5099,53 @@ _base_get_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
* if master trigger bit enabled in TriggerFlags.
*/
if ((u16)trigger_flags &
- MPI26_DRIVER_TRIGGER0_FLAG_MASTER_TRIGGER_VALID)
- _base_get_master_diag_triggers(ioc);
+ MPI26_DRIVER_TRIGGER0_FLAG_MASTER_TRIGGER_VALID) {
+ r = _base_get_master_diag_triggers(ioc);
+ if (r)
+ return r;
+ }
/*
* Retrieve event diag trigger values from driver trigger pg2
* if event trigger bit enabled in TriggerFlags.
*/
if ((u16)trigger_flags &
- MPI26_DRIVER_TRIGGER0_FLAG_MPI_EVENT_TRIGGER_VALID)
- _base_get_event_diag_triggers(ioc);
+ MPI26_DRIVER_TRIGGER0_FLAG_MPI_EVENT_TRIGGER_VALID) {
+ r = _base_get_event_diag_triggers(ioc);
+ if (r)
+ return r;
+ }
/*
* Retrieve scsi diag trigger values from driver trigger pg3
* if scsi trigger bit enabled in TriggerFlags.
*/
if ((u16)trigger_flags &
- MPI26_DRIVER_TRIGGER0_FLAG_SCSI_SENSE_TRIGGER_VALID)
- _base_get_scsi_diag_triggers(ioc);
+ MPI26_DRIVER_TRIGGER0_FLAG_SCSI_SENSE_TRIGGER_VALID) {
+ r = _base_get_scsi_diag_triggers(ioc);
+ if (r)
+ return r;
+ }
/*
* Retrieve mpi error diag trigger values from driver trigger pg4
* if loginfo trigger bit enabled in TriggerFlags.
*/
if ((u16)trigger_flags &
- MPI26_DRIVER_TRIGGER0_FLAG_LOGINFO_TRIGGER_VALID)
- _base_get_mpi_diag_triggers(ioc);
+ MPI26_DRIVER_TRIGGER0_FLAG_LOGINFO_TRIGGER_VALID) {
+ r = _base_get_mpi_diag_triggers(ioc);
+ if (r)
+ return r;
+ }
+ return 0;
}
/**
* _base_update_diag_trigger_pages - Update the driver trigger pages after
- * online FW update, incase updated FW supports driver
+ * online FW update, in case updated FW supports driver
* trigger pages.
* @ioc : per adapter object
*
- * Return nothing.
+ * Return: nothing.
*/
static void
_base_update_diag_trigger_pages(struct MPT3SAS_ADAPTER *ioc)
@@ -5119,23 +5172,33 @@ _base_update_diag_trigger_pages(struct MPT3SAS_ADAPTER *ioc)
* _base_static_config_pages - static start of day config pages
* @ioc: per adapter object
*/
-static void
+static int
_base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
{
Mpi2ConfigReply_t mpi_reply;
u32 iounit_pg1_flags;
int tg_flags = 0;
+ int rc;
ioc->nvme_abort_timeout = 30;
- mpt3sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0);
- if (ioc->ir_firmware)
- mpt3sas_config_get_manufacturing_pg10(ioc, &mpi_reply,
- &ioc->manu_pg10);
+ rc = mpt3sas_config_get_manufacturing_pg0(ioc, &mpi_reply,
+ &ioc->manu_pg0);
+ if (rc)
+ return rc;
+ if (ioc->ir_firmware) {
+ rc = mpt3sas_config_get_manufacturing_pg10(ioc, &mpi_reply,
+ &ioc->manu_pg10);
+ if (rc)
+ return rc;
+ }
/*
* Ensure correct T10 PI operation if vendor left EEDPTagMode
* flag unset in NVDATA.
*/
- mpt3sas_config_get_manufacturing_pg11(ioc, &mpi_reply, &ioc->manu_pg11);
+ rc = mpt3sas_config_get_manufacturing_pg11(ioc, &mpi_reply,
+ &ioc->manu_pg11);
+ if (rc)
+ return rc;
if (!ioc->is_gen35_ioc && ioc->manu_pg11.EEDPTagMode == 0) {
pr_err("%s: overriding NVDATA EEDPTagMode setting\n",
ioc->name);
@@ -5174,12 +5237,24 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
ioc_warn(ioc,
"TimeSync Interval in Manuf page-11 is not enabled. Periodic Time-Sync will be disabled\n");
}
- mpt3sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
- mpt3sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3);
- mpt3sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8);
- mpt3sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0);
- mpt3sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
- mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8);
+ rc = mpt3sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
+ if (rc)
+ return rc;
+ rc = mpt3sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3);
+ if (rc)
+ return rc;
+ rc = mpt3sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8);
+ if (rc)
+ return rc;
+ rc = mpt3sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0);
+ if (rc)
+ return rc;
+ rc = mpt3sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
+ if (rc)
+ return rc;
+ rc = mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8);
+ if (rc)
+ return rc;
_base_display_ioc_capabilities(ioc);
/*
@@ -5195,16 +5270,23 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
iounit_pg1_flags |=
MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags);
- mpt3sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
+ rc = mpt3sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
+ if (rc)
+ return rc;
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);
+ if (ioc->is_aero_ioc) {
+ rc = _base_update_ioc_page1_inlinewith_perf_mode(ioc);
+ if (rc)
+ return rc;
+ }
if (ioc->is_gen35_ioc) {
- if (ioc->is_driver_loading)
- _base_get_diag_triggers(ioc);
- else {
+ if (ioc->is_driver_loading) {
+ rc = _base_get_diag_triggers(ioc);
+ if (rc)
+ return rc;
+ } else {
/*
* In case of online HBA FW update operation,
* check whether updated FW supports the driver trigger
@@ -5216,7 +5298,7 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
* and new FW doesn't support them then disable
* support_trigger_pages flag.
*/
- tg_flags = _base_check_for_trigger_pages_support(ioc);
+ _base_check_for_trigger_pages_support(ioc, &tg_flags);
if (!ioc->supports_trigger_pages && tg_flags != -EFAULT)
_base_update_diag_trigger_pages(ioc);
else if (ioc->supports_trigger_pages &&
@@ -5224,6 +5306,7 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
ioc->supports_trigger_pages = 0;
}
}
+ return 0;
}
/**
@@ -6233,7 +6316,7 @@ _base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state, int timeout)
* _base_dump_reg_set - This function will print hexdump of register set.
* @ioc: per adapter object
*
- * Returns nothing.
+ * Return: nothing.
*/
static inline void
_base_dump_reg_set(struct MPT3SAS_ADAPTER *ioc)
@@ -6467,7 +6550,7 @@ _base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout)
*
* Return: Waits up to timeout seconds for the IOC to
* become operational. Returns 0 if IOC is present
- * and operational; otherwise returns -EFAULT.
+ * and operational; otherwise returns %-EFAULT.
*/
int
@@ -6480,6 +6563,17 @@ mpt3sas_wait_for_ioc(struct MPT3SAS_ADAPTER *ioc, int timeout)
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
if (ioc_state == MPI2_IOC_STATE_OPERATIONAL)
break;
+
+ /*
+ * Watchdog thread will be started after IOC Initialization, so
+ * no need to wait here for IOC state to become operational
+ * when IOC Initialization is on. Instead the driver will
+ * return ETIME status, so that calling function can issue
+ * diag reset operation and retry the command.
+ */
+ if (ioc->is_driver_loading)
+ return -ETIME;
+
ssleep(1);
ioc_info(ioc, "%s: waiting for operational state(count=%d)\n",
__func__, ++wait_state_count);
@@ -7112,7 +7206,8 @@ mpt3sas_port_enable_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
ioc->port_enable_failed = 1;
- if (ioc->is_driver_loading) {
+ if (ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE_ASYNC) {
+ ioc->port_enable_cmds.status &= ~MPT3_CMD_COMPLETE_ASYNC;
if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
mpt3sas_port_enable_complete(ioc);
return 1;
@@ -7213,8 +7308,9 @@ mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc)
ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
return -EAGAIN;
}
-
+ ioc->drv_internal_flags |= MPT_DRV_INTERNAL_FIRST_PE_ISSUED;
ioc->port_enable_cmds.status = MPT3_CMD_PENDING;
+ ioc->port_enable_cmds.status |= MPT3_CMD_COMPLETE_ASYNC;
mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
ioc->port_enable_cmds.smid = smid;
memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
@@ -7311,7 +7407,7 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc)
Mpi2EventNotificationRequest_t *mpi_request;
u16 smid;
int r = 0;
- int i;
+ int i, issue_diag_reset = 0;
dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
@@ -7345,10 +7441,19 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc)
if (ioc->base_cmds.status & MPT3_CMD_RESET)
r = -EFAULT;
else
- r = -ETIME;
+ issue_diag_reset = 1;
+
} else
dinitprintk(ioc, ioc_info(ioc, "%s: complete\n", __func__));
ioc->base_cmds.status = MPT3_CMD_NOT_USED;
+
+ if (issue_diag_reset) {
+ if (ioc->drv_internal_flags & MPT_DRV_INTERNAL_FIRST_PE_ISSUED)
+ return -EFAULT;
+ if (mpt3sas_base_check_for_fault_and_issue_reset(ioc))
+ return -EFAULT;
+ r = -EAGAIN;
+ }
return r;
}
@@ -7712,7 +7817,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc)
if (!ioc->is_driver_loading)
return r;
- rc = _base_check_for_fault_and_issue_reset(ioc);
+ rc = mpt3sas_base_check_for_fault_and_issue_reset(ioc);
if (rc || (_base_send_ioc_init(ioc)))
return r;
}
@@ -7746,12 +7851,15 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc)
return r;
}
- _base_static_config_pages(ioc);
+ rc = _base_static_config_pages(ioc);
+ if (r)
+ return r;
+
r = _base_event_notification(ioc);
if (r)
return r;
- if (ioc->is_driver_loading) {
+ if (!ioc->shost_recovery) {
if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier
== 0x80) {
@@ -7851,7 +7959,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
pci_set_drvdata(ioc->pdev, ioc->shost);
r = _base_get_ioc_facts(ioc);
if (r) {
- rc = _base_check_for_fault_and_issue_reset(ioc);
+ rc = mpt3sas_base_check_for_fault_and_issue_reset(ioc);
if (rc || (_base_get_ioc_facts(ioc)))
goto out_free_resources;
}
@@ -7868,7 +7976,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
/*
* In SAS3.0,
* SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and
- * Target Status - all require the IEEE formated scatter gather
+ * Target Status - all require the IEEE formatted scatter gather
* elements.
*/
ioc->build_sg_scmd = &_base_build_sg_scmd_ieee;
@@ -7923,7 +8031,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {
r = _base_get_port_facts(ioc, i);
if (r) {
- rc = _base_check_for_fault_and_issue_reset(ioc);
+ rc = mpt3sas_base_check_for_fault_and_issue_reset(ioc);
if (rc || (_base_get_port_facts(ioc, i)))
goto out_free_resources;
}
@@ -8049,8 +8157,11 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
}
}
r = _base_make_ioc_operational(ioc);
- if (r)
- goto out_free_resources;
+ if (r == -EAGAIN) {
+ r = _base_make_ioc_operational(ioc);
+ if (r)
+ goto out_free_resources;
+ }
/*
* Copy current copy of IOCFacts in prev_fw_facts
@@ -8168,8 +8279,6 @@ _base_clear_outstanding_mpt_commands(struct MPT3SAS_ADAPTER *ioc)
ioc->start_scan_failed =
MPI2_IOCSTATUS_INTERNAL_ERROR;
ioc->start_scan = 0;
- ioc->port_enable_cmds.status =
- MPT3_CMD_NOT_USED;
} else {
complete(&ioc->port_enable_cmds.done);
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index 98558d9c8c2d..d4834c8ee9c0 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -500,6 +500,7 @@ struct MPT3SAS_DEVICE {
#define MPT3_CMD_PENDING 0x0002 /* pending */
#define MPT3_CMD_REPLY_VALID 0x0004 /* reply is valid */
#define MPT3_CMD_RESET 0x0008 /* host reset dropped the command */
+#define MPT3_CMD_COMPLETE_ASYNC 0x0010 /* tells whether cmd completes in same thread or not */
/**
* struct _internal_cmd - internal commands struct
@@ -1175,6 +1176,7 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
* @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands
* @thresh_hold: Max number of reply descriptors processed
* before updating Host Index
+ * @drv_internal_flags: Bit map internal to driver
* @drv_support_bitmap: driver's supported feature bit map
* @use_32bit_dma: Flag to use 32 bit consistent dma mask
* @scsi_io_cb_idx: shost generated commands
@@ -1370,6 +1372,7 @@ struct MPT3SAS_ADAPTER {
bool msix_load_balance;
u16 thresh_hold;
u8 high_iops_queues;
+ u32 drv_internal_flags;
u32 drv_support_bitmap;
u32 dma_mask;
bool enable_sdev_max_qd;
@@ -1615,6 +1618,8 @@ struct mpt3sas_debugfs_buffer {
#define MPT_DRV_SUPPORT_BITMAP_MEMMOVE 0x00000001
#define MPT_DRV_SUPPORT_BITMAP_ADDNLQUERY 0x00000002
+#define MPT_DRV_INTERNAL_FIRST_PE_ISSUED 0x00000001
+
typedef u8 (*MPT_CALLBACK)(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u32 reply);
@@ -1709,6 +1714,9 @@ void mpt3sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc);
void mpt3sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc,
u16 device_missing_delay, u8 io_missing_delay);
+int mpt3sas_base_check_for_fault_and_issue_reset(
+ struct MPT3SAS_ADAPTER *ioc);
+
int mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc);
void
diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c
index 55cd32908924..83a5c2172ad4 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_config.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_config.c
@@ -359,8 +359,11 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
}
r = mpt3sas_wait_for_ioc(ioc, MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT);
- if (r)
+ if (r) {
+ if (r == -ETIME)
+ issue_host_reset = 1;
goto free_mem;
+ }
smid = mpt3sas_base_get_smid(ioc, ioc->config_cb_idx);
if (!smid) {
@@ -395,7 +398,6 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
MPT3_CMD_RESET) || ioc->pci_error_recovery)
goto retry_config;
issue_host_reset = 1;
- r = -EFAULT;
goto free_mem;
}
@@ -486,8 +488,16 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
ioc->config_cmds.status = MPT3_CMD_NOT_USED;
mutex_unlock(&ioc->config_cmds.mutex);
- if (issue_host_reset)
- mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
+ if (issue_host_reset) {
+ if (ioc->drv_internal_flags & MPT_DRV_INTERNAL_FIRST_PE_ISSUED) {
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
+ r = -EFAULT;
+ } else {
+ if (mpt3sas_base_check_for_fault_and_issue_reset(ioc))
+ return -EFAULT;
+ r = -EAGAIN;
+ }
+ }
return r;
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index d00aca3c77ce..866d118f7931 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -78,6 +78,7 @@ static void _scsih_pcie_device_remove_from_sml(struct MPT3SAS_ADAPTER *ioc,
static void
_scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle);
static u8 _scsih_check_for_pending_tm(struct MPT3SAS_ADAPTER *ioc, u16 smid);
+static void _scsih_complete_devices_scanning(struct MPT3SAS_ADAPTER *ioc);
/* global parameters */
LIST_HEAD(mpt3sas_ioc_list);
@@ -3631,8 +3632,6 @@ _scsih_error_recovery_delete_devices(struct MPT3SAS_ADAPTER *ioc)
{
struct fw_event_work *fw_event;
- if (ioc->is_driver_loading)
- return;
fw_event = alloc_fw_event_work(0);
if (!fw_event)
return;
@@ -3693,10 +3692,53 @@ _scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc)
if ((list_empty(&ioc->fw_event_list) && !ioc->current_event) ||
!ioc->firmware_event_thread)
return;
+ /*
+ * Set current running event as ignore, so that
+ * current running event will exit quickly.
+ * As diag reset has occurred it is of no use
+ * to process remaining stale event data entries.
+ */
+ if (ioc->shost_recovery && ioc->current_event)
+ ioc->current_event->ignore = 1;
ioc->fw_events_cleanup = 1;
while ((fw_event = dequeue_next_fw_event(ioc)) ||
(fw_event = ioc->current_event)) {
+
+ /*
+ * Don't call cancel_work_sync() for current_event
+ * other than MPT3SAS_REMOVE_UNRESPONDING_DEVICES;
+ * otherwise we may observe deadlock if current
+ * hard reset issued as part of processing the current_event.
+ *
+ * Orginal logic of cleaning the current_event is added
+ * for handling the back to back host reset issued by the user.
+ * i.e. during back to back host reset, driver use to process
+ * the two instances of MPT3SAS_REMOVE_UNRESPONDING_DEVICES
+ * event back to back and this made the drives to unregister
+ * the devices from SML.
+ */
+
+ if (fw_event == ioc->current_event &&
+ ioc->current_event->event !=
+ MPT3SAS_REMOVE_UNRESPONDING_DEVICES) {
+ ioc->current_event = NULL;
+ continue;
+ }
+
+ /*
+ * Driver has to clear ioc->start_scan flag when
+ * it is cleaning up MPT3SAS_PORT_ENABLE_COMPLETE,
+ * otherwise scsi_scan_host() API waits for the
+ * 5 minute timer to expire. If we exit from
+ * scsi_scan_host() early then we can issue the
+ * new port enable request as part of current diag reset.
+ */
+ if (fw_event->event == MPT3SAS_PORT_ENABLE_COMPLETE) {
+ ioc->port_enable_cmds.status |= MPT3_CMD_RESET;
+ ioc->start_scan = 0;
+ }
+
/*
* Wait on the fw_event to complete. If this returns 1, then
* the event was never executed, and we need a put for the
@@ -5077,10 +5119,8 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
ascq = 0x00;
break;
}
- scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 0x10,
- ascq);
- scmd->result = DRIVER_SENSE << 24 | (DID_ABORT << 16) |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x10, ascq);
+ set_host_byte(scmd, DID_ABORT);
}
/**
@@ -5837,12 +5877,8 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
- scmd->result = (DRIVER_SENSE << 24) |
- SAM_STAT_CHECK_CONDITION;
- scmd->sense_buffer[0] = 0x70;
- scmd->sense_buffer[2] = ILLEGAL_REQUEST;
- scmd->sense_buffer[12] = 0x20;
- scmd->sense_buffer[13] = 0;
+ scsi_build_sense(scmd, 0, ILLEGAL_REQUEST,
+ 0x20, 0);
}
break;
@@ -6884,8 +6920,10 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle)
handle, parent_handle,
(u64)sas_expander->sas_address, sas_expander->num_phys);
- if (!sas_expander->num_phys)
+ if (!sas_expander->num_phys) {
+ rc = -1;
goto out_fail;
+ }
sas_expander->phy = kcalloc(sas_expander->num_phys,
sizeof(struct _sas_phy), GFP_KERNEL);
if (!sas_expander->phy) {
@@ -10118,6 +10156,17 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc)
* owner for the reference the list had on any object we prune.
*/
spin_lock_irqsave(&ioc->sas_device_lock, flags);
+
+ /*
+ * Clean up the sas_device_init_list list as
+ * driver goes for fresh scan as part of diag reset.
+ */
+ list_for_each_entry_safe(sas_device, sas_device_next,
+ &ioc->sas_device_init_list, list) {
+ list_del_init(&sas_device->list);
+ sas_device_put(sas_device);
+ }
+
list_for_each_entry_safe(sas_device, sas_device_next,
&ioc->sas_device_list, list) {
if (!sas_device->responding)
@@ -10139,6 +10188,16 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc)
ioc_info(ioc, "Removing unresponding devices: pcie end-devices\n");
INIT_LIST_HEAD(&head);
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
+ /*
+ * Clean up the pcie_device_init_list list as
+ * driver goes for fresh scan as part of diag reset.
+ */
+ list_for_each_entry_safe(pcie_device, pcie_device_next,
+ &ioc->pcie_device_init_list, list) {
+ list_del_init(&pcie_device->list);
+ pcie_device_put(pcie_device);
+ }
+
list_for_each_entry_safe(pcie_device, pcie_device_next,
&ioc->pcie_device_list, list) {
if (!pcie_device->responding)
@@ -10541,8 +10600,7 @@ void
mpt3sas_scsih_reset_done_handler(struct MPT3SAS_ADAPTER *ioc)
{
dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_DONE_RESET\n", __func__));
- if ((!ioc->is_driver_loading) && !(disable_discovery > 0 &&
- !ioc->sas_hba.num_phys)) {
+ if (!(disable_discovery > 0 && !ioc->sas_hba.num_phys)) {
if (ioc->multipath_on_hba) {
_scsih_sas_port_refresh(ioc);
_scsih_update_vphys_after_reset(ioc);
@@ -10597,6 +10655,18 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
_scsih_del_dirty_vphy(ioc);
_scsih_del_dirty_port_entries(ioc);
_scsih_scan_for_devices_after_reset(ioc);
+ /*
+ * If diag reset has occurred during the driver load
+ * then driver has to complete the driver load operation
+ * by executing the following items:
+ *- Register the devices from sas_device_init_list to SML
+ *- clear is_driver_loading flag,
+ *- start the watchdog thread.
+ * In happy driver load path, above things are taken care of when
+ * driver executes scsih_scan_finished().
+ */
+ if (ioc->is_driver_loading)
+ _scsih_complete_devices_scanning(ioc);
_scsih_set_nvme_max_shutdown_latency(ioc);
break;
case MPT3SAS_PORT_ENABLE_COMPLETE:
@@ -10742,11 +10812,23 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
_scsih_check_topo_delete_events(ioc,
(Mpi2EventDataSasTopologyChangeList_t *)
mpi_reply->EventData);
+ /*
+ * No need to add the topology change list
+ * event to fw event work queue when
+ * diag reset is going on. Since during diag
+ * reset driver scan the devices by reading
+ * sas device page0's not by processing the
+ * events.
+ */
+ if (ioc->shost_recovery)
+ return 1;
break;
case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
_scsih_check_pcie_topo_remove_events(ioc,
(Mpi26EventDataPCIeTopologyChangeList_t *)
mpi_reply->EventData);
+ if (ioc->shost_recovery)
+ return 1;
break;
case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
_scsih_check_ir_config_unhide_events(ioc,
@@ -11262,13 +11344,27 @@ _scsih_probe_boot_devices(struct MPT3SAS_ADAPTER *ioc)
if (channel == RAID_CHANNEL) {
raid_device = device;
+ /*
+ * If this boot vd is already registered with SML then
+ * no need to register it again as part of device scanning
+ * after diag reset during driver load operation.
+ */
+ if (raid_device->starget)
+ return;
rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
raid_device->id, 0);
if (rc)
_scsih_raid_device_remove(ioc, raid_device);
} else if (channel == PCIE_CHANNEL) {
- spin_lock_irqsave(&ioc->pcie_device_lock, flags);
pcie_device = device;
+ /*
+ * If this boot NVMe device is already registered with SML then
+ * no need to register it again as part of device scanning
+ * after diag reset during driver load operation.
+ */
+ if (pcie_device->starget)
+ return;
+ spin_lock_irqsave(&ioc->pcie_device_lock, flags);
tid = pcie_device->id;
list_move_tail(&pcie_device->list, &ioc->pcie_device_list);
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
@@ -11276,8 +11372,15 @@ _scsih_probe_boot_devices(struct MPT3SAS_ADAPTER *ioc)
if (rc)
_scsih_pcie_device_remove(ioc, pcie_device);
} else {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = device;
+ /*
+ * If this boot sas/sata device is already registered with SML
+ * then no need to register it again as part of device scanning
+ * after diag reset during driver load operation.
+ */
+ if (sas_device->starget)
+ return;
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
handle = sas_device->handle;
sas_address_parent = sas_device->sas_address_parent;
sas_address = sas_device->sas_address;
@@ -11576,6 +11679,25 @@ scsih_scan_start(struct Scsi_Host *shost)
}
/**
+ * _scsih_complete_devices_scanning - add the devices to sml and
+ * complete ioc initialization.
+ * @ioc: per adapter object
+ *
+ * Return nothing.
+ */
+static void _scsih_complete_devices_scanning(struct MPT3SAS_ADAPTER *ioc)
+{
+
+ if (ioc->wait_for_discovery_to_complete) {
+ ioc->wait_for_discovery_to_complete = 0;
+ _scsih_probe_devices(ioc);
+ }
+
+ mpt3sas_base_start_watchdog(ioc);
+ ioc->is_driver_loading = 0;
+}
+
+/**
* scsih_scan_finished - scsi lld callback for .scan_finished
* @shost: SCSI host pointer
* @time: elapsed time of the scan in jiffies
@@ -11588,6 +11710,8 @@ static int
scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
+ u32 ioc_state;
+ int issue_hard_reset = 0;
if (disable_discovery > 0) {
ioc->is_driver_loading = 0;
@@ -11602,9 +11726,30 @@ scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
return 1;
}
- if (ioc->start_scan)
+ if (ioc->start_scan) {
+ ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
+ mpt3sas_print_fault_code(ioc, ioc_state &
+ MPI2_DOORBELL_DATA_MASK);
+ issue_hard_reset = 1;
+ goto out;
+ } else if ((ioc_state & MPI2_IOC_STATE_MASK) ==
+ MPI2_IOC_STATE_COREDUMP) {
+ mpt3sas_base_coredump_info(ioc, ioc_state &
+ MPI2_DOORBELL_DATA_MASK);
+ mpt3sas_base_wait_for_coredump_completion(ioc, __func__);
+ issue_hard_reset = 1;
+ goto out;
+ }
return 0;
+ }
+ if (ioc->port_enable_cmds.status & MPT3_CMD_RESET) {
+ ioc_info(ioc,
+ "port enable: aborted due to diag reset\n");
+ ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED;
+ goto out;
+ }
if (ioc->start_scan_failed) {
ioc_info(ioc, "port enable: FAILED with (ioc_status=0x%08x)\n",
ioc->start_scan_failed);
@@ -11616,13 +11761,14 @@ scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
ioc_info(ioc, "port enable: SUCCESS\n");
ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED;
+ _scsih_complete_devices_scanning(ioc);
- if (ioc->wait_for_discovery_to_complete) {
- ioc->wait_for_discovery_to_complete = 0;
- _scsih_probe_devices(ioc);
+out:
+ if (issue_hard_reset) {
+ ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED;
+ if (mpt3sas_base_hard_reset_handler(ioc, SOFT_RESET))
+ ioc->is_driver_loading = 0;
}
- mpt3sas_base_start_watchdog(ioc);
- ioc->is_driver_loading = 0;
return 1;
}
@@ -11932,6 +12078,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->multipath_on_hba = 1;
else
ioc->multipath_on_hba = 0;
+ break;
default:
break;
}
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index 6aa2697c4a15..f18dd9703595 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -46,6 +46,7 @@ static struct scsi_host_template mvs_sht = {
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_target_reset_handler = sas_eh_target_reset_handler,
+ .slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
#ifdef CONFIG_COMPAT
@@ -692,22 +693,17 @@ static struct pci_driver mvs_pci_driver = {
.remove = mvs_pci_remove,
};
-static ssize_t
-mvs_show_driver_version(struct device *cdev,
- struct device_attribute *attr, char *buffer)
+static ssize_t driver_version_show(struct device *cdev,
+ struct device_attribute *attr, char *buffer)
{
return snprintf(buffer, PAGE_SIZE, "%s\n", DRV_VERSION);
}
-static DEVICE_ATTR(driver_version,
- S_IRUGO,
- mvs_show_driver_version,
- NULL);
+static DEVICE_ATTR_RO(driver_version);
-static ssize_t
-mvs_store_interrupt_coalescing(struct device *cdev,
- struct device_attribute *attr,
- const char *buffer, size_t size)
+static ssize_t interrupt_coalescing_store(struct device *cdev,
+ struct device_attribute *attr,
+ const char *buffer, size_t size)
{
unsigned int val = 0;
struct mvs_info *mvi = NULL;
@@ -745,16 +741,13 @@ mvs_store_interrupt_coalescing(struct device *cdev,
return strlen(buffer);
}
-static ssize_t mvs_show_interrupt_coalescing(struct device *cdev,
- struct device_attribute *attr, char *buffer)
+static ssize_t interrupt_coalescing_show(struct device *cdev,
+ struct device_attribute *attr, char *buffer)
{
return snprintf(buffer, PAGE_SIZE, "%d\n", interrupt_coalescing);
}
-static DEVICE_ATTR(interrupt_coalescing,
- S_IRUGO|S_IWUSR,
- mvs_show_interrupt_coalescing,
- mvs_store_interrupt_coalescing);
+static DEVICE_ATTR_RW(interrupt_coalescing);
static int __init mvs_init(void)
{
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index 1acea528f27f..31d1ea5a5dd2 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -1314,7 +1314,7 @@ static int mvs_exec_internal_tmf_task(struct domain_device *dev,
}
if (task->task_status.resp == SAS_TASK_COMPLETE &&
- task->task_status.stat == SAM_STAT_GOOD) {
+ task->task_status.stat == SAS_SAM_STAT_GOOD) {
res = TMF_RESP_FUNC_COMPLETE;
break;
}
@@ -1764,7 +1764,7 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
case SAS_PROTOCOL_SSP:
/* hw says status == 0, datapres == 0 */
if (rx_desc & RXQ_GOOD) {
- tstat->stat = SAM_STAT_GOOD;
+ tstat->stat = SAS_SAM_STAT_GOOD;
tstat->resp = SAS_TASK_COMPLETE;
}
/* response frame present */
@@ -1773,12 +1773,12 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
sizeof(struct mvs_err_info);
sas_ssp_task_response(mvi->dev, task, iu);
} else
- tstat->stat = SAM_STAT_CHECK_CONDITION;
+ tstat->stat = SAS_SAM_STAT_CHECK_CONDITION;
break;
case SAS_PROTOCOL_SMP: {
struct scatterlist *sg_resp = &task->smp_task.smp_resp;
- tstat->stat = SAM_STAT_GOOD;
+ tstat->stat = SAS_SAM_STAT_GOOD;
to = kmap_atomic(sg_page(sg_resp));
memcpy(to + sg_resp->offset,
slot->response + sizeof(struct mvs_err_info),
@@ -1795,7 +1795,7 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
}
default:
- tstat->stat = SAM_STAT_CHECK_CONDITION;
+ tstat->stat = SAS_SAM_STAT_CHECK_CONDITION;
break;
}
if (!slot->port->port_attached) {
diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c
index 9d5743627604..6bb03d7a254d 100644
--- a/drivers/scsi/mvumi.c
+++ b/drivers/scsi/mvumi.c
@@ -1317,11 +1317,10 @@ static void mvumi_complete_cmd(struct mvumi_hba *mhba, struct mvumi_cmd *cmd,
if (ob_frame->rsp_flag & CL_RSP_FLAG_SENSEDATA) {
memcpy(cmd->scmd->sense_buffer, ob_frame->payload,
sizeof(struct mvumi_sense_data));
- scmd->result |= (DRIVER_SENSE << 24);
}
break;
default:
- scmd->result |= (DRIVER_INVALID << 24) | (DID_ABORT << 16);
+ scmd->result |= (DID_ABORT << 16);
break;
}
@@ -2068,10 +2067,7 @@ static unsigned char mvumi_build_frame(struct mvumi_hba *mhba,
return 0;
error:
- scmd->result = (DID_OK << 16) | (DRIVER_SENSE << 24) |
- SAM_STAT_CHECK_CONDITION;
- scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 0x24,
- 0);
+ scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x24, 0);
return -1;
}
@@ -2131,7 +2127,7 @@ static enum blk_eh_timer_return mvumi_timed_out(struct scsi_cmnd *scmd)
else
atomic_dec(&mhba->fw_outstanding);
- scmd->result = (DRIVER_INVALID << 24) | (DID_ABORT << 16);
+ scmd->result = (DID_ABORT << 16);
scmd->SCp.ptr = NULL;
if (scsi_bufflen(scmd)) {
dma_unmap_sg(&mhba->pdev->dev, scsi_sglist(scmd),
diff --git a/drivers/scsi/myrb.c b/drivers/scsi/myrb.c
index d9c82e211ae7..542ed88ef90d 100644
--- a/drivers/scsi/myrb.c
+++ b/drivers/scsi/myrb.c
@@ -1397,8 +1397,7 @@ myrb_mode_sense(struct myrb_hba *cb, struct scsi_cmnd *scmd,
static void myrb_request_sense(struct myrb_hba *cb,
struct scsi_cmnd *scmd)
{
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- NO_SENSE, 0, 0);
+ scsi_build_sense(scmd, 0, NO_SENSE, 0, 0);
scsi_sg_copy_from_buffer(scmd, scmd->sense_buffer,
SCSI_SENSE_BUFFERSIZE);
}
@@ -1447,10 +1446,7 @@ static int myrb_ldev_queuecommand(struct Scsi_Host *shost,
case INQUIRY:
if (scmd->cmnd[1] & 1) {
/* Illegal request, invalid field in CDB */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- ILLEGAL_REQUEST, 0x24, 0);
- scmd->result = (DRIVER_SENSE << 24) |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x24, 0);
} else {
myrb_inquiry(cb, scmd);
scmd->result = (DID_OK << 16);
@@ -1465,10 +1461,7 @@ static int myrb_ldev_queuecommand(struct Scsi_Host *shost,
if ((scmd->cmnd[2] & 0x3F) != 0x3F &&
(scmd->cmnd[2] & 0x3F) != 0x08) {
/* Illegal request, invalid field in CDB */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- ILLEGAL_REQUEST, 0x24, 0);
- scmd->result = (DRIVER_SENSE << 24) |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x24, 0);
} else {
myrb_mode_sense(cb, scmd, ldev_info);
scmd->result = (DID_OK << 16);
@@ -1479,20 +1472,14 @@ static int myrb_ldev_queuecommand(struct Scsi_Host *shost,
if ((scmd->cmnd[1] & 1) ||
(scmd->cmnd[8] & 1)) {
/* Illegal request, invalid field in CDB */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- ILLEGAL_REQUEST, 0x24, 0);
- scmd->result = (DRIVER_SENSE << 24) |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x24, 0);
scmd->scsi_done(scmd);
return 0;
}
lba = get_unaligned_be32(&scmd->cmnd[2]);
if (lba) {
/* Illegal request, invalid field in CDB */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- ILLEGAL_REQUEST, 0x24, 0);
- scmd->result = (DRIVER_SENSE << 24) |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x24, 0);
scmd->scsi_done(scmd);
return 0;
}
@@ -1506,10 +1493,7 @@ static int myrb_ldev_queuecommand(struct Scsi_Host *shost,
case SEND_DIAGNOSTIC:
if (scmd->cmnd[1] != 0x04) {
/* Illegal request, invalid field in CDB */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- ILLEGAL_REQUEST, 0x24, 0);
- scmd->result = (DRIVER_SENSE << 24) |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x24, 0);
} else {
/* Assume good status */
scmd->result = (DID_OK << 16);
@@ -1519,10 +1503,7 @@ static int myrb_ldev_queuecommand(struct Scsi_Host *shost,
case READ_6:
if (ldev_info->state == MYRB_DEVICE_WO) {
/* Data protect, attempt to read invalid data */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- DATA_PROTECT, 0x21, 0x06);
- scmd->result = (DRIVER_SENSE << 24) |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 0, DATA_PROTECT, 0x21, 0x06);
scmd->scsi_done(scmd);
return 0;
}
@@ -1536,10 +1517,7 @@ static int myrb_ldev_queuecommand(struct Scsi_Host *shost,
case READ_10:
if (ldev_info->state == MYRB_DEVICE_WO) {
/* Data protect, attempt to read invalid data */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- DATA_PROTECT, 0x21, 0x06);
- scmd->result = (DRIVER_SENSE << 24) |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 0, DATA_PROTECT, 0x21, 0x06);
scmd->scsi_done(scmd);
return 0;
}
@@ -1553,10 +1531,7 @@ static int myrb_ldev_queuecommand(struct Scsi_Host *shost,
case READ_12:
if (ldev_info->state == MYRB_DEVICE_WO) {
/* Data protect, attempt to read invalid data */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- DATA_PROTECT, 0x21, 0x06);
- scmd->result = (DRIVER_SENSE << 24) |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 0, DATA_PROTECT, 0x21, 0x06);
scmd->scsi_done(scmd);
return 0;
}
@@ -1569,9 +1544,7 @@ static int myrb_ldev_queuecommand(struct Scsi_Host *shost,
break;
default:
/* Illegal request, invalid opcode */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- ILLEGAL_REQUEST, 0x20, 0);
- scmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x20, 0);
scmd->scsi_done(scmd);
return 0;
}
@@ -2352,25 +2325,19 @@ static void myrb_handle_scsi(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk,
"Bad Data Encountered\n");
if (scmd->sc_data_direction == DMA_FROM_DEVICE)
/* Unrecovered read error */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- MEDIUM_ERROR, 0x11, 0);
+ scsi_build_sense(scmd, 0, MEDIUM_ERROR, 0x11, 0);
else
/* Write error */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- MEDIUM_ERROR, 0x0C, 0);
- scmd->result = (DID_OK << 16) | SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 0, MEDIUM_ERROR, 0x0C, 0);
break;
case MYRB_STATUS_IRRECOVERABLE_DATA_ERROR:
scmd_printk(KERN_ERR, scmd, "Irrecoverable Data Error\n");
if (scmd->sc_data_direction == DMA_FROM_DEVICE)
/* Unrecovered read error, auto-reallocation failed */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- MEDIUM_ERROR, 0x11, 0x04);
+ scsi_build_sense(scmd, 0, MEDIUM_ERROR, 0x11, 0x04);
else
/* Write error, auto-reallocation failed */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- MEDIUM_ERROR, 0x0C, 0x02);
- scmd->result = (DID_OK << 16) | SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 0, MEDIUM_ERROR, 0x0C, 0x02);
break;
case MYRB_STATUS_LDRV_NONEXISTENT_OR_OFFLINE:
dev_dbg(&scmd->device->sdev_gendev,
@@ -2381,8 +2348,7 @@ static void myrb_handle_scsi(struct myrb_hba *cb, struct myrb_cmdblk *cmd_blk,
dev_dbg(&scmd->device->sdev_gendev,
"Attempt to Access Beyond End of Logical Drive");
/* Logical block address out of range */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- NOT_READY, 0x21, 0);
+ scsi_build_sense(scmd, 0, NOT_READY, 0x21, 0);
break;
case MYRB_STATUS_DEVICE_NONRESPONSIVE:
dev_dbg(&scmd->device->sdev_gendev, "Device nonresponsive\n");
diff --git a/drivers/scsi/myrs.c b/drivers/scsi/myrs.c
index 3b68c68d1716..26326af23dbc 100644
--- a/drivers/scsi/myrs.c
+++ b/drivers/scsi/myrs.c
@@ -1600,9 +1600,7 @@ static int myrs_queuecommand(struct Scsi_Host *shost,
switch (scmd->cmnd[0]) {
case REPORT_LUNS:
- scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST,
- 0x20, 0x0);
- scmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x20, 0x0);
scmd->scsi_done(scmd);
return 0;
case MODE_SENSE:
@@ -1612,10 +1610,7 @@ static int myrs_queuecommand(struct Scsi_Host *shost,
if ((scmd->cmnd[2] & 0x3F) != 0x3F &&
(scmd->cmnd[2] & 0x3F) != 0x08) {
/* Illegal request, invalid field in CDB */
- scsi_build_sense_buffer(0, scmd->sense_buffer,
- ILLEGAL_REQUEST, 0x24, 0);
- scmd->result = (DRIVER_SENSE << 24) |
- SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(scmd, 0, ILLEGAL_REQUEST, 0x24, 0);
} else {
myrs_mode_sense(cs, scmd, ldev_info);
scmd->result = (DID_OK << 16);
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 134bbd2d8b66..bc9d29e5fdba 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -176,38 +176,40 @@ static nsp32_sync_table nsp32_sync_table_pci[] = {
* function declaration
*/
/* module entry point */
-static int nsp32_probe (struct pci_dev *, const struct pci_device_id *);
-static void nsp32_remove(struct pci_dev *);
+static int nsp32_probe (struct pci_dev *, const struct pci_device_id *);
+static void nsp32_remove(struct pci_dev *);
static int __init init_nsp32 (void);
static void __exit exit_nsp32 (void);
/* struct struct scsi_host_template */
-static int nsp32_show_info (struct seq_file *, struct Scsi_Host *);
+static int nsp32_show_info (struct seq_file *, struct Scsi_Host *);
-static int nsp32_detect (struct pci_dev *pdev);
-static int nsp32_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
-static const char *nsp32_info (struct Scsi_Host *);
-static int nsp32_release (struct Scsi_Host *);
+static int nsp32_detect (struct pci_dev *pdev);
+static int nsp32_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
+static const char *nsp32_info (struct Scsi_Host *);
+static int nsp32_release (struct Scsi_Host *);
/* SCSI error handler */
-static int nsp32_eh_abort (struct scsi_cmnd *);
-static int nsp32_eh_host_reset(struct scsi_cmnd *);
+static int nsp32_eh_abort (struct scsi_cmnd *);
+static int nsp32_eh_host_reset(struct scsi_cmnd *);
/* generate SCSI message */
static void nsp32_build_identify(struct scsi_cmnd *);
static void nsp32_build_nop (struct scsi_cmnd *);
static void nsp32_build_reject (struct scsi_cmnd *);
-static void nsp32_build_sdtr (struct scsi_cmnd *, unsigned char, unsigned char);
+static void nsp32_build_sdtr (struct scsi_cmnd *, unsigned char,
+ unsigned char);
/* SCSI message handler */
static int nsp32_busfree_occur(struct scsi_cmnd *, unsigned short);
static void nsp32_msgout_occur (struct scsi_cmnd *);
-static void nsp32_msgin_occur (struct scsi_cmnd *, unsigned long, unsigned short);
+static void nsp32_msgin_occur (struct scsi_cmnd *, unsigned long,
+ unsigned short);
static int nsp32_setup_sg_table (struct scsi_cmnd *);
static int nsp32_selection_autopara(struct scsi_cmnd *);
static int nsp32_selection_autoscsi(struct scsi_cmnd *);
-static void nsp32_scsi_done (struct scsi_cmnd *);
+static void nsp32_scsi_done (struct scsi_cmnd *);
static int nsp32_arbitration (struct scsi_cmnd *, unsigned int);
static int nsp32_reselection (struct scsi_cmnd *, unsigned char);
static void nsp32_adjust_busfree (struct scsi_cmnd *, unsigned int);
@@ -215,10 +217,13 @@ static void nsp32_restart_autoscsi (struct scsi_cmnd *, unsigned short);
/* SCSI SDTR */
static void nsp32_analyze_sdtr (struct scsi_cmnd *);
-static int nsp32_search_period_entry(nsp32_hw_data *, nsp32_target *, unsigned char);
-static void nsp32_set_async (nsp32_hw_data *, nsp32_target *);
-static void nsp32_set_max_sync (nsp32_hw_data *, nsp32_target *, unsigned char *, unsigned char *);
-static void nsp32_set_sync_entry (nsp32_hw_data *, nsp32_target *, int, unsigned char);
+static int nsp32_search_period_entry(nsp32_hw_data *, nsp32_target *,
+ unsigned char);
+static void nsp32_set_async (nsp32_hw_data *, nsp32_target *);
+static void nsp32_set_max_sync (nsp32_hw_data *, nsp32_target *,
+ unsigned char *, unsigned char *);
+static void nsp32_set_sync_entry (nsp32_hw_data *, nsp32_target *,
+ int, unsigned char);
/* SCSI bus status handler */
static void nsp32_wait_req (nsp32_hw_data *, int);
@@ -234,16 +239,16 @@ static irqreturn_t do_nsp32_isr(int, void *);
static int nsp32hw_init(nsp32_hw_data *);
/* EEPROM handler */
-static int nsp32_getprom_param (nsp32_hw_data *);
-static int nsp32_getprom_at24 (nsp32_hw_data *);
-static int nsp32_getprom_c16 (nsp32_hw_data *);
-static void nsp32_prom_start (nsp32_hw_data *);
-static void nsp32_prom_stop (nsp32_hw_data *);
-static int nsp32_prom_read (nsp32_hw_data *, int);
-static int nsp32_prom_read_bit (nsp32_hw_data *);
-static void nsp32_prom_write_bit(nsp32_hw_data *, int);
-static void nsp32_prom_set (nsp32_hw_data *, int, int);
-static int nsp32_prom_get (nsp32_hw_data *, int);
+static int nsp32_getprom_param (nsp32_hw_data *);
+static int nsp32_getprom_at24 (nsp32_hw_data *);
+static int nsp32_getprom_c16 (nsp32_hw_data *);
+static void nsp32_prom_start (nsp32_hw_data *);
+static void nsp32_prom_stop (nsp32_hw_data *);
+static int nsp32_prom_read (nsp32_hw_data *, int);
+static int nsp32_prom_read_bit (nsp32_hw_data *);
+static void nsp32_prom_write_bit(nsp32_hw_data *, int);
+static void nsp32_prom_set (nsp32_hw_data *, int, int);
+static int nsp32_prom_get (nsp32_hw_data *, int);
/* debug/warning/info message */
static void nsp32_message (const char *, int, char *, char *, ...);
@@ -356,8 +361,8 @@ static void nsp32_dmessage(const char *func, int line, int mask, char *fmt, ...)
static void nsp32_build_identify(struct scsi_cmnd *SCpnt)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
- int pos = data->msgout_len;
- int mode = FALSE;
+ int pos = data->msgout_len;
+ int mode = FALSE;
/* XXX: Auto DiscPriv detection is progressing... */
if (disc_priv == 0) {
@@ -377,13 +382,13 @@ static void nsp32_build_sdtr(struct scsi_cmnd *SCpnt,
unsigned char offset)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
- int pos = data->msgout_len;
+ int pos = data->msgout_len;
data->msgoutbuf[pos] = EXTENDED_MESSAGE; pos++;
data->msgoutbuf[pos] = EXTENDED_SDTR_LEN; pos++;
data->msgoutbuf[pos] = EXTENDED_SDTR; pos++;
- data->msgoutbuf[pos] = period; pos++;
- data->msgoutbuf[pos] = offset; pos++;
+ data->msgoutbuf[pos] = period; pos++;
+ data->msgoutbuf[pos] = offset; pos++;
data->msgout_len = pos;
}
@@ -394,7 +399,7 @@ static void nsp32_build_sdtr(struct scsi_cmnd *SCpnt,
static void nsp32_build_nop(struct scsi_cmnd *SCpnt)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
- int pos = data->msgout_len;
+ int pos = data->msgout_len;
if (pos != 0) {
nsp32_msg(KERN_WARNING,
@@ -412,12 +417,12 @@ static void nsp32_build_nop(struct scsi_cmnd *SCpnt)
static void nsp32_build_reject(struct scsi_cmnd *SCpnt)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
- int pos = data->msgout_len;
+ int pos = data->msgout_len;
data->msgoutbuf[pos] = MESSAGE_REJECT; pos++;
data->msgout_len = pos;
}
-
+
/*
* timer
*/
@@ -450,7 +455,7 @@ static int nsp32_selection_autopara(struct scsi_cmnd *SCpnt)
unsigned char phase;
int i, ret;
unsigned int msgout;
- u16_le s;
+ u16_le s;
nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in");
@@ -482,7 +487,7 @@ static int nsp32_selection_autopara(struct scsi_cmnd *SCpnt)
* the sending order of the message is:
* MCNT 3: MSG#0 -> MSG#1 -> MSG#2
* MCNT 2: MSG#1 -> MSG#2
- * MCNT 1: MSG#2
+ * MCNT 1: MSG#2
*/
msgout >>= 8;
msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24);
@@ -494,7 +499,8 @@ static int nsp32_selection_autopara(struct scsi_cmnd *SCpnt)
msgout = 0;
}
- // nsp_dbg(NSP32_DEBUG_AUTOSCSI, "sel time out=0x%x\n", nsp32_read2(base, SEL_TIME_OUT));
+ // nsp_dbg(NSP32_DEBUG_AUTOSCSI, "sel time out=0x%x\n",
+ // nsp32_read2(base, SEL_TIME_OUT));
// nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME);
/*
@@ -520,10 +526,10 @@ static int nsp32_selection_autopara(struct scsi_cmnd *SCpnt)
/* command control */
param->command_control = cpu_to_le16(CLEAR_CDB_FIFO_POINTER |
- AUTOSCSI_START |
- AUTO_MSGIN_00_OR_04 |
- AUTO_MSGIN_02 |
- AUTO_ATN );
+ AUTOSCSI_START |
+ AUTO_MSGIN_00_OR_04 |
+ AUTO_MSGIN_02 |
+ AUTO_ATN );
/* transfer control */
@@ -555,9 +561,9 @@ static int nsp32_selection_autopara(struct scsi_cmnd *SCpnt)
/*
* transfer parameter to ASIC
*/
- nsp32_write4(base, SGT_ADR, data->auto_paddr);
- nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER |
- AUTO_PARAMETER );
+ nsp32_write4(base, SGT_ADR, data->auto_paddr);
+ nsp32_write2(base, COMMAND_CONTROL,
+ CLEAR_CDB_FIFO_POINTER | AUTO_PARAMETER );
/*
* Check arbitration
@@ -599,7 +605,7 @@ static int nsp32_selection_autoscsi(struct scsi_cmnd *SCpnt)
SCpnt->result = DID_BUS_BUSY << 16;
status = 1;
goto out;
- }
+ }
/*
* clear execph
@@ -616,13 +622,14 @@ static int nsp32_selection_autoscsi(struct scsi_cmnd *SCpnt)
*/
for (i = 0; i < SCpnt->cmd_len; i++) {
nsp32_write1(base, COMMAND_DATA, SCpnt->cmnd[i]);
- }
+ }
nsp32_dbg(NSP32_DEBUG_CDB_CONTENTS, "CDB[0]=[0x%x]", SCpnt->cmnd[0]);
/*
* set SCSIOUT LATCH(initiator)/TARGET(target) (OR-ed) ID
*/
- nsp32_write1(base, SCSI_OUT_LATCH_TARGET_ID, BIT(host_id) | BIT(target));
+ nsp32_write1(base, SCSI_OUT_LATCH_TARGET_ID,
+ BIT(host_id) | BIT(target));
/*
* set SCSI MSGOUT REG
@@ -642,7 +649,7 @@ static int nsp32_selection_autoscsi(struct scsi_cmnd *SCpnt)
* the sending order of the message is:
* MCNT 3: MSG#0 -> MSG#1 -> MSG#2
* MCNT 2: MSG#1 -> MSG#2
- * MCNT 1: MSG#2
+ * MCNT 1: MSG#2
*/
msgout >>= 8;
msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24);
@@ -662,7 +669,7 @@ static int nsp32_selection_autoscsi(struct scsi_cmnd *SCpnt)
/*
* set SREQ hazard killer sampling rate
- *
+ *
* TODO: sample_rate (BASE+0F) is 0 when internal clock = 40MHz.
* check other internal clock!
*/
@@ -687,7 +694,8 @@ static int nsp32_selection_autoscsi(struct scsi_cmnd *SCpnt)
nsp32_dbg(NSP32_DEBUG_AUTOSCSI,
"syncreg=0x%x, ackwidth=0x%x, sgtpaddr=0x%x, id=0x%x",
nsp32_read1(base, SYNC_REG), nsp32_read1(base, ACK_WIDTH),
- nsp32_read4(base, SGT_ADR), nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID));
+ nsp32_read4(base, SGT_ADR),
+ nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID));
nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "msgout_len=%d, msgout=0x%x",
data->msgout_len, msgout);
@@ -716,10 +724,10 @@ static int nsp32_selection_autoscsi(struct scsi_cmnd *SCpnt)
* start AUTO SCSI, kick off arbitration
*/
command = (CLEAR_CDB_FIFO_POINTER |
- AUTOSCSI_START |
+ AUTOSCSI_START |
AUTO_MSGIN_00_OR_04 |
- AUTO_MSGIN_02 |
- AUTO_ATN );
+ AUTO_MSGIN_02 |
+ AUTO_ATN);
nsp32_write2(base, COMMAND_CONTROL, command);
/*
@@ -739,9 +747,9 @@ static int nsp32_selection_autoscsi(struct scsi_cmnd *SCpnt)
/*
* Arbitration Status Check
- *
+ *
* Note: Arbitration counter is waited during ARBIT_GO is not lifting.
- * Using udelay(1) consumes CPU time and system time, but
+ * Using udelay(1) consumes CPU time and system time, but
* arbitration delay time is defined minimal 2.4us in SCSI
* specification, thus udelay works as coarse grained wait timer.
*/
@@ -776,7 +784,7 @@ static int nsp32_arbitration(struct scsi_cmnd *SCpnt, unsigned int base)
nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit timeout");
SCpnt->result = DID_NO_CONNECT << 16;
status = FALSE;
- }
+ }
/*
* clear Arbit
@@ -822,7 +830,8 @@ static int nsp32_reselection(struct scsi_cmnd *SCpnt, unsigned char newlun)
* or current nexus is not existed, unexpected
* reselection is occurred. Send reject message.
*/
- if (newid >= ARRAY_SIZE(data->lunt) || newlun >= ARRAY_SIZE(data->lunt[0])) {
+ if (newid >= ARRAY_SIZE(data->lunt) ||
+ newlun >= ARRAY_SIZE(data->lunt[0])) {
nsp32_msg(KERN_WARNING, "unknown id/lun");
return FALSE;
} else if(data->lunt[newid][newlun].SCpnt == NULL) {
@@ -876,7 +885,8 @@ static int nsp32_setup_sg_table(struct scsi_cmnd *SCpnt)
if (le32_to_cpu(sgt[i].len) > 0x10000) {
nsp32_msg(KERN_ERR,
- "can't transfer over 64KB at a time, size=0x%x", le32_to_cpu(sgt[i].len));
+ "can't transfer over 64KB at a time, "
+ "size=0x%x", le32_to_cpu(sgt[i].len));
return FALSE;
}
nsp32_dbg(NSP32_DEBUG_SGLIST,
@@ -894,7 +904,8 @@ static int nsp32_setup_sg_table(struct scsi_cmnd *SCpnt)
return TRUE;
}
-static int nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+static int nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt,
+ void (*done)(struct scsi_cmnd *))
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
nsp32_target *target;
@@ -904,8 +915,9 @@ static int nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct s
nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
"enter. target: 0x%x LUN: 0x%llx cmnd: 0x%x cmndlen: 0x%x "
"use_sg: 0x%x reqbuf: 0x%lx reqlen: 0x%x",
- SCpnt->device->id, SCpnt->device->lun, SCpnt->cmnd[0], SCpnt->cmd_len,
- scsi_sg_count(SCpnt), scsi_sglist(SCpnt), scsi_bufflen(SCpnt));
+ SCpnt->device->id, SCpnt->device->lun, SCpnt->cmnd[0],
+ SCpnt->cmd_len, scsi_sg_count(SCpnt), scsi_sglist(SCpnt),
+ scsi_bufflen(SCpnt));
if (data->CurrentSC != NULL) {
nsp32_msg(KERN_ERR, "Currentsc != NULL. Cancel this command request");
@@ -936,7 +948,6 @@ static int nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct s
SCpnt->scsi_done = done;
data->CurrentSC = SCpnt;
SCpnt->SCp.Status = SAM_STAT_CHECK_CONDITION;
- SCpnt->SCp.Message = 0;
scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
SCpnt->SCp.ptr = (char *)scsi_sglist(SCpnt);
@@ -966,7 +977,7 @@ static int nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct s
/* Build IDENTIFY */
nsp32_build_identify(SCpnt);
- /*
+ /*
* If target is the first time to transfer after the reset
* (target don't have SDTR_DONE and SDTR_INITIATOR), sync
* message SDTR is needed to do synchronous transfer.
@@ -1051,9 +1062,9 @@ static int nsp32hw_init(nsp32_hw_data *data)
nsp32_index_write2(base, CFG_LATE_CACHE, lc_reg & 0xffff);
}
- nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
- nsp32_write2(base, TRANSFER_CONTROL, 0);
- nsp32_write4(base, BM_CNT, 0);
+ nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+ nsp32_write2(base, TRANSFER_CONTROL, 0);
+ nsp32_write4(base, BM_CNT, 0);
nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);
do {
@@ -1081,12 +1092,13 @@ static int nsp32hw_init(nsp32_hw_data *data)
nsp32_index_read1(base, FIFO_EMPTY_SHLD_COUNT));
nsp32_index_write1(base, CLOCK_DIV, data->clock);
- nsp32_index_write1(base, BM_CYCLE, MEMRD_CMD1 | SGT_AUTO_PARA_MEMED_CMD);
+ nsp32_index_write1(base, BM_CYCLE,
+ MEMRD_CMD1 | SGT_AUTO_PARA_MEMED_CMD);
nsp32_write1(base, PARITY_CONTROL, 0); /* parity check is disable */
/*
* initialize MISC_WRRD register
- *
+ *
* Note: Designated parameters is obeyed as following:
* MISC_SCSI_DIRECTION_DETECTOR_SELECT: It must be set.
* MISC_MASTER_TERMINATION_SELECT: It must be set.
@@ -1101,10 +1113,10 @@ static int nsp32hw_init(nsp32_hw_data *data)
*/
nsp32_index_write2(base, MISC_WR,
(SCSI_DIRECTION_DETECTOR_SELECT |
- DELAYED_BMSTART |
- MASTER_TERMINATION_SELECT |
- BMREQ_NEGATE_TIMING_SEL |
- AUTOSEL_TIMING_SEL |
+ DELAYED_BMSTART |
+ MASTER_TERMINATION_SELECT |
+ BMREQ_NEGATE_TIMING_SEL |
+ AUTOSEL_TIMING_SEL |
BMSTOP_CHANGE2_NONDATA_PHASE));
nsp32_index_write1(base, TERM_PWR_CONTROL, 0);
@@ -1125,15 +1137,16 @@ static int nsp32hw_init(nsp32_hw_data *data)
* enable to select designated IRQ (except for
* IRQSELECT_SERR, IRQSELECT_PERR, IRQSELECT_BMCNTERR)
*/
- nsp32_index_write2(base, IRQ_SELECT, IRQSELECT_TIMER_IRQ |
- IRQSELECT_SCSIRESET_IRQ |
- IRQSELECT_FIFO_SHLD_IRQ |
- IRQSELECT_RESELECT_IRQ |
- IRQSELECT_PHASE_CHANGE_IRQ |
- IRQSELECT_AUTO_SCSI_SEQ_IRQ |
- // IRQSELECT_BMCNTERR_IRQ |
- IRQSELECT_TARGET_ABORT_IRQ |
- IRQSELECT_MASTER_ABORT_IRQ );
+ nsp32_index_write2(base, IRQ_SELECT,
+ IRQSELECT_TIMER_IRQ |
+ IRQSELECT_SCSIRESET_IRQ |
+ IRQSELECT_FIFO_SHLD_IRQ |
+ IRQSELECT_RESELECT_IRQ |
+ IRQSELECT_PHASE_CHANGE_IRQ |
+ IRQSELECT_AUTO_SCSI_SEQ_IRQ |
+ // IRQSELECT_BMCNTERR_IRQ |
+ IRQSELECT_TARGET_ABORT_IRQ |
+ IRQSELECT_MASTER_ABORT_IRQ );
nsp32_write2(base, IRQ_CONTROL, 0);
/* PCI LED off */
@@ -1163,11 +1176,12 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
* IRQ check, then enable IRQ mask
*/
irq_stat = nsp32_read2(base, IRQ_STATUS);
- nsp32_dbg(NSP32_DEBUG_INTR,
+ nsp32_dbg(NSP32_DEBUG_INTR,
"enter IRQ: %d, IRQstatus: 0x%x", irq, irq_stat);
/* is this interrupt comes from Ninja asic? */
if ((irq_stat & IRQSTATUS_ANY_IRQ) == 0) {
- nsp32_dbg(NSP32_DEBUG_INTR, "shared interrupt: irq other 0x%x", irq_stat);
+ nsp32_dbg(NSP32_DEBUG_INTR,
+ "shared interrupt: irq other 0x%x", irq_stat);
goto out2;
}
handled = 1;
@@ -1207,7 +1221,8 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
if (SCpnt == NULL) {
nsp32_msg(KERN_WARNING, "SCpnt==NULL this can't be happened");
- nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat);
+ nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x",
+ irq_stat, trans_stat);
goto out;
}
@@ -1265,13 +1280,13 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
"Data in/out phase processed");
/* read BMCNT, SGT pointer addr */
- nsp32_dbg(NSP32_DEBUG_INTR, "BMCNT=0x%lx",
+ nsp32_dbg(NSP32_DEBUG_INTR, "BMCNT=0x%lx",
nsp32_read4(base, BM_CNT));
- nsp32_dbg(NSP32_DEBUG_INTR, "addr=0x%lx",
+ nsp32_dbg(NSP32_DEBUG_INTR, "addr=0x%lx",
nsp32_read4(base, SGT_ADR));
- nsp32_dbg(NSP32_DEBUG_INTR, "SACK=0x%lx",
+ nsp32_dbg(NSP32_DEBUG_INTR, "SACK=0x%lx",
nsp32_read4(base, SACK_CNT));
- nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx",
+ nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx",
nsp32_read4(base, SAVED_SACK_CNT));
scsi_set_resid(SCpnt, 0); /* all data transferred! */
@@ -1306,7 +1321,7 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
* Read CSB and substitute CSB for SCpnt->result
* to save status phase stutas byte.
* scsi error handler checks host_byte (DID_*:
- * low level driver to indicate status), then checks
+ * low level driver to indicate status), then checks
* status_byte (SCSI status byte).
*/
SCpnt->result = (int)nsp32_read1(base, SCSI_CSB_IN);
@@ -1314,7 +1329,7 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
if (auto_stat & ILLEGAL_PHASE) {
/* Illegal phase is detected. SACK is not back. */
- nsp32_msg(KERN_WARNING,
+ nsp32_msg(KERN_WARNING,
"AUTO SCSI ILLEGAL PHASE OCCUR!!!!");
/* TODO: currently we don't have any action... bus reset? */
@@ -1367,7 +1382,8 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
break;
default:
nsp32_dbg(NSP32_DEBUG_INTR, "fifo/other phase");
- nsp32_dbg(NSP32_DEBUG_INTR, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat);
+ nsp32_dbg(NSP32_DEBUG_INTR, "irq_stat=0x%x trans_stat=0x%x",
+ irq_stat, trans_stat);
show_busphase(busphase);
break;
}
@@ -1433,32 +1449,39 @@ static int nsp32_show_info(struct seq_file *m, struct Scsi_Host *host)
{
unsigned long flags;
nsp32_hw_data *data;
- int hostno;
+ int hostno;
unsigned int base;
unsigned char mode_reg;
- int id, speed;
- long model;
+ int id, speed;
+ long model;
hostno = host->host_no;
data = (nsp32_hw_data *)host->hostdata;
base = host->io_port;
seq_puts(m, "NinjaSCSI-32 status\n\n");
- seq_printf(m, "Driver version: %s, $Revision: 1.33 $\n", nsp32_release_version);
- seq_printf(m, "SCSI host No.: %d\n", hostno);
- seq_printf(m, "IRQ: %d\n", host->irq);
- seq_printf(m, "IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
- seq_printf(m, "MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
- seq_printf(m, "sg_tablesize: %d\n", host->sg_tablesize);
- seq_printf(m, "Chip revision: 0x%x\n", (nsp32_read2(base, INDEX_REG) >> 8) & 0xff);
+ seq_printf(m, "Driver version: %s, $Revision: 1.33 $\n",
+ nsp32_release_version);
+ seq_printf(m, "SCSI host No.: %d\n", hostno);
+ seq_printf(m, "IRQ: %d\n", host->irq);
+ seq_printf(m, "IO: 0x%lx-0x%lx\n",
+ host->io_port, host->io_port + host->n_io_port - 1);
+ seq_printf(m, "MMIO(virtual address): 0x%lx-0x%lx\n",
+ host->base, host->base + data->MmioLength - 1);
+ seq_printf(m, "sg_tablesize: %d\n",
+ host->sg_tablesize);
+ seq_printf(m, "Chip revision: 0x%x\n",
+ (nsp32_read2(base, INDEX_REG) >> 8) & 0xff);
mode_reg = nsp32_index_read1(base, CHIP_MODE);
model = data->pci_devid->driver_data;
#ifdef CONFIG_PM
- seq_printf(m, "Power Management: %s\n", (mode_reg & OPTF) ? "yes" : "no");
+ seq_printf(m, "Power Management: %s\n",
+ (mode_reg & OPTF) ? "yes" : "no");
#endif
- seq_printf(m, "OEM: %ld, %s\n", (mode_reg & (OEM0|OEM1)), nsp32_model[model]);
+ seq_printf(m, "OEM: %ld, %s\n",
+ (mode_reg & (OEM0|OEM1)), nsp32_model[model]);
spin_lock_irqsave(&(data->Lock), flags);
seq_printf(m, "CurrentSC: 0x%p\n\n", data->CurrentSC);
@@ -1476,7 +1499,7 @@ static int nsp32_show_info(struct seq_file *m, struct Scsi_Host *host)
}
if (data->target[id].sync_flag == SDTR_DONE) {
- if (data->target[id].period == 0 &&
+ if (data->target[id].period == 0 &&
data->target[id].offset == ASYNC_OFFSET ) {
seq_puts(m, "async");
} else {
@@ -1518,7 +1541,7 @@ static void nsp32_scsi_done(struct scsi_cmnd *SCpnt)
* clear TRANSFERCONTROL_BM_START
*/
nsp32_write2(base, TRANSFER_CONTROL, 0);
- nsp32_write4(base, BM_CNT, 0);
+ nsp32_write4(base, BM_CNT, 0);
/*
* call scsi_done
@@ -1528,10 +1551,10 @@ static void nsp32_scsi_done(struct scsi_cmnd *SCpnt)
/*
* reset parameters
*/
- data->cur_lunt->SCpnt = NULL;
- data->cur_lunt = NULL;
- data->cur_target = NULL;
- data->CurrentSC = NULL;
+ data->cur_lunt->SCpnt = NULL;
+ data->cur_lunt = NULL;
+ data->cur_target = NULL;
+ data->CurrentSC = NULL;
}
@@ -1553,7 +1576,7 @@ static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph)
nsp32_dbg(NSP32_DEBUG_BUSFREE, "enter execph=0x%x", execph);
show_autophase(execph);
- nsp32_write4(base, BM_CNT, 0);
+ nsp32_write4(base, BM_CNT, 0);
nsp32_write2(base, TRANSFER_CONTROL, 0);
/*
@@ -1561,7 +1584,7 @@ static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph)
*
* VALID:
* Save Data Pointer is received. Adjust pointer.
- *
+ *
* NO-VALID:
* SCSI-3 says if Save Data Pointer is not received, then we restart
* processing and we can't adjust any SCSI data pointer in next data
@@ -1574,7 +1597,7 @@ static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph)
* Check sack_cnt/saved_sack_cnt, then adjust sg table if
* needed.
*/
- if (!(execph & MSGIN_00_VALID) &&
+ if (!(execph & MSGIN_00_VALID) &&
((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE))) {
unsigned int sacklen, s_sacklen;
@@ -1617,7 +1640,7 @@ static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph)
* no processing.
*/
}
-
+
if (execph & MSGIN_03_VALID) {
/* MsgIn03 was valid to be processed. No need processing. */
}
@@ -1639,7 +1662,7 @@ static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph)
* negotiating.
*/
if (execph & (MSGIN_00_VALID | MSGIN_04_VALID)) {
- /*
+ /*
* If valid message is received, then
* negotiation is succeeded.
*/
@@ -1666,21 +1689,18 @@ static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph)
nsp32_dbg(NSP32_DEBUG_BUSFREE, "command complete");
SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN);
- SCpnt->SCp.Message = 0;
- nsp32_dbg(NSP32_DEBUG_BUSFREE,
+ nsp32_dbg(NSP32_DEBUG_BUSFREE,
"normal end stat=0x%x resid=0x%x\n",
SCpnt->SCp.Status, scsi_get_resid(SCpnt));
- SCpnt->result = (DID_OK << 16) |
- (SCpnt->SCp.Message << 8) |
- (SCpnt->SCp.Status << 0);
+ SCpnt->result = (DID_OK << 16) |
+ (SCpnt->SCp.Status << 0);
nsp32_scsi_done(SCpnt);
/* All operation is done */
return TRUE;
} else if (execph & MSGIN_04_VALID) {
/* MsgIn 04: Disconnect */
SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN);
- SCpnt->SCp.Message = 4;
-
+
nsp32_dbg(NSP32_DEBUG_BUSFREE, "disconnect");
return TRUE;
} else {
@@ -1688,7 +1708,7 @@ static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph)
nsp32_msg(KERN_WARNING, "unexpected bus free occurred");
/* DID_ERROR? */
- //SCpnt->result = (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0);
+ //SCpnt->result = (DID_OK << 16) | (SCpnt->SCp.Status << 0);
SCpnt->result = DID_ERROR << 16;
nsp32_scsi_done(SCpnt);
return TRUE;
@@ -1706,12 +1726,12 @@ static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph)
static void nsp32_adjust_busfree(struct scsi_cmnd *SCpnt, unsigned int s_sacklen)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
- int old_entry = data->cur_entry;
- int new_entry;
- int sg_num = data->cur_lunt->sg_num;
- nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt;
- unsigned int restlen, sentlen;
- u32_le len, addr;
+ int old_entry = data->cur_entry;
+ int new_entry;
+ int sg_num = data->cur_lunt->sg_num;
+ nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt;
+ unsigned int restlen, sentlen;
+ u32_le len, addr;
nsp32_dbg(NSP32_DEBUG_SGLIST, "old resid=0x%x", scsi_get_resid(SCpnt));
@@ -1719,7 +1739,7 @@ static void nsp32_adjust_busfree(struct scsi_cmnd *SCpnt, unsigned int s_sacklen
s_sacklen -= le32_to_cpu(sgt[old_entry].addr) & 3;
/*
- * calculate new_entry from sack count and each sgt[].len
+ * calculate new_entry from sack count and each sgt[].len
* calculate the byte which is intent to send
*/
sentlen = 0;
@@ -1737,8 +1757,10 @@ static void nsp32_adjust_busfree(struct scsi_cmnd *SCpnt, unsigned int s_sacklen
if (sentlen == s_sacklen) {
/* XXX: confirm it's ok or not */
- /* In this case, it's ok because we are at
- the head element of the sg. restlen is correctly calculated. */
+ /* In this case, it's ok because we are at
+ * the head element of the sg. restlen is correctly
+ * calculated.
+ */
}
/* calculate the rest length for transferring */
@@ -1753,7 +1775,7 @@ static void nsp32_adjust_busfree(struct scsi_cmnd *SCpnt, unsigned int s_sacklen
/* set cur_entry with new_entry */
data->cur_entry = new_entry;
-
+
return;
last:
@@ -1781,7 +1803,7 @@ static void nsp32_msgout_occur(struct scsi_cmnd *SCpnt)
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
unsigned int base = SCpnt->device->host->io_port;
int i;
-
+
nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,
"enter: msgout_len: 0x%x", data->msgout_len);
@@ -1815,10 +1837,10 @@ static void nsp32_msgout_occur(struct scsi_cmnd *SCpnt)
//nsp32_restart_autoscsi(SCpnt, command);
nsp32_write2(base, COMMAND_CONTROL,
(CLEAR_CDB_FIFO_POINTER |
- AUTO_COMMAND_PHASE |
- AUTOSCSI_RESTART |
- AUTO_MSGIN_00_OR_04 |
- AUTO_MSGIN_02 ));
+ AUTO_COMMAND_PHASE |
+ AUTOSCSI_RESTART |
+ AUTO_MSGIN_00_OR_04 |
+ AUTO_MSGIN_02 ));
}
/*
* Write data with SACK, then wait sack is
@@ -1918,9 +1940,9 @@ static void nsp32_msgin_occur(struct scsi_cmnd *SCpnt,
unsigned char msgtype;
unsigned char newlun;
unsigned short command = 0;
- int msgclear = TRUE;
- long new_sgtp;
- int ret;
+ int msgclear = TRUE;
+ long new_sgtp;
+ int ret;
/*
* read first message
@@ -1960,7 +1982,7 @@ static void nsp32_msgin_occur(struct scsi_cmnd *SCpnt,
goto reject;
}
}
-
+
/*
* processing messages except for IDENTIFY
*
@@ -1976,10 +1998,10 @@ static void nsp32_msgin_occur(struct scsi_cmnd *SCpnt,
* These messages should not be occurred.
* They should be processed on AutoSCSI sequencer.
*/
- nsp32_msg(KERN_WARNING,
+ nsp32_msg(KERN_WARNING,
"unexpected message of AutoSCSI MsgIn: 0x%x", msg);
break;
-
+
case RESTORE_POINTERS:
/*
* AutoMsgIn03 is disabled, and HBA gets this message.
@@ -2005,7 +2027,7 @@ static void nsp32_msgin_occur(struct scsi_cmnd *SCpnt,
/*
* set new sg pointer
*/
- new_sgtp = data->cur_lunt->sglun_paddr +
+ new_sgtp = data->cur_lunt->sglun_paddr +
(data->cur_lunt->cur_entry * sizeof(nsp32_sgtable));
nsp32_write4(base, SGT_ADR, new_sgtp);
@@ -2016,13 +2038,13 @@ static void nsp32_msgin_occur(struct scsi_cmnd *SCpnt,
* These messages should not be occurred.
* They should be processed on AutoSCSI sequencer.
*/
- nsp32_msg (KERN_WARNING,
+ nsp32_msg (KERN_WARNING,
"unexpected message of AutoSCSI MsgIn: SAVE_POINTERS");
-
+
break;
-
+
case MESSAGE_REJECT:
- /* If previous message_out is sending SDTR, and get
+ /* If previous message_out is sending SDTR, and get
message_reject from target, SDTR negotiation is failed */
if (data->cur_target->sync_flag &
(SDTR_INITIATOR | SDTR_TARGET)) {
@@ -2041,7 +2063,7 @@ static void nsp32_msgin_occur(struct scsi_cmnd *SCpnt,
case LINKED_CMD_COMPLETE:
case LINKED_FLG_CMD_COMPLETE:
/* queue tag is not supported currently */
- nsp32_msg (KERN_WARNING,
+ nsp32_msg (KERN_WARNING,
"unsupported message: 0x%x", msgtype);
break;
@@ -2094,7 +2116,7 @@ static void nsp32_msgin_occur(struct scsi_cmnd *SCpnt,
}
/*
- * Reach here means regular length of each type of
+ * Reach here means regular length of each type of
* extended messages.
*/
switch (data->msginbuf[2]) {
@@ -2129,12 +2151,12 @@ static void nsp32_msgin_occur(struct scsi_cmnd *SCpnt,
goto reject; /* not implemented yet */
break;
-
+
default:
goto reject;
}
break;
-
+
default:
goto reject;
}
@@ -2150,7 +2172,7 @@ static void nsp32_msgin_occur(struct scsi_cmnd *SCpnt,
* AutoSCSI restart, at the same time MsgOutOccur should be
* happened (however, such situation is really possible...?).
*/
- if (data->msgout_len > 0) {
+ if (data->msgout_len > 0) {
nsp32_write4(base, SCSI_MSG_OUT, 0);
command |= AUTO_ATN;
}
@@ -2192,7 +2214,7 @@ static void nsp32_msgin_occur(struct scsi_cmnd *SCpnt,
return;
reject:
- nsp32_msg(KERN_WARNING,
+ nsp32_msg(KERN_WARNING,
"invalid or unsupported MessageIn, rejected. "
"current msg: 0x%x (len: 0x%x), processing msg: 0x%x",
msg, data->msgin_len, msgtype);
@@ -2203,15 +2225,15 @@ static void nsp32_msgin_occur(struct scsi_cmnd *SCpnt,
}
/*
- *
+ *
*/
static void nsp32_analyze_sdtr(struct scsi_cmnd *SCpnt)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
- nsp32_target *target = data->cur_target;
- unsigned char get_period = data->msginbuf[3];
- unsigned char get_offset = data->msginbuf[4];
- int entry;
+ nsp32_target *target = data->cur_target;
+ unsigned char get_period = data->msginbuf[3];
+ unsigned char get_offset = data->msginbuf[4];
+ int entry;
nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "enter");
@@ -2219,16 +2241,16 @@ static void nsp32_analyze_sdtr(struct scsi_cmnd *SCpnt)
* If this inititor sent the SDTR message, then target responds SDTR,
* initiator SYNCREG, ACKWIDTH from SDTR parameter.
* Messages are not appropriate, then send back reject message.
- * If initiator did not send the SDTR, but target sends SDTR,
+ * If initiator did not send the SDTR, but target sends SDTR,
* initiator calculator the appropriate parameter and send back SDTR.
- */
+ */
if (target->sync_flag & SDTR_INITIATOR) {
/*
* Initiator sent SDTR, the target responds and
* send back negotiation SDTR.
*/
nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target responds SDTR");
-
+
target->sync_flag &= ~SDTR_INITIATOR;
target->sync_flag |= SDTR_DONE;
@@ -2242,7 +2264,7 @@ static void nsp32_analyze_sdtr(struct scsi_cmnd *SCpnt)
*/
goto reject;
}
-
+
if (get_offset == ASYNC_OFFSET) {
/*
* Negotiation is succeeded, the target want
@@ -2273,7 +2295,7 @@ static void nsp32_analyze_sdtr(struct scsi_cmnd *SCpnt)
if (entry < 0) {
/*
- * Target want to use long period which is not
+ * Target want to use long period which is not
* acceptable NinjaSCSI-32Bi/UDE.
*/
goto reject;
@@ -2286,7 +2308,7 @@ static void nsp32_analyze_sdtr(struct scsi_cmnd *SCpnt)
} else {
/* Target send SDTR to initiator. */
nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target send SDTR");
-
+
target->sync_flag |= SDTR_INITIATOR;
/* offset: */
@@ -2409,7 +2431,7 @@ static void nsp32_set_max_sync(nsp32_hw_data *data,
*/
static void nsp32_set_sync_entry(nsp32_hw_data *data,
nsp32_target *target,
- int entry,
+ int entry,
unsigned char offset)
{
unsigned char period, ackwidth, sample_rate;
@@ -2438,7 +2460,7 @@ static void nsp32_set_sync_entry(nsp32_hw_data *data,
static void nsp32_wait_req(nsp32_hw_data *data, int state)
{
unsigned int base = data->BaseAddress;
- int wait_time = 0;
+ int wait_time = 0;
unsigned char bus, req_bit;
if (!((state == ASSERT) || (state == NEGATE))) {
@@ -2450,7 +2472,7 @@ static void nsp32_wait_req(nsp32_hw_data *data, int state)
do {
bus = nsp32_read1(base, SCSI_BUS_MONITOR);
if ((bus & BUSMON_REQ) == req_bit) {
- nsp32_dbg(NSP32_DEBUG_WAIT,
+ nsp32_dbg(NSP32_DEBUG_WAIT,
"wait_time: %d", wait_time);
return;
}
@@ -2467,7 +2489,7 @@ static void nsp32_wait_req(nsp32_hw_data *data, int state)
static void nsp32_wait_sack(nsp32_hw_data *data, int state)
{
unsigned int base = data->BaseAddress;
- int wait_time = 0;
+ int wait_time = 0;
unsigned char bus, ack_bit;
if (!((state == ASSERT) || (state == NEGATE))) {
@@ -2532,8 +2554,8 @@ static int nsp32_detect(struct pci_dev *pdev)
struct Scsi_Host *host; /* registered host structure */
struct resource *res;
nsp32_hw_data *data;
- int ret;
- int i, j;
+ int ret;
+ int i, j;
nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
@@ -2610,7 +2632,7 @@ static int nsp32_detect(struct pci_dev *pdev)
*/
/*
- * setup DMA
+ * setup DMA
*/
if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)) != 0) {
nsp32_msg (KERN_ERR, "failed to set PCI DMA mask");
@@ -2710,16 +2732,16 @@ static int nsp32_detect(struct pci_dev *pdev)
goto free_sg_list;
}
- /*
+ /*
* PCI IO register
*/
res = request_region(host->io_port, host->n_io_port, "nsp32");
if (res == NULL) {
- nsp32_msg(KERN_ERR,
+ nsp32_msg(KERN_ERR,
"I/O region 0x%x+0x%x is already used",
data->BaseAddress, data->NumAddress);
goto free_irq;
- }
+ }
ret = scsi_add_host(host, &pdev->dev);
if (ret) {
@@ -2743,7 +2765,7 @@ static int nsp32_detect(struct pci_dev *pdev)
free_autoparam:
dma_free_coherent(&pdev->dev, sizeof(nsp32_autoparam),
data->autoparam, data->auto_paddr);
-
+
scsi_unregister:
scsi_host_put(host);
@@ -2810,7 +2832,7 @@ static int nsp32_eh_abort(struct scsi_cmnd *SCpnt)
}
nsp32_write2(base, TRANSFER_CONTROL, 0);
- nsp32_write2(base, BM_CNT, 0);
+ nsp32_write2(base, BM_CNT, 0);
SCpnt->result = DID_ABORT << 16;
nsp32_scsi_done(SCpnt);
@@ -2833,8 +2855,8 @@ static void nsp32_do_bus_reset(nsp32_hw_data *data)
* clear counter
*/
nsp32_write2(base, TRANSFER_CONTROL, 0);
- nsp32_write4(base, BM_CNT, 0);
- nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
+ nsp32_write4(base, BM_CNT, 0);
+ nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
/*
* fall back to asynchronous transfer mode
@@ -2856,7 +2878,7 @@ static void nsp32_do_bus_reset(nsp32_hw_data *data)
for(i = 0; i < 5; i++) {
intrdat = nsp32_read2(base, IRQ_STATUS); /* dummy read */
nsp32_dbg(NSP32_DEBUG_BUSRESET, "irq:1: 0x%x", intrdat);
- }
+ }
data->CurrentSC = NULL;
}
@@ -2867,7 +2889,7 @@ static int nsp32_eh_host_reset(struct scsi_cmnd *SCpnt)
unsigned int base = SCpnt->device->host->io_port;
nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata;
- nsp32_msg(KERN_INFO, "Host Reset");
+ nsp32_msg(KERN_INFO, "Host Reset");
nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt);
spin_lock_irq(SCpnt->device->host->host_lock);
@@ -2942,13 +2964,13 @@ static int nsp32_getprom_param(nsp32_hw_data *data)
* AT24C01A (Logitec: LHA-600S), AT24C02 (Melco Buffalo: IFC-USLP) data map:
*
* ROMADDR
- * 0x00 - 0x06 : Device Synchronous Transfer Period (SCSI ID 0 - 6)
+ * 0x00 - 0x06 : Device Synchronous Transfer Period (SCSI ID 0 - 6)
* Value 0x0: ASYNC, 0x0c: Ultra-20M, 0x19: Fast-10M
* 0x07 : HBA Synchronous Transfer Period
* Value 0: AutoSync, 1: Manual Setting
* 0x08 - 0x0f : Not Used? (0x0)
* 0x10 : Bus Termination
- * Value 0: Auto[ON], 1: ON, 2: OFF
+ * Value 0: Auto[ON], 1: ON, 2: OFF
* 0x11 : Not Used? (0)
* 0x12 : Bus Reset Delay Time (0x03)
* 0x13 : Bootable CD Support
@@ -2956,7 +2978,7 @@ static int nsp32_getprom_param(nsp32_hw_data *data)
* 0x14 : Device Scan
* Bit 7 6 5 4 3 2 1 0
* | <----------------->
- * | SCSI ID: Value 0: Skip, 1: YES
+ * | SCSI ID: Value 0: Skip, 1: YES
* |-> Value 0: ALL scan, Value 1: Manual
* 0x15 - 0x1b : Not Used? (0)
* 0x1c : Constant? (0x01) (clock div?)
@@ -2967,10 +2989,10 @@ static int nsp32_getprom_param(nsp32_hw_data *data)
*/
static int nsp32_getprom_at24(nsp32_hw_data *data)
{
- int ret, i;
- int auto_sync;
+ int ret, i;
+ int auto_sync;
nsp32_target *target;
- int entry;
+ int entry;
/*
* Reset time which is designated by EEPROM.
@@ -3036,7 +3058,7 @@ static int nsp32_getprom_at24(nsp32_hw_data *data)
* C16 110 (I-O Data: SC-NBD) data map:
*
* ROMADDR
- * 0x00 - 0x06 : Device Synchronous Transfer Period (SCSI ID 0 - 6)
+ * 0x00 - 0x06 : Device Synchronous Transfer Period (SCSI ID 0 - 6)
* Value 0x0: 20MB/S, 0x1: 10MB/S, 0x2: 5MB/S, 0x3: ASYNC
* 0x07 : 0 (HBA Synchronous Transfer Period: Auto Sync)
* 0x08 - 0x0f : Not Used? (0x0)
@@ -3044,7 +3066,7 @@ static int nsp32_getprom_at24(nsp32_hw_data *data)
* Value 0: PIO, 1: Busmater
* 0x11 : Bus Reset Delay Time (0x00-0x20)
* 0x12 : Bus Termination
- * Value 0: Disable, 1: Enable
+ * Value 0: Disable, 1: Enable
* 0x13 - 0x19 : Disconnection
* Value 0: Disable, 1: Enable
* 0x1a - 0x7c : Not Used? (0)
@@ -3054,9 +3076,9 @@ static int nsp32_getprom_at24(nsp32_hw_data *data)
*/
static int nsp32_getprom_c16(nsp32_hw_data *data)
{
- int ret, i;
+ int ret, i;
nsp32_target *target;
- int entry, val;
+ int entry, val;
/*
* Reset time which is designated by EEPROM.
@@ -3156,7 +3178,7 @@ static int nsp32_prom_read(nsp32_hw_data *data, int romaddr)
for (i = 7; i >= 0; i--) {
val += (nsp32_prom_read_bit(data) << i);
}
-
+
/* no ack */
nsp32_prom_write_bit(data, 1);
@@ -3281,7 +3303,8 @@ static int nsp32_resume(struct pci_dev *pdev)
nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata;
unsigned short reg;
- nsp32_msg(KERN_INFO, "pci-resume: pdev=0x%p, slot=%s, host=0x%p", pdev, pci_name(pdev), host);
+ nsp32_msg(KERN_INFO, "pci-resume: pdev=0x%p, slot=%s, host=0x%p",
+ pdev, pci_name(pdev), host);
pci_set_power_state(pdev, PCI_D0);
pci_enable_wake (pdev, PCI_D0, 0);
@@ -3316,13 +3339,13 @@ static int nsp32_probe(struct pci_dev *pdev, const struct pci_device_id *id)
nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
- ret = pci_enable_device(pdev);
+ ret = pci_enable_device(pdev);
if (ret) {
nsp32_msg(KERN_ERR, "failed to enable pci device");
return ret;
}
- data->Pci = pdev;
+ data->Pci = pdev;
data->pci_devid = id;
data->IrqNumber = pdev->irq;
data->BaseAddress = pci_resource_start(pdev, 0);
@@ -3351,7 +3374,7 @@ static void nsp32_remove(struct pci_dev *pdev)
nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
- scsi_remove_host(host);
+ scsi_remove_host(host);
nsp32_release(host);
@@ -3364,8 +3387,8 @@ static struct pci_driver nsp32_driver = {
.probe = nsp32_probe,
.remove = nsp32_remove,
#ifdef CONFIG_PM
- .suspend = nsp32_suspend,
- .resume = nsp32_resume,
+ .suspend = nsp32_suspend,
+ .resume = nsp32_resume,
#endif
};
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index ac89002646a3..7c0f931e55e8 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -221,7 +221,7 @@ static int nsp_queuecommand_lck(struct scsi_cmnd *SCpnt,
data->CurrentSC = SCpnt;
- SCpnt->SCp.Status = CHECK_CONDITION;
+ SCpnt->SCp.Status = SAM_STAT_CHECK_CONDITION;
SCpnt->SCp.Message = 0;
SCpnt->SCp.have_data_in = IO_UNKNOWN;
SCpnt->SCp.sent_command = 0;
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
index 0b8802beb7ce..ec05c42e8ee6 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.c
+++ b/drivers/scsi/pm8001/pm8001_ctl.c
@@ -77,7 +77,7 @@ DEVICE_ATTR(interface_rev, S_IRUGO, pm8001_ctl_mpi_interface_rev_show, NULL);
* @attr: device attribute (unused)
* @buf: the buffer returned
*
- * A sysfs 'read only' shost attribute.
+ * A sysfs 'read-only' shost attribute.
*/
static ssize_t controller_fatal_error_show(struct device *cdev,
struct device_attribute *attr, char *buf)
@@ -149,7 +149,7 @@ static ssize_t pm8001_ctl_ila_version_show(struct device *cdev,
static DEVICE_ATTR(ila_version, 0444, pm8001_ctl_ila_version_show, NULL);
/**
- * pm8001_ctl_inactive_fw_version_show - Inacative firmware version number
+ * pm8001_ctl_inactive_fw_version_show - Inactive firmware version number
* @cdev: pointer to embedded class device
* @attr: device attribute (unused)
* @buf: the buffer returned
@@ -396,6 +396,7 @@ static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL);
* @cdev:pointer to embedded class device
* @attr: device attribute (unused)
* @buf: the buffer returned
+ *
* A sysfs 'read-only' shost attribute.
*/
static ssize_t pm8001_ctl_ib_queue_log_show(struct device *cdev,
@@ -430,6 +431,7 @@ static DEVICE_ATTR(ib_log, S_IRUGO, pm8001_ctl_ib_queue_log_show, NULL);
* @cdev:pointer to embedded class device
* @attr: device attribute (unused)
* @buf: the buffer returned
+ *
* A sysfs 'read-only' shost attribute.
*/
@@ -464,6 +466,7 @@ static DEVICE_ATTR(ob_log, S_IRUGO, pm8001_ctl_ob_queue_log_show, NULL);
* @cdev:pointer to embedded class device
* @attr: device attribute (unused)
* @buf:the buffer returned
+ *
* A sysfs 'read-only' shost attribute.
*/
static ssize_t pm8001_ctl_bios_version_show(struct device *cdev,
@@ -555,13 +558,13 @@ static ssize_t pm8001_ctl_iop_log_show(struct device *cdev,
static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);
/**
- ** pm8001_ctl_fatal_log_show - fatal error logging
- ** @cdev:pointer to embedded class device
- ** @attr: device attribute
- ** @buf: the buffer returned
- **
- ** A sysfs 'read-only' shost attribute.
- **/
+ * pm8001_ctl_fatal_log_show - fatal error logging
+ * @cdev:pointer to embedded class device
+ * @attr: device attribute
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev,
struct device_attribute *attr, char *buf)
@@ -575,13 +578,13 @@ static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev,
static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL);
/**
- ** non_fatal_log_show - non fatal error logging
- ** @cdev:pointer to embedded class device
- ** @attr: device attribute
- ** @buf: the buffer returned
- **
- ** A sysfs 'read-only' shost attribute.
- **/
+ * non_fatal_log_show - non fatal error logging
+ * @cdev:pointer to embedded class device
+ * @attr: device attribute
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
static ssize_t non_fatal_log_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
@@ -620,12 +623,13 @@ static ssize_t non_fatal_count_store(struct device *cdev,
static DEVICE_ATTR_RW(non_fatal_count);
/**
- ** pm8001_ctl_gsm_log_show - gsm dump collection
- ** @cdev:pointer to embedded class device
- ** @attr: device attribute (unused)
- ** @buf: the buffer returned
- ** A sysfs 'read-only' shost attribute.
- **/
+ * pm8001_ctl_gsm_log_show - gsm dump collection
+ * @cdev:pointer to embedded class device
+ * @attr: device attribute (unused)
+ * @buf: the buffer returned
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 71aa6af08340..17c0f26e683a 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -384,7 +384,7 @@ static void update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha,
/**
* pm8001_bar4_shift - function is called to shift BAR base address
- * @pm8001_ha : our hba card infomation
+ * @pm8001_ha : our hba card information
* @shiftValue : shifting value in memory bar.
*/
int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue)
@@ -1151,7 +1151,7 @@ static void pm8001_hw_chip_rst(struct pm8001_hba_info *pm8001_ha)
}
/**
- * pm8001_chip_iounmap - which maped when initialized.
+ * pm8001_chip_iounmap - which mapped when initialized.
* @pm8001_ha: our hba card information
*/
void pm8001_chip_iounmap(struct pm8001_hba_info *pm8001_ha)
@@ -1187,10 +1187,10 @@ pm8001_chip_intx_interrupt_enable(struct pm8001_hba_info *pm8001_ha)
pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, ODCR_CLEAR_ALL);
}
- /**
- * pm8001_chip_intx_interrupt_disable- disable PM8001 chip interrupt
- * @pm8001_ha: our hba card information
- */
+/**
+ * pm8001_chip_intx_interrupt_disable - disable PM8001 chip interrupt
+ * @pm8001_ha: our hba card information
+ */
static void
pm8001_chip_intx_interrupt_disable(struct pm8001_hba_info *pm8001_ha)
{
@@ -1876,8 +1876,8 @@ static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha,
* @piomb: the message contents of this outbound message.
*
* When FW has completed a ssp request for example a IO request, after it has
- * filled the SG data with the data, it will trigger this event represent
- * that he has finished the job,please check the coresponding buffer.
+ * filled the SG data with the data, it will trigger this event representing
+ * that he has finished the job; please check the corresponding buffer.
* So we will tell the caller who maybe waiting the result to tell upper layer
* that the task has been finished.
*/
@@ -1930,7 +1930,7 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
param);
if (param == 0) {
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
} else {
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_PROTO_RESPONSE;
@@ -2390,7 +2390,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n");
if (param == 0) {
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
/* check if response is for SEND READ LOG */
if (pm8001_dev &&
(pm8001_dev->id & NCQ_READ_LOG_FLAG)) {
@@ -2912,7 +2912,7 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
case IO_SUCCESS:
pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n");
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
@@ -2939,17 +2939,17 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
case IO_ERROR_HW_TIMEOUT:
pm8001_dbg(pm8001_ha, IO, "IO_ERROR_HW_TIMEOUT\n");
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_BUSY;
+ ts->stat = SAS_SAM_STAT_BUSY;
break;
case IO_XFER_ERROR_BREAK:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_BUSY;
+ ts->stat = SAS_SAM_STAT_BUSY;
break;
case IO_XFER_ERROR_PHY_NOT_READY:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_BUSY;
+ ts->stat = SAS_SAM_STAT_BUSY;
break;
case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
pm8001_dbg(pm8001_ha, IO,
@@ -3522,7 +3522,7 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb)
*
* when sas layer find a device it will notify LLDD, then the driver register
* the domain device to FW, this event is the return device ID which the FW
- * has assigned, from now,inter-communication with FW is no longer using the
+ * has assigned, from now, inter-communication with FW is no longer using the
* SAS address, use device ID which FW assigned.
*/
int pm8001_mpi_reg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
@@ -3710,7 +3710,7 @@ int pm8001_mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
case IO_SUCCESS:
pm8001_dbg(pm8001_ha, EH, "IO_SUCCESS\n");
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
break;
case IO_NOT_VALID:
pm8001_dbg(pm8001_ha, EH, "IO_NOT_VALID\n");
@@ -4357,7 +4357,7 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
spin_lock_irqsave(&task->task_state_lock, flags);
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
task->task_state_flags |= SAS_TASK_STATE_DONE;
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index af09bd282cb9..47db7e0beae6 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -101,6 +101,7 @@ static struct scsi_host_template pm8001_sht = {
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_target_reset_handler = sas_eh_target_reset_handler,
+ .slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
#ifdef CONFIG_COMPAT
@@ -232,7 +233,7 @@ static irqreturn_t pm8001_interrupt_handler_msix(int irq, void *opaque)
/**
* pm8001_interrupt_handler_intx - main INTx interrupt handler.
* @irq: interrupt number
- * @dev_id: sas_ha structure. The HBA is retrieved from sas_has structure.
+ * @dev_id: sas_ha structure. The HBA is retrieved from sas_ha structure.
*/
static irqreturn_t pm8001_interrupt_handler_intx(int irq, void *dev_id)
@@ -438,9 +439,9 @@ err_out:
}
/**
- * pm8001_ioremap - remap the pci high physical address to kernal virtual
+ * pm8001_ioremap - remap the pci high physical address to kernel virtual
* address so that we can access them.
- * @pm8001_ha:our hba structure.
+ * @pm8001_ha: our hba structure.
*/
static int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha)
{
@@ -651,7 +652,7 @@ static void pm8001_post_sas_ha_init(struct Scsi_Host *shost,
* pm8001_init_sas_add - initialize sas address
* @pm8001_ha: our ha struct.
*
- * Currently we just set the fixed SAS address to our HBA,for manufacture,
+ * Currently we just set the fixed SAS address to our HBA, for manufacture,
* it should read from the EEPROM
*/
static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
@@ -789,7 +790,7 @@ struct pm8001_mpi3_phy_pg_trx_config {
};
/**
- * pm8001_get_internal_phy_settings : Retrieves the internal PHY settings
+ * pm8001_get_internal_phy_settings - Retrieves the internal PHY settings
* @pm8001_ha : our adapter
* @phycfg : PHY config page to populate
*/
@@ -809,7 +810,7 @@ void pm8001_get_internal_phy_settings(struct pm8001_hba_info *pm8001_ha,
}
/**
- * pm8001_get_external_phy_settings : Retrieves the external PHY settings
+ * pm8001_get_external_phy_settings - Retrieves the external PHY settings
* @pm8001_ha : our adapter
* @phycfg : PHY config page to populate
*/
@@ -829,7 +830,7 @@ void pm8001_get_external_phy_settings(struct pm8001_hba_info *pm8001_ha,
}
/**
- * pm8001_get_phy_mask : Retrieves the mask that denotes if a PHY is int/ext
+ * pm8001_get_phy_mask - Retrieves the mask that denotes if a PHY is int/ext
* @pm8001_ha : our adapter
* @phymask : The PHY mask
*/
@@ -867,7 +868,7 @@ void pm8001_get_phy_mask(struct pm8001_hba_info *pm8001_ha, int *phymask)
}
/**
- * pm8001_set_phy_settings_ven_117c_12G() : Configure ATTO 12Gb PHY settings
+ * pm8001_set_phy_settings_ven_117c_12G() - Configure ATTO 12Gb PHY settings
* @pm8001_ha : our adapter
*/
static
@@ -902,7 +903,7 @@ int pm8001_set_phy_settings_ven_117c_12G(struct pm8001_hba_info *pm8001_ha)
}
/**
- * pm8001_configure_phy_settings : Configures PHY settings based on vendor ID.
+ * pm8001_configure_phy_settings - Configures PHY settings based on vendor ID.
* @pm8001_ha : our hba.
*/
static int pm8001_configure_phy_settings(struct pm8001_hba_info *pm8001_ha)
@@ -1052,8 +1053,8 @@ intx:
* @ent: pci device id
*
* This function is the main initialization function, when register a new
- * pci driver it is invoked, all struct an hardware initilization should be done
- * here, also, register interrupt
+ * pci driver it is invoked, all struct and hardware initialization should be
+ * done here, also, register interrupt.
*/
static int pm8001_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -1171,10 +1172,11 @@ err_out_enable:
return rc;
}
-/*
+/**
* pm8001_init_ccb_tag - allocate memory to CCB and tag.
* @pm8001_ha: our hba card information.
* @shost: scsi host which has been allocated outside.
+ * @pdev: pci device.
*/
static int
pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha, struct Scsi_Host *shost,
@@ -1269,7 +1271,7 @@ static void pm8001_pci_remove(struct pci_dev *pdev)
* pm8001_pci_suspend - power management suspend main entry point
* @dev: Device struct
*
- * Returns 0 success, anything else error.
+ * Return: 0 on success, anything else on error.
*/
static int __maybe_unused pm8001_pci_suspend(struct device *dev)
{
@@ -1314,7 +1316,7 @@ static int __maybe_unused pm8001_pci_suspend(struct device *dev)
* pm8001_pci_resume - power management resume main entry point
* @dev: Device struct
*
- * Returns 0 success, anything else error.
+ * Return: 0 on success, anything else on error.
*/
static int __maybe_unused pm8001_pci_resume(struct device *dev)
{
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index 335cf37e6cb9..48548a95327b 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -98,14 +98,16 @@ void pm8001_tag_init(struct pm8001_hba_info *pm8001_ha)
pm8001_tag_free(pm8001_ha, i);
}
- /**
- * pm8001_mem_alloc - allocate memory for pm8001.
- * @pdev: pci device.
- * @virt_addr: the allocated virtual address
- * @pphys_addr_hi: the physical address high byte address.
- * @pphys_addr_lo: the physical address low byte address.
- * @mem_size: memory size.
- */
+/**
+ * pm8001_mem_alloc - allocate memory for pm8001.
+ * @pdev: pci device.
+ * @virt_addr: the allocated virtual address
+ * @pphys_addr: DMA address for this device
+ * @pphys_addr_hi: the physical address high byte address.
+ * @pphys_addr_lo: the physical address low byte address.
+ * @mem_size: memory size.
+ * @align: requested byte alignment
+ */
int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr,
dma_addr_t *pphys_addr, u32 *pphys_addr_hi,
u32 *pphys_addr_lo, u32 mem_size, u32 align)
@@ -118,10 +120,8 @@ int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr,
align_offset = (dma_addr_t)align - 1;
mem_virt_alloc = dma_alloc_coherent(&pdev->dev, mem_size + align,
&mem_dma_handle, GFP_KERNEL);
- if (!mem_virt_alloc) {
- pr_err("pm80xx: memory allocation error\n");
- return -1;
- }
+ if (!mem_virt_alloc)
+ return -ENOMEM;
*pphys_addr = mem_dma_handle;
phys_align = (*pphys_addr + align_offset) & ~align_offset;
*virt_addr = (void *)mem_virt_alloc + phys_align - *pphys_addr;
@@ -341,7 +341,7 @@ static int pm8001_task_prep_ssp_tm(struct pm8001_hba_info *pm8001_ha,
}
/**
- * pm8001_task_prep_ssp - the dispatcher function,prepare ssp data for ssp task
+ * pm8001_task_prep_ssp - the dispatcher function, prepare ssp data for ssp task
* @pm8001_ha: our hba card information
* @ccb: the ccb which attached to ssp task
*/
@@ -556,10 +556,10 @@ void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha,
pm8001_tag_free(pm8001_ha, ccb_idx);
}
- /**
- * pm8001_alloc_dev - find a empty pm8001_device
- * @pm8001_ha: our hba card information
- */
+/**
+ * pm8001_alloc_dev - find a empty pm8001_device
+ * @pm8001_ha: our hba card information
+ */
static struct pm8001_device *pm8001_alloc_dev(struct pm8001_hba_info *pm8001_ha)
{
u32 dev;
@@ -707,7 +707,7 @@ static void pm8001_tmf_timedout(struct timer_list *t)
* @parameter: ssp task parameter.
*
* when errors or exception happened, we may want to do something, for example
- * abort the issued task which result in this execption, it is done by calling
+ * abort the issued task which result in this exception, it is done by calling
* this function, note it is also with the task execute interface.
*/
static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
@@ -758,7 +758,7 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
}
if (task->task_status.resp == SAS_TASK_COMPLETE &&
- task->task_status.stat == SAM_STAT_GOOD) {
+ task->task_status.stat == SAS_SAM_STAT_GOOD) {
res = TMF_RESP_FUNC_COMPLETE;
break;
}
@@ -843,7 +843,7 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha,
}
if (task->task_status.resp == SAS_TASK_COMPLETE &&
- task->task_status.stat == SAM_STAT_GOOD) {
+ task->task_status.stat == SAS_SAM_STAT_GOOD) {
res = TMF_RESP_FUNC_COMPLETE;
break;
@@ -986,11 +986,12 @@ void pm8001_open_reject_retry(
}
/**
- * pm8001_I_T_nexus_reset()
- * Standard mandates link reset for ATA (type 0) and hard reset for
- * SSP (type 1) , only for RECOVERY
- * @dev: the device structure for the device to reset.
- */
+ * pm8001_I_T_nexus_reset() - reset the initiator/target connection
+ * @dev: the device structure for the device to reset.
+ *
+ * Standard mandates link reset for ATA (type 0) and hard reset for
+ * SSP (type 1), only for RECOVERY
+ */
int pm8001_I_T_nexus_reset(struct domain_device *dev)
{
int rc = TMF_RESP_FUNC_FAILED;
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 700530e969ac..6ffe17b849ae 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -140,7 +140,7 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
pm8001_ha->fatal_bar_loc = 0;
}
- /* Read until accum_len is retrived */
+ /* Read until accum_len is retrieved */
accum_len = pm8001_mr32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_ACCUM_LEN);
/* Determine length of data between previously stored transfer length
@@ -1011,7 +1011,7 @@ static int mpi_init_check(struct pm8001_hba_info *pm8001_ha)
value);
return -EBUSY;
}
- /* check the MPI-State for initialization upto 100ms*/
+ /* check the MPI-State for initialization up to 100ms*/
max_wait_count = 5;/* 100 msec */
do {
msleep(FW_READY_INTERVAL);
@@ -1093,7 +1093,7 @@ static int init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
- /**
+ /*
* lower 26 bits of SCRATCHPAD0 register describes offset within the
* PCIe BAR where the MPI configuration table is present
*/
@@ -1101,7 +1101,7 @@ static int init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
pm8001_dbg(pm8001_ha, DEV, "Scratchpad 0 Offset: 0x%x value 0x%x\n",
offset, value);
- /**
+ /*
* Upper 6 bits describe the offset within PCI config space where BAR
* is located.
*/
@@ -1109,7 +1109,7 @@ static int init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
pcibar = get_pci_bar_index(pcilogic);
pm8001_dbg(pm8001_ha, INIT, "Scratchpad 0 PCI BAR: %d\n", pcibar);
- /**
+ /*
* Make sure the offset falls inside the ioremapped PCI BAR
*/
if (offset > pm8001_ha->io_mem[pcibar].memsize) {
@@ -1121,7 +1121,7 @@ static int init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->main_cfg_tbl_addr = base_addr =
pm8001_ha->io_mem[pcibar].memvirtaddr + offset;
- /**
+ /*
* Validate main configuration table address: first DWord should read
* "PMCS"
*/
@@ -1385,7 +1385,7 @@ pm80xx_get_encrypt_info(struct pm8001_hba_info *pm8001_ha)
}
/**
- * pm80xx_encrypt_update - update flash with encryption informtion
+ * pm80xx_encrypt_update - update flash with encryption information
* @pm8001_ha: our hba card information.
*/
static int pm80xx_encrypt_update(struct pm8001_hba_info *pm8001_ha)
@@ -1422,7 +1422,7 @@ static int pm80xx_encrypt_update(struct pm8001_hba_info *pm8001_ha)
}
/**
- * pm80xx_chip_init - the main init function that initialize whole PM8001 chip.
+ * pm80xx_chip_init - the main init function that initializes whole PM8001 chip.
* @pm8001_ha: our hba card information
*/
static int pm80xx_chip_init(struct pm8001_hba_info *pm8001_ha)
@@ -1541,7 +1541,7 @@ static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha)
}
/**
- * pm80xx_fatal_errors - returns non zero *ONLY* when fatal errors
+ * pm80xx_fatal_errors - returns non-zero *ONLY* when fatal errors
* @pm8001_ha: our hba card information
*
* Fatal errors are recoverable only after a host reboot.
@@ -1576,8 +1576,8 @@ pm80xx_fatal_errors(struct pm8001_hba_info *pm8001_ha)
}
/**
- * pm80xx_chip_soft_rst - soft reset the PM8001 chip, so that the clear all
- * the FW register status to the originated status.
+ * pm80xx_chip_soft_rst - soft reset the PM8001 chip, so that all
+ * FW register status are reset to the originated status.
* @pm8001_ha: our hba card information
*/
@@ -1895,13 +1895,13 @@ static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha,
}
/**
- * mpi_ssp_completion- process the event that FW response to the SSP request.
+ * mpi_ssp_completion - process the event that FW response to the SSP request.
* @pm8001_ha: our hba card information
* @piomb: the message contents of this outbound message.
*
* When FW has completed a ssp request for example a IO request, after it has
- * filled the SG data with the data, it will trigger this event represent
- * that he has finished the job,please check the coresponding buffer.
+ * filled the SG data with the data, it will trigger this event representing
+ * that he has finished the job; please check the corresponding buffer.
* So we will tell the caller who maybe waiting the result to tell upper layer
* that the task has been finished.
*/
@@ -1952,7 +1952,7 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
param);
if (param == 0) {
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
} else {
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_PROTO_RESPONSE;
@@ -2487,7 +2487,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n");
if (param == 0) {
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
/* check if response is for SEND READ LOG */
if (pm8001_dev &&
(pm8001_dev->id & NCQ_READ_LOG_FLAG)) {
@@ -3042,7 +3042,7 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
case IO_SUCCESS:
pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n");
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
if (pm8001_ha->smp_exp_mode == SMP_DIRECT) {
@@ -3084,17 +3084,17 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
case IO_ERROR_HW_TIMEOUT:
pm8001_dbg(pm8001_ha, IO, "IO_ERROR_HW_TIMEOUT\n");
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_BUSY;
+ ts->stat = SAS_SAM_STAT_BUSY;
break;
case IO_XFER_ERROR_BREAK:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_BUSY;
+ ts->stat = SAS_SAM_STAT_BUSY;
break;
case IO_XFER_ERROR_PHY_NOT_READY:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_BUSY;
+ ts->stat = SAS_SAM_STAT_BUSY;
break;
case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
pm8001_dbg(pm8001_ha, IO,
@@ -3217,7 +3217,7 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
}
/**
- * pm80xx_hw_event_ack_req- For PM8001,some events need to acknowage to FW.
+ * pm80xx_hw_event_ack_req- For PM8001, some events need to acknowledge to FW.
* @pm8001_ha: our hba card information
* @Qnum: the outbound queue message number.
* @SEA: source of event to ack
@@ -3275,7 +3275,7 @@ static void hw_event_port_recover(struct pm8001_hba_info *pm8001_ha,
}
/**
- * hw_event_sas_phy_up -FW tells me a SAS phy up event.
+ * hw_event_sas_phy_up - FW tells me a SAS phy up event.
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
@@ -3353,7 +3353,7 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
}
/**
- * hw_event_sata_phy_up -FW tells me a SATA phy up event.
+ * hw_event_sata_phy_up - FW tells me a SATA phy up event.
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
@@ -3400,7 +3400,7 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
}
/**
- * hw_event_phy_down -we should notify the libsas the phy is down.
+ * hw_event_phy_down - we should notify the libsas the phy is down.
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
@@ -3500,7 +3500,7 @@ static int mpi_phy_start_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
}
/**
- * mpi_thermal_hw_event -The hw event has come.
+ * mpi_thermal_hw_event - a thermal hw event has come.
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
@@ -3530,7 +3530,7 @@ static int mpi_thermal_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
}
/**
- * mpi_hw_event -The hw event has come.
+ * mpi_hw_event - The hw event has come.
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
@@ -4025,7 +4025,7 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
case OPC_OUB_SET_DEV_INFO:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEV_INFO\n");
break;
- /* spcv specifc commands */
+ /* spcv specific commands */
case OPC_OUB_PHY_START_RESP:
pm8001_dbg(pm8001_ha, MSG,
"OPC_OUB_PHY_START_RESP opcode:%x\n", opc);
@@ -4186,7 +4186,7 @@ static void build_smp_cmd(u32 deviceID, __le32 hTag,
}
/**
- * pm80xx_chip_smp_req - send a SMP task to FW
+ * pm80xx_chip_smp_req - send an SMP task to FW
* @pm8001_ha: our hba card information.
* @ccb: the ccb information this request used.
*/
@@ -4346,7 +4346,7 @@ static int check_enc_sat_cmd(struct sas_task *task)
}
/**
- * pm80xx_chip_ssp_io_req - send a SSP task to FW
+ * pm80xx_chip_ssp_io_req - send an SSP task to FW
* @pm8001_ha: our hba card information.
* @ccb: the ccb information this request used.
*/
@@ -4699,7 +4699,7 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
spin_lock_irqsave(&task->task_state_lock, flags);
ts->resp = SAS_TASK_COMPLETE;
- ts->stat = SAM_STAT_GOOD;
+ ts->stat = SAS_SAM_STAT_GOOD;
task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
task->task_state_flags |= SAS_TASK_STATE_DONE;
@@ -4750,13 +4750,13 @@ pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id)
payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE |
LINKMODE_AUTO | pm8001_ha->link_rate | phy_id);
/* SSC Disable and SAS Analog ST configuration */
- /**
+ /*
payload.ase_sh_lm_slr_phyid =
cpu_to_le32(SSC_DISABLE_30 | SAS_ASE | SPINHOLD_DISABLE |
LINKMODE_AUTO | LINKRATE_15 | LINKRATE_30 | LINKRATE_60 |
phy_id);
Have to add "SAS PHY Analog Setup SPASTI 1 Byte" Based on need
- **/
+ */
payload.sas_identify.dev_type = SAS_END_DEVICE;
payload.sas_identify.initiator_bits = SAS_PROTOCOL_ALL;
diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h
index 6d36debde18e..bbb75318f1e7 100644
--- a/drivers/scsi/pmcraid.h
+++ b/drivers/scsi/pmcraid.h
@@ -47,8 +47,8 @@
/*
* MAX_CMD : maximum commands that can be outstanding with IOA
* MAX_IO_CMD : command blocks available for IO commands
- * MAX_HCAM_CMD : command blocks avaibale for HCAMS
- * MAX_INTERNAL_CMD : command blocks avaible for internal commands like reset
+ * MAX_HCAM_CMD : command blocks available for HCAMS
+ * MAX_INTERNAL_CMD : command blocks available for internal commands like reset
*/
#define PMCRAID_MAX_CMD 1024
#define PMCRAID_MAX_IO_CMD 1020
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index aa41f7ac91cb..977315fdc254 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -1148,18 +1148,6 @@ static struct parport_driver ppa_driver = {
.detach = ppa_detach,
.devmodel = true,
};
+module_parport_driver(ppa_driver);
-static int __init ppa_driver_init(void)
-{
- printk(KERN_INFO "ppa: Version %s\n", PPA_VERSION);
- return parport_register_driver(&ppa_driver);
-}
-
-static void __exit ppa_driver_exit(void)
-{
- parport_unregister_driver(&ppa_driver);
-}
-
-module_init(ppa_driver_init);
-module_exit(ppa_driver_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c
index ccb5771f1cb7..0f4b99d92f12 100644
--- a/drivers/scsi/ps3rom.c
+++ b/drivers/scsi/ps3rom.c
@@ -234,10 +234,8 @@ static int ps3rom_queuecommand_lck(struct scsi_cmnd *cmd,
}
if (res) {
- memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ scsi_build_sense(cmd, 0, ILLEGAL_REQUEST, 0, 0);
cmd->result = res;
- cmd->sense_buffer[0] = 0x70;
- cmd->sense_buffer[2] = ILLEGAL_REQUEST;
priv->curr_cmd = NULL;
cmd->scsi_done(cmd);
}
@@ -319,8 +317,7 @@ static irqreturn_t ps3rom_interrupt(int irq, void *data)
goto done;
}
- scsi_build_sense_buffer(0, cmd->sense_buffer, sense_key, asc, ascq);
- cmd->result = SAM_STAT_CHECK_CONDITION;
+ scsi_build_sense(cmd, 0, sense_key, asc, ascq);
done:
priv->curr_cmd = NULL;
diff --git a/drivers/scsi/qedf/qedf_attr.c b/drivers/scsi/qedf/qedf_attr.c
index d995f72a6759..461c0c9180c4 100644
--- a/drivers/scsi/qedf/qedf_attr.c
+++ b/drivers/scsi/qedf/qedf_attr.c
@@ -24,9 +24,8 @@ static struct qedf_ctx *qedf_get_base_qedf(struct qedf_ctx *qedf)
return lport_priv(base_lport);
}
-static ssize_t
-qedf_fcoe_mac_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t fcoe_mac_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct fc_lport *lport = shost_priv(class_to_shost(dev));
u32 port_id;
@@ -42,9 +41,8 @@ qedf_fcoe_mac_show(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%pM\n", fcoe_mac);
}
-static ssize_t
-qedf_fka_period_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t fka_period_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct fc_lport *lport = shost_priv(class_to_shost(dev));
struct qedf_ctx *qedf = lport_priv(lport);
@@ -59,8 +57,8 @@ qedf_fka_period_show(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%d\n", fka_period);
}
-static DEVICE_ATTR(fcoe_mac, S_IRUGO, qedf_fcoe_mac_show, NULL);
-static DEVICE_ATTR(fka_period, S_IRUGO, qedf_fka_period_show, NULL);
+static DEVICE_ATTR_RO(fcoe_mac);
+static DEVICE_ATTR_RO(fka_period);
struct device_attribute *qedf_host_attrs[] = {
&dev_attr_fcoe_mac,
diff --git a/drivers/scsi/qedf/qedf_dbg.c b/drivers/scsi/qedf/qedf_dbg.c
index e0387e495261..0d2aed82882a 100644
--- a/drivers/scsi/qedf/qedf_dbg.c
+++ b/drivers/scsi/qedf/qedf_dbg.c
@@ -106,11 +106,10 @@ ret:
int
qedf_alloc_grc_dump_buf(u8 **buf, uint32_t len)
{
- *buf = vmalloc(len);
+ *buf = vzalloc(len);
if (!(*buf))
return -ENOMEM;
- memset(*buf, 0, len);
return 0;
}
diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c
index 4869ef813dc4..6b5b6a75ac88 100644
--- a/drivers/scsi/qedf/qedf_io.c
+++ b/drivers/scsi/qedf/qedf_io.c
@@ -23,11 +23,6 @@ static void qedf_cmd_timeout(struct work_struct *work)
struct qedf_ctx *qedf;
struct qedf_rport *fcport;
- if (io_req == NULL) {
- QEDF_INFO(NULL, QEDF_LOG_IO, "io_req is NULL.\n");
- return;
- }
-
fcport = io_req->fcport;
if (io_req->fcport == NULL) {
QEDF_INFO(NULL, QEDF_LOG_IO, "fcport is NULL.\n");
@@ -1520,9 +1515,19 @@ void qedf_process_error_detect(struct qedf_ctx *qedf, struct fcoe_cqe *cqe,
{
int rval;
+ if (io_req == NULL) {
+ QEDF_INFO(NULL, QEDF_LOG_IO, "io_req is NULL.\n");
+ return;
+ }
+
+ if (io_req->fcport == NULL) {
+ QEDF_INFO(NULL, QEDF_LOG_IO, "fcport is NULL.\n");
+ return;
+ }
+
if (!cqe) {
QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
- "cqe is NULL for io_req %p\n", io_req);
+ "cqe is NULL for io_req %p\n", io_req);
return;
}
@@ -1538,6 +1543,16 @@ void qedf_process_error_detect(struct qedf_ctx *qedf, struct fcoe_cqe *cqe,
le32_to_cpu(cqe->cqe_info.err_info.rx_buf_off),
le32_to_cpu(cqe->cqe_info.err_info.rx_id));
+ /* When flush is active, let the cmds be flushed out from the cleanup context */
+ if (test_bit(QEDF_RPORT_IN_TARGET_RESET, &io_req->fcport->flags) ||
+ (test_bit(QEDF_RPORT_IN_LUN_RESET, &io_req->fcport->flags) &&
+ io_req->sc_cmd->device->lun == (u64)io_req->fcport->lun_reset_lun)) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Dropping EQE for xid=0x%x as fcport is flushing",
+ io_req->xid);
+ return;
+ }
+
if (qedf->stop_io_on_error) {
qedf_stop_all_io(qedf);
return;
diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c
index b92570a7c309..85f41abcb56c 100644
--- a/drivers/scsi/qedf/qedf_main.c
+++ b/drivers/scsi/qedf/qedf_main.c
@@ -1717,6 +1717,9 @@ static void qedf_setup_fdmi(struct qedf_ctx *qedf)
FW_MAJOR_VERSION, FW_MINOR_VERSION, FW_REVISION_VERSION,
FW_ENGINEERING_VERSION);
+ snprintf(fc_host_vendor_identifier(lport->host),
+ FC_VENDOR_IDENTIFIER, "%s", "Marvell");
+
}
static int qedf_lport_setup(struct qedf_ctx *qedf)
@@ -1877,6 +1880,7 @@ static int qedf_vport_create(struct fc_vport *vport, bool disabled)
vn_port->host->max_lun = qedf_max_lun;
vn_port->host->sg_tablesize = QEDF_MAX_BDS_PER_CMD;
vn_port->host->max_cmd_len = QEDF_MAX_CDB_LEN;
+ vn_port->host->max_id = QEDF_MAX_SESSIONS;
rc = scsi_add_host(vn_port->host, &vport->dev);
if (rc) {
@@ -3528,6 +3532,7 @@ retry_probe:
host->transportt = qedf_fc_transport_template;
host->max_lun = qedf_max_lun;
host->max_cmd_len = QEDF_MAX_CDB_LEN;
+ host->max_id = QEDF_MAX_SESSIONS;
host->can_queue = FCOE_PARAMS_NUM_TASKS;
rc = scsi_add_host(host, &pdev->dev);
if (rc) {
@@ -3971,10 +3976,6 @@ void qedf_stag_change_work(struct work_struct *work)
struct qedf_ctx *qedf =
container_of(work, struct qedf_ctx, stag_work.work);
- if (!qedf) {
- QEDF_ERR(NULL, "qedf is NULL");
- return;
- }
QEDF_ERR(&qedf->dbg_ctx, "Performing software context reset.\n");
qedf_ctx_soft_reset(qedf->lport);
}
diff --git a/drivers/scsi/qedi/qedi.h b/drivers/scsi/qedi/qedi.h
index c342defc3f52..ce199a7a16b8 100644
--- a/drivers/scsi/qedi/qedi.h
+++ b/drivers/scsi/qedi/qedi.h
@@ -284,6 +284,7 @@ struct qedi_ctx {
#define QEDI_IN_RECOVERY 5
#define QEDI_IN_OFFLINE 6
#define QEDI_IN_SHUTDOWN 7
+#define QEDI_BLOCK_IO 8
u8 mac[ETH_ALEN];
u32 src_ip[4];
diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c
index 440ddd2309f1..71333d3c5c86 100644
--- a/drivers/scsi/qedi/qedi_fw.c
+++ b/drivers/scsi/qedi/qedi_fw.c
@@ -14,8 +14,8 @@
#include "qedi_fw_iscsi.h"
#include "qedi_fw_scsi.h"
-static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
- struct iscsi_task *mtask);
+static int send_iscsi_tmf(struct qedi_conn *qedi_conn,
+ struct iscsi_task *mtask, struct iscsi_task *ctask);
void qedi_iscsi_unmap_sg_list(struct qedi_cmd *cmd)
{
@@ -73,7 +73,6 @@ static void qedi_process_logout_resp(struct qedi_ctx *qedi,
spin_unlock(&qedi_conn->list_lock);
cmd->state = RESPONSE_RECEIVED;
- qedi_clear_task_idx(qedi, cmd->task_id);
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
spin_unlock(&session->back_lock);
@@ -138,7 +137,6 @@ static void qedi_process_text_resp(struct qedi_ctx *qedi,
spin_unlock(&qedi_conn->list_lock);
cmd->state = RESPONSE_RECEIVED;
- qedi_clear_task_idx(qedi, cmd->task_id);
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr,
qedi_conn->gen_pdu.resp_buf,
@@ -158,19 +156,11 @@ static void qedi_tmf_resp_work(struct work_struct *work)
struct iscsi_tm_rsp *resp_hdr_ptr;
int rval = 0;
- set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
resp_hdr_ptr = (struct iscsi_tm_rsp *)qedi_cmd->tmf_resp_buf;
- iscsi_block_session(session->cls_session);
rval = qedi_cleanup_all_io(qedi, qedi_conn, qedi_cmd->task, true);
- if (rval) {
- qedi_clear_task_idx(qedi, qedi_cmd->task_id);
- iscsi_unblock_session(session->cls_session);
+ if (rval)
goto exit_tmf_resp;
- }
-
- iscsi_unblock_session(session->cls_session);
- qedi_clear_task_idx(qedi, qedi_cmd->task_id);
spin_lock(&session->back_lock);
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr, NULL, 0);
@@ -178,7 +168,10 @@ static void qedi_tmf_resp_work(struct work_struct *work)
exit_tmf_resp:
kfree(resp_hdr_ptr);
- clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
+
+ spin_lock(&qedi_conn->tmf_work_lock);
+ qedi_conn->fw_cleanup_works--;
+ spin_unlock(&qedi_conn->tmf_work_lock);
}
static void qedi_process_tmf_resp(struct qedi_ctx *qedi,
@@ -234,18 +227,25 @@ static void qedi_process_tmf_resp(struct qedi_ctx *qedi,
}
spin_unlock(&qedi_conn->list_lock);
- if (((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
- ISCSI_TM_FUNC_LOGICAL_UNIT_RESET) ||
- ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
- ISCSI_TM_FUNC_TARGET_WARM_RESET) ||
- ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
- ISCSI_TM_FUNC_TARGET_COLD_RESET)) {
+ spin_lock(&qedi_conn->tmf_work_lock);
+ switch (tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) {
+ case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET:
+ case ISCSI_TM_FUNC_TARGET_WARM_RESET:
+ case ISCSI_TM_FUNC_TARGET_COLD_RESET:
+ if (qedi_conn->ep_disconnect_starting) {
+ /* Session is down so ep_disconnect will clean up */
+ spin_unlock(&qedi_conn->tmf_work_lock);
+ goto unblock_sess;
+ }
+
+ qedi_conn->fw_cleanup_works++;
+ spin_unlock(&qedi_conn->tmf_work_lock);
+
INIT_WORK(&qedi_cmd->tmf_work, qedi_tmf_resp_work);
queue_work(qedi->tmf_thread, &qedi_cmd->tmf_work);
goto unblock_sess;
}
-
- qedi_clear_task_idx(qedi, qedi_cmd->task_id);
+ spin_unlock(&qedi_conn->tmf_work_lock);
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr, NULL, 0);
kfree(resp_hdr_ptr);
@@ -314,7 +314,6 @@ static void qedi_process_login_resp(struct qedi_ctx *qedi,
"Freeing tid=0x%x for cid=0x%x\n",
cmd->task_id, qedi_conn->iscsi_conn_id);
cmd->state = RESPONSE_RECEIVED;
- qedi_clear_task_idx(qedi, cmd->task_id);
}
static void qedi_get_rq_bdq_buf(struct qedi_ctx *qedi,
@@ -468,7 +467,6 @@ static int qedi_process_nopin_mesg(struct qedi_ctx *qedi,
}
spin_unlock(&qedi_conn->list_lock);
- qedi_clear_task_idx(qedi, cmd->task_id);
}
done:
@@ -673,7 +671,6 @@ static void qedi_scsi_completion(struct qedi_ctx *qedi,
if (qedi_io_tracing)
qedi_trace_io(qedi, task, cmd->task_id, QEDI_IO_TRACE_RSP);
- qedi_clear_task_idx(qedi, cmd->task_id);
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
conn->data, datalen);
error:
@@ -730,7 +727,6 @@ static void qedi_process_nopin_local_cmpl(struct qedi_ctx *qedi,
cqe->itid, cmd->task_id);
cmd->state = RESPONSE_RECEIVED;
- qedi_clear_task_idx(qedi, cmd->task_id);
spin_lock_bh(&session->back_lock);
__iscsi_put_task(task);
@@ -739,20 +735,17 @@ static void qedi_process_nopin_local_cmpl(struct qedi_ctx *qedi,
static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
struct iscsi_cqe_solicited *cqe,
- struct iscsi_task *task,
struct iscsi_conn *conn)
{
struct qedi_work_map *work, *work_tmp;
u32 proto_itt = cqe->itid;
- u32 ptmp_itt = 0;
itt_t protoitt = 0;
int found = 0;
struct qedi_cmd *qedi_cmd = NULL;
- u32 rtid = 0;
u32 iscsi_cid;
struct qedi_conn *qedi_conn;
struct qedi_cmd *dbg_cmd;
- struct iscsi_task *mtask;
+ struct iscsi_task *mtask, *task;
struct iscsi_tm *tmf_hdr = NULL;
iscsi_cid = cqe->conn_id;
@@ -778,93 +771,64 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
}
found = 1;
mtask = qedi_cmd->task;
+ task = work->ctask;
tmf_hdr = (struct iscsi_tm *)mtask->hdr;
- rtid = work->rtid;
list_del_init(&work->list);
kfree(work);
qedi_cmd->list_tmf_work = NULL;
}
}
- spin_unlock_bh(&qedi_conn->tmf_work_lock);
-
- if (found) {
- QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
- "TMF work, cqe->tid=0x%x, tmf flags=0x%x, cid=0x%x\n",
- proto_itt, tmf_hdr->flags, qedi_conn->iscsi_conn_id);
-
- if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
- ISCSI_TM_FUNC_ABORT_TASK) {
- spin_lock_bh(&conn->session->back_lock);
-
- protoitt = build_itt(get_itt(tmf_hdr->rtt),
- conn->session->age);
- task = iscsi_itt_to_task(conn, protoitt);
-
- spin_unlock_bh(&conn->session->back_lock);
-
- if (!task) {
- QEDI_NOTICE(&qedi->dbg_ctx,
- "IO task completed, tmf rtt=0x%x, cid=0x%x\n",
- get_itt(tmf_hdr->rtt),
- qedi_conn->iscsi_conn_id);
- return;
- }
-
- dbg_cmd = task->dd_data;
- QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
- "Abort tmf rtt=0x%x, i/o itt=0x%x, i/o tid=0x%x, cid=0x%x\n",
- get_itt(tmf_hdr->rtt), get_itt(task->itt),
- dbg_cmd->task_id, qedi_conn->iscsi_conn_id);
+ if (!found) {
+ spin_unlock_bh(&qedi_conn->tmf_work_lock);
+ goto check_cleanup_reqs;
+ }
- if (qedi_cmd->state == CLEANUP_WAIT_FAILED)
- qedi_cmd->state = CLEANUP_RECV;
+ QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
+ "TMF work, cqe->tid=0x%x, tmf flags=0x%x, cid=0x%x\n",
+ proto_itt, tmf_hdr->flags, qedi_conn->iscsi_conn_id);
+
+ spin_lock_bh(&conn->session->back_lock);
+ if (iscsi_task_is_completed(task)) {
+ QEDI_NOTICE(&qedi->dbg_ctx,
+ "IO task completed, tmf rtt=0x%x, cid=0x%x\n",
+ get_itt(tmf_hdr->rtt), qedi_conn->iscsi_conn_id);
+ goto unlock;
+ }
- qedi_clear_task_idx(qedi_conn->qedi, rtid);
+ dbg_cmd = task->dd_data;
- spin_lock(&qedi_conn->list_lock);
- if (likely(dbg_cmd->io_cmd_in_list)) {
- dbg_cmd->io_cmd_in_list = false;
- list_del_init(&dbg_cmd->io_cmd);
- qedi_conn->active_cmd_count--;
- }
- spin_unlock(&qedi_conn->list_lock);
- qedi_cmd->state = CLEANUP_RECV;
- wake_up_interruptible(&qedi_conn->wait_queue);
- }
- } else if (qedi_conn->cmd_cleanup_req > 0) {
- spin_lock_bh(&conn->session->back_lock);
- qedi_get_proto_itt(qedi, cqe->itid, &ptmp_itt);
- protoitt = build_itt(ptmp_itt, conn->session->age);
- task = iscsi_itt_to_task(conn, protoitt);
- QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
- "cleanup io itid=0x%x, protoitt=0x%x, cmd_cleanup_cmpl=%d, cid=0x%x\n",
- cqe->itid, protoitt, qedi_conn->cmd_cleanup_cmpl,
- qedi_conn->iscsi_conn_id);
+ QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
+ "Abort tmf rtt=0x%x, i/o itt=0x%x, i/o tid=0x%x, cid=0x%x\n",
+ get_itt(tmf_hdr->rtt), get_itt(task->itt), dbg_cmd->task_id,
+ qedi_conn->iscsi_conn_id);
- spin_unlock_bh(&conn->session->back_lock);
- if (!task) {
- QEDI_NOTICE(&qedi->dbg_ctx,
- "task is null, itid=0x%x, cid=0x%x\n",
- cqe->itid, qedi_conn->iscsi_conn_id);
- return;
- }
- qedi_conn->cmd_cleanup_cmpl++;
- wake_up(&qedi_conn->wait_queue);
+ spin_lock(&qedi_conn->list_lock);
+ if (likely(dbg_cmd->io_cmd_in_list)) {
+ dbg_cmd->io_cmd_in_list = false;
+ list_del_init(&dbg_cmd->io_cmd);
+ qedi_conn->active_cmd_count--;
+ }
+ spin_unlock(&qedi_conn->list_lock);
+ qedi_cmd->state = CLEANUP_RECV;
+unlock:
+ spin_unlock_bh(&conn->session->back_lock);
+ spin_unlock_bh(&qedi_conn->tmf_work_lock);
+ wake_up_interruptible(&qedi_conn->wait_queue);
+ return;
+check_cleanup_reqs:
+ if (qedi_conn->cmd_cleanup_req > 0) {
QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
"Freeing tid=0x%x for cid=0x%x\n",
cqe->itid, qedi_conn->iscsi_conn_id);
- qedi_clear_task_idx(qedi_conn->qedi, cqe->itid);
-
+ qedi_conn->cmd_cleanup_cmpl++;
+ wake_up(&qedi_conn->wait_queue);
} else {
- qedi_get_proto_itt(qedi, cqe->itid, &ptmp_itt);
- protoitt = build_itt(ptmp_itt, conn->session->age);
- task = iscsi_itt_to_task(conn, protoitt);
QEDI_ERR(&qedi->dbg_ctx,
- "Delayed or untracked cleanup response, itt=0x%x, tid=0x%x, cid=0x%x, task=%p\n",
- protoitt, cqe->itid, qedi_conn->iscsi_conn_id, task);
+ "Delayed or untracked cleanup response, itt=0x%x, tid=0x%x, cid=0x%x\n",
+ protoitt, cqe->itid, qedi_conn->iscsi_conn_id);
}
}
@@ -959,8 +923,7 @@ void qedi_fp_process_cqes(struct qedi_work *work)
goto exit_fp_process;
case ISCSI_CQE_TYPE_TASK_CLEANUP:
QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, "CleanUp CqE\n");
- qedi_process_cmd_cleanup_resp(qedi, &cqe->cqe_solicited, task,
- conn);
+ qedi_process_cmd_cleanup_resp(qedi, &cqe->cqe_solicited, conn);
goto exit_fp_process;
default:
QEDI_ERR(&qedi->dbg_ctx, "Error cqe.\n");
@@ -1368,7 +1331,7 @@ static int qedi_wait_for_cleanup_request(struct qedi_ctx *qedi,
return 0;
}
-static void qedi_tmf_work(struct work_struct *work)
+static void qedi_abort_work(struct work_struct *work)
{
struct qedi_cmd *qedi_cmd =
container_of(work, struct qedi_cmd, tmf_work);
@@ -1381,17 +1344,29 @@ static void qedi_tmf_work(struct work_struct *work)
struct iscsi_task *ctask;
struct iscsi_tm *tmf_hdr;
s16 rval = 0;
- s16 tid = 0;
mtask = qedi_cmd->task;
tmf_hdr = (struct iscsi_tm *)mtask->hdr;
- set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
- ctask = iscsi_itt_to_task(conn, tmf_hdr->rtt);
- if (!ctask || !ctask->sc) {
- QEDI_ERR(&qedi->dbg_ctx, "Task already completed\n");
- goto abort_ret;
+ spin_lock_bh(&conn->session->back_lock);
+ ctask = iscsi_itt_to_ctask(conn, tmf_hdr->rtt);
+ if (!ctask) {
+ spin_unlock_bh(&conn->session->back_lock);
+ QEDI_ERR(&qedi->dbg_ctx, "Invalid RTT. Letting abort timeout.\n");
+ goto clear_cleanup;
+ }
+
+ if (iscsi_task_is_completed(ctask)) {
+ spin_unlock_bh(&conn->session->back_lock);
+ QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+ "Task already completed\n");
+ /*
+ * We have to still send the TMF because libiscsi needs the
+ * response to avoid a timeout.
+ */
+ goto send_tmf;
}
+ spin_unlock_bh(&conn->session->back_lock);
cmd = (struct qedi_cmd *)ctask->dd_data;
QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
@@ -1402,19 +1377,21 @@ static void qedi_tmf_work(struct work_struct *work)
if (qedi_do_not_recover) {
QEDI_ERR(&qedi->dbg_ctx, "DONT SEND CLEANUP/ABORT %d\n",
qedi_do_not_recover);
- goto abort_ret;
+ goto clear_cleanup;
}
- list_work = kzalloc(sizeof(*list_work), GFP_ATOMIC);
+ list_work = kzalloc(sizeof(*list_work), GFP_NOIO);
if (!list_work) {
QEDI_ERR(&qedi->dbg_ctx, "Memory allocation failed\n");
- goto abort_ret;
+ goto clear_cleanup;
}
qedi_cmd->type = TYPEIO;
+ qedi_cmd->state = CLEANUP_WAIT;
list_work->qedi_cmd = qedi_cmd;
list_work->rtid = cmd->task_id;
list_work->state = QEDI_WORK_SCHEDULED;
+ list_work->ctask = ctask;
qedi_cmd->list_tmf_work = list_work;
QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
@@ -1437,23 +1414,13 @@ static void qedi_tmf_work(struct work_struct *work)
goto ldel_exit;
}
- tid = qedi_get_task_idx(qedi);
- if (tid == -1) {
- QEDI_ERR(&qedi->dbg_ctx, "Invalid tid, cid=0x%x\n",
- qedi_conn->iscsi_conn_id);
- goto ldel_exit;
- }
-
- qedi_cmd->task_id = tid;
- qedi_send_iscsi_tmf(qedi_conn, qedi_cmd->task);
-
-abort_ret:
- clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
- return;
+send_tmf:
+ send_iscsi_tmf(qedi_conn, qedi_cmd->task, ctask);
+ goto clear_cleanup;
ldel_exit:
spin_lock_bh(&qedi_conn->tmf_work_lock);
- if (!qedi_cmd->list_tmf_work) {
+ if (qedi_cmd->list_tmf_work) {
list_del_init(&list_work->list);
qedi_cmd->list_tmf_work = NULL;
kfree(list_work);
@@ -1468,18 +1435,19 @@ ldel_exit:
}
spin_unlock(&qedi_conn->list_lock);
- clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
+clear_cleanup:
+ spin_lock(&qedi_conn->tmf_work_lock);
+ qedi_conn->fw_cleanup_works--;
+ spin_unlock(&qedi_conn->tmf_work_lock);
}
-static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
- struct iscsi_task *mtask)
+static int send_iscsi_tmf(struct qedi_conn *qedi_conn, struct iscsi_task *mtask,
+ struct iscsi_task *ctask)
{
struct iscsi_tmf_request_hdr tmf_pdu_header;
struct iscsi_task_params task_params;
struct qedi_ctx *qedi = qedi_conn->qedi;
struct e4_iscsi_task_context *fw_task_ctx;
- struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
- struct iscsi_task *ctask;
struct iscsi_tm *tmf_hdr;
struct qedi_cmd *qedi_cmd;
struct qedi_cmd *cmd;
@@ -1487,7 +1455,6 @@ static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
u32 scsi_lun[2];
s16 tid = 0;
u16 sq_idx = 0;
- int rval = 0;
tmf_hdr = (struct iscsi_tm *)mtask->hdr;
qedi_cmd = (struct qedi_cmd *)mtask->dd_data;
@@ -1520,12 +1487,6 @@ static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
ISCSI_TM_FUNC_ABORT_TASK) {
- ctask = iscsi_itt_to_task(conn, tmf_hdr->rtt);
- if (!ctask || !ctask->sc) {
- QEDI_ERR(&qedi->dbg_ctx,
- "Could not get reference task\n");
- return 0;
- }
cmd = (struct qedi_cmd *)ctask->dd_data;
tmf_pdu_header.rtt =
qedi_set_itt(cmd->task_id,
@@ -1551,10 +1512,7 @@ static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
task_params.sqe = &ep->sq[sq_idx];
memset(task_params.sqe, 0, sizeof(struct iscsi_wqe));
- rval = init_initiator_tmf_request_task(&task_params,
- &tmf_pdu_header);
- if (rval)
- return -1;
+ init_initiator_tmf_request_task(&task_params, &tmf_pdu_header);
spin_lock(&qedi_conn->list_lock);
list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
@@ -1566,47 +1524,34 @@ static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
return 0;
}
-int qedi_iscsi_abort_work(struct qedi_conn *qedi_conn,
- struct iscsi_task *mtask)
+int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, struct iscsi_task *mtask)
{
+ struct iscsi_tm *tmf_hdr = (struct iscsi_tm *)mtask->hdr;
+ struct qedi_cmd *qedi_cmd = mtask->dd_data;
struct qedi_ctx *qedi = qedi_conn->qedi;
- struct iscsi_tm *tmf_hdr;
- struct qedi_cmd *qedi_cmd = (struct qedi_cmd *)mtask->dd_data;
- s16 tid = 0;
+ int rc = 0;
- tmf_hdr = (struct iscsi_tm *)mtask->hdr;
- qedi_cmd->task = mtask;
+ switch (tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) {
+ case ISCSI_TM_FUNC_ABORT_TASK:
+ spin_lock(&qedi_conn->tmf_work_lock);
+ qedi_conn->fw_cleanup_works++;
+ spin_unlock(&qedi_conn->tmf_work_lock);
- /* If abort task then schedule the work and return */
- if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
- ISCSI_TM_FUNC_ABORT_TASK) {
- qedi_cmd->state = CLEANUP_WAIT;
- INIT_WORK(&qedi_cmd->tmf_work, qedi_tmf_work);
+ INIT_WORK(&qedi_cmd->tmf_work, qedi_abort_work);
queue_work(qedi->tmf_thread, &qedi_cmd->tmf_work);
-
- } else if (((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
- ISCSI_TM_FUNC_LOGICAL_UNIT_RESET) ||
- ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
- ISCSI_TM_FUNC_TARGET_WARM_RESET) ||
- ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
- ISCSI_TM_FUNC_TARGET_COLD_RESET)) {
- tid = qedi_get_task_idx(qedi);
- if (tid == -1) {
- QEDI_ERR(&qedi->dbg_ctx, "Invalid tid, cid=0x%x\n",
- qedi_conn->iscsi_conn_id);
- return -1;
- }
- qedi_cmd->task_id = tid;
-
- qedi_send_iscsi_tmf(qedi_conn, qedi_cmd->task);
-
- } else {
+ break;
+ case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET:
+ case ISCSI_TM_FUNC_TARGET_WARM_RESET:
+ case ISCSI_TM_FUNC_TARGET_COLD_RESET:
+ rc = send_iscsi_tmf(qedi_conn, mtask, NULL);
+ break;
+ default:
QEDI_ERR(&qedi->dbg_ctx, "Invalid tmf, cid=0x%x\n",
qedi_conn->iscsi_conn_id);
- return -1;
+ return -EINVAL;
}
- return 0;
+ return rc;
}
int qedi_send_iscsi_text(struct qedi_conn *qedi_conn,
diff --git a/drivers/scsi/qedi/qedi_gbl.h b/drivers/scsi/qedi/qedi_gbl.h
index 116645c08c71..9f8e8ef405a1 100644
--- a/drivers/scsi/qedi/qedi_gbl.h
+++ b/drivers/scsi/qedi/qedi_gbl.h
@@ -31,8 +31,7 @@ int qedi_send_iscsi_login(struct qedi_conn *qedi_conn,
struct iscsi_task *task);
int qedi_send_iscsi_logout(struct qedi_conn *qedi_conn,
struct iscsi_task *task);
-int qedi_iscsi_abort_work(struct qedi_conn *qedi_conn,
- struct iscsi_task *mtask);
+int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, struct iscsi_task *mtask);
int qedi_send_iscsi_text(struct qedi_conn *qedi_conn,
struct iscsi_task *task);
int qedi_send_iscsi_nopout(struct qedi_conn *qedi_conn,
@@ -73,6 +72,5 @@ void qedi_remove_sysfs_ctx_attr(struct qedi_ctx *qedi);
void qedi_clearsq(struct qedi_ctx *qedi,
struct qedi_conn *qedi_conn,
struct iscsi_task *task);
-void qedi_clear_session_ctx(struct iscsi_cls_session *cls_sess);
#endif
diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c
index 08c05403cd72..97f83760da88 100644
--- a/drivers/scsi/qedi/qedi_iscsi.c
+++ b/drivers/scsi/qedi/qedi_iscsi.c
@@ -330,12 +330,22 @@ free_conn:
void qedi_mark_device_missing(struct iscsi_cls_session *cls_session)
{
- iscsi_block_session(cls_session);
+ struct iscsi_session *session = cls_session->dd_data;
+ struct qedi_conn *qedi_conn = session->leadconn->dd_data;
+
+ spin_lock_bh(&session->frwd_lock);
+ set_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags);
+ spin_unlock_bh(&session->frwd_lock);
}
void qedi_mark_device_available(struct iscsi_cls_session *cls_session)
{
- iscsi_unblock_session(cls_session);
+ struct iscsi_session *session = cls_session->dd_data;
+ struct qedi_conn *qedi_conn = session->leadconn->dd_data;
+
+ spin_lock_bh(&session->frwd_lock);
+ clear_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags);
+ spin_unlock_bh(&session->frwd_lock);
}
static int qedi_bind_conn_to_iscsi_cid(struct qedi_ctx *qedi,
@@ -377,6 +387,7 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session,
struct qedi_ctx *qedi = iscsi_host_priv(shost);
struct qedi_endpoint *qedi_ep;
struct iscsi_endpoint *ep;
+ int rc = 0;
ep = iscsi_lookup_endpoint(transport_fd);
if (!ep)
@@ -384,11 +395,16 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session,
qedi_ep = ep->dd_data;
if ((qedi_ep->state == EP_STATE_TCP_FIN_RCVD) ||
- (qedi_ep->state == EP_STATE_TCP_RST_RCVD))
- return -EINVAL;
+ (qedi_ep->state == EP_STATE_TCP_RST_RCVD)) {
+ rc = -EINVAL;
+ goto put_ep;
+ }
+
+ if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) {
+ rc = -EINVAL;
+ goto put_ep;
+ }
- if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
- return -EINVAL;
qedi_ep->conn = qedi_conn;
qedi_conn->ep = qedi_ep;
@@ -398,13 +414,18 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session,
qedi_conn->cmd_cleanup_req = 0;
qedi_conn->cmd_cleanup_cmpl = 0;
- if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn))
- return -EINVAL;
+ if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn)) {
+ rc = -EINVAL;
+ goto put_ep;
+ }
+
spin_lock_init(&qedi_conn->tmf_work_lock);
INIT_LIST_HEAD(&qedi_conn->tmf_work_list);
init_waitqueue_head(&qedi_conn->wait_queue);
- return 0;
+put_ep:
+ iscsi_put_endpoint(ep);
+ return rc;
}
static int qedi_iscsi_update_conn(struct qedi_ctx *qedi,
@@ -582,7 +603,11 @@ static int qedi_conn_start(struct iscsi_cls_conn *cls_conn)
goto start_err;
}
- clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
+ spin_lock(&qedi_conn->tmf_work_lock);
+ qedi_conn->fw_cleanup_works = 0;
+ qedi_conn->ep_disconnect_starting = false;
+ spin_unlock(&qedi_conn->tmf_work_lock);
+
qedi_conn->abrt_conn = 0;
rval = iscsi_conn_start(cls_conn);
@@ -742,7 +767,7 @@ static int qedi_iscsi_send_generic_request(struct iscsi_task *task)
rc = qedi_send_iscsi_logout(qedi_conn, task);
break;
case ISCSI_OP_SCSI_TMFUNC:
- rc = qedi_iscsi_abort_work(qedi_conn, task);
+ rc = qedi_send_iscsi_tmf(qedi_conn, task);
break;
case ISCSI_OP_TEXT:
rc = qedi_send_iscsi_text(qedi_conn, task);
@@ -772,7 +797,6 @@ static int qedi_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
}
cmd->conn = conn->dd_data;
- cmd->scsi_cmd = NULL;
return qedi_iscsi_send_generic_request(task);
}
@@ -783,9 +807,16 @@ static int qedi_task_xmit(struct iscsi_task *task)
struct qedi_cmd *cmd = task->dd_data;
struct scsi_cmnd *sc = task->sc;
+ /* Clear now so in cleanup_task we know it didn't make it */
+ cmd->scsi_cmd = NULL;
+ cmd->task_id = U16_MAX;
+
if (test_bit(QEDI_IN_SHUTDOWN, &qedi_conn->qedi->flags))
return -ENODEV;
+ if (test_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags))
+ return -EACCES;
+
cmd->state = 0;
cmd->task = NULL;
cmd->use_slowpath = false;
@@ -988,12 +1019,10 @@ static void qedi_ep_disconnect(struct iscsi_endpoint *ep)
{
struct qedi_endpoint *qedi_ep;
struct qedi_conn *qedi_conn = NULL;
- struct iscsi_conn *conn = NULL;
struct qedi_ctx *qedi;
int ret = 0;
int wait_delay;
int abrt_conn = 0;
- int count = 10;
wait_delay = 60 * HZ + DEF_MAX_RT_TIME;
qedi_ep = ep->dd_data;
@@ -1007,17 +1036,21 @@ static void qedi_ep_disconnect(struct iscsi_endpoint *ep)
if (qedi_ep->conn) {
qedi_conn = qedi_ep->conn;
- conn = qedi_conn->cls_conn->dd_data;
- iscsi_suspend_queue(conn);
abrt_conn = qedi_conn->abrt_conn;
- while (count--) {
- if (!test_bit(QEDI_CONN_FW_CLEANUP,
- &qedi_conn->flags)) {
- break;
- }
+ QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+ "cid=0x%x qedi_ep=%p waiting for %d tmfs\n",
+ qedi_ep->iscsi_cid, qedi_ep,
+ qedi_conn->fw_cleanup_works);
+
+ spin_lock(&qedi_conn->tmf_work_lock);
+ qedi_conn->ep_disconnect_starting = true;
+ while (qedi_conn->fw_cleanup_works > 0) {
+ spin_unlock(&qedi_conn->tmf_work_lock);
msleep(1000);
+ spin_lock(&qedi_conn->tmf_work_lock);
}
+ spin_unlock(&qedi_conn->tmf_work_lock);
if (test_bit(QEDI_IN_RECOVERY, &qedi->flags)) {
if (qedi_do_not_recover) {
@@ -1383,13 +1416,24 @@ static umode_t qedi_attr_is_visible(int param_type, int param)
static void qedi_cleanup_task(struct iscsi_task *task)
{
- if (!task->sc || task->state == ISCSI_TASK_PENDING) {
+ struct qedi_cmd *cmd;
+
+ if (task->state == ISCSI_TASK_PENDING) {
QEDI_INFO(NULL, QEDI_LOG_IO, "Returning ref_cnt=%d\n",
refcount_read(&task->refcount));
return;
}
- qedi_iscsi_unmap_sg_list(task->dd_data);
+ if (task->sc)
+ qedi_iscsi_unmap_sg_list(task->dd_data);
+
+ cmd = task->dd_data;
+ if (cmd->task_id != U16_MAX)
+ qedi_clear_task_idx(iscsi_host_priv(task->conn->session->host),
+ cmd->task_id);
+
+ cmd->task_id = U16_MAX;
+ cmd->scsi_cmd = NULL;
}
struct iscsi_transport qedi_iscsi_transport = {
@@ -1401,6 +1445,7 @@ struct iscsi_transport qedi_iscsi_transport = {
.destroy_session = qedi_session_destroy,
.create_conn = qedi_conn_create,
.bind_conn = qedi_conn_bind,
+ .unbind_conn = iscsi_conn_unbind,
.start_conn = qedi_conn_start,
.stop_conn = iscsi_conn_stop,
.destroy_conn = qedi_conn_destroy,
@@ -1614,20 +1659,6 @@ void qedi_process_iscsi_error(struct qedi_endpoint *ep,
qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn);
}
-void qedi_clear_session_ctx(struct iscsi_cls_session *cls_sess)
-{
- struct iscsi_session *session = cls_sess->dd_data;
- struct iscsi_conn *conn = session->leadconn;
- struct qedi_conn *qedi_conn = conn->dd_data;
-
- if (iscsi_is_session_online(cls_sess))
- qedi_ep_disconnect(qedi_conn->iscsi_ep);
-
- qedi_conn_destroy(qedi_conn->cls_conn);
-
- qedi_session_destroy(cls_sess);
-}
-
void qedi_process_tcp_error(struct qedi_endpoint *ep,
struct iscsi_eqe_data *data)
{
diff --git a/drivers/scsi/qedi/qedi_iscsi.h b/drivers/scsi/qedi/qedi_iscsi.h
index 39dc27c85e3c..758735209e15 100644
--- a/drivers/scsi/qedi/qedi_iscsi.h
+++ b/drivers/scsi/qedi/qedi_iscsi.h
@@ -169,8 +169,8 @@ struct qedi_conn {
struct list_head tmf_work_list;
wait_queue_head_t wait_queue;
spinlock_t tmf_work_lock; /* tmf work lock */
- unsigned long flags;
-#define QEDI_CONN_FW_CLEANUP 1
+ bool ep_disconnect_starting;
+ int fw_cleanup_works;
};
struct qedi_cmd {
@@ -212,6 +212,7 @@ struct qedi_cmd {
struct qedi_work_map {
struct list_head list;
struct qedi_cmd *qedi_cmd;
+ struct iscsi_task *ctask;
int rtid;
int state;
diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
index 2455d1448a7e..0b0acb827071 100644
--- a/drivers/scsi/qedi/qedi_main.c
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -640,7 +640,7 @@ static struct qedi_ctx *qedi_host_alloc(struct pci_dev *pdev)
goto exit_setup_shost;
}
- shost->max_id = QEDI_MAX_ISCSI_CONNS_PER_HBA;
+ shost->max_id = QEDI_MAX_ISCSI_CONNS_PER_HBA - 1;
shost->max_channel = 0;
shost->max_lun = ~0;
shost->max_cmd_len = 16;
@@ -2417,11 +2417,9 @@ static void __qedi_remove(struct pci_dev *pdev, int mode)
int rval;
u16 retry = 10;
- if (mode == QEDI_MODE_SHUTDOWN)
- iscsi_host_for_each_session(qedi->shost,
- qedi_clear_session_ctx);
-
if (mode == QEDI_MODE_NORMAL || mode == QEDI_MODE_SHUTDOWN) {
+ iscsi_host_remove(qedi->shost);
+
if (qedi->tmf_thread) {
flush_workqueue(qedi->tmf_thread);
destroy_workqueue(qedi->tmf_thread);
@@ -2482,7 +2480,6 @@ static void __qedi_remove(struct pci_dev *pdev, int mode)
if (qedi->boot_kset)
iscsi_boot_destroy_kset(qedi->boot_kset);
- iscsi_host_remove(qedi->shost);
iscsi_host_free(qedi->shost);
}
}
diff --git a/drivers/scsi/qedi/qedi_sysfs.c b/drivers/scsi/qedi/qedi_sysfs.c
index 04ee68e6499c..be174d30eb7c 100644
--- a/drivers/scsi/qedi/qedi_sysfs.c
+++ b/drivers/scsi/qedi/qedi_sysfs.c
@@ -16,9 +16,9 @@ static inline struct qedi_ctx *qedi_dev_to_hba(struct device *dev)
return iscsi_host_priv(shost);
}
-static ssize_t qedi_show_port_state(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t port_state_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct qedi_ctx *qedi = qedi_dev_to_hba(dev);
@@ -28,8 +28,8 @@ static ssize_t qedi_show_port_state(struct device *dev,
return sprintf(buf, "Linkdown\n");
}
-static ssize_t qedi_show_speed(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t speed_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct qedi_ctx *qedi = qedi_dev_to_hba(dev);
struct qed_link_output if_link;
@@ -39,8 +39,8 @@ static ssize_t qedi_show_speed(struct device *dev,
return sprintf(buf, "%d Gbit\n", if_link.speed / 1000);
}
-static DEVICE_ATTR(port_state, 0444, qedi_show_port_state, NULL);
-static DEVICE_ATTR(speed, 0444, qedi_show_speed, NULL);
+static DEVICE_ATTR_RO(port_state);
+static DEVICE_ATTR_RO(speed);
struct device_attribute *qedi_shost_attrs[] = {
&dev_attr_port_state,
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index def4d99f80e9..2f67ec1df3e6 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -3660,6 +3660,8 @@ struct qla_qpair {
struct qla_tgt_counters tgt_counters;
uint16_t cpuid;
struct qla_fw_resources fwres ____cacheline_aligned;
+ u32 cmd_cnt;
+ u32 cmd_completion_cnt;
};
/* Place holder for FW buffer parameters */
@@ -4616,6 +4618,7 @@ struct qla_hw_data {
struct qla_hw_data_stat stat;
pci_error_state_t pci_error_state;
+ u64 prev_cmd_cnt;
};
struct active_regions {
@@ -4743,6 +4746,7 @@ typedef struct scsi_qla_host {
#define SET_ZIO_THRESHOLD_NEEDED 32
#define ISP_ABORT_TO_ROM 33
#define VPORT_DELETE 34
+#define HEARTBEAT_CHK 38
#define PROCESS_PUREX_IOCB 63
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index fae5cae6f0a8..2f867da822ae 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -173,7 +173,6 @@ extern int ql2xnvmeenable;
extern int ql2xautodetectsfp;
extern int ql2xenablemsix;
extern int qla2xuseresexchforels;
-extern int ql2xexlogins;
extern int ql2xdifbundlinginternalbuffers;
extern int ql2xfulldump_on_mpifail;
extern int ql2xenforce_iocb_limit;
@@ -220,7 +219,6 @@ extern int qla83xx_set_drv_presence(scsi_qla_host_t *vha);
extern int __qla83xx_set_drv_presence(scsi_qla_host_t *vha);
extern int qla83xx_clear_drv_presence(scsi_qla_host_t *vha);
extern int __qla83xx_clear_drv_presence(scsi_qla_host_t *vha);
-extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
extern void qla2x00_disable_board_on_pci_error(struct work_struct *);
@@ -551,6 +549,7 @@ extern int qla2xxx_read_remote_register(scsi_qla_host_t *, uint32_t,
uint32_t *);
extern int qla2xxx_write_remote_register(scsi_qla_host_t *, uint32_t,
uint32_t);
+void qla_no_op_mb(struct scsi_qla_host *vha);
/*
* Global Function Prototypes in qla_isr.c source file.
@@ -687,8 +686,6 @@ extern int qla2x00_chk_ms_status(scsi_qla_host_t *, ms_iocb_entry_t *,
struct ct_sns_rsp *, const char *);
extern void qla2x00_async_iocb_timeout(void *data);
-extern void qla2x00_free_fcport(fc_port_t *);
-
extern int qla24xx_post_gpnid_work(struct scsi_qla_host *, port_id_t *);
extern int qla24xx_async_gpnid(scsi_qla_host_t *, port_id_t *);
void qla24xx_handle_gpnid_event(scsi_qla_host_t *, struct event_arg *);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 0de250570e39..f8f471157109 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -4356,8 +4356,6 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
if (IS_QLAFX00(vha->hw))
return qlafx00_fw_ready(vha);
- rval = QLA_SUCCESS;
-
/* Time to wait for loop down */
if (IS_P3P_TYPE(ha))
min_wait = 30;
@@ -6872,10 +6870,14 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
ha->flags.fw_init_done = 0;
ha->chip_reset++;
ha->base_qpair->chip_reset = ha->chip_reset;
+ ha->base_qpair->cmd_cnt = ha->base_qpair->cmd_completion_cnt = 0;
for (i = 0; i < ha->max_qpairs; i++) {
- if (ha->queue_pair_map[i])
+ if (ha->queue_pair_map[i]) {
ha->queue_pair_map[i]->chip_reset =
ha->base_qpair->chip_reset;
+ ha->queue_pair_map[i]->cmd_cnt =
+ ha->queue_pair_map[i]->cmd_completion_cnt = 0;
+ }
}
/* purge MBox commands */
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 38b5bdde2405..d0ee843f6b04 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -1710,6 +1710,7 @@ qla24xx_start_scsi(srb_t *sp)
} else
req->ring_ptr++;
+ sp->qpair->cmd_cnt++;
sp->flags |= SRB_DMA_VALID;
/* Set chip new ring index. */
@@ -1912,6 +1913,7 @@ qla24xx_dif_start_scsi(srb_t *sp)
} else
req->ring_ptr++;
+ sp->qpair->cmd_cnt++;
/* Set chip new ring index. */
wrt_reg_dword(req->req_q_in, req->ring_index);
@@ -2068,6 +2070,7 @@ qla2xxx_start_scsi_mq(srb_t *sp)
} else
req->ring_ptr++;
+ sp->qpair->cmd_cnt++;
sp->flags |= SRB_DMA_VALID;
/* Set chip new ring index. */
@@ -2284,6 +2287,7 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp)
} else
req->ring_ptr++;
+ sp->qpair->cmd_cnt++;
/* Set chip new ring index. */
wrt_reg_dword(req->req_q_in, req->ring_index);
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 6e8f737a4af3..d9fb093a60a1 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -2322,6 +2322,8 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
if (unlikely(iocb->u.nvme.aen_op))
atomic_dec(&sp->vha->hw->nvme_active_aen_cnt);
+ else
+ sp->qpair->cmd_completion_cnt++;
if (unlikely(comp_status != CS_COMPLETE))
logit = 1;
@@ -2694,31 +2696,22 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
/* check guard */
if (e_guard != a_guard) {
- scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x1);
- set_driver_byte(cmd, DRIVER_SENSE);
+ scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x1);
set_host_byte(cmd, DID_ABORT);
- cmd->result |= SAM_STAT_CHECK_CONDITION;
return 1;
}
/* check ref tag */
if (e_ref_tag != a_ref_tag) {
- scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x3);
- set_driver_byte(cmd, DRIVER_SENSE);
+ scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x3);
set_host_byte(cmd, DID_ABORT);
- cmd->result |= SAM_STAT_CHECK_CONDITION;
return 1;
}
/* check appl tag */
if (e_app_tag != a_app_tag) {
- scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
- 0x10, 0x2);
- set_driver_byte(cmd, DRIVER_SENSE);
+ scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x2);
set_host_byte(cmd, DID_ABORT);
- cmd->result |= SAM_STAT_CHECK_CONDITION;
return 1;
}
@@ -2976,6 +2969,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
return;
}
+ sp->qpair->cmd_completion_cnt++;
+
/* Fast path completion. */
if (comp_status == CS_COMPLETE && scsi_status == 0) {
qla2x00_process_completed_request(vha, req, handle);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 0bcd8afdc0ff..9f3ad8aa649c 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -6939,3 +6939,30 @@ ql26xx_led_config(scsi_qla_host_t *vha, uint16_t options, uint16_t *led)
return rval;
}
+
+/**
+ * qla_no_op_mb(): This MB is used to check if FW is still alive and
+ * able to generate an interrupt. Otherwise, a timeout will trigger
+ * FW dump + reset
+ * @vha: host adapter pointer
+ * Return: None
+ */
+void qla_no_op_mb(struct scsi_qla_host *vha)
+{
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ int rval;
+
+ memset(&mc, 0, sizeof(mc));
+ mcp->mb[0] = 0; // noop cmd= 0
+ mcp->out_mb = MBX_0;
+ mcp->in_mb = MBX_0;
+ mcp->tov = 5;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ if (rval) {
+ ql_dbg(ql_dbg_async, vha, 0x7071,
+ "Failed %s %x\n", __func__, rval);
+ }
+}
diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index 0cacb667a88b..3e5c70a1d969 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -536,6 +536,10 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
req->ring_ptr++;
}
+ /* ignore nvme async cmd due to long timeout */
+ if (!nvme->u.nvme.aen_op)
+ sp->qpair->cmd_cnt++;
+
/* Set chip new ring index. */
wrt_reg_dword(req->req_q_in, req->ring_index);
@@ -671,7 +675,7 @@ void qla_nvme_unregister_remote_port(struct fc_port *fcport)
if (!IS_ENABLED(CONFIG_NVME_FC))
return;
- ql_log(ql_log_warn, NULL, 0x2112,
+ ql_log(ql_log_warn, fcport->vha, 0x2112,
"%s: unregister remoteport on %p %8phN\n",
__func__, fcport, fcport->port_name);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 4eab564ea6a0..cedd558f65eb 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -6969,6 +6969,17 @@ intr_on_check:
qla2x00_lip_reset(base_vha);
}
+ if (test_bit(HEARTBEAT_CHK, &base_vha->dpc_flags)) {
+ /*
+ * if there is a mb in progress then that's
+ * enough of a check to see if fw is still ticking.
+ */
+ if (!ha->flags.mbox_busy && base_vha->flags.init_done)
+ qla_no_op_mb(base_vha);
+
+ clear_bit(HEARTBEAT_CHK, &base_vha->dpc_flags);
+ }
+
ha->dpc_active = 0;
end_loop:
set_current_state(TASK_INTERRUPTIBLE);
@@ -7025,6 +7036,61 @@ qla2x00_rst_aen(scsi_qla_host_t *vha)
}
}
+static bool qla_do_heartbeat(struct scsi_qla_host *vha)
+{
+ u64 cmd_cnt, prev_cmd_cnt;
+ bool do_hb = false;
+ struct qla_hw_data *ha = vha->hw;
+ int i;
+
+ /* if cmds are still pending down in fw, then do hb */
+ if (ha->base_qpair->cmd_cnt != ha->base_qpair->cmd_completion_cnt) {
+ do_hb = true;
+ goto skip;
+ }
+
+ for (i = 0; i < ha->max_qpairs; i++) {
+ if (ha->queue_pair_map[i] &&
+ ha->queue_pair_map[i]->cmd_cnt !=
+ ha->queue_pair_map[i]->cmd_completion_cnt) {
+ do_hb = true;
+ break;
+ }
+ }
+
+skip:
+ prev_cmd_cnt = ha->prev_cmd_cnt;
+ cmd_cnt = ha->base_qpair->cmd_cnt;
+ for (i = 0; i < ha->max_qpairs; i++) {
+ if (ha->queue_pair_map[i])
+ cmd_cnt += ha->queue_pair_map[i]->cmd_cnt;
+ }
+ ha->prev_cmd_cnt = cmd_cnt;
+
+ if (!do_hb && ((cmd_cnt - prev_cmd_cnt) > 50))
+ /*
+ * IOs are completing before periodic hb check.
+ * IOs seems to be running, do hb for sanity check.
+ */
+ do_hb = true;
+
+ return do_hb;
+}
+
+static void qla_heart_beat(struct scsi_qla_host *vha)
+{
+ if (vha->vp_idx)
+ return;
+
+ if (vha->hw->flags.eeh_busy || qla2x00_chip_is_down(vha))
+ return;
+
+ if (qla_do_heartbeat(vha)) {
+ set_bit(HEARTBEAT_CHK, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ }
+}
+
/**************************************************************************
* qla2x00_timer
*
@@ -7243,6 +7309,8 @@ qla2x00_timer(struct timer_list *t)
qla2xxx_wake_dpc(vha);
}
+ qla_heart_beat(vha);
+
qla2x00_restart_timer(vha, WATCH_INTERVAL);
}
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 12a6848ade43..eb47140a899f 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -5481,8 +5481,7 @@ qlt_free_qfull_cmds(struct qla_qpair *qpair)
"%s: Unexpected cmd in QFull list %p\n", __func__,
cmd);
- list_del(&cmd->cmd_list);
- list_add_tail(&cmd->cmd_list, &free_list);
+ list_move_tail(&cmd->cmd_list, &free_list);
/* piggy back on hardware_lock for protection */
vha->hw->tgt.num_qfull_cmds_alloc--;
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.c b/drivers/scsi/qla4xxx/ql4_83xx.c
index 5f56122f6664..db41d90a5b6e 100644
--- a/drivers/scsi/qla4xxx/ql4_83xx.c
+++ b/drivers/scsi/qla4xxx/ql4_83xx.c
@@ -472,8 +472,7 @@ int qla4_83xx_can_perform_reset(struct scsi_qla_host *ha)
} else if (device_map[i].device_type == ISCSI_CLASS) {
if (drv_active & (1 << device_map[i].func_num)) {
if (!iscsi_present ||
- (iscsi_present &&
- (iscsi_func_low > device_map[i].func_num)))
+ iscsi_func_low > device_map[i].func_num)
iscsi_func_low = device_map[i].func_num;
iscsi_present++;
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index ad3afe30f617..6ee7ea4c27e0 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -259,6 +259,7 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
.start_conn = qla4xxx_conn_start,
.create_conn = qla4xxx_conn_create,
.bind_conn = qla4xxx_conn_bind,
+ .unbind_conn = iscsi_conn_unbind,
.stop_conn = iscsi_conn_stop,
.destroy_conn = qla4xxx_conn_destroy,
.set_param = iscsi_set_param,
@@ -814,8 +815,6 @@ static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
valid_chap_entries++;
if (valid_chap_entries == *num_entries)
break;
- else
- continue;
}
mutex_unlock(&ha->chap_sem);
@@ -3234,6 +3233,7 @@ static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
conn = cls_conn->dd_data;
qla_conn = conn->dd_data;
qla_conn->qla_ep = ep->dd_data;
+ iscsi_put_endpoint(ep);
return 0;
}
diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c
index 136681ad18a5..3bbe0b5545d9 100644
--- a/drivers/scsi/qlogicfas408.c
+++ b/drivers/scsi/qlogicfas408.c
@@ -4,9 +4,9 @@
Use at your own risk. Support Tort Reform so you won't have to read all
these silly disclaimers.
- Copyright 1994, Tom Zerucha.
+ Copyright 1994, Tom Zerucha.
tz@execpc.com
-
+
Additional Code, and much appreciated help by
Michael A. Griffith
grif@cs.ucr.edu
@@ -22,12 +22,12 @@
Functions as standalone, loadable, and PCMCIA driver, the latter from
Dave Hinds' PCMCIA package.
-
+
Cleaned up 26/10/2002 by Alan Cox <alan@lxorguk.ukuu.org.uk> as part of the 2.5
SCSI driver cleanup and audit. This driver still needs work on the
following
- - Non terminating hardware waits
- - Some layering violations with its pcmcia stub
+ - Non terminating hardware waits
+ - Some layering violations with its pcmcia stub
Redistributable under terms of the GNU General Public License
@@ -92,8 +92,9 @@ static void ql_zap(struct qlogicfas408_priv *priv)
/*
* Do a pseudo-dma tranfer
*/
-
-static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request, int reqlen)
+
+static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request,
+ int reqlen)
{
int j;
int qbase = priv->qbase;
@@ -108,7 +109,7 @@ static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request, int
request += 128;
}
while (reqlen >= 84 && !(j & 0xc0)) /* 2/3 */
- if ((j = inb(qbase + 8)) & 4)
+ if ((j = inb(qbase + 8)) & 4)
{
insl(qbase + 4, request, 21);
reqlen -= 84;
@@ -123,11 +124,11 @@ static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request, int
/* until both empty and int (or until reclen is 0) */
rtrc(7)
j = 0;
- while (reqlen && !((j & 0x10) && (j & 0xc0)))
+ while (reqlen && !((j & 0x10) && (j & 0xc0)))
{
/* while bytes to receive and not empty */
j &= 0xc0;
- while (reqlen && !((j = inb(qbase + 8)) & 0x10))
+ while (reqlen && !((j = inb(qbase + 8)) & 0x10))
{
*request++ = inb(qbase + 4);
reqlen--;
@@ -161,7 +162,7 @@ static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request, int
j = 0;
while (reqlen && !((j & 2) && (j & 0xc0))) {
/* while bytes to send and not full */
- while (reqlen && !((j = inb(qbase + 8)) & 2))
+ while (reqlen && !((j = inb(qbase + 8)) & 2))
{
outb(*request++, qbase + 4);
reqlen--;
@@ -175,7 +176,7 @@ static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request, int
}
/*
- * Wait for interrupt flag (polled - not real hardware interrupt)
+ * Wait for interrupt flag (polled - not real hardware interrupt)
*/
static int ql_wai(struct qlogicfas408_priv *priv)
@@ -205,14 +206,14 @@ static int ql_wai(struct qlogicfas408_priv *priv)
}
/*
- * Initiate scsi command - queueing handler
+ * Initiate scsi command - queueing handler
* caller must hold host lock
*/
static void ql_icmd(struct scsi_cmnd *cmd)
{
struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
- int qbase = priv->qbase;
+ int qbase = priv->qbase;
int int_type = priv->int_type;
unsigned int i;
@@ -253,14 +254,13 @@ static void ql_icmd(struct scsi_cmnd *cmd)
}
/*
- * Process scsi command - usually after interrupt
+ * Process scsi command - usually after interrupt
*/
-static unsigned int ql_pcmd(struct scsi_cmnd *cmd)
+static void ql_pcmd(struct scsi_cmnd *cmd)
{
unsigned int i, j;
unsigned long k;
- unsigned int result; /* ultimate return result */
unsigned int status; /* scsi returned status */
unsigned int message; /* scsi returned message */
unsigned int phase; /* recorded scsi phase */
@@ -274,13 +274,15 @@ static unsigned int ql_pcmd(struct scsi_cmnd *cmd)
j = inb(qbase + 6);
i = inb(qbase + 5);
if (i == 0x20) {
- return (DID_NO_CONNECT << 16);
+ set_host_byte(cmd, DID_NO_CONNECT);
+ return;
}
i |= inb(qbase + 5); /* the 0x10 bit can be set after the 0x08 */
if (i != 0x18) {
printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i);
ql_zap(priv);
- return (DID_BAD_INTR << 16);
+ set_host_byte(cmd, DID_BAD_INTR);
+ return;
}
j &= 7; /* j = inb( qbase + 7 ) >> 5; */
@@ -293,9 +295,10 @@ static unsigned int ql_pcmd(struct scsi_cmnd *cmd)
printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n",
j, i, inb(qbase + 7) & 0x1f);
ql_zap(priv);
- return (DID_ERROR << 16);
+ set_host_byte(cmd, DID_ERROR);
+ return;
}
- result = DID_OK;
+
if (inb(qbase + 7) & 0x1f) /* if some bytes in fifo */
outb(1, qbase + 3); /* clear fifo */
/* note that request_bufflen is the total xfer size when sg is used */
@@ -314,28 +317,31 @@ static unsigned int ql_pcmd(struct scsi_cmnd *cmd)
scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) {
if (priv->qabort) {
REG0;
- return ((priv->qabort == 1 ?
- DID_ABORT : DID_RESET) << 16);
+ set_host_byte(cmd,
+ priv->qabort == 1 ?
+ DID_ABORT : DID_RESET);
}
buf = sg_virt(sg);
if (ql_pdma(priv, phase, buf, sg->length))
break;
}
REG0;
- rtrc(2)
+ rtrc(2);
/*
* Wait for irq (split into second state of irq handler
- * if this can take time)
+ * if this can take time)
*/
- if ((k = ql_wai(priv)))
- return (k << 16);
+ if ((k = ql_wai(priv))) {
+ set_host_byte(cmd, k);
+ return;
+ }
k = inb(qbase + 5); /* should be 0x10, bus service */
}
/*
- * Enter Status (and Message In) Phase
+ * Enter Status (and Message In) Phase
*/
-
+
k = jiffies + WATCHDOG;
while (time_before(jiffies, k) && !priv->qabort &&
@@ -344,57 +350,72 @@ static unsigned int ql_pcmd(struct scsi_cmnd *cmd)
if (time_after_eq(jiffies, k)) {
ql_zap(priv);
- return (DID_TIME_OUT << 16);
+ set_host_byte(cmd, DID_TIME_OUT);
+ return;
}
/* FIXME: timeout ?? */
while (inb(qbase + 5))
cpu_relax(); /* clear pending ints */
- if (priv->qabort)
- return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
+ if (priv->qabort) {
+ set_host_byte(cmd,
+ priv->qabort == 1 ? DID_ABORT : DID_RESET);
+ return;
+ }
outb(0x11, qbase + 3); /* get status and message */
- if ((k = ql_wai(priv)))
- return (k << 16);
+ if ((k = ql_wai(priv))) {
+ set_host_byte(cmd, k);
+ return;
+ }
i = inb(qbase + 5); /* get chip irq stat */
j = inb(qbase + 7) & 0x1f; /* and bytes rec'd */
status = inb(qbase + 2);
message = inb(qbase + 2);
/*
- * Should get function complete int if Status and message, else
- * bus serv if only status
+ * Should get function complete int if Status and message, else
+ * bus serv if only status
*/
if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
printk(KERN_ERR "Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
- result = DID_ERROR;
+ set_host_byte(cmd, DID_ERROR);
}
outb(0x12, qbase + 3); /* done, disconnect */
- rtrc(1)
- if ((k = ql_wai(priv)))
- return (k << 16);
+ rtrc(1);
+ if ((k = ql_wai(priv))) {
+ set_host_byte(cmd, k);
+ return;
+ }
/*
- * Should get bus service interrupt and disconnect interrupt
+ * Should get bus service interrupt and disconnect interrupt
*/
-
+
i = inb(qbase + 5); /* should be bus service */
while (!priv->qabort && ((i & 0x20) != 0x20)) {
barrier();
cpu_relax();
i |= inb(qbase + 5);
}
- rtrc(0)
+ rtrc(0);
- if (priv->qabort)
- return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
-
- return (result << 16) | (message << 8) | (status & STATUS_MASK);
+ if (priv->qabort) {
+ set_host_byte(cmd,
+ priv->qabort == 1 ? DID_ABORT : DID_RESET);
+ return;
+ }
+
+ set_host_byte(cmd, DID_OK);
+ if (message != COMMAND_COMPLETE)
+ scsi_msg_to_host_byte(cmd, message);
+ set_status_byte(cmd, status);
+ return;
}
/*
- * Interrupt handler
+ * Interrupt handler
*/
static void ql_ihandl(void *dev_id)
@@ -415,11 +436,11 @@ static void ql_ihandl(void *dev_id)
return;
}
icmd = priv->qlcmd;
- icmd->result = ql_pcmd(icmd);
+ ql_pcmd(icmd);
priv->qlcmd = NULL;
/*
- * If result is CHECK CONDITION done calls qcommand to request
- * sense
+ * If result is CHECK CONDITION done calls qcommand to request
+ * sense
*/
(icmd->scsi_done) (icmd);
}
@@ -443,8 +464,11 @@ static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd,
void (*done) (struct scsi_cmnd *))
{
struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
+
+ set_host_byte(cmd, DID_OK);
+ set_status_byte(cmd, SAM_STAT_GOOD);
if (scmd_id(cmd) == priv->qinitid) {
- cmd->result = DID_BAD_TARGET << 16;
+ set_host_byte(cmd, DID_BAD_TARGET);
done(cmd);
return 0;
}
@@ -461,8 +485,8 @@ static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd,
DEF_SCSI_QCMD(qlogicfas408_queuecommand)
-/*
- * Return bios parameters
+/*
+ * Return bios parameters
*/
int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev,
@@ -487,7 +511,7 @@ int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev,
/*
* Abort a command in progress
*/
-
+
int qlogicfas408_abort(struct scsi_cmnd *cmd)
{
struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
@@ -566,9 +590,9 @@ void qlogicfas408_setup(int qbase, int id, int int_type)
int qlogicfas408_detect(int qbase, int int_type)
{
- REG1;
+ REG1;
return (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) &&
- ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7));
+ ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7));
}
/*
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index e9e2f0e15ac8..d26025cf5de3 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -144,7 +144,7 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
(level > 1)) {
scsi_print_result(cmd, "Done", disposition);
scsi_print_command(cmd);
- if (status_byte(cmd->result) == CHECK_CONDITION)
+ if (scsi_status_is_check_condition(cmd->result))
scsi_print_sense(cmd);
if (level > 3)
scmd_printk(KERN_INFO, cmd,
@@ -185,13 +185,6 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
if (atomic_read(&sdev->device_blocked))
atomic_set(&sdev->device_blocked, 0);
- /*
- * If we have valid sense information, then some kind of recovery
- * must have taken place. Make a note of this.
- */
- if (SCSI_SENSE_VALID(cmd))
- cmd->result |= (DRIVER_SENSE << 24);
-
SCSI_LOG_MLCOMPLETE(4, sdev_printk(KERN_INFO, sdev,
"Notifying upper driver of completion "
"(result %x)\n", cmd->result));
@@ -508,6 +501,8 @@ int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len,
&sshdr, 30 * HZ, 3, NULL);
+ if (result < 0)
+ return result;
if (result && scsi_sense_valid(&sshdr) &&
sshdr.sense_key == ILLEGAL_REQUEST &&
(sshdr.asc == 0x20 || sshdr.asc == 0x24) && sshdr.ascq == 0x00)
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index a5d1633b5bd8..5b3a20a140f9 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -851,10 +851,10 @@ static struct device_driver sdebug_driverfs_driver = {
};
static const int check_condition_result =
- (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+ SAM_STAT_CHECK_CONDITION;
static const int illegal_condition_result =
- (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
+ (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
static const int device_qfull_result =
(DID_OK << 16) | SAM_STAT_TASK_SET_FULL;
@@ -931,7 +931,7 @@ static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
}
asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
- scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
+ scsi_build_sense(scp, sdebug_dsense, ILLEGAL_REQUEST, asc, 0);
memset(sks, 0, sizeof(sks));
sks[0] = 0x80;
if (c_d)
@@ -957,17 +957,14 @@ static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
{
- unsigned char *sbuff;
-
- sbuff = scp->sense_buffer;
- if (!sbuff) {
+ if (!scp->sense_buffer) {
sdev_printk(KERN_ERR, scp->device,
"%s: sense_buffer is NULL\n", __func__);
return;
}
- memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
+ memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
+ scsi_build_sense(scp, sdebug_dsense, key, asc, asq);
if (sdebug_verbose)
sdev_printk(KERN_INFO, scp->device,
@@ -7684,11 +7681,6 @@ static int sdebug_driver_remove(struct device *dev)
sdbg_host = to_sdebug_host(dev);
- if (!sdbg_host) {
- pr_err("Unable to locate host info\n");
- return -ENODEV;
- }
-
scsi_remove_host(sdbg_host->shost);
list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index d8fafe77dbbe..58a252c38992 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -742,41 +742,35 @@ static enum scsi_disposition scsi_eh_completed_normally(struct scsi_cmnd *scmd)
return FAILED;
/*
- * next, check the message byte.
- */
- if (msg_byte(scmd->result) != COMMAND_COMPLETE)
- return FAILED;
-
- /*
* now, check the status byte to see if this indicates
* anything special.
*/
- switch (status_byte(scmd->result)) {
- case GOOD:
+ switch (get_status_byte(scmd)) {
+ case SAM_STAT_GOOD:
scsi_handle_queue_ramp_up(scmd->device);
fallthrough;
- case COMMAND_TERMINATED:
+ case SAM_STAT_COMMAND_TERMINATED:
return SUCCESS;
- case CHECK_CONDITION:
+ case SAM_STAT_CHECK_CONDITION:
return scsi_check_sense(scmd);
- case CONDITION_GOOD:
- case INTERMEDIATE_GOOD:
- case INTERMEDIATE_C_GOOD:
+ case SAM_STAT_CONDITION_MET:
+ case SAM_STAT_INTERMEDIATE:
+ case SAM_STAT_INTERMEDIATE_CONDITION_MET:
/*
* who knows? FIXME(eric)
*/
return SUCCESS;
- case RESERVATION_CONFLICT:
+ case SAM_STAT_RESERVATION_CONFLICT:
if (scmd->cmnd[0] == TEST_UNIT_READY)
/* it is a success, we probed the device and
* found it */
return SUCCESS;
/* otherwise, we failed to send the command */
return FAILED;
- case QUEUE_FULL:
+ case SAM_STAT_TASK_SET_FULL:
scsi_handle_queue_full(scmd->device);
fallthrough;
- case BUSY:
+ case SAM_STAT_BUSY:
return NEEDS_RETRY;
default:
return FAILED;
@@ -1258,7 +1252,7 @@ int scsi_eh_get_sense(struct list_head *work_q,
current->comm));
break;
}
- if (status_byte(scmd->result) != CHECK_CONDITION)
+ if (!scsi_status_is_check_condition(scmd->result))
/*
* don't request sense if there's no check condition
* status because the error we're processing isn't one
@@ -1766,15 +1760,14 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd)
case DID_PARITY:
return (scmd->request->cmd_flags & REQ_FAILFAST_DEV);
case DID_ERROR:
- if (msg_byte(scmd->result) == COMMAND_COMPLETE &&
- status_byte(scmd->result) == RESERVATION_CONFLICT)
+ if (get_status_byte(scmd) == SAM_STAT_RESERVATION_CONFLICT)
return 0;
fallthrough;
case DID_SOFT_ERROR:
return (scmd->request->cmd_flags & REQ_FAILFAST_DRIVER);
}
- if (status_byte(scmd->result) != CHECK_CONDITION)
+ if (!scsi_status_is_check_condition(scmd->result))
return 0;
check_type:
@@ -1883,8 +1876,7 @@ enum scsi_disposition scsi_decide_disposition(struct scsi_cmnd *scmd)
*/
return SUCCESS;
case DID_ERROR:
- if (msg_byte(scmd->result) == COMMAND_COMPLETE &&
- status_byte(scmd->result) == RESERVATION_CONFLICT)
+ if (get_status_byte(scmd) == SAM_STAT_RESERVATION_CONFLICT)
/*
* execute reservation conflict processing code
* lower down
@@ -1913,23 +1905,17 @@ enum scsi_disposition scsi_decide_disposition(struct scsi_cmnd *scmd)
}
/*
- * next, check the message byte.
- */
- if (msg_byte(scmd->result) != COMMAND_COMPLETE)
- return FAILED;
-
- /*
* check the status byte to see if this indicates anything special.
*/
- switch (status_byte(scmd->result)) {
- case QUEUE_FULL:
+ switch (get_status_byte(scmd)) {
+ case SAM_STAT_TASK_SET_FULL:
scsi_handle_queue_full(scmd->device);
/*
* the case of trying to send too many commands to a
* tagged queueing device.
*/
fallthrough;
- case BUSY:
+ case SAM_STAT_BUSY:
/*
* device can't talk to us at the moment. Should only
* occur (SAM-3) when the task queue is empty, so will cause
@@ -1937,16 +1923,16 @@ enum scsi_disposition scsi_decide_disposition(struct scsi_cmnd *scmd)
* device.
*/
return ADD_TO_MLQUEUE;
- case GOOD:
+ case SAM_STAT_GOOD:
if (scmd->cmnd[0] == REPORT_LUNS)
scmd->device->sdev_target->expecting_lun_change = 0;
scsi_handle_queue_ramp_up(scmd->device);
fallthrough;
- case COMMAND_TERMINATED:
+ case SAM_STAT_COMMAND_TERMINATED:
return SUCCESS;
- case TASK_ABORTED:
+ case SAM_STAT_TASK_ABORTED:
goto maybe_retry;
- case CHECK_CONDITION:
+ case SAM_STAT_CHECK_CONDITION:
rtn = scsi_check_sense(scmd);
if (rtn == NEEDS_RETRY)
goto maybe_retry;
@@ -1955,16 +1941,16 @@ enum scsi_disposition scsi_decide_disposition(struct scsi_cmnd *scmd)
* to collect the sense and redo the decide
* disposition */
return rtn;
- case CONDITION_GOOD:
- case INTERMEDIATE_GOOD:
- case INTERMEDIATE_C_GOOD:
- case ACA_ACTIVE:
+ case SAM_STAT_CONDITION_MET:
+ case SAM_STAT_INTERMEDIATE:
+ case SAM_STAT_INTERMEDIATE_CONDITION_MET:
+ case SAM_STAT_ACA_ACTIVE:
/*
* who knows? FIXME(eric)
*/
return SUCCESS;
- case RESERVATION_CONFLICT:
+ case SAM_STAT_RESERVATION_CONFLICT:
sdev_printk(KERN_INFO, scmd->device,
"reservation conflict\n");
set_host_byte(scmd, DID_NEXUS_FAILURE);
@@ -2011,7 +1997,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
struct request *req;
struct scsi_request *rq;
- req = blk_get_request(sdev->request_queue, REQ_OP_SCSI_IN, 0);
+ req = blk_get_request(sdev->request_queue, REQ_OP_DRV_IN, 0);
if (IS_ERR(req))
return;
rq = scsi_req(req);
@@ -2137,10 +2123,10 @@ void scsi_eh_flush_done_q(struct list_head *done_q)
/*
* If just we got sense for the device (called
* scsi_eh_get_sense), scmd->result is already
- * set, do not set DRIVER_TIMEOUT.
+ * set, do not set DID_TIME_OUT.
*/
if (!scmd->result)
- scmd->result |= (DRIVER_TIMEOUT << 24);
+ scmd->result |= (DID_TIME_OUT << 16);
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
"%s: flush finish cmd\n",
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 14872c9dc78c..0d13610cd6bf 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -101,8 +101,9 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
SCSI_LOG_IOCTL(2, sdev_printk(KERN_INFO, sdev,
"Ioctl returned 0x%x\n", result));
- if (driver_byte(result) == DRIVER_SENSE &&
- scsi_sense_valid(&sshdr)) {
+ if (result < 0)
+ goto out;
+ if (scsi_sense_valid(&sshdr)) {
switch (sshdr.sense_key) {
case ILLEGAL_REQUEST:
if (cmd[0] == ALLOW_MEDIUM_REMOVAL)
@@ -133,7 +134,7 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
break;
}
}
-
+out:
SCSI_LOG_IOCTL(2, sdev_printk(KERN_INFO, sdev,
"IOCTL Releasing command\n"));
return result;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 532304d42f00..7456a26aef51 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -194,7 +194,7 @@ void scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
* @bufflen: len of buffer
* @sense: optional sense buffer
* @sshdr: optional decoded sense header
- * @timeout: request timeout in seconds
+ * @timeout: request timeout in HZ
* @retries: number of times to retry request
* @flags: flags for ->cmd_flags
* @rq_flags: flags for ->rq_flags
@@ -211,20 +211,23 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
{
struct request *req;
struct scsi_request *rq;
- int ret = DRIVER_ERROR << 24;
+ int ret;
req = blk_get_request(sdev->request_queue,
data_direction == DMA_TO_DEVICE ?
- REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN,
+ REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
rq_flags & RQF_PM ? BLK_MQ_REQ_PM : 0);
if (IS_ERR(req))
- return ret;
- rq = scsi_req(req);
+ return PTR_ERR(req);
- if (bufflen && blk_rq_map_kern(sdev->request_queue, req,
- buffer, bufflen, GFP_NOIO))
- goto out;
+ rq = scsi_req(req);
+ if (bufflen) {
+ ret = blk_rq_map_kern(sdev->request_queue, req,
+ buffer, bufflen, GFP_NOIO);
+ if (ret)
+ goto out;
+ }
rq->cmd_len = COMMAND_SIZE(cmd[0]);
memcpy(rq->cmd, cmd, rq->cmd_len);
rq->retries = retries;
@@ -540,7 +543,7 @@ static bool scsi_end_request(struct request *req, blk_status_t error,
if (blk_queue_add_random(q))
add_disk_randomness(req->rq_disk);
- if (!blk_rq_is_scsi(req)) {
+ if (!blk_rq_is_passthrough(req)) {
WARN_ON_ONCE(!(cmd->flags & SCMD_INITIALIZED));
cmd->flags &= ~SCMD_INITIALIZED;
}
@@ -588,12 +591,7 @@ static blk_status_t scsi_result_to_blk_status(struct scsi_cmnd *cmd, int result)
{
switch (host_byte(result)) {
case DID_OK:
- /*
- * Also check the other bytes than the status byte in result
- * to handle the case when a SCSI LLD sets result to
- * DRIVER_SENSE << 24 without setting SAM_STAT_CHECK_CONDITION.
- */
- if (scsi_status_is_good(result) && (result & ~0xff) == 0)
+ if (scsi_status_is_good(result))
return BLK_STS_OK;
return BLK_STS_IOERR;
case DID_TRANSPORT_FAILFAST:
@@ -728,6 +726,7 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result)
case 0x07: /* operation in progress */
case 0x08: /* Long write in progress */
case 0x09: /* self test in progress */
+ case 0x11: /* notify (enable spinup) required */
case 0x14: /* space allocation in progress */
case 0x1a: /* start stop unit in progress */
case 0x1b: /* sanitize in progress */
@@ -787,7 +786,7 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result)
*/
if (!level && __ratelimit(&_rs)) {
scsi_print_result(cmd, NULL, FAILED);
- if (driver_byte(result) == DRIVER_SENSE)
+ if (sense_valid)
scsi_print_sense(cmd);
scsi_print_command(cmd);
}
@@ -875,7 +874,7 @@ static int scsi_io_completion_nz_result(struct scsi_cmnd *cmd, int result,
* if it can't fit). Treat SAM_STAT_CONDITION_MET and the related
* intermediate statuses (both obsolete in SAM-4) as good.
*/
- if (status_byte(result) && scsi_status_is_good(result)) {
+ if ((result & 0xff) && scsi_status_is_good(result)) {
result = 0;
*blk_statp = BLK_STS_OK;
}
@@ -1115,7 +1114,7 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd)
bool in_flight;
int budget_token = cmd->budget_token;
- if (!blk_rq_is_scsi(rq) && !(flags & SCMD_INITIALIZED)) {
+ if (!blk_rq_is_passthrough(rq) && !(flags & SCMD_INITIALIZED)) {
flags |= SCMD_INITIALIZED;
scsi_initialize_rq(rq);
}
@@ -1556,7 +1555,7 @@ static blk_status_t scsi_prepare_cmd(struct request *req)
* Special handling for passthrough commands, which don't go to the ULP
* at all:
*/
- if (blk_rq_is_scsi(req))
+ if (blk_rq_is_passthrough(req))
return scsi_setup_scsi_cmnd(sdev, req);
if (sdev->handler && sdev->handler->prep_fn) {
@@ -1899,18 +1898,6 @@ static const struct blk_mq_ops scsi_mq_ops = {
.get_rq_budget_token = scsi_mq_get_rq_budget_token,
};
-struct request_queue *scsi_mq_alloc_queue(struct scsi_device *sdev)
-{
- sdev->request_queue = blk_mq_init_queue(&sdev->host->tag_set);
- if (IS_ERR(sdev->request_queue))
- return NULL;
-
- sdev->request_queue->queuedata = sdev;
- __scsi_init_queue(sdev->host, sdev->request_queue);
- blk_queue_flag_set(QUEUE_FLAG_SCSI_PASSTHROUGH, sdev->request_queue);
- return sdev->request_queue;
-}
-
int scsi_mq_setup_tags(struct Scsi_Host *shost)
{
unsigned int cmd_size, sgl_size;
@@ -2093,9 +2080,7 @@ EXPORT_SYMBOL_GPL(scsi_mode_select);
* @sshdr: place to put sense data (or NULL if no sense to be collected).
* must be SCSI_SENSE_BUFFERSIZE big.
*
- * Returns zero if unsuccessful, or the header offset (either 4
- * or 8 depending on whether a six or ten byte command was
- * issued) if successful.
+ * Returns zero if successful, or a negative error number on failure
*/
int
scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
@@ -2142,58 +2127,60 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len,
sshdr, timeout, retries, NULL);
+ if (result < 0)
+ return result;
/* This code looks awful: what it's doing is making sure an
* ILLEGAL REQUEST sense return identifies the actual command
* byte as the problem. MODE_SENSE commands can return
* ILLEGAL REQUEST if the code page isn't supported */
- if (use_10_for_ms && !scsi_status_is_good(result) &&
- driver_byte(result) == DRIVER_SENSE) {
+ if (!scsi_status_is_good(result)) {
if (scsi_sense_valid(sshdr)) {
if ((sshdr->sense_key == ILLEGAL_REQUEST) &&
(sshdr->asc == 0x20) && (sshdr->ascq == 0)) {
/*
* Invalid command operation code
*/
- sdev->use_10_for_ms = 0;
+ if (use_10_for_ms) {
+ sdev->use_10_for_ms = 0;
+ goto retry;
+ }
+ }
+ if (scsi_status_is_check_condition(result) &&
+ sshdr->sense_key == UNIT_ATTENTION &&
+ retry_count) {
+ retry_count--;
goto retry;
}
}
+ return -EIO;
+ }
+ if (unlikely(buffer[0] == 0x86 && buffer[1] == 0x0b &&
+ (modepage == 6 || modepage == 8))) {
+ /* Initio breakage? */
+ header_length = 0;
+ data->length = 13;
+ data->medium_type = 0;
+ data->device_specific = 0;
+ data->longlba = 0;
+ data->block_descriptor_length = 0;
+ } else if (use_10_for_ms) {
+ data->length = buffer[0]*256 + buffer[1] + 2;
+ data->medium_type = buffer[2];
+ data->device_specific = buffer[3];
+ data->longlba = buffer[4] & 0x01;
+ data->block_descriptor_length = buffer[6]*256
+ + buffer[7];
+ } else {
+ data->length = buffer[0] + 1;
+ data->medium_type = buffer[1];
+ data->device_specific = buffer[2];
+ data->block_descriptor_length = buffer[3];
}
+ data->header_length = header_length;
- if (scsi_status_is_good(result)) {
- if (unlikely(buffer[0] == 0x86 && buffer[1] == 0x0b &&
- (modepage == 6 || modepage == 8))) {
- /* Initio breakage? */
- header_length = 0;
- data->length = 13;
- data->medium_type = 0;
- data->device_specific = 0;
- data->longlba = 0;
- data->block_descriptor_length = 0;
- } else if (use_10_for_ms) {
- data->length = buffer[0]*256 + buffer[1] + 2;
- data->medium_type = buffer[2];
- data->device_specific = buffer[3];
- data->longlba = buffer[4] & 0x01;
- data->block_descriptor_length = buffer[6]*256
- + buffer[7];
- } else {
- data->length = buffer[0] + 1;
- data->medium_type = buffer[1];
- data->device_specific = buffer[2];
- data->block_descriptor_length = buffer[3];
- }
- data->header_length = header_length;
- } else if ((status_byte(result) == CHECK_CONDITION) &&
- scsi_sense_valid(sshdr) &&
- sshdr->sense_key == UNIT_ATTENTION && retry_count) {
- retry_count--;
- goto retry;
- }
-
- return result;
+ return 0;
}
EXPORT_SYMBOL(scsi_mode_sense);
@@ -3218,3 +3205,20 @@ int scsi_vpd_tpg_id(struct scsi_device *sdev, int *rel_id)
return group_id;
}
EXPORT_SYMBOL(scsi_vpd_tpg_id);
+
+/**
+ * scsi_build_sense - build sense data for a command
+ * @scmd: scsi command for which the sense should be formatted
+ * @desc: Sense format (non-zero == descriptor format,
+ * 0 == fixed format)
+ * @key: Sense key
+ * @asc: Additional sense code
+ * @ascq: Additional sense code qualifier
+ *
+ **/
+void scsi_build_sense(struct scsi_cmnd *scmd, int desc, u8 key, u8 asc, u8 ascq)
+{
+ scsi_build_sense_buffer(desc, scmd->sense_buffer, key, asc, ascq);
+ scmd->result = SAM_STAT_CHECK_CONDITION;
+}
+EXPORT_SYMBOL_GPL(scsi_build_sense);
diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c
index 8ea44c6595ef..2317717935e9 100644
--- a/drivers/scsi/scsi_logging.c
+++ b/drivers/scsi/scsi_logging.c
@@ -385,7 +385,6 @@ void scsi_print_result(const struct scsi_cmnd *cmd, const char *msg,
size_t off, logbuf_len;
const char *mlret_string = scsi_mlreturn_string(disposition);
const char *hb_string = scsi_hostbyte_string(cmd->result);
- const char *db_string = scsi_driverbyte_string(cmd->result);
unsigned long cmd_age = (jiffies - cmd->jiffies_at_alloc) / HZ;
logbuf = scsi_log_reserve_buffer(&logbuf_len);
@@ -426,13 +425,8 @@ void scsi_print_result(const struct scsi_cmnd *cmd, const char *msg,
if (WARN_ON(off >= logbuf_len))
goto out_printk;
- if (db_string)
- off += scnprintf(logbuf + off, logbuf_len - off,
- "driverbyte=%s ", db_string);
- else
- off += scnprintf(logbuf + off, logbuf_len - off,
- "driverbyte=0x%02x ",
- driver_byte(cmd->result));
+ off += scnprintf(logbuf + off, logbuf_len - off,
+ "driverbyte=DRIVER_OK ");
off += scnprintf(logbuf + off, logbuf_len - off,
"cmd_age=%lus", cmd_age);
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 75d6f23e4fff..eae2235f79b5 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -91,7 +91,6 @@ extern void scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
extern void scsi_run_host_queues(struct Scsi_Host *shost);
extern void scsi_requeue_run_queue(struct work_struct *work);
-extern struct request_queue *scsi_mq_alloc_queue(struct scsi_device *sdev);
extern void scsi_start_queue(struct scsi_device *sdev);
extern int scsi_mq_setup_tags(struct Scsi_Host *shost);
extern void scsi_mq_destroy_tags(struct Scsi_Host *shost);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 12f54571b83e..b059bf2b61d4 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -217,6 +217,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
{
unsigned int depth;
struct scsi_device *sdev;
+ struct request_queue *q;
int display_failure_msg = 1, ret;
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
@@ -266,16 +267,19 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
*/
sdev->borken = 1;
- sdev->request_queue = scsi_mq_alloc_queue(sdev);
- if (!sdev->request_queue) {
+ q = blk_mq_init_queue(&sdev->host->tag_set);
+ if (IS_ERR(q)) {
/* release fn is set up in scsi_sysfs_device_initialise, so
* have to free and put manually here */
put_device(&starget->dev);
kfree(sdev);
goto out;
}
- WARN_ON_ONCE(!blk_get_queue(sdev->request_queue));
- sdev->request_queue->queuedata = sdev;
+ sdev->request_queue = q;
+ q->queuedata = sdev;
+ __scsi_init_queue(sdev->host, q);
+ blk_queue_flag_set(QUEUE_FLAG_SCSI_PASSTHROUGH, q);
+ WARN_ON_ONCE(!blk_get_queue(q));
depth = sdev->host->cmd_per_lun ?: 1;
@@ -616,14 +620,14 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
"scsi scan: INQUIRY %s with code 0x%x\n",
result ? "failed" : "successful", result));
- if (result) {
+ if (result > 0) {
/*
* not-ready to ready transition [asc/ascq=0x28/0x0]
* or power-on, reset [asc/ascq=0x29/0x0], continue.
* INQUIRY should not yield UNIT_ATTENTION
* but many buggy devices do so anyway.
*/
- if (driver_byte(result) == DRIVER_SENSE &&
+ if (scsi_status_is_check_condition(result) &&
scsi_sense_valid(&sshdr)) {
if ((sshdr.sense_key == UNIT_ATTENTION) &&
((sshdr.asc == 0x28) ||
@@ -631,7 +635,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
(sshdr.ascq == 0))
continue;
}
- } else {
+ } else if (result == 0) {
/*
* if nothing was transferred, we try
* again. It's a workaround for some USB
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index da5b503dc7a1..49748cd817a5 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -1686,7 +1686,7 @@ store_fc_vport_delete(struct device *dev, struct device_attribute *attr,
unsigned long flags;
spin_lock_irqsave(shost->host_lock, flags);
- if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING | FC_VPORT_DELETING)) {
+ if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) {
spin_unlock_irqrestore(shost->host_lock, flags);
return -EBUSY;
}
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 441f0152193f..b07105ae7c91 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -86,16 +86,10 @@ struct iscsi_internal {
struct transport_container session_cont;
};
-/* Worker to perform connection failure on unresponsive connections
- * completely in kernel space.
- */
-static void stop_conn_work_fn(struct work_struct *work);
-static DECLARE_WORK(stop_conn_work, stop_conn_work_fn);
-
static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
static struct workqueue_struct *iscsi_eh_timer_workq;
-static struct workqueue_struct *iscsi_destroy_workq;
+static struct workqueue_struct *iscsi_conn_cleanup_workq;
static DEFINE_IDA(iscsi_sess_ida);
/*
@@ -268,9 +262,20 @@ void iscsi_destroy_endpoint(struct iscsi_endpoint *ep)
}
EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint);
+void iscsi_put_endpoint(struct iscsi_endpoint *ep)
+{
+ put_device(&ep->dev);
+}
+EXPORT_SYMBOL_GPL(iscsi_put_endpoint);
+
+/**
+ * iscsi_lookup_endpoint - get ep from handle
+ * @handle: endpoint handle
+ *
+ * Caller must do a iscsi_put_endpoint.
+ */
struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
{
- struct iscsi_endpoint *ep;
struct device *dev;
dev = class_find_device(&iscsi_endpoint_class, NULL, &handle,
@@ -278,13 +283,7 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
if (!dev)
return NULL;
- ep = iscsi_dev_to_endpoint(dev);
- /*
- * we can drop this now because the interface will prevent
- * removals and lookups from racing.
- */
- put_device(dev);
- return ep;
+ return iscsi_dev_to_endpoint(dev);
}
EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
@@ -1620,12 +1619,6 @@ static DECLARE_TRANSPORT_CLASS(iscsi_connection_class,
static struct sock *nls;
static DEFINE_MUTEX(rx_queue_mutex);
-/*
- * conn_mutex protects the {start,bind,stop,destroy}_conn from racing
- * against the kernel stop_connection recovery mechanism
- */
-static DEFINE_MUTEX(conn_mutex);
-
static LIST_HEAD(sesslist);
static DEFINE_SPINLOCK(sesslock);
static LIST_HEAD(connlist);
@@ -1976,6 +1969,8 @@ static void __iscsi_unblock_session(struct work_struct *work)
*/
void iscsi_unblock_session(struct iscsi_cls_session *session)
{
+ flush_work(&session->block_work);
+
queue_work(iscsi_eh_timer_workq, &session->unblock_work);
/*
* Blocking the session can be done from any context so we only
@@ -2242,6 +2237,123 @@ void iscsi_remove_session(struct iscsi_cls_session *session)
}
EXPORT_SYMBOL_GPL(iscsi_remove_session);
+static void iscsi_stop_conn(struct iscsi_cls_conn *conn, int flag)
+{
+ ISCSI_DBG_TRANS_CONN(conn, "Stopping conn.\n");
+
+ switch (flag) {
+ case STOP_CONN_RECOVER:
+ conn->state = ISCSI_CONN_FAILED;
+ break;
+ case STOP_CONN_TERM:
+ conn->state = ISCSI_CONN_DOWN;
+ break;
+ default:
+ iscsi_cls_conn_printk(KERN_ERR, conn, "invalid stop flag %d\n",
+ flag);
+ return;
+ }
+
+ conn->transport->stop_conn(conn, flag);
+ ISCSI_DBG_TRANS_CONN(conn, "Stopping conn done.\n");
+}
+
+static int iscsi_if_stop_conn(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ int flag = ev->u.stop_conn.flag;
+ struct iscsi_cls_conn *conn;
+
+ conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid);
+ if (!conn)
+ return -EINVAL;
+
+ ISCSI_DBG_TRANS_CONN(conn, "iscsi if conn stop.\n");
+ /*
+ * If this is a termination we have to call stop_conn with that flag
+ * so the correct states get set. If we haven't run the work yet try to
+ * avoid the extra run.
+ */
+ if (flag == STOP_CONN_TERM) {
+ cancel_work_sync(&conn->cleanup_work);
+ iscsi_stop_conn(conn, flag);
+ } else {
+ /*
+ * Figure out if it was the kernel or userspace initiating this.
+ */
+ if (!test_and_set_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags)) {
+ iscsi_stop_conn(conn, flag);
+ } else {
+ ISCSI_DBG_TRANS_CONN(conn,
+ "flush kernel conn cleanup.\n");
+ flush_work(&conn->cleanup_work);
+ }
+ /*
+ * Only clear for recovery to avoid extra cleanup runs during
+ * termination.
+ */
+ clear_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags);
+ }
+ ISCSI_DBG_TRANS_CONN(conn, "iscsi if conn stop done.\n");
+ return 0;
+}
+
+static void iscsi_ep_disconnect(struct iscsi_cls_conn *conn, bool is_active)
+{
+ struct iscsi_cls_session *session = iscsi_conn_to_session(conn);
+ struct iscsi_endpoint *ep;
+
+ ISCSI_DBG_TRANS_CONN(conn, "disconnect ep.\n");
+ conn->state = ISCSI_CONN_FAILED;
+
+ if (!conn->ep || !session->transport->ep_disconnect)
+ return;
+
+ ep = conn->ep;
+ conn->ep = NULL;
+
+ session->transport->unbind_conn(conn, is_active);
+ session->transport->ep_disconnect(ep);
+ ISCSI_DBG_TRANS_CONN(conn, "disconnect ep done.\n");
+}
+
+static void iscsi_cleanup_conn_work_fn(struct work_struct *work)
+{
+ struct iscsi_cls_conn *conn = container_of(work, struct iscsi_cls_conn,
+ cleanup_work);
+ struct iscsi_cls_session *session = iscsi_conn_to_session(conn);
+
+ mutex_lock(&conn->ep_mutex);
+ /*
+ * If we are not at least bound there is nothing for us to do. Userspace
+ * will do a ep_disconnect call if offload is used, but will not be
+ * doing a stop since there is nothing to clean up, so we have to clear
+ * the cleanup bit here.
+ */
+ if (conn->state != ISCSI_CONN_BOUND && conn->state != ISCSI_CONN_UP) {
+ ISCSI_DBG_TRANS_CONN(conn, "Got error while conn is already failed. Ignoring.\n");
+ clear_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags);
+ mutex_unlock(&conn->ep_mutex);
+ return;
+ }
+
+ iscsi_ep_disconnect(conn, false);
+
+ if (system_state != SYSTEM_RUNNING) {
+ /*
+ * If the user has set up for the session to never timeout
+ * then hang like they wanted. For all other cases fail right
+ * away since userspace is not going to relogin.
+ */
+ if (session->recovery_tmo > 0)
+ session->recovery_tmo = 0;
+ }
+
+ iscsi_stop_conn(conn, STOP_CONN_RECOVER);
+ mutex_unlock(&conn->ep_mutex);
+ ISCSI_DBG_TRANS_CONN(conn, "cleanup done.\n");
+}
+
void iscsi_free_session(struct iscsi_cls_session *session)
{
ISCSI_DBG_TRANS_SESSION(session, "Freeing session\n");
@@ -2281,7 +2393,7 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
mutex_init(&conn->ep_mutex);
INIT_LIST_HEAD(&conn->conn_list);
- INIT_LIST_HEAD(&conn->conn_list_err);
+ INIT_WORK(&conn->cleanup_work, iscsi_cleanup_conn_work_fn);
conn->transport = transport;
conn->cid = cid;
conn->state = ISCSI_CONN_DOWN;
@@ -2338,7 +2450,6 @@ int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
spin_lock_irqsave(&connlock, flags);
list_del(&conn->conn_list);
- list_del(&conn->conn_list_err);
spin_unlock_irqrestore(&connlock, flags);
transport_unregister_device(&conn->dev);
@@ -2348,6 +2459,18 @@ int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
}
EXPORT_SYMBOL_GPL(iscsi_destroy_conn);
+void iscsi_put_conn(struct iscsi_cls_conn *conn)
+{
+ put_device(&conn->dev);
+}
+EXPORT_SYMBOL_GPL(iscsi_put_conn);
+
+void iscsi_get_conn(struct iscsi_cls_conn *conn)
+{
+ get_device(&conn->dev);
+}
+EXPORT_SYMBOL_GPL(iscsi_get_conn);
+
/*
* iscsi interface functions
*/
@@ -2453,77 +2576,6 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
}
EXPORT_SYMBOL_GPL(iscsi_offload_mesg);
-/*
- * This can be called without the rx_queue_mutex, if invoked by the kernel
- * stop work. But, in that case, it is guaranteed not to race with
- * iscsi_destroy by conn_mutex.
- */
-static void iscsi_if_stop_conn(struct iscsi_cls_conn *conn, int flag)
-{
- /*
- * It is important that this path doesn't rely on
- * rx_queue_mutex, otherwise, a thread doing allocation on a
- * start_session/start_connection could sleep waiting on a
- * writeback to a failed iscsi device, that cannot be recovered
- * because the lock is held. If we don't hold it here, the
- * kernel stop_conn_work_fn has a chance to stop the broken
- * session and resolve the allocation.
- *
- * Still, the user invoked .stop_conn() needs to be serialized
- * with stop_conn_work_fn by a private mutex. Not pretty, but
- * it works.
- */
- mutex_lock(&conn_mutex);
- switch (flag) {
- case STOP_CONN_RECOVER:
- conn->state = ISCSI_CONN_FAILED;
- break;
- case STOP_CONN_TERM:
- conn->state = ISCSI_CONN_DOWN;
- break;
- default:
- iscsi_cls_conn_printk(KERN_ERR, conn,
- "invalid stop flag %d\n", flag);
- goto unlock;
- }
-
- conn->transport->stop_conn(conn, flag);
-unlock:
- mutex_unlock(&conn_mutex);
-}
-
-static void stop_conn_work_fn(struct work_struct *work)
-{
- struct iscsi_cls_conn *conn, *tmp;
- unsigned long flags;
- LIST_HEAD(recovery_list);
-
- spin_lock_irqsave(&connlock, flags);
- if (list_empty(&connlist_err)) {
- spin_unlock_irqrestore(&connlock, flags);
- return;
- }
- list_splice_init(&connlist_err, &recovery_list);
- spin_unlock_irqrestore(&connlock, flags);
-
- list_for_each_entry_safe(conn, tmp, &recovery_list, conn_list_err) {
- uint32_t sid = iscsi_conn_get_sid(conn);
- struct iscsi_cls_session *session;
-
- session = iscsi_session_lookup(sid);
- if (session) {
- if (system_state != SYSTEM_RUNNING) {
- session->recovery_tmo = 0;
- iscsi_if_stop_conn(conn, STOP_CONN_TERM);
- } else {
- iscsi_if_stop_conn(conn, STOP_CONN_RECOVER);
- }
- }
-
- list_del_init(&conn->conn_list_err);
- }
-}
-
void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
{
struct nlmsghdr *nlh;
@@ -2531,12 +2583,9 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
struct iscsi_uevent *ev;
struct iscsi_internal *priv;
int len = nlmsg_total_size(sizeof(*ev));
- unsigned long flags;
- spin_lock_irqsave(&connlock, flags);
- list_add(&conn->conn_list_err, &connlist_err);
- spin_unlock_irqrestore(&connlock, flags);
- queue_work(system_unbound_wq, &stop_conn_work);
+ if (!test_and_set_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags))
+ queue_work(iscsi_conn_cleanup_workq, &conn->cleanup_work);
priv = iscsi_if_transport_lookup(conn->transport);
if (!priv)
@@ -2866,26 +2915,17 @@ static int
iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
{
struct iscsi_cls_conn *conn;
- unsigned long flags;
conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);
if (!conn)
return -EINVAL;
- spin_lock_irqsave(&connlock, flags);
- if (!list_empty(&conn->conn_list_err)) {
- spin_unlock_irqrestore(&connlock, flags);
- return -EAGAIN;
- }
- spin_unlock_irqrestore(&connlock, flags);
-
+ ISCSI_DBG_TRANS_CONN(conn, "Flushing cleanup during destruction\n");
+ flush_work(&conn->cleanup_work);
ISCSI_DBG_TRANS_CONN(conn, "Destroying transport conn\n");
- mutex_lock(&conn_mutex);
if (transport->destroy_conn)
transport->destroy_conn(conn);
- mutex_unlock(&conn_mutex);
-
return 0;
}
@@ -2975,15 +3015,31 @@ static int iscsi_if_ep_disconnect(struct iscsi_transport *transport,
ep = iscsi_lookup_endpoint(ep_handle);
if (!ep)
return -EINVAL;
+
conn = ep->conn;
- if (conn) {
- mutex_lock(&conn->ep_mutex);
- conn->ep = NULL;
+ if (!conn) {
+ /*
+ * conn was not even bound yet, so we can't get iscsi conn
+ * failures yet.
+ */
+ transport->ep_disconnect(ep);
+ goto put_ep;
+ }
+
+ mutex_lock(&conn->ep_mutex);
+ /* Check if this was a conn error and the kernel took ownership */
+ if (test_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags)) {
+ ISCSI_DBG_TRANS_CONN(conn, "flush kernel conn cleanup.\n");
mutex_unlock(&conn->ep_mutex);
- conn->state = ISCSI_CONN_FAILED;
+
+ flush_work(&conn->cleanup_work);
+ goto put_ep;
}
- transport->ep_disconnect(ep);
+ iscsi_ep_disconnect(conn, false);
+ mutex_unlock(&conn->ep_mutex);
+put_ep:
+ iscsi_put_endpoint(ep);
return 0;
}
@@ -3009,6 +3065,7 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
ev->r.retcode = transport->ep_poll(ep,
ev->u.ep_poll.timeout_ms);
+ iscsi_put_endpoint(ep);
break;
case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
rc = iscsi_if_ep_disconnect(transport,
@@ -3639,18 +3696,129 @@ exit_host_stats:
return err;
}
+static int iscsi_if_transport_conn(struct iscsi_transport *transport,
+ struct nlmsghdr *nlh)
+{
+ struct iscsi_uevent *ev = nlmsg_data(nlh);
+ struct iscsi_cls_session *session;
+ struct iscsi_cls_conn *conn = NULL;
+ struct iscsi_endpoint *ep;
+ uint32_t pdu_len;
+ int err = 0;
+
+ switch (nlh->nlmsg_type) {
+ case ISCSI_UEVENT_CREATE_CONN:
+ return iscsi_if_create_conn(transport, ev);
+ case ISCSI_UEVENT_DESTROY_CONN:
+ return iscsi_if_destroy_conn(transport, ev);
+ case ISCSI_UEVENT_STOP_CONN:
+ return iscsi_if_stop_conn(transport, ev);
+ }
+
+ /*
+ * The following cmds need to be run under the ep_mutex so in kernel
+ * conn cleanup (ep_disconnect + unbind and conn) is not done while
+ * these are running. They also must not run if we have just run a conn
+ * cleanup because they would set the state in a way that might allow
+ * IO or send IO themselves.
+ */
+ switch (nlh->nlmsg_type) {
+ case ISCSI_UEVENT_START_CONN:
+ conn = iscsi_conn_lookup(ev->u.start_conn.sid,
+ ev->u.start_conn.cid);
+ break;
+ case ISCSI_UEVENT_BIND_CONN:
+ conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid);
+ break;
+ case ISCSI_UEVENT_SEND_PDU:
+ conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid);
+ break;
+ }
+
+ if (!conn)
+ return -EINVAL;
+
+ mutex_lock(&conn->ep_mutex);
+ if (test_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags)) {
+ mutex_unlock(&conn->ep_mutex);
+ ev->r.retcode = -ENOTCONN;
+ return 0;
+ }
+
+ switch (nlh->nlmsg_type) {
+ case ISCSI_UEVENT_BIND_CONN:
+ if (conn->ep) {
+ /*
+ * For offload boot support where iscsid is restarted
+ * during the pivot root stage, the ep will be intact
+ * here when the new iscsid instance starts up and
+ * reconnects.
+ */
+ iscsi_ep_disconnect(conn, true);
+ }
+
+ session = iscsi_session_lookup(ev->u.b_conn.sid);
+ if (!session) {
+ err = -EINVAL;
+ break;
+ }
+
+ ev->r.retcode = transport->bind_conn(session, conn,
+ ev->u.b_conn.transport_eph,
+ ev->u.b_conn.is_leading);
+ if (!ev->r.retcode)
+ conn->state = ISCSI_CONN_BOUND;
+
+ if (ev->r.retcode || !transport->ep_connect)
+ break;
+
+ ep = iscsi_lookup_endpoint(ev->u.b_conn.transport_eph);
+ if (ep) {
+ ep->conn = conn;
+ conn->ep = ep;
+ iscsi_put_endpoint(ep);
+ } else {
+ err = -ENOTCONN;
+ iscsi_cls_conn_printk(KERN_ERR, conn,
+ "Could not set ep conn binding\n");
+ }
+ break;
+ case ISCSI_UEVENT_START_CONN:
+ ev->r.retcode = transport->start_conn(conn);
+ if (!ev->r.retcode)
+ conn->state = ISCSI_CONN_UP;
+ break;
+ case ISCSI_UEVENT_SEND_PDU:
+ pdu_len = nlh->nlmsg_len - sizeof(*nlh) - sizeof(*ev);
+
+ if ((ev->u.send_pdu.hdr_size > pdu_len) ||
+ (ev->u.send_pdu.data_size > (pdu_len - ev->u.send_pdu.hdr_size))) {
+ err = -EINVAL;
+ break;
+ }
+
+ ev->r.retcode = transport->send_pdu(conn,
+ (struct iscsi_hdr *)((char *)ev + sizeof(*ev)),
+ (char *)ev + sizeof(*ev) + ev->u.send_pdu.hdr_size,
+ ev->u.send_pdu.data_size);
+ break;
+ default:
+ err = -ENOSYS;
+ }
+
+ mutex_unlock(&conn->ep_mutex);
+ return err;
+}
static int
iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
{
int err = 0;
u32 portid;
- u32 pdu_len;
struct iscsi_uevent *ev = nlmsg_data(nlh);
struct iscsi_transport *transport = NULL;
struct iscsi_internal *priv;
struct iscsi_cls_session *session;
- struct iscsi_cls_conn *conn;
struct iscsi_endpoint *ep = NULL;
if (!netlink_capable(skb, CAP_SYS_ADMIN))
@@ -3691,6 +3859,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
ev->u.c_bound_session.initial_cmdsn,
ev->u.c_bound_session.cmds_max,
ev->u.c_bound_session.queue_depth);
+ iscsi_put_endpoint(ep);
break;
case ISCSI_UEVENT_DESTROY_SESSION:
session = iscsi_session_lookup(ev->u.d_session.sid);
@@ -3715,7 +3884,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
list_del_init(&session->sess_list);
spin_unlock_irqrestore(&sesslock, flags);
- queue_work(iscsi_destroy_workq, &session->destroy_work);
+ queue_work(system_unbound_wq, &session->destroy_work);
}
break;
case ISCSI_UEVENT_UNBIND_SESSION:
@@ -3726,89 +3895,16 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
else
err = -EINVAL;
break;
- case ISCSI_UEVENT_CREATE_CONN:
- err = iscsi_if_create_conn(transport, ev);
- break;
- case ISCSI_UEVENT_DESTROY_CONN:
- err = iscsi_if_destroy_conn(transport, ev);
- break;
- case ISCSI_UEVENT_BIND_CONN:
- session = iscsi_session_lookup(ev->u.b_conn.sid);
- conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid);
-
- if (conn && conn->ep)
- iscsi_if_ep_disconnect(transport, conn->ep->id);
-
- if (!session || !conn) {
- err = -EINVAL;
- break;
- }
-
- mutex_lock(&conn_mutex);
- ev->r.retcode = transport->bind_conn(session, conn,
- ev->u.b_conn.transport_eph,
- ev->u.b_conn.is_leading);
- if (!ev->r.retcode)
- conn->state = ISCSI_CONN_BOUND;
- mutex_unlock(&conn_mutex);
-
- if (ev->r.retcode || !transport->ep_connect)
- break;
-
- ep = iscsi_lookup_endpoint(ev->u.b_conn.transport_eph);
- if (ep) {
- ep->conn = conn;
-
- mutex_lock(&conn->ep_mutex);
- conn->ep = ep;
- mutex_unlock(&conn->ep_mutex);
- } else
- iscsi_cls_conn_printk(KERN_ERR, conn,
- "Could not set ep conn "
- "binding\n");
- break;
case ISCSI_UEVENT_SET_PARAM:
err = iscsi_set_param(transport, ev);
break;
- case ISCSI_UEVENT_START_CONN:
- conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid);
- if (conn) {
- mutex_lock(&conn_mutex);
- ev->r.retcode = transport->start_conn(conn);
- if (!ev->r.retcode)
- conn->state = ISCSI_CONN_UP;
- mutex_unlock(&conn_mutex);
- }
- else
- err = -EINVAL;
- break;
+ case ISCSI_UEVENT_CREATE_CONN:
+ case ISCSI_UEVENT_DESTROY_CONN:
case ISCSI_UEVENT_STOP_CONN:
- conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid);
- if (conn)
- iscsi_if_stop_conn(conn, ev->u.stop_conn.flag);
- else
- err = -EINVAL;
- break;
+ case ISCSI_UEVENT_START_CONN:
+ case ISCSI_UEVENT_BIND_CONN:
case ISCSI_UEVENT_SEND_PDU:
- pdu_len = nlh->nlmsg_len - sizeof(*nlh) - sizeof(*ev);
-
- if ((ev->u.send_pdu.hdr_size > pdu_len) ||
- (ev->u.send_pdu.data_size > (pdu_len - ev->u.send_pdu.hdr_size))) {
- err = -EINVAL;
- break;
- }
-
- conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid);
- if (conn) {
- mutex_lock(&conn_mutex);
- ev->r.retcode = transport->send_pdu(conn,
- (struct iscsi_hdr*)((char*)ev + sizeof(*ev)),
- (char*)ev + sizeof(*ev) + ev->u.send_pdu.hdr_size,
- ev->u.send_pdu.data_size);
- mutex_unlock(&conn_mutex);
- }
- else
- err = -EINVAL;
+ err = iscsi_if_transport_conn(transport, nlh);
break;
case ISCSI_UEVENT_GET_STATS:
err = iscsi_if_get_stats(transport, nlh);
@@ -4656,6 +4752,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
int err;
BUG_ON(!tt);
+ WARN_ON(tt->ep_disconnect && !tt->unbind_conn);
priv = iscsi_if_transport_lookup(tt);
if (priv)
@@ -4810,10 +4907,10 @@ static __init int iscsi_transport_init(void)
goto release_nls;
}
- iscsi_destroy_workq = alloc_workqueue("%s",
- WQ_SYSFS | __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_UNBOUND,
- 1, "iscsi_destroy");
- if (!iscsi_destroy_workq) {
+ iscsi_conn_cleanup_workq = alloc_workqueue("%s",
+ WQ_SYSFS | WQ_MEM_RECLAIM | WQ_UNBOUND, 0,
+ "iscsi_conn_cleanup");
+ if (!iscsi_conn_cleanup_workq) {
err = -ENOMEM;
goto destroy_wq;
}
@@ -4843,7 +4940,7 @@ unregister_transport_class:
static void __exit iscsi_transport_exit(void)
{
- destroy_workqueue(iscsi_destroy_workq);
+ destroy_workqueue(iscsi_conn_cleanup_workq);
destroy_workqueue(iscsi_eh_timer_workq);
netlink_kernel_release(nls);
bus_unregister(&iscsi_flashnode_bus);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index c9abed8429c9..4a96fb05731d 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -1229,16 +1229,15 @@ int sas_read_port_mode_page(struct scsi_device *sdev)
char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata;
struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
struct scsi_mode_data mode_data;
- int res, error;
+ int error;
if (!buffer)
return -ENOMEM;
- res = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3,
- &mode_data, NULL);
+ error = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3,
+ &mode_data, NULL);
- error = -EINVAL;
- if (!scsi_status_is_good(res))
+ if (error)
goto out;
msdata = buffer + mode_data.header_length +
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index c37dd15d16d2..5af7a10e9514 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -127,7 +127,7 @@ static int spi_execute(struct scsi_device *sdev, const void *cmd,
REQ_FAILFAST_TRANSPORT |
REQ_FAILFAST_DRIVER,
RQF_PM, NULL);
- if (driver_byte(result) != DRIVER_SENSE ||
+ if (result < 0 || !scsi_sense_valid(sshdr) ||
sshdr->sense_key != UNIT_ATTENTION)
break;
}
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index cb3c37d1e009..b8d55af763f9 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -98,11 +98,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD);
MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
MODULE_ALIAS_SCSI_DEVICE(TYPE_ZBC);
-#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
#define SD_MINORS 16
-#else
-#define SD_MINORS 0
-#endif
static void sd_config_discard(struct scsi_disk *, unsigned int);
static void sd_config_write_same(struct scsi_disk *);
@@ -1387,6 +1383,22 @@ static void sd_uninit_command(struct scsi_cmnd *SCpnt)
}
}
+static bool sd_need_revalidate(struct block_device *bdev,
+ struct scsi_disk *sdkp)
+{
+ if (sdkp->device->removable || sdkp->write_prot) {
+ if (bdev_check_media_change(bdev))
+ return true;
+ }
+
+ /*
+ * Force a full rescan after ioctl(BLKRRPART). While the disk state has
+ * nothing to do with partitions, BLKRRPART is used to force a full
+ * revalidate after things like a format for historical reasons.
+ */
+ return test_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state);
+}
+
/**
* sd_open - open a scsi disk device
* @bdev: Block device of the scsi disk to open
@@ -1400,7 +1412,7 @@ static void sd_uninit_command(struct scsi_cmnd *SCpnt)
* In the latter case @inode and @filp carry an abridged amount
* of information as noted above.
*
- * Locking: called with bdev->bd_mutex held.
+ * Locking: called with bdev->bd_disk->open_mutex held.
**/
static int sd_open(struct block_device *bdev, fmode_t mode)
{
@@ -1423,10 +1435,8 @@ static int sd_open(struct block_device *bdev, fmode_t mode)
if (!scsi_block_when_processing_errors(sdev))
goto error_out;
- if (sdev->removable || sdkp->write_prot) {
- if (bdev_check_media_change(bdev))
- sd_revalidate_disk(bdev->bd_disk);
- }
+ if (sd_need_revalidate(bdev, sdkp))
+ sd_revalidate_disk(bdev->bd_disk);
/*
* If the drive is empty, just let the open fail.
@@ -1476,7 +1486,7 @@ error_out:
* Note: may block (uninterruptible) if error recovery is underway
* on this disk.
*
- * Locking: called with bdev->bd_mutex held.
+ * Locking: called with bdev->bd_disk->open_mutex held.
**/
static void sd_release(struct gendisk *disk, fmode_t mode)
{
@@ -1658,7 +1668,7 @@ static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing)
&sshdr);
/* failed to execute TUR, assume media not present */
- if (host_byte(retval)) {
+ if (retval < 0 || host_byte(retval)) {
set_media_not_present(sdkp);
goto out;
}
@@ -1719,16 +1729,20 @@ static int sd_sync_cache(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr)
if (res) {
sd_print_result(sdkp, "Synchronize Cache(10) failed", res);
- if (driver_byte(res) == DRIVER_SENSE)
+ if (res < 0)
+ return res;
+
+ if (scsi_status_is_check_condition(res) &&
+ scsi_sense_valid(sshdr)) {
sd_print_sense_hdr(sdkp, sshdr);
- /* we need to evaluate the error return */
- if (scsi_sense_valid(sshdr) &&
- (sshdr->asc == 0x3a || /* medium not present */
- sshdr->asc == 0x20 || /* invalid command */
- (sshdr->asc == 0x74 && sshdr->ascq == 0x71))) /* drive is password locked */
+ /* we need to evaluate the error return */
+ if (sshdr->asc == 0x3a || /* medium not present */
+ sshdr->asc == 0x20 || /* invalid command */
+ (sshdr->asc == 0x74 && sshdr->ascq == 0x71)) /* drive is password locked */
/* this is no error here */
return 0;
+ }
switch (host_byte(res)) {
/* ignore errors due to racing a disconnection */
@@ -1825,7 +1839,7 @@ static int sd_pr_command(struct block_device *bdev, u8 sa,
result = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, &data, sizeof(data),
&sshdr, SD_TIMEOUT, sdkp->max_retries, NULL);
- if (driver_byte(result) == DRIVER_SENSE &&
+ if (scsi_status_is_check_condition(result) &&
scsi_sense_valid(&sshdr)) {
sdev_printk(KERN_INFO, sdev, "PR command failed: %d\n", result);
scsi_print_sense_hdr(sdev, NULL, &sshdr);
@@ -2069,7 +2083,7 @@ static int sd_done(struct scsi_cmnd *SCpnt)
}
sdkp->medium_access_timed_out = 0;
- if (driver_byte(result) != DRIVER_SENSE &&
+ if (!scsi_status_is_check_condition(result) &&
(!sense_valid || sense_deferred))
goto out;
@@ -2172,12 +2186,12 @@ sd_spinup_disk(struct scsi_disk *sdkp)
if (the_result)
sense_valid = scsi_sense_valid(&sshdr);
retries++;
- } while (retries < 3 &&
+ } while (retries < 3 &&
(!scsi_status_is_good(the_result) ||
- ((driver_byte(the_result) == DRIVER_SENSE) &&
+ (scsi_status_is_check_condition(the_result) &&
sense_valid && sshdr.sense_key == UNIT_ATTENTION)));
- if (driver_byte(the_result) != DRIVER_SENSE) {
+ if (!scsi_status_is_check_condition(the_result)) {
/* no sense, TUR either succeeded or failed
* with a status error */
if(!spintime && !scsi_status_is_good(the_result)) {
@@ -2305,7 +2319,7 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
struct scsi_sense_hdr *sshdr, int sense_valid,
int the_result)
{
- if (driver_byte(the_result) == DRIVER_SENSE)
+ if (sense_valid)
sd_print_sense_hdr(sdkp, sshdr);
else
sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n");
@@ -2362,7 +2376,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
if (media_not_present(sdkp, &sshdr))
return -ENODEV;
- if (the_result) {
+ if (the_result > 0) {
sense_valid = scsi_sense_valid(&sshdr);
if (sense_valid &&
sshdr.sense_key == ILLEGAL_REQUEST &&
@@ -2447,7 +2461,7 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
if (media_not_present(sdkp, &sshdr))
return -ENODEV;
- if (the_result) {
+ if (the_result > 0) {
sense_valid = scsi_sense_valid(&sshdr);
if (sense_valid &&
sshdr.sense_key == UNIT_ATTENTION &&
@@ -2670,18 +2684,18 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
* 5: Illegal Request, Sense Code 24: Invalid field in
* CDB.
*/
- if (!scsi_status_is_good(res))
+ if (res < 0)
res = sd_do_mode_sense(sdkp, 0, 0, buffer, 4, &data, NULL);
/*
* Third attempt: ask 255 bytes, as we did earlier.
*/
- if (!scsi_status_is_good(res))
+ if (res < 0)
res = sd_do_mode_sense(sdkp, 0, 0x3F, buffer, 255,
&data, NULL);
}
- if (!scsi_status_is_good(res)) {
+ if (res < 0) {
sd_first_printk(KERN_WARNING, sdkp,
"Test WP failed, assume Write Enabled\n");
} else {
@@ -2742,7 +2756,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
res = sd_do_mode_sense(sdkp, dbd, modepage, buffer, first_len,
&data, &sshdr);
- if (!scsi_status_is_good(res))
+ if (res < 0)
goto bad_sense;
if (!data.header_length) {
@@ -2774,7 +2788,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
res = sd_do_mode_sense(sdkp, dbd, modepage, buffer, len,
&data, &sshdr);
- if (scsi_status_is_good(res)) {
+ if (!res) {
int offset = data.header_length + data.block_descriptor_length;
while (offset < len) {
@@ -2892,7 +2906,7 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)
res = scsi_mode_sense(sdp, 1, 0x0a, buffer, 36, SD_TIMEOUT,
sdkp->max_retries, &data, &sshdr);
- if (!scsi_status_is_good(res) || !data.header_length ||
+ if (res < 0 || !data.header_length ||
data.length < 6) {
sd_first_printk(KERN_WARNING, sdkp,
"getting Control mode page failed, assume no ATO\n");
@@ -3591,12 +3605,12 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start)
SD_TIMEOUT, sdkp->max_retries, 0, RQF_PM, NULL);
if (res) {
sd_print_result(sdkp, "Start/Stop Unit failed", res);
- if (driver_byte(res) == DRIVER_SENSE)
+ if (res > 0 && scsi_sense_valid(&sshdr)) {
sd_print_sense_hdr(sdkp, &sshdr);
- if (scsi_sense_valid(&sshdr) &&
/* 0x3a is medium not present */
- sshdr.asc == 0x3a)
- res = 0;
+ if (sshdr.asc == 0x3a)
+ res = 0;
+ }
}
/* SCSI error codes must not go to the generic layer */
@@ -3806,15 +3820,14 @@ void sd_print_sense_hdr(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr)
void sd_print_result(const struct scsi_disk *sdkp, const char *msg, int result)
{
const char *hb_string = scsi_hostbyte_string(result);
- const char *db_string = scsi_driverbyte_string(result);
- if (hb_string || db_string)
+ if (hb_string)
sd_printk(KERN_INFO, sdkp,
"%s: Result: hostbyte=%s driverbyte=%s\n", msg,
hb_string ? hb_string : "invalid",
- db_string ? db_string : "invalid");
+ "DRIVER_OK");
else
sd_printk(KERN_INFO, sdkp,
- "%s: Result: hostbyte=0x%02x driverbyte=0x%02x\n",
- msg, host_byte(result), driver_byte(result));
+ "%s: Result: hostbyte=0x%02x driverbyte=%s\n",
+ msg, host_byte(result), "DRIVER_OK");
}
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index e45d8d94574c..186b5ff52c3a 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -116,8 +116,7 @@ static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
sd_printk(KERN_ERR, sdkp,
"REPORT ZONES start lba %llu failed\n", lba);
sd_print_result(sdkp, "REPORT ZONES", result);
- if (driver_byte(result) == DRIVER_SENSE &&
- scsi_sense_valid(&sshdr))
+ if (result > 0 && scsi_sense_valid(&sshdr))
sd_print_sense_hdr(sdkp, &sshdr);
return -EIO;
}
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index def7ec3bbaf9..91e2221bbb0d 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -498,9 +498,11 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
old_hdr->host_status = hp->host_status;
old_hdr->driver_status = hp->driver_status;
if ((CHECK_CONDITION & hp->masked_status) ||
- (DRIVER_SENSE & hp->driver_status))
+ (srp->sense_b[0] & 0x70) == 0x70) {
+ old_hdr->driver_status = DRIVER_SENSE;
memcpy(old_hdr->sense_buffer, srp->sense_b,
sizeof (old_hdr->sense_buffer));
+ }
switch (hp->host_status) {
/* This setup of 'result' is for backward compatibility and is best
ignored by the user who should use target, host + driver status */
@@ -574,7 +576,7 @@ sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp)
hp->sb_len_wr = 0;
if ((hp->mx_sb_len > 0) && hp->sbp) {
if ((CHECK_CONDITION & hp->masked_status) ||
- (DRIVER_SENSE & hp->driver_status)) {
+ (srp->sense_b[0] & 0x70) == 0x70) {
int sb_len = SCSI_SENSE_BUFFERSIZE;
sb_len = (hp->mx_sb_len > sb_len) ? sb_len : hp->mx_sb_len;
len = 8 + (int) srp->sense_b[7]; /* Additional sense length field */
@@ -583,6 +585,7 @@ sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp)
err = -EFAULT;
goto err_out;
}
+ hp->driver_status = DRIVER_SENSE;
hp->sb_len_wr = len;
}
}
@@ -1373,7 +1376,7 @@ sg_rq_end_io(struct request *rq, blk_status_t status)
srp->header.status = 0xff & result;
srp->header.masked_status = status_byte(result);
- srp->header.msg_status = msg_byte(result);
+ srp->header.msg_status = COMMAND_COMPLETE;
srp->header.host_status = host_byte(result);
srp->header.driver_status = driver_byte(result);
if ((sdp->sgdebug > 0) &&
@@ -1756,7 +1759,7 @@ sg_start_req(Sg_request *srp, unsigned char *cmd)
* not expect an EWOULDBLOCK from this condition.
*/
rq = blk_get_request(q, hp->dxfer_direction == SG_DXFER_TO_DEV ?
- REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0);
+ REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
if (IS_ERR(rq)) {
kfree(long_cmdp);
return PTR_ERR(rq);
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
index 5db16509b6e1..dcc0b9618a64 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -3087,8 +3087,7 @@ static void pqi_process_aio_io_error(struct pqi_io_request *io_request)
}
if (device_offline && sense_data_length == 0)
- scsi_build_sense_buffer(0, scmd->sense_buffer, HARDWARE_ERROR,
- 0x3e, 0x1);
+ scsi_build_sense(scmd, 0, HARDWARE_ERROR, 0x3e, 0x1);
scmd->result = scsi_status;
set_host_byte(scmd, host_byte);
diff --git a/drivers/scsi/snic/snic_ctl.c b/drivers/scsi/snic/snic_ctl.c
index 4cd86115cfb2..703f229862fc 100644
--- a/drivers/scsi/snic/snic_ctl.c
+++ b/drivers/scsi/snic/snic_ctl.c
@@ -114,10 +114,7 @@ snic_queue_exch_ver_req(struct snic *snic)
rqi = snic_req_init(snic, 0);
if (!rqi) {
- SNIC_HOST_ERR(snic->shost,
- "Queuing Exch Ver Req failed, err = %d\n",
- ret);
-
+ SNIC_HOST_ERR(snic->shost, "Init Exch Ver Req failed\n");
ret = -ENOMEM;
goto error;
}
diff --git a/drivers/scsi/snic/snic_debugfs.c b/drivers/scsi/snic/snic_debugfs.c
index 3aeee856d5c7..5e0faeba516e 100644
--- a/drivers/scsi/snic/snic_debugfs.c
+++ b/drivers/scsi/snic/snic_debugfs.c
@@ -430,21 +430,19 @@ static const struct seq_operations snic_trc_sops = {
DEFINE_SEQ_ATTRIBUTE(snic_trc);
+#define TRC_ENABLE_FILE "tracing_enable"
+#define TRC_FILE "trace"
/*
* snic_trc_debugfs_init : creates trace/tracing_enable files for trace
* under debugfs
*/
void snic_trc_debugfs_init(void)
{
- snic_glob->trc.trc_enable = debugfs_create_bool("tracing_enable",
- S_IFREG | S_IRUGO | S_IWUSR,
- snic_glob->trc_root,
- &snic_glob->trc.enable);
-
- snic_glob->trc.trc_file = debugfs_create_file("trace",
- S_IFREG | S_IRUGO | S_IWUSR,
- snic_glob->trc_root, NULL,
- &snic_trc_fops);
+ debugfs_create_bool(TRC_ENABLE_FILE, S_IFREG | S_IRUGO | S_IWUSR,
+ snic_glob->trc_root, &snic_glob->trc.enable);
+
+ debugfs_create_file(TRC_FILE, S_IFREG | S_IRUGO | S_IWUSR,
+ snic_glob->trc_root, NULL, &snic_trc_fops);
}
/*
@@ -453,9 +451,6 @@ void snic_trc_debugfs_init(void)
void
snic_trc_debugfs_term(void)
{
- debugfs_remove(snic_glob->trc.trc_file);
- snic_glob->trc.trc_file = NULL;
-
- debugfs_remove(snic_glob->trc.trc_enable);
- snic_glob->trc.trc_enable = NULL;
+ debugfs_remove(debugfs_lookup(TRC_FILE, snic_glob->trc_root));
+ debugfs_remove(debugfs_lookup(TRC_ENABLE_FILE, snic_glob->trc_root));
}
diff --git a/drivers/scsi/snic/snic_trc.h b/drivers/scsi/snic/snic_trc.h
index 87dcc7457d15..ce305b4b8fa2 100644
--- a/drivers/scsi/snic/snic_trc.h
+++ b/drivers/scsi/snic/snic_trc.h
@@ -46,9 +46,6 @@ struct snic_trc {
u32 rd_idx;
u32 wr_idx;
bool enable; /* Control Variable for Tracing */
-
- struct dentry *trc_enable; /* debugfs file object */
- struct dentry *trc_file;
};
int snic_trc_init(void);
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index e4633b84c556..94c254e9012e 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -220,6 +220,8 @@ static unsigned int sr_get_events(struct scsi_device *sdev)
return DISK_EVENT_EJECT_REQUEST;
else if (med->media_event_code == 2)
return DISK_EVENT_MEDIA_CHANGE;
+ else if (med->media_event_code == 3)
+ return DISK_EVENT_EJECT_REQUEST;
return 0;
}
@@ -338,7 +340,7 @@ static int sr_done(struct scsi_cmnd *SCpnt)
* care is taken to avoid unnecessary additional work such as
* memcpy's that could be avoided.
*/
- if (driver_byte(result) != 0 && /* An error occurred */
+ if (scsi_status_is_check_condition(result) &&
(SCpnt->sense_buffer[0] & 0x7f) == 0x70) { /* Sense current */
switch (SCpnt->sense_buffer[2]) {
case MEDIUM_ERROR:
@@ -911,7 +913,7 @@ static void get_capabilities(struct scsi_cd *cd)
rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, ms_len,
SR_TIMEOUT, 3, &data, NULL);
- if (!scsi_status_is_good(rc) || data.length > ms_len ||
+ if (rc < 0 || data.length > ms_len ||
data.header_length + data.block_descriptor_length > data.length) {
/* failed, drive doesn't have capabilities mode page */
cd->cdi.speed = 1;
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index 15c305283b6c..79d9aa2df528 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -201,7 +201,11 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
cgc->timeout, IOCTL_RETRIES, 0, 0, NULL);
/* Minimal error checking. Ignore cases we know about, and report the rest. */
- if (driver_byte(result) != 0) {
+ if (result < 0) {
+ err = result;
+ goto out;
+ }
+ if (scsi_status_is_check_condition(result)) {
switch (sshdr->sense_key) {
case UNIT_ATTENTION:
SDev->changed = 1;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 3b1afe1d5b27..c6f14540ae03 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -390,8 +390,8 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
if (!debugging) { /* Abnormal conditions for tape */
if (!cmdstatp->have_sense)
st_printk(KERN_WARNING, STp,
- "Error %x (driver bt 0x%x, host bt 0x%x).\n",
- result, driver_byte(result), host_byte(result));
+ "Error %x (driver bt 0, host bt 0x%x).\n",
+ result, host_byte(result));
else if (cmdstatp->have_sense &&
scode != NO_SENSE &&
scode != RECOVERED_ERROR &&
@@ -549,9 +549,9 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
req = blk_get_request(SRpnt->stp->device->request_queue,
data_direction == DMA_TO_DEVICE ?
- REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0);
+ REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
if (IS_ERR(req))
- return DRIVER_ERROR << 24;
+ return PTR_ERR(req);
rq = scsi_req(req);
req->rq_flags |= RQF_QUIET;
@@ -562,7 +562,7 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
GFP_KERNEL);
if (err) {
blk_put_request(req);
- return DRIVER_ERROR << 24;
+ return err;
}
}
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 12471208c7a8..491b435273a6 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -398,11 +398,8 @@ static struct status_msg *stex_get_status(struct st_hba *hba)
static void stex_invalid_field(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
- cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
-
/* "Invalid field in cdb" */
- scsi_build_sense_buffer(0, cmd->sense_buffer, ILLEGAL_REQUEST, 0x24,
- 0x0);
+ scsi_build_sense(cmd, 0, ILLEGAL_REQUEST, 0x24, 0x0);
done(cmd);
}
@@ -740,7 +737,7 @@ static void stex_scsi_done(struct st_ccb *ccb)
result |= DID_OK << 16;
break;
case SAM_STAT_CHECK_CONDITION:
- result |= DRIVER_SENSE << 24;
+ result |= DID_OK << 16;
break;
case SAM_STAT_BUSY:
result |= DID_BUS_BUSY << 16;
@@ -751,7 +748,7 @@ static void stex_scsi_done(struct st_ccb *ccb)
}
}
else if (ccb->srb_status & SRB_SEE_SENSE)
- result = DRIVER_SENSE << 24 | SAM_STAT_CHECK_CONDITION;
+ result = SAM_STAT_CHECK_CONDITION;
else switch (ccb->srb_status) {
case SRB_STATUS_SELECTION_TIMEOUT:
result = DID_NO_CONNECT << 16;
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index e6718a74e5da..328bb961c281 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -406,6 +406,14 @@ static void storvsc_on_channel_callback(void *context);
#define STORVSC_IDE_MAX_TARGETS 1
#define STORVSC_IDE_MAX_CHANNELS 1
+/*
+ * Upper bound on the size of a storvsc packet. vmscsi_size_delta is not
+ * included in the calculation because it is set after STORVSC_MAX_PKT_SIZE
+ * is used in storvsc_connect_to_vsp
+ */
+#define STORVSC_MAX_PKT_SIZE (sizeof(struct vmpacket_descriptor) +\
+ sizeof(struct vstor_packet))
+
struct storvsc_cmd_request {
struct scsi_cmnd *cmd;
@@ -688,6 +696,23 @@ old_is_alloced:
spin_unlock_irqrestore(&stor_device->lock, flags);
}
+static u64 storvsc_next_request_id(struct vmbus_channel *channel, u64 rqst_addr)
+{
+ struct storvsc_cmd_request *request =
+ (struct storvsc_cmd_request *)(unsigned long)rqst_addr;
+
+ if (rqst_addr == VMBUS_RQST_INIT)
+ return VMBUS_RQST_INIT;
+ if (rqst_addr == VMBUS_RQST_RESET)
+ return VMBUS_RQST_RESET;
+
+ /*
+ * Cannot return an ID of 0, which is reserved for an unsolicited
+ * message from Hyper-V.
+ */
+ return (u64)blk_mq_unique_tag(request->cmd->request) + 1;
+}
+
static void handle_sc_creation(struct vmbus_channel *new_sc)
{
struct hv_device *device = new_sc->primary_channel->device_obj;
@@ -701,12 +726,9 @@ static void handle_sc_creation(struct vmbus_channel *new_sc)
return;
memset(&props, 0, sizeof(struct vmstorage_channel_properties));
+ new_sc->max_pkt_size = STORVSC_MAX_PKT_SIZE;
- /*
- * The size of vmbus_requestor is an upper bound on the number of requests
- * that can be in-progress at any one time across all channels.
- */
- new_sc->rqstor_size = scsi_driver.can_queue;
+ new_sc->next_request_id_callback = storvsc_next_request_id;
ret = vmbus_open(new_sc,
storvsc_ringbuffer_size,
@@ -773,7 +795,7 @@ static void handle_multichannel_storage(struct hv_device *device, int max_chns)
ret = vmbus_sendpacket(device->channel, vstor_packet,
(sizeof(struct vstor_packet) -
stor_device->vmscsi_size_delta),
- (unsigned long)request,
+ VMBUS_RQST_INIT,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
@@ -842,7 +864,7 @@ static int storvsc_execute_vstor_op(struct hv_device *device,
ret = vmbus_sendpacket(device->channel, vstor_packet,
(sizeof(struct vstor_packet) -
stor_device->vmscsi_size_delta),
- (unsigned long)request,
+ VMBUS_RQST_INIT,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0)
@@ -1009,17 +1031,40 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
struct storvsc_scan_work *wrk;
void (*process_err_fn)(struct work_struct *work);
struct hv_host_device *host_dev = shost_priv(host);
- bool do_work = false;
- switch (SRB_STATUS(vm_srb->srb_status)) {
- case SRB_STATUS_ERROR:
+ /*
+ * In some situations, Hyper-V sets multiple bits in the
+ * srb_status, such as ABORTED and ERROR. So process them
+ * individually, with the most specific bits first.
+ */
+
+ if (vm_srb->srb_status & SRB_STATUS_INVALID_LUN) {
+ set_host_byte(scmnd, DID_NO_CONNECT);
+ process_err_fn = storvsc_remove_lun;
+ goto do_work;
+ }
+
+ if (vm_srb->srb_status & SRB_STATUS_ABORTED) {
+ if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID &&
+ /* Capacity data has changed */
+ (asc == 0x2a) && (ascq == 0x9)) {
+ process_err_fn = storvsc_device_scan;
+ /*
+ * Retry the I/O that triggered this.
+ */
+ set_host_byte(scmnd, DID_REQUEUE);
+ goto do_work;
+ }
+ }
+
+ if (vm_srb->srb_status & SRB_STATUS_ERROR) {
/*
* Let upper layer deal with error when
* sense message is present.
*/
-
if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID)
- break;
+ return;
+
/*
* If there is an error; offline the device since all
* error recovery strategies would have already been
@@ -1032,37 +1077,19 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
set_host_byte(scmnd, DID_PASSTHROUGH);
break;
/*
- * On Some Windows hosts TEST_UNIT_READY command can return
- * SRB_STATUS_ERROR, let the upper level code deal with it
- * based on the sense information.
+ * On some Hyper-V hosts TEST_UNIT_READY command can
+ * return SRB_STATUS_ERROR. Let the upper level code
+ * deal with it based on the sense information.
*/
case TEST_UNIT_READY:
break;
default:
set_host_byte(scmnd, DID_ERROR);
}
- break;
- case SRB_STATUS_INVALID_LUN:
- set_host_byte(scmnd, DID_NO_CONNECT);
- do_work = true;
- process_err_fn = storvsc_remove_lun;
- break;
- case SRB_STATUS_ABORTED:
- if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID &&
- (asc == 0x2a) && (ascq == 0x9)) {
- do_work = true;
- process_err_fn = storvsc_device_scan;
- /*
- * Retry the I/O that triggered this.
- */
- set_host_byte(scmnd, DID_REQUEUE);
- }
- break;
}
+ return;
- if (!do_work)
- return;
-
+do_work:
/*
* We need to schedule work to process this error; schedule it.
*/
@@ -1090,6 +1117,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request,
struct Scsi_Host *host;
u32 payload_sz = cmd_request->payload_sz;
void *payload = cmd_request->payload;
+ bool sense_ok;
host = stor_dev->host;
@@ -1099,11 +1127,10 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request,
scmnd->result = vm_srb->scsi_status;
if (scmnd->result) {
- if (scsi_normalize_sense(scmnd->sense_buffer,
- SCSI_SENSE_BUFFERSIZE, &sense_hdr) &&
- !(sense_hdr.sense_key == NOT_READY &&
- sense_hdr.asc == 0x03A) &&
- do_logging(STORVSC_LOGGING_ERROR))
+ sense_ok = scsi_normalize_sense(scmnd->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE, &sense_hdr);
+
+ if (sense_ok && do_logging(STORVSC_LOGGING_WARN))
scsi_print_sense_hdr(scmnd->device, "storvsc",
&sense_hdr);
}
@@ -1160,53 +1187,41 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device,
vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS;
}
-
/* Copy over the status...etc */
stor_pkt->vm_srb.scsi_status = vstor_packet->vm_srb.scsi_status;
stor_pkt->vm_srb.srb_status = vstor_packet->vm_srb.srb_status;
- /* Validate sense_info_length (from Hyper-V) */
- if (vstor_packet->vm_srb.sense_info_length > sense_buffer_size)
- vstor_packet->vm_srb.sense_info_length = sense_buffer_size;
-
- stor_pkt->vm_srb.sense_info_length =
- vstor_packet->vm_srb.sense_info_length;
+ /*
+ * Copy over the sense_info_length, but limit to the known max
+ * size if Hyper-V returns a bad value.
+ */
+ stor_pkt->vm_srb.sense_info_length = min_t(u8, sense_buffer_size,
+ vstor_packet->vm_srb.sense_info_length);
if (vstor_packet->vm_srb.scsi_status != 0 ||
vstor_packet->vm_srb.srb_status != SRB_STATUS_SUCCESS)
- storvsc_log(device, STORVSC_LOGGING_WARN,
- "cmd 0x%x scsi status 0x%x srb status 0x%x\n",
+ storvsc_log(device, STORVSC_LOGGING_ERROR,
+ "tag#%d cmd 0x%x status: scsi 0x%x srb 0x%x hv 0x%x\n",
+ request->cmd->request->tag,
stor_pkt->vm_srb.cdb[0],
vstor_packet->vm_srb.scsi_status,
- vstor_packet->vm_srb.srb_status);
-
- if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) {
- /* CHECK_CONDITION */
- if (vstor_packet->vm_srb.srb_status &
- SRB_STATUS_AUTOSENSE_VALID) {
- /* autosense data available */
-
- storvsc_log(device, STORVSC_LOGGING_WARN,
- "stor pkt %p autosense data valid - len %d\n",
- request, vstor_packet->vm_srb.sense_info_length);
-
- memcpy(request->cmd->sense_buffer,
- vstor_packet->vm_srb.sense_data,
- vstor_packet->vm_srb.sense_info_length);
+ vstor_packet->vm_srb.srb_status,
+ vstor_packet->status);
- }
- }
+ if (vstor_packet->vm_srb.scsi_status == SAM_STAT_CHECK_CONDITION &&
+ (vstor_packet->vm_srb.srb_status & SRB_STATUS_AUTOSENSE_VALID))
+ memcpy(request->cmd->sense_buffer,
+ vstor_packet->vm_srb.sense_data,
+ stor_pkt->vm_srb.sense_info_length);
stor_pkt->vm_srb.data_transfer_length =
- vstor_packet->vm_srb.data_transfer_length;
+ vstor_packet->vm_srb.data_transfer_length;
storvsc_command_completion(request, stor_device);
if (atomic_dec_and_test(&stor_device->num_outstanding_req) &&
stor_device->drain_notify)
wake_up(&stor_device->waiting_to_drain);
-
-
}
static void storvsc_on_receive(struct storvsc_device *stor_device,
@@ -1244,6 +1259,7 @@ static void storvsc_on_channel_callback(void *context)
const struct vmpacket_descriptor *desc;
struct hv_device *device;
struct storvsc_device *stor_device;
+ struct Scsi_Host *shost;
if (channel->primary_channel != NULL)
device = channel->primary_channel->device_obj;
@@ -1254,20 +1270,12 @@ static void storvsc_on_channel_callback(void *context)
if (!stor_device)
return;
- foreach_vmbus_pkt(desc, channel) {
- void *packet = hv_pkt_data(desc);
- struct storvsc_cmd_request *request;
- u64 cmd_rqst;
-
- cmd_rqst = vmbus_request_addr(&channel->requestor,
- desc->trans_id);
- if (cmd_rqst == VMBUS_RQST_ERROR) {
- dev_err(&device->device,
- "Incorrect transaction id\n");
- continue;
- }
+ shost = stor_device->host;
- request = (struct storvsc_cmd_request *)(unsigned long)cmd_rqst;
+ foreach_vmbus_pkt(desc, channel) {
+ struct vstor_packet *packet = hv_pkt_data(desc);
+ struct storvsc_cmd_request *request = NULL;
+ u64 rqst_id = desc->trans_id;
if (hv_pkt_datalen(desc) < sizeof(struct vstor_packet) -
stor_device->vmscsi_size_delta) {
@@ -1275,14 +1283,44 @@ static void storvsc_on_channel_callback(void *context)
continue;
}
- if (request == &stor_device->init_request ||
- request == &stor_device->reset_request) {
- memcpy(&request->vstor_packet, packet,
- (sizeof(struct vstor_packet) - stor_device->vmscsi_size_delta));
- complete(&request->wait_event);
+ if (rqst_id == VMBUS_RQST_INIT) {
+ request = &stor_device->init_request;
+ } else if (rqst_id == VMBUS_RQST_RESET) {
+ request = &stor_device->reset_request;
} else {
+ /* Hyper-V can send an unsolicited message with ID of 0 */
+ if (rqst_id == 0) {
+ /*
+ * storvsc_on_receive() looks at the vstor_packet in the message
+ * from the ring buffer. If the operation in the vstor_packet is
+ * COMPLETE_IO, then we call storvsc_on_io_completion(), and
+ * dereference the guest memory address. Make sure we don't call
+ * storvsc_on_io_completion() with a guest memory address that is
+ * zero if Hyper-V were to construct and send such a bogus packet.
+ */
+ if (packet->operation == VSTOR_OPERATION_COMPLETE_IO) {
+ dev_err(&device->device, "Invalid packet with ID of 0\n");
+ continue;
+ }
+ } else {
+ struct scsi_cmnd *scmnd;
+
+ /* Transaction 'rqst_id' corresponds to tag 'rqst_id - 1' */
+ scmnd = scsi_host_find_tag(shost, rqst_id - 1);
+ if (scmnd == NULL) {
+ dev_err(&device->device, "Incorrect transaction ID\n");
+ continue;
+ }
+ request = (struct storvsc_cmd_request *)scsi_cmd_priv(scmnd);
+ }
+
storvsc_on_receive(stor_device, packet, request);
+ continue;
}
+
+ memcpy(&request->vstor_packet, packet,
+ (sizeof(struct vstor_packet) - stor_device->vmscsi_size_delta));
+ complete(&request->wait_event);
}
}
@@ -1294,11 +1332,8 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size,
memset(&props, 0, sizeof(struct vmstorage_channel_properties));
- /*
- * The size of vmbus_requestor is an upper bound on the number of requests
- * that can be in-progress at any one time across all channels.
- */
- device->channel->rqstor_size = scsi_driver.can_queue;
+ device->channel->max_pkt_size = STORVSC_MAX_PKT_SIZE;
+ device->channel->next_request_id_callback = storvsc_next_request_id;
ret = vmbus_open(device->channel,
ring_size,
@@ -1624,7 +1659,7 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
ret = vmbus_sendpacket(device->channel, vstor_packet,
(sizeof(struct vstor_packet) -
stor_device->vmscsi_size_delta),
- (unsigned long)&stor_device->reset_request,
+ VMBUS_RQST_RESET,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0)
@@ -1675,7 +1710,7 @@ static bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd)
* this. So, don't send it.
*/
case SET_WINDOW:
- scmnd->result = DID_ERROR << 16;
+ set_host_byte(scmnd, DID_ERROR);
allowed = false;
break;
default:
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index d9a045f9858c..16b65fc4405c 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -170,9 +170,8 @@ static int sym_xerr_cam_status(int cam_status, int x_status)
void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
{
struct scsi_cmnd *cmd = cp->cmd;
- u_int cam_status, scsi_status, drv_status;
+ u_int cam_status, scsi_status;
- drv_status = 0;
cam_status = DID_OK;
scsi_status = cp->ssss_status;
@@ -186,7 +185,6 @@ void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
cp->xerr_status == 0) {
cam_status = sym_xerr_cam_status(DID_OK,
cp->sv_xerr_status);
- drv_status = DRIVER_SENSE;
/*
* Bounce back the sense data to user.
*/
@@ -235,7 +233,7 @@ void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
cam_status = sym_xerr_cam_status(DID_ERROR, cp->xerr_status);
}
scsi_set_resid(cmd, resid);
- cmd->result = (drv_status << 24) | (cam_status << 16) | scsi_status;
+ cmd->result = (cam_status << 16) | scsi_status;
}
static int sym_scatter(struct sym_hcb *np, struct sym_ccb *cp, struct scsi_cmnd *cmd)
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index 07cf415367b4..2d137953e7b4 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -115,6 +115,7 @@ config SCSI_UFS_MEDIATEK
tristate "Mediatek specific hooks to UFS controller platform driver"
depends on SCSI_UFSHCD_PLATFORM && ARCH_MEDIATEK
select PHY_MTK_UFS
+ select RESET_TI_SYSCON
help
This selects the Mediatek specific additions to UFSHCD platform driver.
UFS host on Mediatek needs some vendor specific configuration before
diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 13d92043e13b..908ff39c4856 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -323,6 +323,8 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume = ufshcd_pltfrm_runtime_resume,
.runtime_idle = ufshcd_pltfrm_runtime_idle,
+ .prepare = ufshcd_suspend_prepare,
+ .complete = ufshcd_resume_complete,
};
static struct platform_driver cdns_ufs_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 67a6a61154b7..ec4589afbc13 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -148,6 +148,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
.runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
.runtime_resume = tc_dwc_g210_pci_runtime_resume,
.runtime_idle = tc_dwc_g210_pci_runtime_idle,
+ .prepare = ufshcd_suspend_prepare,
+ .complete = ufshcd_resume_complete,
};
static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index ced9ef4d7c78..4e1ff209b933 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -13,7 +13,7 @@ void __init ufs_debugfs_init(void)
ufs_debugfs_root = debugfs_create_dir("ufshcd", NULL);
}
-void __exit ufs_debugfs_exit(void)
+void ufs_debugfs_exit(void)
{
debugfs_remove_recursive(ufs_debugfs_root);
}
@@ -60,14 +60,14 @@ __acquires(&hba->host_sem)
up(&hba->host_sem);
return -EBUSY;
}
- pm_runtime_get_sync(hba->dev);
+ ufshcd_rpm_get_sync(hba);
return 0;
}
static void ufs_debugfs_put_user_access(struct ufs_hba *hba)
__releases(&hba->host_sem)
{
- pm_runtime_put_sync(hba->dev);
+ ufshcd_rpm_put_sync(hba);
up(&hba->host_sem);
}
diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h
index 3ca29d30460a..97548a3f90eb 100644
--- a/drivers/scsi/ufs/ufs-debugfs.h
+++ b/drivers/scsi/ufs/ufs-debugfs.h
@@ -9,7 +9,7 @@ struct ufs_hba;
#ifdef CONFIG_DEBUG_FS
void __init ufs_debugfs_init(void);
-void __exit ufs_debugfs_exit(void);
+void ufs_debugfs_exit(void);
void ufs_debugfs_hba_init(struct ufs_hba *hba);
void ufs_debugfs_hba_exit(struct ufs_hba *hba);
void ufs_debugfs_exception_event(struct ufs_hba *hba, u16 status);
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 70647eacf195..cf46d6f86e0e 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -107,6 +107,7 @@ enum {
#define CNTR_DIV_VAL 40
+static struct exynos_ufs_drv_data exynos_ufs_drvs;
static void exynos_ufs_auto_ctrl_hcc(struct exynos_ufs *ufs, bool en);
static void exynos_ufs_ctrl_clkstop(struct exynos_ufs *ufs, bool en);
@@ -1048,7 +1049,7 @@ static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, u8 enter)
exynos_ufs_ungate_clks(ufs);
if (ufs->opts & EXYNOS_UFS_OPT_USE_SW_HIBERN8_TIMER) {
- const unsigned int granularity_tbl[] = {
+ static const unsigned int granularity_tbl[] = {
1, 4, 8, 16, 32, 100
};
int h8_time = attr->pa_hibern8time *
@@ -1231,8 +1232,32 @@ static int exynos_ufs_remove(struct platform_device *pdev)
return 0;
}
-struct exynos_ufs_drv_data exynos_ufs_drvs = {
+static struct exynos_ufs_uic_attr exynos7_uic_attr = {
+ .tx_trailingclks = 0x10,
+ .tx_dif_p_nsec = 3000000, /* unit: ns */
+ .tx_dif_n_nsec = 1000000, /* unit: ns */
+ .tx_high_z_cnt_nsec = 20000, /* unit: ns */
+ .tx_base_unit_nsec = 100000, /* unit: ns */
+ .tx_gran_unit_nsec = 4000, /* unit: ns */
+ .tx_sleep_cnt = 1000, /* unit: ns */
+ .tx_min_activatetime = 0xa,
+ .rx_filler_enable = 0x2,
+ .rx_dif_p_nsec = 1000000, /* unit: ns */
+ .rx_hibern8_wait_nsec = 4000000, /* unit: ns */
+ .rx_base_unit_nsec = 100000, /* unit: ns */
+ .rx_gran_unit_nsec = 4000, /* unit: ns */
+ .rx_sleep_cnt = 1280, /* unit: ns */
+ .rx_stall_cnt = 320, /* unit: ns */
+ .rx_hs_g1_sync_len_cap = SYNC_LEN_COARSE(0xf),
+ .rx_hs_g2_sync_len_cap = SYNC_LEN_COARSE(0xf),
+ .rx_hs_g3_sync_len_cap = SYNC_LEN_COARSE(0xf),
+ .rx_hs_g1_prep_sync_len_cap = PREP_LEN(0xf),
+ .rx_hs_g2_prep_sync_len_cap = PREP_LEN(0xf),
+ .rx_hs_g3_prep_sync_len_cap = PREP_LEN(0xf),
+ .pa_dbg_option_suite = 0x30103,
+};
+static struct exynos_ufs_drv_data exynos_ufs_drvs = {
.compatible = "samsung,exynos7-ufs",
.uic_attr = &exynos7_uic_attr,
.quirks = UFSHCD_QUIRK_PRDT_BYTE_GRAN |
@@ -1267,6 +1292,8 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume = ufshcd_pltfrm_runtime_resume,
.runtime_idle = ufshcd_pltfrm_runtime_idle,
+ .prepare = ufshcd_suspend_prepare,
+ .complete = ufshcd_resume_complete,
};
static struct platform_driver exynos_ufs_pltform = {
diff --git a/drivers/scsi/ufs/ufs-exynos.h b/drivers/scsi/ufs/ufs-exynos.h
index 06ee565f7eb0..67505fe32ebf 100644
--- a/drivers/scsi/ufs/ufs-exynos.h
+++ b/drivers/scsi/ufs/ufs-exynos.h
@@ -245,30 +245,4 @@ static inline void exynos_ufs_disable_dbg_mode(struct ufs_hba *hba)
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_MODE), FALSE);
}
-struct exynos_ufs_drv_data exynos_ufs_drvs;
-
-struct exynos_ufs_uic_attr exynos7_uic_attr = {
- .tx_trailingclks = 0x10,
- .tx_dif_p_nsec = 3000000, /* unit: ns */
- .tx_dif_n_nsec = 1000000, /* unit: ns */
- .tx_high_z_cnt_nsec = 20000, /* unit: ns */
- .tx_base_unit_nsec = 100000, /* unit: ns */
- .tx_gran_unit_nsec = 4000, /* unit: ns */
- .tx_sleep_cnt = 1000, /* unit: ns */
- .tx_min_activatetime = 0xa,
- .rx_filler_enable = 0x2,
- .rx_dif_p_nsec = 1000000, /* unit: ns */
- .rx_hibern8_wait_nsec = 4000000, /* unit: ns */
- .rx_base_unit_nsec = 100000, /* unit: ns */
- .rx_gran_unit_nsec = 4000, /* unit: ns */
- .rx_sleep_cnt = 1280, /* unit: ns */
- .rx_stall_cnt = 320, /* unit: ns */
- .rx_hs_g1_sync_len_cap = SYNC_LEN_COARSE(0xf),
- .rx_hs_g2_sync_len_cap = SYNC_LEN_COARSE(0xf),
- .rx_hs_g3_sync_len_cap = SYNC_LEN_COARSE(0xf),
- .rx_hs_g1_prep_sync_len_cap = PREP_LEN(0xf),
- .rx_hs_g2_prep_sync_len_cap = PREP_LEN(0xf),
- .rx_hs_g3_prep_sync_len_cap = PREP_LEN(0xf),
- .pa_dbg_option_suite = 0x30103,
-};
#endif /* _UFS_EXYNOS_H_ */
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c
index d0626773eb38..5b147a48161b 100644
--- a/drivers/scsi/ufs/ufs-hisi.c
+++ b/drivers/scsi/ufs/ufs-hisi.c
@@ -400,7 +400,7 @@ static int ufs_hisi_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
struct ufs_hisi_host *host = ufshcd_get_variant(hba);
- if (ufshcd_is_runtime_pm(pm_op))
+ if (pm_op == UFS_RUNTIME_PM)
return 0;
if (host->in_suspend) {
@@ -577,6 +577,8 @@ static const struct dev_pm_ops ufs_hisi_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume = ufshcd_pltfrm_runtime_resume,
.runtime_idle = ufshcd_pltfrm_runtime_idle,
+ .prepare = ufshcd_suspend_prepare,
+ .complete = ufshcd_resume_complete,
};
static struct platform_driver ufs_hisi_pltform = {
diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
index 0a84ec9e7cea..d2c251628a05 100644
--- a/drivers/scsi/ufs/ufs-mediatek.c
+++ b/drivers/scsi/ufs/ufs-mediatek.c
@@ -822,12 +822,10 @@ static int ufs_mtk_post_link(struct ufs_hba *hba)
/* enable unipro clock gating feature */
ufs_mtk_cfg_unipro_cg(hba, true);
- /* configure auto-hibern8 timer to 10ms */
- if (ufshcd_is_auto_hibern8_supported(hba)) {
- ufshcd_auto_hibern8_update(hba,
- FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 10) |
- FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3));
- }
+ /* will be configured during probe hba */
+ if (ufshcd_is_auto_hibern8_supported(hba))
+ hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 10) |
+ FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3);
ufs_mtk_setup_clk_gating(hba);
@@ -858,6 +856,9 @@ static int ufs_mtk_device_reset(struct ufs_hba *hba)
{
struct arm_smccc_res res;
+ /* disable hba before device reset */
+ ufshcd_hba_stop(hba);
+
ufs_mtk_device_reset_ctrl(0, res);
/*
@@ -1084,12 +1085,42 @@ static int ufs_mtk_probe(struct platform_device *pdev)
{
int err;
struct device *dev = &pdev->dev;
+ struct device_node *reset_node;
+ struct platform_device *reset_pdev;
+ struct device_link *link;
+
+ reset_node = of_find_compatible_node(NULL, NULL,
+ "ti,syscon-reset");
+ if (!reset_node) {
+ dev_notice(dev, "find ti,syscon-reset fail\n");
+ goto skip_reset;
+ }
+ reset_pdev = of_find_device_by_node(reset_node);
+ if (!reset_pdev) {
+ dev_notice(dev, "find reset_pdev fail\n");
+ goto skip_reset;
+ }
+ link = device_link_add(dev, &reset_pdev->dev,
+ DL_FLAG_AUTOPROBE_CONSUMER);
+ if (!link) {
+ dev_notice(dev, "add reset device_link fail\n");
+ goto skip_reset;
+ }
+ /* supplier is not probed */
+ if (link->status == DL_STATE_DORMANT) {
+ err = -EPROBE_DEFER;
+ goto out;
+ }
+skip_reset:
/* perform generic probe */
err = ufshcd_pltfrm_init(pdev, &ufs_hba_mtk_vops);
+
+out:
if (err)
dev_info(dev, "probe failed %d\n", err);
+ of_node_put(reset_node);
return err;
}
@@ -1114,6 +1145,8 @@ static const struct dev_pm_ops ufs_mtk_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume = ufshcd_pltfrm_runtime_resume,
.runtime_idle = ufshcd_pltfrm_runtime_idle,
+ .prepare = ufshcd_suspend_prepare,
+ .complete = ufshcd_resume_complete,
};
static struct platform_driver ufs_mtk_pltform = {
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 2a3dd21da6a6..9b1d18d7c9bb 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1551,6 +1551,8 @@ static const struct dev_pm_ops ufs_qcom_pm_ops = {
.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
.runtime_resume = ufshcd_pltfrm_runtime_resume,
.runtime_idle = ufshcd_pltfrm_runtime_idle,
+ .prepare = ufshcd_suspend_prepare,
+ .complete = ufshcd_resume_complete,
};
static struct platform_driver ufs_qcom_pltform = {
diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index 5d0e98a05ada..52bd807f7940 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -245,9 +245,9 @@ static ssize_t wb_on_store(struct device *dev, struct device_attribute *attr,
goto out;
}
- pm_runtime_get_sync(hba->dev);
+ ufshcd_rpm_get_sync(hba);
res = ufshcd_wb_toggle(hba, wb_enable);
- pm_runtime_put_sync(hba->dev);
+ ufshcd_rpm_put_sync(hba);
out:
up(&hba->host_sem);
return res < 0 ? res : count;
@@ -278,6 +278,242 @@ static const struct attribute_group ufs_sysfs_default_group = {
.attrs = ufs_sysfs_ufshcd_attrs,
};
+static ssize_t monitor_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%d\n", hba->monitor.enabled);
+}
+
+static ssize_t monitor_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ unsigned long value, flags;
+
+ if (kstrtoul(buf, 0, &value))
+ return -EINVAL;
+
+ value = !!value;
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ if (value == hba->monitor.enabled)
+ goto out_unlock;
+
+ if (!value) {
+ memset(&hba->monitor, 0, sizeof(hba->monitor));
+ } else {
+ hba->monitor.enabled = true;
+ hba->monitor.enabled_ts = ktime_get();
+ }
+
+out_unlock:
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ return count;
+}
+
+static ssize_t monitor_chunk_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%lu\n", hba->monitor.chunk_size);
+}
+
+static ssize_t monitor_chunk_size_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ unsigned long value, flags;
+
+ if (kstrtoul(buf, 0, &value))
+ return -EINVAL;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ /* Only allow chunk size change when monitor is disabled */
+ if (!hba->monitor.enabled)
+ hba->monitor.chunk_size = value;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ return count;
+}
+
+static ssize_t read_total_sectors_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%lu\n", hba->monitor.nr_sec_rw[READ]);
+}
+
+static ssize_t read_total_busy_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%llu\n",
+ ktime_to_us(hba->monitor.total_busy[READ]));
+}
+
+static ssize_t read_nr_requests_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%lu\n", hba->monitor.nr_req[READ]);
+}
+
+static ssize_t read_req_latency_avg_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ struct ufs_hba_monitor *m = &hba->monitor;
+
+ return sysfs_emit(buf, "%llu\n", div_u64(ktime_to_us(m->lat_sum[READ]),
+ m->nr_req[READ]));
+}
+
+static ssize_t read_req_latency_max_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%llu\n",
+ ktime_to_us(hba->monitor.lat_max[READ]));
+}
+
+static ssize_t read_req_latency_min_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%llu\n",
+ ktime_to_us(hba->monitor.lat_min[READ]));
+}
+
+static ssize_t read_req_latency_sum_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%llu\n",
+ ktime_to_us(hba->monitor.lat_sum[READ]));
+}
+
+static ssize_t write_total_sectors_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%lu\n", hba->monitor.nr_sec_rw[WRITE]);
+}
+
+static ssize_t write_total_busy_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%llu\n",
+ ktime_to_us(hba->monitor.total_busy[WRITE]));
+}
+
+static ssize_t write_nr_requests_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%lu\n", hba->monitor.nr_req[WRITE]);
+}
+
+static ssize_t write_req_latency_avg_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ struct ufs_hba_monitor *m = &hba->monitor;
+
+ return sysfs_emit(buf, "%llu\n", div_u64(ktime_to_us(m->lat_sum[WRITE]),
+ m->nr_req[WRITE]));
+}
+
+static ssize_t write_req_latency_max_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%llu\n",
+ ktime_to_us(hba->monitor.lat_max[WRITE]));
+}
+
+static ssize_t write_req_latency_min_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%llu\n",
+ ktime_to_us(hba->monitor.lat_min[WRITE]));
+}
+
+static ssize_t write_req_latency_sum_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%llu\n",
+ ktime_to_us(hba->monitor.lat_sum[WRITE]));
+}
+
+static DEVICE_ATTR_RW(monitor_enable);
+static DEVICE_ATTR_RW(monitor_chunk_size);
+static DEVICE_ATTR_RO(read_total_sectors);
+static DEVICE_ATTR_RO(read_total_busy);
+static DEVICE_ATTR_RO(read_nr_requests);
+static DEVICE_ATTR_RO(read_req_latency_avg);
+static DEVICE_ATTR_RO(read_req_latency_max);
+static DEVICE_ATTR_RO(read_req_latency_min);
+static DEVICE_ATTR_RO(read_req_latency_sum);
+static DEVICE_ATTR_RO(write_total_sectors);
+static DEVICE_ATTR_RO(write_total_busy);
+static DEVICE_ATTR_RO(write_nr_requests);
+static DEVICE_ATTR_RO(write_req_latency_avg);
+static DEVICE_ATTR_RO(write_req_latency_max);
+static DEVICE_ATTR_RO(write_req_latency_min);
+static DEVICE_ATTR_RO(write_req_latency_sum);
+
+static struct attribute *ufs_sysfs_monitor_attrs[] = {
+ &dev_attr_monitor_enable.attr,
+ &dev_attr_monitor_chunk_size.attr,
+ &dev_attr_read_total_sectors.attr,
+ &dev_attr_read_total_busy.attr,
+ &dev_attr_read_nr_requests.attr,
+ &dev_attr_read_req_latency_avg.attr,
+ &dev_attr_read_req_latency_max.attr,
+ &dev_attr_read_req_latency_min.attr,
+ &dev_attr_read_req_latency_sum.attr,
+ &dev_attr_write_total_sectors.attr,
+ &dev_attr_write_total_busy.attr,
+ &dev_attr_write_nr_requests.attr,
+ &dev_attr_write_req_latency_avg.attr,
+ &dev_attr_write_req_latency_max.attr,
+ &dev_attr_write_req_latency_min.attr,
+ &dev_attr_write_req_latency_sum.attr,
+ NULL
+};
+
+static const struct attribute_group ufs_sysfs_monitor_group = {
+ .name = "monitor",
+ .attrs = ufs_sysfs_monitor_attrs,
+};
+
static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba,
enum desc_idn desc_id,
u8 desc_index,
@@ -297,10 +533,10 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba,
goto out;
}
- pm_runtime_get_sync(hba->dev);
+ ufshcd_rpm_get_sync(hba);
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
param_offset, desc_buf, param_size);
- pm_runtime_put_sync(hba->dev);
+ ufshcd_rpm_put_sync(hba);
if (ret) {
ret = -EINVAL;
goto out;
@@ -678,7 +914,7 @@ static ssize_t _name##_show(struct device *dev, \
up(&hba->host_sem); \
return -ENOMEM; \
} \
- pm_runtime_get_sync(hba->dev); \
+ ufshcd_rpm_get_sync(hba); \
ret = ufshcd_query_descriptor_retry(hba, \
UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \
0, 0, desc_buf, &desc_len); \
@@ -695,7 +931,7 @@ static ssize_t _name##_show(struct device *dev, \
goto out; \
ret = sysfs_emit(buf, "%s\n", desc_buf); \
out: \
- pm_runtime_put_sync(hba->dev); \
+ ufshcd_rpm_put_sync(hba); \
kfree(desc_buf); \
up(&hba->host_sem); \
return ret; \
@@ -724,8 +960,8 @@ static const struct attribute_group ufs_sysfs_string_descriptors_group = {
static inline bool ufshcd_is_wb_flags(enum flag_idn idn)
{
- return ((idn >= QUERY_FLAG_IDN_WB_EN) &&
- (idn <= QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8));
+ return idn >= QUERY_FLAG_IDN_WB_EN &&
+ idn <= QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8;
}
#define UFS_FLAG(_name, _uname) \
@@ -744,10 +980,10 @@ static ssize_t _name##_show(struct device *dev, \
} \
if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
- pm_runtime_get_sync(hba->dev); \
+ ufshcd_rpm_get_sync(hba); \
ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG, \
QUERY_FLAG_IDN##_uname, index, &flag); \
- pm_runtime_put_sync(hba->dev); \
+ ufshcd_rpm_put_sync(hba); \
if (ret) { \
ret = -EINVAL; \
goto out; \
@@ -793,8 +1029,8 @@ static const struct attribute_group ufs_sysfs_flags_group = {
static inline bool ufshcd_is_wb_attrs(enum attr_idn idn)
{
- return ((idn >= QUERY_ATTR_IDN_WB_FLUSH_STATUS) &&
- (idn <= QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE));
+ return idn >= QUERY_ATTR_IDN_WB_FLUSH_STATUS &&
+ idn <= QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE;
}
#define UFS_ATTRIBUTE(_name, _uname) \
@@ -813,10 +1049,10 @@ static ssize_t _name##_show(struct device *dev, \
} \
if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \
index = ufshcd_wb_get_query_index(hba); \
- pm_runtime_get_sync(hba->dev); \
+ ufshcd_rpm_get_sync(hba); \
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, \
QUERY_ATTR_IDN##_uname, index, 0, &value); \
- pm_runtime_put_sync(hba->dev); \
+ ufshcd_rpm_put_sync(hba); \
if (ret) { \
ret = -EINVAL; \
goto out; \
@@ -881,6 +1117,7 @@ static const struct attribute_group ufs_sysfs_attributes_group = {
static const struct attribute_group *ufs_sysfs_groups[] = {
&ufs_sysfs_default_group,
+ &ufs_sysfs_monitor_group,
&ufs_sysfs_device_descriptor_group,
&ufs_sysfs_interconnect_descriptor_group,
&ufs_sysfs_geometry_descriptor_group,
@@ -964,10 +1201,10 @@ static ssize_t dyn_cap_needed_attribute_show(struct device *dev,
goto out;
}
- pm_runtime_get_sync(hba->dev);
+ ufshcd_rpm_get_sync(hba);
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
QUERY_ATTR_IDN_DYN_CAP_NEEDED, lun, 0, &value);
- pm_runtime_put_sync(hba->dev);
+ ufshcd_rpm_put_sync(hba);
if (ret) {
ret = -EINVAL;
goto out;
diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c
index 5b2bc1a6f922..39bf204c6ec3 100644
--- a/drivers/scsi/ufs/ufs_bsg.c
+++ b/drivers/scsi/ufs/ufs_bsg.c
@@ -97,7 +97,7 @@ static int ufs_bsg_request(struct bsg_job *job)
bsg_reply->reply_payload_rcv_len = 0;
- pm_runtime_get_sync(hba->dev);
+ ufshcd_rpm_get_sync(hba);
msgcode = bsg_request->msgcode;
switch (msgcode) {
@@ -106,7 +106,7 @@ static int ufs_bsg_request(struct bsg_job *job)
ret = ufs_bsg_alloc_desc_buffer(hba, job, &desc_buff,
&desc_len, desc_op);
if (ret) {
- pm_runtime_put_sync(hba->dev);
+ ufshcd_rpm_put_sync(hba);
goto out;
}
@@ -138,7 +138,7 @@ static int ufs_bsg_request(struct bsg_job *job)
break;
}
- pm_runtime_put_sync(hba->dev);
+ ufshcd_rpm_put_sync(hba);
if (!desc_buff)
goto out;
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 23ee828747e2..e6c334bfb4c2 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -410,29 +410,6 @@ static int ufshcd_pci_resume(struct device *dev)
return ufshcd_system_resume(dev_get_drvdata(dev));
}
-/**
- * ufshcd_pci_poweroff - suspend-to-disk poweroff function
- * @dev: pointer to PCI device handle
- *
- * Returns 0 if successful
- * Returns non-zero otherwise
- */
-static int ufshcd_pci_poweroff(struct device *dev)
-{
- struct ufs_hba *hba = dev_get_drvdata(dev);
- int spm_lvl = hba->spm_lvl;
- int ret;
-
- /*
- * For poweroff we need to set the UFS device to PowerDown mode.
- * Force spm_lvl to ensure that.
- */
- hba->spm_lvl = 5;
- ret = ufshcd_system_suspend(hba);
- hba->spm_lvl = spm_lvl;
- return ret;
-}
-
#endif /* !CONFIG_PM_SLEEP */
#ifdef CONFIG_PM
@@ -533,17 +510,14 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
static const struct dev_pm_ops ufshcd_pci_pm_ops = {
-#ifdef CONFIG_PM_SLEEP
- .suspend = ufshcd_pci_suspend,
- .resume = ufshcd_pci_resume,
- .freeze = ufshcd_pci_suspend,
- .thaw = ufshcd_pci_resume,
- .poweroff = ufshcd_pci_poweroff,
- .restore = ufshcd_pci_resume,
-#endif
SET_RUNTIME_PM_OPS(ufshcd_pci_runtime_suspend,
ufshcd_pci_runtime_resume,
ufshcd_pci_runtime_idle)
+ SET_SYSTEM_SLEEP_PM_OPS(ufshcd_pci_suspend, ufshcd_pci_resume)
+#ifdef CONFIG_PM_SLEEP
+ .prepare = ufshcd_suspend_prepare,
+ .complete = ufshcd_resume_complete,
+#endif
};
static const struct pci_device_id ufshcd_pci_tbl[] = {
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 72fd41bfbd54..708b3b62fc4d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -16,6 +16,7 @@
#include <linux/bitfield.h>
#include <linux/blk-pm.h>
#include <linux/blkdev.h>
+#include <scsi/scsi_driver.h>
#include "ufshcd.h"
#include "ufs_quirks.h"
#include "unipro.h"
@@ -24,6 +25,7 @@
#include "ufs_bsg.h"
#include "ufshcd-crypto.h"
#include <asm/unaligned.h>
+#include "../sd.h"
#define CREATE_TRACE_POINTS
#include <trace/events/ufs.h>
@@ -77,6 +79,8 @@
/* Polling time to wait for fDeviceInit */
#define FDEVICEINIT_COMPL_TIMEOUT 1500 /* millisecs */
+#define wlun_dev_to_hba(dv) shost_priv(to_scsi_device(dv)->host)
+
#define ufshcd_toggle_vreg(_dev, _vreg, _on) \
({ \
int _ret; \
@@ -157,17 +161,17 @@ enum {
((h)->eh_flags &= ~UFSHCD_EH_IN_PROGRESS)
struct ufs_pm_lvl_states ufs_pm_lvl_states[] = {
- {UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE},
- {UFS_ACTIVE_PWR_MODE, UIC_LINK_HIBERN8_STATE},
- {UFS_SLEEP_PWR_MODE, UIC_LINK_ACTIVE_STATE},
- {UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE},
- {UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE},
- {UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE},
+ [UFS_PM_LVL_0] = {UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE},
+ [UFS_PM_LVL_1] = {UFS_ACTIVE_PWR_MODE, UIC_LINK_HIBERN8_STATE},
+ [UFS_PM_LVL_2] = {UFS_SLEEP_PWR_MODE, UIC_LINK_ACTIVE_STATE},
+ [UFS_PM_LVL_3] = {UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE},
+ [UFS_PM_LVL_4] = {UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE},
+ [UFS_PM_LVL_5] = {UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE},
/*
* For DeepSleep, the link is first put in hibern8 and then off.
* Leaving the link in hibern8 is not supported.
*/
- {UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE},
+ [UFS_PM_LVL_6] = {UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE},
};
static inline enum ufs_dev_pwr_mode
@@ -298,11 +302,17 @@ static void ufshcd_add_cmd_upiu_trace(struct ufs_hba *hba, unsigned int tag,
enum ufs_trace_str_t str_t)
{
struct utp_upiu_req *rq = hba->lrb[tag].ucd_req_ptr;
+ struct utp_upiu_header *header;
if (!trace_ufshcd_upiu_enabled())
return;
- trace_ufshcd_upiu(dev_name(hba->dev), str_t, &rq->header, &rq->sc.cdb,
+ if (str_t == UFS_CMD_SEND)
+ header = &rq->header;
+ else
+ header = &hba->lrb[tag].ucd_rsp_ptr->header;
+
+ trace_ufshcd_upiu(dev_name(hba->dev), str_t, header, &rq->sc.cdb,
UFS_TSF_CDB);
}
@@ -361,41 +371,40 @@ static void ufshcd_add_uic_command_trace(struct ufs_hba *hba,
static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag,
enum ufs_trace_str_t str_t)
{
- sector_t lba = -1;
+ u64 lba = -1;
u8 opcode = 0, group_id = 0;
u32 intr, doorbell;
struct ufshcd_lrb *lrbp = &hba->lrb[tag];
struct scsi_cmnd *cmd = lrbp->cmd;
int transfer_len = -1;
+ if (!cmd)
+ return;
+
if (!trace_ufshcd_command_enabled()) {
/* trace UPIU W/O tracing command */
- if (cmd)
- ufshcd_add_cmd_upiu_trace(hba, tag, str_t);
+ ufshcd_add_cmd_upiu_trace(hba, tag, str_t);
return;
}
- if (cmd) { /* data phase exists */
- /* trace UPIU also */
- ufshcd_add_cmd_upiu_trace(hba, tag, str_t);
- opcode = cmd->cmnd[0];
- if ((opcode == READ_10) || (opcode == WRITE_10)) {
- /*
- * Currently we only fully trace read(10) and write(10)
- * commands
- */
- if (cmd->request && cmd->request->bio)
- lba = cmd->request->bio->bi_iter.bi_sector;
- transfer_len = be32_to_cpu(
- lrbp->ucd_req_ptr->sc.exp_data_transfer_len);
- if (opcode == WRITE_10)
- group_id = lrbp->cmd->cmnd[6];
- } else if (opcode == UNMAP) {
- if (cmd->request) {
- lba = scsi_get_lba(cmd);
- transfer_len = blk_rq_bytes(cmd->request);
- }
- }
+ /* trace UPIU also */
+ ufshcd_add_cmd_upiu_trace(hba, tag, str_t);
+ opcode = cmd->cmnd[0];
+ lba = sectors_to_logical(cmd->device, blk_rq_pos(cmd->request));
+
+ if (opcode == READ_10 || opcode == WRITE_10) {
+ /*
+ * Currently we only fully trace read(10) and write(10) commands
+ */
+ transfer_len =
+ be32_to_cpu(lrbp->ucd_req_ptr->sc.exp_data_transfer_len);
+ if (opcode == WRITE_10)
+ group_id = lrbp->cmd->cmnd[6];
+ } else if (opcode == UNMAP) {
+ /*
+ * The number of Bytes to be unmapped beginning with the lba.
+ */
+ transfer_len = blk_rq_bytes(cmd->request);
}
intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
@@ -755,7 +764,7 @@ static inline void ufshcd_utmrl_clear(struct ufs_hba *hba, u32 pos)
*/
static inline void ufshcd_outstanding_req_clear(struct ufs_hba *hba, int tag)
{
- __clear_bit(tag, &hba->outstanding_reqs);
+ clear_bit(tag, &hba->outstanding_reqs);
}
/**
@@ -1551,7 +1560,7 @@ static ssize_t ufshcd_clkscale_enable_store(struct device *dev,
if (value == hba->clk_scaling.is_enabled)
goto out;
- pm_runtime_get_sync(hba->dev);
+ ufshcd_rpm_get_sync(hba);
ufshcd_hold(hba, false);
hba->clk_scaling.is_enabled = value;
@@ -1567,7 +1576,7 @@ static ssize_t ufshcd_clkscale_enable_store(struct device *dev,
}
ufshcd_release(hba);
- pm_runtime_put_sync(hba->dev);
+ ufshcd_rpm_put_sync(hba);
out:
up(&hba->host_sem);
return err ? err : count;
@@ -1981,15 +1990,19 @@ static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba)
{
bool queue_resume_work = false;
ktime_t curr_t = ktime_get();
+ unsigned long flags;
if (!ufshcd_is_clkscaling_supported(hba))
return;
+ spin_lock_irqsave(hba->host->host_lock, flags);
if (!hba->clk_scaling.active_reqs++)
queue_resume_work = true;
- if (!hba->clk_scaling.is_enabled || hba->pm_op_in_progress)
+ if (!hba->clk_scaling.is_enabled || hba->pm_op_in_progress) {
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
return;
+ }
if (queue_resume_work)
queue_work(hba->clk_scaling.workq,
@@ -2005,22 +2018,91 @@ static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba)
hba->clk_scaling.busy_start_t = curr_t;
hba->clk_scaling.is_busy_started = true;
}
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
}
static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba)
{
struct ufs_clk_scaling *scaling = &hba->clk_scaling;
+ unsigned long flags;
if (!ufshcd_is_clkscaling_supported(hba))
return;
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->clk_scaling.active_reqs--;
if (!hba->outstanding_reqs && scaling->is_busy_started) {
scaling->tot_busy_t += ktime_to_us(ktime_sub(ktime_get(),
scaling->busy_start_t));
scaling->busy_start_t = 0;
scaling->is_busy_started = false;
}
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+}
+
+static inline int ufshcd_monitor_opcode2dir(u8 opcode)
+{
+ if (opcode == READ_6 || opcode == READ_10 || opcode == READ_16)
+ return READ;
+ else if (opcode == WRITE_6 || opcode == WRITE_10 || opcode == WRITE_16)
+ return WRITE;
+ else
+ return -EINVAL;
+}
+
+static inline bool ufshcd_should_inform_monitor(struct ufs_hba *hba,
+ struct ufshcd_lrb *lrbp)
+{
+ struct ufs_hba_monitor *m = &hba->monitor;
+
+ return (m->enabled && lrbp && lrbp->cmd &&
+ (!m->chunk_size || m->chunk_size == lrbp->cmd->sdb.length) &&
+ ktime_before(hba->monitor.enabled_ts, lrbp->issue_time_stamp));
+}
+
+static void ufshcd_start_monitor(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+ int dir = ufshcd_monitor_opcode2dir(*lrbp->cmd->cmnd);
+ unsigned long flags;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ if (dir >= 0 && hba->monitor.nr_queued[dir]++ == 0)
+ hba->monitor.busy_start_ts[dir] = ktime_get();
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+}
+
+static void ufshcd_update_monitor(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+ int dir = ufshcd_monitor_opcode2dir(*lrbp->cmd->cmnd);
+ unsigned long flags;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ if (dir >= 0 && hba->monitor.nr_queued[dir] > 0) {
+ struct request *req = lrbp->cmd->request;
+ struct ufs_hba_monitor *m = &hba->monitor;
+ ktime_t now, inc, lat;
+
+ now = lrbp->compl_time_stamp;
+ inc = ktime_sub(now, m->busy_start_ts[dir]);
+ m->total_busy[dir] = ktime_add(m->total_busy[dir], inc);
+ m->nr_sec_rw[dir] += blk_rq_sectors(req);
+
+ /* Update latencies */
+ m->nr_req[dir]++;
+ lat = ktime_sub(now, lrbp->issue_time_stamp);
+ m->lat_sum[dir] += lat;
+ if (m->lat_max[dir] < lat || !m->lat_max[dir])
+ m->lat_max[dir] = lat;
+ if (m->lat_min[dir] > lat || !m->lat_min[dir])
+ m->lat_min[dir] = lat;
+
+ m->nr_queued[dir]--;
+ /* Push forward the busy start of monitor */
+ m->busy_start_ts[dir] = now;
+ }
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
}
+
/**
* ufshcd_send_command - Send SCSI or device management commands
* @hba: per adapter instance
@@ -2036,8 +2118,21 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
ufshcd_vops_setup_xfer_req(hba, task_tag, (lrbp->cmd ? true : false));
ufshcd_add_command_trace(hba, task_tag, UFS_CMD_SEND);
ufshcd_clk_scaling_start_busy(hba);
- __set_bit(task_tag, &hba->outstanding_reqs);
- ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
+ if (unlikely(ufshcd_should_inform_monitor(hba, lrbp)))
+ ufshcd_start_monitor(hba, lrbp);
+ if (ufshcd_has_utrlcnr(hba)) {
+ set_bit(task_tag, &hba->outstanding_reqs);
+ ufshcd_writel(hba, 1 << task_tag,
+ REG_UTP_TRANSFER_REQ_DOOR_BELL);
+ } else {
+ unsigned long flags;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ set_bit(task_tag, &hba->outstanding_reqs);
+ ufshcd_writel(hba, 1 << task_tag,
+ REG_UTP_TRANSFER_REQ_DOOR_BELL);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ }
/* Make sure that doorbell is committed immediately */
wmb();
}
@@ -2565,6 +2660,17 @@ static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id)
return (upiu_wlun_id & ~UFS_UPIU_WLUN_ID) | SCSI_W_LUN_BASE;
}
+static inline bool is_rpmb_wlun(struct scsi_device *sdev)
+{
+ return sdev->lun == ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN);
+}
+
+static inline bool is_device_wlun(struct scsi_device *sdev)
+{
+ return sdev->lun ==
+ ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN);
+}
+
static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i)
{
struct utp_transfer_cmd_desc *cmd_descp = hba->ucdl_base_addr;
@@ -2597,7 +2703,6 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
{
struct ufshcd_lrb *lrbp;
struct ufs_hba *hba;
- unsigned long flags;
int tag;
int err = 0;
@@ -2614,6 +2719,43 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
if (!down_read_trylock(&hba->clk_scaling_lock))
return SCSI_MLQUEUE_HOST_BUSY;
+ switch (hba->ufshcd_state) {
+ case UFSHCD_STATE_OPERATIONAL:
+ case UFSHCD_STATE_EH_SCHEDULED_NON_FATAL:
+ break;
+ case UFSHCD_STATE_EH_SCHEDULED_FATAL:
+ /*
+ * pm_runtime_get_sync() is used at error handling preparation
+ * stage. If a scsi cmd, e.g. the SSU cmd, is sent from hba's
+ * PM ops, it can never be finished if we let SCSI layer keep
+ * retrying it, which gets err handler stuck forever. Neither
+ * can we let the scsi cmd pass through, because UFS is in bad
+ * state, the scsi cmd may eventually time out, which will get
+ * err handler blocked for too long. So, just fail the scsi cmd
+ * sent from PM ops, err handler can recover PM error anyways.
+ */
+ if (hba->pm_op_in_progress) {
+ hba->force_reset = true;
+ set_host_byte(cmd, DID_BAD_TARGET);
+ cmd->scsi_done(cmd);
+ goto out;
+ }
+ fallthrough;
+ case UFSHCD_STATE_RESET:
+ err = SCSI_MLQUEUE_HOST_BUSY;
+ goto out;
+ case UFSHCD_STATE_ERROR:
+ set_host_byte(cmd, DID_ERROR);
+ cmd->scsi_done(cmd);
+ goto out;
+ default:
+ dev_WARN_ONCE(hba->dev, 1, "%s: invalid state %d\n",
+ __func__, hba->ufshcd_state);
+ set_host_byte(cmd, DID_BAD_TARGET);
+ cmd->scsi_done(cmd);
+ goto out;
+ }
+
hba->req_abort_count = 0;
err = ufshcd_hold(hba, true);
@@ -2624,8 +2766,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
WARN_ON(ufshcd_is_clkgating_allowed(hba) &&
(hba->clk_gating.state != CLKS_ON));
- lrbp = &hba->lrb[tag];
- if (unlikely(lrbp->in_use)) {
+ if (unlikely(test_bit(tag, &hba->outstanding_reqs))) {
if (hba->pm_op_in_progress)
set_host_byte(cmd, DID_BAD_TARGET);
else
@@ -2634,6 +2775,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
goto out;
}
+ lrbp = &hba->lrb[tag];
WARN_ON(lrbp->cmd);
lrbp->cmd = cmd;
lrbp->sense_bufflen = UFS_SENSE_SIZE;
@@ -2657,51 +2799,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
/* Make sure descriptors are ready before ringing the doorbell */
wmb();
- spin_lock_irqsave(hba->host->host_lock, flags);
- switch (hba->ufshcd_state) {
- case UFSHCD_STATE_OPERATIONAL:
- case UFSHCD_STATE_EH_SCHEDULED_NON_FATAL:
- break;
- case UFSHCD_STATE_EH_SCHEDULED_FATAL:
- /*
- * pm_runtime_get_sync() is used at error handling preparation
- * stage. If a scsi cmd, e.g. the SSU cmd, is sent from hba's
- * PM ops, it can never be finished if we let SCSI layer keep
- * retrying it, which gets err handler stuck forever. Neither
- * can we let the scsi cmd pass through, because UFS is in bad
- * state, the scsi cmd may eventually time out, which will get
- * err handler blocked for too long. So, just fail the scsi cmd
- * sent from PM ops, err handler can recover PM error anyways.
- */
- if (hba->pm_op_in_progress) {
- hba->force_reset = true;
- set_host_byte(cmd, DID_BAD_TARGET);
- goto out_compl_cmd;
- }
- fallthrough;
- case UFSHCD_STATE_RESET:
- err = SCSI_MLQUEUE_HOST_BUSY;
- goto out_compl_cmd;
- case UFSHCD_STATE_ERROR:
- set_host_byte(cmd, DID_ERROR);
- goto out_compl_cmd;
- default:
- dev_WARN_ONCE(hba->dev, 1, "%s: invalid state %d\n",
- __func__, hba->ufshcd_state);
- set_host_byte(cmd, DID_BAD_TARGET);
- goto out_compl_cmd;
- }
ufshcd_send_command(hba, tag);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- goto out;
-
-out_compl_cmd:
- scsi_dma_unmap(lrbp->cmd);
- lrbp->cmd = NULL;
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- ufshcd_release(hba);
- if (!err)
- cmd->scsi_done(cmd);
out:
up_read(&hba->clk_scaling_lock);
return err;
@@ -2735,7 +2833,7 @@ ufshcd_clear_cmd(struct ufs_hba *hba, int tag)
spin_unlock_irqrestore(hba->host->host_lock, flags);
/*
- * wait for for h/w to clear corresponding bit in door-bell.
+ * wait for h/w to clear corresponding bit in door-bell.
* max. wait is 1 sec.
*/
err = ufshcd_wait_for_register(hba,
@@ -2856,7 +2954,6 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
int err;
int tag;
struct completion wait;
- unsigned long flags;
down_read(&hba->clk_scaling_lock);
@@ -2876,34 +2973,30 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
req->timeout = msecs_to_jiffies(2 * timeout);
blk_mq_start_request(req);
- init_completion(&wait);
- lrbp = &hba->lrb[tag];
- if (unlikely(lrbp->in_use)) {
+ if (unlikely(test_bit(tag, &hba->outstanding_reqs))) {
err = -EBUSY;
goto out;
}
+ init_completion(&wait);
+ lrbp = &hba->lrb[tag];
WARN_ON(lrbp->cmd);
err = ufshcd_compose_dev_cmd(hba, lrbp, cmd_type, tag);
if (unlikely(err))
- goto out_put_tag;
+ goto out;
hba->dev_cmd.complete = &wait;
ufshcd_add_query_upiu_trace(hba, UFS_QUERY_SEND, lrbp->ucd_req_ptr);
/* Make sure descriptors are ready before ringing the doorbell */
wmb();
- spin_lock_irqsave(hba->host->host_lock, flags);
- ufshcd_send_command(hba, tag);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
+ ufshcd_send_command(hba, tag);
err = ufshcd_wait_for_dev_cmd(hba, lrbp, timeout);
-
-out:
ufshcd_add_query_upiu_trace(hba, err ? UFS_QUERY_ERR : UFS_QUERY_COMP,
(struct utp_upiu_req *)lrbp->ucd_rsp_ptr);
-out_put_tag:
+out:
blk_put_request(req);
out_unlock:
up_read(&hba->clk_scaling_lock);
@@ -4101,12 +4194,13 @@ void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit)
}
spin_unlock_irqrestore(hba->host->host_lock, flags);
- if (update && !pm_runtime_suspended(hba->dev)) {
- pm_runtime_get_sync(hba->dev);
+ if (update &&
+ !pm_runtime_suspended(&hba->sdev_ufs_device->sdev_gendev)) {
+ ufshcd_rpm_get_sync(hba);
ufshcd_hold(hba, false);
ufshcd_auto_hibern8_enable(hba);
ufshcd_release(hba);
- pm_runtime_put(hba->dev);
+ ufshcd_rpm_put_sync(hba);
}
}
EXPORT_SYMBOL_GPL(ufshcd_auto_hibern8_update);
@@ -4420,7 +4514,7 @@ EXPORT_SYMBOL_GPL(ufshcd_make_hba_operational);
* ufshcd_hba_stop - Send controller to reset state
* @hba: per adapter instance
*/
-static inline void ufshcd_hba_stop(struct ufs_hba *hba)
+void ufshcd_hba_stop(struct ufs_hba *hba)
{
unsigned long flags;
int err;
@@ -4439,6 +4533,7 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba)
if (err)
dev_err(hba->dev, "%s: Controller disable failed\n", __func__);
}
+EXPORT_SYMBOL_GPL(ufshcd_hba_stop);
/**
* ufshcd_hba_execute_hce - initialize the controller
@@ -4804,6 +4899,43 @@ static inline void ufshcd_get_lu_power_on_wp_status(struct ufs_hba *hba,
}
/**
+ * ufshcd_setup_links - associate link b/w device wlun and other luns
+ * @sdev: pointer to SCSI device
+ * @hba: pointer to ufs hba
+ */
+static void ufshcd_setup_links(struct ufs_hba *hba, struct scsi_device *sdev)
+{
+ struct device_link *link;
+
+ /*
+ * Device wlun is the supplier & rest of the luns are consumers.
+ * This ensures that device wlun suspends after all other luns.
+ */
+ if (hba->sdev_ufs_device) {
+ link = device_link_add(&sdev->sdev_gendev,
+ &hba->sdev_ufs_device->sdev_gendev,
+ DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+ if (!link) {
+ dev_err(&sdev->sdev_gendev, "Failed establishing link - %s\n",
+ dev_name(&hba->sdev_ufs_device->sdev_gendev));
+ return;
+ }
+ hba->luns_avail--;
+ /* Ignore REPORT_LUN wlun probing */
+ if (hba->luns_avail == 1) {
+ ufshcd_rpm_put(hba);
+ return;
+ }
+ } else {
+ /*
+ * Device wlun is probed. The assumption is that WLUNs are
+ * scanned before other LUNs.
+ */
+ hba->luns_avail--;
+ }
+}
+
+/**
* ufshcd_slave_alloc - handle initial SCSI device configurations
* @sdev: pointer to SCSI device
*
@@ -4834,6 +4966,8 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev)
ufshcd_get_lu_power_on_wp_status(hba, sdev);
+ ufshcd_setup_links(hba, sdev);
+
return 0;
}
@@ -4865,8 +4999,13 @@ static int ufshcd_slave_configure(struct scsi_device *sdev)
blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1);
if (hba->quirks & UFSHCD_QUIRK_ALIGN_SG_WITH_PAGE_SIZE)
blk_queue_update_dma_alignment(q, PAGE_SIZE - 1);
-
- if (ufshcd_is_rpm_autosuspend_allowed(hba))
+ /*
+ * Block runtime-pm until all consumers are added.
+ * Refer ufshcd_setup_links().
+ */
+ if (is_device_wlun(sdev))
+ pm_runtime_get_noresume(&sdev->sdev_gendev);
+ else if (ufshcd_is_rpm_autosuspend_allowed(hba))
sdev->rpm_autosuspend = 1;
ufshcd_crypto_setup_rq_keyslot_manager(hba, q);
@@ -4982,15 +5121,9 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
*/
if (!hba->pm_op_in_progress &&
!ufshcd_eh_in_progress(hba) &&
- ufshcd_is_exception_event(lrbp->ucd_rsp_ptr) &&
- schedule_work(&hba->eeh_work)) {
- /*
- * Prevent suspend once eeh_work is scheduled
- * to avoid deadlock between ufshcd_suspend
- * and exception event handler.
- */
- pm_runtime_get_noresume(hba->dev);
- }
+ ufshcd_is_exception_event(lrbp->ucd_rsp_ptr))
+ /* Flushed in suspend */
+ schedule_work(&hba->eeh_work);
break;
case UPIU_TRANSACTION_REJECT_UPIU:
/* TODO: handle Reject UPIU Response */
@@ -5037,6 +5170,24 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
return result;
}
+static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba,
+ u32 intr_mask)
+{
+ if (!ufshcd_is_auto_hibern8_supported(hba) ||
+ !ufshcd_is_auto_hibern8_enabled(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_uic_cmd_compl - handle completion of uic command
* @hba: per adapter instance
@@ -5050,6 +5201,10 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
{
irqreturn_t retval = IRQ_NONE;
+ spin_lock(hba->host->host_lock);
+ if (ufshcd_is_auto_hibern8_error(hba, intr_status))
+ hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status);
+
if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) {
hba->active_uic_cmd->argument2 |=
ufshcd_get_uic_cmd_result(hba);
@@ -5070,6 +5225,7 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
if (retval == IRQ_HANDLED)
ufshcd_add_uic_command_trace(hba, hba->active_uic_cmd,
UFS_CMD_COMP);
+ spin_unlock(hba->host->host_lock);
return retval;
}
@@ -5088,11 +5244,14 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
bool update_scaling = false;
for_each_set_bit(index, &completed_reqs, hba->nutrs) {
+ if (!test_and_clear_bit(index, &hba->outstanding_reqs))
+ continue;
lrbp = &hba->lrb[index];
- lrbp->in_use = false;
lrbp->compl_time_stamp = ktime_get();
cmd = lrbp->cmd;
if (cmd) {
+ if (unlikely(ufshcd_should_inform_monitor(hba, lrbp)))
+ ufshcd_update_monitor(hba, lrbp);
ufshcd_add_command_trace(hba, index, UFS_CMD_COMP);
result = ufshcd_transfer_rsp_status(hba, lrbp);
scsi_dma_unmap(cmd);
@@ -5101,7 +5260,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
lrbp->cmd = NULL;
/* Do not touch lrbp after scsi done */
cmd->scsi_done(cmd);
- __ufshcd_release(hba);
+ ufshcd_release(hba);
update_scaling = true;
} else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE ||
lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) {
@@ -5112,28 +5271,23 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
update_scaling = true;
}
}
- if (ufshcd_is_clkscaling_supported(hba) && update_scaling)
- hba->clk_scaling.active_reqs--;
+ if (update_scaling)
+ ufshcd_clk_scaling_update_busy(hba);
}
-
- /* clear corresponding bits of completed commands */
- hba->outstanding_reqs ^= completed_reqs;
-
- ufshcd_clk_scaling_update_busy(hba);
}
/**
- * ufshcd_transfer_req_compl - handle SCSI and query command completion
+ * ufshcd_trc_handler - handle transfer requests completion
* @hba: per adapter instance
+ * @use_utrlcnr: get completed requests from UTRLCNR
*
* Returns
* IRQ_HANDLED - If interrupt is valid
* IRQ_NONE - If invalid interrupt
*/
-static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba)
+static irqreturn_t ufshcd_trc_handler(struct ufs_hba *hba, bool use_utrlcnr)
{
- unsigned long completed_reqs;
- u32 tr_doorbell;
+ unsigned long completed_reqs = 0;
/* Resetting interrupt aggregation counters first and reading the
* DOOR_BELL afterward allows us to handle all the completed requests.
@@ -5146,8 +5300,24 @@ static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba)
!(hba->quirks & UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR))
ufshcd_reset_intr_aggr(hba);
- tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
- completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
+ if (use_utrlcnr) {
+ u32 utrlcnr;
+
+ utrlcnr = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_LIST_COMPL);
+ if (utrlcnr) {
+ ufshcd_writel(hba, utrlcnr,
+ REG_UTP_TRANSFER_REQ_LIST_COMPL);
+ completed_reqs = utrlcnr;
+ }
+ } else {
+ unsigned long flags;
+ u32 tr_doorbell;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
+ completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ }
if (completed_reqs) {
__ufshcd_transfer_req_compl(hba, completed_reqs);
@@ -5589,8 +5759,8 @@ static void ufshcd_rpm_dev_flush_recheck_work(struct work_struct *work)
* after a certain delay to recheck the threshold by next runtime
* suspend.
*/
- pm_runtime_get_sync(hba->dev);
- pm_runtime_put_sync(hba->dev);
+ ufshcd_rpm_get_sync(hba);
+ ufshcd_rpm_put_sync(hba);
}
/**
@@ -5607,7 +5777,6 @@ static void ufshcd_exception_event_handler(struct work_struct *work)
u32 status = 0;
hba = container_of(work, struct ufs_hba, eeh_work);
- pm_runtime_get_sync(hba->dev);
ufshcd_scsi_block_requests(hba);
err = ufshcd_get_ee_status(hba, &status);
if (err) {
@@ -5624,21 +5793,13 @@ static void ufshcd_exception_event_handler(struct work_struct *work)
ufs_debugfs_exception_event(hba, status);
out:
ufshcd_scsi_unblock_requests(hba);
- /*
- * pm_runtime_get_noresume is called while scheduling
- * eeh_work to avoid suspend racing with exception work.
- * Hence decrement usage counter using pm_runtime_put_noidle
- * to allow suspend on completion of exception event handler.
- */
- pm_runtime_put_noidle(hba->dev);
- pm_runtime_put(hba->dev);
return;
}
/* Complete requests that have door-bell cleared */
static void ufshcd_complete_requests(struct ufs_hba *hba)
{
- ufshcd_transfer_req_compl(hba);
+ ufshcd_trc_handler(hba, false);
ufshcd_tmc_handler(hba);
}
@@ -5756,12 +5917,13 @@ static void ufshcd_clk_scaling_suspend(struct ufs_hba *hba, bool suspend)
static void ufshcd_err_handling_prepare(struct ufs_hba *hba)
{
- pm_runtime_get_sync(hba->dev);
- if (pm_runtime_status_suspended(hba->dev) || hba->is_sys_suspended) {
+ ufshcd_rpm_get_sync(hba);
+ if (pm_runtime_status_suspended(&hba->sdev_ufs_device->sdev_gendev) ||
+ hba->is_sys_suspended) {
enum ufs_pm_op pm_op;
/*
- * Don't assume anything of pm_runtime_get_sync(), if
+ * Don't assume anything of resume, if
* resume fails, irq and clocks can be OFF, and powers
* can be OFF or in LPM.
*/
@@ -5797,12 +5959,13 @@ static void ufshcd_err_handling_unprepare(struct ufs_hba *hba)
if (ufshcd_is_clkscaling_supported(hba))
ufshcd_clk_scaling_suspend(hba, false);
ufshcd_clear_ua_wluns(hba);
- pm_runtime_put(hba->dev);
+ ufshcd_rpm_put(hba);
}
static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba)
{
return (!hba->is_powered || hba->shutting_down ||
+ !hba->sdev_ufs_device ||
hba->ufshcd_state == UFSHCD_STATE_ERROR ||
(!(hba->saved_err || hba->saved_uic_err || hba->force_reset ||
ufshcd_is_link_broken(hba))));
@@ -5818,14 +5981,18 @@ static void ufshcd_recover_pm_error(struct ufs_hba *hba)
hba->is_sys_suspended = false;
/*
- * Set RPM status of hba device to RPM_ACTIVE,
+ * Set RPM status of wlun device to RPM_ACTIVE,
* this also clears its runtime error.
*/
- ret = pm_runtime_set_active(hba->dev);
+ ret = pm_runtime_set_active(&hba->sdev_ufs_device->sdev_gendev);
+
+ /* hba device might have a runtime error otherwise */
+ if (ret)
+ ret = pm_runtime_set_active(hba->dev);
/*
- * If hba device had runtime error, we also need to resume those
- * scsi devices under hba in case any of them has failed to be
- * resumed due to hba runtime resume failure. This is to unblock
+ * If wlun device had runtime error, we also need to resume those
+ * consumer scsi devices in case any of them has failed to be
+ * resumed due to supplier runtime resume failure. This is to unblock
* blk_queue_enter in case there are bios waiting inside it.
*/
if (!ret) {
@@ -5887,13 +6054,11 @@ static void ufshcd_err_handler(struct work_struct *work)
ufshcd_set_eh_in_progress(hba);
spin_unlock_irqrestore(hba->host->host_lock, flags);
ufshcd_err_handling_prepare(hba);
+ /* Complete requests that have door-bell cleared by h/w */
+ ufshcd_complete_requests(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
if (hba->ufshcd_state != UFSHCD_STATE_ERROR)
hba->ufshcd_state = UFSHCD_STATE_RESET;
-
- /* Complete requests that have door-bell cleared by h/w */
- ufshcd_complete_requests(hba);
-
/*
* A full reset and restore might have happened after preparation
* is finished, double check whether we should stop.
@@ -5976,12 +6141,11 @@ static void ufshcd_err_handler(struct work_struct *work)
}
lock_skip_pending_xfer_clear:
- spin_lock_irqsave(hba->host->host_lock, flags);
-
/* Complete the requests that are cleared by s/w */
ufshcd_complete_requests(hba);
- hba->silence_err_logs = false;
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->silence_err_logs = false;
if (err_xfer || err_tm) {
needs_reset = true;
goto do_reset;
@@ -6014,19 +6178,6 @@ lock_skip_pending_xfer_clear:
do_reset:
/* Fatal errors need reset */
if (needs_reset) {
- unsigned long max_doorbells = (1UL << hba->nutrs) - 1;
-
- /*
- * ufshcd_reset_and_restore() does the link reinitialization
- * which will need atleast one empty doorbell slot to send the
- * device management commands (NOP and query commands).
- * If there is no slot empty at this moment then free up last
- * slot forcefully.
- */
- if (hba->outstanding_reqs == max_doorbells)
- __ufshcd_transfer_req_compl(hba,
- (1UL << (hba->nutrs - 1)));
-
hba->force_reset = false;
spin_unlock_irqrestore(hba->host->host_lock, flags);
err = ufshcd_reset_and_restore(hba);
@@ -6144,37 +6295,23 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba)
return retval;
}
-static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba,
- u32 intr_mask)
-{
- if (!ufshcd_is_auto_hibern8_supported(hba) ||
- !ufshcd_is_auto_hibern8_enabled(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
+ * @intr_status: interrupt status generated by the controller
*
* Returns
* IRQ_HANDLED - If interrupt is valid
* IRQ_NONE - If invalid interrupt
*/
-static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba)
+static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba, u32 intr_status)
{
bool queue_eh_work = false;
irqreturn_t retval = IRQ_NONE;
+ spin_lock(hba->host->host_lock);
+ hba->errors |= UFSHCD_ERROR_MASK & intr_status;
+
if (hba->errors & INT_FATAL_ERRORS) {
ufshcd_update_evt_hist(hba, UFS_EVT_FATAL_ERR,
hba->errors);
@@ -6229,6 +6366,9 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba)
* itself without s/w intervention or errors that will be
* handled by the SCSI core layer.
*/
+ hba->errors = 0;
+ hba->uic_error = 0;
+ spin_unlock(hba->host->host_lock);
return retval;
}
@@ -6263,13 +6403,17 @@ static bool ufshcd_compl_tm(struct request *req, void *priv, bool reserved)
*/
static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba)
{
+ unsigned long flags;
struct request_queue *q = hba->tmf_queue;
struct ctm_info ci = {
.hba = hba,
- .pending = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL),
};
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ ci.pending = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
blk_mq_tagset_busy_iter(q->tag_set, ufshcd_compl_tm, &ci);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
return ci.ncpl ? IRQ_HANDLED : IRQ_NONE;
}
@@ -6286,22 +6430,17 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
{
irqreturn_t retval = IRQ_NONE;
- 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)
- retval |= ufshcd_check_errors(hba);
-
if (intr_status & UFSHCD_UIC_MASK)
retval |= ufshcd_uic_cmd_compl(hba, intr_status);
+ if (intr_status & UFSHCD_ERROR_MASK || hba->errors)
+ retval |= ufshcd_check_errors(hba, intr_status);
+
if (intr_status & UTP_TASK_REQ_COMPL)
retval |= ufshcd_tmc_handler(hba);
if (intr_status & UTP_TRANSFER_REQ_COMPL)
- retval |= ufshcd_transfer_req_compl(hba);
+ retval |= ufshcd_trc_handler(hba, ufshcd_has_utrlcnr(hba));
return retval;
}
@@ -6322,7 +6461,6 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
struct ufs_hba *hba = __hba;
int retries = hba->nutrs;
- spin_lock(hba->host->host_lock);
intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
hba->ufs_stats.last_intr_status = intr_status;
hba->ufs_stats.last_intr_ts = ktime_get();
@@ -6344,7 +6482,8 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
}
if (enabled_intr_status && retval == IRQ_NONE &&
- !ufshcd_eh_in_progress(hba)) {
+ (!(enabled_intr_status & UTP_TRANSFER_REQ_COMPL) ||
+ hba->outstanding_reqs) && !ufshcd_eh_in_progress(hba)) {
dev_err(hba->dev, "%s: Unhandled interrupt 0x%08x (0x%08x, 0x%08x)\n",
__func__,
intr_status,
@@ -6353,7 +6492,6 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
ufshcd_dump_regs(hba, 0, UFSHCI_REG_SPACE_SIZE, "host_regs: ");
}
- spin_unlock(hba->host->host_lock);
return retval;
}
@@ -6530,7 +6668,6 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
int err = 0;
int tag;
struct completion wait;
- unsigned long flags;
u8 upiu_flags;
down_read(&hba->clk_scaling_lock);
@@ -6543,13 +6680,13 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
tag = req->tag;
WARN_ON_ONCE(!ufshcd_valid_tag(hba, tag));
- init_completion(&wait);
- lrbp = &hba->lrb[tag];
- if (unlikely(lrbp->in_use)) {
+ if (unlikely(test_bit(tag, &hba->outstanding_reqs))) {
err = -EBUSY;
goto out;
}
+ init_completion(&wait);
+ lrbp = &hba->lrb[tag];
WARN_ON(lrbp->cmd);
lrbp->cmd = NULL;
lrbp->sense_bufflen = 0;
@@ -6585,12 +6722,11 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
hba->dev_cmd.complete = &wait;
+ ufshcd_add_query_upiu_trace(hba, UFS_QUERY_SEND, lrbp->ucd_req_ptr);
/* Make sure descriptors are ready before ringing the doorbell */
wmb();
- spin_lock_irqsave(hba->host->host_lock, flags);
- ufshcd_send_command(hba, tag);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
+ ufshcd_send_command(hba, tag);
/*
* ignore the returning value here - ufshcd_check_query_response is
* bound to fail since dev_cmd.query and dev_cmd.type were left empty.
@@ -6616,6 +6752,8 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
err = -EINVAL;
}
}
+ ufshcd_add_query_upiu_trace(hba, err ? UFS_QUERY_ERR : UFS_QUERY_COMP,
+ (struct utp_upiu_req *)lrbp->ucd_rsp_ptr);
out:
blk_put_request(req);
@@ -6709,7 +6847,6 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
u32 pos;
int err;
u8 resp = 0xF, lun;
- unsigned long flags;
host = cmd->device->host;
hba = shost_priv(host);
@@ -6728,11 +6865,9 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
err = ufshcd_clear_cmd(hba, pos);
if (err)
break;
+ __ufshcd_transfer_req_compl(hba, pos);
}
}
- spin_lock_irqsave(host->host_lock, flags);
- ufshcd_transfer_req_compl(hba);
- spin_unlock_irqrestore(host->host_lock, flags);
out:
hba->req_abort_count = 0;
@@ -6909,20 +7044,16 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
* will fail, due to spec violation, scsi err handling next step
* will be to send LU reset which, again, is a spec violation.
* To avoid these unnecessary/illegal steps, first we clean up
- * the lrb taken by this cmd and mark the lrb as in_use, then
- * queue the eh_work and bail.
+ * the lrb taken by this cmd and re-set it in outstanding_reqs,
+ * then queue the eh_work and bail.
*/
if (lrbp->lun == UFS_UPIU_UFS_DEVICE_WLUN) {
ufshcd_update_evt_hist(hba, UFS_EVT_ABORT, lrbp->lun);
+ __ufshcd_transfer_req_compl(hba, (1UL << tag));
+ set_bit(tag, &hba->outstanding_reqs);
spin_lock_irqsave(host->host_lock, flags);
- if (lrbp->cmd) {
- __ufshcd_transfer_req_compl(hba, (1UL << tag));
- __set_bit(tag, &hba->outstanding_reqs);
- lrbp->in_use = true;
- hba->force_reset = true;
- ufshcd_schedule_eh_work(hba);
- }
-
+ hba->force_reset = true;
+ ufshcd_schedule_eh_work(hba);
spin_unlock_irqrestore(host->host_lock, flags);
goto out;
}
@@ -6935,9 +7066,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
if (!err) {
cleanup:
- spin_lock_irqsave(host->host_lock, flags);
__ufshcd_transfer_req_compl(hba, (1UL << tag));
- spin_unlock_irqrestore(host->host_lock, flags);
out:
err = SUCCESS;
} else {
@@ -6967,19 +7096,15 @@ out:
static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
{
int err;
- unsigned long flags;
/*
* Stop the host controller and complete the requests
* cleared by h/w
*/
ufshcd_hba_stop(hba);
-
- spin_lock_irqsave(hba->host->host_lock, flags);
hba->silence_err_logs = true;
ufshcd_complete_requests(hba);
hba->silence_err_logs = false;
- spin_unlock_irqrestore(hba->host->host_lock, flags);
/* scale up clocks to max frequency before full reinitialization */
ufshcd_set_clk_freq(hba, true);
@@ -7249,7 +7374,6 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
hba->sdev_ufs_device = NULL;
goto out;
}
- ufshcd_blk_pm_runtime_init(hba->sdev_ufs_device);
scsi_device_put(hba->sdev_ufs_device);
hba->sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
@@ -7413,6 +7537,9 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
goto out;
}
+ hba->luns_avail = desc_buf[DEVICE_DESC_PARAM_NUM_LU] +
+ desc_buf[DEVICE_DESC_PARAM_NUM_WLU];
+
ufs_fixup_device_setup(hba);
ufshcd_wb_probe(hba, desc_buf);
@@ -7890,6 +8017,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool async)
ufshcd_set_ufs_dev_active(hba);
ufshcd_force_reset_auto_bkops(hba);
hba->wlun_dev_clr_ua = true;
+ hba->wlun_rpmb_clr_ua = true;
/* Gear up to HS gear if supported */
if (hba->max_pwr_info.is_valid) {
@@ -8475,7 +8603,8 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
* handling context.
*/
hba->host->eh_noresume = 1;
- ufshcd_clear_ua_wluns(hba);
+ if (hba->wlun_dev_clr_ua)
+ ufshcd_clear_ua_wlun(hba, UFS_UPIU_UFS_DEVICE_WLUN);
cmd[4] = pwr_mode << 4;
@@ -8490,7 +8619,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
sdev_printk(KERN_WARNING, sdp,
"START_STOP failed for power mode: %d, result %x\n",
pwr_mode, ret);
- if (driver_byte(ret) == DRIVER_SENSE)
+ if (ret > 0 && scsi_sense_valid(&sshdr))
scsi_print_sense_hdr(sdp, NULL, &sshdr);
}
@@ -8650,23 +8779,7 @@ static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba)
ufshcd_setup_hba_vreg(hba, true);
}
-/**
- * ufshcd_suspend - helper function for suspend operations
- * @hba: per adapter instance
- * @pm_op: desired low power operation type
- *
- * This function will try to put the UFS device and link into low power
- * mode based on the "rpm_lvl" (Runtime PM level) or "spm_lvl"
- * (System PM level).
- *
- * If this function is called during shutdown, it will make sure that
- * both UFS device and UFS link is powered off.
- *
- * NOTE: UFS device & link must be active before we enter in this function.
- *
- * Returns 0 for success and non-zero for failure
- */
-static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
+static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
int ret = 0;
int check_for_bkops;
@@ -8674,9 +8787,9 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
enum ufs_dev_pwr_mode req_dev_pwr_mode;
enum uic_link_state req_link_state;
- hba->pm_op_in_progress = 1;
- if (!ufshcd_is_shutdown_pm(pm_op)) {
- pm_lvl = ufshcd_is_runtime_pm(pm_op) ?
+ hba->pm_op_in_progress = true;
+ if (pm_op != UFS_SHUTDOWN_PM) {
+ pm_lvl = pm_op == UFS_RUNTIME_PM ?
hba->rpm_lvl : hba->spm_lvl;
req_dev_pwr_mode = ufs_get_pm_lvl_to_dev_pwr_mode(pm_lvl);
req_link_state = ufs_get_pm_lvl_to_link_pwr_state(pm_lvl);
@@ -8697,20 +8810,20 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
if (req_dev_pwr_mode == UFS_ACTIVE_PWR_MODE &&
req_link_state == UIC_LINK_ACTIVE_STATE) {
- goto disable_clks;
+ goto vops_suspend;
}
if ((req_dev_pwr_mode == hba->curr_dev_pwr_mode) &&
(req_link_state == hba->uic_link_state))
- goto enable_gating;
+ goto enable_scaling;
/* UFS device & link must be active before we enter in this function */
if (!ufshcd_is_ufs_dev_active(hba) || !ufshcd_is_link_active(hba)) {
ret = -EINVAL;
- goto enable_gating;
+ goto enable_scaling;
}
- if (ufshcd_is_runtime_pm(pm_op)) {
+ if (pm_op == UFS_RUNTIME_PM) {
if (ufshcd_can_autobkops_during_suspend(hba)) {
/*
* The device is idle with no requests in the queue,
@@ -8719,7 +8832,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
*/
ret = ufshcd_urgent_bkops(hba);
if (ret)
- goto enable_gating;
+ goto enable_scaling;
} else {
/* make sure that auto bkops is disabled */
ufshcd_disable_auto_bkops(hba);
@@ -8740,14 +8853,14 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
flush_work(&hba->eeh_work);
if (req_dev_pwr_mode != hba->curr_dev_pwr_mode) {
- if (!ufshcd_is_runtime_pm(pm_op))
+ if (pm_op != UFS_RUNTIME_PM)
/* ensure that bkops is disabled */
ufshcd_disable_auto_bkops(hba);
if (!hba->dev_info.b_rpm_dev_flush_capable) {
ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode);
if (ret)
- goto enable_gating;
+ goto enable_scaling;
}
}
@@ -8760,7 +8873,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
if (ret)
goto set_dev_active;
-disable_clks:
+vops_suspend:
/*
* Call vendor specific suspend callback. As these callbacks may access
* vendor specific host controller register space call them before the
@@ -8769,28 +8882,9 @@ disable_clks:
ret = ufshcd_vops_suspend(hba, pm_op);
if (ret)
goto set_link_active;
- /*
- * Disable the host irq as host controller as there won't be any
- * host controller transaction expected till resume.
- */
- ufshcd_disable_irq(hba);
-
- ufshcd_setup_clocks(hba, false);
-
- if (ufshcd_is_clkgating_allowed(hba)) {
- hba->clk_gating.state = CLKS_OFF;
- trace_ufshcd_clk_gating(dev_name(hba->dev),
- hba->clk_gating.state);
- }
-
- ufshcd_vreg_set_lpm(hba);
-
- /* Put the host controller in low power mode if possible */
- ufshcd_hba_vreg_set_lpm(hba);
goto out;
set_link_active:
- ufshcd_vreg_set_hpm(hba);
/*
* Device hardware reset is required to exit DeepSleep. Also, for
* DeepSleep, the link is off so host reset and restore will be done
@@ -8812,57 +8906,33 @@ set_dev_active:
}
if (!ufshcd_set_dev_pwr_mode(hba, UFS_ACTIVE_PWR_MODE))
ufshcd_disable_auto_bkops(hba);
-enable_gating:
+enable_scaling:
if (ufshcd_is_clkscaling_supported(hba))
ufshcd_clk_scaling_suspend(hba, false);
- hba->clk_gating.is_suspended = false;
hba->dev_info.b_rpm_dev_flush_capable = false;
- ufshcd_clear_ua_wluns(hba);
- ufshcd_release(hba);
out:
if (hba->dev_info.b_rpm_dev_flush_capable) {
schedule_delayed_work(&hba->rpm_dev_flush_recheck_work,
msecs_to_jiffies(RPM_DEV_FLUSH_RECHECK_WORK_DELAY_MS));
}
- hba->pm_op_in_progress = 0;
-
- if (ret)
- ufshcd_update_evt_hist(hba, UFS_EVT_SUSPEND_ERR, (u32)ret);
+ if (ret) {
+ ufshcd_update_evt_hist(hba, UFS_EVT_WL_SUSP_ERR, (u32)ret);
+ hba->clk_gating.is_suspended = false;
+ ufshcd_release(hba);
+ }
+ hba->pm_op_in_progress = false;
return ret;
}
-/**
- * ufshcd_resume - helper function for resume operations
- * @hba: per adapter instance
- * @pm_op: runtime PM or system PM
- *
- * This function basically brings the UFS device, UniPro link and controller
- * to active state.
- *
- * Returns 0 for success and non-zero for failure
- */
-static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
+#ifdef CONFIG_PM
+static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
int ret;
- enum uic_link_state old_link_state;
+ enum uic_link_state old_link_state = hba->uic_link_state;
- hba->pm_op_in_progress = 1;
- old_link_state = hba->uic_link_state;
-
- ufshcd_hba_vreg_set_hpm(hba);
- ret = ufshcd_vreg_set_hpm(hba);
- if (ret)
- goto out;
-
- /* Make sure clocks are enabled before accessing controller */
- ret = ufshcd_setup_clocks(hba, true);
- if (ret)
- goto disable_vreg;
-
- /* enable the host irq as host controller would be active soon */
- ufshcd_enable_irq(hba);
+ hba->pm_op_in_progress = true;
/*
* Call vendor specific resume callback. As these callbacks may access
@@ -8871,7 +8941,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
*/
ret = ufshcd_vops_resume(hba, pm_op);
if (ret)
- goto disable_irq_and_vops_clks;
+ goto out;
/* For DeepSleep, the only supported option is to have the link off */
WARN_ON(ufshcd_is_ufs_dev_deepsleep(hba) && !ufshcd_is_link_off(hba));
@@ -8919,42 +8989,218 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
if (hba->ee_usr_mask)
ufshcd_write_ee_control(hba);
- hba->clk_gating.is_suspended = false;
-
if (ufshcd_is_clkscaling_supported(hba))
ufshcd_clk_scaling_suspend(hba, false);
- /* Enable Auto-Hibernate if configured */
- ufshcd_auto_hibern8_enable(hba);
-
if (hba->dev_info.b_rpm_dev_flush_capable) {
hba->dev_info.b_rpm_dev_flush_capable = false;
cancel_delayed_work(&hba->rpm_dev_flush_recheck_work);
}
- ufshcd_clear_ua_wluns(hba);
-
- /* Schedule clock gating in case of no access to UFS device yet */
- ufshcd_release(hba);
-
+ /* Enable Auto-Hibernate if configured */
+ ufshcd_auto_hibern8_enable(hba);
goto out;
set_old_link_state:
ufshcd_link_state_transition(hba, old_link_state, 0);
vendor_suspend:
ufshcd_vops_suspend(hba, pm_op);
-disable_irq_and_vops_clks:
+out:
+ if (ret)
+ ufshcd_update_evt_hist(hba, UFS_EVT_WL_RES_ERR, (u32)ret);
+ hba->clk_gating.is_suspended = false;
+ ufshcd_release(hba);
+ hba->pm_op_in_progress = false;
+ return ret;
+}
+
+static int ufshcd_wl_runtime_suspend(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct ufs_hba *hba;
+ int ret;
+ ktime_t start = ktime_get();
+
+ hba = shost_priv(sdev->host);
+
+ ret = __ufshcd_wl_suspend(hba, UFS_RUNTIME_PM);
+ if (ret)
+ dev_err(&sdev->sdev_gendev, "%s failed: %d\n", __func__, ret);
+
+ trace_ufshcd_wl_runtime_suspend(dev_name(dev), ret,
+ ktime_to_us(ktime_sub(ktime_get(), start)),
+ hba->curr_dev_pwr_mode, hba->uic_link_state);
+
+ return ret;
+}
+
+static int ufshcd_wl_runtime_resume(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct ufs_hba *hba;
+ int ret = 0;
+ ktime_t start = ktime_get();
+
+ hba = shost_priv(sdev->host);
+
+ ret = __ufshcd_wl_resume(hba, UFS_RUNTIME_PM);
+ if (ret)
+ dev_err(&sdev->sdev_gendev, "%s failed: %d\n", __func__, ret);
+
+ trace_ufshcd_wl_runtime_resume(dev_name(dev), ret,
+ ktime_to_us(ktime_sub(ktime_get(), start)),
+ hba->curr_dev_pwr_mode, hba->uic_link_state);
+
+ return ret;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int ufshcd_wl_suspend(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct ufs_hba *hba;
+ int ret = 0;
+ ktime_t start = ktime_get();
+
+ hba = shost_priv(sdev->host);
+ down(&hba->host_sem);
+
+ if (pm_runtime_suspended(dev))
+ goto out;
+
+ ret = __ufshcd_wl_suspend(hba, UFS_SYSTEM_PM);
+ if (ret) {
+ dev_err(&sdev->sdev_gendev, "%s failed: %d\n", __func__, ret);
+ up(&hba->host_sem);
+ }
+
+out:
+ if (!ret)
+ hba->is_sys_suspended = true;
+ trace_ufshcd_wl_suspend(dev_name(dev), ret,
+ ktime_to_us(ktime_sub(ktime_get(), start)),
+ hba->curr_dev_pwr_mode, hba->uic_link_state);
+
+ return ret;
+}
+
+static int ufshcd_wl_resume(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct ufs_hba *hba;
+ int ret = 0;
+ ktime_t start = ktime_get();
+
+ hba = shost_priv(sdev->host);
+
+ if (pm_runtime_suspended(dev))
+ goto out;
+
+ ret = __ufshcd_wl_resume(hba, UFS_SYSTEM_PM);
+ if (ret)
+ dev_err(&sdev->sdev_gendev, "%s failed: %d\n", __func__, ret);
+out:
+ trace_ufshcd_wl_resume(dev_name(dev), ret,
+ ktime_to_us(ktime_sub(ktime_get(), start)),
+ hba->curr_dev_pwr_mode, hba->uic_link_state);
+ if (!ret)
+ hba->is_sys_suspended = false;
+ up(&hba->host_sem);
+ return ret;
+}
+#endif
+
+static void ufshcd_wl_shutdown(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct ufs_hba *hba;
+
+ hba = shost_priv(sdev->host);
+
+ down(&hba->host_sem);
+ hba->shutting_down = true;
+ up(&hba->host_sem);
+
+ /* Turn on everything while shutting down */
+ ufshcd_rpm_get_sync(hba);
+ scsi_device_quiesce(sdev);
+ shost_for_each_device(sdev, hba->host) {
+ if (sdev == hba->sdev_ufs_device)
+ continue;
+ scsi_device_quiesce(sdev);
+ }
+ __ufshcd_wl_suspend(hba, UFS_SHUTDOWN_PM);
+}
+
+/**
+ * ufshcd_suspend - helper function for suspend operations
+ * @hba: per adapter instance
+ *
+ * This function will put disable irqs, turn off clocks
+ * and set vreg and hba-vreg in lpm mode.
+ */
+static int ufshcd_suspend(struct ufs_hba *hba)
+{
+ int ret;
+
+ if (!hba->is_powered)
+ return 0;
+ /*
+ * Disable the host irq as host controller as there won't be any
+ * host controller transaction expected till resume.
+ */
ufshcd_disable_irq(hba);
- ufshcd_setup_clocks(hba, false);
+ ret = ufshcd_setup_clocks(hba, false);
+ if (ret) {
+ ufshcd_enable_irq(hba);
+ return ret;
+ }
if (ufshcd_is_clkgating_allowed(hba)) {
hba->clk_gating.state = CLKS_OFF;
trace_ufshcd_clk_gating(dev_name(hba->dev),
hba->clk_gating.state);
}
+
+ ufshcd_vreg_set_lpm(hba);
+ /* Put the host controller in low power mode if possible */
+ ufshcd_hba_vreg_set_lpm(hba);
+ return ret;
+}
+
+/**
+ * ufshcd_resume - helper function for resume operations
+ * @hba: per adapter instance
+ *
+ * This function basically turns on the regulators, clocks and
+ * irqs of the hba.
+ *
+ * Returns 0 for success and non-zero for failure
+ */
+static int ufshcd_resume(struct ufs_hba *hba)
+{
+ int ret;
+
+ if (!hba->is_powered)
+ return 0;
+
+ ufshcd_hba_vreg_set_hpm(hba);
+ ret = ufshcd_vreg_set_hpm(hba);
+ if (ret)
+ goto out;
+
+ /* Make sure clocks are enabled before accessing controller */
+ ret = ufshcd_setup_clocks(hba, true);
+ if (ret)
+ goto disable_vreg;
+
+ /* enable the host irq as host controller would be active soon */
+ ufshcd_enable_irq(hba);
+ goto out;
+
disable_vreg:
ufshcd_vreg_set_lpm(hba);
out:
- hba->pm_op_in_progress = 0;
if (ret)
ufshcd_update_evt_hist(hba, UFS_EVT_RESUME_ERR, (u32)ret);
return ret;
@@ -8973,44 +9219,14 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
int ret = 0;
ktime_t start = ktime_get();
- down(&hba->host_sem);
-
- if (!hba->is_powered)
- return 0;
-
- cancel_delayed_work_sync(&hba->rpm_dev_flush_recheck_work);
-
- if ((ufs_get_pm_lvl_to_dev_pwr_mode(hba->spm_lvl) ==
- hba->curr_dev_pwr_mode) &&
- (ufs_get_pm_lvl_to_link_pwr_state(hba->spm_lvl) ==
- hba->uic_link_state) &&
- pm_runtime_suspended(hba->dev) &&
- !hba->dev_info.b_rpm_dev_flush_capable)
+ if (pm_runtime_suspended(hba->dev))
goto out;
- if (pm_runtime_suspended(hba->dev)) {
- /*
- * UFS device and/or UFS link low power states during runtime
- * suspend seems to be different than what is expected during
- * system suspend. Hence runtime resume the devic & link and
- * let the system suspend low power states to take effect.
- * TODO: If resume takes longer time, we might have optimize
- * it in future by not resuming everything if possible.
- */
- ret = ufshcd_runtime_resume(hba);
- if (ret)
- goto out;
- }
-
- ret = ufshcd_suspend(hba, UFS_SYSTEM_PM);
+ ret = ufshcd_suspend(hba);
out:
trace_ufshcd_system_suspend(dev_name(hba->dev), ret,
ktime_to_us(ktime_sub(ktime_get(), start)),
hba->curr_dev_pwr_mode, hba->uic_link_state);
- if (!ret)
- hba->is_sys_suspended = true;
- else
- up(&hba->host_sem);
return ret;
}
EXPORT_SYMBOL(ufshcd_system_suspend);
@@ -9027,21 +9243,16 @@ int ufshcd_system_resume(struct ufs_hba *hba)
int ret = 0;
ktime_t start = ktime_get();
- if (!hba->is_powered || pm_runtime_suspended(hba->dev))
- /*
- * Let the runtime resume take care of resuming
- * if runtime suspended.
- */
+ if (pm_runtime_suspended(hba->dev))
goto out;
- else
- ret = ufshcd_resume(hba, UFS_SYSTEM_PM);
+
+ ret = ufshcd_resume(hba);
+
out:
trace_ufshcd_system_resume(dev_name(hba->dev), ret,
ktime_to_us(ktime_sub(ktime_get(), start)),
hba->curr_dev_pwr_mode, hba->uic_link_state);
- if (!ret)
- hba->is_sys_suspended = false;
- up(&hba->host_sem);
+
return ret;
}
EXPORT_SYMBOL(ufshcd_system_resume);
@@ -9056,14 +9267,11 @@ EXPORT_SYMBOL(ufshcd_system_resume);
*/
int ufshcd_runtime_suspend(struct ufs_hba *hba)
{
- int ret = 0;
+ int ret;
ktime_t start = ktime_get();
- if (!hba->is_powered)
- goto out;
- else
- ret = ufshcd_suspend(hba, UFS_RUNTIME_PM);
-out:
+ ret = ufshcd_suspend(hba);
+
trace_ufshcd_runtime_suspend(dev_name(hba->dev), ret,
ktime_to_us(ktime_sub(ktime_get(), start)),
hba->curr_dev_pwr_mode, hba->uic_link_state);
@@ -9075,33 +9283,19 @@ EXPORT_SYMBOL(ufshcd_runtime_suspend);
* ufshcd_runtime_resume - runtime resume routine
* @hba: per adapter instance
*
- * This function basically brings the UFS device, UniPro link and controller
+ * This function basically brings controller
* to active state. Following operations are done in this function:
*
* 1. Turn on all the controller related clocks
- * 2. Bring the UniPro link out of Hibernate state
- * 3. If UFS device is in sleep state, turn ON VCC rail and bring the UFS device
- * to active state.
- * 4. If auto-bkops is enabled on the device, disable it.
- *
- * So following would be the possible power state after this function return
- * successfully:
- * S1: UFS device in Active state with VCC rail ON
- * UniPro link in Active state
- * All the UFS/UniPro controller clocks are ON
- *
- * Returns 0 for success and non-zero for failure
+ * 2. Turn ON VCC rail
*/
int ufshcd_runtime_resume(struct ufs_hba *hba)
{
- int ret = 0;
+ int ret;
ktime_t start = ktime_get();
- if (!hba->is_powered)
- goto out;
- else
- ret = ufshcd_resume(hba, UFS_RUNTIME_PM);
-out:
+ ret = ufshcd_resume(hba);
+
trace_ufshcd_runtime_resume(dev_name(hba->dev), ret,
ktime_to_us(ktime_sub(ktime_get(), start)),
hba->curr_dev_pwr_mode, hba->uic_link_state);
@@ -9119,30 +9313,20 @@ EXPORT_SYMBOL(ufshcd_runtime_idle);
* ufshcd_shutdown - shutdown routine
* @hba: per adapter instance
*
- * This function would power off both UFS device and UFS link.
+ * This function would turn off both UFS device and UFS hba
+ * regulators. It would also disable clocks.
*
* Returns 0 always to allow force shutdown even in case of errors.
*/
int ufshcd_shutdown(struct ufs_hba *hba)
{
- int ret = 0;
-
- down(&hba->host_sem);
- hba->shutting_down = true;
- up(&hba->host_sem);
-
- if (!hba->is_powered)
- goto out;
-
if (ufshcd_is_ufs_dev_poweroff(hba) && ufshcd_is_link_off(hba))
goto out;
pm_runtime_get_sync(hba->dev);
- ret = ufshcd_suspend(hba, UFS_SHUTDOWN_PM);
+ ufshcd_suspend(hba);
out:
- if (ret)
- dev_err(hba->dev, "%s failed, err %d\n", __func__, ret);
hba->is_powered = false;
/* allow force shutdown even in case of errors */
return 0;
@@ -9156,6 +9340,8 @@ EXPORT_SYMBOL(ufshcd_shutdown);
*/
void ufshcd_remove(struct ufs_hba *hba)
{
+ if (hba->sdev_ufs_device)
+ ufshcd_rpm_get_sync(hba);
ufs_bsg_remove(hba);
ufs_sysfs_remove_nodes(hba->dev);
blk_cleanup_queue(hba->tmf_queue);
@@ -9459,15 +9645,182 @@ out_error:
}
EXPORT_SYMBOL_GPL(ufshcd_init);
+void ufshcd_resume_complete(struct device *dev)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ if (hba->complete_put) {
+ ufshcd_rpm_put(hba);
+ hba->complete_put = false;
+ }
+ if (hba->rpmb_complete_put) {
+ ufshcd_rpmb_rpm_put(hba);
+ hba->rpmb_complete_put = false;
+ }
+}
+EXPORT_SYMBOL_GPL(ufshcd_resume_complete);
+
+int ufshcd_suspend_prepare(struct device *dev)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ int ret;
+
+ /*
+ * SCSI assumes that runtime-pm and system-pm for scsi drivers
+ * are same. And it doesn't wake up the device for system-suspend
+ * if it's runtime suspended. But ufs doesn't follow that.
+ * Refer ufshcd_resume_complete()
+ */
+ if (hba->sdev_ufs_device) {
+ ret = ufshcd_rpm_get_sync(hba);
+ if (ret < 0 && ret != -EACCES) {
+ ufshcd_rpm_put(hba);
+ return ret;
+ }
+ hba->complete_put = true;
+ }
+ if (hba->sdev_rpmb) {
+ ufshcd_rpmb_rpm_get_sync(hba);
+ hba->rpmb_complete_put = true;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ufshcd_suspend_prepare);
+
+#ifdef CONFIG_PM_SLEEP
+static int ufshcd_wl_poweroff(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct ufs_hba *hba = shost_priv(sdev->host);
+
+ __ufshcd_wl_suspend(hba, UFS_SHUTDOWN_PM);
+ return 0;
+}
+#endif
+
+static int ufshcd_wl_probe(struct device *dev)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ if (!is_device_wlun(sdev))
+ return -ENODEV;
+
+ blk_pm_runtime_init(sdev->request_queue, dev);
+ pm_runtime_set_autosuspend_delay(dev, 0);
+ pm_runtime_allow(dev);
+
+ return 0;
+}
+
+static int ufshcd_wl_remove(struct device *dev)
+{
+ pm_runtime_forbid(dev);
+ return 0;
+}
+
+static const struct dev_pm_ops ufshcd_wl_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+ .suspend = ufshcd_wl_suspend,
+ .resume = ufshcd_wl_resume,
+ .freeze = ufshcd_wl_suspend,
+ .thaw = ufshcd_wl_resume,
+ .poweroff = ufshcd_wl_poweroff,
+ .restore = ufshcd_wl_resume,
+#endif
+ SET_RUNTIME_PM_OPS(ufshcd_wl_runtime_suspend, ufshcd_wl_runtime_resume, NULL)
+};
+
+/*
+ * ufs_dev_wlun_template - describes ufs device wlun
+ * ufs-device wlun - used to send pm commands
+ * All luns are consumers of ufs-device wlun.
+ *
+ * Currently, no sd driver is present for wluns.
+ * Hence the no specific pm operations are performed.
+ * With ufs design, SSU should be sent to ufs-device wlun.
+ * Hence register a scsi driver for ufs wluns only.
+ */
+static struct scsi_driver ufs_dev_wlun_template = {
+ .gendrv = {
+ .name = "ufs_device_wlun",
+ .owner = THIS_MODULE,
+ .probe = ufshcd_wl_probe,
+ .remove = ufshcd_wl_remove,
+ .pm = &ufshcd_wl_pm_ops,
+ .shutdown = ufshcd_wl_shutdown,
+ },
+};
+
+static int ufshcd_rpmb_probe(struct device *dev)
+{
+ return is_rpmb_wlun(to_scsi_device(dev)) ? 0 : -ENODEV;
+}
+
+static inline int ufshcd_clear_rpmb_uac(struct ufs_hba *hba)
+{
+ int ret = 0;
+
+ if (!hba->wlun_rpmb_clr_ua)
+ return 0;
+ ret = ufshcd_clear_ua_wlun(hba, UFS_UPIU_RPMB_WLUN);
+ if (!ret)
+ hba->wlun_rpmb_clr_ua = 0;
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int ufshcd_rpmb_resume(struct device *dev)
+{
+ struct ufs_hba *hba = wlun_dev_to_hba(dev);
+
+ if (hba->sdev_rpmb)
+ ufshcd_clear_rpmb_uac(hba);
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops ufs_rpmb_pm_ops = {
+ SET_RUNTIME_PM_OPS(NULL, ufshcd_rpmb_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(NULL, ufshcd_rpmb_resume)
+};
+
+/* ufs_rpmb_wlun_template - Describes UFS RPMB WLUN. Used only to send UAC. */
+static struct scsi_driver ufs_rpmb_wlun_template = {
+ .gendrv = {
+ .name = "ufs_rpmb_wlun",
+ .owner = THIS_MODULE,
+ .probe = ufshcd_rpmb_probe,
+ .pm = &ufs_rpmb_pm_ops,
+ },
+};
+
static int __init ufshcd_core_init(void)
{
+ int ret;
+
ufs_debugfs_init();
- return 0;
+
+ ret = scsi_register_driver(&ufs_dev_wlun_template.gendrv);
+ if (ret)
+ goto debugfs_exit;
+
+ ret = scsi_register_driver(&ufs_rpmb_wlun_template.gendrv);
+ if (ret)
+ goto unregister;
+
+ return ret;
+unregister:
+ scsi_unregister_driver(&ufs_dev_wlun_template.gendrv);
+debugfs_exit:
+ ufs_debugfs_exit();
+ return ret;
}
static void __exit ufshcd_core_exit(void)
{
ufs_debugfs_exit();
+ scsi_unregister_driver(&ufs_rpmb_wlun_template.gendrv);
+ scsi_unregister_driver(&ufs_dev_wlun_template.gendrv);
}
module_init(ufshcd_core_init);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 5eb66a8debc7..194755c9ddfe 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -72,6 +72,8 @@ enum ufs_event_type {
UFS_EVT_LINK_STARTUP_FAIL,
UFS_EVT_RESUME_ERR,
UFS_EVT_SUSPEND_ERR,
+ UFS_EVT_WL_SUSP_ERR,
+ UFS_EVT_WL_RES_ERR,
/* abnormal events */
UFS_EVT_DEV_RESET,
@@ -106,10 +108,6 @@ enum ufs_pm_op {
UFS_SHUTDOWN_PM,
};
-#define ufshcd_is_runtime_pm(op) ((op) == UFS_RUNTIME_PM)
-#define ufshcd_is_system_pm(op) ((op) == UFS_SYSTEM_PM)
-#define ufshcd_is_shutdown_pm(op) ((op) == UFS_SHUTDOWN_PM)
-
/* Host <-> Device UniPro Link state */
enum uic_link_state {
UIC_LINK_OFF_STATE = 0, /* Link powered down or disabled */
@@ -157,13 +155,13 @@ enum uic_link_state {
* power off.
*/
enum ufs_pm_level {
- UFS_PM_LVL_0, /* UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE */
- UFS_PM_LVL_1, /* UFS_ACTIVE_PWR_MODE, UIC_LINK_HIBERN8_STATE */
- UFS_PM_LVL_2, /* UFS_SLEEP_PWR_MODE, UIC_LINK_ACTIVE_STATE */
- UFS_PM_LVL_3, /* UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE */
- UFS_PM_LVL_4, /* UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE */
- UFS_PM_LVL_5, /* UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE */
- UFS_PM_LVL_6, /* UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE */
+ UFS_PM_LVL_0,
+ UFS_PM_LVL_1,
+ UFS_PM_LVL_2,
+ UFS_PM_LVL_3,
+ UFS_PM_LVL_4,
+ UFS_PM_LVL_5,
+ UFS_PM_LVL_6,
UFS_PM_LVL_MAX
};
@@ -195,7 +193,6 @@ struct ufs_pm_lvl_states {
* @crypto_key_slot: the key slot to use for inline crypto (-1 if none)
* @data_unit_num: the data unit number for the first block for inline crypto
* @req_abort_skip: skip request abort task flag
- * @in_use: indicates that this lrb is still in use
*/
struct ufshcd_lrb {
struct utp_transfer_req_desc *utr_descriptor_ptr;
@@ -225,7 +222,6 @@ struct ufshcd_lrb {
#endif
bool req_abort_skip;
- bool in_use;
};
/**
@@ -645,6 +641,25 @@ struct ufs_hba_variant_params {
u32 wb_flush_threshold;
};
+struct ufs_hba_monitor {
+ unsigned long chunk_size;
+
+ unsigned long nr_sec_rw[2];
+ ktime_t total_busy[2];
+
+ unsigned long nr_req[2];
+ /* latencies*/
+ ktime_t lat_sum[2];
+ ktime_t lat_max[2];
+ ktime_t lat_min[2];
+
+ u32 nr_queued[2];
+ ktime_t busy_start_ts[2];
+
+ ktime_t enabled_ts;
+ bool enabled;
+};
+
/**
* struct ufs_hba - per adapter private structure
* @mmio_base: UFSHCI base register address
@@ -807,6 +822,7 @@ struct ufs_hba {
struct list_head clk_list_head;
bool wlun_dev_clr_ua;
+ bool wlun_rpmb_clr_ua;
/* Number of requests aborts */
int req_abort_count;
@@ -835,6 +851,8 @@ struct ufs_hba {
struct request_queue *bsg_queue;
struct delayed_work rpm_dev_flush_recheck_work;
+ struct ufs_hba_monitor monitor;
+
#ifdef CONFIG_SCSI_UFS_CRYPTO
union ufs_crypto_capabilities crypto_capabilities;
union ufs_crypto_cap_entry *crypto_cap_array;
@@ -846,6 +864,9 @@ struct ufs_hba {
struct delayed_work debugfs_ee_work;
u32 debugfs_ee_rate_limit_ms;
#endif
+ u32 luns_avail;
+ bool complete_put;
+ bool rpmb_complete_put;
};
/* Returns true if clocks can be gated. Otherwise false */
@@ -936,7 +957,7 @@ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)
int ufshcd_alloc_host(struct device *, struct ufs_hba **);
void ufshcd_dealloc_host(struct ufs_hba *);
int ufshcd_hba_enable(struct ufs_hba *hba);
-int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
+int ufshcd_init(struct ufs_hba *, void __iomem *, unsigned int);
int ufshcd_link_recovery(struct ufs_hba *hba);
int ufshcd_make_hba_operational(struct ufs_hba *hba);
void ufshcd_remove(struct ufs_hba *);
@@ -947,6 +968,7 @@ int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
unsigned long timeout_ms);
void ufshcd_parse_dev_ref_clk_freq(struct ufs_hba *hba, struct clk *refclk);
void ufshcd_update_evt_hist(struct ufs_hba *hba, u32 id, u32 val);
+void ufshcd_hba_stop(struct ufs_hba *hba);
static inline void check_upiu_size(void)
{
@@ -1105,6 +1127,8 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
enum query_opcode desc_op);
int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable);
+int ufshcd_suspend_prepare(struct device *dev);
+void ufshcd_resume_complete(struct device *dev);
/* Wrapper functions for safely calling variant operations */
static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
@@ -1136,6 +1160,11 @@ static inline u32 ufshcd_vops_get_ufs_hci_version(struct ufs_hba *hba)
return ufshcd_readl(hba, REG_UFS_VERSION);
}
+static inline bool ufshcd_has_utrlcnr(struct ufs_hba *hba)
+{
+ return (hba->ufs_version >= ufshci_version(3, 0));
+}
+
static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba,
bool up, enum ufs_notify_change_status status)
{
@@ -1200,8 +1229,13 @@ static inline int ufshcd_vops_pwr_change_notify(struct ufs_hba *hba,
static inline void ufshcd_vops_setup_xfer_req(struct ufs_hba *hba, int tag,
bool is_scsi_cmd)
{
- if (hba->vops && hba->vops->setup_xfer_req)
- return hba->vops->setup_xfer_req(hba, tag, is_scsi_cmd);
+ if (hba->vops && hba->vops->setup_xfer_req) {
+ unsigned long flags;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->vops->setup_xfer_req(hba, tag, is_scsi_cmd);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ }
}
static inline void ufshcd_vops_setup_task_mgmt(struct ufs_hba *hba,
@@ -1309,4 +1343,29 @@ static inline int ufshcd_update_ee_usr_mask(struct ufs_hba *hba,
&hba->ee_drv_mask, set, clr);
}
+static inline int ufshcd_rpm_get_sync(struct ufs_hba *hba)
+{
+ return pm_runtime_get_sync(&hba->sdev_ufs_device->sdev_gendev);
+}
+
+static inline int ufshcd_rpm_put_sync(struct ufs_hba *hba)
+{
+ return pm_runtime_put_sync(&hba->sdev_ufs_device->sdev_gendev);
+}
+
+static inline int ufshcd_rpm_put(struct ufs_hba *hba)
+{
+ return pm_runtime_put(&hba->sdev_ufs_device->sdev_gendev);
+}
+
+static inline int ufshcd_rpmb_rpm_get_sync(struct ufs_hba *hba)
+{
+ return pm_runtime_get_sync(&hba->sdev_rpmb->sdev_gendev);
+}
+
+static inline int ufshcd_rpmb_rpm_put(struct ufs_hba *hba)
+{
+ return pm_runtime_put(&hba->sdev_rpmb->sdev_gendev);
+}
+
#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index de95be5d11d4..5affb1fce5ad 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -39,6 +39,7 @@ enum {
REG_UTP_TRANSFER_REQ_DOOR_BELL = 0x58,
REG_UTP_TRANSFER_REQ_LIST_CLEAR = 0x5C,
REG_UTP_TRANSFER_REQ_LIST_RUN_STOP = 0x60,
+ REG_UTP_TRANSFER_REQ_LIST_COMPL = 0x64,
REG_UTP_TASK_REQ_LIST_BASE_L = 0x70,
REG_UTP_TASK_REQ_LIST_BASE_H = 0x74,
REG_UTP_TASK_REQ_DOOR_BELL = 0x78,
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index b9c86a7e3b97..b0deaf4af5a3 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -97,7 +97,7 @@ static inline struct Scsi_Host *virtio_scsi_host(struct virtio_device *vdev)
static void virtscsi_compute_resid(struct scsi_cmnd *sc, u32 resid)
{
if (resid)
- scsi_set_resid(sc, resid);
+ scsi_set_resid(sc, min(resid, scsi_bufflen(sc)));
}
/*
@@ -156,13 +156,11 @@ static void virtscsi_complete_cmd(struct virtio_scsi *vscsi, void *buf)
WARN_ON(virtio32_to_cpu(vscsi->vdev, resp->sense_len) >
VIRTIO_SCSI_SENSE_SIZE);
- if (sc->sense_buffer) {
+ if (resp->sense_len) {
memcpy(sc->sense_buffer, resp->sense,
min_t(u32,
virtio32_to_cpu(vscsi->vdev, resp->sense_len),
VIRTIO_SCSI_SENSE_SIZE));
- if (resp->sense_len)
- set_driver_byte(sc, DRIVER_SENSE);
}
sc->scsi_done(sc);
@@ -355,7 +353,7 @@ static void virtscsi_rescan_hotunplug(struct virtio_scsi *vscsi)
if (result == 0 && inq_result[0] >> 5) {
/* PQ indicates the LUN is not attached */
scsi_remove_device(sdev);
- } else if (host_byte(result) == DID_BAD_TARGET) {
+ } else if (result > 0 && host_byte(result) == DID_BAD_TARGET) {
/*
* If all LUNs of a virtio-scsi device are unplugged
* it will respond with BAD TARGET on any INQUIRY
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index b9969fce6b4d..ce1ba1b93629 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -576,9 +576,6 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter,
cmd->result = (DID_RESET << 16);
} else {
cmd->result = (DID_OK << 16) | sdstat;
- if (sdstat == SAM_STAT_CHECK_CONDITION &&
- cmd->sense_buffer)
- cmd->result |= (DRIVER_SENSE << 24);
}
} else
switch (btstat) {
@@ -610,9 +607,6 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter,
case BTSTAT_LUNMISMATCH:
case BTSTAT_TAGREJECT:
case BTSTAT_BADMSG:
- cmd->result = (DRIVER_INVALID << 24);
- fallthrough;
-
case BTSTAT_HAHARDWARE:
case BTSTAT_INVPHASE:
case BTSTAT_HATIMEOUT:
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index a23277bb870e..4468bc45aaa4 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -1176,13 +1176,13 @@ wd33c93_intr(struct Scsi_Host *instance)
if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE)
cmd->SCp.Status = lun;
if (cmd->cmnd[0] == REQUEST_SENSE
- && cmd->SCp.Status != SAM_STAT_GOOD)
- cmd->result =
- (cmd->
- result & 0x00ffff) | (DID_ERROR << 16);
- else
- cmd->result =
- cmd->SCp.Status | (cmd->SCp.Message << 8);
+ && cmd->SCp.Status != SAM_STAT_GOOD) {
+ set_host_byte(cmd, DID_ERROR);
+ } else {
+ set_host_byte(cmd, DID_OK);
+ scsi_msg_to_host_byte(cmd, cmd->SCp.Message);
+ set_status_byte(cmd, cmd->SCp.Status);
+ }
cmd->scsi_done(cmd);
/* We are no longer connected to a target - check to see if
@@ -1262,11 +1262,14 @@ wd33c93_intr(struct Scsi_Host *instance)
hostdata->connected = NULL;
hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xff));
hostdata->state = S_UNCONNECTED;
- if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != SAM_STAT_GOOD)
- cmd->result =
- (cmd->result & 0x00ffff) | (DID_ERROR << 16);
- else
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+ if (cmd->cmnd[0] == REQUEST_SENSE &&
+ cmd->SCp.Status != SAM_STAT_GOOD) {
+ set_host_byte(cmd, DID_ERROR);
+ } else {
+ set_host_byte(cmd, DID_OK);
+ scsi_msg_to_host_byte(cmd, cmd->SCp.Message);
+ set_status_byte(cmd, cmd->SCp.Status);
+ }
cmd->scsi_done(cmd);
/* We are no longer connected to a target - check to see if
@@ -1295,14 +1298,14 @@ wd33c93_intr(struct Scsi_Host *instance)
hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xff));
hostdata->state = S_UNCONNECTED;
DB(DB_INTR, printk(":%d", cmd->SCp.Status))
- if (cmd->cmnd[0] == REQUEST_SENSE
- && cmd->SCp.Status != SAM_STAT_GOOD)
- cmd->result =
- (cmd->
- result & 0x00ffff) | (DID_ERROR << 16);
- else
- cmd->result =
- cmd->SCp.Status | (cmd->SCp.Message << 8);
+ if (cmd->cmnd[0] == REQUEST_SENSE
+ && cmd->SCp.Status != SAM_STAT_GOOD) {
+ set_host_byte(cmd, DID_ERROR);
+ } else {
+ set_host_byte(cmd, DID_OK);
+ scsi_msg_to_host_byte(cmd, cmd->SCp.Message);
+ set_status_byte(cmd, cmd->SCp.Status);
+ }
cmd->scsi_done(cmd);
break;
case S_PRE_TMP_DISC:
diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c
index 259fc248d06c..ec9d399fbbd8 100644
--- a/drivers/scsi/xen-scsifront.c
+++ b/drivers/scsi/xen-scsifront.c
@@ -251,6 +251,7 @@ static void scsifront_cdb_cmd_done(struct vscsifrnt_info *info,
struct scsi_cmnd *sc;
uint32_t id;
uint8_t sense_len;
+ int result;
id = ring_rsp->rqid;
shadow = info->shadow[id];
@@ -261,7 +262,12 @@ static void scsifront_cdb_cmd_done(struct vscsifrnt_info *info,
scsifront_gnttab_done(info, shadow);
scsifront_put_rqid(info, id);
- sc->result = ring_rsp->rslt;
+ result = ring_rsp->rslt;
+ if (result >> 24)
+ set_host_byte(sc, DID_ERROR);
+ else
+ set_host_byte(sc, host_byte(result));
+ set_status_byte(sc, result & 0xff);
scsi_set_resid(sc, ring_rsp->residual_len);
sense_len = min_t(uint8_t, VSCSIIF_SENSE_BUFFERSIZE,
diff --git a/drivers/siox/siox-bus-gpio.c b/drivers/siox/siox-bus-gpio.c
index 46b4cda36bac..aeefeb725524 100644
--- a/drivers/siox/siox-bus-gpio.c
+++ b/drivers/siox/siox-bus-gpio.c
@@ -102,29 +102,29 @@ static int siox_gpio_probe(struct platform_device *pdev)
ddata->din = devm_gpiod_get(dev, "din", GPIOD_IN);
if (IS_ERR(ddata->din)) {
- ret = PTR_ERR(ddata->din);
- dev_err(dev, "Failed to get %s GPIO: %d\n", "din", ret);
+ ret = dev_err_probe(dev, PTR_ERR(ddata->din),
+ "Failed to get din GPIO\n");
goto err;
}
ddata->dout = devm_gpiod_get(dev, "dout", GPIOD_OUT_LOW);
if (IS_ERR(ddata->dout)) {
- ret = PTR_ERR(ddata->dout);
- dev_err(dev, "Failed to get %s GPIO: %d\n", "dout", ret);
+ ret = dev_err_probe(dev, PTR_ERR(ddata->dout),
+ "Failed to get dout GPIO\n");
goto err;
}
ddata->dclk = devm_gpiod_get(dev, "dclk", GPIOD_OUT_LOW);
if (IS_ERR(ddata->dclk)) {
- ret = PTR_ERR(ddata->dclk);
- dev_err(dev, "Failed to get %s GPIO: %d\n", "dclk", ret);
+ ret = dev_err_probe(dev, PTR_ERR(ddata->dclk),
+ "Failed to get dclk GPIO\n");
goto err;
}
ddata->dld = devm_gpiod_get(dev, "dld", GPIOD_OUT_LOW);
if (IS_ERR(ddata->dld)) {
- ret = PTR_ERR(ddata->dld);
- dev_err(dev, "Failed to get %s GPIO: %d\n", "dld", ret);
+ ret = dev_err_probe(dev, PTR_ERR(ddata->dld),
+ "Failed to get dld GPIO\n");
goto err;
}
@@ -134,7 +134,8 @@ static int siox_gpio_probe(struct platform_device *pdev)
ret = siox_master_register(smaster);
if (ret) {
- dev_err(dev, "Failed to register siox master: %d\n", ret);
+ dev_err_probe(dev, ret,
+ "Failed to register siox master\n");
err:
siox_master_put(smaster);
}
diff --git a/drivers/soc/amlogic/meson-ee-pwrc.c b/drivers/soc/amlogic/meson-ee-pwrc.c
index 50bf5d2b828b..2be3afe6c2e3 100644
--- a/drivers/soc/amlogic/meson-ee-pwrc.c
+++ b/drivers/soc/amlogic/meson-ee-pwrc.c
@@ -68,7 +68,7 @@ struct meson_ee_pwrc_domain_desc {
struct meson_ee_pwrc_top_domain *top_pd;
unsigned int mem_pd_count;
struct meson_ee_pwrc_mem_domain *mem_pd;
- bool (*get_power)(struct meson_ee_pwrc_domain *pwrc_domain);
+ bool (*is_powered_off)(struct meson_ee_pwrc_domain *pwrc_domain);
};
struct meson_ee_pwrc_domain_data {
@@ -217,7 +217,7 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
{ HHI_AUDIO_MEM_PD_REG0, GENMASK(27, 26) },
};
-#define VPU_PD(__name, __top_pd, __mem, __get_power, __resets, __clks) \
+#define VPU_PD(__name, __top_pd, __mem, __is_pwr_off, __resets, __clks) \
{ \
.name = __name, \
.reset_names_count = __resets, \
@@ -225,46 +225,46 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
.top_pd = __top_pd, \
.mem_pd_count = ARRAY_SIZE(__mem), \
.mem_pd = __mem, \
- .get_power = __get_power, \
+ .is_powered_off = __is_pwr_off, \
}
-#define TOP_PD(__name, __top_pd, __mem, __get_power) \
+#define TOP_PD(__name, __top_pd, __mem, __is_pwr_off) \
{ \
.name = __name, \
.top_pd = __top_pd, \
.mem_pd_count = ARRAY_SIZE(__mem), \
.mem_pd = __mem, \
- .get_power = __get_power, \
+ .is_powered_off = __is_pwr_off, \
}
#define MEM_PD(__name, __mem) \
TOP_PD(__name, NULL, __mem, NULL)
-static bool pwrc_ee_get_power(struct meson_ee_pwrc_domain *pwrc_domain);
+static bool pwrc_ee_is_powered_off(struct meson_ee_pwrc_domain *pwrc_domain);
static struct meson_ee_pwrc_domain_desc axg_pwrc_domains[] = {
[PWRC_AXG_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, axg_pwrc_mem_vpu,
- pwrc_ee_get_power, 5, 2),
+ pwrc_ee_is_powered_off, 5, 2),
[PWRC_AXG_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
[PWRC_AXG_AUDIO_ID] = MEM_PD("AUDIO", axg_pwrc_mem_audio),
};
static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
[PWRC_G12A_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, g12a_pwrc_mem_vpu,
- pwrc_ee_get_power, 11, 2),
+ pwrc_ee_is_powered_off, 11, 2),
[PWRC_G12A_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
};
static struct meson_ee_pwrc_domain_desc gxbb_pwrc_domains[] = {
[PWRC_GXBB_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, gxbb_pwrc_mem_vpu,
- pwrc_ee_get_power, 12, 2),
+ pwrc_ee_is_powered_off, 12, 2),
[PWRC_GXBB_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
};
static struct meson_ee_pwrc_domain_desc meson8_pwrc_domains[] = {
[PWRC_MESON8_VPU_ID] = VPU_PD("VPU", &meson8_pwrc_vpu,
- meson8_pwrc_mem_vpu, pwrc_ee_get_power,
- 0, 1),
+ meson8_pwrc_mem_vpu,
+ pwrc_ee_is_powered_off, 0, 1),
[PWRC_MESON8_ETHERNET_MEM_ID] = MEM_PD("ETHERNET_MEM",
meson_pwrc_mem_eth),
[PWRC_MESON8_AUDIO_DSP_MEM_ID] = MEM_PD("AUDIO_DSP_MEM",
@@ -273,8 +273,8 @@ static struct meson_ee_pwrc_domain_desc meson8_pwrc_domains[] = {
static struct meson_ee_pwrc_domain_desc meson8b_pwrc_domains[] = {
[PWRC_MESON8_VPU_ID] = VPU_PD("VPU", &meson8_pwrc_vpu,
- meson8_pwrc_mem_vpu, pwrc_ee_get_power,
- 11, 1),
+ meson8_pwrc_mem_vpu,
+ pwrc_ee_is_powered_off, 11, 1),
[PWRC_MESON8_ETHERNET_MEM_ID] = MEM_PD("ETHERNET_MEM",
meson_pwrc_mem_eth),
[PWRC_MESON8_AUDIO_DSP_MEM_ID] = MEM_PD("AUDIO_DSP_MEM",
@@ -283,15 +283,15 @@ static struct meson_ee_pwrc_domain_desc meson8b_pwrc_domains[] = {
static struct meson_ee_pwrc_domain_desc sm1_pwrc_domains[] = {
[PWRC_SM1_VPU_ID] = VPU_PD("VPU", &sm1_pwrc_vpu, sm1_pwrc_mem_vpu,
- pwrc_ee_get_power, 11, 2),
+ pwrc_ee_is_powered_off, 11, 2),
[PWRC_SM1_NNA_ID] = TOP_PD("NNA", &sm1_pwrc_nna, sm1_pwrc_mem_nna,
- pwrc_ee_get_power),
+ pwrc_ee_is_powered_off),
[PWRC_SM1_USB_ID] = TOP_PD("USB", &sm1_pwrc_usb, sm1_pwrc_mem_usb,
- pwrc_ee_get_power),
+ pwrc_ee_is_powered_off),
[PWRC_SM1_PCIE_ID] = TOP_PD("PCI", &sm1_pwrc_pci, sm1_pwrc_mem_pcie,
- pwrc_ee_get_power),
+ pwrc_ee_is_powered_off),
[PWRC_SM1_GE2D_ID] = TOP_PD("GE2D", &sm1_pwrc_ge2d, sm1_pwrc_mem_ge2d,
- pwrc_ee_get_power),
+ pwrc_ee_is_powered_off),
[PWRC_SM1_AUDIO_ID] = MEM_PD("AUDIO", sm1_pwrc_mem_audio),
[PWRC_SM1_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
};
@@ -314,7 +314,7 @@ struct meson_ee_pwrc {
struct genpd_onecell_data xlate;
};
-static bool pwrc_ee_get_power(struct meson_ee_pwrc_domain *pwrc_domain)
+static bool pwrc_ee_is_powered_off(struct meson_ee_pwrc_domain *pwrc_domain)
{
u32 reg;
@@ -445,7 +445,7 @@ static int meson_ee_pwrc_init_domain(struct platform_device *pdev,
* we need to power the domain off, otherwise the internal clocks
* prepare/enable counters won't be in sync.
*/
- if (dom->num_clks && dom->desc.get_power && !dom->desc.get_power(dom)) {
+ if (dom->num_clks && dom->desc.is_powered_off && !dom->desc.is_powered_off(dom)) {
ret = clk_bulk_prepare_enable(dom->num_clks, dom->clks);
if (ret)
return ret;
@@ -456,8 +456,8 @@ static int meson_ee_pwrc_init_domain(struct platform_device *pdev,
return ret;
} else {
ret = pm_genpd_init(&dom->base, NULL,
- (dom->desc.get_power ?
- dom->desc.get_power(dom) : true));
+ (dom->desc.is_powered_off ?
+ dom->desc.is_powered_off(dom) : true));
if (ret)
return ret;
}
@@ -536,7 +536,7 @@ static void meson_ee_pwrc_shutdown(struct platform_device *pdev)
for (i = 0 ; i < pwrc->xlate.num_domains ; ++i) {
struct meson_ee_pwrc_domain *dom = &pwrc->domains[i];
- if (dom->desc.get_power && !dom->desc.get_power(dom))
+ if (dom->desc.is_powered_off && !dom->desc.is_powered_off(dom))
meson_ee_pwrc_off(&dom->base);
}
}
diff --git a/drivers/soc/bcm/brcmstb/common.c b/drivers/soc/bcm/brcmstb/common.c
index e87dfc6660f3..2a010881f4b6 100644
--- a/drivers/soc/bcm/brcmstb/common.c
+++ b/drivers/soc/bcm/brcmstb/common.c
@@ -14,11 +14,6 @@
static u32 family_id;
static u32 product_id;
-static const struct of_device_id brcmstb_machine_match[] = {
- { .compatible = "brcm,brcmstb", },
- { }
-};
-
u32 brcmstb_get_family_id(void)
{
return family_id;
diff --git a/drivers/soc/bcm/brcmstb/pm/pm-arm.c b/drivers/soc/bcm/brcmstb/pm/pm-arm.c
index a673fdffe216..3cbb165d6e30 100644
--- a/drivers/soc/bcm/brcmstb/pm/pm-arm.c
+++ b/drivers/soc/bcm/brcmstb/pm/pm-arm.c
@@ -28,6 +28,7 @@
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/panic_notifier.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/printk.h>
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
index db7e7fc321b1..34a9ac1f2b9b 100644
--- a/drivers/soc/imx/gpcv2.c
+++ b/drivers/soc/imx/gpcv2.c
@@ -12,11 +12,15 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
#include <linux/sizes.h>
#include <dt-bindings/power/imx7-power.h>
#include <dt-bindings/power/imx8mq-power.h>
+#include <dt-bindings/power/imx8mm-power.h>
+#include <dt-bindings/power/imx8mn-power.h>
#define GPC_LPCR_A_CORE_BSC 0x000
@@ -42,6 +46,25 @@
#define IMX8M_PCIE1_A53_DOMAIN BIT(3)
#define IMX8M_MIPI_A53_DOMAIN BIT(2)
+#define IMX8MM_VPUH1_A53_DOMAIN BIT(15)
+#define IMX8MM_VPUG2_A53_DOMAIN BIT(14)
+#define IMX8MM_VPUG1_A53_DOMAIN BIT(13)
+#define IMX8MM_DISPMIX_A53_DOMAIN BIT(12)
+#define IMX8MM_VPUMIX_A53_DOMAIN BIT(10)
+#define IMX8MM_GPUMIX_A53_DOMAIN BIT(9)
+#define IMX8MM_GPU_A53_DOMAIN (BIT(8) | BIT(11))
+#define IMX8MM_DDR1_A53_DOMAIN BIT(7)
+#define IMX8MM_OTG2_A53_DOMAIN BIT(5)
+#define IMX8MM_OTG1_A53_DOMAIN BIT(4)
+#define IMX8MM_PCIE_A53_DOMAIN BIT(3)
+#define IMX8MM_MIPI_A53_DOMAIN BIT(2)
+
+#define IMX8MN_DISPMIX_A53_DOMAIN BIT(12)
+#define IMX8MN_GPUMIX_A53_DOMAIN BIT(9)
+#define IMX8MN_DDR1_A53_DOMAIN BIT(7)
+#define IMX8MN_OTG1_A53_DOMAIN BIT(4)
+#define IMX8MN_MIPI_A53_DOMAIN BIT(2)
+
#define GPC_PU_PGC_SW_PUP_REQ 0x0f8
#define GPC_PU_PGC_SW_PDN_REQ 0x104
@@ -65,14 +88,55 @@
#define IMX8M_PCIE1_SW_Pxx_REQ BIT(1)
#define IMX8M_MIPI_SW_Pxx_REQ BIT(0)
+#define IMX8MM_VPUH1_SW_Pxx_REQ BIT(13)
+#define IMX8MM_VPUG2_SW_Pxx_REQ BIT(12)
+#define IMX8MM_VPUG1_SW_Pxx_REQ BIT(11)
+#define IMX8MM_DISPMIX_SW_Pxx_REQ BIT(10)
+#define IMX8MM_VPUMIX_SW_Pxx_REQ BIT(8)
+#define IMX8MM_GPUMIX_SW_Pxx_REQ BIT(7)
+#define IMX8MM_GPU_SW_Pxx_REQ (BIT(6) | BIT(9))
+#define IMX8MM_DDR1_SW_Pxx_REQ BIT(5)
+#define IMX8MM_OTG2_SW_Pxx_REQ BIT(3)
+#define IMX8MM_OTG1_SW_Pxx_REQ BIT(2)
+#define IMX8MM_PCIE_SW_Pxx_REQ BIT(1)
+#define IMX8MM_MIPI_SW_Pxx_REQ BIT(0)
+
+#define IMX8MN_DISPMIX_SW_Pxx_REQ BIT(10)
+#define IMX8MN_GPUMIX_SW_Pxx_REQ BIT(7)
+#define IMX8MN_DDR1_SW_Pxx_REQ BIT(5)
+#define IMX8MN_OTG1_SW_Pxx_REQ BIT(2)
+#define IMX8MN_MIPI_SW_Pxx_REQ BIT(0)
+
#define GPC_M4_PU_PDN_FLG 0x1bc
#define GPC_PU_PWRHSK 0x1fc
+#define IMX8M_GPU_HSK_PWRDNACKN BIT(26)
+#define IMX8M_VPU_HSK_PWRDNACKN BIT(25)
+#define IMX8M_DISP_HSK_PWRDNACKN BIT(24)
#define IMX8M_GPU_HSK_PWRDNREQN BIT(6)
#define IMX8M_VPU_HSK_PWRDNREQN BIT(5)
#define IMX8M_DISP_HSK_PWRDNREQN BIT(4)
+
+#define IMX8MM_GPUMIX_HSK_PWRDNACKN BIT(29)
+#define IMX8MM_GPU_HSK_PWRDNACKN (BIT(27) | BIT(28))
+#define IMX8MM_VPUMIX_HSK_PWRDNACKN BIT(26)
+#define IMX8MM_DISPMIX_HSK_PWRDNACKN BIT(25)
+#define IMX8MM_HSIO_HSK_PWRDNACKN (BIT(23) | BIT(24))
+#define IMX8MM_GPUMIX_HSK_PWRDNREQN BIT(11)
+#define IMX8MM_GPU_HSK_PWRDNREQN (BIT(9) | BIT(10))
+#define IMX8MM_VPUMIX_HSK_PWRDNREQN BIT(8)
+#define IMX8MM_DISPMIX_HSK_PWRDNREQN BIT(7)
+#define IMX8MM_HSIO_HSK_PWRDNREQN (BIT(5) | BIT(6))
+
+#define IMX8MN_GPUMIX_HSK_PWRDNACKN (BIT(29) | BIT(27))
+#define IMX8MN_DISPMIX_HSK_PWRDNACKN BIT(25)
+#define IMX8MN_HSIO_HSK_PWRDNACKN BIT(23)
+#define IMX8MN_GPUMIX_HSK_PWRDNREQN (BIT(11) | BIT(9))
+#define IMX8MN_DISPMIX_HSK_PWRDNREQN BIT(7)
+#define IMX8MN_HSIO_HSK_PWRDNREQN BIT(5)
+
/*
* The PGC offset values in Reference Manual
* (Rev. 1, 01/2018 and the older ones) GPC chapter's
@@ -95,18 +159,37 @@
#define IMX8M_PGC_MIPI_CSI2 28
#define IMX8M_PGC_PCIE2 29
+#define IMX8MM_PGC_MIPI 16
+#define IMX8MM_PGC_PCIE 17
+#define IMX8MM_PGC_OTG1 18
+#define IMX8MM_PGC_OTG2 19
+#define IMX8MM_PGC_DDR1 21
+#define IMX8MM_PGC_GPU2D 22
+#define IMX8MM_PGC_GPUMIX 23
+#define IMX8MM_PGC_VPUMIX 24
+#define IMX8MM_PGC_GPU3D 25
+#define IMX8MM_PGC_DISPMIX 26
+#define IMX8MM_PGC_VPUG1 27
+#define IMX8MM_PGC_VPUG2 28
+#define IMX8MM_PGC_VPUH1 29
+
+#define IMX8MN_PGC_MIPI 16
+#define IMX8MN_PGC_OTG1 18
+#define IMX8MN_PGC_DDR1 21
+#define IMX8MN_PGC_GPUMIX 23
+#define IMX8MN_PGC_DISPMIX 26
+
#define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40)
#define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc)
#define GPC_PGC_CTRL_PCR BIT(0)
-#define GPC_CLK_MAX 6
-
struct imx_pgc_domain {
struct generic_pm_domain genpd;
struct regmap *regmap;
struct regulator *regulator;
- struct clk *clk[GPC_CLK_MAX];
+ struct reset_control *reset;
+ struct clk_bulk_data *clks;
int num_clks;
unsigned int pgc;
@@ -114,7 +197,8 @@ struct imx_pgc_domain {
const struct {
u32 pxx;
u32 map;
- u32 hsk;
+ u32 hskreq;
+ u32 hskack;
} bits;
const int voltage;
@@ -127,96 +211,172 @@ struct imx_pgc_domain_data {
const struct regmap_access_table *reg_access_table;
};
-static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
- bool on)
+static inline struct imx_pgc_domain *
+to_imx_pgc_domain(struct generic_pm_domain *genpd)
{
- struct imx_pgc_domain *domain = container_of(genpd,
- struct imx_pgc_domain,
- genpd);
- unsigned int offset = on ?
- GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ;
- const bool enable_power_control = !on;
- const bool has_regulator = !IS_ERR(domain->regulator);
- int i, ret = 0;
- u32 pxx_req;
-
- regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
- domain->bits.map, domain->bits.map);
-
- if (has_regulator && on) {
+ return container_of(genpd, struct imx_pgc_domain, genpd);
+}
+
+static int imx_pgc_power_up(struct generic_pm_domain *genpd)
+{
+ struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd);
+ u32 reg_val;
+ int ret;
+
+ ret = pm_runtime_get_sync(domain->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(domain->dev);
+ return ret;
+ }
+
+ if (!IS_ERR(domain->regulator)) {
ret = regulator_enable(domain->regulator);
if (ret) {
dev_err(domain->dev, "failed to enable regulator\n");
- goto unmap;
+ goto out_put_pm;
}
}
/* Enable reset clocks for all devices in the domain */
- for (i = 0; i < domain->num_clks; i++)
- clk_prepare_enable(domain->clk[i]);
+ ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
+ if (ret) {
+ dev_err(domain->dev, "failed to enable reset clocks\n");
+ goto out_regulator_disable;
+ }
- if (enable_power_control)
- regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc),
- GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR);
+ if (domain->bits.pxx) {
+ /* request the domain to power up */
+ regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PUP_REQ,
+ domain->bits.pxx, domain->bits.pxx);
+ /*
+ * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
+ * for PUP_REQ/PDN_REQ bit to be cleared
+ */
+ ret = regmap_read_poll_timeout(domain->regmap,
+ GPC_PU_PGC_SW_PUP_REQ, reg_val,
+ !(reg_val & domain->bits.pxx),
+ 0, USEC_PER_MSEC);
+ if (ret) {
+ dev_err(domain->dev, "failed to command PGC\n");
+ goto out_clk_disable;
+ }
+
+ /* disable power control */
+ regmap_clear_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc),
+ GPC_PGC_CTRL_PCR);
+ }
- if (domain->bits.hsk)
+ reset_control_assert(domain->reset);
+
+ /* delay for reset to propagate */
+ udelay(5);
+
+ reset_control_deassert(domain->reset);
+
+ /* request the ADB400 to power up */
+ if (domain->bits.hskreq) {
regmap_update_bits(domain->regmap, GPC_PU_PWRHSK,
- domain->bits.hsk, on ? domain->bits.hsk : 0);
-
- regmap_update_bits(domain->regmap, offset,
- domain->bits.pxx, domain->bits.pxx);
-
- /*
- * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
- * for PUP_REQ/PDN_REQ bit to be cleared
- */
- ret = regmap_read_poll_timeout(domain->regmap, offset, pxx_req,
- !(pxx_req & domain->bits.pxx),
- 0, USEC_PER_MSEC);
- if (ret) {
- dev_err(domain->dev, "failed to command PGC\n");
+ domain->bits.hskreq, domain->bits.hskreq);
+
/*
- * If we were in a process of enabling a
- * domain and failed we might as well disable
- * the regulator we just enabled. And if it
- * was the opposite situation and we failed to
- * power down -- keep the regulator on
+ * ret = regmap_read_poll_timeout(domain->regmap, GPC_PU_PWRHSK, reg_val,
+ * (reg_val & domain->bits.hskack), 0,
+ * USEC_PER_MSEC);
+ * Technically we need the commented code to wait handshake. But that needs
+ * the BLK-CTL module BUS clk-en bit being set.
+ *
+ * There is a separate BLK-CTL module and we will have such a driver for it,
+ * that driver will set the BUS clk-en bit and handshake will be triggered
+ * automatically there. Just add a delay and suppose the handshake finish
+ * after that.
*/
- on = !on;
}
- if (enable_power_control)
- regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc),
- GPC_PGC_CTRL_PCR, 0);
-
/* Disable reset clocks for all devices in the domain */
- for (i = 0; i < domain->num_clks; i++)
- clk_disable_unprepare(domain->clk[i]);
-
- if (has_regulator && !on) {
- int err;
-
- err = regulator_disable(domain->regulator);
- if (err)
- dev_err(domain->dev,
- "failed to disable regulator: %d\n", err);
- /* Preserve earlier error code */
- ret = ret ?: err;
- }
-unmap:
- regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
- domain->bits.map, 0);
+ clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
+
+ return 0;
+
+out_clk_disable:
+ clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
+out_regulator_disable:
+ if (!IS_ERR(domain->regulator))
+ regulator_disable(domain->regulator);
+out_put_pm:
+ pm_runtime_put(domain->dev);
+
return ret;
}
-static int imx_gpc_pu_pgc_sw_pup_req(struct generic_pm_domain *genpd)
+static int imx_pgc_power_down(struct generic_pm_domain *genpd)
{
- return imx_gpc_pu_pgc_sw_pxx_req(genpd, true);
-}
+ struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd);
+ u32 reg_val;
+ int ret;
-static int imx_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd)
-{
- return imx_gpc_pu_pgc_sw_pxx_req(genpd, false);
+ /* Enable reset clocks for all devices in the domain */
+ ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
+ if (ret) {
+ dev_err(domain->dev, "failed to enable reset clocks\n");
+ return ret;
+ }
+
+ /* request the ADB400 to power down */
+ if (domain->bits.hskreq) {
+ regmap_clear_bits(domain->regmap, GPC_PU_PWRHSK,
+ domain->bits.hskreq);
+
+ ret = regmap_read_poll_timeout(domain->regmap, GPC_PU_PWRHSK,
+ reg_val,
+ !(reg_val & domain->bits.hskack),
+ 0, USEC_PER_MSEC);
+ if (ret) {
+ dev_err(domain->dev, "failed to power down ADB400\n");
+ goto out_clk_disable;
+ }
+ }
+
+ if (domain->bits.pxx) {
+ /* enable power control */
+ regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc),
+ GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR);
+
+ /* request the domain to power down */
+ regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PDN_REQ,
+ domain->bits.pxx, domain->bits.pxx);
+ /*
+ * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
+ * for PUP_REQ/PDN_REQ bit to be cleared
+ */
+ ret = regmap_read_poll_timeout(domain->regmap,
+ GPC_PU_PGC_SW_PDN_REQ, reg_val,
+ !(reg_val & domain->bits.pxx),
+ 0, USEC_PER_MSEC);
+ if (ret) {
+ dev_err(domain->dev, "failed to command PGC\n");
+ goto out_clk_disable;
+ }
+ }
+
+ /* Disable reset clocks for all devices in the domain */
+ clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
+
+ if (!IS_ERR(domain->regulator)) {
+ ret = regulator_disable(domain->regulator);
+ if (ret) {
+ dev_err(domain->dev, "failed to disable regulator\n");
+ return ret;
+ }
+ }
+
+ pm_runtime_put(domain->dev);
+
+ return 0;
+
+out_clk_disable:
+ clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
+
+ return ret;
}
static const struct imx_pgc_domain imx7_pgc_domains[] = {
@@ -342,7 +502,8 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
.bits = {
.pxx = IMX8M_GPU_SW_Pxx_REQ,
.map = IMX8M_GPU_A53_DOMAIN,
- .hsk = IMX8M_GPU_HSK_PWRDNREQN,
+ .hskreq = IMX8M_GPU_HSK_PWRDNREQN,
+ .hskack = IMX8M_GPU_HSK_PWRDNACKN,
},
.pgc = IMX8M_PGC_GPU,
},
@@ -354,7 +515,8 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
.bits = {
.pxx = IMX8M_VPU_SW_Pxx_REQ,
.map = IMX8M_VPU_A53_DOMAIN,
- .hsk = IMX8M_VPU_HSK_PWRDNREQN,
+ .hskreq = IMX8M_VPU_HSK_PWRDNREQN,
+ .hskack = IMX8M_VPU_HSK_PWRDNACKN,
},
.pgc = IMX8M_PGC_VPU,
},
@@ -366,7 +528,8 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {
.bits = {
.pxx = IMX8M_DISP_SW_Pxx_REQ,
.map = IMX8M_DISP_A53_DOMAIN,
- .hsk = IMX8M_DISP_HSK_PWRDNREQN,
+ .hskreq = IMX8M_DISP_HSK_PWRDNREQN,
+ .hskack = IMX8M_DISP_HSK_PWRDNACKN,
},
.pgc = IMX8M_PGC_DISP,
},
@@ -443,40 +606,254 @@ static const struct imx_pgc_domain_data imx8m_pgc_domain_data = {
.reg_access_table = &imx8m_access_table,
};
-static int imx_pgc_get_clocks(struct imx_pgc_domain *domain)
-{
- int i, ret;
-
- for (i = 0; ; i++) {
- struct clk *clk = of_clk_get(domain->dev->of_node, i);
- if (IS_ERR(clk))
- break;
- if (i >= GPC_CLK_MAX) {
- dev_err(domain->dev, "more than %d clocks\n",
- GPC_CLK_MAX);
- ret = -EINVAL;
- goto clk_err;
- }
- domain->clk[i] = clk;
- }
- domain->num_clks = i;
+static const struct imx_pgc_domain imx8mm_pgc_domains[] = {
+ [IMX8MM_POWER_DOMAIN_HSIOMIX] = {
+ .genpd = {
+ .name = "hsiomix",
+ },
+ .bits = {
+ .pxx = 0, /* no power sequence control */
+ .map = 0, /* no power sequence control */
+ .hskreq = IMX8MM_HSIO_HSK_PWRDNREQN,
+ .hskack = IMX8MM_HSIO_HSK_PWRDNACKN,
+ },
+ },
- return 0;
+ [IMX8MM_POWER_DOMAIN_PCIE] = {
+ .genpd = {
+ .name = "pcie",
+ },
+ .bits = {
+ .pxx = IMX8MM_PCIE_SW_Pxx_REQ,
+ .map = IMX8MM_PCIE_A53_DOMAIN,
+ },
+ .pgc = IMX8MM_PGC_PCIE,
+ },
-clk_err:
- while (i--)
- clk_put(domain->clk[i]);
+ [IMX8MM_POWER_DOMAIN_OTG1] = {
+ .genpd = {
+ .name = "usb-otg1",
+ },
+ .bits = {
+ .pxx = IMX8MM_OTG1_SW_Pxx_REQ,
+ .map = IMX8MM_OTG1_A53_DOMAIN,
+ },
+ .pgc = IMX8MM_PGC_OTG1,
+ },
- return ret;
-}
+ [IMX8MM_POWER_DOMAIN_OTG2] = {
+ .genpd = {
+ .name = "usb-otg2",
+ },
+ .bits = {
+ .pxx = IMX8MM_OTG2_SW_Pxx_REQ,
+ .map = IMX8MM_OTG2_A53_DOMAIN,
+ },
+ .pgc = IMX8MM_PGC_OTG2,
+ },
-static void imx_pgc_put_clocks(struct imx_pgc_domain *domain)
-{
- int i;
+ [IMX8MM_POWER_DOMAIN_GPUMIX] = {
+ .genpd = {
+ .name = "gpumix",
+ },
+ .bits = {
+ .pxx = IMX8MM_GPUMIX_SW_Pxx_REQ,
+ .map = IMX8MM_GPUMIX_A53_DOMAIN,
+ .hskreq = IMX8MM_GPUMIX_HSK_PWRDNREQN,
+ .hskack = IMX8MM_GPUMIX_HSK_PWRDNACKN,
+ },
+ .pgc = IMX8MM_PGC_GPUMIX,
+ },
- for (i = domain->num_clks - 1; i >= 0; i--)
- clk_put(domain->clk[i]);
-}
+ [IMX8MM_POWER_DOMAIN_GPU] = {
+ .genpd = {
+ .name = "gpu",
+ },
+ .bits = {
+ .pxx = IMX8MM_GPU_SW_Pxx_REQ,
+ .map = IMX8MM_GPU_A53_DOMAIN,
+ .hskreq = IMX8MM_GPU_HSK_PWRDNREQN,
+ .hskack = IMX8MM_GPU_HSK_PWRDNACKN,
+ },
+ .pgc = IMX8MM_PGC_GPU2D,
+ },
+
+ [IMX8MM_POWER_DOMAIN_VPUMIX] = {
+ .genpd = {
+ .name = "vpumix",
+ },
+ .bits = {
+ .pxx = IMX8MM_VPUMIX_SW_Pxx_REQ,
+ .map = IMX8MM_VPUMIX_A53_DOMAIN,
+ .hskreq = IMX8MM_VPUMIX_HSK_PWRDNREQN,
+ .hskack = IMX8MM_VPUMIX_HSK_PWRDNACKN,
+ },
+ .pgc = IMX8MM_PGC_VPUMIX,
+ },
+
+ [IMX8MM_POWER_DOMAIN_VPUG1] = {
+ .genpd = {
+ .name = "vpu-g1",
+ },
+ .bits = {
+ .pxx = IMX8MM_VPUG1_SW_Pxx_REQ,
+ .map = IMX8MM_VPUG1_A53_DOMAIN,
+ },
+ .pgc = IMX8MM_PGC_VPUG1,
+ },
+
+ [IMX8MM_POWER_DOMAIN_VPUG2] = {
+ .genpd = {
+ .name = "vpu-g2",
+ },
+ .bits = {
+ .pxx = IMX8MM_VPUG2_SW_Pxx_REQ,
+ .map = IMX8MM_VPUG2_A53_DOMAIN,
+ },
+ .pgc = IMX8MM_PGC_VPUG2,
+ },
+
+ [IMX8MM_POWER_DOMAIN_VPUH1] = {
+ .genpd = {
+ .name = "vpu-h1",
+ },
+ .bits = {
+ .pxx = IMX8MM_VPUH1_SW_Pxx_REQ,
+ .map = IMX8MM_VPUH1_A53_DOMAIN,
+ },
+ .pgc = IMX8MM_PGC_VPUH1,
+ },
+
+ [IMX8MM_POWER_DOMAIN_DISPMIX] = {
+ .genpd = {
+ .name = "dispmix",
+ },
+ .bits = {
+ .pxx = IMX8MM_DISPMIX_SW_Pxx_REQ,
+ .map = IMX8MM_DISPMIX_A53_DOMAIN,
+ .hskreq = IMX8MM_DISPMIX_HSK_PWRDNREQN,
+ .hskack = IMX8MM_DISPMIX_HSK_PWRDNACKN,
+ },
+ .pgc = IMX8MM_PGC_DISPMIX,
+ },
+
+ [IMX8MM_POWER_DOMAIN_MIPI] = {
+ .genpd = {
+ .name = "mipi",
+ },
+ .bits = {
+ .pxx = IMX8MM_MIPI_SW_Pxx_REQ,
+ .map = IMX8MM_MIPI_A53_DOMAIN,
+ },
+ .pgc = IMX8MM_PGC_MIPI,
+ },
+};
+
+static const struct regmap_range imx8mm_yes_ranges[] = {
+ regmap_reg_range(GPC_LPCR_A_CORE_BSC,
+ GPC_PU_PWRHSK),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_MIPI),
+ GPC_PGC_SR(IMX8MM_PGC_MIPI)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_PCIE),
+ GPC_PGC_SR(IMX8MM_PGC_PCIE)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_OTG1),
+ GPC_PGC_SR(IMX8MM_PGC_OTG1)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_OTG2),
+ GPC_PGC_SR(IMX8MM_PGC_OTG2)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_DDR1),
+ GPC_PGC_SR(IMX8MM_PGC_DDR1)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPU2D),
+ GPC_PGC_SR(IMX8MM_PGC_GPU2D)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPUMIX),
+ GPC_PGC_SR(IMX8MM_PGC_GPUMIX)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUMIX),
+ GPC_PGC_SR(IMX8MM_PGC_VPUMIX)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_GPU3D),
+ GPC_PGC_SR(IMX8MM_PGC_GPU3D)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_DISPMIX),
+ GPC_PGC_SR(IMX8MM_PGC_DISPMIX)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUG1),
+ GPC_PGC_SR(IMX8MM_PGC_VPUG1)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUG2),
+ GPC_PGC_SR(IMX8MM_PGC_VPUG2)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MM_PGC_VPUH1),
+ GPC_PGC_SR(IMX8MM_PGC_VPUH1)),
+};
+
+static const struct regmap_access_table imx8mm_access_table = {
+ .yes_ranges = imx8mm_yes_ranges,
+ .n_yes_ranges = ARRAY_SIZE(imx8mm_yes_ranges),
+};
+
+static const struct imx_pgc_domain_data imx8mm_pgc_domain_data = {
+ .domains = imx8mm_pgc_domains,
+ .domains_num = ARRAY_SIZE(imx8mm_pgc_domains),
+ .reg_access_table = &imx8mm_access_table,
+};
+
+static const struct imx_pgc_domain imx8mn_pgc_domains[] = {
+ [IMX8MN_POWER_DOMAIN_HSIOMIX] = {
+ .genpd = {
+ .name = "hsiomix",
+ },
+ .bits = {
+ .pxx = 0, /* no power sequence control */
+ .map = 0, /* no power sequence control */
+ .hskreq = IMX8MN_HSIO_HSK_PWRDNREQN,
+ .hskack = IMX8MN_HSIO_HSK_PWRDNACKN,
+ },
+ },
+
+ [IMX8MN_POWER_DOMAIN_OTG1] = {
+ .genpd = {
+ .name = "usb-otg1",
+ },
+ .bits = {
+ .pxx = IMX8MN_OTG1_SW_Pxx_REQ,
+ .map = IMX8MN_OTG1_A53_DOMAIN,
+ },
+ .pgc = IMX8MN_PGC_OTG1,
+ },
+
+ [IMX8MN_POWER_DOMAIN_GPUMIX] = {
+ .genpd = {
+ .name = "gpumix",
+ },
+ .bits = {
+ .pxx = IMX8MN_GPUMIX_SW_Pxx_REQ,
+ .map = IMX8MN_GPUMIX_A53_DOMAIN,
+ .hskreq = IMX8MN_GPUMIX_HSK_PWRDNREQN,
+ .hskack = IMX8MN_GPUMIX_HSK_PWRDNACKN,
+ },
+ .pgc = IMX8MN_PGC_GPUMIX,
+ },
+};
+
+static const struct regmap_range imx8mn_yes_ranges[] = {
+ regmap_reg_range(GPC_LPCR_A_CORE_BSC,
+ GPC_PU_PWRHSK),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_MIPI),
+ GPC_PGC_SR(IMX8MN_PGC_MIPI)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_OTG1),
+ GPC_PGC_SR(IMX8MN_PGC_OTG1)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_DDR1),
+ GPC_PGC_SR(IMX8MN_PGC_DDR1)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_GPUMIX),
+ GPC_PGC_SR(IMX8MN_PGC_GPUMIX)),
+ regmap_reg_range(GPC_PGC_CTRL(IMX8MN_PGC_DISPMIX),
+ GPC_PGC_SR(IMX8MN_PGC_DISPMIX)),
+};
+
+static const struct regmap_access_table imx8mn_access_table = {
+ .yes_ranges = imx8mn_yes_ranges,
+ .n_yes_ranges = ARRAY_SIZE(imx8mn_yes_ranges),
+};
+
+static const struct imx_pgc_domain_data imx8mn_pgc_domain_data = {
+ .domains = imx8mn_pgc_domains,
+ .domains_num = ARRAY_SIZE(imx8mn_pgc_domains),
+ .reg_access_table = &imx8mn_access_table,
+};
static int imx_pgc_domain_probe(struct platform_device *pdev)
{
@@ -495,25 +872,45 @@ static int imx_pgc_domain_probe(struct platform_device *pdev)
domain->voltage, domain->voltage);
}
- ret = imx_pgc_get_clocks(domain);
- if (ret)
- return dev_err_probe(domain->dev, ret, "Failed to get domain's clocks\n");
+ domain->num_clks = devm_clk_bulk_get_all(domain->dev, &domain->clks);
+ if (domain->num_clks < 0)
+ return dev_err_probe(domain->dev, domain->num_clks,
+ "Failed to get domain's clocks\n");
+
+ domain->reset = devm_reset_control_array_get_optional_exclusive(domain->dev);
+ if (IS_ERR(domain->reset))
+ return dev_err_probe(domain->dev, PTR_ERR(domain->reset),
+ "Failed to get domain's resets\n");
+
+ pm_runtime_enable(domain->dev);
+
+ if (domain->bits.map)
+ regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
+ domain->bits.map, domain->bits.map);
ret = pm_genpd_init(&domain->genpd, NULL, true);
if (ret) {
dev_err(domain->dev, "Failed to init power domain\n");
- imx_pgc_put_clocks(domain);
- return ret;
+ goto out_domain_unmap;
}
ret = of_genpd_add_provider_simple(domain->dev->of_node,
&domain->genpd);
if (ret) {
dev_err(domain->dev, "Failed to add genpd provider\n");
- pm_genpd_remove(&domain->genpd);
- imx_pgc_put_clocks(domain);
+ goto out_genpd_remove;
}
+ return 0;
+
+out_genpd_remove:
+ pm_genpd_remove(&domain->genpd);
+out_domain_unmap:
+ if (domain->bits.map)
+ regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
+ domain->bits.map, 0);
+ pm_runtime_disable(domain->dev);
+
return ret;
}
@@ -523,7 +920,12 @@ static int imx_pgc_domain_remove(struct platform_device *pdev)
of_genpd_del_provider(domain->dev->of_node);
pm_genpd_remove(&domain->genpd);
- imx_pgc_put_clocks(domain);
+
+ if (domain->bits.map)
+ regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
+ domain->bits.map, 0);
+
+ pm_runtime_disable(domain->dev);
return 0;
}
@@ -617,8 +1019,8 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
domain = pd_pdev->dev.platform_data;
domain->regmap = regmap;
- domain->genpd.power_on = imx_gpc_pu_pgc_sw_pup_req;
- domain->genpd.power_off = imx_gpc_pu_pgc_sw_pdn_req;
+ domain->genpd.power_on = imx_pgc_power_up;
+ domain->genpd.power_off = imx_pgc_power_down;
pd_pdev->dev.parent = dev;
pd_pdev->dev.of_node = np;
@@ -636,6 +1038,8 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
static const struct of_device_id imx_gpcv2_dt_ids[] = {
{ .compatible = "fsl,imx7d-gpc", .data = &imx7_pgc_domain_data, },
+ { .compatible = "fsl,imx8mm-gpc", .data = &imx8mm_pgc_domain_data, },
+ { .compatible = "fsl,imx8mn-gpc", .data = &imx8mn_pgc_domain_data, },
{ .compatible = "fsl,imx8mq-gpc", .data = &imx8m_pgc_domain_data, },
{ }
};
diff --git a/drivers/soc/imx/soc-imx.c b/drivers/soc/imx/soc-imx.c
index 0738c0f36792..ac6d856ba228 100644
--- a/drivers/soc/imx/soc-imx.c
+++ b/drivers/soc/imx/soc-imx.c
@@ -70,6 +70,9 @@ static int __init imx_soc_device_init(void)
case MXC_CPU_MX35:
soc_id = "i.MX35";
break;
+ case MXC_CPU_MX50:
+ soc_id = "i.MX50";
+ break;
case MXC_CPU_MX51:
ocotp_compat = "fsl,imx51-iim";
soc_id = "i.MX51";
diff --git a/drivers/soc/ixp4xx/ixp4xx-npe.c b/drivers/soc/ixp4xx/ixp4xx-npe.c
index ec90b44fa0cd..7bd19354982a 100644
--- a/drivers/soc/ixp4xx/ixp4xx-npe.c
+++ b/drivers/soc/ixp4xx/ixp4xx-npe.c
@@ -18,8 +18,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/soc/ixp4xx/npe.h>
+#include <mach/hardware.h>
+#include <linux/soc/ixp4xx/cpu.h>
#define DEBUG_MSG 0
#define DEBUG_FW 0
@@ -679,6 +682,7 @@ static int ixp4xx_npe_probe(struct platform_device *pdev)
{
int i, found = 0;
struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct resource *res;
for (i = 0; i < NPE_COUNT; i++) {
@@ -711,6 +715,11 @@ static int ixp4xx_npe_probe(struct platform_device *pdev)
if (!found)
return -ENODEV;
+
+ /* Spawn crypto subdevice if using device tree */
+ if (IS_ENABLED(CONFIG_OF) && np)
+ devm_of_platform_populate(dev);
+
return 0;
}
diff --git a/drivers/soc/ixp4xx/ixp4xx-qmgr.c b/drivers/soc/ixp4xx/ixp4xx-qmgr.c
index 8c968382cea7..7149510b307e 100644
--- a/drivers/soc/ixp4xx/ixp4xx-qmgr.c
+++ b/drivers/soc/ixp4xx/ixp4xx-qmgr.c
@@ -12,6 +12,8 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/soc/ixp4xx/qmgr.h>
+#include <mach/hardware.h>
+#include <linux/soc/ixp4xx/cpu.h>
static struct qmgr_regs __iomem *qmgr_regs;
static int qmgr_irq_1;
diff --git a/drivers/soc/litex/Kconfig b/drivers/soc/litex/Kconfig
index e7011d665b15..e6ba3573a772 100644
--- a/drivers/soc/litex/Kconfig
+++ b/drivers/soc/litex/Kconfig
@@ -17,16 +17,4 @@ config LITEX_SOC_CONTROLLER
All drivers that use functions from litex.h must depend on
LITEX.
-config LITEX_SUBREG_SIZE
- int "Size of a LiteX CSR subregister, in bytes"
- depends on LITEX
- range 1 4
- default 4
- help
- LiteX MMIO registers (referred to as Configuration and Status
- registers, or CSRs) are spread across adjacent 8- or 32-bit
- subregisters, located at 32-bit aligned MMIO addresses. Use
- this to select the appropriate size (1 or 4 bytes) matching
- your particular LiteX build.
-
endmenu
diff --git a/drivers/soc/litex/litex_soc_ctrl.c b/drivers/soc/litex/litex_soc_ctrl.c
index c3e379a990f2..f75790091d38 100644
--- a/drivers/soc/litex/litex_soc_ctrl.c
+++ b/drivers/soc/litex/litex_soc_ctrl.c
@@ -62,8 +62,7 @@ static int litex_check_csr_access(void __iomem *reg_addr)
/* restore original value of the SCRATCH register */
litex_write32(reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_VALUE);
- pr_info("LiteX SoC Controller driver initialized: subreg:%d, align:%d",
- LITEX_SUBREG_SIZE, LITEX_SUBREG_ALIGN);
+ pr_info("LiteX SoC Controller driver initialized");
return 0;
}
diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
index f1cea041dc5a..7c65ad3d1f8a 100644
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -234,6 +234,7 @@ static const struct of_device_id mtk_devapc_dt_match[] = {
}, {
},
};
+MODULE_DEVICE_TABLE(of, mtk_devapc_dt_match);
static int mtk_devapc_probe(struct platform_device *pdev)
{
diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c
index 0af00efa0ef8..b762bc40f56b 100644
--- a/drivers/soc/mediatek/mtk-pm-domains.c
+++ b/drivers/soc/mediatek/mtk-pm-domains.c
@@ -211,7 +211,7 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
if (ret)
return ret;
- ret = clk_bulk_enable(pd->num_clks, pd->clks);
+ ret = clk_bulk_prepare_enable(pd->num_clks, pd->clks);
if (ret)
goto err_reg;
@@ -229,7 +229,7 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT);
regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
- ret = clk_bulk_enable(pd->num_subsys_clks, pd->subsys_clks);
+ ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks);
if (ret)
goto err_pwr_ack;
@@ -246,9 +246,9 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
err_disable_sram:
scpsys_sram_disable(pd);
err_disable_subsys_clks:
- clk_bulk_disable(pd->num_subsys_clks, pd->subsys_clks);
+ clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
err_pwr_ack:
- clk_bulk_disable(pd->num_clks, pd->clks);
+ clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
err_reg:
scpsys_regulator_disable(pd->supply);
return ret;
@@ -269,7 +269,7 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
if (ret < 0)
return ret;
- clk_bulk_disable(pd->num_subsys_clks, pd->subsys_clks);
+ clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
/* subsys power off */
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
@@ -284,7 +284,7 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
if (ret < 0)
return ret;
- clk_bulk_disable(pd->num_clks, pd->clks);
+ clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
scpsys_regulator_disable(pd->supply);
@@ -297,6 +297,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
const struct scpsys_domain_data *domain_data;
struct scpsys_domain *pd;
struct device_node *root_node = scpsys->dev->of_node;
+ struct device_node *smi_node;
struct property *prop;
const char *clk_name;
int i, ret, num_clks;
@@ -352,9 +353,13 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
if (IS_ERR(pd->infracfg))
return ERR_CAST(pd->infracfg);
- pd->smi = syscon_regmap_lookup_by_phandle_optional(node, "mediatek,smi");
- if (IS_ERR(pd->smi))
- return ERR_CAST(pd->smi);
+ smi_node = of_parse_phandle(node, "mediatek,smi", 0);
+ if (smi_node) {
+ pd->smi = device_node_to_regmap(smi_node);
+ of_node_put(smi_node);
+ if (IS_ERR(pd->smi))
+ return ERR_CAST(pd->smi);
+ }
num_clks = of_clk_get_parent_count(node);
if (num_clks > 0) {
@@ -405,14 +410,6 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
pd->subsys_clks[i].clk = clk;
}
- ret = clk_bulk_prepare(pd->num_clks, pd->clks);
- if (ret)
- goto err_put_subsys_clocks;
-
- ret = clk_bulk_prepare(pd->num_subsys_clks, pd->subsys_clks);
- if (ret)
- goto err_unprepare_clocks;
-
/*
* Initially turn on all domains to make the domains usable
* with !CONFIG_PM and to get the hardware in sync with the
@@ -427,7 +424,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
ret = scpsys_power_on(&pd->genpd);
if (ret < 0) {
dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret);
- goto err_unprepare_clocks;
+ goto err_put_subsys_clocks;
}
}
@@ -435,7 +432,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
ret = -EINVAL;
dev_err(scpsys->dev,
"power domain with id %d already exists, check your device-tree\n", id);
- goto err_unprepare_subsys_clocks;
+ goto err_put_subsys_clocks;
}
if (!pd->data->name)
@@ -455,10 +452,6 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
return scpsys->pd_data.domains[id];
-err_unprepare_subsys_clocks:
- clk_bulk_unprepare(pd->num_subsys_clks, pd->subsys_clks);
-err_unprepare_clocks:
- clk_bulk_unprepare(pd->num_clks, pd->clks);
err_put_subsys_clocks:
clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
err_put_clocks:
@@ -537,10 +530,7 @@ static void scpsys_remove_one_domain(struct scpsys_domain *pd)
"failed to remove domain '%s' : %d - state may be inconsistent\n",
pd->genpd.name, ret);
- clk_bulk_unprepare(pd->num_clks, pd->clks);
clk_bulk_put(pd->num_clks, pd->clks);
-
- clk_bulk_unprepare(pd->num_subsys_clks, pd->subsys_clks);
clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
}
diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
index e4de75f35c33..952bc554f443 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -961,6 +961,23 @@ static int mt8183_regs[] = {
[PWRAP_WACS2_VLDCLR] = 0xC28,
};
+static int mt8195_regs[] = {
+ [PWRAP_INIT_DONE2] = 0x0,
+ [PWRAP_STAUPD_CTRL] = 0x4C,
+ [PWRAP_TIMER_EN] = 0x3E4,
+ [PWRAP_INT_EN] = 0x420,
+ [PWRAP_INT_FLG] = 0x428,
+ [PWRAP_INT_CLR] = 0x42C,
+ [PWRAP_INT1_EN] = 0x450,
+ [PWRAP_INT1_FLG] = 0x458,
+ [PWRAP_INT1_CLR] = 0x45C,
+ [PWRAP_WACS2_CMD] = 0x880,
+ [PWRAP_SWINF_2_WDATA_31_0] = 0x884,
+ [PWRAP_SWINF_2_RDATA_31_0] = 0x894,
+ [PWRAP_WACS2_VLDCLR] = 0x8A4,
+ [PWRAP_WACS2_RDATA] = 0x8A8,
+};
+
static int mt8516_regs[] = {
[PWRAP_MUX_SEL] = 0x0,
[PWRAP_WRAP_EN] = 0x4,
@@ -1066,6 +1083,7 @@ enum pwrap_type {
PWRAP_MT8135,
PWRAP_MT8173,
PWRAP_MT8183,
+ PWRAP_MT8195,
PWRAP_MT8516,
};
@@ -1525,6 +1543,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
break;
case PWRAP_MT6873:
case PWRAP_MT8183:
+ case PWRAP_MT8195:
break;
}
@@ -2025,6 +2044,19 @@ static const struct pmic_wrapper_type pwrap_mt8183 = {
.init_soc_specific = pwrap_mt8183_init_soc_specific,
};
+static struct pmic_wrapper_type pwrap_mt8195 = {
+ .regs = mt8195_regs,
+ .type = PWRAP_MT8195,
+ .arb_en_all = 0x777f, /* NEED CONFIRM */
+ .int_en_all = 0x180000, /* NEED CONFIRM */
+ .int1_en_all = 0,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = PWRAP_CAP_INT1_EN | PWRAP_CAP_ARB,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = NULL,
+};
+
static struct pmic_wrapper_type pwrap_mt8516 = {
.regs = mt8516_regs,
.type = PWRAP_MT8516,
@@ -2066,6 +2098,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = {
.compatible = "mediatek,mt8183-pwrap",
.data = &pwrap_mt8183,
}, {
+ .compatible = "mediatek,mt8195-pwrap",
+ .data = &pwrap_mt8195,
+ }, {
.compatible = "mediatek,mt8516-pwrap",
.data = &pwrap_mt8516,
}, {
diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c
index bb21c4f1c0c4..2daa17ba54a3 100644
--- a/drivers/soc/qcom/rpmhpd.c
+++ b/drivers/soc/qcom/rpmhpd.c
@@ -271,9 +271,30 @@ static const struct rpmhpd_desc sc7280_desc = {
.num_pds = ARRAY_SIZE(sc7280_rpmhpds),
};
+/* SC8180x RPMH powerdomains */
+static struct rpmhpd *sc8180x_rpmhpds[] = {
+ [SC8180X_CX] = &sdm845_cx,
+ [SC8180X_CX_AO] = &sdm845_cx_ao,
+ [SC8180X_EBI] = &sdm845_ebi,
+ [SC8180X_GFX] = &sdm845_gfx,
+ [SC8180X_LCX] = &sdm845_lcx,
+ [SC8180X_LMX] = &sdm845_lmx,
+ [SC8180X_MMCX] = &sm8150_mmcx,
+ [SC8180X_MMCX_AO] = &sm8150_mmcx_ao,
+ [SC8180X_MSS] = &sdm845_mss,
+ [SC8180X_MX] = &sdm845_mx,
+ [SC8180X_MX_AO] = &sdm845_mx_ao,
+};
+
+static const struct rpmhpd_desc sc8180x_desc = {
+ .rpmhpds = sc8180x_rpmhpds,
+ .num_pds = ARRAY_SIZE(sc8180x_rpmhpds),
+};
+
static const struct of_device_id rpmhpd_match_table[] = {
{ .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc },
{ .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc },
+ { .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc },
{ .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc },
{ .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc},
{ .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc },
diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c
index 27733b0e7fca..0b532a892d60 100644
--- a/drivers/soc/qcom/rpmpd.c
+++ b/drivers/soc/qcom/rpmpd.c
@@ -118,6 +118,27 @@ struct rpmpd_desc {
static DEFINE_MUTEX(rpmpd_lock);
+/* mdm9607 RPM Power Domains */
+DEFINE_RPMPD_PAIR(mdm9607, vddcx, vddcx_ao, SMPA, LEVEL, 3);
+DEFINE_RPMPD_VFL(mdm9607, vddcx_vfl, SMPA, 3);
+
+DEFINE_RPMPD_PAIR(mdm9607, vddmx, vddmx_ao, LDOA, LEVEL, 12);
+DEFINE_RPMPD_VFL(mdm9607, vddmx_vfl, LDOA, 12);
+static struct rpmpd *mdm9607_rpmpds[] = {
+ [MDM9607_VDDCX] = &mdm9607_vddcx,
+ [MDM9607_VDDCX_AO] = &mdm9607_vddcx_ao,
+ [MDM9607_VDDCX_VFL] = &mdm9607_vddcx_vfl,
+ [MDM9607_VDDMX] = &mdm9607_vddmx,
+ [MDM9607_VDDMX_AO] = &mdm9607_vddmx_ao,
+ [MDM9607_VDDMX_VFL] = &mdm9607_vddmx_vfl,
+};
+
+static const struct rpmpd_desc mdm9607_desc = {
+ .rpmpds = mdm9607_rpmpds,
+ .num_pds = ARRAY_SIZE(mdm9607_rpmpds),
+ .max_state = RPM_SMD_LEVEL_TURBO,
+};
+
/* msm8939 RPM Power Domains */
DEFINE_RPMPD_PAIR(msm8939, vddmd, vddmd_ao, SMPA, CORNER, 1);
DEFINE_RPMPD_VFC(msm8939, vddmd_vfc, SMPA, 1);
@@ -326,6 +347,7 @@ static const struct rpmpd_desc sdm660_desc = {
};
static const struct of_device_id rpmpd_match_table[] = {
+ { .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc },
{ .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc },
{ .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc },
{ .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc },
diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c
index b93218cb50b5..bc0be1d4be5f 100644
--- a/drivers/soc/qcom/smd-rpm.c
+++ b/drivers/soc/qcom/smd-rpm.c
@@ -233,6 +233,7 @@ static void qcom_smd_rpm_remove(struct rpmsg_device *rpdev)
static const struct of_device_id qcom_smd_rpm_of_match[] = {
{ .compatible = "qcom,rpm-apq8084" },
{ .compatible = "qcom,rpm-ipq6018" },
+ { .compatible = "qcom,rpm-msm8226" },
{ .compatible = "qcom,rpm-msm8916" },
{ .compatible = "qcom,rpm-msm8936" },
{ .compatible = "qcom,rpm-msm8974" },
@@ -241,6 +242,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = {
{ .compatible = "qcom,rpm-msm8996" },
{ .compatible = "qcom,rpm-msm8998" },
{ .compatible = "qcom,rpm-sdm660" },
+ { .compatible = "qcom,rpm-sm6125" },
{ .compatible = "qcom,rpm-qcs404" },
{}
};
diff --git a/drivers/soc/qcom/smem_state.c b/drivers/soc/qcom/smem_state.c
index d2b558438deb..31faf4aa868e 100644
--- a/drivers/soc/qcom/smem_state.c
+++ b/drivers/soc/qcom/smem_state.c
@@ -151,6 +151,42 @@ void qcom_smem_state_put(struct qcom_smem_state *state)
}
EXPORT_SYMBOL_GPL(qcom_smem_state_put);
+static void devm_qcom_smem_state_release(struct device *dev, void *res)
+{
+ qcom_smem_state_put(*(struct qcom_smem_state **)res);
+}
+
+/**
+ * devm_qcom_smem_state_get() - acquire handle to a devres managed state
+ * @dev: client device pointer
+ * @con_id: name of the state to lookup
+ * @bit: flags from the state reference, indicating which bit's affected
+ *
+ * Returns handle to the state, or ERR_PTR(). qcom_smem_state_put() is called
+ * automatically when @dev is removed.
+ */
+struct qcom_smem_state *devm_qcom_smem_state_get(struct device *dev,
+ const char *con_id,
+ unsigned *bit)
+{
+ struct qcom_smem_state **ptr, *state;
+
+ ptr = devres_alloc(devm_qcom_smem_state_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ state = qcom_smem_state_get(dev, con_id, bit);
+ if (!IS_ERR(state)) {
+ *ptr = state;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return state;
+}
+EXPORT_SYMBOL_GPL(devm_qcom_smem_state_get);
+
/**
* qcom_smem_state_register() - register a new state
* @of_node: of_node used for matching client lookups
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index f6cfb79338f0..b2f049faa3df 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -70,21 +70,33 @@ static const char *const socinfo_image_names[] = {
static const char *const pmic_models[] = {
[0] = "Unknown PMIC model",
+ [1] = "PM8941",
+ [2] = "PM8841",
+ [3] = "PM8019",
+ [4] = "PM8226",
+ [5] = "PM8110",
+ [6] = "PMA8084",
+ [7] = "PMI8962",
+ [8] = "PMD9635",
[9] = "PM8994",
+ [10] = "PMI8994",
[11] = "PM8916",
- [13] = "PM8058",
+ [12] = "PM8004",
+ [13] = "PM8909/PM8058",
[14] = "PM8028",
[15] = "PM8901",
- [16] = "PM8027",
- [17] = "ISL9519",
+ [16] = "PM8950/PM8027",
+ [17] = "PMI8950/ISL9519",
[18] = "PM8921",
[19] = "PM8018",
- [20] = "PM8015",
- [21] = "PM8014",
+ [20] = "PM8998/PM8015",
+ [21] = "PMI8998/PM8014",
[22] = "PM8821",
[23] = "PM8038",
- [24] = "PM8922",
+ [24] = "PM8005/PM8922",
[25] = "PM8917",
+ [26] = "PM660L",
+ [27] = "PM660",
[30] = "PM8150",
[31] = "PM8150L",
[32] = "PM8150B",
@@ -195,11 +207,30 @@ static const struct soc_id soc_id[] = {
{ 139, "APQ8060AB" },
{ 140, "MSM8260AB" },
{ 141, "MSM8660AB" },
+ { 145, "MSM8626" },
+ { 147, "MSM8610" },
+ { 153, "APQ8064AB" },
+ { 158, "MSM8226" },
+ { 159, "MSM8526" },
+ { 161, "MSM8110" },
+ { 162, "MSM8210" },
+ { 163, "MSM8810" },
+ { 164, "MSM8212" },
+ { 165, "MSM8612" },
+ { 166, "MSM8112" },
+ { 168, "MSM8225Q" },
+ { 169, "MSM8625Q" },
+ { 170, "MSM8125Q" },
+ { 172, "APQ8064AA" },
{ 178, "APQ8084" },
{ 184, "APQ8074" },
{ 185, "MSM8274" },
{ 186, "MSM8674" },
{ 194, "MSM8974PRO" },
+ { 198, "MSM8126" },
+ { 199, "APQ8026" },
+ { 200, "MSM8926" },
+ { 205, "MSM8326" },
{ 206, "MSM8916" },
{ 207, "MSM8994" },
{ 208, "APQ8074-AA" },
@@ -213,6 +244,14 @@ static const struct soc_id soc_id[] = {
{ 216, "MSM8674PRO" },
{ 217, "MSM8974-AA" },
{ 218, "MSM8974-AB" },
+ { 219, "APQ8028" },
+ { 220, "MSM8128" },
+ { 221, "MSM8228" },
+ { 222, "MSM8528" },
+ { 223, "MSM8628" },
+ { 224, "MSM8928" },
+ { 225, "MSM8510" },
+ { 226, "MSM8512" },
{ 233, "MSM8936" },
{ 239, "MSM8939" },
{ 240, "APQ8036" },
@@ -254,8 +293,13 @@ static const struct soc_id soc_id[] = {
{ 350, "SDA632" },
{ 351, "SDA450" },
{ 356, "SM8250" },
+ { 394, "SM6125" },
{ 402, "IPQ6018" },
+ { 403, "IPQ6028" },
+ { 421, "IPQ6000" },
+ { 422, "IPQ6010" },
{ 425, "SC7180" },
+ { 453, "IPQ6005" },
{ 455, "QRB5165" },
};
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index b70bbc38efc6..71b44c31b012 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -279,6 +279,11 @@ config ARCH_R8A774B1
help
This enables support for the Renesas RZ/G2N SoC.
+config ARCH_R9A07G044
+ bool "ARM64 Platform support for RZ/G2L"
+ help
+ This enables support for the Renesas RZ/G2L SoC variants.
+
endif # ARM64
config RST_RCAR
diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c
index 0f8eff4a641a..8310fce7714e 100644
--- a/drivers/soc/renesas/renesas-soc.c
+++ b/drivers/soc/renesas/renesas-soc.c
@@ -56,6 +56,10 @@ static const struct renesas_family fam_rzg2 __initconst __maybe_unused = {
.reg = 0xfff00044, /* PRR (Product Register) */
};
+static const struct renesas_family fam_rzg2l __initconst __maybe_unused = {
+ .name = "RZ/G2L",
+};
+
static const struct renesas_family fam_shmobile __initconst __maybe_unused = {
.name = "SH-Mobile",
.reg = 0xe600101c, /* CCCR (Common Chip Code Register) */
@@ -64,7 +68,7 @@ static const struct renesas_family fam_shmobile __initconst __maybe_unused = {
struct renesas_soc {
const struct renesas_family *family;
- u8 id;
+ u32 id;
};
static const struct renesas_soc soc_rz_a1h __initconst __maybe_unused = {
@@ -131,6 +135,11 @@ static const struct renesas_soc soc_rz_g2h __initconst __maybe_unused = {
.id = 0x4f,
};
+static const struct renesas_soc soc_rz_g2l __initconst __maybe_unused = {
+ .family = &fam_rzg2l,
+ .id = 0x841c447,
+};
+
static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = {
.family = &fam_rcar_gen1,
};
@@ -299,6 +308,9 @@ static const struct of_device_id renesas_socs[] __initconst = {
#ifdef CONFIG_ARCH_R8A779A0
{ .compatible = "renesas,r8a779a0", .data = &soc_rcar_v3u },
#endif
+#if defined(CONFIG_ARCH_R9A07G044)
+ { .compatible = "renesas,r9a07g044", .data = &soc_rz_g2l },
+#endif
#ifdef CONFIG_ARCH_SH73A0
{ .compatible = "renesas,sh73a0", .data = &soc_shmobile_ag5 },
#endif
@@ -348,6 +360,25 @@ static int __init renesas_soc_init(void)
goto done;
}
+ np = of_find_compatible_node(NULL, NULL, "renesas,r9a07g044-sysc");
+ if (np) {
+ chipid = of_iomap(np, 0);
+ of_node_put(np);
+
+ if (chipid) {
+ product = readl(chipid + 0x0a04);
+ iounmap(chipid);
+
+ if (soc->id && (product & 0xfffffff) != soc->id) {
+ pr_warn("SoC mismatch (product = 0x%x)\n",
+ product);
+ return -ENODEV;
+ }
+ }
+
+ goto done;
+ }
+
/* Try PRR first, then hardcoded fallback */
np = of_find_compatible_node(NULL, NULL, "renesas,prr");
if (np) {
diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c
index 54eb6cfc5d5b..0868b7d406fb 100644
--- a/drivers/soc/rockchip/pm_domains.c
+++ b/drivers/soc/rockchip/pm_domains.c
@@ -27,8 +27,10 @@
#include <dt-bindings/power/rk3366-power.h>
#include <dt-bindings/power/rk3368-power.h>
#include <dt-bindings/power/rk3399-power.h>
+#include <dt-bindings/power/rk3568-power.h>
struct rockchip_domain_info {
+ const char *name;
int pwr_mask;
int status_mask;
int req_mask;
@@ -85,8 +87,9 @@ struct rockchip_pmu {
#define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd)
-#define DOMAIN(pwr, status, req, idle, ack, wakeup) \
+#define DOMAIN(_name, pwr, status, req, idle, ack, wakeup) \
{ \
+ .name = _name, \
.pwr_mask = (pwr), \
.status_mask = (status), \
.req_mask = (req), \
@@ -95,8 +98,9 @@ struct rockchip_pmu {
.active_wakeup = (wakeup), \
}
-#define DOMAIN_M(pwr, status, req, idle, ack, wakeup) \
+#define DOMAIN_M(_name, pwr, status, req, idle, ack, wakeup) \
{ \
+ .name = _name, \
.pwr_w_mask = (pwr) << 16, \
.pwr_mask = (pwr), \
.status_mask = (status), \
@@ -107,8 +111,9 @@ struct rockchip_pmu {
.active_wakeup = wakeup, \
}
-#define DOMAIN_RK3036(req, ack, idle, wakeup) \
+#define DOMAIN_RK3036(_name, req, ack, idle, wakeup) \
{ \
+ .name = _name, \
.req_mask = (req), \
.req_w_mask = (req) << 16, \
.ack_mask = (ack), \
@@ -116,20 +121,23 @@ struct rockchip_pmu {
.active_wakeup = wakeup, \
}
-#define DOMAIN_PX30(pwr, status, req, wakeup) \
- DOMAIN_M(pwr, status, req, (req) << 16, req, wakeup)
+#define DOMAIN_PX30(name, pwr, status, req, wakeup) \
+ DOMAIN_M(name, pwr, status, req, (req) << 16, req, wakeup)
-#define DOMAIN_RK3288(pwr, status, req, wakeup) \
- DOMAIN(pwr, status, req, req, (req) << 16, wakeup)
+#define DOMAIN_RK3288(name, pwr, status, req, wakeup) \
+ DOMAIN(name, pwr, status, req, req, (req) << 16, wakeup)
-#define DOMAIN_RK3328(pwr, status, req, wakeup) \
- DOMAIN_M(pwr, pwr, req, (req) << 10, req, wakeup)
+#define DOMAIN_RK3328(name, pwr, status, req, wakeup) \
+ DOMAIN_M(name, pwr, pwr, req, (req) << 10, req, wakeup)
-#define DOMAIN_RK3368(pwr, status, req, wakeup) \
- DOMAIN(pwr, status, req, (req) << 16, req, wakeup)
+#define DOMAIN_RK3368(name, pwr, status, req, wakeup) \
+ DOMAIN(name, pwr, status, req, (req) << 16, req, wakeup)
-#define DOMAIN_RK3399(pwr, status, req, wakeup) \
- DOMAIN(pwr, status, req, req, req, wakeup)
+#define DOMAIN_RK3399(name, pwr, status, req, wakeup) \
+ DOMAIN(name, pwr, status, req, req, req, wakeup)
+
+#define DOMAIN_RK3568(name, pwr, req, wakeup) \
+ DOMAIN_M(name, pwr, pwr, req, req, req, wakeup)
static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
{
@@ -490,7 +498,10 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
goto err_unprepare_clocks;
}
- pd->genpd.name = node->name;
+ if (pd->info->name)
+ pd->genpd.name = pd->info->name;
+ else
+ pd->genpd.name = kbasename(node->full_name);
pd->genpd.power_off = rockchip_pd_power_off;
pd->genpd.power_on = rockchip_pd_power_on;
pd->genpd.attach_dev = rockchip_pd_attach_dev;
@@ -716,129 +727,141 @@ err_out:
}
static const struct rockchip_domain_info px30_pm_domains[] = {
- [PX30_PD_USB] = DOMAIN_PX30(BIT(5), BIT(5), BIT(10), false),
- [PX30_PD_SDCARD] = DOMAIN_PX30(BIT(8), BIT(8), BIT(9), false),
- [PX30_PD_GMAC] = DOMAIN_PX30(BIT(10), BIT(10), BIT(6), false),
- [PX30_PD_MMC_NAND] = DOMAIN_PX30(BIT(11), BIT(11), BIT(5), false),
- [PX30_PD_VPU] = DOMAIN_PX30(BIT(12), BIT(12), BIT(14), false),
- [PX30_PD_VO] = DOMAIN_PX30(BIT(13), BIT(13), BIT(7), false),
- [PX30_PD_VI] = DOMAIN_PX30(BIT(14), BIT(14), BIT(8), false),
- [PX30_PD_GPU] = DOMAIN_PX30(BIT(15), BIT(15), BIT(2), false),
+ [PX30_PD_USB] = DOMAIN_PX30("usb", BIT(5), BIT(5), BIT(10), false),
+ [PX30_PD_SDCARD] = DOMAIN_PX30("sdcard", BIT(8), BIT(8), BIT(9), false),
+ [PX30_PD_GMAC] = DOMAIN_PX30("gmac", BIT(10), BIT(10), BIT(6), false),
+ [PX30_PD_MMC_NAND] = DOMAIN_PX30("mmc_nand", BIT(11), BIT(11), BIT(5), false),
+ [PX30_PD_VPU] = DOMAIN_PX30("vpu", BIT(12), BIT(12), BIT(14), false),
+ [PX30_PD_VO] = DOMAIN_PX30("vo", BIT(13), BIT(13), BIT(7), false),
+ [PX30_PD_VI] = DOMAIN_PX30("vi", BIT(14), BIT(14), BIT(8), false),
+ [PX30_PD_GPU] = DOMAIN_PX30("gpu", BIT(15), BIT(15), BIT(2), false),
};
static const struct rockchip_domain_info rk3036_pm_domains[] = {
- [RK3036_PD_MSCH] = DOMAIN_RK3036(BIT(14), BIT(23), BIT(30), true),
- [RK3036_PD_CORE] = DOMAIN_RK3036(BIT(13), BIT(17), BIT(24), false),
- [RK3036_PD_PERI] = DOMAIN_RK3036(BIT(12), BIT(18), BIT(25), false),
- [RK3036_PD_VIO] = DOMAIN_RK3036(BIT(11), BIT(19), BIT(26), false),
- [RK3036_PD_VPU] = DOMAIN_RK3036(BIT(10), BIT(20), BIT(27), false),
- [RK3036_PD_GPU] = DOMAIN_RK3036(BIT(9), BIT(21), BIT(28), false),
- [RK3036_PD_SYS] = DOMAIN_RK3036(BIT(8), BIT(22), BIT(29), false),
+ [RK3036_PD_MSCH] = DOMAIN_RK3036("msch", BIT(14), BIT(23), BIT(30), true),
+ [RK3036_PD_CORE] = DOMAIN_RK3036("core", BIT(13), BIT(17), BIT(24), false),
+ [RK3036_PD_PERI] = DOMAIN_RK3036("peri", BIT(12), BIT(18), BIT(25), false),
+ [RK3036_PD_VIO] = DOMAIN_RK3036("vio", BIT(11), BIT(19), BIT(26), false),
+ [RK3036_PD_VPU] = DOMAIN_RK3036("vpu", BIT(10), BIT(20), BIT(27), false),
+ [RK3036_PD_GPU] = DOMAIN_RK3036("gpu", BIT(9), BIT(21), BIT(28), false),
+ [RK3036_PD_SYS] = DOMAIN_RK3036("sys", BIT(8), BIT(22), BIT(29), false),
};
static const struct rockchip_domain_info rk3066_pm_domains[] = {
- [RK3066_PD_GPU] = DOMAIN(BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),
- [RK3066_PD_VIDEO] = DOMAIN(BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),
- [RK3066_PD_VIO] = DOMAIN(BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),
- [RK3066_PD_PERI] = DOMAIN(BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),
- [RK3066_PD_CPU] = DOMAIN(0, BIT(5), BIT(1), BIT(26), BIT(31), false),
+ [RK3066_PD_GPU] = DOMAIN("gpu", BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),
+ [RK3066_PD_VIDEO] = DOMAIN("video", BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),
+ [RK3066_PD_VIO] = DOMAIN("vio", BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),
+ [RK3066_PD_PERI] = DOMAIN("peri", BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),
+ [RK3066_PD_CPU] = DOMAIN("cpu", 0, BIT(5), BIT(1), BIT(26), BIT(31), false),
};
static const struct rockchip_domain_info rk3128_pm_domains[] = {
- [RK3128_PD_CORE] = DOMAIN_RK3288(BIT(0), BIT(0), BIT(4), false),
- [RK3128_PD_MSCH] = DOMAIN_RK3288(0, 0, BIT(6), true),
- [RK3128_PD_VIO] = DOMAIN_RK3288(BIT(3), BIT(3), BIT(2), false),
- [RK3128_PD_VIDEO] = DOMAIN_RK3288(BIT(2), BIT(2), BIT(1), false),
- [RK3128_PD_GPU] = DOMAIN_RK3288(BIT(1), BIT(1), BIT(3), false),
+ [RK3128_PD_CORE] = DOMAIN_RK3288("core", BIT(0), BIT(0), BIT(4), false),
+ [RK3128_PD_MSCH] = DOMAIN_RK3288("msch", 0, 0, BIT(6), true),
+ [RK3128_PD_VIO] = DOMAIN_RK3288("vio", BIT(3), BIT(3), BIT(2), false),
+ [RK3128_PD_VIDEO] = DOMAIN_RK3288("video", BIT(2), BIT(2), BIT(1), false),
+ [RK3128_PD_GPU] = DOMAIN_RK3288("gpu", BIT(1), BIT(1), BIT(3), false),
};
static const struct rockchip_domain_info rk3188_pm_domains[] = {
- [RK3188_PD_GPU] = DOMAIN(BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),
- [RK3188_PD_VIDEO] = DOMAIN(BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),
- [RK3188_PD_VIO] = DOMAIN(BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),
- [RK3188_PD_PERI] = DOMAIN(BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),
- [RK3188_PD_CPU] = DOMAIN(BIT(5), BIT(5), BIT(1), BIT(26), BIT(31), false),
+ [RK3188_PD_GPU] = DOMAIN("gpu", BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),
+ [RK3188_PD_VIDEO] = DOMAIN("video", BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),
+ [RK3188_PD_VIO] = DOMAIN("vio", BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),
+ [RK3188_PD_PERI] = DOMAIN("peri", BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),
+ [RK3188_PD_CPU] = DOMAIN("cpu", BIT(5), BIT(5), BIT(1), BIT(26), BIT(31), false),
};
static const struct rockchip_domain_info rk3228_pm_domains[] = {
- [RK3228_PD_CORE] = DOMAIN_RK3036(BIT(0), BIT(0), BIT(16), true),
- [RK3228_PD_MSCH] = DOMAIN_RK3036(BIT(1), BIT(1), BIT(17), true),
- [RK3228_PD_BUS] = DOMAIN_RK3036(BIT(2), BIT(2), BIT(18), true),
- [RK3228_PD_SYS] = DOMAIN_RK3036(BIT(3), BIT(3), BIT(19), true),
- [RK3228_PD_VIO] = DOMAIN_RK3036(BIT(4), BIT(4), BIT(20), false),
- [RK3228_PD_VOP] = DOMAIN_RK3036(BIT(5), BIT(5), BIT(21), false),
- [RK3228_PD_VPU] = DOMAIN_RK3036(BIT(6), BIT(6), BIT(22), false),
- [RK3228_PD_RKVDEC] = DOMAIN_RK3036(BIT(7), BIT(7), BIT(23), false),
- [RK3228_PD_GPU] = DOMAIN_RK3036(BIT(8), BIT(8), BIT(24), false),
- [RK3228_PD_PERI] = DOMAIN_RK3036(BIT(9), BIT(9), BIT(25), true),
- [RK3228_PD_GMAC] = DOMAIN_RK3036(BIT(10), BIT(10), BIT(26), false),
+ [RK3228_PD_CORE] = DOMAIN_RK3036("core", BIT(0), BIT(0), BIT(16), true),
+ [RK3228_PD_MSCH] = DOMAIN_RK3036("msch", BIT(1), BIT(1), BIT(17), true),
+ [RK3228_PD_BUS] = DOMAIN_RK3036("bus", BIT(2), BIT(2), BIT(18), true),
+ [RK3228_PD_SYS] = DOMAIN_RK3036("sys", BIT(3), BIT(3), BIT(19), true),
+ [RK3228_PD_VIO] = DOMAIN_RK3036("vio", BIT(4), BIT(4), BIT(20), false),
+ [RK3228_PD_VOP] = DOMAIN_RK3036("vop", BIT(5), BIT(5), BIT(21), false),
+ [RK3228_PD_VPU] = DOMAIN_RK3036("vpu", BIT(6), BIT(6), BIT(22), false),
+ [RK3228_PD_RKVDEC] = DOMAIN_RK3036("vdec", BIT(7), BIT(7), BIT(23), false),
+ [RK3228_PD_GPU] = DOMAIN_RK3036("gpu", BIT(8), BIT(8), BIT(24), false),
+ [RK3228_PD_PERI] = DOMAIN_RK3036("peri", BIT(9), BIT(9), BIT(25), true),
+ [RK3228_PD_GMAC] = DOMAIN_RK3036("gmac", BIT(10), BIT(10), BIT(26), false),
};
static const struct rockchip_domain_info rk3288_pm_domains[] = {
- [RK3288_PD_VIO] = DOMAIN_RK3288(BIT(7), BIT(7), BIT(4), false),
- [RK3288_PD_HEVC] = DOMAIN_RK3288(BIT(14), BIT(10), BIT(9), false),
- [RK3288_PD_VIDEO] = DOMAIN_RK3288(BIT(8), BIT(8), BIT(3), false),
- [RK3288_PD_GPU] = DOMAIN_RK3288(BIT(9), BIT(9), BIT(2), false),
+ [RK3288_PD_VIO] = DOMAIN_RK3288("vio", BIT(7), BIT(7), BIT(4), false),
+ [RK3288_PD_HEVC] = DOMAIN_RK3288("hevc", BIT(14), BIT(10), BIT(9), false),
+ [RK3288_PD_VIDEO] = DOMAIN_RK3288("video", BIT(8), BIT(8), BIT(3), false),
+ [RK3288_PD_GPU] = DOMAIN_RK3288("gpu", BIT(9), BIT(9), BIT(2), false),
};
static const struct rockchip_domain_info rk3328_pm_domains[] = {
- [RK3328_PD_CORE] = DOMAIN_RK3328(0, BIT(0), BIT(0), false),
- [RK3328_PD_GPU] = DOMAIN_RK3328(0, BIT(1), BIT(1), false),
- [RK3328_PD_BUS] = DOMAIN_RK3328(0, BIT(2), BIT(2), true),
- [RK3328_PD_MSCH] = DOMAIN_RK3328(0, BIT(3), BIT(3), true),
- [RK3328_PD_PERI] = DOMAIN_RK3328(0, BIT(4), BIT(4), true),
- [RK3328_PD_VIDEO] = DOMAIN_RK3328(0, BIT(5), BIT(5), false),
- [RK3328_PD_HEVC] = DOMAIN_RK3328(0, BIT(6), BIT(6), false),
- [RK3328_PD_VIO] = DOMAIN_RK3328(0, BIT(8), BIT(8), false),
- [RK3328_PD_VPU] = DOMAIN_RK3328(0, BIT(9), BIT(9), false),
+ [RK3328_PD_CORE] = DOMAIN_RK3328("core", 0, BIT(0), BIT(0), false),
+ [RK3328_PD_GPU] = DOMAIN_RK3328("gpu", 0, BIT(1), BIT(1), false),
+ [RK3328_PD_BUS] = DOMAIN_RK3328("bus", 0, BIT(2), BIT(2), true),
+ [RK3328_PD_MSCH] = DOMAIN_RK3328("msch", 0, BIT(3), BIT(3), true),
+ [RK3328_PD_PERI] = DOMAIN_RK3328("peri", 0, BIT(4), BIT(4), true),
+ [RK3328_PD_VIDEO] = DOMAIN_RK3328("video", 0, BIT(5), BIT(5), false),
+ [RK3328_PD_HEVC] = DOMAIN_RK3328("hevc", 0, BIT(6), BIT(6), false),
+ [RK3328_PD_VIO] = DOMAIN_RK3328("vio", 0, BIT(8), BIT(8), false),
+ [RK3328_PD_VPU] = DOMAIN_RK3328("vpu", 0, BIT(9), BIT(9), false),
};
static const struct rockchip_domain_info rk3366_pm_domains[] = {
- [RK3366_PD_PERI] = DOMAIN_RK3368(BIT(10), BIT(10), BIT(6), true),
- [RK3366_PD_VIO] = DOMAIN_RK3368(BIT(14), BIT(14), BIT(8), false),
- [RK3366_PD_VIDEO] = DOMAIN_RK3368(BIT(13), BIT(13), BIT(7), false),
- [RK3366_PD_RKVDEC] = DOMAIN_RK3368(BIT(11), BIT(11), BIT(7), false),
- [RK3366_PD_WIFIBT] = DOMAIN_RK3368(BIT(8), BIT(8), BIT(9), false),
- [RK3366_PD_VPU] = DOMAIN_RK3368(BIT(12), BIT(12), BIT(7), false),
- [RK3366_PD_GPU] = DOMAIN_RK3368(BIT(15), BIT(15), BIT(2), false),
+ [RK3366_PD_PERI] = DOMAIN_RK3368("peri", BIT(10), BIT(10), BIT(6), true),
+ [RK3366_PD_VIO] = DOMAIN_RK3368("vio", BIT(14), BIT(14), BIT(8), false),
+ [RK3366_PD_VIDEO] = DOMAIN_RK3368("video", BIT(13), BIT(13), BIT(7), false),
+ [RK3366_PD_RKVDEC] = DOMAIN_RK3368("vdec", BIT(11), BIT(11), BIT(7), false),
+ [RK3366_PD_WIFIBT] = DOMAIN_RK3368("wifibt", BIT(8), BIT(8), BIT(9), false),
+ [RK3366_PD_VPU] = DOMAIN_RK3368("vpu", BIT(12), BIT(12), BIT(7), false),
+ [RK3366_PD_GPU] = DOMAIN_RK3368("gpu", BIT(15), BIT(15), BIT(2), false),
};
static const struct rockchip_domain_info rk3368_pm_domains[] = {
- [RK3368_PD_PERI] = DOMAIN_RK3368(BIT(13), BIT(12), BIT(6), true),
- [RK3368_PD_VIO] = DOMAIN_RK3368(BIT(15), BIT(14), BIT(8), false),
- [RK3368_PD_VIDEO] = DOMAIN_RK3368(BIT(14), BIT(13), BIT(7), false),
- [RK3368_PD_GPU_0] = DOMAIN_RK3368(BIT(16), BIT(15), BIT(2), false),
- [RK3368_PD_GPU_1] = DOMAIN_RK3368(BIT(17), BIT(16), BIT(2), false),
+ [RK3368_PD_PERI] = DOMAIN_RK3368("peri", BIT(13), BIT(12), BIT(6), true),
+ [RK3368_PD_VIO] = DOMAIN_RK3368("vio", BIT(15), BIT(14), BIT(8), false),
+ [RK3368_PD_VIDEO] = DOMAIN_RK3368("video", BIT(14), BIT(13), BIT(7), false),
+ [RK3368_PD_GPU_0] = DOMAIN_RK3368("gpu_0", BIT(16), BIT(15), BIT(2), false),
+ [RK3368_PD_GPU_1] = DOMAIN_RK3368("gpu_1", BIT(17), BIT(16), BIT(2), false),
};
static const struct rockchip_domain_info rk3399_pm_domains[] = {
- [RK3399_PD_TCPD0] = DOMAIN_RK3399(BIT(8), BIT(8), 0, false),
- [RK3399_PD_TCPD1] = DOMAIN_RK3399(BIT(9), BIT(9), 0, false),
- [RK3399_PD_CCI] = DOMAIN_RK3399(BIT(10), BIT(10), 0, true),
- [RK3399_PD_CCI0] = DOMAIN_RK3399(0, 0, BIT(15), true),
- [RK3399_PD_CCI1] = DOMAIN_RK3399(0, 0, BIT(16), true),
- [RK3399_PD_PERILP] = DOMAIN_RK3399(BIT(11), BIT(11), BIT(1), true),
- [RK3399_PD_PERIHP] = DOMAIN_RK3399(BIT(12), BIT(12), BIT(2), true),
- [RK3399_PD_CENTER] = DOMAIN_RK3399(BIT(13), BIT(13), BIT(14), true),
- [RK3399_PD_VIO] = DOMAIN_RK3399(BIT(14), BIT(14), BIT(17), false),
- [RK3399_PD_GPU] = DOMAIN_RK3399(BIT(15), BIT(15), BIT(0), false),
- [RK3399_PD_VCODEC] = DOMAIN_RK3399(BIT(16), BIT(16), BIT(3), false),
- [RK3399_PD_VDU] = DOMAIN_RK3399(BIT(17), BIT(17), BIT(4), false),
- [RK3399_PD_RGA] = DOMAIN_RK3399(BIT(18), BIT(18), BIT(5), false),
- [RK3399_PD_IEP] = DOMAIN_RK3399(BIT(19), BIT(19), BIT(6), false),
- [RK3399_PD_VO] = DOMAIN_RK3399(BIT(20), BIT(20), 0, false),
- [RK3399_PD_VOPB] = DOMAIN_RK3399(0, 0, BIT(7), false),
- [RK3399_PD_VOPL] = DOMAIN_RK3399(0, 0, BIT(8), false),
- [RK3399_PD_ISP0] = DOMAIN_RK3399(BIT(22), BIT(22), BIT(9), false),
- [RK3399_PD_ISP1] = DOMAIN_RK3399(BIT(23), BIT(23), BIT(10), false),
- [RK3399_PD_HDCP] = DOMAIN_RK3399(BIT(24), BIT(24), BIT(11), false),
- [RK3399_PD_GMAC] = DOMAIN_RK3399(BIT(25), BIT(25), BIT(23), true),
- [RK3399_PD_EMMC] = DOMAIN_RK3399(BIT(26), BIT(26), BIT(24), true),
- [RK3399_PD_USB3] = DOMAIN_RK3399(BIT(27), BIT(27), BIT(12), true),
- [RK3399_PD_EDP] = DOMAIN_RK3399(BIT(28), BIT(28), BIT(22), false),
- [RK3399_PD_GIC] = DOMAIN_RK3399(BIT(29), BIT(29), BIT(27), true),
- [RK3399_PD_SD] = DOMAIN_RK3399(BIT(30), BIT(30), BIT(28), true),
- [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399(BIT(31), BIT(31), BIT(29), true),
+ [RK3399_PD_TCPD0] = DOMAIN_RK3399("tcpd0", BIT(8), BIT(8), 0, false),
+ [RK3399_PD_TCPD1] = DOMAIN_RK3399("tcpd1", BIT(9), BIT(9), 0, false),
+ [RK3399_PD_CCI] = DOMAIN_RK3399("cci", BIT(10), BIT(10), 0, true),
+ [RK3399_PD_CCI0] = DOMAIN_RK3399("cci0", 0, 0, BIT(15), true),
+ [RK3399_PD_CCI1] = DOMAIN_RK3399("cci1", 0, 0, BIT(16), true),
+ [RK3399_PD_PERILP] = DOMAIN_RK3399("perilp", BIT(11), BIT(11), BIT(1), true),
+ [RK3399_PD_PERIHP] = DOMAIN_RK3399("perihp", BIT(12), BIT(12), BIT(2), true),
+ [RK3399_PD_CENTER] = DOMAIN_RK3399("center", BIT(13), BIT(13), BIT(14), true),
+ [RK3399_PD_VIO] = DOMAIN_RK3399("vio", BIT(14), BIT(14), BIT(17), false),
+ [RK3399_PD_GPU] = DOMAIN_RK3399("gpu", BIT(15), BIT(15), BIT(0), false),
+ [RK3399_PD_VCODEC] = DOMAIN_RK3399("vcodec", BIT(16), BIT(16), BIT(3), false),
+ [RK3399_PD_VDU] = DOMAIN_RK3399("vdu", BIT(17), BIT(17), BIT(4), false),
+ [RK3399_PD_RGA] = DOMAIN_RK3399("rga", BIT(18), BIT(18), BIT(5), false),
+ [RK3399_PD_IEP] = DOMAIN_RK3399("iep", BIT(19), BIT(19), BIT(6), false),
+ [RK3399_PD_VO] = DOMAIN_RK3399("vo", BIT(20), BIT(20), 0, false),
+ [RK3399_PD_VOPB] = DOMAIN_RK3399("vopb", 0, 0, BIT(7), false),
+ [RK3399_PD_VOPL] = DOMAIN_RK3399("vopl", 0, 0, BIT(8), false),
+ [RK3399_PD_ISP0] = DOMAIN_RK3399("isp0", BIT(22), BIT(22), BIT(9), false),
+ [RK3399_PD_ISP1] = DOMAIN_RK3399("isp1", BIT(23), BIT(23), BIT(10), false),
+ [RK3399_PD_HDCP] = DOMAIN_RK3399("hdcp", BIT(24), BIT(24), BIT(11), false),
+ [RK3399_PD_GMAC] = DOMAIN_RK3399("gmac", BIT(25), BIT(25), BIT(23), true),
+ [RK3399_PD_EMMC] = DOMAIN_RK3399("emmc", BIT(26), BIT(26), BIT(24), true),
+ [RK3399_PD_USB3] = DOMAIN_RK3399("usb3", BIT(27), BIT(27), BIT(12), true),
+ [RK3399_PD_EDP] = DOMAIN_RK3399("edp", BIT(28), BIT(28), BIT(22), false),
+ [RK3399_PD_GIC] = DOMAIN_RK3399("gic", BIT(29), BIT(29), BIT(27), true),
+ [RK3399_PD_SD] = DOMAIN_RK3399("sd", BIT(30), BIT(30), BIT(28), true),
+ [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399("sdioaudio", BIT(31), BIT(31), BIT(29), true),
+};
+
+static const struct rockchip_domain_info rk3568_pm_domains[] = {
+ [RK3568_PD_NPU] = DOMAIN_RK3568("npu", BIT(1), BIT(2), false),
+ [RK3568_PD_GPU] = DOMAIN_RK3568("gpu", BIT(0), BIT(1), false),
+ [RK3568_PD_VI] = DOMAIN_RK3568("vi", BIT(6), BIT(3), false),
+ [RK3568_PD_VO] = DOMAIN_RK3568("vo", BIT(7), BIT(4), false),
+ [RK3568_PD_RGA] = DOMAIN_RK3568("rga", BIT(5), BIT(5), false),
+ [RK3568_PD_VPU] = DOMAIN_RK3568("vpu", BIT(2), BIT(6), false),
+ [RK3568_PD_RKVDEC] = DOMAIN_RK3568("vdec", BIT(4), BIT(8), false),
+ [RK3568_PD_RKVENC] = DOMAIN_RK3568("venc", BIT(3), BIT(7), false),
+ [RK3568_PD_PIPE] = DOMAIN_RK3568("pipe", BIT(8), BIT(11), false),
};
static const struct rockchip_pmu_info px30_pmu = {
@@ -976,6 +999,17 @@ static const struct rockchip_pmu_info rk3399_pmu = {
.domain_info = rk3399_pm_domains,
};
+static const struct rockchip_pmu_info rk3568_pmu = {
+ .pwr_offset = 0xa0,
+ .status_offset = 0x98,
+ .req_offset = 0x50,
+ .idle_offset = 0x68,
+ .ack_offset = 0x60,
+
+ .num_domains = ARRAY_SIZE(rk3568_pm_domains),
+ .domain_info = rk3568_pm_domains,
+};
+
static const struct of_device_id rockchip_pm_domain_dt_match[] = {
{
.compatible = "rockchip,px30-power-controller",
@@ -1021,6 +1055,10 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = {
.compatible = "rockchip,rk3399-power-controller",
.data = (void *)&rk3399_pmu,
},
+ {
+ .compatible = "rockchip,rk3568-power-controller",
+ .data = (void *)&rk3568_pmu,
+ },
{ /* sentinel */ },
};
diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig
index 976dee036470..20ace654553a 100644
--- a/drivers/soc/tegra/Kconfig
+++ b/drivers/soc/tegra/Kconfig
@@ -144,6 +144,8 @@ config SOC_TEGRA_FLOWCTRL
config SOC_TEGRA_PMC
bool
select GENERIC_PINCONF
+ select PM_OPP
+ select PM_GENERIC_DOMAINS
config SOC_TEGRA_POWERGATE_BPMP
def_bool y
diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c
index 3dc54f59cafe..cd33e99249c3 100644
--- a/drivers/soc/tegra/common.c
+++ b/drivers/soc/tegra/common.c
@@ -3,9 +3,16 @@
* Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
*/
+#define dev_fmt(fmt) "tegra-soc: " fmt
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/export.h>
#include <linux/of.h>
+#include <linux/pm_opp.h>
#include <soc/tegra/common.h>
+#include <soc/tegra/fuse.h>
static const struct of_device_id tegra_machine_match[] = {
{ .compatible = "nvidia,tegra20", },
@@ -31,3 +38,93 @@ bool soc_is_tegra(void)
return match != NULL;
}
+
+static int tegra_core_dev_init_opp_state(struct device *dev)
+{
+ unsigned long rate;
+ struct clk *clk;
+ int err;
+
+ clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(dev, "failed to get clk: %pe\n", clk);
+ return PTR_ERR(clk);
+ }
+
+ rate = clk_get_rate(clk);
+ if (!rate) {
+ dev_err(dev, "failed to get clk rate\n");
+ return -EINVAL;
+ }
+
+ /* first dummy rate-setting initializes voltage vote */
+ err = dev_pm_opp_set_rate(dev, rate);
+ if (err) {
+ dev_err(dev, "failed to initialize OPP clock: %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * devm_tegra_core_dev_init_opp_table() - initialize OPP table
+ * @dev: device for which OPP table is initialized
+ * @params: pointer to the OPP table configuration
+ *
+ * This function will initialize OPP table and sync OPP state of a Tegra SoC
+ * core device.
+ *
+ * Return: 0 on success or errorno.
+ */
+int devm_tegra_core_dev_init_opp_table(struct device *dev,
+ struct tegra_core_opp_params *params)
+{
+ u32 hw_version;
+ int err;
+
+ err = devm_pm_opp_set_clkname(dev, NULL);
+ if (err) {
+ dev_err(dev, "failed to set OPP clk: %d\n", err);
+ return err;
+ }
+
+ /* Tegra114+ doesn't support OPP yet */
+ if (!of_machine_is_compatible("nvidia,tegra20") &&
+ !of_machine_is_compatible("nvidia,tegra30"))
+ return -ENODEV;
+
+ if (of_machine_is_compatible("nvidia,tegra20"))
+ hw_version = BIT(tegra_sku_info.soc_process_id);
+ else
+ hw_version = BIT(tegra_sku_info.soc_speedo_id);
+
+ err = devm_pm_opp_set_supported_hw(dev, &hw_version, 1);
+ if (err) {
+ dev_err(dev, "failed to set OPP supported HW: %d\n", err);
+ return err;
+ }
+
+ /*
+ * Older device-trees have an empty OPP table, we will get
+ * -ENODEV from devm_pm_opp_of_add_table() in this case.
+ */
+ err = devm_pm_opp_of_add_table(dev);
+ if (err) {
+ if (err == -ENODEV)
+ dev_err_once(dev, "OPP table not found, please update device-tree\n");
+ else
+ dev_err(dev, "failed to add OPP table: %d\n", err);
+
+ return err;
+ }
+
+ if (params->init_state) {
+ err = tegra_core_dev_init_opp_state(dev);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devm_tegra_core_dev_init_opp_table);
diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
index 94b60a692b51..3d9da3d359da 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -489,10 +489,8 @@ static int __init tegra_init_fuse(void)
size_t size = sizeof(*fuse->lookups) * fuse->soc->num_lookups;
fuse->lookups = kmemdup(fuse->soc->lookups, size, GFP_KERNEL);
- if (!fuse->lookups)
- return -ENOMEM;
-
- nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups);
+ if (fuse->lookups)
+ nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups);
}
return 0;
diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c
index 9ea7f0168457..c1aa7815bd6e 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra30.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra30.c
@@ -37,7 +37,8 @@
defined(CONFIG_ARCH_TEGRA_132_SOC) || \
defined(CONFIG_ARCH_TEGRA_210_SOC) || \
defined(CONFIG_ARCH_TEGRA_186_SOC) || \
- defined(CONFIG_ARCH_TEGRA_194_SOC)
+ defined(CONFIG_ARCH_TEGRA_194_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_234_SOC)
static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset)
{
if (WARN_ON(!fuse->base))
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 8e3b78bb2ac2..ea62f84d1c8b 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -38,6 +38,7 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
+#include <linux/pm_opp.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/reset.h>
@@ -428,6 +429,9 @@ struct tegra_pmc {
struct irq_chip irq;
struct notifier_block clk_nb;
+
+ bool core_domain_state_synced;
+ bool core_domain_registered;
};
static struct tegra_pmc *pmc = &(struct tegra_pmc) {
@@ -743,11 +747,6 @@ out:
return err;
}
-int __weak tegra210_clk_handle_mbist_war(unsigned int id)
-{
- return 0;
-}
-
static int tegra_powergate_power_up(struct tegra_powergate *pg,
bool disable_clocks)
{
@@ -1302,12 +1301,107 @@ free_mem:
return err;
}
+bool tegra_pmc_core_domain_state_synced(void)
+{
+ return pmc->core_domain_state_synced;
+}
+
+static int
+tegra_pmc_core_pd_set_performance_state(struct generic_pm_domain *genpd,
+ unsigned int level)
+{
+ struct dev_pm_opp *opp;
+ int err;
+
+ opp = dev_pm_opp_find_level_ceil(&genpd->dev, &level);
+ if (IS_ERR(opp)) {
+ dev_err(&genpd->dev, "failed to find OPP for level %u: %pe\n",
+ level, opp);
+ return PTR_ERR(opp);
+ }
+
+ mutex_lock(&pmc->powergates_lock);
+ err = dev_pm_opp_set_opp(pmc->dev, opp);
+ mutex_unlock(&pmc->powergates_lock);
+
+ dev_pm_opp_put(opp);
+
+ if (err) {
+ dev_err(&genpd->dev, "failed to set voltage to %duV: %d\n",
+ level, err);
+ return err;
+ }
+
+ return 0;
+}
+
+static unsigned int
+tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd,
+ struct dev_pm_opp *opp)
+{
+ return dev_pm_opp_get_level(opp);
+}
+
+static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
+{
+ struct generic_pm_domain *genpd;
+ const char *rname = "core";
+ int err;
+
+ genpd = devm_kzalloc(pmc->dev, sizeof(*genpd), GFP_KERNEL);
+ if (!genpd)
+ return -ENOMEM;
+
+ genpd->name = np->name;
+ genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state;
+ genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state;
+
+ err = devm_pm_opp_set_regulators(pmc->dev, &rname, 1);
+ if (err)
+ return dev_err_probe(pmc->dev, err,
+ "failed to set core OPP regulator\n");
+
+ err = pm_genpd_init(genpd, NULL, false);
+ if (err) {
+ dev_err(pmc->dev, "failed to init core genpd: %d\n", err);
+ return err;
+ }
+
+ err = of_genpd_add_provider_simple(np, genpd);
+ if (err) {
+ dev_err(pmc->dev, "failed to add core genpd: %d\n", err);
+ goto remove_genpd;
+ }
+
+ pmc->core_domain_registered = true;
+
+ return 0;
+
+remove_genpd:
+ pm_genpd_remove(genpd);
+
+ return err;
+}
+
static int tegra_powergate_init(struct tegra_pmc *pmc,
struct device_node *parent)
{
+ struct of_phandle_args child_args, parent_args;
struct device_node *np, *child;
int err = 0;
+ /*
+ * Core power domain is the parent of powergate domains, hence it
+ * should be registered first.
+ */
+ np = of_get_child_by_name(parent, "core-domain");
+ if (np) {
+ err = tegra_pmc_core_pd_add(pmc, np);
+ of_node_put(np);
+ if (err)
+ return err;
+ }
+
np = of_get_child_by_name(parent, "powergates");
if (!np)
return 0;
@@ -1318,6 +1412,21 @@ static int tegra_powergate_init(struct tegra_pmc *pmc,
of_node_put(child);
break;
}
+
+ if (of_parse_phandle_with_args(child, "power-domains",
+ "#power-domain-cells",
+ 0, &parent_args))
+ continue;
+
+ child_args.np = child;
+ child_args.args_count = 0;
+
+ err = of_genpd_add_subdomain(&parent_args, &child_args);
+ of_node_put(parent_args.np);
+ if (err) {
+ of_node_put(child);
+ break;
+ }
}
of_node_put(np);
@@ -1361,6 +1470,12 @@ static void tegra_powergate_remove_all(struct device_node *parent)
}
of_node_put(np);
+
+ np = of_get_child_by_name(parent, "core-domain");
+ if (np) {
+ of_genpd_del_provider(np);
+ of_genpd_remove_last(np);
+ }
}
static const struct tegra_io_pad_soc *
@@ -3672,6 +3787,29 @@ static const struct of_device_id tegra_pmc_match[] = {
{ }
};
+static void tegra_pmc_sync_state(struct device *dev)
+{
+ int err;
+
+ /*
+ * Older device-trees don't have core PD, and thus, there are
+ * no dependencies that will block the state syncing. We shouldn't
+ * mark the domain as synced in this case.
+ */
+ if (!pmc->core_domain_registered)
+ return;
+
+ pmc->core_domain_state_synced = true;
+
+ /* this is a no-op if core regulator isn't used */
+ mutex_lock(&pmc->powergates_lock);
+ err = dev_pm_opp_sync_regulators(dev);
+ mutex_unlock(&pmc->powergates_lock);
+
+ if (err)
+ dev_err(dev, "failed to sync regulators: %d\n", err);
+}
+
static struct platform_driver tegra_pmc_driver = {
.driver = {
.name = "tegra-pmc",
@@ -3680,6 +3818,7 @@ static struct platform_driver tegra_pmc_driver = {
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
.pm = &tegra_pmc_pm_ops,
#endif
+ .sync_state = tegra_pmc_sync_state,
},
.probe = tegra_pmc_probe,
};
diff --git a/drivers/soc/tegra/regulators-tegra20.c b/drivers/soc/tegra/regulators-tegra20.c
index 367a71a3cd10..b8ce9fd0650d 100644
--- a/drivers/soc/tegra/regulators-tegra20.c
+++ b/drivers/soc/tegra/regulators-tegra20.c
@@ -12,16 +12,22 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
+#include <linux/reboot.h>
#include <linux/regulator/coupler.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <soc/tegra/pmc.h>
+
struct tegra_regulator_coupler {
struct regulator_coupler coupler;
struct regulator_dev *core_rdev;
struct regulator_dev *cpu_rdev;
struct regulator_dev *rtc_rdev;
- int core_min_uV;
+ struct notifier_block reboot_notifier;
+ int core_min_uV, cpu_min_uV;
+ bool sys_reboot_mode_req;
+ bool sys_reboot_mode;
};
static inline struct tegra_regulator_coupler *
@@ -38,6 +44,21 @@ static int tegra20_core_limit(struct tegra_regulator_coupler *tegra,
int core_cur_uV;
int err;
+ /*
+ * Tegra20 SoC has critical DVFS-capable devices that are
+ * permanently-active or active at a boot time, like EMC
+ * (DRAM controller) or Display controller for example.
+ *
+ * The voltage of a CORE SoC power domain shall not be dropped below
+ * a minimum level, which is determined by device's clock rate.
+ * This means that we can't fully allow CORE voltage scaling until
+ * the state of all DVFS-critical CORE devices is synced.
+ */
+ if (tegra_pmc_core_domain_state_synced() && !tegra->sys_reboot_mode) {
+ pr_info_once("voltage state synced\n");
+ return 0;
+ }
+
if (tegra->core_min_uV > 0)
return tegra->core_min_uV;
@@ -58,7 +79,7 @@ static int tegra20_core_limit(struct tegra_regulator_coupler *tegra,
*/
tegra->core_min_uV = core_max_uV;
- pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV);
+ pr_info("core voltage initialized to %duV\n", tegra->core_min_uV);
return tegra->core_min_uV;
}
@@ -242,6 +263,10 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra,
if (cpu_uV < 0)
return cpu_uV;
+ /* store boot voltage level */
+ if (!tegra->cpu_min_uV)
+ tegra->cpu_min_uV = cpu_uV;
+
/*
* CPU's regulator may not have any consumers, hence the voltage
* must not be changed in that case because CPU simply won't
@@ -250,6 +275,10 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra,
if (!cpu_min_uV_consumers)
cpu_min_uV = cpu_uV;
+ /* restore boot voltage level */
+ if (tegra->sys_reboot_mode)
+ cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV);
+
if (cpu_min_uV > cpu_uV) {
err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
cpu_uV, cpu_min_uV);
@@ -290,6 +319,8 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler,
return -EINVAL;
}
+ tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req);
+
if (rdev == cpu_rdev)
return tegra20_cpu_voltage_update(tegra, cpu_rdev,
core_rdev, rtc_rdev);
@@ -303,6 +334,51 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler,
return -EPERM;
}
+static int tegra20_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra,
+ bool sys_reboot_mode)
+{
+ int err;
+
+ if (!tegra->core_rdev || !tegra->rtc_rdev || !tegra->cpu_rdev)
+ return 0;
+
+ WRITE_ONCE(tegra->sys_reboot_mode_req, true);
+
+ /*
+ * Some devices use CPU soft-reboot method and in this case we
+ * should ensure that voltages are sane for the reboot by restoring
+ * the minimum boot levels.
+ */
+ err = regulator_sync_voltage_rdev(tegra->cpu_rdev);
+ if (err)
+ return err;
+
+ err = regulator_sync_voltage_rdev(tegra->core_rdev);
+ if (err)
+ return err;
+
+ WRITE_ONCE(tegra->sys_reboot_mode_req, sys_reboot_mode);
+
+ return 0;
+}
+
+static int tegra20_regulator_reboot(struct notifier_block *notifier,
+ unsigned long event, void *cmd)
+{
+ struct tegra_regulator_coupler *tegra;
+ int ret;
+
+ if (event != SYS_RESTART)
+ return NOTIFY_DONE;
+
+ tegra = container_of(notifier, struct tegra_regulator_coupler,
+ reboot_notifier);
+
+ ret = tegra20_regulator_prepare_reboot(tegra, true);
+
+ return notifier_from_errno(ret);
+}
+
static int tegra20_regulator_attach(struct regulator_coupler *coupler,
struct regulator_dev *rdev)
{
@@ -335,6 +411,14 @@ static int tegra20_regulator_detach(struct regulator_coupler *coupler,
{
struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
+ /*
+ * We don't expect regulators to be decoupled during reboot,
+ * this may race with the reboot handler and shouldn't ever
+ * happen in practice.
+ */
+ if (WARN_ON_ONCE(system_state > SYSTEM_RUNNING))
+ return -EPERM;
+
if (tegra->core_rdev == rdev) {
tegra->core_rdev = NULL;
return 0;
@@ -359,13 +443,19 @@ static struct tegra_regulator_coupler tegra20_coupler = {
.detach_regulator = tegra20_regulator_detach,
.balance_voltage = tegra20_regulator_balance_voltage,
},
+ .reboot_notifier.notifier_call = tegra20_regulator_reboot,
};
static int __init tegra_regulator_coupler_init(void)
{
+ int err;
+
if (!of_machine_is_compatible("nvidia,tegra20"))
return 0;
+ err = register_reboot_notifier(&tegra20_coupler.reboot_notifier);
+ WARN_ON(err);
+
return regulator_coupler_register(&tegra20_coupler.coupler);
}
arch_initcall(tegra_regulator_coupler_init);
diff --git a/drivers/soc/tegra/regulators-tegra30.c b/drivers/soc/tegra/regulators-tegra30.c
index 0e776b20f625..e74bbc9c7859 100644
--- a/drivers/soc/tegra/regulators-tegra30.c
+++ b/drivers/soc/tegra/regulators-tegra30.c
@@ -12,17 +12,22 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
+#include <linux/reboot.h>
#include <linux/regulator/coupler.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <soc/tegra/fuse.h>
+#include <soc/tegra/pmc.h>
struct tegra_regulator_coupler {
struct regulator_coupler coupler;
struct regulator_dev *core_rdev;
struct regulator_dev *cpu_rdev;
- int core_min_uV;
+ struct notifier_block reboot_notifier;
+ int core_min_uV, cpu_min_uV;
+ bool sys_reboot_mode_req;
+ bool sys_reboot_mode;
};
static inline struct tegra_regulator_coupler *
@@ -39,6 +44,21 @@ static int tegra30_core_limit(struct tegra_regulator_coupler *tegra,
int core_cur_uV;
int err;
+ /*
+ * Tegra30 SoC has critical DVFS-capable devices that are
+ * permanently-active or active at a boot time, like EMC
+ * (DRAM controller) or Display controller for example.
+ *
+ * The voltage of a CORE SoC power domain shall not be dropped below
+ * a minimum level, which is determined by device's clock rate.
+ * This means that we can't fully allow CORE voltage scaling until
+ * the state of all DVFS-critical CORE devices is synced.
+ */
+ if (tegra_pmc_core_domain_state_synced() && !tegra->sys_reboot_mode) {
+ pr_info_once("voltage state synced\n");
+ return 0;
+ }
+
if (tegra->core_min_uV > 0)
return tegra->core_min_uV;
@@ -59,7 +79,7 @@ static int tegra30_core_limit(struct tegra_regulator_coupler *tegra,
*/
tegra->core_min_uV = core_max_uV;
- pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV);
+ pr_info("core voltage initialized to %duV\n", tegra->core_min_uV);
return tegra->core_min_uV;
}
@@ -172,6 +192,10 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra,
if (cpu_uV < 0)
return cpu_uV;
+ /* store boot voltage level */
+ if (!tegra->cpu_min_uV)
+ tegra->cpu_min_uV = cpu_uV;
+
/*
* CPU's regulator may not have any consumers, hence the voltage
* must not be changed in that case because CPU simply won't
@@ -195,6 +219,10 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra,
if (err)
return err;
+ /* restore boot voltage level */
+ if (tegra->sys_reboot_mode)
+ cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV);
+
if (core_min_limited_uV > core_uV) {
pr_err("core voltage constraint violated: %d %d %d\n",
core_uV, core_min_limited_uV, cpu_uV);
@@ -263,9 +291,56 @@ static int tegra30_regulator_balance_voltage(struct regulator_coupler *coupler,
return -EINVAL;
}
+ tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req);
+
return tegra30_voltage_update(tegra, cpu_rdev, core_rdev);
}
+static int tegra30_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra,
+ bool sys_reboot_mode)
+{
+ int err;
+
+ if (!tegra->core_rdev || !tegra->cpu_rdev)
+ return 0;
+
+ WRITE_ONCE(tegra->sys_reboot_mode_req, true);
+
+ /*
+ * Some devices use CPU soft-reboot method and in this case we
+ * should ensure that voltages are sane for the reboot by restoring
+ * the minimum boot levels.
+ */
+ err = regulator_sync_voltage_rdev(tegra->cpu_rdev);
+ if (err)
+ return err;
+
+ err = regulator_sync_voltage_rdev(tegra->core_rdev);
+ if (err)
+ return err;
+
+ WRITE_ONCE(tegra->sys_reboot_mode_req, sys_reboot_mode);
+
+ return 0;
+}
+
+static int tegra30_regulator_reboot(struct notifier_block *notifier,
+ unsigned long event, void *cmd)
+{
+ struct tegra_regulator_coupler *tegra;
+ int ret;
+
+ if (event != SYS_RESTART)
+ return NOTIFY_DONE;
+
+ tegra = container_of(notifier, struct tegra_regulator_coupler,
+ reboot_notifier);
+
+ ret = tegra30_regulator_prepare_reboot(tegra, true);
+
+ return notifier_from_errno(ret);
+}
+
static int tegra30_regulator_attach(struct regulator_coupler *coupler,
struct regulator_dev *rdev)
{
@@ -292,6 +367,14 @@ static int tegra30_regulator_detach(struct regulator_coupler *coupler,
{
struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
+ /*
+ * We don't expect regulators to be decoupled during reboot,
+ * this may race with the reboot handler and shouldn't ever
+ * happen in practice.
+ */
+ if (WARN_ON_ONCE(system_state > SYSTEM_RUNNING))
+ return -EPERM;
+
if (tegra->core_rdev == rdev) {
tegra->core_rdev = NULL;
return 0;
@@ -311,13 +394,19 @@ static struct tegra_regulator_coupler tegra30_coupler = {
.detach_regulator = tegra30_regulator_detach,
.balance_voltage = tegra30_regulator_balance_voltage,
},
+ .reboot_notifier.notifier_call = tegra30_regulator_reboot,
};
static int __init tegra_regulator_coupler_init(void)
{
+ int err;
+
if (!of_machine_is_compatible("nvidia,tegra30"))
return 0;
+ err = register_reboot_notifier(&tegra30_coupler.reboot_notifier);
+ WARN_ON(err);
+
return regulator_coupler_register(&tegra30_coupler.coupler);
}
arch_initcall(tegra_regulator_coupler_init);
diff --git a/drivers/soc/ti/smartreflex.c b/drivers/soc/ti/smartreflex.c
index 5376f3d22f31..06cbee5fd254 100644
--- a/drivers/soc/ti/smartreflex.c
+++ b/drivers/soc/ti/smartreflex.c
@@ -846,10 +846,8 @@ static int omap_sr_probe(struct platform_device *pdev)
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sr_info->base = devm_ioremap_resource(&pdev->dev, mem);
- if (IS_ERR(sr_info->base)) {
- dev_err(&pdev->dev, "%s: ioremap fail\n", __func__);
+ if (IS_ERR(sr_info->base))
return PTR_ERR(sr_info->base);
- }
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c
index c3e2161df732..09abd17065ba 100644
--- a/drivers/soc/ti/wkup_m3_ipc.c
+++ b/drivers/soc/ti/wkup_m3_ipc.c
@@ -445,10 +445,8 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
m3_ipc->ipc_mem_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(m3_ipc->ipc_mem_base)) {
- dev_err(dev, "could not ioremap ipc_mem\n");
+ if (IS_ERR(m3_ipc->ipc_mem_base))
return PTR_ERR(m3_ipc->ipc_mem_base);
- }
irq = platform_get_irq(pdev, 0);
if (!irq) {
diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig
index 016e74230bb7..2b7795233282 100644
--- a/drivers/soundwire/Kconfig
+++ b/drivers/soundwire/Kconfig
@@ -25,6 +25,7 @@ config SOUNDWIRE_INTEL
tristate "Intel SoundWire Master driver"
select SOUNDWIRE_CADENCE
select SOUNDWIRE_GENERIC_ALLOCATION
+ select AUXILIARY_BUS
depends on ACPI && SND_SOC
help
SoundWire Intel Master driver.
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index a9e0aa72654d..3e6d4addac2f 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -394,13 +394,13 @@ sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
}
static int
-sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
+sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
{
struct sdw_msg msg;
int ret;
ret = sdw_fill_msg(&msg, slave, addr, count,
- slave->dev_num, SDW_MSG_FLAG_WRITE, val);
+ slave->dev_num, SDW_MSG_FLAG_WRITE, (u8 *)val);
if (ret < 0)
return ret;
@@ -492,7 +492,7 @@ int sdw_read_no_pm(struct sdw_slave *slave, u32 addr)
}
EXPORT_SYMBOL(sdw_read_no_pm);
-static int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
+int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
{
int tmp;
@@ -503,6 +503,21 @@ static int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
tmp = (tmp & ~mask) | val;
return sdw_write_no_pm(slave, addr, tmp);
}
+EXPORT_SYMBOL(sdw_update_no_pm);
+
+/* Read-Modify-Write Slave register */
+int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
+{
+ int tmp;
+
+ tmp = sdw_read(slave, addr);
+ if (tmp < 0)
+ return tmp;
+
+ tmp = (tmp & ~mask) | val;
+ return sdw_write(slave, addr, tmp);
+}
+EXPORT_SYMBOL(sdw_update);
/**
* sdw_nread() - Read "n" contiguous SDW Slave registers
@@ -535,9 +550,9 @@ EXPORT_SYMBOL(sdw_nread);
* @slave: SDW Slave
* @addr: Register address
* @count: length
- * @val: Buffer for values to be read
+ * @val: Buffer for values to be written
*/
-int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
+int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
{
int ret;
@@ -821,26 +836,6 @@ static void sdw_modify_slave_status(struct sdw_slave *slave,
mutex_unlock(&bus->bus_lock);
}
-static enum sdw_clk_stop_mode sdw_get_clk_stop_mode(struct sdw_slave *slave)
-{
- enum sdw_clk_stop_mode mode;
-
- /*
- * Query for clock stop mode if Slave implements
- * ops->get_clk_stop_mode, else read from property.
- */
- if (slave->ops && slave->ops->get_clk_stop_mode) {
- mode = slave->ops->get_clk_stop_mode(slave);
- } else {
- if (slave->prop.clk_stop_mode1)
- mode = SDW_CLK_STOP_MODE1;
- else
- mode = SDW_CLK_STOP_MODE0;
- }
-
- return mode;
-}
-
static int sdw_slave_clk_stop_callback(struct sdw_slave *slave,
enum sdw_clk_stop_mode mode,
enum sdw_clk_stop_type type)
@@ -849,11 +844,8 @@ static int sdw_slave_clk_stop_callback(struct sdw_slave *slave,
if (slave->ops && slave->ops->clk_stop) {
ret = slave->ops->clk_stop(slave, mode, type);
- if (ret < 0) {
- dev_err(&slave->dev,
- "Clk Stop type =%d failed: %d\n", type, ret);
+ if (ret < 0)
return ret;
- }
}
return 0;
@@ -880,7 +872,8 @@ static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave,
} else {
ret = sdw_read_no_pm(slave, SDW_SCP_SYSTEMCTRL);
if (ret < 0) {
- dev_err(&slave->dev, "SDW_SCP_SYSTEMCTRL read failed:%d\n", ret);
+ if (ret != -ENODATA)
+ dev_err(&slave->dev, "SDW_SCP_SYSTEMCTRL read failed:%d\n", ret);
return ret;
}
val = ret;
@@ -889,9 +882,8 @@ static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave,
ret = sdw_write_no_pm(slave, SDW_SCP_SYSTEMCTRL, val);
- if (ret < 0)
- dev_err(&slave->dev,
- "Clock Stop prepare failed for slave: %d", ret);
+ if (ret < 0 && ret != -ENODATA)
+ dev_err(&slave->dev, "SDW_SCP_SYSTEMCTRL write failed:%d\n", ret);
return ret;
}
@@ -909,7 +901,7 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num)
}
val &= SDW_SCP_STAT_CLK_STP_NF;
if (!val) {
- dev_dbg(bus->dev, "clock stop prep/de-prep done slave:%d",
+ dev_dbg(bus->dev, "clock stop prep/de-prep done slave:%d\n",
dev_num);
return 0;
}
@@ -918,7 +910,7 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num)
retry--;
} while (retry);
- dev_err(bus->dev, "clock stop prep/de-prep failed slave:%d",
+ dev_err(bus->dev, "clock stop prep/de-prep failed slave:%d\n",
dev_num);
return -ETIMEDOUT;
@@ -933,7 +925,6 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num)
*/
int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
{
- enum sdw_clk_stop_mode slave_mode;
bool simple_clk_stop = true;
struct sdw_slave *slave;
bool is_slave = false;
@@ -943,6 +934,9 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
* In order to save on transition time, prepare
* each Slave and then wait for all Slave(s) to be
* prepared for clock stop.
+ * If one of the Slave devices has lost sync and
+ * replies with Command Ignored/-ENODATA, we continue
+ * the loop
*/
list_for_each_entry(slave, &bus->slaves, node) {
if (!slave->dev_num)
@@ -955,36 +949,45 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
/* Identify if Slave(s) are available on Bus */
is_slave = true;
- slave_mode = sdw_get_clk_stop_mode(slave);
- slave->curr_clk_stop_mode = slave_mode;
-
- ret = sdw_slave_clk_stop_callback(slave, slave_mode,
+ ret = sdw_slave_clk_stop_callback(slave,
+ SDW_CLK_STOP_MODE0,
SDW_CLK_PRE_PREPARE);
- if (ret < 0) {
- dev_err(&slave->dev,
- "pre-prepare failed:%d", ret);
- return ret;
- }
-
- ret = sdw_slave_clk_stop_prepare(slave,
- slave_mode, true);
- if (ret < 0) {
- dev_err(&slave->dev,
- "pre-prepare failed:%d", ret);
+ if (ret < 0 && ret != -ENODATA) {
+ dev_err(&slave->dev, "clock stop pre-prepare cb failed:%d\n", ret);
return ret;
}
- if (slave_mode == SDW_CLK_STOP_MODE1)
+ /* Only prepare a Slave device if needed */
+ if (!slave->prop.simple_clk_stop_capable) {
simple_clk_stop = false;
+
+ ret = sdw_slave_clk_stop_prepare(slave,
+ SDW_CLK_STOP_MODE0,
+ true);
+ if (ret < 0 && ret != -ENODATA) {
+ dev_err(&slave->dev, "clock stop prepare failed:%d\n", ret);
+ return ret;
+ }
+ }
}
/* Skip remaining clock stop preparation if no Slave is attached */
if (!is_slave)
- return ret;
+ return 0;
+ /*
+ * Don't wait for all Slaves to be ready if they follow the simple
+ * state machine
+ */
if (!simple_clk_stop) {
ret = sdw_bus_wait_for_clk_prep_deprep(bus,
SDW_BROADCAST_DEV_NUM);
+ /*
+ * if there are no Slave devices present and the reply is
+ * Command_Ignored/-ENODATA, we don't need to continue with the
+ * flow and can just return here. The error code is not modified
+ * and its handling left as an exercise for the caller.
+ */
if (ret < 0)
return ret;
}
@@ -998,21 +1001,17 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
slave->status != SDW_SLAVE_ALERT)
continue;
- slave_mode = slave->curr_clk_stop_mode;
+ ret = sdw_slave_clk_stop_callback(slave,
+ SDW_CLK_STOP_MODE0,
+ SDW_CLK_POST_PREPARE);
- if (slave_mode == SDW_CLK_STOP_MODE1) {
- ret = sdw_slave_clk_stop_callback(slave,
- slave_mode,
- SDW_CLK_POST_PREPARE);
-
- if (ret < 0) {
- dev_err(&slave->dev,
- "post-prepare failed:%d", ret);
- }
+ if (ret < 0 && ret != -ENODATA) {
+ dev_err(&slave->dev, "clock stop post-prepare cb failed:%d\n", ret);
+ return ret;
}
}
- return ret;
+ return 0;
}
EXPORT_SYMBOL(sdw_bus_prep_clk_stop);
@@ -1035,12 +1034,8 @@ int sdw_bus_clk_stop(struct sdw_bus *bus)
ret = sdw_bwrite_no_pm(bus, SDW_BROADCAST_DEV_NUM,
SDW_SCP_CTRL, SDW_SCP_CTRL_CLK_STP_NOW);
if (ret < 0) {
- if (ret == -ENODATA)
- dev_dbg(bus->dev,
- "ClockStopNow Broadcast msg ignored %d", ret);
- else
- dev_err(bus->dev,
- "ClockStopNow Broadcast msg failed %d", ret);
+ if (ret != -ENODATA)
+ dev_err(bus->dev, "ClockStopNow Broadcast msg failed %d\n", ret);
return ret;
}
@@ -1059,7 +1054,6 @@ EXPORT_SYMBOL(sdw_bus_clk_stop);
*/
int sdw_bus_exit_clk_stop(struct sdw_bus *bus)
{
- enum sdw_clk_stop_mode mode;
bool simple_clk_stop = true;
struct sdw_slave *slave;
bool is_slave = false;
@@ -1081,33 +1075,36 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus)
/* Identify if Slave(s) are available on Bus */
is_slave = true;
- mode = slave->curr_clk_stop_mode;
-
- if (mode == SDW_CLK_STOP_MODE1) {
- simple_clk_stop = false;
- continue;
- }
-
- ret = sdw_slave_clk_stop_callback(slave, mode,
+ ret = sdw_slave_clk_stop_callback(slave, SDW_CLK_STOP_MODE0,
SDW_CLK_PRE_DEPREPARE);
if (ret < 0)
- dev_warn(&slave->dev,
- "clk stop deprep failed:%d", ret);
+ dev_warn(&slave->dev, "clock stop pre-deprepare cb failed:%d\n", ret);
+
+ /* Only de-prepare a Slave device if needed */
+ if (!slave->prop.simple_clk_stop_capable) {
+ simple_clk_stop = false;
- ret = sdw_slave_clk_stop_prepare(slave, mode,
- false);
+ ret = sdw_slave_clk_stop_prepare(slave, SDW_CLK_STOP_MODE0,
+ false);
- if (ret < 0)
- dev_warn(&slave->dev,
- "clk stop deprep failed:%d", ret);
+ if (ret < 0)
+ dev_warn(&slave->dev, "clock stop deprepare failed:%d\n", ret);
+ }
}
/* Skip remaining clock stop de-preparation if no Slave is attached */
if (!is_slave)
return 0;
- if (!simple_clk_stop)
- sdw_bus_wait_for_clk_prep_deprep(bus, SDW_BROADCAST_DEV_NUM);
+ /*
+ * Don't wait for all Slaves to be ready if they follow the simple
+ * state machine
+ */
+ if (!simple_clk_stop) {
+ ret = sdw_bus_wait_for_clk_prep_deprep(bus, SDW_BROADCAST_DEV_NUM);
+ if (ret < 0)
+ dev_warn(&slave->dev, "clock stop deprepare wait failed:%d\n", ret);
+ }
list_for_each_entry(slave, &bus->slaves, node) {
if (!slave->dev_num)
@@ -1117,9 +1114,10 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus)
slave->status != SDW_SLAVE_ALERT)
continue;
- mode = slave->curr_clk_stop_mode;
- sdw_slave_clk_stop_callback(slave, mode,
- SDW_CLK_POST_DEPREPARE);
+ ret = sdw_slave_clk_stop_callback(slave, SDW_CLK_STOP_MODE0,
+ SDW_CLK_POST_DEPREPARE);
+ if (ret < 0)
+ dev_warn(&slave->dev, "clock stop post-deprepare cb failed:%d\n", ret);
}
return 0;
diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
index 40354469860a..7631ef5e71fb 100644
--- a/drivers/soundwire/bus.h
+++ b/drivers/soundwire/bus.h
@@ -201,19 +201,6 @@ static inline void sdw_fill_port_params(struct sdw_port_params *params,
params->data_mode = data_mode;
}
-/* Read-Modify-Write Slave register */
-static inline int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
-{
- int tmp;
-
- tmp = sdw_read(slave, addr);
- if (tmp < 0)
- return tmp;
-
- tmp = (tmp & ~mask) | val;
- return sdw_write(slave, addr, tmp);
-}
-
/* broadcast read/write for tests */
int sdw_bread_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr);
int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value);
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index 192dac10f0c2..25950422b085 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -1428,20 +1428,6 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake)
}
}
- /*
- * This CMD_ACCEPT should be used when there are no devices
- * attached on the link when entering clock stop mode. If this is
- * not set and there is a broadcast write then the command ignored
- * will be treated as a failure
- */
- if (!slave_present)
- cdns_updatel(cdns, CDNS_MCP_CONTROL,
- CDNS_MCP_CONTROL_CMD_ACCEPT,
- CDNS_MCP_CONTROL_CMD_ACCEPT);
- else
- cdns_updatel(cdns, CDNS_MCP_CONTROL,
- CDNS_MCP_CONTROL_CMD_ACCEPT, 0);
-
/* commit changes */
ret = cdns_config_update(cdns);
if (ret < 0) {
@@ -1508,11 +1494,8 @@ int sdw_cdns_clock_restart(struct sdw_cdns *cdns, bool bus_reset)
cdns_updatel(cdns, CDNS_MCP_CONTROL,
CDNS_MCP_CONTROL_BLOCK_WAKEUP, 0);
- /*
- * clear CMD_ACCEPT so that the command ignored
- * will be treated as a failure during a broadcast write
- */
- cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT, 0);
+ cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT,
+ CDNS_MCP_CONTROL_CMD_ACCEPT);
if (!bus_reset) {
diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
index 4d1aab5b5ec2..0e7f8b35bb21 100644
--- a/drivers/soundwire/cadence_master.h
+++ b/drivers/soundwire/cadence_master.h
@@ -180,9 +180,6 @@ enum sdw_command_response
cdns_xfer_msg_defer(struct sdw_bus *bus,
struct sdw_msg *msg, struct sdw_defer *defer);
-enum sdw_command_response
-cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num);
-
int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params);
int cdns_set_sdw_stream(struct snd_soc_dai *dai,
diff --git a/drivers/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c
index 82061c1d9835..5db0a2443a1d 100644
--- a/drivers/soundwire/dmi-quirks.c
+++ b/drivers/soundwire/dmi-quirks.c
@@ -80,7 +80,7 @@ u64 sdw_dmi_override_adr(struct sdw_bus *bus, u64 addr)
/* check if any address remap quirk applies */
dmi_id = dmi_first_match(adr_remap_quirk_table);
if (dmi_id) {
- struct adr_remap *map = dmi_id->driver_data;
+ struct adr_remap *map;
for (map = dmi_id->driver_data; map->adr; map++) {
if (map->adr == addr) {
diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c
index 84d129587084..f7c66083a4dd 100644
--- a/drivers/soundwire/generic_bandwidth_allocation.c
+++ b/drivers/soundwire/generic_bandwidth_allocation.c
@@ -382,12 +382,18 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
*/
}
- if (i == clk_values)
+ if (i == clk_values) {
+ dev_err(bus->dev, "%s: could not find clock value for bandwidth %d\n",
+ __func__, bus->params.bandwidth);
return -EINVAL;
+ }
ret = sdw_select_row_col(bus, curr_dr_freq);
- if (ret < 0)
+ if (ret < 0) {
+ dev_err(bus->dev, "%s: could not find frame configuration for bus dr_freq %d\n",
+ __func__, curr_dr_freq);
return -EINVAL;
+ }
bus->params.curr_dr_freq = curr_dr_freq;
return 0;
@@ -404,10 +410,8 @@ int sdw_compute_params(struct sdw_bus *bus)
/* Computes clock frequency, frame shape and frame frequency */
ret = sdw_compute_bus_params(bus);
- if (ret < 0) {
- dev_err(bus->dev, "Compute bus params failed: %d\n", ret);
+ if (ret < 0)
return ret;
- }
/* Compute transport and port params */
ret = sdw_compute_port_params(bus);
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index fd95f94630b1..c11e3d8cd308 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -11,7 +11,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/platform_device.h>
+#include <linux/auxiliary_bus.h>
#include <sound/pcm_params.h>
#include <linux/pm_runtime.h>
#include <sound/soc.h>
@@ -1327,11 +1327,14 @@ static int intel_init(struct sdw_intel *sdw)
}
/*
- * probe and init
+ * probe and init (aux_dev_id argument is required by function prototype but not used)
*/
-static int intel_master_probe(struct platform_device *pdev)
+static int intel_link_probe(struct auxiliary_device *auxdev,
+ const struct auxiliary_device_id *aux_dev_id)
+
{
- struct device *dev = &pdev->dev;
+ struct device *dev = &auxdev->dev;
+ struct sdw_intel_link_dev *ldev = auxiliary_dev_to_sdw_intel_link_dev(auxdev);
struct sdw_intel *sdw;
struct sdw_cdns *cdns;
struct sdw_bus *bus;
@@ -1344,14 +1347,14 @@ static int intel_master_probe(struct platform_device *pdev)
cdns = &sdw->cdns;
bus = &cdns->bus;
- sdw->instance = pdev->id;
- sdw->link_res = dev_get_platdata(dev);
+ sdw->instance = auxdev->id;
+ sdw->link_res = &ldev->link_res;
cdns->dev = dev;
cdns->registers = sdw->link_res->registers;
cdns->instance = sdw->instance;
cdns->msg_count = 0;
- bus->link_id = pdev->id;
+ bus->link_id = auxdev->id;
sdw_cdns_probe(cdns);
@@ -1384,10 +1387,10 @@ static int intel_master_probe(struct platform_device *pdev)
return 0;
}
-int intel_master_startup(struct platform_device *pdev)
+int intel_link_startup(struct auxiliary_device *auxdev)
{
struct sdw_cdns_stream_config config;
- struct device *dev = &pdev->dev;
+ struct device *dev = &auxdev->dev;
struct sdw_cdns *cdns = dev_get_drvdata(dev);
struct sdw_intel *sdw = cdns_to_intel(cdns);
struct sdw_bus *bus = &cdns->bus;
@@ -1524,9 +1527,9 @@ err_init:
return ret;
}
-static int intel_master_remove(struct platform_device *pdev)
+static void intel_link_remove(struct auxiliary_device *auxdev)
{
- struct device *dev = &pdev->dev;
+ struct device *dev = &auxdev->dev;
struct sdw_cdns *cdns = dev_get_drvdata(dev);
struct sdw_intel *sdw = cdns_to_intel(cdns);
struct sdw_bus *bus = &cdns->bus;
@@ -1542,19 +1545,17 @@ static int intel_master_remove(struct platform_device *pdev)
snd_soc_unregister_component(dev);
}
sdw_bus_master_delete(bus);
-
- return 0;
}
-int intel_master_process_wakeen_event(struct platform_device *pdev)
+int intel_link_process_wakeen_event(struct auxiliary_device *auxdev)
{
- struct device *dev = &pdev->dev;
+ struct device *dev = &auxdev->dev;
struct sdw_intel *sdw;
struct sdw_bus *bus;
void __iomem *shim;
u16 wake_sts;
- sdw = platform_get_drvdata(pdev);
+ sdw = dev_get_drvdata(dev);
bus = &sdw->cdns.bus;
if (bus->prop.hw_disabled) {
@@ -1976,17 +1977,22 @@ static const struct dev_pm_ops intel_pm = {
SET_RUNTIME_PM_OPS(intel_suspend_runtime, intel_resume_runtime, NULL)
};
-static struct platform_driver sdw_intel_drv = {
- .probe = intel_master_probe,
- .remove = intel_master_remove,
+static const struct auxiliary_device_id intel_link_id_table[] = {
+ { .name = "soundwire_intel.link" },
+ {},
+};
+MODULE_DEVICE_TABLE(auxiliary, intel_link_id_table);
+
+static struct auxiliary_driver sdw_intel_drv = {
+ .probe = intel_link_probe,
+ .remove = intel_link_remove,
.driver = {
- .name = "intel-sdw",
+ /* auxiliary_driver_register() sets .name to be the modname */
.pm = &intel_pm,
- }
+ },
+ .id_table = intel_link_id_table
};
-
-module_platform_driver(sdw_intel_drv);
+module_auxiliary_driver(sdw_intel_drv);
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_ALIAS("platform:intel-sdw");
-MODULE_DESCRIPTION("Intel Soundwire Master Driver");
+MODULE_DESCRIPTION("Intel Soundwire Link Driver");
diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h
index 06bac8ba14e9..0b47b148da3f 100644
--- a/drivers/soundwire/intel.h
+++ b/drivers/soundwire/intel.h
@@ -7,7 +7,6 @@
/**
* struct sdw_intel_link_res - Soundwire Intel link resource structure,
* typically populated by the controller driver.
- * @pdev: platform_device
* @mmio_base: mmio base of SoundWire registers
* @registers: Link IO registers base
* @shim: Audio shim pointer
@@ -23,7 +22,6 @@
* @list: used to walk-through all masters exposed by the same controller
*/
struct sdw_intel_link_res {
- struct platform_device *pdev;
void __iomem *mmio_base; /* not strictly needed, useful for debug */
void __iomem *registers;
void __iomem *shim;
@@ -48,7 +46,15 @@ struct sdw_intel {
#endif
};
-int intel_master_startup(struct platform_device *pdev);
-int intel_master_process_wakeen_event(struct platform_device *pdev);
+int intel_link_startup(struct auxiliary_device *auxdev);
+int intel_link_process_wakeen_event(struct auxiliary_device *auxdev);
+
+struct sdw_intel_link_dev {
+ struct auxiliary_device auxdev;
+ struct sdw_intel_link_res link_res;
+};
+
+#define auxiliary_dev_to_sdw_intel_link_dev(auxiliary_dev) \
+ container_of(auxiliary_dev, struct sdw_intel_link_dev, auxdev)
#endif /* __SDW_INTEL_LOCAL_H */
diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c
index 30ce95ec2d70..9e283bef53d2 100644
--- a/drivers/soundwire/intel_init.c
+++ b/drivers/soundwire/intel_init.c
@@ -12,7 +12,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/platform_device.h>
+#include <linux/auxiliary_bus.h>
#include <linux/pm_runtime.h>
#include <linux/soundwire/sdw_intel.h>
#include "cadence_master.h"
@@ -24,28 +24,108 @@
#define SDW_LINK_BASE 0x30000
#define SDW_LINK_SIZE 0x10000
+static void intel_link_dev_release(struct device *dev)
+{
+ struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+ struct sdw_intel_link_dev *ldev = auxiliary_dev_to_sdw_intel_link_dev(auxdev);
+
+ kfree(ldev);
+}
+
+/* alloc, init and add link devices */
+static struct sdw_intel_link_dev *intel_link_dev_register(struct sdw_intel_res *res,
+ struct sdw_intel_ctx *ctx,
+ struct fwnode_handle *fwnode,
+ const char *name,
+ int link_id)
+{
+ struct sdw_intel_link_dev *ldev;
+ struct sdw_intel_link_res *link;
+ struct auxiliary_device *auxdev;
+ int ret;
+
+ ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
+ if (!ldev)
+ return ERR_PTR(-ENOMEM);
+
+ auxdev = &ldev->auxdev;
+ auxdev->name = name;
+ auxdev->dev.parent = res->parent;
+ auxdev->dev.fwnode = fwnode;
+ auxdev->dev.release = intel_link_dev_release;
+
+ /* we don't use an IDA since we already have a link ID */
+ auxdev->id = link_id;
+
+ /*
+ * keep a handle on the allocated memory, to be used in all other functions.
+ * Since the same pattern is used to skip links that are not enabled, there is
+ * no need to check if ctx->ldev[i] is NULL later on.
+ */
+ ctx->ldev[link_id] = ldev;
+
+ /* Add link information used in the driver probe */
+ link = &ldev->link_res;
+ link->mmio_base = res->mmio_base;
+ link->registers = res->mmio_base + SDW_LINK_BASE
+ + (SDW_LINK_SIZE * link_id);
+ link->shim = res->mmio_base + SDW_SHIM_BASE;
+ link->alh = res->mmio_base + SDW_ALH_BASE;
+
+ link->ops = res->ops;
+ link->dev = res->dev;
+
+ link->clock_stop_quirks = res->clock_stop_quirks;
+ link->shim_lock = &ctx->shim_lock;
+ link->shim_mask = &ctx->shim_mask;
+ link->link_mask = ctx->link_mask;
+
+ /* now follow the two-step init/add sequence */
+ ret = auxiliary_device_init(auxdev);
+ if (ret < 0) {
+ dev_err(res->parent, "failed to initialize link dev %s link_id %d\n",
+ name, link_id);
+ kfree(ldev);
+ return ERR_PTR(ret);
+ }
+
+ ret = auxiliary_device_add(&ldev->auxdev);
+ if (ret < 0) {
+ dev_err(res->parent, "failed to add link dev %s link_id %d\n",
+ ldev->auxdev.name, link_id);
+ /* ldev will be freed with the put_device() and .release sequence */
+ auxiliary_device_uninit(&ldev->auxdev);
+ return ERR_PTR(ret);
+ }
+
+ return ldev;
+}
+
+static void intel_link_dev_unregister(struct sdw_intel_link_dev *ldev)
+{
+ auxiliary_device_delete(&ldev->auxdev);
+ auxiliary_device_uninit(&ldev->auxdev);
+}
+
static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx)
{
- struct sdw_intel_link_res *link = ctx->links;
+ struct sdw_intel_link_dev *ldev;
u32 link_mask;
int i;
- if (!link)
- return 0;
-
link_mask = ctx->link_mask;
- for (i = 0; i < ctx->count; i++, link++) {
+ for (i = 0; i < ctx->count; i++) {
if (!(link_mask & BIT(i)))
continue;
- if (link->pdev) {
- pm_runtime_disable(&link->pdev->dev);
- platform_device_unregister(link->pdev);
- }
+ ldev = ctx->ldev[i];
- if (!link->clock_stop_quirks)
- pm_runtime_put_noidle(link->dev);
+ pm_runtime_disable(&ldev->auxdev.dev);
+ if (!ldev->link_res.clock_stop_quirks)
+ pm_runtime_put_noidle(ldev->link_res.dev);
+
+ intel_link_dev_unregister(ldev);
}
return 0;
@@ -91,9 +171,8 @@ EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT);
static struct sdw_intel_ctx
*sdw_intel_probe_controller(struct sdw_intel_res *res)
{
- struct platform_device_info pdevinfo;
- struct platform_device *pdev;
struct sdw_intel_link_res *link;
+ struct sdw_intel_link_dev *ldev;
struct sdw_intel_ctx *ctx;
struct acpi_device *adev;
struct sdw_slave *slave;
@@ -116,67 +195,60 @@ static struct sdw_intel_ctx
count = res->count;
dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
- ctx = devm_kzalloc(&adev->dev, sizeof(*ctx), GFP_KERNEL);
+ /*
+ * we need to alloc/free memory manually and can't use devm:
+ * this routine may be called from a workqueue, and not from
+ * the parent .probe.
+ * If devm_ was used, the memory might never be freed on errors.
+ */
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return NULL;
ctx->count = count;
- ctx->links = devm_kcalloc(&adev->dev, ctx->count,
- sizeof(*ctx->links), GFP_KERNEL);
- if (!ctx->links)
+
+ /*
+ * allocate the array of pointers. The link-specific data is allocated
+ * as part of the first loop below and released with the auxiliary_device_uninit().
+ * If some links are disabled, the link pointer will remain NULL. Given that the
+ * number of links is small, this is simpler than using a list to keep track of links.
+ */
+ ctx->ldev = kcalloc(ctx->count, sizeof(*ctx->ldev), GFP_KERNEL);
+ if (!ctx->ldev) {
+ kfree(ctx);
return NULL;
+ }
- ctx->count = count;
ctx->mmio_base = res->mmio_base;
ctx->link_mask = res->link_mask;
ctx->handle = res->handle;
mutex_init(&ctx->shim_lock);
- link = ctx->links;
link_mask = ctx->link_mask;
INIT_LIST_HEAD(&ctx->link_list);
- /* Create SDW Master devices */
- for (i = 0; i < count; i++, link++) {
- if (!(link_mask & BIT(i))) {
- dev_dbg(&adev->dev,
- "Link %d masked, will not be enabled\n", i);
+ for (i = 0; i < count; i++) {
+ if (!(link_mask & BIT(i)))
continue;
- }
- link->mmio_base = res->mmio_base;
- link->registers = res->mmio_base + SDW_LINK_BASE
- + (SDW_LINK_SIZE * i);
- link->shim = res->mmio_base + SDW_SHIM_BASE;
- link->alh = res->mmio_base + SDW_ALH_BASE;
-
- link->ops = res->ops;
- link->dev = res->dev;
-
- link->clock_stop_quirks = res->clock_stop_quirks;
- link->shim_lock = &ctx->shim_lock;
- link->shim_mask = &ctx->shim_mask;
- link->link_mask = link_mask;
-
- memset(&pdevinfo, 0, sizeof(pdevinfo));
-
- pdevinfo.parent = res->parent;
- pdevinfo.name = "intel-sdw";
- pdevinfo.id = i;
- pdevinfo.fwnode = acpi_fwnode_handle(adev);
- pdevinfo.data = link;
- pdevinfo.size_data = sizeof(*link);
-
- pdev = platform_device_register_full(&pdevinfo);
- if (IS_ERR(pdev)) {
- dev_err(&adev->dev,
- "platform device creation failed: %ld\n",
- PTR_ERR(pdev));
+ /*
+ * init and add a device for each link
+ *
+ * The name of the device will be soundwire_intel.link.[i],
+ * with the "soundwire_intel" module prefix automatically added
+ * by the auxiliary bus core.
+ */
+ ldev = intel_link_dev_register(res,
+ ctx,
+ acpi_fwnode_handle(adev),
+ "link",
+ i);
+ if (IS_ERR(ldev))
goto err;
- }
- link->pdev = pdev;
- link->cdns = platform_get_drvdata(pdev);
+
+ link = &ldev->link_res;
+ link->cdns = dev_get_drvdata(&ldev->auxdev.dev);
if (!link->cdns) {
dev_err(&adev->dev, "failed to get link->cdns\n");
@@ -194,8 +266,7 @@ static struct sdw_intel_ctx
num_slaves++;
}
- ctx->ids = devm_kcalloc(&adev->dev, num_slaves,
- sizeof(*ctx->ids), GFP_KERNEL);
+ ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL);
if (!ctx->ids)
goto err;
@@ -213,8 +284,14 @@ static struct sdw_intel_ctx
return ctx;
err:
- ctx->count = i;
- sdw_intel_cleanup(ctx);
+ while (i--) {
+ if (!(link_mask & BIT(i)))
+ continue;
+ ldev = ctx->ldev[i];
+ intel_link_dev_unregister(ldev);
+ }
+ kfree(ctx->ldev);
+ kfree(ctx);
return NULL;
}
@@ -222,7 +299,7 @@ static int
sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
{
struct acpi_device *adev;
- struct sdw_intel_link_res *link;
+ struct sdw_intel_link_dev *ldev;
u32 caps;
u32 link_mask;
int i;
@@ -241,27 +318,28 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
return -EINVAL;
}
- if (!ctx->links)
+ if (!ctx->ldev)
return -EINVAL;
- link = ctx->links;
link_mask = ctx->link_mask;
/* Startup SDW Master devices */
- for (i = 0; i < ctx->count; i++, link++) {
+ for (i = 0; i < ctx->count; i++) {
if (!(link_mask & BIT(i)))
continue;
- intel_master_startup(link->pdev);
+ ldev = ctx->ldev[i];
+
+ intel_link_startup(&ldev->auxdev);
- if (!link->clock_stop_quirks) {
+ if (!ldev->link_res.clock_stop_quirks) {
/*
* we need to prevent the parent PCI device
* from entering pm_runtime suspend, so that
* power rails to the SoundWire IP are not
* turned off.
*/
- pm_runtime_get_noresume(link->dev);
+ pm_runtime_get_noresume(ldev->link_res.dev);
}
}
@@ -272,8 +350,8 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
* sdw_intel_probe() - SoundWire Intel probe routine
* @res: resource data
*
- * This registers a platform device for each Master handled by the controller,
- * and SoundWire Master and Slave devices will be created by the platform
+ * This registers an auxiliary device for each Master handled by the controller,
+ * and SoundWire Master and Slave devices will be created by the auxiliary
* device probe. All the information necessary is stored in the context, and
* the res argument pointer can be freed after this step.
* This function will be called after sdw_intel_acpi_scan() by SOF probe.
@@ -306,27 +384,31 @@ EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT);
void sdw_intel_exit(struct sdw_intel_ctx *ctx)
{
sdw_intel_cleanup(ctx);
+ kfree(ctx->ids);
+ kfree(ctx->ldev);
+ kfree(ctx);
}
EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT);
void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx)
{
- struct sdw_intel_link_res *link;
+ struct sdw_intel_link_dev *ldev;
u32 link_mask;
int i;
- if (!ctx->links)
+ if (!ctx->ldev)
return;
- link = ctx->links;
link_mask = ctx->link_mask;
/* Startup SDW Master devices */
- for (i = 0; i < ctx->count; i++, link++) {
+ for (i = 0; i < ctx->count; i++) {
if (!(link_mask & BIT(i)))
continue;
- intel_master_process_wakeen_event(link->pdev);
+ ldev = ctx->ldev[i];
+
+ intel_link_process_wakeen_event(&ldev->auxdev);
}
}
EXPORT_SYMBOL_NS(sdw_intel_process_wakeen_event, SOUNDWIRE_INTEL_INIT);
diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c
index 0eed38a79c6d..669d7573320b 100644
--- a/drivers/soundwire/slave.c
+++ b/drivers/soundwire/slave.c
@@ -39,12 +39,12 @@ int sdw_slave_add(struct sdw_bus *bus,
if (id->unique_id == SDW_IGNORED_UNIQUE_ID) {
/* name shall be sdw:link:mfg:part:class */
- dev_set_name(&slave->dev, "sdw:%x:%x:%x:%x",
+ dev_set_name(&slave->dev, "sdw:%01x:%04x:%04x:%02x",
bus->link_id, id->mfg_id, id->part_id,
id->class_id);
} else {
/* name shall be sdw:link:mfg:part:class:unique */
- dev_set_name(&slave->dev, "sdw:%x:%x:%x:%x:%x",
+ dev_set_name(&slave->dev, "sdw:%01x:%04x:%04x:%02x:%01x",
bus->link_id, id->mfg_id, id->part_id,
id->class_id, id->unique_id);
}
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index 1eaedaaba094..1a18308f4ef4 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -422,7 +422,6 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
struct completion *port_ready;
struct sdw_dpn_prop *dpn_prop;
struct sdw_prepare_ch prep_ch;
- unsigned int time_left;
bool intr = false;
int ret = 0, val;
u32 addr;
@@ -479,15 +478,15 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
/* Wait for completion on port ready */
port_ready = &s_rt->slave->port_ready[prep_ch.num];
- time_left = wait_for_completion_timeout(port_ready,
- msecs_to_jiffies(dpn_prop->ch_prep_timeout));
+ wait_for_completion_timeout(port_ready,
+ msecs_to_jiffies(dpn_prop->ch_prep_timeout));
val = sdw_read(s_rt->slave, SDW_DPN_PREPARESTATUS(p_rt->num));
- val &= p_rt->ch_mask;
- if (!time_left || val) {
+ if ((val < 0) || (val & p_rt->ch_mask)) {
+ ret = (val < 0) ? val : -ETIMEDOUT;
dev_err(&s_rt->slave->dev,
- "Chn prep failed for port:%d\n", prep_ch.num);
- return -ETIMEDOUT;
+ "Chn prep failed for port %d: %d\n", prep_ch.num, ret);
+ return ret;
}
}
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index f4481fe48bf0..e71a4c514f7b 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -806,6 +806,7 @@ config SPI_STM32_QSPI
tristate "STMicroelectronics STM32 QUAD SPI controller"
depends on ARCH_STM32 || COMPILE_TEST
depends on OF
+ depends on SPI_MEM
help
This enables support for the Quad SPI controller in master mode.
This driver does not support generic SPI. The implementation only
diff --git a/drivers/spi/spi-altera-dfl.c b/drivers/spi/spi-altera-dfl.c
index 3e32e4fe5895..39a3e1a032e0 100644
--- a/drivers/spi/spi-altera-dfl.c
+++ b/drivers/spi/spi-altera-dfl.c
@@ -148,10 +148,8 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
base = devm_ioremap_resource(dev, &dfl_dev->mmio_res);
- if (IS_ERR(base)) {
- dev_err(dev, "%s get mem resource fail!\n", __func__);
+ if (IS_ERR(base))
return PTR_ERR(base);
- }
config_spi_master(base, master);
dev_dbg(dev, "%s cs %u bpm 0x%x mode 0x%x\n", __func__,
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index 98ace748cd98..d1e287d2d9cd 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -19,7 +19,6 @@
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <linux/platform_data/spi-ath79.h>
#define DRV_NAME "ath79-spi"
@@ -138,7 +137,6 @@ static int ath79_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct ath79_spi *sp;
- struct ath79_spi_platform_data *pdata;
unsigned long rate;
int ret;
@@ -152,15 +150,10 @@ static int ath79_spi_probe(struct platform_device *pdev)
master->dev.of_node = pdev->dev.of_node;
platform_set_drvdata(pdev, sp);
- pdata = dev_get_platdata(&pdev->dev);
-
master->use_gpio_descriptors = true;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
master->flags = SPI_MASTER_GPIO_SS;
- if (pdata) {
- master->bus_num = pdata->bus_num;
- master->num_chipselect = pdata->num_chipselect;
- }
+ master->num_chipselect = 3;
sp->bitbang.master = master;
sp->bitbang.chipselect = ath79_spi_chipselect;
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 7cd5fe00dfc1..2ef74885ffa2 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -700,7 +700,6 @@ static void atmel_spi_next_xfer_pio(struct spi_master *master,
static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
struct spi_transfer *xfer,
u32 *plen)
- __must_hold(&as->lock)
{
struct atmel_spi *as = spi_master_get_devdata(master);
struct dma_chan *rxchan = master->dma_rx;
@@ -716,8 +715,6 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
if (!rxchan || !txchan)
return -ENODEV;
- /* release lock for DMA operations */
- atmel_spi_unlock(as);
*plen = xfer->len;
@@ -786,15 +783,12 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
rxchan->device->device_issue_pending(rxchan);
txchan->device->device_issue_pending(txchan);
- /* take back lock */
- atmel_spi_lock(as);
return 0;
err_dma:
spi_writel(as, IDR, SPI_BIT(OVRES));
atmel_spi_stop_dma(master);
err_exit:
- atmel_spi_lock(as);
return -ENOMEM;
}
@@ -863,7 +857,6 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
* lock is held, spi irq is blocked
*/
static void atmel_spi_pdc_next_xfer(struct spi_master *master,
- struct spi_message *msg,
struct spi_transfer *xfer)
{
struct atmel_spi *as = spi_master_get_devdata(master);
@@ -879,12 +872,12 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
spi_writel(as, RPR, rx_dma);
spi_writel(as, TPR, tx_dma);
- if (msg->spi->bits_per_word > 8)
+ if (xfer->bits_per_word > 8)
len >>= 1;
spi_writel(as, RCR, len);
spi_writel(as, TCR, len);
- dev_dbg(&msg->spi->dev,
+ dev_dbg(&master->dev,
" start xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
xfer, xfer->len, xfer->tx_buf,
(unsigned long long)xfer->tx_dma, xfer->rx_buf,
@@ -898,12 +891,12 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
spi_writel(as, RNPR, rx_dma);
spi_writel(as, TNPR, tx_dma);
- if (msg->spi->bits_per_word > 8)
+ if (xfer->bits_per_word > 8)
len >>= 1;
spi_writel(as, RNCR, len);
spi_writel(as, TNCR, len);
- dev_dbg(&msg->spi->dev,
+ dev_dbg(&master->dev,
" next xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
xfer, xfer->len, xfer->tx_buf,
(unsigned long long)xfer->tx_dma, xfer->rx_buf,
@@ -1054,8 +1047,6 @@ atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer)
/* Interrupt
*
- * No need for locking in this Interrupt handler: done_status is the
- * only information modified.
*/
static irqreturn_t
atmel_spi_pio_interrupt(int irq, void *dev_id)
@@ -1273,12 +1264,28 @@ static int atmel_spi_setup(struct spi_device *spi)
return 0;
}
+static void atmel_spi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct atmel_spi *as = spi_master_get_devdata(spi->master);
+ /* the core doesn't really pass us enable/disable, but CS HIGH vs CS LOW
+ * since we already have routines for activate/deactivate translate
+ * high/low to active/inactive
+ */
+ enable = (!!(spi->mode & SPI_CS_HIGH) == enable);
+
+ if (enable) {
+ cs_activate(as, spi);
+ } else {
+ cs_deactivate(as, spi);
+ }
+
+}
+
static int atmel_spi_one_transfer(struct spi_master *master,
- struct spi_message *msg,
+ struct spi_device *spi,
struct spi_transfer *xfer)
{
struct atmel_spi *as;
- struct spi_device *spi = msg->spi;
u8 bits;
u32 len;
struct atmel_spi_device *asd;
@@ -1288,11 +1295,6 @@ static int atmel_spi_one_transfer(struct spi_master *master,
as = spi_master_get_devdata(master);
- if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) {
- dev_dbg(&spi->dev, "missing rx or tx buf\n");
- return -EINVAL;
- }
-
asd = spi->controller_state;
bits = (asd->csr >> 4) & 0xf;
if (bits != xfer->bits_per_word - 8) {
@@ -1305,13 +1307,13 @@ static int atmel_spi_one_transfer(struct spi_master *master,
* DMA map early, for performance (empties dcache ASAP) and
* better fault reporting.
*/
- if ((!msg->is_dma_mapped)
+ if ((!master->cur_msg_mapped)
&& as->use_pdc) {
if (atmel_spi_dma_map_xfer(as, xfer) < 0)
return -ENOMEM;
}
- atmel_spi_set_xfer_speed(as, msg->spi, xfer);
+ atmel_spi_set_xfer_speed(as, spi, xfer);
as->done_status = 0;
as->current_transfer = xfer;
@@ -1320,7 +1322,9 @@ static int atmel_spi_one_transfer(struct spi_master *master,
reinit_completion(&as->xfer_completion);
if (as->use_pdc) {
- atmel_spi_pdc_next_xfer(master, msg, xfer);
+ atmel_spi_lock(as);
+ atmel_spi_pdc_next_xfer(master, xfer);
+ atmel_spi_unlock(as);
} else if (atmel_spi_use_dma(as, xfer)) {
len = as->current_remaining_bytes;
ret = atmel_spi_next_xfer_dma_submit(master,
@@ -1328,21 +1332,21 @@ static int atmel_spi_one_transfer(struct spi_master *master,
if (ret) {
dev_err(&spi->dev,
"unable to use DMA, fallback to PIO\n");
- atmel_spi_next_xfer_pio(master, xfer);
+ as->done_status = ret;
+ break;
} else {
as->current_remaining_bytes -= len;
if (as->current_remaining_bytes < 0)
as->current_remaining_bytes = 0;
}
} else {
+ atmel_spi_lock(as);
atmel_spi_next_xfer_pio(master, xfer);
+ atmel_spi_unlock(as);
}
- /* interrupts are disabled, so free the lock for schedule */
- atmel_spi_unlock(as);
dma_timeout = wait_for_completion_timeout(&as->xfer_completion,
SPI_DMA_TIMEOUT);
- atmel_spi_lock(as);
if (WARN_ON(dma_timeout == 0)) {
dev_err(&spi->dev, "spi transfer timeout\n");
as->done_status = -EIO;
@@ -1381,90 +1385,16 @@ static int atmel_spi_one_transfer(struct spi_master *master,
} else if (atmel_spi_use_dma(as, xfer)) {
atmel_spi_stop_dma(master);
}
-
- if (!msg->is_dma_mapped
- && as->use_pdc)
- atmel_spi_dma_unmap_xfer(master, xfer);
-
- return 0;
-
- } else {
- /* only update length if no error */
- msg->actual_length += xfer->len;
}
- if (!msg->is_dma_mapped
+ if (!master->cur_msg_mapped
&& as->use_pdc)
atmel_spi_dma_unmap_xfer(master, xfer);
- spi_transfer_delay_exec(xfer);
-
- if (xfer->cs_change) {
- if (list_is_last(&xfer->transfer_list,
- &msg->transfers)) {
- as->keep_cs = true;
- } else {
- cs_deactivate(as, msg->spi);
- udelay(10);
- cs_activate(as, msg->spi);
- }
- }
-
- return 0;
-}
-
-static int atmel_spi_transfer_one_message(struct spi_master *master,
- struct spi_message *msg)
-{
- struct atmel_spi *as;
- struct spi_transfer *xfer;
- struct spi_device *spi = msg->spi;
- int ret = 0;
-
- as = spi_master_get_devdata(master);
-
- dev_dbg(&spi->dev, "new message %p submitted for %s\n",
- msg, dev_name(&spi->dev));
-
- atmel_spi_lock(as);
- cs_activate(as, spi);
-
- as->keep_cs = false;
-
- msg->status = 0;
- msg->actual_length = 0;
-
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- trace_spi_transfer_start(msg, xfer);
-
- ret = atmel_spi_one_transfer(master, msg, xfer);
- if (ret)
- goto msg_done;
-
- trace_spi_transfer_stop(msg, xfer);
- }
-
if (as->use_pdc)
atmel_spi_disable_pdc_transfer(as);
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- dev_dbg(&spi->dev,
- " xfer %p: len %u tx %p/%pad rx %p/%pad\n",
- xfer, xfer->len,
- xfer->tx_buf, &xfer->tx_dma,
- xfer->rx_buf, &xfer->rx_dma);
- }
-
-msg_done:
- if (!as->keep_cs)
- cs_deactivate(as, msg->spi);
-
- atmel_spi_unlock(as);
-
- msg->status = as->done_status;
- spi_finalize_current_message(spi->master);
-
- return ret;
+ return as->done_status;
}
static void atmel_spi_cleanup(struct spi_device *spi)
@@ -1554,7 +1484,8 @@ static int atmel_spi_probe(struct platform_device *pdev)
master->num_chipselect = 4;
master->setup = atmel_spi_setup;
master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX);
- master->transfer_one_message = atmel_spi_transfer_one_message;
+ master->transfer_one = atmel_spi_one_transfer;
+ master->set_cs = atmel_spi_set_cs;
master->cleanup = atmel_spi_cleanup;
master->auto_runtime_pm = true;
master->max_dma_len = SPI_MAX_DMA_XFER;
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index fe40626e45aa..5f8771fe1a31 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -68,7 +68,6 @@
#define BCM2835_SPI_FIFO_SIZE 64
#define BCM2835_SPI_FIFO_SIZE_3_4 48
#define BCM2835_SPI_DMA_MIN_LENGTH 96
-#define BCM2835_SPI_NUM_CS 24 /* raise as necessary */
#define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
| SPI_NO_CS | SPI_3WIRE)
@@ -96,8 +95,6 @@ MODULE_PARM_DESC(polling_limit_us,
* @rx_prologue: bytes received without DMA if first RX sglist entry's
* length is not a multiple of 4 (to overcome hardware limitation)
* @tx_spillover: whether @tx_prologue spills over to second TX sglist entry
- * @prepare_cs: precalculated CS register value for ->prepare_message()
- * (uses slave-specific clock polarity and phase settings)
* @debugfs_dir: the debugfs directory - neede to remove debugfs when
* unloading the module
* @count_transfer_polling: count of how often polling mode is used
@@ -107,7 +104,7 @@ MODULE_PARM_DESC(polling_limit_us,
* These are counted as well in @count_transfer_polling and
* @count_transfer_irq
* @count_transfer_dma: count how often dma mode is used
- * @chip_select: SPI slave currently selected
+ * @slv: SPI slave currently selected
* (used by bcm2835_spi_dma_tx_done() to write @clear_rx_cs)
* @tx_dma_active: whether a TX DMA descriptor is in progress
* @rx_dma_active: whether a RX DMA descriptor is in progress
@@ -115,11 +112,6 @@ MODULE_PARM_DESC(polling_limit_us,
* @fill_tx_desc: preallocated TX DMA descriptor used for RX-only transfers
* (cyclically copies from zero page to TX FIFO)
* @fill_tx_addr: bus address of zero page
- * @clear_rx_desc: preallocated RX DMA descriptor used for TX-only transfers
- * (cyclically clears RX FIFO by writing @clear_rx_cs to CS register)
- * @clear_rx_addr: bus address of @clear_rx_cs
- * @clear_rx_cs: precalculated CS register value to clear RX FIFO
- * (uses slave-specific clock polarity and phase settings)
*/
struct bcm2835_spi {
void __iomem *regs;
@@ -134,7 +126,6 @@ struct bcm2835_spi {
int tx_prologue;
int rx_prologue;
unsigned int tx_spillover;
- u32 prepare_cs[BCM2835_SPI_NUM_CS];
struct dentry *debugfs_dir;
u64 count_transfer_polling;
@@ -142,14 +133,28 @@ struct bcm2835_spi {
u64 count_transfer_irq_after_polling;
u64 count_transfer_dma;
- u8 chip_select;
+ struct bcm2835_spidev *slv;
unsigned int tx_dma_active;
unsigned int rx_dma_active;
struct dma_async_tx_descriptor *fill_tx_desc;
dma_addr_t fill_tx_addr;
- struct dma_async_tx_descriptor *clear_rx_desc[BCM2835_SPI_NUM_CS];
+};
+
+/**
+ * struct bcm2835_spidev - BCM2835 SPI slave
+ * @prepare_cs: precalculated CS register value for ->prepare_message()
+ * (uses slave-specific clock polarity and phase settings)
+ * @clear_rx_desc: preallocated RX DMA descriptor used for TX-only transfers
+ * (cyclically clears RX FIFO by writing @clear_rx_cs to CS register)
+ * @clear_rx_addr: bus address of @clear_rx_cs
+ * @clear_rx_cs: precalculated CS register value to clear RX FIFO
+ * (uses slave-specific clock polarity and phase settings)
+ */
+struct bcm2835_spidev {
+ u32 prepare_cs;
+ struct dma_async_tx_descriptor *clear_rx_desc;
dma_addr_t clear_rx_addr;
- u32 clear_rx_cs[BCM2835_SPI_NUM_CS] ____cacheline_aligned;
+ u32 clear_rx_cs ____cacheline_aligned;
};
#if defined(CONFIG_DEBUG_FS)
@@ -624,8 +629,7 @@ static void bcm2835_spi_dma_tx_done(void *data)
/* busy-wait for TX FIFO to empty */
while (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE))
- bcm2835_wr(bs, BCM2835_SPI_CS,
- bs->clear_rx_cs[bs->chip_select]);
+ bcm2835_wr(bs, BCM2835_SPI_CS, bs->slv->clear_rx_cs);
bs->tx_dma_active = false;
smp_wmb();
@@ -646,18 +650,18 @@ static void bcm2835_spi_dma_tx_done(void *data)
/**
* bcm2835_spi_prepare_sg() - prepare and submit DMA descriptor for sglist
* @ctlr: SPI master controller
- * @spi: SPI slave
* @tfr: SPI transfer
* @bs: BCM2835 SPI controller
+ * @slv: BCM2835 SPI slave
* @is_tx: whether to submit DMA descriptor for TX or RX sglist
*
* Prepare and submit a DMA descriptor for the TX or RX sglist of @tfr.
* Return 0 on success or a negative error number.
*/
static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
- struct spi_device *spi,
struct spi_transfer *tfr,
struct bcm2835_spi *bs,
+ struct bcm2835_spidev *slv,
bool is_tx)
{
struct dma_chan *chan;
@@ -697,7 +701,7 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
} else if (!tfr->rx_buf) {
desc->callback = bcm2835_spi_dma_tx_done;
desc->callback_param = ctlr;
- bs->chip_select = spi->chip_select;
+ bs->slv = slv;
}
/* submit it to DMA-engine */
@@ -709,8 +713,8 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
/**
* bcm2835_spi_transfer_one_dma() - perform SPI transfer using DMA engine
* @ctlr: SPI master controller
- * @spi: SPI slave
* @tfr: SPI transfer
+ * @slv: BCM2835 SPI slave
* @cs: CS register
*
* For *bidirectional* transfers (both tx_buf and rx_buf are non-%NULL), set up
@@ -754,8 +758,8 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
* performed at the end of an RX-only transfer.
*/
static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
- struct spi_device *spi,
struct spi_transfer *tfr,
+ struct bcm2835_spidev *slv,
u32 cs)
{
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
@@ -773,7 +777,7 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
/* setup tx-DMA */
if (bs->tx_buf) {
- ret = bcm2835_spi_prepare_sg(ctlr, spi, tfr, bs, true);
+ ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, slv, true);
} else {
cookie = dmaengine_submit(bs->fill_tx_desc);
ret = dma_submit_error(cookie);
@@ -799,9 +803,9 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
* this saves 10us or more.
*/
if (bs->rx_buf) {
- ret = bcm2835_spi_prepare_sg(ctlr, spi, tfr, bs, false);
+ ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, slv, false);
} else {
- cookie = dmaengine_submit(bs->clear_rx_desc[spi->chip_select]);
+ cookie = dmaengine_submit(slv->clear_rx_desc);
ret = dma_submit_error(cookie);
}
if (ret) {
@@ -850,8 +854,6 @@ static bool bcm2835_spi_can_dma(struct spi_controller *ctlr,
static void bcm2835_dma_release(struct spi_controller *ctlr,
struct bcm2835_spi *bs)
{
- int i;
-
if (ctlr->dma_tx) {
dmaengine_terminate_sync(ctlr->dma_tx);
@@ -870,17 +872,6 @@ static void bcm2835_dma_release(struct spi_controller *ctlr,
if (ctlr->dma_rx) {
dmaengine_terminate_sync(ctlr->dma_rx);
-
- for (i = 0; i < BCM2835_SPI_NUM_CS; i++)
- if (bs->clear_rx_desc[i])
- dmaengine_desc_free(bs->clear_rx_desc[i]);
-
- if (bs->clear_rx_addr)
- dma_unmap_single(ctlr->dma_rx->device->dev,
- bs->clear_rx_addr,
- sizeof(bs->clear_rx_cs),
- DMA_TO_DEVICE);
-
dma_release_channel(ctlr->dma_rx);
ctlr->dma_rx = NULL;
}
@@ -892,7 +883,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
struct dma_slave_config slave_config;
const __be32 *addr;
dma_addr_t dma_reg_base;
- int ret, i;
+ int ret;
/* base address in dma-space */
addr = of_get_address(ctlr->dev.of_node, 0, NULL, NULL);
@@ -972,35 +963,6 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
if (ret)
goto err_config;
- bs->clear_rx_addr = dma_map_single(ctlr->dma_rx->device->dev,
- bs->clear_rx_cs,
- sizeof(bs->clear_rx_cs),
- DMA_TO_DEVICE);
- if (dma_mapping_error(ctlr->dma_rx->device->dev, bs->clear_rx_addr)) {
- dev_err(dev, "cannot map clear_rx_cs - not using DMA mode\n");
- bs->clear_rx_addr = 0;
- ret = -ENOMEM;
- goto err_release;
- }
-
- for (i = 0; i < BCM2835_SPI_NUM_CS; i++) {
- bs->clear_rx_desc[i] = dmaengine_prep_dma_cyclic(ctlr->dma_rx,
- bs->clear_rx_addr + i * sizeof(u32),
- sizeof(u32), 0,
- DMA_MEM_TO_DEV, 0);
- if (!bs->clear_rx_desc[i]) {
- dev_err(dev, "cannot prepare clear_rx_desc - not using DMA mode\n");
- ret = -ENOMEM;
- goto err_release;
- }
-
- ret = dmaengine_desc_set_reuse(bs->clear_rx_desc[i]);
- if (ret) {
- dev_err(dev, "cannot reuse clear_rx_desc - not using DMA mode\n");
- goto err_release;
- }
- }
-
/* all went well, so set can_dma */
ctlr->can_dma = bcm2835_spi_can_dma;
@@ -1082,9 +1044,10 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
struct spi_transfer *tfr)
{
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+ struct bcm2835_spidev *slv = spi_get_ctldata(spi);
unsigned long spi_hz, clk_hz, cdiv;
unsigned long hz_per_byte, byte_limit;
- u32 cs = bs->prepare_cs[spi->chip_select];
+ u32 cs = slv->prepare_cs;
/* set clock */
spi_hz = tfr->speed_hz;
@@ -1133,7 +1096,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
* this 1 idle clock cycle pattern but runs the spi clock without gaps
*/
if (ctlr->can_dma && bcm2835_spi_can_dma(ctlr, spi, tfr))
- return bcm2835_spi_transfer_one_dma(ctlr, spi, tfr, cs);
+ return bcm2835_spi_transfer_one_dma(ctlr, tfr, slv, cs);
/* run in interrupt-mode */
return bcm2835_spi_transfer_one_irq(ctlr, spi, tfr, cs, true);
@@ -1144,6 +1107,7 @@ static int bcm2835_spi_prepare_message(struct spi_controller *ctlr,
{
struct spi_device *spi = msg->spi;
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+ struct bcm2835_spidev *slv = spi_get_ctldata(spi);
int ret;
if (ctlr->can_dma) {
@@ -1162,7 +1126,7 @@ static int bcm2835_spi_prepare_message(struct spi_controller *ctlr,
* Set up clock polarity before spi_transfer_one_message() asserts
* chip select to avoid a gratuitous clock signal edge.
*/
- bcm2835_wr(bs, BCM2835_SPI_CS, bs->prepare_cs[spi->chip_select]);
+ bcm2835_wr(bs, BCM2835_SPI_CS, slv->prepare_cs);
return 0;
}
@@ -1188,17 +1152,81 @@ static int chip_match_name(struct gpio_chip *chip, void *data)
return !strcmp(chip->label, data);
}
+static void bcm2835_spi_cleanup(struct spi_device *spi)
+{
+ struct bcm2835_spidev *slv = spi_get_ctldata(spi);
+ struct spi_controller *ctlr = spi->controller;
+
+ if (slv->clear_rx_desc)
+ dmaengine_desc_free(slv->clear_rx_desc);
+
+ if (slv->clear_rx_addr)
+ dma_unmap_single(ctlr->dma_rx->device->dev,
+ slv->clear_rx_addr,
+ sizeof(u32),
+ DMA_TO_DEVICE);
+
+ kfree(slv);
+}
+
+static int bcm2835_spi_setup_dma(struct spi_controller *ctlr,
+ struct spi_device *spi,
+ struct bcm2835_spi *bs,
+ struct bcm2835_spidev *slv)
+{
+ int ret;
+
+ if (!ctlr->dma_rx)
+ return 0;
+
+ slv->clear_rx_addr = dma_map_single(ctlr->dma_rx->device->dev,
+ &slv->clear_rx_cs,
+ sizeof(u32),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ctlr->dma_rx->device->dev, slv->clear_rx_addr)) {
+ dev_err(&spi->dev, "cannot map clear_rx_cs\n");
+ slv->clear_rx_addr = 0;
+ return -ENOMEM;
+ }
+
+ slv->clear_rx_desc = dmaengine_prep_dma_cyclic(ctlr->dma_rx,
+ slv->clear_rx_addr,
+ sizeof(u32), 0,
+ DMA_MEM_TO_DEV, 0);
+ if (!slv->clear_rx_desc) {
+ dev_err(&spi->dev, "cannot prepare clear_rx_desc\n");
+ return -ENOMEM;
+ }
+
+ ret = dmaengine_desc_set_reuse(slv->clear_rx_desc);
+ if (ret) {
+ dev_err(&spi->dev, "cannot reuse clear_rx_desc\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static int bcm2835_spi_setup(struct spi_device *spi)
{
struct spi_controller *ctlr = spi->controller;
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+ struct bcm2835_spidev *slv = spi_get_ctldata(spi);
struct gpio_chip *chip;
+ int ret;
u32 cs;
- if (spi->chip_select >= BCM2835_SPI_NUM_CS) {
- dev_err(&spi->dev, "only %d chip-selects supported\n",
- BCM2835_SPI_NUM_CS - 1);
- return -EINVAL;
+ if (!slv) {
+ slv = kzalloc(ALIGN(sizeof(*slv), dma_get_cache_alignment()),
+ GFP_KERNEL);
+ if (!slv)
+ return -ENOMEM;
+
+ spi_set_ctldata(spi, slv);
+
+ ret = bcm2835_spi_setup_dma(ctlr, spi, bs, slv);
+ if (ret)
+ goto err_cleanup;
}
/*
@@ -1212,20 +1240,19 @@ static int bcm2835_spi_setup(struct spi_device *spi)
cs |= BCM2835_SPI_CS_CPOL;
if (spi->mode & SPI_CPHA)
cs |= BCM2835_SPI_CS_CPHA;
- bs->prepare_cs[spi->chip_select] = cs;
+ slv->prepare_cs = cs;
/*
* Precalculate SPI slave's CS register value to clear RX FIFO
* in case of a TX-only DMA transfer.
*/
if (ctlr->dma_rx) {
- bs->clear_rx_cs[spi->chip_select] = cs |
- BCM2835_SPI_CS_TA |
- BCM2835_SPI_CS_DMAEN |
- BCM2835_SPI_CS_CLEAR_RX;
+ slv->clear_rx_cs = cs | BCM2835_SPI_CS_TA |
+ BCM2835_SPI_CS_DMAEN |
+ BCM2835_SPI_CS_CLEAR_RX;
dma_sync_single_for_device(ctlr->dma_rx->device->dev,
- bs->clear_rx_addr,
- sizeof(bs->clear_rx_cs),
+ slv->clear_rx_addr,
+ sizeof(u32),
DMA_TO_DEVICE);
}
@@ -1247,7 +1274,8 @@ static int bcm2835_spi_setup(struct spi_device *spi)
*/
dev_err(&spi->dev,
"setup: only two native chip-selects are supported\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_cleanup;
}
/*
@@ -1268,14 +1296,20 @@ static int bcm2835_spi_setup(struct spi_device *spi)
DRV_NAME,
GPIO_LOOKUP_FLAGS_DEFAULT,
GPIOD_OUT_LOW);
- if (IS_ERR(spi->cs_gpiod))
- return PTR_ERR(spi->cs_gpiod);
+ if (IS_ERR(spi->cs_gpiod)) {
+ ret = PTR_ERR(spi->cs_gpiod);
+ goto err_cleanup;
+ }
/* and set up the "mode" and level */
dev_info(&spi->dev, "setting up native-CS%i to use GPIO\n",
spi->chip_select);
return 0;
+
+err_cleanup:
+ bcm2835_spi_cleanup(spi);
+ return ret;
}
static int bcm2835_spi_probe(struct platform_device *pdev)
@@ -1284,8 +1318,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
struct bcm2835_spi *bs;
int err;
- ctlr = devm_spi_alloc_master(&pdev->dev, ALIGN(sizeof(*bs),
- dma_get_cache_alignment()));
+ ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*bs));
if (!ctlr)
return -ENOMEM;
@@ -1296,6 +1329,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
ctlr->num_chipselect = 3;
ctlr->setup = bcm2835_spi_setup;
+ ctlr->cleanup = bcm2835_spi_cleanup;
ctlr->transfer_one = bcm2835_spi_transfer_one;
ctlr->handle_err = bcm2835_spi_handle_err;
ctlr->prepare_message = bcm2835_spi_prepare_message;
diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
index 75589ac6e95f..37eab100a7d8 100644
--- a/drivers/spi/spi-bcm2835aux.c
+++ b/drivers/spi/spi-bcm2835aux.c
@@ -384,7 +384,7 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
bs->pending = 0;
/* Calculate the estimated time in us the transfer runs. Note that
- * there are are 2 idle clocks cycles after each chunk getting
+ * there are 2 idle clocks cycles after each chunk getting
* transferred - in our case the chunk size is 3 bytes, so we
* approximate this by 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
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index 17c06039a74d..3379720cfcb8 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -56,7 +56,7 @@ struct dw_spi_mscc {
/*
* The Designware SPI controller (referred to as master in the documentation)
* automatically deasserts chip select when the tx fifo is empty. The chip
- * selects then needs to be either driven as GPIOs or, for the first 4 using the
+ * selects then needs to be either driven as GPIOs or, for the first 4 using
* the SPI boot controller registers. the final chip select is an OR gate
* between the Designware SPI controller and the SPI boot controller.
*/
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 3d0d8ddd5772..b3861fb88711 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -639,8 +639,8 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
complete(&mas->abort_done);
/*
- * It's safe or a good idea to Ack all of our our interrupts at the
- * end of the function. Specifically:
+ * It's safe or a good idea to Ack all of our interrupts at the end
+ * of the function. Specifically:
* - M_CMD_DONE_EN / M_RX_FIFO_LAST_EN: Edge triggered interrupts and
* clearing Acks. Clearing at the end relies on nobody else having
* started a new transfer yet or else we could be clearing _their_
diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c
index 3f986ba1c328..58b823a16fc4 100644
--- a/drivers/spi/spi-hisi-kunpeng.c
+++ b/drivers/spi/spi-hisi-kunpeng.c
@@ -9,6 +9,7 @@
#include <linux/acpi.h>
#include <linux/bitfield.h>
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/interrupt.h>
@@ -126,6 +127,7 @@ struct hisi_spi {
void __iomem *regs;
int irq;
u32 fifo_len; /* depth of the FIFO buffer */
+ u16 bus_num;
/* Current message transfer state info */
const void *tx;
@@ -133,8 +135,49 @@ struct hisi_spi {
void *rx;
unsigned int rx_len;
u8 n_bytes; /* current is a 1/2/4 bytes op */
+
+ struct dentry *debugfs;
+ struct debugfs_regset32 regset;
+};
+
+#define HISI_SPI_DBGFS_REG(_name, _off) \
+{ \
+ .name = _name, \
+ .offset = _off, \
+}
+
+static const struct debugfs_reg32 hisi_spi_regs[] = {
+ HISI_SPI_DBGFS_REG("CSCR", HISI_SPI_CSCR),
+ HISI_SPI_DBGFS_REG("CR", HISI_SPI_CR),
+ HISI_SPI_DBGFS_REG("ENR", HISI_SPI_ENR),
+ HISI_SPI_DBGFS_REG("FIFOC", HISI_SPI_FIFOC),
+ HISI_SPI_DBGFS_REG("IMR", HISI_SPI_IMR),
+ HISI_SPI_DBGFS_REG("DIN", HISI_SPI_DIN),
+ HISI_SPI_DBGFS_REG("DOUT", HISI_SPI_DOUT),
+ HISI_SPI_DBGFS_REG("SR", HISI_SPI_SR),
+ HISI_SPI_DBGFS_REG("RISR", HISI_SPI_RISR),
+ HISI_SPI_DBGFS_REG("ISR", HISI_SPI_ISR),
+ HISI_SPI_DBGFS_REG("ICR", HISI_SPI_ICR),
+ HISI_SPI_DBGFS_REG("VERSION", HISI_SPI_VERSION),
};
+static int hisi_spi_debugfs_init(struct hisi_spi *hs)
+{
+ char name[32];
+
+ snprintf(name, 32, "hisi_spi%d", hs->bus_num);
+ hs->debugfs = debugfs_create_dir(name, NULL);
+ if (!hs->debugfs)
+ return -ENOMEM;
+
+ hs->regset.regs = hisi_spi_regs;
+ hs->regset.nregs = ARRAY_SIZE(hisi_spi_regs);
+ hs->regset.base = hs->regs;
+ debugfs_create_regset32("registers", 0400, hs->debugfs, &hs->regset);
+
+ return 0;
+}
+
static u32 hisi_spi_busy(struct hisi_spi *hs)
{
return readl(hs->regs + HISI_SPI_SR) & SR_BUSY;
@@ -424,6 +467,7 @@ static int hisi_spi_probe(struct platform_device *pdev)
hs = spi_controller_get_devdata(master);
hs->dev = dev;
hs->irq = irq;
+ hs->bus_num = pdev->id;
hs->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(hs->regs))
@@ -446,7 +490,7 @@ static int hisi_spi_probe(struct platform_device *pdev)
master->use_gpio_descriptors = true;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
- master->bus_num = pdev->id;
+ master->bus_num = hs->bus_num;
master->setup = hisi_spi_setup;
master->cleanup = hisi_spi_cleanup;
master->transfer_one = hisi_spi_transfer_one;
@@ -462,6 +506,9 @@ static int hisi_spi_probe(struct platform_device *pdev)
return ret;
}
+ if (hisi_spi_debugfs_init(hs))
+ dev_info(dev, "failed to create debugfs dir\n");
+
ret = spi_register_controller(master);
if (ret) {
dev_err(dev, "failed to register spi master, ret=%d\n", ret);
@@ -478,7 +525,9 @@ static int hisi_spi_probe(struct platform_device *pdev)
static int hisi_spi_remove(struct platform_device *pdev)
{
struct spi_controller *master = platform_get_drvdata(pdev);
+ struct hisi_spi *hs = spi_controller_get_devdata(master);
+ debugfs_remove_recursive(hs->debugfs);
spi_unregister_controller(master);
return 0;
diff --git a/drivers/spi/spi-lm70llp.c b/drivers/spi/spi-lm70llp.c
index f914b8d2043e..ead0507c63be 100644
--- a/drivers/spi/spi-lm70llp.c
+++ b/drivers/spi/spi-lm70llp.c
@@ -202,7 +202,7 @@ static void spi_lm70llp_attach(struct parport *p)
* the lm70 driver could verify it, reading the manf ID.
*/
- master = spi_alloc_master(p->physport->dev, sizeof *pp);
+ master = spi_alloc_master(p->physport->dev, sizeof(*pp));
if (!master) {
status = -ENOMEM;
goto out_fail;
diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c
index f1cf2232f0b5..4d4f77a186a9 100644
--- a/drivers/spi/spi-loopback-test.c
+++ b/drivers/spi/spi-loopback-test.c
@@ -875,7 +875,7 @@ static int spi_test_run_iter(struct spi_device *spi,
test.transfers[i].len = len;
if (test.transfers[i].tx_buf)
test.transfers[i].tx_buf += tx_off;
- if (test.transfers[i].tx_buf)
+ if (test.transfers[i].rx_buf)
test.transfers[i].rx_buf += rx_off;
}
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 1513553e4080..37f4443ce9a0 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -6,6 +6,7 @@
* Author: Boris Brezillon <boris.brezillon@bootlin.com>
*/
#include <linux/dmaengine.h>
+#include <linux/iopoll.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
@@ -743,6 +744,91 @@ static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv)
return container_of(drv, struct spi_mem_driver, spidrv.driver);
}
+static int spi_mem_read_status(struct spi_mem *mem,
+ const struct spi_mem_op *op,
+ u16 *status)
+{
+ const u8 *bytes = (u8 *)op->data.buf.in;
+ int ret;
+
+ ret = spi_mem_exec_op(mem, op);
+ if (ret)
+ return ret;
+
+ if (op->data.nbytes > 1)
+ *status = ((u16)bytes[0] << 8) | bytes[1];
+ else
+ *status = bytes[0];
+
+ return 0;
+}
+
+/**
+ * spi_mem_poll_status() - Poll memory device status
+ * @mem: SPI memory device
+ * @op: the memory operation to execute
+ * @mask: status bitmask to ckeck
+ * @match: (status & mask) expected value
+ * @initial_delay_us: delay in us before starting to poll
+ * @polling_delay_us: time to sleep between reads in us
+ * @timeout_ms: timeout in milliseconds
+ *
+ * This function polls a status register and returns when
+ * (status & mask) == match or when the timeout has expired.
+ *
+ * Return: 0 in case of success, -ETIMEDOUT in case of error,
+ * -EOPNOTSUPP if not supported.
+ */
+int spi_mem_poll_status(struct spi_mem *mem,
+ const struct spi_mem_op *op,
+ u16 mask, u16 match,
+ unsigned long initial_delay_us,
+ unsigned long polling_delay_us,
+ u16 timeout_ms)
+{
+ struct spi_controller *ctlr = mem->spi->controller;
+ int ret = -EOPNOTSUPP;
+ int read_status_ret;
+ u16 status;
+
+ if (op->data.nbytes < 1 || op->data.nbytes > 2 ||
+ op->data.dir != SPI_MEM_DATA_IN)
+ return -EINVAL;
+
+ if (ctlr->mem_ops && ctlr->mem_ops->poll_status) {
+ ret = spi_mem_access_start(mem);
+ if (ret)
+ return ret;
+
+ ret = ctlr->mem_ops->poll_status(mem, op, mask, match,
+ initial_delay_us, polling_delay_us,
+ timeout_ms);
+
+ spi_mem_access_end(mem);
+ }
+
+ if (ret == -EOPNOTSUPP) {
+ if (!spi_mem_supports_op(mem, op))
+ return ret;
+
+ if (initial_delay_us < 10)
+ udelay(initial_delay_us);
+ else
+ usleep_range((initial_delay_us >> 2) + 1,
+ initial_delay_us);
+
+ ret = read_poll_timeout(spi_mem_read_status, read_status_ret,
+ (read_status_ret || ((status) & mask) == match),
+ polling_delay_us, timeout_ms * 1000, false, mem,
+ op, &status);
+ if (read_status_ret)
+ return read_status_ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(spi_mem_poll_status);
+
static int spi_mem_probe(struct spi_device *spi)
{
struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver);
@@ -810,7 +896,7 @@ int spi_mem_driver_register_with_owner(struct spi_mem_driver *memdrv,
EXPORT_SYMBOL_GPL(spi_mem_driver_register_with_owner);
/**
- * spi_mem_driver_unregister_with_owner() - Unregister a SPI memory driver
+ * spi_mem_driver_unregister() - Unregister a SPI memory driver
* @memdrv: the SPI memory driver to unregister
*
* Unregisters a SPI memory driver.
diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c
index ecba6b4a5d85..b2c4621db34d 100644
--- a/drivers/spi/spi-meson-spicc.c
+++ b/drivers/spi/spi-meson-spicc.c
@@ -725,7 +725,7 @@ static int meson_spicc_probe(struct platform_device *pdev)
ret = clk_prepare_enable(spicc->pclk);
if (ret) {
dev_err(&pdev->dev, "pclk clock enable failed\n");
- goto out_master;
+ goto out_core_clk;
}
device_reset_optional(&pdev->dev);
@@ -752,7 +752,7 @@ static int meson_spicc_probe(struct platform_device *pdev)
ret = meson_spicc_clk_init(spicc);
if (ret) {
dev_err(&pdev->dev, "clock registration failed\n");
- goto out_master;
+ goto out_clk;
}
ret = devm_spi_register_master(&pdev->dev, master);
@@ -764,9 +764,11 @@ static int meson_spicc_probe(struct platform_device *pdev)
return 0;
out_clk:
- clk_disable_unprepare(spicc->core);
clk_disable_unprepare(spicc->pclk);
+out_core_clk:
+ clk_disable_unprepare(spicc->core);
+
out_master:
spi_master_put(master);
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index ea1b07953d38..78a9bca8cc68 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -369,7 +369,7 @@ static int mpc512x_psc_spi_setup(struct spi_device *spi)
return -EINVAL;
if (!cs) {
- cs = kzalloc(sizeof *cs, GFP_KERNEL);
+ cs = kzalloc(sizeof(*cs), GFP_KERNEL);
if (!cs)
return -ENOMEM;
@@ -491,7 +491,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
void *tempp;
struct clk *clk;
- master = spi_alloc_master(dev, sizeof *mps);
+ master = spi_alloc_master(dev, sizeof(*mps));
if (master == NULL)
return -ENOMEM;
diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c
index 17935e71b02f..21ef5d481faf 100644
--- a/drivers/spi/spi-mpc52xx-psc.c
+++ b/drivers/spi/spi-mpc52xx-psc.c
@@ -265,7 +265,7 @@ static int mpc52xx_psc_spi_setup(struct spi_device *spi)
return -EINVAL;
if (!cs) {
- cs = kzalloc(sizeof *cs, GFP_KERNEL);
+ cs = kzalloc(sizeof(*cs), GFP_KERNEL);
if (!cs)
return -ENOMEM;
spi->controller_state = cs;
@@ -365,7 +365,7 @@ static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
struct spi_master *master;
int ret;
- master = spi_alloc_master(dev, sizeof *mps);
+ master = spi_alloc_master(dev, sizeof(*mps));
if (master == NULL)
return -ENOMEM;
diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c
index 124cba7213f1..51041526546d 100644
--- a/drivers/spi/spi-mpc52xx.c
+++ b/drivers/spi/spi-mpc52xx.c
@@ -415,7 +415,7 @@ static int mpc52xx_spi_probe(struct platform_device *op)
}
dev_dbg(&op->dev, "allocating spi_master struct\n");
- master = spi_alloc_master(&op->dev, sizeof *ms);
+ master = spi_alloc_master(&op->dev, sizeof(*ms));
if (!master) {
rc = -ENOMEM;
goto err_alloc;
diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c
index 56d10c4511db..1668a347e003 100644
--- a/drivers/spi/spi-npcm-pspi.c
+++ b/drivers/spi/spi-npcm-pspi.c
@@ -105,7 +105,7 @@ static void npcm_pspi_set_mode(struct spi_device *spi)
u16 regtemp;
u16 mode_val;
- switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
+ switch (spi->mode & SPI_MODE_X_MASK) {
case SPI_MODE_0:
mode_val = 0;
break;
diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c
index 6e6c2403944d..a66fa97046ee 100644
--- a/drivers/spi/spi-nxp-fspi.c
+++ b/drivers/spi/spi-nxp-fspi.c
@@ -1124,12 +1124,6 @@ static int nxp_fspi_probe(struct platform_device *pdev)
goto err_put_ctrl;
}
- /* Clear potential interrupts */
- reg = fspi_readl(f, f->iobase + FSPI_INTR);
- if (reg)
- fspi_writel(f, reg, f->iobase + FSPI_INTR);
-
-
/* find the resources - controller memory mapped space */
if (is_acpi_node(f->dev->fwnode))
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -1167,6 +1161,11 @@ static int nxp_fspi_probe(struct platform_device *pdev)
}
}
+ /* Clear potential interrupts */
+ reg = fspi_readl(f, f->iobase + FSPI_INTR);
+ if (reg)
+ fspi_writel(f, reg, f->iobase + FSPI_INTR);
+
/* find the irq */
ret = platform_get_irq(pdev, 0);
if (ret < 0)
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c
index f3843f0ff260..38c14c4e4e21 100644
--- a/drivers/spi/spi-oc-tiny.c
+++ b/drivers/spi/spi-oc-tiny.c
@@ -86,7 +86,7 @@ static int tiny_spi_setup(struct spi_device *spi)
hw->speed_hz = spi->max_speed_hz;
hw->baud = tiny_spi_baud(spi, hw->speed_hz);
}
- hw->mode = spi->mode & (SPI_CPOL | SPI_CPHA);
+ hw->mode = spi->mode & SPI_MODE_X_MASK;
return 0;
}
diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c
index 7062f2902253..20b047172965 100644
--- a/drivers/spi/spi-omap-100k.c
+++ b/drivers/spi/spi-omap-100k.c
@@ -6,7 +6,7 @@
*
* Copyright (C) 2005, 2006 Nokia Corporation
* Author: Samuel Ortiz <samuel.ortiz@nokia.com> and
- * Juha Yrj�l� <juha.yrjola@nokia.com>
+ * Juha Yrjola <juha.yrjola@nokia.com>
*/
#include <linux/kernel.h>
#include <linux/init.h>
@@ -241,7 +241,7 @@ static int omap1_spi100k_setup_transfer(struct spi_device *spi,
else
word_len = spi->bits_per_word;
- if (spi->bits_per_word > 32)
+ if (word_len > 32)
return -EINVAL;
cs->word_len = word_len;
@@ -296,7 +296,6 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master,
list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
- status = -EINVAL;
break;
}
status = omap1_spi100k_setup_transfer(spi, t);
@@ -315,7 +314,6 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master,
m->actual_length += count;
if (count != t->len) {
- status = -EIO;
break;
}
}
diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c
index df28c6664aba..087172a193fa 100644
--- a/drivers/spi/spi-omap-uwire.c
+++ b/drivers/spi/spi-omap-uwire.c
@@ -330,7 +330,7 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
if (spi->mode & SPI_CPOL)
flags |= UWIRE_CLK_INVERTED;
- switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
+ switch (spi->mode & SPI_MODE_X_MASK) {
case SPI_MODE_0:
case SPI_MODE_3:
flags |= UWIRE_WRITE_FALLING_EDGE | UWIRE_READ_RISING_EDGE;
@@ -460,7 +460,7 @@ static int uwire_probe(struct platform_device *pdev)
struct uwire_spi *uwire;
int status;
- master = spi_alloc_master(&pdev->dev, sizeof *uwire);
+ master = spi_alloc_master(&pdev->dev, sizeof(*uwire));
if (!master)
return -ENODEV;
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index ede7f05e5ced..60c9cdf1c94b 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2005, 2006 Nokia Corporation
* Author: Samuel Ortiz <samuel.ortiz@nokia.com> and
- * Juha Yrj�l� <juha.yrjola@nokia.com>
+ * Juha Yrjola <juha.yrjola@nokia.com>
*/
#include <linux/kernel.h>
@@ -1054,7 +1054,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
struct omap2_mcspi_cs *cs = spi->controller_state;
if (!cs) {
- cs = kzalloc(sizeof *cs, GFP_KERNEL);
+ cs = kzalloc(sizeof(*cs), GFP_KERNEL);
if (!cs)
return -ENOMEM;
cs->base = mcspi->base + spi->chip_select * 0x14;
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 0c9e3f270f05..feebda66f56e 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -288,7 +288,7 @@
#define SPI_POLLING_TIMEOUT 1000
/*
- * The type of reading going on on this chip
+ * The type of reading going on this chip
*/
enum ssp_reading {
READING_NULL,
@@ -298,7 +298,7 @@ enum ssp_reading {
};
/*
- * The type of writing going on on this chip
+ * The type of writing going on this chip
*/
enum ssp_writing {
WRITING_NULL,
diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c
index d8ee363fb714..d65f047b6c82 100644
--- a/drivers/spi/spi-ppc4xx.c
+++ b/drivers/spi/spi-ppc4xx.c
@@ -34,7 +34,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/dcr.h>
#include <asm/dcr-regs.h>
@@ -223,7 +223,7 @@ static int spi_ppc4xx_setup(struct spi_device *spi)
}
if (cs == NULL) {
- cs = kzalloc(sizeof *cs, GFP_KERNEL);
+ cs = kzalloc(sizeof(*cs), GFP_KERNEL);
if (!cs)
return -ENOMEM;
spi->controller_state = cs;
@@ -235,7 +235,7 @@ static int spi_ppc4xx_setup(struct spi_device *spi)
*/
cs->mode = SPI_PPC4XX_MODE_SPE;
- switch (spi->mode & (SPI_CPHA | SPI_CPOL)) {
+ switch (spi->mode & SPI_MODE_X_MASK) {
case SPI_MODE_0:
cs->mode |= SPI_CLK_MODE0;
break;
@@ -326,7 +326,7 @@ static void spi_ppc4xx_enable(struct ppc4xx_spi *hw)
{
/*
* On all 4xx PPC's the SPI bus is shared/multiplexed with
- * the 2nd I2C bus. We need to enable the the SPI bus before
+ * the 2nd I2C bus. We need to enable the SPI bus before
* using it.
*/
@@ -349,7 +349,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
int ret;
const unsigned int *clk;
- master = spi_alloc_master(dev, sizeof *hw);
+ master = spi_alloc_master(dev, sizeof(*hw));
if (master == NULL)
return -ENOMEM;
master->dev.of_node = np;
diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c
index 37567bc7a523..be563f0dd03a 100644
--- a/drivers/spi/spi-pxa2xx-dma.c
+++ b/drivers/spi/spi-pxa2xx-dma.c
@@ -2,18 +2,18 @@
/*
* PXA2xx SPI DMA engine support.
*
- * Copyright (C) 2013, Intel Corporation
+ * Copyright (C) 2013, 2021 Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
*/
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
-#include <linux/pxa2xx_ssp.h>
#include <linux/scatterlist.h>
#include <linux/sizes.h>
-#include <linux/spi/spi.h>
+
#include <linux/spi/pxa2xx_spi.h>
+#include <linux/spi/spi.h>
#include "spi-pxa2xx.h"
@@ -26,7 +26,7 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
* It is possible that one CPU is handling ROR interrupt and other
* just gets DMA completion. Calling pump_transfers() twice for the
* same transfer leads to problems thus we prevent concurrent calls
- * by using ->dma_running.
+ * by using dma_running.
*/
if (atomic_dec_and_test(&drv_data->dma_running)) {
/*
@@ -34,25 +34,18 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
* might not know about the error yet. So we re-check the
* ROR bit here before we clear the status register.
*/
- if (!error) {
- u32 status = pxa2xx_spi_read(drv_data, SSSR)
- & drv_data->mask_sr;
- error = status & SSSR_ROR;
- }
+ if (!error)
+ error = read_SSSR_bits(drv_data, drv_data->mask_sr) & SSSR_ROR;
/* Clear status & disable interrupts */
- pxa2xx_spi_write(drv_data, SSCR1,
- pxa2xx_spi_read(drv_data, SSCR1)
- & ~drv_data->dma_cr1);
+ clear_SSCR1_bits(drv_data, drv_data->dma_cr1);
write_SSSR_CS(drv_data, drv_data->clear_sr);
if (!pxa25x_ssp_comp(drv_data))
pxa2xx_spi_write(drv_data, SSTO, 0);
if (error) {
/* In case we got an error we disable the SSP now */
- pxa2xx_spi_write(drv_data, SSCR0,
- pxa2xx_spi_read(drv_data, SSCR0)
- & ~SSCR0_SSE);
+ pxa_ssp_disable(drv_data->ssp);
msg->status = -EIO;
}
@@ -94,14 +87,14 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
cfg.direction = dir;
if (dir == DMA_MEM_TO_DEV) {
- cfg.dst_addr = drv_data->ssdr_physical;
+ cfg.dst_addr = drv_data->ssp->phys_base + SSDR;
cfg.dst_addr_width = width;
cfg.dst_maxburst = chip->dma_burst_size;
sgt = &xfer->tx_sg;
chan = drv_data->controller->dma_tx;
} else {
- cfg.src_addr = drv_data->ssdr_physical;
+ cfg.src_addr = drv_data->ssp->phys_base + SSDR;
cfg.src_addr_width = width;
cfg.src_maxburst = chip->dma_burst_size;
@@ -111,7 +104,7 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
ret = dmaengine_slave_config(chan, &cfg);
if (ret) {
- dev_warn(&drv_data->pdev->dev, "DMA slave config failed\n");
+ dev_warn(drv_data->ssp->dev, "DMA slave config failed\n");
return NULL;
}
@@ -123,9 +116,9 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
{
u32 status;
- status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr;
+ status = read_SSSR_bits(drv_data, drv_data->mask_sr);
if (status & SSSR_ROR) {
- dev_err(&drv_data->pdev->dev, "FIFO overrun\n");
+ dev_err(drv_data->ssp->dev, "FIFO overrun\n");
dmaengine_terminate_async(drv_data->controller->dma_rx);
dmaengine_terminate_async(drv_data->controller->dma_tx);
@@ -145,16 +138,14 @@ int pxa2xx_spi_dma_prepare(struct driver_data *drv_data,
tx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_MEM_TO_DEV, xfer);
if (!tx_desc) {
- dev_err(&drv_data->pdev->dev,
- "failed to get DMA TX descriptor\n");
+ dev_err(drv_data->ssp->dev, "failed to get DMA TX descriptor\n");
err = -EBUSY;
goto err_tx;
}
rx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_DEV_TO_MEM, xfer);
if (!rx_desc) {
- dev_err(&drv_data->pdev->dev,
- "failed to get DMA RX descriptor\n");
+ dev_err(drv_data->ssp->dev, "failed to get DMA RX descriptor\n");
err = -EBUSY;
goto err_rx;
}
@@ -191,8 +182,8 @@ void pxa2xx_spi_dma_stop(struct driver_data *drv_data)
int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
{
struct pxa2xx_spi_controller *pdata = drv_data->controller_info;
- struct device *dev = &drv_data->pdev->dev;
struct spi_controller *controller = drv_data->controller;
+ struct device *dev = drv_data->ssp->dev;
dma_cap_mask_t mask;
dma_cap_zero(mask);
diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
index 1833f5876e9f..2e134eb4bd2c 100644
--- a/drivers/spi/spi-pxa2xx-pci.c
+++ b/drivers/spi/spi-pxa2xx-pci.c
@@ -1,13 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * CE4100's SPI device is more or less the same one as found on PXA
+ * PCI glue driver for SPI PXA2xx compatible controllers.
+ * CE4100's SPI device is more or less the same one as found on PXA.
*
- * Copyright (C) 2016, Intel Corporation
+ * Copyright (C) 2016, 2021 Intel Corporation
*/
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
+
#include <linux/spi/pxa2xx_spi.h>
#include <linux/dmaengine.h>
@@ -178,7 +180,7 @@ static struct pxa_spi_info spi_info_configs[] = {
.rx_param = &bsw2_rx_param,
},
[PORT_MRFLD] = {
- .type = PXA27x_SSP,
+ .type = MRFLD_SSP,
.max_clk_rate = 25000000,
.setup = mrfld_spi_setup,
},
@@ -239,6 +241,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
spi_pdata.dma_burst_size = c->dma_burst_size ? c->dma_burst_size : 1;
ssp = &spi_pdata.ssp;
+ ssp->dev = &dev->dev;
ssp->phys_base = pci_resource_start(dev, 0);
ssp->mmio_base = pcim_iomap_table(dev)[0];
ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn;
@@ -254,7 +257,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id);
ssp->clk = clk_register_fixed_rate(&dev->dev, buf, NULL, 0,
c->max_clk_rate);
- if (IS_ERR(ssp->clk))
+ if (IS_ERR(ssp->clk))
return PTR_ERR(ssp->clk);
memset(&pi, 0, sizeof(pi));
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index 8ee0cc071777..974e30744b83 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
- * Copyright (C) 2013, Intel Corporation
+ * Copyright (C) 2013, 2021 Intel Corporation
*/
#include <linux/acpi.h>
@@ -9,6 +9,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/dmaengine.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gpio/consumer.h>
@@ -25,6 +26,7 @@
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/slab.h>
+
#include <linux/spi/pxa2xx_spi.h>
#include <linux/spi/spi.h>
@@ -38,11 +40,11 @@ MODULE_ALIAS("platform:pxa2xx-spi");
#define TIMOUT_DFLT 1000
/*
- * for testing SSCR1 changes that require SSP restart, basically
- * everything except the service and interrupt enables, the pxa270 developer
+ * For testing SSCR1 changes that require SSP restart, basically
+ * everything except the service and interrupt enables, the PXA270 developer
* manual says only SSCR1_SCFR, SSCR1_SPH, SSCR1_SPO need to be in this
- * list, but the PXA255 dev man says all bits without really meaning the
- * service and interrupt enables
+ * list, but the PXA255 developer manual says all bits without really meaning
+ * the service and interrupt enables.
*/
#define SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_SCFR \
| SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \
@@ -198,6 +200,17 @@ static bool is_mmp2_ssp(const struct driver_data *drv_data)
return drv_data->ssp_type == MMP2_SSP;
}
+static bool is_mrfld_ssp(const struct driver_data *drv_data)
+{
+ return drv_data->ssp_type == MRFLD_SSP;
+}
+
+static void pxa2xx_spi_update(const struct driver_data *drv_data, u32 reg, u32 mask, u32 value)
+{
+ if ((pxa2xx_spi_read(drv_data, reg) & mask) != value)
+ pxa2xx_spi_write(drv_data, reg, value & mask);
+}
+
static u32 pxa2xx_spi_get_ssrc1_change_mask(const struct driver_data *drv_data)
{
switch (drv_data->ssp_type) {
@@ -239,7 +252,7 @@ static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data)
break;
}
- return (pxa2xx_spi_read(drv_data, SSSR) & mask) == mask;
+ return read_SSSR_bits(drv_data, mask) == mask;
}
static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data,
@@ -284,13 +297,11 @@ static u32 pxa2xx_configure_sscr0(const struct driver_data *drv_data,
case QUARK_X1000_SSP:
return clk_div
| QUARK_X1000_SSCR0_Motorola
- | QUARK_X1000_SSCR0_DataSize(bits > 32 ? 8 : bits)
- | SSCR0_SSE;
+ | QUARK_X1000_SSCR0_DataSize(bits > 32 ? 8 : bits);
default:
return clk_div
| SSCR0_Motorola
| SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
- | SSCR0_SSE
| (bits > 16 ? SSCR0_EDSS : 0);
}
}
@@ -325,7 +336,7 @@ static void lpss_ssp_setup(struct driver_data *drv_data)
u32 value;
config = lpss_get_config(drv_data);
- drv_data->lpss_base = drv_data->ioaddr + config->offset;
+ drv_data->lpss_base = drv_data->ssp->mmio_base + config->offset;
/* Enable software chip select control */
value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
@@ -421,7 +432,7 @@ static void cs_assert(struct spi_device *spi)
spi_controller_get_devdata(spi->controller);
if (drv_data->ssp_type == CE4100_SSP) {
- pxa2xx_spi_write(drv_data, SSSR, chip->frm);
+ pxa2xx_spi_write(drv_data, SSSR, spi->chip_select);
return;
}
@@ -430,11 +441,6 @@ static void cs_assert(struct spi_device *spi)
return;
}
- if (chip->gpiod_cs) {
- gpiod_set_value(chip->gpiod_cs, chip->gpio_cs_inverted);
- return;
- }
-
if (is_lpss_ssp(drv_data))
lpss_ssp_cs_control(spi, true);
}
@@ -460,11 +466,6 @@ static void cs_deassert(struct spi_device *spi)
return;
}
- if (chip->gpiod_cs) {
- gpiod_set_value(chip->gpiod_cs, !chip->gpio_cs_inverted);
- return;
- }
-
if (is_lpss_ssp(drv_data))
lpss_ssp_cs_control(spi, false);
}
@@ -482,7 +483,7 @@ int pxa2xx_spi_flush(struct driver_data *drv_data)
unsigned long limit = loops_per_jiffy << 1;
do {
- while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
+ while (read_SSSR_bits(drv_data, SSSR_RNE))
pxa2xx_spi_read(drv_data, SSDR);
} while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit);
write_SSSR_CS(drv_data, SSSR_ROR);
@@ -496,8 +497,7 @@ static void pxa2xx_spi_off(struct driver_data *drv_data)
if (is_mmp2_ssp(drv_data))
return;
- pxa2xx_spi_write(drv_data, SSCR0,
- pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE);
+ pxa_ssp_disable(drv_data->ssp);
}
static int null_writer(struct driver_data *drv_data)
@@ -518,8 +518,7 @@ static int null_reader(struct driver_data *drv_data)
{
u8 n_bytes = drv_data->n_bytes;
- while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
- && (drv_data->rx < drv_data->rx_end)) {
+ while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) {
pxa2xx_spi_read(drv_data, SSDR);
drv_data->rx += n_bytes;
}
@@ -541,8 +540,7 @@ static int u8_writer(struct driver_data *drv_data)
static int u8_reader(struct driver_data *drv_data)
{
- while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
- && (drv_data->rx < drv_data->rx_end)) {
+ while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) {
*(u8 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
++drv_data->rx;
}
@@ -564,8 +562,7 @@ static int u16_writer(struct driver_data *drv_data)
static int u16_reader(struct driver_data *drv_data)
{
- while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
- && (drv_data->rx < drv_data->rx_end)) {
+ while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) {
*(u16 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
drv_data->rx += 2;
}
@@ -587,8 +584,7 @@ static int u32_writer(struct driver_data *drv_data)
static int u32_reader(struct driver_data *drv_data)
{
- while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
- && (drv_data->rx < drv_data->rx_end)) {
+ while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) {
*(u32 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
drv_data->rx += 4;
}
@@ -618,47 +614,51 @@ static void reset_sccr1(struct driver_data *drv_data)
pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg);
}
-static void int_error_stop(struct driver_data *drv_data, const char *msg)
+static void int_stop_and_reset(struct driver_data *drv_data)
{
- /* Stop and reset SSP */
+ /* Clear and disable interrupts */
write_SSSR_CS(drv_data, drv_data->clear_sr);
reset_sccr1(drv_data);
- if (!pxa25x_ssp_comp(drv_data))
- pxa2xx_spi_write(drv_data, SSTO, 0);
+ if (pxa25x_ssp_comp(drv_data))
+ return;
+
+ pxa2xx_spi_write(drv_data, SSTO, 0);
+}
+
+static void int_error_stop(struct driver_data *drv_data, const char *msg, int err)
+{
+ int_stop_and_reset(drv_data);
pxa2xx_spi_flush(drv_data);
pxa2xx_spi_off(drv_data);
- dev_err(&drv_data->pdev->dev, "%s\n", msg);
+ dev_err(drv_data->ssp->dev, "%s\n", msg);
- drv_data->controller->cur_msg->status = -EIO;
+ drv_data->controller->cur_msg->status = err;
spi_finalize_current_transfer(drv_data->controller);
}
static void int_transfer_complete(struct driver_data *drv_data)
{
- /* Clear and disable interrupts */
- write_SSSR_CS(drv_data, drv_data->clear_sr);
- reset_sccr1(drv_data);
- if (!pxa25x_ssp_comp(drv_data))
- pxa2xx_spi_write(drv_data, SSTO, 0);
+ int_stop_and_reset(drv_data);
spi_finalize_current_transfer(drv_data->controller);
}
static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
{
- u32 irq_mask = (pxa2xx_spi_read(drv_data, SSCR1) & SSCR1_TIE) ?
- drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
+ u32 irq_status;
- u32 irq_status = pxa2xx_spi_read(drv_data, SSSR) & irq_mask;
+ irq_status = read_SSSR_bits(drv_data, drv_data->mask_sr);
+ if (!(pxa2xx_spi_read(drv_data, SSCR1) & SSCR1_TIE))
+ irq_status &= ~SSSR_TFS;
if (irq_status & SSSR_ROR) {
- int_error_stop(drv_data, "interrupt_transfer: fifo overrun");
+ int_error_stop(drv_data, "interrupt_transfer: FIFO overrun", -EIO);
return IRQ_HANDLED;
}
if (irq_status & SSSR_TUR) {
- int_error_stop(drv_data, "interrupt_transfer: fifo underrun");
+ int_error_stop(drv_data, "interrupt_transfer: FIFO underrun", -EIO);
return IRQ_HANDLED;
}
@@ -670,7 +670,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
}
}
- /* Drain rx fifo, Fill tx fifo and prevent overruns */
+ /* Drain Rx FIFO, Fill Tx FIFO and prevent overruns */
do {
if (drv_data->read(drv_data)) {
int_transfer_complete(drv_data);
@@ -691,8 +691,8 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
sccr1_reg &= ~SSCR1_TIE;
/*
- * PXA25x_SSP has no timeout, set up rx threshould for the
- * remaining RX bytes.
+ * PXA25x_SSP has no timeout, set up Rx threshold for
+ * the remaining Rx bytes.
*/
if (pxa25x_ssp_comp(drv_data)) {
u32 rx_thre;
@@ -725,14 +725,12 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
static void handle_bad_msg(struct driver_data *drv_data)
{
pxa2xx_spi_off(drv_data);
- pxa2xx_spi_write(drv_data, SSCR1,
- pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1);
+ clear_SSCR1_bits(drv_data, drv_data->int_cr1);
if (!pxa25x_ssp_comp(drv_data))
pxa2xx_spi_write(drv_data, SSTO, 0);
write_SSSR_CS(drv_data, drv_data->clear_sr);
- dev_err(&drv_data->pdev->dev,
- "bad message state in interrupt handler\n");
+ dev_err(drv_data->ssp->dev, "bad message state in interrupt handler\n");
}
static irqreturn_t ssp_int(int irq, void *dev_id)
@@ -748,7 +746,7 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
* the IRQ was not for us (we shouldn't be RPM suspended when the
* interrupt is enabled).
*/
- if (pm_runtime_suspended(&drv_data->pdev->dev))
+ if (pm_runtime_suspended(drv_data->ssp->dev))
return IRQ_NONE;
/*
@@ -916,7 +914,7 @@ static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
/*
* Calculate the divisor for the SCR (Serial Clock Rate), avoiding
- * that the SSP transmission rate can be greater than the device rate
+ * that the SSP transmission rate can be greater than the device rate.
*/
if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
return (DIV_ROUND_UP(ssp_clk, 2 * rate) - 1) & 0xff;
@@ -974,7 +972,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
/* Check if we can DMA this transfer */
if (transfer->len > MAX_DMA_LEN && chip->enable_dma) {
- /* reject already-mapped transfers; PIO won't always work */
+ /* Reject already-mapped transfers; PIO won't always work */
if (message->is_dma_mapped
|| transfer->rx_dma || transfer->tx_dma) {
dev_err(&spi->dev,
@@ -983,10 +981,10 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
return -EINVAL;
}
- /* warn ... we force this to PIO mode */
+ /* Warn ... we force this to PIO mode */
dev_warn_ratelimited(&spi->dev,
- "DMA disabled for transfer length %ld greater than %d\n",
- (long)transfer->len, MAX_DMA_LEN);
+ "DMA disabled for transfer length %u greater than %d\n",
+ transfer->len, MAX_DMA_LEN);
}
/* Setup the transfer state based on the type of transfer */
@@ -1028,8 +1026,8 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
u32_writer : null_writer;
}
/*
- * if bits/word is changed in dma mode, then must check the
- * thresholds and burst also
+ * If bits per word is changed in DMA mode, then must check
+ * the thresholds and burst also.
*/
if (chip->enable_dma) {
if (pxa2xx_spi_set_dma_burst_and_threshold(chip,
@@ -1080,47 +1078,45 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
dma_mapped ? "DMA" : "PIO");
if (is_lpss_ssp(drv_data)) {
- if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff)
- != chip->lpss_rx_threshold)
- pxa2xx_spi_write(drv_data, SSIRF,
- chip->lpss_rx_threshold);
- if ((pxa2xx_spi_read(drv_data, SSITF) & 0xffff)
- != chip->lpss_tx_threshold)
- pxa2xx_spi_write(drv_data, SSITF,
- chip->lpss_tx_threshold);
+ pxa2xx_spi_update(drv_data, SSIRF, GENMASK(7, 0), chip->lpss_rx_threshold);
+ pxa2xx_spi_update(drv_data, SSITF, GENMASK(15, 0), chip->lpss_tx_threshold);
}
- if (is_quark_x1000_ssp(drv_data) &&
- (pxa2xx_spi_read(drv_data, DDS_RATE) != chip->dds_rate))
- pxa2xx_spi_write(drv_data, DDS_RATE, chip->dds_rate);
-
- /* see if we need to reload the config registers */
- if ((pxa2xx_spi_read(drv_data, SSCR0) != cr0)
- || (pxa2xx_spi_read(drv_data, SSCR1) & change_mask)
- != (cr1 & change_mask)) {
- /* stop the SSP, and update the other bits */
- if (!is_mmp2_ssp(drv_data))
- pxa2xx_spi_write(drv_data, SSCR0, cr0 & ~SSCR0_SSE);
- if (!pxa25x_ssp_comp(drv_data))
- pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
- /* first set CR1 without interrupt and service enables */
- pxa2xx_spi_write(drv_data, SSCR1, cr1 & change_mask);
- /* restart the SSP */
- pxa2xx_spi_write(drv_data, SSCR0, cr0);
+ if (is_mrfld_ssp(drv_data)) {
+ u32 mask = SFIFOTT_RFT | SFIFOTT_TFT;
+ u32 thresh = 0;
- } else {
- if (!pxa25x_ssp_comp(drv_data))
- pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
+ thresh |= SFIFOTT_RxThresh(chip->lpss_rx_threshold);
+ thresh |= SFIFOTT_TxThresh(chip->lpss_tx_threshold);
+
+ pxa2xx_spi_update(drv_data, SFIFOTT, mask, thresh);
}
+ if (is_quark_x1000_ssp(drv_data))
+ pxa2xx_spi_update(drv_data, DDS_RATE, GENMASK(23, 0), chip->dds_rate);
+
+ /* Stop the SSP */
+ if (!is_mmp2_ssp(drv_data))
+ pxa_ssp_disable(drv_data->ssp);
+
+ if (!pxa25x_ssp_comp(drv_data))
+ pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
+
+ /* First set CR1 without interrupt and service enables */
+ pxa2xx_spi_update(drv_data, SSCR1, change_mask, cr1);
+
+ /* See if we need to reload the configuration registers */
+ pxa2xx_spi_update(drv_data, SSCR0, GENMASK(31, 0), cr0);
+
+ /* Restart the SSP */
+ pxa_ssp_enable(drv_data->ssp);
+
if (is_mmp2_ssp(drv_data)) {
- u8 tx_level = (pxa2xx_spi_read(drv_data, SSSR)
- & SSSR_TFL_MASK) >> 8;
+ u8 tx_level = read_SSSR_bits(drv_data, SSSR_TFL_MASK) >> 8;
if (tx_level) {
- /* On MMP2, flipping SSE doesn't to empty TXFIFO. */
- dev_warn(&spi->dev, "%d bytes of garbage in TXFIFO!\n",
- tx_level);
+ /* On MMP2, flipping SSE doesn't to empty Tx FIFO. */
+ dev_warn(&spi->dev, "%u bytes of garbage in Tx FIFO!\n", tx_level);
if (tx_level > transfer->len)
tx_level = transfer->len;
drv_data->tx += tx_level;
@@ -1139,7 +1135,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
/*
* Release the data by enabling service requests and interrupts,
- * without changing any mode bits
+ * without changing any mode bits.
*/
pxa2xx_spi_write(drv_data, SSCR1, cr1);
@@ -1150,18 +1146,7 @@ static int pxa2xx_spi_slave_abort(struct spi_controller *controller)
{
struct driver_data *drv_data = spi_controller_get_devdata(controller);
- /* Stop and reset SSP */
- write_SSSR_CS(drv_data, drv_data->clear_sr);
- reset_sccr1(drv_data);
- if (!pxa25x_ssp_comp(drv_data))
- pxa2xx_spi_write(drv_data, SSTO, 0);
- pxa2xx_spi_flush(drv_data);
- pxa2xx_spi_off(drv_data);
-
- dev_dbg(&drv_data->pdev->dev, "transfer aborted\n");
-
- drv_data->controller->cur_msg->status = -EINTR;
- spi_finalize_current_transfer(drv_data->controller);
+ int_error_stop(drv_data, "transfer aborted", -EINTR);
return 0;
}
@@ -1175,9 +1160,7 @@ static void pxa2xx_spi_handle_err(struct spi_controller *controller,
pxa2xx_spi_off(drv_data);
/* Clear and disable interrupts and service requests */
write_SSSR_CS(drv_data, drv_data->clear_sr);
- pxa2xx_spi_write(drv_data, SSCR1,
- pxa2xx_spi_read(drv_data, SSCR1)
- & ~(drv_data->int_cr1 | drv_data->dma_cr1));
+ clear_SSCR1_bits(drv_data, drv_data->int_cr1 | drv_data->dma_cr1);
if (!pxa25x_ssp_comp(drv_data))
pxa2xx_spi_write(drv_data, SSTO, 0);
@@ -1202,63 +1185,61 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_controller *controller)
return 0;
}
+static void cleanup_cs(struct spi_device *spi)
+{
+ if (!gpio_is_valid(spi->cs_gpio))
+ return;
+
+ gpio_free(spi->cs_gpio);
+ spi->cs_gpio = -ENOENT;
+}
+
static int setup_cs(struct spi_device *spi, struct chip_data *chip,
struct pxa2xx_spi_chip *chip_info)
{
- struct driver_data *drv_data =
- spi_controller_get_devdata(spi->controller);
- struct gpio_desc *gpiod;
- int err = 0;
+ struct driver_data *drv_data = spi_controller_get_devdata(spi->controller);
if (chip == NULL)
return 0;
- if (drv_data->cs_gpiods) {
- gpiod = drv_data->cs_gpiods[spi->chip_select];
- if (gpiod) {
- chip->gpiod_cs = gpiod;
- chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH;
- gpiod_set_value(gpiod, chip->gpio_cs_inverted);
- }
-
+ if (chip_info == NULL)
return 0;
- }
- if (chip_info == NULL)
+ if (drv_data->ssp_type == CE4100_SSP)
return 0;
- /* NOTE: setup() can be called multiple times, possibly with
- * different chip_info, release previously requested GPIO
+ /*
+ * NOTE: setup() can be called multiple times, possibly with
+ * different chip_info, release previously requested GPIO.
*/
- if (chip->gpiod_cs) {
- gpiod_put(chip->gpiod_cs);
- chip->gpiod_cs = NULL;
- }
+ cleanup_cs(spi);
- /* If (*cs_control) is provided, ignore GPIO chip select */
+ /* If ->cs_control() is provided, ignore GPIO chip select */
if (chip_info->cs_control) {
chip->cs_control = chip_info->cs_control;
return 0;
}
if (gpio_is_valid(chip_info->gpio_cs)) {
- err = gpio_request(chip_info->gpio_cs, "SPI_CS");
+ int gpio = chip_info->gpio_cs;
+ int err;
+
+ err = gpio_request(gpio, "SPI_CS");
if (err) {
- dev_err(&spi->dev, "failed to request chip select GPIO%d\n",
- chip_info->gpio_cs);
+ dev_err(&spi->dev, "failed to request chip select GPIO%d\n", gpio);
return err;
}
- gpiod = gpio_to_desc(chip_info->gpio_cs);
- chip->gpiod_cs = gpiod;
- chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH;
+ err = gpio_direction_output(gpio, !(spi->mode & SPI_CS_HIGH));
+ if (err) {
+ gpio_free(gpio);
+ return err;
+ }
- err = gpiod_direction_output(gpiod, !chip->gpio_cs_inverted);
- if (err)
- gpiod_put(chip->gpiod_cs);
+ spi->cs_gpio = gpio;
}
- return err;
+ return 0;
}
static int setup(struct spi_device *spi)
@@ -1277,6 +1258,11 @@ static int setup(struct spi_device *spi)
tx_hi_thres = 0;
rx_thres = RX_THRESH_QUARK_X1000_DFLT;
break;
+ case MRFLD_SSP:
+ tx_thres = TX_THRESH_MRFLD_DFLT;
+ tx_hi_thres = 0;
+ rx_thres = RX_THRESH_MRFLD_DFLT;
+ break;
case CE4100_SSP:
tx_thres = TX_THRESH_CE4100_DFLT;
tx_hi_thres = 0;
@@ -1305,7 +1291,7 @@ static int setup(struct spi_device *spi)
break;
}
- /* Only alloc on first setup */
+ /* Only allocate on the first setup */
chip = spi_get_ctldata(spi);
if (!chip) {
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
@@ -1319,15 +1305,15 @@ static int setup(struct spi_device *spi)
kfree(chip);
return -EINVAL;
}
-
- chip->frm = spi->chip_select;
}
chip->enable_dma = drv_data->controller_info->enable_dma;
chip->timeout = TIMOUT_DFLT;
}
- /* protocol drivers may change the chip settings, so...
- * if chip_info exists, use it */
+ /*
+ * Protocol drivers may change the chip settings, so...
+ * if chip_info exists, use it.
+ */
chip_info = spi->controller_data;
/* chip_info isn't always needed */
@@ -1352,15 +1338,24 @@ static int setup(struct spi_device *spi)
chip->cr1 |= SSCR1_SPH;
}
- chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres);
- chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres)
- | SSITF_TxHiThresh(tx_hi_thres);
+ if (is_lpss_ssp(drv_data)) {
+ chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres);
+ chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres) |
+ SSITF_TxHiThresh(tx_hi_thres);
+ }
+
+ if (is_mrfld_ssp(drv_data)) {
+ chip->lpss_rx_threshold = rx_thres;
+ chip->lpss_tx_threshold = tx_thres;
+ }
- /* set dma burst and threshold outside of chip_info path so that if
- * chip_info goes away after setting chip->enable_dma, the
- * burst and threshold can still respond to changes in bits_per_word */
+ /*
+ * Set DMA burst and threshold outside of chip_info path so that if
+ * chip_info goes away after setting chip->enable_dma, the burst and
+ * threshold can still respond to changes in bits_per_word.
+ */
if (chip->enable_dma) {
- /* set up legal burst and threshold for dma */
+ /* Set up legal burst and threshold for DMA */
if (pxa2xx_spi_set_dma_burst_and_threshold(chip, spi,
spi->bits_per_word,
&chip->dma_burst_size,
@@ -1391,8 +1386,8 @@ static int setup(struct spi_device *spi)
}
chip->cr1 &= ~(SSCR1_SPO | SSCR1_SPH);
- chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
- | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
+ chip->cr1 |= ((spi->mode & SPI_CPHA) ? SSCR1_SPH : 0) |
+ ((spi->mode & SPI_CPOL) ? SSCR1_SPO : 0);
if (spi->mode & SPI_LOOP)
chip->cr1 |= SSCR1_LBM;
@@ -1426,16 +1421,8 @@ static int setup(struct spi_device *spi)
static void cleanup(struct spi_device *spi)
{
struct chip_data *chip = spi_get_ctldata(spi);
- struct driver_data *drv_data =
- spi_controller_get_devdata(spi->controller);
-
- if (!chip)
- return;
-
- if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods &&
- chip->gpiod_cs)
- gpiod_put(chip->gpiod_cs);
+ cleanup_cs(spi);
kfree(chip);
}
@@ -1652,7 +1639,7 @@ static int pxa2xx_spi_fw_translate_cs(struct spi_controller *controller,
{
struct driver_data *drv_data = spi_controller_get_devdata(controller);
- if (has_acpi_companion(&drv_data->pdev->dev)) {
+ if (has_acpi_companion(drv_data->ssp->dev)) {
switch (drv_data->ssp_type) {
/*
* For Atoms the ACPI DeviceSelection used by the Windows
@@ -1684,7 +1671,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
struct driver_data *drv_data;
struct ssp_device *ssp;
const struct lpss_config *config;
- int status, count;
+ int status;
u32 tmp;
platform_info = dev_get_platdata(dev);
@@ -1701,7 +1688,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
ssp = &platform_info->ssp;
if (!ssp->mmio_base) {
- dev_err(&pdev->dev, "failed to get ssp\n");
+ dev_err(&pdev->dev, "failed to get SSP\n");
return -ENODEV;
}
@@ -1712,17 +1699,18 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
if (!controller) {
dev_err(&pdev->dev, "cannot alloc spi_controller\n");
- pxa_ssp_free(ssp);
- return -ENOMEM;
+ status = -ENOMEM;
+ goto out_error_controller_alloc;
}
drv_data = spi_controller_get_devdata(controller);
drv_data->controller = controller;
drv_data->controller_info = platform_info;
- drv_data->pdev = pdev;
drv_data->ssp = ssp;
- controller->dev.of_node = pdev->dev.of_node;
- /* the spi->mode bits understood by this driver: */
+ controller->dev.of_node = dev->of_node;
+ controller->dev.fwnode = dev->fwnode;
+
+ /* The spi->mode bits understood by this driver: */
controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
controller->bus_num = ssp->port_id;
@@ -1740,8 +1728,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
drv_data->ssp_type = ssp->type;
- drv_data->ioaddr = ssp->mmio_base;
- drv_data->ssdr_physical = ssp->phys_base + SSDR;
if (pxa25x_ssp_comp(drv_data)) {
switch (drv_data->ssp_type) {
case QUARK_X1000_SSP:
@@ -1803,15 +1789,16 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
controller->min_speed_hz =
DIV_ROUND_UP(controller->max_speed_hz, 512);
+ pxa_ssp_disable(ssp);
+
/* Load default SSP configuration */
- pxa2xx_spi_write(drv_data, SSCR0, 0);
switch (drv_data->ssp_type) {
case QUARK_X1000_SSP:
tmp = QUARK_X1000_SSCR1_RxTresh(RX_THRESH_QUARK_X1000_DFLT) |
QUARK_X1000_SSCR1_TxTresh(TX_THRESH_QUARK_X1000_DFLT);
pxa2xx_spi_write(drv_data, SSCR1, tmp);
- /* using the Motorola SPI protocol and use 8 bit frame */
+ /* Using the Motorola SPI protocol and use 8 bit frame */
tmp = QUARK_X1000_SSCR0_Motorola | QUARK_X1000_SSCR0_DataSize(8);
pxa2xx_spi_write(drv_data, SSCR0, tmp);
break;
@@ -1863,38 +1850,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
}
}
controller->num_chipselect = platform_info->num_chipselect;
-
- count = gpiod_count(&pdev->dev, "cs");
- if (count > 0) {
- int i;
-
- controller->num_chipselect = max_t(int, count,
- controller->num_chipselect);
-
- drv_data->cs_gpiods = devm_kcalloc(&pdev->dev,
- controller->num_chipselect, sizeof(struct gpio_desc *),
- GFP_KERNEL);
- if (!drv_data->cs_gpiods) {
- status = -ENOMEM;
- goto out_error_clock_enabled;
- }
-
- for (i = 0; i < controller->num_chipselect; i++) {
- struct gpio_desc *gpiod;
-
- gpiod = devm_gpiod_get_index(dev, "cs", i, GPIOD_ASIS);
- if (IS_ERR(gpiod)) {
- /* Means use native chip select */
- if (PTR_ERR(gpiod) == -ENOENT)
- continue;
-
- status = PTR_ERR(gpiod);
- goto out_error_clock_enabled;
- } else {
- drv_data->cs_gpiods[i] = gpiod;
- }
- }
- }
+ controller->use_gpio_descriptors = true;
if (platform_info->is_slave) {
drv_data->gpiod_ready = devm_gpiod_get_optional(dev,
@@ -1913,8 +1869,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
/* Register with the SPI framework */
platform_set_drvdata(pdev, drv_data);
status = spi_register_controller(controller);
- if (status != 0) {
- dev_err(&pdev->dev, "problem registering spi controller\n");
+ if (status) {
+ dev_err(&pdev->dev, "problem registering SPI controller\n");
goto out_error_pm_runtime_enabled;
}
@@ -1945,7 +1901,7 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
spi_unregister_controller(drv_data->controller);
/* Disable the SSP at the peripheral and SOC level */
- pxa2xx_spi_write(drv_data, SSCR0, 0);
+ pxa_ssp_disable(ssp);
clk_disable_unprepare(ssp->clk);
/* Release DMA */
@@ -1972,9 +1928,10 @@ static int pxa2xx_spi_suspend(struct device *dev)
int status;
status = spi_controller_suspend(drv_data->controller);
- if (status != 0)
+ if (status)
return status;
- pxa2xx_spi_write(drv_data, SSCR0, 0);
+
+ pxa_ssp_disable(ssp);
if (!pm_runtime_suspended(dev))
clk_disable_unprepare(ssp->clk);
diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h
index 1400472bc986..9a20fb88e50f 100644
--- a/drivers/spi/spi-pxa2xx.h
+++ b/drivers/spi/spi-pxa2xx.h
@@ -1,28 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
- * Copyright (C) 2013, Intel Corporation
+ * Copyright (C) 2013, 2021 Intel Corporation
*/
#ifndef SPI_PXA2XX_H
#define SPI_PXA2XX_H
-#include <linux/atomic.h>
-#include <linux/dmaengine.h>
-#include <linux/errno.h>
-#include <linux/io.h>
#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/pxa2xx_ssp.h>
-#include <linux/scatterlist.h>
+#include <linux/io.h>
+#include <linux/types.h>
#include <linux/sizes.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/pxa2xx_spi.h>
-struct driver_data {
- /* Driver model hookup */
- struct platform_device *pdev;
+#include <linux/pxa2xx_ssp.h>
+
+struct gpio_desc;
+struct pxa2xx_spi_controller;
+struct spi_controller;
+struct spi_device;
+struct spi_transfer;
+struct driver_data {
/* SSP Info */
struct ssp_device *ssp;
@@ -33,10 +31,6 @@ struct driver_data {
/* PXA hookup */
struct pxa2xx_spi_controller *controller_info;
- /* SSP register addresses */
- void __iomem *ioaddr;
- phys_addr_t ssdr_physical;
-
/* SSP masks*/
u32 dma_cr1;
u32 int_cr1;
@@ -59,9 +53,6 @@ struct driver_data {
void __iomem *lpss_base;
- /* GPIOs for chip selects */
- struct gpio_desc **cs_gpiods;
-
/* Optional slave FIFO ready signal */
struct gpio_desc *gpiod_ready;
};
@@ -71,37 +62,32 @@ struct chip_data {
u32 dds_rate;
u32 timeout;
u8 n_bytes;
+ u8 enable_dma;
u32 dma_burst_size;
- u32 threshold;
u32 dma_threshold;
+ u32 threshold;
u16 lpss_rx_threshold;
u16 lpss_tx_threshold;
- u8 enable_dma;
- union {
- struct gpio_desc *gpiod_cs;
- unsigned int frm;
- };
- int gpio_cs_inverted;
+
int (*write)(struct driver_data *drv_data);
int (*read)(struct driver_data *drv_data);
+
void (*cs_control)(u32 command);
};
-static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data,
- unsigned reg)
+static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, u32 reg)
{
- return __raw_readl(drv_data->ioaddr + reg);
+ return pxa_ssp_read_reg(drv_data->ssp, reg);
}
-static inline void pxa2xx_spi_write(const struct driver_data *drv_data,
- unsigned reg, u32 val)
+static inline void pxa2xx_spi_write(const struct driver_data *drv_data, u32 reg, u32 val)
{
- __raw_writel(val, drv_data->ioaddr + reg);
+ pxa_ssp_write_reg(drv_data->ssp, reg, val);
}
#define DMA_ALIGNMENT 8
-static inline int pxa25x_ssp_comp(struct driver_data *drv_data)
+static inline int pxa25x_ssp_comp(const struct driver_data *drv_data)
{
switch (drv_data->ssp_type) {
case PXA25x_SSP:
@@ -113,11 +99,21 @@ static inline int pxa25x_ssp_comp(struct driver_data *drv_data)
}
}
-static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val)
+static inline void clear_SSCR1_bits(const struct driver_data *drv_data, u32 bits)
+{
+ pxa2xx_spi_write(drv_data, SSCR1, pxa2xx_spi_read(drv_data, SSCR1) & ~bits);
+}
+
+static inline u32 read_SSSR_bits(const struct driver_data *drv_data, u32 bits)
+{
+ return pxa2xx_spi_read(drv_data, SSSR) & bits;
+}
+
+static inline void write_SSSR_CS(const struct driver_data *drv_data, u32 val)
{
if (drv_data->ssp_type == CE4100_SSP ||
drv_data->ssp_type == QUARK_X1000_SSP)
- val |= pxa2xx_spi_read(drv_data, SSSR) & SSSR_ALT_FRM_MASK;
+ val |= read_SSSR_bits(drv_data, SSSR_ALT_FRM_MASK);
pxa2xx_spi_write(drv_data, SSSR, val);
}
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 52d6259d96ed..540861ca2ba3 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -107,6 +107,8 @@
#define CR0_OPM_MASTER 0x0
#define CR0_OPM_SLAVE 0x1
+#define CR0_SOI_OFFSET 23
+
#define CR0_MTM_OFFSET 0x21
/* Bit fields in SER, 2bit */
@@ -116,13 +118,14 @@
#define BAUDR_SCKDV_MIN 2
#define BAUDR_SCKDV_MAX 65534
-/* Bit fields in SR, 5bit */
-#define SR_MASK 0x1f
+/* Bit fields in SR, 6bit */
+#define SR_MASK 0x3f
#define SR_BUSY (1 << 0)
#define SR_TF_FULL (1 << 1)
#define SR_TF_EMPTY (1 << 2)
#define SR_RF_EMPTY (1 << 3)
#define SR_RF_FULL (1 << 4)
+#define SR_SLAVE_TX_BUSY (1 << 5)
/* Bit fields in ISR, IMR, ISR, RISR, 5bit */
#define INT_MASK 0x1f
@@ -156,7 +159,8 @@
*/
#define ROCKCHIP_SPI_MAX_TRANLEN 0xffff
-#define ROCKCHIP_SPI_MAX_CS_NUM 2
+/* 2 for native cs, 2 for cs-gpio */
+#define ROCKCHIP_SPI_MAX_CS_NUM 4
#define ROCKCHIP_SPI_VER2_TYPE1 0x05EC0002
#define ROCKCHIP_SPI_VER2_TYPE2 0x00110002
@@ -197,13 +201,19 @@ static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR);
}
-static inline void wait_for_idle(struct rockchip_spi *rs)
+static inline void wait_for_tx_idle(struct rockchip_spi *rs, bool slave_mode)
{
unsigned long timeout = jiffies + msecs_to_jiffies(5);
do {
- if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY))
- return;
+ if (slave_mode) {
+ if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_SLAVE_TX_BUSY) &&
+ !((readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY)))
+ return;
+ } else {
+ if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY))
+ return;
+ }
} while (!time_after(jiffies, timeout));
dev_warn(rs->dev, "spi controller is in busy state!\n");
@@ -228,7 +238,7 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
{
struct spi_controller *ctlr = spi->controller;
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
- bool cs_asserted = !enable;
+ bool cs_asserted = spi->mode & SPI_CS_HIGH ? enable : !enable;
/* Return immediately for no-op */
if (cs_asserted == rs->cs_asserted[spi->chip_select])
@@ -238,11 +248,15 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
/* Keep things powered as long as CS is asserted */
pm_runtime_get_sync(rs->dev);
- ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER,
- BIT(spi->chip_select));
+ if (spi->cs_gpiod)
+ ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, 1);
+ else
+ ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select));
} else {
- ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER,
- BIT(spi->chip_select));
+ if (spi->cs_gpiod)
+ ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, 1);
+ else
+ ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select));
/* Drop reference from when we first asserted CS */
pm_runtime_put(rs->dev);
@@ -383,7 +397,7 @@ static void rockchip_spi_dma_txcb(void *data)
return;
/* Wait until the FIFO data completely. */
- wait_for_idle(rs);
+ wait_for_tx_idle(rs, ctlr->slave);
spi_enable_chip(rs, false);
spi_finalize_current_transfer(ctlr);
@@ -495,6 +509,8 @@ static int rockchip_spi_config(struct rockchip_spi *rs,
cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;
if (spi->mode & SPI_LSB_FIRST)
cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET;
+ if (spi->mode & SPI_CS_HIGH)
+ cr0 |= BIT(spi->chip_select) << CR0_SOI_OFFSET;
if (xfer->rx_buf && xfer->tx_buf)
cr0 |= CR0_XFM_TR << CR0_XFM_OFFSET;
@@ -540,12 +556,12 @@ static int rockchip_spi_config(struct rockchip_spi *rs,
* interrupt exactly when the fifo is full doesn't seem to work,
* so we need the strict inequality here
*/
- if (xfer->len < rs->fifo_len)
- writel_relaxed(xfer->len - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
+ if ((xfer->len / rs->n_bytes) < rs->fifo_len)
+ writel_relaxed(xfer->len / rs->n_bytes - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
else
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
- writel_relaxed(rs->fifo_len / 2, rs->regs + ROCKCHIP_SPI_DMATDLR);
+ writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
writel_relaxed(rockchip_spi_calc_burst_size(xfer->len / rs->n_bytes) - 1,
rs->regs + ROCKCHIP_SPI_DMARDLR);
writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);
@@ -783,6 +799,14 @@ static int rockchip_spi_probe(struct platform_device *pdev)
ctlr->can_dma = rockchip_spi_can_dma;
}
+ switch (readl_relaxed(rs->regs + ROCKCHIP_SPI_VERSION)) {
+ case ROCKCHIP_SPI_VER2_TYPE2:
+ ctlr->mode_bits |= SPI_CS_HIGH;
+ break;
+ default:
+ break;
+ }
+
ret = devm_spi_register_controller(&pdev->dev, ctlr);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register controller\n");
@@ -922,6 +946,7 @@ static const struct of_device_id rockchip_spi_dt_match[] = {
{ .compatible = "rockchip,rk3368-spi", },
{ .compatible = "rockchip,rk3399-spi", },
{ .compatible = "rockchip,rv1108-spi", },
+ { .compatible = "rockchip,rv1126-spi", },
{ },
};
MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match);
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index e39fd38f5180..d16ed88802d3 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -618,9 +618,9 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
ret = -ETIMEDOUT;
}
if (tx)
- dmaengine_terminate_all(rspi->ctlr->dma_tx);
+ dmaengine_terminate_sync(rspi->ctlr->dma_tx);
if (rx)
- dmaengine_terminate_all(rspi->ctlr->dma_rx);
+ dmaengine_terminate_sync(rspi->ctlr->dma_rx);
}
rspi_disable_irq(rspi, irq_mask);
@@ -634,7 +634,7 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
no_dma_tx:
if (rx)
- dmaengine_terminate_all(rspi->ctlr->dma_rx);
+ dmaengine_terminate_sync(rspi->ctlr->dma_rx);
no_dma_rx:
if (ret == -EAGAIN) {
dev_warn_once(&rspi->ctlr->dev,
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 41ed9ff8fad0..f88d9acd20d9 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -853,10 +853,10 @@ stop_reset:
sh_msiof_spi_stop(p, rx);
stop_dma:
if (tx)
- dmaengine_terminate_all(p->ctlr->dma_tx);
+ dmaengine_terminate_sync(p->ctlr->dma_tx);
no_dma_tx:
if (rx)
- dmaengine_terminate_all(p->ctlr->dma_rx);
+ dmaengine_terminate_sync(p->ctlr->dma_rx);
sh_msiof_write(p, SIIER, 0);
return ret;
}
diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
index 594f64136208..27f35aa2d746 100644
--- a/drivers/spi/spi-stm32-qspi.c
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -36,6 +36,7 @@
#define CR_FTIE BIT(18)
#define CR_SMIE BIT(19)
#define CR_TOIE BIT(20)
+#define CR_APMS BIT(22)
#define CR_PRESC_MASK GENMASK(31, 24)
#define QSPI_DCR 0x04
@@ -53,6 +54,7 @@
#define QSPI_FCR 0x0c
#define FCR_CTEF BIT(0)
#define FCR_CTCF BIT(1)
+#define FCR_CSMF BIT(3)
#define QSPI_DLR 0x10
@@ -91,7 +93,6 @@
#define STM32_AUTOSUSPEND_DELAY -1
struct stm32_qspi_flash {
- struct stm32_qspi *qspi;
u32 cs;
u32 presc;
};
@@ -107,6 +108,7 @@ struct stm32_qspi {
u32 clk_rate;
struct stm32_qspi_flash flash[STM32_QSPI_MAX_NORCHIP];
struct completion data_completion;
+ struct completion match_completion;
u32 fmode;
struct dma_chan *dma_chtx;
@@ -115,6 +117,7 @@ struct stm32_qspi {
u32 cr_reg;
u32 dcr_reg;
+ unsigned long status_timeout;
/*
* to protect device configuration, could be different between
@@ -128,11 +131,20 @@ static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id;
u32 cr, sr;
+ cr = readl_relaxed(qspi->io_base + QSPI_CR);
sr = readl_relaxed(qspi->io_base + QSPI_SR);
+ if (cr & CR_SMIE && sr & SR_SMF) {
+ /* disable irq */
+ cr &= ~CR_SMIE;
+ writel_relaxed(cr, qspi->io_base + QSPI_CR);
+ complete(&qspi->match_completion);
+
+ return IRQ_HANDLED;
+ }
+
if (sr & (SR_TEF | SR_TCF)) {
/* disable irq */
- cr = readl_relaxed(qspi->io_base + QSPI_CR);
cr &= ~CR_TCIE & ~CR_TEIE;
writel_relaxed(cr, qspi->io_base + QSPI_CR);
complete(&qspi->data_completion);
@@ -322,6 +334,24 @@ wait_nobusy:
return err;
}
+static int stm32_qspi_wait_poll_status(struct stm32_qspi *qspi,
+ const struct spi_mem_op *op)
+{
+ u32 cr;
+
+ reinit_completion(&qspi->match_completion);
+ cr = readl_relaxed(qspi->io_base + QSPI_CR);
+ writel_relaxed(cr | CR_SMIE, qspi->io_base + QSPI_CR);
+
+ if (!wait_for_completion_timeout(&qspi->match_completion,
+ msecs_to_jiffies(qspi->status_timeout)))
+ return -ETIMEDOUT;
+
+ writel_relaxed(FCR_CSMF, qspi->io_base + QSPI_FCR);
+
+ return 0;
+}
+
static int stm32_qspi_get_mode(struct stm32_qspi *qspi, u8 buswidth)
{
if (buswidth == 4)
@@ -335,7 +365,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
struct stm32_qspi_flash *flash = &qspi->flash[mem->spi->chip_select];
u32 ccr, cr;
- int timeout, err = 0;
+ int timeout, err = 0, err_poll_status = 0;
dev_dbg(qspi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n",
op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
@@ -381,6 +411,9 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
if (op->addr.nbytes && qspi->fmode != CCR_FMODE_MM)
writel_relaxed(op->addr.val, qspi->io_base + QSPI_AR);
+ if (qspi->fmode == CCR_FMODE_APM)
+ err_poll_status = stm32_qspi_wait_poll_status(qspi, op);
+
err = stm32_qspi_tx(qspi, op);
/*
@@ -390,7 +423,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
* byte of device (device size - fifo size). like device size is not
* knows, the prefetching is always stop.
*/
- if (err || qspi->fmode == CCR_FMODE_MM)
+ if (err || err_poll_status || qspi->fmode == CCR_FMODE_MM)
goto abort;
/* wait end of tx in indirect mode */
@@ -409,15 +442,49 @@ abort:
cr, !(cr & CR_ABORT), 1,
STM32_ABT_TIMEOUT_US);
- writel_relaxed(FCR_CTCF, qspi->io_base + QSPI_FCR);
+ writel_relaxed(FCR_CTCF | FCR_CSMF, qspi->io_base + QSPI_FCR);
- if (err || timeout)
- dev_err(qspi->dev, "%s err:%d abort timeout:%d\n",
- __func__, err, timeout);
+ if (err || err_poll_status || timeout)
+ dev_err(qspi->dev, "%s err:%d err_poll_status:%d abort timeout:%d\n",
+ __func__, err, err_poll_status, timeout);
return err;
}
+static int stm32_qspi_poll_status(struct spi_mem *mem, const struct spi_mem_op *op,
+ u16 mask, u16 match,
+ unsigned long initial_delay_us,
+ unsigned long polling_rate_us,
+ unsigned long timeout_ms)
+{
+ struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
+ int ret;
+
+ if (!spi_mem_supports_op(mem, op))
+ return -EOPNOTSUPP;
+
+ ret = pm_runtime_get_sync(qspi->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(qspi->dev);
+ return ret;
+ }
+
+ mutex_lock(&qspi->lock);
+
+ writel_relaxed(mask, qspi->io_base + QSPI_PSMKR);
+ writel_relaxed(match, qspi->io_base + QSPI_PSMAR);
+ qspi->fmode = CCR_FMODE_APM;
+ qspi->status_timeout = timeout_ms;
+
+ ret = stm32_qspi_send(mem, op);
+ mutex_unlock(&qspi->lock);
+
+ pm_runtime_mark_last_busy(qspi->dev);
+ pm_runtime_put_autosuspend(qspi->dev);
+
+ return ret;
+}
+
static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
@@ -525,12 +592,11 @@ static int stm32_qspi_setup(struct spi_device *spi)
presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1;
flash = &qspi->flash[spi->chip_select];
- flash->qspi = qspi;
flash->cs = spi->chip_select;
flash->presc = presc;
mutex_lock(&qspi->lock);
- qspi->cr_reg = 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN;
+ qspi->cr_reg = CR_APMS | 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN;
writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR);
/* set dcr fsize to max address */
@@ -610,6 +676,7 @@ static const struct spi_controller_mem_ops stm32_qspi_mem_ops = {
.exec_op = stm32_qspi_exec_op,
.dirmap_create = stm32_qspi_dirmap_create,
.dirmap_read = stm32_qspi_dirmap_read,
+ .poll_status = stm32_qspi_poll_status,
};
static int stm32_qspi_probe(struct platform_device *pdev)
@@ -664,6 +731,7 @@ static int stm32_qspi_probe(struct platform_device *pdev)
}
init_completion(&qspi->data_completion);
+ init_completion(&qspi->match_completion);
qspi->clk = devm_clk_get(dev, NULL);
if (IS_ERR(qspi->clk)) {
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index cc8401980125..23ad052528db 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -379,6 +379,10 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
}
sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
+ /* Finally enable the bus - doing so before might raise SCK to HIGH */
+ reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG);
+ reg |= SUN6I_GBL_CTL_BUS_ENABLE;
+ sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, reg);
/* Setup the transfer now... */
if (sspi->tx_buf)
@@ -504,7 +508,7 @@ static int sun6i_spi_runtime_resume(struct device *dev)
}
sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG,
- SUN6I_GBL_CTL_BUS_ENABLE | SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP);
+ SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP);
return 0;
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index a2e5907276e7..5131141bbf0d 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -1071,8 +1071,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
ret = wait_for_completion_timeout(&tspi->xfer_completion,
SPI_DMA_TIMEOUT);
if (WARN_ON(ret == 0)) {
- dev_err(tspi->dev,
- "spi transfer timeout, err %d\n", ret);
+ dev_err(tspi->dev, "spi transfer timeout\n");
if (tspi->is_curr_dma_xfer &&
(tspi->cur_direction & DATA_DIR_TX))
dmaengine_terminate_all(tspi->tx_dma_chan);
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c
index f7c832fd4003..6a726c95ac7a 100644
--- a/drivers/spi/spi-tegra20-slink.c
+++ b/drivers/spi/spi-tegra20-slink.c
@@ -1118,6 +1118,11 @@ static int tegra_slink_probe(struct platform_device *pdev)
pm_runtime_put_noidle(&pdev->dev);
goto exit_pm_disable;
}
+
+ reset_control_assert(tspi->rst);
+ udelay(2);
+ reset_control_deassert(tspi->rst);
+
tspi->def_command_reg = SLINK_M_S;
tspi->def_command2_reg = SLINK_CS_ACTIVE_BETWEEN;
tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index 2f806f4b2c34..2354ca1e3858 100644
--- a/drivers/spi/spi-tegra210-quad.c
+++ b/drivers/spi/spi-tegra210-quad.c
@@ -1028,7 +1028,7 @@ static int tegra_qspi_transfer_one_message(struct spi_master *master, struct spi
ret = wait_for_completion_timeout(&tqspi->xfer_completion,
QSPI_DMA_TIMEOUT);
if (WARN_ON(ret == 0)) {
- dev_err(tqspi->dev, "transfer timeout: %d\n", ret);
+ dev_err(tqspi->dev, "transfer timeout\n");
if (tqspi->is_curr_dma_xfer && (tqspi->cur_direction & DATA_DIR_TX))
dmaengine_terminate_all(tqspi->tx_dma_chan);
if (tqspi->is_curr_dma_xfer && (tqspi->cur_direction & DATA_DIR_RX))
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index b8870784fc6e..8c4615b76339 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -580,8 +580,10 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw)
data->pkt_tx_buff = kzalloc(size, GFP_KERNEL);
if (data->pkt_tx_buff != NULL) {
data->pkt_rx_buff = kzalloc(size, GFP_KERNEL);
- if (!data->pkt_rx_buff)
+ if (!data->pkt_rx_buff) {
kfree(data->pkt_tx_buff);
+ data->pkt_tx_buff = NULL;
+ }
}
if (!data->pkt_rx_buff) {
diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c
index 6a9ef8ee3cc9..8900e51e1a1c 100644
--- a/drivers/spi/spi-uniphier.c
+++ b/drivers/spi/spi-uniphier.c
@@ -142,7 +142,7 @@ static void uniphier_spi_set_mode(struct spi_device *spi)
* FSTRT start frame timing
* 0: rising edge of clock, 1: falling edge of clock
*/
- switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
+ switch (spi->mode & SPI_MODE_X_MASK) {
case SPI_MODE_0:
/* CKPHS=1, CKINIT=0, CKDLY=1, FSTRT=0 */
val1 = SSI_CKS_CKPHS | SSI_CKS_CKDLY;
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index e353b7a9e54e..c99181165321 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -363,6 +363,10 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
const struct spi_device *spi = to_spi_device(dev);
int rc;
+ rc = of_device_uevent_modalias(dev, env);
+ if (rc != -ENODEV)
+ return rc;
+
rc = acpi_device_uevent_modalias(dev, env);
if (rc != -ENODEV)
return rc;
@@ -560,49 +564,23 @@ static void spi_cleanup(struct spi_device *spi)
spi->controller->cleanup(spi);
}
-/**
- * spi_add_device - Add spi_device allocated with spi_alloc_device
- * @spi: spi_device to register
- *
- * Companion function to spi_alloc_device. Devices allocated with
- * spi_alloc_device can be added onto the spi bus with this function.
- *
- * Return: 0 on success; negative errno on failure
- */
-int spi_add_device(struct spi_device *spi)
+static int __spi_add_device(struct spi_device *spi)
{
struct spi_controller *ctlr = spi->controller;
struct device *dev = ctlr->dev.parent;
int status;
- /* Chipselects are numbered 0..max; validate. */
- if (spi->chip_select >= ctlr->num_chipselect) {
- dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
- ctlr->num_chipselect);
- return -EINVAL;
- }
-
- /* Set the bus ID string */
- spi_dev_set_name(spi);
-
- /* We need to make sure there's no other device with this
- * chipselect **BEFORE** we call setup(), else we'll trash
- * its configuration. Lock against concurrent add() calls.
- */
- mutex_lock(&spi_add_lock);
-
status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
if (status) {
dev_err(dev, "chipselect %d already in use\n",
spi->chip_select);
- goto done;
+ return status;
}
/* Controller may unregister concurrently */
if (IS_ENABLED(CONFIG_SPI_DYNAMIC) &&
!device_is_registered(&ctlr->dev)) {
- status = -ENODEV;
- goto done;
+ return -ENODEV;
}
/* Descriptors take precedence */
@@ -619,7 +597,7 @@ int spi_add_device(struct spi_device *spi)
if (status < 0) {
dev_err(dev, "can't setup %s, status %d\n",
dev_name(&spi->dev), status);
- goto done;
+ return status;
}
/* Device may be bound to an active driver when this returns */
@@ -632,12 +610,64 @@ int spi_add_device(struct spi_device *spi)
dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
}
-done:
+ return status;
+}
+
+/**
+ * spi_add_device - Add spi_device allocated with spi_alloc_device
+ * @spi: spi_device to register
+ *
+ * Companion function to spi_alloc_device. Devices allocated with
+ * spi_alloc_device can be added onto the spi bus with this function.
+ *
+ * Return: 0 on success; negative errno on failure
+ */
+int spi_add_device(struct spi_device *spi)
+{
+ struct spi_controller *ctlr = spi->controller;
+ struct device *dev = ctlr->dev.parent;
+ int status;
+
+ /* Chipselects are numbered 0..max; validate. */
+ if (spi->chip_select >= ctlr->num_chipselect) {
+ dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
+ ctlr->num_chipselect);
+ return -EINVAL;
+ }
+
+ /* Set the bus ID string */
+ spi_dev_set_name(spi);
+
+ /* We need to make sure there's no other device with this
+ * chipselect **BEFORE** we call setup(), else we'll trash
+ * its configuration. Lock against concurrent add() calls.
+ */
+ mutex_lock(&spi_add_lock);
+ status = __spi_add_device(spi);
mutex_unlock(&spi_add_lock);
return status;
}
EXPORT_SYMBOL_GPL(spi_add_device);
+static int spi_add_device_locked(struct spi_device *spi)
+{
+ struct spi_controller *ctlr = spi->controller;
+ struct device *dev = ctlr->dev.parent;
+
+ /* Chipselects are numbered 0..max; validate. */
+ if (spi->chip_select >= ctlr->num_chipselect) {
+ dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
+ ctlr->num_chipselect);
+ return -EINVAL;
+ }
+
+ /* Set the bus ID string */
+ spi_dev_set_name(spi);
+
+ WARN_ON(!mutex_is_locked(&spi_add_lock));
+ return __spi_add_device(spi);
+}
+
/**
* spi_new_device - instantiate one new SPI device
* @ctlr: Controller to which device is connected
@@ -804,6 +834,8 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
(spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH)))
return;
+ trace_spi_set_cs(spi, activate);
+
spi->controller->last_cs_enable = enable;
spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH;
@@ -961,11 +993,15 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
if (ctlr->dma_tx)
tx_dev = ctlr->dma_tx->device->dev;
+ else if (ctlr->dma_map_dev)
+ tx_dev = ctlr->dma_map_dev;
else
tx_dev = ctlr->dev.parent;
if (ctlr->dma_rx)
rx_dev = ctlr->dma_rx->device->dev;
+ else if (ctlr->dma_map_dev)
+ rx_dev = ctlr->dma_map_dev;
else
rx_dev = ctlr->dev.parent;
@@ -1132,10 +1168,20 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
if (!speed_hz)
speed_hz = 100000;
- ms = 8LL * 1000LL * xfer->len;
+ /*
+ * For each byte we wait for 8 cycles of the SPI clock.
+ * Since speed is defined in Hz and we want milliseconds,
+ * use respective multiplier, but before the division,
+ * otherwise we may get 0 for short transfers.
+ */
+ ms = 8LL * MSEC_PER_SEC * xfer->len;
do_div(ms, speed_hz);
- ms += ms + 200; /* some tolerance */
+ /*
+ * Increase it twice and add 200 ms tolerance, use
+ * predefined maximum in case of overflow.
+ */
+ ms += ms + 200;
if (ms > UINT_MAX)
ms = UINT_MAX;
@@ -1158,10 +1204,10 @@ static void _spi_transfer_delay_ns(u32 ns)
{
if (!ns)
return;
- if (ns <= 1000) {
+ if (ns <= NSEC_PER_USEC) {
ndelay(ns);
} else {
- u32 us = DIV_ROUND_UP(ns, 1000);
+ u32 us = DIV_ROUND_UP(ns, NSEC_PER_USEC);
if (us <= 10)
udelay(us);
@@ -1181,21 +1227,25 @@ int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer)
switch (unit) {
case SPI_DELAY_UNIT_USECS:
- delay *= 1000;
+ delay *= NSEC_PER_USEC;
break;
- case SPI_DELAY_UNIT_NSECS: /* nothing to do here */
+ case SPI_DELAY_UNIT_NSECS:
+ /* Nothing to do here */
break;
case SPI_DELAY_UNIT_SCK:
/* clock cycles need to be obtained from spi_transfer */
if (!xfer)
return -EINVAL;
- /* if there is no effective speed know, then approximate
- * by underestimating with half the requested hz
+ /*
+ * If there is unknown effective speed, approximate it
+ * by underestimating with half of the requested hz.
*/
hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2;
if (!hz)
return -EINVAL;
- delay *= DIV_ROUND_UP(1000000000, hz);
+
+ /* Convert delay to nanoseconds */
+ delay *= DIV_ROUND_UP(NSEC_PER_SEC, hz);
break;
default:
return -EINVAL;
@@ -1227,6 +1277,7 @@ EXPORT_SYMBOL_GPL(spi_delay_exec);
static void _spi_transfer_cs_change_delay(struct spi_message *msg,
struct spi_transfer *xfer)
{
+ u32 default_delay_ns = 10 * NSEC_PER_USEC;
u32 delay = xfer->cs_change_delay.value;
u32 unit = xfer->cs_change_delay.unit;
int ret;
@@ -1234,16 +1285,16 @@ static void _spi_transfer_cs_change_delay(struct spi_message *msg,
/* return early on "fast" mode - for everything but USECS */
if (!delay) {
if (unit == SPI_DELAY_UNIT_USECS)
- _spi_transfer_delay_ns(10000);
+ _spi_transfer_delay_ns(default_delay_ns);
return;
}
ret = spi_delay_exec(&xfer->cs_change_delay, xfer);
if (ret) {
dev_err_once(&msg->spi->dev,
- "Use of unsupported delay unit %i, using default of 10us\n",
- unit);
- _spi_transfer_delay_ns(10000);
+ "Use of unsupported delay unit %i, using default of %luus\n",
+ unit, default_delay_ns / NSEC_PER_USEC);
+ _spi_transfer_delay_ns(default_delay_ns);
}
}
@@ -2057,6 +2108,7 @@ of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc)
/* Store a pointer to the node in the device structure */
of_node_get(nc);
spi->dev.of_node = nc;
+ spi->dev.fwnode = of_fwnode_handle(nc);
/* Register the new device */
rc = spi_add_device(spi);
@@ -2104,6 +2156,55 @@ static void of_register_spi_devices(struct spi_controller *ctlr)
static void of_register_spi_devices(struct spi_controller *ctlr) { }
#endif
+/**
+ * spi_new_ancillary_device() - Register ancillary SPI device
+ * @spi: Pointer to the main SPI device registering the ancillary device
+ * @chip_select: Chip Select of the ancillary device
+ *
+ * Register an ancillary SPI device; for example some chips have a chip-select
+ * for normal device usage and another one for setup/firmware upload.
+ *
+ * This may only be called from main SPI device's probe routine.
+ *
+ * Return: 0 on success; negative errno on failure
+ */
+struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
+ u8 chip_select)
+{
+ struct spi_device *ancillary;
+ int rc = 0;
+
+ /* Alloc an spi_device */
+ ancillary = spi_alloc_device(spi->controller);
+ if (!ancillary) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ strlcpy(ancillary->modalias, "dummy", sizeof(ancillary->modalias));
+
+ /* Use provided chip-select for ancillary device */
+ ancillary->chip_select = chip_select;
+
+ /* Take over SPI mode/speed from SPI main device */
+ ancillary->max_speed_hz = spi->max_speed_hz;
+ ancillary->mode = spi->mode;
+
+ /* Register the new device */
+ rc = spi_add_device_locked(ancillary);
+ if (rc) {
+ dev_err(&spi->dev, "failed to register ancillary device\n");
+ goto err_out;
+ }
+
+ return ancillary;
+
+err_out:
+ spi_dev_put(ancillary);
+ return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(spi_new_ancillary_device);
+
#ifdef CONFIG_ACPI
struct acpi_spi_lookup {
struct spi_controller *ctlr;
@@ -2621,9 +2722,10 @@ static int spi_get_gpio_descs(struct spi_controller *ctlr)
native_cs_mask |= BIT(i);
}
- ctlr->unused_native_cs = ffz(native_cs_mask);
- if (num_cs_gpios && ctlr->max_native_cs &&
- ctlr->unused_native_cs >= ctlr->max_native_cs) {
+ ctlr->unused_native_cs = ffs(~native_cs_mask) - 1;
+
+ if ((ctlr->flags & SPI_MASTER_GPIO_SS) && num_cs_gpios &&
+ ctlr->max_native_cs && ctlr->unused_native_cs >= ctlr->max_native_cs) {
dev_err(dev, "No unused native chip select available\n");
return -EINVAL;
}
@@ -3440,8 +3542,10 @@ int spi_setup(struct spi_device *spi)
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)),
+ trace_spi_setup(spi, status);
+
+ dev_dbg(&spi->dev, "setup mode %lu, %s%s%s%s%u bits/w, %u Hz max --> %d\n",
+ spi->mode & SPI_MODE_X_MASK,
(spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
(spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
(spi->mode & SPI_3WIRE) ? "3wire, " : "",
@@ -3453,79 +3557,6 @@ int spi_setup(struct spi_device *spi)
}
EXPORT_SYMBOL_GPL(spi_setup);
-/**
- * spi_set_cs_timing - configure CS setup, hold, and inactive delays
- * @spi: the device that requires specific CS timing configuration
- * @setup: CS setup time specified via @spi_delay
- * @hold: CS hold time specified via @spi_delay
- * @inactive: CS inactive delay between transfers specified via @spi_delay
- *
- * Return: zero on success, else a negative error code.
- */
-int spi_set_cs_timing(struct spi_device *spi, struct spi_delay *setup,
- struct spi_delay *hold, struct spi_delay *inactive)
-{
- struct device *parent = spi->controller->dev.parent;
- size_t len;
- int status;
-
- if (spi->controller->set_cs_timing &&
- !(spi->cs_gpiod || gpio_is_valid(spi->cs_gpio))) {
- mutex_lock(&spi->controller->io_mutex);
-
- if (spi->controller->auto_runtime_pm) {
- status = pm_runtime_get_sync(parent);
- if (status < 0) {
- mutex_unlock(&spi->controller->io_mutex);
- pm_runtime_put_noidle(parent);
- dev_err(&spi->controller->dev, "Failed to power device: %d\n",
- status);
- return status;
- }
-
- status = spi->controller->set_cs_timing(spi, setup,
- hold, inactive);
- pm_runtime_mark_last_busy(parent);
- pm_runtime_put_autosuspend(parent);
- } else {
- status = spi->controller->set_cs_timing(spi, setup, hold,
- inactive);
- }
-
- mutex_unlock(&spi->controller->io_mutex);
- return status;
- }
-
- if ((setup && setup->unit == SPI_DELAY_UNIT_SCK) ||
- (hold && hold->unit == SPI_DELAY_UNIT_SCK) ||
- (inactive && inactive->unit == SPI_DELAY_UNIT_SCK)) {
- dev_err(&spi->dev,
- "Clock-cycle delays for CS not supported in SW mode\n");
- return -ENOTSUPP;
- }
-
- len = sizeof(struct spi_delay);
-
- /* copy delays to controller */
- if (setup)
- memcpy(&spi->controller->cs_setup, setup, len);
- else
- memset(&spi->controller->cs_setup, 0, len);
-
- if (hold)
- memcpy(&spi->controller->cs_hold, hold, len);
- else
- memset(&spi->controller->cs_hold, 0, len);
-
- if (inactive)
- memcpy(&spi->controller->cs_inactive, inactive, len);
- else
- memset(&spi->controller->cs_inactive, 0, len);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(spi_set_cs_timing);
-
static int _spi_xfer_word_delay_update(struct spi_transfer *xfer,
struct spi_device *spi)
{
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index f56e0e975a46..24e9469ea35b 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -59,7 +59,7 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS);
*
* REVISIT should changing those flags be privileged?
*/
-#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
+#define SPI_MODE_MASK (SPI_MODE_X_MASK | SPI_CS_HIGH \
| SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
| SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
| SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
index a53bad541f1a..2874b6c26028 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -11,6 +11,15 @@ menuconfig SPMI
if SPMI
+config SPMI_HISI3670
+ tristate "Hisilicon 3670 SPMI Controller"
+ select IRQ_DOMAIN_HIERARCHY
+ depends on HAS_IOMEM
+ help
+ If you say yes to this option, support will be included for the
+ built-in SPMI PMIC Arbiter interface on Hisilicon 3670
+ processors.
+
config SPMI_MSM_PMIC_ARB
tristate "Qualcomm MSM SPMI Controller (PMIC Arbiter)"
select IRQ_DOMAIN_HIERARCHY
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index 55a94cadeffe..6e092e6f290c 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -4,4 +4,5 @@
#
obj-$(CONFIG_SPMI) += spmi.o
+obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o
obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o
diff --git a/drivers/staging/hikey9xx/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
index 0d42bc65f39b..5bd23262abd6 100644
--- a/drivers/staging/hikey9xx/hisi-spmi-controller.c
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -290,7 +290,7 @@ static int spmi_controller_probe(struct platform_device *pdev)
goto err_put_controller;
}
- ret = of_property_read_u32(pdev->dev.of_node, "spmi-channel",
+ ret = of_property_read_u32(pdev->dev.of_node, "hisilicon,spmi-channel",
&spmi_controller->channel);
if (ret) {
dev_err(&pdev->dev, "can not get channel\n");
diff --git a/drivers/ssb/driver_gpio.c b/drivers/ssb/driver_gpio.c
index 66a76fd83248..2de3896489c8 100644
--- a/drivers/ssb/driver_gpio.c
+++ b/drivers/ssb/driver_gpio.c
@@ -231,7 +231,8 @@ static int ssb_gpio_chipco_init(struct ssb_bus *bus)
chip->ngpio = 16;
/* There is just one SoC in one device and its GPIO addresses should be
* deterministic to address them more easily. The other buses could get
- * a random base number. */
+ * a random base number.
+ */
if (bus->bustype == SSB_BUSTYPE_SSB)
chip->base = 0;
else
@@ -424,7 +425,8 @@ static int ssb_gpio_extif_init(struct ssb_bus *bus)
chip->ngpio = 5;
/* There is just one SoC in one device and its GPIO addresses should be
* deterministic to address them more easily. The other buses could get
- * a random base number. */
+ * a random base number.
+ */
if (bus->bustype == SSB_BUSTYPE_SSB)
chip->base = 0;
else
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index c1186415896b..d11b4242b6d2 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -55,7 +55,8 @@ void pcicore_write16(struct ssb_pcicore *pc, u16 offset, u16 value)
#include <asm/paccess.h>
/* Probe a 32bit value on the bus and catch bus exceptions.
* Returns nonzero on a bus exception.
- * This is MIPS specific */
+ * This is MIPS specific
+ */
#define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr)))
/* Assume one-hot slot wiring */
@@ -255,7 +256,8 @@ static struct pci_controller ssb_pcicore_controller = {
};
/* This function is called when doing a pci_enable_device().
- * We must first check if the device is a device on the PCI-core bridge. */
+ * We must first check if the device is a device on the PCI-core bridge.
+ */
int ssb_pcicore_plat_dev_init(struct pci_dev *d)
{
if (d->bus->ops != &ssb_pcicore_pciops) {
@@ -381,11 +383,13 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
/* Ok, ready to run, register it to the system.
* The following needs change, if we want to port hostmode
- * to non-MIPS platform. */
+ * to non-MIPS platform.
+ */
ssb_pcicore_controller.io_map_base = (unsigned long)ioremap(SSB_PCI_MEM, 0x04000000);
set_io_port_base(ssb_pcicore_controller.io_map_base);
/* Give some time to the PCI controller to configure itself with the new
- * values. Not waiting at this point causes crashes of the machine. */
+ * values. Not waiting at this point causes crashes of the machine.
+ */
mdelay(10);
register_pci_controller(&ssb_pcicore_controller);
}
@@ -405,7 +409,8 @@ static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)
return 0;
/* The 200-pin BCM4712 package does not bond out PCI. Even when
- * PCI is bonded out, some boards may leave the pins floating. */
+ * PCI is bonded out, some boards may leave the pins floating.
+ */
if (bus->chip_id == 0x4712) {
if (bus->chip_package == SSB_CHIPPACK_BCM4712S)
return 0;
@@ -685,7 +690,8 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
if (dev->bus->bustype != SSB_BUSTYPE_PCI) {
/* This SSB device is not on a PCI host-bus. So the IRQs are
* not routed through the PCI core.
- * So we must not enable routing through the PCI core. */
+ * So we must not enable routing through the PCI core.
+ */
goto out;
}
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 0a26984acb2c..3a29b5570f9f 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -37,7 +37,8 @@ static LIST_HEAD(buses);
/* Software ID counter */
static unsigned int next_busnumber;
/* buses_mutes locks the two buslists and the next_busnumber.
- * Don't lock this directly, but use ssb_buses_[un]lock() below. */
+ * Don't lock this directly, but use ssb_buses_[un]lock() below.
+ */
static DEFINE_MUTEX(buses_mutex);
/* There are differences in the codeflow, if the bus is
@@ -45,7 +46,8 @@ static DEFINE_MUTEX(buses_mutex);
* are not available early. This is a mechanism to delay
* these initializations to after early boot has finished.
* It's also used to avoid mutex locking, as that's not
- * available and needed early. */
+ * available and needed early.
+ */
static bool ssb_is_early_boot = 1;
static void ssb_buses_lock(void);
@@ -161,7 +163,8 @@ int ssb_bus_resume(struct ssb_bus *bus)
int err;
/* Reset HW state information in memory, so that HW is
- * completely reinitialized. */
+ * completely reinitialized.
+ */
bus->mapped_device = NULL;
#ifdef CONFIG_SSB_DRIVER_PCICORE
bus->pcicore.setup_done = 0;
@@ -431,9 +434,7 @@ void ssb_bus_unregister(struct ssb_bus *bus)
int err;
err = ssb_gpio_unregister(bus);
- if (err == -EBUSY)
- pr_debug("Some GPIOs are still in use\n");
- else if (err)
+ if (err)
pr_debug("Can not unregister GPIO driver: %i\n", err);
ssb_buses_lock();
@@ -467,7 +468,8 @@ static int ssb_devices_register(struct ssb_bus *bus)
sdev = &(bus->devices[i]);
/* We don't register SSB-system devices to the kernel,
- * as the drivers for them are built into SSB. */
+ * as the drivers for them are built into SSB.
+ */
switch (sdev->id.coreid) {
case SSB_DEV_CHIPCOMMON:
case SSB_DEV_PCI:
@@ -521,7 +523,8 @@ static int ssb_devices_register(struct ssb_bus *bus)
if (err) {
pr_err("Could not register %s\n", dev_name(dev));
/* Set dev to NULL to not unregister
- * dev on error unwinding. */
+ * dev on error unwinding.
+ */
sdev->dev = NULL;
put_device(dev);
goto error;
@@ -667,7 +670,8 @@ ssb_bus_register(struct ssb_bus *bus,
ssb_bus_may_powerdown(bus);
/* Queue it for attach.
- * See the comment at the ssb_is_early_boot definition. */
+ * See the comment at the ssb_is_early_boot definition.
+ */
list_add_tail(&bus->list, &attach_queue);
if (!ssb_is_early_boot) {
/* This is not early boot, so we must attach the bus now */
@@ -1007,7 +1011,8 @@ static void ssb_flush_tmslow(struct ssb_device *dev)
* a machine check exception otherwise.
* Do this by reading the register back to commit the
* PCI write and delay an additional usec for the device
- * to react to the change. */
+ * to react to the change.
+ */
ssb_read32(dev, SSB_TMSLOW);
udelay(1);
}
@@ -1044,7 +1049,8 @@ void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags)
EXPORT_SYMBOL(ssb_device_enable);
/* Wait for bitmask in a register to get set or cleared.
- * timeout is in units of ten-microseconds */
+ * timeout is in units of ten-microseconds
+ */
static int ssb_wait_bits(struct ssb_device *dev, u16 reg, u32 bitmask,
int timeout, int set)
{
@@ -1153,7 +1159,8 @@ int ssb_bus_may_powerdown(struct ssb_bus *bus)
/* On buses where more than one core may be working
* at a time, we must not powerdown stuff if there are
- * still cores that may want to run. */
+ * still cores that may want to run.
+ */
if (bus->bustype == SSB_BUSTYPE_SSB)
goto out;
@@ -1303,13 +1310,11 @@ static int __init ssb_modinit(void)
if (err) {
pr_err("Broadcom 43xx PCI-SSB-bridge initialization failed\n");
/* don't fail SSB init because of this */
- err = 0;
}
err = ssb_host_pcmcia_init();
if (err) {
pr_err("PCMCIA host initialization failed\n");
/* don't fail SSB init because of this */
- err = 0;
}
err = ssb_gige_init();
if (err) {
@@ -1322,7 +1327,8 @@ out:
}
/* ssb must be initialized after PCI but before the ssb drivers.
* That means we must use some initcall between subsys_initcall
- * and device_initcall. */
+ * and device_initcall.
+ */
fs_initcall(ssb_modinit);
static void __exit ssb_modexit(void)
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index dac54041ad8d..148bcb99c212 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -1117,9 +1117,9 @@ const struct ssb_bus_ops ssb_pci_ops = {
#endif
};
-static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t ssb_sprom_show(struct device *pcidev,
+ struct device_attribute *attr,
+ char *buf)
{
struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
struct ssb_bus *bus;
@@ -1131,9 +1131,9 @@ static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
return ssb_attr_sprom_show(bus, buf, sprom_do_read);
}
-static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t ssb_sprom_store(struct device *pcidev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
struct ssb_bus *bus;
@@ -1146,9 +1146,7 @@ static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
sprom_check_crc, sprom_do_write);
}
-static DEVICE_ATTR(ssb_sprom, 0600,
- ssb_pci_attr_sprom_show,
- ssb_pci_attr_sprom_store);
+static DEVICE_ATTR_ADMIN_RW(ssb_sprom);
void ssb_pci_exit(struct ssb_bus *bus)
{
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
index d7d730c245c5..45502098e0c7 100644
--- a/drivers/ssb/pcmcia.c
+++ b/drivers/ssb/pcmcia.c
@@ -723,9 +723,9 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
return -ENODEV;
}
-static ssize_t ssb_pcmcia_attr_sprom_show(struct device *pcmciadev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t ssb_sprom_show(struct device *pcmciadev,
+ struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_device *pdev =
container_of(pcmciadev, struct pcmcia_device, dev);
@@ -739,9 +739,9 @@ static ssize_t ssb_pcmcia_attr_sprom_show(struct device *pcmciadev,
ssb_pcmcia_sprom_read_all);
}
-static ssize_t ssb_pcmcia_attr_sprom_store(struct device *pcmciadev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t ssb_sprom_store(struct device *pcmciadev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct pcmcia_device *pdev =
container_of(pcmciadev, struct pcmcia_device, dev);
@@ -756,9 +756,7 @@ static ssize_t ssb_pcmcia_attr_sprom_store(struct device *pcmciadev,
ssb_pcmcia_sprom_write_all);
}
-static DEVICE_ATTR(ssb_sprom, 0600,
- ssb_pcmcia_attr_sprom_show,
- ssb_pcmcia_attr_sprom_store);
+static DEVICE_ATTR_ADMIN_RW(ssb_sprom);
static int ssb_pcmcia_cor_setup(struct ssb_bus *bus, u8 cor)
{
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
index f49ab1aa2149..4161e5d1f276 100644
--- a/drivers/ssb/scan.c
+++ b/drivers/ssb/scan.c
@@ -325,6 +325,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
if (bus->nr_devices > ARRAY_SIZE(bus->devices)) {
pr_err("More than %d ssb cores found (%d)\n",
SSB_MAX_NR_CORES, bus->nr_devices);
+ err = -EINVAL;
goto err_unmap;
}
if (bus->bustype == SSB_BUSTYPE_SSB) {
diff --git a/drivers/ssb/sdio.c b/drivers/ssb/sdio.c
index 7fe0afb42234..66c5c2169704 100644
--- a/drivers/ssb/sdio.c
+++ b/drivers/ssb/sdio.c
@@ -411,7 +411,6 @@ static void ssb_sdio_block_write(struct ssb_device *dev, const void *buffer,
sdio_claim_host(bus->host_sdio);
if (unlikely(ssb_sdio_switch_core(bus, dev))) {
error = -EIO;
- memset((void *)buffer, 0xff, count);
goto err_out;
}
offset |= bus->sdio_sbaddr & 0xffff;
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index b7ae5bdc4eb5..c8eaae6412bb 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -98,8 +98,6 @@ source "drivers/staging/axis-fifo/Kconfig"
source "drivers/staging/fieldbus/Kconfig"
-source "drivers/staging/kpc2000/Kconfig"
-
source "drivers/staging/qlge/Kconfig"
source "drivers/staging/wfx/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 075c979bfe7c..818b6f964369 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -39,7 +39,6 @@ obj-$(CONFIG_DMA_RALINK) += ralink-gdma/
obj-$(CONFIG_SOC_MT7621) += mt7621-dts/
obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/
obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/
-obj-$(CONFIG_KPC2000) += kpc2000/
obj-$(CONFIG_QLGE) += qlge/
obj-$(CONFIG_WFX) += wfx/
obj-y += hikey9xx/
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index d66a64e42273..ddbde3f8430e 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -179,6 +179,7 @@ static inline void lru_del(struct ashmem_range *range)
* @purged: Initial purge status (ASMEM_NOT_PURGED or ASHMEM_WAS_PURGED)
* @start: The starting page (inclusive)
* @end: The ending page (inclusive)
+ * @new_range: The placeholder for the new range
*
* This function is protected by ashmem_mutex.
*/
@@ -894,6 +895,8 @@ static void ashmem_show_fdinfo(struct seq_file *m, struct file *file)
seq_printf(m, "name:\t%s\n",
asma->name + ASHMEM_NAME_PREFIX_LEN);
+ seq_printf(m, "size:\t%zu\n", asma->size);
+
mutex_unlock(&ashmem_mutex);
}
#endif
diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c
index ed9281089738..b23eabb863d1 100644
--- a/drivers/staging/axis-fifo/axis-fifo.c
+++ b/drivers/staging/axis-fifo/axis-fifo.c
@@ -337,11 +337,11 @@ static void reset_ip_core(struct axis_fifo *fifo)
}
/**
- * axis_fifo_write() - Read a packet from AXIS-FIFO character device.
- * @f Open file.
- * @buf User space buffer to read to.
- * @len User space buffer length.
- * @off Buffer offset.
+ * axis_fifo_read() - Read a packet from AXIS-FIFO character device.
+ * @f: Open file.
+ * @buf: User space buffer to read to.
+ * @len: User space buffer length.
+ * @off: Buffer offset.
*
* As defined by the device's documentation, we need to check the device's
* occupancy before reading the length register and then the data. All these
@@ -460,10 +460,10 @@ end_unlock:
/**
* axis_fifo_write() - Write buffer to AXIS-FIFO character device.
- * @f Open file.
- * @buf User space buffer to write to the device.
- * @len User space buffer length.
- * @off Buffer offset.
+ * @f: Open file.
+ * @buf: User space buffer to write to the device.
+ * @len: User space buffer length.
+ * @off: Buffer offset.
*
* As defined by the device's documentation, we need to write to the device's
* data buffer then to the device's packet length register atomically. Also,
diff --git a/drivers/staging/board/Kconfig b/drivers/staging/board/Kconfig
index 64c77970eee8..b49216768ef6 100644
--- a/drivers/staging/board/Kconfig
+++ b/drivers/staging/board/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
config STAGING_BOARD
bool "Staging Board Support"
- depends on OF_ADDRESS && OF_IRQ && CLKDEV_LOOKUP
+ depends on OF_ADDRESS && OF_IRQ && HAVE_CLK
help
Staging board base is to support continuous upstream
in-tree development and integration of platform devices.
diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c
index ecc5c9da9027..b6abd3770e81 100644
--- a/drivers/staging/emxx_udc/emxx_udc.c
+++ b/drivers/staging/emxx_udc/emxx_udc.c
@@ -1073,9 +1073,8 @@ static int _nbu2ss_epn_in_pio(struct nbu2ss_udc *udc, struct nbu2ss_ep *ep,
i_word_length = length / sizeof(u32);
if (i_word_length > 0) {
for (i = 0; i < i_word_length; i++) {
- _nbu2ss_writel(
- &preg->EP_REGS[ep->epnum - 1].EP_WRITE,
- p_buf_32->dw);
+ _nbu2ss_writel(&preg->EP_REGS[ep->epnum - 1].EP_WRITE,
+ p_buf_32->dw);
p_buf_32++;
}
@@ -1225,8 +1224,7 @@ static void _nbu2ss_restert_transfer(struct nbu2ss_ep *ep)
return;
if (ep->epnum > 0) {
- length = _nbu2ss_readl(
- &ep->udc->p_regs->EP_REGS[ep->epnum - 1].EP_LEN_DCNT);
+ length = _nbu2ss_readl(&ep->udc->p_regs->EP_REGS[ep->epnum - 1].EP_LEN_DCNT);
length &= EPN_LDATA;
if (length < ep->ep.maxpacket)
@@ -1462,8 +1460,7 @@ static void _nbu2ss_epn_set_stall(struct nbu2ss_udc *udc,
for (limit_cnt = 0
; limit_cnt < IN_DATA_EMPTY_COUNT
; limit_cnt++) {
- regdata = _nbu2ss_readl(
- &preg->EP_REGS[ep->epnum - 1].EP_STATUS);
+ regdata = _nbu2ss_readl(&preg->EP_REGS[ep->epnum - 1].EP_STATUS);
if ((regdata & EPN_IN_DATA) == 0)
break;
diff --git a/drivers/staging/fbtft/TODO b/drivers/staging/fbtft/TODO
index a9f4802bb6be..e72a08bf221c 100644
--- a/drivers/staging/fbtft/TODO
+++ b/drivers/staging/fbtft/TODO
@@ -1,8 +1,3 @@
-* convert all uses of the old GPIO API from <linux/gpio.h> to the
- GPIO descriptor API in <linux/gpio/consumer.h> and look up GPIO
- lines from device tree, ACPI or board files, board files should
- use <linux/gpio/machine.h>
-
* convert all these over to drm_simple_display_pipe and submit for inclusion
into the DRM subsystem under drivers/gpu/drm - fbdev doesn't take any new
drivers anymore.
diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c
index eeeeec97ad27..207d578547cd 100644
--- a/drivers/staging/fbtft/fb_agm1264k-fl.c
+++ b/drivers/staging/fbtft/fb_agm1264k-fl.c
@@ -77,19 +77,6 @@ static int init_display(struct fbtft_par *par)
return 0;
}
-static void reset(struct fbtft_par *par)
-{
- if (!par->gpio.reset)
- return;
-
- dev_dbg(par->info->device, "%s()\n", __func__);
-
- gpiod_set_value(par->gpio.reset, 0);
- udelay(20);
- gpiod_set_value(par->gpio.reset, 1);
- mdelay(120);
-}
-
/* Check if all necessary GPIOS defined */
static int verify_gpios(struct fbtft_par *par)
{
@@ -194,12 +181,12 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
/* select chip */
if (*buf) {
/* cs1 */
- gpiod_set_value(par->CS0, 1);
- gpiod_set_value(par->CS1, 0);
- } else {
- /* cs0 */
gpiod_set_value(par->CS0, 0);
gpiod_set_value(par->CS1, 1);
+ } else {
+ /* cs0 */
+ gpiod_set_value(par->CS0, 1);
+ gpiod_set_value(par->CS1, 0);
}
gpiod_set_value(par->RS, 0); /* RS->0 (command mode) */
@@ -397,8 +384,8 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
}
kfree(convert_buf);
- gpiod_set_value(par->CS0, 1);
- gpiod_set_value(par->CS1, 1);
+ gpiod_set_value(par->CS0, 0);
+ gpiod_set_value(par->CS1, 0);
return ret;
}
@@ -419,10 +406,10 @@ static int write(struct fbtft_par *par, void *buf, size_t len)
for (i = 0; i < 8; ++i)
gpiod_set_value(par->gpio.db[i], data & (1 << i));
/* set E */
- gpiod_set_value(par->EPIN, 1);
+ gpiod_set_value(par->EPIN, 0);
udelay(5);
/* unset E - write */
- gpiod_set_value(par->EPIN, 0);
+ gpiod_set_value(par->EPIN, 1);
udelay(1);
}
@@ -439,7 +426,6 @@ static struct fbtft_display display = {
.set_addr_win = set_addr_win,
.verify_gpios = verify_gpios,
.request_gpios_match = request_gpios_match,
- .reset = reset,
.write = write,
.write_register = write_reg8_bus8,
.write_vmem = write_vmem,
diff --git a/drivers/staging/fbtft/fb_bd663474.c b/drivers/staging/fbtft/fb_bd663474.c
index e2c7646588f8..1629c2c440a9 100644
--- a/drivers/staging/fbtft/fb_bd663474.c
+++ b/drivers/staging/fbtft/fb_bd663474.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
@@ -24,9 +23,6 @@
static int init_display(struct fbtft_par *par)
{
- if (par->gpio.cs)
- gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
-
par->fbtftops.reset(par);
/* Initialization sequence from Lib_UTFT */
diff --git a/drivers/staging/fbtft/fb_hx8347d.c b/drivers/staging/fbtft/fb_hx8347d.c
index 37eaf0862c5b..a9b72a8b42b5 100644
--- a/drivers/staging/fbtft/fb_hx8347d.c
+++ b/drivers/staging/fbtft/fb_hx8347d.c
@@ -68,9 +68,6 @@ static int init_display(struct fbtft_par *par)
mdelay(40);
write_reg(par, 0x28, 0x3C);
- /* orientation */
- write_reg(par, 0x16, 0x60 | (par->bgr << 3));
-
return 0;
}
@@ -87,6 +84,31 @@ static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
write_reg(par, 0x22);
}
+#define MEM_Y BIT(7) /* MY row address order */
+#define MEM_X BIT(6) /* MX column address order */
+#define MEM_V BIT(5) /* MV row / column exchange */
+#define MEM_L BIT(4) /* ML vertical refresh order */
+#define MEM_BGR (3) /* RGB-BGR Order */
+static int set_var(struct fbtft_par *par)
+{
+ switch (par->info->var.rotate) {
+ case 0:
+ write_reg(par, 0x16, MEM_V | MEM_X | (par->bgr << MEM_BGR));
+ break;
+ case 270:
+ write_reg(par, 0x16, par->bgr << MEM_BGR);
+ break;
+ case 180:
+ write_reg(par, 0x16, MEM_V | MEM_Y | (par->bgr << MEM_BGR));
+ break;
+ case 90:
+ write_reg(par, 0x16, MEM_X | MEM_Y | (par->bgr << MEM_BGR));
+ break;
+ }
+
+ return 0;
+}
+
/*
* Gamma string format:
* VRP0 VRP1 VRP2 VRP3 VRP4 VRP5 PRP0 PRP1 PKP0 PKP1 PKP2 PKP3 PKP4 CGM
@@ -144,6 +166,7 @@ static struct fbtft_display display = {
.fbtftops = {
.init_display = init_display,
.set_addr_win = set_addr_win,
+ .set_var = set_var,
.set_gamma = set_gamma,
},
};
diff --git a/drivers/staging/fbtft/fb_ili9163.c b/drivers/staging/fbtft/fb_ili9163.c
index 05648c3ffe47..6582a2c90aaf 100644
--- a/drivers/staging/fbtft/fb_ili9163.c
+++ b/drivers/staging/fbtft/fb_ili9163.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <video/mipi_display.h>
@@ -77,9 +76,6 @@ static int init_display(struct fbtft_par *par)
{
par->fbtftops.reset(par);
- if (par->gpio.cs)
- gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
-
write_reg(par, MIPI_DCS_SOFT_RESET); /* software reset */
mdelay(500);
write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE); /* exit sleep */
diff --git a/drivers/staging/fbtft/fb_ili9320.c b/drivers/staging/fbtft/fb_ili9320.c
index f2e72d14431d..0be7c2d51548 100644
--- a/drivers/staging/fbtft/fb_ili9320.c
+++ b/drivers/staging/fbtft/fb_ili9320.c
@@ -8,7 +8,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
@@ -22,11 +21,10 @@
static unsigned int read_devicecode(struct fbtft_par *par)
{
- int ret;
u8 rxbuf[8] = {0, };
write_reg(par, 0x0000);
- ret = par->fbtftops.read(par, rxbuf, 4);
+ par->fbtftops.read(par, rxbuf, 4);
return (rxbuf[2] << 8) | rxbuf[3];
}
diff --git a/drivers/staging/fbtft/fb_ili9325.c b/drivers/staging/fbtft/fb_ili9325.c
index c9aa4cb43123..16d3b17ca279 100644
--- a/drivers/staging/fbtft/fb_ili9325.c
+++ b/drivers/staging/fbtft/fb_ili9325.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
@@ -85,9 +84,6 @@ static int init_display(struct fbtft_par *par)
{
par->fbtftops.reset(par);
- if (par->gpio.cs)
- gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
-
bt &= 0x07;
vc &= 0x07;
vrh &= 0x0f;
diff --git a/drivers/staging/fbtft/fb_ili9340.c b/drivers/staging/fbtft/fb_ili9340.c
index 415183c7054a..704236bcaf3f 100644
--- a/drivers/staging/fbtft/fb_ili9340.c
+++ b/drivers/staging/fbtft/fb_ili9340.c
@@ -8,7 +8,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <video/mipi_display.h>
diff --git a/drivers/staging/fbtft/fb_s6d1121.c b/drivers/staging/fbtft/fb_s6d1121.c
index 8c7de3290343..62f27172f844 100644
--- a/drivers/staging/fbtft/fb_s6d1121.c
+++ b/drivers/staging/fbtft/fb_s6d1121.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
@@ -29,9 +28,6 @@ static int init_display(struct fbtft_par *par)
{
par->fbtftops.reset(par);
- if (par->gpio.cs)
- gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
-
/* Initialization sequence from Lib_UTFT */
write_reg(par, 0x0011, 0x2004);
diff --git a/drivers/staging/fbtft/fb_sh1106.c b/drivers/staging/fbtft/fb_sh1106.c
index 6f7249493ea3..7b9ab39e1c1a 100644
--- a/drivers/staging/fbtft/fb_sh1106.c
+++ b/drivers/staging/fbtft/fb_sh1106.c
@@ -9,7 +9,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
diff --git a/drivers/staging/fbtft/fb_ssd1289.c b/drivers/staging/fbtft/fb_ssd1289.c
index 7a3fe022cc69..f27bab38b3ec 100644
--- a/drivers/staging/fbtft/fb_ssd1289.c
+++ b/drivers/staging/fbtft/fb_ssd1289.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio/consumer.h>
#include "fbtft.h"
@@ -28,9 +27,6 @@ static int init_display(struct fbtft_par *par)
{
par->fbtftops.reset(par);
- if (par->gpio.cs)
- gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
-
write_reg(par, 0x00, 0x0001);
write_reg(par, 0x03, 0xA8A4);
write_reg(par, 0x0C, 0x0000);
diff --git a/drivers/staging/fbtft/fb_ssd1325.c b/drivers/staging/fbtft/fb_ssd1325.c
index 8a3140d41d8b..796a2ac3e194 100644
--- a/drivers/staging/fbtft/fb_ssd1325.c
+++ b/drivers/staging/fbtft/fb_ssd1325.c
@@ -35,8 +35,6 @@ static int init_display(struct fbtft_par *par)
{
par->fbtftops.reset(par);
- gpiod_set_value(par->gpio.cs, 0);
-
write_reg(par, 0xb3);
write_reg(par, 0xf0);
write_reg(par, 0xae);
diff --git a/drivers/staging/fbtft/fb_ssd1331.c b/drivers/staging/fbtft/fb_ssd1331.c
index 37622c9462aa..ec5eced7f8cb 100644
--- a/drivers/staging/fbtft/fb_ssd1331.c
+++ b/drivers/staging/fbtft/fb_ssd1331.c
@@ -81,8 +81,7 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
va_start(args, len);
*buf = (u8)va_arg(args, unsigned int);
- if (par->gpio.dc)
- gpiod_set_value(par->gpio.dc, 0);
+ gpiod_set_value(par->gpio.dc, 0);
ret = par->fbtftops.write(par, par->buf, sizeof(u8));
if (ret < 0) {
va_end(args);
@@ -104,8 +103,7 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
return;
}
}
- if (par->gpio.dc)
- gpiod_set_value(par->gpio.dc, 1);
+ gpiod_set_value(par->gpio.dc, 1);
va_end(args);
}
diff --git a/drivers/staging/fbtft/fb_ssd1351.c b/drivers/staging/fbtft/fb_ssd1351.c
index 900b28d826b2..cf263a58a148 100644
--- a/drivers/staging/fbtft/fb_ssd1351.c
+++ b/drivers/staging/fbtft/fb_ssd1351.c
@@ -2,7 +2,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
diff --git a/drivers/staging/fbtft/fb_upd161704.c b/drivers/staging/fbtft/fb_upd161704.c
index c77832ae5e5b..c680160d6380 100644
--- a/drivers/staging/fbtft/fb_upd161704.c
+++ b/drivers/staging/fbtft/fb_upd161704.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
@@ -26,9 +25,6 @@ static int init_display(struct fbtft_par *par)
{
par->fbtftops.reset(par);
- if (par->gpio.cs)
- gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
-
/* Initialization sequence from Lib_UTFT */
/* register reset */
diff --git a/drivers/staging/fbtft/fb_watterott.c b/drivers/staging/fbtft/fb_watterott.c
index 76b25df376b8..a57e1f4feef3 100644
--- a/drivers/staging/fbtft/fb_watterott.c
+++ b/drivers/staging/fbtft/fb_watterott.c
@@ -8,7 +8,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
diff --git a/drivers/staging/fbtft/fbtft-bus.c b/drivers/staging/fbtft/fbtft-bus.c
index 63c65dd67b17..3d422bc11641 100644
--- a/drivers/staging/fbtft/fbtft-bus.c
+++ b/drivers/staging/fbtft/fbtft-bus.c
@@ -135,8 +135,7 @@ int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len)
remain = len / 2;
vmem16 = (u16 *)(par->info->screen_buffer + offset);
- if (par->gpio.dc)
- gpiod_set_value(par->gpio.dc, 1);
+ gpiod_set_value(par->gpio.dc, 1);
/* non buffered write */
if (!par->txbuf.buf)
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
index 4f362dad4436..3723269890d5 100644
--- a/drivers/staging/fbtft/fbtft-core.c
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -38,8 +38,7 @@ int fbtft_write_buf_dc(struct fbtft_par *par, void *buf, size_t len, int dc)
{
int ret;
- if (par->gpio.dc)
- gpiod_set_value(par->gpio.dc, dc);
+ gpiod_set_value(par->gpio.dc, dc);
ret = par->fbtftops.write(par, buf, len);
if (ret < 0)
@@ -76,20 +75,16 @@ static int fbtft_request_one_gpio(struct fbtft_par *par,
struct gpio_desc **gpiop)
{
struct device *dev = par->info->device;
- int ret = 0;
*gpiop = devm_gpiod_get_index_optional(dev, name, index,
- GPIOD_OUT_HIGH);
- if (IS_ERR(*gpiop)) {
- ret = PTR_ERR(*gpiop);
- dev_err(dev,
- "Failed to request %s GPIO: %d\n", name, ret);
- return ret;
- }
+ GPIOD_OUT_LOW);
+ if (IS_ERR(*gpiop))
+ return dev_err_probe(dev, PTR_ERR(*gpiop), "Failed to request %s GPIO\n", name);
+
fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' GPIO\n",
__func__, name);
- return ret;
+ return 0;
}
static int fbtft_request_gpios(struct fbtft_par *par)
@@ -226,11 +221,15 @@ static void fbtft_reset(struct fbtft_par *par)
{
if (!par->gpio.reset)
return;
+
fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__);
+
gpiod_set_value_cansleep(par->gpio.reset, 1);
usleep_range(20, 40);
gpiod_set_value_cansleep(par->gpio.reset, 0);
msleep(120);
+
+ gpiod_set_value_cansleep(par->gpio.cs, 1); /* Activate chip */
}
static void fbtft_update_display(struct fbtft_par *par, unsigned int start_line,
@@ -922,8 +921,6 @@ static int fbtft_init_display_from_property(struct fbtft_par *par)
goto out_free;
par->fbtftops.reset(par);
- if (par->gpio.cs)
- gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
index = -1;
val = values[++index];
@@ -1018,8 +1015,6 @@ int fbtft_init_display(struct fbtft_par *par)
}
par->fbtftops.reset(par);
- if (par->gpio.cs)
- gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
i = 0;
while (i < FBTFT_MAX_INIT_SEQUENCE) {
diff --git a/drivers/staging/fbtft/fbtft-io.c b/drivers/staging/fbtft/fbtft-io.c
index 0863d257d762..de1904a443c2 100644
--- a/drivers/staging/fbtft/fbtft-io.c
+++ b/drivers/staging/fbtft/fbtft-io.c
@@ -142,12 +142,12 @@ int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len)
data = *(u8 *)buf;
/* Start writing by pulling down /WR */
- gpiod_set_value(par->gpio.wr, 0);
+ gpiod_set_value(par->gpio.wr, 1);
/* Set data */
#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
if (data == prev_data) {
- gpiod_set_value(par->gpio.wr, 0); /* used as delay */
+ gpiod_set_value(par->gpio.wr, 1); /* used as delay */
} else {
for (i = 0; i < 8; i++) {
if ((data & 1) != (prev_data & 1))
@@ -165,7 +165,7 @@ int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len)
#endif
/* Pullup /WR */
- gpiod_set_value(par->gpio.wr, 1);
+ gpiod_set_value(par->gpio.wr, 0);
#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
prev_data = *(u8 *)buf;
@@ -192,12 +192,12 @@ int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len)
data = *(u16 *)buf;
/* Start writing by pulling down /WR */
- gpiod_set_value(par->gpio.wr, 0);
+ gpiod_set_value(par->gpio.wr, 1);
/* Set data */
#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
if (data == prev_data) {
- gpiod_set_value(par->gpio.wr, 0); /* used as delay */
+ gpiod_set_value(par->gpio.wr, 1); /* used as delay */
} else {
for (i = 0; i < 16; i++) {
if ((data & 1) != (prev_data & 1))
@@ -215,7 +215,7 @@ int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len)
#endif
/* Pullup /WR */
- gpiod_set_value(par->gpio.wr, 1);
+ gpiod_set_value(par->gpio.wr, 0);
#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
prev_data = *(u16 *)buf;
diff --git a/drivers/staging/fieldbus/anybuss/anybuss-client.h b/drivers/staging/fieldbus/anybuss/anybuss-client.h
index 8ee1f1baccf1..a219688006fe 100644
--- a/drivers/staging/fieldbus/anybuss/anybuss-client.h
+++ b/drivers/staging/fieldbus/anybuss/anybuss-client.h
@@ -32,7 +32,7 @@ struct anybuss_client {
struct anybuss_client_driver {
struct device_driver driver;
int (*probe)(struct anybuss_client *adev);
- int (*remove)(struct anybuss_client *adev);
+ void (*remove)(struct anybuss_client *adev);
u16 anybus_id;
};
diff --git a/drivers/staging/fieldbus/anybuss/hms-profinet.c b/drivers/staging/fieldbus/anybuss/hms-profinet.c
index eca7d97b8e85..e691736a53f1 100644
--- a/drivers/staging/fieldbus/anybuss/hms-profinet.c
+++ b/drivers/staging/fieldbus/anybuss/hms-profinet.c
@@ -190,12 +190,11 @@ static int profinet_probe(struct anybuss_client *client)
return 0;
}
-static int profinet_remove(struct anybuss_client *client)
+static void profinet_remove(struct anybuss_client *client)
{
struct profi_priv *priv = anybuss_get_drvdata(client);
fieldbus_dev_unregister(&priv->fbdev);
- return 0;
}
static struct anybuss_client_driver profinet_driver = {
diff --git a/drivers/staging/fieldbus/anybuss/host.c b/drivers/staging/fieldbus/anybuss/host.c
index c97df91124a4..0f730efe9a6d 100644
--- a/drivers/staging/fieldbus/anybuss/host.c
+++ b/drivers/staging/fieldbus/anybuss/host.c
@@ -1183,8 +1183,6 @@ static int anybus_bus_probe(struct device *dev)
struct anybuss_client *adev =
to_anybuss_client(dev);
- if (!adrv->probe)
- return -ENODEV;
return adrv->probe(adev);
}
@@ -1194,7 +1192,8 @@ static int anybus_bus_remove(struct device *dev)
to_anybuss_client_driver(dev->driver);
if (adrv->remove)
- return adrv->remove(to_anybuss_client(dev));
+ adrv->remove(to_anybuss_client(dev));
+
return 0;
}
@@ -1207,6 +1206,9 @@ static struct bus_type anybus_bus = {
int anybuss_client_driver_register(struct anybuss_client_driver *drv)
{
+ if (!drv->probe)
+ return -ENODEV;
+
drv->driver.bus = &anybus_bus;
return driver_register(&drv->driver);
}
diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c
index 1ee6382cafc4..38a280e876c2 100644
--- a/drivers/staging/fwserial/fwserial.c
+++ b/drivers/staging/fwserial/fwserial.c
@@ -45,14 +45,14 @@ module_param_named(loop, create_loop_dev, bool, 0644);
*/
#define WAKEUP_CHARS 256
-/**
+/*
* fwserial_list: list of every fw_serial created for each fw_card
* See discussion in fwserial_probe.
*/
static LIST_HEAD(fwserial_list);
static DEFINE_MUTEX(fwserial_list_mutex);
-/**
+/*
* port_table: array of tty ports allocated to each fw_card
*
* tty ports are allocated during probe when an fw_serial is first
@@ -284,7 +284,7 @@ static void fwtty_restart_tx(struct fwtty_port *port)
spin_unlock_bh(&port->lock);
}
-/**
+/*
* fwtty_update_port_status - decodes & dispatches line status changes
*
* Note: in loopback, the port->lock is being held. Only use functions that
@@ -375,7 +375,7 @@ static void fwtty_update_port_status(struct fwtty_port *port,
wake_up_interruptible(&port->port.delta_msr_wait);
}
-/**
+/*
* __fwtty_port_line_status - generate 'line status' for indicated port
*
* This function returns a remote 'MSR' state based on the local 'MCR' state,
@@ -403,7 +403,7 @@ static unsigned int __fwtty_port_line_status(struct fwtty_port *port)
return status;
}
-/**
+/*
* __fwtty_write_port_status - send the port line status to peer
*
* Note: caller must be holding the port lock.
@@ -426,7 +426,7 @@ static int __fwtty_write_port_status(struct fwtty_port *port)
return err;
}
-/**
+/*
* fwtty_write_port_status - same as above but locked by port lock
*/
static int fwtty_write_port_status(struct fwtty_port *port)
@@ -462,7 +462,7 @@ static void fwtty_throttle_port(struct fwtty_port *port)
tty_kref_put(tty);
}
-/**
+/*
* fwtty_do_hangup - wait for ldisc to deliver all pending rx; only then hangup
*
* When the remote has finished tx, and all in-flight rx has been received and
@@ -589,9 +589,8 @@ out:
return err;
}
-/**
+/*
* fwtty_port_handler - bus address handler for port reads/writes
- * @parameters: fw_address_callback_t as specified by firewire core interface
*
* This handler is responsible for handling inbound read/write dma from remotes.
*/
@@ -656,7 +655,7 @@ respond:
fw_send_response(card, request, rcode);
}
-/**
+/*
* fwtty_tx_complete - callback for tx dma
* @data: ignored, has no meaning for write txns
* @length: ignored, has no meaning for write txns
@@ -722,7 +721,7 @@ static int fwtty_tx(struct fwtty_port *port, bool drain)
/* try to write as many dma transactions out as possible */
n = -EAGAIN;
- while (!tty->stopped && !tty->hw_stopped &&
+ while (!tty->flow.stopped && !tty->hw_stopped &&
!test_bit(STOP_TX, &port->flags)) {
txn = kmem_cache_alloc(fwtty_txn_cache, GFP_ATOMIC);
if (!txn) {
@@ -904,7 +903,7 @@ static void fwtty_port_dtr_rts(struct tty_port *tty_port, int on)
spin_unlock_bh(&port->lock);
}
-/**
+/*
* fwtty_port_carrier_raised: required tty_port operation
*
* This port operation is polled after a tty has been opened and is waiting for
@@ -1011,7 +1010,7 @@ static int fwtty_port_activate(struct tty_port *tty_port,
return 0;
}
-/**
+/*
* fwtty_port_shutdown
*
* Note: the tty port core ensures this is not the console and
@@ -1113,30 +1112,30 @@ static int fwtty_write(struct tty_struct *tty, const unsigned char *buf, int c)
return (n < 0) ? 0 : n;
}
-static int fwtty_write_room(struct tty_struct *tty)
+static unsigned int fwtty_write_room(struct tty_struct *tty)
{
struct fwtty_port *port = tty->driver_data;
- int n;
+ unsigned int n;
spin_lock_bh(&port->lock);
n = dma_fifo_avail(&port->tx_fifo);
spin_unlock_bh(&port->lock);
- fwtty_dbg(port, "%d\n", n);
+ fwtty_dbg(port, "%u\n", n);
return n;
}
-static int fwtty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int fwtty_chars_in_buffer(struct tty_struct *tty)
{
struct fwtty_port *port = tty->driver_data;
- int n;
+ unsigned int n;
spin_lock_bh(&port->lock);
n = dma_fifo_level(&port->tx_fifo);
spin_unlock_bh(&port->lock);
- fwtty_dbg(port, "%d\n", n);
+ fwtty_dbg(port, "%u\n", n);
return n;
}
@@ -1297,7 +1296,7 @@ static void fwtty_set_termios(struct tty_struct *tty, struct ktermios *old)
}
}
-/**
+/*
* fwtty_break_ctl - start/stop sending breaks
*
* Signals the remote to start or stop generating simulated breaks.
@@ -1669,7 +1668,7 @@ static inline int fwserial_send_mgmt_sync(struct fwtty_peer *peer,
return rcode;
}
-/**
+/*
* fwserial_claim_port - attempt to claim port @ index for peer
*
* Returns ptr to claimed port or error code (as ERR_PTR())
@@ -1697,7 +1696,7 @@ static struct fwtty_port *fwserial_claim_port(struct fwtty_peer *peer,
return port;
}
-/**
+/*
* fwserial_find_port - find avail port and claim for peer
*
* Returns ptr to claimed port or NULL if none avail
@@ -1764,7 +1763,7 @@ static void fwserial_plug_timeout(struct timer_list *t)
fwserial_release_port(port, false);
}
-/**
+/*
* fwserial_connect_peer - initiate virtual cable with peer
*
* Returns 0 if VIRT_CABLE_PLUG request was successfully sent,
@@ -1829,7 +1828,7 @@ free_pkt:
return err;
}
-/**
+/*
* fwserial_close_port -
* HUP the tty (if the tty exists) and unregister the tty device.
* Only used by the unit driver upon unit removal to disconnect and
@@ -1893,7 +1892,7 @@ static struct fw_serial *__fwserial_lookup_rcu(struct fw_card *card)
return NULL;
}
-/**
+/*
* __fwserial_peer_by_node_id - finds a peer matching the given generation + id
*
* If a matching peer could not be found for the specified generation/node id,
@@ -2076,7 +2075,7 @@ static int fwserial_add_peer(struct fw_serial *serial, struct fw_unit *unit)
return 0;
}
-/**
+/*
* fwserial_remove_peer - remove a 'serial' unit device as a 'peer'
*
* Remove a 'peer' from its list of peers. This function is only
@@ -2279,7 +2278,7 @@ free_ports:
return err;
}
-/**
+/*
* fwserial_probe: bus probe function for firewire 'serial' unit devices
*
* A 'serial' unit device is created and probed as a result of:
@@ -2331,7 +2330,7 @@ static int fwserial_probe(struct fw_unit *unit,
return err;
}
-/**
+/*
* fwserial_remove: bus removal function for firewire 'serial' unit devices
*
* The corresponding 'peer' for this unit device is removed from the list of
@@ -2363,7 +2362,7 @@ static void fwserial_remove(struct fw_unit *unit)
mutex_unlock(&fwserial_list_mutex);
}
-/**
+/*
* fwserial_update: bus update function for 'firewire' serial unit devices
*
* Updates the new node_id and bus generation for this peer. Note that locking
@@ -2699,9 +2698,8 @@ static int fwserial_parse_mgmt_write(struct fwtty_peer *peer,
return rcode;
}
-/**
+/*
* fwserial_mgmt_handler: bus address handler for mgmt requests
- * @parameters: fw_address_callback_t as specified by firewire core interface
*
* This handler is responsible for handling virtual cable requests from remotes
* for all cards.
diff --git a/drivers/staging/gdm724x/gdm_lte.c b/drivers/staging/gdm724x/gdm_lte.c
index 571f47d39484..e390c924ec1c 100644
--- a/drivers/staging/gdm724x/gdm_lte.c
+++ b/drivers/staging/gdm724x/gdm_lte.c
@@ -611,10 +611,12 @@ static void gdm_lte_netif_rx(struct net_device *dev, char *buf,
* bytes (99,130,83,99 dec)
*/
} __packed;
- void *addr = buf + sizeof(struct iphdr) +
- sizeof(struct udphdr) +
- offsetof(struct dhcp_packet, chaddr);
- ether_addr_copy(nic->dest_mac_addr, addr);
+ int offset = sizeof(struct iphdr) +
+ sizeof(struct udphdr) +
+ offsetof(struct dhcp_packet, chaddr);
+ if (offset + ETH_ALEN > len)
+ return;
+ ether_addr_copy(nic->dest_mac_addr, buf + offset);
}
}
@@ -677,6 +679,7 @@ static void gdm_lte_multi_sdu_pkt(struct phy_dev *phy_dev, char *buf, int len)
struct sdu *sdu = NULL;
u8 endian = phy_dev->get_endian(phy_dev->priv_dev);
u8 *data = (u8 *)multi_sdu->data;
+ int copied;
u16 i = 0;
u16 num_packet;
u16 hci_len;
@@ -684,10 +687,15 @@ static void gdm_lte_multi_sdu_pkt(struct phy_dev *phy_dev, char *buf, int len)
u32 nic_type;
int index;
- hci_len = gdm_dev16_to_cpu(endian, multi_sdu->len);
num_packet = gdm_dev16_to_cpu(endian, multi_sdu->num_packet);
for (i = 0; i < num_packet; i++) {
+ copied = data - multi_sdu->data;
+ if (len < copied + sizeof(*sdu)) {
+ pr_err("rx prevent buffer overflow");
+ return;
+ }
+
sdu = (struct sdu *)data;
cmd_evt = gdm_dev16_to_cpu(endian, sdu->cmd_evt);
@@ -698,7 +706,8 @@ static void gdm_lte_multi_sdu_pkt(struct phy_dev *phy_dev, char *buf, int len)
pr_err("rx sdu wrong hci %04x\n", cmd_evt);
return;
}
- if (hci_len < 12) {
+ if (hci_len < 12 ||
+ len < copied + sizeof(*sdu) + (hci_len - 12)) {
pr_err("rx sdu invalid len %d\n", hci_len);
return;
}
diff --git a/drivers/staging/gdm724x/gdm_tty.c b/drivers/staging/gdm724x/gdm_tty.c
index 0ccc8c24e754..279de2cd9c4a 100644
--- a/drivers/staging/gdm724x/gdm_tty.c
+++ b/drivers/staging/gdm724x/gdm_tty.c
@@ -183,7 +183,7 @@ static int gdm_tty_write(struct tty_struct *tty, const unsigned char *buf,
return len;
}
-static int gdm_tty_write_room(struct tty_struct *tty)
+static unsigned int gdm_tty_write_room(struct tty_struct *tty)
{
struct gdm *gdm = tty->driver_data;
diff --git a/drivers/staging/greybus/audio_topology.c b/drivers/staging/greybus/audio_topology.c
index 1fc7727ab7be..1e613d42d823 100644
--- a/drivers/staging/greybus/audio_topology.c
+++ b/drivers/staging/greybus/audio_topology.c
@@ -676,7 +676,7 @@ static int gbaudio_tplg_create_kcontrol(struct gbaudio_module_info *gb,
struct gbaudio_ctl_pvt *ctldata;
switch (ctl->iface) {
- case SNDRV_CTL_ELEM_IFACE_MIXER:
+ case (__force int)SNDRV_CTL_ELEM_IFACE_MIXER:
switch (ctl->info.type) {
case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED:
ret = gbaudio_tplg_create_enum_kctl(gb, kctl, ctl);
@@ -903,7 +903,7 @@ static int gbaudio_tplg_create_wcontrol(struct gbaudio_module_info *gb,
int ret;
switch (ctl->iface) {
- case SNDRV_CTL_ELEM_IFACE_MIXER:
+ case (__force int)SNDRV_CTL_ELEM_IFACE_MIXER:
switch (ctl->info.type) {
case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED:
ret = gbaudio_tplg_create_enum_ctl(gb, kctl, ctl);
diff --git a/drivers/staging/greybus/gbphy.c b/drivers/staging/greybus/gbphy.c
index 9fc5c47be9bd..13d319860da5 100644
--- a/drivers/staging/greybus/gbphy.c
+++ b/drivers/staging/greybus/gbphy.c
@@ -27,7 +27,7 @@ struct gbphy_host {
static DEFINE_IDA(gbphy_id);
static ssize_t protocol_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr, char *buf)
{
struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
@@ -221,7 +221,7 @@ void gb_gbphy_deregister_driver(struct gbphy_driver *driver)
EXPORT_SYMBOL_GPL(gb_gbphy_deregister_driver);
static struct gbphy_device *gb_gbphy_create_dev(struct gb_bundle *bundle,
- struct greybus_descriptor_cport *cport_desc)
+ struct greybus_descriptor_cport *cport_desc)
{
struct gbphy_device *gbphy_dev;
int retval;
diff --git a/drivers/staging/greybus/spilib.c b/drivers/staging/greybus/spilib.c
index 30655153df6a..ad0700a0bb81 100644
--- a/drivers/staging/greybus/spilib.c
+++ b/drivers/staging/greybus/spilib.c
@@ -246,6 +246,7 @@ static struct gb_operation *gb_spi_operation_create(struct gb_spilib *spi,
xfer = spi->first_xfer;
while (msg->state != GB_SPI_STATE_OP_DONE) {
int xfer_delay;
+
if (xfer == spi->last_xfer)
xfer_len = spi->last_xfer_size;
else
diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c
index b1e63f7798b0..73f01ed1e5b7 100644
--- a/drivers/staging/greybus/uart.c
+++ b/drivers/staging/greybus/uart.c
@@ -440,7 +440,7 @@ static int gb_tty_write(struct tty_struct *tty, const unsigned char *buf,
return count;
}
-static int gb_tty_write_room(struct tty_struct *tty)
+static unsigned int gb_tty_write_room(struct tty_struct *tty)
{
struct gb_tty *gb_tty = tty->driver_data;
unsigned long flags;
@@ -457,11 +457,11 @@ static int gb_tty_write_room(struct tty_struct *tty)
return room;
}
-static int gb_tty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int gb_tty_chars_in_buffer(struct tty_struct *tty)
{
struct gb_tty *gb_tty = tty->driver_data;
unsigned long flags;
- int chars;
+ unsigned int chars;
spin_lock_irqsave(&gb_tty->write_lock, flags);
chars = kfifo_len(&gb_tty->write_fifo);
@@ -494,21 +494,7 @@ static void gb_tty_set_termios(struct tty_struct *tty,
(termios->c_cflag & PARODD ? 1 : 2) +
(termios->c_cflag & CMSPAR ? 2 : 0) : 0;
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- newline.data_bits = 5;
- break;
- case CS6:
- newline.data_bits = 6;
- break;
- case CS7:
- newline.data_bits = 7;
- break;
- case CS8:
- default:
- newline.data_bits = 8;
- break;
- }
+ newline.data_bits = tty_get_char_size(termios->c_cflag);
/* FIXME: needs to clear unsupported bits in the termios */
gb_tty->clocal = ((termios->c_cflag & CLOCAL) != 0);
diff --git a/drivers/staging/gs_fpgaboot/README b/drivers/staging/gs_fpgaboot/README
index b85a76849fc4..ec1235a21bcc 100644
--- a/drivers/staging/gs_fpgaboot/README
+++ b/drivers/staging/gs_fpgaboot/README
@@ -39,7 +39,7 @@ TABLE OF CONTENTS.
5. USE CASE (from a mailing list discussion with Greg)
- a. As a FPGA development support tool,
+ a. As an FPGA development support tool,
During FPGA firmware development, you need to download a new FPGA
image frequently.
You would do that with a dedicated JTAG, which usually a limited
diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig
index c4dc1016edf2..9f53df9068fe 100644
--- a/drivers/staging/hikey9xx/Kconfig
+++ b/drivers/staging/hikey9xx/Kconfig
@@ -1,27 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-# to be placed at drivers/phy
-config PHY_HI3670_USB
- tristate "hi3670 USB PHY support"
- depends on (ARCH_HISI && ARM64) || COMPILE_TEST
- select GENERIC_PHY
- select MFD_SYSCON
- help
- Enable this to support the HISILICON HI3670 USB PHY.
-
- To compile this driver as a module, choose M here.
-
-# to be placed at drivers/spmi
-config SPMI_HISI3670
- tristate "Hisilicon 3670 SPMI Controller"
- select IRQ_DOMAIN_HIERARCHY
- depends on HAS_IOMEM
- depends on SPMI
- help
- If you say yes to this option, support will be included for the
- built-in SPMI PMIC Arbiter interface on Hisilicon 3670
- processors.
-
# to be placed at drivers/mfd
config MFD_HI6421_SPMI
tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC"
diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile
index 9103735d8377..e3108d7dd849 100644
--- a/drivers/staging/hikey9xx/Makefile
+++ b/drivers/staging/hikey9xx/Makefile
@@ -1,6 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_PHY_HI3670_USB) += phy-hi3670-usb3.o
-
-obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o
obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o
diff --git a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c b/drivers/staging/hikey9xx/hi6421-spmi-pmic.c
index 626140cb96f2..35ef3d4c760b 100644
--- a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c
+++ b/drivers/staging/hikey9xx/hi6421-spmi-pmic.c
@@ -33,17 +33,27 @@ enum hi6421_spmi_pmic_irq_list {
SIM0_HPD_F,
SIM1_HPD_R,
SIM1_HPD_F,
- PMIC_IRQ_LIST_MAX,
+
+ PMIC_IRQ_LIST_MAX
};
-#define HISI_IRQ_ARRAY 2
-#define HISI_IRQ_NUM (HISI_IRQ_ARRAY * 8)
+#define HISI_IRQ_BANK_SIZE 2
-#define HISI_IRQ_KEY_NUM 0
+/*
+ * IRQ number for the power key button and mask for both UP and DOWN IRQs
+ */
+#define HISI_POWERKEY_IRQ_NUM 0
+#define HISI_IRQ_POWERKEY_UP_DOWN (BIT(POWERKEY_DOWN) | BIT(POWERKEY_UP))
-#define HISI_BITS 8
-#define HISI_IRQ_KEY_VALUE (BIT(POWERKEY_DOWN) | BIT(POWERKEY_UP))
-#define HISI_MASK GENMASK(HISI_BITS - 1, 0)
+/*
+ * Registers for IRQ address and IRQ mask bits
+ *
+ * Please notice that we need to regmap a larger region, as other
+ * registers are used by the regulators.
+ * See drivers/regulator/hi6421-regulator.c.
+ */
+#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202
+#define SOC_PMIC_IRQ0_ADDR 0x0212
/*
* The IRQs are mapped as:
@@ -67,13 +77,14 @@ enum hi6421_spmi_pmic_irq_list {
* SIM1_HPD_R 0x0203 0x213 bit 4
* SIM1_HPD_F 0x0203 0x213 bit 5
* ====================== ============= ============ =====
+ *
+ * Each mask register contains 8 bits. The ancillary macros below
+ * convert a number from 0 to 14 into a register address and a bit mask
*/
-#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202
-#define SOC_PMIC_IRQ0_ADDR 0x0212
-
-#define IRQ_MASK_REGISTER(irq_data) (SOC_PMIC_IRQ_MASK_0_ADDR + \
- (irqd_to_hwirq(irq_data) >> 3))
-#define IRQ_MASK_BIT(irq_data) BIT(irqd_to_hwirq(irq_data) & 0x07)
+#define HISI_IRQ_MASK_REG(irq_data) (SOC_PMIC_IRQ_MASK_0_ADDR + \
+ (irqd_to_hwirq(irq_data) / BITS_PER_BYTE))
+#define HISI_IRQ_MASK_BIT(irq_data) BIT(irqd_to_hwirq(irq_data) & (BITS_PER_BYTE - 1))
+#define HISI_8BITS_MASK 0xff
static const struct mfd_cell hi6421v600_devs[] = {
{ .name = "hi6421v600-regulator", },
@@ -86,23 +97,31 @@ static irqreturn_t hi6421_spmi_irq_handler(int irq, void *priv)
unsigned int in;
int i, offset;
- for (i = 0; i < HISI_IRQ_ARRAY; i++) {
+ for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
regmap_read(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, &in);
- pending = HISI_MASK & in;
- regmap_write(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, pending);
- if (i == HISI_IRQ_KEY_NUM &&
- (pending & HISI_IRQ_KEY_VALUE) == HISI_IRQ_KEY_VALUE) {
+ /* Mark pending IRQs as handled */
+ regmap_write(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, in);
+
+ pending = in & HISI_8BITS_MASK;
+
+ if (i == HISI_POWERKEY_IRQ_NUM &&
+ (pending & HISI_IRQ_POWERKEY_UP_DOWN) == HISI_IRQ_POWERKEY_UP_DOWN) {
+ /*
+ * If both powerkey down and up IRQs are received,
+ * handle them at the right order
+ */
generic_handle_irq(ddata->irqs[POWERKEY_DOWN]);
generic_handle_irq(ddata->irqs[POWERKEY_UP]);
- pending &= (~HISI_IRQ_KEY_VALUE);
+ pending &= ~HISI_IRQ_POWERKEY_UP_DOWN;
}
if (!pending)
continue;
- for_each_set_bit(offset, &pending, HISI_BITS)
- generic_handle_irq(ddata->irqs[offset + i * HISI_BITS]);
+ for_each_set_bit(offset, &pending, BITS_PER_BYTE) {
+ generic_handle_irq(ddata->irqs[offset + i * BITS_PER_BYTE]);
+ }
}
return IRQ_HANDLED;
@@ -115,12 +134,12 @@ static void hi6421_spmi_irq_mask(struct irq_data *d)
unsigned int data;
u32 offset;
- offset = IRQ_MASK_REGISTER(d);
+ offset = HISI_IRQ_MASK_REG(d);
spin_lock_irqsave(&ddata->lock, flags);
regmap_read(ddata->regmap, offset, &data);
- data |= IRQ_MASK_BIT(d);
+ data |= HISI_IRQ_MASK_BIT(d);
regmap_write(ddata->regmap, offset, data);
spin_unlock_irqrestore(&ddata->lock, flags);
@@ -132,20 +151,19 @@ static void hi6421_spmi_irq_unmask(struct irq_data *d)
u32 data, offset;
unsigned long flags;
- offset = (irqd_to_hwirq(d) >> 3);
- offset += SOC_PMIC_IRQ_MASK_0_ADDR;
+ offset = HISI_IRQ_MASK_REG(d);
spin_lock_irqsave(&ddata->lock, flags);
regmap_read(ddata->regmap, offset, &data);
- data &= ~(1 << (irqd_to_hwirq(d) & 0x07));
+ data &= ~HISI_IRQ_MASK_BIT(d);
regmap_write(ddata->regmap, offset, data);
spin_unlock_irqrestore(&ddata->lock, flags);
}
static struct irq_chip hi6421_spmi_pmu_irqchip = {
- .name = "hisi-irq",
+ .name = "hi6421v600-irq",
.irq_mask = hi6421_spmi_irq_mask,
.irq_unmask = hi6421_spmi_irq_unmask,
.irq_disable = hi6421_spmi_irq_mask,
@@ -158,7 +176,7 @@ static int hi6421_spmi_irq_map(struct irq_domain *d, unsigned int virq,
struct hi6421_spmi_pmic *ddata = d->host_data;
irq_set_chip_and_handler_name(virq, &hi6421_spmi_pmu_irqchip,
- handle_simple_irq, "hisi");
+ handle_simple_irq, "hi6421v600");
irq_set_chip_data(virq, ddata);
irq_set_irq_type(virq, IRQ_TYPE_NONE);
@@ -175,22 +193,24 @@ static void hi6421_spmi_pmic_irq_init(struct hi6421_spmi_pmic *ddata)
int i;
unsigned int pending;
- for (i = 0; i < HISI_IRQ_ARRAY; i++)
+ /* Mask all IRQs */
+ for (i = 0; i < HISI_IRQ_BANK_SIZE; i++)
regmap_write(ddata->regmap, SOC_PMIC_IRQ_MASK_0_ADDR + i,
- HISI_MASK);
+ HISI_8BITS_MASK);
- for (i = 0; i < HISI_IRQ_ARRAY; i++) {
+ /* Mark all IRQs as handled */
+ for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
regmap_read(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, &pending);
regmap_write(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i,
- HISI_MASK);
+ HISI_8BITS_MASK);
}
}
static const struct regmap_config regmap_config = {
- .reg_bits = 16,
- .val_bits = HISI_BITS,
- .max_register = 0xffff,
- .fast_io = true
+ .reg_bits = 16,
+ .val_bits = BITS_PER_BYTE,
+ .max_register = 0xffff,
+ .fast_io = true
};
static int hi6421_spmi_pmic_probe(struct spmi_device *pdev)
@@ -230,29 +250,31 @@ static int hi6421_spmi_pmic_probe(struct spmi_device *pdev)
hi6421_spmi_pmic_irq_init(ddata);
- ddata->irqs = devm_kzalloc(dev, HISI_IRQ_NUM * sizeof(int), GFP_KERNEL);
+ ddata->irqs = devm_kzalloc(dev, PMIC_IRQ_LIST_MAX * sizeof(int), GFP_KERNEL);
if (!ddata->irqs)
return -ENOMEM;
- ddata->domain = irq_domain_add_simple(np, HISI_IRQ_NUM, 0,
+ ddata->domain = irq_domain_add_simple(np, PMIC_IRQ_LIST_MAX, 0,
&hi6421_spmi_domain_ops, ddata);
if (!ddata->domain) {
dev_err(dev, "Failed to create IRQ domain\n");
return -ENODEV;
}
- for (i = 0; i < HISI_IRQ_NUM; i++) {
+ for (i = 0; i < PMIC_IRQ_LIST_MAX; i++) {
virq = irq_create_mapping(ddata->domain, i);
if (!virq) {
dev_err(dev, "Failed to map H/W IRQ\n");
- return -ENOSPC;
+ return -ENODEV;
}
ddata->irqs[i] = virq;
}
- ret = request_threaded_irq(ddata->irq, hi6421_spmi_irq_handler, NULL,
- IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
- "pmic", ddata);
+ ret = devm_request_threaded_irq(dev,
+ ddata->irq, hi6421_spmi_irq_handler,
+ NULL,
+ IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
+ "pmic", ddata);
if (ret < 0) {
dev_err(dev, "Failed to start IRQ handling thread: error %d\n",
ret);
@@ -270,13 +292,6 @@ static int hi6421_spmi_pmic_probe(struct spmi_device *pdev)
return ret;
}
-static void hi6421_spmi_pmic_remove(struct spmi_device *pdev)
-{
- struct hi6421_spmi_pmic *ddata = dev_get_drvdata(&pdev->dev);
-
- free_irq(ddata->irq, ddata);
-}
-
static const struct of_device_id pmic_spmi_id_table[] = {
{ .compatible = "hisilicon,hi6421-spmi" },
{ }
@@ -289,7 +304,6 @@ static struct spmi_driver hi6421_spmi_pmic_driver = {
.of_match_table = pmic_spmi_id_table,
},
.probe = hi6421_spmi_pmic_probe,
- .remove = hi6421_spmi_pmic_remove,
};
module_spmi_driver(hi6421_spmi_pmic_driver);
diff --git a/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml b/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
index 3b23ad56b31a..8e355cddd437 100644
--- a/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
+++ b/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
@@ -17,7 +17,7 @@ description: |
node.
The SPMI controller part is provided by
- drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml.
+ Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
properties:
$nodename:
@@ -32,12 +32,11 @@ properties:
'#interrupt-cells':
const: 2
- interrupt-controller:
- description:
- Identify that the PMIC is capable of behaving as an interrupt controller.
+ interrupt-controller: true
gpios:
maxItems: 1
+ description: GPIO used for IRQs
regulators:
type: object
diff --git a/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml b/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml
deleted file mode 100644
index 6b755039a74c..000000000000
--- a/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml
+++ /dev/null
@@ -1,71 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/spmi/hisilicon,hisi-spmi-controller.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: HiSilicon SPMI controller
-
-maintainers:
- - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
-
-description: |
- The HiSilicon SPMI BUS controller is found on some Kirin-based designs.
- It is a MIPI System Power Management (SPMI) controller.
-
- The PMIC part is provided by
- drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
-
-allOf:
- - $ref: spmi.yaml#
-
-properties:
-
- $nodename:
- pattern: "spmi@[0-9a-f]"
-
- compatible:
- const: hisilicon,kirin970-spmi-controller
-
- reg:
- maxItems: 1
-
- spmi-channel:
- $ref: /schemas/types.yaml#/definitions/uint32
- description: |
- number of the Kirin 970 SPMI channel where the SPMI devices are connected.
-
-required:
- - compatible
- - reg
- - spmi-channel
-
-patternProperties:
- "@[0-9a-f]$":
- description: |
- PMIC properties, which are specific to the used SPMI PMIC device(s).
- When used in combination with HiSilicon 6421v600, the properties
- are documented at
- drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
-
-unevaluatedProperties: false
-
-examples:
- - |
- bus {
- #address-cells = <2>;
- #size-cells = <2>;
-
- spmi: spmi@fff24000 {
- compatible = "hisilicon,kirin970-spmi-controller";
- #address-cells = <2>;
- #size-cells = <0>;
- reg = <0x0 0xfff24000 0x0 0x1000>;
- spmi-channel = <2>;
-
- pmic@0 {
- reg = <0 0>;
- /* pmic properties */
- };
- };
- };
diff --git a/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml b/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml
deleted file mode 100644
index ebd78acfe2de..000000000000
--- a/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml
+++ /dev/null
@@ -1,73 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/phy/hisilicon,hi3670-usb3.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Hisilicon Kirin970 USB PHY
-
-maintainers:
- - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
-
-description: |+
- Bindings for USB3 PHY on HiSilicon Kirin 970.
-
-properties:
- compatible:
- const: hisilicon,hi3670-usb-phy
-
- "#phy-cells":
- const: 0
-
- hisilicon,pericrg-syscon:
- $ref: '/schemas/types.yaml#/definitions/phandle'
- description: phandle of syscon used to control iso refclk.
-
- hisilicon,pctrl-syscon:
- $ref: '/schemas/types.yaml#/definitions/phandle'
- description: phandle of syscon used to control usb tcxo.
-
- hisilicon,sctrl-syscon:
- $ref: '/schemas/types.yaml#/definitions/phandle'
- description: phandle of syscon used to control phy deep sleep.
-
- hisilicon,eye-diagram-param:
- $ref: /schemas/types.yaml#/definitions/uint32
- description: Eye diagram for phy.
-
- hisilicon,tx-vboost-lvl:
- $ref: /schemas/types.yaml#/definitions/uint32
- description: TX level vboost for phy.
-
-required:
- - compatible
- - hisilicon,pericrg-syscon
- - hisilicon,pctrl-syscon
- - hisilicon,sctrl-syscon
- - hisilicon,eye-diagram-param
- - hisilicon,tx-vboost-lvl
- - "#phy-cells"
-
-additionalProperties: false
-
-examples:
- - |
- bus {
- #address-cells = <2>;
- #size-cells = <2>;
-
- usb3_otg_bc: usb3_otg_bc@ff200000 {
- compatible = "syscon", "simple-mfd";
- reg = <0x0 0xff200000 0x0 0x1000>;
-
- usb_phy {
- compatible = "hisilicon,hi3670-usb-phy";
- #phy-cells = <0>;
- hisilicon,pericrg-syscon = <&crg_ctrl>;
- hisilicon,pctrl-syscon = <&pctrl>;
- hisilicon,sctrl-syscon = <&sctrl>;
- hisilicon,eye-diagram-param = <0xfdfee4>;
- hisilicon,tx-vboost-lvl = <0x5>;
- };
- };
- };
diff --git a/drivers/staging/iio/accel/adis16203.c b/drivers/staging/iio/accel/adis16203.c
index b68304da288b..1d3026dae827 100644
--- a/drivers/staging/iio/accel/adis16203.c
+++ b/drivers/staging/iio/accel/adis16203.c
@@ -5,20 +5,14 @@
* Copyright 2010 Analog Devices Inc.
*/
-#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/imu/adis.h>
-#include <linux/iio/sysfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include <linux/sysfs.h>
#define ADIS16203_STARTUP_DELAY 220 /* ms */
diff --git a/drivers/staging/iio/accel/adis16240.c b/drivers/staging/iio/accel/adis16240.c
index 8d3afc6dc755..2a8aa83b8d9e 100644
--- a/drivers/staging/iio/accel/adis16240.c
+++ b/drivers/staging/iio/accel/adis16240.c
@@ -5,20 +5,14 @@
* Copyright 2010 Analog Devices Inc.
*/
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
-#include <linux/slab.h>
#include <linux/sysfs.h>
-#include <linux/list.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#define ADIS16240_STARTUP_DELAY 220 /* ms */
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index ccbafcaaf27e..79467f056a05 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -1348,9 +1348,9 @@ static ssize_t adt7316_show_in_analog_temp_offset(struct device *dev,
}
static ssize_t adt7316_store_in_analog_temp_offset(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
{
struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1375,9 +1375,9 @@ static ssize_t adt7316_show_ex_analog_temp_offset(struct device *dev,
}
static ssize_t adt7316_store_ex_analog_temp_offset(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
{
struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c
index eab534dc4bcc..78ac720266e6 100644
--- a/drivers/staging/iio/cdc/ad7746.c
+++ b/drivers/staging/iio/cdc/ad7746.c
@@ -18,8 +18,6 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include "ad7746.h"
-
/*
* AD7746 Register Definition
*/
@@ -84,10 +82,6 @@
#define AD7746_CAPDAC_DACEN BIT(7)
#define AD7746_CAPDAC_DACP(x) ((x) & 0x7F)
-/*
- * struct ad7746_chip_info - chip specific information
- */
-
struct ad7746_chip_info {
struct i2c_client *client;
struct mutex lock; /* protect sensor state */
@@ -215,6 +209,19 @@ static const unsigned char ad7746_cap_filter_rate_table[][2] = {
{16, 62 + 1}, {13, 77 + 1}, {11, 92 + 1}, {9, 110 + 1},
};
+static int ad7746_set_capdac(struct ad7746_chip_info *chip, int channel)
+{
+ int ret = i2c_smbus_write_byte_data(chip->client,
+ AD7746_REG_CAPDACA,
+ chip->capdac[channel][0]);
+ if (ret < 0)
+ return ret;
+
+ return i2c_smbus_write_byte_data(chip->client,
+ AD7746_REG_CAPDACB,
+ chip->capdac[channel][1]);
+}
+
static int ad7746_select_channel(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan)
{
@@ -230,17 +237,11 @@ static int ad7746_select_channel(struct iio_dev *indio_dev,
AD7746_CONF_CAPFS_SHIFT;
delay = ad7746_cap_filter_rate_table[idx][1];
+ ret = ad7746_set_capdac(chip, chan->channel);
+ if (ret < 0)
+ return ret;
+
if (chip->capdac_set != chan->channel) {
- ret = i2c_smbus_write_byte_data(chip->client,
- AD7746_REG_CAPDACA,
- chip->capdac[chan->channel][0]);
- if (ret < 0)
- return ret;
- ret = i2c_smbus_write_byte_data(chip->client,
- AD7746_REG_CAPDACB,
- chip->capdac[chan->channel][1]);
- if (ret < 0)
- return ret;
chip->capdac_set = chan->channel;
}
@@ -484,14 +485,7 @@ static int ad7746_write_raw(struct iio_dev *indio_dev,
chip->capdac[chan->channel][chan->differential] = val > 0 ?
AD7746_CAPDAC_DACP(val) | AD7746_CAPDAC_DACEN : 0;
- ret = i2c_smbus_write_byte_data(chip->client,
- AD7746_REG_CAPDACA,
- chip->capdac[chan->channel][0]);
- if (ret < 0)
- goto out;
- ret = i2c_smbus_write_byte_data(chip->client,
- AD7746_REG_CAPDACB,
- chip->capdac[chan->channel][1]);
+ ret = ad7746_set_capdac(chip, chan->channel);
if (ret < 0)
goto out;
@@ -564,10 +558,10 @@ static int ad7746_read_raw(struct iio_dev *indio_dev,
switch (chan->type) {
case IIO_TEMP:
- /*
- * temperature in milli degrees Celsius
- * T = ((*val / 2048) - 4096) * 1000
- */
+ /*
+ * temperature in milli degrees Celsius
+ * T = ((*val / 2048) - 4096) * 1000
+ */
*val = (*val * 125) / 256;
break;
case IIO_VOLTAGE:
@@ -669,18 +663,15 @@ static const struct iio_info ad7746_info = {
.write_raw = ad7746_write_raw,
};
-/*
- * device probe and remove
- */
-
static int ad7746_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct ad7746_platform_data *pdata = client->dev.platform_data;
+ struct device *dev = &client->dev;
struct ad7746_chip_info *chip;
struct iio_dev *indio_dev;
unsigned char regval = 0;
- int ret = 0;
+ unsigned int vdd_permille;
+ int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
if (!indio_dev)
@@ -702,26 +693,39 @@ static int ad7746_probe(struct i2c_client *client,
indio_dev->num_channels = ARRAY_SIZE(ad7746_channels) - 2;
indio_dev->modes = INDIO_DIRECT_MODE;
- if (pdata) {
- if (pdata->exca_en) {
- if (pdata->exca_inv_en)
- regval |= AD7746_EXCSETUP_NEXCA;
- else
- regval |= AD7746_EXCSETUP_EXCA;
- }
+ if (device_property_read_bool(dev, "adi,exca-output-en")) {
+ if (device_property_read_bool(dev, "adi,exca-output-invert"))
+ regval |= AD7746_EXCSETUP_NEXCA;
+ else
+ regval |= AD7746_EXCSETUP_EXCA;
+ }
- if (pdata->excb_en) {
- if (pdata->excb_inv_en)
- regval |= AD7746_EXCSETUP_NEXCB;
- else
- regval |= AD7746_EXCSETUP_EXCB;
- }
+ if (device_property_read_bool(dev, "adi,excb-output-en")) {
+ if (device_property_read_bool(dev, "adi,excb-output-invert"))
+ regval |= AD7746_EXCSETUP_NEXCB;
+ else
+ regval |= AD7746_EXCSETUP_EXCB;
+ }
- regval |= AD7746_EXCSETUP_EXCLVL(pdata->exclvl);
- } else {
- dev_warn(&client->dev, "No platform data? using default\n");
- regval = AD7746_EXCSETUP_EXCA | AD7746_EXCSETUP_EXCB |
- AD7746_EXCSETUP_EXCLVL(3);
+ ret = device_property_read_u32(dev, "adi,excitation-vdd-permille",
+ &vdd_permille);
+ if (!ret) {
+ switch (vdd_permille) {
+ case 125:
+ regval |= AD7746_EXCSETUP_EXCLVL(0);
+ break;
+ case 250:
+ regval |= AD7746_EXCSETUP_EXCLVL(1);
+ break;
+ case 375:
+ regval |= AD7746_EXCSETUP_EXCLVL(2);
+ break;
+ case 500:
+ regval |= AD7746_EXCSETUP_EXCLVL(3);
+ break;
+ default:
+ break;
+ }
}
ret = i2c_smbus_write_byte_data(chip->client,
@@ -729,11 +733,7 @@ static int ad7746_probe(struct i2c_client *client,
if (ret < 0)
return ret;
- ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev);
- if (ret)
- return ret;
-
- return 0;
+ return devm_iio_device_register(indio_dev->dev.parent, indio_dev);
}
static const struct i2c_device_id ad7746_id[] = {
diff --git a/drivers/staging/iio/cdc/ad7746.h b/drivers/staging/iio/cdc/ad7746.h
deleted file mode 100644
index 8bdbd732dbbd..000000000000
--- a/drivers/staging/iio/cdc/ad7746.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * AD7746 capacitive sensor driver supporting AD7745, AD7746 and AD7747
- *
- * Copyright 2011 Analog Devices Inc.
- */
-
-#ifndef IIO_CDC_AD7746_H_
-#define IIO_CDC_AD7746_H_
-
-/*
- * TODO: struct ad7746_platform_data needs to go into include/linux/iio
- */
-
-#define AD7466_EXCLVL_0 0 /* +-VDD/8 */
-#define AD7466_EXCLVL_1 1 /* +-VDD/4 */
-#define AD7466_EXCLVL_2 2 /* +-VDD * 3/8 */
-#define AD7466_EXCLVL_3 3 /* +-VDD/2 */
-
-struct ad7746_platform_data {
- unsigned char exclvl; /*Excitation Voltage Level */
- bool exca_en; /* enables EXCA pin as the excitation output */
- bool exca_inv_en; /* enables /EXCA pin as the excitation output */
- bool excb_en; /* enables EXCB pin as the excitation output */
- bool excb_inv_en; /* enables /EXCB pin as the excitation output */
-};
-
-#endif /* IIO_CDC_AD7746_H_ */
diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c
index 60a3ae5587b9..94b131ef8a22 100644
--- a/drivers/staging/iio/frequency/ad9834.c
+++ b/drivers/staging/iio/frequency/ad9834.c
@@ -58,6 +58,7 @@
* @spi: spi_device
* @mclk: external master clock
* @control: cached control word
+ * @devid: device id
* @xfer: default spi transfer
* @msg: default spi message
* @freq_xfer: tuning word spi transfer
@@ -86,7 +87,7 @@ struct ad9834_state {
__be16 freq_data[2];
};
-/**
+/*
* ad9834_supported_device_ids:
*/
@@ -316,7 +317,7 @@ ssize_t ad9834_show_out1_wavetype_available(struct device *dev,
static IIO_DEVICE_ATTR(out_altvoltage0_out1_wavetype_available, 0444,
ad9834_show_out1_wavetype_available, NULL, 0);
-/**
+/*
* see dds.h for further information
*/
diff --git a/drivers/staging/kpc2000/Kconfig b/drivers/staging/kpc2000/Kconfig
deleted file mode 100644
index 897965359fcb..000000000000
--- a/drivers/staging/kpc2000/Kconfig
+++ /dev/null
@@ -1,59 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-config KPC2000
- bool "Daktronics KPC Device support"
- select MFD_CORE
- depends on PCI
- depends on UIO
- help
- Select this if you wish to use the Daktronics KPC PCI devices
-
- If unsure, say N.
-
-config KPC2000_CORE
- tristate "Daktronics KPC PCI UIO device"
- depends on KPC2000
- help
- Say Y here if you wish to support the Daktronics KPC PCI
- device in UIO mode.
-
- To compile this driver as a module, choose M here: the module
- will be called kpc2000
-
- If unsure, say N.
-
-config KPC2000_SPI
- tristate "Daktronics KPC SPI device"
- depends on KPC2000 && SPI
- help
- Say Y here if you wish to support the Daktronics KPC PCI
- device in SPI mode.
-
- To compile this driver as a module, choose M here: the module
- will be called kpc2000_spi
-
- If unsure, say N.
-
-config KPC2000_I2C
- tristate "Daktronics KPC I2C device"
- depends on KPC2000 && I2C
- help
- Say Y here if you wish to support the Daktronics KPC PCI
- device in I2C mode.
-
- To compile this driver as a module, choose M here: the module
- will be called kpc2000_i2c
-
- If unsure, say N.
-
-config KPC2000_DMA
- tristate "Daktronics KPC DMA controller"
- depends on KPC2000
- help
- Say Y here if you wish to support the Daktronics DMA controller.
-
- To compile this driver as a module, choose M here: the module
- will be called kpc2000_dma
-
- If unsure, say N.
-
diff --git a/drivers/staging/kpc2000/Makefile b/drivers/staging/kpc2000/Makefile
deleted file mode 100644
index d15ed49807d5..000000000000
--- a/drivers/staging/kpc2000/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-$(CONFIG_KPC2000) += kpc2000/
-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
deleted file mode 100644
index 9b5ab37fb3a0..000000000000
--- a/drivers/staging/kpc2000/TODO
+++ /dev/null
@@ -1,2 +0,0 @@
-- 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.
diff --git a/drivers/staging/kpc2000/kpc.h b/drivers/staging/kpc2000/kpc.h
deleted file mode 100644
index a3fc9c9221aa..000000000000
--- a/drivers/staging/kpc2000/kpc.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-#ifndef KPC_H_
-#define KPC_H_
-
-/* ***** Driver Names ***** */
-#define KP_DRIVER_NAME_KP2000 "kp2000"
-#define KP_DRIVER_NAME_INVALID "kpc_invalid"
-#define KP_DRIVER_NAME_DMA_CONTROLLER "kpc_nwl_dma"
-#define KP_DRIVER_NAME_UIO "uio_pdrv_genirq"
-#define KP_DRIVER_NAME_I2C "kpc_i2c"
-#define KP_DRIVER_NAME_SPI "kpc_spi"
-
-struct kpc_core_device_platdata {
- u32 card_id;
- u32 build_version;
- u32 hardware_revision;
- u64 ssid;
- u64 ddna;
-};
-
-#define PCI_DEVICE_ID_DAKTRONICS_KADOKA_P2KR0 0x4b03
-
-#endif /* KPC_H_ */
diff --git a/drivers/staging/kpc2000/kpc2000/Makefile b/drivers/staging/kpc2000/kpc2000/Makefile
deleted file mode 100644
index c274ad083db6..000000000000
--- a/drivers/staging/kpc2000/kpc2000/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-m := kpc2000.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
deleted file mode 100644
index e7e963d62699..000000000000
--- a/drivers/staging/kpc2000/kpc2000/cell_probe.c
+++ /dev/null
@@ -1,548 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/types.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/io-64-nonatomic-lo-hi.h>
-#include <linux/mfd/core.h>
-#include <linux/platform_device.h>
-#include <linux/ioport.h>
-#include <linux/uio_driver.h>
-#include "pcie.h"
-
-/* Core (Resource) Table Layout:
- * one Resource per record (8 bytes)
- * 6 5 4 3 2 1 0
- * 3210987654321098765432109876543210987654321098765432109876543210
- * IIIIIIIIIIII Core Type [up to 4095 types]
- * D S2C DMA Present
- * DDD S2C DMA Channel Number [up to 8 channels]
- * LLLLLLLLLLLLLLLL Register Count (64-bit registers) [up to 65535 registers]
- * OOOOOOOOOOOOOOOO Core Offset (in 4kB blocks) [up to 65535 cores]
- * D C2S DMA Present
- * DDD C2S DMA Channel Number [up to 8 channels]
- * II IRQ Count [0 to 3 IRQs per core]
- * 1111111000
- * IIIIIII IRQ Base Number [up to 128 IRQs per card]
- * ___ Spare
- *
- */
-
-#define KPC_OLD_DMA_CH_NUM(present, channel) \
- ((present) ? (0x8 | ((channel) & 0x7)) : 0)
-#define KPC_OLD_S2C_DMA_CH_NUM(cte) \
- KPC_OLD_DMA_CH_NUM(cte.s2c_dma_present, cte.s2c_dma_channel_num)
-#define KPC_OLD_C2S_DMA_CH_NUM(cte) \
- KPC_OLD_DMA_CH_NUM(cte.c2s_dma_present, cte.c2s_dma_channel_num)
-
-#define KP_CORE_ID_INVALID 0
-#define KP_CORE_ID_I2C 3
-#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;
-};
-
-static
-void parse_core_table_entry_v0(struct core_table_entry *cte, const u64 read_val)
-{
- cte->type = ((read_val & 0xFFF0000000000000UL) >> 52);
- cte->offset = ((read_val & 0x00000000FFFF0000UL) >> 16) * 4096;
- cte->length = ((read_val & 0x0000FFFF00000000UL) >> 32) * 8;
- cte->s2c_dma_present = ((read_val & 0x0008000000000000UL) >> 51);
- cte->s2c_dma_channel_num = ((read_val & 0x0007000000000000UL) >> 48);
- cte->c2s_dma_present = ((read_val & 0x0000000000008000UL) >> 15);
- cte->c2s_dma_channel_num = ((read_val & 0x0000000000007000UL) >> 12);
- cte->irq_count = ((read_val & 0x0000000000000C00UL) >> 10);
- cte->irq_base_num = ((read_val & 0x00000000000003F8UL) >> 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
- );
-}
-
-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;
- }
-}
-
-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 = { .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;
-};
-
-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);
-
- 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);
-
-struct attribute *kpc_uio_class_attrs[] = {
- &dev_attr_offset.attr,
- &dev_attr_size.attr,
- &dev_attr_type.attr,
- &dev_attr_s2c_dma.attr,
- &dev_attr_c2s_dma.attr,
- &dev_attr_irq_count.attr,
- &dev_attr_irq_base_num.attr,
- &dev_attr_core_num.attr,
- 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 = 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)) {
- /* 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;
-
- 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;
-}
-
-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(*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;
-
- // Round up to nearest PAGE_SIZE boundary
- kudev->uioinfo.mem[0].size = (cte.length + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
- 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 = { .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;
-
-err_out:
- 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;
-
- 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);
- }
-}
-
diff --git a/drivers/staging/kpc2000/kpc2000/core.c b/drivers/staging/kpc2000/kpc2000/core.c
deleted file mode 100644
index 6462a3059fb0..000000000000
--- a/drivers/staging/kpc2000/kpc2000/core.c
+++ /dev/null
@@ -1,565 +0,0 @@
-// 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 <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>
-#include <linux/ioport.h>
-#include <linux/io-64-nonatomic-lo-hi.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/device.h>
-#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 ssid_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct kp2000_device *pcard = dev_get_drvdata(dev);
-
- return sprintf(buf, "%016llx\n", pcard->ssid);
-}
-static DEVICE_ATTR_RO(ssid);
-
-static ssize_t ddna_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct kp2000_device *pcard = dev_get_drvdata(dev);
-
- return sprintf(buf, "%016llx\n", pcard->ddna);
-}
-static DEVICE_ATTR_RO(ddna);
-
-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 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);
- unsigned long wr_val;
- int rv;
-
- rv = kstrtoul(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 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 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;
-
- 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
- ******************************************************/
-
-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 & 0x8000000000000000UL) {
- pcard->ssid = read_val;
- return;
- }
-
- timeout = jiffies + (HZ * 2);
- do {
- read_val = readq(pcard->sysinfo_regs_base + REG_FPGA_SSID);
- if (read_val & 0x8000000000000000UL) {
- 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%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 & 0xFFFFFFFF00000000UL) >> 32;
- pcard->build_version = (read_val & 0x00000000FFFFFFFFUL) >> 0;
-
- read_val = readq(pcard->sysinfo_regs_base + REG_DATE_AND_TIME_STAMPS);
- pcard->build_datestamp = (read_val & 0xFFFFFFFF00000000UL) >> 32;
- pcard->build_timestamp = (read_val & 0x00000000FFFFFFFFUL) >> 0;
-
- read_val = readq(pcard->sysinfo_regs_base + REG_CORE_TABLE_OFFSET);
- pcard->core_table_length = (read_val & 0xFFFFFFFF00000000UL) >> 32;
- pcard->core_table_offset = (read_val & 0x00000000FFFFFFFFUL) >> 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;
-}
-
-static irqreturn_t kp2000_irq_handler(int irq, void *dev_id)
-{
- 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;
-}
-
-static int kp2000_pcie_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- int err = 0;
- struct kp2000_device *pcard;
- 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(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(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(0xFFFFFFFFFFFFFFFFUL,
- 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;
-
- err = request_irq(pcard->pdev->irq, kp2000_irq_handler, IRQF_SHARED,
- pcard->name, pcard);
- if (err) {
- dev_err(&pcard->pdev->dev,
- "%s: failed to request_irq: %d\n", __func__, err);
- 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,
-};
-
-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);
- 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
deleted file mode 100644
index 613c4898f65e..000000000000
--- a/drivers/staging/kpc2000/kpc2000/dma_common_defs.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-#ifndef KPC_DMA_COMMON_DEFS_H_
-#define KPC_DMA_COMMON_DEFS_H_
-
-#define KPC_DMA_COMMON_OFFSET 0x4000
-#define KPC_DMA_S2C_BASE_OFFSET 0x0000
-#define KPC_DMA_C2S_BASE_OFFSET 0x2000
-#define KPC_DMA_ENGINE_SIZE 0x0100
-#define ENGINE_CAP_PRESENT_MASK 0x1
-
-#define KPC_DMA_CARD_IRQ_ENABLE BIT(0)
-#define KPC_DMA_CARD_IRQ_ACTIVE BIT(1)
-#define KPC_DMA_CARD_IRQ_PENDING BIT(2)
-#define KPC_DMA_CARD_IRQ_MSI BIT(3)
-#define KPC_DMA_CARD_USER_INTERRUPT_MODE BIT(4)
-#define KPC_DMA_CARD_USER_INTERRUPT_ACTIVE BIT(5)
-#define KPC_DMA_CARD_IRQ_MSIX_MODE BIT(6)
-#define KPC_DMA_CARD_MAX_PAYLOAD_SIZE_MASK 0x0700
-#define KPC_DMA_CARD_MAX_READ_REQUEST_SIZE_MASK 0x7000
-#define KPC_DMA_CARD_S2C_INTERRUPT_STATUS_MASK 0x00FF0000
-#define KPC_DMA_CARD_C2S_INTERRUPT_STATUS_MASK 0xFF000000
-
-#endif /* KPC_DMA_COMMON_DEFS_H_ */
diff --git a/drivers/staging/kpc2000/kpc2000/pcie.h b/drivers/staging/kpc2000/kpc2000/pcie.h
deleted file mode 100644
index f1fc91b4c704..000000000000
--- a/drivers/staging/kpc2000/kpc2000/pcie.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-#ifndef KP2000_PCIE_H
-#define KP2000_PCIE_H
-#include <linux/types.h>
-#include <linux/pci.h>
-#include "../kpc.h"
-#include "dma_common_defs.h"
-
-/* System Register Map (BAR 1, Start Addr 0)
- *
- * BAR Size:
- * 1048576 (0x100000) bytes = 131072 (0x20000) registers = 256 pages (4K)
- *
- * 6 5 4 3 2 1 0
- * 3210987654321098765432109876543210987654321098765432109876543210
- * 0 <--------------------------- MAGIC ---------------------------->
- * 1 <----------- Card ID ---------><----------- Revision ---------->
- * 2 <--------- Date Stamp --------><--------- Time Stamp ---------->
- * 3 <-------- Core Tbl Len -------><-------- Core Tbl Offset ------>
- * 4 <---------------------------- SSID ---------------------------->
- * 5 < HWID >
- * 6 <------------------------- FPGA DDNA -------------------------->
- * 7 <------------------------ CPLD Config ------------------------->
- * 8 <----------------------- IRQ Mask Flags ----------------------->
- * 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 KP2000_MAGIC_VALUE 0x196C61482231894DULL
-
-#define PCI_VENDOR_ID_DAKTRONICS 0x1c33
-#define PCI_DEVICE_ID_DAKTRONICS 0x6021
-
-#define DMA_BAR 0
-#define REG_BAR 1
-
-struct kp2000_device {
- 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_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))
-
-#endif /* KP2000_PCIE_H */
diff --git a/drivers/staging/kpc2000/kpc2000/uapi.h b/drivers/staging/kpc2000/kpc2000/uapi.h
deleted file mode 100644
index 16f37f002dc6..000000000000
--- a/drivers/staging/kpc2000/kpc2000/uapi.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-#ifndef KP2000_CDEV_UAPI_H_
-#define KP2000_CDEV_UAPI_H_
-#include <linux/types.h>
-#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;
-};
-
-#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
deleted file mode 100644
index 14f7940fa4fb..000000000000
--- a/drivers/staging/kpc2000/kpc2000_i2c.c
+++ /dev/null
@@ -1,731 +0,0 @@
-// 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 kpc_i2c {
- 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 __iomem *)a)
-#undef outb_p
-#define outb_p(d, a) writeq(d, (void __iomem *)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 kpc_i2c *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) {
- 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 kpc_i2c *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 kpc_i2c *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 kpc_i2c *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 kpc_i2c *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 kpc_i2c *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 kpc_i2c *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 kpc_i2c *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 kpc_i2c *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) {
- 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;
-}
-
-#define enable_flag(x) (x)
-#define disable_flag(x) 0
-#define enable_flag_if(x, cond) ((cond) ? (x) : 0)
-
-static u32 i801_func(struct i2c_adapter *adapter)
-{
- struct kpc_i2c *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 =
- enable_flag(I2C_FUNC_I2C) | /* 0x00000001(I enabled this one) */
- disable_flag(I2C_FUNC_10BIT_ADDR) | /* 0x00000002 */
- disable_flag(I2C_FUNC_PROTOCOL_MANGLING) | /* 0x00000004 */
- enable_flag_if(I2C_FUNC_SMBUS_PEC,
- priv->features & FEATURE_SMBUS_PEC) |
- /* 0x00000008 */
- disable_flag(I2C_FUNC_SMBUS_BLOCK_PROC_CALL) | /* 0x00008000 */
- enable_flag(I2C_FUNC_SMBUS_QUICK) | /* 0x00010000 */
- disable_flag(I2C_FUNC_SMBUS_READ_BYTE) | /* 0x00020000 */
- disable_flag(I2C_FUNC_SMBUS_WRITE_BYTE) | /* 0x00040000 */
- disable_flag(I2C_FUNC_SMBUS_READ_BYTE_DATA) | /* 0x00080000 */
- disable_flag(I2C_FUNC_SMBUS_WRITE_BYTE_DATA) | /* 0x00100000 */
- disable_flag(I2C_FUNC_SMBUS_READ_WORD_DATA) | /* 0x00200000 */
- disable_flag(I2C_FUNC_SMBUS_WRITE_WORD_DATA) | /* 0x00400000 */
- disable_flag(I2C_FUNC_SMBUS_PROC_CALL) | /* 0x00800000 */
- disable_flag(I2C_FUNC_SMBUS_READ_BLOCK_DATA) | /* 0x01000000 */
- disable_flag(I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) | /* 0x02000000 */
- enable_flag_if(I2C_FUNC_SMBUS_READ_I2C_BLOCK,
- priv->features & FEATURE_I2C_BLOCK_READ) |
- /* 0x04000000 */
- enable_flag(I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) | /* 0x08000000 */
-
- enable_flag(I2C_FUNC_SMBUS_BYTE) | /* _READ_BYTE _WRITE_BYTE */
- enable_flag(I2C_FUNC_SMBUS_BYTE_DATA) | /* _READ_BYTE_DATA
- * _WRITE_BYTE_DATA
- */
- enable_flag(I2C_FUNC_SMBUS_WORD_DATA) | /* _READ_WORD_DATA
- * _WRITE_WORD_DATA
- */
- enable_flag(I2C_FUNC_SMBUS_BLOCK_DATA) | /* _READ_BLOCK_DATA
- * _WRITE_BLOCK_DATA
- */
- disable_flag(I2C_FUNC_SMBUS_I2C_BLOCK) | /* _READ_I2C_BLOCK
- * _WRITE_I2C_BLOCK
- */
- disable_flag(I2C_FUNC_SMBUS_EMUL); /* _QUICK _BYTE
- * _BYTE_DATA _WORD_DATA
- * _PROC_CALL
- * _WRITE_BLOCK_DATA
- * _I2C_BLOCK _PEC
- */
- return f;
-}
-
-#undef enable_flag
-#undef disable_flag
-#undef enable_flag_if
-
-static const struct i2c_algorithm smbus_algorithm = {
- .smbus_xfer = i801_access,
- .functionality = i801_func,
-};
-
-/********************************
- *** Part 2 - Driver Handlers ***
- ********************************/
-static int kpc_i2c_probe(struct platform_device *pldev)
-{
- int err;
- struct kpc_i2c *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(&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");
-
- 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 kpc_i2c_remove(struct platform_device *pldev)
-{
- struct kpc_i2c *lddev;
-
- lddev = (struct kpc_i2c *)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 kpc_i2c_driver = {
- .probe = kpc_i2c_probe,
- .remove = kpc_i2c_remove,
- .driver = {
- .name = KP_DRIVER_NAME_I2C,
- },
-};
-
-module_platform_driver(kpc_i2c_driver);
diff --git a/drivers/staging/kpc2000/kpc2000_spi.c b/drivers/staging/kpc2000/kpc2000_spi.c
deleted file mode 100644
index 16ca18b8aa15..000000000000
--- a/drivers/staging/kpc2000/kpc2000_spi.c
+++ /dev/null
@@ -1,517 +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"
-
-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;
-
- addr += idx;
- if ((idx == KP_SPI_REG_CONFIG) && (cs->conf_cache >= 0))
- return cs->conf_cache;
-
- return readq(addr);
-}
-
- 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.value)
- ndelay(spi_delay_to_ns(&transfer->delay, transfer));
- }
-
- /* 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;
-
- 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(&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/Makefile b/drivers/staging/kpc2000/kpc_dma/Makefile
deleted file mode 100644
index fe5db532c8c8..000000000000
--- a/drivers/staging/kpc2000/kpc_dma/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-m := kpc_dma.o
-kpc_dma-objs += dma.o
-kpc_dma-objs += fileops.o
-kpc_dma-objs += kpc_dma_driver.o
diff --git a/drivers/staging/kpc2000/kpc_dma/dma.c b/drivers/staging/kpc2000/kpc_dma/dma.c
deleted file mode 100644
index e169ac609ba4..000000000000
--- a/drivers/staging/kpc2000/kpc_dma/dma.c
+++ /dev/null
@@ -1,270 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/io.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/fs.h>
-#include <linux/rwsem.h>
-#include "kpc_dma_driver.h"
-
-/********** IRQ Handlers **********/
-static
-irqreturn_t ndd_irq_handler(int irq, void *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;
-}
-
-static
-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) {
- 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->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;
- dma_addr_t next_handle;
- dma_addr_t head_handle;
- unsigned int i;
- int rv;
-
- caps = GetEngineCapabilities(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)
- 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, "%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++) {
- next = dma_pool_alloc(eng->desc_pool, GFP_KERNEL | GFP_DMA, &next_handle);
- 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, "%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;
-
- // 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)) {
- 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)) {
- 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)) {
- 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;
- 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++) {
- 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) {
- BUG_ON(!cur);
- count++;
- cur = cur->Next;
- }
- return count;
-}
-
-void clear_desc(struct kpc_dma_descriptor *desc)
-{
- if (!desc)
- return;
- desc->DescByteCount = 0;
- desc->DescStatusErrorFlags = 0;
- desc->DescStatusFlags = 0;
- desc->DescUserControlLS = 0;
- desc->DescUserControlMS = 0;
- desc->DescCardAddrLS = 0;
- desc->DescBufferByteCount = 0;
- desc->DescCardAddrMS = 0;
- desc->DescControlFlags = 0;
- desc->DescSystemAddrLS = 0;
- desc->DescSystemAddrMS = 0;
- desc->acd = NULL;
-}
diff --git a/drivers/staging/kpc2000/kpc_dma/fileops.c b/drivers/staging/kpc2000/kpc_dma/fileops.c
deleted file mode 100644
index 10dcd6646b01..000000000000
--- a/drivers/staging/kpc2000/kpc_dma/fileops.c
+++ /dev/null
@@ -1,363 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/mm.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/highmem.h>
-#include <linux/pagemap.h>
-#include "kpc_dma_driver.h"
-#include "uapi.h"
-
-/********** Helper Functions **********/
-static inline
-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)
-{
- return DIV_ROUND_UP(sg_dma_len(sg), 0x80000);
-}
-
-/********** Transfer Helpers **********/
-static int kpc_dma_transfer(struct dev_private_data *priv,
- unsigned long iov_base, size_t iov_len)
-{
- unsigned int i = 0;
- int rv = 0, nr_pages = 0;
- struct kpc_dma_device *ldev;
- struct aio_cb_data *acd;
- DECLARE_COMPLETION_ONSTACK(done);
- u32 desc_needed = 0;
- struct scatterlist *sg;
- u32 num_descrs_avail;
- struct kpc_dma_descriptor *desc;
- unsigned int pcnt;
- unsigned int p;
- u64 card_addr;
- u64 dma_addr;
- u64 user_ctl;
-
- ldev = priv->ldev;
-
- acd = kzalloc(sizeof(*acd), GFP_KERNEL);
- if (!acd) {
- dev_err(&priv->ldev->pldev->dev, "Couldn't kmalloc space 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->len = iov_len;
- acd->page_count = count_pages(iov_base, iov_len);
-
- // Allocate an array of page pointers
- acd->user_pages = kcalloc(acd->page_count, sizeof(struct page *),
- GFP_KERNEL);
- if (!acd->user_pages) {
- dev_err(&priv->ldev->pldev->dev, "Couldn't kmalloc space 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)
- mmap_read_lock(current->mm); /* get memory map semaphore */
- rv = pin_user_pages(iov_base, acd->page_count, FOLL_TOUCH | FOLL_WRITE,
- acd->user_pages, NULL);
- mmap_read_unlock(current->mm); /* release the semaphore */
- if (rv != acd->page_count) {
- nr_pages = rv;
- if (rv > 0)
- rv = -EFAULT;
-
- dev_err(&priv->ldev->pldev->dev, "Couldn't pin_user_pages (%d)\n", rv);
- goto unpin_pages;
- }
- nr_pages = acd->page_count;
-
- // 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) {
- dev_err(&priv->ldev->pldev->dev, "Couldn't alloc sg_table (%d)\n", rv);
- goto unpin_pages;
- }
-
- // 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) {
- dev_err(&priv->ldev->pldev->dev, "Couldn't dma_map_sg (%d)\n",
- acd->mapped_entry_count);
- goto free_table;
- }
-
- // Calculate how many descriptors are actually needed for this transfer.
- 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) {
- 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) {
- 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;
- }
-
- // 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) {
- pcnt = count_parts_for_sge(sg);
- for (p = 0 ; p < pcnt ; p++) {
- // Fill out the descriptor
- BUG_ON(!desc);
- clear_desc(desc);
- 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 & 0x00000000FFFFFFFFUL) >> 0;
- desc->DescSystemAddrMS = (dma_addr & 0xFFFFFFFF00000000UL) >> 32;
-
- user_ctl = acd->priv->user_ctl;
- if (i == acd->mapped_entry_count - 1 && p == pcnt - 1)
- user_ctl = acd->priv->user_ctl_last;
-
- desc->DescUserControlLS = (user_ctl & 0x00000000FFFFFFFFUL) >> 0;
- desc->DescUserControlMS = (user_ctl & 0xFFFFFFFF00000000UL) >> 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);
-
- 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;
-
- err_descr_too_many:
- unlock_engine(ldev);
- dma_unmap_sg(&ldev->pldev->dev, acd->sgt.sgl, acd->sgt.nents, ldev->dir);
- free_table:
- sg_free_table(&acd->sgt);
-
- unpin_pages:
- if (nr_pages > 0)
- unpin_user_pages(acd->user_pages, nr_pages);
- kfree(acd->user_pages);
- err_alloc_userpages:
- kfree(acd);
- dev_dbg(&priv->ldev->pldev->dev, "%s returning with error %d\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);
- BUG_ON(!acd->user_pages);
- BUG_ON(!acd->sgt.sgl);
- BUG_ON(!acd->ldev);
- BUG_ON(!acd->ldev->pldev);
-
- dma_unmap_sg(&acd->ldev->pldev->dev, acd->sgt.sgl, acd->sgt.nents, acd->ldev->dir);
-
- for (i = 0 ; i < acd->page_count ; i++) {
- if (!PageReserved(acd->user_pages[i]))
- set_page_dirty_lock(acd->user_pages[i]);
- }
-
- unpin_user_pages(acd->user_pages, acd->page_count);
-
- sg_free_table(&acd->sgt);
-
- kfree(acd->user_pages);
-
- acd->flags = flags;
-
- if (acd->cpl) {
- complete(acd->cpl);
- } else {
- /*
- * There's no completion, so we're responsible for cleaning up
- * the acd
- */
- kfree(acd);
- }
-}
-
-/********** Fileops **********/
-static
-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)
- return -ENODEV;
-
- if (!atomic_dec_and_test(&ldev->open_count)) {
- atomic_inc(&ldev->open_count);
- return -EBUSY; /* already open */
- }
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->ldev = ldev;
- filp->private_data = priv;
-
- return 0;
-}
-
-static
-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;
-
- lock_engine(eng);
-
- stop_dma_engine(eng);
-
- cur = eng->desc_completed->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->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;
-}
-
-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;
-
- if (priv->ldev->dir != DMA_FROM_DEVICE)
- return -EMEDIUMTYPE;
-
- 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;
-
- if (priv->ldev->dir != DMA_TO_DEVICE)
- return -EMEDIUMTYPE;
-
- 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;
-
- 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;
-}
-
-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,
- .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
deleted file mode 100644
index 175fe8b0d055..000000000000
--- a/drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.c
+++ /dev/null
@@ -1,249 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/io.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/fs.h>
-#include <linux/rwsem.h>
-#include "kpc_dma_driver.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Matt.Sickler@daktronics.com");
-
-#define KPC_DMA_CHAR_MAJOR UNNAMED_MAJOR
-#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 *c;
-
- mutex_lock(&kpc_dma_mtx);
- list_for_each_entry(c, &kpc_dma_list, list) {
- if (c->pldev->id == minor)
- goto out;
- }
- c = NULL; // not-found case
-out:
- mutex_unlock(&kpc_dma_mtx);
- return c;
-}
-
-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);
-}
-
-static void kpc_dma_del_device(struct kpc_dma_device *ldev)
-{
- mutex_lock(&kpc_dma_mtx);
- list_del(&ldev->list);
- mutex_unlock(&kpc_dma_mtx);
-}
-
-/********** SysFS Attributes **********/
-static ssize_t engine_regs_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct kpc_dma_device *ldev;
- struct platform_device *pldev = to_platform_device(dev);
-
- if (!pldev)
- return 0;
- ldev = platform_get_drvdata(pldev);
- if (!ldev)
- return 0;
-
- return scnprintf(buf, PAGE_SIZE,
- "EngineControlStatus = 0x%08x\n"
- "RegNextDescPtr = 0x%08x\n"
- "RegSWDescPtr = 0x%08x\n"
- "RegCompletedDescPtr = 0x%08x\n"
- "desc_pool_first = %p\n"
- "desc_pool_last = %p\n"
- "desc_next = %p\n"
- "desc_completed = %p\n",
- readl(ldev->eng_regs + 1),
- readl(ldev->eng_regs + 2),
- readl(ldev->eng_regs + 3),
- readl(ldev->eng_regs + 4),
- ldev->desc_pool_first,
- ldev->desc_pool_last,
- ldev->desc_next,
- ldev->desc_completed
- );
-}
-static DEVICE_ATTR_RO(engine_regs);
-
-static const struct attribute *ndd_attr_list[] = {
- &dev_attr_engine_regs.attr,
- NULL,
-};
-
-static struct class *kpc_dma_class;
-
-/********** Platform Driver Functions **********/
-static
-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(*ldev), GFP_KERNEL);
-
- if (!ldev) {
- dev_err(&pldev->dev, "%s: unable to kzalloc space for kpc_dma_device\n", __func__);
- rv = -ENOMEM;
- goto err_rv;
- }
-
- 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, "%s: didn't get the engine regs resource!\n", __func__);
- rv = -ENXIO;
- goto err_kfree;
- }
- ldev->eng_regs = ioremap(r->start, resource_size(r));
- 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, "%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)) {
- rv = PTR_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, "%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, "%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:
- device_destroy(kpc_dma_class, dev);
- err_kfree:
- kfree(ldev);
- err_rv:
- return rv;
-}
-
-static
-int kpc_dma_remove(struct platform_device *pldev)
-{
- struct kpc_dma_device *ldev = platform_get_drvdata(pldev);
-
- if (!ldev)
- return -ENXIO;
-
- 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 **********/
-static struct platform_driver kpc_dma_plat_driver_i = {
- .probe = kpc_dma_probe,
- .remove = kpc_dma_remove,
- .driver = {
- .name = KP_DRIVER_NAME_DMA_CONTROLLER,
- },
-};
-
-static
-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) {
- 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)) {
- 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) {
- pr_err("Can't register platform driver for kpc_dma (err = %d)\n", err);
- goto fail_platdriver_register;
- }
-
- return err;
-
-fail_platdriver_register:
- class_destroy(kpc_dma_class);
-fail_class_create:
- __unregister_chrdev(KPC_DMA_CHAR_MAJOR, 0, KPC_DMA_NUM_MINORS, "kpc_dma");
-fail_chrdev_register:
- return err;
-}
-module_init(kpc_dma_driver_init);
-
-static
-void __exit kpc_dma_driver_exit(void)
-{
- platform_driver_unregister(&kpc_dma_plat_driver_i);
- class_destroy(kpc_dma_class);
- __unregister_chrdev(KPC_DMA_CHAR_MAJOR, 0, KPC_DMA_NUM_MINORS, "kpc_dma");
-}
-module_exit(kpc_dma_driver_exit);
diff --git a/drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.h b/drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.h
deleted file mode 100644
index 8b9c978257b9..000000000000
--- a/drivers/staging/kpc2000/kpc_dma/kpc_dma_driver.h
+++ /dev/null
@@ -1,222 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-#ifndef KPC_DMA_DRIVER_H
-#define KPC_DMA_DRIVER_H
-#include <linux/platform_device.h>
-#include <linux/cdev.h>
-#include <linux/kfifo.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/miscdevice.h>
-#include <linux/rwsem.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmapool.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/bitops.h>
-#include "../kpc.h"
-
-struct kp2000_device;
-struct kpc_dma_device {
- struct list_head list;
- struct platform_device *pldev;
- u32 __iomem *eng_regs;
- 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;
-};
-
-struct dev_private_data {
- struct kpc_dma_device *ldev;
- u64 card_addr;
- u64 user_ctl;
- u64 user_ctl_last;
- u64 user_sts;
-};
-
-struct kpc_dma_device *kpc_dma_lookup_device(int minor);
-
-extern const struct file_operations kpc_dma_fops;
-
-#define ENG_CAP_PRESENT 0x00000001
-#define ENG_CAP_DIRECTION 0x00000002
-#define ENG_CAP_TYPE_MASK 0x000000F0
-#define ENG_CAP_NUMBER_MASK 0x0000FF00
-#define ENG_CAP_CARD_ADDR_SIZE_MASK 0x007F0000
-#define ENG_CAP_DESC_MAX_BYTE_CNT_MASK 0x3F000000
-#define ENG_CAP_PERF_SCALE_MASK 0xC0000000
-
-#define ENG_CTL_IRQ_ENABLE BIT(0)
-#define ENG_CTL_IRQ_ACTIVE BIT(1)
-#define ENG_CTL_DESC_COMPLETE BIT(2)
-#define ENG_CTL_DESC_ALIGN_ERR BIT(3)
-#define ENG_CTL_DESC_FETCH_ERR BIT(4)
-#define ENG_CTL_SW_ABORT_ERR BIT(5)
-#define ENG_CTL_DESC_CHAIN_END BIT(7)
-#define ENG_CTL_DMA_ENABLE BIT(8)
-#define ENG_CTL_DMA_RUNNING BIT(10)
-#define ENG_CTL_DMA_WAITING BIT(11)
-#define ENG_CTL_DMA_WAITING_PERSIST BIT(12)
-#define ENG_CTL_DMA_RESET_REQUEST BIT(14)
-#define ENG_CTL_DMA_RESET BIT(15)
-#define ENG_CTL_DESC_FETCH_ERR_CLASS_MASK 0x700000
-
-struct aio_cb_data {
- struct dev_private_data *priv;
- struct kpc_dma_device *ldev;
- struct completion *cpl;
- unsigned char flags;
- size_t len;
-
- unsigned int page_count;
- struct page **user_pages;
- struct sg_table sgt;
- int mapped_entry_count;
-};
-
-#define ACD_FLAG_DONE 0
-#define ACD_FLAG_ABORT 1
-#define ACD_FLAG_ENG_ACCUM_ERROR 4
-#define ACD_FLAG_ENG_ACCUM_SHORT 5
-
-struct kpc_dma_descriptor {
- struct {
- volatile u32 DescByteCount :20;
- volatile u32 DescStatusErrorFlags :4;
- volatile u32 DescStatusFlags :8;
- };
- volatile u32 DescUserControlLS;
- volatile u32 DescUserControlMS;
- volatile u32 DescCardAddrLS;
- struct {
- volatile u32 DescBufferByteCount :20;
- volatile u32 DescCardAddrMS :4;
- volatile u32 DescControlFlags :8;
- };
- 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:
-#define DMA_DESC_CTL_SOP BIT(7)
-#define DMA_DESC_CTL_EOP BIT(6)
-#define DMA_DESC_CTL_AFIFO BIT(2)
-#define DMA_DESC_CTL_IRQONERR BIT(1)
-#define DMA_DESC_CTL_IRQONDONE BIT(0)
-// DescStatusFlags:
-#define DMA_DESC_STS_SOP BIT(7)
-#define DMA_DESC_STS_EOP BIT(6)
-#define DMA_DESC_STS_ERROR BIT(4)
-#define DMA_DESC_STS_USMSZ BIT(3)
-#define DMA_DESC_STS_USLSZ BIT(2)
-#define DMA_DESC_STS_SHORT BIT(1)
-#define DMA_DESC_STS_COMPLETE BIT(0)
-// DescStatusErrorFlags:
-#define DMA_DESC_ESTS_ECRC BIT(2)
-#define DMA_DESC_ESTS_POISON BIT(1)
-#define DMA_DESC_ESTS_UNSUCCESSFUL BIT(0)
-
-#define DMA_DESC_ALIGNMENT 0x20
-
-static inline
-u32 GetEngineCapabilities(struct kpc_dma_device *eng)
-{
- return readl(eng->eng_regs + 0);
-}
-
-static inline
-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)
-{
- writel(desc->MyDMAAddr, eng->eng_regs + 2);
-}
-
-static inline
-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)
-{
- return readl(eng->eng_regs + 4);
-}
-
-static inline
-void lock_engine(struct kpc_dma_device *eng)
-{
- BUG_ON(!eng);
- mutex_lock(&eng->sem);
-}
-
-static inline
-void unlock_engine(struct kpc_dma_device *eng)
-{
- BUG_ON(!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);
-void stop_dma_engine(struct kpc_dma_device *eng);
-void destroy_dma_engine(struct kpc_dma_device *eng);
-void clear_desc(struct kpc_dma_descriptor *desc);
-int count_descriptors_available(struct kpc_dma_device *eng);
-void transfer_complete_cb(struct aio_cb_data *acd, size_t xfr_count, u32 flags);
-
-#endif /* KPC_DMA_DRIVER_H */
-
diff --git a/drivers/staging/kpc2000/kpc_dma/uapi.h b/drivers/staging/kpc2000/kpc_dma/uapi.h
deleted file mode 100644
index 5ff6a1a36ff9..000000000000
--- a/drivers/staging/kpc2000/kpc_dma/uapi.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-#ifndef KPC_DMA_DRIVER_UAPI_H_
-#define KPC_DMA_DRIVER_UAPI_H_
-#include <linux/ioctl.h>
-
-#define KND_IOCTL_SET_CARD_ADDR _IOW('k', 1, __u32)
-#define KND_IOCTL_SET_USER_CTL _IOW('k', 2, __u64)
-#define KND_IOCTL_SET_USER_CTL_LAST _IOW('k', 4, __u64)
-#define KND_IOCTL_GET_USER_STS _IOR('k', 3, __u64)
-
-#endif /* KPC_DMA_DRIVER_UAPI_H_ */
diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c
index 8bc3b7d8d3d5..eaa70893224a 100644
--- a/drivers/staging/ks7010/ks_hostif.c
+++ b/drivers/staging/ks7010/ks_hostif.c
@@ -524,13 +524,11 @@ void hostif_mib_get_confirm(struct ks_wlan_private *priv)
struct net_device *dev = priv->net_dev;
u32 mib_status;
u32 mib_attribute;
- u16 mib_val_size;
- u16 mib_val_type;
mib_status = get_dword(priv);
mib_attribute = get_dword(priv);
- mib_val_size = get_word(priv);
- mib_val_type = get_word(priv);
+ get_word(priv); /* mib_val_size */
+ get_word(priv); /* mib_val_type */
if (mib_status) {
netdev_err(priv->net_dev, "attribute=%08X, status=%08X\n",
@@ -846,9 +844,7 @@ void hostif_ps_adhoc_set_confirm(struct ks_wlan_private *priv)
static
void hostif_infrastructure_set_confirm(struct ks_wlan_private *priv)
{
- u16 result_code;
-
- result_code = get_word(priv);
+ get_word(priv); /* result_code */
priv->infra_status = 1; /* infrastructure mode set */
hostif_sme_enqueue(priv, SME_MODE_SET_CONFIRM);
}
@@ -926,14 +922,14 @@ static
void hostif_phy_information_confirm(struct ks_wlan_private *priv)
{
struct iw_statistics *wstats = &priv->wstats;
- u8 rssi, signal, noise;
+ u8 rssi, signal;
u8 link_speed;
u32 transmitted_frame_count, received_fragment_count;
u32 failed_count, fcs_error_count;
rssi = get_byte(priv);
signal = get_byte(priv);
- noise = get_byte(priv);
+ get_byte(priv); /* noise */
link_speed = get_byte(priv);
transmitted_frame_count = get_dword(priv);
received_fragment_count = get_dword(priv);
diff --git a/drivers/staging/ks7010/ks_hostif.h b/drivers/staging/ks7010/ks_hostif.h
index 39138191a556..c62a494ed6bb 100644
--- a/drivers/staging/ks7010/ks_hostif.h
+++ b/drivers/staging/ks7010/ks_hostif.h
@@ -498,20 +498,20 @@ struct hostif_mic_failure_request {
#define TX_RATE_FIXED 5
/* 11b rate */
-#define TX_RATE_1M (u8)(10 / 5) /* 11b 11g basic rate */
-#define TX_RATE_2M (u8)(20 / 5) /* 11b 11g basic rate */
-#define TX_RATE_5M (u8)(55 / 5) /* 11g basic rate */
-#define TX_RATE_11M (u8)(110 / 5) /* 11g basic rate */
+#define TX_RATE_1M ((u8)(10 / 5)) /* 11b 11g basic rate */
+#define TX_RATE_2M ((u8)(20 / 5)) /* 11b 11g basic rate */
+#define TX_RATE_5M ((u8)(55 / 5)) /* 11g basic rate */
+#define TX_RATE_11M ((u8)(110 / 5)) /* 11g basic rate */
/* 11g rate */
-#define TX_RATE_6M (u8)(60 / 5) /* 11g basic rate */
-#define TX_RATE_12M (u8)(120 / 5) /* 11g basic rate */
-#define TX_RATE_24M (u8)(240 / 5) /* 11g basic rate */
-#define TX_RATE_9M (u8)(90 / 5)
-#define TX_RATE_18M (u8)(180 / 5)
-#define TX_RATE_36M (u8)(360 / 5)
-#define TX_RATE_48M (u8)(480 / 5)
-#define TX_RATE_54M (u8)(540 / 5)
+#define TX_RATE_6M ((u8)(60 / 5)) /* 11g basic rate */
+#define TX_RATE_12M ((u8)(120 / 5)) /* 11g basic rate */
+#define TX_RATE_24M ((u8)(240 / 5)) /* 11g basic rate */
+#define TX_RATE_9M ((u8)(90 / 5))
+#define TX_RATE_18M ((u8)(180 / 5))
+#define TX_RATE_36M ((u8)(360 / 5))
+#define TX_RATE_48M ((u8)(480 / 5))
+#define TX_RATE_54M ((u8)(540 / 5))
static inline bool is_11b_rate(u8 rate)
{
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index ca59986b20f8..e3aaae920847 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -42,4 +42,6 @@ source "drivers/staging/media/tegra-video/Kconfig"
source "drivers/staging/media/ipu3/Kconfig"
+source "drivers/staging/media/av7110/Kconfig"
+
endif
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 716929a1a313..5b5afc5b03a0 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_TEGRA_VDE) += tegra-vde/
obj-$(CONFIG_VIDEO_HANTRO) += hantro/
obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/
obj-$(CONFIG_VIDEO_ZORAN) += zoran/
+obj-$(CONFIG_DVB_AV7110) += av7110/
diff --git a/drivers/staging/media/atomisp/Makefile b/drivers/staging/media/atomisp/Makefile
index 51498b2e85b8..606b7754fdfd 100644
--- a/drivers/staging/media/atomisp/Makefile
+++ b/drivers/staging/media/atomisp/Makefile
@@ -16,7 +16,6 @@ atomisp-objs += \
pci/atomisp_acc.o \
pci/atomisp_cmd.o \
pci/atomisp_compat_css20.o \
- pci/atomisp_compat_ioctl32.o \
pci/atomisp_csi2.o \
pci/atomisp_drvfs.o \
pci/atomisp_file.o \
diff --git a/drivers/staging/media/atomisp/TODO b/drivers/staging/media/atomisp/TODO
index 6987bb2d32cf..2d1ef9eb262a 100644
--- a/drivers/staging/media/atomisp/TODO
+++ b/drivers/staging/media/atomisp/TODO
@@ -120,6 +120,11 @@ TODO
for this driver until the other work is done, as there will be a lot
of code churn until this driver becomes functional again.
+16. Fix private ioctls to not need a compat_ioctl handler for running
+ 32-bit tasks. The compat code has been removed because of bugs,
+ and should not be needed for modern drivers. Fixing this properly
+ unfortunately means an incompatible ABI change.
+
Limitations
===========
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
index d170d0adfea4..687888d643df 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
@@ -300,7 +300,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client,
/* pixel clock calculattion */
dev->vt_pix_clk_freq_mhz = 14400000; // 16.8MHz
buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz;
- pr_info("vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz);
+ dev_dbg(&client->dev, "vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz);
/* get integration time */
buf->coarse_integration_time_min = GC0310_COARSE_INTG_TIME_MIN;
@@ -326,7 +326,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client,
if (ret)
return ret;
buf->crop_horizontal_start = val | (reg_val & 0xFF);
- pr_info("crop_horizontal_start=%d\n", buf->crop_horizontal_start);
+ dev_dbg(&client->dev, "crop_horizontal_start=%d\n", buf->crop_horizontal_start);
/* Getting crop_vertical_start */
ret = gc0310_read_reg(client, GC0310_8BIT,
@@ -339,7 +339,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client,
if (ret)
return ret;
buf->crop_vertical_start = val | (reg_val & 0xFF);
- pr_info("crop_vertical_start=%d\n", buf->crop_vertical_start);
+ dev_dbg(&client->dev, "crop_vertical_start=%d\n", buf->crop_vertical_start);
/* Getting output_width */
ret = gc0310_read_reg(client, GC0310_8BIT,
@@ -352,7 +352,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client,
if (ret)
return ret;
buf->output_width = val | (reg_val & 0xFF);
- pr_info("output_width=%d\n", buf->output_width);
+ dev_dbg(&client->dev, "output_width=%d\n", buf->output_width);
/* Getting output_height */
ret = gc0310_read_reg(client, GC0310_8BIT,
@@ -365,12 +365,12 @@ static int gc0310_get_intg_factor(struct i2c_client *client,
if (ret)
return ret;
buf->output_height = val | (reg_val & 0xFF);
- pr_info("output_height=%d\n", buf->output_height);
+ dev_dbg(&client->dev, "output_height=%d\n", buf->output_height);
buf->crop_horizontal_end = buf->crop_horizontal_start + buf->output_width - 1;
buf->crop_vertical_end = buf->crop_vertical_start + buf->output_height - 1;
- pr_info("crop_horizontal_end=%d\n", buf->crop_horizontal_end);
- pr_info("crop_vertical_end=%d\n", buf->crop_vertical_end);
+ dev_dbg(&client->dev, "crop_horizontal_end=%d\n", buf->crop_horizontal_end);
+ dev_dbg(&client->dev, "crop_vertical_end=%d\n", buf->crop_vertical_end);
/* Getting line_length_pck */
ret = gc0310_read_reg(client, GC0310_8BIT,
@@ -389,7 +389,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client,
return ret;
sh_delay = reg_val;
buf->line_length_pck = buf->output_width + hori_blanking + sh_delay + 4;
- pr_info("hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking,
+ dev_dbg(&client->dev, "hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking,
sh_delay, buf->line_length_pck);
/* Getting frame_length_lines */
@@ -404,7 +404,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client,
return ret;
vert_blanking = val | (reg_val & 0xFF);
buf->frame_length_lines = buf->output_height + vert_blanking;
- pr_info("vert_blanking=%d frame_length_lines=%d\n", vert_blanking,
+ dev_dbg(&client->dev, "vert_blanking=%d frame_length_lines=%d\n", vert_blanking,
buf->frame_length_lines);
buf->binning_factor_x = res->bin_factor_x ?
@@ -434,7 +434,7 @@ static int gc0310_set_gain(struct v4l2_subdev *sd, int gain)
dgain = gain / 2;
}
- pr_info("gain=0x%x again=0x%x dgain=0x%x\n", gain, again, dgain);
+ dev_dbg(&client->dev, "gain=0x%x again=0x%x dgain=0x%x\n", gain, again, dgain);
/* set analog gain */
ret = gc0310_write_reg(client, GC0310_8BIT,
@@ -458,7 +458,7 @@ static int __gc0310_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
- pr_info("coarse_itg=%d gain=%d digitgain=%d\n", coarse_itg, gain, digitgain);
+ dev_dbg(&client->dev, "coarse_itg=%d gain=%d digitgain=%d\n", coarse_itg, gain, digitgain);
/* set exposure */
ret = gc0310_write_reg(client, GC0310_8BIT,
@@ -718,7 +718,6 @@ static int gc0310_init(struct v4l2_subdev *sd)
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct gc0310_device *dev = to_gc0310_sensor(sd);
- pr_info("%s S\n", __func__);
mutex_lock(&dev->input_lock);
/* set initial registers */
@@ -730,7 +729,6 @@ static int gc0310_init(struct v4l2_subdev *sd)
mutex_unlock(&dev->input_lock);
- pr_info("%s E\n", __func__);
return ret;
}
@@ -796,7 +794,6 @@ static int power_up(struct v4l2_subdev *sd)
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
- pr_info("%s S\n", __func__);
if (!dev->platform_data) {
dev_err(&client->dev,
"no camera_sensor_platform_data");
@@ -823,7 +820,6 @@ static int power_up(struct v4l2_subdev *sd)
msleep(100);
- pr_info("%s E\n", __func__);
return 0;
fail_gpio:
@@ -959,20 +955,17 @@ static int startup(struct v4l2_subdev *sd)
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = 0;
- pr_info("%s S\n", __func__);
-
ret = gc0310_write_reg_array(client, gc0310_res[dev->fmt_idx].regs);
if (ret) {
dev_err(&client->dev, "gc0310 write register err.\n");
return ret;
}
- pr_info("%s E\n", __func__);
return ret;
}
static int gc0310_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -982,8 +975,6 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd,
int ret = 0;
int idx = 0;
- pr_info("%s S\n", __func__);
-
if (format->pad)
return -EINVAL;
@@ -1008,7 +999,7 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd,
fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *fmt;
+ sd_state->pads->try_fmt = *fmt;
mutex_unlock(&dev->input_lock);
return 0;
}
@@ -1020,8 +1011,8 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd,
return -EINVAL;
}
- printk("%s: before gc0310_write_reg_array %s\n", __func__,
- gc0310_res[dev->fmt_idx].desc);
+ dev_dbg(&client->dev, "%s: before gc0310_write_reg_array %s\n",
+ __func__, gc0310_res[dev->fmt_idx].desc);
ret = startup(sd);
if (ret) {
dev_err(&client->dev, "gc0310 startup err\n");
@@ -1035,14 +1026,13 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd,
goto err;
}
- pr_info("%s E\n", __func__);
err:
mutex_unlock(&dev->input_lock);
return ret;
}
static int gc0310_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -1068,7 +1058,6 @@ static int gc0310_detect(struct i2c_client *client)
int ret;
u16 id;
- pr_info("%s S\n", __func__);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
return -ENODEV;
@@ -1085,7 +1074,7 @@ static int gc0310_detect(struct i2c_client *client)
return -ENODEV;
}
id = ((((u16)high) << 8) | (u16)low);
- pr_info("sensor ID = 0x%x\n", id);
+ dev_dbg(&client->dev, "sensor ID = 0x%x\n", id);
if (id != GC0310_ID) {
dev_err(&client->dev, "sensor ID error, read id = 0x%x, target id = 0x%x\n", id,
@@ -1095,8 +1084,6 @@ static int gc0310_detect(struct i2c_client *client)
dev_dbg(&client->dev, "detect gc0310 success\n");
- pr_info("%s E\n", __func__);
-
return 0;
}
@@ -1106,7 +1093,7 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable)
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
- pr_info("%s S enable=%d\n", __func__, enable);
+ dev_dbg(&client->dev, "%s S enable=%d\n", __func__, enable);
mutex_lock(&dev->input_lock);
if (enable) {
@@ -1142,7 +1129,6 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable)
}
mutex_unlock(&dev->input_lock);
- pr_info("%s E\n", __func__);
return ret;
}
@@ -1153,7 +1139,6 @@ static int gc0310_s_config(struct v4l2_subdev *sd,
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = 0;
- pr_info("%s S\n", __func__);
if (!platform_data)
return -ENODEV;
@@ -1196,7 +1181,6 @@ static int gc0310_s_config(struct v4l2_subdev *sd,
}
mutex_unlock(&dev->input_lock);
- pr_info("%s E\n", __func__);
return 0;
fail_csi_cfg:
@@ -1221,7 +1205,7 @@ static int gc0310_g_frame_interval(struct v4l2_subdev *sd,
}
static int gc0310_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= MAX_FMTS)
@@ -1232,7 +1216,7 @@ static int gc0310_enum_mbus_code(struct v4l2_subdev *sd,
}
static int gc0310_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
int index = fse->index;
@@ -1365,7 +1349,6 @@ static int gc0310_probe(struct i2c_client *client)
if (ret)
gc0310_remove(client);
- pr_info("%s E\n", __func__);
return ret;
out_free:
v4l2_device_unregister_subdev(&dev->sd);
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
index 78147ffb6099..9363c1a52ae9 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
@@ -171,8 +171,8 @@ static int __gc2235_buf_reg_array(struct i2c_client *client,
}
static int __gc2235_write_reg_is_consecutive(struct i2c_client *client,
- struct gc2235_write_ctrl *ctrl,
- const struct gc2235_reg *next)
+ struct gc2235_write_ctrl *ctrl,
+ const struct gc2235_reg *next)
{
if (ctrl->index == 0)
return 1;
@@ -228,7 +228,7 @@ static int gc2235_g_focal(struct v4l2_subdev *sd, s32 *val)
static int gc2235_g_fnumber(struct v4l2_subdev *sd, s32 *val)
{
- /*const f number for imx*/
+ /* const f number for imx */
*val = (GC2235_F_NUMBER_DEFAULT_NUM << 16) | GC2235_F_NUMBER_DEM;
return 0;
}
@@ -427,7 +427,8 @@ static long gc2235_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
return 0;
}
-/* This returns the exposure time being used. This should only be used
+/*
+ * This returns the exposure time being used. This should only be used
* for filling in EXIF data, not for actual image processing.
*/
static int gc2235_q_exposure(struct v4l2_subdev *sd, s32 *value)
@@ -658,9 +659,9 @@ static int gc2235_s_power(struct v4l2_subdev *sd, int on)
{
int ret;
- if (on == 0)
+ if (on == 0) {
ret = power_down(sd);
- else {
+ } else {
ret = power_up(sd);
if (!ret)
ret = __gc2235_init(sd);
@@ -746,11 +747,12 @@ static int startup(struct v4l2_subdev *sd)
int ret = 0;
if (is_init == 0) {
- /* force gc2235 to do a reset in res change, otherwise it
- * can not output normal after switching res. and it is not
- * necessary for first time run up after power on, for the sack
- * of performance
- */
+ /*
+ * force gc2235 to do a reset in res change, otherwise it
+ * can not output normal after switching res. and it is not
+ * necessary for first time run up after power on, for the sack
+ * of performance
+ */
power_down(sd);
power_up(sd);
gc2235_write_reg_array(client, gc2235_init_settings);
@@ -767,7 +769,7 @@ static int startup(struct v4l2_subdev *sd)
}
static int gc2235_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -796,7 +798,7 @@ static int gc2235_set_fmt(struct v4l2_subdev *sd,
}
fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *fmt;
+ sd_state->pads->try_fmt = *fmt;
mutex_unlock(&dev->input_lock);
return 0;
}
@@ -825,7 +827,7 @@ err:
}
static int gc2235_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -904,7 +906,8 @@ static int gc2235_s_config(struct v4l2_subdev *sd,
(struct camera_sensor_platform_data *)platform_data;
mutex_lock(&dev->input_lock);
- /* power off the module, then power on it in future
+ /*
+ * power off the module, then power on it in future
* as first power on by board may not fulfill the
* power on sequqence needed by the module
*/
@@ -963,7 +966,7 @@ static int gc2235_g_frame_interval(struct v4l2_subdev *sd,
}
static int gc2235_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= MAX_FMTS)
@@ -974,7 +977,7 @@ static int gc2235_enum_mbus_code(struct v4l2_subdev *sd,
}
static int gc2235_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
int index = fse->index;
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c b/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c
index b93c80471f22..7a20d918a9d5 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c
@@ -50,14 +50,16 @@ struct tbd_data_record_header {
static int set_msr_configuration(struct i2c_client *client, uint8_t *bufptr,
unsigned int size)
{
- /* The configuration data contains any number of sequences where
+ /*
+ * The configuration data contains any number of sequences where
* the first byte (that is, uint8_t) that marks the number of bytes
* in the sequence to follow, is indeed followed by the indicated
* number of bytes of actual data to be written to sensor.
* By convention, the first two bytes of actual data should be
* understood as an address in the sensor address space (hibyte
* followed by lobyte) where the remaining data in the sequence
- * will be written. */
+ * will be written.
+ */
u8 *ptr = bufptr;
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
index f5de81132177..11196180a206 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
@@ -475,10 +475,12 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
if (!dev || !dev->platform_data)
return -ENODEV;
- /* Note: current modules wire only one GPIO signal (RESET#),
+ /*
+ * Note: current modules wire only one GPIO signal (RESET#),
* but the schematic wires up two to the connector. BIOS
* versions have been unfortunately inconsistent with which
- * ACPI index RESET# is on, so hit both */
+ * ACPI index RESET# is on, so hit both
+ */
if (flag) {
ret = dev->platform_data->gpio0_ctrl(sd, 0);
@@ -560,7 +562,7 @@ static int power_down(struct v4l2_subdev *sd)
if (ret)
dev_err(&client->dev, "vprog failed.\n");
- /*according to DS, 20ms is needed after power down*/
+ /* according to DS, 20ms is needed after power down */
msleep(20);
return ret;
@@ -568,9 +570,9 @@ static int power_down(struct v4l2_subdev *sd)
static int mt9m114_s_power(struct v4l2_subdev *sd, int power)
{
- if (power == 0)
+ if (power == 0) {
return power_down(sd);
- else {
+ } else {
if (power_up(sd))
return -EINVAL;
@@ -801,7 +803,7 @@ static int mt9m114_get_intg_factor(struct i2c_client *client,
}
static int mt9m114_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -822,7 +824,7 @@ static int mt9m114_get_fmt(struct v4l2_subdev *sd,
}
static int mt9m114_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -846,7 +848,7 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd,
mt9m114_try_res(&width, &height);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *fmt;
+ sd_state->pads->try_fmt = *fmt;
return 0;
}
res_index = mt9m114_to_res(width, height);
@@ -947,7 +949,7 @@ static int mt9m114_g_focal(struct v4l2_subdev *sd, s32 *val)
static int mt9m114_g_fnumber(struct v4l2_subdev *sd, s32 *val)
{
- /*const f number for mt9m114*/
+ /* const f number for mt9m114 */
*val = (MT9M114_F_NUMBER_DEFAULT_NUM << 16) | MT9M114_F_NUMBER_DEM;
return 0;
}
@@ -998,44 +1000,48 @@ static long mt9m114_s_exposure(struct v4l2_subdev *sd,
struct mt9m114_device *dev = to_mt9m114_sensor(sd);
int ret = 0;
unsigned int coarse_integration = 0;
- unsigned int FLines = 0;
- unsigned int FrameLengthLines = 0; /* ExposureTime.FrameLengthLines; */
- unsigned int AnalogGain, DigitalGain;
- u32 AnalogGainToWrite = 0;
+ unsigned int f_lines = 0;
+ unsigned int frame_len_lines = 0; /* ExposureTime.FrameLengthLines; */
+ unsigned int analog_gain, digital_gain;
+ u32 analog_gain_to_write = 0;
dev_dbg(&client->dev, "%s(0x%X 0x%X 0x%X)\n", __func__,
exposure->integration_time[0], exposure->gain[0],
exposure->gain[1]);
coarse_integration = exposure->integration_time[0];
- /* fine_integration = ExposureTime.FineIntegrationTime; */
- /* FrameLengthLines = ExposureTime.FrameLengthLines; */
- FLines = mt9m114_res[dev->res].lines_per_frame;
- AnalogGain = exposure->gain[0];
- DigitalGain = exposure->gain[1];
+ /*
+ * fine_integration = ExposureTime.FineIntegrationTime;
+ * frame_len_lines = ExposureTime.FrameLengthLines;
+ */
+ f_lines = mt9m114_res[dev->res].lines_per_frame;
+ analog_gain = exposure->gain[0];
+ digital_gain = exposure->gain[1];
if (!dev->streamon) {
/*Save the first exposure values while stream is off*/
dev->first_exp = coarse_integration;
- dev->first_gain = AnalogGain;
- dev->first_diggain = DigitalGain;
+ dev->first_gain = analog_gain;
+ dev->first_diggain = digital_gain;
}
- /* DigitalGain = 0x400 * (((u16) DigitalGain) >> 8) +
- ((unsigned int)(0x400 * (((u16) DigitalGain) & 0xFF)) >>8); */
+ /* digital_gain = 0x400 * (((u16) digital_gain) >> 8) + */
+ /* ((unsigned int)(0x400 * (((u16) digital_gain) & 0xFF)) >>8); */
/* set frame length */
- if (FLines < coarse_integration + 6)
- FLines = coarse_integration + 6;
- if (FLines < FrameLengthLines)
- FLines = FrameLengthLines;
- ret = mt9m114_write_reg(client, MISENSOR_16BIT, 0x300A, FLines);
+ if (f_lines < coarse_integration + 6)
+ f_lines = coarse_integration + 6;
+ if (f_lines < frame_len_lines)
+ f_lines = frame_len_lines;
+ ret = mt9m114_write_reg(client, MISENSOR_16BIT, 0x300A, f_lines);
if (ret) {
- v4l2_err(client, "%s: fail to set FLines\n", __func__);
+ v4l2_err(client, "%s: fail to set f_lines\n", __func__);
return -EINVAL;
}
/* set coarse integration */
- /* 3A provide real exposure time.
- should not translate to any value here. */
+ /*
+ * 3A provide real exposure time.
+ * should not translate to any value here.
+ */
ret = mt9m114_write_reg(client, MISENSOR_16BIT,
REG_EXPO_COARSE, (u16)(coarse_integration));
if (ret) {
@@ -1044,38 +1050,40 @@ static long mt9m114_s_exposure(struct v4l2_subdev *sd,
}
/*
- // set analog/digital gain
- switch(AnalogGain)
+ * set analog/digital gain
+ switch(analog_gain)
{
case 0:
- AnalogGainToWrite = 0x0;
+ analog_gain_to_write = 0x0;
break;
case 1:
- AnalogGainToWrite = 0x20;
+ analog_gain_to_write = 0x20;
break;
case 2:
- AnalogGainToWrite = 0x60;
+ analog_gain_to_write = 0x60;
break;
case 4:
- AnalogGainToWrite = 0xA0;
+ analog_gain_to_write = 0xA0;
break;
case 8:
- AnalogGainToWrite = 0xE0;
+ analog_gain_to_write = 0xE0;
break;
default:
- AnalogGainToWrite = 0x20;
+ analog_gain_to_write = 0x20;
break;
}
*/
- if (DigitalGain >= 16 || DigitalGain <= 1)
- DigitalGain = 1;
- /* AnalogGainToWrite =
- (u16)((DigitalGain << 12) | AnalogGainToWrite); */
- AnalogGainToWrite = (u16)((DigitalGain << 12) | (u16)AnalogGain);
+ if (digital_gain >= 16 || digital_gain <= 1)
+ digital_gain = 1;
+ /*
+ * analog_gain_to_write = (u16)((digital_gain << 12)
+ * | analog_gain_to_write);
+ */
+ analog_gain_to_write = (u16)((digital_gain << 12) | (u16)analog_gain);
ret = mt9m114_write_reg(client, MISENSOR_16BIT,
- REG_GAIN, AnalogGainToWrite);
+ REG_GAIN, analog_gain_to_write);
if (ret) {
- v4l2_err(client, "%s: fail to set AnalogGainToWrite\n",
+ v4l2_err(client, "%s: fail to set analog_gain_to_write\n",
__func__);
return -EINVAL;
}
@@ -1095,8 +1103,10 @@ static long mt9m114_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
return 0;
}
-/* This returns the exposure time being used. This should only be used
- for filling in EXIF data, not for actual image processing. */
+/*
+ * This returns the exposure time being used. This should only be used
+ * for filling in EXIF data, not for actual image processing.
+ */
static int mt9m114_g_exposure(struct v4l2_subdev *sd, s32 *value)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1158,7 +1168,7 @@ static int mt9m114_s_exposure_metering(struct v4l2_subdev *sd, s32 val)
* This function is for touch exposure feature.
*/
static int mt9m114_s_exposure_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1247,7 +1257,8 @@ static int mt9m114_s_ev(struct v4l2_subdev *sd, s32 val)
s32 luma = 0x37;
int err;
- /* EV value only support -2 to 2
+ /*
+ * EV value only support -2 to 2
* 0: 0x37, 1:0x47, 2:0x57, -1:0x27, -2:0x17
*/
if (val < -2 || val > 2)
@@ -1295,9 +1306,10 @@ static int mt9m114_g_ev(struct v4l2_subdev *sd, s32 *val)
return 0;
}
-/* Fake interface
+/*
+ * Fake interface
* mt9m114 now can not support 3a_lock
-*/
+ */
static int mt9m114_s_3a_lock(struct v4l2_subdev *sd, s32 val)
{
aaalock = val;
@@ -1719,7 +1731,7 @@ static int mt9m114_s_stream(struct v4l2_subdev *sd, int enable)
}
static int mt9m114_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index)
@@ -1730,7 +1742,7 @@ static int mt9m114_enum_mbus_code(struct v4l2_subdev *sd,
}
static int mt9m114_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
unsigned int index = fse->index;
@@ -1843,7 +1855,7 @@ static int mt9m114_probe(struct i2c_client *client)
return ret;
}
- /*TODO add format code here*/
+ /* TODO add format code here */
dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
dev->pad.flags = MEDIA_PAD_FL_SOURCE;
dev->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
index c90730513438..2111e4a478c1 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
@@ -127,7 +127,7 @@ static int ov2680_g_focal(struct v4l2_subdev *sd, s32 *val)
static int ov2680_g_fnumber(struct v4l2_subdev *sd, s32 *val)
{
- /*const f number for ov2680*/
+ /* const f number for ov2680 */
*val = (OV2680_F_NUMBER_DEFAULT_NUM << 16) | OV2680_F_NUMBER_DEM;
return 0;
@@ -399,7 +399,8 @@ static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
return 0;
}
-/* This returns the exposure time being used. This should only be used
+/*
+ * This returns the exposure time being used. This should only be used
* for filling in EXIF data, not for actual image processing.
*/
static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value)
@@ -461,11 +462,11 @@ static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value)
ret = ov2680_read_reg(client, 1, OV2680_FLIP_REG, &val);
if (ret)
return ret;
- if (value) {
+ if (value)
val |= OV2680_FLIP_MIRROR_BIT_ENABLE;
- } else {
+ else
val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE;
- }
+
ret = ov2680_write_reg(client, 1,
OV2680_FLIP_REG, val);
if (ret)
@@ -727,11 +728,13 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
if (!dev || !dev->platform_data)
return -ENODEV;
- /* The OV2680 documents only one GPIO input (#XSHUTDN), but
+ /*
+ * The OV2680 documents only one GPIO input (#XSHUTDN), but
* existing integrations often wire two (reset/power_down)
* because that is the way other sensors work. There is no
* way to tell how it is wired internally, so existing
- * firmwares expose both and we drive them symmetrically. */
+ * firmwares expose both and we drive them symmetrically.
+ */
if (flag) {
ret = dev->platform_data->gpio0_ctrl(sd, 1);
usleep_range(10000, 15000);
@@ -911,7 +914,7 @@ static int get_resolution_index(int w, int h)
}
static int ov2680_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -948,7 +951,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
}
fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *fmt;
+ sd_state->pads->try_fmt = *fmt;
mutex_unlock(&dev->input_lock);
return 0;
}
@@ -977,7 +980,8 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
goto err;
}
- /*recall flip functions to avoid flip registers
+ /*
+ * recall flip functions to avoid flip registers
* were overridden by default setting
*/
if (h_flag)
@@ -987,7 +991,8 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
v4l2_info(client, "\n%s idx %d\n", __func__, dev->fmt_idx);
- /*ret = startup(sd);
+ /*
+ * ret = startup(sd);
* if (ret)
* dev_err(&client->dev, "ov2680 startup err\n");
*/
@@ -997,7 +1002,7 @@ err:
}
static int ov2680_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -1096,7 +1101,8 @@ static int ov2680_s_config(struct v4l2_subdev *sd,
(struct camera_sensor_platform_data *)platform_data;
mutex_lock(&dev->input_lock);
- /* power off the module, then power on it in future
+ /*
+ * power off the module, then power on it in future
* as first power on by board may not fulfill the
* power on sequqence needed by the module
*/
@@ -1155,7 +1161,7 @@ static int ov2680_g_frame_interval(struct v4l2_subdev *sd,
}
static int ov2680_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= MAX_FMTS)
@@ -1166,7 +1172,7 @@ static int ov2680_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov2680_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
int index = fse->index;
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
index 1209492c1826..90d0871a78a3 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
@@ -49,8 +49,8 @@ static int ov2722_read_reg(struct i2c_client *client,
return -ENODEV;
}
- if (data_length != OV2722_8BIT && data_length != OV2722_16BIT
- && data_length != OV2722_32BIT) {
+ if (data_length != OV2722_8BIT && data_length != OV2722_16BIT &&
+ data_length != OV2722_32BIT) {
dev_err(&client->dev, "%s error, invalid data length\n",
__func__);
return -EINVAL;
@@ -212,8 +212,8 @@ static int __ov2722_buf_reg_array(struct i2c_client *client,
}
static int __ov2722_write_reg_is_consecutive(struct i2c_client *client,
- struct ov2722_write_ctrl *ctrl,
- const struct ov2722_reg *next)
+ struct ov2722_write_ctrl *ctrl,
+ const struct ov2722_reg *next)
{
if (ctrl->index == 0)
return 1;
@@ -774,11 +774,11 @@ static int ov2722_s_power(struct v4l2_subdev *sd, int on)
if (on == 0)
return power_down(sd);
- else {
- ret = power_up(sd);
- if (!ret)
- return ov2722_init(sd);
- }
+
+ ret = power_up(sd);
+ if (!ret)
+ return ov2722_init(sd);
+
return ret;
}
@@ -876,7 +876,7 @@ static int startup(struct v4l2_subdev *sd)
}
static int ov2722_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -906,7 +906,7 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd,
}
fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *fmt;
+ sd_state->pads->try_fmt = *fmt;
mutex_unlock(&dev->input_lock);
return 0;
}
@@ -961,7 +961,7 @@ err:
}
static int ov2722_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -1104,7 +1104,7 @@ static int ov2722_g_frame_interval(struct v4l2_subdev *sd,
}
static int ov2722_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= MAX_FMTS)
@@ -1115,7 +1115,7 @@ static int ov2722_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov2722_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
int index = fse->index;
diff --git a/drivers/staging/media/atomisp/i2c/mt9m114.h b/drivers/staging/media/atomisp/i2c/mt9m114.h
index 787bbf59e895..bcce18b65fa6 100644
--- a/drivers/staging/media/atomisp/i2c/mt9m114.h
+++ b/drivers/staging/media/atomisp/i2c/mt9m114.h
@@ -764,8 +764,10 @@ static struct misensor_reg const mt9m114_common[] = {
{MISENSOR_8BIT, 0xC85C, 0x03}, /* cam_crop_cropmode = 3 */
{MISENSOR_16BIT, 0xC868, 0x0280}, /* cam_output_width = 952 */
{MISENSOR_16BIT, 0xC86A, 0x01E0}, /* cam_output_height = 538 */
- /* LOAD = Step3-Recommended
- * Patch,Errata and Sensor optimization Setting */
+ /*
+ * LOAD = Step3-Recommended
+ * Patch, Errata and Sensor optimization Setting
+ */
{MISENSOR_16BIT, 0x316A, 0x8270}, /* DAC_TXLO_ROW */
{MISENSOR_16BIT, 0x316C, 0x8270}, /* DAC_TXLO */
{MISENSOR_16BIT, 0x3ED0, 0x2305}, /* DAC_LD_4_5 */
diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h
index 49920245e064..4d43b45915e5 100644
--- a/drivers/staging/media/atomisp/i2c/ov2680.h
+++ b/drivers/staging/media/atomisp/i2c/ov2680.h
@@ -459,8 +459,8 @@ static struct ov2680_reg const ov2680_656x496_30fps[] = {
};
/*
-* 800x600 30fps VBlanking 1lane 10Bit (binning)
-*/
+ * 800x600 30fps VBlanking 1lane 10Bit (binning)
+ */
static struct ov2680_reg const ov2680_720x592_30fps[] = {
{0x3086, 0x01},
{0x3501, 0x26},
@@ -504,8 +504,8 @@ static struct ov2680_reg const ov2680_720x592_30fps[] = {
};
/*
-* 800x600 30fps VBlanking 1lane 10Bit (binning)
-*/
+ * 800x600 30fps VBlanking 1lane 10Bit (binning)
+ */
static struct ov2680_reg const ov2680_800x600_30fps[] = {
{0x3086, 0x01},
{0x3501, 0x26},
@@ -634,7 +634,7 @@ static struct ov2680_reg const ov2680_1296x976_30fps[] = {
/*
* 1456*1096 30fps VBlanking 1lane 10bit(no-scaling)
-*/
+ */
static struct ov2680_reg const ov2680_1456x1096_30fps[] = {
{0x3086, 0x00},
{0x3501, 0x48},
diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
index e698b63d6cb7..0828ca9ab6f2 100644
--- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
+++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
@@ -1577,7 +1577,7 @@ static int startup(struct v4l2_subdev *sd)
}
static int ov5693_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -1608,7 +1608,7 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd,
fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *fmt;
+ sd_state->pads->try_fmt = *fmt;
mutex_unlock(&dev->input_lock);
return 0;
}
@@ -1676,7 +1676,7 @@ err:
}
static int ov5693_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -1825,7 +1825,7 @@ static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
}
static int ov5693_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= MAX_FMTS)
@@ -1836,7 +1836,7 @@ static int ov5693_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ov5693_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
int index = fse->index;
diff --git a/drivers/staging/media/atomisp/pci/atomisp_acc.c b/drivers/staging/media/atomisp/pci/atomisp_acc.c
index f638d0bd09fe..9a1751895ab0 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_acc.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_acc.c
@@ -77,8 +77,8 @@ acc_get_fw(struct atomisp_sub_device *asd, unsigned int handle)
struct atomisp_acc_fw *acc_fw;
list_for_each_entry(acc_fw, &asd->acc.fw, list)
- if (acc_fw->handle == handle)
- return acc_fw;
+ if (acc_fw->handle == handle)
+ return acc_fw;
return NULL;
}
@@ -464,9 +464,11 @@ int atomisp_acc_load_extensions(struct atomisp_sub_device *asd)
continue;
for (i = 0; i < ARRAY_SIZE(acc_flag_to_pipe); i++) {
- /* QoS (ACC pipe) acceleration stages are currently
- * allowed only in continuous mode. Skip them for
- * all other modes. */
+ /*
+ * QoS (ACC pipe) acceleration stages are
+ * currently allowed only in continuous mode.
+ * Skip them for all other modes.
+ */
if (!continuous &&
acc_flag_to_pipe[i].flag ==
ATOMISP_ACC_FW_LOAD_FL_ACC)
diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
index 14abc1ca00e8..366161cff560 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
@@ -1138,9 +1138,10 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
asd->frame_status[vb->i] =
ATOMISP_FRAME_STATUS_OK;
}
- } else
+ } else {
asd->frame_status[vb->i] =
ATOMISP_FRAME_STATUS_OK;
+ }
} else {
asd->frame_status[vb->i] = ATOMISP_FRAME_STATUS_OK;
}
@@ -4841,6 +4842,9 @@ int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f,
struct atomisp_device *isp = video_get_drvdata(vdev);
struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd;
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = {
+ .pads = &pad_cfg
+ };
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -4876,7 +4880,7 @@ int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f,
snr_mbus_fmt->width, snr_mbus_fmt->height);
ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
- pad, set_fmt, &pad_cfg, &format);
+ pad, set_fmt, &pad_state, &format);
if (ret)
return ret;
@@ -4941,9 +4945,9 @@ atomisp_try_fmt_file(struct atomisp_device *isp, struct v4l2_format *f)
depth = get_pixel_depth(pixelformat);
- if (field == V4L2_FIELD_ANY)
+ if (field == V4L2_FIELD_ANY) {
field = V4L2_FIELD_NONE;
- else if (field != V4L2_FIELD_NONE) {
+ } else if (field != V4L2_FIELD_NONE) {
dev_err(isp->dev, "Wrong output field\n");
return -EINVAL;
}
@@ -5251,11 +5255,11 @@ static int atomisp_set_fmt_to_isp(struct video_device *vdev,
atomisp_output_fmts[] in atomisp_v4l2.c */
vf_ffmt.code = V4L2_MBUS_FMT_CUSTOM_YUV420;
- atomisp_subdev_set_selection(&asd->subdev, fh.pad,
+ atomisp_subdev_set_selection(&asd->subdev, fh.state,
V4L2_SUBDEV_FORMAT_ACTIVE,
ATOMISP_SUBDEV_PAD_SOURCE_VF,
V4L2_SEL_TGT_COMPOSE, 0, &vf_size);
- atomisp_subdev_set_ffmt(&asd->subdev, fh.pad,
+ atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
V4L2_SUBDEV_FORMAT_ACTIVE,
ATOMISP_SUBDEV_PAD_SOURCE_VF, &vf_ffmt);
asd->video_out_vf.sh_fmt = IA_CSS_FRAME_FORMAT_NV12;
@@ -5492,6 +5496,9 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev,
struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd;
const struct atomisp_format_bridge *format;
struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = {
+ .pads = &pad_cfg
+ };
struct v4l2_subdev_format vformat = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -5530,7 +5537,7 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev,
source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO) {
vformat.which = V4L2_SUBDEV_FORMAT_TRY;
ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
- pad, set_fmt, &pad_cfg, &vformat);
+ pad, set_fmt, &pad_state, &vformat);
if (ret)
return ret;
if (ffmt->width < req_ffmt->width ||
@@ -5568,7 +5575,7 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev,
asd->params.video_dis_en = false;
}
- atomisp_subdev_set_ffmt(&asd->subdev, fh.pad,
+ atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
V4L2_SUBDEV_FORMAT_ACTIVE,
ATOMISP_SUBDEV_PAD_SINK, ffmt);
@@ -5647,7 +5654,7 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
}
atomisp_subdev_set_selection(
- &asd->subdev, fh.pad,
+ &asd->subdev, fh.state,
V4L2_SUBDEV_FORMAT_ACTIVE, source_pad,
V4L2_SEL_TGT_COMPOSE, 0, &r);
@@ -5777,7 +5784,7 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
ATOMISP_SUBDEV_PAD_SINK);
isp_source_fmt.code = format_bridge->mbus_code;
- atomisp_subdev_set_ffmt(&asd->subdev, fh.pad,
+ atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
V4L2_SUBDEV_FORMAT_ACTIVE,
source_pad, &isp_source_fmt);
@@ -5896,13 +5903,13 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
isp_sink_crop.height = f->fmt.pix.height;
}
- atomisp_subdev_set_selection(&asd->subdev, fh.pad,
+ atomisp_subdev_set_selection(&asd->subdev, fh.state,
V4L2_SUBDEV_FORMAT_ACTIVE,
ATOMISP_SUBDEV_PAD_SINK,
V4L2_SEL_TGT_CROP,
V4L2_SEL_FLAG_KEEP_CONFIG,
&isp_sink_crop);
- atomisp_subdev_set_selection(&asd->subdev, fh.pad,
+ atomisp_subdev_set_selection(&asd->subdev, fh.state,
V4L2_SUBDEV_FORMAT_ACTIVE,
source_pad, V4L2_SEL_TGT_COMPOSE,
0, &isp_sink_crop);
@@ -5921,7 +5928,7 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
f->fmt.pix.height);
}
- atomisp_subdev_set_selection(&asd->subdev, fh.pad,
+ atomisp_subdev_set_selection(&asd->subdev, fh.state,
V4L2_SUBDEV_FORMAT_ACTIVE,
source_pad,
V4L2_SEL_TGT_COMPOSE, 0,
@@ -5955,14 +5962,14 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
f->fmt.pix.width,
ATOM_ISP_STEP_HEIGHT);
}
- atomisp_subdev_set_selection(&asd->subdev, fh.pad,
+ atomisp_subdev_set_selection(&asd->subdev, fh.state,
V4L2_SUBDEV_FORMAT_ACTIVE,
ATOMISP_SUBDEV_PAD_SINK,
V4L2_SEL_TGT_CROP,
V4L2_SEL_FLAG_KEEP_CONFIG,
&sink_crop);
}
- atomisp_subdev_set_selection(&asd->subdev, fh.pad,
+ atomisp_subdev_set_selection(&asd->subdev, fh.state,
V4L2_SUBDEV_FORMAT_ACTIVE,
source_pad,
V4L2_SEL_TGT_COMPOSE, 0,
@@ -6053,7 +6060,8 @@ int atomisp_set_fmt_file(struct video_device *vdev, struct v4l2_format *f)
ffmt.height = f->fmt.pix.height;
ffmt.code = format_bridge->mbus_code;
- atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, V4L2_SUBDEV_FORMAT_ACTIVE,
+ atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
+ V4L2_SUBDEV_FORMAT_ACTIVE,
ATOMISP_SUBDEV_PAD_SINK, &ffmt);
return 0;
@@ -6564,17 +6572,17 @@ static int atomisp_get_pipe_id(struct atomisp_video_pipe *pipe)
{
struct atomisp_sub_device *asd = pipe->asd;
- if (ATOMISP_USE_YUVPP(asd))
+ if (ATOMISP_USE_YUVPP(asd)) {
return IA_CSS_PIPE_ID_YUVPP;
- else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER)
+ } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
return IA_CSS_PIPE_ID_VIDEO;
- else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT)
+ } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
return IA_CSS_PIPE_ID_CAPTURE;
- else if (pipe == &asd->video_out_video_capture)
+ } else if (pipe == &asd->video_out_video_capture) {
return IA_CSS_PIPE_ID_VIDEO;
- else if (pipe == &asd->video_out_vf)
+ } else if (pipe == &asd->video_out_vf) {
return IA_CSS_PIPE_ID_CAPTURE;
- else if (pipe == &asd->video_out_preview) {
+ } else if (pipe == &asd->video_out_preview) {
if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)
return IA_CSS_PIPE_ID_VIDEO;
else
diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp_cmd.h
index 412baeb91944..e8bdd264d31b 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_cmd.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.h
@@ -49,9 +49,7 @@ struct ia_css_frame;
/* FIXME: check if can go */
extern int atomisp_punit_hpll_freq;
-/*
- * Helper function
- */
+/* Helper function */
void dump_sp_dmem(struct atomisp_device *isp, unsigned int addr,
unsigned int size);
struct camera_mipi_info *atomisp_to_sensor_mipi_info(struct v4l2_subdev *sd);
@@ -65,9 +63,7 @@ bool atomisp_buffers_queued(struct atomisp_sub_device *asd);
/* ISP2401 */
bool atomisp_buffers_queued_pipe(struct atomisp_video_pipe *pipe);
-/*
- * Interrupt functions
- */
+/* Interrupt functions */
void atomisp_msi_irq_init(struct atomisp_device *isp);
void atomisp_msi_irq_uninit(struct atomisp_device *isp);
void atomisp_wdt_work(struct work_struct *work);
@@ -82,15 +78,10 @@ int atomisp_get_frame_pgnr(struct atomisp_device *isp,
const struct ia_css_frame *frame, u32 *p_pgnr);
void atomisp_delayed_init_work(struct work_struct *work);
-/*
- * Get internal fmt according to V4L2 fmt
- */
-
+/* Get internal fmt according to V4L2 fmt */
bool atomisp_is_viewfinder_support(struct atomisp_device *isp);
-/*
- * ISP features control function
- */
+/* ISP features control function */
/*
* Function to set sensor runmode by user when
@@ -105,9 +96,7 @@ int atomisp_set_sensor_runmode(struct atomisp_sub_device *asd,
int atomisp_gdc_cac(struct atomisp_sub_device *asd, int flag,
__s32 *value);
-/*
- * Function to enable/disable low light mode (including ANR)
- */
+/* Function to enable/disable low light mode (including ANR) */
int atomisp_low_light(struct atomisp_sub_device *asd, int flag,
__s32 *value);
@@ -120,91 +109,63 @@ int atomisp_xnr(struct atomisp_sub_device *asd, int flag, int *arg);
int atomisp_formats(struct atomisp_sub_device *asd, int flag,
struct atomisp_formats_config *config);
-/*
- * Function to configure noise reduction
- */
+/* Function to configure noise reduction */
int atomisp_nr(struct atomisp_sub_device *asd, int flag,
struct atomisp_nr_config *config);
-/*
- * Function to configure temporal noise reduction (TNR)
- */
+/* Function to configure temporal noise reduction (TNR) */
int atomisp_tnr(struct atomisp_sub_device *asd, int flag,
struct atomisp_tnr_config *config);
-/*
- * Function to configure black level compensation
- */
+/* Function to configure black level compensation */
int atomisp_black_level(struct atomisp_sub_device *asd, int flag,
struct atomisp_ob_config *config);
-/*
- * Function to configure edge enhancement
- */
+/* Function to configure edge enhancement */
int atomisp_ee(struct atomisp_sub_device *asd, int flag,
struct atomisp_ee_config *config);
-/*
- * Function to update Gamma table for gamma, brightness and contrast config
- */
+/* Function to update Gamma table for gamma, brightness and contrast config */
int atomisp_gamma(struct atomisp_sub_device *asd, int flag,
struct atomisp_gamma_table *config);
-/*
- * Function to update Ctc table for Chroma Enhancement
- */
+
+/* Function to update Ctc table for Chroma Enhancement */
int atomisp_ctc(struct atomisp_sub_device *asd, int flag,
struct atomisp_ctc_table *config);
-/*
- * Function to update gamma correction parameters
- */
+/* Function to update gamma correction parameters */
int atomisp_gamma_correction(struct atomisp_sub_device *asd, int flag,
struct atomisp_gc_config *config);
-/*
- * Function to update Gdc table for gdc
- */
+/* Function to update Gdc table for gdc */
int atomisp_gdc_cac_table(struct atomisp_sub_device *asd, int flag,
struct atomisp_morph_table *config);
-/*
- * Function to update table for macc
- */
+/* Function to update table for macc */
int atomisp_macc_table(struct atomisp_sub_device *asd, int flag,
struct atomisp_macc_config *config);
-/*
- * Function to get DIS statistics.
- */
+
+/* Function to get DIS statistics. */
int atomisp_get_dis_stat(struct atomisp_sub_device *asd,
struct atomisp_dis_statistics *stats);
-/*
- * Function to get DVS2 BQ resolution settings
- */
+/* Function to get DVS2 BQ resolution settings */
int atomisp_get_dvs2_bq_resolutions(struct atomisp_sub_device *asd,
struct atomisp_dvs2_bq_resolutions *bq_res);
-/*
- * Function to set the DIS coefficients.
- */
+/* Function to set the DIS coefficients. */
int atomisp_set_dis_coefs(struct atomisp_sub_device *asd,
struct atomisp_dis_coefficients *coefs);
-/*
- * Function to set the DIS motion vector.
- */
+/* Function to set the DIS motion vector. */
int atomisp_set_dis_vector(struct atomisp_sub_device *asd,
struct atomisp_dis_vector *vector);
-/*
- * Function to set/get 3A stat from isp
- */
+/* Function to set/get 3A stat from isp */
int atomisp_3a_stat(struct atomisp_sub_device *asd, int flag,
struct atomisp_3a_statistics *config);
-/*
- * Function to get metadata from isp
- */
+/* Function to get metadata from isp */
int atomisp_get_metadata(struct atomisp_sub_device *asd, int flag,
struct atomisp_metadata *config);
@@ -213,84 +174,59 @@ int atomisp_get_metadata_by_type(struct atomisp_sub_device *asd, int flag,
int atomisp_set_parameters(struct video_device *vdev,
struct atomisp_parameters *arg);
-/*
- * Function to set/get isp parameters to isp
- */
+
+/* Function to set/get isp parameters to isp */
int atomisp_param(struct atomisp_sub_device *asd, int flag,
struct atomisp_parm *config);
-/*
- * Function to configure color effect of the image
- */
+/* Function to configure color effect of the image */
int atomisp_color_effect(struct atomisp_sub_device *asd, int flag,
__s32 *effect);
-/*
- * Function to configure bad pixel correction
- */
+/* Function to configure bad pixel correction */
int atomisp_bad_pixel(struct atomisp_sub_device *asd, int flag,
__s32 *value);
-/*
- * Function to configure bad pixel correction params
- */
+/* Function to configure bad pixel correction params */
int atomisp_bad_pixel_param(struct atomisp_sub_device *asd, int flag,
struct atomisp_dp_config *config);
-/*
- * Function to enable/disable video image stablization
- */
+/* Function to enable/disable video image stablization */
int atomisp_video_stable(struct atomisp_sub_device *asd, int flag,
__s32 *value);
-/*
- * Function to configure fixed pattern noise
- */
+/* Function to configure fixed pattern noise */
int atomisp_fixed_pattern(struct atomisp_sub_device *asd, int flag,
__s32 *value);
-/*
- * Function to configure fixed pattern noise table
- */
+/* Function to configure fixed pattern noise table */
int atomisp_fixed_pattern_table(struct atomisp_sub_device *asd,
struct v4l2_framebuffer *config);
-/*
- * Function to configure false color correction
- */
+/* Function to configure false color correction */
int atomisp_false_color(struct atomisp_sub_device *asd, int flag,
__s32 *value);
-/*
- * Function to configure false color correction params
- */
+/* Function to configure false color correction params */
int atomisp_false_color_param(struct atomisp_sub_device *asd, int flag,
struct atomisp_de_config *config);
-/*
- * Function to configure white balance params
- */
+/* Function to configure white balance params */
int atomisp_white_balance_param(struct atomisp_sub_device *asd, int flag,
struct atomisp_wb_config *config);
int atomisp_3a_config_param(struct atomisp_sub_device *asd, int flag,
struct atomisp_3a_config *config);
-/*
- * Function to setup digital zoom
- */
+/* Function to setup digital zoom */
int atomisp_digital_zoom(struct atomisp_sub_device *asd, int flag,
__s32 *value);
-/*
- * Function set camera_prefiles.xml current sensor pixel array size
- */
+/* Function set camera_prefiles.xml current sensor pixel array size */
int atomisp_set_array_res(struct atomisp_sub_device *asd,
struct atomisp_resolution *config);
-/*
- * Function to calculate real zoom region for every pipe
- */
+/* Function to calculate real zoom region for every pipe */
int atomisp_calculate_real_zoom_region(struct atomisp_sub_device *asd,
struct ia_css_dz_config *dz_config,
enum ia_css_pipe_id css_pipe_id);
@@ -371,9 +307,7 @@ void atomisp_css_flush(struct atomisp_device *isp);
int atomisp_source_pad_to_stream_id(struct atomisp_sub_device *asd,
uint16_t source_pad);
-/*
- * Events. Only one event has to be exported for now.
- */
+/* Events. Only one event has to be exported for now. */
void atomisp_eof_event(struct atomisp_sub_device *asd, uint8_t exp_id);
enum mipi_port_id __get_mipi_port(struct atomisp_device *isp,
@@ -389,34 +323,25 @@ void atomisp_free_css_parameters(struct atomisp_css_params *css_param);
void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe);
void atomisp_flush_params_queue(struct atomisp_video_pipe *asd);
-/*
- * Function to do Raw Buffer related operation, after enable Lock Unlock Raw Buffer
- */
+
+/* Function to do Raw Buffer related operation, after enable Lock Unlock Raw Buffer */
int atomisp_exp_id_unlock(struct atomisp_sub_device *asd, int *exp_id);
int atomisp_exp_id_capture(struct atomisp_sub_device *asd, int *exp_id);
-/*
- * Function to update Raw Buffer bitmap
- */
+/* Function to update Raw Buffer bitmap */
int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id);
void atomisp_init_raw_buffer_bitmap(struct atomisp_sub_device *asd);
-/*
- * Function to enable/disable zoom for capture pipe
- */
+/* Function to enable/disable zoom for capture pipe */
int atomisp_enable_dz_capt_pipe(struct atomisp_sub_device *asd,
unsigned int *enable);
-/*
- * Function to get metadata type bu pipe id
- */
+/* Function to get metadata type bu pipe id */
enum atomisp_metadata_type
atomisp_get_metadata_type(struct atomisp_sub_device *asd,
enum ia_css_pipe_id pipe_id);
-/*
- * Function for HAL to inject a fake event to wake up poll thread
- */
+/* Function for HAL to inject a fake event to wake up poll thread */
int atomisp_inject_a_fake_event(struct atomisp_sub_device *asd, int *event);
/*
diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c
index ce3165291eec..f60198bb8a1a 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c
@@ -2782,9 +2782,9 @@ int atomisp_get_css_frame_info(struct atomisp_sub_device *asd,
int stream_index;
struct atomisp_device *isp = asd->isp;
- if (ATOMISP_SOC_CAMERA(asd))
+ if (ATOMISP_SOC_CAMERA(asd)) {
stream_index = atomisp_source_pad_to_stream_id(asd, source_pad);
- else {
+ } else {
stream_index = (pipe_index == IA_CSS_PIPE_ID_YUVPP) ?
ATOMISP_INPUT_STREAM_VIDEO :
atomisp_source_pad_to_stream_id(asd, source_pad);
diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.c b/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.c
deleted file mode 100644
index e5553df5bad4..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.c
+++ /dev/null
@@ -1,1202 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- *
- * Copyright (c) 2013 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
- */
-#ifdef CONFIG_COMPAT
-#include <linux/compat.h>
-
-#include <linux/videodev2.h>
-
-#include "atomisp_internal.h"
-#include "atomisp_compat.h"
-#include "atomisp_ioctl.h"
-#include "atomisp_compat_ioctl32.h"
-
-/* Macros borrowed from v4l2-compat-ioctl32.c */
-
-#define get_user_cast(__x, __ptr) \
-({ \
- get_user(__x, (typeof(*__ptr) __user *)(__ptr)); \
-})
-
-#define put_user_force(__x, __ptr) \
-({ \
- put_user((typeof(*__x) __force *)(__x), __ptr); \
-})
-
-/* Use the same argument order as copy_in_user */
-#define assign_in_user(to, from) \
-({ \
- typeof(*from) __assign_tmp; \
- \
- get_user_cast(__assign_tmp, from) || put_user(__assign_tmp, to);\
-})
-
-static int get_atomisp_histogram32(struct atomisp_histogram __user *kp,
- struct atomisp_histogram32 __user *up)
-{
- compat_uptr_t tmp;
-
- if (!access_ok(up, sizeof(struct atomisp_histogram32)) ||
- assign_in_user(&kp->num_elements, &up->num_elements) ||
- get_user(tmp, &up->data) ||
- put_user(compat_ptr(tmp), &kp->data))
- return -EFAULT;
-
- return 0;
-}
-
-static int put_atomisp_histogram32(struct atomisp_histogram __user *kp,
- struct atomisp_histogram32 __user *up)
-{
- void __user *tmp;
-
- if (!access_ok(up, sizeof(struct atomisp_histogram32)) ||
- assign_in_user(&up->num_elements, &kp->num_elements) ||
- get_user(tmp, &kp->data) ||
- put_user(ptr_to_compat(tmp), &up->data))
- return -EFAULT;
-
- return 0;
-}
-
-static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
- struct v4l2_framebuffer32 __user *up)
-{
- compat_uptr_t tmp;
-
- if (!access_ok(up, sizeof(struct v4l2_framebuffer32)) ||
- get_user(tmp, &up->base) ||
- put_user_force(compat_ptr(tmp), &kp->base) ||
- assign_in_user(&kp->capability, &up->capability) ||
- assign_in_user(&kp->flags, &up->flags) ||
- copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt)))
- return -EFAULT;
-
- return 0;
-}
-
-static int get_atomisp_dis_statistics32(struct atomisp_dis_statistics __user *kp,
- struct atomisp_dis_statistics32 __user *up)
-{
- compat_uptr_t hor_prod_odd_real;
- compat_uptr_t hor_prod_odd_imag;
- compat_uptr_t hor_prod_even_real;
- compat_uptr_t hor_prod_even_imag;
- compat_uptr_t ver_prod_odd_real;
- compat_uptr_t ver_prod_odd_imag;
- compat_uptr_t ver_prod_even_real;
- compat_uptr_t ver_prod_even_imag;
-
- if (!access_ok(up, sizeof(struct atomisp_dis_statistics32)) ||
- copy_in_user(kp, up, sizeof(struct atomisp_dvs_grid_info)) ||
- get_user(hor_prod_odd_real,
- &up->dvs2_stat.hor_prod.odd_real) ||
- get_user(hor_prod_odd_imag,
- &up->dvs2_stat.hor_prod.odd_imag) ||
- get_user(hor_prod_even_real,
- &up->dvs2_stat.hor_prod.even_real) ||
- get_user(hor_prod_even_imag,
- &up->dvs2_stat.hor_prod.even_imag) ||
- get_user(ver_prod_odd_real,
- &up->dvs2_stat.ver_prod.odd_real) ||
- get_user(ver_prod_odd_imag,
- &up->dvs2_stat.ver_prod.odd_imag) ||
- get_user(ver_prod_even_real,
- &up->dvs2_stat.ver_prod.even_real) ||
- get_user(ver_prod_even_imag,
- &up->dvs2_stat.ver_prod.even_imag) ||
- assign_in_user(&kp->exp_id, &up->exp_id) ||
- put_user(compat_ptr(hor_prod_odd_real),
- &kp->dvs2_stat.hor_prod.odd_real) ||
- put_user(compat_ptr(hor_prod_odd_imag),
- &kp->dvs2_stat.hor_prod.odd_imag) ||
- put_user(compat_ptr(hor_prod_even_real),
- &kp->dvs2_stat.hor_prod.even_real) ||
- put_user(compat_ptr(hor_prod_even_imag),
- &kp->dvs2_stat.hor_prod.even_imag) ||
- put_user(compat_ptr(ver_prod_odd_real),
- &kp->dvs2_stat.ver_prod.odd_real) ||
- put_user(compat_ptr(ver_prod_odd_imag),
- &kp->dvs2_stat.ver_prod.odd_imag) ||
- put_user(compat_ptr(ver_prod_even_real),
- &kp->dvs2_stat.ver_prod.even_real) ||
- put_user(compat_ptr(ver_prod_even_imag),
- &kp->dvs2_stat.ver_prod.even_imag))
- return -EFAULT;
-
- return 0;
-}
-
-static int put_atomisp_dis_statistics32(struct atomisp_dis_statistics __user *kp,
- struct atomisp_dis_statistics32 __user *up)
-{
- void __user *hor_prod_odd_real;
- void __user *hor_prod_odd_imag;
- void __user *hor_prod_even_real;
- void __user *hor_prod_even_imag;
- void __user *ver_prod_odd_real;
- void __user *ver_prod_odd_imag;
- void __user *ver_prod_even_real;
- void __user *ver_prod_even_imag;
-
- if (!!access_ok(up, sizeof(struct atomisp_dis_statistics32)) ||
- copy_in_user(up, kp, sizeof(struct atomisp_dvs_grid_info)) ||
- get_user(hor_prod_odd_real,
- &kp->dvs2_stat.hor_prod.odd_real) ||
- get_user(hor_prod_odd_imag,
- &kp->dvs2_stat.hor_prod.odd_imag) ||
- get_user(hor_prod_even_real,
- &kp->dvs2_stat.hor_prod.even_real) ||
- get_user(hor_prod_even_imag,
- &kp->dvs2_stat.hor_prod.even_imag) ||
- get_user(ver_prod_odd_real,
- &kp->dvs2_stat.ver_prod.odd_real) ||
- get_user(ver_prod_odd_imag,
- &kp->dvs2_stat.ver_prod.odd_imag) ||
- get_user(ver_prod_even_real,
- &kp->dvs2_stat.ver_prod.even_real) ||
- get_user(ver_prod_even_imag,
- &kp->dvs2_stat.ver_prod.even_imag) ||
- put_user(ptr_to_compat(hor_prod_odd_real),
- &up->dvs2_stat.hor_prod.odd_real) ||
- put_user(ptr_to_compat(hor_prod_odd_imag),
- &up->dvs2_stat.hor_prod.odd_imag) ||
- put_user(ptr_to_compat(hor_prod_even_real),
- &up->dvs2_stat.hor_prod.even_real) ||
- put_user(ptr_to_compat(hor_prod_even_imag),
- &up->dvs2_stat.hor_prod.even_imag) ||
- put_user(ptr_to_compat(ver_prod_odd_real),
- &up->dvs2_stat.ver_prod.odd_real) ||
- put_user(ptr_to_compat(ver_prod_odd_imag),
- &up->dvs2_stat.ver_prod.odd_imag) ||
- put_user(ptr_to_compat(ver_prod_even_real),
- &up->dvs2_stat.ver_prod.even_real) ||
- put_user(ptr_to_compat(ver_prod_even_imag),
- &up->dvs2_stat.ver_prod.even_imag) ||
- assign_in_user(&up->exp_id, &kp->exp_id))
- return -EFAULT;
-
- return 0;
-}
-
-static int get_atomisp_dis_coefficients32(struct atomisp_dis_coefficients __user *kp,
- struct atomisp_dis_coefficients32 __user *up)
-{
- compat_uptr_t hor_coefs_odd_real;
- compat_uptr_t hor_coefs_odd_imag;
- compat_uptr_t hor_coefs_even_real;
- compat_uptr_t hor_coefs_even_imag;
- compat_uptr_t ver_coefs_odd_real;
- compat_uptr_t ver_coefs_odd_imag;
- compat_uptr_t ver_coefs_even_real;
- compat_uptr_t ver_coefs_even_imag;
-
- if (!access_ok(up, sizeof(struct atomisp_dis_coefficients32)) ||
- copy_in_user(kp, up, sizeof(struct atomisp_dvs_grid_info)) ||
- get_user(hor_coefs_odd_real, &up->hor_coefs.odd_real) ||
- get_user(hor_coefs_odd_imag, &up->hor_coefs.odd_imag) ||
- get_user(hor_coefs_even_real, &up->hor_coefs.even_real) ||
- get_user(hor_coefs_even_imag, &up->hor_coefs.even_imag) ||
- get_user(ver_coefs_odd_real, &up->ver_coefs.odd_real) ||
- get_user(ver_coefs_odd_imag, &up->ver_coefs.odd_imag) ||
- get_user(ver_coefs_even_real, &up->ver_coefs.even_real) ||
- get_user(ver_coefs_even_imag, &up->ver_coefs.even_imag) ||
- put_user(compat_ptr(hor_coefs_odd_real),
- &kp->hor_coefs.odd_real) ||
- put_user(compat_ptr(hor_coefs_odd_imag),
- &kp->hor_coefs.odd_imag) ||
- put_user(compat_ptr(hor_coefs_even_real),
- &kp->hor_coefs.even_real) ||
- put_user(compat_ptr(hor_coefs_even_imag),
- &kp->hor_coefs.even_imag) ||
- put_user(compat_ptr(ver_coefs_odd_real),
- &kp->ver_coefs.odd_real) ||
- put_user(compat_ptr(ver_coefs_odd_imag),
- &kp->ver_coefs.odd_imag) ||
- put_user(compat_ptr(ver_coefs_even_real),
- &kp->ver_coefs.even_real) ||
- put_user(compat_ptr(ver_coefs_even_imag),
- &kp->ver_coefs.even_imag))
- return -EFAULT;
-
- return 0;
-}
-
-static int get_atomisp_dvs_6axis_config32(struct atomisp_dvs_6axis_config __user *kp,
- struct atomisp_dvs_6axis_config32 __user *up)
-{
- compat_uptr_t xcoords_y;
- compat_uptr_t ycoords_y;
- compat_uptr_t xcoords_uv;
- compat_uptr_t ycoords_uv;
-
- if (!access_ok(up, sizeof(struct atomisp_dvs_6axis_config32)) ||
- assign_in_user(&kp->exp_id, &up->exp_id) ||
- assign_in_user(&kp->width_y, &up->width_y) ||
- assign_in_user(&kp->height_y, &up->height_y) ||
- assign_in_user(&kp->width_uv, &up->width_uv) ||
- assign_in_user(&kp->height_uv, &up->height_uv) ||
- get_user(xcoords_y, &up->xcoords_y) ||
- get_user(ycoords_y, &up->ycoords_y) ||
- get_user(xcoords_uv, &up->xcoords_uv) ||
- get_user(ycoords_uv, &up->ycoords_uv) ||
- put_user_force(compat_ptr(xcoords_y), &kp->xcoords_y) ||
- put_user_force(compat_ptr(ycoords_y), &kp->ycoords_y) ||
- put_user_force(compat_ptr(xcoords_uv), &kp->xcoords_uv) ||
- put_user_force(compat_ptr(ycoords_uv), &kp->ycoords_uv))
- return -EFAULT;
-
- return 0;
-}
-
-static int get_atomisp_3a_statistics32(struct atomisp_3a_statistics __user *kp,
- struct atomisp_3a_statistics32 __user *up)
-{
- compat_uptr_t data;
- compat_uptr_t rgby_data;
-
- if (!access_ok(up, sizeof(struct atomisp_3a_statistics32)) ||
- copy_in_user(kp, up, sizeof(struct atomisp_grid_info)) ||
- get_user(rgby_data, &up->rgby_data) ||
- put_user(compat_ptr(rgby_data), &kp->rgby_data) ||
- get_user(data, &up->data) ||
- put_user(compat_ptr(data), &kp->data) ||
- assign_in_user(&kp->exp_id, &up->exp_id) ||
- assign_in_user(&kp->isp_config_id, &up->isp_config_id))
- return -EFAULT;
-
- return 0;
-}
-
-static int put_atomisp_3a_statistics32(struct atomisp_3a_statistics __user *kp,
- struct atomisp_3a_statistics32 __user *up)
-{
- void __user *data;
- void __user *rgby_data;
-
- if (!access_ok(up, sizeof(struct atomisp_3a_statistics32)) ||
- copy_in_user(up, kp, sizeof(struct atomisp_grid_info)) ||
- get_user(rgby_data, &kp->rgby_data) ||
- put_user(ptr_to_compat(rgby_data), &up->rgby_data) ||
- get_user(data, &kp->data) ||
- put_user(ptr_to_compat(data), &up->data) ||
- assign_in_user(&up->exp_id, &kp->exp_id) ||
- assign_in_user(&up->isp_config_id, &kp->isp_config_id))
- return -EFAULT;
-
- return 0;
-}
-
-static int get_atomisp_metadata_stat32(struct atomisp_metadata __user *kp,
- struct atomisp_metadata32 __user *up)
-{
- compat_uptr_t data;
- compat_uptr_t effective_width;
-
- if (!access_ok(up, sizeof(struct atomisp_metadata32)) ||
- get_user(data, &up->data) ||
- put_user(compat_ptr(data), &kp->data) ||
- assign_in_user(&kp->width, &up->width) ||
- assign_in_user(&kp->height, &up->height) ||
- assign_in_user(&kp->stride, &up->stride) ||
- assign_in_user(&kp->exp_id, &up->exp_id) ||
- get_user(effective_width, &up->effective_width) ||
- put_user_force(compat_ptr(effective_width), &kp->effective_width))
- return -EFAULT;
-
- return 0;
-}
-
-static int put_atomisp_metadata_stat32(struct atomisp_metadata __user *kp,
- struct atomisp_metadata32 __user *up)
-{
- void __user *data;
- void *effective_width;
-
- if (!access_ok(up, sizeof(struct atomisp_metadata32)) ||
- get_user(data, &kp->data) ||
- put_user(ptr_to_compat(data), &up->data) ||
- assign_in_user(&up->width, &kp->width) ||
- assign_in_user(&up->height, &kp->height) ||
- assign_in_user(&up->stride, &kp->stride) ||
- assign_in_user(&up->exp_id, &kp->exp_id) ||
- get_user(effective_width, &kp->effective_width) ||
- put_user(ptr_to_compat((void __user *)effective_width),
- &up->effective_width))
- return -EFAULT;
-
- return 0;
-}
-
-static int
-put_atomisp_metadata_by_type_stat32(struct atomisp_metadata_with_type __user *kp,
- struct atomisp_metadata_with_type32 __user *up)
-{
- void __user *data;
- u32 *effective_width;
-
- if (!access_ok(up, sizeof(struct atomisp_metadata_with_type32)) ||
- get_user(data, &kp->data) ||
- put_user(ptr_to_compat(data), &up->data) ||
- assign_in_user(&up->width, &kp->width) ||
- assign_in_user(&up->height, &kp->height) ||
- assign_in_user(&up->stride, &kp->stride) ||
- assign_in_user(&up->exp_id, &kp->exp_id) ||
- get_user(effective_width, &kp->effective_width) ||
- put_user(ptr_to_compat((void __user *)effective_width),
- &up->effective_width) ||
- assign_in_user(&up->type, &kp->type))
- return -EFAULT;
-
- return 0;
-}
-
-static int
-get_atomisp_metadata_by_type_stat32(struct atomisp_metadata_with_type __user *kp,
- struct atomisp_metadata_with_type32 __user *up)
-{
- compat_uptr_t data;
- compat_uptr_t effective_width;
-
- if (!access_ok(up, sizeof(struct atomisp_metadata_with_type32)) ||
- get_user(data, &up->data) ||
- put_user(compat_ptr(data), &kp->data) ||
- assign_in_user(&kp->width, &up->width) ||
- assign_in_user(&kp->height, &up->height) ||
- assign_in_user(&kp->stride, &up->stride) ||
- assign_in_user(&kp->exp_id, &up->exp_id) ||
- get_user(effective_width, &up->effective_width) ||
- put_user_force(compat_ptr(effective_width), &kp->effective_width) ||
- assign_in_user(&kp->type, &up->type))
- return -EFAULT;
-
- return 0;
-}
-
-static int
-get_atomisp_morph_table32(struct atomisp_morph_table __user *kp,
- struct atomisp_morph_table32 __user *up)
-{
- unsigned int n = ATOMISP_MORPH_TABLE_NUM_PLANES;
-
- if (!access_ok(up, sizeof(struct atomisp_morph_table32)) ||
- assign_in_user(&kp->enabled, &up->enabled) ||
- assign_in_user(&kp->width, &up->width) ||
- assign_in_user(&kp->height, &up->height))
- return -EFAULT;
-
- while (n-- > 0) {
- compat_uptr_t coord_kp;
-
- if (get_user(coord_kp, &up->coordinates_x[n]) ||
- put_user(compat_ptr(coord_kp), &kp->coordinates_x[n]) ||
- get_user(coord_kp, &up->coordinates_y[n]) ||
- put_user(compat_ptr(coord_kp), &kp->coordinates_y[n]))
- return -EFAULT;
- }
- return 0;
-}
-
-static int put_atomisp_morph_table32(struct atomisp_morph_table __user *kp,
- struct atomisp_morph_table32 __user *up)
-{
- unsigned int n = ATOMISP_MORPH_TABLE_NUM_PLANES;
-
- if (!access_ok(up, sizeof(struct atomisp_morph_table32)) ||
- assign_in_user(&up->enabled, &kp->enabled) ||
- assign_in_user(&up->width, &kp->width) ||
- assign_in_user(&up->height, &kp->height))
- return -EFAULT;
-
- while (n-- > 0) {
- void __user *coord_kp;
-
- if (get_user(coord_kp, &kp->coordinates_x[n]) ||
- put_user(ptr_to_compat(coord_kp), &up->coordinates_x[n]) ||
- get_user(coord_kp, &kp->coordinates_y[n]) ||
- put_user(ptr_to_compat(coord_kp), &up->coordinates_y[n]))
- return -EFAULT;
- }
- return 0;
-}
-
-static int get_atomisp_overlay32(struct atomisp_overlay __user *kp,
- struct atomisp_overlay32 __user *up)
-{
- compat_uptr_t frame;
-
- if (!access_ok(up, sizeof(struct atomisp_overlay32)) ||
- get_user(frame, &up->frame) ||
- put_user_force(compat_ptr(frame), &kp->frame) ||
- assign_in_user(&kp->bg_y, &up->bg_y) ||
- assign_in_user(&kp->bg_u, &up->bg_u) ||
- assign_in_user(&kp->bg_v, &up->bg_v) ||
- assign_in_user(&kp->blend_input_perc_y,
- &up->blend_input_perc_y) ||
- assign_in_user(&kp->blend_input_perc_u,
- &up->blend_input_perc_u) ||
- assign_in_user(&kp->blend_input_perc_v,
- &up->blend_input_perc_v) ||
- assign_in_user(&kp->blend_overlay_perc_y,
- &up->blend_overlay_perc_y) ||
- assign_in_user(&kp->blend_overlay_perc_u,
- &up->blend_overlay_perc_u) ||
- assign_in_user(&kp->blend_overlay_perc_v,
- &up->blend_overlay_perc_v) ||
- assign_in_user(&kp->overlay_start_x, &up->overlay_start_x) ||
- assign_in_user(&kp->overlay_start_y, &up->overlay_start_y))
- return -EFAULT;
-
- return 0;
-}
-
-static int put_atomisp_overlay32(struct atomisp_overlay __user *kp,
- struct atomisp_overlay32 __user *up)
-{
- void *frame;
-
- if (!access_ok(up, sizeof(struct atomisp_overlay32)) ||
- get_user(frame, &kp->frame) ||
- put_user(ptr_to_compat((void __user *)frame), &up->frame) ||
- assign_in_user(&up->bg_y, &kp->bg_y) ||
- assign_in_user(&up->bg_u, &kp->bg_u) ||
- assign_in_user(&up->bg_v, &kp->bg_v) ||
- assign_in_user(&up->blend_input_perc_y,
- &kp->blend_input_perc_y) ||
- assign_in_user(&up->blend_input_perc_u,
- &kp->blend_input_perc_u) ||
- assign_in_user(&up->blend_input_perc_v,
- &kp->blend_input_perc_v) ||
- assign_in_user(&up->blend_overlay_perc_y,
- &kp->blend_overlay_perc_y) ||
- assign_in_user(&up->blend_overlay_perc_u,
- &kp->blend_overlay_perc_u) ||
- assign_in_user(&up->blend_overlay_perc_v,
- &kp->blend_overlay_perc_v) ||
- assign_in_user(&up->overlay_start_x, &kp->overlay_start_x) ||
- assign_in_user(&up->overlay_start_y, &kp->overlay_start_y))
- return -EFAULT;
-
- return 0;
-}
-
-static int
-get_atomisp_calibration_group32(struct atomisp_calibration_group __user *kp,
- struct atomisp_calibration_group32 __user *up)
-{
- compat_uptr_t calb_grp_values;
-
- if (!access_ok(up, sizeof(struct atomisp_calibration_group32)) ||
- assign_in_user(&kp->size, &up->size) ||
- assign_in_user(&kp->type, &up->type) ||
- get_user(calb_grp_values, &up->calb_grp_values) ||
- put_user_force(compat_ptr(calb_grp_values), &kp->calb_grp_values))
- return -EFAULT;
-
- return 0;
-}
-
-static int
-put_atomisp_calibration_group32(struct atomisp_calibration_group __user *kp,
- struct atomisp_calibration_group32 __user *up)
-{
- void *calb_grp_values;
-
- if (!access_ok(up, sizeof(struct atomisp_calibration_group32)) ||
- assign_in_user(&up->size, &kp->size) ||
- assign_in_user(&up->type, &kp->type) ||
- get_user(calb_grp_values, &kp->calb_grp_values) ||
- put_user(ptr_to_compat((void __user *)calb_grp_values),
- &up->calb_grp_values))
- return -EFAULT;
-
- return 0;
-}
-
-static int get_atomisp_acc_fw_load32(struct atomisp_acc_fw_load __user *kp,
- struct atomisp_acc_fw_load32 __user *up)
-{
- compat_uptr_t data;
-
- if (!access_ok(up, sizeof(struct atomisp_acc_fw_load32)) ||
- assign_in_user(&kp->size, &up->size) ||
- assign_in_user(&kp->fw_handle, &up->fw_handle) ||
- get_user_cast(data, &up->data) ||
- put_user(compat_ptr(data), &kp->data))
- return -EFAULT;
-
- return 0;
-}
-
-static int put_atomisp_acc_fw_load32(struct atomisp_acc_fw_load __user *kp,
- struct atomisp_acc_fw_load32 __user *up)
-{
- void __user *data;
-
- if (!access_ok(up, sizeof(struct atomisp_acc_fw_load32)) ||
- assign_in_user(&up->size, &kp->size) ||
- assign_in_user(&up->fw_handle, &kp->fw_handle) ||
- get_user(data, &kp->data) ||
- put_user(ptr_to_compat(data), &up->data))
- return -EFAULT;
-
- return 0;
-}
-
-static int get_atomisp_acc_fw_arg32(struct atomisp_acc_fw_arg __user *kp,
- struct atomisp_acc_fw_arg32 __user *up)
-{
- compat_uptr_t value;
-
- if (!access_ok(up, sizeof(struct atomisp_acc_fw_arg32)) ||
- assign_in_user(&kp->fw_handle, &up->fw_handle) ||
- assign_in_user(&kp->index, &up->index) ||
- get_user(value, &up->value) ||
- put_user(compat_ptr(value), &kp->value) ||
- assign_in_user(&kp->size, &up->size))
- return -EFAULT;
-
- return 0;
-}
-
-static int put_atomisp_acc_fw_arg32(struct atomisp_acc_fw_arg __user *kp,
- struct atomisp_acc_fw_arg32 __user *up)
-{
- void __user *value;
-
- if (!access_ok(up, sizeof(struct atomisp_acc_fw_arg32)) ||
- assign_in_user(&up->fw_handle, &kp->fw_handle) ||
- assign_in_user(&up->index, &kp->index) ||
- get_user(value, &kp->value) ||
- put_user(ptr_to_compat(value), &up->value) ||
- assign_in_user(&up->size, &kp->size))
- return -EFAULT;
-
- return 0;
-}
-
-static int get_v4l2_private_int_data32(struct v4l2_private_int_data __user *kp,
- struct v4l2_private_int_data32 __user *up)
-{
- compat_uptr_t data;
-
- if (!access_ok(up, sizeof(struct v4l2_private_int_data32)) ||
- assign_in_user(&kp->size, &up->size) ||
- get_user(data, &up->data) ||
- put_user(compat_ptr(data), &kp->data) ||
- assign_in_user(&kp->reserved[0], &up->reserved[0]) ||
- assign_in_user(&kp->reserved[1], &up->reserved[1]))
- return -EFAULT;
-
- return 0;
-}
-
-static int put_v4l2_private_int_data32(struct v4l2_private_int_data __user *kp,
- struct v4l2_private_int_data32 __user *up)
-{
- void __user *data;
-
- if (!access_ok(up, sizeof(struct v4l2_private_int_data32)) ||
- assign_in_user(&up->size, &kp->size) ||
- get_user(data, &kp->data) ||
- put_user(ptr_to_compat(data), &up->data) ||
- assign_in_user(&up->reserved[0], &kp->reserved[0]) ||
- assign_in_user(&up->reserved[1], &kp->reserved[1]))
- return -EFAULT;
-
- return 0;
-}
-
-static int get_atomisp_shading_table32(struct atomisp_shading_table __user *kp,
- struct atomisp_shading_table32 __user *up)
-{
- unsigned int n = ATOMISP_NUM_SC_COLORS;
-
- if (!access_ok(up, sizeof(struct atomisp_shading_table32)) ||
- assign_in_user(&kp->enable, &up->enable) ||
- assign_in_user(&kp->sensor_width, &up->sensor_width) ||
- assign_in_user(&kp->sensor_height, &up->sensor_height) ||
- assign_in_user(&kp->width, &up->width) ||
- assign_in_user(&kp->height, &up->height) ||
- assign_in_user(&kp->fraction_bits, &up->fraction_bits))
- return -EFAULT;
-
- while (n-- > 0) {
- compat_uptr_t tmp;
-
- if (get_user(tmp, &up->data[n]) ||
- put_user_force(compat_ptr(tmp), &kp->data[n]))
- return -EFAULT;
- }
- return 0;
-}
-
-static int get_atomisp_acc_map32(struct atomisp_acc_map __user *kp,
- struct atomisp_acc_map32 __user *up)
-{
- compat_uptr_t user_ptr;
-
- if (!access_ok(up, sizeof(struct atomisp_acc_map32)) ||
- assign_in_user(&kp->flags, &up->flags) ||
- assign_in_user(&kp->length, &up->length) ||
- get_user(user_ptr, &up->user_ptr) ||
- put_user(compat_ptr(user_ptr), &kp->user_ptr) ||
- assign_in_user(&kp->css_ptr, &up->css_ptr) ||
- assign_in_user(&kp->reserved[0], &up->reserved[0]) ||
- assign_in_user(&kp->reserved[1], &up->reserved[1]) ||
- assign_in_user(&kp->reserved[2], &up->reserved[2]) ||
- assign_in_user(&kp->reserved[3], &up->reserved[3]))
- return -EFAULT;
-
- return 0;
-}
-
-static int put_atomisp_acc_map32(struct atomisp_acc_map __user *kp,
- struct atomisp_acc_map32 __user *up)
-{
- void __user *user_ptr;
-
- if (!access_ok(up, sizeof(struct atomisp_acc_map32)) ||
- assign_in_user(&up->flags, &kp->flags) ||
- assign_in_user(&up->length, &kp->length) ||
- get_user(user_ptr, &kp->user_ptr) ||
- put_user(ptr_to_compat(user_ptr), &up->user_ptr) ||
- assign_in_user(&up->css_ptr, &kp->css_ptr) ||
- assign_in_user(&up->reserved[0], &kp->reserved[0]) ||
- assign_in_user(&up->reserved[1], &kp->reserved[1]) ||
- assign_in_user(&up->reserved[2], &kp->reserved[2]) ||
- assign_in_user(&up->reserved[3], &kp->reserved[3]))
- return -EFAULT;
-
- return 0;
-}
-
-static int
-get_atomisp_acc_s_mapped_arg32(struct atomisp_acc_s_mapped_arg __user *kp,
- struct atomisp_acc_s_mapped_arg32 __user *up)
-{
- if (!access_ok(up, sizeof(struct atomisp_acc_s_mapped_arg32)) ||
- assign_in_user(&kp->fw_handle, &up->fw_handle) ||
- assign_in_user(&kp->memory, &up->memory) ||
- assign_in_user(&kp->length, &up->length) ||
- assign_in_user(&kp->css_ptr, &up->css_ptr))
- return -EFAULT;
-
- return 0;
-}
-
-static int
-put_atomisp_acc_s_mapped_arg32(struct atomisp_acc_s_mapped_arg __user *kp,
- struct atomisp_acc_s_mapped_arg32 __user *up)
-{
- if (!access_ok(up, sizeof(struct atomisp_acc_s_mapped_arg32)) ||
- assign_in_user(&up->fw_handle, &kp->fw_handle) ||
- assign_in_user(&up->memory, &kp->memory) ||
- assign_in_user(&up->length, &kp->length) ||
- assign_in_user(&up->css_ptr, &kp->css_ptr))
- return -EFAULT;
-
- return 0;
-}
-
-static int get_atomisp_parameters32(struct atomisp_parameters __user *kp,
- struct atomisp_parameters32 __user *up)
-{
- int n = offsetof(struct atomisp_parameters32, output_frame) /
- sizeof(compat_uptr_t);
- compat_uptr_t stp, mtp, dcp, dscp;
- struct {
- struct atomisp_shading_table shading_table;
- struct atomisp_morph_table morph_table;
- struct atomisp_dis_coefficients dvs2_coefs;
- struct atomisp_dvs_6axis_config dvs_6axis_config;
- } __user *karg = (void __user *)(kp + 1);
-
- if (!access_ok(up, sizeof(struct atomisp_parameters32)))
- return -EFAULT;
-
- while (n >= 0) {
- compat_uptr_t __user *src = (compat_uptr_t __user *)up + n;
- void * __user *dst = (void * __user *)kp + n;
- compat_uptr_t tmp;
-
- if (get_user_cast(tmp, src) || put_user_force(compat_ptr(tmp), dst))
- return -EFAULT;
- n--;
- }
-
- if (assign_in_user(&kp->isp_config_id, &up->isp_config_id) ||
- assign_in_user(&kp->per_frame_setting, &up->per_frame_setting) ||
- get_user(stp, &up->shading_table) ||
- get_user(mtp, &up->morph_table) ||
- get_user(dcp, &up->dvs2_coefs) ||
- get_user(dscp, &up->dvs_6axis_config))
- return -EFAULT;
-
- /* handle shading table */
- if (stp && (get_atomisp_shading_table32(&karg->shading_table,
- compat_ptr(stp)) ||
- put_user_force(&karg->shading_table, &kp->shading_table)))
- return -EFAULT;
-
- /* handle morph table */
- if (mtp && (get_atomisp_morph_table32(&karg->morph_table,
- compat_ptr(mtp)) ||
- put_user_force(&karg->morph_table, &kp->morph_table)))
- return -EFAULT;
-
- /* handle dvs2 coefficients */
- if (dcp && (get_atomisp_dis_coefficients32(&karg->dvs2_coefs,
- compat_ptr(dcp)) ||
- put_user_force(&karg->dvs2_coefs, &kp->dvs2_coefs)))
- return -EFAULT;
-
- /* handle dvs 6axis configuration */
- if (dscp &&
- (get_atomisp_dvs_6axis_config32(&karg->dvs_6axis_config,
- compat_ptr(dscp)) ||
- put_user_force(&karg->dvs_6axis_config, &kp->dvs_6axis_config)))
- return -EFAULT;
-
- return 0;
-}
-
-static int
-get_atomisp_acc_fw_load_to_pipe32(struct atomisp_acc_fw_load_to_pipe __user *kp,
- struct atomisp_acc_fw_load_to_pipe32 __user *up)
-{
- compat_uptr_t data;
-
- if (!access_ok(up, sizeof(struct atomisp_acc_fw_load_to_pipe32)) ||
- assign_in_user(&kp->flags, &up->flags) ||
- assign_in_user(&kp->fw_handle, &up->fw_handle) ||
- assign_in_user(&kp->size, &up->size) ||
- assign_in_user(&kp->type, &up->type) ||
- assign_in_user(&kp->reserved[0], &up->reserved[0]) ||
- assign_in_user(&kp->reserved[1], &up->reserved[1]) ||
- assign_in_user(&kp->reserved[2], &up->reserved[2]) ||
- get_user(data, &up->data) ||
- put_user(compat_ptr(data), &kp->data))
- return -EFAULT;
-
- return 0;
-}
-
-static int
-put_atomisp_acc_fw_load_to_pipe32(struct atomisp_acc_fw_load_to_pipe __user *kp,
- struct atomisp_acc_fw_load_to_pipe32 __user *up)
-{
- void __user *data;
-
- if (!access_ok(up, sizeof(struct atomisp_acc_fw_load_to_pipe32)) ||
- assign_in_user(&up->flags, &kp->flags) ||
- assign_in_user(&up->fw_handle, &kp->fw_handle) ||
- assign_in_user(&up->size, &kp->size) ||
- assign_in_user(&up->type, &kp->type) ||
- assign_in_user(&up->reserved[0], &kp->reserved[0]) ||
- assign_in_user(&up->reserved[1], &kp->reserved[1]) ||
- assign_in_user(&up->reserved[2], &kp->reserved[2]) ||
- get_user(data, &kp->data) ||
- put_user(ptr_to_compat(data), &up->data))
- return -EFAULT;
-
- return 0;
-}
-
-static int
-get_atomisp_sensor_ae_bracketing_lut(struct atomisp_sensor_ae_bracketing_lut __user *kp,
- struct atomisp_sensor_ae_bracketing_lut32 __user *up)
-{
- compat_uptr_t lut;
-
- if (!access_ok(up, sizeof(struct atomisp_sensor_ae_bracketing_lut32)) ||
- assign_in_user(&kp->lut_size, &up->lut_size) ||
- get_user(lut, &up->lut) ||
- put_user_force(compat_ptr(lut), &kp->lut))
- return -EFAULT;
-
- return 0;
-}
-
-static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- long ret = -ENOIOCTLCMD;
-
- if (file->f_op->unlocked_ioctl)
- ret = file->f_op->unlocked_ioctl(file, cmd, arg);
-
- return ret;
-}
-
-static long atomisp_do_compat_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- union {
- struct atomisp_histogram his;
- struct atomisp_dis_statistics dis_s;
- struct atomisp_dis_coefficients dis_c;
- struct atomisp_dvs_6axis_config dvs_c;
- struct atomisp_3a_statistics s3a_s;
- struct atomisp_morph_table mor_t;
- struct v4l2_framebuffer v4l2_buf;
- struct atomisp_overlay overlay;
- struct atomisp_calibration_group cal_grp;
- struct atomisp_acc_fw_load acc_fw_load;
- struct atomisp_acc_fw_arg acc_fw_arg;
- struct v4l2_private_int_data v4l2_pri_data;
- struct atomisp_shading_table shd_tbl;
- struct atomisp_acc_map acc_map;
- struct atomisp_acc_s_mapped_arg acc_map_arg;
- struct atomisp_parameters param;
- struct atomisp_acc_fw_load_to_pipe acc_fw_to_pipe;
- struct atomisp_metadata md;
- struct atomisp_metadata_with_type md_with_type;
- struct atomisp_sensor_ae_bracketing_lut lut;
- } __user *karg;
- void __user *up = compat_ptr(arg);
- long err = -ENOIOCTLCMD;
-
- karg = compat_alloc_user_space(
- sizeof(*karg) + (cmd == ATOMISP_IOC_S_PARAMETERS32 ?
- sizeof(struct atomisp_shading_table) +
- sizeof(struct atomisp_morph_table) +
- sizeof(struct atomisp_dis_coefficients) +
- sizeof(struct atomisp_dvs_6axis_config) : 0));
- if (!karg)
- return -ENOMEM;
-
- /* First, convert the command. */
- switch (cmd) {
- case ATOMISP_IOC_G_HISTOGRAM32:
- cmd = ATOMISP_IOC_G_HISTOGRAM;
- break;
- case ATOMISP_IOC_S_HISTOGRAM32:
- cmd = ATOMISP_IOC_S_HISTOGRAM;
- break;
- case ATOMISP_IOC_G_DIS_STAT32:
- cmd = ATOMISP_IOC_G_DIS_STAT;
- break;
- case ATOMISP_IOC_S_DIS_COEFS32:
- cmd = ATOMISP_IOC_S_DIS_COEFS;
- break;
- case ATOMISP_IOC_S_DIS_VECTOR32:
- cmd = ATOMISP_IOC_S_DIS_VECTOR;
- break;
- case ATOMISP_IOC_G_3A_STAT32:
- cmd = ATOMISP_IOC_G_3A_STAT;
- break;
- case ATOMISP_IOC_G_ISP_GDC_TAB32:
- cmd = ATOMISP_IOC_G_ISP_GDC_TAB;
- break;
- case ATOMISP_IOC_S_ISP_GDC_TAB32:
- cmd = ATOMISP_IOC_S_ISP_GDC_TAB;
- break;
- case ATOMISP_IOC_S_ISP_FPN_TABLE32:
- cmd = ATOMISP_IOC_S_ISP_FPN_TABLE;
- break;
- case ATOMISP_IOC_G_ISP_OVERLAY32:
- cmd = ATOMISP_IOC_G_ISP_OVERLAY;
- break;
- case ATOMISP_IOC_S_ISP_OVERLAY32:
- cmd = ATOMISP_IOC_S_ISP_OVERLAY;
- break;
- case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP32:
- cmd = ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP;
- break;
- case ATOMISP_IOC_ACC_LOAD32:
- cmd = ATOMISP_IOC_ACC_LOAD;
- break;
- case ATOMISP_IOC_ACC_S_ARG32:
- cmd = ATOMISP_IOC_ACC_S_ARG;
- break;
- case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA32:
- cmd = ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA;
- break;
- case ATOMISP_IOC_S_ISP_SHD_TAB32:
- cmd = ATOMISP_IOC_S_ISP_SHD_TAB;
- break;
- case ATOMISP_IOC_ACC_DESTAB32:
- cmd = ATOMISP_IOC_ACC_DESTAB;
- break;
- case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA32:
- cmd = ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA;
- break;
- case ATOMISP_IOC_ACC_MAP32:
- cmd = ATOMISP_IOC_ACC_MAP;
- break;
- case ATOMISP_IOC_ACC_UNMAP32:
- cmd = ATOMISP_IOC_ACC_UNMAP;
- break;
- case ATOMISP_IOC_ACC_S_MAPPED_ARG32:
- cmd = ATOMISP_IOC_ACC_S_MAPPED_ARG;
- break;
- case ATOMISP_IOC_S_PARAMETERS32:
- cmd = ATOMISP_IOC_S_PARAMETERS;
- break;
- case ATOMISP_IOC_ACC_LOAD_TO_PIPE32:
- cmd = ATOMISP_IOC_ACC_LOAD_TO_PIPE;
- break;
- case ATOMISP_IOC_G_METADATA32:
- cmd = ATOMISP_IOC_G_METADATA;
- break;
- case ATOMISP_IOC_G_METADATA_BY_TYPE32:
- cmd = ATOMISP_IOC_G_METADATA_BY_TYPE;
- break;
- case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_LUT32:
- cmd = ATOMISP_IOC_S_SENSOR_AE_BRACKETING_LUT;
- break;
- }
-
- switch (cmd) {
- case ATOMISP_IOC_G_HISTOGRAM:
- case ATOMISP_IOC_S_HISTOGRAM:
- err = get_atomisp_histogram32(&karg->his, up);
- break;
- case ATOMISP_IOC_G_DIS_STAT:
- err = get_atomisp_dis_statistics32(&karg->dis_s, up);
- break;
- case ATOMISP_IOC_S_DIS_COEFS:
- err = get_atomisp_dis_coefficients32(&karg->dis_c, up);
- break;
- case ATOMISP_IOC_S_DIS_VECTOR:
- err = get_atomisp_dvs_6axis_config32(&karg->dvs_c, up);
- break;
- case ATOMISP_IOC_G_3A_STAT:
- err = get_atomisp_3a_statistics32(&karg->s3a_s, up);
- break;
- case ATOMISP_IOC_G_ISP_GDC_TAB:
- case ATOMISP_IOC_S_ISP_GDC_TAB:
- err = get_atomisp_morph_table32(&karg->mor_t, up);
- break;
- case ATOMISP_IOC_S_ISP_FPN_TABLE:
- err = get_v4l2_framebuffer32(&karg->v4l2_buf, up);
- break;
- case ATOMISP_IOC_G_ISP_OVERLAY:
- case ATOMISP_IOC_S_ISP_OVERLAY:
- err = get_atomisp_overlay32(&karg->overlay, up);
- break;
- case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP:
- err = get_atomisp_calibration_group32(&karg->cal_grp, up);
- break;
- case ATOMISP_IOC_ACC_LOAD:
- err = get_atomisp_acc_fw_load32(&karg->acc_fw_load, up);
- break;
- case ATOMISP_IOC_ACC_S_ARG:
- case ATOMISP_IOC_ACC_DESTAB:
- err = get_atomisp_acc_fw_arg32(&karg->acc_fw_arg, up);
- break;
- case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA:
- case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA:
- err = get_v4l2_private_int_data32(&karg->v4l2_pri_data, up);
- break;
- case ATOMISP_IOC_S_ISP_SHD_TAB:
- err = get_atomisp_shading_table32(&karg->shd_tbl, up);
- break;
- case ATOMISP_IOC_ACC_MAP:
- case ATOMISP_IOC_ACC_UNMAP:
- err = get_atomisp_acc_map32(&karg->acc_map, up);
- break;
- case ATOMISP_IOC_ACC_S_MAPPED_ARG:
- err = get_atomisp_acc_s_mapped_arg32(&karg->acc_map_arg, up);
- break;
- case ATOMISP_IOC_S_PARAMETERS:
- err = get_atomisp_parameters32(&karg->param, up);
- break;
- case ATOMISP_IOC_ACC_LOAD_TO_PIPE:
- err = get_atomisp_acc_fw_load_to_pipe32(&karg->acc_fw_to_pipe,
- up);
- break;
- case ATOMISP_IOC_G_METADATA:
- err = get_atomisp_metadata_stat32(&karg->md, up);
- break;
- case ATOMISP_IOC_G_METADATA_BY_TYPE:
- err = get_atomisp_metadata_by_type_stat32(&karg->md_with_type,
- up);
- break;
- case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_LUT:
- err = get_atomisp_sensor_ae_bracketing_lut(&karg->lut, up);
- break;
- }
- if (err)
- return err;
-
- err = native_ioctl(file, cmd, (unsigned long)karg);
- if (err)
- return err;
-
- switch (cmd) {
- case ATOMISP_IOC_G_HISTOGRAM:
- err = put_atomisp_histogram32(&karg->his, up);
- break;
- case ATOMISP_IOC_G_DIS_STAT:
- err = put_atomisp_dis_statistics32(&karg->dis_s, up);
- break;
- case ATOMISP_IOC_G_3A_STAT:
- err = put_atomisp_3a_statistics32(&karg->s3a_s, up);
- break;
- case ATOMISP_IOC_G_ISP_GDC_TAB:
- err = put_atomisp_morph_table32(&karg->mor_t, up);
- break;
- case ATOMISP_IOC_G_ISP_OVERLAY:
- err = put_atomisp_overlay32(&karg->overlay, up);
- break;
- case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP:
- err = put_atomisp_calibration_group32(&karg->cal_grp, up);
- break;
- case ATOMISP_IOC_ACC_LOAD:
- err = put_atomisp_acc_fw_load32(&karg->acc_fw_load, up);
- break;
- case ATOMISP_IOC_ACC_S_ARG:
- case ATOMISP_IOC_ACC_DESTAB:
- err = put_atomisp_acc_fw_arg32(&karg->acc_fw_arg, up);
- break;
- case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA:
- case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA:
- err = put_v4l2_private_int_data32(&karg->v4l2_pri_data, up);
- break;
- case ATOMISP_IOC_ACC_MAP:
- case ATOMISP_IOC_ACC_UNMAP:
- err = put_atomisp_acc_map32(&karg->acc_map, up);
- break;
- case ATOMISP_IOC_ACC_S_MAPPED_ARG:
- err = put_atomisp_acc_s_mapped_arg32(&karg->acc_map_arg, up);
- break;
- case ATOMISP_IOC_ACC_LOAD_TO_PIPE:
- err = put_atomisp_acc_fw_load_to_pipe32(&karg->acc_fw_to_pipe,
- up);
- break;
- case ATOMISP_IOC_G_METADATA:
- err = put_atomisp_metadata_stat32(&karg->md, up);
- break;
- case ATOMISP_IOC_G_METADATA_BY_TYPE:
- err = put_atomisp_metadata_by_type_stat32(&karg->md_with_type,
- up);
- break;
- }
-
- return err;
-}
-
-long atomisp_compat_ioctl32(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct video_device *vdev = video_devdata(file);
- struct atomisp_device *isp = video_get_drvdata(vdev);
- long ret = -ENOIOCTLCMD;
-
- if (!file->f_op->unlocked_ioctl)
- return ret;
-
- switch (cmd) {
- case ATOMISP_IOC_G_XNR:
- case ATOMISP_IOC_S_XNR:
- case ATOMISP_IOC_G_NR:
- case ATOMISP_IOC_S_NR:
- case ATOMISP_IOC_G_TNR:
- case ATOMISP_IOC_S_TNR:
- case ATOMISP_IOC_G_BLACK_LEVEL_COMP:
- case ATOMISP_IOC_S_BLACK_LEVEL_COMP:
- case ATOMISP_IOC_G_EE:
- case ATOMISP_IOC_S_EE:
- case ATOMISP_IOC_S_DIS_VECTOR:
- case ATOMISP_IOC_G_ISP_PARM:
- case ATOMISP_IOC_S_ISP_PARM:
- case ATOMISP_IOC_G_ISP_GAMMA:
- case ATOMISP_IOC_S_ISP_GAMMA:
- case ATOMISP_IOC_ISP_MAKERNOTE:
- case ATOMISP_IOC_G_ISP_MACC:
- case ATOMISP_IOC_S_ISP_MACC:
- case ATOMISP_IOC_G_ISP_BAD_PIXEL_DETECTION:
- case ATOMISP_IOC_S_ISP_BAD_PIXEL_DETECTION:
- case ATOMISP_IOC_G_ISP_FALSE_COLOR_CORRECTION:
- case ATOMISP_IOC_S_ISP_FALSE_COLOR_CORRECTION:
- case ATOMISP_IOC_G_ISP_CTC:
- case ATOMISP_IOC_S_ISP_CTC:
- case ATOMISP_IOC_G_ISP_WHITE_BALANCE:
- case ATOMISP_IOC_S_ISP_WHITE_BALANCE:
- case ATOMISP_IOC_CAMERA_BRIDGE:
- case ATOMISP_IOC_G_SENSOR_MODE_DATA:
- case ATOMISP_IOC_S_EXPOSURE:
- case ATOMISP_IOC_G_3A_CONFIG:
- case ATOMISP_IOC_S_3A_CONFIG:
- case ATOMISP_IOC_ACC_UNLOAD:
- case ATOMISP_IOC_ACC_START:
- case ATOMISP_IOC_ACC_WAIT:
- case ATOMISP_IOC_ACC_ABORT:
- case ATOMISP_IOC_G_ISP_GAMMA_CORRECTION:
- case ATOMISP_IOC_S_ISP_GAMMA_CORRECTION:
- case ATOMISP_IOC_S_CONT_CAPTURE_CONFIG:
- case ATOMISP_IOC_G_DVS2_BQ_RESOLUTIONS:
- case ATOMISP_IOC_EXT_ISP_CTRL:
- case ATOMISP_IOC_EXP_ID_UNLOCK:
- case ATOMISP_IOC_EXP_ID_CAPTURE:
- case ATOMISP_IOC_S_ENABLE_DZ_CAPT_PIPE:
- case ATOMISP_IOC_G_FORMATS_CONFIG:
- case ATOMISP_IOC_S_FORMATS_CONFIG:
- case ATOMISP_IOC_S_EXPOSURE_WINDOW:
- case ATOMISP_IOC_S_ACC_STATE:
- case ATOMISP_IOC_G_ACC_STATE:
- case ATOMISP_IOC_INJECT_A_FAKE_EVENT:
- case ATOMISP_IOC_G_SENSOR_AE_BRACKETING_INFO:
- case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_MODE:
- case ATOMISP_IOC_G_SENSOR_AE_BRACKETING_MODE:
- case ATOMISP_IOC_G_INVALID_FRAME_NUM:
- case ATOMISP_IOC_S_ARRAY_RESOLUTION:
- case ATOMISP_IOC_S_SENSOR_RUNMODE:
- case ATOMISP_IOC_G_UPDATE_EXPOSURE:
- ret = native_ioctl(file, cmd, arg);
- break;
-
- case ATOMISP_IOC_G_HISTOGRAM32:
- case ATOMISP_IOC_S_HISTOGRAM32:
- case ATOMISP_IOC_G_DIS_STAT32:
- case ATOMISP_IOC_S_DIS_COEFS32:
- case ATOMISP_IOC_S_DIS_VECTOR32:
- case ATOMISP_IOC_G_3A_STAT32:
- case ATOMISP_IOC_G_ISP_GDC_TAB32:
- case ATOMISP_IOC_S_ISP_GDC_TAB32:
- case ATOMISP_IOC_S_ISP_FPN_TABLE32:
- case ATOMISP_IOC_G_ISP_OVERLAY32:
- case ATOMISP_IOC_S_ISP_OVERLAY32:
- case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP32:
- case ATOMISP_IOC_ACC_LOAD32:
- case ATOMISP_IOC_ACC_S_ARG32:
- case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA32:
- case ATOMISP_IOC_S_ISP_SHD_TAB32:
- case ATOMISP_IOC_ACC_DESTAB32:
- case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA32:
- case ATOMISP_IOC_ACC_MAP32:
- case ATOMISP_IOC_ACC_UNMAP32:
- case ATOMISP_IOC_ACC_S_MAPPED_ARG32:
- case ATOMISP_IOC_S_PARAMETERS32:
- case ATOMISP_IOC_ACC_LOAD_TO_PIPE32:
- case ATOMISP_IOC_G_METADATA32:
- case ATOMISP_IOC_G_METADATA_BY_TYPE32:
- case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_LUT32:
- ret = atomisp_do_compat_ioctl(file, cmd, arg);
- break;
-
- default:
- dev_warn(isp->dev,
- "%s: unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
- __func__, _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd),
- cmd);
- break;
- }
- return ret;
-}
-#endif /* CONFIG_COMPAT */
diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp_csi2.c
index 060b8765ae96..56456e59bf89 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_csi2.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.c
@@ -25,13 +25,13 @@
static struct v4l2_mbus_framefmt *__csi2_get_format(struct
atomisp_mipi_csi2_device
* csi2,
- struct
- v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
enum
v4l2_subdev_format_whence
which, unsigned int pad) {
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&csi2->subdev, sd_state,
+ pad);
else
return &csi2->formats[pad];
}
@@ -44,7 +44,7 @@ static struct v4l2_mbus_framefmt *__csi2_get_format(struct
* return -EINVAL or zero on success
*/
static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
const struct atomisp_in_fmt_conv *ic = atomisp_in_fmt_conv;
@@ -70,13 +70,13 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
* return -EINVAL or zero on success
*/
static int csi2_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __csi2_get_format(csi2, cfg, fmt->which, fmt->pad);
+ format = __csi2_get_format(csi2, sd_state, fmt->which, fmt->pad);
fmt->format = *format;
@@ -84,12 +84,14 @@ static int csi2_get_format(struct v4l2_subdev *sd,
}
int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int which, uint16_t pad,
struct v4l2_mbus_framefmt *ffmt)
{
struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *actual_ffmt = __csi2_get_format(csi2, cfg, which, pad);
+ struct v4l2_mbus_framefmt *actual_ffmt = __csi2_get_format(csi2,
+ sd_state,
+ which, pad);
if (pad == CSI2_PAD_SINK) {
const struct atomisp_in_fmt_conv *ic;
@@ -110,12 +112,14 @@ int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd,
tmp_ffmt = *ffmt = *actual_ffmt;
- return atomisp_csi2_set_ffmt(sd, cfg, which, CSI2_PAD_SOURCE,
+ return atomisp_csi2_set_ffmt(sd, sd_state, which,
+ CSI2_PAD_SOURCE,
&tmp_ffmt);
}
/* FIXME: DPCM decompression */
- *actual_ffmt = *ffmt = *__csi2_get_format(csi2, cfg, which, CSI2_PAD_SINK);
+ *actual_ffmt = *ffmt = *__csi2_get_format(csi2, sd_state, which,
+ CSI2_PAD_SINK);
return 0;
}
@@ -129,10 +133,10 @@ int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd,
* return -EINVAL or zero on success
*/
static int csi2_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
- return atomisp_csi2_set_ffmt(sd, cfg, fmt->which, fmt->pad,
+ return atomisp_csi2_set_ffmt(sd, sd_state, fmt->which, fmt->pad,
&fmt->format);
}
diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.h b/drivers/staging/media/atomisp/pci/atomisp_csi2.h
index 59261e8f1a1a..e35711be8a37 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_csi2.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.h
@@ -44,7 +44,7 @@ struct atomisp_mipi_csi2_device {
};
int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int which, uint16_t pad,
struct v4l2_mbus_framefmt *ffmt);
int atomisp_mipi_csi2_init(struct atomisp_device *isp);
diff --git a/drivers/staging/media/atomisp/pci/atomisp_file.c b/drivers/staging/media/atomisp/pci/atomisp_file.c
index e568ca99c45a..4570a9ab100b 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_file.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_file.c
@@ -80,7 +80,7 @@ static int file_input_s_stream(struct v4l2_subdev *sd, int enable)
}
static int file_input_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -104,16 +104,16 @@ static int file_input_get_fmt(struct v4l2_subdev *sd,
}
static int file_input_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
if (format->pad)
return -EINVAL;
- file_input_get_fmt(sd, cfg, format);
+ file_input_get_fmt(sd, sd_state, format);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- cfg->try_fmt = *fmt;
+ sd_state->pads->try_fmt = *fmt;
return 0;
}
@@ -130,7 +130,7 @@ static int file_input_s_power(struct v4l2_subdev *sd, int on)
}
static int file_input_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
/*to fake*/
@@ -138,7 +138,7 @@ static int file_input_enum_mbus_code(struct v4l2_subdev *sd,
}
static int file_input_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
/*to fake*/
@@ -146,7 +146,7 @@ static int file_input_enum_frame_size(struct v4l2_subdev *sd,
}
static int file_input_enum_frame_ival(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum
*fie)
{
diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c
index f1e6b2597853..f82bf082aa79 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_fops.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c
@@ -837,7 +837,7 @@ dev_init:
}
/* runtime power management, turn on ISP */
- ret = pm_runtime_get_sync(vdev->v4l2_dev->dev);
+ ret = pm_runtime_resume_and_get(vdev->v4l2_dev->dev);
if (ret < 0) {
dev_err(isp->dev, "Failed to power on device\n");
goto error;
@@ -881,9 +881,9 @@ done:
css_error:
atomisp_css_uninit(isp);
+ pm_runtime_put(vdev->v4l2_dev->dev);
error:
hmm_pool_unregister(HMM_POOL_TYPE_DYNAMIC);
- pm_runtime_put(vdev->v4l2_dev->dev);
rt_mutex_unlock(&isp->mutex);
return ret;
}
@@ -963,7 +963,7 @@ static int atomisp_release(struct file *file)
if (!isp->sw_contex.file_input && asd->fmt_auto->val) {
struct v4l2_mbus_framefmt isp_sink_fmt = { 0 };
- atomisp_subdev_set_ffmt(&asd->subdev, fh.pad,
+ atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
V4L2_SUBDEV_FORMAT_ACTIVE,
ATOMISP_SUBDEV_PAD_SINK, &isp_sink_fmt);
}
@@ -975,7 +975,7 @@ subdev_uninit:
if (isp->sw_contex.file_input && asd->fmt_auto->val) {
struct v4l2_mbus_framefmt isp_sink_fmt = { 0 };
- atomisp_subdev_set_ffmt(&asd->subdev, fh.pad,
+ atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
V4L2_SUBDEV_FORMAT_ACTIVE,
ATOMISP_SUBDEV_PAD_SINK, &isp_sink_fmt);
}
@@ -1016,7 +1016,7 @@ subdev_uninit:
done:
if (!acc_node) {
- atomisp_subdev_set_selection(&asd->subdev, fh.pad,
+ atomisp_subdev_set_selection(&asd->subdev, fh.state,
V4L2_SUBDEV_FORMAT_ACTIVE,
atomisp_subdev_source_pad(vdev),
V4L2_SEL_TGT_COMPOSE, 0,
@@ -1283,7 +1283,8 @@ const struct v4l2_file_operations atomisp_fops = {
.unlocked_ioctl = video_ioctl2,
#ifdef CONFIG_COMPAT
/*
- * There are problems with this code. Disable this for now.
+ * this was removed because of bugs, the interface
+ * needs to be made safe for compat tasks instead.
.compat_ioctl32 = atomisp_compat_ioctl32,
*/
#endif
@@ -1297,10 +1298,7 @@ const struct v4l2_file_operations atomisp_file_fops = {
.mmap = atomisp_file_mmap,
.unlocked_ioctl = video_ioctl2,
#ifdef CONFIG_COMPAT
- /*
- * There are problems with this code. Disable this for now.
- .compat_ioctl32 = atomisp_compat_ioctl32,
- */
+ /* .compat_ioctl32 = atomisp_compat_ioctl32, */
#endif
.poll = atomisp_poll,
};
diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c
index 2ef5f44e4b6b..12f22ad007c7 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c
@@ -213,7 +213,7 @@ static int isp_subdev_unsubscribe_event(struct v4l2_subdev *sd,
* return -EINVAL or zero on success
*/
static int isp_subdev_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(atomisp_in_fmt_conv) - 1)
@@ -246,7 +246,7 @@ static int isp_subdev_validate_rect(struct v4l2_subdev *sd, uint32_t pad,
}
struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
u32 which, uint32_t pad,
uint32_t target)
{
@@ -255,9 +255,9 @@ struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
if (which == V4L2_SUBDEV_FORMAT_TRY) {
switch (target) {
case V4L2_SEL_TGT_CROP:
- return v4l2_subdev_get_try_crop(sd, cfg, pad);
+ return v4l2_subdev_get_try_crop(sd, sd_state, pad);
case V4L2_SEL_TGT_COMPOSE:
- return v4l2_subdev_get_try_compose(sd, cfg, pad);
+ return v4l2_subdev_get_try_compose(sd, sd_state, pad);
}
}
@@ -273,19 +273,20 @@ struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt
*atomisp_subdev_get_ffmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg, uint32_t which,
+ struct v4l2_subdev_state *sd_state, uint32_t which,
uint32_t pad)
{
struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(sd, cfg, pad);
+ return v4l2_subdev_get_try_format(sd, sd_state, pad);
return &isp_sd->fmt[pad].fmt;
}
static void isp_get_fmt_rect(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg, uint32_t which,
+ struct v4l2_subdev_state *sd_state,
+ uint32_t which,
struct v4l2_mbus_framefmt **ffmt,
struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM],
struct v4l2_rect *comp[ATOMISP_SUBDEV_PADS_NUM])
@@ -293,16 +294,16 @@ static void isp_get_fmt_rect(struct v4l2_subdev *sd,
unsigned int i;
for (i = 0; i < ATOMISP_SUBDEV_PADS_NUM; i++) {
- ffmt[i] = atomisp_subdev_get_ffmt(sd, cfg, which, i);
- crop[i] = atomisp_subdev_get_rect(sd, cfg, which, i,
+ ffmt[i] = atomisp_subdev_get_ffmt(sd, sd_state, which, i);
+ crop[i] = atomisp_subdev_get_rect(sd, sd_state, which, i,
V4L2_SEL_TGT_CROP);
- comp[i] = atomisp_subdev_get_rect(sd, cfg, which, i,
+ comp[i] = atomisp_subdev_get_rect(sd, sd_state, which, i,
V4L2_SEL_TGT_COMPOSE);
}
}
static void isp_subdev_propagate(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
u32 which, uint32_t pad, uint32_t target,
uint32_t flags)
{
@@ -313,7 +314,7 @@ static void isp_subdev_propagate(struct v4l2_subdev *sd,
if (flags & V4L2_SEL_FLAG_KEEP_CONFIG)
return;
- isp_get_fmt_rect(sd, cfg, which, ffmt, crop, comp);
+ isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp);
switch (pad) {
case ATOMISP_SUBDEV_PAD_SINK: {
@@ -323,7 +324,7 @@ static void isp_subdev_propagate(struct v4l2_subdev *sd,
r.width = ffmt[pad]->width;
r.height = ffmt[pad]->height;
- atomisp_subdev_set_selection(sd, cfg, which, pad,
+ atomisp_subdev_set_selection(sd, sd_state, which, pad,
target, flags, &r);
break;
}
@@ -331,7 +332,7 @@ static void isp_subdev_propagate(struct v4l2_subdev *sd,
}
static int isp_subdev_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct v4l2_rect *rec;
@@ -340,7 +341,7 @@ static int isp_subdev_get_selection(struct v4l2_subdev *sd,
if (rval)
return rval;
- rec = atomisp_subdev_get_rect(sd, cfg, sel->which, sel->pad,
+ rec = atomisp_subdev_get_rect(sd, sd_state, sel->which, sel->pad,
sel->target);
if (!rec)
return -EINVAL;
@@ -365,7 +366,7 @@ static const char *atomisp_pad_str(unsigned int pad)
}
int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
u32 which, uint32_t pad, uint32_t target,
u32 flags, struct v4l2_rect *r)
{
@@ -382,7 +383,7 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
stream_id = atomisp_source_pad_to_stream_id(isp_sd, vdev_pad);
- isp_get_fmt_rect(sd, cfg, which, ffmt, crop, comp);
+ isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp);
dev_dbg(isp->dev,
"sel: pad %s tgt %s l %d t %d w %d h %d which %s f 0x%8.8x\n",
@@ -450,7 +451,8 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
struct v4l2_rect tmp = *crop[pad];
atomisp_subdev_set_selection(
- sd, cfg, which, i, V4L2_SEL_TGT_COMPOSE,
+ sd, sd_state, which, i,
+ V4L2_SEL_TGT_COMPOSE,
flags, &tmp);
}
}
@@ -472,9 +474,9 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
* when dvs is disabled.
*/
dvs_w = dvs_h = 12;
- } else
+ } else {
dvs_w = dvs_h = 0;
-
+ }
atomisp_css_video_set_dis_envelope(isp_sd, dvs_w, dvs_h);
atomisp_css_input_set_effective_resolution(isp_sd, stream_id,
crop[pad]->width, crop[pad]->height);
@@ -551,9 +553,9 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
ffmt[pad]->height = comp[pad]->height;
}
- if (!atomisp_subdev_get_rect(sd, cfg, which, pad, target))
+ if (!atomisp_subdev_get_rect(sd, sd_state, which, pad, target))
return -EINVAL;
- *r = *atomisp_subdev_get_rect(sd, cfg, which, pad, target);
+ *r = *atomisp_subdev_get_rect(sd, sd_state, which, pad, target);
dev_dbg(isp->dev, "sel actual: l %d t %d w %d h %d\n",
r->left, r->top, r->width, r->height);
@@ -562,7 +564,7 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
}
static int isp_subdev_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target);
@@ -570,7 +572,8 @@ static int isp_subdev_set_selection(struct v4l2_subdev *sd,
if (rval)
return rval;
- return atomisp_subdev_set_selection(sd, cfg, sel->which, sel->pad,
+ return atomisp_subdev_set_selection(sd, sd_state, sel->which,
+ sel->pad,
sel->target, sel->flags, &sel->r);
}
@@ -609,13 +612,14 @@ static int atomisp_get_sensor_bin_factor(struct atomisp_sub_device *asd)
}
void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg, uint32_t which,
+ struct v4l2_subdev_state *sd_state,
+ uint32_t which,
u32 pad, struct v4l2_mbus_framefmt *ffmt)
{
struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
struct atomisp_device *isp = isp_sd->isp;
struct v4l2_mbus_framefmt *__ffmt =
- atomisp_subdev_get_ffmt(sd, cfg, which, pad);
+ atomisp_subdev_get_ffmt(sd, sd_state, which, pad);
u16 vdev_pad = atomisp_subdev_source_pad(sd->devnode);
enum atomisp_input_stream_id stream_id;
@@ -640,7 +644,7 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
*__ffmt = *ffmt;
- isp_subdev_propagate(sd, cfg, which, pad,
+ isp_subdev_propagate(sd, sd_state, which, pad,
V4L2_SEL_TGT_CROP, 0);
if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
@@ -679,10 +683,11 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
* to the format type.
*/
static int isp_subdev_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
- fmt->format = *atomisp_subdev_get_ffmt(sd, cfg, fmt->which, fmt->pad);
+ fmt->format = *atomisp_subdev_get_ffmt(sd, sd_state, fmt->which,
+ fmt->pad);
return 0;
}
@@ -698,10 +703,11 @@ static int isp_subdev_get_format(struct v4l2_subdev *sd,
* to the format type.
*/
static int isp_subdev_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
- atomisp_subdev_set_ffmt(sd, cfg, fmt->which, fmt->pad, &fmt->format);
+ atomisp_subdev_set_ffmt(sd, sd_state, fmt->which, fmt->pad,
+ &fmt->format);
return 0;
}
diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.h b/drivers/staging/media/atomisp/pci/atomisp_subdev.h
index 330a77eed8aa..d6fcfab6352d 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_subdev.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.h
@@ -437,19 +437,20 @@ uint16_t atomisp_subdev_source_pad(struct video_device *vdev);
/* Get pointer to appropriate format */
struct v4l2_mbus_framefmt
*atomisp_subdev_get_ffmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg, uint32_t which,
+ struct v4l2_subdev_state *sd_state, uint32_t which,
uint32_t pad);
struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
u32 which, uint32_t pad,
uint32_t target);
int atomisp_subdev_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
u32 which, uint32_t pad, uint32_t target,
u32 flags, struct v4l2_rect *r);
/* Actually set the format */
void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg, uint32_t which,
+ struct v4l2_subdev_state *sd_state,
+ uint32_t which,
u32 pad, struct v4l2_mbus_framefmt *ffmt);
int atomisp_update_run_mode(struct atomisp_sub_device *asd);
diff --git a/drivers/staging/media/atomisp/pci/atomisp_tpg.c b/drivers/staging/media/atomisp/pci/atomisp_tpg.c
index 1def80bab180..e29a96da5f98 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_tpg.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_tpg.c
@@ -29,7 +29,7 @@ static int tpg_s_stream(struct v4l2_subdev *sd, int enable)
}
static int tpg_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
/*to fake*/
@@ -37,7 +37,7 @@ static int tpg_get_fmt(struct v4l2_subdev *sd,
}
static int tpg_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
@@ -47,7 +47,7 @@ static int tpg_set_fmt(struct v4l2_subdev *sd,
/* only raw8 grbg is supported by TPG */
fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *fmt;
+ sd_state->pads->try_fmt = *fmt;
return 0;
}
return 0;
@@ -65,7 +65,7 @@ static int tpg_s_power(struct v4l2_subdev *sd, int on)
}
static int tpg_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
/*to fake*/
@@ -73,7 +73,7 @@ static int tpg_enum_mbus_code(struct v4l2_subdev *sd,
}
static int tpg_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
/*to fake*/
@@ -81,7 +81,7 @@ static int tpg_enum_frame_size(struct v4l2_subdev *sd,
}
static int tpg_enum_frame_ival(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
/*to fake*/
diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
index 0295e2e32d79..948769ca6539 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
@@ -1178,7 +1178,7 @@ static void atomisp_unregister_entities(struct atomisp_device *isp)
atomisp_mipi_csi2_unregister_entities(&isp->csi2_port[i]);
list_for_each_entry_safe(sd, next, &isp->v4l2_dev.subdevs, list)
- v4l2_device_unregister_subdev(sd);
+ v4l2_device_unregister_subdev(sd);
v4l2_device_unregister(&isp->v4l2_dev);
media_device_unregister(&isp->media_dev);
@@ -1500,9 +1500,9 @@ static int init_atomisp_wdts(struct atomisp_device *isp)
for (i = 0; i < isp->num_of_streams; i++) {
struct atomisp_sub_device *asd = &isp->asd[i];
- if (!IS_ISP2401)
+ if (!IS_ISP2401) {
timer_setup(&asd->wdt, atomisp_wdt, 0);
- else {
+ } else {
timer_setup(&asd->video_out_capture.wdt,
atomisp_wdt, 0);
timer_setup(&asd->video_out_preview.wdt,
diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c
index 27dd8ce8ba0a..d26b1301eeb7 100644
--- a/drivers/staging/media/atomisp/pci/sh_css.c
+++ b/drivers/staging/media/atomisp/pci/sh_css.c
@@ -239,8 +239,8 @@ ia_css_reset_defaults(struct sh_css *css);
static void
sh_css_init_host_sp_control_vars(void);
-static int set_num_primary_stages(unsigned int *num,
- enum ia_css_pipe_version version);
+static int
+set_num_primary_stages(unsigned int *num, enum ia_css_pipe_version version);
static bool
need_capture_pp(const struct ia_css_pipe *pipe);
@@ -308,8 +308,7 @@ sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
const void *acc_fw);
static int
-alloc_continuous_frames(
- struct ia_css_pipe *pipe, bool init_time);
+alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time);
static void
pipe_global_init(void);
@@ -413,7 +412,6 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
static void
sh_css_pipe_free_shading_table(struct ia_css_pipe *pipe)
{
- assert(pipe);
if (!pipe) {
IA_CSS_ERROR("NULL input parameter");
return;
@@ -453,15 +451,15 @@ static enum ia_css_frame_format yuv422_copy_formats[] = {
* by the copy binary given the stream format.
* */
static int
-verify_copy_out_frame_format(struct ia_css_pipe *pipe) {
+verify_copy_out_frame_format(struct ia_css_pipe *pipe)
+{
enum ia_css_frame_format out_fmt = pipe->output_info[0].format;
unsigned int i, found = 0;
assert(pipe);
assert(pipe->stream);
- switch (pipe->stream->config.input_config.format)
- {
+ switch (pipe->stream->config.input_config.format) {
case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY:
case ATOMISP_INPUT_FORMAT_YUV420_8:
for (i = 0; i < ARRAY_SIZE(yuv420_copy_formats) && !found; i++)
@@ -528,7 +526,8 @@ ia_css_stream_input_format_bits_per_pixel(struct ia_css_stream *stream)
#if !defined(ISP2401)
static int
-sh_css_config_input_network(struct ia_css_stream *stream) {
+sh_css_config_input_network(struct ia_css_stream *stream)
+{
unsigned int fmt_type;
struct ia_css_pipe *pipe = stream->last_pipe;
struct ia_css_binary *binary = NULL;
@@ -554,8 +553,7 @@ sh_css_config_input_network(struct ia_css_stream *stream) {
stream->config.mode);
if ((binary && (binary->online || stream->config.continuous)) ||
- pipe->config.mode == IA_CSS_PIPE_MODE_COPY)
- {
+ pipe->config.mode == IA_CSS_PIPE_MODE_COPY) {
err = ia_css_ifmtr_configure(&stream->config,
binary);
if (err)
@@ -563,8 +561,7 @@ sh_css_config_input_network(struct ia_css_stream *stream) {
}
if (stream->config.mode == IA_CSS_INPUT_MODE_TPG ||
- stream->config.mode == IA_CSS_INPUT_MODE_PRBS)
- {
+ stream->config.mode == IA_CSS_INPUT_MODE_PRBS) {
unsigned int hblank_cycles = 100,
vblank_lines = 6,
width,
@@ -723,35 +720,32 @@ static bool sh_css_translate_stream_cfg_to_input_system_input_port_id(
switch (stream_cfg->mode) {
case IA_CSS_INPUT_MODE_TPG:
- if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID0) {
+ if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID0)
isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT0_ID;
- } else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID1) {
+ else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID1)
isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT1_ID;
- } else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID2) {
+ else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID2)
isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT2_ID;
- }
break;
case IA_CSS_INPUT_MODE_PRBS:
- if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID0) {
+ if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID0)
isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT0_ID;
- } else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID1) {
+ else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID1)
isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT1_ID;
- } else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID2) {
+ else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID2)
isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT2_ID;
- }
break;
case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
- if (stream_cfg->source.port.port == MIPI_PORT0_ID) {
+ if (stream_cfg->source.port.port == MIPI_PORT0_ID)
isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT0_ID;
- } else if (stream_cfg->source.port.port == MIPI_PORT1_ID) {
+ else if (stream_cfg->source.port.port == MIPI_PORT1_ID)
isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT1_ID;
- } else if (stream_cfg->source.port.port == MIPI_PORT2_ID) {
+ else if (stream_cfg->source.port.port == MIPI_PORT2_ID)
isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT2_ID;
- }
break;
default:
@@ -804,15 +798,14 @@ static bool sh_css_translate_stream_cfg_to_input_system_input_port_attr(
rc = true;
switch (stream_cfg->mode) {
case IA_CSS_INPUT_MODE_TPG:
- if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_RAMP) {
+ if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_RAMP)
isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_RAMP;
- } else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_CHECKERBOARD) {
+ else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_CHECKERBOARD)
isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_CHBO;
- } else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_MONO) {
+ else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_MONO)
isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_MONO;
- } else {
+ else
rc = false;
- }
/*
* TODO
@@ -951,12 +944,12 @@ static bool sh_css_translate_stream_cfg_to_input_system_input_port_resolution(
stream_cfg->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) &&
stream_cfg->source.port.compression.type != IA_CSS_CSI2_COMPRESSION_TYPE_NONE) {
if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel ==
- UNCOMPRESSED_BITS_PER_PIXEL_10) {
+ UNCOMPRESSED_BITS_PER_PIXEL_10)
fmt_type = ATOMISP_INPUT_FORMAT_RAW_10;
- } else if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel ==
- UNCOMPRESSED_BITS_PER_PIXEL_12) {
+ else if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel ==
+ UNCOMPRESSED_BITS_PER_PIXEL_12)
fmt_type = ATOMISP_INPUT_FORMAT_RAW_12;
- } else
+ else
return false;
}
@@ -1045,7 +1038,8 @@ static bool sh_css_translate_binary_info_to_input_system_output_port_attr(
}
static int
-sh_css_config_input_network(struct ia_css_stream *stream) {
+sh_css_config_input_network(struct ia_css_stream *stream)
+{
bool rc;
ia_css_isys_descr_t isys_stream_descr;
unsigned int sp_thread_id;
@@ -1060,19 +1054,16 @@ sh_css_config_input_network(struct ia_css_stream *stream) {
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
"sh_css_config_input_network() enter 0x%p:\n", stream);
- if (stream->config.continuous)
- {
- if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE) {
+ if (stream->config.continuous) {
+ if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE)
pipe = stream->last_pipe;
- } else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_YUVPP) {
+ else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_YUVPP)
pipe = stream->last_pipe;
- } else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) {
+ else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
pipe = stream->last_pipe->pipe_settings.preview.copy_pipe;
- } else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) {
+ else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO)
pipe = stream->last_pipe->pipe_settings.video.copy_pipe;
- }
- } else
- {
+ } else {
pipe = stream->last_pipe;
if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE) {
/*
@@ -1087,7 +1078,6 @@ sh_css_config_input_network(struct ia_css_stream *stream) {
}
}
- assert(pipe);
if (!pipe)
return -EINVAL;
@@ -1095,8 +1085,7 @@ sh_css_config_input_network(struct ia_css_stream *stream) {
if (pipe->pipeline.stages->binary)
binary = pipe->pipeline.stages->binary;
- if (binary)
- {
+ if (binary) {
/* this was being done in ifmtr in 2400.
* online and cont bypass the init_in_frameinfo_memory_defaults
* so need to do it here
@@ -1111,8 +1100,7 @@ sh_css_config_input_network(struct ia_css_stream *stream) {
/* get the target input terminal */
sp_pipeline_input_terminal = &sh_css_sp_group.pipe_io[sp_thread_id].input;
- for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++)
- {
+ for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) {
/* initialization */
memset((void *)(&isys_stream_descr), 0, sizeof(ia_css_isys_descr_t));
sp_pipeline_input_terminal->context.virtual_input_system_stream[i].valid = 0;
@@ -1210,11 +1198,10 @@ static inline struct ia_css_pipe *stream_get_target_pipe(
struct ia_css_pipe *target_pipe;
/* get the pipe that consumes the stream */
- if (stream->config.continuous) {
+ if (stream->config.continuous)
target_pipe = stream_get_copy_pipe(stream);
- } else {
+ else
target_pipe = stream_get_last_pipe(stream);
- }
return target_pipe;
}
@@ -1388,10 +1375,9 @@ start_binary(struct ia_css_pipe *pipe,
/* start the copy function on the SP */
static int
start_copy_on_sp(struct ia_css_pipe *pipe,
- struct ia_css_frame *out_frame) {
+ struct ia_css_frame *out_frame)
+{
(void)out_frame;
- assert(pipe);
- assert(pipe->stream);
if ((!pipe) || (!pipe->stream))
return -EINVAL;
@@ -1406,8 +1392,7 @@ start_copy_on_sp(struct ia_css_pipe *pipe,
sh_css_sp_start_binary_copy(ia_css_pipe_get_pipe_num(pipe), out_frame, pipe->stream->config.pixels_per_clock == 2);
#if !defined(ISP2401)
- if (pipe->stream->reconfigure_css_rx)
- {
+ if (pipe->stream->reconfigure_css_rx) {
ia_css_isys_rx_configure(&pipe->stream->csi_rx_config,
pipe->stream->config.mode);
pipe->stream->reconfigure_css_rx = false;
@@ -1596,7 +1581,8 @@ ia_css_reset_defaults(struct sh_css *css)
int
ia_css_load_firmware(struct device *dev, const struct ia_css_env *env,
- const struct ia_css_fw *fw) {
+ const struct ia_css_fw *fw)
+{
int err;
if (!env)
@@ -1607,16 +1593,14 @@ ia_css_load_firmware(struct device *dev, const struct ia_css_env *env,
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_load_firmware() enter\n");
/* make sure we initialize my_css */
- if (my_css.flush != env->cpu_mem_env.flush)
- {
+ if (my_css.flush != env->cpu_mem_env.flush) {
ia_css_reset_defaults(&my_css);
my_css.flush = env->cpu_mem_env.flush;
}
ia_css_unload_firmware(); /* in case we are called twice */
err = sh_css_load_firmware(dev, fw->data, fw->bytes);
- if (!err)
- {
+ if (!err) {
err = ia_css_binary_init_infos();
if (!err)
fw_explicitly_loaded = true;
@@ -1630,7 +1614,8 @@ int
ia_css_init(struct device *dev, const struct ia_css_env *env,
const struct ia_css_fw *fw,
u32 mmu_l1_base,
- enum ia_css_irq_type irq_type) {
+ enum ia_css_irq_type irq_type)
+{
int err;
ia_css_spctrl_cfg spctrl_cfg;
@@ -1704,16 +1689,14 @@ ia_css_init(struct device *dev, const struct ia_css_env *env,
my_css.flush = flush_func;
err = ia_css_rmgr_init();
- if (err)
- {
+ if (err) {
IA_CSS_LEAVE_ERR(err);
return err;
}
IA_CSS_LOG("init: %d", my_css_save_initialized);
- if (!my_css_save_initialized)
- {
+ if (!my_css_save_initialized) {
my_css_save_initialized = true;
my_css_save.mode = sh_css_mode_working;
memset(my_css_save.stream_seeds, 0,
@@ -1741,19 +1724,16 @@ ia_css_init(struct device *dev, const struct ia_css_env *env,
gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_0, 0);
err = ia_css_refcount_init(REFCOUNT_SIZE);
- if (err)
- {
+ if (err) {
IA_CSS_LEAVE_ERR(err);
return err;
}
err = sh_css_params_init();
- if (err)
- {
+ if (err) {
IA_CSS_LEAVE_ERR(err);
return err;
}
- if (fw)
- {
+ if (fw) {
ia_css_unload_firmware(); /* in case we already had firmware loaded */
err = sh_css_load_firmware(dev, fw->data, fw->bytes);
if (err) {
@@ -1774,23 +1754,20 @@ ia_css_init(struct device *dev, const struct ia_css_env *env,
return -EINVAL;
err = ia_css_spctrl_load_fw(SP0_ID, &spctrl_cfg);
- if (err)
- {
+ if (err) {
IA_CSS_LEAVE_ERR(err);
return err;
}
#if WITH_PC_MONITORING
- if (!thread_alive)
- {
+ if (!thread_alive) {
thread_alive++;
sh_css_print("PC_MONITORING: %s() -- create thread DISABLED\n",
__func__);
spying_thread_create();
}
#endif
- if (!sh_css_hrt_system_is_idle())
- {
+ if (!sh_css_hrt_system_is_idle()) {
IA_CSS_LEAVE_ERR(-EBUSY);
return -EBUSY;
}
@@ -1823,7 +1800,8 @@ ia_css_init(struct device *dev, const struct ia_css_env *env,
}
int
-ia_css_enable_isys_event_queue(bool enable) {
+ia_css_enable_isys_event_queue(bool enable)
+{
if (sh_css_sp_is_running())
return -EBUSY;
sh_css_sp_enable_isys_event_queue(enable);
@@ -1844,7 +1822,8 @@ sh_css_flush(struct ia_css_acc_fw *fw)
* doing it from stream_create since we could run out of sp threads due to
* allocation on inactive pipelines. */
static int
-map_sp_threads(struct ia_css_stream *stream, bool map) {
+map_sp_threads(struct ia_css_stream *stream, bool map)
+{
struct ia_css_pipe *main_pipe = NULL;
struct ia_css_pipe *copy_pipe = NULL;
struct ia_css_pipe *capture_pipe = NULL;
@@ -1852,12 +1831,10 @@ map_sp_threads(struct ia_css_stream *stream, bool map) {
int err = 0;
enum ia_css_pipe_id pipe_id;
- assert(stream);
IA_CSS_ENTER_PRIVATE("stream = %p, map = %s",
stream, map ? "true" : "false");
- if (!stream)
- {
+ if (!stream) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
@@ -1867,8 +1844,7 @@ map_sp_threads(struct ia_css_stream *stream, bool map) {
ia_css_pipeline_map(main_pipe->pipe_num, map);
- switch (pipe_id)
- {
+ switch (pipe_id) {
case IA_CSS_PIPE_ID_PREVIEW:
copy_pipe = main_pipe->pipe_settings.preview.copy_pipe;
capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
@@ -1887,23 +1863,17 @@ map_sp_threads(struct ia_css_stream *stream, bool map) {
}
if (acc_pipe)
- {
ia_css_pipeline_map(acc_pipe->pipe_num, map);
- }
if (capture_pipe)
- {
ia_css_pipeline_map(capture_pipe->pipe_num, map);
- }
/* Firmware expects copy pipe to be the last pipe mapped. (if needed) */
if (copy_pipe)
- {
ia_css_pipeline_map(copy_pipe->pipe_num, map);
- }
+
/* DH regular multi pipe - not continuous mode: map the next pipes too */
- if (!stream->config.continuous)
- {
+ if (!stream->config.continuous) {
int i;
for (i = 1; i < stream->num_pipes; i++)
@@ -1917,7 +1887,8 @@ map_sp_threads(struct ia_css_stream *stream, bool map) {
/* creates a host pipeline skeleton for all pipes in a stream. Called during
* stream_create. */
static int
-create_host_pipeline_structure(struct ia_css_stream *stream) {
+create_host_pipeline_structure(struct ia_css_stream *stream)
+{
struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL;
struct ia_css_pipe *acc_pipe = NULL;
enum ia_css_pipe_id pipe_id;
@@ -1926,27 +1897,22 @@ create_host_pipeline_structure(struct ia_css_stream *stream) {
unsigned int copy_pipe_delay = 0,
capture_pipe_delay = 0;
- assert(stream);
IA_CSS_ENTER_PRIVATE("stream = %p", stream);
- if (!stream)
- {
+ if (!stream) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
main_pipe = stream->last_pipe;
- assert(main_pipe);
- if (!main_pipe)
- {
+ if (!main_pipe) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
pipe_id = main_pipe->mode;
- switch (pipe_id)
- {
+ switch (pipe_id) {
case IA_CSS_PIPE_ID_PREVIEW:
copy_pipe = main_pipe->pipe_settings.preview.copy_pipe;
copy_pipe_delay = main_pipe->dvs_frame_delay;
@@ -1986,30 +1952,23 @@ create_host_pipeline_structure(struct ia_css_stream *stream) {
}
if (!(err) && copy_pipe)
- {
err = ia_css_pipeline_create(&copy_pipe->pipeline,
copy_pipe->mode,
copy_pipe->pipe_num,
copy_pipe_delay);
- }
if (!(err) && capture_pipe)
- {
err = ia_css_pipeline_create(&capture_pipe->pipeline,
capture_pipe->mode,
capture_pipe->pipe_num,
capture_pipe_delay);
- }
if (!(err) && acc_pipe)
- {
err = ia_css_pipeline_create(&acc_pipe->pipeline, acc_pipe->mode,
acc_pipe->pipe_num, main_pipe->dvs_frame_delay);
- }
/* DH regular multi pipe - not continuous mode: create the next pipelines too */
- if (!stream->config.continuous)
- {
+ if (!stream->config.continuous) {
int i;
for (i = 1; i < stream->num_pipes && 0 == err; i++) {
@@ -2028,7 +1987,8 @@ create_host_pipeline_structure(struct ia_css_stream *stream) {
/* creates a host pipeline for all pipes in a stream. Called during
* stream_start. */
static int
-create_host_pipeline(struct ia_css_stream *stream) {
+create_host_pipeline(struct ia_css_stream *stream)
+{
struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL;
struct ia_css_pipe *acc_pipe = NULL;
enum ia_css_pipe_id pipe_id;
@@ -2037,8 +1997,7 @@ create_host_pipeline(struct ia_css_stream *stream) {
unsigned int max_input_width = 0;
IA_CSS_ENTER_PRIVATE("stream = %p", stream);
- if (!stream)
- {
+ if (!stream) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
@@ -2049,8 +2008,7 @@ create_host_pipeline(struct ia_css_stream *stream) {
/* No continuous frame allocation for capture pipe. It uses the
* "main" pipe's frames. */
if ((pipe_id == IA_CSS_PIPE_ID_PREVIEW) ||
- (pipe_id == IA_CSS_PIPE_ID_VIDEO))
- {
+ (pipe_id == IA_CSS_PIPE_ID_VIDEO)) {
/* About pipe_id == IA_CSS_PIPE_ID_PREVIEW && stream->config.mode != IA_CSS_INPUT_MODE_MEMORY:
* The original condition pipe_id == IA_CSS_PIPE_ID_PREVIEW is too strong. E.g. in SkyCam (with memory
* based input frames) there is no continuous mode and thus no need for allocated continuous frames
@@ -2068,24 +2026,21 @@ create_host_pipeline(struct ia_css_stream *stream) {
#if !defined(ISP2401)
/* old isys: need to allocate_mipi_frames() even in IA_CSS_PIPE_MODE_COPY */
- if (pipe_id != IA_CSS_PIPE_ID_ACC)
- {
+ if (pipe_id != IA_CSS_PIPE_ID_ACC) {
err = allocate_mipi_frames(main_pipe, &stream->info);
if (err)
goto ERR;
}
#elif defined(ISP2401)
if ((pipe_id != IA_CSS_PIPE_ID_ACC) &&
- (main_pipe->config.mode != IA_CSS_PIPE_MODE_COPY))
- {
+ (main_pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) {
err = allocate_mipi_frames(main_pipe, &stream->info);
if (err)
goto ERR;
}
#endif
- switch (pipe_id)
- {
+ switch (pipe_id) {
case IA_CSS_PIPE_ID_PREVIEW:
copy_pipe = main_pipe->pipe_settings.preview.copy_pipe;
capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
@@ -2135,31 +2090,27 @@ create_host_pipeline(struct ia_css_stream *stream) {
if (err)
goto ERR;
- if (copy_pipe)
- {
+ if (copy_pipe) {
err = create_host_copy_pipeline(copy_pipe, max_input_width,
main_pipe->continuous_frames[0]);
if (err)
goto ERR;
}
- if (capture_pipe)
- {
+ if (capture_pipe) {
err = create_host_capture_pipeline(capture_pipe);
if (err)
goto ERR;
}
- if (acc_pipe)
- {
+ if (acc_pipe) {
err = create_host_acc_pipeline(acc_pipe);
if (err)
goto ERR;
}
/* DH regular multi pipe - not continuous mode: create the next pipelines too */
- if (!stream->config.continuous)
- {
+ if (!stream->config.continuous) {
int i;
for (i = 1; i < stream->num_pipes && 0 == err; i++) {
@@ -2201,10 +2152,9 @@ static const struct ia_css_yuvpp_settings yuvpp = IA_CSS_DEFAULT_YUVPP_SETTINGS;
static int
init_pipe_defaults(enum ia_css_pipe_mode mode,
struct ia_css_pipe *pipe,
- bool copy_pipe) {
-
- if (!pipe)
- {
+ bool copy_pipe)
+{
+ if (!pipe) {
IA_CSS_ERROR("NULL pipe parameter");
return -EINVAL;
}
@@ -2213,18 +2163,17 @@ init_pipe_defaults(enum ia_css_pipe_mode mode,
memcpy(pipe, &default_pipe, sizeof(default_pipe));
/* TODO: JB should not be needed, but temporary backward reference */
- switch (mode)
- {
+ switch (mode) {
case IA_CSS_PIPE_MODE_PREVIEW:
pipe->mode = IA_CSS_PIPE_ID_PREVIEW;
memcpy(&pipe->pipe_settings.preview, &preview, sizeof(preview));
break;
case IA_CSS_PIPE_MODE_CAPTURE:
- if (copy_pipe) {
+ if (copy_pipe)
pipe->mode = IA_CSS_PIPE_ID_COPY;
- } else {
+ else
pipe->mode = IA_CSS_PIPE_ID_CAPTURE;
- }
+
memcpy(&pipe->pipe_settings.capture, &capture, sizeof(capture));
break;
case IA_CSS_PIPE_MODE_VIDEO:
@@ -2254,27 +2203,25 @@ pipe_global_init(void)
u8 i;
my_css.pipe_counter = 0;
- for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) {
+ for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++)
my_css.all_pipes[i] = NULL;
- }
}
static int
pipe_generate_pipe_num(const struct ia_css_pipe *pipe,
- unsigned int *pipe_number) {
+ unsigned int *pipe_number)
+{
const u8 INVALID_PIPE_NUM = (uint8_t)~(0);
u8 pipe_num = INVALID_PIPE_NUM;
u8 i;
- if (!pipe)
- {
+ if (!pipe) {
IA_CSS_ERROR("NULL pipe parameter");
return -EINVAL;
}
/* Assign a new pipe_num .... search for empty place */
- for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++)
- {
+ for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) {
if (!my_css.all_pipes[i]) {
/*position is reserved */
my_css.all_pipes[i] = (struct ia_css_pipe *)pipe;
@@ -2282,8 +2229,7 @@ pipe_generate_pipe_num(const struct ia_css_pipe *pipe,
break;
}
}
- if (pipe_num == INVALID_PIPE_NUM)
- {
+ if (pipe_num == INVALID_PIPE_NUM) {
/* Max number of pipes already allocated */
IA_CSS_ERROR("Max number of pipes already created");
return -ENOSPC;
@@ -2309,12 +2255,12 @@ pipe_release_pipe_num(unsigned int pipe_num)
static int
create_pipe(enum ia_css_pipe_mode mode,
struct ia_css_pipe **pipe,
- bool copy_pipe) {
+ bool copy_pipe)
+{
int err = 0;
struct ia_css_pipe *me;
- if (!pipe)
- {
+ if (!pipe) {
IA_CSS_ERROR("NULL pipe parameter");
return -EINVAL;
}
@@ -2324,15 +2270,13 @@ create_pipe(enum ia_css_pipe_mode mode,
return -ENOMEM;
err = init_pipe_defaults(mode, me, copy_pipe);
- if (err)
- {
+ if (err) {
kfree(me);
return err;
}
err = pipe_generate_pipe_num(me, &me->pipe_num);
- if (err)
- {
+ if (err) {
kfree(me);
return err;
}
@@ -2361,7 +2305,6 @@ static void sh_css_pipe_free_acc_binaries(
struct ia_css_pipeline *pipeline;
struct ia_css_pipeline_stage *stage;
- assert(pipe);
if (!pipe) {
IA_CSS_ERROR("NULL input pointer");
return;
@@ -2378,26 +2321,24 @@ static void sh_css_pipe_free_acc_binaries(
}
int
-ia_css_pipe_destroy(struct ia_css_pipe *pipe) {
+ia_css_pipe_destroy(struct ia_css_pipe *pipe)
+{
int err = 0;
IA_CSS_ENTER("pipe = %p", pipe);
- if (!pipe)
- {
+ if (!pipe) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
- if (pipe->stream)
- {
+ if (pipe->stream) {
IA_CSS_LOG("ia_css_stream_destroy not called!");
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
- switch (pipe->config.mode)
- {
+ switch (pipe->config.mode) {
case IA_CSS_PIPE_MODE_PREVIEW:
/* need to take into account that this function is also called
on the internal copy pipe */
@@ -2461,9 +2402,8 @@ ia_css_pipe_destroy(struct ia_css_pipe *pipe) {
/* Temporarily, not every sh_css_pipe has an acc_extension. */
if (pipe->config.acc_extension)
- {
ia_css_pipe_unload_extension(pipe, pipe->config.acc_extension);
- }
+
kfree(pipe);
IA_CSS_LEAVE("err = %d", err);
return err;
@@ -2493,9 +2433,9 @@ ia_css_uninit(void)
ifmtr_set_if_blocking_mode_reset = true;
#endif
- if (!fw_explicitly_loaded) {
+ if (!fw_explicitly_loaded)
ia_css_unload_firmware();
- }
+
ia_css_spctrl_unload_fw(SP0_ID);
sh_css_sp_set_sp_running(false);
/* check and free any remaining mipi frames */
@@ -2681,8 +2621,8 @@ static int load_copy_binary(
}
static int
-alloc_continuous_frames(
- struct ia_css_pipe *pipe, bool init_time) {
+alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time)
+{
int err = 0;
struct ia_css_frame_info ref_info;
enum ia_css_pipe_id pipe_id;
@@ -2692,8 +2632,7 @@ alloc_continuous_frames(
IA_CSS_ENTER_PRIVATE("pipe = %p, init_time = %d", pipe, init_time);
- if ((!pipe) || (!pipe->stream))
- {
+ if ((!pipe) || (!pipe->stream)) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
@@ -2701,26 +2640,22 @@ alloc_continuous_frames(
pipe_id = pipe->mode;
continuous = pipe->stream->config.continuous;
- if (continuous)
- {
+ if (continuous) {
if (init_time) {
num_frames = pipe->stream->config.init_num_cont_raw_buf;
pipe->stream->continuous_pipe = pipe;
- } else
+ } else {
num_frames = pipe->stream->config.target_num_cont_raw_buf;
- } else
- {
+ }
+ } else {
num_frames = NUM_ONLINE_INIT_CONTINUOUS_FRAMES;
}
- if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
- {
+ if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
ref_info = pipe->pipe_settings.preview.preview_binary.in_frame_info;
- } else if (pipe_id == IA_CSS_PIPE_ID_VIDEO)
- {
+ } else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) {
ref_info = pipe->pipe_settings.video.video_binary.in_frame_info;
- } else
- {
+ } else {
/* should not happen */
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
@@ -2736,8 +2671,7 @@ alloc_continuous_frames(
#endif
#if !defined(HAS_NO_PACKED_RAW_PIXELS)
- if (pipe->stream->config.pack_raw_pixels)
- {
+ if (pipe->stream->config.pack_raw_pixels) {
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
"alloc_continuous_frames() IA_CSS_FRAME_FORMAT_RAW_PACKED\n");
ref_info.format = IA_CSS_FRAME_FORMAT_RAW_PACKED;
@@ -2766,8 +2700,7 @@ alloc_continuous_frames(
else
idx = pipe->stream->config.init_num_cont_raw_buf;
- for (i = idx; i < NUM_CONTINUOUS_FRAMES; i++)
- {
+ for (i = idx; i < NUM_CONTINUOUS_FRAMES; i++) {
/* free previous frame */
if (pipe->continuous_frames[i]) {
ia_css_frame_free(pipe->continuous_frames[i]);
@@ -2797,14 +2730,16 @@ alloc_continuous_frames(
}
int
-ia_css_alloc_continuous_frame_remain(struct ia_css_stream *stream) {
+ia_css_alloc_continuous_frame_remain(struct ia_css_stream *stream)
+{
if (!stream)
return -EINVAL;
return alloc_continuous_frames(stream->continuous_pipe, false);
}
static int
-load_preview_binaries(struct ia_css_pipe *pipe) {
+load_preview_binaries(struct ia_css_pipe *pipe)
+{
struct ia_css_frame_info prev_in_info,
prev_bds_out_info,
prev_out_info,
@@ -2912,8 +2847,7 @@ load_preview_binaries(struct ia_css_pipe *pipe) {
* then the preview binary selection is done again.
*/
if (need_vf_pp &&
- (mycs->preview_binary.out_frame_info[0].format != IA_CSS_FRAME_FORMAT_YUV_LINE))
- {
+ (mycs->preview_binary.out_frame_info[0].format != IA_CSS_FRAME_FORMAT_YUV_LINE)) {
/* Preview step 2 */
if (pipe->vf_yuv_ds_input_info.res.width)
prev_vf_info = pipe->vf_yuv_ds_input_info;
@@ -2938,8 +2872,7 @@ load_preview_binaries(struct ia_css_pipe *pipe) {
return err;
}
- if (need_vf_pp)
- {
+ if (need_vf_pp) {
struct ia_css_binary_descr vf_pp_descr;
/* Viewfinder post-processing */
@@ -2970,8 +2903,7 @@ load_preview_binaries(struct ia_css_pipe *pipe) {
#endif
/* Copy */
- if (need_isp_copy_binary)
- {
+ if (need_isp_copy_binary) {
err = load_copy_binary(pipe,
&mycs->copy_binary,
&mycs->preview_binary);
@@ -2979,8 +2911,7 @@ load_preview_binaries(struct ia_css_pipe *pipe) {
return err;
}
- if (pipe->shading_table)
- {
+ if (pipe->shading_table) {
ia_css_shading_table_free(pipe->shading_table);
pipe->shading_table = NULL;
}
@@ -2995,11 +2926,11 @@ ia_css_binary_unload(struct ia_css_binary *binary)
}
static int
-unload_preview_binaries(struct ia_css_pipe *pipe) {
+unload_preview_binaries(struct ia_css_pipe *pipe)
+{
IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
- if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW))
- {
+ if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
@@ -3052,20 +2983,19 @@ static int add_firmwares(
struct ia_css_frame *in = NULL;
struct ia_css_frame *vf = NULL;
- if ((fw == last_fw) && (fw->info.isp.sp.enable.out_frame != 0)) {
+ if ((fw == last_fw) && (fw->info.isp.sp.enable.out_frame != 0))
out[0] = out_frame;
- }
- if (fw->info.isp.sp.enable.in_frame != 0) {
+
+ if (fw->info.isp.sp.enable.in_frame != 0)
in = in_frame;
- }
- if (fw->info.isp.sp.enable.out_frame != 0) {
+
+ if (fw->info.isp.sp.enable.out_frame != 0)
vf = vf_frame;
- }
+
ia_css_pipe_get_firmwares_stage_desc(&stage_desc, binary,
out, in, vf, fw, binary_mode);
- err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc,
- &extra_stage);
+ err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+ &extra_stage);
if (err)
return err;
if (fw->info.isp.sp.enable.output != 0)
@@ -3173,9 +3103,8 @@ static int add_yuv_scaler_stage(
ia_css_pipe_get_generic_stage_desc(&stage_desc,
yuv_scaler_binary, out_frames, in_frame, vf_frame);
}
- err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc,
- pre_vf_pp_stage);
+ err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+ pre_vf_pp_stage);
if (err)
return err;
in_frame = (*pre_vf_pp_stage)->args.out_frame[0];
@@ -3233,9 +3162,8 @@ static int add_capture_pp_stage(
ia_css_pipe_get_generic_stage_desc(&stage_desc,
capture_pp_binary, out_frames, NULL, vf_frame);
}
- err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc,
- capture_pp_stage);
+ err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+ capture_pp_stage);
if (err)
return err;
err = add_firmwares(me, capture_pp_binary, pipe->output_stage, last_fw,
@@ -3274,7 +3202,8 @@ static void sh_css_setup_queues(void)
static int
init_vf_frameinfo_defaults(struct ia_css_pipe *pipe,
- struct ia_css_frame *vf_frame, unsigned int idx) {
+ struct ia_css_frame *vf_frame, unsigned int idx)
+{
int err = 0;
unsigned int thread_id;
enum sh_css_queue_id queue_id;
@@ -3439,7 +3368,8 @@ ia_css_get_crop_offsets(
static int
init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe,
- struct ia_css_frame *frame, enum ia_css_frame_format format) {
+ struct ia_css_frame *frame, enum ia_css_frame_format format)
+{
struct ia_css_frame *in_frame;
int err = 0;
unsigned int thread_id;
@@ -3480,7 +3410,8 @@ init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe,
static int
init_out_frameinfo_defaults(struct ia_css_pipe *pipe,
- struct ia_css_frame *out_frame, unsigned int idx) {
+ struct ia_css_frame *out_frame, unsigned int idx)
+{
int err = 0;
unsigned int thread_id;
enum sh_css_queue_id queue_id;
@@ -3587,9 +3518,8 @@ static int create_host_video_pipeline(struct ia_css_pipe *pipe)
ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
out_frames, NULL, NULL);
- err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc,
- &copy_stage);
+ err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+ &copy_stage);
if (err)
goto ERR;
in_frame = me->stages->args.out_frame[0];
@@ -3616,9 +3546,8 @@ static int create_host_video_pipeline(struct ia_css_pipe *pipe)
ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary,
out_frames, in_frame, vf_frame);
}
- err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc,
- &video_stage);
+ err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+ &video_stage);
if (err)
goto ERR;
@@ -3681,13 +3610,10 @@ static int create_host_video_pipeline(struct ia_css_pipe *pipe)
struct ia_css_frame *tmp_out_frame = NULL;
for (i = 0; i < num_yuv_scaler; i++) {
- if (is_output_stage[i]) {
- tmp_out_frame = out_frame;
- } else {
- tmp_out_frame = NULL;
- }
- err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, tmp_out_frame,
- NULL,
+ tmp_out_frame = is_output_stage[i] ? out_frame : NULL;
+
+ err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
+ tmp_out_frame, NULL,
&yuv_scaler_binary[i],
&yuv_scaler_stage);
@@ -3711,14 +3637,14 @@ ERR:
}
static int
-create_host_acc_pipeline(struct ia_css_pipe *pipe) {
+create_host_acc_pipeline(struct ia_css_pipe *pipe)
+{
int err = 0;
const struct ia_css_fw_info *fw;
unsigned int i;
IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
- if ((!pipe) || (!pipe->stream))
- {
+ if ((!pipe) || (!pipe->stream)) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
@@ -3729,15 +3655,13 @@ create_host_acc_pipeline(struct ia_css_pipe *pipe) {
pipe->pipeline.pipe_qos_config = 0;
fw = pipe->vf_stage;
- for (i = 0; fw; fw = fw->next)
- {
+ for (i = 0; fw; fw = fw->next) {
err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
if (err)
goto ERR;
}
- for (i = 0; i < pipe->config.num_acc_stages; i++)
- {
+ for (i = 0; i < pipe->config.num_acc_stages; i++) {
struct ia_css_fw_info *fw = pipe->config.acc_stages[i];
err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
@@ -3754,7 +3678,8 @@ ERR:
/* Create stages for preview */
static int
-create_host_preview_pipeline(struct ia_css_pipe *pipe) {
+create_host_preview_pipeline(struct ia_css_pipe *pipe)
+{
struct ia_css_pipeline_stage *copy_stage = NULL;
struct ia_css_pipeline_stage *preview_stage = NULL;
struct ia_css_pipeline_stage *vf_pp_stage = NULL;
@@ -3774,8 +3699,7 @@ create_host_preview_pipeline(struct ia_css_pipe *pipe) {
#endif
IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
- if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW))
- {
+ if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
@@ -3803,16 +3727,14 @@ create_host_preview_pipeline(struct ia_css_pipe *pipe) {
/* Construct in_frame info (only in case we have dynamic input */
need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
#endif
- if (need_in_frameinfo_memory)
- {
+ if (need_in_frameinfo_memory) {
err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame,
IA_CSS_FRAME_FORMAT_RAW);
if (err)
goto ERR;
in_frame = &me->in_frame;
- } else
- {
+ } else {
in_frame = NULL;
}
@@ -3826,14 +3748,12 @@ create_host_preview_pipeline(struct ia_css_pipe *pipe) {
if (pipe->pipe_settings.preview.vf_pp_binary.info)
vf_pp_binary = &pipe->pipe_settings.preview.vf_pp_binary;
- if (pipe->pipe_settings.preview.copy_binary.info)
- {
+ if (pipe->pipe_settings.preview.copy_binary.info) {
ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
out_frames, NULL, NULL);
- err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc,
- &copy_stage);
+ err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+ &copy_stage);
if (err)
goto ERR;
in_frame = me->stages->args.out_frame[0];
@@ -3842,42 +3762,37 @@ create_host_preview_pipeline(struct ia_css_pipe *pipe) {
/* When continuous is enabled, configure in_frame with the
* last pipe, which is the copy pipe.
*/
- if (continuous || !online) {
+ if (continuous || !online)
in_frame = pipe->stream->last_pipe->continuous_frames[0];
- }
+
#else
in_frame = pipe->continuous_frames[0];
#endif
}
- if (vf_pp_binary)
- {
+ if (vf_pp_binary) {
ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary,
out_frames, in_frame, NULL);
- } else
- {
+ } else {
ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary,
out_frames, in_frame, NULL);
}
- err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc,
- &preview_stage);
+ err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+ &preview_stage);
if (err)
goto ERR;
/* If we use copy iso preview, the input must be yuv iso raw */
preview_stage->args.copy_vf =
preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY;
preview_stage->args.copy_output = !preview_stage->args.copy_vf;
- if (preview_stage->args.copy_vf && !preview_stage->args.out_vf_frame)
- {
+ if (preview_stage->args.copy_vf && !preview_stage->args.out_vf_frame) {
/* in case of copy, use the vf frame as output frame */
preview_stage->args.out_vf_frame =
preview_stage->args.out_frame[0];
}
- if (vf_pp_binary)
- {
+ if (vf_pp_binary) {
if (preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY)
in_frame = preview_stage->args.out_vf_frame;
else
@@ -3917,7 +3832,8 @@ static void send_raw_frames(struct ia_css_pipe *pipe)
}
static int
-preview_start(struct ia_css_pipe *pipe) {
+preview_start(struct ia_css_pipe *pipe)
+{
int err = 0;
struct ia_css_pipe *copy_pipe, *capture_pipe;
struct ia_css_pipe *acc_pipe;
@@ -3927,8 +3843,7 @@ preview_start(struct ia_css_pipe *pipe) {
const struct ia_css_isp_parameters *params = NULL;
IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
- if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW))
- {
+ if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
@@ -3955,8 +3870,7 @@ preview_start(struct ia_css_pipe *pipe) {
ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
copy_ovrd = 1 << thread_id;
- if (pipe->stream->cont_capt)
- {
+ if (pipe->stream->cont_capt) {
ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
&thread_id);
copy_ovrd |= 1 << thread_id;
@@ -3969,8 +3883,7 @@ preview_start(struct ia_css_pipe *pipe) {
}
/* Construct and load the copy pipe */
- if (pipe->stream->config.continuous)
- {
+ if (pipe->stream->config.continuous) {
sh_css_sp_init_pipeline(&copy_pipe->pipeline,
IA_CSS_PIPE_ID_COPY,
(uint8_t)ia_css_pipe_get_pipe_num(copy_pipe),
@@ -3991,8 +3904,7 @@ preview_start(struct ia_css_pipe *pipe) {
}
/* Construct and load the capture pipe */
- if (pipe->stream->cont_capt)
- {
+ if (pipe->stream->cont_capt) {
sh_css_sp_init_pipeline(&capture_pipe->pipeline,
IA_CSS_PIPE_ID_CAPTURE,
(uint8_t)ia_css_pipe_get_pipe_num(capture_pipe),
@@ -4010,8 +3922,7 @@ preview_start(struct ia_css_pipe *pipe) {
params);
}
- if (acc_pipe)
- {
+ if (acc_pipe) {
sh_css_sp_init_pipeline(&acc_pipe->pipeline,
IA_CSS_PIPE_ID_ACC,
(uint8_t)ia_css_pipe_get_pipe_num(acc_pipe),
@@ -4037,7 +3948,8 @@ preview_start(struct ia_css_pipe *pipe) {
int
ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
- const struct ia_css_buffer *buffer) {
+ const struct ia_css_buffer *buffer)
+{
int return_err = 0;
unsigned int thread_id;
enum sh_css_queue_id queue_id;
@@ -4052,8 +3964,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer);
- if ((!pipe) || (!buffer))
- {
+ if ((!pipe) || (!buffer)) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
@@ -4062,8 +3973,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
/* following code will be enabled when IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME
is removed */
#if 0
- if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)
- {
+ if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
bool found_pipe = false;
for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
@@ -4077,8 +3987,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
if (!found_pipe)
return -EINVAL;
}
- if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME)
- {
+ if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
bool found_pipe = false;
for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
@@ -4099,36 +4008,31 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
assert(pipe_id < IA_CSS_PIPE_ID_NUM);
assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
- if ((buf_type == IA_CSS_BUFFER_TYPE_INVALID) ||
- (buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE) ||
- (pipe_id >= IA_CSS_PIPE_ID_NUM))
- {
+ if (buf_type == IA_CSS_BUFFER_TYPE_INVALID ||
+ buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE ||
+ pipe_id >= IA_CSS_PIPE_ID_NUM) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
- if (!ret_err)
- {
+ if (!ret_err) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id);
- if (!ret_err)
- {
+ if (!ret_err) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
- if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES))
- {
+ if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
- if (!sh_css_sp_is_running())
- {
+ if (!sh_css_sp_is_running()) {
IA_CSS_LOG("SP is not running!");
IA_CSS_LEAVE_ERR(-EBUSY);
/* SP is not running. The queues are not valid */
@@ -4146,36 +4050,32 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
ddr_buffer.cookie_ptr = buffer->driver_cookie;
ddr_buffer.timing_data = buffer->timing_data;
- if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS)
- {
+ if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS) {
if (!buffer->data.stats_3a) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_3a);
ddr_buffer.payload.s3a = *buffer->data.stats_3a;
- } else if (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS)
- {
+ } else if (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS) {
if (!buffer->data.stats_dvs) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_dvs);
ddr_buffer.payload.dis = *buffer->data.stats_dvs;
- } else if (buf_type == IA_CSS_BUFFER_TYPE_METADATA)
- {
+ } else if (buf_type == IA_CSS_BUFFER_TYPE_METADATA) {
if (!buffer->data.metadata) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.metadata);
ddr_buffer.payload.metadata = *buffer->data.metadata;
- } else if ((buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME)
- || (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)
- || (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME)
- || (buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME)
- || (buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME))
- {
+ } else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME ||
+ buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
+ buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME ||
+ buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME ||
+ buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME) {
if (!buffer->data.frame) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
@@ -4207,22 +4107,17 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
/* TODO: change next to correct pool for optimization */
ia_css_rmgr_acq_vbuf(hmm_buffer_pool, &h_vbuf);
- assert(h_vbuf);
- assert(h_vbuf->vptr != 0x0);
-
- if ((!h_vbuf) || (h_vbuf->vptr == 0x0))
- {
+ if ((!h_vbuf) || (h_vbuf->vptr == 0x0)) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
hmm_store(h_vbuf->vptr,
- (void *)(&ddr_buffer),
- sizeof(struct sh_css_hmm_buffer));
- if ((buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS)
- || (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS)
- || (buf_type == IA_CSS_BUFFER_TYPE_LACE_STATISTICS))
- {
+ (void *)(&ddr_buffer),
+ sizeof(struct sh_css_hmm_buffer));
+ if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS ||
+ buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS ||
+ buf_type == IA_CSS_BUFFER_TYPE_LACE_STATISTICS) {
if (!pipeline) {
ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf);
IA_CSS_LOG("pipeline is empty!");
@@ -4240,19 +4135,18 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
(uint32_t)h_vbuf->vptr);
}
}
- } else if ((buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME)
- || (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)
- || (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME)
- || (buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME)
- || (buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME)
- || (buf_type == IA_CSS_BUFFER_TYPE_METADATA))
- {
+ } else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME ||
+ buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
+ buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME ||
+ buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME ||
+ buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME ||
+ buf_type == IA_CSS_BUFFER_TYPE_METADATA) {
return_err = ia_css_bufq_enqueue_buffer(thread_id,
queue_id,
(uint32_t)h_vbuf->vptr);
#if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS)
- if (!(return_err) &&
- (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)) {
+ if (!return_err &&
+ buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
IA_CSS_LOG("pfp: enqueued OF %d to q %d thread %d",
ddr_buffer.payload.frame.frame_data,
queue_id, thread_id);
@@ -4260,8 +4154,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
#endif
}
- if (!return_err)
- {
+ if (!return_err) {
if (sh_css_hmm_buffer_record_acquire(
h_vbuf, buf_type,
HOST_ADDRESS(ddr_buffer.kernel_ptr))) {
@@ -4276,8 +4169,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
* Tell the SP which queues are not empty,
* by sending the software event.
*/
- if (!return_err)
- {
+ if (!return_err) {
if (!sh_css_sp_is_running()) {
/* SP is not running. The queues are not valid */
IA_CSS_LOG("SP is not running!");
@@ -4289,8 +4181,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
(uint8_t)thread_id,
queue_id,
0);
- } else
- {
+ } else {
ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf);
IA_CSS_ERROR("buffer not enqueued");
}
@@ -4305,7 +4196,8 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
*/
int
ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
- struct ia_css_buffer *buffer) {
+ struct ia_css_buffer *buffer)
+{
int return_err;
enum sh_css_queue_id queue_id;
ia_css_ptr ddr_buffer_addr = (ia_css_ptr)0;
@@ -4318,8 +4210,7 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer);
- if ((!pipe) || (!buffer))
- {
+ if ((!pipe) || (!buffer)) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
@@ -4333,27 +4224,23 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
ddr_buffer.kernel_ptr = 0;
ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
- if (!ret_err)
- {
+ if (!ret_err) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id);
- if (!ret_err)
- {
+ if (!ret_err) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
- if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES))
- {
+ if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
- if (!sh_css_sp_is_running())
- {
+ if (!sh_css_sp_is_running()) {
IA_CSS_LOG("SP is not running!");
IA_CSS_LEAVE_ERR(-EBUSY);
/* SP is not running. The queues are not valid */
@@ -4363,8 +4250,7 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
return_err = ia_css_bufq_dequeue_buffer(queue_id,
(uint32_t *)&ddr_buffer_addr);
- if (!return_err)
- {
+ if (!return_err) {
struct ia_css_frame *frame;
struct sh_css_hmm_buffer_record *hmm_buffer_record = NULL;
@@ -4389,8 +4275,8 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
}
hmm_load(ddr_buffer_addr,
- &ddr_buffer,
- sizeof(struct sh_css_hmm_buffer));
+ &ddr_buffer,
+ sizeof(struct sh_css_hmm_buffer));
/* if the kernel_ptr is 0 or an invalid, return an error.
* do not access the buffer via the kernal_ptr.
@@ -4412,8 +4298,8 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
buffer->driver_cookie = ddr_buffer.cookie_ptr;
buffer->timing_data = ddr_buffer.timing_data;
- if ((buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) ||
- (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME)) {
+ if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
+ buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
buffer->isys_eof_clock_tick.ticks = ddr_buffer.isys_eof_clock_tick;
}
@@ -4506,8 +4392,7 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
* Tell the SP which queues are not full,
* by sending the software event.
*/
- if (!return_err)
- {
+ if (!return_err) {
if (!sh_css_sp_is_running()) {
IA_CSS_LOG("SP is not running!");
IA_CSS_LEAVE_ERR(-EBUSY);
@@ -4556,12 +4441,14 @@ static enum ia_css_event_type convert_event_sp_to_host_domain[] = {
};
int
-ia_css_dequeue_event(struct ia_css_event *event) {
+ia_css_dequeue_event(struct ia_css_event *event)
+{
return ia_css_dequeue_psys_event(event);
}
int
-ia_css_dequeue_psys_event(struct ia_css_event *event) {
+ia_css_dequeue_psys_event(struct ia_css_event *event)
+{
enum ia_css_pipe_id pipe_id = 0;
u8 payload[4] = {0, 0, 0, 0};
int ret_err;
@@ -4576,11 +4463,9 @@ ia_css_dequeue_psys_event(struct ia_css_event *event) {
if (!event)
return -EINVAL;
+ /* SP is not running. The queues are not valid */
if (!sh_css_sp_is_running())
- {
- /* SP is not running. The queues are not valid */
return -EBUSY;
- }
/* dequeue the event (if any) from the psys event queue */
ret_err = ia_css_bufq_dequeue_psys_event(payload);
@@ -4607,8 +4492,7 @@ ia_css_dequeue_psys_event(struct ia_css_event *event) {
event->timer_code = 0;
event->timer_subcode = 0;
- if (event->type == IA_CSS_EVENT_TYPE_TIMER)
- {
+ if (event->type == IA_CSS_EVENT_TYPE_TIMER) {
/* timer event ??? get the 2nd event and decode the data into the event struct */
u32 tmp_data;
/* 1st event: LSB 16-bit timer data and code */
@@ -4632,37 +4516,32 @@ ia_css_dequeue_psys_event(struct ia_css_event *event) {
tmp_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8));
event->timer_data |= (tmp_data << 16);
event->timer_subcode = payload[2];
- }
+ } else {
/* It's a non timer event. So clear first half of the timer event data.
* If the second part of the TIMER event is not received, we discard
* the first half of the timer data and process the non timer event without
* affecting the flow. So the non timer event falls through
* the code. */
- else {
event->timer_data = 0;
event->timer_code = 0;
event->timer_subcode = 0;
IA_CSS_ERROR("Missing 2nd timer event. Timer event discarded");
}
}
- if (event->type == IA_CSS_EVENT_TYPE_PORT_EOF)
- {
+ if (event->type == IA_CSS_EVENT_TYPE_PORT_EOF) {
event->port = (enum mipi_port_id)payload[1];
event->exp_id = payload[3];
- } else if (event->type == IA_CSS_EVENT_TYPE_FW_WARNING)
- {
+ } else if (event->type == IA_CSS_EVENT_TYPE_FW_WARNING) {
event->fw_warning = (enum ia_css_fw_warning)payload[1];
/* exp_id is only available in these warning types */
if (event->fw_warning == IA_CSS_FW_WARNING_EXP_ID_LOCKED ||
event->fw_warning == IA_CSS_FW_WARNING_TAG_EXP_ID_FAILED)
event->exp_id = payload[3];
- } else if (event->type == IA_CSS_EVENT_TYPE_FW_ASSERT)
- {
+ } else if (event->type == IA_CSS_EVENT_TYPE_FW_ASSERT) {
event->fw_assert_module_id = payload[1]; /* module */
event->fw_assert_line_no = (payload[2] << 8) + payload[3];
/* payload[2] is line_no>>8, payload[3] is line_no&0xff */
- } else if (event->type != IA_CSS_EVENT_TYPE_TIMER)
- {
+ } else if (event->type != IA_CSS_EVENT_TYPE_TIMER) {
/* pipe related events.
* payload[1] contains the pipe_num,
* payload[2] contains the pipe_id. These are different. */
@@ -4712,7 +4591,8 @@ ia_css_dequeue_psys_event(struct ia_css_event *event) {
}
int
-ia_css_dequeue_isys_event(struct ia_css_event *event) {
+ia_css_dequeue_isys_event(struct ia_css_event *event)
+{
u8 payload[4] = {0, 0, 0, 0};
int err = 0;
@@ -4722,11 +4602,9 @@ ia_css_dequeue_isys_event(struct ia_css_event *event) {
if (!event)
return -EINVAL;
+ /* SP is not running. The queues are not valid */
if (!sh_css_sp_is_running())
- {
- /* SP is not running. The queues are not valid */
return -EBUSY;
- }
err = ia_css_bufq_dequeue_isys_event(payload);
if (err)
@@ -4759,7 +4637,8 @@ acc_start(struct ia_css_pipe *pipe)
}
static int
-sh_css_pipe_start(struct ia_css_stream *stream) {
+sh_css_pipe_start(struct ia_css_stream *stream)
+{
int err = 0;
struct ia_css_pipe *pipe;
@@ -4768,22 +4647,19 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
IA_CSS_ENTER_PRIVATE("stream = %p", stream);
- if (!stream)
- {
+ if (!stream) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
pipe = stream->last_pipe;
- if (!pipe)
- {
+ if (!pipe) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
pipe_id = pipe->mode;
- if (stream->started)
- {
+ if (stream->started) {
IA_CSS_WARNING("Cannot start stream that is already started");
IA_CSS_LEAVE_ERR(err);
return err;
@@ -4791,8 +4667,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
pipe->stop_requested = false;
- switch (pipe_id)
- {
+ switch (pipe_id) {
case IA_CSS_PIPE_ID_PREVIEW:
err = preview_start(pipe);
break;
@@ -4812,8 +4687,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
err = -EINVAL;
}
/* DH regular multi pipe - not continuous mode: start the next pipes too */
- if (!stream->config.continuous)
- {
+ if (!stream->config.continuous) {
int i;
for (i = 1; i < stream->num_pipes && 0 == err ; i++) {
@@ -4843,8 +4717,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
}
}
}
- if (err)
- {
+ if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
}
@@ -4854,8 +4727,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
* don't use ISP parameters anyway. So this should be okay.
* The SP binary (jpeg) copy does not use any parameters.
*/
- if (!copy_on_sp(pipe))
- {
+ if (!copy_on_sp(pipe)) {
sh_css_invalidate_params(stream);
err = sh_css_param_update_isp_params(pipe,
stream->isp_params_configs, true, NULL);
@@ -4869,8 +4741,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
- if (!sh_css_sp_is_running())
- {
+ if (!sh_css_sp_is_running()) {
IA_CSS_LEAVE_ERR_PRIVATE(-EBUSY);
/* SP is not running. The queues are not valid */
return -EBUSY;
@@ -4879,8 +4750,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
(uint8_t)thread_id, 0, 0);
/* DH regular multi pipe - not continuous mode: enqueue event to the next pipes too */
- if (!stream->config.continuous)
- {
+ if (!stream->config.continuous) {
int i;
for (i = 1; i < stream->num_pipes; i++) {
@@ -4894,8 +4764,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
}
/* in case of continuous capture mode, we also start capture thread and copy thread*/
- if (pipe->stream->config.continuous)
- {
+ if (pipe->stream->config.continuous) {
struct ia_css_pipe *copy_pipe = NULL;
if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
@@ -4914,8 +4783,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
IA_CSS_PSYS_SW_EVENT_START_STREAM,
(uint8_t)thread_id, 0, 0);
}
- if (pipe->stream->cont_capt)
- {
+ if (pipe->stream->cont_capt) {
struct ia_css_pipe *capture_pipe = NULL;
if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
@@ -4936,8 +4804,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) {
}
/* in case of PREVIEW mode, check whether QOS acc_pipe is available, then start the qos pipe */
- if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
- {
+ if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
struct ia_css_pipe *acc_pipe = NULL;
acc_pipe = pipe->pipe_settings.preview.acc_pipe;
@@ -4988,7 +4855,8 @@ sh_css_continuous_is_enabled(uint8_t pipe_num)
/* ISP2400 */
int
ia_css_stream_get_max_buffer_depth(struct ia_css_stream *stream,
- int *buffer_depth) {
+ int *buffer_depth)
+{
if (!buffer_depth)
return -EINVAL;
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_max_buffer_depth() enter: void\n");
@@ -4998,7 +4866,8 @@ ia_css_stream_get_max_buffer_depth(struct ia_css_stream *stream,
}
int
-ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth) {
+ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth)
+{
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_set_buffer_depth() enter: num_frames=%d\n", buffer_depth);
(void)stream;
if (buffer_depth > NUM_CONTINUOUS_FRAMES || buffer_depth < 1)
@@ -5012,7 +4881,8 @@ ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth) {
/* ISP2401 */
int
ia_css_stream_get_buffer_depth(struct ia_css_stream *stream,
- int *buffer_depth) {
+ int *buffer_depth)
+{
if (!buffer_depth)
return -EINVAL;
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_buffer_depth() enter: void\n");
@@ -5036,18 +4906,14 @@ sh_css_pipes_stop(struct ia_css_stream *stream)
enum ia_css_pipe_id main_pipe_id;
int i;
- assert(stream);
- if (!stream)
- {
+ if (!stream) {
IA_CSS_LOG("stream does NOT exist!");
err = -EINVAL;
goto ERR;
}
main_pipe = stream->last_pipe;
- assert(main_pipe);
- if (!main_pipe)
- {
+ if (!main_pipe) {
IA_CSS_LOG("main_pipe does NOT exist!");
err = -EINVAL;
goto ERR;
@@ -5060,11 +4926,10 @@ sh_css_pipes_stop(struct ia_css_stream *stream)
* Stop all "ia_css_pipe" instances in this target
* "ia_css_stream" instance.
*/
- for (i = 0; i < stream->num_pipes; i++)
- {
+ for (i = 0; i < stream->num_pipes; i++) {
/* send the "stop" request to the "ia_css_pipe" instance */
IA_CSS_LOG("Send the stop-request to the pipe: pipe_id=%d",
- stream->pipes[i]->pipeline.pipe_id);
+ stream->pipes[i]->pipeline.pipe_id);
err = ia_css_pipeline_request_stop(&stream->pipes[i]->pipeline);
/*
@@ -5095,8 +4960,7 @@ sh_css_pipes_stop(struct ia_css_stream *stream)
*
* We need to stop this "Copy Pipe", as well.
*/
- if (main_pipe->stream->config.continuous)
- {
+ if (main_pipe->stream->config.continuous) {
struct ia_css_pipe *copy_pipe = NULL;
/* get the reference to "Copy Pipe" */
@@ -5106,7 +4970,6 @@ sh_css_pipes_stop(struct ia_css_stream *stream)
copy_pipe = main_pipe->pipe_settings.video.copy_pipe;
/* return the error code if "Copy Pipe" does NOT exist */
- assert(copy_pipe);
if (!copy_pipe) {
IA_CSS_LOG("Copy Pipe does NOT exist!");
err = -EINVAL;
@@ -5115,7 +4978,7 @@ sh_css_pipes_stop(struct ia_css_stream *stream)
/* send the "stop" request to "Copy Pipe" */
IA_CSS_LOG("Send the stop-request to the pipe: pipe_id=%d",
- copy_pipe->pipeline.pipe_id);
+ copy_pipe->pipeline.pipe_id);
err = ia_css_pipeline_request_stop(&copy_pipe->pipeline);
}
@@ -5141,7 +5004,6 @@ sh_css_pipes_have_stopped(struct ia_css_stream *stream)
int i;
- assert(stream);
if (!stream) {
IA_CSS_LOG("stream does NOT exist!");
rval = false;
@@ -5149,7 +5011,6 @@ sh_css_pipes_have_stopped(struct ia_css_stream *stream)
}
main_pipe = stream->last_pipe;
- assert(main_pipe);
if (!main_pipe) {
IA_CSS_LOG("main_pipe does NOT exist!");
@@ -5190,7 +5051,6 @@ sh_css_pipes_have_stopped(struct ia_css_stream *stream)
copy_pipe = main_pipe->pipe_settings.video.copy_pipe;
/* return if "Copy Pipe" does NOT exist */
- assert(copy_pipe);
if (!copy_pipe) {
IA_CSS_LOG("Copy Pipe does NOT exist!");
@@ -5272,8 +5132,7 @@ sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe,
binary = ia_css_pipe_get_shading_correction_binary(pipe);
- if (binary)
- {
+ if (binary) {
err = ia_css_binary_get_shading_info(binary,
IA_CSS_SHADING_CORRECTION_TYPE_1,
pipe->required_bds_factor,
@@ -5283,8 +5142,7 @@ sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe,
/* Other function calls can be added here when other shading correction types will be added
* in the future.
*/
- } else
- {
+ } else {
/* When the pipe does not have a binary which has the shading
* correction, this function does not need to fill the shading
* information. It is not a error case, and then
@@ -5297,7 +5155,8 @@ sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe,
static int
sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe,
- struct ia_css_grid_info *info) {
+ struct ia_css_grid_info *info)
+{
int err = 0;
struct ia_css_binary *binary = NULL;
@@ -5308,30 +5167,27 @@ sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe,
binary = ia_css_pipe_get_s3a_binary(pipe);
- if (binary)
- {
+ if (binary) {
err = ia_css_binary_3a_grid_info(binary, info, pipe);
if (err)
goto ERR;
- } else
+ } else {
memset(&info->s3a_grid, 0, sizeof(info->s3a_grid));
+ }
binary = ia_css_pipe_get_sdis_binary(pipe);
- if (binary)
- {
+ if (binary) {
ia_css_binary_dvs_grid_info(binary, info, pipe);
ia_css_binary_dvs_stat_grid_info(binary, info, pipe);
- } else
- {
+ } else {
memset(&info->dvs_grid.dvs_grid_info, 0,
sizeof(info->dvs_grid.dvs_grid_info));
memset(&info->dvs_grid.dvs_stat_grid_info, 0,
sizeof(info->dvs_grid.dvs_stat_grid_info));
}
- if (binary)
- {
+ if (binary) {
/* copy pipe does not have ISP binary*/
info->isp_in_width = binary->internal_frame_info.res.width;
info->isp_in_height = binary->internal_frame_info.res.height;
@@ -5351,7 +5207,8 @@ ERR :
*/
static int
ia_css_pipe_check_format(struct ia_css_pipe *pipe,
- enum ia_css_frame_format format) {
+ enum ia_css_frame_format format)
+{
const enum ia_css_frame_format *supported_formats;
int number_of_formats;
int found = 0;
@@ -5359,8 +5216,7 @@ ia_css_pipe_check_format(struct ia_css_pipe *pipe,
IA_CSS_ENTER_PRIVATE("");
- if (NULL == pipe || NULL == pipe->pipe_settings.video.video_binary.info)
- {
+ if (NULL == pipe || NULL == pipe->pipe_settings.video.video_binary.info) {
IA_CSS_ERROR("Pipe or binary info is not set");
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
@@ -5369,23 +5225,19 @@ ia_css_pipe_check_format(struct ia_css_pipe *pipe,
supported_formats = pipe->pipe_settings.video.video_binary.info->output_formats;
number_of_formats = sizeof(pipe->pipe_settings.video.video_binary.info->output_formats) / sizeof(enum ia_css_frame_format);
- for (i = 0; i < number_of_formats && !found; i++)
- {
+ for (i = 0; i < number_of_formats && !found; i++) {
if (supported_formats[i] == format) {
found = 1;
break;
}
}
- if (!found)
- {
+ if (!found) {
IA_CSS_ERROR("Requested format is not supported by binary");
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
- } else
- {
- IA_CSS_LEAVE_ERR_PRIVATE(0);
- return 0;
}
+ IA_CSS_LEAVE_ERR_PRIVATE(0);
+ return 0;
}
static int load_video_binaries(struct ia_css_pipe *pipe)
@@ -5528,10 +5380,10 @@ static int load_video_binaries(struct ia_css_pipe *pipe)
&mycs->video_binary);
if (err) {
- if (video_vf_info) {
- /* This will do another video binary lookup later for YUV_LINE format*/
+ /* This will do another video binary lookup later for YUV_LINE format*/
+ if (video_vf_info)
need_vf_pp = true;
- } else
+ else
return err;
} else if (video_vf_info) {
/* The first video binary lookup is successful, but we may
@@ -5694,13 +5546,13 @@ static int load_video_binaries(struct ia_css_pipe *pipe)
}
static int
-unload_video_binaries(struct ia_css_pipe *pipe) {
+unload_video_binaries(struct ia_css_pipe *pipe)
+{
unsigned int i;
IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
- if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO))
- {
+ if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
@@ -5850,31 +5702,29 @@ static int
sh_css_pipe_configure_viewfinder(struct ia_css_pipe *pipe, unsigned int width,
unsigned int height, unsigned int min_width,
enum ia_css_frame_format format,
- unsigned int idx) {
+ unsigned int idx)
+{
int err = 0;
IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, min_width = %d, format = %d, idx = %d\n",
pipe, width, height, min_width, format, idx);
- if (!pipe)
- {
+ if (!pipe) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
err = ia_css_util_check_res(width, height);
- if (err)
- {
+ if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
}
if (pipe->vf_output_info[idx].res.width != width ||
pipe->vf_output_info[idx].res.height != height ||
pipe->vf_output_info[idx].format != format)
- {
ia_css_frame_info_init(&pipe->vf_output_info[idx], width, height,
format, min_width);
- }
+
IA_CSS_LEAVE_ERR_PRIVATE(0);
return 0;
}
@@ -5955,7 +5805,7 @@ static bool need_capt_ldc(
}
static int set_num_primary_stages(unsigned int *num,
- enum ia_css_pipe_version version)
+ enum ia_css_pipe_version version)
{
int err = 0;
@@ -6155,10 +6005,13 @@ static int load_primary_binaries(
capt_pp_in_info = &prim_out_info;
ia_css_pipe_get_capturepp_binarydesc(pipe,
- &capture_pp_descr, capt_pp_in_info,
- &capt_pp_out_info, &vf_info);
+ &capture_pp_descr,
+ capt_pp_in_info,
+ &capt_pp_out_info,
+ &vf_info);
+
err = ia_css_binary_find(&capture_pp_descr,
- &mycs->capture_pp_binary);
+ &mycs->capture_pp_binary);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
@@ -6168,11 +6021,12 @@ static int load_primary_binaries(
struct ia_css_binary_descr capt_ldc_descr;
ia_css_pipe_get_ldc_binarydesc(pipe,
- &capt_ldc_descr, &prim_out_info,
- &capt_ldc_out_info);
+ &capt_ldc_descr,
+ &prim_out_info,
+ &capt_ldc_out_info);
err = ia_css_binary_find(&capt_ldc_descr,
- &mycs->capture_ldc_binary);
+ &mycs->capture_ldc_binary);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
@@ -6189,8 +6043,9 @@ static int load_primary_binaries(
if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] &&
(i == mycs->num_primary_stage - 1))
local_vf_info = &vf_info;
- ia_css_pipe_get_primary_binarydesc(pipe, &prim_descr[i], &prim_in_info,
- &prim_out_info, local_vf_info, i);
+ ia_css_pipe_get_primary_binarydesc(pipe, &prim_descr[i],
+ &prim_in_info, &prim_out_info,
+ local_vf_info, i);
err = ia_css_binary_find(&prim_descr[i], &mycs->primary_binary[i]);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -6242,8 +6097,8 @@ static int load_primary_binaries(
/* ISP Copy */
if (need_isp_copy_binary) {
err = load_copy_binary(pipe,
- &mycs->copy_binary,
- &mycs->primary_binary[0]);
+ &mycs->copy_binary,
+ &mycs->primary_binary[0]);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
@@ -6254,7 +6109,8 @@ static int load_primary_binaries(
}
static int
-allocate_delay_frames(struct ia_css_pipe *pipe) {
+allocate_delay_frames(struct ia_css_pipe *pipe)
+{
unsigned int num_delay_frames = 0, i = 0;
unsigned int dvs_frame_delay = 0;
struct ia_css_frame_info ref_info;
@@ -6264,8 +6120,7 @@ allocate_delay_frames(struct ia_css_pipe *pipe) {
IA_CSS_ENTER_PRIVATE("");
- if (!pipe)
- {
+ if (!pipe) {
IA_CSS_ERROR("Invalid args - pipe %p", pipe);
return -EINVAL;
}
@@ -6276,8 +6131,7 @@ allocate_delay_frames(struct ia_css_pipe *pipe) {
if (dvs_frame_delay > 0)
num_delay_frames = dvs_frame_delay + 1;
- switch (mode)
- {
+ switch (mode) {
case IA_CSS_PIPE_ID_CAPTURE: {
struct ia_css_capture_settings *mycs_capture = &pipe->pipe_settings.capture;
(void)mycs_capture;
@@ -6329,8 +6183,7 @@ allocate_delay_frames(struct ia_css_pipe *pipe) {
ref_info.raw_bit_depth = SH_CSS_REF_BIT_DEPTH;
assert(num_delay_frames <= MAX_NUM_VIDEO_DELAY_FRAMES);
- for (i = 0; i < num_delay_frames; i++)
- {
+ for (i = 0; i < num_delay_frames; i++) {
err = ia_css_frame_allocate_from_info(&delay_frames[i], &ref_info);
if (err)
return err;
@@ -6339,8 +6192,8 @@ allocate_delay_frames(struct ia_css_pipe *pipe) {
return 0;
}
-static int load_advanced_binaries(
- struct ia_css_pipe *pipe) {
+static int load_advanced_binaries(struct ia_css_pipe *pipe)
+{
struct ia_css_frame_info pre_in_info, gdc_in_info,
post_in_info, post_out_info,
vf_info, *vf_pp_in_info, *pipe_out_info,
@@ -6353,7 +6206,7 @@ static int load_advanced_binaries(
assert(pipe);
assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
- pipe->mode == IA_CSS_PIPE_ID_COPY);
+ pipe->mode == IA_CSS_PIPE_ID_COPY);
if (pipe->pipe_settings.capture.pre_isp_binary.info)
return 0;
pipe_out_info = &pipe->output_info[0];
@@ -6366,17 +6219,18 @@ static int load_advanced_binaries(
need_pp = need_capture_pp(pipe);
ia_css_frame_info_set_format(&vf_info,
- IA_CSS_FRAME_FORMAT_YUV_LINE);
+ IA_CSS_FRAME_FORMAT_YUV_LINE);
/* we build up the pipeline starting at the end */
/* Capture post-processing */
if (need_pp) {
struct ia_css_binary_descr capture_pp_descr;
- ia_css_pipe_get_capturepp_binarydesc(pipe,
- &capture_pp_descr, &post_out_info, pipe_out_info, &vf_info);
+ ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr,
+ &post_out_info,
+ pipe_out_info, &vf_info);
err = ia_css_binary_find(&capture_pp_descr,
- &pipe->pipe_settings.capture.capture_pp_binary);
+ &pipe->pipe_settings.capture.capture_pp_binary);
if (err)
return err;
} else {
@@ -6387,10 +6241,11 @@ static int load_advanced_binaries(
{
struct ia_css_binary_descr post_gdc_descr;
- ia_css_pipe_get_post_gdc_binarydesc(pipe,
- &post_gdc_descr, &post_in_info, &post_out_info, &vf_info);
+ ia_css_pipe_get_post_gdc_binarydesc(pipe, &post_gdc_descr,
+ &post_in_info,
+ &post_out_info, &vf_info);
err = ia_css_binary_find(&post_gdc_descr,
- &pipe->pipe_settings.capture.post_isp_binary);
+ &pipe->pipe_settings.capture.post_isp_binary);
if (err)
return err;
}
@@ -6400,9 +6255,9 @@ static int load_advanced_binaries(
struct ia_css_binary_descr gdc_descr;
ia_css_pipe_get_gdc_binarydesc(pipe, &gdc_descr, &gdc_in_info,
- &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
+ &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
err = ia_css_binary_find(&gdc_descr,
- &pipe->pipe_settings.capture.anr_gdc_binary);
+ &pipe->pipe_settings.capture.anr_gdc_binary);
if (err)
return err;
}
@@ -6414,9 +6269,9 @@ static int load_advanced_binaries(
struct ia_css_binary_descr pre_gdc_descr;
ia_css_pipe_get_pre_gdc_binarydesc(pipe, &pre_gdc_descr, &pre_in_info,
- &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
+ &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
err = ia_css_binary_find(&pre_gdc_descr,
- &pipe->pipe_settings.capture.pre_isp_binary);
+ &pipe->pipe_settings.capture.pre_isp_binary);
if (err)
return err;
}
@@ -6438,7 +6293,7 @@ static int load_advanced_binaries(
ia_css_pipe_get_vfpp_binarydesc(pipe,
&vf_pp_descr, vf_pp_in_info, pipe_vf_out_info);
err = ia_css_binary_find(&vf_pp_descr,
- &pipe->pipe_settings.capture.vf_pp_binary);
+ &pipe->pipe_settings.capture.vf_pp_binary);
if (err)
return err;
}
@@ -6450,14 +6305,14 @@ static int load_advanced_binaries(
#endif
if (need_isp_copy)
load_copy_binary(pipe,
- &pipe->pipe_settings.capture.copy_binary,
- &pipe->pipe_settings.capture.pre_isp_binary);
+ &pipe->pipe_settings.capture.copy_binary,
+ &pipe->pipe_settings.capture.pre_isp_binary);
return err;
}
-static int load_bayer_isp_binaries(
- struct ia_css_pipe *pipe) {
+static int load_bayer_isp_binaries(struct ia_css_pipe *pipe)
+{
struct ia_css_frame_info pre_isp_in_info, *pipe_out_info;
int err = 0;
struct ia_css_binary_descr pre_de_descr;
@@ -6465,7 +6320,7 @@ static int load_bayer_isp_binaries(
IA_CSS_ENTER_PRIVATE("");
assert(pipe);
assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
- pipe->mode == IA_CSS_PIPE_ID_COPY);
+ pipe->mode == IA_CSS_PIPE_ID_COPY);
pipe_out_info = &pipe->output_info[0];
if (pipe->pipe_settings.capture.pre_isp_binary.info)
@@ -6476,17 +6331,17 @@ static int load_bayer_isp_binaries(
return err;
ia_css_pipe_get_pre_de_binarydesc(pipe, &pre_de_descr,
- &pre_isp_in_info,
- pipe_out_info);
+ &pre_isp_in_info,
+ pipe_out_info);
err = ia_css_binary_find(&pre_de_descr,
- &pipe->pipe_settings.capture.pre_isp_binary);
+ &pipe->pipe_settings.capture.pre_isp_binary);
return err;
}
-static int load_low_light_binaries(
- struct ia_css_pipe *pipe) {
+static int load_low_light_binaries(struct ia_css_pipe *pipe)
+{
struct ia_css_frame_info pre_in_info, anr_in_info,
post_in_info, post_out_info,
vf_info, *pipe_vf_out_info, *pipe_out_info,
@@ -6498,7 +6353,7 @@ static int load_low_light_binaries(
IA_CSS_ENTER_PRIVATE("");
assert(pipe);
assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
- pipe->mode == IA_CSS_PIPE_ID_COPY);
+ pipe->mode == IA_CSS_PIPE_ID_COPY);
if (pipe->pipe_settings.capture.pre_isp_binary.info)
return 0;
@@ -6513,17 +6368,18 @@ static int load_low_light_binaries(
need_pp = need_capture_pp(pipe);
ia_css_frame_info_set_format(&vf_info,
- IA_CSS_FRAME_FORMAT_YUV_LINE);
+ IA_CSS_FRAME_FORMAT_YUV_LINE);
/* we build up the pipeline starting at the end */
/* Capture post-processing */
if (need_pp) {
struct ia_css_binary_descr capture_pp_descr;
- ia_css_pipe_get_capturepp_binarydesc(pipe,
- &capture_pp_descr, &post_out_info, pipe_out_info, &vf_info);
+ ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr,
+ &post_out_info,
+ pipe_out_info, &vf_info);
err = ia_css_binary_find(&capture_pp_descr,
- &pipe->pipe_settings.capture.capture_pp_binary);
+ &pipe->pipe_settings.capture.capture_pp_binary);
if (err)
return err;
} else {
@@ -6537,7 +6393,7 @@ static int load_low_light_binaries(
ia_css_pipe_get_post_anr_binarydesc(pipe,
&post_anr_descr, &post_in_info, &post_out_info, &vf_info);
err = ia_css_binary_find(&post_anr_descr,
- &pipe->pipe_settings.capture.post_isp_binary);
+ &pipe->pipe_settings.capture.post_isp_binary);
if (err)
return err;
}
@@ -6547,9 +6403,9 @@ static int load_low_light_binaries(
struct ia_css_binary_descr anr_descr;
ia_css_pipe_get_anr_binarydesc(pipe, &anr_descr, &anr_in_info,
- &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
+ &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
err = ia_css_binary_find(&anr_descr,
- &pipe->pipe_settings.capture.anr_gdc_binary);
+ &pipe->pipe_settings.capture.anr_gdc_binary);
if (err)
return err;
}
@@ -6561,9 +6417,9 @@ static int load_low_light_binaries(
struct ia_css_binary_descr pre_anr_descr;
ia_css_pipe_get_pre_anr_binarydesc(pipe, &pre_anr_descr, &pre_in_info,
- &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
+ &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
err = ia_css_binary_find(&pre_anr_descr,
- &pipe->pipe_settings.capture.pre_isp_binary);
+ &pipe->pipe_settings.capture.pre_isp_binary);
if (err)
return err;
}
@@ -6582,10 +6438,10 @@ static int load_low_light_binaries(
{
struct ia_css_binary_descr vf_pp_descr;
- ia_css_pipe_get_vfpp_binarydesc(pipe,
- &vf_pp_descr, vf_pp_in_info, pipe_vf_out_info);
+ ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr,
+ vf_pp_in_info, pipe_vf_out_info);
err = ia_css_binary_find(&vf_pp_descr,
- &pipe->pipe_settings.capture.vf_pp_binary);
+ &pipe->pipe_settings.capture.vf_pp_binary);
if (err)
return err;
}
@@ -6597,8 +6453,8 @@ static int load_low_light_binaries(
#endif
if (need_isp_copy)
err = load_copy_binary(pipe,
- &pipe->pipe_settings.capture.copy_binary,
- &pipe->pipe_settings.capture.pre_isp_binary);
+ &pipe->pipe_settings.capture.copy_binary,
+ &pipe->pipe_settings.capture.pre_isp_binary);
return err;
}
@@ -6623,15 +6479,15 @@ static bool copy_on_sp(struct ia_css_pipe *pipe)
return rval;
}
-static int load_capture_binaries(
- struct ia_css_pipe *pipe) {
+static int load_capture_binaries(struct ia_css_pipe *pipe)
+{
int err = 0;
bool must_be_raw;
IA_CSS_ENTER_PRIVATE("");
assert(pipe);
assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
- pipe->mode == IA_CSS_PIPE_ID_COPY);
+ pipe->mode == IA_CSS_PIPE_ID_COPY);
if (pipe->pipe_settings.capture.primary_binary[0].info) {
IA_CSS_LEAVE_ERR_PRIVATE(0);
@@ -6692,13 +6548,14 @@ static int load_capture_binaries(
}
static int
-unload_capture_binaries(struct ia_css_pipe *pipe) {
+unload_capture_binaries(struct ia_css_pipe *pipe)
+{
unsigned int i;
IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
- if ((!pipe) || ((pipe->mode != IA_CSS_PIPE_ID_CAPTURE) && (pipe->mode != IA_CSS_PIPE_ID_COPY)))
- {
+ if (!pipe || (pipe->mode != IA_CSS_PIPE_ID_CAPTURE &&
+ pipe->mode != IA_CSS_PIPE_ID_COPY)) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
@@ -6726,7 +6583,8 @@ unload_capture_binaries(struct ia_css_pipe *pipe) {
static bool
need_downscaling(const struct ia_css_resolution in_res,
- const struct ia_css_resolution out_res) {
+ const struct ia_css_resolution out_res)
+{
if (in_res.width > out_res.width || in_res.height > out_res.height)
return true;
@@ -6734,7 +6592,8 @@ need_downscaling(const struct ia_css_resolution in_res,
}
static bool
-need_yuv_scaler_stage(const struct ia_css_pipe *pipe) {
+need_yuv_scaler_stage(const struct ia_css_pipe *pipe)
+{
unsigned int i;
struct ia_css_resolution in_res, out_res;
@@ -6773,10 +6632,11 @@ need_yuv_scaler_stage(const struct ia_css_pipe *pipe) {
/* which has some hard-coded knowledge which prevents reuse of the function. */
/* Later, merge this with ia_css_pipe_create_cas_scaler_desc */
static int ia_css_pipe_create_cas_scaler_desc_single_output(
- struct ia_css_frame_info *cas_scaler_in_info,
- struct ia_css_frame_info *cas_scaler_out_info,
- struct ia_css_frame_info *cas_scaler_vf_info,
- struct ia_css_cas_binary_descr *descr) {
+ struct ia_css_frame_info *cas_scaler_in_info,
+ struct ia_css_frame_info *cas_scaler_out_info,
+ struct ia_css_frame_info *cas_scaler_vf_info,
+ struct ia_css_cas_binary_descr *descr)
+{
unsigned int i;
unsigned int hor_ds_factor = 0, ver_ds_factor = 0;
int err = 0;
@@ -6794,9 +6654,9 @@ static int ia_css_pipe_create_cas_scaler_desc_single_output(
descr->num_output_stage = 1;
hor_ds_factor = CEIL_DIV(cas_scaler_in_info->res.width,
- cas_scaler_out_info->res.width);
+ cas_scaler_out_info->res.width);
ver_ds_factor = CEIL_DIV(cas_scaler_in_info->res.height,
- cas_scaler_out_info->res.height);
+ cas_scaler_out_info->res.height);
/* use the same horizontal and vertical downscaling factor for simplicity */
assert(hor_ds_factor == ver_ds_factor);
@@ -6806,31 +6666,36 @@ static int ia_css_pipe_create_cas_scaler_desc_single_output(
i *= max_scale_factor_per_stage;
}
- descr->in_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info),
- GFP_KERNEL);
+ descr->in_info = kmalloc(descr->num_stage *
+ sizeof(struct ia_css_frame_info),
+ GFP_KERNEL);
if (!descr->in_info) {
err = -ENOMEM;
goto ERR;
}
- descr->internal_out_info = kmalloc(descr->num_stage * sizeof(
- struct ia_css_frame_info), GFP_KERNEL);
+ descr->internal_out_info = kmalloc(descr->num_stage *
+ sizeof(struct ia_css_frame_info),
+ GFP_KERNEL);
if (!descr->internal_out_info) {
err = -ENOMEM;
goto ERR;
}
- descr->out_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info),
- GFP_KERNEL);
+ descr->out_info = kmalloc(descr->num_stage *
+ sizeof(struct ia_css_frame_info),
+ GFP_KERNEL);
if (!descr->out_info) {
err = -ENOMEM;
goto ERR;
}
- descr->vf_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info),
- GFP_KERNEL);
+ descr->vf_info = kmalloc(descr->num_stage *
+ sizeof(struct ia_css_frame_info),
+ GFP_KERNEL);
if (!descr->vf_info) {
err = -ENOMEM;
goto ERR;
}
- descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool), GFP_KERNEL);
+ descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool),
+ GFP_KERNEL);
if (!descr->is_output_stage) {
err = -ENOMEM;
goto ERR;
@@ -6874,9 +6739,9 @@ static int ia_css_pipe_create_cas_scaler_desc_single_output(
max_scale_factor_per_stage;
descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
ia_css_frame_info_init(&descr->internal_out_info[i],
- tmp_in_info.res.width / max_scale_factor_per_stage,
- tmp_in_info.res.height / max_scale_factor_per_stage,
- IA_CSS_FRAME_FORMAT_YUV420, 0);
+ tmp_in_info.res.width / max_scale_factor_per_stage,
+ tmp_in_info.res.height / max_scale_factor_per_stage,
+ IA_CSS_FRAME_FORMAT_YUV420, 0);
descr->out_info[i].res.width = 0;
descr->out_info[i].res.height = 0;
descr->vf_info[i].res.width = 0;
@@ -6892,9 +6757,10 @@ ERR:
}
/* FIXME: merge most of this and single output version */
-static int ia_css_pipe_create_cas_scaler_desc(
- struct ia_css_pipe *pipe,
- struct ia_css_cas_binary_descr *descr) {
+static int
+ia_css_pipe_create_cas_scaler_desc(struct ia_css_pipe *pipe,
+ struct ia_css_cas_binary_descr *descr)
+{
struct ia_css_frame_info in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO;
struct ia_css_frame_info *out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
struct ia_css_frame_info *vf_out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
@@ -6951,30 +6817,35 @@ static int ia_css_pipe_create_cas_scaler_desc(
descr->num_stage = num_stages;
descr->in_info = kmalloc_array(descr->num_stage,
- sizeof(struct ia_css_frame_info), GFP_KERNEL);
+ sizeof(struct ia_css_frame_info),
+ GFP_KERNEL);
if (!descr->in_info) {
err = -ENOMEM;
goto ERR;
}
- descr->internal_out_info = kmalloc(descr->num_stage * sizeof(
- struct ia_css_frame_info), GFP_KERNEL);
+ descr->internal_out_info = kmalloc(descr->num_stage *
+ sizeof(struct ia_css_frame_info),
+ GFP_KERNEL);
if (!descr->internal_out_info) {
err = -ENOMEM;
goto ERR;
}
- descr->out_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info),
- GFP_KERNEL);
+ descr->out_info = kmalloc(descr->num_stage *
+ sizeof(struct ia_css_frame_info),
+ GFP_KERNEL);
if (!descr->out_info) {
err = -ENOMEM;
goto ERR;
}
- descr->vf_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info),
- GFP_KERNEL);
+ descr->vf_info = kmalloc(descr->num_stage *
+ sizeof(struct ia_css_frame_info),
+ GFP_KERNEL);
if (!descr->vf_info) {
err = -ENOMEM;
goto ERR;
}
- descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool), GFP_KERNEL);
+ descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool),
+ GFP_KERNEL);
if (!descr->is_output_stage) {
err = -ENOMEM;
goto ERR;
@@ -6984,7 +6855,7 @@ static int ia_css_pipe_create_cas_scaler_desc(
if (out_info[i]) {
if (i > 0) {
assert((out_info[i - 1]->res.width >= out_info[i]->res.width) &&
- (out_info[i - 1]->res.height >= out_info[i]->res.height));
+ (out_info[i - 1]->res.height >= out_info[i]->res.height));
}
}
}
@@ -7032,9 +6903,9 @@ static int ia_css_pipe_create_cas_scaler_desc(
max_scale_factor_per_stage;
descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
ia_css_frame_info_init(&descr->internal_out_info[i],
- tmp_in_info.res.width / max_scale_factor_per_stage,
- tmp_in_info.res.height / max_scale_factor_per_stage,
- IA_CSS_FRAME_FORMAT_YUV420, 0);
+ tmp_in_info.res.width / max_scale_factor_per_stage,
+ tmp_in_info.res.height / max_scale_factor_per_stage,
+ IA_CSS_FRAME_FORMAT_YUV420, 0);
descr->out_info[i].res.width = 0;
descr->out_info[i].res.height = 0;
descr->vf_info[i].res.width = 0;
@@ -7050,7 +6921,8 @@ ERR:
}
static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr
- *descr) {
+ *descr)
+{
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
"ia_css_pipe_destroy_cas_scaler_desc() enter:\n");
kfree(descr->in_info);
@@ -7068,7 +6940,8 @@ static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr
}
static int
-load_yuvpp_binaries(struct ia_css_pipe *pipe) {
+load_yuvpp_binaries(struct ia_css_pipe *pipe)
+{
int err = 0;
bool need_scaler = false;
struct ia_css_frame_info *vf_pp_in_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
@@ -7093,8 +6966,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
mycs = &pipe->pipe_settings.yuvpp;
- for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++)
- {
+ for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
if (pipe->vf_output_info[i].res.width != 0) {
err = ia_css_util_check_vf_out_info(&pipe->output_info[i],
&pipe->vf_output_info[i]);
@@ -7108,18 +6980,18 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
/* we build up the pipeline starting at the end */
/* Capture post-processing */
- if (need_scaler)
- {
+ if (need_scaler) {
struct ia_css_binary_descr yuv_scaler_descr;
err = ia_css_pipe_create_cas_scaler_desc(pipe,
- &cas_scaler_descr);
+ &cas_scaler_descr);
if (err)
goto ERR;
mycs->num_output = cas_scaler_descr.num_output_stage;
mycs->num_yuv_scaler = cas_scaler_descr.num_stage;
mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage *
- sizeof(struct ia_css_binary), GFP_KERNEL);
+ sizeof(struct ia_css_binary),
+ GFP_KERNEL);
if (!mycs->yuv_scaler_binary) {
err = -ENOMEM;
goto ERR;
@@ -7133,28 +7005,25 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
for (i = 0; i < cas_scaler_descr.num_stage; i++) {
mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i];
ia_css_pipe_get_yuvscaler_binarydesc(pipe,
- &yuv_scaler_descr, &cas_scaler_descr.in_info[i],
- &cas_scaler_descr.out_info[i],
- &cas_scaler_descr.internal_out_info[i],
- &cas_scaler_descr.vf_info[i]);
+ &yuv_scaler_descr,
+ &cas_scaler_descr.in_info[i],
+ &cas_scaler_descr.out_info[i],
+ &cas_scaler_descr.internal_out_info[i],
+ &cas_scaler_descr.vf_info[i]);
err = ia_css_binary_find(&yuv_scaler_descr,
- &mycs->yuv_scaler_binary[i]);
+ &mycs->yuv_scaler_binary[i]);
if (err)
goto ERR;
}
ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
- } else
- {
+ } else {
mycs->num_output = 1;
}
if (need_scaler)
- {
next_binary = &mycs->yuv_scaler_binary[0];
- } else
- {
+ else
next_binary = NULL;
- }
#if defined(ISP2401)
/*
@@ -7180,11 +7049,10 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
need_isp_copy_binary = true;
#endif /* ISP2401 */
- if (need_isp_copy_binary)
- {
+ if (need_isp_copy_binary) {
err = load_copy_binary(pipe,
- &mycs->copy_binary,
- next_binary);
+ &mycs->copy_binary,
+ next_binary);
if (err)
goto ERR;
@@ -7211,8 +7079,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
}
/* Viewfinder post-processing */
- if (need_scaler)
- {
+ if (need_scaler) {
for (i = 0, j = 0; i < mycs->num_yuv_scaler; i++) {
if (mycs->is_output_stage[i]) {
assert(j < 2);
@@ -7222,19 +7089,18 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
}
}
mycs->num_vf_pp = j;
- } else
- {
+ } else {
vf_pp_in_info[0] =
&mycs->copy_binary.vf_frame_info;
- for (i = 1; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
+ for (i = 1; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++)
vf_pp_in_info[i] = NULL;
- }
+
mycs->num_vf_pp = 1;
}
- mycs->vf_pp_binary = kzalloc(mycs->num_vf_pp * sizeof(struct ia_css_binary),
- GFP_KERNEL);
- if (!mycs->vf_pp_binary)
- {
+ mycs->vf_pp_binary = kzalloc(mycs->num_vf_pp *
+ sizeof(struct ia_css_binary),
+ GFP_KERNEL);
+ if (!mycs->vf_pp_binary) {
err = -ENOMEM;
goto ERR;
}
@@ -7242,8 +7108,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
{
struct ia_css_binary_descr vf_pp_descr;
- for (i = 0; i < mycs->num_vf_pp; i++)
- {
+ for (i = 0; i < mycs->num_vf_pp; i++) {
if (pipe->vf_output_info[i].res.width != 0) {
ia_css_pipe_get_vfpp_binarydesc(pipe,
&vf_pp_descr, vf_pp_in_info[i], &pipe->vf_output_info[i]);
@@ -7259,34 +7124,31 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) {
ERR:
if (need_scaler)
- {
ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
- }
+
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "load_yuvpp_binaries() leave, err=%d\n",
err);
return err;
}
static int
-unload_yuvpp_binaries(struct ia_css_pipe *pipe) {
+unload_yuvpp_binaries(struct ia_css_pipe *pipe)
+{
unsigned int i;
IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
- if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP))
- {
+ if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
ia_css_binary_unload(&pipe->pipe_settings.yuvpp.copy_binary);
for (i = 0; i < pipe->pipe_settings.yuvpp.num_yuv_scaler; i++)
- {
ia_css_binary_unload(&pipe->pipe_settings.yuvpp.yuv_scaler_binary[i]);
- }
+
for (i = 0; i < pipe->pipe_settings.yuvpp.num_vf_pp; i++)
- {
ia_css_binary_unload(&pipe->pipe_settings.yuvpp.vf_pp_binary[i]);
- }
+
kfree(pipe->pipe_settings.yuvpp.is_output_stage);
pipe->pipe_settings.yuvpp.is_output_stage = NULL;
kfree(pipe->pipe_settings.yuvpp.yuv_scaler_binary);
@@ -7336,25 +7198,23 @@ static int yuvpp_start(struct ia_css_pipe *pipe)
}
static int
-sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe) {
+sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe)
+{
int err = 0;
IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
- if (!pipe)
- {
+ if (!pipe) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
/* PIPE_MODE_COPY has no binaries, but has output frames to outside*/
- if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY)
- {
+ if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) {
IA_CSS_LEAVE_ERR_PRIVATE(0);
return 0;
}
- switch (pipe->mode)
- {
+ switch (pipe->mode) {
case IA_CSS_PIPE_ID_PREVIEW:
err = unload_preview_binaries(pipe);
break;
@@ -7375,7 +7235,8 @@ sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe) {
}
static int
-sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) {
+sh_css_pipe_load_binaries(struct ia_css_pipe *pipe)
+{
int err = 0;
assert(pipe);
@@ -7385,8 +7246,7 @@ sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) {
if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY)
return err;
- switch (pipe->mode)
- {
+ switch (pipe->mode) {
case IA_CSS_PIPE_ID_PREVIEW:
err = load_preview_binaries(pipe);
break;
@@ -7405,8 +7265,7 @@ sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) {
err = -EINVAL;
break;
}
- if (err)
- {
+ if (err) {
if (sh_css_pipe_unload_binaries(pipe)) {
/* currently css does not support multiple error returns in a single function,
* using -EINVAL in this case */
@@ -7417,7 +7276,8 @@ sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) {
}
static int
-create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
+create_host_yuvpp_pipeline(struct ia_css_pipe *pipe)
+{
struct ia_css_pipeline *me;
int err = 0;
struct ia_css_pipeline_stage *vf_pp_stage = NULL,
@@ -7444,15 +7304,13 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
#endif
IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
- if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP))
- {
+ if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
me = &pipe->pipeline;
ia_css_pipeline_clean(me);
- for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++)
- {
+ for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
out_frame[i] = NULL;
vf_frame[i] = NULL;
}
@@ -7480,8 +7338,7 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
/* the input frame can come from:
* a) memory: connect yuvscaler to me->in_frame
* b) sensor, via copy binary: connect yuvscaler to copy binary later on */
- if (need_in_frameinfo_memory)
- {
+ if (need_in_frameinfo_memory) {
/* TODO: improve for different input formats. */
/*
@@ -7530,13 +7387,11 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
}
in_frame = &me->in_frame;
- } else
- {
+ } else {
in_frame = NULL;
}
- for (i = 0; i < num_output_stage; i++)
- {
+ for (i = 0; i < num_output_stage; i++) {
assert(i < IA_CSS_PIPE_MAX_OUTPUT_STAGE);
if (pipe->output_info[i].res.width != 0) {
err = init_out_frameinfo_defaults(pipe, &me->out_frame[i], i);
@@ -7563,8 +7418,7 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
yuv_scaler_binary = pipe->pipe_settings.yuvpp.yuv_scaler_binary;
need_scaler = need_yuv_scaler_stage(pipe);
- if (pipe->pipe_settings.yuvpp.copy_binary.info)
- {
+ if (pipe->pipe_settings.yuvpp.copy_binary.info) {
struct ia_css_frame *in_frame_local = NULL;
#ifdef ISP2401
@@ -7574,18 +7428,26 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
#endif
if (need_scaler) {
- ia_css_pipe_util_set_output_frames(bin_out_frame, 0, NULL);
- ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
- bin_out_frame, in_frame_local, NULL);
+ ia_css_pipe_util_set_output_frames(bin_out_frame,
+ 0, NULL);
+ ia_css_pipe_get_generic_stage_desc(&stage_desc,
+ copy_binary,
+ bin_out_frame,
+ in_frame_local,
+ NULL);
} else {
- ia_css_pipe_util_set_output_frames(bin_out_frame, 0, out_frame[0]);
- ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
- bin_out_frame, in_frame_local, NULL);
+ ia_css_pipe_util_set_output_frames(bin_out_frame,
+ 0, out_frame[0]);
+ ia_css_pipe_get_generic_stage_desc(&stage_desc,
+ copy_binary,
+ bin_out_frame,
+ in_frame_local,
+ NULL);
}
err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc,
- &copy_stage);
+ &stage_desc,
+ &copy_stage);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -7602,8 +7464,7 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
}
}
- if (need_scaler)
- {
+ if (need_scaler) {
struct ia_css_frame *tmp_out_frame = NULL;
struct ia_css_frame *tmp_vf_frame = NULL;
struct ia_css_frame *tmp_in_frame = in_frame;
@@ -7618,10 +7479,11 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
tmp_vf_frame = NULL;
}
- err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, tmp_out_frame,
- NULL,
- &yuv_scaler_binary[i],
- &yuv_scaler_stage);
+ err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
+ tmp_out_frame,
+ NULL,
+ &yuv_scaler_binary[i],
+ &yuv_scaler_stage);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -7632,8 +7494,10 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
if (pipe->pipe_settings.yuvpp.is_output_stage[i]) {
if (tmp_vf_frame && (tmp_vf_frame->info.res.width != 0)) {
in_frame = yuv_scaler_stage->args.out_vf_frame;
- err = add_vf_pp_stage(pipe, in_frame, tmp_vf_frame, &vf_pp_binary[j],
- &vf_pp_stage);
+ err = add_vf_pp_stage(pipe, in_frame,
+ tmp_vf_frame,
+ &vf_pp_binary[j],
+ &vf_pp_stage);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -7643,12 +7507,11 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
j++;
}
}
- } else if (copy_stage)
- {
+ } else if (copy_stage) {
if (vf_frame[0] && vf_frame[0]->info.res.width != 0) {
in_frame = copy_stage->args.out_vf_frame;
- err = add_vf_pp_stage(pipe, in_frame, vf_frame[0], &vf_pp_binary[0],
- &vf_pp_stage);
+ err = add_vf_pp_stage(pipe, in_frame, vf_frame[0],
+ &vf_pp_binary[0], &vf_pp_stage);
}
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -7656,7 +7519,8 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
}
}
- ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
+ ia_css_pipeline_finalize_stages(&pipe->pipeline,
+ pipe->stream->config.continuous);
IA_CSS_LEAVE_ERR_PRIVATE(0);
@@ -7665,8 +7529,9 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) {
static int
create_host_copy_pipeline(struct ia_css_pipe *pipe,
- unsigned int max_input_width,
- struct ia_css_frame *out_frame) {
+ unsigned int max_input_width,
+ struct ia_css_frame *out_frame)
+{
struct ia_css_pipeline *me;
int err = 0;
struct ia_css_pipeline_stage_desc stage_desc;
@@ -7683,16 +7548,10 @@ create_host_copy_pipeline(struct ia_css_pipe *pipe,
out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
if (copy_on_sp(pipe) &&
- pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8)
- {
- ia_css_frame_info_init(
- &out_frame->info,
- JPEG_BYTES,
- 1,
- IA_CSS_FRAME_FORMAT_BINARY_8,
- 0);
- } else if (out_frame->info.format == IA_CSS_FRAME_FORMAT_RAW)
- {
+ pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
+ ia_css_frame_info_init(&out_frame->info, JPEG_BYTES, 1,
+ IA_CSS_FRAME_FORMAT_BINARY_8, 0);
+ } else if (out_frame->info.format == IA_CSS_FRAME_FORMAT_RAW) {
out_frame->info.raw_bit_depth =
ia_css_pipe_util_pipe_input_format_bpp(pipe);
}
@@ -7702,12 +7561,12 @@ create_host_copy_pipeline(struct ia_css_pipe *pipe,
pipe->mode = IA_CSS_PIPE_ID_COPY;
ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame,
- IA_CSS_PIPELINE_RAW_COPY, max_input_width);
- err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc,
- NULL);
+ IA_CSS_PIPELINE_RAW_COPY,
+ max_input_width);
+ err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, NULL);
- ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
+ ia_css_pipeline_finalize_stages(&pipe->pipeline,
+ pipe->stream->config.continuous);
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
"create_host_copy_pipeline() leave:\n");
@@ -7716,7 +7575,8 @@ create_host_copy_pipeline(struct ia_css_pipe *pipe,
}
static int
-create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe) {
+create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe)
+{
struct ia_css_pipeline *me = &pipe->pipeline;
int err = 0;
struct ia_css_pipeline_stage_desc stage_desc;
@@ -7745,9 +7605,10 @@ create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe) {
me->pipe_id = IA_CSS_PIPE_ID_CAPTURE;
pipe->mode = IA_CSS_PIPE_ID_CAPTURE;
ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame,
- IA_CSS_PIPELINE_ISYS_COPY, max_input_width);
+ IA_CSS_PIPELINE_ISYS_COPY,
+ max_input_width);
err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc, &out_stage);
+ &stage_desc, &out_stage);
if (err)
return err;
@@ -7760,7 +7621,8 @@ create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe) {
}
static int
-create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
+create_host_regular_capture_pipeline(struct ia_css_pipe *pipe)
+{
struct ia_css_pipeline *me;
int err = 0;
enum ia_css_capture_mode mode;
@@ -7798,7 +7660,8 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
IA_CSS_ENTER_PRIVATE("");
assert(pipe);
assert(pipe->stream);
- assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || pipe->mode == IA_CSS_PIPE_ID_COPY);
+ assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
+ pipe->mode == IA_CSS_PIPE_ID_COPY);
me = &pipe->pipeline;
mode = pipe->config.default_capture_config.mode;
@@ -7824,8 +7687,7 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
/* Construct in_frame info (only in case we have dynamic input */
need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
#endif
- if (need_in_frameinfo_memory)
- {
+ if (need_in_frameinfo_memory) {
err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame,
IA_CSS_FRAME_FORMAT_RAW);
if (err) {
@@ -7834,22 +7696,19 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
}
in_frame = &me->in_frame;
- } else
- {
+ } else {
in_frame = NULL;
}
err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0);
- if (err)
- {
+ if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
}
out_frame = &me->out_frame[0];
/* Construct vf_frame info (only in case we have VF) */
- if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0])
- {
+ if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
if (mode == IA_CSS_CAPTURE_MODE_RAW || mode == IA_CSS_CAPTURE_MODE_BAYER) {
/* These modes don't support viewfinder output */
vf_frame = NULL;
@@ -7857,22 +7716,20 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
init_vf_frameinfo_defaults(pipe, &me->vf_frame[0], 0);
vf_frame = &me->vf_frame[0];
}
- } else
- {
+ } else {
vf_frame = NULL;
}
copy_binary = &pipe->pipe_settings.capture.copy_binary;
num_primary_stage = pipe->pipe_settings.capture.num_primary_stage;
- if ((num_primary_stage == 0) && (mode == IA_CSS_CAPTURE_MODE_PRIMARY))
- {
+ if ((num_primary_stage == 0) && (mode == IA_CSS_CAPTURE_MODE_PRIMARY)) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
+
for (i = 0; i < num_primary_stage; i++)
- {
primary_binary[i] = &pipe->pipe_settings.capture.primary_binary[i];
- }
+
vf_pp_binary = &pipe->pipe_settings.capture.vf_pp_binary;
pre_isp_binary = &pipe->pipe_settings.capture.pre_isp_binary;
anr_gdc_binary = &pipe->pipe_settings.capture.anr_gdc_binary;
@@ -7889,43 +7746,51 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info);
need_ldc = (capture_ldc_binary && capture_ldc_binary->info);
- if (pipe->pipe_settings.capture.copy_binary.info)
- {
+ if (pipe->pipe_settings.capture.copy_binary.info) {
if (raw) {
ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
#if defined(ISP2401)
if (!continuous) {
- ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
- out_frames, in_frame, NULL);
+ ia_css_pipe_get_generic_stage_desc(&stage_desc,
+ copy_binary,
+ out_frames,
+ in_frame,
+ NULL);
} else {
in_frame = pipe->stream->last_pipe->continuous_frames[0];
- ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
- out_frames, in_frame, NULL);
+ ia_css_pipe_get_generic_stage_desc(&stage_desc,
+ copy_binary,
+ out_frames,
+ in_frame,
+ NULL);
}
#else
- ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
- out_frames, NULL, NULL);
+ ia_css_pipe_get_generic_stage_desc(&stage_desc,
+ copy_binary,
+ out_frames,
+ NULL, NULL);
#endif
} else {
- ia_css_pipe_util_set_output_frames(out_frames, 0, in_frame);
- ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
- out_frames, NULL, NULL);
+ ia_css_pipe_util_set_output_frames(out_frames, 0,
+ in_frame);
+ ia_css_pipe_get_generic_stage_desc(&stage_desc,
+ copy_binary,
+ out_frames,
+ NULL, NULL);
}
err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc,
- &current_stage);
+ &stage_desc,
+ &current_stage);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
}
- } else if (pipe->stream->config.continuous)
- {
+ } else if (pipe->stream->config.continuous) {
in_frame = pipe->stream->last_pipe->continuous_frames[0];
}
- if (mode == IA_CSS_CAPTURE_MODE_PRIMARY)
- {
+ if (mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
struct ia_css_frame *local_in_frame = NULL;
struct ia_css_frame *local_out_frame = NULL;
@@ -7953,11 +7818,14 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
* Proper investigation should be done to come up with the clean
* solution.
* */
- ia_css_pipe_get_generic_stage_desc(&stage_desc, primary_binary[i],
- out_frames, local_in_frame, NULL);
+ ia_css_pipe_get_generic_stage_desc(&stage_desc,
+ primary_binary[i],
+ out_frames,
+ local_in_frame,
+ NULL);
err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc,
- &current_stage);
+ &stage_desc,
+ &current_stage);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
@@ -7970,22 +7838,21 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
IA_CSS_BINARY_MODE_COPY;
current_stage->args.copy_output = current_stage->args.copy_vf;
} else if (mode == IA_CSS_CAPTURE_MODE_ADVANCED ||
- mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT)
- {
+ mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary,
- out_frames, in_frame, NULL);
- err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc, NULL);
+ out_frames, in_frame, NULL);
+ err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+ NULL);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
}
ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
ia_css_pipe_get_generic_stage_desc(&stage_desc, anr_gdc_binary,
- out_frames, NULL, NULL);
- err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc, NULL);
+ out_frames, NULL, NULL);
+ err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+ NULL);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
@@ -7993,28 +7860,31 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
if (need_pp) {
ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
- ia_css_pipe_get_generic_stage_desc(&stage_desc, post_isp_binary,
- out_frames, NULL, NULL);
+ ia_css_pipe_get_generic_stage_desc(&stage_desc,
+ post_isp_binary,
+ out_frames,
+ NULL, NULL);
} else {
- ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
- ia_css_pipe_get_generic_stage_desc(&stage_desc, post_isp_binary,
- out_frames, NULL, NULL);
+ ia_css_pipe_util_set_output_frames(out_frames, 0,
+ out_frame);
+ ia_css_pipe_get_generic_stage_desc(&stage_desc,
+ post_isp_binary,
+ out_frames,
+ NULL, NULL);
}
- err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc, &current_stage);
+ err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+ &current_stage);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
}
- } else if (mode == IA_CSS_CAPTURE_MODE_BAYER)
- {
+ } else if (mode == IA_CSS_CAPTURE_MODE_BAYER) {
ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary,
- out_frames, in_frame, NULL);
- err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc,
- NULL);
+ out_frames, in_frame, NULL);
+ err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+ NULL);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
@@ -8022,49 +7892,48 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
}
#ifndef ISP2401
- if (need_pp && current_stage)
- {
+ if (need_pp && current_stage) {
struct ia_css_frame *local_in_frame = NULL;
local_in_frame = current_stage->args.out_frame[0];
if (need_ldc) {
ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
- ia_css_pipe_get_generic_stage_desc(&stage_desc, capture_ldc_binary,
- out_frames, local_in_frame, NULL);
+ ia_css_pipe_get_generic_stage_desc(&stage_desc,
+ capture_ldc_binary,
+ out_frames,
+ local_in_frame,
+ NULL);
err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc,
- &current_stage);
+ &stage_desc,
+ &current_stage);
local_in_frame = current_stage->args.out_frame[0];
}
err = add_capture_pp_stage(pipe, me, local_in_frame,
- need_yuv_pp ? NULL : out_frame,
+ need_yuv_pp ? NULL : out_frame,
#else
/* ldc and capture_pp not supported in same pipeline */
- if (need_ldc && current_stage)
- {
+ if (need_ldc && current_stage) {
in_frame = current_stage->args.out_frame[0];
ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
ia_css_pipe_get_generic_stage_desc(&stage_desc, capture_ldc_binary,
- out_frames, in_frame, NULL);
- err = ia_css_pipeline_create_and_add_stage(me,
- &stage_desc,
- NULL);
- } else if (need_pp && current_stage)
- {
+ out_frames, in_frame, NULL);
+ err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
+ NULL);
+ } else if (need_pp && current_stage) {
in_frame = current_stage->args.out_frame[0];
- err = add_capture_pp_stage(pipe, me, in_frame, need_yuv_pp ? NULL : out_frame,
+ err = add_capture_pp_stage(pipe, me, in_frame,
+ need_yuv_pp ? NULL : out_frame,
#endif
- capture_pp_binary,
- &current_stage);
+ capture_pp_binary,
+ &current_stage);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
}
}
- if (need_yuv_pp && current_stage)
- {
+ if (need_yuv_pp && current_stage) {
struct ia_css_frame *tmp_in_frame = current_stage->args.out_frame[0];
struct ia_css_frame *tmp_out_frame = NULL;
@@ -8074,10 +7943,10 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
else
tmp_out_frame = NULL;
- err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, tmp_out_frame,
- NULL,
- &yuv_scaler_binary[i],
- &yuv_scaler_stage);
+ err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
+ tmp_out_frame, NULL,
+ &yuv_scaler_binary[i],
+ &yuv_scaler_stage);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
@@ -8096,11 +7965,12 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
* should not be considered as a clean solution. Proper
* investigation should be done to come up with the clean solution.
* */
- if (mode != IA_CSS_CAPTURE_MODE_RAW && mode != IA_CSS_CAPTURE_MODE_BAYER && current_stage && vf_frame)
- {
+ if (mode != IA_CSS_CAPTURE_MODE_RAW &&
+ mode != IA_CSS_CAPTURE_MODE_BAYER &&
+ current_stage && vf_frame) {
in_frame = current_stage->args.out_vf_frame;
err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary,
- &current_stage);
+ &current_stage);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
@@ -8115,7 +7985,8 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) {
}
static int
-create_host_capture_pipeline(struct ia_css_pipe *pipe) {
+create_host_capture_pipeline(struct ia_css_pipe *pipe)
+{
int err = 0;
IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
@@ -8124,8 +7995,7 @@ create_host_capture_pipeline(struct ia_css_pipe *pipe) {
err = create_host_isyscopy_capture_pipeline(pipe);
else
err = create_host_regular_capture_pipeline(pipe);
- if (err)
- {
+ if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
}
@@ -8135,8 +8005,8 @@ create_host_capture_pipeline(struct ia_css_pipe *pipe) {
return err;
}
-static int capture_start(
- struct ia_css_pipe *pipe) {
+static int capture_start(struct ia_css_pipe *pipe)
+{
struct ia_css_pipeline *me;
int err = 0;
@@ -8151,7 +8021,7 @@ static int capture_start(
me = &pipe->pipeline;
if ((pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW ||
- pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) &&
+ pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) &&
(pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) {
if (copy_on_sp(pipe)) {
err = start_copy_on_sp(pipe, &me->out_frame[0]);
@@ -8195,7 +8065,7 @@ static int capture_start(
if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY &&
pipe->stream->reconfigure_css_rx) {
ia_css_isys_rx_configure(&pipe->stream->csi_rx_config,
- pipe->stream->config.mode);
+ pipe->stream->config.mode);
pipe->stream->reconfigure_css_rx = false;
}
#endif
@@ -8206,8 +8076,9 @@ static int capture_start(
static int
sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
- struct ia_css_frame_info *info,
- unsigned int idx) {
+ struct ia_css_frame_info *info,
+ unsigned int idx)
+{
assert(pipe);
assert(info);
@@ -8216,8 +8087,7 @@ sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
*info = pipe->output_info[idx];
if (copy_on_sp(pipe) &&
- pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8)
- {
+ pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
ia_css_frame_info_init(
info,
JPEG_BYTES,
@@ -8225,8 +8095,7 @@ sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
IA_CSS_FRAME_FORMAT_BINARY_8,
0);
} else if (info->format == IA_CSS_FRAME_FORMAT_RAW ||
- info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED)
- {
+ info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED) {
info->raw_bit_depth =
ia_css_pipe_util_pipe_input_format_bpp(pipe);
}
@@ -8238,9 +8107,10 @@ sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
void
ia_css_stream_send_input_frame(const struct ia_css_stream *stream,
- const unsigned short *data,
- unsigned int width,
- unsigned int height) {
+ const unsigned short *data,
+ unsigned int width,
+ unsigned int height)
+{
assert(stream);
ia_css_inputfifo_send_input_frame(
@@ -8251,7 +8121,8 @@ ia_css_stream_send_input_frame(const struct ia_css_stream *stream,
}
void
-ia_css_stream_start_input_frame(const struct ia_css_stream *stream) {
+ia_css_stream_start_input_frame(const struct ia_css_stream *stream)
+{
assert(stream);
ia_css_inputfifo_start_frame(
@@ -8262,21 +8133,23 @@ ia_css_stream_start_input_frame(const struct ia_css_stream *stream) {
void
ia_css_stream_send_input_line(const struct ia_css_stream *stream,
- const unsigned short *data,
- unsigned int width,
- const unsigned short *data2,
- unsigned int width2) {
+ const unsigned short *data,
+ unsigned int width,
+ const unsigned short *data2,
+ unsigned int width2)
+{
assert(stream);
ia_css_inputfifo_send_line(stream->config.channel_id,
- data, width, data2, width2);
+ data, width, data2, width2);
}
void
ia_css_stream_send_input_embedded_line(const struct ia_css_stream *stream,
- enum atomisp_input_format format,
- const unsigned short *data,
- unsigned int width) {
+ enum atomisp_input_format format,
+ const unsigned short *data,
+ unsigned int width)
+{
assert(stream);
if (!data || width == 0)
return;
@@ -8285,14 +8158,16 @@ ia_css_stream_send_input_embedded_line(const struct ia_css_stream *stream,
}
void
-ia_css_stream_end_input_frame(const struct ia_css_stream *stream) {
+ia_css_stream_end_input_frame(const struct ia_css_stream *stream)
+{
assert(stream);
ia_css_inputfifo_end_frame(stream->config.channel_id);
}
static void
-append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware) {
+append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware)
+{
IA_CSS_ENTER_PRIVATE("l = %p, firmware = %p", l, firmware);
if (!l) {
IA_CSS_ERROR("NULL fw_info");
@@ -8307,7 +8182,8 @@ append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware) {
}
static void
-remove_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware) {
+remove_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware)
+{
assert(*l);
assert(firmware);
(void)l;
@@ -8349,12 +8225,12 @@ static int upload_isp_code(struct ia_css_fw_info *firmware)
}
static int
-acc_load_extension(struct ia_css_fw_info *firmware) {
+acc_load_extension(struct ia_css_fw_info *firmware)
+{
int err;
struct ia_css_fw_info *hd = firmware;
- while (hd)
- {
+ while (hd) {
err = upload_isp_code(hd);
if (err)
return err;
@@ -8368,7 +8244,8 @@ acc_load_extension(struct ia_css_fw_info *firmware) {
}
static void
-acc_unload_extension(struct ia_css_fw_info *firmware) {
+acc_unload_extension(struct ia_css_fw_info *firmware)
+{
struct ia_css_fw_info *hd = firmware;
struct ia_css_fw_info *hdn = NULL;
@@ -8392,13 +8269,13 @@ acc_unload_extension(struct ia_css_fw_info *firmware) {
/* Load firmware for extension */
static int
ia_css_pipe_load_extension(struct ia_css_pipe *pipe,
- struct ia_css_fw_info *firmware) {
+ struct ia_css_fw_info *firmware)
+{
int err = 0;
IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe);
- if ((!firmware) || (!pipe))
- {
+ if ((!firmware) || (!pipe)) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
@@ -8416,7 +8293,8 @@ ia_css_pipe_load_extension(struct ia_css_pipe *pipe,
/* Unload firmware for extension */
static void
ia_css_pipe_unload_extension(struct ia_css_pipe *pipe,
- struct ia_css_fw_info *firmware) {
+ struct ia_css_fw_info *firmware)
+{
IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe);
if ((!firmware) || (!pipe)) {
@@ -8435,7 +8313,8 @@ ia_css_pipe_unload_extension(struct ia_css_pipe *pipe,
}
bool
-ia_css_pipeline_uses_params(struct ia_css_pipeline *me) {
+ia_css_pipeline_uses_params(struct ia_css_pipeline *me)
+{
struct ia_css_pipeline_stage *stage;
assert(me);
@@ -8456,7 +8335,8 @@ ia_css_pipeline_uses_params(struct ia_css_pipeline *me) {
static int
sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
- const void *acc_fw) {
+ const void *acc_fw)
+{
struct ia_css_fw_info *fw = (struct ia_css_fw_info *)acc_fw;
/* In QoS case, load_extension already called, so skipping */
int err = 0;
@@ -8468,14 +8348,13 @@ sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
"sh_css_pipeline_add_acc_stage() enter: pipeline=%p, acc_fw=%p\n",
pipeline, acc_fw);
- if (!err)
- {
+ if (!err) {
struct ia_css_pipeline_stage_desc stage_desc;
ia_css_pipe_get_acc_stage_desc(&stage_desc, NULL, fw);
err = ia_css_pipeline_create_and_add_stage(pipeline,
- &stage_desc,
- NULL);
+ &stage_desc,
+ NULL);
}
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
@@ -8488,7 +8367,8 @@ sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
* Refer to "sh_css_internal.h" for details.
*/
int ia_css_stream_capture_frame(struct ia_css_stream *stream,
- unsigned int exp_id) {
+ unsigned int exp_id)
+{
struct sh_css_tag_descr tag_descr;
u32 encoded_tag_descr;
int err;
@@ -8526,11 +8406,9 @@ int ia_css_stream_capture_frame(struct ia_css_stream *stream,
* @brief Configure the continuous capture.
* Refer to "sh_css_internal.h" for details.
*/
-int ia_css_stream_capture(
- struct ia_css_stream *stream,
- int num_captures,
- unsigned int skip,
- int offset) {
+int ia_css_stream_capture(struct ia_css_stream *stream, int num_captures,
+ unsigned int skip, int offset)
+{
struct sh_css_tag_descr tag_descr;
unsigned int encoded_tag_descr;
int return_err;
@@ -8593,8 +8471,9 @@ void ia_css_stream_request_flash(struct ia_css_stream *stream)
ia_css_debug_dump_sp_sw_debug_info();
ia_css_debug_dump_debug_info(NULL);
}
- } else
+ } else {
IA_CSS_LOG("SP is not running!");
+ }
#endif
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
@@ -8602,7 +8481,8 @@ void ia_css_stream_request_flash(struct ia_css_stream *stream)
}
static void
-sh_css_init_host_sp_control_vars(void) {
+sh_css_init_host_sp_control_vars(void)
+{
const struct ia_css_fw_info *fw;
unsigned int HIVE_ADDR_ia_css_ispctrl_sp_isp_started;
@@ -8643,22 +8523,22 @@ sh_css_init_host_sp_control_vars(void) {
(void)HIVE_ADDR_host_sp_com;
sp_dmem_store_uint32(SP0_ID,
- (unsigned int)sp_address_of(ia_css_ispctrl_sp_isp_started),
- (uint32_t)(0));
+ (unsigned int)sp_address_of(ia_css_ispctrl_sp_isp_started),
+ (uint32_t)(0));
sp_dmem_store_uint32(SP0_ID,
- (unsigned int)sp_address_of(host_sp_queues_initialized),
- (uint32_t)(0));
+ (unsigned int)sp_address_of(host_sp_queues_initialized),
+ (uint32_t)(0));
sp_dmem_store_uint32(SP0_ID,
- (unsigned int)sp_address_of(sp_sleep_mode),
- (uint32_t)(0));
+ (unsigned int)sp_address_of(sp_sleep_mode),
+ (uint32_t)(0));
sp_dmem_store_uint32(SP0_ID,
- (unsigned int)sp_address_of(ia_css_dmaproxy_sp_invalidate_tlb),
- (uint32_t)(false));
+ (unsigned int)sp_address_of(ia_css_dmaproxy_sp_invalidate_tlb),
+ (uint32_t)(false));
#ifndef ISP2401
sp_dmem_store_uint32(SP0_ID,
- (unsigned int)sp_address_of(sp_stop_copy_preview),
- my_css.stop_copy_preview ? (uint32_t)(1) : (uint32_t)(0));
+ (unsigned int)sp_address_of(sp_stop_copy_preview),
+ my_css.stop_copy_preview ? (uint32_t)(1) : (uint32_t)(0));
#endif
store_sp_array_uint(host_sp_com, o, host2sp_cmd_ready);
@@ -8685,8 +8565,8 @@ void ia_css_pipe_config_defaults(struct ia_css_pipe_config *pipe_config)
}
void
-ia_css_pipe_extra_config_defaults(struct ia_css_pipe_extra_config
- *extra_config) {
+ia_css_pipe_extra_config_defaults(struct ia_css_pipe_extra_config *extra_config)
+{
if (!extra_config) {
IA_CSS_ERROR("NULL input parameter");
return;
@@ -8716,11 +8596,11 @@ void ia_css_stream_config_defaults(struct ia_css_stream_config *stream_config)
}
static int
-ia_css_acc_pipe_create(struct ia_css_pipe *pipe) {
+ia_css_acc_pipe_create(struct ia_css_pipe *pipe)
+{
int err = 0;
- if (!pipe)
- {
+ if (!pipe) {
IA_CSS_ERROR("NULL input parameter");
return -EINVAL;
}
@@ -8730,9 +8610,7 @@ ia_css_acc_pipe_create(struct ia_css_pipe *pipe) {
pipe->config.acc_num_execs = 1;
if (pipe->config.acc_extension)
- {
err = ia_css_pipe_load_extension(pipe, pipe->config.acc_extension);
- }
return err;
}
@@ -8751,9 +8629,8 @@ int ia_css_pipe_create(const struct ia_css_pipe_config *config,
err = ia_css_pipe_create_extra(config, NULL, pipe);
- if (err == 0) {
+ if (err == 0)
IA_CSS_LOG("pipe created successfully = %p", *pipe);
- }
IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -8762,8 +8639,9 @@ int ia_css_pipe_create(const struct ia_css_pipe_config *config,
int
ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
- const struct ia_css_pipe_extra_config *extra_config,
- struct ia_css_pipe **pipe) {
+ const struct ia_css_pipe_extra_config *extra_config,
+ struct ia_css_pipe **pipe)
+{
int err = -EINVAL;
struct ia_css_pipe *internal_pipe = NULL;
unsigned int i;
@@ -8771,14 +8649,12 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
IA_CSS_ENTER_PRIVATE("config = %p, extra_config = %p and pipe = %p", config, extra_config, pipe);
/* do not allow to create more than the maximum limit */
- if (my_css.pipe_counter >= IA_CSS_PIPELINE_NUM_MAX)
- {
+ if (my_css.pipe_counter >= IA_CSS_PIPELINE_NUM_MAX) {
IA_CSS_LEAVE_ERR_PRIVATE(-ENOSPC);
return -EINVAL;
}
- if ((!pipe) || (!config))
- {
+ if ((!pipe) || (!config)) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
@@ -8787,8 +8663,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
ia_css_debug_dump_pipe_extra_config(extra_config);
err = create_pipe(config->mode, &internal_pipe, false);
- if (err)
- {
+ if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
}
@@ -8800,8 +8675,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
else
ia_css_pipe_extra_config_defaults(&internal_pipe->extra_config);
- if (config->mode == IA_CSS_PIPE_MODE_ACC)
- {
+ if (config->mode == IA_CSS_PIPE_MODE_ACC) {
/* Temporary hack to migrate acceleration to CSS 2.0.
* In the future the code for all pipe types should be
* unified. */
@@ -8828,15 +8702,13 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
set bayer_ds_out_res equal to IF output resolution(IF may do cropping on
sensor output) or use default decimation factor 1. */
if (internal_pipe->extra_config.enable_raw_binning &&
- internal_pipe->config.bayer_ds_out_res.width)
- {
+ internal_pipe->config.bayer_ds_out_res.width) {
/* fill some code here, if no code is needed, please remove it during integration */
}
/* YUV downscaling */
if ((internal_pipe->config.vf_pp_in_res.width ||
- internal_pipe->config.capt_pp_in_res.width))
- {
+ internal_pipe->config.capt_pp_in_res.width)) {
enum ia_css_frame_format format;
if (internal_pipe->config.vf_pp_in_res.width) {
@@ -8857,8 +8729,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
}
}
if (internal_pipe->config.vf_pp_in_res.width &&
- internal_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
- {
+ internal_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) {
ia_css_frame_info_init(
&internal_pipe->vf_yuv_ds_input_info,
internal_pipe->config.vf_pp_in_res.width,
@@ -8866,8 +8737,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
IA_CSS_FRAME_FORMAT_YUV_LINE, 0);
}
/* handle bayer downscaling output info */
- if (internal_pipe->config.bayer_ds_out_res.width)
- {
+ if (internal_pipe->config.bayer_ds_out_res.width) {
ia_css_frame_info_init(
&internal_pipe->bds_output_info,
internal_pipe->config.bayer_ds_out_res.width,
@@ -8876,8 +8746,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
}
/* handle output info, assume always needed */
- for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++)
- {
+ for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
if (internal_pipe->config.output_info[i].res.width) {
err = sh_css_pipe_configure_output(
internal_pipe,
@@ -8913,10 +8782,9 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
}
}
}
- if (internal_pipe->config.acc_extension)
- {
+ if (internal_pipe->config.acc_extension) {
err = ia_css_pipe_load_extension(internal_pipe,
- internal_pipe->config.acc_extension);
+ internal_pipe->config.acc_extension);
if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
kvfree(internal_pipe);
@@ -8934,18 +8802,16 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
int
ia_css_pipe_get_info(const struct ia_css_pipe *pipe,
- struct ia_css_pipe_info *pipe_info) {
+ struct ia_css_pipe_info *pipe_info)
+{
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
"ia_css_pipe_get_info()\n");
- assert(pipe_info);
- if (!pipe_info)
- {
+ if (!pipe_info) {
ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
"ia_css_pipe_get_info: pipe_info cannot be NULL\n");
return -EINVAL;
}
- if (!pipe || !pipe->stream)
- {
+ if (!pipe || !pipe->stream) {
ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
"ia_css_pipe_get_info: ia_css_stream_create needs to be called before ia_css_[stream/pipe]_get_info\n");
return -EINVAL;
@@ -8972,41 +8838,37 @@ bool ia_css_pipe_has_dvs_stats(struct ia_css_pipe_info *pipe_info)
int
ia_css_pipe_override_frame_format(struct ia_css_pipe *pipe,
- int pin_index,
- enum ia_css_frame_format new_format) {
+ int pin_index,
+ enum ia_css_frame_format new_format)
+{
int err = 0;
IA_CSS_ENTER_PRIVATE("pipe = %p, pin_index = %d, new_formats = %d", pipe, pin_index, new_format);
- if (!pipe)
- {
+ if (!pipe) {
IA_CSS_ERROR("pipe is not set");
err = -EINVAL;
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
}
- if (0 != pin_index && 1 != pin_index)
- {
+ if (0 != pin_index && 1 != pin_index) {
IA_CSS_ERROR("pin index is not valid");
err = -EINVAL;
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
}
- if (new_format != IA_CSS_FRAME_FORMAT_NV12_TILEY)
- {
+ if (new_format != IA_CSS_FRAME_FORMAT_NV12_TILEY) {
IA_CSS_ERROR("new format is not valid");
err = -EINVAL;
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
- } else
- {
+ } else {
err = ia_css_pipe_check_format(pipe, new_format);
if (!err) {
- if (pin_index == 0) {
+ if (pin_index == 0)
pipe->output_info[0].format = new_format;
- } else {
+ else
pipe->vf_output_info[0].format = new_format;
- }
}
}
IA_CSS_LEAVE_ERR_PRIVATE(err);
@@ -9016,7 +8878,8 @@ ia_css_pipe_override_frame_format(struct ia_css_pipe *pipe,
#if !defined(ISP2401)
/* Configuration of INPUT_SYSTEM_VERSION_2401 is done on SP */
static int
-ia_css_stream_configure_rx(struct ia_css_stream *stream) {
+ia_css_stream_configure_rx(struct ia_css_stream *stream)
+{
struct ia_css_input_port *config;
assert(stream);
@@ -9045,11 +8908,10 @@ ia_css_stream_configure_rx(struct ia_css_stream *stream) {
if (config->compression.type == IA_CSS_CSI2_COMPRESSION_TYPE_NONE)
stream->csi_rx_config.comp = MIPI_PREDICTOR_NONE;
else
- {
/* not implemented yet, requires extension of the rx_cfg_t
* struct */
return -EINVAL;
- }
+
stream->csi_rx_config.is_two_ppc = (stream->config.pixels_per_clock == 2);
stream->reconfigure_css_rx = true;
return 0;
@@ -9057,10 +8919,9 @@ ia_css_stream_configure_rx(struct ia_css_stream *stream) {
#endif
static struct ia_css_pipe *
-find_pipe(struct ia_css_pipe *pipes[],
- unsigned int num_pipes,
- enum ia_css_pipe_mode mode,
- bool copy_pipe) {
+find_pipe(struct ia_css_pipe *pipes[], unsigned int num_pipes,
+ enum ia_css_pipe_mode mode, bool copy_pipe)
+{
unsigned int i;
assert(pipes);
@@ -9076,24 +8937,21 @@ find_pipe(struct ia_css_pipe *pipes[],
}
static int
-ia_css_acc_stream_create(struct ia_css_stream *stream) {
+ia_css_acc_stream_create(struct ia_css_stream *stream)
+{
int i;
int err = 0;
- assert(stream);
IA_CSS_ENTER_PRIVATE("stream = %p", stream);
- if (!stream)
- {
+ if (!stream) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
}
- for (i = 0; i < stream->num_pipes; i++)
- {
+ for (i = 0; i < stream->num_pipes; i++) {
struct ia_css_pipe *pipe = stream->pipes[i];
- assert(pipe);
if (!pipe) {
IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
return -EINVAL;
@@ -9104,14 +8962,12 @@ ia_css_acc_stream_create(struct ia_css_stream *stream) {
/* Map SP threads before doing anything. */
err = map_sp_threads(stream, true);
- if (err)
- {
+ if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
}
- for (i = 0; i < stream->num_pipes; i++)
- {
+ for (i = 0; i < stream->num_pipes; i++) {
struct ia_css_pipe *pipe = stream->pipes[i];
assert(pipe);
@@ -9119,8 +8975,7 @@ ia_css_acc_stream_create(struct ia_css_stream *stream) {
}
err = create_host_pipeline_structure(stream);
- if (err)
- {
+ if (err) {
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
}
@@ -9134,7 +8989,8 @@ ia_css_acc_stream_create(struct ia_css_stream *stream) {
static int
metadata_info_init(const struct ia_css_metadata_config *mdc,
- struct ia_css_metadata_info *md) {
+ struct ia_css_metadata_info *md)
+{
/* Either both width and height should be set or neither */
if ((mdc->resolution.height > 0) ^ (mdc->resolution.width > 0))
return -EINVAL;
@@ -9161,7 +9017,7 @@ static int check_pipe_resolutions(const struct ia_css_pipe *pipe)
}
if (ia_css_util_check_res(pipe->config.input_effective_res.width,
- pipe->config.input_effective_res.height) != 0) {
+ pipe->config.input_effective_res.height) != 0) {
IA_CSS_ERROR("effective resolution not supported");
err = -EINVAL;
goto EXIT;
@@ -9169,7 +9025,7 @@ static int check_pipe_resolutions(const struct ia_css_pipe *pipe)
if (!ia_css_util_resolution_is_zero(
pipe->stream->config.input_config.input_res)) {
if (!ia_css_util_res_leq(pipe->config.input_effective_res,
- pipe->stream->config.input_config.input_res)) {
+ pipe->stream->config.input_config.input_res)) {
IA_CSS_ERROR("effective resolution is larger than input resolution");
err = -EINVAL;
goto EXIT;
@@ -9192,9 +9048,10 @@ EXIT:
int
ia_css_stream_create(const struct ia_css_stream_config *stream_config,
- int num_pipes,
- struct ia_css_pipe *pipes[],
- struct ia_css_stream **stream) {
+ int num_pipes,
+ struct ia_css_pipe *pipes[],
+ struct ia_css_stream **stream)
+{
struct ia_css_pipe *curr_pipe;
struct ia_css_stream *curr_stream = NULL;
bool spcopyonly;
@@ -9213,8 +9070,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
/* some checks */
if (num_pipes == 0 ||
!stream ||
- !pipes)
- {
+ !pipes) {
err = -EINVAL;
IA_CSS_LEAVE_ERR(err);
return err;
@@ -9223,8 +9079,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
#if !defined(ISP2401)
/* We don't support metadata for JPEG stream, since they both use str2mem */
if (stream_config->input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8 &&
- stream_config->metadata_config.resolution.height > 0)
- {
+ stream_config->metadata_config.resolution.height > 0) {
err = -EINVAL;
IA_CSS_LEAVE_ERR(err);
return err;
@@ -9232,8 +9087,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
#endif
#ifdef ISP2401
- if (stream_config->online && stream_config->pack_raw_pixels)
- {
+ if (stream_config->online && stream_config->pack_raw_pixels) {
IA_CSS_LOG("online and pack raw is invalid on input system 2401");
err = -EINVAL;
IA_CSS_LEAVE_ERR(err);
@@ -9288,16 +9142,14 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
/* Currently we only supported metadata up to a certain size. */
err = metadata_info_init(&stream_config->metadata_config, &md_info);
- if (err)
- {
+ if (err) {
IA_CSS_LEAVE_ERR(err);
return err;
}
/* allocate the stream instance */
curr_stream = kzalloc(sizeof(struct ia_css_stream), GFP_KERNEL);
- if (!curr_stream)
- {
+ if (!curr_stream) {
err = -ENOMEM;
IA_CSS_LEAVE_ERR(err);
return err;
@@ -9308,8 +9160,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
/* allocate pipes */
curr_stream->num_pipes = num_pipes;
curr_stream->pipes = kcalloc(num_pipes, sizeof(struct ia_css_pipe *), GFP_KERNEL);
- if (!curr_stream->pipes)
- {
+ if (!curr_stream->pipes) {
curr_stream->num_pipes = 0;
kfree(curr_stream);
curr_stream = NULL;
@@ -9332,8 +9183,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
#endif
#ifdef ISP2401
- if (curr_stream->config.online)
- {
+ if (curr_stream->config.online) {
curr_stream->config.source.port.num_lanes =
stream_config->source.port.num_lanes;
curr_stream->config.mode = IA_CSS_INPUT_MODE_BUFFERED_SENSOR;
@@ -9351,8 +9201,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
curr_stream->config.lock_all);
/* copy mode specific stuff */
- switch (curr_stream->config.mode)
- {
+ switch (curr_stream->config.mode) {
case IA_CSS_INPUT_MODE_SENSOR:
case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
#if !defined(ISP2401)
@@ -9362,11 +9211,11 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
case IA_CSS_INPUT_MODE_TPG:
#if !defined(ISP2401)
IA_CSS_LOG("tpg_configuration: x_mask=%d, y_mask=%d, x_delta=%d, y_delta=%d, xy_mask=%d",
- curr_stream->config.source.tpg.x_mask,
- curr_stream->config.source.tpg.y_mask,
- curr_stream->config.source.tpg.x_delta,
- curr_stream->config.source.tpg.y_delta,
- curr_stream->config.source.tpg.xy_mask);
+ curr_stream->config.source.tpg.x_mask,
+ curr_stream->config.source.tpg.y_mask,
+ curr_stream->config.source.tpg.x_delta,
+ curr_stream->config.source.tpg.y_delta,
+ curr_stream->config.source.tpg.xy_mask);
sh_css_sp_configure_tpg(
curr_stream->config.source.tpg.x_mask,
@@ -9391,17 +9240,14 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
}
#ifdef ISP2401
- err = aspect_ratio_crop_init(curr_stream,
- pipes,
- &aspect_ratio_crop_enabled);
- if (err)
- {
+ err = aspect_ratio_crop_init(curr_stream, pipes,
+ &aspect_ratio_crop_enabled);
+ if (err) {
IA_CSS_LEAVE_ERR(err);
goto ERR;
}
#endif
- for (i = 0; i < num_pipes; i++)
- {
+ for (i = 0; i < num_pipes; i++) {
struct ia_css_resolution effective_res;
curr_pipe = pipes[i];
@@ -9432,8 +9278,8 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
curr_pipe->config.input_effective_res = effective_res;
}
IA_CSS_LOG("effective_res=%dx%d",
- effective_res.width,
- effective_res.height);
+ effective_res.width,
+ effective_res.height);
}
if (IS_ISP2401) {
@@ -9441,9 +9287,8 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
if (pipes[i]->config.mode != IA_CSS_PIPE_MODE_ACC &&
pipes[i]->config.mode != IA_CSS_PIPE_MODE_COPY) {
err = check_pipe_resolutions(pipes[i]);
- if (err) {
+ if (err)
goto ERR;
- }
}
}
}
@@ -9453,32 +9298,28 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
goto ERR;
IA_CSS_LOG("isp_params_configs: %p", curr_stream->isp_params_configs);
- if (num_pipes == 1 && pipes[0]->config.mode == IA_CSS_PIPE_MODE_ACC)
- {
+ if (num_pipes == 1 && pipes[0]->config.mode == IA_CSS_PIPE_MODE_ACC) {
*stream = curr_stream;
err = ia_css_acc_stream_create(curr_stream);
goto ERR;
}
/* sensor binning */
- if (!spcopyonly)
- {
+ if (!spcopyonly) {
sensor_binning_changed =
sh_css_params_set_binning_factor(curr_stream,
- curr_stream->config.sensor_binning_factor);
- } else
- {
+ curr_stream->config.sensor_binning_factor);
+ } else {
sensor_binning_changed = false;
}
IA_CSS_LOG("sensor_binning=%d, changed=%d",
- curr_stream->config.sensor_binning_factor, sensor_binning_changed);
+ curr_stream->config.sensor_binning_factor, sensor_binning_changed);
/* loop over pipes */
IA_CSS_LOG("num_pipes=%d", num_pipes);
curr_stream->cont_capt = false;
/* Temporary hack: we give the preview pipe a reference to the capture
* pipe in continuous capture mode. */
- if (curr_stream->config.continuous)
- {
+ if (curr_stream->config.continuous) {
/* Search for the preview pipe and create the copy pipe */
struct ia_css_pipe *preview_pipe;
struct ia_css_pipe *video_pipe;
@@ -9496,17 +9337,18 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
/* Create copy pipe here, since it may not be exposed to the driver */
preview_pipe = find_pipe(pipes, num_pipes,
- IA_CSS_PIPE_MODE_PREVIEW, false);
+ IA_CSS_PIPE_MODE_PREVIEW, false);
video_pipe = find_pipe(pipes, num_pipes,
- IA_CSS_PIPE_MODE_VIDEO, false);
- acc_pipe = find_pipe(pipes, num_pipes,
- IA_CSS_PIPE_MODE_ACC, false);
+ IA_CSS_PIPE_MODE_VIDEO, false);
+ acc_pipe = find_pipe(pipes, num_pipes, IA_CSS_PIPE_MODE_ACC,
+ false);
if (acc_pipe && num_pipes == 2 && curr_stream->cont_capt)
curr_stream->cont_capt =
false; /* preview + QoS case will not need cont_capt switch */
if (curr_stream->cont_capt) {
capture_pipe = find_pipe(pipes, num_pipes,
- IA_CSS_PIPE_MODE_CAPTURE, false);
+ IA_CSS_PIPE_MODE_CAPTURE,
+ false);
if (!capture_pipe) {
err = -EINVAL;
goto ERR;
@@ -9526,9 +9368,9 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
preview_pipe->pipe_settings.preview.copy_pipe = copy_pipe;
copy_pipe->stream = curr_stream;
}
- if (preview_pipe && curr_stream->cont_capt) {
+ if (preview_pipe && curr_stream->cont_capt)
preview_pipe->pipe_settings.preview.capture_pipe = capture_pipe;
- }
+
if (video_pipe && !video_pipe->pipe_settings.video.copy_pipe) {
err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, &copy_pipe, true);
if (err)
@@ -9537,15 +9379,13 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
video_pipe->pipe_settings.video.copy_pipe = copy_pipe;
copy_pipe->stream = curr_stream;
}
- if (video_pipe && curr_stream->cont_capt) {
+ if (video_pipe && curr_stream->cont_capt)
video_pipe->pipe_settings.video.capture_pipe = capture_pipe;
- }
- if (preview_pipe && acc_pipe) {
+
+ if (preview_pipe && acc_pipe)
preview_pipe->pipe_settings.preview.acc_pipe = acc_pipe;
- }
}
- for (i = 0; i < num_pipes; i++)
- {
+ for (i = 0; i < num_pipes; i++) {
curr_pipe = pipes[i];
/* set current stream */
curr_pipe->stream = curr_stream;
@@ -9566,8 +9406,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
}
/* now pipes have been configured, info should be available */
- for (i = 0; i < num_pipes; i++)
- {
+ for (i = 0; i < num_pipes; i++) {
struct ia_css_pipe_info *pipe_info = NULL;
curr_pipe = pipes[i];
@@ -9591,10 +9430,12 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
if (!spcopyonly) {
if (!IS_ISP2401)
err = sh_css_pipe_get_shading_info(curr_pipe,
- &pipe_info->shading_info, NULL);
+ &pipe_info->shading_info,
+ NULL);
else
err = sh_css_pipe_get_shading_info(curr_pipe,
- &pipe_info->shading_info, &curr_pipe->config);
+ &pipe_info->shading_info,
+ &curr_pipe->config);
if (err)
goto ERR;
@@ -9604,7 +9445,8 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
goto ERR;
for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) {
sh_css_pipe_get_viewfinder_frame_info(curr_pipe,
- &pipe_info->vf_output_info[j], j);
+ &pipe_info->vf_output_info[j],
+ j);
if (err)
goto ERR;
}
@@ -9617,22 +9459,19 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config,
/* Map SP threads before doing anything. */
err = map_sp_threads(curr_stream, true);
- if (err)
- {
+ if (err) {
IA_CSS_LOG("map_sp_threads: return_err=%d", err);
goto ERR;
}
- for (i = 0; i < num_pipes; i++)
- {
+ for (i = 0; i < num_pipes; i++) {
curr_pipe = pipes[i];
ia_css_pipe_map_queue(curr_pipe, true);
}
/* Create host side pipeline objects without stages */
err = create_host_pipeline_structure(curr_stream);
- if (err)
- {
+ if (err) {
IA_CSS_LOG("create_host_pipeline_structure: return_err=%d", err);
goto ERR;
}
@@ -9670,13 +9509,13 @@ ERR:
}
int
-ia_css_stream_destroy(struct ia_css_stream *stream) {
+ia_css_stream_destroy(struct ia_css_stream *stream)
+{
int i;
int err = 0;
IA_CSS_ENTER_PRIVATE("stream = %p", stream);
- if (!stream)
- {
+ if (!stream) {
err = -EINVAL;
IA_CSS_LEAVE_ERR_PRIVATE(err);
return err;
@@ -9685,8 +9524,7 @@ ia_css_stream_destroy(struct ia_css_stream *stream) {
ia_css_stream_isp_parameters_uninit(stream);
if ((stream->last_pipe) &&
- ia_css_pipeline_is_mapped(stream->last_pipe->pipe_num))
- {
+ ia_css_pipeline_is_mapped(stream->last_pipe->pipe_num)) {
#if defined(ISP2401)
bool free_mpi;
@@ -9748,8 +9586,7 @@ ia_css_stream_destroy(struct ia_css_stream *stream) {
}
/* remove references from pipes to stream */
- for (i = 0; i < stream->num_pipes; i++)
- {
+ for (i = 0; i < stream->num_pipes; i++) {
struct ia_css_pipe *entry = stream->pipes[i];
assert(entry);
@@ -9778,8 +9615,7 @@ ia_css_stream_destroy(struct ia_css_stream *stream) {
/* working mode: take out of the seed list */
if (my_css_save.mode == sh_css_mode_working) {
for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
- if (my_css_save.stream_seeds[i].stream == stream)
- {
+ if (my_css_save.stream_seeds[i].stream == stream) {
IA_CSS_LOG("took out stream %d", i);
my_css_save.stream_seeds[i].stream = NULL;
break;
@@ -9795,7 +9631,8 @@ ia_css_stream_destroy(struct ia_css_stream *stream) {
int
ia_css_stream_get_info(const struct ia_css_stream *stream,
- struct ia_css_stream_info *stream_info) {
+ struct ia_css_stream_info *stream_info)
+{
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_info: enter/exit\n");
assert(stream);
assert(stream_info);
@@ -9811,59 +9648,58 @@ ia_css_stream_get_info(const struct ia_css_stream *stream,
* The stream handle is used to identify the correct entry in the css_save struct
*/
int
-ia_css_stream_load(struct ia_css_stream *stream) {
- if (!IS_ISP2401) {
- int i;
- int err;
-
- assert(stream);
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() enter,\n");
- for (i = 0; i < MAX_ACTIVE_STREAMS; i++)
- {
- if (my_css_save.stream_seeds[i].stream == stream) {
- int j;
-
- for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) {
- if ((err = ia_css_pipe_create(&my_css_save.stream_seeds[i].pipe_config[j],
- &my_css_save.stream_seeds[i].pipes[j])) != 0) {
- if (j) {
- int k;
+ia_css_stream_load(struct ia_css_stream *stream)
+{
+ int i, j, err;
- for (k = 0; k < j; k++)
- ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[k]);
- }
- return err;
- }
- }
- err = ia_css_stream_create(&my_css_save.stream_seeds[i].stream_config,
- my_css_save.stream_seeds[i].num_pipes,
- my_css_save.stream_seeds[i].pipes,
- &my_css_save.stream_seeds[i].stream);
- if (err) {
- ia_css_stream_destroy(stream);
- for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++)
- ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]);
- return err;
- }
- break;
- }
- }
- ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() exit,\n");
- return 0;
- } else {
+ if (IS_ISP2401) {
/* TODO remove function - DEPRECATED */
(void)stream;
return -ENOTSUPP;
}
+
+ assert(stream);
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() enter,\n");
+ for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
+ if (my_css_save.stream_seeds[i].stream != stream)
+ continue;
+
+ for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) {
+ int k;
+
+ err = ia_css_pipe_create(&my_css_save.stream_seeds[i].pipe_config[j],
+ &my_css_save.stream_seeds[i].pipes[j]);
+ if (!err)
+ continue;
+
+ for (k = 0; k < j; k++)
+ ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[k]);
+ return err;
+ }
+ err = ia_css_stream_create(&my_css_save.stream_seeds[i].stream_config,
+ my_css_save.stream_seeds[i].num_pipes,
+ my_css_save.stream_seeds[i].pipes,
+ &my_css_save.stream_seeds[i].stream);
+ if (!err)
+ break;
+
+ ia_css_stream_destroy(stream);
+ for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++)
+ ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]);
+ return err;
+ }
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() exit,\n");
+ return 0;
}
int
-ia_css_stream_start(struct ia_css_stream *stream) {
+ia_css_stream_start(struct ia_css_stream *stream)
+{
int err = 0;
IA_CSS_ENTER("stream = %p", stream);
- if ((!stream) || (!stream->last_pipe))
- {
+ if ((!stream) || (!stream->last_pipe)) {
IA_CSS_LEAVE_ERR(-EINVAL);
return -EINVAL;
}
@@ -9873,8 +9709,7 @@ ia_css_stream_start(struct ia_css_stream *stream) {
/* Create host side pipeline. */
err = create_host_pipeline(stream);
- if (err)
- {
+ if (err) {
IA_CSS_LEAVE_ERR(err);
return err;
}
@@ -9887,8 +9722,7 @@ ia_css_stream_start(struct ia_css_stream *stream) {
#if !defined(ISP2401)
/* Initialize mipi size checks */
- if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
- {
+ if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
unsigned int idx;
unsigned int port = (unsigned int)(stream->config.source.port.port);
@@ -9899,8 +9733,7 @@ ia_css_stream_start(struct ia_css_stream *stream) {
}
#endif
- if (stream->config.mode != IA_CSS_INPUT_MODE_MEMORY)
- {
+ if (stream->config.mode != IA_CSS_INPUT_MODE_MEMORY) {
err = sh_css_config_input_network(stream);
if (err)
return err;
@@ -9912,7 +9745,8 @@ ia_css_stream_start(struct ia_css_stream *stream) {
}
int
-ia_css_stream_stop(struct ia_css_stream *stream) {
+ia_css_stream_stop(struct ia_css_stream *stream)
+{
int err = 0;
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop() enter/exit\n");
@@ -9923,22 +9757,19 @@ ia_css_stream_stop(struct ia_css_stream *stream) {
#if !defined(ISP2401)
/* De-initialize mipi size checks */
- if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
- {
+ if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
unsigned int idx;
unsigned int port = (unsigned int)(stream->config.source.port.port);
- for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++) {
+ for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++)
sh_css_sp_group.config.mipi_sizes_for_check[port][idx] = 0;
- }
}
#endif
- if (!IS_ISP2401) {
+ if (!IS_ISP2401)
err = ia_css_pipeline_request_stop(&stream->last_pipe->pipeline);
- } else {
+ else
err = sh_css_pipes_stop(stream);
- }
if (err)
return err;
@@ -9951,16 +9782,16 @@ ia_css_stream_stop(struct ia_css_stream *stream) {
}
bool
-ia_css_stream_has_stopped(struct ia_css_stream *stream) {
+ia_css_stream_has_stopped(struct ia_css_stream *stream)
+{
bool stopped;
assert(stream);
- if (!IS_ISP2401) {
+ if (!IS_ISP2401)
stopped = ia_css_pipeline_has_stopped(&stream->last_pipe->pipeline);
- } else {
+ else
stopped = sh_css_pipes_have_stopped(stream);
- }
return stopped;
}
@@ -9971,7 +9802,8 @@ ia_css_stream_has_stopped(struct ia_css_stream *stream) {
* The stream handle is used to identify the correct entry in the css_save struct
*/
int
-ia_css_stream_unload(struct ia_css_stream *stream) {
+ia_css_stream_unload(struct ia_css_stream *stream)
+{
int i;
assert(stream);
@@ -9979,8 +9811,7 @@ ia_css_stream_unload(struct ia_css_stream *stream) {
/* some checks */
assert(stream);
for (i = 0; i < MAX_ACTIVE_STREAMS; i++)
- if (my_css_save.stream_seeds[i].stream == stream)
- {
+ if (my_css_save.stream_seeds[i].stream == stream) {
int j;
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
@@ -10000,7 +9831,8 @@ ia_css_stream_unload(struct ia_css_stream *stream) {
int
ia_css_temp_pipe_to_pipe_id(const struct ia_css_pipe *pipe,
- enum ia_css_pipe_id *pipe_id) {
+ enum ia_css_pipe_id *pipe_id)
+{
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_temp_pipe_to_pipe_id() enter/exit\n");
if (pipe)
*pipe_id = pipe->mode;
@@ -10011,18 +9843,21 @@ ia_css_temp_pipe_to_pipe_id(const struct ia_css_pipe *pipe,
}
enum atomisp_input_format
-ia_css_stream_get_format(const struct ia_css_stream *stream) {
+ia_css_stream_get_format(const struct ia_css_stream *stream)
+{
return stream->config.input_config.format;
}
bool
-ia_css_stream_get_two_pixels_per_clock(const struct ia_css_stream *stream) {
+ia_css_stream_get_two_pixels_per_clock(const struct ia_css_stream *stream)
+{
return (stream->config.pixels_per_clock == 2);
}
struct ia_css_binary *
ia_css_stream_get_shading_correction_binary(const struct ia_css_stream
- *stream) {
+ *stream)
+{
struct ia_css_pipe *pipe;
assert(stream);
@@ -10040,7 +9875,8 @@ ia_css_stream_get_shading_correction_binary(const struct ia_css_stream
}
struct ia_css_binary *
-ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream) {
+ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream)
+{
int i;
struct ia_css_pipe *video_pipe = NULL;
@@ -10059,7 +9895,8 @@ ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream) {
}
struct ia_css_binary *
-ia_css_stream_get_3a_binary(const struct ia_css_stream *stream) {
+ia_css_stream_get_3a_binary(const struct ia_css_stream *stream)
+{
struct ia_css_pipe *pipe;
struct ia_css_binary *s3a_binary = NULL;
@@ -10081,7 +9918,8 @@ ia_css_stream_get_3a_binary(const struct ia_css_stream *stream) {
int
ia_css_stream_set_output_padded_width(struct ia_css_stream *stream,
- unsigned int output_padded_width) {
+ unsigned int output_padded_width)
+{
struct ia_css_pipe *pipe;
assert(stream);
@@ -10098,7 +9936,8 @@ ia_css_stream_set_output_padded_width(struct ia_css_stream *stream,
}
static struct ia_css_binary *
-ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe) {
+ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe)
+{
struct ia_css_binary *binary = NULL;
assert(pipe);
@@ -10143,7 +9982,8 @@ ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe) {
}
static struct ia_css_binary *
-ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe) {
+ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe)
+{
struct ia_css_binary *binary = NULL;
assert(pipe);
@@ -10166,9 +10006,9 @@ ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe) {
}
}
} else if (pipe->config.default_capture_config.mode ==
- IA_CSS_CAPTURE_MODE_BAYER)
+ IA_CSS_CAPTURE_MODE_BAYER) {
binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
- else if (pipe->config.default_capture_config.mode ==
+ } else if (pipe->config.default_capture_config.mode ==
IA_CSS_CAPTURE_MODE_ADVANCED ||
pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1)
@@ -10190,7 +10030,8 @@ ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe) {
}
static struct ia_css_binary *
-ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe) {
+ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe)
+{
struct ia_css_binary *binary = NULL;
assert(pipe);
@@ -10210,14 +10051,16 @@ ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe) {
}
struct ia_css_pipeline *
-ia_css_pipe_get_pipeline(const struct ia_css_pipe *pipe) {
+ia_css_pipe_get_pipeline(const struct ia_css_pipe *pipe)
+{
assert(pipe);
return (struct ia_css_pipeline *)&pipe->pipeline;
}
unsigned int
-ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe) {
+ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe)
+{
assert(pipe);
/* KW was not sure this function was not returning a value
@@ -10234,7 +10077,8 @@ ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe) {
}
unsigned int
-ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe) {
+ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe)
+{
assert(pipe);
return (unsigned int)pipe->config.isp_pipe_version;
@@ -10243,7 +10087,8 @@ ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe) {
#define SP_START_TIMEOUT_US 30000000
int
-ia_css_start_sp(void) {
+ia_css_start_sp(void)
+{
unsigned long timeout;
int err = 0;
@@ -10252,13 +10097,11 @@ ia_css_start_sp(void) {
/* waiting for the SP is completely started */
timeout = SP_START_TIMEOUT_US;
- while ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_INITIALIZED) && timeout)
- {
+ while ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_INITIALIZED) && timeout) {
timeout--;
udelay(1);
}
- if (timeout == 0)
- {
+ if (timeout == 0) {
IA_CSS_ERROR("timeout during SP initialization");
return -EINVAL;
}
@@ -10286,14 +10129,14 @@ ia_css_start_sp(void) {
#define SP_SHUTDOWN_TIMEOUT_US 200000
int
-ia_css_stop_sp(void) {
+ia_css_stop_sp(void)
+{
unsigned long timeout;
int err = 0;
IA_CSS_ENTER("void");
- if (!sh_css_sp_is_running())
- {
+ if (!sh_css_sp_is_running()) {
err = -EINVAL;
IA_CSS_LEAVE("SP already stopped : return_err=%d", err);
@@ -10305,8 +10148,7 @@ ia_css_stop_sp(void) {
if (!IS_ISP2401) {
sh_css_write_host2sp_command(host2sp_cmd_terminate);
} else {
- if (!sh_css_write_host2sp_command(host2sp_cmd_terminate))
- {
+ if (!sh_css_write_host2sp_command(host2sp_cmd_terminate)) {
IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed");
ia_css_debug_dump_sp_sw_debug_info();
ia_css_debug_dump_debug_info(NULL);
@@ -10316,27 +10158,23 @@ ia_css_stop_sp(void) {
sh_css_sp_set_sp_running(false);
timeout = SP_SHUTDOWN_TIMEOUT_US;
- while (!ia_css_spctrl_is_idle(SP0_ID) && timeout)
- {
+ while (!ia_css_spctrl_is_idle(SP0_ID) && timeout) {
timeout--;
udelay(1);
}
if ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED))
IA_CSS_WARNING("SP has not terminated (SW)");
- if (timeout == 0)
- {
+ if (timeout == 0) {
IA_CSS_WARNING("SP is not idle");
ia_css_debug_dump_sp_sw_debug_info();
}
timeout = SP_SHUTDOWN_TIMEOUT_US;
- while (!isp_ctrl_getbit(ISP0_ID, ISP_SC_REG, ISP_IDLE_BIT) && timeout)
- {
+ while (!isp_ctrl_getbit(ISP0_ID, ISP_SC_REG, ISP_IDLE_BIT) && timeout) {
timeout--;
udelay(1);
}
- if (timeout == 0)
- {
+ if (timeout == 0) {
IA_CSS_WARNING("ISP is not idle");
ia_css_debug_dump_sp_sw_debug_info();
}
@@ -10351,7 +10189,8 @@ ia_css_stop_sp(void) {
}
int
-ia_css_update_continuous_frames(struct ia_css_stream *stream) {
+ia_css_update_continuous_frames(struct ia_css_stream *stream)
+{
struct ia_css_pipe *pipe;
unsigned int i;
@@ -10359,8 +10198,7 @@ ia_css_update_continuous_frames(struct ia_css_stream *stream) {
IA_CSS_DEBUG_TRACE,
"sh_css_update_continuous_frames() enter:\n");
- if (!stream)
- {
+ if (!stream) {
ia_css_debug_dtrace(
IA_CSS_DEBUG_TRACE,
"sh_css_update_continuous_frames() leave: invalid stream, return_void\n");
@@ -10371,10 +10209,9 @@ ia_css_update_continuous_frames(struct ia_css_stream *stream) {
for (i = stream->config.init_num_cont_raw_buf;
i < stream->config.target_num_cont_raw_buf; i++)
- {
sh_css_update_host2sp_offline_frame(i,
pipe->continuous_frames[i], pipe->cont_md_buffers[i]);
- }
+
sh_css_update_host2sp_cont_num_raw_frames
(stream->config.target_num_cont_raw_buf, true);
ia_css_debug_dtrace(
@@ -10500,7 +10337,8 @@ void ia_css_pipe_map_queue(struct ia_css_pipe *pipe, bool map)
#if CONFIG_ON_FRAME_ENQUEUE()
static int set_config_on_frame_enqueue(struct ia_css_frame_info
- *info, struct frame_data_wrapper *frame) {
+ *info, struct frame_data_wrapper *frame)
+{
frame->config_on_frame_enqueue.padded_width = 0;
/* currently we support configuration on frame enqueue only on YUV formats */
@@ -10508,11 +10346,11 @@ static int set_config_on_frame_enqueue(struct ia_css_frame_info
switch (info->format) {
case IA_CSS_FRAME_FORMAT_YUV420:
case IA_CSS_FRAME_FORMAT_NV12:
- if (info->padded_width > info->res.width) {
+ if (info->padded_width > info->res.width)
frame->config_on_frame_enqueue.padded_width = info->padded_width;
- } else if ((info->padded_width < info->res.width) && (info->padded_width > 0)) {
+ else if ((info->padded_width < info->res.width) && (info->padded_width > 0))
return -EINVAL;
- }
+
/* nothing to do if width == padded width or padded width is zeroed (the same) */
break;
default:
@@ -10524,22 +10362,21 @@ static int set_config_on_frame_enqueue(struct ia_css_frame_info
#endif
int
-ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id) {
+ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id)
+{
int ret;
IA_CSS_ENTER("");
/* Only continuous streams have a tagger to which we can send the
* unlock message. */
- if (!stream || !stream->config.continuous)
- {
+ if (!stream || !stream->config.continuous) {
IA_CSS_ERROR("invalid stream pointer");
return -EINVAL;
}
if (exp_id > IA_CSS_ISYS_MAX_EXPOSURE_ID ||
- exp_id < IA_CSS_ISYS_MIN_EXPOSURE_ID)
- {
+ exp_id < IA_CSS_ISYS_MIN_EXPOSURE_ID) {
IA_CSS_ERROR("invalid exposure ID: %d\n", exp_id);
return -EINVAL;
}
@@ -10558,7 +10395,8 @@ ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id) {
*/
int
ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
- bool enable) {
+ bool enable)
+{
unsigned int thread_id;
struct ia_css_pipeline_stage *stage;
int err = 0;
@@ -10566,20 +10404,16 @@ ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
IA_CSS_ENTER("");
/* Parameter Check */
- if (!pipe || !pipe->stream)
- {
+ if (!pipe || !pipe->stream) {
IA_CSS_ERROR("Invalid Pipe.");
err = -EINVAL;
- } else if (!(pipe->config.acc_extension))
- {
+ } else if (!(pipe->config.acc_extension)) {
IA_CSS_ERROR("Invalid Pipe(No Extension Firmware)");
err = -EINVAL;
- } else if (!sh_css_sp_is_running())
- {
+ } else if (!sh_css_sp_is_running()) {
IA_CSS_ERROR("Leaving: queue unavailable.");
err = -EBUSY;
- } else
- {
+ } else {
/* Query the threadid and stage_num for the Extension firmware*/
ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
@@ -10607,7 +10441,8 @@ ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
*/
int
ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
- bool *enable) {
+ bool *enable)
+{
struct ia_css_pipeline_stage *stage;
unsigned int thread_id;
int err = 0;
@@ -10615,20 +10450,16 @@ ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
IA_CSS_ENTER("");
/* Parameter Check */
- if (!pipe || !pipe->stream)
- {
+ if (!pipe || !pipe->stream) {
IA_CSS_ERROR("Invalid Pipe.");
err = -EINVAL;
- } else if (!(pipe->config.acc_extension))
- {
+ } else if (!(pipe->config.acc_extension)) {
IA_CSS_ERROR("Invalid Pipe (No Extension Firmware).");
err = -EINVAL;
- } else if (!sh_css_sp_is_running())
- {
+ } else if (!sh_css_sp_is_running()) {
IA_CSS_ERROR("Leaving: queue unavailable.");
err = -EBUSY;
- } else
- {
+ } else {
/* Query the threadid and stage_num corresponding to the Extension firmware*/
ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
@@ -10646,9 +10477,10 @@ ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
/* ISP2401 */
int
ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe,
- u32 fw_handle,
- struct ia_css_isp_param_css_segments *css_seg,
- struct ia_css_isp_param_isp_segments *isp_seg) {
+ u32 fw_handle,
+ struct ia_css_isp_param_css_segments *css_seg,
+ struct ia_css_isp_param_isp_segments *isp_seg)
+{
unsigned int HIVE_ADDR_sp_group;
static struct sh_css_sp_group sp_group;
static struct sh_css_sp_stage sp_stage;
@@ -10666,27 +10498,23 @@ ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe,
fw = &sh_css_sp_fw;
/* Parameter Check */
- if (!pipe || !pipe->stream)
- {
+ if (!pipe || !pipe->stream) {
IA_CSS_ERROR("Invalid Pipe.");
err = -EINVAL;
- } else if (!(pipe->config.acc_extension))
- {
+ } else if (!(pipe->config.acc_extension)) {
IA_CSS_ERROR("Invalid Pipe (No Extension Firmware).");
err = -EINVAL;
- } else if (!sh_css_sp_is_running())
- {
+ } else if (!sh_css_sp_is_running()) {
IA_CSS_ERROR("Leaving: queue unavailable.");
err = -EBUSY;
- } else
- {
+ } else {
/* Query the thread_id and stage_num corresponding to the Extension firmware */
ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
if (!err) {
/* Get the Extension State */
enabled = (SH_CSS_QOS_STAGE_IS_ENABLED(&sh_css_sp_group.pipe[thread_id],
- stage->stage_num)) ? true : false;
+ stage->stage_num)) ? true : false;
/* Update mapped arg only when extension stage is not enabled */
if (enabled) {
IA_CSS_ERROR("Leaving: cannot update when stage is enabled.");
@@ -10696,13 +10524,14 @@ ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe,
HIVE_ADDR_sp_group = fw->info.sp.group;
sp_dmem_load(SP0_ID,
- (unsigned int)sp_address_of(sp_group),
- &sp_group, sizeof(struct sh_css_sp_group));
+ (unsigned int)sp_address_of(sp_group),
+ &sp_group,
+ sizeof(struct sh_css_sp_group));
hmm_load(sp_group.pipe[thread_id].sp_stage_addr[stage_num],
- &sp_stage, sizeof(struct sh_css_sp_stage));
+ &sp_stage, sizeof(struct sh_css_sp_stage));
hmm_load(sp_stage.isp_stage_addr,
- &isp_stage, sizeof(struct sh_css_isp_stage));
+ &isp_stage, sizeof(struct sh_css_isp_stage));
for (mem = 0; mem < N_IA_CSS_ISP_MEMORIES; mem++) {
isp_stage.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].address =
@@ -10718,7 +10547,8 @@ ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe,
}
hmm_store(sp_stage.isp_stage_addr,
- &isp_stage, sizeof(struct sh_css_isp_stage));
+ &isp_stage,
+ sizeof(struct sh_css_isp_stage));
}
}
}
@@ -10729,8 +10559,9 @@ ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe,
#ifdef ISP2401
static int
aspect_ratio_crop_init(struct ia_css_stream *curr_stream,
- struct ia_css_pipe *pipes[],
- bool *do_crop_status) {
+ struct ia_css_pipe *pipes[],
+ bool *do_crop_status)
+{
int err = 0;
int i;
struct ia_css_pipe *curr_pipe;
@@ -10739,15 +10570,13 @@ aspect_ratio_crop_init(struct ia_css_stream *curr_stream,
if ((!curr_stream) ||
(curr_stream->num_pipes == 0) ||
(!pipes) ||
- (!do_crop_status))
- {
+ (!do_crop_status)) {
err = -EINVAL;
IA_CSS_LEAVE_ERR(err);
return err;
}
- for (i = 0; i < curr_stream->num_pipes; i++)
- {
+ for (i = 0; i < curr_stream->num_pipes; i++) {
curr_pipe = pipes[i];
pipe_mask |= (1 << curr_pipe->config.mode);
}
@@ -10761,7 +10590,8 @@ aspect_ratio_crop_init(struct ia_css_stream *curr_stream,
}
static bool
-aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe) {
+aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe)
+{
bool status = false;
if ((curr_pipe) && enabled) {
@@ -10776,7 +10606,8 @@ aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe) {
static int
aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
- struct ia_css_resolution *effective_res) {
+ struct ia_css_resolution *effective_res)
+{
int err = 0;
struct ia_css_resolution crop_res;
struct ia_css_resolution *in_res = NULL;
@@ -10786,8 +10617,7 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
bool use_capt_pp_in_res = false;
if ((!curr_pipe) ||
- (!effective_res))
- {
+ (!effective_res)) {
err = -EINVAL;
IA_CSS_LEAVE_ERR(err);
return err;
@@ -10795,8 +10625,7 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
if ((curr_pipe->config.mode != IA_CSS_PIPE_MODE_PREVIEW) &&
(curr_pipe->config.mode != IA_CSS_PIPE_MODE_VIDEO) &&
- (curr_pipe->config.mode != IA_CSS_PIPE_MODE_CAPTURE))
- {
+ (curr_pipe->config.mode != IA_CSS_PIPE_MODE_CAPTURE)) {
err = -EINVAL;
IA_CSS_LEAVE_ERR(err);
return err;
@@ -10817,8 +10646,7 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
in_res = &curr_pipe->stream->config.input_config.effective_res;
out_res = &curr_pipe->output_info[0].res;
- switch (curr_pipe->config.mode)
- {
+ switch (curr_pipe->config.mode) {
case IA_CSS_PIPE_MODE_PREVIEW:
if (use_bds_output_info)
out_res = &curr_pipe->bds_output_info.res;
@@ -10838,27 +10666,26 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
case IA_CSS_PIPE_MODE_YUVPP:
default:
IA_CSS_ERROR("aspect ratio cropping invalid args: mode[%d]\n",
- curr_pipe->config.mode);
+ curr_pipe->config.mode);
assert(0);
break;
}
err = ia_css_frame_find_crop_resolution(in_res, out_res, &crop_res);
if (!err)
- {
*effective_res = crop_res;
- } else
- {
+ else
/* in case of error fallback to default
* effective resolution from driver. */
IA_CSS_LOG("ia_css_frame_find_crop_resolution() failed with err(%d)", err);
- }
+
return err;
}
#endif
static void
-sh_css_hmm_buffer_record_init(void) {
+sh_css_hmm_buffer_record_init(void)
+{
int i;
for (i = 0; i < MAX_HMM_BUFFER_NUM; i++)
@@ -10866,7 +10693,8 @@ sh_css_hmm_buffer_record_init(void) {
}
static void
-sh_css_hmm_buffer_record_uninit(void) {
+sh_css_hmm_buffer_record_uninit(void)
+{
int i;
struct sh_css_hmm_buffer_record *buffer_record = NULL;
@@ -10882,7 +10710,8 @@ sh_css_hmm_buffer_record_uninit(void) {
}
static void
-sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record) {
+sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record)
+{
assert(buffer_record);
buffer_record->in_use = false;
buffer_record->type = IA_CSS_BUFFER_TYPE_INVALID;
@@ -10893,14 +10722,15 @@ sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record) {
static struct sh_css_hmm_buffer_record
*sh_css_hmm_buffer_record_acquire(struct ia_css_rmgr_vbuf_handle *h_vbuf,
enum ia_css_buffer_type type,
- hrt_address kernel_ptr) {
+ hrt_address kernel_ptr)
+{
int i;
struct sh_css_hmm_buffer_record *buffer_record = NULL;
struct sh_css_hmm_buffer_record *out_buffer_record = NULL;
assert(h_vbuf);
assert((type > IA_CSS_BUFFER_TYPE_INVALID) &&
- (type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE));
+ (type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE));
assert(kernel_ptr != 0);
buffer_record = &hmm_buffer_record[0];
@@ -10921,7 +10751,8 @@ static struct sh_css_hmm_buffer_record
static struct sh_css_hmm_buffer_record
*sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr,
- enum ia_css_buffer_type type) {
+ enum ia_css_buffer_type type)
+{
int i;
struct sh_css_hmm_buffer_record *buffer_record = NULL;
bool found_record = false;
diff --git a/drivers/staging/media/av7110/Kconfig b/drivers/staging/media/av7110/Kconfig
new file mode 100644
index 000000000000..9faf9d2d4001
--- /dev/null
+++ b/drivers/staging/media/av7110/Kconfig
@@ -0,0 +1,94 @@
+# 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
+ depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
+ select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SP8870 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_L64781 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for SAA7146 and AV7110 based DVB cards as produced
+ by Fujitsu-Siemens, Technotrend, Hauppauge and others.
+
+ This driver only supports the fullfeatured cards with
+ onboard MPEG2 decoder.
+
+ This driver needs an external firmware. Please use the script
+ "<kerneldir>/scripts/get_dvb_firmware av7110" to
+ download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
+
+ Alternatively, you can download the file and use the kernel's
+ EXTRA_FIRMWARE configuration option to build it into your
+ kernel image by adding the filename to the EXTRA_FIRMWARE
+ configuration option string.
+
+ Say Y if you own such a card and want to use it.
+
+config DVB_AV7110_OSD
+ bool "AV7110 OSD support"
+ depends on DVB_AV7110
+ default y if DVB_AV7110=y || DVB_AV7110=m
+ help
+ The AV7110 firmware provides some code to generate an OnScreenDisplay
+ on the video output. This is kind of nonstandard and not guaranteed to
+ be maintained.
+
+ Anyway, some popular DVB software like VDR uses this OSD to render
+ its menus, so say Y if you want to use this software.
+
+ All other people say N.
+
+config DVB_BUDGET_PATCH
+ tristate "AV7110 cards with Budget Patch"
+ depends on DVB_BUDGET_CORE && I2C
+ depends on DVB_AV7110
+ select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for Budget Patch (full TS) modification on
+ SAA7146+AV7110 based cards (DVB-S cards). This
+ driver doesn't use onboard MPEG2 decoder. The
+ card is driven in Budget-only mode. Card is
+ required to have loaded firmware to tune properly.
+ Firmware can be loaded by insertion and removal of
+ standard AV7110 driver prior to loading this
+ driver.
+
+ Say Y if you own such a card and want to use it.
+
+ To compile this driver as a module, choose M here: the
+ module will be called budget-patch.
+
+if DVB_AV7110
+
+# Frontend driver that it is used only by AV7110 driver
+# While technically independent, it doesn't make sense to keep
+# it if we drop support for AV7110, as no other driver will use it.
+
+config DVB_SP8870
+ tristate "Spase sp8870 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ This driver needs external firmware. Please use the command
+ "<kerneldir>/scripts/get_dvb_firmware sp8870" to
+ download/extract it, and then copy it to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
+
+endif
diff --git a/drivers/staging/media/av7110/Makefile b/drivers/staging/media/av7110/Makefile
new file mode 100644
index 000000000000..307b267598ea
--- /dev/null
+++ b/drivers/staging/media/av7110/Makefile
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the AV7110 DVB device driver
+#
+
+dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o \
+ av7110_ipack.o dvb_filter.o
+
+ifdef CONFIG_DVB_AV7110_IR
+dvb-ttpci-objs += av7110_ir.o
+endif
+
+obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
+
+obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
+
+obj-$(CONFIG_DVB_SP8870) += sp8870.o
+
+ccflags-y += -I $(srctree)/drivers/media/dvb-frontends
+ccflags-y += -I $(srctree)/drivers/media/tuners
+ccflags-y += -I $(srctree)/drivers/media/pci/ttpci
+ccflags-y += -I $(srctree)/drivers/media/common
diff --git a/drivers/staging/media/av7110/TODO b/drivers/staging/media/av7110/TODO
new file mode 100644
index 000000000000..60062d8441b3
--- /dev/null
+++ b/drivers/staging/media/av7110/TODO
@@ -0,0 +1,3 @@
+- This driver is too old and relies on a different API.
+ Drop it from Kernel on a couple of versions.
+- Cleanup patches for the drivers here won't be accepted.
diff --git a/drivers/staging/media/av7110/audio-bilingual-channel-select.rst b/drivers/staging/media/av7110/audio-bilingual-channel-select.rst
new file mode 100644
index 000000000000..33b5363317f1
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-bilingual-channel-select.rst
@@ -0,0 +1,58 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_BILINGUAL_CHANNEL_SELECT:
+
+==============================
+AUDIO_BILINGUAL_CHANNEL_SELECT
+==============================
+
+Name
+----
+
+AUDIO_BILINGUAL_CHANNEL_SELECT
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_BILINGUAL_CHANNEL_SELECT
+
+``int ioctl(int fd, AUDIO_BILINGUAL_CHANNEL_SELECT, struct audio_channel_select *select)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ -
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ -
+
+ - audio_channel_select_t ch
+
+ - Select the output format of the audio (mono left/right, stereo).
+
+Description
+-----------
+
+This ioctl is obsolete. Do not use in new drivers. It has been replaced
+by the V4L2 ``V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK`` control
+for MPEG decoders controlled through V4L2.
+
+This ioctl call asks the Audio Device to select the requested channel
+for bilingual streams if possible.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-channel-select.rst b/drivers/staging/media/av7110/audio-channel-select.rst
new file mode 100644
index 000000000000..74093df92a68
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-channel-select.rst
@@ -0,0 +1,57 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_CHANNEL_SELECT:
+
+====================
+AUDIO_CHANNEL_SELECT
+====================
+
+Name
+----
+
+AUDIO_CHANNEL_SELECT
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_CHANNEL_SELECT
+
+``int ioctl(int fd, AUDIO_CHANNEL_SELECT, struct audio_channel_select *select)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ -
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ -
+
+ - audio_channel_select_t ch
+
+ - Select the output format of the audio (mono left/right, stereo).
+
+Description
+-----------
+
+This ioctl is for Digital TV devices only. To control a V4L2 decoder use the
+V4L2 ``V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK`` control instead.
+
+This ioctl call asks the Audio Device to select the requested channel if
+possible.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-clear-buffer.rst b/drivers/staging/media/av7110/audio-clear-buffer.rst
new file mode 100644
index 000000000000..a0ebb0278260
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-clear-buffer.rst
@@ -0,0 +1,48 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_CLEAR_BUFFER:
+
+==================
+AUDIO_CLEAR_BUFFER
+==================
+
+Name
+----
+
+AUDIO_CLEAR_BUFFER
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_CLEAR_BUFFER
+
+``int ioctl(int fd, AUDIO_CLEAR_BUFFER)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+Description
+-----------
+
+This ioctl call asks the Audio Device to clear all software and hardware
+buffers of the audio decoder device.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-continue.rst b/drivers/staging/media/av7110/audio-continue.rst
new file mode 100644
index 000000000000..a2e9850f37f2
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-continue.rst
@@ -0,0 +1,48 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_CONTINUE:
+
+==============
+AUDIO_CONTINUE
+==============
+
+Name
+----
+
+AUDIO_CONTINUE
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_CONTINUE
+
+``int ioctl(int fd, AUDIO_CONTINUE)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+Description
+-----------
+
+This ioctl restarts the decoding and playing process previously paused
+with AUDIO_PAUSE command.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-fclose.rst b/drivers/staging/media/av7110/audio-fclose.rst
new file mode 100644
index 000000000000..77857d578e83
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-fclose.rst
@@ -0,0 +1,51 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _audio_fclose:
+
+========================
+Digital TV audio close()
+========================
+
+Name
+----
+
+Digital TV audio close()
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:function:: int close(int fd)
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+Description
+-----------
+
+This system call closes a previously opened audio device.
+
+Return Value
+------------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - ``EBADF``
+
+ - fd is not a valid open file descriptor.
diff --git a/drivers/staging/media/av7110/audio-fopen.rst b/drivers/staging/media/av7110/audio-fopen.rst
new file mode 100644
index 000000000000..774daaab3bad
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-fopen.rst
@@ -0,0 +1,103 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _audio_fopen:
+
+=======================
+Digital TV audio open()
+=======================
+
+Name
+----
+
+Digital TV audio open()
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:function:: int open(const char *deviceName, int flags)
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - const char \*deviceName
+
+ - Name of specific audio device.
+
+ - .. row 2
+
+ - int flags
+
+ - A bit-wise OR of the following flags:
+
+ - .. row 3
+
+ -
+ - O_RDONLY read-only access
+
+ - .. row 4
+
+ -
+ - O_RDWR read/write access
+
+ - .. row 5
+
+ -
+ - O_NONBLOCK open in non-blocking mode
+
+ - .. row 6
+
+ -
+ - (blocking mode is the default)
+
+Description
+-----------
+
+This system call opens a named audio device (e.g.
+/dev/dvb/adapter0/audio0) for subsequent use. When an open() call has
+succeeded, the device will be ready for use. The significance of
+blocking or non-blocking mode is described in the documentation for
+functions where there is a difference. It does not affect the semantics
+of the open() call itself. A device opened in blocking mode can later be
+put into non-blocking mode (and vice versa) using the F_SETFL command
+of the fcntl system call. This is a standard system call, documented in
+the Linux manual page for fcntl. Only one user can open the Audio Device
+in O_RDWR mode. All other attempts to open the device in this mode will
+fail, and an error code will be returned. If the Audio Device is opened
+in O_RDONLY mode, the only ioctl call that can be used is
+AUDIO_GET_STATUS. All other call will return with an error code.
+
+Return Value
+------------
+
+.. tabularcolumns:: |p{2.5cm}|p{15.0cm}|
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - ``ENODEV``
+
+ - Device driver not loaded/available.
+
+ - .. row 2
+
+ - ``EBUSY``
+
+ - Device or resource busy.
+
+ - .. row 3
+
+ - ``EINVAL``
+
+ - Invalid argument.
diff --git a/drivers/staging/media/av7110/audio-fwrite.rst b/drivers/staging/media/av7110/audio-fwrite.rst
new file mode 100644
index 000000000000..7b096ac2b6c4
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-fwrite.rst
@@ -0,0 +1,79 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _audio_fwrite:
+
+=========================
+Digital TV audio write()
+=========================
+
+Name
+----
+
+Digital TV audio write()
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:function:: size_t write(int fd, const void *buf, size_t count)
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - void \*buf
+
+ - Pointer to the buffer containing the PES data.
+
+ - .. row 3
+
+ - size_t count
+
+ - Size of buf.
+
+Description
+-----------
+
+This system call can only be used if AUDIO_SOURCE_MEMORY is selected
+in the ioctl call AUDIO_SELECT_SOURCE. The data provided shall be in
+PES format. If O_NONBLOCK is not specified the function will block
+until buffer space is available. The amount of data to be transferred is
+implied by count.
+
+Return Value
+------------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - ``EPERM``
+
+ - Mode AUDIO_SOURCE_MEMORY not selected.
+
+ - .. row 2
+
+ - ``ENOMEM``
+
+ - Attempted to write more data than the internal buffer can hold.
+
+ - .. row 3
+
+ - ``EBADF``
+
+ - fd is not a valid open file descriptor.
diff --git a/drivers/staging/media/av7110/audio-get-capabilities.rst b/drivers/staging/media/av7110/audio-get-capabilities.rst
new file mode 100644
index 000000000000..6d9eb71dad17
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-get-capabilities.rst
@@ -0,0 +1,54 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_GET_CAPABILITIES:
+
+======================
+AUDIO_GET_CAPABILITIES
+======================
+
+Name
+----
+
+AUDIO_GET_CAPABILITIES
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_GET_CAPABILITIES
+
+``int ioctl(int fd, AUDIO_GET_CAPABILITIES, unsigned int *cap)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ -
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ -
+
+ - unsigned int \*cap
+
+ - Returns a bit array of supported sound formats.
+
+Description
+-----------
+
+This ioctl call asks the Audio Device to tell us about the decoding
+capabilities of the audio hardware.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-get-status.rst b/drivers/staging/media/av7110/audio-get-status.rst
new file mode 100644
index 000000000000..7ae8db2e65e9
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-get-status.rst
@@ -0,0 +1,54 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_GET_STATUS:
+
+================
+AUDIO_GET_STATUS
+================
+
+Name
+----
+
+AUDIO_GET_STATUS
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_GET_STATUS
+
+``int ioctl(int fd, AUDIO_GET_STATUS, struct audio_status *status)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ -
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ -
+
+ - struct audio_status \*status
+
+ - Returns the current state of Audio Device.
+
+Description
+-----------
+
+This ioctl call asks the Audio Device to return the current state of the
+Audio Device.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-pause.rst b/drivers/staging/media/av7110/audio-pause.rst
new file mode 100644
index 000000000000..d37d1ddce4df
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-pause.rst
@@ -0,0 +1,49 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_PAUSE:
+
+===========
+AUDIO_PAUSE
+===========
+
+Name
+----
+
+AUDIO_PAUSE
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_PAUSE
+
+``int ioctl(int fd, AUDIO_PAUSE)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+Description
+-----------
+
+This ioctl call suspends the audio stream being played. Decoding and
+playing are paused. It is then possible to restart again decoding and
+playing process of the audio stream using AUDIO_CONTINUE command.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-play.rst b/drivers/staging/media/av7110/audio-play.rst
new file mode 100644
index 000000000000..e591930b6ca7
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-play.rst
@@ -0,0 +1,48 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_PLAY:
+
+==========
+AUDIO_PLAY
+==========
+
+Name
+----
+
+AUDIO_PLAY
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_PLAY
+
+``int ioctl(int fd, AUDIO_PLAY)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+Description
+-----------
+
+This ioctl call asks the Audio Device to start playing an audio stream
+from the selected source.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-select-source.rst b/drivers/staging/media/av7110/audio-select-source.rst
new file mode 100644
index 000000000000..6a0c0f365eb1
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-select-source.rst
@@ -0,0 +1,56 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_SELECT_SOURCE:
+
+===================
+AUDIO_SELECT_SOURCE
+===================
+
+Name
+----
+
+AUDIO_SELECT_SOURCE
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_SELECT_SOURCE
+
+``int ioctl(int fd, AUDIO_SELECT_SOURCE, struct audio_stream_source *source)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ -
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ -
+
+ - audio_stream_source_t source
+
+ - Indicates the source that shall be used for the Audio stream.
+
+Description
+-----------
+
+This ioctl call informs the audio device which source shall be used for
+the input data. The possible sources are demux or memory. If
+AUDIO_SOURCE_MEMORY is selected, the data is fed to the Audio Device
+through the write command.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-set-av-sync.rst b/drivers/staging/media/av7110/audio-set-av-sync.rst
new file mode 100644
index 000000000000..85a8016bf025
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-set-av-sync.rst
@@ -0,0 +1,58 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_SET_AV_SYNC:
+
+=================
+AUDIO_SET_AV_SYNC
+=================
+
+Name
+----
+
+AUDIO_SET_AV_SYNC
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_SET_AV_SYNC
+
+``int ioctl(int fd, AUDIO_SET_AV_SYNC, boolean state)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ -
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ -
+
+ - boolean state
+
+ - Tells the Digital TV subsystem if A/V synchronization shall be ON or OFF.
+
+ TRUE: AV-sync ON
+
+ FALSE: AV-sync OFF
+
+Description
+-----------
+
+This ioctl call asks the Audio Device to turn ON or OFF A/V
+synchronization.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-set-bypass-mode.rst b/drivers/staging/media/av7110/audio-set-bypass-mode.rst
new file mode 100644
index 000000000000..80d551a2053a
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-set-bypass-mode.rst
@@ -0,0 +1,62 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_SET_BYPASS_MODE:
+
+=====================
+AUDIO_SET_BYPASS_MODE
+=====================
+
+Name
+----
+
+AUDIO_SET_BYPASS_MODE
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_SET_BYPASS_MODE
+
+``int ioctl(int fd, AUDIO_SET_BYPASS_MODE, boolean mode)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ -
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ -
+
+ - boolean mode
+
+ - Enables or disables the decoding of the current Audio stream in
+ the Digital TV subsystem.
+
+ TRUE: Bypass is disabled
+
+ FALSE: Bypass is enabled
+
+Description
+-----------
+
+This ioctl call asks the Audio Device to bypass the Audio decoder and
+forward the stream without decoding. This mode shall be used if streams
+that can't be handled by the Digital TV system shall be decoded. Dolby
+DigitalTM streams are automatically forwarded by the Digital TV subsystem if
+the hardware can handle it.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-set-id.rst b/drivers/staging/media/av7110/audio-set-id.rst
new file mode 100644
index 000000000000..39ad846d412d
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-set-id.rst
@@ -0,0 +1,59 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_SET_ID:
+
+============
+AUDIO_SET_ID
+============
+
+Name
+----
+
+AUDIO_SET_ID
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_SET_ID
+
+``int ioctl(int fd, AUDIO_SET_ID, int id)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ -
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ -
+
+ - int id
+
+ - audio sub-stream id
+
+Description
+-----------
+
+This ioctl selects which sub-stream is to be decoded if a program or
+system stream is sent to the video device. If no audio stream type is
+set the id has to be in [0xC0,0xDF] for MPEG sound, in [0x80,0x87] for
+AC3 and in [0xA0,0xA7] for LPCM. More specifications may follow for
+other stream types. If the stream type is set the id just specifies the
+substream id of the audio stream and only the first 5 bits are
+recognized.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-set-mixer.rst b/drivers/staging/media/av7110/audio-set-mixer.rst
new file mode 100644
index 000000000000..45dbdf4801e0
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-set-mixer.rst
@@ -0,0 +1,53 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_SET_MIXER:
+
+===============
+AUDIO_SET_MIXER
+===============
+
+Name
+----
+
+AUDIO_SET_MIXER
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_SET_MIXER
+
+``int ioctl(int fd, AUDIO_SET_MIXER, struct audio_mixer *mix)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ -
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ -
+
+ - audio_mixer_t \*mix
+
+ - mixer settings.
+
+Description
+-----------
+
+This ioctl lets you adjust the mixer settings of the audio decoder.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-set-mute.rst b/drivers/staging/media/av7110/audio-set-mute.rst
new file mode 100644
index 000000000000..987751f92967
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-set-mute.rst
@@ -0,0 +1,62 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_SET_MUTE:
+
+==============
+AUDIO_SET_MUTE
+==============
+
+Name
+----
+
+AUDIO_SET_MUTE
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_SET_MUTE
+
+``int ioctl(int fd, AUDIO_SET_MUTE, boolean state)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ -
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ -
+
+ - boolean state
+
+ - Indicates if audio device shall mute or not.
+
+ TRUE: Audio Mute
+
+ FALSE: Audio Un-mute
+
+Description
+-----------
+
+This ioctl is for Digital TV devices only. To control a V4L2 decoder use the
+V4L2 :ref:`VIDIOC_DECODER_CMD` with the
+``V4L2_DEC_CMD_START_MUTE_AUDIO`` flag instead.
+
+This ioctl call asks the audio device to mute the stream that is
+currently being played.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-set-streamtype.rst b/drivers/staging/media/av7110/audio-set-streamtype.rst
new file mode 100644
index 000000000000..77d73c74882f
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-set-streamtype.rst
@@ -0,0 +1,66 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_SET_STREAMTYPE:
+
+====================
+AUDIO_SET_STREAMTYPE
+====================
+
+Name
+----
+
+AUDIO_SET_STREAMTYPE
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_SET_STREAMTYPE
+
+``int ioctl(fd, AUDIO_SET_STREAMTYPE, int type)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ -
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ -
+
+ - int type
+
+ - stream type
+
+Description
+-----------
+
+This ioctl tells the driver which kind of audio stream to expect. This
+is useful if the stream offers several audio sub-streams like LPCM and
+AC3.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
+
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - ``EINVAL``
+
+ - type is not a valid or supported stream type.
diff --git a/drivers/staging/media/av7110/audio-stop.rst b/drivers/staging/media/av7110/audio-stop.rst
new file mode 100644
index 000000000000..d77f786fd797
--- /dev/null
+++ b/drivers/staging/media/av7110/audio-stop.rst
@@ -0,0 +1,48 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.audio
+
+.. _AUDIO_STOP:
+
+==========
+AUDIO_STOP
+==========
+
+Name
+----
+
+AUDIO_STOP
+
+.. attention:: This ioctl is deprecated
+
+Synopsis
+--------
+
+.. c:macro:: AUDIO_STOP
+
+``int ioctl(int fd, AUDIO_STOP)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+Description
+-----------
+
+This ioctl call asks the Audio Device to stop playing the current
+stream.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio.h b/drivers/staging/media/av7110/audio.h
new file mode 100644
index 000000000000..2f869da69171
--- /dev/null
+++ b/drivers/staging/media/av7110/audio.h
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */
+/*
+ * audio.h - DEPRECATED MPEG-TS audio decoder API
+ *
+ * NOTE: should not be used on future drivers
+ *
+ * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>
+ * & Marcus Metzler <marcus@convergence.de>
+ * for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Lesser Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser 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.
+ *
+ */
+
+#ifndef _DVBAUDIO_H_
+#define _DVBAUDIO_H_
+
+#include <linux/types.h>
+
+typedef enum {
+ AUDIO_SOURCE_DEMUX, /* Select the demux as the main source */
+ AUDIO_SOURCE_MEMORY /* Select internal memory as the main source */
+} audio_stream_source_t;
+
+
+typedef enum {
+ AUDIO_STOPPED, /* Device is stopped */
+ AUDIO_PLAYING, /* Device is currently playing */
+ AUDIO_PAUSED /* Device is paused */
+} audio_play_state_t;
+
+
+typedef enum {
+ AUDIO_STEREO,
+ AUDIO_MONO_LEFT,
+ AUDIO_MONO_RIGHT,
+ AUDIO_MONO,
+ AUDIO_STEREO_SWAPPED
+} audio_channel_select_t;
+
+
+typedef struct audio_mixer {
+ unsigned int volume_left;
+ unsigned int volume_right;
+ /* what else do we need? bass, pass-through, ... */
+} audio_mixer_t;
+
+
+typedef struct audio_status {
+ int AV_sync_state; /* sync audio and video? */
+ int mute_state; /* audio is muted */
+ audio_play_state_t play_state; /* current playback state */
+ audio_stream_source_t stream_source; /* current stream source */
+ audio_channel_select_t channel_select; /* currently selected channel */
+ int bypass_mode; /* pass on audio data to */
+ audio_mixer_t mixer_state; /* current mixer state */
+} audio_status_t; /* separate decoder hardware */
+
+
+/* for GET_CAPABILITIES and SET_FORMAT, the latter should only set one bit */
+#define AUDIO_CAP_DTS 1
+#define AUDIO_CAP_LPCM 2
+#define AUDIO_CAP_MP1 4
+#define AUDIO_CAP_MP2 8
+#define AUDIO_CAP_MP3 16
+#define AUDIO_CAP_AAC 32
+#define AUDIO_CAP_OGG 64
+#define AUDIO_CAP_SDDS 128
+#define AUDIO_CAP_AC3 256
+
+#define AUDIO_STOP _IO('o', 1)
+#define AUDIO_PLAY _IO('o', 2)
+#define AUDIO_PAUSE _IO('o', 3)
+#define AUDIO_CONTINUE _IO('o', 4)
+#define AUDIO_SELECT_SOURCE _IO('o', 5)
+#define AUDIO_SET_MUTE _IO('o', 6)
+#define AUDIO_SET_AV_SYNC _IO('o', 7)
+#define AUDIO_SET_BYPASS_MODE _IO('o', 8)
+#define AUDIO_CHANNEL_SELECT _IO('o', 9)
+#define AUDIO_GET_STATUS _IOR('o', 10, audio_status_t)
+
+#define AUDIO_GET_CAPABILITIES _IOR('o', 11, unsigned int)
+#define AUDIO_CLEAR_BUFFER _IO('o', 12)
+#define AUDIO_SET_ID _IO('o', 13)
+#define AUDIO_SET_MIXER _IOW('o', 14, audio_mixer_t)
+#define AUDIO_SET_STREAMTYPE _IO('o', 15)
+#define AUDIO_BILINGUAL_CHANNEL_SELECT _IO('o', 20)
+
+#endif /* _DVBAUDIO_H_ */
diff --git a/drivers/staging/media/av7110/audio.rst b/drivers/staging/media/av7110/audio.rst
new file mode 100644
index 000000000000..aa753336b31f
--- /dev/null
+++ b/drivers/staging/media/av7110/audio.rst
@@ -0,0 +1,27 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+
+.. _dvb_audio:
+
+#######################
+Digital TV Audio Device
+#######################
+
+The Digital TV audio device controls the MPEG2 audio decoder of the Digital
+TV hardware. It can be accessed through ``/dev/dvb/adapter?/audio?``. Data
+types and ioctl definitions can be accessed by including
+``linux/dvb/audio.h`` in your application.
+
+Please note that some Digital TV cards don't have their own MPEG decoder, which
+results in the omission of the audio and video device.
+
+These ioctls were also used by V4L2 to control MPEG decoders implemented
+in V4L2. The use of these ioctls for that purpose has been made obsolete
+and proper V4L2 ioctls or controls have been created to replace that
+functionality.
+
+
+.. toctree::
+ :maxdepth: 1
+
+ audio_data_types
+ audio_function_calls
diff --git a/drivers/staging/media/av7110/audio_data_types.rst b/drivers/staging/media/av7110/audio_data_types.rst
new file mode 100644
index 000000000000..4744529136a8
--- /dev/null
+++ b/drivers/staging/media/av7110/audio_data_types.rst
@@ -0,0 +1,116 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+
+.. _audio_data_types:
+
+****************
+Audio Data Types
+****************
+
+This section describes the structures, data types and defines used when
+talking to the audio device.
+
+.. c:type:: audio_stream_source
+
+The audio stream source is set through the AUDIO_SELECT_SOURCE call
+and can take the following values, depending on whether we are replaying
+from an internal (demux) or external (user write) source.
+
+
+.. code-block:: c
+
+ typedef enum {
+ AUDIO_SOURCE_DEMUX,
+ AUDIO_SOURCE_MEMORY
+ } audio_stream_source_t;
+
+AUDIO_SOURCE_DEMUX selects the demultiplexer (fed either by the
+frontend or the DVR device) as the source of the video stream. If
+AUDIO_SOURCE_MEMORY is selected the stream comes from the application
+through the ``write()`` system call.
+
+
+.. c:type:: audio_play_state
+
+The following values can be returned by the AUDIO_GET_STATUS call
+representing the state of audio playback.
+
+
+.. code-block:: c
+
+ typedef enum {
+ AUDIO_STOPPED,
+ AUDIO_PLAYING,
+ AUDIO_PAUSED
+ } audio_play_state_t;
+
+
+.. c:type:: audio_channel_select
+
+The audio channel selected via AUDIO_CHANNEL_SELECT is determined by
+the following values.
+
+
+.. code-block:: c
+
+ typedef enum {
+ AUDIO_STEREO,
+ AUDIO_MONO_LEFT,
+ AUDIO_MONO_RIGHT,
+ AUDIO_MONO,
+ AUDIO_STEREO_SWAPPED
+ } audio_channel_select_t;
+
+
+.. c:type:: audio_status
+
+The AUDIO_GET_STATUS call returns the following structure informing
+about various states of the playback operation.
+
+
+.. code-block:: c
+
+ typedef struct audio_status {
+ boolean AV_sync_state;
+ boolean mute_state;
+ audio_play_state_t play_state;
+ audio_stream_source_t stream_source;
+ audio_channel_select_t channel_select;
+ boolean bypass_mode;
+ audio_mixer_t mixer_state;
+ } audio_status_t;
+
+
+.. c:type:: audio_mixer
+
+The following structure is used by the AUDIO_SET_MIXER call to set the
+audio volume.
+
+
+.. code-block:: c
+
+ typedef struct audio_mixer {
+ unsigned int volume_left;
+ unsigned int volume_right;
+ } audio_mixer_t;
+
+
+.. _audio_encodings:
+
+audio encodings
+===============
+
+A call to AUDIO_GET_CAPABILITIES returns an unsigned integer with the
+following bits set according to the hardwares capabilities.
+
+
+.. code-block:: c
+
+ #define AUDIO_CAP_DTS 1
+ #define AUDIO_CAP_LPCM 2
+ #define AUDIO_CAP_MP1 4
+ #define AUDIO_CAP_MP2 8
+ #define AUDIO_CAP_MP3 16
+ #define AUDIO_CAP_AAC 32
+ #define AUDIO_CAP_OGG 64
+ #define AUDIO_CAP_SDDS 128
+ #define AUDIO_CAP_AC3 256
diff --git a/drivers/staging/media/av7110/audio_function_calls.rst b/drivers/staging/media/av7110/audio_function_calls.rst
new file mode 100644
index 000000000000..fa5ba9539caf
--- /dev/null
+++ b/drivers/staging/media/av7110/audio_function_calls.rst
@@ -0,0 +1,30 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+
+.. _audio_function_calls:
+
+********************
+Audio Function Calls
+********************
+
+.. toctree::
+ :maxdepth: 1
+
+ audio-fopen
+ audio-fclose
+ audio-fwrite
+ audio-stop
+ audio-play
+ audio-pause
+ audio-continue
+ audio-select-source
+ audio-set-mute
+ audio-set-av-sync
+ audio-set-bypass-mode
+ audio-channel-select
+ audio-bilingual-channel-select
+ audio-get-status
+ audio-get-capabilities
+ audio-clear-buffer
+ audio-set-id
+ audio-set-mixer
+ audio-set-streamtype
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/staging/media/av7110/av7110.c
index d74ee0ecfb36..d74ee0ecfb36 100644
--- a/drivers/media/pci/ttpci/av7110.c
+++ b/drivers/staging/media/av7110/av7110.c
diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/staging/media/av7110/av7110.h
index 809d938ae166..b8e8fc8ddbe9 100644
--- a/drivers/media/pci/ttpci/av7110.h
+++ b/drivers/staging/media/av7110/av7110.h
@@ -9,11 +9,12 @@
#include <linux/input.h>
#include <linux/time.h>
-#include <linux/dvb/video.h>
-#include <linux/dvb/audio.h>
+#include "video.h"
+#include "audio.h"
+#include "osd.h"
+
#include <linux/dvb/dmx.h>
#include <linux/dvb/ca.h>
-#include <linux/dvb/osd.h>
#include <linux/dvb/net.h>
#include <linux/mutex.h>
diff --git a/drivers/media/pci/ttpci/av7110_av.c b/drivers/staging/media/av7110/av7110_av.c
index 91f4866c7e59..91f4866c7e59 100644
--- a/drivers/media/pci/ttpci/av7110_av.c
+++ b/drivers/staging/media/av7110/av7110_av.c
diff --git a/drivers/media/pci/ttpci/av7110_av.h b/drivers/staging/media/av7110/av7110_av.h
index 71bbd4391f57..71bbd4391f57 100644
--- a/drivers/media/pci/ttpci/av7110_av.h
+++ b/drivers/staging/media/av7110/av7110_av.h
diff --git a/drivers/media/pci/ttpci/av7110_ca.c b/drivers/staging/media/av7110/av7110_ca.c
index c1338e074a3d..c1338e074a3d 100644
--- a/drivers/media/pci/ttpci/av7110_ca.c
+++ b/drivers/staging/media/av7110/av7110_ca.c
diff --git a/drivers/media/pci/ttpci/av7110_ca.h b/drivers/staging/media/av7110/av7110_ca.h
index a6e3f2955730..a6e3f2955730 100644
--- a/drivers/media/pci/ttpci/av7110_ca.h
+++ b/drivers/staging/media/av7110/av7110_ca.h
diff --git a/drivers/media/pci/ttpci/av7110_hw.c b/drivers/staging/media/av7110/av7110_hw.c
index 93ca31e38ddd..93ca31e38ddd 100644
--- a/drivers/media/pci/ttpci/av7110_hw.c
+++ b/drivers/staging/media/av7110/av7110_hw.c
diff --git a/drivers/media/pci/ttpci/av7110_hw.h b/drivers/staging/media/av7110/av7110_hw.h
index 6380d8950c69..6380d8950c69 100644
--- a/drivers/media/pci/ttpci/av7110_hw.h
+++ b/drivers/staging/media/av7110/av7110_hw.h
diff --git a/drivers/media/pci/ttpci/av7110_ipack.c b/drivers/staging/media/av7110/av7110_ipack.c
index 30330ed01ce8..30330ed01ce8 100644
--- a/drivers/media/pci/ttpci/av7110_ipack.c
+++ b/drivers/staging/media/av7110/av7110_ipack.c
diff --git a/drivers/media/pci/ttpci/av7110_ipack.h b/drivers/staging/media/av7110/av7110_ipack.h
index 943ec899bb93..943ec899bb93 100644
--- a/drivers/media/pci/ttpci/av7110_ipack.h
+++ b/drivers/staging/media/av7110/av7110_ipack.h
diff --git a/drivers/media/pci/ttpci/av7110_ir.c b/drivers/staging/media/av7110/av7110_ir.c
index a851ba328e4a..a851ba328e4a 100644
--- a/drivers/media/pci/ttpci/av7110_ir.c
+++ b/drivers/staging/media/av7110/av7110_ir.c
diff --git a/drivers/media/pci/ttpci/av7110_v4l.c b/drivers/staging/media/av7110/av7110_v4l.c
index c89f536f699c..c89f536f699c 100644
--- a/drivers/media/pci/ttpci/av7110_v4l.c
+++ b/drivers/staging/media/av7110/av7110_v4l.c
diff --git a/drivers/media/pci/ttpci/budget-patch.c b/drivers/staging/media/av7110/budget-patch.c
index d173c8ade6a7..d173c8ade6a7 100644
--- a/drivers/media/pci/ttpci/budget-patch.c
+++ b/drivers/staging/media/av7110/budget-patch.c
diff --git a/drivers/media/pci/ttpci/dvb_filter.c b/drivers/staging/media/av7110/dvb_filter.c
index 8c2eca5dcdc9..8c2eca5dcdc9 100644
--- a/drivers/media/pci/ttpci/dvb_filter.c
+++ b/drivers/staging/media/av7110/dvb_filter.c
diff --git a/drivers/media/pci/ttpci/dvb_filter.h b/drivers/staging/media/av7110/dvb_filter.h
index 67a3c6333bca..67a3c6333bca 100644
--- a/drivers/media/pci/ttpci/dvb_filter.h
+++ b/drivers/staging/media/av7110/dvb_filter.h
diff --git a/drivers/staging/media/av7110/osd.h b/drivers/staging/media/av7110/osd.h
new file mode 100644
index 000000000000..858997c74043
--- /dev/null
+++ b/drivers/staging/media/av7110/osd.h
@@ -0,0 +1,181 @@
+/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */
+/*
+ * osd.h - DEPRECATED On Screen Display API
+ *
+ * NOTE: should not be used on future drivers
+ *
+ * Copyright (C) 2001 Ralph Metzler <ralph@convergence.de>
+ * & Marcus Metzler <marcus@convergence.de>
+ * for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Lesser Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser 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.
+ *
+ */
+
+#ifndef _DVBOSD_H_
+#define _DVBOSD_H_
+
+#include <linux/compiler.h>
+
+typedef enum {
+ /* All functions return -2 on "not open" */
+ OSD_Close = 1, /* () */
+ /*
+ * Disables OSD and releases the buffers
+ * returns 0 on success
+ */
+ OSD_Open, /* (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0)) */
+ /*
+ * Opens OSD with this size and bit depth
+ * returns 0 on success, -1 on DRAM allocation error, -2 on "already open"
+ */
+ OSD_Show, /* () */
+ /*
+ * enables OSD mode
+ * returns 0 on success
+ */
+ OSD_Hide, /* () */
+ /*
+ * disables OSD mode
+ * returns 0 on success
+ */
+ OSD_Clear, /* () */
+ /*
+ * Sets all pixel to color 0
+ * returns 0 on success
+ */
+ OSD_Fill, /* (color) */
+ /*
+ * Sets all pixel to color <col>
+ * returns 0 on success
+ */
+ OSD_SetColor, /* (color,R{x0},G{y0},B{x1},opacity{y1}) */
+ /*
+ * set palette entry <num> to <r,g,b>, <mix> and <trans> apply
+ * R,G,B: 0..255
+ * R=Red, G=Green, B=Blue
+ * opacity=0: pixel opacity 0% (only video pixel shows)
+ * opacity=1..254: pixel opacity as specified in header
+ * opacity=255: pixel opacity 100% (only OSD pixel shows)
+ * returns 0 on success, -1 on error
+ */
+ OSD_SetPalette, /* (firstcolor{color},lastcolor{x0},data) */
+ /*
+ * Set a number of entries in the palette
+ * sets the entries "firstcolor" through "lastcolor" from the array "data"
+ * data has 4 byte for each color:
+ * R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel
+ */
+ OSD_SetTrans, /* (transparency{color}) */
+ /*
+ * Sets transparency of mixed pixel (0..15)
+ * returns 0 on success
+ */
+ OSD_SetPixel, /* (x0,y0,color) */
+ /*
+ * sets pixel <x>,<y> to color number <col>
+ * returns 0 on success, -1 on error
+ */
+ OSD_GetPixel, /* (x0,y0) */
+ /* returns color number of pixel <x>,<y>, or -1 */
+ OSD_SetRow, /* (x0,y0,x1,data) */
+ /*
+ * fills pixels x0,y through x1,y with the content of data[]
+ * returns 0 on success, -1 on clipping all pixel (no pixel drawn)
+ */
+ OSD_SetBlock, /* (x0,y0,x1,y1,increment{color},data) */
+ /*
+ * fills pixels x0,y0 through x1,y1 with the content of data[]
+ * inc contains the width of one line in the data block,
+ * inc<=0 uses blockwidth as linewidth
+ * returns 0 on success, -1 on clipping all pixel
+ */
+ OSD_FillRow, /* (x0,y0,x1,color) */
+ /*
+ * fills pixels x0,y through x1,y with the color <col>
+ * returns 0 on success, -1 on clipping all pixel
+ */
+ OSD_FillBlock, /* (x0,y0,x1,y1,color) */
+ /*
+ * fills pixels x0,y0 through x1,y1 with the color <col>
+ * returns 0 on success, -1 on clipping all pixel
+ */
+ OSD_Line, /* (x0,y0,x1,y1,color) */
+ /*
+ * draw a line from x0,y0 to x1,y1 with the color <col>
+ * returns 0 on success
+ */
+ OSD_Query, /* (x0,y0,x1,y1,xasp{color}}), yasp=11 */
+ /*
+ * fills parameters with the picture dimensions and the pixel aspect ratio
+ * returns 0 on success
+ */
+ OSD_Test, /* () */
+ /*
+ * draws a test picture. for debugging purposes only
+ * returns 0 on success
+ * TODO: remove "test" in final version
+ */
+ OSD_Text, /* (x0,y0,size,color,text) */
+ OSD_SetWindow, /* (x0) set window with number 0<x0<8 as current */
+ OSD_MoveWindow, /* move current window to (x0, y0) */
+ OSD_OpenRaw, /* Open other types of OSD windows */
+} OSD_Command;
+
+typedef struct osd_cmd_s {
+ OSD_Command cmd;
+ int x0;
+ int y0;
+ int x1;
+ int y1;
+ int color;
+ void __user *data;
+} osd_cmd_t;
+
+/* OSD_OpenRaw: set 'color' to desired window type */
+typedef enum {
+ OSD_BITMAP1, /* 1 bit bitmap */
+ OSD_BITMAP2, /* 2 bit bitmap */
+ OSD_BITMAP4, /* 4 bit bitmap */
+ OSD_BITMAP8, /* 8 bit bitmap */
+ OSD_BITMAP1HR, /* 1 Bit bitmap half resolution */
+ OSD_BITMAP2HR, /* 2 bit bitmap half resolution */
+ OSD_BITMAP4HR, /* 4 bit bitmap half resolution */
+ OSD_BITMAP8HR, /* 8 bit bitmap half resolution */
+ OSD_YCRCB422, /* 4:2:2 YCRCB Graphic Display */
+ OSD_YCRCB444, /* 4:4:4 YCRCB Graphic Display */
+ OSD_YCRCB444HR, /* 4:4:4 YCRCB graphic half resolution */
+ OSD_VIDEOTSIZE, /* True Size Normal MPEG Video Display */
+ OSD_VIDEOHSIZE, /* MPEG Video Display Half Resolution */
+ OSD_VIDEOQSIZE, /* MPEG Video Display Quarter Resolution */
+ OSD_VIDEODSIZE, /* MPEG Video Display Double Resolution */
+ OSD_VIDEOTHSIZE, /* True Size MPEG Video Display Half Resolution */
+ OSD_VIDEOTQSIZE, /* True Size MPEG Video Display Quarter Resolution*/
+ OSD_VIDEOTDSIZE, /* True Size MPEG Video Display Double Resolution */
+ OSD_VIDEONSIZE, /* Full Size MPEG Video Display */
+ OSD_CURSOR /* Cursor */
+} osd_raw_window_t;
+
+typedef struct osd_cap_s {
+ int cmd;
+#define OSD_CAP_MEMSIZE 1 /* memory size */
+ long val;
+} osd_cap_t;
+
+
+#define OSD_SEND_CMD _IOW('o', 160, osd_cmd_t)
+#define OSD_GET_CAPABILITY _IOR('o', 161, osd_cap_t)
+
+#endif
diff --git a/drivers/media/dvb-frontends/sp8870.c b/drivers/staging/media/av7110/sp8870.c
index 9767159aeb9b..9767159aeb9b 100644
--- a/drivers/media/dvb-frontends/sp8870.c
+++ b/drivers/staging/media/av7110/sp8870.c
diff --git a/drivers/media/dvb-frontends/sp8870.h b/drivers/staging/media/av7110/sp8870.h
index 5eacf39f425e..5eacf39f425e 100644
--- a/drivers/media/dvb-frontends/sp8870.h
+++ b/drivers/staging/media/av7110/sp8870.h
diff --git a/drivers/staging/media/av7110/video-clear-buffer.rst b/drivers/staging/media/av7110/video-clear-buffer.rst
new file mode 100644
index 000000000000..a7730559bbb2
--- /dev/null
+++ b/drivers/staging/media/av7110/video-clear-buffer.rst
@@ -0,0 +1,54 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_CLEAR_BUFFER:
+
+==================
+VIDEO_CLEAR_BUFFER
+==================
+
+Name
+----
+
+VIDEO_CLEAR_BUFFER
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_CLEAR_BUFFER
+
+``int ioctl(fd, VIDEO_CLEAR_BUFFER)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_CLEAR_BUFFER for this command.
+
+Description
+-----------
+
+This ioctl call clears all video buffers in the driver and in the
+decoder hardware.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-command.rst b/drivers/staging/media/av7110/video-command.rst
new file mode 100644
index 000000000000..cae9445eb3af
--- /dev/null
+++ b/drivers/staging/media/av7110/video-command.rst
@@ -0,0 +1,96 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_COMMAND:
+
+=============
+VIDEO_COMMAND
+=============
+
+Name
+----
+
+VIDEO_COMMAND
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_COMMAND
+
+``int ioctl(int fd, VIDEO_COMMAND, struct video_command *cmd)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_COMMAND for this command.
+
+ - .. row 3
+
+ - struct video_command \*cmd
+
+ - Commands the decoder.
+
+Description
+-----------
+
+This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders
+this ioctl has been replaced by the
+:ref:`VIDIOC_DECODER_CMD` ioctl.
+
+This ioctl commands the decoder. The ``video_command`` struct is a
+subset of the ``v4l2_decoder_cmd`` struct, so refer to the
+:ref:`VIDIOC_DECODER_CMD` documentation for
+more information.
+
+.. c:type:: video_command
+
+.. code-block:: c
+
+ /* The structure must be zeroed before use by the application
+ This ensures it can be extended safely in the future. */
+ struct video_command {
+ __u32 cmd;
+ __u32 flags;
+ union {
+ struct {
+ __u64 pts;
+ } stop;
+
+ struct {
+ /* 0 or 1000 specifies normal speed,
+ 1 specifies forward single stepping,
+ -1 specifies backward single stepping,
+ >1: playback at speed/1000 of the normal speed,
+ <-1: reverse playback at (-speed/1000) of the normal speed. */
+ __s32 speed;
+ __u32 format;
+ } play;
+
+ struct {
+ __u32 data[16];
+ } raw;
+ };
+ };
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-continue.rst b/drivers/staging/media/av7110/video-continue.rst
new file mode 100644
index 000000000000..bc34bf3989e4
--- /dev/null
+++ b/drivers/staging/media/av7110/video-continue.rst
@@ -0,0 +1,57 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_CONTINUE:
+
+==============
+VIDEO_CONTINUE
+==============
+
+Name
+----
+
+VIDEO_CONTINUE
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_CONTINUE
+
+``int ioctl(fd, VIDEO_CONTINUE)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_CONTINUE for this command.
+
+Description
+-----------
+
+This ioctl is for Digital TV devices only. To control a V4L2 decoder use the
+V4L2 :ref:`VIDIOC_DECODER_CMD` instead.
+
+This ioctl call restarts decoding and playing processes of the video
+stream which was played before a call to VIDEO_FREEZE was made.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-fast-forward.rst b/drivers/staging/media/av7110/video-fast-forward.rst
new file mode 100644
index 000000000000..e71fa8d6965b
--- /dev/null
+++ b/drivers/staging/media/av7110/video-fast-forward.rst
@@ -0,0 +1,72 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_FAST_FORWARD:
+
+==================
+VIDEO_FAST_FORWARD
+==================
+
+Name
+----
+
+VIDEO_FAST_FORWARD
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_FAST_FORWARD
+
+``int ioctl(fd, VIDEO_FAST_FORWARD, int nFrames)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_FAST_FORWARD for this command.
+
+ - .. row 3
+
+ - int nFrames
+
+ - The number of frames to skip.
+
+Description
+-----------
+
+This ioctl call asks the Video Device to skip decoding of N number of
+I-frames. This call can only be used if VIDEO_SOURCE_MEMORY is
+selected.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
+
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - ``EPERM``
+
+ - Mode VIDEO_SOURCE_MEMORY not selected.
diff --git a/drivers/staging/media/av7110/video-fclose.rst b/drivers/staging/media/av7110/video-fclose.rst
new file mode 100644
index 000000000000..01d24d548439
--- /dev/null
+++ b/drivers/staging/media/av7110/video-fclose.rst
@@ -0,0 +1,51 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _video_fclose:
+
+=================
+dvb video close()
+=================
+
+Name
+----
+
+dvb video close()
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:function:: int close(int fd)
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+Description
+-----------
+
+This system call closes a previously opened video device.
+
+Return Value
+------------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - ``EBADF``
+
+ - fd is not a valid open file descriptor.
diff --git a/drivers/staging/media/av7110/video-fopen.rst b/drivers/staging/media/av7110/video-fopen.rst
new file mode 100644
index 000000000000..1371b083e4e8
--- /dev/null
+++ b/drivers/staging/media/av7110/video-fopen.rst
@@ -0,0 +1,111 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _video_fopen:
+
+================
+dvb video open()
+================
+
+Name
+----
+
+dvb video open()
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:function:: int open(const char *deviceName, int flags)
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - const char \*deviceName
+
+ - Name of specific video device.
+
+ - .. row 2
+
+ - int flags
+
+ - A bit-wise OR of the following flags:
+
+ - .. row 3
+
+ -
+ - O_RDONLY read-only access
+
+ - .. row 4
+
+ -
+ - O_RDWR read/write access
+
+ - .. row 5
+
+ -
+ - O_NONBLOCK open in non-blocking mode
+
+ - .. row 6
+
+ -
+ - (blocking mode is the default)
+
+Description
+-----------
+
+This system call opens a named video device (e.g.
+/dev/dvb/adapter0/video0) for subsequent use.
+
+When an open() call has succeeded, the device will be ready for use. The
+significance of blocking or non-blocking mode is described in the
+documentation for functions where there is a difference. It does not
+affect the semantics of the open() call itself. A device opened in
+blocking mode can later be put into non-blocking mode (and vice versa)
+using the F_SETFL command of the fcntl system call. This is a standard
+system call, documented in the Linux manual page for fcntl. Only one
+user can open the Video Device in O_RDWR mode. All other attempts to
+open the device in this mode will fail, and an error-code will be
+returned. If the Video Device is opened in O_RDONLY mode, the only
+ioctl call that can be used is VIDEO_GET_STATUS. All other call will
+return an error code.
+
+Return Value
+------------
+
+.. tabularcolumns:: |p{2.5cm}|p{15.0cm}|
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - ``ENODEV``
+
+ - Device driver not loaded/available.
+
+ - .. row 2
+
+ - ``EINTERNAL``
+
+ - Internal error.
+
+ - .. row 3
+
+ - ``EBUSY``
+
+ - Device or resource busy.
+
+ - .. row 4
+
+ - ``EINVAL``
+
+ - Invalid argument.
diff --git a/drivers/staging/media/av7110/video-freeze.rst b/drivers/staging/media/av7110/video-freeze.rst
new file mode 100644
index 000000000000..4321f257cb70
--- /dev/null
+++ b/drivers/staging/media/av7110/video-freeze.rst
@@ -0,0 +1,61 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_FREEZE:
+
+============
+VIDEO_FREEZE
+============
+
+Name
+----
+
+VIDEO_FREEZE
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_FREEZE
+
+``int ioctl(fd, VIDEO_FREEZE)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_FREEZE for this command.
+
+Description
+-----------
+
+This ioctl is for Digital TV devices only. To control a V4L2 decoder use the
+V4L2 :ref:`VIDIOC_DECODER_CMD` instead.
+
+This ioctl call suspends the live video stream being played. Decoding
+and playing are frozen. It is then possible to restart the decoding and
+playing process of the video stream using the VIDEO_CONTINUE command.
+If VIDEO_SOURCE_MEMORY is selected in the ioctl call
+VIDEO_SELECT_SOURCE, the Digital TV subsystem will not decode any more data
+until the ioctl call VIDEO_CONTINUE or VIDEO_PLAY is performed.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-fwrite.rst b/drivers/staging/media/av7110/video-fwrite.rst
new file mode 100644
index 000000000000..a07fd7d7a40e
--- /dev/null
+++ b/drivers/staging/media/av7110/video-fwrite.rst
@@ -0,0 +1,79 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _video_fwrite:
+
+=================
+dvb video write()
+=================
+
+Name
+----
+
+dvb video write()
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:function:: size_t write(int fd, const void *buf, size_t count)
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - void \*buf
+
+ - Pointer to the buffer containing the PES data.
+
+ - .. row 3
+
+ - size_t count
+
+ - Size of buf.
+
+Description
+-----------
+
+This system call can only be used if VIDEO_SOURCE_MEMORY is selected
+in the ioctl call VIDEO_SELECT_SOURCE. The data provided shall be in
+PES format, unless the capability allows other formats. If O_NONBLOCK
+is not specified the function will block until buffer space is
+available. The amount of data to be transferred is implied by count.
+
+Return Value
+------------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - ``EPERM``
+
+ - Mode VIDEO_SOURCE_MEMORY not selected.
+
+ - .. row 2
+
+ - ``ENOMEM``
+
+ - Attempted to write more data than the internal buffer can hold.
+
+ - .. row 3
+
+ - ``EBADF``
+
+ - fd is not a valid open file descriptor.
diff --git a/drivers/staging/media/av7110/video-get-capabilities.rst b/drivers/staging/media/av7110/video-get-capabilities.rst
new file mode 100644
index 000000000000..01e09f56656c
--- /dev/null
+++ b/drivers/staging/media/av7110/video-get-capabilities.rst
@@ -0,0 +1,61 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_GET_CAPABILITIES:
+
+======================
+VIDEO_GET_CAPABILITIES
+======================
+
+Name
+----
+
+VIDEO_GET_CAPABILITIES
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_GET_CAPABILITIES
+
+``int ioctl(fd, VIDEO_GET_CAPABILITIES, unsigned int *cap)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_GET_CAPABILITIES for this command.
+
+ - .. row 3
+
+ - unsigned int \*cap
+
+ - Pointer to a location where to store the capability information.
+
+Description
+-----------
+
+This ioctl call asks the video device about its decoding capabilities.
+On success it returns and integer which has bits set according to the
+defines in section ??.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-get-event.rst b/drivers/staging/media/av7110/video-get-event.rst
new file mode 100644
index 000000000000..90382bc36cfe
--- /dev/null
+++ b/drivers/staging/media/av7110/video-get-event.rst
@@ -0,0 +1,105 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_GET_EVENT:
+
+===============
+VIDEO_GET_EVENT
+===============
+
+Name
+----
+
+VIDEO_GET_EVENT
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_GET_EVENT
+
+``int ioctl(fd, VIDEO_GET_EVENT, struct video_event *ev)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_GET_EVENT for this command.
+
+ - .. row 3
+
+ - struct video_event \*ev
+
+ - Points to the location where the event, if any, is to be stored.
+
+Description
+-----------
+
+This ioctl is for Digital TV devices only. To get events from a V4L2 decoder
+use the V4L2 :ref:`VIDIOC_DQEVENT` ioctl instead.
+
+This ioctl call returns an event of type video_event if available. If
+an event is not available, the behavior depends on whether the device is
+in blocking or non-blocking mode. In the latter case, the call fails
+immediately with errno set to ``EWOULDBLOCK``. In the former case, the call
+blocks until an event becomes available. The standard Linux poll()
+and/or select() system calls can be used with the device file descriptor
+to watch for new events. For select(), the file descriptor should be
+included in the exceptfds argument, and for poll(), POLLPRI should be
+specified as the wake-up condition. Read-only permissions are sufficient
+for this ioctl call.
+
+.. c:type:: video_event
+
+.. code-block:: c
+
+ struct video_event {
+ __s32 type;
+ #define VIDEO_EVENT_SIZE_CHANGED 1
+ #define VIDEO_EVENT_FRAME_RATE_CHANGED 2
+ #define VIDEO_EVENT_DECODER_STOPPED 3
+ #define VIDEO_EVENT_VSYNC 4
+ long timestamp;
+ union {
+ video_size_t size;
+ unsigned int frame_rate; /* in frames per 1000sec */
+ unsigned char vsync_field; /* unknown/odd/even/progressive */
+ } u;
+ };
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - ``EWOULDBLOCK``
+
+ - There is no event pending, and the device is in non-blocking mode.
+
+ - .. row 2
+
+ - ``EOVERFLOW``
+
+ - Overflow in event queue - one or more events were lost.
diff --git a/drivers/staging/media/av7110/video-get-frame-count.rst b/drivers/staging/media/av7110/video-get-frame-count.rst
new file mode 100644
index 000000000000..b48ac8c58a41
--- /dev/null
+++ b/drivers/staging/media/av7110/video-get-frame-count.rst
@@ -0,0 +1,65 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_GET_FRAME_COUNT:
+
+=====================
+VIDEO_GET_FRAME_COUNT
+=====================
+
+Name
+----
+
+VIDEO_GET_FRAME_COUNT
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_GET_FRAME_COUNT
+
+``int ioctl(int fd, VIDEO_GET_FRAME_COUNT, __u64 *pts)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_GET_FRAME_COUNT for this command.
+
+ - .. row 3
+
+ - __u64 \*pts
+
+ - Returns the number of frames displayed since the decoder was
+ started.
+
+Description
+-----------
+
+This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders
+this ioctl has been replaced by the ``V4L2_CID_MPEG_VIDEO_DEC_FRAME``
+control.
+
+This ioctl call asks the Video Device to return the number of displayed
+frames since the decoder was started.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-get-pts.rst b/drivers/staging/media/av7110/video-get-pts.rst
new file mode 100644
index 000000000000..fedaff41be0b
--- /dev/null
+++ b/drivers/staging/media/av7110/video-get-pts.rst
@@ -0,0 +1,69 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_GET_PTS:
+
+=============
+VIDEO_GET_PTS
+=============
+
+Name
+----
+
+VIDEO_GET_PTS
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_GET_PTS
+
+``int ioctl(int fd, VIDEO_GET_PTS, __u64 *pts)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_GET_PTS for this command.
+
+ - .. row 3
+
+ - __u64 \*pts
+
+ - Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 /
+ ISO/IEC 13818-1.
+
+ The PTS should belong to the currently played frame if possible,
+ but may also be a value close to it like the PTS of the last
+ decoded frame or the last PTS extracted by the PES parser.
+
+Description
+-----------
+
+This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders
+this ioctl has been replaced by the ``V4L2_CID_MPEG_VIDEO_DEC_PTS``
+control.
+
+This ioctl call asks the Video Device to return the current PTS
+timestamp.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-get-size.rst b/drivers/staging/media/av7110/video-get-size.rst
new file mode 100644
index 000000000000..de34331c5bd1
--- /dev/null
+++ b/drivers/staging/media/av7110/video-get-size.rst
@@ -0,0 +1,69 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_GET_SIZE:
+
+==============
+VIDEO_GET_SIZE
+==============
+
+Name
+----
+
+VIDEO_GET_SIZE
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_GET_SIZE
+
+``int ioctl(int fd, VIDEO_GET_SIZE, video_size_t *size)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_GET_SIZE for this command.
+
+ - .. row 3
+
+ - video_size_t \*size
+
+ - Returns the size and aspect ratio.
+
+Description
+-----------
+
+This ioctl returns the size and aspect ratio.
+
+.. c:type:: video_size_t
+
+.. code-block::c
+
+ typedef struct {
+ int w;
+ int h;
+ video_format_t aspect_ratio;
+ } video_size_t;
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-get-status.rst b/drivers/staging/media/av7110/video-get-status.rst
new file mode 100644
index 000000000000..9b86fbf411d4
--- /dev/null
+++ b/drivers/staging/media/av7110/video-get-status.rst
@@ -0,0 +1,72 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_GET_STATUS:
+
+================
+VIDEO_GET_STATUS
+================
+
+Name
+----
+
+VIDEO_GET_STATUS
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_GET_STATUS
+
+``int ioctl(fd, VIDEO_GET_STATUS, struct video_status *status)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_GET_STATUS for this command.
+
+ - .. row 3
+
+ - struct video_status \*status
+
+ - Returns the current status of the Video Device.
+
+Description
+-----------
+
+This ioctl call asks the Video Device to return the current status of
+the device.
+
+.. c:type:: video_status
+
+.. code-block:: c
+
+ struct video_status {
+ int video_blank; /* blank video on freeze? */
+ video_play_state_t play_state; /* current state of playback */
+ video_stream_source_t stream_source; /* current source (demux/memory) */
+ video_format_t video_format; /* current aspect ratio of stream*/
+ video_displayformat_t display_format;/* selected cropping mode */
+ };
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-play.rst b/drivers/staging/media/av7110/video-play.rst
new file mode 100644
index 000000000000..35ac8b98fdbf
--- /dev/null
+++ b/drivers/staging/media/av7110/video-play.rst
@@ -0,0 +1,57 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_PLAY:
+
+==========
+VIDEO_PLAY
+==========
+
+Name
+----
+
+VIDEO_PLAY
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_PLAY
+
+``int ioctl(fd, VIDEO_PLAY)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_PLAY for this command.
+
+Description
+-----------
+
+This ioctl is for Digital TV devices only. To control a V4L2 decoder use the
+V4L2 :ref:`VIDIOC_DECODER_CMD` instead.
+
+This ioctl call asks the Video Device to start playing a video stream
+from the selected source.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-select-source.rst b/drivers/staging/media/av7110/video-select-source.rst
new file mode 100644
index 000000000000..929a20985d53
--- /dev/null
+++ b/drivers/staging/media/av7110/video-select-source.rst
@@ -0,0 +1,76 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_SELECT_SOURCE:
+
+===================
+VIDEO_SELECT_SOURCE
+===================
+
+Name
+----
+
+VIDEO_SELECT_SOURCE
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_SELECT_SOURCE
+
+``int ioctl(fd, VIDEO_SELECT_SOURCE, video_stream_source_t source)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_SELECT_SOURCE for this command.
+
+ - .. row 3
+
+ - video_stream_source_t source
+
+ - Indicates which source shall be used for the Video stream.
+
+Description
+-----------
+
+This ioctl is for Digital TV devices only. This ioctl was also supported by the
+V4L2 ivtv driver, but that has been replaced by the ivtv-specific
+``IVTV_IOC_PASSTHROUGH_MODE`` ioctl.
+
+This ioctl call informs the video device which source shall be used for
+the input data. The possible sources are demux or memory. If memory is
+selected, the data is fed to the video device through the write command.
+
+.. c:type:: video_stream_source_t
+
+.. code-block:: c
+
+ typedef enum {
+ VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */
+ VIDEO_SOURCE_MEMORY /* If this source is selected, the stream
+ comes from the user through the write
+ system call */
+ } video_stream_source_t;
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-set-blank.rst b/drivers/staging/media/av7110/video-set-blank.rst
new file mode 100644
index 000000000000..70249a6ba125
--- /dev/null
+++ b/drivers/staging/media/av7110/video-set-blank.rst
@@ -0,0 +1,64 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_SET_BLANK:
+
+===============
+VIDEO_SET_BLANK
+===============
+
+Name
+----
+
+VIDEO_SET_BLANK
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_SET_BLANK
+
+``int ioctl(fd, VIDEO_SET_BLANK, boolean mode)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_SET_BLANK for this command.
+
+ - .. row 3
+
+ - boolean mode
+
+ - TRUE: Blank screen when stop.
+
+ - .. row 4
+
+ -
+ - FALSE: Show last decoded frame.
+
+Description
+-----------
+
+This ioctl call asks the Video Device to blank out the picture.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-set-display-format.rst b/drivers/staging/media/av7110/video-set-display-format.rst
new file mode 100644
index 000000000000..1de4f40ae732
--- /dev/null
+++ b/drivers/staging/media/av7110/video-set-display-format.rst
@@ -0,0 +1,60 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_SET_DISPLAY_FORMAT:
+
+========================
+VIDEO_SET_DISPLAY_FORMAT
+========================
+
+Name
+----
+
+VIDEO_SET_DISPLAY_FORMAT
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_SET_DISPLAY_FORMAT
+
+``int ioctl(fd, VIDEO_SET_DISPLAY_FORMAT)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_SET_DISPLAY_FORMAT for this command.
+
+ - .. row 3
+
+ - video_display_format_t format
+
+ - Selects the video format to be used.
+
+Description
+-----------
+
+This ioctl call asks the Video Device to select the video format to be
+applied by the MPEG chip on the video.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-set-format.rst b/drivers/staging/media/av7110/video-set-format.rst
new file mode 100644
index 000000000000..bb64e37ae081
--- /dev/null
+++ b/drivers/staging/media/av7110/video-set-format.rst
@@ -0,0 +1,82 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_SET_FORMAT:
+
+================
+VIDEO_SET_FORMAT
+================
+
+Name
+----
+
+VIDEO_SET_FORMAT
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_SET_FORMAT
+
+``int ioctl(fd, VIDEO_SET_FORMAT, video_format_t format)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_SET_FORMAT for this command.
+
+ - .. row 3
+
+ - video_format_t format
+
+ - video format of TV as defined in section ??.
+
+Description
+-----------
+
+This ioctl sets the screen format (aspect ratio) of the connected output
+device (TV) so that the output of the decoder can be adjusted
+accordingly.
+
+.. c:type:: video_format_t
+
+.. code-block:: c
+
+ typedef enum {
+ VIDEO_FORMAT_4_3, /* Select 4:3 format */
+ VIDEO_FORMAT_16_9, /* Select 16:9 format. */
+ VIDEO_FORMAT_221_1 /* 2.21:1 */
+ } video_format_t;
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
+
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - ``EINVAL``
+
+ - format is not a valid video format.
diff --git a/drivers/staging/media/av7110/video-set-streamtype.rst b/drivers/staging/media/av7110/video-set-streamtype.rst
new file mode 100644
index 000000000000..1f31c048bdbc
--- /dev/null
+++ b/drivers/staging/media/av7110/video-set-streamtype.rst
@@ -0,0 +1,61 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_SET_STREAMTYPE:
+
+====================
+VIDEO_SET_STREAMTYPE
+====================
+
+Name
+----
+
+VIDEO_SET_STREAMTYPE
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_SET_STREAMTYPE
+
+``int ioctl(fd, VIDEO_SET_STREAMTYPE, int type)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_SET_STREAMTYPE for this command.
+
+ - .. row 3
+
+ - int type
+
+ - stream type
+
+Description
+-----------
+
+This ioctl tells the driver which kind of stream to expect being written
+to it. If this call is not used the default of video PES is used. Some
+drivers might not support this call and always expect PES.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-slowmotion.rst b/drivers/staging/media/av7110/video-slowmotion.rst
new file mode 100644
index 000000000000..1478fcc30cb8
--- /dev/null
+++ b/drivers/staging/media/av7110/video-slowmotion.rst
@@ -0,0 +1,72 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_SLOWMOTION:
+
+================
+VIDEO_SLOWMOTION
+================
+
+Name
+----
+
+VIDEO_SLOWMOTION
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_SLOWMOTION
+
+``int ioctl(fd, VIDEO_SLOWMOTION, int nFrames)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_SLOWMOTION for this command.
+
+ - .. row 3
+
+ - int nFrames
+
+ - The number of times to repeat each frame.
+
+Description
+-----------
+
+This ioctl call asks the video device to repeat decoding frames N number
+of times. This call can only be used if VIDEO_SOURCE_MEMORY is
+selected.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
+
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - ``EPERM``
+
+ - Mode VIDEO_SOURCE_MEMORY not selected.
diff --git a/drivers/staging/media/av7110/video-stillpicture.rst b/drivers/staging/media/av7110/video-stillpicture.rst
new file mode 100644
index 000000000000..d25384222a20
--- /dev/null
+++ b/drivers/staging/media/av7110/video-stillpicture.rst
@@ -0,0 +1,61 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_STILLPICTURE:
+
+==================
+VIDEO_STILLPICTURE
+==================
+
+Name
+----
+
+VIDEO_STILLPICTURE
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_STILLPICTURE
+
+``int ioctl(fd, VIDEO_STILLPICTURE, struct video_still_picture *sp)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_STILLPICTURE for this command.
+
+ - .. row 3
+
+ - struct video_still_picture \*sp
+
+ - Pointer to a location where an I-frame and size is stored.
+
+Description
+-----------
+
+This ioctl call asks the Video Device to display a still picture
+(I-frame). The input data shall contain an I-frame. If the pointer is
+NULL, then the current displayed still picture is blanked.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-stop.rst b/drivers/staging/media/av7110/video-stop.rst
new file mode 100644
index 000000000000..96f61c5b48a2
--- /dev/null
+++ b/drivers/staging/media/av7110/video-stop.rst
@@ -0,0 +1,74 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_STOP:
+
+==========
+VIDEO_STOP
+==========
+
+Name
+----
+
+VIDEO_STOP
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_STOP
+
+``int ioctl(fd, VIDEO_STOP, boolean mode)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_STOP for this command.
+
+ - .. row 3
+
+ - Boolean mode
+
+ - Indicates how the screen shall be handled.
+
+ - .. row 4
+
+ -
+ - TRUE: Blank screen when stop.
+
+ - .. row 5
+
+ -
+ - FALSE: Show last decoded frame.
+
+Description
+-----------
+
+This ioctl is for Digital TV devices only. To control a V4L2 decoder use the
+V4L2 :ref:`VIDIOC_DECODER_CMD` instead.
+
+This ioctl call asks the Video Device to stop playing the current
+stream. Depending on the input parameter, the screen can be blanked out
+or displaying the last decoded frame.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-try-command.rst b/drivers/staging/media/av7110/video-try-command.rst
new file mode 100644
index 000000000000..79bf3dfb8a32
--- /dev/null
+++ b/drivers/staging/media/av7110/video-try-command.rst
@@ -0,0 +1,66 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: DTV.video
+
+.. _VIDEO_TRY_COMMAND:
+
+=================
+VIDEO_TRY_COMMAND
+=================
+
+Name
+----
+
+VIDEO_TRY_COMMAND
+
+.. attention:: This ioctl is deprecated.
+
+Synopsis
+--------
+
+.. c:macro:: VIDEO_TRY_COMMAND
+
+``int ioctl(int fd, VIDEO_TRY_COMMAND, struct video_command *cmd)``
+
+Arguments
+---------
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ - .. row 1
+
+ - int fd
+
+ - File descriptor returned by a previous call to open().
+
+ - .. row 2
+
+ - int request
+
+ - Equals VIDEO_TRY_COMMAND for this command.
+
+ - .. row 3
+
+ - struct video_command \*cmd
+
+ - Try a decoder command.
+
+Description
+-----------
+
+This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders
+this ioctl has been replaced by the
+:ref:`VIDIOC_TRY_DECODER_CMD <VIDIOC_DECODER_CMD>` ioctl.
+
+This ioctl tries a decoder command. The ``video_command`` struct is a
+subset of the ``v4l2_decoder_cmd`` struct, so refer to the
+:ref:`VIDIOC_TRY_DECODER_CMD <VIDIOC_DECODER_CMD>` documentation
+for more information.
+
+Return Value
+------------
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video.h b/drivers/staging/media/av7110/video.h
new file mode 100644
index 000000000000..179f1ec60af6
--- /dev/null
+++ b/drivers/staging/media/av7110/video.h
@@ -0,0 +1,220 @@
+/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */
+/*
+ * video.h - DEPRECATED MPEG-TS video decoder API
+ *
+ * NOTE: should not be used on future drivers
+ *
+ * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de>
+ * & Ralph Metzler <ralph@convergence.de>
+ * for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser 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.
+ *
+ */
+
+#ifndef _UAPI_DVBVIDEO_H_
+#define _UAPI_DVBVIDEO_H_
+
+#include <linux/types.h>
+#ifndef __KERNEL__
+#include <time.h>
+#endif
+
+typedef enum {
+ VIDEO_FORMAT_4_3, /* Select 4:3 format */
+ VIDEO_FORMAT_16_9, /* Select 16:9 format. */
+ VIDEO_FORMAT_221_1 /* 2.21:1 */
+} video_format_t;
+
+
+typedef enum {
+ VIDEO_PAN_SCAN, /* use pan and scan format */
+ VIDEO_LETTER_BOX, /* use letterbox format */
+ VIDEO_CENTER_CUT_OUT /* use center cut out format */
+} video_displayformat_t;
+
+typedef struct {
+ int w;
+ int h;
+ video_format_t aspect_ratio;
+} video_size_t;
+
+typedef enum {
+ VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */
+ VIDEO_SOURCE_MEMORY /* If this source is selected, the stream
+ comes from the user through the write
+ system call */
+} video_stream_source_t;
+
+
+typedef enum {
+ VIDEO_STOPPED, /* Video is stopped */
+ VIDEO_PLAYING, /* Video is currently playing */
+ VIDEO_FREEZED /* Video is freezed */
+} video_play_state_t;
+
+
+/* Decoder commands */
+#define VIDEO_CMD_PLAY (0)
+#define VIDEO_CMD_STOP (1)
+#define VIDEO_CMD_FREEZE (2)
+#define VIDEO_CMD_CONTINUE (3)
+
+/* Flags for VIDEO_CMD_FREEZE */
+#define VIDEO_CMD_FREEZE_TO_BLACK (1 << 0)
+
+/* Flags for VIDEO_CMD_STOP */
+#define VIDEO_CMD_STOP_TO_BLACK (1 << 0)
+#define VIDEO_CMD_STOP_IMMEDIATELY (1 << 1)
+
+/* Play input formats: */
+/* The decoder has no special format requirements */
+#define VIDEO_PLAY_FMT_NONE (0)
+/* The decoder requires full GOPs */
+#define VIDEO_PLAY_FMT_GOP (1)
+
+/* The structure must be zeroed before use by the application
+ This ensures it can be extended safely in the future. */
+struct video_command {
+ __u32 cmd;
+ __u32 flags;
+ union {
+ struct {
+ __u64 pts;
+ } stop;
+
+ struct {
+ /* 0 or 1000 specifies normal speed,
+ 1 specifies forward single stepping,
+ -1 specifies backward single stepping,
+ >1: playback at speed/1000 of the normal speed,
+ <-1: reverse playback at (-speed/1000) of the normal speed. */
+ __s32 speed;
+ __u32 format;
+ } play;
+
+ struct {
+ __u32 data[16];
+ } raw;
+ };
+};
+
+/* FIELD_UNKNOWN can be used if the hardware does not know whether
+ the Vsync is for an odd, even or progressive (i.e. non-interlaced)
+ field. */
+#define VIDEO_VSYNC_FIELD_UNKNOWN (0)
+#define VIDEO_VSYNC_FIELD_ODD (1)
+#define VIDEO_VSYNC_FIELD_EVEN (2)
+#define VIDEO_VSYNC_FIELD_PROGRESSIVE (3)
+
+struct video_event {
+ __s32 type;
+#define VIDEO_EVENT_SIZE_CHANGED 1
+#define VIDEO_EVENT_FRAME_RATE_CHANGED 2
+#define VIDEO_EVENT_DECODER_STOPPED 3
+#define VIDEO_EVENT_VSYNC 4
+ /* unused, make sure to use atomic time for y2038 if it ever gets used */
+ long timestamp;
+ union {
+ video_size_t size;
+ unsigned int frame_rate; /* in frames per 1000sec */
+ unsigned char vsync_field; /* unknown/odd/even/progressive */
+ } u;
+};
+
+
+struct video_status {
+ int video_blank; /* blank video on freeze? */
+ video_play_state_t play_state; /* current state of playback */
+ video_stream_source_t stream_source; /* current source (demux/memory) */
+ video_format_t video_format; /* current aspect ratio of stream*/
+ video_displayformat_t display_format;/* selected cropping mode */
+};
+
+
+struct video_still_picture {
+ char __user *iFrame; /* pointer to a single iframe in memory */
+ __s32 size;
+};
+
+
+typedef __u16 video_attributes_t;
+/* bits: descr. */
+/* 15-14 Video compression mode (0=MPEG-1, 1=MPEG-2) */
+/* 13-12 TV system (0=525/60, 1=625/50) */
+/* 11-10 Aspect ratio (0=4:3, 3=16:9) */
+/* 9- 8 permitted display mode on 4:3 monitor (0=both, 1=only pan-sca */
+/* 7 line 21-1 data present in GOP (1=yes, 0=no) */
+/* 6 line 21-2 data present in GOP (1=yes, 0=no) */
+/* 5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/57 */
+/* 2 source letterboxed (1=yes, 0=no) */
+/* 0 film/camera mode (0=
+ *camera, 1=film (625/50 only)) */
+
+
+/* bit definitions for capabilities: */
+/* can the hardware decode MPEG1 and/or MPEG2? */
+#define VIDEO_CAP_MPEG1 1
+#define VIDEO_CAP_MPEG2 2
+/* can you send a system and/or program stream to video device?
+ (you still have to open the video and the audio device but only
+ send the stream to the video device) */
+#define VIDEO_CAP_SYS 4
+#define VIDEO_CAP_PROG 8
+/* can the driver also handle SPU, NAVI and CSS encoded data?
+ (CSS API is not present yet) */
+#define VIDEO_CAP_SPU 16
+#define VIDEO_CAP_NAVI 32
+#define VIDEO_CAP_CSS 64
+
+
+#define VIDEO_STOP _IO('o', 21)
+#define VIDEO_PLAY _IO('o', 22)
+#define VIDEO_FREEZE _IO('o', 23)
+#define VIDEO_CONTINUE _IO('o', 24)
+#define VIDEO_SELECT_SOURCE _IO('o', 25)
+#define VIDEO_SET_BLANK _IO('o', 26)
+#define VIDEO_GET_STATUS _IOR('o', 27, struct video_status)
+#define VIDEO_GET_EVENT _IOR('o', 28, struct video_event)
+#define VIDEO_SET_DISPLAY_FORMAT _IO('o', 29)
+#define VIDEO_STILLPICTURE _IOW('o', 30, struct video_still_picture)
+#define VIDEO_FAST_FORWARD _IO('o', 31)
+#define VIDEO_SLOWMOTION _IO('o', 32)
+#define VIDEO_GET_CAPABILITIES _IOR('o', 33, unsigned int)
+#define VIDEO_CLEAR_BUFFER _IO('o', 34)
+#define VIDEO_SET_STREAMTYPE _IO('o', 36)
+#define VIDEO_SET_FORMAT _IO('o', 37)
+#define VIDEO_GET_SIZE _IOR('o', 55, video_size_t)
+
+/**
+ * VIDEO_GET_PTS
+ *
+ * Read the 33 bit presentation time stamp as defined
+ * in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
+ *
+ * The PTS should belong to the currently played
+ * frame if possible, but may also be a value close to it
+ * like the PTS of the last decoded frame or the last PTS
+ * extracted by the PES parser.
+ */
+#define VIDEO_GET_PTS _IOR('o', 57, __u64)
+
+/* Read the number of displayed frames since the decoder was started */
+#define VIDEO_GET_FRAME_COUNT _IOR('o', 58, __u64)
+
+#define VIDEO_COMMAND _IOWR('o', 59, struct video_command)
+#define VIDEO_TRY_COMMAND _IOWR('o', 60, struct video_command)
+
+#endif /* _UAPI_DVBVIDEO_H_ */
diff --git a/drivers/staging/media/av7110/video.rst b/drivers/staging/media/av7110/video.rst
new file mode 100644
index 000000000000..808705b769a1
--- /dev/null
+++ b/drivers/staging/media/av7110/video.rst
@@ -0,0 +1,36 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+
+.. _dvb_video:
+
+#######################
+Digital TV Video Device
+#######################
+
+The Digital TV video device controls the MPEG2 video decoder of the Digital
+TV hardware. It can be accessed through **/dev/dvb/adapter0/video0**. Data
+types and ioctl definitions can be accessed by including
+**linux/dvb/video.h** in your application.
+
+Note that the Digital TV video device only controls decoding of the MPEG video
+stream, not its presentation on the TV or computer screen. On PCs this
+is typically handled by an associated video4linux device, e.g.
+**/dev/video**, which allows scaling and defining output windows.
+
+Some Digital TV cards don't have their own MPEG decoder, which results in the
+omission of the audio and video device as well as the video4linux
+device.
+
+The ioctls that deal with SPUs (sub picture units) and navigation
+packets are only supported on some MPEG decoders made for DVD playback.
+
+These ioctls were also used by V4L2 to control MPEG decoders implemented
+in V4L2. The use of these ioctls for that purpose has been made obsolete
+and proper V4L2 ioctls or controls have been created to replace that
+functionality.
+
+
+.. toctree::
+ :maxdepth: 1
+
+ video_types
+ video_function_calls
diff --git a/drivers/staging/media/av7110/video_function_calls.rst b/drivers/staging/media/av7110/video_function_calls.rst
new file mode 100644
index 000000000000..20a897be5dca
--- /dev/null
+++ b/drivers/staging/media/av7110/video_function_calls.rst
@@ -0,0 +1,35 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+
+.. _video_function_calls:
+
+********************
+Video Function Calls
+********************
+
+.. toctree::
+ :maxdepth: 1
+
+ video-fopen
+ video-fclose
+ video-fwrite
+ video-stop
+ video-play
+ video-freeze
+ video-continue
+ video-select-source
+ video-set-blank
+ video-get-status
+ video-get-frame-count
+ video-get-pts
+ video-get-event
+ video-command
+ video-try-command
+ video-get-size
+ video-set-display-format
+ video-stillpicture
+ video-fast-forward
+ video-slowmotion
+ video-get-capabilities
+ video-clear-buffer
+ video-set-streamtype
+ video-set-format
diff --git a/drivers/staging/media/av7110/video_types.rst b/drivers/staging/media/av7110/video_types.rst
new file mode 100644
index 000000000000..c4557d328b7a
--- /dev/null
+++ b/drivers/staging/media/av7110/video_types.rst
@@ -0,0 +1,248 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+
+.. _video_types:
+
+****************
+Video Data Types
+****************
+
+
+.. _video-format-t:
+
+video_format_t
+==============
+
+The ``video_format_t`` data type defined by
+
+
+.. code-block:: c
+
+ typedef enum {
+ VIDEO_FORMAT_4_3, /* Select 4:3 format */
+ VIDEO_FORMAT_16_9, /* Select 16:9 format. */
+ VIDEO_FORMAT_221_1 /* 2.21:1 */
+ } video_format_t;
+
+is used in the VIDEO_SET_FORMAT function (??) to tell the driver which
+aspect ratio the output hardware (e.g. TV) has. It is also used in the
+data structures video_status (??) returned by VIDEO_GET_STATUS (??)
+and video_event (??) returned by VIDEO_GET_EVENT (??) which report
+about the display format of the current video stream.
+
+
+.. _video-displayformat-t:
+
+video_displayformat_t
+=====================
+
+In case the display format of the video stream and of the display
+hardware differ the application has to specify how to handle the
+cropping of the picture. This can be done using the
+VIDEO_SET_DISPLAY_FORMAT call (??) which accepts
+
+
+.. code-block:: c
+
+ typedef enum {
+ VIDEO_PAN_SCAN, /* use pan and scan format */
+ VIDEO_LETTER_BOX, /* use letterbox format */
+ VIDEO_CENTER_CUT_OUT /* use center cut out format */
+ } video_displayformat_t;
+
+as argument.
+
+
+.. _video-stream-source-t:
+
+video_stream_source_t
+=====================
+
+The video stream source is set through the VIDEO_SELECT_SOURCE call
+and can take the following values, depending on whether we are replaying
+from an internal (demuxer) or external (user write) source.
+
+
+.. code-block:: c
+
+ typedef enum {
+ VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */
+ VIDEO_SOURCE_MEMORY /* If this source is selected, the stream
+ comes from the user through the write
+ system call */
+ } video_stream_source_t;
+
+VIDEO_SOURCE_DEMUX selects the demultiplexer (fed either by the
+frontend or the DVR device) as the source of the video stream. If
+VIDEO_SOURCE_MEMORY is selected the stream comes from the application
+through the **write()** system call.
+
+
+.. _video-play-state-t:
+
+video_play_state_t
+==================
+
+The following values can be returned by the VIDEO_GET_STATUS call
+representing the state of video playback.
+
+
+.. code-block:: c
+
+ typedef enum {
+ VIDEO_STOPPED, /* Video is stopped */
+ VIDEO_PLAYING, /* Video is currently playing */
+ VIDEO_FREEZED /* Video is freezed */
+ } video_play_state_t;
+
+
+.. c:type:: video_command
+
+struct video_command
+====================
+
+The structure must be zeroed before use by the application This ensures
+it can be extended safely in the future.
+
+
+.. code-block:: c
+
+ struct video_command {
+ __u32 cmd;
+ __u32 flags;
+ union {
+ struct {
+ __u64 pts;
+ } stop;
+
+ struct {
+ /* 0 or 1000 specifies normal speed,
+ 1 specifies forward single stepping,
+ -1 specifies backward single stepping,
+ >>1: playback at speed/1000 of the normal speed,
+ <-1: reverse playback at (-speed/1000) of the normal speed. */
+ __s32 speed;
+ __u32 format;
+ } play;
+
+ struct {
+ __u32 data[16];
+ } raw;
+ };
+ };
+
+
+.. _video-size-t:
+
+video_size_t
+============
+
+
+.. code-block:: c
+
+ typedef struct {
+ int w;
+ int h;
+ video_format_t aspect_ratio;
+ } video_size_t;
+
+
+.. c:type:: video_event
+
+struct video_event
+==================
+
+The following is the structure of a video event as it is returned by the
+VIDEO_GET_EVENT call.
+
+
+.. code-block:: c
+
+ struct video_event {
+ __s32 type;
+ #define VIDEO_EVENT_SIZE_CHANGED 1
+ #define VIDEO_EVENT_FRAME_RATE_CHANGED 2
+ #define VIDEO_EVENT_DECODER_STOPPED 3
+ #define VIDEO_EVENT_VSYNC 4
+ long timestamp;
+ union {
+ video_size_t size;
+ unsigned int frame_rate; /* in frames per 1000sec */
+ unsigned char vsync_field; /* unknown/odd/even/progressive */
+ } u;
+ };
+
+
+.. c:type:: video_status
+
+struct video_status
+===================
+
+The VIDEO_GET_STATUS call returns the following structure informing
+about various states of the playback operation.
+
+
+.. code-block:: c
+
+ struct video_status {
+ int video_blank; /* blank video on freeze? */
+ video_play_state_t play_state; /* current state of playback */
+ video_stream_source_t stream_source; /* current source (demux/memory) */
+ video_format_t video_format; /* current aspect ratio of stream */
+ video_displayformat_t display_format;/* selected cropping mode */
+ };
+
+If video_blank is set video will be blanked out if the channel is
+changed or if playback is stopped. Otherwise, the last picture will be
+displayed. play_state indicates if the video is currently frozen,
+stopped, or being played back. The stream_source corresponds to the
+selected source for the video stream. It can come either from the
+demultiplexer or from memory. The video_format indicates the aspect
+ratio (one of 4:3 or 16:9) of the currently played video stream.
+Finally, display_format corresponds to the selected cropping mode in
+case the source video format is not the same as the format of the output
+device.
+
+
+.. c:type:: video_still_picture
+
+struct video_still_picture
+==========================
+
+An I-frame displayed via the VIDEO_STILLPICTURE call is passed on
+within the following structure.
+
+
+.. code-block:: c
+
+ /* pointer to and size of a single iframe in memory */
+ struct video_still_picture {
+ char *iFrame; /* pointer to a single iframe in memory */
+ int32_t size;
+ };
+
+
+.. _video_caps:
+
+video capabilities
+==================
+
+A call to VIDEO_GET_CAPABILITIES returns an unsigned integer with the
+following bits set according to the hardwares capabilities.
+
+
+.. code-block:: c
+
+ /* bit definitions for capabilities: */
+ /* can the hardware decode MPEG1 and/or MPEG2? */
+ #define VIDEO_CAP_MPEG1 1
+ #define VIDEO_CAP_MPEG2 2
+ /* can you send a system and/or program stream to video device?
+ (you still have to open the video and the audio device but only
+ send the stream to the video device) */
+ #define VIDEO_CAP_SYS 4
+ #define VIDEO_CAP_PROG 8
+ /* can the driver also handle SPU, NAVI and CSS encoded data?
+ (CSS API is not present yet) */
+ #define VIDEO_CAP_SPU 16
+ #define VIDEO_CAP_NAVI 32
+ #define VIDEO_CAP_CSS 64
diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/staging/media/hantro/Kconfig
index 5b6cf9f62b1a..20b1f6d7b69c 100644
--- a/drivers/staging/media/hantro/Kconfig
+++ b/drivers/staging/media/hantro/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
config VIDEO_HANTRO
tristate "Hantro VPU driver"
- depends on ARCH_MXC || ARCH_ROCKCHIP || COMPILE_TEST
+ depends on ARCH_MXC || ARCH_ROCKCHIP || ARCH_AT91 || COMPILE_TEST
depends on VIDEO_DEV && VIDEO_V4L2
select MEDIA_CONTROLLER
select MEDIA_CONTROLLER_REQUEST_API
@@ -24,6 +24,14 @@ config VIDEO_HANTRO_IMX8M
help
Enable support for i.MX8M SoCs.
+config VIDEO_HANTRO_SAMA5D4
+ bool "Hantro VDEC SAMA5D4 support"
+ depends on VIDEO_HANTRO
+ depends on ARCH_AT91 || COMPILE_TEST
+ default y
+ help
+ Enable support for Microchip SAMA5D4 SoCs.
+
config VIDEO_HANTRO_ROCKCHIP
bool "Hantro VPU Rockchip support"
depends on VIDEO_HANTRO
diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile
index 743ce08eb184..287370188d2a 100644
--- a/drivers/staging/media/hantro/Makefile
+++ b/drivers/staging/media/hantro/Makefile
@@ -7,20 +7,25 @@ hantro-vpu-y += \
hantro_v4l2.o \
hantro_postproc.o \
hantro_h1_jpeg_enc.o \
+ hantro_g1.o \
hantro_g1_h264_dec.o \
hantro_g1_mpeg2_dec.o \
+ hantro_g2_hevc_dec.o \
hantro_g1_vp8_dec.o \
- rk3399_vpu_hw_jpeg_enc.o \
- rk3399_vpu_hw_mpeg2_dec.o \
- rk3399_vpu_hw_vp8_dec.o \
+ rockchip_vpu2_hw_jpeg_enc.o \
+ rockchip_vpu2_hw_mpeg2_dec.o \
+ rockchip_vpu2_hw_vp8_dec.o \
hantro_jpeg.o \
hantro_h264.o \
+ hantro_hevc.o \
hantro_mpeg2.o \
hantro_vp8.o
hantro-vpu-$(CONFIG_VIDEO_HANTRO_IMX8M) += \
imx8m_vpu_hw.o
+hantro-vpu-$(CONFIG_VIDEO_HANTRO_SAMA5D4) += \
+ sama5d4_vdec_hw.o
+
hantro-vpu-$(CONFIG_VIDEO_HANTRO_ROCKCHIP) += \
- rk3288_vpu_hw.o \
- rk3399_vpu_hw.o
+ rockchip_vpu_hw.o
diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h
index 6c1b888abe75..a70c386de6f1 100644
--- a/drivers/staging/media/hantro/hantro.h
+++ b/drivers/staging/media/hantro/hantro.h
@@ -34,6 +34,7 @@ struct hantro_codec_ops;
#define HANTRO_MPEG2_DECODER BIT(16)
#define HANTRO_VP8_DECODER BIT(17)
#define HANTRO_H264_DECODER BIT(18)
+#define HANTRO_HEVC_DECODER BIT(19)
#define HANTRO_DECODERS 0xffff0000
/**
@@ -99,6 +100,7 @@ struct hantro_variant {
* @HANTRO_MODE_H264_DEC: H264 decoder.
* @HANTRO_MODE_MPEG2_DEC: MPEG-2 decoder.
* @HANTRO_MODE_VP8_DEC: VP8 decoder.
+ * @HANTRO_MODE_HEVC_DEC: HEVC decoder.
*/
enum hantro_codec_mode {
HANTRO_MODE_NONE = -1,
@@ -106,6 +108,7 @@ enum hantro_codec_mode {
HANTRO_MODE_H264_DEC,
HANTRO_MODE_MPEG2_DEC,
HANTRO_MODE_VP8_DEC,
+ HANTRO_MODE_HEVC_DEC,
};
/*
@@ -218,6 +221,7 @@ struct hantro_dev {
* @jpeg_enc: JPEG-encoding context.
* @mpeg2_dec: MPEG-2-decoding context.
* @vp8_dec: VP8-decoding context.
+ * @hevc_dec: HEVC-decoding context.
*/
struct hantro_ctx {
struct hantro_dev *dev;
@@ -244,6 +248,7 @@ struct hantro_ctx {
struct hantro_jpeg_enc_hw_ctx jpeg_enc;
struct hantro_mpeg2_dec_hw_ctx mpeg2_dec;
struct hantro_vp8_dec_hw_ctx vp8_dec;
+ struct hantro_hevc_dec_hw_ctx hevc_dec;
};
};
@@ -410,12 +415,8 @@ hantro_get_dst_buf(struct hantro_ctx *ctx)
return v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
}
-static inline bool
-hantro_needs_postproc(const struct hantro_ctx *ctx,
- const struct hantro_fmt *fmt)
-{
- return !ctx->is_encoder && fmt->fourcc != V4L2_PIX_FMT_NV12;
-}
+bool hantro_needs_postproc(const struct hantro_ctx *ctx,
+ const struct hantro_fmt *fmt);
static inline dma_addr_t
hantro_get_dec_buf_addr(struct hantro_ctx *ctx, struct vb2_buffer *vb)
diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c
index 595e82a82728..31d8449ca1d2 100644
--- a/drivers/staging/media/hantro/hantro_drv.c
+++ b/drivers/staging/media/hantro/hantro_drv.c
@@ -56,16 +56,12 @@ dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts)
return hantro_get_dec_buf_addr(ctx, buf);
}
-static void hantro_job_finish(struct hantro_dev *vpu,
- struct hantro_ctx *ctx,
- enum vb2_buffer_state result)
+static void hantro_job_finish_no_pm(struct hantro_dev *vpu,
+ struct hantro_ctx *ctx,
+ enum vb2_buffer_state result)
{
struct vb2_v4l2_buffer *src, *dst;
- 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_next_src_buf(ctx->fh.m2m_ctx);
dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
@@ -81,6 +77,18 @@ static void hantro_job_finish(struct hantro_dev *vpu,
result);
}
+static void hantro_job_finish(struct hantro_dev *vpu,
+ struct hantro_ctx *ctx,
+ enum vb2_buffer_state result)
+{
+ pm_runtime_mark_last_busy(vpu->dev);
+ pm_runtime_put_autosuspend(vpu->dev);
+
+ clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks);
+
+ hantro_job_finish_no_pm(vpu, ctx, result);
+}
+
void hantro_irq_done(struct hantro_dev *vpu,
enum vb2_buffer_state result)
{
@@ -152,20 +160,23 @@ static void device_run(void *priv)
src = hantro_get_src_buf(ctx);
dst = hantro_get_dst_buf(ctx);
+ ret = pm_runtime_resume_and_get(ctx->dev->dev);
+ if (ret < 0)
+ goto err_cancel_job;
+
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;
v4l2_m2m_buf_copy_metadata(src, dst, true);
- ctx->codec_ops->run(ctx);
+ if (ctx->codec_ops->run(ctx))
+ goto err_cancel_job;
+
return;
err_cancel_job:
- hantro_job_finish(ctx->dev, ctx, VB2_BUF_STATE_ERROR);
+ hantro_job_finish_no_pm(ctx->dev, ctx, VB2_BUF_STATE_ERROR);
}
static struct v4l2_m2m_ops vpu_m2m_ops = {
@@ -243,6 +254,18 @@ static int hantro_try_ctrl(struct v4l2_ctrl *ctrl)
if (sps->bit_depth_luma_minus8 != 0)
/* Only 8-bit is supported */
return -EINVAL;
+ } else if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEVC_SPS) {
+ const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
+
+ if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
+ /* Luma and chroma bit depth mismatch */
+ return -EINVAL;
+ if (sps->bit_depth_luma_minus8 != 0)
+ /* Only 8-bit is supported */
+ return -EINVAL;
+ if (sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED)
+ /* No scaling support */
+ return -EINVAL;
}
return 0;
}
@@ -267,6 +290,26 @@ static int hantro_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
+static int hantro_hevc_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_HANTRO_HEVC_SLICE_HEADER_SKIP:
+ ctx->hevc_dec.ctrls.hevc_hdr_skip_length = ctrl->val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static const struct v4l2_ctrl_ops hantro_ctrl_ops = {
.try_ctrl = hantro_try_ctrl,
};
@@ -275,6 +318,10 @@ static const struct v4l2_ctrl_ops hantro_jpeg_ctrl_ops = {
.s_ctrl = hantro_jpeg_s_ctrl,
};
+static const struct v4l2_ctrl_ops hantro_hevc_ctrl_ops = {
+ .s_ctrl = hantro_hevc_s_ctrl,
+};
+
static const struct hantro_ctrl controls[] = {
{
.codec = HANTRO_JPEG_ENCODER,
@@ -289,12 +336,17 @@ static const struct hantro_ctrl controls[] = {
}, {
.codec = HANTRO_MPEG2_DECODER,
.cfg = {
- .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
+ .id = V4L2_CID_STATELESS_MPEG2_SEQUENCE,
+ },
+ }, {
+ .codec = HANTRO_MPEG2_DECODER,
+ .cfg = {
+ .id = V4L2_CID_STATELESS_MPEG2_PICTURE,
},
}, {
.codec = HANTRO_MPEG2_DECODER,
.cfg = {
- .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION,
+ .id = V4L2_CID_STATELESS_MPEG2_QUANTISATION,
},
}, {
.codec = HANTRO_VP8_DECODER,
@@ -349,6 +401,64 @@ static const struct hantro_ctrl controls[] = {
.def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN,
}
}, {
+ .codec = HANTRO_HEVC_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE,
+ .min = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED,
+ .max = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED,
+ .def = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED,
+ },
+ }, {
+ .codec = HANTRO_HEVC_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE,
+ .min = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B,
+ .max = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B,
+ .def = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B,
+ },
+ }, {
+ .codec = HANTRO_HEVC_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+ .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+ .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
+ .def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+ },
+ }, {
+ .codec = HANTRO_HEVC_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+ .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+ .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1,
+ },
+ }, {
+ .codec = HANTRO_HEVC_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS,
+ .ops = &hantro_ctrl_ops,
+ },
+ }, {
+ .codec = HANTRO_HEVC_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_PPS,
+ },
+ }, {
+ .codec = HANTRO_HEVC_DECODER,
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS,
+ },
+ }, {
+ .codec = HANTRO_HEVC_DECODER,
+ .cfg = {
+ .id = V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP,
+ .name = "Hantro HEVC slice header skip bytes",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .def = 0,
+ .max = 0x100,
+ .step = 1,
+ .ops = &hantro_hevc_ctrl_ops,
+ },
},
};
@@ -472,12 +582,18 @@ static const struct v4l2_file_operations hantro_fops = {
static const struct of_device_id of_hantro_match[] = {
#ifdef CONFIG_VIDEO_HANTRO_ROCKCHIP
- { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, },
- { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, },
+ { .compatible = "rockchip,rk3036-vpu", .data = &rk3036_vpu_variant, },
+ { .compatible = "rockchip,rk3066-vpu", .data = &rk3066_vpu_variant, },
{ .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, },
+ { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, },
+ { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, },
#endif
#ifdef CONFIG_VIDEO_HANTRO_IMX8M
{ .compatible = "nxp,imx8mq-vpu", .data = &imx8mq_vpu_variant, },
+ { .compatible = "nxp,imx8mq-vpu-g2", .data = &imx8mq_vpu_g2_variant },
+#endif
+#ifdef CONFIG_VIDEO_HANTRO_SAMA5D4
+ { .compatible = "microchip,sama5d4-vdec", .data = &sama5d4_vdec_variant, },
#endif
{ /* sentinel */ }
};
@@ -752,12 +868,23 @@ static int hantro_probe(struct platform_device *pdev)
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;
+ if (vpu->variant->num_clocks > 1) {
+ 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;
+ } else {
+ /*
+ * If the driver has a single clk, chances are there will be no
+ * actual name in the DT bindings.
+ */
+ vpu->clocks[0].clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(vpu->clocks[0].clk))
+ return PTR_ERR(vpu->clocks[0].clk);
+ }
num_bases = vpu->variant->num_regs ?: 1;
vpu->reg_bases = devm_kcalloc(&pdev->dev, num_bases,
@@ -785,13 +912,23 @@ static int hantro_probe(struct platform_device *pdev)
vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
for (i = 0; i < vpu->variant->num_irqs; i++) {
- const char *irq_name = vpu->variant->irqs[i].name;
+ const char *irq_name;
int irq;
if (!vpu->variant->irqs[i].handler)
continue;
- irq = platform_get_irq_byname(vpu->pdev, irq_name);
+ if (vpu->variant->num_clocks > 1) {
+ irq_name = vpu->variant->irqs[i].name;
+ irq = platform_get_irq_byname(vpu->pdev, irq_name);
+ } else {
+ /*
+ * If the driver has a single IRQ, chances are there
+ * will be no actual name in the DT bindings.
+ */
+ irq_name = "default";
+ irq = platform_get_irq(vpu->pdev, 0);
+ }
if (irq <= 0)
return -ENXIO;
diff --git a/drivers/staging/media/hantro/hantro_g1.c b/drivers/staging/media/hantro/hantro_g1.c
new file mode 100644
index 000000000000..0ab1cee62218
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_g1.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ * Jeffy Chen <jeffy.chen@rock-chips.com>
+ * Copyright (C) 2019 Pengutronix, Philipp Zabel <kernel@pengutronix.de>
+ * Copyright (C) 2021 Collabora Ltd, Emil Velikov <emil.velikov@collabora.com>
+ */
+
+#include "hantro.h"
+#include "hantro_g1_regs.h"
+
+irqreturn_t hantro_g1_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, state);
+
+ return IRQ_HANDLED;
+}
+
+void hantro_g1_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);
+}
diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c
index 845bef73d218..5c792b7bcb79 100644
--- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c
+++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c
@@ -273,13 +273,15 @@ static void set_buffers(struct hantro_ctx *ctx)
vdpu_write_relaxed(vpu, ctx->h264_dec.priv.dma, G1_REG_ADDR_QTABLE);
}
-void hantro_g1_h264_dec_run(struct hantro_ctx *ctx)
+int hantro_g1_h264_dec_run(struct hantro_ctx *ctx)
{
struct hantro_dev *vpu = ctx->dev;
+ int ret;
/* Prepare the H264 decoder context. */
- if (hantro_h264_dec_prepare_run(ctx))
- return;
+ ret = hantro_h264_dec_prepare_run(ctx);
+ if (ret)
+ return ret;
/* Configure hardware registers. */
set_params(ctx);
@@ -301,4 +303,6 @@ void hantro_g1_h264_dec_run(struct hantro_ctx *ctx)
G1_REG_CONFIG_DEC_CLK_GATE_E,
G1_REG_CONFIG);
vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT);
+
+ return 0;
}
diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c
index 6386a3989bfe..9aea331e1a3c 100644
--- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c
+++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c
@@ -10,6 +10,7 @@
#include <media/v4l2-mem2mem.h>
#include "hantro.h"
#include "hantro_hw.h"
+#include "hantro_g1_regs.h"
#define G1_SWREG(nr) ((nr) * 4)
@@ -20,7 +21,6 @@
#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)
@@ -77,43 +77,33 @@
#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,
+hantro_g1_mpeg2_dec_set_quantisation(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);
+ struct v4l2_ctrl_mpeg2_quantisation *q;
+
+ q = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_MPEG2_QUANTISATION);
+ hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, q);
+ 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)
+ const struct v4l2_ctrl_mpeg2_sequence *seq,
+ const struct v4l2_ctrl_mpeg2_picture *pic)
{
dma_addr_t forward_addr = 0, backward_addr = 0;
dma_addr_t current_addr, addr;
- switch (picture->picture_coding_type) {
- case V4L2_MPEG2_PICTURE_CODING_TYPE_B:
- backward_addr = hantro_get_ref(ctx,
- slice_params->backward_ref_ts);
+ switch (pic->picture_coding_type) {
+ case V4L2_MPEG2_PIC_CODING_TYPE_B:
+ backward_addr = hantro_get_ref(ctx, pic->backward_ref_ts);
fallthrough;
- case V4L2_MPEG2_PICTURE_CODING_TYPE_P:
- forward_addr = hantro_get_ref(ctx,
- slice_params->forward_ref_ts);
+ case V4L2_MPEG2_PIC_CODING_TYPE_P:
+ forward_addr = hantro_get_ref(ctx, pic->forward_ref_ts);
}
/* Source bitstream buffer */
@@ -124,7 +114,7 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx,
addr = hantro_get_dec_buf_addr(ctx, dst_buf);
current_addr = addr;
- if (picture->picture_structure == PICT_BOTTOM_FIELD)
+ if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD)
addr += ALIGN(ctx->dst_fmt.width, 16);
vdpu_write_relaxed(vpu, addr, G1_REG_DEC_OUT_BASE);
@@ -134,18 +124,18 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx,
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)) {
+ if (pic->picture_structure == V4L2_MPEG2_PIC_FRAME ||
+ pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B ||
+ (pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD &&
+ pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST) ||
+ (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD &&
+ !(pic->flags & V4L2_MPEG2_PIC_FLAG_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) {
+ } else if (pic->picture_structure == V4L2_MPEG2_PIC_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) {
+ } else if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD) {
vdpu_write_relaxed(vpu, current_addr, G1_REG_REFER0_BASE);
vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER1_BASE);
}
@@ -155,13 +145,12 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx,
vdpu_write_relaxed(vpu, backward_addr, G1_REG_REFER3_BASE);
}
-void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx)
+int 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;
+ const struct v4l2_ctrl_mpeg2_sequence *seq;
+ const struct v4l2_ctrl_mpeg2_picture *pic;
u32 reg;
src_buf = hantro_get_src_buf(ctx);
@@ -170,10 +159,10 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx)
/* Apply request controls if any */
hantro_start_prepare_run(ctx);
- slice_params = hantro_get_ctrl(ctx,
- V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS);
- sequence = &slice_params->sequence;
- picture = &slice_params->picture;
+ seq = hantro_get_ctrl(ctx,
+ V4L2_CID_STATELESS_MPEG2_SEQUENCE);
+ pic = hantro_get_ctrl(ctx,
+ V4L2_CID_STATELESS_MPEG2_PICTURE);
reg = G1_REG_DEC_AXI_RD_ID(0) |
G1_REG_DEC_TIMEOUT_E(1) |
@@ -193,11 +182,11 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx)
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_PIC_INTERLACE_E(!(seq->flags & V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE)) |
+ G1_REG_PIC_FIELDMODE_E(pic->picture_structure != V4L2_MPEG2_PIC_FRAME) |
+ G1_REG_PIC_B_E(pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B) |
+ G1_REG_PIC_INTER_E(pic->picture_coding_type != V4L2_MPEG2_PIC_CODING_TYPE_I) |
+ G1_REG_PIC_TOPFIELD_E(pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD) |
G1_REG_FWD_INTERLACE_E(0) |
G1_REG_FILTERING_DIS(1) |
G1_REG_WRITE_MVS_E(0) |
@@ -206,27 +195,27 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx)
reg = G1_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->dst_fmt.width)) |
G1_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->dst_fmt.height)) |
- G1_REG_ALT_SCAN_E(picture->alternate_scan) |
- G1_REG_TOPFIELDFIRST_E(picture->top_field_first);
+ G1_REG_ALT_SCAN_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) |
+ G1_REG_TOPFIELDFIRST_E(pic->flags & V4L2_MPEG2_PIC_FLAG_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);
+ reg = G1_REG_STRM_START_BIT(0) |
+ G1_REG_QSCALE_TYPE(pic->flags & V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE) |
+ G1_REG_CON_MV_E(pic->flags & V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV) |
+ G1_REG_INTRA_DC_PREC(pic->intra_dc_precision) |
+ G1_REG_INTRA_VLC_TAB(pic->flags & V4L2_MPEG2_PIC_FLAG_INTRA_VLC) |
+ G1_REG_FRAME_PRED_DCT(pic->flags & V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT);
vdpu_write_relaxed(vpu, reg, G1_SWREG(5));
reg = G1_REG_INIT_QP(1) |
- G1_REG_STREAM_LEN(slice_params->bit_size >> 3);
+ G1_REG_STREAM_LEN(vb2_get_plane_payload(&src_buf->vb2_buf, 0));
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]) |
+ reg = G1_REG_ALT_SCAN_FLAG_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) |
+ G1_REG_FCODE_FWD_HOR(pic->f_code[0][0]) |
+ G1_REG_FCODE_FWD_VER(pic->f_code[0][1]) |
+ G1_REG_FCODE_BWD_HOR(pic->f_code[1][0]) |
+ G1_REG_FCODE_BWD_VER(pic->f_code[1][1]) |
G1_REG_MV_ACCURACY_FWD(1) |
G1_REG_MV_ACCURACY_BWD(1);
vdpu_write_relaxed(vpu, reg, G1_SWREG(18));
@@ -238,14 +227,14 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx)
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_quantisation(vpu, ctx);
hantro_g1_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf,
&dst_buf->vb2_buf,
- sequence, picture, slice_params);
+ seq, pic);
hantro_end_prepare_run(ctx);
- reg = G1_REG_DEC_E(1);
- vdpu_write(vpu, reg, G1_SWREG(1));
+ vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT);
+
+ return 0;
}
diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c
index 57002ba70176..96622a7f8279 100644
--- a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c
+++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c
@@ -425,7 +425,7 @@ static void cfg_buffers(struct hantro_ctx *ctx,
vdpu_write_relaxed(vpu, dst_dma, G1_REG_ADDR_DST);
}
-void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx)
+int hantro_g1_vp8_dec_run(struct hantro_ctx *ctx)
{
const struct v4l2_ctrl_vp8_frame *hdr;
struct hantro_dev *vpu = ctx->dev;
@@ -438,7 +438,7 @@ void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx)
hdr = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_VP8_FRAME);
if (WARN_ON(!hdr))
- return;
+ return -EINVAL;
/* Reset segment_map buffer in keyframe */
if (V4L2_VP8_FRAME_IS_KEY_FRAME(hdr) && ctx->vp8_dec.segment_map.cpu)
@@ -498,4 +498,6 @@ void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx)
hantro_end_prepare_run(ctx);
vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT);
+
+ return 0;
}
diff --git a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c
new file mode 100644
index 000000000000..340efb57fd18
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c
@@ -0,0 +1,586 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU HEVC codec driver
+ *
+ * Copyright (C) 2020 Safran Passenger Innovations LLC
+ */
+
+#include "hantro_hw.h"
+#include "hantro_g2_regs.h"
+
+#define HEVC_DEC_MODE 0xC
+
+#define BUS_WIDTH_32 0
+#define BUS_WIDTH_64 1
+#define BUS_WIDTH_128 2
+#define BUS_WIDTH_256 3
+
+static inline void hantro_write_addr(struct hantro_dev *vpu,
+ unsigned long offset,
+ dma_addr_t addr)
+{
+ vdpu_write(vpu, addr & 0xffffffff, offset);
+}
+
+static void prepare_tile_info_buffer(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+ const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps;
+ const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
+ u16 *p = (u16 *)((u8 *)ctx->hevc_dec.tile_sizes.cpu);
+ unsigned int num_tile_rows = pps->num_tile_rows_minus1 + 1;
+ unsigned int num_tile_cols = pps->num_tile_columns_minus1 + 1;
+ unsigned int pic_width_in_ctbs, pic_height_in_ctbs;
+ unsigned int max_log2_ctb_size, ctb_size;
+ bool tiles_enabled, uniform_spacing;
+ u32 no_chroma = 0;
+
+ tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED);
+ uniform_spacing = !!(pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING);
+
+ hantro_reg_write(vpu, &g2_tile_e, tiles_enabled);
+
+ max_log2_ctb_size = sps->log2_min_luma_coding_block_size_minus3 + 3 +
+ sps->log2_diff_max_min_luma_coding_block_size;
+ pic_width_in_ctbs = (sps->pic_width_in_luma_samples +
+ (1 << max_log2_ctb_size) - 1) >> max_log2_ctb_size;
+ pic_height_in_ctbs = (sps->pic_height_in_luma_samples + (1 << max_log2_ctb_size) - 1)
+ >> max_log2_ctb_size;
+ ctb_size = 1 << max_log2_ctb_size;
+
+ vpu_debug(1, "Preparing tile sizes buffer for %dx%d CTBs (CTB size %d)\n",
+ pic_width_in_ctbs, pic_height_in_ctbs, ctb_size);
+
+ if (tiles_enabled) {
+ unsigned int i, j, h;
+
+ vpu_debug(1, "Tiles enabled! %dx%d\n", num_tile_cols, num_tile_rows);
+
+ hantro_reg_write(vpu, &g2_num_tile_rows, num_tile_rows);
+ hantro_reg_write(vpu, &g2_num_tile_cols, num_tile_cols);
+
+ /* write width + height for each tile in pic */
+ if (!uniform_spacing) {
+ u32 tmp_w = 0, tmp_h = 0;
+
+ for (i = 0; i < num_tile_rows; i++) {
+ if (i == num_tile_rows - 1)
+ h = pic_height_in_ctbs - tmp_h;
+ else
+ h = pps->row_height_minus1[i] + 1;
+ tmp_h += h;
+ if (i == 0 && h == 1 && ctb_size == 16)
+ no_chroma = 1;
+ for (j = 0, tmp_w = 0; j < num_tile_cols - 1; j++) {
+ tmp_w += pps->column_width_minus1[j] + 1;
+ *p++ = pps->column_width_minus1[j + 1];
+ *p++ = h;
+ if (i == 0 && h == 1 && ctb_size == 16)
+ no_chroma = 1;
+ }
+ /* last column */
+ *p++ = pic_width_in_ctbs - tmp_w;
+ *p++ = h;
+ }
+ } else { /* uniform spacing */
+ u32 tmp, prev_h, prev_w;
+
+ for (i = 0, prev_h = 0; i < num_tile_rows; i++) {
+ tmp = (i + 1) * pic_height_in_ctbs / num_tile_rows;
+ h = tmp - prev_h;
+ prev_h = tmp;
+ if (i == 0 && h == 1 && ctb_size == 16)
+ no_chroma = 1;
+ for (j = 0, prev_w = 0; j < num_tile_cols; j++) {
+ tmp = (j + 1) * pic_width_in_ctbs / num_tile_cols;
+ *p++ = tmp - prev_w;
+ *p++ = h;
+ if (j == 0 &&
+ (pps->column_width_minus1[0] + 1) == 1 &&
+ ctb_size == 16)
+ no_chroma = 1;
+ prev_w = tmp;
+ }
+ }
+ }
+ } else {
+ hantro_reg_write(vpu, &g2_num_tile_rows, 1);
+ hantro_reg_write(vpu, &g2_num_tile_cols, 1);
+
+ /* There's one tile, with dimensions equal to pic size. */
+ p[0] = pic_width_in_ctbs;
+ p[1] = pic_height_in_ctbs;
+ }
+
+ if (no_chroma)
+ vpu_debug(1, "%s: no chroma!\n", __func__);
+}
+
+static void set_params(struct hantro_ctx *ctx)
+{
+ const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+ const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
+ const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps;
+ const struct v4l2_ctrl_hevc_decode_params *decode_params = ctrls->decode_params;
+ struct hantro_dev *vpu = ctx->dev;
+ u32 min_log2_cb_size, max_log2_ctb_size, min_cb_size, max_ctb_size;
+ u32 pic_width_in_min_cbs, pic_height_in_min_cbs;
+ u32 pic_width_aligned, pic_height_aligned;
+ u32 partial_ctb_x, partial_ctb_y;
+
+ hantro_reg_write(vpu, &g2_bit_depth_y_minus8, sps->bit_depth_luma_minus8);
+ hantro_reg_write(vpu, &g2_bit_depth_c_minus8, sps->bit_depth_chroma_minus8);
+
+ hantro_reg_write(vpu, &g2_output_8_bits, 0);
+
+ hantro_reg_write(vpu, &g2_hdr_skip_length, ctrls->hevc_hdr_skip_length);
+
+ min_log2_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
+ max_log2_ctb_size = min_log2_cb_size + sps->log2_diff_max_min_luma_coding_block_size;
+
+ hantro_reg_write(vpu, &g2_min_cb_size, min_log2_cb_size);
+ hantro_reg_write(vpu, &g2_max_cb_size, max_log2_ctb_size);
+
+ min_cb_size = 1 << min_log2_cb_size;
+ max_ctb_size = 1 << max_log2_ctb_size;
+
+ pic_width_in_min_cbs = sps->pic_width_in_luma_samples / min_cb_size;
+ pic_height_in_min_cbs = sps->pic_height_in_luma_samples / min_cb_size;
+ pic_width_aligned = ALIGN(sps->pic_width_in_luma_samples, max_ctb_size);
+ pic_height_aligned = ALIGN(sps->pic_height_in_luma_samples, max_ctb_size);
+
+ partial_ctb_x = !!(sps->pic_width_in_luma_samples != pic_width_aligned);
+ partial_ctb_y = !!(sps->pic_height_in_luma_samples != pic_height_aligned);
+
+ hantro_reg_write(vpu, &g2_partial_ctb_x, partial_ctb_x);
+ hantro_reg_write(vpu, &g2_partial_ctb_y, partial_ctb_y);
+
+ hantro_reg_write(vpu, &g2_pic_width_in_cbs, pic_width_in_min_cbs);
+ hantro_reg_write(vpu, &g2_pic_height_in_cbs, pic_height_in_min_cbs);
+
+ hantro_reg_write(vpu, &g2_pic_width_4x4,
+ (pic_width_in_min_cbs * min_cb_size) / 4);
+ hantro_reg_write(vpu, &g2_pic_height_4x4,
+ (pic_height_in_min_cbs * min_cb_size) / 4);
+
+ hantro_reg_write(vpu, &hevc_max_inter_hierdepth,
+ sps->max_transform_hierarchy_depth_inter);
+ hantro_reg_write(vpu, &hevc_max_intra_hierdepth,
+ sps->max_transform_hierarchy_depth_intra);
+ hantro_reg_write(vpu, &hevc_min_trb_size,
+ sps->log2_min_luma_transform_block_size_minus2 + 2);
+ hantro_reg_write(vpu, &hevc_max_trb_size,
+ sps->log2_min_luma_transform_block_size_minus2 + 2 +
+ sps->log2_diff_max_min_luma_transform_block_size);
+
+ hantro_reg_write(vpu, &g2_tempor_mvp_e,
+ !!(sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED) &&
+ !(decode_params->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC));
+ hantro_reg_write(vpu, &g2_strong_smooth_e,
+ !!(sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED));
+ hantro_reg_write(vpu, &g2_asym_pred_e,
+ !!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED));
+ hantro_reg_write(vpu, &g2_sao_e,
+ !!(sps->flags & V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET));
+ hantro_reg_write(vpu, &g2_sign_data_hide,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED));
+
+ if (pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED) {
+ hantro_reg_write(vpu, &g2_cu_qpd_e, 1);
+ hantro_reg_write(vpu, &g2_max_cu_qpd_depth, pps->diff_cu_qp_delta_depth);
+ } else {
+ hantro_reg_write(vpu, &g2_cu_qpd_e, 0);
+ hantro_reg_write(vpu, &g2_max_cu_qpd_depth, 0);
+ }
+
+ if (pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT) {
+ hantro_reg_write(vpu, &g2_cb_qp_offset, pps->pps_cb_qp_offset);
+ hantro_reg_write(vpu, &g2_cr_qp_offset, pps->pps_cr_qp_offset);
+ } else {
+ hantro_reg_write(vpu, &g2_cb_qp_offset, 0);
+ hantro_reg_write(vpu, &g2_cr_qp_offset, 0);
+ }
+
+ hantro_reg_write(vpu, &g2_filt_offset_beta, pps->pps_beta_offset_div2);
+ hantro_reg_write(vpu, &g2_filt_offset_tc, pps->pps_tc_offset_div2);
+ hantro_reg_write(vpu, &g2_slice_hdr_ext_e,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT));
+ hantro_reg_write(vpu, &g2_slice_hdr_ext_bits, pps->num_extra_slice_header_bits);
+ hantro_reg_write(vpu, &g2_slice_chqp_present,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT));
+ hantro_reg_write(vpu, &g2_weight_bipr_idc,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED));
+ hantro_reg_write(vpu, &g2_transq_bypass,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED));
+ hantro_reg_write(vpu, &g2_list_mod_e,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT));
+ hantro_reg_write(vpu, &g2_entropy_sync_e,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED));
+ hantro_reg_write(vpu, &g2_cabac_init_present,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT));
+ hantro_reg_write(vpu, &g2_idr_pic_e,
+ !!(decode_params->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC));
+ hantro_reg_write(vpu, &hevc_parallel_merge,
+ pps->log2_parallel_merge_level_minus2 + 2);
+ hantro_reg_write(vpu, &g2_pcm_filt_d,
+ !!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED));
+ hantro_reg_write(vpu, &g2_pcm_e,
+ !!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED));
+ if (sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED) {
+ hantro_reg_write(vpu, &g2_max_pcm_size,
+ sps->log2_diff_max_min_pcm_luma_coding_block_size +
+ sps->log2_min_pcm_luma_coding_block_size_minus3 + 3);
+ hantro_reg_write(vpu, &g2_min_pcm_size,
+ sps->log2_min_pcm_luma_coding_block_size_minus3 + 3);
+ hantro_reg_write(vpu, &g2_bit_depth_pcm_y,
+ sps->pcm_sample_bit_depth_luma_minus1 + 1);
+ hantro_reg_write(vpu, &g2_bit_depth_pcm_c,
+ sps->pcm_sample_bit_depth_chroma_minus1 + 1);
+ } else {
+ hantro_reg_write(vpu, &g2_max_pcm_size, 0);
+ hantro_reg_write(vpu, &g2_min_pcm_size, 0);
+ hantro_reg_write(vpu, &g2_bit_depth_pcm_y, 0);
+ hantro_reg_write(vpu, &g2_bit_depth_pcm_c, 0);
+ }
+
+ hantro_reg_write(vpu, &g2_start_code_e, 1);
+ hantro_reg_write(vpu, &g2_init_qp, pps->init_qp_minus26 + 26);
+ hantro_reg_write(vpu, &g2_weight_pred_e,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED));
+ hantro_reg_write(vpu, &g2_cabac_init_present,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT));
+ hantro_reg_write(vpu, &g2_const_intra_e,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED));
+ hantro_reg_write(vpu, &g2_transform_skip,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED));
+ hantro_reg_write(vpu, &g2_out_filtering_dis,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER));
+ hantro_reg_write(vpu, &g2_filt_ctrl_pres,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT));
+ hantro_reg_write(vpu, &g2_dependent_slice,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED));
+ hantro_reg_write(vpu, &g2_filter_override,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED));
+ hantro_reg_write(vpu, &g2_refidx0_active,
+ pps->num_ref_idx_l0_default_active_minus1 + 1);
+ hantro_reg_write(vpu, &g2_refidx1_active,
+ pps->num_ref_idx_l1_default_active_minus1 + 1);
+ hantro_reg_write(vpu, &g2_apf_threshold, 8);
+}
+
+static int find_ref_pic_index(const struct v4l2_hevc_dpb_entry *dpb, int pic_order_cnt)
+{
+ int i;
+
+ for (i = 0; i < V4L2_HEVC_DPB_ENTRIES_NUM_MAX; i++) {
+ if (dpb[i].pic_order_cnt[0] == pic_order_cnt)
+ return i;
+ }
+
+ return 0x0;
+}
+
+static void set_ref_pic_list(struct hantro_ctx *ctx)
+{
+ const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+ struct hantro_dev *vpu = ctx->dev;
+ const struct v4l2_ctrl_hevc_decode_params *decode_params = ctrls->decode_params;
+ const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
+ u32 list0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX] = {};
+ u32 list1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX] = {};
+ static const struct hantro_reg ref_pic_regs0[] = {
+ hevc_rlist_f0,
+ hevc_rlist_f1,
+ hevc_rlist_f2,
+ hevc_rlist_f3,
+ hevc_rlist_f4,
+ hevc_rlist_f5,
+ hevc_rlist_f6,
+ hevc_rlist_f7,
+ hevc_rlist_f8,
+ hevc_rlist_f9,
+ hevc_rlist_f10,
+ hevc_rlist_f11,
+ hevc_rlist_f12,
+ hevc_rlist_f13,
+ hevc_rlist_f14,
+ hevc_rlist_f15,
+ };
+ static const struct hantro_reg ref_pic_regs1[] = {
+ hevc_rlist_b0,
+ hevc_rlist_b1,
+ hevc_rlist_b2,
+ hevc_rlist_b3,
+ hevc_rlist_b4,
+ hevc_rlist_b5,
+ hevc_rlist_b6,
+ hevc_rlist_b7,
+ hevc_rlist_b8,
+ hevc_rlist_b9,
+ hevc_rlist_b10,
+ hevc_rlist_b11,
+ hevc_rlist_b12,
+ hevc_rlist_b13,
+ hevc_rlist_b14,
+ hevc_rlist_b15,
+ };
+ unsigned int i, j;
+
+ /* List 0 contains: short term before, short term after and long term */
+ j = 0;
+ for (i = 0; i < decode_params->num_poc_st_curr_before && j < ARRAY_SIZE(list0); i++)
+ list0[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_before[i]);
+ for (i = 0; i < decode_params->num_poc_st_curr_after && j < ARRAY_SIZE(list0); i++)
+ list0[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_after[i]);
+ for (i = 0; i < decode_params->num_poc_lt_curr && j < ARRAY_SIZE(list0); i++)
+ list0[j++] = find_ref_pic_index(dpb, decode_params->poc_lt_curr[i]);
+
+ /* Fill the list, copying over and over */
+ i = 0;
+ while (j < ARRAY_SIZE(list0))
+ list0[j++] = list0[i++];
+
+ j = 0;
+ for (i = 0; i < decode_params->num_poc_st_curr_after && j < ARRAY_SIZE(list1); i++)
+ list1[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_after[i]);
+ for (i = 0; i < decode_params->num_poc_st_curr_before && j < ARRAY_SIZE(list1); i++)
+ list1[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_before[i]);
+ for (i = 0; i < decode_params->num_poc_lt_curr && j < ARRAY_SIZE(list1); i++)
+ list1[j++] = find_ref_pic_index(dpb, decode_params->poc_lt_curr[i]);
+
+ i = 0;
+ while (j < ARRAY_SIZE(list1))
+ list1[j++] = list1[i++];
+
+ for (i = 0; i < V4L2_HEVC_DPB_ENTRIES_NUM_MAX; i++) {
+ hantro_reg_write(vpu, &ref_pic_regs0[i], list0[i]);
+ hantro_reg_write(vpu, &ref_pic_regs1[i], list1[i]);
+ }
+}
+
+static int set_ref(struct hantro_ctx *ctx)
+{
+ const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+ const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
+ const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps;
+ const struct v4l2_ctrl_hevc_decode_params *decode_params = ctrls->decode_params;
+ const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb;
+ dma_addr_t luma_addr, chroma_addr, mv_addr = 0;
+ struct hantro_dev *vpu = ctx->dev;
+ size_t cr_offset = hantro_hevc_chroma_offset(sps);
+ size_t mv_offset = hantro_hevc_motion_vectors_offset(sps);
+ u32 max_ref_frames;
+ u16 dpb_longterm_e;
+ static const struct hantro_reg cur_poc[] = {
+ hevc_cur_poc_00,
+ hevc_cur_poc_01,
+ hevc_cur_poc_02,
+ hevc_cur_poc_03,
+ hevc_cur_poc_04,
+ hevc_cur_poc_05,
+ hevc_cur_poc_06,
+ hevc_cur_poc_07,
+ hevc_cur_poc_08,
+ hevc_cur_poc_09,
+ hevc_cur_poc_10,
+ hevc_cur_poc_11,
+ hevc_cur_poc_12,
+ hevc_cur_poc_13,
+ hevc_cur_poc_14,
+ hevc_cur_poc_15,
+ };
+ unsigned int i;
+
+ max_ref_frames = decode_params->num_poc_lt_curr +
+ decode_params->num_poc_st_curr_before +
+ decode_params->num_poc_st_curr_after;
+ /*
+ * Set max_ref_frames to non-zero to avoid HW hang when decoding
+ * badly marked I-frames.
+ */
+ max_ref_frames = max_ref_frames ? max_ref_frames : 1;
+ hantro_reg_write(vpu, &g2_num_ref_frames, max_ref_frames);
+ hantro_reg_write(vpu, &g2_filter_over_slices,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED));
+ hantro_reg_write(vpu, &g2_filter_over_tiles,
+ !!(pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED));
+
+ /*
+ * Write POC count diff from current pic. For frame decoding only compute
+ * pic_order_cnt[0] and ignore pic_order_cnt[1] used in field-coding.
+ */
+ for (i = 0; i < decode_params->num_active_dpb_entries && i < ARRAY_SIZE(cur_poc); i++) {
+ char poc_diff = decode_params->pic_order_cnt_val - dpb[i].pic_order_cnt[0];
+
+ hantro_reg_write(vpu, &cur_poc[i], poc_diff);
+ }
+
+ if (i < ARRAY_SIZE(cur_poc)) {
+ /*
+ * After the references, fill one entry pointing to itself,
+ * i.e. difference is zero.
+ */
+ hantro_reg_write(vpu, &cur_poc[i], 0);
+ i++;
+ }
+
+ /* Fill the rest with the current picture */
+ for (; i < ARRAY_SIZE(cur_poc); i++)
+ hantro_reg_write(vpu, &cur_poc[i], decode_params->pic_order_cnt_val);
+
+ set_ref_pic_list(ctx);
+
+ /* We will only keep the references picture that are still used */
+ ctx->hevc_dec.ref_bufs_used = 0;
+
+ /* Set up addresses of DPB buffers */
+ dpb_longterm_e = 0;
+ for (i = 0; i < decode_params->num_active_dpb_entries &&
+ i < (V4L2_HEVC_DPB_ENTRIES_NUM_MAX - 1); i++) {
+ luma_addr = hantro_hevc_get_ref_buf(ctx, dpb[i].pic_order_cnt[0]);
+ if (!luma_addr)
+ return -ENOMEM;
+
+ chroma_addr = luma_addr + cr_offset;
+ mv_addr = luma_addr + mv_offset;
+
+ if (dpb[i].rps == V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR)
+ dpb_longterm_e |= BIT(V4L2_HEVC_DPB_ENTRIES_NUM_MAX - 1 - i);
+
+ hantro_write_addr(vpu, G2_REG_ADDR_REF(i), luma_addr);
+ hantro_write_addr(vpu, G2_REG_CHR_REF(i), chroma_addr);
+ hantro_write_addr(vpu, G2_REG_DMV_REF(i), mv_addr);
+ }
+
+ luma_addr = hantro_hevc_get_ref_buf(ctx, decode_params->pic_order_cnt_val);
+ if (!luma_addr)
+ return -ENOMEM;
+
+ chroma_addr = luma_addr + cr_offset;
+ mv_addr = luma_addr + mv_offset;
+
+ hantro_write_addr(vpu, G2_REG_ADDR_REF(i), luma_addr);
+ hantro_write_addr(vpu, G2_REG_CHR_REF(i), chroma_addr);
+ hantro_write_addr(vpu, G2_REG_DMV_REF(i++), mv_addr);
+
+ hantro_write_addr(vpu, G2_ADDR_DST, luma_addr);
+ hantro_write_addr(vpu, G2_ADDR_DST_CHR, chroma_addr);
+ hantro_write_addr(vpu, G2_ADDR_DST_MV, mv_addr);
+
+ hantro_hevc_ref_remove_unused(ctx);
+
+ for (; i < V4L2_HEVC_DPB_ENTRIES_NUM_MAX; i++) {
+ hantro_write_addr(vpu, G2_REG_ADDR_REF(i), 0);
+ hantro_write_addr(vpu, G2_REG_CHR_REF(i), 0);
+ hantro_write_addr(vpu, G2_REG_DMV_REF(i), 0);
+ }
+
+ hantro_reg_write(vpu, &g2_refer_lterm_e, dpb_longterm_e);
+
+ return 0;
+}
+
+static void set_buffers(struct hantro_ctx *ctx)
+{
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ struct hantro_dev *vpu = ctx->dev;
+ const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+ const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
+ size_t cr_offset = hantro_hevc_chroma_offset(sps);
+ dma_addr_t src_dma, dst_dma;
+ u32 src_len, src_buf_len;
+
+ src_buf = hantro_get_src_buf(ctx);
+ dst_buf = hantro_get_dst_buf(ctx);
+
+ /* Source (stream) buffer. */
+ src_dma = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+ src_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
+ src_buf_len = vb2_plane_size(&src_buf->vb2_buf, 0);
+
+ hantro_write_addr(vpu, G2_ADDR_STR, src_dma);
+ hantro_reg_write(vpu, &g2_stream_len, src_len);
+ hantro_reg_write(vpu, &g2_strm_buffer_len, src_buf_len);
+ hantro_reg_write(vpu, &g2_strm_start_offset, 0);
+ hantro_reg_write(vpu, &g2_write_mvs_e, 1);
+
+ /* Destination (decoded frame) buffer. */
+ dst_dma = hantro_get_dec_buf_addr(ctx, &dst_buf->vb2_buf);
+
+ hantro_write_addr(vpu, G2_RASTER_SCAN, dst_dma);
+ hantro_write_addr(vpu, G2_RASTER_SCAN_CHR, dst_dma + cr_offset);
+ hantro_write_addr(vpu, G2_ADDR_TILE_SIZE, ctx->hevc_dec.tile_sizes.dma);
+ hantro_write_addr(vpu, G2_TILE_FILTER, ctx->hevc_dec.tile_filter.dma);
+ hantro_write_addr(vpu, G2_TILE_SAO, ctx->hevc_dec.tile_sao.dma);
+ hantro_write_addr(vpu, G2_TILE_BSD, ctx->hevc_dec.tile_bsd.dma);
+}
+
+static void hantro_g2_check_idle(struct hantro_dev *vpu)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ u32 status;
+
+ /* Make sure the VPU is idle */
+ status = vdpu_read(vpu, G2_REG_INTERRUPT);
+ if (status & G2_REG_INTERRUPT_DEC_E) {
+ dev_warn(vpu->dev, "device still running, aborting");
+ status |= G2_REG_INTERRUPT_DEC_ABORT_E | G2_REG_INTERRUPT_DEC_IRQ_DIS;
+ vdpu_write(vpu, status, G2_REG_INTERRUPT);
+ }
+ }
+}
+
+int hantro_g2_hevc_dec_run(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ int ret;
+
+ hantro_g2_check_idle(vpu);
+
+ /* Prepare HEVC decoder context. */
+ ret = hantro_hevc_dec_prepare_run(ctx);
+ if (ret)
+ return ret;
+
+ /* Configure hardware registers. */
+ set_params(ctx);
+
+ /* set reference pictures */
+ ret = set_ref(ctx);
+ if (ret)
+ return ret;
+
+ set_buffers(ctx);
+ prepare_tile_info_buffer(ctx);
+
+ hantro_end_prepare_run(ctx);
+
+ hantro_reg_write(vpu, &g2_mode, HEVC_DEC_MODE);
+ hantro_reg_write(vpu, &g2_clk_gate_e, 1);
+
+ /* Don't disable output */
+ hantro_reg_write(vpu, &g2_out_dis, 0);
+
+ /* Don't compress buffers */
+ hantro_reg_write(vpu, &g2_ref_compress_bypass, 1);
+
+ /* use NV12 as output format */
+ hantro_reg_write(vpu, &g2_out_rs_e, 1);
+
+ /* Bus width and max burst */
+ hantro_reg_write(vpu, &g2_buswidth, BUS_WIDTH_128);
+ hantro_reg_write(vpu, &g2_max_burst, 16);
+
+ /* Swap */
+ hantro_reg_write(vpu, &g2_strm_swap, 0xf);
+ hantro_reg_write(vpu, &g2_dirmv_swap, 0xf);
+ hantro_reg_write(vpu, &g2_compress_swap, 0xf);
+
+ /* Start decoding! */
+ vdpu_write(vpu, G2_REG_INTERRUPT_DEC_E, G2_REG_INTERRUPT);
+
+ return 0;
+}
diff --git a/drivers/staging/media/hantro/hantro_g2_regs.h b/drivers/staging/media/hantro/hantro_g2_regs.h
new file mode 100644
index 000000000000..bb22fa921914
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_g2_regs.h
@@ -0,0 +1,198 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021, Collabora
+ *
+ * Author: Benjamin Gaignard <benjamin.gaignard@collabora.com>
+ */
+
+#ifndef HANTRO_G2_REGS_H_
+#define HANTRO_G2_REGS_H_
+
+#include "hantro.h"
+
+#define G2_SWREG(nr) ((nr) * 4)
+
+#define G2_DEC_REG(b, s, m) \
+ ((const struct hantro_reg) { \
+ .base = G2_SWREG(b), \
+ .shift = s, \
+ .mask = m, \
+ })
+
+#define G2_REG_VERSION G2_SWREG(0)
+
+#define G2_REG_INTERRUPT G2_SWREG(1)
+#define G2_REG_INTERRUPT_DEC_RDY_INT BIT(12)
+#define G2_REG_INTERRUPT_DEC_ABORT_E BIT(5)
+#define G2_REG_INTERRUPT_DEC_IRQ_DIS BIT(4)
+#define G2_REG_INTERRUPT_DEC_E BIT(0)
+
+#define g2_strm_swap G2_DEC_REG(2, 28, 0xf)
+#define g2_dirmv_swap G2_DEC_REG(2, 20, 0xf)
+
+#define g2_mode G2_DEC_REG(3, 27, 0x1f)
+#define g2_compress_swap G2_DEC_REG(3, 20, 0xf)
+#define g2_ref_compress_bypass G2_DEC_REG(3, 17, 0x1)
+#define g2_out_rs_e G2_DEC_REG(3, 16, 0x1)
+#define g2_out_dis G2_DEC_REG(3, 15, 0x1)
+#define g2_out_filtering_dis G2_DEC_REG(3, 14, 0x1)
+#define g2_write_mvs_e G2_DEC_REG(3, 12, 0x1)
+
+#define g2_pic_width_in_cbs G2_DEC_REG(4, 19, 0x1fff)
+#define g2_pic_height_in_cbs G2_DEC_REG(4, 6, 0x1fff)
+#define g2_num_ref_frames G2_DEC_REG(4, 0, 0x1f)
+
+#define g2_scaling_list_e G2_DEC_REG(5, 24, 0x1)
+#define g2_cb_qp_offset G2_DEC_REG(5, 19, 0x1f)
+#define g2_cr_qp_offset G2_DEC_REG(5, 14, 0x1f)
+#define g2_sign_data_hide G2_DEC_REG(5, 12, 0x1)
+#define g2_tempor_mvp_e G2_DEC_REG(5, 11, 0x1)
+#define g2_max_cu_qpd_depth G2_DEC_REG(5, 5, 0x3f)
+#define g2_cu_qpd_e G2_DEC_REG(5, 4, 0x1)
+
+#define g2_stream_len G2_DEC_REG(6, 0, 0xffffffff)
+
+#define g2_cabac_init_present G2_DEC_REG(7, 31, 0x1)
+#define g2_weight_pred_e G2_DEC_REG(7, 28, 0x1)
+#define g2_weight_bipr_idc G2_DEC_REG(7, 26, 0x3)
+#define g2_filter_over_slices G2_DEC_REG(7, 25, 0x1)
+#define g2_filter_over_tiles G2_DEC_REG(7, 24, 0x1)
+#define g2_asym_pred_e G2_DEC_REG(7, 23, 0x1)
+#define g2_sao_e G2_DEC_REG(7, 22, 0x1)
+#define g2_pcm_filt_d G2_DEC_REG(7, 21, 0x1)
+#define g2_slice_chqp_present G2_DEC_REG(7, 20, 0x1)
+#define g2_dependent_slice G2_DEC_REG(7, 19, 0x1)
+#define g2_filter_override G2_DEC_REG(7, 18, 0x1)
+#define g2_strong_smooth_e G2_DEC_REG(7, 17, 0x1)
+#define g2_filt_offset_beta G2_DEC_REG(7, 12, 0x1f)
+#define g2_filt_offset_tc G2_DEC_REG(7, 7, 0x1f)
+#define g2_slice_hdr_ext_e G2_DEC_REG(7, 6, 0x1)
+#define g2_slice_hdr_ext_bits G2_DEC_REG(7, 3, 0x7)
+
+#define g2_const_intra_e G2_DEC_REG(8, 31, 0x1)
+#define g2_filt_ctrl_pres G2_DEC_REG(8, 30, 0x1)
+#define g2_idr_pic_e G2_DEC_REG(8, 16, 0x1)
+#define g2_bit_depth_pcm_y G2_DEC_REG(8, 12, 0xf)
+#define g2_bit_depth_pcm_c G2_DEC_REG(8, 8, 0xf)
+#define g2_bit_depth_y_minus8 G2_DEC_REG(8, 6, 0x3)
+#define g2_bit_depth_c_minus8 G2_DEC_REG(8, 4, 0x3)
+#define g2_output_8_bits G2_DEC_REG(8, 3, 0x1)
+
+#define g2_refidx1_active G2_DEC_REG(9, 19, 0x1f)
+#define g2_refidx0_active G2_DEC_REG(9, 14, 0x1f)
+#define g2_hdr_skip_length G2_DEC_REG(9, 0, 0x3fff)
+
+#define g2_start_code_e G2_DEC_REG(10, 31, 0x1)
+#define g2_init_qp G2_DEC_REG(10, 24, 0x3f)
+#define g2_num_tile_cols G2_DEC_REG(10, 19, 0x1f)
+#define g2_num_tile_rows G2_DEC_REG(10, 14, 0x1f)
+#define g2_tile_e G2_DEC_REG(10, 1, 0x1)
+#define g2_entropy_sync_e G2_DEC_REG(10, 0, 0x1)
+
+#define g2_refer_lterm_e G2_DEC_REG(12, 16, 0xffff)
+#define g2_min_cb_size G2_DEC_REG(12, 13, 0x7)
+#define g2_max_cb_size G2_DEC_REG(12, 10, 0x7)
+#define g2_min_pcm_size G2_DEC_REG(12, 7, 0x7)
+#define g2_max_pcm_size G2_DEC_REG(12, 4, 0x7)
+#define g2_pcm_e G2_DEC_REG(12, 3, 0x1)
+#define g2_transform_skip G2_DEC_REG(12, 2, 0x1)
+#define g2_transq_bypass G2_DEC_REG(12, 1, 0x1)
+#define g2_list_mod_e G2_DEC_REG(12, 0, 0x1)
+
+#define hevc_min_trb_size G2_DEC_REG(13, 13, 0x7)
+#define hevc_max_trb_size G2_DEC_REG(13, 10, 0x7)
+#define hevc_max_intra_hierdepth G2_DEC_REG(13, 7, 0x7)
+#define hevc_max_inter_hierdepth G2_DEC_REG(13, 4, 0x7)
+#define hevc_parallel_merge G2_DEC_REG(13, 0, 0xf)
+
+#define hevc_rlist_f0 G2_DEC_REG(14, 0, 0x1f)
+#define hevc_rlist_f1 G2_DEC_REG(14, 10, 0x1f)
+#define hevc_rlist_f2 G2_DEC_REG(14, 20, 0x1f)
+#define hevc_rlist_b0 G2_DEC_REG(14, 5, 0x1f)
+#define hevc_rlist_b1 G2_DEC_REG(14, 15, 0x1f)
+#define hevc_rlist_b2 G2_DEC_REG(14, 25, 0x1f)
+
+#define hevc_rlist_f3 G2_DEC_REG(15, 0, 0x1f)
+#define hevc_rlist_f4 G2_DEC_REG(15, 10, 0x1f)
+#define hevc_rlist_f5 G2_DEC_REG(15, 20, 0x1f)
+#define hevc_rlist_b3 G2_DEC_REG(15, 5, 0x1f)
+#define hevc_rlist_b4 G2_DEC_REG(15, 15, 0x1f)
+#define hevc_rlist_b5 G2_DEC_REG(15, 25, 0x1f)
+
+#define hevc_rlist_f6 G2_DEC_REG(16, 0, 0x1f)
+#define hevc_rlist_f7 G2_DEC_REG(16, 10, 0x1f)
+#define hevc_rlist_f8 G2_DEC_REG(16, 20, 0x1f)
+#define hevc_rlist_b6 G2_DEC_REG(16, 5, 0x1f)
+#define hevc_rlist_b7 G2_DEC_REG(16, 15, 0x1f)
+#define hevc_rlist_b8 G2_DEC_REG(16, 25, 0x1f)
+
+#define hevc_rlist_f9 G2_DEC_REG(17, 0, 0x1f)
+#define hevc_rlist_f10 G2_DEC_REG(17, 10, 0x1f)
+#define hevc_rlist_f11 G2_DEC_REG(17, 20, 0x1f)
+#define hevc_rlist_b9 G2_DEC_REG(17, 5, 0x1f)
+#define hevc_rlist_b10 G2_DEC_REG(17, 15, 0x1f)
+#define hevc_rlist_b11 G2_DEC_REG(17, 25, 0x1f)
+
+#define hevc_rlist_f12 G2_DEC_REG(18, 0, 0x1f)
+#define hevc_rlist_f13 G2_DEC_REG(18, 10, 0x1f)
+#define hevc_rlist_f14 G2_DEC_REG(18, 20, 0x1f)
+#define hevc_rlist_b12 G2_DEC_REG(18, 5, 0x1f)
+#define hevc_rlist_b13 G2_DEC_REG(18, 15, 0x1f)
+#define hevc_rlist_b14 G2_DEC_REG(18, 25, 0x1f)
+
+#define hevc_rlist_f15 G2_DEC_REG(19, 0, 0x1f)
+#define hevc_rlist_b15 G2_DEC_REG(19, 5, 0x1f)
+
+#define g2_partial_ctb_x G2_DEC_REG(20, 31, 0x1)
+#define g2_partial_ctb_y G2_DEC_REG(20, 30, 0x1)
+#define g2_pic_width_4x4 G2_DEC_REG(20, 16, 0xfff)
+#define g2_pic_height_4x4 G2_DEC_REG(20, 0, 0xfff)
+#define hevc_cur_poc_00 G2_DEC_REG(46, 24, 0xff)
+#define hevc_cur_poc_01 G2_DEC_REG(46, 16, 0xff)
+#define hevc_cur_poc_02 G2_DEC_REG(46, 8, 0xff)
+#define hevc_cur_poc_03 G2_DEC_REG(46, 0, 0xff)
+
+#define hevc_cur_poc_04 G2_DEC_REG(47, 24, 0xff)
+#define hevc_cur_poc_05 G2_DEC_REG(47, 16, 0xff)
+#define hevc_cur_poc_06 G2_DEC_REG(47, 8, 0xff)
+#define hevc_cur_poc_07 G2_DEC_REG(47, 0, 0xff)
+
+#define hevc_cur_poc_08 G2_DEC_REG(48, 24, 0xff)
+#define hevc_cur_poc_09 G2_DEC_REG(48, 16, 0xff)
+#define hevc_cur_poc_10 G2_DEC_REG(48, 8, 0xff)
+#define hevc_cur_poc_11 G2_DEC_REG(48, 0, 0xff)
+
+#define hevc_cur_poc_12 G2_DEC_REG(49, 24, 0xff)
+#define hevc_cur_poc_13 G2_DEC_REG(49, 16, 0xff)
+#define hevc_cur_poc_14 G2_DEC_REG(49, 8, 0xff)
+#define hevc_cur_poc_15 G2_DEC_REG(49, 0, 0xff)
+
+#define g2_apf_threshold G2_DEC_REG(55, 0, 0xffff)
+
+#define g2_clk_gate_e G2_DEC_REG(58, 16, 0x1)
+#define g2_buswidth G2_DEC_REG(58, 8, 0x7)
+#define g2_max_burst G2_DEC_REG(58, 0, 0xff)
+
+#define G2_REG_CONFIG G2_SWREG(58)
+#define G2_REG_CONFIG_DEC_CLK_GATE_E BIT(16)
+#define G2_REG_CONFIG_DEC_CLK_GATE_IDLE_E BIT(17)
+
+#define G2_ADDR_DST (G2_SWREG(65))
+#define G2_REG_ADDR_REF(i) (G2_SWREG(67) + ((i) * 0x8))
+#define G2_ADDR_DST_CHR (G2_SWREG(99))
+#define G2_REG_CHR_REF(i) (G2_SWREG(101) + ((i) * 0x8))
+#define G2_ADDR_DST_MV (G2_SWREG(133))
+#define G2_REG_DMV_REF(i) (G2_SWREG(135) + ((i) * 0x8))
+#define G2_ADDR_TILE_SIZE (G2_SWREG(167))
+#define G2_ADDR_STR (G2_SWREG(169))
+#define HEVC_SCALING_LIST (G2_SWREG(171))
+#define G2_RASTER_SCAN (G2_SWREG(175))
+#define G2_RASTER_SCAN_CHR (G2_SWREG(177))
+#define G2_TILE_FILTER (G2_SWREG(179))
+#define G2_TILE_SAO (G2_SWREG(181))
+#define G2_TILE_BSD (G2_SWREG(183))
+
+#define g2_strm_buffer_len G2_DEC_REG(258, 0, 0xffffffff)
+#define g2_strm_start_offset G2_DEC_REG(259, 0, 0xffffffff)
+
+#endif
diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c
index b88dc4ed06db..56cf261a8e95 100644
--- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c
+++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c
@@ -88,7 +88,7 @@ hantro_h1_jpeg_enc_set_qtable(struct hantro_dev *vpu,
}
}
-void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx)
+int hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx)
{
struct hantro_dev *vpu = ctx->dev;
struct vb2_v4l2_buffer *src_buf, *dst_buf;
@@ -136,6 +136,8 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx)
hantro_end_prepare_run(ctx);
vepu_write(vpu, reg, H1_REG_ENC_CTRL);
+
+ return 0;
}
void hantro_jpeg_enc_done(struct hantro_ctx *ctx)
diff --git a/drivers/staging/media/hantro/hantro_hevc.c b/drivers/staging/media/hantro/hantro_hevc.c
new file mode 100644
index 000000000000..5347f5a41c2a
--- /dev/null
+++ b/drivers/staging/media/hantro/hantro_hevc.c
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU HEVC codec driver
+ *
+ * Copyright (C) 2020 Safran Passenger Innovations LLC
+ */
+
+#include <linux/types.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "hantro.h"
+#include "hantro_hw.h"
+
+#define VERT_FILTER_RAM_SIZE 8 /* bytes per pixel row */
+/*
+ * BSD control data of current picture at tile border
+ * 128 bits per 4x4 tile = 128/(8*4) bytes per row
+ */
+#define BSD_CTRL_RAM_SIZE 4 /* bytes per pixel row */
+/* tile border coefficients of filter */
+#define VERT_SAO_RAM_SIZE 48 /* bytes per pixel */
+
+#define MAX_TILE_COLS 20
+#define MAX_TILE_ROWS 22
+
+#define UNUSED_REF -1
+
+#define G2_ALIGN 16
+
+size_t hantro_hevc_chroma_offset(const struct v4l2_ctrl_hevc_sps *sps)
+{
+ int bytes_per_pixel = sps->bit_depth_luma_minus8 == 0 ? 1 : 2;
+
+ return sps->pic_width_in_luma_samples *
+ sps->pic_height_in_luma_samples * bytes_per_pixel;
+}
+
+size_t hantro_hevc_motion_vectors_offset(const struct v4l2_ctrl_hevc_sps *sps)
+{
+ size_t cr_offset = hantro_hevc_chroma_offset(sps);
+
+ return ALIGN((cr_offset * 3) / 2, G2_ALIGN);
+}
+
+static size_t hantro_hevc_mv_size(const struct v4l2_ctrl_hevc_sps *sps)
+{
+ u32 min_cb_log2_size_y = sps->log2_min_luma_coding_block_size_minus3 + 3;
+ u32 ctb_log2_size_y = min_cb_log2_size_y + sps->log2_diff_max_min_luma_coding_block_size;
+ u32 pic_width_in_ctbs_y = (sps->pic_width_in_luma_samples + (1 << ctb_log2_size_y) - 1)
+ >> ctb_log2_size_y;
+ u32 pic_height_in_ctbs_y = (sps->pic_height_in_luma_samples + (1 << ctb_log2_size_y) - 1)
+ >> ctb_log2_size_y;
+ size_t mv_size;
+
+ mv_size = pic_width_in_ctbs_y * pic_height_in_ctbs_y *
+ (1 << (2 * (ctb_log2_size_y - 4))) * 16;
+
+ vpu_debug(4, "%dx%d (CTBs) %zu MV bytes\n",
+ pic_width_in_ctbs_y, pic_height_in_ctbs_y, mv_size);
+
+ return mv_size;
+}
+
+static size_t hantro_hevc_ref_size(struct hantro_ctx *ctx)
+{
+ const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+ const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
+
+ return hantro_hevc_motion_vectors_offset(sps) + hantro_hevc_mv_size(sps);
+}
+
+static void hantro_hevc_ref_free(struct hantro_ctx *ctx)
+{
+ struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
+ struct hantro_dev *vpu = ctx->dev;
+ int i;
+
+ for (i = 0; i < NUM_REF_PICTURES; i++) {
+ if (hevc_dec->ref_bufs[i].cpu)
+ dma_free_coherent(vpu->dev, hevc_dec->ref_bufs[i].size,
+ hevc_dec->ref_bufs[i].cpu,
+ hevc_dec->ref_bufs[i].dma);
+ }
+}
+
+static void hantro_hevc_ref_init(struct hantro_ctx *ctx)
+{
+ struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
+ int i;
+
+ for (i = 0; i < NUM_REF_PICTURES; i++)
+ hevc_dec->ref_bufs_poc[i] = UNUSED_REF;
+}
+
+dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx,
+ int poc)
+{
+ struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
+ int i;
+
+ /* Find the reference buffer in already know ones */
+ for (i = 0; i < NUM_REF_PICTURES; i++) {
+ if (hevc_dec->ref_bufs_poc[i] == poc) {
+ hevc_dec->ref_bufs_used |= 1 << i;
+ return hevc_dec->ref_bufs[i].dma;
+ }
+ }
+
+ /* Allocate a new reference buffer */
+ for (i = 0; i < NUM_REF_PICTURES; i++) {
+ if (hevc_dec->ref_bufs_poc[i] == UNUSED_REF) {
+ if (!hevc_dec->ref_bufs[i].cpu) {
+ struct hantro_dev *vpu = ctx->dev;
+
+ /*
+ * Allocate the space needed for the raw data +
+ * motion vector data. Optimizations could be to
+ * allocate raw data in non coherent memory and only
+ * clear the motion vector data.
+ */
+ hevc_dec->ref_bufs[i].cpu =
+ dma_alloc_coherent(vpu->dev,
+ hantro_hevc_ref_size(ctx),
+ &hevc_dec->ref_bufs[i].dma,
+ GFP_KERNEL);
+ if (!hevc_dec->ref_bufs[i].cpu)
+ return 0;
+
+ hevc_dec->ref_bufs[i].size = hantro_hevc_ref_size(ctx);
+ }
+ hevc_dec->ref_bufs_used |= 1 << i;
+ memset(hevc_dec->ref_bufs[i].cpu, 0, hantro_hevc_ref_size(ctx));
+ hevc_dec->ref_bufs_poc[i] = poc;
+
+ return hevc_dec->ref_bufs[i].dma;
+ }
+ }
+
+ return 0;
+}
+
+void hantro_hevc_ref_remove_unused(struct hantro_ctx *ctx)
+{
+ struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
+ int i;
+
+ /* Just tag buffer as unused, do not free them */
+ for (i = 0; i < NUM_REF_PICTURES; i++) {
+ if (hevc_dec->ref_bufs_poc[i] == UNUSED_REF)
+ continue;
+
+ if (hevc_dec->ref_bufs_used & (1 << i))
+ continue;
+
+ hevc_dec->ref_bufs_poc[i] = UNUSED_REF;
+ }
+}
+
+static int tile_buffer_reallocate(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
+ const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+ const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps;
+ const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
+ unsigned int num_tile_cols = pps->num_tile_columns_minus1 + 1;
+ unsigned int height64 = (sps->pic_height_in_luma_samples + 63) & ~63;
+ unsigned int size;
+
+ if (num_tile_cols <= 1 ||
+ num_tile_cols <= hevc_dec->num_tile_cols_allocated)
+ return 0;
+
+ /* Need to reallocate due to tiles passed via PPS */
+ if (hevc_dec->tile_filter.cpu) {
+ dma_free_coherent(vpu->dev, hevc_dec->tile_filter.size,
+ hevc_dec->tile_filter.cpu,
+ hevc_dec->tile_filter.dma);
+ hevc_dec->tile_filter.cpu = NULL;
+ }
+
+ if (hevc_dec->tile_sao.cpu) {
+ dma_free_coherent(vpu->dev, hevc_dec->tile_sao.size,
+ hevc_dec->tile_sao.cpu,
+ hevc_dec->tile_sao.dma);
+ hevc_dec->tile_sao.cpu = NULL;
+ }
+
+ if (hevc_dec->tile_bsd.cpu) {
+ dma_free_coherent(vpu->dev, hevc_dec->tile_bsd.size,
+ hevc_dec->tile_bsd.cpu,
+ hevc_dec->tile_bsd.dma);
+ hevc_dec->tile_bsd.cpu = NULL;
+ }
+
+ size = VERT_FILTER_RAM_SIZE * height64 * (num_tile_cols - 1);
+ hevc_dec->tile_filter.cpu = dma_alloc_coherent(vpu->dev, size,
+ &hevc_dec->tile_filter.dma,
+ GFP_KERNEL);
+ if (!hevc_dec->tile_filter.cpu)
+ goto err_free_tile_buffers;
+ hevc_dec->tile_filter.size = size;
+
+ size = VERT_SAO_RAM_SIZE * height64 * (num_tile_cols - 1);
+ hevc_dec->tile_sao.cpu = dma_alloc_coherent(vpu->dev, size,
+ &hevc_dec->tile_sao.dma,
+ GFP_KERNEL);
+ if (!hevc_dec->tile_sao.cpu)
+ goto err_free_tile_buffers;
+ hevc_dec->tile_sao.size = size;
+
+ size = BSD_CTRL_RAM_SIZE * height64 * (num_tile_cols - 1);
+ hevc_dec->tile_bsd.cpu = dma_alloc_coherent(vpu->dev, size,
+ &hevc_dec->tile_bsd.dma,
+ GFP_KERNEL);
+ if (!hevc_dec->tile_bsd.cpu)
+ goto err_free_tile_buffers;
+ hevc_dec->tile_bsd.size = size;
+
+ hevc_dec->num_tile_cols_allocated = num_tile_cols;
+
+ return 0;
+
+err_free_tile_buffers:
+ if (hevc_dec->tile_filter.cpu)
+ dma_free_coherent(vpu->dev, hevc_dec->tile_filter.size,
+ hevc_dec->tile_filter.cpu,
+ hevc_dec->tile_filter.dma);
+ hevc_dec->tile_filter.cpu = NULL;
+
+ if (hevc_dec->tile_sao.cpu)
+ dma_free_coherent(vpu->dev, hevc_dec->tile_sao.size,
+ hevc_dec->tile_sao.cpu,
+ hevc_dec->tile_sao.dma);
+ hevc_dec->tile_sao.cpu = NULL;
+
+ if (hevc_dec->tile_bsd.cpu)
+ dma_free_coherent(vpu->dev, hevc_dec->tile_bsd.size,
+ hevc_dec->tile_bsd.cpu,
+ hevc_dec->tile_bsd.dma);
+ hevc_dec->tile_bsd.cpu = NULL;
+
+ return -ENOMEM;
+}
+
+int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx)
+{
+ struct hantro_hevc_dec_hw_ctx *hevc_ctx = &ctx->hevc_dec;
+ struct hantro_hevc_dec_ctrls *ctrls = &hevc_ctx->ctrls;
+ int ret;
+
+ hantro_start_prepare_run(ctx);
+
+ ctrls->decode_params =
+ hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS);
+ if (WARN_ON(!ctrls->decode_params))
+ return -EINVAL;
+
+ ctrls->sps =
+ hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SPS);
+ if (WARN_ON(!ctrls->sps))
+ return -EINVAL;
+
+ ctrls->pps =
+ hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_PPS);
+ if (WARN_ON(!ctrls->pps))
+ return -EINVAL;
+
+ ret = tile_buffer_reallocate(ctx);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void hantro_hevc_dec_exit(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
+
+ if (hevc_dec->tile_sizes.cpu)
+ dma_free_coherent(vpu->dev, hevc_dec->tile_sizes.size,
+ hevc_dec->tile_sizes.cpu,
+ hevc_dec->tile_sizes.dma);
+ hevc_dec->tile_sizes.cpu = NULL;
+
+ if (hevc_dec->tile_filter.cpu)
+ dma_free_coherent(vpu->dev, hevc_dec->tile_filter.size,
+ hevc_dec->tile_filter.cpu,
+ hevc_dec->tile_filter.dma);
+ hevc_dec->tile_filter.cpu = NULL;
+
+ if (hevc_dec->tile_sao.cpu)
+ dma_free_coherent(vpu->dev, hevc_dec->tile_sao.size,
+ hevc_dec->tile_sao.cpu,
+ hevc_dec->tile_sao.dma);
+ hevc_dec->tile_sao.cpu = NULL;
+
+ if (hevc_dec->tile_bsd.cpu)
+ dma_free_coherent(vpu->dev, hevc_dec->tile_bsd.size,
+ hevc_dec->tile_bsd.cpu,
+ hevc_dec->tile_bsd.dma);
+ hevc_dec->tile_bsd.cpu = NULL;
+
+ hantro_hevc_ref_free(ctx);
+}
+
+int hantro_hevc_dec_init(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
+ unsigned int size;
+
+ memset(hevc_dec, 0, sizeof(*hevc_dec));
+
+ /*
+ * Maximum number of tiles times width and height (2 bytes each),
+ * rounding up to next 16 bytes boundary + one extra 16 byte
+ * chunk (HW guys wanted to have this).
+ */
+ size = round_up(MAX_TILE_COLS * MAX_TILE_ROWS * 4 * sizeof(u16) + 16, 16);
+ hevc_dec->tile_sizes.cpu = dma_alloc_coherent(vpu->dev, size,
+ &hevc_dec->tile_sizes.dma,
+ GFP_KERNEL);
+ if (!hevc_dec->tile_sizes.cpu)
+ return -ENOMEM;
+
+ hevc_dec->tile_sizes.size = size;
+
+ hantro_hevc_ref_init(ctx);
+
+ return 0;
+}
diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h
index 83b3e42b63a3..5dcf65805396 100644
--- a/drivers/staging/media/hantro/hantro_hw.h
+++ b/drivers/staging/media/hantro/hantro_hw.h
@@ -20,6 +20,8 @@
#define MB_WIDTH(w) DIV_ROUND_UP(w, MB_DIM)
#define MB_HEIGHT(h) DIV_ROUND_UP(h, MB_DIM)
+#define NUM_REF_PICTURES (V4L2_HEVC_DPB_ENTRIES_NUM_MAX + 1)
+
struct hantro_dev;
struct hantro_ctx;
struct hantro_buf;
@@ -96,6 +98,46 @@ struct hantro_h264_dec_hw_ctx {
};
/**
+ * struct hantro_hevc_dec_ctrls
+ * @decode_params: Decode params
+ * @sps: SPS info
+ * @pps: PPS info
+ * @hevc_hdr_skip_length: the number of data (in bits) to skip in the
+ * slice segment header syntax after 'slice type'
+ * token
+ */
+struct hantro_hevc_dec_ctrls {
+ const struct v4l2_ctrl_hevc_decode_params *decode_params;
+ const struct v4l2_ctrl_hevc_sps *sps;
+ const struct v4l2_ctrl_hevc_pps *pps;
+ u32 hevc_hdr_skip_length;
+};
+
+/**
+ * struct hantro_hevc_dec_hw_ctx
+ * @tile_sizes: Tile sizes buffer
+ * @tile_filter: Tile vertical filter buffer
+ * @tile_sao: Tile SAO buffer
+ * @tile_bsd: Tile BSD control buffer
+ * @ref_bufs: Internal reference buffers
+ * @ref_bufs_poc: Internal reference buffers picture order count
+ * @ref_bufs_used: Bitfield of used reference buffers
+ * @ctrls: V4L2 controls attached to a run
+ * @num_tile_cols_allocated: number of allocated tiles
+ */
+struct hantro_hevc_dec_hw_ctx {
+ struct hantro_aux_buf tile_sizes;
+ struct hantro_aux_buf tile_filter;
+ struct hantro_aux_buf tile_sao;
+ struct hantro_aux_buf tile_bsd;
+ struct hantro_aux_buf ref_bufs[NUM_REF_PICTURES];
+ int ref_bufs_poc[NUM_REF_PICTURES];
+ u32 ref_bufs_used;
+ struct hantro_hevc_dec_ctrls ctrls;
+ unsigned int num_tile_cols_allocated;
+};
+
+/**
* struct hantro_mpeg2_dec_hw_ctx
*
* @qtable: Quantization table
@@ -133,14 +175,15 @@ struct hantro_postproc_ctx {
* 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.
+ * should be programmed and started. Returns zero if OK, a
+ * negative value in error cases.
* @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);
+ int (*run)(struct hantro_ctx *ctx);
void (*done)(struct hantro_ctx *ctx);
void (*reset)(struct hantro_ctx *ctx);
};
@@ -148,22 +191,26 @@ struct hantro_codec_ops {
/**
* enum hantro_enc_fmt - source format ID for hardware registers.
*
- * @RK3288_VPU_ENC_FMT_YUV420P: Y/CbCr 4:2:0 planar format
- * @RK3288_VPU_ENC_FMT_YUV420SP: Y/CbCr 4:2:0 semi-planar format
- * @RK3288_VPU_ENC_FMT_YUYV422: YUV 4:2:2 packed format (YUYV)
- * @RK3288_VPU_ENC_FMT_UYVY422: YUV 4:2:2 packed format (UYVY)
+ * @ROCKCHIP_VPU_ENC_FMT_YUV420P: Y/CbCr 4:2:0 planar format
+ * @ROCKCHIP_VPU_ENC_FMT_YUV420SP: Y/CbCr 4:2:0 semi-planar format
+ * @ROCKCHIP_VPU_ENC_FMT_YUYV422: YUV 4:2:2 packed format (YUYV)
+ * @ROCKCHIP_VPU_ENC_FMT_UYVY422: YUV 4:2:2 packed format (UYVY)
*/
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,
+ ROCKCHIP_VPU_ENC_FMT_YUV420P = 0,
+ ROCKCHIP_VPU_ENC_FMT_YUV420SP = 1,
+ ROCKCHIP_VPU_ENC_FMT_YUYV422 = 2,
+ ROCKCHIP_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;
+extern const struct hantro_variant imx8mq_vpu_g2_variant;
extern const struct hantro_variant imx8mq_vpu_variant;
+extern const struct hantro_variant rk3036_vpu_variant;
+extern const struct hantro_variant rk3066_vpu_variant;
+extern const struct hantro_variant rk3288_vpu_variant;
+extern const struct hantro_variant rk3328_vpu_variant;
+extern const struct hantro_variant rk3399_vpu_variant;
+extern const struct hantro_variant sama5d4_vdec_variant;
extern const struct hantro_postproc_regs hantro_g1_postproc_regs;
@@ -176,8 +223,11 @@ void hantro_irq_done(struct hantro_dev *vpu,
void hantro_start_prepare_run(struct hantro_ctx *ctx);
void hantro_end_prepare_run(struct hantro_ctx *ctx);
-void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx);
-void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx);
+irqreturn_t hantro_g1_irq(int irq, void *dev_id);
+void hantro_g1_reset(struct hantro_ctx *ctx);
+
+int hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx);
+int rockchip_vpu2_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_jpeg_enc_done(struct hantro_ctx *ctx);
@@ -185,10 +235,19 @@ void hantro_jpeg_enc_done(struct hantro_ctx *ctx);
dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx,
unsigned int dpb_idx);
int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx);
-void hantro_g1_h264_dec_run(struct hantro_ctx *ctx);
+int hantro_g1_h264_dec_run(struct hantro_ctx *ctx);
int hantro_h264_dec_init(struct hantro_ctx *ctx);
void hantro_h264_dec_exit(struct hantro_ctx *ctx);
+int hantro_hevc_dec_init(struct hantro_ctx *ctx);
+void hantro_hevc_dec_exit(struct hantro_ctx *ctx);
+int hantro_g2_hevc_dec_run(struct hantro_ctx *ctx);
+int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx);
+dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx, int poc);
+void hantro_hevc_ref_remove_unused(struct hantro_ctx *ctx);
+size_t hantro_hevc_chroma_offset(const struct v4l2_ctrl_hevc_sps *sps);
+size_t hantro_hevc_motion_vectors_offset(const struct v4l2_ctrl_hevc_sps *sps);
+
static inline size_t
hantro_h264_mv_size(unsigned int width, unsigned int height)
{
@@ -216,15 +275,15 @@ hantro_h264_mv_size(unsigned int width, unsigned int height)
return 64 * MB_WIDTH(width) * MB_WIDTH(height) + 32;
}
-void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx);
-void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx);
+int hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx);
+int rockchip_vpu2_mpeg2_dec_run(struct hantro_ctx *ctx);
void hantro_mpeg2_dec_copy_qtable(u8 *qtable,
- const struct v4l2_ctrl_mpeg2_quantization *ctrl);
+ const struct v4l2_ctrl_mpeg2_quantisation *ctrl);
int hantro_mpeg2_dec_init(struct hantro_ctx *ctx);
void hantro_mpeg2_dec_exit(struct hantro_ctx *ctx);
-void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx);
-void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx);
+int hantro_g1_vp8_dec_run(struct hantro_ctx *ctx);
+int rockchip_vpu2_vp8_dec_run(struct hantro_ctx *ctx);
int hantro_vp8_dec_init(struct hantro_ctx *ctx);
void hantro_vp8_dec_exit(struct hantro_ctx *ctx);
void hantro_vp8_prob_update(struct hantro_ctx *ctx,
diff --git a/drivers/staging/media/hantro/hantro_mpeg2.c b/drivers/staging/media/hantro/hantro_mpeg2.c
index 1d334e6fcd06..04e545eb0a83 100644
--- a/drivers/staging/media/hantro/hantro_mpeg2.c
+++ b/drivers/staging/media/hantro/hantro_mpeg2.c
@@ -19,7 +19,7 @@ static const u8 zigzag[64] = {
};
void hantro_mpeg2_dec_copy_qtable(u8 *qtable,
- const struct v4l2_ctrl_mpeg2_quantization *ctrl)
+ const struct v4l2_ctrl_mpeg2_quantisation *ctrl)
{
int i, n;
diff --git a/drivers/staging/media/hantro/hantro_postproc.c b/drivers/staging/media/hantro/hantro_postproc.c
index 6d2a8f2a8f0b..ed8916c950a4 100644
--- a/drivers/staging/media/hantro/hantro_postproc.c
+++ b/drivers/staging/media/hantro/hantro_postproc.c
@@ -50,6 +50,20 @@ const struct hantro_postproc_regs hantro_g1_postproc_regs = {
.display_width = {G1_REG_PP_DISPLAY_WIDTH, 0, 0xfff},
};
+bool hantro_needs_postproc(const struct hantro_ctx *ctx,
+ const struct hantro_fmt *fmt)
+{
+ struct hantro_dev *vpu = ctx->dev;
+
+ if (ctx->is_encoder)
+ return false;
+
+ if (!vpu->variant->postproc_fmts)
+ return false;
+
+ return fmt->fourcc != V4L2_PIX_FMT_NV12;
+}
+
void hantro_postproc_enable(struct hantro_ctx *ctx)
{
struct hantro_dev *vpu = ctx->dev;
diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c
index 1bc118e375a1..bcb0bdff4a9a 100644
--- a/drivers/staging/media/hantro/hantro_v4l2.c
+++ b/drivers/staging/media/hantro/hantro_v4l2.c
@@ -55,7 +55,9 @@ static const struct hantro_fmt *
hantro_get_postproc_formats(const struct hantro_ctx *ctx,
unsigned int *num_fmts)
{
- if (ctx->is_encoder) {
+ struct hantro_dev *vpu = ctx->dev;
+
+ if (ctx->is_encoder || !vpu->variant->postproc_fmts) {
*num_fmts = 0;
return NULL;
}
@@ -390,6 +392,7 @@ hantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc)
case V4L2_PIX_FMT_MPEG2_SLICE:
case V4L2_PIX_FMT_VP8_FRAME:
case V4L2_PIX_FMT_H264_SLICE:
+ case V4L2_PIX_FMT_HEVC_SLICE:
ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true;
break;
default:
@@ -639,7 +642,14 @@ static int hantro_buf_prepare(struct vb2_buffer *vb)
ret = hantro_buf_plane_check(vb, pix_fmt);
if (ret)
return ret;
- vb2_set_plane_payload(vb, 0, pix_fmt->plane_fmt[0].sizeimage);
+ /*
+ * Buffer's bytesused must be written by driver for CAPTURE buffers.
+ * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets
+ * it to buffer length).
+ */
+ if (V4L2_TYPE_IS_CAPTURE(vq->type))
+ vb2_set_plane_payload(vb, 0, pix_fmt->plane_fmt[0].sizeimage);
+
return 0;
}
diff --git a/drivers/staging/media/hantro/imx8m_vpu_hw.c b/drivers/staging/media/hantro/imx8m_vpu_hw.c
index c222de075ef4..ea919bfb9891 100644
--- a/drivers/staging/media/hantro/imx8m_vpu_hw.c
+++ b/drivers/staging/media/hantro/imx8m_vpu_hw.c
@@ -11,6 +11,7 @@
#include "hantro.h"
#include "hantro_jpeg.h"
#include "hantro_g1_regs.h"
+#include "hantro_g2_regs.h"
#define CTRL_SOFT_RESET 0x00
#define RESET_G1 BIT(1)
@@ -109,10 +110,10 @@ static const struct hantro_fmt imx8m_vpu_dec_fmts[] = {
.frmsize = {
.min_width = 48,
.max_width = 3840,
- .step_width = 16,
+ .step_width = MB_DIM,
.min_height = 48,
.max_height = 2160,
- .step_height = 16,
+ .step_height = MB_DIM,
},
},
{
@@ -130,6 +131,26 @@ static const struct hantro_fmt imx8m_vpu_dec_fmts[] = {
},
};
+static const struct hantro_fmt imx8m_vpu_g2_dec_fmts[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .codec_mode = HANTRO_MODE_NONE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_HEVC_SLICE,
+ .codec_mode = HANTRO_MODE_HEVC_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 3840,
+ .step_width = MB_DIM,
+ .min_height = 48,
+ .max_height = 2160,
+ .step_height = MB_DIM,
+ },
+ },
+};
+
static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id)
{
struct hantro_dev *vpu = dev_id;
@@ -148,9 +169,26 @@ static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static irqreturn_t imx8m_vpu_g2_irq(int irq, void *dev_id)
+{
+ struct hantro_dev *vpu = dev_id;
+ enum vb2_buffer_state state;
+ u32 status;
+
+ status = vdpu_read(vpu, G2_REG_INTERRUPT);
+ state = (status & G2_REG_INTERRUPT_DEC_RDY_INT) ?
+ VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+ vdpu_write(vpu, 0, G2_REG_INTERRUPT);
+ vdpu_write(vpu, G2_REG_CONFIG_DEC_CLK_GATE_E, G2_REG_CONFIG);
+
+ hantro_irq_done(vpu, state);
+
+ return IRQ_HANDLED;
+}
+
static int imx8mq_vpu_hw_init(struct hantro_dev *vpu)
{
- vpu->dec_base = vpu->reg_bases[0];
vpu->ctrl_base = vpu->reg_bases[vpu->variant->num_regs - 1];
return 0;
@@ -163,6 +201,13 @@ static void imx8m_vpu_g1_reset(struct hantro_ctx *ctx)
imx8m_soft_reset(vpu, RESET_G1);
}
+static void imx8m_vpu_g2_reset(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+
+ imx8m_soft_reset(vpu, RESET_G2);
+}
+
/*
* Supported codec ops.
*/
@@ -188,13 +233,25 @@ static const struct hantro_codec_ops imx8mq_vpu_codec_ops[] = {
},
};
+static const struct hantro_codec_ops imx8mq_vpu_g2_codec_ops[] = {
+ [HANTRO_MODE_HEVC_DEC] = {
+ .run = hantro_g2_hevc_dec_run,
+ .reset = imx8m_vpu_g2_reset,
+ .init = hantro_hevc_dec_init,
+ .exit = hantro_hevc_dec_exit,
+ },
+};
+
/*
* VPU variants.
*/
static const struct hantro_irq imx8mq_irqs[] = {
{ "g1", imx8m_vpu_g1_irq },
- { "g2", NULL /* TODO: imx8m_vpu_g2_irq */ },
+};
+
+static const struct hantro_irq imx8mq_g2_irqs[] = {
+ { "g2", imx8m_vpu_g2_irq },
};
static const char * const imx8mq_clk_names[] = { "g1", "g2", "bus" };
@@ -218,3 +275,17 @@ const struct hantro_variant imx8mq_vpu_variant = {
.reg_names = imx8mq_reg_names,
.num_regs = ARRAY_SIZE(imx8mq_reg_names)
};
+
+const struct hantro_variant imx8mq_vpu_g2_variant = {
+ .dec_offset = 0x0,
+ .dec_fmts = imx8m_vpu_g2_dec_fmts,
+ .num_dec_fmts = ARRAY_SIZE(imx8m_vpu_g2_dec_fmts),
+ .codec = HANTRO_HEVC_DECODER,
+ .codec_ops = imx8mq_vpu_g2_codec_ops,
+ .init = imx8mq_vpu_hw_init,
+ .runtime_resume = imx8mq_runtime_resume,
+ .irqs = imx8mq_g2_irqs,
+ .num_irqs = ARRAY_SIZE(imx8mq_g2_irqs),
+ .clk_names = imx8mq_clk_names,
+ .num_clocks = ARRAY_SIZE(imx8mq_clk_names),
+};
diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c
deleted file mode 100644
index 7b299ee3e93d..000000000000
--- a/drivers/staging/media/hantro/rk3288_vpu_hw.c
+++ /dev/null
@@ -1,236 +0,0 @@
-// 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 = MB_DIM,
- .min_height = 32,
- .max_height = 8192,
- .step_height = MB_DIM,
- },
- },
-};
-
-static const struct hantro_fmt rk3288_vpu_postproc_fmts[] = {
- {
- .fourcc = V4L2_PIX_FMT_YUYV,
- .codec_mode = HANTRO_MODE_NONE,
- },
-};
-
-static const struct hantro_fmt rk3288_vpu_dec_fmts[] = {
- {
- .fourcc = V4L2_PIX_FMT_NV12,
- .codec_mode = HANTRO_MODE_NONE,
- },
- {
- .fourcc = V4L2_PIX_FMT_H264_SLICE,
- .codec_mode = HANTRO_MODE_H264_DEC,
- .max_depth = 2,
- .frmsize = {
- .min_width = 48,
- .max_width = 4096,
- .step_width = MB_DIM,
- .min_height = 48,
- .max_height = 2304,
- .step_height = MB_DIM,
- },
- },
- {
- .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
- .codec_mode = HANTRO_MODE_MPEG2_DEC,
- .max_depth = 2,
- .frmsize = {
- .min_width = 48,
- .max_width = 1920,
- .step_width = MB_DIM,
- .min_height = 48,
- .max_height = 1088,
- .step_height = MB_DIM,
- },
- },
- {
- .fourcc = V4L2_PIX_FMT_VP8_FRAME,
- .codec_mode = HANTRO_MODE_VP8_DEC,
- .max_depth = 2,
- .frmsize = {
- .min_width = 48,
- .max_width = 3840,
- .step_width = MB_DIM,
- .min_height = 48,
- .max_height = 2160,
- .step_height = 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;
-
- status = vepu_read(vpu, H1_REG_INTERRUPT);
- 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, 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, 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,
- .done = hantro_jpeg_enc_done,
- .exit = hantro_jpeg_enc_exit,
- },
- [HANTRO_MODE_H264_DEC] = {
- .run = hantro_g1_h264_dec_run,
- .reset = rk3288_vpu_dec_reset,
- .init = hantro_h264_dec_init,
- .exit = hantro_h264_dec_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,
- },
- [HANTRO_MODE_VP8_DEC] = {
- .run = hantro_g1_vp8_dec_run,
- .reset = rk3288_vpu_dec_reset,
- .init = hantro_vp8_dec_init,
- .exit = hantro_vp8_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),
- .postproc_fmts = rk3288_vpu_postproc_fmts,
- .num_postproc_fmts = ARRAY_SIZE(rk3288_vpu_postproc_fmts),
- .postproc_regs = &hantro_g1_postproc_regs,
- .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER |
- HANTRO_VP8_DECODER | HANTRO_H264_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
deleted file mode 100644
index 7a7962cf771e..000000000000
--- a/drivers/staging/media/hantro/rk3399_vpu_hw.c
+++ /dev/null
@@ -1,222 +0,0 @@
-// 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 = MB_DIM,
- .min_height = 32,
- .max_height = 8192,
- .step_height = 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 = MB_DIM,
- .min_height = 48,
- .max_height = 1088,
- .step_height = MB_DIM,
- },
- },
- {
- .fourcc = V4L2_PIX_FMT_VP8_FRAME,
- .codec_mode = HANTRO_MODE_VP8_DEC,
- .max_depth = 2,
- .frmsize = {
- .min_width = 48,
- .max_width = 3840,
- .step_width = MB_DIM,
- .min_height = 48,
- .max_height = 2160,
- .step_height = 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;
-
- status = vepu_read(vpu, VEPU_REG_INTERRUPT);
- 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, 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, 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,
- },
- [HANTRO_MODE_VP8_DEC] = {
- .run = rk3399_vpu_vp8_dec_run,
- .reset = rk3399_vpu_dec_reset,
- .init = hantro_vp8_dec_init,
- .exit = hantro_vp8_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 |
- HANTRO_VP8_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)
-};
-
-static const struct hantro_irq rk3328_irqs[] = {
- { "vdpu", rk3399_vdpu_irq },
-};
-
-const struct hantro_variant rk3328_vpu_variant = {
- .dec_offset = 0x400,
- .dec_fmts = rk3399_vpu_dec_fmts,
- .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts),
- .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER,
- .codec_ops = rk3399_vpu_codec_ops,
- .irqs = rk3328_irqs,
- .num_irqs = ARRAY_SIZE(rk3328_irqs),
- .init = rk3399_vpu_hw_init,
- .clk_names = rk3399_clk_names,
- .num_clocks = ARRAY_SIZE(rk3399_clk_names),
-};
diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c
index 3498e6124acd..991213ce1610 100644
--- a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c
+++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c
@@ -28,12 +28,12 @@
#include "hantro.h"
#include "hantro_v4l2.h"
#include "hantro_hw.h"
-#include "rk3399_vpu_regs.h"
+#include "rockchip_vpu2_regs.h"
#define VEPU_JPEG_QUANT_TABLE_COUNT 16
-static void rk3399_vpu_set_src_img_ctrl(struct hantro_dev *vpu,
- struct hantro_ctx *ctx)
+static void rockchip_vpu2_set_src_img_ctrl(struct hantro_dev *vpu,
+ struct hantro_ctx *ctx)
{
struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt;
u32 reg;
@@ -59,9 +59,9 @@ static void rk3399_vpu_set_src_img_ctrl(struct hantro_dev *vpu,
vepu_write_relaxed(vpu, reg, VEPU_REG_ENC_CTRL1);
}
-static void rk3399_vpu_jpeg_enc_set_buffers(struct hantro_dev *vpu,
- struct hantro_ctx *ctx,
- struct vb2_buffer *src_buf)
+static void rockchip_vpu2_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];
@@ -92,9 +92,9 @@ static void rk3399_vpu_jpeg_enc_set_buffers(struct hantro_dev *vpu,
}
static void
-rk3399_vpu_jpeg_enc_set_qtable(struct hantro_dev *vpu,
- unsigned char *luma_qtable,
- unsigned char *chroma_qtable)
+rockchip_vpu2_jpeg_enc_set_qtable(struct hantro_dev *vpu,
+ unsigned char *luma_qtable,
+ unsigned char *chroma_qtable)
{
u32 reg, i;
__be32 *luma_qtable_p;
@@ -118,7 +118,7 @@ rk3399_vpu_jpeg_enc_set_qtable(struct hantro_dev *vpu,
}
}
-void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx)
+int rockchip_vpu2_jpeg_enc_run(struct hantro_ctx *ctx)
{
struct hantro_dev *vpu = ctx->dev;
struct vb2_v4l2_buffer *src_buf, *dst_buf;
@@ -141,11 +141,11 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx)
vepu_write_relaxed(vpu, VEPU_REG_ENCODE_FORMAT_JPEG,
VEPU_REG_ENCODE_START);
- 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,
- hantro_jpeg_get_qtable(0),
- hantro_jpeg_get_qtable(1));
+ rockchip_vpu2_set_src_img_ctrl(vpu, ctx);
+ rockchip_vpu2_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf);
+ rockchip_vpu2_jpeg_enc_set_qtable(vpu,
+ hantro_jpeg_get_qtable(0),
+ hantro_jpeg_get_qtable(1));
reg = VEPU_REG_OUTPUT_SWAP32
| VEPU_REG_OUTPUT_SWAP16
@@ -168,4 +168,6 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx)
/* Kick the watchdog and start encoding */
hantro_end_prepare_run(ctx);
vepu_write(vpu, reg, VEPU_REG_ENCODE_START);
+
+ return 0;
}
diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_mpeg2_dec.c
index f610fa5b4335..b66737fab46b 100644
--- a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c
+++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_mpeg2_dec.c
@@ -79,43 +79,34 @@
#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)
+rockchip_vpu2_mpeg2_dec_set_quantisation(struct hantro_dev *vpu,
+ struct hantro_ctx *ctx)
{
- struct v4l2_ctrl_mpeg2_quantization *quantization;
+ struct v4l2_ctrl_mpeg2_quantisation *q;
- 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);
+ q = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_MPEG2_QUANTISATION);
+ hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, q);
+ 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)
+rockchip_vpu2_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_ctrl_mpeg2_sequence *seq,
+ const struct v4l2_ctrl_mpeg2_picture *pic)
{
dma_addr_t forward_addr = 0, backward_addr = 0;
dma_addr_t current_addr, addr;
- switch (picture->picture_coding_type) {
- case V4L2_MPEG2_PICTURE_CODING_TYPE_B:
- backward_addr = hantro_get_ref(ctx,
- slice_params->backward_ref_ts);
+ switch (pic->picture_coding_type) {
+ case V4L2_MPEG2_PIC_CODING_TYPE_B:
+ backward_addr = hantro_get_ref(ctx, pic->backward_ref_ts);
fallthrough;
- case V4L2_MPEG2_PICTURE_CODING_TYPE_P:
- forward_addr = hantro_get_ref(ctx,
- slice_params->forward_ref_ts);
+ case V4L2_MPEG2_PIC_CODING_TYPE_P:
+ forward_addr = hantro_get_ref(ctx, pic->forward_ref_ts);
}
/* Source bitstream buffer */
@@ -126,7 +117,7 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu,
addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
current_addr = addr;
- if (picture->picture_structure == PICT_BOTTOM_FIELD)
+ if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD)
addr += ALIGN(ctx->dst_fmt.width, 16);
vdpu_write_relaxed(vpu, addr, VDPU_REG_DEC_OUT_BASE);
@@ -136,18 +127,18 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu,
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)) {
+ if (pic->picture_structure == V4L2_MPEG2_PIC_FRAME ||
+ pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B ||
+ (pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD &&
+ pic->flags & V4L2_MPEG2_PIC_TOP_FIELD) ||
+ (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD &&
+ !(pic->flags & V4L2_MPEG2_PIC_TOP_FIELD))) {
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) {
+ } else if (pic->picture_structure == V4L2_MPEG2_PIC_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) {
+ } else if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD) {
vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER0_BASE);
vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE);
}
@@ -157,13 +148,12 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu,
vdpu_write_relaxed(vpu, backward_addr, VDPU_REG_REFER3_BASE);
}
-void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx)
+int rockchip_vpu2_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;
+ const struct v4l2_ctrl_mpeg2_sequence *seq;
+ const struct v4l2_ctrl_mpeg2_picture *pic;
u32 reg;
src_buf = hantro_get_src_buf(ctx);
@@ -171,10 +161,10 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx)
hantro_start_prepare_run(ctx);
- slice_params = hantro_get_ctrl(ctx,
- V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS);
- sequence = &slice_params->sequence;
- picture = &slice_params->picture;
+ seq = hantro_get_ctrl(ctx,
+ V4L2_CID_STATELESS_MPEG2_SEQUENCE);
+ pic = hantro_get_ctrl(ctx,
+ V4L2_CID_STATELESS_MPEG2_PICTURE);
reg = VDPU_REG_DEC_ADV_PRE_DIS(0) |
VDPU_REG_DEC_SCMD_DIS(0) |
@@ -183,7 +173,7 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx)
vdpu_write_relaxed(vpu, reg, VDPU_SWREG(50));
reg = VDPU_REG_INIT_QP(1) |
- VDPU_REG_STREAM_LEN(slice_params->bit_size >> 3);
+ VDPU_REG_STREAM_LEN(vb2_get_plane_payload(&src_buf->vb2_buf, 0));
vdpu_write_relaxed(vpu, reg, VDPU_SWREG(51));
reg = VDPU_REG_APF_THRESHOLD(8) |
@@ -209,11 +199,11 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx)
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_PIC_INTERLACE_E(!(seq->flags & V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE)) |
+ VDPU_REG_PIC_FIELDMODE_E(pic->picture_structure != V4L2_MPEG2_PIC_FRAME) |
+ VDPU_REG_PIC_B_E(pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B) |
+ VDPU_REG_PIC_INTER_E(pic->picture_coding_type != V4L2_MPEG2_PIC_CODING_TYPE_I) |
+ VDPU_REG_PIC_TOPFIELD_E(pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD) |
VDPU_REG_FWD_INTERLACE_E(0) |
VDPU_REG_WRITE_MVS_E(0) |
VDPU_REG_DEC_TIMEOUT_E(1) |
@@ -222,36 +212,37 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx)
reg = VDPU_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->dst_fmt.width)) |
VDPU_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->dst_fmt.height)) |
- VDPU_REG_ALT_SCAN_E(picture->alternate_scan) |
- VDPU_REG_TOPFIELDFIRST_E(picture->top_field_first);
+ VDPU_REG_ALT_SCAN_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) |
+ VDPU_REG_TOPFIELDFIRST_E(pic->flags & V4L2_MPEG2_PIC_FLAG_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);
+ reg = VDPU_REG_STRM_START_BIT(0) |
+ VDPU_REG_QSCALE_TYPE(pic->flags & V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE) |
+ VDPU_REG_CON_MV_E(pic->flags & V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV) |
+ VDPU_REG_INTRA_DC_PREC(pic->intra_dc_precision) |
+ VDPU_REG_INTRA_VLC_TAB(pic->flags & V4L2_MPEG2_PIC_FLAG_INTRA_VLC) |
+ VDPU_REG_FRAME_PRED_DCT(pic->flags & V4L2_MPEG2_PIC_FLAG_FRAME_PRED_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]) |
+ reg = VDPU_REG_ALT_SCAN_FLAG_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) |
+ VDPU_REG_FCODE_FWD_HOR(pic->f_code[0][0]) |
+ VDPU_REG_FCODE_FWD_VER(pic->f_code[0][1]) |
+ VDPU_REG_FCODE_BWD_HOR(pic->f_code[1][0]) |
+ VDPU_REG_FCODE_BWD_VER(pic->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);
+ rockchip_vpu2_mpeg2_dec_set_quantisation(vpu, ctx);
- rk3399_vpu_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf,
- &dst_buf->vb2_buf,
- sequence, picture, slice_params);
+ rockchip_vpu2_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf,
+ &dst_buf->vb2_buf, seq, pic);
/* Kick the watchdog and start decoding */
hantro_end_prepare_run(ctx);
reg = vdpu_read(vpu, VDPU_SWREG(57)) | VDPU_REG_DEC_E(1);
vdpu_write(vpu, reg, VDPU_SWREG(57));
+
+ return 0;
}
diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c
index 8661a3cc1e6b..951b55f58a61 100644
--- a/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c
+++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c
@@ -503,7 +503,7 @@ static void cfg_buffers(struct hantro_ctx *ctx,
vdpu_write_relaxed(vpu, dst_dma, VDPU_REG_ADDR_DST);
}
-void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx)
+int rockchip_vpu2_vp8_dec_run(struct hantro_ctx *ctx)
{
const struct v4l2_ctrl_vp8_frame *hdr;
struct hantro_dev *vpu = ctx->dev;
@@ -516,7 +516,7 @@ void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx)
hdr = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_VP8_FRAME);
if (WARN_ON(!hdr))
- return;
+ return -EINVAL;
/* Reset segment_map buffer in keyframe */
if (V4L2_VP8_FRAME_IS_KEY_FRAME(hdr) && ctx->vp8_dec.segment_map.cpu)
@@ -589,4 +589,6 @@ void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx)
hantro_end_prepare_run(ctx);
hantro_reg_write(vpu, &vp8_dec_start_dec, 1);
+
+ return 0;
}
diff --git a/drivers/staging/media/hantro/rk3399_vpu_regs.h b/drivers/staging/media/hantro/rockchip_vpu2_regs.h
index 88d096920f30..49e40889545b 100644
--- a/drivers/staging/media/hantro/rk3399_vpu_regs.h
+++ b/drivers/staging/media/hantro/rockchip_vpu2_regs.h
@@ -6,8 +6,8 @@
* Alpha Lin <alpha.lin@rock-chips.com>
*/
-#ifndef RK3399_VPU_REGS_H_
-#define RK3399_VPU_REGS_H_
+#ifndef ROCKCHIP_VPU2_REGS_H_
+#define ROCKCHIP_VPU2_REGS_H_
/* Encoder registers. */
#define VEPU_REG_VP8_QUT_1ST(i) (0x000 + ((i) * 0x24))
@@ -597,4 +597,4 @@
#define VDPU_REG_PRED_FLT_PRED_BC_TAP_4_3(x) (((x) & 0x3ff) << 12)
#define VDPU_REG_PRED_FLT_PRED_BC_TAP_5_0(x) (((x) & 0x3ff) << 2)
-#endif /* RK3399_VPU_REGS_H_ */
+#endif /* ROCKCHIP_VPU2_REGS_H_ */
diff --git a/drivers/staging/media/hantro/rockchip_vpu_hw.c b/drivers/staging/media/hantro/rockchip_vpu_hw.c
new file mode 100644
index 000000000000..3ccc16413f42
--- /dev/null
+++ b/drivers/staging/media/hantro/rockchip_vpu_hw.c
@@ -0,0 +1,526 @@
+// 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"
+#include "rockchip_vpu2_regs.h"
+
+#define RK3066_ACLK_MAX_FREQ (300 * 1000 * 1000)
+#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000)
+
+/*
+ * Supported formats.
+ */
+
+static const struct hantro_fmt rockchip_vpu_enc_fmts[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_YUV420M,
+ .codec_mode = HANTRO_MODE_NONE,
+ .enc_fmt = ROCKCHIP_VPU_ENC_FMT_YUV420P,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .codec_mode = HANTRO_MODE_NONE,
+ .enc_fmt = ROCKCHIP_VPU_ENC_FMT_YUV420SP,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .codec_mode = HANTRO_MODE_NONE,
+ .enc_fmt = ROCKCHIP_VPU_ENC_FMT_YUYV422,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .codec_mode = HANTRO_MODE_NONE,
+ .enc_fmt = ROCKCHIP_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 = MB_DIM,
+ .min_height = 32,
+ .max_height = 8192,
+ .step_height = MB_DIM,
+ },
+ },
+};
+
+static const struct hantro_fmt rockchip_vpu1_postproc_fmts[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .codec_mode = HANTRO_MODE_NONE,
+ },
+};
+
+static const struct hantro_fmt rk3066_vpu_dec_fmts[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .codec_mode = HANTRO_MODE_NONE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_H264_SLICE,
+ .codec_mode = HANTRO_MODE_H264_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 1920,
+ .step_width = MB_DIM,
+ .min_height = 48,
+ .max_height = 1088,
+ .step_height = MB_DIM,
+ },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
+ .codec_mode = HANTRO_MODE_MPEG2_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 1920,
+ .step_width = MB_DIM,
+ .min_height = 48,
+ .max_height = 1088,
+ .step_height = MB_DIM,
+ },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_VP8_FRAME,
+ .codec_mode = HANTRO_MODE_VP8_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 1920,
+ .step_width = MB_DIM,
+ .min_height = 48,
+ .max_height = 1088,
+ .step_height = 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_H264_SLICE,
+ .codec_mode = HANTRO_MODE_H264_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 4096,
+ .step_width = MB_DIM,
+ .min_height = 48,
+ .max_height = 2304,
+ .step_height = MB_DIM,
+ },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
+ .codec_mode = HANTRO_MODE_MPEG2_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 1920,
+ .step_width = MB_DIM,
+ .min_height = 48,
+ .max_height = 1088,
+ .step_height = MB_DIM,
+ },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_VP8_FRAME,
+ .codec_mode = HANTRO_MODE_VP8_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 3840,
+ .step_width = MB_DIM,
+ .min_height = 48,
+ .max_height = 2160,
+ .step_height = 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 = MB_DIM,
+ .min_height = 48,
+ .max_height = 1088,
+ .step_height = MB_DIM,
+ },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_VP8_FRAME,
+ .codec_mode = HANTRO_MODE_VP8_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 3840,
+ .step_width = MB_DIM,
+ .min_height = 48,
+ .max_height = 2160,
+ .step_height = MB_DIM,
+ },
+ },
+};
+
+static irqreturn_t rockchip_vpu1_vepu_irq(int irq, void *dev_id)
+{
+ struct hantro_dev *vpu = dev_id;
+ enum vb2_buffer_state state;
+ u32 status;
+
+ status = vepu_read(vpu, H1_REG_INTERRUPT);
+ 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, state);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rockchip_vpu2_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, state);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rockchip_vpu2_vepu_irq(int irq, void *dev_id)
+{
+ struct hantro_dev *vpu = dev_id;
+ enum vb2_buffer_state state;
+ u32 status;
+
+ status = vepu_read(vpu, VEPU_REG_INTERRUPT);
+ 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, state);
+
+ return IRQ_HANDLED;
+}
+
+static int rk3036_vpu_hw_init(struct hantro_dev *vpu)
+{
+ /* Bump ACLK to max. possible freq. to improve performance. */
+ clk_set_rate(vpu->clocks[0].clk, RK3066_ACLK_MAX_FREQ);
+ return 0;
+}
+
+static int rk3066_vpu_hw_init(struct hantro_dev *vpu)
+{
+ /* Bump ACLKs to max. possible freq. to improve performance. */
+ clk_set_rate(vpu->clocks[0].clk, RK3066_ACLK_MAX_FREQ);
+ clk_set_rate(vpu->clocks[2].clk, RK3066_ACLK_MAX_FREQ);
+ return 0;
+}
+
+static int rockchip_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 rk3066_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);
+}
+
+static void rockchip_vpu1_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 rockchip_vpu2_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);
+}
+
+static void rockchip_vpu2_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);
+}
+
+/*
+ * Supported codec ops.
+ */
+static const struct hantro_codec_ops rk3036_vpu_codec_ops[] = {
+ [HANTRO_MODE_H264_DEC] = {
+ .run = hantro_g1_h264_dec_run,
+ .reset = hantro_g1_reset,
+ .init = hantro_h264_dec_init,
+ .exit = hantro_h264_dec_exit,
+ },
+ [HANTRO_MODE_MPEG2_DEC] = {
+ .run = hantro_g1_mpeg2_dec_run,
+ .reset = hantro_g1_reset,
+ .init = hantro_mpeg2_dec_init,
+ .exit = hantro_mpeg2_dec_exit,
+ },
+ [HANTRO_MODE_VP8_DEC] = {
+ .run = hantro_g1_vp8_dec_run,
+ .reset = hantro_g1_reset,
+ .init = hantro_vp8_dec_init,
+ .exit = hantro_vp8_dec_exit,
+ },
+};
+
+static const struct hantro_codec_ops rk3066_vpu_codec_ops[] = {
+ [HANTRO_MODE_JPEG_ENC] = {
+ .run = hantro_h1_jpeg_enc_run,
+ .reset = rockchip_vpu1_enc_reset,
+ .init = hantro_jpeg_enc_init,
+ .done = hantro_jpeg_enc_done,
+ .exit = hantro_jpeg_enc_exit,
+ },
+ [HANTRO_MODE_H264_DEC] = {
+ .run = hantro_g1_h264_dec_run,
+ .reset = rk3066_vpu_dec_reset,
+ .init = hantro_h264_dec_init,
+ .exit = hantro_h264_dec_exit,
+ },
+ [HANTRO_MODE_MPEG2_DEC] = {
+ .run = hantro_g1_mpeg2_dec_run,
+ .reset = rk3066_vpu_dec_reset,
+ .init = hantro_mpeg2_dec_init,
+ .exit = hantro_mpeg2_dec_exit,
+ },
+ [HANTRO_MODE_VP8_DEC] = {
+ .run = hantro_g1_vp8_dec_run,
+ .reset = rk3066_vpu_dec_reset,
+ .init = hantro_vp8_dec_init,
+ .exit = hantro_vp8_dec_exit,
+ },
+};
+
+static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = {
+ [HANTRO_MODE_JPEG_ENC] = {
+ .run = hantro_h1_jpeg_enc_run,
+ .reset = rockchip_vpu1_enc_reset,
+ .init = hantro_jpeg_enc_init,
+ .done = hantro_jpeg_enc_done,
+ .exit = hantro_jpeg_enc_exit,
+ },
+ [HANTRO_MODE_H264_DEC] = {
+ .run = hantro_g1_h264_dec_run,
+ .reset = hantro_g1_reset,
+ .init = hantro_h264_dec_init,
+ .exit = hantro_h264_dec_exit,
+ },
+ [HANTRO_MODE_MPEG2_DEC] = {
+ .run = hantro_g1_mpeg2_dec_run,
+ .reset = hantro_g1_reset,
+ .init = hantro_mpeg2_dec_init,
+ .exit = hantro_mpeg2_dec_exit,
+ },
+ [HANTRO_MODE_VP8_DEC] = {
+ .run = hantro_g1_vp8_dec_run,
+ .reset = hantro_g1_reset,
+ .init = hantro_vp8_dec_init,
+ .exit = hantro_vp8_dec_exit,
+ },
+};
+
+static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = {
+ [HANTRO_MODE_JPEG_ENC] = {
+ .run = rockchip_vpu2_jpeg_enc_run,
+ .reset = rockchip_vpu2_enc_reset,
+ .init = hantro_jpeg_enc_init,
+ .exit = hantro_jpeg_enc_exit,
+ },
+ [HANTRO_MODE_MPEG2_DEC] = {
+ .run = rockchip_vpu2_mpeg2_dec_run,
+ .reset = rockchip_vpu2_dec_reset,
+ .init = hantro_mpeg2_dec_init,
+ .exit = hantro_mpeg2_dec_exit,
+ },
+ [HANTRO_MODE_VP8_DEC] = {
+ .run = rockchip_vpu2_vp8_dec_run,
+ .reset = rockchip_vpu2_dec_reset,
+ .init = hantro_vp8_dec_init,
+ .exit = hantro_vp8_dec_exit,
+ },
+};
+
+/*
+ * VPU variant.
+ */
+
+static const struct hantro_irq rockchip_vdpu1_irqs[] = {
+ { "vdpu", hantro_g1_irq },
+};
+
+static const struct hantro_irq rockchip_vpu1_irqs[] = {
+ { "vepu", rockchip_vpu1_vepu_irq },
+ { "vdpu", hantro_g1_irq },
+};
+
+static const struct hantro_irq rockchip_vdpu2_irqs[] = {
+ { "vdpu", rockchip_vpu2_vdpu_irq },
+};
+
+static const struct hantro_irq rockchip_vpu2_irqs[] = {
+ { "vepu", rockchip_vpu2_vepu_irq },
+ { "vdpu", rockchip_vpu2_vdpu_irq },
+};
+
+static const char * const rk3066_vpu_clk_names[] = {
+ "aclk_vdpu", "hclk_vdpu",
+ "aclk_vepu", "hclk_vepu"
+};
+
+static const char * const rockchip_vpu_clk_names[] = {
+ "aclk", "hclk"
+};
+
+const struct hantro_variant rk3036_vpu_variant = {
+ .dec_offset = 0x400,
+ .dec_fmts = rk3066_vpu_dec_fmts,
+ .num_dec_fmts = ARRAY_SIZE(rk3066_vpu_dec_fmts),
+ .postproc_fmts = rockchip_vpu1_postproc_fmts,
+ .num_postproc_fmts = ARRAY_SIZE(rockchip_vpu1_postproc_fmts),
+ .postproc_regs = &hantro_g1_postproc_regs,
+ .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER |
+ HANTRO_H264_DECODER,
+ .codec_ops = rk3036_vpu_codec_ops,
+ .irqs = rockchip_vdpu1_irqs,
+ .num_irqs = ARRAY_SIZE(rockchip_vdpu1_irqs),
+ .init = rk3036_vpu_hw_init,
+ .clk_names = rockchip_vpu_clk_names,
+ .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names)
+};
+
+/*
+ * Despite this variant has separate clocks for decoder and encoder,
+ * it's still required to enable all four of them for either decoding
+ * or encoding and we can't split it in separate g1/h1 variants.
+ */
+const struct hantro_variant rk3066_vpu_variant = {
+ .enc_offset = 0x0,
+ .enc_fmts = rockchip_vpu_enc_fmts,
+ .num_enc_fmts = ARRAY_SIZE(rockchip_vpu_enc_fmts),
+ .dec_offset = 0x400,
+ .dec_fmts = rk3066_vpu_dec_fmts,
+ .num_dec_fmts = ARRAY_SIZE(rk3066_vpu_dec_fmts),
+ .postproc_fmts = rockchip_vpu1_postproc_fmts,
+ .num_postproc_fmts = ARRAY_SIZE(rockchip_vpu1_postproc_fmts),
+ .postproc_regs = &hantro_g1_postproc_regs,
+ .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER |
+ HANTRO_VP8_DECODER | HANTRO_H264_DECODER,
+ .codec_ops = rk3066_vpu_codec_ops,
+ .irqs = rockchip_vpu1_irqs,
+ .num_irqs = ARRAY_SIZE(rockchip_vpu1_irqs),
+ .init = rk3066_vpu_hw_init,
+ .clk_names = rk3066_vpu_clk_names,
+ .num_clocks = ARRAY_SIZE(rk3066_vpu_clk_names)
+};
+
+const struct hantro_variant rk3288_vpu_variant = {
+ .enc_offset = 0x0,
+ .enc_fmts = rockchip_vpu_enc_fmts,
+ .num_enc_fmts = ARRAY_SIZE(rockchip_vpu_enc_fmts),
+ .dec_offset = 0x400,
+ .dec_fmts = rk3288_vpu_dec_fmts,
+ .num_dec_fmts = ARRAY_SIZE(rk3288_vpu_dec_fmts),
+ .postproc_fmts = rockchip_vpu1_postproc_fmts,
+ .num_postproc_fmts = ARRAY_SIZE(rockchip_vpu1_postproc_fmts),
+ .postproc_regs = &hantro_g1_postproc_regs,
+ .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER |
+ HANTRO_VP8_DECODER | HANTRO_H264_DECODER,
+ .codec_ops = rk3288_vpu_codec_ops,
+ .irqs = rockchip_vpu1_irqs,
+ .num_irqs = ARRAY_SIZE(rockchip_vpu1_irqs),
+ .init = rockchip_vpu_hw_init,
+ .clk_names = rockchip_vpu_clk_names,
+ .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names)
+};
+
+const struct hantro_variant rk3328_vpu_variant = {
+ .dec_offset = 0x400,
+ .dec_fmts = rk3399_vpu_dec_fmts,
+ .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts),
+ .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER,
+ .codec_ops = rk3399_vpu_codec_ops,
+ .irqs = rockchip_vdpu2_irqs,
+ .num_irqs = ARRAY_SIZE(rockchip_vdpu2_irqs),
+ .init = rockchip_vpu_hw_init,
+ .clk_names = rockchip_vpu_clk_names,
+ .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names),
+};
+
+const struct hantro_variant rk3399_vpu_variant = {
+ .enc_offset = 0x0,
+ .enc_fmts = rockchip_vpu_enc_fmts,
+ .num_enc_fmts = ARRAY_SIZE(rockchip_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 |
+ HANTRO_VP8_DECODER,
+ .codec_ops = rk3399_vpu_codec_ops,
+ .irqs = rockchip_vpu2_irqs,
+ .num_irqs = ARRAY_SIZE(rockchip_vpu2_irqs),
+ .init = rockchip_vpu_hw_init,
+ .clk_names = rockchip_vpu_clk_names,
+ .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names)
+};
diff --git a/drivers/staging/media/hantro/sama5d4_vdec_hw.c b/drivers/staging/media/hantro/sama5d4_vdec_hw.c
new file mode 100644
index 000000000000..58ae72c2b723
--- /dev/null
+++ b/drivers/staging/media/hantro/sama5d4_vdec_hw.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VDEC driver
+ *
+ * Copyright (C) 2021 Collabora Ltd, Emil Velikov <emil.velikov@collabora.com>
+ */
+
+#include "hantro.h"
+
+/*
+ * Supported formats.
+ */
+
+static const struct hantro_fmt sama5d4_vdec_postproc_fmts[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .codec_mode = HANTRO_MODE_NONE,
+ },
+};
+
+static const struct hantro_fmt sama5d4_vdec_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 = 1280,
+ .step_width = MB_DIM,
+ .min_height = 48,
+ .max_height = 720,
+ .step_height = MB_DIM,
+ },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_VP8_FRAME,
+ .codec_mode = HANTRO_MODE_VP8_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 1280,
+ .step_width = MB_DIM,
+ .min_height = 48,
+ .max_height = 720,
+ .step_height = MB_DIM,
+ },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_H264_SLICE,
+ .codec_mode = HANTRO_MODE_H264_DEC,
+ .max_depth = 2,
+ .frmsize = {
+ .min_width = 48,
+ .max_width = 1280,
+ .step_width = MB_DIM,
+ .min_height = 48,
+ .max_height = 720,
+ .step_height = MB_DIM,
+ },
+ },
+};
+
+static int sama5d4_hw_init(struct hantro_dev *vpu)
+{
+ return 0;
+}
+
+/*
+ * Supported codec ops.
+ */
+
+static const struct hantro_codec_ops sama5d4_vdec_codec_ops[] = {
+ [HANTRO_MODE_MPEG2_DEC] = {
+ .run = hantro_g1_mpeg2_dec_run,
+ .reset = hantro_g1_reset,
+ .init = hantro_mpeg2_dec_init,
+ .exit = hantro_mpeg2_dec_exit,
+ },
+ [HANTRO_MODE_VP8_DEC] = {
+ .run = hantro_g1_vp8_dec_run,
+ .reset = hantro_g1_reset,
+ .init = hantro_vp8_dec_init,
+ .exit = hantro_vp8_dec_exit,
+ },
+ [HANTRO_MODE_H264_DEC] = {
+ .run = hantro_g1_h264_dec_run,
+ .reset = hantro_g1_reset,
+ .init = hantro_h264_dec_init,
+ .exit = hantro_h264_dec_exit,
+ },
+};
+
+static const struct hantro_irq sama5d4_irqs[] = {
+ { "vdec", hantro_g1_irq },
+};
+
+static const char * const sama5d4_clk_names[] = { "vdec_clk" };
+
+const struct hantro_variant sama5d4_vdec_variant = {
+ .dec_fmts = sama5d4_vdec_fmts,
+ .num_dec_fmts = ARRAY_SIZE(sama5d4_vdec_fmts),
+ .postproc_fmts = sama5d4_vdec_postproc_fmts,
+ .num_postproc_fmts = ARRAY_SIZE(sama5d4_vdec_postproc_fmts),
+ .postproc_regs = &hantro_g1_postproc_regs,
+ .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER |
+ HANTRO_H264_DECODER,
+ .codec_ops = sama5d4_vdec_codec_ops,
+ .init = sama5d4_hw_init,
+ .irqs = sama5d4_irqs,
+ .num_irqs = ARRAY_SIZE(sama5d4_irqs),
+ .clk_names = sama5d4_clk_names,
+ .num_clocks = ARRAY_SIZE(sama5d4_clk_names),
+};
diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c
index f21ed881295f..ac5fb332088e 100644
--- a/drivers/staging/media/imx/imx-ic-prp.c
+++ b/drivers/staging/media/imx/imx-ic-prp.c
@@ -79,13 +79,13 @@ static void prp_stop(struct prp_priv *priv)
}
static struct v4l2_mbus_framefmt *
-__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_pad_config *cfg,
+__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
struct imx_ic_priv *ic_priv = priv->ic_priv;
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&ic_priv->sd, cfg, pad);
+ return v4l2_subdev_get_try_format(&ic_priv->sd, sd_state, pad);
else
return &priv->format_mbus;
}
@@ -95,7 +95,7 @@ __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_pad_config *cfg,
*/
static int prp_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct prp_priv *priv = sd_to_priv(sd);
@@ -115,7 +115,8 @@ static int prp_enum_mbus_code(struct v4l2_subdev *sd,
ret = -EINVAL;
goto out;
}
- infmt = __prp_get_fmt(priv, cfg, PRP_SINK_PAD, code->which);
+ infmt = __prp_get_fmt(priv, sd_state, PRP_SINK_PAD,
+ code->which);
code->code = infmt->code;
break;
default:
@@ -127,7 +128,7 @@ out:
}
static int prp_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct prp_priv *priv = sd_to_priv(sd);
@@ -139,7 +140,7 @@ static int prp_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&priv->lock);
- fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+ fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
if (!fmt) {
ret = -EINVAL;
goto out;
@@ -152,7 +153,7 @@ out:
}
static int prp_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct prp_priv *priv = sd_to_priv(sd);
@@ -171,7 +172,7 @@ static int prp_set_fmt(struct v4l2_subdev *sd,
goto out;
}
- infmt = __prp_get_fmt(priv, cfg, PRP_SINK_PAD, sdformat->which);
+ infmt = __prp_get_fmt(priv, sd_state, PRP_SINK_PAD, sdformat->which);
switch (sdformat->pad) {
case PRP_SINK_PAD:
@@ -201,7 +202,7 @@ static int prp_set_fmt(struct v4l2_subdev *sd,
imx_media_try_colorimetry(&sdformat->format, true);
- fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+ fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
*fmt = sdformat->format;
out:
mutex_unlock(&priv->lock);
diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c
index d990553de87b..9b81cfbcd777 100644
--- a/drivers/staging/media/imx/imx-ic-prpencvf.c
+++ b/drivers/staging/media/imx/imx-ic-prpencvf.c
@@ -787,13 +787,13 @@ static void prp_stop(struct prp_priv *priv)
}
static struct v4l2_mbus_framefmt *
-__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_pad_config *cfg,
+__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
struct imx_ic_priv *ic_priv = priv->ic_priv;
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&ic_priv->sd, cfg, pad);
+ return v4l2_subdev_get_try_format(&ic_priv->sd, sd_state, pad);
else
return &priv->format_mbus[pad];
}
@@ -841,7 +841,7 @@ static bool prp_bound_align_output(struct v4l2_mbus_framefmt *outfmt,
*/
static int prp_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad >= PRPENCVF_NUM_PADS)
@@ -852,7 +852,7 @@ static int prp_enum_mbus_code(struct v4l2_subdev *sd,
}
static int prp_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct prp_priv *priv = sd_to_priv(sd);
@@ -864,7 +864,7 @@ static int prp_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&priv->lock);
- fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+ fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
if (!fmt) {
ret = -EINVAL;
goto out;
@@ -877,7 +877,7 @@ out:
}
static void prp_try_fmt(struct prp_priv *priv,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat,
const struct imx_media_pixfmt **cc)
{
@@ -894,7 +894,8 @@ static void prp_try_fmt(struct prp_priv *priv,
sdformat->format.code = (*cc)->codes[0];
}
- infmt = __prp_get_fmt(priv, cfg, PRPENCVF_SINK_PAD, sdformat->which);
+ infmt = __prp_get_fmt(priv, sd_state, PRPENCVF_SINK_PAD,
+ sdformat->which);
if (sdformat->pad == PRPENCVF_SRC_PAD) {
sdformat->format.field = infmt->field;
@@ -920,7 +921,7 @@ static void prp_try_fmt(struct prp_priv *priv,
}
static int prp_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct prp_priv *priv = sd_to_priv(sd);
@@ -938,9 +939,9 @@ static int prp_set_fmt(struct v4l2_subdev *sd,
goto out;
}
- prp_try_fmt(priv, cfg, sdformat, &cc);
+ prp_try_fmt(priv, sd_state, sdformat, &cc);
- fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+ fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
*fmt = sdformat->format;
/* propagate a default format to source pad */
@@ -952,9 +953,9 @@ static int prp_set_fmt(struct v4l2_subdev *sd,
format.pad = PRPENCVF_SRC_PAD;
format.which = sdformat->which;
format.format = sdformat->format;
- prp_try_fmt(priv, cfg, &format, &outcc);
+ prp_try_fmt(priv, sd_state, &format, &outcc);
- outfmt = __prp_get_fmt(priv, cfg, PRPENCVF_SRC_PAD,
+ outfmt = __prp_get_fmt(priv, sd_state, PRPENCVF_SRC_PAD,
sdformat->which);
*outfmt = format.format;
if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
@@ -970,7 +971,7 @@ out:
}
static int prp_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct prp_priv *priv = sd_to_priv(sd);
@@ -988,7 +989,7 @@ static int prp_enum_frame_size(struct v4l2_subdev *sd,
format.format.code = fse->code;
format.format.width = 1;
format.format.height = 1;
- prp_try_fmt(priv, cfg, &format, &cc);
+ prp_try_fmt(priv, sd_state, &format, &cc);
fse->min_width = format.format.width;
fse->min_height = format.format.height;
@@ -1000,7 +1001,7 @@ static int prp_enum_frame_size(struct v4l2_subdev *sd,
format.format.code = fse->code;
format.format.width = -1;
format.format.height = -1;
- prp_try_fmt(priv, cfg, &format, &cc);
+ prp_try_fmt(priv, sd_state, &format, &cc);
fse->max_width = format.format.width;
fse->max_height = format.format.height;
out:
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index e3bfd635a89a..bb1305c9daaf 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -750,9 +750,10 @@ static int csi_setup(struct csi_priv *priv)
static int csi_start(struct csi_priv *priv)
{
- struct v4l2_fract *output_fi;
+ struct v4l2_fract *input_fi, *output_fi;
int ret;
+ input_fi = &priv->frame_interval[CSI_SINK_PAD];
output_fi = &priv->frame_interval[priv->active_output_pad];
/* start upstream */
@@ -761,6 +762,17 @@ static int csi_start(struct csi_priv *priv)
if (ret)
return ret;
+ /* Skip first few frames from a BT.656 source */
+ if (priv->upstream_ep.bus_type == V4L2_MBUS_BT656) {
+ u32 delay_usec, bad_frames = 20;
+
+ delay_usec = DIV_ROUND_UP_ULL((u64)USEC_PER_SEC *
+ input_fi->numerator * bad_frames,
+ input_fi->denominator);
+
+ usleep_range(delay_usec, delay_usec + 1000);
+ }
+
if (priv->dest == IPU_CSI_DEST_IDMAC) {
ret = csi_idmac_start(priv);
if (ret)
@@ -1139,31 +1151,32 @@ static int csi_link_validate(struct v4l2_subdev *sd,
}
static struct v4l2_mbus_framefmt *
-__csi_get_fmt(struct csi_priv *priv, struct v4l2_subdev_pad_config *cfg,
+__csi_get_fmt(struct csi_priv *priv, struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&priv->sd, cfg, pad);
+ return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad);
else
return &priv->format_mbus[pad];
}
static struct v4l2_rect *
-__csi_get_crop(struct csi_priv *priv, struct v4l2_subdev_pad_config *cfg,
+__csi_get_crop(struct csi_priv *priv, struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&priv->sd, cfg, CSI_SINK_PAD);
+ return v4l2_subdev_get_try_crop(&priv->sd, sd_state,
+ CSI_SINK_PAD);
else
return &priv->crop;
}
static struct v4l2_rect *
-__csi_get_compose(struct csi_priv *priv, struct v4l2_subdev_pad_config *cfg,
+__csi_get_compose(struct csi_priv *priv, struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_compose(&priv->sd, cfg,
+ return v4l2_subdev_get_try_compose(&priv->sd, sd_state,
CSI_SINK_PAD);
else
return &priv->compose;
@@ -1171,7 +1184,7 @@ __csi_get_compose(struct csi_priv *priv, struct v4l2_subdev_pad_config *cfg,
static void csi_try_crop(struct csi_priv *priv,
struct v4l2_rect *crop,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_mbus_framefmt *infmt,
struct v4l2_fwnode_endpoint *upstream_ep)
{
@@ -1210,7 +1223,7 @@ static void csi_try_crop(struct csi_priv *priv,
}
static int csi_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1221,7 +1234,7 @@ static int csi_enum_mbus_code(struct v4l2_subdev *sd,
mutex_lock(&priv->lock);
- infmt = __csi_get_fmt(priv, cfg, CSI_SINK_PAD, code->which);
+ infmt = __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, code->which);
incc = imx_media_find_mbus_format(infmt->code, PIXFMT_SEL_ANY);
switch (code->pad) {
@@ -1263,7 +1276,7 @@ out:
}
static int csi_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1282,7 +1295,7 @@ static int csi_enum_frame_size(struct v4l2_subdev *sd,
fse->min_height = MIN_H;
fse->max_height = MAX_H;
} else {
- crop = __csi_get_crop(priv, cfg, fse->which);
+ crop = __csi_get_crop(priv, sd_state, fse->which);
fse->min_width = fse->index & 1 ?
crop->width / 2 : crop->width;
@@ -1297,7 +1310,7 @@ static int csi_enum_frame_size(struct v4l2_subdev *sd,
}
static int csi_enum_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1313,7 +1326,7 @@ static int csi_enum_frame_interval(struct v4l2_subdev *sd,
mutex_lock(&priv->lock);
input_fi = &priv->frame_interval[CSI_SINK_PAD];
- crop = __csi_get_crop(priv, cfg, fie->which);
+ crop = __csi_get_crop(priv, sd_state, fie->which);
if ((fie->width != crop->width && fie->width != crop->width / 2) ||
(fie->height != crop->height && fie->height != crop->height / 2)) {
@@ -1333,7 +1346,7 @@ out:
}
static int csi_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1345,7 +1358,7 @@ static int csi_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&priv->lock);
- fmt = __csi_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+ fmt = __csi_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
if (!fmt) {
ret = -EINVAL;
goto out;
@@ -1358,11 +1371,11 @@ out:
}
static void csi_try_field(struct csi_priv *priv,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct v4l2_mbus_framefmt *infmt =
- __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sdformat->which);
+ __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, sdformat->which);
/*
* no restrictions on sink pad field type except must
@@ -1408,7 +1421,7 @@ static void csi_try_field(struct csi_priv *priv,
static void csi_try_fmt(struct csi_priv *priv,
struct v4l2_fwnode_endpoint *upstream_ep,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat,
struct v4l2_rect *crop,
struct v4l2_rect *compose,
@@ -1418,7 +1431,7 @@ static void csi_try_fmt(struct csi_priv *priv,
struct v4l2_mbus_framefmt *infmt;
u32 code;
- infmt = __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sdformat->which);
+ infmt = __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, sdformat->which);
switch (sdformat->pad) {
case CSI_SRC_PAD_DIRECT:
@@ -1445,7 +1458,7 @@ static void csi_try_fmt(struct csi_priv *priv,
}
}
- csi_try_field(priv, cfg, sdformat);
+ csi_try_field(priv, sd_state, sdformat);
/* propagate colorimetry from sink */
sdformat->format.colorspace = infmt->colorspace;
@@ -1469,7 +1482,7 @@ static void csi_try_fmt(struct csi_priv *priv,
sdformat->format.code = (*cc)->codes[0];
}
- csi_try_field(priv, cfg, sdformat);
+ csi_try_field(priv, sd_state, sdformat);
/* Reset crop and compose rectangles */
crop->left = 0;
@@ -1478,7 +1491,8 @@ static void csi_try_fmt(struct csi_priv *priv,
crop->height = sdformat->format.height;
if (sdformat->format.field == V4L2_FIELD_ALTERNATE)
crop->height *= 2;
- csi_try_crop(priv, crop, cfg, &sdformat->format, upstream_ep);
+ csi_try_crop(priv, crop, sd_state, &sdformat->format,
+ upstream_ep);
compose->left = 0;
compose->top = 0;
compose->width = crop->width;
@@ -1492,7 +1506,7 @@ static void csi_try_fmt(struct csi_priv *priv,
}
static int csi_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1518,12 +1532,13 @@ static int csi_set_fmt(struct v4l2_subdev *sd,
goto out;
}
- crop = __csi_get_crop(priv, cfg, sdformat->which);
- compose = __csi_get_compose(priv, cfg, sdformat->which);
+ crop = __csi_get_crop(priv, sd_state, sdformat->which);
+ compose = __csi_get_compose(priv, sd_state, sdformat->which);
- csi_try_fmt(priv, &upstream_ep, cfg, sdformat, crop, compose, &cc);
+ csi_try_fmt(priv, &upstream_ep, sd_state, sdformat, crop, compose,
+ &cc);
- fmt = __csi_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+ fmt = __csi_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
*fmt = sdformat->format;
if (sdformat->pad == CSI_SINK_PAD) {
@@ -1538,10 +1553,11 @@ static int csi_set_fmt(struct v4l2_subdev *sd,
format.pad = pad;
format.which = sdformat->which;
format.format = sdformat->format;
- csi_try_fmt(priv, &upstream_ep, cfg, &format,
+ csi_try_fmt(priv, &upstream_ep, sd_state, &format,
NULL, compose, &outcc);
- outfmt = __csi_get_fmt(priv, cfg, pad, sdformat->which);
+ outfmt = __csi_get_fmt(priv, sd_state, pad,
+ sdformat->which);
*outfmt = format.format;
if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
@@ -1558,7 +1574,7 @@ out:
}
static int csi_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1571,9 +1587,9 @@ static int csi_get_selection(struct v4l2_subdev *sd,
mutex_lock(&priv->lock);
- infmt = __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sel->which);
- crop = __csi_get_crop(priv, cfg, sel->which);
- compose = __csi_get_compose(priv, cfg, sel->which);
+ infmt = __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, sel->which);
+ crop = __csi_get_crop(priv, sd_state, sel->which);
+ compose = __csi_get_compose(priv, sd_state, sel->which);
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
@@ -1622,7 +1638,7 @@ static int csi_set_scale(u32 *compose, u32 crop, u32 flags)
}
static int csi_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
@@ -1647,9 +1663,9 @@ static int csi_set_selection(struct v4l2_subdev *sd,
goto out;
}
- infmt = __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sel->which);
- crop = __csi_get_crop(priv, cfg, sel->which);
- compose = __csi_get_compose(priv, cfg, sel->which);
+ infmt = __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, sel->which);
+ crop = __csi_get_crop(priv, sd_state, sel->which);
+ compose = __csi_get_compose(priv, sd_state, sel->which);
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
@@ -1665,7 +1681,7 @@ static int csi_set_selection(struct v4l2_subdev *sd,
goto out;
}
- csi_try_crop(priv, &sel->r, cfg, infmt, &upstream_ep);
+ csi_try_crop(priv, &sel->r, sd_state, infmt, &upstream_ep);
*crop = sel->r;
@@ -1706,7 +1722,7 @@ static int csi_set_selection(struct v4l2_subdev *sd,
for (pad = CSI_SINK_PAD + 1; pad < CSI_NUM_PADS; pad++) {
struct v4l2_mbus_framefmt *outfmt;
- outfmt = __csi_get_fmt(priv, cfg, pad, sel->which);
+ outfmt = __csi_get_fmt(priv, sd_state, pad, sel->which);
outfmt->width = compose->width;
outfmt->height = compose->height;
}
diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
index 5128915a5d6f..6f90acf9c725 100644
--- a/drivers/staging/media/imx/imx-media-utils.c
+++ b/drivers/staging/media/imx/imx-media-utils.c
@@ -429,7 +429,7 @@ EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
* of a subdev. Can be used as the .init_cfg pad operation.
*/
int imx_media_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *mf_try;
struct v4l2_subdev_format format;
@@ -445,7 +445,7 @@ int imx_media_init_cfg(struct v4l2_subdev *sd,
if (ret)
continue;
- mf_try = v4l2_subdev_get_try_format(sd, cfg, pad);
+ mf_try = v4l2_subdev_get_try_format(sd, sd_state, pad);
*mf_try = format.format;
}
diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c
index abf290bda98d..3c2093c520ba 100644
--- a/drivers/staging/media/imx/imx-media-vdic.c
+++ b/drivers/staging/media/imx/imx-media-vdic.c
@@ -532,17 +532,17 @@ out:
}
static struct v4l2_mbus_framefmt *
-__vdic_get_fmt(struct vdic_priv *priv, struct v4l2_subdev_pad_config *cfg,
+__vdic_get_fmt(struct vdic_priv *priv, struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&priv->sd, cfg, pad);
+ return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad);
else
return &priv->format_mbus[pad];
}
static int vdic_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad >= VDIC_NUM_PADS)
@@ -553,7 +553,7 @@ static int vdic_enum_mbus_code(struct v4l2_subdev *sd,
}
static int vdic_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct vdic_priv *priv = v4l2_get_subdevdata(sd);
@@ -565,7 +565,7 @@ static int vdic_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&priv->lock);
- fmt = __vdic_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+ fmt = __vdic_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
if (!fmt) {
ret = -EINVAL;
goto out;
@@ -578,7 +578,7 @@ out:
}
static void vdic_try_fmt(struct vdic_priv *priv,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat,
const struct imx_media_pixfmt **cc)
{
@@ -594,7 +594,7 @@ static void vdic_try_fmt(struct vdic_priv *priv,
sdformat->format.code = (*cc)->codes[0];
}
- infmt = __vdic_get_fmt(priv, cfg, priv->active_input_pad,
+ infmt = __vdic_get_fmt(priv, sd_state, priv->active_input_pad,
sdformat->which);
switch (sdformat->pad) {
@@ -620,7 +620,7 @@ static void vdic_try_fmt(struct vdic_priv *priv,
}
static int vdic_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct vdic_priv *priv = v4l2_get_subdevdata(sd);
@@ -638,9 +638,9 @@ static int vdic_set_fmt(struct v4l2_subdev *sd,
goto out;
}
- vdic_try_fmt(priv, cfg, sdformat, &cc);
+ vdic_try_fmt(priv, sd_state, sdformat, &cc);
- fmt = __vdic_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
+ fmt = __vdic_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
*fmt = sdformat->format;
/* propagate format to source pad */
@@ -653,9 +653,9 @@ static int vdic_set_fmt(struct v4l2_subdev *sd,
format.pad = VDIC_SRC_PAD_DIRECT;
format.which = sdformat->which;
format.format = sdformat->format;
- vdic_try_fmt(priv, cfg, &format, &outcc);
+ vdic_try_fmt(priv, sd_state, &format, &outcc);
- outfmt = __vdic_get_fmt(priv, cfg, VDIC_SRC_PAD_DIRECT,
+ outfmt = __vdic_get_fmt(priv, sd_state, VDIC_SRC_PAD_DIRECT,
sdformat->which);
*outfmt = format.format;
if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
index 492d9a64e704..6740e7917458 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -193,7 +193,7 @@ int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
u32 width, u32 height, u32 code, u32 field,
const struct imx_media_pixfmt **cc);
int imx_media_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg);
+ struct v4l2_subdev_state *sd_state);
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,
diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c
index fc2378ac04b7..9de0ebd439dc 100644
--- a/drivers/staging/media/imx/imx6-mipi-csi2.c
+++ b/drivers/staging/media/imx/imx6-mipi-csi2.c
@@ -508,17 +508,17 @@ out:
}
static struct v4l2_mbus_framefmt *
-__csi2_get_fmt(struct csi2_dev *csi2, struct v4l2_subdev_pad_config *cfg,
+__csi2_get_fmt(struct csi2_dev *csi2, struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csi2->sd, cfg, pad);
+ return v4l2_subdev_get_try_format(&csi2->sd, sd_state, pad);
else
return &csi2->format_mbus;
}
static int csi2_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct csi2_dev *csi2 = sd_to_dev(sd);
@@ -526,7 +526,7 @@ static int csi2_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&csi2->lock);
- fmt = __csi2_get_fmt(csi2, cfg, sdformat->pad, sdformat->which);
+ fmt = __csi2_get_fmt(csi2, sd_state, sdformat->pad, sdformat->which);
sdformat->format = *fmt;
@@ -536,7 +536,7 @@ static int csi2_get_fmt(struct v4l2_subdev *sd,
}
static int csi2_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct csi2_dev *csi2 = sd_to_dev(sd);
@@ -557,7 +557,7 @@ static int csi2_set_fmt(struct v4l2_subdev *sd,
if (sdformat->pad != CSI2_SINK_PAD)
sdformat->format = csi2->format_mbus;
- fmt = __csi2_get_fmt(csi2, cfg, sdformat->pad, sdformat->which);
+ fmt = __csi2_get_fmt(csi2, sd_state, sdformat->pad, sdformat->which);
*fmt = sdformat->format;
out:
diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c
index f85a2f5f1413..894c4de31790 100644
--- a/drivers/staging/media/imx/imx7-media-csi.c
+++ b/drivers/staging/media/imx/imx7-media-csi.c
@@ -724,7 +724,7 @@ out_unlock:
}
static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg)
+ struct v4l2_subdev_state *sd_state)
{
struct imx7_csi *csi = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf;
@@ -732,7 +732,7 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
int i;
for (i = 0; i < IMX7_CSI_PADS_NUM; i++) {
- mf = v4l2_subdev_get_try_format(sd, cfg, i);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, i);
ret = imx_media_init_mbus_fmt(mf, 800, 600, 0, V4L2_FIELD_NONE,
&csi->cc[i]);
@@ -745,18 +745,18 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
static struct v4l2_mbus_framefmt *
imx7_csi_get_format(struct imx7_csi *csi,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csi->sd, cfg, pad);
+ return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad);
return &csi->format_mbus[pad];
}
static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct imx7_csi *csi = v4l2_get_subdevdata(sd);
@@ -765,7 +765,8 @@ static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd,
mutex_lock(&csi->lock);
- in_fmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SINK, code->which);
+ in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK,
+ code->which);
switch (code->pad) {
case IMX7_CSI_PAD_SINK:
@@ -791,7 +792,7 @@ out_unlock:
}
static int imx7_csi_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct imx7_csi *csi = v4l2_get_subdevdata(sd);
@@ -800,7 +801,8 @@ static int imx7_csi_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&csi->lock);
- fmt = imx7_csi_get_format(csi, cfg, sdformat->pad, sdformat->which);
+ fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad,
+ sdformat->which);
if (!fmt) {
ret = -EINVAL;
goto out_unlock;
@@ -815,7 +817,7 @@ out_unlock:
}
static int imx7_csi_try_fmt(struct imx7_csi *csi,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat,
const struct imx_media_pixfmt **cc)
{
@@ -823,7 +825,7 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi,
struct v4l2_mbus_framefmt *in_fmt;
u32 code;
- in_fmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SINK,
+ in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK,
sdformat->which);
if (!in_fmt)
return -EINVAL;
@@ -868,7 +870,7 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi,
}
static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
struct imx7_csi *csi = v4l2_get_subdevdata(sd);
@@ -889,11 +891,12 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
goto out_unlock;
}
- ret = imx7_csi_try_fmt(csi, cfg, sdformat, &cc);
+ ret = imx7_csi_try_fmt(csi, sd_state, sdformat, &cc);
if (ret < 0)
goto out_unlock;
- fmt = imx7_csi_get_format(csi, cfg, sdformat->pad, sdformat->which);
+ fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad,
+ sdformat->which);
if (!fmt) {
ret = -EINVAL;
goto out_unlock;
@@ -906,11 +909,11 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
format.pad = IMX7_CSI_PAD_SRC;
format.which = sdformat->which;
format.format = sdformat->format;
- if (imx7_csi_try_fmt(csi, cfg, &format, &outcc)) {
+ if (imx7_csi_try_fmt(csi, sd_state, &format, &outcc)) {
ret = -EINVAL;
goto out_unlock;
}
- outfmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SRC,
+ outfmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SRC,
sdformat->which);
*outfmt = format.format;
diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c
index 025fdc488bd6..ead696eb4610 100644
--- a/drivers/staging/media/imx/imx7-mipi-csis.c
+++ b/drivers/staging/media/imx/imx7-mipi-csis.c
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -166,15 +167,11 @@
#define MIPI_CSIS_ISP_CONFIG_CH(n) (0x40 + (n) * 0x10)
#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP_MSK (0xff << 24)
#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP(x) ((x) << 24)
-#define MIPI_CSIS_ISPCFG_DOUBLE_CMPNT BIT(12)
+#define MIPI_CSIS_ISPCFG_PIXEL_MODE_SINGLE (0 << 12)
+#define MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL (1 << 12)
+#define MIPI_CSIS_ISPCFG_PIXEL_MODE_QUAD (2 << 12) /* i.MX8M[MNP] only */
#define MIPI_CSIS_ISPCFG_ALIGN_32BIT BIT(11)
-#define MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT (0x1e << 2)
-#define MIPI_CSIS_ISPCFG_FMT_RAW8 (0x2a << 2)
-#define MIPI_CSIS_ISPCFG_FMT_RAW10 (0x2b << 2)
-#define MIPI_CSIS_ISPCFG_FMT_RAW12 (0x2c << 2)
-#define MIPI_CSIS_ISPCFG_FMT_RAW14 (0x2d << 2)
-/* User defined formats, x = 1...4 */
-#define MIPI_CSIS_ISPCFG_FMT_USER(x) ((0x30 + (x) - 1) << 2)
+#define MIPI_CSIS_ISPCFG_FMT(fmt) ((fmt) << 2)
#define MIPI_CSIS_ISPCFG_FMT_MASK (0x3f << 2)
/* ISP Image Resolution register */
@@ -195,6 +192,24 @@
/* Debug control register */
#define MIPI_CSIS_DBG_CTRL 0xc0
+#define MIPI_CSIS_DBG_INTR_MSK 0xc4
+#define MIPI_CSIS_DBG_INTR_MSK_DT_NOT_SUPPORT BIT(25)
+#define MIPI_CSIS_DBG_INTR_MSK_DT_IGNORE BIT(24)
+#define MIPI_CSIS_DBG_INTR_MSK_ERR_FRAME_SIZE BIT(20)
+#define MIPI_CSIS_DBG_INTR_MSK_TRUNCATED_FRAME BIT(16)
+#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FE BIT(12)
+#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FS BIT(8)
+#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_FALL BIT(4)
+#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_RISE BIT(0)
+#define MIPI_CSIS_DBG_INTR_SRC 0xc8
+#define MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT BIT(25)
+#define MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE BIT(24)
+#define MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE BIT(20)
+#define MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME BIT(16)
+#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FE BIT(12)
+#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FS BIT(8)
+#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL BIT(4)
+#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE BIT(0)
/* Non-image packet data buffers */
#define MIPI_CSIS_PKTDATA_ODD 0x2000
@@ -203,6 +218,25 @@
#define DEFAULT_SCLK_CSIS_FREQ 166000000UL
+/* MIPI CSI-2 Data Types */
+#define MIPI_CSI2_DATA_TYPE_YUV420_8 0x18
+#define MIPI_CSI2_DATA_TYPE_YUV420_10 0x19
+#define MIPI_CSI2_DATA_TYPE_LE_YUV420_8 0x1a
+#define MIPI_CSI2_DATA_TYPE_CS_YUV420_8 0x1c
+#define MIPI_CSI2_DATA_TYPE_CS_YUV420_10 0x1d
+#define MIPI_CSI2_DATA_TYPE_YUV422_8 0x1e
+#define MIPI_CSI2_DATA_TYPE_YUV422_10 0x1f
+#define MIPI_CSI2_DATA_TYPE_RGB565 0x22
+#define MIPI_CSI2_DATA_TYPE_RGB666 0x23
+#define MIPI_CSI2_DATA_TYPE_RGB888 0x24
+#define MIPI_CSI2_DATA_TYPE_RAW6 0x28
+#define MIPI_CSI2_DATA_TYPE_RAW7 0x29
+#define MIPI_CSI2_DATA_TYPE_RAW8 0x2a
+#define MIPI_CSI2_DATA_TYPE_RAW10 0x2b
+#define MIPI_CSI2_DATA_TYPE_RAW12 0x2c
+#define MIPI_CSI2_DATA_TYPE_RAW14 0x2d
+#define MIPI_CSI2_DATA_TYPE_USER(x) (0x30 + (x))
+
enum {
ST_POWERED = 1,
ST_STREAMING = 2,
@@ -210,6 +244,7 @@ enum {
};
struct mipi_csis_event {
+ bool debug;
u32 mask;
const char * const name;
unsigned int counter;
@@ -217,22 +252,30 @@ struct mipi_csis_event {
static const struct mipi_csis_event mipi_csis_events[] = {
/* Errors */
- { MIPI_CSIS_INT_SRC_ERR_SOT_HS, "SOT Error" },
- { MIPI_CSIS_INT_SRC_ERR_LOST_FS, "Lost Frame Start Error" },
- { MIPI_CSIS_INT_SRC_ERR_LOST_FE, "Lost Frame End Error" },
- { MIPI_CSIS_INT_SRC_ERR_OVER, "FIFO Overflow Error" },
- { MIPI_CSIS_INT_SRC_ERR_WRONG_CFG, "Wrong Configuration Error" },
- { MIPI_CSIS_INT_SRC_ERR_ECC, "ECC Error" },
- { MIPI_CSIS_INT_SRC_ERR_CRC, "CRC Error" },
- { MIPI_CSIS_INT_SRC_ERR_UNKNOWN, "Unknown Error" },
+ { false, MIPI_CSIS_INT_SRC_ERR_SOT_HS, "SOT Error" },
+ { false, MIPI_CSIS_INT_SRC_ERR_LOST_FS, "Lost Frame Start Error" },
+ { false, MIPI_CSIS_INT_SRC_ERR_LOST_FE, "Lost Frame End Error" },
+ { false, MIPI_CSIS_INT_SRC_ERR_OVER, "FIFO Overflow Error" },
+ { false, MIPI_CSIS_INT_SRC_ERR_WRONG_CFG, "Wrong Configuration Error" },
+ { false, MIPI_CSIS_INT_SRC_ERR_ECC, "ECC Error" },
+ { false, MIPI_CSIS_INT_SRC_ERR_CRC, "CRC Error" },
+ { false, MIPI_CSIS_INT_SRC_ERR_UNKNOWN, "Unknown Error" },
+ { true, MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT, "Data Type Not Supported" },
+ { true, MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE, "Data Type Ignored" },
+ { true, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE, "Frame Size Error" },
+ { true, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME, "Truncated Frame" },
+ { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE, "Early Frame End" },
+ { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS, "Early Frame Start" },
/* Non-image data receive events */
- { MIPI_CSIS_INT_SRC_EVEN_BEFORE, "Non-image data before even frame" },
- { MIPI_CSIS_INT_SRC_EVEN_AFTER, "Non-image data after even frame" },
- { MIPI_CSIS_INT_SRC_ODD_BEFORE, "Non-image data before odd frame" },
- { MIPI_CSIS_INT_SRC_ODD_AFTER, "Non-image data after odd frame" },
+ { false, MIPI_CSIS_INT_SRC_EVEN_BEFORE, "Non-image data before even frame" },
+ { false, MIPI_CSIS_INT_SRC_EVEN_AFTER, "Non-image data after even frame" },
+ { false, MIPI_CSIS_INT_SRC_ODD_BEFORE, "Non-image data before odd frame" },
+ { false, MIPI_CSIS_INT_SRC_ODD_AFTER, "Non-image data after odd frame" },
/* Frame start/end */
- { MIPI_CSIS_INT_SRC_FRAME_START, "Frame Start" },
- { MIPI_CSIS_INT_SRC_FRAME_END, "Frame End" },
+ { false, MIPI_CSIS_INT_SRC_FRAME_START, "Frame Start" },
+ { false, MIPI_CSIS_INT_SRC_FRAME_END, "Frame End" },
+ { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL, "VSYNC Falling Edge" },
+ { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE, "VSYNC Rising Edge" },
};
#define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events)
@@ -241,63 +284,63 @@ enum mipi_csis_clk {
MIPI_CSIS_CLK_PCLK,
MIPI_CSIS_CLK_WRAP,
MIPI_CSIS_CLK_PHY,
+ MIPI_CSIS_CLK_AXI,
};
static const char * const mipi_csis_clk_id[] = {
"pclk",
"wrap",
"phy",
+ "axi",
};
-struct csis_hw_reset {
- struct regmap *src;
- u8 req_src;
- u8 rst_bit;
+enum mipi_csis_version {
+ MIPI_CSIS_V3_3,
+ MIPI_CSIS_V3_6_3,
+};
+
+struct mipi_csis_info {
+ enum mipi_csis_version version;
+ unsigned int num_clocks;
};
struct csi_state {
- /* lock elements below */
- struct mutex lock;
- /* lock for event handler */
- spinlock_t slock;
struct device *dev;
+ void __iomem *regs;
+ struct clk_bulk_data *clks;
+ struct reset_control *mrst;
+ struct regulator *mipi_phy_regulator;
+ const struct mipi_csis_info *info;
+ u8 index;
+
+ struct v4l2_subdev sd;
struct media_pad pads[CSIS_PADS_NUM];
- struct v4l2_subdev mipi_sd;
struct v4l2_async_notifier notifier;
struct v4l2_subdev *src_sd;
- u8 index;
- struct platform_device *pdev;
- struct phy *phy;
- void __iomem *regs;
- int irq;
- u32 flags;
-
- struct dentry *debugfs_root;
- bool debug;
-
- int num_clks;
- struct clk_bulk_data *clks;
-
+ struct v4l2_fwnode_bus_mipi_csi2 bus;
u32 clk_frequency;
u32 hs_settle;
+ u32 clk_settle;
- struct reset_control *mrst;
-
+ struct mutex lock; /* Protect csis_fmt, format_mbus and state */
const struct csis_pix_format *csis_fmt;
struct v4l2_mbus_framefmt format_mbus;
+ u32 state;
- struct v4l2_fwnode_bus_mipi_csi2 bus;
-
+ spinlock_t slock; /* Protect events */
struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS];
-
- struct csis_hw_reset hw_reset;
- struct regulator *mipi_phy_regulator;
+ struct dentry *debugfs_root;
+ bool debug;
};
+/* -----------------------------------------------------------------------------
+ * Format helpers
+ */
+
struct csis_pix_format {
u32 code;
- u32 fmt_reg;
+ u32 data_type;
u8 width;
};
@@ -305,156 +348,117 @@ static const struct csis_pix_format mipi_csis_formats[] = {
/* YUV formats. */
{
.code = MEDIA_BUS_FMT_UYVY8_1X16,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT,
+ .data_type = MIPI_CSI2_DATA_TYPE_YUV422_8,
.width = 16,
},
/* RAW (Bayer and greyscale) formats. */
{
.code = MEDIA_BUS_FMT_SBGGR8_1X8,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW8,
.width = 8,
}, {
.code = MEDIA_BUS_FMT_SGBRG8_1X8,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW8,
.width = 8,
}, {
.code = MEDIA_BUS_FMT_SGRBG8_1X8,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW8,
.width = 8,
}, {
.code = MEDIA_BUS_FMT_SRGGB8_1X8,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW8,
.width = 8,
}, {
.code = MEDIA_BUS_FMT_Y8_1X8,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW8,
.width = 8,
}, {
.code = MEDIA_BUS_FMT_SBGGR10_1X10,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW10,
.width = 10,
}, {
.code = MEDIA_BUS_FMT_SGBRG10_1X10,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW10,
.width = 10,
}, {
.code = MEDIA_BUS_FMT_SGRBG10_1X10,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW10,
.width = 10,
}, {
.code = MEDIA_BUS_FMT_SRGGB10_1X10,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW10,
.width = 10,
}, {
.code = MEDIA_BUS_FMT_Y10_1X10,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW10,
.width = 10,
}, {
.code = MEDIA_BUS_FMT_SBGGR12_1X12,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW12,
.width = 12,
}, {
.code = MEDIA_BUS_FMT_SGBRG12_1X12,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW12,
.width = 12,
}, {
.code = MEDIA_BUS_FMT_SGRBG12_1X12,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW12,
.width = 12,
}, {
.code = MEDIA_BUS_FMT_SRGGB12_1X12,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW12,
.width = 12,
}, {
.code = MEDIA_BUS_FMT_Y12_1X12,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW12,
.width = 12,
}, {
.code = MEDIA_BUS_FMT_SBGGR14_1X14,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW14,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW14,
.width = 14,
}, {
.code = MEDIA_BUS_FMT_SGBRG14_1X14,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW14,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW14,
.width = 14,
}, {
.code = MEDIA_BUS_FMT_SGRBG14_1X14,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW14,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW14,
.width = 14,
}, {
.code = MEDIA_BUS_FMT_SRGGB14_1X14,
- .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW14,
+ .data_type = MIPI_CSI2_DATA_TYPE_RAW14,
.width = 14,
}
};
-static inline void mipi_csis_write(struct csi_state *state, u32 reg, u32 val)
-{
- writel(val, state->regs + reg);
-}
-
-static inline u32 mipi_csis_read(struct csi_state *state, u32 reg)
-{
- return readl(state->regs + reg);
-}
-
-static int mipi_csis_dump_regs(struct csi_state *state)
+static const struct csis_pix_format *find_csis_format(u32 code)
{
- struct device *dev = &state->pdev->dev;
unsigned int i;
- u32 cfg;
- static const struct {
- u32 offset;
- const char * const name;
- } registers[] = {
- { MIPI_CSIS_CMN_CTRL, "CMN_CTRL" },
- { MIPI_CSIS_CLK_CTRL, "CLK_CTRL" },
- { MIPI_CSIS_INT_MSK, "INT_MSK" },
- { MIPI_CSIS_DPHY_STATUS, "DPHY_STATUS" },
- { MIPI_CSIS_DPHY_CMN_CTRL, "DPHY_CMN_CTRL" },
- { MIPI_CSIS_DPHY_SCTRL_L, "DPHY_SCTRL_L" },
- { MIPI_CSIS_DPHY_SCTRL_H, "DPHY_SCTRL_H" },
- { MIPI_CSIS_ISP_CONFIG_CH(0), "ISP_CONFIG_CH0" },
- { MIPI_CSIS_ISP_RESOL_CH(0), "ISP_RESOL_CH0" },
- { MIPI_CSIS_SDW_CONFIG_CH(0), "SDW_CONFIG_CH0" },
- { MIPI_CSIS_SDW_RESOL_CH(0), "SDW_RESOL_CH0" },
- { MIPI_CSIS_DBG_CTRL, "DBG_CTRL" },
- };
- dev_info(dev, "--- REGISTERS ---\n");
-
- for (i = 0; i < ARRAY_SIZE(registers); i++) {
- cfg = mipi_csis_read(state, registers[i].offset);
- dev_info(dev, "%14s: 0x%08x\n", registers[i].name, cfg);
- }
-
- return 0;
+ for (i = 0; i < ARRAY_SIZE(mipi_csis_formats); i++)
+ if (code == mipi_csis_formats[i].code)
+ return &mipi_csis_formats[i];
+ return NULL;
}
-static struct csi_state *
-mipi_notifier_to_csis_state(struct v4l2_async_notifier *n)
-{
- return container_of(n, struct csi_state, notifier);
-}
+/* -----------------------------------------------------------------------------
+ * Hardware configuration
+ */
-static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev)
+static inline u32 mipi_csis_read(struct csi_state *state, u32 reg)
{
- return container_of(sdev, struct csi_state, mipi_sd);
+ return readl(state->regs + reg);
}
-static const struct csis_pix_format *find_csis_format(u32 code)
+static inline void mipi_csis_write(struct csi_state *state, u32 reg, u32 val)
{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(mipi_csis_formats); i++)
- if (code == mipi_csis_formats[i].code)
- return &mipi_csis_formats[i];
- return NULL;
+ writel(val, state->regs + reg);
}
static void mipi_csis_enable_interrupts(struct csi_state *state, bool on)
{
mipi_csis_write(state, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0);
+ mipi_csis_write(state, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0);
}
static void mipi_csis_sw_reset(struct csi_state *state)
@@ -466,25 +470,6 @@ static void mipi_csis_sw_reset(struct csi_state *state)
usleep_range(10, 20);
}
-static int mipi_csis_phy_init(struct csi_state *state)
-{
- state->mipi_phy_regulator = devm_regulator_get(state->dev, "phy");
- if (IS_ERR(state->mipi_phy_regulator))
- return PTR_ERR(state->mipi_phy_regulator);
-
- return regulator_set_voltage(state->mipi_phy_regulator, 1000000,
- 1000000);
-}
-
-static void mipi_csis_phy_reset(struct csi_state *state)
-{
- reset_control_assert(state->mrst);
-
- msleep(20);
-
- reset_control_deassert(state->mrst);
-}
-
static void mipi_csis_system_enable(struct csi_state *state, int on)
{
u32 val, mask;
@@ -514,7 +499,7 @@ static void __mipi_csis_set_format(struct csi_state *state)
/* Color format */
val = mipi_csis_read(state, MIPI_CSIS_ISP_CONFIG_CH(0));
val &= ~(MIPI_CSIS_ISPCFG_ALIGN_32BIT | MIPI_CSIS_ISPCFG_FMT_MASK);
- val |= state->csis_fmt->fmt_reg;
+ val |= MIPI_CSIS_ISPCFG_FMT(state->csis_fmt->data_type);
mipi_csis_write(state, MIPI_CSIS_ISP_CONFIG_CH(0), val);
/* Pixel resolution */
@@ -546,11 +531,15 @@ static int mipi_csis_calculate_params(struct csi_state *state)
/*
* The HSSETTLE counter value is document in a table, but can also
- * easily be calculated.
+ * easily be calculated. Hardcode the CLKSETTLE value to 0 for now
+ * (which is documented as corresponding to CSI-2 v0.87 to v1.00) until
+ * we figure out how to compute it correctly.
*/
state->hs_settle = (lane_rate - 5000000) / 45000000;
- dev_dbg(state->dev, "lane rate %u, Ths_settle %u\n",
- lane_rate, state->hs_settle);
+ state->clk_settle = 0;
+
+ dev_dbg(state->dev, "lane rate %u, Tclk_settle %u, Ths_settle %u\n",
+ lane_rate, state->clk_settle, state->hs_settle);
return 0;
}
@@ -563,13 +552,15 @@ static void mipi_csis_set_params(struct csi_state *state)
val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK;
val |= (lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET;
- val |= MIPI_CSIS_CMN_CTRL_INTER_MODE;
+ if (state->info->version == MIPI_CSIS_V3_3)
+ val |= MIPI_CSIS_CMN_CTRL_INTER_MODE;
mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val);
__mipi_csis_set_format(state);
mipi_csis_write(state, MIPI_CSIS_DPHY_CMN_CTRL,
- MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(state->hs_settle));
+ MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(state->hs_settle) |
+ MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(state->clk_settle));
val = (0 << MIPI_CSIS_ISP_SYNC_HSYNC_LINTV_OFFSET)
| (0 << MIPI_CSIS_ISP_SYNC_VSYNC_SINTV_OFFSET)
@@ -601,31 +592,30 @@ static void mipi_csis_set_params(struct csi_state *state)
static int mipi_csis_clk_enable(struct csi_state *state)
{
- return clk_bulk_prepare_enable(state->num_clks, state->clks);
+ return clk_bulk_prepare_enable(state->info->num_clocks, state->clks);
}
static void mipi_csis_clk_disable(struct csi_state *state)
{
- clk_bulk_disable_unprepare(state->num_clks, state->clks);
+ clk_bulk_disable_unprepare(state->info->num_clocks, state->clks);
}
static int mipi_csis_clk_get(struct csi_state *state)
{
- struct device *dev = &state->pdev->dev;
unsigned int i;
int ret;
- state->num_clks = ARRAY_SIZE(mipi_csis_clk_id);
- state->clks = devm_kcalloc(dev, state->num_clks, sizeof(*state->clks),
- GFP_KERNEL);
+ state->clks = devm_kcalloc(state->dev, state->info->num_clocks,
+ sizeof(*state->clks), GFP_KERNEL);
if (!state->clks)
return -ENOMEM;
- for (i = 0; i < state->num_clks; i++)
+ for (i = 0; i < state->info->num_clocks; i++)
state->clks[i].id = mipi_csis_clk_id[i];
- ret = devm_clk_bulk_get(dev, state->num_clks, state->clks);
+ ret = devm_clk_bulk_get(state->dev, state->info->num_clocks,
+ state->clks);
if (ret < 0)
return ret;
@@ -633,8 +623,8 @@ static int mipi_csis_clk_get(struct csi_state *state)
ret = clk_set_rate(state->clks[MIPI_CSIS_CLK_WRAP].clk,
state->clk_frequency);
if (ret < 0)
- dev_err(dev, "set rate=%d failed: %d\n", state->clk_frequency,
- ret);
+ dev_err(state->dev, "set rate=%d failed: %d\n",
+ state->clk_frequency, ret);
return ret;
}
@@ -653,6 +643,89 @@ static void mipi_csis_stop_stream(struct csi_state *state)
mipi_csis_system_enable(state, false);
}
+static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
+{
+ struct csi_state *state = dev_id;
+ unsigned long flags;
+ unsigned int i;
+ u32 status;
+ u32 dbg_status;
+
+ status = mipi_csis_read(state, MIPI_CSIS_INT_SRC);
+ dbg_status = mipi_csis_read(state, MIPI_CSIS_DBG_INTR_SRC);
+
+ spin_lock_irqsave(&state->slock, flags);
+
+ /* Update the event/error counters */
+ if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug) {
+ for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) {
+ struct mipi_csis_event *event = &state->events[i];
+
+ if ((!event->debug && (status & event->mask)) ||
+ (event->debug && (dbg_status & event->mask)))
+ event->counter++;
+ }
+ }
+ spin_unlock_irqrestore(&state->slock, flags);
+
+ mipi_csis_write(state, MIPI_CSIS_INT_SRC, status);
+ mipi_csis_write(state, MIPI_CSIS_DBG_INTR_SRC, dbg_status);
+
+ return IRQ_HANDLED;
+}
+
+/* -----------------------------------------------------------------------------
+ * PHY regulator and reset
+ */
+
+static int mipi_csis_phy_enable(struct csi_state *state)
+{
+ if (state->info->version != MIPI_CSIS_V3_3)
+ return 0;
+
+ return regulator_enable(state->mipi_phy_regulator);
+}
+
+static int mipi_csis_phy_disable(struct csi_state *state)
+{
+ if (state->info->version != MIPI_CSIS_V3_3)
+ return 0;
+
+ return regulator_disable(state->mipi_phy_regulator);
+}
+
+static void mipi_csis_phy_reset(struct csi_state *state)
+{
+ if (state->info->version != MIPI_CSIS_V3_3)
+ return;
+
+ reset_control_assert(state->mrst);
+ msleep(20);
+ reset_control_deassert(state->mrst);
+}
+
+static int mipi_csis_phy_init(struct csi_state *state)
+{
+ if (state->info->version != MIPI_CSIS_V3_3)
+ return 0;
+
+ /* Get MIPI PHY reset and regulator. */
+ state->mrst = devm_reset_control_get_exclusive(state->dev, NULL);
+ if (IS_ERR(state->mrst))
+ return PTR_ERR(state->mrst);
+
+ state->mipi_phy_regulator = devm_regulator_get(state->dev, "phy");
+ if (IS_ERR(state->mipi_phy_regulator))
+ return PTR_ERR(state->mipi_phy_regulator);
+
+ return regulator_set_voltage(state->mipi_phy_regulator, 1000000,
+ 1000000);
+}
+
+/* -----------------------------------------------------------------------------
+ * Debug
+ */
+
static void mipi_csis_clear_counters(struct csi_state *state)
{
unsigned long flags;
@@ -666,26 +739,90 @@ static void mipi_csis_clear_counters(struct csi_state *state)
static void mipi_csis_log_counters(struct csi_state *state, bool non_errors)
{
- int i = non_errors ? MIPI_CSIS_NUM_EVENTS : MIPI_CSIS_NUM_EVENTS - 4;
- struct device *dev = &state->pdev->dev;
+ unsigned int num_events = non_errors ? MIPI_CSIS_NUM_EVENTS
+ : MIPI_CSIS_NUM_EVENTS - 8;
unsigned long flags;
+ unsigned int i;
spin_lock_irqsave(&state->slock, flags);
- for (i--; i >= 0; i--) {
+ for (i = 0; i < num_events; ++i) {
if (state->events[i].counter > 0 || state->debug)
- dev_info(dev, "%s events: %d\n", state->events[i].name,
+ dev_info(state->dev, "%s events: %d\n",
+ state->events[i].name,
state->events[i].counter);
}
spin_unlock_irqrestore(&state->slock, flags);
}
-/*
+static int mipi_csis_dump_regs(struct csi_state *state)
+{
+ static const struct {
+ u32 offset;
+ const char * const name;
+ } registers[] = {
+ { MIPI_CSIS_CMN_CTRL, "CMN_CTRL" },
+ { MIPI_CSIS_CLK_CTRL, "CLK_CTRL" },
+ { MIPI_CSIS_INT_MSK, "INT_MSK" },
+ { MIPI_CSIS_DPHY_STATUS, "DPHY_STATUS" },
+ { MIPI_CSIS_DPHY_CMN_CTRL, "DPHY_CMN_CTRL" },
+ { MIPI_CSIS_DPHY_SCTRL_L, "DPHY_SCTRL_L" },
+ { MIPI_CSIS_DPHY_SCTRL_H, "DPHY_SCTRL_H" },
+ { MIPI_CSIS_ISP_CONFIG_CH(0), "ISP_CONFIG_CH0" },
+ { MIPI_CSIS_ISP_RESOL_CH(0), "ISP_RESOL_CH0" },
+ { MIPI_CSIS_SDW_CONFIG_CH(0), "SDW_CONFIG_CH0" },
+ { MIPI_CSIS_SDW_RESOL_CH(0), "SDW_RESOL_CH0" },
+ { MIPI_CSIS_DBG_CTRL, "DBG_CTRL" },
+ };
+
+ unsigned int i;
+ u32 cfg;
+
+ dev_info(state->dev, "--- REGISTERS ---\n");
+
+ for (i = 0; i < ARRAY_SIZE(registers); i++) {
+ cfg = mipi_csis_read(state, registers[i].offset);
+ dev_info(state->dev, "%14s: 0x%08x\n", registers[i].name, cfg);
+ }
+
+ return 0;
+}
+
+static int mipi_csis_dump_regs_show(struct seq_file *m, void *private)
+{
+ struct csi_state *state = m->private;
+
+ return mipi_csis_dump_regs(state);
+}
+DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs);
+
+static void mipi_csis_debugfs_init(struct csi_state *state)
+{
+ state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL);
+
+ debugfs_create_bool("debug_enable", 0600, state->debugfs_root,
+ &state->debug);
+ debugfs_create_file("dump_regs", 0600, state->debugfs_root, state,
+ &mipi_csis_dump_regs_fops);
+}
+
+static void mipi_csis_debugfs_exit(struct csi_state *state)
+{
+ debugfs_remove_recursive(state->debugfs_root);
+}
+
+/* -----------------------------------------------------------------------------
* V4L2 subdev operations
*/
-static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable)
+
+static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev)
{
- struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ return container_of(sdev, struct csi_state, sd);
+}
+
+static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct csi_state *state = mipi_sd_to_csis_state(sd);
int ret;
if (enable) {
@@ -695,11 +832,10 @@ static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable)
mipi_csis_clear_counters(state);
- ret = pm_runtime_get_sync(&state->pdev->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(&state->pdev->dev);
+ ret = pm_runtime_resume_and_get(state->dev);
+ if (ret < 0)
return ret;
- }
+
ret = v4l2_subdev_call(state->src_sd, core, s_power, 1);
if (ret < 0 && ret != -ENOIOCTLCMD)
goto done;
@@ -708,7 +844,7 @@ static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable)
mutex_lock(&state->lock);
if (enable) {
- if (state->flags & ST_SUSPENDED) {
+ if (state->state & ST_SUSPENDED) {
ret = -EBUSY;
goto unlock;
}
@@ -720,14 +856,14 @@ static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable)
mipi_csis_log_counters(state, true);
- state->flags |= ST_STREAMING;
+ state->state |= ST_STREAMING;
} else {
v4l2_subdev_call(state->src_sd, video, s_stream, 0);
ret = v4l2_subdev_call(state->src_sd, core, s_power, 0);
if (ret == -ENOIOCTLCMD)
ret = 0;
mipi_csis_stop_stream(state);
- state->flags &= ~ST_STREAMING;
+ state->state &= ~ST_STREAMING;
if (state->debug)
mipi_csis_log_counters(state, true);
}
@@ -737,62 +873,33 @@ unlock:
done:
if (!enable || ret < 0)
- pm_runtime_put(&state->pdev->dev);
+ pm_runtime_put(state->dev);
return ret;
}
-static int mipi_csis_link_setup(struct media_entity *entity,
- const struct media_pad *local_pad,
- const struct media_pad *remote_pad, u32 flags)
-{
- struct v4l2_subdev *mipi_sd = media_entity_to_v4l2_subdev(entity);
- struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
- struct v4l2_subdev *remote_sd;
-
- dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name,
- local_pad->entity->name);
-
- /* We only care about the link to the source. */
- if (!(local_pad->flags & MEDIA_PAD_FL_SINK))
- return 0;
-
- remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
-
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (state->src_sd)
- return -EBUSY;
-
- state->src_sd = remote_sd;
- } else {
- state->src_sd = NULL;
- }
-
- return 0;
-}
-
static struct v4l2_mbus_framefmt *
mipi_csis_get_format(struct csi_state *state,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which,
unsigned int pad)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&state->mipi_sd, cfg, pad);
+ return v4l2_subdev_get_try_format(&state->sd, sd_state, pad);
return &state->format_mbus;
}
-static int mipi_csis_init_cfg(struct v4l2_subdev *mipi_sd,
- struct v4l2_subdev_pad_config *cfg)
+static int mipi_csis_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
- struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ struct csi_state *state = mipi_sd_to_csis_state(sd);
struct v4l2_mbus_framefmt *fmt_sink;
struct v4l2_mbus_framefmt *fmt_source;
enum v4l2_subdev_format_whence which;
- which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt_sink = mipi_csis_get_format(state, cfg, which, CSIS_PAD_SINK);
+ which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ fmt_sink = mipi_csis_get_format(state, sd_state, which, CSIS_PAD_SINK);
fmt_sink->code = MEDIA_BUS_FMT_UYVY8_1X16;
fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH;
@@ -811,35 +918,38 @@ static int mipi_csis_init_cfg(struct v4l2_subdev *mipi_sd,
* configuration, cfg is NULL, which indicates there's no source pad
* configuration to set.
*/
- if (!cfg)
+ if (!sd_state)
return 0;
- fmt_source = mipi_csis_get_format(state, cfg, which, CSIS_PAD_SOURCE);
+ fmt_source = mipi_csis_get_format(state, sd_state, which,
+ CSIS_PAD_SOURCE);
*fmt_source = *fmt_sink;
return 0;
}
-static int mipi_csis_get_fmt(struct v4l2_subdev *mipi_sd,
- struct v4l2_subdev_pad_config *cfg,
+static int mipi_csis_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
- struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ struct csi_state *state = mipi_sd_to_csis_state(sd);
struct v4l2_mbus_framefmt *fmt;
+ fmt = mipi_csis_get_format(state, sd_state, sdformat->which,
+ sdformat->pad);
+
mutex_lock(&state->lock);
- fmt = mipi_csis_get_format(state, cfg, sdformat->which, sdformat->pad);
sdformat->format = *fmt;
mutex_unlock(&state->lock);
return 0;
}
-static int mipi_csis_enum_mbus_code(struct v4l2_subdev *mipi_sd,
- struct v4l2_subdev_pad_config *cfg,
+static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ struct csi_state *state = mipi_sd_to_csis_state(sd);
/*
* The CSIS can't transcode in any way, the source format is identical
@@ -851,7 +961,8 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *mipi_sd,
if (code->index > 0)
return -EINVAL;
- fmt = mipi_csis_get_format(state, cfg, code->which, code->pad);
+ fmt = mipi_csis_get_format(state, sd_state, code->which,
+ code->pad);
code->code = fmt->code;
return 0;
}
@@ -867,11 +978,11 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *mipi_sd,
return 0;
}
-static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd,
- struct v4l2_subdev_pad_config *cfg,
+static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
- struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ struct csi_state *state = mipi_sd_to_csis_state(sd);
struct csis_pix_format const *csis_fmt;
struct v4l2_mbus_framefmt *fmt;
unsigned int align;
@@ -881,29 +992,22 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd,
* modified.
*/
if (sdformat->pad == CSIS_PAD_SOURCE)
- return mipi_csis_get_fmt(mipi_sd, cfg, sdformat);
+ return mipi_csis_get_fmt(sd, sd_state, sdformat);
if (sdformat->pad != CSIS_PAD_SINK)
return -EINVAL;
- fmt = mipi_csis_get_format(state, cfg, sdformat->which, sdformat->pad);
-
- mutex_lock(&state->lock);
-
- /* Validate the media bus code and clamp the size. */
- csis_fmt = find_csis_format(sdformat->format.code);
- if (!csis_fmt)
- csis_fmt = &mipi_csis_formats[0];
-
- fmt->code = csis_fmt->code;
- fmt->width = sdformat->format.width;
- fmt->height = sdformat->format.height;
-
/*
+ * Validate the media bus code and clamp and align the size.
+ *
* The total number of bits per line must be a multiple of 8. We thus
* need to align the width for formats that are not multiples of 8
* bits.
*/
+ csis_fmt = find_csis_format(sdformat->format.code);
+ if (!csis_fmt)
+ csis_fmt = &mipi_csis_formats[0];
+
switch (csis_fmt->width % 8) {
case 0:
align = 0;
@@ -923,13 +1027,24 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd,
break;
}
- v4l_bound_align_image(&fmt->width, 1, CSIS_MAX_PIX_WIDTH, align,
- &fmt->height, 1, CSIS_MAX_PIX_HEIGHT, 0, 0);
+ v4l_bound_align_image(&sdformat->format.width, 1,
+ CSIS_MAX_PIX_WIDTH, align,
+ &sdformat->format.height, 1,
+ CSIS_MAX_PIX_HEIGHT, 0, 0);
+
+ fmt = mipi_csis_get_format(state, sd_state, sdformat->which,
+ sdformat->pad);
+
+ mutex_lock(&state->lock);
+
+ fmt->code = csis_fmt->code;
+ fmt->width = sdformat->format.width;
+ fmt->height = sdformat->format.height;
sdformat->format = *fmt;
/* Propagate the format from sink to source. */
- fmt = mipi_csis_get_format(state, cfg, sdformat->which,
+ fmt = mipi_csis_get_format(state, sd_state, sdformat->which,
CSIS_PAD_SOURCE);
*fmt = sdformat->format;
@@ -942,55 +1057,23 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd,
return 0;
}
-static int mipi_csis_log_status(struct v4l2_subdev *mipi_sd)
+static int mipi_csis_log_status(struct v4l2_subdev *sd)
{
- struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ struct csi_state *state = mipi_sd_to_csis_state(sd);
mutex_lock(&state->lock);
mipi_csis_log_counters(state, true);
- if (state->debug && (state->flags & ST_POWERED))
+ if (state->debug && (state->state & ST_POWERED))
mipi_csis_dump_regs(state);
mutex_unlock(&state->lock);
return 0;
}
-static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
-{
- struct csi_state *state = dev_id;
- unsigned long flags;
- unsigned int i;
- u32 status;
-
- status = mipi_csis_read(state, MIPI_CSIS_INT_SRC);
-
- spin_lock_irqsave(&state->slock, flags);
-
- /* Update the event/error counters */
- if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug) {
- for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) {
- if (!(status & state->events[i].mask))
- continue;
- state->events[i].counter++;
- }
- }
- spin_unlock_irqrestore(&state->slock, flags);
-
- mipi_csis_write(state, MIPI_CSIS_INT_SRC, status);
-
- return IRQ_HANDLED;
-}
-
static const struct v4l2_subdev_core_ops mipi_csis_core_ops = {
.log_status = mipi_csis_log_status,
};
-static const struct media_entity_operations mipi_csis_entity_ops = {
- .link_setup = mipi_csis_link_setup,
- .link_validate = v4l2_subdev_link_validate,
- .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
-};
-
static const struct v4l2_subdev_video_ops mipi_csis_video_ops = {
.s_stream = mipi_csis_s_stream,
};
@@ -1008,31 +1091,61 @@ static const struct v4l2_subdev_ops mipi_csis_subdev_ops = {
.pad = &mipi_csis_pad_ops,
};
-static int mipi_csis_parse_dt(struct platform_device *pdev,
- struct csi_state *state)
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+static int mipi_csis_link_setup(struct media_entity *entity,
+ const struct media_pad *local_pad,
+ const struct media_pad *remote_pad, u32 flags)
{
- struct device_node *node = pdev->dev.of_node;
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct csi_state *state = mipi_sd_to_csis_state(sd);
+ struct v4l2_subdev *remote_sd;
- if (of_property_read_u32(node, "clock-frequency",
- &state->clk_frequency))
- state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;
+ dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name,
+ local_pad->entity->name);
- /* Get MIPI PHY resets */
- state->mrst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
- if (IS_ERR(state->mrst))
- return PTR_ERR(state->mrst);
+ /* We only care about the link to the source. */
+ if (!(local_pad->flags & MEDIA_PAD_FL_SINK))
+ return 0;
+
+ remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (state->src_sd)
+ return -EBUSY;
+
+ state->src_sd = remote_sd;
+ } else {
+ state->src_sd = NULL;
+ }
return 0;
}
-static int mipi_csis_pm_resume(struct device *dev, bool runtime);
+static const struct media_entity_operations mipi_csis_entity_ops = {
+ .link_setup = mipi_csis_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
+ .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
+};
+
+/* -----------------------------------------------------------------------------
+ * Async subdev notifier
+ */
+
+static struct csi_state *
+mipi_notifier_to_csis_state(struct v4l2_async_notifier *n)
+{
+ return container_of(n, struct csi_state, notifier);
+}
static int mipi_csis_notify_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *sd,
struct v4l2_async_subdev *asd)
{
struct csi_state *state = mipi_notifier_to_csis_state(notifier);
- struct media_pad *sink = &state->mipi_sd.entity.pads[CSIS_PAD_SINK];
+ struct media_pad *sink = &state->sd.entity.pads[CSIS_PAD_SINK];
return v4l2_create_fwnode_links_to_pad(sd, sink, 0);
}
@@ -1041,38 +1154,6 @@ static const struct v4l2_async_notifier_operations mipi_csis_notify_ops = {
.bound = mipi_csis_notify_bound,
};
-static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd,
- struct platform_device *pdev,
- const struct v4l2_subdev_ops *ops)
-{
- struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
-
- v4l2_subdev_init(mipi_sd, ops);
- mipi_sd->owner = THIS_MODULE;
- snprintf(mipi_sd->name, sizeof(mipi_sd->name), "%s.%d",
- CSIS_SUBDEV_NAME, state->index);
-
- mipi_sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- mipi_sd->ctrl_handler = NULL;
-
- mipi_sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
- mipi_sd->entity.ops = &mipi_csis_entity_ops;
-
- mipi_sd->dev = &pdev->dev;
-
- state->csis_fmt = &mipi_csis_formats[0];
- mipi_csis_init_cfg(mipi_sd, NULL);
-
- v4l2_set_subdevdata(mipi_sd, &pdev->dev);
-
- state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK
- | MEDIA_PAD_FL_MUST_CONNECT;
- state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE
- | MEDIA_PAD_FL_MUST_CONNECT;
- return media_entity_pads_init(&mipi_sd->entity, CSIS_PADS_NUM,
- state->pads);
-}
-
static int mipi_csis_async_register(struct csi_state *state)
{
struct v4l2_fwnode_endpoint vep = {
@@ -1080,6 +1161,7 @@ static int mipi_csis_async_register(struct csi_state *state)
};
struct v4l2_async_subdev *asd;
struct fwnode_handle *ep;
+ unsigned int i;
int ret;
v4l2_async_notifier_init(&state->notifier);
@@ -1093,6 +1175,15 @@ static int mipi_csis_async_register(struct csi_state *state)
if (ret)
goto err_parse;
+ for (i = 0; i < vep.bus.mipi_csi2.num_data_lanes; ++i) {
+ if (vep.bus.mipi_csi2.data_lanes[i] != i + 1) {
+ dev_err(state->dev,
+ "data lanes reordering is not supported");
+ ret = -EINVAL;
+ goto err_parse;
+ }
+ }
+
state->bus = vep.bus.mipi_csi2;
dev_dbg(state->dev, "data lanes: %d\n", state->bus.num_data_lanes);
@@ -1109,12 +1200,11 @@ static int mipi_csis_async_register(struct csi_state *state)
state->notifier.ops = &mipi_csis_notify_ops;
- ret = v4l2_async_subdev_notifier_register(&state->mipi_sd,
- &state->notifier);
+ ret = v4l2_async_subdev_notifier_register(&state->sd, &state->notifier);
if (ret)
return ret;
- return v4l2_async_register_subdev(&state->mipi_sd);
+ return v4l2_async_register_subdev(&state->sd);
err_parse:
fwnode_handle_put(ep);
@@ -1122,98 +1212,209 @@ err_parse:
return ret;
}
-static int mipi_csis_dump_regs_show(struct seq_file *m, void *private)
+/* -----------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+static int mipi_csis_pm_suspend(struct device *dev, bool runtime)
{
- struct csi_state *state = m->private;
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct csi_state *state = mipi_sd_to_csis_state(sd);
+ int ret = 0;
- return mipi_csis_dump_regs(state);
+ mutex_lock(&state->lock);
+ if (state->state & ST_POWERED) {
+ mipi_csis_stop_stream(state);
+ ret = mipi_csis_phy_disable(state);
+ if (ret)
+ goto unlock;
+ mipi_csis_clk_disable(state);
+ state->state &= ~ST_POWERED;
+ if (!runtime)
+ state->state |= ST_SUSPENDED;
+ }
+
+unlock:
+ mutex_unlock(&state->lock);
+
+ return ret ? -EAGAIN : 0;
}
-DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs);
-static void mipi_csis_debugfs_init(struct csi_state *state)
+static int mipi_csis_pm_resume(struct device *dev, bool runtime)
{
- state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL);
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct csi_state *state = mipi_sd_to_csis_state(sd);
+ int ret = 0;
- debugfs_create_bool("debug_enable", 0600, state->debugfs_root,
- &state->debug);
- debugfs_create_file("dump_regs", 0600, state->debugfs_root, state,
- &mipi_csis_dump_regs_fops);
+ mutex_lock(&state->lock);
+ if (!runtime && !(state->state & ST_SUSPENDED))
+ goto unlock;
+
+ if (!(state->state & ST_POWERED)) {
+ ret = mipi_csis_phy_enable(state);
+ if (ret)
+ goto unlock;
+
+ state->state |= ST_POWERED;
+ mipi_csis_clk_enable(state);
+ }
+ if (state->state & ST_STREAMING)
+ mipi_csis_start_stream(state);
+
+ state->state &= ~ST_SUSPENDED;
+
+unlock:
+ mutex_unlock(&state->lock);
+
+ return ret ? -EAGAIN : 0;
}
-static void mipi_csis_debugfs_exit(struct csi_state *state)
+static int __maybe_unused mipi_csis_suspend(struct device *dev)
{
- debugfs_remove_recursive(state->debugfs_root);
+ return mipi_csis_pm_suspend(dev, false);
+}
+
+static int __maybe_unused mipi_csis_resume(struct device *dev)
+{
+ return mipi_csis_pm_resume(dev, false);
+}
+
+static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev)
+{
+ return mipi_csis_pm_suspend(dev, true);
+}
+
+static int __maybe_unused mipi_csis_runtime_resume(struct device *dev)
+{
+ return mipi_csis_pm_resume(dev, true);
+}
+
+static const struct dev_pm_ops mipi_csis_pm_ops = {
+ SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume,
+ NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume)
+};
+
+/* -----------------------------------------------------------------------------
+ * Probe/remove & platform driver
+ */
+
+static int mipi_csis_subdev_init(struct csi_state *state)
+{
+ struct v4l2_subdev *sd = &state->sd;
+
+ v4l2_subdev_init(sd, &mipi_csis_subdev_ops);
+ sd->owner = THIS_MODULE;
+ snprintf(sd->name, sizeof(sd->name), "%s.%d",
+ CSIS_SUBDEV_NAME, state->index);
+
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->ctrl_handler = NULL;
+
+ sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ sd->entity.ops = &mipi_csis_entity_ops;
+
+ sd->dev = state->dev;
+
+ state->csis_fmt = &mipi_csis_formats[0];
+ mipi_csis_init_cfg(sd, NULL);
+
+ state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK
+ | MEDIA_PAD_FL_MUST_CONNECT;
+ state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE
+ | MEDIA_PAD_FL_MUST_CONNECT;
+ return media_entity_pads_init(&sd->entity, CSIS_PADS_NUM,
+ state->pads);
+}
+
+static int mipi_csis_parse_dt(struct csi_state *state)
+{
+ struct device_node *node = state->dev->of_node;
+
+ if (of_property_read_u32(node, "clock-frequency",
+ &state->clk_frequency))
+ state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;
+
+ return 0;
}
static int mipi_csis_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct csi_state *state;
+ int irq;
int ret;
state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
+ mutex_init(&state->lock);
spin_lock_init(&state->slock);
- state->pdev = pdev;
state->dev = dev;
+ state->info = of_device_get_match_data(dev);
+
+ memcpy(state->events, mipi_csis_events, sizeof(state->events));
- ret = mipi_csis_parse_dt(pdev, state);
+ /* Parse DT properties. */
+ ret = mipi_csis_parse_dt(state);
if (ret < 0) {
dev_err(dev, "Failed to parse device tree: %d\n", ret);
return ret;
}
- ret = mipi_csis_phy_init(state);
- if (ret < 0)
- return ret;
-
- mipi_csis_phy_reset(state);
-
+ /* Acquire resources. */
state->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(state->regs))
return PTR_ERR(state->regs);
- state->irq = platform_get_irq(pdev, 0);
- if (state->irq < 0)
- return state->irq;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = mipi_csis_phy_init(state);
+ if (ret < 0)
+ return ret;
ret = mipi_csis_clk_get(state);
if (ret < 0)
return ret;
+ /* Reset PHY and enable the clocks. */
+ mipi_csis_phy_reset(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);
+ /* Now that the hardware is initialized, request the interrupt. */
+ ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0,
+ dev_name(dev), state);
if (ret) {
dev_err(dev, "Interrupt request failed\n");
goto disable_clock;
}
- platform_set_drvdata(pdev, &state->mipi_sd);
-
- mutex_init(&state->lock);
- ret = mipi_csis_subdev_init(&state->mipi_sd, pdev,
- &mipi_csis_subdev_ops);
+ /* Initialize and register the subdev. */
+ ret = mipi_csis_subdev_init(state);
if (ret < 0)
goto disable_clock;
+ platform_set_drvdata(pdev, &state->sd);
+
ret = mipi_csis_async_register(state);
if (ret < 0) {
- dev_err(&pdev->dev, "async register failed: %d\n", ret);
+ dev_err(dev, "async register failed: %d\n", ret);
goto cleanup;
}
- memcpy(state->events, mipi_csis_events, sizeof(state->events));
-
+ /* Initialize debugfs. */
mipi_csis_debugfs_init(state);
+
+ /* Enable runtime PM. */
pm_runtime_enable(dev);
if (!pm_runtime_enabled(dev)) {
ret = mipi_csis_pm_resume(dev, true);
@@ -1221,7 +1422,7 @@ static int mipi_csis_probe(struct platform_device *pdev)
goto unregister_all;
}
- dev_info(&pdev->dev, "lanes: %d, freq: %u\n",
+ dev_info(dev, "lanes: %d, freq: %u\n",
state->bus.num_data_lanes, state->clk_frequency);
return 0;
@@ -1229,10 +1430,10 @@ static int mipi_csis_probe(struct platform_device *pdev)
unregister_all:
mipi_csis_debugfs_exit(state);
cleanup:
- media_entity_cleanup(&state->mipi_sd.entity);
+ media_entity_cleanup(&state->sd.entity);
v4l2_async_notifier_unregister(&state->notifier);
v4l2_async_notifier_cleanup(&state->notifier);
- v4l2_async_unregister_subdev(&state->mipi_sd);
+ v4l2_async_unregister_subdev(&state->sd);
disable_clock:
mipi_csis_clk_disable(state);
mutex_destroy(&state->lock);
@@ -1240,107 +1441,40 @@ disable_clock:
return ret;
}
-static int mipi_csis_pm_suspend(struct device *dev, bool runtime)
-{
- struct v4l2_subdev *mipi_sd = dev_get_drvdata(dev);
- struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
- int ret = 0;
-
- mutex_lock(&state->lock);
- if (state->flags & ST_POWERED) {
- mipi_csis_stop_stream(state);
- ret = regulator_disable(state->mipi_phy_regulator);
- if (ret)
- goto unlock;
- mipi_csis_clk_disable(state);
- state->flags &= ~ST_POWERED;
- if (!runtime)
- state->flags |= ST_SUSPENDED;
- }
-
-unlock:
- mutex_unlock(&state->lock);
-
- return ret ? -EAGAIN : 0;
-}
-
-static int mipi_csis_pm_resume(struct device *dev, bool runtime)
-{
- struct v4l2_subdev *mipi_sd = dev_get_drvdata(dev);
- struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
- int ret = 0;
-
- mutex_lock(&state->lock);
- if (!runtime && !(state->flags & ST_SUSPENDED))
- goto unlock;
-
- if (!(state->flags & ST_POWERED)) {
- ret = regulator_enable(state->mipi_phy_regulator);
- if (ret)
- goto unlock;
-
- state->flags |= ST_POWERED;
- mipi_csis_clk_enable(state);
- }
- if (state->flags & ST_STREAMING)
- mipi_csis_start_stream(state);
-
- state->flags &= ~ST_SUSPENDED;
-
-unlock:
- mutex_unlock(&state->lock);
-
- return ret ? -EAGAIN : 0;
-}
-
-static int __maybe_unused mipi_csis_suspend(struct device *dev)
-{
- return mipi_csis_pm_suspend(dev, false);
-}
-
-static int __maybe_unused mipi_csis_resume(struct device *dev)
-{
- return mipi_csis_pm_resume(dev, false);
-}
-
-static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev)
-{
- return mipi_csis_pm_suspend(dev, true);
-}
-
-static int __maybe_unused mipi_csis_runtime_resume(struct device *dev)
-{
- return mipi_csis_pm_resume(dev, true);
-}
-
static int mipi_csis_remove(struct platform_device *pdev)
{
- struct v4l2_subdev *mipi_sd = platform_get_drvdata(pdev);
- struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct csi_state *state = mipi_sd_to_csis_state(sd);
mipi_csis_debugfs_exit(state);
v4l2_async_notifier_unregister(&state->notifier);
v4l2_async_notifier_cleanup(&state->notifier);
- v4l2_async_unregister_subdev(&state->mipi_sd);
+ v4l2_async_unregister_subdev(&state->sd);
pm_runtime_disable(&pdev->dev);
mipi_csis_pm_suspend(&pdev->dev, true);
mipi_csis_clk_disable(state);
- media_entity_cleanup(&state->mipi_sd.entity);
+ media_entity_cleanup(&state->sd.entity);
mutex_destroy(&state->lock);
pm_runtime_set_suspended(&pdev->dev);
return 0;
}
-static const struct dev_pm_ops mipi_csis_pm_ops = {
- SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume,
- NULL)
- SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume)
-};
-
static const struct of_device_id mipi_csis_of_match[] = {
- { .compatible = "fsl,imx7-mipi-csi2", },
+ {
+ .compatible = "fsl,imx7-mipi-csi2",
+ .data = &(const struct mipi_csis_info){
+ .version = MIPI_CSIS_V3_3,
+ .num_clocks = 3,
+ },
+ }, {
+ .compatible = "fsl,imx8mm-mipi-csi2",
+ .data = &(const struct mipi_csis_info){
+ .version = MIPI_CSIS_V3_6_3,
+ .num_clocks = 4,
+ },
+ },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, mipi_csis_of_match);
@@ -1357,6 +1491,6 @@ static struct platform_driver mipi_csis_driver = {
module_platform_driver(mipi_csis_driver);
-MODULE_DESCRIPTION("i.MX7 MIPI CSI-2 Receiver driver");
+MODULE_DESCRIPTION("i.MX7 & i.MX8 MIPI CSI-2 receiver driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:imx7-mipi-csi2");
diff --git a/drivers/staging/media/ipu3/include/intel-ipu3.h b/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h
index 9b644fb23dde..fa3d6ee5adf2 100644
--- a/drivers/staging/media/ipu3/include/intel-ipu3.h
+++ b/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h
@@ -9,8 +9,10 @@
/* from /drivers/staging/media/ipu3/include/videodev2.h */
/* Vendor specific - used for IPU3 camera sub-system */
-#define V4L2_META_FMT_IPU3_PARAMS v4l2_fourcc('i', 'p', '3', 'p') /* IPU3 processing parameters */
-#define V4L2_META_FMT_IPU3_STAT_3A v4l2_fourcc('i', 'p', '3', 's') /* IPU3 3A statistics */
+/* IPU3 processing parameters */
+#define V4L2_META_FMT_IPU3_PARAMS v4l2_fourcc('i', 'p', '3', 'p')
+/* IPU3 3A statistics */
+#define V4L2_META_FMT_IPU3_STAT_3A v4l2_fourcc('i', 'p', '3', 's')
/* from include/uapi/linux/v4l2-controls.h */
#define V4L2_CID_INTEL_IPU3_BASE (V4L2_CID_USER_BASE + 0x10c0)
@@ -74,7 +76,6 @@ struct ipu3_uapi_grid_config {
(IPU3_UAPI_AWB_MAX_SETS * \
(IPU3_UAPI_AWB_SET_SIZE + IPU3_UAPI_AWB_SPARE_FOR_BUBBLES))
-
/**
* struct ipu3_uapi_awb_raw_buffer - AWB raw buffer
*
@@ -244,8 +245,8 @@ struct ipu3_uapi_ae_ccm {
*/
struct ipu3_uapi_ae_config {
struct ipu3_uapi_ae_grid_config grid_cfg __attribute__((aligned(32)));
- struct ipu3_uapi_ae_weight_elem weights[
- IPU3_UAPI_AE_WEIGHTS] __attribute__((aligned(32)));
+ struct ipu3_uapi_ae_weight_elem weights[IPU3_UAPI_AE_WEIGHTS]
+ __attribute__((aligned(32)));
struct ipu3_uapi_ae_ccm ae_ccm __attribute__((aligned(32)));
} __packed;
@@ -630,7 +631,7 @@ struct ipu3_uapi_bnr_static_config_wb_gains_thr_config {
* @cg: Gain coefficient for threshold calculation, [0, 31], default 8.
* @ci: Intensity coefficient for threshold calculation. range [0, 0x1f]
* default 6.
- * format: u3.2 (3 most significant bits represent whole number,
+ * format: u3.2 (3 most significant bits represent whole number,
* 2 least significant bits represent the fractional part
* with each count representing 0.25)
* e.g. 6 in binary format is 00110, that translates to 1.5
diff --git a/drivers/staging/media/ipu3/ipu3-abi.h b/drivers/staging/media/ipu3/ipu3-abi.h
index e1185602c7fd..c76935b436d7 100644
--- a/drivers/staging/media/ipu3/ipu3-abi.h
+++ b/drivers/staging/media/ipu3/ipu3-abi.h
@@ -4,7 +4,7 @@
#ifndef __IPU3_ABI_H
#define __IPU3_ABI_H
-#include "include/intel-ipu3.h"
+#include "include/uapi/intel-ipu3.h"
/******************* IMGU Hardware information *******************/
diff --git a/drivers/staging/media/ipu3/ipu3-css-pool.h b/drivers/staging/media/ipu3/ipu3-css-pool.h
index 35519a08c08c..3f9e32e0e9a7 100644
--- a/drivers/staging/media/ipu3/ipu3-css-pool.h
+++ b/drivers/staging/media/ipu3/ipu3-css-pool.h
@@ -15,6 +15,7 @@ struct imgu_device;
* @size: size of the buffer in bytes.
* @vaddr: kernel virtual address.
* @daddr: iova dma address to access IPU3.
+ * @pages: pages mapped to this buffer
*/
struct imgu_css_map {
size_t size;
diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c
index 6d9c49b39531..38a240764509 100644
--- a/drivers/staging/media/ipu3/ipu3-v4l2.c
+++ b/drivers/staging/media/ipu3/ipu3-v4l2.c
@@ -36,7 +36,7 @@ static int imgu_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
/* Initialize try_fmt */
for (i = 0; i < IMGU_NODE_NUM; i++) {
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->pad, i);
+ v4l2_subdev_get_try_format(sd, fh->state, i);
try_fmt->width = try_crop.width;
try_fmt->height = try_crop.height;
@@ -44,8 +44,8 @@ static int imgu_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
try_fmt->field = V4L2_FIELD_NONE;
}
- *v4l2_subdev_get_try_crop(sd, fh->pad, IMGU_NODE_IN) = try_crop;
- *v4l2_subdev_get_try_compose(sd, fh->pad, IMGU_NODE_IN) = try_crop;
+ *v4l2_subdev_get_try_crop(sd, fh->state, IMGU_NODE_IN) = try_crop;
+ *v4l2_subdev_get_try_compose(sd, fh->state, IMGU_NODE_IN) = try_crop;
return 0;
}
@@ -120,7 +120,7 @@ static int imgu_subdev_s_stream(struct v4l2_subdev *sd, int enable)
}
static int imgu_subdev_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imgu_device *imgu = v4l2_get_subdevdata(sd);
@@ -136,7 +136,7 @@ static int imgu_subdev_get_fmt(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
fmt->format = imgu_pipe->nodes[pad].pad_fmt;
} else {
- mf = v4l2_subdev_get_try_format(sd, cfg, pad);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, pad);
fmt->format = *mf;
}
@@ -144,7 +144,7 @@ static int imgu_subdev_get_fmt(struct v4l2_subdev *sd,
}
static int imgu_subdev_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imgu_media_pipe *imgu_pipe;
@@ -161,7 +161,7 @@ static int imgu_subdev_set_fmt(struct v4l2_subdev *sd,
imgu_pipe = &imgu->imgu_pipe[pipe];
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- mf = v4l2_subdev_get_try_format(sd, cfg, pad);
+ mf = v4l2_subdev_get_try_format(sd, sd_state, pad);
else
mf = &imgu_pipe->nodes[pad].pad_fmt;
@@ -189,7 +189,7 @@ static int imgu_subdev_set_fmt(struct v4l2_subdev *sd,
}
static int imgu_subdev_get_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct v4l2_rect *try_sel, *r;
@@ -202,11 +202,11 @@ static int imgu_subdev_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+ try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
r = &imgu_sd->rect.eff;
break;
case V4L2_SEL_TGT_COMPOSE:
- try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
+ try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad);
r = &imgu_sd->rect.bds;
break;
default:
@@ -222,7 +222,7 @@ static int imgu_subdev_get_selection(struct v4l2_subdev *sd,
}
static int imgu_subdev_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
struct imgu_device *imgu = v4l2_get_subdevdata(sd);
@@ -241,11 +241,11 @@ static int imgu_subdev_set_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+ try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
rect = &imgu_sd->rect.eff;
break;
case V4L2_SEL_TGT_COMPOSE:
- try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
+ try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad);
rect = &imgu_sd->rect.bds;
break;
default:
diff --git a/drivers/staging/media/ipu3/ipu3.c b/drivers/staging/media/ipu3/ipu3.c
index ee1bba6bdcac..8e1e9e46e604 100644
--- a/drivers/staging/media/ipu3/ipu3.c
+++ b/drivers/staging/media/ipu3/ipu3.c
@@ -392,10 +392,9 @@ int imgu_s_stream(struct imgu_device *imgu, int enable)
}
/* Set Power */
- r = pm_runtime_get_sync(dev);
+ r = pm_runtime_resume_and_get(dev);
if (r < 0) {
dev_err(dev, "failed to set imgu power\n");
- pm_runtime_put(dev);
return r;
}
diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.c b/drivers/staging/media/meson/vdec/vdec_helpers.c
index 7f07a9175815..b9125c295d1d 100644
--- a/drivers/staging/media/meson/vdec/vdec_helpers.c
+++ b/drivers/staging/media/meson/vdec/vdec_helpers.c
@@ -183,7 +183,7 @@ int amvdec_set_canvases(struct amvdec_session *sess,
u32 pixfmt = sess->pixfmt_cap;
u32 width = ALIGN(sess->width, 32);
u32 height = ALIGN(sess->height, 32);
- u32 reg_cur = reg_base[0];
+ u32 reg_cur;
u32 reg_num_cur = 0;
u32 reg_base_cur = 0;
int i = 0;
diff --git a/drivers/staging/media/omap4iss/iss.h b/drivers/staging/media/omap4iss/iss.h
index b88f9529683c..3f587e000729 100644
--- a/drivers/staging/media/omap4iss/iss.h
+++ b/drivers/staging/media/omap4iss/iss.h
@@ -119,9 +119,6 @@ struct iss_device {
unsigned int isp_subclk_resources;
};
-#define v4l2_dev_to_iss_device(dev) \
- container_of(dev, struct iss_device, v4l2_dev)
-
int omap4iss_get_external_info(struct iss_pipeline *pipe,
struct media_link *link);
diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c
index a6dc2d2b1228..124ab2f44fbf 100644
--- a/drivers/staging/media/omap4iss/iss_csi2.c
+++ b/drivers/staging/media/omap4iss/iss_csi2.c
@@ -825,19 +825,20 @@ static const struct iss_video_operations csi2_issvideo_ops = {
static struct v4l2_mbus_framefmt *
__csi2_get_format(struct iss_csi2_device *csi2,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&csi2->subdev, sd_state,
+ pad);
return &csi2->formats[pad];
}
static void
csi2_try_format(struct iss_csi2_device *csi2,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
@@ -868,7 +869,8 @@ csi2_try_format(struct iss_csi2_device *csi2,
* compression.
*/
pixelcode = fmt->code;
- format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, which);
+ format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SINK,
+ which);
memcpy(fmt, format, sizeof(*fmt));
/*
@@ -894,7 +896,7 @@ csi2_try_format(struct iss_csi2_device *csi2,
* return -EINVAL or zero on success
*/
static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
@@ -907,7 +909,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
code->code = csi2_input_fmts[code->index];
} else {
- format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK,
+ format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SINK,
code->which);
switch (code->index) {
case 0:
@@ -931,7 +933,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
}
static int csi2_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
@@ -943,7 +945,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- csi2_try_format(csi2, cfg, fse->pad, &format, fse->which);
+ csi2_try_format(csi2, sd_state, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -953,7 +955,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- csi2_try_format(csi2, cfg, fse->pad, &format, fse->which);
+ csi2_try_format(csi2, sd_state, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -968,13 +970,13 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
* return -EINVAL or zero on success
*/
static int csi2_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which);
+ format = __csi2_get_format(csi2, sd_state, fmt->pad, fmt->which);
if (!format)
return -EINVAL;
@@ -990,25 +992,26 @@ static int csi2_get_format(struct v4l2_subdev *sd,
* return -EINVAL or zero on success
*/
static int csi2_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which);
+ format = __csi2_get_format(csi2, sd_state, fmt->pad, fmt->which);
if (!format)
return -EINVAL;
- csi2_try_format(csi2, cfg, fmt->pad, &fmt->format, fmt->which);
+ csi2_try_format(csi2, sd_state, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == CSI2_PAD_SINK) {
- format = __csi2_get_format(csi2, cfg, CSI2_PAD_SOURCE,
+ format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SOURCE,
fmt->which);
*format = fmt->format;
- csi2_try_format(csi2, cfg, CSI2_PAD_SOURCE, format, fmt->which);
+ csi2_try_format(csi2, sd_state, CSI2_PAD_SOURCE, format,
+ fmt->which);
}
return 0;
@@ -1050,7 +1053,7 @@ static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
- csi2_set_format(sd, fh ? fh->pad : NULL, &format);
+ csi2_set_format(sd, fh ? fh->state : NULL, &format);
return 0;
}
diff --git a/drivers/staging/media/omap4iss/iss_ipipe.c b/drivers/staging/media/omap4iss/iss_ipipe.c
index 26be078b69f3..23f707cb336f 100644
--- a/drivers/staging/media/omap4iss/iss_ipipe.c
+++ b/drivers/staging/media/omap4iss/iss_ipipe.c
@@ -21,7 +21,7 @@
static struct v4l2_mbus_framefmt *
__ipipe_get_format(struct iss_ipipe_device *ipipe,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
enum v4l2_subdev_format_whence which);
@@ -175,12 +175,13 @@ static int ipipe_set_stream(struct v4l2_subdev *sd, int enable)
static struct v4l2_mbus_framefmt *
__ipipe_get_format(struct iss_ipipe_device *ipipe,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&ipipe->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&ipipe->subdev, sd_state,
+ pad);
return &ipipe->formats[pad];
}
@@ -194,7 +195,7 @@ __ipipe_get_format(struct iss_ipipe_device *ipipe,
*/
static void
ipipe_try_format(struct iss_ipipe_device *ipipe,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
@@ -222,7 +223,8 @@ ipipe_try_format(struct iss_ipipe_device *ipipe,
break;
case IPIPE_PAD_SOURCE_VP:
- format = __ipipe_get_format(ipipe, cfg, IPIPE_PAD_SINK, which);
+ format = __ipipe_get_format(ipipe, sd_state, IPIPE_PAD_SINK,
+ which);
memcpy(fmt, format, sizeof(*fmt));
fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
@@ -243,7 +245,7 @@ ipipe_try_format(struct iss_ipipe_device *ipipe,
* return -EINVAL or zero on success
*/
static int ipipe_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
switch (code->pad) {
@@ -270,7 +272,7 @@ static int ipipe_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ipipe_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
@@ -282,7 +284,7 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which);
+ ipipe_try_format(ipipe, sd_state, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -292,7 +294,7 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which);
+ ipipe_try_format(ipipe, sd_state, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -309,13 +311,13 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd,
* to the format type.
*/
static int ipipe_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which);
+ format = __ipipe_get_format(ipipe, sd_state, fmt->pad, fmt->which);
if (!format)
return -EINVAL;
@@ -333,25 +335,26 @@ static int ipipe_get_format(struct v4l2_subdev *sd,
* to the format type.
*/
static int ipipe_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which);
+ format = __ipipe_get_format(ipipe, sd_state, fmt->pad, fmt->which);
if (!format)
return -EINVAL;
- ipipe_try_format(ipipe, cfg, fmt->pad, &fmt->format, fmt->which);
+ ipipe_try_format(ipipe, sd_state, fmt->pad, &fmt->format, fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == IPIPE_PAD_SINK) {
- format = __ipipe_get_format(ipipe, cfg, IPIPE_PAD_SOURCE_VP,
+ format = __ipipe_get_format(ipipe, sd_state,
+ IPIPE_PAD_SOURCE_VP,
fmt->which);
*format = fmt->format;
- ipipe_try_format(ipipe, cfg, IPIPE_PAD_SOURCE_VP, format,
+ ipipe_try_format(ipipe, sd_state, IPIPE_PAD_SOURCE_VP, format,
fmt->which);
}
@@ -392,7 +395,7 @@ static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
- ipipe_set_format(sd, fh ? fh->pad : NULL, &format);
+ ipipe_set_format(sd, fh ? fh->state : NULL, &format);
return 0;
}
diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c
index c2978d02e797..5e7f25cd53ac 100644
--- a/drivers/staging/media/omap4iss/iss_ipipeif.c
+++ b/drivers/staging/media/omap4iss/iss_ipipeif.c
@@ -357,11 +357,12 @@ static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable)
static struct v4l2_mbus_framefmt *
__ipipeif_get_format(struct iss_ipipeif_device *ipipeif,
- struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+ struct v4l2_subdev_state *sd_state, unsigned int pad,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&ipipeif->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&ipipeif->subdev, sd_state,
+ pad);
return &ipipeif->formats[pad];
}
@@ -374,7 +375,7 @@ __ipipeif_get_format(struct iss_ipipeif_device *ipipeif,
*/
static void
ipipeif_try_format(struct iss_ipipeif_device *ipipeif,
- struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+ struct v4l2_subdev_state *sd_state, unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -403,7 +404,8 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif,
break;
case IPIPEIF_PAD_SOURCE_ISIF_SF:
- format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK,
+ format = __ipipeif_get_format(ipipeif, sd_state,
+ IPIPEIF_PAD_SINK,
which);
memcpy(fmt, format, sizeof(*fmt));
@@ -418,7 +420,8 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif,
break;
case IPIPEIF_PAD_SOURCE_VP:
- format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK,
+ format = __ipipeif_get_format(ipipeif, sd_state,
+ IPIPEIF_PAD_SINK,
which);
memcpy(fmt, format, sizeof(*fmt));
@@ -442,7 +445,7 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif,
* return -EINVAL or zero on success
*/
static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
@@ -462,7 +465,8 @@ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index != 0)
return -EINVAL;
- format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK,
+ format = __ipipeif_get_format(ipipeif, sd_state,
+ IPIPEIF_PAD_SINK,
code->which);
code->code = format->code;
@@ -476,7 +480,7 @@ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd,
}
static int ipipeif_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
@@ -488,7 +492,7 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which);
+ ipipeif_try_format(ipipeif, sd_state, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -498,7 +502,7 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which);
+ ipipeif_try_format(ipipeif, sd_state, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -515,13 +519,13 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd,
* to the format type.
*/
static int ipipeif_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which);
+ format = __ipipeif_get_format(ipipeif, sd_state, fmt->pad, fmt->which);
if (!format)
return -EINVAL;
@@ -539,33 +543,36 @@ static int ipipeif_get_format(struct v4l2_subdev *sd,
* to the format type.
*/
static int ipipeif_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which);
+ format = __ipipeif_get_format(ipipeif, sd_state, fmt->pad, fmt->which);
if (!format)
return -EINVAL;
- ipipeif_try_format(ipipeif, cfg, fmt->pad, &fmt->format, fmt->which);
+ ipipeif_try_format(ipipeif, sd_state, fmt->pad, &fmt->format,
+ fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == IPIPEIF_PAD_SINK) {
- format = __ipipeif_get_format(ipipeif, cfg,
+ format = __ipipeif_get_format(ipipeif, sd_state,
IPIPEIF_PAD_SOURCE_ISIF_SF,
fmt->which);
*format = fmt->format;
- ipipeif_try_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_ISIF_SF,
+ ipipeif_try_format(ipipeif, sd_state,
+ IPIPEIF_PAD_SOURCE_ISIF_SF,
format, fmt->which);
- format = __ipipeif_get_format(ipipeif, cfg,
+ format = __ipipeif_get_format(ipipeif, sd_state,
IPIPEIF_PAD_SOURCE_VP,
fmt->which);
*format = fmt->format;
- ipipeif_try_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_VP, format,
+ ipipeif_try_format(ipipeif, sd_state, IPIPEIF_PAD_SOURCE_VP,
+ format,
fmt->which);
}
@@ -608,7 +615,7 @@ static int ipipeif_init_formats(struct v4l2_subdev *sd,
format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
- ipipeif_set_format(sd, fh ? fh->pad : NULL, &format);
+ ipipeif_set_format(sd, fh ? fh->state : NULL, &format);
return 0;
}
diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c
index 3b6875cbca9b..a5f8f9f1ab16 100644
--- a/drivers/staging/media/omap4iss/iss_resizer.c
+++ b/drivers/staging/media/omap4iss/iss_resizer.c
@@ -416,11 +416,12 @@ static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
static struct v4l2_mbus_framefmt *
__resizer_get_format(struct iss_resizer_device *resizer,
- struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+ struct v4l2_subdev_state *sd_state, unsigned int pad,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&resizer->subdev, cfg, pad);
+ return v4l2_subdev_get_try_format(&resizer->subdev, sd_state,
+ pad);
return &resizer->formats[pad];
}
@@ -433,7 +434,7 @@ __resizer_get_format(struct iss_resizer_device *resizer,
*/
static void
resizer_try_format(struct iss_resizer_device *resizer,
- struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+ struct v4l2_subdev_state *sd_state, unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
@@ -461,7 +462,8 @@ resizer_try_format(struct iss_resizer_device *resizer,
case RESIZER_PAD_SOURCE_MEM:
pixelcode = fmt->code;
- format = __resizer_get_format(resizer, cfg, RESIZER_PAD_SINK,
+ format = __resizer_get_format(resizer, sd_state,
+ RESIZER_PAD_SINK,
which);
memcpy(fmt, format, sizeof(*fmt));
@@ -492,7 +494,7 @@ resizer_try_format(struct iss_resizer_device *resizer,
* return -EINVAL or zero on success
*/
static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
@@ -507,7 +509,8 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
break;
case RESIZER_PAD_SOURCE_MEM:
- format = __resizer_get_format(resizer, cfg, RESIZER_PAD_SINK,
+ format = __resizer_get_format(resizer, sd_state,
+ RESIZER_PAD_SINK,
code->which);
if (code->index == 0) {
@@ -537,7 +540,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
}
static int resizer_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
@@ -549,7 +552,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = 1;
format.height = 1;
- resizer_try_format(resizer, cfg, fse->pad, &format, fse->which);
+ resizer_try_format(resizer, sd_state, fse->pad, &format, fse->which);
fse->min_width = format.width;
fse->min_height = format.height;
@@ -559,7 +562,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
format.code = fse->code;
format.width = -1;
format.height = -1;
- resizer_try_format(resizer, cfg, fse->pad, &format, fse->which);
+ resizer_try_format(resizer, sd_state, fse->pad, &format, fse->which);
fse->max_width = format.width;
fse->max_height = format.height;
@@ -576,13 +579,13 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
* to the format type.
*/
static int resizer_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __resizer_get_format(resizer, cfg, fmt->pad, fmt->which);
+ format = __resizer_get_format(resizer, sd_state, fmt->pad, fmt->which);
if (!format)
return -EINVAL;
@@ -600,26 +603,28 @@ static int resizer_get_format(struct v4l2_subdev *sd,
* to the format type.
*/
static int resizer_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- format = __resizer_get_format(resizer, cfg, fmt->pad, fmt->which);
+ format = __resizer_get_format(resizer, sd_state, fmt->pad, fmt->which);
if (!format)
return -EINVAL;
- resizer_try_format(resizer, cfg, fmt->pad, &fmt->format, fmt->which);
+ resizer_try_format(resizer, sd_state, fmt->pad, &fmt->format,
+ fmt->which);
*format = fmt->format;
/* Propagate the format from sink to source */
if (fmt->pad == RESIZER_PAD_SINK) {
- format = __resizer_get_format(resizer, cfg,
+ format = __resizer_get_format(resizer, sd_state,
RESIZER_PAD_SOURCE_MEM,
fmt->which);
*format = fmt->format;
- resizer_try_format(resizer, cfg, RESIZER_PAD_SOURCE_MEM, format,
+ resizer_try_format(resizer, sd_state, RESIZER_PAD_SOURCE_MEM,
+ format,
fmt->which);
}
@@ -662,7 +667,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd,
format.format.code = MEDIA_BUS_FMT_UYVY8_1X16;
format.format.width = 4096;
format.format.height = 4096;
- resizer_set_format(sd, fh ? fh->pad : NULL, &format);
+ resizer_set_format(sd, fh ? fh->state : NULL, &format);
return 0;
}
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index 930f638f51eb..d0da083deed5 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -399,7 +399,7 @@ static void iss_video_buf_queue(struct vb2_buffer *vb)
if (start)
omap4iss_pipeline_set_stream(pipe,
- ISS_PIPELINE_STREAM_SINGLESHOT);
+ ISS_PIPELINE_STREAM_SINGLESHOT);
}
}
@@ -960,7 +960,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
unsigned long flags;
ret = omap4iss_pipeline_set_stream(pipe,
- ISS_PIPELINE_STREAM_CONTINUOUS);
+ ISS_PIPELINE_STREAM_CONTINUOUS);
if (ret < 0)
goto err_omap4iss_set_stream;
spin_lock_irqsave(&video->qlock, flags);
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index d821661d30f3..7131156c1f2c 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -481,7 +481,15 @@ static int rkvdec_buf_prepare(struct vb2_buffer *vb)
if (vb2_plane_size(vb, i) < sizeimage)
return -EINVAL;
}
- vb2_set_plane_payload(vb, 0, f->fmt.pix_mp.plane_fmt[0].sizeimage);
+
+ /*
+ * Buffer's bytesused must be written by driver for CAPTURE buffers.
+ * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets
+ * it to buffer length).
+ */
+ if (V4L2_TYPE_IS_CAPTURE(vq->type))
+ vb2_set_plane_payload(vb, 0, f->fmt.pix_mp.plane_fmt[0].sizeimage);
+
return 0;
}
@@ -658,7 +666,7 @@ static void rkvdec_device_run(void *priv)
if (WARN_ON(!desc))
return;
- ret = pm_runtime_get_sync(rkvdec->dev);
+ ret = pm_runtime_resume_and_get(rkvdec->dev);
if (ret < 0) {
rkvdec_job_finish_no_pm(ctx, VB2_BUF_STATE_ERROR);
return;
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
index 92812d1a39d4..c0d005dafc6c 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -31,13 +31,19 @@
static const struct cedrus_control cedrus_controls[] = {
{
.cfg = {
- .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
+ .id = V4L2_CID_STATELESS_MPEG2_SEQUENCE,
},
.codec = CEDRUS_CODEC_MPEG2,
},
{
.cfg = {
- .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION,
+ .id = V4L2_CID_STATELESS_MPEG2_PICTURE,
+ },
+ .codec = CEDRUS_CODEC_MPEG2,
+ },
+ {
+ .cfg = {
+ .id = V4L2_CID_STATELESS_MPEG2_QUANTISATION,
},
.codec = CEDRUS_CODEC_MPEG2,
},
@@ -151,6 +157,12 @@ static const struct cedrus_control cedrus_controls[] = {
},
.codec = CEDRUS_CODEC_VP8,
},
+ {
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS,
+ },
+ .codec = CEDRUS_CODEC_H265,
+ },
};
#define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index 15f147dad4cb..88afba17b78b 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -68,14 +68,16 @@ struct cedrus_h264_run {
};
struct cedrus_mpeg2_run {
- const struct v4l2_ctrl_mpeg2_slice_params *slice_params;
- const struct v4l2_ctrl_mpeg2_quantization *quantization;
+ const struct v4l2_ctrl_mpeg2_sequence *sequence;
+ const struct v4l2_ctrl_mpeg2_picture *picture;
+ const struct v4l2_ctrl_mpeg2_quantisation *quantisation;
};
struct cedrus_h265_run {
const struct v4l2_ctrl_hevc_sps *sps;
const struct v4l2_ctrl_hevc_pps *pps;
const struct v4l2_ctrl_hevc_slice_params *slice_params;
+ const struct v4l2_ctrl_hevc_decode_params *decode_params;
};
struct cedrus_vp8_run {
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
index d696b3ec70c0..40e8c4123f76 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
@@ -40,10 +40,12 @@ void cedrus_device_run(void *priv)
switch (ctx->src_fmt.pixelformat) {
case V4L2_PIX_FMT_MPEG2_SLICE:
- run.mpeg2.slice_params = cedrus_find_control_data(ctx,
- V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS);
- run.mpeg2.quantization = cedrus_find_control_data(ctx,
- V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION);
+ run.mpeg2.sequence = cedrus_find_control_data(ctx,
+ V4L2_CID_STATELESS_MPEG2_SEQUENCE);
+ run.mpeg2.picture = cedrus_find_control_data(ctx,
+ V4L2_CID_STATELESS_MPEG2_PICTURE);
+ run.mpeg2.quantisation = cedrus_find_control_data(ctx,
+ V4L2_CID_STATELESS_MPEG2_QUANTISATION);
break;
case V4L2_PIX_FMT_H264_SLICE:
@@ -68,6 +70,8 @@ void cedrus_device_run(void *priv)
V4L2_CID_MPEG_VIDEO_HEVC_PPS);
run.h265.slice_params = cedrus_find_control_data(ctx,
V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS);
+ run.h265.decode_params = cedrus_find_control_data(ctx,
+ V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS);
break;
case V4L2_PIX_FMT_VP8_FRAME:
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
index ce497d0197df..6821e3d05d34 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -245,6 +245,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
const struct v4l2_ctrl_hevc_sps *sps;
const struct v4l2_ctrl_hevc_pps *pps;
const struct v4l2_ctrl_hevc_slice_params *slice_params;
+ const struct v4l2_ctrl_hevc_decode_params *decode_params;
const struct v4l2_hevc_pred_weight_table *pred_weight_table;
dma_addr_t src_buf_addr;
dma_addr_t src_buf_end_addr;
@@ -256,6 +257,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
sps = run->h265.sps;
pps = run->h265.pps;
slice_params = run->h265.slice_params;
+ decode_params = run->h265.decode_params;
pred_weight_table = &slice_params->pred_weight_table;
/* MV column buffer size and allocation. */
@@ -477,8 +479,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
slice_params->flags);
reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_DEPENDENT_SLICE_SEGMENT,
- V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT,
- pps->flags);
+ V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT,
+ slice_params->flags);
/* FIXME: For multi-slice support. */
reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_FIRST_SLICE_SEGMENT_IN_PIC;
@@ -487,7 +489,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
reg = VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_TC_OFFSET_DIV2(slice_params->slice_tc_offset_div2) |
VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_BETA_OFFSET_DIV2(slice_params->slice_beta_offset_div2) |
- VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_POC_BIGEST_IN_RPS_ST(slice_params->num_rps_poc_st_curr_after == 0) |
+ VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_POC_BIGEST_IN_RPS_ST(decode_params->num_poc_st_curr_after == 0) |
VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CR_QP_OFFSET(slice_params->slice_cr_qp_offset) |
VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CB_QP_OFFSET(slice_params->slice_cb_qp_offset) |
VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_QP_DELTA(slice_params->slice_qp_delta);
@@ -527,8 +529,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
cedrus_write(dev, VE_DEC_H265_NEIGHBOR_INFO_ADDR, reg);
/* Write decoded picture buffer in pic list. */
- cedrus_h265_frame_info_write_dpb(ctx, slice_params->dpb,
- slice_params->num_active_dpb_entries);
+ cedrus_h265_frame_info_write_dpb(ctx, decode_params->dpb,
+ decode_params->num_active_dpb_entries);
/* Output frame. */
@@ -545,7 +547,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
/* Reference picture list 0 (for P/B frames). */
if (slice_params->slice_type != V4L2_HEVC_SLICE_TYPE_I) {
- cedrus_h265_ref_pic_list_write(dev, slice_params->dpb,
+ cedrus_h265_ref_pic_list_write(dev, decode_params->dpb,
slice_params->ref_idx_l0,
slice_params->num_ref_idx_l0_active_minus1 + 1,
VE_DEC_H265_SRAM_OFFSET_REF_PIC_LIST0);
@@ -564,7 +566,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
/* Reference picture list 1 (for B frames). */
if (slice_params->slice_type == V4L2_HEVC_SLICE_TYPE_B) {
- cedrus_h265_ref_pic_list_write(dev, slice_params->dpb,
+ cedrus_h265_ref_pic_list_write(dev, decode_params->dpb,
slice_params->ref_idx_l1,
slice_params->num_ref_idx_l1_active_minus1 + 1,
VE_DEC_H265_SRAM_OFFSET_REF_PIC_LIST1);
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
index 8bcd6b8f9e2d..5dad2f296c6d 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
@@ -13,30 +13,6 @@
#include "cedrus_hw.h"
#include "cedrus_regs.h"
-/* Default MPEG-2 quantization coefficients, from the specification. */
-
-static const u8 intra_quantization_matrix_default[64] = {
- 8, 16, 16, 19, 16, 19, 22, 22,
- 22, 22, 22, 22, 26, 24, 26, 27,
- 27, 27, 26, 26, 26, 26, 27, 27,
- 27, 29, 29, 29, 34, 34, 34, 29,
- 29, 29, 27, 27, 29, 29, 32, 32,
- 34, 34, 37, 38, 37, 35, 35, 34,
- 35, 38, 38, 40, 40, 40, 48, 48,
- 46, 46, 56, 56, 58, 69, 69, 83
-};
-
-static const u8 non_intra_quantization_matrix_default[64] = {
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16
-};
-
static enum cedrus_irq_status cedrus_mpeg2_irq_status(struct cedrus_ctx *ctx)
{
struct cedrus_dev *dev = ctx->dev;
@@ -74,10 +50,9 @@ static void cedrus_mpeg2_irq_disable(struct cedrus_ctx *ctx)
static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
{
- const struct v4l2_ctrl_mpeg2_slice_params *slice_params;
- const struct v4l2_mpeg2_sequence *sequence;
- const struct v4l2_mpeg2_picture *picture;
- const struct v4l2_ctrl_mpeg2_quantization *quantization;
+ const struct v4l2_ctrl_mpeg2_sequence *seq;
+ const struct v4l2_ctrl_mpeg2_picture *pic;
+ const struct v4l2_ctrl_mpeg2_quantisation *quantisation;
dma_addr_t src_buf_addr, dst_luma_addr, dst_chroma_addr;
dma_addr_t fwd_luma_addr, fwd_chroma_addr;
dma_addr_t bwd_luma_addr, bwd_chroma_addr;
@@ -89,22 +64,16 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
unsigned int i;
u32 reg;
- slice_params = run->mpeg2.slice_params;
- sequence = &slice_params->sequence;
- picture = &slice_params->picture;
+ seq = run->mpeg2.sequence;
+ pic = run->mpeg2.picture;
- quantization = run->mpeg2.quantization;
+ quantisation = run->mpeg2.quantisation;
/* Activate MPEG engine. */
cedrus_engine_enable(ctx, CEDRUS_CODEC_MPEG2);
- /* Set intra quantization matrix. */
-
- if (quantization && quantization->load_intra_quantiser_matrix)
- matrix = quantization->intra_quantiser_matrix;
- else
- matrix = intra_quantization_matrix_default;
-
+ /* Set intra quantisation matrix. */
+ matrix = quantisation->intra_quantiser_matrix;
for (i = 0; i < 64; i++) {
reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]);
reg |= VE_DEC_MPEG_IQMINPUT_FLAG_INTRA;
@@ -112,13 +81,8 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
cedrus_write(dev, VE_DEC_MPEG_IQMINPUT, reg);
}
- /* Set non-intra quantization matrix. */
-
- if (quantization && quantization->load_non_intra_quantiser_matrix)
- matrix = quantization->non_intra_quantiser_matrix;
- else
- matrix = non_intra_quantization_matrix_default;
-
+ /* Set non-intra quantisation matrix. */
+ matrix = quantisation->non_intra_quantiser_matrix;
for (i = 0; i < 64; i++) {
reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]);
reg |= VE_DEC_MPEG_IQMINPUT_FLAG_NON_INTRA;
@@ -128,19 +92,19 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
/* Set MPEG picture header. */
- reg = VE_DEC_MPEG_MP12HDR_SLICE_TYPE(picture->picture_coding_type);
- reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 0, picture->f_code[0][0]);
- reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 1, picture->f_code[0][1]);
- reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 0, picture->f_code[1][0]);
- reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 1, picture->f_code[1][1]);
- reg |= VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(picture->intra_dc_precision);
- reg |= VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(picture->picture_structure);
- reg |= VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(picture->top_field_first);
- reg |= VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(picture->frame_pred_frame_dct);
- reg |= VE_DEC_MPEG_MP12HDR_CONCEALMENT_MOTION_VECTORS(picture->concealment_motion_vectors);
- reg |= VE_DEC_MPEG_MP12HDR_Q_SCALE_TYPE(picture->q_scale_type);
- reg |= VE_DEC_MPEG_MP12HDR_INTRA_VLC_FORMAT(picture->intra_vlc_format);
- reg |= VE_DEC_MPEG_MP12HDR_ALTERNATE_SCAN(picture->alternate_scan);
+ reg = VE_DEC_MPEG_MP12HDR_SLICE_TYPE(pic->picture_coding_type);
+ reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 0, pic->f_code[0][0]);
+ reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 1, pic->f_code[0][1]);
+ reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 0, pic->f_code[1][0]);
+ reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 1, pic->f_code[1][1]);
+ reg |= VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(pic->intra_dc_precision);
+ reg |= VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(pic->picture_structure);
+ reg |= VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST);
+ reg |= VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(pic->flags & V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT);
+ reg |= VE_DEC_MPEG_MP12HDR_CONCEALMENT_MOTION_VECTORS(pic->flags & V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV);
+ reg |= VE_DEC_MPEG_MP12HDR_Q_SCALE_TYPE(pic->flags & V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE);
+ reg |= VE_DEC_MPEG_MP12HDR_INTRA_VLC_FORMAT(pic->flags & V4L2_MPEG2_PIC_FLAG_INTRA_VLC);
+ reg |= VE_DEC_MPEG_MP12HDR_ALTERNATE_SCAN(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN);
reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_FORWARD_VECTOR(0);
reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_BACKWARD_VECTOR(0);
@@ -148,8 +112,8 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
/* Set frame dimensions. */
- reg = VE_DEC_MPEG_PICCODEDSIZE_WIDTH(sequence->horizontal_size);
- reg |= VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(sequence->vertical_size);
+ reg = VE_DEC_MPEG_PICCODEDSIZE_WIDTH(seq->horizontal_size);
+ reg |= VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(seq->vertical_size);
cedrus_write(dev, VE_DEC_MPEG_PICCODEDSIZE, reg);
@@ -162,14 +126,14 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
- forward_idx = vb2_find_timestamp(vq, slice_params->forward_ref_ts, 0);
+ forward_idx = vb2_find_timestamp(vq, pic->forward_ref_ts, 0);
fwd_luma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 0);
fwd_chroma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 1);
cedrus_write(dev, VE_DEC_MPEG_FWD_REF_LUMA_ADDR, fwd_luma_addr);
cedrus_write(dev, VE_DEC_MPEG_FWD_REF_CHROMA_ADDR, fwd_chroma_addr);
- backward_idx = vb2_find_timestamp(vq, slice_params->backward_ref_ts, 0);
+ backward_idx = vb2_find_timestamp(vq, pic->backward_ref_ts, 0);
bwd_luma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 0);
bwd_chroma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 1);
@@ -186,10 +150,9 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
/* Source offset and length in bits. */
- cedrus_write(dev, VE_DEC_MPEG_VLD_OFFSET,
- slice_params->data_bit_offset);
+ cedrus_write(dev, VE_DEC_MPEG_VLD_OFFSET, 0);
- reg = slice_params->bit_size - slice_params->data_bit_offset;
+ reg = vb2_get_plane_payload(&run->src->vb2_buf, 0) * 8;
cedrus_write(dev, VE_DEC_MPEG_VLD_LEN, reg);
/* Source beginning and end addresses. */
@@ -203,7 +166,7 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
cedrus_write(dev, VE_DEC_MPEG_VLD_ADDR, reg);
- reg = src_buf_addr + DIV_ROUND_UP(slice_params->bit_size, 8);
+ reg = src_buf_addr + vb2_get_plane_payload(&run->src->vb2_buf, 0);
cedrus_write(dev, VE_DEC_MPEG_VLD_END_ADDR, reg);
/* Macroblock address: start at the beginning. */
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
index b62eb8e84057..32c13ecb22d8 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -457,7 +457,13 @@ static int cedrus_buf_prepare(struct vb2_buffer *vb)
if (vb2_plane_size(vb, 0) < pix_fmt->sizeimage)
return -EINVAL;
- vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage);
+ /*
+ * Buffer's bytesused must be written by driver for CAPTURE buffers.
+ * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets
+ * it to buffer length).
+ */
+ if (V4L2_TYPE_IS_CAPTURE(vq->type))
+ vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage);
return 0;
}
@@ -490,11 +496,9 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
}
if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
- ret = pm_runtime_get_sync(dev->dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev->dev);
+ ret = pm_runtime_resume_and_get(dev->dev);
+ if (ret < 0)
goto err_cleanup;
- }
if (dev->dec_ops[ctx->current_codec]->start) {
ret = dev->dec_ops[ctx->current_codec]->start(ctx);
diff --git a/drivers/staging/media/tegra-vde/vde.c b/drivers/staging/media/tegra-vde/vde.c
index 28845b5bafaf..ed4c1250b303 100644
--- a/drivers/staging/media/tegra-vde/vde.c
+++ b/drivers/staging/media/tegra-vde/vde.c
@@ -775,9 +775,9 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde,
if (ret)
goto release_dpb_frames;
- ret = pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
- goto put_runtime_pm;
+ goto unlock;
/*
* We rely on the VDE registers reset value, otherwise VDE
@@ -843,6 +843,8 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde,
put_runtime_pm:
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
+
+unlock:
mutex_unlock(&vde->lock);
release_dpb_frames:
@@ -1069,11 +1071,20 @@ static int tegra_vde_probe(struct platform_device *pdev)
* power-cycle it in order to put hardware into a predictable lower
* power state.
*/
- pm_runtime_get_sync(dev);
+ err = pm_runtime_resume_and_get(dev);
+ if (err)
+ goto err_pm_runtime;
+
pm_runtime_put(dev);
return 0;
+err_pm_runtime:
+ misc_deregister(&vde->miscdev);
+
+ pm_runtime_dont_use_autosuspend(dev);
+ pm_runtime_disable(dev);
+
err_deinit_iommu:
tegra_vde_iommu_deinit(vde);
@@ -1089,7 +1100,12 @@ static int tegra_vde_remove(struct platform_device *pdev)
struct tegra_vde *vde = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
+ /*
+ * As it increments RPM usage_count even on errors, we don't need to
+ * check the returned code here.
+ */
pm_runtime_get_sync(dev);
+
pm_runtime_dont_use_autosuspend(dev);
pm_runtime_disable(dev);
diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index 033a6935c26d..b26e44adb2be 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -64,7 +64,7 @@ static const struct v4l2_frmsize_discrete tegra_csi_tpg_sizes[] = {
* V4L2 Subdevice Pad Operations
*/
static int csi_enum_bus_code(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
@@ -79,7 +79,7 @@ static int csi_enum_bus_code(struct v4l2_subdev *subdev,
}
static int csi_get_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
@@ -127,7 +127,7 @@ static void csi_chan_update_blank_intervals(struct tegra_csi_channel *csi_chan,
}
static int csi_enum_framesizes(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
unsigned int i;
@@ -154,7 +154,7 @@ static int csi_enum_framesizes(struct v4l2_subdev *subdev,
}
static int csi_enum_frameintervals(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
@@ -181,7 +181,7 @@ static int csi_enum_frameintervals(struct v4l2_subdev *subdev,
}
static int csi_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
@@ -298,10 +298,9 @@ static int tegra_csi_enable_stream(struct v4l2_subdev *subdev)
struct tegra_csi *csi = csi_chan->csi;
int ret, err;
- ret = pm_runtime_get_sync(csi->dev);
+ ret = pm_runtime_resume_and_get(csi->dev);
if (ret < 0) {
dev_err(csi->dev, "failed to get runtime PM: %d\n", ret);
- pm_runtime_put_noidle(csi->dev);
return ret;
}
diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index df5ca3596470..89709cd06d4d 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -297,10 +297,9 @@ static int tegra_channel_start_streaming(struct vb2_queue *vq, u32 count)
struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
int ret;
- ret = pm_runtime_get_sync(chan->vi->dev);
+ ret = pm_runtime_resume_and_get(chan->vi->dev);
if (ret < 0) {
dev_err(chan->vi->dev, "failed to get runtime PM: %d\n", ret);
- pm_runtime_put_noidle(chan->vi->dev);
return ret;
}
@@ -494,7 +493,7 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
const struct tegra_video_format *fmtinfo;
struct v4l2_subdev *subdev;
struct v4l2_subdev_format fmt;
- struct v4l2_subdev_pad_config *pad_cfg;
+ struct v4l2_subdev_state *sd_state;
struct v4l2_subdev_frame_size_enum fse = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -508,8 +507,8 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
if (!subdev)
return -ENODEV;
- pad_cfg = v4l2_subdev_alloc_pad_config(subdev);
- if (!pad_cfg)
+ sd_state = v4l2_subdev_alloc_state(subdev);
+ if (!sd_state)
return -ENOMEM;
/*
* Retrieve the format information and if requested format isn't
@@ -533,33 +532,33 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
* If not available, try to get crop boundary from subdev.
*/
fse.code = fmtinfo->code;
- ret = v4l2_subdev_call(subdev, pad, enum_frame_size, pad_cfg, &fse);
+ ret = v4l2_subdev_call(subdev, pad, enum_frame_size, sd_state, &fse);
if (ret) {
if (!v4l2_subdev_has_op(subdev, pad, get_selection)) {
- pad_cfg->try_crop.width = 0;
- pad_cfg->try_crop.height = 0;
+ sd_state->pads->try_crop.width = 0;
+ sd_state->pads->try_crop.height = 0;
} else {
ret = v4l2_subdev_call(subdev, pad, get_selection,
NULL, &sdsel);
if (ret)
return -EINVAL;
- pad_cfg->try_crop.width = sdsel.r.width;
- pad_cfg->try_crop.height = sdsel.r.height;
+ sd_state->pads->try_crop.width = sdsel.r.width;
+ sd_state->pads->try_crop.height = sdsel.r.height;
}
} else {
- pad_cfg->try_crop.width = fse.max_width;
- pad_cfg->try_crop.height = fse.max_height;
+ sd_state->pads->try_crop.width = fse.max_width;
+ sd_state->pads->try_crop.height = fse.max_height;
}
- ret = v4l2_subdev_call(subdev, pad, set_fmt, pad_cfg, &fmt);
+ ret = v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &fmt);
if (ret < 0)
return ret;
v4l2_fill_pix_format(pix, &fmt.format);
tegra_channel_fmt_align(chan, pix, fmtinfo->bpp);
- v4l2_subdev_free_pad_config(pad_cfg);
+ v4l2_subdev_free_state(sd_state);
return 0;
}
@@ -1812,8 +1811,8 @@ static int tegra_vi_graph_parse_one(struct tegra_vi_channel *chan,
continue;
}
- tvge = v4l2_async_notifier_add_fwnode_subdev(&chan->notifier,
- remote, struct tegra_vi_graph_entity);
+ tvge = v4l2_async_notifier_add_fwnode_subdev(&chan->notifier, remote,
+ struct tegra_vi_graph_entity);
if (IS_ERR(tvge)) {
ret = PTR_ERR(tvge);
dev_err(vi->dev,
diff --git a/drivers/staging/media/zoran/zoran.h b/drivers/staging/media/zoran/zoran.h
index e7fe8da7732c..b1ad2a2b914c 100644
--- a/drivers/staging/media/zoran/zoran.h
+++ b/drivers/staging/media/zoran/zoran.h
@@ -158,7 +158,6 @@ struct zoran_jpg_settings {
struct v4l2_jpegcompression jpg_comp; /* JPEG-specific capture settings */
};
-
struct zoran;
/* zoran_fh contains per-open() settings */
diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c
index dfc60e2e9dd7..f259585b0689 100644
--- a/drivers/staging/media/zoran/zoran_card.c
+++ b/drivers/staging/media/zoran/zoran_card.c
@@ -37,9 +37,10 @@ module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(card, "Card type");
/*
- * The video mem address of the video card. The driver has a little database for some videocards
- * to determine it from there. If your video card is not in there you have either to give it to
- * the driver as a parameter or set in in a VIDIOCSFBUF ioctl
+ * The video mem address of the video card. The driver has a little database
+ * for some videocards to determine it from there. If your video card is not
+ * in there you have either to give it to the driver as a parameter or set
+ * in a VIDIOCSFBUF ioctl
*/
static unsigned long vidmem; /* default = 0 - Video memory base address */
diff --git a/drivers/staging/media/zoran/zoran_device.c b/drivers/staging/media/zoran/zoran_device.c
index cf788d9cd1df..5b12a730a229 100644
--- a/drivers/staging/media/zoran/zoran_device.c
+++ b/drivers/staging/media/zoran/zoran_device.c
@@ -148,71 +148,6 @@ int post_office_read(struct zoran *zr, unsigned int guest, unsigned int reg)
}
/*
- * detect guests
- */
-
-static void dump_guests(struct zoran *zr)
-{
- if (zr36067_debug > 2) {
- int i, guest[8];
-
- /* do not print random data */
- guest[0] = 0;
-
- for (i = 1; i < 8; i++) /* Don't read jpeg codec here */
- guest[i] = post_office_read(zr, i, 0);
-
- pci_info(zr->pci_dev, "Guests: %*ph\n", 8, guest);
- }
-}
-
-void detect_guest_activity(struct zoran *zr)
-{
- int timeout, i, j, res, guest[8], guest0[8], change[8][3];
- ktime_t t0, t1;
-
- /* do not print random data */
- guest[0] = 0;
- guest0[0] = 0;
-
- dump_guests(zr);
- pci_info(zr->pci_dev, "Detecting guests activity, please wait...\n");
- for (i = 1; i < 8; i++) /* Don't read jpeg codec here */
- guest0[i] = guest[i] = post_office_read(zr, i, 0);
-
- timeout = 0;
- j = 0;
- t0 = ktime_get();
- while (timeout < 10000) {
- udelay(10);
- timeout++;
- for (i = 1; (i < 8) && (j < 8); i++) {
- res = post_office_read(zr, i, 0);
- if (res != guest[i]) {
- t1 = ktime_get();
- change[j][0] = ktime_to_us(ktime_sub(t1, t0));
- t0 = t1;
- change[j][1] = i;
- change[j][2] = res;
- j++;
- guest[i] = res;
- }
- }
- if (j >= 8)
- break;
- }
-
- pci_info(zr->pci_dev, "Guests: %*ph\n", 8, guest0);
-
- if (j == 0) {
- pci_info(zr->pci_dev, "No activity detected.\n");
- return;
- }
- for (i = 0; i < j; i++)
- pci_info(zr->pci_dev, "%6d: %d => 0x%02x\n", change[i][0], change[i][1], change[i][2]);
-}
-
-/*
* JPEG Codec access
*/
diff --git a/drivers/staging/media/zoran/zoran_device.h b/drivers/staging/media/zoran/zoran_device.h
index 24be19a61b6d..6c5d70238228 100644
--- a/drivers/staging/media/zoran/zoran_device.h
+++ b/drivers/staging/media/zoran/zoran_device.h
@@ -20,8 +20,6 @@ extern int post_office_wait(struct zoran *zr);
extern int post_office_write(struct zoran *zr, unsigned int guest, unsigned int reg, unsigned int value);
extern int post_office_read(struct zoran *zr, unsigned int guest, unsigned int reg);
-extern void detect_guest_activity(struct zoran *zr);
-
extern void jpeg_codec_sleep(struct zoran *zr, int sleep);
extern int jpeg_codec_reset(struct zoran *zr);
diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c
index e8902f824d6c..46382e43f1bf 100644
--- a/drivers/staging/media/zoran/zoran_driver.c
+++ b/drivers/staging/media/zoran/zoran_driver.c
@@ -678,12 +678,14 @@ static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selectio
sel->r.height = zr->jpg_settings.img_height;
break;
case V4L2_SEL_TGT_CROP_DEFAULT:
- sel->r.top = sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.left = 0;
sel->r.width = BUZ_MIN_WIDTH;
sel->r.height = BUZ_MIN_HEIGHT;
break;
case V4L2_SEL_TGT_CROP_BOUNDS:
- sel->r.top = sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.left = 0;
sel->r.width = BUZ_MAX_WIDTH;
sel->r.height = BUZ_MAX_HEIGHT;
break;
diff --git a/drivers/staging/media/zoran/zr36016.c b/drivers/staging/media/zoran/zr36016.c
index 2d7dc7abde79..9b350a885879 100644
--- a/drivers/staging/media/zoran/zr36016.c
+++ b/drivers/staging/media/zoran/zr36016.c
@@ -361,7 +361,8 @@ static int zr36016_setup(struct videocodec *codec)
return -ENOSPC;
}
//mem structure init
- codec->data = ptr = kzalloc(sizeof(struct zr36016), GFP_KERNEL);
+ ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
+ codec->data = ptr;
if (!ptr)
return -ENOMEM;
diff --git a/drivers/staging/media/zoran/zr36050.c b/drivers/staging/media/zoran/zr36050.c
index 2826f4e5d37b..c62af27f2683 100644
--- a/drivers/staging/media/zoran/zr36050.c
+++ b/drivers/staging/media/zoran/zr36050.c
@@ -16,7 +16,7 @@
#include <linux/wait.h>
/* I/O commands, error codes */
-#include <asm/io.h>
+#include <linux/io.h>
/* headerfile of this module */
#include "zr36050.h"
@@ -754,7 +754,8 @@ static int zr36050_setup(struct videocodec *codec)
return -ENOSPC;
}
//mem structure init
- codec->data = ptr = kzalloc(sizeof(struct zr36050), GFP_KERNEL);
+ ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
+ codec->data = ptr;
if (!ptr)
return -ENOMEM;
diff --git a/drivers/staging/media/zoran/zr36057.h b/drivers/staging/media/zoran/zr36057.h
index 71b651add35a..a2a75fd9f535 100644
--- a/drivers/staging/media/zoran/zr36057.h
+++ b/drivers/staging/media/zoran/zr36057.h
@@ -30,13 +30,13 @@
#define ZR36057_VFESPFR_HOR_DCM 14
#define ZR36057_VFESPFR_VER_DCM 8
#define ZR36057_VFESPFR_DISP_MODE 6
-#define ZR36057_VFESPFR_YUV422 (0<<3)
-#define ZR36057_VFESPFR_RGB888 (1<<3)
-#define ZR36057_VFESPFR_RGB565 (2<<3)
-#define ZR36057_VFESPFR_RGB555 (3<<3)
-#define ZR36057_VFESPFR_ERR_DIF (1<<2)
-#define ZR36057_VFESPFR_PACK24 (1<<1)
-#define ZR36057_VFESPFR_LITTLE_ENDIAN (1<<0)
+#define ZR36057_VFESPFR_YUV422 (0 << 3)
+#define ZR36057_VFESPFR_RGB888 (1 << 3)
+#define ZR36057_VFESPFR_RGB565 (2 << 3)
+#define ZR36057_VFESPFR_RGB555 (3 << 3)
+#define ZR36057_VFESPFR_ERR_DIF (1 << 2)
+#define ZR36057_VFESPFR_PACK24 (1 << 1)
+#define ZR36057_VFESPFR_LITTLE_ENDIAN (1 << 0)
#define ZR36057_VDTR 0x00c /* Video Display "Top" Register */
diff --git a/drivers/staging/media/zoran/zr36060.c b/drivers/staging/media/zoran/zr36060.c
index 4f9eb9ff2c42..1c3af11b5f24 100644
--- a/drivers/staging/media/zoran/zr36060.c
+++ b/drivers/staging/media/zoran/zr36060.c
@@ -790,7 +790,8 @@ static int zr36060_setup(struct videocodec *codec)
return -ENOSPC;
}
//mem structure init
- codec->data = ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
+ ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
+ codec->data = ptr;
if (!ptr)
return -ENOMEM;
diff --git a/drivers/staging/most/dim2/dim2.c b/drivers/staging/most/dim2/dim2.c
index b34e3c130f53..093ef9a2b291 100644
--- a/drivers/staging/most/dim2/dim2.c
+++ b/drivers/staging/most/dim2/dim2.c
@@ -50,8 +50,10 @@ static DECLARE_TASKLET_OLD(dim2_tasklet, dim2_tasklet_fn);
/**
* struct hdm_channel - private structure to keep channel specific data
+ * @name: channel name
* @is_initialized: identifier to know whether the channel is initialized
* @ch: HAL specific channel data
+ * @reset_dbr_size: reset DBR data buffer size
* @pending_list: list to keep MBO's before starting transfer
* @started_list: list to keep MBO's after starting transfer
* @direction: channel direction (TX or RX)
@@ -68,7 +70,7 @@ struct hdm_channel {
enum most_channel_data_type data_type;
};
-/**
+/*
* struct dim2_hdm - private structure to keep interface specific data
* @hch: an array of channel specific data
* @most_iface: most interface structure
@@ -428,9 +430,9 @@ static void complete_all_mbos(struct list_head *head)
/**
* configure_channel - initialize a channel
- * @iface: interface the channel belongs to
- * @channel: channel to be configured
- * @channel_config: structure that holds the configuration information
+ * @most_iface: interface the channel belongs to
+ * @ch_idx: channel index to be configured
+ * @ccfg: structure that holds the configuration information
*
* Receives configuration information from mostcore and initialize
* the corresponding channel. Return 0 on success, negative on failure.
@@ -546,8 +548,8 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx,
/**
* enqueue - enqueue a buffer for data transfer
- * @iface: intended interface
- * @channel: ID of the channel the buffer is intended for
+ * @most_iface: intended interface
+ * @ch_idx: ID of the channel the buffer is intended for
* @mbo: pointer to the buffer object
*
* Push the buffer into pending_list and try to transfer one buffer from
@@ -579,8 +581,9 @@ static int enqueue(struct most_interface *most_iface, int ch_idx,
/**
* request_netinfo - triggers retrieving of network info
- * @iface: pointer to the interface
- * @channel_id: corresponding channel ID
+ * @most_iface: pointer to the interface
+ * @ch_idx: corresponding channel ID
+ * @on_netinfo: call-back used to deliver network status to mostcore
*
* Send a command to INIC which triggers retrieving of network info by means of
* "Message exchange over MDP/MEP". Return 0 on success, negative on failure.
@@ -621,8 +624,8 @@ static void request_netinfo(struct most_interface *most_iface, int ch_idx,
/**
* poison_channel - poison buffers of a channel
- * @iface: pointer to the interface the channel to be poisoned belongs to
- * @channel_id: corresponding channel ID
+ * @most_iface: pointer to the interface the channel to be poisoned belongs to
+ * @ch_idx: corresponding channel ID
*
* Destroy a channel and complete all the buffers in both started_list &
* pending_list. Return 0 on success, negative on failure.
diff --git a/drivers/staging/most/dim2/hal.c b/drivers/staging/most/dim2/hal.c
index 39e17a7d2f24..65282c276862 100644
--- a/drivers/staging/most/dim2/hal.c
+++ b/drivers/staging/most/dim2/hal.c
@@ -96,9 +96,9 @@ static int dbr_get_mask_size(u16 size)
}
/**
- * Allocates DBR memory.
- * @param size Allocating memory size.
- * @return Offset in DBR memory by success or DBR_SIZE if out of memory.
+ * alloc_dbr() - Allocates DBR memory.
+ * @size: Allocating memory size.
+ * Returns: Offset in DBR memory by success or DBR_SIZE if out of memory.
*/
static int alloc_dbr(u16 size)
{
@@ -778,7 +778,7 @@ void dim_service_mlb_int_irq(void)
writel(0, &g.dim2->MS1);
}
-/**
+/*
* Retrieves maximal possible correct buffer size for isochronous data type
* conform to given packet length and not bigger than given buffer size.
*
@@ -792,7 +792,7 @@ u16 dim_norm_isoc_buffer_size(u16 buf_size, u16 packet_length)
return norm_isoc_buffer_size(buf_size, packet_length);
}
-/**
+/*
* Retrieves maximal possible correct buffer size for synchronous data type
* conform to given bytes per frame and not bigger than given buffer size.
*
diff --git a/drivers/staging/most/i2c/i2c.c b/drivers/staging/most/i2c/i2c.c
index 893a8babdb2f..7042f10887bb 100644
--- a/drivers/staging/most/i2c/i2c.c
+++ b/drivers/staging/most/i2c/i2c.c
@@ -51,8 +51,8 @@ static void pending_rx_work(struct work_struct *);
/**
* configure_channel - called from MOST core to configure a channel
- * @iface: interface the channel belongs to
- * @channel: channel to be configured
+ * @most_iface: interface the channel belongs to
+ * @ch_idx: channel to be configured
* @channel_config: structure that holds the configuration information
*
* Return 0 on success, negative on failure.
@@ -107,8 +107,8 @@ static int configure_channel(struct most_interface *most_iface,
/**
* enqueue - called from MOST core to enqueue a buffer for data transfer
- * @iface: intended interface
- * @channel: ID of the channel the buffer is intended for
+ * @most_iface: intended interface
+ * @ch_idx: ID of the channel the buffer is intended for
* @mbo: pointer to the buffer object
*
* Return 0 on success, negative on failure.
@@ -153,8 +153,8 @@ static int enqueue(struct most_interface *most_iface,
/**
* poison_channel - called from MOST core to poison buffers of a channel
- * @iface: pointer to the interface the channel to be poisoned belongs to
- * @channel_id: corresponding channel ID
+ * @most_iface: pointer to the interface the channel to be poisoned belongs to
+ * @ch_idx: corresponding channel ID
*
* Return 0 on success, negative on failure.
*
diff --git a/drivers/staging/most/net/net.c b/drivers/staging/most/net/net.c
index f125bb6da406..a5fd14246046 100644
--- a/drivers/staging/most/net/net.c
+++ b/drivers/staging/most/net/net.c
@@ -539,9 +539,9 @@ static void __exit most_net_exit(void)
/**
* on_netinfo - callback for HDM to be informed about HW's MAC
- * @param iface - most interface instance
- * @param link_stat - link status
- * @param mac_addr - MAC address
+ * @iface: most interface instance
+ * @link_stat: link status
+ * @mac_addr: MAC address
*/
static void on_netinfo(struct most_interface *iface,
unsigned char link_stat, unsigned char *mac_addr)
diff --git a/drivers/staging/mt7621-dts/gbpc1.dts b/drivers/staging/mt7621-dts/gbpc1.dts
index 7716d0efe524..b65d71686814 100644
--- a/drivers/staging/mt7621-dts/gbpc1.dts
+++ b/drivers/staging/mt7621-dts/gbpc1.dts
@@ -101,12 +101,6 @@
};
&pcie {
- pinctrl-names = "default";
- pinctrl-0 = <&pcie_pins>;
-
- reset-gpios = <&gpio 19 GPIO_ACTIVE_LOW>,
- <&gpio 8 GPIO_ACTIVE_LOW>,
- <&gpio 7 GPIO_ACTIVE_LOW>;
status = "okay";
};
diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt7621-dts/mt7621.dtsi
index f0c9ae757bcd..eeabe9c0f4fb 100644
--- a/drivers/staging/mt7621-dts/mt7621.dtsi
+++ b/drivers/staging/mt7621-dts/mt7621.dtsi
@@ -55,7 +55,7 @@
#address-cells = <1>;
#size-cells = <1>;
- sysc: sysc@0 {
+ sysc: syscon@0 {
compatible = "mediatek,mt7621-sysc", "syscon";
reg = <0x0 0x100>;
#clock-cells = <1>;
@@ -122,7 +122,7 @@
status = "disabled";
};
- memc: memc@5000 {
+ memc: syscon@5000 {
compatible = "mediatek,mt7621-memc", "syscon";
reg = <0x5000 0x1000>;
};
@@ -372,13 +372,6 @@
clock-names = "nand";
};
- ethsys: syscon@1e000000 {
- compatible = "mediatek,mt7621-ethsys",
- "syscon";
- reg = <0x1e000000 0x1000>;
- #clock-cells = <1>;
- };
-
ethernet: ethernet@1e100000 {
compatible = "mediatek,mt7621-eth";
reg = <0x1e100000 0x10000>;
@@ -396,7 +389,7 @@
interrupt-parent = <&gic>;
interrupts = <GIC_SHARED 3 IRQ_TYPE_LEVEL_HIGH>;
- mediatek,ethsys = <&ethsys>;
+ mediatek,ethsys = <&sysc>;
gmac0: mac@0 {
@@ -437,6 +430,10 @@
mediatek,mcm;
resets = <&rstctrl 2>;
reset-names = "mcm";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SHARED 23 IRQ_TYPE_LEVEL_HIGH>;
ports {
#address-cells = <1>;
@@ -484,10 +481,10 @@
pcie: pcie@1e140000 {
compatible = "mediatek,mt7621-pci";
- reg = <0x1e140000 0x100 /* host-pci bridge registers */
- 0x1e142000 0x100 /* pcie port 0 RC control registers */
- 0x1e143000 0x100 /* pcie port 1 RC control registers */
- 0x1e144000 0x100>; /* pcie port 2 RC control registers */
+ reg = <0x1e140000 0x100>, /* host-pci bridge registers */
+ <0x1e142000 0x100>, /* pcie port 0 RC control registers */
+ <0x1e143000 0x100>, /* pcie port 1 RC control registers */
+ <0x1e144000 0x100>; /* pcie port 2 RC control registers */
#address-cells = <3>;
#size-cells = <2>;
@@ -496,64 +493,76 @@
device_type = "pci";
- bus-range = <0 255>;
- ranges = <
- 0x02000000 0 0x00000000 0x60000000 0 0x10000000 /* pci memory */
- 0x01000000 0 0x00000000 0x1e160000 0 0x00010000 /* io space */
- >;
+ ranges = <0x02000000 0 0x60000000 0x60000000 0 0x10000000>, /* pci memory */
+ <0x01000000 0 0x00000000 0x1e160000 0 0x00010000>; /* io space */
- interrupt-parent = <&gic>;
- interrupts = <GIC_SHARED 4 IRQ_TYPE_LEVEL_HIGH
- GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH
- GIC_SHARED 25 IRQ_TYPE_LEVEL_HIGH>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xF800 0 0 0>;
+ interrupt-map = <0x0000 0 0 0 &gic GIC_SHARED 4 IRQ_TYPE_LEVEL_HIGH>,
+ <0x0800 0 0 0 &gic GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH>,
+ <0x1000 0 0 0 &gic GIC_SHARED 25 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
- resets = <&rstctrl 24 &rstctrl 25 &rstctrl 26>;
- reset-names = "pcie0", "pcie1", "pcie2";
- clocks = <&sysc MT7621_CLK_PCIE0>,
- <&sysc MT7621_CLK_PCIE1>,
- <&sysc MT7621_CLK_PCIE2>;
- clock-names = "pcie0", "pcie1", "pcie2";
- phys = <&pcie0_phy 1>, <&pcie2_phy 0>;
- phy-names = "pcie-phy0", "pcie-phy2";
-
reset-gpios = <&gpio 19 GPIO_ACTIVE_LOW>;
pcie@0,0 {
reg = <0x0000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &gic GIC_SHARED 4 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&rstctrl 24>;
+ clocks = <&sysc MT7621_CLK_PCIE0>;
+ phys = <&pcie0_phy 1>;
+ phy-names = "pcie-phy0";
ranges;
- bus-range = <0x00 0xff>;
};
pcie@1,0 {
reg = <0x0800 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &gic GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&rstctrl 25>;
+ clocks = <&sysc MT7621_CLK_PCIE1>;
+ phys = <&pcie0_phy 1>;
+ phy-names = "pcie-phy1";
ranges;
- bus-range = <0x00 0xff>;
};
pcie@2,0 {
reg = <0x1000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &gic GIC_SHARED 25 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&rstctrl 26>;
+ clocks = <&sysc MT7621_CLK_PCIE2>;
+ phys = <&pcie2_phy 0>;
+ phy-names = "pcie-phy2";
ranges;
- bus-range = <0x00 0xff>;
};
};
pcie0_phy: pcie-phy@1e149000 {
compatible = "mediatek,mt7621-pci-phy";
reg = <0x1e149000 0x0700>;
+ clocks = <&sysc MT7621_CLK_XTAL>;
#phy-cells = <1>;
};
pcie2_phy: pcie-phy@1e14a000 {
compatible = "mediatek,mt7621-pci-phy";
reg = <0x1e14a000 0x0700>;
+ clocks = <&sysc MT7621_CLK_XTAL>;
#phy-cells = <1>;
};
};
diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c
index 115250115f10..691030e1a5ed 100644
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
@@ -16,13 +16,12 @@
*/
#include <linux/bitops.h>
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
-#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_irq.h>
#include <linux/of_pci.h>
#include <linux/of_platform.h>
#include <linux/pci.h>
@@ -30,22 +29,12 @@
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/sys_soc.h>
-#include <mt7621.h>
-#include <ralink_regs.h>
-
-#include "../../pci/pci.h"
-
-/* sysctl */
-#define MT7621_GPIO_MODE 0x60
/* 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)
-/* rt_sysc_membase relative registers */
-#define RALINK_CLKCFG1 0x30
-
/* Host-PCI bridge registers */
#define RALINK_PCI_PCICFG_ADDR 0x0000
#define RALINK_PCI_PCIMSK_ADDR 0x000C
@@ -54,20 +43,7 @@
#define RALINK_PCI_MEMBASE 0x0028
#define RALINK_PCI_IOBASE 0x002C
-/* PCICFG virtual bridges */
-#define PCIE_P2P_CNT 3
-#define PCIE_P2P_BR_DEVNUM_SHIFT(p) (16 + (p) * 4)
-#define PCIE_P2P_BR_DEVNUM0_SHIFT PCIE_P2P_BR_DEVNUM_SHIFT(0)
-#define PCIE_P2P_BR_DEVNUM1_SHIFT PCIE_P2P_BR_DEVNUM_SHIFT(1)
-#define PCIE_P2P_BR_DEVNUM2_SHIFT PCIE_P2P_BR_DEVNUM_SHIFT(2)
-#define PCIE_P2P_BR_DEVNUM_MASK 0xf
-#define PCIE_P2P_BR_DEVNUM_MASK_FULL (0xfff << PCIE_P2P_BR_DEVNUM0_SHIFT)
-
/* PCIe RC control registers */
-#define MT7621_PCIE_OFFSET 0x2000
-#define MT7621_NEXT_PORT 0x1000
-
-#define RALINK_PCI_BAR0SETUP_ADDR 0x0010
#define RALINK_PCI_ID 0x0030
#define RALINK_PCI_CLASS 0x0034
#define RALINK_PCI_SUBID 0x0038
@@ -79,11 +55,8 @@
#define PCIE_BAR_MAP_MAX GENMASK(30, 16)
#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_LINKUP BIT(0)
-#define PERST_MODE_MASK GENMASK(11, 10)
-#define PERST_MODE_GPIO BIT(10)
#define PERST_DELAY_MS 100
/**
@@ -91,76 +64,68 @@
* @base: I/O mapped register base
* @list: port list
* @pcie: pointer to PCIe host info
+ * @clk: pointer to the port clock gate
* @phy: pointer to PHY control block
* @pcie_rst: pointer to port reset control
* @gpio_rst: gpio reset
* @slot: port slot
- * @irq: GIC irq
* @enabled: indicates if port is enabled
*/
struct mt7621_pcie_port {
void __iomem *base;
struct list_head list;
struct mt7621_pcie *pcie;
+ struct clk *clk;
struct phy *phy;
struct reset_control *pcie_rst;
struct gpio_desc *gpio_rst;
u32 slot;
- int irq;
bool enabled;
};
/**
* struct mt7621_pcie - PCIe host information
* @base: IO Mapped Register Base
- * @io: IO resource
- * @mem: pointer to non-prefetchable memory resource
* @dev: Pointer to PCIe device
- * @io_map_base: virtual memory base address for io
* @ports: pointer to PCIe port information
- * @irq_map: irq mapping info according pcie link status
* @resets_inverted: depends on chip revision
* reset lines are inverted.
*/
struct mt7621_pcie {
void __iomem *base;
struct device *dev;
- struct resource io;
- struct resource *mem;
- unsigned long io_map_base;
struct list_head ports;
- int irq_map[PCIE_P2P_CNT];
bool resets_inverted;
};
static inline u32 pcie_read(struct mt7621_pcie *pcie, u32 reg)
{
- return readl(pcie->base + reg);
+ return readl_relaxed(pcie->base + reg);
}
static inline void pcie_write(struct mt7621_pcie *pcie, u32 val, u32 reg)
{
- writel(val, pcie->base + reg);
+ writel_relaxed(val, pcie->base + reg);
}
static inline void pcie_rmw(struct mt7621_pcie *pcie, u32 reg, u32 clr, u32 set)
{
- u32 val = readl(pcie->base + reg);
+ u32 val = readl_relaxed(pcie->base + reg);
val &= ~clr;
val |= set;
- writel(val, pcie->base + reg);
+ writel_relaxed(val, pcie->base + reg);
}
static inline u32 pcie_port_read(struct mt7621_pcie_port *port, u32 reg)
{
- return readl(port->base + reg);
+ return readl_relaxed(port->base + reg);
}
static inline void pcie_port_write(struct mt7621_pcie_port *port,
u32 val, u32 reg)
{
- writel(val, port->base + reg);
+ writel_relaxed(val, port->base + reg);
}
static inline u32 mt7621_pci_get_cfgaddr(unsigned int bus, unsigned int slot,
@@ -177,7 +142,7 @@ static void __iomem *mt7621_pcie_map_bus(struct pci_bus *bus,
u32 address = mt7621_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn),
PCI_FUNC(devfn), where);
- writel(address, pcie->base + RALINK_PCI_CONFIG_ADDR);
+ writel_relaxed(address, pcie->base + RALINK_PCI_CONFIG_ADDR);
return pcie->base + RALINK_PCI_CONFIG_DATA + (where & 3);
}
@@ -222,16 +187,6 @@ 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_enable(struct mt7621_pcie_port *port)
-{
- rt_sysc_m32(0, PCIE_PORT_CLK_EN(port->slot), RALINK_CLKCFG1);
-}
-
-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)
{
struct mt7621_pcie *pcie = port->pcie;
@@ -252,96 +207,46 @@ static inline void mt7621_control_deassert(struct mt7621_pcie_port *port)
reset_control_assert(port->pcie_rst);
}
-static void setup_cm_memory_region(struct mt7621_pcie *pcie)
+static int setup_cm_memory_region(struct pci_host_bridge *host)
{
- struct resource *mem_resource = pcie->mem;
+ struct mt7621_pcie *pcie = pci_host_bridge_priv(host);
struct device *dev = pcie->dev;
+ struct resource_entry *entry;
resource_size_t mask;
+ entry = resource_list_first_type(&host->windows, IORESOURCE_MEM);
+ if (!entry) {
+ dev_err(dev, "Cannot get memory resource\n");
+ return -EINVAL;
+ }
+
if (mips_cps_numiocu(0)) {
/*
* FIXME: hardware doesn't accept mask values with 1s after
* 0s (e.g. 0xffef), so it would be great to warn if that's
* about to happen
*/
- mask = ~(mem_resource->end - mem_resource->start);
+ mask = ~(entry->res->end - entry->res->start);
- write_gcr_reg1_base(mem_resource->start);
+ write_gcr_reg1_base(entry->res->start);
write_gcr_reg1_mask(mask | CM_GCR_REGn_MASK_CMTGT_IOCU0);
dev_info(dev, "PCI coherence region base: 0x%08llx, mask/settings: 0x%08llx\n",
(unsigned long long)read_gcr_reg1_base(),
(unsigned long long)read_gcr_reg1_mask());
}
-}
-
-static int mt7621_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
-{
- struct mt7621_pcie *pcie = pdev->bus->sysdata;
- struct device *dev = pcie->dev;
- int irq = pcie->irq_map[slot];
-
- dev_info(dev, "bus=%d slot=%d irq=%d\n", pdev->bus->number, slot, irq);
- return irq;
-}
-
-static int mt7621_pci_parse_request_of_pci_ranges(struct pci_host_bridge *host)
-{
- struct mt7621_pcie *pcie = pci_host_bridge_priv(host);
- struct device *dev = pcie->dev;
- struct device_node *node = dev->of_node;
- struct of_pci_range_parser parser;
- struct resource_entry *entry;
- struct of_pci_range range;
- LIST_HEAD(res);
-
- if (of_pci_range_parser_init(&parser, node)) {
- dev_err(dev, "missing \"ranges\" property\n");
- return -EINVAL;
- }
-
- /*
- * IO_SPACE_LIMIT for MIPS is 0xffff but this platform uses IO at
- * upper address 0x001e160000. of_pci_range_to_resource does not work
- * well for MIPS platforms that don't define PCI_IOBASE, so set the IO
- * resource manually instead.
- */
- pcie->io.name = node->full_name;
- pcie->io.parent = pcie->io.child = pcie->io.sibling = NULL;
- for_each_of_pci_range(&parser, &range) {
- switch (range.flags & IORESOURCE_TYPE_BITS) {
- case IORESOURCE_IO:
- pcie->io_map_base =
- (unsigned long)ioremap(range.cpu_addr,
- range.size);
- pcie->io.flags = range.flags;
- pcie->io.start = range.cpu_addr;
- pcie->io.end = range.cpu_addr + range.size - 1;
- set_io_port_base(pcie->io_map_base);
- break;
- }
- }
-
- entry = resource_list_first_type(&host->windows, IORESOURCE_MEM);
- if (!entry) {
- dev_err(dev, "Cannot get memory resource");
- return -EINVAL;
- }
-
- pcie->mem = entry->res;
- pci_add_resource(&res, &pcie->io);
- pci_add_resource(&res, entry->res);
- list_splice_init(&res, &host->windows);
return 0;
}
static int mt7621_pcie_parse_port(struct mt7621_pcie *pcie,
+ struct device_node *node,
int slot)
{
struct mt7621_pcie_port *port;
struct device *dev = pcie->dev;
struct platform_device *pdev = to_platform_device(dev);
char name[10];
+ int err;
port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
if (!port)
@@ -351,38 +256,45 @@ static int mt7621_pcie_parse_port(struct mt7621_pcie *pcie,
if (IS_ERR(port->base))
return PTR_ERR(port->base);
- snprintf(name, sizeof(name), "pcie%d", slot);
- port->pcie_rst = devm_reset_control_get_exclusive(dev, name);
+ port->clk = devm_get_clk_from_child(dev, node, NULL);
+ if (IS_ERR(port->clk)) {
+ dev_err(dev, "failed to get pcie%d clock\n", slot);
+ return PTR_ERR(port->clk);
+ }
+
+ port->pcie_rst = of_reset_control_get_exclusive(node, NULL);
if (PTR_ERR(port->pcie_rst) == -EPROBE_DEFER) {
dev_err(dev, "failed to get pcie%d reset control\n", slot);
return PTR_ERR(port->pcie_rst);
}
snprintf(name, sizeof(name), "pcie-phy%d", slot);
- port->phy = devm_phy_get(dev, name);
- if (IS_ERR(port->phy) && slot != 1)
- return PTR_ERR(port->phy);
+ port->phy = devm_of_phy_get(dev, node, name);
+ if (IS_ERR(port->phy)) {
+ dev_err(dev, "failed to get pcie-phy%d\n", slot);
+ err = PTR_ERR(port->phy);
+ goto remove_reset;
+ }
port->gpio_rst = devm_gpiod_get_index_optional(dev, "reset", slot,
GPIOD_OUT_LOW);
if (IS_ERR(port->gpio_rst)) {
dev_err(dev, "Failed to get GPIO for PCIe%d\n", slot);
- return PTR_ERR(port->gpio_rst);
+ err = PTR_ERR(port->gpio_rst);
+ goto remove_reset;
}
port->slot = slot;
port->pcie = pcie;
- port->irq = platform_get_irq(pdev, slot);
- if (port->irq < 0) {
- dev_err(dev, "Failed to get IRQ for PCIe%d\n", slot);
- return -ENXIO;
- }
-
INIT_LIST_HEAD(&port->list);
list_add_tail(&port->list, &pcie->ports);
return 0;
+
+remove_reset:
+ reset_control_put(port->pcie_rst);
+ return err;
}
static int mt7621_pcie_parse_dt(struct mt7621_pcie *pcie)
@@ -408,7 +320,7 @@ static int mt7621_pcie_parse_dt(struct mt7621_pcie *pcie)
slot = PCI_SLOT(err);
- err = mt7621_pcie_parse_port(pcie, slot);
+ err = mt7621_pcie_parse_port(pcie, child, slot);
if (err) {
of_node_put(child);
return err;
@@ -455,7 +367,7 @@ static void mt7621_pcie_reset_assert(struct mt7621_pcie *pcie)
mt7621_rst_gpio_pcie_assert(port);
}
- mdelay(PERST_DELAY_MS);
+ msleep(PERST_DELAY_MS);
}
static void mt7621_pcie_reset_rc_deassert(struct mt7621_pcie *pcie)
@@ -473,7 +385,7 @@ static void mt7621_pcie_reset_ep_deassert(struct mt7621_pcie *pcie)
list_for_each_entry(port, &pcie->ports, list)
mt7621_rst_gpio_pcie_deassert(port);
- mdelay(PERST_DELAY_MS);
+ msleep(PERST_DELAY_MS);
}
static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
@@ -482,8 +394,6 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
struct mt7621_pcie_port *port, *tmp;
int err;
- rt_sysc_m32(PERST_MODE_MASK, PERST_MODE_GPIO, MT7621_GPIO_MODE);
-
mt7621_pcie_reset_assert(pcie);
mt7621_pcie_reset_rc_deassert(pcie);
@@ -512,7 +422,7 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n",
slot);
mt7621_control_assert(port);
- mt7621_pcie_port_clk_disable(port);
+ clk_disable_unprepare(port->clk);
port->enabled = false;
if (slot == 0) {
@@ -530,7 +440,6 @@ 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;
/* enable pcie interrupt */
@@ -539,95 +448,52 @@ static void mt7621_pcie_enable_port(struct mt7621_pcie_port *port)
pcie_write(pcie, val, RALINK_PCI_PCIMSK_ADDR);
/* map 2G DDR region */
- pcie_write(pcie, PCIE_BAR_MAP_MAX | PCIE_BAR_ENABLE,
- offset + RALINK_PCI_BAR0SETUP_ADDR);
+ pcie_port_write(port, PCIE_BAR_MAP_MAX | PCIE_BAR_ENABLE,
+ PCI_BASE_ADDRESS_0);
/* configure class code and revision ID */
- pcie_write(pcie, PCIE_CLASS_CODE | PCIE_REVISION_ID,
- offset + RALINK_PCI_CLASS);
+ pcie_port_write(port, PCIE_CLASS_CODE | PCIE_REVISION_ID,
+ RALINK_PCI_CLASS);
+
+ /* configure RC FTS number to 250 when it leaves L0s */
+ val = read_config(pcie, slot, PCIE_FTS_NUM);
+ val &= ~PCIE_FTS_NUM_MASK;
+ val |= PCIE_FTS_NUM_L0(0x50);
+ write_config(pcie, slot, PCIE_FTS_NUM, val);
}
-static void mt7621_pcie_enable_ports(struct mt7621_pcie *pcie)
+static int mt7621_pcie_enable_ports(struct pci_host_bridge *host)
{
+ struct mt7621_pcie *pcie = pci_host_bridge_priv(host);
struct device *dev = pcie->dev;
struct mt7621_pcie_port *port;
- u8 num_slots_enabled = 0;
- u32 slot;
- u32 val;
+ struct resource_entry *entry;
+ int err;
+
+ entry = resource_list_first_type(&host->windows, IORESOURCE_IO);
+ if (!entry) {
+ dev_err(dev, "Cannot get io resource\n");
+ return -EINVAL;
+ }
/* Setup MEMWIN and IOWIN */
pcie_write(pcie, 0xffffffff, RALINK_PCI_MEMBASE);
- pcie_write(pcie, pcie->io.start, RALINK_PCI_IOBASE);
+ pcie_write(pcie, entry->res->start, RALINK_PCI_IOBASE);
list_for_each_entry(port, &pcie->ports, list) {
if (port->enabled) {
- mt7621_pcie_port_clk_enable(port);
+ err = clk_prepare_enable(port->clk);
+ if (err) {
+ dev_err(dev, "enabling clk pcie%d\n",
+ port->slot);
+ return err;
+ }
+
mt7621_pcie_enable_port(port);
dev_info(dev, "PCIE%d enabled\n", port->slot);
- num_slots_enabled++;
}
}
- for (slot = 0; slot < num_slots_enabled; slot++) {
- val = read_config(pcie, slot, PCI_COMMAND);
- val |= PCI_COMMAND_MASTER;
- write_config(pcie, slot, PCI_COMMAND, val);
- /* configure RC FTS number to 250 when it leaves L0s */
- val = read_config(pcie, slot, PCIE_FTS_NUM);
- val &= ~PCIE_FTS_NUM_MASK;
- val |= PCIE_FTS_NUM_L0(0x50);
- write_config(pcie, slot, PCIE_FTS_NUM, val);
- }
-}
-
-static int mt7621_pcie_init_virtual_bridges(struct mt7621_pcie *pcie)
-{
- u32 pcie_link_status = 0;
- u32 n = 0;
- int i = 0;
- u32 p2p_br_devnum[PCIE_P2P_CNT];
- int irqs[PCIE_P2P_CNT];
- struct mt7621_pcie_port *port;
-
- list_for_each_entry(port, &pcie->ports, list) {
- u32 slot = port->slot;
-
- irqs[i++] = port->irq;
- if (port->enabled)
- pcie_link_status |= BIT(slot);
- }
-
- if (pcie_link_status == 0)
- return -1;
-
- /*
- * Assign device numbers from zero to the enabled ports,
- * then assigning remaining device numbers to any disabled
- * ports.
- */
- for (i = 0; i < PCIE_P2P_CNT; i++)
- if (pcie_link_status & BIT(i))
- p2p_br_devnum[i] = n++;
-
- for (i = 0; i < PCIE_P2P_CNT; i++)
- if ((pcie_link_status & BIT(i)) == 0)
- p2p_br_devnum[i] = n++;
-
- pcie_rmw(pcie, RALINK_PCI_PCICFG_ADDR,
- PCIE_P2P_BR_DEVNUM_MASK_FULL,
- (p2p_br_devnum[0] << PCIE_P2P_BR_DEVNUM0_SHIFT) |
- (p2p_br_devnum[1] << PCIE_P2P_BR_DEVNUM1_SHIFT) |
- (p2p_br_devnum[2] << PCIE_P2P_BR_DEVNUM2_SHIFT));
-
- /* Assign IRQs */
- n = 0;
- for (i = 0; i < PCIE_P2P_CNT; i++)
- if (pcie_link_status & BIT(i))
- pcie->irq_map[n++] = irqs[i];
-
- for (i = n; i < PCIE_P2P_CNT; i++)
- pcie->irq_map[i] = -1;
-
return 0;
}
@@ -636,9 +502,7 @@ static int mt7621_pcie_register_host(struct pci_host_bridge *host)
struct mt7621_pcie *pcie = pci_host_bridge_priv(host);
host->ops = &mt7621_pci_ops;
- host->map_irq = mt7621_map_irq;
host->sysdata = pcie;
-
return pci_host_probe(host);
}
@@ -650,6 +514,7 @@ static int mt7621_pci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct soc_device_attribute *attr;
+ struct mt7621_pcie_port *port;
struct mt7621_pcie *pcie;
struct pci_host_bridge *bridge;
int err;
@@ -676,33 +541,36 @@ static int mt7621_pci_probe(struct platform_device *pdev)
return err;
}
- err = mt7621_pci_parse_request_of_pci_ranges(bridge);
+ mt7621_pcie_init_ports(pcie);
+
+ err = mt7621_pcie_enable_ports(bridge);
if (err) {
- dev_err(dev, "Error requesting pci resources from ranges");
- return err;
+ dev_err(dev, "Error enabling pcie ports\n");
+ goto remove_resets;
}
- /* set resources limits */
- ioport_resource.start = pcie->io.start;
- ioport_resource.end = pcie->io.end;
-
- mt7621_pcie_init_ports(pcie);
-
- err = mt7621_pcie_init_virtual_bridges(pcie);
+ err = setup_cm_memory_region(bridge);
if (err) {
- dev_err(dev, "Nothing is connected in virtual bridges. Exiting...");
- return 0;
+ dev_err(dev, "Error setting up iocu mem regions\n");
+ goto remove_resets;
}
- mt7621_pcie_enable_ports(pcie);
+ return mt7621_pcie_register_host(bridge);
- setup_cm_memory_region(pcie);
+remove_resets:
+ list_for_each_entry(port, &pcie->ports, list)
+ reset_control_put(port->pcie_rst);
- err = mt7621_pcie_register_host(bridge);
- if (err) {
- dev_err(dev, "Error registering host\n");
- return err;
- }
+ return err;
+}
+
+static int mt7621_pci_remove(struct platform_device *pdev)
+{
+ struct mt7621_pcie *pcie = platform_get_drvdata(pdev);
+ struct mt7621_pcie_port *port;
+
+ list_for_each_entry(port, &pcie->ports, list)
+ reset_control_put(port->pcie_rst);
return 0;
}
@@ -715,10 +583,10 @@ MODULE_DEVICE_TABLE(of, mt7621_pci_ids);
static struct platform_driver mt7621_pci_driver = {
.probe = mt7621_pci_probe,
+ .remove = mt7621_pci_remove,
.driver = {
.name = "mt7621-pci",
.of_match_table = of_match_ptr(mt7621_pci_ids),
},
};
-
builtin_platform_driver(mt7621_pci_driver);
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index a80996b2f5ce..990d15c31a13 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -99,6 +99,7 @@ static const struct mfd_cell nvec_devices[] = {
* nvec_register_notifier - Register a notifier with nvec
* @nvec: A &struct nvec_chip
* @nb: The notifier block to register
+ * @events: Unused
*
* Registers a notifier with @nvec. The notifier will be added to an atomic
* notifier chain that is called for all received messages except those that
@@ -125,7 +126,7 @@ int nvec_unregister_notifier(struct nvec_chip *nvec, struct notifier_block *nb)
}
EXPORT_SYMBOL_GPL(nvec_unregister_notifier);
-/**
+/*
* nvec_status_notifier - The final notifier
*
* Prints a message about control events not handled in the notifier
@@ -343,8 +344,8 @@ static void nvec_toggle_global_events(struct nvec_chip *nvec, bool state)
/**
* nvec_event_mask - fill the command string with event bitfield
- * ev: points to event command string
- * mask: bit to insert into the event mask
+ * @ev: points to event command string
+ * @mask: bit to insert into the event mask
*
* Configure event command expects a 32 bit bitfield which describes
* which events to enable. The bitfield has the following structure
diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
index f27f20a4aa2d..a1cd81d4a114 100644
--- a/drivers/staging/octeon-usb/octeon-hcd.c
+++ b/drivers/staging/octeon-usb/octeon-hcd.c
@@ -50,8 +50,10 @@
#include <linux/module.h>
#include <linux/usb/hcd.h>
#include <linux/prefetch.h>
+#include <linux/irqdomain.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
#include <asm/octeon/octeon.h>
diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c
index 9c71ad5af7b9..1ad94c5060b5 100644
--- a/drivers/staging/octeon/ethernet-tx.c
+++ b/drivers/staging/octeon/ethernet-tx.c
@@ -504,7 +504,6 @@ skip_xmit:
* cvm_oct_xmit_pow - transmit a packet to the POW
* @skb: Packet to send
* @dev: Device info structure
-
* Returns Always returns zero
*/
int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev)
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c
index 6d8e9a481786..7284cb4ac395 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon.c
@@ -22,6 +22,7 @@
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/ctype.h>
+#include <linux/panic_notifier.h>
#include <linux/reboot.h>
#include <linux/olpc-ec.h>
#include <asm/tsc.h>
diff --git a/drivers/staging/qlge/qlge_ethtool.c b/drivers/staging/qlge/qlge_ethtool.c
index b70570b7b467..87d60115ac67 100644
--- a/drivers/staging/qlge/qlge_ethtool.c
+++ b/drivers/staging/qlge/qlge_ethtool.c
@@ -553,7 +553,7 @@ static int qlge_run_loopback_test(struct qlge_adapter *qdev)
atomic_inc(&qdev->lb_count);
}
/* Give queue time to settle before testing results. */
- msleep(2);
+ usleep_range(2000, 2100);
qlge_clean_lb_rx_ring(&qdev->rx_ring[0], 128);
return atomic_read(&qdev->lb_count) ? -EIO : 0;
}
diff --git a/drivers/staging/qlge/qlge_main.c b/drivers/staging/qlge/qlge_main.c
index c9dc6a852af4..19a02e958865 100644
--- a/drivers/staging/qlge/qlge_main.c
+++ b/drivers/staging/qlge/qlge_main.c
@@ -1389,7 +1389,7 @@ static void qlge_categorize_rx_err(struct qlge_adapter *qdev, u8 rx_err,
}
}
-/**
+/*
* qlge_update_mac_hdr_len - helper routine to update the mac header length
* based on vlan tags if present
*/
@@ -2235,7 +2235,7 @@ static void qlge_vlan_mode(struct net_device *ndev, netdev_features_t features)
}
}
-/**
+/*
* qlge_update_hw_vlan_features - helper routine to reinitialize the adapter
* based on the features to enable/disable hardware vlan accel
*/
@@ -2796,12 +2796,8 @@ static int qlge_init_bq(struct qlge_bq *bq)
bq->base = dma_alloc_coherent(&qdev->pdev->dev, QLGE_BQ_SIZE,
&bq->base_dma, GFP_ATOMIC);
- if (!bq->base) {
- netif_err(qdev, ifup, qdev->ndev,
- "ring %u %s allocation failed.\n", rx_ring->cq_id,
- bq_type_name[bq->type]);
+ if (!bq->base)
return -ENOMEM;
- }
bq->queue = kmalloc_array(QLGE_BQ_LEN, sizeof(struct qlge_bq_desc),
GFP_KERNEL);
diff --git a/drivers/staging/rtl8188eu/Makefile b/drivers/staging/rtl8188eu/Makefile
index 7da911c2ab89..28b936e8be0a 100644
--- a/drivers/staging/rtl8188eu/Makefile
+++ b/drivers/staging/rtl8188eu/Makefile
@@ -2,7 +2,6 @@
r8188eu-y := \
core/rtw_ap.o \
core/rtw_cmd.o \
- core/rtw_debug.o \
core/rtw_efuse.o \
core/rtw_ieee80211.o \
core/rtw_ioctl_set.o \
diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c
index 008b60e72758..b817aa8b9de4 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ap.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ap.c
@@ -164,9 +164,9 @@ static u8 chk_sta_is_alive(struct sta_info *psta)
void expire_timeout_chk(struct adapter *padapter)
{
- struct list_head *phead, *plist;
+ struct list_head *phead;
u8 updated = 0;
- struct sta_info *psta = NULL;
+ struct sta_info *psta, *temp;
struct sta_priv *pstapriv = &padapter->stapriv;
u8 chk_alive_num = 0;
char chk_alive_list[NUM_STA];
@@ -175,22 +175,14 @@ void expire_timeout_chk(struct adapter *padapter)
spin_lock_bh(&pstapriv->auth_list_lock);
phead = &pstapriv->auth_list;
- plist = phead->next;
-
/* check auth_queue */
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, auth_list);
- plist = plist->next;
-
+ list_for_each_entry_safe(psta, temp, phead, auth_list) {
if (psta->expire_to > 0) {
psta->expire_to--;
if (psta->expire_to == 0) {
list_del_init(&psta->auth_list);
pstapriv->auth_list_cnt--;
- DBG_88E("auth expire %6ph\n",
- psta->hwaddr);
-
spin_unlock_bh(&pstapriv->auth_list_lock);
spin_lock_bh(&pstapriv->sta_hash_lock);
@@ -208,13 +200,8 @@ void expire_timeout_chk(struct adapter *padapter)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = phead->next;
-
/* check asoc_queue */
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, asoc_list);
- plist = plist->next;
-
+ list_for_each_entry_safe(psta, temp, phead, asoc_list) {
if (chk_sta_is_alive(psta) || !psta->expire_to) {
psta->expire_to = pstapriv->expire_to;
psta->keep_alive_trycnt = 0;
@@ -264,20 +251,13 @@ void expire_timeout_chk(struct adapter *padapter)
list_del_init(&psta->asoc_list);
pstapriv->asoc_list_cnt--;
- DBG_88E("asoc expire %pM, state = 0x%x\n",
- (psta->hwaddr), psta->state);
updated = ap_free_sta(padapter, psta, true,
WLAN_REASON_DEAUTH_LEAVING);
} else {
/* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */
if (psta->sleepq_len > (NR_XMITFRAME / pstapriv->asoc_list_cnt) &&
- padapter->xmitpriv.free_xmitframe_cnt < (NR_XMITFRAME / pstapriv->asoc_list_cnt / 2)) {
- DBG_88E("%s sta:%pM, sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__,
- (psta->hwaddr), psta->sleepq_len,
- padapter->xmitpriv.free_xmitframe_cnt,
- pstapriv->asoc_list_cnt);
+ padapter->xmitpriv.free_xmitframe_cnt < (NR_XMITFRAME / pstapriv->asoc_list_cnt / 2))
wakeup_sta_to_xmit(padapter, psta);
- }
}
}
@@ -309,21 +289,16 @@ void expire_timeout_chk(struct adapter *padapter)
psta->keep_alive_trycnt++;
if (ret == _SUCCESS) {
- DBG_88E("asoc check, sta(%pM) is alive\n",
- (psta->hwaddr));
psta->expire_to = pstapriv->expire_to;
psta->keep_alive_trycnt = 0;
continue;
} else if (psta->keep_alive_trycnt <= 3) {
- DBG_88E("ack check for asoc expire, keep_alive_trycnt =%d\n", psta->keep_alive_trycnt);
psta->expire_to = 1;
continue;
}
psta->keep_alive_trycnt = 0;
- DBG_88E("asoc expire %pM, state = 0x%x\n",
- psta->hwaddr, psta->state);
spin_lock_bh(&pstapriv->asoc_list_lock);
list_del_init(&psta->asoc_list);
pstapriv->asoc_list_cnt--;
@@ -394,9 +369,6 @@ void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
tx_ra_bitmap |= ((raid << 28) & 0xf0000000);
- DBG_88E("%s => mac_id:%d , raid:%d , bitmap = 0x%x, arg = 0x%x\n",
- __func__, psta->mac_id, raid, tx_ra_bitmap, arg);
-
/* bitmap[0:27] = tx_rate_bitmap */
/* bitmap[28:31]= Rate Adaptive id */
/* arg[0:4] = macid */
@@ -410,8 +382,6 @@ void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
psta->raid = raid;
psta->init_rate = init_rate;
- } else {
- DBG_88E("station aid %d exceed the max number\n", psta->aid);
}
}
@@ -467,8 +437,6 @@ static void update_bmc_sta(struct adapter *padapter)
arg = psta->mac_id & 0x1f;
arg |= BIT(7);
tx_ra_bitmap |= ((raid << 28) & 0xf0000000);
- DBG_88E("%s, mask = 0x%x, arg = 0x%x\n", __func__,
- tx_ra_bitmap, arg);
/* bitmap[0:27] = tx_rate_bitmap */
/* bitmap[28:31]= Rate Adaptive id */
@@ -486,8 +454,6 @@ static void update_bmc_sta(struct adapter *padapter)
psta->state = _FW_LINKED;
spin_unlock_bh(&psta->lock);
- } else {
- DBG_88E("add_RATid_bmc_sta error!\n");
}
}
@@ -582,8 +548,6 @@ static void update_hw_ht_param(struct adapter *padapter)
/* Config SM Power Save setting */
pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.cap_info) & 0x0C) >> 2;
- if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC)
- DBG_88E("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__);
}
static void start_bss_network(struct adapter *padapter, u8 *pbuf)
@@ -695,9 +659,6 @@ static void start_bss_network(struct adapter *padapter, u8 *pbuf)
*/
set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode);
- DBG_88E("CH =%d, BW =%d, offset =%d\n", cur_channel, cur_bwmode,
- cur_ch_offset);
-
/* */
pmlmeext->cur_channel = cur_channel;
pmlmeext->cur_bwmode = cur_bwmode;
@@ -717,8 +678,7 @@ static void start_bss_network(struct adapter *padapter, u8 *pbuf)
update_beacon(padapter, WLAN_EID_TIM, NULL, false);
/* issue beacon frame */
- if (send_beacon(padapter) == _FAIL)
- DBG_88E("send_beacon, fail!\n");
+ send_beacon(padapter);
}
/* update bc/mc sta_info */
@@ -756,8 +716,6 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
/* ht_capab, ht_oper */
/* WPS IE */
- DBG_88E("%s, len =%d\n", __func__, len);
-
if (!check_fwstate(pmlmepriv, WIFI_AP_STATE))
return _FAIL;
@@ -1009,8 +967,6 @@ void rtw_set_macaddr_acl(struct adapter *padapter, int mode)
struct sta_priv *pstapriv = &padapter->stapriv;
struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
- DBG_88E("%s, mode =%d\n", __func__, mode);
-
pacl_list->mode = mode;
}
@@ -1024,24 +980,18 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
struct __queue *pacl_node_q = &pacl_list->acl_node_q;
- DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr));
-
if ((NUM_ACL - 1) < pacl_list->num)
return -1;
spin_lock_bh(&pacl_node_q->lock);
phead = get_list_head(pacl_node_q);
- plist = phead->next;
-
- while (phead != plist) {
- paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
- plist = plist->next;
+ list_for_each(plist, phead) {
+ paclnode = list_entry(plist, struct rtw_wlan_acl_node, list);
if (!memcmp(paclnode->addr, addr, ETH_ALEN)) {
if (paclnode->valid) {
added = true;
- DBG_88E("%s, sta has been added\n", __func__);
break;
}
}
@@ -1072,8 +1022,6 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
}
}
- DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num);
-
spin_unlock_bh(&pacl_node_q->lock);
return ret;
@@ -1081,23 +1029,16 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
{
- struct list_head *plist, *phead;
- struct rtw_wlan_acl_node *paclnode;
+ struct list_head *phead;
+ struct rtw_wlan_acl_node *paclnode, *temp;
struct sta_priv *pstapriv = &padapter->stapriv;
struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
struct __queue *pacl_node_q = &pacl_list->acl_node_q;
- DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr));
-
spin_lock_bh(&pacl_node_q->lock);
phead = get_list_head(pacl_node_q);
- plist = phead->next;
-
- while (phead != plist) {
- paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
- plist = plist->next;
-
+ list_for_each_entry_safe(paclnode, temp, phead, list) {
if (!memcmp(paclnode->addr, addr, ETH_ALEN)) {
if (paclnode->valid) {
paclnode->valid = false;
@@ -1111,7 +1052,6 @@ int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
spin_unlock_bh(&pacl_node_q->lock);
- DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num);
return 0;
}
@@ -1124,8 +1064,6 @@ static void update_bcn_erpinfo_ie(struct adapter *padapter)
unsigned char *p, *ie = pnetwork->ies;
u32 len = 0;
- DBG_88E("%s, ERP_enable =%d\n", __func__, pmlmeinfo->ERP_enable);
-
if (!pmlmeinfo->ERP_enable)
return;
@@ -1205,8 +1143,6 @@ static void update_bcn_vendor_spec_ie(struct adapter *padapter, u8 *oui)
if (!memcmp(WPS_OUI, oui, 4))
update_bcn_wps_ie(padapter);
- else
- DBG_88E("unknown OUI type!\n");
}
void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx)
@@ -1269,9 +1205,6 @@ static int rtw_ht_operation_update(struct adapter *padapter)
if (pmlmepriv->htpriv.ht_option)
return 0;
- DBG_88E("%s current operation mode = 0x%X\n",
- __func__, pmlmepriv->ht_op_mode);
-
if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
pmlmepriv->num_sta_ht_no_gf) {
pmlmepriv->ht_op_mode |=
@@ -1321,9 +1254,6 @@ static int rtw_ht_operation_update(struct adapter *padapter)
op_mode_changes++;
}
- DBG_88E("%s new operation mode = 0x%X changes =%d\n",
- __func__, pmlmepriv->ht_op_mode, op_mode_changes);
-
return op_mode_changes;
}
@@ -1338,13 +1268,9 @@ void associated_clients_update(struct adapter *padapter, u8 updated)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = phead->next;
-
/* check asoc_queue */
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, asoc_list);
-
- plist = plist->next;
+ list_for_each(plist, phead) {
+ psta = list_entry(plist, struct sta_info, asoc_list);
VCS_update(padapter, psta);
}
@@ -1438,9 +1364,6 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
if (psta->flags & WLAN_STA_HT) {
u16 ht_capab = le16_to_cpu(psta->htpriv.ht_cap.cap_info);
- DBG_88E("HT: STA %pM HT Capabilities Info: 0x%04x\n",
- (psta->hwaddr), ht_capab);
-
if (psta->no_ht_set) {
psta->no_ht_set = 0;
pmlmepriv->num_sta_no_ht--;
@@ -1451,9 +1374,6 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
psta->no_ht_gf_set = 1;
pmlmepriv->num_sta_ht_no_gf++;
}
- DBG_88E("%s STA %pM - no greenfield, num of non-gf stations %d\n",
- __func__, (psta->hwaddr),
- pmlmepriv->num_sta_ht_no_gf);
}
if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH_20_40) == 0) {
@@ -1461,20 +1381,12 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
psta->ht_20mhz_set = 1;
pmlmepriv->num_sta_ht_20mhz++;
}
- DBG_88E("%s STA %pM - 20 MHz HT, num of 20MHz HT STAs %d\n",
- __func__, (psta->hwaddr),
- pmlmepriv->num_sta_ht_20mhz);
}
} else {
if (!psta->no_ht_set) {
psta->no_ht_set = 1;
pmlmepriv->num_sta_no_ht++;
}
- if (pmlmepriv->htpriv.ht_option) {
- DBG_88E("%s STA %pM - no HT, num of non-HT stations %d\n",
- __func__, (psta->hwaddr),
- pmlmepriv->num_sta_no_ht);
- }
}
if (rtw_ht_operation_update(padapter) > 0) {
@@ -1484,8 +1396,6 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
/* update associated stations cap. */
associated_clients_update(padapter, beacon_updated);
-
- DBG_88E("%s, updated =%d\n", __func__, beacon_updated);
}
u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta)
@@ -1548,8 +1458,6 @@ u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta)
/* update associated stations cap. */
- DBG_88E("%s, updated =%d\n", __func__, beacon_updated);
-
return beacon_updated;
}
@@ -1595,28 +1503,20 @@ u8 ap_free_sta(struct adapter *padapter, struct sta_info *psta,
int rtw_sta_flush(struct adapter *padapter)
{
- struct list_head *phead, *plist;
- struct sta_info *psta = NULL;
+ struct list_head *phead;
+ struct sta_info *psta, *temp;
struct sta_priv *pstapriv = &padapter->stapriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
-
if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)
return 0;
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = phead->next;
-
/* free sta asoc_queue */
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, asoc_list);
-
- plist = plist->next;
-
+ list_for_each_entry_safe(psta, temp, phead, asoc_list) {
list_del_init(&psta->asoc_list);
pstapriv->asoc_list_cnt--;
@@ -1716,8 +1616,7 @@ void start_ap_mode(struct adapter *padapter)
void stop_ap_mode(struct adapter *padapter)
{
- struct list_head *phead, *plist;
- struct rtw_wlan_acl_node *paclnode;
+ struct rtw_wlan_acl_node *paclnode, *n;
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
@@ -1737,12 +1636,7 @@ void stop_ap_mode(struct adapter *padapter)
/* for ACL */
spin_lock_bh(&pacl_node_q->lock);
- phead = get_list_head(pacl_node_q);
- plist = phead->next;
- while (phead != plist) {
- paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
- plist = plist->next;
-
+ list_for_each_entry_safe(paclnode, n, &pacl_node_q->queue, list) {
if (paclnode->valid) {
paclnode->valid = false;
@@ -1753,8 +1647,6 @@ void stop_ap_mode(struct adapter *padapter)
}
spin_unlock_bh(&pacl_node_q->lock);
- DBG_88E("%s, free acl_node_queue, num =%d\n", __func__, pacl_list->num);
-
rtw_sta_flush(padapter);
/* free_assoc_sta_resources */
diff --git a/drivers/staging/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c
index 6728391d39e3..eb89a52aa4e3 100644
--- a/drivers/staging/rtl8188eu/core/rtw_cmd.c
+++ b/drivers/staging/rtl8188eu/core/rtw_cmd.c
@@ -37,7 +37,7 @@ static struct _cmd_callback rtw_cmd_callback[] = {
{_SiteSurvey_CMD_, &rtw_survey_cmd_callback},
{_SetAuth_CMD_, NULL},
{_SetKey_CMD_, NULL},
- {_SetStaKey_CMD_, &rtw_setstaKey_cmdrsp_callback},
+ {_SetStaKey_CMD_, NULL},
{_SetAssocSta_CMD_, &rtw_setassocsta_cmdrsp_callback},
{_AddBAReq_CMD_, NULL},
{_SetChannel_CMD_, NULL},
@@ -52,13 +52,11 @@ static struct _cmd_callback rtw_cmd_callback[] = {
* No irqsave is necessary.
*/
-int rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
+void rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
{
init_completion(&pcmdpriv->cmd_queue_comp);
- init_completion(&pcmdpriv->terminate_cmdthread_comp);
_rtw_init_queue(&pcmdpriv->cmd_queue);
- return _SUCCESS;
}
/*
@@ -74,17 +72,12 @@ static int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
{
unsigned long irqL;
- if (!obj)
- goto exit;
-
spin_lock_irqsave(&queue->lock, irqL);
list_add_tail(&obj->list, &queue->queue);
spin_unlock_irqrestore(&queue->lock, irqL);
-exit:
-
return _SUCCESS;
}
@@ -104,11 +97,12 @@ struct cmd_obj *rtw_dequeue_cmd(struct __queue *queue)
static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
{
+ struct adapter *padapter = container_of(pcmdpriv, struct adapter, cmdpriv);
u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */
/* To decide allow or not */
- if ((pcmdpriv->padapter->pwrctrlpriv.bHWPwrPindetect) &&
- (!pcmdpriv->padapter->registrypriv.usbss_enable)) {
+ if ((padapter->pwrctrlpriv.bHWPwrPindetect) &&
+ (!padapter->registrypriv.usbss_enable)) {
if (cmd_obj->cmdcode == _Set_Drv_Extra_CMD_) {
struct drvextra_cmd_parm *pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)cmd_obj->parmbuf;
@@ -120,8 +114,8 @@ static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
if (cmd_obj->cmdcode == _SetChannelPlan_CMD_)
bAllow = true;
- if ((!pcmdpriv->padapter->hw_init_completed && !bAllow) ||
- !pcmdpriv->cmdthd_running) /* com_thread not running */
+ if ((!padapter->hw_init_completed && !bAllow) ||
+ !padapter->cmdThread) /* com_thread not running */
return _FAIL;
return _SUCCESS;
}
@@ -129,7 +123,7 @@ static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
{
int res = _FAIL;
- struct adapter *padapter = pcmdpriv->padapter;
+ struct adapter *padapter = container_of(pcmdpriv, struct adapter, cmdpriv);
if (!cmd_obj)
goto exit;
@@ -181,20 +175,9 @@ int rtw_cmd_thread(void *context)
allow_signal(SIGTERM);
- pcmdpriv->cmdthd_running = true;
- complete(&pcmdpriv->terminate_cmdthread_comp);
-
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
- ("start r871x %s !!!!\n", __func__));
-
- while (1) {
- if (padapter->bDriverStopped ||
- padapter->bSurpriseRemoved) {
- DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n",
- __func__, padapter->bDriverStopped,
- padapter->bSurpriseRemoved, __LINE__);
+ do {
+ if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
break;
- }
pcmd = rtw_dequeue_cmd(&pcmdpriv->cmd_queue);
if (!pcmd) {
@@ -223,33 +206,23 @@ int rtw_cmd_thread(void *context)
/* call callback function for post-processed */
if (pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) {
pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback;
- if (!pcmd_callback) {
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
- ("mlme_cmd_hdl(): pcmd_callback = 0x%p, cmdcode = 0x%x\n",
- pcmd_callback, pcmd->cmdcode));
- } else {
+ if (pcmd_callback) {
/* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */
pcmd_callback(pcmd->padapter, pcmd);
}
- } else {
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
- ("%s: cmdcode = 0x%x callback not defined!\n",
- __func__, pcmd->cmdcode));
}
rtw_free_cmd_obj(pcmd);
if (signal_pending(current))
flush_signals(current);
- }
- pcmdpriv->cmdthd_running = false;
+ } while (!kthread_should_stop());
/* free all cmd_obj resources */
while ((pcmd = rtw_dequeue_cmd(&pcmdpriv->cmd_queue)))
rtw_free_cmd_obj(pcmd);
- complete(&pcmdpriv->terminate_cmdthread_comp);
-
- complete_and_exit(NULL, 0);
+ padapter->cmdThread = NULL;
+ return 0;
}
/*
@@ -282,8 +255,6 @@ u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid,
rtw_free_network_queue(padapter, false);
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("%s: flush network queue\n", __func__));
-
init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, _SiteSurvey_CMD_);
psurveyPara->scan_mode = pmlmepriv->scan_mode;
@@ -342,19 +313,11 @@ u8 rtw_createbss_cmd(struct adapter *padapter)
{
struct cmd_obj *pcmd;
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
- struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network;
u8 res = _SUCCESS;
led_control_8188eu(padapter, LED_CTL_START_TO_LINK);
- if (pmlmepriv->assoc_ssid.ssid_length == 0)
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
- (" createbss for Any SSid:%s\n", pmlmepriv->assoc_ssid.ssid));
- else
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
- (" createbss for SSid:%s\n", pmlmepriv->assoc_ssid.ssid));
-
pcmd = kzalloc(sizeof(*pcmd), GFP_ATOMIC);
if (!pcmd) {
res = _FAIL;
@@ -392,12 +355,6 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork)
led_control_8188eu(padapter, LED_CTL_START_TO_LINK);
- if (pmlmepriv->assoc_ssid.ssid_length == 0)
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+Join cmd: Any SSid\n"));
- else
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_,
- ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.ssid));
-
pcmd = kzalloc(sizeof(*pcmd), GFP_ATOMIC);
if (!pcmd) {
res = _FAIL;
@@ -428,9 +385,6 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork)
res = _FAIL;
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
- ("%s :psecnetwork == NULL!!!\n", __func__));
-
goto exit;
}
@@ -502,8 +456,6 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork)
else
padapter->pwrctrlpriv.smart_ps = padapter->registrypriv.smart_ps;
- DBG_88E("%s: smart_ps =%d\n", __func__, padapter->pwrctrlpriv.smart_ps);
-
pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);/* get cmdsz before endian conversion */
INIT_LIST_HEAD(&pcmd->list);
@@ -526,8 +478,6 @@ u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueu
struct cmd_priv *cmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+%s\n", __func__));
-
/* prepare cmd parameter */
param = kzalloc(sizeof(*param), GFP_ATOMIC);
if (!param) {
@@ -745,8 +695,6 @@ u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue)
u8 res = _SUCCESS;
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+%s\n", __func__));
-
/* check input parameter */
if (!rtw_is_channel_plan_valid(chplan)) {
res = _FAIL;
@@ -912,39 +860,28 @@ static void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type)
u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue)
{
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
struct cmd_obj *ph2c;
- struct drvextra_cmd_parm *pdrvextra_cmd_parm;
- struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
- u8 res = _SUCCESS;
-
- if (enqueue) {
- ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
- if (!ph2c) {
- res = _FAIL;
- goto exit;
- }
-
- pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
- if (!pdrvextra_cmd_parm) {
- kfree(ph2c);
- res = _FAIL;
- goto exit;
- }
-
- pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID;
- pdrvextra_cmd_parm->type_size = lps_ctrl_type;
- pdrvextra_cmd_parm->pbuf = NULL;
- init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, _Set_Drv_Extra_CMD_);
-
- res = rtw_enqueue_cmd(pcmdpriv, ph2c);
- } else {
+ if (!enqueue) {
lps_ctrl_wk_hdl(padapter, lps_ctrl_type);
+ return _SUCCESS;
}
-exit:
+ ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
+ pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
+ if (!ph2c || !pdrvextra_cmd_parm) {
+ kfree(ph2c);
+ kfree(pdrvextra_cmd_parm);
+ return _FAIL;
+ }
- return res;
+ pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID;
+ pdrvextra_cmd_parm->type_size = lps_ctrl_type;
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, _Set_Drv_Extra_CMD_);
+ return rtw_enqueue_cmd(pcmdpriv, ph2c);
}
static void rpt_timer_setting_wk_hdl(struct adapter *padapter, u16 min_time)
@@ -1172,8 +1109,6 @@ void rtw_survey_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
} else if (pcmd->res != H2C_SUCCESS) {
mod_timer(&pmlmepriv->scan_to_timer,
jiffies + msecs_to_jiffies(1));
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
- ("\n ********Error: MgntActrtw_set_802_11_bssid_LIST_SCAN Fail ************\n\n."));
}
}
@@ -1185,9 +1120,6 @@ void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
spin_lock_bh(&pmlmepriv->lock);
set_fwstate(pmlmepriv, _FW_LINKED);
spin_unlock_bh(&pmlmepriv->lock);
-
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
- ("\n ***Error: disconnect_cmd_callback Fail ***\n."));
}
}
@@ -1201,8 +1133,6 @@ void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
mod_timer(&pmlmepriv->assoc_timer,
jiffies + msecs_to_jiffies(1));
} else if (pcmd->res != H2C_SUCCESS) {
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
- ("********Error:rtw_select_and_join_from_scanned_queue Wait Sema Fail ************\n"));
mod_timer(&pmlmepriv->assoc_timer,
jiffies + msecs_to_jiffies(1));
}
@@ -1217,8 +1147,6 @@ void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
struct wlan_network *tgt_network = &pmlmepriv->cur_network;
if (pcmd->res != H2C_SUCCESS) {
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
- ("\n **** Error: %s Fail ****\n\n.", __func__));
mod_timer(&pmlmepriv->assoc_timer,
jiffies + msecs_to_jiffies(1));
}
@@ -1232,8 +1160,6 @@ void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
if (!psta) {
psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress);
if (!psta) {
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
- ("\nCan't alloc sta_info when createbss_cmd_callback\n"));
goto createbss_cmd_fail;
}
}
@@ -1245,8 +1171,6 @@ void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
if (!pwlan) {
pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue);
if (!pwlan) {
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
- ("\n Error: can't get pwlan in rtw_joinbss_event_callback\n"));
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
goto createbss_cmd_fail;
}
@@ -1274,18 +1198,6 @@ createbss_cmd_fail:
spin_unlock_bh(&pmlmepriv->lock);
}
-void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
-{
- struct sta_priv *pstapriv = &padapter->stapriv;
- struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)(pcmd->rsp);
- struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr);
-
- if (!psta) {
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
- ("\nERROR: %s => can't get sta_info\n\n", __func__));
- }
-}
-
void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
{
struct sta_priv *pstapriv = &padapter->stapriv;
@@ -1294,11 +1206,8 @@ void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *
struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *)(pcmd->rsp);
struct sta_info *psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr);
- if (!psta) {
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
- ("\nERROR: %s => can't get sta_info\n\n", __func__));
+ if (!psta)
return;
- }
psta->aid = passocsta_rsp->cam_id;
psta->mac_id = passocsta_rsp->cam_id;
diff --git a/drivers/staging/rtl8188eu/core/rtw_debug.c b/drivers/staging/rtl8188eu/core/rtw_debug.c
deleted file mode 100644
index 1060837fe463..000000000000
--- a/drivers/staging/rtl8188eu/core/rtw_debug.c
+++ /dev/null
@@ -1,187 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-#define _RTW_DEBUG_C_
-
-#include <rtw_debug.h>
-#include <usb_ops_linux.h>
-
-int proc_get_drv_version(char *page, char **start,
- off_t offset, int count,
- int *eof, void *data)
-{
- int len = 0;
-
- len += scnprintf(page + len, count - len, "%s\n", DRIVERVERSION);
-
- *eof = 1;
- return len;
-}
-
-int proc_get_write_reg(char *page, char **start,
- off_t offset, int count,
- int *eof, void *data)
-{
- *eof = 1;
- return 0;
-}
-
-int proc_set_write_reg(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = netdev_priv(dev);
- char tmp[32];
- u32 addr, val, len;
-
- if (count < 3) {
- DBG_88E("argument size is less than 3\n");
- return -EFAULT;
- }
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
- int num = sscanf(tmp, "%x %x %x", &addr, &val, &len);
-
- if (num != 3) {
- DBG_88E("invalid write_reg parameter!\n");
- return count;
- }
- switch (len) {
- case 1:
- usb_write8(padapter, addr, (u8)val);
- break;
- case 2:
- usb_write16(padapter, addr, (u16)val);
- break;
- case 4:
- usb_write32(padapter, addr, val);
- break;
- default:
- DBG_88E("error write length =%d", len);
- break;
- }
- }
- return count;
-}
-
-static u32 proc_get_read_addr = 0xeeeeeeee;
-static u32 proc_get_read_len = 0x4;
-
-int proc_get_read_reg(char *page, char **start,
- off_t offset, int count,
- int *eof, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = netdev_priv(dev);
-
- int len = 0;
-
- if (proc_get_read_addr == 0xeeeeeeee) {
- *eof = 1;
- return len;
- }
-
- switch (proc_get_read_len) {
- case 1:
- len += scnprintf(page + len, count - len, "usb_read8(0x%x)=0x%x\n",
- proc_get_read_addr, usb_read8(padapter, proc_get_read_addr));
- break;
- case 2:
- len += scnprintf(page + len, count - len, "usb_read16(0x%x)=0x%x\n",
- proc_get_read_addr, usb_read16(padapter, proc_get_read_addr));
- break;
- case 4:
- len += scnprintf(page + len, count - len, "usb_read32(0x%x)=0x%x\n",
- proc_get_read_addr, usb_read32(padapter, proc_get_read_addr));
- break;
- default:
- len += scnprintf(page + len, count - len, "error read length=%d\n",
- proc_get_read_len);
- break;
- }
-
- *eof = 1;
- return len;
-}
-
-int proc_set_read_reg(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- char tmp[16];
- u32 addr, len;
-
- if (count < 2) {
- DBG_88E("argument size is less than 2\n");
- return -EFAULT;
- }
-
- if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
- int num = sscanf(tmp, "%x %x", &addr, &len);
-
- if (num != 2) {
- DBG_88E("invalid read_reg parameter!\n");
- return count;
- }
-
- proc_get_read_addr = addr;
-
- proc_get_read_len = len;
- }
-
- return count;
-}
-
-int proc_get_adapter_state(char *page, char **start,
- off_t offset, int count,
- int *eof, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = netdev_priv(dev);
- int len = 0;
-
- len += scnprintf(page + len, count - len, "bSurpriseRemoved=%d, bDriverStopped=%d\n",
- padapter->bSurpriseRemoved,
- padapter->bDriverStopped);
-
- *eof = 1;
- return len;
-}
-
-int proc_get_best_channel(char *page, char **start,
- off_t offset, int count,
- int *eof, void *data)
-{
- struct net_device *dev = data;
- struct adapter *padapter = netdev_priv(dev);
- struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- int len = 0;
- u32 i, best_channel_24G = 1, index_24G = 0;
-
- for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) {
- if (pmlmeext->channel_set[i].ChannelNum == 1)
- index_24G = i;
- }
-
- for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) {
- /* 2.4G */
- if (pmlmeext->channel_set[i].ChannelNum == 6) {
- if (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_24G].rx_count) {
- index_24G = i;
- best_channel_24G = pmlmeext->channel_set[i].ChannelNum;
- }
- }
-
- /* debug */
- len += scnprintf(page + len, count - len, "The rx cnt of channel %3d = %d\n",
- pmlmeext->channel_set[i].ChannelNum,
- pmlmeext->channel_set[i].rx_count);
- }
-
- len += scnprintf(page + len, count - len, "best_channel_24G = %d\n", best_channel_24G);
-
- *eof = 1;
- return len;
-}
diff --git a/drivers/staging/rtl8188eu/core/rtw_efuse.c b/drivers/staging/rtl8188eu/core/rtw_efuse.c
index 9bb3ec0cd62f..80673a73c119 100644
--- a/drivers/staging/rtl8188eu/core/rtw_efuse.c
+++ b/drivers/staging/rtl8188eu/core/rtw_efuse.c
@@ -91,10 +91,8 @@ efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf)
tmp = kcalloc(EFUSE_MAX_SECTION_88E,
sizeof(void *) + EFUSE_MAX_WORD_UNIT * sizeof(u16),
GFP_KERNEL);
- if (!tmp) {
- DBG_88E("%s: alloc eFuseWord fail!\n", __func__);
+ if (!tmp)
goto eFuseWord_failed;
- }
for (i = 0; i < EFUSE_MAX_SECTION_88E; i++)
tmp[i] = ((char *)(tmp + EFUSE_MAX_SECTION_88E)) + i * EFUSE_MAX_WORD_UNIT * sizeof(u16);
eFuseWord = (u16 **)tmp;
@@ -113,7 +111,6 @@ efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf)
efuse_utilized++;
eFuse_Addr++;
} else {
- DBG_88E("EFUSE is empty efuse_Addr-%d efuse_data =%x\n", eFuse_Addr, rtemp8);
goto exit;
}
@@ -220,8 +217,6 @@ static void efuse_read_phymap_from_txpktbuf(
if (bcnhead < 0) /* if not valid */
bcnhead = usb_read8(adapter, REG_TDECTRL + 1);
- DBG_88E("%s bcnhead:%d\n", __func__, bcnhead);
-
usb_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
dbg_addr = bcnhead * 128 / 8; /* 8-bytes addressing */
@@ -232,31 +227,20 @@ static void efuse_read_phymap_from_txpktbuf(
usb_write8(adapter, REG_TXPKTBUF_DBG, 0);
start = jiffies;
while (!(reg_0x143 = usb_read8(adapter, REG_TXPKTBUF_DBG)) &&
- jiffies_to_msecs(jiffies - start) < 1000) {
- DBG_88E("%s polling reg_0x143:0x%02x, reg_0x106:0x%02x\n", __func__, reg_0x143, usb_read8(adapter, 0x106));
+ jiffies_to_msecs(jiffies - start) < 1000)
usleep_range(1000, 2000);
- }
lo32 = usb_read32(adapter, REG_PKTBUF_DBG_DATA_L);
hi32 = usb_read32(adapter, REG_PKTBUF_DBG_DATA_H);
if (i == 0) {
- u8 lenc[2];
- u16 lenbak, aaabak;
- u16 aaa;
+ usb_read8(adapter, REG_PKTBUF_DBG_DATA_L);
+ usb_read8(adapter, REG_PKTBUF_DBG_DATA_L + 1);
- lenc[0] = usb_read8(adapter, REG_PKTBUF_DBG_DATA_L);
- lenc[1] = usb_read8(adapter, REG_PKTBUF_DBG_DATA_L + 1);
-
- aaabak = le16_to_cpup((__le16 *)lenc);
- lenbak = le16_to_cpu(*((__le16 *)lenc));
- aaa = le16_to_cpup((__le16 *)&lo32);
len = le16_to_cpu(*((__le16 *)&lo32));
limit = min_t(u16, len - 2, limit);
- DBG_88E("%s len:%u, lenbak:%u, aaa:%u, aaabak:%u\n", __func__, len, lenbak, aaa, aaabak);
-
memcpy(pos, ((u8 *)&lo32) + 2, (limit >= count + 2) ? 2 : limit - count);
count += (limit >= count + 2) ? 2 : limit - count;
pos = content + count;
@@ -278,7 +262,6 @@ static void efuse_read_phymap_from_txpktbuf(
i++;
}
usb_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, DISABLE_TRXPKT_BUF_ACCESS);
- DBG_88E("%s read count:%u\n", __func__, count);
*size = count;
}
@@ -298,7 +281,7 @@ static s32 iol_read_efuse(struct adapter *padapter, u8 txpktbuf_bndy, u16 offset
return status;
}
-void efuse_ReadEFuse(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf)
+static void efuse_ReadEFuse(struct adapter *Adapter, u16 _offset, u16 _size_byte, u8 *pbuf)
{
if (rtw_iol_applied(Adapter)) {
rtw_hal_power_on(Adapter);
@@ -432,7 +415,6 @@ int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data)
hoffset = ((tmp_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
hworden = efuse_data & 0x0F;
} else {
- DBG_88E("Error, All words disabled\n");
efuse_addr++;
continue;
}
@@ -479,7 +461,7 @@ int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data)
return true;
}
-static bool hal_EfuseFixHeaderProcess(struct adapter *pAdapter, u8 efuseType, struct pgpkt *pFixPkt, u16 *pAddr)
+static bool hal_EfuseFixHeaderProcess(struct adapter *pAdapter, struct pgpkt *pFixPkt, u16 *pAddr)
{
u8 originaldata[8], badworden = 0;
u16 efuse_addr = *pAddr;
@@ -508,7 +490,7 @@ static bool hal_EfuseFixHeaderProcess(struct adapter *pAdapter, u8 efuseType, st
return true;
}
-static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt)
+static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u16 *pAddr, struct pgpkt *pTargetPkt)
{
bool ret = false;
u16 efuse_addr = *pAddr;
@@ -559,7 +541,7 @@ static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u8 efuse
fixPkt.offset = ((pg_header_temp & 0xE0) >> 5) | ((tmp_header & 0xF0) >> 1);
fixPkt.word_en = tmp_header & 0x0F;
fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en);
- if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr))
+ if (!hal_EfuseFixHeaderProcess(pAdapter, &fixPkt, &efuse_addr))
return false;
} else {
ret = true;
@@ -575,7 +557,7 @@ static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u8 efuse
return ret;
}
-static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt)
+static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u16 *pAddr, struct pgpkt *pTargetPkt)
{
bool ret = false;
u8 pg_header = 0, tmp_header = 0;
@@ -602,7 +584,7 @@ static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuse
fixPkt.offset = (tmp_header >> 4) & 0x0F;
fixPkt.word_en = tmp_header & 0x0F;
fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en);
- if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr))
+ if (!hal_EfuseFixHeaderProcess(pAdapter, &fixPkt, &efuse_addr))
return false;
}
@@ -610,7 +592,7 @@ static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuse
return ret;
}
-static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt)
+static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u16 *pAddr, struct pgpkt *pTargetPkt)
{
u16 efuse_addr = *pAddr;
u8 badworden;
@@ -632,16 +614,15 @@ static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u
static bool
hal_EfusePgPacketWriteHeader(
struct adapter *pAdapter,
- u8 efuseType,
u16 *pAddr,
struct pgpkt *pTargetPkt)
{
bool ret = false;
if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE)
- ret = hal_EfusePgPacketWrite2ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt);
+ ret = hal_EfusePgPacketWrite2ByteHeader(pAdapter, pAddr, pTargetPkt);
else
- ret = hal_EfusePgPacketWrite1ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt);
+ ret = hal_EfusePgPacketWrite1ByteHeader(pAdapter, pAddr, pTargetPkt);
return ret;
}
@@ -685,7 +666,7 @@ static bool hal_EfuseCheckIfDatafollowed(struct adapter *pAdapter, u8 word_cnts,
return ret;
}
-static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt)
+static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u16 *pAddr, struct pgpkt *pTargetPkt)
{
bool ret = false;
u8 i, efuse_data = 0, cur_header = 0;
@@ -772,20 +753,19 @@ bool Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *pD
{
struct pgpkt targetPkt;
u16 startAddr = 0;
- u8 efuseType = EFUSE_WIFI;
if (Efuse_GetCurrentSize(pAdapter) >= EFUSE_MAP_LEN_88E)
return false;
hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt);
- if (!hal_EfusePartialWriteCheck(pAdapter, efuseType, &startAddr, &targetPkt))
+ if (!hal_EfusePartialWriteCheck(pAdapter, &startAddr, &targetPkt))
return false;
- if (!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, &startAddr, &targetPkt))
+ if (!hal_EfusePgPacketWriteHeader(pAdapter, &startAddr, &targetPkt))
return false;
- if (!hal_EfusePgPacketWriteData(pAdapter, efuseType, &startAddr, &targetPkt))
+ if (!hal_EfusePgPacketWriteData(pAdapter, &startAddr, &targetPkt))
return false;
return true;
@@ -875,22 +855,22 @@ void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata)
}
/* Read All Efuse content */
-static void Efuse_ReadAllMap(struct adapter *pAdapter, u8 efuseType, u8 *Efuse)
+static void Efuse_ReadAllMap(struct adapter *pAdapter, u8 *Efuse)
{
efuse_power_switch(pAdapter, false, true);
- efuse_ReadEFuse(pAdapter, efuseType, 0, EFUSE_MAP_LEN_88E, Efuse);
+ efuse_ReadEFuse(pAdapter, 0, EFUSE_MAP_LEN_88E, Efuse);
efuse_power_switch(pAdapter, false, false);
}
/* Transfer current EFUSE content to shadow init and modify map. */
-void EFUSE_ShadowMapUpdate(struct adapter *pAdapter, u8 efuseType)
+void EFUSE_ShadowMapUpdate(struct adapter *pAdapter)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
if (pEEPROM->bautoload_fail_flag)
memset(pEEPROM->efuse_eeprom_data, 0xFF, EFUSE_MAP_LEN_88E);
else
- Efuse_ReadAllMap(pAdapter, efuseType, pEEPROM->efuse_eeprom_data);
+ Efuse_ReadAllMap(pAdapter, pEEPROM->efuse_eeprom_data);
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
index 7a706fe11750..e431914db008 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
@@ -370,7 +370,6 @@ int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwis
pos += WPA_SELECTOR_LEN;
left -= WPA_SELECTOR_LEN;
} else if (left > 0) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie length mismatch, %u too much", __func__, left));
return _FAIL;
}
@@ -380,11 +379,8 @@ int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwis
pos += 2;
left -= 2;
- if (count == 0 || left < count * WPA_SELECTOR_LEN) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie count botch (pairwise), count %u left %u",
- __func__, count, left));
+ if (count == 0 || left < count * WPA_SELECTOR_LEN)
return _FAIL;
- }
for (i = 0; i < count; i++) {
*pairwise_cipher |= rtw_get_wpa_cipher_suite(pos);
@@ -393,17 +389,14 @@ int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwis
left -= WPA_SELECTOR_LEN;
}
} else if (left == 1) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie too short (for key mgmt)", __func__));
return _FAIL;
}
if (is_8021x) {
if (left >= 6) {
pos += 2;
- if (!memcmp(pos, SUITE_1X, 4)) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s : there has 802.1x auth\n", __func__));
+ if (!memcmp(pos, SUITE_1X, 4))
*is_8021x = 1;
- }
}
}
@@ -437,7 +430,6 @@ int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwi
left -= RSN_SELECTOR_LEN;
} else if (left > 0) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie length mismatch, %u too much", __func__, left));
return _FAIL;
}
@@ -447,11 +439,8 @@ int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwi
pos += 2;
left -= 2;
- if (count == 0 || left < count * RSN_SELECTOR_LEN) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie count botch (pairwise), count %u left %u",
- __func__, count, left));
+ if (count == 0 || left < count * RSN_SELECTOR_LEN)
return _FAIL;
- }
for (i = 0; i < count; i++) {
*pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos);
@@ -461,18 +450,14 @@ int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwi
}
} else if (left == 1) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie too short (for key mgmt)", __func__));
-
return _FAIL;
}
if (is_8021x) {
if (left >= 6) {
pos += 2;
- if (!memcmp(pos, SUITE_1X, 4)) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s (): there has 802.1x auth\n", __func__));
+ if (!memcmp(pos, SUITE_1X, 4))
*is_8021x = 1;
- }
}
}
return ret;
@@ -480,7 +465,7 @@ int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwi
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 authmode, sec_idx;
u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01};
uint cnt;
@@ -494,40 +479,16 @@ void rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie
authmode = in_ie[cnt];
if ((authmode == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4))) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("\n rtw_get_wpa_ie: sec_idx =%d in_ie[cnt+1]+2 =%d\n",
- sec_idx, in_ie[cnt + 1] + 2));
-
- if (wpa_ie) {
+ if (wpa_ie)
memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
- for (i = 0; i < (in_ie[cnt + 1] + 2); i += 8) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
- wpa_ie[i], wpa_ie[i + 1], wpa_ie[i + 2], wpa_ie[i + 3], wpa_ie[i + 4],
- wpa_ie[i + 5], wpa_ie[i + 6], wpa_ie[i + 7]));
- }
- }
-
*wpa_len = in_ie[cnt + 1] + 2;
cnt += in_ie[cnt + 1] + 2; /* get next */
} else {
if (authmode == WLAN_EID_RSN) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("\n get_rsn_ie: sec_idx =%d in_ie[cnt+1]+2 =%d\n",
- sec_idx, in_ie[cnt + 1] + 2));
-
- if (rsn_ie) {
+ if (rsn_ie)
memcpy(rsn_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
- for (i = 0; i < (in_ie[cnt + 1] + 2); i += 8) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
- rsn_ie[i], rsn_ie[i + 1], rsn_ie[i + 2], rsn_ie[i + 3], rsn_ie[i + 4],
- rsn_ie[i + 5], rsn_ie[i + 6], rsn_ie[i + 7]));
- }
- }
-
*rsn_len = in_ie[cnt + 1] + 2;
cnt += in_ie[cnt + 1] + 2; /* get next */
} else {
@@ -686,13 +647,8 @@ static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen,
* OUI of the vendor. The following byte is used a vendor specific
* sub-type.
*/
- if (elen < 4) {
- if (show_errors) {
- DBG_88E("short vendor specific information element ignored (len=%lu)\n",
- (unsigned long)elen);
- }
+ if (elen < 4)
return -1;
- }
oui = RTW_GET_BE24(pos);
switch (oui) {
@@ -711,11 +667,9 @@ static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen,
elems->wpa_ie_len = elen;
break;
case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */
- if (elen < 5) {
- DBG_88E("short WME information element ignored (len=%lu)\n",
- (unsigned long)elen);
+ if (elen < 5)
return -1;
- }
+
switch (pos[4]) {
case WME_OUI_SUBTYPE_INFORMATION_ELEMENT:
case WME_OUI_SUBTYPE_PARAMETER_ELEMENT:
@@ -727,8 +681,6 @@ static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen,
elems->wme_tspec_len = elen;
break;
default:
- DBG_88E("unknown WME information element ignored (subtype=%d len=%lu)\n",
- pos[4], (unsigned long)elen);
return -1;
}
break;
@@ -738,8 +690,6 @@ static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen,
elems->wps_ie_len = elen;
break;
default:
- DBG_88E("Unknown Microsoft information element ignored (type=%d len=%lu)\n",
- pos[3], (unsigned long)elen);
return -1;
}
break;
@@ -751,21 +701,17 @@ static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen,
elems->vendor_ht_cap_len = elen;
break;
default:
- DBG_88E("Unknown Broadcom information element ignored (type=%d len=%lu)\n",
- pos[3], (unsigned long)elen);
return -1;
}
break;
default:
- DBG_88E("unknown vendor specific information element ignored (vendor OUI %3phC len=%lu)\n",
- pos, (unsigned long)elen);
return -1;
}
return 0;
}
/**
- * ieee802_11_parse_elems - Parse information elements in management frames
+ * rtw_ieee802_11_parse_elems - Parse information elements in management frames
* @start: Pointer to the start of ies
* @len: Length of IE buffer in octets
* @elems: Data structure for parsed elements
@@ -789,13 +735,8 @@ enum parse_res rtw_ieee802_11_parse_elems(u8 *start, uint len,
elen = *pos++;
left -= 2;
- if (elen > left) {
- if (show_errors) {
- DBG_88E("IEEE 802.11 element parse failed (id=%d elen=%d left=%lu)\n",
- id, elen, (unsigned long)left);
- }
+ if (elen > left)
return ParseFailed;
- }
switch (id) {
case WLAN_EID_SSID:
@@ -876,10 +817,6 @@ enum parse_res rtw_ieee802_11_parse_elems(u8 *start, uint len,
break;
default:
unknown++;
- if (!show_errors)
- break;
- DBG_88E("IEEE 802.11 element parse ignored unknown element (id=%d elen=%d)\n",
- id, elen);
break;
}
left -= elen;
@@ -905,12 +842,8 @@ void rtw_macaddr_cfg(u8 *mac_addr)
ether_addr_copy(mac, mac_addr);
}
- if (is_broadcast_ether_addr(mac) || is_zero_ether_addr(mac)) {
+ if (is_broadcast_ether_addr(mac) || is_zero_ether_addr(mac))
eth_random_addr(mac_addr);
- DBG_88E("MAC Address from efuse error, assign random one !!!\n");
- }
-
- DBG_88E("%s MAC Address = %pM\n", __func__, mac_addr);
}
static int rtw_get_cipher_info(struct wlan_network *pnetwork)
@@ -923,30 +856,20 @@ static int rtw_get_cipher_info(struct wlan_network *pnetwork)
pbuf = rtw_get_wpa_ie(&pnetwork->network.ies[12], &wpa_ielen, pnetwork->network.ie_length - 12);
if (pbuf && (wpa_ielen > 0)) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: wpa_ielen: %d", __func__, wpa_ielen));
if (rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x) == _SUCCESS) {
pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
pnetwork->BcnInfo.group_cipher = group_cipher;
pnetwork->BcnInfo.is_8021x = is8021x;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("%s: pnetwork->pairwise_cipher: %d, is_8021x is %d",
- __func__, pnetwork->BcnInfo.pairwise_cipher,
- pnetwork->BcnInfo.is_8021x));
ret = _SUCCESS;
}
} else {
pbuf = rtw_get_wpa2_ie(&pnetwork->network.ies[12], &wpa_ielen, pnetwork->network.ie_length - 12);
if (pbuf && (wpa_ielen > 0)) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE\n"));
if (rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x) == _SUCCESS) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE OK!!!\n"));
pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
pnetwork->BcnInfo.group_cipher = group_cipher;
pnetwork->BcnInfo.is_8021x = is8021x;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->pairwise_cipher: %d, pnetwork->group_cipher is %d, is_8021x is %d",
- __func__, pnetwork->BcnInfo.pairwise_cipher,
- pnetwork->BcnInfo.group_cipher, pnetwork->BcnInfo.is_8021x));
ret = _SUCCESS;
}
}
@@ -974,10 +897,6 @@ void rtw_get_bcn_info(struct wlan_network *pnetwork)
pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS;
}
rtw_get_sec_ie(pnetwork->network.ies, pnetwork->network.ie_length, NULL, &rsn_len, NULL, &wpa_len);
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: ssid =%s\n", __func__, pnetwork->network.ssid.ssid));
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: wpa_len =%d rsn_len =%d\n", __func__, wpa_len, rsn_len));
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: ssid =%s\n", __func__, pnetwork->network.ssid.ssid));
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: wpa_len =%d rsn_len =%d\n", __func__, wpa_len, rsn_len));
if (rsn_len > 0) {
pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2;
@@ -987,10 +906,6 @@ void rtw_get_bcn_info(struct wlan_network *pnetwork)
if (bencrypt)
pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP;
}
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->encryp_protocol is %x\n",
- __func__, pnetwork->BcnInfo.encryp_protocol));
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->encryp_protocol is %x\n",
- __func__, pnetwork->BcnInfo.encryp_protocol));
rtw_get_cipher_info(pnetwork);
/* get bwmode and ch_offset */
diff --git a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
index 17b999f45132..f679a7f8fe75 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
@@ -12,12 +12,12 @@
#include <hal_intf.h>
static const struct {
- int channel_plan;
- char *name;
+ int channel_plan;
+ char *name;
} channel_table[] = { { RT_CHANNEL_DOMAIN_FCC, "US" },
- { RT_CHANNEL_DOMAIN_ETSI, "EU" },
- { RT_CHANNEL_DOMAIN_MKK, "JP" },
- { RT_CHANNEL_DOMAIN_CHINA, "CN"} };
+ { RT_CHANNEL_DOMAIN_ETSI, "EU" },
+ { RT_CHANNEL_DOMAIN_MKK, "JP" },
+ { RT_CHANNEL_DOMAIN_CHINA, "CN"} };
extern void indicate_wx_scan_complete_event(struct adapter *padapter);
@@ -33,8 +33,6 @@ u8 rtw_do_join(struct adapter *padapter)
phead = get_list_head(queue);
plist = phead->next;
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("\n %s: phead = %p; plist = %p\n\n\n", __func__, phead, plist));
-
pmlmepriv->cur_network.join_res = -2;
set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
@@ -52,13 +50,10 @@ u8 rtw_do_join(struct adapter *padapter)
if (!pmlmepriv->LinkDetectInfo.bBusyTraffic ||
pmlmepriv->to_roaming > 0) {
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("%s: site survey if scanned_queue is empty\n.", __func__));
/* submit site_survey_cmd */
ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
- if (ret != _SUCCESS) {
+ if (ret != _SUCCESS)
pmlmepriv->to_join = false;
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("%s: site survey return error\n.", __func__));
- }
} else {
pmlmepriv->to_join = false;
ret = _FAIL;
@@ -92,14 +87,10 @@ u8 rtw_do_join(struct adapter *padapter)
rtw_generate_random_ibss(pibss);
if (rtw_createbss_cmd(padapter) != _SUCCESS) {
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error =>do_goin: rtw_createbss_cmd status FAIL***\n "));
ret = false;
goto exit;
}
pmlmepriv->to_join = false;
-
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
- ("***Error => rtw_select_and_join_from_scanned_queue FAIL under STA_Mode***\n "));
} else {
/* can't associate ; reset under-linking */
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
@@ -109,10 +100,8 @@ u8 rtw_do_join(struct adapter *padapter)
if (!pmlmepriv->LinkDetectInfo.bBusyTraffic ||
pmlmepriv->to_roaming > 0) {
ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
- if (ret != _SUCCESS) {
+ if (ret != _SUCCESS)
pmlmepriv->to_join = false;
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("do_join(): site survey return error\n."));
- }
} else {
ret = _FAIL;
pmlmepriv->to_join = false;
@@ -131,8 +120,6 @@ u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid)
u32 cur_time = 0;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- DBG_88E_LEVEL(_drv_info_, "set bssid:%pM\n", bssid);
-
if ((bssid[0] == 0x00 && bssid[1] == 0x00 && bssid[2] == 0x00 &&
bssid[3] == 0x00 && bssid[4] == 0x00 && bssid[5] == 0x00) ||
(bssid[0] == 0xFF && bssid[1] == 0xFF && bssid[2] == 0xFF &&
@@ -143,23 +130,16 @@ u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid)
spin_lock_bh(&pmlmepriv->lock);
- DBG_88E("Set BSSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv));
if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
goto handle_tkip_countermeasure;
else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
goto release_mlme_lock;
if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) {
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n"));
-
if (!memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, ETH_ALEN)) {
if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE))
goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */
} else {
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("Set BSSID not the same bssid\n"));
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid =%pM\n", (bssid)));
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("cur_bssid =%pM\n", (pmlmepriv->cur_network.network.MacAddress)));
-
rtw_disassoc_cmd(padapter, 0, true);
if (check_fwstate(pmlmepriv, _FW_LINKED))
@@ -201,9 +181,6 @@ release_mlme_lock:
spin_unlock_bh(&pmlmepriv->lock);
exit:
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
- ("%s: status=%d\n", __func__, status));
-
return status;
}
@@ -215,35 +192,22 @@ u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wlan_network *pnetwork = &pmlmepriv->cur_network;
- DBG_88E_LEVEL(_drv_info_, "set ssid [%s] fw_state=0x%08x\n",
- ssid->ssid, get_fwstate(pmlmepriv));
-
if (!padapter->hw_init_completed) {
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
- ("set_ssid: hw_init_completed == false =>exit!!!\n"));
status = _FAIL;
goto exit;
}
spin_lock_bh(&pmlmepriv->lock);
- DBG_88E("Set SSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv));
if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
goto handle_tkip_countermeasure;
else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
goto release_mlme_lock;
if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) {
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
- ("set_ssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n"));
-
if (pmlmepriv->assoc_ssid.ssid_length == ssid->ssid_length &&
!memcmp(&pmlmepriv->assoc_ssid.ssid, ssid->ssid, ssid->ssid_length)) {
if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
- ("Set SSID is the same ssid, fw_state = 0x%08x\n",
- get_fwstate(pmlmepriv)));
-
if (!rtw_is_same_ibss(padapter, pnetwork)) {
/* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */
rtw_disassoc_cmd(padapter, 0, true);
@@ -264,10 +228,6 @@ u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid)
rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_JOINBSS, 1);
}
} else {
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("Set SSID not the same ssid\n"));
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_ssid =[%s] len = 0x%x\n", ssid->ssid, (unsigned int)ssid->ssid_length));
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("assoc_ssid =[%s] len = 0x%x\n", pmlmepriv->assoc_ssid.ssid, (unsigned int)pmlmepriv->assoc_ssid.ssid_length));
-
rtw_disassoc_cmd(padapter, 0, true);
if (check_fwstate(pmlmepriv, _FW_LINKED))
@@ -308,8 +268,6 @@ release_mlme_lock:
spin_unlock_bh(&pmlmepriv->lock);
exit:
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
- ("-%s: status =%d\n", __func__, status));
return status;
}
@@ -320,16 +278,9 @@ u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter,
struct wlan_network *cur_network = &pmlmepriv->cur_network;
enum ndis_802_11_network_infra *pold_state = &cur_network->network.InfrastructureMode;
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_notice_,
- ("+%s: old =%d new =%d fw_state = 0x%08x\n", __func__,
- *pold_state, networktype, get_fwstate(pmlmepriv)));
-
if (*pold_state != networktype) {
spin_lock_bh(&pmlmepriv->lock);
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, (" change mode!"));
- /* DBG_88E("change mode, old_mode =%d, new_mode =%d, fw_state = 0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); */
-
if (*pold_state == Ndis802_11APMode) {
/* change to other mode from Ndis802_11APMode */
cur_network->join_res = -1;
@@ -387,9 +338,6 @@ u8 rtw_set_802_11_disassociate(struct adapter *padapter)
spin_lock_bh(&pmlmepriv->lock);
if (check_fwstate(pmlmepriv, _FW_LINKED)) {
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
- ("MgntActrtw_set_802_11_disassociate: rtw_indicate_disconnect\n"));
-
rtw_disassoc_cmd(padapter, 0, true);
rtw_indicate_disconnect(padapter);
rtw_free_assoc_resources(padapter);
@@ -406,33 +354,21 @@ u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_s
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
u8 res = true;
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("+%s(), fw_state =%x\n", __func__, get_fwstate(pmlmepriv)));
-
if (!padapter) {
res = false;
goto exit;
}
if (!padapter->hw_init_completed) {
res = false;
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n === %s:hw_init_completed == false ===\n", __func__));
goto exit;
}
if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) ||
pmlmepriv->LinkDetectInfo.bBusyTraffic) {
/* Scan or linking is in progress, do nothing. */
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("%s fail since fw_state = %x\n", __func__, get_fwstate(pmlmepriv)));
res = true;
-
- if (check_fwstate(pmlmepriv,
- _FW_UNDER_SURVEY | _FW_UNDER_LINKING))
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n###_FW_UNDER_SURVEY|_FW_UNDER_LINKING\n\n"));
- else
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n###pmlmepriv->sitesurveyctrl.traffic_busy == true\n\n"));
-
} else {
if (rtw_is_scan_deny(padapter)) {
- DBG_88E(FUNC_ADPT_FMT": scan deny\n", FUNC_ADPT_ARG(padapter));
indicate_wx_scan_complete_event(padapter);
return _SUCCESS;
}
@@ -453,15 +389,8 @@ u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum ndis_802_11
int res;
u8 ret;
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
- ("set_802_11_auth.mode(): mode =%x\n", authmode));
-
psecuritypriv->ndisauthtype = authmode;
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
- ("%s:psecuritypriv->ndisauthtype=%d", __func__,
- psecuritypriv->ndisauthtype));
-
if (psecuritypriv->ndisauthtype > 3)
psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
@@ -484,7 +413,6 @@ u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep)
keyid = wep->KeyIndex & 0x3fffffff;
if (keyid >= 4) {
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("MgntActrtw_set_802_11_add_wep:keyid>4 =>fail\n"));
ret = false;
goto exit;
}
@@ -492,20 +420,14 @@ u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep)
switch (wep->KeyLength) {
case 5:
psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength = 5\n"));
break;
case 13:
psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength = 13\n"));
break;
default:
psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength!= 5 or 13\n"));
break;
}
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
- ("%s:before memcpy, wep->KeyLength = 0x%x wep->KeyIndex = 0x%x keyid =%x\n", __func__,
- wep->KeyLength, wep->KeyIndex, keyid));
memcpy(&psecuritypriv->dot11DefKey[keyid].skey[0],
&wep->KeyMaterial, wep->KeyLength);
@@ -514,22 +436,6 @@ u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep)
psecuritypriv->dot11PrivacyKeyIndex = keyid;
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
- ("%s:security key material : %x %x %x %x %x %x %x %x %x %x %x %x %x\n", __func__,
- psecuritypriv->dot11DefKey[keyid].skey[0],
- psecuritypriv->dot11DefKey[keyid].skey[1],
- psecuritypriv->dot11DefKey[keyid].skey[2],
- psecuritypriv->dot11DefKey[keyid].skey[3],
- psecuritypriv->dot11DefKey[keyid].skey[4],
- psecuritypriv->dot11DefKey[keyid].skey[5],
- psecuritypriv->dot11DefKey[keyid].skey[6],
- psecuritypriv->dot11DefKey[keyid].skey[7],
- psecuritypriv->dot11DefKey[keyid].skey[8],
- psecuritypriv->dot11DefKey[keyid].skey[9],
- psecuritypriv->dot11DefKey[keyid].skey[10],
- psecuritypriv->dot11DefKey[keyid].skey[11],
- psecuritypriv->dot11DefKey[keyid].skey[12]));
-
res = rtw_set_key(padapter, psecuritypriv, keyid, 1);
if (res == _FAIL)
@@ -595,7 +501,6 @@ int rtw_set_country(struct adapter *adapter, const char *country_code)
int i;
int channel_plan = RT_CHANNEL_DOMAIN_WORLD_WIDE_5G;
- DBG_88E("%s country_code:%s\n", __func__, country_code);
for (i = 0; i < ARRAY_SIZE(channel_table); i++) {
if (strcmp(channel_table[i].name, country_code) == 0) {
channel_plan = channel_table[i].channel_plan;
@@ -603,8 +508,5 @@ int rtw_set_country(struct adapter *adapter, const char *country_code)
}
}
- if (i == ARRAY_SIZE(channel_table))
- DBG_88E("%s unknown country_code:%s\n", __func__, country_code);
-
return rtw_set_chplan_cmd(adapter, channel_plan, 1);
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_led.c b/drivers/staging/rtl8188eu/core/rtw_led.c
index 32dccae186ca..be868f386204 100644
--- a/drivers/staging/rtl8188eu/core/rtw_led.c
+++ b/drivers/staging/rtl8188eu/core/rtw_led.c
@@ -43,7 +43,7 @@ void BlinkWorkItemCallback(struct work_struct *work)
void ResetLedStatus(struct LED_871x *pLed)
{
pLed->CurrLedState = RTW_LED_OFF; /* Current LED state. */
- pLed->bLedOn = false; /* true if LED is ON, false if LED is OFF. */
+ pLed->led_on = false; /* true if LED is ON, false if LED is OFF. */
pLed->bLedBlinkInProgress = false; /* true if it is blinking, false o.w.. */
pLed->bLedWPSBlinkInProgress = false;
@@ -92,15 +92,10 @@ static void SwLedBlink1(struct LED_871x *pLed)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
/* Change LED according to BlinkingLedState specified. */
- if (pLed->BlinkingLedState == RTW_LED_ON) {
+ if (pLed->BlinkingLedState == RTW_LED_ON)
sw_led_on(padapter, pLed);
- RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
- ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
- } else {
+ else
sw_led_off(padapter, pLed);
- RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
- ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
- }
if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
sw_led_off(padapter, pLed);
@@ -110,7 +105,7 @@ static void SwLedBlink1(struct LED_871x *pLed)
switch (pLed->CurrLedState) {
case LED_BLINK_SLOWLY:
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
@@ -118,7 +113,7 @@ static void SwLedBlink1(struct LED_871x *pLed)
msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
break;
case LED_BLINK_NORMAL:
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
@@ -131,27 +126,25 @@ static void SwLedBlink1(struct LED_871x *pLed)
if (check_fwstate(pmlmepriv, _FW_LINKED)) {
pLed->bLedLinkBlinkInProgress = true;
pLed->CurrLedState = LED_BLINK_NORMAL;
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
mod_timer(&pLed->BlinkTimer, jiffies +
msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
- RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
} else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
pLed->bLedNoLinkBlinkInProgress = true;
pLed->CurrLedState = LED_BLINK_SLOWLY;
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
mod_timer(&pLed->BlinkTimer, jiffies +
msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
- RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
}
pLed->bLedScanBlinkInProgress = false;
} else {
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
@@ -165,27 +158,25 @@ static void SwLedBlink1(struct LED_871x *pLed)
if (check_fwstate(pmlmepriv, _FW_LINKED)) {
pLed->bLedLinkBlinkInProgress = true;
pLed->CurrLedState = LED_BLINK_NORMAL;
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
mod_timer(&pLed->BlinkTimer, jiffies +
msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
- RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
} else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
pLed->bLedNoLinkBlinkInProgress = true;
pLed->CurrLedState = LED_BLINK_SLOWLY;
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
mod_timer(&pLed->BlinkTimer, jiffies +
msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
- RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
}
pLed->bLedBlinkInProgress = false;
} else {
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
@@ -194,7 +185,7 @@ static void SwLedBlink1(struct LED_871x *pLed)
}
break;
case LED_BLINK_WPS:
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
@@ -205,13 +196,12 @@ static void SwLedBlink1(struct LED_871x *pLed)
if (pLed->BlinkingLedState != RTW_LED_ON) {
pLed->bLedLinkBlinkInProgress = true;
pLed->CurrLedState = LED_BLINK_NORMAL;
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
mod_timer(&pLed->BlinkTimer, jiffies +
msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA));
- RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
pLed->bLedWPSBlinkInProgress = false;
} else {
@@ -251,7 +241,7 @@ static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAct
}
pLed->bLedNoLinkBlinkInProgress = true;
pLed->CurrLedState = LED_BLINK_SLOWLY;
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
@@ -274,7 +264,7 @@ static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAct
}
pLed->bLedLinkBlinkInProgress = true;
pLed->CurrLedState = LED_BLINK_NORMAL;
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
@@ -304,7 +294,7 @@ static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAct
pLed->bLedScanBlinkInProgress = true;
pLed->CurrLedState = LED_BLINK_SCAN;
pLed->BlinkTimes = 24;
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
@@ -329,7 +319,7 @@ static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAct
pLed->bLedBlinkInProgress = true;
pLed->CurrLedState = LED_BLINK_TXRX;
pLed->BlinkTimes = 2;
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
@@ -358,7 +348,7 @@ static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAct
}
pLed->bLedWPSBlinkInProgress = true;
pLed->CurrLedState = LED_BLINK_WPS;
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
@@ -387,7 +377,7 @@ static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAct
else
pLed->bLedWPSBlinkInProgress = true;
pLed->CurrLedState = LED_BLINK_WPS_STOP;
- if (pLed->bLedOn) {
+ if (pLed->led_on) {
pLed->BlinkingLedState = RTW_LED_OFF;
mod_timer(&pLed->BlinkTimer, jiffies +
msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA));
@@ -404,7 +394,7 @@ static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAct
}
pLed->bLedNoLinkBlinkInProgress = true;
pLed->CurrLedState = LED_BLINK_SLOWLY;
- if (pLed->bLedOn)
+ if (pLed->led_on)
pLed->BlinkingLedState = RTW_LED_OFF;
else
pLed->BlinkingLedState = RTW_LED_ON;
@@ -439,9 +429,6 @@ static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAct
default:
break;
}
-
- RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
- ("Led %d\n", pLed->CurrLedState));
}
void blink_handler(struct LED_871x *pLed)
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c
index b6ac5b8915b1..71d205f3d73d 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c
@@ -19,6 +19,7 @@
#include <wlan_bssdef.h>
#include <rtw_ioctl_set.h>
#include <linux/vmalloc.h>
+#include <linux/etherdevice.h>
extern const u8 MCS_rate_1R[16];
@@ -32,8 +33,6 @@ int rtw_init_mlme_priv(struct adapter *padapter)
/* We don't need to memset padapter->XXX to zero, because adapter is allocated by vzalloc(). */
- pmlmepriv->nic_hdl = (u8 *)padapter;
-
pmlmepriv->pscanned = NULL;
pmlmepriv->fw_state = 0;
pmlmepriv->cur_network.network.InfrastructureMode = Ndis802_11AutoUnknown;
@@ -118,8 +117,6 @@ struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv)
list_del_init(&pnetwork->list);
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("rtw_alloc_network: ptr=%p\n", &pnetwork->list));
pnetwork->network_type = 0;
pnetwork->fixed = false;
pnetwork->last_scanned = jiffies;
@@ -181,20 +178,16 @@ struct wlan_network *rtw_find_network(struct __queue *scanned_queue, u8 *addr)
{
struct list_head *phead, *plist;
struct wlan_network *pnetwork = NULL;
- u8 zero_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
- if (!memcmp(zero_addr, addr, ETH_ALEN)) {
+ if (is_zero_ether_addr(addr)) {
pnetwork = NULL;
goto exit;
}
phead = get_list_head(scanned_queue);
- plist = phead->next;
-
- while (plist != phead) {
- pnetwork = container_of(plist, struct wlan_network, list);
+ list_for_each(plist, phead) {
+ pnetwork = list_entry(plist, struct wlan_network, list);
if (!memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN))
break;
- plist = plist->next;
}
if (plist == phead)
pnetwork = NULL;
@@ -204,23 +197,17 @@ exit:
void rtw_free_network_queue(struct adapter *padapter, u8 isfreeall)
{
- struct list_head *phead, *plist;
- struct wlan_network *pnetwork;
+ struct list_head *phead;
+ struct wlan_network *pnetwork, *temp;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct __queue *scanned_queue = &pmlmepriv->scanned_queue;
spin_lock_bh(&scanned_queue->lock);
phead = get_list_head(scanned_queue);
- plist = phead->next;
-
- while (phead != plist) {
- pnetwork = container_of(plist, struct wlan_network, list);
-
- plist = plist->next;
-
+ list_for_each_entry_safe(pnetwork, temp, phead, list)
_rtw_free_network(pmlmepriv, pnetwork, isfreeall);
- }
+
spin_unlock_bh(&scanned_queue->lock);
}
@@ -229,15 +216,10 @@ int rtw_if_up(struct adapter *padapter)
int res;
if (padapter->bDriverStopped || padapter->bSurpriseRemoved ||
- !check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("%s:bDriverStopped(%d) OR bSurpriseRemoved(%d)",
- __func__, padapter->bDriverStopped,
- padapter->bSurpriseRemoved));
+ !check_fwstate(&padapter->mlmepriv, _FW_LINKED))
res = false;
- } else {
+ else
res = true;
- }
return res;
}
@@ -400,17 +382,14 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t
spin_lock_bh(&queue->lock);
phead = get_list_head(queue);
- plist = phead->next;
-
- while (phead != plist) {
- pnetwork = container_of(plist, struct wlan_network, list);
+ list_for_each(plist, phead) {
+ pnetwork = list_entry(plist, struct wlan_network, list);
if (is_same_network(&pnetwork->network, target))
break;
if ((oldest == ((struct wlan_network *)0)) ||
time_after(oldest->last_scanned, pnetwork->last_scanned))
oldest = pnetwork;
- plist = plist->next;
}
/* If we didn't find a match, then get a new network slot to initialize
* with this beacon's information
@@ -440,11 +419,8 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t
pnetwork = rtw_alloc_network(pmlmepriv); /* will update scan_time */
- if (!pnetwork) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
- ("\n\n\nsomething wrong here\n\n\n"));
+ if (!pnetwork)
goto exit;
- }
bssid_ex_sz = get_wlan_bssid_ex_sz(target);
target->Length = bssid_ex_sz;
@@ -520,10 +496,8 @@ static int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *
bselected = false;
}
- if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) {
- DBG_88E("desired_encmode: %d, privacy: %d\n", desired_encmode, privacy);
+ if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0))
bselected = false;
- }
if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode)
@@ -533,12 +507,6 @@ static int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *
return bselected;
}
-/* TODO: Perry: For Power Management */
-void rtw_atimdone_event_callback(struct adapter *adapter, u8 *pbuf)
-{
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("receive atimdone_event\n"));
-}
-
void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf)
{
u32 len;
@@ -547,15 +515,9 @@ void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf)
pnetwork = (struct wlan_bssid_ex *)pbuf;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("%s, ssid=%s\n", __func__, pnetwork->ssid.ssid));
-
len = get_wlan_bssid_ex_sz(pnetwork);
- if (len > (sizeof(struct wlan_bssid_ex))) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
- ("\n****%s: return a wrong bss ***\n", __func__));
+ if (len > (sizeof(struct wlan_bssid_ex)))
return;
- }
spin_lock_bh(&pmlmepriv->lock);
/* update IBSS_network 's timestamp */
@@ -598,14 +560,9 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf)
pmlmepriv->wps_probe_req_ie = NULL;
}
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("%s: fw_state:%x\n\n", __func__, get_fwstate(pmlmepriv)));
-
if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
del_timer_sync(&pmlmepriv->scan_to_timer);
_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
- } else {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("nic status=%x, survey done event comes too late!\n", get_fwstate(pmlmepriv)));
}
rtw_set_signal_stat_timer(&adapter->recvpriv);
@@ -624,8 +581,6 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf)
_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("switching to adhoc master\n"));
-
memcpy(&pdev_network->ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid));
rtw_update_registrypriv_dev_network(adapter);
@@ -633,8 +588,7 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf)
pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;
- if (rtw_createbss_cmd(adapter) != _SUCCESS)
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error=>rtw_createbss_cmd status FAIL\n"));
+ rtw_createbss_cmd(adapter);
pmlmepriv->to_join = false;
}
}
@@ -651,7 +605,6 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf)
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
rtw_indicate_connect(adapter);
} else {
- DBG_88E("try_to_join, but select scanning queue fail, to_roaming:%d\n", pmlmepriv->to_roaming);
if (pmlmepriv->to_roaming != 0) {
if (--pmlmepriv->to_roaming == 0 ||
rtw_sitesurvey_cmd(adapter, &pmlmepriv->assoc_ssid, 1, NULL, 0) != _SUCCESS) {
@@ -688,7 +641,6 @@ static void free_scanqueue(struct mlme_priv *pmlmepriv)
struct __queue *scan_queue = &pmlmepriv->scanned_queue;
struct list_head *plist, *phead, *ptemp;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+%s\n", __func__));
spin_lock_bh(&scan_queue->lock);
spin_lock_bh(&free_queue->lock);
@@ -728,11 +680,6 @@ void rtw_free_assoc_resources_locked(struct adapter *adapter)
struct sta_priv *pstapriv = &adapter->stapriv;
struct wlan_network *tgt_network = &pmlmepriv->cur_network;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_free_assoc_resources\n"));
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("tgt_network->network.MacAddress=%pM ssid=%s\n",
- tgt_network->network.MacAddress, tgt_network->network.ssid.ssid));
-
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_AP_STATE)) {
struct sta_info *psta;
@@ -759,8 +706,6 @@ void rtw_free_assoc_resources_locked(struct adapter *adapter)
pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress);
if (pwlan)
pwlan->fixed = false;
- else
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_assoc_resources:pwlan==NULL\n\n"));
if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count == 1)))
rtw_free_network_nolock(pmlmepriv, pwlan);
@@ -775,8 +720,6 @@ void rtw_indicate_connect(struct adapter *padapter)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+%s\n", __func__));
-
pmlmepriv->to_join = false;
if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
@@ -790,8 +733,6 @@ void rtw_indicate_connect(struct adapter *padapter)
pmlmepriv->to_roaming = 0;
rtw_set_scan_deny(padapter, 3000);
-
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-%s: fw_state=0x%08x\n", __func__, get_fwstate(pmlmepriv)));
}
/*
@@ -801,8 +742,6 @@ void rtw_indicate_disconnect(struct adapter *padapter)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+%s\n", __func__));
-
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING | WIFI_UNDER_WPS);
if (pmlmepriv->to_roaming > 0)
@@ -837,7 +776,6 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str
psta = rtw_alloc_stainfo(pstapriv, pnetwork->network.MacAddress);
if (psta) { /* update ptarget_sta */
- DBG_88E("%s\n", __func__);
psta->aid = pnetwork->join_res;
psta->mac_id = 0;
/* sta mode */
@@ -900,12 +838,6 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wlan_network *cur_network = &pmlmepriv->cur_network;
- DBG_88E("%s\n", __func__);
-
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("\nfw_state:%x, BSSID:%pM\n",
- get_fwstate(pmlmepriv), pnetwork->network.MacAddress));
-
/* why not use ptarget_wlan?? */
memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.Length);
/* some ies in pnetwork is wrong, so we should use ptarget_wlan ies */
@@ -934,7 +866,6 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net
break;
default:
pmlmepriv->fw_state = WIFI_NULL_STATE;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Invalid network_mode\n"));
break;
}
@@ -961,27 +892,16 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf)
struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL;
unsigned int the_same_macaddr = false;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("joinbss event call back received with res=%d\n", pnetwork->join_res));
-
rtw_get_encrypt_decrypt_from_registrypriv(adapter);
- if (pmlmepriv->assoc_ssid.ssid_length == 0)
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ joinbss event call back for Any SSid\n"));
- else
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ rtw_joinbss_event_callback for SSid:%s\n", pmlmepriv->assoc_ssid.ssid));
-
the_same_macaddr = !memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN);
pnetwork->network.Length = get_wlan_bssid_ex_sz(&pnetwork->network);
- if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n ***joinbss_evt_callback return a wrong bss ***\n\n"));
+ if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex))
return;
- }
spin_lock_bh(&pmlmepriv->lock);
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\nrtw_joinbss_event_callback!! _enter_critical\n"));
-
if (pnetwork->join_res > 0) {
spin_lock_bh(&pmlmepriv->scanned_queue.lock);
if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) {
@@ -1019,7 +939,6 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf)
if (ptarget_wlan) {
rtw_joinbss_update_network(adapter, ptarget_wlan, pnetwork);
} else {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't find ptarget_wlan when joinbss_event callback\n"));
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
goto ignore_joinbss_callback;
}
@@ -1028,7 +947,6 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf)
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork);
if (!ptarget_sta) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't update stainfo when joinbss_event callback\n"));
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
goto ignore_joinbss_callback;
}
@@ -1037,18 +955,11 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf)
/* s4. indicate connect */
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
rtw_indicate_connect(adapter);
- } else {
- /* adhoc mode will rtw_indicate_connect when rtw_stassoc_event_callback */
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("adhoc mode, fw_state:%x", get_fwstate(pmlmepriv)));
}
/* s5. Cancel assoc_timer */
del_timer_sync(&pmlmepriv->assoc_timer);
-
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("Cancel assoc_timer\n"));
-
} else {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_joinbss_event_callback err: fw_state:%x", get_fwstate(pmlmepriv)));
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
goto ignore_joinbss_callback;
}
@@ -1060,10 +971,8 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf)
mod_timer(&pmlmepriv->assoc_timer,
jiffies + msecs_to_jiffies(1));
- if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("fail! clear _FW_UNDER_LINKING ^^^fw_state=%x\n", get_fwstate(pmlmepriv)));
+ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
- }
} else { /* if join_res < 0 (join fails), then try again */
mod_timer(&pmlmepriv->assoc_timer,
jiffies + msecs_to_jiffies(1));
@@ -1150,23 +1059,16 @@ void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf)
#endif
/* for AD-HOC mode */
psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr);
- if (psta) {
+ if (psta)
/* the sta have been in sta_info_queue => do nothing */
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
- ("Error: %s: sta has been in sta_hash_queue\n",
- __func__));
return; /* between drv has received this event before and fw have not yet to set key to CAM_ENTRY) */
- }
psta = rtw_alloc_stainfo(&adapter->stapriv, pstassoc->macaddr);
- if (!psta) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
- ("Can't alloc sta_info when %s\n", __func__));
+ if (!psta)
return;
- }
+
/* to do: init sta_info variable */
psta->qos_option = 0;
psta->mac_id = (uint)pstassoc->cam_id;
- DBG_88E("%s\n", __func__);
/* for ad-hoc mode */
rtw_hal_set_odm_var(adapter, HAL_ODM_STA_INFO, psta, true);
rtw_stassoc_hw_rpt(adapter, psta);
@@ -1208,8 +1110,6 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf)
else
mac_id = pstadel->mac_id;
- DBG_88E("%s(mac_id=%d)=%pM\n", __func__, mac_id, pstadel->macaddr);
-
if (mac_id >= 0) {
u16 media_status;
@@ -1280,18 +1180,12 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf)
_clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE);
}
- if (rtw_createbss_cmd(adapter) != _SUCCESS)
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error=>stadel_event_callback: rtw_createbss_cmd status FAIL***\n "));
+ rtw_createbss_cmd(adapter);
}
}
spin_unlock_bh(&pmlmepriv->lock);
}
-void rtw_cpwm_event_callback(struct adapter *padapter, u8 *pbuf)
-{
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+%s !!!\n", __func__));
-}
-
/*
* _rtw_join_timeout_handler - Timeout/failure handler for CMD JoinBss
* @adapter: pointer to struct adapter structure
@@ -1302,8 +1196,6 @@ void _rtw_join_timeout_handler (struct timer_list *t)
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
int do_join_r;
- DBG_88E("%s, fw_state=%x\n", __func__, get_fwstate(pmlmepriv));
-
if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
return;
@@ -1313,15 +1205,11 @@ void _rtw_join_timeout_handler (struct timer_list *t)
while (1) {
pmlmepriv->to_roaming--;
if (pmlmepriv->to_roaming != 0) { /* try another , */
- DBG_88E("%s try another roaming\n", __func__);
do_join_r = rtw_do_join(adapter);
- if (do_join_r != _SUCCESS) {
- DBG_88E("%s roaming do_join return %d\n", __func__, do_join_r);
+ if (do_join_r != _SUCCESS)
continue;
- }
break;
}
- DBG_88E("%s We've try roaming but fail\n", __func__);
rtw_indicate_disconnect(adapter);
break;
}
@@ -1342,7 +1230,6 @@ void rtw_scan_timeout_handler (struct timer_list *t)
mlmepriv.scan_to_timer);
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
- DBG_88E(FUNC_ADPT_FMT" fw_state=%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv));
spin_lock_bh(&pmlmepriv->lock);
_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
spin_unlock_bh(&pmlmepriv->lock);
@@ -1357,7 +1244,6 @@ static void rtw_auto_scan_handler(struct adapter *padapter)
if (pmlmepriv->scan_interval > 0) {
pmlmepriv->scan_interval--;
if (pmlmepriv->scan_interval == 0) {
- DBG_88E("%s\n", __func__);
rtw_set_802_11_bssid_list_scan(padapter, NULL, 0);
pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */
}
@@ -1431,15 +1317,6 @@ static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv
*candidate = competitor;
updated = true;
}
- if (updated) {
- DBG_88E("[by_bssid:%u][assoc_ssid:%s]new candidate: %s(%pM rssi:%d\n",
- pmlmepriv->assoc_by_bssid,
- pmlmepriv->assoc_ssid.ssid,
- (*candidate)->network.ssid.ssid,
- (*candidate)->network.MacAddress,
- (int)(*candidate)->network.Rssi);
- DBG_88E("[to_roaming:%u]\n", pmlmepriv->to_roaming);
- }
exit:
return updated;
@@ -1456,7 +1333,7 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv)
{
int ret;
struct list_head *phead;
- struct adapter *adapter;
+ struct adapter *adapter = container_of(pmlmepriv, struct adapter, mlmepriv);
struct __queue *queue = &pmlmepriv->scanned_queue;
struct wlan_network *pnetwork = NULL;
struct wlan_network *candidate = NULL;
@@ -1464,32 +1341,18 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv)
spin_lock_bh(&pmlmepriv->scanned_queue.lock);
phead = get_list_head(queue);
- adapter = (struct adapter *)pmlmepriv->nic_hdl;
- pmlmepriv->pscanned = phead->next;
- while (phead != pmlmepriv->pscanned) {
- pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list);
- if (!pnetwork) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s return _FAIL:(pnetwork==NULL)\n", __func__));
- ret = _FAIL;
- goto exit;
- }
- pmlmepriv->pscanned = pmlmepriv->pscanned->next;
+ list_for_each(pmlmepriv->pscanned, phead) {
+ pnetwork = list_entry(pmlmepriv->pscanned,
+ struct wlan_network, list);
rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork);
}
if (!candidate) {
- DBG_88E("%s: return _FAIL(candidate==NULL)\n", __func__);
ret = _FAIL;
goto exit;
- } else {
- DBG_88E("%s: candidate: %s(%pM ch:%u)\n", __func__,
- candidate->network.ssid.ssid, candidate->network.MacAddress,
- candidate->network.Configuration.DSConfig);
}
/* check for situation of _FW_LINKED */
if (check_fwstate(pmlmepriv, _FW_LINKED)) {
- DBG_88E("%s: _FW_LINKED while ask_for_joinbss!!!\n", __func__);
-
rtw_disassoc_cmd(adapter, 0, true);
rtw_indicate_disconnect(adapter);
rtw_free_assoc_resources_locked(adapter);
@@ -1500,10 +1363,6 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv)
u8 cur_ant;
rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(cur_ant));
- DBG_88E("#### Opt_Ant_(%s), cur_Ant(%s)\n",
- (candidate->network.PhyInfo.Optimum_antenna == 2) ? "A" : "B",
- (cur_ant == 2) ? "A" : "B"
- );
}
ret = rtw_joinbss_cmd(adapter, candidate);
@@ -1539,9 +1398,6 @@ int rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv)
pcmd->rsp = NULL;
pcmd->rspsz = 0;
INIT_LIST_HEAD(&pcmd->list);
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
- ("after enqueue set_auth_cmd, auth_mode=%x\n",
- psecuritypriv->dot11AuthAlgrthm));
res = rtw_enqueue_cmd(pcmdpriv, pcmd);
exit:
return res;
@@ -1566,26 +1422,13 @@ int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, in
goto err_free_cmd;
}
- if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
+ if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)
psetkeyparm->algorithm = (unsigned char)psecuritypriv->dot118021XGrpPrivacy;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
- ("\n %s: psetkeyparm->algorithm=(unsigned char)psecuritypriv->dot118021XGrpPrivacy=%d\n",
- __func__, psetkeyparm->algorithm));
- } else {
+ else
psetkeyparm->algorithm = (u8)psecuritypriv->dot11PrivacyAlgrthm;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
- ("\n %s: psetkeyparm->algorithm=(u8)psecuritypriv->dot11PrivacyAlgrthm=%d\n",
- __func__, psetkeyparm->algorithm));
- }
psetkeyparm->keyid = (u8)keyid;/* 0~3 */
psetkeyparm->set_tx = set_tx;
pmlmepriv->key_mask |= BIT(psetkeyparm->keyid);
- DBG_88E("==> %s algorithm(%x), keyid(%x), key_mask(%x)\n",
- __func__, psetkeyparm->algorithm, psetkeyparm->keyid,
- pmlmepriv->key_mask);
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
- ("\n %s: psetkeyparm->algorithm=%d psetkeyparm->keyid=(u8)keyid=%d\n",
- __func__, psetkeyparm->algorithm, keyid));
switch (psetkeyparm->algorithm) {
case _WEP40_:
@@ -1609,9 +1452,6 @@ int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, in
psetkeyparm->grpkey = 1;
break;
default:
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
- ("\n %s:psecuritypriv->dot11PrivacyAlgrthm=%x (must be 1 or 2 or 4 or 5)\n",
- __func__, psecuritypriv->dot11PrivacyAlgrthm));
res = _FAIL;
goto err_free_parm;
}
@@ -1717,11 +1557,6 @@ int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
struct security_priv *psecuritypriv = &adapter->securitypriv;
uint ndisauthmode = psecuritypriv->ndisauthtype;
- uint ndissecuritytype = psecuritypriv->ndisencryptstatus;
-
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
- ("+%s: ndisauthmode=%d ndissecuritytype=%d\n", __func__,
- ndisauthmode, ndissecuritytype));
/* copy fixed ie only */
memcpy(out_ie, in_ie, 12);
@@ -1801,9 +1636,6 @@ void rtw_update_registrypriv_dev_network(struct adapter *adapter)
}
pdev_network->Configuration.DSConfig = pregistrypriv->channel;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("pregistrypriv->channel=%d, pdev_network->Configuration.DSConfig=0x%x\n",
- pregistrypriv->channel, pdev_network->Configuration.DSConfig));
if (cur_network->network.InfrastructureMode == Ndis802_11IBSS)
pdev_network->Configuration.ATIMWindow = 0;
@@ -1936,8 +1768,6 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len)
if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable))
return;
- DBG_88E("+%s()\n", __func__);
-
/* maybe needs check if ap supports rx ampdu. */
if ((!phtpriv->ampdu_enable) && (pregistrypriv->ampdu_enable == 1)) {
if (pregistrypriv->wifi_spec == 1)
@@ -1974,8 +1804,6 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len)
/* Config SM Power Save setting */
pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.cap_info) & 0x0C) >> 2;
- if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC)
- DBG_88E("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__);
/* Config current HT Protection mode. */
pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3;
@@ -2010,7 +1838,6 @@ void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitfr
issued |= (phtpriv->candidate_tid_bitmap >> priority) & 0x1;
if (issued == 0) {
- DBG_88E("%s, p=%d\n", __func__, priority);
psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority);
rtw_addbareq_cmd(padapter, (u8)priority, pattrib->ra);
}
@@ -2038,9 +1865,6 @@ void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network)
pnetwork = &pmlmepriv->cur_network;
if (pmlmepriv->to_roaming > 0) {
- DBG_88E("roaming from %s(%pM length:%d\n",
- pnetwork->network.ssid.ssid, pnetwork->network.MacAddress,
- pnetwork->network.ssid.ssid_length);
memcpy(&pmlmepriv->assoc_ssid, &pnetwork->network.ssid, sizeof(struct ndis_802_11_ssid));
pmlmepriv->assoc_by_bssid = false;
@@ -2050,13 +1874,11 @@ void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network)
if (do_join_r == _SUCCESS)
break;
- 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;
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
index 50d3c3631be0..25653ebfaafd 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
@@ -7,6 +7,7 @@
#define _RTW_MLME_EXT_C_
#include <linux/ieee80211.h>
+#include <linux/etherdevice.h>
#include <asm/unaligned.h>
#include <osdep_service.h>
@@ -148,14 +149,11 @@ struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv)
struct xmit_buf *pxmitbuf;
pmgntframe = rtw_alloc_xmitframe(pxmitpriv);
- if (!pmgntframe) {
- DBG_88E("%s, alloc xmitframe fail\n", __func__);
+ if (!pmgntframe)
return NULL;
- }
pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv);
if (!pxmitbuf) {
- DBG_88E("%s, alloc xmitbuf fail\n", __func__);
rtw_free_xmitframe(pxmitpriv, pmgntframe);
return NULL;
}
@@ -177,7 +175,6 @@ void update_mgnt_tx_rate(struct adapter *padapter, u8 rate)
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
pmlmeext->tx_rate = rate;
- DBG_88E("%s(): rate = %x\n", __func__, rate);
}
void update_mgntframe_attrib(struct adapter *padapter, struct pkt_attrib *pattrib)
@@ -314,13 +311,10 @@ static void issue_beacon(struct adapter *padapter, int timeout_ms)
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
- u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
- if (!pmgntframe) {
- DBG_88E("%s, alloc mgnt frame fail\n", __func__);
+ if (!pmgntframe)
return;
- }
#if defined(CONFIG_88EU_AP_MODE)
spin_lock_bh(&pmlmepriv->bcn_update_lock);
#endif
@@ -338,13 +332,13 @@ static void issue_beacon(struct adapter *padapter, int timeout_ms)
fctrl = &pwlanhdr->frame_control;
*(fctrl) = 0;
- ether_addr_copy(pwlanhdr->addr1, bc_addr);
+ eth_broadcast_addr(pwlanhdr->addr1);
ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
ether_addr_copy(pwlanhdr->addr3, cur_network->MacAddress);
SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
/* pmlmeext->mgnt_seq++; */
- SetFrameSubType(pframe, WIFI_BEACON);
+ SetFrameSubType(pframe, IEEE80211_STYPE_BEACON);
pframe += sizeof(struct ieee80211_hdr_3addr);
pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
@@ -428,14 +422,11 @@ _issue_bcn:
spin_unlock_bh(&pmlmepriv->bcn_update_lock);
#endif
- if ((pattrib->pktlen + TXDESC_SIZE) > 512) {
- DBG_88E("beacon frame too large\n");
+ if ((pattrib->pktlen + TXDESC_SIZE) > 512)
return;
- }
pattrib->last_txcmdsz = pattrib->pktlen;
- /* DBG_88E("issue bcn_sz=%d\n", pattrib->last_txcmdsz); */
if (timeout_ms > 0)
dump_mgntframe_and_wait(padapter, pmgntframe, timeout_ms);
else
@@ -462,10 +453,8 @@ static void issue_probersp(struct adapter *padapter, unsigned char *da)
unsigned int rate_len;
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
- if (!pmgntframe) {
- DBG_88E("%s, alloc mgnt frame fail\n", __func__);
+ if (!pmgntframe)
return;
- }
/* update attribute */
pattrib = &pmgntframe->attrib;
@@ -487,7 +476,7 @@ static void issue_probersp(struct adapter *padapter, unsigned char *da)
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
- SetFrameSubType(fctrl, WIFI_PROBERSP);
+ SetFrameSubType(fctrl, IEEE80211_STYPE_PROBE_RESP);
pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr);
pattrib->pktlen = pattrib->hdrlen;
@@ -604,9 +593,6 @@ static int issue_probereq(struct adapter *padapter,
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
int bssrate_len = 0;
- u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+%s\n", __func__));
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
if (!pmgntframe)
@@ -632,15 +618,15 @@ static int issue_probereq(struct adapter *padapter,
ether_addr_copy(pwlanhdr->addr3, da);
} else {
/* broadcast probe request frame */
- ether_addr_copy(pwlanhdr->addr1, bc_addr);
- ether_addr_copy(pwlanhdr->addr3, bc_addr);
+ eth_broadcast_addr(pwlanhdr->addr1);
+ eth_broadcast_addr(pwlanhdr->addr3);
}
ether_addr_copy(pwlanhdr->addr2, mac);
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
- SetFrameSubType(pframe, WIFI_PROBEREQ);
+ SetFrameSubType(pframe, IEEE80211_STYPE_PROBE_REQ);
pframe += sizeof(struct ieee80211_hdr_3addr);
pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
@@ -668,9 +654,6 @@ static int issue_probereq(struct adapter *padapter,
pattrib->last_txcmdsz = pattrib->pktlen;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
- ("issuing probe_req, tx_len=%d\n", pattrib->last_txcmdsz));
-
if (wait_ack) {
ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe);
} else {
@@ -688,7 +671,6 @@ static int issue_probereq_ex(struct adapter *padapter,
{
int ret;
int i = 0;
- unsigned long start = jiffies;
do {
ret = issue_probereq(padapter, pssid, da, wait_ms > 0);
@@ -707,19 +689,6 @@ static int issue_probereq_ex(struct adapter *padapter,
ret = _SUCCESS;
goto exit;
}
-
- if (try_cnt && wait_ms) {
- if (da)
- DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
- FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt,
- jiffies_to_msecs(jiffies - start));
- else
- DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
- FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt,
- jiffies_to_msecs(jiffies - start));
- }
exit:
return ret;
}
@@ -762,7 +731,7 @@ static void issue_auth(struct adapter *padapter, struct sta_info *psta,
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
- SetFrameSubType(pframe, WIFI_AUTH);
+ SetFrameSubType(pframe, IEEE80211_STYPE_AUTH);
pframe += sizeof(struct ieee80211_hdr_3addr);
pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
@@ -865,7 +834,6 @@ static void issue_auth(struct adapter *padapter, struct sta_info *psta,
pattrib->last_txcmdsz = pattrib->pktlen;
rtw_wep_encrypt(padapter, pmgntframe);
- DBG_88E("%s\n", __func__);
dump_mgntframe(padapter, pmgntframe);
}
@@ -887,8 +855,6 @@ static void issue_asocrsp(struct adapter *padapter, unsigned short status,
u8 *ie = pnetwork->ies;
__le16 lestatus, leval;
- DBG_88E("%s\n", __func__);
-
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
if (!pmgntframe)
return;
@@ -912,7 +878,7 @@ static void issue_asocrsp(struct adapter *padapter, unsigned short status,
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
- if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP))
+ if ((pkt_type == IEEE80211_STYPE_ASSOC_RESP) || (pkt_type == IEEE80211_STYPE_REASSOC_RESP))
SetFrameSubType(pwlanhdr, pkt_type);
else
return;
@@ -1034,7 +1000,7 @@ static void issue_assocreq(struct adapter *padapter)
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
- SetFrameSubType(pframe, WIFI_ASSOCREQ);
+ SetFrameSubType(pframe, IEEE80211_STYPE_ASSOC_REQ);
pframe += sizeof(struct ieee80211_hdr_3addr);
pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
@@ -1066,7 +1032,6 @@ static void issue_assocreq(struct adapter *padapter)
for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
if (pmlmeinfo->network.SupportedRates[i] == 0)
break;
- DBG_88E("network.SupportedRates[%d]=%02X\n", i, pmlmeinfo->network.SupportedRates[i]);
}
for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
@@ -1081,17 +1046,12 @@ static void issue_assocreq(struct adapter *padapter)
break;
}
- if (j == sta_bssrate_len) {
- /* the rate is not supported by STA */
- DBG_88E("%s(): the rate[%d]=%02X is not supported by STA!\n", __func__, i, pmlmeinfo->network.SupportedRates[i]);
- } else {
+ if (j != sta_bssrate_len)
/* the rate is supported by STA */
bssrate[index++] = pmlmeinfo->network.SupportedRates[i];
- }
}
bssrate_len = index;
- DBG_88E("bssrate_len=%d\n", bssrate_len);
if (bssrate_len == 0) {
rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf);
@@ -1226,7 +1186,7 @@ static int _issue_nulldata(struct adapter *padapter, unsigned char *da,
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
- SetFrameSubType(pframe, WIFI_DATA_NULL);
+ SetFrameSubType(pframe, IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC);
pframe += sizeof(struct ieee80211_hdr_3addr);
pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
@@ -1251,7 +1211,6 @@ int issue_nulldata(struct adapter *padapter, unsigned char *da,
{
int ret;
int i = 0;
- unsigned long start = jiffies;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
@@ -1276,19 +1235,6 @@ int issue_nulldata(struct adapter *padapter, unsigned char *da,
ret = _SUCCESS;
goto exit;
}
-
- if (try_cnt && wait_ms) {
- if (da)
- DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
- FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt,
- jiffies_to_msecs(jiffies - start));
- else
- DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
- FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt,
- jiffies_to_msecs(jiffies - start));
- }
exit:
return ret;
}
@@ -1309,8 +1255,6 @@ static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da,
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
- DBG_88E("%s\n", __func__);
-
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
if (!pmgntframe)
goto exit;
@@ -1355,7 +1299,7 @@ static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da,
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
- SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
+ SetFrameSubType(pframe, IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC);
pframe += sizeof(struct ieee80211_qos_hdr);
pattrib->pktlen = sizeof(struct ieee80211_qos_hdr);
@@ -1380,7 +1324,6 @@ int issue_qos_nulldata(struct adapter *padapter, unsigned char *da,
{
int ret;
int i = 0;
- unsigned long start = jiffies;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
@@ -1405,19 +1348,6 @@ int issue_qos_nulldata(struct adapter *padapter, unsigned char *da,
ret = _SUCCESS;
goto exit;
}
-
- if (try_cnt && wait_ms) {
- if (da)
- DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
- FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt,
- jiffies_to_msecs(jiffies - start));
- else
- DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
- FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt,
- jiffies_to_msecs(jiffies - start));
- }
exit:
return ret;
}
@@ -1460,7 +1390,7 @@ static int _issue_deauth(struct adapter *padapter, unsigned char *da,
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
- SetFrameSubType(pframe, WIFI_DEAUTH);
+ SetFrameSubType(pframe, IEEE80211_STYPE_DEAUTH);
pframe += sizeof(struct ieee80211_hdr_3addr);
pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
@@ -1485,7 +1415,6 @@ exit:
int issue_deauth(struct adapter *padapter, unsigned char *da,
unsigned short reason)
{
- DBG_88E("%s to %pM\n", __func__, da);
return _issue_deauth(padapter, da, reason, false);
}
@@ -1495,7 +1424,6 @@ static int issue_deauth_ex(struct adapter *padapter, u8 *da,
{
int ret;
int i = 0;
- unsigned long start = jiffies;
do {
ret = _issue_deauth(padapter, da, reason, wait_ms > 0);
@@ -1513,19 +1441,6 @@ static int issue_deauth_ex(struct adapter *padapter, u8 *da,
ret = _SUCCESS;
goto exit;
}
-
- if (try_cnt && wait_ms) {
- if (da)
- DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
- FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt,
- jiffies_to_msecs(jiffies - start));
- else
- DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
- FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
- ret == _SUCCESS ? ", acked" : "", i, try_cnt,
- jiffies_to_msecs(jiffies - start));
- }
exit:
return ret;
}
@@ -1554,8 +1469,6 @@ static void issue_action_BA(struct adapter *padapter, unsigned char *raddr,
struct registry_priv *pregpriv = &padapter->registrypriv;
struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
- DBG_88E("%s, category=%d, action=%d, status=%d\n", __func__, category, action, status);
-
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
if (!pmgntframe)
return;
@@ -1578,7 +1491,7 @@ static void issue_action_BA(struct adapter *padapter, unsigned char *raddr,
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
- SetFrameSubType(pframe, WIFI_ACTION);
+ SetFrameSubType(pframe, IEEE80211_STYPE_ACTION);
pframe += sizeof(struct ieee80211_hdr_3addr);
pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
@@ -1608,8 +1521,6 @@ static void issue_action_BA(struct adapter *padapter, unsigned char *raddr,
if (psta) {
start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07] & 0xfff) + 1;
- DBG_88E("BA_starting_seqctrl=%d for TID=%d\n", start_seq, status & 0x07);
-
psta->BA_starting_seqctrl[status & 0x07] = start_seq;
BA_starting_seqctrl = start_seq << 4;
@@ -1708,8 +1619,6 @@ static void issue_action_BSSCoexistPacket(struct adapter *padapter)
if (pmlmeinfo->bwmode_updated)
return;
- DBG_88E("%s\n", __func__);
-
category = RTW_WLAN_CATEGORY_PUBLIC;
action = ACT_PUBLIC_BSSCOEXIST;
@@ -1735,7 +1644,7 @@ static void issue_action_BSSCoexistPacket(struct adapter *padapter)
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
- SetFrameSubType(pframe, WIFI_ACTION);
+ SetFrameSubType(pframe, IEEE80211_STYPE_ACTION);
pframe += sizeof(struct ieee80211_hdr_3addr);
pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
@@ -1760,16 +1669,13 @@ static void issue_action_BSSCoexistPacket(struct adapter *padapter)
spin_lock_bh(&pmlmepriv->scanned_queue.lock);
phead = get_list_head(queue);
- plist = phead->next;
-
- while (phead != plist) {
+ list_for_each(plist, phead) {
uint len;
u8 *p;
struct wlan_bssid_ex *pbss_network;
- pnetwork = container_of(plist, struct wlan_network, list);
-
- plist = plist->next;
+ pnetwork = list_entry(plist, struct wlan_network,
+ list);
pbss_network = &pnetwork->network;
@@ -1833,8 +1739,7 @@ unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr)
if (initiator == 0) { /* recipient */
for (tid = 0; tid < MAXTID; tid++) {
if (psta->recvreorder_ctrl[tid].enable) {
- DBG_88E("rx agg disable tid(%d)\n", tid);
- issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator) & 0x1F));
+ issue_action_BA(padapter, addr, WLAN_ACTION_DELBA, (((tid << 1) | initiator) & 0x1F));
psta->recvreorder_ctrl[tid].enable = false;
psta->recvreorder_ctrl[tid].indicate_seq = 0xffff;
}
@@ -1842,8 +1747,7 @@ unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr)
} else if (initiator == 1) { /* originator */
for (tid = 0; tid < MAXTID; tid++) {
if (psta->htpriv.agg_enable_bitmap & BIT(tid)) {
- DBG_88E("tx agg disable tid(%d)\n", tid);
- issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator) & 0x1F));
+ issue_action_BA(padapter, addr, WLAN_ACTION_DELBA, (((tid << 1) | initiator) & 0x1F));
psta->htpriv.agg_enable_bitmap &= ~BIT(tid);
psta->htpriv.candidate_tid_bitmap &= ~BIT(tid);
}
@@ -1858,8 +1762,6 @@ unsigned int send_beacon(struct adapter *padapter)
u8 bxmitok = false;
int issue = 0;
int poll = 0;
- unsigned long start = jiffies;
- u32 passing_time;
rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
do {
@@ -1874,17 +1776,9 @@ unsigned int send_beacon(struct adapter *padapter)
if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
return _FAIL;
- if (!bxmitok) {
- DBG_88E("%s fail! %u ms\n", __func__,
- jiffies_to_msecs(jiffies - start));
+ if (!bxmitok)
return _FAIL;
- }
- passing_time = jiffies_to_msecs(jiffies - start);
- if (passing_time > 100 || issue > 3)
- DBG_88E("%s success, issue:%d, poll:%d, %u ms\n",
- __func__, issue, poll,
- jiffies_to_msecs(jiffies - start));
return _SUCCESS;
}
@@ -2024,15 +1918,15 @@ static u8 collect_bss_info(struct adapter *padapter,
subtype = GetFrameSubType(pframe);
- if (subtype == WIFI_BEACON) {
+ if (subtype == IEEE80211_STYPE_BEACON) {
bssid->Reserved[0] = 1;
ie_offset = _BEACON_IE_OFFSET_;
} else {
/* FIXME : more type */
- if (subtype == WIFI_PROBEREQ) {
+ if (subtype == IEEE80211_STYPE_PROBE_REQ) {
ie_offset = _PROBEREQ_IE_OFFSET_;
bssid->Reserved[0] = 2;
- } else if (subtype == WIFI_PROBERSP) {
+ } else if (subtype == IEEE80211_STYPE_PROBE_RESP) {
ie_offset = _PROBERSP_IE_OFFSET_;
bssid->Reserved[0] = 3;
} else {
@@ -2055,16 +1949,12 @@ static u8 collect_bss_info(struct adapter *padapter,
/* checking SSID */
p = rtw_get_ie(bssid->ies + ie_offset, WLAN_EID_SSID, &len, bssid->ie_length - ie_offset);
- if (!p) {
- DBG_88E("marc: cannot find SSID for survey event\n");
+ if (!p)
return _FAIL;
- }
if (len) {
- if (len > NDIS_802_11_LENGTH_SSID) {
- DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len);
+ if (len > NDIS_802_11_LENGTH_SSID)
return _FAIL;
- }
memcpy(bssid->ssid.ssid, (p + 2), len);
bssid->ssid.ssid_length = len;
} else {
@@ -2077,20 +1967,16 @@ static u8 collect_bss_info(struct adapter *padapter,
i = 0;
p = rtw_get_ie(bssid->ies + ie_offset, WLAN_EID_SUPP_RATES, &len, bssid->ie_length - ie_offset);
if (p) {
- if (len > NDIS_802_11_LENGTH_RATES_EX) {
- DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len);
+ if (len > NDIS_802_11_LENGTH_RATES_EX)
return _FAIL;
- }
memcpy(bssid->SupportedRates, (p + 2), len);
i = len;
}
p = rtw_get_ie(bssid->ies + ie_offset, WLAN_EID_EXT_SUPP_RATES, &len, bssid->ie_length - ie_offset);
if (p) {
- if (len > (NDIS_802_11_LENGTH_RATES_EX - i)) {
- DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len);
+ if (len > (NDIS_802_11_LENGTH_RATES_EX - i))
return _FAIL;
- }
memcpy(bssid->SupportedRates + i, (p + 2), len);
}
@@ -2120,7 +2006,7 @@ static u8 collect_bss_info(struct adapter *padapter,
}
}
- if (subtype == WIFI_PROBEREQ) {
+ if (subtype == IEEE80211_STYPE_PROBE_REQ) {
/* FIXME */
bssid->InfrastructureMode = Ndis802_11Infrastructure;
ether_addr_copy(bssid->MacAddress, GetAddr2Ptr(pframe));
@@ -2204,8 +2090,6 @@ static void start_create_ibss(struct adapter *padapter)
/* issue beacon */
if (send_beacon(padapter) == _FAIL) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("issuing beacon frame fail....\n"));
-
report_join_res(padapter, -1);
pmlmeinfo->state = WIFI_FW_NULL_STATE;
} else {
@@ -2217,7 +2101,6 @@ static void start_create_ibss(struct adapter *padapter)
pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
}
} else {
- DBG_88E("%s, invalid cap:%x\n", __func__, caps);
return;
}
}
@@ -2300,7 +2183,6 @@ static void start_clnt_auth(struct adapter *padapter)
/* For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. */
issue_deauth(padapter, (&pmlmeinfo->network)->MacAddress, WLAN_REASON_DEAUTH_LEAVING);
- DBG_88E_LEVEL(_drv_info_, "start auth\n");
issue_auth(padapter, NULL, 0);
set_link_timer(pmlmeext, REAUTH_TO);
@@ -2333,8 +2215,6 @@ static unsigned int receive_disconnect(struct adapter *padapter,
if (memcmp(MacAddr, pnetwork->MacAddress, ETH_ALEN))
return _SUCCESS;
- DBG_88E("%s\n", __func__);
-
if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) {
if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {
pmlmeinfo->state = WIFI_FW_NULL_STATE;
@@ -2382,9 +2262,6 @@ static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid
memset(country, 0, 4);
memcpy(country, p, 3);
p += 3;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
- ("%s: 802.11d country =%s\n", __func__, country));
-
i = 0;
while ((ie - p) >= 3) {
fcn = *(p++);
@@ -2478,12 +2355,8 @@ static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid
i = 0;
while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) {
if (chplan_new[i].ChannelNum == channel) {
- if (chplan_new[i].ScanType == SCAN_PASSIVE) {
+ if (chplan_new[i].ScanType == SCAN_PASSIVE)
chplan_new[i].ScanType = SCAN_ACTIVE;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
- ("%s: change channel %d scan type from passive to active\n",
- __func__, channel));
- }
break;
}
i++;
@@ -2593,7 +2466,6 @@ static unsigned int OnBeacon(struct adapter *padapter,
if (psta) {
ret = rtw_check_bcn_info(padapter, pframe, len);
if (!ret) {
- DBG_88E_LEVEL(_drv_info_, "ap has changed, disconnect now\n ");
receive_disconnect(padapter, pmlmeinfo->network.MacAddress, 65535);
return _SUCCESS;
}
@@ -2656,25 +2528,18 @@ static unsigned int OnAuth(struct adapter *padapter,
if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)
return _FAIL;
- DBG_88E("+%s\n", __func__);
-
sa = GetAddr2Ptr(pframe);
auth_mode = psecuritypriv->dot11AuthAlgrthm;
seq = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + 2));
algorithm = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN));
- DBG_88E("auth alg=%x, seq=%X\n", algorithm, seq);
-
if (auth_mode == 2 && psecuritypriv->dot11PrivacyAlgrthm != _WEP40_ &&
psecuritypriv->dot11PrivacyAlgrthm != _WEP104_)
auth_mode = 0;
if ((algorithm > 0 && auth_mode == 0) || /* rx a shared-key auth but shared not enabled */
(algorithm == 0 && auth_mode == 1)) { /* rx a open-system auth but shared-key is enabled */
- DBG_88E("auth rejected due to bad alg [alg=%d, auth_mib=%d] %02X%02X%02X%02X%02X%02X\n",
- algorithm, auth_mode, sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]);
-
status = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
goto auth_fail;
@@ -2688,10 +2553,8 @@ static unsigned int OnAuth(struct adapter *padapter,
pstat = rtw_get_stainfo(pstapriv, sa);
if (!pstat) {
/* allocate a new one */
- DBG_88E("going to alloc stainfo for sa=%pM\n", sa);
pstat = rtw_alloc_stainfo(pstapriv, sa);
if (!pstat) {
- DBG_88E(" Exceed the upper limit of supported clients...\n");
status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto auth_fail;
}
@@ -2722,8 +2585,6 @@ static unsigned int OnAuth(struct adapter *padapter,
pstat->expire_to = pstapriv->auth_to;
if ((pstat->auth_seq + 1) != seq) {
- DBG_88E("(1)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n",
- seq, pstat->auth_seq + 1);
status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
goto auth_fail;
}
@@ -2735,8 +2596,6 @@ static unsigned int OnAuth(struct adapter *padapter,
pstat->expire_to = pstapriv->assoc_to;
pstat->authalg = algorithm;
} else {
- DBG_88E("(2)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n",
- seq, pstat->auth_seq + 1);
status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
goto auth_fail;
}
@@ -2750,13 +2609,10 @@ static unsigned int OnAuth(struct adapter *padapter,
pstat->auth_seq = 2;
} else if (seq == 3) {
/* checking for challenging txt... */
- DBG_88E("checking for challenging txt...\n");
-
p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + 4 + _AUTH_IE_OFFSET_, WLAN_EID_CHALLENGE, &ie_len,
len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_ - 4);
if (!p || ie_len <= 0) {
- DBG_88E("auth rejected because challenge failure!(1)\n");
status = WLAN_STATUS_CHALLENGE_FAIL;
goto auth_fail;
}
@@ -2767,13 +2623,10 @@ static unsigned int OnAuth(struct adapter *padapter,
/* challenging txt is correct... */
pstat->expire_to = pstapriv->assoc_to;
} else {
- DBG_88E("auth rejected because challenge failure!\n");
status = WLAN_STATUS_CHALLENGE_FAIL;
goto auth_fail;
}
} else {
- DBG_88E("(3)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n",
- seq, pstat->auth_seq + 1);
status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
goto auth_fail;
}
@@ -2816,8 +2669,6 @@ static unsigned int OnAuthClient(struct adapter *padapter,
u8 *pframe = precv_frame->pkt->data;
uint pkt_len = precv_frame->pkt->len;
- DBG_88E("%s\n", __func__);
-
/* check A1 matches or not */
if (memcmp(myid(&padapter->eeprompriv), ieee80211_get_DA((struct ieee80211_hdr *)pframe), ETH_ALEN))
return _SUCCESS;
@@ -2831,7 +2682,6 @@ static unsigned int OnAuthClient(struct adapter *padapter,
status = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + offset + 4));
if (status != 0) {
- DBG_88E("clnt auth fail, status: %d\n", status);
if (status == 13) { /* pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */
if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)
pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open;
@@ -2872,7 +2722,6 @@ static unsigned int OnAuthClient(struct adapter *padapter,
}
if (go2asoc) {
- DBG_88E_LEVEL(_drv_info_, "auth success, start assoc\n");
start_clnt_assoc(padapter);
return _SUCCESS;
}
@@ -2887,7 +2736,7 @@ static unsigned int OnAssocReq(struct adapter *padapter,
u16 capab_info;
struct rtw_ieee802_11_elems elems;
struct sta_info *pstat;
- unsigned char reassoc, *p, *pos, *wpa_ie;
+ unsigned char *p, *pos, *wpa_ie;
unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01};
int i, wpa_ie_len, left;
unsigned char supportRate[16];
@@ -2907,19 +2756,13 @@ static unsigned int OnAssocReq(struct adapter *padapter,
return _FAIL;
frame_type = GetFrameSubType(pframe);
- if (frame_type == WIFI_ASSOCREQ) {
- reassoc = 0;
+ if (frame_type == IEEE80211_STYPE_ASSOC_REQ)
ie_offset = _ASOCREQ_IE_OFFSET_;
- } else { /* WIFI_REASSOCREQ */
- reassoc = 1;
+ else /* IEEE80211_STYPE_REASSOC_REQ */
ie_offset = _REASOCREQ_IE_OFFSET_;
- }
- if (pkt_len < IEEE80211_3ADDR_LEN + ie_offset) {
- DBG_88E("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
- "\n", reassoc, (unsigned long)pkt_len);
+ if (pkt_len < IEEE80211_3ADDR_LEN + ie_offset)
return _FAIL;
- }
pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
if (!pstat) {
@@ -2932,8 +2775,6 @@ static unsigned int OnAssocReq(struct adapter *padapter,
left = pkt_len - (IEEE80211_3ADDR_LEN + ie_offset);
pos = pframe + (IEEE80211_3ADDR_LEN + ie_offset);
- DBG_88E("%s\n", __func__);
-
/* check if this stat has been successfully authenticated/assocated */
if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS)) {
if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS)) {
@@ -2951,8 +2792,6 @@ static unsigned int OnAssocReq(struct adapter *padapter,
/* now parse all ieee802_11 ie to point to elems */
if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed ||
!elems.ssid) {
- DBG_88E("STA %pM sent invalid association request\n",
- pstat->hwaddr);
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto OnAssocReqFail;
}
@@ -2981,7 +2820,6 @@ static unsigned int OnAssocReq(struct adapter *padapter,
/* check if the supported rate is ok */
p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, WLAN_EID_SUPP_RATES, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset);
if (!p) {
- DBG_88E("Rx a sta assoc-req which supported rate is empty!\n");
/* use our own rate set as statoin used */
/* memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); */
/* supportRateNum = AP_BSSRATE_LEN; */
@@ -3072,17 +2910,11 @@ static unsigned int OnAssocReq(struct adapter *padapter,
pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
if (!wpa_ie) {
if (elems.wps_ie) {
- DBG_88E("STA included WPS IE in "
- "(Re)Association Request - assume WPS is "
- "used\n");
pstat->flags |= WLAN_STA_WPS;
/* wpabuf_free(sta->wps_ie); */
/* sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, */
/* elems.wps_ie_len - 4); */
} else {
- DBG_88E("STA did not include WPA/RSN IE "
- "in (Re)Association Request - possible WPS "
- "use\n");
pstat->flags |= WLAN_STA_MAYBE_WPS;
}
@@ -3095,8 +2927,6 @@ static unsigned int OnAssocReq(struct adapter *padapter,
rtw_get_wps_attr_content(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len, WPS_ATTR_SELECTED_REGISTRAR, &selected_registrar, NULL);
if (!selected_registrar) {
- DBG_88E("selected_registrar is false , or AP is not ready to do WPS\n");
-
status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto OnAssocReqFail;
@@ -3107,18 +2937,12 @@ static unsigned int OnAssocReq(struct adapter *padapter,
int copy_len;
if (psecuritypriv->wpa_psk == 0) {
- DBG_88E("STA %pM: WPA/RSN IE in association "
- "request, but AP don't support WPA/RSN\n", pstat->hwaddr);
-
status = WLAN_STATUS_INVALID_IE;
goto OnAssocReqFail;
}
if (elems.wps_ie) {
- DBG_88E("STA included WPS IE in "
- "(Re)Association Request - WPS is "
- "used\n");
pstat->flags |= WLAN_STA_WPS;
copy_len = 0;
} else {
@@ -3202,16 +3026,6 @@ static unsigned int OnAssocReq(struct adapter *padapter,
goto OnAssocReqFail;
}
- if ((pstat->flags & WLAN_STA_HT) &&
- ((pstat->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) ||
- (pstat->wpa_pairwise_cipher & WPA_CIPHER_TKIP))) {
- DBG_88E("HT: %pM tried to "
- "use TKIP with HT association\n", pstat->hwaddr);
-
- /* status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; */
- /* goto OnAssocReqFail; */
- }
-
pstat->flags |= WLAN_STA_NONERP;
for (i = 0; i < pstat->bssratelen; i++) {
if ((pstat->bssrateset[i] & 0x7f) > 22) {
@@ -3235,9 +3049,7 @@ static unsigned int OnAssocReq(struct adapter *padapter,
/* Customer proprietary IE */
/* get a unique AID */
- if (pstat->aid > 0) {
- DBG_88E(" old AID %d\n", pstat->aid);
- } else {
+ if (pstat->aid <= 0) {
for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++)
if (!pstapriv->sta_aid[pstat->aid - 1])
break;
@@ -3246,14 +3058,11 @@ static unsigned int OnAssocReq(struct adapter *padapter,
if (pstat->aid > pstapriv->max_num_sta) {
pstat->aid = 0;
- DBG_88E(" no room for more AIDs\n");
-
status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto OnAssocReqFail;
} else {
pstapriv->sta_aid[pstat->aid - 1] = pstat;
- DBG_88E("allocate new AID=(%d)\n", pstat->aid);
}
}
@@ -3282,13 +3091,12 @@ static unsigned int OnAssocReq(struct adapter *padapter,
sta_info_update(padapter, pstat);
/* issue assoc rsp before notify station join event. */
- if (frame_type == WIFI_ASSOCREQ)
- issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP);
+ if (frame_type == IEEE80211_STYPE_ASSOC_REQ)
+ issue_asocrsp(padapter, status, pstat, IEEE80211_STYPE_ASSOC_RESP);
else
- issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP);
+ issue_asocrsp(padapter, status, pstat, IEEE80211_STYPE_REASSOC_RESP);
/* 2 - report to upper layer */
- DBG_88E("indicate_sta_join_event to upper layer - hostapd\n");
rtw_indicate_sta_assoc_event(padapter, pstat);
/* 3-(1) report sta add event */
@@ -3306,10 +3114,10 @@ asoc_class2_error:
OnAssocReqFail:
pstat->aid = 0;
- if (frame_type == WIFI_ASSOCREQ)
- issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP);
+ if (frame_type == IEEE80211_STYPE_ASSOC_REQ)
+ issue_asocrsp(padapter, status, pstat, IEEE80211_STYPE_ASSOC_RESP);
else
- issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP);
+ issue_asocrsp(padapter, status, pstat, IEEE80211_STYPE_REASSOC_RESP);
#endif /* CONFIG_88EU_AP_MODE */
@@ -3329,8 +3137,6 @@ static unsigned int OnAssocRsp(struct adapter *padapter,
u8 *pframe = precv_frame->pkt->data;
uint pkt_len = precv_frame->pkt->len;
- DBG_88E("%s\n", __func__);
-
/* check A1 matches or not */
if (memcmp(myid(&padapter->eeprompriv), ieee80211_get_DA((struct ieee80211_hdr *)pframe), ETH_ALEN))
return _SUCCESS;
@@ -3346,7 +3152,6 @@ static unsigned int OnAssocRsp(struct adapter *padapter,
/* status */
status = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 2));
if (status > 0) {
- DBG_88E("assoc reject, status code: %d\n", status);
pmlmeinfo->state = WIFI_FW_NULL_STATE;
res = -4;
goto report_assoc_result;
@@ -3381,6 +3186,7 @@ static unsigned int OnAssocRsp(struct adapter *padapter,
break;
case WLAN_EID_ERP_INFO:
ERP_IE_handler(padapter, pIE);
+ break;
default:
break;
}
@@ -3420,16 +3226,11 @@ static unsigned int OnDeAuth(struct adapter *padapter,
reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN));
- DBG_88E("%s Reason code(%d)\n", __func__, reason);
-
#ifdef CONFIG_88EU_AP_MODE
if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
struct sta_info *psta;
struct sta_priv *pstapriv = &padapter->stapriv;
- DBG_88E_LEVEL(_drv_always_, "ap recv deauth reason code(%d) sta:%pM\n",
- reason, GetAddr2Ptr(pframe));
-
psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
if (psta) {
u8 updated = 0;
@@ -3448,9 +3249,6 @@ static unsigned int OnDeAuth(struct adapter *padapter,
return _SUCCESS;
}
#endif
- DBG_88E_LEVEL(_drv_always_, "sta recv deauth reason code(%d) sta:%pM\n",
- reason, GetAddr3Ptr(pframe));
-
receive_disconnect(padapter, GetAddr3Ptr(pframe), reason);
pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
@@ -3473,16 +3271,11 @@ static unsigned int OnDisassoc(struct adapter *padapter,
reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN));
- DBG_88E("%s Reason code(%d)\n", __func__, reason);
-
#ifdef CONFIG_88EU_AP_MODE
if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
struct sta_info *psta;
struct sta_priv *pstapriv = &padapter->stapriv;
- DBG_88E_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n",
- reason, GetAddr2Ptr(pframe));
-
psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
if (psta) {
u8 updated = 0;
@@ -3501,9 +3294,6 @@ static unsigned int OnDisassoc(struct adapter *padapter,
return _SUCCESS;
}
#endif
- DBG_88E_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n",
- reason, GetAddr3Ptr(pframe));
-
receive_disconnect(padapter, GetAddr3Ptr(pframe), reason);
pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
@@ -3513,7 +3303,6 @@ static unsigned int OnDisassoc(struct adapter *padapter,
static unsigned int OnAtim(struct adapter *padapter,
struct recv_frame *precv_frame)
{
- DBG_88E("%s\n", __func__);
return _SUCCESS;
}
@@ -3527,8 +3316,6 @@ static unsigned int on_action_spct(struct adapter *padapter,
u8 category;
u8 action;
- DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
-
psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
if (!psta)
@@ -3575,7 +3362,7 @@ static unsigned int OnAction_back(struct adapter *padapter,
struct recv_reorder_ctrl *preorder_ctrl;
unsigned char *frame_body;
unsigned char category, action;
- unsigned short tid, status, reason_code = 0;
+ unsigned short tid, status;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
u8 *pframe = precv_frame->pkt->data;
@@ -3586,8 +3373,6 @@ static unsigned int OnAction_back(struct adapter *padapter,
ETH_ALEN))/* for if1, sta/ap mode */
return _SUCCESS;
- DBG_88E("%s\n", __func__);
-
if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)
if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS))
return _SUCCESS;
@@ -3605,40 +3390,36 @@ static unsigned int OnAction_back(struct adapter *padapter,
if (!pmlmeinfo->HT_enable)
return _SUCCESS;
action = frame_body[1];
- DBG_88E("%s, action=%d\n", __func__, action);
switch (action) {
- case RTW_WLAN_ACTION_ADDBA_REQ: /* ADDBA request */
+ case WLAN_ACTION_ADDBA_REQ:
memcpy(&pmlmeinfo->ADDBA_req, &frame_body[2], sizeof(struct ADDBA_request));
process_addba_req(padapter, (u8 *)&pmlmeinfo->ADDBA_req, addr);
/* 37 = reject ADDBA Req */
issue_action_BA(padapter, addr,
- RTW_WLAN_ACTION_ADDBA_RESP,
+ WLAN_ACTION_ADDBA_RESP,
pmlmeinfo->accept_addba_req ? 0 : 37);
break;
- case RTW_WLAN_ACTION_ADDBA_RESP: /* ADDBA response */
+ case WLAN_ACTION_ADDBA_RESP:
status = get_unaligned_le16(&frame_body[3]);
tid = (frame_body[5] >> 2) & 0x7;
if (status == 0) { /* successful */
- DBG_88E("agg_enable for TID=%d\n", tid);
psta->htpriv.agg_enable_bitmap |= 1 << tid;
psta->htpriv.candidate_tid_bitmap &= ~BIT(tid);
} else {
psta->htpriv.agg_enable_bitmap &= ~BIT(tid);
}
break;
- case RTW_WLAN_ACTION_DELBA: /* DELBA */
+ case WLAN_ACTION_DELBA:
if ((frame_body[3] & BIT(3)) == 0) {
psta->htpriv.agg_enable_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf));
psta->htpriv.candidate_tid_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf));
- reason_code = get_unaligned_le16(&frame_body[4]);
} else if ((frame_body[3] & BIT(3)) == BIT(3)) {
tid = (frame_body[3] >> 4) & 0x0F;
preorder_ctrl = &psta->recvreorder_ctrl[tid];
preorder_ctrl->enable = false;
preorder_ctrl->indicate_seq = 0xffff;
}
- DBG_88E("%s(): DELBA: %x(%x)\n", __func__, pmlmeinfo->agg_enable_bitmap, reason_code);
/* todo: how to notify the host while receiving DELETE BA */
break;
default:
@@ -3658,17 +3439,11 @@ static s32 rtw_action_public_decache(struct recv_frame *recv_frame, s32 token)
if (GetRetry(frame)) {
if (token >= 0) {
- if ((seq_ctrl == mlmeext->action_public_rxseq) && (token == mlmeext->action_public_dialog_token)) {
- DBG_88E(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x, token:%d\n",
- FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq, token);
+ if ((seq_ctrl == mlmeext->action_public_rxseq) && (token == mlmeext->action_public_dialog_token))
return _FAIL;
- }
} else {
- if (seq_ctrl == mlmeext->action_public_rxseq) {
- DBG_88E(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x\n",
- FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq);
+ if (seq_ctrl == mlmeext->action_public_rxseq)
return _FAIL;
- }
}
}
@@ -3822,20 +3597,20 @@ Following are the initialization functions for WiFi MLME
*****************************************************************************/
static struct mlme_handler mlme_sta_tbl[] = {
- {WIFI_ASSOCREQ, "OnAssocReq", &OnAssocReq},
- {WIFI_ASSOCRSP, "OnAssocRsp", &OnAssocRsp},
- {WIFI_REASSOCREQ, "OnReAssocReq", &OnAssocReq},
- {WIFI_REASSOCRSP, "OnReAssocRsp", &OnAssocRsp},
- {WIFI_PROBEREQ, "OnProbeReq", &OnProbeReq},
- {WIFI_PROBERSP, "OnProbeRsp", &OnProbeRsp},
- {0, "DoReserved", &DoReserved},
- {0, "DoReserved", &DoReserved},
- {WIFI_BEACON, "OnBeacon", &OnBeacon},
- {WIFI_ATIM, "OnATIM", &OnAtim},
- {WIFI_DISASSOC, "OnDisassoc", &OnDisassoc},
- {WIFI_AUTH, "OnAuth", &OnAuthClient},
- {WIFI_DEAUTH, "OnDeAuth", &OnDeAuth},
- {WIFI_ACTION, "OnAction", &OnAction},
+ {IEEE80211_STYPE_ASSOC_REQ, "OnAssocReq", &OnAssocReq},
+ {IEEE80211_STYPE_ASSOC_RESP, "OnAssocRsp", &OnAssocRsp},
+ {IEEE80211_STYPE_REASSOC_REQ, "OnReAssocReq", &OnAssocReq},
+ {IEEE80211_STYPE_REASSOC_RESP, "OnReAssocRsp", &OnAssocRsp},
+ {IEEE80211_STYPE_PROBE_REQ, "OnProbeReq", &OnProbeReq},
+ {IEEE80211_STYPE_PROBE_RESP, "OnProbeRsp", &OnProbeRsp},
+ {0, "DoReserved", &DoReserved},
+ {0, "DoReserved", &DoReserved},
+ {IEEE80211_STYPE_BEACON, "OnBeacon", &OnBeacon},
+ {IEEE80211_STYPE_ATIM, "OnATIM", &OnAtim},
+ {IEEE80211_STYPE_DISASSOC, "OnDisassoc", &OnDisassoc},
+ {IEEE80211_STYPE_AUTH, "OnAuth", &OnAuthClient},
+ {IEEE80211_STYPE_DEAUTH, "OnDeAuth", &OnDeAuth},
+ {IEEE80211_STYPE_ACTION, "OnAction", &OnAction},
};
int init_hw_mlme_ext(struct adapter *padapter)
@@ -3971,10 +3746,8 @@ static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan,
memset(channel_set, 0, sizeof(struct rt_channel_info) * MAX_CHANNEL_NUM);
- if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) {
- DBG_88E("ChannelPlan ID %x error !!!!!\n", ChannelPlan);
+ if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE)
return chanset_size;
- }
if (padapter->registrypriv.wireless_mode & WIRELESS_11G) {
b2_4GBand = true;
@@ -4017,8 +3790,6 @@ int init_mlme_ext_priv(struct adapter *padapter)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
- pmlmeext->padapter = padapter;
-
init_mlme_ext_priv_value(padapter);
pmlmeinfo->accept_addba_req = pregistrypriv->accept_addba_req;
@@ -4041,10 +3812,7 @@ int init_mlme_ext_priv(struct adapter *padapter)
void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext)
{
- struct adapter *padapter = pmlmeext->padapter;
-
- if (!padapter)
- return;
+ struct adapter *padapter = container_of(pmlmeext, struct adapter, mlmeextpriv);
if (padapter->bDriverStopped) {
del_timer_sync(&pmlmeext->survey_timer);
@@ -4056,13 +3824,12 @@ static void _mgt_dispatcher(struct adapter *padapter,
struct mlme_handler *ptable,
struct recv_frame *precv_frame)
{
- u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
u8 *pframe = precv_frame->pkt->data;
if (ptable->func) {
/* receive the frames that ra(a1) is my address or ra(a1) is bc address. */
if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) &&
- memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN))
+ !is_broadcast_ether_addr(GetAddr1Ptr(pframe)))
return;
ptable->func(padapter, precv_frame);
}
@@ -4075,63 +3842,48 @@ void mgt_dispatcher(struct adapter *padapter, struct recv_frame *precv_frame)
#ifdef CONFIG_88EU_AP_MODE
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
#endif
- u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
u8 *pframe = precv_frame->pkt->data;
struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(pframe));
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("+%s: type(0x%x) subtype(0x%x)\n", __func__,
- (unsigned int)GetFrameType(pframe),
- (unsigned int)GetFrameSubType(pframe)));
-
- if (GetFrameType(pframe) != WIFI_MGT_TYPE) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
- ("%s: type(0x%x) error!\n", __func__,
- (unsigned int)GetFrameType(pframe)));
+ if (GetFrameType(pframe) != WIFI_MGT_TYPE)
return;
- }
/* receive the frames that ra(a1) is my address or ra(a1) is bc address. */
if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) &&
- memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN))
+ !is_broadcast_ether_addr(GetAddr1Ptr(pframe)))
return;
ptable = mlme_sta_tbl;
index = GetFrameSubType(pframe) >> 4;
- if (index > 13) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Currently we do not support reserved sub-fr-type=%d\n", index));
+ if (index > 13)
return;
- }
ptable += index;
if (psta) {
if (GetRetry(pframe)) {
if (precv_frame->attrib.seq_num ==
- psta->RxMgmtFrameSeqNum) {
+ psta->RxMgmtFrameSeqNum)
/* drop the duplicate management frame */
- DBG_88E("Drop duplicate management frame with seq_num=%d.\n",
- precv_frame->attrib.seq_num);
return;
- }
}
psta->RxMgmtFrameSeqNum = precv_frame->attrib.seq_num;
}
#ifdef CONFIG_88EU_AP_MODE
switch (GetFrameSubType(pframe)) {
- case WIFI_AUTH:
+ case IEEE80211_STYPE_AUTH:
if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
ptable->func = &OnAuth;
else
ptable->func = &OnAuthClient;
fallthrough;
- case WIFI_ASSOCREQ:
- case WIFI_REASSOCREQ:
- case WIFI_PROBEREQ:
- case WIFI_BEACON:
- case WIFI_ACTION:
+ case IEEE80211_STYPE_ASSOC_REQ:
+ case IEEE80211_STYPE_REASSOC_REQ:
+ case IEEE80211_STYPE_PROBE_REQ:
+ case IEEE80211_STYPE_BEACON:
+ case IEEE80211_STYPE_ACTION:
_mgt_dispatcher(padapter, ptable, precv_frame);
break;
default:
@@ -4244,8 +3996,6 @@ void report_surveydone_event(struct adapter *padapter)
psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt;
- DBG_88E("survey done event(%x)\n", psurveydone_evt->bss_cnt);
-
rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
}
@@ -4290,8 +4040,6 @@ void report_join_res(struct adapter *padapter, int res)
pjoinbss_evt->network.join_res = res;
pjoinbss_evt->network.aid = res;
- DBG_88E("%s(%d)\n", __func__, res);
-
rtw_joinbss_event_prehandle(padapter, (u8 *)&pjoinbss_evt->network);
rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
@@ -4347,8 +4095,6 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr,
pdel_sta_evt->mac_id = mac_id;
- DBG_88E("%s: delete STA, mac_id =%d\n", __func__, mac_id);
-
rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
}
@@ -4392,8 +4138,6 @@ void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr,
ether_addr_copy((unsigned char *)(&padd_sta_evt->macaddr), MacAddr);
padd_sta_evt->cam_id = cam_idx;
- DBG_88E("%s: add STA\n", __func__);
-
rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
}
@@ -4462,7 +4206,7 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res)
/* restore to initial setting. */
update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode);
- goto exit_mlmeext_joinbss_event_callback;
+ return;
}
if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) {
@@ -4518,10 +4262,6 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res)
correct_TSF(padapter, pmlmeext);
}
rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_CONNECT, 0);
-
-exit_mlmeext_joinbss_event_callback:
-
- DBG_88E("=>%s\n", __func__);
}
void mlmeext_sta_add_event_callback(struct adapter *padapter, struct sta_info *psta)
@@ -4530,8 +4270,6 @@ void mlmeext_sta_add_event_callback(struct adapter *padapter, struct sta_info *p
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
u8 join_type;
- DBG_88E("%s\n", __func__);
-
if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) {
if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {/* adhoc master or sta_count>1 */
/* nothing to do */
@@ -4683,8 +4421,6 @@ void linked_status_chk(struct adapter *padapter)
if (rx_chk == _FAIL) {
pmlmeext->retry++;
if (pmlmeext->retry > rx_chk_limit) {
- DBG_88E_LEVEL(_drv_always_, FUNC_ADPT_FMT" disconnect or roaming\n",
- FUNC_ADPT_ARG(padapter));
receive_disconnect(padapter, pmlmeinfo->network.MacAddress,
WLAN_REASON_EXPIRATION_CHK);
return;
@@ -4744,8 +4480,6 @@ void survey_timer_hdl(struct timer_list *t)
if (pmlmeext->scan_abort) {
pmlmeext->sitesurvey_res.channel_idx = pmlmeext->sitesurvey_res.ch_num;
- DBG_88E("%s idx:%d\n", __func__
- , pmlmeext->sitesurvey_res.channel_idx);
pmlmeext->scan_abort = false;/* reset */
}
@@ -4776,7 +4510,6 @@ void link_timer_hdl(struct timer_list *t)
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) {
- DBG_88E("%s:no beacon while connecting\n", __func__);
pmlmeinfo->state = WIFI_FW_NULL_STATE;
report_join_res(padapter, -3);
} else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) {
@@ -4787,7 +4520,6 @@ void link_timer_hdl(struct timer_list *t)
return;
}
- DBG_88E("%s: auth timeout and try again\n", __func__);
pmlmeinfo->auth_seq = 1;
issue_auth(padapter, NULL, 0);
set_link_timer(pmlmeext, REAUTH_TO);
@@ -4799,7 +4531,6 @@ void link_timer_hdl(struct timer_list *t)
return;
}
- DBG_88E("%s: assoc timeout and try again\n", __func__);
issue_assocreq(padapter);
set_link_timer(pmlmeext, REASSOC_TO);
}
@@ -4991,9 +4722,8 @@ u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf)
default:
pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
break;
- }
+ }
- DBG_88E("set ch/bw before connected\n");
}
}
break;
@@ -5204,8 +4934,6 @@ u8 setkey_hdl(struct adapter *padapter, u8 *pbuf)
/* write cam */
ctrl = BIT(15) | ((pparm->algorithm) << 2) | pparm->keyid;
- DBG_88E_LEVEL(_drv_info_, "set group key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) "
- "keyid:%d\n", pparm->algorithm, pparm->keyid);
write_cam(padapter, pparm->keyid, ctrl, null_sta, pparm->key);
return H2C_SUCCESS;
@@ -5234,8 +4962,6 @@ u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf)
cam_id = 4;
- DBG_88E_LEVEL(_drv_info_, "set pairwise key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) camid:%d\n",
- pparm->algorithm, cam_id);
if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) {
struct sta_info *psta;
struct sta_priv *pstapriv = &padapter->stapriv;
@@ -5249,24 +4975,16 @@ u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf)
if (psta) {
ctrl = BIT(15) | ((pparm->algorithm) << 2);
- DBG_88E("r871x_set_stakey_hdl(): enc_algorithm=%d\n", pparm->algorithm);
-
- if ((psta->mac_id < 1) || (psta->mac_id > (NUM_STA - 4))) {
- DBG_88E("r871x_set_stakey_hdl():set_stakey failed, mac_id(aid)=%d\n", psta->mac_id);
+ if ((psta->mac_id < 1) || (psta->mac_id > (NUM_STA - 4)))
return H2C_REJECTED;
- }
cam_id = psta->mac_id + 3;/* 0~3 for default key, cmd_id = macid + 3, macid = aid+1; */
- DBG_88E("Write CAM, mac_addr =%pM, cam_entry=%d\n",
- pparm->addr, cam_id);
-
write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key);
return H2C_SUCCESS_RSP;
}
- DBG_88E("r871x_set_stakey_hdl(): sta has been free\n");
return H2C_REJECTED;
}
@@ -5294,7 +5012,7 @@ u8 add_ba_hdl(struct adapter *padapter, unsigned char *pbuf)
if (((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && (pmlmeinfo->HT_enable)) ||
((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) {
- issue_action_BA(padapter, pparm->addr, RTW_WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid);
+ issue_action_BA(padapter, pparm->addr, WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid);
mod_timer(&psta->addba_retry_timer,
jiffies + msecs_to_jiffies(ADDBA_TO));
} else {
@@ -5352,19 +5070,13 @@ u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf)
evt_code = (u8)((*peventbuf >> 16) & 0xff);
/* checking if event code is valid */
- if (evt_code >= MAX_C2HEVT) {
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nEvent Code(%d) mismatch!\n", evt_code));
+ if (evt_code >= MAX_C2HEVT)
goto _abort_event_;
- }
/* checking if event size match the event parm size */
if ((wlanevents[evt_code].parmsize != 0) &&
- (wlanevents[evt_code].parmsize != evt_sz)) {
- RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
- ("\nEvent(%d) Parm Size mismatch (%d vs %d)!\n",
- evt_code, wlanevents[evt_code].parmsize, evt_sz));
+ (wlanevents[evt_code].parmsize != evt_sz))
goto _abort_event_;
- }
peventbuf += 2;
@@ -5379,15 +5091,13 @@ _abort_event_:
u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf)
{
- if (send_beacon(padapter) == _FAIL) {
- DBG_88E("issue_beacon, fail!\n");
+ if (send_beacon(padapter) == _FAIL)
return H2C_PARAMETERS_ERROR;
- }
#ifdef CONFIG_88EU_AP_MODE
else { /* tx bc/mc frames after update TIM */
struct sta_info *psta_bmc;
- struct list_head *xmitframe_plist, *xmitframe_phead;
- struct xmit_frame *pxmitframe = NULL;
+ struct list_head *xmitframe_phead;
+ struct xmit_frame *pxmitframe, *n;
struct sta_priv *pstapriv = &padapter->stapriv;
/* for BC/MC Frames */
@@ -5400,13 +5110,8 @@ u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf)
spin_lock_bh(&psta_bmc->sleep_q.lock);
xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
- xmitframe_plist = xmitframe_phead->next;
-
- while (xmitframe_phead != xmitframe_plist) {
- pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
-
- xmitframe_plist = xmitframe_plist->next;
-
+ list_for_each_entry_safe(pxmitframe, n, xmitframe_phead,
+ list) {
list_del_init(&pxmitframe->list);
psta_bmc->sleepq_len--;
@@ -5441,10 +5146,6 @@ u8 set_ch_hdl(struct adapter *padapter, u8 *pbuf)
set_ch_parm = (struct set_ch_parm *)pbuf;
- DBG_88E(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n",
- FUNC_NDEV_ARG(padapter->pnetdev),
- set_ch_parm->ch, set_ch_parm->bw, set_ch_parm->ch_offset);
-
pmlmeext->cur_channel = set_ch_parm->ch;
pmlmeext->cur_ch_offset = set_ch_parm->ch_offset;
pmlmeext->cur_bwmode = set_ch_parm->bw;
diff --git a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
index 4d507d9faec2..cbb34b920ab9 100644
--- a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
+++ b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
@@ -18,17 +18,12 @@ static int rtw_hw_suspend(struct adapter *padapter)
struct net_device *pnetdev = padapter->pnetdev;
if ((!padapter->bup) || (padapter->bDriverStopped) ||
- (padapter->bSurpriseRemoved)) {
- DBG_88E("padapter->bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n",
- padapter->bup, padapter->bDriverStopped,
- padapter->bSurpriseRemoved);
+ (padapter->bSurpriseRemoved))
goto error_exit;
- }
/* system suspend */
LeaveAllPowerSaveMode(padapter);
- DBG_88E("==> %s\n", __func__);
mutex_lock(&pwrpriv->mutex_lock);
pwrpriv->bips_processing = true;
/* s1. */
@@ -69,7 +64,6 @@ static int rtw_hw_suspend(struct adapter *padapter)
return 0;
error_exit:
- DBG_88E("%s, failed\n", __func__);
return -1;
}
@@ -79,7 +73,6 @@ static int rtw_hw_resume(struct adapter *padapter)
struct net_device *pnetdev = padapter->pnetdev;
/* system resume */
- DBG_88E("==> %s\n", __func__);
mutex_lock(&pwrpriv->mutex_lock);
pwrpriv->bips_processing = true;
rtw_reset_drv_sw(padapter);
@@ -107,7 +100,6 @@ static int rtw_hw_resume(struct adapter *padapter)
return 0;
error_exit:
- DBG_88E("%s, Open net dev failed\n", __func__);
return -1;
}
@@ -120,12 +112,8 @@ void ips_enter(struct adapter *padapter)
return;
if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF ||
- pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) {
- DBG_88E_LEVEL(_drv_info_, "There are some pkts to transmit\n");
- DBG_88E_LEVEL(_drv_info_, "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n",
- pxmit_priv->free_xmitbuf_cnt, pxmit_priv->free_xmit_extbuf_cnt);
+ pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF)
return;
- }
mutex_lock(&pwrpriv->mutex_lock);
@@ -135,10 +123,8 @@ void ips_enter(struct adapter *padapter)
pwrpriv->ips_mode = pwrpriv->ips_mode_req;
pwrpriv->ips_enter_cnts++;
- DBG_88E("==>%s:%d\n", __func__, pwrpriv->ips_enter_cnts);
if (rf_off == pwrpriv->change_rfpwrstate) {
pwrpriv->bpower_saving = true;
- DBG_88E_LEVEL(_drv_info_, "nolinked power save enter\n");
if (pwrpriv->ips_mode == IPS_LEVEL_2)
pwrpriv->bkeepfwalive = true;
@@ -165,16 +151,12 @@ int ips_leave(struct adapter *padapter)
pwrpriv->bips_processing = true;
pwrpriv->change_rfpwrstate = rf_on;
pwrpriv->ips_leave_cnts++;
- DBG_88E("==>%s:%d\n", __func__, pwrpriv->ips_leave_cnts);
result = rtw_ips_pwr_up(padapter);
if (result == _SUCCESS)
pwrpriv->rf_pwrstate = rf_on;
- DBG_88E_LEVEL(_drv_info_, "nolinked power save leave\n");
-
if ((psecuritypriv->dot11PrivacyAlgrthm == _WEP40_) || (psecuritypriv->dot11PrivacyAlgrthm == _WEP104_)) {
- DBG_88E("==>%s, channel(%d), processing(%x)\n", __func__, padapter->mlmeextpriv.cur_channel, pwrpriv->bips_processing);
set_channel_bwmode(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
for (keyid = 0; keyid < 4; keyid++) {
if (pmlmepriv->key_mask & BIT(keyid)) {
@@ -186,7 +168,6 @@ int ips_leave(struct adapter *padapter)
}
}
- DBG_88E("==> %s.....LED(0x%08x)...\n", __func__, usb_read32(padapter, 0x4c));
pwrpriv->bips_processing = false;
pwrpriv->bkeepfwalive = false;
@@ -217,7 +198,6 @@ static bool rtw_pwr_unassociated_idle(struct adapter *adapter)
void rtw_ps_processor(struct adapter *padapter)
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
- struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
enum rt_rf_power_state rfpwrstate;
pwrpriv->ps_processing = true;
@@ -227,7 +207,6 @@ void rtw_ps_processor(struct adapter *padapter)
if (padapter->pwrctrlpriv.bHWPwrPindetect) {
rfpwrstate = RfOnOffDetect(padapter);
- DBG_88E("@@@@- #2 %s==> rfstate:%s\n", __func__, (rfpwrstate == rf_on) ? "rf_on" : "rf_off");
if (rfpwrstate != pwrpriv->rf_pwrstate) {
if (rfpwrstate == rf_off) {
@@ -238,7 +217,6 @@ void rtw_ps_processor(struct adapter *padapter)
pwrpriv->change_rfpwrstate = rf_on;
rtw_hw_resume(padapter);
}
- DBG_88E("current rf_pwrstate(%s)\n", (pwrpriv->rf_pwrstate == rf_off) ? "rf_off" : "rf_on");
}
pwrpriv->pwr_state_check_cnts++;
}
@@ -250,7 +228,6 @@ void rtw_ps_processor(struct adapter *padapter)
goto exit;
if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts % 4) == 0)) {
- DBG_88E("==>%s .fw_state(%x)\n", __func__, get_fwstate(pmlmepriv));
pwrpriv->change_rfpwrstate = rf_off;
ips_enter(padapter);
@@ -288,37 +265,22 @@ void rtw_set_rpwm(struct adapter *padapter, u8 pslv)
pslv = PS_STATE_S3;
}
- if (pwrpriv->rpwm == pslv) {
- RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
- ("%s: Already set rpwm[0x%02X], new=0x%02X!\n", __func__, pwrpriv->rpwm, pslv));
+ if (pwrpriv->rpwm == pslv)
return;
- }
if ((padapter->bSurpriseRemoved) ||
(!padapter->hw_init_completed)) {
- RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
- ("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n",
- __func__, padapter->bSurpriseRemoved, padapter->hw_init_completed));
-
pwrpriv->cpwm = PS_STATE_S4;
return;
}
if (padapter->bDriverStopped) {
- RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
- ("%s: change power state(0x%02X) when DriverStopped\n", __func__, pslv));
-
- if (pslv < PS_STATE_S2) {
- RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
- ("%s: Reject to enter PS_STATE(0x%02X) lower than S2 when DriverStopped!!\n", __func__, pslv));
+ if (pslv < PS_STATE_S2)
return;
- }
}
rpwm = pslv | pwrpriv->tog;
- RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
- ("%s: rpwm=0x%02x cpwm=0x%02x\n", __func__, rpwm, pwrpriv->cpwm));
pwrpriv->rpwm = pslv;
@@ -349,10 +311,8 @@ static u8 PS_RDY_CHECK(struct adapter *padapter)
if (pwrpriv->bInSuspend)
return false;
if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X &&
- !padapter->securitypriv.binstallGrpkey) {
- DBG_88E("Group handshake still in progress !!!\n");
+ !padapter->securitypriv.binstallGrpkey)
return false;
- }
return true;
}
@@ -360,14 +320,8 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
- RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
- ("%s: PowerMode=%d Smart_PS=%d\n",
- __func__, ps_mode, smart_ps));
-
- if (ps_mode > PM_Card_Disable) {
- RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ("ps_mode:%d error\n", ps_mode));
+ if (ps_mode > PM_Card_Disable)
return;
- }
if (pwrpriv->pwr_mode == ps_mode) {
if (ps_mode == PS_MODE_ACTIVE)
@@ -381,7 +335,6 @@ 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 (PS_RDY_CHECK(padapter)) {
- DBG_88E("%s: Enter 802.11 power save\n", __func__);
pwrpriv->bFwCurrentInPSMode = true;
pwrpriv->pwr_mode = ps_mode;
pwrpriv->smart_ps = smart_ps;
@@ -412,13 +365,11 @@ s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms)
if (padapter->bSurpriseRemoved) {
err = -2;
- DBG_88E("%s: device surprise removed!!\n", __func__);
break;
}
if (jiffies_to_msecs(jiffies - start_time) > delay_ms) {
err = -1;
- DBG_88E("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms);
break;
}
msleep(1);
@@ -443,7 +394,6 @@ void LPS_Enter(struct adapter *padapter)
if (pwrpriv->LpsIdleCount >= 2) { /* 4 Sec */
if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) {
pwrpriv->bpower_saving = true;
- DBG_88E("%s smart_ps:%d\n", __func__, pwrpriv->smart_ps);
/* For Tenda W311R IOT issue */
rtw_set_ps_mode(padapter, pwrpriv->power_mgnt, pwrpriv->smart_ps, 0);
}
@@ -549,14 +499,9 @@ int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *cal
start = jiffies;
if (pwrpriv->ps_processing) {
- DBG_88E("%s wait ps_processing...\n", __func__);
while (pwrpriv->ps_processing &&
jiffies_to_msecs(jiffies - start) <= 3000)
udelay(1500);
- if (pwrpriv->ps_processing)
- DBG_88E("%s wait ps_processing timeout\n", __func__);
- else
- DBG_88E("%s wait ps_processing done\n", __func__);
}
/* System suspend is not allowed to wakeup */
@@ -577,9 +522,7 @@ int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *cal
goto exit;
}
if (rf_off == pwrpriv->rf_pwrstate) {
- DBG_88E("%s call ips_leave....\n", __func__);
if (ips_leave(padapter) == _FAIL) {
- DBG_88E("======> ips_leave fail.............\n");
ret = _FAIL;
goto exit;
}
@@ -588,11 +531,6 @@ int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *cal
/* TODO: the following checking need to be merged... */
if (padapter->bDriverStopped || !padapter->bup ||
!padapter->hw_init_completed) {
- DBG_88E("%s: bDriverStopped=%d, bup=%d, hw_init_completed =%u\n"
- , caller
- , padapter->bDriverStopped
- , padapter->bup
- , padapter->hw_init_completed);
ret = false;
goto exit;
}
@@ -631,11 +569,9 @@ int rtw_pm_set_ips(struct adapter *padapter, u8 mode)
if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) {
rtw_ips_mode_req(pwrctrlpriv, mode);
- DBG_88E("%s %s\n", __func__, mode == IPS_NORMAL ? "IPS_NORMAL" : "IPS_LEVEL_2");
return 0;
} else if (mode == IPS_NONE) {
rtw_ips_mode_req(pwrctrlpriv, mode);
- DBG_88E("%s %s\n", __func__, "IPS_NONE");
if ((padapter->bSurpriseRemoved == 0) && (rtw_pwr_wakeup(padapter) == _FAIL))
return -EFAULT;
} else {
diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c
index b2fe448d999d..ff2ef36604e1 100644
--- a/drivers/staging/rtl8188eu/core/rtw_recv.c
+++ b/drivers/staging/rtl8188eu/core/rtw_recv.c
@@ -7,6 +7,7 @@
#define _RTW_RECV_C_
#include <linux/ieee80211.h>
+#include <linux/if_ether.h>
#include <osdep_service.h>
#include <drv_types.h>
@@ -15,9 +16,9 @@
#include <mon.h>
#include <wifi.h>
#include <linux/vmalloc.h>
+#include <linux/etherdevice.h>
#include <net/cfg80211.h>
-#define ETHERNET_HEADER_SIZE 14 /* Ethernet Header Length */
#define LLC_HEADER_SIZE 6 /* LLC Header Length */
static u8 SNAP_ETH_TYPE_IPX[2] = {0x81, 0x37};
@@ -114,11 +115,11 @@ struct recv_frame *rtw_alloc_recvframe(struct __queue *pfree_recv_queue)
return precvframe;
}
-int rtw_free_recvframe(struct recv_frame *precvframe,
- struct __queue *pfree_recv_queue)
+void rtw_free_recvframe(struct recv_frame *precvframe, struct __queue *pfree_recv_queue)
{
if (!precvframe)
- return _FAIL;
+ return;
+
if (precvframe->pkt) {
dev_kfree_skb_any(precvframe->pkt);/* free skb by driver */
precvframe->pkt = NULL;
@@ -131,8 +132,6 @@ int rtw_free_recvframe(struct recv_frame *precvframe,
list_add_tail(&precvframe->list, get_list_head(pfree_recv_queue));
spin_unlock_bh(&pfree_recv_queue->lock);
-
- return _SUCCESS;
}
int _rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue)
@@ -190,7 +189,6 @@ u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter)
while ((pending_frame = rtw_alloc_recvframe(&adapter->recvpriv.uc_swdec_pending_queue))) {
rtw_free_recvframe(pending_frame, &adapter->recvpriv.free_recv_queue);
- DBG_88E("%s: dequeue uc_swdec_pending_queue\n", __func__);
cnt++;
}
@@ -216,31 +214,16 @@ static int recvframe_chkmic(struct adapter *adapter,
stainfo = rtw_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]);
if (prxattrib->encrypt == _TKIP_) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- ("\n %s: prxattrib->encrypt==_TKIP_\n", __func__));
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- ("\n %s: da=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
- __func__, prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2],
- prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5]));
-
/* calculate mic code */
if (stainfo) {
if (is_multicast_ether_addr(prxattrib->ra)) {
if (!psecuritypriv) {
res = _FAIL;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("\n %s: didn't install group key!!!!!!!!!!\n", __func__));
- DBG_88E("\n %s: didn't install group key!!!!!!!!!!\n", __func__);
goto exit;
}
mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0];
-
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- ("\n %s: bcmc key\n", __func__));
} else {
mickey = &stainfo->dot11tkiprxmickey.skey[0];
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("\n %s: unicast key\n", __func__));
}
/* icv_len included the mic code */
@@ -249,7 +232,6 @@ static int recvframe_chkmic(struct adapter *adapter,
pframe = precvframe->pkt->data;
payload = pframe + prxattrib->hdrlen + prxattrib->iv_len;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n prxattrib->iv_len=%d prxattrib->icv_len=%d\n", prxattrib->iv_len, prxattrib->icv_len));
rtw_seccalctkipmic(mickey, pframe, payload, datalen, &miccode[0],
(unsigned char)prxattrib->priority); /* care the length of the data */
@@ -258,83 +240,25 @@ static int recvframe_chkmic(struct adapter *adapter,
bmic_err = false;
for (i = 0; i < 8; i++) {
- if (miccode[i] != *(pframemic + i)) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("%s: miccode[%d](%02x)!=*(pframemic+%d)(%02x) ",
- __func__, i, miccode[i], i, *(pframemic + i)));
+ if (miccode[i] != *(pframemic + i))
bmic_err = true;
- }
}
if (bmic_err) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("\n *(pframemic-8)-*(pframemic-1)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
- *(pframemic - 8), *(pframemic - 7), *(pframemic - 6),
- *(pframemic - 5), *(pframemic - 4), *(pframemic - 3),
- *(pframemic - 2), *(pframemic - 1)));
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("\n *(pframemic-16)-*(pframemic-9)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
- *(pframemic - 16), *(pframemic - 15), *(pframemic - 14),
- *(pframemic - 13), *(pframemic - 12), *(pframemic - 11),
- *(pframemic - 10), *(pframemic - 9)));
- {
- uint i;
-
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("\n ======demp packet (len=%d)======\n",
- precvframe->pkt->len));
- for (i = 0; i < precvframe->pkt->len; i += 8) {
- RT_TRACE(_module_rtl871x_recv_c_,
- _drv_err_,
- ("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x",
- *(precvframe->pkt->data + i),
- *(precvframe->pkt->data + i + 1),
- *(precvframe->pkt->data + i + 2),
- *(precvframe->pkt->data + i + 3),
- *(precvframe->pkt->data + i + 4),
- *(precvframe->pkt->data + i + 5),
- *(precvframe->pkt->data + i + 6),
- *(precvframe->pkt->data + i + 7)));
- }
- RT_TRACE(_module_rtl871x_recv_c_,
- _drv_err_,
- ("\n ====== demp packet end [len=%d]======\n",
- precvframe->pkt->len));
- RT_TRACE(_module_rtl871x_recv_c_,
- _drv_err_,
- ("\n hrdlen=%d,\n",
- prxattrib->hdrlen));
- }
-
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("ra=0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x psecuritypriv->binstallGrpkey=%d ",
- prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2],
- prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5], psecuritypriv->binstallGrpkey));
-
/* double check key_index for some timing issue , */
/* cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue */
if (is_multicast_ether_addr(prxattrib->ra) && prxattrib->key_index != pmlmeinfo->key_index)
brpt_micerror = false;
- if ((prxattrib->bdecrypted) && (brpt_micerror)) {
+ if ((prxattrib->bdecrypted) && (brpt_micerror))
rtw_handle_tkip_mic_err(adapter, (u8)is_multicast_ether_addr(prxattrib->ra));
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted));
- DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted);
- } else {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted));
- DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted);
- }
res = _FAIL;
} else {
/* mic checked ok */
- if (!psecuritypriv->bcheck_grpkey && is_multicast_ether_addr(prxattrib->ra)) {
+ if (!psecuritypriv->bcheck_grpkey &&
+ is_multicast_ether_addr(prxattrib->ra))
psecuritypriv->bcheck_grpkey = true;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("psecuritypriv->bcheck_grpkey = true"));
- }
}
- } else {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("%s: rtw_get_stainfo==NULL!!!\n", __func__));
}
skb_trim(precvframe->pkt, precvframe->pkt->len - 8);
@@ -354,16 +278,12 @@ static struct recv_frame *decryptor(struct adapter *padapter,
struct recv_frame *return_packet = precv_frame;
u32 res = _SUCCESS;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("prxstat->decrypted=%x prxattrib->encrypt=0x%03x\n", prxattrib->bdecrypted, prxattrib->encrypt));
-
if (prxattrib->encrypt > 0) {
u8 *iv = precv_frame->pkt->data + prxattrib->hdrlen;
prxattrib->key_index = (((iv[3]) >> 6) & 0x3);
if (prxattrib->key_index > WEP_KEYS) {
- DBG_88E("prxattrib->key_index(%d)>WEP_KEYS\n", prxattrib->key_index);
-
switch (prxattrib->encrypt) {
case _WEP40_:
case _WEP104_:
@@ -434,8 +354,6 @@ static struct recv_frame *portctrl(struct adapter *adapter,
prtnframe = NULL;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########%s:adapter->securitypriv.dot11AuthAlgrthm=%d\n", __func__, adapter->securitypriv.dot11AuthAlgrthm));
-
if (auth_alg == 2) {
/* get ether_type */
ptr = ptr + pfhdr->attrib.hdrlen + LLC_HEADER_SIZE + pfhdr->attrib.iv_len;
@@ -445,8 +363,6 @@ static struct recv_frame *portctrl(struct adapter *adapter,
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__));
-
if (ether_type == eapol_type) {
prtnframe = precv_frame;
} else {
@@ -457,24 +373,11 @@ static struct recv_frame *portctrl(struct adapter *adapter,
} else {
/* allowed */
/* check decryption status, and decrypt the frame if needed */
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########%s:psta->ieee8021x_blocked==0\n", __func__));
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- ("%s:precv_frame->hdr.attrib.privacy=%x\n",
- __func__, precv_frame->attrib.privacy));
-
- if (pattrib->bdecrypted == 0)
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("%s:prxstat->decrypted=%x\n", __func__, pattrib->bdecrypted));
-
prtnframe = precv_frame;
/* check is the EAPOL frame or not (Rekey) */
- if (ether_type == eapol_type) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("########%s:ether_type==0x888e\n", __func__));
+ if (ether_type == eapol_type)
/* check Rekey */
-
prtnframe = precv_frame;
- } else {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########%s:ether_type=0x%04x\n", __func__, ether_type));
- }
}
} else {
prtnframe = precv_frame;
@@ -491,19 +394,11 @@ static int recv_decache(struct recv_frame *precv_frame, u8 bretry,
u16 seq_ctrl = ((precv_frame->attrib.seq_num & 0xffff) << 4) |
(precv_frame->attrib.frag_num & 0xf);
- if (tid > 15) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s, (tid>15)! seq_ctrl=0x%x, tid=0x%x\n", __func__, seq_ctrl, tid));
-
+ if (tid > 15)
return _FAIL;
- }
- if (1) {/* if (bretry) */
- if (seq_ctrl == prxcache->tid_rxseq[tid]) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s, seq_ctrl=0x%x, tid=0x%x, tid_rxseq=0x%x\n", __func__, seq_ctrl, tid, prxcache->tid_rxseq[tid]));
-
- return _FAIL;
- }
- }
+ if (seq_ctrl == prxcache->tid_rxseq[tid])
+ return _FAIL;
prxcache->tid_rxseq[tid] = seq_ctrl;
@@ -641,7 +536,6 @@ static int sta2sta_data_frame(struct adapter *adapter,
check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
/* filter packets that SA is myself or multicast or broadcast */
if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA==myself\n"));
ret = _FAIL;
goto exit;
}
@@ -651,8 +545,8 @@ static int sta2sta_data_frame(struct adapter *adapter,
goto exit;
}
- if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
- !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+ if (is_zero_ether_addr(pattrib->bssid) ||
+ is_zero_ether_addr(mybssid) ||
memcmp(pattrib->bssid, mybssid, ETH_ALEN)) {
ret = _FAIL;
goto exit;
@@ -662,7 +556,6 @@ static int sta2sta_data_frame(struct adapter *adapter,
} else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
/* For Station mode, sa and bssid should always be BSSID, and DA is my mac-address */
if (memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("bssid!=TA under STATION_MODE; drop pkt\n"));
ret = _FAIL;
goto exit;
}
@@ -693,7 +586,6 @@ static int sta2sta_data_frame(struct adapter *adapter,
*psta = rtw_get_stainfo(pstapriv, sta_addr); /* get ap_info */
if (!*psta) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under %s ; drop pkt\n", __func__));
ret = _FAIL;
goto exit;
}
@@ -720,31 +612,22 @@ static int ap2sta_data_frame(struct adapter *adapter,
check_fwstate(pmlmepriv, _FW_UNDER_LINKING))) {
/* filter packets that SA is myself or multicast or broadcast */
if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA==myself\n"));
ret = _FAIL;
goto exit;
}
/* da should be for me */
if (memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && !mcast) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- (" %s: compare DA fail; DA=%pM\n", __func__, (pattrib->dst)));
ret = _FAIL;
goto exit;
}
/* check BSSID */
- if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
- !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
- (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- (" %s: compare BSSID fail ; BSSID=%pM\n", __func__, (pattrib->bssid)));
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("mybssid=%pM\n", (mybssid)));
-
- if (!mcast) {
- DBG_88E("issue_deauth to the nonassociated ap=%pM for the reason(7)\n", (pattrib->bssid));
+ if (is_zero_ether_addr(pattrib->bssid) ||
+ is_zero_ether_addr(mybssid) ||
+ (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) {
+ if (!mcast)
issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
- }
ret = _FAIL;
goto exit;
@@ -756,7 +639,6 @@ static int ap2sta_data_frame(struct adapter *adapter,
*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get ap_info */
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;
}
@@ -777,11 +659,8 @@ static int ap2sta_data_frame(struct adapter *adapter,
} else {
if (!memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && !mcast) {
*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */
- if (!*psta) {
- DBG_88E("issue_deauth to the ap =%pM for the reason(7)\n", (pattrib->bssid));
-
+ if (!*psta)
issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
- }
}
ret = _FAIL;
@@ -812,9 +691,6 @@ static int sta2ap_data_frame(struct adapter *adapter,
*psta = rtw_get_stainfo(pstapriv, pattrib->src);
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));
-
issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
ret = RTW_RX_HANDLED;
@@ -839,7 +715,6 @@ static int sta2ap_data_frame(struct adapter *adapter,
ret = RTW_RX_HANDLED;
goto exit;
}
- DBG_88E("issue_deauth to sta=%pM for the reason(7)\n", (pattrib->src));
issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
ret = RTW_RX_HANDLED;
goto exit;
@@ -866,7 +741,7 @@ static int validate_recv_ctrl_frame(struct adapter *padapter,
return _FAIL;
/* only handle ps-poll */
- if (GetFrameSubType(pframe) == WIFI_PSPOLL) {
+ if (GetFrameSubType(pframe) == (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL)) {
u16 aid;
u8 wmmps_ac = 0;
struct sta_info *psta = NULL;
@@ -904,7 +779,6 @@ static int validate_recv_ctrl_frame(struct adapter *padapter,
return _FAIL;
if (psta->state & WIFI_STA_ALIVE_CHK_STATE) {
- DBG_88E("%s alive check-rx ps-poll\n", __func__);
psta->expire_to = pstapriv->expire_to;
psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
}
@@ -948,15 +822,11 @@ static int validate_recv_ctrl_frame(struct adapter *padapter,
}
} else {
if (pstapriv->tim_bitmap & BIT(psta->aid)) {
- if (psta->sleepq_len == 0) {
- DBG_88E("no buffered packets to xmit\n");
-
+ if (psta->sleepq_len == 0)
/* issue nulldata with More data bit = 0 to indicate we have no buffered packets */
issue_nulldata(padapter, psta->hwaddr, 0, 0, 0);
- } else {
- DBG_88E("error!psta->sleepq_len=%d\n", psta->sleepq_len);
+ else
psta->sleepq_len = 0;
- }
pstapriv->tim_bitmap &= ~BIT(psta->aid);
@@ -983,25 +853,20 @@ static int validate_recv_mgnt_frame(struct adapter *padapter,
{
struct sta_info *psta;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+%s\n", __func__));
-
precv_frame = recvframe_chk_defrag(padapter, precv_frame);
- if (!precv_frame) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
- ("%s: fragment packet\n", __func__));
+ if (!precv_frame)
return _SUCCESS;
- }
/* for rx pkt statistics */
psta = rtw_get_stainfo(&padapter->stapriv,
GetAddr2Ptr(precv_frame->pkt->data));
if (psta) {
psta->sta_stats.rx_mgnt_pkts++;
- if (GetFrameSubType(precv_frame->pkt->data) == WIFI_BEACON) {
+ if (GetFrameSubType(precv_frame->pkt->data) == IEEE80211_STYPE_BEACON) {
psta->sta_stats.rx_beacon_pkts++;
- } else if (GetFrameSubType(precv_frame->pkt->data) == WIFI_PROBEREQ) {
+ } else if (GetFrameSubType(precv_frame->pkt->data) == IEEE80211_STYPE_PROBE_REQ) {
psta->sta_stats.rx_probereq_pkts++;
- } else if (GetFrameSubType(precv_frame->pkt->data) == WIFI_PROBERSP) {
+ } else if (GetFrameSubType(precv_frame->pkt->data) == IEEE80211_STYPE_PROBE_RESP) {
if (!memcmp(padapter->eeprompriv.mac_addr,
GetAddr1Ptr(precv_frame->pkt->data), ETH_ALEN))
psta->sta_stats.rx_probersp_pkts++;
@@ -1063,7 +928,6 @@ static int validate_recv_data_frame(struct adapter *adapter,
memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN);
memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN);
ret = _FAIL;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" case 3\n"));
break;
default:
ret = _FAIL;
@@ -1076,7 +940,6 @@ static int validate_recv_data_frame(struct adapter *adapter,
goto exit;
if (!psta) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" after to_fr_ds_chk; psta==NULL\n"));
ret = _FAIL;
goto exit;
}
@@ -1108,19 +971,12 @@ static int validate_recv_data_frame(struct adapter *adapter,
/* decache, drop duplicate recv packets */
if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) == _FAIL) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decache : drop pkt\n"));
ret = _FAIL;
goto exit;
}
if (pattrib->privacy) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("%s:pattrib->privacy=%x\n", __func__, pattrib->privacy));
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n ^^^^^^^^^^^is_multicast_ether_addr(pattrib->ra(0x%02x))=%d^^^^^^^^^^^^^^^6\n", pattrib->ra[0], is_multicast_ether_addr(pattrib->ra)));
-
GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, is_multicast_ether_addr(pattrib->ra));
-
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n pattrib->encrypt=%d\n", pattrib->encrypt));
-
SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt);
} else {
pattrib->encrypt = 0;
@@ -1158,7 +1014,6 @@ static int validate_recv_frame(struct adapter *adapter,
/* add version chk */
if (ver != 0) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail! (ver!=0)\n"));
retval = _FAIL;
goto exit;
}
@@ -1177,41 +1032,14 @@ static int validate_recv_frame(struct adapter *adapter,
pattrib->privacy = GetPrivacy(ptr);
pattrib->order = GetOrder(ptr);
- /* Dump rx packets */
rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt));
- if (bDumpRxPkt == 1) {/* dump all rx packets */
- if (_drv_err_ <= GlobalDebugLevel) {
- pr_info(DRIVER_PREFIX "#############################\n");
- print_hex_dump(KERN_INFO, DRIVER_PREFIX, DUMP_PREFIX_NONE,
- 16, 1, ptr, 64, false);
- pr_info(DRIVER_PREFIX "#############################\n");
- }
- } else if (bDumpRxPkt == 2) {
- if ((_drv_err_ <= GlobalDebugLevel) && (type == WIFI_MGT_TYPE)) {
- pr_info(DRIVER_PREFIX "#############################\n");
- print_hex_dump(KERN_INFO, DRIVER_PREFIX, DUMP_PREFIX_NONE,
- 16, 1, ptr, 64, false);
- pr_info(DRIVER_PREFIX "#############################\n");
- }
- } else if (bDumpRxPkt == 3) {
- if ((_drv_err_ <= GlobalDebugLevel) && (type == WIFI_DATA_TYPE)) {
- pr_info(DRIVER_PREFIX "#############################\n");
- print_hex_dump(KERN_INFO, DRIVER_PREFIX, DUMP_PREFIX_NONE,
- 16, 1, ptr, 64, false);
- pr_info(DRIVER_PREFIX "#############################\n");
- }
- }
switch (type) {
case WIFI_MGT_TYPE: /* mgnt */
retval = validate_recv_mgnt_frame(adapter, precv_frame);
- if (retval == _FAIL)
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_mgnt_frame fail\n"));
retval = _FAIL; /* only data frame return _SUCCESS */
break;
case WIFI_CTRL_TYPE: /* ctrl */
retval = validate_recv_ctrl_frame(adapter, precv_frame);
- if (retval == _FAIL)
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_ctrl_frame fail\n"));
retval = _FAIL; /* only data frame return _SUCCESS */
break;
case WIFI_DATA_TYPE: /* data */
@@ -1225,7 +1053,6 @@ static int validate_recv_frame(struct adapter *adapter,
}
break;
default:
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail! type= 0x%x\n", type));
retval = _FAIL;
break;
}
@@ -1282,9 +1109,6 @@ static int wlanhdr_to_ethhdr(struct recv_frame *precvframe)
rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0);
len = precvframe->pkt->len - rmv_len;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- ("\n===pattrib->hdrlen: %x, pattrib->iv_len:%x===\n\n", pattrib->hdrlen, pattrib->iv_len));
-
memcpy(&be_tmp, ptr + rmv_len, 2);
eth_type = ntohs(be_tmp); /* pattrib->ether_type */
pattrib->eth_type = eth_type;
@@ -1373,8 +1197,6 @@ static struct recv_frame *recvframe_defrag(struct adapter *adapter,
/* free the defrag_q queue and return the prframe */
rtw_free_recvframe_queue(defrag_q, pfree_recv_queue);
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Performance defrag!!!!!\n"));
-
return prframe;
}
@@ -1436,14 +1258,11 @@ struct recv_frame *recvframe_chk_defrag(struct adapter *padapter,
phead = get_list_head(pdefrag_q);
list_add_tail(&pfhdr->list, phead);
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Enqueuq: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum));
-
prtnframe = NULL;
} else {
/* can't find this ta's defrag_queue, so free this recv_frame */
rtw_free_recvframe(precv_frame, pfree_recv_queue);
prtnframe = NULL;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("Free because pdefrag_q==NULL: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum));
}
}
@@ -1455,21 +1274,18 @@ struct recv_frame *recvframe_chk_defrag(struct adapter *padapter,
list_add_tail(&pfhdr->list, phead);
/* call recvframe_defrag to defrag */
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("defrag: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum));
precv_frame = recvframe_defrag(padapter, pdefrag_q);
prtnframe = precv_frame;
} else {
/* can't find this ta's defrag_queue, so free this recv_frame */
rtw_free_recvframe(precv_frame, pfree_recv_queue);
prtnframe = NULL;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("Free because pdefrag_q==NULL: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum));
}
}
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"));
rtw_free_recvframe(prtnframe, pfree_recv_queue);
prtnframe = NULL;
}
@@ -1505,10 +1321,8 @@ static int amsdu_to_msdu(struct adapter *padapter, struct recv_frame *prframe)
/* Offset 12 denote 2 mac address */
nSubframe_Length = get_unaligned_be16(pdata + 12);
- if (a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) {
- DBG_88E("nRemain_Length is %d and nSubframe_Length is : %d\n", a_len, nSubframe_Length);
+ if (a_len < (ETH_HLEN + nSubframe_Length))
goto exit;
- }
/* move the data point to data content */
pdata += ETH_HLEN;
@@ -1516,20 +1330,16 @@ static int amsdu_to_msdu(struct adapter *padapter, struct recv_frame *prframe)
/* Allocate new skb for releasing to upper layer */
sub_skb = dev_alloc_skb(nSubframe_Length + 12);
- if (!sub_skb) {
- DBG_88E("dev_alloc_skb() Fail!!! , nr_subframes=%d\n", nr_subframes);
+ if (!sub_skb)
break;
- }
skb_reserve(sub_skb, 12);
skb_put_data(sub_skb, pdata, nSubframe_Length);
subframes[nr_subframes++] = sub_skb;
- if (nr_subframes >= MAX_SUBFRAME_COUNT) {
- DBG_88E("ParseSubframe(): Too many Subframes! Packets dropped!\n");
+ if (nr_subframes >= MAX_SUBFRAME_COUNT)
break;
- }
pdata += nSubframe_Length;
a_len -= nSubframe_Length;
@@ -1674,9 +1484,6 @@ static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reor
pattrib = &prframe->attrib;
if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
- ("%s: indicate=%d seq=%d amsdu=%d\n",
- __func__, preorder_ctrl->indicate_seq, pattrib->seq_num, pattrib->amsdu));
plist = plist->next;
list_del_init(&prframe->list);
@@ -1723,8 +1530,6 @@ static int recv_indicatepkt_reorder(struct adapter *padapter,
(pattrib->ack_policy != 0)) {
if ((!padapter->bDriverStopped) &&
(!padapter->bSurpriseRemoved)) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ %s -recv_func recv_indicatepkt\n", __func__));
-
rtw_recv_indicatepkt(padapter, prframe);
return _SUCCESS;
}
@@ -1754,10 +1559,6 @@ static int recv_indicatepkt_reorder(struct adapter *padapter,
spin_lock_bh(&ppending_recvframe_queue->lock);
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
- ("%s: indicate=%d seq=%d\n", __func__,
- preorder_ctrl->indicate_seq, pattrib->seq_num));
-
/* s2. check if winstart_b(indicate_seq) needs to been updated */
if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) {
rtw_recv_indicatepkt(padapter, prframe);
@@ -1838,22 +1639,15 @@ static int process_recv_indicatepkts(struct adapter *padapter,
}
} else { /* B/G mode */
retval = wlanhdr_to_ethhdr(prframe);
- if (retval != _SUCCESS) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("wlanhdr_to_ethhdr: drop pkt\n"));
+ if (retval != _SUCCESS)
return retval;
- }
if ((!padapter->bDriverStopped) &&
- (!padapter->bSurpriseRemoved)) {
+ (!padapter->bSurpriseRemoved))
/* indicate this recv_frame */
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ %s- recv_func recv_indicatepkt\n", __func__));
rtw_recv_indicatepkt(padapter, prframe);
- } else {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ %s- recv_func free_indicatepkt\n", __func__));
-
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_func:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved));
+ else
return _FAIL;
- }
}
return retval;
@@ -1868,7 +1662,6 @@ static int recv_func_prehandle(struct adapter *padapter,
/* check the frame crtl field and decache */
ret = validate_recv_frame(padapter, rframe);
if (ret != _SUCCESS) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("recv_func: validate_recv_frame fail! drop pkt\n"));
rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */
goto exit;
}
@@ -1890,20 +1683,16 @@ static int recv_func_posthandle(struct adapter *padapter,
prframe = decryptor(padapter, prframe);
if (!prframe) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decryptor: drop pkt\n"));
ret = _FAIL;
goto _recv_data_drop;
}
prframe = recvframe_chk_defrag(padapter, prframe);
- if (!prframe) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chk_defrag: drop pkt\n"));
+ if (!prframe)
goto _recv_data_drop;
- }
prframe = portctrl(padapter, prframe);
if (!prframe) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("portctrl: drop pkt\n"));
ret = _FAIL;
goto _recv_data_drop;
}
@@ -1912,7 +1701,6 @@ static int recv_func_posthandle(struct adapter *padapter,
ret = process_recv_indicatepkts(padapter, prframe);
if (ret != _SUCCESS) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recv_func: process_recv_indicatepkts fail!\n"));
rtw_free_recvframe(orig_prframe, pfree_recv_queue);/* free this recv_frame */
goto _recv_data_drop;
}
@@ -1934,10 +1722,8 @@ static int recv_func(struct adapter *padapter, struct recv_frame *rframe)
if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && psecuritypriv->busetkipkey) {
struct recv_frame *pending_frame;
- while ((pending_frame = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue))) {
- if (recv_func_posthandle(padapter, pending_frame) == _SUCCESS)
- DBG_88E("%s: dequeue uc_swdec_pending_queue\n", __func__);
- }
+ while ((pending_frame = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue)))
+ recv_func_posthandle(padapter, pending_frame);
}
ret = recv_func_prehandle(padapter, rframe);
@@ -1951,7 +1737,6 @@ static int recv_func(struct adapter *padapter, struct recv_frame *rframe)
!is_wep_enc(psecuritypriv->dot11PrivacyAlgrthm) &&
!psecuritypriv->busetkipkey) {
rtw_enqueue_recvframe(rframe, &padapter->recvpriv.uc_swdec_pending_queue);
- DBG_88E("%s: no key, enqueue uc_swdec_pending_queue\n", __func__);
goto exit;
}
@@ -1971,8 +1756,6 @@ int rtw_recv_entry(struct recv_frame *precvframe)
ret = recv_func(padapter, precvframe);
if (ret == _SUCCESS)
precvpriv->rx_pkts++;
- else
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("%s: recv_func return fail!!!\n", __func__));
return ret;
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c
index 617f89842c81..1b2cb6196463 100644
--- a/drivers/staging/rtl8188eu/core/rtw_security.c
+++ b/drivers/staging/rtl8188eu/core/rtw_security.c
@@ -465,8 +465,9 @@ static const unsigned short Sbox1[2][256] = { /* Sbox for hash (can be in ROM)
/**
* phase1() - generate P1K, given TA, TK, IV32
- * @tk[]: temporal key [128 bits]
- * @ta[]: transmitter's MAC address [ 48 bits]
+ * @p1k: placeholder for the returned phase 1 key
+ * @tk: temporal key [128 bits]
+ * @ta: transmitter's MAC address [ 48 bits]
* @iv32: upper 32 bits of IV [ 32 bits]
*
* This function only needs to be called every 2**16 packets,
@@ -498,8 +499,9 @@ static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32)
/**
* phase2() - generate RC4KEY, given TK, P1K, IV16
- * @tk[]: Temporal key [128 bits]
- * @p1k[]: Phase 1 output key [ 80 bits]
+ * @rc4key: Placeholder for the returned key
+ * @tk: Temporal key [128 bits]
+ * @p1k: Phase 1 output key [ 80 bits]
* @iv16: low 16 bits of IV counter [ 16 bits]
*
* The value {TA, IV32, IV16} for Phase1/Phase2 must be unique
@@ -589,8 +591,6 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, struct xmit_frame *pxmitframe)
stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]);
if (stainfo) {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo!= NULL!!!\n", __func__));
-
if (is_multicast_ether_addr(pattrib->ra))
prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey;
else
@@ -609,9 +609,6 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, struct xmit_frame *pxmitframe)
if ((curfragnum + 1) == pattrib->nr_frags) { /* 4 the last fragment */
length = pattrib->last_txcmdsz - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len;
- RT_TRACE(_module_rtl871x_security_c_, _drv_info_,
- ("pattrib->iv_len=%x, pattrib->icv_len=%x\n",
- pattrib->iv_len, pattrib->icv_len));
*((__le32 *)crc) = getcrc32(payload, length);/* modified by Amy*/
arcfour_init(&mycontext, rc4key, 16);
@@ -629,7 +626,6 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, struct xmit_frame *pxmitframe)
}
}
} else {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo==NULL!!!\n", __func__));
res = _FAIL;
}
}
@@ -662,12 +658,10 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, struct recv_frame *precvframe)
if (is_multicast_ether_addr(prxattrib->ra)) {
if (!psecuritypriv->binstallGrpkey) {
res = _FAIL;
- DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__);
goto exit;
}
prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey;
} else {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo!= NULL!!!\n", __func__));
prwskey = &stainfo->dot118021x_UncstKey.skey[0];
}
@@ -693,14 +687,9 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, struct recv_frame *precvframe)
if (crc[3] != payload[length - 1] ||
crc[2] != payload[length - 2] ||
crc[1] != payload[length - 3] ||
- crc[0] != payload[length - 4]) {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
- ("rtw_wep_decrypt:icv error crc (%4ph)!=payload (%4ph)\n",
- &crc, &payload[length - 4]));
+ crc[0] != payload[length - 4])
res = _FAIL;
- }
} else {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo==NULL!!!\n", __func__));
res = _FAIL;
}
}
@@ -742,10 +731,8 @@ u32 rtw_aes_encrypt(struct adapter *padapter, struct xmit_frame *pxmitframe)
else
stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]);
- if (!stainfo) {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo==NULL!!!\n", __func__));
+ if (!stainfo)
return _FAIL;
- }
crypto_ops = lib80211_get_crypto_ops("CCMP");
@@ -770,8 +757,6 @@ u32 rtw_aes_encrypt(struct adapter *padapter, struct xmit_frame *pxmitframe)
goto exit_crypto_ops_deinit;
}
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo!= NULL!!!\n", __func__));
-
for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) {
if (curfragnum + 1 == pattrib->nr_frags)
length = pattrib->last_txcmdsz;
@@ -834,7 +819,6 @@ u32 rtw_aes_decrypt(struct adapter *padapter, struct recv_frame *precvframe)
/* in concurrent we should use sw descrypt in group key, so we remove this message */
if (!psecuritypriv->binstallGrpkey) {
res = _FAIL;
- DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__);
goto exit;
}
key_idx = psecuritypriv->dot118021XGrpKeyid;
@@ -877,7 +861,6 @@ exit_lib80211_ccmp:
if (crypto_ops && crypto_private)
crypto_ops->deinit(crypto_private);
} else {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo==NULL!!!\n"));
res = _FAIL;
}
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c
index 3c03141e25b1..19eddf573fd8 100644
--- a/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c
+++ b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c
@@ -114,17 +114,11 @@ inline int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta)
{
int offset = (((u8 *)sta) - stapriv->pstainfo_buf) / sizeof(struct sta_info);
- if (!stainfo_offset_valid(offset))
- DBG_88E("%s invalid offset(%d), out of range!!!", __func__, offset);
-
return offset;
}
inline struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int offset)
{
- if (!stainfo_offset_valid(offset))
- DBG_88E("%s invalid offset(%d), out of range!!!", __func__, offset);
-
return (struct sta_info *)(stapriv->pstainfo_buf + offset * sizeof(struct sta_info));
}
@@ -142,13 +136,10 @@ u32 _rtw_free_sta_priv(struct sta_priv *pstapriv)
spin_lock_bh(&pstapriv->sta_hash_lock);
for (index = 0; index < NUM_STA; index++) {
phead = &pstapriv->sta_hash[index];
- plist = phead->next;
-
- while (phead != plist) {
+ list_for_each(plist, phead) {
int i;
- psta = container_of(plist, struct sta_info, hash_list);
- plist = plist->next;
+ psta = list_entry(plist, struct sta_info, hash_list);
for (i = 0; i < 16; i++) {
preorder_ctrl = &psta->recvreorder_ctrl[i];
@@ -188,13 +179,8 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
_rtw_init_stainfo(psta);
memcpy(psta->hwaddr, hwaddr, ETH_ALEN);
index = wifi_mac_hash(hwaddr);
- RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_,
- ("%s: index=%x", __func__, index));
- if (index >= NUM_STA) {
- RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_,
- ("ERROR => %s: index >= NUM_STA", __func__));
+ if (index >= NUM_STA)
return NULL;
- }
phash_list = &pstapriv->sta_hash[index];
spin_lock_bh(&pstapriv->sta_hash_lock);
@@ -214,10 +200,6 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i],
&wRxSeqInitialValue, 2);
- RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_,
- ("alloc number_%d stainfo with hwaddr = %pM\n",
- pstapriv->asoc_sta_count, hwaddr));
-
init_addba_retry_timer(pstapriv->padapter, psta);
/* for A-MPDU Rx reordering buffer control */
@@ -288,11 +270,6 @@ u32 rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta)
spin_unlock_bh(&pxmitpriv->lock);
list_del_init(&psta->hash_list);
- RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_,
- ("\n free number_%d stainfo with hwaddr=0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n",
- pstapriv->asoc_sta_count, psta->hwaddr[0], psta->hwaddr[1],
- psta->hwaddr[2], psta->hwaddr[3], psta->hwaddr[4],
- psta->hwaddr[5]));
pstapriv->asoc_sta_count--;
/* re-init sta_info; 20061114 */
@@ -382,9 +359,9 @@ exit:
/* free all stainfo which in sta_hash[all] */
void rtw_free_all_stainfo(struct adapter *padapter)
{
- struct list_head *plist, *phead;
+ struct list_head *phead;
s32 index;
- struct sta_info *psta = NULL;
+ struct sta_info *psta, *temp;
struct sta_priv *pstapriv = &padapter->stapriv;
struct sta_info *pbcmc_stainfo = rtw_get_bcmc_stainfo(padapter);
@@ -395,13 +372,7 @@ void rtw_free_all_stainfo(struct adapter *padapter)
for (index = 0; index < NUM_STA; index++) {
phead = &pstapriv->sta_hash[index];
- plist = phead->next;
-
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, hash_list);
-
- plist = plist->next;
-
+ list_for_each_entry_safe(psta, temp, phead, hash_list) {
if (pbcmc_stainfo != psta)
rtw_free_stainfo(padapter, psta);
}
@@ -431,17 +402,14 @@ struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
spin_lock_bh(&pstapriv->sta_hash_lock);
phead = &pstapriv->sta_hash[index];
- plist = phead->next;
-
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, hash_list);
+ list_for_each(plist, phead) {
+ psta = list_entry(plist, struct sta_info, hash_list);
if (!memcmp(psta->hwaddr, addr, ETH_ALEN)) {
/* if found the matched address */
break;
}
psta = NULL;
- plist = plist->next;
}
spin_unlock_bh(&pstapriv->sta_hash_lock);
@@ -456,11 +424,8 @@ u32 rtw_init_bcmc_stainfo(struct adapter *padapter)
psta = rtw_alloc_stainfo(pstapriv, bc_addr);
- if (!psta) {
- RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_,
- ("rtw_alloc_stainfo fail"));
+ if (!psta)
return _FAIL;
- }
/* default broadcast & multicast use macid 1 */
psta->mac_id = 1;
@@ -489,10 +454,8 @@ bool rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr)
spin_lock_bh(&pacl_node_q->lock);
phead = get_list_head(pacl_node_q);
- plist = phead->next;
- while (phead != plist) {
- paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
- plist = plist->next;
+ list_for_each(plist, phead) {
+ paclnode = list_entry(plist, struct rtw_wlan_acl_node, list);
if (!memcmp(paclnode->addr, mac_addr, ETH_ALEN)) {
if (paclnode->valid) {
diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
index 7015db16dcf8..2d4776debb97 100644
--- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
+++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
@@ -521,8 +521,6 @@ void WMMOnAssocRsp(struct adapter *padapter)
edca[XMIT_VO_QUEUE] = acParm;
break;
}
-
- DBG_88E("WMM(%x): %x, %x\n", ACI, ACM, acParm);
}
if (padapter->registrypriv.acm_method == 1)
@@ -556,10 +554,8 @@ void WMMOnAssocRsp(struct adapter *padapter)
}
}
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < 4; i++)
pxmitpriv->wmm_para_seq[i] = inx[i];
- DBG_88E("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]);
- }
}
static void bwmode_update_check(struct adapter *padapter, struct ndis_802_11_var_ie *pIE)
@@ -708,8 +704,6 @@ void HTOnAssocRsp(struct adapter *padapter)
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
- DBG_88E("%s\n", __func__);
-
if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) {
pmlmeinfo->HT_enable = 1;
} else {
@@ -803,16 +797,11 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
len = packet_len - sizeof(struct ieee80211_hdr_3addr);
- if (len > MAX_IE_SZ) {
- DBG_88E("%s IE too long for survey event\n", __func__);
+ if (len > MAX_IE_SZ)
return _FAIL;
- }
- if (memcmp(cur_network->network.MacAddress, pbssid, 6)) {
- DBG_88E("Oops: rtw_check_network_encrypt linked but recv other bssid bcn\n%pM %pM\n",
- (pbssid), (cur_network->network.MacAddress));
+ if (memcmp(cur_network->network.MacAddress, pbssid, 6))
return true;
- }
bssid = kzalloc(sizeof(struct wlan_bssid_ex), GFP_ATOMIC);
if (!bssid)
@@ -820,7 +809,7 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
subtype = GetFrameSubType(pframe) >> 4;
- if (subtype == WIFI_BEACON)
+ if (subtype == IEEE80211_STYPE_BEACON)
bssid->Reserved[0] = 1;
bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len;
@@ -850,11 +839,6 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
}
if (ht_cap_info != cur_network->BcnInfo.ht_cap_info ||
((ht_info_infos_0 & 0x03) != (cur_network->BcnInfo.ht_info_infos_0 & 0x03))) {
- DBG_88E("%s bcn now: ht_cap_info:%x ht_info_infos_0:%x\n", __func__,
- ht_cap_info, ht_info_infos_0);
- DBG_88E("%s bcn link: ht_cap_info:%x ht_info_infos_0:%x\n", __func__,
- cur_network->BcnInfo.ht_cap_info, cur_network->BcnInfo.ht_info_infos_0);
- DBG_88E("%s bw mode change, disconnect\n", __func__);
/* bcn_info_update */
cur_network->BcnInfo.ht_cap_info = ht_cap_info;
cur_network->BcnInfo.ht_info_infos_0 = ht_info_infos_0;
@@ -868,18 +852,13 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
bcn_channel = *(p + 2);
} else {/* In 5G, some ap do not have DSSET IE checking HT info for channel */
p = rtw_get_ie(bssid->ies + _FIXED_IE_LENGTH_, WLAN_EID_HT_OPERATION, &len, bssid->ie_length - _FIXED_IE_LENGTH_);
- if (pht_info) {
+ if (pht_info)
bcn_channel = pht_info->primary_channel;
- } else { /* we don't find channel IE, so don't check it */
- DBG_88E("Oops: %s we don't find channel IE, so don't check it\n", __func__);
+ else /* we don't find channel IE, so don't check it */
bcn_channel = Adapter->mlmeextpriv.cur_channel;
- }
}
- if (bcn_channel != Adapter->mlmeextpriv.cur_channel) {
- DBG_88E("%s beacon channel:%d cur channel:%d disconnect\n", __func__,
- bcn_channel, Adapter->mlmeextpriv.cur_channel);
+ if (bcn_channel != Adapter->mlmeextpriv.cur_channel)
goto _mismatch;
- }
/* checking SSID */
ssid_len = 0;
@@ -892,17 +871,10 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
memcpy(bssid->ssid.ssid, (p + 2), ssid_len);
bssid->ssid.ssid_length = ssid_len;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s bssid.ssid.ssid:%s bssid.ssid.ssid_length:%d "
- "cur_network->network.ssid.ssid:%s len:%d\n", __func__, bssid->ssid.ssid,
- bssid->ssid.ssid_length, cur_network->network.ssid.ssid,
- cur_network->network.ssid.ssid_length));
-
if (memcmp(bssid->ssid.ssid, cur_network->network.ssid.ssid, 32) ||
bssid->ssid.ssid_length != cur_network->network.ssid.ssid_length) {
- if (bssid->ssid.ssid[0] != '\0' && bssid->ssid.ssid_length != 0) { /* not hidden ssid */
- DBG_88E("%s(), SSID is not match return FAIL\n", __func__);
+ if (bssid->ssid.ssid[0] != '\0' && bssid->ssid.ssid_length != 0) /* not hidden ssid */
goto _mismatch;
- }
}
/* check encryption info */
@@ -913,13 +885,8 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
else
bssid->Privacy = 0;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("%s(): cur_network->network.Privacy is %d, bssid.Privacy is %d\n",
- __func__, cur_network->network.Privacy, bssid->Privacy));
- if (cur_network->network.Privacy != bssid->Privacy) {
- DBG_88E("%s(), privacy is not match return FAIL\n", __func__);
+ if (cur_network->network.Privacy != bssid->Privacy)
goto _mismatch;
- }
rtw_get_sec_ie(bssid->ies, bssid->ie_length, NULL, &rsn_len, NULL, &wpa_len);
@@ -932,46 +899,29 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
encryp_protocol = ENCRYP_PROTOCOL_WEP;
}
- if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) {
- DBG_88E("%s(): encryption protocol is not match , return FAIL\n", __func__);
+ if (cur_network->BcnInfo.encryp_protocol != encryp_protocol)
goto _mismatch;
- }
if (encryp_protocol == ENCRYP_PROTOCOL_WPA || encryp_protocol == ENCRYP_PROTOCOL_WPA2) {
pbuf = rtw_get_wpa_ie(&bssid->ies[12], &wpa_ielen,
bssid->ie_length - 12);
if (pbuf && (wpa_ielen > 0)) {
- if (rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is_8021x) == _SUCCESS) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("%s pnetwork->pairwise_cipher: %d, group_cipher is %d, is_8021x is %d\n", __func__,
- pairwise_cipher, group_cipher, is_8021x));
- }
+ rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher,
+ &pairwise_cipher, &is_8021x);
} else {
pbuf = rtw_get_wpa2_ie(&bssid->ies[12], &wpa_ielen,
bssid->ie_length - 12);
- if (pbuf && (wpa_ielen > 0)) {
- if (rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is_8021x) == _SUCCESS) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("%s pnetwork->pairwise_cipher: %d, pnetwork->group_cipher is %d, is_802x is %d\n",
- __func__, pairwise_cipher, group_cipher, is_8021x));
- }
- }
+ if (pbuf && (wpa_ielen > 0))
+ rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher,
+ &pairwise_cipher, &is_8021x);
}
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
- ("%s cur_network->group_cipher is %d: %d\n", __func__, cur_network->BcnInfo.group_cipher, group_cipher));
- if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || group_cipher != cur_network->BcnInfo.group_cipher) {
- DBG_88E("%s pairwise_cipher(%x:%x) or group_cipher(%x:%x) is not match , return FAIL\n", __func__,
- pairwise_cipher, cur_network->BcnInfo.pairwise_cipher,
- group_cipher, cur_network->BcnInfo.group_cipher);
+ if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || group_cipher != cur_network->BcnInfo.group_cipher)
goto _mismatch;
- }
- if (is_8021x != cur_network->BcnInfo.is_8021x) {
- DBG_88E("%s authentication is not match , return FAIL\n", __func__);
+ if (is_8021x != cur_network->BcnInfo.is_8021x)
goto _mismatch;
- }
}
kfree(bssid);
@@ -1029,6 +979,7 @@ unsigned int is_ap_in_tkip(struct adapter *padapter)
case WLAN_EID_RSN:
if (!memcmp((pIE->data + 8), RSN_TKIP_CIPHER, 4))
return true;
+ break;
default:
break;
}
@@ -1191,41 +1142,31 @@ unsigned char check_assoc_AP(u8 *pframe, uint len)
case WLAN_EID_VENDOR_SPECIFIC:
if ((!memcmp(pIE->data, ARTHEROS_OUI1, 3)) ||
(!memcmp(pIE->data, ARTHEROS_OUI2, 3))) {
- DBG_88E("link to Artheros AP\n");
return HT_IOT_PEER_ATHEROS;
} else if ((!memcmp(pIE->data, BROADCOM_OUI1, 3)) ||
(!memcmp(pIE->data, BROADCOM_OUI2, 3))) {
- DBG_88E("link to Broadcom AP\n");
return HT_IOT_PEER_BROADCOM;
} else if (!memcmp(pIE->data, MARVELL_OUI, 3)) {
- DBG_88E("link to Marvell AP\n");
return HT_IOT_PEER_MARVELL;
} else if (!memcmp(pIE->data, RALINK_OUI, 3)) {
- if (!ralink_vendor_flag) {
+ if (!ralink_vendor_flag)
ralink_vendor_flag = 1;
- } else {
- DBG_88E("link to Ralink AP\n");
+ else
return HT_IOT_PEER_RALINK;
- }
} else if (!memcmp(pIE->data, CISCO_OUI, 3)) {
- DBG_88E("link to Cisco AP\n");
return HT_IOT_PEER_CISCO;
} else if (!memcmp(pIE->data, REALTEK_OUI, 3)) {
- DBG_88E("link to Realtek 96B\n");
return HT_IOT_PEER_REALTEK;
} else if (!memcmp(pIE->data, AIRGOCAP_OUI, 3)) {
- DBG_88E("link to Airgo Cap\n");
return HT_IOT_PEER_AIRGO;
} else if (!memcmp(pIE->data, EPIGRAM_OUI, 3)) {
epigram_vendor_flag = 1;
- if (ralink_vendor_flag) {
- DBG_88E("link to Tenda W311R AP\n");
+ if (ralink_vendor_flag)
return HT_IOT_PEER_TENDA;
- }
- DBG_88E("Capture EPIGRAM_OUI\n");
} else {
break;
}
+ break;
default:
break;
@@ -1233,14 +1174,10 @@ unsigned char check_assoc_AP(u8 *pframe, uint len)
i += (pIE->Length + 2);
}
- if (ralink_vendor_flag && !epigram_vendor_flag) {
- DBG_88E("link to Ralink AP\n");
+ if (ralink_vendor_flag && !epigram_vendor_flag)
return HT_IOT_PEER_RALINK;
- } else if (ralink_vendor_flag && epigram_vendor_flag) {
- DBG_88E("link to Tenda W311R AP\n");
+ else if (ralink_vendor_flag && epigram_vendor_flag)
return HT_IOT_PEER_TENDA;
- }
- DBG_88E("link to new AP\n");
return HT_IOT_PEER_UNKNOWN;
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c
index 99e44b2c6f36..d5fc59417ec6 100644
--- a/drivers/staging/rtl8188eu/core/rtw_xmit.c
+++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c
@@ -75,7 +75,6 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
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;
goto exit;
}
@@ -110,7 +109,6 @@ 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) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_buf fail!\n"));
res = _FAIL;
goto exit;
}
@@ -149,7 +147,6 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
pxmitpriv->pallocated_xmit_extbuf = vzalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
if (!pxmitpriv->pallocated_xmit_extbuf) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_extbuf fail!\n"));
res = _FAIL;
goto exit;
}
@@ -364,8 +361,6 @@ u8 qos_acm(u8 acm_mask, u8 priority)
change_priority = 5;
break;
default:
- DBG_88E("%s(): invalid pattrib->priority: %d!!!\n",
- __func__, priority);
break;
}
@@ -444,14 +439,11 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
((tmp[21] == 67) && (tmp[23] == 68))) {
/* 68 : UDP BOOTP client */
/* 67 : UDP BOOTP server */
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====================== %s: get DHCP Packet\n", __func__));
/* Use low rate to send DHCP packet. */
pattrib->dhcp_pkt = 1;
}
}
}
- } else if (pattrib->ether_type == ETH_P_PAE) {
- DBG_88E_LEVEL(_drv_info_, "send eapol packet\n");
}
if ((pattrib->ether_type == ETH_P_PAE) || (pattrib->dhcp_pkt == 1))
@@ -469,7 +461,6 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
} else {
psta = rtw_get_stainfo(pstapriv, pattrib->ra);
if (!psta) { /* if we cannot get psta => drrp the pkt */
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra: %pM\n", (pattrib->ra)));
res = _FAIL;
goto exit;
} else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) &&
@@ -481,11 +472,9 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
if (psta) {
pattrib->mac_id = psta->mac_id;
- /* DBG_88E("%s ==> mac_id(%d)\n", __func__, pattrib->mac_id); */
pattrib->psta = psta;
} else {
/* if we cannot get psta => drop the pkt */
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:%pM\n", (pattrib->ra)));
res = _FAIL;
goto exit;
}
@@ -510,12 +499,9 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
}
if (psta->ieee8021x_blocked) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\n psta->ieee8021x_blocked == true\n"));
-
pattrib->encrypt = 0;
if (pattrib->ether_type != ETH_P_PAE) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\npsta->ieee8021x_blocked == true, pattrib->ether_type(%.4x) != ETH_P_PAE\n", pattrib->ether_type));
res = _FAIL;
goto exit;
}
@@ -551,15 +537,11 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
pattrib->icv_len = 4;
if (padapter->securitypriv.busetkipkey == _FAIL) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
- ("\npadapter->securitypriv.busetkipkey(%d) == _FAIL drop packet\n",
- padapter->securitypriv.busetkipkey));
res = _FAIL;
goto exit;
}
break;
case _AES_:
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("pattrib->encrypt=%d (_AES_)\n", pattrib->encrypt));
pattrib->iv_len = 8;
pattrib->icv_len = 8;
break;
@@ -569,18 +551,10 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
break;
}
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
- ("%s: encrypt=%d\n", __func__, pattrib->encrypt));
-
- if (pattrib->encrypt && !psecuritypriv->hw_decrypted) {
+ if (pattrib->encrypt && !psecuritypriv->hw_decrypted)
pattrib->bswenc = true;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
- ("%s: encrypt=%d bswenc = true\n", __func__,
- pattrib->encrypt));
- } else {
+ else
pattrib->bswenc = false;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s: bswenc = false\n", __func__));
- }
update_attrib_phy_info(pattrib, psta);
@@ -649,17 +623,8 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr
for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) {
payload = (u8 *)round_up((size_t)(payload), 4);
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
- ("=== curfragnum=%d, pframe = 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x,!!!\n",
- curfragnum, *payload, *(payload + 1),
- *(payload + 2), *(payload + 3),
- *(payload + 4), *(payload + 5),
- *(payload + 6), *(payload + 7)));
payload += pattrib->hdrlen + pattrib->iv_len;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
- ("curfragnum=%d pattrib->hdrlen=%d pattrib->iv_len=%d",
- curfragnum, pattrib->hdrlen, pattrib->iv_len));
if (curfragnum + 1 == pattrib->nr_frags) {
length = pattrib->last_txcmdsz -
pattrib->hdrlen -
@@ -676,32 +641,16 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr
pattrib->icv_len : 0);
rtw_secmicappend(&micdata, payload, length);
payload += length + pattrib->icv_len;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("curfragnum=%d length=%d pattrib->icv_len=%d", curfragnum, length, pattrib->icv_len));
}
}
rtw_secgetmic(&micdata, &mic[0]);
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: before add mic code!!!\n", __func__));
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: pattrib->last_txcmdsz=%d!!!\n", __func__, pattrib->last_txcmdsz));
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: mic[0]=0x%.2x , mic[1]=0x%.2x , mic[2]= 0x%.2x, mic[3]=0x%.2x\n\
- mic[4]= 0x%.2x , mic[5]= 0x%.2x , mic[6]= 0x%.2x , mic[7]= 0x%.2x !!!!\n",
- __func__, mic[0], mic[1], mic[2], mic[3], mic[4], mic[5], mic[6], mic[7]));
/* add mic code and add the mic code length in last_txcmdsz */
memcpy(payload, &mic[0], 8);
pattrib->last_txcmdsz += 8;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("\n ======== last pkt ========\n"));
payload -= pattrib->last_txcmdsz + 8;
- for (curfragnum = 0; curfragnum < pattrib->last_txcmdsz; curfragnum += 8)
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
- (" %.2x, %.2x, %.2x, %.2x, %.2x, %.2x, %.2x, %.2x ",
- *(payload + curfragnum), *(payload + curfragnum + 1),
- *(payload + curfragnum + 2), *(payload + curfragnum + 3),
- *(payload + curfragnum + 4), *(payload + curfragnum + 5),
- *(payload + curfragnum + 6), *(payload + curfragnum + 7)));
- } else {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: rtw_get_stainfo==NULL!!!\n", __func__));
- }
+ }
}
return _SUCCESS;
@@ -712,7 +661,6 @@ static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmi
struct pkt_attrib *pattrib = &pxmitframe->attrib;
if (pattrib->bswenc) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("### %s\n", __func__));
switch (pattrib->encrypt) {
case _WEP40_:
case _WEP104_:
@@ -727,8 +675,6 @@ static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmi
default:
break;
}
- } else {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, ("### xmitframe_hwencrypt\n"));
}
return _SUCCESS;
@@ -790,7 +736,6 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr
if (psta && psta->qos_option)
qos_option = true;
} else {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("fw_state:%x is not allowed to xmit frame\n", get_fwstate(pmlmepriv)));
res = _FAIL;
goto exit;
}
@@ -926,10 +871,8 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
if (!psta)
return _FAIL;
- if (!pxmitframe->buf_addr) {
- DBG_88E("==> %s buf_addr == NULL\n", __func__);
+ if (!pxmitframe->buf_addr)
return _FAIL;
- }
pbuf_start = pxmitframe->buf_addr;
@@ -938,8 +881,6 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
mem_start = pbuf_start + hw_hdr_offset;
if (rtw_make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: rtw_make_wlanhdr fail; drop pkt\n", __func__));
- DBG_88E("%s: rtw_make_wlanhdr fail; drop pkt\n", __func__);
res = _FAIL;
goto exit;
}
@@ -982,13 +923,6 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
memcpy(pframe, pattrib->iv, pattrib->iv_len);
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_,
- ("%s: keyid=%d pattrib->iv[3]=%.2x pframe=%.2x %.2x %.2x %.2x\n",
- __func__,
- padapter->securitypriv.dot11PrivacyKeyIndex,
- pattrib->iv[3], *pframe, *(pframe + 1),
- *(pframe + 2), *(pframe + 3)));
-
pframe += pattrib->iv_len;
mpdu_len -= pattrib->iv_len;
@@ -1027,8 +961,6 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
break;
}
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: There're still something in packet!\n", __func__));
-
addr = (size_t)(pframe);
mem_start = (unsigned char *)round_up(addr, 4) + hw_hdr_offset;
@@ -1039,8 +971,6 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
rtl88eu_mon_xmit_hook(padapter->pmondev, pxmitframe, frg_len);
if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n"));
- DBG_88E("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n");
res = _FAIL;
goto exit;
}
@@ -1153,10 +1083,8 @@ struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv)
list_del_init(&pxmitbuf->list);
pxmitpriv->free_xmit_extbuf_cnt--;
pxmitbuf->priv_data = NULL;
- if (pxmitbuf->sctx) {
- DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__);
+ if (pxmitbuf->sctx)
rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC);
- }
}
spin_unlock_irqrestore(&pfree_queue->lock, irql);
@@ -1197,7 +1125,6 @@ struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv)
pxmitpriv->free_xmitbuf_cnt--;
pxmitbuf->priv_data = NULL;
if (pxmitbuf->sctx) {
- DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__);
rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC);
}
}
@@ -1214,10 +1141,8 @@ s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
if (!pxmitbuf)
return _FAIL;
- if (pxmitbuf->sctx) {
- DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__);
+ if (pxmitbuf->sctx)
rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_FREE);
- }
if (pxmitbuf->ext_tag) {
rtw_free_xmitbuf_ext(pxmitpriv, pxmitbuf);
@@ -1261,20 +1186,12 @@ struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)
spin_lock_bh(&pfree_xmit_queue->lock);
pxframe = list_first_entry_or_null(&pfree_xmit_queue->queue,
struct xmit_frame, list);
- if (!pxframe) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
- ("rtw_alloc_xmitframe:%d\n",
- pxmitpriv->free_xmitframe_cnt));
- } else {
+ if (pxframe) {
list_del_init(&pxframe->list);
/* default value setting */
pxmitpriv->free_xmitframe_cnt--;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
- ("rtw_alloc_xmitframe():free_xmitframe_cnt=%d\n",
- pxmitpriv->free_xmitframe_cnt));
-
pxframe->buf_addr = NULL;
pxframe->pxmitbuf = NULL;
@@ -1299,10 +1216,8 @@ s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitfram
struct adapter *padapter = pxmitpriv->adapter;
struct sk_buff *pndis_pkt = NULL;
- if (!pxmitframe) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====== %s:pxmitframe == NULL!!!!!!!!!!\n", __func__));
+ if (!pxmitframe)
goto exit;
- }
spin_lock_bh(&pfree_xmit_queue->lock);
@@ -1316,7 +1231,6 @@ s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitfram
list_add_tail(&pxmitframe->list, get_list_head(pfree_xmit_queue));
pxmitpriv->free_xmitframe_cnt++;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("%s:free_xmitframe_cnt=%d\n", __func__, pxmitpriv->free_xmitframe_cnt));
spin_unlock_bh(&pfree_xmit_queue->lock);
@@ -1329,31 +1243,22 @@ exit:
void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pframequeue)
{
- struct list_head *plist, *phead;
- struct xmit_frame *pxmitframe;
+ struct list_head *phead;
+ struct xmit_frame *pxmitframe, *temp;
spin_lock_bh(&pframequeue->lock);
phead = get_list_head(pframequeue);
- plist = phead->next;
-
- while (phead != plist) {
- pxmitframe = container_of(plist, struct xmit_frame, list);
-
- plist = plist->next;
-
+ list_for_each_entry_safe(pxmitframe, temp, phead, list)
rtw_free_xmitframe(pxmitpriv, pxmitframe);
- }
+
spin_unlock_bh(&pframequeue->lock);
}
s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe)
{
- if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
- ("%s: drop xmit pkt for classifier fail\n", __func__));
+ if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL)
return _FAIL;
- }
return _SUCCESS;
}
@@ -1404,10 +1309,9 @@ struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv, struct hw_xmi
phwxmit = phwxmit_i + inx[i];
sta_phead = get_list_head(phwxmit->sta_queue);
- sta_plist = sta_phead->next;
-
- while (sta_phead != sta_plist) {
- ptxservq = container_of(sta_plist, struct tx_servq, tx_pending);
+ list_for_each(sta_plist, sta_phead) {
+ ptxservq = list_entry(sta_plist, struct tx_servq,
+ tx_pending);
pframe_queue = &ptxservq->sta_pending;
@@ -1421,8 +1325,6 @@ struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv, struct hw_xmi
list_del_init(&ptxservq->tx_pending);
goto exit;
}
-
- sta_plist = sta_plist->next;
}
}
exit:
@@ -1440,30 +1342,22 @@ struct tx_servq *rtw_get_sta_pending(struct adapter *padapter,
case 2:
ptxservq = &psta->sta_xmitpriv.bk_q;
*(ac) = 3;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
- ("%s : BK\n", __func__));
break;
case 4:
case 5:
ptxservq = &psta->sta_xmitpriv.vi_q;
*(ac) = 1;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
- ("%s : VI\n", __func__));
break;
case 6:
case 7:
ptxservq = &psta->sta_xmitpriv.vo_q;
*(ac) = 0;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
- ("%s : VO\n", __func__));
break;
case 0:
case 3:
default:
ptxservq = &psta->sta_xmitpriv.be_q;
*(ac) = 2;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
- ("%s : BE\n", __func__));
break;
}
@@ -1491,8 +1385,6 @@ s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe)
if (!psta) {
res = _FAIL;
- DBG_88E("%s: psta == NULL\n", __func__);
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: psta == NULL\n", __func__));
goto exit;
}
@@ -1598,16 +1490,12 @@ s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt)
s32 res;
pxmitframe = rtw_alloc_xmitframe(pxmitpriv);
- if (!pxmitframe) {
- RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("%s: no more pxmitframe\n", __func__));
- DBG_88E("DBG_TX_DROP_FRAME %s no more pxmitframe\n", __func__);
+ if (!pxmitframe)
return -1;
- }
res = update_attrib(padapter, *ppkt, &pxmitframe->attrib);
if (res == _FAIL) {
- RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("%s: update attrib fail\n", __func__));
rtw_free_xmitframe(pxmitpriv, pxmitframe);
return -1;
}
@@ -1738,21 +1626,15 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra
static void dequeue_xmitframes_to_sleeping_queue(struct adapter *padapter, struct sta_info *psta, struct __queue *pframequeue)
{
- struct list_head *plist, *phead;
+ struct list_head *phead;
u8 ac_index;
struct tx_servq *ptxservq;
struct pkt_attrib *pattrib;
- struct xmit_frame *pxmitframe;
+ struct xmit_frame *pxmitframe, *n;
struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits;
phead = get_list_head(pframequeue);
- plist = phead->next;
-
- while (phead != plist) {
- pxmitframe = container_of(plist, struct xmit_frame, list);
-
- plist = plist->next;
-
+ list_for_each_entry_safe(pxmitframe, n, phead, list) {
xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe);
pattrib = &pxmitframe->attrib;
@@ -1811,20 +1693,14 @@ void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta)
{
u8 update_mask = 0, wmmps_ac = 0;
struct sta_info *psta_bmc;
- struct list_head *xmitframe_plist, *xmitframe_phead;
- struct xmit_frame *pxmitframe = NULL;
+ struct list_head *xmitframe_phead;
+ struct xmit_frame *pxmitframe, *n;
struct sta_priv *pstapriv = &padapter->stapriv;
spin_lock_bh(&psta->sleep_q.lock);
xmitframe_phead = get_list_head(&psta->sleep_q);
- xmitframe_plist = xmitframe_phead->next;
-
- while (xmitframe_phead != xmitframe_plist) {
- pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
-
- xmitframe_plist = xmitframe_plist->next;
-
+ list_for_each_entry_safe(pxmitframe, n, xmitframe_phead, list) {
list_del_init(&pxmitframe->list);
switch (pxmitframe->attrib.priority) {
@@ -1899,13 +1775,7 @@ void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta)
spin_lock_bh(&psta_bmc->sleep_q.lock);
xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
- xmitframe_plist = xmitframe_phead->next;
-
- while (xmitframe_phead != xmitframe_plist) {
- pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
-
- xmitframe_plist = xmitframe_plist->next;
-
+ list_for_each_entry_safe(pxmitframe, n, xmitframe_phead, list) {
list_del_init(&pxmitframe->list);
psta_bmc->sleepq_len--;
@@ -1939,20 +1809,14 @@ void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta)
void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta)
{
u8 wmmps_ac = 0;
- struct list_head *xmitframe_plist, *xmitframe_phead;
- struct xmit_frame *pxmitframe = NULL;
+ struct list_head *xmitframe_phead;
+ struct xmit_frame *pxmitframe, *n;
struct sta_priv *pstapriv = &padapter->stapriv;
spin_lock_bh(&psta->sleep_q.lock);
xmitframe_phead = get_list_head(&psta->sleep_q);
- xmitframe_plist = xmitframe_phead->next;
-
- while (xmitframe_phead != xmitframe_plist) {
- pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
-
- xmitframe_plist = xmitframe_plist->next;
-
+ list_for_each_entry_safe(pxmitframe, n, xmitframe_phead, list) {
switch (pxmitframe->attrib.priority) {
case 1:
case 2:
@@ -2025,7 +1889,6 @@ int rtw_sctx_wait(struct submit_ctx *sctx)
if (!wait_for_completion_timeout(&sctx->done, expire)) {
/* timeout, do something?? */
status = RTW_SCTX_DONE_TIMEOUT;
- DBG_88E("%s timeout\n", __func__);
} else {
status = sctx->status;
}
@@ -2036,26 +1899,9 @@ int rtw_sctx_wait(struct submit_ctx *sctx)
return ret;
}
-static bool rtw_sctx_chk_warning_status(int status)
-{
- switch (status) {
- case RTW_SCTX_DONE_UNKNOWN:
- case RTW_SCTX_DONE_BUF_ALLOC:
- case RTW_SCTX_DONE_BUF_FREE:
-
- case RTW_SCTX_DONE_DRV_STOP:
- case RTW_SCTX_DONE_DEV_REMOVE:
- return true;
- default:
- return false;
- }
-}
-
void rtw_sctx_done_err(struct submit_ctx **sctx, int status)
{
if (*sctx) {
- if (rtw_sctx_chk_warning_status(status))
- DBG_88E("%s status:%d\n", __func__, status);
(*sctx)->status = status;
complete(&((*sctx)->done));
*sctx = NULL;
@@ -2079,6 +1925,4 @@ void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status)
if (pxmitpriv->ack_tx)
rtw_sctx_done_err(&pack_tx_ops, status);
- else
- DBG_88E("%s ack_tx not set\n", __func__);
}
diff --git a/drivers/staging/rtl8188eu/hal/hal8188e_rate_adaptive.c b/drivers/staging/rtl8188eu/hal/hal8188e_rate_adaptive.c
index 5792f491b59a..74fff76af16d 100644
--- a/drivers/staging/rtl8188eu/hal/hal8188e_rate_adaptive.c
+++ b/drivers/staging/rtl8188eu/hal/hal8188e_rate_adaptive.c
@@ -101,9 +101,6 @@ static void odm_SetTxRPTTiming_8188E(struct odm_dm_struct *dm_odm,
idx -= 1;
}
pRaInfo->RptTime = DynamicTxRPTTiming[idx];
-
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
- ("pRaInfo->RptTime = 0x%x\n", pRaInfo->RptTime));
}
static int odm_RateDown_8188E(struct odm_dm_struct *dm_odm,
@@ -112,20 +109,13 @@ static int odm_RateDown_8188E(struct odm_dm_struct *dm_odm,
u8 RateID, LowestRate, HighestRate;
u8 i;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE,
- ODM_DBG_TRACE, ("=====>%s()\n", __func__));
- if (!pRaInfo) {
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
- ("%s(): pRaInfo is NULL\n", __func__));
+ if (!pRaInfo)
return -1;
- }
+
RateID = pRaInfo->PreRate;
LowestRate = pRaInfo->LowestRate;
HighestRate = pRaInfo->HighestRate;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- (" RateID =%d LowestRate =%d HighestRate =%d RateSGI =%d\n",
- RateID, LowestRate, HighestRate, pRaInfo->RateSGI));
if (RateID > HighestRate) {
RateID = HighestRate;
} else if (pRaInfo->RateSGI) {
@@ -158,15 +148,6 @@ RateDownFinish:
pRaInfo->DecisionRate = RateID;
odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 2);
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE,
- ODM_DBG_LOUD, ("Rate down, RPT Timing default\n"));
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- ("RAWaitingCounter %d, RAPendingCounter %d",
- pRaInfo->RAWaitingCounter, pRaInfo->RAPendingCounter));
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
- ("Rate down to RateID %d RateSGI %d\n", RateID, pRaInfo->RateSGI));
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- ("<===== %s()\n", __func__));
return 0;
}
@@ -176,18 +157,11 @@ static int odm_RateUp_8188E(struct odm_dm_struct *dm_odm,
u8 RateID, HighestRate;
u8 i;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE,
- ODM_DBG_TRACE, ("=====>%s()\n", __func__));
- if (!pRaInfo) {
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
- ("%s(): pRaInfo is NULL\n", __func__));
+ if (!pRaInfo)
return -1;
- }
+
RateID = pRaInfo->PreRate;
HighestRate = pRaInfo->HighestRate;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- (" RateID =%d HighestRate =%d\n",
- RateID, HighestRate));
if (pRaInfo->RAWaitingCounter == 1) {
pRaInfo->RAWaitingCounter = 0;
pRaInfo->RAPendingCounter = 0;
@@ -196,8 +170,6 @@ static int odm_RateUp_8188E(struct odm_dm_struct *dm_odm,
goto RateUpfinish;
}
odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 0);
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
- ("%s():Decrease RPT Timing\n", __func__));
if (RateID < HighestRate) {
for (i = RateID + 1; i <= HighestRate; i++) {
@@ -222,13 +194,6 @@ RateUpfinish:
pRaInfo->RAWaitingCounter++;
pRaInfo->DecisionRate = RateID;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
- ("Rate up to RateID %d\n", RateID));
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- ("RAWaitingCounter %d, RAPendingCounter %d",
- pRaInfo->RAWaitingCounter, pRaInfo->RAPendingCounter));
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE,
- ODM_DBG_TRACE, ("<===== %s()\n", __func__));
return 0;
}
@@ -250,9 +215,6 @@ static void odm_RateDecision_8188E(struct odm_dm_struct *dm_odm,
/* u32 pool_retry; */
static u8 DynamicTxRPTTimingCounter;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- ("=====>%s()\n", __func__));
-
if (pRaInfo->Active && (pRaInfo->TOTAL > 0)) { /* STA used and data packet exits */
if ((pRaInfo->RssiStaRA < (pRaInfo->PreRssiStaRA - 3)) ||
(pRaInfo->RssiStaRA > (pRaInfo->PreRssiStaRA + 3))) {
@@ -270,16 +232,9 @@ static void odm_RateDecision_8188E(struct odm_dm_struct *dm_odm,
RtyPtID = 1;
PenaltyID1 = RETRY_PENALTY_IDX[RtyPtID][RateID]; /* TODO by page */
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- (" NscDown init is %d\n", pRaInfo->NscDown));
-
for (i = 0 ; i <= 4 ; i++)
pRaInfo->NscDown += pRaInfo->RTY[i] * RETRY_PENALTY[PenaltyID1][i];
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- (" NscDown is %d, total*penalty[5] is %d\n", pRaInfo->NscDown,
- (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5])));
-
if (pRaInfo->NscDown > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5]))
pRaInfo->NscDown -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5];
else
@@ -287,24 +242,15 @@ static void odm_RateDecision_8188E(struct odm_dm_struct *dm_odm,
/* rate up */
PenaltyID2 = RETRY_PENALTY_UP_IDX[RateID];
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- (" NscUp init is %d\n", pRaInfo->NscUp));
for (i = 0 ; i <= 4 ; i++)
pRaInfo->NscUp += pRaInfo->RTY[i] * RETRY_PENALTY[PenaltyID2][i];
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- ("NscUp is %d, total*up[5] is %d\n",
- pRaInfo->NscUp, (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5])));
-
if (pRaInfo->NscUp > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5]))
pRaInfo->NscUp -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5];
else
pRaInfo->NscUp = 0;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE | ODM_COMP_INIT, ODM_DBG_LOUD,
- (" RssiStaRa = %d RtyPtID =%d PenaltyID1 = 0x%x PenaltyID2 = 0x%x RateID =%d NscDown =%d NscUp =%d SGI =%d\n",
- pRaInfo->RssiStaRA, RtyPtID, PenaltyID1, PenaltyID2, RateID, pRaInfo->NscDown, pRaInfo->NscUp, pRaInfo->RateSGI));
if ((pRaInfo->NscDown < N_THRESHOLD_LOW[RateID]) ||
(pRaInfo->DROP > DROPING_NECESSARY[RateID]))
odm_RateDown_8188E(dm_odm, pRaInfo);
@@ -321,8 +267,6 @@ static void odm_RateDecision_8188E(struct odm_dm_struct *dm_odm,
if (DynamicTxRPTTimingCounter >= 4) {
odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 1);
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE,
- ODM_DBG_LOUD, ("<===== Rate don't change 4 times, Extend RPT Timing\n"));
DynamicTxRPTTimingCounter = 0;
}
@@ -330,8 +274,6 @@ static void odm_RateDecision_8188E(struct odm_dm_struct *dm_odm,
odm_ResetRaCounter_8188E(pRaInfo);
}
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- ("<===== %s()\n", __func__));
}
static int odm_ARFBRefresh_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_info *pRaInfo)
@@ -414,15 +356,9 @@ static int odm_ARFBRefresh_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_inf
else
pRaInfo->PTModeSS = 0;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
- ("ODM_ARFBRefresh_8188E(): PTModeSS =%d\n", pRaInfo->PTModeSS));
-
if (pRaInfo->DecisionRate > pRaInfo->HighestRate)
pRaInfo->DecisionRate = pRaInfo->HighestRate;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
- ("ODM_ARFBRefresh_8188E(): RateID =%d RateMask =%8.8x RAUseRate =%8.8x HighestRate =%d, DecisionRate =%d\n",
- pRaInfo->RateID, pRaInfo->RateMask, pRaInfo->RAUseRate, pRaInfo->HighestRate, pRaInfo->DecisionRate));
return 0;
}
@@ -518,17 +454,10 @@ static void odm_PTDecision_8188E(struct odm_ra_info *pRaInfo)
static void odm_RATxRPTTimerSetting(struct odm_dm_struct *dm_odm,
u16 minRptTime)
{
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- (" =====>%s()\n", __func__));
-
if (dm_odm->CurrminRptTime != minRptTime) {
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
- (" CurrminRptTime = 0x%04x minRptTime = 0x%04x\n", dm_odm->CurrminRptTime, minRptTime));
rtw_rpt_timer_cfg_cmd(dm_odm->Adapter, minRptTime);
dm_odm->CurrminRptTime = minRptTime;
}
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- (" <===== %s()\n", __func__));
}
int ODM_RAInfo_Init(struct odm_dm_struct *dm_odm, u8 macid)
@@ -549,10 +478,6 @@ int ODM_RAInfo_Init(struct odm_dm_struct *dm_odm, u8 macid)
max_rate_idx = 0x03;
}
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
- ("%s(): WirelessMode:0x%08x , max_raid_idx:0x%02x\n",
- __func__, WirelessMode, max_rate_idx));
-
pRaInfo->DecisionRate = max_rate_idx;
pRaInfo->PreRate = max_rate_idx;
pRaInfo->HighestRate = max_rate_idx;
@@ -593,7 +518,6 @@ int ODM_RAInfo_Init_all(struct odm_dm_struct *dm_odm)
{
u8 macid = 0;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>\n"));
dm_odm->CurrminRptTime = 0;
for (macid = 0; macid < ODM_ASSOCIATE_ENTRY_NUM; macid++)
@@ -606,8 +530,6 @@ u8 ODM_RA_GetShortGI_8188E(struct odm_dm_struct *dm_odm, u8 macid)
{
if ((!dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
return 0;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- ("macid =%d SGI =%d\n", macid, dm_odm->RAInfo[macid].RateSGI));
return dm_odm->RAInfo[macid].RateSGI;
}
@@ -618,8 +540,6 @@ u8 ODM_RA_GetDecisionRate_8188E(struct odm_dm_struct *dm_odm, u8 macid)
if ((!dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
return 0;
DecisionRate = dm_odm->RAInfo[macid].DecisionRate;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- (" macid =%d DecisionRate = 0x%x\n", macid, DecisionRate));
return DecisionRate;
}
@@ -630,8 +550,6 @@ u8 ODM_RA_GetHwPwrStatus_8188E(struct odm_dm_struct *dm_odm, u8 macid)
if ((!dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
return 0;
PTStage = dm_odm->RAInfo[macid].PTStage;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- ("macid =%d PTStage = 0x%x\n", macid, PTStage));
return PTStage;
}
@@ -641,9 +559,6 @@ void ODM_RA_UpdateRateInfo_8188E(struct odm_dm_struct *dm_odm, u8 macid, u8 Rate
if ((!dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
return;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
- ("macid =%d RateID = 0x%x RateMask = 0x%x SGIEnable =%d\n",
- macid, RateID, RateMask, SGIEnable));
pRaInfo = &dm_odm->RAInfo[macid];
pRaInfo->RateID = RateID;
@@ -658,8 +573,6 @@ void ODM_RA_SetRSSI_8188E(struct odm_dm_struct *dm_odm, u8 macid, u8 Rssi)
if ((!dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
return;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
- (" macid =%d Rssi =%d\n", macid, Rssi));
pRaInfo = &dm_odm->RAInfo[macid];
pRaInfo->RssiStaRA = Rssi;
@@ -680,10 +593,6 @@ void ODM_RA_TxRPT2Handle_8188E(struct odm_dm_struct *dm_odm, u8 *TxRPT_Buf, u16
u32 valid = 0, ItemNum = 0;
u16 minRptTime = 0x927c;
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
- ("=====>%s(): valid0 =%d valid1 =%d BufferLength =%d\n",
- __func__, macid_entry0, macid_entry1, TxRPT_Len));
-
ItemNum = TxRPT_Len >> 3;
pBuffer = TxRPT_Buf;
@@ -707,13 +616,6 @@ void ODM_RA_TxRPT2Handle_8188E(struct odm_dm_struct *dm_odm, u8 *TxRPT_Buf, u16
pRAInfo->RTY[2] + pRAInfo->RTY[3] +
pRAInfo->RTY[4] + pRAInfo->DROP;
if (pRAInfo->TOTAL != 0) {
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
- ("macid =%d Total =%d R0 =%d R1 =%d R2 =%d R3 =%d R4 =%d D0 =%d valid0 =%x valid1 =%x\n",
- MacId, pRAInfo->TOTAL,
- pRAInfo->RTY[0], pRAInfo->RTY[1],
- pRAInfo->RTY[2], pRAInfo->RTY[3],
- pRAInfo->RTY[4], pRAInfo->DROP,
- macid_entry0, macid_entry1));
if (pRAInfo->PTActive) {
if (pRAInfo->RAstage < 5)
odm_RateDecision_8188E(dm_odm, pRAInfo);
@@ -730,20 +632,6 @@ void ODM_RA_TxRPT2Handle_8188E(struct odm_dm_struct *dm_odm, u8 *TxRPT_Buf, u16
} else {
odm_RateDecision_8188E(dm_odm, pRAInfo);
}
- ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD,
- ("macid =%d R0 =%d R1 =%d R2 =%d R3 =%d R4 =%d drop =%d valid0 =%x RateID =%d SGI =%d\n",
- MacId,
- pRAInfo->RTY[0],
- pRAInfo->RTY[1],
- pRAInfo->RTY[2],
- pRAInfo->RTY[3],
- pRAInfo->RTY[4],
- pRAInfo->DROP,
- macid_entry0,
- pRAInfo->DecisionRate,
- pRAInfo->RateSGI));
- } else {
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, (" TOTAL = 0!!!!\n"));
}
}
@@ -755,7 +643,4 @@ void ODM_RA_TxRPT2Handle_8188E(struct odm_dm_struct *dm_odm, u8 *TxRPT_Buf, u16
} while (MacId < ItemNum);
odm_RATxRPTTimerSetting(dm_odm, minRptTime);
-
- ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
- ("<===== %s()\n", __func__));
}
diff --git a/drivers/staging/rtl8188eu/hal/hal_intf.c b/drivers/staging/rtl8188eu/hal/hal_intf.c
index 9585dffc63a3..f09620c54e69 100644
--- a/drivers/staging/rtl8188eu/hal/hal_intf.c
+++ b/drivers/staging/rtl8188eu/hal/hal_intf.c
@@ -23,12 +23,8 @@ uint rtw_hal_init(struct adapter *adapt)
rtw_hal_notch_filter(adapt, 1);
} else {
adapt->hw_init_completed = false;
- DBG_88E("%s: hal__init fail\n", __func__);
}
- RT_TRACE(_module_hal_init_c_, _drv_err_,
- ("-rtl871x_hal_init:status=0x%x\n", status));
-
return status;
}
@@ -40,8 +36,6 @@ uint rtw_hal_deinit(struct adapter *adapt)
if (status == _SUCCESS)
adapt->hw_init_completed = false;
- else
- DBG_88E("\n %s: hal_init fail\n", __func__);
return status;
}
diff --git a/drivers/staging/rtl8188eu/hal/odm.c b/drivers/staging/rtl8188eu/hal/odm.c
index 4d659a812aed..ffc5394d5bb9 100644
--- a/drivers/staging/rtl8188eu/hal/odm.c
+++ b/drivers/staging/rtl8188eu/hal/odm.c
@@ -5,11 +5,11 @@
*
******************************************************************************/
+#include <linux/etherdevice.h>
+
#include "odm_precomp.h"
#include "phy.h"
-u32 GlobalDebugLevel;
-
/* avoid to warn in FreeBSD ==> To DO modify */
static u32 EDCAParam[HT_IOT_PEER_MAX][3] = {
/* UL DL */
@@ -147,13 +147,6 @@ u8 CCKSwingTable_Ch14[CCK_TABLE_SIZE][8] = {
#define RxDefaultAnt1 0x65a9
#define RxDefaultAnt2 0x569a
-void ODM_InitDebugSetting(struct odm_dm_struct *pDM_Odm)
-{
- pDM_Odm->DebugLevel = ODM_DBG_TRACE;
-
- pDM_Odm->DebugComponents = 0;
-}
-
/* 3 Export Interface */
/* 2011/09/21 MH Add to describe different team necessary resource allocate?? */
@@ -161,7 +154,6 @@ void ODM_DMInit(struct odm_dm_struct *pDM_Odm)
{
/* 2012.05.03 Luke: For all IC series */
odm_CommonInfoSelfInit(pDM_Odm);
- odm_CmnInfoInit_Debug(pDM_Odm);
odm_DIGInit(pDM_Odm);
odm_RateAdaptiveMaskInit(pDM_Odm);
@@ -181,8 +173,6 @@ void ODM_DMInit(struct odm_dm_struct *pDM_Odm)
void ODM_DMWatchdog(struct odm_dm_struct *pDM_Odm)
{
/* 2012.05.03 Luke: For all IC series */
- odm_CmnInfoHook_Debug(pDM_Odm);
- odm_CmnInfoUpdate_Debug(pDM_Odm);
odm_CommonInfoSelfUpdate(pDM_Odm);
odm_FalseAlarmCounterStatistics(pDM_Odm);
odm_RSSIMonitorCheck(pDM_Odm);
@@ -217,8 +207,6 @@ void odm_CommonInfoSelfInit(struct odm_dm_struct *pDM_Odm)
pDM_Odm->bCckHighPower = (bool)phy_query_bb_reg(adapter, 0x824, BIT(9));
pDM_Odm->RFPathRxEnable = (u8)phy_query_bb_reg(adapter, 0xc04, 0x0F);
-
- ODM_InitDebugSetting(pDM_Odm);
}
void odm_CommonInfoSelfUpdate(struct odm_dm_struct *pDM_Odm)
@@ -247,48 +235,6 @@ void odm_CommonInfoSelfUpdate(struct odm_dm_struct *pDM_Odm)
pDM_Odm->bOneEntryOnly = false;
}
-void odm_CmnInfoInit_Debug(struct odm_dm_struct *pDM_Odm)
-{
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("%s==>\n", __func__));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportPlatform=%d\n", pDM_Odm->SupportPlatform));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportAbility=0x%x\n", pDM_Odm->SupportAbility));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportInterface=%d\n", pDM_Odm->SupportInterface));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportICType=0x%x\n", pDM_Odm->SupportICType));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("CutVersion=%d\n", pDM_Odm->CutVersion));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("BoardType=%d\n", pDM_Odm->BoardType));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtLNA=%d\n", pDM_Odm->ExtLNA));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtPA=%d\n", pDM_Odm->ExtPA));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtTRSW=%d\n", pDM_Odm->ExtTRSW));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("PatchID=%d\n", pDM_Odm->PatchID));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bInHctTest=%d\n", pDM_Odm->bInHctTest));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFITest=%d\n", pDM_Odm->bWIFITest));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bDualMacSmartConcurrent=%d\n", pDM_Odm->bDualMacSmartConcurrent));
-}
-
-void odm_CmnInfoHook_Debug(struct odm_dm_struct *pDM_Odm)
-{
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("%s==>\n", __func__));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumTxBytesUnicast=%llu\n", *pDM_Odm->pNumTxBytesUnicast));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumRxBytesUnicast=%llu\n", *pDM_Odm->pNumRxBytesUnicast));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pWirelessMode=0x%x\n", *pDM_Odm->pWirelessMode));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecChOffset=%d\n", *pDM_Odm->pSecChOffset));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecurity=%d\n", *pDM_Odm->pSecurity));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pBandWidth=%d\n", *pDM_Odm->pBandWidth));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pChannel=%d\n", *pDM_Odm->pChannel));
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbScanInProcess=%d\n", *pDM_Odm->pbScanInProcess));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbPowerSaving=%d\n", *pDM_Odm->pbPowerSaving));
-}
-
-void odm_CmnInfoUpdate_Debug(struct odm_dm_struct *pDM_Odm)
-{
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("%s==>\n", __func__));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Direct=%d\n", pDM_Odm->bWIFI_Direct));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Display=%d\n", pDM_Odm->bWIFI_Display));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bLinked=%d\n", pDM_Odm->bLinked));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RSSI_Min=%d\n", pDM_Odm->RSSI_Min));
-}
-
void ODM_Write_DIG(struct odm_dm_struct *pDM_Odm, u8 CurrentIGI)
{
struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable;
@@ -339,23 +285,15 @@ void odm_DIG(struct odm_dm_struct *pDM_Odm)
u8 dm_dig_max, dm_dig_min;
u8 CurrentIGI = pDM_DigTable->CurIGValue;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("%s()==>\n", __func__));
- if ((!(pDM_Odm->SupportAbility & ODM_BB_DIG)) || (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT))) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
- ("%s() Return: SupportAbility ODM_BB_DIG or ODM_BB_FA_CNT is disabled\n", __func__));
+ if ((!(pDM_Odm->SupportAbility & ODM_BB_DIG)) || (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT)))
return;
- }
- if (*pDM_Odm->pbScanInProcess) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("%s() Return: In Scan Progress\n", __func__));
+ if (*pDM_Odm->pbScanInProcess)
return;
- }
/* add by Neil Chen to avoid PSD is processing */
- if (!pDM_Odm->bDMInitialGainEnable) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("%s() Return: PSD is Processing\n", __func__));
+ if (!pDM_Odm->bDMInitialGainEnable)
return;
- }
DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0;
FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_0);
@@ -382,33 +320,20 @@ void odm_DIG(struct odm_dm_struct *pDM_Odm)
DIG_Dynamic_MIN = DIG_MaxOfMin;
else
DIG_Dynamic_MIN = pDM_Odm->RSSI_Min;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
- ("%s() : bOneEntryOnly=true, DIG_Dynamic_MIN=0x%x\n",
- __func__, DIG_Dynamic_MIN));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
- ("%s() : pDM_Odm->RSSI_Min=%d\n",
- __func__, pDM_Odm->RSSI_Min));
} else if (pDM_Odm->SupportAbility & ODM_BB_ANT_DIV) {
/* 1 Lower Bound for 88E AntDiv */
- if (pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) {
+ if (pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV)
DIG_Dynamic_MIN = (u8)pDM_DigTable->AntDiv_RSSI_max;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
- ("%s(): pDM_DigTable->AntDiv_RSSI_max=%d\n",
- __func__, pDM_DigTable->AntDiv_RSSI_max));
- }
} else {
DIG_Dynamic_MIN = dm_dig_min;
}
} else {
pDM_DigTable->rx_gain_range_max = dm_dig_max;
DIG_Dynamic_MIN = dm_dig_min;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("%s() : No Link\n", __func__));
}
/* 1 Modify DIG lower bound, deal with abnormally large false alarm */
if (pFalseAlmCnt->Cnt_all > 10000) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("dm_DIG(): Abnormally false alarm case.\n"));
-
if (pDM_DigTable->LargeFAHit != 3)
pDM_DigTable->LargeFAHit++;
if (pDM_DigTable->ForbiddenIGI < CurrentIGI) {
@@ -433,27 +358,20 @@ void odm_DIG(struct odm_dm_struct *pDM_Odm)
if ((pDM_DigTable->ForbiddenIGI - 1) < DIG_Dynamic_MIN) { /* DM_DIG_MIN) */
pDM_DigTable->ForbiddenIGI = DIG_Dynamic_MIN; /* DM_DIG_MIN; */
pDM_DigTable->rx_gain_range_min = DIG_Dynamic_MIN; /* DM_DIG_MIN; */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("%s(): Normal Case: At Lower Bound\n", __func__));
} else {
pDM_DigTable->ForbiddenIGI--;
pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("%s(): Normal Case: Approach Lower Bound\n", __func__));
}
} else {
pDM_DigTable->LargeFAHit = 0;
}
}
}
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
- ("%s(): pDM_DigTable->LargeFAHit=%d\n",
- __func__, pDM_DigTable->LargeFAHit));
/* 1 Adjust initial gain by false alarm */
if (pDM_Odm->bLinked) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("%s(): DIG AfterLink\n", __func__));
if (FirstConnect) {
CurrentIGI = pDM_Odm->RSSI_Min;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("DIG: First Connect\n"));
} else {
if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2)
CurrentIGI = CurrentIGI + 4;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */
@@ -463,10 +381,8 @@ void odm_DIG(struct odm_dm_struct *pDM_Odm)
CurrentIGI = CurrentIGI - 2;/* pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; */
}
} else {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("%s(): DIG BeforeLink\n", __func__));
if (FirstDisConnect) {
CurrentIGI = pDM_DigTable->rx_gain_range_min;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("%s(): First DisConnect\n", __func__));
} else {
/* 2012.03.30 LukeLee: enable DIG before link but with very high thresholds */
if (pFalseAlmCnt->Cnt_all > 10000)
@@ -475,24 +391,15 @@ void odm_DIG(struct odm_dm_struct *pDM_Odm)
CurrentIGI = CurrentIGI + 1;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */
else if (pFalseAlmCnt->Cnt_all < 500)
CurrentIGI = CurrentIGI - 1;/* pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("%s(): England DIG\n", __func__));
}
}
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("%s(): DIG End Adjust IGI\n", __func__));
/* 1 Check initial gain by upper/lower bound */
if (CurrentIGI > pDM_DigTable->rx_gain_range_max)
CurrentIGI = pDM_DigTable->rx_gain_range_max;
if (CurrentIGI < pDM_DigTable->rx_gain_range_min)
CurrentIGI = pDM_DigTable->rx_gain_range_min;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
- ("%s(): rx_gain_range_max=0x%x, rx_gain_range_min=0x%x\n",
- __func__, pDM_DigTable->rx_gain_range_max, pDM_DigTable->rx_gain_range_min));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("%s(): TotalFA=%d\n", __func__, pFalseAlmCnt->Cnt_all));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("%s(): CurIGValue=0x%x\n", __func__, CurrentIGI));
-
/* 2 High power RSSI threshold */
-
ODM_Write_DIG(pDM_Odm, CurrentIGI);/* ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); */
pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked;
pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN;
@@ -556,20 +463,6 @@ void odm_FalseAlarmCounterStatistics(struct odm_dm_struct *pDM_Odm)
FalseAlmCnt->Cnt_Cck_fail);
FalseAlmCnt->Cnt_CCA_all = FalseAlmCnt->Cnt_OFDM_CCA + FalseAlmCnt->Cnt_CCK_CCA;
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Enter %s\n", __func__));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD,
- ("Cnt_Fast_Fsync=%d, Cnt_SB_Search_fail=%d\n",
- FalseAlmCnt->Cnt_Fast_Fsync, FalseAlmCnt->Cnt_SB_Search_fail));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD,
- ("Cnt_Parity_Fail=%d, Cnt_Rate_Illegal=%d\n",
- FalseAlmCnt->Cnt_Parity_Fail, FalseAlmCnt->Cnt_Rate_Illegal));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD,
- ("Cnt_Crc8_fail=%d, Cnt_Mcs_fail=%d\n",
- FalseAlmCnt->Cnt_Crc8_fail, FalseAlmCnt->Cnt_Mcs_fail));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Cck_fail=%d\n", FalseAlmCnt->Cnt_Cck_fail));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Ofdm_fail=%d\n", FalseAlmCnt->Cnt_Ofdm_fail));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Total False Alarm=%d\n", FalseAlmCnt->Cnt_all));
}
/* 3============================================================ */
@@ -750,10 +643,6 @@ u32 ODM_Get_Rate_Bitmap(struct odm_dm_struct *pDM_Odm, u32 macid, u32 ra_mask, u
break;
}
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD,
- (" ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x\n",
- rssi_level, WirelessMode, rate_bitmap));
-
return rate_bitmap;
}
@@ -775,26 +664,18 @@ void odm_RefreshRateAdaptiveMaskCE(struct odm_dm_struct *pDM_Odm)
u8 i;
struct adapter *pAdapter = pDM_Odm->Adapter;
- if (pAdapter->bDriverStopped) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("<---- odm_RefreshRateAdaptiveMask(): driver is going to unload\n"));
+ if (pAdapter->bDriverStopped)
return;
- }
- if (!pDM_Odm->bUseRAMask) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("<---- odm_RefreshRateAdaptiveMask(): driver does not control rate adaptive mask\n"));
+ if (!pDM_Odm->bUseRAMask)
return;
- }
for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
struct sta_info *pstat = pDM_Odm->pODM_StaInfo[i];
if (IS_STA_VALID(pstat)) {
- if (ODM_RAStateCheck(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, false, &pstat->rssi_level)) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD,
- ("RSSI:%d, RSSI_LEVEL:%d\n",
- pstat->rssi_stat.UndecoratedSmoothedPWDB, pstat->rssi_level));
+ if (ODM_RAStateCheck(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, false, &pstat->rssi_level))
rtw_hal_update_ra_mask(pAdapter, i, pstat->rssi_level);
- }
}
}
}
@@ -808,6 +689,7 @@ bool ODM_RAStateCheck(struct odm_dm_struct *pDM_Odm, s32 RSSI, bool bForceUpdate
u8 HighRSSIThreshForRA = pRA->HighRSSIThresh;
u8 LowRSSIThreshForRA = pRA->LowRSSIThresh;
u8 RATRState;
+ struct device *dev = dvobj_to_dev(adapter_to_dvobj(pDM_Odm->Adapter));
/* Threshold Adjustment: */
/* when RSSI state trends to go up one or two levels, make sure RSSI is high enough. */
@@ -824,7 +706,7 @@ bool ODM_RAStateCheck(struct odm_dm_struct *pDM_Odm, s32 RSSI, bool bForceUpdate
LowRSSIThreshForRA += GoUpGap;
break;
default:
- ODM_RT_ASSERT(pDM_Odm, false, ("wrong rssi level setting %d !", *pRATRState));
+ dev_err(dev, "%s(): wrong rssi level setting %d!\n", __func__, *pRATRState);
break;
}
@@ -837,7 +719,6 @@ bool ODM_RAStateCheck(struct odm_dm_struct *pDM_Odm, s32 RSSI, bool bForceUpdate
RATRState = DM_RATR_STA_LOW;
if (*pRATRState != RATRState || bForceUpdate) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI Level %d -> %d\n", *pRATRState, RATRState));
*pRATRState = RATRState;
return true;
}
@@ -892,7 +773,6 @@ void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm)
u8 sta_cnt = 0;
u32 PWDB_rssi[NUM_STA] = {0};/* 0~15]:MACID, [16~31]:PWDB_rssi */
struct sta_info *psta;
- u8 bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
if (!check_fwstate(&Adapter->mlmepriv, _FW_LINKED))
return;
@@ -901,7 +781,7 @@ void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm)
psta = pDM_Odm->pODM_StaInfo[i];
if (IS_STA_VALID(psta) &&
(psta->state & WIFI_ASOC_STATE) &&
- memcmp(psta->hwaddr, bcast_addr, ETH_ALEN) &&
+ !is_broadcast_ether_addr(psta->hwaddr) &&
memcmp(psta->hwaddr, myid(&Adapter->eeprompriv), ETH_ALEN)) {
if (psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB)
tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB;
@@ -945,7 +825,6 @@ void odm_TXPowerTrackingInit(struct odm_dm_struct *pDM_Odm)
pDM_Odm->RFCalibrateInfo.TXPowercount = 0;
if (*pDM_Odm->mp_mode != 1)
pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true;
- MSG_88E("pDM_Odm TxPowerTrackControl = %d\n", pDM_Odm->RFCalibrateInfo.TxPowerTrackControl);
pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true;
}
@@ -977,20 +856,16 @@ void ODM_TXPowerTrackingCheck(struct odm_dm_struct *pDM_Odm)
void odm_InitHybridAntDiv(struct odm_dm_struct *pDM_Odm)
{
- if (!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Return: Not Support HW AntDiv\n"));
+ if (!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV))
return;
- }
rtl88eu_dm_antenna_div_init(pDM_Odm);
}
void odm_HwAntDiv(struct odm_dm_struct *pDM_Odm)
{
- if (!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Return: Not Support HW AntDiv\n"));
+ if (!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV))
return;
- }
rtl88eu_dm_antenna_diversity(pDM_Odm);
}
@@ -1003,11 +878,6 @@ void ODM_EdcaTurboInit(struct odm_dm_struct *pDM_Odm)
pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false;
pDM_Odm->DM_EDCA_Table.bIsCurRDLState = false;
Adapter->recvpriv.bIsAnyNonBEPkts = false;
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Original VO PARAM: 0x%x\n", usb_read32(Adapter, ODM_EDCA_VO_PARAM)));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Original VI PARAM: 0x%x\n", usb_read32(Adapter, ODM_EDCA_VI_PARAM)));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Original BE PARAM: 0x%x\n", usb_read32(Adapter, ODM_EDCA_BE_PARAM)));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Original BK PARAM: 0x%x\n", usb_read32(Adapter, ODM_EDCA_BK_PARAM)));
} /* ODM_InitEdcaTurbo */
void odm_EdcaTurboCheck(struct odm_dm_struct *pDM_Odm)
@@ -1015,13 +885,10 @@ void odm_EdcaTurboCheck(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_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("%s========================>\n", __func__));
-
if (!(pDM_Odm->SupportAbility & ODM_MAC_EDCA_TURBO))
return;
odm_EdcaTurboCheckCE(pDM_Odm);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("<========================%s\n", __func__));
} /* odm_CheckEdcaTurbo */
void odm_EdcaTurboCheckCE(struct odm_dm_struct *pDM_Odm)
diff --git a/drivers/staging/rtl8188eu/hal/odm_rtl8188e.c b/drivers/staging/rtl8188eu/hal/odm_rtl8188e.c
index a55a0d8b9fb7..e29cd35a5811 100644
--- a/drivers/staging/rtl8188eu/hal/odm_rtl8188e.c
+++ b/drivers/staging/rtl8188eu/hal/odm_rtl8188e.c
@@ -307,11 +307,7 @@ void rtl88eu_dm_antenna_diversity(struct odm_dm_struct *dm_odm)
return;
if (!dm_odm->bLinked) {
- ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
- ("ODM_AntennaDiversity_88E(): No Link.\n"));
if (dm_fat_tbl->bBecomeLinked) {
- ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
- ("Need to Turn off HW AntDiv\n"));
phy_set_bb_reg(adapter, ODM_REG_IGI_A_11N, BIT(7), 0);
phy_set_bb_reg(adapter, ODM_REG_CCK_ANTDIV_PARA1_11N,
BIT(15), 0);
@@ -324,8 +320,6 @@ void rtl88eu_dm_antenna_diversity(struct odm_dm_struct *dm_odm)
}
if (!dm_fat_tbl->bBecomeLinked) {
- ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
- ("Need to Turn on HW AntDiv\n"));
phy_set_bb_reg(adapter, ODM_REG_IGI_A_11N, BIT(7), 1);
phy_set_bb_reg(adapter, ODM_REG_CCK_ANTDIV_PARA1_11N,
BIT(15), 1);
diff --git a/drivers/staging/rtl8188eu/hal/phy.c b/drivers/staging/rtl8188eu/hal/phy.c
index a664bff370bb..256f87b9d630 100644
--- a/drivers/staging/rtl8188eu/hal/phy.c
+++ b/drivers/staging/rtl8188eu/hal/phy.c
@@ -162,18 +162,6 @@ static void get_tx_power_index(struct adapter *adapt, u8 channel, u8 *cck_pwr,
}
}
-static void phy_power_index_check(struct adapter *adapt, u8 channel,
- u8 *cck_pwr, u8 *ofdm_pwr, u8 *bw20_pwr,
- u8 *bw40_pwr)
-{
- struct hal_data_8188e *hal_data = adapt->HalData;
-
- hal_data->CurrentCckTxPwrIdx = cck_pwr[0];
- hal_data->CurrentOfdm24GTxPwrIdx = ofdm_pwr[0];
- hal_data->CurrentBW2024GTxPwrIdx = bw20_pwr[0];
- hal_data->CurrentBW4024GTxPwrIdx = bw40_pwr[0];
-}
-
void phy_set_tx_power_level(struct adapter *adapt, u8 channel)
{
u8 cck_pwr[MAX_TX_COUNT] = {0};
@@ -184,9 +172,6 @@ void phy_set_tx_power_level(struct adapter *adapt, u8 channel)
get_tx_power_index(adapt, channel, &cck_pwr[0], &ofdm_pwr[0],
&bw20_pwr[0], &bw40_pwr[0]);
- phy_power_index_check(adapt, channel, &cck_pwr[0], &ofdm_pwr[0],
- &bw20_pwr[0], &bw40_pwr[0]);
-
rtl88eu_phy_rf6052_set_cck_txpower(adapt, &cck_pwr[0]);
rtl88eu_phy_rf6052_set_ofdm_txpower(adapt, &ofdm_pwr[0], &bw20_pwr[0],
&bw40_pwr[0], channel);
@@ -303,10 +288,6 @@ void rtl88eu_dm_txpower_track_adjust(struct odm_dm_struct *dm_odm, u8 type,
u8 pwr_value = 0;
/* Tx power tracking BB swing table. */
if (type == 0) { /* For OFDM adjust */
- ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
- ("BbSwingIdxOfdm = %d BbSwingFlagOfdm=%d\n",
- dm_odm->BbSwingIdxOfdm, dm_odm->BbSwingFlagOfdm));
-
if (dm_odm->BbSwingIdxOfdm <= dm_odm->BbSwingIdxOfdmBase) {
*direction = 1;
pwr_value = dm_odm->BbSwingIdxOfdmBase -
@@ -316,12 +297,7 @@ void rtl88eu_dm_txpower_track_adjust(struct odm_dm_struct *dm_odm, u8 type,
pwr_value = dm_odm->BbSwingIdxOfdm -
dm_odm->BbSwingIdxOfdmBase;
}
-
} else if (type == 1) { /* For CCK adjust. */
- ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
- ("dm_odm->BbSwingIdxCck = %d dm_odm->BbSwingIdxCckBase = %d\n",
- dm_odm->BbSwingIdxCck, dm_odm->BbSwingIdxCckBase));
-
if (dm_odm->BbSwingIdxCck <= dm_odm->BbSwingIdxCckBase) {
*direction = 1;
pwr_value = dm_odm->BbSwingIdxCckBase -
@@ -343,8 +319,6 @@ void rtl88eu_dm_txpower_track_adjust(struct odm_dm_struct *dm_odm, u8 type,
static void dm_txpwr_track_setpwr(struct odm_dm_struct *dm_odm)
{
if (dm_odm->BbSwingFlagOfdm || dm_odm->BbSwingFlagCck) {
- ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
- ("%s CH=%d\n", __func__, *dm_odm->pChannel));
phy_set_tx_power_level(dm_odm->Adapter, *dm_odm->pChannel);
dm_odm->BbSwingFlagOfdm = false;
dm_odm->BbSwingFlagCck = false;
@@ -557,7 +531,6 @@ static u8 phy_path_a_rx_iqk(struct adapter *adapt, bool configPathB)
{
u32 reg_eac, reg_e94, reg_e9c, reg_ea4, u4tmp;
u8 result = 0x00;
- struct odm_dm_struct *dm_odm = &adapt->HalData->odmpriv;
/* 1 Get TXIMR setting */
/* modify RXIQK mode table */
@@ -610,8 +583,6 @@ static u8 phy_path_a_rx_iqk(struct adapter *adapt, bool configPathB)
/* 1 RX IQK */
/* modify RXIQK mode table */
- ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
- ("Path-A Rx IQK modify RXIQK mode table 2!\n"));
phy_set_bb_reg(adapt, rFPGA0_IQK, bMaskDWord, 0x00000000);
phy_set_rf_reg(adapt, RF_PATH_A, RF_WE_LUT, bRFRegOffsetMask, 0x800a0);
phy_set_rf_reg(adapt, RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x30000);
@@ -650,9 +621,6 @@ static u8 phy_path_a_rx_iqk(struct adapter *adapt, bool configPathB)
(((reg_ea4 & 0x03FF0000) >> 16) != 0x132) &&
(((reg_eac & 0x03FF0000) >> 16) != 0x36))
result |= 0x02;
- else
- ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
- ("Path A Rx IQK fail!!\n"));
return result;
}
@@ -661,7 +629,6 @@ static u8 phy_path_b_iqk(struct adapter *adapt)
{
u32 regeac, regeb4, regebc, regec4, regecc;
u8 result = 0x00;
- struct odm_dm_struct *dm_odm = &adapt->HalData->odmpriv;
/* One shot, path B LOK & IQK */
phy_set_bb_reg(adapt, rIQK_AGC_Cont, bMaskDWord, 0x00000002);
@@ -686,9 +653,7 @@ static u8 phy_path_b_iqk(struct adapter *adapt)
(((regec4 & 0x03FF0000) >> 16) != 0x132) &&
(((regecc & 0x03FF0000) >> 16) != 0x36))
result |= 0x02;
- else
- ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION,
- ODM_DBG_LOUD, ("Path B Rx IQK fail!!\n"));
+
return result;
}
@@ -1055,13 +1020,6 @@ static void phy_iq_calibrate(struct adapter *adapt, s32 result[][8],
bMaskDWord) & 0x3FF0000) >> 16;
break;
}
- ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
- ("Path A Rx IQK Fail!!\n"));
- }
-
- if (path_a_ok == 0x00) {
- ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
- ("Path A IQK failed!!\n"));
}
if (is2t) {
@@ -1089,11 +1047,6 @@ static void phy_iq_calibrate(struct adapter *adapt, s32 result[][8],
bMaskDWord) & 0x3FF0000) >> 16;
}
}
-
- if (path_b_ok == 0x00) {
- ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
- ("Path B IQK failed!!\n"));
- }
}
/* Back to BB mode, load original value */
@@ -1214,8 +1167,6 @@ void rtl88eu_phy_iq_calibrate(struct adapter *adapt, bool recovery)
return;
if (recovery) {
- ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD,
- ("phy_iq_calibrate: Return due to recovery!\n"));
reload_adda_reg(adapt, iqk_bb_reg_92c,
dm_odm->RFCalibrateInfo.IQK_BB_backup_recover, 9);
return;
@@ -1280,8 +1231,6 @@ void rtl88eu_phy_iq_calibrate(struct adapter *adapt, bool recovery)
pathaok = true;
pathbok = true;
} else {
- ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
- ("IQK: FAIL use default value\n"));
dm_odm->RFCalibrateInfo.RegE94 = 0x100;
dm_odm->RFCalibrateInfo.RegEB4 = 0x100;
dm_odm->RFCalibrateInfo.RegE9C = 0x0;
diff --git a/drivers/staging/rtl8188eu/hal/pwrseqcmd.c b/drivers/staging/rtl8188eu/hal/pwrseqcmd.c
index 34784943a7d1..cec2ff879f5d 100644
--- a/drivers/staging/rtl8188eu/hal/pwrseqcmd.c
+++ b/drivers/staging/rtl8188eu/hal/pwrseqcmd.c
@@ -25,27 +25,12 @@ u8 rtl88eu_pwrseqcmdparsing(struct adapter *padapter, u8 cut_vers,
do {
pwrcfgcmd = pwrseqcmd[aryidx];
- RT_TRACE(_module_hal_init_c_, _drv_info_,
- ("%s: offset(%#x) cut_msk(%#x)"
- " cmd(%#x)"
- "msk(%#x) value(%#x)\n",
- __func__,
- GET_PWR_CFG_OFFSET(pwrcfgcmd),
- GET_PWR_CFG_CUT_MASK(pwrcfgcmd),
- GET_PWR_CFG_CMD(pwrcfgcmd),
- GET_PWR_CFG_MASK(pwrcfgcmd),
- GET_PWR_CFG_VALUE(pwrcfgcmd)));
-
/* Only Handle the command whose CUT is matched */
if (GET_PWR_CFG_CUT_MASK(pwrcfgcmd) & cut_vers) {
switch (GET_PWR_CFG_CMD(pwrcfgcmd)) {
case PWR_CMD_READ:
- RT_TRACE(_module_hal_init_c_, _drv_info_,
- ("%s: PWR_CMD_READ\n", __func__));
break;
case PWR_CMD_WRITE:
- RT_TRACE(_module_hal_init_c_, _drv_info_,
- ("%s: PWR_CMD_WRITE\n", __func__));
offset = GET_PWR_CFG_OFFSET(pwrcfgcmd);
/* Read the value from system register */
@@ -59,9 +44,6 @@ u8 rtl88eu_pwrseqcmdparsing(struct adapter *padapter, u8 cut_vers,
usb_write8(padapter, offset, value);
break;
case PWR_CMD_POLLING:
- RT_TRACE(_module_hal_init_c_, _drv_info_,
- ("%s: PWR_CMD_POLLING\n", __func__));
-
poll_bit = false;
offset = GET_PWR_CFG_OFFSET(pwrcfgcmd);
do {
@@ -74,15 +56,11 @@ u8 rtl88eu_pwrseqcmdparsing(struct adapter *padapter, u8 cut_vers,
else
udelay(10);
- if (poll_count++ > max_poll_count) {
- DBG_88E("Fail to polling Offset[%#x]\n", offset);
+ if (poll_count++ > max_poll_count)
return false;
- }
} while (!poll_bit);
break;
case PWR_CMD_DELAY:
- RT_TRACE(_module_hal_init_c_, _drv_info_,
- ("%s: PWR_CMD_DELAY\n", __func__));
if (GET_PWR_CFG_VALUE(pwrcfgcmd) == PWRSEQ_DELAY_US)
udelay(GET_PWR_CFG_OFFSET(pwrcfgcmd));
else
@@ -90,12 +68,8 @@ u8 rtl88eu_pwrseqcmdparsing(struct adapter *padapter, u8 cut_vers,
break;
case PWR_CMD_END:
/* When this command is parsed, end the process */
- RT_TRACE(_module_hal_init_c_, _drv_info_,
- ("%s: PWR_CMD_END\n", __func__));
return true;
default:
- RT_TRACE(_module_hal_init_c_, _drv_err_,
- ("%s: Unknown CMD!!\n", __func__));
break;
}
}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
index 3a0e3d41a404..f2969e160ac3 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
@@ -55,11 +55,8 @@ static s32 FillH2CCmd_88E(struct adapter *adapt, u8 ElementID, u32 CmdLen, u8 *p
u32 h2c_cmd_ex = 0;
s32 ret = _FAIL;
- if (!adapt->bFWReady) {
- DBG_88E("%s(): return H2C cmd because fw is not ready\n",
- __func__);
+ if (!adapt->bFWReady)
return ret;
- }
if (!pCmdBuffer)
goto exit;
@@ -71,10 +68,8 @@ static s32 FillH2CCmd_88E(struct adapter *adapt, u8 ElementID, u32 CmdLen, u8 *p
/* pay attention to if race condition happened in H2C cmd setting. */
h2c_box_num = adapt->HalData->LastHMEBoxNum;
- if (!_is_fw_read_cmd_down(adapt, h2c_box_num)) {
- DBG_88E(" fw read cmd failed...\n");
+ if (!_is_fw_read_cmd_down(adapt, h2c_box_num))
goto exit;
- }
*(u8 *)(&h2c_cmd) = ElementID;
@@ -134,9 +129,6 @@ void rtw_hal_add_ra_tid(struct adapter *pAdapter, u32 bitmap, u8 arg, u8 rssi_le
bitmap &= 0x0fffffff;
- DBG_88E("%s=> mac_id:%d, raid:%d, ra_bitmap=0x%x, shortGIrate=0x%02x\n",
- __func__, macid, raid, bitmap, shortGIrate);
-
ODM_RA_UpdateRateInfo_8188E(odmpriv, macid, raid, bitmap, shortGIrate);
}
@@ -146,9 +138,6 @@ void rtl8188e_set_FwPwrMode_cmd(struct adapter *adapt, u8 Mode)
struct pwrctrl_priv *pwrpriv = &adapt->pwrctrlpriv;
u8 RLBM = 0; /* 0:Min, 1:Max, 2:User define */
- DBG_88E("%s: Mode=%d SmartPS=%d UAPSD=%d\n", __func__,
- Mode, pwrpriv->smart_ps, adapt->registrypriv.uapsd_enable);
-
switch (Mode) {
case PS_MODE_ACTIVE:
H2CSetPwrMode.Mode = 0;
@@ -188,13 +177,8 @@ void rtl8188e_set_FwPwrMode_cmd(struct adapter *adapt, u8 Mode)
void rtl8188e_set_FwMediaStatus_cmd(struct adapter *adapt, __le16 mstatus_rpt)
{
- u8 opmode, macid;
u16 mst_rpt = le16_to_cpu(mstatus_rpt);
- opmode = (u8)mst_rpt;
- macid = (u8)(mst_rpt >> 8);
-
- DBG_88E("### %s: MStatus=%x MACID=%d\n", __func__, opmode, macid);
FillH2CCmd_88E(adapt, H2C_COM_MEDIA_STATUS_RPT, sizeof(mst_rpt), (u8 *)&mst_rpt);
}
@@ -218,7 +202,7 @@ static void ConstructBeacon(struct adapter *adapt, u8 *pframe, u32 *pLength)
ether_addr_copy(pwlanhdr->addr3, cur_network->MacAddress);
SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
- SetFrameSubType(pframe, WIFI_BEACON);
+ SetFrameSubType(pframe, IEEE80211_STYPE_BEACON);
pframe += sizeof(struct ieee80211_hdr_3addr);
pktlen = sizeof(struct ieee80211_hdr_3addr);
@@ -275,10 +259,8 @@ static void ConstructBeacon(struct adapter *adapt, u8 *pframe, u32 *pLength)
_ConstructBeacon:
- if ((pktlen + TXDESC_SIZE) > 512) {
- DBG_88E("beacon frame too large\n");
+ if ((pktlen + TXDESC_SIZE) > 512)
return;
- }
*pLength = pktlen;
}
@@ -297,7 +279,7 @@ static void ConstructPSPoll(struct adapter *adapt, u8 *pframe, u32 *pLength)
fctrl = &pwlanhdr->frame_control;
*(fctrl) = 0;
SetPwrMgt(fctrl);
- SetFrameSubType(pframe, WIFI_PSPOLL);
+ SetFrameSubType(pframe, IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
/* AID. */
SetDuration(pframe, (pmlmeinfo->aid | 0xc000));
@@ -361,7 +343,7 @@ static void ConstructNullFunctionData(struct adapter *adapt, u8 *pframe,
if (bQoS) {
struct ieee80211_qos_hdr *pwlanqoshdr;
- SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
+ SetFrameSubType(pframe, IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC);
pwlanqoshdr = (struct ieee80211_qos_hdr *)pframe;
SetPriority(&pwlanqoshdr->qos_ctrl, AC);
@@ -369,7 +351,7 @@ static void ConstructNullFunctionData(struct adapter *adapt, u8 *pframe,
pktlen = sizeof(struct ieee80211_qos_hdr);
} else {
- SetFrameSubType(pframe, WIFI_DATA_NULL);
+ SetFrameSubType(pframe, IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC);
pktlen = sizeof(struct ieee80211_hdr_3addr);
}
@@ -399,7 +381,7 @@ static void ConstructProbeRsp(struct adapter *adapt, u8 *pframe, u32 *pLength, u
ether_addr_copy(pwlanhdr->addr3, bssid);
SetSeqNum(pwlanhdr, 0);
- SetFrameSubType(fctrl, WIFI_PROBERSP);
+ SetFrameSubType(fctrl, IEEE80211_STYPE_PROBE_RESP);
pktlen = sizeof(struct ieee80211_hdr_3addr);
pframe += pktlen;
@@ -440,12 +422,9 @@ static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
struct rsvdpage_loc RsvdPageLoc;
struct wlan_bssid_ex *pnetwork;
- DBG_88E("%s\n", __func__);
ReservedPagePacket = kzalloc(1000, GFP_KERNEL);
- if (!ReservedPagePacket) {
- DBG_88E("%s: alloc ReservedPagePacket fail!\n", __func__);
+ if (!ReservedPagePacket)
return;
- }
pxmitpriv = &adapt->xmitpriv;
pmlmeext = &adapt->mlmeextpriv;
@@ -466,7 +445,6 @@ static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
if (PageNeed == 1)
PageNeed += 1;
PageNum += PageNeed;
- adapt->HalData->FwRsvdPageStartOffset = PageNum;
BufIndex += PageNeed * 128;
@@ -524,7 +502,6 @@ static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
rtw_hal_mgnt_xmit(adapt, pmgntframe);
- DBG_88E("%s: Set RSVD page location to Fw\n", __func__);
FillH2CCmd_88E(adapt, H2C_COM_RSVD_PAGE, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc);
exit:
@@ -541,8 +518,6 @@ void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus)
u8 DLBcnCount = 0;
u32 poll = 0;
- DBG_88E("%s mstatus(%x)\n", __func__, mstatus);
-
if (mstatus == 1) {
/* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */
/* Suggested by filen. Added by tynli. */
@@ -559,10 +534,8 @@ void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus)
usb_write8(adapt, REG_BCN_CTRL, usb_read8(adapt, REG_BCN_CTRL) & (~BIT(3)));
usb_write8(adapt, REG_BCN_CTRL, usb_read8(adapt, REG_BCN_CTRL) | BIT(4));
- if (haldata->RegFwHwTxQCtrl & BIT(6)) {
- DBG_88E("HalDownloadRSVDPage(): There is an Adapter is sending beacon.\n");
+ if (haldata->RegFwHwTxQCtrl & BIT(6))
bSendBeacon = true;
- }
/* Set FWHW_TXQ_CTRL 0x422[6]=0 to tell Hw the packet is not a real beacon frame. */
usb_write8(adapt, REG_FWHW_TXQ_CTRL + 2, (haldata->RegFwHwTxQCtrl & (~BIT(6))));
@@ -585,12 +558,6 @@ void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus)
} while (!bcn_valid && (poll % 10) != 0 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped);
} while (!bcn_valid && DLBcnCount <= 100 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped);
- if (adapt->bSurpriseRemoved || adapt->bDriverStopped)
- ;
- else if (!bcn_valid)
- DBG_88E("%s: 1 Download RSVD page failed! DLBcnCount:%u, poll:%u\n", __func__, DLBcnCount, poll);
- else
- DBG_88E("%s: 1 Download RSVD success! DLBcnCount:%u, poll:%u\n", __func__, DLBcnCount, poll);
/* */
/* We just can send the reserved page twice during the time that Tx thread is stopped (e.g. pnpsetpower) */
/* because we need to free the Tx BCN Desc which is used by the first reserved page packet. */
@@ -613,10 +580,8 @@ void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus)
}
/* Update RSVD page location H2C to Fw. */
- if (bcn_valid) {
+ if (bcn_valid)
rtw_hal_set_hwreg(adapt, HW_VAR_BCN_VALID, NULL);
- DBG_88E("Set RSVD page location to Fw.\n");
- }
/* Do not enable HW DMA BCN or it will cause Pcie interface hang by timing issue. 2011.11.24. by tynli. */
/* Clear CR[8] or beacon packet will not be send to TxBuf anymore. */
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c b/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
index 391c59490718..10e88f976163 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
@@ -165,11 +165,9 @@ skip_dm:
void rtw_hal_dm_init(struct adapter *Adapter)
{
struct dm_priv *pdmpriv = &Adapter->HalData->dmpriv;
- struct odm_dm_struct *podmpriv = &Adapter->HalData->odmpriv;
memset(pdmpriv, 0, sizeof(struct dm_priv));
Init_ODM_ComInfo_88E(Adapter);
- ODM_InitDebugSetting(podmpriv);
}
/* Add new function to reset the state of antenna diversity before link. */
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
index 95b27b4df705..d1086699f952 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
@@ -24,11 +24,8 @@ void iol_mode_enable(struct adapter *padapter, u8 enable)
reg_0xf0 = usb_read8(padapter, REG_SYS_CFG);
usb_write8(padapter, REG_SYS_CFG, reg_0xf0 | SW_OFFLOAD_EN);
- if (!padapter->bFWReady) {
- DBG_88E("bFWReady == false call reset 8051...\n");
+ if (!padapter->bFWReady)
_8051Reset88E(padapter);
- }
-
} else {
/* disable initial offload */
reg_0xf0 = usb_read8(padapter, REG_SYS_CFG);
@@ -74,7 +71,6 @@ s32 rtl8188e_iol_efuse_patch(struct adapter *padapter)
{
s32 result = _SUCCESS;
- DBG_88E("==> %s\n", __func__);
if (rtw_iol_applied(padapter)) {
iol_mode_enable(padapter, 1);
result = iol_execute(padapter, CMD_READ_EFUSE_MAP);
@@ -95,7 +91,6 @@ void _8051Reset88E(struct adapter *padapter)
u1bTmp = usb_read8(padapter, REG_SYS_FUNC_EN + 1);
usb_write8(padapter, REG_SYS_FUNC_EN + 1, u1bTmp & (~BIT(2)));
usb_write8(padapter, REG_SYS_FUNC_EN + 1, u1bTmp | (BIT(2)));
- DBG_88E("=====> %s(): 8051 reset success .\n", __func__);
}
void rtl8188e_InitializeFirmwareVars(struct adapter *padapter)
@@ -139,11 +134,9 @@ void rtw_hal_set_odm_var(struct adapter *Adapter, enum hal_odm_variable eVariabl
struct sta_info *psta = pValue1;
if (bSet) {
- DBG_88E("### Set STA_(%d) info\n", psta->mac_id);
ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, psta);
ODM_RAInfo_Init(podmpriv, psta->mac_id);
} else {
- DBG_88E("### Clean STA_(%d) info\n", psta->mac_id);
ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, NULL);
}
}
@@ -161,13 +154,10 @@ void rtw_hal_set_odm_var(struct adapter *Adapter, enum hal_odm_variable eVariabl
void rtw_hal_notch_filter(struct adapter *adapter, bool enable)
{
- if (enable) {
- DBG_88E("Enable notch filter\n");
+ if (enable)
usb_write8(adapter, rOFDM0_RxDSP + 1, usb_read8(adapter, rOFDM0_RxDSP + 1) | BIT(1));
- } else {
- DBG_88E("Disable notch filter\n");
+ else
usb_write8(adapter, rOFDM0_RxDSP + 1, usb_read8(adapter, rOFDM0_RxDSP + 1) & ~BIT(1));
- }
}
/* */
@@ -191,7 +181,6 @@ static s32 _LLTWrite(struct adapter *padapter, u32 address, u32 data)
break;
if (count > POLLING_LLT_THRESHOLD) {
- RT_TRACE(_module_hal_init_c_, _drv_err_, ("Failed to polling write LLT done at address %d!\n", address));
status = _FAIL;
break;
}
@@ -241,19 +230,8 @@ s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy)
void Hal_InitPGData88E(struct adapter *padapter)
{
- struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
-
- if (!pEEPROM->bautoload_fail_flag) { /* autoload OK. */
- if (!is_boot_from_eeprom(padapter)) {
- /* Read EFUSE real map to shadow. */
- EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI);
- }
- } else {/* autoload fail */
- RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("AutoLoad Fail reported from CR9346!!\n"));
- /* update to default value 0xFF */
- if (!is_boot_from_eeprom(padapter))
- EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI);
- }
+ if (!is_boot_from_eeprom(padapter))
+ EFUSE_ShadowMapUpdate(padapter);
}
void Hal_EfuseParseIDCode88E(struct adapter *padapter, u8 *hwinfo)
@@ -263,14 +241,10 @@ void Hal_EfuseParseIDCode88E(struct adapter *padapter, u8 *hwinfo)
/* Checl 0x8129 again for making sure autoload status!! */
EEPROMId = le16_to_cpu(*((__le16 *)hwinfo));
- if (EEPROMId != RTL_EEPROM_ID) {
- DBG_88E("EEPROM ID(%#x) is invalid!!\n", EEPROMId);
+ if (EEPROMId != RTL_EEPROM_ID)
pEEPROM->bautoload_fail_flag = true;
- } else {
+ else
pEEPROM->bautoload_fail_flag = false;
- }
-
- DBG_88E("EEPROM ID = 0x%04x\n", EEPROMId);
}
static void Hal_ReadPowerValueFromPROM_8188E(struct txpowerinfo24g *pwrInfo24G, u8 *PROMContent, bool AutoLoadFail)
@@ -404,11 +378,6 @@ void Hal_ReadPowerSavingMode88E(struct adapter *padapter, u8 *hwinfo, bool AutoL
/* decide hw if support remote wakeup function */
/* if hw supported, 8051 (SIE) will generate WeakUP signal(D+/D- toggle) when autoresume */
padapter->pwrctrlpriv.bSupportRemoteWakeup = (hwinfo[EEPROM_USB_OPTIONAL_FUNCTION0] & BIT(1)) ? true : false;
-
- DBG_88E("%s...bHWPwrPindetect(%x)-bHWPowerdown(%x) , bSupportRemoteWakeup(%x)\n", __func__,
- padapter->pwrctrlpriv.bHWPwrPindetect, padapter->pwrctrlpriv.bHWPowerdown, padapter->pwrctrlpriv.bSupportRemoteWakeup);
-
- DBG_88E("### PS params => power_mgnt(%x), usbss_enable(%x) ###\n", padapter->registrypriv.power_mgnt, padapter->registrypriv.usbss_enable);
}
}
@@ -431,21 +400,12 @@ void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *PROMContent, bool Auto
pHalData->Index24G_BW40_Base[0][ch] = pwrInfo24G.IndexBW40_Base[0][4];
else
pHalData->Index24G_BW40_Base[0][ch] = pwrInfo24G.IndexBW40_Base[0][group];
-
- DBG_88E("======= Path %d, Channel %d =======\n", 0, ch);
- DBG_88E("Index24G_CCK_Base[%d][%d] = 0x%x\n", 0, ch, pHalData->Index24G_CCK_Base[0][ch]);
- DBG_88E("Index24G_BW40_Base[%d][%d] = 0x%x\n", 0, ch, pHalData->Index24G_BW40_Base[0][ch]);
}
for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
pHalData->CCK_24G_Diff[0][TxCount] = pwrInfo24G.CCK_Diff[0][TxCount];
pHalData->OFDM_24G_Diff[0][TxCount] = pwrInfo24G.OFDM_Diff[0][TxCount];
pHalData->BW20_24G_Diff[0][TxCount] = pwrInfo24G.BW20_Diff[0][TxCount];
pHalData->BW40_24G_Diff[0][TxCount] = pwrInfo24G.BW40_Diff[0][TxCount];
- DBG_88E("======= TxCount %d =======\n", TxCount);
- DBG_88E("CCK_24G_Diff[%d][%d] = %d\n", 0, TxCount, pHalData->CCK_24G_Diff[0][TxCount]);
- DBG_88E("OFDM_24G_Diff[%d][%d] = %d\n", 0, TxCount, pHalData->OFDM_24G_Diff[0][TxCount]);
- DBG_88E("BW20_24G_Diff[%d][%d] = %d\n", 0, TxCount, pHalData->BW20_24G_Diff[0][TxCount]);
- DBG_88E("BW40_24G_Diff[%d][%d] = %d\n", 0, TxCount, pHalData->BW40_24G_Diff[0][TxCount]);
}
/* 2010/10/19 MH Add Regulator recognize for CU. */
@@ -456,7 +416,6 @@ void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *PROMContent, bool Auto
} else {
pHalData->EEPROMRegulatory = 0;
}
- DBG_88E("EEPROMRegulatory = 0x%x\n", pHalData->EEPROMRegulatory);
}
void Hal_EfuseParseXtal_8188E(struct adapter *pAdapter, u8 *hwinfo, bool AutoLoadFail)
@@ -470,7 +429,6 @@ void Hal_EfuseParseXtal_8188E(struct adapter *pAdapter, u8 *hwinfo, bool AutoLoa
} else {
pHalData->CrystalCap = EEPROM_Default_CrystalCap_88E;
}
- DBG_88E("CrystalCap: 0x%2x\n", pHalData->CrystalCap);
}
void Hal_EfuseParseBoardType88E(struct adapter *pAdapter, u8 *hwinfo, bool AutoLoadFail)
@@ -482,7 +440,6 @@ void Hal_EfuseParseBoardType88E(struct adapter *pAdapter, u8 *hwinfo, bool AutoL
& 0xE0) >> 5;
else
pHalData->BoardType = 0;
- DBG_88E("Board Type: 0x%2x\n", pHalData->BoardType);
}
void Hal_EfuseParseEEPROMVer88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
@@ -496,9 +453,6 @@ void Hal_EfuseParseEEPROMVer88E(struct adapter *padapter, u8 *hwinfo, bool AutoL
} else {
pHalData->EEPROMVersion = 1;
}
- RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
- ("Hal_EfuseParseEEPROMVer(), EEVer = %d\n",
- pHalData->EEPROMVersion));
}
void rtl8188e_EfuseParseChnlPlan(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
@@ -508,7 +462,6 @@ void rtl8188e_EfuseParseChnlPlan(struct adapter *padapter, u8 *hwinfo, bool Auto
padapter->registrypriv.channel_plan,
RT_CHANNEL_DOMAIN_WORLD_WIDE_13, AutoLoadFail);
- DBG_88E("mlmepriv.ChannelPlan = 0x%02x\n", padapter->mlmepriv.ChannelPlan);
}
void Hal_EfuseParseCustomerID88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
@@ -521,7 +474,6 @@ void Hal_EfuseParseCustomerID88E(struct adapter *padapter, u8 *hwinfo, bool Auto
pHalData->EEPROMCustomerID = 0;
pHalData->EEPROMSubCustomerID = 0;
}
- DBG_88E("EEPROM Customer ID: 0x%2x\n", pHalData->EEPROMCustomerID);
}
void Hal_ReadAntennaDiversity88E(struct adapter *pAdapter, u8 *PROMContent, bool AutoLoadFail)
@@ -553,7 +505,6 @@ void Hal_ReadAntennaDiversity88E(struct adapter *pAdapter, u8 *PROMContent, bool
} else {
pHalData->AntDivCfg = 0;
}
- DBG_88E("EEPROM : AntDivCfg = %x, TRxAntDivType = %x\n", pHalData->AntDivCfg, pHalData->TRxAntDivType);
}
void Hal_ReadThermalMeter_88E(struct adapter *Adapter, u8 *PROMContent, bool AutoloadFail)
@@ -567,8 +518,6 @@ void Hal_ReadThermalMeter_88E(struct adapter *Adapter, u8 *PROMContent, bool Aut
pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_88E;
if (pHalData->EEPROMThermalMeter == 0xff || AutoloadFail) {
- pHalData->bAPKThermalMeterIgnore = true;
pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_88E;
}
- DBG_88E("ThermalMeter = 0x%x\n", pHalData->EEPROMThermalMeter);
}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c b/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c
index 8669bf097479..05dbd3f08328 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c
@@ -156,7 +156,7 @@ void update_recvframe_phyinfo_88e(struct recv_frame *precvframe,
myid(&padapter->eeprompriv), ETH_ALEN));
pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID &&
- (GetFrameSubType(wlanhdr) == WIFI_BEACON);
+ (GetFrameSubType(wlanhdr) == IEEE80211_STYPE_BEACON);
if (pkt_info.bPacketBeacon) {
if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE))
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_xmit.c b/drivers/staging/rtl8188eu/hal/rtl8188e_xmit.c
index 9b8a284544ac..efa8960a7eb5 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_xmit.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_xmit.c
@@ -23,35 +23,3 @@ void handle_txrpt_ccx_88e(struct adapter *adapter, u8 *buf)
RTW_SCTX_DONE_CCX_PKT_FAIL);
}
}
-
-void _dbg_dump_tx_info(struct adapter *padapter, int frame_tag,
- struct tx_desc *ptxdesc)
-{
- u8 dmp_txpkt;
- bool dump_txdesc = false;
-
- rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DUMP_TXPKT, &(dmp_txpkt));
-
- if (dmp_txpkt == 1) {/* dump txdesc for data frame */
- DBG_88E("dump tx_desc for data frame\n");
- if ((frame_tag & 0x0f) == DATA_FRAMETAG)
- dump_txdesc = true;
- } else if (dmp_txpkt == 2) {/* dump txdesc for mgnt frame */
- DBG_88E("dump tx_desc for mgnt frame\n");
- if ((frame_tag & 0x0f) == MGNT_FRAMETAG)
- dump_txdesc = true;
- }
-
- if (dump_txdesc) {
- DBG_88E("=====================================\n");
- DBG_88E("txdw0(0x%08x)\n", ptxdesc->txdw0);
- DBG_88E("txdw1(0x%08x)\n", ptxdesc->txdw1);
- DBG_88E("txdw2(0x%08x)\n", ptxdesc->txdw2);
- DBG_88E("txdw3(0x%08x)\n", ptxdesc->txdw3);
- DBG_88E("txdw4(0x%08x)\n", ptxdesc->txdw4);
- DBG_88E("txdw5(0x%08x)\n", ptxdesc->txdw5);
- DBG_88E("txdw6(0x%08x)\n", ptxdesc->txdw6);
- DBG_88E("txdw7(0x%08x)\n", ptxdesc->txdw7);
- DBG_88E("=====================================\n");
- }
-}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_led.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_led.c
index 35806b27fdee..25ce6db3beae 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188eu_led.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_led.c
@@ -18,7 +18,7 @@ void sw_led_on(struct adapter *padapter, struct LED_871x *pLed)
return;
led_cfg = usb_read8(padapter, REG_LEDCFG2);
usb_write8(padapter, REG_LEDCFG2, (led_cfg & 0xf0) | BIT(5) | BIT(6));
- pLed->bLedOn = true;
+ pLed->led_on = true;
}
void sw_led_off(struct adapter *padapter, struct LED_871x *pLed)
@@ -37,7 +37,7 @@ void sw_led_off(struct adapter *padapter, struct LED_871x *pLed)
led_cfg &= 0xFE;
usb_write8(padapter, REG_MAC_PINMUX_CFG, led_cfg);
exit:
- pLed->bLedOn = false;
+ pLed->led_on = false;
}
void rtw_hal_sw_led_init(struct adapter *padapter)
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c
index 09bc915994db..aa69fc3880b3 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c
@@ -31,8 +31,6 @@ int rtw_hal_init_recv_priv(struct adapter *padapter)
kcalloc(NR_RECVBUFF, sizeof(struct recv_buf), GFP_KERNEL);
if (!precvpriv->precv_buf) {
res = _FAIL;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("alloc recv_buf fail!\n"));
goto exit;
}
precvbuf = precvpriv->precv_buf;
@@ -80,14 +78,6 @@ void rtw_hal_free_recv_priv(struct adapter *padapter)
}
kfree(precvpriv->precv_buf);
-
- if (skb_queue_len(&precvpriv->rx_skb_queue))
- DBG_88E(KERN_WARNING "rx_skb_queue not empty\n");
skb_queue_purge(&precvpriv->rx_skb_queue);
-
- if (skb_queue_len(&precvpriv->free_recv_skb_queue))
- DBG_88E(KERN_WARNING "free_recv_skb_queue not empty, %d\n",
- skb_queue_len(&precvpriv->free_recv_skb_queue));
-
skb_queue_purge(&precvpriv->free_recv_skb_queue);
}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
index 2866283c211d..1fa558e0de38 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
@@ -287,11 +287,7 @@ static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bag
ptxdesc->txdw5 |= cpu_to_le32(0x00300000);/* retry limit = 12 */
ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate));
- } else if ((pxmitframe->frame_tag & 0x0f) == TXAGG_FRAMETAG) {
- DBG_88E("pxmitframe->frame_tag == TXAGG_FRAMETAG\n");
} else {
- DBG_88E("pxmitframe->frame_tag = %d\n", pxmitframe->frame_tag);
-
/* offset 4 */
ptxdesc->txdw1 |= cpu_to_le32((4) & 0x3f);/* CAM_ID(MAC_ID) */
@@ -322,7 +318,6 @@ static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bag
rtl88eu_dm_set_tx_ant_by_tx_info(odmpriv, pmem, pattrib->mac_id);
rtl8188eu_cal_txdesc_chksum(ptxdesc);
- _dbg_dump_tx_info(adapt, pxmitframe->frame_tag, ptxdesc);
return pull;
}
@@ -346,15 +341,11 @@ static s32 rtw_dump_xframe(struct adapter *adapt, struct xmit_frame *pxmitframe)
rtw_issue_addbareq_cmd(adapt, pxmitframe);
mem_addr = pxmitframe->buf_addr;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s()\n", __func__));
-
for (t = 0; t < pattrib->nr_frags; t++) {
if (inner_ret != _SUCCESS && ret == _SUCCESS)
ret = _FAIL;
if (t != (pattrib->nr_frags - 1)) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("pattrib->nr_frags=%d\n", pattrib->nr_frags));
-
sz = pxmitpriv->frag_len;
sz = sz - 4 - pattrib->icv_len;
} else {
@@ -377,8 +368,6 @@ static s32 rtw_dump_xframe(struct adapter *adapt, struct xmit_frame *pxmitframe)
rtw_count_tx_stats(adapt, pxmitframe, sz);
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_write_port, w_sz=%d\n", w_sz));
-
mem_addr += w_sz;
mem_addr = (u8 *)round_up((size_t)mem_addr, 4);
@@ -413,7 +402,7 @@ static u32 xmitframe_need_length(struct xmit_frame *pxmitframe)
bool rtl8188eu_xmitframe_complete(struct adapter *adapt,
struct xmit_priv *pxmitpriv)
{
- struct xmit_frame *pxmitframe = NULL;
+ struct xmit_frame *pxmitframe, *n;
struct xmit_frame *pfirstframe = NULL;
struct xmit_buf *pxmitbuf;
@@ -422,7 +411,7 @@ bool rtl8188eu_xmitframe_complete(struct adapter *adapt,
struct sta_info *psta = NULL;
struct tx_servq *ptxservq = NULL;
- struct list_head *xmitframe_plist = NULL, *xmitframe_phead = NULL;
+ struct list_head *xmitframe_phead = NULL;
u32 pbuf; /* next pkt address */
u32 pbuf_tail; /* last pkt tail */
@@ -435,15 +424,11 @@ bool rtl8188eu_xmitframe_complete(struct adapter *adapt,
/* dump frame variable */
u32 ff_hwaddr;
- RT_TRACE(_module_rtl8192c_xmit_c_, _drv_info_, ("+xmitframe_complete\n"));
-
pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
if (!pxmitbuf)
return false;
/* 3 1. pick up first frame */
- rtw_free_xmitframe(pxmitpriv, pxmitframe);
-
pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
if (!pxmitframe) {
/* no more xmit frame, release xmit buffer */
@@ -507,12 +492,7 @@ bool rtl8188eu_xmitframe_complete(struct adapter *adapt,
spin_lock_bh(&pxmitpriv->lock);
xmitframe_phead = get_list_head(&ptxservq->sta_pending);
- xmitframe_plist = xmitframe_phead->next;
-
- while (xmitframe_phead != xmitframe_plist) {
- pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
- xmitframe_plist = xmitframe_plist->next;
-
+ list_for_each_entry_safe(pxmitframe, n, xmitframe_phead, list) {
pxmitframe->agg_num = 0; /* not first frame of aggregation */
pxmitframe->pkt_offset = 0; /* not first frame of aggregation, no need to reserve offset */
@@ -627,7 +607,6 @@ bool rtw_hal_xmit(struct adapter *adapt, struct xmit_frame *pxmitframe)
if (res == _SUCCESS) {
rtw_dump_xframe(adapt, pxmitframe);
} else {
- DBG_88E("==> %s xmitframe_coalesce failed\n", __func__);
rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
rtw_free_xmitframe(pxmitpriv, pxmitframe);
}
@@ -639,7 +618,6 @@ enqueue:
spin_unlock_bh(&pxmitpriv->lock);
if (res != _SUCCESS) {
- RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("pre_xmitframe: enqueue xmitframe fail\n"));
rtw_free_xmitframe(pxmitpriv, pxmitframe);
/* Trick, make the statistics correct */
diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c
index 80cdcf6f7879..05c67e7d23ad 100644
--- a/drivers/staging/rtl8188eu/hal/usb_halinit.c
+++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c
@@ -35,7 +35,6 @@ static void _ConfigNormalChipOutEP_8188E(struct adapter *adapt, u8 NumOutPipe)
default:
break;
}
- DBG_88E("%s OutEpQueueSel(0x%02x), OutEpNumber(%d)\n", __func__, haldata->OutEpQueueSel, haldata->OutEpNumber);
}
static bool HalUsbSetQueuePipeMapping8188EUsb(struct adapter *adapt, u8 NumInPipe, u8 NumOutPipe)
@@ -90,10 +89,8 @@ u32 rtw_hal_power_on(struct adapter *adapt)
return _SUCCESS;
if (!rtl88eu_pwrseqcmdparsing(adapt, PWR_CUT_ALL_MSK,
- Rtl8188E_NIC_PWR_ON_FLOW)) {
- DBG_88E(KERN_ERR "%s: run power on flow fail\n", __func__);
+ Rtl8188E_NIC_PWR_ON_FLOW))
return _FAIL;
- }
/* Enable MAC DMA/WMAC/SCHEDULE/SEC block */
/* Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy. Added by tynli. 2011.08.31. */
@@ -594,7 +591,6 @@ static void _InitAntenna_Selection(struct adapter *Adapter)
if (haldata->AntDivCfg == 0)
return;
- DBG_88E("==> %s ....\n", __func__);
usb_write32(Adapter, REG_LEDCFG0, usb_read32(Adapter, REG_LEDCFG0) | BIT(23));
phy_set_bb_reg(Adapter, rFPGA0_XAB_RFParameter, BIT(13), 0x01);
@@ -603,25 +599,8 @@ static void _InitAntenna_Selection(struct adapter *Adapter)
haldata->CurAntenna = Antenna_A;
else
haldata->CurAntenna = Antenna_B;
- DBG_88E("%s,Cur_ant:(%x)%s\n", __func__, haldata->CurAntenna, (haldata->CurAntenna == Antenna_A) ? "Antenna_A" : "Antenna_B");
}
-/*-----------------------------------------------------------------------------
- * Function: HwSuspendModeEnable92Cu()
- *
- * Overview: HW suspend mode switch.
- *
- * Input: NONE
- *
- * Output: NONE
- *
- * Return: NONE
- *
- * Revised History:
- * When Who Remark
- * 08/23/2010 MHC HW suspend mode switch test..
- *---------------------------------------------------------------------------
- */
enum rt_rf_power_state RfOnOffDetect(struct adapter *adapt)
{
u8 val8;
@@ -629,12 +608,10 @@ enum rt_rf_power_state RfOnOffDetect(struct adapter *adapt)
if (adapt->pwrctrlpriv.bHWPowerdown) {
val8 = usb_read8(adapt, REG_HSISR);
- DBG_88E("pwrdown, 0x5c(BIT(7))=%02x\n", val8);
rfpowerstate = (val8 & BIT(7)) ? rf_off : rf_on;
} else { /* rf on/off */
usb_write8(adapt, REG_MAC_PINMUX_CFG, usb_read8(adapt, REG_MAC_PINMUX_CFG) & ~(BIT(3)));
val8 = usb_read8(adapt, REG_GPIO_IO_SEL);
- DBG_88E("GPIO_IN=%02x\n", val8);
rfpowerstate = (val8 & BIT(3)) ? rf_on : rf_off;
}
return rfpowerstate;
@@ -649,11 +626,6 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
struct hal_data_8188e *haldata = Adapter->HalData;
struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv;
struct registry_priv *pregistrypriv = &Adapter->registrypriv;
- unsigned long init_start_time = jiffies;
-
- #define HAL_INIT_PROFILE_TAG(stage) do {} while (0)
-
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BEGIN);
if (Adapter->pwrctrlpriv.bkeepfwalive) {
if (haldata->odmpriv.RFCalibrateInfo.bIQKInitialized) {
@@ -669,10 +641,8 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
goto exit;
}
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PW_ON);
status = rtw_hal_power_on(Adapter);
if (status == _FAIL) {
- RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("Failed to init power on!\n"));
goto exit;
}
@@ -693,7 +663,6 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
txpktbuf_bndy = WMM_NORMAL_TX_PAGE_BOUNDARY_88E;
}
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC01);
_InitQueueReservedPage(Adapter);
_InitQueuePriority(Adapter);
_InitPageBoundary(Adapter);
@@ -701,7 +670,6 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
_InitTxBufferBoundary(Adapter, 0);
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_DOWNLOAD_FW);
if (Adapter->registrypriv.mp_mode == 1) {
_InitRxSetting(Adapter);
Adapter->bFWReady = false;
@@ -709,11 +677,9 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
status = rtl88eu_download_fw(Adapter);
if (status) {
- DBG_88E("%s: Download Firmware failed!!\n", __func__);
Adapter->bFWReady = false;
return status;
}
- RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializeadapt8192CSdio(): Download Firmware Success!!\n"));
Adapter->bFWReady = true;
}
rtl8188e_InitializeFirmwareVars(Adapter);
@@ -724,23 +690,17 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
rtl88eu_phy_rf_config(Adapter);
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_EFUSE_PATCH);
status = rtl8188e_iol_efuse_patch(Adapter);
- if (status == _FAIL) {
- DBG_88E("%s rtl8188e_iol_efuse_patch failed\n", __func__);
+ if (status == _FAIL)
goto exit;
- }
_InitTxBufferBoundary(Adapter, txpktbuf_bndy);
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_LLTT);
status = InitLLTTable(Adapter, txpktbuf_bndy);
if (status == _FAIL) {
- RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("Failed to init LLT table\n"));
goto exit;
}
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC02);
/* Get Rx PHY status in order to report RSSI and others. */
_InitDriverInfoSize(Adapter, DRVINFO_SZ);
@@ -782,13 +742,10 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
haldata->RfRegChnlVal[0] = rtw_hal_read_rfreg(Adapter, (enum rf_radio_path)0, RF_CHNLBW, bRFRegOffsetMask);
haldata->RfRegChnlVal[1] = rtw_hal_read_rfreg(Adapter, (enum rf_radio_path)1, RF_CHNLBW, bRFRegOffsetMask);
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_TURN_ON_BLOCK);
_BBTurnOnBlock(Adapter);
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_SECURITY);
invalidate_cam_all(Adapter);
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC11);
/* 2010/12/17 MH We need to set TX power according to EFUSE content at first. */
phy_set_tx_power_level(Adapter, haldata->CurrentChannel);
@@ -813,7 +770,6 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
/* Nav limit , suggest by scott */
usb_write8(Adapter, 0x652, 0x0);
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_HAL_DM);
rtl8188e_InitHalDm(Adapter);
/* 2010/08/11 MH Merge from 8192SE for Minicard init. We need to confirm current radio status */
@@ -837,7 +793,6 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
/* enable tx DMA to drop the redundate data of packet */
usb_write16(Adapter, REG_TXDMA_OFFSET_CHK, (usb_read16(Adapter, REG_TXDMA_OFFSET_CHK) | DROP_DATA_EN));
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_IQK);
/* 2010/08/26 MH Merge from 8192CE. */
if (pwrctrlpriv->rf_pwrstate == rf_on) {
if (haldata->odmpriv.RFCalibrateInfo.bIQKInitialized) {
@@ -847,15 +802,11 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
haldata->odmpriv.RFCalibrateInfo.bIQKInitialized = true;
}
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_PW_TRACK);
-
ODM_TXPowerTrackingCheck(&haldata->odmpriv);
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_LCK);
rtl88eu_phy_lc_calibrate(Adapter);
}
-/* HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PABIAS); */
/* _InitPABias(Adapter); */
usb_write8(Adapter, REG_USB_HRPWM, 0);
@@ -863,10 +814,6 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
usb_write32(Adapter, REG_FWHW_TXQ_CTRL, usb_read32(Adapter, REG_FWHW_TXQ_CTRL) | BIT(12));
exit:
- HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_END);
-
- DBG_88E("%s in %dms\n", __func__,
- jiffies_to_msecs(jiffies - init_start_time));
return status;
}
@@ -875,8 +822,6 @@ static void CardDisableRTL8188EU(struct adapter *Adapter)
{
u8 val8;
- RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("%s\n", __func__));
-
/* Stop Tx Report Timer. 0x4EC[Bit1]=b'0 */
val8 = usb_read8(Adapter, REG_TX_RPT_CTRL);
usb_write8(Adapter, REG_TX_RPT_CTRL, val8 & (~BIT(1)));
@@ -942,12 +887,9 @@ static void rtl8192cu_hw_power_down(struct adapter *adapt)
u32 rtl8188eu_hal_deinit(struct adapter *Adapter)
{
- DBG_88E("==> %s\n", __func__);
-
usb_write32(Adapter, REG_HIMR_88E, IMR_DISABLED_88E);
usb_write32(Adapter, REG_HIMRE_88E, IMR_DISABLED_88E);
- DBG_88E("bkeepfwalive(%x)\n", Adapter->pwrctrlpriv.bkeepfwalive);
if (Adapter->pwrctrlpriv.bkeepfwalive) {
if ((Adapter->pwrctrlpriv.bHWPwrPindetect) && (Adapter->pwrctrlpriv.bHWPowerdown))
rtl8192cu_hw_power_down(Adapter);
@@ -971,14 +913,10 @@ u32 rtw_hal_inirp_init(struct adapter *Adapter)
status = _SUCCESS;
- RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
- ("===> usb_inirp_init\n"));
-
/* issue Rx irp to receive data */
precvbuf = precvpriv->precv_buf;
for (i = 0; i < NR_RECVBUFF; i++) {
if (!usb_read_port(Adapter, RECV_BULK_IN_ADDR, precvbuf)) {
- RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("usb_rx_init: usb_read_port error\n"));
status = _FAIL;
goto exit;
}
@@ -987,9 +925,6 @@ u32 rtw_hal_inirp_init(struct adapter *Adapter)
}
exit:
-
- RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("<=== usb_inirp_init\n"));
-
return status;
}
@@ -1018,9 +953,6 @@ static void Hal_EfuseParsePIDVID_8188EU(struct adapter *adapt, u8 *hwinfo, bool
haldata->EEPROMCustomerID = EEPROM_Default_CustomerID;
haldata->EEPROMSubCustomerID = EEPROM_Default_SubCustomerID;
}
-
- DBG_88E("VID = 0x%04X, PID = 0x%04X\n", haldata->EEPROMVID, haldata->EEPROMPID);
- DBG_88E("Customer ID: 0x%02X, SubCustomer ID: 0x%02X\n", haldata->EEPROMCustomerID, haldata->EEPROMSubCustomerID);
}
static void Hal_EfuseParseMACAddr_8188EU(struct adapter *adapt, u8 *hwinfo, bool AutoLoadFail)
@@ -1036,8 +968,6 @@ static void Hal_EfuseParseMACAddr_8188EU(struct adapter *adapt, u8 *hwinfo, bool
/* Read Permanent MAC address */
memcpy(eeprom->mac_addr, &hwinfo[EEPROM_MAC_ADDR_88EU], ETH_ALEN);
}
- RT_TRACE(_module_hci_hal_init_c_, _drv_notice_,
- ("%s: Permanent Address = %pM\n", __func__, eeprom->mac_addr));
}
static void readAdapterInfo_8188EU(struct adapter *adapt)
@@ -1070,23 +1000,13 @@ static void _ReadPROMContent(struct adapter *Adapter)
eeprom->EepromOrEfuse = (eeValue & BOOT_FROM_EEPROM) ? true : false;
eeprom->bautoload_fail_flag = (eeValue & EEPROM_EN) ? false : true;
- DBG_88E("Boot from %s, Autoload %s !\n", (eeprom->EepromOrEfuse ? "EEPROM" : "EFUSE"),
- (eeprom->bautoload_fail_flag ? "Fail" : "OK"));
-
Hal_InitPGData88E(Adapter);
readAdapterInfo_8188EU(Adapter);
}
void rtw_hal_read_chip_info(struct adapter *Adapter)
{
- unsigned long start = jiffies;
-
- MSG_88E("====> %s\n", __func__);
-
_ReadPROMContent(Adapter);
-
- MSG_88E("<==== %s in %d ms\n", __func__,
- jiffies_to_msecs(jiffies - start));
}
#define GPIO_DEBUG_PORT_NUM 0
@@ -1137,8 +1057,6 @@ static void hw_var_set_opmode(struct adapter *Adapter, u8 variable, u8 *val)
val8 |= mode;
usb_write8(Adapter, MSR, val8);
- DBG_88E("%s()-%d mode = %d\n", __func__, __LINE__, mode);
-
if ((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) {
StopTxBeacon(Adapter);
@@ -1259,7 +1177,6 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
/* For 8190, we select only 24M, 12M, 6M, 11M, 5.5M, 2M, and 1M from the Basic rate. */
/* We do not use other rates. */
hal_set_brate_cfg(val, &BrateCfg);
- DBG_88E("HW_VAR_BASIC_RATE: BrateCfg(%#x)\n", BrateCfg);
/* 2011.03.30 add by Luke Lee */
/* CCK 2M ACK should be disabled for some BCM and Atheros AP IOT */
@@ -1541,7 +1458,6 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
else
AcmCtrl &= (~AcmHw_BeqEn);
- DBG_88E("[HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl);
usb_write8(Adapter, REG_ACMHWCTRL, AcmCtrl);
}
break;
@@ -1684,9 +1600,7 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
do {
if (!(usb_read32(Adapter, REG_RXPKT_NUM) & RXDMA_IDLE))
break;
- } while (trycnt--);
- if (trycnt == 0)
- DBG_88E("Stop RX DMA failed......\n");
+ } while (--trycnt);
/* RQPN Load 0 */
usb_write16(Adapter, REG_RQPN_NPQ, 0x0);
@@ -1699,13 +1613,11 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
break;
case HW_VAR_APFM_ON_MAC:
haldata->bMacPwrCtrlOn = *val;
- DBG_88E("%s: bMacPwrCtrlOn=%d\n", __func__, haldata->bMacPwrCtrlOn);
break;
case HW_VAR_TX_RPT_MAX_MACID:
{
u8 maxMacid = *val;
- DBG_88E("### MacID(%d),Set Max Tx RPT MID(%d)\n", maxMacid, maxMacid + 1);
usb_write8(Adapter, REG_TX_RPT_CTRL + 1, maxMacid + 1);
}
break;
@@ -1835,27 +1747,6 @@ u8 rtw_hal_get_def_var(struct adapter *Adapter, enum hal_def_variable eVariable,
*((u32 *)pValue) = MAX_AMPDU_FACTOR_64K;
break;
case HW_DEF_RA_INFO_DUMP:
- {
- u8 entry_id = *((u8 *)pValue);
-
- if (check_fwstate(&Adapter->mlmepriv, _FW_LINKED)) {
- DBG_88E("============ RA status check ===================\n");
- DBG_88E("Mac_id:%d , RateID = %d, RAUseRate = 0x%08x, RateSGI = %d, DecisionRate = 0x%02x ,PTStage = %d\n",
- entry_id,
- haldata->odmpriv.RAInfo[entry_id].RateID,
- haldata->odmpriv.RAInfo[entry_id].RAUseRate,
- haldata->odmpriv.RAInfo[entry_id].RateSGI,
- haldata->odmpriv.RAInfo[entry_id].DecisionRate,
- haldata->odmpriv.RAInfo[entry_id].PTStage);
- }
- }
- break;
- case HW_DEF_ODM_DBG_FLAG:
- {
- struct odm_dm_struct *dm_ocm = &haldata->odmpriv;
-
- pr_info("dm_ocm->DebugComponents = 0x%llx\n", dm_ocm->DebugComponents);
- }
break;
case HAL_DEF_DBG_DUMP_RXPKT:
*((u8 *)pValue) = haldata->bDumpRxPkt;
@@ -1919,8 +1810,6 @@ void UpdateHalRAMask8188EUsb(struct adapter *adapt, u32 mac_id, u8 rssi_level)
}
rate_bitmap = ODM_Get_Rate_Bitmap(odmpriv, mac_id, mask, rssi_level);
- DBG_88E("%s => mac_id:%d, networkType:0x%02x, mask:0x%08x\n\t ==> rssi_level:%d, rate_bitmap:0x%08x\n",
- __func__, mac_id, networkType, mask, rssi_level, rate_bitmap);
mask &= rate_bitmap;
diff --git a/drivers/staging/rtl8188eu/include/drv_types.h b/drivers/staging/rtl8188eu/include/drv_types.h
index 4116051a9a65..3609a44ed078 100644
--- a/drivers/staging/rtl8188eu/include/drv_types.h
+++ b/drivers/staging/rtl8188eu/include/drv_types.h
@@ -34,7 +34,6 @@ struct qos_priv {
};
#include <rtw_mlme.h>
-#include <rtw_debug.h>
#include <rtw_rf.h>
#include <rtw_event.h>
#include <rtw_led.h>
diff --git a/drivers/staging/rtl8188eu/include/hal_intf.h b/drivers/staging/rtl8188eu/include/hal_intf.h
index 39df30599a5d..2e3e933781eb 100644
--- a/drivers/staging/rtl8188eu/include/hal_intf.h
+++ b/drivers/staging/rtl8188eu/include/hal_intf.h
@@ -117,7 +117,6 @@ enum hal_def_variable {
HW_DEF_RA_INFO_DUMP,
HAL_DEF_DBG_DUMP_TXPKT,
HW_DEF_FA_CNT_DUMP,
- HW_DEF_ODM_DBG_FLAG,
};
enum hal_odm_variable {
diff --git a/drivers/staging/rtl8188eu/include/ieee80211.h b/drivers/staging/rtl8188eu/include/ieee80211.h
index cb6940d2aeab..da6245a77d5d 100644
--- a/drivers/staging/rtl8188eu/include/ieee80211.h
+++ b/drivers/staging/rtl8188eu/include/ieee80211.h
@@ -546,13 +546,6 @@ enum _PUBLIC_ACTION {
ACT_PUBLIC_MAX
};
-/* BACK action code */
-enum rtw_ieee80211_back_actioncode {
- RTW_WLAN_ACTION_ADDBA_REQ = 0,
- RTW_WLAN_ACTION_ADDBA_RESP = 1,
- RTW_WLAN_ACTION_DELBA = 2,
-};
-
/* HT features action code */
enum rtw_ieee80211_ht_actioncode {
RTW_WLAN_ACTION_NOTIFY_CH_WIDTH = 0,
@@ -566,13 +559,6 @@ enum rtw_ieee80211_ht_actioncode {
RTW_WLAN_ACTION_HI_INFO_EXCHG = 8,
};
-/* BACK (block-ack) parties */
-enum rtw_ieee80211_back_parties {
- RTW_WLAN_BACK_RECIPIENT = 0,
- RTW_WLAN_BACK_INITIATOR = 1,
- RTW_WLAN_BACK_TIMER = 2,
-};
-
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
* 00:50:F2
*/
diff --git a/drivers/staging/rtl8188eu/include/odm.h b/drivers/staging/rtl8188eu/include/odm.h
index d814ce492424..98402cfb1168 100644
--- a/drivers/staging/rtl8188eu/include/odm.h
+++ b/drivers/staging/rtl8188eu/include/odm.h
@@ -691,8 +691,6 @@ struct odm_dm_struct {
bool odm_ready;
struct rtl8192cd_priv *fake_priv;
- u64 DebugComponents;
- u32 DebugLevel;
/* ODM HANDLE, DRIVER NEEDS NOT TO HOOK------ */
bool bCckHighPower;
diff --git a/drivers/staging/rtl8188eu/include/odm_debug.h b/drivers/staging/rtl8188eu/include/odm_debug.h
deleted file mode 100644
index 857c64b8d2f4..000000000000
--- a/drivers/staging/rtl8188eu/include/odm_debug.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-
-#ifndef __ODM_DBG_H__
-#define __ODM_DBG_H__
-
-/* */
-/* Define the debug levels */
-/* */
-/* 1. DBG_TRACE and DBG_LOUD are used for normal cases. */
-/* They can help SW engineer to develop or trace states changed */
-/* and also help HW enginner to trace every operation to and from HW, */
-/* e.g IO, Tx, Rx. */
-/* */
-/* 2. DBG_WARNNING and DBG_SERIOUS are used for unusual or error cases, */
-/* which help us to debug SW or HW. */
-
-/* Never used in a call to ODM_RT_TRACE()! */
-#define ODM_DBG_OFF 1
-
-/* Fatal bug. */
-/* For example, Tx/Rx/IO locked up, OS hangs, memory access violation, */
-/* resource allocation failed, unexpected HW behavior, HW BUG and so on. */
-#define ODM_DBG_SERIOUS 2
-
-/* Abnormal, rare, or unexpected cases. */
-/* For example, IRP/Packet/OID canceled, device suprisely unremoved and so on. */
-#define ODM_DBG_WARNING 3
-
-/* Normal case with useful information about current SW or HW state. */
-/* For example, Tx/Rx descriptor to fill, Tx/Rx descr. completed status, */
-/* SW protocol state change, dynamic mechanism state change and so on. */
-/* */
-#define ODM_DBG_LOUD 4
-
-/* Normal case with detail execution flow or information. */
-#define ODM_DBG_TRACE 5
-
-/* Define the tracing components */
-/* BB Functions */
-#define ODM_COMP_DIG BIT(0)
-#define ODM_COMP_RA_MASK BIT(1)
-#define ODM_COMP_DYNAMIC_TXPWR BIT(2)
-#define ODM_COMP_FA_CNT BIT(3)
-#define ODM_COMP_RSSI_MONITOR BIT(4)
-#define ODM_COMP_CCK_PD BIT(5)
-#define ODM_COMP_ANT_DIV BIT(6)
-#define ODM_COMP_PWR_SAVE BIT(7)
-#define ODM_COMP_PWR_TRA BIT(8)
-#define ODM_COMP_RATE_ADAPTIVE BIT(9)
-#define ODM_COMP_PATH_DIV BIT(10)
-#define ODM_COMP_PSD BIT(11)
-#define ODM_COMP_DYNAMIC_PRICCA BIT(12)
-#define ODM_COMP_RXHP BIT(13)
-/* MAC Functions */
-#define ODM_COMP_EDCA_TURBO BIT(16)
-#define ODM_COMP_EARLY_MODE BIT(17)
-/* RF Functions */
-#define ODM_COMP_TX_PWR_TRACK BIT(24)
-#define ODM_COMP_RX_GAIN_TRACK BIT(25)
-#define ODM_COMP_CALIBRATION BIT(26)
-/* Common Functions */
-#define ODM_COMP_COMMON BIT(30)
-#define ODM_COMP_INIT BIT(31)
-
-/*------------------------Export Marco Definition---------------------------*/
-#define RT_PRINTK(fmt, args...) \
- pr_info("%s(): " fmt, __func__, ## args);
-
-#ifndef ASSERT
- #define ASSERT(expr)
-#endif
-
-#define ODM_RT_TRACE(pDM_Odm, comp, level, fmt) \
- if (((comp) & pDM_Odm->DebugComponents) && \
- (level <= pDM_Odm->DebugLevel)) { \
- pr_info("[ODM-8188E] "); \
- RT_PRINTK fmt; \
- }
-
-#define ODM_RT_ASSERT(pDM_Odm, expr, fmt) \
- if (!(expr)) { \
- pr_info("Assertion failed! %s at ......\n", #expr); \
- pr_info(" ......%s,%s,line=%d\n", __FILE__, \
- __func__, __LINE__); \
- RT_PRINTK fmt; \
- ASSERT(false); \
- }
-
-void ODM_InitDebugSetting(struct odm_dm_struct *pDM_Odm);
-
-#endif /* __ODM_DBG_H__ */
diff --git a/drivers/staging/rtl8188eu/include/odm_precomp.h b/drivers/staging/rtl8188eu/include/odm_precomp.h
index 5254d875f96b..eb2b8b613aad 100644
--- a/drivers/staging/rtl8188eu/include/odm_precomp.h
+++ b/drivers/staging/rtl8188eu/include/odm_precomp.h
@@ -23,7 +23,6 @@
#include "odm.h"
#include "odm_hwconfig.h"
-#include "odm_debug.h"
#include "phydm_regdefine11n.h"
#include "hal8188e_rate_adaptive.h" /* for RA,Power training */
@@ -33,8 +32,6 @@
#include "odm_rtl8188e.h"
-void odm_CmnInfoHook_Debug(struct odm_dm_struct *pDM_Odm);
-void odm_CmnInfoInit_Debug(struct odm_dm_struct *pDM_Odm);
void odm_DIGInit(struct odm_dm_struct *pDM_Odm);
void odm_RateAdaptiveMaskInit(struct odm_dm_struct *pDM_Odm);
void odm_DynamicBBPowerSavingInit(struct odm_dm_struct *pDM_Odm);
@@ -42,7 +39,6 @@ void odm_DynamicTxPowerInit(struct odm_dm_struct *pDM_Odm);
void odm_TXPowerTrackingInit(struct odm_dm_struct *pDM_Odm);
void ODM_EdcaTurboInit(struct odm_dm_struct *pDM_Odm);
void odm_SwAntDivInit_NIC(struct odm_dm_struct *pDM_Odm);
-void odm_CmnInfoUpdate_Debug(struct odm_dm_struct *pDM_Odm);
void odm_CommonInfoSelfUpdate(struct odm_dm_struct *pDM_Odm);
void odm_FalseAlarmCounterStatistics(struct odm_dm_struct *pDM_Odm);
void odm_DIG(struct odm_dm_struct *pDM_Odm);
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
index 0c4c23be1dd5..2c16d3f33e1c 100644
--- a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
@@ -20,19 +20,6 @@
#include "rtw_sreset.h"
#include "odm_precomp.h"
-/* Fw Array */
-#define Rtl8188E_FwImageArray Rtl8188EFwImgArray
-#define Rtl8188E_FWImgArrayLength Rtl8188EFWImgArrayLength
-
-#define RTL8188E_FW_UMC_IMG "rtl8188E\\rtl8188efw.bin"
-#define RTL8188E_PHY_REG "rtl8188E\\PHY_REG_1T.txt"
-#define RTL8188E_PHY_RADIO_A "rtl8188E\\radio_a_1T.txt"
-#define RTL8188E_PHY_RADIO_B "rtl8188E\\radio_b_1T.txt"
-#define RTL8188E_AGC_TAB "rtl8188E\\AGC_TAB_1T.txt"
-#define RTL8188E_PHY_MACREG "rtl8188E\\MAC_REG.txt"
-#define RTL8188E_PHY_REG_PG "rtl8188E\\PHY_REG_PG.txt"
-#define RTL8188E_PHY_REG_MP "rtl8188E\\PHY_REG_MP.txt"
-
/* RTL8188E Power Configuration CMDs for USB/SDIO interfaces */
#define Rtl8188E_NIC_PWR_ON_FLOW rtl8188E_power_on_flow
#define Rtl8188E_NIC_RF_OFF_FLOW rtl8188E_radio_off_flow
@@ -208,7 +195,6 @@ struct hal_data_8188e {
u8 bTXPowerDataReadFromEEPORM;
u8 EEPROMThermalMeter;
- u8 bAPKThermalMeterIgnore;
bool EepromOrEfuse;
@@ -233,21 +219,10 @@ struct hal_data_8188e {
u8 PwrGroupHT20[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
u8 PwrGroupHT40[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
- u8 LegacyHTTxPowerDiff;/* Legacy to HT rate power diff */
- /* The current Tx Power Level */
- u8 CurrentCckTxPwrIdx;
- u8 CurrentOfdm24GTxPwrIdx;
- u8 CurrentBW2024GTxPwrIdx;
- u8 CurrentBW4024GTxPwrIdx;
-
/* Read/write are allow for following hardware information variables */
u8 framesync;
- u32 framesyncC34;
- u8 framesyncMonitor;
- u8 DefaultInitialGain[4];
u8 pwrGroupCnt;
u32 MCSTxPowerLevelOriginalOffset[MAX_PG_GROUP][16];
- u32 CCKTxPowerLevelOriginalOffset;
u8 CrystalCap;
@@ -280,12 +255,6 @@ struct hal_data_8188e {
u8 bDumpRxPkt;/* for debug */
u8 bDumpTxPkt;/* for debug */
- u8 FwRsvdPageStartOffset; /* Reserve page start offset except
- * beacon in TxQ.
- */
-
- /* 2010/08/09 MH Add CU power down mode. */
- bool pwrdown;
/* Add for dual MAC 0--Mac0 1--Mac1 */
u32 interfaceIndex;
@@ -309,7 +278,6 @@ struct hal_data_8188e {
u8 UsbTxAggMode;
u8 UsbTxAggDescNum;
u16 HwRxPageSize; /* Hardware setting */
- u32 MaxUsbRxAggBlock;
enum usb_rx_agg_mode UsbRxAggMode;
u8 UsbRxAggBlockCount; /* USB Block count. Block size is
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_spec.h b/drivers/staging/rtl8188eu/include/rtl8188e_spec.h
index 55cce1f6bd77..fe0871bbb95f 100644
--- a/drivers/staging/rtl8188eu/include/rtl8188e_spec.h
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_spec.h
@@ -7,15 +7,8 @@
#ifndef __RTL8188E_SPEC_H__
#define __RTL8188E_SPEC_H__
-/* 8192C Register offset definition */
-
-#define HAL_PS_TIMER_INT_DELAY 50 /* 50 microseconds */
-#define HAL_92C_NAV_UPPER_UNIT 128 /* micro-second */
-
-#define MAC_ADDR_LEN 6
/* 8188E PKT_BUFF_ACCESS_CTRL value */
#define TXPKT_BUF_SELECT 0x69
-#define RXPKT_BUF_SELECT 0xA5
#define DISABLE_TRXPKT_BUF_ACCESS 0x0
/* 0x0000h ~ 0x00FFh System Configuration */
@@ -52,19 +45,7 @@
#define REG_FSISR 0x0054
#define REG_HSIMR 0x0058
#define REG_HSISR 0x005c
-#define REG_GPIO_PIN_CTRL_2 0x0060 /* RTL8723 WIFI/BT/GPS
- * Multi-Function GPIO Pin Control.
- */
-#define REG_GPIO_IO_SEL_2 0x0062 /* RTL8723 WIFI/BT/GPS
- * Multi-Function GPIO Select.
- */
#define REG_BB_PAD_CTRL 0x0064
-#define REG_MULTI_FUNC_CTRL 0x0068 /* RTL8723 WIFI/BT/GPS
- * Multi-Function control source.
- */
-#define REG_GPIO_OUTPUT 0x006c
-#define REG_AFE_XTAL_CTRL_EXT 0x0078 /* RTL8188E */
-#define REG_XCK_OUT_CTRL 0x007c /* RTL8188E */
#define REG_MCUFWDL 0x0080
#define REG_WOL_EVENT 0x0081 /* RTL8188E */
#define REG_MCUTSTCFG 0x0084
@@ -172,9 +153,6 @@
#define REG_PCIE_HCPWM 0x0363 /* PCIe CPWM */
#define REG_WATCH_DOG 0x0368
-/* RTL8723 series ------------------------------ */
-#define REG_PCIE_HISR 0x03A0
-
/* spec version 11 */
/* 0x0400h ~ 0x047Fh Protocol Configuration */
#define REG_VOQ_INFORMATION 0x0400
@@ -459,34 +437,6 @@
#define GPIO_IO_SEL (REG_GPIO_PIN_CTRL + 2)
#define GPIO_MOD (REG_GPIO_PIN_CTRL + 3)
-/* 8723/8188E Host System Interrupt Mask Register (offset 0x58, 32 byte) */
-#define HSIMR_GPIO12_0_INT_EN BIT(0)
-#define HSIMR_SPS_OCP_INT_EN BIT(5)
-#define HSIMR_RON_INT_EN BIT(6)
-#define HSIMR_PDN_INT_EN BIT(7)
-#define HSIMR_GPIO9_INT_EN BIT(25)
-
-/* 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) */
-#define HSISR_GPIO12_0_INT BIT(0)
-#define HSISR_SPS_OCP_INT BIT(5)
-#define HSISR_RON_INT_EN BIT(6)
-#define HSISR_PDNINT BIT(7)
-#define HSISR_GPIO9_INT BIT(25)
-
-/* 8192C (MSR) Media Status Register (Offset 0x4C, 8 bits) */
-/*
- * Network Type
- * 00: No link
- * 01: Link in ad hoc network
- * 10: Link in infrastructure network
- * 11: AP mode
- * Default: 00b.
- */
-#define MSR_NOLINK 0x00
-#define MSR_ADHOC 0x01
-#define MSR_INFRA 0x02
-#define MSR_AP 0x03
-
/* 88EU (MSR) Media Status Register (Offset 0x4C, 8 bits) */
#define USB_INTR_CONTENT_C2H_OFFSET 0
#define USB_INTR_CONTENT_CPWM1_OFFSET 16
@@ -505,34 +455,6 @@
#define CMD_EFUSE_PATCH_ERR BIT(6)
#define CMD_IOCONFIG_ERR BIT(7)
-/* 6. Adaptive Control Registers (Offset: 0x0160 - 0x01CF) */
-/* 8192C Response Rate Set Register (offset 0x181, 24bits) */
-#define RRSR_1M BIT(0)
-#define RRSR_2M BIT(1)
-#define RRSR_5_5M BIT(2)
-#define RRSR_11M BIT(3)
-#define RRSR_6M BIT(4)
-#define RRSR_9M BIT(5)
-#define RRSR_12M BIT(6)
-#define RRSR_18M BIT(7)
-#define RRSR_24M BIT(8)
-#define RRSR_36M BIT(9)
-#define RRSR_48M BIT(10)
-#define RRSR_54M BIT(11)
-#define RRSR_MCS0 BIT(12)
-#define RRSR_MCS1 BIT(13)
-#define RRSR_MCS2 BIT(14)
-#define RRSR_MCS3 BIT(15)
-#define RRSR_MCS4 BIT(16)
-#define RRSR_MCS5 BIT(17)
-#define RRSR_MCS6 BIT(18)
-#define RRSR_MCS7 BIT(19)
-
-/* 8192C Response Rate Set Register (offset 0x1BF, 8bits) */
-/* WOL bit information */
-#define HAL92C_WOL_PTK_UPDATE_EVENT BIT(0)
-#define HAL92C_WOL_GTK_UPDATE_EVENT BIT(1)
-
/* 8192C BW_OPMODE bits (Offset 0x203, 8bit) */
#define BW_OPMODE_20MHZ BIT(2)
#define BW_OPMODE_5G BIT(1)
@@ -565,12 +487,6 @@
#define SCR_TxSecEnable 0x02
#define SCR_RxSecEnable 0x04
-/* 10. Power Save Control Registers (Offset: 0x0260 - 0x02DF) */
-#define WOW_PMEN BIT(0) /* Power management Enable. */
-#define WOW_WOMEN BIT(1) /* WoW function on or off. */
-#define WOW_MAGIC BIT(2) /* Magic packet */
-#define WOW_UWF BIT(3) /* Unicast Wakeup frame. */
-
/* 12. Host Interrupt Status Registers (Offset: 0x0300 - 0x030F) */
/* 8188 IMR/ISR bits */
#define IMR_DISABLED_88E 0x0
@@ -648,21 +564,6 @@ So the following defines for 92C is not entire!!!!!!
* 0x0600h ~ 0x07FFh WMAC Configuration (512 Bytes)
* 0x2000h ~ 0x3FFFh 8051 FW Download Region (8196 Bytes)
*/
-/* 8192C (TXPAUSE) transmission pause (Offset 0x522, 8 bits) */
-/* Note:
- * The bits of stopping AC(VO/VI/BE/BK) queue in datasheet
- * RTL8192S/RTL8192C are wrong,
- * the correct arragement is VO - Bit0, VI - Bit1, BE - Bit2,
- * and BK - Bit3.
- * 8723 and 88E may be not correct either in the earlier version.
- */
-#define StopBecon BIT(6)
-#define StopHigh BIT(5)
-#define StopMgt BIT(4)
-#define StopBK BIT(3)
-#define StopBE BIT(2)
-#define StopVI BIT(1)
-#define StopVO BIT(0)
/* 8192C (RCR) Receive Configuration Register(Offset 0x608, 32 bits) */
#define RCR_APPFCS BIT(31) /* WMAC append FCS after payload */
@@ -695,14 +596,8 @@ So the following defines for 92C is not entire!!!!!!
#define RCR_FIFO_OFFSET 13
/* 0xFE00h ~ 0xFE55h USB Configuration */
-#define REG_USB_INFO 0xFE17
-#define REG_USB_SPECIAL_OPTION 0xFE55
-#define REG_USB_DMA_AGG_TO 0xFE5B
-#define REG_USB_AGG_TO 0xFE5C
-#define REG_USB_AGG_TH 0xFE5D
-
#define REG_USB_HRPWM 0xFE58
-#define REG_USB_HCPWM 0xFE57
+
/* 8192C Register Bit and Content definition */
/* 0x0000h ~ 0x00FFh System Configuration */
@@ -1089,142 +984,6 @@ So the following defines for 92C is not entire!!!!!!
#define SCR_TXBCUSEDK BIT(6) /* Force Tx Bcast pkt Use Default Key */
#define SCR_RXBCUSEDK BIT(7) /* Force Rx Bcast pkt Use Default Key */
-/* RTL8188E SDIO Configuration */
-
-/* I/O bus domain address mapping */
-#define SDIO_LOCAL_BASE 0x10250000
-#define WLAN_IOREG_BASE 0x10260000
-#define FIRMWARE_FIFO_BASE 0x10270000
-#define TX_HIQ_BASE 0x10310000
-#define TX_MIQ_BASE 0x10320000
-#define TX_LOQ_BASE 0x10330000
-#define RX_RX0FF_BASE 0x10340000
-
-/* SDIO host local register space mapping. */
-#define SDIO_LOCAL_MSK 0x0FFF
-#define WLAN_IOREG_MSK 0x7FFF
-#define WLAN_FIFO_MSK 0x1FFF /* Aggregation Length[12:0] */
-#define WLAN_RX0FF_MSK 0x0003
-
-/* Without ref to the SDIO Device ID */
-#define SDIO_WITHOUT_REF_DEVICE_ID 0
-#define SDIO_LOCAL_DEVICE_ID 0 /* 0b[16], 000b[15:13] */
-#define WLAN_TX_HIQ_DEVICE_ID 4 /* 0b[16], 100b[15:13] */
-#define WLAN_TX_MIQ_DEVICE_ID 5 /* 0b[16], 101b[15:13] */
-#define WLAN_TX_LOQ_DEVICE_ID 6 /* 0b[16], 110b[15:13] */
-#define WLAN_RX0FF_DEVICE_ID 7 /* 0b[16], 111b[15:13] */
-#define WLAN_IOREG_DEVICE_ID 8 /* 1b[16] */
-
-/* SDIO Tx Free Page Index */
-#define HI_QUEUE_IDX 0
-#define MID_QUEUE_IDX 1
-#define LOW_QUEUE_IDX 2
-#define PUBLIC_QUEUE_IDX 3
-
-#define SDIO_MAX_TX_QUEUE 3 /* HIQ, MIQ and LOQ */
-#define SDIO_MAX_RX_QUEUE 1
-
-/* SDIO Tx Control */
-#define SDIO_REG_TX_CTRL 0x0000
-/* SDIO Host Interrupt Mask */
-#define SDIO_REG_HIMR 0x0014
-/* SDIO Host Interrupt Service Routine */
-#define SDIO_REG_HISR 0x0018
-/* HCI Current Power Mode */
-#define SDIO_REG_HCPWM 0x0019
-/* RXDMA Request Length */
-#define SDIO_REG_RX0_REQ_LEN 0x001C
-/* Free Tx Buffer Page */
-#define SDIO_REG_FREE_TXPG 0x0020
-/* HCI Current Power Mode 1 */
-#define SDIO_REG_HCPWM1 0x0024
-/* HCI Current Power Mode 2 */
-#define SDIO_REG_HCPWM2 0x0026
-/* HTSF Informaion */
-#define SDIO_REG_HTSFR_INFO 0x0030
-/* HCI Request Power Mode 1 */
-#define SDIO_REG_HRPWM1 0x0080
-/* HCI Request Power Mode 2 */
-#define SDIO_REG_HRPWM2 0x0082
-/* HCI Power Save Clock */
-#define SDIO_REG_HPS_CLKR 0x0084
-/* SDIO HCI Suspend Control */
-#define SDIO_REG_HSUS_CTRL 0x0086
-/* SDIO Host Extension Interrupt Mask Always */
-#define SDIO_REG_HIMR_ON 0x0090
-/* SDIO Host Extension Interrupt Status Always */
-#define SDIO_REG_HISR_ON 0x0091
-
-#define SDIO_HIMR_DISABLED 0
-
-/* RTL8188E SDIO Host Interrupt Mask Register */
-#define SDIO_HIMR_RX_REQUEST_MSK BIT(0)
-#define SDIO_HIMR_AVAL_MSK BIT(1)
-#define SDIO_HIMR_TXERR_MSK BIT(2)
-#define SDIO_HIMR_RXERR_MSK BIT(3)
-#define SDIO_HIMR_TXFOVW_MSK BIT(4)
-#define SDIO_HIMR_RXFOVW_MSK BIT(5)
-#define SDIO_HIMR_TXBCNOK_MSK BIT(6)
-#define SDIO_HIMR_TXBCNERR_MSK BIT(7)
-#define SDIO_HIMR_BCNERLY_INT_MSK BIT(16)
-#define SDIO_HIMR_C2HCMD_MSK BIT(17)
-#define SDIO_HIMR_CPWM1_MSK BIT(18)
-#define SDIO_HIMR_CPWM2_MSK BIT(19)
-#define SDIO_HIMR_HSISR_IND_MSK BIT(20)
-#define SDIO_HIMR_GTINT3_IND_MSK BIT(21)
-#define SDIO_HIMR_GTINT4_IND_MSK BIT(22)
-#define SDIO_HIMR_PSTIMEOUT_MSK BIT(23)
-#define SDIO_HIMR_OCPINT_MSK BIT(24)
-#define SDIO_HIMR_ATIMEND_MSK BIT(25)
-#define SDIO_HIMR_ATIMEND_E_MSK BIT(26)
-#define SDIO_HIMR_CTWEND_MSK BIT(27)
-
-/* RTL8188E SDIO Specific */
-#define SDIO_HIMR_MCU_ERR_MSK BIT(28)
-#define SDIO_HIMR_TSF_BIT32_TOGGLE_MSK BIT(29)
-
-/* SDIO Host Interrupt Service Routine */
-#define SDIO_HISR_RX_REQUEST BIT(0)
-#define SDIO_HISR_AVAL BIT(1)
-#define SDIO_HISR_TXERR BIT(2)
-#define SDIO_HISR_RXERR BIT(3)
-#define SDIO_HISR_TXFOVW BIT(4)
-#define SDIO_HISR_RXFOVW BIT(5)
-#define SDIO_HISR_TXBCNOK BIT(6)
-#define SDIO_HISR_TXBCNERR BIT(7)
-#define SDIO_HISR_BCNERLY_INT BIT(16)
-#define SDIO_HISR_C2HCMD BIT(17)
-#define SDIO_HISR_CPWM1 BIT(18)
-#define SDIO_HISR_CPWM2 BIT(19)
-#define SDIO_HISR_HSISR_IND BIT(20)
-#define SDIO_HISR_GTINT3_IND BIT(21)
-#define SDIO_HISR_GTINT4_IND BIT(22)
-#define SDIO_HISR_PSTIME BIT(23)
-#define SDIO_HISR_OCPINT BIT(24)
-#define SDIO_HISR_ATIMEND BIT(25)
-#define SDIO_HISR_ATIMEND_E BIT(26)
-#define SDIO_HISR_CTWEND BIT(27)
-
-/* RTL8188E SDIO Specific */
-#define SDIO_HISR_MCU_ERR BIT(28)
-#define SDIO_HISR_TSF_BIT32_TOGGLE BIT(29)
-
-#define MASK_SDIO_HISR_CLEAR \
- (SDIO_HISR_TXERR | SDIO_HISR_RXERR | SDIO_HISR_TXFOVW |\
- SDIO_HISR_RXFOVW | SDIO_HISR_TXBCNOK | SDIO_HISR_TXBCNERR |\
- SDIO_HISR_C2HCMD | SDIO_HISR_CPWM1 | SDIO_HISR_CPWM2 |\
- SDIO_HISR_HSISR_IND | SDIO_HISR_GTINT3_IND | SDIO_HISR_GTINT4_IND |\
- SDIO_HISR_PSTIMEOUT | SDIO_HISR_OCPINT)
-
-/* SDIO HCI Suspend Control Register */
-#define HCI_RESUME_PWR_RDY BIT(1)
-#define HCI_SUS_CTRL BIT(0)
-
-/* SDIO Tx FIFO related */
-/* The number of Tx FIFO free page */
-#define SDIO_TX_FREE_PG_QUEUE 4
-#define SDIO_TX_FIFO_PAGE_SZ 128
-
/* 0xFE00h ~ 0xFE55h USB Configuration */
/* 2 USB Information (0xFE17) */
@@ -1276,14 +1035,6 @@ So the following defines for 92C is not entire!!!!!!
/* GPS function enable */
#define GPS_FUNC_EN BIT(22)
-/* 3 REG_LIFECTRL_CTRL */
-#define HAL92C_EN_PKT_LIFE_TIME_BK BIT(3)
-#define HAL92C_EN_PKT_LIFE_TIME_BE BIT(2)
-#define HAL92C_EN_PKT_LIFE_TIME_VI BIT(1)
-#define HAL92C_EN_PKT_LIFE_TIME_VO BIT(0)
-
-#define HAL92C_MSDU_LIFE_TIME_UNIT 128 /* in us */
-
/* General definitions */
#define LAST_ENTRY_OF_TX_PKT_BUFFER 176 /* 22k 22528 bytes */
@@ -1309,48 +1060,15 @@ So the following defines for 92C is not entire!!!!!!
#define EEPROM_CUSTOMERID_88E 0xC5
#define EEPROM_RF_ANTENNA_OPT_88E 0xC9
-/* RTL88EE */
-#define EEPROM_MAC_ADDR_88EE 0xD0
-#define EEPROM_VID_88EE 0xD6
-#define EEPROM_DID_88EE 0xD8
-#define EEPROM_SVID_88EE 0xDA
-#define EEPROM_SMID_88EE 0xDC
-
/* RTL88EU */
#define EEPROM_MAC_ADDR_88EU 0xD7
#define EEPROM_VID_88EU 0xD0
#define EEPROM_PID_88EU 0xD2
#define EEPROM_USB_OPTIONAL_FUNCTION0 0xD4
-/* RTL88ES */
-#define EEPROM_MAC_ADDR_88ES 0x11A
-
/* EEPROM/Efuse Value Type */
#define EETYPE_TX_PWR 0x0
-/* Default Value for EEPROM or EFUSE!!! */
-#define EEPROM_Default_TSSI 0x0
-#define EEPROM_Default_TxPowerDiff 0x0
-#define EEPROM_Default_CrystalCap 0x5
-/* Default: 2X2, RTL8192CE(QFPN68) */
-#define EEPROM_Default_BoardType 0x02
-#define EEPROM_Default_TxPower 0x1010
-#define EEPROM_Default_HT2T_TxPwr 0x10
-
-#define EEPROM_Default_LegacyHTTxPowerDiff 0x3
-#define EEPROM_Default_ThermalMeter 0x12
-
-#define EEPROM_Default_AntTxPowerDiff 0x0
-#define EEPROM_Default_TxPwDiff_CrystalCap 0x5
-#define EEPROM_Default_TxPowerLevel 0x2A
-
-#define EEPROM_Default_HT40_2SDiff 0x0
-/* HT20<->40 default Tx Power Index Difference */
-#define EEPROM_Default_HT20_Diff 2
-#define EEPROM_Default_LegacyHTTxPowerDiff 0x3
-#define EEPROM_Default_HT40_PwrMaxOffset 0
-#define EEPROM_Default_HT20_PwrMaxOffset 0
-
#define EEPROM_Default_CrystalCap_88E 0x20
#define EEPROM_Default_ThermalMeter_88E 0x18
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_xmit.h b/drivers/staging/rtl8188eu/include/rtl8188e_xmit.h
index 617c2273b41b..72a2bb812c9a 100644
--- a/drivers/staging/rtl8188eu/include/rtl8188e_xmit.h
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_xmit.h
@@ -154,7 +154,4 @@ bool rtl8188eu_xmitframe_complete(struct adapter *padapter,
void handle_txrpt_ccx_88e(struct adapter *adapter, u8 *buf);
-void _dbg_dump_tx_info(struct adapter *padapter, int frame_tag,
- struct tx_desc *ptxdesc);
-
#endif /* __RTL8188E_XMIT_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_android.h b/drivers/staging/rtl8188eu/include/rtw_android.h
index d7ca7c2fb118..2c26993b8205 100644
--- a/drivers/staging/rtl8188eu/include/rtw_android.h
+++ b/drivers/staging/rtl8188eu/include/rtw_android.h
@@ -45,7 +45,6 @@ enum ANDROID_WIFI_CMD {
ANDROID_WIFI_CMD_MAX
};
-int rtw_android_cmdstr_to_num(char *cmdstr);
int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd);
#endif /* __RTW_ANDROID_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_cmd.h b/drivers/staging/rtl8188eu/include/rtw_cmd.h
index 68b8ad1a412f..4e9cb93e4b8f 100644
--- a/drivers/staging/rtl8188eu/include/rtw_cmd.h
+++ b/drivers/staging/rtl8188eu/include/rtw_cmd.h
@@ -32,10 +32,7 @@ struct cmd_obj {
struct cmd_priv {
struct completion cmd_queue_comp;
- struct completion terminate_cmdthread_comp;
struct __queue cmd_queue;
- u8 cmdthd_running;
- struct adapter *padapter;
};
#define init_h2fwcmd_w_parm_no_rsp(pcmd, pparm, code) \
@@ -54,7 +51,7 @@ void rtw_free_cmd_obj(struct cmd_obj *pcmd);
int rtw_cmd_thread(void *context);
-int rtw_init_cmd_priv(struct cmd_priv *pcmdpriv);
+void rtw_init_cmd_priv(struct cmd_priv *pcmdpriv);
enum rtw_drvextra_cmd_id {
NONE_WK_CID,
diff --git a/drivers/staging/rtl8188eu/include/rtw_debug.h b/drivers/staging/rtl8188eu/include/rtw_debug.h
deleted file mode 100644
index 1fdf16124a0d..000000000000
--- a/drivers/staging/rtl8188eu/include/rtw_debug.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-#ifndef __RTW_DEBUG_H__
-#define __RTW_DEBUG_H__
-
-#include <osdep_service.h>
-#include <drv_types.h>
-
-#define DRIVERVERSION "v4.1.4_6773.20130222"
-#define _drv_always_ 1
-#define _drv_emerg_ 2
-#define _drv_alert_ 3
-#define _drv_crit_ 4
-#define _drv_err_ 5
-#define _drv_warning_ 6
-#define _drv_notice_ 7
-#define _drv_info_ 8
-#define _drv_debug_ 9
-
-#define _module_rtl871x_xmit_c_ BIT(0)
-#define _module_xmit_osdep_c_ BIT(1)
-#define _module_rtl871x_recv_c_ BIT(2)
-#define _module_recv_osdep_c_ BIT(3)
-#define _module_rtl871x_mlme_c_ BIT(4)
-#define _module_mlme_osdep_c_ BIT(5)
-#define _module_rtl871x_sta_mgt_c_ BIT(6)
-#define _module_rtl871x_cmd_c_ BIT(7)
-#define _module_cmd_osdep_c_ BIT(8)
-#define _module_rtl871x_io_c_ BIT(9)
-#define _module_io_osdep_c_ BIT(10)
-#define _module_os_intfs_c_ BIT(11)
-#define _module_rtl871x_security_c_ BIT(12)
-#define _module_rtl871x_eeprom_c_ BIT(13)
-#define _module_hal_init_c_ BIT(14)
-#define _module_hci_hal_init_c_ BIT(15)
-#define _module_rtl871x_ioctl_c_ BIT(16)
-#define _module_rtl871x_ioctl_set_c_ BIT(17)
-#define _module_rtl871x_ioctl_query_c_ BIT(18)
-#define _module_rtl871x_pwrctrl_c_ BIT(19)
-#define _module_hci_intfs_c_ BIT(20)
-#define _module_hci_ops_c_ BIT(21)
-#define _module_osdep_service_c_ BIT(22)
-#define _module_mp_ BIT(23)
-#define _module_hci_ops_os_c_ BIT(24)
-#define _module_rtl871x_ioctl_os_c BIT(25)
-#define _module_rtl8712_cmd_c_ BIT(26)
-#define _module_rtl8192c_xmit_c_ BIT(27)
-#define _module_hal_xmit_c_ BIT(28)
-#define _module_efuse_ BIT(29)
-#define _module_rtl8712_recv_c_ BIT(30)
-#define _module_rtl8712_led_c_ BIT(31)
-
-#define DRIVER_PREFIX "R8188EU: "
-
-extern u32 GlobalDebugLevel;
-
-#define DBG_88E_LEVEL(_level, fmt, arg...) \
- do { \
- if (_level <= GlobalDebugLevel) \
- pr_info(DRIVER_PREFIX fmt, ##arg); \
- } while (0)
-
-#define DBG_88E(...) \
- do { \
- if (_drv_err_ <= GlobalDebugLevel) \
- pr_info(DRIVER_PREFIX __VA_ARGS__); \
- } while (0)
-
-#define MSG_88E(...) \
- do { \
- if (_drv_err_ <= GlobalDebugLevel) \
- pr_info(DRIVER_PREFIX __VA_ARGS__); \
- } while (0)
-
-#define RT_TRACE(_comp, _level, fmt) \
- do { \
- if (_level <= GlobalDebugLevel) { \
- pr_info("%s [0x%08x,%d]", DRIVER_PREFIX, \
- (unsigned int)_comp, _level); \
- pr_info fmt; \
- } \
- } while (0)
-
-#define RT_PRINT_DATA(_comp, _level, _titlestring, _hexdata, _hexdatalen)\
- do { \
- if (_level <= GlobalDebugLevel) { \
- int __i; \
- u8 *ptr = (u8 *)_hexdata; \
- pr_info("%s", DRIVER_PREFIX); \
- pr_info(_titlestring); \
- for (__i = 0; __i < (int)_hexdatalen; __i++) { \
- pr_info("%02X%s", ptr[__i], \
- (((__i + 1) % 4) == 0) ? \
- " " : " "); \
- if (((__i + 1) % 16) == 0) \
- pr_cont("\n"); \
- } \
- pr_cont("\n"); \
- } \
- } while (0)
-
-int proc_get_drv_version(char *page, char **start,
- off_t offset, int count,
- int *eof, void *data);
-
-int proc_get_write_reg(char *page, char **start,
- off_t offset, int count,
- int *eof, void *data);
-
-int proc_set_write_reg(struct file *file, const char __user *buffer,
- unsigned long count, void *data);
-int proc_get_read_reg(char *page, char **start,
- off_t offset, int count,
- int *eof, void *data);
-
-int proc_set_read_reg(struct file *file, const char __user *buffer,
- unsigned long count, void *data);
-
-int proc_get_adapter_state(char *page, char **start,
- off_t offset, int count,
- int *eof, void *data);
-
-int proc_get_best_channel(char *page, char **start,
- off_t offset, int count,
- int *eof, void *data);
-
-#endif /* __RTW_DEBUG_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_efuse.h b/drivers/staging/rtl8188eu/include/rtw_efuse.h
index 74182c32c4ec..bb5e2b5d4bf1 100644
--- a/drivers/staging/rtl8188eu/include/rtw_efuse.h
+++ b/drivers/staging/rtl8188eu/include/rtw_efuse.h
@@ -23,9 +23,6 @@
#define PGPKT_DATA_SIZE 8
-#define EFUSE_WIFI 0
-#define EFUSE_BT 1
-
/* E-Fuse */
#define EFUSE_MAP_SIZE 512
#define EFUSE_MAX_SIZE 256
@@ -60,13 +57,11 @@ u8 Efuse_CalculateWordCnts(u8 word_en);
u8 efuse_OneByteRead(struct adapter *adapter, u16 addr, u8 *data);
u8 efuse_OneByteWrite(struct adapter *adapter, u16 addr, u8 data);
-void efuse_ReadEFuse(struct adapter *Adapter, u8 efuseType, u16 _offset,
- u16 _size_byte, u8 *pbuf);
int Efuse_PgPacketRead(struct adapter *adapt, u8 offset, u8 *data);
bool Efuse_PgPacketWrite(struct adapter *adapter, u8 offset, u8 word, u8 *data);
void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata);
u8 Efuse_WordEnableDataWrite(struct adapter *adapter, u16 efuse_addr,
u8 word_en, u8 *data);
-void EFUSE_ShadowMapUpdate(struct adapter *adapter, u8 efusetype);
+void EFUSE_ShadowMapUpdate(struct adapter *adapter);
#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_led.h b/drivers/staging/rtl8188eu/include/rtw_led.h
index ee62ed76a465..5f65c3e1e46f 100644
--- a/drivers/staging/rtl8188eu/include/rtw_led.h
+++ b/drivers/staging/rtl8188eu/include/rtw_led.h
@@ -52,7 +52,7 @@ struct LED_871x {
* either RTW_LED_ON or RTW_LED_OFF are.
*/
- u8 bLedOn; /* true if LED is ON, false if LED is OFF. */
+ u8 led_on; /* true if LED is ON, false if LED is OFF. */
u8 bLedBlinkInProgress; /* true if it is blinking, false o.w.. */
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme.h b/drivers/staging/rtl8188eu/include/rtw_mlme.h
index 1b74b32b8a81..2f02316906d0 100644
--- a/drivers/staging/rtl8188eu/include/rtw_mlme.h
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme.h
@@ -111,8 +111,6 @@ struct mlme_priv {
u8 to_join; /* flag */
u8 to_roaming; /* roaming trying times */
- u8 *nic_hdl;
-
struct list_head *pscanned;
struct __queue free_bss_pool;
struct __queue scanned_queue;
@@ -222,8 +220,6 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf);
void rtw_joinbss_event_callback(struct adapter *adapter, u8 *pbuf);
void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf);
void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf);
-void rtw_atimdone_event_callback(struct adapter *adapter, u8 *pbuf);
-void rtw_cpwm_event_callback(struct adapter *adapter, u8 *pbuf);
void indicate_wx_scan_complete_event(struct adapter *padapter);
void rtw_indicate_wx_assoc_event(struct adapter *padapter);
void rtw_indicate_wx_disassoc_event(struct adapter *padapter);
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
index 03d55eb7dc16..c4fcfa986726 100644
--- a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
@@ -383,7 +383,6 @@ struct p2p_oper_class_map {
};
struct mlme_ext_priv {
- struct adapter *padapter;
u8 mlmeext_init;
atomic_t event_seq;
u16 mgnt_seq;
@@ -662,7 +661,7 @@ static struct fwevent wlanevents[] = {
{0, &rtw_joinbss_event_callback}, /*10*/
{sizeof(struct stassoc_event), &rtw_stassoc_event_callback},
{sizeof(struct stadel_event), &rtw_stadel_event_callback},
- {0, &rtw_atimdone_event_callback},
+ {0, NULL},
{0, rtw_dummy_event_callback},
{0, NULL}, /*15*/
{0, NULL},
@@ -672,7 +671,7 @@ static struct fwevent wlanevents[] = {
{0, NULL}, /*20*/
{0, NULL},
{0, NULL},
- {0, &rtw_cpwm_event_callback},
+ {0, NULL},
{0, NULL},
};
diff --git a/drivers/staging/rtl8188eu/include/rtw_recv.h b/drivers/staging/rtl8188eu/include/rtw_recv.h
index e20bab41708a..8c906b666b62 100644
--- a/drivers/staging/rtl8188eu/include/rtw_recv.h
+++ b/drivers/staging/rtl8188eu/include/rtw_recv.h
@@ -231,8 +231,7 @@ struct recv_frame *_rtw_alloc_recvframe(struct __queue *pfree_recv_queue);
struct recv_frame *rtw_alloc_recvframe(struct __queue *pfree_recv_queue);
void rtw_init_recvframe(struct recv_frame *precvframe,
struct recv_priv *precvpriv);
-int rtw_free_recvframe(struct recv_frame *precvframe,
- struct __queue *pfree_recv_queue);
+void rtw_free_recvframe(struct recv_frame *precvframe, struct __queue *pfree_recv_queue);
#define rtw_dequeue_recvframe(queue) rtw_alloc_recvframe(queue)
int _rtw_enqueue_recvframe(struct recv_frame *precvframe,
struct __queue *queue);
diff --git a/drivers/staging/rtl8188eu/include/wifi.h b/drivers/staging/rtl8188eu/include/wifi.h
index 84e17330628e..716fec036e54 100644
--- a/drivers/staging/rtl8188eu/include/wifi.h
+++ b/drivers/staging/rtl8188eu/include/wifi.h
@@ -25,42 +25,6 @@ enum WIFI_FRAME_TYPE {
WIFI_QOS_DATA_TYPE = (BIT(7) | BIT(3)), /* QoS Data */
};
-enum WIFI_FRAME_SUBTYPE {
- /* below is for mgt frame */
- WIFI_ASSOCREQ = (0 | WIFI_MGT_TYPE),
- WIFI_ASSOCRSP = (BIT(4) | WIFI_MGT_TYPE),
- WIFI_REASSOCREQ = (BIT(5) | WIFI_MGT_TYPE),
- WIFI_REASSOCRSP = (BIT(5) | BIT(4) | WIFI_MGT_TYPE),
- WIFI_PROBEREQ = (BIT(6) | WIFI_MGT_TYPE),
- WIFI_PROBERSP = (BIT(6) | BIT(4) | WIFI_MGT_TYPE),
- WIFI_BEACON = (BIT(7) | WIFI_MGT_TYPE),
- WIFI_ATIM = (BIT(7) | BIT(4) | WIFI_MGT_TYPE),
- WIFI_DISASSOC = (BIT(7) | BIT(5) | WIFI_MGT_TYPE),
- WIFI_AUTH = (BIT(7) | BIT(5) | BIT(4) | WIFI_MGT_TYPE),
- WIFI_DEAUTH = (BIT(7) | BIT(6) | WIFI_MGT_TYPE),
- WIFI_ACTION = (BIT(7) | BIT(6) | BIT(4) | WIFI_MGT_TYPE),
-
- /* below is for control frame */
- WIFI_PSPOLL = (BIT(7) | BIT(5) | WIFI_CTRL_TYPE),
- WIFI_RTS = (BIT(7) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE),
- WIFI_CTS = (BIT(7) | BIT(6) | WIFI_CTRL_TYPE),
- WIFI_ACK = (BIT(7) | BIT(6) | BIT(4) | WIFI_CTRL_TYPE),
- WIFI_CFEND = (BIT(7) | BIT(6) | BIT(5) | WIFI_CTRL_TYPE),
- WIFI_CFEND_CFACK = (BIT(7) | BIT(6) | BIT(5) | BIT(4) |
- WIFI_CTRL_TYPE),
-
- /* below is for data frame */
- WIFI_DATA = (0 | WIFI_DATA_TYPE),
- WIFI_DATA_CFACK = (BIT(4) | WIFI_DATA_TYPE),
- WIFI_DATA_CFPOLL = (BIT(5) | WIFI_DATA_TYPE),
- WIFI_DATA_CFACKPOLL = (BIT(5) | BIT(4) | WIFI_DATA_TYPE),
- WIFI_DATA_NULL = (BIT(6) | WIFI_DATA_TYPE),
- WIFI_CF_ACK = (BIT(6) | BIT(4) | WIFI_DATA_TYPE),
- WIFI_CF_POLL = (BIT(6) | BIT(5) | WIFI_DATA_TYPE),
- WIFI_CF_ACKPOLL = (BIT(6) | BIT(5) | BIT(4) | WIFI_DATA_TYPE),
- WIFI_QOS_DATA_NULL = (BIT(6) | WIFI_QOS_DATA_TYPE),
-};
-
#define SetToDs(pbuf) \
*(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_TODS)
diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
index c95ae4d6a3b6..b958a8d882b0 100644
--- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
@@ -11,7 +11,6 @@
#include <osdep_service.h>
#include <drv_types.h>
#include <wlan_bssdef.h>
-#include <rtw_debug.h>
#include <wifi.h>
#include <rtw_mlme.h>
#include <rtw_mlme_ext.h>
@@ -71,7 +70,6 @@ void rtw_indicate_wx_assoc_event(struct adapter *padapter)
memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress, ETH_ALEN);
- DBG_88E_LEVEL(_drv_always_, "assoc success\n");
wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
}
@@ -84,7 +82,6 @@ void rtw_indicate_wx_disassoc_event(struct adapter *padapter)
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
eth_zero_addr(wrqu.ap_addr.sa_data);
- DBG_88E_LEVEL(_drv_always_, "indicate disassoc\n");
wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
}
@@ -224,7 +221,7 @@ static char *translate_scan(struct adapter *padapter,
/* parsing WPA/WPA2 IE */
{
u8 *buf;
- u8 wpa_ie[255], rsn_ie[255];
+ u8 *wpa_ie, *rsn_ie;
u16 wpa_len = 0, rsn_len = 0;
u8 *p;
@@ -232,9 +229,15 @@ static char *translate_scan(struct adapter *padapter,
if (!buf)
return start;
+ wpa_ie = kzalloc(255, GFP_ATOMIC);
+ if (!wpa_ie)
+ return start;
+
+ rsn_ie = kzalloc(255, GFP_ATOMIC);
+ if (!rsn_ie)
+ return start;
+
rtw_get_sec_ie(pnetwork->network.ies, pnetwork->network.ie_length, 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));
if (wpa_len > 0) {
p = buf;
@@ -268,6 +271,8 @@ static char *translate_scan(struct adapter *padapter,
start = iwe_stream_add_point(info, start, stop, &iwe, rsn_ie);
}
kfree(buf);
+ kfree(wpa_ie);
+ kfree(rsn_ie);
}
{/* parsing WPS IE */
@@ -315,26 +320,20 @@ static int wpa_set_auth_algs(struct net_device *dev, u32 value)
int ret = 0;
if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) {
- DBG_88E("%s, AUTH_ALG_SHARED_KEY and AUTH_ALG_OPEN_SYSTEM [value:0x%x]\n", __func__, value);
padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch;
padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
} else if (value & AUTH_ALG_SHARED_KEY) {
- DBG_88E("%s, AUTH_ALG_SHARED_KEY [value:0x%x]\n", __func__, value);
padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared;
padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared;
} else if (value & AUTH_ALG_OPEN_SYSTEM) {
- DBG_88E("%s, AUTH_ALG_OPEN_SYSTEM\n", __func__);
if (padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK) {
padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
}
- } else if (value & AUTH_ALG_LEAP) {
- DBG_88E("%s, AUTH_ALG_LEAP\n", __func__);
} else {
- DBG_88E("%s, error!\n", __func__);
ret = -EINVAL;
}
return ret;
@@ -368,9 +367,6 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
}
if (strcmp(param->u.crypt.alg, "WEP") == 0) {
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("%s, crypt.alg = WEP\n", __func__));
- DBG_88E("%s, crypt.alg = WEP\n", __func__);
-
padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
@@ -378,22 +374,15 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
wep_key_idx = param->u.crypt.idx;
wep_key_len = param->u.crypt.key_len;
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("(1)wep_key_idx =%d\n", wep_key_idx));
- DBG_88E("(1)wep_key_idx =%d\n", wep_key_idx);
-
if (wep_key_idx > WEP_KEYS)
return -EINVAL;
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("(2)wep_key_idx =%d\n", wep_key_idx));
-
if (wep_key_len > 0) {
wep_key_len = wep_key_len <= 5 ? 5 : 13;
wep_total_len = wep_key_len + offsetof(struct ndis_802_11_wep, KeyMaterial);
pwep = (struct ndis_802_11_wep *)rtw_malloc(wep_total_len);
- if (!pwep) {
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("%s: pwep allocate fail !!!\n", __func__));
+ if (!pwep)
goto exit;
- }
memset(pwep, 0, wep_total_len);
pwep->KeyLength = wep_key_len;
pwep->Length = wep_total_len;
@@ -409,11 +398,9 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
pwep->KeyIndex |= 0x80000000;
memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength);
if (param->u.crypt.set_tx) {
- DBG_88E("wep, set_tx = 1\n");
if (rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL)
ret = -EOPNOTSUPP;
} else {
- DBG_88E("wep, set_tx = 0\n");
if (wep_key_idx >= WEP_KEYS) {
ret = -EOPNOTSUPP;
goto exit;
@@ -450,15 +437,12 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
padapter->securitypriv.busetkipkey = false;
}
- DBG_88E(" ~~~~set sta key:unicastkey\n");
-
rtw_setstakey_cmd(padapter, (unsigned char *)psta, true);
} else { /* group key */
memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, min_t(u16, param->u.crypt.key_len, 16));
memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey, &param->u.crypt.key[16], 8);
memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey, &param->u.crypt.key[24], 8);
padapter->securitypriv.binstallGrpkey = true;
- DBG_88E(" ~~~~set sta key:groupkey\n");
padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx;
@@ -507,17 +491,7 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie
goto exit;
}
- /* dump */
- {
- int i;
-
- DBG_88E("\n wpa_ie(length:%d):\n", ielen);
- for (i = 0; i < ielen; i += 8)
- DBG_88E("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]);
- }
-
if (ielen < RSN_HEADER_LEN) {
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("Ie len too short %d\n", ielen));
ret = -1;
goto exit;
}
@@ -588,8 +562,6 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie
while (cnt < ielen) {
eid = buf[cnt];
if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(&buf[cnt + 2], wps_oui, 4))) {
- DBG_88E("SET WPS_IE\n");
-
padapter->securitypriv.wps_ie_len = min(buf[cnt + 1] + 2, MAX_WPA_IE_LEN << 2);
memcpy(padapter->securitypriv.wps_ie, &buf[cnt], padapter->securitypriv.wps_ie_len);
@@ -602,10 +574,6 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie
}
}
}
-
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
- ("%s: pairwise_cipher = 0x%08x padapter->securitypriv.ndisencryptstatus =%d padapter->securitypriv.ndisauthtype =%d\n",
- __func__, pairwise_cipher, padapter->securitypriv.ndisencryptstatus, padapter->securitypriv.ndisauthtype));
exit:
kfree(buf);
return ret;
@@ -625,8 +593,6 @@ static int rtw_wx_get_name(struct net_device *dev,
struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
NDIS_802_11_RATES_EX *prates = NULL;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("cmd_code =%x\n", info->cmd));
-
if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) {
/* parsing HT_CAP_IE */
p = rtw_get_ie(&pcur_bss->ies[12], WLAN_EID_HT_CAPABILITY, &ht_ielen, pcur_bss->ie_length - 12);
@@ -657,14 +623,6 @@ static int rtw_wx_get_name(struct net_device *dev,
return 0;
}
-static int rtw_wx_set_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+%s\n", __func__));
- return 0;
-}
-
static int rtw_wx_get_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
@@ -707,23 +665,18 @@ static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
switch (wrqu->mode) {
case IW_MODE_AUTO:
networkType = Ndis802_11AutoUnknown;
- DBG_88E("set_mode = IW_MODE_AUTO\n");
break;
case IW_MODE_ADHOC:
networkType = Ndis802_11IBSS;
- DBG_88E("set_mode = IW_MODE_ADHOC\n");
break;
case IW_MODE_MASTER:
networkType = Ndis802_11APMode;
- DBG_88E("set_mode = IW_MODE_MASTER\n");
break;
case IW_MODE_INFRA:
networkType = Ndis802_11Infrastructure;
- DBG_88E("set_mode = IW_MODE_INFRA\n");
break;
default:
ret = -EINVAL;
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("\n Mode: %s is not supported\n", iw_operation_mode[wrqu->mode]));
goto exit;
}
if (!rtw_set_802_11_infrastructure_mode(padapter, networkType)) {
@@ -741,8 +694,6 @@ static int rtw_wx_get_mode(struct net_device *dev, struct iw_request_info *a,
struct adapter *padapter = netdev_priv(dev);
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s\n", __func__));
-
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
wrqu->mode = IW_MODE_INFRA;
else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ||
@@ -770,7 +721,6 @@ static int rtw_wx_set_pmkid(struct net_device *dev,
memcpy(strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN);
if (pPMK->cmd == IW_PMKSA_ADD) {
- DBG_88E("[%s] IW_PMKSA_ADD!\n", __func__);
if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN))
return ret;
ret = true;
@@ -780,7 +730,6 @@ static int rtw_wx_set_pmkid(struct net_device *dev,
for (j = 0; j < NUM_PMKID_CACHE; j++) {
if (!memcmp(psecuritypriv->PMKIDList[j].bssid, strIssueBssid, ETH_ALEN)) {
/* BSSID is matched, the same AP => rewrite with new PMKID. */
- DBG_88E("[%s] BSSID exists in the PMKList.\n", __func__);
memcpy(psecuritypriv->PMKIDList[j].PMKID, pPMK->pmkid, IW_PMKID_LEN);
psecuritypriv->PMKIDList[j].used = true;
psecuritypriv->PMKIDIndex = j + 1;
@@ -791,9 +740,6 @@ static int rtw_wx_set_pmkid(struct net_device *dev,
if (!blInserted) {
/* Find a new entry */
- DBG_88E("[%s] Use the new entry index = %d for this PMKID.\n",
- __func__, psecuritypriv->PMKIDIndex);
-
memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bssid, strIssueBssid, ETH_ALEN);
memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, pPMK->pmkid, IW_PMKID_LEN);
@@ -803,7 +749,6 @@ static int rtw_wx_set_pmkid(struct net_device *dev,
psecuritypriv->PMKIDIndex = 0;
}
} else if (pPMK->cmd == IW_PMKSA_REMOVE) {
- DBG_88E("[%s] IW_PMKSA_REMOVE!\n", __func__);
ret = true;
for (j = 0; j < NUM_PMKID_CACHE; j++) {
if (!memcmp(psecuritypriv->PMKIDList[j].bssid, strIssueBssid, ETH_ALEN)) {
@@ -814,7 +759,6 @@ static int rtw_wx_set_pmkid(struct net_device *dev,
}
}
} else if (pPMK->cmd == IW_PMKSA_FLUSH) {
- DBG_88E("[%s] IW_PMKSA_FLUSH!\n", __func__);
memset(&psecuritypriv->PMKIDList[0], 0x00, sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE);
psecuritypriv->PMKIDIndex = 0;
ret = true;
@@ -843,8 +787,6 @@ static int rtw_wx_get_range(struct net_device *dev,
u16 val;
int i;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s. cmd_code =%x\n", __func__, info->cmd));
-
wrqu->data.length = sizeof(*range);
memset(range, 0, sizeof(*range));
@@ -952,12 +894,9 @@ static int rtw_wx_set_wap(struct net_device *dev,
authmode = padapter->securitypriv.ndisauthtype;
spin_lock_bh(&queue->lock);
phead = get_list_head(queue);
- pmlmepriv->pscanned = phead->next;
-
- while (phead != pmlmepriv->pscanned) {
- pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list);
-
- pmlmepriv->pscanned = pmlmepriv->pscanned->next;
+ list_for_each(pmlmepriv->pscanned, phead) {
+ pnetwork = list_entry(pmlmepriv->pscanned,
+ struct wlan_network, list);
dst_bssid = pnetwork->network.MacAddress;
@@ -998,8 +937,6 @@ static int rtw_wx_get_wap(struct net_device *dev,
eth_zero_addr(wrqu->ap_addr.sa_data);
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s\n", __func__));
-
if (check_fwstate(pmlmepriv, _FW_LINKED) ||
check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ||
check_fwstate(pmlmepriv, WIFI_AP_STATE))
@@ -1014,19 +951,12 @@ static int rtw_wx_set_mlme(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
int ret = 0;
- u16 reason;
struct adapter *padapter = netdev_priv(dev);
struct iw_mlme *mlme = (struct iw_mlme *)extra;
if (!mlme)
return -1;
- DBG_88E("%s\n", __func__);
-
- reason = mlme->reason_code;
-
- DBG_88E("%s, cmd =%d, reason =%d\n", __func__, mlme->cmd, reason);
-
switch (mlme->cmd) {
case IW_MLME_DEAUTH:
if (!rtw_set_802_11_disassociate(padapter))
@@ -1051,15 +981,12 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT];
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s\n", __func__));
-
if (!rtw_pwr_wakeup(padapter)) {
ret = -1;
goto exit;
}
if (padapter->bDriverStopped) {
- DBG_88E("bDriverStopped =%d\n", padapter->bDriverStopped);
ret = -1;
goto exit;
}
@@ -1103,15 +1030,11 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
memcpy(ssid[0].ssid, req->essid, len);
ssid[0].ssid_length = len;
- DBG_88E("IW_SCAN_THIS_ESSID, ssid =%s, len =%d\n", req->essid, req->essid_len);
-
spin_lock_bh(&pmlmepriv->lock);
_status = rtw_sitesurvey_cmd(padapter, ssid, 1, NULL, 0);
spin_unlock_bh(&pmlmepriv->lock);
- } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) {
- DBG_88E("%s, req->scan_type == IW_SCAN_TYPE_PASSIVE\n", __func__);
}
} else {
if (wrqu->data.length >= WEXT_CSCAN_HEADER_SIZE &&
@@ -1189,9 +1112,6 @@ static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
u32 wait_for_surveydone;
int wait_status;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s\n", __func__));
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, (" Start of Query SIOCGIWSCAN .\n"));
-
if (padapter->pwrctrlpriv.brfoffbyhw && padapter->bDriverStopped) {
ret = -EINVAL;
goto exit;
@@ -1211,21 +1131,17 @@ static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
spin_lock_bh(&pmlmepriv->scanned_queue.lock);
phead = get_list_head(queue);
- plist = phead->next;
-
- while (phead != plist) {
+ list_for_each(plist, phead) {
if ((stop - ev) < SCAN_ITEM_SIZE) {
ret = -E2BIG;
break;
}
- pnetwork = container_of(plist, struct wlan_network, list);
+ pnetwork = list_entry(plist, struct wlan_network, list);
/* report network only if the current channel set contains the channel to which this network belongs */
if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0)
ev = translate_scan(padapter, a, pnetwork, ev, stop);
-
- plist = plist->next;
}
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
@@ -1257,8 +1173,6 @@ static int rtw_wx_set_essid(struct net_device *dev,
uint ret = 0, len;
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
- ("+%s: fw_state = 0x%08x\n", __func__, get_fwstate(pmlmepriv)));
if (!rtw_pwr_wakeup(padapter)) {
ret = -1;
goto exit;
@@ -1280,38 +1194,24 @@ static int rtw_wx_set_essid(struct net_device *dev,
}
authmode = padapter->securitypriv.ndisauthtype;
- DBG_88E("=>%s\n", __func__);
if (wrqu->essid.flags && wrqu->essid.length) {
len = min_t(uint, wrqu->essid.length, IW_ESSID_MAX_SIZE);
- if (wrqu->essid.length != 33)
- DBG_88E("ssid =%s, len =%d\n", extra, wrqu->essid.length);
-
memset(&ndis_ssid, 0, sizeof(struct ndis_802_11_ssid));
ndis_ssid.ssid_length = len;
memcpy(ndis_ssid.ssid, extra, len);
src_ssid = ndis_ssid.ssid;
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("%s: ssid =[%s]\n", __func__, src_ssid));
spin_lock_bh(&queue->lock);
phead = get_list_head(queue);
- pmlmepriv->pscanned = phead->next;
-
- while (phead != pmlmepriv->pscanned) {
- pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list);
-
- pmlmepriv->pscanned = pmlmepriv->pscanned->next;
+ list_for_each(pmlmepriv->pscanned, phead) {
+ pnetwork = list_entry(pmlmepriv->pscanned,
+ struct wlan_network, list);
dst_ssid = pnetwork->network.ssid.ssid;
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
- ("%s: dst_ssid =%s\n", __func__,
- pnetwork->network.ssid.ssid));
-
if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.ssid_length)) &&
(pnetwork->network.ssid.ssid_length == ndis_ssid.ssid_length)) {
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
- ("%s: find match, set infra mode\n", __func__));
if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode)
@@ -1328,8 +1228,6 @@ static int rtw_wx_set_essid(struct net_device *dev,
}
}
spin_unlock_bh(&queue->lock);
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
- ("set ssid: set_802_11_auth. mode =%d\n", authmode));
rtw_set_802_11_authentication_mode(padapter, authmode);
if (!rtw_set_802_11_ssid(padapter, &ndis_ssid)) {
ret = -1;
@@ -1338,8 +1236,6 @@ static int rtw_wx_set_essid(struct net_device *dev,
}
exit:
- DBG_88E("<=%s, ret %d\n", __func__, ret);
-
return ret;
}
@@ -1352,8 +1248,6 @@ static int rtw_wx_get_essid(struct net_device *dev,
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s\n", __func__));
-
if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
(check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) {
len = pcur_bss->ssid.ssid_length;
@@ -1379,9 +1273,6 @@ static int rtw_wx_set_rate(struct net_device *dev,
u32 ratevalue = 0;
u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s\n", __func__));
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("target_rate = %d, fixed = %d\n", target_rate, fixed));
-
if (target_rate == -1) {
ratevalue = 11;
goto set_rate;
@@ -1440,8 +1331,6 @@ set_rate:
} else {
datarates[i] = 0xff;
}
-
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("datarate_inx =%d\n", datarates[i]));
}
return 0;
@@ -1480,8 +1369,6 @@ static int rtw_wx_set_rts(struct net_device *dev,
padapter->registrypriv.rts_thresh = wrqu->rts.value;
}
- DBG_88E("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh);
-
return 0;
}
@@ -1491,8 +1378,6 @@ static int rtw_wx_get_rts(struct net_device *dev,
{
struct adapter *padapter = netdev_priv(dev);
- DBG_88E("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh);
-
wrqu->rts.value = padapter->registrypriv.rts_thresh;
wrqu->rts.fixed = 0; /* no auto select */
/* wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); */
@@ -1516,8 +1401,6 @@ static int rtw_wx_set_frag(struct net_device *dev,
padapter->xmitpriv.frag_len = wrqu->frag.value & ~0x1;
}
- DBG_88E("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len);
-
return 0;
}
@@ -1527,8 +1410,6 @@ static int rtw_wx_get_frag(struct net_device *dev,
{
struct adapter *padapter = netdev_priv(dev);
- DBG_88E("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len);
-
wrqu->frag.value = padapter->xmitpriv.frag_len;
wrqu->frag.fixed = 0; /* no auto select */
@@ -1559,14 +1440,11 @@ static int rtw_wx_set_enc(struct net_device *dev,
struct adapter *padapter = netdev_priv(dev);
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
- DBG_88E("+%s, flags = 0x%x\n", __func__, erq->flags);
-
memset(&wep, 0, sizeof(struct ndis_802_11_wep));
key = erq->flags & IW_ENCODE_INDEX;
if (erq->flags & IW_ENCODE_DISABLED) {
- DBG_88E("EncryptionDisabled\n");
padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
@@ -1585,12 +1463,10 @@ static int rtw_wx_set_enc(struct net_device *dev,
} else {
keyindex_provided = 0;
key = padapter->securitypriv.dot11PrivacyKeyIndex;
- DBG_88E("%s, key =%d\n", __func__, key);
}
/* set authentication mode */
if (erq->flags & IW_ENCODE_OPEN) {
- DBG_88E("%s():IW_ENCODE_OPEN\n", __func__);
padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */
padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
@@ -1598,7 +1474,6 @@ static int rtw_wx_set_enc(struct net_device *dev,
authmode = Ndis802_11AuthModeOpen;
padapter->securitypriv.ndisauthtype = authmode;
} else if (erq->flags & IW_ENCODE_RESTRICTED) {
- DBG_88E("%s():IW_ENCODE_RESTRICTED\n", __func__);
padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared;
padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
@@ -1606,8 +1481,6 @@ static int rtw_wx_set_enc(struct net_device *dev,
authmode = Ndis802_11AuthModeShared;
padapter->securitypriv.ndisauthtype = authmode;
} else {
- DBG_88E("%s():erq->flags = 0x%x\n", __func__, erq->flags);
-
padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */
padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
@@ -1628,8 +1501,6 @@ static int rtw_wx_set_enc(struct net_device *dev,
/* set key_id only, no given KeyMaterial(erq->length == 0). */
padapter->securitypriv.dot11PrivacyKeyIndex = key;
- DBG_88E("(keyindex_provided == 1), keyid =%d, key_len =%d\n", key, padapter->securitypriv.dot11DefKeylen[key]);
-
switch (padapter->securitypriv.dot11DefKeylen[key]) {
case 5:
padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
@@ -1807,7 +1678,6 @@ static int rtw_wx_set_auth(struct net_device *dev,
if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
LeaveAllPowerSaveMode(padapter);
rtw_disassoc_cmd(padapter, 500, false);
- DBG_88E("%s...call rtw_indicate_disconnect\n ", __func__);
rtw_indicate_disconnect(padapter);
rtw_free_assoc_resources(padapter);
}
@@ -1910,12 +1780,6 @@ static int rtw_wx_get_nick(struct net_device *dev,
return 0;
}
-static int dummy(struct net_device *dev, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- return -1;
-}
-
static int wpa_set_param(struct net_device *dev, u8 name, u32 value)
{
uint ret = 0;
@@ -1934,8 +1798,6 @@ static int wpa_set_param(struct net_device *dev, u8 name, u32 value)
padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
break;
}
- RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
- ("%s:padapter->securitypriv.ndisauthtype =%d\n", __func__, padapter->securitypriv.ndisauthtype));
break;
case IEEE_PARAM_TKIP_COUNTERMEASURES:
break;
@@ -2024,7 +1886,6 @@ static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p)
break;
default:
- DBG_88E("Unknown WPA supplicant request: %d\n", param->cmd);
ret = -EOPNOTSUPP;
break;
}
@@ -2080,8 +1941,6 @@ static int set_group_key(struct adapter *padapter, u8 *key, u8 alg, int keyid)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
int res = _SUCCESS;
- DBG_88E("%s\n", __func__);
-
pcmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
if (!pcmd) {
res = _FAIL;
@@ -2160,7 +2019,6 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct sta_priv *pstapriv = &padapter->stapriv;
- DBG_88E("%s\n", __func__);
param->u.crypt.err = 0;
param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) {
@@ -2174,23 +2032,17 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
}
} else {
psta = rtw_get_stainfo(pstapriv, param->sta_addr);
- if (!psta) {
- DBG_88E("%s(), sta has already been removed or never been added\n", __func__);
+ if (!psta)
goto exit;
- }
}
- if (strcmp(param->u.crypt.alg, "none") == 0 && (!psta)) {
+ if (strcmp(param->u.crypt.alg, "none") == 0 && (!psta))
/* todo:clear default encryption keys */
-
- DBG_88E("clear default encryption keys, keyid =%d\n", param->u.crypt.idx);
goto exit;
- }
+
if (strcmp(param->u.crypt.alg, "WEP") == 0 && (!psta)) {
- DBG_88E("r871x_set_encryption, crypt.alg = WEP\n");
wep_key_idx = param->u.crypt.idx;
wep_key_len = param->u.crypt.key_len;
- DBG_88E("r871x_set_encryption, wep_key_idx=%d, len=%d\n", wep_key_idx, wep_key_len);
if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) {
ret = -EINVAL;
goto exit;
@@ -2200,10 +2052,8 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
wep_key_len = wep_key_len <= 5 ? 5 : 13;
wep_total_len = wep_key_len + offsetof(struct ndis_802_11_wep, KeyMaterial);
pwep = (struct ndis_802_11_wep *)rtw_malloc(wep_total_len);
- if (!pwep) {
- DBG_88E(" r871x_set_encryption: pwep allocate fail !!!\n");
+ if (!pwep)
goto exit;
- }
memset(pwep, 0, wep_total_len);
@@ -2216,8 +2066,6 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength);
if (param->u.crypt.set_tx) {
- DBG_88E("wep, set_tx = 1\n");
-
psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
@@ -2235,8 +2083,6 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx);
} else {
- DBG_88E("wep, set_tx = 0\n");
-
/* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */
/* psecuritypriv->dot11PrivacyKeyIndex = keyid", but can rtw_set_key to cam */
@@ -2253,8 +2099,6 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) { /* group key */
if (param->u.crypt.set_tx == 1) {
if (strcmp(param->u.crypt.alg, "WEP") == 0) {
- DBG_88E("%s, set group_key, WEP\n", __func__);
-
memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
param->u.crypt.key, min_t(u16, param->u.crypt.key_len, 16));
@@ -2262,7 +2106,6 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
if (param->u.crypt.key_len == 13)
psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
} else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
- DBG_88E("%s, set group_key, TKIP\n", __func__);
psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
param->u.crypt.key, min_t(u16, param->u.crypt.key_len, 16));
@@ -2272,12 +2115,10 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
psecuritypriv->busetkipkey = true;
} else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
- DBG_88E("%s, set group_key, CCMP\n", __func__);
psecuritypriv->dot118021XGrpPrivacy = _AES_;
memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
param->u.crypt.key, min_t(u16, param->u.crypt.key_len, 16));
} else {
- DBG_88E("%s, set group_key, none\n", __func__);
psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
}
psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
@@ -2299,14 +2140,10 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, min_t(u16, param->u.crypt.key_len, 16));
if (strcmp(param->u.crypt.alg, "WEP") == 0) {
- DBG_88E("%s, set pairwise key, WEP\n", __func__);
-
psta->dot118021XPrivacy = _WEP40_;
if (param->u.crypt.key_len == 13)
psta->dot118021XPrivacy = _WEP104_;
} else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
- DBG_88E("%s, set pairwise key, TKIP\n", __func__);
-
psta->dot118021XPrivacy = _TKIP_;
/* set mic key */
@@ -2315,12 +2152,8 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
psecuritypriv->busetkipkey = true;
} else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
- DBG_88E("%s, set pairwise key, CCMP\n", __func__);
-
psta->dot118021XPrivacy = _AES_;
} else {
- DBG_88E("%s, set pairwise key, none\n", __func__);
-
psta->dot118021XPrivacy = _NO_PRIVACY_;
}
@@ -2386,8 +2219,6 @@ static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int
struct sta_priv *pstapriv = &padapter->stapriv;
unsigned char *pbuf = param->u.bcn_ie.buf;
- DBG_88E("%s, len =%d\n", __func__, len);
-
if (!check_fwstate(pmlmepriv, WIFI_AP_STATE))
return -EINVAL;
@@ -2408,8 +2239,6 @@ static int rtw_hostapd_sta_flush(struct net_device *dev)
{
struct adapter *padapter = netdev_priv(dev);
- DBG_88E("%s\n", __func__);
-
flush_all_cam_entry(padapter); /* clear CAM */
return rtw_sta_flush(padapter);
@@ -2423,8 +2252,6 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct sta_priv *pstapriv = &padapter->stapriv;
- DBG_88E("%s(aid =%d) =%pM\n", __func__, param->u.add_sta.aid, (param->sta_addr));
-
if (!check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)))
return -EINVAL;
@@ -2477,8 +2304,6 @@ static int rtw_del_sta(struct net_device *dev, struct ieee_param *param)
struct sta_priv *pstapriv = &padapter->stapriv;
int updated = 0;
- DBG_88E("%s =%pM\n", __func__, (param->sta_addr));
-
if (!check_fwstate(pmlmepriv, _FW_LINKED | WIFI_AP_STATE))
return -EINVAL;
@@ -2496,8 +2321,6 @@ static int rtw_del_sta(struct net_device *dev, struct ieee_param *param)
spin_unlock_bh(&pstapriv->asoc_list_lock);
associated_clients_update(padapter, updated);
psta = NULL;
- } else {
- DBG_88E("%s(), sta has already been removed or never been added\n", __func__);
}
return 0;
@@ -2513,8 +2336,6 @@ static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *par
struct ieee_param_ex *param_ex = (struct ieee_param_ex *)param;
struct sta_data *psta_data = (struct sta_data *)param_ex->data;
- DBG_88E("rtw_ioctl_get_sta_info, sta_addr: %pM\n", (param_ex->sta_addr));
-
if (!check_fwstate(pmlmepriv, _FW_LINKED | WIFI_AP_STATE))
return -EINVAL;
@@ -2567,8 +2388,6 @@ static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct sta_priv *pstapriv = &padapter->stapriv;
- DBG_88E("%s, sta_addr: %pM\n", __func__, (param->sta_addr));
-
if (!check_fwstate(pmlmepriv, _FW_LINKED | WIFI_AP_STATE))
return -EINVAL;
@@ -2586,8 +2405,6 @@ static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param)
copy_len = min_t(int, wpa_ie_len + 2, sizeof(psta->wpa_ie));
param->u.wpa_ie.len = copy_len;
memcpy(param->u.wpa_ie.reserved, psta->wpa_ie, copy_len);
- } else {
- DBG_88E("sta's wpa_ie is NONE\n");
}
} else {
ret = -1;
@@ -2604,8 +2421,6 @@ static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param,
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
int ie_len;
- DBG_88E("%s, len =%d\n", __func__, len);
-
if (!check_fwstate(pmlmepriv, WIFI_AP_STATE))
return -EINVAL;
@@ -2617,10 +2432,8 @@ static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param,
if (ie_len > 0) {
pmlmepriv->wps_beacon_ie = rtw_malloc(ie_len);
pmlmepriv->wps_beacon_ie_len = ie_len;
- if (!pmlmepriv->wps_beacon_ie) {
- DBG_88E("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ if (!pmlmepriv->wps_beacon_ie)
return -EINVAL;
- }
memcpy(pmlmepriv->wps_beacon_ie, param->u.bcn_ie.buf, ie_len);
@@ -2638,8 +2451,6 @@ static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *par
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
int ie_len;
- DBG_88E("%s, len =%d\n", __func__, len);
-
if (!check_fwstate(pmlmepriv, WIFI_AP_STATE))
return -EINVAL;
@@ -2651,10 +2462,8 @@ static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *par
if (ie_len > 0) {
pmlmepriv->wps_probe_resp_ie = rtw_malloc(ie_len);
pmlmepriv->wps_probe_resp_ie_len = ie_len;
- if (!pmlmepriv->wps_probe_resp_ie) {
- DBG_88E("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ if (!pmlmepriv->wps_probe_resp_ie)
return -EINVAL;
- }
memcpy(pmlmepriv->wps_probe_resp_ie, param->u.bcn_ie.buf, ie_len);
}
@@ -2667,8 +2476,6 @@ static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *par
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
int ie_len;
- DBG_88E("%s, len =%d\n", __func__, len);
-
if (!check_fwstate(pmlmepriv, WIFI_AP_STATE))
return -EINVAL;
@@ -2680,10 +2487,8 @@ static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *par
if (ie_len > 0) {
pmlmepriv->wps_assoc_resp_ie = rtw_malloc(ie_len);
pmlmepriv->wps_assoc_resp_ie_len = ie_len;
- if (!pmlmepriv->wps_assoc_resp_ie) {
- DBG_88E("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ if (!pmlmepriv->wps_assoc_resp_ie)
return -EINVAL;
- }
memcpy(pmlmepriv->wps_assoc_resp_ie, param->u.bcn_ie.buf, ie_len);
}
@@ -2703,14 +2508,11 @@ static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param,
if (!check_fwstate(pmlmepriv, WIFI_AP_STATE))
return -EINVAL;
- if (param->u.wpa_param.name != 0) /* dummy test... */
- DBG_88E("%s name(%u) != 0\n", __func__, param->u.wpa_param.name);
value = param->u.wpa_param.value;
/* use the same definition of hostapd's ignore_broadcast_ssid */
if (value != 1 && value != 2)
value = 0;
- DBG_88E("%s value(%u)\n", __func__, value);
pmlmeinfo->hidden_ssid_mode = value;
return 0;
}
@@ -2821,7 +2623,6 @@ static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p)
ret = rtw_ioctl_acl_remove_sta(dev, param, p->length);
break;
default:
- DBG_88E("Unknown hostapd request: %d\n", param->cmd);
ret = -EOPNOTSUPP;
break;
}
@@ -2899,87 +2700,53 @@ FREE_EXT:
}
static iw_handler rtw_handlers[] = {
- NULL, /* SIOCSIWCOMMIT */
- rtw_wx_get_name, /* SIOCGIWNAME */
- dummy, /* SIOCSIWNWID */
- dummy, /* SIOCGIWNWID */
- rtw_wx_set_freq, /* SIOCSIWFREQ */
- rtw_wx_get_freq, /* SIOCGIWFREQ */
- rtw_wx_set_mode, /* SIOCSIWMODE */
- rtw_wx_get_mode, /* SIOCGIWMODE */
- dummy, /* SIOCSIWSENS */
- rtw_wx_get_sens, /* SIOCGIWSENS */
- NULL, /* SIOCSIWRANGE */
- rtw_wx_get_range, /* SIOCGIWRANGE */
- rtw_wx_set_priv, /* SIOCSIWPRIV */
- NULL, /* SIOCGIWPRIV */
- NULL, /* SIOCSIWSTATS */
- NULL, /* SIOCGIWSTATS */
- dummy, /* SIOCSIWSPY */
- dummy, /* SIOCGIWSPY */
- NULL, /* SIOCGIWTHRSPY */
- NULL, /* SIOCWIWTHRSPY */
- rtw_wx_set_wap, /* SIOCSIWAP */
- rtw_wx_get_wap, /* SIOCGIWAP */
- rtw_wx_set_mlme, /* request MLME operation; uses struct iw_mlme */
- dummy, /* SIOCGIWAPLIST -- depricated */
- rtw_wx_set_scan, /* SIOCSIWSCAN */
- rtw_wx_get_scan, /* SIOCGIWSCAN */
- rtw_wx_set_essid, /* SIOCSIWESSID */
- rtw_wx_get_essid, /* SIOCGIWESSID */
- dummy, /* SIOCSIWNICKN */
- rtw_wx_get_nick, /* SIOCGIWNICKN */
- NULL, /* -- hole -- */
- NULL, /* -- hole -- */
- rtw_wx_set_rate, /* SIOCSIWRATE */
- rtw_wx_get_rate, /* SIOCGIWRATE */
- rtw_wx_set_rts, /* SIOCSIWRTS */
- rtw_wx_get_rts, /* SIOCGIWRTS */
- rtw_wx_set_frag, /* SIOCSIWFRAG */
- rtw_wx_get_frag, /* SIOCGIWFRAG */
- dummy, /* SIOCSIWTXPOW */
- dummy, /* SIOCGIWTXPOW */
- dummy, /* SIOCSIWRETRY */
- rtw_wx_get_retry, /* SIOCGIWRETRY */
- rtw_wx_set_enc, /* SIOCSIWENCODE */
- rtw_wx_get_enc, /* SIOCGIWENCODE */
- dummy, /* SIOCSIWPOWER */
- rtw_wx_get_power, /* SIOCGIWPOWER */
- NULL, /*---hole---*/
- NULL, /*---hole---*/
- rtw_wx_set_gen_ie, /* SIOCSIWGENIE */
- NULL, /* SIOCGWGENIE */
- rtw_wx_set_auth, /* SIOCSIWAUTH */
- NULL, /* SIOCGIWAUTH */
- rtw_wx_set_enc_ext, /* SIOCSIWENCODEEXT */
- NULL, /* SIOCGIWENCODEEXT */
- rtw_wx_set_pmkid, /* SIOCSIWPMKSA */
- NULL, /*---hole---*/
+ IW_HANDLER(SIOCGIWNAME, rtw_wx_get_name),
+ IW_HANDLER(SIOCGIWFREQ, rtw_wx_get_freq),
+ IW_HANDLER(SIOCSIWMODE, rtw_wx_set_mode),
+ IW_HANDLER(SIOCGIWMODE, rtw_wx_get_mode),
+ IW_HANDLER(SIOCGIWSENS, rtw_wx_get_sens),
+ IW_HANDLER(SIOCGIWRANGE, rtw_wx_get_range),
+ IW_HANDLER(SIOCSIWPRIV, rtw_wx_set_priv),
+ IW_HANDLER(SIOCSIWAP, rtw_wx_set_wap),
+ IW_HANDLER(SIOCGIWAP, rtw_wx_get_wap),
+ IW_HANDLER(SIOCSIWMLME, rtw_wx_set_mlme),
+ IW_HANDLER(SIOCSIWSCAN, rtw_wx_set_scan),
+ IW_HANDLER(SIOCGIWSCAN, rtw_wx_get_scan),
+ IW_HANDLER(SIOCSIWESSID, rtw_wx_set_essid),
+ IW_HANDLER(SIOCGIWESSID, rtw_wx_get_essid),
+ IW_HANDLER(SIOCGIWNICKN, rtw_wx_get_nick),
+ IW_HANDLER(SIOCSIWRATE, rtw_wx_set_rate),
+ IW_HANDLER(SIOCGIWRATE, rtw_wx_get_rate),
+ IW_HANDLER(SIOCSIWRTS, rtw_wx_set_rts),
+ IW_HANDLER(SIOCGIWRTS, rtw_wx_get_rts),
+ IW_HANDLER(SIOCSIWFRAG, rtw_wx_set_frag),
+ IW_HANDLER(SIOCGIWFRAG, rtw_wx_get_frag),
+ IW_HANDLER(SIOCGIWRETRY, rtw_wx_get_retry),
+ IW_HANDLER(SIOCSIWENCODE, rtw_wx_set_enc),
+ IW_HANDLER(SIOCGIWENCODE, rtw_wx_get_enc),
+ IW_HANDLER(SIOCGIWPOWER, rtw_wx_get_power),
+ IW_HANDLER(SIOCSIWGENIE, rtw_wx_set_gen_ie),
+ IW_HANDLER(SIOCSIWAUTH, rtw_wx_set_auth),
+ IW_HANDLER(SIOCSIWENCODEEXT, rtw_wx_set_enc_ext),
+ IW_HANDLER(SIOCSIWPMKSA, rtw_wx_set_pmkid),
};
static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev)
{
struct adapter *padapter = netdev_priv(dev);
struct iw_statistics *piwstats = &padapter->iwstats;
- int tmp_level = 0;
- int tmp_qual = 0;
- int tmp_noise = 0;
if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
piwstats->qual.qual = 0;
piwstats->qual.level = 0;
piwstats->qual.noise = 0;
} else {
- tmp_level = padapter->recvpriv.signal_strength;
- tmp_qual = padapter->recvpriv.signal_qual;
- tmp_noise = padapter->recvpriv.noise;
-
- piwstats->qual.level = tmp_level;
- piwstats->qual.qual = tmp_qual;
- piwstats->qual.noise = tmp_noise;
+ piwstats->qual.level = padapter->recvpriv.signal_strength;
+ piwstats->qual.qual = padapter->recvpriv.signal_qual;
+ piwstats->qual.noise = padapter->recvpriv.noise;
}
piwstats->qual.updated = IW_QUAL_ALL_UPDATED;/* IW_QUAL_DBM; */
- return &padapter->iwstats;
+ return piwstats;
}
struct iw_handler_def rtw_handlers_def = {
diff --git a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
index df53b7d52618..f12d8a707376 100644
--- a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
@@ -87,12 +87,8 @@ void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie)
u8 *buff, *p, i;
union iwreq_data wrqu;
- RT_TRACE(_module_mlme_osdep_c_, _drv_info_,
- ("+%s, authmode=%d\n", __func__, authmode));
buff = NULL;
if (authmode == WLAN_EID_VENDOR_SPECIFIC) {
- RT_TRACE(_module_mlme_osdep_c_, _drv_info_,
- ("%s, authmode=%d\n", __func__, authmode));
buff = rtw_malloc(IW_CUSTOM_MAX);
if (!buff)
return;
@@ -144,8 +140,6 @@ void rtw_indicate_sta_assoc_event(struct adapter *padapter, struct sta_info *pst
memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
- DBG_88E("+%s\n", __func__);
-
wireless_send_event(padapter->pnetdev, IWEVREGISTERED, &wrqu, NULL);
}
@@ -167,8 +161,6 @@ void rtw_indicate_sta_disassoc_event(struct adapter *padapter, struct sta_info *
memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
- DBG_88E("+%s\n", __func__);
-
wireless_send_event(padapter->pnetdev, IWEVEXPIRED, &wrqu, NULL);
}
diff --git a/drivers/staging/rtl8188eu/os_dep/mon.c b/drivers/staging/rtl8188eu/os_dep/mon.c
index 73b9599fe0dc..6370a3d8881b 100644
--- a/drivers/staging/rtl8188eu/os_dep/mon.c
+++ b/drivers/staging/rtl8188eu/os_dep/mon.c
@@ -14,7 +14,7 @@
#include <rtw_xmit.h>
#include <mon.h>
-/**
+/*
* unprotect_frame() - unset Protected flag and strip off IV and ICV/MIC
*/
static void unprotect_frame(struct sk_buff *skb, int iv_len, int icv_len)
@@ -65,7 +65,7 @@ static void mon_recv_encrypted(struct net_device *dev, const u8 *data,
netdev_info(dev, "Encrypted packets are not supported");
}
-/**
+/*
* rtl88eu_mon_recv_hook() - forward received frame to the monitor interface
*
* Assumes that the frame contains an IV and an ICV/MIC, and that
@@ -96,7 +96,7 @@ void rtl88eu_mon_recv_hook(struct net_device *dev, struct recv_frame *frame)
mon_recv_encrypted(dev, data, data_len);
}
-/**
+/*
* rtl88eu_mon_xmit_hook() - forward trasmitted frame to the monitor interface
*
* Assumes that:
@@ -163,18 +163,15 @@ struct net_device *rtl88eu_mon_init(void)
dev = alloc_netdev(0, "mon%d", NET_NAME_UNKNOWN, mon_setup);
if (!dev)
- goto fail;
+ return NULL;
err = register_netdev(dev);
- if (err < 0)
- goto fail_free_dev;
+ if (err < 0) {
+ free_netdev(dev);
+ return NULL;
+ }
return dev;
-
-fail_free_dev:
- free_netdev(dev);
-fail:
- return NULL;
}
void rtl88eu_mon_deinit(struct net_device *dev)
diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
index a826228cbbe9..423c382e3d20 100644
--- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c
+++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
@@ -18,7 +18,7 @@
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Realtek Wireless Lan Driver");
MODULE_AUTHOR("Realtek Semiconductor Corp.");
-MODULE_VERSION(DRIVERVERSION);
+MODULE_VERSION("v4.1.4_6773.20130222");
MODULE_FIRMWARE("rtlwifi/rtl8188eufw.bin");
#define RTW_NOTCH_FILTER 0 /* 0:Disable, 1:Enable, */
@@ -136,12 +136,10 @@ MODULE_PARM_DESC(monitor_enable, "Enable monitor interface (default: false)");
static int netdev_close(struct net_device *pnetdev);
-static void loadparam(struct adapter *padapter, struct net_device *pnetdev)
+static void loadparam(struct adapter *padapter)
{
struct registry_priv *registry_par = &padapter->registrypriv;
- GlobalDebugLevel = rtw_debug;
-
memcpy(registry_par->ssid.ssid, "ANY", 3);
registry_par->ssid.ssid_length = 3;
@@ -301,8 +299,6 @@ struct net_device *rtw_init_netdev(void)
struct adapter *padapter;
struct net_device *pnetdev;
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+init_net_dev\n"));
-
pnetdev = alloc_etherdev_mq(sizeof(struct adapter), 4);
if (!pnetdev)
return NULL;
@@ -310,12 +306,12 @@ struct net_device *rtw_init_netdev(void)
pnetdev->dev.type = &wlan_type;
padapter = netdev_priv(pnetdev);
padapter->pnetdev = pnetdev;
- DBG_88E("register rtw_netdev_ops to netdev_ops\n");
pnetdev->netdev_ops = &rtw_netdev_ops;
pnetdev->watchdog_timeo = HZ * 3; /* 3 second timeout */
pnetdev->wireless_handlers = (struct iw_handler_def *)&rtw_handlers_def;
- loadparam(padapter, pnetdev);
+ loadparam(padapter);
+ padapter->cmdThread = NULL;
return pnetdev;
}
@@ -324,27 +320,22 @@ static int rtw_start_drv_threads(struct adapter *padapter)
{
int err = 0;
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+%s\n", __func__));
-
- padapter->cmdThread = kthread_run(rtw_cmd_thread, padapter,
- "RTW_CMD_THREAD");
- if (IS_ERR(padapter->cmdThread))
+ padapter->cmdThread = kthread_run(rtw_cmd_thread, padapter, "RTW_CMD_THREAD");
+ if (IS_ERR(padapter->cmdThread)) {
err = PTR_ERR(padapter->cmdThread);
- else
- /* wait for cmd_thread to run */
- wait_for_completion_interruptible(&padapter->cmdpriv.terminate_cmdthread_comp);
+ padapter->cmdThread = NULL;
+ }
return err;
}
void rtw_stop_drv_threads(struct adapter *padapter)
{
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+%s\n", __func__));
+ if (!padapter->cmdThread)
+ return;
- /* Below is to terminate rtw_cmd_thread & event_thread... */
complete(&padapter->cmdpriv.cmd_queue_comp);
- if (padapter->cmdThread)
- wait_for_completion_interruptible(&padapter->cmdpriv.terminate_cmdthread_comp);
+ kthread_stop(padapter->cmdThread);
}
static u8 rtw_init_default_value(struct adapter *padapter)
@@ -422,42 +413,29 @@ u8 rtw_init_drv_sw(struct adapter *padapter)
{
u8 ret8 = _SUCCESS;
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+%s\n", __func__));
-
- if ((rtw_init_cmd_priv(&padapter->cmdpriv)) == _FAIL) {
- RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init cmd_priv\n"));
- ret8 = _FAIL;
- goto exit;
- }
-
- padapter->cmdpriv.padapter = padapter;
+ rtw_init_cmd_priv(&padapter->cmdpriv);
if (rtw_init_mlme_priv(padapter) == _FAIL) {
- RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init mlme_priv\n"));
ret8 = _FAIL;
goto exit;
}
if (init_mlme_ext_priv(padapter) == _FAIL) {
- RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init mlme_ext_priv\n"));
ret8 = _FAIL;
goto exit;
}
if (_rtw_init_xmit_priv(&padapter->xmitpriv, padapter) == _FAIL) {
- DBG_88E("Can't _rtw_init_xmit_priv\n");
ret8 = _FAIL;
goto exit;
}
if (_rtw_init_recv_priv(&padapter->recvpriv, padapter) == _FAIL) {
- DBG_88E("Can't _rtw_init_recv_priv\n");
ret8 = _FAIL;
goto exit;
}
if (_rtw_init_sta_priv(&padapter->stapriv) == _FAIL) {
- DBG_88E("Can't _rtw_init_sta_priv\n");
ret8 = _FAIL;
goto exit;
}
@@ -476,27 +454,19 @@ u8 rtw_init_drv_sw(struct adapter *padapter)
rtw_hal_sreset_init(padapter);
exit:
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-%s\n", __func__));
-
return ret8;
}
void rtw_cancel_all_timer(struct adapter *padapter)
{
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+%s\n", __func__));
-
del_timer_sync(&padapter->mlmepriv.assoc_timer);
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("%s:cancel association timer complete!\n", __func__));
del_timer_sync(&padapter->mlmepriv.scan_to_timer);
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("%s:cancel scan_to_timer!\n", __func__));
del_timer_sync(&padapter->mlmepriv.dynamic_chk_timer);
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("%s:cancel dynamic_chk_timer!\n", __func__));
/* cancel sw led timer */
rtw_hal_sw_led_deinit(padapter);
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("%s:cancel DeInitSwLeds!\n", __func__));
del_timer_sync(&padapter->pwrctrlpriv.pwr_state_check_timer);
@@ -505,8 +475,6 @@ void rtw_cancel_all_timer(struct adapter *padapter)
u8 rtw_free_drv_sw(struct adapter *padapter)
{
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("==>%s", __func__));
-
free_mlme_ext_priv(&padapter->mlmeextpriv);
rtw_free_mlme_priv(&padapter->mlmepriv);
@@ -519,12 +487,8 @@ u8 rtw_free_drv_sw(struct adapter *padapter)
rtw_hal_free_data(padapter);
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("<== %s\n", __func__));
-
mutex_destroy(&padapter->hw_init_mutex);
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-%s\n", __func__));
-
return _SUCCESS;
}
@@ -535,9 +499,6 @@ static int _netdev_open(struct net_device *pnetdev)
struct adapter *padapter = netdev_priv(pnetdev);
struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+88eu_drv - dev_open\n"));
- DBG_88E("+88eu_drv - drv_open, bup =%d\n", padapter->bup);
-
if (pwrctrlpriv->ps_flag) {
padapter->net_closed = false;
goto netdev_open_normal_process;
@@ -548,10 +509,8 @@ static int _netdev_open(struct net_device *pnetdev)
padapter->bSurpriseRemoved = false;
status = rtw_hal_init(padapter);
- if (status == _FAIL) {
- RT_TRACE(_module_os_intfs_c_, _drv_err_, ("rtl88eu_hal_init(): Can't init h/w!\n"));
+ if (status == _FAIL)
goto netdev_open_error;
- }
pr_info("MAC Address = %pM\n", pnetdev->dev_addr);
@@ -585,16 +544,12 @@ static int _netdev_open(struct net_device *pnetdev)
netif_tx_wake_all_queues(pnetdev);
netdev_open_normal_process:
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-88eu_drv - dev_open\n"));
- DBG_88E("-88eu_drv - drv_open, bup =%d\n", padapter->bup);
return 0;
netdev_open_error:
padapter->bup = false;
netif_carrier_off(pnetdev);
netif_tx_stop_all_queues(pnetdev);
- RT_TRACE(_module_os_intfs_c_, _drv_err_, ("-88eu_drv - dev_open, fail!\n"));
- DBG_88E("-88eu_drv - drv_open fail, bup =%d\n", padapter->bup);
return -1;
}
@@ -615,16 +570,13 @@ int ips_netdrv_open(struct adapter *padapter)
int status = _SUCCESS;
padapter->net_closed = false;
- DBG_88E("===> %s.........\n", __func__);
padapter->bDriverStopped = false;
padapter->bSurpriseRemoved = false;
status = rtw_hal_init(padapter);
- if (status == _FAIL) {
- RT_TRACE(_module_os_intfs_c_, _drv_err_, ("%s(): Can't init h/w!\n", __func__));
+ if (status == _FAIL)
goto netdev_open_error;
- }
rtw_hal_inirp_init(padapter);
@@ -635,47 +587,33 @@ int ips_netdrv_open(struct adapter *padapter)
return _SUCCESS;
netdev_open_error:
- DBG_88E("-%s - drv_open failure, bup =%d\n", __func__, padapter->bup);
-
return _FAIL;
}
int rtw_ips_pwr_up(struct adapter *padapter)
{
int result;
- unsigned long start_time = jiffies;
- DBG_88E("===> %s..............\n", __func__);
rtw_reset_drv_sw(padapter);
result = ips_netdrv_open(padapter);
led_control_8188eu(padapter, LED_CTL_NO_LINK);
- DBG_88E("<=== %s.............. in %dms\n", __func__,
- jiffies_to_msecs(jiffies - start_time));
return result;
}
void rtw_ips_pwr_down(struct adapter *padapter)
{
- unsigned long start_time = jiffies;
-
- DBG_88E("===> %s...................\n", __func__);
-
padapter->net_closed = true;
led_control_8188eu(padapter, LED_CTL_POWER_OFF);
rtw_ips_dev_unload(padapter);
- DBG_88E("<=== %s..................... in %dms\n", __func__,
- jiffies_to_msecs(jiffies - start_time));
}
void rtw_ips_dev_unload(struct adapter *padapter)
{
- DBG_88E("====> %s...\n", __func__);
-
rtw_hal_set_hwreg(padapter, HW_VAR_FIFO_CLEARN_UP, NULL);
usb_intf_stop(padapter);
@@ -689,8 +627,6 @@ static int netdev_close(struct net_device *pnetdev)
{
struct adapter *padapter = netdev_priv(pnetdev);
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+88eu_drv - drv_close\n"));
-
if (padapter->pwrctrlpriv.bInternalAutoSuspend) {
if (padapter->pwrctrlpriv.rf_pwrstate == rf_off)
padapter->pwrctrlpriv.ps_flag = true;
@@ -698,9 +634,6 @@ static int netdev_close(struct net_device *pnetdev)
padapter->net_closed = true;
if (padapter->pwrctrlpriv.rf_pwrstate == rf_on) {
- DBG_88E("(2)88eu_drv - drv_close, bup =%d, hw_init_completed =%d\n",
- padapter->bup, padapter->hw_init_completed);
-
/* s1. */
if (pnetdev) {
if (!rtw_netif_queue_stopped(pnetdev))
@@ -720,7 +653,5 @@ static int netdev_close(struct net_device *pnetdev)
led_control_8188eu(padapter, LED_CTL_POWER_OFF);
}
- RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-88eu_drv - drv_close\n"));
- DBG_88E("-88eu_drv - drv_close, bup =%d\n", padapter->bup);
return 0;
}
diff --git a/drivers/staging/rtl8188eu/os_dep/recv_linux.c b/drivers/staging/rtl8188eu/os_dep/recv_linux.c
index a647cdc330e4..3460619ae08f 100644
--- a/drivers/staging/rtl8188eu/os_dep/recv_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/recv_linux.c
@@ -72,11 +72,8 @@ int rtw_recv_indicatepkt(struct adapter *padapter,
pfree_recv_queue = &precvpriv->free_recv_queue;
skb = precv_frame->pkt;
- if (!skb) {
- RT_TRACE(_module_recv_osdep_c_, _drv_err_,
- ("%s():skb == NULL something wrong!!!!\n", __func__));
+ if (!skb)
goto _recv_indicatepkt_drop;
- }
if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
struct sk_buff *pskb2 = NULL;
@@ -124,9 +121,6 @@ _recv_indicatepkt_end:
rtw_free_recvframe(precv_frame, pfree_recv_queue);
- RT_TRACE(_module_recv_osdep_c_, _drv_info_,
- ("\n %s :after netif_rx!!!!\n", __func__));
-
return _SUCCESS;
_recv_indicatepkt_drop:
diff --git a/drivers/staging/rtl8188eu/os_dep/rtw_android.c b/drivers/staging/rtl8188eu/os_dep/rtw_android.c
index f1470ac56874..3c5446999686 100644
--- a/drivers/staging/rtl8188eu/os_dep/rtw_android.c
+++ b/drivers/staging/rtl8188eu/os_dep/rtw_android.c
@@ -10,7 +10,6 @@
#include <rtw_android.h>
#include <osdep_service.h>
-#include <rtw_debug.h>
#include <rtw_ioctl_set.h>
static const char *android_wifi_cmd_str[ANDROID_WIFI_CMD_MAX] = {
@@ -52,7 +51,7 @@ struct android_wifi_priv_cmd {
int total_len;
};
-int rtw_android_cmdstr_to_num(char *cmdstr)
+static int rtw_android_cmdstr_to_num(char *cmdstr)
{
int cmd_num;
@@ -135,8 +134,6 @@ int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
if (IS_ERR(command))
return PTR_ERR(command);
command[priv_cmd.total_len - 1] = 0;
- DBG_88E("%s: Android private cmd \"%s\" on %s\n",
- __func__, command, ifr->ifr_name);
cmd_num = rtw_android_cmdstr_to_num(command);
switch (cmd_num) {
case ANDROID_WIFI_CMD_START:
@@ -202,7 +199,6 @@ int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
case ANDROID_WIFI_CMD_P2P_SET_PS:
break;
default:
- DBG_88E("Unknown PRIVATE command %s - ignored\n", command);
snprintf(command, 3, "OK");
bytes_written = strlen("OK");
}
@@ -211,20 +207,14 @@ response:
if (bytes_written >= 0) {
if ((bytes_written == 0) && (priv_cmd.total_len > 0))
command[0] = '\0';
- if (bytes_written >= priv_cmd.total_len) {
- DBG_88E("%s: bytes_written = %d\n", __func__,
- bytes_written);
+ if (bytes_written >= priv_cmd.total_len)
bytes_written = priv_cmd.total_len;
- } else {
+ else
bytes_written++;
- }
priv_cmd.used_len = bytes_written;
if (copy_to_user((char __user *)priv_cmd.buf, command,
- bytes_written)) {
- DBG_88E("%s: failed to copy data to user buffer\n",
- __func__);
+ bytes_written))
ret = -EFAULT;
- }
} else {
ret = bytes_written;
}
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
index 3a970d67aa8c..b7e2692c35f3 100644
--- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c
+++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
@@ -143,16 +143,6 @@ static void usb_dvobj_deinit(struct usb_interface *usb_intf)
void usb_intf_stop(struct adapter *padapter)
{
- RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+%s\n", __func__));
-
- /* disable_hw_interrupt */
- if (!padapter->bSurpriseRemoved) {
- /* device still exists, so driver can do i/o operation */
- /* TODO: */
- RT_TRACE(_module_hci_intfs_c_, _drv_err_,
- ("SurpriseRemoved == false\n"));
- }
-
/* cancel in irp */
rtw_hal_inirp_deinit(padapter);
@@ -160,14 +150,10 @@ void usb_intf_stop(struct adapter *padapter)
usb_write_port_cancel(padapter);
/* todo:cancel other irps */
-
- RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-%s\n", __func__));
}
static void rtw_dev_unload(struct adapter *padapter)
{
- RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+%s\n", __func__));
-
if (padapter->bup) {
pr_debug("===> %s\n", __func__);
padapter->bDriverStopped = true;
@@ -186,14 +172,9 @@ static void rtw_dev_unload(struct adapter *padapter)
}
padapter->bup = false;
- } else {
- RT_TRACE(_module_hci_intfs_c_, _drv_err_,
- ("r871x_dev_unload():padapter->bup == false\n"));
}
pr_debug("<=== %s\n", __func__);
-
- RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-%s\n", __func__));
}
static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message)
@@ -351,7 +332,6 @@ static int rtw_usb_if1_init(struct usb_interface *pusb_intf)
padapter->HalData = kzalloc(sizeof(struct hal_data_8188e), GFP_KERNEL);
if (!padapter->HalData) {
- DBG_88E("Failed to allocate memory for HAL data\n");
err = -ENOMEM;
goto free_adapter;
}
@@ -367,8 +347,6 @@ static int rtw_usb_if1_init(struct usb_interface *pusb_intf)
/* step 5. */
if (rtw_init_drv_sw(padapter) == _FAIL) {
- RT_TRACE(_module_hci_intfs_c_, _drv_err_,
- ("Initialize driver software resource Failed!\n"));
err = -ENOMEM;
goto free_hal_data;
}
@@ -388,8 +366,9 @@ static int rtw_usb_if1_init(struct usb_interface *pusb_intf)
pr_debug("can't get autopm:\n");
/* alloc dev name after read efuse. */
- if (dev_alloc_name(pnetdev, padapter->registrypriv.ifname) < 0)
- RT_TRACE(_module_os_intfs_c_, _drv_err_, ("dev_alloc_name, fail!\n"));
+ err = dev_alloc_name(pnetdev, padapter->registrypriv.ifname);
+ if (err < 0)
+ goto free_hal_data;
netif_carrier_off(pnetdev);
@@ -401,7 +380,6 @@ static int rtw_usb_if1_init(struct usb_interface *pusb_intf)
/* step 6. Tell the network stack we exist */
err = register_netdev(pnetdev);
if (err) {
- RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("register_netdev() failed\n"));
goto free_hal_data;
}
@@ -478,7 +456,6 @@ static void rtw_dev_remove(struct usb_interface *pusb_intf)
struct adapter *padapter = dvobj->if1;
pr_debug("+%s\n", __func__);
- RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+dev_remove()\n"));
if (!pusb_intf->unregistering)
padapter->bSurpriseRemoved = true;
@@ -492,7 +469,6 @@ static void rtw_dev_remove(struct usb_interface *pusb_intf)
usb_dvobj_deinit(pusb_intf);
- RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-dev_remove()\n"));
pr_debug("-r871xu_dev_remove, done\n");
}
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
index e8222ffb6fea..0ceb05f3884f 100644
--- a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
@@ -28,10 +28,8 @@ static void interrupt_handler_8188eu(struct adapter *adapt, u16 pkt_len, u8 *pbu
{
struct hal_data_8188e *haldata = adapt->HalData;
- if (pkt_len != INTERRUPT_MSG_FORMAT_LEN) {
- DBG_88E("%s Invalid interrupt content length (%d)!\n", __func__, pkt_len);
+ if (pkt_len != INTERRUPT_MSG_FORMAT_LEN)
return;
- }
/* HISR */
memcpy(&haldata->IntArray[0], &pbuf[USB_INTR_CONTENT_HISR_OFFSET], 4);
@@ -66,20 +64,11 @@ static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb)
pkt_cnt = (le32_to_cpu(prxstat->rxdw2) >> 16) & 0xff;
do {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- ("%s: rxdesc=offsset 0:0x%08x, 4:0x%08x, 8:0x%08x, C:0x%08x\n",
- __func__, prxstat->rxdw0, prxstat->rxdw1,
- prxstat->rxdw2, prxstat->rxdw4));
-
prxstat = (struct recv_stat *)pbuf;
precvframe = rtw_alloc_recvframe(pfree_recv_queue);
- if (!precvframe) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("%s: precvframe==NULL\n", __func__));
- DBG_88E("%s()-%d: rtw_alloc_recvframe() failed! RX Drop!\n", __func__, __LINE__);
+ if (!precvframe)
goto _exit_recvbuf2recvframe;
- }
INIT_LIST_HEAD(&precvframe->list);
@@ -88,8 +77,6 @@ static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb)
pattrib = &precvframe->attrib;
if ((pattrib->crc_err) || (pattrib->icv_err)) {
- DBG_88E("%s: RX Warning! crc_err=%d icv_err=%d, skip!\n", __func__, pattrib->crc_err, pattrib->icv_err);
-
rtw_free_recvframe(precvframe, pfree_recv_queue);
goto _exit_recvbuf2recvframe;
}
@@ -100,9 +87,6 @@ static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb)
pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz + pattrib->shift_sz + pattrib->pkt_len;
if ((pattrib->pkt_len <= 0) || (pkt_offset > transfer_len)) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- ("%s: pkt_len<=0\n", __func__));
- DBG_88E("%s()-%d: RX Warning!,pkt_len<=0 or pkt_offset> transfer_len\n", __func__, __LINE__);
rtw_free_recvframe(precvframe, pfree_recv_queue);
goto _exit_recvbuf2recvframe;
}
@@ -138,8 +122,6 @@ static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb)
skb_reserve(pkt_copy, shift_sz);/* force ip_hdr at 8-byte alignment address according to shift_sz. */
skb_put_data(pkt_copy, (pbuf + pattrib->drvinfo_sz + RXDESC_SIZE), skb_len);
} else {
- DBG_88E("%s: alloc_skb fail , drop frag frame\n",
- __func__);
rtw_free_recvframe(precvframe, pfree_recv_queue);
goto _exit_recvbuf2recvframe;
}
@@ -159,11 +141,7 @@ static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb)
if (pattrib->pkt_rpt_type == NORMAL_RX) { /* Normal rx packet */
if (pattrib->physt)
update_recvframe_phyinfo_88e(precvframe, pphy_status);
- if (rtw_recv_entry(precvframe) != _SUCCESS) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("%s: rtw_recv_entry(precvframe) != _SUCCESS\n",
- __func__));
- }
+ rtw_recv_entry(precvframe);
} else if (pattrib->pkt_rpt_type == TX_REPORT1) {
/* CCX-TXRPT ack for xmit mgmt frames. */
handle_txrpt_ccx_88e(adapt, precvframe->pkt->data);
@@ -223,15 +201,11 @@ usbctrl_vendorreq(struct adapter *adapt, u16 value, void *pdata, u16 len, u8 req
int vendorreq_times = 0;
if ((adapt->bSurpriseRemoved) || (adapt->pwrctrlpriv.pnp_bstop_trx)) {
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s:(adapt->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",
- __func__));
status = -EPERM;
goto exit;
}
if (len > MAX_VENDOR_REQ_CMD_SIZE) {
- DBG_88E("[%s] Buffer len error ,vendor request failed\n", __func__);
status = -EINVAL;
goto exit;
}
@@ -272,10 +246,6 @@ usbctrl_vendorreq(struct adapter *adapt, u16 value, void *pdata, u16 len, u8 req
if (reqtype == REALTEK_USB_VENQT_READ)
memcpy(pdata, pIo_buf, len);
} else { /* error cases */
- DBG_88E("reg 0x%x, usb %s %u fail, status:%d value=0x%x, vendorreq_times:%d\n",
- value, (reqtype == REALTEK_USB_VENQT_READ) ? "read" : "write",
- len, status, *(u32 *)pdata, vendorreq_times);
-
if (status < 0) {
if (status == -ESHUTDOWN || status == -ENODEV)
adapt->bSurpriseRemoved = true;
@@ -340,29 +310,15 @@ static void usb_read_port_complete(struct urb *purb)
struct adapter *adapt = (struct adapter *)precvbuf->adapter;
struct recv_priv *precvpriv = &adapt->recvpriv;
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s!!!\n", __func__));
-
if (adapt->bSurpriseRemoved || adapt->bDriverStopped || adapt->bReadPortCancel) {
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s:bDriverStopped(%d) OR bSurpriseRemoved(%d)\n",
- __func__, adapt->bDriverStopped,
- adapt->bSurpriseRemoved));
-
precvbuf->reuse = true;
- DBG_88E("%s() RX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bReadPortCancel(%d)\n",
- __func__, adapt->bDriverStopped,
- adapt->bSurpriseRemoved, adapt->bReadPortCancel);
return;
}
if (purb->status == 0) { /* SUCCESS */
if ((purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)) {
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s: (purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)\n",
- __func__));
precvbuf->reuse = true;
usb_read_port(adapt, RECV_BULK_IN_ADDR, precvbuf);
- DBG_88E("%s()-%d: RX Warning!\n", __func__, __LINE__);
} else {
skb_put(precvbuf->pskb, purb->actual_length);
skb_queue_tail(&precvpriv->rx_skb_queue, precvbuf->pskb);
@@ -375,11 +331,6 @@ static void usb_read_port_complete(struct urb *purb)
usb_read_port(adapt, RECV_BULK_IN_ADDR, precvbuf);
}
} else {
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s : purb->status(%d) != 0\n",
- __func__, purb->status));
-
- DBG_88E("###=> %s => urb status(%d)\n", __func__, purb->status);
skb_put(precvbuf->pskb, purb->actual_length);
precvbuf->pskb = NULL;
@@ -392,8 +343,6 @@ static void usb_read_port_complete(struct urb *purb)
fallthrough;
case -ENOENT:
adapt->bDriverStopped = true;
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s:bDriverStopped=true\n", __func__));
break;
case -EPROTO:
case -EOVERFLOW:
@@ -402,7 +351,6 @@ static void usb_read_port_complete(struct urb *purb)
usb_read_port(adapt, RECV_BULK_IN_ADDR, precvbuf);
break;
case -EINPROGRESS:
- DBG_88E("ERROR: URB IS IN PROGRESS!\n");
break;
default:
break;
@@ -418,21 +366,14 @@ u32 usb_read_port(struct adapter *adapter, u32 addr, struct recv_buf *precvbuf)
struct usb_device *pusbd = pdvobj->pusbdev;
int err;
unsigned int pipe;
- u32 ret = _SUCCESS;
if (adapter->bDriverStopped || adapter->bSurpriseRemoved ||
adapter->pwrctrlpriv.pnp_bstop_trx) {
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s:(adapt->bDriverStopped ||adapt->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",
- __func__));
return _FAIL;
}
- if (!precvbuf) {
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s:precvbuf==NULL\n", __func__));
+ if (!precvbuf)
return _FAIL;
- }
if (!precvbuf->reuse || !precvbuf->pskb) {
precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue);
@@ -443,11 +384,8 @@ u32 usb_read_port(struct adapter *adapter, u32 addr, struct recv_buf *precvbuf)
/* re-assign for linux based on skb */
if (!precvbuf->reuse || !precvbuf->pskb) {
precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, MAX_RECVBUF_SZ);
- if (!precvbuf->pskb) {
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("init_recvbuf(): alloc_skb fail!\n"));
- DBG_88E("#### %s() alloc_skb fail!#####\n", __func__);
+ if (!precvbuf->pskb)
return _FAIL;
- }
} else { /* reuse skb */
precvbuf->reuse = false;
}
@@ -464,16 +402,10 @@ u32 usb_read_port(struct adapter *adapter, u32 addr, struct recv_buf *precvbuf)
precvbuf);/* context is precvbuf */
err = usb_submit_urb(purb, GFP_ATOMIC);
- if ((err) && (err != (-EPERM))) {
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("cannot submit rx in-token(err=0x%.8x), URB_STATUS =0x%.8x",
- err, purb->status));
- DBG_88E("cannot submit rx in-token(err = 0x%08x),urb_status = %d\n",
- err, purb->status);
- ret = _FAIL;
- }
+ if (err)
+ return _FAIL;
- return ret;
+ return _SUCCESS;
}
void rtw_hal_inirp_deinit(struct adapter *padapter)
@@ -483,8 +415,6 @@ void rtw_hal_inirp_deinit(struct adapter *padapter)
precvbuf = padapter->recvpriv.precv_buf;
- DBG_88E("%s\n", __func__);
-
padapter->bReadPortCancel = true;
for (i = 0; i < NR_RECVBUFF; i++) {
@@ -547,49 +477,23 @@ static void usb_write_port_complete(struct urb *purb)
break;
}
- if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
- padapter->bWritePortCancel) {
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s:bDriverStopped(%d) OR bSurpriseRemoved(%d)",
- __func__, padapter->bDriverStopped,
- padapter->bSurpriseRemoved));
- DBG_88E("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x)\n",
- __func__, padapter->bDriverStopped,
- padapter->bSurpriseRemoved, padapter->bReadPortCancel,
- pxmitbuf->ext_tag);
-
+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped || padapter->bWritePortCancel)
goto check_completion;
- }
if (purb->status) {
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s : purb->status(%d) != 0\n",
- __func__, purb->status));
- DBG_88E("###=> %s status(%d)\n", __func__, purb->status);
if ((purb->status == -EPIPE) || (purb->status == -EPROTO)) {
sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL);
} else if (purb->status == -EINPROGRESS) {
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s: EINPROGRESS\n", __func__));
goto check_completion;
} else if (purb->status == -ENOENT) {
- DBG_88E("%s: -ENOENT\n", __func__);
goto check_completion;
} else if (purb->status == -ECONNRESET) {
- DBG_88E("%s: -ECONNRESET\n", __func__);
goto check_completion;
} else if (purb->status == -ESHUTDOWN) {
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s: ESHUTDOWN\n", __func__));
padapter->bDriverStopped = true;
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s:bDriverStopped = true\n", __func__));
goto check_completion;
} else {
padapter->bSurpriseRemoved = true;
- DBG_88E("bSurpriseRemoved = true\n");
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s:bSurpriseRemoved = true\n", __func__));
goto check_completion;
}
}
@@ -616,13 +520,8 @@ u32 usb_write_port(struct adapter *padapter, u32 addr, u32 cnt, struct xmit_buf
struct xmit_frame *pxmitframe = (struct xmit_frame *)xmitbuf->priv_data;
struct usb_device *pusbd = pdvobj->pusbdev;
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("+%s\n", __func__));
-
if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||
(padapter->pwrctrlpriv.pnp_bstop_trx)) {
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n",
- __func__));
rtw_sctx_done_err(&xmitbuf->sctx, RTW_SCTX_DONE_TX_DENY);
goto exit;
}
@@ -670,11 +569,6 @@ u32 usb_write_port(struct adapter *padapter, u32 addr, u32 cnt, struct xmit_buf
status = usb_submit_urb(purb, GFP_ATOMIC);
if (status) {
rtw_sctx_done_err(&xmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
- DBG_88E("%s, status =%d\n", __func__, status);
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
- ("%s(): usb_submit_urb, status =%x\n",
- __func__, status));
-
if (status == -ENODEV)
padapter->bDriverStopped = true;
@@ -683,8 +577,6 @@ u32 usb_write_port(struct adapter *padapter, u32 addr, u32 cnt, struct xmit_buf
ret = _SUCCESS;
- RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("-%s\n", __func__));
-
exit:
if (ret != _SUCCESS)
rtw_free_xmitbuf(pxmitpriv, xmitbuf);
@@ -696,8 +588,6 @@ void usb_write_port_cancel(struct adapter *padapter)
int i, j;
struct xmit_buf *pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmitbuf;
- DBG_88E("%s\n", __func__);
-
padapter->bWritePortCancel = true;
for (i = 0; i < NR_XMITBUFF; i++) {
@@ -726,7 +616,6 @@ void rtl8188eu_recv_tasklet(struct tasklet_struct *t)
while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) {
if ((adapt->bDriverStopped) || (adapt->bSurpriseRemoved)) {
- DBG_88E("recv_tasklet => bDriverStopped or bSurpriseRemoved\n");
dev_kfree_skb_any(pskb);
break;
}
@@ -746,12 +635,8 @@ void rtl8188eu_xmit_tasklet(struct tasklet_struct *t)
return;
while (1) {
- if ((adapt->bDriverStopped) ||
- (adapt->bSurpriseRemoved) ||
- (adapt->bWritePortCancel)) {
- DBG_88E("xmit_tasklet => bDriverStopped or bSurpriseRemoved or bWritePortCancel\n");
+ if ((adapt->bDriverStopped) || (adapt->bSurpriseRemoved) || (adapt->bWritePortCancel))
break;
- }
if (!rtl8188eu_xmitframe_complete(adapt, pxmitpriv))
break;
diff --git a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
index a9c42fb80583..1b5776ae8eba 100644
--- a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
@@ -26,10 +26,8 @@ int rtw_os_xmit_resource_alloc(struct xmit_buf *pxmitbuf, u32 alloc_sz)
for (i = 0; i < 8; i++) {
pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
- if (!pxmitbuf->pxmit_urb[i]) {
- DBG_88E("pxmitbuf->pxmit_urb[i]==NULL");
+ if (!pxmitbuf->pxmit_urb[i])
return _FAIL;
- }
}
return _SUCCESS;
}
@@ -118,13 +116,9 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = phead->next;
-
/* free sta asoc_queue */
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, asoc_list);
-
- plist = plist->next;
+ list_for_each(plist, phead) {
+ psta = list_entry(plist, struct sta_info, asoc_list);
/* avoid come from STA1 and send back STA1 */
if (!memcmp(psta->hwaddr, &skb->data[6], 6))
@@ -136,16 +130,12 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb)
memcpy(newskb->data, psta->hwaddr, 6);
res = rtw_xmit(padapter, &newskb);
if (res < 0) {
- DBG_88E("%s()-%d: rtw_xmit() return error!\n",
- __func__, __LINE__);
pxmitpriv->tx_drop++;
dev_kfree_skb_any(newskb);
} else {
pxmitpriv->tx_pkts++;
}
} else {
- DBG_88E("%s-%d: skb_copy() failed!\n",
- __func__, __LINE__);
pxmitpriv->tx_drop++;
spin_unlock_bh(&pstapriv->asoc_list_lock);
@@ -169,13 +159,8 @@ int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
s32 res = 0;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n"));
-
- if (!rtw_if_up(padapter)) {
- RT_TRACE(_module_xmit_osdep_c_, _drv_err_,
- ("%s: rtw_if_up fail\n", __func__));
+ if (!rtw_if_up(padapter))
goto drop_packet;
- }
rtw_check_xmit_resource(padapter, pkt);
@@ -194,16 +179,11 @@ int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev)
goto drop_packet;
pxmitpriv->tx_pkts++;
- RT_TRACE(_module_xmit_osdep_c_, _drv_info_,
- ("%s: tx_pkts=%d\n", __func__, (u32)pxmitpriv->tx_pkts));
goto exit;
drop_packet:
pxmitpriv->tx_drop++;
dev_kfree_skb_any(pkt);
- RT_TRACE(_module_xmit_osdep_c_, _drv_notice_,
- ("%s: drop, tx_drop=%d\n", __func__, (u32)pxmitpriv->tx_drop));
-
exit:
return NETDEV_TX_OK;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c
index 7876b389913a..52eeb56c5c76 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c
@@ -46,7 +46,6 @@ void rtl92e_set_bandwidth(struct net_device *dev,
netdev_err(dev, "%s(): Unknown bandwidth: %#X\n",
__func__, Bandwidth);
break;
-
}
}
}
@@ -73,7 +72,6 @@ bool rtl92e_config_rf(struct net_device *dev)
pPhyReg = &priv->PHYRegDef[eRFPath];
-
switch (eRFPath) {
case RF90_PATH_A:
case RF90_PATH_C:
@@ -143,7 +141,6 @@ bool rtl92e_config_rf(struct net_device *dev)
__func__, eRFPath);
goto fail;
}
-
}
RT_TRACE(COMP_PHY, "PHY Initialization Success\n");
@@ -170,7 +167,6 @@ void rtl92e_set_cck_tx_power(struct net_device *dev, u8 powerlevel)
rtl92e_set_bb_reg(dev, rTxAGC_CCK_Mcs32, bTxAGCRateCCK, TxAGC);
}
-
void rtl92e_set_ofdm_tx_power(struct net_device *dev, u8 powerlevel)
{
struct r8192_priv *priv = rtllib_priv(dev);
@@ -215,5 +211,4 @@ void rtl92e_set_ofdm_tx_power(struct net_device *dev, u8 powerlevel)
(byte1 << 8) | byte0;
rtl92e_set_bb_reg(dev, RegOffset[index], 0x7f7f7f7f, writeVal);
}
-
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
index c8506517cc8d..f75a12543781 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
@@ -185,14 +185,12 @@ void rtl92e_cam_restore(struct net_device *dev)
rtl92e_set_key(dev, 4, 0,
priv->rtllib->pairwise_key_type,
(u8 *)dev->dev_addr, 0,
- (u32 *)(&priv->rtllib->swcamtable[4].
- key_buf[0]));
+ (u32 *)(&priv->rtllib->swcamtable[4].key_buf[0]));
} else {
rtl92e_set_key(dev, 4, 0,
priv->rtllib->pairwise_key_type,
MacAddr, 0,
- (u32 *)(&priv->rtllib->swcamtable[4].
- key_buf[0]));
+ (u32 *)(&priv->rtllib->swcamtable[4].key_buf[0]));
}
} else if (priv->rtllib->pairwise_key_type == KEY_TYPE_CCMP) {
@@ -200,13 +198,11 @@ void rtl92e_cam_restore(struct net_device *dev)
rtl92e_set_key(dev, 4, 0,
priv->rtllib->pairwise_key_type,
(u8 *)dev->dev_addr, 0,
- (u32 *)(&priv->rtllib->swcamtable[4].
- key_buf[0]));
+ (u32 *)(&priv->rtllib->swcamtable[4].key_buf[0]));
} else {
rtl92e_set_key(dev, 4, 0,
priv->rtllib->pairwise_key_type, MacAddr,
- 0, (u32 *)(&priv->rtllib->swcamtable[4].
- key_buf[0]));
+ 0, (u32 *)(&priv->rtllib->swcamtable[4].key_buf[0]));
}
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
index 736f1a824cd2..698552a92100 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
@@ -569,8 +569,8 @@ void rtl92e_writel(struct net_device *dev, int x, u32 y);
void force_pci_posting(struct net_device *dev);
-void rtl92e_rx_enable(struct net_device *);
-void rtl92e_tx_enable(struct net_device *);
+void rtl92e_rx_enable(struct net_device *dev);
+void rtl92e_tx_enable(struct net_device *dev);
void rtl92e_hw_sleep_wq(void *data);
void rtl92e_commit(struct net_device *dev);
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
index c53aa2d305ca..756d8db51937 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
@@ -1733,7 +1733,7 @@ static void _rtl92e_dm_check_edca_turbo(struct net_device *dev)
priv->bcurrent_turbo_EDCA = true;
}
} else {
- if (priv->bcurrent_turbo_EDCA) {
+ if (priv->bcurrent_turbo_EDCA) {
u8 tmp = AC0_BE;
priv->rtllib->SetHwRegHandler(dev, HW_VAR_AC_PARAM,
diff --git a/drivers/staging/rtl8192e/rtl819x_HTProc.c b/drivers/staging/rtl8192e/rtl819x_HTProc.c
index 48d28c7d870b..3b8efaf9b88c 100644
--- a/drivers/staging/rtl8192e/rtl819x_HTProc.c
+++ b/drivers/staging/rtl8192e/rtl819x_HTProc.c
@@ -276,7 +276,7 @@ void HTConstructCapabilityElement(struct rtllib_device *ieee, u8 *posHTCap,
struct rt_hi_throughput *pHT = ieee->pHTInfo;
struct ht_capab_ele *pCapELE = NULL;
- if ((posHTCap == NULL) || (pHT == NULL)) {
+ if (!posHTCap || !pHT) {
netdev_warn(ieee->dev,
"%s(): posHTCap and pHTInfo are null\n", __func__);
return;
@@ -357,7 +357,7 @@ void HTConstructInfoElement(struct rtllib_device *ieee, u8 *posHTInfo,
struct rt_hi_throughput *pHT = ieee->pHTInfo;
struct ht_info_ele *pHTInfoEle = (struct ht_info_ele *)posHTInfo;
- if ((posHTInfo == NULL) || (pHTInfoEle == NULL)) {
+ if (!posHTInfo || !pHTInfoEle) {
netdev_warn(ieee->dev,
"%s(): posHTInfo and pHTInfoEle are null\n",
__func__);
@@ -397,7 +397,7 @@ void HTConstructInfoElement(struct rtllib_device *ieee, u8 *posHTInfo,
void HTConstructRT2RTAggElement(struct rtllib_device *ieee, u8 *posRT2RTAgg,
u8 *len)
{
- if (posRT2RTAgg == NULL) {
+ if (!posRT2RTAgg) {
netdev_warn(ieee->dev, "%s(): posRT2RTAgg is null\n", __func__);
return;
}
@@ -420,7 +420,7 @@ static u8 HT_PickMCSRate(struct rtllib_device *ieee, u8 *pOperateMCS)
{
u8 i;
- if (pOperateMCS == NULL) {
+ if (!pOperateMCS) {
netdev_warn(ieee->dev, "%s(): pOperateMCS is null\n", __func__);
return false;
}
@@ -453,7 +453,7 @@ u8 HTGetHighestMCSRate(struct rtllib_device *ieee, u8 *pMCSRateSet,
u8 mcsRate = 0;
u8 availableMcsRate[16];
- if (pMCSRateSet == NULL || pMCSFilter == NULL) {
+ if (!pMCSRateSet || !pMCSFilter) {
netdev_warn(ieee->dev,
"%s(): pMCSRateSet and pMCSFilter are null\n",
__func__);
diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h
index 4cabaf21c1ca..c6f8b772335c 100644
--- a/drivers/staging/rtl8192e/rtllib.h
+++ b/drivers/staging/rtl8192e/rtllib.h
@@ -1979,8 +1979,6 @@ void rtllib_softmac_new_net(struct rtllib_device *ieee,
void SendDisassociation(struct rtllib_device *ieee, bool deauth, u16 asRsn);
void rtllib_softmac_xmit(struct rtllib_txb *txb, struct rtllib_device *ieee);
-void rtllib_stop_send_beacons(struct rtllib_device *ieee);
-void notify_wx_assoc_event(struct rtllib_device *ieee);
void rtllib_start_ibss(struct rtllib_device *ieee);
void rtllib_softmac_init(struct rtllib_device *ieee);
void rtllib_softmac_free(struct rtllib_device *ieee);
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
index 6e48b31a9afc..c2209c033838 100644
--- a/drivers/staging/rtl8192e/rtllib_rx.c
+++ b/drivers/staging/rtl8192e/rtllib_rx.c
@@ -2285,8 +2285,7 @@ int rtllib_parse_info_param(struct rtllib_device *ieee,
length -= sizeof(*info_element) + info_element->len;
info_element =
- (struct rtllib_info_element *)&info_element->
- data[info_element->len];
+ (struct rtllib_info_element *)&info_element->data[info_element->len];
}
if (!network->atheros_cap_exist && !network->broadcom_cap_exist &&
diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c
index f9a51f3620d2..25b3d3950a3c 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac.c
@@ -730,7 +730,6 @@ EXPORT_SYMBOL(rtllib_act_scanning);
/* called with ieee->lock held */
static void rtllib_start_scan(struct rtllib_device *ieee)
{
- RT_TRACE(COMP_DBG, "===>%s()\n", __func__);
if (ieee->rtllib_ips_leave_wq != NULL)
ieee->rtllib_ips_leave_wq(ieee->dev);
diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c
index 89ec72b1895a..37715afb0210 100644
--- a/drivers/staging/rtl8192e/rtllib_tx.c
+++ b/drivers/staging/rtl8192e/rtllib_tx.c
@@ -881,7 +881,7 @@ static int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
success:
if (txb) {
- struct cb_desc *tcb_desc = (struct cb_desc *)
+ tcb_desc = (struct cb_desc *)
(txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE);
tcb_desc->bTxEnableFwCalcDur = 1;
tcb_desc->priority = skb->priority;
diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c
index ab1b8217c4e0..0d67d5880377 100644
--- a/drivers/staging/rtl8192e/rtllib_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_wx.c
@@ -293,8 +293,6 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee,
int i, key, key_provided, len;
struct lib80211_crypt_data **crypt;
- netdev_dbg(ieee->dev, "%s()\n", __func__);
-
key = erq->flags & IW_ENCODE_INDEX;
if (key) {
if (key > NUM_WEP_KEYS)
@@ -463,8 +461,6 @@ int rtllib_wx_get_encode(struct rtllib_device *ieee,
int len, key;
struct lib80211_crypt_data *crypt;
- netdev_dbg(ieee->dev, "%s()\n", __func__);
-
if (ieee->iw_mode == IW_MODE_MONITOR)
return -1;
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
index 39f4ddd86796..7903c777a417 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
@@ -2249,10 +2249,8 @@ void ieee80211_wake_queue(struct ieee80211_device *ieee);
void ieee80211_stop_queue(struct ieee80211_device *ieee);
struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee);
void ieee80211_start_send_beacons(struct ieee80211_device *ieee);
-void ieee80211_stop_send_beacons(struct ieee80211_device *ieee);
int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee,
struct iw_point *p);
-void notify_wx_assoc_event(struct ieee80211_device *ieee);
void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success);
void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
index 25ea8e1b6b65..ab885353f668 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
@@ -33,9 +33,9 @@ short ieee80211_is_shortslot(const struct ieee80211_network *net)
}
EXPORT_SYMBOL(ieee80211_is_shortslot);
-/* returns the total length needed for pleacing the RATE MFIE
+/* returns the total length needed for placing the RATE MFIE
* tag and the EXTENDED RATE MFIE tag if needed.
- * It encludes two bytes per tag for the tag itself and its len
+ * It includes two bytes per tag for the tag itself and its len
*/
static unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee)
{
@@ -50,7 +50,7 @@ static unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee)
return rate_len;
}
-/* pleace the MFIE rate, tag to the memory (double) poined.
+/* place the MFIE rate, tag to the memory (double) pointer.
* Then it updates the pointer so that
* it points after the new MFIE tag added.
*/
@@ -436,7 +436,7 @@ void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee)
* So we switch to IEEE80211_LINKED_SCANNING to remember
* that we are still logically linked (not interested in
* new network events, despite for updating the net list,
- * but we are temporarly 'unlinked' as the driver shall
+ * but we are temporarily 'unlinked' as the driver shall
* not filter RX frames and the channel is changing.
* So the only situation in witch are interested is to check
* if the state become LINKED because of the #1 situation
@@ -1162,7 +1162,7 @@ void ieee80211_associate_abort(struct ieee80211_device *ieee)
ieee->associate_seq++;
- /* don't scan, and avoid to have the RX path possibily
+ /* don't scan, and avoid having the RX path possibly
* try again to associate. Even do not react to AUTH or
* ASSOC response. Just wait for the retry wq to be scheduled.
* Here we will check if there are good nets to associate
@@ -1373,7 +1373,7 @@ inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee
/* if the user set the AP check if match.
* if the network does not broadcast essid we check the user supplyed ANY essid
* if the network does broadcast and the user does not set essid it is OK
- * if the network does broadcast and the user did set essid chech if essid match
+ * if the network does broadcast and the user did set essid check if essid match
*/
if ((apset && apmatch &&
((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset))) ||
@@ -1911,8 +1911,11 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATED &&
ieee->iw_mode == IW_MODE_INFRA) {
- struct ieee80211_network network_resp;
- struct ieee80211_network *network = &network_resp;
+ struct ieee80211_network *network;
+
+ network = kzalloc(sizeof(*network), GFP_KERNEL);
+ if (!network)
+ return -ENOMEM;
errcode = assoc_parse(ieee, skb, &aid);
if (!errcode) {
@@ -1923,7 +1926,6 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
/* Let the register setting defaultly with Legacy station */
if (ieee->qos_support) {
assoc_resp = (struct ieee80211_assoc_response_frame *)skb->data;
- memset(network, 0, sizeof(*network));
if (ieee80211_parse_info_param(ieee, assoc_resp->info_element,\
rx_stats->len - sizeof(*assoc_resp), \
network, rx_stats)) {
@@ -1949,6 +1951,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
else
ieee80211_associate_abort(ieee);
}
+ kfree(network);
}
break;
@@ -2240,9 +2243,9 @@ static void ieee80211_start_ibss_wq(struct work_struct *work)
* time to scan all the chans..) or we have just run up the iface
* after setting ad-hoc mode. So we have to give another try..
* Here, in ibss mode, should be safe to do this without extra care
- * (in bss mode we had to make sure no-one tryed to associate when
+ * (in bss mode we had to make sure no-one tried to associate when
* we had just checked the ieee->state and we was going to start the
- * scan) beacause in ibss mode the ieee80211_new_net function, when
+ * scan) because in ibss mode the ieee80211_new_net function, when
* finds a good net, just set the ieee->state to IEEE80211_LINKED,
* so, at worst, we waste a bit of time to initiate an unneeded syncro
* scan, that will stop at the first round because it sees the state
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
index 96e6aaf859ec..8602e3a6c837 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
@@ -795,7 +795,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
success:
//WB add to fill data tcb_desc here. only first fragment is considered, need to change, and you may remove to other place.
if (txb) {
- struct cb_desc *tcb_desc = (struct cb_desc *)(txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE);
+ tcb_desc = (struct cb_desc *)(txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE);
tcb_desc->bTxEnableFwCalcDur = 1;
if (is_multicast_ether_addr(header.addr1))
tcb_desc->bMulticast = 1;
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index f48186a89fa1..db26edeccea6 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -902,7 +902,6 @@ static void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev,
int rate)
{
struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev);
- int ret;
unsigned long flags;
struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
u8 queue_index = tcb_desc->queue_index;
@@ -915,7 +914,7 @@ static void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev,
*(struct net_device **)(skb->cb) = dev;
tcb_desc->bTxEnableFwCalcDur = 1;
skb_push(skb, priv->ieee80211->tx_headroom);
- ret = rtl8192_tx(dev, skb);
+ rtl8192_tx(dev, skb);
spin_unlock_irqrestore(&priv->tx_lock, flags);
}
@@ -2304,8 +2303,6 @@ static int rtl8192_read_eeprom_info(struct net_device *dev)
/* set channelplan from eeprom */
priv->ChannelPlan = priv->eeprom_ChannelPlan;
if (bLoad_From_EEPOM) {
- int i;
-
for (i = 0; i < 6; i += 2) {
ret = eprom_read(dev, (u16)((EEPROM_NODE_ADDRESS_BYTE_0 + i) >> 1));
if (ret < 0)
@@ -2369,8 +2366,6 @@ static int rtl8192_read_eeprom_info(struct net_device *dev)
priv->EEPROM_Def_Ver = 1;
RT_TRACE(COMP_EPROM, "EEPROM_DEF_VER:%d\n", priv->EEPROM_Def_Ver);
if (priv->EEPROM_Def_Ver == 0) { /* old eeprom definition */
- int i;
-
if (bLoad_From_EEPOM) {
ret = eprom_read(dev, (EEPROM_TX_PW_INDEX_CCK >> 1));
if (ret < 0)
@@ -2972,12 +2967,10 @@ static RESET_TYPE RxCheckStuck(struct net_device *dev)
return RESET_TYPE_NORESET;
}
-/**
+/*
* This function is called by Checkforhang to check whether we should
* ask OS to reset driver
*
- * \param pAdapter The adapter context for this miniport
- *
* Note:NIC with USB interface sholud not call this function because we
* cannot scan descriptor to judge whether there is tx stuck.
* Note: This function may be required to be rewrite for Vista OS.
@@ -3697,7 +3690,7 @@ static u8 HwRateToMRate90(bool bIsHT, u8 rate)
return ret_rate;
}
-/**
+/*
* Function: UpdateRxPktTimeStamp
* Overview: Record the TSF time stamp when receiving a packet
*
@@ -4297,7 +4290,7 @@ static void TranslateRxSignalStuff819xUsb(struct sk_buff *skb,
rtl8192_record_rxdesc_forlateruse(pstats, &previous_stats);
}
-/**
+/*
* Function: UpdateReceivedRateHistogramStatistics
* Overview: Record the received data rate
*
diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c
index bac402b40121..725bf5ca9e34 100644
--- a/drivers/staging/rtl8192u/r8192U_dm.c
+++ b/drivers/staging/rtl8192u/r8192U_dm.c
@@ -2876,7 +2876,8 @@ void dm_check_fsync(struct net_device *dev)
* When Who Remark
* 05/29/2008 amy Create Version 0 porting from windows code.
*
- *---------------------------------------------------------------------------*/
+ *---------------------------------------------------------------------------
+ */
void dm_shadow_init(struct net_device *dev)
{
u8 page;
@@ -2915,7 +2916,8 @@ void dm_shadow_init(struct net_device *dev)
* When Who Remark
* 03/06/2008 Jacken Create Version 0.
*
- *---------------------------------------------------------------------------*/
+ *---------------------------------------------------------------------------
+ */
static void dm_init_dynamic_txpower(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
diff --git a/drivers/staging/rtl8192u/r8192U_hw.h b/drivers/staging/rtl8192u/r8192U_hw.h
index 8d3a592f1c35..217e77766442 100644
--- a/drivers/staging/rtl8192u/r8192U_hw.h
+++ b/drivers/staging/rtl8192u/r8192U_hw.h
@@ -88,7 +88,7 @@ enum _RTL8192Usb_HW {
#define RX_FIFO_THRESHOLD_MASK (BIT(13) | BIT(14) | BIT(15))
#define RX_FIFO_THRESHOLD_SHIFT 13
#define RX_FIFO_THRESHOLD_NONE 7
-#define MAX_RX_DMA_MASK (BIT(8) | BIT(9) | BIT(10))
+#define MAX_RX_DMA_MASK (BIT(8) | BIT(9) | BIT(10))
#define RCR_MXDMA_OFFSET 8
#define RCR_FIFO_OFFSET 13
#define RCR_ONLYERLPKT BIT(31) // Early Receiving based on Packet Size.
@@ -159,7 +159,7 @@ enum _RTL8192Usb_HW {
#define BW_OPMODE_20MHZ BIT(2)
BW_OPMODE = 0x300, // Bandwidth operation mode
MSR = 0x303, // Media Status register
-#define MSR_LINK_MASK (BIT(0)|BIT(1))
+#define MSR_LINK_MASK (BIT(0) | BIT(1))
#define MSR_LINK_MANAGED 2
#define MSR_LINK_NONE 0
#define MSR_LINK_SHIFT 0
@@ -221,14 +221,13 @@ enum _RTL8192Usb_HW {
#define RATR_MCS14 0x04000000
#define RATR_MCS15 0x08000000
// ALL CCK Rate
-#define RATE_ALL_CCK RATR_1M|RATR_2M|RATR_55M|RATR_11M
-#define RATE_ALL_OFDM_AG RATR_6M|RATR_9M|RATR_12M|RATR_18M|RATR_24M\
- |RATR_36M|RATR_48M|RATR_54M
-#define RATE_ALL_OFDM_1SS RATR_MCS0|RATR_MCS1|RATR_MCS2|RATR_MCS3 | \
- RATR_MCS4|RATR_MCS5|RATR_MCS6|RATR_MCS7
-#define RATE_ALL_OFDM_2SS RATR_MCS8|RATR_MCS9 |RATR_MCS10|RATR_MCS11| \
- RATR_MCS12|RATR_MCS13|RATR_MCS14|RATR_MCS15
-
+#define RATE_ALL_CCK (RATR_1M | RATR_2M | RATR_55M | RATR_11M)
+#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | RATR_12M | RATR_18M |\
+ RATR_24M | RATR_36M | RATR_48M | RATR_54M)
+#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | RATR_MCS3 |\
+ RATR_MCS4 | RATR_MCS5 | RATR_MCS6 | RATR_MCS7)
+#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | RATR_MCS11 |\
+ RATR_MCS12 | RATR_MCS13 | RATR_MCS14 | RATR_MCS15)
EPROM_CMD = 0xfe58,
#define Cmd9346CR_9356SEL BIT(4)
#define EPROM_CMD_OPERATING_MODE_SHIFT 6
diff --git a/drivers/staging/rtl8192u/r819xU_cmdpkt.c b/drivers/staging/rtl8192u/r819xU_cmdpkt.c
index 4cece40a92f6..30a320422358 100644
--- a/drivers/staging/rtl8192u/r819xU_cmdpkt.c
+++ b/drivers/staging/rtl8192u/r819xU_cmdpkt.c
@@ -250,46 +250,6 @@ static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
}
/*-----------------------------------------------------------------------------
- * Function: cmpk_handle_query_config_rx()
- *
- * Overview: The function is responsible for extract the message from
- * firmware. It will contain dedicated info in
- * ws-06-0063-rtl8190-command-packet-specification. Please
- * refer to chapter "Beacon State Element".
- *
- * Input: u8 *pmsg - Message Pointer of the command packet.
- *
- * Output: NONE
- *
- * Return: NONE
- *
- * Revised History:
- * When Who Remark
- * 05/12/2008 amy Create Version 0 porting from windows code.
- *
- *---------------------------------------------------------------------------
- */
-static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg)
-{
- struct cmpk_query_cfg rx_query_cfg;
-
- /* 1. Extract TX feedback info from RFD to temp structure buffer. */
- /* It seems that FW use big endian(MIPS) and DRV use little endian in
- * windows OS. So we have to read the content byte by byte or transfer
- * endian type before copy the message copy.
- */
- rx_query_cfg.cfg_action = (pmsg[4] & 0x80) >> 7;
- rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
- rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
- rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
- rx_query_cfg.cfg_offset = pmsg[7];
- rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
- (pmsg[10] << 8) | (pmsg[11] << 0);
- rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
- (pmsg[14] << 8) | (pmsg[15] << 0);
-}
-
-/*-----------------------------------------------------------------------------
* Function: cmpk_count_tx_status()
*
* Overview: Count aggregated tx status from firmwar of one type rx command
@@ -514,7 +474,6 @@ u32 cmpk_message_handle_rx(struct net_device *dev,
break;
case BOTH_QUERY_CONFIG:
- cmpk_handle_query_config_rx(dev, pcmd_buff);
cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
break;
diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c
index eef751d2b12e..37b82553412e 100644
--- a/drivers/staging/rtl8192u/r819xU_phy.c
+++ b/drivers/staging/rtl8192u/r819xU_phy.c
@@ -1185,14 +1185,32 @@ static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel,
u8 *stage, u8 *step, u32 *delay)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- struct sw_chnl_cmd PreCommonCmd[MAX_PRECMD_CNT];
+ struct sw_chnl_cmd *PreCommonCmd;
u32 PreCommonCmdCnt;
- struct sw_chnl_cmd PostCommonCmd[MAX_POSTCMD_CNT];
+ struct sw_chnl_cmd *PostCommonCmd;
u32 PostCommonCmdCnt;
- struct sw_chnl_cmd RfDependCmd[MAX_RFDEPENDCMD_CNT];
+ struct sw_chnl_cmd *RfDependCmd;
u32 RfDependCmdCnt;
struct sw_chnl_cmd *CurrentCmd = NULL;
u8 e_rfpath;
+ bool ret;
+
+ PreCommonCmd = kzalloc(sizeof(*PreCommonCmd) * MAX_PRECMD_CNT, GFP_KERNEL);
+ if (!PreCommonCmd)
+ return false;
+
+ PostCommonCmd = kzalloc(sizeof(*PostCommonCmd) * MAX_POSTCMD_CNT, GFP_KERNEL);
+ if (!PostCommonCmd) {
+ kfree(PreCommonCmd);
+ return false;
+ }
+
+ RfDependCmd = kzalloc(sizeof(*RfDependCmd) * MAX_RFDEPENDCMD_CNT, GFP_KERNEL);
+ if (!RfDependCmd) {
+ kfree(PreCommonCmd);
+ kfree(PostCommonCmd);
+ return false;
+ }
RT_TRACE(COMP_CH, "%s() stage: %d, step: %d, channel: %d\n",
__func__, *stage, *step, channel);
@@ -1201,7 +1219,8 @@ static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel,
/* return true to tell upper caller function this channel
* setting is finished! Or it will in while loop.
*/
- return true;
+ ret = true;
+ goto out;
}
/* FIXME: need to check whether channel is legal or not here */
@@ -1227,7 +1246,8 @@ static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel,
RT_TRACE(COMP_ERR,
"illegal channel for Zebra 8225: %d\n",
channel);
- return true;
+ ret = true;
+ goto out;
}
rtl8192_phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++,
MAX_RFDEPENDCMD_CNT,
@@ -1246,7 +1266,8 @@ static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel,
RT_TRACE(COMP_ERR,
"illegal channel for Zebra 8256: %d\n",
channel);
- return true;
+ ret = true;
+ goto out;
}
rtl8192_phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++,
MAX_RFDEPENDCMD_CNT,
@@ -1262,7 +1283,8 @@ static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel,
default:
RT_TRACE(COMP_ERR, "Unknown RFChipID: %d\n", priv->rf_chip);
- return true;
+ ret = true;
+ goto out;
}
do {
@@ -1281,7 +1303,8 @@ static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel,
if (CurrentCmd->cmd_id == CMD_ID_END) {
if ((*stage) == 2) {
(*delay) = CurrentCmd->ms_delay;
- return true;
+ ret = true;
+ goto out;
}
(*stage)++;
(*step) = 0;
@@ -1324,7 +1347,14 @@ static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel,
(*delay) = CurrentCmd->ms_delay;
(*step)++;
- return false;
+ ret = false;
+
+out:
+ kfree(PreCommonCmd);
+ kfree(PostCommonCmd);
+ kfree(RfDependCmd);
+
+ return ret;
}
/******************************************************************************
diff --git a/drivers/staging/rtl8712/hal_init.c b/drivers/staging/rtl8712/hal_init.c
index 715f1fe8b472..22974277afa0 100644
--- a/drivers/staging/rtl8712/hal_init.c
+++ b/drivers/staging/rtl8712/hal_init.c
@@ -40,7 +40,10 @@ static void rtl871x_load_fw_cb(const struct firmware *firmware, void *context)
dev_err(&udev->dev, "r8712u: Firmware request failed\n");
usb_put_dev(udev);
usb_set_intfdata(usb_intf, NULL);
+ r8712_free_drv_sw(adapter);
+ adapter->dvobj_deinit(adapter);
complete(&adapter->rtl8712_fw_ready);
+ free_netdev(adapter->pnetdev);
return;
}
adapter->fw = firmware;
diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c
index 0c3ae8495afb..2214aca09730 100644
--- a/drivers/staging/rtl8712/os_intfs.c
+++ b/drivers/staging/rtl8712/os_intfs.c
@@ -328,8 +328,6 @@ int r8712_init_drv_sw(struct _adapter *padapter)
void r8712_free_drv_sw(struct _adapter *padapter)
{
- struct net_device *pnetdev = padapter->pnetdev;
-
r8712_free_cmd_priv(&padapter->cmdpriv);
r8712_free_evt_priv(&padapter->evtpriv);
r8712_DeInitSwLeds(padapter);
@@ -339,8 +337,6 @@ void r8712_free_drv_sw(struct _adapter *padapter)
_r8712_free_sta_priv(&padapter->stapriv);
_r8712_free_recv_priv(&padapter->recvpriv);
mp871xdeinit(padapter);
- if (pnetdev)
- free_netdev(pnetdev);
}
static void enable_video_mode(struct _adapter *padapter, int cbw40_value)
diff --git a/drivers/staging/rtl8712/rtl8712_cmd.c b/drivers/staging/rtl8712/rtl8712_cmd.c
index ff3cb09c57a6..e9294e1ed06e 100644
--- a/drivers/staging/rtl8712/rtl8712_cmd.c
+++ b/drivers/staging/rtl8712/rtl8712_cmd.c
@@ -55,7 +55,7 @@ static void check_hw_pbc(struct _adapter *padapter)
/* Here we only set bPbcPressed to true
* After trigger PBC, the variable will be set to false
*/
- DBG_8712("CheckPbcGPIO - PBC is pressed !!!!\n");
+ netdev_dbg(padapter->pnetdev, "CheckPbcGPIO - PBC is pressed !!!!\n");
/* 0 is the default value and it means the application monitors
* the HW PBC doesn't provide its pid to driver.
*/
diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c
index db5c7a487ab3..0ffb30f1af7e 100644
--- a/drivers/staging/rtl8712/rtl8712_recv.c
+++ b/drivers/staging/rtl8712/rtl8712_recv.c
@@ -1039,8 +1039,9 @@ static void recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb)
skb_reserve(pkt_copy, 4 - ((addr_t)(pkt_copy->data) % 4));
skb_reserve(pkt_copy, shift_sz);
memcpy(pkt_copy->data, pbuf, tmp_len);
- precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_data =
- precvframe->u.hdr.rx_tail = pkt_copy->data;
+ precvframe->u.hdr.rx_head = pkt_copy->data;
+ precvframe->u.hdr.rx_data = pkt_copy->data;
+ precvframe->u.hdr.rx_tail = pkt_copy->data;
precvframe->u.hdr.rx_end = pkt_copy->data + alloc_sz;
recvframe_put(precvframe, tmp_len);
diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c
index 116cb812dcb9..84a22eba7ebf 100644
--- a/drivers/staging/rtl8712/rtl8712_xmit.c
+++ b/drivers/staging/rtl8712/rtl8712_xmit.c
@@ -482,9 +482,9 @@ static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz)
ptxdesc->txdw1 |= cpu_to_le32((0x01 << 22) &
0x00c00000);
/*KEY_ID when WEP is used;*/
- ptxdesc->txdw1 |= cpu_to_le32((psecuritypriv->
- PrivacyKeyIndex << 17) &
- 0x00060000);
+ ptxdesc->txdw1 |=
+ cpu_to_le32((psecuritypriv->PrivacyKeyIndex << 17) &
+ 0x00060000);
break;
case _TKIP_:
case _TKIP_WTMIC_:
diff --git a/drivers/staging/rtl8712/rtl871x_debug.h b/drivers/staging/rtl8712/rtl871x_debug.h
index 57f2a38cb71c..69c631af2a2a 100644
--- a/drivers/staging/rtl8712/rtl871x_debug.h
+++ b/drivers/staging/rtl8712/rtl871x_debug.h
@@ -127,27 +127,4 @@
#undef _MODULE_DEFINE_
#endif
-#define _dbgdump printk
-
-#define MSG_8712(x, ...) {}
-
-#define DBG_8712(x, ...) {}
-
-#define WRN_8712(x, ...) {}
-
-#define ERR_8712(x, ...) {}
-
-#undef MSG_8712
-#define MSG_8712 _dbgdump
-
-#undef DBG_8712
-#define DBG_8712 _dbgdump
-
-#undef WRN_8712
-#define WRN_8712 _dbgdump
-
-#undef ERR_8712
-#define ERR_8712 _dbgdump
-
#endif /*__RTL871X_DEBUG_H__*/
-
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c
index ba4a71e91ae0..92b7c9c07df6 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.c
+++ b/drivers/staging/rtl8712/rtl871x_mlme.c
@@ -139,10 +139,8 @@ static struct wlan_network *r8712_find_network(struct __queue *scanned_queue,
return NULL;
spin_lock_irqsave(&scanned_queue->lock, irqL);
phead = &scanned_queue->queue;
- plist = phead->next;
- while (plist != phead) {
- pnetwork = container_of(plist, struct wlan_network, list);
- plist = plist->next;
+ list_for_each(plist, phead) {
+ pnetwork = list_entry(plist, struct wlan_network, list);
if (!memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN))
break;
}
diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
index 31414a960c9e..26fa09b45c90 100644
--- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
+++ b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
@@ -149,26 +149,30 @@ static int mp_start_test(struct _adapter *padapter)
struct mp_priv *pmppriv = &padapter->mppriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wlan_network *tgt_network = &pmlmepriv->cur_network;
- struct wlan_bssid_ex bssid;
+ struct wlan_bssid_ex *bssid;
struct sta_info *psta;
unsigned long length;
unsigned long irqL;
int res = 0;
+ bssid = kzalloc(sizeof(*bssid), GFP_KERNEL);
+ if (!bssid)
+ return -ENOMEM;
+
/* 3 1. initialize a new struct wlan_bssid_ex */
- memcpy(bssid.MacAddress, pmppriv->network_macaddr, ETH_ALEN);
- bssid.Ssid.SsidLength = 16;
- memcpy(bssid.Ssid.Ssid, (unsigned char *)"mp_pseudo_adhoc",
- bssid.Ssid.SsidLength);
- bssid.InfrastructureMode = Ndis802_11IBSS;
- bssid.NetworkTypeInUse = Ndis802_11DS;
- bssid.IELength = 0;
- length = r8712_get_wlan_bssid_ex_sz(&bssid);
+ memcpy(bssid->MacAddress, pmppriv->network_macaddr, ETH_ALEN);
+ bssid->Ssid.SsidLength = 16;
+ memcpy(bssid->Ssid.Ssid, (unsigned char *)"mp_pseudo_adhoc",
+ bssid->Ssid.SsidLength);
+ bssid->InfrastructureMode = Ndis802_11IBSS;
+ bssid->NetworkTypeInUse = Ndis802_11DS;
+ bssid->IELength = 0;
+ length = r8712_get_wlan_bssid_ex_sz(bssid);
if (length % 4) {
/*round up to multiple of 4 bytes.*/
- bssid.Length = ((length >> 2) + 1) << 2;
+ bssid->Length = ((length >> 2) + 1) << 2;
} else {
- bssid.Length = length;
+ bssid->Length = length;
}
spin_lock_irqsave(&pmlmepriv->lock, irqL);
if (check_fwstate(pmlmepriv, WIFI_MP_STATE))
@@ -185,7 +189,7 @@ static int mp_start_test(struct _adapter *padapter)
tgt_network->network.MacAddress);
if (psta)
r8712_free_stainfo(padapter, psta);
- psta = r8712_alloc_stainfo(&padapter->stapriv, bssid.MacAddress);
+ psta = r8712_alloc_stainfo(&padapter->stapriv, bssid->MacAddress);
if (!psta) {
res = -ENOMEM;
goto end_of_mp_start_test;
@@ -193,13 +197,14 @@ static int mp_start_test(struct _adapter *padapter)
/* 3 3. join pseudo AdHoc */
tgt_network->join_res = 1;
tgt_network->aid = psta->aid = 1;
- memcpy(&tgt_network->network, &bssid, length);
+ memcpy(&tgt_network->network, bssid, length);
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
r8712_os_indicate_connect(padapter);
/* Set to LINKED STATE for MP TRX Testing */
set_fwstate(pmlmepriv, _FW_LINKED);
end_of_mp_start_test:
spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
+ kfree(bssid);
return res;
}
diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.h b/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
index 59fa6664d868..98204493a04c 100644
--- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
+++ b/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
@@ -135,135 +135,8 @@ uint oid_rt_get_power_mode_hdl(
struct oid_par_priv *poid_par_priv);
#ifdef _RTL871X_MP_IOCTL_C_ /* CAUTION!!! */
/* This ifdef _MUST_ be left in!! */
-static const struct oid_obj_priv oid_rtl_seg_81_80_00[] = {
- /* 0x00 OID_RT_PRO_RESET_DUT */
- {1, oid_null_function},
- /* 0x01 */
- {1, oid_rt_pro_set_data_rate_hdl},
- /* 0x02 */
- {1, oid_rt_pro_start_test_hdl},
- /* 0x03 */
- {1, oid_rt_pro_stop_test_hdl},
- /* 0x04 OID_RT_PRO_SET_PREAMBLE */
- {1, oid_null_function},
- /* 0x05 OID_RT_PRO_SET_SCRAMBLER */
- {1, oid_null_function},
- /* 0x06 OID_RT_PRO_SET_FILTER_BB */
- {1, oid_null_function},
- /* 0x07 OID_RT_PRO_SET_MANUAL_DIVERS_BB */
- {1, oid_null_function},
- /* 0x08 */
- {1, oid_rt_pro_set_channel_direct_call_hdl},
- /* 0x09 OID_RT_PRO_SET_SLEEP_MODE_DIRECT_CALL */
- {1, oid_null_function},
- /* 0x0A OID_RT_PRO_SET_WAKE_MODE_DIRECT_CALL */
- {1, oid_null_function},
- /* 0x0B OID_RT_PRO_SET_TX_CONTINUOUS_DIRECT_CALL */
- {1, oid_rt_pro_set_continuous_tx_hdl},
- /* 0x0C OID_RT_PRO_SET_SINGLE_CARRIER_TX_CONTINUOUS */
- {1, oid_rt_pro_set_single_carrier_tx_hdl},
- /* 0x0D OID_RT_PRO_SET_TX_ANTENNA_BB */
- {1, oid_null_function},
- /* 0x0E */
- {1, oid_rt_pro_set_antenna_bb_hdl},
- /* 0x0F OID_RT_PRO_SET_CR_SCRAMBLER */
- {1, oid_null_function},
- /* 0x10 OID_RT_PRO_SET_CR_NEW_FILTER */
- {1, oid_null_function},
- /* 0x11 OID_RT_PRO_SET_TX_POWER_CONTROL */
- {1, oid_rt_pro_set_tx_power_control_hdl},
- /* 0x12 OID_RT_PRO_SET_CR_TX_CONFIG */
- {1, oid_null_function},
- /* 0x13 OID_RT_PRO_GET_TX_POWER_CONTROL */
- {1, oid_null_function},
- /* 0x14 OID_RT_PRO_GET_CR_SIGNAL_QUALITY */
- {1, oid_null_function},
- /* 0x15 OID_RT_PRO_SET_CR_SETPOINT */
- {1, oid_null_function},
- /* 0x16 OID_RT_PRO_SET_INTEGRATOR */
- {1, oid_null_function},
- /* 0x17 OID_RT_PRO_SET_SIGNAL_QUALITY */
- {1, oid_null_function},
- /* 0x18 OID_RT_PRO_GET_INTEGRATOR */
- {1, oid_null_function},
- /* 0x19 OID_RT_PRO_GET_SIGNAL_QUALITY */
- {1, oid_null_function},
- /* 0x1A OID_RT_PRO_QUERY_EEPROM_TYPE */
- {1, oid_null_function},
- /* 0x1B OID_RT_PRO_WRITE_MAC_ADDRESS */
- {1, oid_null_function},
- /* 0x1C OID_RT_PRO_READ_MAC_ADDRESS */
- {1, oid_null_function},
- /* 0x1D OID_RT_PRO_WRITE_CIS_DATA */
- {1, oid_null_function},
- /* 0x1E OID_RT_PRO_READ_CIS_DATA */
- {1, oid_null_function},
- /* 0x1F OID_RT_PRO_WRITE_POWER_CONTROL */
- {1, oid_null_function}
-};
-
-static const struct oid_obj_priv oid_rtl_seg_81_80_20[] = {
- /* 0x20 OID_RT_PRO_READ_POWER_CONTROL */
- {1, oid_null_function},
- /* 0x21 OID_RT_PRO_WRITE_EEPROM */
- {1, oid_null_function},
- /* 0x22 OID_RT_PRO_READ_EEPROM */
- {1, oid_null_function},
- /* 0x23 */
- {1, oid_rt_pro_reset_tx_packet_sent_hdl},
- /* 0x24 */
- {1, oid_rt_pro_query_tx_packet_sent_hdl},
- /* 0x25 */
- {1, oid_rt_pro_reset_rx_packet_received_hdl},
- /* 0x26 */
- {1, oid_rt_pro_query_rx_packet_received_hdl},
- /* 0x27 */
- {1, oid_rt_pro_query_rx_packet_crc32_error_hdl},
- /* 0x28 OID_RT_PRO_QUERY_CURRENT_ADDRESS */
- {1, oid_null_function},
- /* 0x29 OID_RT_PRO_QUERY_PERMANENT_ADDRESS */
- {1, oid_null_function},
- /* 0x2A OID_RT_PRO_SET_PHILIPS_RF_PARAMETERS */
- {1, oid_null_function},
- /* 0x2B OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX */
- {1, oid_rt_pro_set_carrier_suppression_tx_hdl},
- /* 0x2C OID_RT_PRO_RECEIVE_PACKET */
- {1, oid_null_function},
- /* 0x2D OID_RT_PRO_WRITE_EEPROM_BYTE */
- {1, oid_null_function},
- /* 0x2E OID_RT_PRO_READ_EEPROM_BYTE */
- {1, oid_null_function},
- /* 0x2F */
- {1, oid_rt_pro_set_modulation_hdl}
-};
-
-static const struct oid_obj_priv oid_rtl_seg_81_80_40[] = {
- {1, oid_null_function}, /* 0x40 */
- {1, oid_null_function}, /* 0x41 */
- {1, oid_null_function}, /* 0x42 */
- {1, oid_rt_pro_set_single_tone_tx_hdl}, /* 0x43 */
- {1, oid_null_function}, /* 0x44 */
- {1, oid_null_function} /* 0x45 */
-};
-
-static const struct oid_obj_priv oid_rtl_seg_81_80_80[] = {
- {1, oid_null_function}, /* 0x80 OID_RT_DRIVER_OPTION */
- {1, oid_null_function}, /* 0x81 OID_RT_RF_OFF */
- {1, oid_null_function} /* 0x82 OID_RT_AUTH_STATUS */
-
-};
-
-static const struct oid_obj_priv oid_rtl_seg_81_85[] = {
- /* 0x00 OID_RT_WIRELESS_MODE */
- {1, oid_rt_wireless_mode_hdl}
-};
#else /* _RTL871X_MP_IOCTL_C_ */
-extern struct oid_obj_priv oid_rtl_seg_81_80_00[32];
-extern struct oid_obj_priv oid_rtl_seg_81_80_20[16];
-extern struct oid_obj_priv oid_rtl_seg_81_80_40[6];
-extern struct oid_obj_priv oid_rtl_seg_81_80_80[3];
-extern struct oid_obj_priv oid_rtl_seg_81_85[1];
extern struct oid_obj_priv oid_rtl_seg_81_87[5];
extern struct oid_obj_priv oid_rtl_seg_87_11_00[32];
extern struct oid_obj_priv oid_rtl_seg_87_11_20[5];
diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c
index db2add576418..c23f6b376111 100644
--- a/drivers/staging/rtl8712/rtl871x_recv.c
+++ b/drivers/staging/rtl8712/rtl871x_recv.c
@@ -374,7 +374,7 @@ static sint ap2sta_data_frame(struct _adapter *adapter,
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) &&
check_fwstate(pmlmepriv, _FW_LINKED)) {
/* if NULL-frame, drop packet */
- if ((GetFrameSubType(ptr)) == IEEE80211_STYPE_NULLFUNC)
+ if ((GetFrameSubType(ptr)) == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC))
return _FAIL;
/* drop QoS-SubType Data, including QoS NULL,
* excluding QoS-Data
diff --git a/drivers/staging/rtl8712/rtl871x_security.c b/drivers/staging/rtl8712/rtl871x_security.c
index 63d63f7be481..e0a1c30a8fe6 100644
--- a/drivers/staging/rtl8712/rtl871x_security.c
+++ b/drivers/staging/rtl8712/rtl871x_security.c
@@ -1045,9 +1045,9 @@ static void aes_cipher(u8 *key, uint hdrlen,
else
a4_exists = 1;
- if ((frtype == IEEE80211_STYPE_DATA_CFACK) ||
- (frtype == IEEE80211_STYPE_DATA_CFPOLL) ||
- (frtype == IEEE80211_STYPE_DATA_CFACKPOLL)) {
+ if ((frtype == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA_CFACK)) ||
+ (frtype == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA_CFPOLL)) ||
+ (frtype == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA_CFACKPOLL))) {
qc_exists = 1;
if (hdrlen != WLAN_HDR_A3_QOS_LEN)
hdrlen += 2;
@@ -1225,9 +1225,9 @@ static void aes_decipher(u8 *key, uint hdrlen,
a4_exists = 0;
else
a4_exists = 1;
- if ((frtype == IEEE80211_STYPE_DATA_CFACK) ||
- (frtype == IEEE80211_STYPE_DATA_CFPOLL) ||
- (frtype == IEEE80211_STYPE_DATA_CFACKPOLL)) {
+ if ((frtype == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA_CFACK)) ||
+ (frtype == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA_CFPOLL)) ||
+ (frtype == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA_CFACKPOLL))) {
qc_exists = 1;
if (hdrlen != WLAN_HDR_A3_QOS_LEN)
hdrlen += 2;
diff --git a/drivers/staging/rtl8712/rtl871x_sta_mgt.c b/drivers/staging/rtl8712/rtl871x_sta_mgt.c
index 706e9db0fc5b..2c806a0105bf 100644
--- a/drivers/staging/rtl8712/rtl871x_sta_mgt.c
+++ b/drivers/staging/rtl8712/rtl871x_sta_mgt.c
@@ -257,7 +257,6 @@ struct sta_info *r8712_get_bcmc_stainfo(struct _adapter *padapter)
return r8712_get_stainfo(pstapriv, bc_addr);
}
-
u8 r8712_access_ctrl(struct wlan_acl_pool *pacl_list, u8 *mac_addr)
{
return true;
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c
index bb4de927fb02..090345bad223 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.c
+++ b/drivers/staging/rtl8712/rtl871x_xmit.c
@@ -846,7 +846,6 @@ static inline struct tx_servq *get_sta_pending(struct _adapter *padapter,
struct __queue **ppstapending,
struct sta_info *psta, sint up)
{
-
struct tx_servq *ptxservq;
struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits;
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index dc21e7743349..2434b13c8b12 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -36,7 +36,6 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
static void r871xu_dev_remove(struct usb_interface *pusb_intf);
static const struct usb_device_id rtl871x_usb_id_tbl[] = {
-
/* RTL8188SU */
/* Realtek */
{USB_DEVICE(0x0BDA, 0x8171)},
@@ -361,7 +360,7 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
/* step 1. */
pnetdev = r8712_init_netdev();
if (!pnetdev)
- goto error;
+ goto put_dev;
padapter = netdev_priv(pnetdev);
disable_ht_for_spec_devid(pdid, padapter);
pdvobjpriv = &padapter->dvobjpriv;
@@ -380,17 +379,15 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
/* step 3.
* initialize the dvobj_priv
*/
- if (!padapter->dvobj_init) {
- goto error;
- } else {
- status = padapter->dvobj_init(padapter);
- if (status != _SUCCESS)
- goto error;
- }
+
+ status = padapter->dvobj_init(padapter);
+ if (status != _SUCCESS)
+ goto free_netdev;
+
/* step 4. */
status = r8712_init_drv_sw(padapter);
if (status)
- goto error;
+ goto dvobj_deinit;
/* step 5. read efuse/eeprom data and get mac_addr */
{
int i, offset;
@@ -570,17 +567,20 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
}
/* step 6. Load the firmware asynchronously */
if (rtl871x_load_fw(padapter))
- goto error;
+ goto deinit_drv_sw;
spin_lock_init(&padapter->lock_rx_ff0_filter);
mutex_init(&padapter->mutex_start);
return 0;
-error:
+
+deinit_drv_sw:
+ r8712_free_drv_sw(padapter);
+dvobj_deinit:
+ padapter->dvobj_deinit(padapter);
+free_netdev:
+ free_netdev(pnetdev);
+put_dev:
usb_put_dev(udev);
usb_set_intfdata(pusb_intf, NULL);
- if (padapter && padapter->dvobj_deinit)
- padapter->dvobj_deinit(padapter);
- if (pnetdev)
- free_netdev(pnetdev);
return -ENODEV;
}
@@ -612,6 +612,7 @@ static void r871xu_dev_remove(struct usb_interface *pusb_intf)
r8712_stop_drv_timers(padapter);
r871x_dev_unload(padapter);
r8712_free_drv_sw(padapter);
+ free_netdev(pnetdev);
/* decrease the reference count of the usb device structure
* when disconnect
diff --git a/drivers/staging/rtl8712/xmit_linux.c b/drivers/staging/rtl8712/xmit_linux.c
index 1f67d86c606f..90d34cf9d2ff 100644
--- a/drivers/staging/rtl8712/xmit_linux.c
+++ b/drivers/staging/rtl8712/xmit_linux.c
@@ -62,7 +62,6 @@ sint r8712_endofpktfile(struct pkt_file *pfile)
return (pfile->pkt_len == 0);
}
-
void r8712_set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib)
{
struct ethhdr etherhdr;
diff --git a/drivers/staging/rtl8723bs/Makefile b/drivers/staging/rtl8723bs/Makefile
index dfe410283ca0..fe45200ff53c 100644
--- a/drivers/staging/rtl8723bs/Makefile
+++ b/drivers/staging/rtl8723bs/Makefile
@@ -28,14 +28,12 @@ r8723bs-y = \
hal/HalPwrSeqCmd.o \
hal/odm.o \
hal/odm_CfoTracking.o \
- hal/odm_debug.o \
hal/odm_DIG.o \
hal/odm_DynamicBBPowerSaving.o \
hal/odm_DynamicTxPower.o \
hal/odm_EdcaTurboCheck.o \
hal/odm_HWConfig.o \
hal/odm_NoiseMonitor.o \
- hal/odm_PathDiv.o \
hal/odm_RegConfig8723B.o \
hal/odm_RTL8723B.o \
hal/rtl8723b_cmd.o \
diff --git a/drivers/staging/rtl8723bs/TODO b/drivers/staging/rtl8723bs/TODO
index afa620ceb2d8..3d8f5a634a10 100644
--- a/drivers/staging/rtl8723bs/TODO
+++ b/drivers/staging/rtl8723bs/TODO
@@ -1,6 +1,4 @@
TODO:
-- find and remove remaining code valid only for 5 GHz. Most of the obvious
- ones have been removed, but things like channel > 14 still exist.
- find and remove any code for other chips that is left over
- convert any remaining unusual variable types
- find codes that can use %pM and %Nph formatting
diff --git a/drivers/staging/rtl8723bs/core/rtw_ap.c b/drivers/staging/rtl8723bs/core/rtw_ap.c
index 4a9bd4825fab..a6fcb5e9d637 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ap.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ap.c
@@ -59,116 +59,112 @@ static void update_BCNTIM(struct adapter *padapter)
unsigned char *pie = pnetwork_mlmeext->IEs;
/* update TIM IE */
- /* if (pstapriv->tim_bitmap) */
- if (true) {
- u8 *p, *dst_ie, *premainder_ie = NULL, *pbackup_remainder_ie = NULL;
- __le16 tim_bitmap_le;
- uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen;
-
- tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap);
-
- p = rtw_get_ie(pie + _FIXED_IE_LENGTH_,
- WLAN_EID_TIM,
- &tim_ielen,
- pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_
- );
- if (p && tim_ielen > 0) {
- tim_ielen += 2;
+ u8 *p, *dst_ie, *premainder_ie = NULL, *pbackup_remainder_ie = NULL;
+ __le16 tim_bitmap_le;
+ uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen;
- premainder_ie = p + tim_ielen;
+ tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap);
- tim_ie_offset = (signed int)(p - pie);
+ p = rtw_get_ie(pie + _FIXED_IE_LENGTH_,
+ WLAN_EID_TIM,
+ &tim_ielen,
+ pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_
+ );
+ if (p && tim_ielen > 0) {
+ tim_ielen += 2;
- remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen;
+ premainder_ie = p + tim_ielen;
- /* append TIM IE from dst_ie offset */
- dst_ie = p;
- } else {
- tim_ielen = 0;
+ tim_ie_offset = (signed int)(p - pie);
- /* calculate head_len */
- offset = _FIXED_IE_LENGTH_;
+ remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen;
- /* get ssid_ie len */
- p = rtw_get_ie(pie + _BEACON_IE_OFFSET_,
- WLAN_EID_SSID,
- &tmp_len,
- (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)
- );
- if (p)
- offset += tmp_len + 2;
+ /* append TIM IE from dst_ie offset */
+ dst_ie = p;
+ } else {
+ tim_ielen = 0;
- /* get supported rates len */
- p = rtw_get_ie(pie + _BEACON_IE_OFFSET_,
- WLAN_EID_SUPP_RATES, &tmp_len,
- (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)
- );
- if (p)
- offset += tmp_len + 2;
+ /* calculate head_len */
+ offset = _FIXED_IE_LENGTH_;
- /* DS Parameter Set IE, len =3 */
- offset += 3;
+ /* get ssid_ie len */
+ p = rtw_get_ie(pie + _BEACON_IE_OFFSET_,
+ WLAN_EID_SSID,
+ &tmp_len,
+ (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)
+ );
+ if (p)
+ offset += tmp_len + 2;
- premainder_ie = pie + offset;
+ /* get supported rates len */
+ p = rtw_get_ie(pie + _BEACON_IE_OFFSET_,
+ WLAN_EID_SUPP_RATES, &tmp_len,
+ (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)
+ );
+ if (p)
+ offset += tmp_len + 2;
- remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen;
+ /* DS Parameter Set IE, len =3 */
+ offset += 3;
- /* append TIM IE from offset */
- dst_ie = pie + offset;
- }
+ premainder_ie = pie + offset;
- if (remainder_ielen > 0) {
- pbackup_remainder_ie = rtw_malloc(remainder_ielen);
- if (pbackup_remainder_ie && premainder_ie)
- memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
- }
+ remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen;
- *dst_ie++ = WLAN_EID_TIM;
+ /* append TIM IE from offset */
+ dst_ie = pie + offset;
+ }
- if ((pstapriv->tim_bitmap & 0xff00) && (pstapriv->tim_bitmap & 0x00fe))
- tim_ielen = 5;
- else
- tim_ielen = 4;
+ if (remainder_ielen > 0) {
+ pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+ if (pbackup_remainder_ie && premainder_ie)
+ memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+ }
- *dst_ie++ = tim_ielen;
+ *dst_ie++ = WLAN_EID_TIM;
- *dst_ie++ = 0;/* DTIM count */
- *dst_ie++ = 1;/* DTIM period */
+ if ((pstapriv->tim_bitmap & 0xff00) && (pstapriv->tim_bitmap & 0x00fe))
+ tim_ielen = 5;
+ else
+ tim_ielen = 4;
- if (pstapriv->tim_bitmap & BIT(0))/* for bc/mc frames */
- *dst_ie++ = BIT(0);/* bitmap ctrl */
- else
- *dst_ie++ = 0;
+ *dst_ie++ = tim_ielen;
- if (tim_ielen == 4) {
- __le16 pvb;
+ *dst_ie++ = 0;/* DTIM count */
+ *dst_ie++ = 1;/* DTIM period */
- if (pstapriv->tim_bitmap & 0xff00)
- pvb = cpu_to_le16(pstapriv->tim_bitmap >> 8);
- else
- pvb = tim_bitmap_le;
+ if (pstapriv->tim_bitmap & BIT(0))/* for bc/mc frames */
+ *dst_ie++ = BIT(0);/* bitmap ctrl */
+ else
+ *dst_ie++ = 0;
- *dst_ie++ = le16_to_cpu(pvb);
+ if (tim_ielen == 4) {
+ __le16 pvb;
- } else if (tim_ielen == 5) {
- memcpy(dst_ie, &tim_bitmap_le, 2);
- dst_ie += 2;
- }
+ if (pstapriv->tim_bitmap & 0xff00)
+ pvb = cpu_to_le16(pstapriv->tim_bitmap >> 8);
+ else
+ pvb = tim_bitmap_le;
- /* copy remainder IE */
- if (pbackup_remainder_ie) {
- memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+ *dst_ie++ = le16_to_cpu(pvb);
- kfree(pbackup_remainder_ie);
- }
+ } else if (tim_ielen == 5) {
+ memcpy(dst_ie, &tim_bitmap_le, 2);
+ dst_ie += 2;
+ }
+
+ /* copy remainder IE */
+ if (pbackup_remainder_ie) {
+ memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
- offset = (uint)(dst_ie - pie);
- pnetwork_mlmeext->IELength = offset + remainder_ielen;
+ kfree(pbackup_remainder_ie);
}
+
+ offset = (uint)(dst_ie - pie);
+ pnetwork_mlmeext->IELength = offset + remainder_ielen;
}
-u8 chk_sta_is_alive(struct sta_info *psta);
-u8 chk_sta_is_alive(struct sta_info *psta)
+static u8 chk_sta_is_alive(struct sta_info *psta)
{
sta_update_last_rx_pkts(psta);
@@ -177,7 +173,7 @@ u8 chk_sta_is_alive(struct sta_info *psta)
void expire_timeout_chk(struct adapter *padapter)
{
- struct list_head *phead, *plist;
+ struct list_head *phead, *plist, *tmp;
u8 updated = false;
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
@@ -188,13 +184,9 @@ void expire_timeout_chk(struct adapter *padapter)
spin_lock_bh(&pstapriv->auth_list_lock);
phead = &pstapriv->auth_list;
- plist = get_next(phead);
-
/* check auth_queue */
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, auth_list);
-
- plist = get_next(plist);
+ list_for_each_safe(plist, tmp, phead) {
+ psta = list_entry(plist, struct sta_info, auth_list);
if (psta->expire_to > 0) {
psta->expire_to--;
@@ -217,12 +209,9 @@ void expire_timeout_chk(struct adapter *padapter)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = get_next(phead);
-
/* check asoc_queue */
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, asoc_list);
- plist = get_next(plist);
+ list_for_each_safe(plist, tmp, phead) {
+ psta = list_entry(plist, struct sta_info, asoc_list);
if (chk_sta_is_alive(psta) || !psta->expire_to) {
psta->expire_to = pstapriv->expire_to;
psta->keep_alive_trycnt = 0;
@@ -352,11 +341,7 @@ void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
shortGIrate = query_ra_short_GI(psta);
if (pcur_network->Configuration.DSConfig > 14) {
- if (tx_ra_bitmap & 0xffff000)
- sta_band |= WIRELESS_11_5N;
-
- if (tx_ra_bitmap & 0xff0)
- sta_band |= WIRELESS_11A;
+ sta_band |= WIRELESS_INVALID;
} else {
if (tx_ra_bitmap & 0xffff000)
sta_band |= WIRELESS_11_24N;
@@ -422,7 +407,7 @@ void update_bmc_sta(struct adapter *padapter)
} else if (network_type == WIRELESS_INVALID) { /* error handling */
if (pcur_network->Configuration.DSConfig > 14)
- network_type = WIRELESS_11A;
+ network_type = WIRELESS_INVALID;
else
network_type = WIRELESS_11B;
}
@@ -653,7 +638,7 @@ static void update_hw_ht_param(struct adapter *padapter)
/* pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; */
}
-void start_bss_network(struct adapter *padapter, u8 *pbuf)
+void start_bss_network(struct adapter *padapter)
{
u8 *p;
u8 val8, cur_channel, cur_bwmode, cur_ch_offset;
@@ -1125,9 +1110,6 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
case WIRELESS_11BG_24N:
pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
break;
- case WIRELESS_11A:
- pbss_network->NetworkTypeInUse = Ndis802_11OFDM5;
- break;
default:
pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
break;
@@ -1210,11 +1192,8 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
spin_lock_bh(&(pacl_node_q->lock));
phead = get_list_head(pacl_node_q);
- plist = get_next(phead);
-
- while (phead != plist) {
- paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
- plist = get_next(plist);
+ list_for_each(plist, phead) {
+ paclnode = list_entry(plist, struct rtw_wlan_acl_node, list);
if (!memcmp(paclnode->addr, addr, ETH_ALEN)) {
if (paclnode->valid == true) {
@@ -1256,7 +1235,7 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
void rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
{
- struct list_head *plist, *phead;
+ struct list_head *plist, *phead, *tmp;
struct rtw_wlan_acl_node *paclnode;
struct sta_priv *pstapriv = &padapter->stapriv;
struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
@@ -1266,11 +1245,8 @@ void rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
spin_lock_bh(&(pacl_node_q->lock));
phead = get_list_head(pacl_node_q);
- plist = get_next(phead);
-
- while (phead != plist) {
- paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
- plist = get_next(plist);
+ list_for_each_safe(plist, tmp, phead) {
+ paclnode = list_entry(plist, struct rtw_wlan_acl_node, list);
if (
!memcmp(paclnode->addr, addr, ETH_ALEN) ||
@@ -1716,13 +1692,9 @@ void associated_clients_update(struct adapter *padapter, u8 updated)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = get_next(phead);
-
/* check asoc_queue */
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, asoc_list);
-
- plist = get_next(plist);
+ list_for_each(plist, phead) {
+ psta = list_entry(plist, struct sta_info, asoc_list);
VCS_update(padapter, psta);
}
@@ -1960,7 +1932,7 @@ u8 ap_free_sta(
void rtw_sta_flush(struct adapter *padapter)
{
- struct list_head *phead, *plist;
+ struct list_head *phead, *plist, *tmp;
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
@@ -1972,13 +1944,9 @@ void rtw_sta_flush(struct adapter *padapter)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = get_next(phead);
-
/* free sta asoc_queue */
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, asoc_list);
-
- plist = get_next(plist);
+ list_for_each_safe(plist, tmp, phead) {
+ psta = list_entry(plist, struct sta_info, asoc_list);
list_del_init(&psta->asoc_list);
pstapriv->asoc_list_cnt--;
@@ -2039,7 +2007,6 @@ void ap_sta_info_defer_update(struct adapter *padapter, struct sta_info *psta)
/* restore hw setting from sw data structures */
void rtw_ap_restore_network(struct adapter *padapter)
{
- struct mlme_priv *mlmepriv = &padapter->mlmepriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct sta_priv *pstapriv = &padapter->stapriv;
struct sta_info *psta;
@@ -2058,7 +2025,7 @@ void rtw_ap_restore_network(struct adapter *padapter)
pmlmeext->cur_bwmode
);
- start_bss_network(padapter, (u8 *)&mlmepriv->cur_network.network);
+ start_bss_network(padapter);
if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) ||
(padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) {
@@ -2075,13 +2042,10 @@ void rtw_ap_restore_network(struct adapter *padapter)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = get_next(phead);
-
- while (phead != plist) {
+ list_for_each(plist, phead) {
int stainfo_offset;
- psta = container_of(plist, struct sta_info, asoc_list);
- plist = get_next(plist);
+ psta = list_entry(plist, struct sta_info, asoc_list);
stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
if (stainfo_offset_valid(stainfo_offset))
@@ -2160,7 +2124,7 @@ void start_ap_mode(struct adapter *padapter)
void stop_ap_mode(struct adapter *padapter)
{
- struct list_head *phead, *plist;
+ struct list_head *phead, *plist, *tmp;
struct rtw_wlan_acl_node *paclnode;
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
@@ -2184,10 +2148,8 @@ void stop_ap_mode(struct adapter *padapter)
/* for ACL */
spin_lock_bh(&(pacl_node_q->lock));
phead = get_list_head(pacl_node_q);
- plist = get_next(phead);
- while (phead != plist) {
- paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
- plist = get_next(plist);
+ list_for_each_safe(plist, tmp, phead) {
+ paclnode = list_entry(plist, struct rtw_wlan_acl_node, list);
if (paclnode->valid) {
paclnode->valid = false;
diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c
index e1a8f8b47edd..04956ccf485c 100644
--- a/drivers/staging/rtl8723bs/core/rtw_cmd.c
+++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c
@@ -4,8 +4,6 @@
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-#define _RTW_CMD_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
#include <hal_btcoex.h>
@@ -157,9 +155,9 @@ static struct cmd_hdl wlancmds[] = {
};
/*
-Caller and the rtw_cmd_thread can protect cmd_q by spin_lock.
-No irqsave is necessary.
-*/
+ * Caller and the rtw_cmd_thread can protect cmd_q by spin_lock.
+ * No irqsave is necessary.
+ */
int rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
{
@@ -225,6 +223,7 @@ void _rtw_free_evt_priv(struct evt_priv *pevtpriv)
while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) {
void *c2h = rtw_cbuf_pop(pevtpriv->c2h_queue);
+
if (c2h && c2h != (void *)pevtpriv)
kfree(c2h);
}
@@ -243,14 +242,14 @@ void _rtw_free_cmd_priv(struct cmd_priv *pcmdpriv)
}
/*
-Calling Context:
-
-rtw_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.
-
-*/
+ * Calling Context:
+ *
+ * rtw_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.
+ *
+ */
int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
{
@@ -529,10 +528,11 @@ post_process:
}
/*
-rtw_sitesurvey_cmd(~)
- ### NOTE:#### (!!!!)
- MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
-*/
+ * rtw_sitesurvey_cmd(~)
+ * ### NOTE:#### (!!!!)
+ * MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
+ */
+
u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, int ssid_num,
struct rtw_ieee80211_channel *ch, int ch_num)
{
@@ -565,6 +565,7 @@ u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid,
/* prepare ssid list */
if (ssid) {
int i;
+
for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) {
if (ssid[i].SsidLength) {
memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(struct ndis_802_11_ssid));
@@ -576,6 +577,7 @@ u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid,
/* prepare channel list */
if (ch) {
int i;
+
for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) {
if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) {
memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel));
@@ -671,7 +673,7 @@ int rtw_startbss_cmd(struct adapter *padapter, int flags)
if (flags & RTW_CMDF_DIRECTLY) {
/* no need to enqueue, do the cmd hdl directly and free cmd parameter */
- start_bss_network(padapter, (u8 *)&(padapter->mlmepriv.cur_network.network));
+ start_bss_network(padapter);
} else {
/* need enqueue, prepare cmd_obj and enqueue */
pcmd = rtw_zmalloc(sizeof(struct cmd_obj));
@@ -695,7 +697,7 @@ int rtw_startbss_cmd(struct adapter *padapter, int flags)
res = rtw_enqueue_cmd(pcmdpriv, pcmd);
if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) {
- rtw_sctx_wait(&sctx, __func__);
+ rtw_sctx_wait(&sctx);
if (mutex_lock_interruptible(&pcmdpriv->sctx_mutex) == 0) {
if (sctx.status == RTW_SCTX_SUBMITTED)
pcmd->sctx = NULL;
@@ -1337,6 +1339,7 @@ u8 traffic_status_watchdog(struct adapter *padapter, u8 from_timer)
static void dynamic_chk_wk_hdl(struct adapter *padapter)
{
struct mlme_priv *pmlmepriv;
+
pmlmepriv = &(padapter->mlmepriv);
if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)
diff --git a/drivers/staging/rtl8723bs/core/rtw_debug.c b/drivers/staging/rtl8723bs/core/rtw_debug.c
index 79fd968bb147..576b039f741c 100644
--- a/drivers/staging/rtl8723bs/core/rtw_debug.c
+++ b/drivers/staging/rtl8723bs/core/rtw_debug.c
@@ -10,60 +10,56 @@
#include <rtw_debug.h>
#include <hal_btcoex.h>
-u32 GlobalDebugLevel = _drv_err_;
-
#include <rtw_version.h>
-void sd_f0_reg_dump(void *sel, struct adapter *adapter)
+static void dump_4_regs(struct adapter *adapter, int offset)
{
+ u32 reg[4];
int i;
- for (i = 0x0; i <= 0xff; i++) {
- if (i%16 == 0)
- netdev_dbg(adapter->pnetdev, "0x%02x ", i);
-
- DBG_871X_SEL(sel, "%02x ", rtw_sd_f0_read8(adapter, i));
+ for (i = 0; i < 4; i++)
+ reg[i] = rtw_read32(adapter, offset + i);
- if (i%16 == 15)
- DBG_871X_SEL(sel, "\n");
- else if (i%8 == 7)
- DBG_871X_SEL(sel, "\t");
- }
+ netdev_dbg(adapter->pnetdev, "0x%03x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ i, reg[0], reg[1], reg[2], reg[3]);
}
-void mac_reg_dump(void *sel, struct adapter *adapter)
+void mac_reg_dump(struct adapter *adapter)
{
- int i, j = 1;
+ int i;
netdev_dbg(adapter->pnetdev, "======= MAC REG =======\n");
- for (i = 0x0; i < 0x800; i += 4) {
- if (j%4 == 1)
- netdev_dbg(adapter->pnetdev, "0x%03x", i);
- DBG_871X_SEL(sel, " 0x%08x ", rtw_read32(adapter, i));
- if ((j++)%4 == 0)
- DBG_871X_SEL(sel, "\n");
- }
+ for (i = 0x0; i < 0x800; i += 4)
+ dump_4_regs(adapter, i);
}
-void bb_reg_dump(void *sel, struct adapter *adapter)
+void bb_reg_dump(struct adapter *adapter)
{
- int i, j = 1;
+ int i;
netdev_dbg(adapter->pnetdev, "======= BB REG =======\n");
- for (i = 0x800; i < 0x1000 ; i += 4) {
- if (j%4 == 1)
- netdev_dbg(adapter->pnetdev, "0x%03x", i);
- DBG_871X_SEL(sel, " 0x%08x ", rtw_read32(adapter, i));
- if ((j++)%4 == 0)
- DBG_871X_SEL(sel, "\n");
- }
+
+ for (i = 0x800; i < 0x1000 ; i += 4)
+ dump_4_regs(adapter, i);
+}
+
+static void dump_4_rf_regs(struct adapter *adapter, int path, int offset)
+{
+ u8 reg[4];
+ int i;
+
+ for (i = 0; i < 4; i++)
+ reg[i] = rtw_hal_read_rfreg(adapter, path, offset + i,
+ 0xffffffff);
+
+ netdev_dbg(adapter->pnetdev, "0x%02x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ i, reg[0], reg[1], reg[2], reg[3]);
}
-void rf_reg_dump(void *sel, struct adapter *adapter)
+void rf_reg_dump(struct adapter *adapter)
{
- int i, j = 1, path;
- u32 value;
+ int i, path;
u8 rf_type = 0;
u8 path_nums = 0;
@@ -77,13 +73,7 @@ void rf_reg_dump(void *sel, struct adapter *adapter)
for (path = 0; path < path_nums; path++) {
netdev_dbg(adapter->pnetdev, "RF_Path(%x)\n", path);
- for (i = 0; i < 0x100; i++) {
- value = rtw_hal_read_rfreg(adapter, path, i, 0xffffffff);
- if (j%4 == 1)
- netdev_dbg(adapter->pnetdev, "0x%02x ", i);
- DBG_871X_SEL(sel, " 0x%08x ", value);
- if ((j++)%4 == 0)
- DBG_871X_SEL(sel, "\n");
- }
+ for (i = 0; i < 0x100; i++)
+ dump_4_rf_regs(adapter, path, i);
}
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_eeprom.c b/drivers/staging/rtl8723bs/core/rtw_eeprom.c
deleted file mode 100644
index be0eda1604d0..000000000000
--- a/drivers/staging/rtl8723bs/core/rtw_eeprom.c
+++ /dev/null
@@ -1,210 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-#define _RTW_EEPROM_C_
-
-#include <drv_conf.h>
-#include <osdep_service.h>
-#include <drv_types.h>
-
-void up_clk(_adapter *padapter, u16 *x)
-{
-_func_enter_;
- *x = *x | _EESK;
- rtw_write8(padapter, EE_9346CR, (u8)*x);
- udelay(CLOCK_RATE);
-
-_func_exit_;
-
-}
-
-void down_clk(_adapter *padapter, u16 *x)
-{
-_func_enter_;
- *x = *x & ~_EESK;
- rtw_write8(padapter, EE_9346CR, (u8)*x);
- udelay(CLOCK_RATE);
-_func_exit_;
-}
-
-void shift_out_bits(_adapter *padapter, u16 data, u16 count)
-{
- u16 x, mask;
-_func_enter_;
-
- if (padapter->bSurpriseRemoved)
- goto out;
-
- mask = 0x01 << (count - 1);
- x = rtw_read8(padapter, EE_9346CR);
-
- x &= ~(_EEDO | _EEDI);
-
- do {
- x &= ~_EEDI;
- if (data & mask)
- x |= _EEDI;
- if (padapter->bSurpriseRemoved)
- goto out;
-
- rtw_write8(padapter, EE_9346CR, (u8)x);
- udelay(CLOCK_RATE);
- up_clk(padapter, &x);
- down_clk(padapter, &x);
- mask = mask >> 1;
- } while (mask);
- if (padapter->bSurpriseRemoved)
- goto out;
-
- x &= ~_EEDI;
- rtw_write8(padapter, EE_9346CR, (u8)x);
-out:
-_func_exit_;
-}
-
-u16 shift_in_bits(_adapter *padapter)
-{
- u16 x, d = 0, i;
-_func_enter_;
- if (padapter->bSurpriseRemoved)
- goto out;
-
- x = rtw_read8(padapter, EE_9346CR);
-
- x &= ~(_EEDO | _EEDI);
- d = 0;
-
- for (i = 0; i < 16; i++) {
- d = d << 1;
- up_clk(padapter, &x);
- if (padapter->bSurpriseRemoved)
- goto out;
-
- x = rtw_read8(padapter, EE_9346CR);
-
- x &= ~(_EEDI);
- if (x & _EEDO)
- d |= 1;
-
- down_clk(padapter, &x);
- }
-out:
-_func_exit_;
-
- return d;
-}
-
-void standby(_adapter *padapter)
-{
- u8 x;
-_func_enter_;
- x = rtw_read8(padapter, EE_9346CR);
-
- x &= ~(_EECS | _EESK);
- rtw_write8(padapter, EE_9346CR, x);
-
- udelay(CLOCK_RATE);
- x |= _EECS;
- rtw_write8(padapter, EE_9346CR, x);
- udelay(CLOCK_RATE);
-_func_exit_;
-}
-
-void eeprom_clean(_adapter *padapter)
-{
- u16 x;
-_func_enter_;
- if (padapter->bSurpriseRemoved)
- goto out;
-
- x = rtw_read8(padapter, EE_9346CR);
- if (padapter->bSurpriseRemoved)
- goto out;
-
- x &= ~(_EECS | _EEDI);
- rtw_write8(padapter, EE_9346CR, (u8)x);
- if (padapter->bSurpriseRemoved)
- goto out;
-
- up_clk(padapter, &x);
- if (padapter->bSurpriseRemoved)
- goto out;
-
- down_clk(padapter, &x);
-out:
-_func_exit_;
-}
-
-u16 eeprom_read16(_adapter *padapter, u16 reg) /*ReadEEprom*/
-{
-
- u16 x;
- u16 data = 0;
-
-_func_enter_;
-
- if (padapter->bSurpriseRemoved)
- goto out;
-
- /* select EEPROM, reset bits, set _EECS*/
- x = rtw_read8(padapter, EE_9346CR);
-
- if (padapter->bSurpriseRemoved)
- 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);
-
- /* Now read the data (16 bits) in from the selected EEPROM word*/
- data = shift_in_bits(padapter);
-
- eeprom_clean(padapter);
-out:
-_func_exit_;
- return data;
-
-
-}
-
-/*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)
-{
- u8 quotient, remainder, addr_2align_odd;
- u16 reg, stmp, i = 0, idx = 0;
-_func_enter_;
- reg = (u16)(addr_off >> 1);
- addr_2align_odd = (u8)(addr_off & 0x1);
-
- /*read that start at high part: e.g 1,3,5,7,9,...*/
- if (addr_2align_odd) {
- stmp = eeprom_read16(padapter, reg);
- rbuf[idx++] = (u8) ((stmp>>8)&0xff); /*return hogh-part of the short*/
- reg++; sz--;
- }
-
- quotient = sz >> 1;
- remainder = sz & 0x1;
-
- for (i = 0; i < quotient; i++) {
- stmp = eeprom_read16(padapter, reg+i);
- rbuf[idx++] = (u8) (stmp&0xff);
- rbuf[idx++] = (u8) ((stmp>>8)&0xff);
- }
-
- reg = reg+i;
- if (remainder) { /*end of read at lower part of short : 0,2,4,6,...*/
- stmp = eeprom_read16(padapter, reg);
- rbuf[idx] = (u8)(stmp & 0xff);
- }
-_func_exit_;
- return true;
-}
diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c
index a28a06d5a576..430e2d81924c 100644
--- a/drivers/staging/rtl8723bs/core/rtw_efuse.c
+++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c
@@ -4,8 +4,6 @@
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-#define _RTW_EFUSE_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
#include <hal_data.h>
@@ -40,7 +38,6 @@ Efuse_Read1ByteFromFakeContent(
{
if (Offset >= EFUSE_MAX_HW_SIZE)
return false;
- /* DbgPrint("Read fake content, offset = %d\n", Offset); */
if (fakeEfuseBank == 0)
*Value = fakeEfuseContent[Offset];
else
@@ -252,9 +249,8 @@ bool bPseudoTest)
u8 bResult;
u8 readbyte;
- if (bPseudoTest) {
+ if (bPseudoTest)
return Efuse_Read1ByteFromFakeContent(padapter, addr, data);
- }
/* <20130121, Kordan> For SMIC EFUSE specificatoin. */
/* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */
@@ -294,9 +290,8 @@ u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoT
u8 bResult = false;
u32 efuseValue = 0;
- if (bPseudoTest) {
+ if (bPseudoTest)
return Efuse_Write1ByteToFakeContent(padapter, addr, data);
- }
/* -----------------e-fuse reg ctrl --------------------------------- */
@@ -322,11 +317,10 @@ u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoT
tmpidx++;
}
- if (tmpidx < 100) {
+ if (tmpidx < 100)
bResult = true;
- } else {
+ else
bResult = false;
- }
/* disable Efuse program enable */
PHY_SetMacReg(padapter, EFUSE_TEST, BIT(11), 0);
diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
index ae057eefeeb3..0f0fcd9dc652 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
@@ -96,10 +96,7 @@ bool rtw_is_cckratesonly_included(u8 *rate)
int rtw_check_network_type(unsigned char *rate, int ratelen, int channel)
{
if (channel > 14) {
- if (rtw_is_cckrates_included(rate))
- return WIRELESS_INVALID;
- else
- return WIRELESS_11A;
+ return WIRELESS_INVALID;
} else { /* could be pure B, pure G, or B/G */
if (rtw_is_cckratesonly_included(rate))
return WIRELESS_11B;
@@ -239,12 +236,10 @@ int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 o
while (1) {
target_ie = rtw_get_ie_ex(start, search_len, eid, oui, oui_len, NULL, &target_ielen);
if (target_ie && target_ielen) {
- u8 buf[MAX_IE_SZ] = {0};
u8 *remain_ies = target_ie + target_ielen;
uint remain_len = search_len - (remain_ies - start);
- memcpy(buf, remain_ies, remain_len);
- memcpy(target_ie, buf, remain_len);
+ memcpy(target_ie, remain_ies, remain_len);
*ies_len = *ies_len - target_ielen;
ret = _SUCCESS;
@@ -268,10 +263,6 @@ void rtw_set_supported_rate(u8 *SupportedRates, uint mode)
break;
case WIRELESS_11G:
- case WIRELESS_11A:
- case WIRELESS_11_5N:
- case WIRELESS_11A_5N:/* Todo: no basic rate for ofdm ? */
- case WIRELESS_11_5AC:
memcpy(SupportedRates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
break;
@@ -329,14 +320,7 @@ int rtw_generate_ie(struct registry_priv *pregistrypriv)
ie = rtw_set_ie(ie, WLAN_EID_SSID, pdev_network->Ssid.SsidLength, pdev_network->Ssid.Ssid, &sz);
/* supported rates */
- if (pregistrypriv->wireless_mode == WIRELESS_11ABGN) {
- if (pdev_network->Configuration.DSConfig > 14)
- wireless_mode = WIRELESS_11A_5N;
- else
- wireless_mode = WIRELESS_11BG_24N;
- } else {
- wireless_mode = pregistrypriv->wireless_mode;
- }
+ wireless_mode = pregistrypriv->wireless_mode;
rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode);
@@ -361,8 +345,8 @@ int rtw_generate_ie(struct registry_priv *pregistrypriv)
}
/* HT Cap. */
- if (((pregistrypriv->wireless_mode&WIRELESS_11_5N) || (pregistrypriv->wireless_mode&WIRELESS_11_24N))
- && (pregistrypriv->ht_enable == true)) {
+ if ((pregistrypriv->wireless_mode & WIRELESS_11_24N) &&
+ (pregistrypriv->ht_enable == true)) {
/* todo: */
}
@@ -877,7 +861,7 @@ static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen,
}
/**
- * ieee802_11_parse_elems - Parse information elements in management frames
+ * rtw_ieee802_11_parse_elems - Parse information elements in management frames
* @start: Pointer to the start of IEs
* @len: Length of IE buffer in octets
* @elems: Data structure for parsed elements
diff --git a/drivers/staging/rtl8723bs/core/rtw_io.c b/drivers/staging/rtl8723bs/core/rtw_io.c
index c860ab7d618c..856e23398c03 100644
--- a/drivers/staging/rtl8723bs/core/rtw_io.c
+++ b/drivers/staging/rtl8723bs/core/rtw_io.c
@@ -25,8 +25,6 @@ jackson@realtek.com.tw
*/
-#define _RTW_IO_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
@@ -35,7 +33,7 @@ jackson@realtek.com.tw
#define rtw_cpu_to_le16(val) val
#define rtw_cpu_to_le32(val) val
-u8 _rtw_read8(struct adapter *adapter, u32 addr)
+u8 rtw_read8(struct adapter *adapter, u32 addr)
{
/* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */
struct io_priv *pio_priv = &adapter->iopriv;
@@ -47,7 +45,7 @@ u8 _rtw_read8(struct adapter *adapter, u32 addr)
return _read8(pintfhdl, addr);
}
-u16 _rtw_read16(struct adapter *adapter, u32 addr)
+u16 rtw_read16(struct adapter *adapter, u32 addr)
{
u16 r_val;
/* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */
@@ -61,7 +59,7 @@ u16 _rtw_read16(struct adapter *adapter, u32 addr)
return rtw_le16_to_cpu(r_val);
}
-u32 _rtw_read32(struct adapter *adapter, u32 addr)
+u32 rtw_read32(struct adapter *adapter, u32 addr)
{
u32 r_val;
/* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */
@@ -76,7 +74,7 @@ u32 _rtw_read32(struct adapter *adapter, u32 addr)
}
-int _rtw_write8(struct adapter *adapter, u32 addr, u8 val)
+int rtw_write8(struct adapter *adapter, u32 addr, u8 val)
{
/* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */
struct io_priv *pio_priv = &adapter->iopriv;
@@ -90,7 +88,7 @@ int _rtw_write8(struct adapter *adapter, u32 addr, u8 val)
return RTW_STATUS_CODE(ret);
}
-int _rtw_write16(struct adapter *adapter, u32 addr, u16 val)
+int rtw_write16(struct adapter *adapter, u32 addr, u16 val)
{
/* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */
struct io_priv *pio_priv = &adapter->iopriv;
@@ -103,7 +101,7 @@ int _rtw_write16(struct adapter *adapter, u32 addr, u16 val)
ret = _write16(pintfhdl, addr, val);
return RTW_STATUS_CODE(ret);
}
-int _rtw_write32(struct adapter *adapter, u32 addr, u32 val)
+int rtw_write32(struct adapter *adapter, u32 addr, u32 val)
{
/* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */
struct io_priv *pio_priv = &adapter->iopriv;
@@ -118,26 +116,7 @@ int _rtw_write32(struct adapter *adapter, u32 addr, u32 val)
return RTW_STATUS_CODE(ret);
}
-u8 _rtw_sd_f0_read8(struct adapter *adapter, u32 addr)
-{
- u8 r_val = 0x00;
- struct io_priv *pio_priv = &adapter->iopriv;
- struct intf_hdl *pintfhdl = &(pio_priv->intf);
- u8 (*_sd_f0_read8)(struct intf_hdl *pintfhdl, u32 addr);
-
- _sd_f0_read8 = pintfhdl->io_ops._sd_f0_read8;
-
- if (_sd_f0_read8)
- r_val = _sd_f0_read8(pintfhdl, addr);
- else
- netdev_warn(adapter->pnetdev,
- FUNC_ADPT_FMT " _sd_f0_read8 callback is NULL\n",
- FUNC_ADPT_ARG(adapter));
-
- return r_val;
-}
-
-u32 _rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
+u32 rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
{
u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
struct io_priv *pio_priv = &adapter->iopriv;
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c
index 4707dba90397..2dd75e007239 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c
@@ -4,8 +4,6 @@
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-#define _RTW_MLME_C_
-
#include <linux/etherdevice.h>
#include <drv_types.h>
#include <rtw_debug.h>
@@ -244,15 +242,11 @@ struct wlan_network *_rtw_find_network(struct __queue *scanned_queue, u8 *addr)
/* spin_lock_bh(&scanned_queue->lock); */
phead = get_list_head(scanned_queue);
- plist = get_next(phead);
-
- while (plist != phead) {
- pnetwork = container_of(plist, struct wlan_network, list);
+ list_for_each(plist, phead) {
+ pnetwork = list_entry(plist, struct wlan_network, list);
if (!memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN))
break;
-
- plist = get_next(plist);
}
if (plist == phead)
@@ -266,7 +260,7 @@ exit:
void rtw_free_network_queue(struct adapter *padapter, u8 isfreeall)
{
- struct list_head *phead, *plist;
+ struct list_head *phead, *plist, *tmp;
struct wlan_network *pnetwork;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct __queue *scanned_queue = &pmlmepriv->scanned_queue;
@@ -274,13 +268,9 @@ void rtw_free_network_queue(struct adapter *padapter, u8 isfreeall)
spin_lock_bh(&scanned_queue->lock);
phead = get_list_head(scanned_queue);
- plist = get_next(phead);
-
- while (phead != plist) {
-
- pnetwork = container_of(plist, struct wlan_network, list);
+ list_for_each_safe(plist, tmp, phead) {
- plist = get_next(plist);
+ pnetwork = list_entry(plist, struct wlan_network, list);
_rtw_free_network(pmlmepriv, pnetwork, isfreeall);
@@ -422,15 +412,11 @@ struct wlan_network *_rtw_find_same_network(struct __queue *scanned_queue, struc
struct wlan_network *found = NULL;
phead = get_list_head(scanned_queue);
- plist = get_next(phead);
-
- while (plist != phead) {
- found = container_of(plist, struct wlan_network, list);
+ list_for_each(plist, phead) {
+ found = list_entry(plist, struct wlan_network, list);
if (is_same_network(&network->network, &found->network, 0))
break;
-
- plist = get_next(plist);
}
if (plist == phead)
@@ -448,21 +434,14 @@ struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue)
phead = get_list_head(scanned_queue);
- plist = get_next(phead);
-
- while (1) {
-
- if (phead == plist)
- break;
+ list_for_each(plist, phead) {
- pwlan = container_of(plist, struct wlan_network, list);
+ pwlan = list_entry(plist, struct wlan_network, list);
if (!pwlan->fixed) {
if (oldest == NULL || time_after(oldest->last_scanned, pwlan->last_scanned))
oldest = pwlan;
}
-
- plist = get_next(plist);
}
return oldest;
@@ -549,13 +528,8 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t
spin_lock_bh(&queue->lock);
phead = get_list_head(queue);
- plist = get_next(phead);
-
- while (1) {
- if (phead == plist)
- break;
-
- pnetwork = container_of(plist, struct wlan_network, list);
+ list_for_each(plist, phead) {
+ pnetwork = list_entry(plist, struct wlan_network, list);
rtw_bug_check(pnetwork, pnetwork, pnetwork, pnetwork);
@@ -571,8 +545,6 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t
if (oldest == NULL || time_after(oldest->last_scanned, pnetwork->last_scanned))
oldest = pnetwork;
- plist = get_next(plist);
-
}
/* If we didn't find a match, then get a new network slot to initialize
@@ -1189,7 +1161,7 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net
/* define REJOIN */
void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf)
{
- static u8 retry;
+ static u8 __maybe_unused retry;
struct sta_info *ptarget_sta = NULL, *pcur_sta = NULL;
struct sta_priv *pstapriv = &adapter->stapriv;
struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
@@ -1788,17 +1760,10 @@ int rtw_select_roaming_candidate(struct mlme_priv *mlme)
spin_lock_bh(&(mlme->scanned_queue.lock));
phead = get_list_head(queue);
- mlme->pscanned = get_next(phead);
-
- while (phead != mlme->pscanned) {
+ list_for_each(mlme->pscanned, phead) {
- pnetwork = container_of(mlme->pscanned, struct wlan_network, list);
- if (!pnetwork) {
- ret = _FAIL;
- goto exit;
- }
-
- mlme->pscanned = get_next(mlme->pscanned);
+ pnetwork = list_entry(mlme->pscanned, struct wlan_network,
+ list);
rtw_check_roaming_candidate(mlme, &candidate, pnetwork);
@@ -1892,17 +1857,10 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv)
}
phead = get_list_head(queue);
- pmlmepriv->pscanned = get_next(phead);
-
- while (phead != pmlmepriv->pscanned) {
-
- pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list);
- if (!pnetwork) {
- ret = _FAIL;
- goto exit;
- }
+ list_for_each(pmlmepriv->pscanned, phead) {
- pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+ pnetwork = list_entry(pmlmepriv->pscanned,
+ struct wlan_network, list);
rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork);
@@ -2226,16 +2184,6 @@ void rtw_update_registrypriv_dev_network(struct adapter *adapter)
case WIRELESS_11BG_24N:
pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24);
break;
- case WIRELESS_11A:
- case WIRELESS_11A_5N:
- pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5);
- break;
- case WIRELESS_11ABGN:
- if (pregistrypriv->channel > 14)
- pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5);
- else
- pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24);
- break;
default:
/* TODO */
break;
@@ -2353,12 +2301,11 @@ void rtw_build_wmm_ie_ht(struct adapter *padapter, u8 *out_ie, uint *pout_len)
{
unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00};
int out_len;
- u8 *pframe;
if (padapter->mlmepriv.qospriv.qos_option == 0) {
out_len = *pout_len;
- pframe = rtw_set_ie(out_ie+out_len, WLAN_EID_VENDOR_SPECIFIC,
- _WMM_IE_Length_, WMM_IE, pout_len);
+ rtw_set_ie(out_ie+out_len, WLAN_EID_VENDOR_SPECIFIC,
+ _WMM_IE_Length_, WMM_IE, pout_len);
padapter->mlmepriv.qospriv.qos_option = 1;
}
@@ -2369,7 +2316,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_
{
u32 ielen, out_len;
enum ieee80211_max_ampdu_length_exp max_rx_ampdu_factor;
- unsigned char *p, *pframe;
+ unsigned char *p;
struct ieee80211_ht_cap ht_capie;
u8 cbw40_enable = 0, stbc_rx_enable = 0, rf_type = 0, operation_bw = 0;
struct registry_priv *pregistrypriv = &padapter->registrypriv;
@@ -2492,8 +2439,8 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_
else
ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00);
- pframe = rtw_set_ie(out_ie+out_len, WLAN_EID_HT_CAPABILITY,
- sizeof(struct ieee80211_ht_cap), (unsigned char *)&ht_capie, pout_len);
+ rtw_set_ie(out_ie+out_len, WLAN_EID_HT_CAPABILITY,
+ sizeof(struct ieee80211_ht_cap), (unsigned char *)&ht_capie, pout_len);
phtpriv->ht_option = true;
@@ -2501,7 +2448,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_
p = rtw_get_ie(in_ie, WLAN_EID_HT_OPERATION, &ielen, in_len);
if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) {
out_len = *pout_len;
- pframe = rtw_set_ie(out_ie+out_len, WLAN_EID_HT_OPERATION, ielen, p+2, pout_len);
+ rtw_set_ie(out_ie+out_len, WLAN_EID_HT_OPERATION, ielen, p+2, pout_len);
}
}
@@ -2516,7 +2463,6 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe
int len;
/* struct sta_info *bmc_sta, *psta; */
struct ieee80211_ht_cap *pht_capie;
- struct ieee80211_ht_addt_info *pht_addtinfo;
/* struct recv_reorder_ctrl *preorder_ctrl; */
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct ht_priv *phtpriv = &pmlmepriv->htpriv;
@@ -2553,7 +2499,6 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe
len = 0;
p = rtw_get_ie(pie+sizeof(struct ndis_802_11_fix_ie), WLAN_EID_HT_OPERATION, &len, ie_len-sizeof(struct ndis_802_11_fix_ie));
if (p && len > 0) {
- pht_addtinfo = (struct ieee80211_ht_addt_info *)(p+2);
/* todo: */
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
index 9031cf7657ae..c128d462c6c7 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
@@ -4,8 +4,6 @@
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-#define _RTW_MLME_EXT_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
#include <rtw_wifi_regd.h>
@@ -48,7 +46,6 @@ static struct action_handler OnAction_tbl[] = {
{RTW_WLAN_CATEGORY_UNPROTECTED_WNM, "ACTION_UNPROTECTED_WNM", &DoReserved},
{RTW_WLAN_CATEGORY_SELF_PROTECTED, "ACTION_SELF_PROTECTED", &DoReserved},
{RTW_WLAN_CATEGORY_WMM, "ACTION_WMM", &DoReserved},
- {RTW_WLAN_CATEGORY_VHT, "ACTION_VHT", &DoReserved},
{RTW_WLAN_CATEGORY_P2P, "ACTION_P2P", &DoReserved},
};
@@ -81,135 +78,95 @@ static struct rt_channel_plan_2g RTW_ChannelPlan2G[RT_CHANNEL_DOMAIN_2G_MAX] = {
{{}, 0}, /* 0x06, RT_CHANNEL_DOMAIN_2G_NULL */
};
-static struct rt_channel_plan_5g RTW_ChannelPlan5G[RT_CHANNEL_DOMAIN_5G_MAX] = {
- {{}, 0}, /* 0x00, RT_CHANNEL_DOMAIN_5G_NULL */
- {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 19}, /* 0x01, RT_CHANNEL_DOMAIN_5G_ETSI1 */
- {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}, 24}, /* 0x02, RT_CHANNEL_DOMAIN_5G_ETSI2 */
- {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 149, 153, 157, 161, 165}, 22}, /* 0x03, RT_CHANNEL_DOMAIN_5G_ETSI3 */
- {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}, 24}, /* 0x04, RT_CHANNEL_DOMAIN_5G_FCC1 */
- {{36, 40, 44, 48, 149, 153, 157, 161, 165}, 9}, /* 0x05, RT_CHANNEL_DOMAIN_5G_FCC2 */
- {{36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}, 13}, /* 0x06, RT_CHANNEL_DOMAIN_5G_FCC3 */
- {{36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161}, 12}, /* 0x07, RT_CHANNEL_DOMAIN_5G_FCC4 */
- {{149, 153, 157, 161, 165}, 5}, /* 0x08, RT_CHANNEL_DOMAIN_5G_FCC5 */
- {{36, 40, 44, 48, 52, 56, 60, 64}, 8}, /* 0x09, RT_CHANNEL_DOMAIN_5G_FCC6 */
- {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165}, 20}, /* 0x0A, RT_CHANNEL_DOMAIN_5G_FCC7_IC1 */
- {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 149, 153, 157, 161, 165}, 20}, /* 0x0B, RT_CHANNEL_DOMAIN_5G_KCC1 */
- {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 19}, /* 0x0C, RT_CHANNEL_DOMAIN_5G_MKK1 */
- {{36, 40, 44, 48, 52, 56, 60, 64}, 8}, /* 0x0D, RT_CHANNEL_DOMAIN_5G_MKK2 */
- {{100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 11}, /* 0x0E, RT_CHANNEL_DOMAIN_5G_MKK3 */
- {{56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165}, 15}, /* 0x0F, RT_CHANNEL_DOMAIN_5G_NCC1 */
- {{56, 60, 64, 149, 153, 157, 161, 165}, 8}, /* 0x10, RT_CHANNEL_DOMAIN_5G_NCC2 */
- {{149, 153, 157, 161, 165}, 5}, /* 0x11, RT_CHANNEL_DOMAIN_5G_NCC3 */
- {{36, 40, 44, 48}, 4}, /* 0x12, RT_CHANNEL_DOMAIN_5G_ETSI4 */
- {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165}, 20}, /* 0x13, RT_CHANNEL_DOMAIN_5G_ETSI5 */
- {{149, 153, 157, 161}, 4}, /* 0x14, RT_CHANNEL_DOMAIN_5G_FCC8 */
- {{36, 40, 44, 48, 52, 56, 60, 64}, 8}, /* 0x15, RT_CHANNEL_DOMAIN_5G_ETSI6 */
- {{36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}, 13}, /* 0x16, RT_CHANNEL_DOMAIN_5G_ETSI7 */
- {{36, 40, 44, 48, 149, 153, 157, 161, 165}, 9}, /* 0x17, RT_CHANNEL_DOMAIN_5G_ETSI8 */
- {{100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 11}, /* 0x18, RT_CHANNEL_DOMAIN_5G_ETSI9 */
- {{149, 153, 157, 161, 165}, 5}, /* 0x19, RT_CHANNEL_DOMAIN_5G_ETSI10 */
- {{36, 40, 44, 48, 52, 56, 60, 64, 132, 136, 140, 149, 153, 157, 161, 165}, 16}, /* 0x1A, RT_CHANNEL_DOMAIN_5G_ETSI11 */
- {{52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}, 17}, /* 0x1B, RT_CHANNEL_DOMAIN_5G_NCC4 */
- {{149, 153, 157, 161}, 4}, /* 0x1C, RT_CHANNEL_DOMAIN_5G_ETSI12 */
- {{36, 40, 44, 48, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}, 17}, /* 0x1D, RT_CHANNEL_DOMAIN_5G_FCC9 */
- {{36, 40, 44, 48, 100, 104, 108, 112, 116, 132, 136, 140}, 12}, /* 0x1E, RT_CHANNEL_DOMAIN_5G_ETSI13 */
- {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161}, 20}, /* 0x1F, RT_CHANNEL_DOMAIN_5G_FCC10 */
-
- /* Driver self defined for old channel plan Compatible , Remember to modify if have new channel plan definition ===== */
- {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}, 21}, /* 0x20, RT_CHANNEL_DOMAIN_5G_FCC */
- {{36, 40, 44, 48}, 4}, /* 0x21, RT_CHANNEL_DOMAIN_5G_JAPAN_NO_DFS */
- {{36, 40, 44, 48, 149, 153, 157, 161}, 8}, /* 0x22, RT_CHANNEL_DOMAIN_5G_FCC4_NO_DFS */
-};
-
static struct rt_channel_plan_map RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = {
/* 0x00 ~ 0x1F , Old Define ===== */
- {0x02, 0x20}, /* 0x00, RT_CHANNEL_DOMAIN_FCC */
- {0x02, 0x0A}, /* 0x01, RT_CHANNEL_DOMAIN_IC */
- {0x01, 0x01}, /* 0x02, RT_CHANNEL_DOMAIN_ETSI */
- {0x01, 0x00}, /* 0x03, RT_CHANNEL_DOMAIN_SPAIN */
- {0x01, 0x00}, /* 0x04, RT_CHANNEL_DOMAIN_FRANCE */
- {0x03, 0x00}, /* 0x05, RT_CHANNEL_DOMAIN_MKK */
- {0x03, 0x00}, /* 0x06, RT_CHANNEL_DOMAIN_MKK1 */
- {0x01, 0x09}, /* 0x07, RT_CHANNEL_DOMAIN_ISRAEL */
- {0x03, 0x09}, /* 0x08, RT_CHANNEL_DOMAIN_TELEC */
- {0x03, 0x00}, /* 0x09, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN */
- {0x00, 0x00}, /* 0x0A, RT_CHANNEL_DOMAIN_WORLD_WIDE_13 */
- {0x02, 0x0F}, /* 0x0B, RT_CHANNEL_DOMAIN_TAIWAN */
- {0x01, 0x08}, /* 0x0C, RT_CHANNEL_DOMAIN_CHINA */
- {0x02, 0x06}, /* 0x0D, RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO */
- {0x02, 0x0B}, /* 0x0E, RT_CHANNEL_DOMAIN_KOREA */
- {0x02, 0x09}, /* 0x0F, RT_CHANNEL_DOMAIN_TURKEY */
- {0x01, 0x01}, /* 0x10, RT_CHANNEL_DOMAIN_JAPAN */
- {0x02, 0x05}, /* 0x11, RT_CHANNEL_DOMAIN_FCC_NO_DFS */
- {0x01, 0x21}, /* 0x12, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */
- {0x00, 0x04}, /* 0x13, RT_CHANNEL_DOMAIN_WORLD_WIDE_5G */
- {0x02, 0x10}, /* 0x14, RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS */
- {0x00, 0x21}, /* 0x15, RT_CHANNEL_DOMAIN_ETSI_NO_DFS */
- {0x00, 0x22}, /* 0x16, RT_CHANNEL_DOMAIN_KOREA_NO_DFS */
- {0x03, 0x21}, /* 0x17, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */
- {0x06, 0x08}, /* 0x18, RT_CHANNEL_DOMAIN_PAKISTAN_NO_DFS */
- {0x02, 0x08}, /* 0x19, RT_CHANNEL_DOMAIN_TAIWAN2_NO_DFS */
- {0x00, 0x00}, /* 0x1A, */
- {0x00, 0x00}, /* 0x1B, */
- {0x00, 0x00}, /* 0x1C, */
- {0x00, 0x00}, /* 0x1D, */
- {0x00, 0x00}, /* 0x1E, */
- {0x06, 0x04}, /* 0x1F, RT_CHANNEL_DOMAIN_WORLD_WIDE_ONLY_5G */
+ {0x02}, /* 0x00, RT_CHANNEL_DOMAIN_FCC */
+ {0x02}, /* 0x01, RT_CHANNEL_DOMAIN_IC */
+ {0x01}, /* 0x02, RT_CHANNEL_DOMAIN_ETSI */
+ {0x01}, /* 0x03, RT_CHANNEL_DOMAIN_SPAIN */
+ {0x01}, /* 0x04, RT_CHANNEL_DOMAIN_FRANCE */
+ {0x03}, /* 0x05, RT_CHANNEL_DOMAIN_MKK */
+ {0x03}, /* 0x06, RT_CHANNEL_DOMAIN_MKK1 */
+ {0x01}, /* 0x07, RT_CHANNEL_DOMAIN_ISRAEL */
+ {0x03}, /* 0x08, RT_CHANNEL_DOMAIN_TELEC */
+ {0x03}, /* 0x09, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN */
+ {0x00}, /* 0x0A, RT_CHANNEL_DOMAIN_WORLD_WIDE_13 */
+ {0x02}, /* 0x0B, RT_CHANNEL_DOMAIN_TAIWAN */
+ {0x01}, /* 0x0C, RT_CHANNEL_DOMAIN_CHINA */
+ {0x02}, /* 0x0D, RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO */
+ {0x02}, /* 0x0E, RT_CHANNEL_DOMAIN_KOREA */
+ {0x02}, /* 0x0F, RT_CHANNEL_DOMAIN_TURKEY */
+ {0x01}, /* 0x10, RT_CHANNEL_DOMAIN_JAPAN */
+ {0x02}, /* 0x11, RT_CHANNEL_DOMAIN_FCC_NO_DFS */
+ {0x01}, /* 0x12, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */
+ {0x00}, /* 0x13, RT_CHANNEL_DOMAIN_WORLD_WIDE_5G */
+ {0x02}, /* 0x14, RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS */
+ {0x00}, /* 0x15, RT_CHANNEL_DOMAIN_ETSI_NO_DFS */
+ {0x00}, /* 0x16, RT_CHANNEL_DOMAIN_KOREA_NO_DFS */
+ {0x03}, /* 0x17, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */
+ {0x06}, /* 0x18, RT_CHANNEL_DOMAIN_PAKISTAN_NO_DFS */
+ {0x02}, /* 0x19, RT_CHANNEL_DOMAIN_TAIWAN2_NO_DFS */
+ {0x00}, /* 0x1A, */
+ {0x00}, /* 0x1B, */
+ {0x00}, /* 0x1C, */
+ {0x00}, /* 0x1D, */
+ {0x00}, /* 0x1E, */
+ {0x06}, /* 0x1F, RT_CHANNEL_DOMAIN_WORLD_WIDE_ONLY_5G */
/* 0x20 ~ 0x7F , New Define ===== */
- {0x00, 0x00}, /* 0x20, RT_CHANNEL_DOMAIN_WORLD_NULL */
- {0x01, 0x00}, /* 0x21, RT_CHANNEL_DOMAIN_ETSI1_NULL */
- {0x02, 0x00}, /* 0x22, RT_CHANNEL_DOMAIN_FCC1_NULL */
- {0x03, 0x00}, /* 0x23, RT_CHANNEL_DOMAIN_MKK1_NULL */
- {0x04, 0x00}, /* 0x24, RT_CHANNEL_DOMAIN_ETSI2_NULL */
- {0x02, 0x04}, /* 0x25, RT_CHANNEL_DOMAIN_FCC1_FCC1 */
- {0x00, 0x01}, /* 0x26, RT_CHANNEL_DOMAIN_WORLD_ETSI1 */
- {0x03, 0x0C}, /* 0x27, RT_CHANNEL_DOMAIN_MKK1_MKK1 */
- {0x00, 0x0B}, /* 0x28, RT_CHANNEL_DOMAIN_WORLD_KCC1 */
- {0x00, 0x05}, /* 0x29, RT_CHANNEL_DOMAIN_WORLD_FCC2 */
- {0x00, 0x00}, /* 0x2A, */
- {0x00, 0x00}, /* 0x2B, */
- {0x00, 0x00}, /* 0x2C, */
- {0x00, 0x00}, /* 0x2D, */
- {0x00, 0x00}, /* 0x2E, */
- {0x00, 0x00}, /* 0x2F, */
- {0x00, 0x06}, /* 0x30, RT_CHANNEL_DOMAIN_WORLD_FCC3 */
- {0x00, 0x07}, /* 0x31, RT_CHANNEL_DOMAIN_WORLD_FCC4 */
- {0x00, 0x08}, /* 0x32, RT_CHANNEL_DOMAIN_WORLD_FCC5 */
- {0x00, 0x09}, /* 0x33, RT_CHANNEL_DOMAIN_WORLD_FCC6 */
- {0x02, 0x0A}, /* 0x34, RT_CHANNEL_DOMAIN_FCC1_FCC7 */
- {0x00, 0x02}, /* 0x35, RT_CHANNEL_DOMAIN_WORLD_ETSI2 */
- {0x00, 0x03}, /* 0x36, RT_CHANNEL_DOMAIN_WORLD_ETSI3 */
- {0x03, 0x0D}, /* 0x37, RT_CHANNEL_DOMAIN_MKK1_MKK2 */
- {0x03, 0x0E}, /* 0x38, RT_CHANNEL_DOMAIN_MKK1_MKK3 */
- {0x02, 0x0F}, /* 0x39, RT_CHANNEL_DOMAIN_FCC1_NCC1 */
- {0x00, 0x00}, /* 0x3A, */
- {0x00, 0x00}, /* 0x3B, */
- {0x00, 0x00}, /* 0x3C, */
- {0x00, 0x00}, /* 0x3D, */
- {0x00, 0x00}, /* 0x3E, */
- {0x00, 0x00}, /* 0x3F, */
- {0x02, 0x10}, /* 0x40, RT_CHANNEL_DOMAIN_FCC1_NCC2 */
- {0x05, 0x00}, /* 0x41, RT_CHANNEL_DOMAIN_GLOBAL_NULL */
- {0x01, 0x12}, /* 0x42, RT_CHANNEL_DOMAIN_ETSI1_ETSI4 */
- {0x02, 0x05}, /* 0x43, RT_CHANNEL_DOMAIN_FCC1_FCC2 */
- {0x02, 0x11}, /* 0x44, RT_CHANNEL_DOMAIN_FCC1_NCC3 */
- {0x00, 0x13}, /* 0x45, RT_CHANNEL_DOMAIN_WORLD_ETSI5 */
- {0x02, 0x14}, /* 0x46, RT_CHANNEL_DOMAIN_FCC1_FCC8 */
- {0x00, 0x15}, /* 0x47, RT_CHANNEL_DOMAIN_WORLD_ETSI6 */
- {0x00, 0x16}, /* 0x48, RT_CHANNEL_DOMAIN_WORLD_ETSI7 */
- {0x00, 0x17}, /* 0x49, RT_CHANNEL_DOMAIN_WORLD_ETSI8 */
- {0x00, 0x18}, /* 0x50, RT_CHANNEL_DOMAIN_WORLD_ETSI9 */
- {0x00, 0x19}, /* 0x51, RT_CHANNEL_DOMAIN_WORLD_ETSI10 */
- {0x00, 0x1A}, /* 0x52, RT_CHANNEL_DOMAIN_WORLD_ETSI11 */
- {0x02, 0x1B}, /* 0x53, RT_CHANNEL_DOMAIN_FCC1_NCC4 */
- {0x00, 0x1C}, /* 0x54, RT_CHANNEL_DOMAIN_WORLD_ETSI12 */
- {0x02, 0x1D}, /* 0x55, RT_CHANNEL_DOMAIN_FCC1_FCC9 */
- {0x00, 0x1E}, /* 0x56, RT_CHANNEL_DOMAIN_WORLD_ETSI13 */
- {0x02, 0x1F}, /* 0x57, RT_CHANNEL_DOMAIN_FCC1_FCC10 */
+ {0x00}, /* 0x20, RT_CHANNEL_DOMAIN_WORLD_NULL */
+ {0x01}, /* 0x21, RT_CHANNEL_DOMAIN_ETSI1_NULL */
+ {0x02}, /* 0x22, RT_CHANNEL_DOMAIN_FCC1_NULL */
+ {0x03}, /* 0x23, RT_CHANNEL_DOMAIN_MKK1_NULL */
+ {0x04}, /* 0x24, RT_CHANNEL_DOMAIN_ETSI2_NULL */
+ {0x02}, /* 0x25, RT_CHANNEL_DOMAIN_FCC1_FCC1 */
+ {0x00}, /* 0x26, RT_CHANNEL_DOMAIN_WORLD_ETSI1 */
+ {0x03}, /* 0x27, RT_CHANNEL_DOMAIN_MKK1_MKK1 */
+ {0x00}, /* 0x28, RT_CHANNEL_DOMAIN_WORLD_KCC1 */
+ {0x00}, /* 0x29, RT_CHANNEL_DOMAIN_WORLD_FCC2 */
+ {0x00}, /* 0x2A, */
+ {0x00}, /* 0x2B, */
+ {0x00}, /* 0x2C, */
+ {0x00}, /* 0x2D, */
+ {0x00}, /* 0x2E, */
+ {0x00}, /* 0x2F, */
+ {0x00}, /* 0x30, RT_CHANNEL_DOMAIN_WORLD_FCC3 */
+ {0x00}, /* 0x31, RT_CHANNEL_DOMAIN_WORLD_FCC4 */
+ {0x00}, /* 0x32, RT_CHANNEL_DOMAIN_WORLD_FCC5 */
+ {0x00}, /* 0x33, RT_CHANNEL_DOMAIN_WORLD_FCC6 */
+ {0x02}, /* 0x34, RT_CHANNEL_DOMAIN_FCC1_FCC7 */
+ {0x00}, /* 0x35, RT_CHANNEL_DOMAIN_WORLD_ETSI2 */
+ {0x00}, /* 0x36, RT_CHANNEL_DOMAIN_WORLD_ETSI3 */
+ {0x03}, /* 0x37, RT_CHANNEL_DOMAIN_MKK1_MKK2 */
+ {0x03}, /* 0x38, RT_CHANNEL_DOMAIN_MKK1_MKK3 */
+ {0x02}, /* 0x39, RT_CHANNEL_DOMAIN_FCC1_NCC1 */
+ {0x00}, /* 0x3A, */
+ {0x00}, /* 0x3B, */
+ {0x00}, /* 0x3C, */
+ {0x00}, /* 0x3D, */
+ {0x00}, /* 0x3E, */
+ {0x00}, /* 0x3F, */
+ {0x02}, /* 0x40, RT_CHANNEL_DOMAIN_FCC1_NCC2 */
+ {0x05}, /* 0x41, RT_CHANNEL_DOMAIN_GLOBAL_NULL */
+ {0x01}, /* 0x42, RT_CHANNEL_DOMAIN_ETSI1_ETSI4 */
+ {0x02}, /* 0x43, RT_CHANNEL_DOMAIN_FCC1_FCC2 */
+ {0x02}, /* 0x44, RT_CHANNEL_DOMAIN_FCC1_NCC3 */
+ {0x00}, /* 0x45, RT_CHANNEL_DOMAIN_WORLD_ETSI5 */
+ {0x02}, /* 0x46, RT_CHANNEL_DOMAIN_FCC1_FCC8 */
+ {0x00}, /* 0x47, RT_CHANNEL_DOMAIN_WORLD_ETSI6 */
+ {0x00}, /* 0x48, RT_CHANNEL_DOMAIN_WORLD_ETSI7 */
+ {0x00}, /* 0x49, RT_CHANNEL_DOMAIN_WORLD_ETSI8 */
+ {0x00}, /* 0x50, RT_CHANNEL_DOMAIN_WORLD_ETSI9 */
+ {0x00}, /* 0x51, RT_CHANNEL_DOMAIN_WORLD_ETSI10 */
+ {0x00}, /* 0x52, RT_CHANNEL_DOMAIN_WORLD_ETSI11 */
+ {0x02}, /* 0x53, RT_CHANNEL_DOMAIN_FCC1_NCC4 */
+ {0x00}, /* 0x54, RT_CHANNEL_DOMAIN_WORLD_ETSI12 */
+ {0x02}, /* 0x55, RT_CHANNEL_DOMAIN_FCC1_FCC9 */
+ {0x00}, /* 0x56, RT_CHANNEL_DOMAIN_WORLD_ETSI13 */
+ {0x02}, /* 0x57, RT_CHANNEL_DOMAIN_FCC1_FCC10 */
};
/* use the combination for max channel numbers */
-static struct rt_channel_plan_map RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03, 0x02};
+static struct rt_channel_plan_map RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03};
/* Search the @param ch in given @param ch_set
* @ch_set: the given channel set
@@ -231,23 +188,6 @@ int rtw_ch_set_search_ch(struct rt_channel_info *ch_set, const u32 ch)
return i;
}
-/* Check the @param ch is fit with setband setting of @param adapter
- * @adapter: the given adapter
- * @ch: the given channel number
- *
- * return true when check valid, false not valid
- */
-bool rtw_mlme_band_check(struct adapter *adapter, const u32 ch)
-{
- if (adapter->setband == GHZ24_50 /* 2.4G and 5G */
- || (adapter->setband == GHZ_24 && ch < 35) /* 2.4G only */
- || (adapter->setband == GHZ_50 && ch > 35) /* 5G only */
- ) {
- return true;
- }
- return false;
-}
-
/****************************************************************************
Following are the initialization functions for WiFi MLME
@@ -395,8 +335,8 @@ static void init_channel_list(struct adapter *padapter, struct rt_channel_info *
static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, struct rt_channel_info *channel_set)
{
u8 index, chanset_size = 0;
- u8 b5GBand = false, b2_4GBand = false;
- u8 Index2G = 0, Index5G = 0;
+ u8 b2_4GBand = false;
+ u8 Index2G = 0;
memset(channel_set, 0, sizeof(struct rt_channel_info)*MAX_CHANNEL_NUM);
@@ -422,7 +362,6 @@ static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, struct rt_c
else if ((channel_set[chanset_size].ChannelNum >= 12 && channel_set[chanset_size].ChannelNum <= 14))
channel_set[chanset_size].ScanType = SCAN_PASSIVE;
} else if (RT_CHANNEL_DOMAIN_WORLD_WIDE_13 == ChannelPlan ||
- RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == ChannelPlan ||
RT_CHANNEL_DOMAIN_2G_WORLD == Index2G) { /* channel 12~13, passive scan */
if (channel_set[chanset_size].ChannelNum <= 11)
channel_set[chanset_size].ScanType = SCAN_ACTIVE;
@@ -435,20 +374,6 @@ static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, struct rt_c
}
}
- if (b5GBand) {
- for (index = 0; index < RTW_ChannelPlan5G[Index5G].Len; index++) {
- if (RTW_ChannelPlan5G[Index5G].Channel[index] <= 48
- || RTW_ChannelPlan5G[Index5G].Channel[index] >= 149) {
- channel_set[chanset_size].ChannelNum = RTW_ChannelPlan5G[Index5G].Channel[index];
- if (RT_CHANNEL_DOMAIN_WORLD_WIDE_5G == ChannelPlan)/* passive scan for all 5G channels */
- channel_set[chanset_size].ScanType = SCAN_PASSIVE;
- else
- channel_set[chanset_size].ScanType = SCAN_ACTIVE;
- chanset_size++;
- }
- }
- }
-
return chanset_size;
}
@@ -1021,7 +946,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
u16 capab_info;
struct rtw_ieee802_11_elems elems;
struct sta_info *pstat;
- unsigned char reassoc, *p, *pos, *wpa_ie;
+ unsigned char *p, *pos, *wpa_ie;
unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01};
int i, ie_len, wpa_ie_len, left;
unsigned char supportRate[16];
@@ -1041,13 +966,10 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
return _FAIL;
frame_type = GetFrameSubType(pframe);
- if (frame_type == WIFI_ASSOCREQ) {
- reassoc = 0;
+ if (frame_type == WIFI_ASSOCREQ)
ie_offset = _ASOCREQ_IE_OFFSET_;
- } else { /* WIFI_REASSOCREQ */
- reassoc = 1;
+ else /* WIFI_REASSOCREQ */
ie_offset = _REASOCREQ_IE_OFFSET_;
- }
if (pkt_len < sizeof(struct ieee80211_hdr_3addr) + ie_offset)
@@ -1726,7 +1648,7 @@ unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_fra
struct recv_reorder_ctrl *preorder_ctrl;
unsigned char *frame_body;
unsigned char category, action;
- unsigned short tid, status, reason_code = 0;
+ unsigned short tid, status;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
u8 *pframe = precv_frame->u.hdr.rx_data;
@@ -1795,9 +1717,6 @@ unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_fra
~BIT((frame_body[3] >> 4) & 0xf);
psta->htpriv.candidate_tid_bitmap &=
~BIT((frame_body[3] >> 4) & 0xf);
-
- /* reason_code = frame_body[4] | (frame_body[5] << 8); */
- reason_code = get_unaligned_le16(&frame_body[4]);
} else if ((frame_body[3] & BIT(3)) == BIT(3)) {
tid = (frame_body[3] >> 4) & 0x0F;
@@ -2142,7 +2061,7 @@ s32 dump_mgntframe_and_wait(struct adapter *padapter, struct xmit_frame *pmgntfr
ret = rtw_hal_mgnt_xmit(padapter, pmgntframe);
if (ret == _SUCCESS)
- ret = rtw_sctx_wait(&sctx, __func__);
+ ret = rtw_sctx_wait(&sctx);
spin_lock_irqsave(&pxmitpriv->lock_sctx, irqL);
pxmitbuf->sctx = NULL;
@@ -2226,7 +2145,6 @@ void issue_beacon(struct adapter *padapter, int timeout_ms)
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
- u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
if (!pmgntframe)
@@ -2248,7 +2166,7 @@ void issue_beacon(struct adapter *padapter, int timeout_ms)
fctrl = &(pwlanhdr->frame_control);
*(fctrl) = 0;
- memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+ eth_broadcast_addr(pwlanhdr->addr1);
memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
@@ -2457,9 +2375,13 @@ void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p
u8 *ssid_ie;
signed int ssid_ielen;
signed int ssid_ielen_diff;
- u8 buf[MAX_IE_SZ];
+ u8 *buf;
u8 *ies = pmgntframe->buf_addr+TXDESC_OFFSET+sizeof(struct ieee80211_hdr_3addr);
+ buf = rtw_zmalloc(MAX_IE_SZ);
+ if (!buf)
+ return;
+
ssid_ie = rtw_get_ie(ies+_FIXED_IE_LENGTH_, WLAN_EID_SSID, &ssid_ielen,
(pframe-ies)-_FIXED_IE_LENGTH_);
@@ -2487,6 +2409,7 @@ void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p
pframe += ssid_ielen_diff;
pattrib->pktlen += ssid_ielen_diff;
}
+ kfree (buf);
}
} else {
/* timestamp will be inserted by hardware */
@@ -2567,7 +2490,6 @@ static int _issue_probereq(struct adapter *padapter,
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
int bssrate_len = 0;
- u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
if (!pmgntframe)
@@ -2594,8 +2516,8 @@ static int _issue_probereq(struct adapter *padapter,
memcpy(pwlanhdr->addr3, da, ETH_ALEN);
} else {
/* broadcast probe request frame */
- memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
- memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN);
+ eth_broadcast_addr(pwlanhdr->addr1);
+ eth_broadcast_addr(pwlanhdr->addr3);
}
memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
@@ -4483,61 +4405,6 @@ static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid
}
}
- if (pregistrypriv->wireless_mode & WIRELESS_11A) {
- do {
- if ((i == MAX_CHANNEL_NUM) ||
- (chplan_sta[i].ChannelNum == 0))
- break;
-
- if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] == 0))
- break;
-
- if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) {
- chplan_new[k].ChannelNum = chplan_ap.Channel[j];
- chplan_new[k].ScanType = SCAN_ACTIVE;
- i++;
- j++;
- k++;
- } else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) {
- chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
-/* chplan_new[k].ScanType = chplan_sta[i].ScanType; */
- chplan_new[k].ScanType = SCAN_PASSIVE;
- i++;
- k++;
- } else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) {
- chplan_new[k].ChannelNum = chplan_ap.Channel[j];
- chplan_new[k].ScanType = SCAN_ACTIVE;
- j++;
- k++;
- }
- } while (1);
-
- /* change AP not support channel to Passive scan */
- while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) {
- chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
-/* chplan_new[k].ScanType = chplan_sta[i].ScanType; */
- chplan_new[k].ScanType = SCAN_PASSIVE;
- i++;
- k++;
- }
-
- /* add channel AP supported */
- while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] != 0)) {
- chplan_new[k].ChannelNum = chplan_ap.Channel[j];
- chplan_new[k].ScanType = SCAN_ACTIVE;
- j++;
- k++;
- }
- } else {
- /* keep original STA 5G channel plan */
- while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) {
- chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
- chplan_new[k].ScanType = chplan_sta[i].ScanType;
- i++;
- k++;
- }
- }
-
pmlmeext->update_channel_plan_by_ap_done = 1;
}
@@ -4548,10 +4415,6 @@ static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid
while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) {
if (chplan_new[i].ChannelNum == channel) {
if (chplan_new[i].ScanType == SCAN_PASSIVE) {
- /* 5G Bnad 2, 3 (DFS) doesn't change to active scan */
- if (channel >= 52 && channel <= 144)
- break;
-
chplan_new[i].ScanType = SCAN_ACTIVE;
}
break;
@@ -5125,24 +4988,9 @@ void _linked_info_dump(struct adapter *padapter)
if (padapter->bLinkInfoDump) {
- if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) {
+ if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)
rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB);
- } else if ((pmlmeinfo->state&0x03) == _HW_STATE_AP_) {
- struct list_head *phead, *plist;
-
- struct sta_info *psta = NULL;
- struct sta_priv *pstapriv = &padapter->stapriv;
- spin_lock_bh(&pstapriv->asoc_list_lock);
- phead = &pstapriv->asoc_list;
- plist = get_next(phead);
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, asoc_list);
- plist = get_next(plist);
- }
- spin_unlock_bh(&pstapriv->asoc_list_lock);
-
- }
for (i = 0; i < NUM_STA; i++) {
if (pdvobj->macid[i]) {
if (i != 1) /* skip bc/mc sta */
@@ -5151,11 +4999,7 @@ void _linked_info_dump(struct adapter *padapter)
}
}
rtw_hal_set_def_var(padapter, HAL_DEF_DBG_RX_INFO_DUMP, NULL);
-
-
}
-
-
}
static u8 chk_ap_is_alive(struct adapter *padapter, struct sta_info *psta)
@@ -5452,9 +5296,7 @@ u8 createbss_hdl(struct adapter *padapter, u8 *pbuf)
/* u32 initialgain; */
if (pmlmeinfo->state == WIFI_FW_AP_STATE) {
- struct wlan_bssid_ex *network = &padapter->mlmepriv.cur_network.network;
-
- start_bss_network(padapter, (u8 *)network);
+ start_bss_network(padapter);
return H2C_SUCCESS;
}
@@ -5692,7 +5534,6 @@ static int rtw_scan_ch_decision(struct adapter *padapter, struct rtw_ieee80211_c
set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, in[i].hw_value);
if (in[i].hw_value && !(in[i].flags & RTW_IEEE80211_CHAN_DISABLED)
&& set_idx >= 0
- && rtw_mlme_band_check(padapter, in[i].hw_value)
) {
if (j >= out_num) {
netdev_dbg(padapter->pnetdev,
@@ -5716,23 +5557,20 @@ static int rtw_scan_ch_decision(struct adapter *padapter, struct rtw_ieee80211_c
if (j == 0) {
for (i = 0; i < pmlmeext->max_chan_nums; i++) {
- if (rtw_mlme_band_check(padapter, pmlmeext->channel_set[i].ChannelNum)) {
-
- if (j >= out_num) {
- netdev_dbg(padapter->pnetdev,
- FUNC_ADPT_FMT " out_num:%u not enough\n",
- FUNC_ADPT_ARG(padapter),
- out_num);
- break;
- }
+ if (j >= out_num) {
+ netdev_dbg(padapter->pnetdev,
+ FUNC_ADPT_FMT " out_num:%u not enough\n",
+ FUNC_ADPT_ARG(padapter),
+ out_num);
+ break;
+ }
- out[j].hw_value = pmlmeext->channel_set[i].ChannelNum;
+ out[j].hw_value = pmlmeext->channel_set[i].ChannelNum;
- if (pmlmeext->channel_set[i].ScanType == SCAN_PASSIVE)
- out[j].flags |= RTW_IEEE80211_CHAN_PASSIVE_SCAN;
+ if (pmlmeext->channel_set[i].ScanType == SCAN_PASSIVE)
+ out[j].flags |= RTW_IEEE80211_CHAN_PASSIVE_SCAN;
- j++;
- }
+ j++;
}
}
@@ -5997,10 +5835,40 @@ exit:
return res;
}
+static struct fwevent wlanevents[] = {
+ {0, rtw_dummy_event_callback}, /*0*/
+ {0, NULL},
+ {0, NULL},
+ {0, NULL},
+ {0, NULL},
+ {0, NULL},
+ {0, NULL},
+ {0, NULL},
+ {0, &rtw_survey_event_callback}, /*8*/
+ {sizeof(struct surveydone_event), &rtw_surveydone_event_callback}, /*9*/
+
+ {0, &rtw_joinbss_event_callback}, /*10*/
+ {sizeof(struct stassoc_event), &rtw_stassoc_event_callback},
+ {sizeof(struct stadel_event), &rtw_stadel_event_callback},
+ {0, &rtw_atimdone_event_callback},
+ {0, rtw_dummy_event_callback},
+ {0, NULL}, /*15*/
+ {0, NULL},
+ {0, NULL},
+ {0, NULL},
+ {0, rtw_fwdbg_event_callback},
+ {0, NULL}, /*20*/
+ {0, NULL},
+ {0, NULL},
+ {0, &rtw_cpwm_event_callback},
+ {0, NULL},
+ {0, &rtw_wmm_event_callback},
+
+};
u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf)
{
- u8 evt_code, evt_seq;
+ u8 evt_code;
u16 evt_sz;
uint *peventbuf;
void (*event_callback)(struct adapter *dev, u8 *pbuf);
@@ -6011,19 +5879,8 @@ u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf)
peventbuf = (uint *)pbuf;
evt_sz = (u16)(*peventbuf&0xffff);
- evt_seq = (u8)((*peventbuf>>24)&0x7f);
evt_code = (u8)((*peventbuf>>16)&0xff);
-
- #ifdef CHECK_EVENT_SEQ
- /* checking event sequence... */
- if (evt_seq != (atomic_read(&pevt_priv->event_seq) & 0x7f)) {
- pevt_priv->event_seq = (evt_seq+1)&0x7f;
-
- goto _abort_event_;
- }
- #endif
-
/* checking if event code is valid */
if (evt_code >= MAX_C2HEVT)
goto _abort_event_;
@@ -6063,7 +5920,7 @@ u8 h2c_msg_hdl(struct adapter *padapter, unsigned char *pbuf)
u8 chk_bmc_sleepq_hdl(struct adapter *padapter, unsigned char *pbuf)
{
struct sta_info *psta_bmc;
- struct list_head *xmitframe_plist, *xmitframe_phead;
+ struct list_head *xmitframe_plist, *xmitframe_phead, *tmp;
struct xmit_frame *pxmitframe = NULL;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct sta_priv *pstapriv = &padapter->stapriv;
@@ -6080,12 +5937,9 @@ u8 chk_bmc_sleepq_hdl(struct adapter *padapter, unsigned char *pbuf)
spin_lock_bh(&pxmitpriv->lock);
xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
- xmitframe_plist = get_next(xmitframe_phead);
-
- while (xmitframe_phead != xmitframe_plist) {
- pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
-
- xmitframe_plist = get_next(xmitframe_plist);
+ list_for_each_safe(xmitframe_plist, tmp, xmitframe_phead) {
+ pxmitframe = list_entry(xmitframe_plist,
+ struct xmit_frame, list);
list_del_init(&pxmitframe->list);
diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
index 251b9abdf591..a392d5b4caf2 100644
--- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
+++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
@@ -4,8 +4,6 @@
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-#define _RTW_PWRCTRL_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
#include <hal_data.h>
diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c
index 668a703dee7f..d4c1725718d9 100644
--- a/drivers/staging/rtl8723bs/core/rtw_recv.c
+++ b/drivers/staging/rtl8723bs/core/rtw_recv.c
@@ -4,8 +4,6 @@
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-#define _RTW_RECV_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
#include <linux/jiffies.h>
@@ -1646,16 +1644,10 @@ static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_n
/* Rx Reorder initialize condition. */
if (preorder_ctrl->indicate_seq == 0xFFFF) {
preorder_ctrl->indicate_seq = seq_num;
-
- /* DbgPrint("check_indicate_seq, 1st->indicate_seq =%d\n", precvpriv->indicate_seq); */
}
- /* DbgPrint("enter->check_indicate_seq(): IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */
-
/* Drop out the packet which SeqNum is smaller than WinStart */
if (SN_LESS(seq_num, preorder_ctrl->indicate_seq)) {
- /* DbgPrint("CheckRxTsIndicateSeq(): Packet Drop! IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */
-
return false;
}
@@ -1668,8 +1660,6 @@ static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_n
preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF;
} else if (SN_LESS(wend, seq_num)) {
- /* DbgPrint("CheckRxTsIndicateSeq(): Window Shift! IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */
-
/* boundary situation, when seq_num cross 0xFFF */
if (seq_num >= (wsize - 1))
preorder_ctrl->indicate_seq = seq_num + 1 - wsize;
@@ -1678,8 +1668,6 @@ static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_n
pdbgpriv->dbg_rx_ampdu_window_shift_cnt++;
}
- /* DbgPrint("exit->check_indicate_seq(): IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */
-
return true;
}
@@ -1691,8 +1679,6 @@ static int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, un
union recv_frame *pnextrframe;
struct rx_pkt_attrib *pnextattrib;
- /* DbgPrint("+enqueue_reorder_recvframe()\n"); */
-
/* spin_lock_irqsave(&ppending_recvframe_queue->lock, irql); */
/* spin_lock(&ppending_recvframe_queue->lock); */
@@ -1713,8 +1699,6 @@ static int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, un
else
break;
- /* DbgPrint("enqueue_reorder_recvframe():while\n"); */
-
}
@@ -1753,8 +1737,6 @@ static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reor
struct dvobj_priv *psdpriv = padapter->dvobj;
struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
- /* DbgPrint("+recv_indicatepkts_in_order\n"); */
-
/* spin_lock_irqsave(&ppending_recvframe_queue->lock, irql); */
/* spin_lock(&ppending_recvframe_queue->lock); */
@@ -1796,11 +1778,8 @@ static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reor
/* pTS->RxIndicateState = RXTS_INDICATE_PROCESSING; */
/* Indicate packets */
- /* RT_ASSERT((index<=REORDER_WIN_SIZE), ("RxReorderIndicatePacket(): Rx Reorder buffer full!!\n")); */
-
/* indicate this recv_frame */
- /* DbgPrint("recv_indicatepkts_in_order, indicate_seq =%d, seq_num =%d\n", precvpriv->indicate_seq, pattrib->seq_num); */
if (!pattrib->amsdu) {
if ((padapter->bDriverStopped == false) &&
(padapter->bSurpriseRemoved == false))
@@ -1823,8 +1802,6 @@ static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reor
break;
}
- /* DbgPrint("recv_indicatepkts_in_order():while\n"); */
-
}
/* spin_unlock(&ppending_recvframe_queue->lock); */
@@ -1894,7 +1871,6 @@ static int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *
/* s3. Insert all packet into Reorder Queue to maintain its ordering. */
if (!enqueue_reorder_recvframe(preorder_ctrl, prframe)) {
- /* DbgPrint("recv_indicatepkt_reorder, enqueue_reorder_recvframe fail!\n"); */
/* spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); */
/* return _FAIL; */
goto _err_exit;
@@ -2123,7 +2099,7 @@ static void rtw_signal_stat_timer_hdl(struct timer_list *t)
u8 avg_signal_strength = 0;
u8 avg_signal_qual = 0;
u32 num_signal_strength = 0;
- u32 num_signal_qual = 0;
+ u32 __maybe_unused num_signal_qual = 0;
u8 _alpha = 5; /* this value is based on converging_constant = 5000 and sampling_interval = 1000 */
if (adapter->recvpriv.is_signal_dbg) {
diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c
index 7823055ed32d..a99f439328f1 100644
--- a/drivers/staging/rtl8723bs/core/rtw_security.c
+++ b/drivers/staging/rtl8723bs/core/rtw_security.c
@@ -4,11 +4,10 @@
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-#define _RTW_SECURITY_C_
-
-#include <linux/crc32poly.h>
+#include <linux/crc32.h>
#include <drv_types.h>
#include <rtw_debug.h>
+#include <crypto/aes.h>
static const char * const _security_type_str[] = {
"N/A",
@@ -31,118 +30,6 @@ const char *security_type_str(u8 value)
/* WEP related ===== */
-struct arc4context {
- u32 x;
- u32 y;
- u8 state[256];
-};
-
-
-static void arcfour_init(struct arc4context *parc4ctx, u8 *key, u32 key_len)
-{
- u32 t, u;
- u32 keyindex;
- u32 stateindex;
- u8 *state;
- u32 counter;
-
- state = parc4ctx->state;
- parc4ctx->x = 0;
- parc4ctx->y = 0;
- for (counter = 0; counter < 256; counter++)
- state[counter] = (u8)counter;
- keyindex = 0;
- stateindex = 0;
- for (counter = 0; counter < 256; counter++) {
- t = state[counter];
- stateindex = (stateindex + key[keyindex] + t) & 0xff;
- u = state[stateindex];
- state[stateindex] = (u8)t;
- state[counter] = (u8)u;
- if (++keyindex >= key_len)
- keyindex = 0;
- }
-}
-
-static u32 arcfour_byte(struct arc4context *parc4ctx)
-{
- u32 x;
- u32 y;
- u32 sx, sy;
- u8 *state;
-
- state = parc4ctx->state;
- x = (parc4ctx->x + 1) & 0xff;
- sx = state[x];
- y = (sx + parc4ctx->y) & 0xff;
- sy = state[y];
- parc4ctx->x = x;
- parc4ctx->y = y;
- state[y] = (u8)sx;
- state[x] = (u8)sy;
- return state[(sx + sy) & 0xff];
-}
-
-static void arcfour_encrypt(struct arc4context *parc4ctx, u8 *dest, u8 *src, u32 len)
-{
- u32 i;
-
- for (i = 0; i < len; i++)
- dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx);
-}
-
-static signed int bcrc32initialized;
-static u32 crc32_table[256];
-
-
-static u8 crc32_reverseBit(u8 data)
-{
- return((u8)((data<<7)&0x80) | ((data<<5)&0x40) | ((data<<3)&0x20) | ((data<<1)&0x10) | ((data>>1)&0x08) | ((data>>3)&0x04) | ((data>>5)&0x02) | ((data>>7)&0x01));
-}
-
-static void crc32_init(void)
-{
- if (bcrc32initialized == 1)
- return;
- else {
- signed int i, j;
- u32 c;
- u8 *p = (u8 *)&c, *p1;
- u8 k;
-
- c = 0x12340000;
-
- for (i = 0; i < 256; ++i) {
- k = crc32_reverseBit((u8)i);
- for (c = ((u32)k) << 24, j = 8; j > 0; --j)
- c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY_BE : (c << 1);
- p1 = (u8 *)&crc32_table[i];
-
- p1[0] = crc32_reverseBit(p[3]);
- p1[1] = crc32_reverseBit(p[2]);
- p1[2] = crc32_reverseBit(p[1]);
- p1[3] = crc32_reverseBit(p[0]);
- }
- bcrc32initialized = 1;
- }
-}
-
-static __le32 getcrc32(u8 *buf, signed int len)
-{
- u8 *p;
- u32 crc;
-
- if (bcrc32initialized == 0)
- crc32_init();
-
- crc = 0xffffffff; /* preload shift register, per CRC-32 spec */
-
- for (p = buf; len > 0; ++p, --len)
- crc = crc32_table[(crc ^ *p) & 0xff] ^ (crc >> 8);
- return cpu_to_le32(~crc); /* transmit complement, per CRC-32 spec */
-}
-
-
/*
Need to consider the fragment situation
*/
@@ -150,7 +37,6 @@ void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe)
{ /* exclude ICV */
unsigned char crc[4];
- struct arc4context mycontext;
signed int curfragnum, length;
u32 keylength;
@@ -161,6 +47,7 @@ void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe)
struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib;
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct arc4_ctx *ctx = &psecuritypriv->xmit_arc4_ctx;
if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL)
return;
@@ -182,18 +69,18 @@ void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe)
length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
- *((__le32 *)crc) = getcrc32(payload, length);
+ *((__le32 *)crc) = ~crc32_le(~0, payload, length);
- arcfour_init(&mycontext, wepkey, 3+keylength);
- arcfour_encrypt(&mycontext, payload, payload, length);
- arcfour_encrypt(&mycontext, payload+length, crc, 4);
+ arc4_setkey(ctx, wepkey, 3 + keylength);
+ arc4_crypt(ctx, payload, payload, length);
+ arc4_crypt(ctx, payload + length, crc, 4);
} else {
length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
- *((__le32 *)crc) = getcrc32(payload, length);
- arcfour_init(&mycontext, wepkey, 3+keylength);
- arcfour_encrypt(&mycontext, payload, payload, length);
- arcfour_encrypt(&mycontext, payload+length, crc, 4);
+ *((__le32 *)crc) = ~crc32_le(~0, payload, length);
+ arc4_setkey(ctx, wepkey, 3 + keylength);
+ arc4_crypt(ctx, payload, payload, length);
+ arc4_crypt(ctx, payload + length, crc, 4);
pframe += pxmitpriv->frag_len;
pframe = (u8 *)round_up((SIZE_PTR)(pframe), 4);
@@ -206,13 +93,13 @@ void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe)
{
/* exclude ICV */
u8 crc[4];
- struct arc4context mycontext;
signed int length;
u32 keylength;
u8 *pframe, *payload, *iv, wepkey[16];
u8 keyindex;
struct rx_pkt_attrib *prxattrib = &(((union recv_frame *)precvframe)->u.hdr.attrib);
struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct arc4_ctx *ctx = &psecuritypriv->recv_arc4_ctx;
pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
@@ -230,11 +117,11 @@ void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe)
payload = pframe+prxattrib->iv_len+prxattrib->hdrlen;
/* decrypt payload include icv */
- arcfour_init(&mycontext, wepkey, 3+keylength);
- arcfour_encrypt(&mycontext, payload, payload, length);
+ arc4_setkey(ctx, wepkey, 3 + keylength);
+ arc4_crypt(ctx, payload, payload, length);
/* calculate icv and compare the icv */
- *((u32 *)crc) = le32_to_cpu(getcrc32(payload, length-4));
+ *((u32 *)crc) = le32_to_cpu(~crc32_le(~0, payload, length - 4));
}
}
@@ -579,7 +466,6 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe)
u8 ttkey[16];
u8 crc[4];
u8 hw_hdr_offset = 0;
- struct arc4context mycontext;
signed int curfragnum, length;
u8 *pframe, *payload, *iv, *prwskey;
@@ -587,6 +473,7 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe)
struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib;
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct arc4_ctx *ctx = &psecuritypriv->xmit_arc4_ctx;
u32 res = _SUCCESS;
if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL)
@@ -619,18 +506,19 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe)
if ((curfragnum+1) == pattrib->nr_frags) { /* 4 the last fragment */
length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
- *((__le32 *)crc) = getcrc32(payload, length);/* modified by Amy*/
+ *((__le32 *)crc) = ~crc32_le(~0, payload, length);
- arcfour_init(&mycontext, rc4key, 16);
- arcfour_encrypt(&mycontext, payload, payload, length);
- arcfour_encrypt(&mycontext, payload+length, crc, 4);
+ arc4_setkey(ctx, rc4key, 16);
+ arc4_crypt(ctx, payload, payload, length);
+ arc4_crypt(ctx, payload + length, crc, 4);
} else {
length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
- *((__le32 *)crc) = getcrc32(payload, length);/* modified by Amy*/
- arcfour_init(&mycontext, rc4key, 16);
- arcfour_encrypt(&mycontext, payload, payload, length);
- arcfour_encrypt(&mycontext, payload+length, crc, 4);
+ *((__le32 *)crc) = ~crc32_le(~0, payload, length);
+
+ arc4_setkey(ctx, rc4key, 16);
+ arc4_crypt(ctx, payload, payload, length);
+ arc4_crypt(ctx, payload + length, crc, 4);
pframe += pxmitpriv->frag_len;
pframe = (u8 *)round_up((SIZE_PTR)(pframe), 4);
@@ -650,7 +538,6 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe)
u8 rc4key[16];
u8 ttkey[16];
u8 crc[4];
- struct arc4context mycontext;
signed int length;
u8 *pframe, *payload, *iv, *prwskey;
@@ -658,6 +545,7 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe)
struct sta_info *stainfo;
struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib;
struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct arc4_ctx *ctx = &psecuritypriv->recv_arc4_ctx;
u32 res = _SUCCESS;
pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
@@ -727,10 +615,10 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe)
/* 4 decrypt payload include icv */
- arcfour_init(&mycontext, rc4key, 16);
- arcfour_encrypt(&mycontext, payload, payload, length);
+ arc4_setkey(ctx, rc4key, 16);
+ arc4_crypt(ctx, payload, payload, length);
- *((u32 *)crc) = le32_to_cpu(getcrc32(payload, length-4));
+ *((u32 *)crc) = le32_to_cpu(~crc32_le(~0, payload, length - 4));
if (crc[3] != payload[length - 1] || crc[2] != payload[length - 2] ||
crc[1] != payload[length - 3] || crc[0] != payload[length - 4])
@@ -749,44 +637,6 @@ exit:
#define MAX_MSG_SIZE 2048
-/*****************************/
-/******** SBOX Table *********/
-/*****************************/
-
- static const u8 sbox_table[256] = {
- 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
- 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
- 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
- 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
- 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
- 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
- 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
- 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
- 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
- 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
- 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
- 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
- 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
- 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
- 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
- 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
- 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
- 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
- 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
- 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
- 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
- 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
- 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
- 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
- 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
- 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
- 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
- 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
- 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
- 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
- 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
- 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
- };
/*****************************/
/**** Function Prototypes ****/
@@ -815,13 +665,7 @@ static void construct_ctr_preload(u8 *ctr_preload,
u8 *pn_vector,
signed int c,
uint frtype); /* for CONFIG_IEEE80211W, none 11w also can use */
-static void xor_128(u8 *a, u8 *b, u8 *out);
-static void xor_32(u8 *a, u8 *b, u8 *out);
-static u8 sbox(u8 a);
-static void next_key(u8 *key, signed int round);
-static void byte_sub(u8 *in, u8 *out);
-static void shift_row(u8 *in, u8 *out);
-static void mix_column(u8 *in, u8 *out);
+
static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext);
@@ -830,171 +674,13 @@ static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext);
/* Performs a 128 bit AES encrypt with */
/* 128 bit data. */
/****************************************/
-static void xor_128(u8 *a, u8 *b, u8 *out)
-{
- signed int i;
-
- for (i = 0; i < 16; i++)
- out[i] = a[i] ^ b[i];
-}
-
-
-static void xor_32(u8 *a, u8 *b, u8 *out)
-{
- signed int i;
-
- for (i = 0; i < 4; i++)
- out[i] = a[i] ^ b[i];
-}
-
-
-static u8 sbox(u8 a)
-{
- return sbox_table[(signed int)a];
-}
-
-
-static void next_key(u8 *key, signed int round)
-{
- u8 rcon;
- u8 sbox_key[4];
- static const u8 rcon_table[12] = {
- 0x01, 0x02, 0x04, 0x08,
- 0x10, 0x20, 0x40, 0x80,
- 0x1b, 0x36, 0x36, 0x36
- };
- sbox_key[0] = sbox(key[13]);
- sbox_key[1] = sbox(key[14]);
- sbox_key[2] = sbox(key[15]);
- sbox_key[3] = sbox(key[12]);
-
- rcon = rcon_table[round];
-
- xor_32(&key[0], sbox_key, &key[0]);
- key[0] = key[0] ^ rcon;
-
- xor_32(&key[4], &key[0], &key[4]);
- xor_32(&key[8], &key[4], &key[8]);
- xor_32(&key[12], &key[8], &key[12]);
-}
-
-
-static void byte_sub(u8 *in, u8 *out)
-{
- signed int i;
-
- for (i = 0; i < 16; i++)
- out[i] = sbox(in[i]);
-}
-
-
-static void shift_row(u8 *in, u8 *out)
-{
- out[0] = in[0];
- out[1] = in[5];
- out[2] = in[10];
- out[3] = in[15];
- out[4] = in[4];
- out[5] = in[9];
- out[6] = in[14];
- out[7] = in[3];
- out[8] = in[8];
- out[9] = in[13];
- out[10] = in[2];
- out[11] = in[7];
- out[12] = in[12];
- out[13] = in[1];
- out[14] = in[6];
- out[15] = in[11];
-}
-
-static void mix_column(u8 *in, u8 *out)
-{
- signed int i;
- u8 add1b[4];
- u8 add1bf7[4];
- u8 rotl[4];
- u8 swap_halfs[4];
- u8 andf7[4];
- u8 rotr[4];
- u8 temp[4];
- u8 tempb[4];
-
- for (i = 0; i < 4; i++) {
- if ((in[i] & 0x80) == 0x80)
- add1b[i] = 0x1b;
- else
- add1b[i] = 0x00;
- }
-
- swap_halfs[0] = in[2]; /* Swap halfs */
- swap_halfs[1] = in[3];
- swap_halfs[2] = in[0];
- swap_halfs[3] = in[1];
-
- rotl[0] = in[3]; /* Rotate left 8 bits */
- rotl[1] = in[0];
- rotl[2] = in[1];
- rotl[3] = in[2];
-
- andf7[0] = in[0] & 0x7f;
- andf7[1] = in[1] & 0x7f;
- andf7[2] = in[2] & 0x7f;
- andf7[3] = in[3] & 0x7f;
-
- for (i = 3; i > 0; i--) { /* logical shift left 1 bit */
- andf7[i] = andf7[i] << 1;
- if ((andf7[i-1] & 0x80) == 0x80)
- andf7[i] = (andf7[i] | 0x01);
- }
- andf7[0] = andf7[0] << 1;
- andf7[0] = andf7[0] & 0xfe;
-
- xor_32(add1b, andf7, add1bf7);
-
- xor_32(in, add1bf7, rotr);
-
- temp[0] = rotr[0]; /* Rotate right 8 bits */
- rotr[0] = rotr[1];
- rotr[1] = rotr[2];
- rotr[2] = rotr[3];
- rotr[3] = temp[0];
-
- xor_32(add1bf7, rotr, temp);
- xor_32(swap_halfs, rotl, tempb);
- xor_32(temp, tempb, out);
-}
-
static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext)
{
- signed int round;
- signed int i;
- u8 intermediatea[16];
- u8 intermediateb[16];
- u8 round_key[16];
+ struct crypto_aes_ctx ctx;
- for (i = 0; i < 16; i++)
- round_key[i] = key[i];
-
- for (round = 0; round < 11; round++) {
- if (round == 0) {
- xor_128(round_key, data, ciphertext);
- next_key(round_key, round);
- } else if (round == 10) {
- byte_sub(ciphertext, intermediatea);
- shift_row(intermediatea, intermediateb);
- xor_128(intermediateb, round_key, ciphertext);
- } else { /* 1 - 9 */
- byte_sub(ciphertext, intermediatea);
- shift_row(intermediatea, intermediateb);
- mix_column(&intermediateb[0], &intermediatea[0]);
- mix_column(&intermediateb[4], &intermediatea[4]);
- mix_column(&intermediateb[8], &intermediatea[8]);
- mix_column(&intermediateb[12], &intermediatea[12]);
- xor_128(intermediatea, round_key, ciphertext);
- next_key(round_key, round);
- }
- }
+ aes_expandkey(&ctx, key, 16);
+ aes_encrypt(&ctx, ciphertext, data);
+ memzero_explicit(&ctx, sizeof(ctx));
}
/************************************************/
@@ -1758,274 +1444,6 @@ BIP_exit:
return res;
}
-/* AES tables*/
-const u32 Te0[256] = {
- 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
- 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
- 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
- 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
- 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
- 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
- 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
- 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
- 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
- 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
- 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
- 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
- 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
- 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
- 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
- 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
- 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
- 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
- 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
- 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
- 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
- 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
- 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
- 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
- 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
- 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
- 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
- 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
- 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
- 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
- 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
- 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
- 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
- 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
- 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
- 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
- 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
- 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
- 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
- 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
- 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
- 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
- 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
- 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
- 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
- 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
- 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
- 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
- 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
- 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
- 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
- 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
- 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
- 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
- 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
- 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
- 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
- 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
- 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
- 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
- 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
- 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
- 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
- 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
-};
-
-const u32 Td0[256] = {
- 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
- 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
- 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
- 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
- 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
- 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
- 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
- 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
- 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
- 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
- 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
- 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
- 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
- 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
- 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
- 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
- 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
- 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
- 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
- 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
- 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
- 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
- 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
- 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
- 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
- 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
- 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
- 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
- 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
- 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
- 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
- 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
- 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
- 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
- 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
- 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
- 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
- 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
- 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
- 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
- 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
- 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
- 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
- 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
- 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
- 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
- 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
- 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
- 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
- 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
- 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
- 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
- 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
- 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
- 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
- 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
- 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
- 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
- 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
- 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
- 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
- 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
- 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
- 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
-};
-
-const u8 Td4s[256] = {
- 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U,
- 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU,
- 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U,
- 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
- 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU,
- 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU,
- 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U,
- 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
- 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U,
- 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U,
- 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU,
- 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
- 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU,
- 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U,
- 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U,
- 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
- 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU,
- 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U,
- 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U,
- 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
- 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U,
- 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
- 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U,
- 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
- 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U,
- 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
- 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU,
- 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
- 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U,
- 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U,
- 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U,
- 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
-};
-
-const u8 rcons[] = {
- 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
- /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
-};
-
-/**
- * Expand the cipher key into the encryption key schedule.
- *
- * @return the number of rounds for the given cipher key size.
- */
-static void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[])
-{
- int i;
- u32 temp;
-
- rk[0] = GETU32(cipherKey);
- rk[1] = GETU32(cipherKey + 4);
- rk[2] = GETU32(cipherKey + 8);
- rk[3] = GETU32(cipherKey + 12);
- for (i = 0; i < 10; i++) {
- temp = rk[3];
- rk[4] = rk[0] ^
- TE421(temp) ^ TE432(temp) ^ TE443(temp) ^ TE414(temp) ^
- RCON(i);
- rk[5] = rk[1] ^ rk[4];
- rk[6] = rk[2] ^ rk[5];
- rk[7] = rk[3] ^ rk[6];
- rk += 4;
- }
-}
-
-static void rijndaelEncrypt(u32 rk[/*44*/], u8 pt[16], u8 ct[16])
-{
- u32 s0, s1, s2, s3, t0, t1, t2, t3;
- int Nr = 10;
- int r;
-
- /*
- * map byte array block to cipher state
- * and add initial round key:
- */
- s0 = GETU32(pt) ^ rk[0];
- s1 = GETU32(pt + 4) ^ rk[1];
- s2 = GETU32(pt + 8) ^ rk[2];
- s3 = GETU32(pt + 12) ^ rk[3];
-
-#define ROUND(i, d, s) \
- do { \
- d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \
- d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \
- d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \
- d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]; \
- } while (0)
-
- /* Nr - 1 full rounds: */
- r = Nr >> 1;
- for (;;) {
- ROUND(1, t, s);
- rk += 8;
- if (--r == 0)
- break;
- ROUND(0, s, t);
- }
-
-#undef ROUND
-
- /*
- * apply last round and
- * map cipher state to byte array block:
- */
- s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0];
- PUTU32(ct, s0);
- s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1];
- PUTU32(ct + 4, s1);
- s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2];
- PUTU32(ct + 8, s2);
- s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3];
- PUTU32(ct + 12, s3);
-}
-
-static void *aes_encrypt_init(u8 *key, size_t len)
-{
- u32 *rk;
-
- if (len != 16)
- return NULL;
- rk = rtw_malloc(AES_PRIV_SIZE);
- if (rk == NULL)
- return NULL;
- rijndaelKeySetupEnc(rk, key);
- return rk;
-}
-
-static void aes_128_encrypt(void *ctx, u8 *plain, u8 *crypt)
-{
- rijndaelEncrypt(ctx, plain, crypt);
-}
-
static void gf_mulx(u8 *pad)
{
int i, carry;
@@ -2039,11 +1457,6 @@ static void gf_mulx(u8 *pad)
pad[AES_BLOCK_SIZE - 1] ^= 0x87;
}
-static void aes_encrypt_deinit(void *ctx)
-{
- kfree_sensitive(ctx);
-}
-
/**
* omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
* @key: 128-bit key for the hash operation
@@ -2058,15 +1471,16 @@ static void aes_encrypt_deinit(void *ctx)
* (SP) 800-38B.
*/
static int omac1_aes_128_vector(u8 *key, size_t num_elem,
- u8 *addr[], size_t *len, u8 *mac)
+ u8 *addr[], size_t *len, u8 *mac)
{
- void *ctx;
+ struct crypto_aes_ctx ctx;
u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
u8 *pos, *end;
size_t i, e, left, total_len;
+ int ret;
- ctx = aes_encrypt_init(key, 16);
- if (ctx == NULL)
+ ret = aes_expandkey(&ctx, key, 16);
+ if (ret)
return -1;
memset(cbc, 0, AES_BLOCK_SIZE);
@@ -2089,12 +1503,12 @@ static int omac1_aes_128_vector(u8 *key, size_t num_elem,
}
}
if (left > AES_BLOCK_SIZE)
- aes_128_encrypt(ctx, cbc, cbc);
+ aes_encrypt(&ctx, cbc, cbc);
left -= AES_BLOCK_SIZE;
}
memset(pad, 0, AES_BLOCK_SIZE);
- aes_128_encrypt(ctx, pad, pad);
+ aes_encrypt(&ctx, pad, pad);
gf_mulx(pad);
if (left || total_len == 0) {
@@ -2112,8 +1526,8 @@ static int omac1_aes_128_vector(u8 *key, size_t num_elem,
for (i = 0; i < AES_BLOCK_SIZE; i++)
pad[i] ^= cbc[i];
- aes_128_encrypt(ctx, pad, mac);
- aes_encrypt_deinit(ctx);
+ aes_encrypt(&ctx, pad, mac);
+ memzero_explicit(&ctx, sizeof(ctx));
return 0;
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c
index 85663182b388..67ca219f95bf 100644
--- a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c
+++ b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c
@@ -4,8 +4,6 @@
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-#define _RTW_STA_MGT_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
@@ -119,7 +117,6 @@ void kfree_all_stainfo(struct sta_priv *pstapriv);
void kfree_all_stainfo(struct sta_priv *pstapriv)
{
struct list_head *plist, *phead;
- struct sta_info *psta = NULL;
spin_lock_bh(&pstapriv->sta_hash_lock);
@@ -127,7 +124,6 @@ void kfree_all_stainfo(struct sta_priv *pstapriv)
plist = get_next(phead);
while (phead != plist) {
- psta = container_of(plist, struct sta_info, list);
plist = get_next(plist);
}
@@ -152,13 +148,11 @@ u32 _rtw_free_sta_priv(struct sta_priv *pstapriv)
spin_lock_bh(&pstapriv->sta_hash_lock);
for (index = 0; index < NUM_STA; index++) {
phead = &(pstapriv->sta_hash[index]);
- plist = get_next(phead);
-
- while (phead != plist) {
+ list_for_each(plist, phead) {
int i;
- psta = container_of(plist, struct sta_info, hash_list);
- plist = get_next(plist);
+ psta = list_entry(plist, struct sta_info,
+ hash_list);
for (i = 0; i < 16 ; i++) {
preorder_ctrl = &psta->recvreorder_ctrl[i];
@@ -429,7 +423,7 @@ exit:
/* free all stainfo which in sta_hash[all] */
void rtw_free_all_stainfo(struct adapter *padapter)
{
- struct list_head *plist, *phead;
+ struct list_head *plist, *phead, *tmp;
s32 index;
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
@@ -442,12 +436,8 @@ void rtw_free_all_stainfo(struct adapter *padapter)
for (index = 0; index < NUM_STA; index++) {
phead = &(pstapriv->sta_hash[index]);
- plist = get_next(phead);
-
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, hash_list);
-
- plist = get_next(plist);
+ list_for_each_safe(plist, tmp, phead) {
+ psta = list_entry(plist, struct sta_info, hash_list);
if (pbcmc_stainfo != psta)
rtw_free_stainfo(padapter, psta);
@@ -479,17 +469,14 @@ struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
spin_lock_bh(&pstapriv->sta_hash_lock);
phead = &(pstapriv->sta_hash[index]);
- plist = get_next(phead);
-
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, hash_list);
+ list_for_each(plist, phead) {
+ psta = list_entry(plist, struct sta_info, hash_list);
if ((!memcmp(psta->hwaddr, addr, ETH_ALEN)))
/* if found the matched address */
break;
psta = NULL;
- plist = get_next(plist);
}
spin_unlock_bh(&pstapriv->sta_hash_lock);
@@ -499,7 +486,6 @@ struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
u32 rtw_init_bcmc_stainfo(struct adapter *padapter)
{
struct sta_info *psta;
- u32 res = _SUCCESS;
NDIS_802_11_MAC_ADDRESS bcast_addr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
struct sta_priv *pstapriv = &padapter->stapriv;
@@ -507,15 +493,12 @@ u32 rtw_init_bcmc_stainfo(struct adapter *padapter)
psta = rtw_alloc_stainfo(pstapriv, bcast_addr);
- if (!psta) {
- res = _FAIL;
- goto exit;
- }
+ if (!psta)
+ return _FAIL;
/* default broadcast & multicast use macid 1 */
psta->mac_id = 1;
-exit:
return _SUCCESS;
}
@@ -539,10 +522,8 @@ u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr)
spin_lock_bh(&(pacl_node_q->lock));
phead = get_list_head(pacl_node_q);
- plist = get_next(phead);
- while (phead != plist) {
- paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
- plist = get_next(plist);
+ list_for_each(plist, phead) {
+ paclnode = list_entry(plist, struct rtw_wlan_acl_node, list);
if (!memcmp(paclnode->addr, mac_addr, ETH_ALEN))
if (paclnode->valid == true) {
diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
index f9bd7c167da7..c06b74f6569a 100644
--- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
+++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c
@@ -55,9 +55,6 @@ u8 networktype_to_raid_ex(struct adapter *adapter, struct sta_info *psta)
if (cur_rf_type == RF_1T1R) {
rf_type = RF_1T1R;
- } else if (IsSupportedVHT(psta->wireless_mode)) {
- if (psta->ra_mask & 0xffc00000)
- rf_type = RF_2T2R;
} else if (IsSupportedHT(psta->wireless_mode)) {
if (psta->ra_mask & 0xfff00000)
rf_type = RF_2T2R;
@@ -67,7 +64,6 @@ u8 networktype_to_raid_ex(struct adapter *adapter, struct sta_info *psta)
case WIRELESS_11B:
raid = RATEID_IDX_B;
break;
- case WIRELESS_11A:
case WIRELESS_11G:
raid = RATEID_IDX_G;
break;
@@ -75,8 +71,6 @@ u8 networktype_to_raid_ex(struct adapter *adapter, struct sta_info *psta)
raid = RATEID_IDX_BG;
break;
case WIRELESS_11_24N:
- case WIRELESS_11_5N:
- case WIRELESS_11A_5N:
case WIRELESS_11G_24N:
if (rf_type == RF_2T2R)
raid = RATEID_IDX_GN_N2SS;
@@ -342,9 +336,7 @@ u8 rtw_get_center_ch(u8 channel, u8 chnl_bw, u8 chnl_offset)
{
u8 center_ch = channel;
- if (chnl_bw == CHANNEL_WIDTH_80) {
- center_ch = 7;
- } else if (chnl_bw == CHANNEL_WIDTH_40) {
+ if (chnl_bw == CHANNEL_WIDTH_40) {
if (chnl_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
center_ch = channel + 2;
else
@@ -381,14 +373,6 @@ void set_channel_bwmode(struct adapter *padapter, unsigned char channel, unsigne
center_ch = rtw_get_center_ch(channel, bwmode, channel_offset);
- if (bwmode == CHANNEL_WIDTH_80) {
- if (center_ch > channel)
- chnl_offset80 = HAL_PRIME_CHNL_OFFSET_LOWER;
- else if (center_ch < channel)
- chnl_offset80 = HAL_PRIME_CHNL_OFFSET_UPPER;
- else
- chnl_offset80 = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
- }
/* set Channel */
if (mutex_lock_interruptible(&(adapter_to_dvobj(padapter)->setch_mutex)))
@@ -777,6 +761,32 @@ int WMM_param_handler(struct adapter *padapter, struct ndis_80211_var_ie *pIE)
return true;
}
+static void sort_wmm_ac_params(u32 *inx, u32 *edca)
+{
+ u32 i, j, change_inx = false;
+
+ /* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */
+ for (i = 0; i < 4; i++) {
+ for (j = i + 1; j < 4; j++) {
+ /* compare CW and AIFS */
+ if ((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF)) {
+ change_inx = true;
+ } else if ((edca[j] & 0xFFFF) == (edca[i] & 0xFFFF)) {
+ /* compare TXOP */
+ if ((edca[j] >> 16) > (edca[i] >> 16))
+ change_inx = true;
+ }
+
+ if (change_inx) {
+ swap(edca[i], edca[j]);
+ swap(inx[i], inx[j]);
+
+ change_inx = false;
+ }
+ }
+ }
+}
+
void WMMOnAssocRsp(struct adapter *padapter)
{
u8 ACI, ACM, AIFS, ECWMin, ECWMax, aSifsTime;
@@ -801,7 +811,7 @@ void WMMOnAssocRsp(struct adapter *padapter)
AIFS = aSifsTime + (2 * pmlmeinfo->slotTime);
- if (pmlmeext->cur_wireless_mode & (WIRELESS_11G | WIRELESS_11A)) {
+ if (pmlmeext->cur_wireless_mode & WIRELESS_11G) {
ECWMin = 4;
ECWMax = 10;
} else if (pmlmeext->cur_wireless_mode & WIRELESS_11B) {
@@ -873,35 +883,8 @@ void WMMOnAssocRsp(struct adapter *padapter)
inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3;
- if (pregpriv->wifi_spec == 1) {
- u32 j, tmp, change_inx = false;
-
- /* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */
- for (i = 0; i < 4; i++) {
- for (j = i+1; j < 4; j++) {
- /* compare CW and AIFS */
- if ((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF)) {
- change_inx = true;
- } else if ((edca[j] & 0xFFFF) == (edca[i] & 0xFFFF)) {
- /* compare TXOP */
- if ((edca[j] >> 16) > (edca[i] >> 16))
- change_inx = true;
- }
-
- if (change_inx) {
- tmp = edca[i];
- edca[i] = edca[j];
- edca[j] = tmp;
-
- tmp = inx[i];
- inx[i] = inx[j];
- inx[j] = tmp;
-
- change_inx = false;
- }
- }
- }
- }
+ if (pregpriv->wifi_spec == 1)
+ sort_wmm_ac_params(inx, edca);
for (i = 0; i < 4; i++)
pxmitpriv->wmm_para_seq[i] = inx[i];
@@ -926,9 +909,6 @@ static void bwmode_update_check(struct adapter *padapter, struct ndis_80211_var_
if (phtpriv->ht_option == false)
return;
- if (pmlmeext->cur_bwmode >= CHANNEL_WIDTH_80)
- return;
-
if (pIE->Length > sizeof(struct HT_info_element))
return;
@@ -1255,34 +1235,34 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
/* parsing HT_CAP_IE */
p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, WLAN_EID_HT_CAPABILITY, &len, bssid->IELength - _FIXED_IE_LENGTH_);
if (p && len > 0) {
- pht_cap = (struct ieee80211_ht_cap *)(p + 2);
- ht_cap_info = le16_to_cpu(pht_cap->cap_info);
+ pht_cap = (struct ieee80211_ht_cap *)(p + 2);
+ ht_cap_info = le16_to_cpu(pht_cap->cap_info);
} else {
- ht_cap_info = 0;
+ ht_cap_info = 0;
}
/* parsing HT_INFO_IE */
p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, WLAN_EID_HT_OPERATION, &len, bssid->IELength - _FIXED_IE_LENGTH_);
if (p && len > 0) {
- pht_info = (struct HT_info_element *)(p + 2);
- ht_info_infos_0 = pht_info->infos[0];
+ pht_info = (struct HT_info_element *)(p + 2);
+ ht_info_infos_0 = pht_info->infos[0];
} else {
- ht_info_infos_0 = 0;
+ ht_info_infos_0 = 0;
}
if (ht_cap_info != cur_network->BcnInfo.ht_cap_info ||
- ((ht_info_infos_0&0x03) != (cur_network->BcnInfo.ht_info_infos_0&0x03))) {
- {
- /* bcn_info_update */
- cur_network->BcnInfo.ht_cap_info = ht_cap_info;
- cur_network->BcnInfo.ht_info_infos_0 = ht_info_infos_0;
- /* to do : need to check that whether modify related register of BB or not */
- }
- /* goto _mismatch; */
+ ((ht_info_infos_0&0x03) != (cur_network->BcnInfo.ht_info_infos_0&0x03))) {
+ {
+ /* bcn_info_update */
+ cur_network->BcnInfo.ht_cap_info = ht_cap_info;
+ cur_network->BcnInfo.ht_info_infos_0 = ht_info_infos_0;
+ /* to do : need to check that whether modify related register of BB or not */
+ }
+ /* goto _mismatch; */
}
/* Checking for channel */
p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, WLAN_EID_DS_PARAMS, &len, bssid->IELength - _FIXED_IE_LENGTH_);
if (p) {
- bcn_channel = *(p + 2);
+ bcn_channel = *(p + 2);
} else {/* In 5G, some ap do not have DSSET IE checking HT info for channel */
rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, WLAN_EID_HT_OPERATION,
&len, bssid->IELength - _FIXED_IE_LENGTH_);
@@ -1293,7 +1273,7 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
}
if (bcn_channel != Adapter->mlmeextpriv.cur_channel)
- goto _mismatch;
+ goto _mismatch;
/* checking SSID */
ssid_len = 0;
@@ -1496,6 +1476,33 @@ void set_sta_rate(struct adapter *padapter, struct sta_info *psta)
Update_RA_Entry(padapter, psta);
}
+static u32 get_realtek_assoc_AP_vender(struct ndis_80211_var_ie *pIE)
+{
+ u32 Vender = HT_IOT_PEER_REALTEK;
+
+ if (pIE->Length >= 5) {
+ if (pIE->data[4] == 1)
+ /* if (pIE->data[5] & RT_HT_CAP_USE_LONG_PREAMBLE) */
+ /* bssDesc->BssHT.RT2RT_HT_Mode |= RT_HT_CAP_USE_LONG_PREAMBLE; */
+ if (pIE->data[5] & RT_HT_CAP_USE_92SE)
+ /* bssDesc->BssHT.RT2RT_HT_Mode |= RT_HT_CAP_USE_92SE; */
+ Vender = HT_IOT_PEER_REALTEK_92SE;
+
+ if (pIE->data[5] & RT_HT_CAP_USE_SOFTAP)
+ Vender = HT_IOT_PEER_REALTEK_SOFTAP;
+
+ if (pIE->data[4] == 2) {
+ if (pIE->data[6] & RT_HT_CAP_USE_JAGUAR_BCUT)
+ Vender = HT_IOT_PEER_REALTEK_JAGUAR_BCUTAP;
+
+ if (pIE->data[6] & RT_HT_CAP_USE_JAGUAR_CCUT)
+ Vender = HT_IOT_PEER_REALTEK_JAGUAR_CCUTAP;
+ }
+ }
+
+ return Vender;
+}
+
unsigned char check_assoc_AP(u8 *pframe, uint len)
{
unsigned int i;
@@ -1506,47 +1513,24 @@ unsigned char check_assoc_AP(u8 *pframe, uint len)
switch (pIE->ElementID) {
case WLAN_EID_VENDOR_SPECIFIC:
- if ((!memcmp(pIE->data, ARTHEROS_OUI1, 3)) || (!memcmp(pIE->data, ARTHEROS_OUI2, 3))) {
+ if ((!memcmp(pIE->data, ARTHEROS_OUI1, 3)) || (!memcmp(pIE->data, ARTHEROS_OUI2, 3)))
return HT_IOT_PEER_ATHEROS;
- } else if ((!memcmp(pIE->data, BROADCOM_OUI1, 3)) ||
- (!memcmp(pIE->data, BROADCOM_OUI2, 3)) ||
- (!memcmp(pIE->data, BROADCOM_OUI3, 3))) {
+ else if ((!memcmp(pIE->data, BROADCOM_OUI1, 3)) ||
+ (!memcmp(pIE->data, BROADCOM_OUI2, 3)) ||
+ (!memcmp(pIE->data, BROADCOM_OUI3, 3)))
return HT_IOT_PEER_BROADCOM;
- } else if (!memcmp(pIE->data, MARVELL_OUI, 3)) {
+ else if (!memcmp(pIE->data, MARVELL_OUI, 3))
return HT_IOT_PEER_MARVELL;
- } else if (!memcmp(pIE->data, RALINK_OUI, 3)) {
+ else if (!memcmp(pIE->data, RALINK_OUI, 3))
return HT_IOT_PEER_RALINK;
- } else if (!memcmp(pIE->data, CISCO_OUI, 3)) {
+ else if (!memcmp(pIE->data, CISCO_OUI, 3))
return HT_IOT_PEER_CISCO;
- } else if (!memcmp(pIE->data, REALTEK_OUI, 3)) {
- u32 Vender = HT_IOT_PEER_REALTEK;
-
- if (pIE->Length >= 5) {
- if (pIE->data[4] == 1)
- /* if (pIE->data[5] & RT_HT_CAP_USE_LONG_PREAMBLE) */
- /* bssDesc->BssHT.RT2RT_HT_Mode |= RT_HT_CAP_USE_LONG_PREAMBLE; */
- if (pIE->data[5] & RT_HT_CAP_USE_92SE)
- /* bssDesc->BssHT.RT2RT_HT_Mode |= RT_HT_CAP_USE_92SE; */
- Vender = HT_IOT_PEER_REALTEK_92SE;
-
- if (pIE->data[5] & RT_HT_CAP_USE_SOFTAP)
- Vender = HT_IOT_PEER_REALTEK_SOFTAP;
-
- if (pIE->data[4] == 2) {
- if (pIE->data[6] & RT_HT_CAP_USE_JAGUAR_BCUT)
- Vender = HT_IOT_PEER_REALTEK_JAGUAR_BCUTAP;
-
- if (pIE->data[6] & RT_HT_CAP_USE_JAGUAR_CCUT)
- Vender = HT_IOT_PEER_REALTEK_JAGUAR_CCUTAP;
- }
- }
-
- return Vender;
- } else if (!memcmp(pIE->data, AIRGOCAP_OUI, 3)) {
+ else if (!memcmp(pIE->data, REALTEK_OUI, 3))
+ return get_realtek_assoc_AP_vender(pIE);
+ else if (!memcmp(pIE->data, AIRGOCAP_OUI, 3))
return HT_IOT_PEER_AIRGO;
- } else {
+ else
break;
- }
default:
break;
@@ -1620,7 +1604,7 @@ void update_capinfo(struct adapter *Adapter, u16 updateCap)
pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME;
} else {
/* Filen: See 802.11-2007 p.90 */
- if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N | WIRELESS_11A | WIRELESS_11_5N | WIRELESS_11AC)) {
+ if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N)) {
pmlmeinfo->slotTime = SHORT_SLOT_TIME;
} else if (pmlmeext->cur_wireless_mode & (WIRELESS_11G)) {
if ((updateCap & cShortSlotTime) /* && (!(pMgntInfo->pHTInfo->RT2RT_HT_Mode & RT_HT_CAP_USE_LONG_PREAMBLE)) */)
@@ -1650,9 +1634,7 @@ void update_wireless_mode(struct adapter *padapter)
if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable))
pmlmeinfo->HT_enable = 1;
- if (pmlmeinfo->VHT_enable)
- network_type = WIRELESS_11AC;
- else if (pmlmeinfo->HT_enable)
+ if (pmlmeinfo->HT_enable)
network_type = WIRELESS_11_24N;
if (rtw_is_cckratesonly_included(rate))
@@ -1716,7 +1698,7 @@ int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie, uint var_ie_l
void process_addba_req(struct adapter *padapter, u8 *paddba_req, u8 *addr)
{
struct sta_info *psta;
- u16 tid, start_seq, param;
+ u16 tid, param;
struct recv_reorder_ctrl *preorder_ctrl;
struct sta_priv *pstapriv = &padapter->stapriv;
struct ADDBA_request *preq = (struct ADDBA_request *)paddba_req;
@@ -1726,8 +1708,6 @@ void process_addba_req(struct adapter *padapter, u8 *paddba_req, u8 *addr)
psta = rtw_get_stainfo(pstapriv, addr);
if (psta) {
- start_seq = le16_to_cpu(preq->BA_starting_seqctrl) >> 4;
-
param = le16_to_cpu(preq->BA_para_set);
tid = (param>>2)&0x0f;
diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c
index bd3acdd7d75f..79e4d7df1ef5 100644
--- a/drivers/staging/rtl8723bs/core/rtw_xmit.c
+++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c
@@ -4,8 +4,6 @@
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-#define _RTW_XMIT_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
@@ -323,15 +321,12 @@ void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv)
u8 query_ra_short_GI(struct sta_info *psta)
{
- u8 sgi = false, sgi_20m = false, sgi_40m = false, sgi_80m = false;
+ u8 sgi = false, sgi_20m = false, sgi_40m = false;
sgi_20m = psta->htpriv.sgi_20m;
sgi_40m = psta->htpriv.sgi_40m;
switch (psta->bw_mode) {
- case CHANNEL_WIDTH_80:
- sgi = sgi_80m;
- break;
case CHANNEL_WIDTH_40:
sgi = sgi_40m;
break;
@@ -647,7 +642,7 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
pattrib->pktlen = pktfile.pkt_len;
- if (ETH_P_IP == pattrib->ether_type) {
+ if (pattrib->ether_type == ETH_P_IP) {
/* The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time */
/* to prevent DHCP protocol fail */
@@ -657,7 +652,7 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
pattrib->dhcp_pkt = 0;
if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */
- if (ETH_P_IP == pattrib->ether_type) {/* IP header */
+ if (pattrib->ether_type == ETH_P_IP) {/* IP header */
if (((tmp[21] == 68) && (tmp[23] == 67)) ||
((tmp[21] == 67) && (tmp[23] == 68))) {
/* 68 : UDP BOOTP client */
@@ -675,7 +670,7 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
if (piphdr->protocol == 0x1) /* protocol type in ip header 0x1 is ICMP */
pattrib->icmp_pkt = 1;
}
- } else if (0x888e == pattrib->ether_type) {
+ } else if (pattrib->ether_type == 0x888e) {
netdev_dbg(padapter->pnetdev, "send eapol packet\n");
}
@@ -1725,18 +1720,14 @@ exit:
void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pframequeue)
{
- struct list_head *plist, *phead;
+ struct list_head *plist, *phead, *tmp;
struct xmit_frame *pxmitframe;
spin_lock_bh(&pframequeue->lock);
phead = get_list_head(pframequeue);
- plist = get_next(phead);
-
- while (phead != plist) {
- pxmitframe = container_of(plist, struct xmit_frame, list);
-
- plist = get_next(plist);
+ list_for_each_safe(plist, tmp, phead) {
+ pxmitframe = list_entry(plist, struct xmit_frame, list);
rtw_free_xmitframe(pxmitpriv, pxmitframe);
}
@@ -2128,7 +2119,7 @@ signed int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct x
static void dequeue_xmitframes_to_sleeping_queue(struct adapter *padapter, struct sta_info *psta, struct __queue *pframequeue)
{
signed int ret;
- struct list_head *plist, *phead;
+ struct list_head *plist, *phead, *tmp;
u8 ac_index;
struct tx_servq *ptxservq;
struct pkt_attrib *pattrib;
@@ -2136,12 +2127,8 @@ static void dequeue_xmitframes_to_sleeping_queue(struct adapter *padapter, struc
struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits;
phead = get_list_head(pframequeue);
- plist = get_next(phead);
-
- while (phead != plist) {
- pxmitframe = container_of(plist, struct xmit_frame, list);
-
- plist = get_next(plist);
+ list_for_each_safe(plist, tmp, phead) {
+ pxmitframe = list_entry(plist, struct xmit_frame, list);
pattrib = &pxmitframe->attrib;
@@ -2201,7 +2188,7 @@ void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta)
{
u8 update_mask = 0, wmmps_ac = 0;
struct sta_info *psta_bmc;
- struct list_head *xmitframe_plist, *xmitframe_phead;
+ struct list_head *xmitframe_plist, *xmitframe_phead, *tmp;
struct xmit_frame *pxmitframe = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
@@ -2211,12 +2198,9 @@ void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta)
spin_lock_bh(&pxmitpriv->lock);
xmitframe_phead = get_list_head(&psta->sleep_q);
- xmitframe_plist = get_next(xmitframe_phead);
-
- while (xmitframe_phead != xmitframe_plist) {
- pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
-
- xmitframe_plist = get_next(xmitframe_plist);
+ list_for_each_safe(xmitframe_plist, tmp, xmitframe_phead) {
+ pxmitframe = list_entry(xmitframe_plist, struct xmit_frame,
+ list);
list_del_init(&pxmitframe->list);
@@ -2285,12 +2269,9 @@ void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta)
if ((pstapriv->sta_dz_bitmap&0xfffe) == 0x0) { /* no any sta in ps mode */
xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
- xmitframe_plist = get_next(xmitframe_phead);
-
- while (xmitframe_phead != xmitframe_plist) {
- pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
-
- xmitframe_plist = get_next(xmitframe_plist);
+ list_for_each_safe(xmitframe_plist, tmp, xmitframe_phead) {
+ pxmitframe = list_entry(xmitframe_plist,
+ struct xmit_frame, list);
list_del_init(&pxmitframe->list);
@@ -2324,7 +2305,7 @@ _exit:
void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta)
{
u8 wmmps_ac = 0;
- struct list_head *xmitframe_plist, *xmitframe_phead;
+ struct list_head *xmitframe_plist, *xmitframe_phead, *tmp;
struct xmit_frame *pxmitframe = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
@@ -2332,12 +2313,9 @@ void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *pst
spin_lock_bh(&pxmitpriv->lock);
xmitframe_phead = get_list_head(&psta->sleep_q);
- xmitframe_plist = get_next(xmitframe_phead);
-
- while (xmitframe_phead != xmitframe_plist) {
- pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
-
- xmitframe_plist = get_next(xmitframe_plist);
+ list_for_each_safe(xmitframe_plist, tmp, xmitframe_phead) {
+ pxmitframe = list_entry(xmitframe_plist, struct xmit_frame,
+ list);
switch (pxmitframe->attrib.priority) {
case 1:
@@ -2524,7 +2502,7 @@ void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms)
sctx->status = RTW_SCTX_SUBMITTED;
}
-int rtw_sctx_wait(struct submit_ctx *sctx, const char *msg)
+int rtw_sctx_wait(struct submit_ctx *sctx)
{
int ret = _FAIL;
unsigned long expire;
@@ -2565,7 +2543,7 @@ int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms)
pack_tx_ops->timeout_ms = timeout_ms;
pack_tx_ops->status = RTW_SCTX_SUBMITTED;
- return rtw_sctx_wait(pack_tx_ops, __func__);
+ return rtw_sctx_wait(pack_tx_ops);
}
void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status)
diff --git a/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c b/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c
index 503790924532..dc58bb87f1b0 100644
--- a/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c
+++ b/drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c
@@ -38,110 +38,44 @@ static u8 halbtc8723b1ant_BtRssiState(
(pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) ||
(pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)
) {
- if (btRssi >= (rssiThresh + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) {
+ if (btRssi >= (rssiThresh + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT))
btRssiState = BTC_RSSI_STATE_HIGH;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_RSSI_STATE,
- ("[BTCoex], BT Rssi state switch to High\n")
- );
- } else {
+ else
btRssiState = BTC_RSSI_STATE_STAY_LOW;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_RSSI_STATE,
- ("[BTCoex], BT Rssi state stay at Low\n")
- );
- }
} else {
- if (btRssi < rssiThresh) {
+ if (btRssi < rssiThresh)
btRssiState = BTC_RSSI_STATE_LOW;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_RSSI_STATE,
- ("[BTCoex], BT Rssi state switch to Low\n")
- );
- } else {
+ else
btRssiState = BTC_RSSI_STATE_STAY_HIGH;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_RSSI_STATE,
- ("[BTCoex], BT Rssi state stay at High\n")
- );
- }
}
} else if (levelNum == 3) {
- if (rssiThresh > rssiThresh1) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_RSSI_STATE,
- ("[BTCoex], BT Rssi thresh error!!\n")
- );
+ if (rssiThresh > rssiThresh1)
return pCoexSta->preBtRssiState;
- }
if (
(pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) ||
(pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)
) {
- if (btRssi >= (rssiThresh + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) {
+ if (btRssi >= (rssiThresh + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT))
btRssiState = BTC_RSSI_STATE_MEDIUM;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_RSSI_STATE,
- ("[BTCoex], BT Rssi state switch to Medium\n")
- );
- } else {
+ else
btRssiState = BTC_RSSI_STATE_STAY_LOW;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_RSSI_STATE,
- ("[BTCoex], BT Rssi state stay at Low\n")
- );
- }
} else if (
(pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) ||
(pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM)
) {
- if (btRssi >= (rssiThresh1 + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) {
+ if (btRssi >= (rssiThresh1 + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT))
btRssiState = BTC_RSSI_STATE_HIGH;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_RSSI_STATE,
- ("[BTCoex], BT Rssi state switch to High\n")
- );
- } else if (btRssi < rssiThresh) {
+ else if (btRssi < rssiThresh)
btRssiState = BTC_RSSI_STATE_LOW;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_RSSI_STATE,
- ("[BTCoex], BT Rssi state switch to Low\n")
- );
- } else {
+ else
btRssiState = BTC_RSSI_STATE_STAY_MEDIUM;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_RSSI_STATE,
- ("[BTCoex], BT Rssi state stay at Medium\n")
- );
- }
} else {
- if (btRssi < rssiThresh1) {
+ if (btRssi < rssiThresh1)
btRssiState = BTC_RSSI_STATE_MEDIUM;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_RSSI_STATE,
- ("[BTCoex], BT Rssi state switch to Medium\n")
- );
- } else {
+ else
btRssiState = BTC_RSSI_STATE_STAY_HIGH;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_RSSI_STATE,
- ("[BTCoex], BT Rssi state stay at High\n")
- );
- }
}
}
@@ -297,7 +231,7 @@ static void halbtc8723b1ant_LimitedRx(
u8 rxAggSize = aggBufSize;
/* */
- /* Rx Aggregation related setting */
+ /* Rx Aggregation related setting */
/* */
pBtCoexist->fBtcSet(
pBtCoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, &bRejectRxAgg
@@ -316,18 +250,12 @@ static void halbtc8723b1ant_LimitedRx(
static void halbtc8723b1ant_QueryBtInfo(struct btc_coexist *pBtCoexist)
{
- u8 H2C_Parameter[1] = {0};
+ u8 H2C_Parameter[1] = {0};
pCoexSta->bC2hBtInfoReqSent = true;
H2C_Parameter[0] |= BIT0; /* trigger */
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_EXEC,
- ("[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", H2C_Parameter[0])
- );
-
pBtCoexist->fBtcFillH2c(pBtCoexist, 0x61, 1, H2C_Parameter);
}
@@ -367,18 +295,6 @@ static void halbtc8723b1ant_MonitorBtCtr(struct btc_coexist *pBtCoexist)
if ((pCoexSta->lowPriorityTx >= 1050) && (!pCoexSta->bC2hBtInquiryPage))
pCoexSta->popEventCnt++;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- (
- "[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n",
- regHPRx,
- regHPTx,
- regLPRx,
- regLPTx
- )
- );
-
/* reset counter */
pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc);
@@ -445,15 +361,15 @@ static void halbtc8723b1ant_MonitorWiFiCtr(struct btc_coexist *pBtCoexist)
)
) {
if (nCCKLockCounter < 5)
- nCCKLockCounter++;
+ nCCKLockCounter++;
} else {
if (nCCKLockCounter > 0)
- nCCKLockCounter--;
+ nCCKLockCounter--;
}
} else {
if (nCCKLockCounter > 0)
- nCCKLockCounter--;
+ nCCKLockCounter--;
}
} else {
if (nCCKLockCounter > 0)
@@ -463,14 +379,14 @@ static void halbtc8723b1ant_MonitorWiFiCtr(struct btc_coexist *pBtCoexist)
if (!pCoexSta->bPreCCKLock) {
if (nCCKLockCounter >= 5)
- pCoexSta->bCCKLock = true;
+ pCoexSta->bCCKLock = true;
else
- pCoexSta->bCCKLock = false;
+ pCoexSta->bCCKLock = false;
} else {
if (nCCKLockCounter == 0)
- pCoexSta->bCCKLock = false;
+ pCoexSta->bCCKLock = false;
else
- pCoexSta->bCCKLock = true;
+ pCoexSta->bCCKLock = true;
}
pCoexSta->bPreCCKLock = pCoexSta->bCCKLock;
@@ -586,14 +502,8 @@ static u8 halbtc8723b1ant_ActionAlgorithm(struct btc_coexist *pBtCoexist)
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn);
- if (!pBtLinkInfo->bBtLinkExist) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], No BT link exists!!!\n")
- );
+ if (!pBtLinkInfo->bBtLinkExist)
return algorithm;
- }
if (pBtLinkInfo->bScoExist)
numOfDiffProfile++;
@@ -606,151 +516,62 @@ static u8 halbtc8723b1ant_ActionAlgorithm(struct btc_coexist *pBtCoexist)
if (numOfDiffProfile == 1) {
if (pBtLinkInfo->bScoExist) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = SCO only\n")
- );
algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
} else {
if (pBtLinkInfo->bHidExist) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = HID only\n")
- );
algorithm = BT_8723B_1ANT_COEX_ALGO_HID;
} else if (pBtLinkInfo->bA2dpExist) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = A2DP only\n")
- );
algorithm = BT_8723B_1ANT_COEX_ALGO_A2DP;
} else if (pBtLinkInfo->bPanExist) {
- if (bBtHsOn) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = PAN(HS) only\n")
- );
+ if (bBtHsOn)
algorithm = BT_8723B_1ANT_COEX_ALGO_PANHS;
- } else {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = PAN(EDR) only\n")
- );
+ else
algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR;
- }
}
}
} else if (numOfDiffProfile == 2) {
if (pBtLinkInfo->bScoExist) {
if (pBtLinkInfo->bHidExist) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = SCO + HID\n")
- );
algorithm = BT_8723B_1ANT_COEX_ALGO_HID;
} else if (pBtLinkInfo->bA2dpExist) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = SCO + A2DP ==> SCO\n")
- );
algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
} else if (pBtLinkInfo->bPanExist) {
- if (bBtHsOn) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = SCO + PAN(HS)\n")
- );
+ if (bBtHsOn)
algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
- } else {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = SCO + PAN(EDR)\n")
- );
+ else
algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
- }
}
} else {
if (pBtLinkInfo->bHidExist && pBtLinkInfo->bA2dpExist) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = HID + A2DP\n")
- );
algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
} else if (pBtLinkInfo->bHidExist && pBtLinkInfo->bPanExist) {
- if (bBtHsOn) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = HID + PAN(HS)\n")
- );
+ if (bBtHsOn)
algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
- } else {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = HID + PAN(EDR)\n")
- );
+ else
algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
- }
} else if (pBtLinkInfo->bPanExist && pBtLinkInfo->bA2dpExist) {
- if (bBtHsOn) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = A2DP + PAN(HS)\n")
- );
+ if (bBtHsOn)
algorithm = BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS;
- } else {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = A2DP + PAN(EDR)\n")
- );
+ else
algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP;
- }
}
}
} else if (numOfDiffProfile == 3) {
if (pBtLinkInfo->bScoExist) {
if (pBtLinkInfo->bHidExist && pBtLinkInfo->bA2dpExist) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n")
- );
algorithm = BT_8723B_1ANT_COEX_ALGO_HID;
} else if (
pBtLinkInfo->bHidExist && pBtLinkInfo->bPanExist
) {
- if (bBtHsOn) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID + PAN(HS)\n"));
+ if (bBtHsOn)
algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
- } else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n"));
+ else
algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
- }
} else if (pBtLinkInfo->bPanExist && pBtLinkInfo->bA2dpExist) {
- if (bBtHsOn) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n"));
+ if (bBtHsOn)
algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
- } else {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n")
- );
+ else
algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
- }
}
} else {
if (
@@ -758,21 +579,10 @@ static u8 halbtc8723b1ant_ActionAlgorithm(struct btc_coexist *pBtCoexist)
pBtLinkInfo->bPanExist &&
pBtLinkInfo->bA2dpExist
) {
- if (bBtHsOn) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n")
- );
+ if (bBtHsOn)
algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
- } else {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n")
- );
+ else
algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR;
- }
}
}
} else if (numOfDiffProfile >= 3) {
@@ -782,21 +592,9 @@ static u8 halbtc8723b1ant_ActionAlgorithm(struct btc_coexist *pBtCoexist)
pBtLinkInfo->bPanExist &&
pBtLinkInfo->bA2dpExist
) {
- if (bBtHsOn) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n")
- );
-
- } else {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR) ==>PAN(EDR)+HID\n")
- );
+ if (!bBtHsOn)
algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
- }
+
}
}
}
@@ -808,7 +606,7 @@ static void halbtc8723b1ant_SetSwPenaltyTxRateAdaptive(
struct btc_coexist *pBtCoexist, bool bLowPenaltyRa
)
{
- u8 H2C_Parameter[6] = {0};
+ u8 H2C_Parameter[6] = {0};
H2C_Parameter[0] = 0x6; /* opCode, 0x6 = Retry_Penalty */
@@ -820,15 +618,6 @@ static void halbtc8723b1ant_SetSwPenaltyTxRateAdaptive(
H2C_Parameter[5] = 0xf9; /* MCS5 or OFDM36 */
}
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_EXEC,
- (
- "[BTCoex], set WiFi Low-Penalty Retry: %s",
- (bLowPenaltyRa ? "ON!!" : "OFF!!")
- )
- );
-
pBtCoexist->fBtcFillH2c(pBtCoexist, 0x69, 6, H2C_Parameter);
}
@@ -857,32 +646,12 @@ static void halbtc8723b1ant_SetCoexTable(
u8 val0x6cc
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_EXEC,
- ("[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0)
- );
pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, val0x6c0);
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_EXEC,
- ("[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4)
- );
pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, val0x6c4);
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_EXEC,
- ("[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8)
- );
pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8);
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_EXEC,
- ("[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc)
- );
pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, val0x6cc);
}
@@ -895,15 +664,6 @@ static void halbtc8723b1ant_CoexTable(
u8 val0x6cc
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW,
- (
- "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6cc = 0x%x\n",
- (bForceExec ? "force to" : ""),
- val0x6c0, val0x6c4, val0x6cc
- )
- );
pCoexDm->curVal0x6c0 = val0x6c0;
pCoexDm->curVal0x6c4 = val0x6c4;
pCoexDm->curVal0x6c8 = val0x6c8;
@@ -933,12 +693,6 @@ static void halbtc8723b1ant_CoexTableWithType(
struct btc_coexist *pBtCoexist, bool bForceExec, u8 type
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], ********** CoexTable(%d) **********\n", type)
- );
-
pCoexSta->nCoexTableType = type;
switch (type) {
@@ -996,15 +750,6 @@ static void halbtc8723b1ant_SetFwIgnoreWlanAct(
if (bEnable)
H2C_Parameter[0] |= BIT0; /* function enable */
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_EXEC,
- (
- "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n",
- H2C_Parameter[0]
- )
- );
-
pBtCoexist->fBtcFillH2c(pBtCoexist, 0x63, 1, H2C_Parameter);
}
@@ -1012,28 +757,9 @@ static void halbtc8723b1ant_IgnoreWlanAct(
struct btc_coexist *pBtCoexist, bool bForceExec, bool bEnable
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW,
- (
- "[BTCoex], %s turn Ignore WlanAct %s\n",
- (bForceExec ? "force to" : ""),
- (bEnable ? "ON" : "OFF")
- )
- );
pCoexDm->bCurIgnoreWlanAct = bEnable;
if (!bForceExec) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_DETAIL,
- (
- "[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n",
- pCoexDm->bPreIgnoreWlanAct,
- pCoexDm->bCurIgnoreWlanAct
- )
- );
-
if (pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct)
return;
}
@@ -1057,44 +783,14 @@ static void halbtc8723b1ant_LpsRpwm(
struct btc_coexist *pBtCoexist, bool bForceExec, u8 lpsVal, u8 rpwmVal
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW,
- (
- "[BTCoex], %s set lps/rpwm = 0x%x/0x%x\n",
- (bForceExec ? "force to" : ""),
- lpsVal,
- rpwmVal
- )
- );
pCoexDm->curLps = lpsVal;
pCoexDm->curRpwm = rpwmVal;
if (!bForceExec) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_DETAIL,
- (
- "[BTCoex], LPS-RxBeaconMode = 0x%x , LPS-RPWM = 0x%x!!\n",
- pCoexDm->curLps,
- pCoexDm->curRpwm
- )
- );
-
if (
(pCoexDm->preLps == pCoexDm->curLps) &&
(pCoexDm->preRpwm == pCoexDm->curRpwm)
) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_DETAIL,
- (
- "[BTCoex], LPS-RPWM_Last = 0x%x , LPS-RPWM_Now = 0x%x!!\n",
- pCoexDm->preRpwm,
- pCoexDm->curRpwm
- )
- );
-
return;
}
}
@@ -1108,12 +804,6 @@ static void halbtc8723b1ant_SwMechanism(
struct btc_coexist *pBtCoexist, bool bLowPenaltyRA
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_MONITOR,
- ("[BTCoex], SM[LpRA] = %d\n", bLowPenaltyRA)
- );
-
halbtc8723b1ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, bLowPenaltyRA);
}
@@ -1189,13 +879,10 @@ static void halbtc8723b1ant_SetAntPath(
u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x49d);
cntBtCalChk++;
- if (u1Tmp & BIT0) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ########### BT is calibrating (wait cnt =%d) ###########\n", cntBtCalChk));
+ if (u1Tmp & BIT0)
mdelay(50);
- } else {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ********** BT is NOT calibrating (wait cnt =%d)**********\n", cntBtCalChk));
+ else
break;
- }
}
/* set grant_bt to PTA */
@@ -1318,11 +1005,6 @@ static void halbtc8723b1ant_SetFwPstdma(
if (bApEnable) {
if (byte1 & BIT4 && !(byte1 & BIT5)) {
- BTC_PRINT(
- BTC_MSG_INTERFACE,
- INTF_NOTIFY,
- ("[BTCoex], FW for 1Ant AP mode\n")
- );
realByte1 &= ~BIT4;
realByte1 |= BIT5;
@@ -1343,19 +1025,6 @@ static void halbtc8723b1ant_SetFwPstdma(
pCoexDm->psTdmaPara[3] = byte4;
pCoexDm->psTdmaPara[4] = realByte5;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_EXEC,
- (
- "[BTCoex], PS-TDMA H2C cmd = 0x%x%08x\n",
- H2C_Parameter[0],
- H2C_Parameter[1] << 24 |
- H2C_Parameter[2] << 16 |
- H2C_Parameter[3] << 8 |
- H2C_Parameter[4]
- )
- );
-
pBtCoexist->fBtcFillH2c(pBtCoexist, 0x60, 5, H2C_Parameter);
}
@@ -1369,35 +1038,13 @@ static void halbtc8723b1ant_PsTdma(
u8 rssiAdjustVal = 0;
u8 psTdmaByte4Val = 0x50, psTdmaByte0Val = 0x51, psTdmaByte3Val = 0x10;
s8 nWiFiDurationAdjust = 0x0;
- /* u32 fwVer = 0; */
+ /* u32 fwVer = 0; */
- /* BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type =%d\n", */
- /* (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); */
pCoexDm->bCurPsTdmaOn = bTurnOn;
pCoexDm->curPsTdma = type;
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy);
- if (pCoexDm->bCurPsTdmaOn) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- (
- "[BTCoex], ********** TDMA(on, %d) **********\n",
- pCoexDm->curPsTdma
- )
- );
- } else {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- (
- "[BTCoex], ********** TDMA(off, %d) **********\n",
- pCoexDm->curPsTdma
- )
- );
- }
-
if (!bForceExec) {
if (
(pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) &&
@@ -1670,80 +1317,40 @@ static bool halbtc8723b1ant_IsCommonAction(struct btc_coexist *pBtCoexist)
if (
!bWifiConnected &&
- BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus
+ pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE
) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n")
- );
-
/* halbtc8723b1ant_SwMechanism(pBtCoexist, false); */
bCommon = true;
} else if (
bWifiConnected &&
- (BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus)
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE)
) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], Wifi connected + BT non connected-idle!!\n")
- );
-
/* halbtc8723b1ant_SwMechanism(pBtCoexist, false); */
bCommon = true;
} else if (
!bWifiConnected &&
- (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE)
) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], Wifi non connected-idle + BT connected-idle!!\n")
- );
-
/* halbtc8723b1ant_SwMechanism(pBtCoexist, false); */
bCommon = true;
} else if (
bWifiConnected &&
- (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE)
) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT connected-idle!!\n"));
-
/* halbtc8723b1ant_SwMechanism(pBtCoexist, false); */
bCommon = true;
} else if (
!bWifiConnected &&
- (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE != pCoexDm->btStatus)
+ (pCoexDm->btStatus != BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE)
) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], Wifi non connected-idle + BT Busy!!\n")
- );
-
/* halbtc8723b1ant_SwMechanism(pBtCoexist, false); */
bCommon = true;
} else {
- if (bWifiBusy) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], Wifi Connected-Busy + BT Busy!!\n")
- );
- } else {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], Wifi Connected-Idle + BT Busy!!\n")
- );
- }
-
bCommon = false;
}
@@ -1759,16 +1366,10 @@ static void halbtc8723b1ant_TdmaDurationAdjustForAcl(
s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */
u8 retryCount = 0, btInfoExt;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW,
- ("[BTCoex], TdmaDurationAdjustForAcl()\n")
- );
-
if (
- (BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) ||
- (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifiStatus) ||
- (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifiStatus)
+ (wifiStatus == BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN) ||
+ (wifiStatus == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN) ||
+ (wifiStatus == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT)
) {
if (
pCoexDm->curPsTdma != 1 &&
@@ -1791,11 +1392,6 @@ static void halbtc8723b1ant_TdmaDurationAdjustForAcl(
if (!pCoexDm->bAutoTdmaAdjust) {
pCoexDm->bAutoTdmaAdjust = true;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_DETAIL,
- ("[BTCoex], first run TdmaDurationAdjust()!!\n")
- );
halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 2);
pCoexDm->psTdmaDuAdjType = 2;
@@ -1810,9 +1406,6 @@ static void halbtc8723b1ant_TdmaDurationAdjustForAcl(
/* acquire the BT TRx retry count from BT_Info byte2 */
retryCount = pCoexSta->btRetryCnt;
btInfoExt = pCoexSta->btInfoExt;
- /* BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); */
- /* BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up =%d, dn =%d, m =%d, n =%d, WaitCount =%d\n", */
- /* up, dn, m, n, WaitCount)); */
if (pCoexSta->lowPriorityTx > 1050 || pCoexSta->lowPriorityRx > 1250)
retryCount++;
@@ -1833,11 +1426,6 @@ static void halbtc8723b1ant_TdmaDurationAdjustForAcl(
up = 0;
dn = 0;
result = 1;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_DETAIL,
- ("[BTCoex], Increase wifi duration!!\n")
- );
}
} else if (retryCount <= 3) { /* <=3 retry in the last 2-second duration */
up--;
@@ -1860,7 +1448,6 @@ static void halbtc8723b1ant_TdmaDurationAdjustForAcl(
dn = 0;
WaitCount = 0;
result = -1;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n"));
}
} else { /* retry count > 3, 只要1次 retry count > 3, 則調窄WiFi duration */
if (WaitCount == 1)
@@ -1876,11 +1463,6 @@ static void halbtc8723b1ant_TdmaDurationAdjustForAcl(
dn = 0;
WaitCount = 0;
result = -1;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_DETAIL,
- ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")
- );
}
if (result == -1) {
@@ -1917,15 +1499,6 @@ static void halbtc8723b1ant_TdmaDurationAdjustForAcl(
halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 1);
pCoexDm->psTdmaDuAdjType = 1;
}
- } else { /* no change */
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_DETAIL,
- (
- "[BTCoex], ********** TDMA(on, %d) **********\n",
- pCoexDm->curPsTdma
- )
- );
}
if (
@@ -2002,13 +1575,13 @@ static void halbtc8723b1ant_PowerSaveState(
/* */
/* */
-/* Software Coex Mechanism start */
+/* Software Coex Mechanism start */
/* */
/* */
/* */
/* */
-/* Non-Software Coex Mechanism start */
+/* Non-Software Coex Mechanism start */
/* */
/* */
static void halbtc8723b1ant_ActionWifiMultiPort(struct btc_coexist *pBtCoexist)
@@ -2091,6 +1664,7 @@ static void halbtc8723b1ant_ActionWifiConnectedBtAclBusy(
)
{
struct btc_bt_link_info *pBtLinkInfo = &pBtCoexist->btLinkInfo;
+
halbtc8723b1ant_BtRssiState(2, 28, 0);
if ((pCoexSta->lowPriorityRx >= 1000) && (pCoexSta->lowPriorityRx != 65535))
@@ -2103,7 +1677,7 @@ static void halbtc8723b1ant_ActionWifiConnectedBtAclBusy(
pCoexDm->bAutoTdmaAdjust = false;
return;
} else if (pBtLinkInfo->bA2dpOnly) { /* A2DP */
- if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifiStatus) {
+ if (wifiStatus == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE) {
halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 32);
halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4);
pCoexDm->bAutoTdmaAdjust = false;
@@ -2158,7 +1732,7 @@ static void halbtc8723b1ant_ActionWifiNotConnectedScan(
halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0);
/* tdma and coex table */
- if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) {
+ if (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) {
if (pBtLinkInfo->bA2dpExist) {
halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 32);
halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4);
@@ -2170,8 +1744,8 @@ static void halbtc8723b1ant_ActionWifiNotConnectedScan(
halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4);
}
} else if (
- (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) ||
- (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus)
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_SCO_BUSY) ||
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY)
) {
halbtc8723b1ant_ActionBtScoHidOnlyBusy(
pBtCoexist, BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN
@@ -2215,7 +1789,7 @@ static void halbtc8723b1ant_ActionWifiConnectedScan(struct btc_coexist *pBtCoexi
halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0);
/* tdma and coex table */
- if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) {
+ if (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) {
if (pBtLinkInfo->bA2dpExist) {
halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 32);
halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4);
@@ -2227,8 +1801,8 @@ static void halbtc8723b1ant_ActionWifiConnectedScan(struct btc_coexist *pBtCoexi
halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4);
}
} else if (
- (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) ||
- (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus)
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_SCO_BUSY) ||
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY)
) {
halbtc8723b1ant_ActionBtScoHidOnlyBusy(
pBtCoexist, BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN
@@ -2271,20 +1845,9 @@ static void halbtc8723b1ant_ActionWifiConnected(struct btc_coexist *pBtCoexist)
bool bScan = false, bLink = false, bRoam = false;
bool bUnder4way = false, bApEnable = false;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], CoexForWifiConnect() ===>\n")
- );
-
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way);
if (bUnder4way) {
halbtc8723b1ant_ActionWifiConnectedSpecialPacket(pBtCoexist);
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n")
- );
return;
}
@@ -2296,11 +1859,6 @@ static void halbtc8723b1ant_ActionWifiConnected(struct btc_coexist *pBtCoexist)
halbtc8723b1ant_ActionWifiConnectedScan(pBtCoexist);
else
halbtc8723b1ant_ActionWifiConnectedSpecialPacket(pBtCoexist);
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n")
- );
return;
}
@@ -2310,7 +1868,7 @@ static void halbtc8723b1ant_ActionWifiConnected(struct btc_coexist *pBtCoexist)
/* power save state */
if (
!bApEnable &&
- BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus &&
+ pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_BUSY &&
!pBtCoexist->btLinkInfo.bHidOnly
) {
if (pBtCoexist->btLinkInfo.bA2dpOnly) { /* A2DP */
@@ -2341,14 +1899,14 @@ static void halbtc8723b1ant_ActionWifiConnected(struct btc_coexist *pBtCoexist)
/* tdma and coex table */
if (!bWifiBusy) {
- if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) {
+ if (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) {
halbtc8723b1ant_ActionWifiConnectedBtAclBusy(
pBtCoexist,
BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE
);
} else if (
- (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) ||
- (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus)
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_SCO_BUSY) ||
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY)
) {
halbtc8723b1ant_ActionBtScoHidOnlyBusy(pBtCoexist,
BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE);
@@ -2361,14 +1919,14 @@ static void halbtc8723b1ant_ActionWifiConnected(struct btc_coexist *pBtCoexist)
halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7);
}
} else {
- if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) {
+ if (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) {
halbtc8723b1ant_ActionWifiConnectedBtAclBusy(
pBtCoexist,
BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY
);
} else if (
- (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) ||
- (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus)
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_SCO_BUSY) ||
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY)
) {
halbtc8723b1ant_ActionBtScoHidOnlyBusy(
pBtCoexist,
@@ -2397,47 +1955,36 @@ static void halbtc8723b1ant_RunSwCoexistMechanism(struct btc_coexist *pBtCoexist
} else {
switch (pCoexDm->curAlgorithm) {
case BT_8723B_1ANT_COEX_ALGO_SCO:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = SCO.\n"));
/* halbtc8723b1ant_ActionSco(pBtCoexist); */
break;
case BT_8723B_1ANT_COEX_ALGO_HID:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID.\n"));
/* halbtc8723b1ant_ActionHid(pBtCoexist); */
break;
case BT_8723B_1ANT_COEX_ALGO_A2DP:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP.\n"));
/* halbtc8723b1ant_ActionA2dp(pBtCoexist); */
break;
case BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP+PAN(HS).\n"));
/* halbtc8723b1ant_ActionA2dpPanHs(pBtCoexist); */
break;
case BT_8723B_1ANT_COEX_ALGO_PANEDR:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR).\n"));
/* halbtc8723b1ant_ActionPanEdr(pBtCoexist); */
break;
case BT_8723B_1ANT_COEX_ALGO_PANHS:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HS mode.\n"));
/* halbtc8723b1ant_ActionPanHs(pBtCoexist); */
break;
case BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN+A2DP.\n"));
/* halbtc8723b1ant_ActionPanEdrA2dp(pBtCoexist); */
break;
case BT_8723B_1ANT_COEX_ALGO_PANEDR_HID:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR)+HID.\n"));
/* halbtc8723b1ant_ActionPanEdrHid(pBtCoexist); */
break;
case BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP+PAN.\n"));
/* halbtc8723b1ant_ActionHidA2dpPanEdr(pBtCoexist); */
break;
case BT_8723B_1ANT_COEX_ALGO_HID_A2DP:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP.\n"));
/* halbtc8723b1ant_ActionHidA2dp(pBtCoexist); */
break;
default:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = coexist All Off!!\n"));
break;
}
pCoexDm->preAlgorithm = pCoexDm->curAlgorithm;
@@ -2454,27 +2001,19 @@ static void halbtc8723b1ant_RunCoexistMechanism(struct btc_coexist *pBtCoexist)
u32 wifiLinkStatus = 0;
u32 numOfWifiLink = 0;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism() ===>\n"));
-
- if (pBtCoexist->bManualControl) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"));
+ if (pBtCoexist->bManualControl)
return;
- }
- if (pBtCoexist->bStopCoexDm) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"));
+ if (pBtCoexist->bStopCoexDm)
return;
- }
- if (pCoexSta->bUnderIps) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is under IPS !!!\n"));
+ if (pCoexSta->bUnderIps)
return;
- }
if (
- (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) ||
- (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) ||
- (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus)
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) ||
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_SCO_BUSY) ||
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY)
){
bIncreaseScanDevNum = true;
}
@@ -2498,26 +2037,12 @@ static void halbtc8723b1ant_RunCoexistMechanism(struct btc_coexist *pBtCoexist)
numOfWifiLink = wifiLinkStatus >> 16;
if ((numOfWifiLink >= 2) || (wifiLinkStatus & WIFI_P2P_GO_CONNECTED)) {
- BTC_PRINT(
- BTC_MSG_INTERFACE,
- INTF_NOTIFY,
- (
- "############# [BTCoex], Multi-Port numOfWifiLink = %d, wifiLinkStatus = 0x%x\n",
- numOfWifiLink,
- wifiLinkStatus
- )
- );
halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0);
halbtc8723b1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, bBtCtrlAggBufSize, aggBufSize);
- if ((pBtLinkInfo->bA2dpExist) && (pCoexSta->bC2hBtInquiryPage)) {
- BTC_PRINT(
- BTC_MSG_INTERFACE,
- INTF_NOTIFY,
- ("############# [BTCoex], BT Is Inquirying\n")
- );
+ if ((pBtLinkInfo->bA2dpExist) && (pCoexSta->bC2hBtInquiryPage))
halbtc8723b1ant_ActionBtInquiry(pBtCoexist);
- } else
+ else
halbtc8723b1ant_ActionWifiMultiPort(pBtCoexist);
return;
@@ -2544,11 +2069,6 @@ static void halbtc8723b1ant_RunCoexistMechanism(struct btc_coexist *pBtCoexist)
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn);
if (pCoexSta->bC2hBtInquiryPage) {
- BTC_PRINT(
- BTC_MSG_INTERFACE,
- INTF_NOTIFY,
- ("############# [BTCoex], BT Is Inquirying\n")
- );
halbtc8723b1ant_ActionBtInquiry(pBtCoexist);
return;
} else if (bBtHsOn) {
@@ -2560,16 +2080,14 @@ static void halbtc8723b1ant_RunCoexistMechanism(struct btc_coexist *pBtCoexist)
if (!bWifiConnected) {
bool bScan = false, bLink = false, bRoam = false;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is non connected-idle !!!\n"));
-
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan);
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink);
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam);
if (bScan || bLink || bRoam) {
- if (bScan)
+ if (bScan)
halbtc8723b1ant_ActionWifiNotConnectedScan(pBtCoexist);
- else
+ else
halbtc8723b1ant_ActionWifiNotConnectedAssoAuth(pBtCoexist);
} else
halbtc8723b1ant_ActionWifiNotConnected(pBtCoexist);
@@ -2596,15 +2114,6 @@ static void halbtc8723b1ant_InitHwConfig(
bool bWifiOnly
)
{
- u32 u4Tmp = 0;/* fwVer; */
- u8 u1Tmpa = 0, u1Tmpb = 0;
-
- BTC_PRINT(
- BTC_MSG_INTERFACE,
- INTF_INIT,
- ("[BTCoex], 1Ant Init HW Config!!\n")
- );
-
pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x550, 0x8, 0x1); /* enable TBTT nterrupt */
/* 0x790[5:0]= 0x5 */
@@ -2624,20 +2133,9 @@ static void halbtc8723b1ant_InitHwConfig(
/* PTA parameter */
halbtc8723b1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0);
- u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x948);
- u1Tmpa = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x765);
- u1Tmpb = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x67);
-
- BTC_PRINT(
- BTC_MSG_INTERFACE,
- INTF_NOTIFY,
- (
- "############# [BTCoex], 0x948 = 0x%x, 0x765 = 0x%x, 0x67 = 0x%x\n",
- u4Tmp,
- u1Tmpa,
- u1Tmpb
- )
- );
+ pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x948);
+ pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x765);
+ pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x67);
}
/* */
@@ -2666,9 +2164,9 @@ void EXhalbtc8723b1ant_PowerOnSetting(struct btc_coexist *pBtCoexist)
/* */
/* S0 or S1 setting and Local register setting(By the setting fw can get ant number, S0/S1, ... info) */
/* Local setting bit define */
- /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */
- /* BIT1: "0" for internal switch; "1" for external switch */
- /* BIT2: "0" for one antenna; "1" for two antenna */
+ /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */
+ /* BIT1: "0" for internal switch; "1" for external switch */
+ /* BIT2: "0" for one antenna; "1" for two antenna */
/* NOTE: here default all internal switch and 1-antenna ==> BIT1 = 0 and BIT2 = 0 */
if (pBtCoexist->chipInterface == BTC_INTF_USB) {
/* fixed at S0 for USB interface */
@@ -2705,12 +2203,6 @@ void EXhalbtc8723b1ant_InitHwConfig(struct btc_coexist *pBtCoexist, bool bWifiOn
void EXhalbtc8723b1ant_InitCoexDm(struct btc_coexist *pBtCoexist)
{
- BTC_PRINT(
- BTC_MSG_INTERFACE,
- INTF_INIT,
- ("[BTCoex], Coex Mechanism Init!!\n")
- );
-
pBtCoexist->bStopCoexDm = false;
halbtc8723b1ant_InitCoexDm(pBtCoexist);
@@ -2730,7 +2222,6 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
bool bRoam = false;
bool bScan = false;
bool bLink = false;
- bool bWifiUnder5G = false;
bool bWifiUnderBMode = false;
bool bBtHsOn = false;
bool bWifiBusy = false;
@@ -2778,7 +2269,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %d/ %d/ %d", "Ant PG Num/ Ant Mech/ Ant Pos:", \
+ "\r\n %-35s = %d/ %d/ %d", "Ant PG Num/ Ant Mech/ Ant Pos:",
pBoardInfo->pgAntNum,
pBoardInfo->btdmAntNum,
pBoardInfo->btdmAntPos
@@ -2788,7 +2279,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \
+ "\r\n %-35s = %s / %d", "BT stack/ hci ext ver",
((pStackInfo->bProfileNotified) ? "Yes" : "No"),
pStackInfo->hciVersion
);
@@ -2799,7 +2290,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", \
+ "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer",
GLCoexVerDate8723b1Ant,
GLCoexVer8723b1Ant,
fwVer,
@@ -2814,7 +2305,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \
+ "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)",
wifiDot11Chnl,
wifiHsChnl,
bBtHsOn
@@ -2824,7 +2315,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \
+ "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info",
pCoexDm->wifiChnlInfo[0],
pCoexDm->wifiChnlInfo[1],
pCoexDm->wifiChnlInfo[2]
@@ -2836,7 +2327,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \
+ "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi",
wifiRssi - 100, btHsRssi - 100
);
CL_PRINTF(cliBuf);
@@ -2847,12 +2338,11 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %d/ %d/ %d/ %s", "Wifi bLink/ bRoam/ bScan/ bHi-Pri", \
+ "\r\n %-35s = %d/ %d/ %d/ %s", "Wifi bLink/ bRoam/ bScan/ bHi-Pri",
bLink, bRoam, bScan, ((pCoexSta->bWiFiIsHighPriTask) ? "1" : "0")
);
CL_PRINTF(cliBuf);
- pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G);
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw);
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy);
pBtCoexist->fBtcGet(
@@ -2865,10 +2355,10 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %s / %s/ %s/ AP =%d/ %s ", "Wifi status", \
- (bWifiUnder5G ? "5G" : "2.4G"),
- ((bWifiUnderBMode) ? "11b" : ((BTC_WIFI_BW_LEGACY == wifiBw) ? "11bg" : (((BTC_WIFI_BW_HT40 == wifiBw) ? "HT40" : "HT20")))),
- ((!bWifiBusy) ? "idle" : ((BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) ? "uplink" : "downlink")),
+ "\r\n %-35s = %s / %s/ %s/ AP =%d/ %s ", "Wifi status",
+ ("2.4G"),
+ ((bWifiUnderBMode) ? "11b" : ((wifiBw == BTC_WIFI_BW_LEGACY) ? "11bg" : (((wifiBw == BTC_WIFI_BW_HT40) ? "HT40" : "HT20")))),
+ ((!bWifiBusy) ? "idle" : ((wifiTrafficDir == BTC_WIFI_TRAFFIC_TX) ? "uplink" : "downlink")),
pCoexSta->nScanAPNum,
(pCoexSta->bCCKLock) ? "Lock" : "noLock"
);
@@ -2880,7 +2370,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %d/ %d/ %d/ %d/ %d", "sta/vwifi/hs/p2pGo/p2pGc", \
+ "\r\n %-35s = %d/ %d/ %d/ %d/ %d", "sta/vwifi/hs/p2pGo/p2pGc",
((wifiLinkStatus & WIFI_STA_CONNECTED) ? 1 : 0),
((wifiLinkStatus & WIFI_AP_CONNECTED) ? 1 : 0),
((wifiLinkStatus & WIFI_HS_CONNECTED) ? 1 : 0),
@@ -2894,9 +2384,9 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = [%s/ %d/ %d/ %d] ", "BT [status/ rssi/ retryCnt/ popCnt]", \
- ((pBtCoexist->btInfo.bBtDisabled) ? ("disabled") : ((pCoexSta->bC2hBtInquiryPage) ? ("inquiry/page scan") : ((BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) ? "non-connected idle" :
- ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ? "connected-idle" : "busy")))),
+ "\r\n %-35s = [%s/ %d/ %d/ %d] ", "BT [status/ rssi/ retryCnt/ popCnt]",
+ ((pBtCoexist->btInfo.bBtDisabled) ? ("disabled") : ((pCoexSta->bC2hBtInquiryPage) ? ("inquiry/page scan") : ((pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE) ? "non-connected idle" :
+ ((pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE) ? "connected-idle" : "busy")))),
pCoexSta->btRssi, pCoexSta->btRetryCnt, pCoexSta->popEventCnt
);
CL_PRINTF(cliBuf);
@@ -2910,7 +2400,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \
+ "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP",
pBtLinkInfo->bScoExist,
pBtLinkInfo->bHidExist,
pBtLinkInfo->bPanExist,
@@ -2921,8 +2411,8 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
if (pStackInfo->bProfileNotified) {
pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO);
} else {
- CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Role", \
- (pBtLinkInfo->bSlaveRole) ? "Slave" : "Master");
+ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Role",
+ (pBtLinkInfo->bSlaveRole) ? "Slave" : "Master");
CL_PRINTF(cliBuf);
}
@@ -2931,7 +2421,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %s", "BT Info A2DP rate", \
+ "\r\n %-35s = %s", "BT Info A2DP rate",
(btInfoExt & BIT0) ? "Basic rate" : "EDR rate"
);
CL_PRINTF(cliBuf);
@@ -2941,7 +2431,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8723b1Ant[i], \
+ "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8723b1Ant[i],
pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1],
pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3],
pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5],
@@ -2953,7 +2443,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %s/%s, (0x%x/0x%x)", "PS state, IPS/LPS, (lps/rpwm)", \
+ "\r\n %-35s = %s/%s, (0x%x/0x%x)", "PS state, IPS/LPS, (lps/rpwm)",
(pCoexSta->bUnderIps ? "IPS ON" : "IPS OFF"),
(pCoexSta->bUnderLps ? "LPS ON" : "LPS OFF"),
pBtCoexist->btInfo.lpsVal,
@@ -2974,7 +2464,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %d", "SM[LowPenaltyRA]", \
+ "\r\n %-35s = %d", "SM[LowPenaltyRA]",
pCoexDm->bCurLowPenaltyRa
);
CL_PRINTF(cliBuf);
@@ -2982,7 +2472,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %s/ %s/ %d ", "DelBA/ BtCtrlAgg/ AggSize", \
+ "\r\n %-35s = %s/ %s/ %d ", "DelBA/ BtCtrlAgg/ AggSize",
(pBtCoexist->btInfo.bRejectAggPkt ? "Yes" : "No"),
(pBtCoexist->btInfo.bBtCtrlAggBufSize ? "Yes" : "No"),
pBtCoexist->btInfo.aggBufSize
@@ -2991,7 +2481,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = 0x%x ", "Rate Mask", \
+ "\r\n %-35s = 0x%x ", "Rate Mask",
pBtCoexist->btInfo.raMask
);
CL_PRINTF(cliBuf);
@@ -3001,41 +2491,35 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_PRINTF(cliBuf);
psTdmaCase = pCoexDm->curPsTdma;
- CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", "PS TDMA", \
- pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1],
- pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3],
- pCoexDm->psTdmaPara[4], psTdmaCase, pCoexDm->bAutoTdmaAdjust);
- CL_PRINTF(cliBuf);
-
- CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "Coex Table Type", \
- pCoexSta->nCoexTableType);
+ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", "PS TDMA",
+ pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1],
+ pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3],
+ pCoexDm->psTdmaPara[4], psTdmaCase, pCoexDm->bAutoTdmaAdjust);
CL_PRINTF(cliBuf);
- CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "IgnWlanAct", \
- pCoexDm->bCurIgnoreWlanAct);
+ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "Coex Table Type",
+ pCoexSta->nCoexTableType);
CL_PRINTF(cliBuf);
- /*
- CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Latest error condition(should be 0)", \
- pCoexDm->errorCondition);
+ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "IgnWlanAct",
+ pCoexDm->bCurIgnoreWlanAct);
CL_PRINTF(cliBuf);
- */
}
/* Hw setting */
CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============");
CL_PRINTF(cliBuf);
- CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "backup ARFR1/ARFR2/RL/AMaxTime", \
- pCoexDm->backupArfrCnt1, pCoexDm->backupArfrCnt2, pCoexDm->backupRetryLimit, pCoexDm->backupAmpduMaxTime);
+ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "backup ARFR1/ARFR2/RL/AMaxTime",
+ pCoexDm->backupArfrCnt1, pCoexDm->backupArfrCnt2, pCoexDm->backupRetryLimit, pCoexDm->backupAmpduMaxTime);
CL_PRINTF(cliBuf);
u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x430);
u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x434);
u2Tmp[0] = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x42a);
u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x456);
- CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "0x430/0x434/0x42a/0x456", \
- u4Tmp[0], u4Tmp[1], u2Tmp[0], u1Tmp[0]);
+ CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "0x430/0x434/0x42a/0x456",
+ u4Tmp[0], u4Tmp[1], u2Tmp[0], u1Tmp[0]);
CL_PRINTF(cliBuf);
u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x778);
@@ -3043,7 +2527,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x880);
CL_SPRINTF(
cliBuf, BT_TMP_BUF_SIZE,
- "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x778/0x6cc/0x880[29:25]", \
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x778/0x6cc/0x880[29:25]",
u1Tmp[0], u4Tmp[0], (u4Tmp[1] & 0x3e000000) >> 25
);
CL_PRINTF(cliBuf);
@@ -3055,7 +2539,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x948/ 0x67[5] / 0x764 / 0x76e", \
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x948/ 0x67[5] / 0x764 / 0x76e",
u4Tmp[0], ((u1Tmp[0] & 0x20) >> 5), (u4Tmp[1] & 0xffff), u1Tmp[1]
);
CL_PRINTF(cliBuf);
@@ -3066,7 +2550,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", \
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]",
u4Tmp[0] & 0x3, u4Tmp[1] & 0xff, u4Tmp[2] & 0x3
);
CL_PRINTF(cliBuf);
@@ -3078,7 +2562,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x38[11]/0x40/0x4c[24:23]/0x64[0]", \
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x38[11]/0x40/0x4c[24:23]/0x64[0]",
((u1Tmp[0] & 0x8) >> 3),
u1Tmp[1],
((u4Tmp[0] & 0x01800000) >> 23),
@@ -3091,7 +2575,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \
+ "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522",
u4Tmp[0], u1Tmp[0]
);
CL_PRINTF(cliBuf);
@@ -3101,7 +2585,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = 0x%x/ 0x%x", "0xc50(dig)/0x49c(null-drop)", \
+ "\r\n %-35s = 0x%x/ 0x%x", "0xc50(dig)/0x49c(null-drop)",
u4Tmp[0] & 0xff, u1Tmp[0]
);
CL_PRINTF(cliBuf);
@@ -3117,14 +2601,14 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
faOfdm =
((u4Tmp[0] & 0xffff0000) >> 16) +
((u4Tmp[1] & 0xffff0000) >> 16) +
- (u4Tmp[1] & 0xffff) + (u4Tmp[2] & 0xffff) + \
+ (u4Tmp[1] & 0xffff) + (u4Tmp[2] & 0xffff) +
((u4Tmp[3] & 0xffff0000) >> 16) + (u4Tmp[3] & 0xffff);
faCck = (u1Tmp[0] << 8) + u1Tmp[1];
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "OFDM-CCA/OFDM-FA/CCK-FA", \
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "OFDM-CCA/OFDM-FA/CCK-FA",
u4Tmp[0] & 0xffff, faOfdm, faCck
);
CL_PRINTF(cliBuf);
@@ -3133,7 +2617,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %d/ %d/ %d/ %d", "CRC_OK CCK/11g/11n/11n-Agg", \
+ "\r\n %-35s = %d/ %d/ %d/ %d", "CRC_OK CCK/11g/11n/11n-Agg",
pCoexSta->nCRCOK_CCK,
pCoexSta->nCRCOK_11g,
pCoexSta->nCRCOK_11n,
@@ -3144,7 +2628,7 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %d/ %d/ %d/ %d", "CRC_Err CCK/11g/11n/11n-Agg", \
+ "\r\n %-35s = %d/ %d/ %d/ %d", "CRC_Err CCK/11g/11n/11n-Agg",
pCoexSta->nCRCErr_CCK,
pCoexSta->nCRCErr_11g,
pCoexSta->nCRCErr_11n,
@@ -3158,21 +2642,21 @@ void EXhalbtc8723b1ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8(coexTable)", \
+ "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8(coexTable)",
u4Tmp[0], u4Tmp[1], u4Tmp[2]);
CL_PRINTF(cliBuf);
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)", \
+ "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)",
pCoexSta->highPriorityRx, pCoexSta->highPriorityTx
);
CL_PRINTF(cliBuf);
CL_SPRINTF(
cliBuf,
BT_TMP_BUF_SIZE,
- "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", \
+ "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)",
pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx
);
CL_PRINTF(cliBuf);
@@ -3186,19 +2670,13 @@ void EXhalbtc8723b1ant_IpsNotify(struct btc_coexist *pBtCoexist, u8 type)
if (pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm)
return;
- if (BTC_IPS_ENTER == type) {
- BTC_PRINT(
- BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")
- );
+ if (type == BTC_IPS_ENTER) {
pCoexSta->bUnderIps = true;
halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 0);
halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0);
halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, false, true);
- } else if (BTC_IPS_LEAVE == type) {
- BTC_PRINT(
- BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")
- );
+ } else if (type == BTC_IPS_LEAVE) {
pCoexSta->bUnderIps = false;
halbtc8723b1ant_InitHwConfig(pBtCoexist, false, false);
@@ -3212,17 +2690,10 @@ void EXhalbtc8723b1ant_LpsNotify(struct btc_coexist *pBtCoexist, u8 type)
if (pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm)
return;
- if (BTC_LPS_ENABLE == type) {
- BTC_PRINT(
- BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")
- );
+ if (type == BTC_LPS_ENABLE)
pCoexSta->bUnderLps = true;
- } else if (BTC_LPS_DISABLE == type) {
- BTC_PRINT(
- BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")
- );
+ else if (type == BTC_LPS_DISABLE)
pCoexSta->bUnderLps = false;
- }
}
void EXhalbtc8723b1ant_ScanNotify(struct btc_coexist *pBtCoexist, u8 type)
@@ -3233,39 +2704,18 @@ void EXhalbtc8723b1ant_ScanNotify(struct btc_coexist *pBtCoexist, u8 type)
bool bBtCtrlAggBufSize = false;
u8 aggBufSize = 5;
- u8 u1Tmpa, u1Tmpb;
- u32 u4Tmp;
-
if (pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm)
return;
- if (BTC_SCAN_START == type) {
+ if (type == BTC_SCAN_START) {
pCoexSta->bWiFiIsHighPriTask = true;
- BTC_PRINT(
- BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")
- );
halbtc8723b1ant_PsTdma(pBtCoexist, FORCE_EXEC, false, 8); /* Force antenna setup for no scan result issue */
- u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x948);
- u1Tmpa = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x765);
- u1Tmpb = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x67);
-
-
- BTC_PRINT(
- BTC_MSG_INTERFACE,
- INTF_NOTIFY,
- (
- "[BTCoex], 0x948 = 0x%x, 0x765 = 0x%x, 0x67 = 0x%x\n",
- u4Tmp,
- u1Tmpa,
- u1Tmpb
- )
- );
+ pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x948);
+ pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x765);
+ pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x67);
} else {
pCoexSta->bWiFiIsHighPriTask = false;
- BTC_PRINT(
- BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")
- );
pBtCoexist->fBtcGet(
pBtCoexist, BTC_GET_U1_AP_NUM, &pCoexSta->nScanAPNum
@@ -3300,14 +2750,12 @@ void EXhalbtc8723b1ant_ScanNotify(struct btc_coexist *pBtCoexist, u8 type)
return;
}
- if (BTC_SCAN_START == type) {
- /* BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); */
+ if (type == BTC_SCAN_START) {
if (!bWifiConnected) /* non-connected scan */
halbtc8723b1ant_ActionWifiNotConnectedScan(pBtCoexist);
else /* wifi is connected */
halbtc8723b1ant_ActionWifiConnectedScan(pBtCoexist);
- } else if (BTC_SCAN_FINISH == type) {
- /* BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); */
+ } else if (type == BTC_SCAN_FINISH) {
if (!bWifiConnected) /* non-connected scan */
halbtc8723b1ant_ActionWifiNotConnected(pBtCoexist);
else
@@ -3330,13 +2778,11 @@ void EXhalbtc8723b1ant_ConnectNotify(struct btc_coexist *pBtCoexist, u8 type)
)
return;
- if (BTC_ASSOCIATE_START == type) {
+ if (type == BTC_ASSOCIATE_START) {
pCoexSta->bWiFiIsHighPriTask = true;
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n"));
pCoexDm->nArpCnt = 0;
} else {
pCoexSta->bWiFiIsHighPriTask = false;
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n"));
/* pCoexDm->nArpCnt = 0; */
}
@@ -3358,12 +2804,9 @@ void EXhalbtc8723b1ant_ConnectNotify(struct btc_coexist *pBtCoexist, u8 type)
return;
}
- if (BTC_ASSOCIATE_START == type) {
- /* BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); */
+ if (type == BTC_ASSOCIATE_START) {
halbtc8723b1ant_ActionWifiNotConnectedAssoAuth(pBtCoexist);
- } else if (BTC_ASSOCIATE_FINISH == type) {
- /* BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); */
-
+ } else if (type == BTC_ASSOCIATE_FINISH) {
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected);
if (!bWifiConnected) /* non-connected scan */
halbtc8723b1ant_ActionWifiNotConnected(pBtCoexist);
@@ -3386,9 +2829,7 @@ void EXhalbtc8723b1ant_MediaStatusNotify(struct btc_coexist *pBtCoexist, u8 type
)
return;
- if (BTC_MEDIA_CONNECT == type) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n"));
-
+ if (type == BTC_MEDIA_CONNECT) {
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, &bWifiUnderBMode);
/* Set CCK Tx/Rx high Pri except 11b mode */
@@ -3405,7 +2846,6 @@ void EXhalbtc8723b1ant_MediaStatusNotify(struct btc_coexist *pBtCoexist, u8 type
pCoexDm->backupRetryLimit = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x42a);
pCoexDm->backupAmpduMaxTime = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x456);
} else {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n"));
pCoexDm->nArpCnt = 0;
pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cd, 0x0); /* CCK Tx */
@@ -3414,13 +2854,13 @@ void EXhalbtc8723b1ant_MediaStatusNotify(struct btc_coexist *pBtCoexist, u8 type
/* only 2.4G we need to inform bt the chnl mask */
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl);
- if ((BTC_MEDIA_CONNECT == type) && (wifiCentralChnl <= 14)) {
+ if ((type == BTC_MEDIA_CONNECT) && (wifiCentralChnl <= 14)) {
/* H2C_Parameter[0] = 0x1; */
H2C_Parameter[0] = 0x0;
H2C_Parameter[1] = wifiCentralChnl;
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw);
- if (BTC_WIFI_BW_HT40 == wifiBw)
+ if (wifiBw == BTC_WIFI_BW_HT40)
H2C_Parameter[2] = 0x30;
else
H2C_Parameter[2] = 0x20;
@@ -3430,15 +2870,6 @@ void EXhalbtc8723b1ant_MediaStatusNotify(struct btc_coexist *pBtCoexist, u8 type
pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1];
pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2];
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_EXEC,
- (
- "[BTCoex], FW write 0x66 = 0x%x\n",
- H2C_Parameter[0] << 16 | H2C_Parameter[1] << 8 | H2C_Parameter[2]
- )
- );
-
pBtCoexist->fBtcFillH2c(pBtCoexist, 0x66, 3, H2C_Parameter);
}
@@ -3458,23 +2889,12 @@ void EXhalbtc8723b1ant_SpecialPacketNotify(struct btc_coexist *pBtCoexist, u8 ty
return;
if (
- BTC_PACKET_DHCP == type ||
- BTC_PACKET_EAPOL == type ||
- BTC_PACKET_ARP == type
+ type == BTC_PACKET_DHCP ||
+ type == BTC_PACKET_EAPOL ||
+ type == BTC_PACKET_ARP
) {
- if (BTC_PACKET_ARP == type) {
- BTC_PRINT(
- BTC_MSG_INTERFACE,
- INTF_NOTIFY,
- ("[BTCoex], special Packet ARP notify\n")
- );
-
+ if (type == BTC_PACKET_ARP) {
pCoexDm->nArpCnt++;
- BTC_PRINT(
- BTC_MSG_INTERFACE,
- INTF_NOTIFY,
- ("[BTCoex], ARP Packet Count = %d\n", pCoexDm->nArpCnt)
- );
if (pCoexDm->nArpCnt >= 10) /* if APR PKT > 10 after connect, do not go to ActionWifiConnectedSpecialPacket(pBtCoexist) */
pCoexSta->bWiFiIsHighPriTask = false;
@@ -3482,19 +2902,9 @@ void EXhalbtc8723b1ant_SpecialPacketNotify(struct btc_coexist *pBtCoexist, u8 ty
pCoexSta->bWiFiIsHighPriTask = true;
} else {
pCoexSta->bWiFiIsHighPriTask = true;
- BTC_PRINT(
- BTC_MSG_INTERFACE,
- INTF_NOTIFY,
- ("[BTCoex], special Packet DHCP or EAPOL notify\n")
- );
}
} else {
pCoexSta->bWiFiIsHighPriTask = false;
- BTC_PRINT(
- BTC_MSG_INTERFACE,
- INTF_NOTIFY,
- ("[BTCoex], special Packet [Type = %d] notify\n", type)
- );
}
pCoexSta->specialPktPeriodCnt = 0;
@@ -3523,9 +2933,9 @@ void EXhalbtc8723b1ant_SpecialPacketNotify(struct btc_coexist *pBtCoexist, u8 ty
}
if (
- BTC_PACKET_DHCP == type ||
- BTC_PACKET_EAPOL == type ||
- ((BTC_PACKET_ARP == type) && (pCoexSta->bWiFiIsHighPriTask))
+ type == BTC_PACKET_DHCP ||
+ type == BTC_PACKET_EAPOL ||
+ ((type == BTC_PACKET_ARP) && (pCoexSta->bWiFiIsHighPriTask))
)
halbtc8723b1ant_ActionWifiConnectedSpecialPacket(pBtCoexist);
}
@@ -3546,26 +2956,13 @@ void EXhalbtc8723b1ant_BtInfoNotify(
rspSource = BT_INFO_SRC_8723B_1ANT_WIFI_FW;
pCoexSta->btInfoC2hCnt[rspSource]++;
- BTC_PRINT(
- BTC_MSG_INTERFACE,
- INTF_NOTIFY,
- ("[BTCoex], Bt info[%d], length =%d, hex data =[",
- rspSource,
- length)
- );
for (i = 0; i < length; i++) {
pCoexSta->btInfoC2h[rspSource][i] = tmpBuf[i];
if (i == 1)
btInfo = tmpBuf[i];
- if (i == length - 1)
- BTC_PRINT(
- BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])
- );
- else
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i]));
}
- if (BT_INFO_SRC_8723B_1ANT_WIFI_FW != rspSource) {
+ if (rspSource != BT_INFO_SRC_8723B_1ANT_WIFI_FW) {
pCoexSta->btRetryCnt = pCoexSta->btInfoC2h[rspSource][2] & 0xf;
if (pCoexSta->btRetryCnt >= 1)
@@ -3586,18 +2983,12 @@ void EXhalbtc8723b1ant_BtInfoNotify(
if (!pCoexSta->bBtTxRxMask) {
/* BT into is responded by BT FW and BT RF REG 0x3C != 0x15 => Need to switch BT TRx Mask */
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x15\n"));
pBtCoexist->fBtcSetBtReg(pBtCoexist, BTC_BT_REG_RF, 0x3c, 0x15);
}
/* Here we need to resend some wifi info to BT */
/* because bt is reset and loss of the info. */
if (pCoexSta->btInfoExt & BIT1) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n")
- );
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected);
if (bWifiConnected)
EXhalbtc8723b1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_CONNECT);
@@ -3606,14 +2997,8 @@ void EXhalbtc8723b1ant_BtInfoNotify(
}
if (pCoexSta->btInfoExt & BIT3) {
- if (!pBtCoexist->bManualControl && !pBtCoexist->bStopCoexDm) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n")
- );
+ if (!pBtCoexist->bManualControl && !pBtCoexist->bStopCoexDm)
halbtc8723b1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, false);
- }
} else {
/* BT already NOT ignore Wlan active, do nothing here. */
}
@@ -3661,32 +3046,27 @@ void EXhalbtc8723b1ant_BtInfoNotify(
if (!(btInfo & BT_INFO_8723B_1ANT_B_CONNECTION)) {
pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"));
} else if (btInfo == BT_INFO_8723B_1ANT_B_CONNECTION) {
/* connection exists but no busy */
pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"));
} else if (
(btInfo & BT_INFO_8723B_1ANT_B_SCO_ESCO) ||
(btInfo & BT_INFO_8723B_1ANT_B_SCO_BUSY)
) {
pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_SCO_BUSY;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"));
} else if (btInfo & BT_INFO_8723B_1ANT_B_ACL_BUSY) {
- if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY != pCoexDm->btStatus)
+ if (pCoexDm->btStatus != BT_8723B_1ANT_BT_STATUS_ACL_BUSY)
pCoexDm->bAutoTdmaAdjust = false;
pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_ACL_BUSY;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"));
} else {
pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_MAX;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"));
}
if (
- (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) ||
- (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) ||
- (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus)
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) ||
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_SCO_BUSY) ||
+ (pCoexDm->btStatus == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY)
)
bBtBusy = true;
else
@@ -3698,8 +3078,6 @@ void EXhalbtc8723b1ant_BtInfoNotify(
void EXhalbtc8723b1ant_HaltNotify(struct btc_coexist *pBtCoexist)
{
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n"));
-
halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0);
halbtc8723b1ant_PsTdma(pBtCoexist, FORCE_EXEC, false, 0);
halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, false, true);
@@ -3713,19 +3091,14 @@ void EXhalbtc8723b1ant_HaltNotify(struct btc_coexist *pBtCoexist)
void EXhalbtc8723b1ant_PnpNotify(struct btc_coexist *pBtCoexist, u8 pnpState)
{
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify\n"));
-
- if (BTC_WIFI_PNP_SLEEP == pnpState) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify to SLEEP\n"));
-
+ if (pnpState == BTC_WIFI_PNP_SLEEP) {
halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0);
halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 0);
halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2);
halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, false, true);
pBtCoexist->bStopCoexDm = true;
- } else if (BTC_WIFI_PNP_WAKE_UP == pnpState) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify to WAKE UP\n"));
+ } else if (pnpState == BTC_WIFI_PNP_WAKE_UP) {
pBtCoexist->bStopCoexDm = false;
halbtc8723b1ant_InitHwConfig(pBtCoexist, false, false);
halbtc8723b1ant_InitCoexDm(pBtCoexist);
@@ -3738,16 +3111,10 @@ void EXhalbtc8723b1ant_Periodical(struct btc_coexist *pBtCoexist)
static u8 disVerInfoCnt;
u32 fwVer = 0, btPatchVer = 0;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ==========================Periodical ===========================\n"));
-
if (disVerInfoCnt <= 5) {
disVerInfoCnt += 1;
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n"));
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer);
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer);
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", \
- GLCoexVerDate8723b1Ant, GLCoexVer8723b1Ant, fwVer, btPatchVer, btPatchVer));
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n"));
}
halbtc8723b1ant_MonitorBtCtr(pBtCoexist);
diff --git a/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c b/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c
index 4b570ec75e67..84241619fb3a 100644
--- a/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c
+++ b/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c
@@ -46,23 +46,18 @@ static u8 halbtc8723b2ant_BtRssiState(
) {
if (btRssi >= (rssiThresh + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) {
btRssiState = BTC_RSSI_STATE_HIGH;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n"));
} else {
btRssiState = BTC_RSSI_STATE_STAY_LOW;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n"));
}
} else {
if (btRssi < rssiThresh) {
btRssiState = BTC_RSSI_STATE_LOW;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n"));
} else {
btRssiState = BTC_RSSI_STATE_STAY_HIGH;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n"));
}
}
} else if (levelNum == 3) {
if (rssiThresh > rssiThresh1) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n"));
return pCoexSta->preBtRssiState;
}
@@ -72,10 +67,8 @@ static u8 halbtc8723b2ant_BtRssiState(
) {
if (btRssi >= (rssiThresh + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) {
btRssiState = BTC_RSSI_STATE_MEDIUM;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n"));
} else {
btRssiState = BTC_RSSI_STATE_STAY_LOW;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n"));
}
} else if (
(pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) ||
@@ -83,21 +76,16 @@ static u8 halbtc8723b2ant_BtRssiState(
) {
if (btRssi >= (rssiThresh1 + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) {
btRssiState = BTC_RSSI_STATE_HIGH;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n"));
} else if (btRssi < rssiThresh) {
btRssiState = BTC_RSSI_STATE_LOW;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n"));
} else {
btRssiState = BTC_RSSI_STATE_STAY_MEDIUM;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n"));
}
} else {
if (btRssi < rssiThresh1) {
btRssiState = BTC_RSSI_STATE_MEDIUM;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n"));
} else {
btRssiState = BTC_RSSI_STATE_STAY_HIGH;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n"));
}
}
}
@@ -127,23 +115,18 @@ static u8 halbtc8723b2ant_WifiRssiState(
) {
if (wifiRssi >= (rssiThresh + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) {
wifiRssiState = BTC_RSSI_STATE_HIGH;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n"));
} else {
wifiRssiState = BTC_RSSI_STATE_STAY_LOW;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n"));
}
} else {
if (wifiRssi < rssiThresh) {
wifiRssiState = BTC_RSSI_STATE_LOW;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n"));
} else {
wifiRssiState = BTC_RSSI_STATE_STAY_HIGH;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n"));
}
}
} else if (levelNum == 3) {
if (rssiThresh > rssiThresh1) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n"));
return pCoexSta->preWifiRssiState[index];
}
@@ -153,10 +136,8 @@ static u8 halbtc8723b2ant_WifiRssiState(
) {
if (wifiRssi >= (rssiThresh + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) {
wifiRssiState = BTC_RSSI_STATE_MEDIUM;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n"));
} else {
wifiRssiState = BTC_RSSI_STATE_STAY_LOW;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n"));
}
} else if (
(pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) ||
@@ -164,21 +145,16 @@ static u8 halbtc8723b2ant_WifiRssiState(
) {
if (wifiRssi >= (rssiThresh1 + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) {
wifiRssiState = BTC_RSSI_STATE_HIGH;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n"));
} else if (wifiRssi < rssiThresh) {
wifiRssiState = BTC_RSSI_STATE_LOW;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n"));
} else {
wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n"));
}
} else {
if (wifiRssi < rssiThresh1) {
wifiRssiState = BTC_RSSI_STATE_MEDIUM;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n"));
} else {
wifiRssiState = BTC_RSSI_STATE_STAY_HIGH;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n"));
}
}
}
@@ -233,31 +209,6 @@ static void halbtc8723b2ant_MonitorBtCtr(struct btc_coexist *pBtCoexist)
pCoexSta->lowPriorityTx = regLPTx;
pCoexSta->lowPriorityRx = regLPRx;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_MONITOR,
- (
- "[BTCoex], High Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n",
- regHPTxRx,
- regHPTx,
- regHPTx,
- regHPRx,
- regHPRx
- )
- );
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_BT_MONITOR,
- (
- "[BTCoex], Low Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n",
- regLPTxRx,
- regLPTx,
- regLPTx,
- regLPRx,
- regLPRx
- )
- );
-
/* reset counter */
pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc);
}
@@ -270,12 +221,6 @@ static void halbtc8723b2ant_QueryBtInfo(struct btc_coexist *pBtCoexist)
H2C_Parameter[0] |= BIT0; /* trigger */
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_EXEC,
- ("[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", H2C_Parameter[0])
- );
-
pBtCoexist->fBtcFillH2c(pBtCoexist, 0x61, 1, H2C_Parameter);
}
@@ -384,7 +329,6 @@ static u8 halbtc8723b2ant_ActionAlgorithm(struct btc_coexist *pBtCoexist)
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn);
if (!pBtLinkInfo->bBtLinkExist) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No BT link exists!!!\n"));
return algorithm;
}
@@ -402,21 +346,16 @@ static u8 halbtc8723b2ant_ActionAlgorithm(struct btc_coexist *pBtCoexist)
if (numOfDiffProfile == 1) {
if (pBtLinkInfo->bScoExist) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO only\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_SCO;
} else {
if (pBtLinkInfo->bHidExist) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID only\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_HID;
} else if (pBtLinkInfo->bA2dpExist) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP only\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_A2DP;
} else if (pBtLinkInfo->bPanExist) {
if (bBtHsOn) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(HS) only\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_PANHS;
} else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(EDR) only\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR;
}
}
@@ -424,17 +363,13 @@ static u8 halbtc8723b2ant_ActionAlgorithm(struct btc_coexist *pBtCoexist)
} else if (numOfDiffProfile == 2) {
if (pBtLinkInfo->bScoExist) {
if (pBtLinkInfo->bHidExist) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
} else if (pBtLinkInfo->bA2dpExist) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP ==> SCO\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
} else if (pBtLinkInfo->bPanExist) {
if (bBtHsOn) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(HS)\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_SCO;
} else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(EDR)\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
}
}
@@ -443,17 +378,14 @@ static u8 halbtc8723b2ant_ActionAlgorithm(struct btc_coexist *pBtCoexist)
pBtLinkInfo->bHidExist &&
pBtLinkInfo->bA2dpExist
) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP;
} else if (
pBtLinkInfo->bHidExist &&
pBtLinkInfo->bPanExist
) {
if (bBtHsOn) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(HS)\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_HID;
} else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(EDR)\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
}
} else if (
@@ -461,10 +393,8 @@ static u8 halbtc8723b2ant_ActionAlgorithm(struct btc_coexist *pBtCoexist)
pBtLinkInfo->bA2dpExist
) {
if (bBtHsOn) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(HS)\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS;
} else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP;
}
}
@@ -475,42 +405,17 @@ static u8 halbtc8723b2ant_ActionAlgorithm(struct btc_coexist *pBtCoexist)
pBtLinkInfo->bHidExist &&
pBtLinkInfo->bA2dpExist
) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], SCO + HID + A2DP ==> HID\n")
- );
algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
} else if (
pBtLinkInfo->bHidExist &&
pBtLinkInfo->bPanExist
) {
- if (bBtHsOn) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], SCO + HID + PAN(HS)\n")
- );
- algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
- } else {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- ("[BTCoex], SCO + HID + PAN(EDR)\n")
- );
- algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
- }
+ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
} else if (
pBtLinkInfo->bPanExist &&
pBtLinkInfo->bA2dpExist
) {
- if (bBtHsOn) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(HS)\n"));
- algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
- } else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n"));
- algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
- }
+ algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
}
} else {
if (
@@ -519,10 +424,8 @@ static u8 halbtc8723b2ant_ActionAlgorithm(struct btc_coexist *pBtCoexist)
pBtLinkInfo->bA2dpExist
) {
if (bBtHsOn) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP;
} else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
}
}
@@ -535,10 +438,7 @@ static u8 halbtc8723b2ant_ActionAlgorithm(struct btc_coexist *pBtCoexist)
pBtLinkInfo->bA2dpExist
) {
if (bBtHsOn) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n"));
-
} else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP + PAN(EDR) ==>PAN(EDR)+HID\n"));
algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID;
}
}
@@ -558,17 +458,6 @@ static void halbtc8723b2ant_SetFwDacSwingLevel(
/* 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */
H2C_Parameter[0] = dacSwingLvl;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_EXEC,
- ("[BTCoex], Set Dac Swing Level = 0x%x\n", dacSwingLvl)
- );
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_EXEC,
- ("[BTCoex], FW write 0x64 = 0x%x\n", H2C_Parameter[0])
- );
-
pBtCoexist->fBtcFillH2c(pBtCoexist, 0x64, 1, H2C_Parameter);
}
@@ -580,16 +469,6 @@ static void halbtc8723b2ant_SetFwDecBtPwr(
H2C_Parameter[0] = decBtPwrLvl;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_EXEC,
- (
- "[BTCoex], decrease Bt Power level = %d, FW write 0x62 = 0x%x\n",
- decBtPwrLvl,
- H2C_Parameter[0]
- )
- );
-
pBtCoexist->fBtcFillH2c(pBtCoexist, 0x62, 1, H2C_Parameter);
}
@@ -597,28 +476,9 @@ static void halbtc8723b2ant_DecBtPwr(
struct btc_coexist *pBtCoexist, bool bForceExec, u8 decBtPwrLvl
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW,
- (
- "[BTCoex], %s Dec BT power level = %d\n",
- (bForceExec ? "force to" : ""),
- decBtPwrLvl
- )
- );
pCoexDm->curBtDecPwrLvl = decBtPwrLvl;
if (!bForceExec) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_DETAIL,
- (
- "[BTCoex], preBtDecPwrLvl =%d, curBtDecPwrLvl =%d\n",
- pCoexDm->preBtDecPwrLvl,
- pCoexDm->curBtDecPwrLvl
- )
- );
-
if (pCoexDm->preBtDecPwrLvl == pCoexDm->curBtDecPwrLvl)
return;
}
@@ -631,28 +491,9 @@ static void halbtc8723b2ant_FwDacSwingLvl(
struct btc_coexist *pBtCoexist, bool bForceExec, u8 fwDacSwingLvl
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW,
- (
- "[BTCoex], %s set FW Dac Swing level = %d\n",
- (bForceExec ? "force to" : ""),
- fwDacSwingLvl
- )
- );
pCoexDm->curFwDacSwingLvl = fwDacSwingLvl;
if (!bForceExec) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_DETAIL,
- (
- "[BTCoex], preFwDacSwingLvl =%d, curFwDacSwingLvl =%d\n",
- pCoexDm->preFwDacSwingLvl,
- pCoexDm->curFwDacSwingLvl
- )
- );
-
if (pCoexDm->preFwDacSwingLvl == pCoexDm->curFwDacSwingLvl)
return;
}
@@ -669,17 +510,11 @@ static void halbtc8723b2ant_SetSwRfRxLpfCorner(
{
if (bRxRfShrinkOn) {
/* Shrink RF Rx LPF corner */
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_EXEC,
- ("[BTCoex], Shrink RF Rx LPF corner!!\n")
- );
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, 0xffffc);
} else {
/* Resume RF Rx LPF corner */
/* After initialized, we can use pCoexDm->btRf0x1eBackup */
if (pBtCoexist->bInitilized) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Resume RF Rx LPF corner!!\n"));
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, pCoexDm->btRf0x1eBackup);
}
}
@@ -689,28 +524,9 @@ static void halbtc8723b2ant_RfShrink(
struct btc_coexist *pBtCoexist, bool bForceExec, bool bRxRfShrinkOn
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW,
- (
- "[BTCoex], %s turn Rx RF Shrink = %s\n",
- (bForceExec ? "force to" : ""),
- (bRxRfShrinkOn ? "ON" : "OFF")
- )
- );
pCoexDm->bCurRfRxLpfShrink = bRxRfShrinkOn;
if (!bForceExec) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_DETAIL,
- (
- "[BTCoex], bPreRfRxLpfShrink =%d, bCurRfRxLpfShrink =%d\n",
- pCoexDm->bPreRfRxLpfShrink,
- pCoexDm->bCurRfRxLpfShrink
- )
- );
-
if (pCoexDm->bPreRfRxLpfShrink == pCoexDm->bCurRfRxLpfShrink)
return;
}
@@ -735,15 +551,6 @@ static void halbtc8723b2ant_SetSwPenaltyTxRateAdaptive(
H2C_Parameter[5] = 0xf9; /* MCS5 or OFDM36 */
}
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_EXEC,
- (
- "[BTCoex], set WiFi Low-Penalty Retry: %s",
- (bLowPenaltyRa ? "ON!!" : "OFF!!")
- )
- );
-
pBtCoexist->fBtcFillH2c(pBtCoexist, 0x69, 6, H2C_Parameter);
}
@@ -752,28 +559,9 @@ static void halbtc8723b2ant_LowPenaltyRa(
)
{
/* return; */
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW,
- (
- "[BTCoex], %s turn LowPenaltyRA = %s\n",
- (bForceExec ? "force to" : ""),
- (bLowPenaltyRa ? "ON" : "OFF")
- )
- );
pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa;
if (!bForceExec) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_DETAIL,
- (
- "[BTCoex], bPreLowPenaltyRa =%d, bCurLowPenaltyRa =%d\n",
- pCoexDm->bPreLowPenaltyRa,
- pCoexDm->bCurLowPenaltyRa
- )
- );
-
if (pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa)
return;
}
@@ -786,11 +574,6 @@ static void halbtc8723b2ant_SetDacSwingReg(struct btc_coexist *pBtCoexist, u32 l
{
u8 val = (u8)level;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_EXEC,
- ("[BTCoex], Write SwDacSwing = 0x%x\n", level)
- );
pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x883, 0x3e, val);
}
@@ -812,32 +595,10 @@ static void halbtc8723b2ant_DacSwing(
u32 dacSwingLvl
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW,
- (
- "[BTCoex], %s turn DacSwing =%s, dacSwingLvl = 0x%x\n",
- (bForceExec ? "force to" : ""),
- (bDacSwingOn ? "ON" : "OFF"),
- dacSwingLvl
- )
- );
pCoexDm->bCurDacSwingOn = bDacSwingOn;
pCoexDm->curDacSwingLvl = dacSwingLvl;
if (!bForceExec) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_DETAIL,
- (
- "[BTCoex], bPreDacSwingOn =%d, preDacSwingLvl = 0x%x, bCurDacSwingOn =%d, curDacSwingLvl = 0x%x\n",
- pCoexDm->bPreDacSwingOn,
- pCoexDm->preDacSwingLvl,
- pCoexDm->bCurDacSwingOn,
- pCoexDm->curDacSwingLvl
- )
- );
-
if ((pCoexDm->bPreDacSwingOn == pCoexDm->bCurDacSwingOn) &&
(pCoexDm->preDacSwingLvl == pCoexDm->curDacSwingLvl))
return;
@@ -857,7 +618,6 @@ static void halbtc8723b2ant_SetAgcTable(
/* BB AGC Gain Table */
if (bAgcTableEn) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB Agc Table On!\n"));
pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6e1A0001);
pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6d1B0001);
pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6c1C0001);
@@ -866,7 +626,6 @@ static void halbtc8723b2ant_SetAgcTable(
pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x691F0001);
pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x68200001);
} else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB Agc Table Off!\n"));
pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xaa1A0001);
pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa91B0001);
pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa81C0001);
@@ -880,11 +639,9 @@ static void halbtc8723b2ant_SetAgcTable(
/* RF Gain */
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000);
if (bAgcTableEn) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n"));
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x38fff);
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x38ffe);
} else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n"));
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x380c3);
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x28ce6);
}
@@ -892,11 +649,9 @@ static void halbtc8723b2ant_SetAgcTable(
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xed, 0xfffff, 0x1);
if (bAgcTableEn) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n"));
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x38fff);
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x38ffe);
} else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n"));
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x380c3);
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x28ce6);
}
@@ -913,28 +668,9 @@ static void halbtc8723b2ant_AgcTable(
struct btc_coexist *pBtCoexist, bool bForceExec, bool bAgcTableEn
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW,
- (
- "[BTCoex], %s %s Agc Table\n",
- (bForceExec ? "force to" : ""),
- (bAgcTableEn ? "Enable" : "Disable")
- )
- );
pCoexDm->bCurAgcTableEn = bAgcTableEn;
if (!bForceExec) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_DETAIL,
- (
- "[BTCoex], bPreAgcTableEn =%d, bCurAgcTableEn =%d\n",
- pCoexDm->bPreAgcTableEn,
- pCoexDm->bCurAgcTableEn
- )
- );
-
if (pCoexDm->bPreAgcTableEn == pCoexDm->bCurAgcTableEn)
return;
}
@@ -951,32 +687,12 @@ static void halbtc8723b2ant_SetCoexTable(
u8 val0x6cc
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_EXEC,
- ("[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0)
- );
pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, val0x6c0);
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_EXEC,
- ("[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4)
- );
pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, val0x6c4);
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_EXEC,
- ("[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8)
- );
pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8);
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_EXEC,
- ("[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc)
- );
pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, val0x6cc);
}
@@ -989,47 +705,12 @@ static void halbtc8723b2ant_CoexTable(
u8 val0x6cc
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW,
- (
- "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n",
- (bForceExec ? "force to" : ""),
- val0x6c0,
- val0x6c4,
- val0x6c8,
- val0x6cc
- )
- );
pCoexDm->curVal0x6c0 = val0x6c0;
pCoexDm->curVal0x6c4 = val0x6c4;
pCoexDm->curVal0x6c8 = val0x6c8;
pCoexDm->curVal0x6cc = val0x6cc;
if (!bForceExec) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_DETAIL,
- (
- "[BTCoex], preVal0x6c0 = 0x%x, preVal0x6c4 = 0x%x, preVal0x6c8 = 0x%x, preVal0x6cc = 0x%x !!\n",
- pCoexDm->preVal0x6c0,
- pCoexDm->preVal0x6c4,
- pCoexDm->preVal0x6c8,
- pCoexDm->preVal0x6cc
- )
- );
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_SW_DETAIL,
- (
- "[BTCoex], curVal0x6c0 = 0x%x, curVal0x6c4 = 0x%x, curVal0x6c8 = 0x%x, curVal0x6cc = 0x%x !!\n",
- pCoexDm->curVal0x6c0,
- pCoexDm->curVal0x6c4,
- pCoexDm->curVal0x6c8,
- pCoexDm->curVal0x6cc
- )
- );
-
if (
(pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) &&
(pCoexDm->preVal0x6c4 == pCoexDm->curVal0x6c4) &&
@@ -1104,15 +785,6 @@ static void halbtc8723b2ant_SetFwIgnoreWlanAct(
if (bEnable)
H2C_Parameter[0] |= BIT0; /* function enable */
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_EXEC,
- (
- "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n",
- H2C_Parameter[0]
- )
- );
-
pBtCoexist->fBtcFillH2c(pBtCoexist, 0x63, 1, H2C_Parameter);
}
@@ -1120,22 +792,9 @@ static void halbtc8723b2ant_IgnoreWlanAct(
struct btc_coexist *pBtCoexist, bool bForceExec, bool bEnable
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW,
- (
- "[BTCoex], %s turn Ignore WlanAct %s\n",
- (bForceExec ? "force to" : ""),
- (bEnable ? "ON" : "OFF")
- )
- );
-
pCoexDm->bCurIgnoreWlanAct = bEnable;
if (!bForceExec) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n",
- pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct));
-
if (pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct)
return;
}
@@ -1167,19 +826,6 @@ static void halbtc8723b2ant_SetFwPstdma(
pCoexDm->psTdmaPara[3] = byte4;
pCoexDm->psTdmaPara[4] = byte5;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_EXEC,
- (
- "[BTCoex], FW write 0x60(5bytes) = 0x%x%08x\n",
- H2C_Parameter[0],
- H2C_Parameter[1] << 24 |
- H2C_Parameter[2] << 16 |
- H2C_Parameter[3] << 8 |
- H2C_Parameter[4]
- )
- );
-
pBtCoexist->fBtcFillH2c(pBtCoexist, 0x60, 5, H2C_Parameter);
}
@@ -1305,38 +951,10 @@ static void halbtc8723b2ant_PsTdma(
struct btc_coexist *pBtCoexist, bool bForceExec, bool bTurnOn, u8 type
)
{
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW,
- (
- "[BTCoex], %s turn %s PS TDMA, type =%d\n",
- (bForceExec ? "force to" : ""),
- (bTurnOn ? "ON" : "OFF"),
- type
- )
- );
pCoexDm->bCurPsTdmaOn = bTurnOn;
pCoexDm->curPsTdma = type;
if (!bForceExec) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_DETAIL,
- (
- "[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n",
- pCoexDm->bPrePsTdmaOn,
- pCoexDm->bCurPsTdmaOn
- )
- );
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_DETAIL,
- (
- "[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n",
- pCoexDm->prePsTdma, pCoexDm->curPsTdma
- )
- );
-
if (
(pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) &&
(pCoexDm->prePsTdma == pCoexDm->curPsTdma)
@@ -1505,8 +1123,6 @@ static bool halbtc8723b2ant_IsCommonAction(struct btc_coexist *pBtCoexist)
pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable);
halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8);
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non-connected idle!!\n"));
-
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0);
halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 1);
@@ -1523,8 +1139,6 @@ static bool halbtc8723b2ant_IsCommonAction(struct btc_coexist *pBtCoexist)
pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable);
halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8);
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT non connected-idle!!\n"));
-
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0);
halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 1);
@@ -1542,7 +1156,6 @@ static bool halbtc8723b2ant_IsCommonAction(struct btc_coexist *pBtCoexist)
if (bBtHsOn)
return false;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT connected-idle!!\n"));
halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8);
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
@@ -1560,13 +1173,11 @@ static bool halbtc8723b2ant_IsCommonAction(struct btc_coexist *pBtCoexist)
pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable);
if (bWifiBusy) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Busy + BT Busy!!\n"));
bCommon = false;
} else {
if (bBtHsOn)
return false;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Idle + BT Busy!!\n"));
btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0);
halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8);
@@ -1598,11 +1209,8 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */
u8 retryCount = 0;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], TdmaDurationAdjust()\n"));
-
if (!pCoexDm->bAutoTdmaAdjust) {
pCoexDm->bAutoTdmaAdjust = true;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n"));
{
if (bScoHid) {
if (bTxPause) {
@@ -1648,15 +1256,6 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
} else {
/* acquire the BT TRx retry count from BT_Info byte2 */
retryCount = pCoexSta->btRetryCnt;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount));
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_DETAIL,
- (
- "[BTCoex], up =%d, dn =%d, m =%d, n =%d, WaitCount =%d\n",
- up, dn, m, n, WaitCount
- )
- );
result = 0;
WaitCount++;
@@ -1673,7 +1272,6 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
up = 0;
dn = 0;
result = 1;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n"));
}
} else if (retryCount <= 3) { /* <=3 retry in the last 2-second duration */
up--;
@@ -1696,7 +1294,6 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
dn = 0;
WaitCount = 0;
result = -1;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n"));
}
} else { /* retry count > 3, 只要1次 retry count > 3, 則調窄WiFi duration */
if (WaitCount == 1)
@@ -1712,14 +1309,10 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
dn = 0;
WaitCount = 0;
result = -1;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n"));
}
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], max Interval = %d\n", maxInterval));
if (maxInterval == 1) {
if (bTxPause) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n"));
-
if (pCoexDm->curPsTdma == 71)
HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(5);
else if (pCoexDm->curPsTdma == 1)
@@ -1768,7 +1361,6 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(13);
}
} else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n"));
if (pCoexDm->curPsTdma == 5)
HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(71);
else if (pCoexDm->curPsTdma == 6)
@@ -1821,7 +1413,6 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
}
} else if (maxInterval == 2) {
if (bTxPause) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n"));
if (pCoexDm->curPsTdma == 1)
HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(6);
else if (pCoexDm->curPsTdma == 2)
@@ -1868,7 +1459,6 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(14);
}
} else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n"));
if (pCoexDm->curPsTdma == 5)
HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(2);
else if (pCoexDm->curPsTdma == 6)
@@ -1917,7 +1507,6 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
}
} else if (maxInterval == 3) {
if (bTxPause) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n"));
if (pCoexDm->curPsTdma == 1)
HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(7);
else if (pCoexDm->curPsTdma == 2)
@@ -1964,7 +1553,6 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(15);
}
} else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n"));
if (pCoexDm->curPsTdma == 5)
HAL_BTC8723B2ANT_DMA_DURATION_ADJUST(3);
else if (pCoexDm->curPsTdma == 6)
@@ -2018,15 +1606,6 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
/* then we have to adjust it back to the previous record one. */
if (pCoexDm->curPsTdma != pCoexDm->psTdmaDuAdjType) {
bool bScan = false, bLink = false, bRoam = false;
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_DETAIL,
- (
- "[BTCoex], PsTdma type mismatch!!!, curPsTdma =%d, recordPsTdma =%d\n",
- pCoexDm->curPsTdma,
- pCoexDm->psTdmaDuAdjType
- )
- );
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan);
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink);
@@ -2034,9 +1613,7 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
if (!bScan && !bLink && !bRoam)
halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, pCoexDm->psTdmaDuAdjType);
- else {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n"));
- }
+
}
}
@@ -2171,7 +1748,6 @@ static void halbtc8723b2ant_ActionA2dp(struct btc_coexist *pBtCoexist)
/* define the office environment */
if (apNum >= 10 && BTC_RSSI_HIGH(wifiRssiState1)) {
- /* DbgPrint(" AP#>10(%d)\n", apNum); */
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8);
halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6);
@@ -2660,21 +2236,16 @@ static void halbtc8723b2ant_RunCoexistMechanism(struct btc_coexist *pBtCoexist)
{
u8 algorithm = 0;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism() ===>\n"));
-
if (pBtCoexist->bManualControl) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"));
return;
}
if (pCoexSta->bUnderIps) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is under IPS !!!\n"));
return;
}
algorithm = halbtc8723b2ant_ActionAlgorithm(pBtCoexist);
if (pCoexSta->bC2hBtInquiryPage && (BT_8723B_2ANT_COEX_ALGO_PANHS != algorithm)) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT is under inquiry/page scan !!\n"));
halbtc8723b2ant_ActionBtInquiry(pBtCoexist);
return;
} else {
@@ -2685,69 +2256,47 @@ static void halbtc8723b2ant_RunCoexistMechanism(struct btc_coexist *pBtCoexist)
}
pCoexDm->curAlgorithm = algorithm;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Algorithm = %d\n", pCoexDm->curAlgorithm));
if (halbtc8723b2ant_IsCommonAction(pBtCoexist)) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant common.\n"));
pCoexDm->bAutoTdmaAdjust = false;
} else {
if (pCoexDm->curAlgorithm != pCoexDm->preAlgorithm) {
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE,
- (
- "[BTCoex], preAlgorithm =%d, curAlgorithm =%d\n",
- pCoexDm->preAlgorithm,
- pCoexDm->curAlgorithm
- )
- );
pCoexDm->bAutoTdmaAdjust = false;
}
switch (pCoexDm->curAlgorithm) {
case BT_8723B_2ANT_COEX_ALGO_SCO:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = SCO.\n"));
halbtc8723b2ant_ActionSco(pBtCoexist);
break;
case BT_8723B_2ANT_COEX_ALGO_HID:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID.\n"));
halbtc8723b2ant_ActionHid(pBtCoexist);
break;
case BT_8723B_2ANT_COEX_ALGO_A2DP:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP.\n"));
halbtc8723b2ant_ActionA2dp(pBtCoexist);
break;
case BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n"));
halbtc8723b2ant_ActionA2dpPanHs(pBtCoexist);
break;
case BT_8723B_2ANT_COEX_ALGO_PANEDR:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n"));
halbtc8723b2ant_ActionPanEdr(pBtCoexist);
break;
case BT_8723B_2ANT_COEX_ALGO_PANHS:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HS mode.\n"));
halbtc8723b2ant_ActionPanHs(pBtCoexist);
break;
case BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n"));
halbtc8723b2ant_ActionPanEdrA2dp(pBtCoexist);
break;
case BT_8723B_2ANT_COEX_ALGO_PANEDR_HID:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n"));
halbtc8723b2ant_ActionPanEdrHid(pBtCoexist);
break;
case BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n"));
halbtc8723b2ant_ActionHidA2dpPanEdr(pBtCoexist);
break;
case BT_8723B_2ANT_COEX_ALGO_HID_A2DP:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n"));
halbtc8723b2ant_ActionHidA2dp(pBtCoexist);
break;
default:
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n"));
halbtc8723b2ant_CoexAllOff(pBtCoexist);
break;
}
@@ -2784,8 +2333,6 @@ static void halbtc8723b2ant_InitHwConfig(struct btc_coexist *pBtCoexist, bool bB
{
u8 u1Tmp = 0;
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 2Ant Init HW Config!!\n"));
-
/* backup rf 0x1e value */
pCoexDm->btRf0x1eBackup =
pBtCoexist->fBtcGetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff);
@@ -2873,8 +2420,6 @@ void EXhalbtc8723b2ant_InitHwConfig(struct btc_coexist *pBtCoexist, bool bWifiOn
void EXhalbtc8723b2ant_InitCoexDm(struct btc_coexist *pBtCoexist)
{
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n"));
-
halbtc8723b2ant_InitCoexDm(pBtCoexist);
}
@@ -2886,7 +2431,7 @@ void EXhalbtc8723b2ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
u8 *cliBuf = pBtCoexist->cliBuf;
u8 u1Tmp[4], i, btInfoExt, psTdmaCase = 0;
u32 u4Tmp[4];
- bool bRoam = false, bScan = false, bLink = false, bWifiUnder5G = false;
+ bool bRoam = false, bScan = false, bLink = false;
bool bBtHsOn = false, bWifiBusy = false;
s32 wifiRssi = 0, btHsRssi = 0;
u32 wifiBw, wifiTrafficDir, faOfdm, faCck;
@@ -2977,7 +2522,6 @@ void EXhalbtc8723b2ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
);
CL_PRINTF(cliBuf);
- pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G);
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw);
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy);
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir);
@@ -2985,7 +2529,7 @@ void EXhalbtc8723b2ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
cliBuf,
BT_TMP_BUF_SIZE,
"\r\n %-35s = %s / %s/ %s ", "Wifi status", \
- (bWifiUnder5G ? "5G" : "2.4G"),
+ ("2.4G"),
((BTC_WIFI_BW_LEGACY == wifiBw) ? "Legacy" : (((BTC_WIFI_BW_HT40 == wifiBw) ? "HT40" : "HT20"))),
((!bWifiBusy) ? "idle" : ((BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) ? "uplink" : "downlink"))
);
@@ -3262,13 +2806,11 @@ void EXhalbtc8723b2ant_DisplayCoexInfo(struct btc_coexist *pBtCoexist)
void EXhalbtc8723b2ant_IpsNotify(struct btc_coexist *pBtCoexist, u8 type)
{
if (BTC_IPS_ENTER == type) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n"));
pCoexSta->bUnderIps = true;
halbtc8723b2ant_WifiOffHwCfg(pBtCoexist);
halbtc8723b2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, true);
halbtc8723b2ant_CoexAllOff(pBtCoexist);
} else if (BTC_IPS_LEAVE == type) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n"));
pCoexSta->bUnderIps = false;
halbtc8723b2ant_InitHwConfig(pBtCoexist, false);
halbtc8723b2ant_InitCoexDm(pBtCoexist);
@@ -3279,10 +2821,8 @@ void EXhalbtc8723b2ant_IpsNotify(struct btc_coexist *pBtCoexist, u8 type)
void EXhalbtc8723b2ant_LpsNotify(struct btc_coexist *pBtCoexist, u8 type)
{
if (BTC_LPS_ENABLE == type) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n"));
pCoexSta->bUnderLps = true;
} else if (BTC_LPS_DISABLE == type) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n"));
pCoexSta->bUnderLps = false;
}
}
@@ -3290,18 +2830,14 @@ void EXhalbtc8723b2ant_LpsNotify(struct btc_coexist *pBtCoexist, u8 type)
void EXhalbtc8723b2ant_ScanNotify(struct btc_coexist *pBtCoexist, u8 type)
{
if (BTC_SCAN_START == type) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n"));
} else if (BTC_SCAN_FINISH == type) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n"));
}
}
void EXhalbtc8723b2ant_ConnectNotify(struct btc_coexist *pBtCoexist, u8 type)
{
if (BTC_ASSOCIATE_START == type) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n"));
} else if (BTC_ASSOCIATE_FINISH == type) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n"));
}
}
@@ -3312,12 +2848,6 @@ void EXhalbtc8723b2ant_MediaStatusNotify(struct btc_coexist *pBtCoexist, u8 type
u8 wifiCentralChnl;
u8 apNum = 0;
- if (BTC_MEDIA_CONNECT == type) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n"));
- } else {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n"));
- }
-
/* only 2.4G we need to inform bt the chnl mask */
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl);
if ((BTC_MEDIA_CONNECT == type) && (wifiCentralChnl <= 14)) {
@@ -3339,23 +2869,11 @@ void EXhalbtc8723b2ant_MediaStatusNotify(struct btc_coexist *pBtCoexist, u8 type
pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1];
pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2];
- BTC_PRINT(
- BTC_MSG_ALGORITHM,
- ALGO_TRACE_FW_EXEC,
- (
- "[BTCoex], FW write 0x66 = 0x%x\n",
- H2C_Parameter[0] << 16 | H2C_Parameter[1] << 8 | H2C_Parameter[2]
- )
- );
-
pBtCoexist->fBtcFillH2c(pBtCoexist, 0x66, 3, H2C_Parameter);
}
void EXhalbtc8723b2ant_SpecialPacketNotify(struct btc_coexist *pBtCoexist, u8 type)
{
- if (type == BTC_PACKET_DHCP) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], DHCP Packet notify\n"));
- }
}
void EXhalbtc8723b2ant_BtInfoNotify(
@@ -3375,21 +2893,14 @@ void EXhalbtc8723b2ant_BtInfoNotify(
pCoexSta->btInfoC2hCnt[rspSource]++;
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length =%d, hex data =[", rspSource, length));
for (i = 0; i < length; i++) {
pCoexSta->btInfoC2h[rspSource][i] = tmpBuf[i];
if (i == 1)
btInfo = tmpBuf[i];
- if (i == length - 1) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i]));
- } else {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i]));
- }
}
if (pBtCoexist->bManualControl) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), return for Manual CTRL<===\n"));
return;
}
@@ -3404,14 +2915,12 @@ void EXhalbtc8723b2ant_BtInfoNotify(
pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TX_RX_MASK, &pCoexSta->bBtTxRxMask);
if (pCoexSta->bBtTxRxMask) {
/* BT into is responded by BT FW and BT RF REG 0x3C != 0x01 => Need to switch BT TRx Mask */
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x01\n"));
pBtCoexist->fBtcSetBtReg(pBtCoexist, BTC_BT_REG_RF, 0x3c, 0x01);
}
/* Here we need to resend some wifi info to BT */
/* because bt is reset and loss of the info. */
if ((pCoexSta->btInfoExt & BIT1)) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"));
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected);
if (bWifiConnected)
@@ -3421,7 +2930,6 @@ void EXhalbtc8723b2ant_BtInfoNotify(
}
if ((pCoexSta->btInfoExt & BIT3)) {
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"));
halbtc8723b2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, false);
} else {
/* BT already NOT ignore Wlan active, do nothing here. */
@@ -3465,22 +2973,17 @@ void EXhalbtc8723b2ant_BtInfoNotify(
if (!(btInfo & BT_INFO_8723B_2ANT_B_CONNECTION)) {
pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"));
} else if (btInfo == BT_INFO_8723B_2ANT_B_CONNECTION) { /* connection exists but no busy */
pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"));
} else if (
(btInfo & BT_INFO_8723B_2ANT_B_SCO_ESCO) ||
(btInfo & BT_INFO_8723B_2ANT_B_SCO_BUSY)
) {
pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_SCO_BUSY;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"));
} else if (btInfo & BT_INFO_8723B_2ANT_B_ACL_BUSY) {
pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_ACL_BUSY;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"));
} else {
pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_MAX;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"));
}
if (
@@ -3505,8 +3008,6 @@ void EXhalbtc8723b2ant_BtInfoNotify(
void EXhalbtc8723b2ant_HaltNotify(struct btc_coexist *pBtCoexist)
{
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n"));
-
halbtc8723b2ant_WifiOffHwCfg(pBtCoexist);
pBtCoexist->fBtcSetBtReg(pBtCoexist, BTC_BT_REG_RF, 0x3c, 0x15); /* BT goto standby while GNT_BT 1-->0 */
halbtc8723b2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, true);
@@ -3516,12 +3017,8 @@ void EXhalbtc8723b2ant_HaltNotify(struct btc_coexist *pBtCoexist)
void EXhalbtc8723b2ant_PnpNotify(struct btc_coexist *pBtCoexist, u8 pnpState)
{
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify\n"));
-
if (BTC_WIFI_PNP_SLEEP == pnpState) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify to SLEEP\n"));
} else if (BTC_WIFI_PNP_WAKE_UP == pnpState) {
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify to WAKE UP\n"));
halbtc8723b2ant_InitHwConfig(pBtCoexist, false);
halbtc8723b2ant_InitCoexDm(pBtCoexist);
halbtc8723b2ant_QueryBtInfo(pBtCoexist);
@@ -3533,16 +3030,10 @@ void EXhalbtc8723b2ant_Periodical(struct btc_coexist *pBtCoexist)
static u8 disVerInfoCnt;
u32 fwVer = 0, btPatchVer = 0;
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ==========================Periodical ===========================\n"));
-
if (disVerInfoCnt <= 5) {
disVerInfoCnt += 1;
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n"));
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer);
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer);
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", \
- GLCoexVerDate8723b2Ant, GLCoexVer8723b2Ant, fwVer, btPatchVer, btPatchVer));
- BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n"));
}
if (
diff --git a/drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h b/drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h
index 7b2d94a33d9c..deb57fa15eaf 100644
--- a/drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h
+++ b/drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h
@@ -78,29 +78,6 @@ enum {
BTC_CHIP_MAX
};
-enum {
- BTC_MSG_INTERFACE = 0x0,
- BTC_MSG_ALGORITHM = 0x1,
- BTC_MSG_MAX
-};
-extern u32 GLBtcDbgType[];
-
-/* following is for BTC_MSG_INTERFACE */
-#define INTF_INIT BIT0
-#define INTF_NOTIFY BIT2
-
-/* following is for BTC_ALGORITHM */
-#define ALGO_BT_RSSI_STATE BIT0
-#define ALGO_WIFI_RSSI_STATE BIT1
-#define ALGO_BT_MONITOR BIT2
-#define ALGO_TRACE BIT3
-#define ALGO_TRACE_FW BIT4
-#define ALGO_TRACE_FW_DETAIL BIT5
-#define ALGO_TRACE_FW_EXEC BIT6
-#define ALGO_TRACE_SW BIT7
-#define ALGO_TRACE_SW_DETAIL BIT8
-#define ALGO_TRACE_SW_EXEC BIT9
-
/* following is for wifi link status */
#define WIFI_STA_CONNECTED BIT0
#define WIFI_AP_CONNECTED BIT1
@@ -112,50 +89,6 @@ extern u32 GLBtcDbgType[];
#define CL_SPRINTF snprintf
#define CL_PRINTF DCMD_Printf
-/* The following is for dbgview print */
-#if DBG
-#define BTC_PRINT(dbgtype, dbgflag, printstr)\
-{\
- if (GLBtcDbgType[dbgtype] & dbgflag)\
- DbgPrint printstr;\
-}
-
-#define BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _Ptr)\
-{\
- if (GLBtcDbgType[dbgtype] & dbgflag) {\
- int __i;\
- u8 *ptr = (u8 *)_Ptr;\
- DbgPrint printstr;\
- DbgPrint(" ");\
- for (__i = 0; __i < 6; __i++)\
- DbgPrint("%02X%s", ptr[__i], (__i == 5) ? "" : "-");\
- DbgPrint("\n");\
- } \
-}
-
-#define BTC_PRINT_DATA(dbgtype, dbgflag, _TitleString, _HexData, _HexDataLen)\
-{\
- if (GLBtcDbgType[dbgtype] & dbgflag) {\
- int __i;\
- u8 *ptr = (u8 *)_HexData;\
- DbgPrint(_TitleString);\
- for (__i = 0; __i < (int)_HexDataLen; __i++) {\
- DbgPrint("%02X%s", ptr[__i], (((__i + 1) % 4) == 0) ? " " : " ");\
- if (((__i + 1) % 16) == 0)\
- DbgPrint("\n");\
- } \
- DbgPrint("\n");\
- } \
-}
-
-#else
-#define BTC_PRINT(dbgtype, dbgflag, printstr) no_printk printstr
-#define BTC_PRINT_F(dbgtype, dbgflag, printstr) no_printk printstr
-#define BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _Ptr) no_printk printstr
-#define BTC_PRINT_DATA(dbgtype, dbgflag, _TitleString, _HexData, _HexDataLen) \
- no_printk("%s %p %zu", _TitleString, _HexData, _HexDataLen)
-#endif
-
struct btc_board_info {
/* The following is some board information */
u8 btChipType;
@@ -209,7 +142,6 @@ enum {
BTC_GET_BL_WIFI_LINK,
BTC_GET_BL_WIFI_ROAM,
BTC_GET_BL_WIFI_4_WAY_PROGRESS,
- BTC_GET_BL_WIFI_UNDER_5G,
BTC_GET_BL_WIFI_AP_MODE_ENABLE,
BTC_GET_BL_WIFI_ENABLE_ENCRYPTION,
BTC_GET_BL_WIFI_UNDER_B_MODE,
diff --git a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c
index 016d257b90a0..3de8dcb5ed7c 100644
--- a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c
+++ b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c
@@ -33,47 +33,6 @@ static bool CheckPositive(
pDM_Odm->TypeALNA << 16 |
pDM_Odm->TypeAPA << 24;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- "===> [8812A] CheckPositive (cond1, cond2) = (0x%X 0x%X)\n",
- cond1,
- cond2
- )
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- "===> [8812A] CheckPositive (driver1, driver2) = (0x%X 0x%X)\n",
- driver1,
- driver2
- )
- );
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (" (Platform, Interface) = (0x%X, 0x%X)\n",
- pDM_Odm->SupportPlatform,
- pDM_Odm->SupportInterface
- )
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- " (Board, Package) = (0x%X, 0x%X)\n",
- pDM_Odm->BoardType,
- pDM_Odm->PackageType
- )
- );
-
/* Value Defined Check =============== */
/* QFN Type [15:12] and Cut Version [27:24] need to do value check */
@@ -263,13 +222,6 @@ void ODM_ReadAndConfig_MP_8723B_AGC_TAB(struct dm_odm_t *pDM_Odm)
u32 ArrayLen = ARRAY_SIZE(Array_MP_8723B_AGC_TAB);
u32 *Array = Array_MP_8723B_AGC_TAB;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_LOUD,
- ("===> ODM_ReadAndConfig_MP_8723B_AGC_TAB\n")
- );
-
for (i = 0; i < ArrayLen; i += 2) {
u32 v1 = Array[i];
u32 v2 = Array[i+1];
@@ -532,13 +484,6 @@ void ODM_ReadAndConfig_MP_8723B_PHY_REG(struct dm_odm_t *pDM_Odm)
u32 ArrayLen = ARRAY_SIZE(Array_MP_8723B_PHY_REG);
u32 *Array = Array_MP_8723B_PHY_REG;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_LOUD,
- ("===> ODM_ReadAndConfig_MP_8723B_PHY_REG\n")
- );
-
for (i = 0; i < ArrayLen; i += 2) {
u32 v1 = Array[i];
u32 v2 = Array[i+1];
@@ -598,12 +543,12 @@ void ODM_ReadAndConfig_MP_8723B_PHY_REG(struct dm_odm_t *pDM_Odm)
******************************************************************************/
static u32 Array_MP_8723B_PHY_REG_PG[] = {
- 0, 0, 0, 0x00000e08, 0x0000ff00, 0x00003800,
- 0, 0, 0, 0x0000086c, 0xffffff00, 0x32343600,
- 0, 0, 0, 0x00000e00, 0xffffffff, 0x40424444,
- 0, 0, 0, 0x00000e04, 0xffffffff, 0x28323638,
- 0, 0, 0, 0x00000e10, 0xffffffff, 0x38404244,
- 0, 0, 0, 0x00000e14, 0xffffffff, 0x26303436
+ 0, 0, 0x00000e08, 0x0000ff00, 0x00003800,
+ 0, 0, 0x0000086c, 0xffffff00, 0x32343600,
+ 0, 0, 0x00000e00, 0xffffffff, 0x40424444,
+ 0, 0, 0x00000e04, 0xffffffff, 0x28323638,
+ 0, 0, 0x00000e10, 0xffffffff, 0x38404244,
+ 0, 0, 0x00000e14, 0xffffffff, 0x26303436
};
void ODM_ReadAndConfig_MP_8723B_PHY_REG_PG(struct dm_odm_t *pDM_Odm)
@@ -611,24 +556,16 @@ void ODM_ReadAndConfig_MP_8723B_PHY_REG_PG(struct dm_odm_t *pDM_Odm)
u32 i = 0;
u32 *Array = Array_MP_8723B_PHY_REG_PG;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_LOUD,
- ("===> ODM_ReadAndConfig_MP_8723B_PHY_REG_PG\n")
- );
-
pDM_Odm->PhyRegPgVersion = 1;
pDM_Odm->PhyRegPgValueType = PHY_REG_PG_EXACT_VALUE;
- for (i = 0; i < ARRAY_SIZE(Array_MP_8723B_PHY_REG_PG); i += 6) {
+ for (i = 0; i < ARRAY_SIZE(Array_MP_8723B_PHY_REG_PG); i += 5) {
u32 v1 = Array[i];
u32 v2 = Array[i+1];
u32 v3 = Array[i+2];
u32 v4 = Array[i+3];
u32 v5 = Array[i+4];
- u32 v6 = Array[i+5];
- odm_ConfigBB_PHY_REG_PG_8723B(pDM_Odm, v1, v2, v3, v4, v5, v6);
+ odm_ConfigBB_PHY_REG_PG_8723B(pDM_Odm, v1, v2, v3, v4, v5);
}
}
diff --git a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c
index 677bcfa10b0d..47e66f4ad9d1 100644
--- a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c
+++ b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_MAC.c
@@ -33,48 +33,6 @@ static bool CheckPositive(
pDM_Odm->TypeALNA << 16 |
pDM_Odm->TypeAPA << 24;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- "===> [8812A] CheckPositive (cond1, cond2) = (0x%X 0x%X)\n",
- cond1,
- cond2
- )
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- "===> [8812A] CheckPositive (driver1, driver2) = (0x%X 0x%X)\n",
- driver1,
- driver2
- )
- );
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- " (Platform, Interface) = (0x%X, 0x%X)\n",
- pDM_Odm->SupportPlatform,
- pDM_Odm->SupportInterface
- )
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- " (Board, Package) = (0x%X, 0x%X)\n",
- pDM_Odm->BoardType,
- pDM_Odm->PackageType
- )
- );
-
/* Value Defined Check =============== */
/* QFN Type [15:12] and Cut Version [27:24] need to do value check */
@@ -234,13 +192,6 @@ void ODM_ReadAndConfig_MP_8723B_MAC_REG(struct dm_odm_t *pDM_Odm)
u32 ArrayLen = ARRAY_SIZE(Array_MP_8723B_MAC_REG);
u32 *Array = Array_MP_8723B_MAC_REG;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_LOUD,
- ("===> ODM_ReadAndConfig_MP_8723B_MAC_REG\n")
- );
-
for (i = 0; i < ArrayLen; i += 2) {
u32 v1 = Array[i];
u32 v2 = Array[i+1];
diff --git a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c
index 2c450c1ce7e7..00d429977ea9 100644
--- a/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c
+++ b/drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c
@@ -33,48 +33,6 @@ static bool CheckPositive(
pDM_Odm->TypeALNA << 16 |
pDM_Odm->TypeAPA << 24;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- "===> [8812A] CheckPositive (cond1, cond2) = (0x%X 0x%X)\n",
- cond1,
- cond2
- )
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- "===> [8812A] CheckPositive (driver1, driver2) = (0x%X 0x%X)\n",
- driver1,
- driver2
- )
- );
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- " (Platform, Interface) = (0x%X, 0x%X)\n",
- pDM_Odm->SupportPlatform,
- pDM_Odm->SupportInterface
- )
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- " (Board, Package) = (0x%X, 0x%X)\n",
- pDM_Odm->BoardType,
- pDM_Odm->PackageType
- )
- );
-
/* Value Defined Check =============== */
/* QFN Type [15:12] and Cut Version [27:24] need to do value check */
@@ -265,13 +223,6 @@ void ODM_ReadAndConfig_MP_8723B_RadioA(struct dm_odm_t *pDM_Odm)
u32 ArrayLen = ARRAY_SIZE(Array_MP_8723B_RadioA);
u32 *Array = Array_MP_8723B_RadioA;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_LOUD,
- ("===> ODM_ReadAndConfig_MP_8723B_RadioA\n")
- );
-
for (i = 0; i < ArrayLen; i += 2) {
u32 v1 = Array[i];
u32 v2 = Array[i+1];
@@ -331,62 +282,6 @@ void ODM_ReadAndConfig_MP_8723B_RadioA(struct dm_odm_t *pDM_Odm)
* TxPowerTrack_SDIO.TXT
******************************************************************************/
-static u8 gDeltaSwingTableIdx_MP_5GB_N_TxPowerTrack_SDIO_8723B[][DELTA_SWINGIDX_SIZE] = {
- {
- 0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9,
- 9, 10, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14
- },
- {
- 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
- 10, 11, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14
- },
- {
- 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
- 10, 11, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14
- },
-};
-static u8 gDeltaSwingTableIdx_MP_5GB_P_TxPowerTrack_SDIO_8723B[][DELTA_SWINGIDX_SIZE] = {
- {
- 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12,
- 12, 13, 14, 15, 15, 16, 16, 17, 17, 18, 19, 20, 20, 20
- },
- {
- 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12,
- 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 19, 20, 20, 20
- },
- {
- 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12,
- 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 20, 21, 21, 21
- },
-};
-static u8 gDeltaSwingTableIdx_MP_5GA_N_TxPowerTrack_SDIO_8723B[][DELTA_SWINGIDX_SIZE] = {
- {
- 0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 8, 9, 9, 10,
- 10, 11, 11, 12, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14
- },
- {
- 0, 1, 2, 3, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 9, 10,
- 11, 11, 12, 13, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16
- },
- {
- 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 10, 11,
- 11, 12, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16
- },
-};
-static u8 gDeltaSwingTableIdx_MP_5GA_P_TxPowerTrack_SDIO_8723B[][DELTA_SWINGIDX_SIZE] = {
- {
- 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, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12,
- 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 20, 21, 21, 21
- },
- {
- 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12,
- 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 20, 21, 21, 21
- },
-};
static u8 gDeltaSwingTableIdx_MP_2GB_N_TxPowerTrack_SDIO_8723B[] = {
0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 6, 6,
7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13, 14, 15
@@ -424,13 +319,6 @@ void ODM_ReadAndConfig_MP_8723B_TxPowerTrack_SDIO(struct dm_odm_t *pDM_Odm)
{
struct odm_rf_cal_t *pRFCalibrateInfo = &pDM_Odm->RFCalibrateInfo;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_LOUD,
- ("===> ODM_ReadAndConfig_MP_MP_8723B\n")
- );
-
memcpy(
pRFCalibrateInfo->DeltaSwingTableIdx_2GA_P,
@@ -473,27 +361,6 @@ void ODM_ReadAndConfig_MP_8723B_TxPowerTrack_SDIO(struct dm_odm_t *pDM_Odm)
gDeltaSwingTableIdx_MP_2GCCKB_N_TxPowerTrack_SDIO_8723B,
DELTA_SWINGIDX_SIZE
);
-
- memcpy(
- pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P,
- gDeltaSwingTableIdx_MP_5GA_P_TxPowerTrack_SDIO_8723B,
- DELTA_SWINGIDX_SIZE*3
- );
- memcpy(
- pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N,
- gDeltaSwingTableIdx_MP_5GA_N_TxPowerTrack_SDIO_8723B,
- DELTA_SWINGIDX_SIZE*3
- );
- memcpy(
- pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P,
- gDeltaSwingTableIdx_MP_5GB_P_TxPowerTrack_SDIO_8723B,
- DELTA_SWINGIDX_SIZE*3
- );
- memcpy(
- pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N,
- gDeltaSwingTableIdx_MP_5GB_N_TxPowerTrack_SDIO_8723B,
- DELTA_SWINGIDX_SIZE*3
- );
}
/******************************************************************************
@@ -501,258 +368,258 @@ void ODM_ReadAndConfig_MP_8723B_TxPowerTrack_SDIO(struct dm_odm_t *pDM_Odm)
******************************************************************************/
static u8 *Array_MP_8723B_TXPWR_LMT[] = {
- "FCC", "2.4G", "20M", "CCK", "1T", "01", "32",
- "ETSI", "2.4G", "20M", "CCK", "1T", "01", "32",
- "MKK", "2.4G", "20M", "CCK", "1T", "01", "32",
- "FCC", "2.4G", "20M", "CCK", "1T", "02", "32",
- "ETSI", "2.4G", "20M", "CCK", "1T", "02", "32",
- "MKK", "2.4G", "20M", "CCK", "1T", "02", "32",
- "FCC", "2.4G", "20M", "CCK", "1T", "03", "32",
- "ETSI", "2.4G", "20M", "CCK", "1T", "03", "32",
- "MKK", "2.4G", "20M", "CCK", "1T", "03", "32",
- "FCC", "2.4G", "20M", "CCK", "1T", "04", "32",
- "ETSI", "2.4G", "20M", "CCK", "1T", "04", "32",
- "MKK", "2.4G", "20M", "CCK", "1T", "04", "32",
- "FCC", "2.4G", "20M", "CCK", "1T", "05", "32",
- "ETSI", "2.4G", "20M", "CCK", "1T", "05", "32",
- "MKK", "2.4G", "20M", "CCK", "1T", "05", "32",
- "FCC", "2.4G", "20M", "CCK", "1T", "06", "32",
- "ETSI", "2.4G", "20M", "CCK", "1T", "06", "32",
- "MKK", "2.4G", "20M", "CCK", "1T", "06", "32",
- "FCC", "2.4G", "20M", "CCK", "1T", "07", "32",
- "ETSI", "2.4G", "20M", "CCK", "1T", "07", "32",
- "MKK", "2.4G", "20M", "CCK", "1T", "07", "32",
- "FCC", "2.4G", "20M", "CCK", "1T", "08", "32",
- "ETSI", "2.4G", "20M", "CCK", "1T", "08", "32",
- "MKK", "2.4G", "20M", "CCK", "1T", "08", "32",
- "FCC", "2.4G", "20M", "CCK", "1T", "09", "32",
- "ETSI", "2.4G", "20M", "CCK", "1T", "09", "32",
- "MKK", "2.4G", "20M", "CCK", "1T", "09", "32",
- "FCC", "2.4G", "20M", "CCK", "1T", "10", "32",
- "ETSI", "2.4G", "20M", "CCK", "1T", "10", "32",
- "MKK", "2.4G", "20M", "CCK", "1T", "10", "32",
- "FCC", "2.4G", "20M", "CCK", "1T", "11", "32",
- "ETSI", "2.4G", "20M", "CCK", "1T", "11", "32",
- "MKK", "2.4G", "20M", "CCK", "1T", "11", "32",
- "FCC", "2.4G", "20M", "CCK", "1T", "12", "63",
- "ETSI", "2.4G", "20M", "CCK", "1T", "12", "32",
- "MKK", "2.4G", "20M", "CCK", "1T", "12", "32",
- "FCC", "2.4G", "20M", "CCK", "1T", "13", "63",
- "ETSI", "2.4G", "20M", "CCK", "1T", "13", "32",
- "MKK", "2.4G", "20M", "CCK", "1T", "13", "32",
- "FCC", "2.4G", "20M", "CCK", "1T", "14", "63",
- "ETSI", "2.4G", "20M", "CCK", "1T", "14", "63",
- "MKK", "2.4G", "20M", "CCK", "1T", "14", "32",
- "FCC", "2.4G", "20M", "OFDM", "1T", "01", "28",
- "ETSI", "2.4G", "20M", "OFDM", "1T", "01", "32",
- "MKK", "2.4G", "20M", "OFDM", "1T", "01", "32",
- "FCC", "2.4G", "20M", "OFDM", "1T", "02", "28",
- "ETSI", "2.4G", "20M", "OFDM", "1T", "02", "32",
- "MKK", "2.4G", "20M", "OFDM", "1T", "02", "32",
- "FCC", "2.4G", "20M", "OFDM", "1T", "03", "32",
- "ETSI", "2.4G", "20M", "OFDM", "1T", "03", "32",
- "MKK", "2.4G", "20M", "OFDM", "1T", "03", "32",
- "FCC", "2.4G", "20M", "OFDM", "1T", "04", "32",
- "ETSI", "2.4G", "20M", "OFDM", "1T", "04", "32",
- "MKK", "2.4G", "20M", "OFDM", "1T", "04", "32",
- "FCC", "2.4G", "20M", "OFDM", "1T", "05", "32",
- "ETSI", "2.4G", "20M", "OFDM", "1T", "05", "32",
- "MKK", "2.4G", "20M", "OFDM", "1T", "05", "32",
- "FCC", "2.4G", "20M", "OFDM", "1T", "06", "32",
- "ETSI", "2.4G", "20M", "OFDM", "1T", "06", "32",
- "MKK", "2.4G", "20M", "OFDM", "1T", "06", "32",
- "FCC", "2.4G", "20M", "OFDM", "1T", "07", "32",
- "ETSI", "2.4G", "20M", "OFDM", "1T", "07", "32",
- "MKK", "2.4G", "20M", "OFDM", "1T", "07", "32",
- "FCC", "2.4G", "20M", "OFDM", "1T", "08", "32",
- "ETSI", "2.4G", "20M", "OFDM", "1T", "08", "32",
- "MKK", "2.4G", "20M", "OFDM", "1T", "08", "32",
- "FCC", "2.4G", "20M", "OFDM", "1T", "09", "32",
- "ETSI", "2.4G", "20M", "OFDM", "1T", "09", "32",
- "MKK", "2.4G", "20M", "OFDM", "1T", "09", "32",
- "FCC", "2.4G", "20M", "OFDM", "1T", "10", "28",
- "ETSI", "2.4G", "20M", "OFDM", "1T", "10", "32",
- "MKK", "2.4G", "20M", "OFDM", "1T", "10", "32",
- "FCC", "2.4G", "20M", "OFDM", "1T", "11", "28",
- "ETSI", "2.4G", "20M", "OFDM", "1T", "11", "32",
- "MKK", "2.4G", "20M", "OFDM", "1T", "11", "32",
- "FCC", "2.4G", "20M", "OFDM", "1T", "12", "63",
- "ETSI", "2.4G", "20M", "OFDM", "1T", "12", "32",
- "MKK", "2.4G", "20M", "OFDM", "1T", "12", "32",
- "FCC", "2.4G", "20M", "OFDM", "1T", "13", "63",
- "ETSI", "2.4G", "20M", "OFDM", "1T", "13", "32",
- "MKK", "2.4G", "20M", "OFDM", "1T", "13", "32",
- "FCC", "2.4G", "20M", "OFDM", "1T", "14", "63",
- "ETSI", "2.4G", "20M", "OFDM", "1T", "14", "63",
- "MKK", "2.4G", "20M", "OFDM", "1T", "14", "63",
- "FCC", "2.4G", "20M", "HT", "1T", "01", "26",
- "ETSI", "2.4G", "20M", "HT", "1T", "01", "32",
- "MKK", "2.4G", "20M", "HT", "1T", "01", "32",
- "FCC", "2.4G", "20M", "HT", "1T", "02", "26",
- "ETSI", "2.4G", "20M", "HT", "1T", "02", "32",
- "MKK", "2.4G", "20M", "HT", "1T", "02", "32",
- "FCC", "2.4G", "20M", "HT", "1T", "03", "32",
- "ETSI", "2.4G", "20M", "HT", "1T", "03", "32",
- "MKK", "2.4G", "20M", "HT", "1T", "03", "32",
- "FCC", "2.4G", "20M", "HT", "1T", "04", "32",
- "ETSI", "2.4G", "20M", "HT", "1T", "04", "32",
- "MKK", "2.4G", "20M", "HT", "1T", "04", "32",
- "FCC", "2.4G", "20M", "HT", "1T", "05", "32",
- "ETSI", "2.4G", "20M", "HT", "1T", "05", "32",
- "MKK", "2.4G", "20M", "HT", "1T", "05", "32",
- "FCC", "2.4G", "20M", "HT", "1T", "06", "32",
- "ETSI", "2.4G", "20M", "HT", "1T", "06", "32",
- "MKK", "2.4G", "20M", "HT", "1T", "06", "32",
- "FCC", "2.4G", "20M", "HT", "1T", "07", "32",
- "ETSI", "2.4G", "20M", "HT", "1T", "07", "32",
- "MKK", "2.4G", "20M", "HT", "1T", "07", "32",
- "FCC", "2.4G", "20M", "HT", "1T", "08", "32",
- "ETSI", "2.4G", "20M", "HT", "1T", "08", "32",
- "MKK", "2.4G", "20M", "HT", "1T", "08", "32",
- "FCC", "2.4G", "20M", "HT", "1T", "09", "32",
- "ETSI", "2.4G", "20M", "HT", "1T", "09", "32",
- "MKK", "2.4G", "20M", "HT", "1T", "09", "32",
- "FCC", "2.4G", "20M", "HT", "1T", "10", "26",
- "ETSI", "2.4G", "20M", "HT", "1T", "10", "32",
- "MKK", "2.4G", "20M", "HT", "1T", "10", "32",
- "FCC", "2.4G", "20M", "HT", "1T", "11", "26",
- "ETSI", "2.4G", "20M", "HT", "1T", "11", "32",
- "MKK", "2.4G", "20M", "HT", "1T", "11", "32",
- "FCC", "2.4G", "20M", "HT", "1T", "12", "63",
- "ETSI", "2.4G", "20M", "HT", "1T", "12", "32",
- "MKK", "2.4G", "20M", "HT", "1T", "12", "32",
- "FCC", "2.4G", "20M", "HT", "1T", "13", "63",
- "ETSI", "2.4G", "20M", "HT", "1T", "13", "32",
- "MKK", "2.4G", "20M", "HT", "1T", "13", "32",
- "FCC", "2.4G", "20M", "HT", "1T", "14", "63",
- "ETSI", "2.4G", "20M", "HT", "1T", "14", "63",
- "MKK", "2.4G", "20M", "HT", "1T", "14", "63",
- "FCC", "2.4G", "20M", "HT", "2T", "01", "30",
- "ETSI", "2.4G", "20M", "HT", "2T", "01", "32",
- "MKK", "2.4G", "20M", "HT", "2T", "01", "32",
- "FCC", "2.4G", "20M", "HT", "2T", "02", "32",
- "ETSI", "2.4G", "20M", "HT", "2T", "02", "32",
- "MKK", "2.4G", "20M", "HT", "2T", "02", "32",
- "FCC", "2.4G", "20M", "HT", "2T", "03", "32",
- "ETSI", "2.4G", "20M", "HT", "2T", "03", "32",
- "MKK", "2.4G", "20M", "HT", "2T", "03", "32",
- "FCC", "2.4G", "20M", "HT", "2T", "04", "32",
- "ETSI", "2.4G", "20M", "HT", "2T", "04", "32",
- "MKK", "2.4G", "20M", "HT", "2T", "04", "32",
- "FCC", "2.4G", "20M", "HT", "2T", "05", "32",
- "ETSI", "2.4G", "20M", "HT", "2T", "05", "32",
- "MKK", "2.4G", "20M", "HT", "2T", "05", "32",
- "FCC", "2.4G", "20M", "HT", "2T", "06", "32",
- "ETSI", "2.4G", "20M", "HT", "2T", "06", "32",
- "MKK", "2.4G", "20M", "HT", "2T", "06", "32",
- "FCC", "2.4G", "20M", "HT", "2T", "07", "32",
- "ETSI", "2.4G", "20M", "HT", "2T", "07", "32",
- "MKK", "2.4G", "20M", "HT", "2T", "07", "32",
- "FCC", "2.4G", "20M", "HT", "2T", "08", "32",
- "ETSI", "2.4G", "20M", "HT", "2T", "08", "32",
- "MKK", "2.4G", "20M", "HT", "2T", "08", "32",
- "FCC", "2.4G", "20M", "HT", "2T", "09", "32",
- "ETSI", "2.4G", "20M", "HT", "2T", "09", "32",
- "MKK", "2.4G", "20M", "HT", "2T", "09", "32",
- "FCC", "2.4G", "20M", "HT", "2T", "10", "32",
- "ETSI", "2.4G", "20M", "HT", "2T", "10", "32",
- "MKK", "2.4G", "20M", "HT", "2T", "10", "32",
- "FCC", "2.4G", "20M", "HT", "2T", "11", "30",
- "ETSI", "2.4G", "20M", "HT", "2T", "11", "32",
- "MKK", "2.4G", "20M", "HT", "2T", "11", "32",
- "FCC", "2.4G", "20M", "HT", "2T", "12", "63",
- "ETSI", "2.4G", "20M", "HT", "2T", "12", "32",
- "MKK", "2.4G", "20M", "HT", "2T", "12", "32",
- "FCC", "2.4G", "20M", "HT", "2T", "13", "63",
- "ETSI", "2.4G", "20M", "HT", "2T", "13", "32",
- "MKK", "2.4G", "20M", "HT", "2T", "13", "32",
- "FCC", "2.4G", "20M", "HT", "2T", "14", "63",
- "ETSI", "2.4G", "20M", "HT", "2T", "14", "63",
- "MKK", "2.4G", "20M", "HT", "2T", "14", "63",
- "FCC", "2.4G", "40M", "HT", "1T", "01", "63",
- "ETSI", "2.4G", "40M", "HT", "1T", "01", "63",
- "MKK", "2.4G", "40M", "HT", "1T", "01", "63",
- "FCC", "2.4G", "40M", "HT", "1T", "02", "63",
- "ETSI", "2.4G", "40M", "HT", "1T", "02", "63",
- "MKK", "2.4G", "40M", "HT", "1T", "02", "63",
- "FCC", "2.4G", "40M", "HT", "1T", "03", "26",
- "ETSI", "2.4G", "40M", "HT", "1T", "03", "32",
- "MKK", "2.4G", "40M", "HT", "1T", "03", "32",
- "FCC", "2.4G", "40M", "HT", "1T", "04", "26",
- "ETSI", "2.4G", "40M", "HT", "1T", "04", "32",
- "MKK", "2.4G", "40M", "HT", "1T", "04", "32",
- "FCC", "2.4G", "40M", "HT", "1T", "05", "32",
- "ETSI", "2.4G", "40M", "HT", "1T", "05", "32",
- "MKK", "2.4G", "40M", "HT", "1T", "05", "32",
- "FCC", "2.4G", "40M", "HT", "1T", "06", "32",
- "ETSI", "2.4G", "40M", "HT", "1T", "06", "32",
- "MKK", "2.4G", "40M", "HT", "1T", "06", "32",
- "FCC", "2.4G", "40M", "HT", "1T", "07", "32",
- "ETSI", "2.4G", "40M", "HT", "1T", "07", "32",
- "MKK", "2.4G", "40M", "HT", "1T", "07", "32",
- "FCC", "2.4G", "40M", "HT", "1T", "08", "26",
- "ETSI", "2.4G", "40M", "HT", "1T", "08", "32",
- "MKK", "2.4G", "40M", "HT", "1T", "08", "32",
- "FCC", "2.4G", "40M", "HT", "1T", "09", "26",
- "ETSI", "2.4G", "40M", "HT", "1T", "09", "32",
- "MKK", "2.4G", "40M", "HT", "1T", "09", "32",
- "FCC", "2.4G", "40M", "HT", "1T", "10", "26",
- "ETSI", "2.4G", "40M", "HT", "1T", "10", "32",
- "MKK", "2.4G", "40M", "HT", "1T", "10", "32",
- "FCC", "2.4G", "40M", "HT", "1T", "11", "26",
- "ETSI", "2.4G", "40M", "HT", "1T", "11", "32",
- "MKK", "2.4G", "40M", "HT", "1T", "11", "32",
- "FCC", "2.4G", "40M", "HT", "1T", "12", "63",
- "ETSI", "2.4G", "40M", "HT", "1T", "12", "32",
- "MKK", "2.4G", "40M", "HT", "1T", "12", "32",
- "FCC", "2.4G", "40M", "HT", "1T", "13", "63",
- "ETSI", "2.4G", "40M", "HT", "1T", "13", "32",
- "MKK", "2.4G", "40M", "HT", "1T", "13", "32",
- "FCC", "2.4G", "40M", "HT", "1T", "14", "63",
- "ETSI", "2.4G", "40M", "HT", "1T", "14", "63",
- "MKK", "2.4G", "40M", "HT", "1T", "14", "63",
- "FCC", "2.4G", "40M", "HT", "2T", "01", "63",
- "ETSI", "2.4G", "40M", "HT", "2T", "01", "63",
- "MKK", "2.4G", "40M", "HT", "2T", "01", "63",
- "FCC", "2.4G", "40M", "HT", "2T", "02", "63",
- "ETSI", "2.4G", "40M", "HT", "2T", "02", "63",
- "MKK", "2.4G", "40M", "HT", "2T", "02", "63",
- "FCC", "2.4G", "40M", "HT", "2T", "03", "30",
- "ETSI", "2.4G", "40M", "HT", "2T", "03", "30",
- "MKK", "2.4G", "40M", "HT", "2T", "03", "30",
- "FCC", "2.4G", "40M", "HT", "2T", "04", "32",
- "ETSI", "2.4G", "40M", "HT", "2T", "04", "30",
- "MKK", "2.4G", "40M", "HT", "2T", "04", "30",
- "FCC", "2.4G", "40M", "HT", "2T", "05", "32",
- "ETSI", "2.4G", "40M", "HT", "2T", "05", "30",
- "MKK", "2.4G", "40M", "HT", "2T", "05", "30",
- "FCC", "2.4G", "40M", "HT", "2T", "06", "32",
- "ETSI", "2.4G", "40M", "HT", "2T", "06", "30",
- "MKK", "2.4G", "40M", "HT", "2T", "06", "30",
- "FCC", "2.4G", "40M", "HT", "2T", "07", "32",
- "ETSI", "2.4G", "40M", "HT", "2T", "07", "30",
- "MKK", "2.4G", "40M", "HT", "2T", "07", "30",
- "FCC", "2.4G", "40M", "HT", "2T", "08", "32",
- "ETSI", "2.4G", "40M", "HT", "2T", "08", "30",
- "MKK", "2.4G", "40M", "HT", "2T", "08", "30",
- "FCC", "2.4G", "40M", "HT", "2T", "09", "32",
- "ETSI", "2.4G", "40M", "HT", "2T", "09", "30",
- "MKK", "2.4G", "40M", "HT", "2T", "09", "30",
- "FCC", "2.4G", "40M", "HT", "2T", "10", "32",
- "ETSI", "2.4G", "40M", "HT", "2T", "10", "30",
- "MKK", "2.4G", "40M", "HT", "2T", "10", "30",
- "FCC", "2.4G", "40M", "HT", "2T", "11", "30",
- "ETSI", "2.4G", "40M", "HT", "2T", "11", "30",
- "MKK", "2.4G", "40M", "HT", "2T", "11", "30",
- "FCC", "2.4G", "40M", "HT", "2T", "12", "63",
- "ETSI", "2.4G", "40M", "HT", "2T", "12", "32",
- "MKK", "2.4G", "40M", "HT", "2T", "12", "32",
- "FCC", "2.4G", "40M", "HT", "2T", "13", "63",
- "ETSI", "2.4G", "40M", "HT", "2T", "13", "32",
- "MKK", "2.4G", "40M", "HT", "2T", "13", "32",
- "FCC", "2.4G", "40M", "HT", "2T", "14", "63",
- "ETSI", "2.4G", "40M", "HT", "2T", "14", "63",
- "MKK", "2.4G", "40M", "HT", "2T", "14", "63"
+ "FCC", "20M", "CCK", "1T", "01", "32",
+ "ETSI", "20M", "CCK", "1T", "01", "32",
+ "MKK", "20M", "CCK", "1T", "01", "32",
+ "FCC", "20M", "CCK", "1T", "02", "32",
+ "ETSI", "20M", "CCK", "1T", "02", "32",
+ "MKK", "20M", "CCK", "1T", "02", "32",
+ "FCC", "20M", "CCK", "1T", "03", "32",
+ "ETSI", "20M", "CCK", "1T", "03", "32",
+ "MKK", "20M", "CCK", "1T", "03", "32",
+ "FCC", "20M", "CCK", "1T", "04", "32",
+ "ETSI", "20M", "CCK", "1T", "04", "32",
+ "MKK", "20M", "CCK", "1T", "04", "32",
+ "FCC", "20M", "CCK", "1T", "05", "32",
+ "ETSI", "20M", "CCK", "1T", "05", "32",
+ "MKK", "20M", "CCK", "1T", "05", "32",
+ "FCC", "20M", "CCK", "1T", "06", "32",
+ "ETSI", "20M", "CCK", "1T", "06", "32",
+ "MKK", "20M", "CCK", "1T", "06", "32",
+ "FCC", "20M", "CCK", "1T", "07", "32",
+ "ETSI", "20M", "CCK", "1T", "07", "32",
+ "MKK", "20M", "CCK", "1T", "07", "32",
+ "FCC", "20M", "CCK", "1T", "08", "32",
+ "ETSI", "20M", "CCK", "1T", "08", "32",
+ "MKK", "20M", "CCK", "1T", "08", "32",
+ "FCC", "20M", "CCK", "1T", "09", "32",
+ "ETSI", "20M", "CCK", "1T", "09", "32",
+ "MKK", "20M", "CCK", "1T", "09", "32",
+ "FCC", "20M", "CCK", "1T", "10", "32",
+ "ETSI", "20M", "CCK", "1T", "10", "32",
+ "MKK", "20M", "CCK", "1T", "10", "32",
+ "FCC", "20M", "CCK", "1T", "11", "32",
+ "ETSI", "20M", "CCK", "1T", "11", "32",
+ "MKK", "20M", "CCK", "1T", "11", "32",
+ "FCC", "20M", "CCK", "1T", "12", "63",
+ "ETSI", "20M", "CCK", "1T", "12", "32",
+ "MKK", "20M", "CCK", "1T", "12", "32",
+ "FCC", "20M", "CCK", "1T", "13", "63",
+ "ETSI", "20M", "CCK", "1T", "13", "32",
+ "MKK", "20M", "CCK", "1T", "13", "32",
+ "FCC", "20M", "CCK", "1T", "14", "63",
+ "ETSI", "20M", "CCK", "1T", "14", "63",
+ "MKK", "20M", "CCK", "1T", "14", "32",
+ "FCC", "20M", "OFDM", "1T", "01", "28",
+ "ETSI", "20M", "OFDM", "1T", "01", "32",
+ "MKK", "20M", "OFDM", "1T", "01", "32",
+ "FCC", "20M", "OFDM", "1T", "02", "28",
+ "ETSI", "20M", "OFDM", "1T", "02", "32",
+ "MKK", "20M", "OFDM", "1T", "02", "32",
+ "FCC", "20M", "OFDM", "1T", "03", "32",
+ "ETSI", "20M", "OFDM", "1T", "03", "32",
+ "MKK", "20M", "OFDM", "1T", "03", "32",
+ "FCC", "20M", "OFDM", "1T", "04", "32",
+ "ETSI", "20M", "OFDM", "1T", "04", "32",
+ "MKK", "20M", "OFDM", "1T", "04", "32",
+ "FCC", "20M", "OFDM", "1T", "05", "32",
+ "ETSI", "20M", "OFDM", "1T", "05", "32",
+ "MKK", "20M", "OFDM", "1T", "05", "32",
+ "FCC", "20M", "OFDM", "1T", "06", "32",
+ "ETSI", "20M", "OFDM", "1T", "06", "32",
+ "MKK", "20M", "OFDM", "1T", "06", "32",
+ "FCC", "20M", "OFDM", "1T", "07", "32",
+ "ETSI", "20M", "OFDM", "1T", "07", "32",
+ "MKK", "20M", "OFDM", "1T", "07", "32",
+ "FCC", "20M", "OFDM", "1T", "08", "32",
+ "ETSI", "20M", "OFDM", "1T", "08", "32",
+ "MKK", "20M", "OFDM", "1T", "08", "32",
+ "FCC", "20M", "OFDM", "1T", "09", "32",
+ "ETSI", "20M", "OFDM", "1T", "09", "32",
+ "MKK", "20M", "OFDM", "1T", "09", "32",
+ "FCC", "20M", "OFDM", "1T", "10", "28",
+ "ETSI", "20M", "OFDM", "1T", "10", "32",
+ "MKK", "20M", "OFDM", "1T", "10", "32",
+ "FCC", "20M", "OFDM", "1T", "11", "28",
+ "ETSI", "20M", "OFDM", "1T", "11", "32",
+ "MKK", "20M", "OFDM", "1T", "11", "32",
+ "FCC", "20M", "OFDM", "1T", "12", "63",
+ "ETSI", "20M", "OFDM", "1T", "12", "32",
+ "MKK", "20M", "OFDM", "1T", "12", "32",
+ "FCC", "20M", "OFDM", "1T", "13", "63",
+ "ETSI", "20M", "OFDM", "1T", "13", "32",
+ "MKK", "20M", "OFDM", "1T", "13", "32",
+ "FCC", "20M", "OFDM", "1T", "14", "63",
+ "ETSI", "20M", "OFDM", "1T", "14", "63",
+ "MKK", "20M", "OFDM", "1T", "14", "63",
+ "FCC", "20M", "HT", "1T", "01", "26",
+ "ETSI", "20M", "HT", "1T", "01", "32",
+ "MKK", "20M", "HT", "1T", "01", "32",
+ "FCC", "20M", "HT", "1T", "02", "26",
+ "ETSI", "20M", "HT", "1T", "02", "32",
+ "MKK", "20M", "HT", "1T", "02", "32",
+ "FCC", "20M", "HT", "1T", "03", "32",
+ "ETSI", "20M", "HT", "1T", "03", "32",
+ "MKK", "20M", "HT", "1T", "03", "32",
+ "FCC", "20M", "HT", "1T", "04", "32",
+ "ETSI", "20M", "HT", "1T", "04", "32",
+ "MKK", "20M", "HT", "1T", "04", "32",
+ "FCC", "20M", "HT", "1T", "05", "32",
+ "ETSI", "20M", "HT", "1T", "05", "32",
+ "MKK", "20M", "HT", "1T", "05", "32",
+ "FCC", "20M", "HT", "1T", "06", "32",
+ "ETSI", "20M", "HT", "1T", "06", "32",
+ "MKK", "20M", "HT", "1T", "06", "32",
+ "FCC", "20M", "HT", "1T", "07", "32",
+ "ETSI", "20M", "HT", "1T", "07", "32",
+ "MKK", "20M", "HT", "1T", "07", "32",
+ "FCC", "20M", "HT", "1T", "08", "32",
+ "ETSI", "20M", "HT", "1T", "08", "32",
+ "MKK", "20M", "HT", "1T", "08", "32",
+ "FCC", "20M", "HT", "1T", "09", "32",
+ "ETSI", "20M", "HT", "1T", "09", "32",
+ "MKK", "20M", "HT", "1T", "09", "32",
+ "FCC", "20M", "HT", "1T", "10", "26",
+ "ETSI", "20M", "HT", "1T", "10", "32",
+ "MKK", "20M", "HT", "1T", "10", "32",
+ "FCC", "20M", "HT", "1T", "11", "26",
+ "ETSI", "20M", "HT", "1T", "11", "32",
+ "MKK", "20M", "HT", "1T", "11", "32",
+ "FCC", "20M", "HT", "1T", "12", "63",
+ "ETSI", "20M", "HT", "1T", "12", "32",
+ "MKK", "20M", "HT", "1T", "12", "32",
+ "FCC", "20M", "HT", "1T", "13", "63",
+ "ETSI", "20M", "HT", "1T", "13", "32",
+ "MKK", "20M", "HT", "1T", "13", "32",
+ "FCC", "20M", "HT", "1T", "14", "63",
+ "ETSI", "20M", "HT", "1T", "14", "63",
+ "MKK", "20M", "HT", "1T", "14", "63",
+ "FCC", "20M", "HT", "2T", "01", "30",
+ "ETSI", "20M", "HT", "2T", "01", "32",
+ "MKK", "20M", "HT", "2T", "01", "32",
+ "FCC", "20M", "HT", "2T", "02", "32",
+ "ETSI", "20M", "HT", "2T", "02", "32",
+ "MKK", "20M", "HT", "2T", "02", "32",
+ "FCC", "20M", "HT", "2T", "03", "32",
+ "ETSI", "20M", "HT", "2T", "03", "32",
+ "MKK", "20M", "HT", "2T", "03", "32",
+ "FCC", "20M", "HT", "2T", "04", "32",
+ "ETSI", "20M", "HT", "2T", "04", "32",
+ "MKK", "20M", "HT", "2T", "04", "32",
+ "FCC", "20M", "HT", "2T", "05", "32",
+ "ETSI", "20M", "HT", "2T", "05", "32",
+ "MKK", "20M", "HT", "2T", "05", "32",
+ "FCC", "20M", "HT", "2T", "06", "32",
+ "ETSI", "20M", "HT", "2T", "06", "32",
+ "MKK", "20M", "HT", "2T", "06", "32",
+ "FCC", "20M", "HT", "2T", "07", "32",
+ "ETSI", "20M", "HT", "2T", "07", "32",
+ "MKK", "20M", "HT", "2T", "07", "32",
+ "FCC", "20M", "HT", "2T", "08", "32",
+ "ETSI", "20M", "HT", "2T", "08", "32",
+ "MKK", "20M", "HT", "2T", "08", "32",
+ "FCC", "20M", "HT", "2T", "09", "32",
+ "ETSI", "20M", "HT", "2T", "09", "32",
+ "MKK", "20M", "HT", "2T", "09", "32",
+ "FCC", "20M", "HT", "2T", "10", "32",
+ "ETSI", "20M", "HT", "2T", "10", "32",
+ "MKK", "20M", "HT", "2T", "10", "32",
+ "FCC", "20M", "HT", "2T", "11", "30",
+ "ETSI", "20M", "HT", "2T", "11", "32",
+ "MKK", "20M", "HT", "2T", "11", "32",
+ "FCC", "20M", "HT", "2T", "12", "63",
+ "ETSI", "20M", "HT", "2T", "12", "32",
+ "MKK", "20M", "HT", "2T", "12", "32",
+ "FCC", "20M", "HT", "2T", "13", "63",
+ "ETSI", "20M", "HT", "2T", "13", "32",
+ "MKK", "20M", "HT", "2T", "13", "32",
+ "FCC", "20M", "HT", "2T", "14", "63",
+ "ETSI", "20M", "HT", "2T", "14", "63",
+ "MKK", "20M", "HT", "2T", "14", "63",
+ "FCC", "40M", "HT", "1T", "01", "63",
+ "ETSI", "40M", "HT", "1T", "01", "63",
+ "MKK", "40M", "HT", "1T", "01", "63",
+ "FCC", "40M", "HT", "1T", "02", "63",
+ "ETSI", "40M", "HT", "1T", "02", "63",
+ "MKK", "40M", "HT", "1T", "02", "63",
+ "FCC", "40M", "HT", "1T", "03", "26",
+ "ETSI", "40M", "HT", "1T", "03", "32",
+ "MKK", "40M", "HT", "1T", "03", "32",
+ "FCC", "40M", "HT", "1T", "04", "26",
+ "ETSI", "40M", "HT", "1T", "04", "32",
+ "MKK", "40M", "HT", "1T", "04", "32",
+ "FCC", "40M", "HT", "1T", "05", "32",
+ "ETSI", "40M", "HT", "1T", "05", "32",
+ "MKK", "40M", "HT", "1T", "05", "32",
+ "FCC", "40M", "HT", "1T", "06", "32",
+ "ETSI", "40M", "HT", "1T", "06", "32",
+ "MKK", "40M", "HT", "1T", "06", "32",
+ "FCC", "40M", "HT", "1T", "07", "32",
+ "ETSI", "40M", "HT", "1T", "07", "32",
+ "MKK", "40M", "HT", "1T", "07", "32",
+ "FCC", "40M", "HT", "1T", "08", "26",
+ "ETSI", "40M", "HT", "1T", "08", "32",
+ "MKK", "40M", "HT", "1T", "08", "32",
+ "FCC", "40M", "HT", "1T", "09", "26",
+ "ETSI", "40M", "HT", "1T", "09", "32",
+ "MKK", "40M", "HT", "1T", "09", "32",
+ "FCC", "40M", "HT", "1T", "10", "26",
+ "ETSI", "40M", "HT", "1T", "10", "32",
+ "MKK", "40M", "HT", "1T", "10", "32",
+ "FCC", "40M", "HT", "1T", "11", "26",
+ "ETSI", "40M", "HT", "1T", "11", "32",
+ "MKK", "40M", "HT", "1T", "11", "32",
+ "FCC", "40M", "HT", "1T", "12", "63",
+ "ETSI", "40M", "HT", "1T", "12", "32",
+ "MKK", "40M", "HT", "1T", "12", "32",
+ "FCC", "40M", "HT", "1T", "13", "63",
+ "ETSI", "40M", "HT", "1T", "13", "32",
+ "MKK", "40M", "HT", "1T", "13", "32",
+ "FCC", "40M", "HT", "1T", "14", "63",
+ "ETSI", "40M", "HT", "1T", "14", "63",
+ "MKK", "40M", "HT", "1T", "14", "63",
+ "FCC", "40M", "HT", "2T", "01", "63",
+ "ETSI", "40M", "HT", "2T", "01", "63",
+ "MKK", "40M", "HT", "2T", "01", "63",
+ "FCC", "40M", "HT", "2T", "02", "63",
+ "ETSI", "40M", "HT", "2T", "02", "63",
+ "MKK", "40M", "HT", "2T", "02", "63",
+ "FCC", "40M", "HT", "2T", "03", "30",
+ "ETSI", "40M", "HT", "2T", "03", "30",
+ "MKK", "40M", "HT", "2T", "03", "30",
+ "FCC", "40M", "HT", "2T", "04", "32",
+ "ETSI", "40M", "HT", "2T", "04", "30",
+ "MKK", "40M", "HT", "2T", "04", "30",
+ "FCC", "40M", "HT", "2T", "05", "32",
+ "ETSI", "40M", "HT", "2T", "05", "30",
+ "MKK", "40M", "HT", "2T", "05", "30",
+ "FCC", "40M", "HT", "2T", "06", "32",
+ "ETSI", "40M", "HT", "2T", "06", "30",
+ "MKK", "40M", "HT", "2T", "06", "30",
+ "FCC", "40M", "HT", "2T", "07", "32",
+ "ETSI", "40M", "HT", "2T", "07", "30",
+ "MKK", "40M", "HT", "2T", "07", "30",
+ "FCC", "40M", "HT", "2T", "08", "32",
+ "ETSI", "40M", "HT", "2T", "08", "30",
+ "MKK", "40M", "HT", "2T", "08", "30",
+ "FCC", "40M", "HT", "2T", "09", "32",
+ "ETSI", "40M", "HT", "2T", "09", "30",
+ "MKK", "40M", "HT", "2T", "09", "30",
+ "FCC", "40M", "HT", "2T", "10", "32",
+ "ETSI", "40M", "HT", "2T", "10", "30",
+ "MKK", "40M", "HT", "2T", "10", "30",
+ "FCC", "40M", "HT", "2T", "11", "30",
+ "ETSI", "40M", "HT", "2T", "11", "30",
+ "MKK", "40M", "HT", "2T", "11", "30",
+ "FCC", "40M", "HT", "2T", "12", "63",
+ "ETSI", "40M", "HT", "2T", "12", "32",
+ "MKK", "40M", "HT", "2T", "12", "32",
+ "FCC", "40M", "HT", "2T", "13", "63",
+ "ETSI", "40M", "HT", "2T", "13", "32",
+ "MKK", "40M", "HT", "2T", "13", "32",
+ "FCC", "40M", "HT", "2T", "14", "63",
+ "ETSI", "40M", "HT", "2T", "14", "63",
+ "MKK", "40M", "HT", "2T", "14", "63"
};
void ODM_ReadAndConfig_MP_8723B_TXPWR_LMT(struct dm_odm_t *pDM_Odm)
@@ -760,26 +627,17 @@ void ODM_ReadAndConfig_MP_8723B_TXPWR_LMT(struct dm_odm_t *pDM_Odm)
u32 i = 0;
u8 **Array = Array_MP_8723B_TXPWR_LMT;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_LOUD,
- ("===> ODM_ReadAndConfig_MP_8723B_TXPWR_LMT\n")
- );
-
- for (i = 0; i < ARRAY_SIZE(Array_MP_8723B_TXPWR_LMT); i += 7) {
+ for (i = 0; i < ARRAY_SIZE(Array_MP_8723B_TXPWR_LMT); i += 6) {
u8 *regulation = Array[i];
- u8 *band = Array[i+1];
- u8 *bandwidth = Array[i+2];
- u8 *rate = Array[i+3];
- u8 *rfPath = Array[i+4];
- u8 *chnl = Array[i+5];
- u8 *val = Array[i+6];
+ u8 *bandwidth = Array[i+1];
+ u8 *rate = Array[i+2];
+ u8 *rfPath = Array[i+3];
+ u8 *chnl = Array[i+4];
+ u8 *val = Array[i+5];
odm_ConfigBB_TXPWR_LMT_8723B(
pDM_Odm,
regulation,
- band,
bandwidth,
rate,
rfPath,
diff --git a/drivers/staging/rtl8723bs/hal/HalPhyRf.c b/drivers/staging/rtl8723bs/hal/HalPhyRf.c
index 14426151faae..365e1195b5e5 100644
--- a/drivers/staging/rtl8723bs/hal/HalPhyRf.c
+++ b/drivers/staging/rtl8723bs/hal/HalPhyRf.c
@@ -76,7 +76,7 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
- u8 ThermalValue = 0, delta, delta_LCK, delta_IQK, p = 0, i = 0;
+ u8 ThermalValue = 0, delta, delta_LCK, p = 0, i = 0;
u8 ThermalValue_AVG_count = 0;
u32 ThermalValue_AVG = 0;
@@ -108,18 +108,6 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
pDM_Odm->RFCalibrateInfo.TXPowerTrackingCallbackCnt++;
pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = true;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "===>ODM_TXPowerTrackingCallback_ThermalMeter,\npDM_Odm->BbSwingIdxCckBase: %d, pDM_Odm->BbSwingIdxOfdmBase[A]: %d, pDM_Odm->DefaultOfdmIndex: %d\n",
- pDM_Odm->BbSwingIdxCckBase,
- pDM_Odm->BbSwingIdxOfdmBase[ODM_RF_PATH_A],
- pDM_Odm->DefaultOfdmIndex
- )
- );
-
ThermalValue = (u8)PHY_QueryRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, c.ThermalRegAddr, 0xfc00); /* 0x42: RF Reg[15:10] 88E */
if (
!pDM_Odm->RFCalibrateInfo.TxPowerTrackControl ||
@@ -130,13 +118,6 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
/* 4 3. Initialize ThermalValues of RFCalibrateInfo */
- if (pDM_Odm->RFCalibrateInfo.bReloadtxpowerindex)
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
- ("reload ofdm index for band switch\n")
- );
-
/* 4 4. Calculate average thermal meter */
pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index] = ThermalValue;
@@ -154,19 +135,9 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
/* Calculate Average ThermalValue after average enough times */
if (ThermalValue_AVG_count) {
ThermalValue = (u8)(ThermalValue_AVG / ThermalValue_AVG_count);
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "AVG Thermal Meter = 0x%X, EFUSE Thermal Base = 0x%X\n",
- ThermalValue,
- pHalData->EEPROMThermalMeter
- )
- );
}
- /* 4 5. Calculate delta, delta_LCK, delta_IQK. */
+ /* 4 5. Calculate delta, delta_LCK */
/* delta" here is used to determine whether thermal value changes or not. */
delta =
(ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue) ?
@@ -176,36 +147,10 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
(ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue_LCK) ?
(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue_LCK) :
(pDM_Odm->RFCalibrateInfo.ThermalValue_LCK - ThermalValue);
- delta_IQK =
- (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue_IQK) ?
- (ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue_IQK) :
- (pDM_Odm->RFCalibrateInfo.ThermalValue_IQK - ThermalValue);
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "(delta, delta_LCK, delta_IQK) = (%d, %d, %d)\n",
- delta,
- delta_LCK,
- delta_IQK
- )
- );
/* 4 6. If necessary, do LCK. */
/* Delta temperature is equal to or larger than 20 centigrade. */
if (delta_LCK >= c.Threshold_IQK) {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "delta_LCK(%d) >= Threshold_IQK(%d)\n",
- delta_LCK,
- c.Threshold_IQK
- )
- );
pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue;
if (c.PHY_LCCalibrate)
(*c.PHY_LCCalibrate)(pDM_Odm);
@@ -224,16 +169,6 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
/* 4 7.1 The Final Power Index = BaseIndex + PowerIndexOffset */
if (ThermalValue > pHalData->EEPROMThermalMeter) {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "deltaSwingTableIdx_TUP_A[%d] = %d\n",
- delta,
- deltaSwingTableIdx_TUP_A[delta]
- )
- );
pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_A] =
pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A];
pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A] =
@@ -243,27 +178,7 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] =
deltaSwingTableIdx_TUP_A[delta];
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "******Temp is higher and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
- pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A]
- )
- );
-
if (c.RfPathCount > 1) {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "deltaSwingTableIdx_TUP_B[%d] = %d\n",
- delta,
- deltaSwingTableIdx_TUP_B[delta]
- )
- );
pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_B] =
pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B];
pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B] =
@@ -272,29 +187,9 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
/* Record delta swing for mix mode power tracking */
pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] =
deltaSwingTableIdx_TUP_B[delta];
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "******Temp is higher and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n",
- pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B]
- )
- );
}
} else {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "deltaSwingTableIdx_TDOWN_A[%d] = %d\n",
- delta,
- deltaSwingTableIdx_TDOWN_A[delta]
- )
- );
-
pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_A] =
pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A];
pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A] =
@@ -304,28 +199,7 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] =
-1 * deltaSwingTableIdx_TDOWN_A[delta];
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "******Temp is lower and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
- pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A]
- )
- );
-
if (c.RfPathCount > 1) {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "deltaSwingTableIdx_TDOWN_B[%d] = %d\n",
- delta,
- deltaSwingTableIdx_TDOWN_B[delta]
- )
- );
-
pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_B] =
pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B];
pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B] =
@@ -334,30 +208,10 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
/* Record delta swing for mix mode power tracking */
pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] =
-1 * deltaSwingTableIdx_TDOWN_B[delta];
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "******Temp is lower and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n",
- pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B]
- )
- );
}
}
for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "\n\n ================================ [Path-%c] Calculating PowerIndexOffset ================================\n",
- (p == ODM_RF_PATH_A ? 'A' : 'B')
- )
- );
-
if (
pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] ==
pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p]
@@ -366,20 +220,6 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
else
pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] - pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p]; /* Power Index Diff between 2 times Power Tracking */
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "[Path-%c] PowerIndexOffset(%d) = DeltaPowerIndex(%d) - DeltaPowerIndexLast(%d)\n",
- (
- p == ODM_RF_PATH_A ? 'A' : 'B'),
- pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p],
- pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p],
- pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p]
- )
- );
-
pDM_Odm->RFCalibrateInfo.OFDM_index[p] =
pDM_Odm->BbSwingIdxOfdmBase[p] +
pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p];
@@ -394,87 +234,23 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
pDM_Odm->BbSwingIdxOfdm[p] =
pDM_Odm->RFCalibrateInfo.OFDM_index[p];
- /* *************Print BB Swing Base and Index Offset************* */
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "The 'CCK' final index(%d) = BaseIndex(%d) + PowerIndexOffset(%d)\n",
- pDM_Odm->BbSwingIdxCck,
- pDM_Odm->BbSwingIdxCckBase,
- pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p]
- )
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "The 'OFDM' final index(%d) = BaseIndex[%c](%d) + PowerIndexOffset(%d)\n",
- pDM_Odm->BbSwingIdxOfdm[p],
- (p == ODM_RF_PATH_A ? 'A' : 'B'),
- pDM_Odm->BbSwingIdxOfdmBase[p],
- pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p]
- )
- );
-
/* 4 7.1 Handle boundary conditions of index. */
if (pDM_Odm->RFCalibrateInfo.OFDM_index[p] > c.SwingTableSize_OFDM-1)
pDM_Odm->RFCalibrateInfo.OFDM_index[p] = c.SwingTableSize_OFDM-1;
else if (pDM_Odm->RFCalibrateInfo.OFDM_index[p] < OFDM_min_index)
pDM_Odm->RFCalibrateInfo.OFDM_index[p] = OFDM_min_index;
}
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- ("\n\n ========================================================================================================\n")
- );
if (pDM_Odm->RFCalibrateInfo.CCK_index > c.SwingTableSize_CCK-1)
pDM_Odm->RFCalibrateInfo.CCK_index = c.SwingTableSize_CCK-1;
/* else if (pDM_Odm->RFCalibrateInfo.CCK_index < 0) */
/* pDM_Odm->RFCalibrateInfo.CCK_index = 0; */
} else {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "The thermal meter is unchanged or TxPowerTracking OFF(%d): ThermalValue: %d , pDM_Odm->RFCalibrateInfo.ThermalValue: %d\n",
- pDM_Odm->RFCalibrateInfo.TxPowerTrackControl,
- ThermalValue,
- pDM_Odm->RFCalibrateInfo.ThermalValue
- )
- );
-
for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++)
pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0;
}
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "TxPowerTracking: [CCK] Swing Current Index: %d, Swing Base Index: %d\n",
- pDM_Odm->RFCalibrateInfo.CCK_index,
- pDM_Odm->BbSwingIdxCckBase
- )
- );
/* Print Swing base & current */
for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "TxPowerTracking: [OFDM] Swing Current Index: %d, Swing Base Index[%c]: %d\n",
- pDM_Odm->RFCalibrateInfo.OFDM_index[p],
- (p == ODM_RF_PATH_A ? 'A' : 'B'),
- pDM_Odm->BbSwingIdxOfdmBase[p]
- )
- );
}
if (
@@ -490,106 +266,11 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
/* to increase TX power. Otherwise, EVM will be bad. */
/* */
/* 2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. */
- if (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue) {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "Temperature Increasing(A): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
- pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_A],
- delta,
- ThermalValue,
- pHalData->EEPROMThermalMeter,
- pDM_Odm->RFCalibrateInfo.ThermalValue
- )
- );
-
- if (c.RfPathCount > 1)
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "Temperature Increasing(B): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
- pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_B],
- delta,
- ThermalValue,
- pHalData->EEPROMThermalMeter,
- pDM_Odm->RFCalibrateInfo.ThermalValue
- )
- );
-
- } else if (ThermalValue < pDM_Odm->RFCalibrateInfo.ThermalValue) { /* Low temperature */
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "Temperature Decreasing(A): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
- pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_A],
- delta,
- ThermalValue,
- pHalData->EEPROMThermalMeter,
- pDM_Odm->RFCalibrateInfo.ThermalValue
- )
- );
-
- if (c.RfPathCount > 1)
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "Temperature Decreasing(B): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
- pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_B],
- delta,
- ThermalValue,
- pHalData->EEPROMThermalMeter,
- pDM_Odm->RFCalibrateInfo.ThermalValue
- )
- );
-
- }
if (ThermalValue > pHalData->EEPROMThermalMeter) {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "Temperature(%d) higher than PG value(%d)\n",
- ThermalValue,
- pHalData->EEPROMThermalMeter
- )
- );
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- ("**********Enter POWER Tracking MIX_MODE**********\n")
- );
for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++)
(*c.ODM_TxPwrTrackSetPwr)(pDM_Odm, MIX_MODE, p, 0);
} else {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- (
- "Temperature(%d) lower than PG value(%d)\n",
- ThermalValue,
- pHalData->EEPROMThermalMeter
- )
- );
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- ("**********Enter POWER Tracking MIX_MODE**********\n")
- );
for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++)
(*c.ODM_TxPwrTrackSetPwr)(pDM_Odm, MIX_MODE, p, Indexforchannel);
}
@@ -599,26 +280,9 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++)
pDM_Odm->BbSwingIdxOfdmBase[p] = pDM_Odm->BbSwingIdxOfdm[p];
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
- (
- "pDM_Odm->RFCalibrateInfo.ThermalValue = %d ThermalValue = %d\n",
- pDM_Odm->RFCalibrateInfo.ThermalValue,
- ThermalValue
- )
- );
-
/* Record last Power Tracking Thermal Value */
pDM_Odm->RFCalibrateInfo.ThermalValue = ThermalValue;
}
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_TX_PWR_TRACK,
- ODM_DBG_LOUD,
- ("<===ODM_TXPowerTrackingCallback_ThermalMeter\n")
- );
-
pDM_Odm->RFCalibrateInfo.TXPowercount = 0;
}
diff --git a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c
index c70b9cf2da32..8121b8eb45b6 100644
--- a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c
+++ b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c
@@ -69,7 +69,7 @@ static void setIqkMatrix_8723B(
ele_D = (OFDMSwingTable_New[OFDM_index] & 0xFFC00000)>>22;
/* new element A = element D x X */
- if ((IqkResult_X != 0) && (*(pDM_Odm->pBandType) == ODM_BAND_2_4G)) {
+ if (IqkResult_X != 0) {
if ((IqkResult_X & 0x00000200) != 0) /* consider minus */
IqkResult_X = IqkResult_X | 0xFFFFFC00;
ele_A = ((IqkResult_X * ele_D)>>8)&0x000003FF;
@@ -129,9 +129,6 @@ static void setIqkMatrix_8723B(
break;
}
}
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("TxPwrTracking path B: X = 0x%x, Y = 0x%x ele_A = 0x%x ele_C = 0x%x ele_D = 0x%x 0xeb4 = 0x%x 0xebc = 0x%x\n",
- (u32)IqkResult_X, (u32)IqkResult_Y, (u32)ele_A, (u32)ele_C, (u32)ele_D, (u32)IqkResult_X, (u32)IqkResult_Y));
}
@@ -210,8 +207,6 @@ void ODM_TxPwrTrackSetPwr_8723B(
}
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("===>ODM_TxPwrTrackSetPwr8723B\n"));
-
if (TxRate != 0xFF) {
/* 2 CCK */
if ((TxRate >= MGN_1M) && (TxRate <= MGN_11M))
@@ -233,13 +228,10 @@ void ODM_TxPwrTrackSetPwr_8723B(
else
PwrTrackingLimit_OFDM = pDM_Odm->DefaultOfdmIndex; /* Default OFDM index = 30 */
}
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("TxRate = 0x%x, PwrTrackingLimit =%d\n", TxRate, PwrTrackingLimit_OFDM));
if (Method == TXAGC) {
struct adapter *Adapter = pDM_Odm->Adapter;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("odm_TxPwrTrackSetPwr8723B CH =%d\n", *(pDM_Odm->pChannel)));
-
pDM_Odm->Remnant_OFDMSwingIdx[RFPath] = pDM_Odm->Absolute_OFDMSwingIdx[RFPath];
pDM_Odm->Modify_TxAGC_Flag_PathA = true;
@@ -270,10 +262,6 @@ void ODM_TxPwrTrackSetPwr_8723B(
setCCKFilterCoefficient(pDM_Odm, Final_CCK_Swing_Index);
} else if (Method == MIX_MODE) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
- ("pDM_Odm->DefaultOfdmIndex =%d, pDM_Odm->DefaultCCKIndex =%d, pDM_Odm->Absolute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n",
- pDM_Odm->DefaultOfdmIndex, pDM_Odm->DefaultCckIndex, pDM_Odm->Absolute_OFDMSwingIdx[RFPath], RFPath));
-
Final_OFDM_Swing_Index = pDM_Odm->DefaultOfdmIndex + pDM_Odm->Absolute_OFDMSwingIdx[RFPath];
Final_CCK_Swing_Index = pDM_Odm->DefaultCckIndex + pDM_Odm->Absolute_OFDMSwingIdx[RFPath];
@@ -287,10 +275,6 @@ void ODM_TxPwrTrackSetPwr_8723B(
pDM_Odm->Modify_TxAGC_Flag_PathA = true;
PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, OFDM);
PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, HT_MCS0_MCS7);
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
- ("******Path_A Over BBSwing Limit , PwrTrackingLimit = %d , Remnant TxAGC Value = %d\n",
- PwrTrackingLimit_OFDM, pDM_Odm->Remnant_OFDMSwingIdx[RFPath]));
} else if (Final_OFDM_Swing_Index <= 0) {
pDM_Odm->Remnant_OFDMSwingIdx[RFPath] = Final_OFDM_Swing_Index;
@@ -301,26 +285,16 @@ void ODM_TxPwrTrackSetPwr_8723B(
pDM_Odm->Modify_TxAGC_Flag_PathA = true;
PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, OFDM);
PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, HT_MCS0_MCS7);
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
- ("******Path_A Lower then BBSwing lower bound 0 , Remnant TxAGC Value = %d\n",
- pDM_Odm->Remnant_OFDMSwingIdx[RFPath]));
} else {
setIqkMatrix_8723B(pDM_Odm, Final_OFDM_Swing_Index, RFPath,
pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][0],
pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][1]);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
- ("******Path_A Compensate with BBSwing , Final_OFDM_Swing_Index = %d\n", Final_OFDM_Swing_Index));
-
if (pDM_Odm->Modify_TxAGC_Flag_PathA) { /* If TxAGC has changed, reset TxAGC again */
pDM_Odm->Remnant_OFDMSwingIdx[RFPath] = 0;
PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, OFDM);
PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, HT_MCS0_MCS7);
pDM_Odm->Modify_TxAGC_Flag_PathA = false;
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
- ("******Path_A pDM_Odm->Modify_TxAGC_Flag = false\n"));
}
}
@@ -329,30 +303,18 @@ void ODM_TxPwrTrackSetPwr_8723B(
setCCKFilterCoefficient(pDM_Odm, PwrTrackingLimit_CCK);
pDM_Odm->Modify_TxAGC_Flag_PathA_CCK = true;
PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, CCK);
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
- ("******Path_A CCK Over Limit , PwrTrackingLimit_CCK = %d , pDM_Odm->Remnant_CCKSwingIdx = %d\n", PwrTrackingLimit_CCK, pDM_Odm->Remnant_CCKSwingIdx));
} else if (Final_CCK_Swing_Index <= 0) { /* Lowest CCK Index = 0 */
pDM_Odm->Remnant_CCKSwingIdx = Final_CCK_Swing_Index;
setCCKFilterCoefficient(pDM_Odm, 0);
pDM_Odm->Modify_TxAGC_Flag_PathA_CCK = true;
PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, CCK);
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
- ("******Path_A CCK Under Limit , PwrTrackingLimit_CCK = %d , pDM_Odm->Remnant_CCKSwingIdx = %d\n", 0, pDM_Odm->Remnant_CCKSwingIdx));
} else {
setCCKFilterCoefficient(pDM_Odm, Final_CCK_Swing_Index);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
- ("******Path_A CCK Compensate with BBSwing , Final_CCK_Swing_Index = %d\n", Final_CCK_Swing_Index));
-
if (pDM_Odm->Modify_TxAGC_Flag_PathA_CCK) { /* If TxAGC has changed, reset TxAGC again */
pDM_Odm->Remnant_CCKSwingIdx = 0;
PHY_SetTxPowerIndexByRateSection(Adapter, RFPath, pHalData->CurrentChannel, CCK);
pDM_Odm->Modify_TxAGC_Flag_PathA_CCK = false;
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
- ("******Path_A pDM_Odm->Modify_TxAGC_Flag_CCK = false\n"));
}
}
} else
@@ -385,22 +347,7 @@ static void GetDeltaSwingTable_8723B(
*TemperatureUP_B = pRFCalibrateInfo->DeltaSwingTableIdx_2GB_P;
*TemperatureDOWN_B = pRFCalibrateInfo->DeltaSwingTableIdx_2GB_N;
}
- } /*else if (36 <= channel && channel <= 64) {
- *TemperatureUP_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[0];
- *TemperatureDOWN_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[0];
- *TemperatureUP_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[0];
- *TemperatureDOWN_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[0];
- } else if (100 <= channel && channel <= 140) {
- *TemperatureUP_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[1];
- *TemperatureDOWN_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[1];
- *TemperatureUP_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[1];
- *TemperatureDOWN_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[1];
- } else if (149 <= channel && channel <= 173) {
- *TemperatureUP_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[2];
- *TemperatureDOWN_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[2];
- *TemperatureUP_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[2];
- *TemperatureDOWN_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[2];
- }*/else {
+ } else {
*TemperatureUP_A = (u8 *)DeltaSwingTableIdx_2GA_P_8188E;
*TemperatureDOWN_A = (u8 *)DeltaSwingTableIdx_2GA_N_8188E;
*TemperatureUP_B = (u8 *)DeltaSwingTableIdx_2GA_P_8188E;
@@ -442,8 +389,6 @@ static u8 phy_PathA_IQK_8723B(
/* Save RF Path */
Path_SEL_BB = PHY_QueryBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQK!\n"));
-
/* leave IQK mode */
PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000);
@@ -461,7 +406,6 @@ static u8 phy_PathA_IQK_8723B(
PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK, bMaskDWord, 0x01007c00);
PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK, bMaskDWord, 0x01004800);
/* path-A IQK setting */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A IQK setting!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_A, bMaskDWord, 0x18008c1c);
PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_A, bMaskDWord, 0x38008c1c);
PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_B, bMaskDWord, 0x38008c1c);
@@ -473,7 +417,6 @@ static u8 phy_PathA_IQK_8723B(
PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_B, bMaskDWord, 0x28110000);
/* LO calibration setting */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Rsp, bMaskDWord, 0x00462911);
/* enter IQK mode */
@@ -491,12 +434,10 @@ static u8 phy_PathA_IQK_8723B(
PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00000800);
/* One shot, path A LOK & IQK */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000);
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
/* delay x ms */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_8723B)); */
/* PlatformStallExecution(IQK_DELAY_TIME_8723B*1000); */
mdelay(IQK_DELAY_TIME_8723B);
@@ -513,11 +454,6 @@ static u8 phy_PathA_IQK_8723B(
regEAC = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord);
regE94 = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord);
regE9C = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x, 0xe9c = 0x%x\n", regE94, regE9C));
- /* monitor image power before & after IQK */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe90(before IQK) = 0x%x, 0xe98(afer IQK) = 0x%x\n",
- PHY_QueryBBReg(pDM_Odm->Adapter, 0xe90, bMaskDWord), PHY_QueryBBReg(pDM_Odm->Adapter, 0xe98, bMaskDWord)));
/* Allen 20131125 */
@@ -550,18 +486,13 @@ static u8 phy_PathA_RxIQK8723B(
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK!\n")); */
-
/* Save RF Path */
Path_SEL_BB = PHY_QueryBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord);
/* leave IQK mode */
PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000);
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A RX IQK:Get TXIMR setting\n"));
/* 1 Get TXIMR setting */
/* modify RXIQK mode table */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table!\n")); */
PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_WE_LUT, 0x80000, 0x1);
PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x18000);
PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0001f);
@@ -587,7 +518,6 @@ static u8 phy_PathA_RxIQK8723B(
PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_B, bMaskDWord, 0x28110000);
/* LO calibration setting */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911);
/* enter IQK mode */
@@ -605,12 +535,10 @@ static u8 phy_PathA_RxIQK8723B(
PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00000800);
/* One shot, path A LOK & IQK */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000);
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
/* delay x ms */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_8723B)); */
/* PlatformStallExecution(IQK_DELAY_TIME_8723B*1000); */
mdelay(IQK_DELAY_TIME_8723B);
@@ -626,11 +554,6 @@ static u8 phy_PathA_RxIQK8723B(
regEAC = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord);
regE94 = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord);
regE9C = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x, 0xe9c = 0x%x\n", regE94, regE9C));
- /* monitor image power before & after IQK */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe90(before IQK) = 0x%x, 0xe98(afer IQK) = 0x%x\n",
- PHY_QueryBBReg(pDM_Odm->Adapter, 0xe90, bMaskDWord), PHY_QueryBBReg(pDM_Odm->Adapter, 0xe98, bMaskDWord)));
/* Allen 20131125 */
tmp = (regE9C & 0x03FF0000)>>16;
@@ -651,14 +574,8 @@ static u8 phy_PathA_RxIQK8723B(
u4tmp = 0x80007C00 | (regE94&0x3FF0000) | ((regE9C&0x3FF0000) >> 16);
PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK, bMaskDWord, u4tmp);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe40 = 0x%x u4tmp = 0x%x\n", PHY_QueryBBReg(pDM_Odm->Adapter, rTx_IQK, bMaskDWord), u4tmp));
-
-
- /* 1 RX IQK */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A RX IQK\n"));
/* modify RXIQK mode table */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table 2!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000);
PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_WE_LUT, 0x80000, 0x1);
PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x18000);
@@ -688,7 +605,6 @@ static u8 phy_PathA_RxIQK8723B(
PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_B, bMaskDWord, 0x28110000);
/* LO calibration setting */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Rsp, bMaskDWord, 0x0046a8d1);
/* enter IQK mode */
@@ -706,12 +622,10 @@ static u8 phy_PathA_RxIQK8723B(
PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00000800);
/* One shot, path A LOK & IQK */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000);
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
/* delay x ms */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E)); */
/* PlatformStallExecution(IQK_DELAY_TIME_8723B*1000); */
mdelay(IQK_DELAY_TIME_8723B);
@@ -726,11 +640,6 @@ static u8 phy_PathA_RxIQK8723B(
/* Check failed */
regEAC = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord);
regEA4 = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_Before_IQK_A_2, bMaskDWord);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea4 = 0x%x, 0xeac = 0x%x\n", regEA4, regEAC));
- /* monitor image power before & after IQK */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea0(before IQK) = 0x%x, 0xea8(afer IQK) = 0x%x\n",
- PHY_QueryBBReg(pDM_Odm->Adapter, 0xea0, bMaskDWord), PHY_QueryBBReg(pDM_Odm->Adapter, 0xea8, bMaskDWord)));
/* PA/PAD controlled by 0x0 */
/* leave IQK mode */
@@ -751,8 +660,7 @@ static u8 phy_PathA_RxIQK8723B(
(tmp < 0xf)
)
result |= 0x02;
- else /* if Tx not OK, ignore Rx */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK fail!!\n"));
+
return result;
}
@@ -764,8 +672,6 @@ static u8 phy_PathB_IQK_8723B(struct adapter *padapter)
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK!\n"));
-
/* Save RF Path */
Path_SEL_BB = PHY_QueryBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord);
@@ -788,7 +694,6 @@ static u8 phy_PathB_IQK_8723B(struct adapter *padapter)
PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK, bMaskDWord, 0x01007c00);
PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK, bMaskDWord, 0x01004800);
/* path-A IQK setting */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-B IQK setting!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_A, bMaskDWord, 0x18008c1c);
PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_A, bMaskDWord, 0x38008c1c);
PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK_Tone_B, bMaskDWord, 0x38008c1c);
@@ -801,7 +706,6 @@ static u8 phy_PathB_IQK_8723B(struct adapter *padapter)
PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_B, bMaskDWord, 0x28110000);
/* LO calibration setting */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Rsp, bMaskDWord, 0x00462911);
/* enter IQK mode */
@@ -815,12 +719,10 @@ static u8 phy_PathB_IQK_8723B(struct adapter *padapter)
PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00000800);
/* One shot, path B LOK & IQK */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path B LOK & IQK!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000);
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
/* delay x ms */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path B LOK & IQK.\n", IQK_DELAY_TIME_88E)); */
/* PlatformStallExecution(IQK_DELAY_TIME_88E*1000); */
mdelay(IQK_DELAY_TIME_8723B);
@@ -832,18 +734,10 @@ static u8 phy_PathB_IQK_8723B(struct adapter *padapter)
/* leave IQK mode */
PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000);
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0x948 = 0x%x\n", PHY_QueryBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord))); */
-
-
/* Check failed */
regEAC = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord);
regE94 = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord);
regE9C = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x, 0xe9c = 0x%x\n", regE94, regE9C));
- /* monitor image power before & after IQK */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe90(before IQK) = 0x%x, 0xe98(afer IQK) = 0x%x\n",
- PHY_QueryBBReg(pDM_Odm->Adapter, 0xe90, bMaskDWord), PHY_QueryBBReg(pDM_Odm->Adapter, 0xe98, bMaskDWord)));
/* Allen 20131125 */
tmp = (regE9C & 0x03FF0000)>>16;
@@ -871,8 +765,6 @@ static u8 phy_PathB_RxIQK8723B(struct adapter *padapter, bool configPathB)
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Rx IQK!\n")); */
-
/* Save RF Path */
Path_SEL_BB = PHY_QueryBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord);
/* leave IQK mode */
@@ -880,11 +772,7 @@ static u8 phy_PathB_RxIQK8723B(struct adapter *padapter, bool configPathB)
/* switch to path B */
PHY_SetBBReg(pDM_Odm->Adapter, 0x948, bMaskDWord, 0x00000280);
-
- /* 1 Get TXIMR setting */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B RX IQK:Get TXIMR setting!\n"));
/* modify RXIQK mode table */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table!\n")); */
PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_WE_LUT, 0x80000, 0x1);
PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x18000);
PHY_SetRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0001f);
@@ -912,7 +800,6 @@ static u8 phy_PathB_RxIQK8723B(struct adapter *padapter, bool configPathB)
PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_B, bMaskDWord, 0x28110000);
/* LO calibration setting */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911);
/* enter IQK mode */
@@ -926,13 +813,11 @@ static u8 phy_PathB_RxIQK8723B(struct adapter *padapter, bool configPathB)
PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00000800);
/* One shot, path B TXIQK @ RXIQK */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path B LOK & IQK!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000);
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
/* delay x ms */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E)); */
/* PlatformStallExecution(IQK_DELAY_TIME_88E*1000); */
mdelay(IQK_DELAY_TIME_8723B);
@@ -948,18 +833,11 @@ static u8 phy_PathB_RxIQK8723B(struct adapter *padapter, bool configPathB)
regEAC = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord);
regE94 = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord);
regE9C = PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x, 0xe9c = 0x%x\n", regE94, regE9C));
- /* monitor image power before & after IQK */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe90(before IQK) = 0x%x, 0xe98(afer IQK) = 0x%x\n",
- PHY_QueryBBReg(pDM_Odm->Adapter, 0xe90, bMaskDWord), PHY_QueryBBReg(pDM_Odm->Adapter, 0xe98, bMaskDWord)));
/* Allen 20131125 */
tmp = (regE9C & 0x03FF0000)>>16;
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("tmp1 = 0x%x\n", tmp)); */
if ((tmp & 0x200) > 0)
tmp = 0x400 - tmp;
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("tmp2 = 0x%x\n", tmp)); */
if (
!(regEAC & BIT28) &&
@@ -975,10 +853,6 @@ static u8 phy_PathB_RxIQK8723B(struct adapter *padapter, bool configPathB)
u4tmp = 0x80007C00 | (regE94&0x3FF0000) | ((regE9C&0x3FF0000) >> 16);
PHY_SetBBReg(pDM_Odm->Adapter, rTx_IQK, bMaskDWord, u4tmp);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe40 = 0x%x u4tmp = 0x%x\n", PHY_QueryBBReg(pDM_Odm->Adapter, rTx_IQK, bMaskDWord), u4tmp));
-
- /* 1 RX IQK */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B RX IQK\n"));
/* modify RXIQK mode table */
/* 20121009, Kordan> RF Mode = 3 */
@@ -1013,7 +887,6 @@ static u8 phy_PathB_RxIQK8723B(struct adapter *padapter, bool configPathB)
PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_PI_B, bMaskDWord, 0x28110000);
/* LO calibration setting */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Rsp, bMaskDWord, 0x0046a8d1);
/* enter IQK mode */
@@ -1027,12 +900,10 @@ static u8 phy_PathB_RxIQK8723B(struct adapter *padapter, bool configPathB)
PHY_SetBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord, 0x00000800);
/* One shot, path B LOK & IQK */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path B LOK & IQK!\n")); */
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000);
PHY_SetBBReg(pDM_Odm->Adapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
/* delay x ms */
-/* ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E)); */
/* PlatformStallExecution(IQK_DELAY_TIME_88E*1000); */
mdelay(IQK_DELAY_TIME_8723B);
@@ -1048,12 +919,6 @@ static u8 phy_PathB_RxIQK8723B(struct adapter *padapter, bool configPathB)
regEAC = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord);
regEA4 = PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_Before_IQK_A_2, bMaskDWord);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea4 = 0x%x, 0xeac = 0x%x\n", regEA4, regEAC));
- /* monitor image power before & after IQK */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea0(before IQK) = 0x%x, 0xea8(afer IQK) = 0x%x\n",
- PHY_QueryBBReg(pDM_Odm->Adapter, 0xea0, bMaskDWord), PHY_QueryBBReg(pDM_Odm->Adapter, 0xea8, bMaskDWord)));
-
/* PA/PAD controlled by 0x0 */
/* leave IQK mode */
/* PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, 0xffffff00, 0x00000000); */
@@ -1075,8 +940,6 @@ static u8 phy_PathB_RxIQK8723B(struct adapter *padapter, bool configPathB)
(tmp < 0xf)
)
result |= 0x02;
- else
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Rx IQK fail!!\n"));
return result;
}
@@ -1096,8 +959,6 @@ static void _PHY_PathAFillIQKMatrix8723B(
struct odm_rf_cal_t *pRFCalibrateInfo = &pDM_Odm->RFCalibrateInfo;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQ Calibration %s !\n", (bIQKOK)?"Success":"Failed"));
-
if (final_candidate == 0xFF)
return;
@@ -1108,7 +969,6 @@ static void _PHY_PathAFillIQKMatrix8723B(
if ((X & 0x00000200) != 0)
X = X | 0xFFFFFC00;
TX0_A = (X * Oldval_0) >> 8;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("X = 0x%x, TX0_A = 0x%x, Oldval_0 0x%x\n", X, TX0_A, Oldval_0));
PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XATxIQImbalance, 0x3FF, TX0_A);
PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, BIT(31), ((X*Oldval_0>>7) & 0x1));
@@ -1119,7 +979,6 @@ static void _PHY_PathAFillIQKMatrix8723B(
/* 2 Tx IQC */
TX0_C = (Y * Oldval_0) >> 8;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Y = 0x%x, TX = 0x%x\n", Y, TX0_C));
PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XCTxAFE, 0xF0000000, ((TX0_C&0x3C0)>>6));
pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC94][KEY] = rOFDM0_XCTxAFE;
pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC94][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XCTxAFE, bMaskDWord);
@@ -1133,8 +992,6 @@ static void _PHY_PathAFillIQKMatrix8723B(
pRFCalibrateInfo->TxIQC_8723B[PATH_S1][IDX_0xC4C][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, bMaskDWord);
if (bTxOnly) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("_PHY_PathAFillIQKMatrix8723B only Tx OK\n"));
-
/* <20130226, Kordan> Saving RxIQC, otherwise not initialized. */
pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xCA0][KEY] = rOFDM0_RxIQExtAnta;
pRFCalibrateInfo->RxIQC_8723B[PATH_S1][IDX_0xCA0][VAL] = 0xfffffff & PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_RxIQExtAnta, bMaskDWord);
@@ -1176,8 +1033,6 @@ static void _PHY_PathBFillIQKMatrix8723B(
struct odm_rf_cal_t *pRFCalibrateInfo = &pDM_Odm->RFCalibrateInfo;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQ Calibration %s !\n", (bIQKOK)?"Success":"Failed"));
-
if (final_candidate == 0xFF)
return;
@@ -1188,7 +1043,6 @@ static void _PHY_PathBFillIQKMatrix8723B(
if ((X & 0x00000200) != 0)
X = X | 0xFFFFFC00;
TX1_A = (X * Oldval_1) >> 8;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("X = 0x%x, TX1_A = 0x%x\n", X, TX1_A));
PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XBTxIQImbalance, 0x3FF, TX1_A);
@@ -1199,7 +1053,6 @@ static void _PHY_PathBFillIQKMatrix8723B(
Y = Y | 0xFFFFFC00;
TX1_C = (Y * Oldval_1) >> 8;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Y = 0x%x, TX1_C = 0x%x\n", Y, TX1_C));
/* 2 Tx IQC */
PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XDTxAFE, 0xF0000000, ((TX1_C&0x3C0)>>6));
@@ -1217,8 +1070,6 @@ static void _PHY_PathBFillIQKMatrix8723B(
pRFCalibrateInfo->TxIQC_8723B[PATH_S0][IDX_0xC4C][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, bMaskDWord);
if (bTxOnly) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("_PHY_PathBFillIQKMatrix8723B only Tx OK\n"));
-
pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xC14][KEY] = rOFDM0_XARxIQImbalance;
/* pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xC14][VAL] = PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XARxIQImbalance, bMaskDWord); */
pRFCalibrateInfo->RxIQC_8723B[PATH_S0][IDX_0xC14][VAL] = 0x40000100;
@@ -1297,7 +1148,6 @@ static void _PHY_SaveADDARegisters8723B(
if (!ODM_CheckPowerStatus(padapter))
return;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save ADDA parameters.\n"));
for (i = 0 ; i < RegisterNum ; i++) {
ADDABackup[i] = PHY_QueryBBReg(pDM_Odm->Adapter, ADDAReg[i], bMaskDWord);
}
@@ -1312,7 +1162,6 @@ static void _PHY_SaveMACRegisters8723B(
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save MAC parameters.\n"));
for (i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++) {
MACBackup[i] = rtw_read8(pDM_Odm->Adapter, MACReg[i]);
}
@@ -1332,7 +1181,6 @@ static void _PHY_ReloadADDARegisters8723B(
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Reload ADDA power saving parameters !\n"));
for (i = 0 ; i < RegiesterNum; i++) {
PHY_SetBBReg(pDM_Odm->Adapter, ADDAReg[i], bMaskDWord, ADDABackup[i]);
}
@@ -1362,8 +1210,6 @@ static void _PHY_PathADDAOn8723B(
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("ADDA ON.\n"));
-
pathOn = 0x01c00014;
if (!is2T) {
pathOn = 0x01c00014;
@@ -1386,8 +1232,6 @@ static void _PHY_MACSettingCalibration8723B(
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("MAC settings for Calibration.\n"));
-
rtw_write8(pDM_Odm->Adapter, MACReg[i], 0x3F);
for (i = 1 ; i < (IQK_MAC_REG_NUM - 1); i++) {
@@ -1540,17 +1384,12 @@ static void phy_IQCalibrate_8723B(
/* u32 bbvalue; */
if (t == 0) {
-/* bbvalue = PHY_QueryBBReg(pDM_Odm->Adapter, rFPGA0_RFMOD, bMaskDWord); */
-/* RT_DISP(FINIT, INIT_IQK, ("phy_IQCalibrate_8188E() ==>0x%08x\n", bbvalue)); */
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQ Calibration for %s for %d times\n", (is2T ? "2T2R" : "1T1R"), t));
/* Save ADDA parameters, turn Path A ADDA on */
_PHY_SaveADDARegisters8723B(padapter, ADDA_REG, pDM_Odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM);
_PHY_SaveMACRegisters8723B(padapter, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup);
_PHY_SaveADDARegisters8723B(padapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM);
}
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQ Calibration for %s for %d times\n", (is2T ? "2T2R" : "1T1R"), t));
_PHY_PathADDAOn8723B(padapter, ADDA_REG, is2T);
@@ -1596,7 +1435,6 @@ static void phy_IQCalibrate_8723B(
PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000);
pDM_Odm->RFCalibrateInfo.TxLOK[ODM_RF_PATH_A] = PHY_QueryRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, 0x8, bRFRegOffsetMask);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Tx IQK Success!!\n"));
result[t][0] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16;
result[t][1] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16;
break;
@@ -1607,19 +1445,15 @@ static void phy_IQCalibrate_8723B(
for (i = 0 ; i < retryCount ; i++) {
PathAOK = phy_PathA_RxIQK8723B(padapter, is2T, RF_Path);
if (PathAOK == 0x03) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK Success!!\n"));
/* result[t][0] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; */
/* result[t][1] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; */
result[t][2] = (PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_Before_IQK_A_2, bMaskDWord)&0x3FF0000)>>16;
result[t][3] = (PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord)&0x3FF0000)>>16;
break;
- } else {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK Fail!!\n"));
}
}
if (0x00 == PathAOK) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQK failed!!\n"));
}
/* path B IQK */
@@ -1633,7 +1467,6 @@ static void phy_IQCalibrate_8723B(
PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0x000000);
pDM_Odm->RFCalibrateInfo.TxLOK[ODM_RF_PATH_B] = PHY_QueryRFReg(pDM_Odm->Adapter, ODM_RF_PATH_B, 0x8, bRFRegOffsetMask);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Tx IQK Success!!\n"));
result[t][4] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16;
result[t][5] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16;
break;
@@ -1644,25 +1477,18 @@ static void phy_IQCalibrate_8723B(
for (i = 0 ; i < retryCount ; i++) {
PathBOK = phy_PathB_RxIQK8723B(padapter, is2T);
if (PathBOK == 0x03) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Rx IQK Success!!\n"));
/* result[t][0] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; */
/* result[t][1] = (PHY_QueryBBReg(pDM_Odm->Adapter, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; */
result[t][6] = (PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_Before_IQK_A_2, bMaskDWord)&0x3FF0000)>>16;
result[t][7] = (PHY_QueryBBReg(pDM_Odm->Adapter, rRx_Power_After_IQK_A_2, bMaskDWord)&0x3FF0000)>>16;
break;
- } else {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Rx IQK Fail!!\n"));
}
}
/* Allen end */
- if (0x00 == PathBOK) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK failed!!\n"));
- }
}
/* Back to BB mode, load original value */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:Back to BB mode, load original value!\n"));
PHY_SetBBReg(pDM_Odm->Adapter, rFPGA0_IQK, bMaskH3Bytes, 0);
if (t != 0) {
@@ -1692,7 +1518,6 @@ static void phy_IQCalibrate_8723B(
PHY_SetBBReg(pDM_Odm->Adapter, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00);
}
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_IQCalibrate_8723B() <==\n"));
}
@@ -1789,7 +1614,7 @@ void PHY_IQCalibrate_8723B(
s32 result[4][8]; /* last is final result */
u8 i, final_candidate;
bool bPathAOK, bPathBOK;
- s32 RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC, RegTmp = 0;
+ s32 RegE94, RegE9C, RegEA4, RegEB4, RegEBC, RegEC4, RegTmp = 0;
bool is12simular, is13simular, is23simular;
bool bSingleTone = false, bCarrierSuppression = false;
u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = {
@@ -1805,8 +1630,6 @@ void PHY_IQCalibrate_8723B(
};
/* u32 Path_SEL_BB = 0; */
u32 GNT_BT_default;
- u32 StartTime;
- s32 ProgressingTime;
if (!ODM_CheckPowerStatus(padapter))
return;
@@ -1818,9 +1641,6 @@ void PHY_IQCalibrate_8723B(
if (bSingleTone || bCarrierSuppression)
return;
-#if DISABLE_BB_RF
- return;
-#endif
if (pDM_Odm->RFCalibrateInfo.bIQKInProgress)
return;
@@ -1868,12 +1688,9 @@ void PHY_IQCalibrate_8723B(
}
if (bReCovery) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("PHY_IQCalibrate_8723B: Return due to bReCovery!\n"));
_PHY_ReloadADDARegisters8723B(padapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup_recover, 9);
return;
}
- StartTime = jiffies;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:Start!!!\n"));
/* save default GNT_BT */
GNT_BT_default = PHY_QueryBBReg(pDM_Odm->Adapter, 0x764, bMaskDWord);
@@ -1908,7 +1725,6 @@ void PHY_IQCalibrate_8723B(
is12simular = phy_SimularityCompare_8723B(padapter, result, 0, 1);
if (is12simular) {
final_candidate = 0;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is12simular final_candidate is %x\n", final_candidate));
break;
}
}
@@ -1917,7 +1733,6 @@ void PHY_IQCalibrate_8723B(
is13simular = phy_SimularityCompare_8723B(padapter, result, 0, 2);
if (is13simular) {
final_candidate = 0;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is13simular final_candidate is %x\n", final_candidate));
break;
}
@@ -1925,7 +1740,6 @@ void PHY_IQCalibrate_8723B(
is23simular = phy_SimularityCompare_8723B(padapter, result, 1, 2);
if (is23simular) {
final_candidate = 1;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is23simular final_candidate is %x\n", final_candidate));
} else {
for (i = 0; i < 8; i++)
RegTmp += result[3][i];
@@ -1942,29 +1756,20 @@ void PHY_IQCalibrate_8723B(
RegE94 = result[i][0];
RegE9C = result[i][1];
RegEA4 = result[i][2];
- RegEAC = result[i][3];
RegEB4 = result[i][4];
RegEBC = result[i][5];
RegEC4 = result[i][6];
- RegECC = result[i][7];
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: RegE94 =%x RegE9C =%x RegEA4 =%x RegEAC =%x RegEB4 =%x RegEBC =%x RegEC4 =%x RegECC =%x\n ", RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC));
}
if (final_candidate != 0xff) {
pDM_Odm->RFCalibrateInfo.RegE94 = RegE94 = result[final_candidate][0];
pDM_Odm->RFCalibrateInfo.RegE9C = RegE9C = result[final_candidate][1];
RegEA4 = result[final_candidate][2];
- RegEAC = result[final_candidate][3];
pDM_Odm->RFCalibrateInfo.RegEB4 = RegEB4 = result[final_candidate][4];
pDM_Odm->RFCalibrateInfo.RegEBC = RegEBC = result[final_candidate][5];
RegEC4 = result[final_candidate][6];
- RegECC = result[final_candidate][7];
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: final_candidate is %x\n", final_candidate));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: RegE94 =%x RegE9C =%x RegEA4 =%x RegEAC =%x RegEB4 =%x RegEBC =%x RegEC4 =%x RegECC =%x\n ", RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC));
bPathAOK = bPathBOK = true;
} else {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: FAIL use default value\n"));
-
pDM_Odm->RFCalibrateInfo.RegE94 = pDM_Odm->RFCalibrateInfo.RegEB4 = 0x100; /* X default value */
pDM_Odm->RFCalibrateInfo.RegE9C = pDM_Odm->RFCalibrateInfo.RegEBC = 0x0; /* Y default value */
}
@@ -1985,7 +1790,6 @@ void PHY_IQCalibrate_8723B(
pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[0].Value[0][i] = result[final_candidate][i];
pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[0].bIQKDone = true;
}
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("\nIQK OK Indexforchannel %d.\n", 0));
_PHY_SaveADDARegisters8723B(padapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup_recover, 9);
@@ -2015,12 +1819,6 @@ void PHY_IQCalibrate_8723B(
}
pDM_Odm->RFCalibrateInfo.bIQKInProgress = false;
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK finished\n"));
- ProgressingTime = jiffies_to_msecs(jiffies - StartTime);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK ProgressingTime = %d\n", ProgressingTime));
-
-
}
@@ -2028,12 +1826,6 @@ void PHY_LCCalibrate_8723B(struct dm_odm_t *pDM_Odm)
{
bool bSingleTone = false, bCarrierSuppression = false;
u32 timeout = 2000, timecount = 0;
- u32 StartTime;
- s32 ProgressingTime;
-
-#if DISABLE_BB_RF
- return;
-#endif
if (!(pDM_Odm->SupportAbility & ODM_RF_CALIBRATION))
return;
@@ -2042,7 +1834,6 @@ void PHY_LCCalibrate_8723B(struct dm_odm_t *pDM_Odm)
if (bSingleTone || bCarrierSuppression)
return;
- StartTime = jiffies;
while (*(pDM_Odm->pbScanInProcess) && timecount < timeout) {
mdelay(50);
timecount += 50;
@@ -2055,8 +1846,4 @@ void PHY_LCCalibrate_8723B(struct dm_odm_t *pDM_Odm)
pDM_Odm->RFCalibrateInfo.bLCKInProgress = false;
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LCK:Finish!!!interface %d\n", pDM_Odm->InterfaceIndex));
- ProgressingTime = jiffies_to_msecs(jiffies - StartTime);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LCK ProgressingTime = %d\n", ProgressingTime));
}
diff --git a/drivers/staging/rtl8723bs/hal/hal_btcoex.c b/drivers/staging/rtl8723bs/hal/hal_btcoex.c
index 5802ed4c6f82..3b0573885dce 100644
--- a/drivers/staging/rtl8723bs/hal/hal_btcoex.c
+++ b/drivers/staging/rtl8723bs/hal/hal_btcoex.c
@@ -17,7 +17,6 @@ struct btc_coexist GLBtCoexist;
static u8 GLBtcWiFiInScanState;
static u8 GLBtcWiFiInIQKState;
-u32 GLBtcDbgType[BTC_MSG_MAX];
static u8 GLBtcDbgBuf[BT_TMP_BUF_SIZE];
struct btcdbginfo { /* _btcoexdbginfo */
@@ -75,32 +74,6 @@ static u8 halbtcoutsrc_IsBtCoexistAvailable(struct btc_coexist *pBtCoexist)
return true;
}
-static void halbtcoutsrc_DbgInit(void)
-{
- u8 i;
-
- for (i = 0; i < BTC_MSG_MAX; i++)
- GLBtcDbgType[i] = 0;
-
- GLBtcDbgType[BTC_MSG_INTERFACE] = \
-/* INTF_INIT | */
-/* INTF_NOTIFY | */
- 0;
-
- GLBtcDbgType[BTC_MSG_ALGORITHM] = \
-/* ALGO_BT_RSSI_STATE | */
-/* ALGO_WIFI_RSSI_STATE | */
-/* ALGO_BT_MONITOR | */
-/* ALGO_TRACE | */
-/* ALGO_TRACE_FW | */
-/* ALGO_TRACE_FW_DETAIL | */
-/* ALGO_TRACE_FW_EXEC | */
-/* ALGO_TRACE_SW | */
-/* ALGO_TRACE_SW_DETAIL | */
-/* ALGO_TRACE_SW_EXEC | */
- 0;
-}
-
static void halbtcoutsrc_LeaveLps(struct btc_coexist *pBtCoexist)
{
struct adapter *padapter;
@@ -131,9 +104,6 @@ static void halbtcoutsrc_NormalLps(struct btc_coexist *pBtCoexist)
{
struct adapter *padapter;
-
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Normal LPS behavior!!!\n"));
-
padapter = pBtCoexist->Adapter;
if (pBtCoexist->btInfo.bBtCtrlLps) {
@@ -398,10 +368,6 @@ static u8 halbtcoutsrc_Get(void *pBtcContext, u8 getType, void *pOutBuf)
*pu8 = false;
break;
- case BTC_GET_BL_WIFI_UNDER_5G:
- *pu8 = pHalData->CurrentBandType == 1;
- break;
-
case BTC_GET_BL_WIFI_AP_MODE_ENABLE:
*pu8 = check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE);
break;
@@ -922,8 +888,6 @@ void hal_btcoex_Initialize(void *padapter)
/* pBtCoexist->statistics.cntBind++; */
- halbtcoutsrc_DbgInit();
-
pBtCoexist->chipInterface = BTC_INTF_SDIO;
EXhalbtcoutsrc_BindBtCoexWithAdapter(padapter);
@@ -1481,10 +1445,6 @@ u32 hal_btcoex_GetRaMask(struct adapter *padapter)
void hal_btcoex_RecordPwrMode(struct adapter *padapter, u8 *pCmdBuf, u8 cmdLen)
{
- BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write pwrModeCmd = 0x%04x%08x\n",
- pCmdBuf[0] << 8 | pCmdBuf[1],
- pCmdBuf[2] << 24 | pCmdBuf[3] << 16 | pCmdBuf[4] << 8 | pCmdBuf[5]));
-
memcpy(GLBtCoexist.pwrModeVal, pCmdBuf, cmdLen);
}
@@ -1499,138 +1459,3 @@ void hal_btcoex_DisplayBtCoexInfo(struct adapter *padapter, u8 *pbuf, u32 bufsiz
DBG_BT_INFO_INIT(pinfo, NULL, 0);
}
-void hal_btcoex_SetDBG(struct adapter *padapter, u32 *pDbgModule)
-{
- u32 i;
-
-
- if (!pDbgModule)
- return;
-
- for (i = 0; i < BTC_MSG_MAX; i++)
- GLBtcDbgType[i] = pDbgModule[i];
-}
-
-u32 hal_btcoex_GetDBG(struct adapter *padapter, u8 *pStrBuf, u32 bufSize)
-{
- s32 count;
- u8 *pstr;
- u32 leftSize;
-
-
- if (!pStrBuf || bufSize == 0)
- return 0;
-
- pstr = pStrBuf;
- leftSize = bufSize;
-
- count = rtw_sprintf(pstr, leftSize, "#define DBG\t%d\n", DBG);
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
-
- count = rtw_sprintf(pstr, leftSize, "BTCOEX Debug Setting:\n");
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
-
- count = rtw_sprintf(pstr, leftSize,
- "INTERFACE / ALGORITHM: 0x%08X / 0x%08X\n\n",
- GLBtcDbgType[BTC_MSG_INTERFACE],
- GLBtcDbgType[BTC_MSG_ALGORITHM]);
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
-
- count = rtw_sprintf(pstr, leftSize, "INTERFACE Debug Setting Definition:\n");
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
- count = rtw_sprintf(pstr, leftSize, "\tbit[0]=%d for INTF_INIT\n",
- (GLBtcDbgType[BTC_MSG_INTERFACE] & INTF_INIT) ? 1 : 0);
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
- count = rtw_sprintf(pstr, leftSize, "\tbit[2]=%d for INTF_NOTIFY\n\n",
- (GLBtcDbgType[BTC_MSG_INTERFACE] & INTF_NOTIFY) ? 1 : 0);
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
-
- count = rtw_sprintf(pstr, leftSize, "ALGORITHM Debug Setting Definition:\n");
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
- count = rtw_sprintf(pstr, leftSize, "\tbit[0]=%d for BT_RSSI_STATE\n",
- (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_BT_RSSI_STATE) ? 1 : 0);
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
- count = rtw_sprintf(pstr, leftSize, "\tbit[1]=%d for WIFI_RSSI_STATE\n",
- (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_WIFI_RSSI_STATE) ? 1 : 0);
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
- count = rtw_sprintf(pstr, leftSize, "\tbit[2]=%d for BT_MONITOR\n",
- (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_BT_MONITOR) ? 1 : 0);
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
- count = rtw_sprintf(pstr, leftSize, "\tbit[3]=%d for TRACE\n",
- (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE) ? 1 : 0);
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
- count = rtw_sprintf(pstr, leftSize, "\tbit[4]=%d for TRACE_FW\n",
- (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_FW) ? 1 : 0);
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
- count = rtw_sprintf(pstr, leftSize, "\tbit[5]=%d for TRACE_FW_DETAIL\n",
- (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_FW_DETAIL) ? 1 : 0);
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
- count = rtw_sprintf(pstr, leftSize, "\tbit[6]=%d for TRACE_FW_EXEC\n",
- (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_FW_EXEC) ? 1 : 0);
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
- count = rtw_sprintf(pstr, leftSize, "\tbit[7]=%d for TRACE_SW\n",
- (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_SW) ? 1 : 0);
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
- count = rtw_sprintf(pstr, leftSize, "\tbit[8]=%d for TRACE_SW_DETAIL\n",
- (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_SW_DETAIL) ? 1 : 0);
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
- count = rtw_sprintf(pstr, leftSize, "\tbit[9]=%d for TRACE_SW_EXEC\n",
- (GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_SW_EXEC) ? 1 : 0);
- if ((count < 0) || (count >= leftSize))
- goto exit;
- pstr += count;
- leftSize -= count;
-
-exit:
- count = pstr - pStrBuf;
-
- return count;
-}
diff --git a/drivers/staging/rtl8723bs/hal/hal_com.c b/drivers/staging/rtl8723bs/hal/hal_com.c
index e82f59fc5e9b..eebd48438733 100644
--- a/drivers/staging/rtl8723bs/hal/hal_com.c
+++ b/drivers/staging/rtl8723bs/hal/hal_com.c
@@ -295,126 +295,6 @@ u8 MRateToHwRate(u8 rate)
case MGN_MCS31:
ret = DESC_RATEMCS31;
break;
- case MGN_VHT1SS_MCS0:
- ret = DESC_RATEVHTSS1MCS0;
- break;
- case MGN_VHT1SS_MCS1:
- ret = DESC_RATEVHTSS1MCS1;
- break;
- case MGN_VHT1SS_MCS2:
- ret = DESC_RATEVHTSS1MCS2;
- break;
- case MGN_VHT1SS_MCS3:
- ret = DESC_RATEVHTSS1MCS3;
- break;
- case MGN_VHT1SS_MCS4:
- ret = DESC_RATEVHTSS1MCS4;
- break;
- case MGN_VHT1SS_MCS5:
- ret = DESC_RATEVHTSS1MCS5;
- break;
- case MGN_VHT1SS_MCS6:
- ret = DESC_RATEVHTSS1MCS6;
- break;
- case MGN_VHT1SS_MCS7:
- ret = DESC_RATEVHTSS1MCS7;
- break;
- case MGN_VHT1SS_MCS8:
- ret = DESC_RATEVHTSS1MCS8;
- break;
- case MGN_VHT1SS_MCS9:
- ret = DESC_RATEVHTSS1MCS9;
- break;
- case MGN_VHT2SS_MCS0:
- ret = DESC_RATEVHTSS2MCS0;
- break;
- case MGN_VHT2SS_MCS1:
- ret = DESC_RATEVHTSS2MCS1;
- break;
- case MGN_VHT2SS_MCS2:
- ret = DESC_RATEVHTSS2MCS2;
- break;
- case MGN_VHT2SS_MCS3:
- ret = DESC_RATEVHTSS2MCS3;
- break;
- case MGN_VHT2SS_MCS4:
- ret = DESC_RATEVHTSS2MCS4;
- break;
- case MGN_VHT2SS_MCS5:
- ret = DESC_RATEVHTSS2MCS5;
- break;
- case MGN_VHT2SS_MCS6:
- ret = DESC_RATEVHTSS2MCS6;
- break;
- case MGN_VHT2SS_MCS7:
- ret = DESC_RATEVHTSS2MCS7;
- break;
- case MGN_VHT2SS_MCS8:
- ret = DESC_RATEVHTSS2MCS8;
- break;
- case MGN_VHT2SS_MCS9:
- ret = DESC_RATEVHTSS2MCS9;
- break;
- case MGN_VHT3SS_MCS0:
- ret = DESC_RATEVHTSS3MCS0;
- break;
- case MGN_VHT3SS_MCS1:
- ret = DESC_RATEVHTSS3MCS1;
- break;
- case MGN_VHT3SS_MCS2:
- ret = DESC_RATEVHTSS3MCS2;
- break;
- case MGN_VHT3SS_MCS3:
- ret = DESC_RATEVHTSS3MCS3;
- break;
- case MGN_VHT3SS_MCS4:
- ret = DESC_RATEVHTSS3MCS4;
- break;
- case MGN_VHT3SS_MCS5:
- ret = DESC_RATEVHTSS3MCS5;
- break;
- case MGN_VHT3SS_MCS6:
- ret = DESC_RATEVHTSS3MCS6;
- break;
- case MGN_VHT3SS_MCS7:
- ret = DESC_RATEVHTSS3MCS7;
- break;
- case MGN_VHT3SS_MCS8:
- ret = DESC_RATEVHTSS3MCS8;
- break;
- case MGN_VHT3SS_MCS9:
- ret = DESC_RATEVHTSS3MCS9;
- break;
- case MGN_VHT4SS_MCS0:
- ret = DESC_RATEVHTSS4MCS0;
- break;
- case MGN_VHT4SS_MCS1:
- ret = DESC_RATEVHTSS4MCS1;
- break;
- case MGN_VHT4SS_MCS2:
- ret = DESC_RATEVHTSS4MCS2;
- break;
- case MGN_VHT4SS_MCS3:
- ret = DESC_RATEVHTSS4MCS3;
- break;
- case MGN_VHT4SS_MCS4:
- ret = DESC_RATEVHTSS4MCS4;
- break;
- case MGN_VHT4SS_MCS5:
- ret = DESC_RATEVHTSS4MCS5;
- break;
- case MGN_VHT4SS_MCS6:
- ret = DESC_RATEVHTSS4MCS6;
- break;
- case MGN_VHT4SS_MCS7:
- ret = DESC_RATEVHTSS4MCS7;
- break;
- case MGN_VHT4SS_MCS8:
- ret = DESC_RATEVHTSS4MCS8;
- break;
- case MGN_VHT4SS_MCS9:
- ret = DESC_RATEVHTSS4MCS9;
- break;
default:
break;
}
@@ -559,127 +439,6 @@ u8 HwRateToMRate(u8 rate)
case DESC_RATEMCS31:
ret_rate = MGN_MCS31;
break;
- case DESC_RATEVHTSS1MCS0:
- ret_rate = MGN_VHT1SS_MCS0;
- break;
- case DESC_RATEVHTSS1MCS1:
- ret_rate = MGN_VHT1SS_MCS1;
- break;
- case DESC_RATEVHTSS1MCS2:
- ret_rate = MGN_VHT1SS_MCS2;
- break;
- case DESC_RATEVHTSS1MCS3:
- ret_rate = MGN_VHT1SS_MCS3;
- break;
- case DESC_RATEVHTSS1MCS4:
- ret_rate = MGN_VHT1SS_MCS4;
- break;
- case DESC_RATEVHTSS1MCS5:
- ret_rate = MGN_VHT1SS_MCS5;
- break;
- case DESC_RATEVHTSS1MCS6:
- ret_rate = MGN_VHT1SS_MCS6;
- break;
- case DESC_RATEVHTSS1MCS7:
- ret_rate = MGN_VHT1SS_MCS7;
- break;
- case DESC_RATEVHTSS1MCS8:
- ret_rate = MGN_VHT1SS_MCS8;
- break;
- case DESC_RATEVHTSS1MCS9:
- ret_rate = MGN_VHT1SS_MCS9;
- break;
- case DESC_RATEVHTSS2MCS0:
- ret_rate = MGN_VHT2SS_MCS0;
- break;
- case DESC_RATEVHTSS2MCS1:
- ret_rate = MGN_VHT2SS_MCS1;
- break;
- case DESC_RATEVHTSS2MCS2:
- ret_rate = MGN_VHT2SS_MCS2;
- break;
- case DESC_RATEVHTSS2MCS3:
- ret_rate = MGN_VHT2SS_MCS3;
- break;
- case DESC_RATEVHTSS2MCS4:
- ret_rate = MGN_VHT2SS_MCS4;
- break;
- case DESC_RATEVHTSS2MCS5:
- ret_rate = MGN_VHT2SS_MCS5;
- break;
- case DESC_RATEVHTSS2MCS6:
- ret_rate = MGN_VHT2SS_MCS6;
- break;
- case DESC_RATEVHTSS2MCS7:
- ret_rate = MGN_VHT2SS_MCS7;
- break;
- case DESC_RATEVHTSS2MCS8:
- ret_rate = MGN_VHT2SS_MCS8;
- break;
- case DESC_RATEVHTSS2MCS9:
- ret_rate = MGN_VHT2SS_MCS9;
- break;
- case DESC_RATEVHTSS3MCS0:
- ret_rate = MGN_VHT3SS_MCS0;
- break;
- case DESC_RATEVHTSS3MCS1:
- ret_rate = MGN_VHT3SS_MCS1;
- break;
- case DESC_RATEVHTSS3MCS2:
- ret_rate = MGN_VHT3SS_MCS2;
- break;
- case DESC_RATEVHTSS3MCS3:
- ret_rate = MGN_VHT3SS_MCS3;
- break;
- case DESC_RATEVHTSS3MCS4:
- ret_rate = MGN_VHT3SS_MCS4;
- break;
- case DESC_RATEVHTSS3MCS5:
- ret_rate = MGN_VHT3SS_MCS5;
- break;
- case DESC_RATEVHTSS3MCS6:
- ret_rate = MGN_VHT3SS_MCS6;
- break;
- case DESC_RATEVHTSS3MCS7:
- ret_rate = MGN_VHT3SS_MCS7;
- break;
- case DESC_RATEVHTSS3MCS8:
- ret_rate = MGN_VHT3SS_MCS8;
- break;
- case DESC_RATEVHTSS3MCS9:
- ret_rate = MGN_VHT3SS_MCS9;
- break;
- case DESC_RATEVHTSS4MCS0:
- ret_rate = MGN_VHT4SS_MCS0;
- break;
- case DESC_RATEVHTSS4MCS1:
- ret_rate = MGN_VHT4SS_MCS1;
- break;
- case DESC_RATEVHTSS4MCS2:
- ret_rate = MGN_VHT4SS_MCS2;
- break;
- case DESC_RATEVHTSS4MCS3:
- ret_rate = MGN_VHT4SS_MCS3;
- break;
- case DESC_RATEVHTSS4MCS4:
- ret_rate = MGN_VHT4SS_MCS4;
- break;
- case DESC_RATEVHTSS4MCS5:
- ret_rate = MGN_VHT4SS_MCS5;
- break;
- case DESC_RATEVHTSS4MCS6:
- ret_rate = MGN_VHT4SS_MCS6;
- break;
- case DESC_RATEVHTSS4MCS7:
- ret_rate = MGN_VHT4SS_MCS7;
- break;
- case DESC_RATEVHTSS4MCS8:
- ret_rate = MGN_VHT4SS_MCS8;
- break;
- case DESC_RATEVHTSS4MCS9:
- ret_rate = MGN_VHT4SS_MCS9;
- break;
-
default:
break;
}
@@ -916,16 +675,10 @@ s32 c2h_evt_read_88xx(struct adapter *adapter, u8 *buf)
c2h_evt->seq = rtw_read8(adapter, REG_C2HEVT_CMD_SEQ_88XX);
c2h_evt->plen = rtw_read8(adapter, REG_C2HEVT_CMD_LEN_88XX);
- print_hex_dump_debug(DRIVER_PREFIX ": c2h_evt_read(): ", DUMP_PREFIX_NONE,
- 16, 1, &c2h_evt, sizeof(c2h_evt), false);
-
/* Read the content */
for (i = 0; i < c2h_evt->plen; i++)
c2h_evt->payload[i] = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 2 + i);
- print_hex_dump_debug(DRIVER_PREFIX ": c2h_evt_read(): Command Content:\n",
- DUMP_PREFIX_NONE, 16, 1, c2h_evt->payload, c2h_evt->plen, false);
-
ret = _SUCCESS;
clear_evt:
@@ -1093,13 +846,6 @@ u8 SetHalDefVar(
u8 bResult = _SUCCESS;
switch (variable) {
- case HW_DEF_FA_CNT_DUMP:
- /* ODM_COMP_COMMON */
- if (*((u8 *)value))
- odm->DebugComponents |= (ODM_COMP_DIG | ODM_COMP_FA_CNT);
- else
- odm->DebugComponents &= ~(ODM_COMP_DIG | ODM_COMP_FA_CNT);
- break;
case HAL_DEF_DBG_RX_INFO_DUMP:
if (odm->bLinked) {
@@ -1166,7 +912,6 @@ u8 GetHalDefVar(
)
{
struct hal_com_data *hal_data = GET_HAL_DATA(adapter);
- struct dm_odm_t *odm = &(hal_data->odmpriv);
u8 bResult = _SUCCESS;
switch (variable) {
@@ -1183,12 +928,6 @@ u8 GetHalDefVar(
*((int *)value) = psta->rssi_stat.UndecoratedSmoothedPWDB;
}
break;
- case HW_DEF_ODM_DBG_FLAG:
- *((u64 *)value) = odm->DebugComponents;
- break;
- case HW_DEF_ODM_DBG_LEVEL:
- *((u32 *)value) = odm->DebugLevel;
- break;
case HAL_DEF_DBG_DM_FUNC:
*((u32 *)value) = hal_data->odmpriv.SupportAbility;
break;
diff --git a/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c b/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c
index 94d11689b4ac..bb7941aee0c4 100644
--- a/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c
+++ b/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c
@@ -11,7 +11,7 @@
#include <hal_data.h>
#include <linux/kernel.h>
-u8 PHY_GetTxPowerByRateBase(struct adapter *Adapter, u8 Band, u8 RfPath,
+u8 PHY_GetTxPowerByRateBase(struct adapter *Adapter, u8 RfPath,
u8 TxNum, enum rate_section RateSection)
{
struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
@@ -20,73 +20,27 @@ u8 PHY_GetTxPowerByRateBase(struct adapter *Adapter, u8 Band, u8 RfPath,
if (RfPath > ODM_RF_PATH_D)
return 0;
- if (Band == BAND_ON_2_4G) {
- switch (RateSection) {
- case CCK:
- value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][0];
- break;
- case OFDM:
- value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][1];
- break;
- case HT_MCS0_MCS7:
- value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][2];
- break;
- case HT_MCS8_MCS15:
- value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][3];
- break;
- case HT_MCS16_MCS23:
- value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][4];
- break;
- case HT_MCS24_MCS31:
- value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][5];
- break;
- case VHT_1SSMCS0_1SSMCS9:
- value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][6];
- break;
- case VHT_2SSMCS0_2SSMCS9:
- value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][7];
- break;
- case VHT_3SSMCS0_3SSMCS9:
- value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][8];
- break;
- case VHT_4SSMCS0_4SSMCS9:
- value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][9];
- break;
- default:
- break;
- }
- } else if (Band == BAND_ON_5G) {
- switch (RateSection) {
- case OFDM:
- value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][0];
- break;
- case HT_MCS0_MCS7:
- value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][1];
- break;
- case HT_MCS8_MCS15:
- value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][2];
- break;
- case HT_MCS16_MCS23:
- value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][3];
- break;
- case HT_MCS24_MCS31:
- value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][4];
- break;
- case VHT_1SSMCS0_1SSMCS9:
- value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][5];
- break;
- case VHT_2SSMCS0_2SSMCS9:
- value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][6];
- break;
- case VHT_3SSMCS0_3SSMCS9:
- value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][7];
- break;
- case VHT_4SSMCS0_4SSMCS9:
- value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][8];
- break;
- default:
- break;
- }
+ switch (RateSection) {
+ case CCK:
+ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][0];
+ break;
+ case OFDM:
+ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][1];
+ break;
+ case HT_MCS0_MCS7:
+ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][2];
+ break;
+ case HT_MCS8_MCS15:
+ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][3];
+ break;
+ case HT_MCS16_MCS23:
+ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][4];
+ break;
+ case HT_MCS24_MCS31:
+ value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][5];
+ break;
+ default:
+ break;
}
return value;
@@ -95,7 +49,6 @@ u8 PHY_GetTxPowerByRateBase(struct adapter *Adapter, u8 Band, u8 RfPath,
static void
phy_SetTxPowerByRateBase(
struct adapter *Adapter,
- u8 Band,
u8 RfPath,
enum rate_section RateSection,
u8 TxNum,
@@ -107,73 +60,27 @@ phy_SetTxPowerByRateBase(
if (RfPath > ODM_RF_PATH_D)
return;
- if (Band == BAND_ON_2_4G) {
- switch (RateSection) {
- case CCK:
- pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][0] = Value;
- break;
- case OFDM:
- pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][1] = Value;
- break;
- case HT_MCS0_MCS7:
- pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][2] = Value;
- break;
- case HT_MCS8_MCS15:
- pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][3] = Value;
- break;
- case HT_MCS16_MCS23:
- pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][4] = Value;
- break;
- case HT_MCS24_MCS31:
- pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][5] = Value;
- break;
- case VHT_1SSMCS0_1SSMCS9:
- pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][6] = Value;
- break;
- case VHT_2SSMCS0_2SSMCS9:
- pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][7] = Value;
- break;
- case VHT_3SSMCS0_3SSMCS9:
- pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][8] = Value;
- break;
- case VHT_4SSMCS0_4SSMCS9:
- pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][9] = Value;
- break;
- default:
- break;
- }
- } else if (Band == BAND_ON_5G) {
- switch (RateSection) {
- case OFDM:
- pHalData->TxPwrByRateBase5G[RfPath][TxNum][0] = Value;
- break;
- case HT_MCS0_MCS7:
- pHalData->TxPwrByRateBase5G[RfPath][TxNum][1] = Value;
- break;
- case HT_MCS8_MCS15:
- pHalData->TxPwrByRateBase5G[RfPath][TxNum][2] = Value;
- break;
- case HT_MCS16_MCS23:
- pHalData->TxPwrByRateBase5G[RfPath][TxNum][3] = Value;
- break;
- case HT_MCS24_MCS31:
- pHalData->TxPwrByRateBase5G[RfPath][TxNum][4] = Value;
- break;
- case VHT_1SSMCS0_1SSMCS9:
- pHalData->TxPwrByRateBase5G[RfPath][TxNum][5] = Value;
- break;
- case VHT_2SSMCS0_2SSMCS9:
- pHalData->TxPwrByRateBase5G[RfPath][TxNum][6] = Value;
- break;
- case VHT_3SSMCS0_3SSMCS9:
- pHalData->TxPwrByRateBase5G[RfPath][TxNum][7] = Value;
- break;
- case VHT_4SSMCS0_4SSMCS9:
- pHalData->TxPwrByRateBase5G[RfPath][TxNum][8] = Value;
- break;
- default:
- break;
- }
+ switch (RateSection) {
+ case CCK:
+ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][0] = Value;
+ break;
+ case OFDM:
+ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][1] = Value;
+ break;
+ case HT_MCS0_MCS7:
+ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][2] = Value;
+ break;
+ case HT_MCS8_MCS15:
+ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][3] = Value;
+ break;
+ case HT_MCS16_MCS23:
+ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][4] = Value;
+ break;
+ case HT_MCS24_MCS31:
+ pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][5] = Value;
+ break;
+ default:
+ break;
}
}
@@ -185,50 +92,21 @@ struct adapter *padapter
u8 path, base;
for (path = ODM_RF_PATH_A; path <= ODM_RF_PATH_B; ++path) {
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_1TX, MGN_11M);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, CCK, RF_1TX, base);
-
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_1TX, MGN_54M);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, OFDM, RF_1TX, base);
-
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_1TX, MGN_MCS7);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, HT_MCS0_MCS7, RF_1TX, base);
-
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_2TX, MGN_MCS15);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, HT_MCS8_MCS15, RF_2TX, base);
-
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_3TX, MGN_MCS23);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, HT_MCS16_MCS23, RF_3TX, base);
-
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_1TX, MGN_VHT1SS_MCS7);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, VHT_1SSMCS0_1SSMCS9, RF_1TX, base);
-
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_2TX, MGN_VHT2SS_MCS7);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, VHT_2SSMCS0_2SSMCS9, RF_2TX, base);
-
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, path, RF_3TX, MGN_VHT3SS_MCS7);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_2_4G, path, VHT_3SSMCS0_3SSMCS9, RF_3TX, base);
+ base = PHY_GetTxPowerByRate(padapter, path, RF_1TX, MGN_11M);
+ phy_SetTxPowerByRateBase(padapter, path, CCK, RF_1TX, base);
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_1TX, MGN_54M);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, OFDM, RF_1TX, base);
+ base = PHY_GetTxPowerByRate(padapter, path, RF_1TX, MGN_54M);
+ phy_SetTxPowerByRateBase(padapter, path, OFDM, RF_1TX, base);
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_1TX, MGN_MCS7);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, HT_MCS0_MCS7, RF_1TX, base);
+ base = PHY_GetTxPowerByRate(padapter, path, RF_1TX, MGN_MCS7);
+ phy_SetTxPowerByRateBase(padapter, path, HT_MCS0_MCS7, RF_1TX, base);
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_2TX, MGN_MCS15);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, HT_MCS8_MCS15, RF_2TX, base);
+ base = PHY_GetTxPowerByRate(padapter, path, RF_2TX, MGN_MCS15);
+ phy_SetTxPowerByRateBase(padapter, path, HT_MCS8_MCS15, RF_2TX, base);
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_3TX, MGN_MCS23);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, HT_MCS16_MCS23, RF_3TX, base);
+ base = PHY_GetTxPowerByRate(padapter, path, RF_3TX, MGN_MCS23);
+ phy_SetTxPowerByRateBase(padapter, path, HT_MCS16_MCS23, RF_3TX, base);
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_1TX, MGN_VHT1SS_MCS7);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, VHT_1SSMCS0_1SSMCS9, RF_1TX, base);
-
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_2TX, MGN_VHT2SS_MCS7);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, VHT_2SSMCS0_2SSMCS9, RF_2TX, base);
-
- base = PHY_GetTxPowerByRate(padapter, BAND_ON_5G, path, RF_3TX, MGN_VHT2SS_MCS7);
- phy_SetTxPowerByRateBase(padapter, BAND_ON_5G, path, VHT_3SSMCS0_3SSMCS9, RF_3TX, base);
}
}
@@ -532,81 +410,6 @@ PHY_GetRateValuesOfTxPowerByRate(
*RateNum = 4;
break;
- case 0xC3C:
- case 0xE3C:
- case 0x183C:
- case 0x1a3C:
- RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS0);
- RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS1);
- RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS2);
- RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS3);
- for (i = 0; i < 4; ++i) {
- PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 +
- ((Value >> (i * 8)) & 0xF));
- }
- *RateNum = 4;
- break;
-
- case 0xC40:
- case 0xE40:
- case 0x1840:
- case 0x1a40:
- RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS4);
- RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS5);
- RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS6);
- RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS7);
- for (i = 0; i < 4; ++i) {
- PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 +
- ((Value >> (i * 8)) & 0xF));
- }
- *RateNum = 4;
- break;
-
- case 0xC44:
- case 0xE44:
- case 0x1844:
- case 0x1a44:
- RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS8);
- RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT1SS_MCS9);
- RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS0);
- RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS1);
- for (i = 0; i < 4; ++i) {
- PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 +
- ((Value >> (i * 8)) & 0xF));
- }
- *RateNum = 4;
- break;
-
- case 0xC48:
- case 0xE48:
- case 0x1848:
- case 0x1a48:
- RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS2);
- RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS3);
- RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS4);
- RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS5);
- for (i = 0; i < 4; ++i) {
- PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 +
- ((Value >> (i * 8)) & 0xF));
- }
- *RateNum = 4;
- break;
-
- case 0xC4C:
- case 0xE4C:
- case 0x184C:
- case 0x1a4C:
- RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS6);
- RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS7);
- RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS8);
- RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS9);
- for (i = 0; i < 4; ++i) {
- PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 +
- ((Value >> (i * 8)) & 0xF));
- }
- *RateNum = 4;
- break;
-
case 0xCD8:
case 0xED8:
case 0x18D8:
@@ -637,49 +440,6 @@ PHY_GetRateValuesOfTxPowerByRate(
*RateNum = 4;
break;
- case 0xCE0:
- case 0xEE0:
- case 0x18E0:
- case 0x1aE0:
- RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS0);
- RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS1);
- RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS2);
- RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS3);
- for (i = 0; i < 4; ++i) {
- PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 +
- ((Value >> (i * 8)) & 0xF));
- }
- *RateNum = 4;
- break;
-
- case 0xCE4:
- case 0xEE4:
- case 0x18E4:
- case 0x1aE4:
- RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS4);
- RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS5);
- RateIndex[2] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS6);
- RateIndex[3] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS7);
- for (i = 0; i < 4; ++i) {
- PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 +
- ((Value >> (i * 8)) & 0xF));
- }
- *RateNum = 4;
- break;
-
- case 0xCE8:
- case 0xEE8:
- case 0x18E8:
- case 0x1aE8:
- RateIndex[0] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS8);
- RateIndex[1] = PHY_GetRateIndexOfTxPowerByRate(MGN_VHT3SS_MCS9);
- for (i = 0; i < 2; ++i) {
- PwrByRateVal[i] = (s8) ((((Value >> (i * 8 + 4)) & 0xF)) * 10 +
- ((Value >> (i * 8)) & 0xF));
- }
- *RateNum = 4;
- break;
-
default:
break;
}
@@ -687,7 +447,6 @@ PHY_GetRateValuesOfTxPowerByRate(
static void PHY_StoreTxPowerByRateNew(
struct adapter *padapter,
- u32 Band,
u32 RfPath,
u32 TxNum,
u32 RegAddr,
@@ -701,9 +460,6 @@ static void PHY_StoreTxPowerByRateNew(
PHY_GetRateValuesOfTxPowerByRate(padapter, RegAddr, BitMask, Data, rateIndex, PwrByRateVal, &rateNum);
- if (Band != BAND_ON_2_4G && Band != BAND_ON_5G)
- return;
-
if (RfPath > ODM_RF_PATH_D)
return;
@@ -711,11 +467,7 @@ static void PHY_StoreTxPowerByRateNew(
return;
for (i = 0; i < rateNum; ++i) {
- if (rateIndex[i] == PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS0) ||
- rateIndex[i] == PHY_GetRateIndexOfTxPowerByRate(MGN_VHT2SS_MCS1))
- TxNum = RF_2TX;
-
- pHalData->TxPwrByRateOffset[Band][RfPath][TxNum][rateIndex[i]] = PwrByRateVal[i];
+ pHalData->TxPwrByRateOffset[RfPath][TxNum][rateIndex[i]] = PwrByRateVal[i];
}
}
@@ -732,18 +484,16 @@ static void PHY_StoreTxPowerByRateOld(
void PHY_InitTxPowerByRate(struct adapter *padapter)
{
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
- u8 band, rfPath, TxNum, rate;
+ u8 rfPath, TxNum, rate;
- for (band = BAND_ON_2_4G; band <= BAND_ON_5G; ++band)
- for (rfPath = 0; rfPath < TX_PWR_BY_RATE_NUM_RF; ++rfPath)
- for (TxNum = 0; TxNum < TX_PWR_BY_RATE_NUM_RF; ++TxNum)
- for (rate = 0; rate < TX_PWR_BY_RATE_NUM_RATE; ++rate)
- pHalData->TxPwrByRateOffset[band][rfPath][TxNum][rate] = 0;
+ for (rfPath = 0; rfPath < TX_PWR_BY_RATE_NUM_RF; ++rfPath)
+ for (TxNum = 0; TxNum < TX_PWR_BY_RATE_NUM_RF; ++TxNum)
+ for (rate = 0; rate < TX_PWR_BY_RATE_NUM_RATE; ++rate)
+ pHalData->TxPwrByRateOffset[rfPath][TxNum][rate] = 0;
}
void PHY_StoreTxPowerByRate(
struct adapter *padapter,
- u32 Band,
u32 RfPath,
u32 TxNum,
u32 RegAddr,
@@ -755,7 +505,7 @@ void PHY_StoreTxPowerByRate(
struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
if (pDM_Odm->PhyRegPgVersion > 0)
- PHY_StoreTxPowerByRateNew(padapter, Band, RfPath, TxNum, RegAddr, BitMask, Data);
+ PHY_StoreTxPowerByRateNew(padapter, RfPath, TxNum, RegAddr, BitMask, Data);
else if (pDM_Odm->PhyRegPgVersion == 0) {
PHY_StoreTxPowerByRateOld(padapter, RegAddr, BitMask, Data);
@@ -771,7 +521,7 @@ phy_ConvertTxPowerByRateInDbmToRelativeValues(
struct adapter *padapter
)
{
- u8 base = 0, i = 0, value = 0, band = 0, path = 0, txNum = 0;
+ u8 base = 0, i = 0, value = 0, path = 0, txNum = 0;
u8 cckRates[4] = {
MGN_1M, MGN_2M, MGN_5_5M, MGN_11M
};
@@ -787,77 +537,42 @@ struct adapter *padapter
u8 mcs16_23Rates[8] = {
MGN_MCS16, MGN_MCS17, MGN_MCS18, MGN_MCS19, MGN_MCS20, MGN_MCS21, MGN_MCS22, MGN_MCS23
};
- u8 vht1ssRates[10] = {
- MGN_VHT1SS_MCS0, MGN_VHT1SS_MCS1, MGN_VHT1SS_MCS2, MGN_VHT1SS_MCS3, MGN_VHT1SS_MCS4,
- MGN_VHT1SS_MCS5, MGN_VHT1SS_MCS6, MGN_VHT1SS_MCS7, MGN_VHT1SS_MCS8, MGN_VHT1SS_MCS9
- };
- u8 vht2ssRates[10] = {
- MGN_VHT2SS_MCS0, MGN_VHT2SS_MCS1, MGN_VHT2SS_MCS2, MGN_VHT2SS_MCS3, MGN_VHT2SS_MCS4,
- MGN_VHT2SS_MCS5, MGN_VHT2SS_MCS6, MGN_VHT2SS_MCS7, MGN_VHT2SS_MCS8, MGN_VHT2SS_MCS9
- };
- u8 vht3ssRates[10] = {
- MGN_VHT3SS_MCS0, MGN_VHT3SS_MCS1, MGN_VHT3SS_MCS2, MGN_VHT3SS_MCS3, MGN_VHT3SS_MCS4,
- MGN_VHT3SS_MCS5, MGN_VHT3SS_MCS6, MGN_VHT3SS_MCS7, MGN_VHT3SS_MCS8, MGN_VHT3SS_MCS9
- };
-
- for (band = BAND_ON_2_4G; band <= BAND_ON_5G; ++band) {
- for (path = ODM_RF_PATH_A; path <= ODM_RF_PATH_D; ++path) {
- for (txNum = RF_1TX; txNum < RF_MAX_TX_NUM; ++txNum) {
- /* CCK */
- base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_11M);
- for (i = 0; i < ARRAY_SIZE(cckRates); ++i) {
- value = PHY_GetTxPowerByRate(padapter, band, path, txNum, cckRates[i]);
- PHY_SetTxPowerByRate(padapter, band, path, txNum, cckRates[i], value - base);
- }
- /* OFDM */
- base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_54M);
- for (i = 0; i < sizeof(ofdmRates); ++i) {
- value = PHY_GetTxPowerByRate(padapter, band, path, txNum, ofdmRates[i]);
- PHY_SetTxPowerByRate(padapter, band, path, txNum, ofdmRates[i], value - base);
- }
-
- /* HT MCS0~7 */
- base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_MCS7);
- for (i = 0; i < sizeof(mcs0_7Rates); ++i) {
- value = PHY_GetTxPowerByRate(padapter, band, path, txNum, mcs0_7Rates[i]);
- PHY_SetTxPowerByRate(padapter, band, path, txNum, mcs0_7Rates[i], value - base);
- }
-
- /* HT MCS8~15 */
- base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_MCS15);
- for (i = 0; i < sizeof(mcs8_15Rates); ++i) {
- value = PHY_GetTxPowerByRate(padapter, band, path, txNum, mcs8_15Rates[i]);
- PHY_SetTxPowerByRate(padapter, band, path, txNum, mcs8_15Rates[i], value - base);
- }
+ for (path = ODM_RF_PATH_A; path <= ODM_RF_PATH_D; ++path) {
+ for (txNum = RF_1TX; txNum < RF_MAX_TX_NUM; ++txNum) {
+ /* CCK */
+ base = PHY_GetTxPowerByRate(padapter, path, txNum, MGN_11M);
+ for (i = 0; i < ARRAY_SIZE(cckRates); ++i) {
+ value = PHY_GetTxPowerByRate(padapter, path, txNum, cckRates[i]);
+ PHY_SetTxPowerByRate(padapter, path, txNum, cckRates[i], value - base);
+ }
- /* HT MCS16~23 */
- base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_MCS23);
- for (i = 0; i < sizeof(mcs16_23Rates); ++i) {
- value = PHY_GetTxPowerByRate(padapter, band, path, txNum, mcs16_23Rates[i]);
- PHY_SetTxPowerByRate(padapter, band, path, txNum, mcs16_23Rates[i], value - base);
- }
+ /* OFDM */
+ base = PHY_GetTxPowerByRate(padapter, path, txNum, MGN_54M);
+ for (i = 0; i < sizeof(ofdmRates); ++i) {
+ value = PHY_GetTxPowerByRate(padapter, path, txNum, ofdmRates[i]);
+ PHY_SetTxPowerByRate(padapter, path, txNum, ofdmRates[i], value - base);
+ }
- /* VHT 1SS */
- base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_VHT1SS_MCS7);
- for (i = 0; i < sizeof(vht1ssRates); ++i) {
- value = PHY_GetTxPowerByRate(padapter, band, path, txNum, vht1ssRates[i]);
- PHY_SetTxPowerByRate(padapter, band, path, txNum, vht1ssRates[i], value - base);
- }
+ /* HT MCS0~7 */
+ base = PHY_GetTxPowerByRate(padapter, path, txNum, MGN_MCS7);
+ for (i = 0; i < sizeof(mcs0_7Rates); ++i) {
+ value = PHY_GetTxPowerByRate(padapter, path, txNum, mcs0_7Rates[i]);
+ PHY_SetTxPowerByRate(padapter, path, txNum, mcs0_7Rates[i], value - base);
+ }
- /* VHT 2SS */
- base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_VHT2SS_MCS7);
- for (i = 0; i < sizeof(vht2ssRates); ++i) {
- value = PHY_GetTxPowerByRate(padapter, band, path, txNum, vht2ssRates[i]);
- PHY_SetTxPowerByRate(padapter, band, path, txNum, vht2ssRates[i], value - base);
- }
+ /* HT MCS8~15 */
+ base = PHY_GetTxPowerByRate(padapter, path, txNum, MGN_MCS15);
+ for (i = 0; i < sizeof(mcs8_15Rates); ++i) {
+ value = PHY_GetTxPowerByRate(padapter, path, txNum, mcs8_15Rates[i]);
+ PHY_SetTxPowerByRate(padapter, path, txNum, mcs8_15Rates[i], value - base);
+ }
- /* VHT 3SS */
- base = PHY_GetTxPowerByRate(padapter, band, path, txNum, MGN_VHT3SS_MCS7);
- for (i = 0; i < sizeof(vht3ssRates); ++i) {
- value = PHY_GetTxPowerByRate(padapter, band, path, txNum, vht3ssRates[i]);
- PHY_SetTxPowerByRate(padapter, band, path, txNum, vht3ssRates[i], value - base);
- }
+ /* HT MCS16~23 */
+ base = PHY_GetTxPowerByRate(padapter, path, txNum, MGN_MCS23);
+ for (i = 0; i < sizeof(mcs16_23Rates); ++i) {
+ value = PHY_GetTxPowerByRate(padapter, path, txNum, mcs16_23Rates[i]);
+ PHY_SetTxPowerByRate(padapter, path, txNum, mcs16_23Rates[i], value - base);
}
}
}
@@ -881,11 +596,10 @@ void PHY_SetTxPowerIndexByRateSection(
if (RateSection == CCK) {
u8 cckRates[] = {MGN_1M, MGN_2M, MGN_5_5M, MGN_11M};
- if (pHalData->CurrentBandType == BAND_ON_2_4G)
- PHY_SetTxPowerIndexByRateArray(padapter, RFPath,
- pHalData->CurrentChannelBW,
- Channel, cckRates,
- ARRAY_SIZE(cckRates));
+ PHY_SetTxPowerIndexByRateArray(padapter, RFPath,
+ pHalData->CurrentChannelBW,
+ Channel, cckRates,
+ ARRAY_SIZE(cckRates));
} else if (RateSection == OFDM) {
u8 ofdmRates[] = {MGN_6M, MGN_9M, MGN_12M, MGN_18M, MGN_24M, MGN_36M, MGN_48M, MGN_54M};
@@ -922,67 +636,7 @@ void PHY_SetTxPowerIndexByRateSection(
Channel, htRates4T,
ARRAY_SIZE(htRates4T));
- } else if (RateSection == VHT_1SSMCS0_1SSMCS9) {
- u8 vhtRates1T[] = {MGN_VHT1SS_MCS0, MGN_VHT1SS_MCS1, MGN_VHT1SS_MCS2, MGN_VHT1SS_MCS3, MGN_VHT1SS_MCS4,
- MGN_VHT1SS_MCS5, MGN_VHT1SS_MCS6, MGN_VHT1SS_MCS7, MGN_VHT1SS_MCS8, MGN_VHT1SS_MCS9};
- PHY_SetTxPowerIndexByRateArray(padapter, RFPath,
- pHalData->CurrentChannelBW,
- Channel, vhtRates1T,
- ARRAY_SIZE(vhtRates1T));
-
- } else if (RateSection == VHT_2SSMCS0_2SSMCS9) {
- u8 vhtRates2T[] = {MGN_VHT2SS_MCS0, MGN_VHT2SS_MCS1, MGN_VHT2SS_MCS2, MGN_VHT2SS_MCS3, MGN_VHT2SS_MCS4,
- MGN_VHT2SS_MCS5, MGN_VHT2SS_MCS6, MGN_VHT2SS_MCS7, MGN_VHT2SS_MCS8, MGN_VHT2SS_MCS9};
-
- PHY_SetTxPowerIndexByRateArray(padapter, RFPath,
- pHalData->CurrentChannelBW,
- Channel, vhtRates2T,
- ARRAY_SIZE(vhtRates2T));
- } else if (RateSection == VHT_3SSMCS0_3SSMCS9) {
- u8 vhtRates3T[] = {MGN_VHT3SS_MCS0, MGN_VHT3SS_MCS1, MGN_VHT3SS_MCS2, MGN_VHT3SS_MCS3, MGN_VHT3SS_MCS4,
- MGN_VHT3SS_MCS5, MGN_VHT3SS_MCS6, MGN_VHT3SS_MCS7, MGN_VHT3SS_MCS8, MGN_VHT3SS_MCS9};
-
- PHY_SetTxPowerIndexByRateArray(padapter, RFPath,
- pHalData->CurrentChannelBW,
- Channel, vhtRates3T,
- ARRAY_SIZE(vhtRates3T));
- } else if (RateSection == VHT_4SSMCS0_4SSMCS9) {
- u8 vhtRates4T[] = {MGN_VHT4SS_MCS0, MGN_VHT4SS_MCS1, MGN_VHT4SS_MCS2, MGN_VHT4SS_MCS3, MGN_VHT4SS_MCS4,
- MGN_VHT4SS_MCS5, MGN_VHT4SS_MCS6, MGN_VHT4SS_MCS7, MGN_VHT4SS_MCS8, MGN_VHT4SS_MCS9};
-
- PHY_SetTxPowerIndexByRateArray(padapter, RFPath,
- pHalData->CurrentChannelBW,
- Channel, vhtRates4T,
- ARRAY_SIZE(vhtRates4T));
- }
-}
-
-static bool phy_GetChnlIndex(u8 Channel, u8 *ChannelIdx)
-{
- u8 channel5G[CHANNEL_MAX_NUMBER_5G] = {
- 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 100, 102,
- 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130,
- 132, 134, 136, 138, 140, 142, 144, 149, 151, 153, 155, 157, 159, 161,
- 163, 165, 167, 168, 169, 171, 173, 175, 177
- };
- u8 i = 0;
- bool bIn24G = true;
-
- if (Channel <= 14) {
- bIn24G = true;
- *ChannelIdx = Channel-1;
- } else {
- bIn24G = false;
-
- for (i = 0; i < ARRAY_SIZE(channel5G); ++i) {
- if (channel5G[i] == Channel) {
- *ChannelIdx = i;
- return bIn24G;
- }
- }
}
-
- return bIn24G;
}
u8 PHY_GetTxPowerIndexBase(
@@ -990,110 +644,45 @@ u8 PHY_GetTxPowerIndexBase(
u8 RFPath,
u8 Rate,
enum channel_width BandWidth,
- u8 Channel,
- bool *bIn24G
+ u8 Channel
)
{
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
- u8 i = 0; /* default set to 1S */
u8 txPower = 0;
u8 chnlIdx = (Channel-1);
if (HAL_IsLegalChannel(padapter, Channel) == false)
chnlIdx = 0;
- *bIn24G = phy_GetChnlIndex(Channel, &chnlIdx);
-
- if (*bIn24G) { /* 3 ============================== 2.4 G ============================== */
- if (IS_CCK_RATE(Rate))
- txPower = pHalData->Index24G_CCK_Base[RFPath][chnlIdx];
- else if (MGN_6M <= Rate)
- txPower = pHalData->Index24G_BW40_Base[RFPath][chnlIdx];
-
- /* OFDM-1T */
- if ((MGN_6M <= Rate && Rate <= MGN_54M) && !IS_CCK_RATE(Rate))
- txPower += pHalData->OFDM_24G_Diff[RFPath][TX_1S];
-
- if (BandWidth == CHANNEL_WIDTH_20) { /* BW20-1S, BW20-2S */
- if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW20_24G_Diff[RFPath][TX_1S];
- if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW20_24G_Diff[RFPath][TX_2S];
- if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW20_24G_Diff[RFPath][TX_3S];
- if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW20_24G_Diff[RFPath][TX_4S];
-
- } else if (BandWidth == CHANNEL_WIDTH_40) { /* BW40-1S, BW40-2S */
- if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW40_24G_Diff[RFPath][TX_1S];
- if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW40_24G_Diff[RFPath][TX_2S];
- if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW40_24G_Diff[RFPath][TX_3S];
- if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW40_24G_Diff[RFPath][TX_4S];
-
- }
- /* Willis suggest adopt BW 40M power index while in BW 80 mode */
- else if (BandWidth == CHANNEL_WIDTH_80) {
- if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW40_24G_Diff[RFPath][TX_1S];
- if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW40_24G_Diff[RFPath][TX_2S];
- if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW40_24G_Diff[RFPath][TX_3S];
- if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW40_24G_Diff[RFPath][TX_4S];
+ if (IS_CCK_RATE(Rate))
+ txPower = pHalData->Index24G_CCK_Base[RFPath][chnlIdx];
+ else if (MGN_6M <= Rate)
+ txPower = pHalData->Index24G_BW40_Base[RFPath][chnlIdx];
+
+ /* OFDM-1T */
+ if ((MGN_6M <= Rate && Rate <= MGN_54M) && !IS_CCK_RATE(Rate))
+ txPower += pHalData->OFDM_24G_Diff[RFPath][TX_1S];
+
+ if (BandWidth == CHANNEL_WIDTH_20) { /* BW20-1S, BW20-2S */
+ if (MGN_MCS0 <= Rate && Rate <= MGN_MCS31)
+ txPower += pHalData->BW20_24G_Diff[RFPath][TX_1S];
+ if (MGN_MCS8 <= Rate && Rate <= MGN_MCS31)
+ txPower += pHalData->BW20_24G_Diff[RFPath][TX_2S];
+ if (MGN_MCS16 <= Rate && Rate <= MGN_MCS31)
+ txPower += pHalData->BW20_24G_Diff[RFPath][TX_3S];
+ if (MGN_MCS24 <= Rate && Rate <= MGN_MCS31)
+ txPower += pHalData->BW20_24G_Diff[RFPath][TX_4S];
+
+ } else if (BandWidth == CHANNEL_WIDTH_40) { /* BW40-1S, BW40-2S */
+ if (MGN_MCS0 <= Rate && Rate <= MGN_MCS31)
+ txPower += pHalData->BW40_24G_Diff[RFPath][TX_1S];
+ if (MGN_MCS8 <= Rate && Rate <= MGN_MCS31)
+ txPower += pHalData->BW40_24G_Diff[RFPath][TX_2S];
+ if (MGN_MCS16 <= Rate && Rate <= MGN_MCS31)
+ txPower += pHalData->BW40_24G_Diff[RFPath][TX_3S];
+ if (MGN_MCS24 <= Rate && Rate <= MGN_MCS31)
+ txPower += pHalData->BW40_24G_Diff[RFPath][TX_4S];
- }
- } else {/* 3 ============================== 5 G ============================== */
- if (MGN_6M <= Rate)
- txPower = pHalData->Index5G_BW40_Base[RFPath][chnlIdx];
-
- /* OFDM-1T */
- if ((MGN_6M <= Rate && Rate <= MGN_54M) && !IS_CCK_RATE(Rate))
- txPower += pHalData->OFDM_5G_Diff[RFPath][TX_1S];
-
- /* BW20-1S, BW20-2S */
- if (BandWidth == CHANNEL_WIDTH_20) {
- if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW20_5G_Diff[RFPath][TX_1S];
- if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW20_5G_Diff[RFPath][TX_2S];
- if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW20_5G_Diff[RFPath][TX_3S];
- if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW20_5G_Diff[RFPath][TX_4S];
-
- } else if (BandWidth == CHANNEL_WIDTH_40) { /* BW40-1S, BW40-2S */
- if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW40_5G_Diff[RFPath][TX_1S];
- if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW40_5G_Diff[RFPath][TX_2S];
- if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW40_5G_Diff[RFPath][TX_3S];
- if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW40_5G_Diff[RFPath][TX_4S];
-
- } else if (BandWidth == CHANNEL_WIDTH_80) { /* BW80-1S, BW80-2S */
- /* <20121220, Kordan> Get the index of array "Index5G_BW80_Base". */
- u8 channel5G_80M[CHANNEL_MAX_NUMBER_5G_80M] = {42, 58, 106, 122, 138, 155, 171};
- for (i = 0; i < ARRAY_SIZE(channel5G_80M); ++i)
- if (channel5G_80M[i] == Channel)
- chnlIdx = i;
-
- txPower = pHalData->Index5G_BW80_Base[RFPath][chnlIdx];
-
- if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += + pHalData->BW80_5G_Diff[RFPath][TX_1S];
- if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW80_5G_Diff[RFPath][TX_2S];
- if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW80_5G_Diff[RFPath][TX_3S];
- if ((MGN_MCS23 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9))
- txPower += pHalData->BW80_5G_Diff[RFPath][TX_4S];
- }
}
return txPower;
@@ -1252,126 +841,6 @@ u8 PHY_GetRateIndexOfTxPowerByRate(u8 Rate)
case MGN_MCS31:
index = 43;
break;
- case MGN_VHT1SS_MCS0:
- index = 44;
- break;
- case MGN_VHT1SS_MCS1:
- index = 45;
- break;
- case MGN_VHT1SS_MCS2:
- index = 46;
- break;
- case MGN_VHT1SS_MCS3:
- index = 47;
- break;
- case MGN_VHT1SS_MCS4:
- index = 48;
- break;
- case MGN_VHT1SS_MCS5:
- index = 49;
- break;
- case MGN_VHT1SS_MCS6:
- index = 50;
- break;
- case MGN_VHT1SS_MCS7:
- index = 51;
- break;
- case MGN_VHT1SS_MCS8:
- index = 52;
- break;
- case MGN_VHT1SS_MCS9:
- index = 53;
- break;
- case MGN_VHT2SS_MCS0:
- index = 54;
- break;
- case MGN_VHT2SS_MCS1:
- index = 55;
- break;
- case MGN_VHT2SS_MCS2:
- index = 56;
- break;
- case MGN_VHT2SS_MCS3:
- index = 57;
- break;
- case MGN_VHT2SS_MCS4:
- index = 58;
- break;
- case MGN_VHT2SS_MCS5:
- index = 59;
- break;
- case MGN_VHT2SS_MCS6:
- index = 60;
- break;
- case MGN_VHT2SS_MCS7:
- index = 61;
- break;
- case MGN_VHT2SS_MCS8:
- index = 62;
- break;
- case MGN_VHT2SS_MCS9:
- index = 63;
- break;
- case MGN_VHT3SS_MCS0:
- index = 64;
- break;
- case MGN_VHT3SS_MCS1:
- index = 65;
- break;
- case MGN_VHT3SS_MCS2:
- index = 66;
- break;
- case MGN_VHT3SS_MCS3:
- index = 67;
- break;
- case MGN_VHT3SS_MCS4:
- index = 68;
- break;
- case MGN_VHT3SS_MCS5:
- index = 69;
- break;
- case MGN_VHT3SS_MCS6:
- index = 70;
- break;
- case MGN_VHT3SS_MCS7:
- index = 71;
- break;
- case MGN_VHT3SS_MCS8:
- index = 72;
- break;
- case MGN_VHT3SS_MCS9:
- index = 73;
- break;
- case MGN_VHT4SS_MCS0:
- index = 74;
- break;
- case MGN_VHT4SS_MCS1:
- index = 75;
- break;
- case MGN_VHT4SS_MCS2:
- index = 76;
- break;
- case MGN_VHT4SS_MCS3:
- index = 77;
- break;
- case MGN_VHT4SS_MCS4:
- index = 78;
- break;
- case MGN_VHT4SS_MCS5:
- index = 79;
- break;
- case MGN_VHT4SS_MCS6:
- index = 80;
- break;
- case MGN_VHT4SS_MCS7:
- index = 81;
- break;
- case MGN_VHT4SS_MCS8:
- index = 82;
- break;
- case MGN_VHT4SS_MCS9:
- index = 83;
- break;
default:
break;
}
@@ -1379,7 +848,7 @@ u8 PHY_GetRateIndexOfTxPowerByRate(u8 Rate)
}
s8 PHY_GetTxPowerByRate(
- struct adapter *padapter, u8 Band, u8 RFPath, u8 TxNum, u8 Rate
+ struct adapter *padapter, u8 RFPath, u8 TxNum, u8 Rate
)
{
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
@@ -1390,9 +859,6 @@ s8 PHY_GetTxPowerByRate(
padapter->registrypriv.RegEnableTxPowerByRate == 0)
return 0;
- if (Band != BAND_ON_2_4G && Band != BAND_ON_5G)
- return value;
-
if (RFPath > ODM_RF_PATH_D)
return value;
@@ -1402,13 +868,12 @@ s8 PHY_GetTxPowerByRate(
if (rateIndex >= TX_PWR_BY_RATE_NUM_RATE)
return value;
- return pHalData->TxPwrByRateOffset[Band][RFPath][TxNum][rateIndex];
+ return pHalData->TxPwrByRateOffset[RFPath][TxNum][rateIndex];
}
void PHY_SetTxPowerByRate(
struct adapter *padapter,
- u8 Band,
u8 RFPath,
u8 TxNum,
u8 Rate,
@@ -1418,9 +883,6 @@ void PHY_SetTxPowerByRate(
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
u8 rateIndex = PHY_GetRateIndexOfTxPowerByRate(Rate);
- if (Band != BAND_ON_2_4G && Band != BAND_ON_5G)
- return;
-
if (RFPath > ODM_RF_PATH_D)
return;
@@ -1430,18 +892,16 @@ void PHY_SetTxPowerByRate(
if (rateIndex >= TX_PWR_BY_RATE_NUM_RATE)
return;
- pHalData->TxPwrByRateOffset[Band][RFPath][TxNum][rateIndex] = Value;
+ pHalData->TxPwrByRateOffset[RFPath][TxNum][rateIndex] = Value;
}
void PHY_SetTxPowerLevelByPath(struct adapter *Adapter, u8 channel, u8 path)
{
struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
- bool bIsIn24G = (pHalData->CurrentBandType == BAND_ON_2_4G);
/* if (pMgntInfo->RegNByteAccess == 0) */
{
- if (bIsIn24G)
- PHY_SetTxPowerIndexByRateSection(Adapter, path, channel, CCK);
+ PHY_SetTxPowerIndexByRateSection(Adapter, path, channel, CCK);
PHY_SetTxPowerIndexByRateSection(Adapter, path, channel, OFDM);
PHY_SetTxPowerIndexByRateSection(Adapter, path, channel, HT_MCS0_MCS7);
@@ -1483,26 +943,9 @@ static s8 phy_GetWorldWideLimit(s8 *LimitTable)
return min;
}
-static s8 phy_GetChannelIndexOfTxPowerLimit(u8 Band, u8 Channel)
+static s8 phy_GetChannelIndexOfTxPowerLimit(u8 Channel)
{
- s8 channelIndex = -1;
- u8 channel5G[CHANNEL_MAX_NUMBER_5G] = {
- 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 100, 102,
- 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130,
- 132, 134, 136, 138, 140, 142, 144, 149, 151, 153, 155, 157, 159, 161,
- 163, 165, 167, 168, 169, 171, 173, 175, 177
- };
- u8 i = 0;
- if (Band == BAND_ON_2_4G)
- channelIndex = Channel - 1;
- else if (Band == BAND_ON_5G) {
- for (i = 0; i < ARRAY_SIZE(channel5G); ++i) {
- if (channel5G[i] == Channel)
- channelIndex = i;
- }
- }
-
- return channelIndex;
+ return Channel - 1;
}
static s16 get_bandwidth_idx(const enum channel_width bandwidth)
@@ -1512,10 +955,6 @@ static s16 get_bandwidth_idx(const enum channel_width bandwidth)
return 0;
case CHANNEL_WIDTH_40:
return 1;
- case CHANNEL_WIDTH_80:
- return 2;
- case CHANNEL_WIDTH_160:
- return 3;
default:
return -1;
}
@@ -1541,42 +980,22 @@ static s16 get_rate_sctn_idx(const u8 rate)
case MGN_MCS24: case MGN_MCS25: case MGN_MCS26: case MGN_MCS27:
case MGN_MCS28: case MGN_MCS29: case MGN_MCS30: case MGN_MCS31:
return 5;
- case MGN_VHT1SS_MCS0: case MGN_VHT1SS_MCS1: case MGN_VHT1SS_MCS2:
- case MGN_VHT1SS_MCS3: case MGN_VHT1SS_MCS4: case MGN_VHT1SS_MCS5:
- case MGN_VHT1SS_MCS6: case MGN_VHT1SS_MCS7: case MGN_VHT1SS_MCS8:
- case MGN_VHT1SS_MCS9:
- return 6;
- case MGN_VHT2SS_MCS0: case MGN_VHT2SS_MCS1: case MGN_VHT2SS_MCS2:
- case MGN_VHT2SS_MCS3: case MGN_VHT2SS_MCS4: case MGN_VHT2SS_MCS5:
- case MGN_VHT2SS_MCS6: case MGN_VHT2SS_MCS7: case MGN_VHT2SS_MCS8:
- case MGN_VHT2SS_MCS9:
- return 7;
- case MGN_VHT3SS_MCS0: case MGN_VHT3SS_MCS1: case MGN_VHT3SS_MCS2:
- case MGN_VHT3SS_MCS3: case MGN_VHT3SS_MCS4: case MGN_VHT3SS_MCS5:
- case MGN_VHT3SS_MCS6: case MGN_VHT3SS_MCS7: case MGN_VHT3SS_MCS8:
- case MGN_VHT3SS_MCS9:
- return 8;
- case MGN_VHT4SS_MCS0: case MGN_VHT4SS_MCS1: case MGN_VHT4SS_MCS2:
- case MGN_VHT4SS_MCS3: case MGN_VHT4SS_MCS4: case MGN_VHT4SS_MCS5:
- case MGN_VHT4SS_MCS6: case MGN_VHT4SS_MCS7: case MGN_VHT4SS_MCS8:
- case MGN_VHT4SS_MCS9:
- return 9;
default:
return -1;
}
}
s8 phy_get_tx_pwr_lmt(struct adapter *adapter, u32 reg_pwr_tbl_sel,
- enum band_type band_type, enum channel_width bandwidth,
+ enum channel_width bandwidth,
u8 rf_path, u8 data_rate, u8 channel)
{
- s16 idx_band = -1;
s16 idx_regulation = -1;
s16 idx_bandwidth = -1;
s16 idx_rate_sctn = -1;
s16 idx_channel = -1;
s8 pwr_lmt = MAX_POWER_INDEX;
struct hal_com_data *hal_data = GET_HAL_DATA(adapter);
+ s8 limits[10] = {0}; u8 i = 0;
if (((adapter->registrypriv.RegEnableTxPowerLimit == 2) &&
(hal_data->EEPROMRegulatory != 1)) ||
@@ -1597,17 +1016,10 @@ s8 phy_get_tx_pwr_lmt(struct adapter *adapter, u32 reg_pwr_tbl_sel,
idx_regulation = TXPWR_LMT_WW;
break;
default:
- idx_regulation = (band_type == BAND_ON_2_4G) ?
- hal_data->Regulation2_4G :
- hal_data->Regulation5G;
+ idx_regulation = hal_data->Regulation2_4G;
break;
}
- if (band_type == BAND_ON_2_4G)
- idx_band = 0;
- else if (band_type == BAND_ON_5G)
- idx_band = 1;
-
idx_bandwidth = get_bandwidth_idx(bandwidth);
idx_rate_sctn = get_rate_sctn_idx(data_rate);
@@ -1617,107 +1029,30 @@ s8 phy_get_tx_pwr_lmt(struct adapter *adapter, u32 reg_pwr_tbl_sel,
/* HT on 80M will reference to HT on 40M */
if (idx_rate_sctn == 0 || idx_rate_sctn == 1)
idx_bandwidth = 0;
- else if ((idx_rate_sctn == 2 || idx_rate_sctn == 3) &&
- (band_type == BAND_ON_5G) && (idx_bandwidth == 2))
- idx_bandwidth = 1;
- if (band_type == BAND_ON_2_4G || band_type == BAND_ON_5G)
- channel = phy_GetChannelIndexOfTxPowerLimit(band_type, channel);
+ channel = phy_GetChannelIndexOfTxPowerLimit(channel);
- if (idx_band == -1 || idx_regulation == -1 || idx_bandwidth == -1 ||
+ if (idx_regulation == -1 || idx_bandwidth == -1 ||
idx_rate_sctn == -1 || idx_channel == -1)
return MAX_POWER_INDEX;
- if (band_type == BAND_ON_2_4G) {
- s8 limits[10] = {0}; u8 i = 0;
-
- for (i = 0; i < MAX_REGULATION_NUM; i++)
- limits[i] = hal_data->TxPwrLimit_2_4G[i]
- [idx_bandwidth]
- [idx_rate_sctn]
- [idx_channel]
- [rf_path];
-
- pwr_lmt = (idx_regulation == TXPWR_LMT_WW) ?
- phy_GetWorldWideLimit(limits) :
- hal_data->TxPwrLimit_2_4G[idx_regulation]
- [idx_bandwidth]
- [idx_rate_sctn]
- [idx_channel]
- [rf_path];
-
- } else if (band_type == BAND_ON_5G) {
- s8 limits[10] = {0}; u8 i = 0;
-
- for (i = 0; i < MAX_REGULATION_NUM; ++i)
- limits[i] = hal_data->TxPwrLimit_5G[i]
- [idx_bandwidth]
- [idx_rate_sctn]
- [idx_channel]
- [rf_path];
-
- pwr_lmt = (idx_regulation == TXPWR_LMT_WW) ?
- phy_GetWorldWideLimit(limits) :
- hal_data->TxPwrLimit_5G[idx_regulation]
- [idx_bandwidth]
- [idx_rate_sctn]
- [idx_channel]
- [rf_path];
- }
- return pwr_lmt;
-}
+ for (i = 0; i < MAX_REGULATION_NUM; i++)
+ limits[i] = hal_data->TxPwrLimit_2_4G[i]
+ [idx_bandwidth]
+ [idx_rate_sctn]
+ [idx_channel]
+ [rf_path];
-static void phy_CrossReferenceHTAndVHTTxPowerLimit(struct adapter *padapter)
-{
- struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
- u8 regulation, bw, channel, rateSection;
- s8 tempPwrLmt = 0;
+ pwr_lmt = (idx_regulation == TXPWR_LMT_WW) ?
+ phy_GetWorldWideLimit(limits) :
+ hal_data->TxPwrLimit_2_4G[idx_regulation]
+ [idx_bandwidth]
+ [idx_rate_sctn]
+ [idx_channel]
+ [rf_path];
- for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) {
- for (bw = 0; bw < MAX_5G_BANDWIDTH_NUM; ++bw) {
- for (channel = 0; channel < CHANNEL_MAX_NUMBER_5G; ++channel) {
- for (rateSection = 0; rateSection < MAX_RATE_SECTION_NUM; ++rateSection) {
- tempPwrLmt = pHalData->TxPwrLimit_5G[regulation][bw][rateSection][channel][ODM_RF_PATH_A];
- if (tempPwrLmt == MAX_POWER_INDEX) {
- u8 baseSection = 2, refSection = 6;
- if (bw == 0 || bw == 1) { /* 5G 20M 40M VHT and HT can cross reference */
- /* 1, bw, rateSection, channel, ODM_RF_PATH_A); */
- if (rateSection >= 2 && rateSection <= 9) {
- if (rateSection == 2) {
- baseSection = 2;
- refSection = 6;
- } else if (rateSection == 3) {
- baseSection = 3;
- refSection = 7;
- } else if (rateSection == 4) {
- baseSection = 4;
- refSection = 8;
- } else if (rateSection == 5) {
- baseSection = 5;
- refSection = 9;
- } else if (rateSection == 6) {
- baseSection = 6;
- refSection = 2;
- } else if (rateSection == 7) {
- baseSection = 7;
- refSection = 3;
- } else if (rateSection == 8) {
- baseSection = 8;
- refSection = 4;
- } else if (rateSection == 9) {
- baseSection = 9;
- refSection = 5;
- }
- pHalData->TxPwrLimit_5G[regulation][bw][baseSection][channel][ODM_RF_PATH_A] =
- pHalData->TxPwrLimit_5G[regulation][bw][refSection][channel][ODM_RF_PATH_A];
- }
- }
- }
- }
- }
- }
- }
+ return pwr_lmt;
}
void PHY_ConvertTxPowerLimitToPowerIndex(struct adapter *Adapter)
@@ -1728,8 +1063,6 @@ void PHY_ConvertTxPowerLimitToPowerIndex(struct adapter *Adapter)
s8 tempValue = 0, tempPwrLmt = 0;
u8 rfPath = 0;
- phy_CrossReferenceHTAndVHTTxPowerLimit(Adapter);
-
for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) {
for (bw = 0; bw < MAX_2_4G_BANDWIDTH_NUM; ++bw) {
for (channel = 0; channel < CHANNEL_MAX_NUMBER_2G; ++channel) {
@@ -1739,17 +1072,17 @@ void PHY_ConvertTxPowerLimitToPowerIndex(struct adapter *Adapter)
for (rfPath = ODM_RF_PATH_A; rfPath < MAX_RF_PATH_NUM; ++rfPath) {
if (pHalData->odmpriv.PhyRegPgValueType == PHY_REG_PG_EXACT_VALUE) {
if (rateSection == 5) /* HT 4T */
- BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, BAND_ON_2_4G, rfPath, RF_4TX, HT_MCS24_MCS31);
+ BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, rfPath, RF_4TX, HT_MCS24_MCS31);
else if (rateSection == 4) /* HT 3T */
- BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, BAND_ON_2_4G, rfPath, RF_3TX, HT_MCS16_MCS23);
+ BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, rfPath, RF_3TX, HT_MCS16_MCS23);
else if (rateSection == 3) /* HT 2T */
- BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, BAND_ON_2_4G, rfPath, RF_2TX, HT_MCS8_MCS15);
+ BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, rfPath, RF_2TX, HT_MCS8_MCS15);
else if (rateSection == 2) /* HT 1T */
- BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, BAND_ON_2_4G, rfPath, RF_1TX, HT_MCS0_MCS7);
+ BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, rfPath, RF_1TX, HT_MCS0_MCS7);
else if (rateSection == 1) /* OFDM */
- BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, BAND_ON_2_4G, rfPath, RF_1TX, OFDM);
+ BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, rfPath, RF_1TX, OFDM);
else if (rateSection == 0) /* CCK */
- BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, BAND_ON_2_4G, rfPath, RF_1TX, CCK);
+ BW40PwrBasedBm2_4G = PHY_GetTxPowerByRateBase(Adapter, rfPath, RF_1TX, CCK);
} else
BW40PwrBasedBm2_4G = Adapter->registrypriv.RegPowerBase * 2;
@@ -1776,20 +1109,11 @@ void PHY_InitTxPowerLimit(struct adapter *Adapter)
for (l = 0; l < MAX_RF_PATH_NUM; ++l)
pHalData->TxPwrLimit_2_4G[i][j][k][m][l] = MAX_POWER_INDEX;
}
-
- for (i = 0; i < MAX_REGULATION_NUM; ++i) {
- for (j = 0; j < MAX_5G_BANDWIDTH_NUM; ++j)
- for (k = 0; k < MAX_RATE_SECTION_NUM; ++k)
- for (m = 0; m < CHANNEL_MAX_NUMBER_5G; ++m)
- for (l = 0; l < MAX_RF_PATH_NUM; ++l)
- pHalData->TxPwrLimit_5G[i][j][k][m][l] = MAX_POWER_INDEX;
- }
}
void PHY_SetTxPowerLimit(
struct adapter *Adapter,
u8 *Regulation,
- u8 *Band,
u8 *Bandwidth,
u8 *RateSection,
u8 *RfPath,
@@ -1827,14 +1151,6 @@ void PHY_SetTxPowerLimit(
rateSection = 4;
else if (eqNByte(RateSection, (u8 *)("HT"), 2) && eqNByte(RfPath, (u8 *)("4T"), 2))
rateSection = 5;
- else if (eqNByte(RateSection, (u8 *)("VHT"), 3) && eqNByte(RfPath, (u8 *)("1T"), 2))
- rateSection = 6;
- else if (eqNByte(RateSection, (u8 *)("VHT"), 3) && eqNByte(RfPath, (u8 *)("2T"), 2))
- rateSection = 7;
- else if (eqNByte(RateSection, (u8 *)("VHT"), 3) && eqNByte(RfPath, (u8 *)("3T"), 2))
- rateSection = 8;
- else if (eqNByte(RateSection, (u8 *)("VHT"), 3) && eqNByte(RfPath, (u8 *)("4T"), 2))
- rateSection = 9;
else
return;
@@ -1847,38 +1163,21 @@ void PHY_SetTxPowerLimit(
else if (eqNByte(Bandwidth, (u8 *)("160M"), 4))
bandwidth = 3;
- if (eqNByte(Band, (u8 *)("2.4G"), 4)) {
- channelIndex = phy_GetChannelIndexOfTxPowerLimit(BAND_ON_2_4G, channel);
+ channelIndex = phy_GetChannelIndexOfTxPowerLimit(channel);
- if (channelIndex == -1)
- return;
-
- prevPowerLimit = pHalData->TxPwrLimit_2_4G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A];
-
- if (powerLimit < prevPowerLimit)
- pHalData->TxPwrLimit_2_4G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A] = powerLimit;
-
- } else if (eqNByte(Band, (u8 *)("5G"), 2)) {
- channelIndex = phy_GetChannelIndexOfTxPowerLimit(BAND_ON_5G, channel);
-
- if (channelIndex == -1)
- return;
-
- prevPowerLimit = pHalData->TxPwrLimit_5G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A];
+ if (channelIndex == -1)
+ return;
- if (powerLimit < prevPowerLimit)
- pHalData->TxPwrLimit_5G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A] = powerLimit;
+ prevPowerLimit = pHalData->TxPwrLimit_2_4G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A];
- } else {
- return;
- }
+ if (powerLimit < prevPowerLimit)
+ pHalData->TxPwrLimit_2_4G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A] = powerLimit;
}
void Hal_ChannelPlanToRegulation(struct adapter *Adapter, u16 ChannelPlan)
{
struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
pHalData->Regulation2_4G = TXPWR_LMT_WW;
- pHalData->Regulation5G = TXPWR_LMT_WW;
switch (ChannelPlan) {
case RT_CHANNEL_DOMAIN_WORLD_NULL:
@@ -1898,139 +1197,105 @@ void Hal_ChannelPlanToRegulation(struct adapter *Adapter, u16 ChannelPlan)
break;
case RT_CHANNEL_DOMAIN_FCC1_FCC1:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_WORLD_ETSI1:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_ETSI;
break;
case RT_CHANNEL_DOMAIN_MKK1_MKK1:
pHalData->Regulation2_4G = TXPWR_LMT_MKK;
- pHalData->Regulation5G = TXPWR_LMT_MKK;
break;
case RT_CHANNEL_DOMAIN_WORLD_KCC1:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_MKK;
break;
case RT_CHANNEL_DOMAIN_WORLD_FCC2:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_WORLD_FCC3:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_WORLD_FCC4:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_WORLD_FCC5:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_WORLD_FCC6:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_FCC1_FCC7:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_WORLD_ETSI2:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_WORLD_ETSI3:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_MKK1_MKK2:
pHalData->Regulation2_4G = TXPWR_LMT_MKK;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_MKK1_MKK3:
pHalData->Regulation2_4G = TXPWR_LMT_MKK;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_FCC1_NCC1:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_FCC1_NCC2:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_GLOBAL_NULL:
pHalData->Regulation2_4G = TXPWR_LMT_WW;
- pHalData->Regulation5G = TXPWR_LMT_WW;
break;
case RT_CHANNEL_DOMAIN_ETSI1_ETSI4:
pHalData->Regulation2_4G = TXPWR_LMT_ETSI;
- pHalData->Regulation5G = TXPWR_LMT_ETSI;
break;
case RT_CHANNEL_DOMAIN_FCC1_FCC2:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_FCC1_NCC3:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_WORLD_ETSI5:
pHalData->Regulation2_4G = TXPWR_LMT_ETSI;
- pHalData->Regulation5G = TXPWR_LMT_ETSI;
break;
case RT_CHANNEL_DOMAIN_FCC1_FCC8:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_WORLD_ETSI6:
pHalData->Regulation2_4G = TXPWR_LMT_ETSI;
- pHalData->Regulation5G = TXPWR_LMT_ETSI;
break;
case RT_CHANNEL_DOMAIN_WORLD_ETSI7:
pHalData->Regulation2_4G = TXPWR_LMT_ETSI;
- pHalData->Regulation5G = TXPWR_LMT_ETSI;
break;
case RT_CHANNEL_DOMAIN_WORLD_ETSI8:
pHalData->Regulation2_4G = TXPWR_LMT_ETSI;
- pHalData->Regulation5G = TXPWR_LMT_ETSI;
break;
case RT_CHANNEL_DOMAIN_WORLD_ETSI9:
pHalData->Regulation2_4G = TXPWR_LMT_ETSI;
- pHalData->Regulation5G = TXPWR_LMT_ETSI;
break;
case RT_CHANNEL_DOMAIN_WORLD_ETSI10:
pHalData->Regulation2_4G = TXPWR_LMT_ETSI;
- pHalData->Regulation5G = TXPWR_LMT_ETSI;
break;
case RT_CHANNEL_DOMAIN_WORLD_ETSI11:
pHalData->Regulation2_4G = TXPWR_LMT_ETSI;
- pHalData->Regulation5G = TXPWR_LMT_ETSI;
break;
case RT_CHANNEL_DOMAIN_FCC1_NCC4:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_WORLD_ETSI12:
pHalData->Regulation2_4G = TXPWR_LMT_ETSI;
- pHalData->Regulation5G = TXPWR_LMT_ETSI;
break;
case RT_CHANNEL_DOMAIN_FCC1_FCC9:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_WORLD_ETSI13:
pHalData->Regulation2_4G = TXPWR_LMT_ETSI;
- pHalData->Regulation5G = TXPWR_LMT_ETSI;
break;
case RT_CHANNEL_DOMAIN_FCC1_FCC10:
pHalData->Regulation2_4G = TXPWR_LMT_FCC;
- pHalData->Regulation5G = TXPWR_LMT_FCC;
break;
case RT_CHANNEL_DOMAIN_REALTEK_DEFINE: /* Realtek Reserve */
pHalData->Regulation2_4G = TXPWR_LMT_WW;
- pHalData->Regulation5G = TXPWR_LMT_WW;
break;
default:
break;
diff --git a/drivers/staging/rtl8723bs/hal/hal_intf.c b/drivers/staging/rtl8723bs/hal/hal_intf.c
index 8dc4dd8c6d4c..4868a69cdb8f 100644
--- a/drivers/staging/rtl8723bs/hal/hal_intf.c
+++ b/drivers/staging/rtl8723bs/hal/hal_intf.c
@@ -4,9 +4,6 @@
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-
-#define _HAL_INTF_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
#include <hal_data.h>
diff --git a/drivers/staging/rtl8723bs/hal/odm.c b/drivers/staging/rtl8723bs/hal/odm.c
index 092b32c41ff3..68dfb77772b2 100644
--- a/drivers/staging/rtl8723bs/hal/odm.c
+++ b/drivers/staging/rtl8723bs/hal/odm.c
@@ -290,8 +290,6 @@ static void odm_CommonInfoSelfInit(struct dm_odm_t *pDM_Odm)
pDM_Odm->bCckHighPower = (bool) PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG(CCK_RPT_FORMAT, pDM_Odm), ODM_BIT(CCK_RPT_FORMAT, pDM_Odm));
pDM_Odm->RFPathRxEnable = (u8) PHY_QueryBBReg(pDM_Odm->Adapter, ODM_REG(BB_RX_PATH, pDM_Odm), ODM_BIT(BB_RX_PATH, pDM_Odm));
- ODM_InitDebugSetting(pDM_Odm);
-
pDM_Odm->TxRate = 0xFF;
}
@@ -323,32 +321,10 @@ static void odm_CommonInfoSelfUpdate(struct dm_odm_t *pDM_Odm)
static void odm_CmnInfoInit_Debug(struct dm_odm_t *pDM_Odm)
{
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoInit_Debug ==>\n"));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportPlatform =%d\n", pDM_Odm->SupportPlatform));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportAbility = 0x%x\n", pDM_Odm->SupportAbility));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportInterface =%d\n", pDM_Odm->SupportInterface));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportICType = 0x%x\n", pDM_Odm->SupportICType));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("CutVersion =%d\n", pDM_Odm->CutVersion));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("FabVersion =%d\n", pDM_Odm->FabVersion));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RFType =%d\n", pDM_Odm->RFType));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("BoardType =%d\n", pDM_Odm->BoardType));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtLNA =%d\n", pDM_Odm->ExtLNA));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtPA =%d\n", pDM_Odm->ExtPA));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtTRSW =%d\n", pDM_Odm->ExtTRSW));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("PatchID =%d\n", pDM_Odm->PatchID));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bInHctTest =%d\n", pDM_Odm->bInHctTest));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFITest =%d\n", pDM_Odm->bWIFITest));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bDualMacSmartConcurrent =%d\n", pDM_Odm->bDualMacSmartConcurrent));
-
}
static void odm_BasicDbgMessage(struct dm_odm_t *pDM_Odm)
{
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_BasicDbgMsg ==>\n"));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bLinked = %d, RSSI_Min = %d,\n",
- pDM_Odm->bLinked, pDM_Odm->RSSI_Min));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RxRate = 0x%x, RSSI_A = %d, RSSI_B = %d\n",
- pDM_Odm->RxRate, pDM_Odm->RSSI_A, pDM_Odm->RSSI_B));
}
/* 3 ============================================================ */
@@ -401,7 +377,6 @@ u32 ODM_Get_Rate_Bitmap(
break;
case (ODM_WM_G):
- case (ODM_WM_A):
if (rssi_level == DM_RATR_STA_HIGH)
rate_bitmap = 0x00000f00;
else
@@ -420,7 +395,6 @@ u32 ODM_Get_Rate_Bitmap(
case (ODM_WM_B|ODM_WM_G|ODM_WM_N24G):
case (ODM_WM_B|ODM_WM_N24G):
case (ODM_WM_G|ODM_WM_N24G):
- case (ODM_WM_A|ODM_WM_N5G):
if (pDM_Odm->RFType == ODM_1T2R || pDM_Odm->RFType == ODM_1T1R) {
if (rssi_level == DM_RATR_STA_HIGH)
rate_bitmap = 0x000f0000;
@@ -446,34 +420,6 @@ u32 ODM_Get_Rate_Bitmap(
}
break;
- case (ODM_WM_AC|ODM_WM_G):
- if (rssi_level == 1)
- rate_bitmap = 0xfc3f0000;
- else if (rssi_level == 2)
- rate_bitmap = 0xfffff000;
- else
- rate_bitmap = 0xffffffff;
- break;
-
- case (ODM_WM_AC|ODM_WM_A):
-
- if (pDM_Odm->RFType == RF_1T1R) {
- if (rssi_level == 1) /* add by Gary for ac-series */
- rate_bitmap = 0x003f8000;
- else if (rssi_level == 2)
- rate_bitmap = 0x003ff000;
- else
- rate_bitmap = 0x003ff010;
- } else {
- if (rssi_level == 1) /* add by Gary for ac-series */
- rate_bitmap = 0xfe3f8000; /* VHT 2SS MCS3~9 */
- else if (rssi_level == 2)
- rate_bitmap = 0xfffff000; /* VHT 2SS MCS0~9 */
- else
- rate_bitmap = 0xfffff010; /* All */
- }
- break;
-
default:
if (pDM_Odm->RFType == RF_1T2R)
rate_bitmap = 0x000fffff;
@@ -482,9 +428,6 @@ u32 ODM_Get_Rate_Bitmap(
break;
}
- /* printk("%s ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x\n", __func__, rssi_level, WirelessMode, rate_bitmap); */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, (" ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x\n", rssi_level, WirelessMode, rate_bitmap));
-
return ra_mask & rate_bitmap;
}
@@ -495,12 +438,10 @@ static void odm_RefreshRateAdaptiveMaskCE(struct dm_odm_t *pDM_Odm)
struct adapter *padapter = pDM_Odm->Adapter;
if (padapter->bDriverStopped) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("<---- odm_RefreshRateAdaptiveMask(): driver is going to unload\n"));
return;
}
if (!pDM_Odm->bUseRAMask) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("<---- odm_RefreshRateAdaptiveMask(): driver does not control rate adaptive mask\n"));
return;
}
@@ -512,7 +453,6 @@ static void odm_RefreshRateAdaptiveMaskCE(struct dm_odm_t *pDM_Odm)
continue;
if (true == ODM_RAStateCheck(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, false, &pstat->rssi_level)) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI:%d, RSSI_LEVEL:%d\n", pstat->rssi_stat.UndecoratedSmoothedPWDB, pstat->rssi_level));
/* printk("RSSI:%d, RSSI_LEVEL:%d\n", pstat->rssi_stat.UndecoratedSmoothedPWDB, pstat->rssi_level); */
rtw_hal_update_ra_mask(pstat, pstat->rssi_level);
}
@@ -541,9 +481,7 @@ static void odm_RefreshRateAdaptiveMaskCE(struct dm_odm_t *pDM_Odm)
static void odm_RefreshRateAdaptiveMask(struct dm_odm_t *pDM_Odm)
{
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("odm_RefreshRateAdaptiveMask()---------->\n"));
if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK)) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("odm_RefreshRateAdaptiveMask(): Return cos not supported\n"));
return;
}
odm_RefreshRateAdaptiveMaskCE(pDM_Odm);
@@ -582,7 +520,8 @@ bool ODM_RAStateCheck(
break;
default:
- ODM_RT_ASSERT(pDM_Odm, false, ("wrong rssi level setting %d !", *pRATRState));
+ netdev_dbg(pDM_Odm->Adapter->pnetdev,
+ "wrong rssi level setting %d !", *pRATRState);
break;
}
@@ -596,7 +535,6 @@ bool ODM_RAStateCheck(
/* printk("==>%s, RATRState:0x%02x , RSSI:%d\n", __func__, RATRState, RSSI); */
if (*pRATRState != RATRState || bForceUpdate) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI Level %d -> %d\n", *pRATRState, RATRState));
*pRATRState = RATRState;
return true;
}
@@ -631,11 +569,8 @@ static void FindMinimumRSSI(struct adapter *padapter)
(pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0)
) {
pdmpriv->MinUndecoratedPWDBForDM = 0;
- /* ODM_RT_TRACE(pDM_Odm, COMP_BB_POWERSAVING, DBG_LOUD, ("Not connected to any\n")); */
} else
pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB;
-
- /* ODM_RT_TRACE(pDM_Odm, COMP_DIG, DBG_LOUD, ("MinUndecoratedPWDBForDM =%d\n", pHalData->MinUndecoratedPWDBForDM)); */
}
static void odm_RSSIMonitorCheckCE(struct dm_odm_t *pDM_Odm)
@@ -838,9 +773,6 @@ void ODM_DMInit(struct dm_odm_t *pDM_Odm)
ODM_ClearTxPowerTrackingState(pDM_Odm);
- if (*(pDM_Odm->mp_mode) != 1)
- odm_PathDiversityInit(pDM_Odm);
-
odm_DynamicBBPowerSavingInit(pDM_Odm);
odm_DynamicTxPowerInit(pDM_Odm);
@@ -858,7 +790,6 @@ void ODM_DMWatchdog(struct dm_odm_t *pDM_Odm)
odm_BasicDbgMessage(pDM_Odm);
odm_FalseAlarmCounterStatistics(pDM_Odm);
odm_NHMCounterStatistics(pDM_Odm);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): RSSI = 0x%x\n", pDM_Odm->RSSI_Min));
odm_RSSIMonitorCheck(pDM_Odm);
@@ -872,8 +803,6 @@ void ODM_DMWatchdog(struct dm_odm_t *pDM_Odm)
/* (pDM_Odm->SupportICType & (ODM_RTL8188E) &&(&&(((pDM_Odm->SupportInterface == ODM_ITRF_SDIO))) */
/* */
) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("----Step1: odm_DIG is in LPS mode\n"));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("---Step2: 8723AS is in LPS mode\n"));
odm_DIGbyRSSI_LPS(pDM_Odm);
} else
odm_DIG(pDM_Odm);
@@ -891,7 +820,6 @@ void ODM_DMWatchdog(struct dm_odm_t *pDM_Odm)
odm_RefreshRateAdaptiveMask(pDM_Odm);
odm_EdcaTurboCheck(pDM_Odm);
- odm_PathDiversity(pDM_Odm);
ODM_CfoTracking(pDM_Odm);
ODM_TXPowerTrackingCheck(pDM_Odm);
@@ -956,10 +884,6 @@ void ODM_CmnInfoInit(struct dm_odm_t *pDM_Odm, enum odm_cmninfo_e CmnInfo, u32 V
pDM_Odm->AntDivType = (u8)Value;
break;
- case ODM_CMNINFO_BOARD_TYPE:
- pDM_Odm->BoardType = (u8)Value;
- break;
-
case ODM_CMNINFO_PACKAGE_TYPE:
pDM_Odm->PackageType = (u8)Value;
break;
@@ -968,18 +892,10 @@ void ODM_CmnInfoInit(struct dm_odm_t *pDM_Odm, enum odm_cmninfo_e CmnInfo, u32 V
pDM_Odm->ExtLNA = (u8)Value;
break;
- case ODM_CMNINFO_5G_EXT_LNA:
- pDM_Odm->ExtLNA5G = (u8)Value;
- break;
-
case ODM_CMNINFO_EXT_PA:
pDM_Odm->ExtPA = (u8)Value;
break;
- case ODM_CMNINFO_5G_EXT_PA:
- pDM_Odm->ExtPA5G = (u8)Value;
- break;
-
case ODM_CMNINFO_GPA:
pDM_Odm->TypeGPA = (enum odm_type_gpa_e)Value;
break;
@@ -1044,10 +960,6 @@ void ODM_CmnInfoHook(struct dm_odm_t *pDM_Odm, enum odm_cmninfo_e CmnInfo, void
pDM_Odm->pwirelessmode = pValue;
break;
- case ODM_CMNINFO_BAND:
- pDM_Odm->pBandType = pValue;
- break;
-
case ODM_CMNINFO_SEC_CHNL_OFFSET:
pDM_Odm->pSecChOffset = pValue;
break;
@@ -1214,13 +1126,6 @@ void ODM_CmnInfoUpdate(struct dm_odm_t *pDM_Odm, u32 CmnInfo, u64 Value)
pDM_Odm->RSSI_Min = (u8)Value;
break;
- case ODM_CMNINFO_DBG_COMP:
- pDM_Odm->DebugComponents = Value;
- break;
-
- case ODM_CMNINFO_DBG_LEVEL:
- pDM_Odm->DebugLevel = (u32)Value;
- break;
case ODM_CMNINFO_RA_THRESHOLD_HIGH:
pDM_Odm->RateAdaptive.HighRSSIThresh = (u8)Value;
break;
@@ -1262,10 +1167,6 @@ void ODM_CmnInfoUpdate(struct dm_odm_t *pDM_Odm, u32 CmnInfo, u64 Value)
pDM_Odm->WirelessMode = (u8)Value;
break;
- case ODM_CMNINFO_BAND:
- pDM_Odm->BandType = (u8)Value;
- break;
-
case ODM_CMNINFO_SEC_CHNL_OFFSET:
pDM_Odm->SecChOffset = (u8)Value;
break;
diff --git a/drivers/staging/rtl8723bs/hal/odm.h b/drivers/staging/rtl8723bs/hal/odm.h
index ff21343fbe0b..abf6547518fb 100644
--- a/drivers/staging/rtl8723bs/hal/odm.h
+++ b/drivers/staging/rtl8723bs/hal/odm.h
@@ -11,7 +11,6 @@
#include "odm_EdcaTurboCheck.h"
#include "odm_DIG.h"
-#include "odm_PathDiv.h"
#include "odm_DynamicBBPowerSaving.h"
#include "odm_DynamicTxPower.h"
#include "odm_CfoTracking.h"
@@ -152,7 +151,6 @@ struct swat_t { /* _SW_Antenna_Switch_ */
bool ANTB_ON; /* To indicate Ant B is on or not */
bool Pre_Aux_FailDetec;
bool RSSI_AntDect_bResult;
- u8 Ant5G;
u8 Ant2G;
s32 RSSI_sum_A;
@@ -197,10 +195,7 @@ struct odm_rate_adaptive {
#define AVG_THERMAL_NUM 8
#define IQK_Matrix_REG_NUM 8
-#define IQK_Matrix_Settings_NUM (14 + 24 + 21) /* Channels_2_4G_NUM
- * + Channels_5G_20M_NUM
- * + Channels_5G
- */
+#define IQK_Matrix_Settings_NUM 14 /* Channels_2_4G_NUM */
#define DM_Type_ByFW 0
#define DM_Type_ByDriver 1
@@ -293,12 +288,9 @@ enum odm_cmninfo_e {
ODM_CMNINFO_FAB_VER, /* ODM_FAB_E */
ODM_CMNINFO_RF_TYPE, /* ODM_RF_PATH_E or ODM_RF_TYPE_E? */
ODM_CMNINFO_RFE_TYPE,
- ODM_CMNINFO_BOARD_TYPE, /* ODM_BOARD_TYPE_E */
ODM_CMNINFO_PACKAGE_TYPE,
ODM_CMNINFO_EXT_LNA, /* true */
- ODM_CMNINFO_5G_EXT_LNA,
ODM_CMNINFO_EXT_PA,
- ODM_CMNINFO_5G_EXT_PA,
ODM_CMNINFO_GPA,
ODM_CMNINFO_APA,
ODM_CMNINFO_GLNA,
@@ -316,7 +308,6 @@ enum odm_cmninfo_e {
ODM_CMNINFO_TX_UNI,
ODM_CMNINFO_RX_UNI,
ODM_CMNINFO_WM_MODE, /* ODM_WIRELESS_MODE_E */
- ODM_CMNINFO_BAND, /* ODM_BAND_TYPE_E */
ODM_CMNINFO_SEC_CHNL_OFFSET, /* ODM_SEC_CHNL_OFFSET_E */
ODM_CMNINFO_SEC_MODE, /* ODM_SECURITY_E */
ODM_CMNINFO_BW, /* ODM_BW_E */
@@ -456,33 +447,17 @@ enum { /* tag_Wireless_Mode_Definition */
ODM_WM_UNKNOWN = 0x0,
ODM_WM_B = BIT0,
ODM_WM_G = BIT1,
- ODM_WM_A = BIT2,
ODM_WM_N24G = BIT3,
- ODM_WM_N5G = BIT4,
ODM_WM_AUTO = BIT5,
- ODM_WM_AC = BIT6,
-};
-
-/* ODM_CMNINFO_BAND */
-enum { /* tag_Band_Type_Definition */
- ODM_BAND_2_4G = 0,
- ODM_BAND_5G,
- ODM_BAND_ON_BOTH,
- ODM_BANDMAX
};
/* ODM_CMNINFO_BW */
enum { /* tag_Bandwidth_Definition */
ODM_BW20M = 0,
ODM_BW40M = 1,
- ODM_BW80M = 2,
- ODM_BW160M = 3,
- ODM_BW10M = 4,
};
-/* ODM_CMNINFO_BOARD_TYPE */
-/* For non-AC-series IC , ODM_BOARD_5G_EXT_PA and ODM_BOARD_5G_EXT_LNA are ignored */
-/* For AC-series IC, external PA & LNA can be indivisuallly added on 2.4G and/or 5G */
+/* For AC-series IC, external PA & LNA can be individually added on 2.4G */
enum odm_type_gpa_e { /* tag_ODM_TYPE_GPA_Definition */
TYPE_GPA0 = 0,
@@ -530,7 +505,6 @@ struct odm_rf_cal_t { /* ODM_RF_Calibration_Structure */
bool bTXPowerTracking;
u8 TxPowerTrackControl; /* for mp mode, turn off txpwrtracking as default */
u8 TM_Trigger;
- u8 InternalPA5G[2]; /* pathA / pathB */
u8 ThermalMeter[2]; /* ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 */
u8 ThermalValue;
@@ -565,7 +539,7 @@ struct odm_rf_cal_t { /* ODM_RF_Calibration_Structure */
bool bIQKInProgress;
u8 Delta_IQK;
u8 Delta_LCK;
- s8 BBSwingDiff2G, BBSwingDiff5G; /* Unit: dB */
+ s8 BBSwingDiff2G; /* Unit: dB */
u8 DeltaSwingTableIdx_2GCCKA_P[DELTA_SWINGIDX_SIZE];
u8 DeltaSwingTableIdx_2GCCKA_N[DELTA_SWINGIDX_SIZE];
u8 DeltaSwingTableIdx_2GCCKB_P[DELTA_SWINGIDX_SIZE];
@@ -574,10 +548,6 @@ struct odm_rf_cal_t { /* ODM_RF_Calibration_Structure */
u8 DeltaSwingTableIdx_2GA_N[DELTA_SWINGIDX_SIZE];
u8 DeltaSwingTableIdx_2GB_P[DELTA_SWINGIDX_SIZE];
u8 DeltaSwingTableIdx_2GB_N[DELTA_SWINGIDX_SIZE];
- u8 DeltaSwingTableIdx_5GA_P[BAND_NUM][DELTA_SWINGIDX_SIZE];
- u8 DeltaSwingTableIdx_5GA_N[BAND_NUM][DELTA_SWINGIDX_SIZE];
- u8 DeltaSwingTableIdx_5GB_P[BAND_NUM][DELTA_SWINGIDX_SIZE];
- u8 DeltaSwingTableIdx_5GB_N[BAND_NUM][DELTA_SWINGIDX_SIZE];
u8 DeltaSwingTableIdx_2GA_P_8188E[DELTA_SWINGIDX_SIZE];
u8 DeltaSwingTableIdx_2GA_N_8188E[DELTA_SWINGIDX_SIZE];
@@ -643,8 +613,6 @@ struct fat_t { /* _FAST_ANTENNA_TRAINNING_ */
bool bBecomeLinked;
u32 MinMaxRSSI;
u8 idx_AntDiv_counter_2G;
- u8 idx_AntDiv_counter_5G;
- u32 AntDiv_2G_5G;
u32 CCK_counter_main;
u32 CCK_counter_aux;
u32 OFDM_counter_main;
@@ -710,9 +678,6 @@ struct dm_odm_t { /* DM_Out_Source_Dynamic_Mechanism_Structure */
enum phy_reg_pg_type PhyRegPgValueType;
u8 PhyRegPgVersion;
- u64 DebugComponents;
- u32 DebugLevel;
-
u32 NumQryPhyStatusAll; /* CCK + OFDM */
u32 LastNumQryPhyStatusAll;
u32 RxPWDBAve;
@@ -766,10 +731,8 @@ struct dm_odm_t { /* DM_Out_Source_Dynamic_Mechanism_Structure */
u8 TypeAPA;
/* with external LNA NO/Yes = 0/1 */
u8 ExtLNA;
- u8 ExtLNA5G;
/* with external PA NO/Yes = 0/1 */
u8 ExtPA;
- u8 ExtPA5G;
/* with external TRSW NO/Yes = 0/1 */
u8 ExtTRSW;
u8 PatchID; /* Customer ID */
@@ -798,8 +761,6 @@ struct dm_odm_t { /* DM_Out_Source_Dynamic_Mechanism_Structure */
u64 *pNumRxBytesUnicast;
/* Wireless mode B/G/A/N = BIT0/BIT1/BIT2/BIT3 */
u8 *pwirelessmode; /* ODM_WIRELESS_MODE_E */
- /* Frequence band 2.4G/5G = 0/1 */
- u8 *pBandType;
/* Secondary channel offset don't_care/below/above = 0/1/2 */
u8 *pSecChOffset;
/* Security mode Open/WEP/AES/TKIP = 0/1/2/3 */
@@ -1068,7 +1029,6 @@ enum ODM_BB_Config_Type {
CONFIG_BB_PHY_REG,
CONFIG_BB_AGC_TAB,
CONFIG_BB_AGC_TAB_2G,
- CONFIG_BB_AGC_TAB_5G,
CONFIG_BB_PHY_REG_PG,
CONFIG_BB_PHY_REG_MP,
CONFIG_BB_AGC_TAB_DIFF,
diff --git a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c
index 75471c6c168e..0f6b9d661e39 100644
--- a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c
+++ b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c
@@ -25,16 +25,6 @@ static void odm_SetCrystalCap(void *pDM_VOID, u8 CrystalCap)
0x00FFF000,
(CrystalCap | (CrystalCap << 6))
);
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CFO_TRACKING,
- ODM_DBG_LOUD,
- (
- "odm_SetCrystalCap(): CrystalCap = 0x%x\n",
- CrystalCap
- )
- );
}
static u8 odm_GetDefaultCrytaltalCap(void *pDM_VOID)
@@ -98,22 +88,6 @@ void ODM_CfoTrackingInit(void *pDM_VOID)
pCfoTrack->CrystalCap = odm_GetDefaultCrytaltalCap(pDM_Odm);
pCfoTrack->bATCStatus = odm_GetATCStatus(pDM_Odm);
pCfoTrack->bAdjust = true;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CFO_TRACKING,
- ODM_DBG_LOUD,
- ("ODM_CfoTracking_init() =========>\n")
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CFO_TRACKING,
- ODM_DBG_LOUD,
- (
- "ODM_CfoTracking_init(): bATCStatus = %d, CrystalCap = 0x%x\n",
- pCfoTrack->bATCStatus,
- pCfoTrack->DefXCap
- )
- );
}
void ODM_CfoTracking(void *pDM_VOID)
@@ -127,47 +101,16 @@ void ODM_CfoTracking(void *pDM_VOID)
/* 4 Support ability */
if (!(pDM_Odm->SupportAbility & ODM_BB_CFO_TRACKING)) {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CFO_TRACKING,
- ODM_DBG_LOUD,
- ("ODM_CfoTracking(): Return: SupportAbility ODM_BB_CFO_TRACKING is disabled\n")
- );
return;
}
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CFO_TRACKING,
- ODM_DBG_LOUD,
- ("ODM_CfoTracking() =========>\n")
- );
-
if (!pDM_Odm->bLinked || !pDM_Odm->bOneEntryOnly) {
/* 4 No link or more than one entry */
ODM_CfoTrackingReset(pDM_Odm);
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CFO_TRACKING,
- ODM_DBG_LOUD,
- (
- "ODM_CfoTracking(): Reset: bLinked = %d, bOneEntryOnly = %d\n",
- pDM_Odm->bLinked,
- pDM_Odm->bOneEntryOnly
- )
- );
} else {
/* 3 1. CFO Tracking */
/* 4 1.1 No new packet */
if (pCfoTrack->packetCount == pCfoTrack->packetCount_pre) {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CFO_TRACKING,
- ODM_DBG_LOUD,
- (
- "ODM_CfoTracking(): packet counter doesn't change\n"
- )
- );
return;
}
pCfoTrack->packetCount_pre = pCfoTrack->packetCount;
@@ -180,17 +123,6 @@ void ODM_CfoTracking(void *pDM_VOID)
CFO_ave = CFO_kHz_A;
else
CFO_ave = (int)(CFO_kHz_A + CFO_kHz_B) >> 1;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CFO_TRACKING,
- ODM_DBG_LOUD,
- (
- "ODM_CfoTracking(): CFO_kHz_A = %dkHz, CFO_kHz_B = %dkHz, CFO_ave = %dkHz\n",
- CFO_kHz_A,
- CFO_kHz_B,
- CFO_ave
- )
- );
/* 4 1.3 Avoid abnormal large CFO */
CFO_ave_diff =
@@ -203,7 +135,6 @@ void ODM_CfoTracking(void *pDM_VOID)
pCfoTrack->largeCFOHit == 0 &&
!pCfoTrack->bAdjust
) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking(): first large CFO hit\n"));
pCfoTrack->largeCFOHit = 1;
return;
} else
@@ -223,12 +154,6 @@ void ODM_CfoTracking(void *pDM_VOID)
if (pDM_Odm->bBtEnabled) {
pCfoTrack->bAdjust = false;
odm_SetCrystalCap(pDM_Odm, pCfoTrack->DefXCap);
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CFO_TRACKING,
- ODM_DBG_LOUD,
- ("ODM_CfoTracking(): Disable CFO tracking for BT!!\n")
- );
}
/* 4 1.6 Big jump */
@@ -237,16 +162,6 @@ void ODM_CfoTracking(void *pDM_VOID)
Adjust_Xtal = Adjust_Xtal+((CFO_ave-CFO_TH_XTAL_LOW)>>2);
else if (CFO_ave < (-CFO_TH_XTAL_LOW))
Adjust_Xtal = Adjust_Xtal+((CFO_TH_XTAL_LOW-CFO_ave)>>2);
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CFO_TRACKING,
- ODM_DBG_LOUD,
- (
- "ODM_CfoTracking(): Crystal cap offset = %d\n",
- Adjust_Xtal
- )
- );
}
/* 4 1.7 Adjust Crystal Cap. */
@@ -263,34 +178,12 @@ void ODM_CfoTracking(void *pDM_VOID)
odm_SetCrystalCap(pDM_Odm, (u8)CrystalCap);
}
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CFO_TRACKING,
- ODM_DBG_LOUD,
- (
- "ODM_CfoTracking(): Crystal cap = 0x%x, Default Crystal cap = 0x%x\n",
- pCfoTrack->CrystalCap,
- pCfoTrack->DefXCap
- )
- );
/* 3 2. Dynamic ATC switch */
if (CFO_ave < CFO_TH_ATC && CFO_ave > -CFO_TH_ATC) {
odm_SetATCStatus(pDM_Odm, false);
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CFO_TRACKING,
- ODM_DBG_LOUD,
- ("ODM_CfoTracking(): Disable ATC!!\n")
- );
} else {
odm_SetATCStatus(pDM_Odm, true);
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CFO_TRACKING,
- ODM_DBG_LOUD,
- ("ODM_CfoTracking(): Enable ATC!!\n")
- );
}
}
}
diff --git a/drivers/staging/rtl8723bs/hal/odm_DIG.c b/drivers/staging/rtl8723bs/hal/odm_DIG.c
index dcef7fb17389..ef5b48bb01b2 100644
--- a/drivers/staging/rtl8723bs/hal/odm_DIG.c
+++ b/drivers/staging/rtl8723bs/hal/odm_DIG.c
@@ -81,17 +81,6 @@ void odm_NHMBB(void *pDM_VOID)
*(pDM_Odm->pNumTxBytesUnicast);
pDM_Odm->NHMLastRxOkcnt =
*(pDM_Odm->pNumRxBytesUnicast);
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- (
- "NHM_cnt_0 =%d, NHMCurTxOkcnt = %llu, NHMCurRxOkcnt = %llu\n",
- pDM_Odm->NHM_cnt_0,
- pDM_Odm->NHMCurTxOkcnt,
- pDM_Odm->NHMCurRxOkcnt
- )
- );
if ((pDM_Odm->NHMCurTxOkcnt) + 1 > (u64)(pDM_Odm->NHMCurRxOkcnt<<2) + 1) { /* Tx > 4*Rx possible for adaptivity test */
@@ -127,8 +116,6 @@ void odm_NHMBB(void *pDM_VOID)
}
}
}
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("adaptivity_flag = %d\n ", pDM_Odm->adaptivity_flag));
}
void odm_SearchPwdBLowerBound(void *pDM_VOID, u8 IGI_target)
@@ -165,7 +152,6 @@ void odm_SearchPwdBLowerBound(void *pDM_VOID, u8 IGI_target)
else
pDM_Odm->txEdcca0 = pDM_Odm->txEdcca0 + 1;
}
- /* DbgPrint("txEdcca1 = %d, txEdcca0 = %d\n", pDM_Odm->txEdcca1, pDM_Odm->txEdcca0); */
if (pDM_Odm->txEdcca1 > 5) {
IGI = IGI-1;
@@ -199,8 +185,6 @@ void odm_SearchPwdBLowerBound(void *pDM_VOID, u8 IGI_target)
pDM_Odm->Adaptivity_IGI_upper = IGI;
}
}
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("IGI = 0x%x, H2L_lb = 0x%x, L2H_lb = 0x%x\n", IGI, pDM_Odm->H2L_lb, pDM_Odm->L2H_lb));
}
void odm_AdaptivityInit(void *pDM_VOID)
@@ -239,19 +223,13 @@ void odm_Adaptivity(void *pDM_VOID, u8 IGI)
bool EDCCA_State = false;
if (!(pDM_Odm->SupportAbility & ODM_BB_ADAPTIVITY)) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("Go to odm_DynamicEDCCA()\n"));
return;
}
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_Adaptivity() =====>\n"));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("ForceEDCCA =%d, IGI_Base = 0x%x, TH_L2H_ini = %d, TH_EDCCA_HL_diff = %d, AdapEn_RSSI = %d\n",
- pDM_Odm->ForceEDCCA, pDM_Odm->IGI_Base, pDM_Odm->TH_L2H_ini, pDM_Odm->TH_EDCCA_HL_diff, pDM_Odm->AdapEn_RSSI));
if (*pDM_Odm->pBandWidth == ODM_BW20M) /* CHANNEL_WIDTH_20 */
IGI_target = pDM_Odm->IGI_Base;
else if (*pDM_Odm->pBandWidth == ODM_BW40M)
IGI_target = pDM_Odm->IGI_Base + 2;
- else if (*pDM_Odm->pBandWidth == ODM_BW80M)
- IGI_target = pDM_Odm->IGI_Base + 2;
else
IGI_target = pDM_Odm->IGI_Base;
pDM_Odm->IGI_target = (u8) IGI_target;
@@ -284,19 +262,6 @@ void odm_Adaptivity(void *pDM_VOID, u8 IGI)
)
odm_NHMBB(pDM_Odm);
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- (
- "BandWidth =%s, IGI_target = 0x%x, EDCCA_State =%d\n",
- (*pDM_Odm->pBandWidth == ODM_BW80M) ? "80M" :
- ((*pDM_Odm->pBandWidth == ODM_BW40M) ? "40M" : "20M"),
- IGI_target,
- EDCCA_State
- )
- );
-
if (EDCCA_State) {
Diff = IGI_target-(s8)IGI;
TH_L2H_dmc = pDM_Odm->TH_L2H_ini + Diff;
@@ -314,8 +279,6 @@ void odm_Adaptivity(void *pDM_VOID, u8 IGI)
TH_L2H_dmc = 0x7f;
TH_H2L_dmc = 0x7f;
}
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("IGI = 0x%x, TH_L2H_dmc = %d, TH_H2L_dmc = %d\n",
- IGI, TH_L2H_dmc, TH_H2L_dmc));
PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, bMaskByte0, (u8)TH_L2H_dmc);
PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_ECCAThreshold, bMaskByte2, (u8)TH_H2L_dmc);
}
@@ -326,18 +289,13 @@ void ODM_Write_DIG(void *pDM_VOID, u8 CurrentIGI)
struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable;
if (pDM_DigTable->bStopDIG) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("Stop Writing IGI\n"));
return;
}
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_TRACE, ("ODM_REG(IGI_A, pDM_Odm) = 0x%x, ODM_BIT(IGI, pDM_Odm) = 0x%x\n",
- ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm)));
-
if (pDM_DigTable->CurIGValue != CurrentIGI) {
/* 1 Check initial gain by upper bound */
if (!pDM_DigTable->bPSDInProgress) {
if (CurrentIGI > pDM_DigTable->rx_gain_range_max) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_TRACE, ("CurrentIGI(0x%02x) is larger than upper bound !!\n", pDM_DigTable->rx_gain_range_max));
CurrentIGI = pDM_DigTable->rx_gain_range_max;
}
@@ -352,8 +310,6 @@ void ODM_Write_DIG(void *pDM_VOID, u8 CurrentIGI)
pDM_DigTable->CurIGValue = CurrentIGI;
}
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_TRACE, ("CurrentIGI(0x%02x).\n", CurrentIGI));
-
}
void odm_PauseDIG(
@@ -366,18 +322,10 @@ void odm_PauseDIG(
struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable;
static bool bPaused;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG() =========>\n"));
-
if (
(pDM_Odm->SupportAbility & ODM_BB_ADAPTIVITY) &&
pDM_Odm->TxHangFlg == true
) {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- ("odm_PauseDIG(): Dynamic adjust threshold in progress !!\n")
- );
return;
}
@@ -385,12 +333,6 @@ void odm_PauseDIG(
!bPaused && (!(pDM_Odm->SupportAbility & ODM_BB_DIG) ||
!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT))
){
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- ("odm_PauseDIG(): Return: SupportAbility ODM_BB_DIG or ODM_BB_FA_CNT is disabled\n")
- );
return;
}
@@ -399,18 +341,15 @@ void odm_PauseDIG(
case ODM_PAUSE_DIG:
/* 2 Disable DIG */
ODM_CmnInfoUpdate(pDM_Odm, ODM_CMNINFO_ABILITY, pDM_Odm->SupportAbility & (~ODM_BB_DIG));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG(): Pause DIG !!\n"));
/* 2 Backup IGI value */
if (!bPaused) {
pDM_DigTable->IGIBackup = pDM_DigTable->CurIGValue;
bPaused = true;
}
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG(): Backup IGI = 0x%x\n", pDM_DigTable->IGIBackup));
/* 2 Write new IGI value */
ODM_Write_DIG(pDM_Odm, IGIValue);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG(): Write new IGI = 0x%x\n", IGIValue));
break;
/* 1 Resume DIG */
@@ -419,16 +358,13 @@ void odm_PauseDIG(
/* 2 Write backup IGI value */
ODM_Write_DIG(pDM_Odm, pDM_DigTable->IGIBackup);
bPaused = false;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG(): Write original IGI = 0x%x\n", pDM_DigTable->IGIBackup));
/* 2 Enable DIG */
ODM_CmnInfoUpdate(pDM_Odm, ODM_CMNINFO_ABILITY, pDM_Odm->SupportAbility | ODM_BB_DIG);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG(): Resume DIG !!\n"));
}
break;
default:
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_PauseDIG(): Wrong type !!\n"));
break;
}
}
@@ -439,25 +375,21 @@ bool odm_DigAbort(void *pDM_VOID)
/* SupportAbility */
if (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT)) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Return: SupportAbility ODM_BB_FA_CNT is disabled\n"));
return true;
}
/* SupportAbility */
if (!(pDM_Odm->SupportAbility & ODM_BB_DIG)) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Return: SupportAbility ODM_BB_DIG is disabled\n"));
return true;
}
/* ScanInProcess */
if (*(pDM_Odm->pbScanInProcess)) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Return: In Scan Progress\n"));
return true;
}
/* add by Neil Chen to avoid PSD is processing */
if (pDM_Odm->bDMInitialGainEnable == false) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Return: PSD is Processing\n"));
return true;
}
@@ -523,8 +455,6 @@ void odm_DIG(void *pDM_VOID)
if (odm_DigAbort(pDM_Odm))
return;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() ===========================>\n\n"));
-
if (pDM_Odm->adaptivity_flag == true)
Adap_IGI_Upper = pDM_Odm->Adaptivity_IGI_upper;
@@ -540,15 +470,12 @@ void odm_DIG(void *pDM_VOID)
dm_dig_min = DM_DIG_MIN_NIC;
DIG_MaxOfMin = DM_DIG_MAX_AP;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Absolutely upper bound = 0x%x, lower bound = 0x%x\n", dm_dig_max, dm_dig_min));
-
/* 1 Adjust boundary by RSSI */
if (pDM_Odm->bLinked && bPerformance) {
/* 2 Modify DIG upper bound */
/* 4 Modify DIG upper bound for 92E, 8723A\B, 8821 & 8812 BT */
if (pDM_Odm->bBtLimitedDig == 1) {
offset = 10;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Coex. case: Force upper bound to RSSI + %d !!!!!!\n", offset));
} else
offset = 15;
@@ -586,49 +513,9 @@ void odm_DIG(void *pDM_VOID)
DIG_Dynamic_MIN = DIG_MaxOfMin;
else
DIG_Dynamic_MIN = (u8) pDM_DigTable->AntDiv_RSSI_max;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_ANT_DIV,
- ODM_DBG_LOUD,
- (
- "odm_DIG(): Antenna diversity case: Force lower bound to 0x%x !!!!!!\n",
- DIG_Dynamic_MIN
- )
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_ANT_DIV,
- ODM_DBG_LOUD,
- (
- "odm_DIG(): Antenna diversity case: RSSI_max = 0x%x !!!!!!\n",
- pDM_DigTable->AntDiv_RSSI_max
- )
- );
}
}
}
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- (
- "odm_DIG(): Adjust boundary by RSSI Upper bound = 0x%x, Lower bound = 0x%x\n",
- pDM_DigTable->rx_gain_range_max,
- DIG_Dynamic_MIN
- )
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- (
- "odm_DIG(): Link status: bLinked = %d, RSSI = %d, bFirstConnect = %d, bFirsrDisConnect = %d\n\n",
- pDM_Odm->bLinked,
- pDM_Odm->RSSI_Min,
- FirstConnect,
- FirstDisConnect
- )
- );
/* 1 Modify DIG lower bound, deal with abnormal case */
/* 2 Abnormal false alarm case */
@@ -645,47 +532,20 @@ void odm_DIG(void *pDM_VOID)
pDM_Odm->bsta_state
) {
pDM_DigTable->rx_gain_range_min = dm_dig_min;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- (
- "odm_DIG(): Abnormal #beacon (%d) case in STA mode: Force lower bound to 0x%x !!!!!!\n\n",
- pDM_Odm->PhyDbgInfo.NumQryBeaconPkt,
- pDM_DigTable->rx_gain_range_min
- )
- );
}
}
/* 2 Abnormal lower bound case */
if (pDM_DigTable->rx_gain_range_min > pDM_DigTable->rx_gain_range_max) {
pDM_DigTable->rx_gain_range_min = pDM_DigTable->rx_gain_range_max;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- (
- "odm_DIG(): Abnormal lower bound case: Force lower bound to 0x%x !!!!!!\n\n",
- pDM_DigTable->rx_gain_range_min
- )
- );
}
/* 1 False alarm threshold decision */
odm_FAThresholdCheck(pDM_Odm, bDFSBand, bPerformance, RxTp, TxTp, dm_FA_thres);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): False alarm threshold = %d, %d, %d\n\n", dm_FA_thres[0], dm_FA_thres[1], dm_FA_thres[2]));
/* 1 Adjust initial gain by false alarm */
if (pDM_Odm->bLinked && bPerformance) {
- /* 2 After link */
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- ("odm_DIG(): Adjust IGI after link\n")
- );
if (bFirstTpTarget || (FirstConnect && bPerformance)) {
pDM_DigTable->LargeFAHit = 0;
@@ -698,16 +558,6 @@ void odm_DIG(void *pDM_VOID)
CurrentIGI = DIG_MaxOfMin;
}
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- (
- "odm_DIG(): First connect case: IGI does on-shot to 0x%x\n",
- CurrentIGI
- )
- );
-
} else {
if (pFalseAlmCnt->Cnt_all > dm_FA_thres[2])
CurrentIGI = CurrentIGI + 4;
@@ -722,35 +572,12 @@ void odm_DIG(void *pDM_VOID)
(pDM_Odm->bsta_state)
) {
CurrentIGI = pDM_DigTable->rx_gain_range_min;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- (
- "odm_DIG(): Abnormal #beacon (%d) case: IGI does one-shot to 0x%x\n",
- pDM_Odm->PhyDbgInfo.NumQryBeaconPkt,
- CurrentIGI
- )
- );
}
}
} else {
- /* 2 Before link */
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- ("odm_DIG(): Adjust IGI before link\n")
- );
if (FirstDisConnect || bFirstCoverage) {
CurrentIGI = dm_dig_min;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- ("odm_DIG(): First disconnect case: IGI does on-shot to lower bound\n")
- );
} else {
if (pFalseAlmCnt->Cnt_all > dm_FA_thres[2])
CurrentIGI = CurrentIGI + 4;
@@ -768,17 +595,6 @@ void odm_DIG(void *pDM_VOID)
if (CurrentIGI > pDM_DigTable->rx_gain_range_max)
CurrentIGI = pDM_DigTable->rx_gain_range_max;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- (
- "odm_DIG(): CurIGValue = 0x%x, TotalFA = %d\n\n",
- CurrentIGI,
- pFalseAlmCnt->Cnt_all
- )
- );
-
/* 1 Force upper bound and lower bound for adaptivity */
if (
pDM_Odm->SupportAbility & ODM_BB_ADAPTIVITY &&
@@ -791,8 +607,6 @@ void odm_DIG(void *pDM_VOID)
if (CurrentIGI < pDM_Odm->IGI_LowerBound)
CurrentIGI = pDM_Odm->IGI_LowerBound;
}
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Adaptivity case: Force upper bound to 0x%x !!!!!!\n", Adap_IGI_Upper));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Adaptivity case: Force lower bound to 0x%x !!!!!!\n\n", pDM_Odm->IGI_LowerBound));
}
@@ -831,13 +645,6 @@ void odm_DIGbyRSSI_LPS(void *pDM_VOID)
CurrentIGI = CurrentIGI+RSSI_OFFSET_DIG;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- ("odm_DIGbyRSSI_LPS() ==>\n")
- );
-
/* Using FW PS mode to make IGI */
/* Adjust by FA in LPS MODE */
if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2_LPS)
@@ -862,26 +669,6 @@ void odm_DIGbyRSSI_LPS(void *pDM_VOID)
else if (CurrentIGI < RSSI_Lower)
CurrentIGI = RSSI_Lower;
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- ("odm_DIGbyRSSI_LPS(): pFalseAlmCnt->Cnt_all = %d\n", pFalseAlmCnt->Cnt_all)
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- ("odm_DIGbyRSSI_LPS(): pDM_Odm->RSSI_Min = %d\n", pDM_Odm->RSSI_Min)
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_DIG,
- ODM_DBG_LOUD,
- ("odm_DIGbyRSSI_LPS(): CurrentIGI = 0x%x\n", CurrentIGI)
- );
-
ODM_Write_DIG(pDM_Odm, CurrentIGI);
/* ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); */
}
@@ -970,86 +757,6 @@ void odm_FalseAlarmCounterStatistics(void *pDM_VOID)
FalseAlmCnt->Cnt_CCA_all =
FalseAlmCnt->Cnt_OFDM_CCA + FalseAlmCnt->Cnt_CCK_CCA;
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_FA_CNT,
- ODM_DBG_LOUD,
- ("Enter odm_FalseAlarmCounterStatistics\n")
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_FA_CNT,
- ODM_DBG_LOUD,
- (
- "Cnt_Fast_Fsync =%d, Cnt_SB_Search_fail =%d\n",
- FalseAlmCnt->Cnt_Fast_Fsync,
- FalseAlmCnt->Cnt_SB_Search_fail
- )
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_FA_CNT,
- ODM_DBG_LOUD,
- (
- "Cnt_Parity_Fail =%d, Cnt_Rate_Illegal =%d\n",
- FalseAlmCnt->Cnt_Parity_Fail,
- FalseAlmCnt->Cnt_Rate_Illegal
- )
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_FA_CNT,
- ODM_DBG_LOUD,
- (
- "Cnt_Crc8_fail =%d, Cnt_Mcs_fail =%d\n",
- FalseAlmCnt->Cnt_Crc8_fail,
- FalseAlmCnt->Cnt_Mcs_fail
- )
- );
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_FA_CNT,
- ODM_DBG_LOUD,
- ("Cnt_OFDM_CCA =%d\n", FalseAlmCnt->Cnt_OFDM_CCA)
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_FA_CNT,
- ODM_DBG_LOUD,
- ("Cnt_CCK_CCA =%d\n", FalseAlmCnt->Cnt_CCK_CCA)
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_FA_CNT,
- ODM_DBG_LOUD,
- ("Cnt_CCA_all =%d\n", FalseAlmCnt->Cnt_CCA_all)
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_FA_CNT,
- ODM_DBG_LOUD,
- ("Cnt_Ofdm_fail =%d\n", FalseAlmCnt->Cnt_Ofdm_fail)
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_FA_CNT,
- ODM_DBG_LOUD,
- ("Cnt_Cck_fail =%d\n", FalseAlmCnt->Cnt_Cck_fail)
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_FA_CNT,
- ODM_DBG_LOUD,
- ("Cnt_Ofdm_fail =%d\n", FalseAlmCnt->Cnt_Ofdm_fail)
- );
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_FA_CNT,
- ODM_DBG_LOUD,
- ("Total False Alarm =%d\n", FalseAlmCnt->Cnt_all)
- );
}
@@ -1084,8 +791,6 @@ u8 odm_ForbiddenIGICheck(void *pDM_VOID, u8 DIG_Dynamic_MIN, u8 CurrentIGI)
u8 rx_gain_range_min = pDM_DigTable->rx_gain_range_min;
if (pFalseAlmCnt->Cnt_all > 10000) {
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Abnormally false alarm case.\n"));
-
if (pDM_DigTable->LargeFAHit != 3)
pDM_DigTable->LargeFAHit++;
@@ -1102,22 +807,18 @@ u8 odm_ForbiddenIGICheck(void *pDM_VOID, u8 DIG_Dynamic_MIN, u8 CurrentIGI)
else
rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 2);
pDM_DigTable->Recover_cnt = 1800;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Abnormally false alarm case: Recover_cnt = %d\n", pDM_DigTable->Recover_cnt));
}
} else {
if (pDM_DigTable->Recover_cnt != 0) {
pDM_DigTable->Recover_cnt--;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: Recover_cnt = %d\n", pDM_DigTable->Recover_cnt));
} else {
if (pDM_DigTable->LargeFAHit < 3) {
if ((pDM_DigTable->ForbiddenIGI - 2) < DIG_Dynamic_MIN) { /* DM_DIG_MIN) */
pDM_DigTable->ForbiddenIGI = DIG_Dynamic_MIN; /* DM_DIG_MIN; */
rx_gain_range_min = DIG_Dynamic_MIN; /* DM_DIG_MIN; */
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: At Lower Bound\n"));
} else {
pDM_DigTable->ForbiddenIGI -= 2;
rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 2);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: Approach Lower Bound\n"));
}
} else
pDM_DigTable->LargeFAHit = 0;
@@ -1143,25 +844,12 @@ void odm_CCKPacketDetectionThresh(void *pDM_VOID)
!(pDM_Odm->SupportAbility & ODM_BB_CCK_PD) ||
!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT)
) {
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CCK_PD,
- ODM_DBG_LOUD,
- ("odm_CCKPacketDetectionThresh() return ==========\n")
- );
return;
}
if (pDM_Odm->ExtLNA)
return;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CCK_PD,
- ODM_DBG_LOUD,
- ("odm_CCKPacketDetectionThresh() ==========>\n")
- );
-
if (pDM_Odm->bLinked) {
if (pDM_Odm->RSSI_Min > 25)
CurCCK_CCAThres = 0xcd;
@@ -1181,16 +869,6 @@ void odm_CCKPacketDetectionThresh(void *pDM_VOID)
}
ODM_Write_CCK_CCA_Thres(pDM_Odm, CurCCK_CCAThres);
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_CCK_PD,
- ODM_DBG_LOUD,
- (
- "odm_CCKPacketDetectionThresh() CurCCK_CCAThres = 0x%x\n",
- CurCCK_CCAThres
- )
- );
}
void ODM_Write_CCK_CCA_Thres(void *pDM_VOID, u8 CurCCK_CCAThres)
diff --git a/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c b/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c
index 12b37c17ea0c..578d5712645c 100644
--- a/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c
+++ b/drivers/staging/rtl8723bs/hal/odm_EdcaTurboCheck.c
@@ -37,19 +37,6 @@ void ODM_EdcaTurboInit(void *pDM_VOID)
pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false;
pDM_Odm->DM_EDCA_Table.bIsCurRDLState = false;
Adapter->recvpriv.bIsAnyNonBEPkts = false;
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD,
- ("Original VO PARAM: 0x%x\n",
- rtw_read32(pDM_Odm->Adapter, ODM_EDCA_VO_PARAM)));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD,
- ("Original VI PARAM: 0x%x\n",
- rtw_read32(pDM_Odm->Adapter, ODM_EDCA_VI_PARAM)));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD,
- ("Original BE PARAM: 0x%x\n",
- rtw_read32(pDM_Odm->Adapter, ODM_EDCA_BE_PARAM)));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD,
- ("Original BK PARAM: 0x%x\n",
- rtw_read32(pDM_Odm->Adapter, ODM_EDCA_BK_PARAM)));
} /* ODM_InitEdcaTurbo */
void odm_EdcaTurboCheck(void *pDM_VOID)
@@ -60,15 +47,10 @@ void odm_EdcaTurboCheck(void *pDM_VOID)
*/
struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD,
- ("odm_EdcaTurboCheck ========================>\n"));
-
if (!(pDM_Odm->SupportAbility & ODM_MAC_EDCA_TURBO))
return;
odm_EdcaTurboCheckCE(pDM_Odm);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD,
- ("<========================odm_EdcaTurboCheck\n"));
} /* odm_CheckEdcaTurbo */
void odm_EdcaTurboCheckCE(void *pDM_VOID)
@@ -142,12 +124,10 @@ void odm_EdcaTurboCheckCE(void *pDM_VOID)
} else if ((iot_peer == HT_IOT_PEER_CISCO) &&
((wirelessmode == ODM_WM_G) ||
(wirelessmode == (ODM_WM_B | ODM_WM_G)) ||
- (wirelessmode == ODM_WM_A) ||
(wirelessmode == ODM_WM_B))) {
EDCA_BE_DL = edca_setting_DL_GMode[iot_peer];
} else if ((iot_peer == HT_IOT_PEER_AIRGO) &&
- ((wirelessmode == ODM_WM_G) ||
- (wirelessmode == ODM_WM_A))) {
+ (wirelessmode == ODM_WM_G)) {
EDCA_BE_DL = 0xa630;
} else if (iot_peer == HT_IOT_PEER_MARVELL) {
EDCA_BE_DL = edca_setting_DL[iot_peer];
diff --git a/drivers/staging/rtl8723bs/hal/odm_HWConfig.c b/drivers/staging/rtl8723bs/hal/odm_HWConfig.c
index 638c16f5c668..32f7eb952ca8 100644
--- a/drivers/staging/rtl8723bs/hal/odm_HWConfig.c
+++ b/drivers/staging/rtl8723bs/hal/odm_HWConfig.c
@@ -59,9 +59,6 @@ static u8 odm_EVMdbToPercentage(s8 Value)
ret_val = Value;
ret_val /= 2;
- /* DbgPrint("Value =%d\n", Value); */
- /* ODM_RT_DISP(FRX, RX_PHY_SQ, ("EVMdbToPercentage92C Value =%d / %x\n", ret_val, ret_val)); */
-
if (ret_val >= 0)
ret_val = 0;
if (ret_val <= -33)
@@ -141,7 +138,6 @@ static void odm_RxPhyStatus92CSeries_Parsing(
}
- /* DbgPrint("cck SQ = %d\n", SQ); */
pPhyInfo->signal_quality = SQ;
pPhyInfo->rx_mimo_signal_quality[ODM_RF_PATH_A] = SQ;
pPhyInfo->rx_mimo_signal_quality[ODM_RF_PATH_B] = -1;
@@ -168,7 +164,6 @@ static void odm_RxPhyStatus92CSeries_Parsing(
/* Translate DBM to percentage. */
RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]);
total_rssi += RSSI;
- /* RT_DISP(FRX, RX_PHY_SS, ("RF-%d RXPWR =%x RSSI =%d\n", i, rx_pwr[i], RSSI)); */
pPhyInfo->rx_mimo_signal_strength[i] = (u8) RSSI;
@@ -183,10 +178,8 @@ static void odm_RxPhyStatus92CSeries_Parsing(
rx_pwr_all = (((pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all) >> 1)&0x7f)-110;
PWDB_ALL_BT = PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all);
- /* RT_DISP(FRX, RX_PHY_SS, ("PWDB_ALL =%d\n", PWDB_ALL)); */
pPhyInfo->rx_pwd_ba11 = PWDB_ALL;
- /* ODM_RT_TRACE(pDM_Odm, ODM_COMP_RSSI_MONITOR, ODM_DBG_LOUD, ("ODM OFDM RSSI =%d\n", pPhyInfo->rx_pwd_ba11)); */
pPhyInfo->bt_rx_rssi_percentage = PWDB_ALL_BT;
pPhyInfo->rx_power = rx_pwr_all;
pPhyInfo->recv_signal_power = rx_pwr_all;
@@ -206,9 +199,6 @@ static void odm_RxPhyStatus92CSeries_Parsing(
/* value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore. */
EVM = odm_EVMdbToPercentage((pPhyStaRpt->stream_rxevm[i])); /* dbm */
- /* RT_DISP(FRX, RX_PHY_SQ, ("RXRATE =%x RXEVM =%x EVM =%s%d\n", */
- /* GET_RX_STATUS_DESC_RX_MCS(pDesc), pDrvInfo->rxevm[i], "%", EVM)); */
-
/* if (pPktinfo->bPacketMatchBSSID) */
{
if (i == ODM_RF_PATH_A) /* Fill value in RFD, Get the first spatial stream only */
@@ -232,9 +222,6 @@ static void odm_RxPhyStatus92CSeries_Parsing(
pPhyInfo->signal_strength = (u8)(odm_SignalScaleMapping(pDM_Odm, total_rssi /= rf_rx_num));
}
}
-
- /* DbgPrint("isCCKrate = %d, pPhyInfo->rx_pwd_ba11 = %d, pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a = 0x%x\n", */
- /* isCCKrate, pPhyInfo->rx_pwd_ba11, pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a); */
}
static void odm_Process_RSSIForDM(
@@ -286,8 +273,6 @@ static void odm_Process_RSSIForDM(
pDM_Odm->RSSI_A = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_A];
pDM_Odm->RSSI_B = 0;
} else {
- /* DbgPrint("pRfd->Status.rx_mimo_signal_strength[0] = %d, pRfd->Status.rx_mimo_signal_strength[1] = %d\n", */
- /* pRfd->Status.rx_mimo_signal_strength[0], pRfd->Status.rx_mimo_signal_strength[1]); */
pDM_Odm->RSSI_A = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_A];
pDM_Odm->RSSI_B = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_B];
@@ -377,11 +362,6 @@ static void odm_Process_RSSIForDM(
pEntry->rssi_stat.UndecoratedSmoothedCCK = UndecoratedSmoothedCCK;
pEntry->rssi_stat.UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM;
pEntry->rssi_stat.UndecoratedSmoothedPWDB = UndecoratedSmoothedPWDB;
-
- /* DbgPrint("OFDM_pkt =%d, Weighting =%d\n", OFDM_pkt, Weighting); */
- /* DbgPrint("UndecoratedSmoothedOFDM =%d, UndecoratedSmoothedPWDB =%d, UndecoratedSmoothedCCK =%d\n", */
- /* UndecoratedSmoothedOFDM, UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK); */
-
}
}
@@ -427,12 +407,6 @@ enum hal_status ODM_ConfigRFWithHeaderFile(
enum odm_rf_radio_path_e eRFPath
)
{
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
- ("===>ODM_ConfigRFWithHeaderFile (%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));
-
if (ConfigType == CONFIG_RF_RADIO)
READ_AND_CONFIG(8723B, _RadioA);
else if (ConfigType == CONFIG_RF_TXPWR_LMT)
@@ -443,12 +417,6 @@ enum hal_status ODM_ConfigRFWithHeaderFile(
enum hal_status ODM_ConfigRFWithTxPwrTrackHeaderFile(struct dm_odm_t *pDM_Odm)
{
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
- ("===>ODM_ConfigRFWithTxPwrTrackHeaderFile (%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));
-
if (pDM_Odm->SupportInterface == ODM_ITRF_SDIO)
READ_AND_CONFIG(8723B, _TxPowerTrack_SDIO);
@@ -459,12 +427,6 @@ enum hal_status ODM_ConfigBBWithHeaderFile(
struct dm_odm_t *pDM_Odm, enum ODM_BB_Config_Type ConfigType
)
{
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
- ("===>ODM_ConfigBBWithHeaderFile (%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));
-
if (ConfigType == CONFIG_BB_PHY_REG)
READ_AND_CONFIG(8723B, _PHY_REG);
else if (ConfigType == CONFIG_BB_AGC_TAB)
diff --git a/drivers/staging/rtl8723bs/hal/odm_NoiseMonitor.c b/drivers/staging/rtl8723bs/hal/odm_NoiseMonitor.c
index c3de123e2a48..ad169704f3e9 100644
--- a/drivers/staging/rtl8723bs/hal/odm_NoiseMonitor.c
+++ b/drivers/staging/rtl8723bs/hal/odm_NoiseMonitor.c
@@ -29,9 +29,8 @@ static s16 odm_InbandNoise_Monitor_NSeries(
u8 max_rf_path = 0, rf_path;
u8 reg_c50, reg_c58, valid_done = 0;
struct noise_level noise_data;
- u32 start = 0, func_start = 0, func_end = 0;
+ u32 start = 0;
- func_start = jiffies;
pDM_Odm->noise_level.noise_all = 0;
if ((pDM_Odm->RFType == ODM_1T2R) || (pDM_Odm->RFType == ODM_2T2R))
@@ -39,8 +38,6 @@ static s16 odm_InbandNoise_Monitor_NSeries(
else
max_rf_path = 1;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_DebugControlInbandNoise_Nseries() ==>\n"));
-
memset(&noise_data, 0, sizeof(struct noise_level));
/* */
@@ -65,7 +62,6 @@ static s16 odm_InbandNoise_Monitor_NSeries(
/* Read Noise Floor Report */
tmp4b = PHY_QueryBBReg(pDM_Odm->Adapter, 0x8f8, bMaskDWord);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("Noise Floor Report (0x8f8) = 0x%08x\n", tmp4b));
/* PHY_SetBBReg(pDM_Odm->Adapter, rOFDM0_XAAGCCore1, bMaskByte0, TestInitialGain); */
/* if (max_rf_path == 2) */
@@ -77,17 +73,10 @@ static s16 odm_InbandNoise_Monitor_NSeries(
noise_data.value[ODM_RF_PATH_A] = (u8)(tmp4b&0xff);
noise_data.value[ODM_RF_PATH_B] = (u8)((tmp4b&0xff00)>>8);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("value_a = 0x%x(%d), value_b = 0x%x(%d)\n",
- noise_data.value[ODM_RF_PATH_A], noise_data.value[ODM_RF_PATH_A], noise_data.value[ODM_RF_PATH_B], noise_data.value[ODM_RF_PATH_B]));
-
for (rf_path = ODM_RF_PATH_A; rf_path < max_rf_path; rf_path++) {
noise_data.sval[rf_path] = (s8)noise_data.value[rf_path];
noise_data.sval[rf_path] /= 2;
}
-
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("sval_a = %d, sval_b = %d\n",
- noise_data.sval[ODM_RF_PATH_A], noise_data.sval[ODM_RF_PATH_B]));
/* mdelay(10); */
/* msleep(10); */
@@ -95,11 +84,8 @@ static s16 odm_InbandNoise_Monitor_NSeries(
if ((noise_data.valid_cnt[rf_path] < ValidCnt) && (noise_data.sval[rf_path] < Valid_Max && noise_data.sval[rf_path] >= Valid_Min)) {
noise_data.valid_cnt[rf_path]++;
noise_data.sum[rf_path] += noise_data.sval[rf_path];
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RF_Path:%d Valid sval = %d\n", rf_path, noise_data.sval[rf_path]));
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("Sum of sval = %d,\n", noise_data.sum[rf_path]));
if (noise_data.valid_cnt[rf_path] == ValidCnt) {
valid_done++;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("After divided, RF_Path:%d , sum = %d\n", rf_path, noise_data.sum[rf_path]));
}
}
@@ -120,43 +106,23 @@ static s16 odm_InbandNoise_Monitor_NSeries(
}
reg_c50 = (s32)PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XAAGCCore1, bMaskByte0);
reg_c50 &= ~BIT7;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("0x%x = 0x%02x(%d)\n", rOFDM0_XAAGCCore1, reg_c50, reg_c50));
pDM_Odm->noise_level.noise[ODM_RF_PATH_A] = -110 + reg_c50 + noise_data.sum[ODM_RF_PATH_A];
pDM_Odm->noise_level.noise_all += pDM_Odm->noise_level.noise[ODM_RF_PATH_A];
if (max_rf_path == 2) {
reg_c58 = (s32)PHY_QueryBBReg(pDM_Odm->Adapter, rOFDM0_XBAGCCore1, bMaskByte0);
reg_c58 &= ~BIT7;
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("0x%x = 0x%02x(%d)\n", rOFDM0_XBAGCCore1, reg_c58, reg_c58));
pDM_Odm->noise_level.noise[ODM_RF_PATH_B] = -110 + reg_c58 + noise_data.sum[ODM_RF_PATH_B];
pDM_Odm->noise_level.noise_all += pDM_Odm->noise_level.noise[ODM_RF_PATH_B];
}
pDM_Odm->noise_level.noise_all /= max_rf_path;
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_COMMON,
- ODM_DBG_LOUD,
- (
- "noise_a = %d, noise_b = %d\n",
- pDM_Odm->noise_level.noise[ODM_RF_PATH_A],
- pDM_Odm->noise_level.noise[ODM_RF_PATH_B]
- )
- );
-
/* */
/* Step 4. Recover the Dig */
/* */
if (bPauseDIG)
odm_PauseDIG(pDM_Odm, ODM_RESUME_DIG, IGIValue);
- func_end = jiffies_to_msecs(jiffies - func_start);
- /* printk("%s noise_a = %d, noise_b = %d noise_all:%d (%d ms)\n", __func__, */
- /* pDM_Odm->noise_level.noise[ODM_RF_PATH_A], */
- /* pDM_Odm->noise_level.noise[ODM_RF_PATH_B], */
- /* pDM_Odm->noise_level.noise_all, func_end); */
-
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_DebugControlInbandNoise_Nseries() <==\n"));
return pDM_Odm->noise_level.noise_all;
}
diff --git a/drivers/staging/rtl8723bs/hal/odm_PathDiv.c b/drivers/staging/rtl8723bs/hal/odm_PathDiv.c
deleted file mode 100644
index 92b708265d47..000000000000
--- a/drivers/staging/rtl8723bs/hal/odm_PathDiv.c
+++ /dev/null
@@ -1,34 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-
-#include "odm_precomp.h"
-
-void odm_PathDiversityInit(void *pDM_VOID)
-{
- struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
-
- if (!(pDM_Odm->SupportAbility & ODM_BB_PATH_DIV))
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_PATH_DIV,
- ODM_DBG_LOUD,
- ("Return: Not Support PathDiv\n")
- );
-}
-
-void odm_PathDiversity(void *pDM_VOID)
-{
- struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
-
- if (!(pDM_Odm->SupportAbility & ODM_BB_PATH_DIV))
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_PATH_DIV,
- ODM_DBG_LOUD,
- ("Return: Not Support PathDiv\n")
- );
-}
diff --git a/drivers/staging/rtl8723bs/hal/odm_PathDiv.h b/drivers/staging/rtl8723bs/hal/odm_PathDiv.h
deleted file mode 100644
index 7a5bc00c3682..000000000000
--- a/drivers/staging/rtl8723bs/hal/odm_PathDiv.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-
-#ifndef __ODMPATHDIV_H__
-#define __ODMPATHDIV_H__
-
-void
-odm_PathDiversityInit(
- void *pDM_VOID
- );
-
-void
-odm_PathDiversity(
- void *pDM_VOID
- );
-
- #endif /* ifndef __ODMPATHDIV_H__ */
diff --git a/drivers/staging/rtl8723bs/hal/odm_RTL8723B.c b/drivers/staging/rtl8723bs/hal/odm_RTL8723B.c
index ecf0045fcad9..54518ea1be6b 100644
--- a/drivers/staging/rtl8723bs/hal/odm_RTL8723B.c
+++ b/drivers/staging/rtl8723bs/hal/odm_RTL8723B.c
@@ -29,7 +29,6 @@ s8 odm_CCKRSSI_8723B(u8 LNA_idx, u8 VGA_idx)
break;
default:
/* rx_pwr_all = -53+(2*(31-VGA_idx)); */
- /* DbgPrint("wrong LNA index\n"); */
break;
}
diff --git a/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.c b/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.c
index 63bf5ba3e0d5..a29bd9375023 100644
--- a/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.c
+++ b/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.c
@@ -38,17 +38,6 @@ void odm_ConfigRFReg_8723B(
PHY_SetRFReg(pDM_Odm->Adapter, RF_PATH, RegAddr, bRFRegOffsetMask, Data);
udelay(1);
getvalue = PHY_QueryRFReg(pDM_Odm->Adapter, RF_PATH, Addr, bMaskDWord);
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- "===> ODM_ConfigRFWithHeaderFile: [B6] getvalue 0x%x, Data 0x%x, count %d\n",
- getvalue,
- Data,
- count
- )
- );
if (count > 5)
break;
}
@@ -86,17 +75,6 @@ void odm_ConfigRFReg_8723B(
getvalue = PHY_QueryRFReg(
pDM_Odm->Adapter, RF_PATH, Addr, bMaskDWord
);
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- "===> ODM_ConfigRFWithHeaderFile: [B2] getvalue 0x%x, Data 0x%x, count %d\n",
- getvalue,
- Data,
- count
- )
- );
if (count > 5)
break;
@@ -118,32 +96,11 @@ void odm_ConfigRF_RadioA_8723B(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Data)
ODM_RF_PATH_A,
Addr|maskforPhySet
);
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- "===> ODM_ConfigRFWithHeaderFile: [RadioA] %08X %08X\n",
- Addr,
- Data
- )
- );
}
void odm_ConfigMAC_8723B(struct dm_odm_t *pDM_Odm, u32 Addr, u8 Data)
{
rtw_write8(pDM_Odm->Adapter, Addr, Data);
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- "===> ODM_ConfigMACWithHeaderFile: [MAC_REG] %08X %08X\n",
- Addr,
- Data
- )
- );
}
void odm_ConfigBB_AGC_8723B(
@@ -156,22 +113,10 @@ void odm_ConfigBB_AGC_8723B(
PHY_SetBBReg(pDM_Odm->Adapter, Addr, Bitmask, Data);
/* Add 1us delay between BB/RF register setting. */
udelay(1);
-
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_TRACE,
- (
- "===> ODM_ConfigBBWithHeaderFile: [AGC_TAB] %08X %08X\n",
- Addr,
- Data
- )
- );
}
void odm_ConfigBB_PHY_REG_PG_8723B(
struct dm_odm_t *pDM_Odm,
- u32 Band,
u32 RfPath,
u32 TxNum,
u32 Addr,
@@ -182,19 +127,8 @@ void odm_ConfigBB_PHY_REG_PG_8723B(
if (Addr == 0xfe || Addr == 0xffe)
msleep(50);
else {
- PHY_StoreTxPowerByRate(pDM_Odm->Adapter, Band, RfPath, TxNum, Addr, Bitmask, Data);
+ PHY_StoreTxPowerByRate(pDM_Odm->Adapter, RfPath, TxNum, Addr, Bitmask, Data);
}
- ODM_RT_TRACE(
- pDM_Odm,
- ODM_COMP_INIT,
- ODM_DBG_LOUD,
- (
- "===> ODM_ConfigBBWithHeaderFile: [PHY_REG] %08X %08X %08X\n",
- Addr,
- Bitmask,
- Data
- )
- );
}
void odm_ConfigBB_PHY_8723B(
@@ -222,13 +156,11 @@ void odm_ConfigBB_PHY_8723B(
/* Add 1us delay between BB/RF register setting. */
udelay(1);
- ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigBBWithHeaderFile: [PHY_REG] %08X %08X\n", Addr, Data));
}
void odm_ConfigBB_TXPWR_LMT_8723B(
struct dm_odm_t *pDM_Odm,
u8 *Regulation,
- u8 *Band,
u8 *Bandwidth,
u8 *RateSection,
u8 *RfPath,
@@ -239,7 +171,6 @@ void odm_ConfigBB_TXPWR_LMT_8723B(
PHY_SetTxPowerLimit(
pDM_Odm->Adapter,
Regulation,
- Band,
Bandwidth,
RateSection,
RfPath,
diff --git a/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h b/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h
index b392d14c389d..bdd6fde49fc6 100644
--- a/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h
+++ b/drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h
@@ -25,7 +25,6 @@ void odm_ConfigBB_AGC_8723B(struct dm_odm_t *pDM_Odm,
);
void odm_ConfigBB_PHY_REG_PG_8723B(struct dm_odm_t *pDM_Odm,
- u32 Band,
u32 RfPath,
u32 TxNum,
u32 Addr,
@@ -41,7 +40,6 @@ void odm_ConfigBB_PHY_8723B(struct dm_odm_t *pDM_Odm,
void odm_ConfigBB_TXPWR_LMT_8723B(struct dm_odm_t *pDM_Odm,
u8 *Regulation,
- u8 *Band,
u8 *Bandwidth,
u8 *RateSection,
u8 *RfPath,
diff --git a/drivers/staging/rtl8723bs/hal/odm_debug.c b/drivers/staging/rtl8723bs/hal/odm_debug.c
deleted file mode 100644
index b35451bcb437..000000000000
--- a/drivers/staging/rtl8723bs/hal/odm_debug.c
+++ /dev/null
@@ -1,44 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-
-#include "odm_precomp.h"
-
-void ODM_InitDebugSetting(struct dm_odm_t *pDM_Odm)
-{
- pDM_Odm->DebugLevel = ODM_DBG_LOUD;
-
- pDM_Odm->DebugComponents =
-/* BB Functions */
-/* ODM_COMP_DIG | */
-/* ODM_COMP_RA_MASK | */
-/* ODM_COMP_DYNAMIC_TXPWR | */
-/* ODM_COMP_FA_CNT | */
-/* ODM_COMP_RSSI_MONITOR | */
-/* ODM_COMP_CCK_PD | */
-/* ODM_COMP_ANT_DIV | */
-/* ODM_COMP_PWR_SAVE | */
-/* ODM_COMP_PWR_TRAIN | */
-/* ODM_COMP_RATE_ADAPTIVE | */
-/* ODM_COMP_PATH_DIV | */
-/* ODM_COMP_DYNAMIC_PRICCA | */
-/* ODM_COMP_RXHP | */
-/* ODM_COMP_MP | */
-/* ODM_COMP_CFO_TRACKING | */
-
-/* MAC Functions */
-/* ODM_COMP_EDCA_TURBO | */
-/* ODM_COMP_EARLY_MODE | */
-/* RF Functions */
-/* ODM_COMP_TX_PWR_TRACK | */
-/* ODM_COMP_RX_GAIN_TRACK | */
-/* ODM_COMP_CALIBRATION | */
-/* Common */
-/* ODM_COMP_COMMON | */
-/* ODM_COMP_INIT | */
-/* ODM_COMP_PSD | */
-0;
-}
diff --git a/drivers/staging/rtl8723bs/hal/odm_debug.h b/drivers/staging/rtl8723bs/hal/odm_debug.h
deleted file mode 100644
index be0d4c49a747..000000000000
--- a/drivers/staging/rtl8723bs/hal/odm_debug.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-
-#ifndef __ODM_DBG_H__
-#define __ODM_DBG_H__
-
-
-/* */
-/* Define the debug levels */
-/* */
-/* 1. DBG_TRACE and DBG_LOUD are used for normal cases. */
-/* So that, they can help SW engineer to developed or trace states changed */
-/* and also help HW enginner to trace every operation to and from HW, */
-/* e.g IO, Tx, Rx. */
-/* */
-/* 2. DBG_WARNNING and DBG_SERIOUS are used for unusual or error cases, */
-/* which help us to debug SW or HW. */
-/* */
-/* */
-/* */
-/* Never used in a call to ODM_RT_TRACE()! */
-/* */
-#define ODM_DBG_OFF 1
-
-/* */
-/* Fatal bug. */
-/* For example, Tx/Rx/IO locked up, OS hangs, memory access violation, */
-/* resource allocation failed, unexpected HW behavior, HW BUG and so on. */
-/* */
-#define ODM_DBG_SERIOUS 2
-
-/* */
-/* Abnormal, rare, or unexpected cases. */
-/* For example, */
-/* IRP/Packet/OID canceled, */
-/* device suprisely unremoved and so on. */
-/* */
-#define ODM_DBG_WARNING 3
-
-/* */
-/* Normal case with useful information about current SW or HW state. */
-/* For example, Tx/Rx descriptor to fill, Tx/Rx descriptor completed status, */
-/* SW protocol state change, dynamic mechanism state change and so on. */
-/* */
-#define ODM_DBG_LOUD 4
-
-/* */
-/* Normal case with detail execution flow or information. */
-/* */
-#define ODM_DBG_TRACE 5
-
-/* */
-/* Define the tracing components */
-/* */
-/* */
-/* BB Functions */
-#define ODM_COMP_DIG BIT0
-#define ODM_COMP_RA_MASK BIT1
-#define ODM_COMP_DYNAMIC_TXPWR BIT2
-#define ODM_COMP_FA_CNT BIT3
-#define ODM_COMP_RSSI_MONITOR BIT4
-#define ODM_COMP_CCK_PD BIT5
-#define ODM_COMP_ANT_DIV BIT6
-#define ODM_COMP_PWR_SAVE BIT7
-#define ODM_COMP_PWR_TRAIN BIT8
-#define ODM_COMP_RATE_ADAPTIVE BIT9
-#define ODM_COMP_PATH_DIV BIT10
-#define ODM_COMP_PSD BIT11
-#define ODM_COMP_DYNAMIC_PRICCA BIT12
-#define ODM_COMP_RXHP BIT13
-#define ODM_COMP_MP BIT14
-#define ODM_COMP_CFO_TRACKING BIT15
-/* MAC Functions */
-#define ODM_COMP_EDCA_TURBO BIT16
-#define ODM_COMP_EARLY_MODE BIT17
-/* RF Functions */
-#define ODM_COMP_TX_PWR_TRACK BIT24
-#define ODM_COMP_RX_GAIN_TRACK BIT25
-#define ODM_COMP_CALIBRATION BIT26
-/* Common Functions */
-#define ODM_COMP_COMMON BIT30
-#define ODM_COMP_INIT BIT31
-
-/*------------------------Export Marco Definition---------------------------*/
- #define DbgPrint printk
- #define RT_PRINTK(fmt, args...)\
- DbgPrint("%s(): " fmt, __func__, ## args)
- #define RT_DISP(dbgtype, dbgflag, printstr)
-
-#ifndef ASSERT
- #define ASSERT(expr)
-#endif
-
-#if DBG
-#define ODM_RT_TRACE(pDM_Odm, comp, level, fmt)\
- do {\
- if (\
- (comp & pDM_Odm->DebugComponents) &&\
- (level <= pDM_Odm->DebugLevel ||\
- level == ODM_DBG_SERIOUS)\
- ) {\
- RT_PRINTK fmt;\
- } \
- } while (0)
-
-#define ODM_RT_TRACE_F(pDM_Odm, comp, level, fmt)\
- do {\
- if (\
- (comp & pDM_Odm->DebugComponents) &&\
- (level <= pDM_Odm->DebugLevel)\
- ) {\
- RT_PRINTK fmt;\
- } \
- } while (0)
-
-#define ODM_RT_ASSERT(pDM_Odm, expr, fmt)\
- do {\
- if (!expr) {\
- DbgPrint("Assertion failed! %s at ......\n", #expr);\
- DbgPrint(\
- " ......%s,%s, line =%d\n",\
- __FILE__,\
- __func__,\
- __LINE__\
- );\
- RT_PRINTK fmt;\
- ASSERT(false);\
- } \
- } while (0)
-#define ODM_dbg_trace(str) { DbgPrint("%s:%s\n", __func__, str); }
-
-#define ODM_PRINT_ADDR(pDM_Odm, comp, level, title_str, ptr)\
- do {\
- if (\
- (comp & pDM_Odm->DebugComponents) &&\
- (level <= pDM_Odm->DebugLevel)\
- ) {\
- int __i;\
- u8 *__ptr = (u8 *)ptr;\
- DbgPrint("[ODM] ");\
- DbgPrint(title_str);\
- DbgPrint(" ");\
- for (__i = 0; __i < 6; __i++)\
- DbgPrint("%02X%s", __ptr[__i], (__i == 5) ? "" : "-");\
- DbgPrint("\n");\
- } \
- } while (0)
-#else
-#define ODM_RT_TRACE(pDM_Odm, comp, level, fmt) no_printk fmt
-#define ODM_RT_TRACE_F(pDM_Odm, comp, level, fmt) no_printk fmt
-#define ODM_RT_ASSERT(pDM_Odm, expr, fmt) no_printk fmt
-#define ODM_dbg_enter() do {} while (0)
-#define ODM_dbg_exit() do {} while (0)
-#define ODM_dbg_trace(str) no_printk("%s", str)
-#define ODM_PRINT_ADDR(pDM_Odm, comp, level, title_str, ptr) \
- no_printk("%s %p", title_str, ptr)
-#endif
-
-void ODM_InitDebugSetting(struct dm_odm_t *pDM_Odm);
-
-#endif /* __ODM_DBG_H__ */
diff --git a/drivers/staging/rtl8723bs/hal/odm_precomp.h b/drivers/staging/rtl8723bs/hal/odm_precomp.h
index d48d681472d5..5041c9535e9a 100644
--- a/drivers/staging/rtl8723bs/hal/odm_precomp.h
+++ b/drivers/staging/rtl8723bs/hal/odm_precomp.h
@@ -27,11 +27,9 @@
#include "odm.h"
#include "odm_HWConfig.h"
-#include "odm_debug.h"
#include "odm_RegDefine11N.h"
#include "odm_EdcaTurboCheck.h"
#include "odm_DIG.h"
-#include "odm_PathDiv.h"
#include "odm_DynamicBBPowerSaving.h"
#include "odm_DynamicTxPower.h"
#include "odm_CfoTracking.h"
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c
index 2451875ab3c0..2b7077bb52df 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c
@@ -114,14 +114,13 @@ static void ConstructBeacon(struct adapter *padapter, u8 *pframe, u32 *pLength)
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
- u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
pwlanhdr = (struct ieee80211_hdr *)pframe;
fctrl = &(pwlanhdr->frame_control);
*(fctrl) = 0;
- memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+ eth_broadcast_addr(pwlanhdr->addr1);
memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
@@ -309,9 +308,6 @@ static void rtl8723b_set_FwRsvdPage_cmd(struct adapter *padapter, struct rsvdpag
SET_8723B_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocQosNull);
SET_8723B_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocBTQosNull);
- print_hex_dump_debug(DRIVER_PREFIX ": u1H2CRsvdPageParm:", DUMP_PREFIX_NONE,
- 16, 1, u1H2CRsvdPageParm, H2C_RSVDPAGE_LOC_LEN, false);
-
FillH2CCmd8723B(padapter, H2C_8723B_RSVD_PAGE, H2C_RSVDPAGE_LOC_LEN, u1H2CRsvdPageParm);
}
@@ -329,9 +325,6 @@ void rtl8723b_set_FwMediaStatusRpt_cmd(struct adapter *padapter, u8 mstatus, u8
SET_8723B_H2CCMD_MSRRPT_PARM_MACID(u1H2CMediaStatusRptParm, macid);
SET_8723B_H2CCMD_MSRRPT_PARM_MACID_END(u1H2CMediaStatusRptParm, macid_end);
- print_hex_dump_debug(DRIVER_PREFIX ": u1H2CMediaStatusRptParm:", DUMP_PREFIX_NONE,
- 16, 1, u1H2CMediaStatusRptParm, H2C_MEDIA_STATUS_RPT_LEN, false);
-
FillH2CCmd8723B(padapter, H2C_8723B_MEDIA_STATUS_RPT, H2C_MEDIA_STATUS_RPT_LEN, u1H2CMediaStatusRptParm);
}
@@ -348,9 +341,6 @@ void rtl8723b_set_FwMacIdConfig_cmd(struct adapter *padapter, u8 mac_id, u8 raid
SET_8723B_H2CCMD_MACID_CFG_RATE_MASK2(u1H2CMacIdConfigParm, (u8)((mask & 0x00ff0000) >> 16));
SET_8723B_H2CCMD_MACID_CFG_RATE_MASK3(u1H2CMacIdConfigParm, (u8)((mask & 0xff000000) >> 24));
- print_hex_dump_debug(DRIVER_PREFIX ": u1H2CMacIdConfigParm:", DUMP_PREFIX_NONE,
- 16, 1, u1H2CMacIdConfigParm, H2C_MACID_CFG_LEN, false);
-
FillH2CCmd8723B(padapter, H2C_8723B_MACID_CFG, H2C_MACID_CFG_LEN, u1H2CMacIdConfigParm);
}
@@ -365,9 +355,6 @@ void rtl8723b_set_rssi_cmd(struct adapter *padapter, u8 *param)
SET_8723B_H2CCMD_RSSI_SETTING_RSSI(u1H2CRssiSettingParm, rssi);
SET_8723B_H2CCMD_RSSI_SETTING_ULDL_STATE(u1H2CRssiSettingParm, uldl_state);
- print_hex_dump_debug(DRIVER_PREFIX ": u1H2CRssiSettingParm:", DUMP_PREFIX_NONE,
- 16, 1, u1H2CRssiSettingParm, H2C_RSSI_SETTING_LEN, false);
-
FillH2CCmd8723B(padapter, H2C_8723B_RSSI_SETTING, H2C_RSSI_SETTING_LEN, u1H2CRssiSettingParm);
}
@@ -465,9 +452,6 @@ void rtl8723b_set_FwPwrMode_cmd(struct adapter *padapter, u8 psmode)
hal_btcoex_RecordPwrMode(padapter, u1H2CPwrModeParm, H2C_PWRMODE_LEN);
- print_hex_dump_debug(DRIVER_PREFIX ": u1H2CPwrModeParm:", DUMP_PREFIX_NONE,
- 16, 1, u1H2CPwrModeParm, H2C_PWRMODE_LEN, false);
-
FillH2CCmd8723B(padapter, H2C_8723B_SET_PWR_MODE, H2C_PWRMODE_LEN, u1H2CPwrModeParm);
}
@@ -485,9 +469,6 @@ void rtl8723b_set_FwPsTuneParam_cmd(struct adapter *padapter)
SET_8723B_H2CCMD_PSTUNE_PARM_ADOPT(u1H2CPsTuneParm, 1);
SET_8723B_H2CCMD_PSTUNE_PARM_DTIM_PERIOD(u1H2CPsTuneParm, dtim_period);
- print_hex_dump_debug(DRIVER_PREFIX ": u1H2CPsTuneParm:", DUMP_PREFIX_NONE,
- 16, 1, u1H2CPsTuneParm, H2C_PSTUNEPARAM_LEN, false);
-
FillH2CCmd8723B(padapter, H2C_8723B_PS_TUNING_PARA, H2C_PSTUNEPARAM_LEN, u1H2CPsTuneParm);
}
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c b/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c
index 23be025ceb5b..5840a5241fde 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c
@@ -109,7 +109,6 @@ static void Update_ODM_ComInfo_8723b(struct adapter *Adapter)
ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_CHNL, &(pHalData->CurrentChannel));
ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_NET_CLOSED, &(Adapter->net_closed));
ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_MP_MODE, &zero);
- ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_BAND, &(pHalData->CurrentBandType));
ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_FORCED_IGI_LB, &(pHalData->u1ForcedIgiLb));
ODM_CmnInfoHook(pDM_Odm, ODM_CMNINFO_FORCED_RATE, &(pHalData->ForcedDataRate));
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
index 082448557b53..059d3050acc6 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
@@ -122,7 +122,6 @@ static int _WriteFW(struct adapter *padapter, void *buffer, u32 size)
u8 *bufferPtr = buffer;
pageNums = size / MAX_DLFW_PAGE_SIZE;
- /* RT_ASSERT((pageNums <= 4), ("Page numbers should not greater then 4\n")); */
remainSize = size % MAX_DLFW_PAGE_SIZE;
for (page = 0; page < pageNums; page++) {
@@ -1149,10 +1148,8 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest)
retU2 = ((bank-1)*EFUSE_BT_REAL_BANK_CONTENT_LEN)+efuse_addr;
if (bPseudoTest) {
pEfuseHal->fakeBTEfuseUsedBytes = retU2;
- /* RT_DISP(FEEPROM, EFUSE_PG, ("Hal_EfuseGetCurrentSize_BT92C(), already use %u bytes\n", pEfuseHal->fakeBTEfuseUsedBytes)); */
} else {
pEfuseHal->BTEfuseUsedBytes = retU2;
- /* RT_DISP(FEEPROM, EFUSE_PG, ("Hal_EfuseGetCurrentSize_BT92C(), already use %u bytes\n", pEfuseHal->BTEfuseUsedBytes)); */
}
return retU2;
@@ -2512,15 +2509,8 @@ u8 BWMapping_8723B(struct adapter *Adapter, struct pkt_attrib *pattrib)
u8 BWSettingOfDesc = 0;
struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
- if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_80) {
- if (pattrib->bwmode == CHANNEL_WIDTH_80)
- BWSettingOfDesc = 2;
- else if (pattrib->bwmode == CHANNEL_WIDTH_40)
- BWSettingOfDesc = 1;
- else
- BWSettingOfDesc = 0;
- } else if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40) {
- if ((pattrib->bwmode == CHANNEL_WIDTH_40) || (pattrib->bwmode == CHANNEL_WIDTH_80))
+ if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40) {
+ if (pattrib->bwmode == CHANNEL_WIDTH_40)
BWSettingOfDesc = 1;
else
BWSettingOfDesc = 0;
@@ -2538,38 +2528,20 @@ u8 SCMapping_8723B(struct adapter *Adapter, struct pkt_attrib *pattrib)
u8 SCSettingOfDesc = 0;
struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
- if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_80) {
- if (pattrib->bwmode == CHANNEL_WIDTH_80) {
- SCSettingOfDesc = VHT_DATA_SC_DONOT_CARE;
- } else if (pattrib->bwmode == CHANNEL_WIDTH_40) {
- if (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER)
- SCSettingOfDesc = VHT_DATA_SC_40_LOWER_OF_80MHZ;
- else if (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER)
- SCSettingOfDesc = VHT_DATA_SC_40_UPPER_OF_80MHZ;
- } else {
- if ((pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) && (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER))
- SCSettingOfDesc = VHT_DATA_SC_20_LOWEST_OF_80MHZ;
- else if ((pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) && (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER))
- SCSettingOfDesc = VHT_DATA_SC_20_LOWER_OF_80MHZ;
- else if ((pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) && (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER))
- SCSettingOfDesc = VHT_DATA_SC_20_UPPER_OF_80MHZ;
- else if ((pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) && (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER))
- SCSettingOfDesc = VHT_DATA_SC_20_UPPERST_OF_80MHZ;
- }
- } else if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40) {
+ if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40) {
if (pattrib->bwmode == CHANNEL_WIDTH_40) {
- SCSettingOfDesc = VHT_DATA_SC_DONOT_CARE;
+ SCSettingOfDesc = HT_DATA_SC_DONOT_CARE;
} else if (pattrib->bwmode == CHANNEL_WIDTH_20) {
if (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) {
- SCSettingOfDesc = VHT_DATA_SC_20_UPPER_OF_80MHZ;
+ SCSettingOfDesc = HT_DATA_SC_20_UPPER_OF_40MHZ;
} else if (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) {
- SCSettingOfDesc = VHT_DATA_SC_20_LOWER_OF_80MHZ;
+ SCSettingOfDesc = HT_DATA_SC_20_LOWER_OF_40MHZ;
} else {
- SCSettingOfDesc = VHT_DATA_SC_DONOT_CARE;
+ SCSettingOfDesc = HT_DATA_SC_DONOT_CARE;
}
}
} else {
- SCSettingOfDesc = VHT_DATA_SC_DONOT_CARE;
+ SCSettingOfDesc = HT_DATA_SC_DONOT_CARE;
}
return SCSettingOfDesc;
@@ -3315,9 +3287,6 @@ void C2HPacketHandler_8723B(struct adapter *padapter, u8 *pbuffer, u16 length)
C2hEvent.CmdLen = length-2;
tmpBuf = pbuffer+2;
- print_hex_dump_debug(DRIVER_PREFIX ": C2HPacketHandler_8723B(): Command Content:\n",
- DUMP_PREFIX_NONE, 16, 1, tmpBuf, C2hEvent.CmdLen, false);
-
process_c2h_event(padapter, &C2hEvent, tmpBuf);
/* c2h_handler_8723b(padapter,&C2hEvent); */
}
@@ -3898,27 +3867,19 @@ u8 GetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, v
{
u8 mac_id = *(u8 *)pval;
u32 cmd;
- u32 ra_info1, ra_info2;
- u32 rate_mask1, rate_mask2;
- u8 curr_tx_rate, curr_tx_sgi, hight_rate, lowest_rate;
cmd = 0x40000100 | mac_id;
rtw_write32(padapter, REG_HMEBOX_DBG_2_8723B, cmd);
msleep(10);
- ra_info1 = rtw_read32(padapter, 0x2F0);
- curr_tx_rate = ra_info1&0x7F;
- curr_tx_sgi = (ra_info1>>7)&0x01;
+ rtw_read32(padapter, 0x2F0); // info 1
cmd = 0x40000400 | mac_id;
rtw_write32(padapter, REG_HMEBOX_DBG_2_8723B, cmd);
msleep(10);
- ra_info1 = rtw_read32(padapter, 0x2F0);
- ra_info2 = rtw_read32(padapter, 0x2F4);
- rate_mask1 = rtw_read32(padapter, 0x2F8);
- rate_mask2 = rtw_read32(padapter, 0x2FC);
- hight_rate = ra_info2&0xFF;
- lowest_rate = (ra_info2>>8) & 0xFF;
-
+ rtw_read32(padapter, 0x2F0); // info 1
+ rtw_read32(padapter, 0x2F4); // info 2
+ rtw_read32(padapter, 0x2F8); // rate mask 1
+ rtw_read32(padapter, 0x2FC); // rate mask 2
}
break;
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c b/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c
index f43abf9b0d22..6e524034f388 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c
@@ -38,7 +38,7 @@ static u32 phy_CalculateBitShift(u32 BitMask)
/**
- * PHY_QueryBBReg - Read "specific bits" from BB register.
+ * PHY_QueryBBReg_8723B - Read "specific bits" from BB register.
* @Adapter:
* @RegAddr: The target address to be readback
* @BitMask: The target bit position in the target address
@@ -53,10 +53,6 @@ u32 PHY_QueryBBReg_8723B(struct adapter *Adapter, u32 RegAddr, u32 BitMask)
{
u32 OriginalValue, BitShift;
-#if (DISABLE_BB_RF == 1)
- return 0;
-#endif
-
OriginalValue = rtw_read32(Adapter, RegAddr);
BitShift = phy_CalculateBitShift(BitMask);
@@ -66,7 +62,7 @@ u32 PHY_QueryBBReg_8723B(struct adapter *Adapter, u32 RegAddr, u32 BitMask)
/**
- * PHY_SetBBReg - Write "Specific bits" to BB register (page 8~).
+ * PHY_SetBBReg_8723B - Write "Specific bits" to BB register (page 8~).
* @Adapter:
* @RegAddr: The target address to be modified
* @BitMask: The target bit position in the target address
@@ -88,10 +84,6 @@ void PHY_SetBBReg_8723B(
/* u16 BBWaitCounter = 0; */
u32 OriginalValue, BitShift;
-#if (DISABLE_BB_RF == 1)
- return;
-#endif
-
if (BitMask != bMaskDWord) { /* if not "double word" write */
OriginalValue = rtw_read32(Adapter, RegAddr);
BitShift = phy_CalculateBitShift(BitMask);
@@ -231,10 +223,10 @@ static void phy_RFSerialWrite_8723B(
/**
- * PHY_QueryRFReg - Query "Specific bits" to RF register (page 8~).
+ * PHY_QueryRFReg_8723B - Query "Specific bits" to RF register (page 8~).
* @Adapter:
* @eRFPath: Radio path of A/B/C/D
- * @RegAdd: The target address to be read
+ * @RegAddr: The target address to be read
* @BitMask: The target bit position in the target address
* to be read
*
@@ -252,10 +244,6 @@ u32 PHY_QueryRFReg_8723B(
{
u32 Original_Value, BitShift;
-#if (DISABLE_BB_RF == 1)
- return 0;
-#endif
-
Original_Value = phy_RFSerialRead_8723B(Adapter, eRFPath, RegAddr);
BitShift = phy_CalculateBitShift(BitMask);
@@ -263,7 +251,7 @@ u32 PHY_QueryRFReg_8723B(
}
/**
- * PHY_SetRFReg - Write "Specific bits" to RF register (page 8~).
+ * PHY_SetRFReg_8723B - Write "Specific bits" to RF register (page 8~).
* @Adapter:
* @eRFPath: Radio path of A/B/C/D
* @RegAddr: The target address to be modified
@@ -285,10 +273,6 @@ void PHY_SetRFReg_8723B(
{
u32 Original_Value, BitShift;
-#if (DISABLE_BB_RF == 1)
- return;
-#endif
-
/* RF data is 12 bits only */
if (BitMask != bRFRegOffsetMask) {
Original_Value = phy_RFSerialRead_8723B(Adapter, eRFPath, RegAddr);
@@ -562,15 +546,13 @@ u8 PHY_GetTxPowerIndex(
{
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
s8 txPower = 0, powerDiffByRate = 0, limit = 0;
- bool bIn24G = false;
- txPower = (s8) PHY_GetTxPowerIndexBase(padapter, RFPath, Rate, BandWidth, Channel, &bIn24G);
- powerDiffByRate = PHY_GetTxPowerByRate(padapter, BAND_ON_2_4G, ODM_RF_PATH_A, RF_1TX, Rate);
+ txPower = (s8) PHY_GetTxPowerIndexBase(padapter, RFPath, Rate, BandWidth, Channel);
+ powerDiffByRate = PHY_GetTxPowerByRate(padapter, ODM_RF_PATH_A, RF_1TX, Rate);
limit = phy_get_tx_pwr_lmt(
padapter,
padapter->registrypriv.RegPwrTblSel,
- (u8)(!bIn24G),
pHalData->CurrentChannelBW,
RFPath,
Rate,
@@ -625,11 +607,6 @@ static void phy_SetRegBW_8723B(
rtw_write16(Adapter, REG_TRXPTCL_CTL_8723B, (u2tmp & 0xFEFF)); /* BIT 7 = 1, BIT 8 = 0 */
break;
- case CHANNEL_WIDTH_80:
- u2tmp = RegRfMod_BW | BIT8;
- rtw_write16(Adapter, REG_TRXPTCL_CTL_8723B, (u2tmp & 0xFF7F)); /* BIT 7 = 0, BIT 8 = 1 */
- break;
-
default:
break;
}
@@ -640,37 +617,11 @@ static u8 phy_GetSecondaryChnl_8723B(struct adapter *Adapter)
u8 SCSettingOf40 = 0, SCSettingOf20 = 0;
struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
- if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_80) {
- if (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER)
- SCSettingOf40 = VHT_DATA_SC_40_LOWER_OF_80MHZ;
- else if (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER)
- SCSettingOf40 = VHT_DATA_SC_40_UPPER_OF_80MHZ;
-
- if (
- (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) &&
- (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER)
- )
- SCSettingOf20 = VHT_DATA_SC_20_LOWEST_OF_80MHZ;
- else if (
- (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) &&
- (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER)
- )
- SCSettingOf20 = VHT_DATA_SC_20_LOWER_OF_80MHZ;
- else if (
- (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) &&
- (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER)
- )
- SCSettingOf20 = VHT_DATA_SC_20_UPPER_OF_80MHZ;
- else if (
- (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) &&
- (pHalData->nCur80MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER)
- )
- SCSettingOf20 = VHT_DATA_SC_20_UPPERST_OF_80MHZ;
- } else if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40) {
+ if (pHalData->CurrentChannelBW == CHANNEL_WIDTH_40) {
if (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER)
- SCSettingOf20 = VHT_DATA_SC_20_UPPER_OF_80MHZ;
+ SCSettingOf20 = HT_DATA_SC_20_UPPER_OF_40MHZ;
else if (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER)
- SCSettingOf20 = VHT_DATA_SC_20_LOWER_OF_80MHZ;
+ SCSettingOf20 = HT_DATA_SC_20_LOWER_OF_40MHZ;
}
return (SCSettingOf40 << 4) | SCSettingOf20;
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c
index 7c2680b6508c..ad803ffc0696 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c
@@ -108,7 +108,7 @@ static void update_recvframe_phyinfo(union recv_frame *precvframe,
!pattrib->icv_err && !pattrib->crc_err &&
ether_addr_equal(rx_bssid, my_bssid));
- rx_ra = get_ra(wlanhdr);
+ rx_ra = rtl8723bs_get_ra(wlanhdr);
my_hwaddr = myid(&padapter->eeprompriv);
pkt_info.to_self = pkt_info.bssid_match &&
ether_addr_equal(rx_ra, my_hwaddr);
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
index bd95e62fb053..a05d43b716ee 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
@@ -178,7 +178,7 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
struct hw_xmit *hwxmits, *phwxmit;
u8 idx, hwentry;
struct tx_servq *ptxservq;
- struct list_head *sta_plist, *sta_phead, *frame_plist, *frame_phead;
+ struct list_head *sta_plist, *sta_phead, *frame_plist, *frame_phead, *tmp;
struct xmit_frame *pxmitframe;
struct __queue *pframe_queue;
struct xmit_buf *pxmitbuf;
@@ -223,12 +223,11 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
spin_lock_bh(&pxmitpriv->lock);
sta_phead = get_list_head(phwxmit->sta_queue);
- sta_plist = get_next(sta_phead);
/* because stop_sta_xmit may delete sta_plist at any time */
/* so we should add lock here, or while loop can not exit */
- while (sta_phead != sta_plist) {
- ptxservq = container_of(sta_plist, struct tx_servq, tx_pending);
- sta_plist = get_next(sta_plist);
+ list_for_each_safe(sta_plist, tmp, sta_phead) {
+ ptxservq = list_entry(sta_plist, struct tx_servq,
+ tx_pending);
pframe_queue = &ptxservq->sta_pending;
diff --git a/drivers/staging/rtl8723bs/hal/sdio_halinit.c b/drivers/staging/rtl8723bs/hal/sdio_halinit.c
index abd90026a8c7..a07a6dacec42 100644
--- a/drivers/staging/rtl8723bs/hal/sdio_halinit.c
+++ b/drivers/staging/rtl8723bs/hal/sdio_halinit.c
@@ -4,8 +4,6 @@
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-#define _SDIO_HALINIT_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
#include <rtl8723b_hal.h>
@@ -228,7 +226,6 @@ static void _InitNormalChipOneOutEpPriority(struct adapter *Adapter)
value = QUEUE_NORMAL;
break;
default:
- /* RT_ASSERT(false, ("Shall not reach here!\n")); */
break;
}
@@ -262,7 +259,6 @@ static void _InitNormalChipTwoOutEpPriority(struct adapter *Adapter)
valueLow = QUEUE_NORMAL;
break;
default:
- /* RT_ASSERT(false, ("Shall not reach here!\n")); */
break;
}
@@ -327,7 +323,6 @@ static void _InitQueuePriority(struct adapter *Adapter)
_InitNormalChipThreeOutEpPriority(Adapter);
break;
default:
- /* RT_ASSERT(false, ("Shall not reach here!\n")); */
break;
}
@@ -517,9 +512,6 @@ static void _InitOperationMode(struct adapter *padapter)
case WIRELESS_MODE_B:
regBwOpMode = BW_OPMODE_20MHZ;
break;
- case WIRELESS_MODE_A:
-/* RT_ASSERT(false, ("Error wireless a mode\n")); */
- break;
case WIRELESS_MODE_G:
regBwOpMode = BW_OPMODE_20MHZ;
break;
@@ -531,10 +523,6 @@ static void _InitOperationMode(struct adapter *padapter)
/* CCK rate will be filtered out only when associated AP does not support it. */
regBwOpMode = BW_OPMODE_20MHZ;
break;
- case WIRELESS_MODE_N_5G:
-/* RT_ASSERT(false, ("Error wireless mode")); */
- regBwOpMode = BW_OPMODE_5G;
- break;
default: /* for MacOSX compiler warning. */
break;
@@ -567,11 +555,6 @@ static void _InitRFType(struct adapter *padapter)
{
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
-#if DISABLE_BB_RF
- pHalData->rf_chip = RF_PSEUDO_11N;
- return;
-#endif
-
pHalData->rf_chip = RF_6052;
pHalData->rf_type = RF_1T1R;
@@ -695,29 +678,23 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
/* <Roger_Notes> Current Channel will be updated again later. */
pHalData->CurrentChannel = 6;
-#if (HAL_MAC_ENABLE == 1)
ret = PHY_MACConfig8723B(padapter);
if (ret != _SUCCESS)
return ret;
-#endif
/* */
/* d. Initialize BB related configurations. */
/* */
-#if (HAL_BB_ENABLE == 1)
ret = PHY_BBConfig8723B(padapter);
if (ret != _SUCCESS)
return ret;
-#endif
/* If RF is on, we need to init RF. Otherwise, skip the procedure. */
/* We need to follow SU method to change the RF cfg.txt. Default disable RF TX/RX mode. */
/* if (pHalData->eRFPowerState == eRfOn) */
{
-#if (HAL_RF_ENABLE == 1)
ret = PHY_RFConfig8723B(padapter);
if (ret != _SUCCESS)
return ret;
-#endif
}
/* */
@@ -798,8 +775,6 @@ static u32 rtl8723bs_hal_init(struct adapter *padapter)
rtl8723b_InitHalDm(padapter);
- /* DbgPrint("pHalData->DefaultTxPwrDbm = %d\n", pHalData->DefaultTxPwrDbm); */
-
/* */
/* Update current Tx FIFO page status. */
/* */
@@ -878,10 +853,9 @@ static void CardDisableRTL8723BSdio(struct adapter *padapter)
{
u8 u1bTmp;
u8 bMacPwrCtrlOn;
- u8 ret = _FAIL;
/* Run LPS WL RFOFF flow */
- ret = HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, rtl8723B_enter_lps_flow);
+ HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, rtl8723B_enter_lps_flow);
/* ==== Reset digital sequence ====== */
@@ -909,9 +883,8 @@ static void CardDisableRTL8723BSdio(struct adapter *padapter)
/* ==== Reset digital sequence end ====== */
bMacPwrCtrlOn = false; /* Disable CMD53 R/W */
- 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);
+ HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, rtl8723B_card_disable_flow);
}
static u32 rtl8723bs_hal_deinit(struct adapter *padapter)
@@ -1046,11 +1019,7 @@ static void _ReadRFType(struct adapter *Adapter)
{
struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
-#if DISABLE_BB_RF
- pHalData->rf_chip = RF_PSEUDO_11N;
-#else
pHalData->rf_chip = RF_6052;
-#endif
}
diff --git a/drivers/staging/rtl8723bs/hal/sdio_ops.c b/drivers/staging/rtl8723bs/hal/sdio_ops.c
index a31694525bc1..2dd251ce177e 100644
--- a/drivers/staging/rtl8723bs/hal/sdio_ops.c
+++ b/drivers/staging/rtl8723bs/hal/sdio_ops.c
@@ -4,8 +4,6 @@
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
*******************************************************************************/
-#define _SDIO_OPS_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
#include <rtl8723b_hal.h>
@@ -160,7 +158,7 @@ static u32 sdio_read32(struct intf_hdl *intfhdl, u32 addr)
u32 ftaddr;
u8 shift;
u32 val;
- s32 err;
+ s32 __maybe_unused err;
__le32 le_tmp;
adapter = intfhdl->padapter;
@@ -348,11 +346,6 @@ static s32 sdio_writeN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf)
return err;
}
-static u8 sdio_f0_read8(struct intf_hdl *intfhdl, u32 addr)
-{
- return sd_f0_read8(intfhdl, addr, NULL);
-}
-
static void sdio_read_mem(
struct intf_hdl *intfhdl,
u32 addr,
@@ -360,10 +353,7 @@ static void sdio_read_mem(
u8 *rmem
)
{
- s32 err;
-
- err = sdio_readN(intfhdl, addr, cnt, rmem);
- /* TODO: Report error is err not zero */
+ sdio_readN(intfhdl, addr, cnt, rmem);
}
static void sdio_write_mem(
@@ -486,8 +476,6 @@ void sdio_set_intf_ops(struct adapter *adapter, struct _io_ops *ops)
ops->_writeN = &sdio_writeN;
ops->_write_mem = &sdio_write_mem;
ops->_write_port = &sdio_write_port;
-
- ops->_sd_f0_read8 = sdio_f0_read8;
}
/*
diff --git a/drivers/staging/rtl8723bs/include/Hal8192CPhyReg.h b/drivers/staging/rtl8723bs/include/Hal8192CPhyReg.h
index 4b3a7c051630..aad962548278 100644
--- a/drivers/staging/rtl8723bs/include/Hal8192CPhyReg.h
+++ b/drivers/staging/rtl8723bs/include/Hal8192CPhyReg.h
@@ -558,7 +558,6 @@
#define b3WireRFPowerDown 0x1 /* Useless now */
/* define bHWSISelect 0x8 */
-#define b5GPAPEPolarity 0x40000000
#define b2GPAPEPolarity 0x80000000
#define bRFSW_TxDefaultAnt 0x3
#define bRFSW_TxOptionAnt 0x30
@@ -577,7 +576,6 @@
#define bRFSI_ANTSW 0x100
#define bRFSI_ANTSWB 0x200
#define bRFSI_PAPE 0x400
-#define bRFSI_PAPE5G 0x800
#define bBandSelect 0x1
#define bHTSIG2_GI 0x80
#define bHTSIG2_Smoothing 0x01
diff --git a/drivers/staging/rtl8723bs/include/autoconf.h b/drivers/staging/rtl8723bs/include/autoconf.h
deleted file mode 100644
index 944a7d2a1e53..000000000000
--- a/drivers/staging/rtl8723bs/include/autoconf.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-
-/*
- * Automatically generated C config: don't edit
- */
-
-/*
- * Functions Config
- */
-
-#ifndef CONFIG_WIRELESS_EXT
-#error CONFIG_WIRELESS_EXT needs to be enabled for this driver to work
-#endif
-
-/*
- * Auto Config Section
- */
-#define LPS_RPWM_WAIT_MS 300
-#ifndef DISABLE_BB_RF
-#define DISABLE_BB_RF 0
-#endif
-
-#if DISABLE_BB_RF
- #define HAL_MAC_ENABLE 0
- #define HAL_BB_ENABLE 0
- #define HAL_RF_ENABLE 0
-#else
- #define HAL_MAC_ENABLE 1
- #define HAL_BB_ENABLE 1
- #define HAL_RF_ENABLE 1
-#endif
-
-/*
- * Platform dependent
- */
-#define WAKEUP_GPIO_IDX 12 /* WIFI Chip Side */
-
-/*
- * Debug Related Config
- */
-
-#define DBG 0 /* for ODM & BTCOEX debug */
-
-/* define DBG_XMIT_BUF */
-/* define DBG_XMIT_BUF_EXT */
diff --git a/drivers/staging/rtl8723bs/include/drv_conf.h b/drivers/staging/rtl8723bs/include/drv_conf.h
deleted file mode 100644
index 9cef9ce589a1..000000000000
--- a/drivers/staging/rtl8723bs/include/drv_conf.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-#ifndef __DRV_CONF_H__
-#define __DRV_CONF_H__
-#include "autoconf.h"
-
-#define DYNAMIC_CAMID_ALLOC
-
-#ifndef CONFIG_RTW_HIQ_FILTER
- #define CONFIG_RTW_HIQ_FILTER 1
-#endif
-
-//#include <rtl871x_byteorder.h>
-
-#endif // __DRV_CONF_H__
diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h
index 83d43e5726dd..895c41526164 100644
--- a/drivers/staging/rtl8723bs/include/drv_types.h
+++ b/drivers/staging/rtl8723bs/include/drv_types.h
@@ -15,7 +15,6 @@
#define __DRV_TYPES_H__
#include <linux/sched/signal.h>
-#include <autoconf.h>
#include <basic_types.h>
#include <osdep_service.h>
#include <rtw_byteorder.h>
@@ -109,9 +108,11 @@ struct registry_priv {
struct wlan_bssid_ex dev_network;
u8 ht_enable;
- /* 0: 20 MHz, 1: 40 MHz, 2: 80 MHz, 3: 160MHz */
- /* 2.4G use bit 0 ~ 3, 5G use bit 4 ~ 7 */
- /* 0x21 means enable 2.4G 40MHz & 5G 80MHz */
+ /*
+ * 0: 20 MHz, 1: 40 MHz
+ * 2.4G use bit 0 ~ 3
+ * 0x01 means enable 2.4G 40MHz
+ */
u8 bw_mode;
u8 ampdu_enable;/* for tx */
u8 rx_stbc;
@@ -170,9 +171,7 @@ struct registry_priv {
u8 RegPowerBase;
u8 RegPwrTblSel;
s8 TxBBSwing_2G;
- s8 TxBBSwing_5G;
u8 AmplifierType_2G;
- u8 AmplifierType_5G;
u8 bEn_RFE;
u8 RFE_Type;
u8 check_fw_ps;
@@ -503,7 +502,6 @@ static inline u8 *myid(struct eeprom_priv *peepriv)
void rtw_indicate_wx_disassoc_event(struct adapter *padapter);
void rtw_indicate_wx_assoc_event(struct adapter *padapter);
-void rtw_indicate_wx_disassoc_event(struct adapter *padapter);
void indicate_wx_scan_complete_event(struct adapter *padapter);
int rtw_change_ifname(struct adapter *padapter, const char *ifname);
diff --git a/drivers/staging/rtl8723bs/include/hal_btcoex.h b/drivers/staging/rtl8723bs/include/hal_btcoex.h
index 3c03be210d87..849fb90b43b7 100644
--- a/drivers/staging/rtl8723bs/include/hal_btcoex.h
+++ b/drivers/staging/rtl8723bs/include/hal_btcoex.h
@@ -9,6 +9,8 @@
#include <drv_types.h>
+#define LPS_RPWM_WAIT_MS 300
+
/* Some variables can't get from outsrc BT-Coex, */
/* so we need to save here */
struct bt_coexist {
@@ -53,7 +55,5 @@ u8 hal_btcoex_LpsVal(struct adapter *);
u32 hal_btcoex_GetRaMask(struct adapter *);
void hal_btcoex_RecordPwrMode(struct adapter *padapter, u8 *pCmdBuf, u8 cmdLen);
void hal_btcoex_DisplayBtCoexInfo(struct adapter *, u8 *pbuf, u32 bufsize);
-void hal_btcoex_SetDBG(struct adapter *, u32 *pDbgModule);
-u32 hal_btcoex_GetDBG(struct adapter *, u8 *pStrBuf, u32 bufSize);
#endif /* !__HAL_BTCOEX_H__ */
diff --git a/drivers/staging/rtl8723bs/include/hal_com.h b/drivers/staging/rtl8723bs/include/hal_com.h
index 6bcc443d59fb..1bc332261b2a 100644
--- a/drivers/staging/rtl8723bs/include/hal_com.h
+++ b/drivers/staging/rtl8723bs/include/hal_com.h
@@ -69,46 +69,6 @@
#define DESC_RATEMCS29 0x29
#define DESC_RATEMCS30 0x2A
#define DESC_RATEMCS31 0x2B
-#define DESC_RATEVHTSS1MCS0 0x2C
-#define DESC_RATEVHTSS1MCS1 0x2D
-#define DESC_RATEVHTSS1MCS2 0x2E
-#define DESC_RATEVHTSS1MCS3 0x2F
-#define DESC_RATEVHTSS1MCS4 0x30
-#define DESC_RATEVHTSS1MCS5 0x31
-#define DESC_RATEVHTSS1MCS6 0x32
-#define DESC_RATEVHTSS1MCS7 0x33
-#define DESC_RATEVHTSS1MCS8 0x34
-#define DESC_RATEVHTSS1MCS9 0x35
-#define DESC_RATEVHTSS2MCS0 0x36
-#define DESC_RATEVHTSS2MCS1 0x37
-#define DESC_RATEVHTSS2MCS2 0x38
-#define DESC_RATEVHTSS2MCS3 0x39
-#define DESC_RATEVHTSS2MCS4 0x3A
-#define DESC_RATEVHTSS2MCS5 0x3B
-#define DESC_RATEVHTSS2MCS6 0x3C
-#define DESC_RATEVHTSS2MCS7 0x3D
-#define DESC_RATEVHTSS2MCS8 0x3E
-#define DESC_RATEVHTSS2MCS9 0x3F
-#define DESC_RATEVHTSS3MCS0 0x40
-#define DESC_RATEVHTSS3MCS1 0x41
-#define DESC_RATEVHTSS3MCS2 0x42
-#define DESC_RATEVHTSS3MCS3 0x43
-#define DESC_RATEVHTSS3MCS4 0x44
-#define DESC_RATEVHTSS3MCS5 0x45
-#define DESC_RATEVHTSS3MCS6 0x46
-#define DESC_RATEVHTSS3MCS7 0x47
-#define DESC_RATEVHTSS3MCS8 0x48
-#define DESC_RATEVHTSS3MCS9 0x49
-#define DESC_RATEVHTSS4MCS0 0x4A
-#define DESC_RATEVHTSS4MCS1 0x4B
-#define DESC_RATEVHTSS4MCS2 0x4C
-#define DESC_RATEVHTSS4MCS3 0x4D
-#define DESC_RATEVHTSS4MCS4 0x4E
-#define DESC_RATEVHTSS4MCS5 0x4F
-#define DESC_RATEVHTSS4MCS6 0x50
-#define DESC_RATEVHTSS4MCS7 0x51
-#define DESC_RATEVHTSS4MCS8 0x52
-#define DESC_RATEVHTSS4MCS9 0x53
#define HDATA_RATE(rate)\
(rate == DESC_RATE1M) ? "CCK_1M" : \
@@ -138,27 +98,7 @@
(rate == DESC_RATEMCS12) ? "MCS12" : \
(rate == DESC_RATEMCS13) ? "MCS13" : \
(rate == DESC_RATEMCS14) ? "MCS14" : \
-(rate == DESC_RATEMCS15) ? "MCS15" : \
-(rate == DESC_RATEVHTSS1MCS0) ? "VHTSS1MCS0" : \
-(rate == DESC_RATEVHTSS1MCS1) ? "VHTSS1MCS1" : \
-(rate == DESC_RATEVHTSS1MCS2) ? "VHTSS1MCS2" : \
-(rate == DESC_RATEVHTSS1MCS3) ? "VHTSS1MCS3" : \
-(rate == DESC_RATEVHTSS1MCS4) ? "VHTSS1MCS4" : \
-(rate == DESC_RATEVHTSS1MCS5) ? "VHTSS1MCS5" : \
-(rate == DESC_RATEVHTSS1MCS6) ? "VHTSS1MCS6" : \
-(rate == DESC_RATEVHTSS1MCS7) ? "VHTSS1MCS7" : \
-(rate == DESC_RATEVHTSS1MCS8) ? "VHTSS1MCS8" : \
-(rate == DESC_RATEVHTSS1MCS9) ? "VHTSS1MCS9" : \
-(rate == DESC_RATEVHTSS2MCS0) ? "VHTSS2MCS0" : \
-(rate == DESC_RATEVHTSS2MCS1) ? "VHTSS2MCS1" : \
-(rate == DESC_RATEVHTSS2MCS2) ? "VHTSS2MCS2" : \
-(rate == DESC_RATEVHTSS2MCS3) ? "VHTSS2MCS3" : \
-(rate == DESC_RATEVHTSS2MCS4) ? "VHTSS2MCS4" : \
-(rate == DESC_RATEVHTSS2MCS5) ? "VHTSS2MCS5" : \
-(rate == DESC_RATEVHTSS2MCS6) ? "VHTSS2MCS6" : \
-(rate == DESC_RATEVHTSS2MCS7) ? "VHTSS2MCS7" : \
-(rate == DESC_RATEVHTSS2MCS8) ? "VHTSS2MCS8" : \
-(rate == DESC_RATEVHTSS2MCS9) ? "VHTSS2MCS9" : "UNKNOWN"
+(rate == DESC_RATEMCS15) ? "MCS15" : "UNKNOWN"
enum{
diff --git a/drivers/staging/rtl8723bs/include/hal_com_phycfg.h b/drivers/staging/rtl8723bs/include/hal_com_phycfg.h
index 73f6cadb5c79..c966d0e3e5ae 100644
--- a/drivers/staging/rtl8723bs/include/hal_com_phycfg.h
+++ b/drivers/staging/rtl8723bs/include/hal_com_phycfg.h
@@ -19,10 +19,6 @@ enum rate_section {
HT_MCS8_MCS15,
HT_MCS16_MCS23,
HT_MCS24_MCS31,
- VHT_1SSMCS0_1SSMCS9,
- VHT_2SSMCS0_2SSMCS9,
- VHT_3SSMCS0_3SSMCS9,
- VHT_4SSMCS0_4SSMCS9,
};
enum {
@@ -70,153 +66,55 @@ struct bb_register_def {
};
-u8
-PHY_GetTxPowerByRateBase(
-struct adapter *Adapter,
-u8 Band,
-u8 RfPath,
-u8 TxNum,
-enum rate_section RateSection
- );
-
-u8
-PHY_GetRateSectionIndexOfTxPowerByRate(
-struct adapter *padapter,
-u32 RegAddr,
-u32 BitMask
- );
-
-void
-PHY_GetRateValuesOfTxPowerByRate(
-struct adapter *padapter,
-u32 RegAddr,
-u32 BitMask,
-u32 Value,
-u8 *RateIndex,
-s8 *PwrByRateVal,
-u8 *RateNum
- );
-
-u8
-PHY_GetRateIndexOfTxPowerByRate(
-u8 Rate
- );
-
-void
-PHY_SetTxPowerIndexByRateSection(
-struct adapter *padapter,
-u8 RFPath,
-u8 Channel,
-u8 RateSection
- );
-
-s8
-PHY_GetTxPowerByRate(
-struct adapter *padapter,
-u8 Band,
-u8 RFPath,
-u8 TxNum,
-u8 RateIndex
- );
-
-void
-PHY_SetTxPowerByRate(
-struct adapter *padapter,
-u8 Band,
-u8 RFPath,
-u8 TxNum,
-u8 Rate,
-s8 Value
- );
-
-void
-PHY_SetTxPowerLevelByPath(
-struct adapter *Adapter,
-u8 channel,
-u8 path
- );
-
-void
-PHY_SetTxPowerIndexByRateArray(
-struct adapter *padapter,
-u8 RFPath,
-enum channel_width BandWidth,
-u8 Channel,
-u8 *Rates,
-u8 RateArraySize
- );
-
-void
-PHY_InitTxPowerByRate(
-struct adapter *padapter
- );
-
-void
-PHY_StoreTxPowerByRate(
-struct adapter *padapter,
-u32 Band,
-u32 RfPath,
-u32 TxNum,
-u32 RegAddr,
-u32 BitMask,
-u32 Data
- );
-
-void
-PHY_TxPowerByRateConfiguration(
- struct adapter *padapter
- );
-
-u8
-PHY_GetTxPowerIndexBase(
-struct adapter *padapter,
-u8 RFPath,
-u8 Rate,
-enum channel_width BandWidth,
-u8 Channel,
- bool *bIn24G
- );
+u8 PHY_GetTxPowerByRateBase(struct adapter *Adapter, u8 RfPath, u8 TxNum,
+ enum rate_section RateSection);
+
+u8 PHY_GetRateSectionIndexOfTxPowerByRate(struct adapter *padapter, u32 RegAddr,
+ u32 BitMask);
+
+void PHY_GetRateValuesOfTxPowerByRate(struct adapter *padapter, u32 RegAddr,
+ u32 BitMask, u32 Value, u8 *RateIndex,
+ s8 *PwrByRateVal, u8 *RateNum);
+
+u8 PHY_GetRateIndexOfTxPowerByRate(u8 Rate);
+
+void PHY_SetTxPowerIndexByRateSection(struct adapter *padapter, u8 RFPath, u8 Channel,
+ u8 RateSection);
+
+s8 PHY_GetTxPowerByRate(struct adapter *padapter, u8 RFPath, u8 TxNum, u8 RateIndex);
+
+void PHY_SetTxPowerByRate(struct adapter *padapter, u8 RFPath, u8 TxNum, u8 Rate,
+ s8 Value);
+
+void PHY_SetTxPowerLevelByPath(struct adapter *Adapter, u8 channel, u8 path);
+
+void PHY_SetTxPowerIndexByRateArray(struct adapter *padapter, u8 RFPath,
+ enum channel_width BandWidth, u8 Channel,
+ u8 *Rates, u8 RateArraySize);
+
+void PHY_InitTxPowerByRate(struct adapter *padapter);
+
+void PHY_StoreTxPowerByRate(struct adapter *padapter, u32 RfPath, u32 TxNum,
+ u32 RegAddr, u32 BitMask, u32 Data);
+
+void PHY_TxPowerByRateConfiguration(struct adapter *padapter);
+
+u8 PHY_GetTxPowerIndexBase(struct adapter *padapter, u8 RFPath, u8 Rate,
+ enum channel_width BandWidth, u8 Channel);
s8 phy_get_tx_pwr_lmt(struct adapter *adapter, u32 RegPwrTblSel,
- enum band_type Band, enum channel_width Bandwidth,
-u8 RfPath,
-u8 DataRate,
-u8 Channel
- );
-
-void
-PHY_SetTxPowerLimit(
-struct adapter *Adapter,
-u8 *Regulation,
-u8 *Band,
-u8 *Bandwidth,
-u8 *RateSection,
-u8 *RfPath,
-u8 *Channel,
-u8 *PowerLimit
- );
-
-void
-PHY_ConvertTxPowerLimitToPowerIndex(
-struct adapter *Adapter
- );
-
-void
-PHY_InitTxPowerLimit(
-struct adapter *Adapter
- );
-
-s8
-PHY_GetTxPowerTrackingOffset(
- struct adapter *padapter,
- u8 Rate,
- u8 RFPath
- );
-
-void
-Hal_ChannelPlanToRegulation(
-struct adapter *Adapter,
-u16 ChannelPlan
- );
+ enum channel_width Bandwidth, u8 RfPath, u8 DataRate,
+ u8 Channel);
+
+void PHY_SetTxPowerLimit(struct adapter *Adapter, u8 *Regulation, u8 *Bandwidth,
+ u8 *RateSection, u8 *RfPath, u8 *Channel, u8 *PowerLimit);
+
+void PHY_ConvertTxPowerLimitToPowerIndex(struct adapter *Adapter);
+
+void PHY_InitTxPowerLimit(struct adapter *Adapter);
+
+s8 PHY_GetTxPowerTrackingOffset(struct adapter *padapter, u8 Rate, u8 RFPath);
+
+void Hal_ChannelPlanToRegulation(struct adapter *Adapter, u16 ChannelPlan);
#endif /* __HAL_COMMON_H__ */
diff --git a/drivers/staging/rtl8723bs/include/hal_com_reg.h b/drivers/staging/rtl8723bs/include/hal_com_reg.h
index b14585cb0233..b2f179b48019 100644
--- a/drivers/staging/rtl8723bs/include/hal_com_reg.h
+++ b/drivers/staging/rtl8723bs/include/hal_com_reg.h
@@ -717,7 +717,6 @@ Default: 00b.
/* BW_OPMODE bits (Offset 0x603, 8bit) */
/* */
#define BW_OPMODE_20MHZ BIT2
-#define BW_OPMODE_5G BIT1
/* */
/* CAM Config Setting (offset 0x680, 1 byte) */
diff --git a/drivers/staging/rtl8723bs/include/hal_data.h b/drivers/staging/rtl8723bs/include/hal_data.h
index babcb03a7c23..3298fa8eb682 100644
--- a/drivers/staging/rtl8723bs/include/hal_data.h
+++ b/drivers/staging/rtl8723bs/include/hal_data.h
@@ -46,21 +46,16 @@ enum rt_ampdu_burst {
RT_AMPDU_BURST_8723B = 7,
};
-#define CHANNEL_MAX_NUMBER (14 + 24 + 21) /* 14 is the max channel number */
+#define CHANNEL_MAX_NUMBER (14) /* 14 is the max channel number */
#define CHANNEL_MAX_NUMBER_2G 14
-#define CHANNEL_MAX_NUMBER_5G 54 /* Please refer to "phy_GetChnlGroup8812A" and "Hal_ReadTxPowerInfo8812A" */
-#define CHANNEL_MAX_NUMBER_5G_80M 7
#define MAX_PG_GROUP 13
/* Tx Power Limit Table Size */
#define MAX_REGULATION_NUM 4
#define MAX_2_4G_BANDWIDTH_NUM 4
#define MAX_RATE_SECTION_NUM 10
-#define MAX_5G_BANDWIDTH_NUM 4
#define MAX_BASE_NUM_IN_PHY_REG_PG_2_4G 10 /* CCK:1, OFDM:1, HT:4, VHT:4 */
-#define MAX_BASE_NUM_IN_PHY_REG_PG_5G 9 /* OFDM:1, HT:4, VHT:4 */
-
/* duplicate code, will move to ODM ######### */
/* define IQK_MAC_REG_NUM 4 */
@@ -182,8 +177,6 @@ struct hal_com_data {
/* current WIFI_PHY values */
enum wireless_mode CurrentWirelessMode;
enum channel_width CurrentChannelBW;
- enum band_type CurrentBandType; /* 0:2.4G, 1:5G */
- enum band_type BandSet;
u8 CurrentChannel;
u8 CurrentCenterFrequencyIndex1;
u8 nCur40MhzPrimeSC;/* Control channel sub-carrier */
@@ -236,16 +229,8 @@ struct hal_com_data {
s8 OFDM_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
s8 BW20_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
s8 BW40_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
- /* 3 [5G] */
- u8 Index5G_BW40_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
- u8 Index5G_BW80_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER_5G_80M];
- s8 OFDM_5G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
- s8 BW20_5G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
- s8 BW40_5G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
- s8 BW80_5G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
u8 Regulation2_4G;
- u8 Regulation5G;
u8 TxPwrInPercentage;
@@ -253,15 +238,13 @@ struct hal_com_data {
/* TX power by rate table at most 4RF path. */
/* The register is */
/* VHT TX power by rate off setArray = */
- /* Band:-2G&5G = 0 / 1 */
/* RF: at most 4*4 = ABCD = 0/1/2/3 */
/* CCK = 0 OFDM = 1/2 HT-MCS 0-15 =3/4/56 VHT =7/8/9/10/11 */
u8 TxPwrByRateTable;
u8 TxPwrByRateBand;
- s8 TxPwrByRateOffset[TX_PWR_BY_RATE_NUM_BAND]
- [TX_PWR_BY_RATE_NUM_RF]
- [TX_PWR_BY_RATE_NUM_RF]
- [TX_PWR_BY_RATE_NUM_RATE];
+ s8 TxPwrByRateOffset[TX_PWR_BY_RATE_NUM_RF]
+ [TX_PWR_BY_RATE_NUM_RF]
+ [TX_PWR_BY_RATE_NUM_RATE];
/* */
/* 2 Power Limit Table */
@@ -278,21 +261,10 @@ struct hal_com_data {
[CHANNEL_MAX_NUMBER_2G]
[MAX_RF_PATH_NUM];
- /* Power Limit Table for 5G */
- s8 TxPwrLimit_5G[MAX_REGULATION_NUM]
- [MAX_5G_BANDWIDTH_NUM]
- [MAX_RATE_SECTION_NUM]
- [CHANNEL_MAX_NUMBER_5G]
- [MAX_RF_PATH_NUM];
-
-
/* Store the original power by rate value of the base of each rate section of rf path A & B */
u8 TxPwrByRateBase2_4G[TX_PWR_BY_RATE_NUM_RF]
[TX_PWR_BY_RATE_NUM_RF]
[MAX_BASE_NUM_IN_PHY_REG_PG_2_4G];
- u8 TxPwrByRateBase5G[TX_PWR_BY_RATE_NUM_RF]
- [TX_PWR_BY_RATE_NUM_RF]
- [MAX_BASE_NUM_IN_PHY_REG_PG_5G];
/* For power group */
u8 PwrGroupHT20[RF_PATH_MAX_92C_88E][CHANNEL_MAX_NUMBER];
@@ -319,13 +291,9 @@ struct hal_com_data {
u32 AntennaRxPath; /* Antenna path Rx */
u8 PAType_2G;
- u8 PAType_5G;
u8 LNAType_2G;
- u8 LNAType_5G;
u8 ExternalPA_2G;
u8 ExternalLNA_2G;
- u8 ExternalPA_5G;
- u8 ExternalLNA_5G;
u8 TypeGLNA;
u8 TypeGPA;
u8 TypeALNA;
diff --git a/drivers/staging/rtl8723bs/include/hal_pg.h b/drivers/staging/rtl8723bs/include/hal_pg.h
index 0b7a8adf5c74..2d8ccc9ddebb 100644
--- a/drivers/staging/rtl8723bs/include/hal_pg.h
+++ b/drivers/staging/rtl8723bs/include/hal_pg.h
@@ -16,10 +16,8 @@
/* For VHT series TX power by rate table. */
/* VHT TX power by rate off setArray = */
-/* Band:-2G&5G = 0 / 1 */
/* RF: at most 4*4 = ABCD = 0/1/2/3 */
/* CCK = 0 OFDM = 1/2 HT-MCS 0-15 =3/4/56 VHT =7/8/9/10/11 */
-#define TX_PWR_BY_RATE_NUM_BAND 2
#define TX_PWR_BY_RATE_NUM_RF 4
#define TX_PWR_BY_RATE_NUM_RATE 84
#define MAX_RF_PATH_NUM 2
diff --git a/drivers/staging/rtl8723bs/include/hal_phy.h b/drivers/staging/rtl8723bs/include/hal_phy.h
index 521eb1c2efad..861aa71cd179 100644
--- a/drivers/staging/rtl8723bs/include/hal_phy.h
+++ b/drivers/staging/rtl8723bs/include/hal_phy.h
@@ -6,20 +6,6 @@
******************************************************************************/
#ifndef __HAL_PHY_H__
#define __HAL_PHY_H__
-
-
-#if DISABLE_BB_RF
-#define HAL_FW_ENABLE 0
-#define HAL_MAC_ENABLE 0
-#define HAL_BB_ENABLE 0
-#define HAL_RF_ENABLE 0
-#else /* FPGA_PHY and ASIC */
-#define HAL_FW_ENABLE 1
-#define HAL_MAC_ENABLE 1
-#define HAL_BB_ENABLE 1
-#define HAL_RF_ENABLE 1
-#endif
-
/* */
/* Antenna detection method, i.e., using single tone detection or RSSI reported from each antenna detected. */
/* Added by Roger, 2013.05.22. */
@@ -31,13 +17,6 @@
/*--------------------------Define Parameters-------------------------------*/
-enum band_type {
- BAND_ON_2_4G = 0,
- BAND_ON_5G,
- BAND_ON_BOTH,
- BANDMAX
-};
-
enum {
RF_TYPE_MIN = 0, /* 0 */
RF_8225 = 1, /* 1 11b/g RF for verification only */
@@ -65,13 +44,10 @@ enum rf_path {
enum wireless_mode {
WIRELESS_MODE_UNKNOWN = 0x00,
- WIRELESS_MODE_A = 0x01,
WIRELESS_MODE_B = 0x02,
WIRELESS_MODE_G = 0x04,
WIRELESS_MODE_AUTO = 0x08,
WIRELESS_MODE_N_24G = 0x10,
- WIRELESS_MODE_N_5G = 0x20,
- WIRELESS_MODE_AC_5G = 0x40,
WIRELESS_MODE_AC_24G = 0x80,
WIRELESS_MODE_AC_ONLY = 0x100,
};
diff --git a/drivers/staging/rtl8723bs/include/ieee80211.h b/drivers/staging/rtl8723bs/include/ieee80211.h
index 6540c7a22938..378c21595e05 100644
--- a/drivers/staging/rtl8723bs/include/ieee80211.h
+++ b/drivers/staging/rtl8723bs/include/ieee80211.h
@@ -60,7 +60,6 @@ enum {
#define WLAN_STA_HT BIT(11)
#define WLAN_STA_WPS BIT(12)
#define WLAN_STA_MAYBE_WPS BIT(13)
-#define WLAN_STA_VHT BIT(14)
#define WLAN_STA_NONERP BIT(31)
#define IEEE_CMD_SET_WPA_PARAM 1
@@ -135,8 +134,6 @@ enum {
RATEID_IDX_BG = 6,
RATEID_IDX_G = 7,
RATEID_IDX_B = 8,
- RATEID_IDX_VHT_2SS = 9,
- RATEID_IDX_VHT_1SS = 10,
};
enum network_type {
@@ -144,33 +141,20 @@ enum network_type {
/* Sub-Element */
WIRELESS_11B = BIT(0), /* tx: cck only , rx: cck only, hw: cck */
WIRELESS_11G = BIT(1), /* tx: ofdm only, rx: ofdm & cck, hw: cck & ofdm */
- WIRELESS_11A = BIT(2), /* tx: ofdm only, rx: ofdm only, hw: ofdm only */
WIRELESS_11_24N = BIT(3), /* tx: MCS only, rx: MCS & cck, hw: MCS & cck */
- WIRELESS_11_5N = BIT(4), /* tx: MCS only, rx: MCS & ofdm, hw: ofdm only */
WIRELESS_AUTO = BIT(5),
- WIRELESS_11AC = BIT(6),
/* Combination */
/* Type for current wireless mode */
WIRELESS_11BG = (WIRELESS_11B|WIRELESS_11G), /* tx: cck & ofdm, rx: cck & ofdm & MCS, hw: cck & ofdm */
WIRELESS_11G_24N = (WIRELESS_11G|WIRELESS_11_24N), /* tx: ofdm & MCS, rx: ofdm & cck & MCS, hw: cck & ofdm */
- WIRELESS_11A_5N = (WIRELESS_11A|WIRELESS_11_5N), /* tx: ofdm & MCS, rx: ofdm & MCS, hw: ofdm only */
WIRELESS_11B_24N = (WIRELESS_11B|WIRELESS_11_24N), /* tx: ofdm & cck & MCS, rx: ofdm & cck & MCS, hw: ofdm & cck */
WIRELESS_11BG_24N = (WIRELESS_11B|WIRELESS_11G|WIRELESS_11_24N), /* tx: ofdm & cck & MCS, rx: ofdm & cck & MCS, hw: ofdm & cck */
- WIRELESS_11_24AC = (WIRELESS_11G|WIRELESS_11AC),
- WIRELESS_11_5AC = (WIRELESS_11A|WIRELESS_11AC),
-
-
- /* Type for registry default wireless mode */
- WIRELESS_11AGN = (WIRELESS_11A|WIRELESS_11G|WIRELESS_11_24N|WIRELESS_11_5N), /* tx: ofdm & MCS, rx: ofdm & MCS, hw: ofdm only */
- WIRELESS_11ABGN = (WIRELESS_11A|WIRELESS_11B|WIRELESS_11G|WIRELESS_11_24N|WIRELESS_11_5N),
- WIRELESS_MODE_24G = (WIRELESS_11B|WIRELESS_11G|WIRELESS_11_24N|WIRELESS_11AC),
- WIRELESS_MODE_MAX = (WIRELESS_11A|WIRELESS_11B|WIRELESS_11G|WIRELESS_11_24N|WIRELESS_11_5N|WIRELESS_11AC),
};
#define SUPPORTED_24G_NETTYPE_MSK (WIRELESS_11B | WIRELESS_11G | WIRELESS_11_24N)
-#define IsLegacyOnly(NetType) ((NetType) == ((NetType) & (WIRELESS_11BG|WIRELESS_11A)))
+#define IsLegacyOnly(NetType) ((NetType) == ((NetType) & (WIRELESS_11BG)))
#define IsSupported24G(NetType) ((NetType) & SUPPORTED_24G_NETTYPE_MSK ? true : false)
@@ -182,11 +166,8 @@ enum network_type {
#define IsSupportedRxHT(NetType) IsEnableHWOFDM(NetType)
#define IsSupportedTxCCK(NetType) (((NetType) & (WIRELESS_11B)) ? true : false)
-#define IsSupportedTxOFDM(NetType) (((NetType) & (WIRELESS_11G|WIRELESS_11A)) ? true : false)
-#define IsSupportedHT(NetType) (((NetType) & (WIRELESS_11_24N|WIRELESS_11_5N)) ? true : false)
-
-#define IsSupportedVHT(NetType) (((NetType) & (WIRELESS_11AC)) ? true : false)
-
+#define IsSupportedTxOFDM(NetType) (((NetType) & (WIRELESS_11G) ? true : false)
+#define IsSupportedHT(NetType) (((NetType) & (WIRELESS_11_24N)) ? true : false)
struct ieee_param {
u32 cmd;
@@ -440,51 +421,10 @@ enum {
MGN_MCS29,
MGN_MCS30,
MGN_MCS31,
- MGN_VHT1SS_MCS0,
- MGN_VHT1SS_MCS1,
- MGN_VHT1SS_MCS2,
- MGN_VHT1SS_MCS3,
- MGN_VHT1SS_MCS4,
- MGN_VHT1SS_MCS5,
- MGN_VHT1SS_MCS6,
- MGN_VHT1SS_MCS7,
- MGN_VHT1SS_MCS8,
- MGN_VHT1SS_MCS9,
- MGN_VHT2SS_MCS0,
- MGN_VHT2SS_MCS1,
- MGN_VHT2SS_MCS2,
- MGN_VHT2SS_MCS3,
- MGN_VHT2SS_MCS4,
- MGN_VHT2SS_MCS5,
- MGN_VHT2SS_MCS6,
- MGN_VHT2SS_MCS7,
- MGN_VHT2SS_MCS8,
- MGN_VHT2SS_MCS9,
- MGN_VHT3SS_MCS0,
- MGN_VHT3SS_MCS1,
- MGN_VHT3SS_MCS2,
- MGN_VHT3SS_MCS3,
- MGN_VHT3SS_MCS4,
- MGN_VHT3SS_MCS5,
- MGN_VHT3SS_MCS6,
- MGN_VHT3SS_MCS7,
- MGN_VHT3SS_MCS8,
- MGN_VHT3SS_MCS9,
- MGN_VHT4SS_MCS0,
- MGN_VHT4SS_MCS1,
- MGN_VHT4SS_MCS2,
- MGN_VHT4SS_MCS3,
- MGN_VHT4SS_MCS4,
- MGN_VHT4SS_MCS5,
- MGN_VHT4SS_MCS6,
- MGN_VHT4SS_MCS7,
- MGN_VHT4SS_MCS8,
- MGN_VHT4SS_MCS9,
MGN_UNKNOWN
};
#define IS_HT_RATE(_rate) (_rate >= MGN_MCS0 && _rate <= MGN_MCS31)
-#define IS_VHT_RATE(_rate) (_rate >= MGN_VHT1SS_MCS0 && _rate <= MGN_VHT4SS_MCS9)
#define IS_CCK_RATE(_rate) (MGN_1M == _rate || _rate == MGN_2M || _rate == MGN_5_5M || _rate == MGN_11M)
#define IS_OFDM_RATE(_rate) (MGN_6M <= _rate && _rate <= MGN_54M && _rate != MGN_11M)
@@ -641,7 +581,6 @@ enum {
RTW_WLAN_CATEGORY_TDLS = 12,
RTW_WLAN_CATEGORY_SELF_PROTECTED = 15, /* add for CONFIG_IEEE80211W, none 11w also can use */
RTW_WLAN_CATEGORY_WMM = 17,
- RTW_WLAN_CATEGORY_VHT = 21,
RTW_WLAN_CATEGORY_P2P = 0x7f,/* P2P action frames */
};
diff --git a/drivers/staging/rtl8723bs/include/osdep_intf.h b/drivers/staging/rtl8723bs/include/osdep_intf.h
index 48c90f00cc2e..111e0179712a 100644
--- a/drivers/staging/rtl8723bs/include/osdep_intf.h
+++ b/drivers/staging/rtl8723bs/include/osdep_intf.h
@@ -66,7 +66,7 @@ void rtw_ips_pwr_down(struct adapter *padapter);
int rtw_drv_register_netdev(struct adapter *padapter);
void rtw_ndev_destructor(struct net_device *ndev);
-int rtw_suspend_common(struct adapter *padapter);
+void rtw_suspend_common(struct adapter *padapter);
int rtw_resume_common(struct adapter *padapter);
int netdev_open(struct net_device *pnetdev);
diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_spec.h b/drivers/staging/rtl8723bs/include/rtl8723b_spec.h
index 999555476ebc..6816040a6aff 100644
--- a/drivers/staging/rtl8723bs/include/rtl8723b_spec.h
+++ b/drivers/staging/rtl8723bs/include/rtl8723b_spec.h
@@ -7,8 +7,6 @@
#ifndef __RTL8723B_SPEC_H__
#define __RTL8723B_SPEC_H__
-#include <autoconf.h>
-
#define HAL_NAV_UPPER_UNIT_8723B 128 /* micro-second */
/* */
diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h b/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h
index 56bdc14af47d..9dd329a5208a 100644
--- a/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h
+++ b/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h
@@ -402,27 +402,6 @@ struct txdesc_8723b {
#define DESC8723B_RATEMCS13 0x19
#define DESC8723B_RATEMCS14 0x1a
#define DESC8723B_RATEMCS15 0x1b
-#define DESC8723B_RATEVHTSS1MCS0 0x2c
-#define DESC8723B_RATEVHTSS1MCS1 0x2d
-#define DESC8723B_RATEVHTSS1MCS2 0x2e
-#define DESC8723B_RATEVHTSS1MCS3 0x2f
-#define DESC8723B_RATEVHTSS1MCS4 0x30
-#define DESC8723B_RATEVHTSS1MCS5 0x31
-#define DESC8723B_RATEVHTSS1MCS6 0x32
-#define DESC8723B_RATEVHTSS1MCS7 0x33
-#define DESC8723B_RATEVHTSS1MCS8 0x34
-#define DESC8723B_RATEVHTSS1MCS9 0x35
-#define DESC8723B_RATEVHTSS2MCS0 0x36
-#define DESC8723B_RATEVHTSS2MCS1 0x37
-#define DESC8723B_RATEVHTSS2MCS2 0x38
-#define DESC8723B_RATEVHTSS2MCS3 0x39
-#define DESC8723B_RATEVHTSS2MCS4 0x3a
-#define DESC8723B_RATEVHTSS2MCS5 0x3b
-#define DESC8723B_RATEVHTSS2MCS6 0x3c
-#define DESC8723B_RATEVHTSS2MCS7 0x3d
-#define DESC8723B_RATEVHTSS2MCS8 0x3e
-#define DESC8723B_RATEVHTSS2MCS9 0x3f
-
#define RX_HAL_IS_CCK_RATE_8723B(pDesc)\
(GET_RX_STATUS_DESC_RX_RATE_8723B(pDesc) == DESC8723B_RATE1M ||\
diff --git a/drivers/staging/rtl8723bs/include/rtw_ap.h b/drivers/staging/rtl8723bs/include/rtw_ap.h
index 4a1ed9eff83a..7a735e691399 100644
--- a/drivers/staging/rtl8723bs/include/rtw_ap.h
+++ b/drivers/staging/rtl8723bs/include/rtw_ap.h
@@ -14,7 +14,7 @@ void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx);
void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level);
void expire_timeout_chk(struct adapter *padapter);
void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta);
-void start_bss_network(struct adapter *padapter, u8 *pbuf);
+void start_bss_network(struct adapter *padapter);
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);
diff --git a/drivers/staging/rtl8723bs/include/rtw_debug.h b/drivers/staging/rtl8723bs/include/rtw_debug.h
index 23f4cb4711d4..7f96ff66915f 100644
--- a/drivers/staging/rtl8723bs/include/rtw_debug.h
+++ b/drivers/staging/rtl8723bs/include/rtw_debug.h
@@ -7,172 +7,8 @@
#ifndef __RTW_DEBUG_H__
#define __RTW_DEBUG_H__
-#include <linux/trace_seq.h>
-
-#define _drv_always_ 1
-#define _drv_emerg_ 2
-#define _drv_alert_ 3
-#define _drv_crit_ 4
-#define _drv_err_ 5
-#define _drv_warning_ 6
-#define _drv_notice_ 7
-#define _drv_info_ 8
-#define _drv_dump_ 9
-#define _drv_debug_ 10
-
-
-#define _module_rtl871x_xmit_c_ BIT(0)
-#define _module_xmit_osdep_c_ BIT(1)
-#define _module_rtl871x_recv_c_ BIT(2)
-#define _module_recv_osdep_c_ BIT(3)
-#define _module_rtl871x_mlme_c_ BIT(4)
-#define _module_mlme_osdep_c_ BIT(5)
-#define _module_rtl871x_sta_mgt_c_ BIT(6)
-#define _module_rtl871x_cmd_c_ BIT(7)
-#define _module_cmd_osdep_c_ BIT(8)
-#define _module_rtl871x_io_c_ BIT(9)
-#define _module_io_osdep_c_ BIT(10)
-#define _module_os_intfs_c_ BIT(11)
-#define _module_rtl871x_security_c_ BIT(12)
-#define _module_rtl871x_eeprom_c_ BIT(13)
-#define _module_hal_init_c_ BIT(14)
-#define _module_hci_hal_init_c_ BIT(15)
-#define _module_rtl871x_ioctl_c_ BIT(16)
-#define _module_rtl871x_ioctl_set_c_ BIT(17)
-#define _module_rtl871x_ioctl_query_c_ BIT(18)
-#define _module_rtl871x_pwrctrl_c_ BIT(19)
-#define _module_hci_intfs_c_ BIT(20)
-#define _module_hci_ops_c_ BIT(21)
-#define _module_osdep_service_c_ BIT(22)
-#define _module_mp_ BIT(23)
-#define _module_hci_ops_os_c_ BIT(24)
-#define _module_rtl871x_ioctl_os_c BIT(25)
-#define _module_rtl8712_cmd_c_ BIT(26)
-/* define _module_efuse_ BIT(27) */
-#define _module_rtl8192c_xmit_c_ BIT(28)
-#define _module_hal_xmit_c_ BIT(28)
-#define _module_efuse_ BIT(29)
-#define _module_rtl8712_recv_c_ BIT(30)
-#define _module_rtl8712_led_c_ BIT(31)
-
-#undef _MODULE_DEFINE_
-
-#if defined _RTW_XMIT_C_
- #define _MODULE_DEFINE_ _module_rtl871x_xmit_c_
-#elif defined _XMIT_OSDEP_C_
- #define _MODULE_DEFINE_ _module_xmit_osdep_c_
-#elif defined _RTW_RECV_C_
- #define _MODULE_DEFINE_ _module_rtl871x_recv_c_
-#elif defined _RECV_OSDEP_C_
- #define _MODULE_DEFINE_ _module_recv_osdep_c_
-#elif defined _RTW_MLME_C_
- #define _MODULE_DEFINE_ _module_rtl871x_mlme_c_
-#elif defined _MLME_OSDEP_C_
- #define _MODULE_DEFINE_ _module_mlme_osdep_c_
-#elif defined _RTW_MLME_EXT_C_
- #define _MODULE_DEFINE_ 1
-#elif defined _RTW_STA_MGT_C_
- #define _MODULE_DEFINE_ _module_rtl871x_sta_mgt_c_
-#elif defined _RTW_CMD_C_
- #define _MODULE_DEFINE_ _module_rtl871x_cmd_c_
-#elif defined _CMD_OSDEP_C_
- #define _MODULE_DEFINE_ _module_cmd_osdep_c_
-#elif defined _RTW_IO_C_
- #define _MODULE_DEFINE_ _module_rtl871x_io_c_
-#elif defined _IO_OSDEP_C_
- #define _MODULE_DEFINE_ _module_io_osdep_c_
-#elif defined _OS_INTFS_C_
- #define _MODULE_DEFINE_ _module_os_intfs_c_
-#elif defined _RTW_SECURITY_C_
- #define _MODULE_DEFINE_ _module_rtl871x_security_c_
-#elif defined _RTW_EEPROM_C_
- #define _MODULE_DEFINE_ _module_rtl871x_eeprom_c_
-#elif defined _HAL_INTF_C_
- #define _MODULE_DEFINE_ _module_hal_init_c_
-#elif (defined _HCI_HAL_INIT_C_) || (defined _SDIO_HALINIT_C_)
- #define _MODULE_DEFINE_ _module_hci_hal_init_c_
-#elif defined _RTL871X_IOCTL_C_
- #define _MODULE_DEFINE_ _module_rtl871x_ioctl_c_
-#elif defined _RTL871X_IOCTL_SET_C_
- #define _MODULE_DEFINE_ _module_rtl871x_ioctl_set_c_
-#elif defined _RTL871X_IOCTL_QUERY_C_
- #define _MODULE_DEFINE_ _module_rtl871x_ioctl_query_c_
-#elif defined _RTL871X_PWRCTRL_C_
- #define _MODULE_DEFINE_ _module_rtl871x_pwrctrl_c_
-#elif defined _RTW_PWRCTRL_C_
- #define _MODULE_DEFINE_ 1
-#elif defined _HCI_INTF_C_
- #define _MODULE_DEFINE_ _module_hci_intfs_c_
-#elif defined _HCI_OPS_C_
- #define _MODULE_DEFINE_ _module_hci_ops_c_
-#elif defined _SDIO_OPS_C_
- #define _MODULE_DEFINE_ 1
-#elif defined _OSDEP_HCI_INTF_C_
- #define _MODULE_DEFINE_ _module_hci_intfs_c_
-#elif defined _OSDEP_SERVICE_C_
- #define _MODULE_DEFINE_ _module_osdep_service_c_
-#elif defined _HCI_OPS_OS_C_
- #define _MODULE_DEFINE_ _module_hci_ops_os_c_
-#elif defined _RTL871X_IOCTL_LINUX_C_
- #define _MODULE_DEFINE_ _module_rtl871x_ioctl_os_c
-#elif defined _RTL8712_CMD_C_
- #define _MODULE_DEFINE_ _module_rtl8712_cmd_c_
-#elif defined _RTL8192C_XMIT_C_
- #define _MODULE_DEFINE_ 1
-#elif defined _RTL8723AS_XMIT_C_
- #define _MODULE_DEFINE_ 1
-#elif defined _RTL8712_RECV_C_
- #define _MODULE_DEFINE_ _module_rtl8712_recv_c_
-#elif defined _RTL8192CU_RECV_C_
- #define _MODULE_DEFINE_ _module_rtl8712_recv_c_
-#elif defined _RTL871X_MLME_EXT_C_
- #define _MODULE_DEFINE_ _module_mlme_osdep_c_
-#elif defined _RTW_EFUSE_C_
- #define _MODULE_DEFINE_ _module_efuse_
-#endif
-
-#undef _dbgdump
-
-#ifndef _RTL871X_DEBUG_C_
- extern u32 GlobalDebugLevel;
- extern u64 GlobalDebugComponents;
-#endif
-
-#define _dbgdump printk
-
-#define DRIVER_PREFIX "RTL8723BS: "
-
-#if defined(_dbgdump)
-
-/* without driver-defined prefix */
-#undef _DBG_871X_LEVEL
-#define _DBG_871X_LEVEL(level, fmt, arg...) \
- do {\
- if (level <= GlobalDebugLevel) {\
- if (level <= _drv_err_ && level > _drv_always_) \
- _dbgdump("ERROR " fmt, ##arg);\
- else \
- _dbgdump(fmt, ##arg);\
- } \
- } while (0)
-
-#define RTW_DBGDUMP NULL /* 'stream' for _dbgdump */
-
-/* dump message to selected 'stream' */
-#define DBG_871X_SEL(sel, fmt, arg...) \
- do { \
- if (sel == RTW_DBGDUMP) \
- _DBG_871X_LEVEL(_drv_always_, fmt, ##arg); \
- else \
- seq_printf(sel, fmt, ##arg); \
- } while (0)
-
-#endif /* defined(_dbgdump) */
-
-void sd_f0_reg_dump(void *sel, struct adapter *adapter);
-
-void mac_reg_dump(void *sel, struct adapter *adapter);
-void bb_reg_dump(void *sel, struct adapter *adapter);
-void rf_reg_dump(void *sel, struct adapter *adapter);
+void mac_reg_dump(struct adapter *adapter);
+void bb_reg_dump(struct adapter *adapter);
+void rf_reg_dump(struct adapter *adapter);
#endif /* __RTW_DEBUG_H__ */
diff --git a/drivers/staging/rtl8723bs/include/rtw_ht.h b/drivers/staging/rtl8723bs/include/rtw_ht.h
index e3f353fe1e47..1527d8be2d7a 100644
--- a/drivers/staging/rtl8723bs/include/rtw_ht.h
+++ b/drivers/staging/rtl8723bs/include/rtw_ht.h
@@ -42,10 +42,6 @@ enum {
HT_AGG_SIZE_16K = 1,
HT_AGG_SIZE_32K = 2,
HT_AGG_SIZE_64K = 3,
- VHT_AGG_SIZE_128K = 4,
- VHT_AGG_SIZE_256K = 5,
- VHT_AGG_SIZE_512K = 6,
- VHT_AGG_SIZE_1024K = 7,
};
enum {
diff --git a/drivers/staging/rtl8723bs/include/rtw_io.h b/drivers/staging/rtl8723bs/include/rtw_io.h
index fbb73e698e09..e98083a07a66 100644
--- a/drivers/staging/rtl8723bs/include/rtw_io.h
+++ b/drivers/staging/rtl8723bs/include/rtw_io.h
@@ -104,8 +104,6 @@ struct _io_ops {
void (*_read_port_cancel)(struct intf_hdl *pintfhdl);
void (*_write_port_cancel)(struct intf_hdl *pintfhdl);
-
- u8 (*_sd_f0_read8)(struct intf_hdl *pintfhdl, u32 addr);
};
struct io_req {
@@ -170,29 +168,15 @@ extern void unregister_intf_hdl(struct intf_hdl *pintfhdl);
extern void _rtw_attrib_read(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
extern void _rtw_attrib_write(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
-extern u8 _rtw_read8(struct adapter *adapter, u32 addr);
-extern u16 _rtw_read16(struct adapter *adapter, u32 addr);
-extern u32 _rtw_read32(struct adapter *adapter, u32 addr);
-
-extern int _rtw_write8(struct adapter *adapter, u32 addr, u8 val);
-extern int _rtw_write16(struct adapter *adapter, u32 addr, u16 val);
-extern int _rtw_write32(struct adapter *adapter, u32 addr, u32 val);
-
-extern u8 _rtw_sd_f0_read8(struct adapter *adapter, u32 addr);
-
-extern u32 _rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+extern u8 rtw_read8(struct adapter *adapter, u32 addr);
+extern u16 rtw_read16(struct adapter *adapter, u32 addr);
+extern u32 rtw_read32(struct adapter *adapter, u32 addr);
-#define rtw_read8(adapter, addr) _rtw_read8((adapter), (addr))
-#define rtw_read16(adapter, addr) _rtw_read16((adapter), (addr))
-#define rtw_read32(adapter, addr) _rtw_read32((adapter), (addr))
+extern int rtw_write8(struct adapter *adapter, u32 addr, u8 val);
+extern int rtw_write16(struct adapter *adapter, u32 addr, u16 val);
+extern int rtw_write32(struct adapter *adapter, u32 addr, u32 val);
-#define rtw_write8(adapter, addr, val) _rtw_write8((adapter), (addr), (val))
-#define rtw_write16(adapter, addr, val) _rtw_write16((adapter), (addr), (val))
-#define rtw_write32(adapter, addr, val) _rtw_write32((adapter), (addr), (val))
-
-#define rtw_write_port(adapter, addr, cnt, mem) _rtw_write_port((adapter), (addr), (cnt), (mem))
-
-#define rtw_sd_f0_read8(adapter, addr) _rtw_sd_f0_read8((adapter), (addr))
+extern u32 rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
extern void rtw_write_scsi(struct adapter *adapter, u32 cnt, u8 *pmem);
@@ -236,18 +220,4 @@ extern void bus_sync_io(struct io_queue *pio_q);
extern u32 _ioreq2rwmem(struct io_queue *pio_q);
extern void dev_power_down(struct adapter *Adapter, u8 bpwrup);
-#define PlatformEFIOWrite1Byte(_a, _b, _c) \
- rtw_write8(_a, _b, _c)
-#define PlatformEFIOWrite2Byte(_a, _b, _c) \
- rtw_write16(_a, _b, _c)
-#define PlatformEFIOWrite4Byte(_a, _b, _c) \
- rtw_write32(_a, _b, _c)
-
-#define PlatformEFIORead1Byte(_a, _b) \
- rtw_read8(_a, _b)
-#define PlatformEFIORead2Byte(_a, _b) \
- rtw_read16(_a, _b)
-#define PlatformEFIORead4Byte(_a, _b) \
- rtw_read32(_a, _b)
-
#endif /* _RTL8711_IO_H_ */
diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h
index 472818c5fd83..89b389d4c44b 100644
--- a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h
+++ b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h
@@ -195,47 +195,6 @@ enum {
RT_CHANNEL_DOMAIN_2G_MAX,
};
-enum {
- RT_CHANNEL_DOMAIN_5G_NULL = 0x00,
- RT_CHANNEL_DOMAIN_5G_ETSI1 = 0x01, /* Europe */
- RT_CHANNEL_DOMAIN_5G_ETSI2 = 0x02, /* Australia, New Zealand */
- RT_CHANNEL_DOMAIN_5G_ETSI3 = 0x03, /* Russia */
- RT_CHANNEL_DOMAIN_5G_FCC1 = 0x04, /* US */
- RT_CHANNEL_DOMAIN_5G_FCC2 = 0x05, /* FCC o/w DFS Channels */
- RT_CHANNEL_DOMAIN_5G_FCC3 = 0x06, /* India, Mexico */
- RT_CHANNEL_DOMAIN_5G_FCC4 = 0x07, /* Venezuela */
- RT_CHANNEL_DOMAIN_5G_FCC5 = 0x08, /* China */
- RT_CHANNEL_DOMAIN_5G_FCC6 = 0x09, /* Israel */
- RT_CHANNEL_DOMAIN_5G_FCC7_IC1 = 0x0A, /* US, Canada */
- RT_CHANNEL_DOMAIN_5G_KCC1 = 0x0B, /* Korea */
- RT_CHANNEL_DOMAIN_5G_MKK1 = 0x0C, /* Japan */
- RT_CHANNEL_DOMAIN_5G_MKK2 = 0x0D, /* Japan (W52, W53) */
- RT_CHANNEL_DOMAIN_5G_MKK3 = 0x0E, /* Japan (W56) */
- RT_CHANNEL_DOMAIN_5G_NCC1 = 0x0F, /* Taiwan */
- RT_CHANNEL_DOMAIN_5G_NCC2 = 0x10, /* Taiwan o/w DFS */
- RT_CHANNEL_DOMAIN_5G_NCC3 = 0x11, /* Taiwan w/o DFS, Band4 only */
- RT_CHANNEL_DOMAIN_5G_ETSI4 = 0x12, /* Europe w/o DFS, Band1 only */
- RT_CHANNEL_DOMAIN_5G_ETSI5 = 0x13, /* Australia, New Zealand(w/o Weather radar) */
- RT_CHANNEL_DOMAIN_5G_FCC8 = 0x14, /* Latin America */
- RT_CHANNEL_DOMAIN_5G_ETSI6 = 0x15, /* Israel, Bahrain, Egypt, India, China, Malaysia */
- RT_CHANNEL_DOMAIN_5G_ETSI7 = 0x16, /* China */
- RT_CHANNEL_DOMAIN_5G_ETSI8 = 0x17, /* Jordan */
- RT_CHANNEL_DOMAIN_5G_ETSI9 = 0x18, /* Lebanon */
- RT_CHANNEL_DOMAIN_5G_ETSI10 = 0x19, /* Qatar */
- RT_CHANNEL_DOMAIN_5G_ETSI11 = 0x1A, /* Russia */
- RT_CHANNEL_DOMAIN_5G_NCC4 = 0x1B, /* Taiwan, (w/o Weather radar) */
- RT_CHANNEL_DOMAIN_5G_ETSI12 = 0x1C, /* Indonesia */
- RT_CHANNEL_DOMAIN_5G_FCC9 = 0x1D, /* w/o Weather radar) */
- RT_CHANNEL_DOMAIN_5G_ETSI13 = 0x1E, /* w/o Weather radar) */
- RT_CHANNEL_DOMAIN_5G_FCC10 = 0x1F, /* Argentina (w/o Weather radar) */
- /* Add new channel plan above this line =============== */
- /* Driver Self Defined ===== */
- RT_CHANNEL_DOMAIN_5G_FCC = 0x20,
- RT_CHANNEL_DOMAIN_5G_JAPAN_NO_DFS = 0x21,
- RT_CHANNEL_DOMAIN_5G_FCC4_NO_DFS = 0x22,
- RT_CHANNEL_DOMAIN_5G_MAX,
-};
-
#define rtw_is_channel_plan_valid(chplan) (chplan < RT_CHANNEL_DOMAIN_MAX || chplan == RT_CHANNEL_DOMAIN_REALTEK_DEFINE)
struct rt_channel_plan {
@@ -248,14 +207,8 @@ struct rt_channel_plan_2g {
unsigned char Len;
};
-struct rt_channel_plan_5g {
- unsigned char Channel[MAX_CHANNEL_NUM_5G];
- unsigned char Len;
-};
-
struct rt_channel_plan_map {
unsigned char Index2G;
- unsigned char Index5G;
};
enum {
@@ -348,13 +301,13 @@ struct FW_Sta_Info {
* When the driver scanned RTW_SCAN_NUM_OF_CH channels, it would switch back to AP's operating channel for
* RTW_STAY_AP_CH_MILLISECOND * SURVEY_TO milliseconds.
* Example:
- * For chip supports 2.4G + 5GHz and AP mode is operating in channel 1,
+ * For chip supports 2.4G and AP mode is operating in channel 1,
* RTW_SCAN_NUM_OF_CH is 8, RTW_STAY_AP_CH_MILLISECOND is 3 and SURVEY_TO is 100.
* When it's STA mode gets set_scan command,
* it would
* 1. Doing the scan on channel 1.2.3.4.5.6.7.8
* 2. Back to channel 1 for 300 milliseconds
- * 3. Go through doing site survey on channel 9.10.11.36.40.44.48.52
+ * 3. Go through doing site survey on channel 9.10.11
* 4. Back to channel 1 for 300 milliseconds
* 5. ... and so on, till survey done.
*/
@@ -411,7 +364,6 @@ struct rt_channel_info {
};
int rtw_ch_set_search_ch(struct rt_channel_info *ch_set, const u32 ch);
-bool rtw_mlme_band_check(struct adapter *adapter, const u32 ch);
/* P2P_MAX_REG_CLASSES - Maximum number of regulatory classes */
#define P2P_MAX_REG_CLASSES 10
@@ -805,38 +757,6 @@ enum {
#ifdef _RTW_MLME_EXT_C_
-static struct fwevent wlanevents[] =
-{
- {0, rtw_dummy_event_callback}, /*0*/
- {0, NULL},
- {0, NULL},
- {0, NULL},
- {0, NULL},
- {0, NULL},
- {0, NULL},
- {0, NULL},
- {0, &rtw_survey_event_callback}, /*8*/
- {sizeof(struct surveydone_event), &rtw_surveydone_event_callback}, /*9*/
-
- {0, &rtw_joinbss_event_callback}, /*10*/
- {sizeof(struct stassoc_event), &rtw_stassoc_event_callback},
- {sizeof(struct stadel_event), &rtw_stadel_event_callback},
- {0, &rtw_atimdone_event_callback},
- {0, rtw_dummy_event_callback},
- {0, NULL}, /*15*/
- {0, NULL},
- {0, NULL},
- {0, NULL},
- {0, rtw_fwdbg_event_callback},
- {0, NULL}, /*20*/
- {0, NULL},
- {0, NULL},
- {0, &rtw_cpwm_event_callback},
- {0, NULL},
- {0, &rtw_wmm_event_callback},
-
-};
-
#endif/* _RTL8192C_CMD_C_ */
#endif
diff --git a/drivers/staging/rtl8723bs/include/rtw_mp.h b/drivers/staging/rtl8723bs/include/rtw_mp.h
index 2788ad80b114..ea3abee325ef 100644
--- a/drivers/staging/rtl8723bs/include/rtw_mp.h
+++ b/drivers/staging/rtl8723bs/include/rtw_mp.h
@@ -348,7 +348,6 @@ void Hal_SetCarrierSuppressionTx(struct adapter *padapter, u8 bStart);
void Hal_SetSingleToneTx(struct adapter *padapter, u8 bStart);
void Hal_SetSingleCarrierTx(struct adapter *padapter, u8 bStart);
void Hal_SetContinuousTx(struct adapter *padapter, u8 bStart);
-void Hal_SetBandwidth(struct adapter *padapter);
void Hal_SetDataRate(struct adapter *padapter);
void Hal_SetChannel(struct adapter *padapter);
diff --git a/drivers/staging/rtl8723bs/include/rtw_rf.h b/drivers/staging/rtl8723bs/include/rtw_rf.h
index cb6beccd3d23..6c25707f4ec8 100644
--- a/drivers/staging/rtl8723bs/include/rtw_rf.h
+++ b/drivers/staging/rtl8723bs/include/rtw_rf.h
@@ -21,16 +21,13 @@
#define RTL8711_RF_MAX_SENS 6
#define RTL8711_RF_DEF_SENS 4
-/* */
-/* We now define the following channels as the max channels in each channel plan. */
-/* 2G, total 14 chnls */
-/* {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14} */
-/* 5G, total 24 chnls */
-/* {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
- * 124, 128, 132, 136, 140, 149, 153, 157, 161, 165} */
+/*
+ * We now define the following channels as the max channels in each channel plan.
+ * 2G, total 14 chnls
+ * {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
+ */
#define MAX_CHANNEL_NUM_2G 14
-#define MAX_CHANNEL_NUM_5G 24
-#define MAX_CHANNEL_NUM 38/* 14+24 */
+#define MAX_CHANNEL_NUM 14
#define NUM_REGULATORYS 1
@@ -83,10 +80,6 @@ enum {
enum channel_width {
CHANNEL_WIDTH_20 = 0,
CHANNEL_WIDTH_40 = 1,
- CHANNEL_WIDTH_80 = 2,
- CHANNEL_WIDTH_160 = 3,
- CHANNEL_WIDTH_80_80 = 4,
- CHANNEL_WIDTH_MAX = 5,
};
/* Represent Extension Channel Offset in HT Capabilities */
@@ -99,17 +92,9 @@ enum extchnl_offset {
};
enum {
- VHT_DATA_SC_DONOT_CARE = 0,
- VHT_DATA_SC_20_UPPER_OF_80MHZ = 1,
- VHT_DATA_SC_20_LOWER_OF_80MHZ = 2,
- VHT_DATA_SC_20_UPPERST_OF_80MHZ = 3,
- VHT_DATA_SC_20_LOWEST_OF_80MHZ = 4,
- VHT_DATA_SC_20_RECV1 = 5,
- VHT_DATA_SC_20_RECV2 = 6,
- VHT_DATA_SC_20_RECV3 = 7,
- VHT_DATA_SC_20_RECV4 = 8,
- VHT_DATA_SC_40_UPPER_OF_80MHZ = 9,
- VHT_DATA_SC_40_LOWER_OF_80MHZ = 10,
+ HT_DATA_SC_DONOT_CARE = 0,
+ HT_DATA_SC_20_UPPER_OF_40MHZ = 1,
+ HT_DATA_SC_20_LOWER_OF_40MHZ = 2,
};
/* 2007/11/15 MH Define different RF type. */
diff --git a/drivers/staging/rtl8723bs/include/rtw_security.h b/drivers/staging/rtl8723bs/include/rtw_security.h
index 5c787e999aab..a68b73858462 100644
--- a/drivers/staging/rtl8723bs/include/rtw_security.h
+++ b/drivers/staging/rtl8723bs/include/rtw_security.h
@@ -7,6 +7,7 @@
#ifndef __RTW_SECURITY_H_
#define __RTW_SECURITY_H_
+#include <crypto/arc4.h>
#define _NO_PRIVACY_ 0x0
#define _WEP40_ 0x1
@@ -127,6 +128,8 @@ struct security_priv {
u8 wps_ie[MAX_WPS_IE_LEN];/* added in assoc req */
int wps_ie_len;
+ struct arc4_ctx xmit_arc4_ctx;
+ struct arc4_ctx recv_arc4_ctx;
u8 binstallGrpkey;
u8 binstallBIPkey;
@@ -191,8 +194,6 @@ do {\
} \
} while (0)
-#define _AES_IV_LEN_ 8
-
#define SET_ICE_IV_LEN(iv_len, icv_len, encrypt)\
do {\
switch (encrypt)\
@@ -243,110 +244,11 @@ struct mic_data {
u32 nBytesInM; /* # bytes in M */
};
-extern const u32 Te0[256];
-extern const u32 Te1[256];
-extern const u32 Te2[256];
-extern const u32 Te3[256];
-extern const u32 Te4[256];
-extern const u32 Td0[256];
-extern const u32 Td1[256];
-extern const u32 Td2[256];
-extern const u32 Td3[256];
-extern const u32 Td4[256];
-extern const u32 rcon[10];
-extern const u8 Td4s[256];
-extern const u8 rcons[10];
-
-#define RCON(i) (rcons[(i)] << 24)
-
-static inline u32 rotr(u32 val, int bits)
-{
- return (val >> bits) | (val << (32 - bits));
-}
-
-#define TE0(i) Te0[((i) >> 24) & 0xff]
-#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8)
-#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16)
-#define TE3(i) rotr(Te0[(i) & 0xff], 24)
-#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000)
-#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000)
-#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00)
-#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff)
-#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000)
-#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000)
-#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00)
-#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff)
-#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff)
-
-#define TD0(i) Td0[((i) >> 24) & 0xff]
-#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
-#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
-#define TD3(i) rotr(Td0[(i) & 0xff], 24)
-#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
-#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
-#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
-#define TD44(i) (Td4s[(i) & 0xff])
-#define TD0_(i) Td0[(i) & 0xff]
-#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
-#define TD2_(i) rotr(Td0[(i) & 0xff], 16)
-#define TD3_(i) rotr(Td0[(i) & 0xff], 24)
-
-#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \
- ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
-
-#define PUTU32(ct, st) { \
-(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \
-(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
-
-#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
- (((u32) (a)[2]) << 8) | ((u32) (a)[3]))
-
-#define WPA_PUT_LE16(a, val) \
- do { \
- (a)[1] = ((u16) (val)) >> 8; \
- (a)[0] = ((u16) (val)) & 0xff; \
- } while (0)
-
-#define WPA_PUT_BE32(a, val) \
- do { \
- (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \
- (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \
- (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \
- (a)[3] = (u8) (((u32) (val)) & 0xff); \
- } while (0)
-
-#define WPA_PUT_BE64(a, val) \
- do { \
- (a)[0] = (u8) (((u64) (val)) >> 56); \
- (a)[1] = (u8) (((u64) (val)) >> 48); \
- (a)[2] = (u8) (((u64) (val)) >> 40); \
- (a)[3] = (u8) (((u64) (val)) >> 32); \
- (a)[4] = (u8) (((u64) (val)) >> 24); \
- (a)[5] = (u8) (((u64) (val)) >> 16); \
- (a)[6] = (u8) (((u64) (val)) >> 8); \
- (a)[7] = (u8) (((u64) (val)) & 0xff); \
- } while (0)
-
/* ===== start - public domain SHA256 implementation ===== */
/* This is based on SHA256 implementation in LibTomCrypt that was released into
* public domain by Tom St Denis. */
-/* Various logical functions */
-#define RORc(x, y) \
-(((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \
- ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
-#define Ch(x, y, z) (z ^ (x & (y ^ z)))
-#define Maj(x, y, z) (((x | y) & z) | (x & y))
-#define S(x, n) RORc((x), (n))
-#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
-#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
-#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
-#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
-#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
-#ifndef MIN
-#define MIN(x, y) (((x) < (y)) ? (x) : (y))
-#endif
int omac1_aes_128(u8 *key, u8 *data, size_t data_len, u8 *mac);
void rtw_secmicsetkey(struct mic_data *pmicdata, u8 *key);
void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b);
diff --git a/drivers/staging/rtl8723bs/include/rtw_xmit.h b/drivers/staging/rtl8723bs/include/rtw_xmit.h
index e45753d17313..676ead0372fa 100644
--- a/drivers/staging/rtl8723bs/include/rtw_xmit.h
+++ b/drivers/staging/rtl8723bs/include/rtw_xmit.h
@@ -234,7 +234,7 @@ enum {
void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms);
-int rtw_sctx_wait(struct submit_ctx *sctx, const char *msg);
+int rtw_sctx_wait(struct submit_ctx *sctx);
void rtw_sctx_done_err(struct submit_ctx **sctx, int status);
void rtw_sctx_done(struct submit_ctx **sctx);
diff --git a/drivers/staging/rtl8723bs/include/sdio_ops_linux.h b/drivers/staging/rtl8723bs/include/sdio_ops_linux.h
index 16a03adbc2cf..18830dd18372 100644
--- a/drivers/staging/rtl8723bs/include/sdio_ops_linux.h
+++ b/drivers/staging/rtl8723bs/include/sdio_ops_linux.h
@@ -11,8 +11,6 @@
#define SDIO_ERR_VAL16 0xEAEA
#define SDIO_ERR_VAL32 0xEAEAEAEA
-u8 sd_f0_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err);
-
s32 _sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata);
s32 _sd_cmd52_write(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata);
s32 sd_cmd52_read(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pdata);
diff --git a/drivers/staging/rtl8723bs/include/wifi.h b/drivers/staging/rtl8723bs/include/wifi.h
index 036cf57c65a9..0bd7b662b972 100644
--- a/drivers/staging/rtl8723bs/include/wifi.h
+++ b/drivers/staging/rtl8723bs/include/wifi.h
@@ -234,7 +234,7 @@ static inline int IS_MCAST(unsigned char *da)
return false;
}
-static inline unsigned char *get_ra(unsigned char *pframe)
+static inline unsigned char *rtl8723bs_get_ra(unsigned char *pframe)
{
unsigned char *ra;
ra = GetAddr1Ptr(pframe);
@@ -336,7 +336,6 @@ static inline int IsFrameTypeCtrl(unsigned char *pframe)
#define _PRE_ALLOCICVHDR_ 5
#define _PRE_ALLOCMICHDR_ 6
-#define _SIFSTIME_ ((priv->pmib->dot11BssType.net_work_type&WIRELESS_11A)?16:10)
#define _ACKCTSLNG_ 14 /* 14 bytes long, including crclng */
#define _CRCLNG_ 4
diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
index 437859228371..fd747c8d920e 100644
--- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
+++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
@@ -77,7 +77,6 @@ static struct ieee80211_rate rtw_rates[] = {
#define RTW_G_RATES_NUM 12
#define RTW_2G_CHANNELS_NUM 14
-#define RTW_5G_CHANNELS_NUM 37
static struct ieee80211_channel rtw_2ghz_channels[] = {
CHAN2G(1, 2412, 0),
@@ -203,8 +202,6 @@ rtw_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
static int rtw_ieee80211_channel_to_frequency(int chan, int band)
{
- /* see 802.11 17.3.8.3.2 and Annex J
- * there are overlapping channel numbers in 5GHz and 2GHz bands */
if (band == NL80211_BAND_2GHZ) {
if (chan == 14)
return 2484;
@@ -229,7 +226,6 @@ struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wl
size_t len, bssinf_len = 0;
struct ieee80211_hdr *pwlanhdr;
__le16 *fctrl;
- u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
struct wireless_dev *wdev = padapter->rtw_wdev;
struct wiphy *wiphy = wdev->wiphy;
@@ -310,7 +306,7 @@ struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wl
/* pmlmeext->mgnt_seq++; */
if (pnetwork->network.Reserved[0] == 1) { /* WIFI_BEACON */
- memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+ eth_broadcast_addr(pwlanhdr->addr1);
SetFrameSubType(pbuf, WIFI_BEACON);
} else {
memcpy(pwlanhdr->addr1, myid(&(padapter->eeprompriv)), ETH_ALEN);
@@ -960,7 +956,7 @@ static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev,
memset(param, 0, param_len);
param->cmd = IEEE_CMD_SET_ENCRYPTION;
- memset(param->sta_addr, 0xff, ETH_ALEN);
+ eth_broadcast_addr(param->sta_addr);
switch (params->cipher) {
case IW_AUTH_CIPHER_NONE:
@@ -1265,18 +1261,12 @@ void rtw_cfg80211_surveydone_event_callback(struct adapter *padapter)
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
-
- while (1)
+ list_for_each(plist, phead)
{
- if (phead == plist)
- break;
-
- pnetwork = container_of(plist, struct wlan_network, list);
+ pnetwork = list_entry(plist, struct wlan_network, list);
/* report network only if the current channel set contains the channel to which this network belongs */
if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0
- && rtw_mlme_band_check(padapter, pnetwork->network.Configuration.DSConfig) == true
&& true == rtw_validate_ssid(&(pnetwork->network.Ssid))
)
{
@@ -1284,8 +1274,6 @@ void rtw_cfg80211_surveydone_event_callback(struct adapter *padapter)
rtw_cfg80211_inform_bss(padapter, pnetwork);
}
- plist = get_next(plist);
-
}
spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
@@ -2460,7 +2448,7 @@ static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev
struct station_del_parameters *params)
{
int ret = 0;
- struct list_head *phead, *plist;
+ struct list_head *phead, *plist, *tmp;
u8 updated = false;
struct sta_info *psta = NULL;
struct adapter *padapter = rtw_netdev_priv(ndev);
@@ -2489,13 +2477,9 @@ static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = get_next(phead);
-
/* check asoc_queue */
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, asoc_list);
-
- plist = get_next(plist);
+ list_for_each_safe(plist, tmp, phead) {
+ psta = list_entry(plist, struct sta_info, asoc_list);
if (!memcmp((u8 *)mac, psta->hwaddr, ETH_ALEN)) {
if (psta->dot8021xalg != 1 || psta->bpairwise_key_installed) {
@@ -2598,7 +2582,7 @@ static int _cfg80211_rtw_mgmt_tx(struct adapter *padapter, u8 tx_ch, const u8 *b
struct pkt_attrib *pattrib;
unsigned char *pframe;
int ret = _FAIL;
- bool ack = true;
+ bool __maybe_unused ack = true;
struct ieee80211_hdr *pwlanhdr;
struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
index 5088c3731b6d..f95000df8942 100644
--- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
@@ -420,8 +420,10 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
wep_key_len = wep_key_len <= 5 ? 5 : 13;
wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial);
pwep = kzalloc(wep_total_len, GFP_KERNEL);
- if (!pwep)
+ if (!pwep) {
+ ret = -ENOMEM;
goto exit;
+ }
pwep->KeyLength = wep_key_len;
pwep->Length = wep_total_len;
@@ -1052,15 +1054,9 @@ static int rtw_wx_set_wap(struct net_device *dev,
authmode = padapter->securitypriv.ndisauthtype;
spin_lock_bh(&queue->lock);
phead = get_list_head(queue);
- pmlmepriv->pscanned = get_next(phead);
-
- while (1) {
- if (phead == pmlmepriv->pscanned)
- break;
-
- pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list);
-
- pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+ list_for_each(pmlmepriv->pscanned, phead) {
+ pnetwork = list_entry(pmlmepriv->pscanned,
+ struct wlan_network, list);
dst_bssid = pnetwork->network.MacAddress;
@@ -1299,29 +1295,21 @@ static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
-
- while (1) {
- if (phead == plist)
- break;
-
+ list_for_each(plist, phead) {
if ((stop - ev) < SCAN_ITEM_SIZE) {
ret = -E2BIG;
break;
}
- pnetwork = container_of(plist, struct wlan_network, list);
+ pnetwork = list_entry(plist, struct wlan_network, list);
/* report network only if the current channel set contains the channel to which this network belongs */
if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0
- && rtw_mlme_band_check(padapter, pnetwork->network.Configuration.DSConfig) == true
&& true == rtw_validate_ssid(&(pnetwork->network.Ssid))) {
ev = translate_scan(padapter, a, pnetwork, ev, stop);
}
- plist = get_next(plist);
-
}
spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
@@ -1387,15 +1375,9 @@ static int rtw_wx_set_essid(struct net_device *dev,
spin_lock_bh(&queue->lock);
phead = get_list_head(queue);
- pmlmepriv->pscanned = get_next(phead);
-
- while (1) {
- if (phead == pmlmepriv->pscanned)
- break;
-
- pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list);
-
- pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+ list_for_each(pmlmepriv->pscanned, phead) {
+ pnetwork = list_entry(pmlmepriv->pscanned,
+ struct wlan_network, list);
dst_ssid = pnetwork->network.Ssid.Ssid;
@@ -1934,7 +1916,7 @@ static int rtw_wx_set_enc_ext(struct net_device *dev,
return -1;
param->cmd = IEEE_CMD_SET_ENCRYPTION;
- memset(param->sta_addr, 0xff, ETH_ALEN);
+ eth_broadcast_addr(param->sta_addr);
switch (pext->alg) {
@@ -2252,14 +2234,8 @@ static int rtw_get_ap_info(struct net_device *dev,
spin_lock_bh(&(pmlmepriv->scanned_queue.lock));
phead = get_list_head(queue);
- plist = get_next(phead);
-
- while (1) {
- if (phead == plist)
- break;
-
-
- pnetwork = container_of(plist, struct wlan_network, list);
+ list_for_each(plist, phead) {
+ pnetwork = list_entry(plist, struct wlan_network, list);
if (!mac_pton(data, bssid)) {
spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
@@ -2282,8 +2258,6 @@ static int rtw_get_ap_info(struct net_device *dev,
}
}
- plist = get_next(plist);
-
}
spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
@@ -2600,10 +2574,9 @@ static int rtw_dbg_port(struct net_device *dev,
case 0x12: /* set rx_stbc */
{
struct registry_priv *pregpriv = &padapter->registrypriv;
- /* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, 0x3: enable both 2.4g and 5g */
- /* default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */
- if (extra_arg == 0 || extra_arg == 1 ||
- extra_arg == 2 || extra_arg == 3)
+ /* 0: disable, bit(0):enable 2.4g */
+ /* default is set to enable 2.4GHZ */
+ if (extra_arg == 0 || extra_arg == 1)
pregpriv->rx_stbc = extra_arg;
}
break;
@@ -2734,11 +2707,11 @@ static int rtw_dbg_port(struct net_device *dev,
case 0xdd:/* registers dump , 0 for mac reg, 1 for bb reg, 2 for rf reg */
{
if (extra_arg == 0)
- mac_reg_dump(RTW_DBGDUMP, padapter);
+ mac_reg_dump(padapter);
else if (extra_arg == 1)
- bb_reg_dump(RTW_DBGDUMP, padapter);
+ bb_reg_dump(padapter);
else if (extra_arg == 2)
- rf_reg_dump(RTW_DBGDUMP, padapter);
+ rf_reg_dump(padapter);
}
break;
diff --git a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c
index 0a16752f805b..a4560ba22db1 100644
--- a/drivers/staging/rtl8723bs/os_dep/mlme_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/mlme_linux.c
@@ -4,10 +4,6 @@
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-
-
-#define _MLME_OSDEP_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
diff --git a/drivers/staging/rtl8723bs/os_dep/os_intfs.c b/drivers/staging/rtl8723bs/os_dep/os_intfs.c
index 160f624612c7..648456b992bb 100644
--- a/drivers/staging/rtl8723bs/os_dep/os_intfs.c
+++ b/drivers/staging/rtl8723bs/os_dep/os_intfs.c
@@ -4,8 +4,6 @@
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-#define _OS_INTFS_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
#include <hal_data.h>
@@ -24,7 +22,7 @@ static int rtw_lbkmode;/* RTL8712_AIR_TRX; */
static int rtw_network_mode = Ndis802_11IBSS;/* Ndis802_11Infrastructure;infra, ad-hoc, auto */
/* struct ndis_802_11_ssid ssid; */
static int rtw_channel = 1;/* ad-hoc support requirement */
-static int rtw_wireless_mode = WIRELESS_MODE_MAX;
+static int rtw_wireless_mode = WIRELESS_11BG_24N;
static int rtw_vrtl_carrier_sense = AUTO_VCS;
static int rtw_vcs_type = RTS_CTS;/* */
static int rtw_rts_thresh = 2347;/* */
@@ -67,10 +65,12 @@ static int rtw_uapsd_acvi_en;
static int rtw_uapsd_acvo_en;
int rtw_ht_enable = 1;
-/* 0: 20 MHz, 1: 40 MHz, 2: 80 MHz, 3: 160MHz, 4: 80+80MHz */
-/* 2.4G use bit 0 ~ 3, 5G use bit 4 ~ 7 */
-/* 0x21 means enable 2.4G 40MHz & 5G 80MHz */
-static int rtw_bw_mode = 0x21;
+/*
+ * 0: 20 MHz, 1: 40 MHz
+ * 2.4G use bit 0 ~ 3
+ * 0x01 means enable 2.4G 40MHz
+ */
+static int rtw_bw_mode = 0x01;
static int rtw_ampdu_enable = 1;/* for enable tx_ampdu ,0: disable, 0x1:enable (but wifi_spec should be 0), 0x2: force enable (don't care wifi_spec) */
static int rtw_rx_stbc = 1;/* 0: disable, 1:enable 2.4g */
static int rtw_ampdu_amsdu;/* 0: disabled, 1:enabled, 2:auto . There is an IOT issu with DLINK DIR-629 when the flag turn on */
@@ -289,7 +289,6 @@ static void loadparam(struct adapter *padapter, struct net_device *pnetdev)
registry_par->RegPowerBase = 14;
registry_par->TxBBSwing_2G = 0xFF;
- registry_par->TxBBSwing_5G = 0xFF;
registry_par->bEn_RFE = 1;
registry_par->RFE_Type = 64;
@@ -1152,14 +1151,13 @@ static void rtw_suspend_normal(struct adapter *padapter)
padapter->intf_deinit(adapter_to_dvobj(padapter));
}
-int rtw_suspend_common(struct adapter *padapter)
+void rtw_suspend_common(struct adapter *padapter)
{
struct dvobj_priv *psdpriv = padapter->dvobj;
struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(psdpriv);
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- int ret = 0;
unsigned long start_time = jiffies;
netdev_dbg(padapter->pnetdev, " suspend start\n");
@@ -1190,19 +1188,14 @@ int rtw_suspend_common(struct adapter *padapter)
rtw_ps_deny_cancel(padapter, PS_DENY_SUSPEND);
- if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
- rtw_suspend_normal(padapter);
- else if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
- rtw_suspend_normal(padapter);
- else
- rtw_suspend_normal(padapter);
+ rtw_suspend_normal(padapter);
netdev_dbg(padapter->pnetdev, "rtw suspend success in %d ms\n",
jiffies_to_msecs(jiffies - start_time));
exit:
- return ret;
+ return;
}
static int rtw_resume_process_normal(struct adapter *padapter)
@@ -1269,17 +1262,10 @@ int rtw_resume_common(struct adapter *padapter)
int ret = 0;
unsigned long start_time = jiffies;
struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
- struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
netdev_dbg(padapter->pnetdev, "resume start\n");
- if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
- rtw_resume_process_normal(padapter);
- } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
- rtw_resume_process_normal(padapter);
- } else {
- rtw_resume_process_normal(padapter);
- }
+ rtw_resume_process_normal(padapter);
hal_btcoex_SuspendNotify(padapter, 0);
diff --git a/drivers/staging/rtl8723bs/os_dep/osdep_service.c b/drivers/staging/rtl8723bs/os_dep/osdep_service.c
index 9c6b1666df13..c58555a4012f 100644
--- a/drivers/staging/rtl8723bs/os_dep/osdep_service.c
+++ b/drivers/staging/rtl8723bs/os_dep/osdep_service.c
@@ -4,10 +4,6 @@
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-
-
-#define _OSDEP_SERVICE_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c
index cd51430d4618..88a69c7ca8f2 100644
--- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c
@@ -4,8 +4,6 @@
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-#define _RECV_OSDEP_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
#include <linux/jiffies.h>
diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
index d2bf444117b8..490431484524 100644
--- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
+++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
@@ -4,8 +4,6 @@
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-#define _HCI_INTF_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
#include <hal_btcoex.h>
@@ -449,7 +447,9 @@ static int rtw_sdio_suspend(struct device *dev)
return 0;
}
- return rtw_suspend_common(padapter);
+ rtw_suspend_common(padapter);
+
+ return 0;
}
static int rtw_resume_process(struct adapter *padapter)
diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c b/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c
index 5cedf775b6ef..bed930760656 100644
--- a/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c
@@ -26,34 +26,6 @@ inline void rtw_sdio_set_irq_thd(struct dvobj_priv *dvobj, void *thd_hdl)
sdio_data->sys_sdio_irq_thd = thd_hdl;
}
-u8 sd_f0_read8(struct intf_hdl *pintfhdl, u32 addr, s32 *err)
-{
- struct adapter *padapter;
- struct dvobj_priv *psdiodev;
- struct sdio_data *psdio;
-
- u8 v = 0;
- struct sdio_func *func;
- bool claim_needed;
-
- padapter = pintfhdl->padapter;
- psdiodev = pintfhdl->pintf_dev;
- psdio = &psdiodev->intf_data;
-
- if (padapter->bSurpriseRemoved)
- return v;
-
- func = psdio->func;
- claim_needed = rtw_sdio_claim_host_needed(func);
-
- if (claim_needed)
- sdio_claim_host(func);
- v = sdio_f0_readb(func, addr, err);
- if (claim_needed)
- sdio_release_host(func);
- return v;
-}
-
/*
* Return:
*0 Success
diff --git a/drivers/staging/rtl8723bs/os_dep/wifi_regd.c b/drivers/staging/rtl8723bs/os_dep/wifi_regd.c
index 0084589499b9..5eef1d68c6f0 100644
--- a/drivers/staging/rtl8723bs/os_dep/wifi_regd.c
+++ b/drivers/staging/rtl8723bs/os_dep/wifi_regd.c
@@ -44,10 +44,6 @@ static const struct ieee80211_regdomain rtw_regdom_rd = {
static int rtw_ieee80211_channel_to_frequency(int chan, int band)
{
- /* see 802.11 17.3.8.3.2 and Annex J
- * there are overlapping channel numbers in 5GHz and 2GHz bands
- */
-
/* NL80211_BAND_2GHZ */
if (chan == 14)
return 2484;
diff --git a/drivers/staging/rtl8723bs/os_dep/xmit_linux.c b/drivers/staging/rtl8723bs/os_dep/xmit_linux.c
index 639408eaf4df..530e7a6c67c5 100644
--- a/drivers/staging/rtl8723bs/os_dep/xmit_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/xmit_linux.c
@@ -4,8 +4,6 @@
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
******************************************************************************/
-#define _XMIT_OSDEP_C_
-
#include <drv_types.h>
#include <rtw_debug.h>
@@ -139,13 +137,11 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
- plist = get_next(phead);
-
/* free sta asoc_queue */
- while (phead != plist) {
+ list_for_each(plist, phead) {
int stainfo_offset;
- psta = container_of(plist, struct sta_info, asoc_list);
- plist = get_next(plist);
+
+ psta = list_entry(plist, struct sta_info, asoc_list);
stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
if (stainfo_offset_valid(stainfo_offset)) {
diff --git a/drivers/staging/rts5208/ms.c b/drivers/staging/rts5208/ms.c
index 9001570a8c94..c6ad34a7fa33 100644
--- a/drivers/staging/rts5208/ms.c
+++ b/drivers/staging/rts5208/ms.c
@@ -2406,7 +2406,6 @@ static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no)
(void)ms_arbitrate_l2p(chip, phy_blk,
log_blk - ms_start_idx[seg_no], us1, us2);
- continue;
}
segment->build_flag = 1;
diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c
index 8faa601c700b..24b9077a634a 100644
--- a/drivers/staging/sm750fb/sm750_accel.c
+++ b/drivers/staging/sm750fb/sm750_accel.c
@@ -131,7 +131,8 @@ int sm750_hw_fillrect(struct lynx_accel *accel,
}
/**
- * sm750_hm_copyarea
+ * sm750_hw_copyarea
+ * @accel: Acceleration device data
* @sBase: Address of source: offset in frame buffer
* @sPitch: Pitch value of source surface in BYTE
* @sx: Starting x coordinate of source surface
@@ -298,6 +299,7 @@ static unsigned int deGetTransparency(struct lynx_accel *accel)
/**
* sm750_hw_imageblit
+ * @accel: Acceleration device data
* @pSrcbuf: pointer to start of source buffer in system memory
* @srcDelta: Pitch value (in bytes) of the source buffer, +ive means top down
* and -ive mean button up
diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c
index 4455d26f7c96..41f8a72a2a95 100644
--- a/drivers/staging/unisys/visorhba/visorhba_main.c
+++ b/drivers/staging/unisys/visorhba/visorhba_main.c
@@ -6,10 +6,10 @@
#include <linux/debugfs.h>
#include <linux/kthread.h>
-#include <linux/idr.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/visorbus.h>
+#include <linux/xarray.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
@@ -82,8 +82,7 @@ struct visorhba_devdata {
* allows us to pass int handles back-and-forth between us and
* iovm, instead of raw pointers
*/
- struct idr idr;
-
+ struct xarray xa;
struct dentry *debugfs_dir;
struct dentry *debugfs_info;
};
@@ -183,70 +182,47 @@ static struct uiscmdrsp *get_scsipending_cmdrsp(struct visorhba_devdata *ddata,
}
/*
- * simple_idr_get - Associate a provided pointer with an int value
- * 1 <= value <= INT_MAX, and return this int value;
- * the pointer value can be obtained later by passing
- * this int value to idr_find()
- * @idrtable: The data object maintaining the pointer<-->int mappings
- * @p: The pointer value to be remembered
- * @lock: A spinlock used when exclusive access to idrtable is needed
- *
- * Return: The id number mapped to pointer 'p', 0 on failure
- */
-static unsigned int simple_idr_get(struct idr *idrtable, void *p,
- spinlock_t *lock)
-{
- int id;
- unsigned long flags;
-
- idr_preload(GFP_KERNEL);
- spin_lock_irqsave(lock, flags);
- id = idr_alloc(idrtable, p, 1, INT_MAX, GFP_NOWAIT);
- spin_unlock_irqrestore(lock, flags);
- idr_preload_end();
- /* failure */
- if (id < 0)
- return 0;
- /* idr_alloc() guarantees > 0 */
- return (unsigned int)(id);
-}
-
-/*
* setup_scsitaskmgmt_handles - Stash the necessary handles so that the
* completion processing logic for a taskmgmt
* cmd will be able to find who to wake up
* and where to stash the result
- * @idrtable: The data object maintaining the pointer<-->int mappings
- * @lock: A spinlock used when exclusive access to idrtable is needed
+ * @xa: The data object maintaining the pointer<-->int mappings
* @cmdrsp: Response from the IOVM
* @event: The event handle to associate with an id
* @result: The location to place the result of the event handle into
*/
-static void setup_scsitaskmgmt_handles(struct idr *idrtable, spinlock_t *lock,
- struct uiscmdrsp *cmdrsp,
+static int setup_scsitaskmgmt_handles(struct xarray *xa, struct uiscmdrsp *cmdrsp,
wait_queue_head_t *event, int *result)
{
- /* specify the event that has to be triggered when this */
- /* cmd is complete */
- cmdrsp->scsitaskmgmt.notify_handle =
- simple_idr_get(idrtable, event, lock);
- cmdrsp->scsitaskmgmt.notifyresult_handle =
- simple_idr_get(idrtable, result, lock);
+ int ret;
+ u32 id;
+
+ /* specify the event that has to be triggered when this cmd is complete */
+ ret = xa_alloc_irq(xa, &id, event, xa_limit_32b, GFP_KERNEL);
+ if (ret)
+ return ret;
+ cmdrsp->scsitaskmgmt.notify_handle = id;
+ ret = xa_alloc_irq(xa, &id, result, xa_limit_32b, GFP_KERNEL);
+ if (ret) {
+ xa_erase_irq(xa, cmdrsp->scsitaskmgmt.notify_handle);
+ return ret;
+ }
+ cmdrsp->scsitaskmgmt.notifyresult_handle = id;
+
+ return 0;
}
/*
* cleanup_scsitaskmgmt_handles - Forget handles created by
* setup_scsitaskmgmt_handles()
- * @idrtable: The data object maintaining the pointer<-->int mappings
+ * @xa: The data object maintaining the pointer<-->int mappings
* @cmdrsp: Response from the IOVM
*/
-static void cleanup_scsitaskmgmt_handles(struct idr *idrtable,
+static void cleanup_scsitaskmgmt_handles(struct xarray *xa,
struct uiscmdrsp *cmdrsp)
{
- if (cmdrsp->scsitaskmgmt.notify_handle)
- idr_remove(idrtable, cmdrsp->scsitaskmgmt.notify_handle);
- if (cmdrsp->scsitaskmgmt.notifyresult_handle)
- idr_remove(idrtable, cmdrsp->scsitaskmgmt.notifyresult_handle);
+ xa_erase_irq(xa, cmdrsp->scsitaskmgmt.notify_handle);
+ xa_erase_irq(xa, cmdrsp->scsitaskmgmt.notifyresult_handle);
}
/*
@@ -269,6 +245,7 @@ static int forward_taskmgmt_command(enum task_mgmt_types tasktype,
int notifyresult = 0xffff;
wait_queue_head_t notifyevent;
int scsicmd_id;
+ int ret;
if (devdata->serverdown || devdata->serverchangingstate)
return FAILED;
@@ -284,8 +261,14 @@ static int forward_taskmgmt_command(enum task_mgmt_types tasktype,
/* issue TASK_MGMT_ABORT_TASK */
cmdrsp->cmdtype = CMD_SCSITASKMGMT_TYPE;
- setup_scsitaskmgmt_handles(&devdata->idr, &devdata->privlock, cmdrsp,
- &notifyevent, &notifyresult);
+
+ ret = setup_scsitaskmgmt_handles(&devdata->xa, cmdrsp,
+ &notifyevent, &notifyresult);
+ if (ret) {
+ dev_dbg(&scsidev->sdev_gendev,
+ "visorhba: setup_scsitaskmgmt_handles returned %d\n", ret);
+ return FAILED;
+ }
/* save destination */
cmdrsp->scsitaskmgmt.tasktype = tasktype;
@@ -311,14 +294,14 @@ static int forward_taskmgmt_command(enum task_mgmt_types tasktype,
dev_dbg(&scsidev->sdev_gendev,
"visorhba: taskmgmt type=%d success; result=0x%x\n",
tasktype, notifyresult);
- cleanup_scsitaskmgmt_handles(&devdata->idr, cmdrsp);
+ cleanup_scsitaskmgmt_handles(&devdata->xa, cmdrsp);
return SUCCESS;
err_del_scsipending_ent:
dev_dbg(&scsidev->sdev_gendev,
"visorhba: taskmgmt type=%d not executed\n", tasktype);
del_scsipending_ent(devdata, scsicmd_id);
- cleanup_scsitaskmgmt_handles(&devdata->idr, cmdrsp);
+ cleanup_scsitaskmgmt_handles(&devdata->xa, cmdrsp);
return FAILED;
}
@@ -654,13 +637,13 @@ DEFINE_SHOW_ATTRIBUTE(info_debugfs);
* Service Partition returned the result of the task management
* command. Wake up anyone waiting for it.
*/
-static void complete_taskmgmt_command(struct idr *idrtable,
+static void complete_taskmgmt_command(struct xarray *xa,
struct uiscmdrsp *cmdrsp, int result)
{
wait_queue_head_t *wq =
- idr_find(idrtable, cmdrsp->scsitaskmgmt.notify_handle);
+ xa_load(xa, cmdrsp->scsitaskmgmt.notify_handle);
int *scsi_result_ptr =
- idr_find(idrtable, cmdrsp->scsitaskmgmt.notifyresult_handle);
+ xa_load(xa, cmdrsp->scsitaskmgmt.notifyresult_handle);
if (unlikely(!(wq && scsi_result_ptr))) {
pr_err("visorhba: no completion context; cmd will time out\n");
return;
@@ -708,7 +691,7 @@ static void visorhba_serverdown_complete(struct visorhba_devdata *devdata)
break;
case CMD_SCSITASKMGMT_TYPE:
cmdrsp = pendingdel->sent;
- complete_taskmgmt_command(&devdata->idr, cmdrsp,
+ complete_taskmgmt_command(&devdata->xa, cmdrsp,
TASK_MGMT_FAILED);
break;
default:
@@ -905,7 +888,7 @@ static void drain_queue(struct uiscmdrsp *cmdrsp,
if (!del_scsipending_ent(devdata,
cmdrsp->scsitaskmgmt.handle))
break;
- complete_taskmgmt_command(&devdata->idr, cmdrsp,
+ complete_taskmgmt_command(&devdata->xa, cmdrsp,
cmdrsp->scsitaskmgmt.result);
} else if (cmdrsp->cmdtype == CMD_NOTIFYGUEST_TYPE)
dev_err_once(&devdata->dev->device,
@@ -1053,7 +1036,7 @@ static int visorhba_probe(struct visor_device *dev)
if (err)
goto err_debugfs_info;
- idr_init(&devdata->idr);
+ xa_init(&devdata->xa);
devdata->cmdrsp = kmalloc(sizeof(*devdata->cmdrsp), GFP_ATOMIC);
visorbus_enable_channel_interrupts(dev);
@@ -1096,8 +1079,6 @@ static void visorhba_remove(struct visor_device *dev)
scsi_remove_host(scsihost);
scsi_host_put(scsihost);
- idr_destroy(&devdata->idr);
-
dev_set_drvdata(&dev->device, NULL);
debugfs_remove(devdata->debugfs_info);
debugfs_remove_recursive(devdata->debugfs_dir);
diff --git a/drivers/staging/unisys/visorinput/visorinput.c b/drivers/staging/unisys/visorinput/visorinput.c
index 6d202cba8575..426deab22d62 100644
--- a/drivers/staging/unisys/visorinput/visorinput.c
+++ b/drivers/staging/unisys/visorinput/visorinput.c
@@ -556,7 +556,6 @@ static void handle_locking_key(struct input_dev *visorinput_dev, int keycode,
led = LED_NUML;
break;
default:
- led = -1;
return;
}
if (test_bit(led, visorinput_dev->led) != desired_state) {
diff --git a/drivers/staging/vc04_services/Makefile b/drivers/staging/vc04_services/Makefile
index 7546d70116a0..e21e73ae3cc6 100644
--- a/drivers/staging/vc04_services/Makefile
+++ b/drivers/staging/vc04_services/Makefile
@@ -12,5 +12,5 @@ obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/
obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
-ccflags-y += -I $(srctree)/$(src)/include -D__VCCOREVER__=0x04000000
+ccflags-y += -I $(srctree)/$(src)/include
diff --git a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h
index fefc664eefcf..81db7fb76d6d 100644
--- a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h
+++ b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h
@@ -104,7 +104,7 @@ extern enum vchiq_status vchiq_bulk_receive(unsigned int service,
enum vchiq_bulk_mode mode);
extern void *vchiq_get_service_userdata(unsigned int service);
extern enum vchiq_status vchiq_get_peer_version(unsigned int handle,
- short *peer_version);
+ short *peer_version);
extern struct vchiq_header *vchiq_msg_hold(unsigned int handle);
#endif /* VCHIQ_H */
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 8782ebe0b39a..30d6f1a404ba 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
@@ -29,6 +29,8 @@
#define BELL0 0x00
#define BELL2 0x08
+#define ARM_DS_ACTIVE BIT(2)
+
struct vchiq_2835_state {
int inited;
struct vchiq_arm_state arm_state;
@@ -132,8 +134,9 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state)
*(char **)&g_fragments_base[i * g_fragments_size] = NULL;
sema_init(&g_free_fragments_sema, MAX_FRAGMENTS);
- if (vchiq_init_state(state, vchiq_slot_zero) != VCHIQ_SUCCESS)
- return -EINVAL;
+ err = vchiq_init_state(state, vchiq_slot_zero);
+ if (err)
+ return err;
g_regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(g_regs))
@@ -169,25 +172,21 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state)
return 0;
}
-enum vchiq_status
+int
vchiq_platform_init_state(struct vchiq_state *state)
{
- enum vchiq_status status = VCHIQ_SUCCESS;
struct vchiq_2835_state *platform_state;
state->platform_state = kzalloc(sizeof(*platform_state), GFP_KERNEL);
if (!state->platform_state)
- return VCHIQ_ERROR;
+ return -ENOMEM;
platform_state = (struct vchiq_2835_state *)state->platform_state;
platform_state->inited = 1;
- status = vchiq_arm_init_state(state, &platform_state->arm_state);
+ vchiq_arm_init_state(state, &platform_state->arm_state);
- if (status != VCHIQ_SUCCESS)
- platform_state->inited = 0;
-
- return status;
+ return 0;
}
struct vchiq_arm_state*
@@ -215,7 +214,7 @@ remote_event_signal(struct remote_event *event)
writel(0, g_regs + BELL2); /* trigger vc interrupt */
}
-enum vchiq_status
+int
vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset,
void __user *uoffset, int size, int dir)
{
@@ -227,7 +226,7 @@ vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset,
: PAGELIST_WRITE);
if (!pagelistinfo)
- return VCHIQ_ERROR;
+ return -ENOMEM;
bulk->data = pagelistinfo->dma_addr;
@@ -237,7 +236,7 @@ vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset,
*/
bulk->remote_data = pagelistinfo;
- return VCHIQ_SUCCESS;
+ return 0;
}
void
@@ -272,7 +271,7 @@ vchiq_doorbell_irq(int irq, void *dev_id)
/* Read (and clear) the doorbell */
status = readl(g_regs + BELL0);
- if (status & 0x4) { /* Was the doorbell rung? */
+ if (status & ARM_DS_ACTIVE) { /* Was the doorbell rung? */
remote_event_pollall(state);
ret = IRQ_HANDLED;
}
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 e39897c38e6a..b5aac862a298 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -139,22 +139,18 @@ static const char *const ioctl_names[] = {
"CLOSE_DELIVERED"
};
-vchiq_static_assert(ARRAY_SIZE(ioctl_names) ==
- (VCHIQ_IOC_MAX + 1));
+static_assert(ARRAY_SIZE(ioctl_names) == (VCHIQ_IOC_MAX + 1));
static enum vchiq_status
vchiq_blocking_bulk_transfer(unsigned int handle, void *data,
unsigned int size, enum vchiq_bulk_dir dir);
#define VCHIQ_INIT_RETRIES 10
-enum vchiq_status vchiq_initialise(struct vchiq_instance **instance_out)
+int vchiq_initialise(struct vchiq_instance **instance_out)
{
- enum vchiq_status status = VCHIQ_ERROR;
struct vchiq_state *state;
struct vchiq_instance *instance = NULL;
- int i;
-
- vchiq_log_trace(vchiq_core_log_level, "%s called", __func__);
+ int i, ret;
/*
* VideoCore may not be ready due to boot up timing.
@@ -170,6 +166,7 @@ enum vchiq_status vchiq_initialise(struct vchiq_instance **instance_out)
if (i == VCHIQ_INIT_RETRIES) {
vchiq_log_error(vchiq_core_log_level,
"%s: videocore not initialized\n", __func__);
+ ret = -ENOTCONN;
goto failed;
} else if (i > 0) {
vchiq_log_warning(vchiq_core_log_level,
@@ -181,6 +178,7 @@ enum vchiq_status vchiq_initialise(struct vchiq_instance **instance_out)
if (!instance) {
vchiq_log_error(vchiq_core_log_level,
"%s: error allocating vchiq instance\n", __func__);
+ ret = -ENOMEM;
goto failed;
}
@@ -191,48 +189,48 @@ enum vchiq_status vchiq_initialise(struct vchiq_instance **instance_out)
*instance_out = instance;
- status = VCHIQ_SUCCESS;
+ ret = 0;
failed:
vchiq_log_trace(vchiq_core_log_level,
- "%s(%p): returning %d", __func__, instance, status);
+ "%s(%p): returning %d", __func__, instance, ret);
- return status;
+ return ret;
}
EXPORT_SYMBOL(vchiq_initialise);
+static void free_bulk_waiter(struct vchiq_instance *instance)
+{
+ struct bulk_waiter_node *waiter, *next;
+
+ list_for_each_entry_safe(waiter, next,
+ &instance->bulk_waiter_list, list) {
+ list_del(&waiter->list);
+ vchiq_log_info(vchiq_arm_log_level,
+ "bulk_waiter - cleaned up %pK for pid %d",
+ waiter, waiter->pid);
+ kfree(waiter);
+ }
+}
+
enum vchiq_status vchiq_shutdown(struct vchiq_instance *instance)
{
- enum vchiq_status status;
+ enum vchiq_status status = VCHIQ_SUCCESS;
struct vchiq_state *state = instance->state;
- vchiq_log_trace(vchiq_core_log_level,
- "%s(%p) called", __func__, instance);
-
if (mutex_lock_killable(&state->mutex))
return VCHIQ_RETRY;
/* Remove all services */
- status = vchiq_shutdown_internal(state, instance);
+ vchiq_shutdown_internal(state, instance);
mutex_unlock(&state->mutex);
vchiq_log_trace(vchiq_core_log_level,
"%s(%p): returning %d", __func__, instance, status);
- if (status == VCHIQ_SUCCESS) {
- struct bulk_waiter_node *waiter, *next;
-
- list_for_each_entry_safe(waiter, next,
- &instance->bulk_waiter_list, list) {
- list_del(&waiter->list);
- vchiq_log_info(vchiq_arm_log_level,
- "bulk_waiter - cleaned up %pK for pid %d",
- waiter, waiter->pid);
- kfree(waiter);
- }
- kfree(instance);
- }
+ free_bulk_waiter(instance);
+ kfree(instance);
return status;
}
@@ -248,9 +246,6 @@ enum vchiq_status vchiq_connect(struct vchiq_instance *instance)
enum vchiq_status status;
struct vchiq_state *state = instance->state;
- vchiq_log_trace(vchiq_core_log_level,
- "%s(%p) called", __func__, instance);
-
if (mutex_lock_killable(&state->mutex)) {
vchiq_log_trace(vchiq_core_log_level,
"%s: call to mutex_lock failed", __func__);
@@ -272,19 +267,16 @@ failed:
}
EXPORT_SYMBOL(vchiq_connect);
-static enum vchiq_status vchiq_add_service(
- struct vchiq_instance *instance,
- const struct vchiq_service_params_kernel *params,
- unsigned int *phandle)
+static enum vchiq_status
+vchiq_add_service(struct vchiq_instance *instance,
+ const struct vchiq_service_params_kernel *params,
+ unsigned int *phandle)
{
enum vchiq_status status;
struct vchiq_state *state = instance->state;
struct vchiq_service *service = NULL;
int srvstate;
- vchiq_log_trace(vchiq_core_log_level,
- "%s(%p) called", __func__, instance);
-
*phandle = VCHIQ_SERVICE_HANDLE_INVALID;
srvstate = vchiq_is_connected(instance)
@@ -301,8 +293,9 @@ static enum vchiq_status vchiq_add_service(
if (service) {
*phandle = service->handle;
status = VCHIQ_SUCCESS;
- } else
+ } else {
status = VCHIQ_ERROR;
+ }
vchiq_log_trace(vchiq_core_log_level,
"%s(%p): returning %d", __func__, instance, status);
@@ -310,18 +303,15 @@ static enum vchiq_status vchiq_add_service(
return status;
}
-enum vchiq_status vchiq_open_service(
- struct vchiq_instance *instance,
- const struct vchiq_service_params_kernel *params,
- unsigned int *phandle)
+enum vchiq_status
+vchiq_open_service(struct vchiq_instance *instance,
+ const struct vchiq_service_params_kernel *params,
+ unsigned int *phandle)
{
enum vchiq_status status = VCHIQ_ERROR;
struct vchiq_state *state = instance->state;
struct vchiq_service *service = NULL;
- vchiq_log_trace(vchiq_core_log_level,
- "%s(%p) called", __func__, instance);
-
*phandle = VCHIQ_SERVICE_HANDLE_INVALID;
if (!vchiq_is_connected(instance))
@@ -351,8 +341,8 @@ failed:
EXPORT_SYMBOL(vchiq_open_service);
enum vchiq_status
-vchiq_bulk_transmit(unsigned int handle, const void *data,
- unsigned int size, void *userdata, enum vchiq_bulk_mode mode)
+vchiq_bulk_transmit(unsigned int handle, const void *data, unsigned int size,
+ void *userdata, enum vchiq_bulk_mode mode)
{
enum vchiq_status status;
@@ -426,8 +416,8 @@ enum vchiq_status vchiq_bulk_receive(unsigned int handle, void *data,
EXPORT_SYMBOL(vchiq_bulk_receive);
static enum vchiq_status
-vchiq_blocking_bulk_transfer(unsigned int handle, void *data,
- unsigned int size, enum vchiq_bulk_dir dir)
+vchiq_blocking_bulk_transfer(unsigned int handle, void *data, unsigned int size,
+ enum vchiq_bulk_dir dir)
{
struct vchiq_instance *instance;
struct vchiq_service *service;
@@ -441,7 +431,7 @@ vchiq_blocking_bulk_transfer(unsigned int handle, void *data,
instance = service->instance;
- unlock_service(service);
+ vchiq_service_put(service);
mutex_lock(&instance->bulk_waiter_list_mutex);
list_for_each_entry(waiter, &instance->bulk_waiter_list, list) {
@@ -471,7 +461,7 @@ vchiq_blocking_bulk_transfer(unsigned int handle, void *data,
}
}
} else {
- waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL);
+ waiter = kzalloc(sizeof(*waiter), GFP_KERNEL);
if (!waiter) {
vchiq_log_error(vchiq_core_log_level,
"%s - out of memory", __func__);
@@ -505,11 +495,6 @@ vchiq_blocking_bulk_transfer(unsigned int handle, void *data,
return status;
}
-/****************************************************************************
- *
- * add_completion
- *
- ***************************************************************************/
static enum vchiq_status
add_completion(struct vchiq_instance *instance, enum vchiq_reason reason,
@@ -554,7 +539,7 @@ add_completion(struct vchiq_instance *instance, enum vchiq_reason reason,
* Take an extra reference, to be held until
* this CLOSED notification is delivered.
*/
- lock_service(user_service->service);
+ vchiq_service_get(user_service->service);
if (instance->use_close_delivered)
user_service->close_pending = 1;
}
@@ -576,12 +561,6 @@ add_completion(struct vchiq_instance *instance, enum vchiq_reason reason,
return VCHIQ_SUCCESS;
}
-/****************************************************************************
- *
- * service_callback
- *
- ***************************************************************************/
-
static enum vchiq_status
service_callback(enum vchiq_reason reason, struct vchiq_header *header,
unsigned int handle, void *bulk_userdata)
@@ -602,7 +581,9 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header,
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
service = handle_to_service(handle);
- BUG_ON(!service);
+ if (WARN_ON(!service))
+ return VCHIQ_SUCCESS;
+
user_service = (struct user_service *)service->base.userdata;
instance = user_service->instance;
@@ -691,22 +672,12 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header,
bulk_userdata);
}
-/****************************************************************************
- *
- * user_service_free
- *
- ***************************************************************************/
static void
user_service_free(void *userdata)
{
kfree(userdata);
}
-/****************************************************************************
- *
- * close_delivered
- *
- ***************************************************************************/
static void close_delivered(struct user_service *user_service)
{
vchiq_log_info(vchiq_arm_log_level,
@@ -715,7 +686,7 @@ static void close_delivered(struct user_service *user_service)
if (user_service->close_pending) {
/* Allow the underlying service to be culled */
- unlock_service(user_service->service);
+ vchiq_service_put(user_service->service);
/* Wake the user-thread blocked in close_ or remove_service */
complete(&user_service->close_event);
@@ -769,14 +740,8 @@ static ssize_t vchiq_ioc_copy_element_data(void *context, void *dest,
return maxsize;
}
-/**************************************************************************
- *
- * vchiq_ioc_queue_message
- *
- **************************************************************************/
static int
-vchiq_ioc_queue_message(unsigned int handle,
- struct vchiq_element *elements,
+vchiq_ioc_queue_message(unsigned int handle, struct vchiq_element *elements,
unsigned long count)
{
struct vchiq_io_copy_callback_context context;
@@ -911,15 +876,18 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance,
break;
}
spin_lock(&msg_queue_spinlock);
- } while (user_service->msg_remove ==
- user_service->msg_insert);
+ } while (user_service->msg_remove == user_service->msg_insert);
if (ret)
goto out;
}
- BUG_ON((int)(user_service->msg_insert -
- user_service->msg_remove) < 0);
+ if (WARN_ON_ONCE((int)(user_service->msg_insert -
+ user_service->msg_remove) < 0)) {
+ spin_unlock(&msg_queue_spinlock);
+ ret = -EINVAL;
+ goto out;
+ }
header = user_service->msg_queue[user_service->msg_remove &
(MSG_QUEUE_SIZE - 1)];
@@ -935,8 +903,9 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance,
header->data, header->size) == 0)) {
ret = header->size;
vchiq_release_message(service->handle, header);
- } else
+ } else {
ret = -EFAULT;
+ }
} else {
vchiq_log_error(vchiq_arm_log_level,
"header %pK: bufsize %x < size %x",
@@ -946,7 +915,7 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance,
}
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
out:
- unlock_service(service);
+ vchiq_service_put(service);
return ret;
}
@@ -967,8 +936,7 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance,
return -EINVAL;
if (args->mode == VCHIQ_BULK_MODE_BLOCKING) {
- waiter = kzalloc(sizeof(struct bulk_waiter_node),
- GFP_KERNEL);
+ waiter = kzalloc(sizeof(*waiter), GFP_KERNEL);
if (!waiter) {
ret = -ENOMEM;
goto out;
@@ -1033,7 +1001,7 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance,
ret = put_user(mode_waiting, mode);
}
out:
- unlock_service(service);
+ vchiq_service_put(service);
if (ret)
return ret;
else if (status == VCHIQ_ERROR)
@@ -1051,6 +1019,7 @@ static inline int vchiq_get_user_ptr(void __user **buf, void __user *ubuf, int i
if (in_compat_syscall()) {
compat_uptr_t ptr32;
compat_uptr_t __user *uptr = ubuf;
+
ret = get_user(ptr32, uptr + index);
if (ret)
return ret;
@@ -1058,6 +1027,7 @@ static inline int vchiq_get_user_ptr(void __user **buf, void __user *ubuf, int i
*buf = compat_ptr(ptr32);
} else {
uintptr_t ptr, __user *uptr = ubuf;
+
ret = get_user(ptr, uptr + index);
if (ret)
@@ -1117,8 +1087,7 @@ static int vchiq_ioc_await_completion(struct vchiq_instance *instance,
mutex_lock(&instance->completion_mutex);
DEBUG_TRACE(AWAIT_COMPLETION_LINE);
- while ((instance->completion_remove ==
- instance->completion_insert)
+ while ((instance->completion_remove == instance->completion_insert)
&& !instance->closing) {
int rc;
@@ -1212,7 +1181,7 @@ static int vchiq_ioc_await_completion(struct vchiq_instance *instance,
if ((completion->reason == VCHIQ_SERVICE_CLOSED) &&
!instance->use_close_delivered)
- unlock_service(service);
+ vchiq_service_put(service);
/*
* FIXME: address space mismatch, does bulk_userdata
@@ -1248,11 +1217,6 @@ out:
return ret;
}
-/****************************************************************************
- *
- * vchiq_ioctl
- *
- ***************************************************************************/
static long
vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
@@ -1279,7 +1243,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
while ((service = next_service_by_instance(instance->state,
instance, &i))) {
status = vchiq_remove_service(service->handle);
- unlock_service(service);
+ vchiq_service_put(service);
if (status != VCHIQ_SUCCESS)
break;
}
@@ -1379,24 +1343,24 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
service = find_service_for_instance(instance, handle);
if (service) {
- status = (cmd == VCHIQ_IOC_USE_SERVICE) ?
+ ret = (cmd == VCHIQ_IOC_USE_SERVICE) ?
vchiq_use_service_internal(service) :
vchiq_release_service_internal(service);
- if (status != VCHIQ_SUCCESS) {
+ if (ret) {
vchiq_log_error(vchiq_susp_log_level,
- "%s: cmd %s returned error %d for service %c%c%c%c:%03d",
+ "%s: cmd %s returned error %ld for service %c%c%c%c:%03d",
__func__,
(cmd == VCHIQ_IOC_USE_SERVICE) ?
"VCHIQ_IOC_USE_SERVICE" :
"VCHIQ_IOC_RELEASE_SERVICE",
- status,
+ ret,
VCHIQ_FOURCC_AS_4CHARS(
service->base.fourcc),
service->client_id);
- ret = -EINVAL;
}
- } else
+ } else {
ret = -EINVAL;
+ }
} break;
case VCHIQ_IOC_QUEUE_MESSAGE: {
@@ -1512,8 +1476,8 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
- status = vchiq_set_service_option(
- args.handle, args.option, args.value);
+ ret = vchiq_set_service_option(args.handle, args.option,
+ args.value);
} break;
case VCHIQ_IOC_LIB_VERSION: {
@@ -1533,8 +1497,9 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct user_service *user_service =
(struct user_service *)service->base.userdata;
close_delivered(user_service);
- } else
+ } else {
ret = -EINVAL;
+ }
} break;
default:
@@ -1543,7 +1508,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
if (service)
- unlock_service(service);
+ vchiq_service_put(service);
if (ret == 0) {
if (status == VCHIQ_ERROR)
@@ -1594,10 +1559,8 @@ struct vchiq_create_service32 {
_IOWR(VCHIQ_IOC_MAGIC, 2, struct vchiq_create_service32)
static long
-vchiq_compat_ioctl_create_service(
- struct file *file,
- unsigned int cmd,
- struct vchiq_create_service32 __user *ptrargs32)
+vchiq_compat_ioctl_create_service(struct file *file, unsigned int cmd,
+ struct vchiq_create_service32 __user *ptrargs32)
{
struct vchiq_create_service args;
struct vchiq_create_service32 args32;
@@ -1678,7 +1641,7 @@ vchiq_compat_ioctl_queue_message(struct file *file,
if (copy_from_user(&element32, args.elements,
sizeof(element32))) {
- unlock_service(service);
+ vchiq_service_put(service);
return -EFAULT;
}
@@ -1692,7 +1655,7 @@ vchiq_compat_ioctl_queue_message(struct file *file,
} else {
ret = -EINVAL;
}
- unlock_service(service);
+ vchiq_service_put(service);
return ret;
}
@@ -1834,6 +1797,7 @@ static long
vchiq_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *argp = compat_ptr(arg);
+
switch (cmd) {
case VCHIQ_IOC_CREATE_SERVICE32:
return vchiq_compat_ioctl_create_service(file, cmd, argp);
@@ -1927,7 +1891,7 @@ static int vchiq_release(struct inode *inode, struct file *file)
complete(&user_service->remove_event);
vchiq_terminate_service_internal(service);
- unlock_service(service);
+ vchiq_service_put(service);
}
/* ...and wait for them to die */
@@ -1937,7 +1901,10 @@ static int vchiq_release(struct inode *inode, struct file *file)
wait_for_completion(&service->remove_event);
- BUG_ON(service->srvstate != VCHIQ_SRVSTATE_FREE);
+ if (WARN_ON(service->srvstate != VCHIQ_SRVSTATE_FREE)) {
+ vchiq_service_put(service);
+ break;
+ }
spin_lock(&msg_queue_spinlock);
@@ -1956,12 +1923,11 @@ static int vchiq_release(struct inode *inode, struct file *file)
spin_unlock(&msg_queue_spinlock);
- unlock_service(service);
+ vchiq_service_put(service);
}
/* Release any closed services */
- while (instance->completion_remove !=
- instance->completion_insert) {
+ while (instance->completion_remove != instance->completion_insert) {
struct vchiq_completion_data_kernel *completion;
struct vchiq_service *service;
@@ -1975,7 +1941,7 @@ static int vchiq_release(struct inode *inode, struct file *file)
/* Wake any blocked user-thread */
if (instance->use_close_delivered)
complete(&user_service->close_event);
- unlock_service(service);
+ vchiq_service_put(service);
}
instance->completion_remove++;
}
@@ -1983,18 +1949,7 @@ static int vchiq_release(struct inode *inode, struct file *file)
/* Release the PEER service count. */
vchiq_release_internal(instance->state, NULL);
- {
- struct bulk_waiter_node *waiter, *next;
-
- list_for_each_entry_safe(waiter, next,
- &instance->bulk_waiter_list, list) {
- list_del(&waiter->list);
- vchiq_log_info(vchiq_arm_log_level,
- "bulk_waiter - cleaned up %pK for pid %d",
- waiter, waiter->pid);
- kfree(waiter);
- }
- }
+ free_bulk_waiter(instance);
vchiq_debugfs_remove_instance(instance);
@@ -2005,12 +1960,6 @@ out:
return ret;
}
-/****************************************************************************
- *
- * vchiq_dump
- *
- ***************************************************************************/
-
int vchiq_dump(void *dump_context, const char *str, int len)
{
struct dump_context *context = (struct dump_context *)dump_context;
@@ -2052,12 +2001,6 @@ int vchiq_dump(void *dump_context, const char *str, int len)
return 0;
}
-/****************************************************************************
- *
- * vchiq_dump_platform_instance_state
- *
- ***************************************************************************/
-
int vchiq_dump_platform_instances(void *dump_context)
{
struct vchiq_state *state = vchiq_get_state();
@@ -2120,12 +2063,6 @@ int vchiq_dump_platform_instances(void *dump_context)
return 0;
}
-/****************************************************************************
- *
- * vchiq_dump_platform_service_state
- *
- ***************************************************************************/
-
int vchiq_dump_platform_service_state(void *dump_context,
struct vchiq_service *service)
{
@@ -2151,15 +2088,8 @@ int vchiq_dump_platform_service_state(void *dump_context,
return vchiq_dump(dump_context, buf, len + 1);
}
-/****************************************************************************
- *
- * vchiq_read
- *
- ***************************************************************************/
-
static ssize_t
-vchiq_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+vchiq_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
struct dump_context context;
int err;
@@ -2183,10 +2113,10 @@ vchiq_get_state(void)
{
if (!g_state.remote)
- printk(KERN_ERR "%s: g_state.remote == NULL\n", __func__);
+ pr_err("%s: g_state.remote == NULL\n", __func__);
else if (g_state.remote->initialised != 1)
- printk(KERN_NOTICE "%s: g_state.remote->initialised != 1 (%d)\n",
- __func__, g_state.remote->initialised);
+ pr_notice("%s: g_state.remote->initialised != 1 (%d)\n",
+ __func__, g_state.remote->initialised);
return (g_state.remote &&
(g_state.remote->initialised == 1)) ? &g_state : NULL;
@@ -2210,9 +2140,8 @@ vchiq_fops = {
static enum vchiq_status
vchiq_keepalive_vchiq_callback(enum vchiq_reason reason,
- struct vchiq_header *header,
- unsigned int service_user,
- void *bulk_user)
+ struct vchiq_header *header,
+ unsigned int service_user, void *bulk_user)
{
vchiq_log_error(vchiq_susp_log_level,
"%s callback reason %d", __func__, reason);
@@ -2228,6 +2157,7 @@ vchiq_keepalive_thread_func(void *v)
enum vchiq_status status;
struct vchiq_instance *instance;
unsigned int ka_handle;
+ int ret;
struct vchiq_service_params_kernel params = {
.fourcc = VCHIQ_MAKE_FOURCC('K', 'E', 'E', 'P'),
@@ -2236,10 +2166,10 @@ vchiq_keepalive_thread_func(void *v)
.version_min = KEEPALIVE_VER_MIN
};
- status = vchiq_initialise(&instance);
- if (status != VCHIQ_SUCCESS) {
+ ret = vchiq_initialise(&instance);
+ if (ret) {
vchiq_log_error(vchiq_susp_log_level,
- "%s vchiq_initialise failed %d", __func__, status);
+ "%s vchiq_initialise failed %d", __func__, ret);
goto exit;
}
@@ -2303,7 +2233,7 @@ exit:
return 0;
}
-enum vchiq_status
+void
vchiq_arm_init_state(struct vchiq_state *state,
struct vchiq_arm_state *arm_state)
{
@@ -2319,26 +2249,23 @@ vchiq_arm_init_state(struct vchiq_state *state,
arm_state->first_connect = 0;
}
- return VCHIQ_SUCCESS;
}
-enum vchiq_status
+int
vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
enum USE_TYPE_E use_type)
{
struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
- enum vchiq_status ret = VCHIQ_SUCCESS;
+ int ret = 0;
char entity[16];
int *entity_uc;
int local_uc;
if (!arm_state) {
- ret = VCHIQ_ERROR;
+ ret = -EINVAL;
goto out;
}
- vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-
if (use_type == USE_TYPE_VCHIQ) {
sprintf(entity, "VCHIQ: ");
entity_uc = &arm_state->peer_use_count;
@@ -2349,7 +2276,7 @@ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
entity_uc = &service->service_use_count;
} else {
vchiq_log_error(vchiq_susp_log_level, "%s null service ptr", __func__);
- ret = VCHIQ_ERROR;
+ ret = -EINVAL;
goto out;
}
@@ -2363,7 +2290,7 @@ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
write_unlock_bh(&arm_state->susp_res_lock);
- if (ret == VCHIQ_SUCCESS) {
+ if (!ret) {
enum vchiq_status status = VCHIQ_SUCCESS;
long ack_cnt = atomic_xchg(&arm_state->ka_use_ack_count, 0);
@@ -2383,21 +2310,19 @@ out:
return ret;
}
-enum vchiq_status
+int
vchiq_release_internal(struct vchiq_state *state, struct vchiq_service *service)
{
struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
- enum vchiq_status ret = VCHIQ_SUCCESS;
+ int ret = 0;
char entity[16];
int *entity_uc;
if (!arm_state) {
- ret = VCHIQ_ERROR;
+ ret = -EINVAL;
goto out;
}
- vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-
if (service) {
sprintf(entity, "%c%c%c%c:%03d",
VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
@@ -2413,7 +2338,7 @@ vchiq_release_internal(struct vchiq_state *state, struct vchiq_service *service)
/* Don't use BUG_ON - don't allow user thread to crash kernel */
WARN_ON(!arm_state->videocore_use_count);
WARN_ON(!(*entity_uc));
- ret = VCHIQ_ERROR;
+ ret = -EINVAL;
goto unlock;
}
--arm_state->videocore_use_count;
@@ -2437,7 +2362,6 @@ vchiq_on_remote_use(struct vchiq_state *state)
{
struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
- vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
atomic_inc(&arm_state->ka_use_count);
complete(&arm_state->ka_evt);
}
@@ -2447,18 +2371,17 @@ vchiq_on_remote_release(struct vchiq_state *state)
{
struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
- vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
atomic_inc(&arm_state->ka_release_count);
complete(&arm_state->ka_evt);
}
-enum vchiq_status
+int
vchiq_use_service_internal(struct vchiq_service *service)
{
return vchiq_use_internal(service->state, service, USE_TYPE_SERVICE);
}
-enum vchiq_status
+int
vchiq_release_service_internal(struct vchiq_service *service)
{
return vchiq_release_internal(service->state, service);
@@ -2521,7 +2444,7 @@ vchiq_use_service(unsigned int handle)
if (service) {
ret = vchiq_use_internal(service->state, service,
USE_TYPE_SERVICE);
- unlock_service(service);
+ vchiq_service_put(service);
}
return ret;
}
@@ -2535,7 +2458,7 @@ vchiq_release_service(unsigned int handle)
if (service) {
ret = vchiq_release_internal(service->state, service);
- unlock_service(service);
+ vchiq_service_put(service);
}
return ret;
}
@@ -2634,8 +2557,6 @@ vchiq_check_service(struct vchiq_service *service)
if (!service || !service->state)
goto out;
- vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-
arm_state = vchiq_platform_get_arm_state(service->state);
read_lock_bh(&arm_state->susp_res_lock);
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 24c331c94354..c7d2cf1f2e68 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
@@ -67,7 +67,7 @@ int vchiq_platform_init(struct platform_device *pdev,
extern struct vchiq_state *
vchiq_get_state(void);
-extern enum vchiq_status
+extern void
vchiq_arm_init_state(struct vchiq_state *state,
struct vchiq_arm_state *arm_state);
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 3023fa9fdc64..0ee96d1d0481 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
@@ -52,6 +52,7 @@ void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback)
}
mutex_unlock(&g_connected_mutex);
}
+EXPORT_SYMBOL(vchiq_add_connected_callback);
/*
* This function is called by the vchiq stack once it has been connected to
@@ -73,4 +74,3 @@ void vchiq_call_connected_callbacks(void)
g_connected = 1;
mutex_unlock(&g_connected_mutex);
}
-EXPORT_SYMBOL(vchiq_add_connected_callback);
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h
index ec5d2b716e7a..95c18670e839 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h
@@ -4,16 +4,8 @@
#ifndef VCHIQ_CONNECTED_H
#define VCHIQ_CONNECTED_H
-/* ---- Include Files ----------------------------------------------------- */
-
-/* ---- Constants and Types ---------------------------------------------- */
-
typedef void (*VCHIQ_CONNECTED_CALLBACK_T)(void);
-/* ---- Variable Externs ------------------------------------------------- */
-
-/* ---- Function Prototypes ---------------------------------------------- */
-
void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback);
void vchiq_call_connected_callbacks(void);
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 517a8c9b41ed..4f43e4213bfe 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
@@ -17,6 +17,75 @@
#define VCHIQ_SLOT_HANDLER_STACK 8192
+#define VCHIQ_MSG_PADDING 0 /* - */
+#define VCHIQ_MSG_CONNECT 1 /* - */
+#define VCHIQ_MSG_OPEN 2 /* + (srcport, -), fourcc, client_id */
+#define VCHIQ_MSG_OPENACK 3 /* + (srcport, dstport) */
+#define VCHIQ_MSG_CLOSE 4 /* + (srcport, dstport) */
+#define VCHIQ_MSG_DATA 5 /* + (srcport, dstport) */
+#define VCHIQ_MSG_BULK_RX 6 /* + (srcport, dstport), data, size */
+#define VCHIQ_MSG_BULK_TX 7 /* + (srcport, dstport), data, size */
+#define VCHIQ_MSG_BULK_RX_DONE 8 /* + (srcport, dstport), actual */
+#define VCHIQ_MSG_BULK_TX_DONE 9 /* + (srcport, dstport), actual */
+#define VCHIQ_MSG_PAUSE 10 /* - */
+#define VCHIQ_MSG_RESUME 11 /* - */
+#define VCHIQ_MSG_REMOTE_USE 12 /* - */
+#define VCHIQ_MSG_REMOTE_RELEASE 13 /* - */
+#define VCHIQ_MSG_REMOTE_USE_ACTIVE 14 /* - */
+
+#define TYPE_SHIFT 24
+
+#define VCHIQ_PORT_MAX (VCHIQ_MAX_SERVICES - 1)
+#define VCHIQ_PORT_FREE 0x1000
+#define VCHIQ_PORT_IS_VALID(port) ((port) < VCHIQ_PORT_FREE)
+#define VCHIQ_MAKE_MSG(type, srcport, dstport) \
+ (((type) << TYPE_SHIFT) | ((srcport) << 12) | ((dstport) << 0))
+#define VCHIQ_MSG_TYPE(msgid) ((unsigned int)(msgid) >> TYPE_SHIFT)
+#define VCHIQ_MSG_SRCPORT(msgid) \
+ (unsigned short)(((unsigned int)(msgid) >> 12) & 0xfff)
+#define VCHIQ_MSG_DSTPORT(msgid) \
+ ((unsigned short)(msgid) & 0xfff)
+
+#define MAKE_CONNECT (VCHIQ_MSG_CONNECT << TYPE_SHIFT)
+#define MAKE_OPEN(srcport) \
+ ((VCHIQ_MSG_OPEN << TYPE_SHIFT) | ((srcport) << 12))
+#define MAKE_OPENACK(srcport, dstport) \
+ ((VCHIQ_MSG_OPENACK << TYPE_SHIFT) | ((srcport) << 12) | ((dstport) << 0))
+#define MAKE_CLOSE(srcport, dstport) \
+ ((VCHIQ_MSG_CLOSE << TYPE_SHIFT) | ((srcport) << 12) | ((dstport) << 0))
+#define MAKE_DATA(srcport, dstport) \
+ ((VCHIQ_MSG_DATA << TYPE_SHIFT) | ((srcport) << 12) | ((dstport) << 0))
+#define MAKE_PAUSE (VCHIQ_MSG_PAUSE << TYPE_SHIFT)
+#define MAKE_RESUME (VCHIQ_MSG_RESUME << TYPE_SHIFT)
+#define MAKE_REMOTE_USE (VCHIQ_MSG_REMOTE_USE << TYPE_SHIFT)
+#define MAKE_REMOTE_USE_ACTIVE (VCHIQ_MSG_REMOTE_USE_ACTIVE << TYPE_SHIFT)
+
+/* Ensure the fields are wide enough */
+static_assert(VCHIQ_MSG_SRCPORT(VCHIQ_MAKE_MSG(0, 0, VCHIQ_PORT_MAX))
+ == 0);
+static_assert(VCHIQ_MSG_TYPE(VCHIQ_MAKE_MSG(0, VCHIQ_PORT_MAX, 0)) == 0);
+static_assert((unsigned int)VCHIQ_PORT_MAX <
+ (unsigned int)VCHIQ_PORT_FREE);
+
+#define VCHIQ_MSGID_PADDING VCHIQ_MAKE_MSG(VCHIQ_MSG_PADDING, 0, 0)
+#define VCHIQ_MSGID_CLAIMED 0x40000000
+
+#define VCHIQ_FOURCC_INVALID 0x00000000
+#define VCHIQ_FOURCC_IS_LEGAL(fourcc) ((fourcc) != VCHIQ_FOURCC_INVALID)
+
+#define VCHIQ_BULK_ACTUAL_ABORTED -1
+
+#if VCHIQ_ENABLE_STATS
+#define VCHIQ_STATS_INC(state, stat) (state->stats. stat++)
+#define VCHIQ_SERVICE_STATS_INC(service, stat) (service->stats. stat++)
+#define VCHIQ_SERVICE_STATS_ADD(service, stat, addend) \
+ (service->stats. stat += addend)
+#else
+#define VCHIQ_STATS_INC(state, stat) ((void)0)
+#define VCHIQ_SERVICE_STATS_INC(service, stat) ((void)0)
+#define VCHIQ_SERVICE_STATS_ADD(service, stat, addend) ((void)0)
+#endif
+
#define HANDLE_STATE_SHIFT 12
#define SLOT_INFO_FROM_INDEX(state, index) (state->slot_info + (index))
@@ -31,13 +100,19 @@
#define SLOT_QUEUE_INDEX_FROM_POS_MASKED(pos) \
(SLOT_QUEUE_INDEX_FROM_POS(pos) & VCHIQ_SLOT_QUEUE_MASK)
-#define BULK_INDEX(x) (x & (VCHIQ_NUM_SERVICE_BULKS - 1))
+#define BULK_INDEX(x) ((x) & (VCHIQ_NUM_SERVICE_BULKS - 1))
#define SRVTRACE_LEVEL(srv) \
(((srv) && (srv)->trace) ? VCHIQ_LOG_TRACE : vchiq_core_msg_log_level)
#define SRVTRACE_ENABLED(srv, lev) \
(((srv) && (srv)->trace) || (vchiq_core_msg_log_level >= (lev)))
+#define NO_CLOSE_RECVD 0
+#define CLOSE_RECVD 1
+
+#define NO_RETRY_POLL 0
+#define RETRY_POLL 1
+
struct vchiq_open_payload {
int fourcc;
int client_id;
@@ -55,13 +130,28 @@ enum {
QMFLAGS_NO_MUTEX_UNLOCK = BIT(2)
};
+enum {
+ VCHIQ_POLL_TERMINATE,
+ VCHIQ_POLL_REMOVE,
+ VCHIQ_POLL_TXNOTIFY,
+ VCHIQ_POLL_RXNOTIFY,
+ VCHIQ_POLL_COUNT
+};
+
/* we require this for consistency between endpoints */
-vchiq_static_assert(sizeof(struct vchiq_header) == 8);
-vchiq_static_assert(IS_POW2(sizeof(struct vchiq_header)));
-vchiq_static_assert(IS_POW2(VCHIQ_NUM_CURRENT_BULKS));
-vchiq_static_assert(IS_POW2(VCHIQ_NUM_SERVICE_BULKS));
-vchiq_static_assert(IS_POW2(VCHIQ_MAX_SERVICES));
-vchiq_static_assert(VCHIQ_VERSION >= VCHIQ_VERSION_MIN);
+static_assert(sizeof(struct vchiq_header) == 8);
+static_assert(VCHIQ_VERSION >= VCHIQ_VERSION_MIN);
+
+static inline void check_sizes(void)
+{
+ BUILD_BUG_ON_NOT_POWER_OF_2(VCHIQ_SLOT_SIZE);
+ BUILD_BUG_ON_NOT_POWER_OF_2(VCHIQ_MAX_SLOTS);
+ BUILD_BUG_ON_NOT_POWER_OF_2(VCHIQ_MAX_SLOTS_PER_SIDE);
+ BUILD_BUG_ON_NOT_POWER_OF_2(sizeof(struct vchiq_header));
+ BUILD_BUG_ON_NOT_POWER_OF_2(VCHIQ_NUM_CURRENT_BULKS);
+ BUILD_BUG_ON_NOT_POWER_OF_2(VCHIQ_NUM_SERVICE_BULKS);
+ BUILD_BUG_ON_NOT_POWER_OF_2(VCHIQ_MAX_SERVICES);
+}
/* Run time control of log level, based on KERN_XXX level. */
int vchiq_core_log_level = VCHIQ_LOG_DEFAULT;
@@ -243,7 +333,8 @@ __next_service_by_instance(struct vchiq_state *state,
while (idx < state->unused_service) {
struct vchiq_service *srv;
- srv = rcu_dereference(state->services[idx++]);
+ srv = rcu_dereference(state->services[idx]);
+ idx++;
if (srv && srv->srvstate != VCHIQ_SRVSTATE_FREE &&
srv->instance == instance) {
service = srv;
@@ -277,7 +368,7 @@ next_service_by_instance(struct vchiq_state *state,
}
void
-lock_service(struct vchiq_service *service)
+vchiq_service_get(struct vchiq_service *service)
{
if (!service) {
WARN(1, "%s service is NULL\n", __func__);
@@ -300,7 +391,7 @@ static void service_release(struct kref *kref)
}
void
-unlock_service(struct vchiq_service *service)
+vchiq_service_put(struct vchiq_service *service)
{
if (!service) {
WARN(1, "%s: service is NULL\n", __func__);
@@ -626,6 +717,68 @@ reserve_space(struct vchiq_state *state, size_t space, int is_blocking)
(tx_pos & VCHIQ_SLOT_MASK));
}
+static void
+process_free_data_message(struct vchiq_state *state, BITSET_T *service_found,
+ struct vchiq_header *header)
+{
+ int msgid = header->msgid;
+ int port = VCHIQ_MSG_SRCPORT(msgid);
+ struct vchiq_service_quota *quota = &state->service_quotas[port];
+ int count;
+
+ spin_lock(&quota_spinlock);
+ count = quota->message_use_count;
+ if (count > 0)
+ quota->message_use_count = count - 1;
+ spin_unlock(&quota_spinlock);
+
+ if (count == quota->message_quota) {
+ /*
+ * Signal the service that it
+ * has dropped below its quota
+ */
+ complete(&quota->quota_event);
+ } else if (count == 0) {
+ vchiq_log_error(vchiq_core_log_level,
+ "service %d message_use_count=%d (header %pK, msgid %x, header->msgid %x, header->size %x)",
+ port,
+ quota->message_use_count,
+ header, msgid, header->msgid,
+ header->size);
+ WARN(1, "invalid message use count\n");
+ }
+ if (!BITSET_IS_SET(service_found, port)) {
+ /* Set the found bit for this service */
+ BITSET_SET(service_found, port);
+
+ spin_lock(&quota_spinlock);
+ count = quota->slot_use_count;
+ if (count > 0)
+ quota->slot_use_count = count - 1;
+ spin_unlock(&quota_spinlock);
+
+ if (count > 0) {
+ /*
+ * Signal the service in case
+ * it has dropped below its quota
+ */
+ complete(&quota->quota_event);
+ vchiq_log_trace(vchiq_core_log_level,
+ "%d: pfq:%d %x@%pK - slot_use->%d",
+ state->id, port,
+ header->size, header,
+ count - 1);
+ } else {
+ vchiq_log_error(vchiq_core_log_level,
+ "service %d slot_use_count=%d (header %pK, msgid %x, header->msgid %x, header->size %x)",
+ port, count, header,
+ msgid, header->msgid,
+ header->size);
+ WARN(1, "bad slot use count\n");
+ }
+ }
+}
+
/* Called by the recycle thread. */
static void
process_free_queue(struct vchiq_state *state, BITSET_T *service_found,
@@ -649,11 +802,12 @@ process_free_queue(struct vchiq_state *state, BITSET_T *service_found,
while (slot_queue_available != local->slot_queue_recycle) {
unsigned int pos;
- int slot_index = local->slot_queue[slot_queue_available++ &
+ int slot_index = local->slot_queue[slot_queue_available &
VCHIQ_SLOT_QUEUE_MASK];
char *data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
int data_found = 0;
+ slot_queue_available++;
/*
* Beware of the address dependency - data is calculated
* using an index written by the other side.
@@ -675,67 +829,8 @@ process_free_queue(struct vchiq_state *state, BITSET_T *service_found,
int msgid = header->msgid;
if (VCHIQ_MSG_TYPE(msgid) == VCHIQ_MSG_DATA) {
- int port = VCHIQ_MSG_SRCPORT(msgid);
- struct vchiq_service_quota *quota =
- &state->service_quotas[port];
- int count;
-
- spin_lock(&quota_spinlock);
- count = quota->message_use_count;
- if (count > 0)
- quota->message_use_count =
- count - 1;
- spin_unlock(&quota_spinlock);
-
- if (count == quota->message_quota)
- /*
- * Signal the service that it
- * has dropped below its quota
- */
- complete(&quota->quota_event);
- else if (count == 0) {
- vchiq_log_error(vchiq_core_log_level,
- "service %d message_use_count=%d (header %pK, msgid %x, header->msgid %x, header->size %x)",
- port,
- quota->message_use_count,
- header, msgid, header->msgid,
- header->size);
- WARN(1, "invalid message use count\n");
- }
- if (!BITSET_IS_SET(service_found, port)) {
- /* Set the found bit for this service */
- BITSET_SET(service_found, port);
-
- spin_lock(&quota_spinlock);
- count = quota->slot_use_count;
- if (count > 0)
- quota->slot_use_count =
- count - 1;
- spin_unlock(&quota_spinlock);
-
- if (count > 0) {
- /*
- * Signal the service in case
- * it has dropped below its quota
- */
- complete(&quota->quota_event);
- vchiq_log_trace(
- vchiq_core_log_level,
- "%d: pfq:%d %x@%pK - slot_use->%d",
- state->id, port,
- header->size, header,
- count - 1);
- } else {
- vchiq_log_error(
- vchiq_core_log_level,
- "service %d slot_use_count=%d (header %pK, msgid %x, header->msgid %x, header->size %x)",
- port, count, header,
- msgid, header->msgid,
- header->size);
- WARN(1, "bad slot use count\n");
- }
- }
-
+ process_free_data_message(state, service_found,
+ header);
data_found = 1;
}
@@ -755,8 +850,7 @@ process_free_queue(struct vchiq_state *state, BITSET_T *service_found,
spin_lock(&quota_spinlock);
count = state->data_use_count;
if (count > 0)
- state->data_use_count =
- count - 1;
+ state->data_use_count = count - 1;
spin_unlock(&quota_spinlock);
if (count == state->data_quota)
complete(&state->data_quota_event);
@@ -834,7 +928,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
stride = calc_stride(size);
- WARN_ON(!(stride <= VCHIQ_SLOT_SIZE));
+ WARN_ON(stride > VCHIQ_SLOT_SIZE);
if (!(flags & QMFLAGS_NO_MUTEX_LOCK) &&
mutex_lock_killable(&state->slot_mutex))
@@ -897,8 +991,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
while ((quota->message_use_count == quota->message_quota) ||
((tx_end_index != quota->previous_tx_index) &&
- (quota->slot_use_count ==
- quota->slot_quota))) {
+ (quota->slot_use_count == quota->slot_quota))) {
spin_unlock(&quota_spinlock);
vchiq_log_trace(vchiq_core_log_level,
"%d: qm:%d %s,%zx - quota stall (msg %d, slot %d)",
@@ -1175,8 +1268,6 @@ static void
release_slot(struct vchiq_state *state, struct vchiq_slot_info *slot_info,
struct vchiq_header *header, struct vchiq_service *service)
{
- int release_count;
-
mutex_lock(&state->recycle_mutex);
if (header) {
@@ -1192,10 +1283,9 @@ release_slot(struct vchiq_state *state, struct vchiq_slot_info *slot_info,
header->msgid = msgid & ~VCHIQ_MSGID_CLAIMED;
}
- release_count = slot_info->release_count;
- slot_info->release_count = ++release_count;
+ slot_info->release_count++;
- if (release_count == slot_info->use_count) {
+ if (slot_info->release_count == slot_info->use_count) {
int slot_queue_recycle;
/* Add to the freed queue */
@@ -1226,6 +1316,22 @@ release_slot(struct vchiq_state *state, struct vchiq_slot_info *slot_info,
mutex_unlock(&state->recycle_mutex);
}
+static inline enum vchiq_reason
+get_bulk_reason(struct vchiq_bulk *bulk)
+{
+ if (bulk->dir == VCHIQ_BULK_TRANSMIT) {
+ if (bulk->actual == VCHIQ_BULK_ACTUAL_ABORTED)
+ return VCHIQ_BULK_TRANSMIT_ABORTED;
+
+ return VCHIQ_BULK_TRANSMIT_DONE;
+ }
+
+ if (bulk->actual == VCHIQ_BULK_ACTUAL_ABORTED)
+ return VCHIQ_BULK_RECEIVE_ABORTED;
+
+ return VCHIQ_BULK_RECEIVE_DONE;
+}
+
/* Called by the slot handler - don't hold the bulk mutex */
static enum vchiq_status
notify_bulks(struct vchiq_service *service, struct vchiq_bulk_queue *queue,
@@ -1241,69 +1347,58 @@ notify_bulks(struct vchiq_service *service, struct vchiq_bulk_queue *queue,
queue->remote_notify = queue->process;
- if (status == VCHIQ_SUCCESS) {
- while (queue->remove != queue->remote_notify) {
- struct vchiq_bulk *bulk =
- &queue->bulks[BULK_INDEX(queue->remove)];
+ while (queue->remove != queue->remote_notify) {
+ struct vchiq_bulk *bulk =
+ &queue->bulks[BULK_INDEX(queue->remove)];
- /*
- * Only generate callbacks for non-dummy bulk
- * requests, and non-terminated services
- */
- if (bulk->data && service->instance) {
- if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED) {
- if (bulk->dir == VCHIQ_BULK_TRANSMIT) {
- VCHIQ_SERVICE_STATS_INC(service,
- bulk_tx_count);
- VCHIQ_SERVICE_STATS_ADD(service,
- bulk_tx_bytes,
- bulk->actual);
- } else {
- VCHIQ_SERVICE_STATS_INC(service,
- bulk_rx_count);
- VCHIQ_SERVICE_STATS_ADD(service,
- bulk_rx_bytes,
- bulk->actual);
- }
+ /*
+ * Only generate callbacks for non-dummy bulk
+ * requests, and non-terminated services
+ */
+ if (bulk->data && service->instance) {
+ if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED) {
+ if (bulk->dir == VCHIQ_BULK_TRANSMIT) {
+ VCHIQ_SERVICE_STATS_INC(service,
+ bulk_tx_count);
+ VCHIQ_SERVICE_STATS_ADD(service,
+ bulk_tx_bytes,
+ bulk->actual);
} else {
VCHIQ_SERVICE_STATS_INC(service,
- bulk_aborted_count);
+ bulk_rx_count);
+ VCHIQ_SERVICE_STATS_ADD(service,
+ bulk_rx_bytes,
+ bulk->actual);
}
- if (bulk->mode == VCHIQ_BULK_MODE_BLOCKING) {
- struct bulk_waiter *waiter;
-
- spin_lock(&bulk_waiter_spinlock);
- waiter = bulk->userdata;
- if (waiter) {
- waiter->actual = bulk->actual;
- complete(&waiter->event);
- }
- spin_unlock(&bulk_waiter_spinlock);
- } else if (bulk->mode ==
- VCHIQ_BULK_MODE_CALLBACK) {
- enum vchiq_reason reason = (bulk->dir ==
- VCHIQ_BULK_TRANSMIT) ?
- ((bulk->actual ==
- VCHIQ_BULK_ACTUAL_ABORTED) ?
- VCHIQ_BULK_TRANSMIT_ABORTED :
- VCHIQ_BULK_TRANSMIT_DONE) :
- ((bulk->actual ==
- VCHIQ_BULK_ACTUAL_ABORTED) ?
- VCHIQ_BULK_RECEIVE_ABORTED :
- VCHIQ_BULK_RECEIVE_DONE);
- status = make_service_callback(service,
- reason, NULL, bulk->userdata);
- if (status == VCHIQ_RETRY)
- break;
+ } else {
+ VCHIQ_SERVICE_STATS_INC(service,
+ bulk_aborted_count);
+ }
+ if (bulk->mode == VCHIQ_BULK_MODE_BLOCKING) {
+ struct bulk_waiter *waiter;
+
+ spin_lock(&bulk_waiter_spinlock);
+ waiter = bulk->userdata;
+ if (waiter) {
+ waiter->actual = bulk->actual;
+ complete(&waiter->event);
}
+ spin_unlock(&bulk_waiter_spinlock);
+ } else if (bulk->mode == VCHIQ_BULK_MODE_CALLBACK) {
+ enum vchiq_reason reason =
+ get_bulk_reason(bulk);
+ status = make_service_callback(service,
+ reason, NULL, bulk->userdata);
+ if (status == VCHIQ_RETRY)
+ break;
}
-
- queue->remove++;
- complete(&service->bulk_remove_event);
}
- if (!retry_poll)
- status = VCHIQ_SUCCESS;
+
+ queue->remove++;
+ complete(&service->bulk_remove_event);
}
+ if (!retry_poll)
+ status = VCHIQ_SUCCESS;
if (status == VCHIQ_RETRY)
request_poll(service->state, service,
@@ -1313,74 +1408,70 @@ notify_bulks(struct vchiq_service *service, struct vchiq_bulk_queue *queue,
return status;
}
-/* Called by the slot handler thread */
static void
-poll_services(struct vchiq_state *state)
+poll_services_of_group(struct vchiq_state *state, int group)
{
- int group, i;
-
- for (group = 0; group < BITSET_SIZE(state->unused_service); group++) {
- u32 flags;
-
- flags = atomic_xchg(&state->poll_services[group], 0);
- for (i = 0; flags; i++) {
- if (flags & BIT(i)) {
- struct vchiq_service *service =
- find_service_by_port(state,
- (group<<5) + i);
- u32 service_flags;
-
- flags &= ~BIT(i);
- if (!service)
- continue;
- service_flags =
- atomic_xchg(&service->poll_flags, 0);
- if (service_flags &
- BIT(VCHIQ_POLL_REMOVE)) {
- vchiq_log_info(vchiq_core_log_level,
- "%d: ps - remove %d<->%d",
- state->id, service->localport,
- service->remoteport);
-
- /*
- * Make it look like a client, because
- * it must be removed and not left in
- * the LISTENING state.
- */
- service->public_fourcc =
- VCHIQ_FOURCC_INVALID;
-
- if (vchiq_close_service_internal(
- service, 0/*!close_recvd*/) !=
- VCHIQ_SUCCESS)
- request_poll(state, service,
- VCHIQ_POLL_REMOVE);
- } else if (service_flags &
- BIT(VCHIQ_POLL_TERMINATE)) {
- vchiq_log_info(vchiq_core_log_level,
- "%d: ps - terminate %d<->%d",
- state->id, service->localport,
- service->remoteport);
- if (vchiq_close_service_internal(
- service, 0/*!close_recvd*/) !=
- VCHIQ_SUCCESS)
- request_poll(state, service,
- VCHIQ_POLL_TERMINATE);
- }
- if (service_flags & BIT(VCHIQ_POLL_TXNOTIFY))
- notify_bulks(service,
- &service->bulk_tx,
- 1/*retry_poll*/);
- if (service_flags & BIT(VCHIQ_POLL_RXNOTIFY))
- notify_bulks(service,
- &service->bulk_rx,
- 1/*retry_poll*/);
- unlock_service(service);
- }
+ u32 flags = atomic_xchg(&state->poll_services[group], 0);
+ int i;
+
+ for (i = 0; flags; i++) {
+ struct vchiq_service *service;
+ u32 service_flags;
+
+ if ((flags & BIT(i)) == 0)
+ continue;
+
+ service = find_service_by_port(state, (group << 5) + i);
+ flags &= ~BIT(i);
+
+ if (!service)
+ continue;
+
+ service_flags = atomic_xchg(&service->poll_flags, 0);
+ if (service_flags & BIT(VCHIQ_POLL_REMOVE)) {
+ vchiq_log_info(vchiq_core_log_level, "%d: ps - remove %d<->%d",
+ state->id, service->localport,
+ service->remoteport);
+
+ /*
+ * Make it look like a client, because
+ * it must be removed and not left in
+ * the LISTENING state.
+ */
+ service->public_fourcc = VCHIQ_FOURCC_INVALID;
+
+ if (vchiq_close_service_internal(service, NO_CLOSE_RECVD) !=
+ VCHIQ_SUCCESS)
+ request_poll(state, service, VCHIQ_POLL_REMOVE);
+ } else if (service_flags & BIT(VCHIQ_POLL_TERMINATE)) {
+ vchiq_log_info(vchiq_core_log_level,
+ "%d: ps - terminate %d<->%d",
+ state->id, service->localport,
+ service->remoteport);
+ if (vchiq_close_service_internal(
+ service, NO_CLOSE_RECVD) !=
+ VCHIQ_SUCCESS)
+ request_poll(state, service,
+ VCHIQ_POLL_TERMINATE);
}
+ if (service_flags & BIT(VCHIQ_POLL_TXNOTIFY))
+ notify_bulks(service, &service->bulk_tx, RETRY_POLL);
+ if (service_flags & BIT(VCHIQ_POLL_RXNOTIFY))
+ notify_bulks(service, &service->bulk_rx, RETRY_POLL);
+ vchiq_service_put(service);
}
}
+/* Called by the slot handler thread */
+static void
+poll_services(struct vchiq_state *state)
+{
+ int group;
+
+ for (group = 0; group < BITSET_SIZE(state->unused_service); group++)
+ poll_services_of_group(state, group);
+}
+
/* Called with the bulk_mutex held */
static void
abort_outstanding_bulks(struct vchiq_service *service,
@@ -1393,8 +1484,8 @@ abort_outstanding_bulks(struct vchiq_service *service,
service->state->id, service->localport, is_tx ? 't' : 'r',
queue->local_insert, queue->remote_insert, queue->process);
- WARN_ON(!((int)(queue->local_insert - queue->process) >= 0));
- WARN_ON(!((int)(queue->remote_insert - queue->process) >= 0));
+ WARN_ON((int)(queue->local_insert - queue->process) < 0);
+ WARN_ON((int)(queue->remote_insert - queue->process) < 0);
while ((queue->process != queue->local_insert) ||
(queue->process != queue->remote_insert)) {
@@ -1435,103 +1526,92 @@ abort_outstanding_bulks(struct vchiq_service *service,
static int
parse_open(struct vchiq_state *state, struct vchiq_header *header)
{
+ const struct vchiq_open_payload *payload;
struct vchiq_service *service = NULL;
int msgid, size;
- unsigned int localport, remoteport;
+ unsigned int localport, remoteport, fourcc;
+ short version, version_min;
msgid = header->msgid;
size = header->size;
localport = VCHIQ_MSG_DSTPORT(msgid);
remoteport = VCHIQ_MSG_SRCPORT(msgid);
- if (size >= sizeof(struct vchiq_open_payload)) {
- const struct vchiq_open_payload *payload =
- (struct vchiq_open_payload *)header->data;
- unsigned int fourcc;
-
- fourcc = payload->fourcc;
- vchiq_log_info(vchiq_core_log_level,
- "%d: prs OPEN@%pK (%d->'%c%c%c%c')",
- state->id, header, localport,
- VCHIQ_FOURCC_AS_4CHARS(fourcc));
-
- service = get_listening_service(state, fourcc);
+ if (size < sizeof(struct vchiq_open_payload))
+ goto fail_open;
- if (service) {
- /* A matching service exists */
- short version = payload->version;
- short version_min = payload->version_min;
-
- if ((service->version < version_min) ||
- (version < service->version_min)) {
- /* Version mismatch */
- vchiq_loud_error_header();
- vchiq_loud_error("%d: service %d (%c%c%c%c) "
- "version mismatch - local (%d, min %d)"
- " vs. remote (%d, min %d)",
- state->id, service->localport,
- VCHIQ_FOURCC_AS_4CHARS(fourcc),
- service->version, service->version_min,
- version, version_min);
- vchiq_loud_error_footer();
- unlock_service(service);
- service = NULL;
- goto fail_open;
- }
- service->peer_version = version;
+ payload = (struct vchiq_open_payload *)header->data;
+ fourcc = payload->fourcc;
+ vchiq_log_info(vchiq_core_log_level,
+ "%d: prs OPEN@%pK (%d->'%c%c%c%c')",
+ state->id, header, localport,
+ VCHIQ_FOURCC_AS_4CHARS(fourcc));
- if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) {
- struct vchiq_openack_payload ack_payload = {
- service->version
- };
-
- if (state->version_common <
- VCHIQ_VERSION_SYNCHRONOUS_MODE)
- service->sync = 0;
-
- /* Acknowledge the OPEN */
- if (service->sync) {
- if (queue_message_sync(
- state,
- NULL,
- VCHIQ_MAKE_MSG(
- VCHIQ_MSG_OPENACK,
- service->localport,
- remoteport),
- memcpy_copy_callback,
- &ack_payload,
- sizeof(ack_payload),
- 0) == VCHIQ_RETRY)
- goto bail_not_ready;
- } else {
- if (queue_message(state,
- NULL,
- VCHIQ_MAKE_MSG(
- VCHIQ_MSG_OPENACK,
- service->localport,
- remoteport),
- memcpy_copy_callback,
- &ack_payload,
- sizeof(ack_payload),
- 0) == VCHIQ_RETRY)
- goto bail_not_ready;
- }
+ service = get_listening_service(state, fourcc);
+ if (!service)
+ goto fail_open;
- /* The service is now open */
- vchiq_set_service_state(service,
- service->sync ? VCHIQ_SRVSTATE_OPENSYNC
- : VCHIQ_SRVSTATE_OPEN);
- }
+ /* A matching service exists */
+ version = payload->version;
+ version_min = payload->version_min;
- /* Success - the message has been dealt with */
- unlock_service(service);
- return 1;
+ if ((service->version < version_min) ||
+ (version < service->version_min)) {
+ /* Version mismatch */
+ vchiq_loud_error_header();
+ vchiq_loud_error("%d: service %d (%c%c%c%c) "
+ "version mismatch - local (%d, min %d)"
+ " vs. remote (%d, min %d)",
+ state->id, service->localport,
+ VCHIQ_FOURCC_AS_4CHARS(fourcc),
+ service->version, service->version_min,
+ version, version_min);
+ vchiq_loud_error_footer();
+ vchiq_service_put(service);
+ service = NULL;
+ goto fail_open;
+ }
+ service->peer_version = version;
+
+ if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) {
+ struct vchiq_openack_payload ack_payload = {
+ service->version
+ };
+ int openack_id = MAKE_OPENACK(service->localport, remoteport);
+
+ if (state->version_common <
+ VCHIQ_VERSION_SYNCHRONOUS_MODE)
+ service->sync = 0;
+
+ /* Acknowledge the OPEN */
+ if (service->sync) {
+ if (queue_message_sync(state, NULL, openack_id,
+ memcpy_copy_callback,
+ &ack_payload,
+ sizeof(ack_payload),
+ 0) == VCHIQ_RETRY)
+ goto bail_not_ready;
+ } else {
+ if (queue_message(state, NULL, openack_id,
+ memcpy_copy_callback,
+ &ack_payload,
+ sizeof(ack_payload),
+ 0) == VCHIQ_RETRY)
+ goto bail_not_ready;
}
+
+ /* The service is now open */
+ vchiq_set_service_state(service,
+ service->sync ? VCHIQ_SRVSTATE_OPENSYNC
+ : VCHIQ_SRVSTATE_OPEN);
}
+ /* Success - the message has been dealt with */
+ vchiq_service_put(service);
+ return 1;
+
fail_open:
/* No available service, or an invalid request - send a CLOSE */
- if (queue_message(state, NULL,
- VCHIQ_MAKE_MSG(VCHIQ_MSG_CLOSE, 0, VCHIQ_MSG_SRCPORT(msgid)),
+ if (queue_message(state, NULL, MAKE_CLOSE(0, VCHIQ_MSG_SRCPORT(msgid)),
NULL, NULL, 0, 0) == VCHIQ_RETRY)
goto bail_not_ready;
@@ -1539,339 +1619,364 @@ fail_open:
bail_not_ready:
if (service)
- unlock_service(service);
+ vchiq_service_put(service);
return 0;
}
-/* Called by the slot handler thread */
-static void
-parse_rx_slots(struct vchiq_state *state)
+/**
+ * parse_message() - parses a single message from the rx slot
+ * @state: vchiq state struct
+ * @header: message header
+ *
+ * Context: Process context
+ *
+ * Return:
+ * * >= 0 - size of the parsed message payload (without header)
+ * * -EINVAL - fatal error occurred, bail out is required
+ */
+static int
+parse_message(struct vchiq_state *state, struct vchiq_header *header)
{
- struct vchiq_shared_state *remote = state->remote;
struct vchiq_service *service = NULL;
- int tx_pos;
+ unsigned int localport, remoteport;
+ int msgid, size, type, ret = -EINVAL;
DEBUG_INITIALISE(state->local)
- tx_pos = remote->tx_pos;
-
- while (state->rx_pos != tx_pos) {
- struct vchiq_header *header;
- int msgid, size;
- int type;
- unsigned int localport, remoteport;
-
- DEBUG_TRACE(PARSE_LINE);
- if (!state->rx_data) {
- int rx_index;
-
- WARN_ON(!((state->rx_pos & VCHIQ_SLOT_MASK) == 0));
- rx_index = remote->slot_queue[
- SLOT_QUEUE_INDEX_FROM_POS_MASKED(state->rx_pos)];
- state->rx_data = (char *)SLOT_DATA_FROM_INDEX(state,
- rx_index);
- state->rx_info = SLOT_INFO_FROM_INDEX(state, rx_index);
+ DEBUG_VALUE(PARSE_HEADER, (int)(long)header);
+ msgid = header->msgid;
+ DEBUG_VALUE(PARSE_MSGID, msgid);
+ size = header->size;
+ type = VCHIQ_MSG_TYPE(msgid);
+ localport = VCHIQ_MSG_DSTPORT(msgid);
+ remoteport = VCHIQ_MSG_SRCPORT(msgid);
+ if (type != VCHIQ_MSG_DATA)
+ VCHIQ_STATS_INC(state, ctrl_rx_count);
+
+ switch (type) {
+ case VCHIQ_MSG_OPENACK:
+ case VCHIQ_MSG_CLOSE:
+ case VCHIQ_MSG_DATA:
+ case VCHIQ_MSG_BULK_RX:
+ case VCHIQ_MSG_BULK_TX:
+ case VCHIQ_MSG_BULK_RX_DONE:
+ case VCHIQ_MSG_BULK_TX_DONE:
+ service = find_service_by_port(state, localport);
+ if ((!service ||
+ ((service->remoteport != remoteport) &&
+ (service->remoteport != VCHIQ_PORT_FREE))) &&
+ (localport == 0) &&
+ (type == VCHIQ_MSG_CLOSE)) {
/*
- * Initialise use_count to one, and increment
- * release_count at the end of the slot to avoid
- * releasing the slot prematurely.
+ * This could be a CLOSE from a client which
+ * hadn't yet received the OPENACK - look for
+ * the connected service
*/
- state->rx_info->use_count = 1;
- state->rx_info->release_count = 0;
+ if (service)
+ vchiq_service_put(service);
+ service = get_connected_service(state,
+ remoteport);
+ if (service)
+ vchiq_log_warning(vchiq_core_log_level,
+ "%d: prs %s@%pK (%d->%d) - found connected service %d",
+ state->id, msg_type_str(type),
+ header, remoteport, localport,
+ service->localport);
}
- header = (struct vchiq_header *)(state->rx_data +
- (state->rx_pos & VCHIQ_SLOT_MASK));
- DEBUG_VALUE(PARSE_HEADER, (int)(long)header);
- msgid = header->msgid;
- DEBUG_VALUE(PARSE_MSGID, msgid);
- size = header->size;
- type = VCHIQ_MSG_TYPE(msgid);
- localport = VCHIQ_MSG_DSTPORT(msgid);
- remoteport = VCHIQ_MSG_SRCPORT(msgid);
-
- if (type != VCHIQ_MSG_DATA)
- VCHIQ_STATS_INC(state, ctrl_rx_count);
+ if (!service) {
+ vchiq_log_error(vchiq_core_log_level,
+ "%d: prs %s@%pK (%d->%d) - invalid/closed service %d",
+ state->id, msg_type_str(type),
+ header, remoteport, localport,
+ localport);
+ goto skip_message;
+ }
+ break;
+ default:
+ break;
+ }
- switch (type) {
- case VCHIQ_MSG_OPENACK:
- case VCHIQ_MSG_CLOSE:
- case VCHIQ_MSG_DATA:
- case VCHIQ_MSG_BULK_RX:
- case VCHIQ_MSG_BULK_TX:
- case VCHIQ_MSG_BULK_RX_DONE:
- case VCHIQ_MSG_BULK_TX_DONE:
- service = find_service_by_port(state, localport);
- if ((!service ||
- ((service->remoteport != remoteport) &&
- (service->remoteport != VCHIQ_PORT_FREE))) &&
- (localport == 0) &&
- (type == VCHIQ_MSG_CLOSE)) {
- /*
- * This could be a CLOSE from a client which
- * hadn't yet received the OPENACK - look for
- * the connected service
- */
- if (service)
- unlock_service(service);
- service = get_connected_service(state,
- remoteport);
- if (service)
- vchiq_log_warning(vchiq_core_log_level,
- "%d: prs %s@%pK (%d->%d) - found connected service %d",
- state->id, msg_type_str(type),
- header, remoteport, localport,
- service->localport);
- }
+ if (SRVTRACE_ENABLED(service, VCHIQ_LOG_INFO)) {
+ int svc_fourcc;
- if (!service) {
- vchiq_log_error(vchiq_core_log_level,
- "%d: prs %s@%pK (%d->%d) - invalid/closed service %d",
- state->id, msg_type_str(type),
- header, remoteport, localport,
- localport);
- goto skip_message;
- }
- break;
- default:
- break;
- }
+ svc_fourcc = service
+ ? service->base.fourcc
+ : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
+ vchiq_log_info(SRVTRACE_LEVEL(service),
+ "Rcvd Msg %s(%u) from %c%c%c%c s:%d d:%d len:%d",
+ msg_type_str(type), type,
+ VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
+ remoteport, localport, size);
+ if (size > 0)
+ vchiq_log_dump_mem("Rcvd", 0, header->data,
+ min(16, size));
+ }
- if (SRVTRACE_ENABLED(service, VCHIQ_LOG_INFO)) {
- int svc_fourcc;
+ if (((unsigned long)header & VCHIQ_SLOT_MASK) +
+ calc_stride(size) > VCHIQ_SLOT_SIZE) {
+ vchiq_log_error(vchiq_core_log_level,
+ "header %pK (msgid %x) - size %x too big for slot",
+ header, (unsigned int)msgid,
+ (unsigned int)size);
+ WARN(1, "oversized for slot\n");
+ }
- svc_fourcc = service
- ? service->base.fourcc
- : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
- vchiq_log_info(SRVTRACE_LEVEL(service),
- "Rcvd Msg %s(%u) from %c%c%c%c s:%d d:%d len:%d",
- msg_type_str(type), type,
- VCHIQ_FOURCC_AS_4CHARS(svc_fourcc),
- remoteport, localport, size);
- if (size > 0)
- vchiq_log_dump_mem("Rcvd", 0, header->data,
- min(16, size));
+ switch (type) {
+ case VCHIQ_MSG_OPEN:
+ WARN_ON(VCHIQ_MSG_DSTPORT(msgid));
+ if (!parse_open(state, header))
+ goto bail_not_ready;
+ break;
+ case VCHIQ_MSG_OPENACK:
+ if (size >= sizeof(struct vchiq_openack_payload)) {
+ const struct vchiq_openack_payload *payload =
+ (struct vchiq_openack_payload *)
+ header->data;
+ service->peer_version = payload->version;
}
-
- if (((unsigned long)header & VCHIQ_SLOT_MASK) +
- calc_stride(size) > VCHIQ_SLOT_SIZE) {
+ vchiq_log_info(vchiq_core_log_level,
+ "%d: prs OPENACK@%pK,%x (%d->%d) v:%d",
+ state->id, header, size, remoteport, localport,
+ service->peer_version);
+ if (service->srvstate == VCHIQ_SRVSTATE_OPENING) {
+ service->remoteport = remoteport;
+ vchiq_set_service_state(service,
+ VCHIQ_SRVSTATE_OPEN);
+ complete(&service->remove_event);
+ } else {
vchiq_log_error(vchiq_core_log_level,
- "header %pK (msgid %x) - size %x too big for slot",
- header, (unsigned int)msgid,
- (unsigned int)size);
- WARN(1, "oversized for slot\n");
+ "OPENACK received in state %s",
+ srvstate_names[service->srvstate]);
}
+ break;
+ case VCHIQ_MSG_CLOSE:
+ WARN_ON(size); /* There should be no data */
- switch (type) {
- case VCHIQ_MSG_OPEN:
- WARN_ON(!(VCHIQ_MSG_DSTPORT(msgid) == 0));
- if (!parse_open(state, header))
- goto bail_not_ready;
- break;
- case VCHIQ_MSG_OPENACK:
- if (size >= sizeof(struct vchiq_openack_payload)) {
- const struct vchiq_openack_payload *payload =
- (struct vchiq_openack_payload *)
- header->data;
- service->peer_version = payload->version;
- }
- vchiq_log_info(vchiq_core_log_level,
- "%d: prs OPENACK@%pK,%x (%d->%d) v:%d",
- state->id, header, size, remoteport, localport,
- service->peer_version);
- if (service->srvstate == VCHIQ_SRVSTATE_OPENING) {
- service->remoteport = remoteport;
- vchiq_set_service_state(service,
- VCHIQ_SRVSTATE_OPEN);
- complete(&service->remove_event);
- } else
- vchiq_log_error(vchiq_core_log_level,
- "OPENACK received in state %s",
- srvstate_names[service->srvstate]);
- break;
- case VCHIQ_MSG_CLOSE:
- WARN_ON(size != 0); /* There should be no data */
-
- vchiq_log_info(vchiq_core_log_level,
- "%d: prs CLOSE@%pK (%d->%d)",
- state->id, header, remoteport, localport);
+ vchiq_log_info(vchiq_core_log_level,
+ "%d: prs CLOSE@%pK (%d->%d)",
+ state->id, header, remoteport, localport);
- mark_service_closing_internal(service, 1);
+ mark_service_closing_internal(service, 1);
- if (vchiq_close_service_internal(service,
- 1/*close_recvd*/) == VCHIQ_RETRY)
- goto bail_not_ready;
+ if (vchiq_close_service_internal(service,
+ CLOSE_RECVD) == VCHIQ_RETRY)
+ goto bail_not_ready;
- vchiq_log_info(vchiq_core_log_level,
- "Close Service %c%c%c%c s:%u d:%d",
- VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
- service->localport,
- service->remoteport);
- break;
- case VCHIQ_MSG_DATA:
- vchiq_log_info(vchiq_core_log_level,
- "%d: prs DATA@%pK,%x (%d->%d)",
- state->id, header, size, remoteport, localport);
-
- if ((service->remoteport == remoteport) &&
- (service->srvstate == VCHIQ_SRVSTATE_OPEN)) {
- header->msgid = msgid | VCHIQ_MSGID_CLAIMED;
- claim_slot(state->rx_info);
+ vchiq_log_info(vchiq_core_log_level,
+ "Close Service %c%c%c%c s:%u d:%d",
+ VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
+ service->localport,
+ service->remoteport);
+ break;
+ case VCHIQ_MSG_DATA:
+ vchiq_log_info(vchiq_core_log_level,
+ "%d: prs DATA@%pK,%x (%d->%d)",
+ state->id, header, size, remoteport, localport);
+
+ if ((service->remoteport == remoteport) &&
+ (service->srvstate == VCHIQ_SRVSTATE_OPEN)) {
+ header->msgid = msgid | VCHIQ_MSGID_CLAIMED;
+ claim_slot(state->rx_info);
+ DEBUG_TRACE(PARSE_LINE);
+ if (make_service_callback(service,
+ VCHIQ_MESSAGE_AVAILABLE, header,
+ NULL) == VCHIQ_RETRY) {
DEBUG_TRACE(PARSE_LINE);
- if (make_service_callback(service,
- VCHIQ_MESSAGE_AVAILABLE, header,
- NULL) == VCHIQ_RETRY) {
- DEBUG_TRACE(PARSE_LINE);
- goto bail_not_ready;
- }
- VCHIQ_SERVICE_STATS_INC(service, ctrl_rx_count);
- VCHIQ_SERVICE_STATS_ADD(service, ctrl_rx_bytes,
- size);
- } else {
- VCHIQ_STATS_INC(state, error_count);
+ goto bail_not_ready;
}
- break;
- case VCHIQ_MSG_CONNECT:
- vchiq_log_info(vchiq_core_log_level,
- "%d: prs CONNECT@%pK", state->id, header);
- state->version_common = ((struct vchiq_slot_zero *)
- state->slot_data)->version;
- complete(&state->connect);
- break;
- case VCHIQ_MSG_BULK_RX:
- case VCHIQ_MSG_BULK_TX:
- /*
- * We should never receive a bulk request from the
- * other side since we're not setup to perform as the
- * master.
- */
- WARN_ON(1);
- break;
- case VCHIQ_MSG_BULK_RX_DONE:
- case VCHIQ_MSG_BULK_TX_DONE:
- if ((service->remoteport == remoteport) &&
- (service->srvstate != VCHIQ_SRVSTATE_FREE)) {
- struct vchiq_bulk_queue *queue;
- struct vchiq_bulk *bulk;
+ VCHIQ_SERVICE_STATS_INC(service, ctrl_rx_count);
+ VCHIQ_SERVICE_STATS_ADD(service, ctrl_rx_bytes,
+ size);
+ } else {
+ VCHIQ_STATS_INC(state, error_count);
+ }
+ break;
+ case VCHIQ_MSG_CONNECT:
+ vchiq_log_info(vchiq_core_log_level,
+ "%d: prs CONNECT@%pK", state->id, header);
+ state->version_common = ((struct vchiq_slot_zero *)
+ state->slot_data)->version;
+ complete(&state->connect);
+ break;
+ case VCHIQ_MSG_BULK_RX:
+ case VCHIQ_MSG_BULK_TX:
+ /*
+ * We should never receive a bulk request from the
+ * other side since we're not setup to perform as the
+ * master.
+ */
+ WARN_ON(1);
+ break;
+ case VCHIQ_MSG_BULK_RX_DONE:
+ case VCHIQ_MSG_BULK_TX_DONE:
+ if ((service->remoteport == remoteport) &&
+ (service->srvstate != VCHIQ_SRVSTATE_FREE)) {
+ struct vchiq_bulk_queue *queue;
+ struct vchiq_bulk *bulk;
- queue = (type == VCHIQ_MSG_BULK_RX_DONE) ?
- &service->bulk_rx : &service->bulk_tx;
+ queue = (type == VCHIQ_MSG_BULK_RX_DONE) ?
+ &service->bulk_rx : &service->bulk_tx;
+ DEBUG_TRACE(PARSE_LINE);
+ if (mutex_lock_killable(&service->bulk_mutex)) {
DEBUG_TRACE(PARSE_LINE);
- if (mutex_lock_killable(&service->bulk_mutex)) {
- DEBUG_TRACE(PARSE_LINE);
- goto bail_not_ready;
- }
- if ((int)(queue->remote_insert -
- queue->local_insert) >= 0) {
- vchiq_log_error(vchiq_core_log_level,
- "%d: prs %s@%pK (%d->%d) unexpected (ri=%d,li=%d)",
- state->id, msg_type_str(type),
- header, remoteport, localport,
- queue->remote_insert,
- queue->local_insert);
- mutex_unlock(&service->bulk_mutex);
- break;
- }
- if (queue->process != queue->remote_insert) {
- pr_err("%s: p %x != ri %x\n",
- __func__,
- queue->process,
- queue->remote_insert);
- mutex_unlock(&service->bulk_mutex);
- goto bail_not_ready;
- }
-
- bulk = &queue->bulks[
- BULK_INDEX(queue->remote_insert)];
- bulk->actual = *(int *)header->data;
- queue->remote_insert++;
-
- vchiq_log_info(vchiq_core_log_level,
- "%d: prs %s@%pK (%d->%d) %x@%pad",
+ goto bail_not_ready;
+ }
+ if ((int)(queue->remote_insert -
+ queue->local_insert) >= 0) {
+ vchiq_log_error(vchiq_core_log_level,
+ "%d: prs %s@%pK (%d->%d) unexpected (ri=%d,li=%d)",
state->id, msg_type_str(type),
header, remoteport, localport,
- bulk->actual, &bulk->data);
-
- vchiq_log_trace(vchiq_core_log_level,
- "%d: prs:%d %cx li=%x ri=%x p=%x",
- state->id, localport,
- (type == VCHIQ_MSG_BULK_RX_DONE) ?
- 'r' : 't',
- queue->local_insert,
- queue->remote_insert, queue->process);
-
- DEBUG_TRACE(PARSE_LINE);
- WARN_ON(queue->process == queue->local_insert);
- vchiq_complete_bulk(bulk);
- queue->process++;
+ queue->remote_insert,
+ queue->local_insert);
mutex_unlock(&service->bulk_mutex);
- DEBUG_TRACE(PARSE_LINE);
- notify_bulks(service, queue, 1/*retry_poll*/);
- DEBUG_TRACE(PARSE_LINE);
- }
- break;
- case VCHIQ_MSG_PADDING:
- vchiq_log_trace(vchiq_core_log_level,
- "%d: prs PADDING@%pK,%x",
- state->id, header, size);
- break;
- case VCHIQ_MSG_PAUSE:
- /* If initiated, signal the application thread */
- vchiq_log_trace(vchiq_core_log_level,
- "%d: prs PAUSE@%pK,%x",
- state->id, header, size);
- if (state->conn_state == VCHIQ_CONNSTATE_PAUSED) {
- vchiq_log_error(vchiq_core_log_level,
- "%d: PAUSE received in state PAUSED",
- state->id);
break;
}
- if (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT) {
- /* Send a PAUSE in response */
- if (queue_message(state, NULL,
- VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0),
- NULL, NULL, 0, QMFLAGS_NO_MUTEX_UNLOCK)
- == VCHIQ_RETRY)
- goto bail_not_ready;
+ if (queue->process != queue->remote_insert) {
+ pr_err("%s: p %x != ri %x\n",
+ __func__,
+ queue->process,
+ queue->remote_insert);
+ mutex_unlock(&service->bulk_mutex);
+ goto bail_not_ready;
}
- /* At this point slot_mutex is held */
- vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSED);
- break;
- case VCHIQ_MSG_RESUME:
- vchiq_log_trace(vchiq_core_log_level,
- "%d: prs RESUME@%pK,%x",
- state->id, header, size);
- /* Release the slot mutex */
- mutex_unlock(&state->slot_mutex);
- vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
- break;
- case VCHIQ_MSG_REMOTE_USE:
- vchiq_on_remote_use(state);
- break;
- case VCHIQ_MSG_REMOTE_RELEASE:
- vchiq_on_remote_release(state);
- break;
- case VCHIQ_MSG_REMOTE_USE_ACTIVE:
- break;
+ bulk = &queue->bulks[
+ BULK_INDEX(queue->remote_insert)];
+ bulk->actual = *(int *)header->data;
+ queue->remote_insert++;
- default:
+ vchiq_log_info(vchiq_core_log_level,
+ "%d: prs %s@%pK (%d->%d) %x@%pad",
+ state->id, msg_type_str(type),
+ header, remoteport, localport,
+ bulk->actual, &bulk->data);
+
+ vchiq_log_trace(vchiq_core_log_level,
+ "%d: prs:%d %cx li=%x ri=%x p=%x",
+ state->id, localport,
+ (type == VCHIQ_MSG_BULK_RX_DONE) ?
+ 'r' : 't',
+ queue->local_insert,
+ queue->remote_insert, queue->process);
+
+ DEBUG_TRACE(PARSE_LINE);
+ WARN_ON(queue->process == queue->local_insert);
+ vchiq_complete_bulk(bulk);
+ queue->process++;
+ mutex_unlock(&service->bulk_mutex);
+ DEBUG_TRACE(PARSE_LINE);
+ notify_bulks(service, queue, RETRY_POLL);
+ DEBUG_TRACE(PARSE_LINE);
+ }
+ break;
+ case VCHIQ_MSG_PADDING:
+ vchiq_log_trace(vchiq_core_log_level,
+ "%d: prs PADDING@%pK,%x",
+ state->id, header, size);
+ break;
+ case VCHIQ_MSG_PAUSE:
+ /* If initiated, signal the application thread */
+ vchiq_log_trace(vchiq_core_log_level,
+ "%d: prs PAUSE@%pK,%x",
+ state->id, header, size);
+ if (state->conn_state == VCHIQ_CONNSTATE_PAUSED) {
vchiq_log_error(vchiq_core_log_level,
- "%d: prs invalid msgid %x@%pK,%x",
- state->id, msgid, header, size);
- WARN(1, "invalid message\n");
+ "%d: PAUSE received in state PAUSED",
+ state->id);
break;
}
+ if (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT) {
+ /* Send a PAUSE in response */
+ if (queue_message(state, NULL, MAKE_PAUSE,
+ NULL, NULL, 0, QMFLAGS_NO_MUTEX_UNLOCK)
+ == VCHIQ_RETRY)
+ goto bail_not_ready;
+ }
+ /* At this point slot_mutex is held */
+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSED);
+ break;
+ case VCHIQ_MSG_RESUME:
+ vchiq_log_trace(vchiq_core_log_level,
+ "%d: prs RESUME@%pK,%x",
+ state->id, header, size);
+ /* Release the slot mutex */
+ mutex_unlock(&state->slot_mutex);
+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
+ break;
+
+ case VCHIQ_MSG_REMOTE_USE:
+ vchiq_on_remote_use(state);
+ break;
+ case VCHIQ_MSG_REMOTE_RELEASE:
+ vchiq_on_remote_release(state);
+ break;
+ case VCHIQ_MSG_REMOTE_USE_ACTIVE:
+ break;
+
+ default:
+ vchiq_log_error(vchiq_core_log_level,
+ "%d: prs invalid msgid %x@%pK,%x",
+ state->id, msgid, header, size);
+ WARN(1, "invalid message\n");
+ break;
+ }
skip_message:
- if (service) {
- unlock_service(service);
- service = NULL;
+ ret = size;
+
+bail_not_ready:
+ if (service)
+ vchiq_service_put(service);
+
+ return ret;
+}
+
+/* Called by the slot handler thread */
+static void
+parse_rx_slots(struct vchiq_state *state)
+{
+ struct vchiq_shared_state *remote = state->remote;
+ int tx_pos;
+
+ DEBUG_INITIALISE(state->local)
+
+ tx_pos = remote->tx_pos;
+
+ while (state->rx_pos != tx_pos) {
+ struct vchiq_header *header;
+ int size;
+
+ DEBUG_TRACE(PARSE_LINE);
+ if (!state->rx_data) {
+ int rx_index;
+
+ WARN_ON(state->rx_pos & VCHIQ_SLOT_MASK);
+ rx_index = remote->slot_queue[
+ SLOT_QUEUE_INDEX_FROM_POS_MASKED(state->rx_pos)];
+ state->rx_data = (char *)SLOT_DATA_FROM_INDEX(state,
+ rx_index);
+ state->rx_info = SLOT_INFO_FROM_INDEX(state, rx_index);
+
+ /*
+ * Initialise use_count to one, and increment
+ * release_count at the end of the slot to avoid
+ * releasing the slot prematurely.
+ */
+ state->rx_info->use_count = 1;
+ state->rx_info->release_count = 0;
}
+ header = (struct vchiq_header *)(state->rx_data +
+ (state->rx_pos & VCHIQ_SLOT_MASK));
+ size = parse_message(state, header);
+ if (size < 0)
+ return;
+
state->rx_pos += calc_stride(size);
DEBUG_TRACE(PARSE_LINE);
@@ -1885,10 +1990,56 @@ skip_message:
state->rx_data = NULL;
}
}
+}
-bail_not_ready:
- if (service)
- unlock_service(service);
+/**
+ * handle_poll() - handle service polling and other rare conditions
+ * @state: vchiq state struct
+ *
+ * Context: Process context
+ *
+ * Return:
+ * * 0 - poll handled successful
+ * * -EAGAIN - retry later
+ */
+static int
+handle_poll(struct vchiq_state *state)
+{
+ switch (state->conn_state) {
+ case VCHIQ_CONNSTATE_CONNECTED:
+ /* Poll the services as requested */
+ poll_services(state);
+ break;
+
+ case VCHIQ_CONNSTATE_PAUSING:
+ if (queue_message(state, NULL, MAKE_PAUSE, NULL, NULL, 0,
+ QMFLAGS_NO_MUTEX_UNLOCK) != VCHIQ_RETRY) {
+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSE_SENT);
+ } else {
+ /* Retry later */
+ return -EAGAIN;
+ }
+ break;
+
+ case VCHIQ_CONNSTATE_RESUMING:
+ if (queue_message(state, NULL, MAKE_RESUME, NULL, NULL, 0,
+ QMFLAGS_NO_MUTEX_LOCK) != VCHIQ_RETRY) {
+ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
+ } else {
+ /*
+ * This should really be impossible,
+ * since the PAUSE should have flushed
+ * through outstanding messages.
+ */
+ vchiq_log_error(vchiq_core_log_level,
+ "Failed to send RESUME message");
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
}
/* Called by the slot handler thread */
@@ -1909,54 +2060,14 @@ slot_handler_func(void *v)
DEBUG_TRACE(SLOT_HANDLER_LINE);
if (state->poll_needed) {
-
state->poll_needed = 0;
/*
* Handle service polling and other rare conditions here
* out of the mainline code
*/
- switch (state->conn_state) {
- case VCHIQ_CONNSTATE_CONNECTED:
- /* Poll the services as requested */
- poll_services(state);
- break;
-
- case VCHIQ_CONNSTATE_PAUSING:
- if (queue_message(state, NULL,
- VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0),
- NULL, NULL, 0,
- QMFLAGS_NO_MUTEX_UNLOCK)
- != VCHIQ_RETRY) {
- vchiq_set_conn_state(state,
- VCHIQ_CONNSTATE_PAUSE_SENT);
- } else {
- /* Retry later */
- state->poll_needed = 1;
- }
- break;
-
- case VCHIQ_CONNSTATE_RESUMING:
- if (queue_message(state, NULL,
- VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0),
- NULL, NULL, 0, QMFLAGS_NO_MUTEX_LOCK)
- != VCHIQ_RETRY) {
- vchiq_set_conn_state(state,
- VCHIQ_CONNSTATE_CONNECTED);
- } else {
- /*
- * This should really be impossible,
- * since the PAUSE should have flushed
- * through outstanding messages.
- */
- vchiq_log_error(vchiq_core_log_level,
- "Failed to send RESUME message");
- }
- break;
- default:
- break;
- }
-
+ if (handle_poll(state) == -EAGAIN)
+ state->poll_needed = 1;
}
DEBUG_TRACE(SLOT_HANDLER_LINE);
@@ -2070,8 +2181,7 @@ sync_func(void *v)
state->id, header, size, remoteport, localport);
if ((service->remoteport == remoteport) &&
- (service->srvstate ==
- VCHIQ_SRVSTATE_OPENSYNC)) {
+ (service->srvstate == VCHIQ_SRVSTATE_OPENSYNC)) {
if (make_service_callback(service,
VCHIQ_MESSAGE_AVAILABLE, header,
NULL) == VCHIQ_RETRY)
@@ -2089,7 +2199,7 @@ sync_func(void *v)
break;
}
- unlock_service(service);
+ vchiq_service_put(service);
}
return 0;
@@ -2118,9 +2228,11 @@ vchiq_init_slots(void *mem_base, int mem_size)
(int)((VCHIQ_SLOT_SIZE - (long)mem_base) & VCHIQ_SLOT_MASK);
struct vchiq_slot_zero *slot_zero =
(struct vchiq_slot_zero *)(mem_base + mem_align);
- int num_slots = (mem_size - mem_align)/VCHIQ_SLOT_SIZE;
+ int num_slots = (mem_size - mem_align) / VCHIQ_SLOT_SIZE;
int first_data_slot = VCHIQ_SLOT_ZERO_SLOTS;
+ check_sizes();
+
/* Ensure there is enough memory to run an absolutely minimum system */
num_slots -= first_data_slot;
@@ -2143,26 +2255,25 @@ vchiq_init_slots(void *mem_base, int mem_size)
slot_zero->master.slot_sync = first_data_slot;
slot_zero->master.slot_first = first_data_slot + 1;
- slot_zero->master.slot_last = first_data_slot + (num_slots/2) - 1;
- slot_zero->slave.slot_sync = first_data_slot + (num_slots/2);
- slot_zero->slave.slot_first = first_data_slot + (num_slots/2) + 1;
+ slot_zero->master.slot_last = first_data_slot + (num_slots / 2) - 1;
+ slot_zero->slave.slot_sync = first_data_slot + (num_slots / 2);
+ slot_zero->slave.slot_first = first_data_slot + (num_slots / 2) + 1;
slot_zero->slave.slot_last = first_data_slot + num_slots - 1;
return slot_zero;
}
-enum vchiq_status
+int
vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero)
{
struct vchiq_shared_state *local;
struct vchiq_shared_state *remote;
- enum vchiq_status status;
char threadname[16];
- int i;
+ int i, ret;
if (vchiq_states[0]) {
pr_err("%s: VCHIQ state already initialized\n", __func__);
- return VCHIQ_ERROR;
+ return -EINVAL;
}
local = &slot_zero->slave;
@@ -2175,7 +2286,7 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero)
else
vchiq_loud_error("master/slave mismatch two slaves");
vchiq_loud_error_footer();
- return VCHIQ_ERROR;
+ return -EINVAL;
}
memset(state, 0, sizeof(struct vchiq_state));
@@ -2206,17 +2317,17 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero)
state->slot_queue_available = 0;
for (i = 0; i < VCHIQ_MAX_SERVICES; i++) {
- struct vchiq_service_quota *quota =
- &state->service_quotas[i];
+ struct vchiq_service_quota *quota = &state->service_quotas[i];
init_completion(&quota->quota_event);
}
for (i = local->slot_first; i <= local->slot_last; i++) {
- local->slot_queue[state->slot_queue_available++] = i;
+ local->slot_queue[state->slot_queue_available] = i;
+ state->slot_queue_available++;
complete(&state->slot_available_event);
}
- state->default_slot_quota = state->slot_queue_available/2;
+ state->default_slot_quota = state->slot_queue_available / 2;
state->default_message_quota =
min((unsigned short)(state->default_slot_quota * 256),
(unsigned short)~0);
@@ -2240,9 +2351,9 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero)
local->debug[DEBUG_ENTRIES] = DEBUG_MAX;
- status = vchiq_platform_init_state(state);
- if (status != VCHIQ_SUCCESS)
- return VCHIQ_ERROR;
+ ret = vchiq_platform_init_state(state);
+ if (ret)
+ return ret;
/*
* bring up slot handler thread
@@ -2256,7 +2367,7 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero)
vchiq_loud_error_header();
vchiq_loud_error("couldn't create thread %s", threadname);
vchiq_loud_error_footer();
- return VCHIQ_ERROR;
+ return PTR_ERR(state->slot_handler_thread);
}
set_user_nice(state->slot_handler_thread, -19);
@@ -2268,6 +2379,7 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero)
vchiq_loud_error_header();
vchiq_loud_error("couldn't create thread %s", threadname);
vchiq_loud_error_footer();
+ ret = PTR_ERR(state->recycle_thread);
goto fail_free_handler_thread;
}
set_user_nice(state->recycle_thread, -19);
@@ -2280,6 +2392,7 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero)
vchiq_loud_error_header();
vchiq_loud_error("couldn't create thread %s", threadname);
vchiq_loud_error_footer();
+ ret = PTR_ERR(state->sync_thread);
goto fail_free_recycle_thread;
}
set_user_nice(state->sync_thread, -20);
@@ -2293,14 +2406,14 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero)
/* Indicate readiness to the other side */
local->initialised = 1;
- return status;
+ return 0;
fail_free_recycle_thread:
kthread_stop(state->recycle_thread);
fail_free_handler_thread:
kthread_stop(state->slot_handler_thread);
- return VCHIQ_ERROR;
+ return ret;
}
void vchiq_msg_queue_push(unsigned int handle, struct vchiq_header *header)
@@ -2314,7 +2427,8 @@ void vchiq_msg_queue_push(unsigned int handle, struct vchiq_header *header)
flush_signals(current);
}
- pos = service->msg_queue_write++ & (VCHIQ_MAX_SLOTS - 1);
+ pos = service->msg_queue_write & (VCHIQ_MAX_SLOTS - 1);
+ service->msg_queue_write++;
service->msg_queue[pos] = header;
complete(&service->msg_queue_push);
@@ -2335,7 +2449,8 @@ struct vchiq_header *vchiq_msg_hold(unsigned int handle)
flush_signals(current);
}
- pos = service->msg_queue_read++ & (VCHIQ_MAX_SLOTS - 1);
+ pos = service->msg_queue_read & (VCHIQ_MAX_SLOTS - 1);
+ service->msg_queue_read++;
header = service->msg_queue[pos];
complete(&service->msg_queue_pop);
@@ -2440,11 +2555,11 @@ vchiq_add_service_internal(struct vchiq_state *state,
struct vchiq_service *srv;
srv = rcu_dereference(state->services[i]);
- if (!srv)
+ if (!srv) {
pservice = &state->services[i];
- else if ((srv->public_fourcc == params->fourcc) &&
- ((srv->instance != instance) ||
- (srv->base.callback != params->callback))) {
+ } else if ((srv->public_fourcc == params->fourcc) &&
+ ((srv->instance != instance) ||
+ (srv->base.callback != params->callback))) {
/*
* There is another server using this
* fourcc which doesn't match.
@@ -2514,10 +2629,7 @@ vchiq_open_service_internal(struct vchiq_service *service, int client_id)
service->client_id = client_id;
vchiq_use_service_internal(service);
status = queue_message(service->state,
- NULL,
- VCHIQ_MAKE_MSG(VCHIQ_MSG_OPEN,
- service->localport,
- 0),
+ NULL, MAKE_OPEN(service->localport),
memcpy_copy_callback,
&payload,
sizeof(payload),
@@ -2568,42 +2680,43 @@ release_service_messages(struct vchiq_service *service)
for (i = state->remote->slot_first; i <= slot_last; i++) {
struct vchiq_slot_info *slot_info =
SLOT_INFO_FROM_INDEX(state, i);
- if (slot_info->release_count != slot_info->use_count) {
- char *data =
- (char *)SLOT_DATA_FROM_INDEX(state, i);
- unsigned int pos, end;
+ unsigned int pos, end;
+ char *data;
- end = VCHIQ_SLOT_SIZE;
- if (data == state->rx_data)
- /*
- * This buffer is still being read from - stop
- * at the current read position
- */
- end = state->rx_pos & VCHIQ_SLOT_MASK;
-
- pos = 0;
-
- while (pos < end) {
- struct vchiq_header *header =
- (struct vchiq_header *)(data + pos);
- int msgid = header->msgid;
- int port = VCHIQ_MSG_DSTPORT(msgid);
-
- if ((port == service->localport) &&
- (msgid & VCHIQ_MSGID_CLAIMED)) {
- vchiq_log_info(vchiq_core_log_level,
- " fsi - hdr %pK", header);
- release_slot(state, slot_info, header,
- NULL);
- }
- pos += calc_stride(header->size);
- if (pos > VCHIQ_SLOT_SIZE) {
- vchiq_log_error(vchiq_core_log_level,
- "fsi - pos %x: header %pK, msgid %x, header->msgid %x, header->size %x",
- pos, header, msgid,
- header->msgid, header->size);
- WARN(1, "invalid slot position\n");
- }
+ if (slot_info->release_count == slot_info->use_count)
+ continue;
+
+ data = (char *)SLOT_DATA_FROM_INDEX(state, i);
+ end = VCHIQ_SLOT_SIZE;
+ if (data == state->rx_data)
+ /*
+ * This buffer is still being read from - stop
+ * at the current read position
+ */
+ end = state->rx_pos & VCHIQ_SLOT_MASK;
+
+ pos = 0;
+
+ while (pos < end) {
+ struct vchiq_header *header =
+ (struct vchiq_header *)(data + pos);
+ int msgid = header->msgid;
+ int port = VCHIQ_MSG_DSTPORT(msgid);
+
+ if ((port == service->localport) &&
+ (msgid & VCHIQ_MSGID_CLAIMED)) {
+ vchiq_log_info(vchiq_core_log_level,
+ " fsi - hdr %pK", header);
+ release_slot(state, slot_info, header,
+ NULL);
+ }
+ pos += calc_stride(header->size);
+ if (pos > VCHIQ_SLOT_SIZE) {
+ vchiq_log_error(vchiq_core_log_level,
+ "fsi - pos %x: header %pK, msgid %x, header->msgid %x, header->size %x",
+ pos, header, msgid,
+ header->msgid, header->size);
+ WARN(1, "invalid slot position\n");
}
}
}
@@ -2621,10 +2734,11 @@ do_abort_bulks(struct vchiq_service *service)
abort_outstanding_bulks(service, &service->bulk_rx);
mutex_unlock(&service->bulk_mutex);
- status = notify_bulks(service, &service->bulk_tx, 0/*!retry_poll*/);
- if (status == VCHIQ_SUCCESS)
- status = notify_bulks(service, &service->bulk_rx,
- 0/*!retry_poll*/);
+ status = notify_bulks(service, &service->bulk_tx, NO_RETRY_POLL);
+ if (status != VCHIQ_SUCCESS)
+ return 0;
+
+ status = notify_bulks(service, &service->bulk_rx, NO_RETRY_POLL);
return (status == VCHIQ_SUCCESS);
}
@@ -2644,10 +2758,12 @@ close_service_complete(struct vchiq_service *service, int failstate)
service->client_id = 0;
service->remoteport = VCHIQ_PORT_FREE;
newstate = VCHIQ_SRVSTATE_LISTENING;
- } else
+ } else {
newstate = VCHIQ_SRVSTATE_CLOSEWAIT;
- } else
+ }
+ } else {
newstate = VCHIQ_SRVSTATE_CLOSED;
+ }
vchiq_set_service_state(service, newstate);
break;
case VCHIQ_SRVSTATE_LISTENING:
@@ -2677,16 +2793,17 @@ close_service_complete(struct vchiq_service *service, int failstate)
service->client_id = 0;
service->remoteport = VCHIQ_PORT_FREE;
- if (service->srvstate == VCHIQ_SRVSTATE_CLOSED)
+ if (service->srvstate == VCHIQ_SRVSTATE_CLOSED) {
vchiq_free_service_internal(service);
- else if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) {
+ } else if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) {
if (is_server)
service->closing = 0;
complete(&service->remove_event);
}
- } else
+ } else {
vchiq_set_service_state(service, failstate);
+ }
return status;
}
@@ -2698,6 +2815,8 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
struct vchiq_state *state = service->state;
enum vchiq_status status = VCHIQ_SUCCESS;
int is_server = (service->public_fourcc != VCHIQ_FOURCC_INVALID);
+ int close_id = MAKE_CLOSE(service->localport,
+ VCHIQ_MSG_DSTPORT(service->remoteport));
vchiq_log_info(vchiq_core_log_level, "%d: csi:%d,%d (%s)",
service->state->id, service->localport, close_recvd,
@@ -2708,11 +2827,11 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
case VCHIQ_SRVSTATE_HIDDEN:
case VCHIQ_SRVSTATE_LISTENING:
case VCHIQ_SRVSTATE_CLOSEWAIT:
- if (close_recvd)
+ if (close_recvd) {
vchiq_log_error(vchiq_core_log_level,
"%s(1) called in state %s",
__func__, srvstate_names[service->srvstate]);
- else if (is_server) {
+ } else if (is_server) {
if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) {
status = VCHIQ_ERROR;
} else {
@@ -2724,8 +2843,9 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
VCHIQ_SRVSTATE_LISTENING);
}
complete(&service->remove_event);
- } else
+ } else {
vchiq_free_service_internal(service);
+ }
break;
case VCHIQ_SRVSTATE_OPENING:
if (close_recvd) {
@@ -2735,11 +2855,7 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
complete(&service->remove_event);
} else {
/* Shutdown mid-open - let the other side know */
- status = queue_message(state, service,
- VCHIQ_MAKE_MSG
- (VCHIQ_MSG_CLOSE,
- service->localport,
- VCHIQ_MSG_DSTPORT(service->remoteport)),
+ status = queue_message(state, service, close_id,
NULL, NULL, 0, 0);
}
break;
@@ -2756,28 +2872,24 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
release_service_messages(service);
if (status == VCHIQ_SUCCESS)
- status = queue_message(state, service,
- VCHIQ_MAKE_MSG
- (VCHIQ_MSG_CLOSE,
- service->localport,
- VCHIQ_MSG_DSTPORT(service->remoteport)),
+ status = queue_message(state, service, close_id,
NULL, NULL, 0, QMFLAGS_NO_MUTEX_UNLOCK);
- if (status == VCHIQ_SUCCESS) {
- if (!close_recvd) {
- /* Change the state while the mutex is still held */
- vchiq_set_service_state(service,
- VCHIQ_SRVSTATE_CLOSESENT);
- mutex_unlock(&state->slot_mutex);
- if (service->sync)
- mutex_unlock(&state->sync_mutex);
- break;
- }
- } else if (service->srvstate == VCHIQ_SRVSTATE_OPENSYNC) {
- mutex_unlock(&state->sync_mutex);
+ if (status != VCHIQ_SUCCESS) {
+ if (service->srvstate == VCHIQ_SRVSTATE_OPENSYNC)
+ mutex_unlock(&state->sync_mutex);
break;
- } else
+ }
+
+ if (!close_recvd) {
+ /* Change the state while the mutex is still held */
+ vchiq_set_service_state(service,
+ VCHIQ_SRVSTATE_CLOSESENT);
+ mutex_unlock(&state->slot_mutex);
+ if (service->sync)
+ mutex_unlock(&state->sync_mutex);
break;
+ }
/* Change the state while the mutex is still held */
vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSERECVD);
@@ -2867,7 +2979,7 @@ vchiq_free_service_internal(struct vchiq_service *service)
complete(&service->remove_event);
/* Release the initial lock */
- unlock_service(service);
+ vchiq_service_put(service);
}
enum vchiq_status
@@ -2883,12 +2995,11 @@ vchiq_connect_internal(struct vchiq_state *state, struct vchiq_instance *instanc
if (service->srvstate == VCHIQ_SRVSTATE_HIDDEN)
vchiq_set_service_state(service,
VCHIQ_SRVSTATE_LISTENING);
- unlock_service(service);
+ vchiq_service_put(service);
}
if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) {
- if (queue_message(state, NULL,
- VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, NULL,
+ if (queue_message(state, NULL, MAKE_CONNECT, NULL, NULL,
0, QMFLAGS_IS_BLOCKING) == VCHIQ_RETRY)
return VCHIQ_RETRY;
@@ -2906,21 +3017,19 @@ vchiq_connect_internal(struct vchiq_state *state, struct vchiq_instance *instanc
return VCHIQ_SUCCESS;
}
-enum vchiq_status
+void
vchiq_shutdown_internal(struct vchiq_state *state, struct vchiq_instance *instance)
{
struct vchiq_service *service;
int i;
- /* Find all services registered to this client and enable them. */
+ /* Find all services registered to this client and remove them. */
i = 0;
while ((service = next_service_by_instance(state, instance,
&i)) != NULL) {
(void)vchiq_remove_service(service->handle);
- unlock_service(service);
+ vchiq_service_put(service);
}
-
- return VCHIQ_SUCCESS;
}
enum vchiq_status
@@ -2940,15 +3049,14 @@ vchiq_close_service(unsigned int handle)
if ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
(service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
(service->srvstate == VCHIQ_SRVSTATE_HIDDEN)) {
- unlock_service(service);
+ vchiq_service_put(service);
return VCHIQ_ERROR;
}
mark_service_closing(service);
if (current == service->state->slot_handler_thread) {
- status = vchiq_close_service_internal(service,
- 0/*!close_recvd*/);
+ status = vchiq_close_service_internal(service, NO_CLOSE_RECVD);
WARN_ON(status == VCHIQ_RETRY);
} else {
/* Mark the service for termination by the slot handler */
@@ -2977,7 +3085,7 @@ vchiq_close_service(unsigned int handle)
(service->srvstate != VCHIQ_SRVSTATE_LISTENING))
status = VCHIQ_ERROR;
- unlock_service(service);
+ vchiq_service_put(service);
return status;
}
@@ -2998,7 +3106,7 @@ vchiq_remove_service(unsigned int handle)
service->state->id, service->localport);
if (service->srvstate == VCHIQ_SRVSTATE_FREE) {
- unlock_service(service);
+ vchiq_service_put(service);
return VCHIQ_ERROR;
}
@@ -3012,8 +3120,7 @@ vchiq_remove_service(unsigned int handle)
*/
service->public_fourcc = VCHIQ_FOURCC_INVALID;
- status = vchiq_close_service_internal(service,
- 0/*!close_recvd*/);
+ status = vchiq_close_service_internal(service, NO_CLOSE_RECVD);
WARN_ON(status == VCHIQ_RETRY);
} else {
/* Mark the service for removal by the slot handler */
@@ -3039,7 +3146,7 @@ vchiq_remove_service(unsigned int handle)
(service->srvstate != VCHIQ_SRVSTATE_FREE))
status = VCHIQ_ERROR;
- unlock_service(service);
+ vchiq_service_put(service);
return status;
}
@@ -3134,8 +3241,7 @@ enum vchiq_status vchiq_bulk_transfer(unsigned int handle,
bulk->size = size;
bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
- if (vchiq_prepare_bulk_data(bulk, offset, uoffset, size, dir)
- != VCHIQ_SUCCESS)
+ if (vchiq_prepare_bulk_data(bulk, offset, uoffset, size, dir))
goto unlock_error_exit;
wmb();
@@ -3185,7 +3291,7 @@ enum vchiq_status vchiq_bulk_transfer(unsigned int handle,
queue->local_insert, queue->remote_insert, queue->process);
waiting:
- unlock_service(service);
+ vchiq_service_put(service);
status = VCHIQ_SUCCESS;
@@ -3208,7 +3314,7 @@ unlock_error_exit:
error_exit:
if (service)
- unlock_service(service);
+ vchiq_service_put(service);
return status;
}
@@ -3221,6 +3327,7 @@ vchiq_queue_message(unsigned int handle,
{
struct vchiq_service *service = find_service_by_handle(handle);
enum vchiq_status status = VCHIQ_ERROR;
+ int data_id;
if (!service)
goto error_exit;
@@ -3239,19 +3346,15 @@ vchiq_queue_message(unsigned int handle,
goto error_exit;
}
+ data_id = MAKE_DATA(service->localport, service->remoteport);
+
switch (service->srvstate) {
case VCHIQ_SRVSTATE_OPEN:
- status = queue_message(service->state, service,
- VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA,
- service->localport,
- service->remoteport),
+ status = queue_message(service->state, service, data_id,
copy_callback, context, size, 1);
break;
case VCHIQ_SRVSTATE_OPENSYNC:
- status = queue_message_sync(service->state, service,
- VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA,
- service->localport,
- service->remoteport),
+ status = queue_message_sync(service->state, service, data_id,
copy_callback, context, size, 1);
break;
default:
@@ -3261,7 +3364,7 @@ vchiq_queue_message(unsigned int handle,
error_exit:
if (service)
- unlock_service(service);
+ vchiq_service_put(service);
return status;
}
@@ -3316,10 +3419,11 @@ vchiq_release_message(unsigned int handle,
release_slot(state, slot_info, header, service);
}
- } else if (slot_index == remote->slot_sync)
+ } else if (slot_index == remote->slot_sync) {
release_message_sync(state, header);
+ }
- unlock_service(service);
+ vchiq_service_put(service);
}
EXPORT_SYMBOL(vchiq_release_message);
@@ -3350,7 +3454,7 @@ vchiq_get_peer_version(unsigned int handle, short *peer_version)
exit:
if (service)
- unlock_service(service);
+ vchiq_service_put(service);
return status;
}
EXPORT_SYMBOL(vchiq_get_peer_version);
@@ -3365,21 +3469,21 @@ void vchiq_get_config(struct vchiq_config *config)
config->version_min = VCHIQ_VERSION_MIN;
}
-enum vchiq_status
+int
vchiq_set_service_option(unsigned int handle,
enum vchiq_service_option option, int value)
{
struct vchiq_service *service = find_service_by_handle(handle);
- enum vchiq_status status = VCHIQ_ERROR;
struct vchiq_service_quota *quota;
+ int ret = -EINVAL;
if (!service)
- return VCHIQ_ERROR;
+ return -EINVAL;
switch (option) {
case VCHIQ_SERVICE_OPTION_AUTOCLOSE:
service->auto_close = value;
- status = VCHIQ_SUCCESS;
+ ret = 0;
break;
case VCHIQ_SERVICE_OPTION_SLOT_QUOTA:
@@ -3396,7 +3500,7 @@ vchiq_set_service_option(unsigned int handle,
* dropped below its quota
*/
complete(&quota->quota_event);
- status = VCHIQ_SUCCESS;
+ ret = 0;
}
break;
@@ -3414,7 +3518,7 @@ vchiq_set_service_option(unsigned int handle,
* dropped below its quota
*/
complete(&quota->quota_event);
- status = VCHIQ_SUCCESS;
+ ret = 0;
}
break;
@@ -3422,21 +3526,21 @@ vchiq_set_service_option(unsigned int handle,
if ((service->srvstate == VCHIQ_SRVSTATE_HIDDEN) ||
(service->srvstate == VCHIQ_SRVSTATE_LISTENING)) {
service->sync = value;
- status = VCHIQ_SUCCESS;
+ ret = 0;
}
break;
case VCHIQ_SERVICE_OPTION_TRACE:
service->trace = value;
- status = VCHIQ_SUCCESS;
+ ret = 0;
break;
default:
break;
}
- unlock_service(service);
+ vchiq_service_put(service);
- return status;
+ return ret;
}
static int
@@ -3575,7 +3679,7 @@ int vchiq_dump_state(void *dump_context, struct vchiq_state *state)
if (service) {
err = vchiq_dump_service_state(dump_context, service);
- unlock_service(service);
+ vchiq_service_put(service);
if (err)
return err;
}
@@ -3611,8 +3715,9 @@ int vchiq_dump_service_state(void *dump_context, struct vchiq_service *service)
scnprintf(remoteport + len2,
sizeof(remoteport) - len2,
" (client %x)", service->client_id);
- } else
+ } else {
strcpy(remoteport, "n/a");
+ }
len += scnprintf(buf + len, sizeof(buf) - len,
" '%c%c%c%c' remote %s (msg use %d/%d, slot use %d/%d)",
@@ -3711,9 +3816,7 @@ enum vchiq_status vchiq_send_remote_use(struct vchiq_state *state)
if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED)
return VCHIQ_RETRY;
- return queue_message(state, NULL,
- VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE, 0, 0),
- NULL, NULL, 0, 0);
+ return queue_message(state, NULL, MAKE_REMOTE_USE, NULL, NULL, 0, 0);
}
enum vchiq_status vchiq_send_remote_use_active(struct vchiq_state *state)
@@ -3721,8 +3824,7 @@ enum vchiq_status vchiq_send_remote_use_active(struct vchiq_state *state)
if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED)
return VCHIQ_RETRY;
- return queue_message(state, NULL,
- VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE_ACTIVE, 0, 0),
+ return queue_message(state, NULL, MAKE_REMOTE_USE_ACTIVE,
NULL, NULL, 0, 0);
}
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 b817097651fa..957fea1f574f 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
@@ -64,74 +64,20 @@
#define vchiq_loud_error(...) \
vchiq_log_error(vchiq_core_log_level, "===== " __VA_ARGS__)
-#ifndef vchiq_static_assert
-#define vchiq_static_assert(cond) __attribute__((unused)) \
- extern int vchiq_static_assert[(cond) ? 1 : -1]
-#endif
-
-#define IS_POW2(x) (x && ((x & (x - 1)) == 0))
-
-/* Ensure that the slot size and maximum number of slots are powers of 2 */
-vchiq_static_assert(IS_POW2(VCHIQ_SLOT_SIZE));
-vchiq_static_assert(IS_POW2(VCHIQ_MAX_SLOTS));
-vchiq_static_assert(IS_POW2(VCHIQ_MAX_SLOTS_PER_SIDE));
-
#define VCHIQ_SLOT_MASK (VCHIQ_SLOT_SIZE - 1)
#define VCHIQ_SLOT_QUEUE_MASK (VCHIQ_MAX_SLOTS_PER_SIDE - 1)
#define VCHIQ_SLOT_ZERO_SLOTS DIV_ROUND_UP(sizeof(struct vchiq_slot_zero), \
VCHIQ_SLOT_SIZE)
-#define VCHIQ_MSG_PADDING 0 /* - */
-#define VCHIQ_MSG_CONNECT 1 /* - */
-#define VCHIQ_MSG_OPEN 2 /* + (srcport, -), fourcc, client_id */
-#define VCHIQ_MSG_OPENACK 3 /* + (srcport, dstport) */
-#define VCHIQ_MSG_CLOSE 4 /* + (srcport, dstport) */
-#define VCHIQ_MSG_DATA 5 /* + (srcport, dstport) */
-#define VCHIQ_MSG_BULK_RX 6 /* + (srcport, dstport), data, size */
-#define VCHIQ_MSG_BULK_TX 7 /* + (srcport, dstport), data, size */
-#define VCHIQ_MSG_BULK_RX_DONE 8 /* + (srcport, dstport), actual */
-#define VCHIQ_MSG_BULK_TX_DONE 9 /* + (srcport, dstport), actual */
-#define VCHIQ_MSG_PAUSE 10 /* - */
-#define VCHIQ_MSG_RESUME 11 /* - */
-#define VCHIQ_MSG_REMOTE_USE 12 /* - */
-#define VCHIQ_MSG_REMOTE_RELEASE 13 /* - */
-#define VCHIQ_MSG_REMOTE_USE_ACTIVE 14 /* - */
-
-#define VCHIQ_PORT_MAX (VCHIQ_MAX_SERVICES - 1)
-#define VCHIQ_PORT_FREE 0x1000
-#define VCHIQ_PORT_IS_VALID(port) (port < VCHIQ_PORT_FREE)
-#define VCHIQ_MAKE_MSG(type, srcport, dstport) \
- ((type<<24) | (srcport<<12) | (dstport<<0))
-#define VCHIQ_MSG_TYPE(msgid) ((unsigned int)msgid >> 24)
-#define VCHIQ_MSG_SRCPORT(msgid) \
- (unsigned short)(((unsigned int)msgid >> 12) & 0xfff)
-#define VCHIQ_MSG_DSTPORT(msgid) \
- ((unsigned short)msgid & 0xfff)
-
#define VCHIQ_FOURCC_AS_4CHARS(fourcc) \
((fourcc) >> 24) & 0xff, \
((fourcc) >> 16) & 0xff, \
((fourcc) >> 8) & 0xff, \
(fourcc) & 0xff
-/* Ensure the fields are wide enough */
-vchiq_static_assert(VCHIQ_MSG_SRCPORT(VCHIQ_MAKE_MSG(0, 0, VCHIQ_PORT_MAX))
- == 0);
-vchiq_static_assert(VCHIQ_MSG_TYPE(VCHIQ_MAKE_MSG(0, VCHIQ_PORT_MAX, 0)) == 0);
-vchiq_static_assert((unsigned int)VCHIQ_PORT_MAX <
- (unsigned int)VCHIQ_PORT_FREE);
-
-#define VCHIQ_MSGID_PADDING VCHIQ_MAKE_MSG(VCHIQ_MSG_PADDING, 0, 0)
-#define VCHIQ_MSGID_CLAIMED 0x40000000
-
-#define VCHIQ_FOURCC_INVALID 0x00000000
-#define VCHIQ_FOURCC_IS_LEGAL(fourcc) (fourcc != VCHIQ_FOURCC_INVALID)
-
-#define VCHIQ_BULK_ACTUAL_ABORTED -1
-
typedef uint32_t BITSET_T;
-vchiq_static_assert((sizeof(BITSET_T) * 8) == 32);
+static_assert((sizeof(BITSET_T) * 8) == 32);
#define BITSET_SIZE(b) ((b + 31) >> 5)
#define BITSET_WORD(b) (b >> 5)
@@ -140,17 +86,6 @@ vchiq_static_assert((sizeof(BITSET_T) * 8) == 32);
#define BITSET_SET(bs, b) (bs[BITSET_WORD(b)] |= BITSET_BIT(b))
#define BITSET_CLR(bs, b) (bs[BITSET_WORD(b)] &= ~BITSET_BIT(b))
-#if VCHIQ_ENABLE_STATS
-#define VCHIQ_STATS_INC(state, stat) (state->stats. stat++)
-#define VCHIQ_SERVICE_STATS_INC(service, stat) (service->stats. stat++)
-#define VCHIQ_SERVICE_STATS_ADD(service, stat, addend) \
- (service->stats. stat += addend)
-#else
-#define VCHIQ_STATS_INC(state, stat) ((void)0)
-#define VCHIQ_SERVICE_STATS_INC(service, stat) ((void)0)
-#define VCHIQ_SERVICE_STATS_ADD(service, stat, addend) ((void)0)
-#endif
-
enum {
DEBUG_ENTRIES,
#if VCHIQ_ENABLE_DEBUG
@@ -212,14 +147,6 @@ enum {
VCHIQ_SRVSTATE_CLOSED
};
-enum {
- VCHIQ_POLL_TERMINATE,
- VCHIQ_POLL_REMOVE,
- VCHIQ_POLL_TXNOTIFY,
- VCHIQ_POLL_RXNOTIFY,
- VCHIQ_POLL_COUNT
-};
-
enum vchiq_bulk_dir {
VCHIQ_BULK_TRANSMIT,
VCHIQ_BULK_RECEIVE
@@ -539,7 +466,7 @@ get_conn_state_name(enum vchiq_connstate conn_state);
extern struct vchiq_slot_zero *
vchiq_init_slots(void *mem_base, int mem_size);
-extern enum vchiq_status
+extern int
vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero);
extern enum vchiq_status
@@ -563,7 +490,7 @@ vchiq_terminate_service_internal(struct vchiq_service *service);
extern void
vchiq_free_service_internal(struct vchiq_service *service);
-extern enum vchiq_status
+extern void
vchiq_shutdown_internal(struct vchiq_state *state, struct vchiq_instance *instance);
extern void
@@ -627,10 +554,10 @@ next_service_by_instance(struct vchiq_state *state,
int *pidx);
extern void
-lock_service(struct vchiq_service *service);
+vchiq_service_get(struct vchiq_service *service);
extern void
-unlock_service(struct vchiq_service *service);
+vchiq_service_put(struct vchiq_service *service);
extern enum vchiq_status
vchiq_queue_message(unsigned int handle,
@@ -644,7 +571,7 @@ vchiq_queue_message(unsigned int handle,
* implementations must be provided.
*/
-extern enum vchiq_status
+extern int
vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset,
void __user *uoffset, int size, int dir);
@@ -667,10 +594,10 @@ extern int
vchiq_dump_platform_service_state(void *dump_context,
struct vchiq_service *service);
-extern enum vchiq_status
+extern int
vchiq_use_service_internal(struct vchiq_service *service);
-extern enum vchiq_status
+extern int
vchiq_release_service_internal(struct vchiq_service *service);
extern void
@@ -679,7 +606,7 @@ vchiq_on_remote_use(struct vchiq_state *state);
extern void
vchiq_on_remote_release(struct vchiq_state *state);
-extern enum vchiq_status
+extern int
vchiq_platform_init_state(struct vchiq_state *state);
extern enum vchiq_status
@@ -712,7 +639,7 @@ extern int vchiq_get_client_id(unsigned int service);
extern void vchiq_get_config(struct vchiq_config *config);
-extern enum vchiq_status
+extern int
vchiq_set_service_option(unsigned int service, enum vchiq_service_option option,
int value);
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 a39757b4e759..8f3d9cb2d562 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
@@ -11,11 +11,6 @@
#ifdef CONFIG_DEBUG_FS
-/****************************************************************************
- *
- * log category entries
- *
- ***************************************************************************/
#define DEBUGFS_WRITE_BUF_SIZE 256
#define VCHIQ_LOG_ERROR_STR "error"
@@ -40,6 +35,7 @@ static struct vchiq_debugfs_log_entry vchiq_debugfs_log_entries[] = {
{ "susp", &vchiq_susp_log_level },
{ "arm", &vchiq_arm_log_level },
};
+
static int n_log_entries = ARRAY_SIZE(vchiq_debugfs_log_entries);
static int debugfs_log_show(struct seq_file *f, void *offset)
diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
index 06bca7be5203..76d3f0399964 100644
--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
@@ -1862,7 +1862,7 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
int status;
int err = -ENODEV;
struct vchiq_mmal_instance *instance;
- static struct vchiq_instance *vchiq_instance;
+ struct vchiq_instance *vchiq_instance;
struct vchiq_service_params_kernel params = {
.version = VC_MMAL_VER,
.version_min = VC_MMAL_MIN_VER,
diff --git a/drivers/staging/vt6655/upc.h b/drivers/staging/vt6655/upc.h
index e086ec6e77f7..8608693ae9c3 100644
--- a/drivers/staging/vt6655/upc.h
+++ b/drivers/staging/vt6655/upc.h
@@ -42,7 +42,7 @@
#define PCAvDelayByIO(uDelayUnit) \
do { \
- unsigned char byData; \
+ unsigned char __maybe_unused byData; \
unsigned long ii; \
\
if (uDelayUnit <= 50) { \
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 759e475e303c..7951bd63816f 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -276,7 +276,7 @@ static int prism2_scan(struct wiphy *wiphy,
struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
struct wlandevice *wlandev;
struct p80211msg_dot11req_scan msg1;
- struct p80211msg_dot11req_scan_results msg2;
+ struct p80211msg_dot11req_scan_results *msg2;
struct cfg80211_bss *bss;
struct cfg80211_scan_info info = {};
@@ -301,6 +301,10 @@ static int prism2_scan(struct wiphy *wiphy,
return -EOPNOTSUPP;
}
+ msg2 = kzalloc(sizeof(*msg2), GFP_KERNEL);
+ if (!msg2)
+ return -ENOMEM;
+
priv->scan_request = request;
memset(&msg1, 0x00, sizeof(msg1));
@@ -342,31 +346,30 @@ static int prism2_scan(struct wiphy *wiphy,
for (i = 0; i < numbss; i++) {
int freq;
- memset(&msg2, 0, sizeof(msg2));
- msg2.msgcode = DIDMSG_DOT11REQ_SCAN_RESULTS;
- msg2.bssindex.data = i;
+ msg2->msgcode = DIDMSG_DOT11REQ_SCAN_RESULTS;
+ msg2->bssindex.data = i;
result = p80211req_dorequest(wlandev, (u8 *)&msg2);
if ((result != 0) ||
- (msg2.resultcode.data != P80211ENUM_resultcode_success)) {
+ (msg2->resultcode.data != P80211ENUM_resultcode_success)) {
break;
}
ie_buf[0] = WLAN_EID_SSID;
- ie_buf[1] = msg2.ssid.data.len;
+ ie_buf[1] = msg2->ssid.data.len;
ie_len = ie_buf[1] + 2;
- memcpy(&ie_buf[2], &msg2.ssid.data.data, msg2.ssid.data.len);
- freq = ieee80211_channel_to_frequency(msg2.dschannel.data,
+ memcpy(&ie_buf[2], &msg2->ssid.data.data, msg2->ssid.data.len);
+ freq = ieee80211_channel_to_frequency(msg2->dschannel.data,
NL80211_BAND_2GHZ);
bss = cfg80211_inform_bss(wiphy,
ieee80211_get_channel(wiphy, freq),
CFG80211_BSS_FTYPE_UNKNOWN,
- (const u8 *)&msg2.bssid.data.data,
- msg2.timestamp.data, msg2.capinfo.data,
- msg2.beaconperiod.data,
+ (const u8 *)&msg2->bssid.data.data,
+ msg2->timestamp.data, msg2->capinfo.data,
+ msg2->beaconperiod.data,
ie_buf,
ie_len,
- (msg2.signal.data - 65536) * 100, /* Conversion to signed type */
+ (msg2->signal.data - 65536) * 100, /* Conversion to signed type */
GFP_KERNEL);
if (!bss) {
@@ -378,12 +381,13 @@ static int prism2_scan(struct wiphy *wiphy,
}
if (result)
- err = prism2_result2err(msg2.resultcode.data);
+ err = prism2_result2err(msg2->resultcode.data);
exit:
info.aborted = !!(err);
cfg80211_scan_done(request, &info);
priv->scan_request = NULL;
+ kfree(msg2);
return err;
}
diff --git a/drivers/staging/wlan-ng/p80211ioctl.h b/drivers/staging/wlan-ng/p80211ioctl.h
index ed65ac57adbe..77e8d2913b76 100644
--- a/drivers/staging/wlan-ng/p80211ioctl.h
+++ b/drivers/staging/wlan-ng/p80211ioctl.h
@@ -81,7 +81,7 @@
struct p80211ioctl_req {
char name[WLAN_DEVNAMELEN_MAX];
- caddr_t data;
+ char __user *data;
u32 magic;
u16 len;
u32 result;
diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c
index 70570e8a5ad2..6f470e7ba647 100644
--- a/drivers/staging/wlan-ng/p80211netdev.c
+++ b/drivers/staging/wlan-ng/p80211netdev.c
@@ -325,7 +325,7 @@ static netdev_tx_t p80211knetdev_hard_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
int result = 0;
- int txresult = -1;
+ int txresult;
struct wlandevice *wlandev = netdev->ml_priv;
union p80211_hdr p80211_hdr;
struct p80211_metawep p80211_wep;
@@ -569,7 +569,7 @@ static int p80211knetdev_do_ioctl(struct net_device *dev,
goto bail;
}
- msgbuf = memdup_user((void __user *)req->data, req->len);
+ msgbuf = memdup_user(req->data, req->len);
if (IS_ERR(msgbuf)) {
result = PTR_ERR(msgbuf);
goto bail;
@@ -579,7 +579,7 @@ static int p80211knetdev_do_ioctl(struct net_device *dev,
if (result == 0) {
if (copy_to_user
- ((void __user *)req->data, msgbuf, req->len)) {
+ (req->data, msgbuf, req->len)) {
result = -EFAULT;
}
}
diff --git a/drivers/target/iscsi/cxgbit/cxgbit_ddp.c b/drivers/target/iscsi/cxgbit/cxgbit_ddp.c
index af35251232eb..b044999ad002 100644
--- a/drivers/target/iscsi/cxgbit/cxgbit_ddp.c
+++ b/drivers/target/iscsi/cxgbit/cxgbit_ddp.c
@@ -265,12 +265,13 @@ void cxgbit_unmap_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
struct cxgbit_cmd *ccmd = iscsit_priv_cmd(cmd);
if (ccmd->release) {
- struct cxgbi_task_tag_info *ttinfo = &ccmd->ttinfo;
-
- if (ttinfo->sgl) {
+ if (cmd->se_cmd.se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) {
+ put_page(sg_page(&ccmd->sg));
+ } else {
struct cxgbit_sock *csk = conn->context;
struct cxgbit_device *cdev = csk->com.cdev;
struct cxgbi_ppm *ppm = cdev2ppm(cdev);
+ struct cxgbi_task_tag_info *ttinfo = &ccmd->ttinfo;
/* Abort the TCP conn if DDP is not complete to
* avoid any possibility of DDP after freeing
@@ -280,14 +281,14 @@ void cxgbit_unmap_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
cmd->se_cmd.data_length))
cxgbit_abort_conn(csk);
+ if (unlikely(ttinfo->sgl)) {
+ dma_unmap_sg(&ppm->pdev->dev, ttinfo->sgl,
+ ttinfo->nents, DMA_FROM_DEVICE);
+ ttinfo->nents = 0;
+ ttinfo->sgl = NULL;
+ }
cxgbi_ppm_ppod_release(ppm, ttinfo->idx);
-
- dma_unmap_sg(&ppm->pdev->dev, ttinfo->sgl,
- ttinfo->nents, DMA_FROM_DEVICE);
- } else {
- put_page(sg_page(&ccmd->sg));
}
-
ccmd->release = false;
}
}
diff --git a/drivers/target/iscsi/cxgbit/cxgbit_target.c b/drivers/target/iscsi/cxgbit/cxgbit_target.c
index b926e1d6c7b8..282297ffc404 100644
--- a/drivers/target/iscsi/cxgbit/cxgbit_target.c
+++ b/drivers/target/iscsi/cxgbit/cxgbit_target.c
@@ -997,17 +997,18 @@ static int cxgbit_handle_iscsi_dataout(struct cxgbit_sock *csk)
struct scatterlist *sg_start;
struct iscsi_conn *conn = csk->conn;
struct iscsi_cmd *cmd = NULL;
+ struct cxgbit_cmd *ccmd;
+ struct cxgbi_task_tag_info *ttinfo;
struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb);
struct iscsi_data *hdr = (struct iscsi_data *)pdu_cb->hdr;
u32 data_offset = be32_to_cpu(hdr->offset);
- u32 data_len = pdu_cb->dlen;
+ u32 data_len = ntoh24(hdr->dlength);
int rc, sg_nents, sg_off;
bool dcrc_err = false;
if (pdu_cb->flags & PDUCBF_RX_DDP_CMP) {
u32 offset = be32_to_cpu(hdr->offset);
u32 ddp_data_len;
- u32 payload_length = ntoh24(hdr->dlength);
bool success = false;
cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt, 0);
@@ -1022,7 +1023,7 @@ static int cxgbit_handle_iscsi_dataout(struct cxgbit_sock *csk)
cmd->data_sn = be32_to_cpu(hdr->datasn);
rc = __iscsit_check_dataout_hdr(conn, (unsigned char *)hdr,
- cmd, payload_length, &success);
+ cmd, data_len, &success);
if (rc < 0)
return rc;
else if (!success)
@@ -1060,6 +1061,20 @@ static int cxgbit_handle_iscsi_dataout(struct cxgbit_sock *csk)
cxgbit_skb_copy_to_sg(csk->skb, sg_start, sg_nents, skip);
}
+ ccmd = iscsit_priv_cmd(cmd);
+ ttinfo = &ccmd->ttinfo;
+
+ if (ccmd->release && ttinfo->sgl &&
+ (cmd->se_cmd.data_length == (cmd->write_data_done + data_len))) {
+ struct cxgbit_device *cdev = csk->com.cdev;
+ struct cxgbi_ppm *ppm = cdev2ppm(cdev);
+
+ dma_unmap_sg(&ppm->pdev->dev, ttinfo->sgl, ttinfo->nents,
+ DMA_FROM_DEVICE);
+ ttinfo->nents = 0;
+ ttinfo->sgl = NULL;
+ }
+
check_payload:
rc = iscsit_check_dataout_payload(cmd, hdr, dcrc_err);
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index cd670cb9b8fb..0dd52f484fec 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -871,8 +871,6 @@ int iscsit_execute_ooo_cmdsns(struct iscsi_session *sess)
if (iscsit_execute_cmd(cmd, 1) < 0)
return -1;
-
- continue;
}
return ooo_count;
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 151e2949bb75..c0ed6f8e5c5b 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -118,13 +118,6 @@ static u32 iscsi_handle_authentication(
" CHAP auth\n");
return -1;
}
- iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl,
- se_node_acl);
- if (!iscsi_nacl) {
- pr_err("Unable to locate struct iscsi_node_acl for"
- " CHAP auth\n");
- return -1;
- }
if (se_nacl->dynamic_node_acl) {
iscsi_tpg = container_of(se_nacl->se_tpg,
@@ -1082,14 +1075,12 @@ int iscsi_target_locate_portal(
login_req = (struct iscsi_login_req *) login->req;
payload_length = ntoh24(login_req->dlength);
- tmpbuf = kzalloc(payload_length + 1, GFP_KERNEL);
+ tmpbuf = kmemdup_nul(login->req_buf, payload_length, GFP_KERNEL);
if (!tmpbuf) {
pr_err("Unable to allocate memory for tmpbuf.\n");
return -1;
}
- memcpy(tmpbuf, login->req_buf, payload_length);
- tmpbuf[payload_length] = '\0';
start = tmpbuf;
end = (start + payload_length);
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 7a461fbb1566..6bc3aaf655fc 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -1357,14 +1357,12 @@ int iscsi_decode_text_input(
struct iscsi_param_list *param_list = conn->param_list;
char *tmpbuf, *start = NULL, *end = NULL;
- tmpbuf = kzalloc(length + 1, GFP_KERNEL);
+ tmpbuf = kmemdup_nul(textbuf, length, GFP_KERNEL);
if (!tmpbuf) {
pr_err("Unable to allocate %u + 1 bytes for tmpbuf.\n", length);
return -ENOMEM;
}
- memcpy(tmpbuf, textbuf, length);
- tmpbuf[length] = '\0';
start = tmpbuf;
end = (start + length);
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index 2687fd7d45db..6d0b0e67e79e 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -566,7 +566,6 @@ static int tcm_loop_queue_data_or_status(const char *func,
memcpy(sc->sense_buffer, se_cmd->sense_buffer,
SCSI_SENSE_BUFFERSIZE);
sc->result = SAM_STAT_CHECK_CONDITION;
- set_driver_byte(sc, DRIVER_SENSE);
} else
sc->result = scsi_status;
diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c
index ce84f93c183a..4d3ceee23622 100644
--- a/drivers/target/sbp/sbp_target.c
+++ b/drivers/target/sbp/sbp_target.c
@@ -1261,7 +1261,6 @@ static int sbp_rw_data(struct sbp_target_request *req)
pg_size = CMDBLK_ORB_PG_SIZE(be32_to_cpu(req->orb.misc));
if (pg_size) {
pr_err("sbp_run_transaction: page size ignored\n");
- pg_size = 0x100 << pg_size;
}
spin_lock_bh(&sess->lock);
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 5517c7dd5144..3bb921345bce 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -123,7 +123,7 @@ target_emulate_report_referrals(struct se_cmd *cmd)
transport_kunmap_data_sg(cmd);
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
@@ -255,7 +255,7 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
}
transport_kunmap_data_sg(cmd);
- target_complete_cmd_with_length(cmd, GOOD, rd_len + 4);
+ target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, rd_len + 4);
return 0;
}
@@ -424,7 +424,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
out:
transport_kunmap_data_sg(cmd);
if (!rc)
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return rc;
}
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 4b2e49341ad6..102ec644bc8a 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -1479,6 +1479,54 @@ static ssize_t target_wwn_revision_store(struct config_item *item,
return count;
}
+static ssize_t
+target_wwn_company_id_show(struct config_item *item,
+ char *page)
+{
+ return snprintf(page, PAGE_SIZE, "%#08x\n",
+ to_t10_wwn(item)->company_id);
+}
+
+static ssize_t
+target_wwn_company_id_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct t10_wwn *t10_wwn = to_t10_wwn(item);
+ struct se_device *dev = t10_wwn->t10_dev;
+ u32 val;
+ int ret;
+
+ /*
+ * The IEEE COMPANY_ID field should contain a 24-bit canonical
+ * form OUI assigned by the IEEE.
+ */
+ ret = kstrtou32(page, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val >= 0x1000000)
+ return -EOVERFLOW;
+
+ /*
+ * Check to see if any active exports exist. If they do exist, fail
+ * here as changing this information on the fly (underneath the
+ * initiator side OS dependent multipath code) could cause negative
+ * effects.
+ */
+ if (dev->export_count) {
+ pr_err("Unable to set Company ID while %u exports exist\n",
+ dev->export_count);
+ return -EINVAL;
+ }
+
+ t10_wwn->company_id = val;
+
+ pr_debug("Target_Core_ConfigFS: Set IEEE Company ID: %#08x\n",
+ t10_wwn->company_id);
+
+ return count;
+}
+
/*
* VPD page 0x80 Unit serial
*/
@@ -1625,6 +1673,7 @@ DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_scsi_target_device, 0x20);
CONFIGFS_ATTR(target_wwn_, vendor_id);
CONFIGFS_ATTR(target_wwn_, product_id);
CONFIGFS_ATTR(target_wwn_, revision);
+CONFIGFS_ATTR(target_wwn_, company_id);
CONFIGFS_ATTR(target_wwn_, vpd_unit_serial);
CONFIGFS_ATTR_RO(target_wwn_, vpd_protocol_identifier);
CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_logical_unit);
@@ -1635,6 +1684,7 @@ static struct configfs_attribute *target_core_dev_wwn_attrs[] = {
&target_wwn_attr_vendor_id,
&target_wwn_attr_product_id,
&target_wwn_attr_revision,
+ &target_wwn_attr_company_id,
&target_wwn_attr_vpd_unit_serial,
&target_wwn_attr_vpd_protocol_identifier,
&target_wwn_attr_vpd_assoc_logical_unit,
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index a8df9f0a82fa..8cb1fa0c0585 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -773,6 +773,11 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
spin_lock_init(&dev->t10_alua.lba_map_lock);
dev->t10_wwn.t10_dev = dev;
+ /*
+ * Use OpenFabrics IEEE Company ID: 00 14 05
+ */
+ dev->t10_wwn.company_id = 0x001405;
+
dev->t10_alua.t10_dev = dev;
dev->dev_attrib.da_dev = dev;
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index a526f9678c34..44d9d028f716 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -474,7 +474,7 @@ iblock_execute_zero_out(struct block_device *bdev, struct se_cmd *cmd)
if (ret)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 6fd5fec95539..4b94b085625b 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -234,7 +234,7 @@ target_scsi2_reservation_release(struct se_cmd *cmd)
out_unlock:
spin_unlock(&dev->dev_reservation_lock);
out:
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
@@ -297,7 +297,7 @@ out_unlock:
spin_unlock(&dev->dev_reservation_lock);
out:
if (!ret)
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return ret;
}
@@ -3676,7 +3676,7 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd)
}
if (!ret)
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return ret;
}
@@ -4073,7 +4073,7 @@ target_scsi3_emulate_pr_in(struct se_cmd *cmd)
}
if (!ret)
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return ret;
}
diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h
index a31c93e4e19c..b793c99637ab 100644
--- a/drivers/target/target_core_pr.h
+++ b/drivers/target/target_core_pr.h
@@ -52,7 +52,7 @@
/*
* Function defined in target_core_spc.c
*/
-void spc_parse_naa_6h_vendor_specific(struct se_device *, unsigned char *);
+void spc_gen_naa_6h_vendor_specific(struct se_device *, unsigned char *);
extern struct kmem_cache *t10_pr_reg_cache;
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index f2a11414366d..2629d2ef3970 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -982,7 +982,7 @@ pscsi_execute_cmd(struct se_cmd *cmd)
req = blk_get_request(pdv->pdv_sd->request_queue,
cmd->data_direction == DMA_TO_DEVICE ?
- REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0);
+ REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
if (IS_ERR(req)) {
pr_err("PSCSI: blk_get_request() failed\n");
ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -1044,7 +1044,7 @@ static void pscsi_req_done(struct request *req, blk_status_t status)
struct se_cmd *cmd = req->end_io_data;
struct pscsi_plugin_task *pt = cmd->priv;
int result = scsi_req(req)->result;
- u8 scsi_status = status_byte(result) << 1;
+ enum sam_status scsi_status = result & 0xff;
if (scsi_status != SAM_STAT_GOOD) {
pr_debug("PSCSI Status Byte exception at cmd: %p CDB:"
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index 7b07e557dc8d..b32f4ee88e79 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -67,7 +67,7 @@ sbc_emulate_readcapacity(struct se_cmd *cmd)
transport_kunmap_data_sg(cmd);
}
- target_complete_cmd_with_length(cmd, GOOD, 8);
+ target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, 8);
return 0;
}
@@ -130,7 +130,7 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
transport_kunmap_data_sg(cmd);
}
- target_complete_cmd_with_length(cmd, GOOD, 32);
+ target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, 32);
return 0;
}
@@ -202,14 +202,14 @@ sbc_execute_write_same_unmap(struct se_cmd *cmd)
return ret;
}
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
static sense_reason_t
sbc_emulate_noop(struct se_cmd *cmd)
{
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
@@ -1245,7 +1245,7 @@ sbc_execute_unmap(struct se_cmd *cmd)
err:
transport_kunmap_data_sg(cmd);
if (!ret)
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return ret;
}
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index 70a661801cb9..22703a0dbd07 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -47,10 +47,32 @@ static void spc_fill_alua_data(struct se_lun *lun, unsigned char *buf)
spin_unlock(&lun->lun_tg_pt_gp_lock);
}
+static u16
+spc_find_scsi_transport_vd(int proto_id)
+{
+ switch (proto_id) {
+ case SCSI_PROTOCOL_FCP:
+ return SCSI_VERSION_DESCRIPTOR_FCP4;
+ case SCSI_PROTOCOL_ISCSI:
+ return SCSI_VERSION_DESCRIPTOR_ISCSI;
+ case SCSI_PROTOCOL_SAS:
+ return SCSI_VERSION_DESCRIPTOR_SAS3;
+ case SCSI_PROTOCOL_SBP:
+ return SCSI_VERSION_DESCRIPTOR_SBP3;
+ case SCSI_PROTOCOL_SRP:
+ return SCSI_VERSION_DESCRIPTOR_SRP;
+ default:
+ pr_warn("Cannot find VERSION DESCRIPTOR value for unknown SCSI"
+ " transport PROTOCOL IDENTIFIER %#x\n", proto_id);
+ return 0;
+ }
+}
+
sense_reason_t
spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
{
struct se_lun *lun = cmd->se_lun;
+ struct se_portal_group *tpg = lun->lun_tpg;
struct se_device *dev = cmd->se_dev;
struct se_session *sess = cmd->se_sess;
@@ -58,7 +80,7 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
if (dev->transport->get_device_type(dev) == TYPE_TAPE)
buf[1] = 0x80;
- buf[2] = 0x05; /* SPC-3 */
+ buf[2] = 0x06; /* SPC-4 */
/*
* NORMACA and HISUP = 0, RESPONSE DATA FORMAT = 2
@@ -108,7 +130,17 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
strnlen(dev->t10_wwn.model, INQUIRY_MODEL_LEN));
memcpy(&buf[32], dev->t10_wwn.revision,
strnlen(dev->t10_wwn.revision, INQUIRY_REVISION_LEN));
- buf[4] = 31; /* Set additional length to 31 */
+
+ /*
+ * Set the VERSION DESCRIPTOR fields
+ */
+ put_unaligned_be16(SCSI_VERSION_DESCRIPTOR_SAM5, &buf[58]);
+ put_unaligned_be16(spc_find_scsi_transport_vd(tpg->proto_id), &buf[60]);
+ put_unaligned_be16(SCSI_VERSION_DESCRIPTOR_SPC4, &buf[62]);
+ if (cmd->se_dev->transport->get_device_type(dev) == TYPE_DISK)
+ put_unaligned_be16(SCSI_VERSION_DESCRIPTOR_SBC3, &buf[64]);
+
+ buf[4] = 91; /* Set additional length to 91 */
return 0;
}
@@ -129,14 +161,29 @@ spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
return 0;
}
-void spc_parse_naa_6h_vendor_specific(struct se_device *dev,
- unsigned char *buf)
+/*
+ * Generate NAA IEEE Registered Extended designator
+ */
+void spc_gen_naa_6h_vendor_specific(struct se_device *dev,
+ unsigned char *buf)
{
unsigned char *p = &dev->t10_wwn.unit_serial[0];
- int cnt;
+ u32 company_id = dev->t10_wwn.company_id;
+ int cnt, off = 0;
bool next = true;
/*
+ * Start NAA IEEE Registered Extended Identifier/Designator
+ */
+ buf[off] = 0x6 << 4;
+
+ /* IEEE COMPANY_ID */
+ buf[off++] |= (company_id >> 20) & 0xf;
+ buf[off++] = (company_id >> 12) & 0xff;
+ buf[off++] = (company_id >> 4) & 0xff;
+ buf[off] = (company_id & 0xf) << 4;
+
+ /*
* Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on
* byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field
* format, followed by 64 bits of VENDOR SPECIFIC IDENTIFIER EXTENSION
@@ -144,7 +191,7 @@ void spc_parse_naa_6h_vendor_specific(struct se_device *dev,
* NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure
* per device uniqeness.
*/
- for (cnt = 0; *p && cnt < 13; p++) {
+ for (cnt = off + 13; *p && off < cnt; p++) {
int val = hex_to_bin(*p);
if (val < 0)
@@ -152,10 +199,10 @@ void spc_parse_naa_6h_vendor_specific(struct se_device *dev,
if (next) {
next = false;
- buf[cnt++] |= val;
+ buf[off++] |= val;
} else {
next = true;
- buf[cnt] = val << 4;
+ buf[off] = val << 4;
}
}
}
@@ -203,24 +250,8 @@ spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
/* Identifier/Designator length */
buf[off++] = 0x10;
- /*
- * Start NAA IEEE Registered Extended Identifier/Designator
- */
- buf[off++] = (0x6 << 4);
-
- /*
- * Use OpenFabrics IEEE Company ID: 00 14 05
- */
- buf[off++] = 0x01;
- buf[off++] = 0x40;
- buf[off] = (0x5 << 4);
-
- /*
- * Return ConfigFS Unit Serial Number information for
- * VENDOR_SPECIFIC_IDENTIFIER and
- * VENDOR_SPECIFIC_IDENTIFIER_EXTENTION
- */
- spc_parse_naa_6h_vendor_specific(dev, &buf[off]);
+ /* NAA IEEE Registered Extended designator */
+ spc_gen_naa_6h_vendor_specific(dev, &buf[off]);
len = 20;
off = (len + 4);
@@ -750,7 +781,7 @@ out:
kfree(buf);
if (!ret)
- target_complete_cmd_with_length(cmd, GOOD, len);
+ target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, len);
return ret;
}
@@ -1104,7 +1135,7 @@ set_length:
transport_kunmap_data_sg(cmd);
}
- target_complete_cmd_with_length(cmd, GOOD, length);
+ target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, length);
return 0;
}
@@ -1122,7 +1153,7 @@ static sense_reason_t spc_emulate_modeselect(struct se_cmd *cmd)
int i;
if (!cmd->data_length) {
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
@@ -1165,7 +1196,7 @@ out:
transport_kunmap_data_sg(cmd);
if (!ret)
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return ret;
}
@@ -1198,7 +1229,7 @@ static sense_reason_t spc_emulate_request_sense(struct se_cmd *cmd)
memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
transport_kunmap_data_sg(cmd);
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
@@ -1265,7 +1296,7 @@ done:
transport_kunmap_data_sg(cmd);
}
- target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8);
+ target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, 8 + lun_count * 8);
return 0;
}
EXPORT_SYMBOL(spc_emulate_report_luns);
@@ -1273,7 +1304,7 @@ EXPORT_SYMBOL(spc_emulate_report_luns);
static sense_reason_t
spc_emulate_testunitready(struct se_cmd *cmd)
{
- target_complete_cmd(cmd, GOOD);
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 4bba10e7755a..fbb6ffaddfbe 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -121,7 +121,7 @@ struct tcmu_dev {
#define TCMU_DEV_BIT_BROKEN 1
#define TCMU_DEV_BIT_BLOCKED 2
#define TCMU_DEV_BIT_TMR_NOTIFY 3
-#define TCM_DEV_BIT_PLUGGED 4
+#define TCMU_DEV_BIT_PLUGGED 4
unsigned long flags;
struct uio_info uio_info;
@@ -982,7 +982,7 @@ static void tcmu_unplug_device(struct se_dev_plug *se_plug)
struct se_device *se_dev = se_plug->se_dev;
struct tcmu_dev *udev = TCMU_DEV(se_dev);
- clear_bit(TCM_DEV_BIT_PLUGGED, &udev->flags);
+ clear_bit(TCMU_DEV_BIT_PLUGGED, &udev->flags);
uio_event_notify(&udev->uio_info);
}
@@ -990,7 +990,7 @@ static struct se_dev_plug *tcmu_plug_device(struct se_device *se_dev)
{
struct tcmu_dev *udev = TCMU_DEV(se_dev);
- if (!test_and_set_bit(TCM_DEV_BIT_PLUGGED, &udev->flags))
+ if (!test_and_set_bit(TCMU_DEV_BIT_PLUGGED, &udev->flags))
return &udev->se_plug;
return NULL;
@@ -1124,7 +1124,7 @@ static int queue_cmd_ring(struct tcmu_cmd *tcmu_cmd, sense_reason_t *scsi_err)
list_add_tail(&tcmu_cmd->queue_entry, &udev->inflight_queue);
- if (!test_bit(TCM_DEV_BIT_PLUGGED, &udev->flags))
+ if (!test_bit(TCMU_DEV_BIT_PLUGGED, &udev->flags))
uio_event_notify(&udev->uio_info);
return 0;
@@ -1423,7 +1423,7 @@ static bool tcmu_handle_completions(struct tcmu_dev *udev)
if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags)) {
pr_err("ring broken, not handling completions\n");
- return 0;
+ return false;
}
mb = udev->mb_addr;
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
index d31ed071cb08..0f1319336f3e 100644
--- a/drivers/target/target_core_xcopy.c
+++ b/drivers/target/target_core_xcopy.c
@@ -33,19 +33,6 @@ static struct workqueue_struct *xcopy_wq = NULL;
static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop);
-static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
-{
- int off = 0;
-
- buf[off++] = (0x6 << 4);
- buf[off++] = 0x01;
- buf[off++] = 0x40;
- buf[off] = (0x5 << 4);
-
- spc_parse_naa_6h_vendor_specific(dev, &buf[off]);
- return 0;
-}
-
/**
* target_xcopy_locate_se_dev_e4_iter - compare XCOPY NAA device identifiers
*
@@ -65,7 +52,7 @@ static int target_xcopy_locate_se_dev_e4_iter(struct se_device *se_dev,
}
memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
- target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]);
+ spc_gen_naa_6h_vendor_specific(se_dev, &tmp_dev_wwn[0]);
rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
if (rc != 0) {
@@ -241,7 +228,7 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
* se_device the XCOPY was received upon..
*/
memset(&xop->local_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
- target_xcopy_gen_naa_ieee(local_dev, &xop->local_dev_wwn[0]);
+ spc_gen_naa_6h_vendor_specific(local_dev, &xop->local_dev_wwn[0]);
while (start < tdll) {
/*
@@ -1011,7 +998,7 @@ static sense_reason_t target_rcr_operating_parameters(struct se_cmd *se_cmd)
put_unaligned_be32(42, &p[0]);
transport_kunmap_data_sg(se_cmd);
- target_complete_cmd(se_cmd, GOOD);
+ target_complete_cmd(se_cmd, SAM_STAT_GOOD);
return TCM_NO_SENSE;
}
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index 480d294a23ab..2b37bc408fc3 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -452,6 +452,7 @@ static int params_to_user(struct tee_ioctl_param __user *uparams,
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
if (put_user((u64)p->u.memref.size, &up->b))
return -EFAULT;
+ break;
default:
break;
}
diff --git a/drivers/thermal/cpufreq_cooling.c b/drivers/thermal/cpufreq_cooling.c
index eeb4e4b76c0b..43b1ae8a7789 100644
--- a/drivers/thermal/cpufreq_cooling.c
+++ b/drivers/thermal/cpufreq_cooling.c
@@ -478,7 +478,7 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
ret = freq_qos_update_request(&cpufreq_cdev->qos_req, frequency);
if (ret >= 0) {
cpufreq_cdev->cpufreq_state = state;
- cpus = cpufreq_cdev->policy->cpus;
+ cpus = cpufreq_cdev->policy->related_cpus;
max_capacity = arch_scale_cpu_capacity(cpumask_first(cpus));
capacity = frequency * max_capacity;
capacity /= cpufreq_cdev->policy->cpuinfo.max_freq;
diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c
index 3a788ac4f525..5a86cffd78f6 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -458,7 +458,7 @@ struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df)
EXPORT_SYMBOL_GPL(devfreq_cooling_register);
/**
- * devfreq_cooling_em_register_power() - Register devfreq cooling device with
+ * devfreq_cooling_em_register() - Register devfreq cooling device with
* power information and automatically register Energy Model (EM)
* @df: Pointer to devfreq device.
* @dfc_power: Pointer to devfreq_cooling_power.
diff --git a/drivers/thermal/imx_sc_thermal.c b/drivers/thermal/imx_sc_thermal.c
index b01d28eca7ee..8d76dbfde6a9 100644
--- a/drivers/thermal/imx_sc_thermal.c
+++ b/drivers/thermal/imx_sc_thermal.c
@@ -93,6 +93,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev)
for_each_available_child_of_node(np, child) {
sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL);
if (!sensor) {
+ of_node_put(child);
of_node_put(sensor_np);
return -ENOMEM;
}
@@ -104,6 +105,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"failed to get valid sensor resource id: %d\n",
ret);
+ of_node_put(child);
break;
}
@@ -114,6 +116,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev)
if (IS_ERR(sensor->tzd)) {
dev_err(&pdev->dev, "failed to register thermal zone\n");
ret = PTR_ERR(sensor->tzd);
+ of_node_put(child);
break;
}
diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile
index 38a2731e503c..4e852ce4a5d5 100644
--- a/drivers/thermal/intel/int340x_thermal/Makefile
+++ b/drivers/thermal/intel/int340x_thermal/Makefile
@@ -4,6 +4,9 @@ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o
obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o
obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o
+obj-$(CONFIG_INT340X_THERMAL) += int3401_thermal.o
+obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci_legacy.o
+obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci.o
obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_rfim.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_mbox.o
diff --git a/drivers/thermal/intel/int340x_thermal/int3401_thermal.c b/drivers/thermal/intel/int340x_thermal/int3401_thermal.c
new file mode 100644
index 000000000000..acebc8ba94e2
--- /dev/null
+++ b/drivers/thermal/intel/int340x_thermal/int3401_thermal.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * INT3401 processor thermal device
+ * Copyright (c) 2020, Intel Corporation.
+ */
+#include <linux/acpi.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+
+#include "int340x_thermal_zone.h"
+#include "processor_thermal_device.h"
+
+static const struct acpi_device_id int3401_device_ids[] = {
+ {"INT3401", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, int3401_device_ids);
+
+static int int3401_add(struct platform_device *pdev)
+{
+ struct proc_thermal_device *proc_priv;
+ int ret;
+
+ proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
+ if (!proc_priv)
+ return -ENOMEM;
+
+ ret = proc_thermal_add(&pdev->dev, proc_priv);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, proc_priv);
+
+ return ret;
+}
+
+static int int3401_remove(struct platform_device *pdev)
+{
+ proc_thermal_remove(platform_get_drvdata(pdev));
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int int3401_thermal_resume(struct device *dev)
+{
+ return proc_thermal_resume(dev);
+}
+#else
+#define int3401_thermal_resume NULL
+#endif
+
+static SIMPLE_DEV_PM_OPS(int3401_proc_thermal_pm, NULL, int3401_thermal_resume);
+
+static struct platform_driver int3401_driver = {
+ .probe = int3401_add,
+ .remove = int3401_remove,
+ .driver = {
+ .name = "int3401 thermal",
+ .acpi_match_table = int3401_device_ids,
+ .pm = &int3401_proc_thermal_pm,
+ },
+};
+
+static int __init proc_thermal_init(void)
+{
+ return platform_driver_register(&int3401_driver);
+}
+
+static void __exit proc_thermal_exit(void)
+{
+ platform_driver_unregister(&int3401_driver);
+}
+
+module_init(proc_thermal_init);
+module_exit(proc_thermal_exit);
+
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
index 9e6f2a895a23..0f0038af2ad4 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
@@ -3,34 +3,17 @@
* processor_thermal_device.c
* Copyright (c) 2014, Intel Corporation.
*/
+#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/acpi.h>
#include <linux/thermal.h>
-#include <linux/cpuhotplug.h>
#include "int340x_thermal_zone.h"
#include "processor_thermal_device.h"
#include "../intel_soc_dts_iosf.h"
#define DRV_NAME "proc_thermal"
-enum proc_thermal_emum_mode_type {
- PROC_THERMAL_NONE,
- PROC_THERMAL_PCI,
- PROC_THERMAL_PLATFORM_DEV
-};
-
-/*
- * We can have only one type of enumeration, PCI or Platform,
- * not both. So we don't need instance specific data.
- */
-static enum proc_thermal_emum_mode_type proc_thermal_emum_mode =
- PROC_THERMAL_NONE;
-
#define POWER_LIMIT_SHOW(index, suffix) \
static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \
struct device_attribute *attr, \
@@ -38,11 +21,6 @@ static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \
{ \
struct proc_thermal_device *proc_dev = dev_get_drvdata(dev); \
\
- if (proc_thermal_emum_mode == PROC_THERMAL_NONE) { \
- dev_warn(dev, "Attempted to get power limit before device was initialized!\n"); \
- return 0; \
- } \
- \
return sprintf(buf, "%lu\n",\
(unsigned long)proc_dev->power_limits[index].suffix * 1000); \
}
@@ -100,24 +78,27 @@ static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
if (err)
return err;
- val = (val >> 24) & 0xff;
+ val = (val >> 24) & 0x3f;
return sprintf(buf, "%d\n", (int)val);
}
-static int tcc_offset_update(int tcc)
+static int tcc_offset_update(unsigned int tcc)
{
u64 val;
int err;
- if (!tcc)
+ if (tcc > 63)
return -EINVAL;
err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
if (err)
return err;
- val &= ~GENMASK_ULL(31, 24);
- val |= (tcc & 0xff) << 24;
+ if (val & BIT(31))
+ return -EPERM;
+
+ val &= ~GENMASK_ULL(29, 24);
+ val |= (tcc & 0x3f) << 24;
err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
if (err)
@@ -126,14 +107,15 @@ static int tcc_offset_update(int tcc)
return 0;
}
-static int tcc_offset_save;
+static unsigned int tcc_offset_save;
static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
+ unsigned int tcc;
u64 val;
- int tcc, err;
+ int err;
err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
if (err)
@@ -142,7 +124,7 @@ static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
if (!(val & BIT(30)))
return -EACCES;
- if (kstrtoint(buf, 0, &tcc))
+ if (kstrtouint(buf, 0, &tcc))
return -EINVAL;
err = tcc_offset_update(tcc);
@@ -291,11 +273,8 @@ static void proc_thermal_notify(acpi_handle handle, u32 event, void *data)
}
}
-
-static int proc_thermal_add(struct device *dev,
- struct proc_thermal_device **priv)
+int proc_thermal_add(struct device *dev, struct proc_thermal_device *proc_priv)
{
- struct proc_thermal_device *proc_priv;
struct acpi_device *adev;
acpi_status status;
unsigned long long tmp;
@@ -306,13 +285,8 @@ static int proc_thermal_add(struct device *dev,
if (!adev)
return -ENODEV;
- proc_priv = devm_kzalloc(dev, sizeof(*proc_priv), GFP_KERNEL);
- if (!proc_priv)
- return -ENOMEM;
-
proc_priv->dev = dev;
proc_priv->adev = adev;
- *priv = proc_priv;
ret = proc_thermal_read_ppcc(proc_priv);
if (ret)
@@ -338,15 +312,29 @@ static int proc_thermal_add(struct device *dev,
if (ret)
goto remove_zone;
+ ret = sysfs_create_file(&dev->kobj, &dev_attr_tcc_offset_degree_celsius.attr);
+ if (ret)
+ goto remove_notify;
+
+ ret = sysfs_create_group(&dev->kobj, &power_limit_attribute_group);
+ if (ret) {
+ sysfs_remove_file(&dev->kobj, &dev_attr_tcc_offset_degree_celsius.attr);
+ goto remove_notify;
+ }
+
return 0;
+remove_notify:
+ acpi_remove_notify_handler(adev->handle,
+ ACPI_DEVICE_NOTIFY, proc_thermal_notify);
remove_zone:
int340x_thermal_zone_remove(proc_priv->int340x_zone);
return ret;
}
+EXPORT_SYMBOL_GPL(proc_thermal_add);
-static void proc_thermal_remove(struct proc_thermal_device *proc_priv)
+void proc_thermal_remove(struct proc_thermal_device *proc_priv)
{
acpi_remove_notify_handler(proc_priv->adev->handle,
ACPI_DEVICE_NOTIFY, proc_thermal_notify);
@@ -355,60 +343,24 @@ static void proc_thermal_remove(struct proc_thermal_device *proc_priv)
sysfs_remove_group(&proc_priv->dev->kobj,
&power_limit_attribute_group);
}
+EXPORT_SYMBOL_GPL(proc_thermal_remove);
-static int int3401_add(struct platform_device *pdev)
+int proc_thermal_resume(struct device *dev)
{
- struct proc_thermal_device *proc_priv;
- int ret;
-
- if (proc_thermal_emum_mode == PROC_THERMAL_PCI) {
- dev_err(&pdev->dev, "error: enumerated as PCI dev\n");
- return -ENODEV;
- }
-
- ret = proc_thermal_add(&pdev->dev, &proc_priv);
- if (ret)
- return ret;
-
- platform_set_drvdata(pdev, proc_priv);
- proc_thermal_emum_mode = PROC_THERMAL_PLATFORM_DEV;
-
- dev_info(&pdev->dev, "Creating sysfs group for PROC_THERMAL_PLATFORM_DEV\n");
-
- ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr);
- if (ret)
- return ret;
-
- ret = sysfs_create_group(&pdev->dev.kobj, &power_limit_attribute_group);
- if (ret)
- sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr);
+ struct proc_thermal_device *proc_dev;
- return ret;
-}
+ proc_dev = dev_get_drvdata(dev);
+ proc_thermal_read_ppcc(proc_dev);
-static int int3401_remove(struct platform_device *pdev)
-{
- proc_thermal_remove(platform_get_drvdata(pdev));
+ tcc_offset_update(tcc_offset_save);
return 0;
}
-
-static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid)
-{
- struct proc_thermal_device *proc_priv;
- struct pci_dev *pdev = devid;
-
- proc_priv = pci_get_drvdata(pdev);
-
- intel_soc_dts_iosf_interrupt_handler(proc_priv->soc_dts);
-
- return IRQ_HANDLED;
-}
+EXPORT_SYMBOL_GPL(proc_thermal_resume);
#define MCHBAR 0
-static int proc_thermal_set_mmio_base(struct pci_dev *pdev,
- struct proc_thermal_device *proc_priv)
+static int proc_thermal_set_mmio_base(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
{
int ret;
@@ -423,9 +375,9 @@ static int proc_thermal_set_mmio_base(struct pci_dev *pdev,
return 0;
}
-static int proc_thermal_mmio_add(struct pci_dev *pdev,
- struct proc_thermal_device *proc_priv,
- kernel_ulong_t feature_mask)
+int proc_thermal_mmio_add(struct pci_dev *pdev,
+ struct proc_thermal_device *proc_priv,
+ kernel_ulong_t feature_mask)
{
int ret;
@@ -471,11 +423,10 @@ err_rem_rapl:
return ret;
}
+EXPORT_SYMBOL_GPL(proc_thermal_mmio_add);
-static void proc_thermal_mmio_remove(struct pci_dev *pdev)
+void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
{
- struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
-
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL)
proc_thermal_rapl_remove();
@@ -486,181 +437,7 @@ static void proc_thermal_mmio_remove(struct pci_dev *pdev)
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MBOX)
proc_thermal_mbox_remove(pdev);
}
-
-static int proc_thermal_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- struct proc_thermal_device *proc_priv;
- int ret;
-
- if (proc_thermal_emum_mode == PROC_THERMAL_PLATFORM_DEV) {
- dev_err(&pdev->dev, "error: enumerated as platform dev\n");
- return -ENODEV;
- }
-
- 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;
-
- pci_set_drvdata(pdev, proc_priv);
- proc_thermal_emum_mode = PROC_THERMAL_PCI;
-
- if (pdev->device == PCI_DEVICE_ID_INTEL_BSW_THERMAL) {
- /*
- * Enumerate additional DTS sensors available via IOSF.
- * But we are not treating as a failure condition, if
- * there are no aux DTSs enabled or fails. This driver
- * already exposes sensors, which can be accessed via
- * ACPI/MSR. So we don't want to fail for auxiliary DTSs.
- */
- proc_priv->soc_dts = intel_soc_dts_iosf_init(
- INTEL_SOC_DTS_INTERRUPT_MSI, 2, 0);
-
- if (!IS_ERR(proc_priv->soc_dts) && pdev->irq) {
- ret = pci_enable_msi(pdev);
- if (!ret) {
- ret = request_threaded_irq(pdev->irq, NULL,
- proc_thermal_pci_msi_irq,
- IRQF_ONESHOT, "proc_thermal",
- pdev);
- if (ret) {
- intel_soc_dts_iosf_exit(
- proc_priv->soc_dts);
- pci_disable_msi(pdev);
- proc_priv->soc_dts = NULL;
- }
- }
- } else
- dev_err(&pdev->dev, "No auxiliary DTSs enabled\n");
- }
-
- dev_info(&pdev->dev, "Creating sysfs group for PROC_THERMAL_PCI\n");
-
- ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr);
- if (ret)
- return ret;
-
- ret = sysfs_create_group(&pdev->dev.kobj, &power_limit_attribute_group);
- if (ret) {
- sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr);
- return ret;
- }
-
- ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
- if (ret) {
- proc_thermal_remove(proc_priv);
- return ret;
- }
-
- return 0;
-}
-
-static void proc_thermal_pci_remove(struct pci_dev *pdev)
-{
- struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
-
- if (proc_priv->soc_dts) {
- intel_soc_dts_iosf_exit(proc_priv->soc_dts);
- if (pdev->irq) {
- free_irq(pdev->irq, pdev);
- pci_disable_msi(pdev);
- }
- }
-
- proc_thermal_mmio_remove(pdev);
- proc_thermal_remove(proc_priv);
-}
-
-#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);
-
- tcc_offset_update(tcc_offset_save);
-
- 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_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) },
- { PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
- { PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
- { PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
- { PCI_DEVICE_DATA(INTEL, BXT1_THERMAL, 0) },
- { PCI_DEVICE_DATA(INTEL, BXTX_THERMAL, 0) },
- { PCI_DEVICE_DATA(INTEL, BXTP_THERMAL, 0) },
- { PCI_DEVICE_DATA(INTEL, CNL_THERMAL, 0) },
- { PCI_DEVICE_DATA(INTEL, CFL_THERMAL, 0) },
- { PCI_DEVICE_DATA(INTEL, GLK_THERMAL, 0) },
- { PCI_DEVICE_DATA(INTEL, HSB_THERMAL, 0) },
- { PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
- { PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
- { PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
- { PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_MBOX) },
- { },
-};
-
-MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
-
-static struct pci_driver proc_thermal_pci_driver = {
- .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[] = {
- {"INT3401", 0},
- {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, int3401_device_ids);
-
-static struct platform_driver int3401_driver = {
- .probe = int3401_add,
- .remove = int3401_remove,
- .driver = {
- .name = "int3401 thermal",
- .acpi_match_table = int3401_device_ids,
- .pm = &proc_thermal_pm,
- },
-};
-
-static int __init proc_thermal_init(void)
-{
- int ret;
-
- ret = platform_driver_register(&int3401_driver);
- if (ret)
- return ret;
-
- ret = pci_register_driver(&proc_thermal_pci_driver);
-
- return ret;
-}
-
-static void __exit proc_thermal_exit(void)
-{
- platform_driver_unregister(&int3401_driver);
- pci_unregister_driver(&proc_thermal_pci_driver);
-}
-
-module_init(proc_thermal_init);
-module_exit(proc_thermal_exit);
+EXPORT_SYMBOL_GPL(proc_thermal_mmio_remove);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
index b9ed64561aaf..5a1cfe4864f1 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
@@ -44,6 +44,7 @@ struct proc_thermal_device {
struct intel_soc_dts_sensors *soc_dts;
u32 mmio_feature_mask;
void __iomem *mmio_base;
+ void *priv_data;
};
struct rapl_mmio_regs {
@@ -79,4 +80,12 @@ void proc_thermal_rfim_remove(struct pci_dev *pdev);
int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
void proc_thermal_mbox_remove(struct pci_dev *pdev);
+int processor_thermal_send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp);
+int proc_thermal_add(struct device *dev, struct proc_thermal_device *priv);
+void proc_thermal_remove(struct proc_thermal_device *proc_priv);
+int proc_thermal_resume(struct device *dev);
+int proc_thermal_mmio_add(struct pci_dev *pdev,
+ struct proc_thermal_device *proc_priv,
+ kernel_ulong_t feature_mask);
+void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
#endif
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
new file mode 100644
index 000000000000..11dd2e825f4f
--- /dev/null
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
@@ -0,0 +1,373 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Processor thermal device for newer processors
+ * Copyright (c) 2020, Intel Corporation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/thermal.h>
+
+#include "int340x_thermal_zone.h"
+#include "processor_thermal_device.h"
+
+#define DRV_NAME "proc_thermal_pci"
+
+struct proc_thermal_pci {
+ struct pci_dev *pdev;
+ struct proc_thermal_device *proc_priv;
+ struct thermal_zone_device *tzone;
+ struct delayed_work work;
+ int stored_thres;
+ int no_legacy;
+};
+
+enum proc_thermal_mmio_type {
+ PROC_THERMAL_MMIO_TJMAX,
+ PROC_THERMAL_MMIO_PP0_TEMP,
+ PROC_THERMAL_MMIO_PP1_TEMP,
+ PROC_THERMAL_MMIO_PKG_TEMP,
+ PROC_THERMAL_MMIO_THRES_0,
+ PROC_THERMAL_MMIO_THRES_1,
+ PROC_THERMAL_MMIO_INT_ENABLE_0,
+ PROC_THERMAL_MMIO_INT_ENABLE_1,
+ PROC_THERMAL_MMIO_INT_STATUS_0,
+ PROC_THERMAL_MMIO_INT_STATUS_1,
+ PROC_THERMAL_MMIO_MAX
+};
+
+struct proc_thermal_mmio_info {
+ enum proc_thermal_mmio_type mmio_type;
+ u64 mmio_addr;
+ u64 shift;
+ u64 mask;
+};
+
+static struct proc_thermal_mmio_info proc_thermal_mmio_info[] = {
+ { PROC_THERMAL_MMIO_TJMAX, 0x599c, 16, 0xff },
+ { PROC_THERMAL_MMIO_PP0_TEMP, 0x597c, 0, 0xff },
+ { PROC_THERMAL_MMIO_PP1_TEMP, 0x5980, 0, 0xff },
+ { PROC_THERMAL_MMIO_PKG_TEMP, 0x5978, 0, 0xff },
+ { PROC_THERMAL_MMIO_THRES_0, 0x5820, 8, 0x7F },
+ { PROC_THERMAL_MMIO_THRES_1, 0x5820, 16, 0x7F },
+ { PROC_THERMAL_MMIO_INT_ENABLE_0, 0x5820, 15, 0x01 },
+ { PROC_THERMAL_MMIO_INT_ENABLE_1, 0x5820, 23, 0x01 },
+ { PROC_THERMAL_MMIO_INT_STATUS_0, 0x7200, 6, 0x01 },
+ { PROC_THERMAL_MMIO_INT_STATUS_1, 0x7200, 8, 0x01 },
+};
+
+#define B0D4_THERMAL_NOTIFY_DELAY 1000
+static int notify_delay_ms = B0D4_THERMAL_NOTIFY_DELAY;
+
+static void proc_thermal_mmio_read(struct proc_thermal_pci *pci_info,
+ enum proc_thermal_mmio_type type,
+ u32 *value)
+{
+ *value = ioread32(((u8 __iomem *)pci_info->proc_priv->mmio_base +
+ proc_thermal_mmio_info[type].mmio_addr));
+ *value >>= proc_thermal_mmio_info[type].shift;
+ *value &= proc_thermal_mmio_info[type].mask;
+}
+
+static void proc_thermal_mmio_write(struct proc_thermal_pci *pci_info,
+ enum proc_thermal_mmio_type type,
+ u32 value)
+{
+ u32 current_val;
+ u32 mask;
+
+ current_val = ioread32(((u8 __iomem *)pci_info->proc_priv->mmio_base +
+ proc_thermal_mmio_info[type].mmio_addr));
+ mask = proc_thermal_mmio_info[type].mask << proc_thermal_mmio_info[type].shift;
+ current_val &= ~mask;
+
+ value &= proc_thermal_mmio_info[type].mask;
+ value <<= proc_thermal_mmio_info[type].shift;
+
+ current_val |= value;
+ iowrite32(current_val, ((u8 __iomem *)pci_info->proc_priv->mmio_base +
+ proc_thermal_mmio_info[type].mmio_addr));
+}
+
+/*
+ * To avoid sending two many messages to user space, we have 1 second delay.
+ * On interrupt we are disabling interrupt and enabling after 1 second.
+ * This workload function is delayed by 1 second.
+ */
+static void proc_thermal_threshold_work_fn(struct work_struct *work)
+{
+ struct delayed_work *delayed_work = to_delayed_work(work);
+ struct proc_thermal_pci *pci_info = container_of(delayed_work,
+ struct proc_thermal_pci, work);
+ struct thermal_zone_device *tzone = pci_info->tzone;
+
+ if (tzone)
+ thermal_zone_device_update(tzone, THERMAL_TRIP_VIOLATED);
+
+ /* Enable interrupt flag */
+ proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1);
+}
+
+static void pkg_thermal_schedule_work(struct delayed_work *work)
+{
+ unsigned long ms = msecs_to_jiffies(notify_delay_ms);
+
+ schedule_delayed_work(work, ms);
+}
+
+static irqreturn_t proc_thermal_irq_handler(int irq, void *devid)
+{
+ struct proc_thermal_pci *pci_info = devid;
+ u32 status;
+
+ proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_INT_STATUS_0, &status);
+
+ /* Disable enable interrupt flag */
+ proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
+ pci_write_config_byte(pci_info->pdev, 0xdc, 0x01);
+
+ pkg_thermal_schedule_work(&pci_info->work);
+
+ return IRQ_HANDLED;
+}
+
+static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
+{
+ struct proc_thermal_pci *pci_info = tzd->devdata;
+ u32 _temp;
+
+ proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_PKG_TEMP, &_temp);
+ *temp = (unsigned long)_temp * 1000;
+
+ return 0;
+}
+
+static int sys_get_trip_temp(struct thermal_zone_device *tzd,
+ int trip, int *temp)
+{
+ struct proc_thermal_pci *pci_info = tzd->devdata;
+ u32 _temp;
+
+ proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_THRES_0, &_temp);
+ if (!_temp) {
+ *temp = THERMAL_TEMP_INVALID;
+ } else {
+ int tjmax;
+
+ proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax);
+ _temp = tjmax - _temp;
+ *temp = (unsigned long)_temp * 1000;
+ }
+
+ return 0;
+}
+
+static int sys_get_trip_type(struct thermal_zone_device *tzd, int trip,
+ enum thermal_trip_type *type)
+{
+ *type = THERMAL_TRIP_PASSIVE;
+
+ return 0;
+}
+
+static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp)
+{
+ struct proc_thermal_pci *pci_info = tzd->devdata;
+ int tjmax, _temp;
+
+ if (temp <= 0) {
+ cancel_delayed_work_sync(&pci_info->work);
+ proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
+ proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0);
+ thermal_zone_device_disable(tzd);
+ pci_info->stored_thres = 0;
+ return 0;
+ }
+
+ proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax);
+ _temp = tjmax - (temp / 1000);
+ if (_temp < 0)
+ return -EINVAL;
+
+ proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, _temp);
+ proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1);
+
+ thermal_zone_device_enable(tzd);
+ pci_info->stored_thres = temp;
+
+ return 0;
+}
+
+static struct thermal_zone_device_ops tzone_ops = {
+ .get_temp = sys_get_curr_temp,
+ .get_trip_temp = sys_get_trip_temp,
+ .get_trip_type = sys_get_trip_type,
+ .set_trip_temp = sys_set_trip_temp,
+};
+
+static struct thermal_zone_params tzone_params = {
+ .governor_name = "user_space",
+ .no_hwmon = true,
+};
+
+static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct proc_thermal_device *proc_priv;
+ struct proc_thermal_pci *pci_info;
+ int irq_flag = 0, irq, ret;
+
+ proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
+ if (!proc_priv)
+ return -ENOMEM;
+
+ pci_info = devm_kzalloc(&pdev->dev, sizeof(*pci_info), GFP_KERNEL);
+ if (!pci_info)
+ return -ENOMEM;
+
+ pci_info->pdev = pdev;
+ ret = pcim_enable_device(pdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "error: could not enable device\n");
+ return ret;
+ }
+
+ pci_set_master(pdev);
+
+ INIT_DELAYED_WORK(&pci_info->work, proc_thermal_threshold_work_fn);
+
+ ret = proc_thermal_add(&pdev->dev, proc_priv);
+ if (ret) {
+ dev_err(&pdev->dev, "error: proc_thermal_add, will continue\n");
+ pci_info->no_legacy = 1;
+ }
+
+ proc_priv->priv_data = pci_info;
+ pci_info->proc_priv = proc_priv;
+ pci_set_drvdata(pdev, proc_priv);
+
+ ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
+ if (ret)
+ goto err_ret_thermal;
+
+ pci_info->tzone = thermal_zone_device_register("TCPU_PCI", 1, 1, pci_info,
+ &tzone_ops,
+ &tzone_params, 0, 0);
+ if (IS_ERR(pci_info->tzone)) {
+ ret = PTR_ERR(pci_info->tzone);
+ goto err_ret_mmio;
+ }
+
+ /* request and enable interrupt */
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to allocate vectors!\n");
+ goto err_ret_tzone;
+ }
+ if (!pdev->msi_enabled && !pdev->msix_enabled)
+ irq_flag = IRQF_SHARED;
+
+ irq = pci_irq_vector(pdev, 0);
+ ret = devm_request_threaded_irq(&pdev->dev, irq,
+ proc_thermal_irq_handler, NULL,
+ irq_flag, KBUILD_MODNAME, pci_info);
+ if (ret) {
+ dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq);
+ goto err_free_vectors;
+ }
+
+ return 0;
+
+err_free_vectors:
+ pci_free_irq_vectors(pdev);
+err_ret_tzone:
+ thermal_zone_device_unregister(pci_info->tzone);
+err_ret_mmio:
+ proc_thermal_mmio_remove(pdev, proc_priv);
+err_ret_thermal:
+ if (!pci_info->no_legacy)
+ proc_thermal_remove(proc_priv);
+ pci_disable_device(pdev);
+
+ return ret;
+}
+
+static void proc_thermal_pci_remove(struct pci_dev *pdev)
+{
+ struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
+ struct proc_thermal_pci *pci_info = proc_priv->priv_data;
+
+ cancel_delayed_work_sync(&pci_info->work);
+
+ proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0);
+ proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
+
+ devm_free_irq(&pdev->dev, pdev->irq, pci_info);
+ pci_free_irq_vectors(pdev);
+
+ thermal_zone_device_unregister(pci_info->tzone);
+ proc_thermal_mmio_remove(pdev, pci_info->proc_priv);
+ if (!pci_info->no_legacy)
+ proc_thermal_remove(proc_priv);
+ pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int proc_thermal_pci_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct proc_thermal_device *proc_priv;
+ struct proc_thermal_pci *pci_info;
+
+ proc_priv = pci_get_drvdata(pdev);
+ pci_info = proc_priv->priv_data;
+
+ if (pci_info->stored_thres) {
+ proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0,
+ pci_info->stored_thres / 1000);
+ proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1);
+ }
+
+ if (!pci_info->no_legacy)
+ return proc_thermal_resume(dev);
+
+ return 0;
+}
+#else
+#define proc_thermal_pci_resume NULL
+#endif
+
+static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, NULL, proc_thermal_pci_resume);
+
+static const struct pci_device_id proc_thermal_pci_ids[] = {
+ { PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) },
+ { },
+};
+
+MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
+
+static struct pci_driver proc_thermal_pci_driver = {
+ .name = DRV_NAME,
+ .probe = proc_thermal_pci_probe,
+ .remove = proc_thermal_pci_remove,
+ .id_table = proc_thermal_pci_ids,
+ .driver.pm = &proc_thermal_pci_pm,
+};
+
+static int __init proc_thermal_init(void)
+{
+ return pci_register_driver(&proc_thermal_pci_driver);
+}
+
+static void __exit proc_thermal_exit(void)
+{
+ pci_unregister_driver(&proc_thermal_pci_driver);
+}
+
+module_init(proc_thermal_init);
+module_exit(proc_thermal_exit);
+
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c
new file mode 100644
index 000000000000..f5fc1791b11e
--- /dev/null
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * B0D4 processor thermal device
+ * Copyright (c) 2020, Intel Corporation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/thermal.h>
+
+#include "int340x_thermal_zone.h"
+#include "processor_thermal_device.h"
+#include "../intel_soc_dts_iosf.h"
+
+#define DRV_NAME "proc_thermal"
+
+static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid)
+{
+ struct proc_thermal_device *proc_priv;
+ struct pci_dev *pdev = devid;
+
+ proc_priv = pci_get_drvdata(pdev);
+
+ intel_soc_dts_iosf_interrupt_handler(proc_priv->soc_dts);
+
+ return IRQ_HANDLED;
+}
+
+static int proc_thermal_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct proc_thermal_device *proc_priv;
+ int ret;
+
+ ret = pcim_enable_device(pdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "error: could not enable device\n");
+ return ret;
+ }
+
+ proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
+ if (!proc_priv)
+ return -ENOMEM;
+
+ ret = proc_thermal_add(&pdev->dev, proc_priv);
+ if (ret)
+ return ret;
+
+ pci_set_drvdata(pdev, proc_priv);
+
+ if (pdev->device == PCI_DEVICE_ID_INTEL_BSW_THERMAL) {
+ /*
+ * Enumerate additional DTS sensors available via IOSF.
+ * But we are not treating as a failure condition, if
+ * there are no aux DTSs enabled or fails. This driver
+ * already exposes sensors, which can be accessed via
+ * ACPI/MSR. So we don't want to fail for auxiliary DTSs.
+ */
+ proc_priv->soc_dts = intel_soc_dts_iosf_init(
+ INTEL_SOC_DTS_INTERRUPT_MSI, 2, 0);
+
+ if (!IS_ERR(proc_priv->soc_dts) && pdev->irq) {
+ ret = pci_enable_msi(pdev);
+ if (!ret) {
+ ret = request_threaded_irq(pdev->irq, NULL,
+ proc_thermal_pci_msi_irq,
+ IRQF_ONESHOT, "proc_thermal",
+ pdev);
+ if (ret) {
+ intel_soc_dts_iosf_exit(
+ proc_priv->soc_dts);
+ pci_disable_msi(pdev);
+ proc_priv->soc_dts = NULL;
+ }
+ }
+ } else
+ dev_err(&pdev->dev, "No auxiliary DTSs enabled\n");
+ } else {
+
+ }
+
+ ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
+ if (ret) {
+ proc_thermal_remove(proc_priv);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void proc_thermal_pci_remove(struct pci_dev *pdev)
+{
+ struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
+
+ if (proc_priv->soc_dts) {
+ intel_soc_dts_iosf_exit(proc_priv->soc_dts);
+ if (pdev->irq) {
+ free_irq(pdev->irq, pdev);
+ pci_disable_msi(pdev);
+ }
+ }
+
+ proc_thermal_mmio_remove(pdev, proc_priv);
+ proc_thermal_remove(proc_priv);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int proc_thermal_pci_resume(struct device *dev)
+{
+ return proc_thermal_resume(dev);
+}
+#else
+#define proc_thermal_pci_resume NULL
+#endif
+
+static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, NULL, proc_thermal_pci_resume);
+
+static const struct pci_device_id proc_thermal_pci_ids[] = {
+ { PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
+ { PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
+ { PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
+ { PCI_DEVICE_DATA(INTEL, BXT1_THERMAL, 0) },
+ { PCI_DEVICE_DATA(INTEL, BXTX_THERMAL, 0) },
+ { PCI_DEVICE_DATA(INTEL, BXTP_THERMAL, 0) },
+ { PCI_DEVICE_DATA(INTEL, CNL_THERMAL, 0) },
+ { PCI_DEVICE_DATA(INTEL, CFL_THERMAL, 0) },
+ { PCI_DEVICE_DATA(INTEL, GLK_THERMAL, 0) },
+ { PCI_DEVICE_DATA(INTEL, HSB_THERMAL, 0) },
+ { PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
+ { PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
+ { PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
+ { PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_MBOX) },
+ { },
+};
+
+MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
+
+static struct pci_driver proc_thermal_pci_driver = {
+ .name = DRV_NAME,
+ .probe = proc_thermal_pci_probe,
+ .remove = proc_thermal_pci_remove,
+ .id_table = proc_thermal_pci_ids,
+ .driver.pm = &proc_thermal_pci_pm,
+};
+
+static int __init proc_thermal_init(void)
+{
+ return pci_register_driver(&proc_thermal_pci_driver);
+}
+
+static void __exit proc_thermal_exit(void)
+{
+ pci_unregister_driver(&proc_thermal_pci_driver);
+}
+
+module_init(proc_thermal_init);
+module_exit(proc_thermal_exit);
+
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
index 990f51f22884..59e93b04f0a9 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
@@ -23,7 +23,7 @@
static DEFINE_MUTEX(mbox_lock);
-static int send_mbox_cmd(struct pci_dev *pdev, u8 cmd_id, u32 cmd_data, u8 *cmd_resp)
+static int send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp)
{
struct proc_thermal_device *proc_priv;
u32 retries, data;
@@ -82,6 +82,12 @@ unlock_mbox:
return ret;
}
+int processor_thermal_send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp)
+{
+ return send_mbox_cmd(pdev, cmd_id, cmd_data, cmd_resp);
+}
+EXPORT_SYMBOL_GPL(processor_thermal_send_mbox_cmd);
+
/* List of workload types */
static const char * const workload_types[] = {
"none",
@@ -147,7 +153,7 @@ static ssize_t workload_type_show(struct device *dev,
char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
- u8 cmd_resp;
+ u32 cmd_resp;
int ret;
ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp);
@@ -181,7 +187,7 @@ static bool workload_req_created;
int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
{
- u8 cmd_resp;
+ u32 cmd_resp;
int ret;
/* Check if there is a mailbox support, if fails return success */
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
index aef993a813e2..2b8a3235d518 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
@@ -190,6 +190,59 @@ static DEVICE_ATTR_RO(ddr_data_rate_point_2);
static DEVICE_ATTR_RO(ddr_data_rate_point_3);
static DEVICE_ATTR_RW(rfi_disable);
+static ssize_t rfi_restriction_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u16 cmd_id = 0x0008;
+ u32 cmd_resp;
+ u32 input;
+ int ret;
+
+ ret = kstrtou32(buf, 10, &input);
+ if (ret)
+ return ret;
+
+ ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, input, &cmd_resp);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t rfi_restriction_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ u16 cmd_id = 0x0007;
+ u32 cmd_resp;
+ int ret;
+
+ ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, 0, &cmd_resp);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", cmd_resp);
+}
+
+static ssize_t ddr_data_rate_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ u16 cmd_id = 0x0107;
+ u32 cmd_resp;
+ int ret;
+
+ ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, 0, &cmd_resp);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", cmd_resp);
+}
+
+static DEVICE_ATTR_RW(rfi_restriction);
+static DEVICE_ATTR_RO(ddr_data_rate);
+
static struct attribute *dvfs_attrs[] = {
&dev_attr_rfi_restriction_run_busy.attr,
&dev_attr_rfi_restriction_err_code.attr,
@@ -199,6 +252,8 @@ static struct attribute *dvfs_attrs[] = {
&dev_attr_ddr_data_rate_point_2.attr,
&dev_attr_ddr_data_rate_point_3.attr,
&dev_attr_rfi_disable.attr,
+ &dev_attr_ddr_data_rate.attr,
+ &dev_attr_rfi_restriction.attr,
NULL
};
diff --git a/drivers/thermal/intel/intel_soc_dts_iosf.c b/drivers/thermal/intel/intel_soc_dts_iosf.c
index 4f1a2f7c016c..342b0bb5a56d 100644
--- a/drivers/thermal/intel/intel_soc_dts_iosf.c
+++ b/drivers/thermal/intel/intel_soc_dts_iosf.c
@@ -350,13 +350,14 @@ int intel_soc_dts_iosf_add_read_only_critical_trip(
int i, j;
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
- for (j = 0; j < sensors->soc_dts[i].trip_count; ++j) {
- if (!(sensors->soc_dts[i].trip_mask & BIT(j))) {
- return update_trip_temp(&sensors->soc_dts[i], j,
- sensors->tj_max - critical_offset,
- THERMAL_TRIP_CRITICAL);
- }
- }
+ struct intel_soc_dts_sensor_entry *entry = &sensors->soc_dts[i];
+ int temp = sensors->tj_max - critical_offset;
+ unsigned long count = entry->trip_count;
+ unsigned long mask = entry->trip_mask;
+
+ j = find_first_zero_bit(&mask, count);
+ if (j < count)
+ return update_trip_temp(entry, j, temp, THERMAL_TRIP_CRITICAL);
}
return -EINVAL;
diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c
index 97e8678ccf0e..ede94eadddda 100644
--- a/drivers/thermal/mtk_thermal.c
+++ b/drivers/thermal/mtk_thermal.c
@@ -23,6 +23,8 @@
#include <linux/reset.h>
#include <linux/types.h>
+#include "thermal_hwmon.h"
+
/* AUXADC Registers */
#define AUXADC_CON1_SET_V 0x008
#define AUXADC_CON1_CLR_V 0x00c
@@ -1087,6 +1089,10 @@ static int mtk_thermal_probe(struct platform_device *pdev)
goto err_disable_clk_peri_therm;
}
+ ret = devm_thermal_add_hwmon_sysfs(tzdev);
+ if (ret)
+ dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs");
+
return 0;
err_disable_clk_peri_therm:
diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c
index e1e412348076..fdf16aa34eb4 100644
--- a/drivers/thermal/rcar_gen3_thermal.c
+++ b/drivers/thermal/rcar_gen3_thermal.c
@@ -143,7 +143,7 @@ static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc,
* Division is not scaled in BSP and if scaled it might overflow
* the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled
*/
- tsc->tj_t = (FIXPT_INT((ptat[1] - ptat[2]) * 157)
+ tsc->tj_t = (FIXPT_INT((ptat[1] - ptat[2]) * (ths_tj_1 - TJ_3))
/ (ptat[0] - ptat[2])) + FIXPT_INT(TJ_3);
tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]),
@@ -307,7 +307,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
{
struct rcar_gen3_thermal_priv *priv;
struct device *dev = &pdev->dev;
- const int *rcar_gen3_ths_tj_1 = of_device_get_match_data(dev);
+ const int *ths_tj_1 = of_device_get_match_data(dev);
struct resource *res;
struct thermal_zone_device *zone;
int ret, i;
@@ -352,8 +352,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
priv->tscs[i] = tsc;
priv->thermal_init(tsc);
- rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i],
- *rcar_gen3_ths_tj_1);
+ rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1);
zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
&rcar_gen3_tz_of_ops);
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
index aa9e0e31ef98..657d84b9963e 100644
--- a/drivers/thermal/rockchip_thermal.c
+++ b/drivers/thermal/rockchip_thermal.c
@@ -211,7 +211,11 @@ struct rockchip_thermal_data {
#define TSADCV3_AUTO_PERIOD_TIME 1875 /* 2.5ms */
#define TSADCV3_AUTO_PERIOD_HT_TIME 1875 /* 2.5ms */
+#define TSADCV5_AUTO_PERIOD_TIME 1622 /* 2.5ms */
+#define TSADCV5_AUTO_PERIOD_HT_TIME 1622 /* 2.5ms */
+
#define TSADCV2_USER_INTER_PD_SOC 0x340 /* 13 clocks */
+#define TSADCV5_USER_INTER_PD_SOC 0xfc0 /* 97us, at least 90us */
#define GRF_SARADC_TESTBIT 0x0e644
#define GRF_TSADC_TESTBIT_L 0x0e648
@@ -219,6 +223,12 @@ struct rockchip_thermal_data {
#define PX30_GRF_SOC_CON2 0x0408
+#define RK3568_GRF_TSADC_CON 0x0600
+#define RK3568_GRF_TSADC_ANA_REG0 (0x10001 << 0)
+#define RK3568_GRF_TSADC_ANA_REG1 (0x10001 << 1)
+#define RK3568_GRF_TSADC_ANA_REG2 (0x10001 << 2)
+#define RK3568_GRF_TSADC_TSEN (0x10001 << 8)
+
#define GRF_SARADC_TESTBIT_ON (0x10001 << 2)
#define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2)
#define GRF_TSADC_VCM_EN_L (0x10001 << 7)
@@ -474,6 +484,45 @@ static const struct tsadc_table rk3399_code_table[] = {
{TSADCV3_DATA_MASK, 125000},
};
+static const struct tsadc_table rk3568_code_table[] = {
+ {0, -40000},
+ {1584, -40000},
+ {1620, -35000},
+ {1652, -30000},
+ {1688, -25000},
+ {1720, -20000},
+ {1756, -15000},
+ {1788, -10000},
+ {1824, -5000},
+ {1856, 0},
+ {1892, 5000},
+ {1924, 10000},
+ {1956, 15000},
+ {1992, 20000},
+ {2024, 25000},
+ {2060, 30000},
+ {2092, 35000},
+ {2128, 40000},
+ {2160, 45000},
+ {2196, 50000},
+ {2228, 55000},
+ {2264, 60000},
+ {2300, 65000},
+ {2332, 70000},
+ {2368, 75000},
+ {2400, 80000},
+ {2436, 85000},
+ {2468, 90000},
+ {2500, 95000},
+ {2536, 100000},
+ {2572, 105000},
+ {2604, 110000},
+ {2636, 115000},
+ {2672, 120000},
+ {2704, 125000},
+ {TSADCV2_DATA_MASK, 125000},
+};
+
static u32 rk_tsadcv2_temp_to_code(const struct chip_tsadc_table *table,
int temp)
{
@@ -701,6 +750,49 @@ static void rk_tsadcv4_initialize(struct regmap *grf, void __iomem *regs,
regmap_write(grf, PX30_GRF_SOC_CON2, GRF_CON_TSADC_CH_INV);
}
+static void rk_tsadcv7_initialize(struct regmap *grf, void __iomem *regs,
+ enum tshut_polarity tshut_polarity)
+{
+ writel_relaxed(TSADCV5_USER_INTER_PD_SOC, regs + TSADCV2_USER_CON);
+ writel_relaxed(TSADCV5_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
+ writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT,
+ regs + TSADCV2_HIGHT_INT_DEBOUNCE);
+ writel_relaxed(TSADCV5_AUTO_PERIOD_HT_TIME,
+ regs + TSADCV2_AUTO_PERIOD_HT);
+ writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT,
+ regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE);
+
+ if (tshut_polarity == TSHUT_HIGH_ACTIVE)
+ writel_relaxed(0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH,
+ regs + TSADCV2_AUTO_CON);
+ else
+ writel_relaxed(0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH,
+ regs + TSADCV2_AUTO_CON);
+
+ /*
+ * The general register file will is optional
+ * and might not be available.
+ */
+ if (!IS_ERR(grf)) {
+ regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_TSEN);
+ /*
+ * RK3568 TRM, section 18.5. requires a delay no less
+ * than 10us between the rising edge of tsadc_tsen_en
+ * and the rising edge of tsadc_ana_reg_0/1/2.
+ */
+ udelay(15);
+ regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG0);
+ regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG1);
+ regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG2);
+
+ /*
+ * RK3568 TRM, section 18.5. requires a delay no less
+ * than 90us after the rising edge of tsadc_ana_reg_0/1/2.
+ */
+ usleep_range(100, 200);
+ }
+}
+
static void rk_tsadcv2_irq_ack(void __iomem *regs)
{
u32 val;
@@ -1027,6 +1119,31 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = {
},
};
+static const struct rockchip_tsadc_chip rk3568_tsadc_data = {
+ .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */
+ .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */
+ .chn_num = 2, /* two channels for tsadc */
+
+ .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */
+ .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */
+ .tshut_temp = 95000,
+
+ .initialize = rk_tsadcv7_initialize,
+ .irq_ack = rk_tsadcv3_irq_ack,
+ .control = rk_tsadcv3_control,
+ .get_temp = rk_tsadcv2_get_temp,
+ .set_alarm_temp = rk_tsadcv2_alarm_temp,
+ .set_tshut_temp = rk_tsadcv2_tshut_temp,
+ .set_tshut_mode = rk_tsadcv2_tshut_mode,
+
+ .table = {
+ .id = rk3568_code_table,
+ .length = ARRAY_SIZE(rk3568_code_table),
+ .data_mask = TSADCV2_DATA_MASK,
+ .mode = ADC_INCREMENT,
+ },
+};
+
static const struct of_device_id of_rockchip_thermal_match[] = {
{ .compatible = "rockchip,px30-tsadc",
.data = (void *)&px30_tsadc_data,
@@ -1059,6 +1176,10 @@ static const struct of_device_id of_rockchip_thermal_match[] = {
.compatible = "rockchip,rk3399-tsadc",
.data = (void *)&rk3399_tsadc_data,
},
+ {
+ .compatible = "rockchip,rk3568-tsadc",
+ .data = (void *)&rk3568_tsadc_data,
+ },
{ /* end */ },
};
MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
diff --git a/drivers/thermal/sprd_thermal.c b/drivers/thermal/sprd_thermal.c
index 3682edb2f466..fff80fc18002 100644
--- a/drivers/thermal/sprd_thermal.c
+++ b/drivers/thermal/sprd_thermal.c
@@ -388,7 +388,7 @@ static int sprd_thm_probe(struct platform_device *pdev)
sen = devm_kzalloc(&pdev->dev, sizeof(*sen), GFP_KERNEL);
if (!sen) {
ret = -ENOMEM;
- goto disable_clk;
+ goto of_put;
}
sen->data = thm;
@@ -397,13 +397,13 @@ static int sprd_thm_probe(struct platform_device *pdev)
ret = of_property_read_u32(sen_child, "reg", &sen->id);
if (ret) {
dev_err(&pdev->dev, "get sensor reg failed");
- goto disable_clk;
+ goto of_put;
}
ret = sprd_thm_sensor_calibration(sen_child, thm, sen);
if (ret) {
dev_err(&pdev->dev, "efuse cal analysis failed");
- goto disable_clk;
+ goto of_put;
}
sprd_thm_sensor_init(thm, sen);
@@ -416,19 +416,20 @@ static int sprd_thm_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "register thermal zone failed %d\n",
sen->id);
ret = PTR_ERR(sen->tzd);
- goto disable_clk;
+ goto of_put;
}
thm->sensor[sen->id] = sen;
}
+ /* sen_child set to NULL at this point */
ret = sprd_thm_set_ready(thm);
if (ret)
- goto disable_clk;
+ goto of_put;
ret = sprd_thm_wait_temp_ready(thm);
if (ret)
- goto disable_clk;
+ goto of_put;
for (i = 0; i < thm->nr_sensors; i++)
sprd_thm_toggle_sensor(thm->sensor[i], true);
@@ -436,6 +437,8 @@ static int sprd_thm_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, thm);
return 0;
+of_put:
+ of_node_put(sen_child);
disable_clk:
clk_disable_unprepare(thm->clk);
return ret;
@@ -532,6 +535,7 @@ static const struct of_device_id sprd_thermal_of_match[] = {
{ .compatible = "sprd,ums512-thermal", .data = &ums512_data },
{ },
};
+MODULE_DEVICE_TABLE(of, sprd_thermal_of_match);
static const struct dev_pm_ops sprd_thermal_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(sprd_thm_suspend, sprd_thm_resume)
diff --git a/drivers/thermal/st/st_thermal_memmap.c b/drivers/thermal/st/st_thermal_memmap.c
index a0114452d11f..d68596c40be9 100644
--- a/drivers/thermal/st/st_thermal_memmap.c
+++ b/drivers/thermal/st/st_thermal_memmap.c
@@ -119,19 +119,10 @@ static int st_mmap_regmap_init(struct st_thermal_sensor *sensor)
{
struct device *dev = sensor->dev;
struct platform_device *pdev = to_platform_device(dev);
- struct resource *res;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "no memory resources defined\n");
- return -ENODEV;
- }
-
- sensor->mmio_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(sensor->mmio_base)) {
- dev_err(dev, "failed to remap IO\n");
+ sensor->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+ if (IS_ERR(sensor->mmio_base))
return PTR_ERR(sensor->mmio_base);
- }
sensor->regmap = devm_regmap_init_mmio(dev, sensor->mmio_base,
&st_416mpe_regmap_config);
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index d20b25f40d19..97ef9b040b84 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -36,10 +36,8 @@ static LIST_HEAD(thermal_governor_list);
static DEFINE_MUTEX(thermal_list_lock);
static DEFINE_MUTEX(thermal_governor_lock);
-static DEFINE_MUTEX(poweroff_lock);
static atomic_t in_suspend;
-static bool power_off_triggered;
static struct thermal_governor *def_governor;
@@ -327,70 +325,18 @@ static void handle_non_critical_trips(struct thermal_zone_device *tz, int trip)
def_governor->throttle(tz, trip);
}
-/**
- * thermal_emergency_poweroff_func - emergency poweroff work after a known delay
- * @work: work_struct associated with the emergency poweroff function
- *
- * This function is called in very critical situations to force
- * a kernel poweroff after a configurable timeout value.
- */
-static void thermal_emergency_poweroff_func(struct work_struct *work)
-{
- /*
- * We have reached here after the emergency thermal shutdown
- * Waiting period has expired. This means orderly_poweroff has
- * not been able to shut off the system for some reason.
- * Try to shut down the system immediately using kernel_power_off
- * if populated
- */
- WARN(1, "Attempting kernel_power_off: Temperature too high\n");
- kernel_power_off();
-
- /*
- * Worst of the worst case trigger emergency restart
- */
- WARN(1, "Attempting emergency_restart: Temperature too high\n");
- emergency_restart();
-}
-
-static DECLARE_DELAYED_WORK(thermal_emergency_poweroff_work,
- thermal_emergency_poweroff_func);
-
-/**
- * thermal_emergency_poweroff - Trigger an emergency system poweroff
- *
- * This may be called from any critical situation to trigger a system shutdown
- * after a known period of time. By default this is not scheduled.
- */
-static void thermal_emergency_poweroff(void)
+void thermal_zone_device_critical(struct thermal_zone_device *tz)
{
- int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS;
/*
* poweroff_delay_ms must be a carefully profiled positive value.
- * Its a must for thermal_emergency_poweroff_work to be scheduled
+ * Its a must for forced_emergency_poweroff_work to be scheduled.
*/
- if (poweroff_delay_ms <= 0)
- return;
- schedule_delayed_work(&thermal_emergency_poweroff_work,
- msecs_to_jiffies(poweroff_delay_ms));
-}
+ int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS;
-void thermal_zone_device_critical(struct thermal_zone_device *tz)
-{
dev_emerg(&tz->device, "%s: critical temperature reached, "
"shutting down\n", tz->type);
- mutex_lock(&poweroff_lock);
- if (!power_off_triggered) {
- /*
- * Queue a backup emergency shutdown in the event of
- * orderly_poweroff failure
- */
- thermal_emergency_poweroff();
- orderly_poweroff(true);
- power_off_triggered = true;
- }
- mutex_unlock(&poweroff_lock);
+ hw_protection_shutdown("Temperature too high", poweroff_delay_ms);
}
EXPORT_SYMBOL(thermal_zone_device_critical);
@@ -1369,7 +1315,7 @@ free_tz:
EXPORT_SYMBOL_GPL(thermal_zone_device_register);
/**
- * thermal_device_unregister - removes the registered thermal zone device
+ * thermal_zone_device_unregister - removes the registered thermal zone device
* @tz: the thermal zone device to remove
*/
void thermal_zone_device_unregister(struct thermal_zone_device *tz)
@@ -1538,7 +1484,6 @@ error:
ida_destroy(&thermal_cdev_ida);
mutex_destroy(&thermal_list_lock);
mutex_destroy(&thermal_governor_lock);
- mutex_destroy(&poweroff_lock);
return result;
}
postcore_initcall(thermal_init);
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index 5b76f9a1280d..6379f26a335f 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -559,6 +559,9 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
if (!tz)
return;
+ /* stop temperature polling */
+ thermal_zone_device_disable(tzd);
+
mutex_lock(&tzd->lock);
tzd->ops->get_temp = NULL;
tzd->ops->get_trend = NULL;
diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile
index 7aa48f6c41d9..da19d7987d00 100644
--- a/drivers/thunderbolt/Makefile
+++ b/drivers/thunderbolt/Makefile
@@ -2,7 +2,7 @@
obj-${CONFIG_USB4} := thunderbolt.o
thunderbolt-objs := nhi.o nhi_ops.o ctl.o tb.o switch.o cap.o path.o tunnel.o eeprom.o
thunderbolt-objs += domain.o dma_port.o icm.o property.o xdomain.o lc.o tmu.o usb4.o
-thunderbolt-objs += nvm.o retimer.o quirks.o
+thunderbolt-objs += usb4_port.o nvm.o retimer.o quirks.o
thunderbolt-${CONFIG_ACPI} += acpi.o
thunderbolt-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/drivers/thunderbolt/acpi.c b/drivers/thunderbolt/acpi.c
index 35fa17f7e599..b67e72d5644b 100644
--- a/drivers/thunderbolt/acpi.c
+++ b/drivers/thunderbolt/acpi.c
@@ -180,3 +180,209 @@ bool tb_acpi_is_xdomain_allowed(void)
return osc_sb_native_usb4_control & OSC_USB_XDOMAIN;
return true;
}
+
+/* UUID for retimer _DSM: e0053122-795b-4122-8a5e-57be1d26acb3 */
+static const guid_t retimer_dsm_guid =
+ GUID_INIT(0xe0053122, 0x795b, 0x4122,
+ 0x8a, 0x5e, 0x57, 0xbe, 0x1d, 0x26, 0xac, 0xb3);
+
+#define RETIMER_DSM_QUERY_ONLINE_STATE 1
+#define RETIMER_DSM_SET_ONLINE_STATE 2
+
+static int tb_acpi_retimer_set_power(struct tb_port *port, bool power)
+{
+ struct usb4_port *usb4 = port->usb4;
+ union acpi_object argv4[2];
+ struct acpi_device *adev;
+ union acpi_object *obj;
+ int ret;
+
+ if (!usb4->can_offline)
+ return 0;
+
+ adev = ACPI_COMPANION(&usb4->dev);
+ if (WARN_ON(!adev))
+ return 0;
+
+ /* Check if we are already powered on (and in correct mode) */
+ obj = acpi_evaluate_dsm_typed(adev->handle, &retimer_dsm_guid, 1,
+ RETIMER_DSM_QUERY_ONLINE_STATE, NULL,
+ ACPI_TYPE_INTEGER);
+ if (!obj) {
+ tb_port_warn(port, "ACPI: query online _DSM failed\n");
+ return -EIO;
+ }
+
+ ret = obj->integer.value;
+ ACPI_FREE(obj);
+
+ if (power == ret)
+ return 0;
+
+ tb_port_dbg(port, "ACPI: calling _DSM to power %s retimers\n",
+ power ? "on" : "off");
+
+ argv4[0].type = ACPI_TYPE_PACKAGE;
+ argv4[0].package.count = 1;
+ argv4[0].package.elements = &argv4[1];
+ argv4[1].integer.type = ACPI_TYPE_INTEGER;
+ argv4[1].integer.value = power;
+
+ obj = acpi_evaluate_dsm_typed(adev->handle, &retimer_dsm_guid, 1,
+ RETIMER_DSM_SET_ONLINE_STATE, argv4,
+ ACPI_TYPE_INTEGER);
+ if (!obj) {
+ tb_port_warn(port,
+ "ACPI: set online state _DSM evaluation failed\n");
+ return -EIO;
+ }
+
+ ret = obj->integer.value;
+ ACPI_FREE(obj);
+
+ if (ret >= 0) {
+ if (power)
+ return ret == 1 ? 0 : -EBUSY;
+ return 0;
+ }
+
+ tb_port_warn(port, "ACPI: set online state _DSM failed with error %d\n", ret);
+ return -EIO;
+}
+
+/**
+ * tb_acpi_power_on_retimers() - Call platform to power on retimers
+ * @port: USB4 port
+ *
+ * Calls platform to turn on power to all retimers behind this USB4
+ * port. After this function returns successfully the caller can
+ * continue with the normal retimer flows (as specified in the USB4
+ * spec). Note if this returns %-EBUSY it means the type-C port is in
+ * non-USB4/TBT mode (there is non-USB4/TBT device connected).
+ *
+ * This should only be called if the USB4/TBT link is not up.
+ *
+ * Returns %0 on success.
+ */
+int tb_acpi_power_on_retimers(struct tb_port *port)
+{
+ return tb_acpi_retimer_set_power(port, true);
+}
+
+/**
+ * tb_acpi_power_off_retimers() - Call platform to power off retimers
+ * @port: USB4 port
+ *
+ * This is the opposite of tb_acpi_power_on_retimers(). After returning
+ * successfully the normal operations with the @port can continue.
+ *
+ * Returns %0 on success.
+ */
+int tb_acpi_power_off_retimers(struct tb_port *port)
+{
+ return tb_acpi_retimer_set_power(port, false);
+}
+
+static bool tb_acpi_bus_match(struct device *dev)
+{
+ return tb_is_switch(dev) || tb_is_usb4_port_device(dev);
+}
+
+static struct acpi_device *tb_acpi_find_port(struct acpi_device *adev,
+ const struct tb_port *port)
+{
+ struct acpi_device *port_adev;
+
+ if (!adev)
+ return NULL;
+
+ /*
+ * Device routers exists under the downstream facing USB4 port
+ * of the parent router. Their _ADR is always 0.
+ */
+ list_for_each_entry(port_adev, &adev->children, node) {
+ if (acpi_device_adr(port_adev) == port->port)
+ return port_adev;
+ }
+
+ return NULL;
+}
+
+static struct acpi_device *tb_acpi_switch_find_companion(struct tb_switch *sw)
+{
+ struct acpi_device *adev = NULL;
+ struct tb_switch *parent_sw;
+
+ parent_sw = tb_switch_parent(sw);
+ if (parent_sw) {
+ struct tb_port *port = tb_port_at(tb_route(sw), parent_sw);
+ struct acpi_device *port_adev;
+
+ port_adev = tb_acpi_find_port(ACPI_COMPANION(&parent_sw->dev), port);
+ if (port_adev)
+ adev = acpi_find_child_device(port_adev, 0, false);
+ } else {
+ struct tb_nhi *nhi = sw->tb->nhi;
+ struct acpi_device *parent_adev;
+
+ parent_adev = ACPI_COMPANION(&nhi->pdev->dev);
+ if (parent_adev)
+ adev = acpi_find_child_device(parent_adev, 0, false);
+ }
+
+ return adev;
+}
+
+static struct acpi_device *tb_acpi_find_companion(struct device *dev)
+{
+ /*
+ * The Thunderbolt/USB4 hierarchy looks like following:
+ *
+ * Device (NHI)
+ * Device (HR) // Host router _ADR == 0
+ * Device (DFP0) // Downstream port _ADR == lane 0 adapter
+ * Device (DR) // Device router _ADR == 0
+ * Device (UFP) // Upstream port _ADR == lane 0 adapter
+ * Device (DFP1) // Downstream port _ADR == lane 0 adapter number
+ *
+ * At the moment we bind the host router to the corresponding
+ * Linux device.
+ */
+ if (tb_is_switch(dev))
+ return tb_acpi_switch_find_companion(tb_to_switch(dev));
+ else if (tb_is_usb4_port_device(dev))
+ return tb_acpi_find_port(ACPI_COMPANION(dev->parent),
+ tb_to_usb4_port_device(dev)->port);
+ return NULL;
+}
+
+static void tb_acpi_setup(struct device *dev)
+{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
+
+ if (!adev || !usb4)
+ return;
+
+ if (acpi_check_dsm(adev->handle, &retimer_dsm_guid, 1,
+ BIT(RETIMER_DSM_QUERY_ONLINE_STATE) |
+ BIT(RETIMER_DSM_SET_ONLINE_STATE)))
+ usb4->can_offline = true;
+}
+
+static struct acpi_bus_type tb_acpi_bus = {
+ .name = "thunderbolt",
+ .match = tb_acpi_bus_match,
+ .find_companion = tb_acpi_find_companion,
+ .setup = tb_acpi_setup,
+};
+
+int tb_acpi_init(void)
+{
+ return register_acpi_bus_type(&tb_acpi_bus);
+}
+
+void tb_acpi_exit(void)
+{
+ unregister_acpi_bus_type(&tb_acpi_bus);
+}
diff --git a/drivers/thunderbolt/dma_port.c b/drivers/thunderbolt/dma_port.c
index 5631319f7b20..9f20c7bbf0ce 100644
--- a/drivers/thunderbolt/dma_port.c
+++ b/drivers/thunderbolt/dma_port.c
@@ -299,15 +299,13 @@ static int dma_port_request(struct tb_dma_port *dma, u32 in,
return status_to_errno(out);
}
-static int dma_port_flash_read_block(struct tb_dma_port *dma, u32 address,
- void *buf, u32 size)
+static int dma_port_flash_read_block(void *data, unsigned int dwaddress,
+ void *buf, size_t dwords)
{
+ struct tb_dma_port *dma = data;
struct tb_switch *sw = dma->sw;
- u32 in, dwaddress, dwords;
int ret;
-
- dwaddress = address / 4;
- dwords = size / 4;
+ u32 in;
in = MAIL_IN_CMD_FLASH_READ << MAIL_IN_CMD_SHIFT;
if (dwords < MAIL_DATA_DWORDS)
@@ -323,14 +321,13 @@ static int dma_port_flash_read_block(struct tb_dma_port *dma, u32 address,
dma->base + MAIL_DATA, dwords, DMA_PORT_TIMEOUT);
}
-static int dma_port_flash_write_block(struct tb_dma_port *dma, u32 address,
- const void *buf, u32 size)
+static int dma_port_flash_write_block(void *data, unsigned int dwaddress,
+ const void *buf, size_t dwords)
{
+ struct tb_dma_port *dma = data;
struct tb_switch *sw = dma->sw;
- u32 in, dwaddress, dwords;
int ret;
-
- dwords = size / 4;
+ u32 in;
/* Write the block to MAIL_DATA registers */
ret = dma_port_write(sw->tb->ctl, buf, tb_route(sw), dma->port,
@@ -341,12 +338,8 @@ static int dma_port_flash_write_block(struct tb_dma_port *dma, u32 address,
in = MAIL_IN_CMD_FLASH_WRITE << MAIL_IN_CMD_SHIFT;
/* CSS header write is always done to the same magic address */
- if (address >= DMA_PORT_CSS_ADDRESS) {
- dwaddress = DMA_PORT_CSS_ADDRESS;
+ if (dwaddress >= DMA_PORT_CSS_ADDRESS)
in |= MAIL_IN_CSS;
- } else {
- dwaddress = address / 4;
- }
in |= ((dwords - 1) << MAIL_IN_DWORDS_SHIFT) & MAIL_IN_DWORDS_MASK;
in |= (dwaddress << MAIL_IN_ADDRESS_SHIFT) & MAIL_IN_ADDRESS_MASK;
@@ -365,36 +358,8 @@ static int dma_port_flash_write_block(struct tb_dma_port *dma, u32 address,
int dma_port_flash_read(struct tb_dma_port *dma, unsigned int address,
void *buf, size_t size)
{
- unsigned int retries = DMA_PORT_RETRIES;
-
- do {
- unsigned int offset;
- size_t nbytes;
- int ret;
-
- offset = address & 3;
- nbytes = min_t(size_t, size + offset, MAIL_DATA_DWORDS * 4);
-
- ret = dma_port_flash_read_block(dma, address, dma->buf,
- ALIGN(nbytes, 4));
- if (ret) {
- if (ret == -ETIMEDOUT) {
- if (retries--)
- continue;
- ret = -EIO;
- }
- return ret;
- }
-
- nbytes -= offset;
- memcpy(buf, dma->buf + offset, nbytes);
-
- size -= nbytes;
- address += nbytes;
- buf += nbytes;
- } while (size > 0);
-
- return 0;
+ return tb_nvm_read_data(address, buf, size, DMA_PORT_RETRIES,
+ dma_port_flash_read_block, dma);
}
/**
@@ -411,40 +376,11 @@ int dma_port_flash_read(struct tb_dma_port *dma, unsigned int address,
int dma_port_flash_write(struct tb_dma_port *dma, unsigned int address,
const void *buf, size_t size)
{
- unsigned int retries = DMA_PORT_RETRIES;
- unsigned int offset;
-
- if (address >= DMA_PORT_CSS_ADDRESS) {
- offset = 0;
- if (size > DMA_PORT_CSS_MAX_SIZE)
- return -E2BIG;
- } else {
- offset = address & 3;
- address = address & ~3;
- }
-
- do {
- u32 nbytes = min_t(u32, size, MAIL_DATA_DWORDS * 4);
- int ret;
+ if (address >= DMA_PORT_CSS_ADDRESS && size > DMA_PORT_CSS_MAX_SIZE)
+ return -E2BIG;
- memcpy(dma->buf + offset, buf, nbytes);
-
- ret = dma_port_flash_write_block(dma, address, buf, nbytes);
- if (ret) {
- if (ret == -ETIMEDOUT) {
- if (retries--)
- continue;
- ret = -EIO;
- }
- return ret;
- }
-
- size -= nbytes;
- address += nbytes;
- buf += nbytes;
- } while (size > 0);
-
- return 0;
+ return tb_nvm_write_data(address, buf, size, DMA_PORT_RETRIES,
+ dma_port_flash_write_block, dma);
}
/**
diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c
index 98f4056f89ff..a062befcb3b2 100644
--- a/drivers/thunderbolt/domain.c
+++ b/drivers/thunderbolt/domain.c
@@ -881,11 +881,12 @@ int tb_domain_init(void)
int ret;
tb_test_init();
-
tb_debugfs_init();
+ tb_acpi_init();
+
ret = tb_xdomain_init();
if (ret)
- goto err_debugfs;
+ goto err_acpi;
ret = bus_register(&tb_bus_type);
if (ret)
goto err_xdomain;
@@ -894,7 +895,8 @@ int tb_domain_init(void)
err_xdomain:
tb_xdomain_exit();
-err_debugfs:
+err_acpi:
+ tb_acpi_exit();
tb_debugfs_exit();
tb_test_exit();
@@ -907,6 +909,7 @@ void tb_domain_exit(void)
ida_destroy(&tb_domain_ida);
tb_nvm_exit();
tb_xdomain_exit();
+ tb_acpi_exit();
tb_debugfs_exit();
tb_test_exit();
}
diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c
index 46d0906a3070..470885e6f1c8 100644
--- a/drivers/thunderbolt/eeprom.c
+++ b/drivers/thunderbolt/eeprom.c
@@ -214,7 +214,10 @@ static u32 tb_crc32(void *data, size_t len)
return ~__crc32c_le(~0, data, len);
}
-#define TB_DROM_DATA_START 13
+#define TB_DROM_DATA_START 13
+#define TB_DROM_HEADER_SIZE 22
+#define USB4_DROM_HEADER_SIZE 16
+
struct tb_drom_header {
/* BYTE 0 */
u8 uid_crc8; /* checksum for uid */
@@ -224,9 +227,9 @@ struct tb_drom_header {
u32 data_crc32; /* checksum for data_len bytes starting at byte 13 */
/* BYTE 13 */
u8 device_rom_revision; /* should be <= 1 */
- u16 data_len:10;
- u8 __unknown1:6;
- /* BYTES 16-21 */
+ u16 data_len:12;
+ u8 reserved:4;
+ /* BYTES 16-21 - Only for TBT DROM, nonexistent in USB4 DROM */
u16 vendor_id;
u16 model_id;
u8 model_rev;
@@ -401,10 +404,10 @@ static int tb_drom_parse_entry_port(struct tb_switch *sw,
*
* Drom must have been copied to sw->drom.
*/
-static int tb_drom_parse_entries(struct tb_switch *sw)
+static int tb_drom_parse_entries(struct tb_switch *sw, size_t header_size)
{
struct tb_drom_header *header = (void *) sw->drom;
- u16 pos = sizeof(*header);
+ u16 pos = header_size;
u16 drom_size = header->data_len + TB_DROM_DATA_START;
int res;
@@ -566,7 +569,7 @@ static int tb_drom_parse(struct tb_switch *sw)
header->data_crc32, crc);
}
- return tb_drom_parse_entries(sw);
+ return tb_drom_parse_entries(sw, TB_DROM_HEADER_SIZE);
}
static int usb4_drom_parse(struct tb_switch *sw)
@@ -583,7 +586,7 @@ static int usb4_drom_parse(struct tb_switch *sw)
return -EINVAL;
}
- return tb_drom_parse_entries(sw);
+ return tb_drom_parse_entries(sw, USB4_DROM_HEADER_SIZE);
}
/**
diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c
index 2f30b816705a..6255f1ef9599 100644
--- a/drivers/thunderbolt/icm.c
+++ b/drivers/thunderbolt/icm.c
@@ -1677,14 +1677,18 @@ static void icm_icl_rtd3_veto(struct tb *tb, const struct icm_pkg_header *hdr)
static bool icm_tgl_is_supported(struct tb *tb)
{
- u32 val;
+ unsigned long end = jiffies + msecs_to_jiffies(10);
- /*
- * If the firmware is not running use software CM. This platform
- * should fully support both.
- */
- val = ioread32(tb->nhi->iobase + REG_FW_STS);
- return !!(val & REG_FW_STS_NVM_AUTH_DONE);
+ do {
+ u32 val;
+
+ val = ioread32(tb->nhi->iobase + REG_FW_STS);
+ if (val & REG_FW_STS_NVM_AUTH_DONE)
+ return true;
+ usleep_range(100, 500);
+ } while (time_before(jiffies, end));
+
+ return false;
}
static void icm_handle_notification(struct work_struct *work)
@@ -2505,6 +2509,8 @@ struct tb *icm_probe(struct tb_nhi *nhi)
case PCI_DEVICE_ID_INTEL_TGL_NHI1:
case PCI_DEVICE_ID_INTEL_TGL_H_NHI0:
case PCI_DEVICE_ID_INTEL_TGL_H_NHI1:
+ case PCI_DEVICE_ID_INTEL_ADL_NHI0:
+ case PCI_DEVICE_ID_INTEL_ADL_NHI1:
icm->is_supported = icm_tgl_is_supported;
icm->driver_ready = icm_icl_driver_ready;
icm->set_uuid = icm_icl_set_uuid;
diff --git a/drivers/thunderbolt/lc.c b/drivers/thunderbolt/lc.c
index bc671730a11f..c178f0d7beab 100644
--- a/drivers/thunderbolt/lc.c
+++ b/drivers/thunderbolt/lc.c
@@ -208,8 +208,8 @@ static int tb_lc_set_wake_one(struct tb_switch *sw, unsigned int offset,
if (ret)
return ret;
- ctrl &= ~(TB_LC_SX_CTRL_WOC | TB_LC_SX_CTRL_WOD | TB_LC_SX_CTRL_WOP |
- TB_LC_SX_CTRL_WOU4);
+ ctrl &= ~(TB_LC_SX_CTRL_WOC | TB_LC_SX_CTRL_WOD | TB_LC_SX_CTRL_WODPC |
+ TB_LC_SX_CTRL_WODPD | TB_LC_SX_CTRL_WOP | TB_LC_SX_CTRL_WOU4);
if (flags & TB_WAKE_ON_CONNECT)
ctrl |= TB_LC_SX_CTRL_WOC | TB_LC_SX_CTRL_WOD;
@@ -217,6 +217,8 @@ static int tb_lc_set_wake_one(struct tb_switch *sw, unsigned int offset,
ctrl |= TB_LC_SX_CTRL_WOU4;
if (flags & TB_WAKE_ON_PCIE)
ctrl |= TB_LC_SX_CTRL_WOP;
+ if (flags & TB_WAKE_ON_DP)
+ ctrl |= TB_LC_SX_CTRL_WODPC | TB_LC_SX_CTRL_WODPD;
return tb_sw_write(sw, &ctrl, TB_CFG_SWITCH, offset + TB_LC_SX_CTRL, 1);
}
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index a0386d1e3fc9..fa44332845a1 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/property.h>
-#include <linux/platform_data/x86/apple.h>
#include "nhi.h"
#include "nhi_regs.h"
@@ -1127,69 +1126,6 @@ static bool nhi_imr_valid(struct pci_dev *pdev)
return true;
}
-/*
- * During suspend the Thunderbolt controller is reset and all PCIe
- * tunnels are lost. The NHI driver will try to reestablish all tunnels
- * during resume. This adds device links between the tunneled PCIe
- * downstream ports and the NHI so that the device core will make sure
- * NHI is resumed first before the rest.
- */
-static void tb_apple_add_links(struct tb_nhi *nhi)
-{
- struct pci_dev *upstream, *pdev;
-
- if (!x86_apple_machine)
- return;
-
- switch (nhi->pdev->device) {
- case PCI_DEVICE_ID_INTEL_LIGHT_RIDGE:
- case PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C:
- case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_2C_NHI:
- case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_NHI:
- break;
- default:
- return;
- }
-
- upstream = pci_upstream_bridge(nhi->pdev);
- while (upstream) {
- if (!pci_is_pcie(upstream))
- return;
- if (pci_pcie_type(upstream) == PCI_EXP_TYPE_UPSTREAM)
- break;
- upstream = pci_upstream_bridge(upstream);
- }
-
- if (!upstream)
- return;
-
- /*
- * For each hotplug downstream port, create add device link
- * back to NHI so that PCIe tunnels can be re-established after
- * sleep.
- */
- for_each_pci_bridge(pdev, upstream->subordinate) {
- const struct device_link *link;
-
- if (!pci_is_pcie(pdev))
- continue;
- if (pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM ||
- !pdev->is_hotplug_bridge)
- continue;
-
- link = device_link_add(&pdev->dev, &nhi->pdev->dev,
- DL_FLAG_AUTOREMOVE_SUPPLIER |
- DL_FLAG_PM_RUNTIME);
- if (link) {
- dev_dbg(&nhi->pdev->dev, "created link from %s\n",
- dev_name(&pdev->dev));
- } else {
- dev_warn(&nhi->pdev->dev, "device link creation from %s failed\n",
- dev_name(&pdev->dev));
- }
- }
-}
-
static struct tb *nhi_select_cm(struct tb_nhi *nhi)
{
struct tb *tb;
@@ -1278,9 +1214,6 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return res;
}
- tb_apple_add_links(nhi);
- tb_acpi_add_links(nhi);
-
tb = nhi_select_cm(nhi);
if (!tb) {
dev_err(&nhi->pdev->dev,
@@ -1400,6 +1333,10 @@ static struct pci_device_id nhi_ids[] = {
.driver_data = (kernel_ulong_t)&icl_nhi_ops },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL_H_NHI1),
.driver_data = (kernel_ulong_t)&icl_nhi_ops },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL_NHI0),
+ .driver_data = (kernel_ulong_t)&icl_nhi_ops },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL_NHI1),
+ .driver_data = (kernel_ulong_t)&icl_nhi_ops },
/* Any USB4 compliant host */
{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_USB4, ~0) },
diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h
index 69770beca792..69083aab2736 100644
--- a/drivers/thunderbolt/nhi.h
+++ b/drivers/thunderbolt/nhi.h
@@ -72,6 +72,8 @@ extern const struct tb_nhi_ops icl_nhi_ops;
#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_BRIDGE 0x15ea
#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_NHI 0x15eb
#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_BRIDGE 0x15ef
+#define PCI_DEVICE_ID_INTEL_ADL_NHI0 0x463e
+#define PCI_DEVICE_ID_INTEL_ADL_NHI1 0x466d
#define PCI_DEVICE_ID_INTEL_ICL_NHI1 0x8a0d
#define PCI_DEVICE_ID_INTEL_ICL_NHI0 0x8a17
#define PCI_DEVICE_ID_INTEL_TGL_NHI0 0x9a1b
diff --git a/drivers/thunderbolt/nvm.c b/drivers/thunderbolt/nvm.c
index 29de6d95c6e7..3a5336913cca 100644
--- a/drivers/thunderbolt/nvm.c
+++ b/drivers/thunderbolt/nvm.c
@@ -164,6 +164,101 @@ void tb_nvm_free(struct tb_nvm *nvm)
kfree(nvm);
}
+/**
+ * tb_nvm_read_data() - Read data from NVM
+ * @address: Start address on the flash
+ * @buf: Buffer where the read data is copied
+ * @size: Size of the buffer in bytes
+ * @retries: Number of retries if block read fails
+ * @read_block: Function that reads block from the flash
+ * @read_block_data: Data passsed to @read_block
+ *
+ * This is a generic function that reads data from NVM or NVM like
+ * device.
+ *
+ * Returns %0 on success and negative errno otherwise.
+ */
+int tb_nvm_read_data(unsigned int address, void *buf, size_t size,
+ unsigned int retries, read_block_fn read_block,
+ void *read_block_data)
+{
+ do {
+ unsigned int dwaddress, dwords, offset;
+ u8 data[NVM_DATA_DWORDS * 4];
+ size_t nbytes;
+ int ret;
+
+ offset = address & 3;
+ nbytes = min_t(size_t, size + offset, NVM_DATA_DWORDS * 4);
+
+ dwaddress = address / 4;
+ dwords = ALIGN(nbytes, 4) / 4;
+
+ ret = read_block(read_block_data, dwaddress, data, dwords);
+ if (ret) {
+ if (ret != -ENODEV && retries--)
+ continue;
+ return ret;
+ }
+
+ nbytes -= offset;
+ memcpy(buf, data + offset, nbytes);
+
+ size -= nbytes;
+ address += nbytes;
+ buf += nbytes;
+ } while (size > 0);
+
+ return 0;
+}
+
+/**
+ * tb_nvm_write_data() - Write data to NVM
+ * @address: Start address on the flash
+ * @buf: Buffer where the data is copied from
+ * @size: Size of the buffer in bytes
+ * @retries: Number of retries if the block write fails
+ * @write_block: Function that writes block to the flash
+ * @write_block_data: Data passwd to @write_block
+ *
+ * This is generic function that writes data to NVM or NVM like device.
+ *
+ * Returns %0 on success and negative errno otherwise.
+ */
+int tb_nvm_write_data(unsigned int address, const void *buf, size_t size,
+ unsigned int retries, write_block_fn write_block,
+ void *write_block_data)
+{
+ do {
+ unsigned int offset, dwaddress;
+ u8 data[NVM_DATA_DWORDS * 4];
+ size_t nbytes;
+ int ret;
+
+ offset = address & 3;
+ nbytes = min_t(u32, size + offset, NVM_DATA_DWORDS * 4);
+
+ memcpy(data + offset, buf, nbytes);
+
+ dwaddress = address / 4;
+ ret = write_block(write_block_data, dwaddress, data, nbytes / 4);
+ if (ret) {
+ if (ret == -ETIMEDOUT) {
+ if (retries--)
+ continue;
+ ret = -EIO;
+ }
+ return ret;
+ }
+
+ size -= nbytes;
+ address += nbytes;
+ buf += nbytes;
+ } while (size > 0);
+
+ return 0;
+}
+
void tb_nvm_exit(void)
{
ida_destroy(&nvm_ida);
diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c
index f63e205a35d9..564e2f42cebd 100644
--- a/drivers/thunderbolt/path.c
+++ b/drivers/thunderbolt/path.c
@@ -367,7 +367,7 @@ static void __tb_path_deallocate_nfc(struct tb_path *path, int first_hop)
int i, res;
for (i = first_hop; i < path->path_length; i++) {
res = tb_port_add_nfc_credits(path->hops[i].in_port,
- -path->nfc_credits);
+ -path->hops[i].nfc_credits);
if (res)
tb_port_warn(path->hops[i].in_port,
"nfc credits deallocation failed for hop %d\n",
@@ -502,7 +502,7 @@ int tb_path_activate(struct tb_path *path)
/* Add non flow controlled credits. */
for (i = path->path_length - 1; i >= 0; i--) {
res = tb_port_add_nfc_credits(path->hops[i].in_port,
- path->nfc_credits);
+ path->hops[i].nfc_credits);
if (res) {
__tb_path_deallocate_nfc(path, i);
goto err;
diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c
index 57e2978a3c21..b5f2ec79c4d6 100644
--- a/drivers/thunderbolt/quirks.c
+++ b/drivers/thunderbolt/quirks.c
@@ -12,7 +12,17 @@ static void quirk_force_power_link(struct tb_switch *sw)
sw->quirks |= QUIRK_FORCE_POWER_LINK_CONTROLLER;
}
+static void quirk_dp_credit_allocation(struct tb_switch *sw)
+{
+ if (sw->credit_allocation && sw->min_dp_main_credits == 56) {
+ sw->min_dp_main_credits = 18;
+ tb_sw_dbg(sw, "quirked DP main: %u\n", sw->min_dp_main_credits);
+ }
+}
+
struct tb_quirk {
+ u16 hw_vendor_id;
+ u16 hw_device_id;
u16 vendor;
u16 device;
void (*hook)(struct tb_switch *sw);
@@ -20,7 +30,13 @@ struct tb_quirk {
static const struct tb_quirk tb_quirks[] = {
/* Dell WD19TB supports self-authentication on unplug */
- { 0x00d4, 0xb070, quirk_force_power_link },
+ { 0x0000, 0x0000, 0x00d4, 0xb070, quirk_force_power_link },
+ { 0x0000, 0x0000, 0x00d4, 0xb071, quirk_force_power_link },
+ /*
+ * Intel Goshen Ridge NVM 27 and before report wrong number of
+ * DP buffers.
+ */
+ { 0x8087, 0x0b26, 0x0000, 0x0000, quirk_dp_credit_allocation },
};
/**
@@ -36,7 +52,15 @@ void tb_check_quirks(struct tb_switch *sw)
for (i = 0; i < ARRAY_SIZE(tb_quirks); i++) {
const struct tb_quirk *q = &tb_quirks[i];
- if (sw->device == q->device && sw->vendor == q->vendor)
- q->hook(sw);
+ if (q->hw_vendor_id && q->hw_vendor_id != sw->config.vendor_id)
+ continue;
+ if (q->hw_device_id && q->hw_device_id != sw->config.device_id)
+ continue;
+ if (q->vendor && q->vendor != sw->vendor)
+ continue;
+ if (q->device && q->device != sw->device)
+ continue;
+
+ q->hook(sw);
}
}
diff --git a/drivers/thunderbolt/retimer.c b/drivers/thunderbolt/retimer.c
index c44fad2b9fbb..722694052f4a 100644
--- a/drivers/thunderbolt/retimer.c
+++ b/drivers/thunderbolt/retimer.c
@@ -103,6 +103,7 @@ static int tb_retimer_nvm_validate_and_write(struct tb_retimer *rt)
unsigned int image_size, hdr_size;
const u8 *buf = rt->nvm->buf;
u16 ds_size, device;
+ int ret;
image_size = rt->nvm->buf_data_size;
if (image_size < NVM_MIN_SIZE || image_size > NVM_MAX_SIZE)
@@ -140,8 +141,43 @@ static int tb_retimer_nvm_validate_and_write(struct tb_retimer *rt)
buf += hdr_size;
image_size -= hdr_size;
- return usb4_port_retimer_nvm_write(rt->port, rt->index, 0, buf,
- image_size);
+ ret = usb4_port_retimer_nvm_write(rt->port, rt->index, 0, buf,
+ image_size);
+ if (!ret)
+ rt->nvm->flushed = true;
+
+ return ret;
+}
+
+static int tb_retimer_nvm_authenticate(struct tb_retimer *rt, bool auth_only)
+{
+ u32 status;
+ int ret;
+
+ if (auth_only) {
+ ret = usb4_port_retimer_nvm_set_offset(rt->port, rt->index, 0);
+ if (ret)
+ return ret;
+ }
+
+ ret = usb4_port_retimer_nvm_authenticate(rt->port, rt->index);
+ if (ret)
+ return ret;
+
+ usleep_range(100, 150);
+
+ /*
+ * Check the status now if we still can access the retimer. It
+ * is expected that the below fails.
+ */
+ ret = usb4_port_retimer_nvm_authenticate_status(rt->port, rt->index,
+ &status);
+ if (!ret) {
+ rt->auth_status = status;
+ return status ? -EINVAL : 0;
+ }
+
+ return 0;
}
static ssize_t device_show(struct device *dev, struct device_attribute *attr,
@@ -176,8 +212,7 @@ static ssize_t nvm_authenticate_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct tb_retimer *rt = tb_to_retimer(dev);
- bool val;
- int ret;
+ int val, ret;
pm_runtime_get_sync(&rt->dev);
@@ -191,7 +226,7 @@ static ssize_t nvm_authenticate_store(struct device *dev,
goto exit_unlock;
}
- ret = kstrtobool(buf, &val);
+ ret = kstrtoint(buf, 10, &val);
if (ret)
goto exit_unlock;
@@ -199,16 +234,22 @@ static ssize_t nvm_authenticate_store(struct device *dev,
rt->auth_status = 0;
if (val) {
- if (!rt->nvm->buf) {
- ret = -EINVAL;
- goto exit_unlock;
+ if (val == AUTHENTICATE_ONLY) {
+ ret = tb_retimer_nvm_authenticate(rt, true);
+ } else {
+ if (!rt->nvm->flushed) {
+ if (!rt->nvm->buf) {
+ ret = -EINVAL;
+ goto exit_unlock;
+ }
+
+ ret = tb_retimer_nvm_validate_and_write(rt);
+ if (ret || val == WRITE_ONLY)
+ goto exit_unlock;
+ }
+ if (val == WRITE_AND_AUTHENTICATE)
+ ret = tb_retimer_nvm_authenticate(rt, false);
}
-
- ret = tb_retimer_nvm_validate_and_write(rt);
- if (ret)
- goto exit_unlock;
-
- ret = usb4_port_retimer_nvm_authenticate(rt->port, rt->index);
}
exit_unlock:
@@ -283,11 +324,13 @@ struct device_type tb_retimer_type = {
static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status)
{
+ struct usb4_port *usb4;
struct tb_retimer *rt;
u32 vendor, device;
int ret;
- if (!port->cap_usb4)
+ usb4 = port->usb4;
+ if (!usb4)
return -EINVAL;
ret = usb4_port_retimer_read(port, index, USB4_SB_VENDOR_ID, &vendor,
@@ -331,7 +374,7 @@ static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status)
rt->port = port;
rt->tb = port->sw->tb;
- rt->dev.parent = &port->sw->dev;
+ rt->dev.parent = &usb4->dev;
rt->dev.bus = &tb_bus_type;
rt->dev.type = &tb_retimer_type;
dev_set_name(&rt->dev, "%s:%u.%u", dev_name(&port->sw->dev),
@@ -389,7 +432,7 @@ static struct tb_retimer *tb_port_find_retimer(struct tb_port *port, u8 index)
struct tb_retimer_lookup lookup = { .port = port, .index = index };
struct device *dev;
- dev = device_find_child(&port->sw->dev, &lookup, retimer_match);
+ dev = device_find_child(&port->usb4->dev, &lookup, retimer_match);
if (dev)
return tb_to_retimer(dev);
@@ -399,19 +442,18 @@ static struct tb_retimer *tb_port_find_retimer(struct tb_port *port, u8 index)
/**
* tb_retimer_scan() - Scan for on-board retimers under port
* @port: USB4 port to scan
+ * @add: If true also registers found retimers
*
- * Tries to enumerate on-board retimers connected to @port. Found
- * retimers are registered as children of @port. Does not scan for cable
- * retimers for now.
+ * Brings the sideband into a state where retimers can be accessed.
+ * Then Tries to enumerate on-board retimers connected to @port. Found
+ * retimers are registered as children of @port if @add is set. Does
+ * not scan for cable retimers for now.
*/
-int tb_retimer_scan(struct tb_port *port)
+int tb_retimer_scan(struct tb_port *port, bool add)
{
u32 status[TB_MAX_RETIMER_INDEX + 1] = {};
int ret, i, last_idx = 0;
- if (!port->cap_usb4)
- return 0;
-
/*
* Send broadcast RT to make sure retimer indices facing this
* port are set.
@@ -421,6 +463,13 @@ int tb_retimer_scan(struct tb_port *port)
return ret;
/*
+ * Enable sideband channel for each retimer. We can do this
+ * regardless whether there is device connected or not.
+ */
+ for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++)
+ usb4_port_retimer_set_inbound_sbtx(port, i);
+
+ /*
* Before doing anything else, read the authentication status.
* If the retimer has it set, store it for the new retimer
* device instance.
@@ -451,10 +500,10 @@ int tb_retimer_scan(struct tb_port *port)
rt = tb_port_find_retimer(port, i);
if (rt) {
put_device(&rt->dev);
- } else {
+ } else if (add) {
ret = tb_retimer_add(port, i, status[i]);
if (ret && ret != -EOPNOTSUPP)
- return ret;
+ break;
}
}
@@ -479,7 +528,10 @@ static int remove_retimer(struct device *dev, void *data)
*/
void tb_retimer_remove_all(struct tb_port *port)
{
- if (port->cap_usb4)
- device_for_each_child_reverse(&port->sw->dev, port,
+ struct usb4_port *usb4;
+
+ usb4 = port->usb4;
+ if (usb4)
+ device_for_each_child_reverse(&usb4->dev, port,
remove_retimer);
}
diff --git a/drivers/thunderbolt/sb_regs.h b/drivers/thunderbolt/sb_regs.h
index 9dafd696612f..bda889ff3bda 100644
--- a/drivers/thunderbolt/sb_regs.h
+++ b/drivers/thunderbolt/sb_regs.h
@@ -17,7 +17,9 @@
enum usb4_sb_opcode {
USB4_SB_OPCODE_ERR = 0x20525245, /* "ERR " */
USB4_SB_OPCODE_ONS = 0x444d4321, /* "!CMD" */
+ USB4_SB_OPCODE_ROUTER_OFFLINE = 0x4e45534c, /* "LSEN" */
USB4_SB_OPCODE_ENUMERATE_RETIMERS = 0x4d554e45, /* "ENUM" */
+ USB4_SB_OPCODE_SET_INBOUND_SBTX = 0x5055534c, /* "LSUP" */
USB4_SB_OPCODE_QUERY_LAST_RETIMER = 0x5453414c, /* "LAST" */
USB4_SB_OPCODE_GET_NVM_SECTOR_SIZE = 0x53534e47, /* "GNSS" */
USB4_SB_OPCODE_NVM_SET_OFFSET = 0x53504f42, /* "BOPS" */
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index e73cd296db7e..83b1ef3d5d03 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -26,11 +26,6 @@ struct nvm_auth_status {
u32 status;
};
-enum nvm_write_ops {
- WRITE_AND_AUTHENTICATE = 1,
- WRITE_ONLY = 2,
-};
-
/*
* Hold NVM authentication failure status per switch This information
* needs to stay around even when the switch gets power cycled so we
@@ -308,13 +303,23 @@ static inline int nvm_read(struct tb_switch *sw, unsigned int address,
return dma_port_flash_read(sw->dma_port, address, buf, size);
}
-static int nvm_authenticate(struct tb_switch *sw)
+static int nvm_authenticate(struct tb_switch *sw, bool auth_only)
{
int ret;
- if (tb_switch_is_usb4(sw))
+ if (tb_switch_is_usb4(sw)) {
+ if (auth_only) {
+ ret = usb4_switch_nvm_set_offset(sw, 0);
+ if (ret)
+ return ret;
+ }
+ sw->nvm->authenticating = true;
return usb4_switch_nvm_authenticate(sw);
+ } else if (auth_only) {
+ return -EOPNOTSUPP;
+ }
+ sw->nvm->authenticating = true;
if (!tb_route(sw)) {
nvm_authenticate_start_dma_port(sw);
ret = nvm_authenticate_host_dma_port(sw);
@@ -459,7 +464,7 @@ static void tb_switch_nvm_remove(struct tb_switch *sw)
/* port utility functions */
-static const char *tb_port_type(struct tb_regs_port_header *port)
+static const char *tb_port_type(const struct tb_regs_port_header *port)
{
switch (port->type >> 16) {
case 0:
@@ -488,17 +493,21 @@ static const char *tb_port_type(struct tb_regs_port_header *port)
}
}
-static void tb_dump_port(struct tb *tb, struct tb_regs_port_header *port)
+static void tb_dump_port(struct tb *tb, const struct tb_port *port)
{
+ const struct tb_regs_port_header *regs = &port->config;
+
tb_dbg(tb,
" Port %d: %x:%x (Revision: %d, TB Version: %d, Type: %s (%#x))\n",
- port->port_number, port->vendor_id, port->device_id,
- port->revision, port->thunderbolt_version, tb_port_type(port),
- port->type);
+ regs->port_number, regs->vendor_id, regs->device_id,
+ regs->revision, regs->thunderbolt_version, tb_port_type(regs),
+ regs->type);
tb_dbg(tb, " Max hop id (in/out): %d/%d\n",
- port->max_in_hop_id, port->max_out_hop_id);
- tb_dbg(tb, " Max counters: %d\n", port->max_counters);
- tb_dbg(tb, " NFC Credits: %#x\n", port->nfc_credits);
+ regs->max_in_hop_id, regs->max_out_hop_id);
+ tb_dbg(tb, " Max counters: %d\n", regs->max_counters);
+ tb_dbg(tb, " NFC Credits: %#x\n", regs->nfc_credits);
+ tb_dbg(tb, " Credits (total/control): %u/%u\n", port->total_credits,
+ port->ctl_credits);
}
/**
@@ -738,13 +747,32 @@ static int tb_init_port(struct tb_port *port)
cap = tb_port_find_cap(port, TB_PORT_CAP_USB4);
if (cap > 0)
port->cap_usb4 = cap;
+
+ /*
+ * USB4 ports the buffers allocated for the control path
+ * can be read from the path config space. Legacy
+ * devices we use hard-coded value.
+ */
+ if (tb_switch_is_usb4(port->sw)) {
+ struct tb_regs_hop hop;
+
+ if (!tb_port_read(port, &hop, TB_CFG_HOPS, 0, 2))
+ port->ctl_credits = hop.initial_credits;
+ }
+ if (!port->ctl_credits)
+ port->ctl_credits = 2;
+
} else if (port->port != 0) {
cap = tb_port_find_cap(port, TB_PORT_CAP_ADAP);
if (cap > 0)
port->cap_adap = cap;
}
- tb_dump_port(port->sw->tb, &port->config);
+ port->total_credits =
+ (port->config.nfc_credits & ADP_CS_4_TOTAL_BUFFERS_MASK) >>
+ ADP_CS_4_TOTAL_BUFFERS_SHIFT;
+
+ tb_dump_port(port->sw->tb, port);
INIT_LIST_HEAD(&port->list);
return 0;
@@ -991,8 +1019,11 @@ static int tb_port_set_link_width(struct tb_port *port, unsigned int width)
* tb_port_lane_bonding_enable() - Enable bonding on port
* @port: port to enable
*
- * Enable bonding by setting the link width of the port and the
- * other port in case of dual link port.
+ * Enable bonding by setting the link width of the port and the other
+ * port in case of dual link port. Does not wait for the link to
+ * actually reach the bonded state so caller needs to call
+ * tb_port_wait_for_link_width() before enabling any paths through the
+ * link to make sure the link is in expected state.
*
* Return: %0 in case of success and negative errno in case of error
*/
@@ -1043,6 +1074,79 @@ void tb_port_lane_bonding_disable(struct tb_port *port)
tb_port_set_link_width(port, 1);
}
+/**
+ * tb_port_wait_for_link_width() - Wait until link reaches specific width
+ * @port: Port to wait for
+ * @width: Expected link width (%1 or %2)
+ * @timeout_msec: Timeout in ms how long to wait
+ *
+ * Should be used after both ends of the link have been bonded (or
+ * bonding has been disabled) to wait until the link actually reaches
+ * the expected state. Returns %-ETIMEDOUT if the @width was not reached
+ * within the given timeout, %0 if it did.
+ */
+int tb_port_wait_for_link_width(struct tb_port *port, int width,
+ int timeout_msec)
+{
+ ktime_t timeout = ktime_add_ms(ktime_get(), timeout_msec);
+ int ret;
+
+ do {
+ ret = tb_port_get_link_width(port);
+ if (ret < 0)
+ return ret;
+ else if (ret == width)
+ return 0;
+
+ usleep_range(1000, 2000);
+ } while (ktime_before(ktime_get(), timeout));
+
+ return -ETIMEDOUT;
+}
+
+static int tb_port_do_update_credits(struct tb_port *port)
+{
+ u32 nfc_credits;
+ int ret;
+
+ ret = tb_port_read(port, &nfc_credits, TB_CFG_PORT, ADP_CS_4, 1);
+ if (ret)
+ return ret;
+
+ if (nfc_credits != port->config.nfc_credits) {
+ u32 total;
+
+ total = (nfc_credits & ADP_CS_4_TOTAL_BUFFERS_MASK) >>
+ ADP_CS_4_TOTAL_BUFFERS_SHIFT;
+
+ tb_port_dbg(port, "total credits changed %u -> %u\n",
+ port->total_credits, total);
+
+ port->config.nfc_credits = nfc_credits;
+ port->total_credits = total;
+ }
+
+ return 0;
+}
+
+/**
+ * tb_port_update_credits() - Re-read port total credits
+ * @port: Port to update
+ *
+ * After the link is bonded (or bonding was disabled) the port total
+ * credits may change, so this function needs to be called to re-read
+ * the credits. Updates also the second lane adapter.
+ */
+int tb_port_update_credits(struct tb_port *port)
+{
+ int ret;
+
+ ret = tb_port_do_update_credits(port);
+ if (ret)
+ return ret;
+ return tb_port_do_update_credits(port->dual_link_port);
+}
+
static int tb_port_start_lane_initialization(struct tb_port *port)
{
int ret;
@@ -1054,6 +1158,33 @@ static int tb_port_start_lane_initialization(struct tb_port *port)
return ret == -EINVAL ? 0 : ret;
}
+/*
+ * Returns true if the port had something (router, XDomain) connected
+ * before suspend.
+ */
+static bool tb_port_resume(struct tb_port *port)
+{
+ bool has_remote = tb_port_has_remote(port);
+
+ if (port->usb4) {
+ usb4_port_device_resume(port->usb4);
+ } else if (!has_remote) {
+ /*
+ * For disconnected downstream lane adapters start lane
+ * initialization now so we detect future connects.
+ *
+ * For XDomain start the lane initialzation now so the
+ * link gets re-established.
+ *
+ * This is only needed for non-USB4 ports.
+ */
+ if (!tb_is_upstream_port(port) || port->xdomain)
+ tb_port_start_lane_initialization(port);
+ }
+
+ return has_remote || port->xdomain;
+}
+
/**
* tb_port_is_enabled() - Is the adapter port enabled
* @port: Port to check
@@ -1592,8 +1723,7 @@ static ssize_t nvm_authenticate_sysfs(struct device *dev, const char *buf,
bool disconnect)
{
struct tb_switch *sw = tb_to_switch(dev);
- int val;
- int ret;
+ int val, ret;
pm_runtime_get_sync(&sw->dev);
@@ -1616,22 +1746,27 @@ static ssize_t nvm_authenticate_sysfs(struct device *dev, const char *buf,
nvm_clear_auth_status(sw);
if (val > 0) {
- if (!sw->nvm->flushed) {
- if (!sw->nvm->buf) {
+ if (val == AUTHENTICATE_ONLY) {
+ if (disconnect)
ret = -EINVAL;
- goto exit_unlock;
+ else
+ ret = nvm_authenticate(sw, true);
+ } else {
+ if (!sw->nvm->flushed) {
+ if (!sw->nvm->buf) {
+ ret = -EINVAL;
+ goto exit_unlock;
+ }
+
+ ret = nvm_validate_and_write(sw);
+ if (ret || val == WRITE_ONLY)
+ goto exit_unlock;
}
-
- ret = nvm_validate_and_write(sw);
- if (ret || val == WRITE_ONLY)
- goto exit_unlock;
- }
- if (val == WRITE_AND_AUTHENTICATE) {
- if (disconnect) {
- ret = tb_lc_force_power(sw);
- } else {
- sw->nvm->authenticating = true;
- ret = nvm_authenticate(sw);
+ if (val == WRITE_AND_AUTHENTICATE) {
+ if (disconnect)
+ ret = tb_lc_force_power(sw);
+ else
+ ret = nvm_authenticate(sw, false);
}
}
}
@@ -2432,6 +2567,14 @@ int tb_switch_lane_bonding_enable(struct tb_switch *sw)
return ret;
}
+ ret = tb_port_wait_for_link_width(down, 2, 100);
+ if (ret) {
+ tb_port_warn(down, "timeout enabling lane bonding\n");
+ return ret;
+ }
+
+ tb_port_update_credits(down);
+ tb_port_update_credits(up);
tb_switch_update_link_attributes(sw);
tb_sw_dbg(sw, "lane bonding enabled\n");
@@ -2462,7 +2605,17 @@ void tb_switch_lane_bonding_disable(struct tb_switch *sw)
tb_port_lane_bonding_disable(up);
tb_port_lane_bonding_disable(down);
+ /*
+ * It is fine if we get other errors as the router might have
+ * been unplugged.
+ */
+ if (tb_port_wait_for_link_width(down, 1, 100) == -ETIMEDOUT)
+ tb_sw_warn(sw, "timeout disabling lane bonding\n");
+
+ tb_port_update_credits(down);
+ tb_port_update_credits(up);
tb_switch_update_link_attributes(sw);
+
tb_sw_dbg(sw, "lane bonding disabled\n");
}
@@ -2529,6 +2682,16 @@ void tb_switch_unconfigure_link(struct tb_switch *sw)
tb_lc_unconfigure_port(down);
}
+static void tb_switch_credits_init(struct tb_switch *sw)
+{
+ if (tb_switch_is_icm(sw))
+ return;
+ if (!tb_switch_is_usb4(sw))
+ return;
+ if (usb4_switch_credits_init(sw))
+ tb_sw_info(sw, "failed to determine preferred buffer allocation, using defaults\n");
+}
+
/**
* tb_switch_add() - Add a switch to the domain
* @sw: Switch to add
@@ -2559,6 +2722,8 @@ int tb_switch_add(struct tb_switch *sw)
}
if (!sw->safe_mode) {
+ tb_switch_credits_init(sw);
+
/* read drom */
ret = tb_drom_read(sw);
if (ret) {
@@ -2612,11 +2777,16 @@ int tb_switch_add(struct tb_switch *sw)
sw->device_name);
}
+ ret = usb4_switch_add_ports(sw);
+ if (ret) {
+ dev_err(&sw->dev, "failed to add USB4 ports\n");
+ goto err_del;
+ }
+
ret = tb_switch_nvm_add(sw);
if (ret) {
dev_err(&sw->dev, "failed to add NVM devices\n");
- device_del(&sw->dev);
- return ret;
+ goto err_ports;
}
/*
@@ -2637,6 +2807,13 @@ int tb_switch_add(struct tb_switch *sw)
tb_switch_debugfs_init(sw);
return 0;
+
+err_ports:
+ usb4_switch_remove_ports(sw);
+err_del:
+ device_del(&sw->dev);
+
+ return ret;
}
/**
@@ -2676,6 +2853,7 @@ void tb_switch_remove(struct tb_switch *sw)
tb_plug_events_active(sw, false);
tb_switch_nvm_remove(sw);
+ usb4_switch_remove_ports(sw);
if (tb_route(sw))
dev_info(&sw->dev, "device disconnected\n");
@@ -2773,22 +2951,11 @@ int tb_switch_resume(struct tb_switch *sw)
/* check for surviving downstream switches */
tb_switch_for_each_port(sw, port) {
- if (!tb_port_has_remote(port) && !port->xdomain) {
- /*
- * For disconnected downstream lane adapters
- * start lane initialization now so we detect
- * future connects.
- */
- if (!tb_is_upstream_port(port) && tb_port_is_null(port))
- tb_port_start_lane_initialization(port);
+ if (!tb_port_is_null(port))
+ continue;
+
+ if (!tb_port_resume(port))
continue;
- } else if (port->xdomain) {
- /*
- * Start lane initialization for XDomain so the
- * link gets re-established.
- */
- tb_port_start_lane_initialization(port);
- }
if (tb_wait_for_port(port, true) <= 0) {
tb_port_warn(port,
@@ -2797,7 +2964,7 @@ int tb_switch_resume(struct tb_switch *sw)
tb_sw_set_unplugged(port->remote->sw);
else if (port->xdomain)
port->xdomain->is_unplugged = true;
- } else if (tb_port_has_remote(port) || port->xdomain) {
+ } else {
/*
* Always unlock the port so the downstream
* switch/domain is accessible.
@@ -2844,7 +3011,8 @@ void tb_switch_suspend(struct tb_switch *sw, bool runtime)
if (runtime) {
/* Trigger wake when something is plugged in/out */
flags |= TB_WAKE_ON_CONNECT | TB_WAKE_ON_DISCONNECT;
- flags |= TB_WAKE_ON_USB4 | TB_WAKE_ON_USB3 | TB_WAKE_ON_PCIE;
+ flags |= TB_WAKE_ON_USB4;
+ flags |= TB_WAKE_ON_USB3 | TB_WAKE_ON_PCIE | TB_WAKE_ON_DP;
} else if (device_may_wakeup(&sw->dev)) {
flags |= TB_WAKE_ON_USB4 | TB_WAKE_ON_USB3 | TB_WAKE_ON_PCIE;
}
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index 7e6dc2b03bed..2897a77d44c3 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -10,6 +10,7 @@
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
+#include <linux/platform_data/x86/apple.h>
#include "tb.h"
#include "tb_regs.h"
@@ -595,7 +596,7 @@ static void tb_scan_port(struct tb_port *port)
return;
}
- tb_retimer_scan(port);
+ tb_retimer_scan(port, true);
sw = tb_switch_alloc(port->sw->tb, &port->sw->dev,
tb_downstream_route(port));
@@ -662,7 +663,7 @@ static void tb_scan_port(struct tb_port *port)
tb_sw_warn(sw, "failed to enable TMU\n");
/* Scan upstream retimers */
- tb_retimer_scan(upstream_port);
+ tb_retimer_scan(upstream_port, true);
/*
* Create USB 3.x tunnels only when the switch is plugged to the
@@ -1571,6 +1572,69 @@ static const struct tb_cm_ops tb_cm_ops = {
.disconnect_xdomain_paths = tb_disconnect_xdomain_paths,
};
+/*
+ * During suspend the Thunderbolt controller is reset and all PCIe
+ * tunnels are lost. The NHI driver will try to reestablish all tunnels
+ * during resume. This adds device links between the tunneled PCIe
+ * downstream ports and the NHI so that the device core will make sure
+ * NHI is resumed first before the rest.
+ */
+static void tb_apple_add_links(struct tb_nhi *nhi)
+{
+ struct pci_dev *upstream, *pdev;
+
+ if (!x86_apple_machine)
+ return;
+
+ switch (nhi->pdev->device) {
+ case PCI_DEVICE_ID_INTEL_LIGHT_RIDGE:
+ case PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C:
+ case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_2C_NHI:
+ case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_NHI:
+ break;
+ default:
+ return;
+ }
+
+ upstream = pci_upstream_bridge(nhi->pdev);
+ while (upstream) {
+ if (!pci_is_pcie(upstream))
+ return;
+ if (pci_pcie_type(upstream) == PCI_EXP_TYPE_UPSTREAM)
+ break;
+ upstream = pci_upstream_bridge(upstream);
+ }
+
+ if (!upstream)
+ return;
+
+ /*
+ * For each hotplug downstream port, create add device link
+ * back to NHI so that PCIe tunnels can be re-established after
+ * sleep.
+ */
+ for_each_pci_bridge(pdev, upstream->subordinate) {
+ const struct device_link *link;
+
+ if (!pci_is_pcie(pdev))
+ continue;
+ if (pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM ||
+ !pdev->is_hotplug_bridge)
+ continue;
+
+ link = device_link_add(&pdev->dev, &nhi->pdev->dev,
+ DL_FLAG_AUTOREMOVE_SUPPLIER |
+ DL_FLAG_PM_RUNTIME);
+ if (link) {
+ dev_dbg(&nhi->pdev->dev, "created link from %s\n",
+ dev_name(&pdev->dev));
+ } else {
+ dev_warn(&nhi->pdev->dev, "device link creation from %s failed\n",
+ dev_name(&pdev->dev));
+ }
+ }
+}
+
struct tb *tb_probe(struct tb_nhi *nhi)
{
struct tb_cm *tcm;
@@ -1594,5 +1658,8 @@ struct tb *tb_probe(struct tb_nhi *nhi)
tb_dbg(tb, "using software connection manager\n");
+ tb_apple_add_links(nhi);
+ tb_acpi_add_links(nhi);
+
return tb;
}
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 9790e9f13d2b..725104c83e3d 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -20,6 +20,7 @@
#define NVM_MIN_SIZE SZ_32K
#define NVM_MAX_SIZE SZ_512K
+#define NVM_DATA_DWORDS 16
/* Intel specific NVM offsets */
#define NVM_DEVID 0x05
@@ -57,6 +58,12 @@ struct tb_nvm {
bool flushed;
};
+enum tb_nvm_write_ops {
+ WRITE_AND_AUTHENTICATE = 1,
+ WRITE_ONLY = 2,
+ AUTHENTICATE_ONLY = 3,
+};
+
#define TB_SWITCH_KEY_SIZE 32
#define TB_SWITCH_MAX_DEPTH 6
#define USB4_SWITCH_MAX_DEPTH 5
@@ -135,6 +142,12 @@ struct tb_switch_tmu {
* @rpm_complete: Completion used to wait for runtime resume to
* complete (ICM only)
* @quirks: Quirks used for this Thunderbolt switch
+ * @credit_allocation: Are the below buffer allocation parameters valid
+ * @max_usb3_credits: Router preferred number of buffers for USB 3.x
+ * @min_dp_aux_credits: Router preferred minimum number of buffers for DP AUX
+ * @min_dp_main_credits: Router preferred minimum number of buffers for DP MAIN
+ * @max_pcie_credits: Router preferred number of buffers for PCIe
+ * @max_dma_credits: Router preferred number of buffers for DMA/P2P
*
* When the switch is being added or removed to the domain (other
* switches) you need to have domain lock held.
@@ -177,6 +190,12 @@ struct tb_switch {
u8 depth;
struct completion rpm_complete;
unsigned long quirks;
+ bool credit_allocation;
+ unsigned int max_usb3_credits;
+ unsigned int min_dp_aux_credits;
+ unsigned int min_dp_main_credits;
+ unsigned int max_pcie_credits;
+ unsigned int max_dma_credits;
};
/**
@@ -189,6 +208,7 @@ struct tb_switch {
* @cap_tmu: Offset of the adapter specific TMU capability (%0 if not present)
* @cap_adap: Offset of the adapter specific capability (%0 if not present)
* @cap_usb4: Offset to the USB4 port capability (%0 if not present)
+ * @usb4: Pointer to the USB4 port structure (only if @cap_usb4 is != %0)
* @port: Port number on switch
* @disabled: Disabled by eeprom or enabled but not implemented
* @bonded: true if the port is bonded (two lanes combined as one)
@@ -198,6 +218,10 @@ struct tb_switch {
* @in_hopids: Currently allocated input HopIDs
* @out_hopids: Currently allocated output HopIDs
* @list: Used to link ports to DP resources list
+ * @total_credits: Total number of buffers available for this port
+ * @ctl_credits: Buffers reserved for control path
+ * @dma_credits: Number of credits allocated for DMA tunneling for all
+ * DMA paths through this port.
*
* In USB4 terminology this structure represents an adapter (protocol or
* lane adapter).
@@ -211,6 +235,7 @@ struct tb_port {
int cap_tmu;
int cap_adap;
int cap_usb4;
+ struct usb4_port *usb4;
u8 port;
bool disabled;
bool bonded;
@@ -219,6 +244,24 @@ struct tb_port {
struct ida in_hopids;
struct ida out_hopids;
struct list_head list;
+ unsigned int total_credits;
+ unsigned int ctl_credits;
+ unsigned int dma_credits;
+};
+
+/**
+ * struct usb4_port - USB4 port device
+ * @dev: Device for the port
+ * @port: Pointer to the lane 0 adapter
+ * @can_offline: Does the port have necessary platform support to moved
+ * it into offline mode and back
+ * @offline: The port is currently in offline mode
+ */
+struct usb4_port {
+ struct device dev;
+ struct tb_port *port;
+ bool can_offline;
+ bool offline;
};
/**
@@ -255,6 +298,8 @@ struct tb_retimer {
* @next_hop_index: HopID of the packet when it is routed out from @out_port
* @initial_credits: Number of initial flow control credits allocated for
* the path
+ * @nfc_credits: Number of non-flow controlled buffers allocated for the
+ * @in_port.
*
* Hop configuration is always done on the IN port of a switch.
* in_port and out_port have to be on the same switch. Packets arriving on
@@ -274,6 +319,7 @@ struct tb_path_hop {
int in_counter_index;
int next_hop_index;
unsigned int initial_credits;
+ unsigned int nfc_credits;
};
/**
@@ -296,7 +342,6 @@ enum tb_path_port {
* struct tb_path - a unidirectional path between two ports
* @tb: Pointer to the domain structure
* @name: Name of the path (used for debugging)
- * @nfc_credits: Number of non flow controlled credits allocated for the path
* @ingress_shared_buffer: Shared buffering used for ingress ports on the path
* @egress_shared_buffer: Shared buffering used for egress ports on the path
* @ingress_fc_enable: Flow control for ingress ports on the path
@@ -317,7 +362,6 @@ enum tb_path_port {
struct tb_path {
struct tb *tb;
const char *name;
- int nfc_credits;
enum tb_path_port ingress_shared_buffer;
enum tb_path_port egress_shared_buffer;
enum tb_path_port ingress_fc_enable;
@@ -346,6 +390,7 @@ struct tb_path {
#define TB_WAKE_ON_USB4 BIT(2)
#define TB_WAKE_ON_USB3 BIT(3)
#define TB_WAKE_ON_PCIE BIT(4)
+#define TB_WAKE_ON_DP BIT(5)
/**
* struct tb_cm_ops - Connection manager specific operations vector
@@ -623,6 +668,7 @@ struct tb *tb_probe(struct tb_nhi *nhi);
extern struct device_type tb_domain_type;
extern struct device_type tb_retimer_type;
extern struct device_type tb_switch_type;
+extern struct device_type usb4_port_device_type;
int tb_domain_init(void);
void tb_domain_exit(void);
@@ -674,6 +720,16 @@ int tb_nvm_add_non_active(struct tb_nvm *nvm, size_t size,
void tb_nvm_free(struct tb_nvm *nvm);
void tb_nvm_exit(void);
+typedef int (*read_block_fn)(void *, unsigned int, void *, size_t);
+typedef int (*write_block_fn)(void *, unsigned int, const void *, size_t);
+
+int tb_nvm_read_data(unsigned int address, void *buf, size_t size,
+ unsigned int retries, read_block_fn read_block,
+ void *read_block_data);
+int tb_nvm_write_data(unsigned int address, const void *buf, size_t size,
+ unsigned int retries, write_block_fn write_next_block,
+ void *write_block_data);
+
struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent,
u64 route);
struct tb_switch *tb_switch_alloc_safe_mode(struct tb *tb,
@@ -853,6 +909,11 @@ void tb_port_release_out_hopid(struct tb_port *port, int hopid);
struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end,
struct tb_port *prev);
+static inline bool tb_port_use_credit_allocation(const struct tb_port *port)
+{
+ return tb_port_is_null(port) && port->sw->credit_allocation;
+}
+
/**
* tb_for_each_port_on_path() - Iterate over each port on path
* @src: Source port
@@ -870,6 +931,9 @@ int tb_port_get_link_width(struct tb_port *port);
int tb_port_state(struct tb_port *port);
int tb_port_lane_bonding_enable(struct tb_port *port);
void tb_port_lane_bonding_disable(struct tb_port *port);
+int tb_port_wait_for_link_width(struct tb_port *port, int width,
+ int timeout_msec);
+int tb_port_update_credits(struct tb_port *port);
int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec);
int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap);
@@ -904,6 +968,17 @@ bool tb_path_is_invalid(struct tb_path *path);
bool tb_path_port_on_path(const struct tb_path *path,
const struct tb_port *port);
+/**
+ * tb_path_for_each_hop() - Iterate over each hop on path
+ * @path: Path whose hops to iterate
+ * @hop: Hop used as iterator
+ *
+ * Iterates over each hop on path.
+ */
+#define tb_path_for_each_hop(path, hop) \
+ for ((hop) = &(path)->hops[0]; \
+ (hop) <= &(path)->hops[(path)->path_length - 1]; (hop)++)
+
int tb_drom_read(struct tb_switch *sw);
int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid);
@@ -950,7 +1025,7 @@ void tb_xdomain_remove(struct tb_xdomain *xd);
struct tb_xdomain *tb_xdomain_find_by_link_depth(struct tb *tb, u8 link,
u8 depth);
-int tb_retimer_scan(struct tb_port *port);
+int tb_retimer_scan(struct tb_port *port, bool add);
void tb_retimer_remove_all(struct tb_port *port);
static inline bool tb_is_retimer(const struct device *dev)
@@ -975,10 +1050,12 @@ int usb4_switch_set_sleep(struct tb_switch *sw);
int usb4_switch_nvm_sector_size(struct tb_switch *sw);
int usb4_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf,
size_t size);
+int usb4_switch_nvm_set_offset(struct tb_switch *sw, unsigned int address);
int usb4_switch_nvm_write(struct tb_switch *sw, unsigned int address,
const void *buf, size_t size);
int usb4_switch_nvm_authenticate(struct tb_switch *sw);
int usb4_switch_nvm_authenticate_status(struct tb_switch *sw, u32 *status);
+int usb4_switch_credits_init(struct tb_switch *sw);
bool usb4_switch_query_dp_resource(struct tb_switch *sw, struct tb_port *in);
int usb4_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in);
int usb4_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in);
@@ -986,20 +1063,27 @@ struct tb_port *usb4_switch_map_pcie_down(struct tb_switch *sw,
const struct tb_port *port);
struct tb_port *usb4_switch_map_usb3_down(struct tb_switch *sw,
const struct tb_port *port);
+int usb4_switch_add_ports(struct tb_switch *sw);
+void usb4_switch_remove_ports(struct tb_switch *sw);
int usb4_port_unlock(struct tb_port *port);
int usb4_port_configure(struct tb_port *port);
void usb4_port_unconfigure(struct tb_port *port);
int usb4_port_configure_xdomain(struct tb_port *port);
void usb4_port_unconfigure_xdomain(struct tb_port *port);
+int usb4_port_router_offline(struct tb_port *port);
+int usb4_port_router_online(struct tb_port *port);
int usb4_port_enumerate_retimers(struct tb_port *port);
+int usb4_port_retimer_set_inbound_sbtx(struct tb_port *port, u8 index);
int usb4_port_retimer_read(struct tb_port *port, u8 index, u8 reg, void *buf,
u8 size);
int usb4_port_retimer_write(struct tb_port *port, u8 index, u8 reg,
const void *buf, u8 size);
int usb4_port_retimer_is_last(struct tb_port *port, u8 index);
int usb4_port_retimer_nvm_sector_size(struct tb_port *port, u8 index);
+int usb4_port_retimer_nvm_set_offset(struct tb_port *port, u8 index,
+ unsigned int address);
int usb4_port_retimer_nvm_write(struct tb_port *port, u8 index,
unsigned int address, const void *buf,
size_t size);
@@ -1018,6 +1102,22 @@ int usb4_usb3_port_allocate_bandwidth(struct tb_port *port, int *upstream_bw,
int usb4_usb3_port_release_bandwidth(struct tb_port *port, int *upstream_bw,
int *downstream_bw);
+static inline bool tb_is_usb4_port_device(const struct device *dev)
+{
+ return dev->type == &usb4_port_device_type;
+}
+
+static inline struct usb4_port *tb_to_usb4_port_device(struct device *dev)
+{
+ if (tb_is_usb4_port_device(dev))
+ return container_of(dev, struct usb4_port, dev);
+ return NULL;
+}
+
+struct usb4_port *usb4_port_device_add(struct tb_port *port);
+void usb4_port_device_remove(struct usb4_port *usb4);
+int usb4_port_device_resume(struct usb4_port *usb4);
+
/* Keep link controller awake during update */
#define QUIRK_FORCE_POWER_LINK_CONTROLLER BIT(0)
@@ -1031,6 +1131,11 @@ bool tb_acpi_may_tunnel_usb3(void);
bool tb_acpi_may_tunnel_dp(void);
bool tb_acpi_may_tunnel_pcie(void);
bool tb_acpi_is_xdomain_allowed(void);
+
+int tb_acpi_init(void);
+void tb_acpi_exit(void);
+int tb_acpi_power_on_retimers(struct tb_port *port);
+int tb_acpi_power_off_retimers(struct tb_port *port);
#else
static inline void tb_acpi_add_links(struct tb_nhi *nhi) { }
@@ -1039,6 +1144,11 @@ static inline bool tb_acpi_may_tunnel_usb3(void) { return true; }
static inline bool tb_acpi_may_tunnel_dp(void) { return true; }
static inline bool tb_acpi_may_tunnel_pcie(void) { return true; }
static inline bool tb_acpi_is_xdomain_allowed(void) { return true; }
+
+static inline int tb_acpi_init(void) { return 0; }
+static inline void tb_acpi_exit(void) { }
+static inline int tb_acpi_power_on_retimers(struct tb_port *port) { return 0; }
+static inline int tb_acpi_power_off_retimers(struct tb_port *port) { return 0; }
#endif
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h
index 626751e06292..484f25be2849 100644
--- a/drivers/thunderbolt/tb_regs.h
+++ b/drivers/thunderbolt/tb_regs.h
@@ -195,6 +195,7 @@ struct tb_regs_switch_header {
#define ROUTER_CS_5_SLP BIT(0)
#define ROUTER_CS_5_WOP BIT(1)
#define ROUTER_CS_5_WOU BIT(2)
+#define ROUTER_CS_5_WOD BIT(3)
#define ROUTER_CS_5_C3S BIT(23)
#define ROUTER_CS_5_PTO BIT(24)
#define ROUTER_CS_5_UTO BIT(25)
@@ -228,6 +229,7 @@ enum usb4_switch_op {
USB4_SWITCH_OP_NVM_SET_OFFSET = 0x23,
USB4_SWITCH_OP_DROM_READ = 0x24,
USB4_SWITCH_OP_NVM_SECTOR_SIZE = 0x25,
+ USB4_SWITCH_OP_BUFFER_ALLOC = 0x33,
};
/* Router TMU configuration */
@@ -458,6 +460,8 @@ struct tb_regs_hop {
#define TB_LC_SX_CTRL 0x96
#define TB_LC_SX_CTRL_WOC BIT(1)
#define TB_LC_SX_CTRL_WOD BIT(2)
+#define TB_LC_SX_CTRL_WODPC BIT(3)
+#define TB_LC_SX_CTRL_WODPD BIT(4)
#define TB_LC_SX_CTRL_WOU4 BIT(5)
#define TB_LC_SX_CTRL_WOP BIT(6)
#define TB_LC_SX_CTRL_L1C BIT(16)
diff --git a/drivers/thunderbolt/test.c b/drivers/thunderbolt/test.c
index 5ff5a03bc9ce..eca0ef311bde 100644
--- a/drivers/thunderbolt/test.c
+++ b/drivers/thunderbolt/test.c
@@ -87,22 +87,30 @@ static struct tb_switch *alloc_host(struct kunit *test)
sw->ports[1].config.type = TB_TYPE_PORT;
sw->ports[1].config.max_in_hop_id = 19;
sw->ports[1].config.max_out_hop_id = 19;
+ sw->ports[1].total_credits = 60;
+ sw->ports[1].ctl_credits = 2;
sw->ports[1].dual_link_port = &sw->ports[2];
sw->ports[2].config.type = TB_TYPE_PORT;
sw->ports[2].config.max_in_hop_id = 19;
sw->ports[2].config.max_out_hop_id = 19;
+ sw->ports[2].total_credits = 60;
+ sw->ports[2].ctl_credits = 2;
sw->ports[2].dual_link_port = &sw->ports[1];
sw->ports[2].link_nr = 1;
sw->ports[3].config.type = TB_TYPE_PORT;
sw->ports[3].config.max_in_hop_id = 19;
sw->ports[3].config.max_out_hop_id = 19;
+ sw->ports[3].total_credits = 60;
+ sw->ports[3].ctl_credits = 2;
sw->ports[3].dual_link_port = &sw->ports[4];
sw->ports[4].config.type = TB_TYPE_PORT;
sw->ports[4].config.max_in_hop_id = 19;
sw->ports[4].config.max_out_hop_id = 19;
+ sw->ports[4].total_credits = 60;
+ sw->ports[4].ctl_credits = 2;
sw->ports[4].dual_link_port = &sw->ports[3];
sw->ports[4].link_nr = 1;
@@ -143,6 +151,25 @@ static struct tb_switch *alloc_host(struct kunit *test)
return sw;
}
+static struct tb_switch *alloc_host_usb4(struct kunit *test)
+{
+ struct tb_switch *sw;
+
+ sw = alloc_host(test);
+ if (!sw)
+ return NULL;
+
+ sw->generation = 4;
+ sw->credit_allocation = true;
+ sw->max_usb3_credits = 32;
+ sw->min_dp_aux_credits = 1;
+ sw->min_dp_main_credits = 0;
+ sw->max_pcie_credits = 64;
+ sw->max_dma_credits = 14;
+
+ return sw;
+}
+
static struct tb_switch *alloc_dev_default(struct kunit *test,
struct tb_switch *parent,
u64 route, bool bonded)
@@ -164,44 +191,60 @@ static struct tb_switch *alloc_dev_default(struct kunit *test,
sw->ports[1].config.type = TB_TYPE_PORT;
sw->ports[1].config.max_in_hop_id = 19;
sw->ports[1].config.max_out_hop_id = 19;
+ sw->ports[1].total_credits = 60;
+ sw->ports[1].ctl_credits = 2;
sw->ports[1].dual_link_port = &sw->ports[2];
sw->ports[2].config.type = TB_TYPE_PORT;
sw->ports[2].config.max_in_hop_id = 19;
sw->ports[2].config.max_out_hop_id = 19;
+ sw->ports[2].total_credits = 60;
+ sw->ports[2].ctl_credits = 2;
sw->ports[2].dual_link_port = &sw->ports[1];
sw->ports[2].link_nr = 1;
sw->ports[3].config.type = TB_TYPE_PORT;
sw->ports[3].config.max_in_hop_id = 19;
sw->ports[3].config.max_out_hop_id = 19;
+ sw->ports[3].total_credits = 60;
+ sw->ports[3].ctl_credits = 2;
sw->ports[3].dual_link_port = &sw->ports[4];
sw->ports[4].config.type = TB_TYPE_PORT;
sw->ports[4].config.max_in_hop_id = 19;
sw->ports[4].config.max_out_hop_id = 19;
+ sw->ports[4].total_credits = 60;
+ sw->ports[4].ctl_credits = 2;
sw->ports[4].dual_link_port = &sw->ports[3];
sw->ports[4].link_nr = 1;
sw->ports[5].config.type = TB_TYPE_PORT;
sw->ports[5].config.max_in_hop_id = 19;
sw->ports[5].config.max_out_hop_id = 19;
+ sw->ports[5].total_credits = 60;
+ sw->ports[5].ctl_credits = 2;
sw->ports[5].dual_link_port = &sw->ports[6];
sw->ports[6].config.type = TB_TYPE_PORT;
sw->ports[6].config.max_in_hop_id = 19;
sw->ports[6].config.max_out_hop_id = 19;
+ sw->ports[6].total_credits = 60;
+ sw->ports[6].ctl_credits = 2;
sw->ports[6].dual_link_port = &sw->ports[5];
sw->ports[6].link_nr = 1;
sw->ports[7].config.type = TB_TYPE_PORT;
sw->ports[7].config.max_in_hop_id = 19;
sw->ports[7].config.max_out_hop_id = 19;
+ sw->ports[7].total_credits = 60;
+ sw->ports[7].ctl_credits = 2;
sw->ports[7].dual_link_port = &sw->ports[8];
sw->ports[8].config.type = TB_TYPE_PORT;
sw->ports[8].config.max_in_hop_id = 19;
sw->ports[8].config.max_out_hop_id = 19;
+ sw->ports[8].total_credits = 60;
+ sw->ports[8].ctl_credits = 2;
sw->ports[8].dual_link_port = &sw->ports[7];
sw->ports[8].link_nr = 1;
@@ -260,14 +303,18 @@ static struct tb_switch *alloc_dev_default(struct kunit *test,
if (port->dual_link_port && upstream_port->dual_link_port) {
port->dual_link_port->remote = upstream_port->dual_link_port;
upstream_port->dual_link_port->remote = port->dual_link_port;
- }
- if (bonded) {
- /* Bonding is used */
- port->bonded = true;
- port->dual_link_port->bonded = true;
- upstream_port->bonded = true;
- upstream_port->dual_link_port->bonded = true;
+ if (bonded) {
+ /* Bonding is used */
+ port->bonded = true;
+ port->total_credits *= 2;
+ port->dual_link_port->bonded = true;
+ port->dual_link_port->total_credits = 0;
+ upstream_port->bonded = true;
+ upstream_port->total_credits *= 2;
+ upstream_port->dual_link_port->bonded = true;
+ upstream_port->dual_link_port->total_credits = 0;
+ }
}
return sw;
@@ -294,6 +341,27 @@ static struct tb_switch *alloc_dev_with_dpin(struct kunit *test,
return sw;
}
+static struct tb_switch *alloc_dev_usb4(struct kunit *test,
+ struct tb_switch *parent,
+ u64 route, bool bonded)
+{
+ struct tb_switch *sw;
+
+ sw = alloc_dev_default(test, parent, route, bonded);
+ if (!sw)
+ return NULL;
+
+ sw->generation = 4;
+ sw->credit_allocation = true;
+ sw->max_usb3_credits = 14;
+ sw->min_dp_aux_credits = 1;
+ sw->min_dp_main_credits = 18;
+ sw->max_pcie_credits = 32;
+ sw->max_dma_credits = 14;
+
+ return sw;
+}
+
static void tb_test_path_basic(struct kunit *test)
{
struct tb_port *src_port, *dst_port, *p;
@@ -389,7 +457,7 @@ static void tb_test_path_single_hop_walk(struct kunit *test)
i++;
}
- KUNIT_EXPECT_EQ(test, i, (int)ARRAY_SIZE(test_data));
+ KUNIT_EXPECT_EQ(test, i, ARRAY_SIZE(test_data));
i = ARRAY_SIZE(test_data) - 1;
tb_for_each_port_on_path(dst_port, src_port, p) {
@@ -448,7 +516,7 @@ static void tb_test_path_daisy_chain_walk(struct kunit *test)
i++;
}
- KUNIT_EXPECT_EQ(test, i, (int)ARRAY_SIZE(test_data));
+ KUNIT_EXPECT_EQ(test, i, ARRAY_SIZE(test_data));
i = ARRAY_SIZE(test_data) - 1;
tb_for_each_port_on_path(dst_port, src_port, p) {
@@ -511,7 +579,7 @@ static void tb_test_path_simple_tree_walk(struct kunit *test)
i++;
}
- KUNIT_EXPECT_EQ(test, i, (int)ARRAY_SIZE(test_data));
+ KUNIT_EXPECT_EQ(test, i, ARRAY_SIZE(test_data));
i = ARRAY_SIZE(test_data) - 1;
tb_for_each_port_on_path(dst_port, src_port, p) {
@@ -595,7 +663,7 @@ static void tb_test_path_complex_tree_walk(struct kunit *test)
i++;
}
- KUNIT_EXPECT_EQ(test, i, (int)ARRAY_SIZE(test_data));
+ KUNIT_EXPECT_EQ(test, i, ARRAY_SIZE(test_data));
i = ARRAY_SIZE(test_data) - 1;
tb_for_each_port_on_path(dst_port, src_port, p) {
@@ -698,7 +766,7 @@ static void tb_test_path_max_length_walk(struct kunit *test)
i++;
}
- KUNIT_EXPECT_EQ(test, i, (int)ARRAY_SIZE(test_data));
+ KUNIT_EXPECT_EQ(test, i, ARRAY_SIZE(test_data));
i = ARRAY_SIZE(test_data) - 1;
tb_for_each_port_on_path(dst_port, src_port, p) {
@@ -780,7 +848,7 @@ static void tb_test_path_not_bonded_lane0(struct kunit *test)
path = tb_path_alloc(NULL, down, 8, up, 8, 0, "PCIe Down");
KUNIT_ASSERT_TRUE(test, path != NULL);
- KUNIT_ASSERT_EQ(test, path->path_length, (int)ARRAY_SIZE(test_data));
+ KUNIT_ASSERT_EQ(test, path->path_length, ARRAY_SIZE(test_data));
for (i = 0; i < ARRAY_SIZE(test_data); i++) {
const struct tb_port *in_port, *out_port;
@@ -842,7 +910,7 @@ static void tb_test_path_not_bonded_lane1(struct kunit *test)
path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video");
KUNIT_ASSERT_TRUE(test, path != NULL);
- KUNIT_ASSERT_EQ(test, path->path_length, (int)ARRAY_SIZE(test_data));
+ KUNIT_ASSERT_EQ(test, path->path_length, ARRAY_SIZE(test_data));
for (i = 0; i < ARRAY_SIZE(test_data); i++) {
const struct tb_port *in_port, *out_port;
@@ -922,7 +990,7 @@ static void tb_test_path_not_bonded_lane1_chain(struct kunit *test)
path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video");
KUNIT_ASSERT_TRUE(test, path != NULL);
- KUNIT_ASSERT_EQ(test, path->path_length, (int)ARRAY_SIZE(test_data));
+ KUNIT_ASSERT_EQ(test, path->path_length, ARRAY_SIZE(test_data));
for (i = 0; i < ARRAY_SIZE(test_data); i++) {
const struct tb_port *in_port, *out_port;
@@ -1002,7 +1070,7 @@ static void tb_test_path_not_bonded_lane1_chain_reverse(struct kunit *test)
path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video");
KUNIT_ASSERT_TRUE(test, path != NULL);
- KUNIT_ASSERT_EQ(test, path->path_length, (int)ARRAY_SIZE(test_data));
+ KUNIT_ASSERT_EQ(test, path->path_length, ARRAY_SIZE(test_data));
for (i = 0; i < ARRAY_SIZE(test_data); i++) {
const struct tb_port *in_port, *out_port;
@@ -1094,7 +1162,7 @@ static void tb_test_path_mixed_chain(struct kunit *test)
path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video");
KUNIT_ASSERT_TRUE(test, path != NULL);
- KUNIT_ASSERT_EQ(test, path->path_length, (int)ARRAY_SIZE(test_data));
+ KUNIT_ASSERT_EQ(test, path->path_length, ARRAY_SIZE(test_data));
for (i = 0; i < ARRAY_SIZE(test_data); i++) {
const struct tb_port *in_port, *out_port;
@@ -1186,7 +1254,7 @@ static void tb_test_path_mixed_chain_reverse(struct kunit *test)
path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video");
KUNIT_ASSERT_TRUE(test, path != NULL);
- KUNIT_ASSERT_EQ(test, path->path_length, (int)ARRAY_SIZE(test_data));
+ KUNIT_ASSERT_EQ(test, path->path_length, ARRAY_SIZE(test_data));
for (i = 0; i < ARRAY_SIZE(test_data); i++) {
const struct tb_port *in_port, *out_port;
@@ -1230,10 +1298,10 @@ static void tb_test_tunnel_pcie(struct kunit *test)
up = &dev1->ports[9];
tunnel1 = tb_tunnel_alloc_pci(NULL, up, down);
KUNIT_ASSERT_TRUE(test, tunnel1 != NULL);
- KUNIT_EXPECT_EQ(test, tunnel1->type, (enum tb_tunnel_type)TB_TUNNEL_PCI);
+ KUNIT_EXPECT_EQ(test, tunnel1->type, TB_TUNNEL_PCI);
KUNIT_EXPECT_PTR_EQ(test, tunnel1->src_port, down);
KUNIT_EXPECT_PTR_EQ(test, tunnel1->dst_port, up);
- KUNIT_ASSERT_EQ(test, tunnel1->npaths, (size_t)2);
+ KUNIT_ASSERT_EQ(test, tunnel1->npaths, 2);
KUNIT_ASSERT_EQ(test, tunnel1->paths[0]->path_length, 2);
KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[0]->hops[0].in_port, down);
KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[0]->hops[1].out_port, up);
@@ -1245,10 +1313,10 @@ static void tb_test_tunnel_pcie(struct kunit *test)
up = &dev2->ports[9];
tunnel2 = tb_tunnel_alloc_pci(NULL, up, down);
KUNIT_ASSERT_TRUE(test, tunnel2 != NULL);
- KUNIT_EXPECT_EQ(test, tunnel2->type, (enum tb_tunnel_type)TB_TUNNEL_PCI);
+ KUNIT_EXPECT_EQ(test, tunnel2->type, TB_TUNNEL_PCI);
KUNIT_EXPECT_PTR_EQ(test, tunnel2->src_port, down);
KUNIT_EXPECT_PTR_EQ(test, tunnel2->dst_port, up);
- KUNIT_ASSERT_EQ(test, tunnel2->npaths, (size_t)2);
+ KUNIT_ASSERT_EQ(test, tunnel2->npaths, 2);
KUNIT_ASSERT_EQ(test, tunnel2->paths[0]->path_length, 2);
KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[0]->hops[0].in_port, down);
KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[0]->hops[1].out_port, up);
@@ -1282,10 +1350,10 @@ static void tb_test_tunnel_dp(struct kunit *test)
tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
KUNIT_ASSERT_TRUE(test, tunnel != NULL);
- KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DP);
+ KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, out);
- KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)3);
+ KUNIT_ASSERT_EQ(test, tunnel->npaths, 3);
KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 2);
KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, in);
KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[1].out_port, out);
@@ -1328,10 +1396,10 @@ static void tb_test_tunnel_dp_chain(struct kunit *test)
tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
KUNIT_ASSERT_TRUE(test, tunnel != NULL);
- KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DP);
+ KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, out);
- KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)3);
+ KUNIT_ASSERT_EQ(test, tunnel->npaths, 3);
KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 3);
KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, in);
KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[2].out_port, out);
@@ -1378,10 +1446,10 @@ static void tb_test_tunnel_dp_tree(struct kunit *test)
tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
KUNIT_ASSERT_TRUE(test, tunnel != NULL);
- KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DP);
+ KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, out);
- KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)3);
+ KUNIT_ASSERT_EQ(test, tunnel->npaths, 3);
KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 4);
KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, in);
KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[3].out_port, out);
@@ -1443,10 +1511,10 @@ static void tb_test_tunnel_dp_max_length(struct kunit *test)
tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
KUNIT_ASSERT_TRUE(test, tunnel != NULL);
- KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DP);
+ KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, out);
- KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)3);
+ KUNIT_ASSERT_EQ(test, tunnel->npaths, 3);
KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 13);
/* First hop */
KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, in);
@@ -1499,10 +1567,10 @@ static void tb_test_tunnel_usb3(struct kunit *test)
up = &dev1->ports[16];
tunnel1 = tb_tunnel_alloc_usb3(NULL, up, down, 0, 0);
KUNIT_ASSERT_TRUE(test, tunnel1 != NULL);
- KUNIT_EXPECT_EQ(test, tunnel1->type, (enum tb_tunnel_type)TB_TUNNEL_USB3);
+ KUNIT_EXPECT_EQ(test, tunnel1->type, TB_TUNNEL_USB3);
KUNIT_EXPECT_PTR_EQ(test, tunnel1->src_port, down);
KUNIT_EXPECT_PTR_EQ(test, tunnel1->dst_port, up);
- KUNIT_ASSERT_EQ(test, tunnel1->npaths, (size_t)2);
+ KUNIT_ASSERT_EQ(test, tunnel1->npaths, 2);
KUNIT_ASSERT_EQ(test, tunnel1->paths[0]->path_length, 2);
KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[0]->hops[0].in_port, down);
KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[0]->hops[1].out_port, up);
@@ -1514,10 +1582,10 @@ static void tb_test_tunnel_usb3(struct kunit *test)
up = &dev2->ports[16];
tunnel2 = tb_tunnel_alloc_usb3(NULL, up, down, 0, 0);
KUNIT_ASSERT_TRUE(test, tunnel2 != NULL);
- KUNIT_EXPECT_EQ(test, tunnel2->type, (enum tb_tunnel_type)TB_TUNNEL_USB3);
+ KUNIT_EXPECT_EQ(test, tunnel2->type, TB_TUNNEL_USB3);
KUNIT_EXPECT_PTR_EQ(test, tunnel2->src_port, down);
KUNIT_EXPECT_PTR_EQ(test, tunnel2->dst_port, up);
- KUNIT_ASSERT_EQ(test, tunnel2->npaths, (size_t)2);
+ KUNIT_ASSERT_EQ(test, tunnel2->npaths, 2);
KUNIT_ASSERT_EQ(test, tunnel2->paths[0]->path_length, 2);
KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[0]->hops[0].in_port, down);
KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[0]->hops[1].out_port, up);
@@ -1618,10 +1686,10 @@ static void tb_test_tunnel_dma(struct kunit *test)
tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 8, 1, 8, 1);
KUNIT_ASSERT_TRUE(test, tunnel != NULL);
- KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DMA);
+ KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DMA);
KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, nhi);
KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, port);
- KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2);
+ KUNIT_ASSERT_EQ(test, tunnel->npaths, 2);
/* RX path */
KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 1);
KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, port);
@@ -1661,10 +1729,10 @@ static void tb_test_tunnel_dma_rx(struct kunit *test)
tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, -1, -1, 15, 2);
KUNIT_ASSERT_TRUE(test, tunnel != NULL);
- KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DMA);
+ KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DMA);
KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, nhi);
KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, port);
- KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)1);
+ KUNIT_ASSERT_EQ(test, tunnel->npaths, 1);
/* RX path */
KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 1);
KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, port);
@@ -1698,10 +1766,10 @@ static void tb_test_tunnel_dma_tx(struct kunit *test)
tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 15, 2, -1, -1);
KUNIT_ASSERT_TRUE(test, tunnel != NULL);
- KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DMA);
+ KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DMA);
KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, nhi);
KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, port);
- KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)1);
+ KUNIT_ASSERT_EQ(test, tunnel->npaths, 1);
/* TX path */
KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 1);
KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, nhi);
@@ -1744,10 +1812,10 @@ static void tb_test_tunnel_dma_chain(struct kunit *test)
port = &dev2->ports[3];
tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 8, 1, 8, 1);
KUNIT_ASSERT_TRUE(test, tunnel != NULL);
- KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DMA);
+ KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DMA);
KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, nhi);
KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, port);
- KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2);
+ KUNIT_ASSERT_EQ(test, tunnel->npaths, 2);
/* RX path */
KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 3);
KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, port);
@@ -1829,6 +1897,475 @@ static void tb_test_tunnel_dma_match(struct kunit *test)
tb_tunnel_free(tunnel);
}
+static void tb_test_credit_alloc_legacy_not_bonded(struct kunit *test)
+{
+ struct tb_switch *host, *dev;
+ struct tb_port *up, *down;
+ struct tb_tunnel *tunnel;
+ struct tb_path *path;
+
+ host = alloc_host(test);
+ dev = alloc_dev_default(test, host, 0x1, false);
+
+ down = &host->ports[8];
+ up = &dev->ports[9];
+ tunnel = tb_tunnel_alloc_pci(NULL, up, down);
+ KUNIT_ASSERT_TRUE(test, tunnel != NULL);
+ KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2);
+
+ path = tunnel->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 16U);
+
+ path = tunnel->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 16U);
+
+ tb_tunnel_free(tunnel);
+}
+
+static void tb_test_credit_alloc_legacy_bonded(struct kunit *test)
+{
+ struct tb_switch *host, *dev;
+ struct tb_port *up, *down;
+ struct tb_tunnel *tunnel;
+ struct tb_path *path;
+
+ host = alloc_host(test);
+ dev = alloc_dev_default(test, host, 0x1, true);
+
+ down = &host->ports[8];
+ up = &dev->ports[9];
+ tunnel = tb_tunnel_alloc_pci(NULL, up, down);
+ KUNIT_ASSERT_TRUE(test, tunnel != NULL);
+ KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2);
+
+ path = tunnel->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 32U);
+
+ path = tunnel->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 32U);
+
+ tb_tunnel_free(tunnel);
+}
+
+static void tb_test_credit_alloc_pcie(struct kunit *test)
+{
+ struct tb_switch *host, *dev;
+ struct tb_port *up, *down;
+ struct tb_tunnel *tunnel;
+ struct tb_path *path;
+
+ host = alloc_host_usb4(test);
+ dev = alloc_dev_usb4(test, host, 0x1, true);
+
+ down = &host->ports[8];
+ up = &dev->ports[9];
+ tunnel = tb_tunnel_alloc_pci(NULL, up, down);
+ KUNIT_ASSERT_TRUE(test, tunnel != NULL);
+ KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2);
+
+ path = tunnel->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 32U);
+
+ path = tunnel->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 64U);
+
+ tb_tunnel_free(tunnel);
+}
+
+static void tb_test_credit_alloc_dp(struct kunit *test)
+{
+ struct tb_switch *host, *dev;
+ struct tb_port *in, *out;
+ struct tb_tunnel *tunnel;
+ struct tb_path *path;
+
+ host = alloc_host_usb4(test);
+ dev = alloc_dev_usb4(test, host, 0x1, true);
+
+ in = &host->ports[5];
+ out = &dev->ports[14];
+
+ tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
+ KUNIT_ASSERT_TRUE(test, tunnel != NULL);
+ KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)3);
+
+ /* Video (main) path */
+ path = tunnel->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 12U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 18U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 0U);
+
+ /* AUX TX */
+ path = tunnel->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 1U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
+
+ /* AUX RX */
+ path = tunnel->paths[2];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 1U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
+
+ tb_tunnel_free(tunnel);
+}
+
+static void tb_test_credit_alloc_usb3(struct kunit *test)
+{
+ struct tb_switch *host, *dev;
+ struct tb_port *up, *down;
+ struct tb_tunnel *tunnel;
+ struct tb_path *path;
+
+ host = alloc_host_usb4(test);
+ dev = alloc_dev_usb4(test, host, 0x1, true);
+
+ down = &host->ports[12];
+ up = &dev->ports[16];
+ tunnel = tb_tunnel_alloc_usb3(NULL, up, down, 0, 0);
+ KUNIT_ASSERT_TRUE(test, tunnel != NULL);
+ KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2);
+
+ path = tunnel->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
+
+ path = tunnel->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 32U);
+
+ tb_tunnel_free(tunnel);
+}
+
+static void tb_test_credit_alloc_dma(struct kunit *test)
+{
+ struct tb_switch *host, *dev;
+ struct tb_port *nhi, *port;
+ struct tb_tunnel *tunnel;
+ struct tb_path *path;
+
+ host = alloc_host_usb4(test);
+ dev = alloc_dev_usb4(test, host, 0x1, true);
+
+ nhi = &host->ports[7];
+ port = &dev->ports[3];
+
+ tunnel = tb_tunnel_alloc_dma(NULL, nhi, port, 8, 1, 8, 1);
+ KUNIT_ASSERT_TRUE(test, tunnel != NULL);
+ KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)2);
+
+ /* DMA RX */
+ path = tunnel->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 14U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
+
+ /* DMA TX */
+ path = tunnel->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
+
+ tb_tunnel_free(tunnel);
+}
+
+static void tb_test_credit_alloc_dma_multiple(struct kunit *test)
+{
+ struct tb_tunnel *tunnel1, *tunnel2, *tunnel3;
+ struct tb_switch *host, *dev;
+ struct tb_port *nhi, *port;
+ struct tb_path *path;
+
+ host = alloc_host_usb4(test);
+ dev = alloc_dev_usb4(test, host, 0x1, true);
+
+ nhi = &host->ports[7];
+ port = &dev->ports[3];
+
+ /*
+ * Create three DMA tunnels through the same ports. With the
+ * default buffers we should be able to create two and the last
+ * one fails.
+ *
+ * For default host we have following buffers for DMA:
+ *
+ * 120 - (2 + 2 * (1 + 0) + 32 + 64 + spare) = 20
+ *
+ * For device we have following:
+ *
+ * 120 - (2 + 2 * (1 + 18) + 14 + 32 + spare) = 34
+ *
+ * spare = 14 + 1 = 15
+ *
+ * So on host the first tunnel gets 14 and the second gets the
+ * remaining 1 and then we run out of buffers.
+ */
+ tunnel1 = tb_tunnel_alloc_dma(NULL, nhi, port, 8, 1, 8, 1);
+ KUNIT_ASSERT_TRUE(test, tunnel1 != NULL);
+ KUNIT_ASSERT_EQ(test, tunnel1->npaths, (size_t)2);
+
+ path = tunnel1->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 14U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
+
+ path = tunnel1->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
+
+ tunnel2 = tb_tunnel_alloc_dma(NULL, nhi, port, 9, 2, 9, 2);
+ KUNIT_ASSERT_TRUE(test, tunnel2 != NULL);
+ KUNIT_ASSERT_EQ(test, tunnel2->npaths, (size_t)2);
+
+ path = tunnel2->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 14U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
+
+ path = tunnel2->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
+
+ tunnel3 = tb_tunnel_alloc_dma(NULL, nhi, port, 10, 3, 10, 3);
+ KUNIT_ASSERT_TRUE(test, tunnel3 == NULL);
+
+ /*
+ * Release the first DMA tunnel. That should make 14 buffers
+ * available for the next tunnel.
+ */
+ tb_tunnel_free(tunnel1);
+
+ tunnel3 = tb_tunnel_alloc_dma(NULL, nhi, port, 10, 3, 10, 3);
+ KUNIT_ASSERT_TRUE(test, tunnel3 != NULL);
+
+ path = tunnel3->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 14U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
+
+ path = tunnel3->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
+
+ tb_tunnel_free(tunnel3);
+ tb_tunnel_free(tunnel2);
+}
+
+static void tb_test_credit_alloc_all(struct kunit *test)
+{
+ struct tb_port *up, *down, *in, *out, *nhi, *port;
+ struct tb_tunnel *pcie_tunnel, *dp_tunnel1, *dp_tunnel2, *usb3_tunnel;
+ struct tb_tunnel *dma_tunnel1, *dma_tunnel2;
+ struct tb_switch *host, *dev;
+ struct tb_path *path;
+
+ /*
+ * Create PCIe, 2 x DP, USB 3.x and two DMA tunnels from host to
+ * device. Expectation is that all these can be established with
+ * the default credit allocation found in Intel hardware.
+ */
+
+ host = alloc_host_usb4(test);
+ dev = alloc_dev_usb4(test, host, 0x1, true);
+
+ down = &host->ports[8];
+ up = &dev->ports[9];
+ pcie_tunnel = tb_tunnel_alloc_pci(NULL, up, down);
+ KUNIT_ASSERT_TRUE(test, pcie_tunnel != NULL);
+ KUNIT_ASSERT_EQ(test, pcie_tunnel->npaths, (size_t)2);
+
+ path = pcie_tunnel->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 32U);
+
+ path = pcie_tunnel->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 64U);
+
+ in = &host->ports[5];
+ out = &dev->ports[13];
+
+ dp_tunnel1 = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
+ KUNIT_ASSERT_TRUE(test, dp_tunnel1 != NULL);
+ KUNIT_ASSERT_EQ(test, dp_tunnel1->npaths, (size_t)3);
+
+ path = dp_tunnel1->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 12U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 18U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 0U);
+
+ path = dp_tunnel1->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 1U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
+
+ path = dp_tunnel1->paths[2];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 1U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
+
+ in = &host->ports[6];
+ out = &dev->ports[14];
+
+ dp_tunnel2 = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
+ KUNIT_ASSERT_TRUE(test, dp_tunnel2 != NULL);
+ KUNIT_ASSERT_EQ(test, dp_tunnel2->npaths, (size_t)3);
+
+ path = dp_tunnel2->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 12U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 18U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 0U);
+
+ path = dp_tunnel2->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 1U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
+
+ path = dp_tunnel2->paths[2];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 1U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
+
+ down = &host->ports[12];
+ up = &dev->ports[16];
+ usb3_tunnel = tb_tunnel_alloc_usb3(NULL, up, down, 0, 0);
+ KUNIT_ASSERT_TRUE(test, usb3_tunnel != NULL);
+ KUNIT_ASSERT_EQ(test, usb3_tunnel->npaths, (size_t)2);
+
+ path = usb3_tunnel->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
+
+ path = usb3_tunnel->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 7U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 32U);
+
+ nhi = &host->ports[7];
+ port = &dev->ports[3];
+
+ dma_tunnel1 = tb_tunnel_alloc_dma(NULL, nhi, port, 8, 1, 8, 1);
+ KUNIT_ASSERT_TRUE(test, dma_tunnel1 != NULL);
+ KUNIT_ASSERT_EQ(test, dma_tunnel1->npaths, (size_t)2);
+
+ path = dma_tunnel1->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 14U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
+
+ path = dma_tunnel1->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 14U);
+
+ dma_tunnel2 = tb_tunnel_alloc_dma(NULL, nhi, port, 9, 2, 9, 2);
+ KUNIT_ASSERT_TRUE(test, dma_tunnel2 != NULL);
+ KUNIT_ASSERT_EQ(test, dma_tunnel2->npaths, (size_t)2);
+
+ path = dma_tunnel2->paths[0];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 14U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
+
+ path = dma_tunnel2->paths[1];
+ KUNIT_ASSERT_EQ(test, path->path_length, 2);
+ KUNIT_EXPECT_EQ(test, path->hops[0].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[0].initial_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].nfc_credits, 0U);
+ KUNIT_EXPECT_EQ(test, path->hops[1].initial_credits, 1U);
+
+ tb_tunnel_free(dma_tunnel2);
+ tb_tunnel_free(dma_tunnel1);
+ tb_tunnel_free(usb3_tunnel);
+ tb_tunnel_free(dp_tunnel2);
+ tb_tunnel_free(dp_tunnel1);
+ tb_tunnel_free(pcie_tunnel);
+}
+
static const u32 root_directory[] = {
0x55584401, /* "UXD" v1 */
0x00000018, /* Root directory length */
@@ -1906,7 +2443,7 @@ static void tb_test_property_parse(struct kunit *test)
p = tb_property_find(dir, "vendorid", TB_PROPERTY_TYPE_VALUE);
KUNIT_ASSERT_TRUE(test, p != NULL);
- KUNIT_EXPECT_EQ(test, p->value.immediate, (u32)0xa27);
+ KUNIT_EXPECT_EQ(test, p->value.immediate, 0xa27);
p = tb_property_find(dir, "deviceid", TB_PROPERTY_TYPE_TEXT);
KUNIT_ASSERT_TRUE(test, p != NULL);
@@ -1914,7 +2451,7 @@ static void tb_test_property_parse(struct kunit *test)
p = tb_property_find(dir, "deviceid", TB_PROPERTY_TYPE_VALUE);
KUNIT_ASSERT_TRUE(test, p != NULL);
- KUNIT_EXPECT_EQ(test, p->value.immediate, (u32)0xa);
+ KUNIT_EXPECT_EQ(test, p->value.immediate, 0xa);
p = tb_property_find(dir, "missing", TB_PROPERTY_TYPE_DIRECTORY);
KUNIT_ASSERT_TRUE(test, !p);
@@ -1927,19 +2464,19 @@ static void tb_test_property_parse(struct kunit *test)
p = tb_property_find(network_dir, "prtcid", TB_PROPERTY_TYPE_VALUE);
KUNIT_ASSERT_TRUE(test, p != NULL);
- KUNIT_EXPECT_EQ(test, p->value.immediate, (u32)0x1);
+ KUNIT_EXPECT_EQ(test, p->value.immediate, 0x1);
p = tb_property_find(network_dir, "prtcvers", TB_PROPERTY_TYPE_VALUE);
KUNIT_ASSERT_TRUE(test, p != NULL);
- KUNIT_EXPECT_EQ(test, p->value.immediate, (u32)0x1);
+ KUNIT_EXPECT_EQ(test, p->value.immediate, 0x1);
p = tb_property_find(network_dir, "prtcrevs", TB_PROPERTY_TYPE_VALUE);
KUNIT_ASSERT_TRUE(test, p != NULL);
- KUNIT_EXPECT_EQ(test, p->value.immediate, (u32)0x1);
+ KUNIT_EXPECT_EQ(test, p->value.immediate, 0x1);
p = tb_property_find(network_dir, "prtcstns", TB_PROPERTY_TYPE_VALUE);
KUNIT_ASSERT_TRUE(test, p != NULL);
- KUNIT_EXPECT_EQ(test, p->value.immediate, (u32)0x0);
+ KUNIT_EXPECT_EQ(test, p->value.immediate, 0x0);
p = tb_property_find(network_dir, "deviceid", TB_PROPERTY_TYPE_VALUE);
KUNIT_EXPECT_TRUE(test, !p);
@@ -1960,7 +2497,7 @@ static void tb_test_property_format(struct kunit *test)
KUNIT_ASSERT_TRUE(test, dir != NULL);
ret = tb_property_format_dir(dir, NULL, 0);
- KUNIT_ASSERT_EQ(test, ret, (int)ARRAY_SIZE(root_directory));
+ KUNIT_ASSERT_EQ(test, ret, ARRAY_SIZE(root_directory));
block_len = ret;
@@ -2063,7 +2600,7 @@ static void tb_test_property_copy(struct kunit *test)
/* Compare the resulting property block */
ret = tb_property_format_dir(dst, NULL, 0);
- KUNIT_ASSERT_EQ(test, ret, (int)ARRAY_SIZE(root_directory));
+ KUNIT_ASSERT_EQ(test, ret, ARRAY_SIZE(root_directory));
block = kunit_kzalloc(test, sizeof(root_directory), GFP_KERNEL);
KUNIT_ASSERT_TRUE(test, block != NULL);
@@ -2105,6 +2642,14 @@ static struct kunit_case tb_test_cases[] = {
KUNIT_CASE(tb_test_tunnel_dma_tx),
KUNIT_CASE(tb_test_tunnel_dma_chain),
KUNIT_CASE(tb_test_tunnel_dma_match),
+ KUNIT_CASE(tb_test_credit_alloc_legacy_not_bonded),
+ KUNIT_CASE(tb_test_credit_alloc_legacy_bonded),
+ KUNIT_CASE(tb_test_credit_alloc_pcie),
+ KUNIT_CASE(tb_test_credit_alloc_dp),
+ KUNIT_CASE(tb_test_credit_alloc_usb3),
+ KUNIT_CASE(tb_test_credit_alloc_dma),
+ KUNIT_CASE(tb_test_credit_alloc_dma_multiple),
+ KUNIT_CASE(tb_test_credit_alloc_all),
KUNIT_CASE(tb_test_property_parse),
KUNIT_CASE(tb_test_property_format),
KUNIT_CASE(tb_test_property_copy),
diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c
index e1979bed7146..bb5cc480fc9a 100644
--- a/drivers/thunderbolt/tunnel.c
+++ b/drivers/thunderbolt/tunnel.c
@@ -34,6 +34,16 @@
#define TB_DP_AUX_PATH_OUT 1
#define TB_DP_AUX_PATH_IN 2
+/* Minimum number of credits needed for PCIe path */
+#define TB_MIN_PCIE_CREDITS 6U
+/*
+ * Number of credits we try to allocate for each DMA path if not limited
+ * by the host router baMaxHI.
+ */
+#define TB_DMA_CREDITS 14U
+/* Minimum number of credits for DMA path */
+#define TB_MIN_DMA_CREDITS 1U
+
static const char * const tb_tunnel_names[] = { "PCI", "DP", "DMA", "USB3" };
#define __TB_TUNNEL_PRINT(level, tunnel, fmt, arg...) \
@@ -57,6 +67,55 @@ static const char * const tb_tunnel_names[] = { "PCI", "DP", "DMA", "USB3" };
#define tb_tunnel_dbg(tunnel, fmt, arg...) \
__TB_TUNNEL_PRINT(tb_dbg, tunnel, fmt, ##arg)
+static inline unsigned int tb_usable_credits(const struct tb_port *port)
+{
+ return port->total_credits - port->ctl_credits;
+}
+
+/**
+ * tb_available_credits() - Available credits for PCIe and DMA
+ * @port: Lane adapter to check
+ * @max_dp_streams: If non-%NULL stores maximum number of simultaneous DP
+ * streams possible through this lane adapter
+ */
+static unsigned int tb_available_credits(const struct tb_port *port,
+ size_t *max_dp_streams)
+{
+ const struct tb_switch *sw = port->sw;
+ int credits, usb3, pcie, spare;
+ size_t ndp;
+
+ usb3 = tb_acpi_may_tunnel_usb3() ? sw->max_usb3_credits : 0;
+ pcie = tb_acpi_may_tunnel_pcie() ? sw->max_pcie_credits : 0;
+
+ if (tb_acpi_is_xdomain_allowed()) {
+ spare = min_not_zero(sw->max_dma_credits, TB_DMA_CREDITS);
+ /* Add some credits for potential second DMA tunnel */
+ spare += TB_MIN_DMA_CREDITS;
+ } else {
+ spare = 0;
+ }
+
+ credits = tb_usable_credits(port);
+ if (tb_acpi_may_tunnel_dp()) {
+ /*
+ * Maximum number of DP streams possible through the
+ * lane adapter.
+ */
+ ndp = (credits - (usb3 + pcie + spare)) /
+ (sw->min_dp_aux_credits + sw->min_dp_main_credits);
+ } else {
+ ndp = 0;
+ }
+ credits -= ndp * (sw->min_dp_aux_credits + sw->min_dp_main_credits);
+ credits -= usb3;
+
+ if (max_dp_streams)
+ *max_dp_streams = ndp;
+
+ return credits > 0 ? credits : 0;
+}
+
static struct tb_tunnel *tb_tunnel_alloc(struct tb *tb, size_t npaths,
enum tb_tunnel_type type)
{
@@ -94,24 +153,37 @@ static int tb_pci_activate(struct tb_tunnel *tunnel, bool activate)
return 0;
}
-static int tb_initial_credits(const struct tb_switch *sw)
+static int tb_pci_init_credits(struct tb_path_hop *hop)
{
- /* If the path is complete sw is not NULL */
- if (sw) {
- /* More credits for faster link */
- switch (sw->link_speed * sw->link_width) {
- case 40:
- return 32;
- case 20:
- return 24;
- }
+ struct tb_port *port = hop->in_port;
+ struct tb_switch *sw = port->sw;
+ unsigned int credits;
+
+ if (tb_port_use_credit_allocation(port)) {
+ unsigned int available;
+
+ available = tb_available_credits(port, NULL);
+ credits = min(sw->max_pcie_credits, available);
+
+ if (credits < TB_MIN_PCIE_CREDITS)
+ return -ENOSPC;
+
+ credits = max(TB_MIN_PCIE_CREDITS, credits);
+ } else {
+ if (tb_port_is_null(port))
+ credits = port->bonded ? 32 : 16;
+ else
+ credits = 7;
}
- return 16;
+ hop->initial_credits = credits;
+ return 0;
}
-static void tb_pci_init_path(struct tb_path *path)
+static int tb_pci_init_path(struct tb_path *path)
{
+ struct tb_path_hop *hop;
+
path->egress_fc_enable = TB_PATH_SOURCE | TB_PATH_INTERNAL;
path->egress_shared_buffer = TB_PATH_NONE;
path->ingress_fc_enable = TB_PATH_ALL;
@@ -119,11 +191,16 @@ static void tb_pci_init_path(struct tb_path *path)
path->priority = 3;
path->weight = 1;
path->drop_packages = 0;
- path->nfc_credits = 0;
- path->hops[0].initial_credits = 7;
- if (path->path_length > 1)
- path->hops[1].initial_credits =
- tb_initial_credits(path->hops[1].in_port->sw);
+
+ tb_path_for_each_hop(path, hop) {
+ int ret;
+
+ ret = tb_pci_init_credits(hop);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
/**
@@ -163,14 +240,16 @@ struct tb_tunnel *tb_tunnel_discover_pci(struct tb *tb, struct tb_port *down)
goto err_free;
}
tunnel->paths[TB_PCI_PATH_UP] = path;
- tb_pci_init_path(tunnel->paths[TB_PCI_PATH_UP]);
+ if (tb_pci_init_path(tunnel->paths[TB_PCI_PATH_UP]))
+ goto err_free;
path = tb_path_discover(tunnel->dst_port, -1, down, TB_PCI_HOPID, NULL,
"PCIe Down");
if (!path)
goto err_deactivate;
tunnel->paths[TB_PCI_PATH_DOWN] = path;
- tb_pci_init_path(tunnel->paths[TB_PCI_PATH_DOWN]);
+ if (tb_pci_init_path(tunnel->paths[TB_PCI_PATH_DOWN]))
+ goto err_deactivate;
/* Validate that the tunnel is complete */
if (!tb_port_is_pcie_up(tunnel->dst_port)) {
@@ -228,23 +307,25 @@ struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up,
path = tb_path_alloc(tb, down, TB_PCI_HOPID, up, TB_PCI_HOPID, 0,
"PCIe Down");
- if (!path) {
- tb_tunnel_free(tunnel);
- return NULL;
- }
- tb_pci_init_path(path);
+ if (!path)
+ goto err_free;
tunnel->paths[TB_PCI_PATH_DOWN] = path;
+ if (tb_pci_init_path(path))
+ goto err_free;
path = tb_path_alloc(tb, up, TB_PCI_HOPID, down, TB_PCI_HOPID, 0,
"PCIe Up");
- if (!path) {
- tb_tunnel_free(tunnel);
- return NULL;
- }
- tb_pci_init_path(path);
+ if (!path)
+ goto err_free;
tunnel->paths[TB_PCI_PATH_UP] = path;
+ if (tb_pci_init_path(path))
+ goto err_free;
return tunnel;
+
+err_free:
+ tb_tunnel_free(tunnel);
+ return NULL;
}
static bool tb_dp_is_usb4(const struct tb_switch *sw)
@@ -599,9 +680,20 @@ static int tb_dp_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up,
return 0;
}
+static void tb_dp_init_aux_credits(struct tb_path_hop *hop)
+{
+ struct tb_port *port = hop->in_port;
+ struct tb_switch *sw = port->sw;
+
+ if (tb_port_use_credit_allocation(port))
+ hop->initial_credits = sw->min_dp_aux_credits;
+ else
+ hop->initial_credits = 1;
+}
+
static void tb_dp_init_aux_path(struct tb_path *path)
{
- int i;
+ struct tb_path_hop *hop;
path->egress_fc_enable = TB_PATH_SOURCE | TB_PATH_INTERNAL;
path->egress_shared_buffer = TB_PATH_NONE;
@@ -610,13 +702,42 @@ static void tb_dp_init_aux_path(struct tb_path *path)
path->priority = 2;
path->weight = 1;
- for (i = 0; i < path->path_length; i++)
- path->hops[i].initial_credits = 1;
+ tb_path_for_each_hop(path, hop)
+ tb_dp_init_aux_credits(hop);
}
-static void tb_dp_init_video_path(struct tb_path *path, bool discover)
+static int tb_dp_init_video_credits(struct tb_path_hop *hop)
{
- u32 nfc_credits = path->hops[0].in_port->config.nfc_credits;
+ struct tb_port *port = hop->in_port;
+ struct tb_switch *sw = port->sw;
+
+ if (tb_port_use_credit_allocation(port)) {
+ unsigned int nfc_credits;
+ size_t max_dp_streams;
+
+ tb_available_credits(port, &max_dp_streams);
+ /*
+ * Read the number of currently allocated NFC credits
+ * from the lane adapter. Since we only use them for DP
+ * tunneling we can use that to figure out how many DP
+ * tunnels already go through the lane adapter.
+ */
+ nfc_credits = port->config.nfc_credits &
+ ADP_CS_4_NFC_BUFFERS_MASK;
+ if (nfc_credits / sw->min_dp_main_credits > max_dp_streams)
+ return -ENOSPC;
+
+ hop->nfc_credits = sw->min_dp_main_credits;
+ } else {
+ hop->nfc_credits = min(port->total_credits - 2, 12U);
+ }
+
+ return 0;
+}
+
+static int tb_dp_init_video_path(struct tb_path *path)
+{
+ struct tb_path_hop *hop;
path->egress_fc_enable = TB_PATH_NONE;
path->egress_shared_buffer = TB_PATH_NONE;
@@ -625,16 +746,15 @@ static void tb_dp_init_video_path(struct tb_path *path, bool discover)
path->priority = 1;
path->weight = 1;
- if (discover) {
- path->nfc_credits = nfc_credits & ADP_CS_4_NFC_BUFFERS_MASK;
- } else {
- u32 max_credits;
+ tb_path_for_each_hop(path, hop) {
+ int ret;
- max_credits = (nfc_credits & ADP_CS_4_TOTAL_BUFFERS_MASK) >>
- ADP_CS_4_TOTAL_BUFFERS_SHIFT;
- /* Leave some credits for AUX path */
- path->nfc_credits = min(max_credits - 2, 12U);
+ ret = tb_dp_init_video_credits(hop);
+ if (ret)
+ return ret;
}
+
+ return 0;
}
/**
@@ -674,7 +794,8 @@ struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in)
goto err_free;
}
tunnel->paths[TB_DP_VIDEO_PATH_OUT] = path;
- tb_dp_init_video_path(tunnel->paths[TB_DP_VIDEO_PATH_OUT], true);
+ if (tb_dp_init_video_path(tunnel->paths[TB_DP_VIDEO_PATH_OUT]))
+ goto err_free;
path = tb_path_discover(in, TB_DP_AUX_TX_HOPID, NULL, -1, NULL, "AUX TX");
if (!path)
@@ -761,7 +882,7 @@ struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in,
1, "Video");
if (!path)
goto err_free;
- tb_dp_init_video_path(path, false);
+ tb_dp_init_video_path(path);
paths[TB_DP_VIDEO_PATH_OUT] = path;
path = tb_path_alloc(tb, in, TB_DP_AUX_TX_HOPID, out,
@@ -785,20 +906,92 @@ err_free:
return NULL;
}
-static u32 tb_dma_credits(struct tb_port *nhi)
+static unsigned int tb_dma_available_credits(const struct tb_port *port)
{
- u32 max_credits;
+ const struct tb_switch *sw = port->sw;
+ int credits;
- max_credits = (nhi->config.nfc_credits & ADP_CS_4_TOTAL_BUFFERS_MASK) >>
- ADP_CS_4_TOTAL_BUFFERS_SHIFT;
- return min(max_credits, 13U);
+ credits = tb_available_credits(port, NULL);
+ if (tb_acpi_may_tunnel_pcie())
+ credits -= sw->max_pcie_credits;
+ credits -= port->dma_credits;
+
+ return credits > 0 ? credits : 0;
}
-static void tb_dma_init_path(struct tb_path *path, unsigned int efc, u32 credits)
+static int tb_dma_reserve_credits(struct tb_path_hop *hop, unsigned int credits)
{
- int i;
+ struct tb_port *port = hop->in_port;
- path->egress_fc_enable = efc;
+ if (tb_port_use_credit_allocation(port)) {
+ unsigned int available = tb_dma_available_credits(port);
+
+ /*
+ * Need to have at least TB_MIN_DMA_CREDITS, otherwise
+ * DMA path cannot be established.
+ */
+ if (available < TB_MIN_DMA_CREDITS)
+ return -ENOSPC;
+
+ while (credits > available)
+ credits--;
+
+ tb_port_dbg(port, "reserving %u credits for DMA path\n",
+ credits);
+
+ port->dma_credits += credits;
+ } else {
+ if (tb_port_is_null(port))
+ credits = port->bonded ? 14 : 6;
+ else
+ credits = min(port->total_credits, credits);
+ }
+
+ hop->initial_credits = credits;
+ return 0;
+}
+
+/* Path from lane adapter to NHI */
+static int tb_dma_init_rx_path(struct tb_path *path, unsigned int credits)
+{
+ struct tb_path_hop *hop;
+ unsigned int i, tmp;
+
+ path->egress_fc_enable = TB_PATH_SOURCE | TB_PATH_INTERNAL;
+ path->ingress_fc_enable = TB_PATH_ALL;
+ path->egress_shared_buffer = TB_PATH_NONE;
+ path->ingress_shared_buffer = TB_PATH_NONE;
+ path->priority = 5;
+ path->weight = 1;
+ path->clear_fc = true;
+
+ /*
+ * First lane adapter is the one connected to the remote host.
+ * We don't tunnel other traffic over this link so can use all
+ * the credits (except the ones reserved for control traffic).
+ */
+ hop = &path->hops[0];
+ tmp = min(tb_usable_credits(hop->in_port), credits);
+ hop->initial_credits = tmp;
+ hop->in_port->dma_credits += tmp;
+
+ for (i = 1; i < path->path_length; i++) {
+ int ret;
+
+ ret = tb_dma_reserve_credits(&path->hops[i], credits);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Path from NHI to lane adapter */
+static int tb_dma_init_tx_path(struct tb_path *path, unsigned int credits)
+{
+ struct tb_path_hop *hop;
+
+ path->egress_fc_enable = TB_PATH_ALL;
path->ingress_fc_enable = TB_PATH_ALL;
path->egress_shared_buffer = TB_PATH_NONE;
path->ingress_shared_buffer = TB_PATH_NONE;
@@ -806,8 +999,46 @@ static void tb_dma_init_path(struct tb_path *path, unsigned int efc, u32 credits
path->weight = 1;
path->clear_fc = true;
- for (i = 0; i < path->path_length; i++)
- path->hops[i].initial_credits = credits;
+ tb_path_for_each_hop(path, hop) {
+ int ret;
+
+ ret = tb_dma_reserve_credits(hop, credits);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void tb_dma_release_credits(struct tb_path_hop *hop)
+{
+ struct tb_port *port = hop->in_port;
+
+ if (tb_port_use_credit_allocation(port)) {
+ port->dma_credits -= hop->initial_credits;
+
+ tb_port_dbg(port, "released %u DMA path credits\n",
+ hop->initial_credits);
+ }
+}
+
+static void tb_dma_deinit_path(struct tb_path *path)
+{
+ struct tb_path_hop *hop;
+
+ tb_path_for_each_hop(path, hop)
+ tb_dma_release_credits(hop);
+}
+
+static void tb_dma_deinit(struct tb_tunnel *tunnel)
+{
+ int i;
+
+ for (i = 0; i < tunnel->npaths; i++) {
+ if (!tunnel->paths[i])
+ continue;
+ tb_dma_deinit_path(tunnel->paths[i]);
+ }
}
/**
@@ -832,7 +1063,7 @@ struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi,
struct tb_tunnel *tunnel;
size_t npaths = 0, i = 0;
struct tb_path *path;
- u32 credits;
+ int credits;
if (receive_ring > 0)
npaths++;
@@ -848,32 +1079,39 @@ struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi,
tunnel->src_port = nhi;
tunnel->dst_port = dst;
+ tunnel->deinit = tb_dma_deinit;
- credits = tb_dma_credits(nhi);
+ credits = min_not_zero(TB_DMA_CREDITS, nhi->sw->max_dma_credits);
if (receive_ring > 0) {
path = tb_path_alloc(tb, dst, receive_path, nhi, receive_ring, 0,
"DMA RX");
- if (!path) {
- tb_tunnel_free(tunnel);
- return NULL;
- }
- tb_dma_init_path(path, TB_PATH_SOURCE | TB_PATH_INTERNAL, credits);
+ if (!path)
+ goto err_free;
tunnel->paths[i++] = path;
+ if (tb_dma_init_rx_path(path, credits)) {
+ tb_tunnel_dbg(tunnel, "not enough buffers for RX path\n");
+ goto err_free;
+ }
}
if (transmit_ring > 0) {
path = tb_path_alloc(tb, nhi, transmit_ring, dst, transmit_path, 0,
"DMA TX");
- if (!path) {
- tb_tunnel_free(tunnel);
- return NULL;
- }
- tb_dma_init_path(path, TB_PATH_ALL, credits);
+ if (!path)
+ goto err_free;
tunnel->paths[i++] = path;
+ if (tb_dma_init_tx_path(path, credits)) {
+ tb_tunnel_dbg(tunnel, "not enough buffers for TX path\n");
+ goto err_free;
+ }
}
return tunnel;
+
+err_free:
+ tb_tunnel_free(tunnel);
+ return NULL;
}
/**
@@ -1067,8 +1305,28 @@ static void tb_usb3_reclaim_available_bandwidth(struct tb_tunnel *tunnel,
tunnel->allocated_up, tunnel->allocated_down);
}
+static void tb_usb3_init_credits(struct tb_path_hop *hop)
+{
+ struct tb_port *port = hop->in_port;
+ struct tb_switch *sw = port->sw;
+ unsigned int credits;
+
+ if (tb_port_use_credit_allocation(port)) {
+ credits = sw->max_usb3_credits;
+ } else {
+ if (tb_port_is_null(port))
+ credits = port->bonded ? 32 : 16;
+ else
+ credits = 7;
+ }
+
+ hop->initial_credits = credits;
+}
+
static void tb_usb3_init_path(struct tb_path *path)
{
+ struct tb_path_hop *hop;
+
path->egress_fc_enable = TB_PATH_SOURCE | TB_PATH_INTERNAL;
path->egress_shared_buffer = TB_PATH_NONE;
path->ingress_fc_enable = TB_PATH_ALL;
@@ -1076,11 +1334,9 @@ static void tb_usb3_init_path(struct tb_path *path)
path->priority = 3;
path->weight = 3;
path->drop_packages = 0;
- path->nfc_credits = 0;
- path->hops[0].initial_credits = 7;
- if (path->path_length > 1)
- path->hops[1].initial_credits =
- tb_initial_credits(path->hops[1].in_port->sw);
+
+ tb_path_for_each_hop(path, hop)
+ tb_usb3_init_credits(hop);
}
/**
@@ -1280,6 +1536,9 @@ void tb_tunnel_free(struct tb_tunnel *tunnel)
if (!tunnel)
return;
+ if (tunnel->deinit)
+ tunnel->deinit(tunnel);
+
for (i = 0; i < tunnel->npaths; i++) {
if (tunnel->paths[i])
tb_path_free(tunnel->paths[i]);
diff --git a/drivers/thunderbolt/tunnel.h b/drivers/thunderbolt/tunnel.h
index a66994fb4e60..eea14e24f7e0 100644
--- a/drivers/thunderbolt/tunnel.h
+++ b/drivers/thunderbolt/tunnel.h
@@ -27,6 +27,7 @@ enum tb_tunnel_type {
* @paths: All paths required by the tunnel
* @npaths: Number of paths in @paths
* @init: Optional tunnel specific initialization
+ * @deinit: Optional tunnel specific de-initialization
* @activate: Optional tunnel specific activation/deactivation
* @consumed_bandwidth: Return how much bandwidth the tunnel consumes
* @release_unused_bandwidth: Release all unused bandwidth
@@ -47,6 +48,7 @@ struct tb_tunnel {
struct tb_path **paths;
size_t npaths;
int (*init)(struct tb_tunnel *tunnel);
+ void (*deinit)(struct tb_tunnel *tunnel);
int (*activate)(struct tb_tunnel *tunnel, bool activate);
int (*consumed_bandwidth)(struct tb_tunnel *tunnel, int *consumed_up,
int *consumed_down);
diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c
index 671d72af8ba1..ceddbe7e9f93 100644
--- a/drivers/thunderbolt/usb4.c
+++ b/drivers/thunderbolt/usb4.c
@@ -13,7 +13,6 @@
#include "sb_regs.h"
#include "tb.h"
-#define USB4_DATA_DWORDS 16
#define USB4_DATA_RETRIES 3
enum usb4_sb_target {
@@ -37,8 +36,19 @@ enum usb4_sb_target {
#define USB4_NVM_SECTOR_SIZE_MASK GENMASK(23, 0)
-typedef int (*read_block_fn)(void *, unsigned int, void *, size_t);
-typedef int (*write_block_fn)(void *, const void *, size_t);
+#define USB4_BA_LENGTH_MASK GENMASK(7, 0)
+#define USB4_BA_INDEX_MASK GENMASK(15, 0)
+
+enum usb4_ba_index {
+ USB4_BA_MAX_USB3 = 0x1,
+ USB4_BA_MIN_DP_AUX = 0x2,
+ USB4_BA_MIN_DP_MAIN = 0x3,
+ USB4_BA_MAX_PCIE = 0x4,
+ USB4_BA_MAX_HI = 0x5,
+};
+
+#define USB4_BA_VALUE_MASK GENMASK(31, 16)
+#define USB4_BA_VALUE_SHIFT 16
static int usb4_switch_wait_for_bit(struct tb_switch *sw, u32 offset, u32 bit,
u32 value, int timeout_msec)
@@ -62,76 +72,6 @@ static int usb4_switch_wait_for_bit(struct tb_switch *sw, u32 offset, u32 bit,
return -ETIMEDOUT;
}
-static int usb4_do_read_data(u16 address, void *buf, size_t size,
- read_block_fn read_block, void *read_block_data)
-{
- unsigned int retries = USB4_DATA_RETRIES;
- unsigned int offset;
-
- do {
- unsigned int dwaddress, dwords;
- u8 data[USB4_DATA_DWORDS * 4];
- size_t nbytes;
- int ret;
-
- offset = address & 3;
- nbytes = min_t(size_t, size + offset, USB4_DATA_DWORDS * 4);
-
- dwaddress = address / 4;
- dwords = ALIGN(nbytes, 4) / 4;
-
- ret = read_block(read_block_data, dwaddress, data, dwords);
- if (ret) {
- if (ret != -ENODEV && retries--)
- continue;
- return ret;
- }
-
- nbytes -= offset;
- memcpy(buf, data + offset, nbytes);
-
- size -= nbytes;
- address += nbytes;
- buf += nbytes;
- } while (size > 0);
-
- return 0;
-}
-
-static int usb4_do_write_data(unsigned int address, const void *buf, size_t size,
- write_block_fn write_next_block, void *write_block_data)
-{
- unsigned int retries = USB4_DATA_RETRIES;
- unsigned int offset;
-
- offset = address & 3;
- address = address & ~3;
-
- do {
- u32 nbytes = min_t(u32, size, USB4_DATA_DWORDS * 4);
- u8 data[USB4_DATA_DWORDS * 4];
- int ret;
-
- memcpy(data + offset, buf, nbytes);
-
- ret = write_next_block(write_block_data, data, nbytes / 4);
- if (ret) {
- if (ret == -ETIMEDOUT) {
- if (retries--)
- continue;
- ret = -EIO;
- }
- return ret;
- }
-
- size -= nbytes;
- address += nbytes;
- buf += nbytes;
- } while (size > 0);
-
- return 0;
-}
-
static int usb4_native_switch_op(struct tb_switch *sw, u16 opcode,
u32 *metadata, u8 *status,
const void *tx_data, size_t tx_dwords,
@@ -193,7 +133,7 @@ static int __usb4_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata,
{
const struct tb_cm_ops *cm_ops = sw->tb->cm_ops;
- if (tx_dwords > USB4_DATA_DWORDS || rx_dwords > USB4_DATA_DWORDS)
+ if (tx_dwords > NVM_DATA_DWORDS || rx_dwords > NVM_DATA_DWORDS)
return -EINVAL;
/*
@@ -320,7 +260,7 @@ int usb4_switch_setup(struct tb_switch *sw)
parent = tb_switch_parent(sw);
downstream_port = tb_port_at(tb_route(sw), parent);
sw->link_usb4 = link_is_usb4(downstream_port);
- tb_sw_dbg(sw, "link: %s\n", sw->link_usb4 ? "USB4" : "TBT3");
+ tb_sw_dbg(sw, "link: %s\n", sw->link_usb4 ? "USB4" : "TBT");
xhci = val & ROUTER_CS_6_HCI;
tbt3 = !(val & ROUTER_CS_6_TNS);
@@ -414,8 +354,8 @@ static int usb4_switch_drom_read_block(void *data,
int usb4_switch_drom_read(struct tb_switch *sw, unsigned int address, void *buf,
size_t size)
{
- return usb4_do_read_data(address, buf, size,
- usb4_switch_drom_read_block, sw);
+ return tb_nvm_read_data(address, buf, size, USB4_DATA_RETRIES,
+ usb4_switch_drom_read_block, sw);
}
/**
@@ -473,12 +413,18 @@ int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags)
val &= ~(PORT_CS_19_WOC | PORT_CS_19_WOD | PORT_CS_19_WOU4);
- if (flags & TB_WAKE_ON_CONNECT)
- val |= PORT_CS_19_WOC;
- if (flags & TB_WAKE_ON_DISCONNECT)
- val |= PORT_CS_19_WOD;
- if (flags & TB_WAKE_ON_USB4)
+ if (tb_is_upstream_port(port)) {
val |= PORT_CS_19_WOU4;
+ } else {
+ bool configured = val & PORT_CS_19_PC;
+
+ if ((flags & TB_WAKE_ON_CONNECT) && !configured)
+ val |= PORT_CS_19_WOC;
+ if ((flags & TB_WAKE_ON_DISCONNECT) && configured)
+ val |= PORT_CS_19_WOD;
+ if ((flags & TB_WAKE_ON_USB4) && configured)
+ val |= PORT_CS_19_WOU4;
+ }
ret = tb_port_write(port, &val, TB_CFG_PORT,
port->cap_usb4 + PORT_CS_19, 1);
@@ -487,7 +433,7 @@ int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags)
}
/*
- * Enable wakes from PCIe and USB 3.x on this router. Only
+ * Enable wakes from PCIe, USB 3.x and DP on this router. Only
* needed for device routers.
*/
if (route) {
@@ -495,11 +441,13 @@ int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags)
if (ret)
return ret;
- val &= ~(ROUTER_CS_5_WOP | ROUTER_CS_5_WOU);
+ val &= ~(ROUTER_CS_5_WOP | ROUTER_CS_5_WOU | ROUTER_CS_5_WOD);
if (flags & TB_WAKE_ON_USB3)
val |= ROUTER_CS_5_WOU;
if (flags & TB_WAKE_ON_PCIE)
val |= ROUTER_CS_5_WOP;
+ if (flags & TB_WAKE_ON_DP)
+ val |= ROUTER_CS_5_WOD;
ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, ROUTER_CS_5, 1);
if (ret)
@@ -595,12 +543,21 @@ static int usb4_switch_nvm_read_block(void *data,
int usb4_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf,
size_t size)
{
- return usb4_do_read_data(address, buf, size,
- usb4_switch_nvm_read_block, sw);
+ return tb_nvm_read_data(address, buf, size, USB4_DATA_RETRIES,
+ usb4_switch_nvm_read_block, sw);
}
-static int usb4_switch_nvm_set_offset(struct tb_switch *sw,
- unsigned int address)
+/**
+ * usb4_switch_nvm_set_offset() - Set NVM write offset
+ * @sw: USB4 router
+ * @address: Start offset
+ *
+ * Explicitly sets NVM write offset. Normally when writing to NVM this
+ * is done automatically by usb4_switch_nvm_write().
+ *
+ * Returns %0 in success and negative errno if there was a failure.
+ */
+int usb4_switch_nvm_set_offset(struct tb_switch *sw, unsigned int address)
{
u32 metadata, dwaddress;
u8 status = 0;
@@ -618,8 +575,8 @@ static int usb4_switch_nvm_set_offset(struct tb_switch *sw,
return status ? -EIO : 0;
}
-static int usb4_switch_nvm_write_next_block(void *data, const void *buf,
- size_t dwords)
+static int usb4_switch_nvm_write_next_block(void *data, unsigned int dwaddress,
+ const void *buf, size_t dwords)
{
struct tb_switch *sw = data;
u8 status;
@@ -652,8 +609,8 @@ int usb4_switch_nvm_write(struct tb_switch *sw, unsigned int address,
if (ret)
return ret;
- return usb4_do_write_data(address, buf, size,
- usb4_switch_nvm_write_next_block, sw);
+ return tb_nvm_write_data(address, buf, size, USB4_DATA_RETRIES,
+ usb4_switch_nvm_write_next_block, sw);
}
/**
@@ -736,6 +693,147 @@ int usb4_switch_nvm_authenticate_status(struct tb_switch *sw, u32 *status)
}
/**
+ * usb4_switch_credits_init() - Read buffer allocation parameters
+ * @sw: USB4 router
+ *
+ * Reads @sw buffer allocation parameters and initializes @sw buffer
+ * allocation fields accordingly. Specifically @sw->credits_allocation
+ * is set to %true if these parameters can be used in tunneling.
+ *
+ * Returns %0 on success and negative errno otherwise.
+ */
+int usb4_switch_credits_init(struct tb_switch *sw)
+{
+ int max_usb3, min_dp_aux, min_dp_main, max_pcie, max_dma;
+ int ret, length, i, nports;
+ const struct tb_port *port;
+ u32 data[NVM_DATA_DWORDS];
+ u32 metadata = 0;
+ u8 status = 0;
+
+ memset(data, 0, sizeof(data));
+ ret = usb4_switch_op_data(sw, USB4_SWITCH_OP_BUFFER_ALLOC, &metadata,
+ &status, NULL, 0, data, ARRAY_SIZE(data));
+ if (ret)
+ return ret;
+ if (status)
+ return -EIO;
+
+ length = metadata & USB4_BA_LENGTH_MASK;
+ if (WARN_ON(length > ARRAY_SIZE(data)))
+ return -EMSGSIZE;
+
+ max_usb3 = -1;
+ min_dp_aux = -1;
+ min_dp_main = -1;
+ max_pcie = -1;
+ max_dma = -1;
+
+ tb_sw_dbg(sw, "credit allocation parameters:\n");
+
+ for (i = 0; i < length; i++) {
+ u16 index, value;
+
+ index = data[i] & USB4_BA_INDEX_MASK;
+ value = (data[i] & USB4_BA_VALUE_MASK) >> USB4_BA_VALUE_SHIFT;
+
+ switch (index) {
+ case USB4_BA_MAX_USB3:
+ tb_sw_dbg(sw, " USB3: %u\n", value);
+ max_usb3 = value;
+ break;
+ case USB4_BA_MIN_DP_AUX:
+ tb_sw_dbg(sw, " DP AUX: %u\n", value);
+ min_dp_aux = value;
+ break;
+ case USB4_BA_MIN_DP_MAIN:
+ tb_sw_dbg(sw, " DP main: %u\n", value);
+ min_dp_main = value;
+ break;
+ case USB4_BA_MAX_PCIE:
+ tb_sw_dbg(sw, " PCIe: %u\n", value);
+ max_pcie = value;
+ break;
+ case USB4_BA_MAX_HI:
+ tb_sw_dbg(sw, " DMA: %u\n", value);
+ max_dma = value;
+ break;
+ default:
+ tb_sw_dbg(sw, " unknown credit allocation index %#x, skipping\n",
+ index);
+ break;
+ }
+ }
+
+ /*
+ * Validate the buffer allocation preferences. If we find
+ * issues, log a warning and fall back using the hard-coded
+ * values.
+ */
+
+ /* Host router must report baMaxHI */
+ if (!tb_route(sw) && max_dma < 0) {
+ tb_sw_warn(sw, "host router is missing baMaxHI\n");
+ goto err_invalid;
+ }
+
+ nports = 0;
+ tb_switch_for_each_port(sw, port) {
+ if (tb_port_is_null(port))
+ nports++;
+ }
+
+ /* Must have DP buffer allocation (multiple USB4 ports) */
+ if (nports > 2 && (min_dp_aux < 0 || min_dp_main < 0)) {
+ tb_sw_warn(sw, "multiple USB4 ports require baMinDPaux/baMinDPmain\n");
+ goto err_invalid;
+ }
+
+ tb_switch_for_each_port(sw, port) {
+ if (tb_port_is_dpout(port) && min_dp_main < 0) {
+ tb_sw_warn(sw, "missing baMinDPmain");
+ goto err_invalid;
+ }
+ if ((tb_port_is_dpin(port) || tb_port_is_dpout(port)) &&
+ min_dp_aux < 0) {
+ tb_sw_warn(sw, "missing baMinDPaux");
+ goto err_invalid;
+ }
+ if ((tb_port_is_usb3_down(port) || tb_port_is_usb3_up(port)) &&
+ max_usb3 < 0) {
+ tb_sw_warn(sw, "missing baMaxUSB3");
+ goto err_invalid;
+ }
+ if ((tb_port_is_pcie_down(port) || tb_port_is_pcie_up(port)) &&
+ max_pcie < 0) {
+ tb_sw_warn(sw, "missing baMaxPCIe");
+ goto err_invalid;
+ }
+ }
+
+ /*
+ * Buffer allocation passed the validation so we can use it in
+ * path creation.
+ */
+ sw->credit_allocation = true;
+ if (max_usb3 > 0)
+ sw->max_usb3_credits = max_usb3;
+ if (min_dp_aux > 0)
+ sw->min_dp_aux_credits = min_dp_aux;
+ if (min_dp_main > 0)
+ sw->min_dp_main_credits = min_dp_main;
+ if (max_pcie > 0)
+ sw->max_pcie_credits = max_pcie;
+ if (max_dma > 0)
+ sw->max_dma_credits = max_dma;
+
+ return 0;
+
+err_invalid:
+ return -EINVAL;
+}
+
+/**
* usb4_switch_query_dp_resource() - Query availability of DP IN resource
* @sw: USB4 router
* @in: DP IN adapter
@@ -897,6 +995,60 @@ struct tb_port *usb4_switch_map_usb3_down(struct tb_switch *sw,
}
/**
+ * usb4_switch_add_ports() - Add USB4 ports for this router
+ * @sw: USB4 router
+ *
+ * For USB4 router finds all USB4 ports and registers devices for each.
+ * Can be called to any router.
+ *
+ * Return %0 in case of success and negative errno in case of failure.
+ */
+int usb4_switch_add_ports(struct tb_switch *sw)
+{
+ struct tb_port *port;
+
+ if (tb_switch_is_icm(sw) || !tb_switch_is_usb4(sw))
+ return 0;
+
+ tb_switch_for_each_port(sw, port) {
+ struct usb4_port *usb4;
+
+ if (!tb_port_is_null(port))
+ continue;
+ if (!port->cap_usb4)
+ continue;
+
+ usb4 = usb4_port_device_add(port);
+ if (IS_ERR(usb4)) {
+ usb4_switch_remove_ports(sw);
+ return PTR_ERR(usb4);
+ }
+
+ port->usb4 = usb4;
+ }
+
+ return 0;
+}
+
+/**
+ * usb4_switch_remove_ports() - Removes USB4 ports from this router
+ * @sw: USB4 router
+ *
+ * Unregisters previously registered USB4 ports.
+ */
+void usb4_switch_remove_ports(struct tb_switch *sw)
+{
+ struct tb_port *port;
+
+ tb_switch_for_each_port(sw, port) {
+ if (port->usb4) {
+ usb4_port_device_remove(port->usb4);
+ port->usb4 = NULL;
+ }
+ }
+}
+
+/**
* usb4_port_unlock() - Unlock USB4 downstream port
* @port: USB4 port to unlock
*
@@ -1029,7 +1181,7 @@ static int usb4_port_wait_for_bit(struct tb_port *port, u32 offset, u32 bit,
static int usb4_port_read_data(struct tb_port *port, void *data, size_t dwords)
{
- if (dwords > USB4_DATA_DWORDS)
+ if (dwords > NVM_DATA_DWORDS)
return -EINVAL;
return tb_port_read(port, data, TB_CFG_PORT, port->cap_usb4 + PORT_CS_2,
@@ -1039,7 +1191,7 @@ static int usb4_port_read_data(struct tb_port *port, void *data, size_t dwords)
static int usb4_port_write_data(struct tb_port *port, const void *data,
size_t dwords)
{
- if (dwords > USB4_DATA_DWORDS)
+ if (dwords > NVM_DATA_DWORDS)
return -EINVAL;
return tb_port_write(port, data, TB_CFG_PORT, port->cap_usb4 + PORT_CS_2,
@@ -1175,6 +1327,48 @@ static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target,
return -ETIMEDOUT;
}
+static int usb4_port_set_router_offline(struct tb_port *port, bool offline)
+{
+ u32 val = !offline;
+ int ret;
+
+ ret = usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0,
+ USB4_SB_METADATA, &val, sizeof(val));
+ if (ret)
+ return ret;
+
+ val = USB4_SB_OPCODE_ROUTER_OFFLINE;
+ return usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0,
+ USB4_SB_OPCODE, &val, sizeof(val));
+}
+
+/**
+ * usb4_port_router_offline() - Put the USB4 port to offline mode
+ * @port: USB4 port
+ *
+ * This function puts the USB4 port into offline mode. In this mode the
+ * port does not react on hotplug events anymore. This needs to be
+ * called before retimer access is done when the USB4 links is not up.
+ *
+ * Returns %0 in case of success and negative errno if there was an
+ * error.
+ */
+int usb4_port_router_offline(struct tb_port *port)
+{
+ return usb4_port_set_router_offline(port, true);
+}
+
+/**
+ * usb4_port_router_online() - Put the USB4 port back to online
+ * @port: USB4 port
+ *
+ * Makes the USB4 port functional again.
+ */
+int usb4_port_router_online(struct tb_port *port)
+{
+ return usb4_port_set_router_offline(port, false);
+}
+
/**
* usb4_port_enumerate_retimers() - Send RT broadcast transaction
* @port: USB4 port
@@ -1201,6 +1395,33 @@ static inline int usb4_port_retimer_op(struct tb_port *port, u8 index,
}
/**
+ * usb4_port_retimer_set_inbound_sbtx() - Enable sideband channel transactions
+ * @port: USB4 port
+ * @index: Retimer index
+ *
+ * Enables sideband channel transations on SBTX. Can be used when USB4
+ * link does not go up, for example if there is no device connected.
+ */
+int usb4_port_retimer_set_inbound_sbtx(struct tb_port *port, u8 index)
+{
+ int ret;
+
+ ret = usb4_port_retimer_op(port, index, USB4_SB_OPCODE_SET_INBOUND_SBTX,
+ 500);
+
+ if (ret != -ENODEV)
+ return ret;
+
+ /*
+ * Per the USB4 retimer spec, the retimer is not required to
+ * send an RT (Retimer Transaction) response for the first
+ * SET_INBOUND_SBTX command
+ */
+ return usb4_port_retimer_op(port, index, USB4_SB_OPCODE_SET_INBOUND_SBTX,
+ 500);
+}
+
+/**
* usb4_port_retimer_read() - Read from retimer sideband registers
* @port: USB4 port
* @index: Retimer index
@@ -1292,8 +1513,19 @@ int usb4_port_retimer_nvm_sector_size(struct tb_port *port, u8 index)
return ret ? ret : metadata & USB4_NVM_SECTOR_SIZE_MASK;
}
-static int usb4_port_retimer_nvm_set_offset(struct tb_port *port, u8 index,
- unsigned int address)
+/**
+ * usb4_port_retimer_nvm_set_offset() - Set NVM write offset
+ * @port: USB4 port
+ * @index: Retimer index
+ * @address: Start offset
+ *
+ * Exlicitly sets NVM write offset. Normally when writing to NVM this is
+ * done automatically by usb4_port_retimer_nvm_write().
+ *
+ * Returns %0 in success and negative errno if there was a failure.
+ */
+int usb4_port_retimer_nvm_set_offset(struct tb_port *port, u8 index,
+ unsigned int address)
{
u32 metadata, dwaddress;
int ret;
@@ -1316,8 +1548,8 @@ struct retimer_info {
u8 index;
};
-static int usb4_port_retimer_nvm_write_next_block(void *data, const void *buf,
- size_t dwords)
+static int usb4_port_retimer_nvm_write_next_block(void *data,
+ unsigned int dwaddress, const void *buf, size_t dwords)
{
const struct retimer_info *info = data;
@@ -1357,8 +1589,8 @@ int usb4_port_retimer_nvm_write(struct tb_port *port, u8 index, unsigned int add
if (ret)
return ret;
- return usb4_do_write_data(address, buf, size,
- usb4_port_retimer_nvm_write_next_block, &info);
+ return tb_nvm_write_data(address, buf, size, USB4_DATA_RETRIES,
+ usb4_port_retimer_nvm_write_next_block, &info);
}
/**
@@ -1442,7 +1674,7 @@ static int usb4_port_retimer_nvm_read_block(void *data, unsigned int dwaddress,
int ret;
metadata = dwaddress << USB4_NVM_READ_OFFSET_SHIFT;
- if (dwords < USB4_DATA_DWORDS)
+ if (dwords < NVM_DATA_DWORDS)
metadata |= dwords << USB4_NVM_READ_LENGTH_SHIFT;
ret = usb4_port_retimer_write(port, index, USB4_SB_METADATA, &metadata,
@@ -1475,8 +1707,8 @@ int usb4_port_retimer_nvm_read(struct tb_port *port, u8 index,
{
struct retimer_info info = { .port = port, .index = index };
- return usb4_do_read_data(address, buf, size,
- usb4_port_retimer_nvm_read_block, &info);
+ return tb_nvm_read_data(address, buf, size, USB4_DATA_RETRIES,
+ usb4_port_retimer_nvm_read_block, &info);
}
/**
diff --git a/drivers/thunderbolt/usb4_port.c b/drivers/thunderbolt/usb4_port.c
new file mode 100644
index 000000000000..29e2a4f9c9f5
--- /dev/null
+++ b/drivers/thunderbolt/usb4_port.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * USB4 port device
+ *
+ * Copyright (C) 2021, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+ */
+
+#include <linux/pm_runtime.h>
+
+#include "tb.h"
+
+static ssize_t link_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
+ struct tb_port *port = usb4->port;
+ struct tb *tb = port->sw->tb;
+ const char *link;
+
+ if (mutex_lock_interruptible(&tb->lock))
+ return -ERESTARTSYS;
+
+ if (tb_is_upstream_port(port))
+ link = port->sw->link_usb4 ? "usb4" : "tbt";
+ else if (tb_port_has_remote(port))
+ link = port->remote->sw->link_usb4 ? "usb4" : "tbt";
+ else
+ link = "none";
+
+ mutex_unlock(&tb->lock);
+
+ return sysfs_emit(buf, "%s\n", link);
+}
+static DEVICE_ATTR_RO(link);
+
+static struct attribute *common_attrs[] = {
+ &dev_attr_link.attr,
+ NULL
+};
+
+static const struct attribute_group common_group = {
+ .attrs = common_attrs,
+};
+
+static int usb4_port_offline(struct usb4_port *usb4)
+{
+ struct tb_port *port = usb4->port;
+ int ret;
+
+ ret = tb_acpi_power_on_retimers(port);
+ if (ret)
+ return ret;
+
+ ret = usb4_port_router_offline(port);
+ if (ret) {
+ tb_acpi_power_off_retimers(port);
+ return ret;
+ }
+
+ ret = tb_retimer_scan(port, false);
+ if (ret) {
+ usb4_port_router_online(port);
+ tb_acpi_power_off_retimers(port);
+ }
+
+ return ret;
+}
+
+static void usb4_port_online(struct usb4_port *usb4)
+{
+ struct tb_port *port = usb4->port;
+
+ usb4_port_router_online(port);
+ tb_acpi_power_off_retimers(port);
+}
+
+static ssize_t offline_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
+
+ return sysfs_emit(buf, "%d\n", usb4->offline);
+}
+
+static ssize_t offline_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
+ struct tb_port *port = usb4->port;
+ struct tb *tb = port->sw->tb;
+ bool val;
+ int ret;
+
+ ret = kstrtobool(buf, &val);
+ if (ret)
+ return ret;
+
+ pm_runtime_get_sync(&usb4->dev);
+
+ if (mutex_lock_interruptible(&tb->lock)) {
+ ret = -ERESTARTSYS;
+ goto out_rpm;
+ }
+
+ if (val == usb4->offline)
+ goto out_unlock;
+
+ /* Offline mode works only for ports that are not connected */
+ if (tb_port_has_remote(port)) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+
+ if (val) {
+ ret = usb4_port_offline(usb4);
+ if (ret)
+ goto out_unlock;
+ } else {
+ usb4_port_online(usb4);
+ tb_retimer_remove_all(port);
+ }
+
+ usb4->offline = val;
+ tb_port_dbg(port, "%s offline mode\n", val ? "enter" : "exit");
+
+out_unlock:
+ mutex_unlock(&tb->lock);
+out_rpm:
+ pm_runtime_mark_last_busy(&usb4->dev);
+ pm_runtime_put_autosuspend(&usb4->dev);
+
+ return ret ? ret : count;
+}
+static DEVICE_ATTR_RW(offline);
+
+static ssize_t rescan_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
+ struct tb_port *port = usb4->port;
+ struct tb *tb = port->sw->tb;
+ bool val;
+ int ret;
+
+ ret = kstrtobool(buf, &val);
+ if (ret)
+ return ret;
+
+ if (!val)
+ return count;
+
+ pm_runtime_get_sync(&usb4->dev);
+
+ if (mutex_lock_interruptible(&tb->lock)) {
+ ret = -ERESTARTSYS;
+ goto out_rpm;
+ }
+
+ /* Must be in offline mode already */
+ if (!usb4->offline) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ tb_retimer_remove_all(port);
+ ret = tb_retimer_scan(port, true);
+
+out_unlock:
+ mutex_unlock(&tb->lock);
+out_rpm:
+ pm_runtime_mark_last_busy(&usb4->dev);
+ pm_runtime_put_autosuspend(&usb4->dev);
+
+ return ret ? ret : count;
+}
+static DEVICE_ATTR_WO(rescan);
+
+static struct attribute *service_attrs[] = {
+ &dev_attr_offline.attr,
+ &dev_attr_rescan.attr,
+ NULL
+};
+
+static umode_t service_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
+
+ /*
+ * Always need some platform help to cycle the modes so that
+ * retimers can be accessed through the sideband.
+ */
+ return usb4->can_offline ? attr->mode : 0;
+}
+
+static const struct attribute_group service_group = {
+ .attrs = service_attrs,
+ .is_visible = service_attr_is_visible,
+};
+
+static const struct attribute_group *usb4_port_device_groups[] = {
+ &common_group,
+ &service_group,
+ NULL
+};
+
+static void usb4_port_device_release(struct device *dev)
+{
+ struct usb4_port *usb4 = container_of(dev, struct usb4_port, dev);
+
+ kfree(usb4);
+}
+
+struct device_type usb4_port_device_type = {
+ .name = "usb4_port",
+ .groups = usb4_port_device_groups,
+ .release = usb4_port_device_release,
+};
+
+/**
+ * usb4_port_device_add() - Add USB4 port device
+ * @port: Lane 0 adapter port to add the USB4 port
+ *
+ * Creates and registers a USB4 port device for @port. Returns the new
+ * USB4 port device pointer or ERR_PTR() in case of error.
+ */
+struct usb4_port *usb4_port_device_add(struct tb_port *port)
+{
+ struct usb4_port *usb4;
+ int ret;
+
+ usb4 = kzalloc(sizeof(*usb4), GFP_KERNEL);
+ if (!usb4)
+ return ERR_PTR(-ENOMEM);
+
+ usb4->port = port;
+ usb4->dev.type = &usb4_port_device_type;
+ usb4->dev.parent = &port->sw->dev;
+ dev_set_name(&usb4->dev, "usb4_port%d", port->port);
+
+ ret = device_register(&usb4->dev);
+ if (ret) {
+ put_device(&usb4->dev);
+ return ERR_PTR(ret);
+ }
+
+ pm_runtime_no_callbacks(&usb4->dev);
+ pm_runtime_set_active(&usb4->dev);
+ pm_runtime_enable(&usb4->dev);
+ pm_runtime_set_autosuspend_delay(&usb4->dev, TB_AUTOSUSPEND_DELAY);
+ pm_runtime_mark_last_busy(&usb4->dev);
+ pm_runtime_use_autosuspend(&usb4->dev);
+
+ return usb4;
+}
+
+/**
+ * usb4_port_device_remove() - Removes USB4 port device
+ * @usb4: USB4 port device
+ *
+ * Unregisters the USB4 port device from the system. The device will be
+ * released when the last reference is dropped.
+ */
+void usb4_port_device_remove(struct usb4_port *usb4)
+{
+ device_unregister(&usb4->dev);
+}
+
+/**
+ * usb4_port_device_resume() - Resumes USB4 port device
+ * @usb4: USB4 port device
+ *
+ * Used to resume USB4 port device after sleep state.
+ */
+int usb4_port_device_resume(struct usb4_port *usb4)
+{
+ return usb4->offline ? usb4_port_offline(usb4) : 0;
+}
diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c
index b21d99d59412..d66ea4d616fd 100644
--- a/drivers/thunderbolt/xdomain.c
+++ b/drivers/thunderbolt/xdomain.c
@@ -1527,6 +1527,13 @@ int tb_xdomain_lane_bonding_enable(struct tb_xdomain *xd)
return ret;
}
+ ret = tb_port_wait_for_link_width(port, 2, 100);
+ if (ret) {
+ tb_port_warn(port, "timeout enabling lane bonding\n");
+ return ret;
+ }
+
+ tb_port_update_credits(port);
tb_xdomain_update_link_attributes(xd);
dev_dbg(&xd->dev, "lane bonding enabled\n");
@@ -1548,7 +1555,10 @@ void tb_xdomain_lane_bonding_disable(struct tb_xdomain *xd)
port = tb_port_at(xd->route, tb_xdomain_parent(xd));
if (port->dual_link_port) {
tb_port_lane_bonding_disable(port);
+ if (tb_port_wait_for_link_width(port, 1, 100) == -ETIMEDOUT)
+ tb_port_warn(port, "timeout disabling lane bonding\n");
tb_port_disable(port->dual_link_port);
+ tb_port_update_credits(port);
tb_xdomain_update_link_attributes(xd);
dev_dbg(&xd->dev, "lane bonding disabled\n");
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index f6a7fd6d3bb6..23cc988c68a4 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -12,9 +12,8 @@ if TTY
config VT
bool "Virtual terminal" if EXPERT
- depends on !UML
select INPUT
- default y
+ default y if !UML
help
If you say Y here, you will get support for terminal devices with
display and keyboard devices. These are called "virtual" because you
@@ -78,7 +77,7 @@ config VT_CONSOLE_SLEEP
config HW_CONSOLE
bool
- depends on VT && !UML
+ depends on VT
default y
config VT_HW_CONSOLE_BINDING
@@ -204,7 +203,7 @@ config MOXA_INTELLIO
config MOXA_SMARTIO
tristate "Moxa SmartIO support v. 2.0"
- depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA)
+ depends on SERIAL_NONSTANDARD && PCI
help
Say Y here if you have a Moxa SmartIO multiport serial card and/or
want to help develop a new version of this driver.
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index c7054f5117c3..a2bd75fbaaa4 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_AUDIT) += tty_audit.o
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_N_GSM) += n_gsm.o
-obj-$(CONFIG_R3964) += n_r3964.o
obj-y += vt/
obj-$(CONFIG_HVC_DRIVER) += hvc/
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index ca48ce5a0862..5ec19c48fb7a 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -148,7 +148,7 @@ static __inline__ void rtsdtr_ctrl(int bits)
* ------------------------------------------------------------
* rs_stop() and rs_start()
*
- * This routines are called before setting or resetting tty->stopped.
+ * This routines are called before setting or resetting tty->flow.stopped.
* They enable or disable transmitter interrupts, as necessary.
* ------------------------------------------------------------
*/
@@ -309,7 +309,7 @@ static void transmit_chars(struct serial_state *info)
return;
}
if (info->xmit.head == info->xmit.tail
- || info->tport.tty->stopped
+ || info->tport.tty->flow.stopped
|| info->tport.tty->hw_stopped) {
info->IER &= ~UART_IER_THRI;
custom.intena = IF_TBE;
@@ -768,7 +768,7 @@ static void rs_flush_chars(struct tty_struct *tty)
unsigned long flags;
if (info->xmit.head == info->xmit.tail
- || tty->stopped
+ || tty->flow.stopped
|| tty->hw_stopped
|| !info->xmit.buf)
return;
@@ -812,7 +812,7 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
local_irq_restore(flags);
if (info->xmit.head != info->xmit.tail
- && !tty->stopped
+ && !tty->flow.stopped
&& !tty->hw_stopped
&& !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
@@ -827,14 +827,14 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
return ret;
}
-static int rs_write_room(struct tty_struct *tty)
+static unsigned int rs_write_room(struct tty_struct *tty)
{
struct serial_state *info = tty->driver_data;
return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
}
-static int rs_chars_in_buffer(struct tty_struct *tty)
+static unsigned int rs_chars_in_buffer(struct tty_struct *tty)
{
struct serial_state *info = tty->driver_data;
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 3c6dd06ec5fb..445e5ff9b36d 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -536,11 +536,11 @@ static void ehv_bc_tty_close(struct tty_struct *ttys, struct file *filp)
* how much write room the driver can guarantee will be sent OR BUFFERED. This
* driver MUST honor the return value.
*/
-static int ehv_bc_tty_write_room(struct tty_struct *ttys)
+static unsigned int ehv_bc_tty_write_room(struct tty_struct *ttys)
{
struct ehv_bc_data *bc = ttys->driver_data;
unsigned long flags;
- int count;
+ unsigned int count;
spin_lock_irqsave(&bc->lock, flags);
count = CIRC_SPACE(bc->head, bc->tail, BUF_SIZE);
diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c
index cd23a4b05c8f..ccb683a6e6f5 100644
--- a/drivers/tty/goldfish.c
+++ b/drivers/tty/goldfish.c
@@ -193,12 +193,12 @@ static int goldfish_tty_write(struct tty_struct *tty, const unsigned char *buf,
return count;
}
-static int goldfish_tty_write_room(struct tty_struct *tty)
+static unsigned int goldfish_tty_write_room(struct tty_struct *tty)
{
return 0x10000;
}
-static int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
{
struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
void __iomem *base = qtty->base;
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index cdcc64ea2554..5bb8c4e44961 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -292,7 +292,7 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
if (vtermnos[index] != -1)
return -1;
- /* make sure no no tty has been registered in this index */
+ /* make sure no tty has been registered in this index */
hp = hvc_get_by_index(index);
if (hp) {
tty_port_put(&hp->port);
@@ -586,7 +586,7 @@ static void hvc_set_winsz(struct work_struct *work)
* how much write room the driver can guarantee will be sent OR BUFFERED. This
* driver MUST honor the return value.
*/
-static int hvc_write_room(struct tty_struct *tty)
+static unsigned int hvc_write_room(struct tty_struct *tty)
{
struct hvc_struct *hp = tty->driver_data;
@@ -596,7 +596,7 @@ static int hvc_write_room(struct tty_struct *tty)
return hp->outbuf_size - hp->n_outbuf;
}
-static int hvc_chars_in_buffer(struct tty_struct *tty)
+static unsigned int hvc_chars_in_buffer(struct tty_struct *tty)
{
struct hvc_struct *hp = tty->driver_data;
@@ -620,7 +620,7 @@ static u32 timeout = MIN_TIMEOUT;
/*
* Maximum number of bytes to get from the console driver if hvc_poll is
* called from driver (and can't sleep). Any more than this and we break
- * and start polling with khvcd. This value was derived from from an OpenBMC
+ * and start polling with khvcd. This value was derived from an OpenBMC
* console with the OPAL driver that results in about 0.25ms interrupts off
* latency.
*/
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
index 2af1e5751bd6..82a76cac94de 100644
--- a/drivers/tty/hvc/hvc_iucv.c
+++ b/drivers/tty/hvc/hvc_iucv.c
@@ -438,8 +438,6 @@ static void hvc_iucv_sndbuf_work(struct work_struct *work)
struct hvc_iucv_private *priv;
priv = container_of(work, struct hvc_iucv_private, sndbuf_work.work);
- if (!priv)
- return;
spin_lock_bh(&priv->lock);
hvc_iucv_send(priv);
@@ -966,37 +964,6 @@ static void hvc_iucv_msg_complete(struct iucv_path *path,
destroy_tty_buffer_list(&list_remove);
}
-/**
- * hvc_iucv_pm_freeze() - Freeze PM callback
- * @dev: IUVC HVC terminal device
- *
- * Sever an established IUCV communication path and
- * trigger a hang-up of the underlying HVC terminal.
- */
-static int hvc_iucv_pm_freeze(struct device *dev)
-{
- struct hvc_iucv_private *priv = dev_get_drvdata(dev);
-
- local_bh_disable();
- hvc_iucv_hangup(priv);
- local_bh_enable();
-
- return 0;
-}
-
-/**
- * hvc_iucv_pm_restore_thaw() - Thaw and restore PM callback
- * @dev: IUVC HVC terminal device
- *
- * Wake up the HVC thread to trigger hang-up and respective
- * HVC back-end notifier invocations.
- */
-static int hvc_iucv_pm_restore_thaw(struct device *dev)
-{
- hvc_kick();
- return 0;
-}
-
static ssize_t hvc_iucv_dev_termid_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1051,20 +1018,6 @@ static const struct hv_ops hvc_iucv_ops = {
.dtr_rts = hvc_iucv_dtr_rts,
};
-/* Suspend / resume device operations */
-static const struct dev_pm_ops hvc_iucv_pm_ops = {
- .freeze = hvc_iucv_pm_freeze,
- .thaw = hvc_iucv_pm_restore_thaw,
- .restore = hvc_iucv_pm_restore_thaw,
-};
-
-/* IUCV HVC device driver */
-static struct device_driver hvc_iucv_driver = {
- .name = KMSG_COMPONENT,
- .bus = &iucv_bus,
- .pm = &hvc_iucv_pm_ops,
-};
-
/* IUCV HVC device attributes */
static DEVICE_ATTR(termid, 0640, hvc_iucv_dev_termid_show, NULL);
static DEVICE_ATTR(state, 0640, hvc_iucv_dev_state_show, NULL);
@@ -1144,7 +1097,6 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
dev_set_drvdata(priv->dev, priv);
priv->dev->bus = &iucv_bus;
priv->dev->parent = iucv_root;
- priv->dev->driver = &hvc_iucv_driver;
priv->dev->groups = hvc_iucv_dev_attr_groups;
priv->dev->release = (void (*)(struct device *)) kfree;
rc = device_register(priv->dev);
@@ -1376,11 +1328,6 @@ static int __init hvc_iucv_init(void)
goto out_error;
}
- /* register IUCV HVC device driver */
- rc = driver_register(&hvc_iucv_driver);
- if (rc)
- goto out_error;
-
/* parse hvc_iucv_allow string and create z/VM user ID filter list */
if (hvc_iucv_filter_string) {
rc = hvc_iucv_setup_filter(hvc_iucv_filter_string);
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c
index 798f27f40cc2..72b11aa7e0a6 100644
--- a/drivers/tty/hvc/hvc_vio.c
+++ b/drivers/tty/hvc/hvc_vio.c
@@ -249,7 +249,7 @@ static void udbg_hvc_putc(char c)
count = hvterm_hvsi_put_chars(0, &c, 1);
break;
}
- } while(count == 0);
+ } while (count == 0 || count == -EAGAIN);
}
static int udbg_hvc_getc_poll(void)
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index 197988c55e0c..fe5e6b4f43de 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -1376,7 +1376,7 @@ static int hvcs_write(struct tty_struct *tty,
* absolutely WILL BUFFER if we can't send it. This driver MUST honor the
* return value, hence the reason for hvcs_struct buffering.
*/
-static int hvcs_write_room(struct tty_struct *tty)
+static unsigned int hvcs_write_room(struct tty_struct *tty)
{
struct hvcs_struct *hvcsd = tty->driver_data;
@@ -1386,7 +1386,7 @@ static int hvcs_write_room(struct tty_struct *tty)
return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
}
-static int hvcs_chars_in_buffer(struct tty_struct *tty)
+static unsigned int hvcs_chars_in_buffer(struct tty_struct *tty)
{
struct hvcs_struct *hvcsd = tty->driver_data;
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
index e8c58f9bd263..bfc15279d5bc 100644
--- a/drivers/tty/hvc/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
@@ -890,14 +890,14 @@ out:
spin_unlock_irqrestore(&hp->lock, flags);
}
-static int hvsi_write_room(struct tty_struct *tty)
+static unsigned int hvsi_write_room(struct tty_struct *tty)
{
struct hvsi_struct *hp = tty->driver_data;
return N_OUTBUF - hp->n_outbuf;
}
-static int hvsi_chars_in_buffer(struct tty_struct *tty)
+static unsigned int hvsi_chars_in_buffer(struct tty_struct *tty)
{
struct hvsi_struct *hp = tty->driver_data;
@@ -929,7 +929,7 @@ static int hvsi_write(struct tty_struct *tty,
* will see there is no room in outbuf and return.
*/
while ((count > 0) && (hvsi_write_room(tty) > 0)) {
- int chunksize = min(count, hvsi_write_room(tty));
+ int chunksize = min_t(int, count, hvsi_write_room(tty));
BUG_ON(hp->n_outbuf < 0);
memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
index 99bb2f149ff5..e3a5a5ba752c 100644
--- a/drivers/tty/ipwireless/tty.c
+++ b/drivers/tty/ipwireless/tty.c
@@ -54,7 +54,6 @@ struct ipw_tty {
unsigned int control_lines;
struct mutex ipw_tty_mutex;
int tx_bytes_queued;
- int closing;
};
static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS];
@@ -228,7 +227,7 @@ static int ipw_write(struct tty_struct *linux_tty,
return count;
}
-static int ipw_write_room(struct tty_struct *linux_tty)
+static unsigned int ipw_write_room(struct tty_struct *linux_tty)
{
struct ipw_tty *tty = linux_tty->driver_data;
int room;
@@ -270,7 +269,7 @@ static int ipwireless_set_serial_info(struct tty_struct *linux_tty,
return 0; /* Keeps the PCMCIA scripts happy. */
}
-static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
+static unsigned int ipw_chars_in_buffer(struct tty_struct *linux_tty)
{
struct ipw_tty *tty = linux_tty->driver_data;
@@ -525,7 +524,6 @@ void ipwireless_tty_free(struct ipw_tty *tty)
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": deregistering %s device ttyIPWp%d\n",
tty_type_name(ttyj->tty_type), j);
- ttyj->closing = 1;
if (ttyj->port.tty != NULL) {
mutex_unlock(&ttyj->ipw_tty_mutex);
tty_vhangup(ttyj->port.tty);
diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c
index a8e19b4833bf..3b5915b94fac 100644
--- a/drivers/tty/mips_ejtag_fdc.c
+++ b/drivers/tty/mips_ejtag_fdc.c
@@ -840,11 +840,11 @@ static int mips_ejtag_fdc_tty_write(struct tty_struct *tty,
return total;
}
-static int mips_ejtag_fdc_tty_write_room(struct tty_struct *tty)
+static unsigned int mips_ejtag_fdc_tty_write_room(struct tty_struct *tty)
{
struct mips_ejtag_fdc_tty_port *dport = tty->driver_data;
struct mips_ejtag_fdc_tty *priv = dport->driver;
- int room;
+ unsigned int room;
/* Report the space in the xmit buffer */
spin_lock(&dport->xmit_lock);
@@ -854,10 +854,10 @@ static int mips_ejtag_fdc_tty_write_room(struct tty_struct *tty)
return room;
}
-static int mips_ejtag_fdc_tty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int mips_ejtag_fdc_tty_chars_in_buffer(struct tty_struct *tty)
{
struct mips_ejtag_fdc_tty_port *dport = tty->driver_data;
- int chars;
+ unsigned int chars;
/* Report the number of bytes in the xmit buffer */
spin_lock(&dport->xmit_lock);
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 4d4f15b5cd29..64b18177c790 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -188,9 +188,9 @@ module_param(ttymajor, int, 0);
static int moxa_open(struct tty_struct *, struct file *);
static void moxa_close(struct tty_struct *, struct file *);
static int moxa_write(struct tty_struct *, const unsigned char *, int);
-static int moxa_write_room(struct tty_struct *);
+static unsigned int moxa_write_room(struct tty_struct *);
static void moxa_flush_buffer(struct tty_struct *);
-static int moxa_chars_in_buffer(struct tty_struct *);
+static unsigned int moxa_chars_in_buffer(struct tty_struct *);
static void moxa_set_termios(struct tty_struct *, struct ktermios *);
static void moxa_stop(struct tty_struct *);
static void moxa_start(struct tty_struct *);
@@ -216,9 +216,9 @@ static int MoxaPortLineStatus(struct moxa_port *);
static void MoxaPortFlushData(struct moxa_port *, int);
static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
static int MoxaPortReadData(struct moxa_port *);
-static int MoxaPortTxQueue(struct moxa_port *);
+static unsigned int MoxaPortTxQueue(struct moxa_port *);
static int MoxaPortRxQueue(struct moxa_port *);
-static int MoxaPortTxFree(struct moxa_port *);
+static unsigned int MoxaPortTxFree(struct moxa_port *);
static void MoxaPortTxDisable(struct moxa_port *);
static void MoxaPortTxEnable(struct moxa_port *);
static int moxa_get_serial_info(struct tty_struct *, struct serial_struct *);
@@ -1217,11 +1217,11 @@ static int moxa_write(struct tty_struct *tty,
return len;
}
-static int moxa_write_room(struct tty_struct *tty)
+static unsigned int moxa_write_room(struct tty_struct *tty)
{
struct moxa_port *ch;
- if (tty->stopped)
+ if (tty->flow.stopped)
return 0;
ch = tty->driver_data;
if (ch == NULL)
@@ -1239,10 +1239,10 @@ static void moxa_flush_buffer(struct tty_struct *tty)
tty_wakeup(tty);
}
-static int moxa_chars_in_buffer(struct tty_struct *tty)
+static unsigned int moxa_chars_in_buffer(struct tty_struct *tty)
{
struct moxa_port *ch = tty->driver_data;
- int chars;
+ unsigned int chars;
chars = MoxaPortTxQueue(ch);
if (chars)
@@ -1374,7 +1374,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
clear_bit(EMPTYWAIT, &p->statusflags);
tty_wakeup(tty);
}
- if (test_bit(LOWWAIT, &p->statusflags) && !tty->stopped &&
+ if (test_bit(LOWWAIT, &p->statusflags) && !tty->flow.stopped &&
MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
clear_bit(LOWWAIT, &p->statusflags);
tty_wakeup(tty);
@@ -1981,7 +1981,7 @@ static int MoxaPortReadData(struct moxa_port *port)
}
-static int MoxaPortTxQueue(struct moxa_port *port)
+static unsigned int MoxaPortTxQueue(struct moxa_port *port)
{
void __iomem *ofsAddr = port->tableAddr;
u16 rptr, wptr, mask;
@@ -1992,7 +1992,7 @@ static int MoxaPortTxQueue(struct moxa_port *port)
return (wptr - rptr) & mask;
}
-static int MoxaPortTxFree(struct moxa_port *port)
+static unsigned int MoxaPortTxFree(struct moxa_port *port)
{
void __iomem *ofsAddr = port->tableAddr;
u16 rptr, wptr, mask;
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 16a852ecbe8a..900ccb2ca166 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -41,9 +41,112 @@
#include <asm/irq.h>
#include <linux/uaccess.h>
-#include "mxser.h"
+/*
+ * Semi-public control interfaces
+ */
+
+/*
+ * MOXA ioctls
+ */
+
+#define MOXA 0x400
+#define MOXA_SET_OP_MODE (MOXA + 66)
+#define MOXA_GET_OP_MODE (MOXA + 67)
+
+#define RS232_MODE 0
+#define RS485_2WIRE_MODE 1
+#define RS422_MODE 2
+#define RS485_4WIRE_MODE 3
+#define OP_MODE_MASK 3
+
+/* --------------------------------------------------- */
+
+/*
+ * Follow just what Moxa Must chip defines.
+ *
+ * When LCR register (offset 0x03) is written the following value, the Must chip
+ * will enter enhanced mode. And a write to EFR (offset 0x02) bit 6,7 will
+ * change bank.
+ */
+#define MOXA_MUST_ENTER_ENHANCED 0xBF
+
+/* when enhanced mode is enabled, access to general bank register */
+#define MOXA_MUST_GDL_REGISTER 0x07
+#define MOXA_MUST_GDL_MASK 0x7F
+#define MOXA_MUST_GDL_HAS_BAD_DATA 0x80
+
+#define MOXA_MUST_LSR_RERR 0x80 /* error in receive FIFO */
+/* enhanced register bank select and enhanced mode setting register */
+/* This works only when LCR register equals to 0xBF */
+#define MOXA_MUST_EFR_REGISTER 0x02
+#define MOXA_MUST_EFR_EFRB_ENABLE 0x10 /* enhanced mode enable */
+/* enhanced register bank set 0, 1, 2 */
+#define MOXA_MUST_EFR_BANK0 0x00
+#define MOXA_MUST_EFR_BANK1 0x40
+#define MOXA_MUST_EFR_BANK2 0x80
+#define MOXA_MUST_EFR_BANK3 0xC0
+#define MOXA_MUST_EFR_BANK_MASK 0xC0
+
+/* set XON1 value register, when LCR=0xBF and change to bank0 */
+#define MOXA_MUST_XON1_REGISTER 0x04
+
+/* set XON2 value register, when LCR=0xBF and change to bank0 */
+#define MOXA_MUST_XON2_REGISTER 0x05
+
+/* set XOFF1 value register, when LCR=0xBF and change to bank0 */
+#define MOXA_MUST_XOFF1_REGISTER 0x06
+
+/* set XOFF2 value register, when LCR=0xBF and change to bank0 */
+#define MOXA_MUST_XOFF2_REGISTER 0x07
+
+#define MOXA_MUST_RBRTL_REGISTER 0x04
+#define MOXA_MUST_RBRTH_REGISTER 0x05
+#define MOXA_MUST_RBRTI_REGISTER 0x06
+#define MOXA_MUST_THRTL_REGISTER 0x07
+#define MOXA_MUST_ENUM_REGISTER 0x04
+#define MOXA_MUST_HWID_REGISTER 0x05
+#define MOXA_MUST_ECR_REGISTER 0x06
+#define MOXA_MUST_CSR_REGISTER 0x07
+
+#define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20 /* good data mode enable */
+#define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10 /* only good data put into RxFIFO */
+
+#define MOXA_MUST_IER_ECTSI 0x80 /* enable CTS interrupt */
+#define MOXA_MUST_IER_ERTSI 0x40 /* enable RTS interrupt */
+#define MOXA_MUST_IER_XINT 0x20 /* enable Xon/Xoff interrupt */
+#define MOXA_MUST_IER_EGDAI 0x10 /* enable GDA interrupt */
+
+#define MOXA_MUST_RECV_ISR (UART_IER_RDI | MOXA_MUST_IER_EGDAI)
+
+/* GDA interrupt pending */
+#define MOXA_MUST_IIR_GDA 0x1C
+#define MOXA_MUST_IIR_RDA 0x04
+#define MOXA_MUST_IIR_RTO 0x0C
+#define MOXA_MUST_IIR_LSR 0x06
+
+/* received Xon/Xoff or specical interrupt pending */
+#define MOXA_MUST_IIR_XSC 0x10
+
+/* RTS/CTS change state interrupt pending */
+#define MOXA_MUST_IIR_RTSCTS 0x20
+#define MOXA_MUST_IIR_MASK 0x3E
+
+#define MOXA_MUST_MCR_XON_FLAG 0x40
+#define MOXA_MUST_MCR_XON_ANY 0x80
+#define MOXA_MUST_MCR_TX_XON 0x08
+
+#define MOXA_MUST_EFR_SF_MASK 0x0F /* software flow control on chip mask value */
+#define MOXA_MUST_EFR_SF_TX1 0x08 /* send Xon1/Xoff1 */
+#define MOXA_MUST_EFR_SF_TX2 0x04 /* send Xon2/Xoff2 */
+#define MOXA_MUST_EFR_SF_TX12 0x0C /* send Xon1,Xon2/Xoff1,Xoff2 */
+#define MOXA_MUST_EFR_SF_TX_NO 0x00 /* don't send Xon/Xoff */
+#define MOXA_MUST_EFR_SF_TX_MASK 0x0C /* Tx software flow control mask */
+#define MOXA_MUST_EFR_SF_RX_NO 0x00 /* don't receive Xon/Xoff */
+#define MOXA_MUST_EFR_SF_RX1 0x02 /* receive Xon1/Xoff1 */
+#define MOXA_MUST_EFR_SF_RX2 0x01 /* receive Xon2/Xoff2 */
+#define MOXA_MUST_EFR_SF_RX12 0x03 /* receive Xon1,Xon2/Xoff1,Xoff2 */
+#define MOXA_MUST_EFR_SF_RX_MASK 0x03 /* Rx software flow control mask */
-#define MXSER_VERSION "2.0.5" /* 1.14 */
#define MXSERMAJOR 174
#define MXSER_BOARDS 4 /* Max. boards */
@@ -51,15 +154,10 @@
#define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD)
#define MXSER_ISR_PASS_LIMIT 100
-/*CheckIsMoxaMust return value*/
-#define MOXA_OTHER_UART 0x00
-#define MOXA_MUST_MU150_HWID 0x01
-#define MOXA_MUST_MU860_HWID 0x02
-
#define WAKEUP_CHARS 256
-#define UART_MCR_AFE 0x20
-#define UART_LSR_SPECIAL 0x1E
+#define MXSER_BAUD_BASE 921600
+#define MXSER_CUSTOM_DIVISOR (MXSER_BAUD_BASE * 16)
#define PCI_DEVICE_ID_POS104UL 0x1044
#define PCI_DEVICE_ID_CB108 0x1080
@@ -70,151 +168,71 @@
#define PCI_DEVICE_ID_CB134I 0x1341
#define PCI_DEVICE_ID_CP138U 0x1380
+#define MXSER_NPORTS(ddata) ((ddata) & 0xffU)
+#define MXSER_HIGHBAUD 0x0100
-#define C168_ASIC_ID 1
-#define C104_ASIC_ID 2
-#define C102_ASIC_ID 0xB
-#define CI132_ASIC_ID 4
-#define CI134_ASIC_ID 3
-#define CI104J_ASIC_ID 5
-
-#define MXSER_HIGHBAUD 1
-#define MXSER_HAS2 2
+enum mxser_must_hwid {
+ MOXA_OTHER_UART = 0x00,
+ MOXA_MUST_MU150_HWID = 0x01,
+ MOXA_MUST_MU860_HWID = 0x02,
+};
-/* This is only for PCI */
static const struct {
- int type;
- int tx_fifo;
- int rx_fifo;
- int xmit_fifo_size;
- int rx_high_water;
- int rx_trigger;
- int rx_low_water;
- long max_baud;
+ u8 type;
+ u8 fifo_size;
+ u8 rx_high_water;
+ u8 rx_low_water;
+ speed_t max_baud;
} Gpci_uart_info[] = {
- {MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L},
- {MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L},
- {MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L}
+ { MOXA_OTHER_UART, 16, 14, 1, 921600 },
+ { MOXA_MUST_MU150_HWID, 64, 48, 16, 230400 },
+ { MOXA_MUST_MU860_HWID, 128, 96, 32, 921600 }
};
#define UART_INFO_NUM ARRAY_SIZE(Gpci_uart_info)
-struct mxser_cardinfo {
- char *name;
- unsigned int nports;
- unsigned int flags;
-};
-
-static const struct mxser_cardinfo mxser_cards[] = {
-/* 0*/ { "C168 series", 8, },
- { "C104 series", 4, },
- { "CI-104J series", 4, },
- { "C168H/PCI series", 8, },
- { "C104H/PCI series", 4, },
-/* 5*/ { "C102 series", 4, MXSER_HAS2 }, /* C102-ISA */
- { "CI-132 series", 4, MXSER_HAS2 },
- { "CI-134 series", 4, },
- { "CP-132 series", 2, },
- { "CP-114 series", 4, },
-/*10*/ { "CT-114 series", 4, },
- { "CP-102 series", 2, MXSER_HIGHBAUD },
- { "CP-104U series", 4, },
- { "CP-168U series", 8, },
- { "CP-132U series", 2, },
-/*15*/ { "CP-134U series", 4, },
- { "CP-104JU series", 4, },
- { "Moxa UC7000 Serial", 8, }, /* RC7000 */
- { "CP-118U series", 8, },
- { "CP-102UL series", 2, },
-/*20*/ { "CP-102U series", 2, },
- { "CP-118EL series", 8, },
- { "CP-168EL series", 8, },
- { "CP-104EL series", 4, },
- { "CB-108 series", 8, },
-/*25*/ { "CB-114 series", 4, },
- { "CB-134I series", 4, },
- { "CP-138U series", 8, },
- { "POS-104UL series", 4, },
- { "CP-114UL series", 4, },
-/*30*/ { "CP-102UF series", 2, },
- { "CP-112UL series", 2, },
-};
/* driver_data correspond to the lines in the structure above
see also ISA probe function before you change something */
static const struct pci_device_id mxser_pcibrds[] = {
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 3 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 8 },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104), .driver_data = 4 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132), .driver_data = 8 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114), .driver_data = 9 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114), .driver_data = 10 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102), .driver_data = 11 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U), .driver_data = 12 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U), .driver_data = 13 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U), .driver_data = 14 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U), .driver_data = 15 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 16 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000), .driver_data = 17 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U), .driver_data = 18 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 19 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U), .driver_data = 20 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 21 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 22 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 23 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108), .driver_data = 24 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114), .driver_data = 25 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I), .driver_data = 26 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U), .driver_data = 27 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL), .driver_data = 28 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL), .driver_data = 29 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP102UF), .driver_data = 30 },
- { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP112UL), .driver_data = 31 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132), .driver_data = 2 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114), .driver_data = 4 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114), .driver_data = 4 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102), .driver_data = 2 | MXSER_HIGHBAUD },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U), .driver_data = 4 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U), .driver_data = 8 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U), .driver_data = 2 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U), .driver_data = 4 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 4 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000), .driver_data = 8 }, /* RC7000 */
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U), .driver_data = 8 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 2 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U), .driver_data = 2 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 8 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 8 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 4 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108), .driver_data = 8 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114), .driver_data = 4 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I), .driver_data = 4 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U), .driver_data = 8 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL), .driver_data = 4 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL), .driver_data = 4 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP102UF), .driver_data = 2 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP112UL), .driver_data = 2 },
{ }
};
MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
-static unsigned long ioaddr[MXSER_BOARDS];
static int ttymajor = MXSERMAJOR;
/* Variables for insmod */
MODULE_AUTHOR("Casper Yang");
MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");
-module_param_hw_array(ioaddr, ulong, ioport, NULL, 0);
-MODULE_PARM_DESC(ioaddr, "ISA io addresses to look for a moxa board");
module_param(ttymajor, int, 0);
MODULE_LICENSE("GPL");
-struct mxser_log {
- int tick;
- unsigned long rxcnt[MXSER_PORTS];
- unsigned long txcnt[MXSER_PORTS];
-};
-
-struct mxser_mon {
- unsigned long rxcnt;
- unsigned long txcnt;
- unsigned long up_rxcnt;
- unsigned long up_txcnt;
- int modem_status;
- unsigned char hold_reason;
-};
-
-struct mxser_mon_ext {
- unsigned long rx_cnt[32];
- unsigned long tx_cnt[32];
- unsigned long up_rxcnt[32];
- unsigned long up_txcnt[32];
- int modem_status[32];
-
- long baudrate[32];
- int databits[32];
- int stopbits[32];
- int parity[32];
- int flowctrl[32];
- int fifo[32];
- int iftype[32];
-};
-
struct mxser_board;
struct mxser_port {
@@ -223,274 +241,147 @@ struct mxser_port {
unsigned long ioaddr;
unsigned long opmode_ioaddr;
- int max_baud;
- int rx_high_water;
- int rx_trigger; /* Rx fifo trigger level */
- int rx_low_water;
- int baud_base; /* max. speed */
+ u8 rx_high_water;
+ u8 rx_low_water;
int type; /* UART type */
- int x_char; /* xon/xoff character */
- int IER; /* Interrupt Enable Register */
- int MCR; /* Modem control register */
+ unsigned char x_char; /* xon/xoff character */
+ u8 IER; /* Interrupt Enable Register */
+ u8 MCR; /* Modem control register */
- unsigned char stop_rx;
unsigned char ldisc_stop_rx;
- int custom_divisor;
- unsigned char err_shadow;
-
struct async_icount icount; /* kernel counters for 4 input interrupts */
unsigned int timeout;
- int read_status_mask;
- int ignore_status_mask;
- unsigned int xmit_fifo_size;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
+ u8 read_status_mask;
+ u8 ignore_status_mask;
+ u8 xmit_fifo_size;
+ unsigned int xmit_head;
+ unsigned int xmit_tail;
+ unsigned int xmit_cnt;
int closing;
- struct ktermios normal_termios;
-
- struct mxser_mon mon_data;
-
spinlock_t slock;
};
struct mxser_board {
unsigned int idx;
+ unsigned short nports;
int irq;
- const struct mxser_cardinfo *info;
unsigned long vector;
- unsigned long vector_mask;
-
- int chip_flag;
- int uart_type;
- struct mxser_port ports[MXSER_PORTS_PER_BOARD];
-};
+ enum mxser_must_hwid must_hwid;
+ speed_t max_baud;
-struct mxser_mstatus {
- tcflag_t cflag;
- int cts;
- int dsr;
- int ri;
- int dcd;
+ struct mxser_port ports[];
};
-static struct mxser_board mxser_boards[MXSER_BOARDS];
+static DECLARE_BITMAP(mxser_boards, MXSER_BOARDS);
static struct tty_driver *mxvar_sdriver;
-static struct mxser_log mxvar_log;
-static int mxser_set_baud_method[MXSER_PORTS + 1];
-static void mxser_enable_must_enchance_mode(unsigned long baseio)
+static u8 __mxser_must_set_EFR(unsigned long baseio, u8 clear, u8 set,
+ bool restore_LCR)
{
- u8 oldlcr;
- u8 efr;
+ u8 oldlcr, efr;
oldlcr = inb(baseio + UART_LCR);
- outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENHANCED, baseio + UART_LCR);
efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
- efr |= MOXA_MUST_EFR_EFRB_ENABLE;
+ efr &= ~clear;
+ efr |= set;
outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
- outb(oldlcr, baseio + UART_LCR);
-}
-#ifdef CONFIG_PCI
-static void mxser_disable_must_enchance_mode(unsigned long baseio)
-{
- u8 oldlcr;
- u8 efr;
+ if (restore_LCR)
+ outb(oldlcr, baseio + UART_LCR);
- oldlcr = inb(baseio + UART_LCR);
- outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
-
- efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
- efr &= ~MOXA_MUST_EFR_EFRB_ENABLE;
+ return oldlcr;
+}
- outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
- outb(oldlcr, baseio + UART_LCR);
+static u8 mxser_must_select_bank(unsigned long baseio, u8 bank)
+{
+ return __mxser_must_set_EFR(baseio, MOXA_MUST_EFR_BANK_MASK, bank,
+ false);
}
-#endif
static void mxser_set_must_xon1_value(unsigned long baseio, u8 value)
{
- u8 oldlcr;
- u8 efr;
-
- oldlcr = inb(baseio + UART_LCR);
- outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
-
- efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
- efr &= ~MOXA_MUST_EFR_BANK_MASK;
- efr |= MOXA_MUST_EFR_BANK0;
-
- outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK0);
outb(value, baseio + MOXA_MUST_XON1_REGISTER);
outb(oldlcr, baseio + UART_LCR);
}
static void mxser_set_must_xoff1_value(unsigned long baseio, u8 value)
{
- u8 oldlcr;
- u8 efr;
-
- oldlcr = inb(baseio + UART_LCR);
- outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
-
- efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
- efr &= ~MOXA_MUST_EFR_BANK_MASK;
- efr |= MOXA_MUST_EFR_BANK0;
-
- outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK0);
outb(value, baseio + MOXA_MUST_XOFF1_REGISTER);
outb(oldlcr, baseio + UART_LCR);
}
static void mxser_set_must_fifo_value(struct mxser_port *info)
{
- u8 oldlcr;
- u8 efr;
-
- oldlcr = inb(info->ioaddr + UART_LCR);
- outb(MOXA_MUST_ENTER_ENCHANCE, info->ioaddr + UART_LCR);
-
- efr = inb(info->ioaddr + MOXA_MUST_EFR_REGISTER);
- efr &= ~MOXA_MUST_EFR_BANK_MASK;
- efr |= MOXA_MUST_EFR_BANK1;
-
- outb(efr, info->ioaddr + MOXA_MUST_EFR_REGISTER);
- outb((u8)info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTH_REGISTER);
- outb((u8)info->rx_trigger, info->ioaddr + MOXA_MUST_RBRTI_REGISTER);
- outb((u8)info->rx_low_water, info->ioaddr + MOXA_MUST_RBRTL_REGISTER);
+ u8 oldlcr = mxser_must_select_bank(info->ioaddr, MOXA_MUST_EFR_BANK1);
+ outb(info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTH_REGISTER);
+ outb(info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTI_REGISTER);
+ outb(info->rx_low_water, info->ioaddr + MOXA_MUST_RBRTL_REGISTER);
outb(oldlcr, info->ioaddr + UART_LCR);
}
static void mxser_set_must_enum_value(unsigned long baseio, u8 value)
{
- u8 oldlcr;
- u8 efr;
-
- oldlcr = inb(baseio + UART_LCR);
- outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
-
- efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
- efr &= ~MOXA_MUST_EFR_BANK_MASK;
- efr |= MOXA_MUST_EFR_BANK2;
-
- outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK2);
outb(value, baseio + MOXA_MUST_ENUM_REGISTER);
outb(oldlcr, baseio + UART_LCR);
}
-#ifdef CONFIG_PCI
-static void mxser_get_must_hardware_id(unsigned long baseio, u8 *pId)
+static u8 mxser_get_must_hardware_id(unsigned long baseio)
{
- u8 oldlcr;
- u8 efr;
-
- oldlcr = inb(baseio + UART_LCR);
- outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
-
- efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
- efr &= ~MOXA_MUST_EFR_BANK_MASK;
- efr |= MOXA_MUST_EFR_BANK2;
-
- outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
- *pId = inb(baseio + MOXA_MUST_HWID_REGISTER);
+ u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK2);
+ u8 id = inb(baseio + MOXA_MUST_HWID_REGISTER);
outb(oldlcr, baseio + UART_LCR);
+
+ return id;
}
-#endif
-static void SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(unsigned long baseio)
+static void mxser_must_set_EFR(unsigned long baseio, u8 clear, u8 set)
{
- u8 oldlcr;
- u8 efr;
-
- oldlcr = inb(baseio + UART_LCR);
- outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
-
- efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
- efr &= ~MOXA_MUST_EFR_SF_MASK;
-
- outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
- outb(oldlcr, baseio + UART_LCR);
+ __mxser_must_set_EFR(baseio, clear, set, true);
}
-static void mxser_enable_must_tx_software_flow_control(unsigned long baseio)
+static void mxser_must_set_enhance_mode(unsigned long baseio, bool enable)
{
- u8 oldlcr;
- u8 efr;
-
- oldlcr = inb(baseio + UART_LCR);
- outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
-
- efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
- efr &= ~MOXA_MUST_EFR_SF_TX_MASK;
- efr |= MOXA_MUST_EFR_SF_TX1;
-
- outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
- outb(oldlcr, baseio + UART_LCR);
+ mxser_must_set_EFR(baseio,
+ enable ? 0 : MOXA_MUST_EFR_EFRB_ENABLE,
+ enable ? MOXA_MUST_EFR_EFRB_ENABLE : 0);
}
-static void mxser_disable_must_tx_software_flow_control(unsigned long baseio)
+static void mxser_must_no_sw_flow_control(unsigned long baseio)
{
- u8 oldlcr;
- u8 efr;
-
- oldlcr = inb(baseio + UART_LCR);
- outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
-
- efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
- efr &= ~MOXA_MUST_EFR_SF_TX_MASK;
-
- outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
- outb(oldlcr, baseio + UART_LCR);
+ mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_MASK, 0);
}
-static void mxser_enable_must_rx_software_flow_control(unsigned long baseio)
+static void mxser_must_set_tx_sw_flow_control(unsigned long baseio, bool enable)
{
- u8 oldlcr;
- u8 efr;
-
- oldlcr = inb(baseio + UART_LCR);
- outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
-
- efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
- efr &= ~MOXA_MUST_EFR_SF_RX_MASK;
- efr |= MOXA_MUST_EFR_SF_RX1;
-
- outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
- outb(oldlcr, baseio + UART_LCR);
+ mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_TX_MASK,
+ enable ? MOXA_MUST_EFR_SF_TX1 : 0);
}
-static void mxser_disable_must_rx_software_flow_control(unsigned long baseio)
+static void mxser_must_set_rx_sw_flow_control(unsigned long baseio, bool enable)
{
- u8 oldlcr;
- u8 efr;
-
- oldlcr = inb(baseio + UART_LCR);
- outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
-
- efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
- efr &= ~MOXA_MUST_EFR_SF_RX_MASK;
-
- outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
- outb(oldlcr, baseio + UART_LCR);
+ mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_RX_MASK,
+ enable ? MOXA_MUST_EFR_SF_RX1 : 0);
}
-#ifdef CONFIG_PCI
-static int CheckIsMoxaMust(unsigned long io)
+static enum mxser_must_hwid mxser_must_get_hwid(unsigned long io)
{
u8 oldmcr, hwid;
int i;
outb(0, io + UART_LCR);
- mxser_disable_must_enchance_mode(io);
+ mxser_must_set_enhance_mode(io, false);
oldmcr = inb(io + UART_MCR);
outb(0, io + UART_MCR);
mxser_set_must_xon1_value(io, 0x11);
@@ -499,49 +390,59 @@ static int CheckIsMoxaMust(unsigned long io)
return MOXA_OTHER_UART;
}
- mxser_get_must_hardware_id(io, &hwid);
- for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */
+ hwid = mxser_get_must_hardware_id(io);
+ for (i = 1; i < UART_INFO_NUM; i++) /* 0 = OTHER_UART */
if (hwid == Gpci_uart_info[i].type)
- return (int)hwid;
- }
+ return hwid;
+
return MOXA_OTHER_UART;
}
-#endif
-static void process_txrx_fifo(struct mxser_port *info)
+static bool mxser_16550A_or_MUST(struct mxser_port *info)
{
- int i;
+ return info->type == PORT_16550A || info->board->must_hwid;
+}
- if ((info->type == PORT_16450) || (info->type == PORT_8250)) {
- info->rx_trigger = 1;
+static void mxser_process_txrx_fifo(struct mxser_port *info)
+{
+ unsigned int i;
+
+ if (info->type == PORT_16450 || info->type == PORT_8250) {
info->rx_high_water = 1;
info->rx_low_water = 1;
info->xmit_fifo_size = 1;
- } else
- for (i = 0; i < UART_INFO_NUM; i++)
- if (info->board->chip_flag == Gpci_uart_info[i].type) {
- info->rx_trigger = Gpci_uart_info[i].rx_trigger;
- info->rx_low_water = Gpci_uart_info[i].rx_low_water;
- info->rx_high_water = Gpci_uart_info[i].rx_high_water;
- info->xmit_fifo_size = Gpci_uart_info[i].xmit_fifo_size;
- break;
- }
+ return;
+ }
+
+ for (i = 0; i < UART_INFO_NUM; i++)
+ if (info->board->must_hwid == Gpci_uart_info[i].type) {
+ info->rx_low_water = Gpci_uart_info[i].rx_low_water;
+ info->rx_high_water = Gpci_uart_info[i].rx_high_water;
+ info->xmit_fifo_size = Gpci_uart_info[i].fifo_size;
+ break;
+ }
}
-static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
+static void __mxser_start_tx(struct mxser_port *info)
{
- static unsigned char mxser_msr[MXSER_PORTS + 1];
- unsigned char status = 0;
+ outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+}
- status = inb(baseaddr + UART_MSR);
+static void mxser_start_tx(struct mxser_port *info)
+{
+ unsigned long flags;
- mxser_msr[port] &= 0x0F;
- mxser_msr[port] |= status;
- status = mxser_msr[port];
- if (mode)
- mxser_msr[port] = 0;
+ spin_lock_irqsave(&info->slock, flags);
+ __mxser_start_tx(info);
+ spin_unlock_irqrestore(&info->slock, flags);
+}
- return status;
+static void __mxser_stop_tx(struct mxser_port *info)
+{
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
}
static int mxser_carrier_raised(struct tty_port *port)
@@ -554,38 +455,36 @@ static void mxser_dtr_rts(struct tty_port *port, int on)
{
struct mxser_port *mp = container_of(port, struct mxser_port, port);
unsigned long flags;
+ u8 mcr;
spin_lock_irqsave(&mp->slock, flags);
+ mcr = inb(mp->ioaddr + UART_MCR);
if (on)
- outb(inb(mp->ioaddr + UART_MCR) |
- UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR);
+ mcr |= UART_MCR_DTR | UART_MCR_RTS;
else
- outb(inb(mp->ioaddr + UART_MCR)&~(UART_MCR_DTR | UART_MCR_RTS),
- mp->ioaddr + UART_MCR);
+ mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
+ outb(mcr, mp->ioaddr + UART_MCR);
spin_unlock_irqrestore(&mp->slock, flags);
}
-static int mxser_set_baud(struct tty_struct *tty, long newspd)
+static int mxser_set_baud(struct tty_struct *tty, speed_t newspd)
{
struct mxser_port *info = tty->driver_data;
unsigned int quot = 0, baud;
unsigned char cval;
u64 timeout;
- if (!info->ioaddr)
- return -1;
-
- if (newspd > info->max_baud)
+ if (newspd > info->board->max_baud)
return -1;
if (newspd == 134) {
- quot = 2 * info->baud_base / 269;
+ quot = 2 * MXSER_BAUD_BASE / 269;
tty_encode_baud_rate(tty, 134, 134);
} else if (newspd) {
- quot = info->baud_base / newspd;
+ quot = MXSER_BAUD_BASE / newspd;
if (quot == 0)
quot = 1;
- baud = info->baud_base/quot;
+ baud = MXSER_BAUD_BASE / quot;
tty_encode_baud_rate(tty, baud, baud);
} else {
quot = 0;
@@ -596,7 +495,7 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd)
* u64 domain
*/
timeout = (u64)info->xmit_fifo_size * HZ * 10 * quot;
- do_div(timeout, info->baud_base);
+ do_div(timeout, MXSER_BAUD_BASE);
info->timeout = timeout + HZ / 50; /* Add .02 seconds of slop */
if (quot) {
@@ -618,7 +517,7 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd)
#ifdef BOTHER
if (C_BAUD(tty) == BOTHER) {
- quot = info->baud_base % newspd;
+ quot = MXSER_BAUD_BASE % newspd;
quot *= 8;
if (quot % newspd > newspd / 2) {
quot /= newspd;
@@ -634,6 +533,28 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd)
return 0;
}
+static void mxser_handle_cts(struct tty_struct *tty, struct mxser_port *info,
+ u8 msr)
+{
+ bool cts = msr & UART_MSR_CTS;
+
+ if (tty->hw_stopped) {
+ if (cts) {
+ tty->hw_stopped = 0;
+
+ if (!mxser_16550A_or_MUST(info))
+ __mxser_start_tx(info);
+ tty_wakeup(tty);
+ }
+ return;
+ } else if (cts)
+ return;
+
+ tty->hw_stopped = 1;
+ if (!mxser_16550A_or_MUST(info))
+ __mxser_stop_tx(info);
+}
+
/*
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
@@ -642,35 +563,30 @@ static void mxser_change_speed(struct tty_struct *tty)
{
struct mxser_port *info = tty->driver_data;
unsigned cflag, cval, fcr;
- unsigned char status;
cflag = tty->termios.c_cflag;
- if (!info->ioaddr)
- return;
- if (mxser_set_baud_method[tty->index] == 0)
- mxser_set_baud(tty, tty_get_baud_rate(tty));
+ mxser_set_baud(tty, tty_get_baud_rate(tty));
/* byte size and parity */
switch (cflag & CSIZE) {
+ default:
case CS5:
- cval = 0x00;
+ cval = UART_LCR_WLEN5;
break;
case CS6:
- cval = 0x01;
+ cval = UART_LCR_WLEN6;
break;
case CS7:
- cval = 0x02;
+ cval = UART_LCR_WLEN7;
break;
case CS8:
- cval = 0x03;
+ cval = UART_LCR_WLEN8;
break;
- default:
- cval = 0x00;
- break; /* too keep GCC shut... */
}
+
if (cflag & CSTOPB)
- cval |= 0x04;
+ cval |= UART_LCR_STOP;
if (cflag & PARENB)
cval |= UART_LCR_PARITY;
if (!(cflag & PARODD))
@@ -679,7 +595,7 @@ static void mxser_change_speed(struct tty_struct *tty)
cval |= UART_LCR_SPAR;
if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
- if (info->board->chip_flag) {
+ if (info->board->must_hwid) {
fcr = UART_FCR_ENABLE_FIFO;
fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
mxser_set_must_fifo_value(info);
@@ -687,11 +603,11 @@ static void mxser_change_speed(struct tty_struct *tty)
fcr = 0;
} else {
fcr = UART_FCR_ENABLE_FIFO;
- if (info->board->chip_flag) {
+ if (info->board->must_hwid) {
fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
mxser_set_must_fifo_value(info);
} else {
- switch (info->rx_trigger) {
+ switch (info->rx_high_water) {
case 1:
fcr |= UART_FCR_TRIGGER_1;
break;
@@ -714,35 +630,11 @@ static void mxser_change_speed(struct tty_struct *tty)
tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
if (cflag & CRTSCTS) {
info->IER |= UART_IER_MSI;
- if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
+ if (mxser_16550A_or_MUST(info)) {
info->MCR |= UART_MCR_AFE;
} else {
- status = inb(info->ioaddr + UART_MSR);
- if (tty->hw_stopped) {
- if (status & UART_MSR_CTS) {
- tty->hw_stopped = 0;
- if (info->type != PORT_16550A &&
- !info->board->chip_flag) {
- outb(info->IER & ~UART_IER_THRI,
- info->ioaddr +
- UART_IER);
- info->IER |= UART_IER_THRI;
- outb(info->IER, info->ioaddr +
- UART_IER);
- }
- tty_wakeup(tty);
- }
- } else {
- if (!(status & UART_MSR_CTS)) {
- tty->hw_stopped = 1;
- if ((info->type != PORT_16550A) &&
- (!info->board->chip_flag)) {
- info->IER &= ~UART_IER_THRI;
- outb(info->IER, info->ioaddr +
- UART_IER);
- }
- }
- }
+ mxser_handle_cts(tty, info,
+ inb(info->ioaddr + UART_MSR));
}
}
outb(info->MCR, info->ioaddr + UART_MCR);
@@ -780,23 +672,11 @@ static void mxser_change_speed(struct tty_struct *tty)
UART_LSR_FE;
}
}
- if (info->board->chip_flag) {
+ if (info->board->must_hwid) {
mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty));
mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty));
- if (I_IXON(tty)) {
- mxser_enable_must_rx_software_flow_control(
- info->ioaddr);
- } else {
- mxser_disable_must_rx_software_flow_control(
- info->ioaddr);
- }
- if (I_IXOFF(tty)) {
- mxser_enable_must_tx_software_flow_control(
- info->ioaddr);
- } else {
- mxser_disable_must_tx_software_flow_control(
- info->ioaddr);
- }
+ mxser_must_set_rx_sw_flow_control(info->ioaddr, I_IXON(tty));
+ mxser_must_set_tx_sw_flow_control(info->ioaddr, I_IXOFF(tty));
}
@@ -816,7 +696,6 @@ static void mxser_check_modem_status(struct tty_struct *tty,
port->icount.dcd++;
if (status & UART_MSR_DCTS)
port->icount.cts++;
- port->mon_data.modem_status = status;
wake_up_interruptible(&port->port.delta_msr_wait);
if (tty_port_check_carrier(&port->port) && (status & UART_MSR_DDCD)) {
@@ -824,33 +703,8 @@ static void mxser_check_modem_status(struct tty_struct *tty,
wake_up_interruptible(&port->port.open_wait);
}
- if (tty_port_cts_enabled(&port->port)) {
- if (tty->hw_stopped) {
- if (status & UART_MSR_CTS) {
- tty->hw_stopped = 0;
-
- if ((port->type != PORT_16550A) &&
- (!port->board->chip_flag)) {
- outb(port->IER & ~UART_IER_THRI,
- port->ioaddr + UART_IER);
- port->IER |= UART_IER_THRI;
- outb(port->IER, port->ioaddr +
- UART_IER);
- }
- tty_wakeup(tty);
- }
- } else {
- if (!(status & UART_MSR_CTS)) {
- tty->hw_stopped = 1;
- if (port->type != PORT_16550A &&
- !port->board->chip_flag) {
- port->IER &= ~UART_IER_THRI;
- outb(port->IER, port->ioaddr +
- UART_IER);
- }
- }
- }
- }
+ if (tty_port_cts_enabled(&port->port))
+ mxser_handle_cts(tty, port, status);
}
static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
@@ -865,7 +719,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
spin_lock_irqsave(&info->slock, flags);
- if (!info->ioaddr || !info->type) {
+ if (!info->type) {
set_bit(TTY_IO_ERROR, &tty->flags);
free_page(page);
spin_unlock_irqrestore(&info->slock, flags);
@@ -877,7 +731,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
* Clear the FIFO buffers and disable them
* (they will be reenabled in mxser_change_speed())
*/
- if (info->board->chip_flag)
+ if (info->board->must_hwid)
outb((UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT |
MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR);
@@ -919,7 +773,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
*/
info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
- if (info->board->chip_flag)
+ if (info->board->must_hwid)
info->IER |= MOXA_MUST_IER_EGDAI;
outb(info->IER, info->ioaddr + UART_IER); /* enable interrupts */
@@ -971,7 +825,7 @@ static void mxser_shutdown_port(struct tty_port *port)
outb(0x00, info->ioaddr + UART_IER);
/* clear Rx/Tx FIFO's */
- if (info->board->chip_flag)
+ if (info->board->must_hwid)
outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
MOXA_MUST_FCR_GDA_MODE_ENABLE,
info->ioaddr + UART_FCR);
@@ -983,8 +837,8 @@ static void mxser_shutdown_port(struct tty_port *port)
(void) inb(info->ioaddr + UART_RX);
- if (info->board->chip_flag)
- SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ if (info->board->must_hwid)
+ mxser_must_no_sw_flow_control(info->ioaddr);
spin_unlock_irqrestore(&info->slock, flags);
}
@@ -997,18 +851,12 @@ static void mxser_shutdown_port(struct tty_port *port)
*/
static int mxser_open(struct tty_struct *tty, struct file *filp)
{
- struct mxser_port *info;
- int line;
+ struct tty_port *tport = tty->port;
+ struct mxser_port *port = container_of(tport, struct mxser_port, port);
- line = tty->index;
- if (line == MXSER_PORTS)
- return 0;
- info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD];
- if (!info->ioaddr)
- return -ENODEV;
+ tty->driver_data = port;
- tty->driver_data = info;
- return tty_port_open(&info->port, tty, filp);
+ return tty_port_open(tport, tty, filp);
}
static void mxser_flush_buffer(struct tty_struct *tty)
@@ -1043,7 +891,7 @@ static void mxser_close_port(struct tty_port *port)
* line status register.
*/
info->IER &= ~UART_IER_RLSI;
- if (info->board->chip_flag)
+ if (info->board->must_hwid)
info->IER &= ~MOXA_MUST_RECV_ISR;
outb(info->IER, info->ioaddr + UART_IER);
@@ -1071,7 +919,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
struct mxser_port *info = tty->driver_data;
struct tty_port *port = &info->port;
- if (tty->index == MXSER_PORTS || info == NULL)
+ if (info == NULL)
return;
if (tty_port_close_start(port, tty, filp) == 0)
return;
@@ -1118,18 +966,10 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou
total += c;
}
- if (info->xmit_cnt && !tty->stopped) {
- if (!tty->hw_stopped ||
- (info->type == PORT_16550A) ||
- (info->board->chip_flag)) {
- spin_lock_irqsave(&info->slock, flags);
- outb(info->IER & ~UART_IER_THRI, info->ioaddr +
- UART_IER);
- info->IER |= UART_IER_THRI;
- outb(info->IER, info->ioaddr + UART_IER);
- spin_unlock_irqrestore(&info->slock, flags);
- }
- }
+ if (info->xmit_cnt && !tty->flow.stopped)
+ if (!tty->hw_stopped || mxser_16550A_or_MUST(info))
+ mxser_start_tx(info);
+
return total;
}
@@ -1149,17 +989,7 @@ static int mxser_put_char(struct tty_struct *tty, unsigned char ch)
info->xmit_head &= SERIAL_XMIT_SIZE - 1;
info->xmit_cnt++;
spin_unlock_irqrestore(&info->slock, flags);
- if (!tty->stopped) {
- if (!tty->hw_stopped ||
- (info->type == PORT_16550A) ||
- info->board->chip_flag) {
- spin_lock_irqsave(&info->slock, flags);
- outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
- info->IER |= UART_IER_THRI;
- outb(info->IER, info->ioaddr + UART_IER);
- spin_unlock_irqrestore(&info->slock, flags);
- }
- }
+
return 1;
}
@@ -1167,23 +997,15 @@ static int mxser_put_char(struct tty_struct *tty, unsigned char ch)
static void mxser_flush_chars(struct tty_struct *tty)
{
struct mxser_port *info = tty->driver_data;
- unsigned long flags;
- if (info->xmit_cnt <= 0 || tty->stopped || !info->port.xmit_buf ||
- (tty->hw_stopped && info->type != PORT_16550A &&
- !info->board->chip_flag))
+ if (!info->xmit_cnt || tty->flow.stopped || !info->port.xmit_buf ||
+ (tty->hw_stopped && !mxser_16550A_or_MUST(info)))
return;
- spin_lock_irqsave(&info->slock, flags);
-
- outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
- info->IER |= UART_IER_THRI;
- outb(info->IER, info->ioaddr + UART_IER);
-
- spin_unlock_irqrestore(&info->slock, flags);
+ mxser_start_tx(info);
}
-static int mxser_write_room(struct tty_struct *tty)
+static unsigned int mxser_write_room(struct tty_struct *tty)
{
struct mxser_port *info = tty->driver_data;
int ret;
@@ -1192,7 +1014,7 @@ static int mxser_write_room(struct tty_struct *tty)
return ret < 0 ? 0 : ret;
}
-static int mxser_chars_in_buffer(struct tty_struct *tty)
+static unsigned int mxser_chars_in_buffer(struct tty_struct *tty)
{
struct mxser_port *info = tty->driver_data;
return info->xmit_cnt;
@@ -1210,9 +1032,6 @@ static int mxser_get_serial_info(struct tty_struct *tty,
struct tty_port *port = &info->port;
unsigned int closing_wait, close_delay;
- if (tty->index == MXSER_PORTS)
- return -ENOTTY;
-
mutex_lock(&port->mutex);
close_delay = jiffies_to_msecs(info->port.close_delay) / 10;
@@ -1225,10 +1044,10 @@ static int mxser_get_serial_info(struct tty_struct *tty,
ss->port = info->ioaddr,
ss->irq = info->board->irq,
ss->flags = info->port.flags,
- ss->baud_base = info->baud_base,
+ ss->baud_base = MXSER_BAUD_BASE,
ss->close_delay = close_delay;
ss->closing_wait = closing_wait;
- ss->custom_divisor = info->custom_divisor,
+ ss->custom_divisor = MXSER_CUSTOM_DIVISOR,
mutex_unlock(&port->mutex);
return 0;
}
@@ -1240,19 +1059,13 @@ static int mxser_set_serial_info(struct tty_struct *tty,
struct tty_port *port = &info->port;
speed_t baud;
unsigned long sl_flags;
- unsigned int flags, close_delay, closing_wait;
+ unsigned int old_speed, close_delay, closing_wait;
int retval = 0;
- if (tty->index == MXSER_PORTS)
- return -ENOTTY;
if (tty_io_error(tty))
return -EIO;
mutex_lock(&port->mutex);
- if (!info->ioaddr) {
- mutex_unlock(&port->mutex);
- return -ENODEV;
- }
if (ss->irq != info->board->irq ||
ss->port != info->ioaddr) {
@@ -1260,7 +1073,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
return -EINVAL;
}
- flags = port->flags & ASYNC_SPD_MASK;
+ old_speed = port->flags & ASYNC_SPD_MASK;
close_delay = msecs_to_jiffies(ss->close_delay * 10);
closing_wait = ss->closing_wait;
@@ -1268,15 +1081,15 @@ static int mxser_set_serial_info(struct tty_struct *tty,
closing_wait = msecs_to_jiffies(closing_wait * 10);
if (!capable(CAP_SYS_ADMIN)) {
- if ((ss->baud_base != info->baud_base) ||
- (close_delay != info->port.close_delay) ||
- (closing_wait != info->port.closing_wait) ||
- ((ss->flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK))) {
+ if ((ss->baud_base != MXSER_BAUD_BASE) ||
+ (close_delay != port->close_delay) ||
+ (closing_wait != port->closing_wait) ||
+ ((ss->flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) {
mutex_unlock(&port->mutex);
return -EPERM;
}
- info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) |
- (ss->flags & ASYNC_USR_MASK));
+ port->flags = (port->flags & ~ASYNC_USR_MASK) |
+ (ss->flags & ASYNC_USR_MASK);
} else {
/*
* OK, past this point, all the error checking has been done.
@@ -1287,9 +1100,9 @@ static int mxser_set_serial_info(struct tty_struct *tty,
port->close_delay = close_delay;
port->closing_wait = closing_wait;
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
- (ss->baud_base != info->baud_base ||
+ (ss->baud_base != MXSER_BAUD_BASE ||
ss->custom_divisor !=
- info->custom_divisor)) {
+ MXSER_CUSTOM_DIVISOR)) {
if (ss->custom_divisor == 0) {
mutex_unlock(&port->mutex);
return -EINVAL;
@@ -1300,11 +1113,11 @@ static int mxser_set_serial_info(struct tty_struct *tty,
info->type = ss->type;
- process_txrx_fifo(info);
+ mxser_process_txrx_fifo(info);
}
if (tty_port_initialized(port)) {
- if (flags != (port->flags & ASYNC_SPD_MASK)) {
+ if (old_speed != (port->flags & ASYNC_SPD_MASK)) {
spin_lock_irqsave(&info->slock, sl_flags);
mxser_change_speed(tty);
spin_unlock_irqrestore(&info->slock, sl_flags);
@@ -1348,19 +1161,16 @@ static int mxser_tiocmget(struct tty_struct *tty)
unsigned char control, status;
unsigned long flags;
-
- if (tty->index == MXSER_PORTS)
- return -ENOIOCTLCMD;
if (tty_io_error(tty))
return -EIO;
- control = info->MCR;
-
spin_lock_irqsave(&info->slock, flags);
+ control = info->MCR;
status = inb(info->ioaddr + UART_MSR);
if (status & UART_MSR_ANY_DELTA)
mxser_check_modem_status(tty, info, status);
spin_unlock_irqrestore(&info->slock, flags);
+
return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
@@ -1375,9 +1185,6 @@ static int mxser_tiocmset(struct tty_struct *tty,
struct mxser_port *info = tty->driver_data;
unsigned long flags;
-
- if (tty->index == MXSER_PORTS)
- return -ENOIOCTLCMD;
if (tty_io_error(tty))
return -EIO;
@@ -1398,267 +1205,6 @@ static int mxser_tiocmset(struct tty_struct *tty,
return 0;
}
-static int __init mxser_program_mode(int port)
-{
- int id, i, j, n;
-
- outb(0, port);
- outb(0, port);
- outb(0, port);
- (void)inb(port);
- (void)inb(port);
- outb(0, port);
- (void)inb(port);
-
- id = inb(port + 1) & 0x1F;
- if ((id != C168_ASIC_ID) &&
- (id != C104_ASIC_ID) &&
- (id != C102_ASIC_ID) &&
- (id != CI132_ASIC_ID) &&
- (id != CI134_ASIC_ID) &&
- (id != CI104J_ASIC_ID))
- return -1;
- for (i = 0, j = 0; i < 4; i++) {
- n = inb(port + 2);
- if (n == 'M') {
- j = 1;
- } else if ((j == 1) && (n == 1)) {
- j = 2;
- break;
- } else
- j = 0;
- }
- if (j != 2)
- id = -2;
- return id;
-}
-
-static void __init mxser_normal_mode(int port)
-{
- int i, n;
-
- outb(0xA5, port + 1);
- outb(0x80, port + 3);
- outb(12, port + 0); /* 9600 bps */
- outb(0, port + 1);
- outb(0x03, port + 3); /* 8 data bits */
- outb(0x13, port + 4); /* loop back mode */
- for (i = 0; i < 16; i++) {
- n = inb(port + 5);
- if ((n & 0x61) == 0x60)
- break;
- if ((n & 1) == 1)
- (void)inb(port);
- }
- outb(0x00, port + 4);
-}
-
-#define CHIP_SK 0x01 /* Serial Data Clock in Eprom */
-#define CHIP_DO 0x02 /* Serial Data Output in Eprom */
-#define CHIP_CS 0x04 /* Serial Chip Select in Eprom */
-#define CHIP_DI 0x08 /* Serial Data Input in Eprom */
-#define EN_CCMD 0x000 /* Chip's command register */
-#define EN0_RSARLO 0x008 /* Remote start address reg 0 */
-#define EN0_RSARHI 0x009 /* Remote start address reg 1 */
-#define EN0_RCNTLO 0x00A /* Remote byte count reg WR */
-#define EN0_RCNTHI 0x00B /* Remote byte count reg WR */
-#define EN0_DCFG 0x00E /* Data configuration reg WR */
-#define EN0_PORT 0x010 /* Rcv missed frame error counter RD */
-#define ENC_PAGE0 0x000 /* Select page 0 of chip registers */
-#define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */
-static int __init mxser_read_register(int port, unsigned short *regs)
-{
- int i, k, value, id;
- unsigned int j;
-
- id = mxser_program_mode(port);
- if (id < 0)
- return id;
- for (i = 0; i < 14; i++) {
- k = (i & 0x3F) | 0x180;
- for (j = 0x100; j > 0; j >>= 1) {
- outb(CHIP_CS, port);
- if (k & j) {
- outb(CHIP_CS | CHIP_DO, port);
- outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */
- } else {
- outb(CHIP_CS, port);
- outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */
- }
- }
- (void)inb(port);
- value = 0;
- for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
- outb(CHIP_CS, port);
- outb(CHIP_CS | CHIP_SK, port);
- if (inb(port) & CHIP_DI)
- value |= j;
- }
- regs[i] = value;
- outb(0, port);
- }
- mxser_normal_mode(port);
- return id;
-}
-
-static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
-{
- struct mxser_port *ip;
- struct tty_port *port;
- struct tty_struct *tty;
- int result, status;
- unsigned int i, j;
- int ret = 0;
-
- switch (cmd) {
- case MOXA_GET_MAJOR:
- printk_ratelimited(KERN_WARNING "mxser: '%s' uses deprecated ioctl "
- "%x (GET_MAJOR), fix your userspace\n",
- current->comm, cmd);
- return put_user(ttymajor, (int __user *)argp);
-
- case MOXA_CHKPORTENABLE:
- result = 0;
- for (i = 0; i < MXSER_BOARDS; i++)
- for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
- if (mxser_boards[i].ports[j].ioaddr)
- result |= (1 << i);
- return put_user(result, (unsigned long __user *)argp);
- case MOXA_GETDATACOUNT:
- /* The receive side is locked by port->slock but it isn't
- clear that an exact snapshot is worth copying here */
- if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
- ret = -EFAULT;
- return ret;
- case MOXA_GETMSTATUS: {
- struct mxser_mstatus ms, __user *msu = argp;
- for (i = 0; i < MXSER_BOARDS; i++)
- for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
- ip = &mxser_boards[i].ports[j];
- port = &ip->port;
- memset(&ms, 0, sizeof(ms));
-
- mutex_lock(&port->mutex);
- if (!ip->ioaddr)
- goto copy;
-
- tty = tty_port_tty_get(port);
-
- if (!tty)
- ms.cflag = ip->normal_termios.c_cflag;
- else
- ms.cflag = tty->termios.c_cflag;
- tty_kref_put(tty);
- spin_lock_irq(&ip->slock);
- status = inb(ip->ioaddr + UART_MSR);
- spin_unlock_irq(&ip->slock);
- if (status & UART_MSR_DCD)
- ms.dcd = 1;
- if (status & UART_MSR_DSR)
- ms.dsr = 1;
- if (status & UART_MSR_CTS)
- ms.cts = 1;
- copy:
- mutex_unlock(&port->mutex);
- if (copy_to_user(msu, &ms, sizeof(ms)))
- return -EFAULT;
- msu++;
- }
- return 0;
- }
- case MOXA_ASPP_MON_EXT: {
- struct mxser_mon_ext *me; /* it's 2k, stack unfriendly */
- unsigned int cflag, iflag, p;
- u8 opmode;
-
- me = kzalloc(sizeof(*me), GFP_KERNEL);
- if (!me)
- return -ENOMEM;
-
- for (i = 0, p = 0; i < MXSER_BOARDS; i++) {
- for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) {
- if (p >= ARRAY_SIZE(me->rx_cnt)) {
- i = MXSER_BOARDS;
- break;
- }
- ip = &mxser_boards[i].ports[j];
- port = &ip->port;
-
- mutex_lock(&port->mutex);
- if (!ip->ioaddr) {
- mutex_unlock(&port->mutex);
- continue;
- }
-
- spin_lock_irq(&ip->slock);
- status = mxser_get_msr(ip->ioaddr, 0, p);
-
- if (status & UART_MSR_TERI)
- ip->icount.rng++;
- if (status & UART_MSR_DDSR)
- ip->icount.dsr++;
- if (status & UART_MSR_DDCD)
- ip->icount.dcd++;
- if (status & UART_MSR_DCTS)
- ip->icount.cts++;
-
- ip->mon_data.modem_status = status;
- me->rx_cnt[p] = ip->mon_data.rxcnt;
- me->tx_cnt[p] = ip->mon_data.txcnt;
- me->up_rxcnt[p] = ip->mon_data.up_rxcnt;
- me->up_txcnt[p] = ip->mon_data.up_txcnt;
- me->modem_status[p] =
- ip->mon_data.modem_status;
- spin_unlock_irq(&ip->slock);
-
- tty = tty_port_tty_get(&ip->port);
-
- if (!tty) {
- cflag = ip->normal_termios.c_cflag;
- iflag = ip->normal_termios.c_iflag;
- me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios);
- } else {
- cflag = tty->termios.c_cflag;
- iflag = tty->termios.c_iflag;
- me->baudrate[p] = tty_get_baud_rate(tty);
- }
- tty_kref_put(tty);
-
- me->databits[p] = cflag & CSIZE;
- me->stopbits[p] = cflag & CSTOPB;
- me->parity[p] = cflag & (PARENB | PARODD |
- CMSPAR);
-
- if (cflag & CRTSCTS)
- me->flowctrl[p] |= 0x03;
-
- if (iflag & (IXON | IXOFF))
- me->flowctrl[p] |= 0x0C;
-
- if (ip->type == PORT_16550A)
- me->fifo[p] = 1;
-
- if (ip->board->chip_flag == MOXA_MUST_MU860_HWID) {
- opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2);
- opmode &= OP_MODE_MASK;
- } else {
- opmode = RS232_MODE;
- }
- me->iftype[p] = opmode;
- mutex_unlock(&port->mutex);
- }
- }
- if (copy_to_user(argp, me, sizeof(*me)))
- ret = -EFAULT;
- kfree(me);
- return ret;
- }
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
static int mxser_cflags_changed(struct mxser_port *info, unsigned long arg,
struct async_icount *cprev)
{
@@ -1680,6 +1226,41 @@ static int mxser_cflags_changed(struct mxser_port *info, unsigned long arg,
return ret;
}
+/* We should likely switch to TIOCGRS485/TIOCSRS485. */
+static int mxser_ioctl_op_mode(struct mxser_port *port, int index, bool set,
+ int __user *u_opmode)
+{
+ int opmode, p = index % 4;
+ int shiftbit = p * 2;
+ u8 val;
+
+ if (port->board->must_hwid != MOXA_MUST_MU860_HWID)
+ return -EFAULT;
+
+ if (set) {
+ if (get_user(opmode, u_opmode))
+ return -EFAULT;
+
+ if (opmode & ~OP_MODE_MASK)
+ return -EINVAL;
+
+ spin_lock_irq(&port->slock);
+ val = inb(port->opmode_ioaddr);
+ val &= ~(OP_MODE_MASK << shiftbit);
+ val |= (opmode << shiftbit);
+ outb(val, port->opmode_ioaddr);
+ spin_unlock_irq(&port->slock);
+
+ return 0;
+ }
+
+ spin_lock_irq(&port->slock);
+ opmode = inb(port->opmode_ioaddr) >> shiftbit;
+ spin_unlock_irq(&port->slock);
+
+ return put_user(opmode & OP_MODE_MASK, u_opmode);
+}
+
static int mxser_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -1688,47 +1269,9 @@ static int mxser_ioctl(struct tty_struct *tty,
unsigned long flags;
void __user *argp = (void __user *)arg;
- if (tty->index == MXSER_PORTS)
- return mxser_ioctl_special(cmd, argp);
-
- if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
- int p;
- unsigned long opmode;
- static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f };
- int shiftbit;
- unsigned char val, mask;
-
- if (info->board->chip_flag != MOXA_MUST_MU860_HWID)
- return -EFAULT;
-
- p = tty->index % 4;
- if (cmd == MOXA_SET_OP_MODE) {
- if (get_user(opmode, (int __user *) argp))
- return -EFAULT;
- if (opmode != RS232_MODE &&
- opmode != RS485_2WIRE_MODE &&
- opmode != RS422_MODE &&
- opmode != RS485_4WIRE_MODE)
- return -EFAULT;
- mask = ModeMask[p];
- shiftbit = p * 2;
- spin_lock_irq(&info->slock);
- val = inb(info->opmode_ioaddr);
- val &= mask;
- val |= (opmode << shiftbit);
- outb(val, info->opmode_ioaddr);
- spin_unlock_irq(&info->slock);
- } else {
- shiftbit = p * 2;
- spin_lock_irq(&info->slock);
- opmode = inb(info->opmode_ioaddr) >> shiftbit;
- spin_unlock_irq(&info->slock);
- opmode &= OP_MODE_MASK;
- if (put_user(opmode, (int __user *)argp))
- return -EFAULT;
- }
- return 0;
- }
+ if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE)
+ return mxser_ioctl_op_mode(info, tty->index,
+ cmd == MOXA_SET_OP_MODE, argp);
if (cmd != TIOCMIWAIT && tty_io_error(tty))
return -EIO;
@@ -1749,72 +1292,6 @@ static int mxser_ioctl(struct tty_struct *tty,
return wait_event_interruptible(info->port.delta_msr_wait,
mxser_cflags_changed(info, arg, &cnow));
- case MOXA_HighSpeedOn:
- return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
- case MOXA_SDS_RSTICOUNTER:
- spin_lock_irq(&info->slock);
- info->mon_data.rxcnt = 0;
- info->mon_data.txcnt = 0;
- spin_unlock_irq(&info->slock);
- return 0;
-
- case MOXA_ASPP_OQUEUE:{
- int len, lsr;
-
- len = mxser_chars_in_buffer(tty);
- spin_lock_irq(&info->slock);
- lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE;
- spin_unlock_irq(&info->slock);
- len += (lsr ? 0 : 1);
-
- return put_user(len, (int __user *)argp);
- }
- case MOXA_ASPP_MON: {
- int mcr, status;
-
- spin_lock_irq(&info->slock);
- status = mxser_get_msr(info->ioaddr, 1, tty->index);
- mxser_check_modem_status(tty, info, status);
-
- mcr = inb(info->ioaddr + UART_MCR);
- spin_unlock_irq(&info->slock);
-
- if (mcr & MOXA_MUST_MCR_XON_FLAG)
- info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
- else
- info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD;
-
- if (mcr & MOXA_MUST_MCR_TX_XON)
- info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT;
- else
- info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
-
- if (tty->hw_stopped)
- info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
- else
- info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
-
- if (copy_to_user(argp, &info->mon_data,
- sizeof(struct mxser_mon)))
- return -EFAULT;
-
- return 0;
- }
- case MOXA_ASPP_LSTATUS: {
- if (put_user(info->err_shadow, (unsigned char __user *)argp))
- return -EFAULT;
-
- info->err_shadow = 0;
- return 0;
- }
- case MOXA_SET_BAUD_METHOD: {
- int method;
-
- if (get_user(method, (int __user *)argp))
- return -EFAULT;
- mxser_set_baud_method[tty->index] = method;
- return put_user(method, (int __user *)argp);
- }
default:
return -ENOIOCTLCMD;
}
@@ -1860,7 +1337,7 @@ static void mxser_stoprx(struct tty_struct *tty)
info->ldisc_stop_rx = 1;
if (I_IXOFF(tty)) {
- if (info->board->chip_flag) {
+ if (info->board->must_hwid) {
info->IER &= ~MOXA_MUST_RECV_ISR;
outb(info->IER, info->ioaddr + UART_IER);
} else {
@@ -1896,7 +1373,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
if (info->x_char)
info->x_char = 0;
else {
- if (info->board->chip_flag) {
+ if (info->board->must_hwid) {
info->IER |= MOXA_MUST_RECV_ISR;
outb(info->IER, info->ioaddr + UART_IER);
} else {
@@ -1917,7 +1394,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
/*
* mxser_stop() and mxser_start()
*
- * This routines are called before setting or resetting tty->stopped.
+ * This routines are called before setting or resetting tty->flow.stopped.
* They enable or disable transmitter interrupts, as necessary.
*/
static void mxser_stop(struct tty_struct *tty)
@@ -1926,10 +1403,8 @@ static void mxser_stop(struct tty_struct *tty)
unsigned long flags;
spin_lock_irqsave(&info->slock, flags);
- if (info->IER & UART_IER_THRI) {
- info->IER &= ~UART_IER_THRI;
- outb(info->IER, info->ioaddr + UART_IER);
- }
+ if (info->IER & UART_IER_THRI)
+ __mxser_stop_tx(info);
spin_unlock_irqrestore(&info->slock, flags);
}
@@ -1939,11 +1414,8 @@ static void mxser_start(struct tty_struct *tty)
unsigned long flags;
spin_lock_irqsave(&info->slock, flags);
- if (info->xmit_cnt && info->port.xmit_buf) {
- outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
- info->IER |= UART_IER_THRI;
- outb(info->IER, info->ioaddr + UART_IER);
- }
+ if (info->xmit_cnt && info->port.xmit_buf)
+ __mxser_start_tx(info);
spin_unlock_irqrestore(&info->slock, flags);
}
@@ -1963,12 +1435,11 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
/* Handle sw stopped */
if ((old_termios->c_iflag & IXON) && !I_IXON(tty)) {
- tty->stopped = 0;
+ tty->flow.stopped = 0;
- if (info->board->chip_flag) {
+ if (info->board->must_hwid) {
spin_lock_irqsave(&info->slock, flags);
- mxser_disable_must_rx_software_flow_control(
- info->ioaddr);
+ mxser_must_set_rx_sw_flow_control(info->ioaddr, false);
spin_unlock_irqrestore(&info->slock, flags);
}
@@ -2051,88 +1522,92 @@ static int mxser_rs_break(struct tty_struct *tty, int break_state)
{
struct mxser_port *info = tty->driver_data;
unsigned long flags;
+ u8 lcr;
spin_lock_irqsave(&info->slock, flags);
+ lcr = inb(info->ioaddr + UART_LCR);
if (break_state == -1)
- outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
- info->ioaddr + UART_LCR);
+ lcr |= UART_LCR_SBC;
else
- outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
- info->ioaddr + UART_LCR);
+ lcr &= ~UART_LCR_SBC;
+ outb(lcr, info->ioaddr + UART_LCR);
spin_unlock_irqrestore(&info->slock, flags);
+
return 0;
}
-static void mxser_receive_chars(struct tty_struct *tty,
- struct mxser_port *port, int *status)
+static bool mxser_receive_chars_new(struct tty_struct *tty,
+ struct mxser_port *port, u8 status)
{
- unsigned char ch, gdl;
- int ignored = 0;
- int cnt = 0;
- int recv_room;
- int max = 256;
+ enum mxser_must_hwid hwid = port->board->must_hwid;
+ u8 gdl;
+
+ if (hwid == MOXA_OTHER_UART)
+ return false;
+ if (status & UART_LSR_BRK_ERROR_BITS)
+ return false;
+ if (hwid == MOXA_MUST_MU860_HWID && (status & MOXA_MUST_LSR_RERR))
+ return false;
+ if (status & MOXA_MUST_LSR_RERR)
+ return false;
- recv_room = tty->receive_room;
- if (recv_room == 0 && !port->ldisc_stop_rx)
+ gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER);
+ if (hwid == MOXA_MUST_MU150_HWID)
+ gdl &= MOXA_MUST_GDL_MASK;
+
+ if (gdl >= tty->receive_room && !port->ldisc_stop_rx)
mxser_stoprx(tty);
- if (port->board->chip_flag != MOXA_OTHER_UART) {
-
- if (*status & UART_LSR_SPECIAL)
- goto intr_old;
- if (port->board->chip_flag == MOXA_MUST_MU860_HWID &&
- (*status & MOXA_MUST_LSR_RERR))
- goto intr_old;
- if (*status & MOXA_MUST_LSR_RERR)
- goto intr_old;
-
- gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER);
-
- if (port->board->chip_flag == MOXA_MUST_MU150_HWID)
- gdl &= MOXA_MUST_GDL_MASK;
- if (gdl >= recv_room) {
- if (!port->ldisc_stop_rx)
- mxser_stoprx(tty);
- }
- while (gdl--) {
- ch = inb(port->ioaddr + UART_RX);
- tty_insert_flip_char(&port->port, ch, 0);
- cnt++;
- }
- goto end_intr;
+
+ while (gdl--) {
+ u8 ch = inb(port->ioaddr + UART_RX);
+ tty_insert_flip_char(&port->port, ch, 0);
}
-intr_old:
+
+ return true;
+}
+
+static u8 mxser_receive_chars_old(struct tty_struct *tty,
+ struct mxser_port *port, u8 status)
+{
+ enum mxser_must_hwid hwid = port->board->must_hwid;
+ int recv_room = tty->receive_room;
+ int ignored = 0;
+ int max = 256;
+ int cnt = 0;
+ u8 ch;
do {
if (max-- < 0)
break;
ch = inb(port->ioaddr + UART_RX);
- if (port->board->chip_flag && (*status & UART_LSR_OE))
- outb(0x23, port->ioaddr + UART_FCR);
- *status &= port->read_status_mask;
- if (*status & port->ignore_status_mask) {
+ if (hwid && (status & UART_LSR_OE))
+ outb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
+ MOXA_MUST_FCR_GDA_MODE_ENABLE,
+ port->ioaddr + UART_FCR);
+ status &= port->read_status_mask;
+ if (status & port->ignore_status_mask) {
if (++ignored > 100)
break;
} else {
char flag = 0;
- if (*status & UART_LSR_SPECIAL) {
- if (*status & UART_LSR_BI) {
+ if (status & UART_LSR_BRK_ERROR_BITS) {
+ if (status & UART_LSR_BI) {
flag = TTY_BREAK;
port->icount.brk++;
if (port->port.flags & ASYNC_SAK)
do_SAK(tty);
- } else if (*status & UART_LSR_PE) {
+ } else if (status & UART_LSR_PE) {
flag = TTY_PARITY;
port->icount.parity++;
- } else if (*status & UART_LSR_FE) {
+ } else if (status & UART_LSR_FE) {
flag = TTY_FRAME;
port->icount.frame++;
- } else if (*status & UART_LSR_OE) {
+ } else if (status & UART_LSR_OE) {
flag = TTY_OVERRUN;
port->icount.overrun++;
- } else
- flag = TTY_BREAK;
+ }
}
tty_insert_flip_char(&port->port, ch, flag);
cnt++;
@@ -2144,18 +1619,27 @@ intr_old:
}
- if (port->board->chip_flag)
+ if (hwid)
break;
- *status = inb(port->ioaddr + UART_LSR);
- } while (*status & UART_LSR_DR);
+ status = inb(port->ioaddr + UART_LSR);
+ } while (status & UART_LSR_DR);
+
+ return status;
+}
+
+static u8 mxser_receive_chars(struct tty_struct *tty,
+ struct mxser_port *port, u8 status)
+{
+ if (tty->receive_room == 0 && !port->ldisc_stop_rx)
+ mxser_stoprx(tty);
-end_intr:
- mxvar_log.rxcnt[tty->index] += cnt;
- port->mon_data.rxcnt += cnt;
- port->mon_data.up_rxcnt += cnt;
+ if (!mxser_receive_chars_new(tty, port, status))
+ status = mxser_receive_chars_old(tty, port, status);
tty_flip_buffer_push(&port->port);
+
+ return status;
}
static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port)
@@ -2165,9 +1649,6 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port
if (port->x_char) {
outb(port->x_char, port->ioaddr + UART_TX);
port->x_char = 0;
- mxvar_log.txcnt[tty->index]++;
- port->mon_data.txcnt++;
- port->mon_data.up_txcnt++;
port->icount.tx++;
return;
}
@@ -2175,12 +1656,9 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port
if (port->port.xmit_buf == NULL)
return;
- if (port->xmit_cnt <= 0 || tty->stopped ||
- (tty->hw_stopped &&
- (port->type != PORT_16550A) &&
- (!port->board->chip_flag))) {
- port->IER &= ~UART_IER_THRI;
- outb(port->IER, port->ioaddr + UART_IER);
+ if (!port->xmit_cnt || tty->flow.stopped ||
+ (tty->hw_stopped && !mxser_16550A_or_MUST(port))) {
+ __mxser_stop_tx(port);
return;
}
@@ -2190,22 +1668,72 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port
outb(port->port.xmit_buf[port->xmit_tail++],
port->ioaddr + UART_TX);
port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
- if (--port->xmit_cnt <= 0)
+ if (!--port->xmit_cnt)
break;
} while (--count > 0);
- mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt);
- port->mon_data.txcnt += (cnt - port->xmit_cnt);
- port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
port->icount.tx += (cnt - port->xmit_cnt);
if (port->xmit_cnt < WAKEUP_CHARS)
tty_wakeup(tty);
- if (port->xmit_cnt <= 0) {
- port->IER &= ~UART_IER_THRI;
- outb(port->IER, port->ioaddr + UART_IER);
+ if (!port->xmit_cnt)
+ __mxser_stop_tx(port);
+}
+
+static bool mxser_port_isr(struct mxser_port *port)
+{
+ struct tty_struct *tty;
+ u8 iir, msr, status;
+ bool error = false;
+
+ iir = inb(port->ioaddr + UART_IIR);
+ if (iir & UART_IIR_NO_INT)
+ return true;
+
+ iir &= MOXA_MUST_IIR_MASK;
+ tty = tty_port_tty_get(&port->port);
+ if (!tty || port->closing || !tty_port_initialized(&port->port)) {
+ status = inb(port->ioaddr + UART_LSR);
+ outb(MOXA_MUST_FCR_GDA_MODE_ENABLE | UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+ port->ioaddr + UART_FCR);
+ inb(port->ioaddr + UART_MSR);
+
+ error = true;
+ goto put_tty;
+ }
+
+ status = inb(port->ioaddr + UART_LSR);
+
+ if (port->board->must_hwid) {
+ if (iir == MOXA_MUST_IIR_GDA ||
+ iir == MOXA_MUST_IIR_RDA ||
+ iir == MOXA_MUST_IIR_RTO ||
+ iir == MOXA_MUST_IIR_LSR)
+ status = mxser_receive_chars(tty, port, status);
+ } else {
+ status &= port->read_status_mask;
+ if (status & UART_LSR_DR)
+ status = mxser_receive_chars(tty, port, status);
+ }
+
+ msr = inb(port->ioaddr + UART_MSR);
+ if (msr & UART_MSR_ANY_DELTA)
+ mxser_check_modem_status(tty, port, msr);
+
+ if (port->board->must_hwid) {
+ if (iir == 0x02 && (status & UART_LSR_THRE))
+ mxser_transmit_chars(tty, port);
+ } else {
+ if (status & UART_LSR_THRE)
+ mxser_transmit_chars(tty, port);
}
+
+put_tty:
+ tty_kref_put(tty);
+
+ return error;
}
/*
@@ -2213,33 +1741,21 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port
*/
static irqreturn_t mxser_interrupt(int irq, void *dev_id)
{
- int status, iir, i;
- struct mxser_board *brd = NULL;
+ struct mxser_board *brd = dev_id;
struct mxser_port *port;
- int max, irqbits, bits, msr;
unsigned int int_cnt, pass_counter = 0;
+ unsigned int i, max = brd->nports;
int handled = IRQ_NONE;
- struct tty_struct *tty;
-
- for (i = 0; i < MXSER_BOARDS; i++)
- if (dev_id == &mxser_boards[i]) {
- brd = dev_id;
- break;
- }
+ u8 irqbits, bits, mask = BIT(max) - 1;
- if (i == MXSER_BOARDS)
- goto irq_stop;
- if (brd == NULL)
- goto irq_stop;
- max = brd->info->nports;
while (pass_counter++ < MXSER_ISR_PASS_LIMIT) {
- irqbits = inb(brd->vector) & brd->vector_mask;
- if (irqbits == brd->vector_mask)
+ irqbits = inb(brd->vector) & mask;
+ if (irqbits == mask)
break;
handled = IRQ_HANDLED;
for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
- if (irqbits == brd->vector_mask)
+ if (irqbits == mask)
break;
if (bits & irqbits)
continue;
@@ -2248,65 +1764,13 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
int_cnt = 0;
spin_lock(&port->slock);
do {
- iir = inb(port->ioaddr + UART_IIR);
- if (iir & UART_IIR_NO_INT)
+ if (mxser_port_isr(port))
break;
- iir &= MOXA_MUST_IIR_MASK;
- tty = tty_port_tty_get(&port->port);
- if (!tty || port->closing ||
- !tty_port_initialized(&port->port)) {
- status = inb(port->ioaddr + UART_LSR);
- outb(0x27, port->ioaddr + UART_FCR);
- inb(port->ioaddr + UART_MSR);
- tty_kref_put(tty);
- break;
- }
-
- status = inb(port->ioaddr + UART_LSR);
-
- if (status & UART_LSR_PE)
- port->err_shadow |= NPPI_NOTIFY_PARITY;
- if (status & UART_LSR_FE)
- port->err_shadow |= NPPI_NOTIFY_FRAMING;
- if (status & UART_LSR_OE)
- port->err_shadow |=
- NPPI_NOTIFY_HW_OVERRUN;
- if (status & UART_LSR_BI)
- port->err_shadow |= NPPI_NOTIFY_BREAK;
-
- if (port->board->chip_flag) {
- if (iir == MOXA_MUST_IIR_GDA ||
- iir == MOXA_MUST_IIR_RDA ||
- iir == MOXA_MUST_IIR_RTO ||
- iir == MOXA_MUST_IIR_LSR)
- mxser_receive_chars(tty, port,
- &status);
-
- } else {
- status &= port->read_status_mask;
- if (status & UART_LSR_DR)
- mxser_receive_chars(tty, port,
- &status);
- }
- msr = inb(port->ioaddr + UART_MSR);
- if (msr & UART_MSR_ANY_DELTA)
- mxser_check_modem_status(tty, port, msr);
-
- if (port->board->chip_flag) {
- if (iir == 0x02 && (status &
- UART_LSR_THRE))
- mxser_transmit_chars(tty, port);
- } else {
- if (status & UART_LSR_THRE)
- mxser_transmit_chars(tty, port);
- }
- tty_kref_put(tty);
} while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
spin_unlock(&port->slock);
}
}
-irq_stop:
return handled;
}
@@ -2346,254 +1810,103 @@ static const struct tty_port_operations mxser_port_ops = {
* The MOXA Smartio/Industio serial driver boot-time initialization code!
*/
-static bool allow_overlapping_vector;
-module_param(allow_overlapping_vector, bool, S_IRUGO);
-MODULE_PARM_DESC(allow_overlapping_vector, "whether we allow ISA cards to be configured such that vector overlabs IO ports (default=no)");
-
-static bool mxser_overlapping_vector(struct mxser_board *brd)
-{
- return allow_overlapping_vector &&
- brd->vector >= brd->ports[0].ioaddr &&
- brd->vector < brd->ports[0].ioaddr + 8 * brd->info->nports;
-}
-
-static int mxser_request_vector(struct mxser_board *brd)
+static void mxser_initbrd(struct mxser_board *brd, bool high_baud)
{
- if (mxser_overlapping_vector(brd))
- return 0;
- return request_region(brd->vector, 1, "mxser(vector)") ? 0 : -EIO;
-}
+ struct mxser_port *info;
+ unsigned int i;
+ bool is_mu860;
-static void mxser_release_vector(struct mxser_board *brd)
-{
- if (mxser_overlapping_vector(brd))
- return;
- release_region(brd->vector, 1);
-}
+ brd->must_hwid = mxser_must_get_hwid(brd->ports[0].ioaddr);
+ is_mu860 = brd->must_hwid == MOXA_MUST_MU860_HWID;
-static void mxser_release_ISA_res(struct mxser_board *brd)
-{
- release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
- mxser_release_vector(brd);
-}
+ for (i = 0; i < UART_INFO_NUM; i++) {
+ if (Gpci_uart_info[i].type == brd->must_hwid) {
+ brd->max_baud = Gpci_uart_info[i].max_baud;
-static int mxser_initbrd(struct mxser_board *brd)
-{
- struct mxser_port *info;
- unsigned int i;
- int retval;
+ /* exception....CP-102 */
+ if (high_baud)
+ brd->max_baud = 921600;
+ break;
+ }
+ }
- printk(KERN_INFO "mxser: max. baud rate = %d bps\n",
- brd->ports[0].max_baud);
+ if (is_mu860) {
+ /* set to RS232 mode by default */
+ outb(0, brd->vector + 4);
+ outb(0, brd->vector + 0x0c);
+ }
- for (i = 0; i < brd->info->nports; i++) {
+ for (i = 0; i < brd->nports; i++) {
info = &brd->ports[i];
+ if (is_mu860) {
+ if (i < 4)
+ info->opmode_ioaddr = brd->vector + 4;
+ else
+ info->opmode_ioaddr = brd->vector + 0x0c;
+ }
tty_port_init(&info->port);
info->port.ops = &mxser_port_ops;
info->board = brd;
- info->stop_rx = 0;
info->ldisc_stop_rx = 0;
/* Enhance mode enabled here */
- if (brd->chip_flag != MOXA_OTHER_UART)
- mxser_enable_must_enchance_mode(info->ioaddr);
+ if (brd->must_hwid != MOXA_OTHER_UART)
+ mxser_must_set_enhance_mode(info->ioaddr, true);
- info->type = brd->uart_type;
+ info->type = PORT_16550A;
- process_txrx_fifo(info);
+ mxser_process_txrx_fifo(info);
- info->custom_divisor = info->baud_base * 16;
info->port.close_delay = 5 * HZ / 10;
info->port.closing_wait = 30 * HZ;
- info->normal_termios = mxvar_sdriver->init_termios;
- memset(&info->mon_data, 0, sizeof(struct mxser_mon));
- info->err_shadow = 0;
spin_lock_init(&info->slock);
/* before set INT ISR, disable all int */
outb(inb(info->ioaddr + UART_IER) & 0xf0,
info->ioaddr + UART_IER);
}
-
- retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser",
- brd);
- if (retval) {
- for (i = 0; i < brd->info->nports; i++)
- tty_port_destroy(&brd->ports[i].port);
- printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may "
- "conflict with another device.\n",
- brd->info->name, brd->irq);
- }
-
- return retval;
-}
-
-static void mxser_board_remove(struct mxser_board *brd)
-{
- unsigned int i;
-
- for (i = 0; i < brd->info->nports; i++) {
- tty_unregister_device(mxvar_sdriver, brd->idx + i);
- tty_port_destroy(&brd->ports[i].port);
- }
- free_irq(brd->irq, brd);
-}
-
-static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
-{
- int id, i, bits, ret;
- unsigned short regs[16], irq;
- unsigned char scratch, scratch2;
-
- brd->chip_flag = MOXA_OTHER_UART;
-
- id = mxser_read_register(cap, regs);
- switch (id) {
- case C168_ASIC_ID:
- brd->info = &mxser_cards[0];
- break;
- case C104_ASIC_ID:
- brd->info = &mxser_cards[1];
- break;
- case CI104J_ASIC_ID:
- brd->info = &mxser_cards[2];
- break;
- case C102_ASIC_ID:
- brd->info = &mxser_cards[5];
- break;
- case CI132_ASIC_ID:
- brd->info = &mxser_cards[6];
- break;
- case CI134_ASIC_ID:
- brd->info = &mxser_cards[7];
- break;
- default:
- return 0;
- }
-
- irq = 0;
- /* some ISA cards have 2 ports, but we want to see them as 4-port (why?)
- Flag-hack checks if configuration should be read as 2-port here. */
- if (brd->info->nports == 2 || (brd->info->flags & MXSER_HAS2)) {
- irq = regs[9] & 0xF000;
- irq = irq | (irq >> 4);
- if (irq != (regs[9] & 0xFF00))
- goto err_irqconflict;
- } else if (brd->info->nports == 4) {
- irq = regs[9] & 0xF000;
- irq = irq | (irq >> 4);
- irq = irq | (irq >> 8);
- if (irq != regs[9])
- goto err_irqconflict;
- } else if (brd->info->nports == 8) {
- irq = regs[9] & 0xF000;
- irq = irq | (irq >> 4);
- irq = irq | (irq >> 8);
- if ((irq != regs[9]) || (irq != regs[10]))
- goto err_irqconflict;
- }
-
- if (!irq) {
- printk(KERN_ERR "mxser: interrupt number unset\n");
- return -EIO;
- }
- brd->irq = ((int)(irq & 0xF000) >> 12);
- for (i = 0; i < 8; i++)
- brd->ports[i].ioaddr = (int) regs[i + 1] & 0xFFF8;
- if ((regs[12] & 0x80) == 0) {
- printk(KERN_ERR "mxser: invalid interrupt vector\n");
- return -EIO;
- }
- brd->vector = (int)regs[11]; /* interrupt vector */
- if (id == 1)
- brd->vector_mask = 0x00FF;
- else
- brd->vector_mask = 0x000F;
- for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
- if (regs[12] & bits) {
- brd->ports[i].baud_base = 921600;
- brd->ports[i].max_baud = 921600;
- } else {
- brd->ports[i].baud_base = 115200;
- brd->ports[i].max_baud = 115200;
- }
- }
- scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
- outb(scratch2 | UART_LCR_DLAB, cap + UART_LCR);
- outb(0, cap + UART_EFR); /* EFR is the same as FCR */
- outb(scratch2, cap + UART_LCR);
- outb(UART_FCR_ENABLE_FIFO, cap + UART_FCR);
- scratch = inb(cap + UART_IIR);
-
- if (scratch & 0xC0)
- brd->uart_type = PORT_16550A;
- else
- brd->uart_type = PORT_16450;
- if (!request_region(brd->ports[0].ioaddr, 8 * brd->info->nports,
- "mxser(IO)")) {
- printk(KERN_ERR "mxser: can't request ports I/O region: "
- "0x%.8lx-0x%.8lx\n",
- brd->ports[0].ioaddr, brd->ports[0].ioaddr +
- 8 * brd->info->nports - 1);
- return -EIO;
- }
-
- ret = mxser_request_vector(brd);
- if (ret) {
- release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
- printk(KERN_ERR "mxser: can't request interrupt vector region: "
- "0x%.8lx-0x%.8lx\n",
- brd->ports[0].ioaddr, brd->ports[0].ioaddr +
- 8 * brd->info->nports - 1);
- return ret;
- }
- return brd->info->nports;
-
-err_irqconflict:
- printk(KERN_ERR "mxser: invalid interrupt number\n");
- return -EIO;
}
static int mxser_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
-#ifdef CONFIG_PCI
struct mxser_board *brd;
- unsigned int i, j;
+ unsigned int i, base;
unsigned long ioaddress;
+ unsigned short nports = MXSER_NPORTS(ent->driver_data);
struct device *tty_dev;
int retval = -EINVAL;
- for (i = 0; i < MXSER_BOARDS; i++)
- if (mxser_boards[i].info == NULL)
- break;
-
+ i = find_first_zero_bit(mxser_boards, MXSER_BOARDS);
if (i >= MXSER_BOARDS) {
dev_err(&pdev->dev, "too many boards found (maximum %d), board "
"not configured\n", MXSER_BOARDS);
goto err;
}
- brd = &mxser_boards[i];
- brd->idx = i * MXSER_PORTS_PER_BOARD;
- dev_info(&pdev->dev, "found MOXA %s board (BusNo=%d, DevNo=%d)\n",
- mxser_cards[ent->driver_data].name,
- pdev->bus->number, PCI_SLOT(pdev->devfn));
+ brd = devm_kzalloc(&pdev->dev, struct_size(brd, ports, nports),
+ GFP_KERNEL);
+ if (!brd)
+ goto err;
+
+ brd->idx = i;
+ __set_bit(brd->idx, mxser_boards);
+ base = i * MXSER_PORTS_PER_BOARD;
- retval = pci_enable_device(pdev);
+ retval = pcim_enable_device(pdev);
if (retval) {
dev_err(&pdev->dev, "PCI enable failed\n");
- goto err;
+ goto err_zero;
}
/* io address */
ioaddress = pci_resource_start(pdev, 2);
retval = pci_request_region(pdev, 2, "mxser(IO)");
if (retval)
- goto err_dis;
+ goto err_zero;
- brd->info = &mxser_cards[ent->driver_data];
- for (i = 0; i < brd->info->nports; i++)
+ brd->nports = nports;
+ for (i = 0; i < nports; i++)
brd->ports[i].ioaddr = ioaddress + 8 * i;
/* vector */
@@ -2606,53 +1919,23 @@ static int mxser_probe(struct pci_dev *pdev,
/* irq */
brd->irq = pdev->irq;
- brd->chip_flag = CheckIsMoxaMust(brd->ports[0].ioaddr);
- brd->uart_type = PORT_16550A;
- brd->vector_mask = 0;
-
- for (i = 0; i < brd->info->nports; i++) {
- for (j = 0; j < UART_INFO_NUM; j++) {
- if (Gpci_uart_info[j].type == brd->chip_flag) {
- brd->ports[i].max_baud =
- Gpci_uart_info[j].max_baud;
-
- /* exception....CP-102 */
- if (brd->info->flags & MXSER_HIGHBAUD)
- brd->ports[i].max_baud = 921600;
- break;
- }
- }
- }
-
- if (brd->chip_flag == MOXA_MUST_MU860_HWID) {
- for (i = 0; i < brd->info->nports; i++) {
- if (i < 4)
- brd->ports[i].opmode_ioaddr = ioaddress + 4;
- else
- brd->ports[i].opmode_ioaddr = ioaddress + 0x0c;
- }
- outb(0, ioaddress + 4); /* default set to RS232 mode */
- outb(0, ioaddress + 0x0c); /* default set to RS232 mode */
- }
+ mxser_initbrd(brd, ent->driver_data & MXSER_HIGHBAUD);
- for (i = 0; i < brd->info->nports; i++) {
- brd->vector_mask |= (1 << i);
- brd->ports[i].baud_base = 921600;
+ retval = devm_request_irq(&pdev->dev, brd->irq, mxser_interrupt,
+ IRQF_SHARED, "mxser", brd);
+ if (retval) {
+ dev_err(&pdev->dev, "request irq failed");
+ goto err_relbrd;
}
- /* mxser_initbrd will hook ISR. */
- retval = mxser_initbrd(brd);
- if (retval)
- goto err_rel3;
-
- for (i = 0; i < brd->info->nports; i++) {
+ for (i = 0; i < nports; i++) {
tty_dev = tty_port_register_device(&brd->ports[i].port,
- mxvar_sdriver, brd->idx + i, &pdev->dev);
+ mxvar_sdriver, base + i, &pdev->dev);
if (IS_ERR(tty_dev)) {
retval = PTR_ERR(tty_dev);
for (; i > 0; i--)
tty_unregister_device(mxvar_sdriver,
- brd->idx + i - 1);
+ base + i - 1);
goto err_relbrd;
}
}
@@ -2661,35 +1944,25 @@ static int mxser_probe(struct pci_dev *pdev,
return 0;
err_relbrd:
- for (i = 0; i < brd->info->nports; i++)
+ for (i = 0; i < nports; i++)
tty_port_destroy(&brd->ports[i].port);
- free_irq(brd->irq, brd);
-err_rel3:
- pci_release_region(pdev, 3);
err_zero:
- brd->info = NULL;
- pci_release_region(pdev, 2);
-err_dis:
- pci_disable_device(pdev);
+ __clear_bit(brd->idx, mxser_boards);
err:
return retval;
-#else
- return -ENODEV;
-#endif
}
static void mxser_remove(struct pci_dev *pdev)
{
-#ifdef CONFIG_PCI
struct mxser_board *brd = pci_get_drvdata(pdev);
+ unsigned int i, base = brd->idx * MXSER_PORTS_PER_BOARD;
- mxser_board_remove(brd);
+ for (i = 0; i < brd->nports; i++) {
+ tty_unregister_device(mxvar_sdriver, base + i);
+ tty_port_destroy(&brd->ports[i].port);
+ }
- pci_release_region(pdev, 2);
- pci_release_region(pdev, 3);
- pci_disable_device(pdev);
- brd->info = NULL;
-#endif
+ __clear_bit(brd->idx, mxser_boards);
}
static struct pci_driver mxser_driver = {
@@ -2701,18 +1974,12 @@ static struct pci_driver mxser_driver = {
static int __init mxser_module_init(void)
{
- struct mxser_board *brd;
- struct device *tty_dev;
- unsigned int b, i, m;
int retval;
- mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);
+ mxvar_sdriver = alloc_tty_driver(MXSER_PORTS);
if (!mxvar_sdriver)
return -ENOMEM;
- printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
- MXSER_VERSION);
-
/* Initialize the tty_driver structure */
mxvar_sdriver->name = "ttyMI";
mxvar_sdriver->major = ttymajor;
@@ -2731,57 +1998,10 @@ static int __init mxser_module_init(void)
goto err_put;
}
- /* Start finding ISA boards here */
- for (m = 0, b = 0; b < MXSER_BOARDS; b++) {
- if (!ioaddr[b])
- continue;
-
- brd = &mxser_boards[m];
- retval = mxser_get_ISA_conf(ioaddr[b], brd);
- if (retval <= 0) {
- brd->info = NULL;
- continue;
- }
-
- printk(KERN_INFO "mxser: found MOXA %s board (CAP=0x%lx)\n",
- brd->info->name, ioaddr[b]);
-
- /* mxser_initbrd will hook ISR. */
- if (mxser_initbrd(brd) < 0) {
- mxser_release_ISA_res(brd);
- brd->info = NULL;
- continue;
- }
-
- brd->idx = m * MXSER_PORTS_PER_BOARD;
- for (i = 0; i < brd->info->nports; i++) {
- tty_dev = tty_port_register_device(&brd->ports[i].port,
- mxvar_sdriver, brd->idx + i, NULL);
- if (IS_ERR(tty_dev)) {
- for (; i > 0; i--)
- tty_unregister_device(mxvar_sdriver,
- brd->idx + i - 1);
- for (i = 0; i < brd->info->nports; i++)
- tty_port_destroy(&brd->ports[i].port);
- free_irq(brd->irq, brd);
- mxser_release_ISA_res(brd);
- brd->info = NULL;
- break;
- }
- }
- if (brd->info == NULL)
- continue;
-
- m++;
- }
-
retval = pci_register_driver(&mxser_driver);
if (retval) {
printk(KERN_ERR "mxser: can't register pci driver\n");
- if (!m) {
- retval = -ENODEV;
- goto err_unr;
- } /* else: we have some ISA cards under control */
+ goto err_unr;
}
return 0;
@@ -2794,19 +2014,9 @@ err_put:
static void __exit mxser_module_exit(void)
{
- unsigned int i;
-
pci_unregister_driver(&mxser_driver);
-
- for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
- if (mxser_boards[i].info != NULL)
- mxser_board_remove(&mxser_boards[i]);
tty_unregister_driver(mxvar_sdriver);
put_tty_driver(mxvar_sdriver);
-
- for (i = 0; i < MXSER_BOARDS; i++)
- if (mxser_boards[i].info != NULL)
- mxser_release_ISA_res(&mxser_boards[i]);
}
module_init(mxser_module_init);
diff --git a/drivers/tty/mxser.h b/drivers/tty/mxser.h
deleted file mode 100644
index e6cb15626567..000000000000
--- a/drivers/tty/mxser.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _MXSER_H
-#define _MXSER_H
-
-/*
- * Semi-public control interfaces
- */
-
-/*
- * MOXA ioctls
- */
-
-#define MOXA 0x400
-#define MOXA_GETDATACOUNT (MOXA + 23)
-#define MOXA_DIAGNOSE (MOXA + 50)
-#define MOXA_CHKPORTENABLE (MOXA + 60)
-#define MOXA_HighSpeedOn (MOXA + 61)
-#define MOXA_GET_MAJOR (MOXA + 63)
-#define MOXA_GETMSTATUS (MOXA + 65)
-#define MOXA_SET_OP_MODE (MOXA + 66)
-#define MOXA_GET_OP_MODE (MOXA + 67)
-
-#define RS232_MODE 0
-#define RS485_2WIRE_MODE 1
-#define RS422_MODE 2
-#define RS485_4WIRE_MODE 3
-#define OP_MODE_MASK 3
-
-#define MOXA_SDS_RSTICOUNTER (MOXA + 69)
-#define MOXA_ASPP_OQUEUE (MOXA + 70)
-#define MOXA_ASPP_MON (MOXA + 73)
-#define MOXA_ASPP_LSTATUS (MOXA + 74)
-#define MOXA_ASPP_MON_EXT (MOXA + 75)
-#define MOXA_SET_BAUD_METHOD (MOXA + 76)
-
-/* --------------------------------------------------- */
-
-#define NPPI_NOTIFY_PARITY 0x01
-#define NPPI_NOTIFY_FRAMING 0x02
-#define NPPI_NOTIFY_HW_OVERRUN 0x04
-#define NPPI_NOTIFY_SW_OVERRUN 0x08
-#define NPPI_NOTIFY_BREAK 0x10
-
-#define NPPI_NOTIFY_CTSHOLD 0x01 /* Tx hold by CTS low */
-#define NPPI_NOTIFY_DSRHOLD 0x02 /* Tx hold by DSR low */
-#define NPPI_NOTIFY_XOFFHOLD 0x08 /* Tx hold by Xoff received */
-#define NPPI_NOTIFY_XOFFXENT 0x10 /* Xoff Sent */
-
-/* follow just for Moxa Must chip define. */
-/* */
-/* when LCR register (offset 0x03) write following value, */
-/* the Must chip will enter enchance mode. And write value */
-/* on EFR (offset 0x02) bit 6,7 to change bank. */
-#define MOXA_MUST_ENTER_ENCHANCE 0xBF
-
-/* when enhance mode enable, access on general bank register */
-#define MOXA_MUST_GDL_REGISTER 0x07
-#define MOXA_MUST_GDL_MASK 0x7F
-#define MOXA_MUST_GDL_HAS_BAD_DATA 0x80
-
-#define MOXA_MUST_LSR_RERR 0x80 /* error in receive FIFO */
-/* enchance register bank select and enchance mode setting register */
-/* when LCR register equal to 0xBF */
-#define MOXA_MUST_EFR_REGISTER 0x02
-/* enchance mode enable */
-#define MOXA_MUST_EFR_EFRB_ENABLE 0x10
-/* enchance reister bank set 0, 1, 2 */
-#define MOXA_MUST_EFR_BANK0 0x00
-#define MOXA_MUST_EFR_BANK1 0x40
-#define MOXA_MUST_EFR_BANK2 0x80
-#define MOXA_MUST_EFR_BANK3 0xC0
-#define MOXA_MUST_EFR_BANK_MASK 0xC0
-
-/* set XON1 value register, when LCR=0xBF and change to bank0 */
-#define MOXA_MUST_XON1_REGISTER 0x04
-
-/* set XON2 value register, when LCR=0xBF and change to bank0 */
-#define MOXA_MUST_XON2_REGISTER 0x05
-
-/* set XOFF1 value register, when LCR=0xBF and change to bank0 */
-#define MOXA_MUST_XOFF1_REGISTER 0x06
-
-/* set XOFF2 value register, when LCR=0xBF and change to bank0 */
-#define MOXA_MUST_XOFF2_REGISTER 0x07
-
-#define MOXA_MUST_RBRTL_REGISTER 0x04
-#define MOXA_MUST_RBRTH_REGISTER 0x05
-#define MOXA_MUST_RBRTI_REGISTER 0x06
-#define MOXA_MUST_THRTL_REGISTER 0x07
-#define MOXA_MUST_ENUM_REGISTER 0x04
-#define MOXA_MUST_HWID_REGISTER 0x05
-#define MOXA_MUST_ECR_REGISTER 0x06
-#define MOXA_MUST_CSR_REGISTER 0x07
-
-/* good data mode enable */
-#define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20
-/* only good data put into RxFIFO */
-#define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10
-
-/* enable CTS interrupt */
-#define MOXA_MUST_IER_ECTSI 0x80
-/* enable RTS interrupt */
-#define MOXA_MUST_IER_ERTSI 0x40
-/* enable Xon/Xoff interrupt */
-#define MOXA_MUST_IER_XINT 0x20
-/* enable GDA interrupt */
-#define MOXA_MUST_IER_EGDAI 0x10
-
-#define MOXA_MUST_RECV_ISR (UART_IER_RDI | MOXA_MUST_IER_EGDAI)
-
-/* GDA interrupt pending */
-#define MOXA_MUST_IIR_GDA 0x1C
-#define MOXA_MUST_IIR_RDA 0x04
-#define MOXA_MUST_IIR_RTO 0x0C
-#define MOXA_MUST_IIR_LSR 0x06
-
-/* received Xon/Xoff or specical interrupt pending */
-#define MOXA_MUST_IIR_XSC 0x10
-
-/* RTS/CTS change state interrupt pending */
-#define MOXA_MUST_IIR_RTSCTS 0x20
-#define MOXA_MUST_IIR_MASK 0x3E
-
-#define MOXA_MUST_MCR_XON_FLAG 0x40
-#define MOXA_MUST_MCR_XON_ANY 0x80
-#define MOXA_MUST_MCR_TX_XON 0x08
-
-/* software flow control on chip mask value */
-#define MOXA_MUST_EFR_SF_MASK 0x0F
-/* send Xon1/Xoff1 */
-#define MOXA_MUST_EFR_SF_TX1 0x08
-/* send Xon2/Xoff2 */
-#define MOXA_MUST_EFR_SF_TX2 0x04
-/* send Xon1,Xon2/Xoff1,Xoff2 */
-#define MOXA_MUST_EFR_SF_TX12 0x0C
-/* don't send Xon/Xoff */
-#define MOXA_MUST_EFR_SF_TX_NO 0x00
-/* Tx software flow control mask */
-#define MOXA_MUST_EFR_SF_TX_MASK 0x0C
-/* don't receive Xon/Xoff */
-#define MOXA_MUST_EFR_SF_RX_NO 0x00
-/* receive Xon1/Xoff1 */
-#define MOXA_MUST_EFR_SF_RX1 0x02
-/* receive Xon2/Xoff2 */
-#define MOXA_MUST_EFR_SF_RX2 0x01
-/* receive Xon1,Xon2/Xoff1,Xoff2 */
-#define MOXA_MUST_EFR_SF_RX12 0x03
-/* Rx software flow control mask */
-#define MOXA_MUST_EFR_SF_RX_MASK 0x03
-
-#endif
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 5fea02cfb0cc..e907b7a5cab5 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -512,7 +512,7 @@ static void gsm_print_packet(const char *hdr, int addr, int cr,
*/
/**
- * gsm_stuff_packet - bytestuff a packet
+ * gsm_stuff_frame - bytestuff a packet
* @input: input buffer
* @output: output buffer
* @len: length of input
@@ -1594,7 +1594,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen)
}
/**
- * gsm_dlci_control - data arrived on control channel
+ * gsm_dlci_command - data arrived on control channel
* @dlci: channel
* @data: block of bytes received
* @len: length of received block
@@ -2424,7 +2424,7 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
}
static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
struct gsm_mux *gsm = tty->disc_data;
char flags = TTY_NORMAL;
@@ -2557,6 +2557,8 @@ static void gsmld_write_wakeup(struct tty_struct *tty)
* @file: file object
* @buf: userspace buffer pointer
* @nr: size of I/O
+ * @cookie: unused
+ * @offset: unused
*
* Perform reads for the line discipline. We are guaranteed that the
* line discipline will not be closed under us but we may get multiple
@@ -2857,6 +2859,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc)
/* Line discipline for real tty */
static struct tty_ldisc_ops tty_ldisc_packet = {
.owner = THIS_MODULE,
+ .num = N_GSM0710,
.name = "n_gsm",
.open = gsmld_open,
.close = gsmld_close,
@@ -3055,7 +3058,7 @@ static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
return sent;
}
-static int gsmtty_write_room(struct tty_struct *tty)
+static unsigned int gsmtty_write_room(struct tty_struct *tty)
{
struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
@@ -3063,7 +3066,7 @@ static int gsmtty_write_room(struct tty_struct *tty)
return TX_SIZE - kfifo_len(&dlci->fifo);
}
-static int gsmtty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int gsmtty_chars_in_buffer(struct tty_struct *tty)
{
struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
@@ -3242,7 +3245,7 @@ static const struct tty_operations gsmtty_ops = {
static int __init gsm_init(void)
{
/* Fill in our line protocol discipline, and register it */
- int status = tty_register_ldisc(N_GSM0710, &tty_ldisc_packet);
+ int status = tty_register_ldisc(&tty_ldisc_packet);
if (status != 0) {
pr_err("n_gsm: can't register line discipline (err = %d)\n",
status);
@@ -3251,9 +3254,9 @@ static int __init gsm_init(void)
gsm_tty_driver = alloc_tty_driver(256);
if (!gsm_tty_driver) {
- tty_unregister_ldisc(N_GSM0710);
pr_err("gsm_init: tty allocation failed.\n");
- return -EINVAL;
+ status = -ENOMEM;
+ goto err_unreg_ldisc;
}
gsm_tty_driver->driver_name = "gsmtty";
gsm_tty_driver->name = "gsmtty";
@@ -3269,22 +3272,23 @@ static int __init gsm_init(void)
tty_set_operations(gsm_tty_driver, &gsmtty_ops);
if (tty_register_driver(gsm_tty_driver)) {
- put_tty_driver(gsm_tty_driver);
- tty_unregister_ldisc(N_GSM0710);
pr_err("gsm_init: tty registration failed.\n");
- return -EBUSY;
+ status = -EBUSY;
+ goto err_put_driver;
}
pr_debug("gsm_init: loaded as %d,%d.\n",
gsm_tty_driver->major, gsm_tty_driver->minor_start);
return 0;
+err_put_driver:
+ put_tty_driver(gsm_tty_driver);
+err_unreg_ldisc:
+ tty_unregister_ldisc(&tty_ldisc_packet);
+ return status;
}
static void __exit gsm_exit(void)
{
- int status = tty_unregister_ldisc(N_GSM0710);
- if (status != 0)
- pr_err("n_gsm: can't unregister line discipline (err = %d)\n",
- status);
+ tty_unregister_ldisc(&tty_ldisc_packet);
tty_unregister_driver(gsm_tty_driver);
put_tty_driver(gsm_tty_driver);
}
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index b0f33e8ac819..580a37b3fe1b 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -358,7 +358,7 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty)
* interpreted as one HDLC frame.
*/
static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
- char *flags, int count)
+ const char *flags, int count)
{
register struct n_hdlc *n_hdlc = tty->disc_data;
register struct n_hdlc_buf *buf;
@@ -411,8 +411,10 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
* n_hdlc_tty_read - Called to retrieve one frame of data (if available)
* @tty: pointer to tty instance data
* @file: pointer to open file object
- * @buf: pointer to returned data buffer
+ * @kbuf: pointer to returned data buffer
* @nr: size of returned data buffer
+ * @cookie: stored rbuf from previous run
+ * @offset: offset into the data buffer
*
* Returns the number of bytes returned or error code.
*/
@@ -788,6 +790,7 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list)
static struct tty_ldisc_ops n_hdlc_ldisc = {
.owner = THIS_MODULE,
+ .num = N_HDLC,
.name = "hdlc",
.open = n_hdlc_tty_open,
.close = n_hdlc_tty_close,
@@ -807,7 +810,7 @@ static int __init n_hdlc_init(void)
/* range check maxframe arg */
maxframe = clamp(maxframe, 4096, MAX_HDLC_FRAME_SIZE);
- status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc);
+ status = tty_register_ldisc(&n_hdlc_ldisc);
if (!status)
pr_info("N_HDLC line discipline registered with maxframe=%d\n",
maxframe);
@@ -821,14 +824,7 @@ static int __init n_hdlc_init(void)
static void __exit n_hdlc_exit(void)
{
- /* Release tty registration of line discipline */
- int status = tty_unregister_ldisc(N_HDLC);
-
- if (status)
- pr_err("N_HDLC: can't unregister line discipline (err = %d)\n",
- status);
- else
- pr_info("N_HDLC: line discipline unregistered\n");
+ tty_unregister_ldisc(&n_hdlc_ldisc);
}
module_init(n_hdlc_init);
diff --git a/drivers/tty/n_null.c b/drivers/tty/n_null.c
index b8f67b5f1ef8..f913b665af72 100644
--- a/drivers/tty/n_null.c
+++ b/drivers/tty/n_null.c
@@ -33,13 +33,14 @@ static ssize_t n_null_write(struct tty_struct *tty, struct file *file,
}
static void n_null_receivebuf(struct tty_struct *tty,
- const unsigned char *cp, char *fp,
+ const unsigned char *cp, const char *fp,
int cnt)
{
}
static struct tty_ldisc_ops null_ldisc = {
.owner = THIS_MODULE,
+ .num = N_NULL,
.name = "n_null",
.open = n_null_open,
.close = n_null_close,
@@ -50,13 +51,13 @@ static struct tty_ldisc_ops null_ldisc = {
static int __init n_null_init(void)
{
- BUG_ON(tty_register_ldisc(N_NULL, &null_ldisc));
+ BUG_ON(tty_register_ldisc(&null_ldisc));
return 0;
}
static void __exit n_null_exit(void)
{
- tty_unregister_ldisc(N_NULL);
+ tty_unregister_ldisc(&null_ldisc);
}
module_init(n_null_init);
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c
deleted file mode 100644
index 2eb76ea1d88d..000000000000
--- a/drivers/tty/n_r3964.c
+++ /dev/null
@@ -1,1283 +0,0 @@
-// SPDX-License-Identifier: GPL-1.0+
-/* r3964 linediscipline for linux
- *
- * -----------------------------------------------------------
- * Copyright by
- * Philips Automation Projects
- * Kassel (Germany)
- * -----------------------------------------------------------
- * Author:
- * L. Haag
- *
- * $Log: n_r3964.c,v $
- * Revision 1.10 2001/03/18 13:02:24 dwmw2
- * Fix timer usage, use spinlocks properly.
- *
- * Revision 1.9 2001/03/18 12:52:14 dwmw2
- * Merge changes in 2.4.2
- *
- * Revision 1.8 2000/03/23 14:14:54 dwmw2
- * Fix race in sleeping in r3964_read()
- *
- * Revision 1.7 1999/28/08 11:41:50 dwmw2
- * Port to 2.3 kernel
- *
- * Revision 1.6 1998/09/30 00:40:40 dwmw2
- * Fixed compilation on 2.0.x kernels
- * Updated to newly registered tty-ldisc number 9
- *
- * Revision 1.5 1998/09/04 21:57:36 dwmw2
- * Signal handling bug fixes, port to 2.1.x.
- *
- * Revision 1.4 1998/04/02 20:26:59 lhaag
- * select, blocking, ...
- *
- * Revision 1.3 1998/02/12 18:58:43 root
- * fixed some memory leaks
- * calculation of checksum characters
- *
- * Revision 1.2 1998/02/07 13:03:34 root
- * ioctl read_telegram
- *
- * Revision 1.1 1998/02/06 19:21:03 root
- * Initial revision
- *
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.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/ioctl.h>
-#include <linux/n_r3964.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/uaccess.h>
-
-/*#define DEBUG_QUEUE*/
-
-/* Log successful handshake and protocol operations */
-/*#define DEBUG_PROTO_S*/
-
-/* Log handshake and protocol errors: */
-/*#define DEBUG_PROTO_E*/
-
-/* Log Linediscipline operations (open, close, read, write...): */
-/*#define DEBUG_LDISC*/
-
-/* Log module and memory operations (init, cleanup; kmalloc, kfree): */
-/*#define DEBUG_MODUL*/
-
-/* Macro helpers for debug output: */
-#define TRACE(format, args...) printk("r3964: " format "\n" , ## args)
-
-#ifdef DEBUG_MODUL
-#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_M(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_PROTO_S
-#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_PS(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_PROTO_E
-#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_PE(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_LDISC
-#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_L(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_QUEUE
-#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_Q(fmt, arg...) do {} while (0)
-#endif
-static void add_tx_queue(struct r3964_info *, struct r3964_block_header *);
-static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code);
-static void put_char(struct r3964_info *pInfo, unsigned char ch);
-static void trigger_transmit(struct r3964_info *pInfo);
-static void retry_transmit(struct r3964_info *pInfo);
-static void transmit_block(struct r3964_info *pInfo);
-static void receive_char(struct r3964_info *pInfo, const unsigned char c);
-static void receive_error(struct r3964_info *pInfo, const char flag);
-static void on_timeout(struct timer_list *t);
-static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg);
-static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
- unsigned char __user * buf);
-static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
- int error_code, struct r3964_block_header *pBlock);
-static struct r3964_message *remove_msg(struct r3964_info *pInfo,
- struct r3964_client_info *pClient);
-static void remove_client_block(struct r3964_info *pInfo,
- struct r3964_client_info *pClient);
-
-static int r3964_open(struct tty_struct *tty);
-static void r3964_close(struct tty_struct *tty);
-static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
- void *cookie, unsigned char *buf, size_t nr);
-static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
- const unsigned char *buf, size_t nr);
-static int r3964_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg);
-#ifdef CONFIG_COMPAT
-static int r3964_compat_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg);
-#endif
-static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
-static __poll_t r3964_poll(struct tty_struct *tty, struct file *file,
- struct poll_table_struct *wait);
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count);
-
-static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
- .owner = THIS_MODULE,
- .name = "R3964",
- .open = r3964_open,
- .close = r3964_close,
- .read = r3964_read,
- .write = r3964_write,
- .ioctl = r3964_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = r3964_compat_ioctl,
-#endif
- .set_termios = r3964_set_termios,
- .poll = r3964_poll,
- .receive_buf = r3964_receive_buf,
-};
-
-static void dump_block(const unsigned char *block, unsigned int length)
-{
- unsigned int i, j;
- char linebuf[16 * 3 + 1];
-
- for (i = 0; i < length; i += 16) {
- for (j = 0; (j < 16) && (j + i < length); j++) {
- sprintf(linebuf + 3 * j, "%02x ", block[i + j]);
- }
- linebuf[3 * j] = '\0';
- TRACE_PS("%s", linebuf);
- }
-}
-
-/*************************************************************
- * Driver initialisation
- *************************************************************/
-
-/*************************************************************
- * Module support routines
- *************************************************************/
-
-static void __exit r3964_exit(void)
-{
- int status;
-
- TRACE_M("cleanup_module()");
-
- status = tty_unregister_ldisc(N_R3964);
-
- if (status != 0) {
- printk(KERN_ERR "r3964: error unregistering linediscipline: "
- "%d\n", status);
- } else {
- TRACE_L("linediscipline successfully unregistered");
- }
-}
-
-static int __init r3964_init(void)
-{
- int status;
-
- printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n");
-
- /*
- * Register the tty line discipline
- */
-
- status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964);
- if (status == 0) {
- TRACE_L("line discipline %d registered", N_R3964);
- TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags,
- tty_ldisc_N_R3964.num);
- TRACE_L("open=%p", tty_ldisc_N_R3964.open);
- TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964);
- } else {
- printk(KERN_ERR "r3964: error registering line discipline: "
- "%d\n", status);
- }
- return status;
-}
-
-module_init(r3964_init);
-module_exit(r3964_exit);
-
-/*************************************************************
- * Protocol implementation routines
- *************************************************************/
-
-static void add_tx_queue(struct r3964_info *pInfo,
- struct r3964_block_header *pHeader)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&pInfo->lock, flags);
-
- pHeader->next = NULL;
-
- if (pInfo->tx_last == NULL) {
- pInfo->tx_first = pInfo->tx_last = pHeader;
- } else {
- pInfo->tx_last->next = pHeader;
- pInfo->tx_last = pHeader;
- }
-
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- TRACE_Q("add_tx_queue %p, length %d, tx_first = %p",
- pHeader, pHeader->length, pInfo->tx_first);
-}
-
-static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
-{
- struct r3964_block_header *pHeader;
- unsigned long flags;
-#ifdef DEBUG_QUEUE
- struct r3964_block_header *pDump;
-#endif
-
- pHeader = pInfo->tx_first;
-
- if (pHeader == NULL)
- return;
-
-#ifdef DEBUG_QUEUE
- printk("r3964: remove_from_tx_queue: %p, length %u - ",
- pHeader, pHeader->length);
- for (pDump = pHeader; pDump; pDump = pDump->next)
- printk("%p ", pDump);
- printk("\n");
-#endif
-
- if (pHeader->owner) {
- if (error_code) {
- add_msg(pHeader->owner, R3964_MSG_ACK, 0,
- error_code, NULL);
- } else {
- add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
- error_code, NULL);
- }
- wake_up_interruptible(&pInfo->tty->read_wait);
- }
-
- spin_lock_irqsave(&pInfo->lock, flags);
-
- pInfo->tx_first = pHeader->next;
- if (pInfo->tx_first == NULL) {
- pInfo->tx_last = NULL;
- }
-
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- kfree(pHeader);
- TRACE_M("remove_from_tx_queue - kfree %p", pHeader);
-
- TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p",
- pInfo->tx_first, pInfo->tx_last);
-}
-
-static void add_rx_queue(struct r3964_info *pInfo,
- struct r3964_block_header *pHeader)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&pInfo->lock, flags);
-
- pHeader->next = NULL;
-
- if (pInfo->rx_last == NULL) {
- pInfo->rx_first = pInfo->rx_last = pHeader;
- } else {
- pInfo->rx_last->next = pHeader;
- pInfo->rx_last = pHeader;
- }
- pInfo->blocks_in_rx_queue++;
-
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d",
- pHeader, pHeader->length,
- pInfo->rx_first, pInfo->blocks_in_rx_queue);
-}
-
-static void remove_from_rx_queue(struct r3964_info *pInfo,
- struct r3964_block_header *pHeader)
-{
- unsigned long flags;
- struct r3964_block_header *pFind;
-
- if (pHeader == NULL)
- return;
-
- TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
- pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
- TRACE_Q("remove_from_rx_queue: %p, length %u",
- pHeader, pHeader->length);
-
- spin_lock_irqsave(&pInfo->lock, flags);
-
- if (pInfo->rx_first == pHeader) {
- /* Remove the first block in the linked list: */
- pInfo->rx_first = pHeader->next;
-
- if (pInfo->rx_first == NULL) {
- pInfo->rx_last = NULL;
- }
- pInfo->blocks_in_rx_queue--;
- } else {
- /* Find block to remove: */
- for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) {
- if (pFind->next == pHeader) {
- /* Got it. */
- pFind->next = pHeader->next;
- pInfo->blocks_in_rx_queue--;
- if (pFind->next == NULL) {
- /* Oh, removed the last one! */
- pInfo->rx_last = pFind;
- }
- break;
- }
- }
- }
-
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- kfree(pHeader);
- TRACE_M("remove_from_rx_queue - kfree %p", pHeader);
-
- TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
- pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
-}
-
-static void put_char(struct r3964_info *pInfo, unsigned char ch)
-{
- struct tty_struct *tty = pInfo->tty;
- /* FIXME: put_char should not be called from an IRQ */
- tty_put_char(tty, ch);
- pInfo->bcc ^= ch;
-}
-
-static void flush(struct r3964_info *pInfo)
-{
- struct tty_struct *tty = pInfo->tty;
-
- if (tty == NULL || tty->ops->flush_chars == NULL)
- return;
- tty->ops->flush_chars(tty);
-}
-
-static void trigger_transmit(struct r3964_info *pInfo)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&pInfo->lock, flags);
-
- if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) {
- pInfo->state = R3964_TX_REQUEST;
- pInfo->nRetry = 0;
- pInfo->flags &= ~R3964_ERROR;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
-
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- TRACE_PS("trigger_transmit - sent STX");
-
- put_char(pInfo, STX);
- flush(pInfo);
-
- pInfo->bcc = 0;
- } else {
- spin_unlock_irqrestore(&pInfo->lock, flags);
- }
-}
-
-static void retry_transmit(struct r3964_info *pInfo)
-{
- if (pInfo->nRetry < R3964_MAX_RETRIES) {
- TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry);
- pInfo->bcc = 0;
- put_char(pInfo, STX);
- flush(pInfo);
- pInfo->state = R3964_TX_REQUEST;
- pInfo->nRetry++;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
- } else {
- TRACE_PE("transmission failed after %d retries",
- R3964_MAX_RETRIES);
-
- remove_from_tx_queue(pInfo, R3964_TX_FAIL);
-
- put_char(pInfo, NAK);
- flush(pInfo);
- pInfo->state = R3964_IDLE;
-
- trigger_transmit(pInfo);
- }
-}
-
-static void transmit_block(struct r3964_info *pInfo)
-{
- struct tty_struct *tty = pInfo->tty;
- struct r3964_block_header *pBlock = pInfo->tx_first;
- int room = 0;
-
- if (tty == NULL || pBlock == NULL) {
- return;
- }
-
- room = tty_write_room(tty);
-
- TRACE_PS("transmit_block %p, room %d, length %d",
- pBlock, room, pBlock->length);
-
- while (pInfo->tx_position < pBlock->length) {
- if (room < 2)
- break;
-
- if (pBlock->data[pInfo->tx_position] == DLE) {
- /* send additional DLE char: */
- put_char(pInfo, DLE);
- }
- put_char(pInfo, pBlock->data[pInfo->tx_position++]);
-
- room--;
- }
-
- if ((pInfo->tx_position == pBlock->length) && (room >= 3)) {
- put_char(pInfo, DLE);
- put_char(pInfo, ETX);
- if (pInfo->flags & R3964_BCC) {
- put_char(pInfo, pInfo->bcc);
- }
- pInfo->state = R3964_WAIT_FOR_TX_ACK;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
- }
- flush(pInfo);
-}
-
-static void on_receive_block(struct r3964_info *pInfo)
-{
- unsigned int length;
- struct r3964_client_info *pClient;
- struct r3964_block_header *pBlock;
-
- length = pInfo->rx_position;
-
- /* compare byte checksum characters: */
- if (pInfo->flags & R3964_BCC) {
- if (pInfo->bcc != pInfo->last_rx) {
- TRACE_PE("checksum error - got %x but expected %x",
- pInfo->last_rx, pInfo->bcc);
- pInfo->flags |= R3964_CHECKSUM;
- }
- }
-
- /* check for errors (parity, overrun,...): */
- if (pInfo->flags & R3964_ERROR) {
- TRACE_PE("on_receive_block - transmission failed error %x",
- pInfo->flags & R3964_ERROR);
-
- put_char(pInfo, NAK);
- flush(pInfo);
- if (pInfo->nRetry < R3964_MAX_RETRIES) {
- pInfo->state = R3964_WAIT_FOR_RX_REPEAT;
- pInfo->nRetry++;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC);
- } else {
- TRACE_PE("on_receive_block - failed after max retries");
- pInfo->state = R3964_IDLE;
- }
- return;
- }
-
- /* received block; submit DLE: */
- put_char(pInfo, DLE);
- flush(pInfo);
- del_timer_sync(&pInfo->tmr);
- TRACE_PS(" rx success: got %d chars", length);
-
- /* prepare struct r3964_block_header: */
- pBlock = kmalloc(length + sizeof(struct r3964_block_header),
- GFP_KERNEL);
- TRACE_M("on_receive_block - kmalloc %p", pBlock);
-
- if (pBlock == NULL)
- return;
-
- pBlock->length = length;
- pBlock->data = ((unsigned char *)pBlock) +
- sizeof(struct r3964_block_header);
- pBlock->locks = 0;
- pBlock->next = NULL;
- pBlock->owner = NULL;
-
- memcpy(pBlock->data, pInfo->rx_buf, length);
-
- /* queue block into rx_queue: */
- add_rx_queue(pInfo, pBlock);
-
- /* notify attached client processes: */
- for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
- if (pClient->sig_flags & R3964_SIG_DATA) {
- add_msg(pClient, R3964_MSG_DATA, length, R3964_OK,
- pBlock);
- }
- }
- wake_up_interruptible(&pInfo->tty->read_wait);
-
- pInfo->state = R3964_IDLE;
-
- trigger_transmit(pInfo);
-}
-
-static void receive_char(struct r3964_info *pInfo, const unsigned char c)
-{
- switch (pInfo->state) {
- case R3964_TX_REQUEST:
- if (c == DLE) {
- TRACE_PS("TX_REQUEST - got DLE");
-
- pInfo->state = R3964_TRANSMITTING;
- pInfo->tx_position = 0;
-
- transmit_block(pInfo);
- } else if (c == STX) {
- if (pInfo->nRetry == 0) {
- TRACE_PE("TX_REQUEST - init conflict");
- if (pInfo->priority == R3964_SLAVE) {
- goto start_receiving;
- }
- } else {
- TRACE_PE("TX_REQUEST - secondary init "
- "conflict!? Switching to SLAVE mode "
- "for next rx.");
- goto start_receiving;
- }
- } else {
- TRACE_PE("TX_REQUEST - char != DLE: %x", c);
- retry_transmit(pInfo);
- }
- break;
- case R3964_TRANSMITTING:
- if (c == NAK) {
- TRACE_PE("TRANSMITTING - got NAK");
- retry_transmit(pInfo);
- } else {
- TRACE_PE("TRANSMITTING - got invalid char");
-
- pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
- }
- break;
- case R3964_WAIT_FOR_TX_ACK:
- if (c == DLE) {
- TRACE_PS("WAIT_FOR_TX_ACK - got DLE");
- remove_from_tx_queue(pInfo, R3964_OK);
-
- pInfo->state = R3964_IDLE;
- trigger_transmit(pInfo);
- } else {
- retry_transmit(pInfo);
- }
- break;
- case R3964_WAIT_FOR_RX_REPEAT:
- case R3964_IDLE:
- if (c == STX) {
- /* Prevent rx_queue from overflow: */
- if (pInfo->blocks_in_rx_queue >=
- R3964_MAX_BLOCKS_IN_RX_QUEUE) {
- TRACE_PE("IDLE - got STX but no space in "
- "rx_queue!");
- pInfo->state = R3964_WAIT_FOR_RX_BUF;
- mod_timer(&pInfo->tmr,
- jiffies + R3964_TO_NO_BUF);
- break;
- }
-start_receiving:
- /* Ok, start receiving: */
- TRACE_PS("IDLE - got STX");
- pInfo->rx_position = 0;
- pInfo->last_rx = 0;
- pInfo->flags &= ~R3964_ERROR;
- pInfo->state = R3964_RECEIVING;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
- pInfo->nRetry = 0;
- put_char(pInfo, DLE);
- flush(pInfo);
- pInfo->bcc = 0;
- }
- break;
- case R3964_RECEIVING:
- if (pInfo->rx_position < RX_BUF_SIZE) {
- pInfo->bcc ^= c;
-
- if (c == DLE) {
- if (pInfo->last_rx == DLE) {
- pInfo->last_rx = 0;
- goto char_to_buf;
- }
- pInfo->last_rx = DLE;
- break;
- } else if ((c == ETX) && (pInfo->last_rx == DLE)) {
- if (pInfo->flags & R3964_BCC) {
- pInfo->state = R3964_WAIT_FOR_BCC;
- mod_timer(&pInfo->tmr,
- jiffies + R3964_TO_ZVZ);
- } else {
- on_receive_block(pInfo);
- }
- } else {
- pInfo->last_rx = c;
-char_to_buf:
- pInfo->rx_buf[pInfo->rx_position++] = c;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
- }
- }
- /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */
- break;
- case R3964_WAIT_FOR_BCC:
- pInfo->last_rx = c;
- on_receive_block(pInfo);
- break;
- }
-}
-
-static void receive_error(struct r3964_info *pInfo, const char flag)
-{
- switch (flag) {
- case TTY_NORMAL:
- break;
- case TTY_BREAK:
- TRACE_PE("received break");
- pInfo->flags |= R3964_BREAK;
- break;
- case TTY_PARITY:
- TRACE_PE("parity error");
- pInfo->flags |= R3964_PARITY;
- break;
- case TTY_FRAME:
- TRACE_PE("frame error");
- pInfo->flags |= R3964_FRAME;
- break;
- case TTY_OVERRUN:
- TRACE_PE("frame overrun");
- pInfo->flags |= R3964_OVERRUN;
- break;
- default:
- TRACE_PE("receive_error - unknown flag %d", flag);
- pInfo->flags |= R3964_UNKNOWN;
- break;
- }
-}
-
-static void on_timeout(struct timer_list *t)
-{
- struct r3964_info *pInfo = from_timer(pInfo, t, tmr);
-
- switch (pInfo->state) {
- case R3964_TX_REQUEST:
- TRACE_PE("TX_REQUEST - timeout");
- retry_transmit(pInfo);
- break;
- case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:
- put_char(pInfo, NAK);
- flush(pInfo);
- retry_transmit(pInfo);
- break;
- case R3964_WAIT_FOR_TX_ACK:
- TRACE_PE("WAIT_FOR_TX_ACK - timeout");
- retry_transmit(pInfo);
- break;
- case R3964_WAIT_FOR_RX_BUF:
- TRACE_PE("WAIT_FOR_RX_BUF - timeout");
- put_char(pInfo, NAK);
- flush(pInfo);
- pInfo->state = R3964_IDLE;
- break;
- case R3964_RECEIVING:
- TRACE_PE("RECEIVING - timeout after %d chars",
- pInfo->rx_position);
- put_char(pInfo, NAK);
- flush(pInfo);
- pInfo->state = R3964_IDLE;
- break;
- case R3964_WAIT_FOR_RX_REPEAT:
- TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");
- pInfo->state = R3964_IDLE;
- break;
- case R3964_WAIT_FOR_BCC:
- TRACE_PE("WAIT_FOR_BCC - timeout");
- put_char(pInfo, NAK);
- flush(pInfo);
- pInfo->state = R3964_IDLE;
- break;
- }
-}
-
-static struct r3964_client_info *findClient(struct r3964_info *pInfo,
- struct pid *pid)
-{
- struct r3964_client_info *pClient;
-
- for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
- if (pClient->pid == pid) {
- return pClient;
- }
- }
- return NULL;
-}
-
-static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg)
-{
- struct r3964_client_info *pClient;
- struct r3964_client_info **ppClient;
- struct r3964_message *pMsg;
-
- if ((arg & R3964_SIG_ALL) == 0) {
- /* Remove client from client list */
- for (ppClient = &pInfo->firstClient; *ppClient;
- ppClient = &(*ppClient)->next) {
- pClient = *ppClient;
-
- if (pClient->pid == pid) {
- TRACE_PS("removing client %d from client list",
- pid_nr(pid));
- *ppClient = pClient->next;
- while (pClient->msg_count) {
- pMsg = remove_msg(pInfo, pClient);
- if (pMsg) {
- kfree(pMsg);
- TRACE_M("enable_signals - msg "
- "kfree %p", pMsg);
- }
- }
- put_pid(pClient->pid);
- kfree(pClient);
- TRACE_M("enable_signals - kfree %p", pClient);
- return 0;
- }
- }
- return -EINVAL;
- } else {
- pClient = findClient(pInfo, pid);
- if (pClient) {
- /* update signal options */
- pClient->sig_flags = arg;
- } else {
- /* add client to client list */
- pClient = kmalloc(sizeof(struct r3964_client_info),
- GFP_KERNEL);
- TRACE_M("enable_signals - kmalloc %p", pClient);
- if (pClient == NULL)
- return -ENOMEM;
-
- TRACE_PS("add client %d to client list", pid_nr(pid));
- spin_lock_init(&pClient->lock);
- pClient->sig_flags = arg;
- pClient->pid = get_pid(pid);
- pClient->next = pInfo->firstClient;
- pClient->first_msg = NULL;
- pClient->last_msg = NULL;
- pClient->next_block_to_read = NULL;
- pClient->msg_count = 0;
- pInfo->firstClient = pClient;
- }
- }
-
- return 0;
-}
-
-static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
- unsigned char __user * buf)
-{
- struct r3964_client_info *pClient;
- struct r3964_block_header *block;
-
- if (!buf) {
- return -EINVAL;
- }
-
- pClient = findClient(pInfo, pid);
- if (pClient == NULL) {
- return -EINVAL;
- }
-
- block = pClient->next_block_to_read;
- if (!block) {
- return 0;
- } else {
- if (copy_to_user(buf, block->data, block->length))
- return -EFAULT;
-
- remove_client_block(pInfo, pClient);
- return block->length;
- }
-
- return -EINVAL;
-}
-
-static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
- int error_code, struct r3964_block_header *pBlock)
-{
- struct r3964_message *pMsg;
- unsigned long flags;
-
- if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) {
-queue_the_message:
-
- pMsg = kmalloc(sizeof(struct r3964_message),
- error_code ? GFP_ATOMIC : GFP_KERNEL);
- TRACE_M("add_msg - kmalloc %p", pMsg);
- if (pMsg == NULL) {
- return;
- }
-
- spin_lock_irqsave(&pClient->lock, flags);
-
- pMsg->msg_id = msg_id;
- pMsg->arg = arg;
- pMsg->error_code = error_code;
- pMsg->block = pBlock;
- pMsg->next = NULL;
-
- if (pClient->last_msg == NULL) {
- pClient->first_msg = pClient->last_msg = pMsg;
- } else {
- pClient->last_msg->next = pMsg;
- pClient->last_msg = pMsg;
- }
-
- pClient->msg_count++;
-
- if (pBlock != NULL) {
- pBlock->locks++;
- }
- spin_unlock_irqrestore(&pClient->lock, flags);
- } else {
- if ((pClient->last_msg->msg_id == R3964_MSG_ACK)
- && (pClient->last_msg->error_code == R3964_OVERFLOW)) {
- pClient->last_msg->arg++;
- TRACE_PE("add_msg - inc prev OVERFLOW-msg");
- } else {
- msg_id = R3964_MSG_ACK;
- arg = 0;
- error_code = R3964_OVERFLOW;
- pBlock = NULL;
- TRACE_PE("add_msg - queue OVERFLOW-msg");
- goto queue_the_message;
- }
- }
- /* Send SIGIO signal to client process: */
- if (pClient->sig_flags & R3964_USE_SIGIO) {
- kill_pid(pClient->pid, SIGIO, 1);
- }
-}
-
-static struct r3964_message *remove_msg(struct r3964_info *pInfo,
- struct r3964_client_info *pClient)
-{
- struct r3964_message *pMsg = NULL;
- unsigned long flags;
-
- if (pClient->first_msg) {
- spin_lock_irqsave(&pClient->lock, flags);
-
- pMsg = pClient->first_msg;
- pClient->first_msg = pMsg->next;
- if (pClient->first_msg == NULL) {
- pClient->last_msg = NULL;
- }
-
- pClient->msg_count--;
- if (pMsg->block) {
- remove_client_block(pInfo, pClient);
- pClient->next_block_to_read = pMsg->block;
- }
- spin_unlock_irqrestore(&pClient->lock, flags);
- }
- return pMsg;
-}
-
-static void remove_client_block(struct r3964_info *pInfo,
- struct r3964_client_info *pClient)
-{
- struct r3964_block_header *block;
-
- TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid));
-
- block = pClient->next_block_to_read;
- if (block) {
- block->locks--;
- if (block->locks == 0) {
- remove_from_rx_queue(pInfo, block);
- }
- }
- pClient->next_block_to_read = NULL;
-}
-
-/*************************************************************
- * Line discipline routines
- *************************************************************/
-
-static int r3964_open(struct tty_struct *tty)
-{
- struct r3964_info *pInfo;
-
- TRACE_L("open");
- TRACE_L("tty=%p, PID=%d, disc_data=%p",
- tty, current->pid, tty->disc_data);
-
- pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL);
- TRACE_M("r3964_open - info kmalloc %p", pInfo);
-
- if (!pInfo) {
- printk(KERN_ERR "r3964: failed to alloc info structure\n");
- return -ENOMEM;
- }
-
- pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
- TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf);
-
- if (!pInfo->rx_buf) {
- printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
- kfree(pInfo);
- TRACE_M("r3964_open - info kfree %p", pInfo);
- return -ENOMEM;
- }
-
- pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
- TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf);
-
- if (!pInfo->tx_buf) {
- printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
- kfree(pInfo->rx_buf);
- TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf);
- kfree(pInfo);
- TRACE_M("r3964_open - info kfree %p", pInfo);
- return -ENOMEM;
- }
-
- spin_lock_init(&pInfo->lock);
- mutex_init(&pInfo->read_lock);
- pInfo->tty = tty;
- pInfo->priority = R3964_MASTER;
- pInfo->rx_first = pInfo->rx_last = NULL;
- pInfo->tx_first = pInfo->tx_last = NULL;
- pInfo->rx_position = 0;
- pInfo->tx_position = 0;
- pInfo->last_rx = 0;
- pInfo->blocks_in_rx_queue = 0;
- pInfo->firstClient = NULL;
- pInfo->state = R3964_IDLE;
- pInfo->flags = R3964_DEBUG;
- pInfo->nRetry = 0;
-
- tty->disc_data = pInfo;
- tty->receive_room = 65536;
-
- timer_setup(&pInfo->tmr, on_timeout, 0);
-
- return 0;
-}
-
-static void r3964_close(struct tty_struct *tty)
-{
- struct r3964_info *pInfo = tty->disc_data;
- struct r3964_client_info *pClient, *pNext;
- struct r3964_message *pMsg;
- struct r3964_block_header *pHeader, *pNextHeader;
- unsigned long flags;
-
- TRACE_L("close");
-
- /*
- * Make sure that our task queue isn't activated. If it
- * is, take it out of the linked list.
- */
- del_timer_sync(&pInfo->tmr);
-
- /* Remove client-structs and message queues: */
- pClient = pInfo->firstClient;
- while (pClient) {
- pNext = pClient->next;
- while (pClient->msg_count) {
- pMsg = remove_msg(pInfo, pClient);
- if (pMsg) {
- kfree(pMsg);
- TRACE_M("r3964_close - msg kfree %p", pMsg);
- }
- }
- put_pid(pClient->pid);
- kfree(pClient);
- TRACE_M("r3964_close - client kfree %p", pClient);
- pClient = pNext;
- }
- /* Remove jobs from tx_queue: */
- spin_lock_irqsave(&pInfo->lock, flags);
- pHeader = pInfo->tx_first;
- pInfo->tx_first = pInfo->tx_last = NULL;
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- while (pHeader) {
- pNextHeader = pHeader->next;
- kfree(pHeader);
- pHeader = pNextHeader;
- }
-
- /* Free buffers: */
- kfree(pInfo->rx_buf);
- TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
- kfree(pInfo->tx_buf);
- TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf);
- kfree(pInfo);
- TRACE_M("r3964_close - info kfree %p", pInfo);
-}
-
-static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
- unsigned char *kbuf, size_t nr,
- void **cookie, unsigned long offset)
-{
- struct r3964_info *pInfo = tty->disc_data;
- struct r3964_client_info *pClient;
- struct r3964_message *pMsg;
- struct r3964_client_message theMsg;
- int ret;
-
- TRACE_L("read()");
-
- /*
- * Internal serialization of reads.
- */
- if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&pInfo->read_lock))
- return -EAGAIN;
- } else {
- if (mutex_lock_interruptible(&pInfo->read_lock))
- return -ERESTARTSYS;
- }
-
- pClient = findClient(pInfo, task_pid(current));
- if (pClient) {
- pMsg = remove_msg(pInfo, pClient);
- if (pMsg == NULL) {
- /* no messages available. */
- if (tty_io_nonblock(tty, file)) {
- ret = -EAGAIN;
- goto unlock;
- }
- /* block until there is a message: */
- wait_event_interruptible(tty->read_wait,
- (pMsg = remove_msg(pInfo, pClient)));
- }
-
- /* If we still haven't got a message, we must have been signalled */
-
- if (!pMsg) {
- ret = -EINTR;
- goto unlock;
- }
-
- /* deliver msg to client process: */
- theMsg.msg_id = pMsg->msg_id;
- theMsg.arg = pMsg->arg;
- theMsg.error_code = pMsg->error_code;
- ret = sizeof(struct r3964_client_message);
-
- kfree(pMsg);
- TRACE_M("r3964_read - msg kfree %p", pMsg);
-
- memcpy(kbuf, &theMsg, ret);
-
- TRACE_PS("read - return %d", ret);
- goto unlock;
- }
- ret = -EPERM;
-unlock:
- mutex_unlock(&pInfo->read_lock);
- return ret;
-}
-
-static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
- const unsigned char *data, size_t count)
-{
- struct r3964_info *pInfo = tty->disc_data;
- struct r3964_block_header *pHeader;
- struct r3964_client_info *pClient;
- unsigned char *new_data;
-
- TRACE_L("write request, %d characters", count);
-/*
- * Verify the pointers
- */
-
- if (!pInfo)
- return -EIO;
-
-/*
- * Ensure that the caller does not wish to send too much.
- */
- if (count > R3964_MTU) {
- if (pInfo->flags & R3964_DEBUG) {
- TRACE_L(KERN_WARNING "r3964_write: truncating user "
- "packet from %u to mtu %d", count, R3964_MTU);
- }
- count = R3964_MTU;
- }
-/*
- * Allocate a buffer for the data and copy it from the buffer with header prepended
- */
- new_data = kmalloc(count + sizeof(struct r3964_block_header),
- GFP_KERNEL);
- TRACE_M("r3964_write - kmalloc %p", new_data);
- if (new_data == NULL) {
- if (pInfo->flags & R3964_DEBUG) {
- printk(KERN_ERR "r3964_write: no memory\n");
- }
- return -ENOSPC;
- }
-
- pHeader = (struct r3964_block_header *)new_data;
- pHeader->data = new_data + sizeof(struct r3964_block_header);
- pHeader->length = count;
- pHeader->locks = 0;
- pHeader->owner = NULL;
-
- pClient = findClient(pInfo, task_pid(current));
- if (pClient) {
- pHeader->owner = pClient;
- }
-
- memcpy(pHeader->data, data, count); /* We already verified this */
-
- if (pInfo->flags & R3964_DEBUG) {
- dump_block(pHeader->data, count);
- }
-
-/*
- * Add buffer to transmit-queue:
- */
- add_tx_queue(pInfo, pHeader);
- trigger_transmit(pInfo);
-
- return 0;
-}
-
-static int r3964_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct r3964_info *pInfo = tty->disc_data;
- if (pInfo == NULL)
- return -EINVAL;
- switch (cmd) {
- case R3964_ENABLE_SIGNALS:
- return enable_signals(pInfo, task_pid(current), arg);
- case R3964_SETPRIORITY:
- if (arg < R3964_MASTER || arg > R3964_SLAVE)
- return -EINVAL;
- pInfo->priority = arg & 0xff;
- return 0;
- case R3964_USE_BCC:
- if (arg)
- pInfo->flags |= R3964_BCC;
- else
- pInfo->flags &= ~R3964_BCC;
- return 0;
- case R3964_READ_TELEGRAM:
- return read_telegram(pInfo, task_pid(current),
- (unsigned char __user *)arg);
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-#ifdef CONFIG_COMPAT
-static int r3964_compat_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case R3964_ENABLE_SIGNALS:
- case R3964_SETPRIORITY:
- case R3964_USE_BCC:
- return r3964_ioctl(tty, file, cmd, arg);
- default:
- return -ENOIOCTLCMD;
- }
-}
-#endif
-
-static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
- TRACE_L("set_termios");
-}
-
-/* Called without the kernel lock held - fine */
-static __poll_t r3964_poll(struct tty_struct *tty, struct file *file,
- struct poll_table_struct *wait)
-{
- struct r3964_info *pInfo = tty->disc_data;
- struct r3964_client_info *pClient;
- struct r3964_message *pMsg = NULL;
- unsigned long flags;
- __poll_t result = EPOLLOUT;
-
- TRACE_L("POLL");
-
- pClient = findClient(pInfo, task_pid(current));
- if (pClient) {
- poll_wait(file, &tty->read_wait, wait);
- spin_lock_irqsave(&pInfo->lock, flags);
- pMsg = pClient->first_msg;
- spin_unlock_irqrestore(&pInfo->lock, flags);
- if (pMsg)
- result |= EPOLLIN | EPOLLRDNORM;
- } else {
- result = -EINVAL;
- }
- return result;
-}
-
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
-{
- struct r3964_info *pInfo = tty->disc_data;
- const unsigned char *p;
- char *f, flags = TTY_NORMAL;
- int i;
-
- for (i = count, p = cp, f = fp; i; i--, p++) {
- if (f)
- flags = *f++;
- if (flags == TTY_NORMAL) {
- receive_char(pInfo, *p);
- } else {
- receive_error(pInfo, flags);
- }
-
- }
-}
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_LDISC(N_R3964);
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 9686c5d10571..0ec93f1a61f5 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -342,10 +342,10 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty)
{
unsigned long flags;
- if (tty->link->packet) {
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- tty->ctrl_status |= TIOCPKT_FLUSHREAD;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (tty->link->ctrl.packet) {
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ tty->ctrl.pktstatus |= TIOCPKT_FLUSHREAD;
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
wake_up_interruptible(&tty->link->read_wait);
}
}
@@ -361,7 +361,7 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty)
* Holds termios_rwsem to exclude producer/consumer while
* buffer indices are reset.
*
- * Locking: ctrl_lock, exclusive termios_rwsem
+ * Locking: ctrl.lock, exclusive termios_rwsem
*/
static void n_tty_flush_buffer(struct tty_struct *tty)
@@ -1103,7 +1103,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
* buffer is 'output'. The signal is processed first to alert any current
* readers or writers to discontinue and exit their i/o loops.
*
- * Locking: ctrl_lock
+ * Locking: ctrl.lock
*/
static void __isig(int sig, struct tty_struct *tty)
@@ -1245,7 +1245,6 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
commit_echoes(tty);
} else
process_echoes(tty);
- return;
}
/**
@@ -1260,12 +1259,8 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
* n_tty_receive_buf()/producer path:
* caller holds non-exclusive termios_rwsem
* publishes canon_head if canonical mode is active
- *
- * Returns 1 if LNEXT was received, else returns 0
*/
-
-static int
-n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
+static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
{
struct n_tty_data *ldata = tty->disc_data;
@@ -1273,35 +1268,35 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
if (c == START_CHAR(tty)) {
start_tty(tty);
process_echoes(tty);
- return 0;
+ return;
}
if (c == STOP_CHAR(tty)) {
stop_tty(tty);
- return 0;
+ return;
}
}
if (L_ISIG(tty)) {
if (c == INTR_CHAR(tty)) {
n_tty_receive_signal_char(tty, SIGINT, c);
- return 0;
+ return;
} else if (c == QUIT_CHAR(tty)) {
n_tty_receive_signal_char(tty, SIGQUIT, c);
- return 0;
+ return;
} else if (c == SUSP_CHAR(tty)) {
n_tty_receive_signal_char(tty, SIGTSTP, c);
- return 0;
+ return;
}
}
- if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
+ if (tty->flow.stopped && !tty->flow.tco_stopped && I_IXON(tty) && I_IXANY(tty)) {
start_tty(tty);
process_echoes(tty);
}
if (c == '\r') {
if (I_IGNCR(tty))
- return 0;
+ return;
if (I_ICRNL(tty))
c = '\n';
} else if (c == '\n' && I_INLCR(tty))
@@ -1312,7 +1307,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
(c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
eraser(c, tty);
commit_echoes(tty);
- return 0;
+ return;
}
if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
ldata->lnext = 1;
@@ -1324,7 +1319,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
commit_echoes(tty);
}
}
- return 1;
+ return;
}
if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && L_IEXTEN(tty)) {
size_t tail = ldata->canon_head;
@@ -1337,7 +1332,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
tail++;
}
commit_echoes(tty);
- return 0;
+ return;
}
if (c == '\n') {
if (L_ECHO(tty) || L_ECHONL(tty)) {
@@ -1375,7 +1370,7 @@ handle_newline:
smp_store_release(&ldata->canon_head, ldata->read_head);
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
wake_up_interruptible_poll(&tty->read_wait, EPOLLIN);
- return 0;
+ return;
}
}
@@ -1397,15 +1392,13 @@ handle_newline:
put_tty_queue(c, ldata);
put_tty_queue(c, ldata);
- return 0;
}
-static inline void
-n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)
+static void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
{
struct n_tty_data *ldata = tty->disc_data;
- if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
+ if (tty->flow.stopped && !tty->flow.tco_stopped && I_IXON(tty) && I_IXANY(tty)) {
start_tty(tty);
process_echoes(tty);
}
@@ -1423,31 +1416,6 @@ n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)
put_tty_queue(c, ldata);
}
-static void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
-{
- n_tty_receive_char_inline(tty, c);
-}
-
-static inline void
-n_tty_receive_char_fast(struct tty_struct *tty, unsigned char c)
-{
- struct n_tty_data *ldata = tty->disc_data;
-
- if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
- start_tty(tty);
- process_echoes(tty);
- }
- if (L_ECHO(tty)) {
- finish_erasing(ldata);
- /* Record the column of first canon char. */
- if (ldata->canon_head == ldata->read_head)
- echo_set_canon_col(ldata);
- echo_char(c, tty);
- commit_echoes(tty);
- }
- put_tty_queue(c, ldata);
-}
-
static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
{
if (I_ISTRIP(tty))
@@ -1459,7 +1427,7 @@ static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
if (c == STOP_CHAR(tty))
stop_tty(tty);
else if (c == START_CHAR(tty) ||
- (tty->stopped && !tty->flow_stopped && I_IXANY(tty) &&
+ (tty->flow.stopped && !tty->flow.tco_stopped && I_IXANY(tty) &&
c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) &&
c != SUSP_CHAR(tty))) {
start_tty(tty);
@@ -1506,7 +1474,7 @@ n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag)
static void
n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
struct n_tty_data *ldata = tty->disc_data;
size_t n, head;
@@ -1526,7 +1494,7 @@ n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
static void
n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
struct n_tty_data *ldata = tty->disc_data;
char flag = TTY_NORMAL;
@@ -1543,7 +1511,7 @@ n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp,
static void
n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
char flag = TTY_NORMAL;
@@ -1555,68 +1523,46 @@ n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp,
}
}
-static void
-n_tty_receive_buf_standard(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+static void n_tty_receive_buf_standard(struct tty_struct *tty,
+ const unsigned char *cp, const char *fp, int count)
{
struct n_tty_data *ldata = tty->disc_data;
char flag = TTY_NORMAL;
while (count--) {
+ unsigned char c = *cp++;
+
if (fp)
flag = *fp++;
- if (likely(flag == TTY_NORMAL)) {
- unsigned char c = *cp++;
-
- if (I_ISTRIP(tty))
- c &= 0x7f;
- if (I_IUCLC(tty) && L_IEXTEN(tty))
- c = tolower(c);
- if (L_EXTPROC(tty)) {
- put_tty_queue(c, ldata);
- continue;
- }
- if (!test_bit(c, ldata->char_map))
- n_tty_receive_char_inline(tty, c);
- else if (n_tty_receive_char_special(tty, c) && count) {
- if (fp)
- flag = *fp++;
- n_tty_receive_char_lnext(tty, *cp++, flag);
- count--;
- }
- } else
- n_tty_receive_char_flagged(tty, *cp++, flag);
- }
-}
-static void
-n_tty_receive_buf_fast(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
-{
- struct n_tty_data *ldata = tty->disc_data;
- char flag = TTY_NORMAL;
+ if (ldata->lnext) {
+ n_tty_receive_char_lnext(tty, c, flag);
+ continue;
+ }
- while (count--) {
- if (fp)
- flag = *fp++;
- if (likely(flag == TTY_NORMAL)) {
- unsigned char c = *cp++;
-
- if (!test_bit(c, ldata->char_map))
- n_tty_receive_char_fast(tty, c);
- else if (n_tty_receive_char_special(tty, c) && count) {
- if (fp)
- flag = *fp++;
- n_tty_receive_char_lnext(tty, *cp++, flag);
- count--;
- }
- } else
- n_tty_receive_char_flagged(tty, *cp++, flag);
+ if (unlikely(flag != TTY_NORMAL)) {
+ n_tty_receive_char_flagged(tty, c, flag);
+ continue;
+ }
+
+ if (I_ISTRIP(tty))
+ c &= 0x7f;
+ if (I_IUCLC(tty) && L_IEXTEN(tty))
+ c = tolower(c);
+ if (L_EXTPROC(tty)) {
+ put_tty_queue(c, ldata);
+ continue;
+ }
+
+ if (test_bit(c, ldata->char_map))
+ n_tty_receive_char_special(tty, c);
+ else
+ n_tty_receive_char(tty, c);
}
}
static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
struct n_tty_data *ldata = tty->disc_data;
bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty));
@@ -1628,19 +1574,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
else if (tty->closing && !L_EXTPROC(tty))
n_tty_receive_buf_closing(tty, cp, fp, count);
else {
- if (ldata->lnext) {
- char flag = TTY_NORMAL;
-
- if (fp)
- flag = *fp++;
- n_tty_receive_char_lnext(tty, *cp++, flag);
- count--;
- }
-
- if (!preops && !I_PARMRK(tty))
- n_tty_receive_buf_fast(tty, cp, fp, count);
- else
- n_tty_receive_buf_standard(tty, cp, fp, count);
+ n_tty_receive_buf_standard(tty, cp, fp, count);
flush_echoes(tty);
if (tty->ops->flush_chars)
@@ -1695,7 +1629,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
*/
static int
n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count, int flow)
+ const char *fp, int count, int flow)
{
struct n_tty_data *ldata = tty->disc_data;
int room, n, rcvd = 0, overflow;
@@ -1764,13 +1698,13 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
}
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
n_tty_receive_buf_common(tty, cp, fp, count, 0);
}
static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
return n_tty_receive_buf_common(tty, cp, fp, count, 1);
}
@@ -1863,7 +1797,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
* Fix tty hang when I_IXON(tty) is cleared, but the tty
* been stopped by STOP_CHAR(tty) before it.
*/
- if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) {
+ if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow.tco_stopped) {
start_tty(tty);
process_echoes(tty);
}
@@ -2091,7 +2025,7 @@ static bool canon_copy_from_read_buf(struct tty_struct *tty,
*
* Locking: redirected write test is safe
* current->signal->tty check is safe
- * ctrl_lock to safely reference tty->pgrp
+ * ctrl.lock to safely reference tty->ctrl.pgrp
*/
static int job_control(struct tty_struct *tty, struct file *file)
@@ -2138,7 +2072,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
int minimum, time;
ssize_t retval = 0;
long timeout;
- int packet;
+ bool packet;
size_t tail;
/*
@@ -2194,20 +2128,20 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
}
}
- packet = tty->packet;
+ packet = tty->ctrl.packet;
tail = ldata->read_tail;
add_wait_queue(&tty->read_wait, &wait);
while (nr) {
/* First test for status change. */
- if (packet && tty->link->ctrl_status) {
+ if (packet && tty->link->ctrl.pktstatus) {
unsigned char cs;
if (kb != kbuf)
break;
- spin_lock_irq(&tty->link->ctrl_lock);
- cs = tty->link->ctrl_status;
- tty->link->ctrl_status = 0;
- spin_unlock_irq(&tty->link->ctrl_lock);
+ spin_lock_irq(&tty->link->ctrl.lock);
+ cs = tty->link->ctrl.pktstatus;
+ tty->link->ctrl.pktstatus = 0;
+ spin_unlock_irq(&tty->link->ctrl.lock);
*kb++ = cs;
nr--;
break;
@@ -2434,7 +2368,7 @@ static __poll_t n_tty_poll(struct tty_struct *tty, struct file *file,
if (input_available_p(tty, 1))
mask |= EPOLLIN | EPOLLRDNORM;
}
- if (tty->packet && tty->link->ctrl_status)
+ if (tty->ctrl.packet && tty->link->ctrl.pktstatus)
mask |= EPOLLPRI | EPOLLIN | EPOLLRDNORM;
if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
mask |= EPOLLHUP;
@@ -2490,6 +2424,7 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
static struct tty_ldisc_ops n_tty_ops = {
.owner = THIS_MODULE,
+ .num = N_TTY,
.name = "n_tty",
.open = n_tty_open,
.close = n_tty_close,
@@ -2515,11 +2450,11 @@ void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
{
*ops = n_tty_ops;
ops->owner = NULL;
- ops->refcount = ops->flags = 0;
+ ops->flags = 0;
}
EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
void __init n_tty_init(void)
{
- tty_register_ldisc(N_TTY, &n_tty_ops);
+ tty_register_ldisc(&n_tty_ops);
}
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index 9a2d78ace49b..0c80f25c8c3d 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -1378,7 +1378,7 @@ static int nozomi_card_init(struct pci_dev *pdev,
NOZOMI_NAME, dc);
if (unlikely(ret)) {
dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq);
- goto err_free_kfifo;
+ goto err_free_all_kfifo;
}
DBG1("base_addr: %p", dc->base_addr);
@@ -1416,12 +1416,15 @@ static int nozomi_card_init(struct pci_dev *pdev,
return 0;
err_free_tty:
- for (i = 0; i < MAX_PORT; ++i) {
+ for (i--; i >= 0; i--) {
tty_unregister_device(ntty_driver, dc->index_start + i);
tty_port_destroy(&dc->port[i].port);
}
+ free_irq(pdev->irq, dc);
+err_free_all_kfifo:
+ i = MAX_PORT;
err_free_kfifo:
- for (i = 0; i < MAX_PORT; i++)
+ for (i--; i >= PORT_MDM; i--)
kfifo_free(&dc->port[i].fifo_ul);
err_free_sbuf:
kfree(dc->send_buf);
@@ -1636,10 +1639,10 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer,
* If the port is unplugged report lots of room and let the bits
* dribble away so we don't block anything.
*/
-static int ntty_write_room(struct tty_struct *tty)
+static unsigned int ntty_write_room(struct tty_struct *tty)
{
struct port *port = tty->driver_data;
- int room = 4096;
+ unsigned int room = 4096;
const struct nozomi *dc = get_dc_by_tty(tty);
if (dc)
@@ -1776,20 +1779,15 @@ static void ntty_throttle(struct tty_struct *tty)
}
/* Returns number of chars in buffer, called by tty layer */
-static s32 ntty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int ntty_chars_in_buffer(struct tty_struct *tty)
{
struct port *port = tty->driver_data;
struct nozomi *dc = get_dc_by_tty(tty);
- s32 rval = 0;
- if (unlikely(!dc || !port)) {
- goto exit_in_buffer;
- }
-
- rval = kfifo_len(&port->fifo_ul);
+ if (unlikely(!dc || !port))
+ return 0;
-exit_in_buffer:
- return rval;
+ return kfifo_len(&port->fifo_ul);
}
static const struct tty_port_operations noz_tty_port_ops = {
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 9b5d4ae5d8f2..74bfabe5b453 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -57,9 +57,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
set_bit(TTY_IO_ERROR, &tty->flags);
wake_up_interruptible(&tty->read_wait);
wake_up_interruptible(&tty->write_wait);
- spin_lock_irq(&tty->ctrl_lock);
- tty->packet = 0;
- spin_unlock_irq(&tty->ctrl_lock);
+ spin_lock_irq(&tty->ctrl.lock);
+ tty->ctrl.packet = false;
+ spin_unlock_irq(&tty->ctrl.lock);
/* Review - krefs on tty_link ?? */
if (!tty->link)
return;
@@ -113,7 +113,7 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
struct tty_struct *to = tty->link;
unsigned long flags;
- if (tty->stopped)
+ if (tty->flow.stopped)
return 0;
if (c > 0) {
@@ -136,26 +136,13 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
* the other device.
*/
-static int pty_write_room(struct tty_struct *tty)
+static unsigned int pty_write_room(struct tty_struct *tty)
{
- if (tty->stopped)
+ if (tty->flow.stopped)
return 0;
return tty_buffer_space_avail(tty->link->port);
}
-/**
- * pty_chars_in_buffer - characters currently in our tx queue
- * @tty: our tty
- *
- * Report how much we have in the transmit queue. As everything is
- * instantly at the other end this is easy to implement.
- */
-
-static int pty_chars_in_buffer(struct tty_struct *tty)
-{
- return 0;
-}
-
/* Set the lock flag on a pty */
static int pty_set_lock(struct tty_struct *tty, int __user *arg)
{
@@ -185,16 +172,16 @@ static int pty_set_pktmode(struct tty_struct *tty, int __user *arg)
if (get_user(pktmode, arg))
return -EFAULT;
- spin_lock_irq(&tty->ctrl_lock);
+ spin_lock_irq(&tty->ctrl.lock);
if (pktmode) {
- if (!tty->packet) {
- tty->link->ctrl_status = 0;
+ if (!tty->ctrl.packet) {
+ tty->link->ctrl.pktstatus = 0;
smp_mb();
- tty->packet = 1;
+ tty->ctrl.packet = true;
}
} else
- tty->packet = 0;
- spin_unlock_irq(&tty->ctrl_lock);
+ tty->ctrl.packet = false;
+ spin_unlock_irq(&tty->ctrl.lock);
return 0;
}
@@ -202,7 +189,7 @@ static int pty_set_pktmode(struct tty_struct *tty, int __user *arg)
/* Get the packet mode of a pty */
static int pty_get_pktmode(struct tty_struct *tty, int __user *arg)
{
- int pktmode = tty->packet;
+ int pktmode = tty->ctrl.packet;
return put_user(pktmode, arg);
}
@@ -232,11 +219,11 @@ static void pty_flush_buffer(struct tty_struct *tty)
return;
tty_buffer_flush(to, NULL);
- if (to->packet) {
- spin_lock_irq(&tty->ctrl_lock);
- tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
+ if (to->ctrl.packet) {
+ spin_lock_irq(&tty->ctrl.lock);
+ tty->ctrl.pktstatus |= TIOCPKT_FLUSHWRITE;
wake_up_interruptible(&to->read_wait);
- spin_unlock_irq(&tty->ctrl_lock);
+ spin_unlock_irq(&tty->ctrl.lock);
}
}
@@ -266,7 +253,7 @@ static void pty_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
/* See if packet mode change of state. */
- if (tty->link && tty->link->packet) {
+ if (tty->link && tty->link->ctrl.packet) {
int extproc = (old_termios->c_lflag & EXTPROC) | L_EXTPROC(tty);
int old_flow = ((old_termios->c_iflag & IXON) &&
(old_termios->c_cc[VSTOP] == '\023') &&
@@ -275,17 +262,17 @@ static void pty_set_termios(struct tty_struct *tty,
STOP_CHAR(tty) == '\023' &&
START_CHAR(tty) == '\021');
if ((old_flow != new_flow) || extproc) {
- spin_lock_irq(&tty->ctrl_lock);
+ spin_lock_irq(&tty->ctrl.lock);
if (old_flow != new_flow) {
- tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
+ tty->ctrl.pktstatus &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
if (new_flow)
- tty->ctrl_status |= TIOCPKT_DOSTOP;
+ tty->ctrl.pktstatus |= TIOCPKT_DOSTOP;
else
- tty->ctrl_status |= TIOCPKT_NOSTOP;
+ tty->ctrl.pktstatus |= TIOCPKT_NOSTOP;
}
if (extproc)
- tty->ctrl_status |= TIOCPKT_IOCTL;
- spin_unlock_irq(&tty->ctrl_lock);
+ tty->ctrl.pktstatus |= TIOCPKT_IOCTL;
+ spin_unlock_irq(&tty->ctrl.lock);
wake_up_interruptible(&tty->link->read_wait);
}
}
@@ -295,7 +282,7 @@ static void pty_set_termios(struct tty_struct *tty,
}
/**
- * pty_do_resize - resize event
+ * pty_resize - resize event
* @tty: tty being resized
* @ws: window size being set.
*
@@ -346,11 +333,11 @@ static void pty_start(struct tty_struct *tty)
{
unsigned long flags;
- if (tty->link && tty->link->packet) {
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- tty->ctrl_status &= ~TIOCPKT_STOP;
- tty->ctrl_status |= TIOCPKT_START;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (tty->link && tty->link->ctrl.packet) {
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ tty->ctrl.pktstatus &= ~TIOCPKT_STOP;
+ tty->ctrl.pktstatus |= TIOCPKT_START;
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
wake_up_interruptible_poll(&tty->link->read_wait, EPOLLIN);
}
}
@@ -359,11 +346,11 @@ static void pty_stop(struct tty_struct *tty)
{
unsigned long flags;
- if (tty->link && tty->link->packet) {
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- tty->ctrl_status &= ~TIOCPKT_START;
- tty->ctrl_status |= TIOCPKT_STOP;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (tty->link && tty->link->ctrl.packet) {
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ tty->ctrl.pktstatus &= ~TIOCPKT_START;
+ tty->ctrl.pktstatus |= TIOCPKT_STOP;
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
wake_up_interruptible_poll(&tty->link->read_wait, EPOLLIN);
}
}
@@ -525,7 +512,6 @@ static const struct tty_operations master_pty_ops_bsd = {
.write = pty_write,
.write_room = pty_write_room,
.flush_buffer = pty_flush_buffer,
- .chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.ioctl = pty_bsd_ioctl,
.compat_ioctl = pty_bsd_compat_ioctl,
@@ -541,7 +527,6 @@ static const struct tty_operations slave_pty_ops_bsd = {
.write = pty_write,
.write_room = pty_write_room,
.flush_buffer = pty_flush_buffer,
- .chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.cleanup = pty_cleanup,
@@ -626,7 +611,7 @@ static struct cdev ptmx_cdev;
*/
int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
{
- int fd = -1;
+ int fd;
struct file *filp;
int retval = -EINVAL;
struct path path;
@@ -776,7 +761,6 @@ static const struct tty_operations ptm_unix98_ops = {
.write = pty_write,
.write_room = pty_write_room,
.flush_buffer = pty_flush_buffer,
- .chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.ioctl = pty_unix98_ioctl,
.compat_ioctl = pty_unix98_compat_ioctl,
@@ -794,7 +778,6 @@ static const struct tty_operations pty_unix98_ops = {
.write = pty_write,
.write_room = pty_write_room,
.flush_buffer = pty_flush_buffer,
- .chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.start = pty_start,
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index aead0c0c9796..9cdfcfe07e87 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -798,7 +798,7 @@ void serdev_controller_remove(struct serdev_controller *ctrl)
EXPORT_SYMBOL_GPL(serdev_controller_remove);
/**
- * serdev_driver_register() - Register client driver with serdev core
+ * __serdev_device_driver_register() - Register client driver with serdev core
* @sdrv: client driver to be associated with client-device.
* @owner: client driver owner to set.
*
diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c
index d035d08cb987..4caab8714e2c 100644
--- a/drivers/tty/serial/8250/8250_aspeed_vuart.c
+++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c
@@ -34,7 +34,6 @@
struct aspeed_vuart {
struct device *dev;
- void __iomem *regs;
struct clk *clk;
int line;
struct timer_list unthrottle_timer;
@@ -64,14 +63,24 @@ static const int unthrottle_timeout = HZ/10;
* different system (though most of them use 3f8/4).
*/
+static inline u8 aspeed_vuart_readb(struct aspeed_vuart *vuart, u8 reg)
+{
+ return readb(vuart->port->port.membase + reg);
+}
+
+static inline void aspeed_vuart_writeb(struct aspeed_vuart *vuart, u8 val, u8 reg)
+{
+ writeb(val, vuart->port->port.membase + reg);
+}
+
static ssize_t lpc_address_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct aspeed_vuart *vuart = dev_get_drvdata(dev);
u16 addr;
- addr = (readb(vuart->regs + ASPEED_VUART_ADDRH) << 8) |
- (readb(vuart->regs + ASPEED_VUART_ADDRL));
+ addr = (aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRH) << 8) |
+ (aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRL));
return snprintf(buf, PAGE_SIZE - 1, "0x%x\n", addr);
}
@@ -81,8 +90,8 @@ static int aspeed_vuart_set_lpc_address(struct aspeed_vuart *vuart, u32 addr)
if (addr > U16_MAX)
return -EINVAL;
- writeb(addr >> 8, vuart->regs + ASPEED_VUART_ADDRH);
- writeb(addr >> 0, vuart->regs + ASPEED_VUART_ADDRL);
+ aspeed_vuart_writeb(vuart, addr >> 8, ASPEED_VUART_ADDRH);
+ aspeed_vuart_writeb(vuart, addr >> 0, ASPEED_VUART_ADDRL);
return 0;
}
@@ -111,7 +120,7 @@ static ssize_t sirq_show(struct device *dev,
struct aspeed_vuart *vuart = dev_get_drvdata(dev);
u8 reg;
- reg = readb(vuart->regs + ASPEED_VUART_GCRB);
+ reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRB);
reg &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
reg >>= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
@@ -128,10 +137,10 @@ static int aspeed_vuart_set_sirq(struct aspeed_vuart *vuart, u32 sirq)
sirq <<= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
sirq &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
- reg = readb(vuart->regs + ASPEED_VUART_GCRB);
+ reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRB);
reg &= ~ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
reg |= sirq;
- writeb(reg, vuart->regs + ASPEED_VUART_GCRB);
+ aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRB);
return 0;
}
@@ -159,7 +168,7 @@ static ssize_t sirq_polarity_show(struct device *dev,
struct aspeed_vuart *vuart = dev_get_drvdata(dev);
u8 reg;
- reg = readb(vuart->regs + ASPEED_VUART_GCRA);
+ reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA);
reg &= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg ? 1 : 0);
@@ -168,14 +177,14 @@ static ssize_t sirq_polarity_show(struct device *dev,
static void aspeed_vuart_set_sirq_polarity(struct aspeed_vuart *vuart,
bool polarity)
{
- u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA);
+ u8 reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA);
if (polarity)
reg |= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
else
reg &= ~ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
- writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
+ aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA);
}
static ssize_t sirq_polarity_store(struct device *dev,
@@ -210,14 +219,14 @@ static const struct attribute_group aspeed_vuart_attr_group = {
static void aspeed_vuart_set_enabled(struct aspeed_vuart *vuart, bool enabled)
{
- u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA);
+ u8 reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA);
if (enabled)
reg |= ASPEED_VUART_GCRA_VUART_EN;
else
reg &= ~ASPEED_VUART_GCRA_VUART_EN;
- writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
+ aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA);
}
static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart,
@@ -225,7 +234,7 @@ static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart,
{
u8 reg;
- reg = readb(vuart->regs + ASPEED_VUART_GCRA);
+ reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA);
/* If the DISABLE_HOST_TX_DISCARD bit is set, discard is disabled */
if (!discard)
@@ -233,7 +242,7 @@ static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart,
else
reg &= ~ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD;
- writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
+ aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA);
}
static int aspeed_vuart_startup(struct uart_port *uart_port)
@@ -320,7 +329,7 @@ static int aspeed_vuart_handle_irq(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int iir, lsr;
- int space, count;
+ unsigned int space, count;
iir = serial_port_in(port, UART_IIR);
@@ -339,14 +348,12 @@ static int aspeed_vuart_handle_irq(struct uart_port *port)
struct aspeed_vuart *vuart = port->private_data;
__aspeed_vuart_set_throttle(up, true);
- if (!timer_pending(&vuart->unthrottle_timer)) {
- vuart->port = up;
+ if (!timer_pending(&vuart->unthrottle_timer))
mod_timer(&vuart->unthrottle_timer,
jiffies + unthrottle_timeout);
- }
} else {
- count = min(space, 256);
+ count = min(space, 256U);
do {
serial8250_read_char(up, lsr);
@@ -421,13 +428,9 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
timer_setup(&vuart->unthrottle_timer, aspeed_vuart_unthrottle_exp, 0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- vuart->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(vuart->regs))
- return PTR_ERR(vuart->regs);
memset(&port, 0, sizeof(port));
port.port.private_data = vuart;
- port.port.membase = vuart->regs;
port.port.mapbase = res->start;
port.port.mapsize = resource_size(res);
port.port.startup = aspeed_vuart_startup;
@@ -485,7 +488,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
port.port.iotype = UPIO_MEM;
port.port.type = PORT_16550A;
port.port.uartclk = clk;
- port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
+ port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
| UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST;
if (of_property_read_bool(np, "no-loopback-test"))
@@ -502,6 +505,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
goto err_clk_disable;
vuart->line = rc;
+ vuart->port = serial8250_get_port(vuart->line);
rc = of_parse_phandle_with_fixed_args(
np, "aspeed,sirq-polarity-sense", 2, 0,
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index cae61d1ebec5..1ce193daea7f 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -172,7 +172,6 @@ static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
static int serial_link_irq_chain(struct uart_8250_port *up)
{
struct hlist_head *h;
- struct hlist_node *n;
struct irq_info *i;
int ret;
@@ -180,13 +179,11 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
h = &irq_lists[up->port.irq % NR_IRQ_HASH];
- hlist_for_each(n, h) {
- i = hlist_entry(n, struct irq_info, node);
+ hlist_for_each_entry(i, h, node)
if (i->irq == up->port.irq)
break;
- }
- if (n == NULL) {
+ if (i == NULL) {
i = kzalloc(sizeof(struct irq_info), GFP_KERNEL);
if (i == NULL) {
mutex_unlock(&hash_mutex);
@@ -220,25 +217,18 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
static void serial_unlink_irq_chain(struct uart_8250_port *up)
{
- /*
- * yes, some broken gcc emit "warning: 'i' may be used uninitialized"
- * but no, we are not going to take a patch that assigns NULL below.
- */
struct irq_info *i;
- struct hlist_node *n;
struct hlist_head *h;
mutex_lock(&hash_mutex);
h = &irq_lists[up->port.irq % NR_IRQ_HASH];
- hlist_for_each(n, h) {
- i = hlist_entry(n, struct irq_info, node);
+ hlist_for_each_entry(i, h, node)
if (i->irq == up->port.irq)
break;
- }
- BUG_ON(n == NULL);
+ BUG_ON(i == NULL);
BUG_ON(i->head == NULL);
if (list_empty(i->head))
@@ -331,9 +321,9 @@ static int univ8250_setup_irq(struct uart_8250_port *up)
* hardware interrupt, we use a timer-based system. The original
* driver used to do this with IRQ0.
*/
- if (!port->irq) {
+ if (!port->irq)
mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
- } else
+ else
retval = serial_link_irq_chain(up);
return retval;
@@ -762,6 +752,7 @@ void serial8250_suspend_port(int line)
if (!console_suspend_enabled && uart_console(port) &&
port->type != PORT_8250) {
unsigned char canary = 0xa5;
+
serial_out(up, UART_SCR, canary);
if (serial_in(up, UART_SCR) == canary)
up->canary = canary;
@@ -915,7 +906,7 @@ static struct platform_device *serial8250_isa_devs;
*/
static DEFINE_MUTEX(serial_mutex);
-static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
+static struct uart_8250_port *serial8250_find_match_or_unused(const struct uart_port *port)
{
int i;
@@ -980,7 +971,7 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work)
*
* On success the port is ready to use and the line number is returned.
*/
-int serial8250_register_8250_port(struct uart_8250_port *up)
+int serial8250_register_8250_port(const struct uart_8250_port *up)
{
struct uart_8250_port *uart;
int ret = -ENOSPC;
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index bd4e9f6ac29c..3ffeedc29c83 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -501,23 +501,27 @@ static const struct dmi_system_id exar_platforms[] = {
{}
};
+static const struct exar8250_platform *exar_get_platform(void)
+{
+ const struct dmi_system_id *dmi_match;
+
+ dmi_match = dmi_first_match(exar_platforms);
+ if (dmi_match)
+ return dmi_match->driver_data;
+
+ return &exar8250_default_platform;
+}
+
static int
pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
struct uart_8250_port *port, int idx)
{
- const struct exar8250_platform *platform;
- const struct dmi_system_id *dmi_match;
+ const struct exar8250_platform *platform = exar_get_platform();
unsigned int offset = idx * 0x400;
unsigned int baud = 7812500;
u8 __iomem *p;
int ret;
- dmi_match = dmi_first_match(exar_platforms);
- if (dmi_match)
- platform = dmi_match->driver_data;
- else
- platform = &exar8250_default_platform;
-
port->port.uartclk = baud * 16;
port->port.rs485_config = platform->rs485_config;
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 0b077b45d6a9..bce28729dd7b 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -192,6 +192,10 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
u32 tx_threshold;
int ret;
+ if (IS_ENABLED(CONFIG_SERIAL_8250_BCM7271) &&
+ of_device_is_compatible(ofdev->dev.of_node, "brcm,bcm7271-uart"))
+ return -ENODEV;
+
port_type = (unsigned long)of_device_get_match_data(&ofdev->dev);
if (port_type == PORT_UNKNOWN)
return -EINVAL;
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 8ac11eaeca51..79418d4beb48 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -43,6 +43,7 @@
#define UART_ERRATA_CLOCK_DISABLE (1 << 3)
#define UART_HAS_EFR2 BIT(4)
#define UART_HAS_RHR_IT_DIS BIT(5)
+#define UART_RX_TIMEOUT_QUIRK BIT(6)
#define OMAP_UART_FCR_RX_TRIG 6
#define OMAP_UART_FCR_TX_TRIG 4
@@ -104,6 +105,9 @@
#define UART_OMAP_EFR2 0x23
#define UART_OMAP_EFR2_TIMEOUT_BEHAVE BIT(6)
+/* RX FIFO occupancy indicator */
+#define UART_OMAP_RX_LVL 0x64
+
struct omap8250_priv {
int line;
u8 habit;
@@ -611,6 +615,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port);
static irqreturn_t omap8250_irq(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
+ struct omap8250_priv *priv = port->private_data;
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int iir;
int ret;
@@ -625,6 +630,18 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
serial8250_rpm_get(up);
iir = serial_port_in(port, UART_IIR);
ret = serial8250_handle_irq(port, iir);
+
+ /*
+ * On K3 SoCs, it is observed that RX TIMEOUT is signalled after
+ * FIFO has been drained, in which case a dummy read of RX FIFO
+ * is required to clear RX TIMEOUT condition.
+ */
+ if (priv->habit & UART_RX_TIMEOUT_QUIRK &&
+ (iir & UART_IIR_RX_TIMEOUT) == UART_IIR_RX_TIMEOUT &&
+ serial_port_in(port, UART_OMAP_RX_LVL) == 0) {
+ serial_port_in(port, UART_RX);
+ }
+
serial8250_rpm_put(up);
return IRQ_RETVAL(ret);
@@ -813,7 +830,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p)
poll_count--)
cpu_relax();
- if (!poll_count)
+ if (poll_count == -1)
dev_err(p->port.dev, "teardown incomplete\n");
}
}
@@ -1218,7 +1235,8 @@ static struct omap8250_dma_params am33xx_dma = {
static struct omap8250_platdata am654_platdata = {
.dma_params = &am654_dma,
- .habit = UART_HAS_EFR2 | UART_HAS_RHR_IT_DIS,
+ .habit = UART_HAS_EFR2 | UART_HAS_RHR_IT_DIS |
+ UART_RX_TIMEOUT_QUIRK,
};
static struct omap8250_platdata am33xx_platdata = {
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 780cc99732b6..75827b608fdb 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -2851,7 +2851,7 @@ enum pci_board_num_t {
pbn_b0_2_1843200,
pbn_b0_4_1843200,
- pbn_b0_1_4000000,
+ pbn_b0_1_3906250,
pbn_b0_bt_1_115200,
pbn_b0_bt_2_115200,
@@ -2931,10 +2931,10 @@ enum pci_board_num_t {
pbn_plx_romulus,
pbn_endrun_2_4000000,
pbn_oxsemi,
- pbn_oxsemi_1_4000000,
- pbn_oxsemi_2_4000000,
- pbn_oxsemi_4_4000000,
- pbn_oxsemi_8_4000000,
+ pbn_oxsemi_1_3906250,
+ pbn_oxsemi_2_3906250,
+ pbn_oxsemi_4_3906250,
+ pbn_oxsemi_8_3906250,
pbn_intel_i960,
pbn_sgi_ioc3,
pbn_computone_4,
@@ -2972,6 +2972,10 @@ enum pci_board_num_t {
pbn_sunix_pci_4s,
pbn_sunix_pci_8s,
pbn_sunix_pci_16s,
+ pbn_titan_1_4000000,
+ pbn_titan_2_4000000,
+ pbn_titan_4_4000000,
+ pbn_titan_8_4000000,
pbn_moxa8250_2p,
pbn_moxa8250_4p,
pbn_moxa8250_8p,
@@ -3077,10 +3081,10 @@ static struct pciserial_board pci_boards[] = {
.uart_offset = 8,
},
- [pbn_b0_1_4000000] = {
+ [pbn_b0_1_3906250] = {
.flags = FL_BASE0,
.num_ports = 1,
- .base_baud = 4000000,
+ .base_baud = 3906250,
.uart_offset = 8,
},
@@ -3475,31 +3479,31 @@ static struct pciserial_board pci_boards[] = {
.base_baud = 115200,
.uart_offset = 8,
},
- [pbn_oxsemi_1_4000000] = {
+ [pbn_oxsemi_1_3906250] = {
.flags = FL_BASE0,
.num_ports = 1,
- .base_baud = 4000000,
+ .base_baud = 3906250,
.uart_offset = 0x200,
.first_offset = 0x1000,
},
- [pbn_oxsemi_2_4000000] = {
+ [pbn_oxsemi_2_3906250] = {
.flags = FL_BASE0,
.num_ports = 2,
- .base_baud = 4000000,
+ .base_baud = 3906250,
.uart_offset = 0x200,
.first_offset = 0x1000,
},
- [pbn_oxsemi_4_4000000] = {
+ [pbn_oxsemi_4_3906250] = {
.flags = FL_BASE0,
.num_ports = 4,
- .base_baud = 4000000,
+ .base_baud = 3906250,
.uart_offset = 0x200,
.first_offset = 0x1000,
},
- [pbn_oxsemi_8_4000000] = {
+ [pbn_oxsemi_8_3906250] = {
.flags = FL_BASE0,
.num_ports = 8,
- .base_baud = 4000000,
+ .base_baud = 3906250,
.uart_offset = 0x200,
.first_offset = 0x1000,
},
@@ -3759,6 +3763,34 @@ static struct pciserial_board pci_boards[] = {
.base_baud = 921600,
.uart_offset = 0x8,
},
+ [pbn_titan_1_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_titan_2_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_titan_4_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_titan_8_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
[pbn_moxa8250_2p] = {
.flags = FL_BASE1,
.num_ports = 2,
@@ -4478,158 +4510,158 @@ static const struct pci_device_id serial_pci_tbl[] = {
*/
{ PCI_VENDOR_ID_OXSEMI, 0xc101, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_1_4000000 },
+ pbn_b0_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc105, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_1_4000000 },
+ pbn_b0_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc11b, /* OXPCIe952 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc11f, /* OXPCIe952 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc120, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_1_4000000 },
+ pbn_b0_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc124, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_1_4000000 },
+ pbn_b0_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc138, /* OXPCIe952 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc13d, /* OXPCIe952 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc140, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_1_4000000 },
+ pbn_b0_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc141, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_1_4000000 },
+ pbn_b0_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc144, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_1_4000000 },
+ pbn_b0_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc145, /* OXPCIe952 1 Legacy UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b0_1_4000000 },
+ pbn_b0_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc158, /* OXPCIe952 2 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_2_4000000 },
+ pbn_oxsemi_2_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc15d, /* OXPCIe952 2 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_2_4000000 },
+ pbn_oxsemi_2_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc208, /* OXPCIe954 4 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_4_4000000 },
+ pbn_oxsemi_4_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc20d, /* OXPCIe954 4 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_4_4000000 },
+ pbn_oxsemi_4_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc308, /* OXPCIe958 8 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_8_4000000 },
+ pbn_oxsemi_8_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc30d, /* OXPCIe958 8 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_8_4000000 },
+ pbn_oxsemi_8_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc40b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc40f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc41b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc41f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc42b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc42f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc43b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc43f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc44b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc44f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc45b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc45f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc46b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc46f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc47b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc47f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc48b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc48f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc49b, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc49f, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc4ab, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc4af, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc4bb, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc4bf, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc4cb, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_OXSEMI, 0xc4cf, /* OXPCIe200 1 Native UART */
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
/*
* Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado
*/
{ PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 Super-G3 Fax */
PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_oxsemi_1_3906250 },
{ PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */
PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0,
- pbn_oxsemi_2_4000000 },
+ pbn_oxsemi_2_3906250 },
{ PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */
PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0,
- pbn_oxsemi_4_4000000 },
+ pbn_oxsemi_4_3906250 },
{ PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */
PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0,
- pbn_oxsemi_8_4000000 },
+ pbn_oxsemi_8_3906250 },
/*
* Digi/IBM PCIe 2-port Async EIA-232 Adapter utilizing OxSemi Tornado
*/
{ PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_2_OX_IBM,
PCI_SUBVENDOR_ID_IBM, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_2_4000000 },
+ pbn_oxsemi_2_3906250 },
/*
* SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards,
@@ -4703,22 +4735,22 @@ static const struct pci_device_id serial_pci_tbl[] = {
pbn_b0_4_921600 },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_1_4000000 },
+ pbn_titan_1_4000000 },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_2_4000000 },
+ pbn_titan_2_4000000 },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_4_4000000 },
+ pbn_titan_4_4000000 },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_8_4000000 },
+ pbn_titan_8_4000000 },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_2_4000000 },
+ pbn_titan_2_4000000 },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_oxsemi_2_4000000 },
+ pbn_titan_2_4000000 },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200V3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_bt_2_921600 },
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index fc5ab2032282..2164290cbd31 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -2512,19 +2512,45 @@ static unsigned int serial8250_do_get_divisor(struct uart_port *port,
unsigned int baud,
unsigned int *frac)
{
+ upf_t magic_multiplier = port->flags & UPF_MAGIC_MULTIPLIER;
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int quot;
/*
- * Handle magic divisors for baud rates above baud_base on
- * SMSC SuperIO chips.
+ * Handle magic divisors for baud rates above baud_base on SMSC
+ * Super I/O chips. We clamp custom rates from clk/6 and clk/12
+ * up to clk/4 (0x8001) and clk/8 (0x8002) respectively. These
+ * magic divisors actually reprogram the baud rate generator's
+ * reference clock derived from chips's 14.318MHz clock input.
*
+ * Documentation claims that with these magic divisors the base
+ * frequencies of 7.3728MHz and 3.6864MHz are used respectively
+ * for the extra baud rates of 460800bps and 230400bps rather
+ * than the usual base frequency of 1.8462MHz. However empirical
+ * evidence contradicts that.
+ *
+ * Instead bit 7 of the DLM register (bit 15 of the divisor) is
+ * effectively used as a clock prescaler selection bit for the
+ * base frequency of 7.3728MHz, always used. If set to 0, then
+ * the base frequency is divided by 4 for use by the Baud Rate
+ * Generator, for the usual arrangement where the value of 1 of
+ * the divisor produces the baud rate of 115200bps. Conversely,
+ * if set to 1 and high-speed operation has been enabled with the
+ * Serial Port Mode Register in the Device Configuration Space,
+ * then the base frequency is supplied directly to the Baud Rate
+ * Generator, so for the divisor values of 0x8001, 0x8002, 0x8003,
+ * 0x8004, etc. the respective baud rates produced are 460800bps,
+ * 230400bps, 153600bps, 115200bps, etc.
+ *
+ * In all cases only low 15 bits of the divisor are used to divide
+ * the baud base and therefore 32767 is the maximum divisor value
+ * possible, even though documentation says that the programmable
+ * Baud Rate Generator is capable of dividing the internal PLL
+ * clock by any divisor from 1 to 65535.
*/
- if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
- baud == (port->uartclk/4))
+ if (magic_multiplier && baud >= port->uartclk / 6)
quot = 0x8001;
- else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
- baud == (port->uartclk/8))
+ else if (magic_multiplier && baud >= port->uartclk / 12)
quot = 0x8002;
else if (up->port.type == PORT_NPCM)
quot = npcm_get_divisor(up, baud);
@@ -2629,6 +2655,21 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
struct ktermios *old)
{
unsigned int tolerance = port->uartclk / 100;
+ unsigned int min;
+ unsigned int max;
+
+ /*
+ * Handle magic divisors for baud rates above baud_base on SMSC
+ * Super I/O chips. Enable custom rates of clk/4 and clk/8, but
+ * disable divisor values beyond 32767, which are unavailable.
+ */
+ if (port->flags & UPF_MAGIC_MULTIPLIER) {
+ min = port->uartclk / 16 / UART_DIV_MAX >> 1;
+ max = (port->uartclk + tolerance) / 4;
+ } else {
+ min = port->uartclk / 16 / UART_DIV_MAX;
+ max = (port->uartclk + tolerance) / 16;
+ }
/*
* Ask the core to calculate the divisor for us.
@@ -2636,9 +2677,7 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
* slower than nominal still match standard baud rates without
* causing transmission errors.
*/
- return uart_get_baud_rate(port, termios, old,
- port->uartclk / 16 / UART_DIV_MAX,
- (port->uartclk + tolerance) / 16);
+ return uart_get_baud_rate(port, termios, old, min, max);
}
/*
diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index 63ea9c4da3d5..dc2ef05a10eb 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -306,6 +306,7 @@ static int serial_resume(struct pcmcia_device *link)
static int serial_probe(struct pcmcia_device *link)
{
struct serial_info *info;
+ int ret;
dev_dbg(&link->dev, "serial_attach()\n");
@@ -320,7 +321,15 @@ static int serial_probe(struct pcmcia_device *link)
if (do_sound)
link->config_flags |= CONF_ENABLE_SPKR;
- return serial_config(link);
+ ret = serial_config(link);
+ if (ret)
+ goto free_info;
+
+ return 0;
+
+free_info:
+ kfree(info);
+ return ret;
}
static void serial_detach(struct pcmcia_device *link)
@@ -777,6 +786,7 @@ static const struct pcmcia_device_id serial_ids[] = {
PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e),
PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a),
PCMCIA_DEVICE_PROD_ID12("Option International", "V34bis GSM/PSTN Data/Fax Modem", 0x9d7cd6f5, 0x5cb8bf41),
+ PCMCIA_DEVICE_PROD_ID12("Option International", "GSM-Ready 56K/ISDN", 0x9d7cd6f5, 0xb23844aa),
PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab),
PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f),
PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d),
@@ -804,7 +814,6 @@ static const struct pcmcia_device_id serial_ids[] = {
PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "cis/COMpad4.cis"),
PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"),
PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"),
- PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"),
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100 1.00.", 0x19ca78af, 0xf964f42b),
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100", 0x19ca78af, 0x71d98e83),
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232 1.00.", 0x19ca78af, 0x69fb7490),
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 682f9171c82c..24282ad99d85 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1553,6 +1553,7 @@ config SERIAL_LITEUART_CONSOLE
bool "LiteUART serial port console support"
depends on SERIAL_LITEUART=y
select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
help
Say 'Y' or 'M' here if you wish to use the FPGA-based LiteUART serial
controller from LiteX SoC builder as the system console
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 78682c12156a..e14f3378b8a0 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1062,7 +1062,7 @@ static void pl011_dma_rx_poll(struct timer_list *t)
struct tty_port *port = &uap->port.state->port;
struct pl011_dmarx_data *dmarx = &uap->dmarx;
struct dma_chan *rxchan = uap->dmarx.chan;
- unsigned long flags = 0;
+ unsigned long flags;
unsigned int dmataken = 0;
unsigned int size = 0;
struct pl011_sgbuf *sgbuf;
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 1a9444b6b57e..596217d10d5c 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -149,7 +149,7 @@ static unsigned int arc_serial_tx_empty(struct uart_port *port)
/*
* Driver internal routine, used by both tty(serial core) as well as tx-isr
* -Called under spinlock in either cases
- * -also tty->stopped has already been checked
+ * -also tty->flow.stopped has already been checked
* = by uart_start( ) before calling us
* = tx_ist checks that too before calling
*/
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 058886d9045b..249ea35088d2 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -30,9 +30,9 @@
#include <linux/irq.h>
#include <linux/suspend.h>
#include <linux/mm.h>
+#include <linux/io.h>
#include <asm/div64.h>
-#include <asm/io.h>
#include <asm/ioctls.h>
#define PDC_BUFFER_SIZE 512
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index 58aaa533203b..c719aa2b1832 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -524,24 +524,7 @@ static void cpm_uart_set_termios(struct uart_port *port,
scval = 0;
/* byte size */
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- bits = 5;
- break;
- case CS6:
- bits = 6;
- break;
- case CS7:
- bits = 7;
- break;
- case CS8:
- bits = 8;
- break;
- /* Never happens, but GCC is too dumb to figure it out */
- default:
- bits = 8;
- break;
- }
+ bits = tty_get_char_size(termios->c_cflag);
sbits = bits - 5;
if (termios->c_cflag & CSTOPB) {
diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
index 4552742c3859..e9edabc5a211 100644
--- a/drivers/tty/serial/dz.c
+++ b/drivers/tty/serial/dz.c
@@ -47,8 +47,8 @@
#include <linux/tty_flip.h>
#include <linux/atomic.h>
+#include <linux/io.h>
#include <asm/bootinfo.h>
-#include <asm/io.h>
#include <asm/dec/interrupts.h>
#include <asm/dec/kn01.h>
@@ -115,7 +115,7 @@ static void dz_out(struct dz_port *dport, unsigned offset, u16 value)
* rs_stop () and rs_start ()
*
* These routines are called before setting or resetting
- * tty->stopped. They enable or disable transmitter interrupts,
+ * tty->flow.stopped. They enable or disable transmitter interrupts,
* as necessary.
* ------------------------------------------------------------
*/
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 794035041744..508128ddfa01 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -824,21 +824,18 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port)
static void lpuart_txint(struct lpuart_port *sport)
{
- unsigned long flags;
-
- spin_lock_irqsave(&sport->port.lock, flags);
+ spin_lock(&sport->port.lock);
lpuart_transmit_buffer(sport);
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ spin_unlock(&sport->port.lock);
}
static void lpuart_rxint(struct lpuart_port *sport)
{
unsigned int flg, ignored = 0, overrun = 0;
struct tty_port *port = &sport->port.state->port;
- unsigned long flags;
unsigned char rx, sr;
- spin_lock_irqsave(&sport->port.lock, flags);
+ spin_lock(&sport->port.lock);
while (!(readb(sport->port.membase + UARTSFIFO) & UARTSFIFO_RXEMPT)) {
flg = TTY_NORMAL;
@@ -850,7 +847,7 @@ static void lpuart_rxint(struct lpuart_port *sport)
sr = readb(sport->port.membase + UARTSR1);
rx = readb(sport->port.membase + UARTDR);
- if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
+ if (uart_prepare_sysrq_char(&sport->port, rx))
continue;
if (sr & (UARTSR1_PE | UARTSR1_OR | UARTSR1_FE)) {
@@ -896,28 +893,26 @@ out:
writeb(UARTSFIFO_RXOF, sport->port.membase + UARTSFIFO);
}
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ uart_unlock_and_check_sysrq(&sport->port);
tty_flip_buffer_push(port);
}
static void lpuart32_txint(struct lpuart_port *sport)
{
- unsigned long flags;
-
- spin_lock_irqsave(&sport->port.lock, flags);
+ spin_lock(&sport->port.lock);
lpuart32_transmit_buffer(sport);
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ spin_unlock(&sport->port.lock);
}
static void lpuart32_rxint(struct lpuart_port *sport)
{
unsigned int flg, ignored = 0;
struct tty_port *port = &sport->port.state->port;
- unsigned long flags;
unsigned long rx, sr;
+ bool is_break;
- spin_lock_irqsave(&sport->port.lock, flags);
+ spin_lock(&sport->port.lock);
while (!(lpuart32_read(&sport->port, UARTFIFO) & UARTFIFO_RXEMPT)) {
flg = TTY_NORMAL;
@@ -928,16 +923,29 @@ static void lpuart32_rxint(struct lpuart_port *sport)
*/
sr = lpuart32_read(&sport->port, UARTSTAT);
rx = lpuart32_read(&sport->port, UARTDATA);
- rx &= 0x3ff;
+ rx &= UARTDATA_MASK;
+
+ /*
+ * The LPUART can't distinguish between a break and a framing error,
+ * thus we assume it is a break if the received data is zero.
+ */
+ is_break = (sr & UARTSTAT_FE) && !rx;
- if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
+ if (is_break && uart_handle_break(&sport->port))
+ continue;
+
+ if (uart_prepare_sysrq_char(&sport->port, rx))
continue;
if (sr & (UARTSTAT_PE | UARTSTAT_OR | UARTSTAT_FE)) {
- if (sr & UARTSTAT_PE)
- sport->port.icount.parity++;
- else if (sr & UARTSTAT_FE)
+ if (sr & UARTSTAT_PE) {
+ if (is_break)
+ sport->port.icount.brk++;
+ else
+ sport->port.icount.parity++;
+ } else if (sr & UARTSTAT_FE) {
sport->port.icount.frame++;
+ }
if (sr & UARTSTAT_OR)
sport->port.icount.overrun++;
@@ -950,22 +958,24 @@ static void lpuart32_rxint(struct lpuart_port *sport)
sr &= sport->port.read_status_mask;
- if (sr & UARTSTAT_PE)
- flg = TTY_PARITY;
- else if (sr & UARTSTAT_FE)
+ if (sr & UARTSTAT_PE) {
+ if (is_break)
+ flg = TTY_BREAK;
+ else
+ flg = TTY_PARITY;
+ } else if (sr & UARTSTAT_FE) {
flg = TTY_FRAME;
+ }
if (sr & UARTSTAT_OR)
flg = TTY_OVERRUN;
-
- sport->port.sysrq = 0;
}
tty_insert_flip_char(port, rx, flg);
}
out:
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ uart_unlock_and_check_sysrq(&sport->port);
tty_flip_buffer_push(port);
}
@@ -1393,58 +1403,54 @@ static int lpuart32_config_rs485(struct uart_port *port,
static unsigned int lpuart_get_mctrl(struct uart_port *port)
{
- unsigned int temp = 0;
- unsigned char reg;
-
- reg = readb(port->membase + UARTMODEM);
- if (reg & UARTMODEM_TXCTSE)
- temp |= TIOCM_CTS;
+ unsigned int mctrl = 0;
+ u8 reg;
- if (reg & UARTMODEM_RXRTSE)
- temp |= TIOCM_RTS;
+ reg = readb(port->membase + UARTCR1);
+ if (reg & UARTCR1_LOOPS)
+ mctrl |= TIOCM_LOOP;
- return temp;
+ return mctrl;
}
static unsigned int lpuart32_get_mctrl(struct uart_port *port)
{
- unsigned int temp = 0;
- unsigned long reg;
-
- reg = lpuart32_read(port, UARTMODIR);
- if (reg & UARTMODIR_TXCTSE)
- temp |= TIOCM_CTS;
+ unsigned int mctrl = 0;
+ u32 reg;
- if (reg & UARTMODIR_RXRTSE)
- temp |= TIOCM_RTS;
+ reg = lpuart32_read(port, UARTCTRL);
+ if (reg & UARTCTRL_LOOPS)
+ mctrl |= TIOCM_LOOP;
- return temp;
+ return mctrl;
}
static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- unsigned char temp;
- struct lpuart_port *sport = container_of(port,
- struct lpuart_port, port);
+ u8 reg;
- /* Make sure RXRTSE bit is not set when RS485 is enabled */
- if (!(sport->port.rs485.flags & SER_RS485_ENABLED)) {
- temp = readb(sport->port.membase + UARTMODEM) &
- ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE);
+ reg = readb(port->membase + UARTCR1);
- if (mctrl & TIOCM_RTS)
- temp |= UARTMODEM_RXRTSE;
+ /* for internal loopback we need LOOPS=1 and RSRC=0 */
+ reg &= ~(UARTCR1_LOOPS | UARTCR1_RSRC);
+ if (mctrl & TIOCM_LOOP)
+ reg |= UARTCR1_LOOPS;
- if (mctrl & TIOCM_CTS)
- temp |= UARTMODEM_TXCTSE;
-
- writeb(temp, port->membase + UARTMODEM);
- }
+ writeb(reg, port->membase + UARTCR1);
}
static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
+ u32 reg;
+
+ reg = lpuart32_read(port, UARTCTRL);
+ /* for internal loopback we need LOOPS=1 and RSRC=0 */
+ reg &= ~(UARTCTRL_LOOPS | UARTCTRL_RSRC);
+ if (mctrl & TIOCM_LOOP)
+ reg |= UARTCTRL_LOOPS;
+
+ lpuart32_write(port, reg, UARTCTRL);
}
static void lpuart_break_ctl(struct uart_port *port, int break_state)
@@ -1581,6 +1587,9 @@ static void lpuart_tx_dma_startup(struct lpuart_port *sport)
u32 uartbaud;
int ret;
+ if (uart_console(&sport->port))
+ goto err;
+
if (!sport->dma_tx_chan)
goto err;
@@ -1610,6 +1619,9 @@ static void lpuart_rx_dma_startup(struct lpuart_port *sport)
int ret;
unsigned char cr3;
+ if (uart_console(&sport->port))
+ goto err;
+
if (!sport->dma_rx_chan)
goto err;
@@ -1625,7 +1637,7 @@ static void lpuart_rx_dma_startup(struct lpuart_port *sport)
sport->lpuart_dma_rx_use = true;
rx_dma_timer_init(sport);
- if (sport->port.has_sysrq) {
+ if (sport->port.has_sysrq && !lpuart_is_32(sport)) {
cr3 = readb(sport->port.membase + UARTCR3);
cr3 |= UARTCR3_FEIE;
writeb(cr3, sport->port.membase + UARTCR3);
@@ -2278,7 +2290,7 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count)
unsigned long flags;
int locked = 1;
- if (sport->port.sysrq || oops_in_progress)
+ if (oops_in_progress)
locked = spin_trylock_irqsave(&sport->port.lock, flags);
else
spin_lock_irqsave(&sport->port.lock, flags);
@@ -2308,7 +2320,7 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count)
unsigned long flags;
int locked = 1;
- if (sport->port.sysrq || oops_in_progress)
+ if (oops_in_progress)
locked = spin_trylock_irqsave(&sport->port.lock, flags);
else
spin_lock_irqsave(&sport->port.lock, flags);
@@ -2414,6 +2426,9 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
bd = lpuart32_read(&sport->port, UARTBAUD);
bd &= UARTBAUD_SBR_MASK;
+ if (!bd)
+ return;
+
sbr = bd;
uartclk = lpuart_get_baud_clk_rate(sport);
/*
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index 9e9abfc4824a..03a2fe9f4c9a 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -37,7 +37,7 @@
#include <linux/firmware.h>
#include <linux/bitops.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <linux/uaccess.h>
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 7d5a8dfa3e91..8b121cd869e9 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -225,6 +225,8 @@ struct imx_port {
struct scatterlist rx_sgl, tx_sgl[2];
void *rx_buf;
struct circ_buf rx_ring;
+ unsigned int rx_buf_size;
+ unsigned int rx_period_length;
unsigned int rx_periods;
dma_cookie_t rx_cookie;
unsigned int tx_bytes;
@@ -1183,10 +1185,6 @@ static void imx_uart_dma_rx_callback(void *data)
}
}
-/* RX DMA buffer periods */
-#define RX_DMA_PERIODS 16
-#define RX_BUF_SIZE (RX_DMA_PERIODS * PAGE_SIZE / 4)
-
static int imx_uart_start_rx_dma(struct imx_port *sport)
{
struct scatterlist *sgl = &sport->rx_sgl;
@@ -1197,9 +1195,8 @@ static int imx_uart_start_rx_dma(struct imx_port *sport)
sport->rx_ring.head = 0;
sport->rx_ring.tail = 0;
- sport->rx_periods = RX_DMA_PERIODS;
- sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE);
+ sg_init_one(sgl, sport->rx_buf, sport->rx_buf_size);
ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE);
if (ret == 0) {
dev_err(dev, "DMA mapping error for RX.\n");
@@ -1316,7 +1313,8 @@ static int imx_uart_dma_init(struct imx_port *sport)
goto err;
}
- sport->rx_buf = kzalloc(RX_BUF_SIZE, GFP_KERNEL);
+ sport->rx_buf_size = sport->rx_period_length * sport->rx_periods;
+ sport->rx_buf = kzalloc(sport->rx_buf_size, GFP_KERNEL);
if (!sport->rx_buf) {
ret = -ENOMEM;
goto err;
@@ -1975,8 +1973,8 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count)
{
struct imx_port *sport = imx_uart_ports[co->index];
struct imx_port_ucrs old_ucr;
+ unsigned long flags;
unsigned int ucr1;
- unsigned long flags = 0;
int locked = 1;
if (sport->port.sysrq)
@@ -2179,11 +2177,16 @@ static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t)
return HRTIMER_NORESTART;
}
+/* Default RX DMA buffer configuration */
+#define RX_DMA_PERIODS 16
+#define RX_DMA_PERIOD_LEN (PAGE_SIZE / 4)
+
static int imx_uart_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct imx_port *sport;
void __iomem *base;
+ u32 dma_buf_conf[2];
int ret = 0;
u32 ucr1;
struct resource *res;
@@ -2218,6 +2221,14 @@ static int imx_uart_probe(struct platform_device *pdev)
if (of_get_property(np, "fsl,inverted-rx", NULL))
sport->inverted_rx = 1;
+ if (!of_property_read_u32_array(np, "fsl,dma-info", dma_buf_conf, 2)) {
+ sport->rx_period_length = dma_buf_conf[0];
+ sport->rx_periods = dma_buf_conf[1];
+ } else {
+ sport->rx_period_length = RX_DMA_PERIOD_LEN;
+ sport->rx_periods = RX_DMA_PERIODS;
+ }
+
if (sport->port.line >= ARRAY_SIZE(imx_uart_ports)) {
dev_err(&pdev->dev, "serial%d out of range\n",
sport->port.line);
diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c
index 86fff69d7e7c..f4dc5fe4ba92 100644
--- a/drivers/tty/serial/ip22zilog.c
+++ b/drivers/tty/serial/ip22zilog.c
@@ -31,7 +31,7 @@
#include <linux/spinlock.h>
#include <linux/init.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <asm/sgialib.h>
#include <asm/sgi/ioc.h>
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
index db059b66438e..3e7c6ee8e4b3 100644
--- a/drivers/tty/serial/kgdb_nmi.c
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -115,7 +115,7 @@ static void kgdb_tty_recv(int ch)
static int kgdb_nmi_poll_one_knock(void)
{
static int n;
- int c = -1;
+ int c;
const char *magic = kgdb_nmi_magic;
size_t m = strlen(magic);
bool printch = false;
@@ -298,7 +298,7 @@ static void kgdb_nmi_tty_hangup(struct tty_struct *tty)
tty_port_hangup(&priv->port);
}
-static int kgdb_nmi_tty_write_room(struct tty_struct *tty)
+static unsigned int kgdb_nmi_tty_write_room(struct tty_struct *tty)
{
/* Actually, we can handle any amount as we use polled writes. */
return 2048;
diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c
index 0b06770642cb..dbc0559a9157 100644
--- a/drivers/tty/serial/liteuart.c
+++ b/drivers/tty/serial/liteuart.c
@@ -370,6 +370,27 @@ static int __init liteuart_console_init(void)
return 0;
}
console_initcall(liteuart_console_init);
+
+static void early_liteuart_write(struct console *console, const char *s,
+ unsigned int count)
+{
+ struct earlycon_device *device = console->data;
+ struct uart_port *port = &device->port;
+
+ uart_console_write(port, s, count, liteuart_putchar);
+}
+
+static int __init early_liteuart_setup(struct earlycon_device *device,
+ const char *options)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = early_liteuart_write;
+ return 0;
+}
+
+OF_EARLYCON_DECLARE(liteuart, "litex,liteuart", early_liteuart_setup);
#endif /* CONFIG_SERIAL_LITEUART_CONSOLE */
static int __init liteuart_init(void)
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 3cbc757d7be7..0c1e4df52215 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -552,7 +552,7 @@ static int max310x_update_best_err(unsigned long f, long *besterr)
return 1;
}
-static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
+static u32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
unsigned long freq, bool xtal)
{
unsigned int div, clksrc, pllcfg = 0;
@@ -618,7 +618,7 @@ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
}
}
- return (int)bestfreq;
+ return bestfreq;
}
static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len)
@@ -1253,9 +1253,10 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype,
struct regmap *regmap, int irq)
{
- int i, ret, fmin, fmax, freq, uartclk;
+ int i, ret, fmin, fmax, freq;
struct max310x_port *s;
- bool xtal = false;
+ u32 uartclk = 0;
+ bool xtal;
if (IS_ERR(regmap))
return PTR_ERR(regmap);
@@ -1267,24 +1268,20 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
return -ENOMEM;
}
+ /* Always ask for fixed clock rate from a property. */
+ device_property_read_u32(dev, "clock-frequency", &uartclk);
+
s->clk = devm_clk_get_optional(dev, "osc");
if (IS_ERR(s->clk))
return PTR_ERR(s->clk);
if (s->clk) {
- fmin = 500000;
- fmax = 35000000;
+ xtal = false;
} else {
s->clk = devm_clk_get_optional(dev, "xtal");
if (IS_ERR(s->clk))
return PTR_ERR(s->clk);
- if (s->clk) {
- fmin = 1000000;
- fmax = 4000000;
- xtal = true;
- } else {
- dev_err(dev, "Cannot get clock\n");
- return -EINVAL;
- }
+
+ xtal = true;
}
ret = clk_prepare_enable(s->clk);
@@ -1292,6 +1289,21 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
return ret;
freq = clk_get_rate(s->clk);
+ if (freq == 0)
+ freq = uartclk;
+ if (freq == 0) {
+ dev_err(dev, "Cannot get clock rate\n");
+ return -EINVAL;
+ }
+
+ if (xtal) {
+ fmin = 1000000;
+ fmax = 4000000;
+ } else {
+ fmin = 500000;
+ fmax = 35000000;
+ }
+
/* Check frequency limits */
if (freq < fmin || freq > fmax) {
ret = -ERANGE;
diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
index 529cd0289056..efee3935917f 100644
--- a/drivers/tty/serial/meson_uart.c
+++ b/drivers/tty/serial/meson_uart.c
@@ -715,13 +715,15 @@ static int meson_uart_probe(struct platform_device *pdev)
{
struct resource *res_mem, *res_irq;
struct uart_port *port;
+ u32 fifosize = 64; /* Default is 64, 128 for EE UART_0 */
int ret = 0;
- int id = -1;
if (pdev->dev.of_node)
pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
if (pdev->id < 0) {
+ int id;
+
for (id = AML_UART_PORT_OFFSET; id < AML_UART_PORT_NUM; id++) {
if (!meson_ports[id]) {
pdev->id = id;
@@ -741,6 +743,8 @@ static int meson_uart_probe(struct platform_device *pdev)
if (!res_irq)
return -ENODEV;
+ of_property_read_u32(pdev->dev.of_node, "fifo-size", &fifosize);
+
if (meson_ports[pdev->id]) {
dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
return -EBUSY;
@@ -770,7 +774,7 @@ static int meson_uart_probe(struct platform_device *pdev)
port->type = PORT_MESON;
port->x_char = 0;
port->ops = &meson_uart_ops;
- port->fifosize = 64;
+ port->fifosize = fifosize;
meson_ports[pdev->id] = port;
platform_set_drvdata(pdev, port);
diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c
index 47ab280f553b..be640d9863cd 100644
--- a/drivers/tty/serial/mux.c
+++ b/drivers/tty/serial/mux.c
@@ -21,7 +21,7 @@
#include <linux/console.h>
#include <linux/delay.h> /* for udelay */
#include <linux/device.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <asm/parisc-device.h>
diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index 51b0ecabf2ec..231de29a6452 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -128,7 +128,6 @@ struct mvebu_uart {
struct uart_port *port;
struct clk *clk;
int irq[UART_IRQ_COUNT];
- unsigned char __iomem *nb;
struct mvebu_uart_driver_data *data;
#if defined(CONFIG_PM)
struct mvebu_uart_pm_regs pm_regs;
@@ -445,12 +444,11 @@ static void mvebu_uart_shutdown(struct uart_port *port)
static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
{
- struct mvebu_uart *mvuart = to_mvuart(port);
unsigned int d_divisor, m_divisor;
u32 brdv, osamp;
- if (IS_ERR(mvuart->clk))
- return -PTR_ERR(mvuart->clk);
+ if (!port->uartclk)
+ return -EOPNOTSUPP;
/*
* The baudrate is derived from the UART clock thanks to two divisors:
@@ -463,7 +461,7 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
* makes use of D to configure the desired baudrate.
*/
m_divisor = OSAMP_DEFAULT_DIVISOR;
- d_divisor = DIV_ROUND_UP(port->uartclk, baud * m_divisor);
+ d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
brdv = readl(port->membase + UART_BRDV);
brdv &= ~BRDV_BAUD_MASK;
@@ -482,7 +480,7 @@ static void mvebu_uart_set_termios(struct uart_port *port,
struct ktermios *old)
{
unsigned long flags;
- unsigned int baud;
+ unsigned int baud, min_baud, max_baud;
spin_lock_irqsave(&port->lock, flags);
@@ -501,16 +499,21 @@ static void mvebu_uart_set_termios(struct uart_port *port,
port->ignore_status_mask |= STAT_RX_RDY(port) | STAT_BRK_ERR;
/*
+ * Maximal divisor is 1023 * 16 when using default (x16) scheme.
* Maximum achievable frequency with simple baudrate divisor is 230400.
* Since the error per bit frame would be of more than 15%, achieving
* higher frequencies would require to implement the fractional divisor
* feature.
*/
- baud = uart_get_baud_rate(port, termios, old, 0, 230400);
+ min_baud = DIV_ROUND_UP(port->uartclk, 1023 * 16);
+ max_baud = 230400;
+
+ baud = uart_get_baud_rate(port, termios, old, min_baud, max_baud);
if (mvebu_uart_baud_rate_set(port, baud)) {
/* No clock available, baudrate cannot be changed */
if (old)
- baud = uart_get_baud_rate(port, old, NULL, 0, 230400);
+ baud = uart_get_baud_rate(port, old, NULL,
+ min_baud, max_baud);
} else {
tty_termios_encode_baud_rate(termios, baud, baud);
uart_update_timeout(port, termios->c_cflag, baud);
@@ -617,7 +620,7 @@ static void mvebu_uart_putc(struct uart_port *port, int c)
static void mvebu_uart_putc_early_write(struct console *con,
const char *s,
- unsigned n)
+ unsigned int n)
{
struct earlycon_device *dev = con->data;
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index f414d6acad69..ac45f3386e97 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -87,7 +87,7 @@
#define AUART_LINECTRL_BAUD_DIVFRAC(v) (((v) & 0x3f) << 8)
#define AUART_LINECTRL_SPS (1 << 7)
#define AUART_LINECTRL_WLEN_MASK 0x00000060
-#define AUART_LINECTRL_WLEN(v) (((v) & 0x3) << 5)
+#define AUART_LINECTRL_WLEN(v) ((((v) - 5) & 0x3) << 5)
#define AUART_LINECTRL_FEN (1 << 4)
#define AUART_LINECTRL_STP2 (1 << 3)
#define AUART_LINECTRL_EPS (1 << 2)
@@ -962,7 +962,7 @@ static void mxs_auart_settermios(struct uart_port *u,
struct ktermios *old)
{
struct mxs_auart_port *s = to_auart_port(u);
- u32 bm, ctrl, ctrl2, div;
+ u32 ctrl, ctrl2, div;
unsigned int cflag, baud, baud_min, baud_max;
cflag = termios->c_cflag;
@@ -970,25 +970,7 @@ static void mxs_auart_settermios(struct uart_port *u,
ctrl = AUART_LINECTRL_FEN;
ctrl2 = mxs_read(s, REG_CTRL2);
- /* byte size */
- switch (cflag & CSIZE) {
- case CS5:
- bm = 0;
- break;
- case CS6:
- bm = 1;
- break;
- case CS7:
- bm = 2;
- break;
- case CS8:
- bm = 3;
- break;
- default:
- return;
- }
-
- ctrl |= AUART_LINECTRL_WLEN(bm);
+ ctrl |= AUART_LINECTRL_WLEN(tty_get_char_size(cflag));
/* parity */
if (cflag & PARENB) {
@@ -1403,7 +1385,7 @@ auart_console_get_options(struct mxs_auart_port *s, int *baud,
*parity = 'o';
}
- if ((lcr_h & AUART_LINECTRL_WLEN_MASK) == AUART_LINECTRL_WLEN(2))
+ if ((lcr_h & AUART_LINECTRL_WLEN_MASK) == AUART_LINECTRL_WLEN(7))
*bits = 7;
else
*bits = 8;
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 84e8158088cd..9e81b09ba08e 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -626,7 +626,7 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id)
static unsigned int serial_omap_tx_empty(struct uart_port *port)
{
struct uart_omap_port *up = to_uart_omap_port(port);
- unsigned long flags = 0;
+ unsigned long flags;
unsigned int ret = 0;
pm_runtime_get_sync(up->dev);
@@ -704,7 +704,7 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void serial_omap_break_ctl(struct uart_port *port, int break_state)
{
struct uart_omap_port *up = to_uart_omap_port(port);
- unsigned long flags = 0;
+ unsigned long flags;
dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line);
pm_runtime_get_sync(up->dev);
@@ -722,7 +722,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
static int serial_omap_startup(struct uart_port *port)
{
struct uart_omap_port *up = to_uart_omap_port(port);
- unsigned long flags = 0;
+ unsigned long flags;
int retval;
/*
@@ -797,7 +797,7 @@ static int serial_omap_startup(struct uart_port *port)
static void serial_omap_shutdown(struct uart_port *port)
{
struct uart_omap_port *up = to_uart_omap_port(port);
- unsigned long flags = 0;
+ unsigned long flags;
dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->port.line);
@@ -845,7 +845,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned char cval = 0;
- unsigned long flags = 0;
+ unsigned long flags;
unsigned int baud, quot;
switch (termios->c_cflag & CSIZE) {
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index d6aef8a1f0a4..12ce150b0ad4 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -47,7 +47,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <asm/sections.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#ifdef CONFIG_PPC_PMAC
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index 23d729ed3bf6..aedc38893e6c 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -1050,21 +1050,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
}
/* bits per char */
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- bits_per_char = 5;
- break;
- case CS6:
- bits_per_char = 6;
- break;
- case CS7:
- bits_per_char = 7;
- break;
- case CS8:
- default:
- bits_per_char = 8;
- break;
- }
+ bits_per_char = tty_get_char_size(termios->c_cflag);
/* stop bits */
if (termios->c_cflag & CSTOPB)
@@ -1338,7 +1324,7 @@ static const struct uart_ops qcom_geni_uart_pops = {
static int qcom_geni_serial_probe(struct platform_device *pdev)
{
int ret = 0;
- int line = -1;
+ int line;
struct qcom_geni_serial_port *port;
struct uart_port *uport;
struct resource *res;
@@ -1354,7 +1340,9 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
line = of_alias_get_id(pdev->dev.of_node, "serial");
} else {
drv = &qcom_geni_uart_driver;
- line = of_alias_get_id(pdev->dev.of_node, "hsuart");
+ line = of_alias_get_id(pdev->dev.of_node, "serial");
+ if (line == -ENODEV) /* compat with non-standard aliases */
+ line = of_alias_get_id(pdev->dev.of_node, "hsuart");
}
port = get_port_from_line(line, console);
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index d9e4b67a12a0..9fbc61151c2e 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -2220,8 +2220,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
default:
dev_warn(&pdev->dev, "unsupported reg-io-width (%d)\n",
prop);
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
}
}
diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c
index 22c7bc90b104..738df6d9c0d9 100644
--- a/drivers/tty/serial/sb1250-duart.c
+++ b/drivers/tty/serial/sb1250-duart.c
@@ -34,7 +34,7 @@
#include <linux/types.h>
#include <linux/refcount.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/sibyte/sb1250.h>
#include <asm/sibyte/sb1250_uart.h>
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 9adb8362578c..acbb615dd28f 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -1208,8 +1208,16 @@ static int sc16is7xx_probe(struct device *dev,
/* Always ask for fixed clock rate from a property. */
device_property_read_u32(dev, "clock-frequency", &uartclk);
- s->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(s->clk)) {
+ s->clk = devm_clk_get_optional(dev, NULL);
+ if (IS_ERR(s->clk))
+ return PTR_ERR(s->clk);
+
+ ret = clk_prepare_enable(s->clk);
+ if (ret)
+ return ret;
+
+ freq = clk_get_rate(s->clk);
+ if (freq == 0) {
if (uartclk)
freq = uartclk;
if (pfreq)
@@ -1217,13 +1225,7 @@ static int sc16is7xx_probe(struct device *dev,
if (freq)
dev_dbg(dev, "Clock frequency: %luHz\n", freq);
else
- return PTR_ERR(s->clk);
- } else {
- ret = clk_prepare_enable(s->clk);
- if (ret)
- return ret;
-
- freq = clk_get_rate(s->clk);
+ return -EINVAL;
}
s->regmap = regmap;
@@ -1358,8 +1360,7 @@ out_thread:
kthread_stop(s->kworker_task);
out_clk:
- if (!IS_ERR(s->clk))
- clk_disable_unprepare(s->clk);
+ clk_disable_unprepare(s->clk);
return ret;
}
@@ -1383,8 +1384,7 @@ static int sc16is7xx_remove(struct device *dev)
kthread_flush_worker(&s->kworker);
kthread_stop(s->kworker_task);
- if (!IS_ERR(s->clk))
- clk_disable_unprepare(s->clk);
+ clk_disable_unprepare(s->clk);
return 0;
}
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 18ff85a83f80..69092deba11f 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -184,8 +184,8 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
int init_hw)
{
struct uart_port *uport = uart_port_check(state);
+ unsigned long flags;
unsigned long page;
- unsigned long flags = 0;
int retval = 0;
if (uport->type == PORT_UNKNOWN)
@@ -275,7 +275,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
{
struct uart_port *uport = uart_port_check(state);
struct tty_port *port = &state->port;
- unsigned long flags = 0;
+ unsigned long flags;
char *xmit_buf = NULL;
/*
@@ -334,39 +334,15 @@ void
uart_update_timeout(struct uart_port *port, unsigned int cflag,
unsigned int baud)
{
- unsigned int bits;
+ unsigned int size;
- /* byte size and parity */
- switch (cflag & CSIZE) {
- case CS5:
- bits = 7;
- break;
- case CS6:
- bits = 8;
- break;
- case CS7:
- bits = 9;
- break;
- default:
- bits = 10;
- break; /* CS8 */
- }
-
- if (cflag & CSTOPB)
- bits++;
- if (cflag & PARENB)
- bits++;
-
- /*
- * The total number of bits to be transmitted in the fifo.
- */
- bits = bits * port->fifosize;
+ size = tty_get_frame_size(cflag) * port->fifosize;
/*
* Figure the timeout to send the above number of bits.
* Add .02 seconds of slop
*/
- port->timeout = (HZ * bits) / baud + HZ/50;
+ port->timeout = (HZ * size) / baud + HZ/50;
}
EXPORT_SYMBOL(uart_update_timeout);
@@ -616,12 +592,12 @@ static int uart_write(struct tty_struct *tty,
return ret;
}
-static int uart_write_room(struct tty_struct *tty)
+static unsigned int uart_write_room(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port;
unsigned long flags;
- int ret;
+ unsigned int ret;
port = uart_port_lock(state, flags);
ret = uart_circ_chars_free(&state->xmit);
@@ -629,12 +605,12 @@ static int uart_write_room(struct tty_struct *tty)
return ret;
}
-static int uart_chars_in_buffer(struct tty_struct *tty)
+static unsigned int uart_chars_in_buffer(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port;
unsigned long flags;
- int ret;
+ unsigned int ret;
port = uart_port_lock(state, flags);
ret = uart_circ_chars_pending(&state->xmit);
@@ -3029,26 +3005,28 @@ out:
/*
* Are the two ports equivalent?
*/
-int uart_match_port(struct uart_port *port1, struct uart_port *port2)
+bool uart_match_port(const struct uart_port *port1,
+ const struct uart_port *port2)
{
if (port1->iotype != port2->iotype)
- return 0;
+ return false;
switch (port1->iotype) {
case UPIO_PORT:
- return (port1->iobase == port2->iobase);
+ return port1->iobase == port2->iobase;
case UPIO_HUB6:
- return (port1->iobase == port2->iobase) &&
- (port1->hub6 == port2->hub6);
+ return port1->iobase == port2->iobase &&
+ port1->hub6 == port2->hub6;
case UPIO_MEM:
case UPIO_MEM16:
case UPIO_MEM32:
case UPIO_MEM32BE:
case UPIO_AU:
case UPIO_TSI:
- return (port1->mapbase == port2->mapbase);
+ return port1->mapbase == port2->mapbase;
}
- return 0;
+
+ return false;
}
EXPORT_SYMBOL(uart_match_port);
diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c
index 0a7e5b74bc1d..aaca4fe38486 100644
--- a/drivers/tty/serial/serial_txx9.c
+++ b/drivers/tty/serial/serial_txx9.c
@@ -24,7 +24,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <asm/io.h>
+#include <linux/io.h>
static char *serial_version = "1.11";
static char *serial_name = "TX39/49 Serial driver";
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 4baf1316ea72..07eb56294371 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -289,7 +289,7 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
},
/*
- * The "SCIFA" that is in RZ/T and RZ/A2.
+ * The "SCIFA" that is in RZ/A2, RZ/G2L and RZ/T.
* It looks like a normal SCIF with FIFO data, but with a
* compressed address space. Also, the break out of interrupts
* are different: ERI/BRI, RXI, TXI, TEI, DRI.
@@ -306,6 +306,7 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
[SCFDR] = { 0x0E, 16 },
[SCSPTR] = { 0x10, 16 },
[SCLSR] = { 0x12, 16 },
+ [SEMR] = { 0x14, 8 },
},
.fifosize = 16,
.overrun_reg = SCLSR,
@@ -610,6 +611,14 @@ static void sci_stop_tx(struct uart_port *port)
ctrl &= ~SCSCR_TIE;
serial_port_out(port, SCSCR, ctrl);
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+ if (to_sci_port(port)->chan_tx &&
+ !dma_submit_error(to_sci_port(port)->cookie_tx)) {
+ dmaengine_terminate_async(to_sci_port(port)->chan_tx);
+ to_sci_port(port)->cookie_tx = -EINVAL;
+ }
+#endif
}
static void sci_start_rx(struct uart_port *port)
@@ -840,9 +849,6 @@ static void sci_transmit_chars(struct uart_port *port)
}
-/* On SH3, SCIF may read end-of-break as a space->mark char */
-#define STEPFN(c) ({int __c = (c); (((__c-1)|(__c)) == -1); })
-
static void sci_receive_chars(struct uart_port *port)
{
struct tty_port *tport = &port->state->port;
@@ -2494,25 +2500,10 @@ done:
uart_update_timeout(port, termios->c_cflag, baud);
/* byte size and parity */
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- bits = 7;
- break;
- case CS6:
- bits = 8;
- break;
- case CS7:
- bits = 9;
- break;
- default:
- bits = 10;
- break;
- }
+ bits = tty_get_frame_size(termios->c_cflag);
- if (termios->c_cflag & CSTOPB)
- bits++;
- if (termios->c_cflag & PARENB)
- bits++;
+ if (sci_getreg(port, SEMR)->size)
+ serial_port_out(port, SEMR, 0);
if (best_clk >= 0) {
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
@@ -3170,6 +3161,10 @@ static const struct of_device_id of_sci_match[] = {
.compatible = "renesas,scif-r7s9210",
.data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
},
+ {
+ .compatible = "renesas,scif-r9a07g044",
+ .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
+ },
/* Family-specific types */
{
.compatible = "renesas,rcar-gen1-scif",
@@ -3452,6 +3447,7 @@ static int __init rzscifa_early_console_setup(struct earlycon_device *device,
port_cfg.regtype = SCIx_RZ_SCIFA_REGTYPE;
return early_console_setup(device, PORT_SCIF);
}
+
static int __init scifa_early_console_setup(struct earlycon_device *device,
const char *opt)
{
@@ -3471,6 +3467,7 @@ static int __init hscif_early_console_setup(struct earlycon_device *device,
OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif-r7s9210", rzscifa_early_console_setup);
+OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a07g044", rzscifa_early_console_setup);
OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup);
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index c0dfe4382898..c0ae78632dda 100644
--- a/drivers/tty/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
@@ -31,6 +31,7 @@ enum {
SCCKS, /* BRG Clock Select Register */
HSRTRGR, /* Rx FIFO Data Count Trigger Register */
HSTTRGR, /* Tx FIFO Data Count Trigger Register */
+ SEMR, /* Serial extended mode register */
SCIx_NR_REGS,
};
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index e7048515a79c..87e480cc8206 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -65,7 +65,7 @@ static struct uart_driver asc_uart_driver;
/* ASC_RXBUF */
#define ASC_RXBUF_PE 0x100
#define ASC_RXBUF_FE 0x200
-/**
+/*
* Some of status comes from higher bits of the character and some come from
* the status register. Combining both of them in to single status using dummy
* bits.
@@ -478,7 +478,7 @@ static void asc_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct asc_port *ascport = to_asc_port(port);
- unsigned long flags = 0;
+ unsigned long flags;
u32 ctl;
switch (state) {
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index c2ae7b392b86..ef793b3b4591 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -718,36 +718,6 @@ static void stm32_usart_shutdown(struct uart_port *port)
free_irq(port->irq, port);
}
-static unsigned int stm32_usart_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_usart_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
@@ -805,7 +775,7 @@ static void stm32_usart_set_termios(struct uart_port *port,
if (cflag & CSTOPB)
cr2 |= USART_CR2_STOP_2B;
- bits = stm32_usart_get_databits(termios);
+ bits = tty_get_char_size(cflag);
stm32_port->rdr_mask = (BIT(bits) - 1);
if (cflag & PARENB) {
@@ -980,7 +950,7 @@ static void stm32_usart_pm(struct uart_port *port, unsigned int state,
struct stm32_port, port);
const struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
const struct stm32_usart_config *cfg = &stm32port->info->cfg;
- unsigned long flags = 0;
+ unsigned long flags;
switch (state) {
case UART_PM_STATE_ON:
@@ -1182,6 +1152,14 @@ static const struct of_device_id stm32_match[] = {
MODULE_DEVICE_TABLE(of, stm32_match);
#endif
+static void stm32_usart_of_dma_rx_remove(struct stm32_port *stm32port,
+ struct platform_device *pdev)
+{
+ if (stm32port->rx_buf)
+ dma_free_coherent(&pdev->dev, RX_BUF_L, stm32port->rx_buf,
+ stm32port->rx_dma_buf);
+}
+
static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port,
struct platform_device *pdev)
{
@@ -1199,19 +1177,11 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port,
if (uart_console(port))
return -ENODEV;
- /* Request DMA RX channel */
- stm32port->rx_ch = dma_request_slave_channel(dev, "rx");
- if (!stm32port->rx_ch) {
- dev_info(dev, "rx dma alloc failed\n");
- return -ENODEV;
- }
stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L,
&stm32port->rx_dma_buf,
GFP_KERNEL);
- if (!stm32port->rx_buf) {
- ret = -ENOMEM;
- goto alloc_err;
- }
+ if (!stm32port->rx_buf)
+ return -ENOMEM;
/* Configure DMA channel */
memset(&config, 0, sizeof(config));
@@ -1221,8 +1191,8 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port,
ret = dmaengine_slave_config(stm32port->rx_ch, &config);
if (ret < 0) {
dev_err(dev, "rx dma channel config failed\n");
- ret = -ENODEV;
- goto config_err;
+ stm32_usart_of_dma_rx_remove(stm32port, pdev);
+ return ret;
}
/* Prepare a DMA cyclic transaction */
@@ -1232,8 +1202,8 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port,
DMA_PREP_INTERRUPT);
if (!desc) {
dev_err(dev, "rx dma prep cyclic failed\n");
- ret = -ENODEV;
- goto config_err;
+ stm32_usart_of_dma_rx_remove(stm32port, pdev);
+ return -ENODEV;
}
/* No callback as dma buffer is drained on usart interrupt */
@@ -1244,24 +1214,22 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port,
ret = dma_submit_error(dmaengine_submit(desc));
if (ret) {
dmaengine_terminate_sync(stm32port->rx_ch);
- goto config_err;
+ stm32_usart_of_dma_rx_remove(stm32port, pdev);
+ return ret;
}
/* Issue pending DMA requests */
dma_async_issue_pending(stm32port->rx_ch);
return 0;
+}
-config_err:
- dma_free_coherent(&pdev->dev,
- RX_BUF_L, stm32port->rx_buf,
- stm32port->rx_dma_buf);
-
-alloc_err:
- dma_release_channel(stm32port->rx_ch);
- stm32port->rx_ch = NULL;
-
- return ret;
+static void stm32_usart_of_dma_tx_remove(struct stm32_port *stm32port,
+ struct platform_device *pdev)
+{
+ if (stm32port->tx_buf)
+ dma_free_coherent(&pdev->dev, TX_BUF_L, stm32port->tx_buf,
+ stm32port->tx_dma_buf);
}
static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port,
@@ -1275,19 +1243,11 @@ static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port,
stm32port->tx_dma_busy = false;
- /* Request DMA TX channel */
- stm32port->tx_ch = dma_request_slave_channel(dev, "tx");
- if (!stm32port->tx_ch) {
- dev_info(dev, "tx dma alloc failed\n");
- return -ENODEV;
- }
stm32port->tx_buf = dma_alloc_coherent(&pdev->dev, TX_BUF_L,
&stm32port->tx_dma_buf,
GFP_KERNEL);
- if (!stm32port->tx_buf) {
- ret = -ENOMEM;
- goto alloc_err;
- }
+ if (!stm32port->tx_buf)
+ return -ENOMEM;
/* Configure DMA channel */
memset(&config, 0, sizeof(config));
@@ -1297,22 +1257,11 @@ static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port,
ret = dmaengine_slave_config(stm32port->tx_ch, &config);
if (ret < 0) {
dev_err(dev, "tx dma channel config failed\n");
- ret = -ENODEV;
- goto config_err;
+ stm32_usart_of_dma_tx_remove(stm32port, pdev);
+ return ret;
}
return 0;
-
-config_err:
- dma_free_coherent(&pdev->dev,
- TX_BUF_L, stm32port->tx_buf,
- stm32port->tx_dma_buf);
-
-alloc_err:
- dma_release_channel(stm32port->tx_ch);
- stm32port->tx_ch = NULL;
-
- return ret;
}
static int stm32_usart_serial_probe(struct platform_device *pdev)
@@ -1336,16 +1285,43 @@ static int stm32_usart_serial_probe(struct platform_device *pdev)
device_set_wakeup_capable(&pdev->dev, true);
ret = dev_pm_set_wake_irq(&pdev->dev, stm32port->port.irq);
if (ret)
- goto err_nowup;
+ goto err_deinit_port;
}
- ret = stm32_usart_of_dma_rx_probe(stm32port, pdev);
- if (ret)
- dev_info(&pdev->dev, "interrupt mode used for rx (no dma)\n");
+ stm32port->rx_ch = dma_request_chan(&pdev->dev, "rx");
+ if (PTR_ERR(stm32port->rx_ch) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err_wakeirq;
+ }
+ /* Fall back in interrupt mode for any non-deferral error */
+ if (IS_ERR(stm32port->rx_ch))
+ stm32port->rx_ch = NULL;
+
+ stm32port->tx_ch = dma_request_chan(&pdev->dev, "tx");
+ if (PTR_ERR(stm32port->tx_ch) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err_dma_rx;
+ }
+ /* Fall back in interrupt mode for any non-deferral error */
+ if (IS_ERR(stm32port->tx_ch))
+ stm32port->tx_ch = NULL;
- ret = stm32_usart_of_dma_tx_probe(stm32port, pdev);
- if (ret)
- dev_info(&pdev->dev, "interrupt mode used for tx (no dma)\n");
+ if (stm32port->rx_ch && stm32_usart_of_dma_rx_probe(stm32port, pdev)) {
+ /* Fall back in interrupt mode */
+ dma_release_channel(stm32port->rx_ch);
+ stm32port->rx_ch = NULL;
+ }
+
+ if (stm32port->tx_ch && stm32_usart_of_dma_tx_probe(stm32port, pdev)) {
+ /* Fall back in interrupt mode */
+ dma_release_channel(stm32port->tx_ch);
+ stm32port->tx_ch = NULL;
+ }
+
+ if (!stm32port->rx_ch)
+ dev_info(&pdev->dev, "interrupt mode for rx (no dma)\n");
+ if (!stm32port->tx_ch)
+ dev_info(&pdev->dev, "interrupt mode for tx (no dma)\n");
platform_set_drvdata(pdev, &stm32port->port);
@@ -1366,30 +1342,23 @@ err_port:
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
- if (stm32port->rx_ch) {
- dmaengine_terminate_async(stm32port->rx_ch);
- dma_release_channel(stm32port->rx_ch);
- }
-
- if (stm32port->rx_dma_buf)
- dma_free_coherent(&pdev->dev,
- RX_BUF_L, stm32port->rx_buf,
- stm32port->rx_dma_buf);
-
if (stm32port->tx_ch) {
- dmaengine_terminate_async(stm32port->tx_ch);
+ stm32_usart_of_dma_tx_remove(stm32port, pdev);
dma_release_channel(stm32port->tx_ch);
}
- if (stm32port->tx_dma_buf)
- dma_free_coherent(&pdev->dev,
- TX_BUF_L, stm32port->tx_buf,
- stm32port->tx_dma_buf);
+ if (stm32port->rx_ch)
+ stm32_usart_of_dma_rx_remove(stm32port, pdev);
+
+err_dma_rx:
+ if (stm32port->rx_ch)
+ dma_release_channel(stm32port->rx_ch);
+err_wakeirq:
if (stm32port->wakeup_src)
dev_pm_clear_wake_irq(&pdev->dev);
-err_nowup:
+err_deinit_port:
if (stm32port->wakeup_src)
device_set_wakeup_capable(&pdev->dev, false);
@@ -1416,28 +1385,20 @@ static int stm32_usart_serial_remove(struct platform_device *pdev)
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
+ if (stm32_port->tx_ch) {
+ dmaengine_terminate_async(stm32_port->tx_ch);
+ stm32_usart_of_dma_tx_remove(stm32_port, pdev);
+ dma_release_channel(stm32_port->tx_ch);
+ }
+
if (stm32_port->rx_ch) {
dmaengine_terminate_async(stm32_port->rx_ch);
+ stm32_usart_of_dma_rx_remove(stm32_port, pdev);
dma_release_channel(stm32_port->rx_ch);
}
- if (stm32_port->rx_dma_buf)
- dma_free_coherent(&pdev->dev,
- RX_BUF_L, stm32_port->rx_buf,
- stm32_port->rx_dma_buf);
-
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
- if (stm32_port->tx_ch) {
- dmaengine_terminate_async(stm32_port->tx_ch);
- dma_release_channel(stm32_port->tx_ch);
- }
-
- if (stm32_port->tx_dma_buf)
- dma_free_coherent(&pdev->dev,
- TX_BUF_L, stm32_port->tx_buf,
- stm32_port->tx_dma_buf);
-
if (stm32_port->wakeup_src) {
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index bab551f46963..92e572634009 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -35,7 +35,7 @@
#include <linux/init.h>
#include <linux/of_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/setup.h>
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index 12c2468f2b0e..425a016f9db7 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -39,7 +39,7 @@
#include <linux/delay.h>
#include <linux/of_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/setup.h>
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index 001e19d7c17d..1a54e3e52ed6 100644
--- a/drivers/tty/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
@@ -35,7 +35,7 @@
#include <linux/init.h>
#include <linux/of_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/setup.h>
diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c
index 52687c65ad74..4877c54c613d 100644
--- a/drivers/tty/serial/tegra-tcu.c
+++ b/drivers/tty/serial/tegra-tcu.c
@@ -195,13 +195,6 @@ static int tegra_tcu_probe(struct platform_device *pdev)
return err;
}
- tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx");
- if (IS_ERR(tcu->rx)) {
- err = PTR_ERR(tcu->rx);
- dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err);
- goto free_tx;
- }
-
#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE)
/* setup the console */
strcpy(tcu->console.name, "ttyTCU");
@@ -226,7 +219,7 @@ static int tegra_tcu_probe(struct platform_device *pdev)
if (err) {
dev_err(&pdev->dev, "failed to register UART driver: %d\n",
err);
- goto free_rx;
+ goto free_tx;
}
/* setup the port */
@@ -246,6 +239,17 @@ static int tegra_tcu_probe(struct platform_device *pdev)
goto unregister_uart;
}
+ /*
+ * Request RX channel after creating port to ensure tcu->port
+ * is ready for any immediate incoming bytes.
+ */
+ tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx");
+ if (IS_ERR(tcu->rx)) {
+ err = PTR_ERR(tcu->rx);
+ dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err);
+ goto remove_uart_port;
+ }
+
platform_set_drvdata(pdev, tcu);
#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE)
register_console(&tcu->console);
@@ -253,10 +257,10 @@ static int tegra_tcu_probe(struct platform_device *pdev)
return 0;
+remove_uart_port:
+ uart_remove_one_port(&tcu->driver, &tcu->port);
unregister_uart:
uart_unregister_driver(&tcu->driver);
-free_rx:
- mbox_free_channel(tcu->rx);
free_tx:
mbox_free_channel(tcu->tx);
@@ -270,9 +274,9 @@ static int tegra_tcu_remove(struct platform_device *pdev)
#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE)
unregister_console(&tcu->console);
#endif
+ mbox_free_channel(tcu->rx);
uart_remove_one_port(&tcu->driver, &tcu->port);
uart_unregister_driver(&tcu->driver);
- mbox_free_channel(tcu->rx);
mbox_free_channel(tcu->tx);
return 0;
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index f42ccc40ffa6..a5f15f22d9ef 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -505,21 +505,23 @@ static void ulite_console_write(struct console *co, const char *s,
static int ulite_console_setup(struct console *co, char *options)
{
- struct uart_port *port;
+ struct uart_port *port = NULL;
int baud = 9600;
int bits = 8;
int parity = 'n';
int flow = 'n';
-
- port = console_port;
+ if (co->index >= 0 && co->index < ULITE_NR_UARTS)
+ port = ulite_ports + co->index;
/* Has the device been initialized yet? */
- if (!port->mapbase) {
+ if (!port || !port->mapbase) {
pr_debug("console on ttyUL%i not present\n", co->index);
return -ENODEV;
}
+ console_port = port;
+
/* not initialized yet? */
if (!port->membase) {
if (ulite_request_port(port))
@@ -655,17 +657,6 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq,
dev_set_drvdata(dev, port);
-#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
- /*
- * If console hasn't been found yet try to assign this port
- * because it is required to be assigned for console setup function.
- * If register_console() don't assign value, then console_port pointer
- * is cleanup.
- */
- if (ulite_uart_driver.cons->index == -1)
- console_port = port;
-#endif
-
/* Register the port */
rc = uart_add_one_port(&ulite_uart_driver, port);
if (rc) {
@@ -675,12 +666,6 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq,
return rc;
}
-#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
- /* This is not port which is used for console that's why clean it up */
- if (ulite_uart_driver.cons->index == -1)
- console_port = NULL;
-#endif
-
return 0;
}
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index f81261cb52b8..6000853973c1 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -1227,7 +1227,7 @@ static int soft_uart_init(struct platform_device *ofdev)
* kernel, then we use it.
*/
ret = request_firmware_nowait(THIS_MODULE,
- FW_ACTION_HOTPLUG, filename, &ofdev->dev,
+ FW_ACTION_UEVENT, filename, &ofdev->dev,
GFP_KERNEL, &ofdev->dev, uart_firmware_cont);
if (ret) {
dev_err(&ofdev->dev,
diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c
index eeb4b6568776..647198b1e2b9 100644
--- a/drivers/tty/serial/vr41xx_siu.c
+++ b/drivers/tty/serial/vr41xx_siu.c
@@ -20,7 +20,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/vr41xx/siu.h>
#include <asm/vr41xx/vr41xx.h>
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 67a2db621e2b..962e522ccc45 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -484,7 +484,7 @@ static unsigned int cdns_uart_set_baud_rate(struct uart_port *port,
#ifdef CONFIG_COMMON_CLK
/**
- * cdns_uart_clk_notitifer_cb - Clock notifier callback
+ * cdns_uart_clk_notifier_cb - Clock notifier callback
* @nb: Notifier block
* @event: Notify event
* @data: Notifier data
@@ -497,8 +497,8 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
struct uart_port *port;
int locked = 0;
struct clk_notifier_data *ndata = data;
- unsigned long flags = 0;
struct cdns_uart *cdns_uart = to_cdns_uart(nb);
+ unsigned long flags;
port = cdns_uart->port;
if (port->suspended)
@@ -1149,7 +1149,7 @@ static void cdns_uart_console_putchar(struct uart_port *port, int ch)
}
static void cdns_early_write(struct console *con, const char *s,
- unsigned n)
+ unsigned int n)
{
struct earlycon_device *dev = con->data;
@@ -1210,7 +1210,7 @@ static void cdns_uart_console_write(struct console *co, const char *s,
unsigned int count)
{
struct uart_port *port = console_port;
- unsigned long flags = 0;
+ unsigned long flags;
unsigned int imr, ctrl;
int locked = 1;
@@ -1308,7 +1308,7 @@ static int cdns_uart_suspend(struct device *device)
may_wake = device_may_wakeup(device);
if (console_suspend_enabled && uart_console(port) && may_wake) {
- unsigned long flags = 0;
+ unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
/* Empty the receive FIFO 1st before making changes */
@@ -1339,7 +1339,7 @@ static int cdns_uart_resume(struct device *device)
{
struct uart_port *port = dev_get_drvdata(device);
struct cdns_uart *cdns_uart = port->private_data;
- unsigned long flags = 0;
+ unsigned long flags;
u32 ctrl_reg;
int may_wake;
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index 5523cf7bd1c2..5bb928b7873e 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -768,7 +768,7 @@ static int write(struct tty_struct *tty,
if (!info->tx_buf || (count > info->max_frame_size))
return -EIO;
- if (!count || tty->stopped || tty->hw_stopped)
+ if (!count || tty->flow.stopped || tty->hw_stopped)
return 0;
spin_lock_irqsave(&info->lock, flags);
@@ -868,15 +868,15 @@ exit:
DBGINFO(("%s wait_until_sent exit\n", info->device_name));
}
-static int write_room(struct tty_struct *tty)
+static unsigned int write_room(struct tty_struct *tty)
{
struct slgt_info *info = tty->driver_data;
- int ret;
+ unsigned int ret;
if (sanity_check(info, tty->name, "write_room"))
return 0;
ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE;
- DBGINFO(("%s write_room=%d\n", info->device_name, ret));
+ DBGINFO(("%s write_room=%u\n", info->device_name, ret));
return ret;
}
@@ -889,7 +889,7 @@ static void flush_chars(struct tty_struct *tty)
return;
DBGINFO(("%s flush_chars entry tx_count=%d\n", info->device_name, info->tx_count));
- if (info->tx_count <= 0 || tty->stopped ||
+ if (info->tx_count <= 0 || tty->flow.stopped ||
tty->hw_stopped || !info->tx_buf)
return;
@@ -1254,14 +1254,14 @@ static int synclink_gt_proc_show(struct seq_file *m, void *v)
/*
* return count of bytes in transmit buffer
*/
-static int chars_in_buffer(struct tty_struct *tty)
+static unsigned int chars_in_buffer(struct tty_struct *tty)
{
struct slgt_info *info = tty->driver_data;
- int count;
+ unsigned int count;
if (sanity_check(info, tty->name, "chars_in_buffer"))
return 0;
count = tbuf_bytes(info);
- DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, count));
+ DBGINFO(("%s chars_in_buffer()=%u\n", info->device_name, count));
return count;
}
@@ -2241,7 +2241,7 @@ static void isr_txeom(struct slgt_info *info, unsigned short status)
else
#endif
{
- if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) {
+ if (info->port.tty && (info->port.tty->flow.stopped || info->port.tty->hw_stopped)) {
tx_stop(info);
return;
}
@@ -2465,14 +2465,7 @@ static void change_params(struct slgt_info *info)
/* byte size and parity */
- switch (cflag & CSIZE) {
- case CS5: info->params.data_bits = 5; break;
- case CS6: info->params.data_bits = 6; break;
- case CS7: info->params.data_bits = 7; break;
- case CS8: info->params.data_bits = 8; break;
- default: info->params.data_bits = 7; break;
- }
-
+ info->params.data_bits = tty_get_char_size(cflag);
info->params.stop_bits = (cflag & CSTOPB) ? 2 : 1;
if (cflag & PARENB)
diff --git a/drivers/tty/tty_baudrate.c b/drivers/tty/tty_baudrate.c
index 48b5de659c77..426b1252781a 100644
--- a/drivers/tty/tty_baudrate.c
+++ b/drivers/tty/tty_baudrate.c
@@ -147,7 +147,7 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
int iclose = ibaud/50, oclose = obaud/50;
int ibinput = 0;
- if (obaud == 0) /* CD dropped */
+ if (obaud == 0) /* CD dropped */
ibaud = 0; /* Clear ibaud to be sure */
termios->c_ispeed = ibaud;
@@ -159,8 +159,9 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
#endif
#ifdef BOTHER
/* If the user asked for a precise weird speed give a precise weird
- answer. If they asked for a Bfoo speed they may have problems
- digesting non-exact replies so fuzz a bit */
+ * answer. If they asked for a Bfoo speed they may have problems
+ * digesting non-exact replies so fuzz a bit.
+ */
if ((termios->c_cflag & CBAUD) == BOTHER) {
oclose = 0;
@@ -191,7 +192,8 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
if (ibaud - iclose <= baud_table[i] &&
ibaud + iclose >= baud_table[i]) {
/* For the case input == output don't set IBAUD bits
- if the user didn't do so */
+ * if the user didn't do so.
+ */
if (ofound == i && !ibinput)
ifound = i;
#ifdef IBSHIFT
@@ -211,7 +213,8 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
if (ofound == -1)
termios->c_cflag |= BOTHER;
/* Set exact input bits only if the input and output differ or the
- user already did */
+ * user already did.
+ */
if (ifound == -1 && (ibaud != obaud || ibinput))
termios->c_cflag |= (BOTHER << IBSHIFT);
#else
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 9733469a14b2..635d0af229b7 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -32,8 +32,8 @@
* We default to dicing tty buffer allocations to this many characters
* in order to avoid multiple page allocations. We know the size of
* tty_buffer itself but it must also be taken into account that the
- * the buffer is 256 byte aligned. See tty_buffer_find for the allocation
- * logic this must match
+ * buffer is 256 byte aligned. See tty_buffer_find for the allocation
+ * logic this must match.
*/
#define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF)
@@ -88,9 +88,10 @@ EXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive);
* pre-allocate if memory guarantee is required).
*/
-int tty_buffer_space_avail(struct tty_port *port)
+unsigned int tty_buffer_space_avail(struct tty_port *port)
{
int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used);
+
return max(space, 0);
}
EXPORT_SYMBOL_GPL(tty_buffer_space_avail);
@@ -169,7 +170,8 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
}
/* Should possibly check if this fails for the largest buffer we
- have queued and recycle that ? */
+ * have queued and recycle that ?
+ */
if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit)
return NULL;
p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
@@ -242,7 +244,7 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)
}
/**
- * tty_buffer_request_room - grow tty buffer if needed
+ * __tty_buffer_request_room - grow tty buffer if needed
* @port: tty port
* @size: size desired
* @flags: buffer flags if new buffer allocated (default = 0)
@@ -312,11 +314,13 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port,
const unsigned char *chars, char flag, size_t size)
{
int copied = 0;
+
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0;
int space = __tty_buffer_request_room(port, goal, flags);
struct tty_buffer *tb = port->buf.tail;
+
if (unlikely(space == 0))
break;
memcpy(char_buf_ptr(tb, tb->used), chars, space);
@@ -326,7 +330,8 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port,
copied += space;
chars += space;
/* There is a small chance that we need to split the data over
- several buffers. If this is the case we must loop */
+ * several buffers. If this is the case we must loop.
+ */
} while (unlikely(size > copied));
return copied;
}
@@ -348,10 +353,12 @@ int tty_insert_flip_string_flags(struct tty_port *port,
const unsigned char *chars, const char *flags, size_t size)
{
int copied = 0;
+
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
int space = tty_buffer_request_room(port, goal);
struct tty_buffer *tb = port->buf.tail;
+
if (unlikely(space == 0))
break;
memcpy(char_buf_ptr(tb, tb->used), chars, space);
@@ -361,7 +368,8 @@ int tty_insert_flip_string_flags(struct tty_port *port,
chars += space;
flags += space;
/* There is a small chance that we need to split the data over
- several buffers. If this is the case we must loop */
+ * several buffers. If this is the case we must loop.
+ */
} while (unlikely(size > copied));
return copied;
}
@@ -431,8 +439,10 @@ int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars,
size_t size)
{
int space = __tty_buffer_request_room(port, size, TTYB_NORMAL);
+
if (likely(space)) {
struct tty_buffer *tb = port->buf.tail;
+
*chars = char_buf_ptr(tb, tb->used);
if (~tb->flags & TTYB_NORMAL)
memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space);
@@ -455,7 +465,7 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
* Returns the number of bytes processed
*/
int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p,
- char *f, int count)
+ const char *f, int count)
{
if (ld->ops->receive_buf2)
count = ld->ops->receive_buf2(ld->tty, p, f, count);
@@ -472,7 +482,7 @@ static int
receive_buf(struct tty_port *port, struct tty_buffer *head, int count)
{
unsigned char *p = char_buf_ptr(head, head->read);
- char *f = NULL;
+ const char *f = NULL;
int n;
if (~head->flags & TTYB_NORMAL)
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 5b5e99604989..26debec26b4e 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -33,7 +33,7 @@
* -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
*
* Rewrote canonical mode and added more termios flags.
- * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
+ * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
*
* Reorganized FASYNC support so mouse code can share it.
* -- ctm@ardi.com, 9Sep95
@@ -131,12 +131,12 @@ struct ktermios tty_std_termios = { /* for the benefit of tty drivers */
.c_ospeed = 38400,
/* .c_line = N_TTY, */
};
-
EXPORT_SYMBOL(tty_std_termios);
/* This list gets poked at by procfs and various bits of boot up code. This
- could do with some rationalisation such as pulling the tty proc function
- into this file */
+ * could do with some rationalisation such as pulling the tty proc function
+ * into this file.
+ */
LIST_HEAD(tty_drivers); /* linked list of tty drivers */
@@ -248,7 +248,6 @@ const char *tty_name(const struct tty_struct *tty)
return "NULL tty";
return tty->name;
}
-
EXPORT_SYMBOL(tty_name);
const char *tty_driver_name(const struct tty_struct *tty)
@@ -320,6 +319,7 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index)
list_for_each_entry(p, &tty_drivers, tty_drivers) {
dev_t base = MKDEV(p->major, p->minor_start);
+
if (device < base || device >= base + p->num)
continue;
*index = device - base;
@@ -537,7 +537,6 @@ void tty_wakeup(struct tty_struct *tty)
}
wake_up_interruptible_poll(&tty->write_wait, EPOLLOUT);
}
-
EXPORT_SYMBOL_GPL(tty_wakeup);
/**
@@ -613,8 +612,9 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
set_bit(TTY_HUPPING, &tty->flags);
/* inuse_filps is protected by the single tty lock,
- this really needs to change if we want to flush the
- workqueue with the lock held */
+ * this really needs to change if we want to flush the
+ * workqueue with the lock held.
+ */
check_tty_count(tty, "tty_hangup");
spin_lock(&tty->files_lock);
@@ -638,15 +638,15 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
tty_ldisc_hangup(tty, cons_filp != NULL);
- spin_lock_irq(&tty->ctrl_lock);
+ spin_lock_irq(&tty->ctrl.lock);
clear_bit(TTY_THROTTLED, &tty->flags);
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- put_pid(tty->session);
- put_pid(tty->pgrp);
- tty->session = NULL;
- tty->pgrp = NULL;
- tty->ctrl_status = 0;
- spin_unlock_irq(&tty->ctrl_lock);
+ put_pid(tty->ctrl.session);
+ put_pid(tty->ctrl.pgrp);
+ tty->ctrl.session = NULL;
+ tty->ctrl.pgrp = NULL;
+ tty->ctrl.pktstatus = 0;
+ spin_unlock_irq(&tty->ctrl.lock);
/*
* If one of the devices matches a console pointer, we
@@ -694,7 +694,6 @@ void tty_hangup(struct tty_struct *tty)
tty_debug_hangup(tty, "hangup\n");
schedule_work(&tty->hangup_work);
}
-
EXPORT_SYMBOL(tty_hangup);
/**
@@ -711,7 +710,6 @@ void tty_vhangup(struct tty_struct *tty)
tty_debug_hangup(tty, "vhangup\n");
__tty_hangup(tty, 0);
}
-
EXPORT_SYMBOL(tty_vhangup);
@@ -761,9 +759,17 @@ int tty_hung_up_p(struct file *filp)
{
return (filp && filp->f_op == &hung_up_tty_fops);
}
-
EXPORT_SYMBOL(tty_hung_up_p);
+void __stop_tty(struct tty_struct *tty)
+{
+ if (tty->flow.stopped)
+ return;
+ tty->flow.stopped = true;
+ if (tty->ops->stop)
+ tty->ops->stop(tty);
+}
+
/**
* stop_tty - propagate flow control
* @tty: tty to stop
@@ -778,28 +784,28 @@ EXPORT_SYMBOL(tty_hung_up_p);
* but not always.
*
* Locking:
- * flow_lock
+ * flow.lock
*/
-
-void __stop_tty(struct tty_struct *tty)
-{
- if (tty->stopped)
- return;
- tty->stopped = 1;
- if (tty->ops->stop)
- tty->ops->stop(tty);
-}
-
void stop_tty(struct tty_struct *tty)
{
unsigned long flags;
- spin_lock_irqsave(&tty->flow_lock, flags);
+ spin_lock_irqsave(&tty->flow.lock, flags);
__stop_tty(tty);
- spin_unlock_irqrestore(&tty->flow_lock, flags);
+ spin_unlock_irqrestore(&tty->flow.lock, flags);
}
EXPORT_SYMBOL(stop_tty);
+void __start_tty(struct tty_struct *tty)
+{
+ if (!tty->flow.stopped || tty->flow.tco_stopped)
+ return;
+ tty->flow.stopped = false;
+ if (tty->ops->start)
+ tty->ops->start(tty);
+ tty_wakeup(tty);
+}
+
/**
* start_tty - propagate flow control
* @tty: tty to start
@@ -809,26 +815,15 @@ EXPORT_SYMBOL(stop_tty);
* start method is invoked and the line discipline woken.
*
* Locking:
- * flow_lock
+ * flow.lock
*/
-
-void __start_tty(struct tty_struct *tty)
-{
- if (!tty->stopped || tty->flow_stopped)
- return;
- tty->stopped = 0;
- if (tty->ops->start)
- tty->ops->start(tty);
- tty_wakeup(tty);
-}
-
void start_tty(struct tty_struct *tty)
{
unsigned long flags;
- spin_lock_irqsave(&tty->flow_lock, flags);
+ spin_lock_irqsave(&tty->flow.lock, flags);
__start_tty(tty);
- spin_unlock_irqrestore(&tty->flow_lock, flags);
+ spin_unlock_irqrestore(&tty->flow.lock, flags);
}
EXPORT_SYMBOL(start_tty);
@@ -914,10 +909,8 @@ static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty,
/**
* tty_read - read method for tty device files
- * @file: pointer to tty file
- * @buf: user buffer
- * @count: size of user buffer
- * @ppos: unused
+ * @iocb: kernel I/O control block
+ * @to: destination for the data read
*
* Perform the read system call function on this terminal device. Checks
* for hung up devices before calling the line discipline method.
@@ -941,7 +934,8 @@ static ssize_t tty_read(struct kiocb *iocb, struct iov_iter *to)
return -EIO;
/* We want to wait for the line discipline to sort out in this
- situation */
+ * situation.
+ */
ld = tty_ldisc_ref_wait(tty);
if (!ld)
return hung_up_tty_read(iocb, to);
@@ -1033,6 +1027,7 @@ static inline ssize_t do_tty_write(
/* Do the write .. */
for (;;) {
size_t size = count;
+
if (size > chunk)
size = chunk;
@@ -1091,36 +1086,18 @@ void tty_write_message(struct tty_struct *tty, char *msg)
tty_unlock(tty);
tty_write_unlock(tty);
}
- return;
}
-
-/**
- * tty_write - write method for tty device file
- * @file: tty file pointer
- * @buf: user data to write
- * @count: bytes to write
- * @ppos: unused
- *
- * Write data to a tty device via the line discipline.
- *
- * Locking:
- * Locks the line discipline as required
- * Writes to the tty driver are serialized by the atomic_write_lock
- * and are then processed in chunks to the device. The line discipline
- * write method will not be invoked in parallel for each device.
- */
-
static ssize_t file_tty_write(struct file *file, struct kiocb *iocb, struct iov_iter *from)
{
struct tty_struct *tty = file_tty(file);
- struct tty_ldisc *ld;
+ struct tty_ldisc *ld;
ssize_t ret;
if (tty_paranoia_check(tty, file_inode(file), "tty_write"))
return -EIO;
if (!tty || !tty->ops->write || tty_io_error(tty))
- return -EIO;
+ return -EIO;
/* Short term debug to catch buggy drivers */
if (tty->ops->write_room == NULL)
tty_err(tty, "missing write_room method\n");
@@ -1135,6 +1112,20 @@ static ssize_t file_tty_write(struct file *file, struct kiocb *iocb, struct iov_
return ret;
}
+/**
+ * tty_write - write method for tty device file
+ * @iocb: kernel I/O control block
+ * @from: iov_iter with data to write
+ *
+ * Write data to a tty device via the line discipline.
+ *
+ * Locking:
+ * Locks the line discipline as required
+ * Writes to the tty driver are serialized by the atomic_write_lock
+ * and are then processed in chunks to the device. The line
+ * discipline write method will not be invoked in parallel for
+ * each device.
+ */
static ssize_t tty_write(struct kiocb *iocb, struct iov_iter *from)
{
return file_tty_write(iocb->ki_filp, iocb, from);
@@ -1150,11 +1141,12 @@ ssize_t redirected_tty_write(struct kiocb *iocb, struct iov_iter *iter)
spin_unlock(&redirect_lock);
/*
- * We know the redirected tty is just another tty, we can can
+ * We know the redirected tty is just another tty, we can
* call file_tty_write() directly with that file pointer.
*/
if (p) {
ssize_t res;
+
res = file_tty_write(p, iocb, iter);
fput(p);
return res;
@@ -1172,7 +1164,7 @@ ssize_t redirected_tty_write(struct kiocb *iocb, struct iov_iter *iter)
int tty_send_xchar(struct tty_struct *tty, char ch)
{
- int was_stopped = tty->stopped;
+ bool was_stopped = tty->flow.stopped;
if (tty->ops->send_xchar) {
down_read(&tty->termios_rwsem);
@@ -1559,8 +1551,8 @@ static void release_one_tty(struct work_struct *work)
list_del_init(&tty->tty_files);
spin_unlock(&tty->files_lock);
- put_pid(tty->pgrp);
- put_pid(tty->session);
+ put_pid(tty->ctrl.pgrp);
+ put_pid(tty->ctrl.session);
free_tty_struct(tty);
}
@@ -1569,7 +1561,8 @@ static void queue_release_one_tty(struct kref *kref)
struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
/* The hangup queue is now free so we can reuse it rather than
- waste a chunk of memory for each port */
+ * waste a chunk of memory for each port.
+ */
INIT_WORK(&tty->hangup_work, release_one_tty);
schedule_work(&tty->hangup_work);
}
@@ -1861,9 +1854,9 @@ int tty_release(struct inode *inode, struct file *filp)
*/
if (!tty->count) {
read_lock(&tasklist_lock);
- session_clear_tty(tty->session);
+ session_clear_tty(tty->ctrl.session);
if (o_tty)
- session_clear_tty(o_tty->session);
+ session_clear_tty(o_tty->ctrl.session);
read_unlock(&tasklist_lock);
}
@@ -1874,7 +1867,8 @@ int tty_release(struct inode *inode, struct file *filp)
tty_unlock(tty);
/* At this point, the tty->count == 0 should ensure a dead tty
- cannot be re-opened by a racing opener */
+ * cannot be re-opened by a racing opener.
+ */
if (!final)
return 0;
@@ -1928,8 +1922,8 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
* @index: index for the device in the @return driver
* @return: driver for this inode (with increased refcount)
*
- * If @return is not erroneous, the caller is responsible to decrement the
- * refcount by tty_driver_kref_put.
+ * If @return is not erroneous, the caller is responsible to decrement the
+ * refcount by tty_driver_kref_put.
*
* Locking: tty_mutex protects get_tty_driver
*/
@@ -1942,6 +1936,7 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
#ifdef CONFIG_VT
case MKDEV(TTY_MAJOR, 0): {
extern struct tty_driver *console_driver;
+
driver = tty_driver_kref_get(console_driver);
*index = fg_console;
break;
@@ -1949,6 +1944,7 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
#endif
case MKDEV(TTYAUX_MAJOR, 1): {
struct tty_driver *console_driver = console_device(index);
+
if (console_driver) {
driver = tty_driver_kref_get(console_driver);
if (driver && filp) {
@@ -2250,16 +2246,16 @@ static int __tty_fasync(int fd, struct file *filp, int on)
enum pid_type type;
struct pid *pid;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- if (tty->pgrp) {
- pid = tty->pgrp;
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ if (tty->ctrl.pgrp) {
+ pid = tty->ctrl.pgrp;
type = PIDTYPE_PGID;
} else {
pid = task_pid(current);
type = PIDTYPE_TGID;
}
get_pid(pid);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
__f_setown(filp, pid, type, 0);
put_pid(pid);
retval = 0;
@@ -2336,7 +2332,7 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
mutex_unlock(&tty->winsize_mutex);
- return err ? -EFAULT: 0;
+ return err ? -EFAULT : 0;
}
/**
@@ -2381,13 +2377,14 @@ EXPORT_SYMBOL(tty_do_resize);
*
* Locking:
* Driver dependent. The default do_resize method takes the
- * tty termios mutex and ctrl_lock. The console takes its own lock
+ * tty termios mutex and ctrl.lock. The console takes its own lock
* then calls into the default method.
*/
static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg)
{
struct winsize tmp_ws;
+
if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
return -EFAULT;
@@ -2412,6 +2409,7 @@ static int tioccons(struct file *file)
return -EPERM;
if (file->f_op->write_iter == redirected_tty_write) {
struct file *f;
+
spin_lock(&redirect_lock);
f = redirect;
redirect = NULL;
@@ -2734,6 +2732,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case TIOCGEXCL:
{
int excl = test_bit(TTY_EXCLUSIVE, &tty->flags);
+
return put_user(excl, (int __user *)p);
}
case TIOCGETD:
@@ -2748,6 +2747,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case TIOCGDEV:
{
unsigned int ret = new_encode_dev(tty_devnum(real_tty));
+
return put_user(ret, (unsigned int __user *)p);
}
/*
@@ -3006,7 +3006,7 @@ static int this_tty(const void *t, struct file *file, unsigned fd)
return 0;
return file_tty(file) != t ? 0 : fd + 1;
}
-
+
/*
* This implements the "Secure Attention Key" --- the idea is to
* prevent trojan horses by killing all processes associated with this
@@ -3039,9 +3039,9 @@ void __do_SAK(struct tty_struct *tty)
if (!tty)
return;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- session = get_pid(tty->session);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ session = get_pid(tty->ctrl.session);
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
tty_ldisc_flush(tty);
@@ -3096,13 +3096,13 @@ void do_SAK(struct tty_struct *tty)
return;
schedule_work(&tty->SAK_work);
}
-
EXPORT_SYMBOL(do_SAK);
/* Must put_device() after it's unused! */
static struct device *tty_get_device(struct tty_struct *tty)
{
dev_t devt = tty_devnum(tty);
+
return class_find_device_by_devt(tty_class, devt);
}
@@ -3129,8 +3129,8 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx)
kfree(tty);
return NULL;
}
- tty->session = NULL;
- tty->pgrp = NULL;
+ tty->ctrl.session = NULL;
+ tty->ctrl.pgrp = NULL;
mutex_init(&tty->legacy_mutex);
mutex_init(&tty->throttle_mutex);
init_rwsem(&tty->termios_rwsem);
@@ -3140,8 +3140,8 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx)
init_waitqueue_head(&tty->read_wait);
INIT_WORK(&tty->hangup_work, do_tty_hangup);
mutex_init(&tty->atomic_write_lock);
- spin_lock_init(&tty->ctrl_lock);
- spin_lock_init(&tty->flow_lock);
+ spin_lock_init(&tty->ctrl.lock);
+ spin_lock_init(&tty->flow.lock);
spin_lock_init(&tty->files_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, do_SAK_work);
@@ -3317,11 +3317,11 @@ err_put:
EXPORT_SYMBOL_GPL(tty_register_device_attr);
/**
- * tty_unregister_device - unregister a tty device
- * @driver: the tty driver that describes the tty device
- * @index: the index in the tty driver for this tty device
+ * tty_unregister_device - unregister a tty device
+ * @driver: the tty driver that describes the tty device
+ * @index: the index in the tty driver for this tty device
*
- * If a tty device is registered with a call to tty_register_device() then
+ * If a tty device is registered with a call to tty_register_device() then
* this function must be called when the tty device is gone.
*
* Locking: ??
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 41f7449d0464..507a25d692bb 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -54,7 +54,7 @@
* to be no queue on the device.
*/
-int tty_chars_in_buffer(struct tty_struct *tty)
+unsigned int tty_chars_in_buffer(struct tty_struct *tty)
{
if (tty->ops->chars_in_buffer)
return tty->ops->chars_in_buffer(tty);
@@ -73,7 +73,7 @@ EXPORT_SYMBOL(tty_chars_in_buffer);
* returned and data may be lost as there will be no flow control.
*/
-int tty_write_room(struct tty_struct *tty)
+unsigned int tty_write_room(struct tty_struct *tty)
{
if (tty->ops->write_room)
return tty->ops->write_room(tty);
@@ -97,28 +97,6 @@ void tty_driver_flush_buffer(struct tty_struct *tty)
EXPORT_SYMBOL(tty_driver_flush_buffer);
/**
- * tty_throttle - flow control
- * @tty: terminal
- *
- * Indicate that a tty should stop transmitting data down the stack.
- * Takes the termios rwsem to protect against parallel throttle/unthrottle
- * and also to ensure the driver can consistently reference its own
- * termios data at this point when implementing software flow control.
- */
-
-void tty_throttle(struct tty_struct *tty)
-{
- down_write(&tty->termios_rwsem);
- /* check TTY_THROTTLED first so it indicates our state */
- if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
- tty->ops->throttle)
- tty->ops->throttle(tty);
- tty->flow_change = 0;
- up_write(&tty->termios_rwsem);
-}
-EXPORT_SYMBOL(tty_throttle);
-
-/**
* tty_unthrottle - flow control
* @tty: terminal
*
@@ -146,10 +124,11 @@ EXPORT_SYMBOL(tty_unthrottle);
* tty_throttle_safe - flow control
* @tty: terminal
*
- * Similar to tty_throttle() but will only attempt throttle
- * if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental
- * throttle due to race conditions when throttling is conditional
- * on factors evaluated prior to throttling.
+ * Indicate that a tty should stop transmitting data down the stack.
+ * tty_throttle_safe will only attempt throttle if tty->flow_change is
+ * TTY_THROTTLE_SAFE. Prevents an accidental throttle due to race
+ * conditions when throttling is conditional on factors evaluated prior to
+ * throttling.
*
* Returns 0 if tty is throttled (or was already throttled)
*/
@@ -301,6 +280,51 @@ int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
EXPORT_SYMBOL(tty_termios_hw_change);
/**
+ * tty_get_char_size - get size of a character
+ * @cflag: termios cflag value
+ *
+ * Get the size (in bits) of a character depending on @cflag's %CSIZE
+ * setting.
+ */
+unsigned char tty_get_char_size(unsigned int cflag)
+{
+ switch (cflag & CSIZE) {
+ case CS5:
+ return 5;
+ case CS6:
+ return 6;
+ case CS7:
+ return 7;
+ case CS8:
+ default:
+ return 8;
+ }
+}
+EXPORT_SYMBOL_GPL(tty_get_char_size);
+
+/**
+ * tty_get_frame_size - get size of a frame
+ * @cflag: termios cflag value
+ *
+ * Get the size (in bits) of a frame depending on @cflag's %CSIZE, %CSTOPB,
+ * and %PARENB setting. The result is a sum of character size, start and
+ * stop bits -- one bit each -- second stop bit (if set), and parity bit
+ * (if set).
+ */
+unsigned char tty_get_frame_size(unsigned int cflag)
+{
+ unsigned char bits = 2 + tty_get_char_size(cflag);
+
+ if (cflag & CSTOPB)
+ bits++;
+ if (cflag & PARENB)
+ bits++;
+
+ return bits;
+}
+EXPORT_SYMBOL_GPL(tty_get_frame_size);
+
+/**
* tty_set_termios - update termios values
* @tty: tty to update
* @new_termios: desired new value
@@ -846,20 +870,20 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
return retval;
switch (arg) {
case TCOOFF:
- spin_lock_irq(&tty->flow_lock);
- if (!tty->flow_stopped) {
- tty->flow_stopped = 1;
+ spin_lock_irq(&tty->flow.lock);
+ if (!tty->flow.tco_stopped) {
+ tty->flow.tco_stopped = true;
__stop_tty(tty);
}
- spin_unlock_irq(&tty->flow_lock);
+ spin_unlock_irq(&tty->flow.lock);
break;
case TCOON:
- spin_lock_irq(&tty->flow_lock);
- if (tty->flow_stopped) {
- tty->flow_stopped = 0;
+ spin_lock_irq(&tty->flow.lock);
+ if (tty->flow.tco_stopped) {
+ tty->flow.tco_stopped = false;
__start_tty(tty);
}
- spin_unlock_irq(&tty->flow_lock);
+ spin_unlock_irq(&tty->flow.lock);
break;
case TCIOFF:
if (STOP_CHAR(tty) != __DISABLED_CHAR)
diff --git a/drivers/tty/tty_jobctrl.c b/drivers/tty/tty_jobctrl.c
index 7813dc910a19..80b86a7992b5 100644
--- a/drivers/tty/tty_jobctrl.c
+++ b/drivers/tty/tty_jobctrl.c
@@ -20,7 +20,7 @@ static int is_ignored(int sig)
}
/**
- * tty_check_change - check for POSIX terminal changes
+ * __tty_check_change - check for POSIX terminal changes
* @tty: tty to check
* @sig: signal to send
*
@@ -28,7 +28,7 @@ static int is_ignored(int sig)
* not in the foreground, send a SIGTTOU. If the signal is blocked or
* ignored, go ahead and perform the operation. (POSIX 7.2)
*
- * Locking: ctrl_lock
+ * Locking: ctrl.lock
*/
int __tty_check_change(struct tty_struct *tty, int sig)
{
@@ -42,9 +42,9 @@ int __tty_check_change(struct tty_struct *tty, int sig)
rcu_read_lock();
pgrp = task_pgrp(current);
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- tty_pgrp = tty->pgrp;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ tty_pgrp = tty->ctrl.pgrp;
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
if (tty_pgrp && pgrp != tty_pgrp) {
if (is_ignored(sig)) {
@@ -85,7 +85,7 @@ void proc_clear_tty(struct task_struct *p)
}
/**
- * proc_set_tty - set the controlling terminal
+ * __proc_set_tty - set the controlling terminal
* @tty: tty structure
*
* Only callable by the session leader and only if it does not already have
@@ -99,16 +99,16 @@ static void __proc_set_tty(struct tty_struct *tty)
{
unsigned long flags;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
/*
* The session and fg pgrp references will be non-NULL if
* tiocsctty() is stealing the controlling tty
*/
- put_pid(tty->session);
- put_pid(tty->pgrp);
- tty->pgrp = get_pid(task_pgrp(current));
- tty->session = get_pid(task_session(current));
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ put_pid(tty->ctrl.session);
+ put_pid(tty->ctrl.pgrp);
+ tty->ctrl.pgrp = get_pid(task_pgrp(current));
+ tty->ctrl.session = get_pid(task_session(current));
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
if (current->signal->tty) {
tty_debug(tty, "current tty %s not NULL!!\n",
current->signal->tty->name);
@@ -135,7 +135,7 @@ void tty_open_proc_set_tty(struct file *filp, struct tty_struct *tty)
spin_lock_irq(&current->sighand->siglock);
if (current->signal->leader &&
!current->signal->tty &&
- tty->session == NULL) {
+ tty->ctrl.session == NULL) {
/*
* Don't let a process that only has write access to the tty
* obtain the privileges associated with having a tty as
@@ -200,8 +200,8 @@ int tty_signal_session_leader(struct tty_struct *tty, int exit_session)
struct pid *tty_pgrp = NULL;
read_lock(&tasklist_lock);
- if (tty->session) {
- do_each_pid_task(tty->session, PIDTYPE_SID, p) {
+ if (tty->ctrl.session) {
+ do_each_pid_task(tty->ctrl.session, PIDTYPE_SID, p) {
spin_lock_irq(&p->sighand->siglock);
if (p->signal->tty == tty) {
p->signal->tty = NULL;
@@ -218,13 +218,14 @@ int tty_signal_session_leader(struct tty_struct *tty, int exit_session)
__group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
put_pid(p->signal->tty_old_pgrp); /* A noop */
- spin_lock(&tty->ctrl_lock);
- tty_pgrp = get_pid(tty->pgrp);
- if (tty->pgrp)
- p->signal->tty_old_pgrp = get_pid(tty->pgrp);
- spin_unlock(&tty->ctrl_lock);
+ spin_lock(&tty->ctrl.lock);
+ tty_pgrp = get_pid(tty->ctrl.pgrp);
+ if (tty->ctrl.pgrp)
+ p->signal->tty_old_pgrp =
+ get_pid(tty->ctrl.pgrp);
+ spin_unlock(&tty->ctrl.lock);
spin_unlock_irq(&p->sighand->siglock);
- } while_each_pid_task(tty->session, PIDTYPE_SID, p);
+ } while_each_pid_task(tty->ctrl.session, PIDTYPE_SID, p);
}
read_unlock(&tasklist_lock);
@@ -309,12 +310,12 @@ void disassociate_ctty(int on_exit)
unsigned long flags;
tty_lock(tty);
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- put_pid(tty->session);
- put_pid(tty->pgrp);
- tty->session = NULL;
- tty->pgrp = NULL;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ put_pid(tty->ctrl.session);
+ put_pid(tty->ctrl.pgrp);
+ tty->ctrl.session = NULL;
+ tty->ctrl.pgrp = NULL;
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
tty_unlock(tty);
tty_kref_put(tty);
}
@@ -363,7 +364,8 @@ static int tiocsctty(struct tty_struct *tty, struct file *file, int arg)
tty_lock(tty);
read_lock(&tasklist_lock);
- if (current->signal->leader && (task_session(current) == tty->session))
+ if (current->signal->leader &&
+ task_session(current) == tty->ctrl.session)
goto unlock;
/*
@@ -375,7 +377,7 @@ static int tiocsctty(struct tty_struct *tty, struct file *file, int arg)
goto unlock;
}
- if (tty->session) {
+ if (tty->ctrl.session) {
/*
* This tty is already the controlling
* tty for another session group!
@@ -384,7 +386,7 @@ static int tiocsctty(struct tty_struct *tty, struct file *file, int arg)
/*
* Steal it away
*/
- session_clear_tty(tty->session);
+ session_clear_tty(tty->ctrl.session);
} else {
ret = -EPERM;
goto unlock;
@@ -416,9 +418,9 @@ struct pid *tty_get_pgrp(struct tty_struct *tty)
unsigned long flags;
struct pid *pgrp;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- pgrp = get_pid(tty->pgrp);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ pgrp = get_pid(tty->ctrl.pgrp);
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
return pgrp;
}
@@ -499,10 +501,10 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
if (pgrp_nr < 0)
return -EINVAL;
- spin_lock_irq(&real_tty->ctrl_lock);
+ spin_lock_irq(&real_tty->ctrl.lock);
if (!current->signal->tty ||
(current->signal->tty != real_tty) ||
- (real_tty->session != task_session(current))) {
+ (real_tty->ctrl.session != task_session(current))) {
retval = -ENOTTY;
goto out_unlock_ctrl;
}
@@ -515,12 +517,12 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
if (session_of_pgrp(pgrp) != task_session(current))
goto out_unlock;
retval = 0;
- put_pid(real_tty->pgrp);
- real_tty->pgrp = get_pid(pgrp);
+ put_pid(real_tty->ctrl.pgrp);
+ real_tty->ctrl.pgrp = get_pid(pgrp);
out_unlock:
rcu_read_unlock();
out_unlock_ctrl:
- spin_unlock_irq(&real_tty->ctrl_lock);
+ spin_unlock_irq(&real_tty->ctrl.lock);
return retval;
}
@@ -545,16 +547,16 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _
if (tty == real_tty && current->signal->tty != real_tty)
return -ENOTTY;
- spin_lock_irqsave(&real_tty->ctrl_lock, flags);
- if (!real_tty->session)
+ spin_lock_irqsave(&real_tty->ctrl.lock, flags);
+ if (!real_tty->ctrl.session)
goto err;
- sid = pid_vnr(real_tty->session);
- spin_unlock_irqrestore(&real_tty->ctrl_lock, flags);
+ sid = pid_vnr(real_tty->ctrl.session);
+ spin_unlock_irqrestore(&real_tty->ctrl.lock, flags);
return put_user(sid, p);
err:
- spin_unlock_irqrestore(&real_tty->ctrl_lock, flags);
+ spin_unlock_irqrestore(&real_tty->ctrl.lock, flags);
return -ENOTTY;
}
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 03f414172f34..756a4bfa6a69 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -48,7 +48,6 @@ static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
/**
* tty_register_ldisc - install a line discipline
- * @disc: ldisc number
* @new_ldisc: pointer to the ldisc object
*
* Installs a new line discipline into the kernel. The discipline
@@ -59,18 +58,16 @@ static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
* takes tty_ldiscs_lock to guard against ldisc races
*/
-int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
+int tty_register_ldisc(struct tty_ldisc_ops *new_ldisc)
{
unsigned long flags;
int ret = 0;
- if (disc < N_TTY || disc >= NR_LDISCS)
+ if (new_ldisc->num < N_TTY || new_ldisc->num >= NR_LDISCS)
return -EINVAL;
raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
- tty_ldiscs[disc] = new_ldisc;
- new_ldisc->num = disc;
- new_ldisc->refcount = 0;
+ tty_ldiscs[new_ldisc->num] = new_ldisc;
raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
return ret;
@@ -79,7 +76,7 @@ EXPORT_SYMBOL(tty_register_ldisc);
/**
* tty_unregister_ldisc - unload a line discipline
- * @disc: ldisc number
+ * @ldisc: ldisc number
*
* Remove a line discipline from the kernel providing it is not
* currently in use.
@@ -88,22 +85,13 @@ EXPORT_SYMBOL(tty_register_ldisc);
* takes tty_ldiscs_lock to guard against ldisc races
*/
-int tty_unregister_ldisc(int disc)
+void tty_unregister_ldisc(struct tty_ldisc_ops *ldisc)
{
unsigned long flags;
- int ret = 0;
-
- if (disc < N_TTY || disc >= NR_LDISCS)
- return -EINVAL;
raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
- if (tty_ldiscs[disc]->refcount)
- ret = -EBUSY;
- else
- tty_ldiscs[disc] = NULL;
+ tty_ldiscs[ldisc->num] = NULL;
raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
-
- return ret;
}
EXPORT_SYMBOL(tty_unregister_ldisc);
@@ -117,10 +105,8 @@ static struct tty_ldisc_ops *get_ldops(int disc)
ldops = tty_ldiscs[disc];
if (ldops) {
ret = ERR_PTR(-EAGAIN);
- if (try_module_get(ldops->owner)) {
- ldops->refcount++;
+ if (try_module_get(ldops->owner))
ret = ldops;
- }
}
raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
return ret;
@@ -131,7 +117,6 @@ static void put_ldops(struct tty_ldisc_ops *ldops)
unsigned long flags;
raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
- ldops->refcount--;
module_put(ldops->owner);
raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
}
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 303c198fbf5c..2f1061a9d926 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -468,7 +468,8 @@ int tty_port_block_til_ready(struct tty_port *port,
DEFINE_WAIT(wait);
/* if non-blocking mode is set we can pass directly to open unless
- the port has just hung up or is in another error state */
+ * the port has just hung up or is in another error state.
+ */
if (tty_io_error(tty)) {
tty_port_set_active(port, 1);
return 0;
@@ -485,8 +486,9 @@ int tty_port_block_til_ready(struct tty_port *port,
do_clocal = 1;
/* Block waiting until we can proceed. We may need to wait for the
- carrier, but we must also wait for any close that is in progress
- before the next open may complete */
+ * carrier, but we must also wait for any close that is in progress
+ * before the next open may complete.
+ */
retval = 0;
@@ -503,7 +505,8 @@ int tty_port_block_til_ready(struct tty_port *port,
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
/* Check for a hangup or uninitialised port.
- Return accordingly */
+ * Return accordingly.
+ */
if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
if (port->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
@@ -530,7 +533,8 @@ int tty_port_block_til_ready(struct tty_port *port,
finish_wait(&port->open_wait, &wait);
/* Update counts. A parallel hangup will have set count to zero and
- we must not mess that up further */
+ * we must not mess that up further.
+ */
spin_lock_irqsave(&port->lock, flags);
if (!tty_hung_up_p(filp))
port->count++;
@@ -587,7 +591,7 @@ int tty_port_close_start(struct tty_port *port,
if (tty_port_initialized(port)) {
/* Don't block on a stalled port, just pull the chain */
- if (tty->flow_stopped)
+ if (tty->flow.tco_stopped)
tty_driver_flush_buffer(tty);
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, port->closing_wait);
@@ -688,6 +692,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
clear_bit(TTY_IO_ERROR, &tty->flags);
if (port->ops->activate) {
int retval = port->ops->activate(port, tty);
+
if (retval) {
mutex_unlock(&port->mutex);
return retval;
@@ -698,5 +703,4 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
mutex_unlock(&port->mutex);
return tty_port_block_til_ready(port, tty, filp);
}
-
EXPORT_SYMBOL(tty_port_open);
diff --git a/drivers/tty/ttynull.c b/drivers/tty/ttynull.c
index 17f05b7eb6d3..af3311a24917 100644
--- a/drivers/tty/ttynull.c
+++ b/drivers/tty/ttynull.c
@@ -35,7 +35,7 @@ static int ttynull_write(struct tty_struct *tty, const unsigned char *buf,
return count;
}
-static int ttynull_write_room(struct tty_struct *tty)
+static unsigned int ttynull_write_room(struct tty_struct *tty)
{
return 65536;
}
diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c
index 0a3a71e14df4..d06bcc3b4c07 100644
--- a/drivers/tty/vcc.c
+++ b/drivers/tty/vcc.c
@@ -473,9 +473,9 @@ static struct vio_version vcc_versions[] = {
static struct tty_port_operations vcc_port_ops = { 0 };
-static ssize_t vcc_sysfs_domain_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t domain_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct vcc_port *port;
int rv;
@@ -505,9 +505,9 @@ static int vcc_send_ctl(struct vcc_port *port, int ctl)
return rv;
}
-static ssize_t vcc_sysfs_break_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t break_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct vcc_port *port;
unsigned long flags;
@@ -530,8 +530,8 @@ static ssize_t vcc_sysfs_break_store(struct device *dev,
return rv;
}
-static DEVICE_ATTR(domain, 0400, vcc_sysfs_domain_show, NULL);
-static DEVICE_ATTR(break, 0200, NULL, vcc_sysfs_break_store);
+static DEVICE_ATTR_ADMIN_RO(domain);
+static DEVICE_ATTR_WO(break);
static struct attribute *vcc_sysfs_entries[] = {
&dev_attr_domain.attr,
@@ -668,7 +668,7 @@ free_port:
*
* Return: status of removal
*/
-static int vcc_remove(struct vio_dev *vdev)
+static void vcc_remove(struct vio_dev *vdev)
{
struct vcc_port *port = dev_get_drvdata(&vdev->dev);
@@ -703,8 +703,6 @@ static int vcc_remove(struct vio_dev *vdev)
kfree(port->domain);
kfree(port);
}
-
- return 0;
}
static const struct vio_device_id vcc_match[] = {
@@ -870,10 +868,10 @@ static int vcc_write(struct tty_struct *tty, const unsigned char *buf,
return total_sent ? total_sent : rv;
}
-static int vcc_write_room(struct tty_struct *tty)
+static unsigned int vcc_write_room(struct tty_struct *tty)
{
struct vcc_port *port;
- u64 num;
+ unsigned int num;
port = vcc_get_ne(tty->index);
if (unlikely(!port)) {
@@ -888,10 +886,10 @@ static int vcc_write_room(struct tty_struct *tty)
return num;
}
-static int vcc_chars_in_buffer(struct tty_struct *tty)
+static unsigned int vcc_chars_in_buffer(struct tty_struct *tty)
{
struct vcc_port *port;
- u64 num;
+ unsigned int num;
port = vcc_get_ne(tty->index);
if (unlikely(!port)) {
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 5d2309742718..4b0d69042ceb 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -515,7 +515,7 @@ static void fn_hold(struct vc_data *vc)
* these routines are also activated by ^S/^Q.
* (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
*/
- if (tty->stopped)
+ if (tty->flow.stopped)
start_tty(tty);
else
stop_tty(tty);
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index f245a5acf7e9..f7755e73696e 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -33,7 +33,7 @@
#include <linux/sched/signal.h>
/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
-#define isspace(c) ((c) == ' ')
+#define is_space_on_vt(c) ((c) == ' ')
/* FIXME: all this needs locking */
static struct vc_selection {
@@ -109,7 +109,7 @@ static inline int inword(const u32 c)
}
/**
- * set loadlut - load the LUT table
+ * sel_loadlut() - load the LUT table
* @p: user table
*
* Load the LUT table from user space. The caller must hold the console
@@ -209,7 +209,7 @@ static int vc_selection_store_chars(struct vc_data *vc, bool unicode)
bp += store_utf8(c, bp);
else
*bp++ = c;
- if (!isspace(c))
+ if (!is_space_on_vt(c))
obp = bp;
if (!((i + 2) % vc->vc_size_row)) {
/* strip trailing blanks from line and add newline,
@@ -238,9 +238,9 @@ static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps,
new_sel_end = pe;
break;
case TIOCL_SELWORD: /* word-by-word selection */
- spc = isspace(sel_pos(ps, unicode));
+ spc = is_space_on_vt(sel_pos(ps, unicode));
for (new_sel_start = ps; ; ps -= 2) {
- if ((spc && !isspace(sel_pos(ps, unicode))) ||
+ if ((spc && !is_space_on_vt(sel_pos(ps, unicode))) ||
(!spc && !inword(sel_pos(ps, unicode))))
break;
new_sel_start = ps;
@@ -248,9 +248,9 @@ static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps,
break;
}
- spc = isspace(sel_pos(pe, unicode));
+ spc = is_space_on_vt(sel_pos(pe, unicode));
for (new_sel_end = pe; ; pe += 2) {
- if ((spc && !isspace(sel_pos(pe, unicode))) ||
+ if ((spc && !is_space_on_vt(sel_pos(pe, unicode))) ||
(!spc && !inword(sel_pos(pe, unicode))))
break;
new_sel_end = pe;
@@ -276,12 +276,12 @@ static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps,
/* select to end of line if on trailing space */
if (new_sel_end > new_sel_start &&
!atedge(new_sel_end, vc->vc_size_row) &&
- isspace(sel_pos(new_sel_end, unicode))) {
+ is_space_on_vt(sel_pos(new_sel_end, unicode))) {
for (pe = new_sel_end + 2; ; pe += 2)
- if (!isspace(sel_pos(pe, unicode)) ||
+ if (!is_space_on_vt(sel_pos(pe, unicode)) ||
atedge(pe, vc->vc_size_row))
break;
- if (isspace(sel_pos(pe, unicode)))
+ if (is_space_on_vt(sel_pos(pe, unicode)))
new_sel_end = pe;
}
if (vc_sel.start == -1) /* no current selection */
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index fa1548d4f94b..ef981d3b7bb4 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1189,7 +1189,7 @@ static inline int resize_screen(struct vc_data *vc, int width, int height,
* information and perform any necessary signal handling.
*
* Caller must hold the console semaphore. Takes the termios rwsem and
- * ctrl_lock of the tty IFF a tty is passed.
+ * ctrl.lock of the tty IFF a tty is passed.
*/
static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
@@ -1355,7 +1355,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
* the actual work.
*
* Takes the console sem and the called methods then take the tty
- * termios_rwsem and the tty ctrl_lock in that order.
+ * termios_rwsem and the tty ctrl.lock in that order.
*/
static int vt_resize(struct tty_struct *tty, struct winsize *ws)
{
@@ -2888,7 +2888,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
param.vc = vc;
- while (!tty->stopped && count) {
+ while (!tty->flow.stopped && count) {
int orig = *buf;
buf++;
n++;
@@ -3260,23 +3260,16 @@ static int con_write(struct tty_struct *tty, const unsigned char *buf, int count
static int con_put_char(struct tty_struct *tty, unsigned char ch)
{
- if (in_interrupt())
- return 0; /* n_r3964 calls put_char() from interrupt context */
return do_con_write(tty, &ch, 1);
}
-static int con_write_room(struct tty_struct *tty)
+static unsigned int con_write_room(struct tty_struct *tty)
{
- if (tty->stopped)
+ if (tty->flow.stopped)
return 0;
return 32768; /* No limit, really; we're not buffering */
}
-static int con_chars_in_buffer(struct tty_struct *tty)
-{
- return 0; /* we're not buffering */
-}
-
/*
* con_throttle and con_unthrottle are only used for
* paste_selection(), which has to stuff in a large number of
@@ -3523,7 +3516,6 @@ static const struct tty_operations con_ops = {
.write_room = con_write_room,
.put_char = con_put_char,
.flush_chars = con_flush_chars,
- .chars_in_buffer = con_chars_in_buffer,
.ioctl = vt_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = vt_compat_ioctl,
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 5531f3afeb21..2e16c5338e5b 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -18,7 +18,7 @@ config UIO_CIF
depends on PCI
help
Driver for Hilscher CIF DeviceNet and Profibus cards. This
- driver requires a userspace component called cif that handles
+ driver requires a userspace component called cif that handles
all of the heavy lifting and can be found at:
<http://www.osadl.org/projects/downloads/UIO/user/>
diff --git a/drivers/uio/uio_aec.c b/drivers/uio/uio_aec.c
index 32357f8a92b5..64eafd59e6e7 100644
--- a/drivers/uio/uio_aec.c
+++ b/drivers/uio/uio_aec.c
@@ -133,7 +133,7 @@ static void remove(struct pci_dev *pdev)
uio_unregister_device(info);
pci_release_regions(pdev);
pci_disable_device(pdev);
- iounmap(info->priv);
+ pci_iounmap(pdev, info->priv);
}
static struct pci_driver pci_driver = {
diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c
index 3bb0b0075467..e03f9b532a96 100644
--- a/drivers/uio/uio_pci_generic.c
+++ b/drivers/uio/uio_pci_generic.c
@@ -72,7 +72,9 @@ static int probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct uio_pci_generic_dev *gdev;
+ struct uio_mem *uiomem;
int err;
+ int i;
err = pcim_enable_device(pdev);
if (err) {
@@ -101,6 +103,36 @@ static int probe(struct pci_dev *pdev,
"no support for interrupts?\n");
}
+ uiomem = &gdev->info.mem[0];
+ for (i = 0; i < MAX_UIO_MAPS; ++i) {
+ struct resource *r = &pdev->resource[i];
+
+ if (r->flags != (IORESOURCE_SIZEALIGN | IORESOURCE_MEM))
+ continue;
+
+ if (uiomem >= &gdev->info.mem[MAX_UIO_MAPS]) {
+ dev_warn(
+ &pdev->dev,
+ "device has more than " __stringify(
+ MAX_UIO_MAPS) " I/O memory resources.\n");
+ break;
+ }
+
+ uiomem->memtype = UIO_MEM_PHYS;
+ uiomem->addr = r->start & PAGE_MASK;
+ uiomem->offs = r->start & ~PAGE_MASK;
+ uiomem->size =
+ (uiomem->offs + resource_size(r) + PAGE_SIZE - 1) &
+ PAGE_MASK;
+ uiomem->name = r->name;
+ ++uiomem;
+ }
+
+ while (uiomem < &gdev->info.mem[MAX_UIO_MAPS]) {
+ uiomem->size = 0;
+ ++uiomem;
+ }
+
return devm_uio_register_device(&pdev->dev, &gdev->info);
}
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 4d3947476f0e..4ce7cba2b48a 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -180,7 +180,7 @@ struct cxacru_data {
struct mutex poll_state_serialize;
enum cxacru_poll_state poll_state;
- /* contol handles */
+ /* control handles */
struct mutex cm_serialize;
u8 *rcv_buf;
u8 *snd_buf;
diff --git a/drivers/usb/cdns3/cdns3-ep0.c b/drivers/usb/cdns3/cdns3-ep0.c
index 9a17802275d5..02ec7ab4bb48 100644
--- a/drivers/usb/cdns3/cdns3-ep0.c
+++ b/drivers/usb/cdns3/cdns3-ep0.c
@@ -677,7 +677,7 @@ static int cdns3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
}
/**
- * cdns3_gadget_ep0_queue Transfer data on endpoint zero
+ * cdns3_gadget_ep0_queue - Transfer data on endpoint zero
* @ep: pointer to endpoint zero object
* @request: pointer to request object
* @gfp_flags: gfp flags
@@ -772,7 +772,7 @@ static int cdns3_gadget_ep0_queue(struct usb_ep *ep,
}
/**
- * cdns3_gadget_ep_set_wedge Set wedge on selected endpoint
+ * cdns3_gadget_ep_set_wedge - Set wedge on selected endpoint
* @ep: endpoint object
*
* Returns 0
@@ -865,7 +865,7 @@ void cdns3_ep0_config(struct cdns3_device *priv_dev)
}
/**
- * cdns3_init_ep0 Initializes software endpoint 0 of gadget
+ * cdns3_init_ep0 - Initializes software endpoint 0 of gadget
* @priv_dev: extended gadget object
* @priv_ep: extended endpoint object
*
diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c
index 5281f8d3fb3d..5d8c982019af 100644
--- a/drivers/usb/cdns3/cdns3-gadget.c
+++ b/drivers/usb/cdns3/cdns3-gadget.c
@@ -155,7 +155,7 @@ static struct cdns3_request *cdns3_next_priv_request(struct list_head *list)
}
/**
- * select_ep - selects endpoint
+ * cdns3_select_ep - selects endpoint
* @priv_dev: extended gadget object
* @ep: endpoint address
*/
@@ -430,9 +430,7 @@ static int cdns3_start_all_request(struct cdns3_device *priv_dev,
if (ret)
return ret;
- list_del(&request->list);
- list_add_tail(&request->list,
- &priv_ep->pending_req_list);
+ list_move_tail(&request->list, &priv_ep->pending_req_list);
if (request->stream_id != 0 || (priv_ep->flags & EP_TDLCHK_EN))
break;
}
@@ -484,7 +482,7 @@ static void __cdns3_descmiss_copy_data(struct usb_request *request,
}
/**
- * cdns3_wa2_descmiss_copy_data copy data from internal requests to
+ * cdns3_wa2_descmiss_copy_data - copy data from internal requests to
* request queued by class driver.
* @priv_ep: extended endpoint object
* @request: request object
@@ -1835,7 +1833,7 @@ __must_hold(&priv_dev->lock)
}
/**
- * cdns3_device_irq_handler- interrupt handler for device part of controller
+ * cdns3_device_irq_handler - interrupt handler for device part of controller
*
* @irq: irq number for cdns3 core device
* @data: structure of cdns3
@@ -1879,7 +1877,7 @@ static irqreturn_t cdns3_device_irq_handler(int irq, void *data)
}
/**
- * cdns3_device_thread_irq_handler- interrupt handler for device part
+ * cdns3_device_thread_irq_handler - interrupt handler for device part
* of controller
*
* @irq: irq number for cdns3 core device
@@ -2022,7 +2020,7 @@ static void cdns3_configure_dmult(struct cdns3_device *priv_dev,
}
/**
- * cdns3_ep_config Configure hardware endpoint
+ * cdns3_ep_config - Configure hardware endpoint
* @priv_ep: extended endpoint object
* @enable: set EP_CFG_ENABLE bit in ep_cfg register.
*/
@@ -2221,7 +2219,7 @@ usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget,
}
/**
- * cdns3_gadget_ep_alloc_request Allocates request
+ * cdns3_gadget_ep_alloc_request - Allocates request
* @ep: endpoint object associated with request
* @gfp_flags: gfp flags
*
@@ -2244,7 +2242,7 @@ struct usb_request *cdns3_gadget_ep_alloc_request(struct usb_ep *ep,
}
/**
- * cdns3_gadget_ep_free_request Free memory occupied by request
+ * cdns3_gadget_ep_free_request - Free memory occupied by request
* @ep: endpoint object associated with request
* @request: request to free memory
*/
@@ -2261,7 +2259,7 @@ void cdns3_gadget_ep_free_request(struct usb_ep *ep,
}
/**
- * cdns3_gadget_ep_enable Enable endpoint
+ * cdns3_gadget_ep_enable - Enable endpoint
* @ep: endpoint object
* @desc: endpoint descriptor
*
@@ -2396,7 +2394,7 @@ exit:
}
/**
- * cdns3_gadget_ep_disable Disable endpoint
+ * cdns3_gadget_ep_disable - Disable endpoint
* @ep: endpoint object
*
* Returns 0 on success, error code elsewhere
@@ -2486,7 +2484,7 @@ static int cdns3_gadget_ep_disable(struct usb_ep *ep)
}
/**
- * cdns3_gadget_ep_queue Transfer data on endpoint
+ * __cdns3_gadget_ep_queue - Transfer data on endpoint
* @ep: endpoint object
* @request: request object
* @gfp_flags: gfp flags
@@ -2586,7 +2584,7 @@ static int cdns3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
}
/**
- * cdns3_gadget_ep_dequeue Remove request from transfer queue
+ * cdns3_gadget_ep_dequeue - Remove request from transfer queue
* @ep: endpoint object associated with request
* @request: request object
*
@@ -2653,7 +2651,7 @@ not_found:
}
/**
- * __cdns3_gadget_ep_set_halt Sets stall on selected endpoint
+ * __cdns3_gadget_ep_set_halt - Sets stall on selected endpoint
* Should be called after acquiring spin_lock and selecting ep
* @priv_ep: endpoint object to set stall on.
*/
@@ -2674,7 +2672,7 @@ void __cdns3_gadget_ep_set_halt(struct cdns3_endpoint *priv_ep)
}
/**
- * __cdns3_gadget_ep_clear_halt Clears stall on selected endpoint
+ * __cdns3_gadget_ep_clear_halt - Clears stall on selected endpoint
* Should be called after acquiring spin_lock and selecting ep
* @priv_ep: endpoint object to clear stall on
*/
@@ -2719,7 +2717,7 @@ int __cdns3_gadget_ep_clear_halt(struct cdns3_endpoint *priv_ep)
}
/**
- * cdns3_gadget_ep_set_halt Sets/clears stall on selected endpoint
+ * cdns3_gadget_ep_set_halt - Sets/clears stall on selected endpoint
* @ep: endpoint object to set/clear stall on
* @value: 1 for set stall, 0 for clear stall
*
@@ -2765,7 +2763,7 @@ static const struct usb_ep_ops cdns3_gadget_ep_ops = {
};
/**
- * cdns3_gadget_get_frame Returns number of actual ITP frame
+ * cdns3_gadget_get_frame - Returns number of actual ITP frame
* @gadget: gadget object
*
* Returns number of actual ITP frame
@@ -2874,7 +2872,7 @@ static void cdns3_gadget_config(struct cdns3_device *priv_dev)
}
/**
- * cdns3_gadget_udc_start Gadget start
+ * cdns3_gadget_udc_start - Gadget start
* @gadget: gadget object
* @driver: driver which operates on this gadget
*
@@ -2920,7 +2918,7 @@ static int cdns3_gadget_udc_start(struct usb_gadget *gadget,
}
/**
- * cdns3_gadget_udc_stop Stops gadget
+ * cdns3_gadget_udc_stop - Stops gadget
* @gadget: gadget object
*
* Returns 0
@@ -2983,7 +2981,7 @@ static void cdns3_free_all_eps(struct cdns3_device *priv_dev)
}
/**
- * cdns3_init_eps Initializes software endpoints of gadget
+ * cdns3_init_eps - Initializes software endpoints of gadget
* @priv_dev: extended gadget object
*
* Returns 0 on success, error code elsewhere
diff --git a/drivers/usb/cdns3/cdns3-imx.c b/drivers/usb/cdns3/cdns3-imx.c
index 74e758dc0895..59860d1753fd 100644
--- a/drivers/usb/cdns3/cdns3-imx.c
+++ b/drivers/usb/cdns3/cdns3-imx.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* cdns3-imx.c - NXP i.MX specific Glue layer for Cadence USB Controller
*
* Copyright (C) 2019 NXP
diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c
index e1deeada425c..4d0f027e5bd3 100644
--- a/drivers/usb/cdns3/cdns3-plat.c
+++ b/drivers/usb/cdns3/cdns3-plat.c
@@ -170,7 +170,7 @@ err_phy3_init:
}
/**
- * cdns3_remove - unbind drd driver and clean up
+ * cdns3_plat_remove() - unbind drd driver and clean up
* @pdev: Pointer to Linux platform device
*
* Returns 0 on success otherwise negative errno
diff --git a/drivers/usb/cdns3/cdns3-ti.c b/drivers/usb/cdns3/cdns3-ti.c
index eccb1c766bba..07c318770362 100644
--- a/drivers/usb/cdns3/cdns3-ti.c
+++ b/drivers/usb/cdns3/cdns3-ti.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* cdns3-ti.c - TI specific Glue layer for Cadence USB Controller
*
* Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c
index c083985e387b..c23f53e9b1ef 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.c
+++ b/drivers/usb/cdns3/cdnsp-gadget.c
@@ -56,7 +56,8 @@ u32 cdnsp_port_state_to_neutral(u32 state)
}
/**
- * Find the offset of the extended capabilities with capability ID id.
+ * cdnsp_find_next_ext_cap - Find the offset of the extended capabilities
+ * with capability ID id.
* @base: PCI MMIO registers base address.
* @start: Address at which to start looking, (0 or HCC_PARAMS to start at
* beginning of list)
@@ -1151,7 +1152,7 @@ static int cdnsp_gadget_ep_set_halt(struct usb_ep *ep, int value)
struct cdnsp_ep *pep = to_cdnsp_ep(ep);
struct cdnsp_device *pdev = pep->pdev;
struct cdnsp_request *preq;
- unsigned long flags = 0;
+ unsigned long flags;
int ret;
spin_lock_irqsave(&pdev->lock, flags);
@@ -1176,7 +1177,7 @@ static int cdnsp_gadget_ep_set_wedge(struct usb_ep *ep)
{
struct cdnsp_ep *pep = to_cdnsp_ep(ep);
struct cdnsp_device *pdev = pep->pdev;
- unsigned long flags = 0;
+ unsigned long flags;
int ret;
spin_lock_irqsave(&pdev->lock, flags);
diff --git a/drivers/usb/cdns3/cdnsp-mem.c b/drivers/usb/cdns3/cdnsp-mem.c
index 5d4c4bfe15b7..a47948a1623f 100644
--- a/drivers/usb/cdns3/cdnsp-mem.c
+++ b/drivers/usb/cdns3/cdnsp-mem.c
@@ -1082,9 +1082,8 @@ void cdnsp_mem_cleanup(struct cdnsp_device *pdev)
dma_pool_destroy(pdev->device_pool);
pdev->device_pool = NULL;
- if (pdev->dcbaa)
- dma_free_coherent(dev, sizeof(*pdev->dcbaa),
- pdev->dcbaa, pdev->dcbaa->dma);
+ dma_free_coherent(dev, sizeof(*pdev->dcbaa),
+ pdev->dcbaa, pdev->dcbaa->dma);
pdev->dcbaa = NULL;
diff --git a/drivers/usb/cdns3/cdnsp-trace.h b/drivers/usb/cdns3/cdnsp-trace.h
index 5aa88ca012de..6a2571c6aa9e 100644
--- a/drivers/usb/cdns3/cdnsp-trace.h
+++ b/drivers/usb/cdns3/cdnsp-trace.h
@@ -138,7 +138,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_simple,
__string(text, msg)
),
TP_fast_assign(
- __assign_str(text, msg)
+ __assign_str(text, msg);
),
TP_printk("%s", __get_str(text))
);
diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c
index bb739d88179f..dbcdf3b24b47 100644
--- a/drivers/usb/cdns3/core.c
+++ b/drivers/usb/cdns3/core.c
@@ -332,7 +332,7 @@ exit:
}
/**
- * cdsn3_role_get - get current role of controller.
+ * cdns_role_get - get current role of controller.
*
* @sw: pointer to USB role switch structure
*
@@ -419,7 +419,7 @@ static irqreturn_t cdns_wakeup_irq(int irq, void *data)
}
/**
- * cdns_probe - probe for cdns3/cdnsp core device
+ * cdns_init - probe for cdns3/cdnsp core device
* @cdns: Pointer to cdns structure.
*
* Returns 0 on success otherwise negative errno
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 0697eb980e5f..99440baa6458 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -195,7 +195,6 @@ struct hw_bank {
* @phy: pointer to PHY, if any
* @usb_phy: pointer to USB PHY, if any and if using the USB PHY framework
* @hcd: pointer to usb_hcd for ehci host driver
- * @debugfs: root dentry for this controller in debugfs
* @id_event: indicates there is an id event, and handled at ci_otg_work
* @b_sess_valid_event: indicates there is a vbus event, and handled
* at ci_otg_work
@@ -249,7 +248,6 @@ struct ci_hdrc {
/* old usb_phy interface */
struct usb_phy *usb_phy;
struct usb_hcd *hcd;
- struct dentry *debugfs;
bool id_event;
bool b_sess_valid_event;
bool imx28_write_fix;
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 3f6c21406dbd..2b18f5088ae4 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -335,7 +335,7 @@ static int _ci_usb_phy_init(struct ci_hdrc *ci)
}
/**
- * _ci_usb_phy_exit: deinitialize phy taking in account both phy and usb_phy
+ * ci_usb_phy_exit: deinitialize phy taking in account both phy and usb_phy
* interfaces
* @ci: the controller
*/
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index da5d18cf6840..faf6b078b6c4 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -342,26 +342,20 @@ DEFINE_SHOW_ATTRIBUTE(ci_registers);
*/
void dbg_create_files(struct ci_hdrc *ci)
{
- ci->debugfs = debugfs_create_dir(dev_name(ci->dev), usb_debug_root);
-
- debugfs_create_file("device", S_IRUGO, ci->debugfs, ci,
- &ci_device_fops);
- debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs, ci,
- &ci_port_test_fops);
- debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci,
- &ci_qheads_fops);
- debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci,
- &ci_requests_fops);
-
- if (ci_otg_is_fsm_mode(ci)) {
- debugfs_create_file("otg", S_IRUGO, ci->debugfs, ci,
- &ci_otg_fops);
- }
+ struct dentry *dir;
+
+ dir = debugfs_create_dir(dev_name(ci->dev), usb_debug_root);
+
+ debugfs_create_file("device", S_IRUGO, dir, ci, &ci_device_fops);
+ debugfs_create_file("port_test", S_IRUGO | S_IWUSR, dir, ci, &ci_port_test_fops);
+ debugfs_create_file("qheads", S_IRUGO, dir, ci, &ci_qheads_fops);
+ debugfs_create_file("requests", S_IRUGO, dir, ci, &ci_requests_fops);
+
+ if (ci_otg_is_fsm_mode(ci))
+ debugfs_create_file("otg", S_IRUGO, dir, ci, &ci_otg_fops);
- debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci,
- &ci_role_fops);
- debugfs_create_file("registers", S_IRUGO, ci->debugfs, ci,
- &ci_registers_fops);
+ debugfs_create_file("role", S_IRUGO | S_IWUSR, dir, ci, &ci_role_fops);
+ debugfs_create_file("registers", S_IRUGO, dir, ci, &ci_registers_fops);
}
/**
@@ -370,5 +364,5 @@ void dbg_create_files(struct ci_hdrc *ci)
*/
void dbg_remove_files(struct ci_hdrc *ci)
{
- debugfs_remove_recursive(ci->debugfs);
+ debugfs_remove(debugfs_lookup(dev_name(ci->dev), usb_debug_root));
}
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
index d3aada3ce7ec..8dd59282827b 100644
--- a/drivers/usb/chipidea/otg.c
+++ b/drivers/usb/chipidea/otg.c
@@ -22,7 +22,7 @@
#include "otg_fsm.h"
/**
- * hw_read_otgsc returns otgsc register bits value.
+ * hw_read_otgsc - returns otgsc register bits value.
* @ci: the controller
* @mask: bitfield mask
*/
@@ -75,7 +75,7 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask)
}
/**
- * hw_write_otgsc updates target bits of OTGSC register.
+ * hw_write_otgsc - updates target bits of OTGSC register.
* @ci: the controller
* @mask: bitfield mask
* @data: to be written
@@ -140,8 +140,9 @@ void ci_handle_vbus_change(struct ci_hdrc *ci)
}
/**
- * When we switch to device mode, the vbus value should be lower
- * than OTGSC_BSV before connecting to host.
+ * hw_wait_vbus_lower_bsv - When we switch to device mode, the vbus value
+ * should be lower than OTGSC_BSV before connecting
+ * to host.
*
* @ci: the controller
*
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 393f216b9161..8834ca613721 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -238,7 +238,7 @@ static int hw_ep_set_halt(struct ci_hdrc *ci, int num, int dir, int value)
}
/**
- * hw_is_port_high_speed: test if port is high speed
+ * hw_port_is_high_speed: test if port is high speed
* @ci: the controller
*
* This function returns true if high speed port
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index ca7a61190dd9..4895325b16a4 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -838,7 +838,7 @@ static int acm_tty_write(struct tty_struct *tty,
return count;
}
-static int acm_tty_write_room(struct tty_struct *tty)
+static unsigned int acm_tty_write_room(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
/*
@@ -848,7 +848,7 @@ static int acm_tty_write_room(struct tty_struct *tty)
return acm_wb_is_avail(acm) ? acm->writesize : 0;
}
-static int acm_tty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int acm_tty_chars_in_buffer(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
/*
@@ -1056,21 +1056,8 @@ static void acm_tty_set_termios(struct tty_struct *tty,
newline.bParityType = termios->c_cflag & PARENB ?
(termios->c_cflag & PARODD ? 1 : 2) +
(termios->c_cflag & CMSPAR ? 2 : 0) : 0;
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- newline.bDataBits = 5;
- break;
- case CS6:
- newline.bDataBits = 6;
- break;
- case CS7:
- newline.bDataBits = 7;
- break;
- case CS8:
- default:
- newline.bDataBits = 8;
- break;
- }
+ newline.bDataBits = tty_get_char_size(termios->c_cflag);
+
/* FIXME: Needs to clear unsupported bits in the termios */
acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
@@ -1959,6 +1946,11 @@ static const struct usb_device_id acm_ids[] = {
.driver_info = IGNORE_DEVICE,
},
+ /* Exclude Heimann Sensor GmbH USB appset demo */
+ { USB_DEVICE(0x32a7, 0x0000),
+ .driver_info = IGNORE_DEVICE,
+ },
+
/* control interfaces without any protocol set */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_PROTO_NONE) },
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index d1e4a7379beb..fdf79bcf7eb0 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -21,8 +21,10 @@
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/poll.h>
+#include <linux/skbuff.h>
#include <linux/usb.h>
#include <linux/usb/cdc.h>
+#include <linux/wwan.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <linux/usb/cdc-wdm.h>
@@ -55,6 +57,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_SUSPENDING 8
#define WDM_RESETTING 9
#define WDM_OVERFLOW 10
+#define WDM_WWAN_IN_USE 11
#define WDM_MAX 16
@@ -106,6 +109,9 @@ struct wdm_device {
struct list_head device_list;
int (*manage_power)(struct usb_interface *, int);
+
+ enum wwan_port_type wwanp_type;
+ struct wwan_port *wwanp;
};
static struct usb_driver wdm_driver;
@@ -157,6 +163,8 @@ static void wdm_out_callback(struct urb *urb)
wake_up_all(&desc->wait);
}
+static void wdm_wwan_rx(struct wdm_device *desc, int length);
+
static void wdm_in_callback(struct urb *urb)
{
unsigned long flags;
@@ -192,6 +200,11 @@ static void wdm_in_callback(struct urb *urb)
}
}
+ if (test_bit(WDM_WWAN_IN_USE, &desc->flags)) {
+ wdm_wwan_rx(desc, length);
+ goto out;
+ }
+
/*
* only set a new error if there is no previous error.
* Errors are only cleared during read/open
@@ -226,6 +239,7 @@ skip_error:
set_bit(WDM_READ, &desc->flags);
wake_up(&desc->wait);
}
+out:
spin_unlock_irqrestore(&desc->iuspin, flags);
}
@@ -708,6 +722,11 @@ static int wdm_open(struct inode *inode, struct file *file)
goto out;
file->private_data = desc;
+ if (test_bit(WDM_WWAN_IN_USE, &desc->flags)) {
+ rv = -EBUSY;
+ goto out;
+ }
+
rv = usb_autopm_get_interface(desc->intf);
if (rv < 0) {
dev_err(&desc->intf->dev, "Error autopm - %d\n", rv);
@@ -804,6 +823,152 @@ static struct usb_class_driver wdm_class = {
.minor_base = WDM_MINOR_BASE,
};
+/* --- WWAN framework integration --- */
+#ifdef CONFIG_WWAN
+static int wdm_wwan_port_start(struct wwan_port *port)
+{
+ struct wdm_device *desc = wwan_port_get_drvdata(port);
+
+ /* The interface is both exposed via the WWAN framework and as a
+ * legacy usbmisc chardev. If chardev is already open, just fail
+ * to prevent concurrent usage. Otherwise, switch to WWAN mode.
+ */
+ mutex_lock(&wdm_mutex);
+ if (desc->count) {
+ mutex_unlock(&wdm_mutex);
+ return -EBUSY;
+ }
+ set_bit(WDM_WWAN_IN_USE, &desc->flags);
+ mutex_unlock(&wdm_mutex);
+
+ desc->manage_power(desc->intf, 1);
+
+ /* tx is allowed */
+ wwan_port_txon(port);
+
+ /* Start getting events */
+ return usb_submit_urb(desc->validity, GFP_KERNEL);
+}
+
+static void wdm_wwan_port_stop(struct wwan_port *port)
+{
+ struct wdm_device *desc = wwan_port_get_drvdata(port);
+
+ /* Stop all transfers and disable WWAN mode */
+ poison_urbs(desc);
+ desc->manage_power(desc->intf, 0);
+ clear_bit(WDM_READ, &desc->flags);
+ clear_bit(WDM_WWAN_IN_USE, &desc->flags);
+ unpoison_urbs(desc);
+}
+
+static void wdm_wwan_port_tx_complete(struct urb *urb)
+{
+ struct sk_buff *skb = urb->context;
+ struct wdm_device *desc = skb_shinfo(skb)->destructor_arg;
+
+ usb_autopm_put_interface(desc->intf);
+ wwan_port_txon(desc->wwanp);
+ kfree_skb(skb);
+}
+
+static int wdm_wwan_port_tx(struct wwan_port *port, struct sk_buff *skb)
+{
+ struct wdm_device *desc = wwan_port_get_drvdata(port);
+ struct usb_interface *intf = desc->intf;
+ struct usb_ctrlrequest *req = desc->orq;
+ int rv;
+
+ rv = usb_autopm_get_interface(intf);
+ if (rv)
+ return rv;
+
+ usb_fill_control_urb(
+ desc->command,
+ interface_to_usbdev(intf),
+ usb_sndctrlpipe(interface_to_usbdev(intf), 0),
+ (unsigned char *)req,
+ skb->data,
+ skb->len,
+ wdm_wwan_port_tx_complete,
+ skb
+ );
+
+ req->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
+ req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;
+ req->wValue = 0;
+ req->wIndex = desc->inum;
+ req->wLength = cpu_to_le16(skb->len);
+
+ skb_shinfo(skb)->destructor_arg = desc;
+
+ rv = usb_submit_urb(desc->command, GFP_KERNEL);
+ if (rv)
+ usb_autopm_put_interface(intf);
+ else /* One transfer at a time, stop TX until URB completion */
+ wwan_port_txoff(port);
+
+ return rv;
+}
+
+static struct wwan_port_ops wdm_wwan_port_ops = {
+ .start = wdm_wwan_port_start,
+ .stop = wdm_wwan_port_stop,
+ .tx = wdm_wwan_port_tx,
+};
+
+static void wdm_wwan_init(struct wdm_device *desc)
+{
+ struct usb_interface *intf = desc->intf;
+ struct wwan_port *port;
+
+ /* Only register to WWAN core if protocol/type is known */
+ if (desc->wwanp_type == WWAN_PORT_UNKNOWN) {
+ dev_info(&intf->dev, "Unknown control protocol\n");
+ return;
+ }
+
+ port = wwan_create_port(&intf->dev, desc->wwanp_type, &wdm_wwan_port_ops, desc);
+ if (IS_ERR(port)) {
+ dev_err(&intf->dev, "%s: Unable to create WWAN port\n",
+ dev_name(intf->usb_dev));
+ return;
+ }
+
+ desc->wwanp = port;
+}
+
+static void wdm_wwan_deinit(struct wdm_device *desc)
+{
+ if (!desc->wwanp)
+ return;
+
+ wwan_remove_port(desc->wwanp);
+ desc->wwanp = NULL;
+}
+
+static void wdm_wwan_rx(struct wdm_device *desc, int length)
+{
+ struct wwan_port *port = desc->wwanp;
+ struct sk_buff *skb;
+
+ /* Forward data to WWAN port */
+ skb = alloc_skb(length, GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ memcpy(skb_put(skb, length), desc->inbuf, length);
+ wwan_port_rx(port, skb);
+
+ /* inbuf has been copied, it is safe to check for outstanding data */
+ schedule_work(&desc->service_outs_intr);
+}
+#else /* CONFIG_WWAN */
+static void wdm_wwan_init(struct wdm_device *desc) {}
+static void wdm_wwan_deinit(struct wdm_device *desc) {}
+static void wdm_wwan_rx(struct wdm_device *desc, int length) {}
+#endif /* CONFIG_WWAN */
+
/* --- error handling --- */
static void wdm_rxwork(struct work_struct *work)
{
@@ -848,7 +1013,8 @@ static void service_interrupt_work(struct work_struct *work)
/* --- hotplug --- */
static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep,
- u16 bufsize, int (*manage_power)(struct usb_interface *, int))
+ u16 bufsize, enum wwan_port_type type,
+ int (*manage_power)(struct usb_interface *, int))
{
int rv = -ENOMEM;
struct wdm_device *desc;
@@ -865,12 +1031,14 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
/* this will be expanded and needed in hardware endianness */
desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber);
desc->intf = intf;
+ desc->wwanp_type = type;
INIT_WORK(&desc->rxwork, wdm_rxwork);
INIT_WORK(&desc->service_outs_intr, service_interrupt_work);
- rv = -EINVAL;
- if (!usb_endpoint_is_int_in(ep))
+ if (!usb_endpoint_is_int_in(ep)) {
+ rv = -EINVAL;
goto err;
+ }
desc->wMaxPacketSize = usb_endpoint_maxp(ep);
@@ -945,6 +1113,9 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
goto err;
else
dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev));
+
+ wdm_wwan_init(desc);
+
out:
return rv;
err:
@@ -989,7 +1160,7 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
goto err;
ep = &iface->endpoint[0].desc;
- rv = wdm_create(intf, ep, maxcom, &wdm_manage_power);
+ rv = wdm_create(intf, ep, maxcom, WWAN_PORT_UNKNOWN, &wdm_manage_power);
err:
return rv;
@@ -1000,6 +1171,7 @@ err:
* @intf: usb interface the subdriver will associate with
* @ep: interrupt endpoint to monitor for notifications
* @bufsize: maximum message size to support for read/write
+ * @type: Type/protocol of the transported data (MBIM, QMI...)
* @manage_power: call-back invoked during open and release to
* manage the device's power
* Create WDM usb class character device and associate it with intf
@@ -1017,12 +1189,12 @@ err:
*/
struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
struct usb_endpoint_descriptor *ep,
- int bufsize,
+ int bufsize, enum wwan_port_type type,
int (*manage_power)(struct usb_interface *, int))
{
int rv;
- rv = wdm_create(intf, ep, bufsize, manage_power);
+ rv = wdm_create(intf, ep, bufsize, type, manage_power);
if (rv < 0)
goto err;
@@ -1041,6 +1213,8 @@ static void wdm_disconnect(struct usb_interface *intf)
desc = wdm_find_device(intf);
mutex_lock(&wdm_mutex);
+ wdm_wwan_deinit(desc);
+
/* the spinlock makes sure no new urbs are generated in the callbacks */
spin_lock_irqsave(&desc->iuspin, flags);
set_bit(WDM_DISCONNECTING, &desc->flags);
diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c
index ce5e6f6711f7..7e13b74e60e5 100644
--- a/drivers/usb/common/ulpi.c
+++ b/drivers/usb/common/ulpi.c
@@ -141,7 +141,7 @@ static const struct device_type ulpi_dev_type = {
/* -------------------------------------------------------------------------- */
/**
- * ulpi_register_driver - register a driver with the ULPI bus
+ * __ulpi_register_driver - register a driver with the ULPI bus
* @drv: driver being registered
* @module: ends up being THIS_MODULE
*
diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c
index 6c4e3a19f42c..0158148cb054 100644
--- a/drivers/usb/common/usb-conn-gpio.c
+++ b/drivers/usb/common/usb-conn-gpio.c
@@ -83,11 +83,11 @@ static void usb_conn_detect_cable(struct work_struct *work)
else
role = USB_ROLE_NONE;
- dev_dbg(info->dev, "role %d/%d, gpios: id %d, vbus %d\n",
- info->last_role, role, id, vbus);
+ dev_dbg(info->dev, "role %s -> %s, gpios: id %d, vbus %d\n",
+ usb_role_string(info->last_role), usb_role_string(role), id, vbus);
if (info->last_role == role) {
- dev_warn(info->dev, "repeated role: %d\n", role);
+ dev_warn(info->dev, "repeated role: %s\n", usb_role_string(role));
return;
}
@@ -149,14 +149,32 @@ static int usb_charger_get_property(struct power_supply *psy,
return 0;
}
-static int usb_conn_probe(struct platform_device *pdev)
+static int usb_conn_psy_register(struct usb_conn_info *info)
{
- struct device *dev = &pdev->dev;
- struct power_supply_desc *desc;
- struct usb_conn_info *info;
+ struct device *dev = info->dev;
+ struct power_supply_desc *desc = &info->desc;
struct power_supply_config cfg = {
.of_node = dev->of_node,
};
+
+ desc->name = "usb-charger";
+ desc->properties = usb_charger_properties;
+ desc->num_properties = ARRAY_SIZE(usb_charger_properties);
+ desc->get_property = usb_charger_get_property;
+ desc->type = POWER_SUPPLY_TYPE_USB;
+ cfg.drv_data = info;
+
+ info->charger = devm_power_supply_register(dev, desc, &cfg);
+ if (IS_ERR(info->charger))
+ dev_err(dev, "Unable to register charger\n");
+
+ return PTR_ERR_OR_ZERO(info->charger);
+}
+
+static int usb_conn_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct usb_conn_info *info;
bool need_vbus = true;
int ret = 0;
@@ -205,18 +223,18 @@ static int usb_conn_probe(struct platform_device *pdev)
}
if (IS_ERR(info->vbus)) {
- if (PTR_ERR(info->vbus) != -EPROBE_DEFER)
- dev_err(dev, "failed to get vbus: %ld\n", PTR_ERR(info->vbus));
- return PTR_ERR(info->vbus);
+ ret = PTR_ERR(info->vbus);
+ return dev_err_probe(dev, ret, "failed to get vbus :%d\n", ret);
}
info->role_sw = usb_role_switch_get(dev);
- if (IS_ERR(info->role_sw)) {
- if (PTR_ERR(info->role_sw) != -EPROBE_DEFER)
- dev_err(dev, "failed to get role switch\n");
+ if (IS_ERR(info->role_sw))
+ return dev_err_probe(dev, PTR_ERR(info->role_sw),
+ "failed to get role switch\n");
- return PTR_ERR(info->role_sw);
- }
+ ret = usb_conn_psy_register(info);
+ if (ret)
+ goto put_role_sw;
if (info->id_gpiod) {
info->id_irq = gpiod_to_irq(info->id_gpiod);
@@ -252,20 +270,6 @@ static int usb_conn_probe(struct platform_device *pdev)
}
}
- desc = &info->desc;
- desc->name = "usb-charger";
- desc->properties = usb_charger_properties;
- desc->num_properties = ARRAY_SIZE(usb_charger_properties);
- desc->get_property = usb_charger_get_property;
- desc->type = POWER_SUPPLY_TYPE_USB;
- cfg.drv_data = info;
-
- info->charger = devm_power_supply_register(dev, desc, &cfg);
- if (IS_ERR(info->charger)) {
- dev_err(dev, "Unable to register charger\n");
- return PTR_ERR(info->charger);
- }
-
platform_set_drvdata(pdev, info);
/* Perform initial detection */
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 2218941d35a3..b97464498763 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1162,7 +1162,7 @@ static int do_proc_control(struct usb_dev_state *ps,
tbuf, ctrl->wLength);
usb_unlock_device(dev);
- i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl->bRequest,
+ i = usb_control_msg(dev, pipe, ctrl->bRequest,
ctrl->bRequestType, ctrl->wValue, ctrl->wIndex,
tbuf, ctrl->wLength, tmo);
usb_lock_device(dev);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 6119fb41d736..0f8b7c93310e 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2111,6 +2111,136 @@ int usb_hcd_get_frame_number (struct usb_device *udev)
}
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_HCD_TEST_MODE
+
+static void usb_ehset_completion(struct urb *urb)
+{
+ struct completion *done = urb->context;
+
+ complete(done);
+}
+/*
+ * Allocate and initialize a control URB. This request will be used by the
+ * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
+ * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
+ * Return NULL if failed.
+ */
+static struct urb *request_single_step_set_feature_urb(
+ struct usb_device *udev,
+ void *dr,
+ void *buf,
+ struct completion *done)
+{
+ struct urb *urb;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ struct usb_host_endpoint *ep;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return NULL;
+
+ urb->pipe = usb_rcvctrlpipe(udev, 0);
+ ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
+ [usb_pipeendpoint(urb->pipe)];
+ if (!ep) {
+ usb_free_urb(urb);
+ return NULL;
+ }
+
+ urb->ep = ep;
+ urb->dev = udev;
+ urb->setup_packet = (void *)dr;
+ urb->transfer_buffer = buf;
+ urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
+ urb->complete = usb_ehset_completion;
+ urb->status = -EINPROGRESS;
+ urb->actual_length = 0;
+ urb->transfer_flags = URB_DIR_IN;
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ if (map_urb_for_dma(hcd, urb, GFP_KERNEL)) {
+ usb_put_urb(urb);
+ usb_free_urb(urb);
+ return NULL;
+ }
+
+ urb->context = done;
+ return urb;
+}
+
+int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
+{
+ int retval = -ENOMEM;
+ struct usb_ctrlrequest *dr;
+ struct urb *urb;
+ struct usb_device *udev;
+ struct usb_device_descriptor *buf;
+ DECLARE_COMPLETION_ONSTACK(done);
+
+ /* Obtain udev of the rhub's child port */
+ udev = usb_hub_find_child(hcd->self.root_hub, port);
+ if (!udev) {
+ dev_err(hcd->self.controller, "No device attached to the RootHub\n");
+ return -ENODEV;
+ }
+ buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!dr) {
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ /* Fill Setup packet for GetDescriptor */
+ dr->bRequestType = USB_DIR_IN;
+ dr->bRequest = USB_REQ_GET_DESCRIPTOR;
+ dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
+ dr->wIndex = 0;
+ dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
+ urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
+ if (!urb)
+ goto cleanup;
+
+ /* Submit just the SETUP stage */
+ retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 1);
+ if (retval)
+ goto out1;
+ if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ dev_err(hcd->self.controller,
+ "%s SETUP stage timed out on ep0\n", __func__);
+ goto out1;
+ }
+ msleep(15 * 1000);
+
+ /* Complete remaining DATA and STATUS stages using the same URB */
+ urb->status = -EINPROGRESS;
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 0);
+ if (!retval && !wait_for_completion_timeout(&done,
+ msecs_to_jiffies(2000))) {
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ dev_err(hcd->self.controller,
+ "%s IN stage timed out on ep0\n", __func__);
+ }
+out1:
+ usb_free_urb(urb);
+cleanup:
+ kfree(dr);
+ kfree(buf);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(ehset_single_step_set_feature);
+#endif /* CONFIG_USB_HCD_TEST_MODE */
+
+/*-------------------------------------------------------------------------*/
#ifdef CONFIG_PM
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index df8e69e60aaf..d1efc7141333 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2434,6 +2434,8 @@ static void set_usb_port_removable(struct usb_device *udev)
u16 wHubCharacteristics;
bool removable = true;
+ dev_set_removable(&udev->dev, DEVICE_REMOVABLE_UNKNOWN);
+
if (!hdev)
return;
@@ -2445,11 +2447,11 @@ static void set_usb_port_removable(struct usb_device *udev)
*/
switch (hub->ports[udev->portnum - 1]->connect_type) {
case USB_PORT_CONNECT_TYPE_HOT_PLUG:
- udev->removable = USB_DEVICE_REMOVABLE;
+ dev_set_removable(&udev->dev, DEVICE_REMOVABLE);
return;
case USB_PORT_CONNECT_TYPE_HARD_WIRED:
case USB_PORT_NOT_USED:
- udev->removable = USB_DEVICE_FIXED;
+ dev_set_removable(&udev->dev, DEVICE_FIXED);
return;
default:
break;
@@ -2474,9 +2476,9 @@ static void set_usb_port_removable(struct usb_device *udev)
}
if (removable)
- udev->removable = USB_DEVICE_REMOVABLE;
+ dev_set_removable(&udev->dev, DEVICE_REMOVABLE);
else
- udev->removable = USB_DEVICE_FIXED;
+ dev_set_removable(&udev->dev, DEVICE_FIXED);
}
@@ -2548,8 +2550,7 @@ int usb_new_device(struct usb_device *udev)
device_enable_async_suspend(&udev->dev);
/* check whether the hub or firmware marks this port as non-removable */
- if (udev->parent)
- set_usb_port_removable(udev);
+ set_usb_port_removable(udev);
/* Register the device. The device driver is responsible
* for configuring the device and invoking the add-device
@@ -3387,6 +3388,26 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
status = 0;
}
if (status) {
+ /* Check if the port has been suspended for the timeout case
+ * to prevent the suspended port from incorrect handling.
+ */
+ if (status == -ETIMEDOUT) {
+ int ret;
+ u16 portstatus, portchange;
+
+ portstatus = portchange = 0;
+ ret = hub_port_status(hub, port1, &portstatus,
+ &portchange);
+
+ dev_dbg(&port_dev->dev,
+ "suspend timeout, status %04x\n", portstatus);
+
+ if (ret == 0 && port_is_suspended(hub, portstatus)) {
+ status = 0;
+ goto suspend_done;
+ }
+ }
+
dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status);
/* Try to enable USB3 LTM again */
@@ -3403,6 +3424,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
if (!PMSG_IS_AUTO(msg))
status = 0;
} else {
+ suspend_done:
dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n",
(PMSG_IS_AUTO(msg) ? "auto-" : ""),
udev->do_remote_wakeup);
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 30e9e680c74c..4d59d927ae3e 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -783,6 +783,9 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type,
int i;
int result;
+ if (size <= 0) /* No point in asking for no data */
+ return -EINVAL;
+
memset(buf, 0, size); /* Make sure we parse really received data */
for (i = 0; i < 3; ++i) {
@@ -832,6 +835,9 @@ static int usb_get_string(struct usb_device *dev, unsigned short langid,
int i;
int result;
+ if (size <= 0) /* No point in asking for no data */
+ return -EINVAL;
+
for (i = 0; i < 3; ++i) {
/* retry on length 0 or stall; some devices are flakey */
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 21e7522655ac..6114cf83bb44 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -406,7 +406,6 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Realtek hub in Dell WD19 (Type-C) */
{ USB_DEVICE(0x0bda, 0x0487), .driver_info = USB_QUIRK_NO_LPM },
- { USB_DEVICE(0x0bda, 0x5487), .driver_info = USB_QUIRK_RESET_RESUME },
/* Generic RTL8153 based ethernet adapters */
{ USB_DEVICE(0x0bda, 0x8153), .driver_info = USB_QUIRK_NO_LPM },
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 5a168ba9fc51..fa2e49d432ff 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -301,29 +301,6 @@ static ssize_t urbnum_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(urbnum);
-static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct usb_device *udev;
- char *state;
-
- udev = to_usb_device(dev);
-
- switch (udev->removable) {
- case USB_DEVICE_REMOVABLE:
- state = "removable";
- break;
- case USB_DEVICE_FIXED:
- state = "fixed";
- break;
- default:
- state = "unknown";
- }
-
- return sprintf(buf, "%s\n", state);
-}
-static DEVICE_ATTR_RO(removable);
-
static ssize_t ltm_capable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -828,7 +805,6 @@ static struct attribute *dev_attrs[] = {
&dev_attr_avoid_reset_quirk.attr,
&dev_attr_authorized.attr,
&dev_attr_remove.attr,
- &dev_attr_removable.attr,
&dev_attr_ltm_capable.attr,
#ifdef CONFIG_OF
&dev_attr_devspec.attr,
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 357b149b20d3..30727729a44c 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -407,6 +407,15 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
return -ENOEXEC;
is_out = !(setup->bRequestType & USB_DIR_IN) ||
!setup->wLength;
+ dev_WARN_ONCE(&dev->dev, (usb_pipeout(urb->pipe) != is_out),
+ "BOGUS control dir, pipe %x doesn't match bRequestType %x\n",
+ urb->pipe, setup->bRequestType);
+ if (le16_to_cpu(setup->wLength) != urb->transfer_buffer_length) {
+ dev_dbg(&dev->dev, "BOGUS control len %d doesn't match transfer length %d\n",
+ le16_to_cpu(setup->wLength),
+ urb->transfer_buffer_length);
+ return -EBADR;
+ }
} else {
is_out = usb_endpoint_dir_out(&ep->desc);
}
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index 6f70ab9577b4..272ae5722c86 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -1111,15 +1111,6 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16);
if (hsotg->params.phy_utmi_width == 16)
usbcfg |= GUSBCFG_PHYIF16;
-
- /* Set turnaround time */
- if (dwc2_is_device_mode(hsotg)) {
- usbcfg &= ~GUSBCFG_USBTRDTIM_MASK;
- if (hsotg->params.phy_utmi_width == 16)
- usbcfg |= 5 << GUSBCFG_USBTRDTIM_SHIFT;
- else
- usbcfg |= 9 << GUSBCFG_USBTRDTIM_SHIFT;
- }
break;
default:
dev_err(hsotg->dev, "FS PHY selected at HS!\n");
@@ -1141,6 +1132,24 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
return retval;
}
+static void dwc2_set_turnaround_time(struct dwc2_hsotg *hsotg)
+{
+ u32 usbcfg;
+
+ if (hsotg->params.phy_type != DWC2_PHY_TYPE_PARAM_UTMI)
+ return;
+
+ usbcfg = dwc2_readl(hsotg, GUSBCFG);
+
+ usbcfg &= ~GUSBCFG_USBTRDTIM_MASK;
+ if (hsotg->params.phy_utmi_width == 16)
+ usbcfg |= 5 << GUSBCFG_USBTRDTIM_SHIFT;
+ else
+ usbcfg |= 9 << GUSBCFG_USBTRDTIM_SHIFT;
+
+ dwc2_writel(hsotg, usbcfg, GUSBCFG);
+}
+
int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
{
u32 usbcfg;
@@ -1158,6 +1167,9 @@ int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
retval = dwc2_hs_phy_init(hsotg, select_phy);
if (retval)
return retval;
+
+ if (dwc2_is_device_mode(hsotg))
+ dwc2_set_turnaround_time(hsotg);
}
if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 184964174dc0..c581ee41ac81 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -1496,8 +1496,8 @@ static int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req,
{
struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
struct dwc2_hsotg *hs = hs_ep->parent;
- unsigned long flags = 0;
- int ret = 0;
+ unsigned long flags;
+ int ret;
spin_lock_irqsave(&hs->lock, flags);
ret = dwc2_hsotg_ep_queue(ep, req, gfp_flags);
@@ -3338,7 +3338,7 @@ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic)
static int dwc2_hsotg_ep_disable(struct usb_ep *ep);
/**
- * dwc2_hsotg_core_init - issue softreset to the core
+ * dwc2_hsotg_core_init_disconnected - issue softreset to the core
* @hsotg: The device state
* @is_usb_reset: Usb resetting flag
*
@@ -4374,8 +4374,8 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value)
{
struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
struct dwc2_hsotg *hs = hs_ep->parent;
- unsigned long flags = 0;
- int ret = 0;
+ unsigned long flags;
+ int ret;
spin_lock_irqsave(&hs->lock, flags);
ret = dwc2_hsotg_ep_sethalt(ep, value, false);
@@ -4505,7 +4505,7 @@ err:
static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget)
{
struct dwc2_hsotg *hsotg = to_hsotg(gadget);
- unsigned long flags = 0;
+ unsigned long flags;
int ep;
if (!hsotg)
@@ -4577,7 +4577,7 @@ static int dwc2_hsotg_set_selfpowered(struct usb_gadget *gadget,
static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on)
{
struct dwc2_hsotg *hsotg = to_hsotg(gadget);
- unsigned long flags = 0;
+ unsigned long flags;
dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on,
hsotg->op_state);
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
index 621a4846bd05..89a788326c56 100644
--- a/drivers/usb/dwc2/hcd_queue.c
+++ b/drivers/usb/dwc2/hcd_queue.c
@@ -675,7 +675,7 @@ static int dwc2_hs_pmap_schedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
}
/**
- * dwc2_ls_pmap_unschedule() - Undo work done by dwc2_hs_pmap_schedule()
+ * dwc2_hs_pmap_unschedule() - Undo work done by dwc2_hs_pmap_schedule()
*
* @hsotg: The HCD state structure for the DWC OTG controller.
* @qh: QH for the periodic transfer.
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index 7a6089fa81e1..67c5eb140232 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -784,8 +784,8 @@ static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg)
}
/**
- * During device initialization, read various hardware configuration
- * registers and interpret the contents.
+ * dwc2_get_hwparams() - During device initialization, read various hardware
+ * configuration registers and interpret the contents.
*
* @hsotg: Programming view of the DWC_otg controller
*
diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c
index 0000151e3ca9..a93559b4ecdb 100644
--- a/drivers/usb/dwc2/pci.c
+++ b/drivers/usb/dwc2/pci.c
@@ -64,7 +64,7 @@ struct dwc2_pci_glue {
};
/**
- * dwc2_pci_probe() - Provides the cleanup entry points for the DWC_otg PCI
+ * dwc2_pci_remove() - Provides the cleanup entry points for the DWC_otg PCI
* driver
*
* @pci: The programming view of DWC_otg PCI
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 520a0beef77c..c8f18f3ba9e3 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -408,7 +408,7 @@ static bool dwc2_check_core_endianness(struct dwc2_hsotg *hsotg)
}
/**
- * Check core version
+ * dwc2_check_core_version() - Check core version
*
* @hsotg: Programming view of the DWC_otg controller
*
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 4ac397e43e19..ba74ad7f6995 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1545,6 +1545,10 @@ static int dwc3_probe(struct platform_device *pdev)
dwc3_get_properties(dwc);
+ ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64));
+ if (ret)
+ return ret;
+
dwc->reset = devm_reset_control_array_get_optional_shared(dev);
if (IS_ERR(dwc->reset))
return PTR_ERR(dwc->reset);
@@ -1616,17 +1620,18 @@ static int dwc3_probe(struct platform_device *pdev)
}
dwc3_check_params(dwc);
+ dwc3_debugfs_init(dwc);
ret = dwc3_core_init_mode(dwc);
if (ret)
goto err5;
- dwc3_debugfs_init(dwc);
pm_runtime_put(dev);
return 0;
err5:
+ dwc3_debugfs_exit(dwc);
dwc3_event_buffers_cleanup(dwc);
usb_phy_shutdown(dwc->usb2_phy);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index c5d5760cdf53..dccdf13b5f9e 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1013,7 +1013,6 @@ struct dwc3_scratchpad_array {
* @link_state: link state
* @speed: device speed (super, high, full, low)
* @hwparams: copy of hwparams registers
- * @root: debugfs root folder pointer
* @regset: debugfs pointer to regdump file
* @dbg_lsp_select: current debug lsp mux register selection
* @test_mode: true when we're entering a USB test mode
@@ -1222,7 +1221,6 @@ struct dwc3 {
u8 num_eps;
struct dwc3_hwparams hwparams;
- struct dentry *root;
struct debugfs_regset32 *regset;
u32 dbg_lsp_select;
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index 5dbbe53269d3..f2b7675c7f62 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -889,8 +889,10 @@ static void dwc3_debugfs_create_endpoint_files(struct dwc3_ep *dep,
void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep)
{
struct dentry *dir;
+ struct dentry *root;
- dir = debugfs_create_dir(dep->name, dep->dwc->root);
+ root = debugfs_lookup(dev_name(dep->dwc->dev), usb_debug_root);
+ dir = debugfs_create_dir(dep->name, root);
dwc3_debugfs_create_endpoint_files(dep, dir);
}
@@ -909,8 +911,6 @@ void dwc3_debugfs_init(struct dwc3 *dwc)
dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START;
root = debugfs_create_dir(dev_name(dwc->dev), usb_debug_root);
- dwc->root = root;
-
debugfs_create_regset32("regdump", 0444, root, dwc->regset);
debugfs_create_file("lsp_dump", 0644, root, dwc, &dwc3_lsp_fops);
@@ -929,6 +929,6 @@ void dwc3_debugfs_init(struct dwc3 *dwc)
void dwc3_debugfs_exit(struct dwc3 *dwc)
{
- debugfs_remove_recursive(dwc->root);
+ debugfs_remove(debugfs_lookup(dev_name(dwc->dev), usb_debug_root));
kfree(dwc->regset);
}
diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
index e2b68bb770d1..8fcbac10510c 100644
--- a/drivers/usb/dwc3/drd.c
+++ b/drivers/usb/dwc3/drd.c
@@ -596,7 +596,6 @@ int dwc3_drd_init(struct dwc3 *dwc)
dwc3_drd_update(dwc);
} else {
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
- dwc->current_dr_role = DWC3_GCTL_PRTCAP_OTG;
/* use OTG block to get ID event */
irq = dwc3_otg_get_irq(dwc);
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 1e51460938b8..2b37bdd39a74 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -36,7 +36,7 @@
#define PCI_DEVICE_ID_INTEL_CNPH 0xa36e
#define PCI_DEVICE_ID_INTEL_CNPV 0xa3b0
#define PCI_DEVICE_ID_INTEL_ICLLP 0x34ee
-#define PCI_DEVICE_ID_INTEL_EHLLP 0x4b7e
+#define PCI_DEVICE_ID_INTEL_EHL 0x4b7e
#define PCI_DEVICE_ID_INTEL_TGPLP 0xa0ee
#define PCI_DEVICE_ID_INTEL_TGPH 0x43ee
#define PCI_DEVICE_ID_INTEL_JSP 0x4dee
@@ -167,7 +167,7 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
if (pdev->device == PCI_DEVICE_ID_INTEL_BXT ||
pdev->device == PCI_DEVICE_ID_INTEL_BXT_M ||
- pdev->device == PCI_DEVICE_ID_INTEL_EHLLP) {
+ pdev->device == PCI_DEVICE_ID_INTEL_EHL) {
guid_parse(PCI_INTEL_BXT_DSM_GUID, &dwc->guid);
dwc->has_dsm_for_pm = true;
}
@@ -375,8 +375,8 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP),
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHLLP),
- (kernel_ulong_t) &dwc3_pci_intel_swnode },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHL),
+ (kernel_ulong_t) &dwc3_pci_intel_swnode, },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP),
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index f14c2aa83759..af6d7f157989 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2798,7 +2798,9 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
list_del(&dep->endpoint.ep_list);
}
- debugfs_remove_recursive(debugfs_lookup(dep->name, dwc->root));
+ debugfs_remove_recursive(debugfs_lookup(dep->name,
+ debugfs_lookup(dev_name(dep->dwc->dev),
+ usb_debug_root)));
kfree(dep);
}
}
diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h
index 51d18e8d1602..cb998ba50fea 100644
--- a/drivers/usb/dwc3/trace.h
+++ b/drivers/usb/dwc3/trace.h
@@ -222,8 +222,6 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
TP_STRUCT__entry(
__string(name, dep->name)
__field(struct dwc3_trb *, trb)
- __field(u32, allocated)
- __field(u32, queued)
__field(u32, bpl)
__field(u32, bph)
__field(u32, size)
diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c
index 2cd9942707b4..5d38f29bda72 100644
--- a/drivers/usb/gadget/function/f_eem.c
+++ b/drivers/usb/gadget/function/f_eem.c
@@ -30,6 +30,11 @@ struct f_eem {
u8 ctrl_id;
};
+struct in_context {
+ struct sk_buff *skb;
+ struct usb_ep *ep;
+};
+
static inline struct f_eem *func_to_eem(struct usb_function *f)
{
return container_of(f, struct f_eem, port.func);
@@ -320,9 +325,12 @@ fail:
static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct sk_buff *skb = (struct sk_buff *)req->context;
+ struct in_context *ctx = req->context;
- dev_kfree_skb_any(skb);
+ dev_kfree_skb_any(ctx->skb);
+ kfree(req->buf);
+ usb_ep_free_request(ctx->ep, req);
+ kfree(ctx);
}
/*
@@ -410,7 +418,9 @@ static int eem_unwrap(struct gether *port,
* b15: bmType (0 == data, 1 == command)
*/
if (header & BIT(15)) {
- struct usb_request *req = cdev->req;
+ struct usb_request *req;
+ struct in_context *ctx;
+ struct usb_ep *ep;
u16 bmEEMCmd;
/* EEM command packet format:
@@ -439,11 +449,36 @@ static int eem_unwrap(struct gether *port,
skb_trim(skb2, len);
put_unaligned_le16(BIT(15) | BIT(11) | len,
skb_push(skb2, 2));
+
+ ep = port->in_ep;
+ req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+ if (!req) {
+ dev_kfree_skb_any(skb2);
+ goto next;
+ }
+
+ req->buf = kmalloc(skb2->len, GFP_KERNEL);
+ if (!req->buf) {
+ usb_ep_free_request(ep, req);
+ dev_kfree_skb_any(skb2);
+ goto next;
+ }
+
+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+ dev_kfree_skb_any(skb2);
+ goto next;
+ }
+ ctx->skb = skb2;
+ ctx->ep = ep;
+
skb_copy_bits(skb2, 0, req->buf, skb2->len);
req->length = skb2->len;
req->complete = eem_cmd_complete;
req->zero = 1;
- req->context = skb2;
+ req->context = ctx;
if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC))
DBG(cdev, "echo response queue fail\n");
break;
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index d4844afeaffc..9c0c393abb39 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -250,8 +250,8 @@ EXPORT_SYMBOL_GPL(ffs_lock);
static struct ffs_dev *_ffs_find_dev(const char *name);
static struct ffs_dev *_ffs_alloc_dev(void);
static void _ffs_free_dev(struct ffs_dev *dev);
-static void *ffs_acquire_dev(const char *dev_name);
-static void ffs_release_dev(struct ffs_data *ffs_data);
+static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data);
+static void ffs_release_dev(struct ffs_dev *ffs_dev);
static int ffs_ready(struct ffs_data *ffs);
static void ffs_closed(struct ffs_data *ffs);
@@ -1554,8 +1554,8 @@ unmapped_value:
static int ffs_fs_get_tree(struct fs_context *fc)
{
struct ffs_sb_fill_data *ctx = fc->fs_private;
- void *ffs_dev;
struct ffs_data *ffs;
+ int ret;
ENTER();
@@ -1574,13 +1574,12 @@ static int ffs_fs_get_tree(struct fs_context *fc)
return -ENOMEM;
}
- ffs_dev = ffs_acquire_dev(ffs->dev_name);
- if (IS_ERR(ffs_dev)) {
+ ret = ffs_acquire_dev(ffs->dev_name, ffs);
+ if (ret) {
ffs_data_put(ffs);
- return PTR_ERR(ffs_dev);
+ return ret;
}
- ffs->private_data = ffs_dev;
ctx->ffs_data = ffs;
return get_tree_nodev(fc, ffs_sb_fill);
}
@@ -1591,7 +1590,6 @@ static void ffs_fs_free_fc(struct fs_context *fc)
if (ctx) {
if (ctx->ffs_data) {
- ffs_release_dev(ctx->ffs_data);
ffs_data_put(ctx->ffs_data);
}
@@ -1630,10 +1628,8 @@ ffs_fs_kill_sb(struct super_block *sb)
ENTER();
kill_litter_super(sb);
- if (sb->s_fs_info) {
- ffs_release_dev(sb->s_fs_info);
+ if (sb->s_fs_info)
ffs_data_closed(sb->s_fs_info);
- }
}
static struct file_system_type ffs_fs_type = {
@@ -1703,6 +1699,7 @@ static void ffs_data_put(struct ffs_data *ffs)
if (refcount_dec_and_test(&ffs->ref)) {
pr_info("%s(): freeing\n", __func__);
ffs_data_clear(ffs);
+ ffs_release_dev(ffs->private_data);
BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
swait_active(&ffs->ep0req_completion.wait) ||
waitqueue_active(&ffs->wait));
@@ -3032,6 +3029,7 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
struct ffs_function *func = ffs_func_from_usb(f);
struct f_fs_opts *ffs_opts =
container_of(f->fi, struct f_fs_opts, func_inst);
+ struct ffs_data *ffs_data;
int ret;
ENTER();
@@ -3046,12 +3044,13 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
if (!ffs_opts->no_configfs)
ffs_dev_lock();
ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV;
- func->ffs = ffs_opts->dev->ffs_data;
+ ffs_data = ffs_opts->dev->ffs_data;
if (!ffs_opts->no_configfs)
ffs_dev_unlock();
if (ret)
return ERR_PTR(ret);
+ func->ffs = ffs_data;
func->conf = c;
func->gadget = c->cdev->gadget;
@@ -3506,6 +3505,7 @@ static void ffs_free_inst(struct usb_function_instance *f)
struct f_fs_opts *opts;
opts = to_f_fs_opts(f);
+ ffs_release_dev(opts->dev);
ffs_dev_lock();
_ffs_free_dev(opts->dev);
ffs_dev_unlock();
@@ -3693,47 +3693,48 @@ static void _ffs_free_dev(struct ffs_dev *dev)
{
list_del(&dev->entry);
- /* Clear the private_data pointer to stop incorrect dev access */
- if (dev->ffs_data)
- dev->ffs_data->private_data = NULL;
-
kfree(dev);
if (list_empty(&ffs_devices))
functionfs_cleanup();
}
-static void *ffs_acquire_dev(const char *dev_name)
+static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data)
{
+ int ret = 0;
struct ffs_dev *ffs_dev;
ENTER();
ffs_dev_lock();
ffs_dev = _ffs_find_dev(dev_name);
- if (!ffs_dev)
- ffs_dev = ERR_PTR(-ENOENT);
- else if (ffs_dev->mounted)
- ffs_dev = ERR_PTR(-EBUSY);
- else if (ffs_dev->ffs_acquire_dev_callback &&
- ffs_dev->ffs_acquire_dev_callback(ffs_dev))
- ffs_dev = ERR_PTR(-ENOENT);
- else
+ if (!ffs_dev) {
+ ret = -ENOENT;
+ } else if (ffs_dev->mounted) {
+ ret = -EBUSY;
+ } else if (ffs_dev->ffs_acquire_dev_callback &&
+ ffs_dev->ffs_acquire_dev_callback(ffs_dev)) {
+ ret = -ENOENT;
+ } else {
ffs_dev->mounted = true;
+ ffs_dev->ffs_data = ffs_data;
+ ffs_data->private_data = ffs_dev;
+ }
ffs_dev_unlock();
- return ffs_dev;
+ return ret;
}
-static void ffs_release_dev(struct ffs_data *ffs_data)
+static void ffs_release_dev(struct ffs_dev *ffs_dev)
{
- struct ffs_dev *ffs_dev;
-
ENTER();
ffs_dev_lock();
- ffs_dev = ffs_data->private_data;
- if (ffs_dev) {
+ if (ffs_dev && ffs_dev->mounted) {
ffs_dev->mounted = false;
+ if (ffs_dev->ffs_data) {
+ ffs_dev->ffs_data->private_data = NULL;
+ ffs_dev->ffs_data = NULL;
+ }
if (ffs_dev->ffs_release_dev_callback)
ffs_dev->ffs_release_dev_callback(ffs_dev);
@@ -3761,7 +3762,6 @@ static int ffs_ready(struct ffs_data *ffs)
}
ffs_obj->desc_ready = true;
- ffs_obj->ffs_data = ffs;
if (ffs_obj->ffs_ready_callback) {
ret = ffs_obj->ffs_ready_callback(ffs);
@@ -3789,7 +3789,6 @@ static void ffs_closed(struct ffs_data *ffs)
goto done;
ffs_obj->desc_ready = false;
- ffs_obj->ffs_data = NULL;
if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags) &&
ffs_obj->ffs_closed_callback)
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index e55699308117..02683ac0719d 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -88,7 +88,7 @@ static struct usb_interface_descriptor hidg_interface_desc = {
static struct hid_descriptor hidg_desc = {
.bLength = sizeof hidg_desc,
.bDescriptorType = HID_DT_HID,
- .bcdHID = 0x0101,
+ .bcdHID = cpu_to_le16(0x0101),
.bCountryCode = 0x00,
.bNumDescriptors = 0x1,
/*.desc[0].bDescriptorType = DYNAMIC */
@@ -1118,7 +1118,7 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
hidg->func.setup = hidg_setup;
hidg->func.free_func = hidg_free;
- /* this could me made configurable at some point */
+ /* this could be made configurable at some point */
hidg->qlen = 4;
return &hidg->func;
diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index 59d382fe1bbf..abec5c58f525 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -667,8 +667,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
value = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
spin_lock(&dev->lock);
if (value) {
- list_del(&req->list);
- list_add(&req->list, &dev->tx_reqs);
+ list_move(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->lock, flags);
mutex_unlock(&dev->lock_printer_io);
return -EAGAIN;
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 7aa4c8bc5a1a..ae29ff2b2b68 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -44,6 +44,7 @@
#define EPIN_EN(_opts) ((_opts)->p_chmask != 0)
#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0)
+#define EPOUT_FBACK_IN_EN(_opts) ((_opts)->c_sync == USB_ENDPOINT_SYNC_ASYNC)
struct f_uac2 {
struct g_audio g_audio;
@@ -273,7 +274,7 @@ static struct usb_endpoint_descriptor fs_epout_desc = {
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ /* .bmAttributes = DYNAMIC */
/* .wMaxPacketSize = DYNAMIC */
.bInterval = 1,
};
@@ -282,7 +283,7 @@ static struct usb_endpoint_descriptor hs_epout_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ /* .bmAttributes = DYNAMIC */
/* .wMaxPacketSize = DYNAMIC */
.bInterval = 4,
};
@@ -292,7 +293,7 @@ static struct usb_endpoint_descriptor ss_epout_desc = {
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ /* .bmAttributes = DYNAMIC */
/* .wMaxPacketSize = DYNAMIC */
.bInterval = 4,
};
@@ -317,6 +318,37 @@ static struct uac2_iso_endpoint_descriptor as_iso_out_desc = {
.wLockDelay = 0,
};
+/* STD AS ISO IN Feedback Endpoint */
+static struct usb_endpoint_descriptor fs_epin_fback_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK,
+ .wMaxPacketSize = cpu_to_le16(3),
+ .bInterval = 1,
+};
+
+static struct usb_endpoint_descriptor hs_epin_fback_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK,
+ .wMaxPacketSize = cpu_to_le16(4),
+ .bInterval = 4,
+};
+
+static struct usb_endpoint_descriptor ss_epin_fback_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK,
+ .wMaxPacketSize = cpu_to_le16(4),
+ .bInterval = 4,
+};
+
+
/* Audio Streaming IN Interface - Alt0 */
static struct usb_interface_descriptor std_as_in_if0_desc = {
.bLength = sizeof std_as_in_if0_desc,
@@ -431,6 +463,7 @@ static struct usb_descriptor_header *fs_audio_desc[] = {
(struct usb_descriptor_header *)&as_out_fmt1_desc,
(struct usb_descriptor_header *)&fs_epout_desc,
(struct usb_descriptor_header *)&as_iso_out_desc,
+ (struct usb_descriptor_header *)&fs_epin_fback_desc,
(struct usb_descriptor_header *)&std_as_in_if0_desc,
(struct usb_descriptor_header *)&std_as_in_if1_desc,
@@ -461,6 +494,7 @@ static struct usb_descriptor_header *hs_audio_desc[] = {
(struct usb_descriptor_header *)&as_out_fmt1_desc,
(struct usb_descriptor_header *)&hs_epout_desc,
(struct usb_descriptor_header *)&as_iso_out_desc,
+ (struct usb_descriptor_header *)&hs_epin_fback_desc,
(struct usb_descriptor_header *)&std_as_in_if0_desc,
(struct usb_descriptor_header *)&std_as_in_if1_desc,
@@ -492,6 +526,7 @@ static struct usb_descriptor_header *ss_audio_desc[] = {
(struct usb_descriptor_header *)&ss_epout_desc,
(struct usb_descriptor_header *)&ss_epout_desc_comp,
(struct usb_descriptor_header *)&as_iso_out_desc,
+ (struct usb_descriptor_header *)&ss_epin_fback_desc,
(struct usb_descriptor_header *)&std_as_in_if0_desc,
(struct usb_descriptor_header *)&std_as_in_if1_desc,
@@ -549,8 +584,11 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
ssize = uac2_opts->c_ssize;
}
+ if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC))
+ srate = srate * (1000 + uac2_opts->fb_max) / 1000;
+
max_size_bw = num_channels(chmask) * ssize *
- ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1);
+ DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1)));
ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw,
max_size_ep));
@@ -568,22 +606,26 @@ static void setup_headers(struct f_uac2_opts *opts,
struct usb_ss_ep_comp_descriptor *epin_desc_comp = NULL;
struct usb_endpoint_descriptor *epout_desc;
struct usb_endpoint_descriptor *epin_desc;
+ struct usb_endpoint_descriptor *epin_fback_desc;
int i;
switch (speed) {
case USB_SPEED_FULL:
epout_desc = &fs_epout_desc;
epin_desc = &fs_epin_desc;
+ epin_fback_desc = &fs_epin_fback_desc;
break;
case USB_SPEED_HIGH:
epout_desc = &hs_epout_desc;
epin_desc = &hs_epin_desc;
+ epin_fback_desc = &hs_epin_fback_desc;
break;
default:
epout_desc = &ss_epout_desc;
epin_desc = &ss_epin_desc;
epout_desc_comp = &ss_epout_desc_comp;
epin_desc_comp = &ss_epin_desc_comp;
+ epin_fback_desc = &ss_epin_fback_desc;
}
i = 0;
@@ -611,6 +653,9 @@ static void setup_headers(struct f_uac2_opts *opts,
headers[i++] = USBDHDR(epout_desc_comp);
headers[i++] = USBDHDR(&as_iso_out_desc);
+
+ if (EPOUT_FBACK_IN_EN(opts))
+ headers[i++] = USBDHDR(epin_fback_desc);
}
if (EPIN_EN(opts)) {
headers[i++] = USBDHDR(&std_as_in_if0_desc);
@@ -781,6 +826,23 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
std_as_out_if1_desc.bInterfaceNumber = ret;
uac2->as_out_intf = ret;
uac2->as_out_alt = 0;
+
+ if (EPOUT_FBACK_IN_EN(uac2_opts)) {
+ fs_epout_desc.bmAttributes =
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC;
+ hs_epout_desc.bmAttributes =
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC;
+ ss_epout_desc.bmAttributes =
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC;
+ std_as_out_if1_desc.bNumEndpoints++;
+ } else {
+ fs_epout_desc.bmAttributes =
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE;
+ hs_epout_desc.bmAttributes =
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE;
+ ss_epout_desc.bmAttributes =
+ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE;
+ }
}
if (EPIN_EN(uac2_opts)) {
@@ -844,6 +906,15 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return -ENODEV;
}
+ if (EPOUT_FBACK_IN_EN(uac2_opts)) {
+ agdev->in_ep_fback = usb_ep_autoconfig(gadget,
+ &fs_epin_fback_desc);
+ if (!agdev->in_ep_fback) {
+ dev_err(dev, "%s:%d Error!\n",
+ __func__, __LINE__);
+ return -ENODEV;
+ }
+ }
}
if (EPIN_EN(uac2_opts)) {
@@ -867,8 +938,10 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
le16_to_cpu(ss_epout_desc.wMaxPacketSize));
hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
+ hs_epin_fback_desc.bEndpointAddress = fs_epin_fback_desc.bEndpointAddress;
hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
ss_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
+ ss_epin_fback_desc.bEndpointAddress = fs_epin_fback_desc.bEndpointAddress;
ss_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
setup_descriptor(uac2_opts);
@@ -887,6 +960,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
agdev->params.c_srate = uac2_opts->c_srate;
agdev->params.c_ssize = uac2_opts->c_ssize;
agdev->params.req_number = uac2_opts->req_number;
+ agdev->params.fb_max = uac2_opts->fb_max;
ret = g_audio_setup(agdev, "UAC2 PCM", "UAC2_Gadget");
if (ret)
goto err_free_descs;
@@ -1195,13 +1269,71 @@ end: \
\
CONFIGFS_ATTR(f_uac2_opts_, name)
+#define UAC2_ATTRIBUTE_SYNC(name) \
+static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \
+ char *page) \
+{ \
+ struct f_uac2_opts *opts = to_f_uac2_opts(item); \
+ int result; \
+ char *str; \
+ \
+ mutex_lock(&opts->lock); \
+ switch (opts->name) { \
+ case USB_ENDPOINT_SYNC_ASYNC: \
+ str = "async"; \
+ break; \
+ case USB_ENDPOINT_SYNC_ADAPTIVE: \
+ str = "adaptive"; \
+ break; \
+ default: \
+ str = "unknown"; \
+ break; \
+ } \
+ result = sprintf(page, "%s\n", str); \
+ mutex_unlock(&opts->lock); \
+ \
+ return result; \
+} \
+ \
+static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \
+ const char *page, size_t len) \
+{ \
+ struct f_uac2_opts *opts = to_f_uac2_opts(item); \
+ int ret = 0; \
+ \
+ mutex_lock(&opts->lock); \
+ if (opts->refcnt) { \
+ ret = -EBUSY; \
+ goto end; \
+ } \
+ \
+ if (!strncmp(page, "async", 5)) \
+ opts->name = USB_ENDPOINT_SYNC_ASYNC; \
+ else if (!strncmp(page, "adaptive", 8)) \
+ opts->name = USB_ENDPOINT_SYNC_ADAPTIVE; \
+ else { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
+ \
+ ret = len; \
+ \
+end: \
+ mutex_unlock(&opts->lock); \
+ return ret; \
+} \
+ \
+CONFIGFS_ATTR(f_uac2_opts_, name)
+
UAC2_ATTRIBUTE(p_chmask);
UAC2_ATTRIBUTE(p_srate);
UAC2_ATTRIBUTE(p_ssize);
UAC2_ATTRIBUTE(c_chmask);
UAC2_ATTRIBUTE(c_srate);
+UAC2_ATTRIBUTE_SYNC(c_sync);
UAC2_ATTRIBUTE(c_ssize);
UAC2_ATTRIBUTE(req_number);
+UAC2_ATTRIBUTE(fb_max);
static struct configfs_attribute *f_uac2_attrs[] = {
&f_uac2_opts_attr_p_chmask,
@@ -1210,7 +1342,9 @@ static struct configfs_attribute *f_uac2_attrs[] = {
&f_uac2_opts_attr_c_chmask,
&f_uac2_opts_attr_c_srate,
&f_uac2_opts_attr_c_ssize,
+ &f_uac2_opts_attr_c_sync,
&f_uac2_opts_attr_req_number,
+ &f_uac2_opts_attr_fb_max,
NULL,
};
@@ -1248,7 +1382,9 @@ static struct usb_function_instance *afunc_alloc_inst(void)
opts->c_chmask = UAC2_DEF_CCHMASK;
opts->c_srate = UAC2_DEF_CSRATE;
opts->c_ssize = UAC2_DEF_CSSIZE;
+ opts->c_sync = UAC2_DEF_CSYNC;
opts->req_number = UAC2_DEF_REQ_NUM;
+ opts->fb_max = UAC2_DEF_FB_MAX;
return &opts->func_inst;
}
diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c
index 5fbceee897a3..018dd0978995 100644
--- a/drivers/usb/gadget/function/u_audio.c
+++ b/drivers/usb/gadget/function/u_audio.c
@@ -16,6 +16,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/control.h>
#include "u_audio.h"
@@ -35,9 +36,13 @@ struct uac_rtd_params {
void *rbuf;
+ unsigned int pitch; /* Stream pitch ratio to 1000000 */
unsigned int max_psize; /* MaxPacketSize of endpoint */
struct usb_request **reqs;
+
+ struct usb_request *req_fback; /* Feedback endpoint request */
+ bool fb_ep_enabled; /* if the ep is enabled */
};
struct snd_uac_chip {
@@ -70,6 +75,48 @@ static const struct snd_pcm_hardware uac_pcm_hardware = {
.periods_min = MIN_PERIODS,
};
+static void u_audio_set_fback_frequency(enum usb_device_speed speed,
+ unsigned long long freq,
+ unsigned int pitch,
+ void *buf)
+{
+ u32 ff = 0;
+
+ /*
+ * Because the pitch base is 1000000, the final divider here
+ * will be 1000 * 1000000 = 1953125 << 9
+ *
+ * Instead of dealing with big numbers lets fold this 9 left shift
+ */
+
+ if (speed == USB_SPEED_FULL) {
+ /*
+ * Full-speed feedback endpoints report frequency
+ * in samples/frame
+ * Format is encoded in Q10.10 left-justified in the 24 bits,
+ * so that it has a Q10.14 format.
+ *
+ * ff = (freq << 14) / 1000
+ */
+ freq <<= 5;
+ } else {
+ /*
+ * High-speed feedback endpoints report frequency
+ * in samples/microframe.
+ * Format is encoded in Q12.13 fitted into four bytes so that
+ * the binary point is located between the second and the third
+ * byte fromat (that is Q16.16)
+ *
+ * ff = (freq << 16) / 8000
+ */
+ freq <<= 4;
+ }
+
+ ff = DIV_ROUND_CLOSEST_ULL((freq * pitch), 1953125);
+
+ *(__le32 *)buf = cpu_to_le32(ff);
+}
+
static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
{
unsigned int pending;
@@ -173,6 +220,35 @@ exit:
dev_err(uac->card->dev, "%d Error!\n", __LINE__);
}
+static void u_audio_iso_fback_complete(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct uac_rtd_params *prm = req->context;
+ struct snd_uac_chip *uac = prm->uac;
+ struct g_audio *audio_dev = uac->audio_dev;
+ struct uac_params *params = &audio_dev->params;
+ int status = req->status;
+
+ /* i/f shutting down */
+ if (!prm->fb_ep_enabled || req->status == -ESHUTDOWN)
+ return;
+
+ /*
+ * We can't really do much about bad xfers.
+ * Afterall, the ISOCH xfers could fail legitimately.
+ */
+ if (status)
+ pr_debug("%s: iso_complete status(%d) %d/%d\n",
+ __func__, status, req->actual, req->length);
+
+ u_audio_set_fback_frequency(audio_dev->gadget->speed,
+ params->c_srate, prm->pitch,
+ req->buf);
+
+ if (usb_ep_queue(ep, req, GFP_ATOMIC))
+ dev_err(uac->card->dev, "%d Error!\n", __LINE__);
+}
+
static int uac_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_uac_chip *uac = snd_pcm_substream_chip(substream);
@@ -335,14 +411,33 @@ static inline void free_ep(struct uac_rtd_params *prm, struct usb_ep *ep)
dev_err(uac->card->dev, "%s:%d Error!\n", __func__, __LINE__);
}
+static inline void free_ep_fback(struct uac_rtd_params *prm, struct usb_ep *ep)
+{
+ struct snd_uac_chip *uac = prm->uac;
+
+ if (!prm->fb_ep_enabled)
+ return;
+
+ prm->fb_ep_enabled = false;
+
+ if (prm->req_fback) {
+ usb_ep_dequeue(ep, prm->req_fback);
+ kfree(prm->req_fback->buf);
+ usb_ep_free_request(ep, prm->req_fback);
+ prm->req_fback = NULL;
+ }
+
+ if (usb_ep_disable(ep))
+ dev_err(uac->card->dev, "%s:%d Error!\n", __func__, __LINE__);
+}
int u_audio_start_capture(struct g_audio *audio_dev)
{
struct snd_uac_chip *uac = audio_dev->uac;
struct usb_gadget *gadget = audio_dev->gadget;
struct device *dev = &gadget->dev;
- struct usb_request *req;
- struct usb_ep *ep;
+ struct usb_request *req, *req_fback;
+ struct usb_ep *ep, *ep_fback;
struct uac_rtd_params *prm;
struct uac_params *params = &audio_dev->params;
int req_len, i;
@@ -374,6 +469,43 @@ int u_audio_start_capture(struct g_audio *audio_dev)
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
}
+ ep_fback = audio_dev->in_ep_fback;
+ if (!ep_fback)
+ return 0;
+
+ /* Setup feedback endpoint */
+ config_ep_by_speed(gadget, &audio_dev->func, ep_fback);
+ prm->fb_ep_enabled = true;
+ usb_ep_enable(ep_fback);
+ req_len = ep_fback->maxpacket;
+
+ req_fback = usb_ep_alloc_request(ep_fback, GFP_ATOMIC);
+ if (req_fback == NULL)
+ return -ENOMEM;
+
+ prm->req_fback = req_fback;
+ req_fback->zero = 0;
+ req_fback->context = prm;
+ req_fback->length = req_len;
+ req_fback->complete = u_audio_iso_fback_complete;
+
+ req_fback->buf = kzalloc(req_len, GFP_ATOMIC);
+ if (!req_fback->buf)
+ return -ENOMEM;
+
+ /*
+ * Configure the feedback endpoint's reported frequency.
+ * Always start with original frequency since its deviation can't
+ * be meauserd at start of playback
+ */
+ prm->pitch = 1000000;
+ u_audio_set_fback_frequency(audio_dev->gadget->speed,
+ params->c_srate, prm->pitch,
+ req_fback->buf);
+
+ if (usb_ep_queue(ep_fback, req_fback, GFP_ATOMIC))
+ dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+
return 0;
}
EXPORT_SYMBOL_GPL(u_audio_start_capture);
@@ -382,6 +514,8 @@ void u_audio_stop_capture(struct g_audio *audio_dev)
{
struct snd_uac_chip *uac = audio_dev->uac;
+ if (audio_dev->in_ep_fback)
+ free_ep_fback(&uac->c_prm, audio_dev->in_ep_fback);
free_ep(&uac->c_prm, audio_dev->out_ep);
}
EXPORT_SYMBOL_GPL(u_audio_stop_capture);
@@ -463,12 +597,82 @@ void u_audio_stop_playback(struct g_audio *audio_dev)
}
EXPORT_SYMBOL_GPL(u_audio_stop_playback);
+static int u_audio_pitch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
+ struct snd_uac_chip *uac = prm->uac;
+ struct g_audio *audio_dev = uac->audio_dev;
+ struct uac_params *params = &audio_dev->params;
+ unsigned int pitch_min, pitch_max;
+
+ pitch_min = (1000 - FBACK_SLOW_MAX) * 1000;
+ pitch_max = (1000 + params->fb_max) * 1000;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = pitch_min;
+ uinfo->value.integer.max = pitch_max;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int u_audio_pitch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = prm->pitch;
+
+ return 0;
+}
+
+static int u_audio_pitch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
+ struct snd_uac_chip *uac = prm->uac;
+ struct g_audio *audio_dev = uac->audio_dev;
+ struct uac_params *params = &audio_dev->params;
+ unsigned int val;
+ unsigned int pitch_min, pitch_max;
+ int change = 0;
+
+ pitch_min = (1000 - FBACK_SLOW_MAX) * 1000;
+ pitch_max = (1000 + params->fb_max) * 1000;
+
+ val = ucontrol->value.integer.value[0];
+
+ if (val < pitch_min)
+ val = pitch_min;
+ if (val > pitch_max)
+ val = pitch_max;
+
+ if (prm->pitch != val) {
+ prm->pitch = val;
+ change = 1;
+ }
+
+ return change;
+}
+
+static const struct snd_kcontrol_new u_audio_controls[] = {
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "Capture Pitch 1000000",
+ .info = u_audio_pitch_info,
+ .get = u_audio_pitch_get,
+ .put = u_audio_pitch_put,
+},
+};
+
int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
const char *card_name)
{
struct snd_uac_chip *uac;
struct snd_card *card;
struct snd_pcm *pcm;
+ struct snd_kcontrol *kctl;
struct uac_params *params;
int p_chmask, c_chmask;
int err;
@@ -556,6 +760,23 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac_pcm_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac_pcm_ops);
+ if (c_chmask && g_audio->in_ep_fback) {
+ strscpy(card->mixername, card_name, sizeof(card->driver));
+
+ kctl = snd_ctl_new1(&u_audio_controls[0], &uac->c_prm);
+ if (!kctl) {
+ err = -ENOMEM;
+ goto snd_fail;
+ }
+
+ kctl->id.device = pcm->device;
+ kctl->id.subdevice = 0;
+
+ err = snd_ctl_add(card, kctl);
+ if (err < 0)
+ goto snd_fail;
+ }
+
strscpy(card->driver, card_name, sizeof(card->driver));
strscpy(card->shortname, card_name, sizeof(card->shortname));
sprintf(card->longname, "%s %i", card_name, card->dev->id);
diff --git a/drivers/usb/gadget/function/u_audio.h b/drivers/usb/gadget/function/u_audio.h
index 5ea6b86f1fda..a218cdf771fe 100644
--- a/drivers/usb/gadget/function/u_audio.h
+++ b/drivers/usb/gadget/function/u_audio.h
@@ -11,6 +11,14 @@
#include <linux/usb/composite.h>
+/*
+ * Same maximum frequency deviation on the slower side as in
+ * sound/usb/endpoint.c. Value is expressed in per-mil deviation.
+ * The maximum deviation on the faster side will be provided as
+ * parameter, as it impacts the endpoint required bandwidth.
+ */
+#define FBACK_SLOW_MAX 250
+
struct uac_params {
/* playback */
int p_chmask; /* channel mask */
@@ -23,6 +31,7 @@ struct uac_params {
int c_ssize; /* sample size */
int req_number; /* number of preallocated requests */
+ int fb_max; /* upper frequency drift feedback limit per-mil */
};
struct g_audio {
@@ -30,7 +39,10 @@ struct g_audio {
struct usb_gadget *gadget;
struct usb_ep *in_ep;
+
struct usb_ep *out_ep;
+ /* feedback IN endpoint corresponding to out_ep */
+ struct usb_ep *in_ep_fback;
/* Max packet size for all in_ep possible speeds */
unsigned int in_ep_maxpsize;
diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h
index 84e6da302499..98d6af558c03 100644
--- a/drivers/usb/gadget/function/u_hid.h
+++ b/drivers/usb/gadget/function/u_hid.h
@@ -29,8 +29,8 @@ struct f_hid_opts {
* Protect the data form concurrent access by read/write
* and create symlink/remove symlink.
*/
- struct mutex lock;
- int refcnt;
+ struct mutex lock;
+ int refcnt;
};
int ghid_setup(struct usb_gadget *g, int count);
diff --git a/drivers/usb/gadget/function/u_midi.h b/drivers/usb/gadget/function/u_midi.h
index f6e14af7f566..2e400b495cb8 100644
--- a/drivers/usb/gadget/function/u_midi.h
+++ b/drivers/usb/gadget/function/u_midi.h
@@ -29,8 +29,8 @@ struct f_midi_opts {
* Protect the data form concurrent access by read/write
* and create symlink/remove symlink.
*/
- struct mutex lock;
- int refcnt;
+ struct mutex lock;
+ int refcnt;
};
#endif /* U_MIDI_H */
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index 1e59204ec7aa..bffef8e47dac 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -774,34 +774,34 @@ static void gs_flush_chars(struct tty_struct *tty)
spin_unlock_irqrestore(&port->port_lock, flags);
}
-static int gs_write_room(struct tty_struct *tty)
+static unsigned int gs_write_room(struct tty_struct *tty)
{
struct gs_port *port = tty->driver_data;
unsigned long flags;
- int room = 0;
+ unsigned int room = 0;
spin_lock_irqsave(&port->port_lock, flags);
if (port->port_usb)
room = kfifo_avail(&port->port_write_buf);
spin_unlock_irqrestore(&port->port_lock, flags);
- pr_vdebug("gs_write_room: (%d,%p) room=%d\n",
+ pr_vdebug("gs_write_room: (%d,%p) room=%u\n",
port->port_num, tty, room);
return room;
}
-static int gs_chars_in_buffer(struct tty_struct *tty)
+static unsigned int gs_chars_in_buffer(struct tty_struct *tty)
{
struct gs_port *port = tty->driver_data;
unsigned long flags;
- int chars = 0;
+ unsigned int chars;
spin_lock_irqsave(&port->port_lock, flags);
chars = kfifo_len(&port->port_write_buf);
spin_unlock_irqrestore(&port->port_lock, flags);
- pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%d\n",
+ pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%u\n",
port->port_num, tty, chars);
return chars;
diff --git a/drivers/usb/gadget/function/u_uac2.h b/drivers/usb/gadget/function/u_uac2.h
index b5035711172d..179d3ef6a195 100644
--- a/drivers/usb/gadget/function/u_uac2.h
+++ b/drivers/usb/gadget/function/u_uac2.h
@@ -21,7 +21,9 @@
#define UAC2_DEF_CCHMASK 0x3
#define UAC2_DEF_CSRATE 64000
#define UAC2_DEF_CSSIZE 2
+#define UAC2_DEF_CSYNC USB_ENDPOINT_SYNC_ASYNC
#define UAC2_DEF_REQ_NUM 2
+#define UAC2_DEF_FB_MAX 5
struct f_uac2_opts {
struct usb_function_instance func_inst;
@@ -31,7 +33,9 @@ struct f_uac2_opts {
int c_chmask;
int c_srate;
int c_ssize;
+ int c_sync;
int req_number;
+ int fb_max;
bool bound;
struct mutex lock;
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index cd28dec837dd..77d64031aa9c 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -914,8 +914,6 @@ static int uvcg_streaming_header_allow_link(struct config_item *src,
target_fmt = container_of(to_config_group(target), struct uvcg_format,
group);
- if (!target_fmt)
- goto out;
uvcg_format_set_indices(to_config_group(target));
@@ -955,8 +953,6 @@ static void uvcg_streaming_header_drop_link(struct config_item *src,
mutex_lock(&opts->lock);
target_fmt = container_of(to_config_group(target), struct uvcg_format,
group);
- if (!target_fmt)
- goto out;
list_for_each_entry_safe(format_ptr, tmp, &src_hdr->formats, entry)
if (format_ptr->fmt == target_fmt) {
@@ -968,7 +964,6 @@ static void uvcg_streaming_header_drop_link(struct config_item *src,
--target_fmt->linked;
-out:
mutex_unlock(&opts->lock);
mutex_unlock(su_mutex);
}
diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c
index c4eda7fe7ab4..5b27d289443f 100644
--- a/drivers/usb/gadget/legacy/hid.c
+++ b/drivers/usb/gadget/legacy/hid.c
@@ -171,8 +171,10 @@ static int hid_bind(struct usb_composite_dev *cdev)
struct usb_descriptor_header *usb_desc;
usb_desc = usb_otg_descriptor_alloc(gadget);
- if (!usb_desc)
+ if (!usb_desc) {
+ status = -ENOMEM;
goto put;
+ }
usb_otg_descriptor_init(gadget, usb_desc);
otg_desc[0] = usb_desc;
otg_desc[1] = NULL;
diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c
index 9cd4a70ccdd6..a9f07c59fc37 100644
--- a/drivers/usb/gadget/udc/bcm63xx_udc.c
+++ b/drivers/usb/gadget/udc/bcm63xx_udc.c
@@ -288,7 +288,6 @@ struct bcm63xx_req {
* @ep0_req_completed: ep0 request has completed; worker has not seen it yet.
* @ep0_reply: Pending reply from gadget driver.
* @ep0_request: Outstanding ep0 request.
- * @debugfs_root: debugfs directory: /sys/kernel/debug/<DRV_MODULE_NAME>.
*/
struct bcm63xx_udc {
spinlock_t lock;
@@ -327,8 +326,6 @@ struct bcm63xx_udc {
unsigned ep0_req_completed:1;
struct usb_request *ep0_reply;
struct usb_request *ep0_request;
-
- struct dentry *debugfs_root;
};
static const struct usb_ep_ops bcm63xx_udc_ep_ops;
@@ -2250,8 +2247,6 @@ static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc)
return;
root = debugfs_create_dir(udc->gadget.name, usb_debug_root);
- udc->debugfs_root = root;
-
debugfs_create_file("usbd", 0400, root, udc, &bcm63xx_usbd_dbg_fops);
debugfs_create_file("iudma", 0400, root, udc, &bcm63xx_iudma_dbg_fops);
}
@@ -2264,7 +2259,7 @@ static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc)
*/
static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc)
{
- debugfs_remove_recursive(udc->debugfs_root);
+ debugfs_remove(debugfs_lookup(udc->gadget.name, usb_debug_root));
}
/***********************************************************************
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 493ff93f7dda..b7f0b1ebaaa8 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -1148,6 +1148,53 @@ static inline void usb_gadget_udc_set_speed(struct usb_udc *udc,
}
/**
+ * usb_gadget_enable_async_callbacks - tell usb device controller to enable asynchronous callbacks
+ * @udc: The UDC which should enable async callbacks
+ *
+ * This routine is used when binding gadget drivers. It undoes the effect
+ * of usb_gadget_disable_async_callbacks(); the UDC driver should enable IRQs
+ * (if necessary) and resume issuing callbacks.
+ *
+ * This routine will always be called in process context.
+ */
+static inline void usb_gadget_enable_async_callbacks(struct usb_udc *udc)
+{
+ struct usb_gadget *gadget = udc->gadget;
+
+ if (gadget->ops->udc_async_callbacks)
+ gadget->ops->udc_async_callbacks(gadget, true);
+}
+
+/**
+ * usb_gadget_disable_async_callbacks - tell usb device controller to disable asynchronous callbacks
+ * @udc: The UDC which should disable async callbacks
+ *
+ * This routine is used when unbinding gadget drivers. It prevents a race:
+ * The UDC driver doesn't know when the gadget driver's ->unbind callback
+ * runs, so unless it is told to disable asynchronous callbacks, it might
+ * issue a callback (such as ->disconnect) after the unbind has completed.
+ *
+ * After this function runs, the UDC driver must suppress all ->suspend,
+ * ->resume, ->disconnect, ->reset, and ->setup callbacks to the gadget driver
+ * until async callbacks are again enabled. A simple-minded but effective
+ * way to accomplish this is to tell the UDC hardware not to generate any
+ * more IRQs.
+ *
+ * Request completion callbacks must still be issued. However, it's okay
+ * to defer them until the request is cancelled, since the pull-up will be
+ * turned off during the time period when async callbacks are disabled.
+ *
+ * This routine will always be called in process context.
+ */
+static inline void usb_gadget_disable_async_callbacks(struct usb_udc *udc)
+{
+ struct usb_gadget *gadget = udc->gadget;
+
+ if (gadget->ops->udc_async_callbacks)
+ gadget->ops->udc_async_callbacks(gadget, false);
+}
+
+/**
* usb_udc_release - release the usb_udc struct
* @dev: the dev member within usb_udc
*
@@ -1361,6 +1408,7 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
usb_gadget_disconnect(udc->gadget);
+ usb_gadget_disable_async_callbacks(udc);
if (udc->gadget->irq)
synchronize_irq(udc->gadget->irq);
udc->driver->unbind(udc->gadget);
@@ -1442,6 +1490,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
driver->unbind(udc->gadget);
goto err1;
}
+ usb_gadget_enable_async_callbacks(udc);
usb_udc_connect_control(udc);
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 7db773c87379..a2d956af42a2 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -934,6 +934,15 @@ static void dummy_udc_set_speed(struct usb_gadget *_gadget,
dummy_udc_update_ep0(dum);
}
+static void dummy_udc_async_callbacks(struct usb_gadget *_gadget, bool enable)
+{
+ struct dummy *dum = gadget_dev_to_dummy(&_gadget->dev);
+
+ spin_lock_irq(&dum->lock);
+ dum->ints_enabled = enable;
+ spin_unlock_irq(&dum->lock);
+}
+
static int dummy_udc_start(struct usb_gadget *g,
struct usb_gadget_driver *driver);
static int dummy_udc_stop(struct usb_gadget *g);
@@ -946,6 +955,7 @@ static const struct usb_gadget_ops dummy_ops = {
.udc_start = dummy_udc_start,
.udc_stop = dummy_udc_stop,
.udc_set_speed = dummy_udc_set_speed,
+ .udc_async_callbacks = dummy_udc_async_callbacks,
};
/*-------------------------------------------------------------------------*/
@@ -1005,7 +1015,6 @@ static int dummy_udc_start(struct usb_gadget *g,
spin_lock_irq(&dum->lock);
dum->devstatus = 0;
dum->driver = driver;
- dum->ints_enabled = 1;
spin_unlock_irq(&dum->lock);
return 0;
diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c
index fa66449b3907..15db7a3868fe 100644
--- a/drivers/usb/gadget/udc/fsl_qe_udc.c
+++ b/drivers/usb/gadget/udc/fsl_qe_udc.c
@@ -541,6 +541,7 @@ static int qe_ep_init(struct qe_udc *udc,
case USB_SPEED_HIGH:
if ((max == 128) || (max == 256) || (max == 512))
break;
+ fallthrough;
default:
switch (max) {
case 4:
@@ -562,9 +563,11 @@ static int qe_ep_init(struct qe_udc *udc,
case USB_SPEED_HIGH:
if (max <= 1024)
break;
+ fallthrough;
case USB_SPEED_FULL:
if (max <= 64)
break;
+ fallthrough;
default:
if (max <= 8)
break;
@@ -579,9 +582,11 @@ static int qe_ep_init(struct qe_udc *udc,
case USB_SPEED_HIGH:
if (max <= 1024)
break;
+ fallthrough;
case USB_SPEED_FULL:
if (max <= 1023)
break;
+ fallthrough;
default:
goto en_done;
}
@@ -605,6 +610,7 @@ static int qe_ep_init(struct qe_udc *udc,
default:
goto en_done;
}
+ fallthrough;
case USB_SPEED_LOW:
switch (max) {
case 1:
diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
index ad6ff9c4188e..29fcb9b461d7 100644
--- a/drivers/usb/gadget/udc/fsl_udc_core.c
+++ b/drivers/usb/gadget/udc/fsl_udc_core.c
@@ -36,7 +36,6 @@
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include <linux/dmapool.h>
-#include <linux/delay.h>
#include <linux/of_device.h>
#include <asm/byteorder.h>
@@ -323,13 +322,11 @@ static int dr_controller_setup(struct fsl_udc *udc)
fsl_writel(tmp, &dr_regs->endptctrl[ep_num]);
}
/* Config control enable i/o output, cpu endian register */
-#ifndef CONFIG_ARCH_MXC
if (udc->pdata->have_sysif_regs) {
ctrl = __raw_readl(&usb_sys_regs->control);
ctrl |= USB_CTRL_IOENB;
__raw_writel(ctrl, &usb_sys_regs->control);
}
-#endif
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
/* Turn on cache snooping hardware, since some PowerPC platforms
@@ -547,7 +544,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
unsigned short max = 0;
unsigned char mult = 0, zlt;
int retval = -EINVAL;
- unsigned long flags = 0;
+ unsigned long flags;
ep = container_of(_ep, struct fsl_ep, ep);
@@ -631,7 +628,7 @@ static int fsl_ep_disable(struct usb_ep *_ep)
{
struct fsl_udc *udc = NULL;
struct fsl_ep *ep = NULL;
- unsigned long flags = 0;
+ unsigned long flags;
u32 epctrl;
int ep_num;
@@ -1001,7 +998,7 @@ out: epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
static int fsl_ep_set_halt(struct usb_ep *_ep, int value)
{
struct fsl_ep *ep = NULL;
- unsigned long flags = 0;
+ unsigned long flags;
int status = -EOPNOTSUPP; /* operation not supported */
unsigned char ep_dir = 0, ep_num = 0;
struct fsl_udc *udc = NULL;
@@ -1938,7 +1935,7 @@ static int fsl_udc_start(struct usb_gadget *g,
struct usb_gadget_driver *driver)
{
int retval = 0;
- unsigned long flags = 0;
+ unsigned long flags;
/* lock is needed but whether should use this lock or another */
spin_lock_irqsave(&udc_controller->lock, flags);
@@ -2153,7 +2150,6 @@ static int fsl_proc_read(struct seq_file *m, void *v)
tmp_reg = fsl_readl(&dr_regs->endpointprime);
seq_printf(m, "EP Prime Reg = [0x%x]\n\n", tmp_reg);
-#ifndef CONFIG_ARCH_MXC
if (udc->pdata->have_sysif_regs) {
tmp_reg = usb_sys_regs->snoop1;
seq_printf(m, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg);
@@ -2161,7 +2157,6 @@ static int fsl_proc_read(struct seq_file *m, void *v)
tmp_reg = usb_sys_regs->control;
seq_printf(m, "General Control Reg : = [0x%x]\n\n", tmp_reg);
}
-#endif
/* ------fsl_udc, fsl_ep, fsl_request structure information ----- */
ep = &udc->eps[0];
@@ -2412,28 +2407,21 @@ static int fsl_udc_probe(struct platform_device *pdev)
*/
if (pdata->init && pdata->init(pdev)) {
ret = -ENODEV;
- goto err_iounmap_noclk;
+ goto err_iounmap;
}
/* Set accessors only after pdata->init() ! */
fsl_set_accessors(pdata);
-#ifndef CONFIG_ARCH_MXC
if (pdata->have_sysif_regs)
usb_sys_regs = (void *)dr_regs + USB_DR_SYS_OFFSET;
-#endif
-
- /* Initialize USB clocks */
- ret = fsl_udc_clk_init(pdev);
- if (ret < 0)
- goto err_iounmap_noclk;
/* Read Device Controller Capability Parameters register */
dccparams = fsl_readl(&dr_regs->dccparams);
if (!(dccparams & DCCPARAMS_DC)) {
ERR("This SOC doesn't support device role\n");
ret = -ENODEV;
- goto err_iounmap;
+ goto err_exit;
}
/* Get max device endpoints */
/* DEN is bidirectional ep number, max_ep doubles the number */
@@ -2442,7 +2430,7 @@ static int fsl_udc_probe(struct platform_device *pdev)
ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
ret = ret ? : -ENODEV;
- goto err_iounmap;
+ goto err_exit;
}
udc_controller->irq = ret;
@@ -2451,7 +2439,7 @@ static int fsl_udc_probe(struct platform_device *pdev)
if (ret != 0) {
ERR("cannot request irq %d err %d\n",
udc_controller->irq, ret);
- goto err_iounmap;
+ goto err_exit;
}
/* Initialize the udc structure including QH member and other member */
@@ -2467,10 +2455,6 @@ static int fsl_udc_probe(struct platform_device *pdev)
dr_controller_setup(udc_controller);
}
- ret = fsl_udc_clk_finalize(pdev);
- if (ret)
- goto err_free_irq;
-
/* Setup gadget structure */
udc_controller->gadget.ops = &fsl_gadget_ops;
udc_controller->gadget.max_speed = USB_SPEED_HIGH;
@@ -2530,11 +2514,10 @@ err_del_udc:
dma_pool_destroy(udc_controller->td_pool);
err_free_irq:
free_irq(udc_controller->irq, udc_controller);
-err_iounmap:
+err_exit:
if (pdata->exit)
pdata->exit(pdev);
- fsl_udc_clk_release();
-err_iounmap_noclk:
+err_iounmap:
iounmap(dr_regs);
err_release_mem_region:
if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
@@ -2561,8 +2544,6 @@ static int fsl_udc_remove(struct platform_device *pdev)
udc_controller->done = &done;
usb_del_gadget_udc(&udc_controller->gadget);
- fsl_udc_clk_release();
-
/* DR has been stopped in usb_gadget_unregister_driver() */
remove_proc_file();
@@ -2677,10 +2658,6 @@ static int fsl_udc_otg_resume(struct device *dev)
--------------------------------------------------------------------------*/
static const struct platform_device_id fsl_udc_devtype[] = {
{
- .name = "imx-udc-mx27",
- }, {
- .name = "imx-udc-mx51",
- }, {
.name = "fsl-usb2-udc",
}, {
/* sentinel */
@@ -2689,7 +2666,6 @@ static const struct platform_device_id fsl_udc_devtype[] = {
MODULE_DEVICE_TABLE(platform, fsl_udc_devtype);
static struct platform_driver udc_driver = {
.remove = fsl_udc_remove,
- /* Just for FSL i.mx SoC currently */
.id_table = fsl_udc_devtype,
/* these suspend and resume are not usb suspend and resume */
.suspend = fsl_udc_suspend,
diff --git a/drivers/usb/gadget/udc/fsl_usb2_udc.h b/drivers/usb/gadget/udc/fsl_usb2_udc.h
index 4ba651ae9048..2efc5a930b48 100644
--- a/drivers/usb/gadget/udc/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/udc/fsl_usb2_udc.h
@@ -588,23 +588,4 @@ static inline struct ep_queue_head *get_qh_by_ep(struct fsl_ep *ep)
USB_DIR_IN) ? 1 : 0];
}
-struct platform_device;
-#ifdef CONFIG_ARCH_MXC
-int fsl_udc_clk_init(struct platform_device *pdev);
-int fsl_udc_clk_finalize(struct platform_device *pdev);
-void fsl_udc_clk_release(void);
-#else
-static inline int fsl_udc_clk_init(struct platform_device *pdev)
-{
- return 0;
-}
-static inline int fsl_udc_clk_finalize(struct platform_device *pdev)
-{
- return 0;
-}
-static inline void fsl_udc_clk_release(void)
-{
-}
-#endif
-
#endif
diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c
index f8f3aa52383b..4b35739d3695 100644
--- a/drivers/usb/gadget/udc/gr_udc.c
+++ b/drivers/usb/gadget/udc/gr_udc.c
@@ -207,14 +207,15 @@ DEFINE_SHOW_ATTRIBUTE(gr_dfs);
static void gr_dfs_create(struct gr_udc *dev)
{
const char *name = "gr_udc_state";
+ struct dentry *root;
- dev->dfs_root = debugfs_create_dir(dev_name(dev->dev), usb_debug_root);
- debugfs_create_file(name, 0444, dev->dfs_root, dev, &gr_dfs_fops);
+ root = debugfs_create_dir(dev_name(dev->dev), usb_debug_root);
+ debugfs_create_file(name, 0444, root, dev, &gr_dfs_fops);
}
static void gr_dfs_delete(struct gr_udc *dev)
{
- debugfs_remove_recursive(dev->dfs_root);
+ debugfs_remove(debugfs_lookup(dev_name(dev->dev), usb_debug_root));
}
#else /* !CONFIG_USB_GADGET_DEBUG_FS */
diff --git a/drivers/usb/gadget/udc/gr_udc.h b/drivers/usb/gadget/udc/gr_udc.h
index ac5b3f65adb5..70134239179e 100644
--- a/drivers/usb/gadget/udc/gr_udc.h
+++ b/drivers/usb/gadget/udc/gr_udc.h
@@ -215,8 +215,6 @@ struct gr_udc {
struct list_head ep_list;
spinlock_t lock; /* General lock, a.k.a. "dev->lock" in comments */
-
- struct dentry *dfs_root;
};
#define to_gr_udc(gadget) (container_of((gadget), struct gr_udc, gadget))
diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c
index 3f1c62adce4b..a25d01c89564 100644
--- a/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ b/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -127,7 +127,6 @@ struct lpc32xx_udc {
struct usb_gadget_driver *driver;
struct platform_device *pdev;
struct device *dev;
- struct dentry *pde;
spinlock_t lock;
struct i2c_client *isp1301_i2c_client;
@@ -528,12 +527,12 @@ DEFINE_SHOW_ATTRIBUTE(udc);
static void create_debug_file(struct lpc32xx_udc *udc)
{
- udc->pde = debugfs_create_file(debug_filename, 0, NULL, udc, &udc_fops);
+ debugfs_create_file(debug_filename, 0, NULL, udc, &udc_fops);
}
static void remove_debug_file(struct lpc32xx_udc *udc)
{
- debugfs_remove(udc->pde);
+ debugfs_remove(debugfs_lookup(debug_filename, NULL));
}
#else
diff --git a/drivers/usb/gadget/udc/max3420_udc.c b/drivers/usb/gadget/udc/max3420_udc.c
index 35179543c327..34f4db554977 100644
--- a/drivers/usb/gadget/udc/max3420_udc.c
+++ b/drivers/usb/gadget/udc/max3420_udc.c
@@ -509,8 +509,7 @@ static irqreturn_t max3420_vbus_handler(int irq, void *dev_id)
? USB_STATE_POWERED : USB_STATE_NOTATTACHED);
spin_unlock_irqrestore(&udc->lock, flags);
- if (udc->thread_task &&
- udc->thread_task->state != TASK_RUNNING)
+ if (udc->thread_task)
wake_up_process(udc->thread_task);
return IRQ_HANDLED;
@@ -529,8 +528,7 @@ static irqreturn_t max3420_irq_handler(int irq, void *dev_id)
}
spin_unlock_irqrestore(&udc->lock, flags);
- if (udc->thread_task &&
- udc->thread_task->state != TASK_RUNNING)
+ if (udc->thread_task)
wake_up_process(udc->thread_task);
return IRQ_HANDLED;
@@ -1093,8 +1091,7 @@ static int max3420_wakeup(struct usb_gadget *gadget)
spin_unlock_irqrestore(&udc->lock, flags);
- if (udc->thread_task &&
- udc->thread_task->state != TASK_RUNNING)
+ if (udc->thread_task)
wake_up_process(udc->thread_task);
return ret;
}
@@ -1117,8 +1114,7 @@ static int max3420_udc_start(struct usb_gadget *gadget,
udc->todo |= UDC_START;
spin_unlock_irqrestore(&udc->lock, flags);
- if (udc->thread_task &&
- udc->thread_task->state != TASK_RUNNING)
+ if (udc->thread_task)
wake_up_process(udc->thread_task);
return 0;
@@ -1137,8 +1133,7 @@ static int max3420_udc_stop(struct usb_gadget *gadget)
udc->todo |= UDC_START;
spin_unlock_irqrestore(&udc->lock, flags);
- if (udc->thread_task &&
- udc->thread_task->state != TASK_RUNNING)
+ if (udc->thread_task)
wake_up_process(udc->thread_task);
return 0;
diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c
index 5486f5a70868..ce3d7a3eb7e3 100644
--- a/drivers/usb/gadget/udc/mv_u3d_core.c
+++ b/drivers/usb/gadget/udc/mv_u3d_core.c
@@ -941,7 +941,7 @@ mv_u3d_ep_set_stall(struct mv_u3d *u3d, u8 ep_num, u8 direction, int stall)
static int mv_u3d_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge)
{
struct mv_u3d_ep *ep;
- unsigned long flags = 0;
+ unsigned long flags;
int status = 0;
struct mv_u3d *u3d;
diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c
index 0fb4ef464321..7f24ce400b59 100644
--- a/drivers/usb/gadget/udc/mv_udc_core.c
+++ b/drivers/usb/gadget/udc/mv_udc_core.c
@@ -888,7 +888,7 @@ static int ep_is_stall(struct mv_udc *udc, u8 ep_num, u8 direction)
static int mv_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge)
{
struct mv_ep *ep;
- unsigned long flags = 0;
+ unsigned long flags;
int status = 0;
struct mv_udc *udc;
diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c
index 89f479b78d80..7c38057dcb4a 100644
--- a/drivers/usb/gadget/udc/net2272.c
+++ b/drivers/usb/gadget/udc/net2272.c
@@ -1150,6 +1150,7 @@ net2272_pullup(struct usb_gadget *_gadget, int is_on)
static int net2272_start(struct usb_gadget *_gadget,
struct usb_gadget_driver *driver);
static int net2272_stop(struct usb_gadget *_gadget);
+static void net2272_async_callbacks(struct usb_gadget *_gadget, bool enable);
static const struct usb_gadget_ops net2272_ops = {
.get_frame = net2272_get_frame,
@@ -1158,6 +1159,7 @@ static const struct usb_gadget_ops net2272_ops = {
.pullup = net2272_pullup,
.udc_start = net2272_start,
.udc_stop = net2272_stop,
+ .udc_async_callbacks = net2272_async_callbacks,
};
/*---------------------------------------------------------------------------*/
@@ -1476,7 +1478,7 @@ stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver)
net2272_dequeue_all(&dev->ep[i]);
/* report disconnect; the driver is already quiesced */
- if (driver) {
+ if (dev->async_callbacks && driver) {
spin_unlock(&dev->lock);
driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
@@ -1501,6 +1503,15 @@ static int net2272_stop(struct usb_gadget *_gadget)
return 0;
}
+static void net2272_async_callbacks(struct usb_gadget *_gadget, bool enable)
+{
+ struct net2272 *dev = container_of(_gadget, struct net2272, gadget);
+
+ spin_lock_irq(&dev->lock);
+ dev->async_callbacks = enable;
+ spin_unlock_irq(&dev->lock);
+}
+
/*---------------------------------------------------------------------------*/
/* handle ep-a/ep-b dma completions */
static void
@@ -1910,9 +1921,11 @@ net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat)
u.r.bRequestType, u.r.bRequest,
u.r.wValue, u.r.wIndex,
net2272_ep_read(ep, EP_CFG));
- spin_unlock(&dev->lock);
- tmp = dev->driver->setup(&dev->gadget, &u.r);
- spin_lock(&dev->lock);
+ if (dev->async_callbacks) {
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &u.r);
+ spin_lock(&dev->lock);
+ }
}
/* stall ep0 on error */
@@ -1994,14 +2007,14 @@ net2272_handle_stat1_irqs(struct net2272 *dev, u8 stat)
if (disconnect || reset) {
stop_activity(dev, dev->driver);
net2272_ep0_start(dev);
- spin_unlock(&dev->lock);
- if (reset)
- usb_gadget_udc_reset
- (&dev->gadget, dev->driver);
- else
- (dev->driver->disconnect)
- (&dev->gadget);
- spin_lock(&dev->lock);
+ if (dev->async_callbacks) {
+ spin_unlock(&dev->lock);
+ if (reset)
+ usb_gadget_udc_reset(&dev->gadget, dev->driver);
+ else
+ (dev->driver->disconnect)(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
return;
}
}
@@ -2015,14 +2028,14 @@ net2272_handle_stat1_irqs(struct net2272 *dev, u8 stat)
if (stat & tmp) {
net2272_write(dev, IRQSTAT1, tmp);
if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) {
- if (dev->driver->suspend)
+ if (dev->async_callbacks && dev->driver->suspend)
dev->driver->suspend(&dev->gadget);
if (!enable_suspend) {
stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT);
dev_dbg(dev->dev, "Suspend disabled, ignoring\n");
}
} else {
- if (dev->driver->resume)
+ if (dev->async_callbacks && dev->driver->resume)
dev->driver->resume(&dev->gadget);
}
stat &= ~tmp;
diff --git a/drivers/usb/gadget/udc/net2272.h b/drivers/usb/gadget/udc/net2272.h
index c669308111c2..a9994f737588 100644
--- a/drivers/usb/gadget/udc/net2272.h
+++ b/drivers/usb/gadget/udc/net2272.h
@@ -442,6 +442,7 @@ struct net2272 {
softconnect:1,
wakeup:1,
added:1,
+ async_callbacks:1,
dma_eot_polarity:1,
dma_dack_polarity:1,
dma_dreq_polarity:1,
diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
index fc9f99fe7f37..16e7d2db6411 100644
--- a/drivers/usb/gadget/udc/net2280.c
+++ b/drivers/usb/gadget/udc/net2280.c
@@ -1617,6 +1617,7 @@ static struct usb_ep *net2280_match_ep(struct usb_gadget *_gadget,
static int net2280_start(struct usb_gadget *_gadget,
struct usb_gadget_driver *driver);
static int net2280_stop(struct usb_gadget *_gadget);
+static void net2280_async_callbacks(struct usb_gadget *_gadget, bool enable);
static const struct usb_gadget_ops net2280_ops = {
.get_frame = net2280_get_frame,
@@ -1625,6 +1626,7 @@ static const struct usb_gadget_ops net2280_ops = {
.pullup = net2280_pullup,
.udc_start = net2280_start,
.udc_stop = net2280_stop,
+ .udc_async_callbacks = net2280_async_callbacks,
.match_ep = net2280_match_ep,
};
@@ -2472,7 +2474,7 @@ static void stop_activity(struct net2280 *dev, struct usb_gadget_driver *driver)
nuke(&dev->ep[i]);
/* report disconnect; the driver is already quiesced */
- if (driver) {
+ if (dev->async_callbacks && driver) {
spin_unlock(&dev->lock);
driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
@@ -2502,6 +2504,15 @@ static int net2280_stop(struct usb_gadget *_gadget)
return 0;
}
+static void net2280_async_callbacks(struct usb_gadget *_gadget, bool enable)
+{
+ struct net2280 *dev = container_of(_gadget, struct net2280, gadget);
+
+ spin_lock_irq(&dev->lock);
+ dev->async_callbacks = enable;
+ spin_unlock_irq(&dev->lock);
+}
+
/*-------------------------------------------------------------------------*/
/* handle ep0, ep-e, ep-f with 64 byte packets: packet per irq.
@@ -2814,8 +2825,6 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r)
* - Wait and try again.
*/
udelay(DEFECT_7374_PROCESSOR_WAIT_TIME);
-
- continue;
}
@@ -3042,9 +3051,11 @@ usb3_delegate:
readl(&ep->cfg->ep_cfg));
ep->responded = 0;
- spin_unlock(&dev->lock);
- tmp = dev->driver->setup(&dev->gadget, &r);
- spin_lock(&dev->lock);
+ if (dev->async_callbacks) {
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &r);
+ spin_lock(&dev->lock);
+ }
}
do_stall3:
if (tmp < 0) {
@@ -3284,9 +3295,11 @@ delegate:
w_value, w_index, w_length,
readl(&ep->cfg->ep_cfg));
ep->responded = 0;
- spin_unlock(&dev->lock);
- tmp = dev->driver->setup(&dev->gadget, &u.r);
- spin_lock(&dev->lock);
+ if (dev->async_callbacks) {
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &u.r);
+ spin_lock(&dev->lock);
+ }
}
/* stall ep0 on error */
@@ -3391,14 +3404,14 @@ __acquires(dev->lock)
if (disconnect || reset) {
stop_activity(dev, dev->driver);
ep0_start(dev);
- spin_unlock(&dev->lock);
- if (reset)
- usb_gadget_udc_reset
- (&dev->gadget, dev->driver);
- else
- (dev->driver->disconnect)
- (&dev->gadget);
- spin_lock(&dev->lock);
+ if (dev->async_callbacks) {
+ spin_unlock(&dev->lock);
+ if (reset)
+ usb_gadget_udc_reset(&dev->gadget, dev->driver);
+ else
+ (dev->driver->disconnect)(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
return;
}
}
@@ -3419,12 +3432,12 @@ __acquires(dev->lock)
writel(tmp, &dev->regs->irqstat1);
spin_unlock(&dev->lock);
if (stat & BIT(SUSPEND_REQUEST_INTERRUPT)) {
- if (dev->driver->suspend)
+ if (dev->async_callbacks && dev->driver->suspend)
dev->driver->suspend(&dev->gadget);
if (!enable_suspend)
stat &= ~BIT(SUSPEND_REQUEST_INTERRUPT);
} else {
- if (dev->driver->resume)
+ if (dev->async_callbacks && dev->driver->resume)
dev->driver->resume(&dev->gadget);
/* at high speed, note erratum 0133 */
}
diff --git a/drivers/usb/gadget/udc/net2280.h b/drivers/usb/gadget/udc/net2280.h
index 7da3dc1e9729..34716a9f4926 100644
--- a/drivers/usb/gadget/udc/net2280.h
+++ b/drivers/usb/gadget/udc/net2280.h
@@ -162,6 +162,7 @@ struct net2280 {
ltm_enable:1,
wakeup_enable:1,
addressed_state:1,
+ async_callbacks:1,
bug7734_patched:1;
u16 chiprev;
int enhanced_mode;
diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c
index 10324a7334fe..69ef1e669d0c 100644
--- a/drivers/usb/gadget/udc/pxa25x_udc.c
+++ b/drivers/usb/gadget/udc/pxa25x_udc.c
@@ -1338,10 +1338,10 @@ DEFINE_SHOW_ATTRIBUTE(udc_debug);
#define create_debug_files(dev) \
do { \
- dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \
+ debugfs_create_file(dev->gadget.name, \
S_IRUGO, NULL, dev, &udc_debug_fops); \
} while (0)
-#define remove_debug_files(dev) debugfs_remove(dev->debugfs_udc)
+#define remove_debug_files(dev) debugfs_remove(debugfs_lookup(dev->gadget.name, NULL))
#else /* !CONFIG_USB_GADGET_DEBUG_FILES */
diff --git a/drivers/usb/gadget/udc/pxa25x_udc.h b/drivers/usb/gadget/udc/pxa25x_udc.h
index ccc6b921f067..aa4b68fd9fc0 100644
--- a/drivers/usb/gadget/udc/pxa25x_udc.h
+++ b/drivers/usb/gadget/udc/pxa25x_udc.h
@@ -116,10 +116,6 @@ struct pxa25x_udc {
struct usb_phy *transceiver;
u64 dma_mask;
struct pxa25x_ep ep [PXA_UDC_NUM_ENDPOINTS];
-
-#ifdef CONFIG_USB_GADGET_DEBUG_FS
- struct dentry *debugfs_udc;
-#endif
void __iomem *regs;
};
#define to_pxa25x(g) (container_of((g), struct pxa25x_udc, gadget))
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c
index ce57961dfd2d..f4b7a2a3e711 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.c
+++ b/drivers/usb/gadget/udc/pxa27x_udc.c
@@ -208,8 +208,6 @@ static void pxa_init_debugfs(struct pxa_udc *udc)
struct dentry *root;
root = debugfs_create_dir(udc->gadget.name, usb_debug_root);
- udc->debugfs_root = root;
-
debugfs_create_file("udcstate", 0400, root, udc, &state_dbg_fops);
debugfs_create_file("queues", 0400, root, udc, &queues_dbg_fops);
debugfs_create_file("epstate", 0400, root, udc, &eps_dbg_fops);
@@ -217,7 +215,7 @@ static void pxa_init_debugfs(struct pxa_udc *udc)
static void pxa_cleanup_debugfs(struct pxa_udc *udc)
{
- debugfs_remove_recursive(udc->debugfs_root);
+ debugfs_remove(debugfs_lookup(udc->gadget.name, usb_debug_root));
}
#else
@@ -1730,7 +1728,7 @@ static void udc_enable(struct pxa_udc *udc)
}
/**
- * pxa27x_start - Register gadget driver
+ * pxa27x_udc_start - Register gadget driver
* @g: gadget
* @driver: gadget driver
*
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.h b/drivers/usb/gadget/udc/pxa27x_udc.h
index 13b2977399ab..0a6bc18a1264 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.h
+++ b/drivers/usb/gadget/udc/pxa27x_udc.h
@@ -440,7 +440,6 @@ struct udc_stats {
* @last_interface: UDC interface of the last SET_INTERFACE host request
* @last_alternate: UDC altsetting of the last SET_INTERFACE host request
* @udccsr0: save of udccsr0 in case of suspend
- * @debugfs_root: root entry of debug filesystem
* @debugfs_state: debugfs entry for "udcstate"
* @debugfs_queues: debugfs entry for "queues"
* @debugfs_eps: debugfs entry for "epstate"
@@ -474,9 +473,6 @@ struct pxa_udc {
#ifdef CONFIG_PM
unsigned udccsr0;
#endif
-#ifdef CONFIG_USB_GADGET_DEBUG_FS
- struct dentry *debugfs_root;
-#endif
};
#define to_pxa(g) (container_of((g), struct pxa_udc, gadget))
diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c
index 7bd5182ce3ef..89f1f8c9f02e 100644
--- a/drivers/usb/gadget/udc/s3c-hsudc.c
+++ b/drivers/usb/gadget/udc/s3c-hsudc.c
@@ -1220,9 +1220,8 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
struct s3c24xx_hsudc_platdata *pd = dev_get_platdata(&pdev->dev);
int ret, i;
- hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) +
- sizeof(struct s3c_hsudc_ep) * pd->epnum,
- GFP_KERNEL);
+ hsudc = devm_kzalloc(&pdev->dev, struct_size(hsudc, ep, pd->epnum),
+ GFP_KERNEL);
if (!hsudc)
return -ENOMEM;
diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c
index b154b62abefa..179777cb699f 100644
--- a/drivers/usb/gadget/udc/s3c2410_udc.c
+++ b/drivers/usb/gadget/udc/s3c2410_udc.c
@@ -198,7 +198,7 @@ static inline void s3c2410_udc_set_ep0_de(void __iomem *base)
udc_writeb(base, S3C2410_UDC_EP0_CSR_DE, S3C2410_UDC_EP0_CSR_REG);
}
-inline void s3c2410_udc_set_ep0_ss(void __iomem *b)
+static inline void s3c2410_udc_set_ep0_ss(void __iomem *b)
{
udc_writeb(b, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
udc_writeb(b, S3C2410_UDC_EP0_CSR_SENDSTL, S3C2410_UDC_EP0_CSR_REG);
@@ -1843,9 +1843,8 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
if (retval)
goto err_add_udc;
- udc->regs_info = debugfs_create_file("registers", S_IRUGO,
- s3c2410_udc_debugfs_root, udc,
- &s3c2410_udc_debugfs_fops);
+ debugfs_create_file("registers", S_IRUGO, s3c2410_udc_debugfs_root, udc,
+ &s3c2410_udc_debugfs_fops);
dev_dbg(dev, "probe ok\n");
@@ -1889,7 +1888,7 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
return -EBUSY;
usb_del_gadget_udc(&udc->gadget);
- debugfs_remove(udc->regs_info);
+ debugfs_remove(debugfs_lookup("registers", s3c2410_udc_debugfs_root));
if (udc_info && !udc_info->udc_command &&
gpio_is_valid(udc_info->pullup_pin))
diff --git a/drivers/usb/gadget/udc/s3c2410_udc.h b/drivers/usb/gadget/udc/s3c2410_udc.h
index 68bdf3e5aac2..135a5bff3c74 100644
--- a/drivers/usb/gadget/udc/s3c2410_udc.h
+++ b/drivers/usb/gadget/udc/s3c2410_udc.h
@@ -89,7 +89,6 @@ struct s3c2410_udc {
unsigned req_config : 1;
unsigned req_pending : 1;
u8 vbus;
- struct dentry *regs_info;
int irq;
};
#define to_s3c2410(g) (container_of((g), struct s3c2410_udc, gadget))
diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c
index 2319c9737c2b..a54d1cef17db 100644
--- a/drivers/usb/gadget/udc/tegra-xudc.c
+++ b/drivers/usb/gadget/udc/tegra-xudc.c
@@ -1907,7 +1907,7 @@ static void tegra_xudc_ep_free_request(struct usb_ep *usb_ep,
kfree(req);
}
-static struct usb_ep_ops tegra_xudc_ep_ops = {
+static const struct usb_ep_ops tegra_xudc_ep_ops = {
.enable = tegra_xudc_ep_enable,
.disable = tegra_xudc_ep_disable,
.alloc_request = tegra_xudc_ep_alloc_request,
@@ -1928,7 +1928,7 @@ static int tegra_xudc_ep0_disable(struct usb_ep *usb_ep)
return -EBUSY;
}
-static struct usb_ep_ops tegra_xudc_ep0_ops = {
+static const struct usb_ep_ops tegra_xudc_ep0_ops = {
.enable = tegra_xudc_ep0_enable,
.disable = tegra_xudc_ep0_disable,
.alloc_request = tegra_xudc_ep_alloc_request,
@@ -2168,7 +2168,7 @@ static int tegra_xudc_set_selfpowered(struct usb_gadget *gadget, int is_on)
return 0;
}
-static struct usb_gadget_ops tegra_xudc_gadget_ops = {
+static const struct usb_gadget_ops tegra_xudc_gadget_ops = {
.get_frame = tegra_xudc_gadget_get_frame,
.wakeup = tegra_xudc_gadget_wakeup,
.pullup = tegra_xudc_gadget_pullup,
@@ -3508,10 +3508,8 @@ static int tegra_xudc_phy_get(struct tegra_xudc *xudc)
xudc->utmi_phy[i] = devm_phy_optional_get(xudc->dev, phy_name);
if (IS_ERR(xudc->utmi_phy[i])) {
err = PTR_ERR(xudc->utmi_phy[i]);
- if (err != -EPROBE_DEFER)
- dev_err(xudc->dev, "failed to get usb2-%d PHY: %d\n",
- i, err);
-
+ dev_err_probe(xudc->dev, err,
+ "failed to get usb2-%d PHY\n", i);
goto clean_up;
} else if (xudc->utmi_phy[i]) {
/* Get usb-phy, if utmi phy is available */
@@ -3520,8 +3518,8 @@ static int tegra_xudc_phy_get(struct tegra_xudc *xudc)
&xudc->vbus_nb);
if (IS_ERR(xudc->usbphy[i])) {
err = PTR_ERR(xudc->usbphy[i]);
- dev_err(xudc->dev, "failed to get usbphy-%d: %d\n",
- i, err);
+ dev_err_probe(xudc->dev, err,
+ "failed to get usbphy-%d\n", i);
goto clean_up;
}
} else if (!xudc->utmi_phy[i]) {
@@ -3538,10 +3536,8 @@ static int tegra_xudc_phy_get(struct tegra_xudc *xudc)
xudc->usb3_phy[i] = devm_phy_optional_get(xudc->dev, phy_name);
if (IS_ERR(xudc->usb3_phy[i])) {
err = PTR_ERR(xudc->usb3_phy[i]);
- if (err != -EPROBE_DEFER)
- dev_err(xudc->dev, "failed to get usb3-%d PHY: %d\n",
- usb3, err);
-
+ dev_err_probe(xudc->dev, err,
+ "failed to get usb3-%d PHY\n", usb3);
goto clean_up;
} else if (xudc->usb3_phy[i])
dev_dbg(xudc->dev, "usb3-%d PHY registered", usb3);
@@ -3781,9 +3777,7 @@ static int tegra_xudc_probe(struct platform_device *pdev)
err = devm_clk_bulk_get(&pdev->dev, xudc->soc->num_clks, xudc->clks);
if (err) {
- if (err != -EPROBE_DEFER)
- dev_err(xudc->dev, "failed to request clocks: %d\n", err);
-
+ dev_err_probe(xudc->dev, err, "failed to request clocks\n");
return err;
}
@@ -3798,9 +3792,7 @@ static int tegra_xudc_probe(struct platform_device *pdev)
err = devm_regulator_bulk_get(&pdev->dev, xudc->soc->num_supplies,
xudc->supplies);
if (err) {
- if (err != -EPROBE_DEFER)
- dev_err(xudc->dev, "failed to request regulators: %d\n", err);
-
+ dev_err_probe(xudc->dev, err, "failed to request regulators\n");
return err;
}
diff --git a/drivers/usb/gadget/udc/trace.c b/drivers/usb/gadget/udc/trace.c
index 7430624c0bd7..19e837de2a20 100644
--- a/drivers/usb/gadget/udc/trace.c
+++ b/drivers/usb/gadget/udc/trace.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* trace.c - USB Gadget Framework Trace Support
*
* Copyright (C) 2016 Intel Corporation
diff --git a/drivers/usb/gadget/udc/trace.h b/drivers/usb/gadget/udc/trace.h
index 2d1f68b5ea76..98584f6b6c66 100644
--- a/drivers/usb/gadget/udc/trace.h
+++ b/drivers/usb/gadget/udc/trace.h
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* udc.c - Core UDC Framework
*
* Copyright (C) 2016 Intel Corporation
diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c
index 72f2ea062d55..fb4ffedd6f0d 100644
--- a/drivers/usb/gadget/udc/udc-xilinx.c
+++ b/drivers/usb/gadget/udc/udc-xilinx.c
@@ -791,7 +791,7 @@ static int xudc_ep_set_halt(struct usb_ep *_ep, int value)
}
/**
- * xudc_ep_enable - Enables the given endpoint.
+ * __xudc_ep_enable - Enables the given endpoint.
* @ep: pointer to the xusb endpoint structure.
* @desc: pointer to usb endpoint descriptor.
*
@@ -987,7 +987,7 @@ static void xudc_free_request(struct usb_ep *_ep, struct usb_request *_req)
}
/**
- * xudc_ep0_queue - Adds the request to endpoint 0 queue.
+ * __xudc_ep0_queue - Adds the request to endpoint 0 queue.
* @ep0: pointer to the xusb endpoint 0 structure.
* @req: pointer to the xusb request structure.
*
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 6f7bd6641694..385be30baad3 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -387,11 +387,11 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
-#ifdef CONFIG_PPC_83xx
+#if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_85xx)
/*
- * Deal with MPC834X that need port power to be cycled after the power
- * fault condition is removed. Otherwise the state machine does not
- * reflect PORTSC[CSC] correctly.
+ * Deal with MPC834X/85XX that need port power to be cycled
+ * after the power fault condition is removed. Otherwise the
+ * state machine does not reflect PORTSC[CSC] correctly.
*/
ehci->need_oc_pp_cycle = 1;
#endif
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 94b5e64ae9a2..36f5bf6a0752 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -76,12 +76,12 @@ static const char hcd_name [] = "ehci_hcd";
#define EHCI_TUNE_FLS 1 /* (medium) 512-frame schedule */
/* Initial IRQ latency: faster than hw default */
-static int log2_irq_thresh = 0; // 0 to 6
+static int log2_irq_thresh; // 0 to 6
module_param (log2_irq_thresh, int, S_IRUGO);
MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
/* initial park setting: slower than hw default */
-static unsigned park = 0;
+static unsigned park;
module_param (park, uint, S_IRUGO);
MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets");
@@ -1238,6 +1238,10 @@ static const struct hc_driver ehci_hc_driver = {
* device support
*/
.free_dev = ehci_remove_device,
+#ifdef CONFIG_USB_HCD_TEST_MODE
+ /* EH SINGLE_STEP_SET_FEATURE test support */
+ .submit_single_step_set_feature = ehci_submit_single_step_set_feature,
+#endif
};
void ehci_init_driver(struct hc_driver *drv,
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 159cc27b1a36..c4f6a2559a98 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -727,145 +727,6 @@ ehci_hub_descriptor (
}
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_USB_HCD_TEST_MODE
-
-#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06
-
-static void usb_ehset_completion(struct urb *urb)
-{
- struct completion *done = urb->context;
-
- complete(done);
-}
-static int submit_single_step_set_feature(
- struct usb_hcd *hcd,
- struct urb *urb,
- int is_setup
-);
-
-/*
- * Allocate and initialize a control URB. This request will be used by the
- * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
- * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
- * Return NULL if failed.
- */
-static struct urb *request_single_step_set_feature_urb(
- struct usb_device *udev,
- void *dr,
- void *buf,
- struct completion *done
-) {
- struct urb *urb;
- struct usb_hcd *hcd = bus_to_hcd(udev->bus);
- struct usb_host_endpoint *ep;
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb)
- return NULL;
-
- urb->pipe = usb_rcvctrlpipe(udev, 0);
- ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
- [usb_pipeendpoint(urb->pipe)];
- if (!ep) {
- usb_free_urb(urb);
- return NULL;
- }
-
- urb->ep = ep;
- urb->dev = udev;
- urb->setup_packet = (void *)dr;
- urb->transfer_buffer = buf;
- urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
- urb->complete = usb_ehset_completion;
- urb->status = -EINPROGRESS;
- urb->actual_length = 0;
- urb->transfer_flags = URB_DIR_IN;
- usb_get_urb(urb);
- atomic_inc(&urb->use_count);
- atomic_inc(&urb->dev->urbnum);
- urb->setup_dma = dma_map_single(
- hcd->self.sysdev,
- urb->setup_packet,
- sizeof(struct usb_ctrlrequest),
- DMA_TO_DEVICE);
- urb->transfer_dma = dma_map_single(
- hcd->self.sysdev,
- urb->transfer_buffer,
- urb->transfer_buffer_length,
- DMA_FROM_DEVICE);
- urb->context = done;
- return urb;
-}
-
-static int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
-{
- int retval = -ENOMEM;
- struct usb_ctrlrequest *dr;
- struct urb *urb;
- struct usb_device *udev;
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- struct usb_device_descriptor *buf;
- DECLARE_COMPLETION_ONSTACK(done);
-
- /* Obtain udev of the rhub's child port */
- udev = usb_hub_find_child(hcd->self.root_hub, port);
- if (!udev) {
- ehci_err(ehci, "No device attached to the RootHub\n");
- return -ENODEV;
- }
- buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
- if (!dr) {
- kfree(buf);
- return -ENOMEM;
- }
-
- /* Fill Setup packet for GetDescriptor */
- dr->bRequestType = USB_DIR_IN;
- dr->bRequest = USB_REQ_GET_DESCRIPTOR;
- dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
- dr->wIndex = 0;
- dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
- urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
- if (!urb)
- goto cleanup;
-
- /* Submit just the SETUP stage */
- retval = submit_single_step_set_feature(hcd, urb, 1);
- if (retval)
- goto out1;
- if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
- usb_kill_urb(urb);
- retval = -ETIMEDOUT;
- ehci_err(ehci, "%s SETUP stage timed out on ep0\n", __func__);
- goto out1;
- }
- msleep(15 * 1000);
-
- /* Complete remaining DATA and STATUS stages using the same URB */
- urb->status = -EINPROGRESS;
- usb_get_urb(urb);
- atomic_inc(&urb->use_count);
- atomic_inc(&urb->dev->urbnum);
- retval = submit_single_step_set_feature(hcd, urb, 0);
- if (!retval && !wait_for_completion_timeout(&done,
- msecs_to_jiffies(2000))) {
- usb_kill_urb(urb);
- retval = -ETIMEDOUT;
- ehci_err(ehci, "%s IN stage timed out on ep0\n", __func__);
- }
-out1:
- usb_free_urb(urb);
-cleanup:
- kfree(dr);
- kfree(buf);
- return retval;
-}
-#endif /* CONFIG_USB_HCD_TEST_MODE */
-/*-------------------------------------------------------------------------*/
int ehci_hub_control(
struct usb_hcd *hcd,
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index a826715ae9bd..2cbf4f85bff3 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -1165,7 +1165,7 @@ submit_async (
* performed; TRUE - SETUP and FALSE - IN+STATUS
* Returns 0 if success
*/
-static int submit_single_step_set_feature(
+static int ehci_submit_single_step_set_feature(
struct usb_hcd *hcd,
struct urb *urb,
int is_setup
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
index 9c2eda0918e1..05fb8d97cf02 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -850,7 +850,6 @@ static inline void create_debug_files(struct fotg210_hcd *fotg210)
struct dentry *root;
root = debugfs_create_dir(bus->bus_name, fotg210_debug_root);
- fotg210->debug_dir = root;
debugfs_create_file("async", S_IRUGO, root, bus, &debug_async_fops);
debugfs_create_file("periodic", S_IRUGO, root, bus,
@@ -861,7 +860,9 @@ static inline void create_debug_files(struct fotg210_hcd *fotg210)
static inline void remove_debug_files(struct fotg210_hcd *fotg210)
{
- debugfs_remove_recursive(fotg210->debug_dir);
+ struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self;
+
+ debugfs_remove(debugfs_lookup(bus->bus_name, fotg210_debug_root));
}
/* handshake - spin reading hc until handshake completes or fails
diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h
index 6cee40ec65b4..0a91061a0551 100644
--- a/drivers/usb/host/fotg210.h
+++ b/drivers/usb/host/fotg210.h
@@ -184,9 +184,6 @@ struct fotg210_hcd { /* one per controller */
/* silicon clock */
struct clk *pclk;
-
- /* debug files */
- struct dentry *debug_dir;
};
/* convert between an HCD pointer and the corresponding FOTG210_HCD */
diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c
index afd9174d83b1..e7a8e0609853 100644
--- a/drivers/usb/host/max3421-hcd.c
+++ b/drivers/usb/host/max3421-hcd.c
@@ -1169,8 +1169,7 @@ max3421_irq_handler(int irq, void *dev_id)
struct spi_device *spi = to_spi_device(hcd->self.controller);
struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd);
- if (max3421_hcd->spi_thread &&
- max3421_hcd->spi_thread->state != TASK_RUNNING)
+ if (max3421_hcd->spi_thread)
wake_up_process(max3421_hcd->spi_thread);
if (!test_and_set_bit(ENABLE_IRQ, &max3421_hcd->todo))
disable_irq_nosync(spi->irq);
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 5a783c423d8e..ae882d76612b 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -2392,8 +2392,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
urb->error_count = 0;
usb_hcd_giveback_urb(hcd, urb, 0);
return 0;
- } else
- continue;
+ }
}
dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring"
"[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X"
@@ -2448,8 +2447,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
queue_scan];
break;
- } else
- continue;
+ }
}
while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
*urb_slot = endp->urb_list[ENDP_QUEUE_MASK &
diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c
index ae4e4ab638b5..bef104511352 100644
--- a/drivers/usb/host/xhci-dbgtty.c
+++ b/drivers/usb/host/xhci-dbgtty.c
@@ -240,11 +240,11 @@ static void dbc_tty_flush_chars(struct tty_struct *tty)
spin_unlock_irqrestore(&port->port_lock, flags);
}
-static int dbc_tty_write_room(struct tty_struct *tty)
+static unsigned int dbc_tty_write_room(struct tty_struct *tty)
{
struct dbc_port *port = tty->driver_data;
unsigned long flags;
- int room = 0;
+ unsigned int room;
spin_lock_irqsave(&port->port_lock, flags);
room = kfifo_avail(&port->write_fifo);
@@ -253,11 +253,11 @@ static int dbc_tty_write_room(struct tty_struct *tty)
return room;
}
-static int dbc_tty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int dbc_tty_chars_in_buffer(struct tty_struct *tty)
{
struct dbc_port *port = tty->driver_data;
unsigned long flags;
- int chars = 0;
+ unsigned int chars;
spin_lock_irqsave(&port->port_lock, flags);
chars = kfifo_len(&port->write_fifo);
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index f66815fe8482..0e312066c5c6 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1924,6 +1924,7 @@ no_bw:
xhci->hw_ports = NULL;
xhci->rh_bw = NULL;
xhci->ext_caps = NULL;
+ xhci->port_caps = NULL;
xhci->page_size = 0;
xhci->page_shift = 0;
@@ -2547,6 +2548,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Wrote ERST address to ir_set 0.");
+ xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
+
/*
* XXX: Might need to set the Interrupter Moderation Register to
* something other than the default (~1ms minimum between interrupts).
diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 8b90da5a6ed1..cffcaf4dfa9f 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -470,11 +470,12 @@ static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset)
static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset)
{
- struct mu3h_sch_tt *tt = sch_ep->sch_tt;
u32 extra_cs_count;
u32 start_ss, last_ss;
u32 start_cs, last_cs;
- int i;
+
+ if (!sch_ep->sch_tt)
+ return 0;
start_ss = offset % 8;
@@ -488,10 +489,6 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset)
if (!(start_ss == 7 || last_ss < 6))
return -ESCH_SS_Y6;
- for (i = 0; i < sch_ep->cs_count; i++)
- if (test_bit(offset + i, tt->ss_bit_map))
- return -ESCH_SS_OVERLAP;
-
} else {
u32 cs_count = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX);
@@ -518,9 +515,6 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset)
if (cs_count > 7)
cs_count = 7; /* HW limit */
- if (test_bit(offset, tt->ss_bit_map))
- return -ESCH_SS_OVERLAP;
-
sch_ep->cs_count = cs_count;
/* one for ss, the other for idle */
sch_ep->num_budget_microframes = cs_count + 2;
@@ -541,11 +535,9 @@ static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used)
struct mu3h_sch_tt *tt = sch_ep->sch_tt;
u32 base, num_esit;
int bw_updated;
- int bits;
int i, j;
num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
- bits = (sch_ep->ep_type == ISOC_OUT_EP) ? sch_ep->cs_count : 1;
if (used)
bw_updated = sch_ep->bw_cost_per_microframe;
@@ -555,13 +547,6 @@ static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used)
for (i = 0; i < num_esit; i++) {
base = sch_ep->offset + i * sch_ep->esit;
- for (j = 0; j < bits; j++) {
- if (used)
- set_bit(base + j, tt->ss_bit_map);
- else
- clear_bit(base + j, tt->ss_bit_map);
- }
-
for (j = 0; j < sch_ep->cs_count; j++)
tt->fs_bus_bw[base + j] += bw_updated;
}
@@ -603,54 +588,47 @@ static u32 get_esit_boundary(struct mu3h_sch_ep_info *sch_ep)
static int check_sch_bw(struct mu3h_sch_bw_info *sch_bw,
struct mu3h_sch_ep_info *sch_ep)
{
+ const u32 esit_boundary = get_esit_boundary(sch_ep);
+ const u32 bw_boundary = get_bw_boundary(sch_ep->speed);
u32 offset;
- u32 min_bw;
- u32 min_index;
u32 worst_bw;
- u32 bw_boundary;
- u32 esit_boundary;
- u32 min_num_budget;
- u32 min_cs_count;
+ u32 min_bw = ~0;
+ int min_index = -1;
int ret = 0;
/*
* Search through all possible schedule microframes.
* and find a microframe where its worst bandwidth is minimum.
*/
- min_bw = ~0;
- min_index = 0;
- min_cs_count = sch_ep->cs_count;
- min_num_budget = sch_ep->num_budget_microframes;
- esit_boundary = get_esit_boundary(sch_ep);
for (offset = 0; offset < sch_ep->esit; offset++) {
- if (sch_ep->sch_tt) {
- ret = check_sch_tt(sch_ep, offset);
- if (ret)
- continue;
- }
+ ret = check_sch_tt(sch_ep, offset);
+ if (ret)
+ continue;
if ((offset + sch_ep->num_budget_microframes) > esit_boundary)
break;
worst_bw = get_max_bw(sch_bw, sch_ep, offset);
+ if (worst_bw > bw_boundary)
+ continue;
+
if (min_bw > worst_bw) {
min_bw = worst_bw;
min_index = offset;
- min_cs_count = sch_ep->cs_count;
- min_num_budget = sch_ep->num_budget_microframes;
}
+
+ /* use first-fit for LS/FS */
+ if (sch_ep->sch_tt && min_index >= 0)
+ break;
+
if (min_bw == 0)
break;
}
- bw_boundary = get_bw_boundary(sch_ep->speed);
- /* check bandwidth */
- if (min_bw > bw_boundary)
+ if (min_index < 0)
return ret ? ret : -ESCH_BW_OVERFLOW;
sch_ep->offset = min_index;
- sch_ep->cs_count = min_cs_count;
- sch_ep->num_budget_microframes = min_num_budget;
return load_ep_bw(sch_bw, sch_ep, true);
}
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index b2058b3bc834..2548976bcf05 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -495,8 +495,6 @@ static int xhci_mtk_probe(struct platform_device *pdev)
goto put_usb2_hcd;
}
mtk->has_ippc = true;
- } else {
- mtk->has_ippc = false;
}
device_init_wakeup(dev, true);
diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
index cd3a37bb73e6..ace432356c41 100644
--- a/drivers/usb/host/xhci-mtk.h
+++ b/drivers/usb/host/xhci-mtk.h
@@ -24,12 +24,10 @@
#define XHCI_MTK_MAX_ESIT 64
/**
- * @ss_bit_map: used to avoid start split microframes overlay
* @fs_bus_bw: array to keep track of bandwidth already used for FS
* @ep_list: Endpoints using this TT
*/
struct mu3h_sch_tt {
- DECLARE_BITMAP(ss_bit_map, XHCI_MTK_MAX_ESIT);
u32 fs_bus_bw[XHCI_MTK_MAX_ESIT];
struct list_head ep_list;
};
@@ -138,17 +136,17 @@ struct xhci_hcd_mtk {
struct mu3h_sch_bw_info *sch_array;
struct list_head bw_ep_chk_list;
struct mu3c_ippc_regs __iomem *ippc_regs;
- bool has_ippc;
int num_u2_ports;
int num_u3_ports;
int u3p_dis_msk;
struct regulator *vusb33;
struct regulator *vbus;
struct clk_bulk_data clks[BULK_CLKS_NUM];
- bool lpm_support;
- bool u2_lpm_disable;
+ unsigned int has_ippc:1;
+ unsigned int lpm_support:1;
+ unsigned int u2_lpm_disable:1;
/* usb remote wakeup */
- bool uwk_en;
+ unsigned int uwk_en:1;
struct regmap *uwk;
u32 uwk_reg_base;
u32 uwk_vers;
diff --git a/drivers/usb/host/xhci-pci-renesas.c b/drivers/usb/host/xhci-pci-renesas.c
index f97ac9f52bf4..1da647961c25 100644
--- a/drivers/usb/host/xhci-pci-renesas.c
+++ b/drivers/usb/host/xhci-pci-renesas.c
@@ -197,7 +197,7 @@ static int renesas_check_rom_state(struct pci_dev *pdev)
if (err)
return pcibios_err_to_errno(err);
- if (rom_state & BIT(15)) {
+ if (rom_state & RENESAS_ROM_STATUS_ROM_EXISTS) {
/* ROM exists */
dev_dbg(&pdev->dev, "ROM exists\n");
@@ -207,7 +207,8 @@ static int renesas_check_rom_state(struct pci_dev *pdev)
return 0;
case RENESAS_ROM_STATUS_NO_RESULT: /* No result yet */
- return 0;
+ dev_dbg(&pdev->dev, "Unknown ROM status ...\n");
+ break;
case RENESAS_ROM_STATUS_ERROR: /* Error State */
default: /* All other states are marked as "Reserved states" */
@@ -224,13 +225,12 @@ static int renesas_fw_check_running(struct pci_dev *pdev)
u8 fw_state;
int err;
- /* Check if device has ROM and loaded, if so skip everything */
- err = renesas_check_rom(pdev);
- if (err) { /* we have rom */
- err = renesas_check_rom_state(pdev);
- if (!err)
- return err;
- }
+ /*
+ * Only if device has ROM and loaded FW we can skip loading and
+ * return success. Otherwise (even unknown state), attempt to load FW.
+ */
+ if (renesas_check_rom(pdev) && !renesas_check_rom_state(pdev))
+ return 0;
/*
* Test if the device is actually needing the firmware. As most
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 6acd2329e08d..8fea44bbc266 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3076,6 +3076,11 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
if (event_loop++ < TRBS_PER_SEGMENT / 2)
continue;
xhci_update_erst_dequeue(xhci, event_ring_deq);
+
+ /* ring is half-full, force isoc trbs to interrupt more often */
+ if (xhci->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN)
+ xhci->isoc_bei_interval = xhci->isoc_bei_interval / 2;
+
event_loop = 0;
}
@@ -3956,7 +3961,7 @@ static bool trb_block_event_intr(struct xhci_hcd *xhci, int num_tds, int i)
* generate an event at least every 8th TD to clear the event ring
*/
if (i && xhci->quirks & XHCI_AVOID_BEI)
- return !!(i % 8);
+ return !!(i % xhci->isoc_bei_interval);
return true;
}
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index 50bb91b6a4b8..575fa89a783f 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -2,7 +2,7 @@
/*
* NVIDIA Tegra xHCI host controller driver
*
- * Copyright (C) 2014 NVIDIA Corporation
+ * Copyright (c) 2014-2020, NVIDIA CORPORATION. All rights reserved.
* Copyright (C) 2014 Google, Inc.
*/
@@ -15,9 +15,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <linux/phy/phy.h>
#include <linux/phy/tegra/xusb.h>
#include <linux/platform_device.h>
+#include <linux/usb/ch9.h>
#include <linux/pm.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
@@ -224,6 +226,7 @@ struct tegra_xusb {
int xhci_irq;
int mbox_irq;
+ int padctl_irq;
void __iomem *ipfs_base;
void __iomem *fpci_base;
@@ -249,8 +252,7 @@ struct tegra_xusb {
struct device *genpd_dev_host;
struct device *genpd_dev_ss;
- struct device_link *genpd_dl_host;
- struct device_link *genpd_dl_ss;
+ bool use_genpd;
struct phy **phys;
unsigned int num_phys;
@@ -270,6 +272,7 @@ struct tegra_xusb {
dma_addr_t phys;
} fw;
+ bool suspended;
struct tegra_xusb_context context;
};
@@ -666,6 +669,9 @@ static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data)
mutex_lock(&tegra->lock);
+ if (pm_runtime_suspended(tegra->dev) || tegra->suspended)
+ goto out;
+
value = fpci_readl(tegra, tegra->soc->mbox.data_out);
tegra_xusb_mbox_unpack(&msg, value);
@@ -679,6 +685,7 @@ static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data)
tegra_xusb_mbox_handle(tegra, &msg);
+out:
mutex_unlock(&tegra->lock);
return IRQ_HANDLED;
}
@@ -819,40 +826,6 @@ static void tegra_xusb_phy_disable(struct tegra_xusb *tegra)
}
}
-static int tegra_xusb_runtime_suspend(struct device *dev)
-{
- struct tegra_xusb *tegra = dev_get_drvdata(dev);
-
- regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
- tegra_xusb_clk_disable(tegra);
-
- return 0;
-}
-
-static int tegra_xusb_runtime_resume(struct device *dev)
-{
- struct tegra_xusb *tegra = dev_get_drvdata(dev);
- int err;
-
- err = tegra_xusb_clk_enable(tegra);
- if (err) {
- dev_err(dev, "failed to enable clocks: %d\n", err);
- return err;
- }
-
- err = regulator_bulk_enable(tegra->soc->num_supplies, tegra->supplies);
- if (err) {
- dev_err(dev, "failed to enable regulators: %d\n", err);
- goto disable_clk;
- }
-
- return 0;
-
-disable_clk:
- tegra_xusb_clk_disable(tegra);
- return err;
-}
-
#ifdef CONFIG_PM_SLEEP
static int tegra_xusb_init_context(struct tegra_xusb *tegra)
{
@@ -917,7 +890,6 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
struct xhci_op_regs __iomem *op;
unsigned long timeout;
time64_t timestamp;
- struct tm time;
u64 address;
u32 value;
int err;
@@ -1014,11 +986,8 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
}
timestamp = le32_to_cpu(header->fwimg_created_time);
- time64_to_tm(timestamp, 0, &time);
- dev_info(dev, "Firmware timestamp: %ld-%02d-%02d %02d:%02d:%02d UTC\n",
- time.tm_year + 1900, time.tm_mon + 1, time.tm_mday,
- time.tm_hour, time.tm_min, time.tm_sec);
+ dev_info(dev, "Firmware timestamp: %ptTs UTC\n", &timestamp);
return 0;
}
@@ -1026,10 +995,9 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
static void tegra_xusb_powerdomain_remove(struct device *dev,
struct tegra_xusb *tegra)
{
- if (tegra->genpd_dl_ss)
- device_link_del(tegra->genpd_dl_ss);
- if (tegra->genpd_dl_host)
- device_link_del(tegra->genpd_dl_host);
+ if (!tegra->use_genpd)
+ return;
+
if (!IS_ERR_OR_NULL(tegra->genpd_dev_ss))
dev_pm_domain_detach(tegra->genpd_dev_ss, true);
if (!IS_ERR_OR_NULL(tegra->genpd_dev_host))
@@ -1055,20 +1023,84 @@ static int tegra_xusb_powerdomain_init(struct device *dev,
return err;
}
- tegra->genpd_dl_host = device_link_add(dev, tegra->genpd_dev_host,
- DL_FLAG_PM_RUNTIME |
- DL_FLAG_STATELESS);
- if (!tegra->genpd_dl_host) {
- dev_err(dev, "adding host device link failed!\n");
- return -ENODEV;
+ tegra->use_genpd = true;
+
+ return 0;
+}
+
+static int tegra_xusb_unpowergate_partitions(struct tegra_xusb *tegra)
+{
+ struct device *dev = tegra->dev;
+ int rc;
+
+ if (tegra->use_genpd) {
+ rc = pm_runtime_get_sync(tegra->genpd_dev_ss);
+ if (rc < 0) {
+ dev_err(dev, "failed to enable XUSB SS partition\n");
+ return rc;
+ }
+
+ rc = pm_runtime_get_sync(tegra->genpd_dev_host);
+ if (rc < 0) {
+ dev_err(dev, "failed to enable XUSB Host partition\n");
+ pm_runtime_put_sync(tegra->genpd_dev_ss);
+ return rc;
+ }
+ } else {
+ rc = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBA,
+ tegra->ss_clk,
+ tegra->ss_rst);
+ if (rc < 0) {
+ dev_err(dev, "failed to enable XUSB SS partition\n");
+ return rc;
+ }
+
+ rc = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBC,
+ tegra->host_clk,
+ tegra->host_rst);
+ if (rc < 0) {
+ dev_err(dev, "failed to enable XUSB Host partition\n");
+ tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
+ return rc;
+ }
}
- tegra->genpd_dl_ss = device_link_add(dev, tegra->genpd_dev_ss,
- DL_FLAG_PM_RUNTIME |
- DL_FLAG_STATELESS);
- if (!tegra->genpd_dl_ss) {
- dev_err(dev, "adding superspeed device link failed!\n");
- return -ENODEV;
+ return 0;
+}
+
+static int tegra_xusb_powergate_partitions(struct tegra_xusb *tegra)
+{
+ struct device *dev = tegra->dev;
+ int rc;
+
+ if (tegra->use_genpd) {
+ rc = pm_runtime_put_sync(tegra->genpd_dev_host);
+ if (rc < 0) {
+ dev_err(dev, "failed to disable XUSB Host partition\n");
+ return rc;
+ }
+
+ rc = pm_runtime_put_sync(tegra->genpd_dev_ss);
+ if (rc < 0) {
+ dev_err(dev, "failed to disable XUSB SS partition\n");
+ pm_runtime_get_sync(tegra->genpd_dev_host);
+ return rc;
+ }
+ } else {
+ rc = tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC);
+ if (rc < 0) {
+ dev_err(dev, "failed to disable XUSB Host partition\n");
+ return rc;
+ }
+
+ rc = tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
+ if (rc < 0) {
+ dev_err(dev, "failed to disable XUSB SS partition\n");
+ tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBC,
+ tegra->host_clk,
+ tegra->host_rst);
+ return rc;
+ }
}
return 0;
@@ -1090,6 +1122,24 @@ static int __tegra_xusb_enable_firmware_messages(struct tegra_xusb *tegra)
return err;
}
+static irqreturn_t tegra_xusb_padctl_irq(int irq, void *data)
+{
+ struct tegra_xusb *tegra = data;
+
+ mutex_lock(&tegra->lock);
+
+ if (tegra->suspended) {
+ mutex_unlock(&tegra->lock);
+ return IRQ_HANDLED;
+ }
+
+ mutex_unlock(&tegra->lock);
+
+ pm_runtime_resume(tegra->dev);
+
+ return IRQ_HANDLED;
+}
+
static int tegra_xusb_enable_firmware_messages(struct tegra_xusb *tegra)
{
int err;
@@ -1213,6 +1263,52 @@ static void tegra_xhci_id_work(struct work_struct *work)
}
}
+#if IS_ENABLED(CONFIG_PM) || IS_ENABLED(CONFIG_PM_SLEEP)
+static bool is_usb2_otg_phy(struct tegra_xusb *tegra, unsigned int index)
+{
+ return (tegra->usbphy[index] != NULL);
+}
+
+static bool is_usb3_otg_phy(struct tegra_xusb *tegra, unsigned int index)
+{
+ struct tegra_xusb_padctl *padctl = tegra->padctl;
+ unsigned int i;
+ int port;
+
+ for (i = 0; i < tegra->num_usb_phys; i++) {
+ if (is_usb2_otg_phy(tegra, i)) {
+ port = tegra_xusb_padctl_get_usb3_companion(padctl, i);
+ if ((port >= 0) && (index == (unsigned int)port))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool is_host_mode_phy(struct tegra_xusb *tegra, unsigned int phy_type, unsigned int index)
+{
+ if (strcmp(tegra->soc->phy_types[phy_type].name, "hsic") == 0)
+ return true;
+
+ if (strcmp(tegra->soc->phy_types[phy_type].name, "usb2") == 0) {
+ if (is_usb2_otg_phy(tegra, index))
+ return ((index == tegra->otg_usb2_port) && tegra->host_mode);
+ else
+ return true;
+ }
+
+ if (strcmp(tegra->soc->phy_types[phy_type].name, "usb3") == 0) {
+ if (is_usb3_otg_phy(tegra, index))
+ return ((index == tegra->otg_usb3_port) && tegra->host_mode);
+ else
+ return true;
+ }
+
+ return false;
+}
+#endif
+
static int tegra_xusb_get_usb2_port(struct tegra_xusb *tegra,
struct usb_phy *usbphy)
{
@@ -1305,6 +1401,7 @@ static void tegra_xusb_deinit_usb_phy(struct tegra_xusb *tegra)
static int tegra_xusb_probe(struct platform_device *pdev)
{
struct tegra_xusb *tegra;
+ struct device_node *np;
struct resource *regs;
struct xhci_hcd *xhci;
unsigned int i, j, k;
@@ -1325,8 +1422,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
if (err < 0)
return err;
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- tegra->regs = devm_ioremap_resource(&pdev->dev, regs);
+ tegra->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
if (IS_ERR(tegra->regs))
return PTR_ERR(tegra->regs);
@@ -1352,6 +1448,18 @@ static int tegra_xusb_probe(struct platform_device *pdev)
if (IS_ERR(tegra->padctl))
return PTR_ERR(tegra->padctl);
+ np = of_parse_phandle(pdev->dev.of_node, "nvidia,xusb-padctl", 0);
+ if (!np) {
+ err = -ENODEV;
+ goto put_padctl;
+ }
+
+ tegra->padctl_irq = of_irq_get(np, 0);
+ if (tegra->padctl_irq <= 0) {
+ err = (tegra->padctl_irq == 0) ? -ENODEV : tegra->padctl_irq;
+ goto put_padctl;
+ }
+
tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host");
if (IS_ERR(tegra->host_clk)) {
err = PTR_ERR(tegra->host_clk);
@@ -1432,25 +1540,6 @@ static int tegra_xusb_probe(struct platform_device *pdev)
err);
goto put_padctl;
}
-
- err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBA,
- tegra->ss_clk,
- tegra->ss_rst);
- if (err) {
- dev_err(&pdev->dev,
- "failed to enable XUSBA domain: %d\n", err);
- goto put_padctl;
- }
-
- err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBC,
- tegra->host_clk,
- tegra->host_rst);
- if (err) {
- tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
- dev_err(&pdev->dev,
- "failed to enable XUSBC domain: %d\n", err);
- goto put_padctl;
- }
} else {
err = tegra_xusb_powerdomain_init(&pdev->dev, tegra);
if (err)
@@ -1515,6 +1604,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto put_powerdomains;
}
+ tegra->hcd->skip_phy_initialization = 1;
tegra->hcd->regs = tegra->regs;
tegra->hcd->rsrc_start = regs->start;
tegra->hcd->rsrc_len = resource_size(regs);
@@ -1525,10 +1615,22 @@ static int tegra_xusb_probe(struct platform_device *pdev)
*/
platform_set_drvdata(pdev, tegra);
+ err = tegra_xusb_clk_enable(tegra);
+ if (err) {
+ dev_err(tegra->dev, "failed to enable clocks: %d\n", err);
+ goto put_hcd;
+ }
+
+ err = regulator_bulk_enable(tegra->soc->num_supplies, tegra->supplies);
+ if (err) {
+ dev_err(tegra->dev, "failed to enable regulators: %d\n", err);
+ goto disable_clk;
+ }
+
err = tegra_xusb_phy_enable(tegra);
if (err < 0) {
dev_err(&pdev->dev, "failed to enable PHYs: %d\n", err);
- goto put_hcd;
+ goto disable_regulator;
}
/*
@@ -1547,30 +1649,22 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto disable_phy;
}
- pm_runtime_enable(&pdev->dev);
-
- if (!pm_runtime_enabled(&pdev->dev))
- err = tegra_xusb_runtime_resume(&pdev->dev);
- else
- err = pm_runtime_get_sync(&pdev->dev);
-
- if (err < 0) {
- dev_err(&pdev->dev, "failed to enable device: %d\n", err);
+ err = tegra_xusb_unpowergate_partitions(tegra);
+ if (err)
goto free_firmware;
- }
tegra_xusb_config(tegra);
err = tegra_xusb_load_firmware(tegra);
if (err < 0) {
dev_err(&pdev->dev, "failed to load firmware: %d\n", err);
- goto put_rpm;
+ goto powergate;
}
err = usb_add_hcd(tegra->hcd, tegra->xhci_irq, IRQF_SHARED);
if (err < 0) {
dev_err(&pdev->dev, "failed to add USB HCD: %d\n", err);
- goto put_rpm;
+ goto powergate;
}
device_wakeup_enable(tegra->hcd->self.controller);
@@ -1593,12 +1687,6 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto put_usb3;
}
- err = tegra_xusb_enable_firmware_messages(tegra);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to enable messages: %d\n", err);
- goto remove_usb3;
- }
-
err = devm_request_threaded_irq(&pdev->dev, tegra->mbox_irq,
tegra_xusb_mbox_irq,
tegra_xusb_mbox_thread, 0,
@@ -1608,12 +1696,36 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto remove_usb3;
}
+ err = devm_request_threaded_irq(&pdev->dev, tegra->padctl_irq, NULL, tegra_xusb_padctl_irq,
+ IRQF_ONESHOT, dev_name(&pdev->dev), tegra);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to request padctl IRQ: %d\n", err);
+ goto remove_usb3;
+ }
+
+ err = tegra_xusb_enable_firmware_messages(tegra);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to enable messages: %d\n", err);
+ goto remove_usb3;
+ }
+
err = tegra_xusb_init_usb_phy(tegra);
if (err < 0) {
dev_err(&pdev->dev, "failed to init USB PHY: %d\n", err);
goto remove_usb3;
}
+ /* Enable wake for both USB 2.0 and USB 3.0 roothubs */
+ device_init_wakeup(&tegra->hcd->self.root_hub->dev, true);
+ device_init_wakeup(&xhci->shared_hcd->self.root_hub->dev, true);
+ device_init_wakeup(tegra->dev, true);
+
+ pm_runtime_use_autosuspend(tegra->dev);
+ pm_runtime_set_autosuspend_delay(tegra->dev, 2000);
+ pm_runtime_mark_last_busy(tegra->dev);
+ pm_runtime_set_active(tegra->dev);
+ pm_runtime_enable(tegra->dev);
+
return 0;
remove_usb3:
@@ -1622,25 +1734,23 @@ put_usb3:
usb_put_hcd(xhci->shared_hcd);
remove_usb2:
usb_remove_hcd(tegra->hcd);
-put_rpm:
- if (!pm_runtime_status_suspended(&pdev->dev))
- tegra_xusb_runtime_suspend(&pdev->dev);
-put_hcd:
- usb_put_hcd(tegra->hcd);
+powergate:
+ tegra_xusb_powergate_partitions(tegra);
free_firmware:
dma_free_coherent(&pdev->dev, tegra->fw.size, tegra->fw.virt,
tegra->fw.phys);
disable_phy:
tegra_xusb_phy_disable(tegra);
- pm_runtime_disable(&pdev->dev);
+disable_regulator:
+ regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
+disable_clk:
+ tegra_xusb_clk_disable(tegra);
+put_hcd:
+ usb_put_hcd(tegra->hcd);
put_powerdomains:
- if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) {
- tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC);
- tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
- } else {
- tegra_xusb_powerdomain_remove(&pdev->dev, tegra);
- }
+ tegra_xusb_powerdomain_remove(&pdev->dev, tegra);
put_padctl:
+ of_node_put(np);
tegra_xusb_padctl_put(tegra->padctl);
return err;
}
@@ -1652,6 +1762,7 @@ static int tegra_xusb_remove(struct platform_device *pdev)
tegra_xusb_deinit_usb_phy(tegra);
+ pm_runtime_get_sync(&pdev->dev);
usb_remove_hcd(xhci->shared_hcd);
usb_put_hcd(xhci->shared_hcd);
xhci->shared_hcd = NULL;
@@ -1661,24 +1772,22 @@ static int tegra_xusb_remove(struct platform_device *pdev)
dma_free_coherent(&pdev->dev, tegra->fw.size, tegra->fw.virt,
tegra->fw.phys);
- pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_put(&pdev->dev);
- if (!of_property_read_bool(pdev->dev.of_node, "power-domains")) {
- tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC);
- tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
- } else {
- tegra_xusb_powerdomain_remove(&pdev->dev, tegra);
- }
+ tegra_xusb_powergate_partitions(tegra);
- tegra_xusb_phy_disable(tegra);
+ tegra_xusb_powerdomain_remove(&pdev->dev, tegra);
+ tegra_xusb_phy_disable(tegra);
+ tegra_xusb_clk_disable(tegra);
+ regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
tegra_xusb_padctl_put(tegra->padctl);
return 0;
}
-#ifdef CONFIG_PM_SLEEP
+#if IS_ENABLED(CONFIG_PM) || IS_ENABLED(CONFIG_PM_SLEEP)
static bool xhci_hub_ports_suspended(struct xhci_hub *hub)
{
struct device *dev = hub->hcd->self.controller;
@@ -1704,9 +1813,17 @@ static bool xhci_hub_ports_suspended(struct xhci_hub *hub)
static int tegra_xusb_check_ports(struct tegra_xusb *tegra)
{
struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
+ struct xhci_bus_state *bus_state = &xhci->usb2_rhub.bus_state;
unsigned long flags;
int err = 0;
+ if (bus_state->bus_suspended) {
+ /* xusb_hub_suspend() has just directed one or more USB2 port(s)
+ * to U3 state, it takes 3ms to enter U3.
+ */
+ usleep_range(3000, 4000);
+ }
+
spin_lock_irqsave(&xhci->lock, flags);
if (!xhci_hub_ports_suspended(&xhci->usb2_rhub) ||
@@ -1752,45 +1869,186 @@ static void tegra_xusb_restore_context(struct tegra_xusb *tegra)
}
}
-static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool wakeup)
+static enum usb_device_speed tegra_xhci_portsc_to_speed(struct tegra_xusb *tegra, u32 portsc)
{
+ if (DEV_LOWSPEED(portsc))
+ return USB_SPEED_LOW;
+
+ if (DEV_HIGHSPEED(portsc))
+ return USB_SPEED_HIGH;
+
+ if (DEV_FULLSPEED(portsc))
+ return USB_SPEED_FULL;
+
+ if (DEV_SUPERSPEED_ANY(portsc))
+ return USB_SPEED_SUPER;
+
+ return USB_SPEED_UNKNOWN;
+}
+
+static void tegra_xhci_enable_phy_sleepwalk_wake(struct tegra_xusb *tegra)
+{
+ struct tegra_xusb_padctl *padctl = tegra->padctl;
struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
+ enum usb_device_speed speed;
+ struct phy *phy;
+ unsigned int index, offset;
+ unsigned int i, j, k;
+ struct xhci_hub *rhub;
+ u32 portsc;
+
+ for (i = 0, k = 0; i < tegra->soc->num_types; i++) {
+ if (strcmp(tegra->soc->phy_types[i].name, "usb3") == 0)
+ rhub = &xhci->usb3_rhub;
+ else
+ rhub = &xhci->usb2_rhub;
+
+ if (strcmp(tegra->soc->phy_types[i].name, "hsic") == 0)
+ offset = tegra->soc->ports.usb2.count;
+ else
+ offset = 0;
+
+ for (j = 0; j < tegra->soc->phy_types[i].num; j++) {
+ phy = tegra->phys[k++];
+
+ if (!phy)
+ continue;
+
+ index = j + offset;
+
+ if (index >= rhub->num_ports)
+ continue;
+
+ if (!is_host_mode_phy(tegra, i, j))
+ continue;
+
+ portsc = readl(rhub->ports[index]->addr);
+ speed = tegra_xhci_portsc_to_speed(tegra, portsc);
+ tegra_xusb_padctl_enable_phy_sleepwalk(padctl, phy, speed);
+ tegra_xusb_padctl_enable_phy_wake(padctl, phy);
+ }
+ }
+}
+
+static void tegra_xhci_disable_phy_wake(struct tegra_xusb *tegra)
+{
+ struct tegra_xusb_padctl *padctl = tegra->padctl;
+ unsigned int i;
+
+ for (i = 0; i < tegra->num_phys; i++) {
+ if (!tegra->phys[i])
+ continue;
+
+ tegra_xusb_padctl_disable_phy_wake(padctl, tegra->phys[i]);
+ }
+}
+
+static void tegra_xhci_disable_phy_sleepwalk(struct tegra_xusb *tegra)
+{
+ struct tegra_xusb_padctl *padctl = tegra->padctl;
+ unsigned int i;
+
+ for (i = 0; i < tegra->num_phys; i++) {
+ if (!tegra->phys[i])
+ continue;
+
+ tegra_xusb_padctl_disable_phy_sleepwalk(padctl, tegra->phys[i]);
+ }
+}
+
+static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool runtime)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
+ struct device *dev = tegra->dev;
+ bool wakeup = runtime ? true : device_may_wakeup(dev);
+ unsigned int i;
int err;
+ u32 usbcmd;
+
+ dev_dbg(dev, "entering ELPG\n");
+
+ usbcmd = readl(&xhci->op_regs->command);
+ usbcmd &= ~CMD_EIE;
+ writel(usbcmd, &xhci->op_regs->command);
err = tegra_xusb_check_ports(tegra);
if (err < 0) {
dev_err(tegra->dev, "not all ports suspended: %d\n", err);
- return err;
+ goto out;
}
err = xhci_suspend(xhci, wakeup);
if (err < 0) {
dev_err(tegra->dev, "failed to suspend XHCI: %d\n", err);
- return err;
+ goto out;
}
tegra_xusb_save_context(tegra);
- tegra_xusb_phy_disable(tegra);
+
+ if (wakeup)
+ tegra_xhci_enable_phy_sleepwalk_wake(tegra);
+
+ tegra_xusb_powergate_partitions(tegra);
+
+ for (i = 0; i < tegra->num_phys; i++) {
+ if (!tegra->phys[i])
+ continue;
+
+ phy_power_off(tegra->phys[i]);
+ if (!wakeup)
+ phy_exit(tegra->phys[i]);
+ }
+
tegra_xusb_clk_disable(tegra);
- return 0;
+out:
+ if (!err)
+ dev_dbg(tegra->dev, "entering ELPG done\n");
+ else {
+ usbcmd = readl(&xhci->op_regs->command);
+ usbcmd |= CMD_EIE;
+ writel(usbcmd, &xhci->op_regs->command);
+
+ dev_dbg(tegra->dev, "entering ELPG failed\n");
+ pm_runtime_mark_last_busy(tegra->dev);
+ }
+
+ return err;
}
-static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool wakeup)
+static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool runtime)
{
struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
+ struct device *dev = tegra->dev;
+ bool wakeup = runtime ? true : device_may_wakeup(dev);
+ unsigned int i;
+ u32 usbcmd;
int err;
+ dev_dbg(dev, "exiting ELPG\n");
+ pm_runtime_mark_last_busy(tegra->dev);
+
err = tegra_xusb_clk_enable(tegra);
if (err < 0) {
dev_err(tegra->dev, "failed to enable clocks: %d\n", err);
- return err;
+ goto out;
}
- err = tegra_xusb_phy_enable(tegra);
- if (err < 0) {
- dev_err(tegra->dev, "failed to enable PHYs: %d\n", err);
- goto disable_clk;
+ err = tegra_xusb_unpowergate_partitions(tegra);
+ if (err)
+ goto disable_clks;
+
+ if (wakeup)
+ tegra_xhci_disable_phy_wake(tegra);
+
+ for (i = 0; i < tegra->num_phys; i++) {
+ if (!tegra->phys[i])
+ continue;
+
+ if (!wakeup)
+ phy_init(tegra->phys[i]);
+
+ phy_power_on(tegra->phys[i]);
}
tegra_xusb_config(tegra);
@@ -1808,31 +2066,79 @@ static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool wakeup)
goto disable_phy;
}
- err = xhci_resume(xhci, true);
+ if (wakeup)
+ tegra_xhci_disable_phy_sleepwalk(tegra);
+
+ err = xhci_resume(xhci, 0);
if (err < 0) {
dev_err(tegra->dev, "failed to resume XHCI: %d\n", err);
goto disable_phy;
}
- return 0;
+ usbcmd = readl(&xhci->op_regs->command);
+ usbcmd |= CMD_EIE;
+ writel(usbcmd, &xhci->op_regs->command);
+
+ goto out;
disable_phy:
- tegra_xusb_phy_disable(tegra);
-disable_clk:
+ for (i = 0; i < tegra->num_phys; i++) {
+ if (!tegra->phys[i])
+ continue;
+
+ phy_power_off(tegra->phys[i]);
+ if (!wakeup)
+ phy_exit(tegra->phys[i]);
+ }
+ tegra_xusb_powergate_partitions(tegra);
+disable_clks:
tegra_xusb_clk_disable(tegra);
+out:
+ if (!err)
+ dev_dbg(dev, "exiting ELPG done\n");
+ else
+ dev_dbg(dev, "exiting ELPG failed\n");
+
return err;
}
static int tegra_xusb_suspend(struct device *dev)
{
struct tegra_xusb *tegra = dev_get_drvdata(dev);
- bool wakeup = device_may_wakeup(dev);
int err;
synchronize_irq(tegra->mbox_irq);
mutex_lock(&tegra->lock);
- err = tegra_xusb_enter_elpg(tegra, wakeup);
+
+ if (pm_runtime_suspended(dev)) {
+ err = tegra_xusb_exit_elpg(tegra, true);
+ if (err < 0)
+ goto out;
+ }
+
+ err = tegra_xusb_enter_elpg(tegra, false);
+ if (err < 0) {
+ if (pm_runtime_suspended(dev)) {
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ }
+
+ goto out;
+ }
+
+out:
+ if (!err) {
+ tegra->suspended = true;
+ pm_runtime_disable(dev);
+
+ if (device_may_wakeup(dev)) {
+ if (enable_irq_wake(tegra->padctl_irq))
+ dev_err(dev, "failed to enable padctl wakes\n");
+ }
+ }
+
mutex_unlock(&tegra->lock);
return err;
@@ -1841,11 +2147,56 @@ static int tegra_xusb_suspend(struct device *dev)
static int tegra_xusb_resume(struct device *dev)
{
struct tegra_xusb *tegra = dev_get_drvdata(dev);
- bool wakeup = device_may_wakeup(dev);
int err;
mutex_lock(&tegra->lock);
- err = tegra_xusb_exit_elpg(tegra, wakeup);
+
+ if (!tegra->suspended) {
+ mutex_unlock(&tegra->lock);
+ return 0;
+ }
+
+ err = tegra_xusb_exit_elpg(tegra, false);
+ if (err < 0) {
+ mutex_unlock(&tegra->lock);
+ return err;
+ }
+
+ if (device_may_wakeup(dev)) {
+ if (disable_irq_wake(tegra->padctl_irq))
+ dev_err(dev, "failed to disable padctl wakes\n");
+ }
+ tegra->suspended = false;
+ mutex_unlock(&tegra->lock);
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int tegra_xusb_runtime_suspend(struct device *dev)
+{
+ struct tegra_xusb *tegra = dev_get_drvdata(dev);
+ int ret;
+
+ synchronize_irq(tegra->mbox_irq);
+ mutex_lock(&tegra->lock);
+ ret = tegra_xusb_enter_elpg(tegra, true);
+ mutex_unlock(&tegra->lock);
+
+ return ret;
+}
+
+static int tegra_xusb_runtime_resume(struct device *dev)
+{
+ struct tegra_xusb *tegra = dev_get_drvdata(dev);
+ int err;
+
+ mutex_lock(&tegra->lock);
+ err = tegra_xusb_exit_elpg(tegra, true);
mutex_unlock(&tegra->lock);
return err;
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 27283654ca08..3618070eba78 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1361,12 +1361,17 @@ static void xhci_unmap_temp_buf(struct usb_hcd *hcd, struct urb *urb)
urb->transfer_buffer_length,
dir);
- if (usb_urb_dir_in(urb))
+ if (usb_urb_dir_in(urb)) {
len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs,
urb->transfer_buffer,
buf_len,
0);
-
+ if (len != buf_len) {
+ xhci_dbg(hcd_to_xhci(hcd),
+ "Copy from tmp buf to urb sg list failed\n");
+ urb->actual_length = len;
+ }
+ }
urb->transfer_flags &= ~URB_DMA_MAP_SINGLE;
kfree(urb->transfer_buffer);
urb->transfer_buffer = NULL;
@@ -4840,7 +4845,6 @@ static int xhci_update_timeout_for_interface(struct xhci_hcd *xhci,
if (xhci_update_timeout_for_endpoint(xhci, udev,
&alt->endpoint[j].desc, state, timeout))
return -E2BIG;
- continue;
}
return 0;
}
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index e417f5ce13d1..3c7d281672ae 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1526,6 +1526,12 @@ static inline const char *xhci_trb_type_string(u8 type)
#define TRB_BUFF_LEN_UP_TO_BOUNDARY(addr) (TRB_MAX_BUFF_SIZE - \
(addr & (TRB_MAX_BUFF_SIZE - 1)))
#define MAX_SOFT_RETRY 3
+/*
+ * Limits of consecutive isoc trbs that can Block Event Interrupt (BEI) if
+ * XHCI_AVOID_BEI quirk is in use.
+ */
+#define AVOID_BEI_INTERVAL_MIN 8
+#define AVOID_BEI_INTERVAL_MAX 32
struct xhci_segment {
union xhci_trb *trbs;
@@ -1663,10 +1669,6 @@ struct urb_priv {
* meaning 64 ring segments.
* Initial allocated size of the ERST, in number of entries */
#define ERST_NUM_SEGS 1
-/* Initial allocated size of the ERST, in number of entries */
-#define ERST_SIZE 64
-/* Initial number of event segment rings allocated */
-#define ERST_ENTRIES 1
/* Poll every 60 seconds */
#define POLL_TIMEOUT 60
/* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */
@@ -1772,6 +1774,7 @@ struct xhci_hcd {
u8 isoc_threshold;
/* imod_interval in ns (I * 250ns) */
u32 imod_interval;
+ u32 isoc_bei_interval;
int event_ring_max;
/* 4KB min, 128MB max */
int page_size;
diff --git a/drivers/usb/isp1760/Kconfig b/drivers/usb/isp1760/Kconfig
index b1022cc490a2..2ed2b73291d1 100644
--- a/drivers/usb/isp1760/Kconfig
+++ b/drivers/usb/isp1760/Kconfig
@@ -1,10 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
config USB_ISP1760
- tristate "NXP ISP 1760/1761 support"
+ tristate "NXP ISP 1760/1761/1763 support"
depends on USB || USB_GADGET
+ select REGMAP_MMIO
help
- Say Y or M here if your system as an ISP1760 USB host controller
+ Say Y or M here if your system as an ISP1760/1763 USB host controller
or an ISP1761 USB dual-role controller.
This driver does not support isochronous transfers or OTG.
diff --git a/drivers/usb/isp1760/isp1760-core.c b/drivers/usb/isp1760/isp1760-core.c
index fdeb4cf97cc5..ff07e2890692 100644
--- a/drivers/usb/isp1760/isp1760-core.c
+++ b/drivers/usb/isp1760/isp1760-core.c
@@ -2,12 +2,14 @@
/*
* Driver for the NXP ISP1760 chip
*
+ * Copyright 2021 Linaro, Rui Miguel Silva
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Rui Miguel Silva <rui.silva@linaro.org>
*/
#include <linux/delay.h>
@@ -15,6 +17,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/usb.h>
@@ -23,10 +26,10 @@
#include "isp1760-regs.h"
#include "isp1760-udc.h"
-static void isp1760_init_core(struct isp1760_device *isp)
+static int isp1760_init_core(struct isp1760_device *isp)
{
- u32 otgctrl;
- u32 hwmode;
+ struct isp1760_hcd *hcd = &isp->hcd;
+ struct isp1760_udc *udc = &isp->udc;
/* Low-level chip reset */
if (isp->rst_gpio) {
@@ -39,24 +42,29 @@ static void isp1760_init_core(struct isp1760_device *isp)
* Reset the host controller, including the CPU interface
* configuration.
*/
- isp1760_write32(isp->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
+ isp1760_field_set(hcd->fields, SW_RESET_RESET_ALL);
msleep(100);
/* Setup HW Mode Control: This assumes a level active-low interrupt */
- hwmode = HW_DATA_BUS_32BIT;
+ if ((isp->devflags & ISP1760_FLAG_ANALOG_OC) && hcd->is_isp1763) {
+ dev_err(isp->dev, "isp1763 analog overcurrent not available\n");
+ return -EINVAL;
+ }
if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16)
- hwmode &= ~HW_DATA_BUS_32BIT;
+ isp1760_field_clear(hcd->fields, HW_DATA_BUS_WIDTH);
+ if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_8)
+ isp1760_field_set(hcd->fields, HW_DATA_BUS_WIDTH);
if (isp->devflags & ISP1760_FLAG_ANALOG_OC)
- hwmode |= HW_ANA_DIGI_OC;
+ isp1760_field_set(hcd->fields, HW_ANA_DIGI_OC);
if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH)
- hwmode |= HW_DACK_POL_HIGH;
+ isp1760_field_set(hcd->fields, HW_DACK_POL_HIGH);
if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
- hwmode |= HW_DREQ_POL_HIGH;
+ isp1760_field_set(hcd->fields, HW_DREQ_POL_HIGH);
if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH)
- hwmode |= HW_INTR_HIGH_ACT;
+ isp1760_field_set(hcd->fields, HW_INTR_HIGH_ACT);
if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
- hwmode |= HW_INTR_EDGE_TRIG;
+ isp1760_field_set(hcd->fields, HW_INTR_EDGE_TRIG);
/*
* The ISP1761 has a dedicated DC IRQ line but supports sharing the HC
@@ -65,59 +73,425 @@ static void isp1760_init_core(struct isp1760_device *isp)
* spurious interrupts during HCD registration.
*/
if (isp->devflags & ISP1760_FLAG_ISP1761) {
- isp1760_write32(isp->regs, DC_MODE, 0);
- hwmode |= HW_COMN_IRQ;
+ isp1760_reg_write(udc->regs, ISP176x_DC_MODE, 0);
+ isp1760_field_set(hcd->fields, HW_COMN_IRQ);
}
/*
- * We have to set this first in case we're in 16-bit mode.
- * Write it twice to ensure correct upper bits if switching
- * to 16-bit mode.
- */
- isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
- isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
-
- /*
* PORT 1 Control register of the ISP1760 is the OTG control register
* on ISP1761.
*
* TODO: Really support OTG. For now we configure port 1 in device mode
- * when OTG is requested.
*/
- if ((isp->devflags & ISP1760_FLAG_ISP1761) &&
- (isp->devflags & ISP1760_FLAG_OTG_EN))
- otgctrl = ((HW_DM_PULLDOWN | HW_DP_PULLDOWN) << 16)
- | HW_OTG_DISABLE;
- else
- otgctrl = (HW_SW_SEL_HC_DC << 16)
- | (HW_VBUS_DRV | HW_SEL_CP_EXT);
-
- isp1760_write32(isp->regs, HC_PORT1_CTRL, otgctrl);
+ if (((isp->devflags & ISP1760_FLAG_ISP1761) ||
+ (isp->devflags & ISP1760_FLAG_ISP1763)) &&
+ (isp->devflags & ISP1760_FLAG_PERIPHERAL_EN)) {
+ isp1760_field_set(hcd->fields, HW_DM_PULLDOWN);
+ isp1760_field_set(hcd->fields, HW_DP_PULLDOWN);
+ isp1760_field_set(hcd->fields, HW_OTG_DISABLE);
+ } else {
+ isp1760_field_set(hcd->fields, HW_SW_SEL_HC_DC);
+ isp1760_field_set(hcd->fields, HW_VBUS_DRV);
+ isp1760_field_set(hcd->fields, HW_SEL_CP_EXT);
+ }
- dev_info(isp->dev, "bus width: %u, oc: %s\n",
+ dev_info(isp->dev, "%s bus width: %u, oc: %s\n",
+ hcd->is_isp1763 ? "isp1763" : "isp1760",
+ isp->devflags & ISP1760_FLAG_BUS_WIDTH_8 ? 8 :
isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32,
+ hcd->is_isp1763 ? "not available" :
isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital");
+
+ return 0;
}
void isp1760_set_pullup(struct isp1760_device *isp, bool enable)
{
- isp1760_write32(isp->regs, HW_OTG_CTRL_SET,
- enable ? HW_DP_PULLUP : HW_DP_PULLUP << 16);
+ struct isp1760_udc *udc = &isp->udc;
+
+ if (enable)
+ isp1760_field_set(udc->fields, HW_DP_PULLUP);
+ else
+ isp1760_field_set(udc->fields, HW_DP_PULLUP_CLEAR);
}
+/*
+ * ISP1760/61:
+ *
+ * 60kb divided in:
+ * - 32 blocks @ 256 bytes
+ * - 20 blocks @ 1024 bytes
+ * - 4 blocks @ 8192 bytes
+ */
+static const struct isp1760_memory_layout isp176x_memory_conf = {
+ .blocks[0] = 32,
+ .blocks_size[0] = 256,
+ .blocks[1] = 20,
+ .blocks_size[1] = 1024,
+ .blocks[2] = 4,
+ .blocks_size[2] = 8192,
+
+ .slot_num = 32,
+ .payload_blocks = 32 + 20 + 4,
+ .payload_area_size = 0xf000,
+};
+
+/*
+ * ISP1763:
+ *
+ * 20kb divided in:
+ * - 8 blocks @ 256 bytes
+ * - 2 blocks @ 1024 bytes
+ * - 4 blocks @ 4096 bytes
+ */
+static const struct isp1760_memory_layout isp1763_memory_conf = {
+ .blocks[0] = 8,
+ .blocks_size[0] = 256,
+ .blocks[1] = 2,
+ .blocks_size[1] = 1024,
+ .blocks[2] = 4,
+ .blocks_size[2] = 4096,
+
+ .slot_num = 16,
+ .payload_blocks = 8 + 2 + 4,
+ .payload_area_size = 0x5000,
+};
+
+static const struct regmap_range isp176x_hc_volatile_ranges[] = {
+ regmap_reg_range(ISP176x_HC_USBCMD, ISP176x_HC_ATL_PTD_LASTPTD),
+ regmap_reg_range(ISP176x_HC_BUFFER_STATUS, ISP176x_HC_MEMORY),
+ regmap_reg_range(ISP176x_HC_INTERRUPT, ISP176x_HC_OTG_CTRL_CLEAR),
+};
+
+static const struct regmap_access_table isp176x_hc_volatile_table = {
+ .yes_ranges = isp176x_hc_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(isp176x_hc_volatile_ranges),
+};
+
+static const struct regmap_config isp1760_hc_regmap_conf = {
+ .name = "isp1760-hc",
+ .reg_bits = 16,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .fast_io = true,
+ .max_register = ISP176x_HC_OTG_CTRL_CLEAR,
+ .volatile_table = &isp176x_hc_volatile_table,
+};
+
+static const struct reg_field isp1760_hc_reg_fields[] = {
+ [HCS_PPC] = REG_FIELD(ISP176x_HC_HCSPARAMS, 4, 4),
+ [HCS_N_PORTS] = REG_FIELD(ISP176x_HC_HCSPARAMS, 0, 3),
+ [HCC_ISOC_CACHE] = REG_FIELD(ISP176x_HC_HCCPARAMS, 7, 7),
+ [HCC_ISOC_THRES] = REG_FIELD(ISP176x_HC_HCCPARAMS, 4, 6),
+ [CMD_LRESET] = REG_FIELD(ISP176x_HC_USBCMD, 7, 7),
+ [CMD_RESET] = REG_FIELD(ISP176x_HC_USBCMD, 1, 1),
+ [CMD_RUN] = REG_FIELD(ISP176x_HC_USBCMD, 0, 0),
+ [STS_PCD] = REG_FIELD(ISP176x_HC_USBSTS, 2, 2),
+ [HC_FRINDEX] = REG_FIELD(ISP176x_HC_FRINDEX, 0, 13),
+ [FLAG_CF] = REG_FIELD(ISP176x_HC_CONFIGFLAG, 0, 0),
+ [HC_ISO_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_ISO_PTD_DONEMAP, 0, 31),
+ [HC_ISO_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_ISO_PTD_SKIPMAP, 0, 31),
+ [HC_ISO_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_ISO_PTD_LASTPTD, 0, 31),
+ [HC_INT_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_INT_PTD_DONEMAP, 0, 31),
+ [HC_INT_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_INT_PTD_SKIPMAP, 0, 31),
+ [HC_INT_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_INT_PTD_LASTPTD, 0, 31),
+ [HC_ATL_PTD_DONEMAP] = REG_FIELD(ISP176x_HC_ATL_PTD_DONEMAP, 0, 31),
+ [HC_ATL_PTD_SKIPMAP] = REG_FIELD(ISP176x_HC_ATL_PTD_SKIPMAP, 0, 31),
+ [HC_ATL_PTD_LASTPTD] = REG_FIELD(ISP176x_HC_ATL_PTD_LASTPTD, 0, 31),
+ [PORT_OWNER] = REG_FIELD(ISP176x_HC_PORTSC1, 13, 13),
+ [PORT_POWER] = REG_FIELD(ISP176x_HC_PORTSC1, 12, 12),
+ [PORT_LSTATUS] = REG_FIELD(ISP176x_HC_PORTSC1, 10, 11),
+ [PORT_RESET] = REG_FIELD(ISP176x_HC_PORTSC1, 8, 8),
+ [PORT_SUSPEND] = REG_FIELD(ISP176x_HC_PORTSC1, 7, 7),
+ [PORT_RESUME] = REG_FIELD(ISP176x_HC_PORTSC1, 6, 6),
+ [PORT_PE] = REG_FIELD(ISP176x_HC_PORTSC1, 2, 2),
+ [PORT_CSC] = REG_FIELD(ISP176x_HC_PORTSC1, 1, 1),
+ [PORT_CONNECT] = REG_FIELD(ISP176x_HC_PORTSC1, 0, 0),
+ [ALL_ATX_RESET] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 31, 31),
+ [HW_ANA_DIGI_OC] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 15, 15),
+ [HW_COMN_IRQ] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 10, 10),
+ [HW_DATA_BUS_WIDTH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 8, 8),
+ [HW_DACK_POL_HIGH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 6, 6),
+ [HW_DREQ_POL_HIGH] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 5, 5),
+ [HW_INTR_HIGH_ACT] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 2, 2),
+ [HW_INTR_EDGE_TRIG] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 1, 1),
+ [HW_GLOBAL_INTR_EN] = REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 0, 0),
+ [HC_CHIP_REV] = REG_FIELD(ISP176x_HC_CHIP_ID, 16, 31),
+ [HC_CHIP_ID_HIGH] = REG_FIELD(ISP176x_HC_CHIP_ID, 8, 15),
+ [HC_CHIP_ID_LOW] = REG_FIELD(ISP176x_HC_CHIP_ID, 0, 7),
+ [HC_SCRATCH] = REG_FIELD(ISP176x_HC_SCRATCH, 0, 31),
+ [SW_RESET_RESET_ALL] = REG_FIELD(ISP176x_HC_RESET, 0, 0),
+ [ISO_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 2, 2),
+ [INT_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 1, 1),
+ [ATL_BUF_FILL] = REG_FIELD(ISP176x_HC_BUFFER_STATUS, 0, 0),
+ [MEM_BANK_SEL] = REG_FIELD(ISP176x_HC_MEMORY, 16, 17),
+ [MEM_START_ADDR] = REG_FIELD(ISP176x_HC_MEMORY, 0, 15),
+ [HC_INTERRUPT] = REG_FIELD(ISP176x_HC_INTERRUPT, 0, 9),
+ [HC_ATL_IRQ_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 8, 8),
+ [HC_INT_IRQ_ENABLE] = REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 7, 7),
+ [HC_ISO_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_ISO_IRQ_MASK_OR, 0, 31),
+ [HC_INT_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_INT_IRQ_MASK_OR, 0, 31),
+ [HC_ATL_IRQ_MASK_OR] = REG_FIELD(ISP176x_HC_ATL_IRQ_MASK_OR, 0, 31),
+ [HC_ISO_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_ISO_IRQ_MASK_AND, 0, 31),
+ [HC_INT_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_INT_IRQ_MASK_AND, 0, 31),
+ [HC_ATL_IRQ_MASK_AND] = REG_FIELD(ISP176x_HC_ATL_IRQ_MASK_AND, 0, 31),
+ [HW_OTG_DISABLE] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 10, 10),
+ [HW_SW_SEL_HC_DC] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 7, 7),
+ [HW_VBUS_DRV] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 4, 4),
+ [HW_SEL_CP_EXT] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 3, 3),
+ [HW_DM_PULLDOWN] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 2, 2),
+ [HW_DP_PULLDOWN] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 1, 1),
+ [HW_DP_PULLUP] = REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 0, 0),
+ [HW_OTG_DISABLE_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 10, 10),
+ [HW_SW_SEL_HC_DC_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 7, 7),
+ [HW_VBUS_DRV_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 4, 4),
+ [HW_SEL_CP_EXT_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 3, 3),
+ [HW_DM_PULLDOWN_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 2, 2),
+ [HW_DP_PULLDOWN_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 1, 1),
+ [HW_DP_PULLUP_CLEAR] = REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 0, 0),
+};
+
+static const struct reg_field isp1763_hc_reg_fields[] = {
+ [CMD_LRESET] = REG_FIELD(ISP1763_HC_USBCMD, 7, 7),
+ [CMD_RESET] = REG_FIELD(ISP1763_HC_USBCMD, 1, 1),
+ [CMD_RUN] = REG_FIELD(ISP1763_HC_USBCMD, 0, 0),
+ [STS_PCD] = REG_FIELD(ISP1763_HC_USBSTS, 2, 2),
+ [HC_FRINDEX] = REG_FIELD(ISP1763_HC_FRINDEX, 0, 13),
+ [FLAG_CF] = REG_FIELD(ISP1763_HC_CONFIGFLAG, 0, 0),
+ [HC_ISO_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_ISO_PTD_DONEMAP, 0, 15),
+ [HC_ISO_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_ISO_PTD_SKIPMAP, 0, 15),
+ [HC_ISO_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_ISO_PTD_LASTPTD, 0, 15),
+ [HC_INT_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_INT_PTD_DONEMAP, 0, 15),
+ [HC_INT_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_INT_PTD_SKIPMAP, 0, 15),
+ [HC_INT_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_INT_PTD_LASTPTD, 0, 15),
+ [HC_ATL_PTD_DONEMAP] = REG_FIELD(ISP1763_HC_ATL_PTD_DONEMAP, 0, 15),
+ [HC_ATL_PTD_SKIPMAP] = REG_FIELD(ISP1763_HC_ATL_PTD_SKIPMAP, 0, 15),
+ [HC_ATL_PTD_LASTPTD] = REG_FIELD(ISP1763_HC_ATL_PTD_LASTPTD, 0, 15),
+ [PORT_OWNER] = REG_FIELD(ISP1763_HC_PORTSC1, 13, 13),
+ [PORT_POWER] = REG_FIELD(ISP1763_HC_PORTSC1, 12, 12),
+ [PORT_LSTATUS] = REG_FIELD(ISP1763_HC_PORTSC1, 10, 11),
+ [PORT_RESET] = REG_FIELD(ISP1763_HC_PORTSC1, 8, 8),
+ [PORT_SUSPEND] = REG_FIELD(ISP1763_HC_PORTSC1, 7, 7),
+ [PORT_RESUME] = REG_FIELD(ISP1763_HC_PORTSC1, 6, 6),
+ [PORT_PE] = REG_FIELD(ISP1763_HC_PORTSC1, 2, 2),
+ [PORT_CSC] = REG_FIELD(ISP1763_HC_PORTSC1, 1, 1),
+ [PORT_CONNECT] = REG_FIELD(ISP1763_HC_PORTSC1, 0, 0),
+ [HW_DATA_BUS_WIDTH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 4, 4),
+ [HW_DACK_POL_HIGH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 6, 6),
+ [HW_DREQ_POL_HIGH] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 5, 5),
+ [HW_INTF_LOCK] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 3, 3),
+ [HW_INTR_HIGH_ACT] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 2, 2),
+ [HW_INTR_EDGE_TRIG] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 1, 1),
+ [HW_GLOBAL_INTR_EN] = REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 0, 0),
+ [SW_RESET_RESET_ATX] = REG_FIELD(ISP1763_HC_RESET, 3, 3),
+ [SW_RESET_RESET_ALL] = REG_FIELD(ISP1763_HC_RESET, 0, 0),
+ [HC_CHIP_ID_HIGH] = REG_FIELD(ISP1763_HC_CHIP_ID, 0, 15),
+ [HC_CHIP_ID_LOW] = REG_FIELD(ISP1763_HC_CHIP_REV, 8, 15),
+ [HC_CHIP_REV] = REG_FIELD(ISP1763_HC_CHIP_REV, 0, 7),
+ [HC_SCRATCH] = REG_FIELD(ISP1763_HC_SCRATCH, 0, 15),
+ [ISO_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 2, 2),
+ [INT_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 1, 1),
+ [ATL_BUF_FILL] = REG_FIELD(ISP1763_HC_BUFFER_STATUS, 0, 0),
+ [MEM_START_ADDR] = REG_FIELD(ISP1763_HC_MEMORY, 0, 15),
+ [HC_DATA] = REG_FIELD(ISP1763_HC_DATA, 0, 15),
+ [HC_INTERRUPT] = REG_FIELD(ISP1763_HC_INTERRUPT, 0, 10),
+ [HC_ATL_IRQ_ENABLE] = REG_FIELD(ISP1763_HC_INTERRUPT_ENABLE, 8, 8),
+ [HC_INT_IRQ_ENABLE] = REG_FIELD(ISP1763_HC_INTERRUPT_ENABLE, 7, 7),
+ [HC_ISO_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_ISO_IRQ_MASK_OR, 0, 15),
+ [HC_INT_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_INT_IRQ_MASK_OR, 0, 15),
+ [HC_ATL_IRQ_MASK_OR] = REG_FIELD(ISP1763_HC_ATL_IRQ_MASK_OR, 0, 15),
+ [HC_ISO_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_ISO_IRQ_MASK_AND, 0, 15),
+ [HC_INT_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_INT_IRQ_MASK_AND, 0, 15),
+ [HC_ATL_IRQ_MASK_AND] = REG_FIELD(ISP1763_HC_ATL_IRQ_MASK_AND, 0, 15),
+ [HW_HC_2_DIS] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 15, 15),
+ [HW_OTG_DISABLE] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 10, 10),
+ [HW_SW_SEL_HC_DC] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 7, 7),
+ [HW_VBUS_DRV] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 4, 4),
+ [HW_SEL_CP_EXT] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 3, 3),
+ [HW_DM_PULLDOWN] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 2, 2),
+ [HW_DP_PULLDOWN] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 1, 1),
+ [HW_DP_PULLUP] = REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 0, 0),
+ [HW_HC_2_DIS_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 15, 15),
+ [HW_OTG_DISABLE_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 10, 10),
+ [HW_SW_SEL_HC_DC_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 7, 7),
+ [HW_VBUS_DRV_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 4, 4),
+ [HW_SEL_CP_EXT_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 3, 3),
+ [HW_DM_PULLDOWN_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 2, 2),
+ [HW_DP_PULLDOWN_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 1, 1),
+ [HW_DP_PULLUP_CLEAR] = REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 0, 0),
+};
+
+static const struct regmap_range isp1763_hc_volatile_ranges[] = {
+ regmap_reg_range(ISP1763_HC_USBCMD, ISP1763_HC_ATL_PTD_LASTPTD),
+ regmap_reg_range(ISP1763_HC_BUFFER_STATUS, ISP1763_HC_DATA),
+ regmap_reg_range(ISP1763_HC_INTERRUPT, ISP1763_HC_OTG_CTRL_CLEAR),
+};
+
+static const struct regmap_access_table isp1763_hc_volatile_table = {
+ .yes_ranges = isp1763_hc_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(isp1763_hc_volatile_ranges),
+};
+
+static const struct regmap_config isp1763_hc_regmap_conf = {
+ .name = "isp1763-hc",
+ .reg_bits = 8,
+ .reg_stride = 2,
+ .val_bits = 16,
+ .fast_io = true,
+ .max_register = ISP1763_HC_OTG_CTRL_CLEAR,
+ .volatile_table = &isp1763_hc_volatile_table,
+};
+
+static const struct regmap_range isp176x_dc_volatile_ranges[] = {
+ regmap_reg_range(ISP176x_DC_EPMAXPKTSZ, ISP176x_DC_EPTYPE),
+ regmap_reg_range(ISP176x_DC_BUFLEN, ISP176x_DC_EPINDEX),
+};
+
+static const struct regmap_access_table isp176x_dc_volatile_table = {
+ .yes_ranges = isp176x_dc_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(isp176x_dc_volatile_ranges),
+};
+
+static const struct regmap_config isp1761_dc_regmap_conf = {
+ .name = "isp1761-dc",
+ .reg_bits = 16,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .fast_io = true,
+ .max_register = ISP176x_DC_TESTMODE,
+ .volatile_table = &isp176x_dc_volatile_table,
+};
+
+static const struct reg_field isp1761_dc_reg_fields[] = {
+ [DC_DEVEN] = REG_FIELD(ISP176x_DC_ADDRESS, 7, 7),
+ [DC_DEVADDR] = REG_FIELD(ISP176x_DC_ADDRESS, 0, 6),
+ [DC_VBUSSTAT] = REG_FIELD(ISP176x_DC_MODE, 8, 8),
+ [DC_SFRESET] = REG_FIELD(ISP176x_DC_MODE, 4, 4),
+ [DC_GLINTENA] = REG_FIELD(ISP176x_DC_MODE, 3, 3),
+ [DC_CDBGMOD_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 6, 6),
+ [DC_DDBGMODIN_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 4, 4),
+ [DC_DDBGMODOUT_ACK] = REG_FIELD(ISP176x_DC_INTCONF, 2, 2),
+ [DC_INTPOL] = REG_FIELD(ISP176x_DC_INTCONF, 0, 0),
+ [DC_IEPRXTX_7] = REG_FIELD(ISP176x_DC_INTENABLE, 25, 25),
+ [DC_IEPRXTX_6] = REG_FIELD(ISP176x_DC_INTENABLE, 23, 23),
+ [DC_IEPRXTX_5] = REG_FIELD(ISP176x_DC_INTENABLE, 21, 21),
+ [DC_IEPRXTX_4] = REG_FIELD(ISP176x_DC_INTENABLE, 19, 19),
+ [DC_IEPRXTX_3] = REG_FIELD(ISP176x_DC_INTENABLE, 17, 17),
+ [DC_IEPRXTX_2] = REG_FIELD(ISP176x_DC_INTENABLE, 15, 15),
+ [DC_IEPRXTX_1] = REG_FIELD(ISP176x_DC_INTENABLE, 13, 13),
+ [DC_IEPRXTX_0] = REG_FIELD(ISP176x_DC_INTENABLE, 11, 11),
+ [DC_IEP0SETUP] = REG_FIELD(ISP176x_DC_INTENABLE, 8, 8),
+ [DC_IEVBUS] = REG_FIELD(ISP176x_DC_INTENABLE, 7, 7),
+ [DC_IEHS_STA] = REG_FIELD(ISP176x_DC_INTENABLE, 5, 5),
+ [DC_IERESM] = REG_FIELD(ISP176x_DC_INTENABLE, 4, 4),
+ [DC_IESUSP] = REG_FIELD(ISP176x_DC_INTENABLE, 3, 3),
+ [DC_IEBRST] = REG_FIELD(ISP176x_DC_INTENABLE, 0, 0),
+ [DC_EP0SETUP] = REG_FIELD(ISP176x_DC_EPINDEX, 5, 5),
+ [DC_ENDPIDX] = REG_FIELD(ISP176x_DC_EPINDEX, 1, 4),
+ [DC_EPDIR] = REG_FIELD(ISP176x_DC_EPINDEX, 0, 0),
+ [DC_CLBUF] = REG_FIELD(ISP176x_DC_CTRLFUNC, 4, 4),
+ [DC_VENDP] = REG_FIELD(ISP176x_DC_CTRLFUNC, 3, 3),
+ [DC_DSEN] = REG_FIELD(ISP176x_DC_CTRLFUNC, 2, 2),
+ [DC_STATUS] = REG_FIELD(ISP176x_DC_CTRLFUNC, 1, 1),
+ [DC_STALL] = REG_FIELD(ISP176x_DC_CTRLFUNC, 0, 0),
+ [DC_BUFLEN] = REG_FIELD(ISP176x_DC_BUFLEN, 0, 15),
+ [DC_FFOSZ] = REG_FIELD(ISP176x_DC_EPMAXPKTSZ, 0, 10),
+ [DC_EPENABLE] = REG_FIELD(ISP176x_DC_EPTYPE, 3, 3),
+ [DC_ENDPTYP] = REG_FIELD(ISP176x_DC_EPTYPE, 0, 1),
+ [DC_UFRAMENUM] = REG_FIELD(ISP176x_DC_FRAMENUM, 11, 13),
+ [DC_FRAMENUM] = REG_FIELD(ISP176x_DC_FRAMENUM, 0, 10),
+ [DC_CHIP_ID_HIGH] = REG_FIELD(ISP176x_DC_CHIPID, 16, 31),
+ [DC_CHIP_ID_LOW] = REG_FIELD(ISP176x_DC_CHIPID, 0, 15),
+ [DC_SCRATCH] = REG_FIELD(ISP176x_DC_SCRATCH, 0, 15),
+};
+
+static const struct regmap_range isp1763_dc_volatile_ranges[] = {
+ regmap_reg_range(ISP1763_DC_EPMAXPKTSZ, ISP1763_DC_EPTYPE),
+ regmap_reg_range(ISP1763_DC_BUFLEN, ISP1763_DC_EPINDEX),
+};
+
+static const struct regmap_access_table isp1763_dc_volatile_table = {
+ .yes_ranges = isp1763_dc_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(isp1763_dc_volatile_ranges),
+};
+
+static const struct reg_field isp1763_dc_reg_fields[] = {
+ [DC_DEVEN] = REG_FIELD(ISP1763_DC_ADDRESS, 7, 7),
+ [DC_DEVADDR] = REG_FIELD(ISP1763_DC_ADDRESS, 0, 6),
+ [DC_VBUSSTAT] = REG_FIELD(ISP1763_DC_MODE, 8, 8),
+ [DC_SFRESET] = REG_FIELD(ISP1763_DC_MODE, 4, 4),
+ [DC_GLINTENA] = REG_FIELD(ISP1763_DC_MODE, 3, 3),
+ [DC_CDBGMOD_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 6, 6),
+ [DC_DDBGMODIN_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 4, 4),
+ [DC_DDBGMODOUT_ACK] = REG_FIELD(ISP1763_DC_INTCONF, 2, 2),
+ [DC_INTPOL] = REG_FIELD(ISP1763_DC_INTCONF, 0, 0),
+ [DC_IEPRXTX_7] = REG_FIELD(ISP1763_DC_INTENABLE, 25, 25),
+ [DC_IEPRXTX_6] = REG_FIELD(ISP1763_DC_INTENABLE, 23, 23),
+ [DC_IEPRXTX_5] = REG_FIELD(ISP1763_DC_INTENABLE, 21, 21),
+ [DC_IEPRXTX_4] = REG_FIELD(ISP1763_DC_INTENABLE, 19, 19),
+ [DC_IEPRXTX_3] = REG_FIELD(ISP1763_DC_INTENABLE, 17, 17),
+ [DC_IEPRXTX_2] = REG_FIELD(ISP1763_DC_INTENABLE, 15, 15),
+ [DC_IEPRXTX_1] = REG_FIELD(ISP1763_DC_INTENABLE, 13, 13),
+ [DC_IEPRXTX_0] = REG_FIELD(ISP1763_DC_INTENABLE, 11, 11),
+ [DC_IEP0SETUP] = REG_FIELD(ISP1763_DC_INTENABLE, 8, 8),
+ [DC_IEVBUS] = REG_FIELD(ISP1763_DC_INTENABLE, 7, 7),
+ [DC_IEHS_STA] = REG_FIELD(ISP1763_DC_INTENABLE, 5, 5),
+ [DC_IERESM] = REG_FIELD(ISP1763_DC_INTENABLE, 4, 4),
+ [DC_IESUSP] = REG_FIELD(ISP1763_DC_INTENABLE, 3, 3),
+ [DC_IEBRST] = REG_FIELD(ISP1763_DC_INTENABLE, 0, 0),
+ [DC_EP0SETUP] = REG_FIELD(ISP1763_DC_EPINDEX, 5, 5),
+ [DC_ENDPIDX] = REG_FIELD(ISP1763_DC_EPINDEX, 1, 4),
+ [DC_EPDIR] = REG_FIELD(ISP1763_DC_EPINDEX, 0, 0),
+ [DC_CLBUF] = REG_FIELD(ISP1763_DC_CTRLFUNC, 4, 4),
+ [DC_VENDP] = REG_FIELD(ISP1763_DC_CTRLFUNC, 3, 3),
+ [DC_DSEN] = REG_FIELD(ISP1763_DC_CTRLFUNC, 2, 2),
+ [DC_STATUS] = REG_FIELD(ISP1763_DC_CTRLFUNC, 1, 1),
+ [DC_STALL] = REG_FIELD(ISP1763_DC_CTRLFUNC, 0, 0),
+ [DC_BUFLEN] = REG_FIELD(ISP1763_DC_BUFLEN, 0, 15),
+ [DC_FFOSZ] = REG_FIELD(ISP1763_DC_EPMAXPKTSZ, 0, 10),
+ [DC_EPENABLE] = REG_FIELD(ISP1763_DC_EPTYPE, 3, 3),
+ [DC_ENDPTYP] = REG_FIELD(ISP1763_DC_EPTYPE, 0, 1),
+ [DC_UFRAMENUM] = REG_FIELD(ISP1763_DC_FRAMENUM, 11, 13),
+ [DC_FRAMENUM] = REG_FIELD(ISP1763_DC_FRAMENUM, 0, 10),
+ [DC_CHIP_ID_HIGH] = REG_FIELD(ISP1763_DC_CHIPID_HIGH, 0, 15),
+ [DC_CHIP_ID_LOW] = REG_FIELD(ISP1763_DC_CHIPID_LOW, 0, 15),
+ [DC_SCRATCH] = REG_FIELD(ISP1763_DC_SCRATCH, 0, 15),
+};
+
+static const struct regmap_config isp1763_dc_regmap_conf = {
+ .name = "isp1763-dc",
+ .reg_bits = 8,
+ .reg_stride = 2,
+ .val_bits = 16,
+ .fast_io = true,
+ .max_register = ISP1763_DC_TESTMODE,
+ .volatile_table = &isp1763_dc_volatile_table,
+};
+
int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
struct device *dev, unsigned int devflags)
{
+ const struct regmap_config *hc_regmap;
+ const struct reg_field *hc_reg_fields;
+ const struct regmap_config *dc_regmap;
+ const struct reg_field *dc_reg_fields;
struct isp1760_device *isp;
- bool udc_disabled = !(devflags & ISP1760_FLAG_ISP1761);
+ struct isp1760_hcd *hcd;
+ struct isp1760_udc *udc;
+ struct regmap_field *f;
+ bool udc_enabled;
int ret;
+ int i;
/*
* If neither the HCD not the UDC is enabled return an error, as no
* device would be registered.
*/
+ udc_enabled = ((devflags & ISP1760_FLAG_ISP1763) ||
+ (devflags & ISP1760_FLAG_ISP1761));
+
if ((!IS_ENABLED(CONFIG_USB_ISP1760_HCD) || usb_disabled()) &&
- (!IS_ENABLED(CONFIG_USB_ISP1761_UDC) || udc_disabled))
+ (!IS_ENABLED(CONFIG_USB_ISP1761_UDC) || !udc_enabled))
return -ENODEV;
isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
@@ -126,28 +500,81 @@ int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
isp->dev = dev;
isp->devflags = devflags;
+ hcd = &isp->hcd;
+ udc = &isp->udc;
+
+ hcd->is_isp1763 = !!(devflags & ISP1760_FLAG_ISP1763);
+ udc->is_isp1763 = !!(devflags & ISP1760_FLAG_ISP1763);
+
+ if (!hcd->is_isp1763 && (devflags & ISP1760_FLAG_BUS_WIDTH_8)) {
+ dev_err(dev, "isp1760/61 do not support data width 8\n");
+ return -EINVAL;
+ }
+
+ if (hcd->is_isp1763) {
+ hc_regmap = &isp1763_hc_regmap_conf;
+ hc_reg_fields = &isp1763_hc_reg_fields[0];
+ dc_regmap = &isp1763_dc_regmap_conf;
+ dc_reg_fields = &isp1763_dc_reg_fields[0];
+ } else {
+ hc_regmap = &isp1760_hc_regmap_conf;
+ hc_reg_fields = &isp1760_hc_reg_fields[0];
+ dc_regmap = &isp1761_dc_regmap_conf;
+ dc_reg_fields = &isp1761_dc_reg_fields[0];
+ }
isp->rst_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH);
if (IS_ERR(isp->rst_gpio))
return PTR_ERR(isp->rst_gpio);
- isp->regs = devm_ioremap_resource(dev, mem);
- if (IS_ERR(isp->regs))
- return PTR_ERR(isp->regs);
+ hcd->base = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(hcd->base))
+ return PTR_ERR(hcd->base);
+
+ hcd->regs = devm_regmap_init_mmio(dev, hcd->base, hc_regmap);
+ if (IS_ERR(hcd->regs))
+ return PTR_ERR(hcd->regs);
+
+ for (i = 0; i < HC_FIELD_MAX; i++) {
+ f = devm_regmap_field_alloc(dev, hcd->regs, hc_reg_fields[i]);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+
+ hcd->fields[i] = f;
+ }
+
+ udc->regs = devm_regmap_init_mmio(dev, hcd->base, dc_regmap);
+ if (IS_ERR(udc->regs))
+ return PTR_ERR(udc->regs);
+
+ for (i = 0; i < DC_FIELD_MAX; i++) {
+ f = devm_regmap_field_alloc(dev, udc->regs, dc_reg_fields[i]);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+
+ udc->fields[i] = f;
+ }
+
+ if (hcd->is_isp1763)
+ hcd->memory_layout = &isp1763_memory_conf;
+ else
+ hcd->memory_layout = &isp176x_memory_conf;
- isp1760_init_core(isp);
+ ret = isp1760_init_core(isp);
+ if (ret < 0)
+ return ret;
if (IS_ENABLED(CONFIG_USB_ISP1760_HCD) && !usb_disabled()) {
- ret = isp1760_hcd_register(&isp->hcd, isp->regs, mem, irq,
+ ret = isp1760_hcd_register(hcd, mem, irq,
irqflags | IRQF_SHARED, dev);
if (ret < 0)
return ret;
}
- if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) {
+ if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && udc_enabled) {
ret = isp1760_udc_register(isp, irq, irqflags);
if (ret < 0) {
- isp1760_hcd_unregister(&isp->hcd);
+ isp1760_hcd_unregister(hcd);
return ret;
}
}
diff --git a/drivers/usb/isp1760/isp1760-core.h b/drivers/usb/isp1760/isp1760-core.h
index d9a0a4cc467c..91e0ee3992a7 100644
--- a/drivers/usb/isp1760/isp1760-core.h
+++ b/drivers/usb/isp1760/isp1760-core.h
@@ -2,18 +2,21 @@
/*
* Driver for the NXP ISP1760 chip
*
+ * Copyright 2021 Linaro, Rui Miguel Silva
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Rui Miguel Silva <rui.silva@linaro.org>
*/
#ifndef _ISP1760_CORE_H_
#define _ISP1760_CORE_H_
#include <linux/ioport.h>
+#include <linux/regmap.h>
#include "isp1760-hcd.h"
#include "isp1760-udc.h"
@@ -27,18 +30,19 @@ struct gpio_desc;
* a sane default configuration.
*/
#define ISP1760_FLAG_BUS_WIDTH_16 0x00000002 /* 16-bit data bus width */
-#define ISP1760_FLAG_OTG_EN 0x00000004 /* Port 1 supports OTG */
+#define ISP1760_FLAG_PERIPHERAL_EN 0x00000004 /* Port 1 supports Peripheral mode*/
#define ISP1760_FLAG_ANALOG_OC 0x00000008 /* Analog overcurrent */
#define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */
#define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */
#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
+#define ISP1760_FLAG_ISP1763 0x00000200 /* Chip is ISP1763 */
+#define ISP1760_FLAG_BUS_WIDTH_8 0x00000400 /* 8-bit data bus width */
struct isp1760_device {
struct device *dev;
- void __iomem *regs;
unsigned int devflags;
struct gpio_desc *rst_gpio;
@@ -52,14 +56,42 @@ void isp1760_unregister(struct device *dev);
void isp1760_set_pullup(struct isp1760_device *isp, bool enable);
-static inline u32 isp1760_read32(void __iomem *base, u32 reg)
+static inline u32 isp1760_field_read(struct regmap_field **fields, u32 field)
{
- return readl(base + reg);
+ unsigned int val;
+
+ regmap_field_read(fields[field], &val);
+
+ return val;
+}
+
+static inline void isp1760_field_write(struct regmap_field **fields, u32 field,
+ u32 val)
+{
+ regmap_field_write(fields[field], val);
+}
+
+static inline void isp1760_field_set(struct regmap_field **fields, u32 field)
+{
+ isp1760_field_write(fields, field, 0xFFFFFFFF);
}
-static inline void isp1760_write32(void __iomem *base, u32 reg, u32 val)
+static inline void isp1760_field_clear(struct regmap_field **fields, u32 field)
{
- writel(val, base + reg);
+ isp1760_field_write(fields, field, 0);
}
+static inline u32 isp1760_reg_read(struct regmap *regs, u32 reg)
+{
+ unsigned int val;
+
+ regmap_read(regs, reg, &val);
+
+ return val;
+}
+
+static inline void isp1760_reg_write(struct regmap *regs, u32 reg, u32 val)
+{
+ regmap_write(regs, reg, val);
+}
#endif
diff --git a/drivers/usb/isp1760/isp1760-hcd.c b/drivers/usb/isp1760/isp1760-hcd.c
index 33ae656c4b68..27168b4a4ef2 100644
--- a/drivers/usb/isp1760/isp1760-hcd.c
+++ b/drivers/usb/isp1760/isp1760-hcd.c
@@ -11,6 +11,8 @@
*
* (c) 2011 Arvid Brodin <arvid.brodin@enea.com>
*
+ * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org>
+ *
*/
#include <linux/gpio/consumer.h>
#include <linux/module.h>
@@ -44,6 +46,9 @@ static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
return *(struct isp1760_hcd **)hcd->hcd_priv;
}
+#define dw_to_le32(x) (cpu_to_le32((__force u32)x))
+#define le32_to_dw(x) ((__force __dw)(le32_to_cpu(x)))
+
/* urb state*/
#define DELETE_URB (0x0008)
#define NO_TRANSFER_ACTIVE (0xffffffff)
@@ -60,50 +65,69 @@ struct ptd {
__dw dw6;
__dw dw7;
};
+
+struct ptd_le32 {
+ __le32 dw0;
+ __le32 dw1;
+ __le32 dw2;
+ __le32 dw3;
+ __le32 dw4;
+ __le32 dw5;
+ __le32 dw6;
+ __le32 dw7;
+};
+
#define PTD_OFFSET 0x0400
#define ISO_PTD_OFFSET 0x0400
#define INT_PTD_OFFSET 0x0800
#define ATL_PTD_OFFSET 0x0c00
#define PAYLOAD_OFFSET 0x1000
-
-/* ATL */
-/* DW0 */
-#define DW0_VALID_BIT 1
-#define FROM_DW0_VALID(x) ((x) & 0x01)
-#define TO_DW0_LENGTH(x) (((u32) x) << 3)
-#define TO_DW0_MAXPACKET(x) (((u32) x) << 18)
-#define TO_DW0_MULTI(x) (((u32) x) << 29)
-#define TO_DW0_ENDPOINT(x) (((u32) x) << 31)
+#define ISP_BANK_0 0x00
+#define ISP_BANK_1 0x01
+#define ISP_BANK_2 0x02
+#define ISP_BANK_3 0x03
+
+#define TO_DW(x) ((__force __dw)x)
+#define TO_U32(x) ((__force u32)x)
+
+ /* ATL */
+ /* DW0 */
+#define DW0_VALID_BIT TO_DW(1)
+#define FROM_DW0_VALID(x) (TO_U32(x) & 0x01)
+#define TO_DW0_LENGTH(x) TO_DW((((u32)x) << 3))
+#define TO_DW0_MAXPACKET(x) TO_DW((((u32)x) << 18))
+#define TO_DW0_MULTI(x) TO_DW((((u32)x) << 29))
+#define TO_DW0_ENDPOINT(x) TO_DW((((u32)x) << 31))
/* DW1 */
-#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3)
-#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10)
-#define DW1_TRANS_BULK ((u32) 2 << 12)
-#define DW1_TRANS_INT ((u32) 3 << 12)
-#define DW1_TRANS_SPLIT ((u32) 1 << 14)
-#define DW1_SE_USB_LOSPEED ((u32) 2 << 16)
-#define TO_DW1_PORT_NUM(x) (((u32) x) << 18)
-#define TO_DW1_HUB_NUM(x) (((u32) x) << 25)
+#define TO_DW1_DEVICE_ADDR(x) TO_DW((((u32)x) << 3))
+#define TO_DW1_PID_TOKEN(x) TO_DW((((u32)x) << 10))
+#define DW1_TRANS_BULK TO_DW(((u32)2 << 12))
+#define DW1_TRANS_INT TO_DW(((u32)3 << 12))
+#define DW1_TRANS_SPLIT TO_DW(((u32)1 << 14))
+#define DW1_SE_USB_LOSPEED TO_DW(((u32)2 << 16))
+#define TO_DW1_PORT_NUM(x) TO_DW((((u32)x) << 18))
+#define TO_DW1_HUB_NUM(x) TO_DW((((u32)x) << 25))
/* DW2 */
-#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8)
-#define TO_DW2_RL(x) ((x) << 25)
-#define FROM_DW2_RL(x) (((x) >> 25) & 0xf)
+#define TO_DW2_DATA_START_ADDR(x) TO_DW((((u32)x) << 8))
+#define TO_DW2_RL(x) TO_DW(((x) << 25))
+#define FROM_DW2_RL(x) ((TO_U32(x) >> 25) & 0xf)
/* DW3 */
-#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff)
-#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff)
-#define TO_DW3_NAKCOUNT(x) ((x) << 19)
-#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf)
-#define TO_DW3_CERR(x) ((x) << 23)
-#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3)
-#define TO_DW3_DATA_TOGGLE(x) ((x) << 25)
-#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1)
-#define TO_DW3_PING(x) ((x) << 26)
-#define FROM_DW3_PING(x) (((x) >> 26) & 0x1)
-#define DW3_ERROR_BIT (1 << 28)
-#define DW3_BABBLE_BIT (1 << 29)
-#define DW3_HALT_BIT (1 << 30)
-#define DW3_ACTIVE_BIT (1 << 31)
-#define FROM_DW3_ACTIVE(x) (((x) >> 31) & 0x01)
+#define FROM_DW3_NRBYTESTRANSFERRED(x) TO_U32((x) & 0x3fff)
+#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) TO_U32((x) & 0x07ff)
+#define TO_DW3_NAKCOUNT(x) TO_DW(((x) << 19))
+#define FROM_DW3_NAKCOUNT(x) ((TO_U32(x) >> 19) & 0xf)
+#define TO_DW3_CERR(x) TO_DW(((x) << 23))
+#define FROM_DW3_CERR(x) ((TO_U32(x) >> 23) & 0x3)
+#define TO_DW3_DATA_TOGGLE(x) TO_DW(((x) << 25))
+#define FROM_DW3_DATA_TOGGLE(x) ((TO_U32(x) >> 25) & 0x1)
+#define TO_DW3_PING(x) TO_DW(((x) << 26))
+#define FROM_DW3_PING(x) ((TO_U32(x) >> 26) & 0x1)
+#define DW3_ERROR_BIT TO_DW((1 << 28))
+#define DW3_BABBLE_BIT TO_DW((1 << 29))
+#define DW3_HALT_BIT TO_DW((1 << 30))
+#define DW3_ACTIVE_BIT TO_DW((1 << 31))
+#define FROM_DW3_ACTIVE(x) ((TO_U32(x) >> 31) & 0x01)
#define INT_UNDERRUN (1 << 2)
#define INT_BABBLE (1 << 1)
@@ -116,7 +140,7 @@ struct ptd {
/* Errata 1 */
#define RL_COUNTER (0)
#define NAK_COUNTER (0)
-#define ERR_COUNTER (2)
+#define ERR_COUNTER (3)
struct isp1760_qtd {
u8 packet_type;
@@ -158,17 +182,124 @@ struct urb_listitem {
struct urb *urb;
};
+static const u32 isp1763_hc_portsc1_fields[] = {
+ [PORT_OWNER] = BIT(13),
+ [PORT_POWER] = BIT(12),
+ [PORT_LSTATUS] = BIT(10),
+ [PORT_RESET] = BIT(8),
+ [PORT_SUSPEND] = BIT(7),
+ [PORT_RESUME] = BIT(6),
+ [PORT_PE] = BIT(2),
+ [PORT_CSC] = BIT(1),
+ [PORT_CONNECT] = BIT(0),
+};
+
+/*
+ * Access functions for isp176x registers regmap fields
+ */
+static u32 isp1760_hcd_read(struct usb_hcd *hcd, u32 field)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ return isp1760_field_read(priv->fields, field);
+}
+
/*
- * Access functions for isp176x registers (addresses 0..0x03FF).
+ * We need, in isp1763, to write directly the values to the portsc1
+ * register so it will make the other values to trigger.
*/
-static u32 reg_read32(void __iomem *base, u32 reg)
+static void isp1760_hcd_portsc1_set_clear(struct isp1760_hcd *priv, u32 field,
+ u32 val)
+{
+ u32 bit = isp1763_hc_portsc1_fields[field];
+ u32 port_status = readl(priv->base + ISP1763_HC_PORTSC1);
+
+ if (val)
+ writel(port_status | bit, priv->base + ISP1763_HC_PORTSC1);
+ else
+ writel(port_status & ~bit, priv->base + ISP1763_HC_PORTSC1);
+}
+
+static void isp1760_hcd_write(struct usb_hcd *hcd, u32 field, u32 val)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (unlikely(priv->is_isp1763 &&
+ (field >= PORT_OWNER && field <= PORT_CONNECT)))
+ return isp1760_hcd_portsc1_set_clear(priv, field, val);
+
+ isp1760_field_write(priv->fields, field, val);
+}
+
+static void isp1760_hcd_set(struct usb_hcd *hcd, u32 field)
+{
+ isp1760_hcd_write(hcd, field, 0xFFFFFFFF);
+}
+
+static void isp1760_hcd_clear(struct usb_hcd *hcd, u32 field)
{
- return isp1760_read32(base, reg);
+ isp1760_hcd_write(hcd, field, 0);
+}
+
+static int isp1760_hcd_set_and_wait(struct usb_hcd *hcd, u32 field,
+ u32 timeout_us)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 val;
+
+ isp1760_hcd_set(hcd, field);
+
+ return regmap_field_read_poll_timeout(priv->fields[field], val,
+ val, 10, timeout_us);
+}
+
+static int isp1760_hcd_set_and_wait_swap(struct usb_hcd *hcd, u32 field,
+ u32 timeout_us)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 val;
+
+ isp1760_hcd_set(hcd, field);
+
+ return regmap_field_read_poll_timeout(priv->fields[field], val,
+ !val, 10, timeout_us);
+}
+
+static int isp1760_hcd_clear_and_wait(struct usb_hcd *hcd, u32 field,
+ u32 timeout_us)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 val;
+
+ isp1760_hcd_clear(hcd, field);
+
+ return regmap_field_read_poll_timeout(priv->fields[field], val,
+ !val, 10, timeout_us);
+}
+
+static bool isp1760_hcd_is_set(struct usb_hcd *hcd, u32 field)
+{
+ return !!isp1760_hcd_read(hcd, field);
+}
+
+static bool isp1760_hcd_ppc_is_set(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (priv->is_isp1763)
+ return true;
+
+ return isp1760_hcd_is_set(hcd, HCS_PPC);
}
-static void reg_write32(void __iomem *base, u32 reg, u32 val)
+static u32 isp1760_hcd_n_ports(struct usb_hcd *hcd)
{
- isp1760_write32(base, reg, val);
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (priv->is_isp1763)
+ return 1;
+
+ return isp1760_hcd_read(hcd, HCS_N_PORTS);
}
/*
@@ -176,7 +307,7 @@ static void reg_write32(void __iomem *base, u32 reg, u32 val)
*
* bank_reads8() reads memory locations prefetched by an earlier write to
* HC_MEMORY_REG (see isp176x datasheet). Unless you want to do fancy multi-
- * bank optimizations, you should use the more generic mem_reads8() below.
+ * bank optimizations, you should use the more generic mem_read() below.
*
* For access to ptd memory, use the specialized ptd_read() and ptd_write()
* below.
@@ -196,7 +327,7 @@ static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr,
if (src_offset < PAYLOAD_OFFSET) {
while (bytes >= 4) {
- *dst = le32_to_cpu(__raw_readl(src));
+ *dst = readl_relaxed(src);
bytes -= 4;
src++;
dst++;
@@ -217,7 +348,7 @@ static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr,
* allocated.
*/
if (src_offset < PAYLOAD_OFFSET)
- val = le32_to_cpu(__raw_readl(src));
+ val = readl_relaxed(src);
else
val = __raw_readl(src);
@@ -231,16 +362,59 @@ static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr,
}
}
-static void mem_reads8(void __iomem *src_base, u32 src_offset, void *dst,
- u32 bytes)
+static void isp1760_mem_read(struct usb_hcd *hcd, u32 src_offset, void *dst,
+ u32 bytes)
{
- reg_write32(src_base, HC_MEMORY_REG, src_offset + ISP_BANK(0));
- ndelay(90);
- bank_reads8(src_base, src_offset, ISP_BANK(0), dst, bytes);
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ isp1760_hcd_write(hcd, MEM_BANK_SEL, ISP_BANK_0);
+ isp1760_hcd_write(hcd, MEM_START_ADDR, src_offset);
+ ndelay(100);
+
+ bank_reads8(priv->base, src_offset, ISP_BANK_0, dst, bytes);
}
-static void mem_writes8(void __iomem *dst_base, u32 dst_offset,
- __u32 const *src, u32 bytes)
+/*
+ * ISP1763 does not have the banks direct host controller memory access,
+ * needs to use the HC_DATA register. Add data read/write according to this,
+ * and also adjust 16bit access.
+ */
+static void isp1763_mem_read(struct usb_hcd *hcd, u16 srcaddr,
+ u16 *dstptr, u32 bytes)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ /* Write the starting device address to the hcd memory register */
+ isp1760_reg_write(priv->regs, ISP1763_HC_MEMORY, srcaddr);
+ ndelay(100); /* Delay between consecutive access */
+
+ /* As long there are at least 16-bit to read ... */
+ while (bytes >= 2) {
+ *dstptr = __raw_readw(priv->base + ISP1763_HC_DATA);
+ bytes -= 2;
+ dstptr++;
+ }
+
+ /* If there are no more bytes to read, return */
+ if (bytes <= 0)
+ return;
+
+ *((u8 *)dstptr) = (u8)(readw(priv->base + ISP1763_HC_DATA) & 0xFF);
+}
+
+static void mem_read(struct usb_hcd *hcd, u32 src_offset, __u32 *dst,
+ u32 bytes)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (!priv->is_isp1763)
+ return isp1760_mem_read(hcd, src_offset, (u16 *)dst, bytes);
+
+ isp1763_mem_read(hcd, (u16)src_offset, (u16 *)dst, bytes);
+}
+
+static void isp1760_mem_write(void __iomem *dst_base, u32 dst_offset,
+ __u32 const *src, u32 bytes)
{
__u32 __iomem *dst;
@@ -248,7 +422,7 @@ static void mem_writes8(void __iomem *dst_base, u32 dst_offset,
if (dst_offset < PAYLOAD_OFFSET) {
while (bytes >= 4) {
- __raw_writel(cpu_to_le32(*src), dst);
+ writel_relaxed(*src, dst);
bytes -= 4;
src++;
dst++;
@@ -269,74 +443,168 @@ static void mem_writes8(void __iomem *dst_base, u32 dst_offset,
*/
if (dst_offset < PAYLOAD_OFFSET)
- __raw_writel(cpu_to_le32(*src), dst);
+ writel_relaxed(*src, dst);
else
__raw_writel(*src, dst);
}
+static void isp1763_mem_write(struct usb_hcd *hcd, u16 dstaddr, u16 *src,
+ u32 bytes)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ /* Write the starting device address to the hcd memory register */
+ isp1760_reg_write(priv->regs, ISP1763_HC_MEMORY, dstaddr);
+ ndelay(100); /* Delay between consecutive access */
+
+ while (bytes >= 2) {
+ /* Get and write the data; then adjust the data ptr and len */
+ __raw_writew(*src, priv->base + ISP1763_HC_DATA);
+ bytes -= 2;
+ src++;
+ }
+
+ /* If there are no more bytes to process, return */
+ if (bytes <= 0)
+ return;
+
+ /*
+ * The only way to get here is if there is a single byte left,
+ * get it and write it to the data reg;
+ */
+ writew(*((u8 *)src), priv->base + ISP1763_HC_DATA);
+}
+
+static void mem_write(struct usb_hcd *hcd, u32 dst_offset, __u32 *src,
+ u32 bytes)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (!priv->is_isp1763)
+ return isp1760_mem_write(priv->base, dst_offset, src, bytes);
+
+ isp1763_mem_write(hcd, dst_offset, (u16 *)src, bytes);
+}
+
/*
* Read and write ptds. 'ptd_offset' should be one of ISO_PTD_OFFSET,
* INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32.
*/
-static void ptd_read(void __iomem *base, u32 ptd_offset, u32 slot,
- struct ptd *ptd)
+static void isp1760_ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
+ struct ptd *ptd)
{
- reg_write32(base, HC_MEMORY_REG,
- ISP_BANK(0) + ptd_offset + slot*sizeof(*ptd));
+ u16 src_offset = ptd_offset + slot * sizeof(*ptd);
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ isp1760_hcd_write(hcd, MEM_BANK_SEL, ISP_BANK_0);
+ isp1760_hcd_write(hcd, MEM_START_ADDR, src_offset);
ndelay(90);
- bank_reads8(base, ptd_offset + slot*sizeof(*ptd), ISP_BANK(0),
- (void *) ptd, sizeof(*ptd));
+
+ bank_reads8(priv->base, src_offset, ISP_BANK_0, (void *)ptd,
+ sizeof(*ptd));
+}
+
+static void isp1763_ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
+ struct ptd *ptd)
+{
+ u16 src_offset = ptd_offset + slot * sizeof(*ptd);
+ struct ptd_le32 le32_ptd;
+
+ isp1763_mem_read(hcd, src_offset, (u16 *)&le32_ptd, sizeof(le32_ptd));
+ /* Normalize the data obtained */
+ ptd->dw0 = le32_to_dw(le32_ptd.dw0);
+ ptd->dw1 = le32_to_dw(le32_ptd.dw1);
+ ptd->dw2 = le32_to_dw(le32_ptd.dw2);
+ ptd->dw3 = le32_to_dw(le32_ptd.dw3);
+ ptd->dw4 = le32_to_dw(le32_ptd.dw4);
+ ptd->dw5 = le32_to_dw(le32_ptd.dw5);
+ ptd->dw6 = le32_to_dw(le32_ptd.dw6);
+ ptd->dw7 = le32_to_dw(le32_ptd.dw7);
+}
+
+static void ptd_read(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
+ struct ptd *ptd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (!priv->is_isp1763)
+ return isp1760_ptd_read(hcd, ptd_offset, slot, ptd);
+
+ isp1763_ptd_read(hcd, ptd_offset, slot, ptd);
+}
+
+static void isp1763_ptd_write(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
+ struct ptd *cpu_ptd)
+{
+ u16 dst_offset = ptd_offset + slot * sizeof(*cpu_ptd);
+ struct ptd_le32 ptd;
+
+ ptd.dw0 = dw_to_le32(cpu_ptd->dw0);
+ ptd.dw1 = dw_to_le32(cpu_ptd->dw1);
+ ptd.dw2 = dw_to_le32(cpu_ptd->dw2);
+ ptd.dw3 = dw_to_le32(cpu_ptd->dw3);
+ ptd.dw4 = dw_to_le32(cpu_ptd->dw4);
+ ptd.dw5 = dw_to_le32(cpu_ptd->dw5);
+ ptd.dw6 = dw_to_le32(cpu_ptd->dw6);
+ ptd.dw7 = dw_to_le32(cpu_ptd->dw7);
+
+ isp1763_mem_write(hcd, dst_offset, (u16 *)&ptd.dw0,
+ 8 * sizeof(ptd.dw0));
}
-static void ptd_write(void __iomem *base, u32 ptd_offset, u32 slot,
- struct ptd *ptd)
+static void isp1760_ptd_write(void __iomem *base, u32 ptd_offset, u32 slot,
+ struct ptd *ptd)
{
- mem_writes8(base, ptd_offset + slot*sizeof(*ptd) + sizeof(ptd->dw0),
- &ptd->dw1, 7*sizeof(ptd->dw1));
- /* Make sure dw0 gets written last (after other dw's and after payload)
- since it contains the enable bit */
+ u32 dst_offset = ptd_offset + slot * sizeof(*ptd);
+
+ /*
+ * Make sure dw0 gets written last (after other dw's and after payload)
+ * since it contains the enable bit
+ */
+ isp1760_mem_write(base, dst_offset + sizeof(ptd->dw0),
+ (__force u32 *)&ptd->dw1, 7 * sizeof(ptd->dw1));
wmb();
- mem_writes8(base, ptd_offset + slot*sizeof(*ptd), &ptd->dw0,
- sizeof(ptd->dw0));
+ isp1760_mem_write(base, dst_offset, (__force u32 *)&ptd->dw0,
+ sizeof(ptd->dw0));
}
+static void ptd_write(struct usb_hcd *hcd, u32 ptd_offset, u32 slot,
+ struct ptd *ptd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (!priv->is_isp1763)
+ return isp1760_ptd_write(priv->base, ptd_offset, slot, ptd);
+
+ isp1763_ptd_write(hcd, ptd_offset, slot, ptd);
+}
/* memory management of the 60kb on the chip from 0x1000 to 0xffff */
static void init_memory(struct isp1760_hcd *priv)
{
- int i, curr;
+ const struct isp1760_memory_layout *mem = priv->memory_layout;
+ int i, j, curr;
u32 payload_addr;
payload_addr = PAYLOAD_OFFSET;
- for (i = 0; i < BLOCK_1_NUM; i++) {
- priv->memory_pool[i].start = payload_addr;
- priv->memory_pool[i].size = BLOCK_1_SIZE;
- priv->memory_pool[i].free = 1;
- payload_addr += priv->memory_pool[i].size;
- }
-
- curr = i;
- for (i = 0; i < BLOCK_2_NUM; i++) {
- priv->memory_pool[curr + i].start = payload_addr;
- priv->memory_pool[curr + i].size = BLOCK_2_SIZE;
- priv->memory_pool[curr + i].free = 1;
- payload_addr += priv->memory_pool[curr + i].size;
- }
- curr = i;
- for (i = 0; i < BLOCK_3_NUM; i++) {
- priv->memory_pool[curr + i].start = payload_addr;
- priv->memory_pool[curr + i].size = BLOCK_3_SIZE;
- priv->memory_pool[curr + i].free = 1;
- payload_addr += priv->memory_pool[curr + i].size;
+ for (i = 0, curr = 0; i < ARRAY_SIZE(mem->blocks); i++) {
+ for (j = 0; j < mem->blocks[i]; j++, curr++) {
+ priv->memory_pool[curr + j].start = payload_addr;
+ priv->memory_pool[curr + j].size = mem->blocks_size[i];
+ priv->memory_pool[curr + j].free = 1;
+ payload_addr += priv->memory_pool[curr + j].size;
+ }
}
- WARN_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE);
+ WARN_ON(payload_addr - priv->memory_pool[0].start >
+ mem->payload_area_size);
}
static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ const struct isp1760_memory_layout *mem = priv->memory_layout;
int i;
WARN_ON(qtd->payload_addr);
@@ -344,7 +612,7 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
if (!qtd->length)
return;
- for (i = 0; i < BLOCKS; i++) {
+ for (i = 0; i < mem->payload_blocks; i++) {
if (priv->memory_pool[i].size >= qtd->length &&
priv->memory_pool[i].free) {
priv->memory_pool[i].free = 0;
@@ -357,12 +625,13 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ const struct isp1760_memory_layout *mem = priv->memory_layout;
int i;
if (!qtd->payload_addr)
return;
- for (i = 0; i < BLOCKS; i++) {
+ for (i = 0; i < mem->payload_blocks; i++) {
if (priv->memory_pool[i].start == qtd->payload_addr) {
WARN_ON(priv->memory_pool[i].free);
priv->memory_pool[i].free = 1;
@@ -377,34 +646,15 @@ static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
qtd->payload_addr = 0;
}
-static int handshake(struct usb_hcd *hcd, u32 reg,
- u32 mask, u32 done, int usec)
-{
- u32 result;
- int ret;
-
- ret = readl_poll_timeout_atomic(hcd->regs + reg, result,
- ((result & mask) == done ||
- result == U32_MAX), 1, usec);
- if (result == U32_MAX)
- return -ENODEV;
-
- return ret;
-}
-
/* reset a non-running (STS_HALT == 1) controller */
static int ehci_reset(struct usb_hcd *hcd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 command = reg_read32(hcd->regs, HC_USBCMD);
-
- command |= CMD_RESET;
- reg_write32(hcd->regs, HC_USBCMD, command);
hcd->state = HC_STATE_HALT;
priv->next_statechange = jiffies;
- return handshake(hcd, HC_USBCMD, CMD_RESET, 0, 250 * 1000);
+ return isp1760_hcd_set_and_wait_swap(hcd, CMD_RESET, 250 * 1000);
}
static struct isp1760_qh *qh_alloc(gfp_t flags)
@@ -432,8 +682,9 @@ static void qh_free(struct isp1760_qh *qh)
/* one-time init, only for memory state */
static int priv_init(struct usb_hcd *hcd)
{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 hcc_params;
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 isoc_cache;
+ u32 isoc_thres;
int i;
spin_lock_init(&priv->lock);
@@ -447,13 +698,20 @@ static int priv_init(struct usb_hcd *hcd)
*/
priv->periodic_size = DEFAULT_I_TDPS;
+ if (priv->is_isp1763) {
+ priv->i_thresh = 2;
+ return 0;
+ }
+
/* controllers may cache some of the periodic schedule ... */
- hcc_params = reg_read32(hcd->regs, HC_HCCPARAMS);
+ isoc_cache = isp1760_hcd_read(hcd, HCC_ISOC_CACHE);
+ isoc_thres = isp1760_hcd_read(hcd, HCC_ISOC_THRES);
+
/* full frame cache */
- if (HCC_ISOC_CACHE(hcc_params))
+ if (isoc_cache)
priv->i_thresh = 8;
else /* N microframes cached */
- priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
+ priv->i_thresh = 2 + isoc_thres;
return 0;
}
@@ -461,15 +719,24 @@ static int priv_init(struct usb_hcd *hcd)
static int isp1760_hc_setup(struct usb_hcd *hcd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 atx_reset;
int result;
- u32 scratch, hwmode;
+ u32 scratch;
+ u32 pattern;
+
+ if (priv->is_isp1763)
+ pattern = 0xcafe;
+ else
+ pattern = 0xdeadcafe;
+
+ isp1760_hcd_write(hcd, HC_SCRATCH, pattern);
- reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe);
/* Change bus pattern */
- scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG);
- scratch = reg_read32(hcd->regs, HC_SCRATCH_REG);
- if (scratch != 0xdeadbabe) {
- dev_err(hcd->self.controller, "Scratch test failed.\n");
+ scratch = isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH);
+ dev_err(hcd->self.controller, "Scratch test 0x%08x\n", scratch);
+ scratch = isp1760_hcd_read(hcd, HC_SCRATCH);
+ if (scratch != pattern) {
+ dev_err(hcd->self.controller, "Scratch test failed. 0x%08x\n", scratch);
return -ENODEV;
}
@@ -481,10 +748,13 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
* the host controller through the EHCI USB Command register. The device
* has been reset in core code anyway, so this shouldn't matter.
*/
- reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0);
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
- reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
+ isp1760_hcd_clear(hcd, ISO_BUF_FILL);
+ isp1760_hcd_clear(hcd, INT_BUF_FILL);
+ isp1760_hcd_clear(hcd, ATL_BUF_FILL);
+
+ isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP);
+ isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP);
+ isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP);
result = ehci_reset(hcd);
if (result)
@@ -493,14 +763,26 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
/* Step 11 passed */
/* ATL reset */
- hwmode = reg_read32(hcd->regs, HC_HW_MODE_CTRL) & ~ALL_ATX_RESET;
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
+ if (priv->is_isp1763)
+ atx_reset = SW_RESET_RESET_ATX;
+ else
+ atx_reset = ALL_ATX_RESET;
+
+ isp1760_hcd_set(hcd, atx_reset);
mdelay(10);
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
+ isp1760_hcd_clear(hcd, atx_reset);
- reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK);
+ if (priv->is_isp1763) {
+ isp1760_hcd_set(hcd, HW_OTG_DISABLE);
+ isp1760_hcd_set(hcd, HW_SW_SEL_HC_DC_CLEAR);
+ isp1760_hcd_set(hcd, HW_HC_2_DIS_CLEAR);
+ mdelay(10);
- priv->hcs_params = reg_read32(hcd->regs, HC_HCSPARAMS);
+ isp1760_hcd_set(hcd, HW_INTF_LOCK);
+ }
+
+ isp1760_hcd_set(hcd, HC_INT_IRQ_ENABLE);
+ isp1760_hcd_set(hcd, HC_ATL_IRQ_ENABLE);
return priv_init(hcd);
}
@@ -553,7 +835,7 @@ static void create_ptd_atl(struct isp1760_qh *qh,
ptd->dw0 |= TO_DW0_ENDPOINT(usb_pipeendpoint(qtd->urb->pipe));
/* DW1 */
- ptd->dw1 = usb_pipeendpoint(qtd->urb->pipe) >> 1;
+ ptd->dw1 = TO_DW((usb_pipeendpoint(qtd->urb->pipe) >> 1));
ptd->dw1 |= TO_DW1_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe));
ptd->dw1 |= TO_DW1_PID_TOKEN(qtd->packet_type);
@@ -575,7 +857,7 @@ static void create_ptd_atl(struct isp1760_qh *qh,
/* SE bit for Split INT transfers */
if (usb_pipeint(qtd->urb->pipe) &&
(qtd->urb->dev->speed == USB_SPEED_LOW))
- ptd->dw1 |= 2 << 16;
+ ptd->dw1 |= DW1_SE_USB_LOSPEED;
rl = 0;
nak = 0;
@@ -647,14 +929,14 @@ static void transform_add_int(struct isp1760_qh *qh,
* that number come from? 0xff seems to work fine...
*/
/* ptd->dw5 = 0x1c; */
- ptd->dw5 = 0xff; /* Execute Complete Split on any uFrame */
+ ptd->dw5 = TO_DW(0xff); /* Execute Complete Split on any uFrame */
}
period = period >> 1;/* Ensure equal or shorter period than requested */
period &= 0xf8; /* Mask off too large values and lowest unused 3 bits */
- ptd->dw2 |= period;
- ptd->dw4 = usof;
+ ptd->dw2 |= TO_DW(period);
+ ptd->dw4 = TO_DW(usof);
}
static void create_ptd_int(struct isp1760_qh *qh,
@@ -720,41 +1002,45 @@ static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
struct ptd *ptd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ const struct isp1760_memory_layout *mem = priv->memory_layout;
int skip_map;
- WARN_ON((slot < 0) || (slot > 31));
+ WARN_ON((slot < 0) || (slot > mem->slot_num - 1));
WARN_ON(qtd->length && !qtd->payload_addr);
WARN_ON(slots[slot].qtd);
WARN_ON(slots[slot].qh);
WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC);
+ if (priv->is_isp1763)
+ ndelay(100);
+
/* Make sure done map has not triggered from some unlinked transfer */
if (ptd_offset == ATL_PTD_OFFSET) {
- priv->atl_done_map |= reg_read32(hcd->regs,
- HC_ATL_PTD_DONEMAP_REG);
+ skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP);
+ isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP,
+ skip_map | (1 << slot));
+ priv->atl_done_map |= isp1760_hcd_read(hcd, HC_ATL_PTD_DONEMAP);
priv->atl_done_map &= ~(1 << slot);
} else {
- priv->int_done_map |= reg_read32(hcd->regs,
- HC_INT_PTD_DONEMAP_REG);
+ skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP);
+ isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP,
+ skip_map | (1 << slot));
+ priv->int_done_map |= isp1760_hcd_read(hcd, HC_INT_PTD_DONEMAP);
priv->int_done_map &= ~(1 << slot);
}
+ skip_map &= ~(1 << slot);
qh->slot = slot;
qtd->status = QTD_XFER_STARTED;
slots[slot].timestamp = jiffies;
slots[slot].qtd = qtd;
slots[slot].qh = qh;
- ptd_write(hcd->regs, ptd_offset, slot, ptd);
+ ptd_write(hcd, ptd_offset, slot, ptd);
- if (ptd_offset == ATL_PTD_OFFSET) {
- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
- skip_map &= ~(1 << qh->slot);
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
- } else {
- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
- skip_map &= ~(1 << qh->slot);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
- }
+ if (ptd_offset == ATL_PTD_OFFSET)
+ isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP, skip_map);
+ else
+ isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP, skip_map);
}
static int is_short_bulk(struct isp1760_qtd *qtd)
@@ -766,9 +1052,9 @@ static int is_short_bulk(struct isp1760_qtd *qtd)
static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
struct list_head *urb_list)
{
- int last_qtd;
struct isp1760_qtd *qtd, *qtd_next;
struct urb_listitem *urb_listitem;
+ int last_qtd;
list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list, qtd_list) {
if (qtd->status < QTD_XFER_COMPLETE)
@@ -783,9 +1069,9 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
if (qtd->actual_length) {
switch (qtd->packet_type) {
case IN_PID:
- mem_reads8(hcd->regs, qtd->payload_addr,
- qtd->data_buffer,
- qtd->actual_length);
+ mem_read(hcd, qtd->payload_addr,
+ qtd->data_buffer,
+ qtd->actual_length);
fallthrough;
case OUT_PID:
qtd->urb->actual_length +=
@@ -829,6 +1115,8 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ const struct isp1760_memory_layout *mem = priv->memory_layout;
+ int slot_num = mem->slot_num;
int ptd_offset;
struct isp1760_slotinfo *slots;
int curr_slot, free_slot;
@@ -855,7 +1143,7 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
}
free_slot = -1;
- for (curr_slot = 0; curr_slot < 32; curr_slot++) {
+ for (curr_slot = 0; curr_slot < slot_num; curr_slot++) {
if ((free_slot == -1) && (slots[curr_slot].qtd == NULL))
free_slot = curr_slot;
if (slots[curr_slot].qh == qh)
@@ -870,11 +1158,10 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
if ((qtd->length) && (!qtd->payload_addr))
break;
- if ((qtd->length) &&
- ((qtd->packet_type == SETUP_PID) ||
- (qtd->packet_type == OUT_PID))) {
- mem_writes8(hcd->regs, qtd->payload_addr,
- qtd->data_buffer, qtd->length);
+ if (qtd->length && (qtd->packet_type == SETUP_PID ||
+ qtd->packet_type == OUT_PID)) {
+ mem_write(hcd, qtd->payload_addr,
+ qtd->data_buffer, qtd->length);
}
qtd->status = QTD_PAYLOAD_ALLOC;
@@ -887,7 +1174,7 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
"available for transfer\n", __func__);
*/
/* Start xfer for this endpoint if not already done */
- if ((curr_slot > 31) && (free_slot > -1)) {
+ if ((curr_slot > slot_num - 1) && (free_slot > -1)) {
if (usb_pipeint(qtd->urb->pipe))
create_ptd_int(qh, qtd, &ptd);
else
@@ -977,10 +1264,10 @@ static void schedule_ptds(struct usb_hcd *hcd)
static int check_int_transfer(struct usb_hcd *hcd, struct ptd *ptd,
struct urb *urb)
{
- __dw dw4;
+ u32 dw4;
int i;
- dw4 = ptd->dw4;
+ dw4 = TO_U32(ptd->dw4);
dw4 >>= 8;
/* FIXME: ISP1761 datasheet does not say what to do with these. Do we
@@ -1074,9 +1361,9 @@ static void handle_done_ptds(struct usb_hcd *hcd)
int modified;
int skip_map;
- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+ skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP);
priv->int_done_map &= ~skip_map;
- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+ skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP);
priv->atl_done_map &= ~skip_map;
modified = priv->int_done_map || priv->atl_done_map;
@@ -1094,7 +1381,7 @@ static void handle_done_ptds(struct usb_hcd *hcd)
continue;
}
ptd_offset = INT_PTD_OFFSET;
- ptd_read(hcd->regs, INT_PTD_OFFSET, slot, &ptd);
+ ptd_read(hcd, INT_PTD_OFFSET, slot, &ptd);
state = check_int_transfer(hcd, &ptd,
slots[slot].qtd->urb);
} else {
@@ -1109,7 +1396,7 @@ static void handle_done_ptds(struct usb_hcd *hcd)
continue;
}
ptd_offset = ATL_PTD_OFFSET;
- ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
+ ptd_read(hcd, ATL_PTD_OFFSET, slot, &ptd);
state = check_atl_transfer(hcd, &ptd,
slots[slot].qtd->urb);
}
@@ -1134,7 +1421,7 @@ static void handle_done_ptds(struct usb_hcd *hcd)
qtd->status = QTD_XFER_COMPLETE;
if (list_is_last(&qtd->qtd_list, &qh->qtd_list) ||
- is_short_bulk(qtd))
+ is_short_bulk(qtd))
qtd = NULL;
else
qtd = list_entry(qtd->qtd_list.next,
@@ -1202,25 +1489,30 @@ static void handle_done_ptds(struct usb_hcd *hcd)
static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 imask;
irqreturn_t irqret = IRQ_NONE;
+ u32 int_reg;
+ u32 imask;
spin_lock(&priv->lock);
if (!(hcd->state & HC_STATE_RUNNING))
goto leave;
- imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
+ imask = isp1760_hcd_read(hcd, HC_INTERRUPT);
if (unlikely(!imask))
goto leave;
- reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
- priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
- priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
+ int_reg = priv->is_isp1763 ? ISP1763_HC_INTERRUPT :
+ ISP176x_HC_INTERRUPT;
+ isp1760_reg_write(priv->regs, int_reg, imask);
+
+ priv->int_done_map |= isp1760_hcd_read(hcd, HC_INT_PTD_DONEMAP);
+ priv->atl_done_map |= isp1760_hcd_read(hcd, HC_ATL_PTD_DONEMAP);
handle_done_ptds(hcd);
irqret = IRQ_HANDLED;
+
leave:
spin_unlock(&priv->lock);
@@ -1261,17 +1553,18 @@ static void errata2_function(struct timer_list *unused)
{
struct usb_hcd *hcd = errata2_timer_hcd;
struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ const struct isp1760_memory_layout *mem = priv->memory_layout;
int slot;
struct ptd ptd;
unsigned long spinflags;
spin_lock_irqsave(&priv->lock, spinflags);
- for (slot = 0; slot < 32; slot++)
+ for (slot = 0; slot < mem->slot_num; slot++)
if (priv->atl_slots[slot].qh && time_after(jiffies,
priv->atl_slots[slot].timestamp +
msecs_to_jiffies(SLOT_TIMEOUT))) {
- ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
+ ptd_read(hcd, ATL_PTD_OFFSET, slot, &ptd);
if (!FROM_DW0_VALID(ptd.dw0) &&
!FROM_DW3_ACTIVE(ptd.dw3))
priv->atl_done_map |= 1 << slot;
@@ -1286,35 +1579,120 @@ static void errata2_function(struct timer_list *unused)
add_timer(&errata2_timer);
}
+static int isp1763_run(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int retval;
+ u32 chipid_h;
+ u32 chipid_l;
+ u32 chip_rev;
+ u32 ptd_atl_int;
+ u32 ptd_iso;
+
+ hcd->uses_new_polling = 1;
+ hcd->state = HC_STATE_RUNNING;
+
+ chipid_h = isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH);
+ chipid_l = isp1760_hcd_read(hcd, HC_CHIP_ID_LOW);
+ chip_rev = isp1760_hcd_read(hcd, HC_CHIP_REV);
+ dev_info(hcd->self.controller, "USB ISP %02x%02x HW rev. %d started\n",
+ chipid_h, chipid_l, chip_rev);
+
+ isp1760_hcd_clear(hcd, ISO_BUF_FILL);
+ isp1760_hcd_clear(hcd, INT_BUF_FILL);
+ isp1760_hcd_clear(hcd, ATL_BUF_FILL);
+
+ isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP);
+ isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP);
+ isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP);
+ ndelay(100);
+ isp1760_hcd_clear(hcd, HC_ATL_PTD_DONEMAP);
+ isp1760_hcd_clear(hcd, HC_INT_PTD_DONEMAP);
+ isp1760_hcd_clear(hcd, HC_ISO_PTD_DONEMAP);
+
+ isp1760_hcd_set(hcd, HW_OTG_DISABLE);
+ isp1760_reg_write(priv->regs, ISP1763_HC_OTG_CTRL_CLEAR, BIT(7));
+ isp1760_reg_write(priv->regs, ISP1763_HC_OTG_CTRL_CLEAR, BIT(15));
+ mdelay(10);
+
+ isp1760_hcd_set(hcd, HC_INT_IRQ_ENABLE);
+ isp1760_hcd_set(hcd, HC_ATL_IRQ_ENABLE);
+
+ isp1760_hcd_set(hcd, HW_GLOBAL_INTR_EN);
+
+ isp1760_hcd_clear(hcd, HC_ATL_IRQ_MASK_AND);
+ isp1760_hcd_clear(hcd, HC_INT_IRQ_MASK_AND);
+ isp1760_hcd_clear(hcd, HC_ISO_IRQ_MASK_AND);
+
+ isp1760_hcd_set(hcd, HC_ATL_IRQ_MASK_OR);
+ isp1760_hcd_set(hcd, HC_INT_IRQ_MASK_OR);
+ isp1760_hcd_set(hcd, HC_ISO_IRQ_MASK_OR);
+
+ ptd_atl_int = 0x8000;
+ ptd_iso = 0x0001;
+
+ isp1760_hcd_write(hcd, HC_ATL_PTD_LASTPTD, ptd_atl_int);
+ isp1760_hcd_write(hcd, HC_INT_PTD_LASTPTD, ptd_atl_int);
+ isp1760_hcd_write(hcd, HC_ISO_PTD_LASTPTD, ptd_iso);
+
+ isp1760_hcd_set(hcd, ATL_BUF_FILL);
+ isp1760_hcd_set(hcd, INT_BUF_FILL);
+
+ isp1760_hcd_clear(hcd, CMD_LRESET);
+ isp1760_hcd_clear(hcd, CMD_RESET);
+
+ retval = isp1760_hcd_set_and_wait(hcd, CMD_RUN, 250 * 1000);
+ if (retval)
+ return retval;
+
+ down_write(&ehci_cf_port_reset_rwsem);
+ retval = isp1760_hcd_set_and_wait(hcd, FLAG_CF, 250 * 1000);
+ up_write(&ehci_cf_port_reset_rwsem);
+ if (retval)
+ return retval;
+
+ return 0;
+}
+
static int isp1760_run(struct usb_hcd *hcd)
{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
int retval;
- u32 temp;
- u32 command;
- u32 chipid;
+ u32 chipid_h;
+ u32 chipid_l;
+ u32 chip_rev;
+ u32 ptd_atl_int;
+ u32 ptd_iso;
+
+ /*
+ * ISP1763 have some differences in the setup and order to enable
+ * the ports, disable otg, setup buffers, and ATL, INT, ISO status.
+ * So, just handle it a separate sequence.
+ */
+ if (priv->is_isp1763)
+ return isp1763_run(hcd);
hcd->uses_new_polling = 1;
hcd->state = HC_STATE_RUNNING;
/* Set PTD interrupt AND & OR maps */
- reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
- reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
- reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
- reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
+ isp1760_hcd_clear(hcd, HC_ATL_IRQ_MASK_AND);
+ isp1760_hcd_clear(hcd, HC_INT_IRQ_MASK_AND);
+ isp1760_hcd_clear(hcd, HC_ISO_IRQ_MASK_AND);
+
+ isp1760_hcd_set(hcd, HC_ATL_IRQ_MASK_OR);
+ isp1760_hcd_set(hcd, HC_INT_IRQ_MASK_OR);
+ isp1760_hcd_set(hcd, HC_ISO_IRQ_MASK_OR);
+
/* step 23 passed */
- temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
+ isp1760_hcd_set(hcd, HW_GLOBAL_INTR_EN);
- command = reg_read32(hcd->regs, HC_USBCMD);
- command &= ~(CMD_LRESET|CMD_RESET);
- command |= CMD_RUN;
- reg_write32(hcd->regs, HC_USBCMD, command);
+ isp1760_hcd_clear(hcd, CMD_LRESET);
+ isp1760_hcd_clear(hcd, CMD_RESET);
- retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
+ retval = isp1760_hcd_set_and_wait(hcd, CMD_RUN, 250 * 1000);
if (retval)
return retval;
@@ -1324,9 +1702,8 @@ static int isp1760_run(struct usb_hcd *hcd)
* the semaphore while doing so.
*/
down_write(&ehci_cf_port_reset_rwsem);
- reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
- retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
+ retval = isp1760_hcd_set_and_wait(hcd, FLAG_CF, 250 * 1000);
up_write(&ehci_cf_port_reset_rwsem);
if (retval)
return retval;
@@ -1336,21 +1713,28 @@ static int isp1760_run(struct usb_hcd *hcd)
errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD);
add_timer(&errata2_timer);
- chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
- dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
- chipid & 0xffff, chipid >> 16);
+ chipid_h = isp1760_hcd_read(hcd, HC_CHIP_ID_HIGH);
+ chipid_l = isp1760_hcd_read(hcd, HC_CHIP_ID_LOW);
+ chip_rev = isp1760_hcd_read(hcd, HC_CHIP_REV);
+ dev_info(hcd->self.controller, "USB ISP %02x%02x HW rev. %d started\n",
+ chipid_h, chipid_l, chip_rev);
/* PTD Register Init Part 2, Step 28 */
/* Setup registers controlling PTD checking */
- reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
- reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
- reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
- ATL_BUF_FILL | INT_BUF_FILL);
+ ptd_atl_int = 0x80000000;
+ ptd_iso = 0x00000001;
+
+ isp1760_hcd_write(hcd, HC_ATL_PTD_LASTPTD, ptd_atl_int);
+ isp1760_hcd_write(hcd, HC_INT_PTD_LASTPTD, ptd_atl_int);
+ isp1760_hcd_write(hcd, HC_ISO_PTD_LASTPTD, ptd_iso);
+
+ isp1760_hcd_set(hcd, HC_ATL_PTD_SKIPMAP);
+ isp1760_hcd_set(hcd, HC_INT_PTD_SKIPMAP);
+ isp1760_hcd_set(hcd, HC_ISO_PTD_SKIPMAP);
+
+ isp1760_hcd_set(hcd, ATL_BUF_FILL);
+ isp1760_hcd_set(hcd, INT_BUF_FILL);
/* GRR this is run-once init(), being done every time the HC starts.
* So long as they're part of class devices, we can't do it init()
@@ -1363,8 +1747,6 @@ static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
{
qtd->data_buffer = databuffer;
- if (len > MAX_PAYLOAD_SIZE)
- len = MAX_PAYLOAD_SIZE;
qtd->length = len;
return qtd->length;
@@ -1388,6 +1770,8 @@ static void qtd_list_free(struct list_head *qtd_list)
static void packetize_urb(struct usb_hcd *hcd,
struct urb *urb, struct list_head *head, gfp_t flags)
{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ const struct isp1760_memory_layout *mem = priv->memory_layout;
struct isp1760_qtd *qtd;
void *buf;
int len, maxpacketsize;
@@ -1440,6 +1824,10 @@ static void packetize_urb(struct usb_hcd *hcd,
qtd = qtd_alloc(flags, urb, packet_type);
if (!qtd)
goto cleanup;
+
+ if (len > mem->blocks_size[ISP176x_BLOCK_NUM - 1])
+ len = mem->blocks_size[ISP176x_BLOCK_NUM - 1];
+
this_qtd_len = qtd_fill(qtd, buf, len);
list_add_tail(&qtd->qtd_list, head);
@@ -1584,15 +1972,16 @@ static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
/* We need to forcefully reclaim the slot since some transfers never
return, e.g. interrupt transfers and NAKed bulk transfers. */
if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) {
- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+ skip_map = isp1760_hcd_read(hcd, HC_ATL_PTD_SKIPMAP);
skip_map |= (1 << qh->slot);
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
+ isp1760_hcd_write(hcd, HC_ATL_PTD_SKIPMAP, skip_map);
+ ndelay(100);
priv->atl_slots[qh->slot].qh = NULL;
priv->atl_slots[qh->slot].qtd = NULL;
} else {
- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+ skip_map = isp1760_hcd_read(hcd, HC_INT_PTD_SKIPMAP);
skip_map |= (1 << qh->slot);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
+ isp1760_hcd_write(hcd, HC_INT_PTD_SKIPMAP, skip_map);
priv->int_slots[qh->slot].qh = NULL;
priv->int_slots[qh->slot].qtd = NULL;
}
@@ -1705,8 +2094,7 @@ out:
static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 temp, status = 0;
- u32 mask;
+ u32 status = 0;
int retval = 1;
unsigned long flags;
@@ -1716,17 +2104,13 @@ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
/* init status to no-changes */
buf[0] = 0;
- mask = PORT_CSC;
spin_lock_irqsave(&priv->lock, flags);
- temp = reg_read32(hcd->regs, HC_PORTSC1);
- if (temp & PORT_OWNER) {
- if (temp & PORT_CSC) {
- temp &= ~PORT_CSC;
- reg_write32(hcd->regs, HC_PORTSC1, temp);
- goto done;
- }
+ if (isp1760_hcd_is_set(hcd, PORT_OWNER) &&
+ isp1760_hcd_is_set(hcd, PORT_CSC)) {
+ isp1760_hcd_clear(hcd, PORT_CSC);
+ goto done;
}
/*
@@ -1735,11 +2119,9 @@ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
* high-speed device is switched over to the companion
* controller by the user.
*/
-
- if ((temp & mask) != 0
- || ((temp & PORT_RESUME) != 0
- && time_after_eq(jiffies,
- priv->reset_done))) {
+ if (isp1760_hcd_is_set(hcd, PORT_CSC) ||
+ (isp1760_hcd_is_set(hcd, PORT_RESUME) &&
+ time_after_eq(jiffies, priv->reset_done))) {
buf [0] |= 1 << (0 + 1);
status = STS_PCD;
}
@@ -1752,9 +2134,11 @@ done:
static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
struct usb_hub_descriptor *desc)
{
- int ports = HCS_N_PORTS(priv->hcs_params);
+ int ports;
u16 temp;
+ ports = isp1760_hcd_n_ports(priv->hcd);
+
desc->bDescriptorType = USB_DT_HUB;
/* priv 1.0, 2.3.9 says 20ms max */
desc->bPwrOn2PwrGood = 10;
@@ -1770,7 +2154,7 @@ static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
/* per-port overcurrent reporting */
temp = HUB_CHAR_INDV_PORT_OCPM;
- if (HCS_PPC(priv->hcs_params))
+ if (isp1760_hcd_ppc_is_set(priv->hcd))
/* per-port power control */
temp |= HUB_CHAR_INDV_PORT_LPSM;
else
@@ -1781,38 +2165,37 @@ static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
-static int check_reset_complete(struct usb_hcd *hcd, int index,
- int port_status)
+static void check_reset_complete(struct usb_hcd *hcd, int index)
{
- if (!(port_status & PORT_CONNECT))
- return port_status;
+ if (!(isp1760_hcd_is_set(hcd, PORT_CONNECT)))
+ return;
/* if reset finished and it's still not enabled -- handoff */
- if (!(port_status & PORT_PE)) {
-
+ if (!isp1760_hcd_is_set(hcd, PORT_PE)) {
dev_info(hcd->self.controller,
- "port %d full speed --> companion\n",
- index + 1);
+ "port %d full speed --> companion\n", index + 1);
- port_status |= PORT_OWNER;
- port_status &= ~PORT_RWC_BITS;
- reg_write32(hcd->regs, HC_PORTSC1, port_status);
+ isp1760_hcd_set(hcd, PORT_OWNER);
- } else
+ isp1760_hcd_clear(hcd, PORT_CSC);
+ } else {
dev_info(hcd->self.controller, "port %d high speed\n",
- index + 1);
+ index + 1);
+ }
- return port_status;
+ return;
}
static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
u16 wValue, u16 wIndex, char *buf, u16 wLength)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
- int ports = HCS_N_PORTS(priv->hcs_params);
- u32 temp, status;
+ u32 status;
unsigned long flags;
int retval = 0;
+ int ports;
+
+ ports = isp1760_hcd_n_ports(hcd);
/*
* FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
@@ -1837,7 +2220,6 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
- temp = reg_read32(hcd->regs, HC_PORTSC1);
/*
* Even if OWNER is set, so the port is owned by the
@@ -1848,22 +2230,22 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
switch (wValue) {
case USB_PORT_FEAT_ENABLE:
- reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_PE);
+ isp1760_hcd_clear(hcd, PORT_PE);
break;
case USB_PORT_FEAT_C_ENABLE:
/* XXX error? */
break;
case USB_PORT_FEAT_SUSPEND:
- if (temp & PORT_RESET)
+ if (isp1760_hcd_is_set(hcd, PORT_RESET))
goto error;
- if (temp & PORT_SUSPEND) {
- if ((temp & PORT_PE) == 0)
+ if (isp1760_hcd_is_set(hcd, PORT_SUSPEND)) {
+ if (!isp1760_hcd_is_set(hcd, PORT_PE))
goto error;
/* resume signaling for 20 msec */
- temp &= ~(PORT_RWC_BITS);
- reg_write32(hcd->regs, HC_PORTSC1,
- temp | PORT_RESUME);
+ isp1760_hcd_clear(hcd, PORT_CSC);
+ isp1760_hcd_set(hcd, PORT_RESUME);
+
priv->reset_done = jiffies +
msecs_to_jiffies(USB_RESUME_TIMEOUT);
}
@@ -1872,12 +2254,11 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
/* we auto-clear this feature */
break;
case USB_PORT_FEAT_POWER:
- if (HCS_PPC(priv->hcs_params))
- reg_write32(hcd->regs, HC_PORTSC1,
- temp & ~PORT_POWER);
+ if (isp1760_hcd_ppc_is_set(hcd))
+ isp1760_hcd_clear(hcd, PORT_POWER);
break;
case USB_PORT_FEAT_C_CONNECTION:
- reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_CSC);
+ isp1760_hcd_set(hcd, PORT_CSC);
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
/* XXX error ?*/
@@ -1888,7 +2269,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
default:
goto error;
}
- reg_read32(hcd->regs, HC_USBCMD);
+ isp1760_hcd_read(hcd, CMD_RUN);
break;
case GetHubDescriptor:
isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *)
@@ -1903,15 +2284,13 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
goto error;
wIndex--;
status = 0;
- temp = reg_read32(hcd->regs, HC_PORTSC1);
/* wPortChange bits */
- if (temp & PORT_CSC)
+ if (isp1760_hcd_is_set(hcd, PORT_CSC))
status |= USB_PORT_STAT_C_CONNECTION << 16;
-
/* whoever resumes must GetPortStatus to complete it!! */
- if (temp & PORT_RESUME) {
+ if (isp1760_hcd_is_set(hcd, PORT_RESUME)) {
dev_err(hcd->self.controller, "Port resume should be skipped.\n");
/* Remote Wakeup received? */
@@ -1930,44 +2309,39 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
priv->reset_done = 0;
/* stop resume signaling */
- temp = reg_read32(hcd->regs, HC_PORTSC1);
- reg_write32(hcd->regs, HC_PORTSC1,
- temp & ~(PORT_RWC_BITS | PORT_RESUME));
- retval = handshake(hcd, HC_PORTSC1,
- PORT_RESUME, 0, 2000 /* 2msec */);
+ isp1760_hcd_clear(hcd, PORT_CSC);
+
+ retval = isp1760_hcd_clear_and_wait(hcd,
+ PORT_RESUME, 2000);
if (retval != 0) {
dev_err(hcd->self.controller,
"port %d resume error %d\n",
wIndex + 1, retval);
goto error;
}
- temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
}
}
/* whoever resets must GetPortStatus to complete it!! */
- if ((temp & PORT_RESET)
- && time_after_eq(jiffies,
- priv->reset_done)) {
+ if (isp1760_hcd_is_set(hcd, PORT_RESET) &&
+ time_after_eq(jiffies, priv->reset_done)) {
status |= USB_PORT_STAT_C_RESET << 16;
priv->reset_done = 0;
/* force reset to complete */
- reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_RESET);
/* REVISIT: some hardware needs 550+ usec to clear
* this bit; seems too long to spin routinely...
*/
- retval = handshake(hcd, HC_PORTSC1,
- PORT_RESET, 0, 750);
+ retval = isp1760_hcd_clear_and_wait(hcd, PORT_RESET,
+ 750);
if (retval != 0) {
dev_err(hcd->self.controller, "port %d reset error %d\n",
- wIndex + 1, retval);
+ wIndex + 1, retval);
goto error;
}
/* see what we found out */
- temp = check_reset_complete(hcd, wIndex,
- reg_read32(hcd->regs, HC_PORTSC1));
+ check_reset_complete(hcd, wIndex);
}
/*
* Even if OWNER is set, there's no harm letting hub_wq
@@ -1975,21 +2349,22 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
* for PORT_POWER anyway).
*/
- if (temp & PORT_OWNER)
+ if (isp1760_hcd_is_set(hcd, PORT_OWNER))
dev_err(hcd->self.controller, "PORT_OWNER is set\n");
- if (temp & PORT_CONNECT) {
+ if (isp1760_hcd_is_set(hcd, PORT_CONNECT)) {
status |= USB_PORT_STAT_CONNECTION;
/* status may be from integrated TT */
status |= USB_PORT_STAT_HIGH_SPEED;
}
- if (temp & PORT_PE)
+ if (isp1760_hcd_is_set(hcd, PORT_PE))
status |= USB_PORT_STAT_ENABLE;
- if (temp & (PORT_SUSPEND|PORT_RESUME))
+ if (isp1760_hcd_is_set(hcd, PORT_SUSPEND) &&
+ isp1760_hcd_is_set(hcd, PORT_RESUME))
status |= USB_PORT_STAT_SUSPEND;
- if (temp & PORT_RESET)
+ if (isp1760_hcd_is_set(hcd, PORT_RESET))
status |= USB_PORT_STAT_RESET;
- if (temp & PORT_POWER)
+ if (isp1760_hcd_is_set(hcd, PORT_POWER))
status |= USB_PORT_STAT_POWER;
put_unaligned(cpu_to_le32(status), (__le32 *) buf);
@@ -2009,41 +2384,40 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
- temp = reg_read32(hcd->regs, HC_PORTSC1);
- if (temp & PORT_OWNER)
+
+ if (isp1760_hcd_is_set(hcd, PORT_OWNER))
break;
-/* temp &= ~PORT_RWC_BITS; */
switch (wValue) {
case USB_PORT_FEAT_ENABLE:
- reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_PE);
+ isp1760_hcd_set(hcd, PORT_PE);
break;
case USB_PORT_FEAT_SUSPEND:
- if ((temp & PORT_PE) == 0
- || (temp & PORT_RESET) != 0)
+ if (!isp1760_hcd_is_set(hcd, PORT_PE) ||
+ isp1760_hcd_is_set(hcd, PORT_RESET))
goto error;
- reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_SUSPEND);
+ isp1760_hcd_set(hcd, PORT_SUSPEND);
break;
case USB_PORT_FEAT_POWER:
- if (HCS_PPC(priv->hcs_params))
- reg_write32(hcd->regs, HC_PORTSC1,
- temp | PORT_POWER);
+ if (isp1760_hcd_ppc_is_set(hcd))
+ isp1760_hcd_set(hcd, PORT_POWER);
break;
case USB_PORT_FEAT_RESET:
- if (temp & PORT_RESUME)
+ if (isp1760_hcd_is_set(hcd, PORT_RESUME))
goto error;
/* line status bits may report this as low speed,
* which can be fine if this root hub has a
* transaction translator built in.
*/
- if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
- && PORT_USB11(temp)) {
- temp |= PORT_OWNER;
+ if ((isp1760_hcd_is_set(hcd, PORT_CONNECT) &&
+ !isp1760_hcd_is_set(hcd, PORT_PE)) &&
+ (isp1760_hcd_read(hcd, PORT_LSTATUS) == 1)) {
+ isp1760_hcd_set(hcd, PORT_OWNER);
} else {
- temp |= PORT_RESET;
- temp &= ~PORT_PE;
+ isp1760_hcd_set(hcd, PORT_RESET);
+ isp1760_hcd_clear(hcd, PORT_PE);
/*
* caller must wait, then call GetPortStatus
@@ -2052,12 +2426,10 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
priv->reset_done = jiffies +
msecs_to_jiffies(50);
}
- reg_write32(hcd->regs, HC_PORTSC1, temp);
break;
default:
goto error;
}
- reg_read32(hcd->regs, HC_USBCMD);
break;
default:
@@ -2074,14 +2446,13 @@ static int isp1760_get_frame(struct usb_hcd *hcd)
struct isp1760_hcd *priv = hcd_to_priv(hcd);
u32 fr;
- fr = reg_read32(hcd->regs, HC_FRINDEX);
+ fr = isp1760_hcd_read(hcd, HC_FRINDEX);
return (fr >> 3) % priv->periodic_size;
}
static void isp1760_stop(struct usb_hcd *hcd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 temp;
del_timer(&errata2_timer);
@@ -2092,24 +2463,19 @@ static void isp1760_stop(struct usb_hcd *hcd)
spin_lock_irq(&priv->lock);
ehci_reset(hcd);
/* Disable IRQ */
- temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN);
+ isp1760_hcd_clear(hcd, HW_GLOBAL_INTR_EN);
spin_unlock_irq(&priv->lock);
- reg_write32(hcd->regs, HC_CONFIGFLAG, 0);
+ isp1760_hcd_clear(hcd, FLAG_CF);
}
static void isp1760_shutdown(struct usb_hcd *hcd)
{
- u32 command, temp;
-
isp1760_stop(hcd);
- temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN);
- command = reg_read32(hcd->regs, HC_USBCMD);
- command &= ~CMD_RUN;
- reg_write32(hcd->regs, HC_USBCMD, command);
+ isp1760_hcd_clear(hcd, HW_GLOBAL_INTR_EN);
+
+ isp1760_hcd_clear(hcd, CMD_RUN);
}
static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
@@ -2182,10 +2548,11 @@ void isp1760_deinit_kmem_cache(void)
kmem_cache_destroy(urb_listitem_cachep);
}
-int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
- struct resource *mem, int irq, unsigned long irqflags,
+int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem,
+ int irq, unsigned long irqflags,
struct device *dev)
{
+ const struct isp1760_memory_layout *mem_layout = priv->memory_layout;
struct usb_hcd *hcd;
int ret;
@@ -2197,10 +2564,23 @@ int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
priv->hcd = hcd;
+ priv->atl_slots = kcalloc(mem_layout->slot_num,
+ sizeof(struct isp1760_slotinfo), GFP_KERNEL);
+ if (!priv->atl_slots) {
+ ret = -ENOMEM;
+ goto put_hcd;
+ }
+
+ priv->int_slots = kcalloc(mem_layout->slot_num,
+ sizeof(struct isp1760_slotinfo), GFP_KERNEL);
+ if (!priv->int_slots) {
+ ret = -ENOMEM;
+ goto free_atl_slots;
+ }
+
init_memory(priv);
hcd->irq = irq;
- hcd->regs = regs;
hcd->rsrc_start = mem->start;
hcd->rsrc_len = resource_size(mem);
@@ -2209,13 +2589,17 @@ int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
ret = usb_add_hcd(hcd, irq, irqflags);
if (ret)
- goto error;
+ goto free_int_slots;
device_wakeup_enable(hcd->self.controller);
return 0;
-error:
+free_int_slots:
+ kfree(priv->int_slots);
+free_atl_slots:
+ kfree(priv->atl_slots);
+put_hcd:
usb_put_hcd(hcd);
return ret;
}
@@ -2227,4 +2611,6 @@ void isp1760_hcd_unregister(struct isp1760_hcd *priv)
usb_remove_hcd(priv->hcd);
usb_put_hcd(priv->hcd);
+ kfree(priv->atl_slots);
+ kfree(priv->int_slots);
}
diff --git a/drivers/usb/isp1760/isp1760-hcd.h b/drivers/usb/isp1760/isp1760-hcd.h
index f1bb2deb1ccf..ee3063a34de3 100644
--- a/drivers/usb/isp1760/isp1760-hcd.h
+++ b/drivers/usb/isp1760/isp1760-hcd.h
@@ -3,30 +3,15 @@
#define _ISP1760_HCD_H_
#include <linux/spinlock.h>
+#include <linux/regmap.h>
+
+#include "isp1760-regs.h"
struct isp1760_qh;
struct isp1760_qtd;
struct resource;
struct usb_hcd;
-/*
- * 60kb divided in:
- * - 32 blocks @ 256 bytes
- * - 20 blocks @ 1024 bytes
- * - 4 blocks @ 8192 bytes
- */
-
-#define BLOCK_1_NUM 32
-#define BLOCK_2_NUM 20
-#define BLOCK_3_NUM 4
-
-#define BLOCK_1_SIZE 256
-#define BLOCK_2_SIZE 1024
-#define BLOCK_3_SIZE 8192
-#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
-#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE
-#define PAYLOAD_AREA_SIZE 0xf000
-
struct isp1760_slotinfo {
struct isp1760_qh *qh;
struct isp1760_qtd *qtd;
@@ -34,6 +19,18 @@ struct isp1760_slotinfo {
};
/* chip memory management */
+#define ISP176x_BLOCK_MAX (32 + 20 + 4)
+#define ISP176x_BLOCK_NUM 3
+
+struct isp1760_memory_layout {
+ unsigned int blocks[ISP176x_BLOCK_NUM];
+ unsigned int blocks_size[ISP176x_BLOCK_NUM];
+
+ unsigned int slot_num;
+ unsigned int payload_blocks;
+ unsigned int payload_area_size;
+};
+
struct isp1760_memory_chunk {
unsigned int start;
unsigned int size;
@@ -48,16 +45,22 @@ enum isp1760_queue_head_types {
};
struct isp1760_hcd {
-#ifdef CONFIG_USB_ISP1760_HCD
struct usb_hcd *hcd;
- u32 hcs_params;
+ void __iomem *base;
+
+ struct regmap *regs;
+ struct regmap_field *fields[HC_FIELD_MAX];
+
+ bool is_isp1763;
+ const struct isp1760_memory_layout *memory_layout;
+
spinlock_t lock;
- struct isp1760_slotinfo atl_slots[32];
+ struct isp1760_slotinfo *atl_slots;
int atl_done_map;
- struct isp1760_slotinfo int_slots[32];
+ struct isp1760_slotinfo *int_slots;
int int_done_map;
- struct isp1760_memory_chunk memory_pool[BLOCKS];
+ struct isp1760_memory_chunk memory_pool[ISP176x_BLOCK_MAX];
struct list_head qh_list[QH_END];
/* periodic schedule support */
@@ -66,20 +69,18 @@ struct isp1760_hcd {
unsigned i_thresh;
unsigned long reset_done;
unsigned long next_statechange;
-#endif
};
#ifdef CONFIG_USB_ISP1760_HCD
-int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
- struct resource *mem, int irq, unsigned long irqflags,
- struct device *dev);
+int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem,
+ int irq, unsigned long irqflags, struct device *dev);
void isp1760_hcd_unregister(struct isp1760_hcd *priv);
int isp1760_init_kmem_once(void);
void isp1760_deinit_kmem_cache(void);
#else
static inline int isp1760_hcd_register(struct isp1760_hcd *priv,
- void __iomem *regs, struct resource *mem,
+ struct resource *mem,
int irq, unsigned long irqflags,
struct device *dev)
{
diff --git a/drivers/usb/isp1760/isp1760-if.c b/drivers/usb/isp1760/isp1760-if.c
index ccd30f835888..7cc349c0b2ad 100644
--- a/drivers/usb/isp1760/isp1760-if.c
+++ b/drivers/usb/isp1760/isp1760-if.c
@@ -7,6 +7,7 @@
* - PDEV (generic platform device centralized driver model)
*
* (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org>
*
*/
@@ -16,8 +17,8 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/usb/isp1760.h>
#include <linux/usb/hcd.h>
+#include <linux/usb/otg.h>
#include "isp1760-core.h"
#include "isp1760-regs.h"
@@ -75,9 +76,9 @@ static int isp1761_pci_init(struct pci_dev *dev)
/*by default host is in 16bit mode, so
* io operations at this stage must be 16 bit
* */
- writel(0xface, iobase + HC_SCRATCH_REG);
+ writel(0xface, iobase + ISP176x_HC_SCRATCH);
udelay(100);
- reg_data = readl(iobase + HC_SCRATCH_REG) & 0x0000ffff;
+ reg_data = readl(iobase + ISP176x_HC_SCRATCH) & 0x0000ffff;
retry_count--;
}
@@ -209,13 +210,21 @@ static int isp1760_plat_probe(struct platform_device *pdev)
if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
devflags |= ISP1760_FLAG_ISP1761;
- /* Some systems wire up only 16 of the 32 data lines */
+ if (of_device_is_compatible(dp, "nxp,usb-isp1763"))
+ devflags |= ISP1760_FLAG_ISP1763;
+
+ /*
+ * Some systems wire up only 8 of 16 data lines or
+ * 16 of the 32 data lines
+ */
of_property_read_u32(dp, "bus-width", &bus_width);
if (bus_width == 16)
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
+ else if (bus_width == 8)
+ devflags |= ISP1760_FLAG_BUS_WIDTH_8;
- if (of_property_read_bool(dp, "port1-otg"))
- devflags |= ISP1760_FLAG_OTG_EN;
+ if (usb_get_dr_mode(&pdev->dev) == USB_DR_MODE_PERIPHERAL)
+ devflags |= ISP1760_FLAG_PERIPHERAL_EN;
if (of_property_read_bool(dp, "analog-oc"))
devflags |= ISP1760_FLAG_ANALOG_OC;
@@ -225,22 +234,9 @@ static int isp1760_plat_probe(struct platform_device *pdev)
if (of_property_read_bool(dp, "dreq-polarity"))
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
- } else if (dev_get_platdata(&pdev->dev)) {
- struct isp1760_platform_data *pdata =
- dev_get_platdata(&pdev->dev);
-
- if (pdata->is_isp1761)
- devflags |= ISP1760_FLAG_ISP1761;
- if (pdata->bus_width_16)
- devflags |= ISP1760_FLAG_BUS_WIDTH_16;
- if (pdata->port1_otg)
- devflags |= ISP1760_FLAG_OTG_EN;
- if (pdata->analog_oc)
- devflags |= ISP1760_FLAG_ANALOG_OC;
- if (pdata->dack_polarity_high)
- devflags |= ISP1760_FLAG_DACK_POL_HIGH;
- if (pdata->dreq_polarity_high)
- devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
+ } else {
+ pr_err("isp1760: no platform data\n");
+ return -ENXIO;
}
ret = isp1760_register(mem_res, irq_res->start, irqflags, &pdev->dev,
@@ -263,6 +259,7 @@ static int isp1760_plat_remove(struct platform_device *pdev)
static const struct of_device_id isp1760_of_match[] = {
{ .compatible = "nxp,usb-isp1760", },
{ .compatible = "nxp,usb-isp1761", },
+ { .compatible = "nxp,usb-isp1763", },
{ },
};
MODULE_DEVICE_TABLE(of, isp1760_of_match);
diff --git a/drivers/usb/isp1760/isp1760-regs.h b/drivers/usb/isp1760/isp1760-regs.h
index fedc4f5cded0..94ea60c20b2a 100644
--- a/drivers/usb/isp1760/isp1760-regs.h
+++ b/drivers/usb/isp1760/isp1760-regs.h
@@ -2,226 +2,291 @@
/*
* Driver for the NXP ISP1760 chip
*
+ * Copyright 2021 Linaro, Rui Miguel Silva
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Rui Miguel Silva <rui.silva@linaro.org>
*/
-#ifndef _ISP1760_REGS_H_
-#define _ISP1760_REGS_H_
+#ifndef _ISP176x_REGS_H_
+#define _ISP176x_REGS_H_
/* -----------------------------------------------------------------------------
* Host Controller
*/
+/* ISP1760/31 */
/* EHCI capability registers */
-#define HC_CAPLENGTH 0x000
-#define HC_LENGTH(p) (((p) >> 00) & 0x00ff) /* bits 7:0 */
-#define HC_VERSION(p) (((p) >> 16) & 0xffff) /* bits 31:16 */
+#define ISP176x_HC_VERSION 0x002
+#define ISP176x_HC_HCSPARAMS 0x004
+#define ISP176x_HC_HCCPARAMS 0x008
-#define HC_HCSPARAMS 0x004
-#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* true: has port indicators */
-#define HCS_PPC(p) ((p) & (1 << 4)) /* true: port power control */
-#define HCS_N_PORTS(p) (((p) >> 0) & 0xf) /* bits 3:0, ports on HC */
+/* EHCI operational registers */
+#define ISP176x_HC_USBCMD 0x020
+#define ISP176x_HC_USBSTS 0x024
+#define ISP176x_HC_FRINDEX 0x02c
+
+#define ISP176x_HC_CONFIGFLAG 0x060
+#define ISP176x_HC_PORTSC1 0x064
+
+#define ISP176x_HC_ISO_PTD_DONEMAP 0x130
+#define ISP176x_HC_ISO_PTD_SKIPMAP 0x134
+#define ISP176x_HC_ISO_PTD_LASTPTD 0x138
+#define ISP176x_HC_INT_PTD_DONEMAP 0x140
+#define ISP176x_HC_INT_PTD_SKIPMAP 0x144
+#define ISP176x_HC_INT_PTD_LASTPTD 0x148
+#define ISP176x_HC_ATL_PTD_DONEMAP 0x150
+#define ISP176x_HC_ATL_PTD_SKIPMAP 0x154
+#define ISP176x_HC_ATL_PTD_LASTPTD 0x158
-#define HC_HCCPARAMS 0x008
-#define HCC_ISOC_CACHE(p) ((p) & (1 << 7)) /* true: can cache isoc frame */
-#define HCC_ISOC_THRES(p) (((p) >> 4) & 0x7) /* bits 6:4, uframes cached */
+/* Configuration Register */
+#define ISP176x_HC_HW_MODE_CTRL 0x300
+#define ISP176x_HC_CHIP_ID 0x304
+#define ISP176x_HC_SCRATCH 0x308
+#define ISP176x_HC_RESET 0x30c
+#define ISP176x_HC_BUFFER_STATUS 0x334
+#define ISP176x_HC_MEMORY 0x33c
+/* Interrupt Register */
+#define ISP176x_HC_INTERRUPT 0x310
+#define ISP176x_HC_INTERRUPT_ENABLE 0x314
+#define ISP176x_HC_ISO_IRQ_MASK_OR 0x318
+#define ISP176x_HC_INT_IRQ_MASK_OR 0x31c
+#define ISP176x_HC_ATL_IRQ_MASK_OR 0x320
+#define ISP176x_HC_ISO_IRQ_MASK_AND 0x324
+#define ISP176x_HC_INT_IRQ_MASK_AND 0x328
+#define ISP176x_HC_ATL_IRQ_MASK_AND 0x32c
+
+#define ISP176x_HC_OTG_CTRL_SET 0x374
+#define ISP176x_HC_OTG_CTRL_CLEAR 0x376
+
+enum isp176x_host_controller_fields {
+ /* HC_PORTSC1 */
+ PORT_OWNER, PORT_POWER, PORT_LSTATUS, PORT_RESET, PORT_SUSPEND,
+ PORT_RESUME, PORT_PE, PORT_CSC, PORT_CONNECT,
+ /* HC_HCSPARAMS */
+ HCS_PPC, HCS_N_PORTS,
+ /* HC_HCCPARAMS */
+ HCC_ISOC_CACHE, HCC_ISOC_THRES,
+ /* HC_USBCMD */
+ CMD_LRESET, CMD_RESET, CMD_RUN,
+ /* HC_USBSTS */
+ STS_PCD,
+ /* HC_FRINDEX */
+ HC_FRINDEX,
+ /* HC_CONFIGFLAG */
+ FLAG_CF,
+ /* ISO/INT/ATL PTD */
+ HC_ISO_PTD_DONEMAP, HC_ISO_PTD_SKIPMAP, HC_ISO_PTD_LASTPTD,
+ HC_INT_PTD_DONEMAP, HC_INT_PTD_SKIPMAP, HC_INT_PTD_LASTPTD,
+ HC_ATL_PTD_DONEMAP, HC_ATL_PTD_SKIPMAP, HC_ATL_PTD_LASTPTD,
+ /* HC_HW_MODE_CTRL */
+ ALL_ATX_RESET, HW_ANA_DIGI_OC, HW_DEV_DMA, HW_COMN_IRQ, HW_COMN_DMA,
+ HW_DATA_BUS_WIDTH, HW_DACK_POL_HIGH, HW_DREQ_POL_HIGH, HW_INTR_HIGH_ACT,
+ HW_INTF_LOCK, HW_INTR_EDGE_TRIG, HW_GLOBAL_INTR_EN,
+ /* HC_CHIP_ID */
+ HC_CHIP_ID_HIGH, HC_CHIP_ID_LOW, HC_CHIP_REV,
+ /* HC_SCRATCH */
+ HC_SCRATCH,
+ /* HC_RESET */
+ SW_RESET_RESET_ATX, SW_RESET_RESET_HC, SW_RESET_RESET_ALL,
+ /* HC_BUFFER_STATUS */
+ ISO_BUF_FILL, INT_BUF_FILL, ATL_BUF_FILL,
+ /* HC_MEMORY */
+ MEM_BANK_SEL, MEM_START_ADDR,
+ /* HC_DATA */
+ HC_DATA,
+ /* HC_INTERRUPT */
+ HC_INTERRUPT,
+ /* HC_INTERRUPT_ENABLE */
+ HC_INT_IRQ_ENABLE, HC_ATL_IRQ_ENABLE,
+ /* INTERRUPT MASKS */
+ HC_ISO_IRQ_MASK_OR, HC_INT_IRQ_MASK_OR, HC_ATL_IRQ_MASK_OR,
+ HC_ISO_IRQ_MASK_AND, HC_INT_IRQ_MASK_AND, HC_ATL_IRQ_MASK_AND,
+ /* HW_OTG_CTRL_SET */
+ HW_OTG_DISABLE, HW_SW_SEL_HC_DC, HW_VBUS_DRV, HW_SEL_CP_EXT,
+ HW_DM_PULLDOWN, HW_DP_PULLDOWN, HW_DP_PULLUP, HW_HC_2_DIS,
+ /* HW_OTG_CTRL_CLR */
+ HW_OTG_DISABLE_CLEAR, HW_SW_SEL_HC_DC_CLEAR, HW_VBUS_DRV_CLEAR,
+ HW_SEL_CP_EXT_CLEAR, HW_DM_PULLDOWN_CLEAR, HW_DP_PULLDOWN_CLEAR,
+ HW_DP_PULLUP_CLEAR, HW_HC_2_DIS_CLEAR,
+ /* Last element */
+ HC_FIELD_MAX,
+};
+
+/* ISP1763 */
/* EHCI operational registers */
-#define HC_USBCMD 0x020
-#define CMD_LRESET (1 << 7) /* partial reset (no ports, etc) */
-#define CMD_RESET (1 << 1) /* reset HC not bus */
-#define CMD_RUN (1 << 0) /* start/stop HC */
-
-#define HC_USBSTS 0x024
-#define STS_PCD (1 << 2) /* port change detect */
-
-#define HC_FRINDEX 0x02c
-
-#define HC_CONFIGFLAG 0x060
-#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */
-
-#define HC_PORTSC1 0x064
-#define PORT_OWNER (1 << 13) /* true: companion hc owns this port */
-#define PORT_POWER (1 << 12) /* true: has power (see PPC) */
-#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
-#define PORT_RESET (1 << 8) /* reset port */
-#define PORT_SUSPEND (1 << 7) /* suspend port */
-#define PORT_RESUME (1 << 6) /* resume it */
-#define PORT_PE (1 << 2) /* port enable */
-#define PORT_CSC (1 << 1) /* connect status change */
-#define PORT_CONNECT (1 << 0) /* device connected */
-#define PORT_RWC_BITS (PORT_CSC)
-
-#define HC_ISO_PTD_DONEMAP_REG 0x130
-#define HC_ISO_PTD_SKIPMAP_REG 0x134
-#define HC_ISO_PTD_LASTPTD_REG 0x138
-#define HC_INT_PTD_DONEMAP_REG 0x140
-#define HC_INT_PTD_SKIPMAP_REG 0x144
-#define HC_INT_PTD_LASTPTD_REG 0x148
-#define HC_ATL_PTD_DONEMAP_REG 0x150
-#define HC_ATL_PTD_SKIPMAP_REG 0x154
-#define HC_ATL_PTD_LASTPTD_REG 0x158
+#define ISP1763_HC_USBCMD 0x8c
+#define ISP1763_HC_USBSTS 0x90
+#define ISP1763_HC_FRINDEX 0x98
+
+#define ISP1763_HC_CONFIGFLAG 0x9c
+#define ISP1763_HC_PORTSC1 0xa0
+
+#define ISP1763_HC_ISO_PTD_DONEMAP 0xa4
+#define ISP1763_HC_ISO_PTD_SKIPMAP 0xa6
+#define ISP1763_HC_ISO_PTD_LASTPTD 0xa8
+#define ISP1763_HC_INT_PTD_DONEMAP 0xaa
+#define ISP1763_HC_INT_PTD_SKIPMAP 0xac
+#define ISP1763_HC_INT_PTD_LASTPTD 0xae
+#define ISP1763_HC_ATL_PTD_DONEMAP 0xb0
+#define ISP1763_HC_ATL_PTD_SKIPMAP 0xb2
+#define ISP1763_HC_ATL_PTD_LASTPTD 0xb4
/* Configuration Register */
-#define HC_HW_MODE_CTRL 0x300
-#define ALL_ATX_RESET (1 << 31)
-#define HW_ANA_DIGI_OC (1 << 15)
-#define HW_DEV_DMA (1 << 11)
-#define HW_COMN_IRQ (1 << 10)
-#define HW_COMN_DMA (1 << 9)
-#define HW_DATA_BUS_32BIT (1 << 8)
-#define HW_DACK_POL_HIGH (1 << 6)
-#define HW_DREQ_POL_HIGH (1 << 5)
-#define HW_INTR_HIGH_ACT (1 << 2)
-#define HW_INTR_EDGE_TRIG (1 << 1)
-#define HW_GLOBAL_INTR_EN (1 << 0)
-
-#define HC_CHIP_ID_REG 0x304
-#define HC_SCRATCH_REG 0x308
-
-#define HC_RESET_REG 0x30c
-#define SW_RESET_RESET_HC (1 << 1)
-#define SW_RESET_RESET_ALL (1 << 0)
-
-#define HC_BUFFER_STATUS_REG 0x334
-#define ISO_BUF_FILL (1 << 2)
-#define INT_BUF_FILL (1 << 1)
-#define ATL_BUF_FILL (1 << 0)
-
-#define HC_MEMORY_REG 0x33c
-#define ISP_BANK(x) ((x) << 16)
-
-#define HC_PORT1_CTRL 0x374
-#define PORT1_POWER (3 << 3)
-#define PORT1_INIT1 (1 << 7)
-#define PORT1_INIT2 (1 << 23)
-#define HW_OTG_CTRL_SET 0x374
-#define HW_OTG_CTRL_CLR 0x376
-#define HW_OTG_DISABLE (1 << 10)
-#define HW_OTG_SE0_EN (1 << 9)
-#define HW_BDIS_ACON_EN (1 << 8)
-#define HW_SW_SEL_HC_DC (1 << 7)
-#define HW_VBUS_CHRG (1 << 6)
-#define HW_VBUS_DISCHRG (1 << 5)
-#define HW_VBUS_DRV (1 << 4)
-#define HW_SEL_CP_EXT (1 << 3)
-#define HW_DM_PULLDOWN (1 << 2)
-#define HW_DP_PULLDOWN (1 << 1)
-#define HW_DP_PULLUP (1 << 0)
+#define ISP1763_HC_HW_MODE_CTRL 0xb6
+#define ISP1763_HC_CHIP_REV 0x70
+#define ISP1763_HC_CHIP_ID 0x72
+#define ISP1763_HC_SCRATCH 0x78
+#define ISP1763_HC_RESET 0xb8
+#define ISP1763_HC_BUFFER_STATUS 0xba
+#define ISP1763_HC_MEMORY 0xc4
+#define ISP1763_HC_DATA 0xc6
/* Interrupt Register */
-#define HC_INTERRUPT_REG 0x310
-
-#define HC_INTERRUPT_ENABLE 0x314
-#define HC_ISO_INT (1 << 9)
-#define HC_ATL_INT (1 << 8)
-#define HC_INTL_INT (1 << 7)
-#define HC_EOT_INT (1 << 3)
-#define HC_SOT_INT (1 << 1)
-#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
-
-#define HC_ISO_IRQ_MASK_OR_REG 0x318
-#define HC_INT_IRQ_MASK_OR_REG 0x31c
-#define HC_ATL_IRQ_MASK_OR_REG 0x320
-#define HC_ISO_IRQ_MASK_AND_REG 0x324
-#define HC_INT_IRQ_MASK_AND_REG 0x328
-#define HC_ATL_IRQ_MASK_AND_REG 0x32c
+#define ISP1763_HC_INTERRUPT 0xd4
+#define ISP1763_HC_INTERRUPT_ENABLE 0xd6
+#define ISP1763_HC_ISO_IRQ_MASK_OR 0xd8
+#define ISP1763_HC_INT_IRQ_MASK_OR 0xda
+#define ISP1763_HC_ATL_IRQ_MASK_OR 0xdc
+#define ISP1763_HC_ISO_IRQ_MASK_AND 0xde
+#define ISP1763_HC_INT_IRQ_MASK_AND 0xe0
+#define ISP1763_HC_ATL_IRQ_MASK_AND 0xe2
+
+#define ISP1763_HC_OTG_CTRL_SET 0xe4
+#define ISP1763_HC_OTG_CTRL_CLEAR 0xe6
/* -----------------------------------------------------------------------------
* Peripheral Controller
*/
-/* Initialization Registers */
-#define DC_ADDRESS 0x0200
-#define DC_DEVEN (1 << 7)
-
-#define DC_MODE 0x020c
-#define DC_DMACLKON (1 << 9)
-#define DC_VBUSSTAT (1 << 8)
-#define DC_CLKAON (1 << 7)
-#define DC_SNDRSU (1 << 6)
-#define DC_GOSUSP (1 << 5)
-#define DC_SFRESET (1 << 4)
-#define DC_GLINTENA (1 << 3)
-#define DC_WKUPCS (1 << 2)
-
-#define DC_INTCONF 0x0210
-#define DC_CDBGMOD_ACK_NAK (0 << 6)
-#define DC_CDBGMOD_ACK (1 << 6)
-#define DC_CDBGMOD_ACK_1NAK (2 << 6)
-#define DC_DDBGMODIN_ACK_NAK (0 << 4)
-#define DC_DDBGMODIN_ACK (1 << 4)
-#define DC_DDBGMODIN_ACK_1NAK (2 << 4)
-#define DC_DDBGMODOUT_ACK_NYET_NAK (0 << 2)
-#define DC_DDBGMODOUT_ACK_NYET (1 << 2)
-#define DC_DDBGMODOUT_ACK_NYET_1NAK (2 << 2)
-#define DC_INTLVL (1 << 1)
-#define DC_INTPOL (1 << 0)
-
-#define DC_DEBUG 0x0212
-#define DC_INTENABLE 0x0214
#define DC_IEPTX(n) (1 << (11 + 2 * (n)))
#define DC_IEPRX(n) (1 << (10 + 2 * (n)))
#define DC_IEPRXTX(n) (3 << (10 + 2 * (n)))
-#define DC_IEP0SETUP (1 << 8)
-#define DC_IEVBUS (1 << 7)
-#define DC_IEDMA (1 << 6)
-#define DC_IEHS_STA (1 << 5)
-#define DC_IERESM (1 << 4)
-#define DC_IESUSP (1 << 3)
-#define DC_IEPSOF (1 << 2)
-#define DC_IESOF (1 << 1)
-#define DC_IEBRST (1 << 0)
+
+#define ISP176x_DC_CDBGMOD_ACK BIT(6)
+#define ISP176x_DC_DDBGMODIN_ACK BIT(4)
+#define ISP176x_DC_DDBGMODOUT_ACK BIT(2)
+
+#define ISP176x_DC_IEP0SETUP BIT(8)
+#define ISP176x_DC_IEVBUS BIT(7)
+#define ISP176x_DC_IEHS_STA BIT(5)
+#define ISP176x_DC_IERESM BIT(4)
+#define ISP176x_DC_IESUSP BIT(3)
+#define ISP176x_DC_IEBRST BIT(0)
+
+#define ISP176x_DC_ENDPTYP_ISOC 0x01
+#define ISP176x_DC_ENDPTYP_BULK 0x02
+#define ISP176x_DC_ENDPTYP_INTERRUPT 0x03
+
+/* Initialization Registers */
+#define ISP176x_DC_ADDRESS 0x0200
+#define ISP176x_DC_MODE 0x020c
+#define ISP176x_DC_INTCONF 0x0210
+#define ISP176x_DC_DEBUG 0x0212
+#define ISP176x_DC_INTENABLE 0x0214
+
+/* Data Flow Registers */
+#define ISP176x_DC_EPMAXPKTSZ 0x0204
+#define ISP176x_DC_EPTYPE 0x0208
+
+#define ISP176x_DC_BUFLEN 0x021c
+#define ISP176x_DC_BUFSTAT 0x021e
+#define ISP176x_DC_DATAPORT 0x0220
+
+#define ISP176x_DC_CTRLFUNC 0x0228
+#define ISP176x_DC_EPINDEX 0x022c
+
+/* DMA Registers */
+#define ISP176x_DC_DMACMD 0x0230
+#define ISP176x_DC_DMATXCOUNT 0x0234
+#define ISP176x_DC_DMACONF 0x0238
+#define ISP176x_DC_DMAHW 0x023c
+#define ISP176x_DC_DMAINTREASON 0x0250
+#define ISP176x_DC_DMAINTEN 0x0254
+#define ISP176x_DC_DMAEP 0x0258
+#define ISP176x_DC_DMABURSTCOUNT 0x0264
+
+/* General Registers */
+#define ISP176x_DC_INTERRUPT 0x0218
+#define ISP176x_DC_CHIPID 0x0270
+#define ISP176x_DC_FRAMENUM 0x0274
+#define ISP176x_DC_SCRATCH 0x0278
+#define ISP176x_DC_UNLOCKDEV 0x027c
+#define ISP176x_DC_INTPULSEWIDTH 0x0280
+#define ISP176x_DC_TESTMODE 0x0284
+
+enum isp176x_device_controller_fields {
+ /* DC_ADDRESS */
+ DC_DEVEN, DC_DEVADDR,
+ /* DC_MODE */
+ DC_VBUSSTAT, DC_SFRESET, DC_GLINTENA,
+ /* DC_INTCONF */
+ DC_CDBGMOD_ACK, DC_DDBGMODIN_ACK, DC_DDBGMODOUT_ACK, DC_INTPOL,
+ /* DC_INTENABLE */
+ DC_IEPRXTX_7, DC_IEPRXTX_6, DC_IEPRXTX_5, DC_IEPRXTX_4, DC_IEPRXTX_3,
+ DC_IEPRXTX_2, DC_IEPRXTX_1, DC_IEPRXTX_0,
+ DC_IEP0SETUP, DC_IEVBUS, DC_IEHS_STA, DC_IERESM, DC_IESUSP, DC_IEBRST,
+ /* DC_EPINDEX */
+ DC_EP0SETUP, DC_ENDPIDX, DC_EPDIR,
+ /* DC_CTRLFUNC */
+ DC_CLBUF, DC_VENDP, DC_DSEN, DC_STATUS, DC_STALL,
+ /* DC_BUFLEN */
+ DC_BUFLEN,
+ /* DC_EPMAXPKTSZ */
+ DC_FFOSZ,
+ /* DC_EPTYPE */
+ DC_EPENABLE, DC_ENDPTYP,
+ /* DC_FRAMENUM */
+ DC_FRAMENUM, DC_UFRAMENUM,
+ /* DC_CHIP_ID */
+ DC_CHIP_ID_HIGH, DC_CHIP_ID_LOW,
+ /* DC_SCRATCH */
+ DC_SCRATCH,
+ /* Last element */
+ DC_FIELD_MAX,
+};
+
+/* ISP1763 */
+/* Initialization Registers */
+#define ISP1763_DC_ADDRESS 0x00
+#define ISP1763_DC_MODE 0x0c
+#define ISP1763_DC_INTCONF 0x10
+#define ISP1763_DC_INTENABLE 0x14
/* Data Flow Registers */
-#define DC_EPINDEX 0x022c
-#define DC_EP0SETUP (1 << 5)
-#define DC_ENDPIDX(n) ((n) << 1)
-#define DC_EPDIR (1 << 0)
-
-#define DC_CTRLFUNC 0x0228
-#define DC_CLBUF (1 << 4)
-#define DC_VENDP (1 << 3)
-#define DC_DSEN (1 << 2)
-#define DC_STATUS (1 << 1)
-#define DC_STALL (1 << 0)
-
-#define DC_DATAPORT 0x0220
-#define DC_BUFLEN 0x021c
-#define DC_DATACOUNT_MASK 0xffff
-#define DC_BUFSTAT 0x021e
-#define DC_EPMAXPKTSZ 0x0204
-
-#define DC_EPTYPE 0x0208
-#define DC_NOEMPKT (1 << 4)
-#define DC_EPENABLE (1 << 3)
-#define DC_DBLBUF (1 << 2)
-#define DC_ENDPTYP_ISOC (1 << 0)
-#define DC_ENDPTYP_BULK (2 << 0)
-#define DC_ENDPTYP_INTERRUPT (3 << 0)
+#define ISP1763_DC_EPMAXPKTSZ 0x04
+#define ISP1763_DC_EPTYPE 0x08
+
+#define ISP1763_DC_BUFLEN 0x1c
+#define ISP1763_DC_BUFSTAT 0x1e
+#define ISP1763_DC_DATAPORT 0x20
+
+#define ISP1763_DC_CTRLFUNC 0x28
+#define ISP1763_DC_EPINDEX 0x2c
/* DMA Registers */
-#define DC_DMACMD 0x0230
-#define DC_DMATXCOUNT 0x0234
-#define DC_DMACONF 0x0238
-#define DC_DMAHW 0x023c
-#define DC_DMAINTREASON 0x0250
-#define DC_DMAINTEN 0x0254
-#define DC_DMAEP 0x0258
-#define DC_DMABURSTCOUNT 0x0264
+#define ISP1763_DC_DMACMD 0x30
+#define ISP1763_DC_DMATXCOUNT 0x34
+#define ISP1763_DC_DMACONF 0x38
+#define ISP1763_DC_DMAHW 0x3c
+#define ISP1763_DC_DMAINTREASON 0x50
+#define ISP1763_DC_DMAINTEN 0x54
+#define ISP1763_DC_DMAEP 0x58
+#define ISP1763_DC_DMABURSTCOUNT 0x64
/* General Registers */
-#define DC_INTERRUPT 0x0218
-#define DC_CHIPID 0x0270
-#define DC_FRAMENUM 0x0274
-#define DC_SCRATCH 0x0278
-#define DC_UNLOCKDEV 0x027c
-#define DC_INTPULSEWIDTH 0x0280
-#define DC_TESTMODE 0x0284
+#define ISP1763_DC_INTERRUPT 0x18
+#define ISP1763_DC_CHIPID_LOW 0x70
+#define ISP1763_DC_CHIPID_HIGH 0x72
+#define ISP1763_DC_FRAMENUM 0x74
+#define ISP1763_DC_SCRATCH 0x78
+#define ISP1763_DC_UNLOCKDEV 0x7c
+#define ISP1763_DC_INTPULSEWIDTH 0x80
+#define ISP1763_DC_TESTMODE 0x84
#endif
diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c
index 1714b2258b54..a78da59d6417 100644
--- a/drivers/usb/isp1760/isp1760-udc.c
+++ b/drivers/usb/isp1760/isp1760-udc.c
@@ -2,10 +2,12 @@
/*
* Driver for the NXP ISP1761 device controller
*
+ * Copyright 2021 Linaro, Rui Miguel Silva
* Copyright 2014 Ideas on Board Oy
*
* Contacts:
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Rui Miguel Silva <rui.silva@linaro.org>
*/
#include <linux/interrupt.h>
@@ -45,16 +47,62 @@ static inline struct isp1760_request *req_to_udc_req(struct usb_request *req)
return container_of(req, struct isp1760_request, req);
}
-static inline u32 isp1760_udc_read(struct isp1760_udc *udc, u16 reg)
+static u32 isp1760_udc_read(struct isp1760_udc *udc, u16 field)
{
- return isp1760_read32(udc->regs, reg);
+ return isp1760_field_read(udc->fields, field);
}
-static inline void isp1760_udc_write(struct isp1760_udc *udc, u16 reg, u32 val)
+static void isp1760_udc_write(struct isp1760_udc *udc, u16 field, u32 val)
{
- isp1760_write32(udc->regs, reg, val);
+ isp1760_field_write(udc->fields, field, val);
}
+static u32 isp1760_udc_read_raw(struct isp1760_udc *udc, u16 reg)
+{
+ __le32 val;
+
+ regmap_raw_read(udc->regs, reg, &val, 4);
+
+ return le32_to_cpu(val);
+}
+
+static u16 isp1760_udc_read_raw16(struct isp1760_udc *udc, u16 reg)
+{
+ __le16 val;
+
+ regmap_raw_read(udc->regs, reg, &val, 2);
+
+ return le16_to_cpu(val);
+}
+
+static void isp1760_udc_write_raw(struct isp1760_udc *udc, u16 reg, u32 val)
+{
+ __le32 val_le = cpu_to_le32(val);
+
+ regmap_raw_write(udc->regs, reg, &val_le, 4);
+}
+
+static void isp1760_udc_write_raw16(struct isp1760_udc *udc, u16 reg, u16 val)
+{
+ __le16 val_le = cpu_to_le16(val);
+
+ regmap_raw_write(udc->regs, reg, &val_le, 2);
+}
+
+static void isp1760_udc_set(struct isp1760_udc *udc, u32 field)
+{
+ isp1760_udc_write(udc, field, 0xFFFFFFFF);
+}
+
+static void isp1760_udc_clear(struct isp1760_udc *udc, u32 field)
+{
+ isp1760_udc_write(udc, field, 0);
+}
+
+static bool isp1760_udc_is_set(struct isp1760_udc *udc, u32 field)
+{
+ return !!isp1760_udc_read(udc, field);
+}
/* -----------------------------------------------------------------------------
* Endpoint Management
*/
@@ -75,16 +123,21 @@ static struct isp1760_ep *isp1760_udc_find_ep(struct isp1760_udc *udc,
return NULL;
}
-static void __isp1760_udc_select_ep(struct isp1760_ep *ep, int dir)
+static void __isp1760_udc_select_ep(struct isp1760_udc *udc,
+ struct isp1760_ep *ep, int dir)
{
- isp1760_udc_write(ep->udc, DC_EPINDEX,
- DC_ENDPIDX(ep->addr & USB_ENDPOINT_NUMBER_MASK) |
- (dir == USB_DIR_IN ? DC_EPDIR : 0));
+ isp1760_udc_write(udc, DC_ENDPIDX, ep->addr & USB_ENDPOINT_NUMBER_MASK);
+
+ if (dir == USB_DIR_IN)
+ isp1760_udc_set(udc, DC_EPDIR);
+ else
+ isp1760_udc_clear(udc, DC_EPDIR);
}
/**
* isp1760_udc_select_ep - Select an endpoint for register access
* @ep: The endpoint
+ * @udc: Reference to the device controller
*
* The ISP1761 endpoint registers are banked. This function selects the target
* endpoint for banked register access. The selection remains valid until the
@@ -93,9 +146,10 @@ static void __isp1760_udc_select_ep(struct isp1760_ep *ep, int dir)
*
* Called with the UDC spinlock held.
*/
-static void isp1760_udc_select_ep(struct isp1760_ep *ep)
+static void isp1760_udc_select_ep(struct isp1760_udc *udc,
+ struct isp1760_ep *ep)
{
- __isp1760_udc_select_ep(ep, ep->addr & USB_ENDPOINT_DIR_MASK);
+ __isp1760_udc_select_ep(udc, ep, ep->addr & USB_ENDPOINT_DIR_MASK);
}
/* Called with the UDC spinlock held. */
@@ -108,9 +162,13 @@ static void isp1760_udc_ctrl_send_status(struct isp1760_ep *ep, int dir)
* the direction opposite to the data stage data packets, we thus need
* to select the OUT/IN endpoint for IN/OUT transfers.
*/
- isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) |
- (dir == USB_DIR_IN ? 0 : DC_EPDIR));
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_STATUS);
+ if (dir == USB_DIR_IN)
+ isp1760_udc_clear(udc, DC_EPDIR);
+ else
+ isp1760_udc_set(udc, DC_EPDIR);
+
+ isp1760_udc_write(udc, DC_ENDPIDX, 1);
+ isp1760_udc_set(udc, DC_STATUS);
/*
* The hardware will terminate the request automatically and go back to
@@ -157,10 +215,10 @@ static void isp1760_udc_ctrl_send_stall(struct isp1760_ep *ep)
spin_lock_irqsave(&udc->lock, flags);
/* Stall both the IN and OUT endpoints. */
- __isp1760_udc_select_ep(ep, USB_DIR_OUT);
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL);
- __isp1760_udc_select_ep(ep, USB_DIR_IN);
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL);
+ __isp1760_udc_select_ep(udc, ep, USB_DIR_OUT);
+ isp1760_udc_set(udc, DC_STALL);
+ __isp1760_udc_select_ep(udc, ep, USB_DIR_IN);
+ isp1760_udc_set(udc, DC_STALL);
/* A protocol stall completes the control transaction. */
udc->ep0_state = ISP1760_CTRL_SETUP;
@@ -181,8 +239,8 @@ static bool isp1760_udc_receive(struct isp1760_ep *ep,
u32 *buf;
int i;
- isp1760_udc_select_ep(ep);
- len = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK;
+ isp1760_udc_select_ep(udc, ep);
+ len = isp1760_udc_read(udc, DC_BUFLEN);
dev_dbg(udc->isp->dev, "%s: received %u bytes (%u/%u done)\n",
__func__, len, req->req.actual, req->req.length);
@@ -198,7 +256,7 @@ static bool isp1760_udc_receive(struct isp1760_ep *ep,
* datasheet doesn't clearly document how this should be
* handled.
*/
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
+ isp1760_udc_set(udc, DC_CLBUF);
return false;
}
@@ -209,9 +267,9 @@ static bool isp1760_udc_receive(struct isp1760_ep *ep,
* the next packet might be removed from the FIFO.
*/
for (i = len; i > 2; i -= 4, ++buf)
- *buf = le32_to_cpu(isp1760_udc_read(udc, DC_DATAPORT));
+ *buf = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT);
if (i > 0)
- *(u16 *)buf = le16_to_cpu(readw(udc->regs + DC_DATAPORT));
+ *(u16 *)buf = isp1760_udc_read_raw16(udc, ISP176x_DC_DATAPORT);
req->req.actual += len;
@@ -253,7 +311,7 @@ static void isp1760_udc_transmit(struct isp1760_ep *ep,
__func__, req->packet_size, req->req.actual,
req->req.length);
- __isp1760_udc_select_ep(ep, USB_DIR_IN);
+ __isp1760_udc_select_ep(udc, ep, USB_DIR_IN);
if (req->packet_size)
isp1760_udc_write(udc, DC_BUFLEN, req->packet_size);
@@ -265,14 +323,14 @@ static void isp1760_udc_transmit(struct isp1760_ep *ep,
* the FIFO for this kind of conditions, but doesn't seem to work.
*/
for (i = req->packet_size; i > 2; i -= 4, ++buf)
- isp1760_udc_write(udc, DC_DATAPORT, cpu_to_le32(*buf));
+ isp1760_udc_write_raw(udc, ISP176x_DC_DATAPORT, *buf);
if (i > 0)
- writew(cpu_to_le16(*(u16 *)buf), udc->regs + DC_DATAPORT);
+ isp1760_udc_write_raw16(udc, ISP176x_DC_DATAPORT, *(u16 *)buf);
if (ep->addr == 0)
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
+ isp1760_udc_set(udc, DC_DSEN);
if (!req->packet_size)
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_VENDP);
+ isp1760_udc_set(udc, DC_VENDP);
}
static void isp1760_ep_rx_ready(struct isp1760_ep *ep)
@@ -408,19 +466,24 @@ static int __isp1760_udc_set_halt(struct isp1760_ep *ep, bool halt)
return -EINVAL;
}
- isp1760_udc_select_ep(ep);
- isp1760_udc_write(udc, DC_CTRLFUNC, halt ? DC_STALL : 0);
+ isp1760_udc_select_ep(udc, ep);
+
+ if (halt)
+ isp1760_udc_set(udc, DC_STALL);
+ else
+ isp1760_udc_clear(udc, DC_STALL);
if (ep->addr == 0) {
/* When halting the control endpoint, stall both IN and OUT. */
- __isp1760_udc_select_ep(ep, USB_DIR_IN);
- isp1760_udc_write(udc, DC_CTRLFUNC, halt ? DC_STALL : 0);
+ __isp1760_udc_select_ep(udc, ep, USB_DIR_IN);
+ if (halt)
+ isp1760_udc_set(udc, DC_STALL);
+ else
+ isp1760_udc_clear(udc, DC_STALL);
} else if (!halt) {
/* Reset the data PID by cycling the endpoint enable bit. */
- u16 eptype = isp1760_udc_read(udc, DC_EPTYPE);
-
- isp1760_udc_write(udc, DC_EPTYPE, eptype & ~DC_EPENABLE);
- isp1760_udc_write(udc, DC_EPTYPE, eptype);
+ isp1760_udc_clear(udc, DC_EPENABLE);
+ isp1760_udc_set(udc, DC_EPENABLE);
/*
* Disabling the endpoint emptied the transmit FIFO, fill it
@@ -479,12 +542,14 @@ static int isp1760_udc_get_status(struct isp1760_udc *udc,
return -EINVAL;
}
- isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) | DC_EPDIR);
+ isp1760_udc_set(udc, DC_EPDIR);
+ isp1760_udc_write(udc, DC_ENDPIDX, 1);
+
isp1760_udc_write(udc, DC_BUFLEN, 2);
- writew(cpu_to_le16(status), udc->regs + DC_DATAPORT);
+ isp1760_udc_write_raw16(udc, ISP176x_DC_DATAPORT, status);
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
+ isp1760_udc_set(udc, DC_DSEN);
dev_dbg(udc->isp->dev, "%s: status 0x%04x\n", __func__, status);
@@ -508,7 +573,8 @@ static int isp1760_udc_set_address(struct isp1760_udc *udc, u16 addr)
usb_gadget_set_state(&udc->gadget, addr ? USB_STATE_ADDRESS :
USB_STATE_DEFAULT);
- isp1760_udc_write(udc, DC_ADDRESS, DC_DEVEN | addr);
+ isp1760_udc_write(udc, DC_DEVADDR, addr);
+ isp1760_udc_set(udc, DC_DEVEN);
spin_lock(&udc->lock);
isp1760_udc_ctrl_send_status(&udc->ep[0], USB_DIR_OUT);
@@ -650,9 +716,9 @@ static void isp1760_ep0_setup(struct isp1760_udc *udc)
spin_lock(&udc->lock);
- isp1760_udc_write(udc, DC_EPINDEX, DC_EP0SETUP);
+ isp1760_udc_set(udc, DC_EP0SETUP);
- count = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK;
+ count = isp1760_udc_read(udc, DC_BUFLEN);
if (count != sizeof(req)) {
spin_unlock(&udc->lock);
@@ -663,8 +729,8 @@ static void isp1760_ep0_setup(struct isp1760_udc *udc)
return;
}
- req.data[0] = isp1760_udc_read(udc, DC_DATAPORT);
- req.data[1] = isp1760_udc_read(udc, DC_DATAPORT);
+ req.data[0] = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT);
+ req.data[1] = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT);
if (udc->ep0_state != ISP1760_CTRL_SETUP) {
spin_unlock(&udc->lock);
@@ -732,13 +798,13 @@ static int isp1760_ep_enable(struct usb_ep *ep,
switch (usb_endpoint_type(desc)) {
case USB_ENDPOINT_XFER_ISOC:
- type = DC_ENDPTYP_ISOC;
+ type = ISP176x_DC_ENDPTYP_ISOC;
break;
case USB_ENDPOINT_XFER_BULK:
- type = DC_ENDPTYP_BULK;
+ type = ISP176x_DC_ENDPTYP_BULK;
break;
case USB_ENDPOINT_XFER_INT:
- type = DC_ENDPTYP_INTERRUPT;
+ type = ISP176x_DC_ENDPTYP_INTERRUPT;
break;
case USB_ENDPOINT_XFER_CONTROL:
default:
@@ -755,10 +821,13 @@ static int isp1760_ep_enable(struct usb_ep *ep,
uep->halted = false;
uep->wedged = false;
- isp1760_udc_select_ep(uep);
- isp1760_udc_write(udc, DC_EPMAXPKTSZ, uep->maxpacket);
+ isp1760_udc_select_ep(udc, uep);
+
+ isp1760_udc_write(udc, DC_FFOSZ, uep->maxpacket);
isp1760_udc_write(udc, DC_BUFLEN, uep->maxpacket);
- isp1760_udc_write(udc, DC_EPTYPE, DC_EPENABLE | type);
+
+ isp1760_udc_write(udc, DC_ENDPTYP, type);
+ isp1760_udc_set(udc, DC_EPENABLE);
spin_unlock_irqrestore(&udc->lock, flags);
@@ -786,8 +855,9 @@ static int isp1760_ep_disable(struct usb_ep *ep)
uep->desc = NULL;
uep->maxpacket = 0;
- isp1760_udc_select_ep(uep);
- isp1760_udc_write(udc, DC_EPTYPE, 0);
+ isp1760_udc_select_ep(udc, uep);
+ isp1760_udc_clear(udc, DC_EPENABLE);
+ isp1760_udc_clear(udc, DC_ENDPTYP);
/* TODO Synchronize with the IRQ handler */
@@ -864,8 +934,8 @@ static int isp1760_ep_queue(struct usb_ep *ep, struct usb_request *_req,
case ISP1760_CTRL_DATA_OUT:
list_add_tail(&req->queue, &uep->queue);
- __isp1760_udc_select_ep(uep, USB_DIR_OUT);
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
+ __isp1760_udc_select_ep(udc, uep, USB_DIR_OUT);
+ isp1760_udc_set(udc, DC_DSEN);
break;
case ISP1760_CTRL_STATUS:
@@ -1025,14 +1095,14 @@ static void isp1760_ep_fifo_flush(struct usb_ep *ep)
spin_lock_irqsave(&udc->lock, flags);
- isp1760_udc_select_ep(uep);
+ isp1760_udc_select_ep(udc, uep);
/*
* Set the CLBUF bit twice to flush both buffers in case double
* buffering is enabled.
*/
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
- isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
+ isp1760_udc_set(udc, DC_CLBUF);
+ isp1760_udc_set(udc, DC_CLBUF);
spin_unlock_irqrestore(&udc->lock, flags);
}
@@ -1082,6 +1152,10 @@ static void isp1760_udc_disconnect(struct isp1760_udc *udc)
static void isp1760_udc_init_hw(struct isp1760_udc *udc)
{
+ u32 intconf = udc->is_isp1763 ? ISP1763_DC_INTCONF : ISP176x_DC_INTCONF;
+ u32 intena = udc->is_isp1763 ? ISP1763_DC_INTENABLE :
+ ISP176x_DC_INTENABLE;
+
/*
* The device controller currently shares its interrupt with the host
* controller, the DC_IRQ polarity and signaling mode are ignored. Set
@@ -1091,19 +1165,22 @@ static void isp1760_udc_init_hw(struct isp1760_udc *udc)
* ACK tokens only (and NYET for the out pipe). The default
* configuration also generates an interrupt on the first NACK token.
*/
- isp1760_udc_write(udc, DC_INTCONF, DC_CDBGMOD_ACK | DC_DDBGMODIN_ACK |
- DC_DDBGMODOUT_ACK_NYET);
-
- isp1760_udc_write(udc, DC_INTENABLE, DC_IEPRXTX(7) | DC_IEPRXTX(6) |
- DC_IEPRXTX(5) | DC_IEPRXTX(4) | DC_IEPRXTX(3) |
- DC_IEPRXTX(2) | DC_IEPRXTX(1) | DC_IEPRXTX(0) |
- DC_IEP0SETUP | DC_IEVBUS | DC_IERESM | DC_IESUSP |
- DC_IEHS_STA | DC_IEBRST);
+ isp1760_reg_write(udc->regs, intconf,
+ ISP176x_DC_CDBGMOD_ACK | ISP176x_DC_DDBGMODIN_ACK |
+ ISP176x_DC_DDBGMODOUT_ACK);
+
+ isp1760_reg_write(udc->regs, intena, DC_IEPRXTX(7) |
+ DC_IEPRXTX(6) | DC_IEPRXTX(5) | DC_IEPRXTX(4) |
+ DC_IEPRXTX(3) | DC_IEPRXTX(2) | DC_IEPRXTX(1) |
+ DC_IEPRXTX(0) | ISP176x_DC_IEP0SETUP |
+ ISP176x_DC_IEVBUS | ISP176x_DC_IERESM |
+ ISP176x_DC_IESUSP | ISP176x_DC_IEHS_STA |
+ ISP176x_DC_IEBRST);
if (udc->connected)
isp1760_set_pullup(udc->isp, true);
- isp1760_udc_write(udc, DC_ADDRESS, DC_DEVEN);
+ isp1760_udc_set(udc, DC_DEVEN);
}
static void isp1760_udc_reset(struct isp1760_udc *udc)
@@ -1152,7 +1229,7 @@ static int isp1760_udc_get_frame(struct usb_gadget *gadget)
{
struct isp1760_udc *udc = gadget_to_udc(gadget);
- return isp1760_udc_read(udc, DC_FRAMENUM) & ((1 << 11) - 1);
+ return isp1760_udc_read(udc, DC_FRAMENUM);
}
static int isp1760_udc_wakeup(struct usb_gadget *gadget)
@@ -1219,7 +1296,7 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
usb_gadget_set_state(&udc->gadget, USB_STATE_ATTACHED);
/* DMA isn't supported yet, don't enable the DMA clock. */
- isp1760_udc_write(udc, DC_MODE, DC_GLINTENA);
+ isp1760_udc_set(udc, DC_GLINTENA);
isp1760_udc_init_hw(udc);
@@ -1232,13 +1309,14 @@ static int isp1760_udc_start(struct usb_gadget *gadget,
static int isp1760_udc_stop(struct usb_gadget *gadget)
{
struct isp1760_udc *udc = gadget_to_udc(gadget);
+ u32 mode_reg = udc->is_isp1763 ? ISP1763_DC_MODE : ISP176x_DC_MODE;
unsigned long flags;
dev_dbg(udc->isp->dev, "%s\n", __func__);
del_timer_sync(&udc->vbus_timer);
- isp1760_udc_write(udc, DC_MODE, 0);
+ isp1760_reg_write(udc->regs, mode_reg, 0);
spin_lock_irqsave(&udc->lock, flags);
udc->driver = NULL;
@@ -1260,15 +1338,30 @@ static const struct usb_gadget_ops isp1760_udc_ops = {
* Interrupt Handling
*/
+static u32 isp1760_udc_irq_get_status(struct isp1760_udc *udc)
+{
+ u32 status;
+
+ if (udc->is_isp1763) {
+ status = isp1760_reg_read(udc->regs, ISP1763_DC_INTERRUPT)
+ & isp1760_reg_read(udc->regs, ISP1763_DC_INTENABLE);
+ isp1760_reg_write(udc->regs, ISP1763_DC_INTERRUPT, status);
+ } else {
+ status = isp1760_reg_read(udc->regs, ISP176x_DC_INTERRUPT)
+ & isp1760_reg_read(udc->regs, ISP176x_DC_INTENABLE);
+ isp1760_reg_write(udc->regs, ISP176x_DC_INTERRUPT, status);
+ }
+
+ return status;
+}
+
static irqreturn_t isp1760_udc_irq(int irq, void *dev)
{
struct isp1760_udc *udc = dev;
unsigned int i;
u32 status;
- status = isp1760_udc_read(udc, DC_INTERRUPT)
- & isp1760_udc_read(udc, DC_INTENABLE);
- isp1760_udc_write(udc, DC_INTERRUPT, status);
+ status = isp1760_udc_irq_get_status(udc);
if (status & DC_IEVBUS) {
dev_dbg(udc->isp->dev, "%s(VBUS)\n", __func__);
@@ -1313,7 +1406,7 @@ static irqreturn_t isp1760_udc_irq(int irq, void *dev)
dev_dbg(udc->isp->dev, "%s(SUSP)\n", __func__);
spin_lock(&udc->lock);
- if (!(isp1760_udc_read(udc, DC_MODE) & DC_VBUSSTAT))
+ if (!isp1760_udc_is_set(udc, DC_VBUSSTAT))
isp1760_udc_disconnect(udc);
else
isp1760_udc_suspend(udc);
@@ -1335,7 +1428,7 @@ static void isp1760_udc_vbus_poll(struct timer_list *t)
spin_lock_irqsave(&udc->lock, flags);
- if (!(isp1760_udc_read(udc, DC_MODE) & DC_VBUSSTAT))
+ if (!(isp1760_udc_is_set(udc, DC_VBUSSTAT)))
isp1760_udc_disconnect(udc);
else if (udc->gadget.state >= USB_STATE_POWERED)
mod_timer(&udc->vbus_timer,
@@ -1403,6 +1496,7 @@ static void isp1760_udc_init_eps(struct isp1760_udc *udc)
static int isp1760_udc_init(struct isp1760_udc *udc)
{
+ u32 mode_reg = udc->is_isp1763 ? ISP1763_DC_MODE : ISP176x_DC_MODE;
u16 scratch;
u32 chipid;
@@ -1413,7 +1507,8 @@ static int isp1760_udc_init(struct isp1760_udc *udc)
* and scratch register contents must match the expected values.
*/
isp1760_udc_write(udc, DC_SCRATCH, 0xbabe);
- chipid = isp1760_udc_read(udc, DC_CHIPID);
+ chipid = isp1760_udc_read(udc, DC_CHIP_ID_HIGH) << 16;
+ chipid |= isp1760_udc_read(udc, DC_CHIP_ID_LOW);
scratch = isp1760_udc_read(udc, DC_SCRATCH);
if (scratch != 0xbabe) {
@@ -1423,15 +1518,16 @@ static int isp1760_udc_init(struct isp1760_udc *udc)
return -ENODEV;
}
- if (chipid != 0x00011582 && chipid != 0x00158210) {
+ if (chipid != 0x00011582 && chipid != 0x00158210 &&
+ chipid != 0x00176320) {
dev_err(udc->isp->dev, "udc: invalid chip ID 0x%08x\n", chipid);
return -ENODEV;
}
/* Reset the device controller. */
- isp1760_udc_write(udc, DC_MODE, DC_SFRESET);
+ isp1760_udc_set(udc, DC_SFRESET);
usleep_range(10000, 11000);
- isp1760_udc_write(udc, DC_MODE, 0);
+ isp1760_reg_write(udc->regs, mode_reg, 0);
usleep_range(10000, 11000);
return 0;
@@ -1445,7 +1541,6 @@ int isp1760_udc_register(struct isp1760_device *isp, int irq,
udc->irq = -1;
udc->isp = isp;
- udc->regs = isp->regs;
spin_lock_init(&udc->lock);
timer_setup(&udc->vbus_timer, isp1760_udc_vbus_poll, 0);
diff --git a/drivers/usb/isp1760/isp1760-udc.h b/drivers/usb/isp1760/isp1760-udc.h
index d2df650d54e9..22044e86bc0e 100644
--- a/drivers/usb/isp1760/isp1760-udc.h
+++ b/drivers/usb/isp1760/isp1760-udc.h
@@ -2,10 +2,12 @@
/*
* Driver for the NXP ISP1761 device controller
*
+ * Copyright 2021 Linaro, Rui Miguel Silva
* Copyright 2014 Ideas on Board Oy
*
* Contacts:
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Rui Miguel Silva <rui.silva@linaro.org>
*/
#ifndef _ISP1760_UDC_H_
@@ -17,6 +19,8 @@
#include <linux/timer.h>
#include <linux/usb/gadget.h>
+#include "isp1760-regs.h"
+
struct isp1760_device;
struct isp1760_udc;
@@ -48,7 +52,7 @@ struct isp1760_ep {
* struct isp1760_udc - UDC state information
* irq: IRQ number
* irqname: IRQ name (as passed to request_irq)
- * regs: Base address of the UDC registers
+ * regs: regmap for UDC registers
* driver: Gadget driver
* gadget: Gadget device
* lock: Protects driver, vbus_timer, ep, ep0_*, DC_EPINDEX register
@@ -59,12 +63,13 @@ struct isp1760_ep {
* connected: Tracks gadget driver bus connection state
*/
struct isp1760_udc {
-#ifdef CONFIG_USB_ISP1761_UDC
struct isp1760_device *isp;
int irq;
char *irqname;
- void __iomem *regs;
+
+ struct regmap *regs;
+ struct regmap_field *fields[DC_FIELD_MAX];
struct usb_gadget_driver *driver;
struct usb_gadget gadget;
@@ -79,9 +84,9 @@ struct isp1760_udc {
u16 ep0_length;
bool connected;
+ bool is_isp1763;
unsigned int devstatus;
-#endif
};
#ifdef CONFIG_USB_ISP1761_UDC
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 8a3d9c0c8d8b..e5a8fcdbb78e 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -2098,7 +2098,6 @@ more:{
} else
d += sprintf(d, " ..");
bytes_read += 1;
- continue;
}
goto more;
} else if (packet_bytes > 1) {
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
index aef0a0bba25a..5546b868b08b 100644
--- a/drivers/usb/mtu3/mtu3.h
+++ b/drivers/usb/mtu3/mtu3.h
@@ -10,6 +10,7 @@
#ifndef __MTU3_H__
#define __MTU3_H__
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/dmapool.h>
#include <linux/extcon.h>
@@ -21,6 +22,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
+#include <linux/usb/role.h>
struct mtu3;
struct mtu3_ep;
@@ -88,6 +90,8 @@ struct mtu3_request;
*/
#define EP0_RESPONSE_BUF 6
+#define BULK_CLKS_CNT 4
+
/* device operated link and speed got from DEVICE_CONF register */
enum mtu3_speed {
MTU3_SPEED_INACTIVE = 0,
@@ -192,13 +196,9 @@ struct mtu3_gpd_ring {
/**
* @vbus: vbus 5V used by host mode
* @edev: external connector used to detect vbus and iddig changes
-* @vbus_nb: notifier for vbus detection
-* @vbus_work : work of vbus detection notifier, used to avoid sleep in
-* notifier callback which is atomic context
-* @vbus_event : event of vbus detecion notifier
* @id_nb : notifier for iddig(idpin) detection
-* @id_work : work of iddig detection notifier
-* @id_event : event of iddig detecion notifier
+* @dr_work : work for drd mode switch, used to avoid sleep in atomic context
+* @desired_role : role desired to switch
* @role_sw : use USB Role Switch to support dual-role switch, can't use
* extcon at the same time, and extcon is deprecated.
* @role_sw_used : true when the USB Role Switch is used.
@@ -209,12 +209,9 @@ struct mtu3_gpd_ring {
struct otg_switch_mtk {
struct regulator *vbus;
struct extcon_dev *edev;
- struct notifier_block vbus_nb;
- struct work_struct vbus_work;
- unsigned long vbus_event;
struct notifier_block id_nb;
- struct work_struct id_work;
- unsigned long id_event;
+ struct work_struct dr_work;
+ enum usb_role desired_role;
struct usb_role_switch *role_sw;
bool role_sw_used;
bool is_u3_drd;
@@ -225,10 +222,6 @@ struct otg_switch_mtk {
* @mac_base: register base address of device MAC, exclude xHCI's
* @ippc_base: register base address of IP Power and Clock interface (IPPC)
* @vusb33: usb3.3V shared by device/host IP
- * @sys_clk: system clock of mtu3, shared by device/host IP
- * @ref_clk: reference clock
- * @mcu_clk: mcu_bus_ck clock for AHB bus etc
- * @dma_clk: dma_bus_ck clock for AXI bus etc
* @dr_mode: works in which mode:
* host only, device only or dual-role mode
* @u2_ports: number of usb2.0 host ports
@@ -250,10 +243,7 @@ struct ssusb_mtk {
int num_phys;
/* common power & clock */
struct regulator *vusb33;
- struct clk *sys_clk;
- struct clk *ref_clk;
- struct clk *mcu_clk;
- struct clk *dma_clk;
+ struct clk_bulk_data clks[BULK_CLKS_CNT];
/* otg */
struct otg_switch_mtk otg_switch;
enum usb_dr_mode dr_mode;
@@ -422,11 +412,9 @@ int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
int interval, int burst, int mult);
void mtu3_deconfig_ep(struct mtu3 *mtu, struct mtu3_ep *mep);
void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set);
-void mtu3_ep0_setup(struct mtu3 *mtu);
void mtu3_start(struct mtu3 *mtu);
void mtu3_stop(struct mtu3 *mtu);
void mtu3_dev_on_off(struct mtu3 *mtu, int is_on);
-void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed);
int mtu3_gadget_setup(struct mtu3 *mtu);
void mtu3_gadget_cleanup(struct mtu3 *mtu);
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
index b3b459937566..562f4357831e 100644
--- a/drivers/usb/mtu3/mtu3_core.c
+++ b/drivers/usb/mtu3/mtu3_core.c
@@ -207,7 +207,7 @@ static void mtu3_intr_enable(struct mtu3 *mtu)
mtu3_writel(mbase, U3D_DEV_LINK_INTR_ENABLE, SSUSB_DEV_SPEED_CHG_INTR);
}
-void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed)
+static void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed)
{
void __iomem *mbase = mtu->mac_base;
@@ -334,6 +334,10 @@ void mtu3_start(struct mtu3 *mtu)
mtu3_readl(mbase, U3D_DEVICE_CONTROL));
mtu3_clrbits(mtu->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
+ if (mtu->is_u3_ip)
+ mtu3_clrbits(mtu->ippc_base, SSUSB_U3_CTRL(0), SSUSB_U3_PORT_PDN);
+
+ mtu3_clrbits(mtu->ippc_base, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_PDN);
mtu3_csr_init(mtu);
mtu3_set_speed(mtu, mtu->speed);
@@ -356,6 +360,11 @@ void mtu3_stop(struct mtu3 *mtu)
mtu3_dev_on_off(mtu, 0);
mtu->is_active = 0;
+
+ if (mtu->is_u3_ip)
+ mtu3_setbits(mtu->ippc_base, SSUSB_U3_CTRL(0), SSUSB_U3_PORT_PDN);
+
+ mtu3_setbits(mtu->ippc_base, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_PDN);
mtu3_setbits(mtu->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
}
@@ -536,7 +545,7 @@ static void get_ep_fifo_config(struct mtu3 *mtu)
rx_fifo->base, rx_fifo->limit);
}
-void mtu3_ep0_setup(struct mtu3 *mtu)
+static void mtu3_ep0_setup(struct mtu3 *mtu)
{
u32 maxpacket = mtu->g.ep0->maxpacket;
u32 csr;
@@ -921,16 +930,15 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
device_init_wakeup(dev, true);
+ /* power down device IP for power saving by default */
+ mtu3_stop(mtu);
+
ret = mtu3_gadget_setup(mtu);
if (ret) {
dev_err(dev, "mtu3 gadget init failed:%d\n", ret);
goto gadget_err;
}
- /* init as host mode, power down device IP for power saving */
- if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG)
- mtu3_stop(mtu);
-
ssusb_dev_debugfs_init(ssusb);
dev_dbg(dev, " %s() done...\n", __func__);
diff --git a/drivers/usb/mtu3/mtu3_debugfs.c b/drivers/usb/mtu3/mtu3_debugfs.c
index 7537bfd651af..d27de647c86a 100644
--- a/drivers/usb/mtu3/mtu3_debugfs.c
+++ b/drivers/usb/mtu3/mtu3_debugfs.c
@@ -30,6 +30,7 @@ static const struct debugfs_reg32 mtu3_ippc_regs[] = {
dump_register(SSUSB_IP_PW_CTRL1),
dump_register(SSUSB_IP_PW_CTRL2),
dump_register(SSUSB_IP_PW_CTRL3),
+ dump_register(SSUSB_IP_PW_STS1),
dump_register(SSUSB_OTG_STS),
dump_register(SSUSB_IP_XHCI_CAP),
dump_register(SSUSB_IP_DEV_CAP),
diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c
index 04f666e85731..318fbc618137 100644
--- a/drivers/usb/mtu3/mtu3_dr.c
+++ b/drivers/usb/mtu3/mtu3_dr.c
@@ -7,8 +7,6 @@
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
*/
-#include <linux/usb/role.h>
-
#include "mtu3.h"
#include "mtu3_dr.h"
#include "mtu3_debug.h"
@@ -16,27 +14,9 @@
#define USB2_PORT 2
#define USB3_PORT 3
-enum mtu3_vbus_id_state {
- MTU3_ID_FLOAT = 1,
- MTU3_ID_GROUND,
- MTU3_VBUS_OFF,
- MTU3_VBUS_VALID,
-};
-
-static char *mailbox_state_string(enum mtu3_vbus_id_state state)
+static inline struct ssusb_mtk *otg_sx_to_ssusb(struct otg_switch_mtk *otg_sx)
{
- switch (state) {
- case MTU3_ID_FLOAT:
- return "ID_FLOAT";
- case MTU3_ID_GROUND:
- return "ID_GROUND";
- case MTU3_VBUS_OFF:
- return "VBUS_OFF";
- case MTU3_VBUS_VALID:
- return "VBUS_VALID";
- default:
- return "UNKNOWN";
- }
+ return container_of(otg_sx, struct ssusb_mtk, otg_switch);
}
static void toggle_opstate(struct ssusb_mtk *ssusb)
@@ -123,8 +103,7 @@ static void switch_port_to_device(struct ssusb_mtk *ssusb)
int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
{
- struct ssusb_mtk *ssusb =
- container_of(otg_sx, struct ssusb_mtk, otg_switch);
+ struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx);
struct regulator *vbus = otg_sx->vbus;
int ret;
@@ -147,99 +126,72 @@ int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
return 0;
}
-/*
- * switch to host: -> MTU3_VBUS_OFF --> MTU3_ID_GROUND
- * switch to device: -> MTU3_ID_FLOAT --> MTU3_VBUS_VALID
- */
-static void ssusb_set_mailbox(struct otg_switch_mtk *otg_sx,
- enum mtu3_vbus_id_state status)
+static void ssusb_mode_sw_work(struct work_struct *work)
{
- struct ssusb_mtk *ssusb =
- container_of(otg_sx, struct ssusb_mtk, otg_switch);
+ struct otg_switch_mtk *otg_sx =
+ container_of(work, struct otg_switch_mtk, dr_work);
+ struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx);
struct mtu3 *mtu = ssusb->u3d;
+ enum usb_role desired_role = otg_sx->desired_role;
+ enum usb_role current_role;
+
+ current_role = ssusb->is_host ? USB_ROLE_HOST : USB_ROLE_DEVICE;
+
+ if (desired_role == USB_ROLE_NONE)
+ desired_role = USB_ROLE_HOST;
- dev_dbg(ssusb->dev, "mailbox %s\n", mailbox_state_string(status));
- mtu3_dbg_trace(ssusb->dev, "mailbox %s", mailbox_state_string(status));
+ if (current_role == desired_role)
+ return;
+
+ dev_dbg(ssusb->dev, "set role : %s\n", usb_role_string(desired_role));
+ mtu3_dbg_trace(ssusb->dev, "set role : %s", usb_role_string(desired_role));
- switch (status) {
- case MTU3_ID_GROUND:
+ switch (desired_role) {
+ case USB_ROLE_HOST:
+ ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
+ mtu3_stop(mtu);
switch_port_to_host(ssusb);
ssusb_set_vbus(otg_sx, 1);
ssusb->is_host = true;
break;
- case MTU3_ID_FLOAT:
+ case USB_ROLE_DEVICE:
+ ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_DEVICE);
ssusb->is_host = false;
ssusb_set_vbus(otg_sx, 0);
switch_port_to_device(ssusb);
- break;
- case MTU3_VBUS_OFF:
- mtu3_stop(mtu);
- pm_relax(ssusb->dev);
- break;
- case MTU3_VBUS_VALID:
- /* avoid suspend when works as device */
- pm_stay_awake(ssusb->dev);
mtu3_start(mtu);
break;
+ case USB_ROLE_NONE:
default:
- dev_err(ssusb->dev, "invalid state\n");
+ dev_err(ssusb->dev, "invalid role\n");
}
}
-static void ssusb_id_work(struct work_struct *work)
+static void ssusb_set_mode(struct otg_switch_mtk *otg_sx, enum usb_role role)
{
- struct otg_switch_mtk *otg_sx =
- container_of(work, struct otg_switch_mtk, id_work);
+ struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx);
- if (otg_sx->id_event)
- ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
- else
- ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
-}
-
-static void ssusb_vbus_work(struct work_struct *work)
-{
- struct otg_switch_mtk *otg_sx =
- container_of(work, struct otg_switch_mtk, vbus_work);
+ if (ssusb->dr_mode != USB_DR_MODE_OTG)
+ return;
- if (otg_sx->vbus_event)
- ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
- else
- ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
+ otg_sx->desired_role = role;
+ queue_work(system_freezable_wq, &otg_sx->dr_work);
}
-/*
- * @ssusb_id_notifier is called in atomic context, but @ssusb_set_mailbox
- * may sleep, so use work queue here
- */
static int ssusb_id_notifier(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct otg_switch_mtk *otg_sx =
container_of(nb, struct otg_switch_mtk, id_nb);
- otg_sx->id_event = event;
- schedule_work(&otg_sx->id_work);
-
- return NOTIFY_DONE;
-}
-
-static int ssusb_vbus_notifier(struct notifier_block *nb,
- unsigned long event, void *ptr)
-{
- struct otg_switch_mtk *otg_sx =
- container_of(nb, struct otg_switch_mtk, vbus_nb);
-
- otg_sx->vbus_event = event;
- schedule_work(&otg_sx->vbus_work);
+ ssusb_set_mode(otg_sx, event ? USB_ROLE_HOST : USB_ROLE_DEVICE);
return NOTIFY_DONE;
}
static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
{
- struct ssusb_mtk *ssusb =
- container_of(otg_sx, struct ssusb_mtk, otg_switch);
+ struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx);
struct extcon_dev *edev = otg_sx->edev;
int ret;
@@ -247,14 +199,6 @@ static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
if (!edev)
return 0;
- otg_sx->vbus_nb.notifier_call = ssusb_vbus_notifier;
- ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB,
- &otg_sx->vbus_nb);
- if (ret < 0) {
- dev_err(ssusb->dev, "failed to register notifier for USB\n");
- return ret;
- }
-
otg_sx->id_nb.notifier_call = ssusb_id_notifier;
ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB_HOST,
&otg_sx->id_nb);
@@ -263,15 +207,12 @@ static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
return ret;
}
- dev_dbg(ssusb->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n",
- extcon_get_state(edev, EXTCON_USB),
- extcon_get_state(edev, EXTCON_USB_HOST));
+ ret = extcon_get_state(edev, EXTCON_USB_HOST);
+ dev_dbg(ssusb->dev, "EXTCON_USB_HOST: %d\n", ret);
/* default as host, switch to device mode if needed */
- if (extcon_get_state(edev, EXTCON_USB_HOST) == false)
- ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
- if (extcon_get_state(edev, EXTCON_USB) == true)
- ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
+ if (!ret)
+ ssusb_set_mode(otg_sx, USB_ROLE_DEVICE);
return 0;
}
@@ -286,15 +227,7 @@ void ssusb_mode_switch(struct ssusb_mtk *ssusb, int to_host)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
- if (to_host) {
- ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
- ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
- ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
- } else {
- ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_DEVICE);
- ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
- ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
- }
+ ssusb_set_mode(otg_sx, to_host ? USB_ROLE_HOST : USB_ROLE_DEVICE);
}
void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
@@ -323,13 +256,9 @@ void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
static int ssusb_role_sw_set(struct usb_role_switch *sw, enum usb_role role)
{
struct ssusb_mtk *ssusb = usb_role_switch_get_drvdata(sw);
- bool to_host = false;
-
- if (role == USB_ROLE_HOST)
- to_host = true;
+ struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
- if (to_host ^ ssusb->is_host)
- ssusb_mode_switch(ssusb, to_host);
+ ssusb_set_mode(otg_sx, role);
return 0;
}
@@ -337,18 +266,14 @@ static int ssusb_role_sw_set(struct usb_role_switch *sw, enum usb_role role)
static enum usb_role ssusb_role_sw_get(struct usb_role_switch *sw)
{
struct ssusb_mtk *ssusb = usb_role_switch_get_drvdata(sw);
- enum usb_role role;
-
- role = ssusb->is_host ? USB_ROLE_HOST : USB_ROLE_DEVICE;
- return role;
+ return ssusb->is_host ? USB_ROLE_HOST : USB_ROLE_DEVICE;
}
static int ssusb_role_sw_register(struct otg_switch_mtk *otg_sx)
{
struct usb_role_switch_desc role_sx_desc = { 0 };
- struct ssusb_mtk *ssusb =
- container_of(otg_sx, struct ssusb_mtk, otg_switch);
+ struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx);
if (!otg_sx->role_sw_used)
return 0;
@@ -367,8 +292,7 @@ int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
int ret = 0;
- INIT_WORK(&otg_sx->id_work, ssusb_id_work);
- INIT_WORK(&otg_sx->vbus_work, ssusb_vbus_work);
+ INIT_WORK(&otg_sx->dr_work, ssusb_mode_sw_work);
if (otg_sx->manual_drd_enabled)
ssusb_dr_debugfs_init(ssusb);
@@ -384,7 +308,6 @@ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
- cancel_work_sync(&otg_sx->id_work);
- cancel_work_sync(&otg_sx->vbus_work);
+ cancel_work_sync(&otg_sx->dr_work);
usb_role_switch_unregister(otg_sx->role_sw);
}
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index 38f17d66d5bc..5e21ba05ebf0 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -577,7 +577,7 @@ mtu3_gadget_set_speed(struct usb_gadget *g, enum usb_device_speed speed)
dev_dbg(mtu->dev, "%s %s\n", __func__, usb_speed_string(speed));
spin_lock_irqsave(&mtu->lock, flags);
- mtu3_set_speed(mtu, speed);
+ mtu->speed = speed;
spin_unlock_irqrestore(&mtu->lock, flags);
}
diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c
index 0a8cd446cf1b..93a1a4c11e1e 100644
--- a/drivers/usb/mtu3/mtu3_host.c
+++ b/drivers/usb/mtu3/mtu3_host.c
@@ -213,8 +213,6 @@ int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
static void ssusb_host_setup(struct ssusb_mtk *ssusb)
{
- struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
-
host_ports_num_get(ssusb);
/*
@@ -222,9 +220,7 @@ static void ssusb_host_setup(struct ssusb_mtk *ssusb)
* if support OTG, gadget driver will switch port0 to device mode
*/
ssusb_host_enable(ssusb);
-
- if (otg_sx->manual_drd_enabled)
- ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
+ ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
/* if port0 supports dual-role, works as host mode by default */
ssusb_set_vbus(&ssusb->otg_switch, 1);
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
index 7786a95a874e..c0615f6e5cce 100644
--- a/drivers/usb/mtu3/mtu3_plat.c
+++ b/drivers/usb/mtu3/mtu3_plat.c
@@ -5,7 +5,6 @@
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
*/
-#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
@@ -101,54 +100,6 @@ static void ssusb_phy_power_off(struct ssusb_mtk *ssusb)
phy_power_off(ssusb->phys[i]);
}
-static int ssusb_clks_enable(struct ssusb_mtk *ssusb)
-{
- int ret;
-
- ret = clk_prepare_enable(ssusb->sys_clk);
- if (ret) {
- dev_err(ssusb->dev, "failed to enable sys_clk\n");
- goto sys_clk_err;
- }
-
- ret = clk_prepare_enable(ssusb->ref_clk);
- if (ret) {
- dev_err(ssusb->dev, "failed to enable ref_clk\n");
- goto ref_clk_err;
- }
-
- ret = clk_prepare_enable(ssusb->mcu_clk);
- if (ret) {
- dev_err(ssusb->dev, "failed to enable mcu_clk\n");
- goto mcu_clk_err;
- }
-
- ret = clk_prepare_enable(ssusb->dma_clk);
- if (ret) {
- dev_err(ssusb->dev, "failed to enable dma_clk\n");
- goto dma_clk_err;
- }
-
- return 0;
-
-dma_clk_err:
- clk_disable_unprepare(ssusb->mcu_clk);
-mcu_clk_err:
- clk_disable_unprepare(ssusb->ref_clk);
-ref_clk_err:
- clk_disable_unprepare(ssusb->sys_clk);
-sys_clk_err:
- return ret;
-}
-
-static void ssusb_clks_disable(struct ssusb_mtk *ssusb)
-{
- clk_disable_unprepare(ssusb->dma_clk);
- clk_disable_unprepare(ssusb->mcu_clk);
- clk_disable_unprepare(ssusb->ref_clk);
- clk_disable_unprepare(ssusb->sys_clk);
-}
-
static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
{
int ret = 0;
@@ -159,7 +110,7 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
goto vusb33_err;
}
- ret = ssusb_clks_enable(ssusb);
+ ret = clk_bulk_prepare_enable(BULK_CLKS_CNT, ssusb->clks);
if (ret)
goto clks_err;
@@ -180,7 +131,7 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
phy_err:
ssusb_phy_exit(ssusb);
phy_init_err:
- ssusb_clks_disable(ssusb);
+ clk_bulk_disable_unprepare(BULK_CLKS_CNT, ssusb->clks);
clks_err:
regulator_disable(ssusb->vusb33);
vusb33_err:
@@ -189,7 +140,7 @@ vusb33_err:
static void ssusb_rscs_exit(struct ssusb_mtk *ssusb)
{
- ssusb_clks_disable(ssusb);
+ clk_bulk_disable_unprepare(BULK_CLKS_CNT, ssusb->clks);
regulator_disable(ssusb->vusb33);
ssusb_phy_power_off(ssusb);
ssusb_phy_exit(ssusb);
@@ -215,6 +166,7 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
{
struct device_node *node = pdev->dev.of_node;
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+ struct clk_bulk_data *clks = ssusb->clks;
struct device *dev = &pdev->dev;
int i;
int ret;
@@ -225,23 +177,13 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
return PTR_ERR(ssusb->vusb33);
}
- ssusb->sys_clk = devm_clk_get(dev, "sys_ck");
- if (IS_ERR(ssusb->sys_clk)) {
- dev_err(dev, "failed to get sys clock\n");
- return PTR_ERR(ssusb->sys_clk);
- }
-
- ssusb->ref_clk = devm_clk_get_optional(dev, "ref_ck");
- if (IS_ERR(ssusb->ref_clk))
- return PTR_ERR(ssusb->ref_clk);
-
- ssusb->mcu_clk = devm_clk_get_optional(dev, "mcu_ck");
- if (IS_ERR(ssusb->mcu_clk))
- return PTR_ERR(ssusb->mcu_clk);
-
- ssusb->dma_clk = devm_clk_get_optional(dev, "dma_ck");
- if (IS_ERR(ssusb->dma_clk))
- return PTR_ERR(ssusb->dma_clk);
+ clks[0].id = "sys_ck";
+ clks[1].id = "ref_ck";
+ clks[2].id = "mcu_ck";
+ clks[3].id = "dma_ck";
+ ret = devm_clk_bulk_get_optional(dev, BULK_CLKS_CNT, clks);
+ if (ret)
+ return ret;
ssusb->num_phys = of_count_phandle_with_args(node,
"phys", "#phy-cells");
@@ -299,11 +241,14 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
of_property_read_bool(node, "enable-manual-drd");
otg_sx->role_sw_used = of_property_read_bool(node, "usb-role-switch");
- if (!otg_sx->role_sw_used && of_property_read_bool(node, "extcon")) {
+ if (otg_sx->role_sw_used || otg_sx->manual_drd_enabled)
+ goto out;
+
+ if (of_property_read_bool(node, "extcon")) {
otg_sx->edev = extcon_get_edev_by_phandle(ssusb->dev, 0);
if (IS_ERR(otg_sx->edev)) {
- dev_err(ssusb->dev, "couldn't get extcon device\n");
- return PTR_ERR(otg_sx->edev);
+ return dev_err_probe(dev, PTR_ERR(otg_sx->edev),
+ "couldn't get extcon device\n");
}
}
@@ -461,7 +406,7 @@ static int __maybe_unused mtu3_suspend(struct device *dev)
ssusb_host_disable(ssusb, true);
ssusb_phy_power_off(ssusb);
- ssusb_clks_disable(ssusb);
+ clk_bulk_disable_unprepare(BULK_CLKS_CNT, ssusb->clks);
ssusb_wakeup_set(ssusb, true);
return 0;
@@ -478,7 +423,7 @@ static int __maybe_unused mtu3_resume(struct device *dev)
return 0;
ssusb_wakeup_set(ssusb, false);
- ret = ssusb_clks_enable(ssusb);
+ ret = clk_bulk_prepare_enable(BULK_CLKS_CNT, ssusb->clks);
if (ret)
goto clks_err;
@@ -491,7 +436,7 @@ static int __maybe_unused mtu3_resume(struct device *dev)
return 0;
phy_err:
- ssusb_clks_disable(ssusb);
+ clk_bulk_disable_unprepare(BULK_CLKS_CNT, ssusb->clks);
clks_err:
return ret;
}
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 4c8f0112481f..f7b1d5993f8c 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -480,9 +480,7 @@ int musb_set_host(struct musb *musb)
devctl = musb_read_devctl(musb);
if (!(devctl & MUSB_DEVCTL_BDEVICE)) {
- dev_info(musb->controller,
- "%s: already in host mode: %02x\n",
- __func__, devctl);
+ trace_musb_state(musb, devctl, "Already in host mode");
goto init_data;
}
@@ -499,6 +497,9 @@ int musb_set_host(struct musb *musb)
return error;
}
+ devctl = musb_read_devctl(musb);
+ trace_musb_state(musb, devctl, "Host mode set");
+
init_data:
musb->is_active = 1;
musb->xceiv->otg->state = OTG_STATE_A_IDLE;
@@ -526,10 +527,7 @@ int musb_set_peripheral(struct musb *musb)
devctl = musb_read_devctl(musb);
if (devctl & MUSB_DEVCTL_BDEVICE) {
- dev_info(musb->controller,
- "%s: already in peripheral mode: %02x\n",
- __func__, devctl);
-
+ trace_musb_state(musb, devctl, "Already in peripheral mode");
goto init_data;
}
@@ -546,6 +544,9 @@ int musb_set_peripheral(struct musb *musb)
return error;
}
+ devctl = musb_read_devctl(musb);
+ trace_musb_state(musb, devctl, "Peripheral mode set");
+
init_data:
musb->is_active = 0;
musb->xceiv->otg->state = OTG_STATE_B_IDLE;
@@ -1984,6 +1985,21 @@ ATTRIBUTE_GROUPS(musb);
#define MUSB_QUIRK_A_DISCONNECT_19 ((3 << MUSB_DEVCTL_VBUS_SHIFT) | \
MUSB_DEVCTL_SESSION)
+static bool musb_state_needs_recheck(struct musb *musb, u8 devctl,
+ const char *desc)
+{
+ if (musb->quirk_retries && !musb->flush_irq_work) {
+ trace_musb_state(musb, devctl, desc);
+ schedule_delayed_work(&musb->irq_work,
+ msecs_to_jiffies(1000));
+ musb->quirk_retries--;
+
+ return true;
+ }
+
+ return false;
+}
+
/*
* Check the musb devctl session bit to determine if we want to
* allow PM runtime for the device. In general, we want to keep things
@@ -2004,35 +2020,21 @@ static void musb_pm_runtime_check_session(struct musb *musb)
MUSB_DEVCTL_HR;
switch (devctl & ~s) {
case MUSB_QUIRK_B_DISCONNECT_99:
- if (musb->quirk_retries && !musb->flush_irq_work) {
- musb_dbg(musb, "Poll devctl in case of suspend after disconnect\n");
- schedule_delayed_work(&musb->irq_work,
- msecs_to_jiffies(1000));
- musb->quirk_retries--;
- }
+ musb_state_needs_recheck(musb, devctl,
+ "Poll devctl in case of suspend after disconnect");
break;
case MUSB_QUIRK_B_INVALID_VBUS_91:
- if (musb->quirk_retries && !musb->flush_irq_work) {
- musb_dbg(musb,
- "Poll devctl on invalid vbus, assume no session");
- schedule_delayed_work(&musb->irq_work,
- msecs_to_jiffies(1000));
- musb->quirk_retries--;
+ if (musb_state_needs_recheck(musb, devctl,
+ "Poll devctl on invalid vbus, assume no session"))
return;
- }
fallthrough;
case MUSB_QUIRK_A_DISCONNECT_19:
- if (musb->quirk_retries && !musb->flush_irq_work) {
- musb_dbg(musb,
- "Poll devctl on possible host mode disconnect");
- schedule_delayed_work(&musb->irq_work,
- msecs_to_jiffies(1000));
- musb->quirk_retries--;
+ if (musb_state_needs_recheck(musb, devctl,
+ "Poll devctl on possible host mode disconnect"))
return;
- }
if (!musb->session)
break;
- musb_dbg(musb, "Allow PM on possible host mode disconnect");
+ trace_musb_state(musb, devctl, "Allow PM on possible host mode disconnect");
pm_runtime_mark_last_busy(musb->controller);
pm_runtime_put_autosuspend(musb->controller);
musb->session = false;
@@ -2048,14 +2050,23 @@ static void musb_pm_runtime_check_session(struct musb *musb)
/* Block PM or allow PM? */
if (s) {
- musb_dbg(musb, "Block PM on active session: %02x", devctl);
+ trace_musb_state(musb, devctl, "Block PM on active session");
error = pm_runtime_get_sync(musb->controller);
if (error < 0)
dev_err(musb->controller, "Could not enable: %i\n",
error);
musb->quirk_retries = 3;
+
+ /*
+ * We can get a spurious MUSB_INTR_SESSREQ interrupt on start-up
+ * in B-peripheral mode with nothing connected and the session
+ * bit clears silently. Check status again in 3 seconds.
+ */
+ if (devctl & MUSB_DEVCTL_BDEVICE)
+ schedule_delayed_work(&musb->irq_work,
+ msecs_to_jiffies(3000));
} else {
- musb_dbg(musb, "Allow PM with no session: %02x", devctl);
+ trace_musb_state(musb, devctl, "Allow PM with no session");
pm_runtime_mark_last_busy(musb->controller);
pm_runtime_put_autosuspend(musb->controller);
}
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index ef374d4dd94a..98c0f4c1bffd 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -611,7 +611,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
* mode 0 only. So we do not get endpoint interrupts due to DMA
* completion. We only get interrupts from DMA controller.
*
- * We could operate in DMA mode 1 if we knew the size of the tranfer
+ * We could operate in DMA mode 1 if we knew the size of the transfer
* in advance. For mass storage class, request->length = what the host
* sends, so that'd work. But for pretty much everything else,
* request->length is routinely more than what the host sends. For
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 30c5e7de0761..9ff7d891b4b7 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -563,10 +563,9 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, u8 epnum)
ep->rx_reinit = 0;
}
-static void musb_tx_dma_set_mode_mentor(struct dma_controller *dma,
- struct musb_hw_ep *hw_ep, struct musb_qh *qh,
- struct urb *urb, u32 offset,
- u32 *length, u8 *mode)
+static void musb_tx_dma_set_mode_mentor(struct musb_hw_ep *hw_ep,
+ struct musb_qh *qh,
+ u32 *length, u8 *mode)
{
struct dma_channel *channel = hw_ep->tx_channel;
void __iomem *epio = hw_ep->regs;
@@ -602,12 +601,8 @@ static void musb_tx_dma_set_mode_mentor(struct dma_controller *dma,
musb_writew(epio, MUSB_TXCSR, csr);
}
-static void musb_tx_dma_set_mode_cppi_tusb(struct dma_controller *dma,
- struct musb_hw_ep *hw_ep,
- struct musb_qh *qh,
+static void musb_tx_dma_set_mode_cppi_tusb(struct musb_hw_ep *hw_ep,
struct urb *urb,
- u32 offset,
- u32 *length,
u8 *mode)
{
struct dma_channel *channel = hw_ep->tx_channel;
@@ -630,11 +625,10 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
u8 mode;
if (musb_dma_inventra(hw_ep->musb) || musb_dma_ux500(hw_ep->musb))
- musb_tx_dma_set_mode_mentor(dma, hw_ep, qh, urb, offset,
+ musb_tx_dma_set_mode_mentor(hw_ep, qh,
&length, &mode);
else if (is_cppi_enabled(hw_ep->musb) || tusb_dma_omap(hw_ep->musb))
- musb_tx_dma_set_mode_cppi_tusb(dma, hw_ep, qh, urb, offset,
- &length, &mode);
+ musb_tx_dma_set_mode_cppi_tusb(hw_ep, urb, &mode);
else
return false;
diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h
index 4804d4d85c15..63298bd233e0 100644
--- a/drivers/usb/musb/musb_host.h
+++ b/drivers/usb/musb/musb_host.h
@@ -61,10 +61,6 @@ extern void musb_host_tx(struct musb *, u8);
extern void musb_host_rx(struct musb *, u8);
extern void musb_root_disconnect(struct musb *musb);
extern void musb_host_free(struct musb *);
-extern void musb_host_cleanup(struct musb *);
-extern void musb_host_tx(struct musb *, u8);
-extern void musb_host_rx(struct musb *, u8);
-extern void musb_root_disconnect(struct musb *musb);
extern void musb_host_resume_root_hub(struct musb *musb);
extern void musb_host_poke_root_hub(struct musb *musb);
extern int musb_port_suspend(struct musb *musb, bool do_suspend);
diff --git a/drivers/usb/musb/musb_trace.h b/drivers/usb/musb/musb_trace.h
index 380ebc77eab1..ec28b5716796 100644
--- a/drivers/usb/musb/musb_trace.h
+++ b/drivers/usb/musb/musb_trace.h
@@ -37,6 +37,23 @@ TRACE_EVENT(musb_log,
TP_printk("%s: %s", __get_str(name), __get_str(msg))
);
+TRACE_EVENT(musb_state,
+ TP_PROTO(struct musb *musb, u8 devctl, const char *desc),
+ TP_ARGS(musb, devctl, desc),
+ TP_STRUCT__entry(
+ __string(name, dev_name(musb->controller))
+ __field(u8, devctl)
+ __string(desc, desc)
+ ),
+ TP_fast_assign(
+ __assign_str(name, dev_name(musb->controller));
+ __entry->devctl = devctl;
+ __assign_str(desc, desc);
+ ),
+ TP_printk("%s: devctl: %02x %s", __get_str(name), __entry->devctl,
+ __get_str(desc))
+);
+
DECLARE_EVENT_CLASS(musb_regb,
TP_PROTO(void *caller, const void __iomem *addr,
unsigned int offset, u8 data),
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 4232f1ce3fbf..640a46f0d118 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -33,6 +33,8 @@ struct omap2430_glue {
enum musb_vbus_id_status status;
struct work_struct omap_musb_mailbox_work;
struct device *control_otghs;
+ unsigned int is_runtime_suspended:1;
+ unsigned int needs_resume:1;
};
#define glue_to_musb(g) platform_get_drvdata(g->musb)
@@ -459,6 +461,8 @@ static int omap2430_runtime_suspend(struct device *dev)
phy_power_off(musb->phy);
phy_exit(musb->phy);
+ glue->is_runtime_suspended = 1;
+
return 0;
}
@@ -480,12 +484,40 @@ static int omap2430_runtime_resume(struct device *dev)
/* Wait for musb to get oriented. Otherwise we can get babble */
usleep_range(200000, 250000);
+ glue->is_runtime_suspended = 0;
+
return 0;
}
+static int omap2430_suspend(struct device *dev)
+{
+ struct omap2430_glue *glue = dev_get_drvdata(dev);
+
+ if (glue->is_runtime_suspended)
+ return 0;
+
+ glue->needs_resume = 1;
+
+ return omap2430_runtime_suspend(dev);
+}
+
+static int omap2430_resume(struct device *dev)
+{
+ struct omap2430_glue *glue = dev_get_drvdata(dev);
+
+ if (!glue->needs_resume)
+ return 0;
+
+ glue->needs_resume = 0;
+
+ return omap2430_runtime_resume(dev);
+}
+
static const struct dev_pm_ops omap2430_pm_ops = {
.runtime_suspend = omap2430_runtime_suspend,
.runtime_resume = omap2430_runtime_resume,
+ .suspend = omap2430_suspend,
+ .resume = omap2430_resume,
};
#define DEV_PM_OPS (&omap2430_pm_ops)
diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c
index 02bb7ddd4bd6..f3e9b3b6ac3e 100644
--- a/drivers/usb/phy/phy-isp1301-omap.c
+++ b/drivers/usb/phy/phy-isp1301-omap.c
@@ -555,7 +555,7 @@ pullup:
case OTG_STATE_A_PERIPHERAL:
if (otg_ctrl & OTG_PULLUP)
goto pullup;
- /* FALLTHROUGH */
+ fallthrough;
// case OTG_STATE_B_WAIT_ACON:
default:
pulldown:
diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c
index 6cf6fbd39237..ad3d57f1c273 100644
--- a/drivers/usb/phy/phy-isp1301.c
+++ b/drivers/usb/phy/phy-isp1301.c
@@ -142,24 +142,17 @@ static struct i2c_driver isp1301_driver = {
module_i2c_driver(isp1301_driver);
-static int match(struct device *dev, const void *data)
-{
- const struct device_node *node = (const struct device_node *)data;
- return (dev->of_node == node) &&
- (dev->driver == &isp1301_driver.driver);
-}
-
struct i2c_client *isp1301_get_client(struct device_node *node)
{
- if (node) { /* reference of ISP1301 I2C node via DT */
- struct device *dev = bus_find_device(&i2c_bus_type, NULL,
- node, match);
- if (!dev)
- return NULL;
- return to_i2c_client(dev);
- } else { /* non-DT: only one ISP1301 chip supported */
- return isp1301_i2c_client;
- }
+ struct i2c_client *client;
+
+ /* reference of ISP1301 I2C node via DT */
+ client = of_find_i2c_device_by_node(node);
+ if (client)
+ return client;
+
+ /* non-DT: only one ISP1301 chip supported */
+ return isp1301_i2c_client;
}
EXPORT_SYMBOL_GPL(isp1301_get_client);
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index a48452a6172b..c0f432d509aa 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -58,12 +58,12 @@
#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
#define USB_PHY_VBUS_SENSORS 0x404
-#define B_SESS_VLD_WAKEUP_EN BIT(6)
-#define B_VBUS_VLD_WAKEUP_EN BIT(14)
+#define B_SESS_VLD_WAKEUP_EN BIT(14)
#define A_SESS_VLD_WAKEUP_EN BIT(22)
#define A_VBUS_VLD_WAKEUP_EN BIT(30)
#define USB_PHY_VBUS_WAKEUP_ID 0x408
+#define VBUS_WAKEUP_STS BIT(10)
#define VBUS_WAKEUP_WAKEUP_EN BIT(30)
#define USB1_LEGACY_CTRL 0x410
@@ -544,7 +544,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
val = readl_relaxed(base + USB_PHY_VBUS_SENSORS);
val &= ~(A_VBUS_VLD_WAKEUP_EN | A_SESS_VLD_WAKEUP_EN);
- val &= ~(B_VBUS_VLD_WAKEUP_EN | B_SESS_VLD_WAKEUP_EN);
+ val &= ~(B_SESS_VLD_WAKEUP_EN);
writel_relaxed(val, base + USB_PHY_VBUS_SENSORS);
val = readl_relaxed(base + UTMIP_BAT_CHRG_CFG0);
@@ -642,6 +642,15 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy)
void __iomem *base = phy->regs;
u32 val;
+ /*
+ * Give hardware time to settle down after VBUS disconnection,
+ * otherwise PHY will immediately wake up from suspend.
+ */
+ if (phy->wakeup_enabled && phy->mode != USB_DR_MODE_HOST)
+ readl_relaxed_poll_timeout(base + USB_PHY_VBUS_WAKEUP_ID,
+ val, !(val & VBUS_WAKEUP_STS),
+ 5000, 100000);
+
utmi_phy_clk_disable(phy);
/* PHY won't resume if reset is asserted */
diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c
index b47285f023cf..83ed5089475a 100644
--- a/drivers/usb/phy/phy.c
+++ b/drivers/usb/phy/phy.c
@@ -42,6 +42,12 @@ static const char *const usb_chger_type[] = {
[ACA_TYPE] = "USB_CHARGER_ACA_TYPE",
};
+static const char *const usb_chger_state[] = {
+ [USB_CHARGER_DEFAULT] = "USB_CHARGER_DEFAULT",
+ [USB_CHARGER_PRESENT] = "USB_CHARGER_PRESENT",
+ [USB_CHARGER_ABSENT] = "USB_CHARGER_ABSENT",
+};
+
static struct usb_phy *__usb_find_phy(struct list_head *list,
enum usb_phy_type type)
{
@@ -74,6 +80,18 @@ static struct usb_phy *__of_usb_find_phy(struct device_node *node)
return ERR_PTR(-EPROBE_DEFER);
}
+static struct usb_phy *__device_to_usb_phy(struct device *dev)
+{
+ struct usb_phy *usb_phy;
+
+ list_for_each_entry(usb_phy, &phy_list, head) {
+ if (usb_phy->dev == dev)
+ break;
+ }
+
+ return usb_phy;
+}
+
static void usb_phy_set_default_current(struct usb_phy *usb_phy)
{
usb_phy->chg_cur.sdp_min = DEFAULT_SDP_CUR_MIN;
@@ -105,9 +123,6 @@ static void usb_phy_set_default_current(struct usb_phy *usb_phy)
static void usb_phy_notify_charger_work(struct work_struct *work)
{
struct usb_phy *usb_phy = container_of(work, struct usb_phy, chg_work);
- char uchger_state[50] = { 0 };
- char uchger_type[50] = { 0 };
- char *envp[] = { uchger_state, uchger_type, NULL };
unsigned int min, max;
switch (usb_phy->chg_state) {
@@ -115,15 +130,11 @@ static void usb_phy_notify_charger_work(struct work_struct *work)
usb_phy_get_charger_current(usb_phy, &min, &max);
atomic_notifier_call_chain(&usb_phy->notifier, max, usb_phy);
- snprintf(uchger_state, ARRAY_SIZE(uchger_state),
- "USB_CHARGER_STATE=%s", "USB_CHARGER_PRESENT");
break;
case USB_CHARGER_ABSENT:
usb_phy_set_default_current(usb_phy);
atomic_notifier_call_chain(&usb_phy->notifier, 0, usb_phy);
- snprintf(uchger_state, ARRAY_SIZE(uchger_state),
- "USB_CHARGER_STATE=%s", "USB_CHARGER_ABSENT");
break;
default:
dev_warn(usb_phy->dev, "Unknown USB charger state: %d\n",
@@ -131,9 +142,30 @@ static void usb_phy_notify_charger_work(struct work_struct *work)
return;
}
+ kobject_uevent(&usb_phy->dev->kobj, KOBJ_CHANGE);
+}
+
+static int usb_phy_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct usb_phy *usb_phy;
+ char uchger_state[50] = { 0 };
+ char uchger_type[50] = { 0 };
+
+ usb_phy = __device_to_usb_phy(dev);
+
+ snprintf(uchger_state, ARRAY_SIZE(uchger_state),
+ "USB_CHARGER_STATE=%s", usb_chger_state[usb_phy->chg_state]);
+
snprintf(uchger_type, ARRAY_SIZE(uchger_type),
"USB_CHARGER_TYPE=%s", usb_chger_type[usb_phy->chg_type]);
- kobject_uevent_env(&usb_phy->dev->kobj, KOBJ_CHANGE, envp);
+
+ if (add_uevent_var(env, uchger_state))
+ return -ENOMEM;
+
+ if (add_uevent_var(env, uchger_type))
+ return -ENOMEM;
+
+ return 0;
}
static void __usb_phy_get_charger_type(struct usb_phy *usb_phy)
@@ -661,6 +693,11 @@ out:
}
EXPORT_SYMBOL_GPL(usb_add_phy);
+static struct device_type usb_phy_dev_type = {
+ .name = "usb_phy",
+ .uevent = usb_phy_uevent,
+};
+
/**
* usb_add_phy_dev - declare the USB PHY
* @x: the USB phy to be used; or NULL
@@ -684,6 +721,8 @@ int usb_add_phy_dev(struct usb_phy *x)
if (ret)
return ret;
+ x->dev->type = &usb_phy_dev_type;
+
ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier);
spin_lock_irqsave(&phy_lock, flags);
diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
index 33b637d0d8d9..dfaed7eee94f 100644
--- a/drivers/usb/roles/class.c
+++ b/drivers/usb/roles/class.c
@@ -214,6 +214,15 @@ static const char * const usb_roles[] = {
[USB_ROLE_DEVICE] = "device",
};
+const char *usb_role_string(enum usb_role role)
+{
+ if (role < 0 || role >= ARRAY_SIZE(usb_roles))
+ return "unknown";
+
+ return usb_roles[role];
+}
+EXPORT_SYMBOL_GPL(usb_role_string);
+
static ssize_t
role_show(struct device *dev, struct device_attribute *attr, char *buf)
{
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index ed9193f3bb1a..8107e4b5b03b 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -356,25 +356,7 @@ static void belkin_sa_set_termios(struct tty_struct *tty,
/* set the number of data bits */
if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
- switch (cflag & CSIZE) {
- case CS5:
- urb_value = BELKIN_SA_DATA_BITS(5);
- break;
- case CS6:
- urb_value = BELKIN_SA_DATA_BITS(6);
- break;
- case CS7:
- urb_value = BELKIN_SA_DATA_BITS(7);
- break;
- case CS8:
- urb_value = BELKIN_SA_DATA_BITS(8);
- break;
- default:
- dev_dbg(&port->dev,
- "CSIZE was not CS5-CS8, using default of 8\n");
- urb_value = BELKIN_SA_DATA_BITS(8);
- break;
- }
+ urb_value = BELKIN_SA_DATA_BITS(tty_get_char_size(cflag));
if (BSA_USB_CMD(BELKIN_SA_SET_DATA_BITS_REQUEST, urb_value) < 0)
dev_err(&port->dev, "Set data bits error\n");
}
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index fcb812bc832c..09b845d0da41 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -247,9 +247,9 @@ struct cp210x_serial_private {
#ifdef CONFIG_GPIOLIB
struct gpio_chip gc;
bool gpio_registered;
- u8 gpio_pushpull;
- u8 gpio_altfunc;
- u8 gpio_input;
+ u16 gpio_pushpull;
+ u16 gpio_altfunc;
+ u16 gpio_input;
#endif
u8 partnum;
u32 fw_version;
@@ -534,6 +534,48 @@ struct cp210x_single_port_config {
#define CP2104_GPIO1_RXLED_MODE BIT(1)
#define CP2104_GPIO2_RS485_MODE BIT(2)
+struct cp210x_quad_port_state {
+ __le16 gpio_mode_pb0;
+ __le16 gpio_mode_pb1;
+ __le16 gpio_mode_pb2;
+ __le16 gpio_mode_pb3;
+ __le16 gpio_mode_pb4;
+
+ __le16 gpio_lowpower_pb0;
+ __le16 gpio_lowpower_pb1;
+ __le16 gpio_lowpower_pb2;
+ __le16 gpio_lowpower_pb3;
+ __le16 gpio_lowpower_pb4;
+
+ __le16 gpio_latch_pb0;
+ __le16 gpio_latch_pb1;
+ __le16 gpio_latch_pb2;
+ __le16 gpio_latch_pb3;
+ __le16 gpio_latch_pb4;
+};
+
+/*
+ * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0x49 bytes
+ * on a CP2108 chip.
+ *
+ * See https://www.silabs.com/documents/public/application-notes/an978-cp210x-usb-to-uart-api-specification.pdf
+ */
+struct cp210x_quad_port_config {
+ struct cp210x_quad_port_state reset_state;
+ struct cp210x_quad_port_state suspend_state;
+ u8 ipdelay_ifc[4];
+ u8 enhancedfxn_ifc[4];
+ u8 enhancedfxn_device;
+ u8 extclkfreq[4];
+} __packed;
+
+#define CP2108_EF_IFC_GPIO_TXLED 0x01
+#define CP2108_EF_IFC_GPIO_RXLED 0x02
+#define CP2108_EF_IFC_GPIO_RS485 0x04
+#define CP2108_EF_IFC_GPIO_RS485_LOGIC 0x08
+#define CP2108_EF_IFC_GPIO_CLOCK 0x10
+#define CP2108_EF_IFC_DYNAMIC_SUSPEND 0x40
+
/* CP2102N configuration array indices */
#define CP210X_2NCONFIG_CONFIG_VERSION_IDX 2
#define CP210X_2NCONFIG_GPIO_MODE_IDX 581
@@ -546,13 +588,25 @@ struct cp210x_single_port_config {
#define CP2102N_QFN20_GPIO1_RS485_MODE BIT(4)
#define CP2102N_QFN20_GPIO0_CLK_MODE BIT(6)
-/* CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x2 bytes. */
+/*
+ * CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x02 bytes
+ * for CP2102N, CP2103, CP2104 and CP2105.
+ */
struct cp210x_gpio_write {
u8 mask;
u8 state;
};
/*
+ * CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x04 bytes
+ * for CP2108.
+ */
+struct cp210x_gpio_write16 {
+ __le16 mask;
+ __le16 state;
+};
+
+/*
* Helper to get interface number when we only have struct usb_serial.
*/
static u8 cp210x_interface_num(struct usb_serial *serial)
@@ -1434,52 +1488,84 @@ static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct usb_serial *serial = gpiochip_get_data(gc);
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
- u8 req_type = REQTYPE_DEVICE_TO_HOST;
+ u8 req_type;
+ u16 mask;
int result;
- u8 buf;
-
- if (priv->partnum == CP210X_PARTNUM_CP2105)
- req_type = REQTYPE_INTERFACE_TO_HOST;
+ int len;
result = usb_autopm_get_interface(serial->interface);
if (result)
return result;
- result = cp210x_read_vendor_block(serial, req_type,
- CP210X_READ_LATCH, &buf, sizeof(buf));
+ switch (priv->partnum) {
+ case CP210X_PARTNUM_CP2105:
+ req_type = REQTYPE_INTERFACE_TO_HOST;
+ len = 1;
+ break;
+ case CP210X_PARTNUM_CP2108:
+ req_type = REQTYPE_INTERFACE_TO_HOST;
+ len = 2;
+ break;
+ default:
+ req_type = REQTYPE_DEVICE_TO_HOST;
+ len = 1;
+ break;
+ }
+
+ mask = 0;
+ result = cp210x_read_vendor_block(serial, req_type, CP210X_READ_LATCH,
+ &mask, len);
+
usb_autopm_put_interface(serial->interface);
+
if (result < 0)
return result;
- return !!(buf & BIT(gpio));
+ le16_to_cpus(&mask);
+
+ return !!(mask & BIT(gpio));
}
static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
struct usb_serial *serial = gpiochip_get_data(gc);
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+ struct cp210x_gpio_write16 buf16;
struct cp210x_gpio_write buf;
+ u16 mask, state;
+ u16 wIndex;
int result;
if (value == 1)
- buf.state = BIT(gpio);
+ state = BIT(gpio);
else
- buf.state = 0;
+ state = 0;
- buf.mask = BIT(gpio);
+ mask = BIT(gpio);
result = usb_autopm_get_interface(serial->interface);
if (result)
goto out;
- if (priv->partnum == CP210X_PARTNUM_CP2105) {
+ switch (priv->partnum) {
+ case CP210X_PARTNUM_CP2105:
+ buf.mask = (u8)mask;
+ buf.state = (u8)state;
result = cp210x_write_vendor_block(serial,
REQTYPE_HOST_TO_INTERFACE,
CP210X_WRITE_LATCH, &buf,
sizeof(buf));
- } else {
- u16 wIndex = buf.state << 8 | buf.mask;
-
+ break;
+ case CP210X_PARTNUM_CP2108:
+ buf16.mask = cpu_to_le16(mask);
+ buf16.state = cpu_to_le16(state);
+ result = cp210x_write_vendor_block(serial,
+ REQTYPE_HOST_TO_INTERFACE,
+ CP210X_WRITE_LATCH, &buf16,
+ sizeof(buf16));
+ break;
+ default:
+ wIndex = state << 8 | mask;
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
CP210X_VENDOR_SPECIFIC,
@@ -1487,6 +1573,7 @@ static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
CP210X_WRITE_LATCH,
wIndex,
NULL, 0, USB_CTRL_SET_TIMEOUT);
+ break;
}
usb_autopm_put_interface(serial->interface);
@@ -1696,6 +1783,61 @@ static int cp2104_gpioconf_init(struct usb_serial *serial)
return 0;
}
+static int cp2108_gpio_init(struct usb_serial *serial)
+{
+ struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+ struct cp210x_quad_port_config config;
+ u16 gpio_latch;
+ int result;
+ u8 i;
+
+ result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST,
+ CP210X_GET_PORTCONFIG, &config,
+ sizeof(config));
+ if (result < 0)
+ return result;
+
+ priv->gc.ngpio = 16;
+ priv->gpio_pushpull = le16_to_cpu(config.reset_state.gpio_mode_pb1);
+ gpio_latch = le16_to_cpu(config.reset_state.gpio_latch_pb1);
+
+ /*
+ * Mark all pins which are not in GPIO mode.
+ *
+ * Refer to table 9.1 "GPIO Mode alternate Functions" in the datasheet:
+ * https://www.silabs.com/documents/public/data-sheets/cp2108-datasheet.pdf
+ *
+ * Alternate functions of GPIO0 to GPIO3 are determine by enhancedfxn_ifc[0]
+ * and the similarly for the other pins; enhancedfxn_ifc[1]: GPIO4 to GPIO7,
+ * enhancedfxn_ifc[2]: GPIO8 to GPIO11, enhancedfxn_ifc[3]: GPIO12 to GPIO15.
+ */
+ for (i = 0; i < 4; i++) {
+ if (config.enhancedfxn_ifc[i] & CP2108_EF_IFC_GPIO_TXLED)
+ priv->gpio_altfunc |= BIT(i * 4);
+ if (config.enhancedfxn_ifc[i] & CP2108_EF_IFC_GPIO_RXLED)
+ priv->gpio_altfunc |= BIT((i * 4) + 1);
+ if (config.enhancedfxn_ifc[i] & CP2108_EF_IFC_GPIO_RS485)
+ priv->gpio_altfunc |= BIT((i * 4) + 2);
+ if (config.enhancedfxn_ifc[i] & CP2108_EF_IFC_GPIO_CLOCK)
+ priv->gpio_altfunc |= BIT((i * 4) + 3);
+ }
+
+ /*
+ * Like CP2102N, CP2108 has also no strict input and output pin
+ * modes. Do the same input mode emulation as CP2102N.
+ */
+ for (i = 0; i < priv->gc.ngpio; ++i) {
+ /*
+ * Set direction to "input" iff pin is open-drain and reset
+ * value is 1.
+ */
+ if (!(priv->gpio_pushpull & BIT(i)) && (gpio_latch & BIT(i)))
+ priv->gpio_input |= BIT(i);
+ }
+
+ return 0;
+}
+
static int cp2102n_gpioconf_init(struct usb_serial *serial)
{
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
@@ -1812,6 +1954,15 @@ static int cp210x_gpio_init(struct usb_serial *serial)
case CP210X_PARTNUM_CP2105:
result = cp2105_gpioconf_init(serial);
break;
+ case CP210X_PARTNUM_CP2108:
+ /*
+ * The GPIOs are not tied to any specific port so only register
+ * once for interface 0.
+ */
+ if (cp210x_interface_num(serial) != 0)
+ return 0;
+ result = cp2108_gpio_init(serial);
+ break;
case CP210X_PARTNUM_CP2102N_QFN28:
case CP210X_PARTNUM_CP2102N_QFN24:
case CP210X_PARTNUM_CP2102N_QFN20:
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index cf389224d528..51e5aac3bf4c 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -53,7 +53,7 @@ static int cyberjack_open(struct tty_struct *tty,
static void cyberjack_close(struct usb_serial_port *port);
static int cyberjack_write(struct tty_struct *tty,
struct usb_serial_port *port, const unsigned char *buf, int count);
-static int cyberjack_write_room(struct tty_struct *tty);
+static unsigned int cyberjack_write_room(struct tty_struct *tty);
static void cyberjack_read_int_callback(struct urb *urb);
static void cyberjack_read_bulk_callback(struct urb *urb);
static void cyberjack_write_bulk_callback(struct urb *urb);
@@ -240,7 +240,7 @@ static int cyberjack_write(struct tty_struct *tty,
return count;
}
-static int cyberjack_write_room(struct tty_struct *tty)
+static unsigned int cyberjack_write_room(struct tty_struct *tty)
{
/* FIXME: .... */
return CYBERJACK_LOCAL_BUF_SIZE;
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 166ee2286fda..6b18990258c3 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -122,14 +122,14 @@ static void cypress_dtr_rts(struct usb_serial_port *port, int on);
static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static void cypress_send(struct usb_serial_port *port);
-static int cypress_write_room(struct tty_struct *tty);
+static unsigned int cypress_write_room(struct tty_struct *tty);
static void cypress_earthmate_init_termios(struct tty_struct *tty);
static void cypress_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static int cypress_tiocmget(struct tty_struct *tty);
static int cypress_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
-static int cypress_chars_in_buffer(struct tty_struct *tty);
+static unsigned int cypress_chars_in_buffer(struct tty_struct *tty);
static void cypress_throttle(struct tty_struct *tty);
static void cypress_unthrottle(struct tty_struct *tty);
static void cypress_set_dead(struct usb_serial_port *port);
@@ -326,7 +326,7 @@ static int cypress_serial_control(struct tty_struct *tty,
/* fill the feature_buffer with new configuration */
put_unaligned_le32(new_baudrate, feature_buffer);
- feature_buffer[4] |= data_bits; /* assign data bits in 2 bit space ( max 3 ) */
+ feature_buffer[4] |= data_bits - 5; /* assign data bits in 2 bit space ( max 3 ) */
/* 1 bit gap */
feature_buffer[4] |= (stop_bits << 3); /* assign stop bits in 1 bit space */
feature_buffer[4] |= (parity_enable << 4); /* assign parity flag in 1 bit space */
@@ -789,18 +789,18 @@ send:
/* returns how much space is available in the soft buffer */
-static int cypress_write_room(struct tty_struct *tty)
+static unsigned int cypress_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct cypress_private *priv = usb_get_serial_port_data(port);
- int room = 0;
+ unsigned int room;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
room = kfifo_avail(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, room);
return room;
}
@@ -887,23 +887,8 @@ static void cypress_set_termios(struct tty_struct *tty,
} else
parity_enable = parity_type = 0;
- switch (cflag & CSIZE) {
- case CS5:
- data_bits = 0;
- break;
- case CS6:
- data_bits = 1;
- break;
- case CS7:
- data_bits = 2;
- break;
- case CS8:
- data_bits = 3;
- break;
- default:
- dev_err(dev, "%s - CSIZE was set, but not CS5-CS8\n", __func__);
- data_bits = 3;
- }
+ data_bits = tty_get_char_size(cflag);
+
spin_lock_irqsave(&priv->lock, flags);
oldlines = priv->line_control;
if ((cflag & CBAUD) == B0) {
@@ -970,18 +955,18 @@ static void cypress_set_termios(struct tty_struct *tty,
/* returns amount of data still left in soft buffer */
-static int cypress_chars_in_buffer(struct tty_struct *tty)
+static unsigned int cypress_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct cypress_private *priv = usb_get_serial_port_data(port);
- int chars = 0;
+ unsigned int chars;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
chars = kfifo_len(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars);
return chars;
}
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 8b2f06539f2c..af65eb863d70 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -223,8 +223,8 @@ static int digi_tiocmset(struct tty_struct *tty, unsigned int set,
static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static void digi_write_bulk_callback(struct urb *urb);
-static int digi_write_room(struct tty_struct *tty);
-static int digi_chars_in_buffer(struct tty_struct *tty);
+static unsigned int digi_write_room(struct tty_struct *tty);
+static unsigned int digi_chars_in_buffer(struct tty_struct *tty);
static int digi_open(struct tty_struct *tty, struct usb_serial_port *port);
static void digi_close(struct usb_serial_port *port);
static void digi_dtr_rts(struct usb_serial_port *port, int on);
@@ -372,7 +372,7 @@ static int digi_write_oob_command(struct usb_serial_port *port,
int len;
struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port;
struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);
- unsigned long flags = 0;
+ unsigned long flags;
dev_dbg(&port->dev,
"digi_write_oob_command: TOP: port=%d, count=%d\n",
@@ -430,7 +430,7 @@ static int digi_write_inb_command(struct usb_serial_port *port,
int len;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned char *data = port->write_urb->transfer_buffer;
- unsigned long flags = 0;
+ unsigned long flags;
dev_dbg(&port->dev, "digi_write_inb_command: TOP: port=%d, count=%d\n",
priv->dp_port_num, count);
@@ -511,8 +511,7 @@ static int digi_set_modem_signals(struct usb_serial_port *port,
struct usb_serial_port *oob_port = (struct usb_serial_port *) ((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port;
struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);
unsigned char *data = oob_port->write_urb->transfer_buffer;
- unsigned long flags = 0;
-
+ unsigned long flags;
dev_dbg(&port->dev,
"digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x\n",
@@ -577,7 +576,7 @@ static int digi_transmit_idle(struct usb_serial_port *port,
int ret;
unsigned char buf[2];
struct digi_port *priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_transmit_idle = 0;
@@ -887,7 +886,7 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
int ret, data_len, new_len;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned char *data = port->write_urb->transfer_buffer;
- unsigned long flags = 0;
+ unsigned long flags;
dev_dbg(&port->dev, "digi_write: TOP: port=%d, count=%d\n",
priv->dp_port_num, count);
@@ -1020,12 +1019,12 @@ static void digi_write_bulk_callback(struct urb *urb)
tty_port_tty_wakeup(&port->port);
}
-static int digi_write_room(struct tty_struct *tty)
+static unsigned int digi_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct digi_port *priv = usb_get_serial_port_data(port);
- int room;
- unsigned long flags = 0;
+ unsigned long flags;
+ unsigned int room;
spin_lock_irqsave(&priv->dp_port_lock, flags);
@@ -1035,27 +1034,28 @@ static int digi_write_room(struct tty_struct *tty)
room = port->bulk_out_size - 2 - priv->dp_out_buf_len;
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
- dev_dbg(&port->dev, "digi_write_room: port=%d, room=%d\n", priv->dp_port_num, room);
+ dev_dbg(&port->dev, "digi_write_room: port=%d, room=%u\n", priv->dp_port_num, room);
return room;
}
-static int digi_chars_in_buffer(struct tty_struct *tty)
+static unsigned int digi_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct digi_port *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int chars;
- if (priv->dp_write_urb_in_use) {
- dev_dbg(&port->dev, "digi_chars_in_buffer: port=%d, chars=%d\n",
- priv->dp_port_num, port->bulk_out_size - 2);
- /* return(port->bulk_out_size - 2); */
- return 256;
- } else {
- dev_dbg(&port->dev, "digi_chars_in_buffer: port=%d, chars=%d\n",
- priv->dp_port_num, priv->dp_out_buf_len);
- return priv->dp_out_buf_len;
- }
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
+ if (priv->dp_write_urb_in_use)
+ chars = port->bulk_out_size - 2;
+ else
+ chars = priv->dp_out_buf_len;
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ dev_dbg(&port->dev, "%s: port=%d, chars=%d\n", __func__,
+ priv->dp_port_num, chars);
+ return chars;
}
static void digi_dtr_rts(struct usb_serial_port *port, int on)
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 50e8bdc77e71..756d1ac7e96f 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1113,7 +1113,7 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port,
}
-static int garmin_write_room(struct tty_struct *tty)
+static unsigned int garmin_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
/*
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index d10aa3d2ee49..15b6dee3a8e5 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -230,11 +230,11 @@ int usb_serial_generic_write(struct tty_struct *tty,
}
EXPORT_SYMBOL_GPL(usb_serial_generic_write);
-int usb_serial_generic_write_room(struct tty_struct *tty)
+unsigned int usb_serial_generic_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
unsigned long flags;
- int room;
+ unsigned int room;
if (!port->bulk_out_size)
return 0;
@@ -243,15 +243,15 @@ int usb_serial_generic_write_room(struct tty_struct *tty)
room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&port->lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, room);
return room;
}
-int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
+unsigned int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
unsigned long flags;
- int chars;
+ unsigned int chars;
if (!port->bulk_out_size)
return 0;
@@ -260,7 +260,7 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
chars = kfifo_len(&port->write_fifo) + port->tx_bytes;
spin_unlock_irqrestore(&port->lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars);
return chars;
}
EXPORT_SYMBOL_GPL(usb_serial_generic_chars_in_buffer);
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index e6fe3882bf69..ea4edf5eed27 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -1351,33 +1351,21 @@ exit_send:
/*****************************************************************************
* edge_write_room
* this function is called by the tty driver when it wants to know how
- * many bytes of data we can accept for a specific port. If successful,
- * we return the amount of room that we have for this port (the txCredits)
- * otherwise we return a negative error number.
+ * many bytes of data we can accept for a specific port.
*****************************************************************************/
-static int edge_write_room(struct tty_struct *tty)
+static unsigned int edge_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- int room;
+ unsigned int room;
unsigned long flags;
- if (edge_port == NULL)
- return 0;
- if (edge_port->closePending)
- return 0;
-
- if (!edge_port->open) {
- dev_dbg(&port->dev, "%s - port not opened\n", __func__);
- return 0;
- }
-
/* total of both buffers is still txCredit */
spin_lock_irqsave(&edge_port->ep_lock, flags);
room = edge_port->txCredits - edge_port->txfifo.count;
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, room);
return room;
}
@@ -1387,33 +1375,20 @@ static int edge_write_room(struct tty_struct *tty)
* this function is called by the tty driver when it wants to know how
* many bytes of data we currently have outstanding in the port (data that
* has been written, but hasn't made it out the port yet)
- * If successful, we return the number of bytes left to be written in the
- * system,
- * Otherwise we return a negative error number.
*****************************************************************************/
-static int edge_chars_in_buffer(struct tty_struct *tty)
+static unsigned int edge_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- int num_chars;
+ unsigned int num_chars;
unsigned long flags;
- if (edge_port == NULL)
- return 0;
- if (edge_port->closePending)
- return 0;
-
- if (!edge_port->open) {
- dev_dbg(&port->dev, "%s - port not opened\n", __func__);
- return 0;
- }
-
spin_lock_irqsave(&edge_port->ep_lock, flags);
num_chars = edge_port->maxTxCredits - edge_port->txCredits +
edge_port->txfifo.count;
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
if (num_chars) {
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, num_chars);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, num_chars);
}
return num_chars;
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 39503fdccebf..84b848d2794e 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2067,11 +2067,11 @@ static void edge_send(struct usb_serial_port *port, struct tty_struct *tty)
tty_wakeup(tty);
}
-static int edge_write_room(struct tty_struct *tty)
+static unsigned int edge_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- int room = 0;
+ unsigned int room;
unsigned long flags;
if (edge_port == NULL)
@@ -2083,15 +2083,15 @@ static int edge_write_room(struct tty_struct *tty)
room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, room);
return room;
}
-static int edge_chars_in_buffer(struct tty_struct *tty)
+static unsigned int edge_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- int chars = 0;
+ unsigned int chars;
unsigned long flags;
if (edge_port == NULL)
return 0;
@@ -2100,7 +2100,7 @@ static int edge_chars_in_buffer(struct tty_struct *tty)
chars = kfifo_len(&port->write_fifo);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars);
return chars;
}
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 172261a908d8..7b44dbea95cd 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -47,7 +47,7 @@ static int xbof = -1;
static int ir_startup (struct usb_serial *serial);
static int ir_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
-static int ir_write_room(struct tty_struct *tty);
+static unsigned int ir_write_room(struct tty_struct *tty);
static void ir_write_bulk_callback(struct urb *urb);
static void ir_process_read_urb(struct urb *urb);
static void ir_set_termios(struct tty_struct *tty,
@@ -339,10 +339,10 @@ static void ir_write_bulk_callback(struct urb *urb)
usb_serial_port_softint(port);
}
-static int ir_write_room(struct tty_struct *tty)
+static unsigned int ir_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int count = 0;
+ unsigned int count = 0;
if (port->bulk_out_size == 0)
return 0;
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index b04a029e3657..87b89c99d517 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -1453,13 +1453,13 @@ static void usa67_glocont_callback(struct urb *urb)
}
}
-static int keyspan_write_room(struct tty_struct *tty)
+static unsigned int keyspan_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct keyspan_port_private *p_priv;
const struct keyspan_device_details *d_details;
int flip;
- int data_len;
+ unsigned int data_len;
struct urb *this_urb;
p_priv = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index a9bc546626ab..4ed8b8b0a361 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -53,7 +53,7 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port);
static void kobil_close(struct usb_serial_port *port);
static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
-static int kobil_write_room(struct tty_struct *tty);
+static unsigned int kobil_write_room(struct tty_struct *tty);
static int kobil_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
static int kobil_tiocmget(struct tty_struct *tty);
@@ -358,7 +358,7 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
}
-static int kobil_write_room(struct tty_struct *tty)
+static unsigned int kobil_write_room(struct tty_struct *tty)
{
/* FIXME */
return 8;
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index f9ce9e7b9b80..30ab565e0738 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -109,9 +109,9 @@ static void metrousb_read_int_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
+ unsigned long flags;
int throttled = 0;
int result = 0;
- unsigned long flags = 0;
dev_dbg(&port->dev, "%s\n", __func__);
@@ -171,7 +171,7 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
int result = 0;
/* Set the private data information for the port. */
@@ -268,7 +268,7 @@ static void metrousb_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
/* Set the private information for the port to stop reading data. */
spin_lock_irqsave(&metro_priv->lock, flags);
@@ -281,7 +281,7 @@ static int metrousb_tiocmget(struct tty_struct *tty)
unsigned long control_state = 0;
struct usb_serial_port *port = tty->driver_data;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
spin_lock_irqsave(&metro_priv->lock, flags);
control_state = metro_priv->control_state;
@@ -296,7 +296,7 @@ static int metrousb_tiocmset(struct tty_struct *tty,
struct usb_serial_port *port = tty->driver_data;
struct usb_serial *serial = port->serial;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
unsigned long control_state = 0;
dev_dbg(&port->dev, "%s - set=%d, clear=%d\n", __func__, set, clear);
@@ -323,7 +323,7 @@ static void metrousb_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
+ unsigned long flags;
int result = 0;
/* Set the private information for the port to resume reading data. */
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 6ee83886e2c9..227f43d2bd56 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -945,27 +945,20 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
* this function is called by the tty driver when it wants to know how many
* bytes of data we currently have outstanding in the port (data that has
* been written, but hasn't made it out the port yet)
- * If successful, we return the number of bytes left to be written in the
- * system,
- * Otherwise we return a negative error number.
*/
-static int mos7720_chars_in_buffer(struct tty_struct *tty)
+static unsigned int mos7720_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
+ struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
int i;
- int chars = 0;
- struct moschip_port *mos7720_port;
-
- mos7720_port = usb_get_serial_port_data(port);
- if (mos7720_port == NULL)
- return 0;
+ unsigned int chars = 0;
for (i = 0; i < NUM_URBS; ++i) {
if (mos7720_port->write_urb_pool[i] &&
mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
chars += URB_TRANSFER_BUFFER_SIZE;
}
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars);
return chars;
}
@@ -1030,20 +1023,14 @@ static void mos7720_break(struct tty_struct *tty, int break_state)
* mos7720_write_room
* this function is called by the tty driver when it wants to know how many
* bytes of data we can accept for a specific port.
- * If successful, we return the amount of room that we have for this port
- * Otherwise we return a negative error number.
*/
-static int mos7720_write_room(struct tty_struct *tty)
+static unsigned int mos7720_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- struct moschip_port *mos7720_port;
- int room = 0;
+ struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
+ unsigned int room = 0;
int i;
- mos7720_port = usb_get_serial_port_data(port);
- if (mos7720_port == NULL)
- return 0;
-
/* FIXME: Locking */
for (i = 0; i < NUM_URBS; ++i) {
if (mos7720_port->write_urb_pool[i] &&
@@ -1051,7 +1038,7 @@ static int mos7720_write_room(struct tty_struct *tty)
room += URB_TRANSFER_BUFFER_SIZE;
}
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, room);
return room;
}
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 28e4093794e0..d7fe33ca73e4 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -730,17 +730,14 @@ err:
* this function is called by the tty driver when it wants to know how many
* bytes of data we currently have outstanding in the port (data that has
* been written, but hasn't made it out the port yet)
- * If successful, we return the number of bytes left to be written in the
- * system,
- * Otherwise we return zero.
*****************************************************************************/
-static int mos7840_chars_in_buffer(struct tty_struct *tty)
+static unsigned int mos7840_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct moschip_port *mos7840_port = usb_get_serial_port_data(port);
int i;
- int chars = 0;
+ unsigned int chars = 0;
unsigned long flags;
spin_lock_irqsave(&mos7840_port->pool_lock, flags);
@@ -751,7 +748,7 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty)
}
}
spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars);
return chars;
}
@@ -814,16 +811,14 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
* mos7840_write_room
* this function is called by the tty driver when it wants to know how many
* bytes of data we can accept for a specific port.
- * If successful, we return the amount of room that we have for this port
- * Otherwise we return a negative error number.
*****************************************************************************/
-static int mos7840_write_room(struct tty_struct *tty)
+static unsigned int mos7840_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct moschip_port *mos7840_port = usb_get_serial_port_data(port);
int i;
- int room = 0;
+ unsigned int room = 0;
unsigned long flags;
spin_lock_irqsave(&mos7840_port->pool_lock, flags);
@@ -834,7 +829,7 @@ static int mos7840_write_room(struct tty_struct *tty)
spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
room = (room == 0) ? 0 : room - URB_TRANSFER_BUFFER_SIZE + 1;
- dev_dbg(&mos7840_port->port->dev, "%s - returns %d\n", __func__, room);
+ dev_dbg(&mos7840_port->port->dev, "%s - returns %u\n", __func__, room);
return room;
}
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index 40c713fae0c3..aed28c35caff 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -267,7 +267,7 @@ error_no_buffer:
return ret;
}
-static int opticon_write_room(struct tty_struct *tty)
+static unsigned int opticon_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct opticon_private *priv = usb_get_serial_port_data(port);
@@ -289,12 +289,12 @@ static int opticon_write_room(struct tty_struct *tty)
return 2048;
}
-static int opticon_chars_in_buffer(struct tty_struct *tty)
+static unsigned int opticon_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct opticon_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- int count;
+ unsigned int count;
spin_lock_irqsave(&priv->lock, flags);
count = priv->outstanding_bytes;
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 65cd0341fa78..a5caedbe72e2 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -126,8 +126,8 @@ static void oti6858_read_bulk_callback(struct urb *urb);
static void oti6858_write_bulk_callback(struct urb *urb);
static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
-static int oti6858_write_room(struct tty_struct *tty);
-static int oti6858_chars_in_buffer(struct tty_struct *tty);
+static unsigned int oti6858_write_room(struct tty_struct *tty);
+static unsigned int oti6858_chars_in_buffer(struct tty_struct *tty);
static int oti6858_tiocmget(struct tty_struct *tty);
static int oti6858_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
@@ -363,10 +363,10 @@ static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port,
return count;
}
-static int oti6858_write_room(struct tty_struct *tty)
+static unsigned int oti6858_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int room = 0;
+ unsigned int room;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
@@ -376,10 +376,10 @@ static int oti6858_write_room(struct tty_struct *tty)
return room;
}
-static int oti6858_chars_in_buffer(struct tty_struct *tty)
+static unsigned int oti6858_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int chars = 0;
+ unsigned int chars;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 940050c31482..2f2f5047452b 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -789,20 +789,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
pl2303_get_line_request(port, buf);
- switch (C_CSIZE(tty)) {
- case CS5:
- buf[6] = 5;
- break;
- case CS6:
- buf[6] = 6;
- break;
- case CS7:
- buf[6] = 7;
- break;
- default:
- case CS8:
- buf[6] = 8;
- }
+ buf[6] = tty_get_char_size(tty->termios.c_cflag);
dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
/* For reference buf[0]:buf[3] baud rate value */
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index 067690dac24c..971907f083a3 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -870,12 +870,12 @@ static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch)
}
-static int qt2_write_room(struct tty_struct *tty)
+static unsigned int qt2_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct qt2_port_private *port_priv;
- unsigned long flags = 0;
- int r;
+ unsigned long flags;
+ unsigned int r;
port_priv = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 54e16ffc30a0..4b49b7c33364 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -613,7 +613,7 @@ static void sierra_instat_callback(struct urb *urb)
}
}
-static int sierra_write_room(struct tty_struct *tty)
+static unsigned int sierra_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct sierra_port_private *portdata = usb_get_serial_port_data(port);
@@ -632,19 +632,19 @@ static int sierra_write_room(struct tty_struct *tty)
return 2048;
}
-static int sierra_chars_in_buffer(struct tty_struct *tty)
+static unsigned int sierra_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct sierra_port_private *portdata = usb_get_serial_port_data(port);
unsigned long flags;
- int chars;
+ unsigned int chars;
/* NOTE: This overcounts somewhat. */
spin_lock_irqsave(&portdata->lock, flags);
chars = portdata->outstanding_urbs * MAX_TRANSFER;
spin_unlock_irqrestore(&portdata->lock, flags);
- dev_dbg(&port->dev, "%s - %d\n", __func__, chars);
+ dev_dbg(&port->dev, "%s - %u\n", __func__, chars);
return chars;
}
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 310db5abea9d..18c0bd853392 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -308,8 +308,8 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port);
static void ti_close(struct usb_serial_port *port);
static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *data, int count);
-static int ti_write_room(struct tty_struct *tty);
-static int ti_chars_in_buffer(struct tty_struct *tty);
+static unsigned int ti_write_room(struct tty_struct *tty);
+static unsigned int ti_chars_in_buffer(struct tty_struct *tty);
static bool ti_tx_empty(struct usb_serial_port *port);
static void ti_throttle(struct tty_struct *tty);
static void ti_unthrottle(struct tty_struct *tty);
@@ -813,34 +813,34 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
}
-static int ti_write_room(struct tty_struct *tty)
+static unsigned int ti_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct ti_port *tport = usb_get_serial_port_data(port);
- int room = 0;
+ unsigned int room;
unsigned long flags;
spin_lock_irqsave(&tport->tp_lock, flags);
room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&tport->tp_lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, room);
return room;
}
-static int ti_chars_in_buffer(struct tty_struct *tty)
+static unsigned int ti_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct ti_port *tport = usb_get_serial_port_data(port);
- int chars = 0;
+ unsigned int chars;
unsigned long flags;
spin_lock_irqsave(&tport->tp_lock, flags);
chars = kfifo_len(&port->write_fifo);
spin_unlock_irqrestore(&tport->tp_lock, flags);
- dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
+ dev_dbg(&port->dev, "%s - returns %u\n", __func__, chars);
return chars;
}
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 98b33b1b5357..eeb441c77207 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -376,7 +376,7 @@ exit:
return retval;
}
-static int serial_write_room(struct tty_struct *tty)
+static unsigned int serial_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
@@ -385,7 +385,7 @@ static int serial_write_room(struct tty_struct *tty)
return port->serial->type->write_room(tty);
}
-static int serial_chars_in_buffer(struct tty_struct *tty)
+static unsigned int serial_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct usb_serial *serial = port->serial;
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h
index b5331d03092f..519101945769 100644
--- a/drivers/usb/serial/usb-wwan.h
+++ b/drivers/usb/serial/usb-wwan.h
@@ -11,13 +11,13 @@ extern int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port);
extern void usb_wwan_close(struct usb_serial_port *port);
extern int usb_wwan_port_probe(struct usb_serial_port *port);
extern void usb_wwan_port_remove(struct usb_serial_port *port);
-extern int usb_wwan_write_room(struct tty_struct *tty);
+extern unsigned int usb_wwan_write_room(struct tty_struct *tty);
extern int usb_wwan_tiocmget(struct tty_struct *tty);
extern int usb_wwan_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
-extern int usb_wwan_chars_in_buffer(struct tty_struct *tty);
+extern unsigned int usb_wwan_chars_in_buffer(struct tty_struct *tty);
#ifdef CONFIG_PM
extern int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message);
extern int usb_wwan_resume(struct usb_serial *serial);
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 3eb72c59ede6..cb01283d4d15 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -278,12 +278,12 @@ static void usb_wwan_outdat_callback(struct urb *urb)
}
}
-int usb_wwan_write_room(struct tty_struct *tty)
+unsigned int usb_wwan_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct usb_wwan_port_private *portdata;
int i;
- int data_len = 0;
+ unsigned int data_len = 0;
struct urb *this_urb;
portdata = usb_get_serial_port_data(port);
@@ -294,17 +294,17 @@ int usb_wwan_write_room(struct tty_struct *tty)
data_len += OUT_BUFLEN;
}
- dev_dbg(&port->dev, "%s: %d\n", __func__, data_len);
+ dev_dbg(&port->dev, "%s: %u\n", __func__, data_len);
return data_len;
}
EXPORT_SYMBOL(usb_wwan_write_room);
-int usb_wwan_chars_in_buffer(struct tty_struct *tty)
+unsigned int usb_wwan_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct usb_wwan_port_private *portdata;
int i;
- int data_len = 0;
+ unsigned int data_len = 0;
struct urb *this_urb;
portdata = usb_get_serial_port_data(port);
@@ -316,7 +316,7 @@ int usb_wwan_chars_in_buffer(struct tty_struct *tty)
if (this_urb && test_bit(i, &portdata->out_busy))
data_len += this_urb->transfer_buffer_length;
}
- dev_dbg(&port->dev, "%s: %d\n", __func__, data_len);
+ dev_dbg(&port->dev, "%s: %u\n", __func__, data_len);
return data_len;
}
EXPORT_SYMBOL(usb_wwan_chars_in_buffer);
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 5116ed9db3eb..da65d14c9ed5 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -625,14 +625,7 @@ static void firm_setup_port(struct tty_struct *tty)
port_settings.port = port->port_number + 1;
- /* get the byte size */
- switch (cflag & CSIZE) {
- case CS5: port_settings.bits = 5; break;
- case CS6: port_settings.bits = 6; break;
- case CS7: port_settings.bits = 7; break;
- default:
- case CS8: port_settings.bits = 8; break;
- }
+ port_settings.bits = tty_get_char_size(cflag);
dev_dbg(dev, "%s - data bits = %d\n", __func__, port_settings.bits);
/* determine the parity */
diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c
index a6f3267bbef6..2f7093ba5a2f 100644
--- a/drivers/usb/storage/cypress_atacb.c
+++ b/drivers/usb/storage/cypress_atacb.c
@@ -221,11 +221,11 @@ static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
desc[12] = regs[6]; /* device */
desc[13] = regs[7]; /* command */
- srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+ srb->result = SAM_STAT_CHECK_CONDITION;
}
goto end;
invalid_fld:
- srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+ srb->result = SAM_STAT_CHECK_CONDITION;
memcpy(srb->sense_buffer,
usb_stor_sense_invalidCDB,
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index b9429c9f65f6..aeef453aa658 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -517,8 +517,10 @@ typec_register_altmode(struct device *parent,
int ret;
alt = kzalloc(sizeof(*alt), GFP_KERNEL);
- if (!alt)
+ if (!alt) {
+ altmode_id_remove(parent, id);
return ERR_PTR(-ENOMEM);
+ }
alt->adev.svid = desc->svid;
alt->adev.mode = desc->mode;
diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c
index 77dabd306ba8..c8340de0ed49 100644
--- a/drivers/usb/typec/mux.c
+++ b/drivers/usb/typec/mux.c
@@ -17,21 +17,12 @@
#include "class.h"
#include "mux.h"
-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");
+ if (!is_typec_switch(dev))
+ return 0;
+
+ return dev_fwnode(dev) == fwnode;
}
static void *typec_switch_match(struct fwnode_handle *fwnode, const char *id,
@@ -39,9 +30,22 @@ static void *typec_switch_match(struct fwnode_handle *fwnode, const char *id,
{
struct device *dev;
+ /*
+ * Device graph (OF graph) does not give any means to identify the
+ * device type or the device class of the remote port parent that @fwnode
+ * represents, so in order to identify the type or the class of @fwnode
+ * an additional device property is needed. With typec switches the
+ * property is named "orientation-switch" (@id). The value of the device
+ * property is ignored.
+ */
if (id && !fwnode_property_present(fwnode, id))
return NULL;
+ /*
+ * At this point we are sure that @fwnode is a typec switch in all
+ * cases. If the switch hasn't yet been registered for some reason, the
+ * function "defers probe" for now.
+ */
dev = class_find_device(&typec_mux_class, NULL, fwnode,
switch_fwnode_match);
@@ -90,7 +94,7 @@ static void typec_switch_release(struct device *dev)
kfree(to_typec_switch(dev));
}
-static const struct device_type typec_switch_dev_type = {
+const struct device_type typec_switch_dev_type = {
.name = "orientation_switch",
.release = typec_switch_release,
};
@@ -180,7 +184,10 @@ 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");
+ if (!is_typec_mux(dev))
+ return 0;
+
+ return dev_fwnode(dev) == fwnode;
}
static void *typec_mux_match(struct fwnode_handle *fwnode, const char *id,
@@ -295,7 +302,7 @@ static void typec_mux_release(struct device *dev)
kfree(to_typec_mux(dev));
}
-static const struct device_type typec_mux_dev_type = {
+const struct device_type typec_mux_dev_type = {
.name = "mode_switch",
.release = typec_mux_release,
};
diff --git a/drivers/usb/typec/mux.h b/drivers/usb/typec/mux.h
index 4fd9426ee44f..b1d6e837cb74 100644
--- a/drivers/usb/typec/mux.h
+++ b/drivers/usb/typec/mux.h
@@ -18,4 +18,10 @@ struct typec_mux {
#define to_typec_switch(_dev_) container_of(_dev_, struct typec_switch, dev)
#define to_typec_mux(_dev_) container_of(_dev_, struct typec_mux, dev)
+extern const struct device_type typec_switch_dev_type;
+extern const struct device_type typec_mux_dev_type;
+
+#define is_typec_switch(dev) ((dev)->type == &typec_switch_dev_type)
+#define is_typec_mux(dev) ((dev)->type == &typec_mux_dev_type)
+
#endif /* __USB_TYPEC_MUX__ */
diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c
index ffa8aa12d5f1..2cdd22130834 100644
--- a/drivers/usb/typec/mux/intel_pmc_mux.c
+++ b/drivers/usb/typec/mux/intel_pmc_mux.c
@@ -83,8 +83,6 @@ enum {
/*
* Input Output Manager (IOM) PORT STATUS
*/
-#define IOM_PORT_STATUS_OFFSET 0x560
-
#define IOM_PORT_STATUS_ACTIVITY_TYPE_MASK GENMASK(9, 6)
#define IOM_PORT_STATUS_ACTIVITY_TYPE_SHIFT 6
#define IOM_PORT_STATUS_ACTIVITY_TYPE_USB 0x03
@@ -144,6 +142,7 @@ struct pmc_usb {
struct pmc_usb_port *port;
struct acpi_device *iom_adev;
void __iomem *iom_base;
+ u32 iom_port_status_offset;
};
static void update_port_status(struct pmc_usb_port *port)
@@ -153,7 +152,8 @@ static void update_port_status(struct pmc_usb_port *port)
/* SoC expects the USB Type-C port numbers to start with 0 */
port_num = port->usb3_port - 1;
- port->iom_status = readl(port->pmc->iom_base + IOM_PORT_STATUS_OFFSET +
+ port->iom_status = readl(port->pmc->iom_base +
+ port->pmc->iom_port_status_offset +
port_num * sizeof(u32));
}
@@ -559,14 +559,32 @@ static int is_memory(struct acpi_resource *res, void *data)
return !acpi_dev_resource_memory(res, &r);
}
+/* IOM ACPI IDs and IOM_PORT_STATUS_OFFSET */
+static const struct acpi_device_id iom_acpi_ids[] = {
+ /* TigerLake */
+ { "INTC1072", 0x560, },
+
+ /* AlderLake */
+ { "INTC1079", 0x160, },
+ {}
+};
+
static int pmc_usb_probe_iom(struct pmc_usb *pmc)
{
struct list_head resource_list;
struct resource_entry *rentry;
- struct acpi_device *adev;
+ static const struct acpi_device_id *dev_id;
+ struct acpi_device *adev = NULL;
int ret;
- adev = acpi_dev_get_first_match_dev("INTC1072", NULL, -1);
+ for (dev_id = &iom_acpi_ids[0]; dev_id->id[0]; dev_id++) {
+ if (acpi_dev_present(dev_id->id, NULL, -1)) {
+ pmc->iom_port_status_offset = (u32)dev_id->driver_data;
+ adev = acpi_dev_get_first_match_dev(dev_id->id, NULL, -1);
+ break;
+ }
+ }
+
if (!adev)
return -ENODEV;
diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
index 25b480752266..9858716698df 100644
--- a/drivers/usb/typec/tcpm/tcpci.c
+++ b/drivers/usb/typec/tcpm/tcpci.c
@@ -21,8 +21,12 @@
#define PD_RETRY_COUNT_DEFAULT 3
#define PD_RETRY_COUNT_3_0_OR_HIGHER 2
#define AUTO_DISCHARGE_DEFAULT_THRESHOLD_MV 3500
-#define AUTO_DISCHARGE_PD_HEADROOM_MV 850
-#define AUTO_DISCHARGE_PPS_HEADROOM_MV 1250
+#define VSINKPD_MIN_IR_DROP_MV 750
+#define VSRC_NEW_MIN_PERCENT 95
+#define VSRC_VALID_MIN_MV 500
+#define VPPS_NEW_MIN_PERCENT 95
+#define VPPS_VALID_MIN_MV 100
+#define VSINKDISCONNECT_PD_MIN_PERCENT 90
#define tcpc_presenting_rd(reg, cc) \
(!(TCPC_ROLE_CTRL_DRP & (reg)) && \
@@ -115,6 +119,33 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
return 0;
}
+static int tcpci_apply_rc(struct tcpc_dev *tcpc, enum typec_cc_status cc,
+ enum typec_cc_polarity polarity)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, &reg);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * APPLY_RC state is when ROLE_CONTROL.CC1 != ROLE_CONTROL.CC2 and vbus autodischarge on
+ * disconnect is disabled. Bail out when ROLE_CONTROL.CC1 != ROLE_CONTROL.CC2.
+ */
+ if (((reg & (TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT)) >>
+ TCPC_ROLE_CTRL_CC2_SHIFT) !=
+ ((reg & (TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT)) >>
+ TCPC_ROLE_CTRL_CC1_SHIFT))
+ return 0;
+
+ return regmap_update_bits(tcpci->regmap, TCPC_ROLE_CTRL, polarity == TYPEC_POLARITY_CC1 ?
+ TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT :
+ TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT,
+ TCPC_ROLE_CTRL_CC_OPEN);
+}
+
static int tcpci_start_toggling(struct tcpc_dev *tcpc,
enum typec_port_type port_type,
enum typec_cc_status cc)
@@ -324,11 +355,13 @@ static int tcpci_set_auto_vbus_discharge_threshold(struct tcpc_dev *dev, enum ty
threshold = AUTO_DISCHARGE_DEFAULT_THRESHOLD_MV;
} else if (mode == TYPEC_PWR_MODE_PD) {
if (pps_active)
- threshold = (95 * requested_vbus_voltage_mv / 100) -
- AUTO_DISCHARGE_PD_HEADROOM_MV;
+ threshold = ((VPPS_NEW_MIN_PERCENT * requested_vbus_voltage_mv / 100) -
+ VSINKPD_MIN_IR_DROP_MV - VPPS_VALID_MIN_MV) *
+ VSINKDISCONNECT_PD_MIN_PERCENT / 100;
else
- threshold = (95 * requested_vbus_voltage_mv / 100) -
- AUTO_DISCHARGE_PPS_HEADROOM_MV;
+ threshold = ((VSRC_NEW_MIN_PERCENT * requested_vbus_voltage_mv / 100) -
+ VSINKPD_MIN_IR_DROP_MV - VSRC_VALID_MIN_MV) *
+ VSINKDISCONNECT_PD_MIN_PERCENT / 100;
} else {
/* 3.5V for non-pd sink */
threshold = AUTO_DISCHARGE_DEFAULT_THRESHOLD_MV;
@@ -728,6 +761,7 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
tcpci->tcpc.get_vbus = tcpci_get_vbus;
tcpci->tcpc.set_vbus = tcpci_set_vbus;
tcpci->tcpc.set_cc = tcpci_set_cc;
+ tcpci->tcpc.apply_rc = tcpci_apply_rc;
tcpci->tcpc.get_cc = tcpci_get_cc;
tcpci->tcpc.set_polarity = tcpci_set_polarity;
tcpci->tcpc.set_vconn = tcpci_set_vconn;
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 63470cf7f4cd..5b22a1c931a9 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -776,6 +776,34 @@ static void tcpm_set_cc(struct tcpm_port *port, enum typec_cc_status cc)
port->tcpc->set_cc(port->tcpc, cc);
}
+static int tcpm_enable_auto_vbus_discharge(struct tcpm_port *port, bool enable)
+{
+ int ret = 0;
+
+ if (port->tcpc->enable_auto_vbus_discharge) {
+ ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, enable);
+ tcpm_log_force(port, "%s vbus discharge ret:%d", enable ? "enable" : "disable",
+ ret);
+ if (!ret)
+ port->auto_vbus_discharge_enabled = enable;
+ }
+
+ return ret;
+}
+
+static void tcpm_apply_rc(struct tcpm_port *port)
+{
+ /*
+ * TCPCI: Move to APPLY_RC state to prevent disconnect during PR_SWAP
+ * when Vbus auto discharge on disconnect is enabled.
+ */
+ if (port->tcpc->enable_auto_vbus_discharge && port->tcpc->apply_rc) {
+ tcpm_log(port, "Apply_RC");
+ port->tcpc->apply_rc(port->tcpc, port->cc_req, port->polarity);
+ tcpm_enable_auto_vbus_discharge(port, false);
+ }
+}
+
/*
* Determine RP value to set based on maximum current supported
* by a port if configured as source.
@@ -2576,6 +2604,11 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
} else {
next_state = SNK_WAIT_CAPABILITIES;
}
+
+ /* Threshold was relaxed before sending Request. Restore it back. */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_PD,
+ port->pps_data.active,
+ port->supply_voltage);
tcpm_set_state(port, next_state, 0);
break;
case SNK_NEGOTIATE_PPS_CAPABILITIES:
@@ -2589,6 +2622,11 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
port->send_discover)
port->vdm_sm_running = true;
+ /* Threshold was relaxed before sending Request. Restore it back. */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_PD,
+ port->pps_data.active,
+ port->supply_voltage);
+
tcpm_set_state(port, SNK_READY, 0);
break;
case DR_SWAP_SEND:
@@ -3308,6 +3346,12 @@ static int tcpm_pd_send_request(struct tcpm_port *port)
if (ret < 0)
return ret;
+ /*
+ * Relax the threshold as voltage will be adjusted after Accept Message plus tSrcTransition.
+ * It is safer to modify the threshold here.
+ */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, 0);
+
memset(&msg, 0, sizeof(msg));
msg.header = PD_HEADER_LE(PD_DATA_REQUEST,
port->pwr_role,
@@ -3405,6 +3449,9 @@ static int tcpm_pd_send_pps_request(struct tcpm_port *port)
if (ret < 0)
return ret;
+ /* Relax the threshold as voltage will be adjusted right after Accept Message. */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, 0);
+
memset(&msg, 0, sizeof(msg));
msg.header = PD_HEADER_LE(PD_DATA_REQUEST,
port->pwr_role,
@@ -3515,12 +3562,7 @@ static int tcpm_src_attach(struct tcpm_port *port)
if (ret < 0)
return ret;
- if (port->tcpc->enable_auto_vbus_discharge) {
- ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, true);
- tcpm_log_force(port, "enable vbus discharge ret:%d", ret);
- if (!ret)
- port->auto_vbus_discharge_enabled = true;
- }
+ tcpm_enable_auto_vbus_discharge(port, true);
ret = tcpm_set_roles(port, true, TYPEC_SOURCE, tcpm_data_role_for_source(port));
if (ret < 0)
@@ -3597,14 +3639,7 @@ static void tcpm_set_partner_usb_comm_capable(struct tcpm_port *port, bool capab
static void tcpm_reset_port(struct tcpm_port *port)
{
- int ret;
-
- if (port->tcpc->enable_auto_vbus_discharge) {
- ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, false);
- tcpm_log_force(port, "Disable vbus discharge ret:%d", ret);
- if (!ret)
- port->auto_vbus_discharge_enabled = false;
- }
+ tcpm_enable_auto_vbus_discharge(port, false);
port->in_ams = false;
port->ams = NONE_AMS;
port->vdm_sm_running = false;
@@ -3672,13 +3707,7 @@ static int tcpm_snk_attach(struct tcpm_port *port)
if (ret < 0)
return ret;
- if (port->tcpc->enable_auto_vbus_discharge) {
- tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, VSAFE5V);
- ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, true);
- tcpm_log_force(port, "enable vbus discharge ret:%d", ret);
- if (!ret)
- port->auto_vbus_discharge_enabled = true;
- }
+ tcpm_enable_auto_vbus_discharge(port, true);
ret = tcpm_set_roles(port, true, TYPEC_SINK, tcpm_data_role_for_sink(port));
if (ret < 0)
@@ -4186,6 +4215,10 @@ static void run_state_machine(struct tcpm_port *port)
port->hard_reset_count = 0;
ret = tcpm_pd_send_request(port);
if (ret < 0) {
+ /* Restore back to the original state */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_PD,
+ port->pps_data.active,
+ port->supply_voltage);
/* Let the Source send capabilities again. */
tcpm_set_state(port, SNK_WAIT_CAPABILITIES, 0);
} else {
@@ -4196,6 +4229,10 @@ static void run_state_machine(struct tcpm_port *port)
case SNK_NEGOTIATE_PPS_CAPABILITIES:
ret = tcpm_pd_send_pps_request(port);
if (ret < 0) {
+ /* Restore back to the original state */
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_PD,
+ port->pps_data.active,
+ port->supply_voltage);
port->pps_status = ret;
/*
* If this was called due to updates to sink
@@ -4515,6 +4552,7 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_state(port, ready_state(port), 0);
break;
case PR_SWAP_START:
+ tcpm_apply_rc(port);
if (port->pwr_role == TYPEC_SOURCE)
tcpm_set_state(port, PR_SWAP_SRC_SNK_TRANSITION_OFF,
PD_T_SRC_TRANSITION);
@@ -4554,6 +4592,7 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_state(port, ERROR_RECOVERY, PD_T_PS_SOURCE_ON_PRS);
break;
case PR_SWAP_SRC_SNK_SINK_ON:
+ tcpm_enable_auto_vbus_discharge(port, true);
/* Set the vbus disconnect threshold for implicit contract */
tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, VSAFE5V);
tcpm_set_state(port, SNK_STARTUP, 0);
@@ -4570,6 +4609,7 @@ static void run_state_machine(struct tcpm_port *port)
PD_T_PS_SOURCE_OFF);
break;
case PR_SWAP_SNK_SRC_SOURCE_ON:
+ tcpm_enable_auto_vbus_discharge(port, true);
tcpm_set_cc(port, tcpm_rp_cc(port));
tcpm_set_vbus(port, true);
/*
@@ -5198,6 +5238,10 @@ static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port)
tcpm_set_state(port, SNK_UNATTACHED, 0);
}
break;
+ case PR_SWAP_SNK_SRC_SINK_OFF:
+ case PR_SWAP_SNK_SRC_SOURCE_ON:
+ /* Do nothing, vsafe0v is expected during transition */
+ break;
default:
if (port->pwr_role == TYPEC_SINK && port->auto_vbus_discharge_enabled)
tcpm_set_state(port, SNK_UNATTACHED, 0);
diff --git a/drivers/usb/typec/tcpm/wcove.c b/drivers/usb/typec/tcpm/wcove.c
index 5d125339687a..20917d85d6f4 100644
--- a/drivers/usb/typec/tcpm/wcove.c
+++ b/drivers/usb/typec/tcpm/wcove.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* typec_wcove.c - WhiskeyCove PMIC USB Type-C PHY driver
*
* Copyright (C) 2017 Intel Corporation
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index b7d104c80d85..5ef5bd0e87cf 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -1219,7 +1219,7 @@ static int ucsi_init(struct ucsi *ucsi)
goto err_reset;
}
- /* Allocate the connectors. Released in ucsi_unregister_ppm() */
+ /* Allocate the connectors. Released in ucsi_unregister() */
ucsi->connector = kcalloc(ucsi->cap.num_connectors + 1,
sizeof(*ucsi->connector), GFP_KERNEL);
if (!ucsi->connector) {
@@ -1280,7 +1280,7 @@ void *ucsi_get_drvdata(struct ucsi *ucsi)
EXPORT_SYMBOL_GPL(ucsi_get_drvdata);
/**
- * ucsi_get_drvdata - Assign private driver data pointer
+ * ucsi_set_drvdata - Assign private driver data pointer
* @ucsi: UCSI interface
* @data: Private data pointer
*/
diff --git a/drivers/vdpa/ifcvf/ifcvf_base.c b/drivers/vdpa/ifcvf/ifcvf_base.c
index 1a661ab45af5..6e197fe0fcf9 100644
--- a/drivers/vdpa/ifcvf/ifcvf_base.c
+++ b/drivers/vdpa/ifcvf/ifcvf_base.c
@@ -133,6 +133,8 @@ int ifcvf_init_hw(struct ifcvf_hw *hw, struct pci_dev *pdev)
&hw->notify_off_multiplier);
hw->notify_bar = cap.bar;
hw->notify_base = get_cap_addr(hw, &cap);
+ hw->notify_base_pa = pci_resource_start(pdev, cap.bar) +
+ le32_to_cpu(cap.offset);
IFCVF_DBG(pdev, "hw->notify_base = %p\n",
hw->notify_base);
break;
@@ -161,6 +163,8 @@ next:
notify_off = ifc_ioread16(&hw->common_cfg->queue_notify_off);
hw->vring[i].notify_addr = hw->notify_base +
notify_off * hw->notify_off_multiplier;
+ hw->vring[i].notify_pa = hw->notify_base_pa +
+ notify_off * hw->notify_off_multiplier;
}
hw->lm_cfg = hw->base[IFCVF_LM_BAR];
diff --git a/drivers/vdpa/ifcvf/ifcvf_base.h b/drivers/vdpa/ifcvf/ifcvf_base.h
index 0111bfdeb342..2996db0da490 100644
--- a/drivers/vdpa/ifcvf/ifcvf_base.h
+++ b/drivers/vdpa/ifcvf/ifcvf_base.h
@@ -19,21 +19,9 @@
#include <uapi/linux/virtio_config.h>
#include <uapi/linux/virtio_pci.h>
-#define N3000_VENDOR_ID 0x1AF4
#define N3000_DEVICE_ID 0x1041
-#define N3000_SUBSYS_VENDOR_ID 0x8086
#define N3000_SUBSYS_DEVICE_ID 0x001A
-#define C5000X_PL_VENDOR_ID 0x1AF4
-#define C5000X_PL_DEVICE_ID 0x1000
-#define C5000X_PL_SUBSYS_VENDOR_ID 0x8086
-#define C5000X_PL_SUBSYS_DEVICE_ID 0x0001
-
-#define C5000X_PL_BLK_VENDOR_ID 0x1AF4
-#define C5000X_PL_BLK_DEVICE_ID 0x1001
-#define C5000X_PL_BLK_SUBSYS_VENDOR_ID 0x8086
-#define C5000X_PL_BLK_SUBSYS_DEVICE_ID 0x0002
-
#define IFCVF_NET_SUPPORTED_FEATURES \
((1ULL << VIRTIO_NET_F_MAC) | \
(1ULL << VIRTIO_F_ANY_LAYOUT) | \
@@ -73,6 +61,7 @@ struct vring_info {
u16 last_avail_idx;
bool ready;
void __iomem *notify_addr;
+ phys_addr_t notify_pa;
u32 irq;
struct vdpa_callback cb;
char msix_name[256];
@@ -87,6 +76,7 @@ struct ifcvf_hw {
u8 notify_bar;
/* Notificaiton bar address */
void __iomem *notify_base;
+ phys_addr_t notify_base_pa;
u32 notify_off_multiplier;
u64 req_features;
u64 hw_features;
diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c
index ab0ab5cf0f6e..21b78f1cd521 100644
--- a/drivers/vdpa/ifcvf/ifcvf_main.c
+++ b/drivers/vdpa/ifcvf/ifcvf_main.c
@@ -264,7 +264,7 @@ static int ifcvf_vdpa_get_vq_state(struct vdpa_device *vdpa_dev, u16 qid,
{
struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
- state->avail_index = ifcvf_get_vq_state(vf, qid);
+ state->split.avail_index = ifcvf_get_vq_state(vf, qid);
return 0;
}
@@ -273,7 +273,7 @@ static int ifcvf_vdpa_set_vq_state(struct vdpa_device *vdpa_dev, u16 qid,
{
struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
- return ifcvf_set_vq_state(vf, qid, state->avail_index);
+ return ifcvf_set_vq_state(vf, qid, state->split.avail_index);
}
static void ifcvf_vdpa_set_vq_cb(struct vdpa_device *vdpa_dev, u16 qid,
@@ -413,6 +413,21 @@ static int ifcvf_vdpa_get_vq_irq(struct vdpa_device *vdpa_dev,
return vf->vring[qid].irq;
}
+static struct vdpa_notification_area ifcvf_get_vq_notification(struct vdpa_device *vdpa_dev,
+ u16 idx)
+{
+ struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+ struct vdpa_notification_area area;
+
+ area.addr = vf->vring[idx].notify_pa;
+ if (!vf->notify_off_multiplier)
+ area.size = PAGE_SIZE;
+ else
+ area.size = vf->notify_off_multiplier;
+
+ return area;
+}
+
/*
* IFCVF currently does't have on-chip IOMMU, so not
* implemented set_map()/dma_map()/dma_unmap()
@@ -440,6 +455,7 @@ static const struct vdpa_config_ops ifc_vdpa_ops = {
.get_config = ifcvf_vdpa_get_config,
.set_config = ifcvf_vdpa_set_config,
.set_config_cb = ifcvf_vdpa_set_config_cb,
+ .get_vq_notification = ifcvf_get_vq_notification,
};
static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -536,18 +552,21 @@ static void ifcvf_remove(struct pci_dev *pdev)
}
static struct pci_device_id ifcvf_pci_ids[] = {
- { PCI_DEVICE_SUB(N3000_VENDOR_ID,
+ /* N3000 network device */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_REDHAT_QUMRANET,
N3000_DEVICE_ID,
- N3000_SUBSYS_VENDOR_ID,
+ PCI_VENDOR_ID_INTEL,
N3000_SUBSYS_DEVICE_ID) },
- { PCI_DEVICE_SUB(C5000X_PL_VENDOR_ID,
- C5000X_PL_DEVICE_ID,
- C5000X_PL_SUBSYS_VENDOR_ID,
- C5000X_PL_SUBSYS_DEVICE_ID) },
- { PCI_DEVICE_SUB(C5000X_PL_BLK_VENDOR_ID,
- C5000X_PL_BLK_DEVICE_ID,
- C5000X_PL_BLK_SUBSYS_VENDOR_ID,
- C5000X_PL_BLK_SUBSYS_DEVICE_ID) },
+ /* C5000X-PL network device */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_REDHAT_QUMRANET,
+ VIRTIO_TRANS_ID_NET,
+ PCI_VENDOR_ID_INTEL,
+ VIRTIO_ID_NET) },
+ /* C5000X-PL block device */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_REDHAT_QUMRANET,
+ VIRTIO_TRANS_ID_BLOCK,
+ PCI_VENDOR_ID_INTEL,
+ VIRTIO_ID_BLOCK) },
{ 0 },
};
diff --git a/drivers/vdpa/mlx5/core/mlx5_vdpa.h b/drivers/vdpa/mlx5/core/mlx5_vdpa.h
index b6cc53ba980c..0002b2136b48 100644
--- a/drivers/vdpa/mlx5/core/mlx5_vdpa.h
+++ b/drivers/vdpa/mlx5/core/mlx5_vdpa.h
@@ -35,12 +35,14 @@ struct mlx5_vdpa_mr {
/* serialize mkey creation and destruction */
struct mutex mkey_mtx;
+ bool user_mr;
};
struct mlx5_vdpa_resources {
u32 pdn;
struct mlx5_uars_page *uar;
void __iomem *kick_addr;
+ u64 phys_kick_addr;
u16 uid;
u32 null_mkey;
bool valid;
diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c
index 800cfd1967ad..dcee6039e966 100644
--- a/drivers/vdpa/mlx5/core/mr.c
+++ b/drivers/vdpa/mlx5/core/mr.c
@@ -219,11 +219,6 @@ static void destroy_indirect_key(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_m
mlx5_vdpa_destroy_mkey(mvdev, &mkey->mkey);
}
-static struct device *get_dma_device(struct mlx5_vdpa_dev *mvdev)
-{
- return &mvdev->mdev->pdev->dev;
-}
-
static int map_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr *mr,
struct vhost_iotlb *iotlb)
{
@@ -239,7 +234,7 @@ static int map_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr
u64 pa;
u64 paend;
struct scatterlist *sg;
- struct device *dma = get_dma_device(mvdev);
+ struct device *dma = mvdev->vdev.dma_dev;
for (map = vhost_iotlb_itree_first(iotlb, mr->start, mr->end - 1);
map; map = vhost_iotlb_itree_next(map, start, mr->end - 1)) {
@@ -298,7 +293,7 @@ err_map:
static void unmap_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr *mr)
{
- struct device *dma = get_dma_device(mvdev);
+ struct device *dma = mvdev->vdev.dma_dev;
destroy_direct_mr(mvdev, mr);
dma_unmap_sg_attrs(dma, mr->sg_head.sgl, mr->nsg, DMA_BIDIRECTIONAL, 0);
@@ -360,7 +355,7 @@ err_alloc:
* indirect memory key that provides access to the enitre address space given
* by iotlb.
*/
-static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb)
+static int create_user_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb)
{
struct mlx5_vdpa_mr *mr = &mvdev->mr;
struct mlx5_vdpa_direct_mr *dmr;
@@ -374,9 +369,6 @@ static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb
int err = 0;
int nnuls;
- if (mr->initialized)
- return 0;
-
INIT_LIST_HEAD(&mr->head);
for (map = vhost_iotlb_itree_first(iotlb, start, last); map;
map = vhost_iotlb_itree_next(map, start, last)) {
@@ -414,7 +406,7 @@ static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb
if (err)
goto err_chain;
- mr->initialized = true;
+ mr->user_mr = true;
return 0;
err_chain:
@@ -426,33 +418,94 @@ err_chain:
return err;
}
-int mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb)
+static int create_dma_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr)
+{
+ int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
+ void *mkc;
+ u32 *in;
+ int err;
+
+ in = kzalloc(inlen, GFP_KERNEL);
+ if (!in)
+ return -ENOMEM;
+
+ mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
+
+ MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA);
+ MLX5_SET(mkc, mkc, length64, 1);
+ MLX5_SET(mkc, mkc, lw, 1);
+ MLX5_SET(mkc, mkc, lr, 1);
+ MLX5_SET(mkc, mkc, pd, mvdev->res.pdn);
+ MLX5_SET(mkc, mkc, qpn, 0xffffff);
+
+ err = mlx5_vdpa_create_mkey(mvdev, &mr->mkey, in, inlen);
+ if (!err)
+ mr->user_mr = false;
+
+ kfree(in);
+ return err;
+}
+
+static void destroy_dma_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr)
+{
+ mlx5_vdpa_destroy_mkey(mvdev, &mr->mkey);
+}
+
+static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb)
{
struct mlx5_vdpa_mr *mr = &mvdev->mr;
int err;
- mutex_lock(&mr->mkey_mtx);
+ if (mr->initialized)
+ return 0;
+
+ if (iotlb)
+ err = create_user_mr(mvdev, iotlb);
+ else
+ err = create_dma_mr(mvdev, mr);
+
+ if (!err)
+ mr->initialized = true;
+
+ return err;
+}
+
+int mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb)
+{
+ int err;
+
+ mutex_lock(&mvdev->mr.mkey_mtx);
err = _mlx5_vdpa_create_mr(mvdev, iotlb);
- mutex_unlock(&mr->mkey_mtx);
+ mutex_unlock(&mvdev->mr.mkey_mtx);
return err;
}
-void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev)
+static void destroy_user_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr)
{
- struct mlx5_vdpa_mr *mr = &mvdev->mr;
struct mlx5_vdpa_direct_mr *dmr;
struct mlx5_vdpa_direct_mr *n;
- mutex_lock(&mr->mkey_mtx);
- if (!mr->initialized)
- goto out;
-
destroy_indirect_key(mvdev, mr);
list_for_each_entry_safe_reverse(dmr, n, &mr->head, list) {
list_del_init(&dmr->list);
unmap_direct_mr(mvdev, dmr);
kfree(dmr);
}
+}
+
+void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev)
+{
+ struct mlx5_vdpa_mr *mr = &mvdev->mr;
+
+ mutex_lock(&mr->mkey_mtx);
+ if (!mr->initialized)
+ goto out;
+
+ if (mr->user_mr)
+ destroy_user_mr(mvdev, mr);
+ else
+ destroy_dma_mr(mvdev, mr);
+
memset(mr, 0, sizeof(*mr));
mr->initialized = false;
out:
diff --git a/drivers/vdpa/mlx5/core/resources.c b/drivers/vdpa/mlx5/core/resources.c
index 6521cbd0f5c2..d4606213f88a 100644
--- a/drivers/vdpa/mlx5/core/resources.c
+++ b/drivers/vdpa/mlx5/core/resources.c
@@ -54,6 +54,9 @@ static int create_uctx(struct mlx5_vdpa_dev *mvdev, u16 *uid)
void *in;
int err;
+ if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0))
+ return 0;
+
/* 0 means not supported */
if (!MLX5_CAP_GEN(mvdev->mdev, log_max_uctx))
return -EOPNOTSUPP;
@@ -79,6 +82,9 @@ static void destroy_uctx(struct mlx5_vdpa_dev *mvdev, u32 uid)
u32 out[MLX5_ST_SZ_DW(destroy_uctx_out)] = {};
u32 in[MLX5_ST_SZ_DW(destroy_uctx_in)] = {};
+ if (!uid)
+ return;
+
MLX5_SET(destroy_uctx_in, in, opcode, MLX5_CMD_OP_DESTROY_UCTX);
MLX5_SET(destroy_uctx_in, in, uid, uid);
@@ -247,6 +253,7 @@ int mlx5_vdpa_alloc_resources(struct mlx5_vdpa_dev *mvdev)
goto err_key;
kick_addr = mdev->bar_addr + offset;
+ res->phys_kick_addr = kick_addr;
res->kick_addr = ioremap(kick_addr, PAGE_SIZE);
if (!res->kick_addr) {
diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
index dda5dc6f7737..2a31467f7ac5 100644
--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
+++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
@@ -611,8 +611,8 @@ static void cq_destroy(struct mlx5_vdpa_net *ndev, u16 idx)
mlx5_db_free(ndev->mvdev.mdev, &vcq->db);
}
-static int umem_size(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int num,
- struct mlx5_vdpa_umem **umemp)
+static void set_umem_size(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int num,
+ struct mlx5_vdpa_umem **umemp)
{
struct mlx5_core_dev *mdev = ndev->mvdev.mdev;
int p_a;
@@ -635,7 +635,7 @@ static int umem_size(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq
*umemp = &mvq->umem3;
break;
}
- return p_a * mvq->num_ent + p_b;
+ (*umemp)->size = p_a * mvq->num_ent + p_b;
}
static void umem_frag_buf_free(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_umem *umem)
@@ -651,15 +651,10 @@ static int create_umem(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *m
void *in;
int err;
__be64 *pas;
- int size;
struct mlx5_vdpa_umem *umem;
- size = umem_size(ndev, mvq, num, &umem);
- if (size < 0)
- return size;
-
- umem->size = size;
- err = umem_frag_buf_alloc(ndev, umem, size);
+ set_umem_size(ndev, mvq, num, &umem);
+ err = umem_frag_buf_alloc(ndev, umem, umem->size);
if (err)
return err;
@@ -829,9 +824,9 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque
MLX5_SET(virtio_q, vq_ctx, umem_1_id, mvq->umem1.id);
MLX5_SET(virtio_q, vq_ctx, umem_1_size, mvq->umem1.size);
MLX5_SET(virtio_q, vq_ctx, umem_2_id, mvq->umem2.id);
- MLX5_SET(virtio_q, vq_ctx, umem_2_size, mvq->umem1.size);
+ MLX5_SET(virtio_q, vq_ctx, umem_2_size, mvq->umem2.size);
MLX5_SET(virtio_q, vq_ctx, umem_3_id, mvq->umem3.id);
- MLX5_SET(virtio_q, vq_ctx, umem_3_size, mvq->umem1.size);
+ MLX5_SET(virtio_q, vq_ctx, umem_3_size, mvq->umem3.size);
MLX5_SET(virtio_q, vq_ctx, pd, ndev->mvdev.res.pdn);
if (MLX5_CAP_DEV_VDPA_EMULATION(ndev->mvdev.mdev, eth_frame_offload_type))
MLX5_SET(virtio_q, vq_ctx, virtio_version_1_0, 1);
@@ -1428,8 +1423,8 @@ static int mlx5_vdpa_set_vq_state(struct vdpa_device *vdev, u16 idx,
return -EINVAL;
}
- mvq->used_idx = state->avail_index;
- mvq->avail_idx = state->avail_index;
+ mvq->used_idx = state->split.avail_index;
+ mvq->avail_idx = state->split.avail_index;
return 0;
}
@@ -1450,7 +1445,7 @@ static int mlx5_vdpa_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa
* Since both values should be identical, we take the value of
* used_idx which is reported correctly.
*/
- state->avail_index = mvq->used_idx;
+ state->split.avail_index = mvq->used_idx;
return 0;
}
@@ -1459,7 +1454,7 @@ static int mlx5_vdpa_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa
mlx5_vdpa_warn(mvdev, "failed to query virtqueue\n");
return err;
}
- state->avail_index = attr.used_index;
+ state->split.avail_index = attr.used_index;
return 0;
}
@@ -1772,6 +1767,14 @@ out:
mutex_unlock(&ndev->reslock);
}
+static void clear_vqs_ready(struct mlx5_vdpa_net *ndev)
+{
+ int i;
+
+ for (i = 0; i < ndev->mvdev.max_vqs; i++)
+ ndev->vqs[i].ready = false;
+}
+
static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status)
{
struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev);
@@ -1782,10 +1785,15 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status)
if (!status) {
mlx5_vdpa_info(mvdev, "performing device reset\n");
teardown_driver(ndev);
+ clear_vqs_ready(ndev);
mlx5_vdpa_destroy_mr(&ndev->mvdev);
ndev->mvdev.status = 0;
ndev->mvdev.mlx_features = 0;
++mvdev->generation;
+ if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) {
+ if (mlx5_vdpa_create_mr(mvdev, NULL))
+ mlx5_vdpa_warn(mvdev, "create MR failed\n");
+ }
return;
}
@@ -1866,6 +1874,7 @@ static void mlx5_vdpa_free(struct vdpa_device *vdev)
ndev = to_mlx5_vdpa_ndev(mvdev);
free_resources(ndev);
+ mlx5_vdpa_destroy_mr(mvdev);
if (!is_zero_ether_addr(ndev->config.mac)) {
pfmdev = pci_get_drvdata(pci_physfn(mvdev->mdev->pdev));
mlx5_mpfs_del_mac(pfmdev, ndev->config.mac);
@@ -1876,8 +1885,22 @@ static void mlx5_vdpa_free(struct vdpa_device *vdev)
static struct vdpa_notification_area mlx5_get_vq_notification(struct vdpa_device *vdev, u16 idx)
{
+ struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev);
struct vdpa_notification_area ret = {};
+ struct mlx5_vdpa_net *ndev;
+ phys_addr_t addr;
+
+ /* If SF BAR size is smaller than PAGE_SIZE, do not use direct
+ * notification to avoid the risk of mapping pages that contain BAR of more
+ * than one SF
+ */
+ if (MLX5_CAP_GEN(mvdev->mdev, log_min_sf_size) + 12 < PAGE_SHIFT)
+ return ret;
+ ndev = to_mlx5_vdpa_ndev(mvdev);
+ addr = (phys_addr_t)ndev->mvdev.res.phys_kick_addr;
+ ret.addr = addr;
+ ret.size = PAGE_SIZE;
return ret;
}
@@ -2037,14 +2060,20 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name)
goto err_mtu;
}
- mvdev->vdev.dma_dev = mdev->device;
+ mvdev->vdev.dma_dev = &mdev->pdev->dev;
err = mlx5_vdpa_alloc_resources(&ndev->mvdev);
if (err)
goto err_mpfs;
+ if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) {
+ err = mlx5_vdpa_create_mr(mvdev, NULL);
+ if (err)
+ goto err_res;
+ }
+
err = alloc_resources(ndev);
if (err)
- goto err_res;
+ goto err_mr;
mvdev->vdev.mdev = &mgtdev->mgtdev;
err = _vdpa_register_device(&mvdev->vdev, 2 * mlx5_vdpa_max_qps(max_vqs));
@@ -2056,6 +2085,8 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name)
err_reg:
free_resources(ndev);
+err_mr:
+ mlx5_vdpa_destroy_mr(mvdev);
err_res:
mlx5_vdpa_free_resources(&ndev->mvdev);
err_mpfs:
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c
index 98f793bc9376..14e024de5cbf 100644
--- a/drivers/vdpa/vdpa_sim/vdpa_sim.c
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c
@@ -374,7 +374,7 @@ static int vdpasim_set_vq_state(struct vdpa_device *vdpa, u16 idx,
struct vringh *vrh = &vq->vring;
spin_lock(&vdpasim->lock);
- vrh->last_avail_idx = state->avail_index;
+ vrh->last_avail_idx = state->split.avail_index;
spin_unlock(&vdpasim->lock);
return 0;
@@ -387,7 +387,7 @@ static int vdpasim_get_vq_state(struct vdpa_device *vdpa, u16 idx,
struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx];
struct vringh *vrh = &vq->vring;
- state->avail_index = vrh->last_avail_idx;
+ state->split.avail_index = vrh->last_avail_idx;
return 0;
}
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
index 5bfe1c281645..a790903f243e 100644
--- a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
@@ -15,7 +15,6 @@
#include <linux/blkdev.h>
#include <linux/vringh.h>
#include <linux/vdpa.h>
-#include <linux/blkdev.h>
#include <uapi/linux/virtio_blk.h>
#include "vdpa_sim.h"
diff --git a/drivers/vdpa/virtio_pci/vp_vdpa.c b/drivers/vdpa/virtio_pci/vp_vdpa.c
index c76ebb531212..7b4a6396c553 100644
--- a/drivers/vdpa/virtio_pci/vp_vdpa.c
+++ b/drivers/vdpa/virtio_pci/vp_vdpa.c
@@ -210,13 +210,49 @@ static int vp_vdpa_get_vq_state(struct vdpa_device *vdpa, u16 qid,
return -EOPNOTSUPP;
}
+static int vp_vdpa_set_vq_state_split(struct vdpa_device *vdpa,
+ const struct vdpa_vq_state *state)
+{
+ const struct vdpa_vq_state_split *split = &state->split;
+
+ if (split->avail_index == 0)
+ return 0;
+
+ return -EOPNOTSUPP;
+}
+
+static int vp_vdpa_set_vq_state_packed(struct vdpa_device *vdpa,
+ const struct vdpa_vq_state *state)
+{
+ const struct vdpa_vq_state_packed *packed = &state->packed;
+
+ if (packed->last_avail_counter == 1 &&
+ packed->last_avail_idx == 0 &&
+ packed->last_used_counter == 1 &&
+ packed->last_used_idx == 0)
+ return 0;
+
+ return -EOPNOTSUPP;
+}
+
static int vp_vdpa_set_vq_state(struct vdpa_device *vdpa, u16 qid,
const struct vdpa_vq_state *state)
{
- /* Note that this is not supported by virtio specification, so
- * we return -ENOPOTSUPP here. This means we can't support live
- * migration, vhost device start/stop.
+ struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa);
+
+ /* Note that this is not supported by virtio specification.
+ * But if the state is by chance equal to the device initial
+ * state, we can let it go.
*/
+ if ((vp_modern_get_status(mdev) & VIRTIO_CONFIG_S_FEATURES_OK) &&
+ !vp_modern_get_queue_enable(mdev, qid)) {
+ if (vp_modern_get_driver_features(mdev) &
+ BIT_ULL(VIRTIO_F_RING_PACKED))
+ return vp_vdpa_set_vq_state_packed(vdpa, state);
+ else
+ return vp_vdpa_set_vq_state_split(vdpa, state);
+ }
+
return -EOPNOTSUPP;
}
@@ -442,6 +478,7 @@ static int vp_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
vp_modern_map_vq_notify(mdev, i,
&vp_vdpa->vring[i].notify_pa);
if (!vp_vdpa->vring[i].notify) {
+ ret = -EINVAL;
dev_warn(&pdev->dev, "Fail to map vq notify %d\n", i);
goto err;
}
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
index 980e59551301..90cad109583b 100644
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
@@ -140,26 +140,18 @@ static int vfio_fsl_mc_open(struct vfio_device *core_vdev)
{
struct vfio_fsl_mc_device *vdev =
container_of(core_vdev, struct vfio_fsl_mc_device, vdev);
- int ret;
-
- if (!try_module_get(THIS_MODULE))
- return -ENODEV;
+ int ret = 0;
mutex_lock(&vdev->reflck->lock);
if (!vdev->refcnt) {
ret = vfio_fsl_mc_regions_init(vdev);
if (ret)
- goto err_reg_init;
+ goto out;
}
vdev->refcnt++;
-
+out:
mutex_unlock(&vdev->reflck->lock);
- return 0;
-
-err_reg_init:
- mutex_unlock(&vdev->reflck->lock);
- module_put(THIS_MODULE);
return ret;
}
@@ -196,8 +188,6 @@ static void vfio_fsl_mc_release(struct vfio_device *core_vdev)
}
mutex_unlock(&vdev->reflck->lock);
-
- module_put(THIS_MODULE);
}
static long vfio_fsl_mc_ioctl(struct vfio_device *core_vdev,
diff --git a/drivers/vfio/mdev/Kconfig b/drivers/vfio/mdev/Kconfig
index 5da27f2100f9..763c877a1318 100644
--- a/drivers/vfio/mdev/Kconfig
+++ b/drivers/vfio/mdev/Kconfig
@@ -9,10 +9,3 @@ config VFIO_MDEV
See Documentation/driver-api/vfio-mediated-device.rst for more details.
If you don't know what do here, say N.
-
-config VFIO_MDEV_DEVICE
- tristate "VFIO driver for Mediated devices"
- depends on VFIO && VFIO_MDEV
- default n
- help
- VFIO based driver for Mediated devices.
diff --git a/drivers/vfio/mdev/Makefile b/drivers/vfio/mdev/Makefile
index 101516fdf375..ff9ecd802125 100644
--- a/drivers/vfio/mdev/Makefile
+++ b/drivers/vfio/mdev/Makefile
@@ -1,6 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-mdev-y := mdev_core.o mdev_sysfs.o mdev_driver.o
+mdev-y := mdev_core.o mdev_sysfs.o mdev_driver.o vfio_mdev.o
obj-$(CONFIG_VFIO_MDEV) += mdev.o
-obj-$(CONFIG_VFIO_MDEV_DEVICE) += vfio_mdev.o
diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c
index 2a85d6fcb7dd..e4581ec093a6 100644
--- a/drivers/vfio/mdev/mdev_core.c
+++ b/drivers/vfio/mdev/mdev_core.c
@@ -94,9 +94,11 @@ static void mdev_device_remove_common(struct mdev_device *mdev)
mdev_remove_sysfs_files(mdev);
device_del(&mdev->dev);
lockdep_assert_held(&parent->unreg_sem);
- ret = parent->ops->remove(mdev);
- if (ret)
- dev_err(&mdev->dev, "Remove failed: err=%d\n", ret);
+ if (parent->ops->remove) {
+ ret = parent->ops->remove(mdev);
+ if (ret)
+ dev_err(&mdev->dev, "Remove failed: err=%d\n", ret);
+ }
/* Balances with device_initialize() */
put_device(&mdev->dev);
@@ -127,7 +129,9 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
char *envp[] = { env_string, NULL };
/* check for mandatory ops */
- if (!ops || !ops->create || !ops->remove || !ops->supported_type_groups)
+ if (!ops || !ops->supported_type_groups)
+ return -EINVAL;
+ if (!ops->device_driver && (!ops->create || !ops->remove))
return -EINVAL;
dev = get_device(dev);
@@ -256,6 +260,7 @@ int mdev_device_create(struct mdev_type *type, const guid_t *uuid)
int ret;
struct mdev_device *mdev, *tmp;
struct mdev_parent *parent = type->parent;
+ struct mdev_driver *drv = parent->ops->device_driver;
mutex_lock(&mdev_list_lock);
@@ -296,14 +301,22 @@ int mdev_device_create(struct mdev_type *type, const guid_t *uuid)
goto out_put_device;
}
- ret = parent->ops->create(mdev);
- if (ret)
- goto out_unlock;
+ if (parent->ops->create) {
+ ret = parent->ops->create(mdev);
+ if (ret)
+ goto out_unlock;
+ }
ret = device_add(&mdev->dev);
if (ret)
goto out_remove;
+ if (!drv)
+ drv = &vfio_mdev_driver;
+ ret = device_driver_attach(&drv->driver, &mdev->dev);
+ if (ret)
+ goto out_del;
+
ret = mdev_create_sysfs_files(mdev);
if (ret)
goto out_del;
@@ -317,7 +330,8 @@ int mdev_device_create(struct mdev_type *type, const guid_t *uuid)
out_del:
device_del(&mdev->dev);
out_remove:
- parent->ops->remove(mdev);
+ if (parent->ops->remove)
+ parent->ops->remove(mdev);
out_unlock:
up_read(&parent->unreg_sem);
out_put_device:
@@ -360,11 +374,24 @@ int mdev_device_remove(struct mdev_device *mdev)
static int __init mdev_init(void)
{
- return mdev_bus_register();
+ int rc;
+
+ rc = mdev_bus_register();
+ if (rc)
+ return rc;
+ rc = mdev_register_driver(&vfio_mdev_driver);
+ if (rc)
+ goto err_bus;
+ return 0;
+err_bus:
+ mdev_bus_unregister();
+ return rc;
}
static void __exit mdev_exit(void)
{
+ mdev_unregister_driver(&vfio_mdev_driver);
+
if (mdev_bus_compat_class)
class_compat_unregister(mdev_bus_compat_class);
@@ -378,4 +405,3 @@ MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_SOFTDEP("post: vfio_mdev");
diff --git a/drivers/vfio/mdev/mdev_driver.c b/drivers/vfio/mdev/mdev_driver.c
index 041699571b7e..c368ec824e2b 100644
--- a/drivers/vfio/mdev/mdev_driver.c
+++ b/drivers/vfio/mdev/mdev_driver.c
@@ -71,10 +71,20 @@ static int mdev_remove(struct device *dev)
return 0;
}
+static int mdev_match(struct device *dev, struct device_driver *drv)
+{
+ /*
+ * No drivers automatically match. Drivers are only bound by explicit
+ * device_driver_attach()
+ */
+ return 0;
+}
+
struct bus_type mdev_bus_type = {
.name = "mdev",
.probe = mdev_probe,
.remove = mdev_remove,
+ .match = mdev_match,
};
EXPORT_SYMBOL_GPL(mdev_bus_type);
diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h
index 6999c89db7b1..afbad7b0a14a 100644
--- a/drivers/vfio/mdev/mdev_private.h
+++ b/drivers/vfio/mdev/mdev_private.h
@@ -37,6 +37,8 @@ struct mdev_type {
#define to_mdev_type(_kobj) \
container_of(_kobj, struct mdev_type, kobj)
+extern struct mdev_driver vfio_mdev_driver;
+
int parent_create_sysfs_files(struct mdev_parent *parent);
void parent_remove_sysfs_files(struct mdev_parent *parent);
diff --git a/drivers/vfio/mdev/vfio_mdev.c b/drivers/vfio/mdev/vfio_mdev.c
index 922729071c5a..39ef7489fe47 100644
--- a/drivers/vfio/mdev/vfio_mdev.c
+++ b/drivers/vfio/mdev/vfio_mdev.c
@@ -17,28 +17,15 @@
#include "mdev_private.h"
-#define DRIVER_VERSION "0.1"
-#define DRIVER_AUTHOR "NVIDIA Corporation"
-#define DRIVER_DESC "VFIO based driver for Mediated device"
-
static int vfio_mdev_open(struct vfio_device *core_vdev)
{
struct mdev_device *mdev = to_mdev_device(core_vdev->dev);
struct mdev_parent *parent = mdev->type->parent;
- int ret;
-
if (unlikely(!parent->ops->open))
return -EINVAL;
- if (!try_module_get(THIS_MODULE))
- return -ENODEV;
-
- ret = parent->ops->open(mdev);
- if (ret)
- module_put(THIS_MODULE);
-
- return ret;
+ return parent->ops->open(mdev);
}
static void vfio_mdev_release(struct vfio_device *core_vdev)
@@ -48,8 +35,6 @@ static void vfio_mdev_release(struct vfio_device *core_vdev)
if (likely(parent->ops->release))
parent->ops->release(mdev);
-
- module_put(THIS_MODULE);
}
static long vfio_mdev_unlocked_ioctl(struct vfio_device *core_vdev,
@@ -151,7 +136,7 @@ static void vfio_mdev_remove(struct mdev_device *mdev)
kfree(vdev);
}
-static struct mdev_driver vfio_mdev_driver = {
+struct mdev_driver vfio_mdev_driver = {
.driver = {
.name = "vfio_mdev",
.owner = THIS_MODULE,
@@ -160,21 +145,3 @@ static struct mdev_driver vfio_mdev_driver = {
.probe = vfio_mdev_probe,
.remove = vfio_mdev_remove,
};
-
-static int __init vfio_mdev_init(void)
-{
- return mdev_register_driver(&vfio_mdev_driver);
-}
-
-static void __exit vfio_mdev_exit(void)
-{
- mdev_unregister_driver(&vfio_mdev_driver);
-}
-
-module_init(vfio_mdev_init)
-module_exit(vfio_mdev_exit)
-
-MODULE_VERSION(DRIVER_VERSION);
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index bd7c482c948a..318864d52837 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -477,13 +477,10 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
* We can not use the "try" reset interface here, which will
* overwrite the previously restored configuration information.
*/
- if (vdev->reset_works && pci_cfg_access_trylock(pdev)) {
- if (device_trylock(&pdev->dev)) {
- if (!__pci_reset_function_locked(pdev))
- vdev->needs_reset = false;
- device_unlock(&pdev->dev);
- }
- pci_cfg_access_unlock(pdev);
+ if (vdev->reset_works && pci_dev_trylock(pdev)) {
+ if (!__pci_reset_function_locked(pdev))
+ vdev->needs_reset = false;
+ pci_dev_unlock(pdev);
}
pci_restore_state(pdev);
@@ -558,8 +555,6 @@ static void vfio_pci_release(struct vfio_device *core_vdev)
}
mutex_unlock(&vdev->reflck->lock);
-
- module_put(THIS_MODULE);
}
static int vfio_pci_open(struct vfio_device *core_vdev)
@@ -568,9 +563,6 @@ static int vfio_pci_open(struct vfio_device *core_vdev)
container_of(core_vdev, struct vfio_pci_device, vdev);
int ret = 0;
- if (!try_module_get(THIS_MODULE))
- return -ENODEV;
-
mutex_lock(&vdev->reflck->lock);
if (!vdev->refcnt) {
@@ -584,8 +576,6 @@ static int vfio_pci_open(struct vfio_device *core_vdev)
vdev->refcnt++;
error:
mutex_unlock(&vdev->reflck->lock);
- if (ret)
- module_put(THIS_MODULE);
return ret;
}
@@ -1594,6 +1584,7 @@ static vm_fault_t vfio_pci_mmap_fault(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
struct vfio_pci_device *vdev = vma->vm_private_data;
+ struct vfio_pci_mmap_vma *mmap_vma;
vm_fault_t ret = VM_FAULT_NOPAGE;
mutex_lock(&vdev->vma_lock);
@@ -1601,24 +1592,36 @@ static vm_fault_t vfio_pci_mmap_fault(struct vm_fault *vmf)
if (!__vfio_pci_memory_enabled(vdev)) {
ret = VM_FAULT_SIGBUS;
- mutex_unlock(&vdev->vma_lock);
goto up_out;
}
- if (__vfio_pci_add_vma(vdev, vma)) {
- ret = VM_FAULT_OOM;
- mutex_unlock(&vdev->vma_lock);
- goto up_out;
+ /*
+ * We populate the whole vma on fault, so we need to test whether
+ * the vma has already been mapped, such as for concurrent faults
+ * to the same vma. io_remap_pfn_range() will trigger a BUG_ON if
+ * we ask it to fill the same range again.
+ */
+ list_for_each_entry(mmap_vma, &vdev->vma_list, vma_next) {
+ if (mmap_vma->vma == vma)
+ goto up_out;
}
- mutex_unlock(&vdev->vma_lock);
-
if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start, vma->vm_page_prot))
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
ret = VM_FAULT_SIGBUS;
+ zap_vma_ptes(vma, vma->vm_start, vma->vm_end - vma->vm_start);
+ goto up_out;
+ }
+
+ if (__vfio_pci_add_vma(vdev, vma)) {
+ ret = VM_FAULT_OOM;
+ zap_vma_ptes(vma, vma->vm_start, vma->vm_end - vma->vm_start);
+ }
up_out:
up_read(&vdev->memory_lock);
+ mutex_unlock(&vdev->vma_lock);
return ret;
}
diff --git a/drivers/vfio/platform/vfio_amba.c b/drivers/vfio/platform/vfio_amba.c
index f970eb2a999f..badfffea14fb 100644
--- a/drivers/vfio/platform/vfio_amba.c
+++ b/drivers/vfio/platform/vfio_amba.c
@@ -59,7 +59,6 @@ static int vfio_amba_probe(struct amba_device *adev, const struct amba_id *id)
vdev->flags = VFIO_DEVICE_FLAGS_AMBA;
vdev->get_resource = get_amba_resource;
vdev->get_irq = get_amba_irq;
- vdev->parent_module = THIS_MODULE;
vdev->reset_required = false;
ret = vfio_platform_probe_common(vdev, &adev->dev);
diff --git a/drivers/vfio/platform/vfio_platform.c b/drivers/vfio/platform/vfio_platform.c
index e4027799a154..68a1c87066d7 100644
--- a/drivers/vfio/platform/vfio_platform.c
+++ b/drivers/vfio/platform/vfio_platform.c
@@ -50,7 +50,6 @@ static int vfio_platform_probe(struct platform_device *pdev)
vdev->flags = VFIO_DEVICE_FLAGS_PLATFORM;
vdev->get_resource = get_platform_resource;
vdev->get_irq = get_platform_irq;
- vdev->parent_module = THIS_MODULE;
vdev->reset_required = reset_required;
ret = vfio_platform_probe_common(vdev, &pdev->dev);
diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c
index 470fcf7dac56..703164df7637 100644
--- a/drivers/vfio/platform/vfio_platform_common.c
+++ b/drivers/vfio/platform/vfio_platform_common.c
@@ -241,8 +241,6 @@ static void vfio_platform_release(struct vfio_device *core_vdev)
}
mutex_unlock(&driver_lock);
-
- module_put(vdev->parent_module);
}
static int vfio_platform_open(struct vfio_device *core_vdev)
@@ -251,9 +249,6 @@ static int vfio_platform_open(struct vfio_device *core_vdev)
container_of(core_vdev, struct vfio_platform_device, vdev);
int ret;
- if (!try_module_get(vdev->parent_module))
- return -ENODEV;
-
mutex_lock(&driver_lock);
if (!vdev->refcnt) {
@@ -291,7 +286,6 @@ err_irq:
vfio_platform_regions_cleanup(vdev);
err_reg:
mutex_unlock(&driver_lock);
- module_put(vdev->parent_module);
return ret;
}
diff --git a/drivers/vfio/platform/vfio_platform_private.h b/drivers/vfio/platform/vfio_platform_private.h
index a5ba82c8cbc3..dfb834c13659 100644
--- a/drivers/vfio/platform/vfio_platform_private.h
+++ b/drivers/vfio/platform/vfio_platform_private.h
@@ -50,7 +50,6 @@ struct vfio_platform_device {
u32 num_irqs;
int refcnt;
struct mutex igate;
- struct module *parent_module;
const char *compat;
const char *acpihid;
struct module *reset_module;
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index 5e631c359ef2..02cc51ce6891 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -1369,8 +1369,14 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
if (IS_ERR(device))
return PTR_ERR(device);
+ if (!try_module_get(device->dev->driver->owner)) {
+ vfio_device_put(device);
+ return -ENODEV;
+ }
+
ret = device->ops->open(device);
if (ret) {
+ module_put(device->dev->driver->owner);
vfio_device_put(device);
return ret;
}
@@ -1382,6 +1388,7 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
ret = get_unused_fd_flags(O_CLOEXEC);
if (ret < 0) {
device->ops->release(device);
+ module_put(device->dev->driver->owner);
vfio_device_put(device);
return ret;
}
@@ -1392,6 +1399,7 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
put_unused_fd(ret);
ret = PTR_ERR(filep);
device->ops->release(device);
+ module_put(device->dev->driver->owner);
vfio_device_put(device);
return ret;
}
@@ -1550,6 +1558,8 @@ static int vfio_device_fops_release(struct inode *inode, struct file *filep)
device->ops->release(device);
+ module_put(device->dev->driver->owner);
+
vfio_group_try_dissolve_container(device->group);
vfio_device_put(device);
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index a3e925a41b0d..0b4f7c174c7a 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -110,7 +110,7 @@ struct vfio_batch {
int offset; /* of next entry in pages */
};
-struct vfio_group {
+struct vfio_iommu_group {
struct iommu_group *iommu_group;
struct list_head next;
bool mdev_group; /* An mdev group */
@@ -160,8 +160,9 @@ struct vfio_regions {
static int put_pfn(unsigned long pfn, int prot);
-static struct vfio_group *vfio_iommu_find_iommu_group(struct vfio_iommu *iommu,
- struct iommu_group *iommu_group);
+static struct vfio_iommu_group*
+vfio_iommu_find_iommu_group(struct vfio_iommu *iommu,
+ struct iommu_group *iommu_group);
/*
* This code handles mapping and unmapping of user data buffers
@@ -567,7 +568,7 @@ static int vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
vaddr = untagged_addr(vaddr);
retry:
- vma = find_vma_intersection(mm, vaddr, vaddr + 1);
+ vma = vma_lookup(mm, vaddr);
if (vma && vma->vm_flags & VM_PFNMAP) {
ret = follow_fault_pfn(vma, mm, vaddr, pfn, prot & IOMMU_WRITE);
@@ -836,7 +837,7 @@ static int vfio_iommu_type1_pin_pages(void *iommu_data,
unsigned long *phys_pfn)
{
struct vfio_iommu *iommu = iommu_data;
- struct vfio_group *group;
+ struct vfio_iommu_group *group;
int i, j, ret;
unsigned long remote_vaddr;
struct vfio_dma *dma;
@@ -1875,10 +1876,10 @@ static void vfio_test_domain_fgsp(struct vfio_domain *domain)
__free_pages(pages, order);
}
-static struct vfio_group *find_iommu_group(struct vfio_domain *domain,
- struct iommu_group *iommu_group)
+static struct vfio_iommu_group *find_iommu_group(struct vfio_domain *domain,
+ struct iommu_group *iommu_group)
{
- struct vfio_group *g;
+ struct vfio_iommu_group *g;
list_for_each_entry(g, &domain->group_list, next) {
if (g->iommu_group == iommu_group)
@@ -1888,11 +1889,12 @@ static struct vfio_group *find_iommu_group(struct vfio_domain *domain,
return NULL;
}
-static struct vfio_group *vfio_iommu_find_iommu_group(struct vfio_iommu *iommu,
- struct iommu_group *iommu_group)
+static struct vfio_iommu_group*
+vfio_iommu_find_iommu_group(struct vfio_iommu *iommu,
+ struct iommu_group *iommu_group)
{
struct vfio_domain *domain;
- struct vfio_group *group = NULL;
+ struct vfio_iommu_group *group = NULL;
list_for_each_entry(domain, &iommu->domain_list, next) {
group = find_iommu_group(domain, iommu_group);
@@ -1967,7 +1969,7 @@ static int vfio_mdev_detach_domain(struct device *dev, void *data)
}
static int vfio_iommu_attach_group(struct vfio_domain *domain,
- struct vfio_group *group)
+ struct vfio_iommu_group *group)
{
if (group->mdev_group)
return iommu_group_for_each_dev(group->iommu_group,
@@ -1978,7 +1980,7 @@ static int vfio_iommu_attach_group(struct vfio_domain *domain,
}
static void vfio_iommu_detach_group(struct vfio_domain *domain,
- struct vfio_group *group)
+ struct vfio_iommu_group *group)
{
if (group->mdev_group)
iommu_group_for_each_dev(group->iommu_group, domain->domain,
@@ -2242,7 +2244,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
struct iommu_group *iommu_group)
{
struct vfio_iommu *iommu = iommu_data;
- struct vfio_group *group;
+ struct vfio_iommu_group *group;
struct vfio_domain *domain, *d;
struct bus_type *bus = NULL;
int ret;
@@ -2518,7 +2520,7 @@ static int vfio_iommu_resv_refresh(struct vfio_iommu *iommu,
struct list_head *iova_copy)
{
struct vfio_domain *d;
- struct vfio_group *g;
+ struct vfio_iommu_group *g;
struct vfio_iova *node;
dma_addr_t start, end;
LIST_HEAD(resv_regions);
@@ -2560,7 +2562,7 @@ static void vfio_iommu_type1_detach_group(void *iommu_data,
{
struct vfio_iommu *iommu = iommu_data;
struct vfio_domain *domain;
- struct vfio_group *group;
+ struct vfio_iommu_group *group;
bool update_dirty_scope = false;
LIST_HEAD(iova_copy);
@@ -2681,7 +2683,7 @@ static void *vfio_iommu_type1_open(unsigned long arg)
static void vfio_release_domain(struct vfio_domain *domain, bool external)
{
- struct vfio_group *group, *group_tmp;
+ struct vfio_iommu_group *group, *group_tmp;
list_for_each_entry_safe(group, group_tmp,
&domain->group_list, next) {
diff --git a/drivers/vhost/iotlb.c b/drivers/vhost/iotlb.c
index 0fd3f87e913c..0582079e4bcc 100644
--- a/drivers/vhost/iotlb.c
+++ b/drivers/vhost/iotlb.c
@@ -83,7 +83,7 @@ int vhost_iotlb_add_range(struct vhost_iotlb *iotlb,
EXPORT_SYMBOL_GPL(vhost_iotlb_add_range);
/**
- * vring_iotlb_del_range - delete overlapped ranges from vhost IOTLB
+ * vhost_iotlb_del_range - delete overlapped ranges from vhost IOTLB
* @iotlb: the IOTLB
* @start: start of the IOVA range
* @last: last of IOVA range
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index df82b124170e..6414bd5741b8 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -744,11 +744,9 @@ static int vhost_net_build_xdp(struct vhost_net_virtqueue *nvq,
if (copied != len)
return -EFAULT;
- xdp->data_hard_start = buf;
- xdp->data = buf + pad;
- xdp->data_end = xdp->data + len;
+ xdp_init_buff(xdp, buflen, NULL);
+ xdp_prepare_buff(xdp, buf, pad, len, true);
hdr->buflen = buflen;
- xdp->frame_sz = buflen;
--net->refcnt_bias;
alloc_frag->offset += buflen;
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index d16c04dcc144..46f897e41217 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -1430,11 +1430,6 @@ static void vhost_scsi_handle_kick(struct vhost_work *work)
vhost_scsi_handle_vq(vs, vq);
}
-static void vhost_scsi_flush_vq(struct vhost_scsi *vs, int index)
-{
- vhost_poll_flush(&vs->vqs[index].vq.poll);
-}
-
/* Callers must hold dev mutex */
static void vhost_scsi_flush(struct vhost_scsi *vs)
{
@@ -1453,10 +1448,7 @@ static void vhost_scsi_flush(struct vhost_scsi *vs)
kref_put(&old_inflight[i]->kref, vhost_scsi_done_inflight);
/* Flush both the vhost poll and vhost work */
- for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)
- vhost_scsi_flush_vq(vs, i);
- vhost_work_flush(&vs->dev, &vs->vs_completion_work);
- vhost_work_flush(&vs->dev, &vs->vs_event_work);
+ vhost_work_dev_flush(&vs->dev);
/* Wait for all reqs issued before the flush to be finished */
for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)
@@ -1740,11 +1732,12 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
mutex_lock(&vq->mutex);
vhost_vq_set_backend(vq, NULL);
mutex_unlock(&vq->mutex);
- /*
- * Make sure cmds are not running before tearing them
- * down.
- */
- vhost_scsi_flush(vs);
+ }
+ /* Make sure cmds are not running before tearing them down. */
+ vhost_scsi_flush(vs);
+
+ for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
+ vq = &vs->vqs[i].vq;
vhost_scsi_destroy_vq_cmds(vq);
}
}
diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
index fb41db3da611..210ab35a7ebf 100644
--- a/drivers/vhost/vdpa.c
+++ b/drivers/vhost/vdpa.c
@@ -383,7 +383,7 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
if (r)
return r;
- vq->last_avail_idx = vq_state.avail_index;
+ vq->last_avail_idx = vq_state.split.avail_index;
break;
}
@@ -401,7 +401,7 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
break;
case VHOST_SET_VRING_BASE:
- vq_state.avail_index = vq->last_avail_idx;
+ vq_state.split.avail_index = vq->last_avail_idx;
if (ops->set_vq_state(vdpa, idx, &vq_state))
r = -EINVAL;
break;
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 5ccb0705beae..b9e853e6094d 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -231,7 +231,7 @@ void vhost_poll_stop(struct vhost_poll *poll)
}
EXPORT_SYMBOL_GPL(vhost_poll_stop);
-void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work)
+void vhost_work_dev_flush(struct vhost_dev *dev)
{
struct vhost_flush_struct flush;
@@ -243,13 +243,13 @@ void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work)
wait_for_completion(&flush.wait_event);
}
}
-EXPORT_SYMBOL_GPL(vhost_work_flush);
+EXPORT_SYMBOL_GPL(vhost_work_dev_flush);
/* Flush any work that has been scheduled. When calling this, don't hold any
* locks that are also used by the callback. */
void vhost_poll_flush(struct vhost_poll *poll)
{
- vhost_work_flush(poll->dev, &poll->work);
+ vhost_work_dev_flush(poll->dev);
}
EXPORT_SYMBOL_GPL(vhost_poll_flush);
@@ -538,7 +538,7 @@ static int vhost_attach_cgroups(struct vhost_dev *dev)
attach.owner = current;
vhost_work_init(&attach.work, vhost_attach_cgroups_work);
vhost_work_queue(dev, &attach.work);
- vhost_work_flush(dev, &attach.work);
+ vhost_work_dev_flush(dev);
return attach.ret;
}
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index b063324c7669..638bb640d6b4 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -20,20 +20,20 @@ typedef void (*vhost_work_fn_t)(struct vhost_work *work);
#define VHOST_WORK_QUEUED 1
struct vhost_work {
- struct llist_node node;
- vhost_work_fn_t fn;
- unsigned long flags;
+ struct llist_node node;
+ vhost_work_fn_t fn;
+ unsigned long flags;
};
/* Poll a file (eventfd or socket) */
/* Note: there's nothing vhost specific about this structure. */
struct vhost_poll {
- poll_table table;
- wait_queue_head_t *wqh;
- wait_queue_entry_t wait;
- struct vhost_work work;
- __poll_t mask;
- struct vhost_dev *dev;
+ poll_table table;
+ wait_queue_head_t *wqh;
+ wait_queue_entry_t wait;
+ struct vhost_work work;
+ __poll_t mask;
+ struct vhost_dev *dev;
};
void vhost_work_init(struct vhost_work *work, vhost_work_fn_t fn);
@@ -46,8 +46,7 @@ int vhost_poll_start(struct vhost_poll *poll, struct file *file);
void vhost_poll_stop(struct vhost_poll *poll);
void vhost_poll_flush(struct vhost_poll *poll);
void vhost_poll_queue(struct vhost_poll *poll);
-void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work);
-long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp);
+void vhost_work_dev_flush(struct vhost_dev *dev);
struct vhost_log {
u64 addr;
diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index 5e78fb719602..f249622ef11b 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -31,7 +31,8 @@
enum {
VHOST_VSOCK_FEATURES = VHOST_FEATURES |
- (1ULL << VIRTIO_F_ACCESS_PLATFORM)
+ (1ULL << VIRTIO_F_ACCESS_PLATFORM) |
+ (1ULL << VIRTIO_VSOCK_F_SEQPACKET)
};
enum {
@@ -56,6 +57,7 @@ struct vhost_vsock {
atomic_t queued_replies;
u32 guest_cid;
+ bool seqpacket_allow;
};
static u32 vhost_transport_get_local_cid(void)
@@ -112,6 +114,7 @@ vhost_transport_do_send_pkt(struct vhost_vsock *vsock,
size_t nbytes;
size_t iov_len, payload_len;
int head;
+ bool restore_flag = false;
spin_lock_bh(&vsock->send_pkt_list_lock);
if (list_empty(&vsock->send_pkt_list)) {
@@ -168,9 +171,26 @@ vhost_transport_do_send_pkt(struct vhost_vsock *vsock,
/* If the packet is greater than the space available in the
* buffer, we split it using multiple buffers.
*/
- if (payload_len > iov_len - sizeof(pkt->hdr))
+ if (payload_len > iov_len - sizeof(pkt->hdr)) {
payload_len = iov_len - sizeof(pkt->hdr);
+ /* As we are copying pieces of large packet's buffer to
+ * small rx buffers, headers of packets in rx queue are
+ * created dynamically and are initialized with header
+ * of current packet(except length). But in case of
+ * SOCK_SEQPACKET, we also must clear record delimeter
+ * bit(VIRTIO_VSOCK_SEQ_EOR). Otherwise, instead of one
+ * packet with delimeter(which marks end of record),
+ * there will be sequence of packets with delimeter
+ * bit set. After initialized header will be copied to
+ * rx buffer, this bit will be restored.
+ */
+ if (le32_to_cpu(pkt->hdr.flags) & VIRTIO_VSOCK_SEQ_EOR) {
+ pkt->hdr.flags &= ~cpu_to_le32(VIRTIO_VSOCK_SEQ_EOR);
+ restore_flag = true;
+ }
+ }
+
/* Set the correct length in the header */
pkt->hdr.len = cpu_to_le32(payload_len);
@@ -204,6 +224,9 @@ vhost_transport_do_send_pkt(struct vhost_vsock *vsock,
* to send it with the next available buffer.
*/
if (pkt->off < pkt->len) {
+ if (restore_flag)
+ pkt->hdr.flags |= cpu_to_le32(VIRTIO_VSOCK_SEQ_EOR);
+
/* We are queueing the same virtio_vsock_pkt to handle
* the remaining bytes, and we want to deliver it
* to monitoring devices in the next iteration.
@@ -354,8 +377,7 @@ vhost_vsock_alloc_pkt(struct vhost_virtqueue *vq,
return NULL;
}
- if (le16_to_cpu(pkt->hdr.type) == VIRTIO_VSOCK_TYPE_STREAM)
- pkt->len = le32_to_cpu(pkt->hdr.len);
+ pkt->len = le32_to_cpu(pkt->hdr.len);
/* No payload */
if (!pkt->len)
@@ -398,6 +420,8 @@ static bool vhost_vsock_more_replies(struct vhost_vsock *vsock)
return val < vq->num;
}
+static bool vhost_transport_seqpacket_allow(u32 remote_cid);
+
static struct virtio_transport vhost_transport = {
.transport = {
.module = THIS_MODULE,
@@ -424,6 +448,11 @@ static struct virtio_transport vhost_transport = {
.stream_is_active = virtio_transport_stream_is_active,
.stream_allow = virtio_transport_stream_allow,
+ .seqpacket_dequeue = virtio_transport_seqpacket_dequeue,
+ .seqpacket_enqueue = virtio_transport_seqpacket_enqueue,
+ .seqpacket_allow = vhost_transport_seqpacket_allow,
+ .seqpacket_has_data = virtio_transport_seqpacket_has_data,
+
.notify_poll_in = virtio_transport_notify_poll_in,
.notify_poll_out = virtio_transport_notify_poll_out,
.notify_recv_init = virtio_transport_notify_recv_init,
@@ -441,6 +470,22 @@ static struct virtio_transport vhost_transport = {
.send_pkt = vhost_transport_send_pkt,
};
+static bool vhost_transport_seqpacket_allow(u32 remote_cid)
+{
+ struct vhost_vsock *vsock;
+ bool seqpacket_allow = false;
+
+ rcu_read_lock();
+ vsock = vhost_vsock_get(remote_cid);
+
+ if (vsock)
+ seqpacket_allow = vsock->seqpacket_allow;
+
+ rcu_read_unlock();
+
+ return seqpacket_allow;
+}
+
static void vhost_vsock_handle_tx_kick(struct vhost_work *work)
{
struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
@@ -663,7 +708,7 @@ static void vhost_vsock_flush(struct vhost_vsock *vsock)
for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++)
if (vsock->vqs[i].handle_kick)
vhost_poll_flush(&vsock->vqs[i].poll);
- vhost_work_flush(&vsock->dev, &vsock->send_pkt_work);
+ vhost_work_dev_flush(&vsock->dev);
}
static void vhost_vsock_reset_orphans(struct sock *sk)
@@ -689,7 +734,7 @@ static void vhost_vsock_reset_orphans(struct sock *sk)
vsk->peer_shutdown = SHUTDOWN_MASK;
sk->sk_state = SS_UNCONNECTED;
sk->sk_err = ECONNRESET;
- sk->sk_error_report(sk);
+ sk_error_report(sk);
}
static int vhost_vsock_dev_release(struct inode *inode, struct file *file)
@@ -785,6 +830,9 @@ static int vhost_vsock_set_features(struct vhost_vsock *vsock, u64 features)
goto err;
}
+ if (features & (1ULL << VIRTIO_VSOCK_F_SEQPACKET))
+ vsock->seqpacket_allow = true;
+
for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) {
vq = &vsock->vqs[i];
mutex_lock(&vq->mutex);
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index d83c87b902c1..e32694c13da5 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -128,12 +128,12 @@ config LCD_HX8357
If you have a HX-8357 LCD panel, say Y to enable its LCD control
driver.
- config LCD_OTM3225A
- tristate "ORISE Technology OTM3225A support"
- depends on SPI
- help
- If you have a panel based on the OTM3225A controller
- chip then say y to include a driver for it.
+config LCD_OTM3225A
+ tristate "ORISE Technology OTM3225A support"
+ depends on SPI
+ help
+ If you have a panel based on the OTM3225A controller
+ chip then say y to include a driver for it.
endif # LCD_CLASS_DEVICE
@@ -269,11 +269,11 @@ config BACKLIGHT_MAX8925
WLED output, say Y here to enable this driver.
config BACKLIGHT_APPLE
- tristate "Apple Backlight Driver"
- depends on X86 && ACPI
- help
- If you have an Intel-based Apple say Y to enable a driver for its
- backlight.
+ tristate "Apple Backlight Driver"
+ depends on X86 && ACPI
+ help
+ If you have an Intel-based Apple say Y to enable a driver for its
+ backlight.
config BACKLIGHT_TOSA
tristate "Sharp SL-6000 Backlight Driver"
@@ -289,6 +289,14 @@ config BACKLIGHT_QCOM_WLED
If you have the Qualcomm PMIC, say Y to enable a driver for the
WLED block. Currently it supports PM8941 and PMI8998.
+config BACKLIGHT_RT4831
+ tristate "Richtek RT4831 Backlight Driver"
+ depends on MFD_RT4831
+ help
+ This enables support for Richtek RT4831 Backlight driver.
+ It's commonly used to drive the display WLED. There're four channels
+ inisde, and each channel can provide up to 30mA current.
+
config BACKLIGHT_SAHARA
tristate "Tabletkiosk Sahara Touch-iT Backlight Driver"
depends on X86
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 685f3f1ca4df..cae2c83422ae 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o
obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
obj-$(CONFIG_BACKLIGHT_QCOM_WLED) += qcom-wled.o
+obj-$(CONFIG_BACKLIGHT_RT4831) += rt4831-backlight.o
obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c
index e88a2b0e5904..e8b185bb6f5e 100644
--- a/drivers/video/backlight/lm3630a_bl.c
+++ b/drivers/video/backlight/lm3630a_bl.c
@@ -52,6 +52,7 @@ struct lm3630a_chip {
struct gpio_desc *enable_gpio;
struct regmap *regmap;
struct pwm_device *pwmd;
+ struct pwm_state pwmd_state;
};
/* i2c access */
@@ -167,16 +168,19 @@ static int lm3630a_intr_config(struct lm3630a_chip *pchip)
return rval;
}
-static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max)
+static int lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max)
{
- unsigned int period = pchip->pdata->pwm_period;
- unsigned int duty = br * period / br_max;
+ int err;
- pwm_config(pchip->pwmd, duty, period);
- if (duty)
- pwm_enable(pchip->pwmd);
- else
- pwm_disable(pchip->pwmd);
+ pchip->pwmd_state.period = pchip->pdata->pwm_period;
+
+ err = pwm_set_relative_duty_cycle(&pchip->pwmd_state, br, br_max);
+ if (err)
+ return err;
+
+ pchip->pwmd_state.enabled = pchip->pwmd_state.duty_cycle ? true : false;
+
+ return pwm_apply_state(pchip->pwmd, &pchip->pwmd_state);
}
/* update and get brightness */
@@ -187,11 +191,9 @@ static int lm3630a_bank_a_update_status(struct backlight_device *bl)
enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
/* pwm control */
- if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) {
- lm3630a_pwm_ctrl(pchip, bl->props.brightness,
- bl->props.max_brightness);
- return bl->props.brightness;
- }
+ if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0)
+ return lm3630a_pwm_ctrl(pchip, bl->props.brightness,
+ bl->props.max_brightness);
/* disable sleep */
ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
@@ -210,8 +212,8 @@ static int lm3630a_bank_a_update_status(struct backlight_device *bl)
return 0;
out_i2c_err:
- dev_err(pchip->dev, "i2c failed to access\n");
- return bl->props.brightness;
+ dev_err(pchip->dev, "i2c failed to access (%pe)\n", ERR_PTR(ret));
+ return ret;
}
static int lm3630a_bank_a_get_brightness(struct backlight_device *bl)
@@ -264,11 +266,9 @@ static int lm3630a_bank_b_update_status(struct backlight_device *bl)
enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
/* pwm control */
- if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) {
- lm3630a_pwm_ctrl(pchip, bl->props.brightness,
- bl->props.max_brightness);
- return bl->props.brightness;
- }
+ if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0)
+ return lm3630a_pwm_ctrl(pchip, bl->props.brightness,
+ bl->props.max_brightness);
/* disable sleep */
ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
@@ -287,8 +287,8 @@ static int lm3630a_bank_b_update_status(struct backlight_device *bl)
return 0;
out_i2c_err:
- dev_err(pchip->dev, "i2c failed to access REG_CTRL\n");
- return bl->props.brightness;
+ dev_err(pchip->dev, "i2c failed to access (%pe)\n", ERR_PTR(ret));
+ return ret;
}
static int lm3630a_bank_b_get_brightness(struct backlight_device *bl)
@@ -482,8 +482,10 @@ static int lm3630a_parse_node(struct lm3630a_chip *pchip,
device_for_each_child_node(pchip->dev, node) {
ret = lm3630a_parse_bank(pdata, node, &seen_led_sources);
- if (ret)
+ if (ret) {
+ fwnode_handle_put(node);
return ret;
+ }
}
return ret;
@@ -563,11 +565,7 @@ static int lm3630a_probe(struct i2c_client *client,
return PTR_ERR(pchip->pwmd);
}
- /*
- * FIXME: pwm_apply_args() should be removed when switching to
- * the atomic PWM API.
- */
- pwm_apply_args(pchip->pwmd);
+ pwm_init_state(pchip->pwmd, &pchip->pwmd_state);
}
/* interrupt enable : irq 0 is not allowed */
diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c
index 7c02f87c51c2..d094299c2a48 100644
--- a/drivers/video/backlight/qcom-wled.c
+++ b/drivers/video/backlight/qcom-wled.c
@@ -1717,6 +1717,7 @@ static int wled_remove(struct platform_device *pdev)
static const struct of_device_id wled_match_table[] = {
{ .compatible = "qcom,pm8941-wled", .data = (void *)3 },
+ { .compatible = "qcom,pmi8994-wled", .data = (void *)4 },
{ .compatible = "qcom,pmi8998-wled", .data = (void *)4 },
{ .compatible = "qcom,pm660l-wled", .data = (void *)4 },
{ .compatible = "qcom,pm8150l-wled", .data = (void *)5 },
diff --git a/drivers/video/backlight/rt4831-backlight.c b/drivers/video/backlight/rt4831-backlight.c
new file mode 100644
index 000000000000..42155c7d2db1
--- /dev/null
+++ b/drivers/video/backlight/rt4831-backlight.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <dt-bindings/leds/rt4831-backlight.h>
+#include <linux/backlight.h>
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#define RT4831_REG_BLCFG 0x02
+#define RT4831_REG_BLDIML 0x04
+#define RT4831_REG_ENABLE 0x08
+
+#define RT4831_BLMAX_BRIGHTNESS 2048
+
+#define RT4831_BLOVP_MASK GENMASK(7, 5)
+#define RT4831_BLOVP_SHIFT 5
+#define RT4831_BLPWMEN_MASK BIT(0)
+#define RT4831_BLEN_MASK BIT(4)
+#define RT4831_BLCH_MASK GENMASK(3, 0)
+#define RT4831_BLDIML_MASK GENMASK(2, 0)
+#define RT4831_BLDIMH_MASK GENMASK(10, 3)
+#define RT4831_BLDIMH_SHIFT 3
+
+struct rt4831_priv {
+ struct device *dev;
+ struct regmap *regmap;
+ struct backlight_device *bl;
+};
+
+static int rt4831_bl_update_status(struct backlight_device *bl_dev)
+{
+ struct rt4831_priv *priv = bl_get_data(bl_dev);
+ int brightness = backlight_get_brightness(bl_dev);
+ unsigned int enable = brightness ? RT4831_BLEN_MASK : 0;
+ u8 v[2];
+ int ret;
+
+ if (brightness) {
+ v[0] = (brightness - 1) & RT4831_BLDIML_MASK;
+ v[1] = ((brightness - 1) & RT4831_BLDIMH_MASK) >> RT4831_BLDIMH_SHIFT;
+
+ ret = regmap_raw_write(priv->regmap, RT4831_REG_BLDIML, v, sizeof(v));
+ if (ret)
+ return ret;
+ }
+
+ return regmap_update_bits(priv->regmap, RT4831_REG_ENABLE, RT4831_BLEN_MASK, enable);
+
+}
+
+static int rt4831_bl_get_brightness(struct backlight_device *bl_dev)
+{
+ struct rt4831_priv *priv = bl_get_data(bl_dev);
+ unsigned int val;
+ u8 v[2];
+ int ret;
+
+ ret = regmap_read(priv->regmap, RT4831_REG_ENABLE, &val);
+ if (ret)
+ return ret;
+
+ if (!(val & RT4831_BLEN_MASK))
+ return 0;
+
+ ret = regmap_raw_read(priv->regmap, RT4831_REG_BLDIML, v, sizeof(v));
+ if (ret)
+ return ret;
+
+ ret = (v[1] << RT4831_BLDIMH_SHIFT) + (v[0] & RT4831_BLDIML_MASK) + 1;
+
+ return ret;
+}
+
+static const struct backlight_ops rt4831_bl_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = rt4831_bl_update_status,
+ .get_brightness = rt4831_bl_get_brightness,
+};
+
+static int rt4831_parse_backlight_properties(struct rt4831_priv *priv,
+ struct backlight_properties *bl_props)
+{
+ struct device *dev = priv->dev;
+ u8 propval;
+ u32 brightness;
+ unsigned int val = 0;
+ int ret;
+
+ /* common properties */
+ ret = device_property_read_u32(dev, "max-brightness", &brightness);
+ if (ret)
+ brightness = RT4831_BLMAX_BRIGHTNESS;
+
+ bl_props->max_brightness = min_t(u32, brightness, RT4831_BLMAX_BRIGHTNESS);
+
+ ret = device_property_read_u32(dev, "default-brightness", &brightness);
+ if (ret)
+ brightness = bl_props->max_brightness;
+
+ bl_props->brightness = min_t(u32, brightness, bl_props->max_brightness);
+
+ /* vendor properties */
+ if (device_property_read_bool(dev, "richtek,pwm-enable"))
+ val = RT4831_BLPWMEN_MASK;
+
+ ret = regmap_update_bits(priv->regmap, RT4831_REG_BLCFG, RT4831_BLPWMEN_MASK, val);
+ if (ret)
+ return ret;
+
+ ret = device_property_read_u8(dev, "richtek,bled-ovp-sel", &propval);
+ if (ret)
+ propval = RT4831_BLOVPLVL_21V;
+
+ propval = min_t(u8, propval, RT4831_BLOVPLVL_29V);
+ ret = regmap_update_bits(priv->regmap, RT4831_REG_BLCFG, RT4831_BLOVP_MASK,
+ propval << RT4831_BLOVP_SHIFT);
+ if (ret)
+ return ret;
+
+ ret = device_property_read_u8(dev, "richtek,channel-use", &propval);
+ if (ret) {
+ dev_err(dev, "richtek,channel-use DT property missing\n");
+ return ret;
+ }
+
+ if (!(propval & RT4831_BLCH_MASK)) {
+ dev_err(dev, "No channel specified\n");
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(priv->regmap, RT4831_REG_ENABLE, RT4831_BLCH_MASK, propval);
+}
+
+static int rt4831_bl_probe(struct platform_device *pdev)
+{
+ struct rt4831_priv *priv;
+ struct backlight_properties bl_props = { .type = BACKLIGHT_RAW,
+ .scale = BACKLIGHT_SCALE_LINEAR };
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = &pdev->dev;
+
+ priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!priv->regmap) {
+ dev_err(&pdev->dev, "Failed to init regmap\n");
+ return -ENODEV;
+ }
+
+ ret = rt4831_parse_backlight_properties(priv, &bl_props);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to parse backlight properties\n");
+ return ret;
+ }
+
+ priv->bl = devm_backlight_device_register(&pdev->dev, pdev->name, &pdev->dev, priv,
+ &rt4831_bl_ops, &bl_props);
+ if (IS_ERR(priv->bl)) {
+ dev_err(&pdev->dev, "Failed to register backlight\n");
+ return PTR_ERR(priv->bl);
+ }
+
+ backlight_update_status(priv->bl);
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+}
+
+static int rt4831_bl_remove(struct platform_device *pdev)
+{
+ struct rt4831_priv *priv = platform_get_drvdata(pdev);
+ struct backlight_device *bl_dev = priv->bl;
+
+ bl_dev->props.brightness = 0;
+ backlight_update_status(priv->bl);
+
+ return 0;
+}
+
+static const struct of_device_id __maybe_unused rt4831_bl_of_match[] = {
+ { .compatible = "richtek,rt4831-backlight", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rt4831_bl_of_match);
+
+static struct platform_driver rt4831_bl_driver = {
+ .driver = {
+ .name = "rt4831-backlight",
+ .of_match_table = rt4831_bl_of_match,
+ },
+ .probe = rt4831_bl_probe,
+ .remove = rt4831_bl_remove,
+};
+module_platform_driver(rt4831_bl_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index ee33b8ec62bb..840d9813b0bc 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -9,7 +9,7 @@ config VGA_CONSOLE
bool "VGA text console" if EXPERT || !X86
depends on !4xx && !PPC_8xx && !SPARC && !M68K && !PARISC && !SUPERH && \
(!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \
- !ARM64 && !ARC && !MICROBLAZE && !OPENRISC && !NDS32 && !S390
+ !ARM64 && !ARC && !MICROBLAZE && !OPENRISC && !NDS32 && !S390 && !UML
default y
help
Saying Y here will allow you to use Linux in text mode through a
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 5e1ad0c92bfc..d33c5cd684c0 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2209,7 +2209,6 @@ config FB_SIMPLE
config FB_SSD1307
tristate "Solomon SSD1307 framebuffer support"
depends on FB && I2C
- depends on OF
depends on GPIOLIB || COMPILE_TEST
select FB_SYS_FOPS
select FB_SYS_FILLRECT
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 98f193078c05..1c855145711b 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -970,13 +970,11 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
fb_var_to_videomode(&mode2, &info->var);
/* make sure we don't delete the videomode of current var */
ret = fb_mode_is_equal(&mode1, &mode2);
-
- if (!ret)
- fbcon_mode_deleted(info, &mode1);
-
- if (!ret)
- fb_delete_videomode(&mode1, &info->modelist);
-
+ if (!ret) {
+ ret = fbcon_mode_deleted(info, &mode1);
+ if (!ret)
+ fb_delete_videomode(&mode1, &info->modelist);
+ }
return ret ? -EINVAL : 0;
}
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index a7e6eea2c4a1..23999df52739 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -52,6 +52,7 @@
#include <linux/completion.h>
#include <linux/fb.h>
#include <linux/pci.h>
+#include <linux/panic_notifier.h>
#include <linux/efi.h>
#include <linux/console.h>
diff --git a/drivers/video/fbdev/xilinxfb.c b/drivers/video/fbdev/xilinxfb.c
index ffbf900648d9..438e2c78142f 100644
--- a/drivers/video/fbdev/xilinxfb.c
+++ b/drivers/video/fbdev/xilinxfb.c
@@ -241,6 +241,8 @@ xilinx_fb_blank(int blank_mode, struct fb_info *fbi)
case FB_BLANK_POWERDOWN:
/* turn off panel */
xilinx_fb_out32(drvdata, REG_CTRL, 0);
+ break;
+
default:
break;
}
diff --git a/drivers/virt/nitro_enclaves/ne_pci_dev.c b/drivers/virt/nitro_enclaves/ne_pci_dev.c
index b9c1de41e300..143207e9b969 100644
--- a/drivers/virt/nitro_enclaves/ne_pci_dev.c
+++ b/drivers/virt/nitro_enclaves/ne_pci_dev.c
@@ -480,6 +480,8 @@ static int ne_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto free_ne_pci_dev;
}
+ pci_set_master(pdev);
+
rc = pci_request_regions_exclusive(pdev, "nitro_enclaves");
if (rc < 0) {
dev_err(&pdev->dev, "Error in pci request regions [rc=%d]\n", rc);
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 510e9318854d..47dce91f788c 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -993,6 +993,23 @@ static int virtballoon_probe(struct virtio_device *vdev)
goto out_unregister_oom;
}
+ /*
+ * The default page reporting order is @pageblock_order, which
+ * corresponds to 512MB in size on ARM64 when 64KB base page
+ * size is used. The page reporting won't be triggered if the
+ * freeing page can't come up with a free area like that huge.
+ * So we specify the page reporting order to 5, corresponding
+ * to 2MB. It helps to avoid THP splitting if 4KB base page
+ * size is used by host.
+ *
+ * Ideally, the page reporting order is selected based on the
+ * host's base page size. However, it needs more work to report
+ * that value. The hard-coded order would be fine currently.
+ */
+#if defined(CONFIG_ARM64) && defined(CONFIG_ARM64_64K_PAGES)
+ vb->pr_dev_info.order = 5;
+#endif
+
err = page_reporting_register(&vb->pr_dev_info);
if (err)
goto out_unregister_oom;
diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c
index 10ec60d81e84..09ed55de07d7 100644
--- a/drivers/virtio/virtio_mem.c
+++ b/drivers/virtio/virtio_mem.c
@@ -75,10 +75,14 @@ enum virtio_mem_sbm_mb_state {
VIRTIO_MEM_SBM_MB_OFFLINE,
/* Partially plugged, fully added to Linux, offline. */
VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL,
- /* Fully plugged, fully added to Linux, online. */
- VIRTIO_MEM_SBM_MB_ONLINE,
- /* Partially plugged, fully added to Linux, online. */
- VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL,
+ /* Fully plugged, fully added to Linux, onlined to a kernel zone. */
+ VIRTIO_MEM_SBM_MB_KERNEL,
+ /* Partially plugged, fully added to Linux, online to a kernel zone */
+ VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL,
+ /* Fully plugged, fully added to Linux, onlined to ZONE_MOVABLE. */
+ VIRTIO_MEM_SBM_MB_MOVABLE,
+ /* Partially plugged, fully added to Linux, onlined to ZONE_MOVABLE. */
+ VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL,
VIRTIO_MEM_SBM_MB_COUNT
};
@@ -699,18 +703,6 @@ static int virtio_mem_sbm_remove_mb(struct virtio_mem *vm, unsigned long mb_id)
}
/*
- * See virtio_mem_remove_memory(): Try to remove all Linux memory blocks covered
- * by the big block.
- */
-static int virtio_mem_bbm_remove_bb(struct virtio_mem *vm, unsigned long bb_id)
-{
- const uint64_t addr = virtio_mem_bb_id_to_phys(vm, bb_id);
- const uint64_t size = vm->bbm.bb_size;
-
- return virtio_mem_remove_memory(vm, addr, size);
-}
-
-/*
* Try offlining and removing memory from Linux.
*
* Must not be called with the vm->hotplug_mutex held (possible deadlock with
@@ -832,11 +824,13 @@ static void virtio_mem_sbm_notify_offline(struct virtio_mem *vm,
unsigned long mb_id)
{
switch (virtio_mem_sbm_get_mb_state(vm, mb_id)) {
- case VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL:
+ case VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL:
+ case VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL:
virtio_mem_sbm_set_mb_state(vm, mb_id,
VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL);
break;
- case VIRTIO_MEM_SBM_MB_ONLINE:
+ case VIRTIO_MEM_SBM_MB_KERNEL:
+ case VIRTIO_MEM_SBM_MB_MOVABLE:
virtio_mem_sbm_set_mb_state(vm, mb_id,
VIRTIO_MEM_SBM_MB_OFFLINE);
break;
@@ -847,21 +841,29 @@ static void virtio_mem_sbm_notify_offline(struct virtio_mem *vm,
}
static void virtio_mem_sbm_notify_online(struct virtio_mem *vm,
- unsigned long mb_id)
+ unsigned long mb_id,
+ unsigned long start_pfn)
{
+ const bool is_movable = page_zonenum(pfn_to_page(start_pfn)) ==
+ ZONE_MOVABLE;
+ int new_state;
+
switch (virtio_mem_sbm_get_mb_state(vm, mb_id)) {
case VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL:
- virtio_mem_sbm_set_mb_state(vm, mb_id,
- VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL);
+ new_state = VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL;
+ if (is_movable)
+ new_state = VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL;
break;
case VIRTIO_MEM_SBM_MB_OFFLINE:
- virtio_mem_sbm_set_mb_state(vm, mb_id,
- VIRTIO_MEM_SBM_MB_ONLINE);
+ new_state = VIRTIO_MEM_SBM_MB_KERNEL;
+ if (is_movable)
+ new_state = VIRTIO_MEM_SBM_MB_MOVABLE;
break;
default:
BUG();
break;
}
+ virtio_mem_sbm_set_mb_state(vm, mb_id, new_state);
}
static void virtio_mem_sbm_notify_going_offline(struct virtio_mem *vm,
@@ -1015,7 +1017,7 @@ static int virtio_mem_memory_notifier_cb(struct notifier_block *nb,
break;
case MEM_ONLINE:
if (vm->in_sbm)
- virtio_mem_sbm_notify_online(vm, id);
+ virtio_mem_sbm_notify_online(vm, id, mhp->start_pfn);
atomic64_sub(size, &vm->offline_size);
/*
@@ -1065,6 +1067,7 @@ static int virtio_mem_memory_notifier_cb(struct notifier_block *nb,
static void virtio_mem_set_fake_offline(unsigned long pfn,
unsigned long nr_pages, bool onlined)
{
+ page_offline_begin();
for (; nr_pages--; pfn++) {
struct page *page = pfn_to_page(pfn);
@@ -1075,6 +1078,7 @@ static void virtio_mem_set_fake_offline(unsigned long pfn,
ClearPageReserved(page);
}
}
+ page_offline_end();
}
/*
@@ -1135,7 +1139,7 @@ static void virtio_mem_fake_online(unsigned long pfn, unsigned long nr_pages)
*/
static int virtio_mem_fake_offline(unsigned long pfn, unsigned long nr_pages)
{
- const bool is_movable = zone_idx(page_zone(pfn_to_page(pfn))) ==
+ const bool is_movable = page_zonenum(pfn_to_page(pfn)) ==
ZONE_MOVABLE;
int rc, retry_count;
@@ -1453,8 +1457,8 @@ static int virtio_mem_bbm_plug_bb(struct virtio_mem *vm, unsigned long bb_id)
*
* Note: can fail after some subblocks were unplugged.
*/
-static int virtio_mem_sbm_unplug_any_sb(struct virtio_mem *vm,
- unsigned long mb_id, uint64_t *nb_sb)
+static int virtio_mem_sbm_unplug_any_sb_raw(struct virtio_mem *vm,
+ unsigned long mb_id, uint64_t *nb_sb)
{
int sb_id, count;
int rc;
@@ -1496,7 +1500,7 @@ static int virtio_mem_sbm_unplug_mb(struct virtio_mem *vm, unsigned long mb_id)
{
uint64_t nb_sb = vm->sbm.sbs_per_mb;
- return virtio_mem_sbm_unplug_any_sb(vm, mb_id, &nb_sb);
+ return virtio_mem_sbm_unplug_any_sb_raw(vm, mb_id, &nb_sb);
}
/*
@@ -1583,9 +1587,9 @@ static int virtio_mem_sbm_plug_and_add_mb(struct virtio_mem *vm,
* Note: Can fail after some subblocks were successfully plugged.
*/
static int virtio_mem_sbm_plug_any_sb(struct virtio_mem *vm,
- unsigned long mb_id, uint64_t *nb_sb,
- bool online)
+ unsigned long mb_id, uint64_t *nb_sb)
{
+ const int old_state = virtio_mem_sbm_get_mb_state(vm, mb_id);
unsigned long pfn, nr_pages;
int sb_id, count;
int rc;
@@ -1607,7 +1611,7 @@ static int virtio_mem_sbm_plug_any_sb(struct virtio_mem *vm,
if (rc)
return rc;
*nb_sb -= count;
- if (!online)
+ if (old_state == VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL)
continue;
/* fake-online the pages if the memory block is online */
@@ -1617,23 +1621,22 @@ static int virtio_mem_sbm_plug_any_sb(struct virtio_mem *vm,
virtio_mem_fake_online(pfn, nr_pages);
}
- if (virtio_mem_sbm_test_sb_plugged(vm, mb_id, 0, vm->sbm.sbs_per_mb)) {
- if (online)
- virtio_mem_sbm_set_mb_state(vm, mb_id,
- VIRTIO_MEM_SBM_MB_ONLINE);
- else
- virtio_mem_sbm_set_mb_state(vm, mb_id,
- VIRTIO_MEM_SBM_MB_OFFLINE);
- }
+ if (virtio_mem_sbm_test_sb_plugged(vm, mb_id, 0, vm->sbm.sbs_per_mb))
+ virtio_mem_sbm_set_mb_state(vm, mb_id, old_state - 1);
return 0;
}
static int virtio_mem_sbm_plug_request(struct virtio_mem *vm, uint64_t diff)
{
+ const int mb_states[] = {
+ VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL,
+ VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL,
+ VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL,
+ };
uint64_t nb_sb = diff / vm->sbm.sb_size;
unsigned long mb_id;
- int rc;
+ int rc, i;
if (!nb_sb)
return 0;
@@ -1641,22 +1644,13 @@ static int virtio_mem_sbm_plug_request(struct virtio_mem *vm, uint64_t diff)
/* Don't race with onlining/offlining */
mutex_lock(&vm->hotplug_mutex);
- /* Try to plug subblocks of partially plugged online blocks. */
- virtio_mem_sbm_for_each_mb(vm, mb_id,
- VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL) {
- rc = virtio_mem_sbm_plug_any_sb(vm, mb_id, &nb_sb, true);
- if (rc || !nb_sb)
- goto out_unlock;
- cond_resched();
- }
-
- /* Try to plug subblocks of partially plugged offline blocks. */
- virtio_mem_sbm_for_each_mb(vm, mb_id,
- VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL) {
- rc = virtio_mem_sbm_plug_any_sb(vm, mb_id, &nb_sb, false);
- if (rc || !nb_sb)
- goto out_unlock;
- cond_resched();
+ for (i = 0; i < ARRAY_SIZE(mb_states); i++) {
+ virtio_mem_sbm_for_each_mb(vm, mb_id, mb_states[i]) {
+ rc = virtio_mem_sbm_plug_any_sb(vm, mb_id, &nb_sb);
+ if (rc || !nb_sb)
+ goto out_unlock;
+ cond_resched();
+ }
}
/*
@@ -1817,7 +1811,7 @@ static int virtio_mem_sbm_unplug_any_sb_offline(struct virtio_mem *vm,
{
int rc;
- rc = virtio_mem_sbm_unplug_any_sb(vm, mb_id, nb_sb);
+ rc = virtio_mem_sbm_unplug_any_sb_raw(vm, mb_id, nb_sb);
/* some subblocks might have been unplugged even on failure */
if (!virtio_mem_sbm_test_sb_plugged(vm, mb_id, 0, vm->sbm.sbs_per_mb))
@@ -1854,6 +1848,7 @@ static int virtio_mem_sbm_unplug_sb_online(struct virtio_mem *vm,
int count)
{
const unsigned long nr_pages = PFN_DOWN(vm->sbm.sb_size) * count;
+ const int old_state = virtio_mem_sbm_get_mb_state(vm, mb_id);
unsigned long start_pfn;
int rc;
@@ -1872,8 +1867,17 @@ static int virtio_mem_sbm_unplug_sb_online(struct virtio_mem *vm,
return rc;
}
- virtio_mem_sbm_set_mb_state(vm, mb_id,
- VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL);
+ switch (old_state) {
+ case VIRTIO_MEM_SBM_MB_KERNEL:
+ virtio_mem_sbm_set_mb_state(vm, mb_id,
+ VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL);
+ break;
+ case VIRTIO_MEM_SBM_MB_MOVABLE:
+ virtio_mem_sbm_set_mb_state(vm, mb_id,
+ VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL);
+ break;
+ }
+
return 0;
}
@@ -1940,11 +1944,50 @@ unplugged:
return 0;
}
+/*
+ * Unplug the desired number of plugged subblocks of a memory block that is
+ * already added to Linux. Will skip subblock of online memory blocks that are
+ * busy (by the OS). Will fail if any subblock that's not busy cannot get
+ * unplugged.
+ *
+ * Will modify the state of the memory block. Might temporarily drop the
+ * hotplug_mutex.
+ *
+ * Note: Can fail after some subblocks were successfully unplugged. Can
+ * return 0 even if subblocks were busy and could not get unplugged.
+ */
+static int virtio_mem_sbm_unplug_any_sb(struct virtio_mem *vm,
+ unsigned long mb_id,
+ uint64_t *nb_sb)
+{
+ const int old_state = virtio_mem_sbm_get_mb_state(vm, mb_id);
+
+ switch (old_state) {
+ case VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL:
+ case VIRTIO_MEM_SBM_MB_KERNEL:
+ case VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL:
+ case VIRTIO_MEM_SBM_MB_MOVABLE:
+ return virtio_mem_sbm_unplug_any_sb_online(vm, mb_id, nb_sb);
+ case VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL:
+ case VIRTIO_MEM_SBM_MB_OFFLINE:
+ return virtio_mem_sbm_unplug_any_sb_offline(vm, mb_id, nb_sb);
+ }
+ return -EINVAL;
+}
+
static int virtio_mem_sbm_unplug_request(struct virtio_mem *vm, uint64_t diff)
{
+ const int mb_states[] = {
+ VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL,
+ VIRTIO_MEM_SBM_MB_OFFLINE,
+ VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL,
+ VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL,
+ VIRTIO_MEM_SBM_MB_MOVABLE,
+ VIRTIO_MEM_SBM_MB_KERNEL,
+ };
uint64_t nb_sb = diff / vm->sbm.sb_size;
unsigned long mb_id;
- int rc;
+ int rc, i;
if (!nb_sb)
return 0;
@@ -1956,47 +1999,26 @@ static int virtio_mem_sbm_unplug_request(struct virtio_mem *vm, uint64_t diff)
*/
mutex_lock(&vm->hotplug_mutex);
- /* Try to unplug subblocks of partially plugged offline blocks. */
- virtio_mem_sbm_for_each_mb_rev(vm, mb_id,
- VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL) {
- rc = virtio_mem_sbm_unplug_any_sb_offline(vm, mb_id, &nb_sb);
- if (rc || !nb_sb)
- goto out_unlock;
- cond_resched();
- }
-
- /* Try to unplug subblocks of plugged offline blocks. */
- virtio_mem_sbm_for_each_mb_rev(vm, mb_id, VIRTIO_MEM_SBM_MB_OFFLINE) {
- rc = virtio_mem_sbm_unplug_any_sb_offline(vm, mb_id, &nb_sb);
- if (rc || !nb_sb)
- goto out_unlock;
- cond_resched();
- }
-
- if (!unplug_online) {
- mutex_unlock(&vm->hotplug_mutex);
- return 0;
- }
-
- /* Try to unplug subblocks of partially plugged online blocks. */
- virtio_mem_sbm_for_each_mb_rev(vm, mb_id,
- VIRTIO_MEM_SBM_MB_ONLINE_PARTIAL) {
- rc = virtio_mem_sbm_unplug_any_sb_online(vm, mb_id, &nb_sb);
- if (rc || !nb_sb)
- goto out_unlock;
- mutex_unlock(&vm->hotplug_mutex);
- cond_resched();
- mutex_lock(&vm->hotplug_mutex);
- }
-
- /* Try to unplug subblocks of plugged online blocks. */
- virtio_mem_sbm_for_each_mb_rev(vm, mb_id, VIRTIO_MEM_SBM_MB_ONLINE) {
- rc = virtio_mem_sbm_unplug_any_sb_online(vm, mb_id, &nb_sb);
- if (rc || !nb_sb)
- goto out_unlock;
- mutex_unlock(&vm->hotplug_mutex);
- cond_resched();
- mutex_lock(&vm->hotplug_mutex);
+ /*
+ * We try unplug from partially plugged blocks first, to try removing
+ * whole memory blocks along with metadata. We prioritize ZONE_MOVABLE
+ * as it's more reliable to unplug memory and remove whole memory
+ * blocks, and we don't want to trigger a zone imbalances by
+ * accidentially removing too much kernel memory.
+ */
+ for (i = 0; i < ARRAY_SIZE(mb_states); i++) {
+ virtio_mem_sbm_for_each_mb_rev(vm, mb_id, mb_states[i]) {
+ rc = virtio_mem_sbm_unplug_any_sb(vm, mb_id, &nb_sb);
+ if (rc || !nb_sb)
+ goto out_unlock;
+ mutex_unlock(&vm->hotplug_mutex);
+ cond_resched();
+ mutex_lock(&vm->hotplug_mutex);
+ }
+ if (!unplug_online && i == 1) {
+ mutex_unlock(&vm->hotplug_mutex);
+ return 0;
+ }
}
mutex_unlock(&vm->hotplug_mutex);
@@ -2083,47 +2105,41 @@ rollback_safe_unplug:
}
/*
- * Try to remove a big block from Linux and unplug it. Will fail with
- * -EBUSY if some memory is online.
- *
- * Will modify the state of the memory block.
+ * Test if a big block is completely offline.
*/
-static int virtio_mem_bbm_remove_and_unplug_bb(struct virtio_mem *vm,
- unsigned long bb_id)
+static bool virtio_mem_bbm_bb_is_offline(struct virtio_mem *vm,
+ unsigned long bb_id)
{
- int rc;
-
- if (WARN_ON_ONCE(virtio_mem_bbm_get_bb_state(vm, bb_id) !=
- VIRTIO_MEM_BBM_BB_ADDED))
- return -EINVAL;
+ const unsigned long start_pfn = PFN_DOWN(virtio_mem_bb_id_to_phys(vm, bb_id));
+ const unsigned long nr_pages = PFN_DOWN(vm->bbm.bb_size);
+ unsigned long pfn;
- rc = virtio_mem_bbm_remove_bb(vm, bb_id);
- if (rc)
- return -EBUSY;
+ for (pfn = start_pfn; pfn < start_pfn + nr_pages;
+ pfn += PAGES_PER_SECTION) {
+ if (pfn_to_online_page(pfn))
+ return false;
+ }
- rc = virtio_mem_bbm_unplug_bb(vm, bb_id);
- if (rc)
- virtio_mem_bbm_set_bb_state(vm, bb_id,
- VIRTIO_MEM_BBM_BB_PLUGGED);
- else
- virtio_mem_bbm_set_bb_state(vm, bb_id,
- VIRTIO_MEM_BBM_BB_UNUSED);
- return rc;
+ return true;
}
/*
- * Test if a big block is completely offline.
+ * Test if a big block is completely onlined to ZONE_MOVABLE (or offline).
*/
-static bool virtio_mem_bbm_bb_is_offline(struct virtio_mem *vm,
+static bool virtio_mem_bbm_bb_is_movable(struct virtio_mem *vm,
unsigned long bb_id)
{
const unsigned long start_pfn = PFN_DOWN(virtio_mem_bb_id_to_phys(vm, bb_id));
const unsigned long nr_pages = PFN_DOWN(vm->bbm.bb_size);
+ struct page *page;
unsigned long pfn;
for (pfn = start_pfn; pfn < start_pfn + nr_pages;
pfn += PAGES_PER_SECTION) {
- if (pfn_to_online_page(pfn))
+ page = pfn_to_online_page(pfn);
+ if (!page)
+ continue;
+ if (page_zonenum(page) != ZONE_MOVABLE)
return false;
}
@@ -2134,42 +2150,37 @@ static int virtio_mem_bbm_unplug_request(struct virtio_mem *vm, uint64_t diff)
{
uint64_t nb_bb = diff / vm->bbm.bb_size;
uint64_t bb_id;
- int rc;
+ int rc, i;
if (!nb_bb)
return 0;
- /* Try to unplug completely offline big blocks first. */
- virtio_mem_bbm_for_each_bb_rev(vm, bb_id, VIRTIO_MEM_BBM_BB_ADDED) {
- cond_resched();
- /*
- * As we're holding no locks, this check is racy as memory
- * can get onlined in the meantime - but we'll fail gracefully.
- */
- if (!virtio_mem_bbm_bb_is_offline(vm, bb_id))
- continue;
- rc = virtio_mem_bbm_remove_and_unplug_bb(vm, bb_id);
- if (rc == -EBUSY)
- continue;
- if (!rc)
- nb_bb--;
- if (rc || !nb_bb)
- return rc;
- }
-
- if (!unplug_online)
- return 0;
+ /*
+ * Try to unplug big blocks. Similar to SBM, start with offline
+ * big blocks.
+ */
+ for (i = 0; i < 3; i++) {
+ virtio_mem_bbm_for_each_bb_rev(vm, bb_id, VIRTIO_MEM_BBM_BB_ADDED) {
+ cond_resched();
- /* Try to unplug any big blocks. */
- virtio_mem_bbm_for_each_bb_rev(vm, bb_id, VIRTIO_MEM_BBM_BB_ADDED) {
- cond_resched();
- rc = virtio_mem_bbm_offline_remove_and_unplug_bb(vm, bb_id);
- if (rc == -EBUSY)
- continue;
- if (!rc)
- nb_bb--;
- if (rc || !nb_bb)
- return rc;
+ /*
+ * As we're holding no locks, these checks are racy,
+ * but we don't care.
+ */
+ if (i == 0 && !virtio_mem_bbm_bb_is_offline(vm, bb_id))
+ continue;
+ if (i == 1 && !virtio_mem_bbm_bb_is_movable(vm, bb_id))
+ continue;
+ rc = virtio_mem_bbm_offline_remove_and_unplug_bb(vm, bb_id);
+ if (rc == -EBUSY)
+ continue;
+ if (!rc)
+ nb_bb--;
+ if (rc || !nb_bb)
+ return rc;
+ }
+ if (i == 0 && !unplug_online)
+ return 0;
}
return nb_bb ? -EBUSY : 0;
@@ -2420,6 +2431,10 @@ static int virtio_mem_init(struct virtio_mem *vm)
dev_warn(&vm->vdev->dev,
"Some device memory is not addressable/pluggable. This can make some memory unusable.\n");
+ /* Prepare the offline threshold - make sure we can add two blocks. */
+ vm->offline_threshold = max_t(uint64_t, 2 * memory_block_size_bytes(),
+ VIRTIO_MEM_DEFAULT_OFFLINE_THRESHOLD);
+
/*
* We want subblocks to span at least MAX_ORDER_NR_PAGES and
* pageblock_nr_pages pages. This:
@@ -2466,14 +2481,11 @@ static int virtio_mem_init(struct virtio_mem *vm)
vm->bbm.bb_size - 1;
vm->bbm.first_bb_id = virtio_mem_phys_to_bb_id(vm, addr);
vm->bbm.next_bb_id = vm->bbm.first_bb_id;
- }
- /* Prepare the offline threshold - make sure we can add two blocks. */
- vm->offline_threshold = max_t(uint64_t, 2 * memory_block_size_bytes(),
- VIRTIO_MEM_DEFAULT_OFFLINE_THRESHOLD);
- /* In BBM, we also want at least two big blocks. */
- vm->offline_threshold = max_t(uint64_t, 2 * vm->bbm.bb_size,
- vm->offline_threshold);
+ /* Make sure we can add two big blocks. */
+ vm->offline_threshold = max_t(uint64_t, 2 * vm->bbm.bb_size,
+ vm->offline_threshold);
+ }
dev_info(&vm->vdev->dev, "start address: 0x%llx", vm->addr);
dev_info(&vm->vdev->dev, "region size: 0x%llx", vm->region_size);
diff --git a/drivers/virtio/virtio_pci_modern_dev.c b/drivers/virtio/virtio_pci_modern_dev.c
index 54f297028586..e11ed748e661 100644
--- a/drivers/virtio/virtio_pci_modern_dev.c
+++ b/drivers/virtio/virtio_pci_modern_dev.c
@@ -384,6 +384,27 @@ u64 vp_modern_get_features(struct virtio_pci_modern_device *mdev)
EXPORT_SYMBOL_GPL(vp_modern_get_features);
/*
+ * vp_modern_get_driver_features - get driver features from device
+ * @mdev: the modern virtio-pci device
+ *
+ * Returns the driver features read from the device
+ */
+u64 vp_modern_get_driver_features(struct virtio_pci_modern_device *mdev)
+{
+ struct virtio_pci_common_cfg __iomem *cfg = mdev->common;
+
+ u64 features;
+
+ vp_iowrite32(0, &cfg->guest_feature_select);
+ features = vp_ioread32(&cfg->guest_feature);
+ vp_iowrite32(1, &cfg->guest_feature_select);
+ features |= ((u64)vp_ioread32(&cfg->guest_feature) << 32);
+
+ return features;
+}
+EXPORT_SYMBOL_GPL(vp_modern_get_driver_features);
+
+/*
* vp_modern_set_features - set features to device
* @mdev: the modern virtio-pci device
* @features: the features set to device
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 71e16b53e9c1..89bfe46a8a7f 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -74,14 +74,14 @@ struct vring_desc_state_packed {
void *data; /* Data for callback. */
struct vring_packed_desc *indir_desc; /* Indirect descriptor, if any. */
u16 num; /* Descriptor list length. */
- u16 next; /* The next desc state in a list. */
u16 last; /* The last desc state in a list. */
};
-struct vring_desc_extra_packed {
+struct vring_desc_extra {
dma_addr_t addr; /* Buffer DMA addr. */
u32 len; /* Buffer length. */
u16 flags; /* Descriptor flags. */
+ u16 next; /* The next desc state in a list. */
};
struct vring_virtqueue {
@@ -113,6 +113,9 @@ struct vring_virtqueue {
/* Last used index we've seen. */
u16 last_used_idx;
+ /* Hint for event idx: already triggered no need to disable. */
+ bool event_triggered;
+
union {
/* Available for split ring */
struct {
@@ -130,6 +133,7 @@ struct vring_virtqueue {
/* Per-descriptor state. */
struct vring_desc_state_split *desc_state;
+ struct vring_desc_extra *desc_extra;
/* DMA address and size information */
dma_addr_t queue_dma_addr;
@@ -166,7 +170,7 @@ struct vring_virtqueue {
/* Per-descriptor state. */
struct vring_desc_state_packed *desc_state;
- struct vring_desc_extra_packed *desc_extra;
+ struct vring_desc_extra *desc_extra;
/* DMA address and size information */
dma_addr_t ring_dma_addr;
@@ -364,8 +368,8 @@ static int vring_mapping_error(const struct vring_virtqueue *vq,
* Split ring specific functions - *_split().
*/
-static void vring_unmap_one_split(const struct vring_virtqueue *vq,
- struct vring_desc *desc)
+static void vring_unmap_one_split_indirect(const struct vring_virtqueue *vq,
+ struct vring_desc *desc)
{
u16 flags;
@@ -389,6 +393,35 @@ static void vring_unmap_one_split(const struct vring_virtqueue *vq,
}
}
+static unsigned int vring_unmap_one_split(const struct vring_virtqueue *vq,
+ unsigned int i)
+{
+ struct vring_desc_extra *extra = vq->split.desc_extra;
+ u16 flags;
+
+ if (!vq->use_dma_api)
+ goto out;
+
+ flags = extra[i].flags;
+
+ if (flags & VRING_DESC_F_INDIRECT) {
+ dma_unmap_single(vring_dma_dev(vq),
+ extra[i].addr,
+ extra[i].len,
+ (flags & VRING_DESC_F_WRITE) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ } else {
+ dma_unmap_page(vring_dma_dev(vq),
+ extra[i].addr,
+ extra[i].len,
+ (flags & VRING_DESC_F_WRITE) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ }
+
+out:
+ return extra[i].next;
+}
+
static struct vring_desc *alloc_indirect_split(struct virtqueue *_vq,
unsigned int total_sg,
gfp_t gfp)
@@ -412,6 +445,35 @@ static struct vring_desc *alloc_indirect_split(struct virtqueue *_vq,
return desc;
}
+static inline unsigned int virtqueue_add_desc_split(struct virtqueue *vq,
+ struct vring_desc *desc,
+ unsigned int i,
+ dma_addr_t addr,
+ unsigned int len,
+ u16 flags,
+ bool indirect)
+{
+ struct vring_virtqueue *vring = to_vvq(vq);
+ struct vring_desc_extra *extra = vring->split.desc_extra;
+ u16 next;
+
+ desc[i].flags = cpu_to_virtio16(vq->vdev, flags);
+ desc[i].addr = cpu_to_virtio64(vq->vdev, addr);
+ desc[i].len = cpu_to_virtio32(vq->vdev, len);
+
+ if (!indirect) {
+ next = extra[i].next;
+ desc[i].next = cpu_to_virtio16(vq->vdev, next);
+
+ extra[i].addr = addr;
+ extra[i].len = len;
+ extra[i].flags = flags;
+ } else
+ next = virtio16_to_cpu(vq->vdev, desc[i].next);
+
+ return next;
+}
+
static inline int virtqueue_add_split(struct virtqueue *_vq,
struct scatterlist *sgs[],
unsigned int total_sg,
@@ -484,11 +546,13 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
if (vring_mapping_error(vq, addr))
goto unmap_release;
- desc[i].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_NEXT);
- desc[i].addr = cpu_to_virtio64(_vq->vdev, addr);
- desc[i].len = cpu_to_virtio32(_vq->vdev, sg->length);
prev = i;
- i = virtio16_to_cpu(_vq->vdev, desc[i].next);
+ /* Note that we trust indirect descriptor
+ * table since it use stream DMA mapping.
+ */
+ i = virtqueue_add_desc_split(_vq, desc, i, addr, sg->length,
+ VRING_DESC_F_NEXT,
+ indirect);
}
}
for (; n < (out_sgs + in_sgs); n++) {
@@ -497,15 +561,22 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
if (vring_mapping_error(vq, addr))
goto unmap_release;
- desc[i].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_NEXT | VRING_DESC_F_WRITE);
- desc[i].addr = cpu_to_virtio64(_vq->vdev, addr);
- desc[i].len = cpu_to_virtio32(_vq->vdev, sg->length);
prev = i;
- i = virtio16_to_cpu(_vq->vdev, desc[i].next);
+ /* Note that we trust indirect descriptor
+ * table since it use stream DMA mapping.
+ */
+ i = virtqueue_add_desc_split(_vq, desc, i, addr,
+ sg->length,
+ VRING_DESC_F_NEXT |
+ VRING_DESC_F_WRITE,
+ indirect);
}
}
/* Last one doesn't continue. */
desc[prev].flags &= cpu_to_virtio16(_vq->vdev, ~VRING_DESC_F_NEXT);
+ if (!indirect && vq->use_dma_api)
+ vq->split.desc_extra[prev & (vq->split.vring.num - 1)].flags =
+ ~VRING_DESC_F_NEXT;
if (indirect) {
/* Now that the indirect table is filled in, map it. */
@@ -515,13 +586,11 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
if (vring_mapping_error(vq, addr))
goto unmap_release;
- vq->split.vring.desc[head].flags = cpu_to_virtio16(_vq->vdev,
- VRING_DESC_F_INDIRECT);
- vq->split.vring.desc[head].addr = cpu_to_virtio64(_vq->vdev,
- addr);
-
- vq->split.vring.desc[head].len = cpu_to_virtio32(_vq->vdev,
- total_sg * sizeof(struct vring_desc));
+ virtqueue_add_desc_split(_vq, vq->split.vring.desc,
+ head, addr,
+ total_sg * sizeof(struct vring_desc),
+ VRING_DESC_F_INDIRECT,
+ false);
}
/* We're using some buffers from the free list. */
@@ -529,8 +598,7 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
/* Update free pointer */
if (indirect)
- vq->free_head = virtio16_to_cpu(_vq->vdev,
- vq->split.vring.desc[head].next);
+ vq->free_head = vq->split.desc_extra[head].next;
else
vq->free_head = i;
@@ -575,8 +643,11 @@ unmap_release:
for (n = 0; n < total_sg; n++) {
if (i == err_idx)
break;
- vring_unmap_one_split(vq, &desc[i]);
- i = virtio16_to_cpu(_vq->vdev, desc[i].next);
+ if (indirect) {
+ vring_unmap_one_split_indirect(vq, &desc[i]);
+ i = virtio16_to_cpu(_vq->vdev, desc[i].next);
+ } else
+ i = vring_unmap_one_split(vq, i);
}
if (indirect)
@@ -630,14 +701,13 @@ static void detach_buf_split(struct vring_virtqueue *vq, unsigned int head,
i = head;
while (vq->split.vring.desc[i].flags & nextflag) {
- vring_unmap_one_split(vq, &vq->split.vring.desc[i]);
- i = virtio16_to_cpu(vq->vq.vdev, vq->split.vring.desc[i].next);
+ vring_unmap_one_split(vq, i);
+ i = vq->split.desc_extra[i].next;
vq->vq.num_free++;
}
- vring_unmap_one_split(vq, &vq->split.vring.desc[i]);
- vq->split.vring.desc[i].next = cpu_to_virtio16(vq->vq.vdev,
- vq->free_head);
+ vring_unmap_one_split(vq, i);
+ vq->split.desc_extra[i].next = vq->free_head;
vq->free_head = head;
/* Plus final descriptor */
@@ -652,15 +722,14 @@ static void detach_buf_split(struct vring_virtqueue *vq, unsigned int head,
if (!indir_desc)
return;
- len = virtio32_to_cpu(vq->vq.vdev,
- vq->split.vring.desc[head].len);
+ len = vq->split.desc_extra[head].len;
- BUG_ON(!(vq->split.vring.desc[head].flags &
- cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_INDIRECT)));
+ BUG_ON(!(vq->split.desc_extra[head].flags &
+ VRING_DESC_F_INDIRECT));
BUG_ON(len == 0 || len % sizeof(struct vring_desc));
for (j = 0; j < len / sizeof(struct vring_desc); j++)
- vring_unmap_one_split(vq, &indir_desc[j]);
+ vring_unmap_one_split_indirect(vq, &indir_desc[j]);
kfree(indir_desc);
vq->split.desc_state[head].indir_desc = NULL;
@@ -739,7 +808,10 @@ static void virtqueue_disable_cb_split(struct virtqueue *_vq)
if (!(vq->split.avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) {
vq->split.avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT;
- if (!vq->event)
+ if (vq->event)
+ /* TODO: this is a hack. Figure out a cleaner value to write. */
+ vring_used_event(&vq->split.vring) = 0x0;
+ else
vq->split.vring.avail->flags =
cpu_to_virtio16(_vq->vdev,
vq->split.avail_flags_shadow);
@@ -912,7 +984,7 @@ static struct virtqueue *vring_create_virtqueue_split(
*/
static void vring_unmap_state_packed(const struct vring_virtqueue *vq,
- struct vring_desc_extra_packed *state)
+ struct vring_desc_extra *state)
{
u16 flags;
@@ -1061,7 +1133,7 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
1 << VRING_PACKED_DESC_F_USED;
}
vq->packed.next_avail_idx = n;
- vq->free_head = vq->packed.desc_state[id].next;
+ vq->free_head = vq->packed.desc_extra[id].next;
/* Store token and indirect buffer state. */
vq->packed.desc_state[id].num = 1;
@@ -1169,7 +1241,7 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
le16_to_cpu(flags);
}
prev = curr;
- curr = vq->packed.desc_state[curr].next;
+ curr = vq->packed.desc_extra[curr].next;
if ((unlikely(++i >= vq->packed.vring.num))) {
i = 0;
@@ -1213,13 +1285,16 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
unmap_release:
err_idx = i;
i = head;
+ curr = vq->free_head;
vq->packed.avail_used_flags = avail_used_flags;
for (n = 0; n < total_sg; n++) {
if (i == err_idx)
break;
- vring_unmap_desc_packed(vq, &desc[i]);
+ vring_unmap_state_packed(vq,
+ &vq->packed.desc_extra[curr]);
+ curr = vq->packed.desc_extra[curr].next;
i++;
if (i >= vq->packed.vring.num)
i = 0;
@@ -1290,7 +1365,7 @@ static void detach_buf_packed(struct vring_virtqueue *vq,
/* Clear data ptr. */
state->data = NULL;
- vq->packed.desc_state[state->last].next = vq->free_head;
+ vq->packed.desc_extra[state->last].next = vq->free_head;
vq->free_head = id;
vq->vq.num_free += state->num;
@@ -1299,7 +1374,7 @@ static void detach_buf_packed(struct vring_virtqueue *vq,
for (i = 0; i < state->num; i++) {
vring_unmap_state_packed(vq,
&vq->packed.desc_extra[curr]);
- curr = vq->packed.desc_state[curr].next;
+ curr = vq->packed.desc_extra[curr].next;
}
}
@@ -1550,6 +1625,25 @@ static void *virtqueue_detach_unused_buf_packed(struct virtqueue *_vq)
return NULL;
}
+static struct vring_desc_extra *vring_alloc_desc_extra(struct vring_virtqueue *vq,
+ unsigned int num)
+{
+ struct vring_desc_extra *desc_extra;
+ unsigned int i;
+
+ desc_extra = kmalloc_array(num, sizeof(struct vring_desc_extra),
+ GFP_KERNEL);
+ if (!desc_extra)
+ return NULL;
+
+ memset(desc_extra, 0, num * sizeof(struct vring_desc_extra));
+
+ for (i = 0; i < num - 1; i++)
+ desc_extra[i].next = i + 1;
+
+ return desc_extra;
+}
+
static struct virtqueue *vring_create_virtqueue_packed(
unsigned int index,
unsigned int num,
@@ -1567,7 +1661,6 @@ static struct virtqueue *vring_create_virtqueue_packed(
struct vring_packed_desc_event *driver, *device;
dma_addr_t ring_dma_addr, driver_event_dma_addr, device_event_dma_addr;
size_t ring_size_in_bytes, event_size_in_bytes;
- unsigned int i;
ring_size_in_bytes = num * sizeof(struct vring_packed_desc);
@@ -1605,6 +1698,7 @@ static struct virtqueue *vring_create_virtqueue_packed(
vq->weak_barriers = weak_barriers;
vq->broken = false;
vq->last_used_idx = 0;
+ vq->event_triggered = false;
vq->num_added = 0;
vq->packed_ring = true;
vq->use_dma_api = vring_use_dma_api(vdev);
@@ -1649,18 +1743,11 @@ static struct virtqueue *vring_create_virtqueue_packed(
/* Put everything in free lists. */
vq->free_head = 0;
- for (i = 0; i < num-1; i++)
- vq->packed.desc_state[i].next = i + 1;
- vq->packed.desc_extra = kmalloc_array(num,
- sizeof(struct vring_desc_extra_packed),
- GFP_KERNEL);
+ vq->packed.desc_extra = vring_alloc_desc_extra(vq, num);
if (!vq->packed.desc_extra)
goto err_desc_extra;
- memset(vq->packed.desc_extra, 0,
- num * sizeof(struct vring_desc_extra_packed));
-
/* No callback? Tell other side not to bother us. */
if (!callback) {
vq->packed.event_flags_shadow = VRING_PACKED_EVENT_FLAG_DISABLE;
@@ -1875,7 +1962,7 @@ bool virtqueue_kick(struct virtqueue *vq)
EXPORT_SYMBOL_GPL(virtqueue_kick);
/**
- * virtqueue_get_buf - get the next used buffer
+ * virtqueue_get_buf_ctx - get the next used buffer
* @_vq: the struct virtqueue we're talking about.
* @len: the length written into the buffer
* @ctx: extra context for the token
@@ -1919,6 +2006,12 @@ void virtqueue_disable_cb(struct virtqueue *_vq)
{
struct vring_virtqueue *vq = to_vvq(_vq);
+ /* If device triggered an event already it won't trigger one again:
+ * no need to disable.
+ */
+ if (vq->event_triggered)
+ return;
+
if (vq->packed_ring)
virtqueue_disable_cb_packed(_vq);
else
@@ -1942,6 +2035,9 @@ unsigned virtqueue_enable_cb_prepare(struct virtqueue *_vq)
{
struct vring_virtqueue *vq = to_vvq(_vq);
+ if (vq->event_triggered)
+ vq->event_triggered = false;
+
return vq->packed_ring ? virtqueue_enable_cb_prepare_packed(_vq) :
virtqueue_enable_cb_prepare_split(_vq);
}
@@ -2005,6 +2101,9 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
{
struct vring_virtqueue *vq = to_vvq(_vq);
+ if (vq->event_triggered)
+ vq->event_triggered = false;
+
return vq->packed_ring ? virtqueue_enable_cb_delayed_packed(_vq) :
virtqueue_enable_cb_delayed_split(_vq);
}
@@ -2044,6 +2143,10 @@ irqreturn_t vring_interrupt(int irq, void *_vq)
if (unlikely(vq->broken))
return IRQ_HANDLED;
+ /* Just a hint for performance: so it's ok that this can be racy! */
+ if (vq->event)
+ vq->event_triggered = true;
+
pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback);
if (vq->vq.callback)
vq->vq.callback(&vq->vq);
@@ -2062,7 +2165,6 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
void (*callback)(struct virtqueue *),
const char *name)
{
- unsigned int i;
struct vring_virtqueue *vq;
if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
@@ -2083,6 +2185,7 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
vq->weak_barriers = weak_barriers;
vq->broken = false;
vq->last_used_idx = 0;
+ vq->event_triggered = false;
vq->num_added = 0;
vq->use_dma_api = vring_use_dma_api(vdev);
#ifdef DEBUG
@@ -2114,20 +2217,26 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
vq->split.desc_state = kmalloc_array(vring.num,
sizeof(struct vring_desc_state_split), GFP_KERNEL);
- if (!vq->split.desc_state) {
- kfree(vq);
- return NULL;
- }
+ if (!vq->split.desc_state)
+ goto err_state;
+
+ vq->split.desc_extra = vring_alloc_desc_extra(vq, vring.num);
+ if (!vq->split.desc_extra)
+ goto err_extra;
/* Put everything in free lists. */
vq->free_head = 0;
- for (i = 0; i < vring.num-1; i++)
- vq->split.vring.desc[i].next = cpu_to_virtio16(vdev, i + 1);
memset(vq->split.desc_state, 0, vring.num *
sizeof(struct vring_desc_state_split));
list_add_tail(&vq->vq.list, &vdev->vqs);
return &vq->vq;
+
+err_extra:
+ kfree(vq->split.desc_state);
+err_state:
+ kfree(vq);
+ return NULL;
}
EXPORT_SYMBOL_GPL(__vring_new_virtqueue);
@@ -2208,8 +2317,10 @@ void vring_del_virtqueue(struct virtqueue *_vq)
vq->split.queue_dma_addr);
}
}
- if (!vq->packed_ring)
+ if (!vq->packed_ring) {
kfree(vq->split.desc_state);
+ kfree(vq->split.desc_extra);
+ }
list_del(&_vq->list);
kfree(vq);
}
diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
index e28acf482e0c..e1a141135992 100644
--- a/drivers/virtio/virtio_vdpa.c
+++ b/drivers/virtio/virtio_vdpa.c
@@ -142,6 +142,8 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
struct vdpa_callback cb;
struct virtqueue *vq;
u64 desc_addr, driver_addr, device_addr;
+ /* Assume split virtqueue, switch to packed if necessary */
+ struct vdpa_vq_state state = {0};
unsigned long flags;
u32 align, num;
int err;
@@ -191,6 +193,19 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
goto err_vq;
}
+ /* reset virtqueue state index */
+ if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED)) {
+ struct vdpa_vq_state_packed *s = &state.packed;
+
+ s->last_avail_counter = 1;
+ s->last_avail_idx = 0;
+ s->last_used_counter = 1;
+ s->last_used_idx = 0;
+ }
+ err = ops->set_vq_state(vdpa, index, &state);
+ if (err)
+ goto err_vq;
+
ops->set_vq_ready(vdpa, index, 1);
vq->priv = info;
diff --git a/drivers/visorbus/visorchipset.c b/drivers/visorbus/visorchipset.c
index cb1eb7e05f87..5668cad86e37 100644
--- a/drivers/visorbus/visorchipset.c
+++ b/drivers/visorbus/visorchipset.c
@@ -1561,7 +1561,7 @@ schedule_out:
static int visorchipset_init(struct acpi_device *acpi_device)
{
- int err = -ENODEV;
+ int err = -ENOMEM;
struct visorchannel *controlvm_channel;
chipset_dev = kzalloc(sizeof(*chipset_dev), GFP_KERNEL);
@@ -1584,8 +1584,10 @@ static int visorchipset_init(struct acpi_device *acpi_device)
"controlvm",
sizeof(struct visor_controlvm_channel),
VISOR_CONTROLVM_CHANNEL_VERSIONID,
- VISOR_CHANNEL_SIGNATURE))
+ VISOR_CHANNEL_SIGNATURE)) {
+ err = -ENODEV;
goto error_delete_groups;
+ }
/* if booting in a crash kernel */
if (is_kdump_kernel())
INIT_DELAYED_WORK(&chipset_dev->periodic_controlvm_work,
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
index b471779c3e2c..6c962e88501c 100644
--- a/drivers/w1/masters/ds2482.c
+++ b/drivers/w1/masters/ds2482.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* ds2482.c - provides i2c to w1-master bridge(s)
* Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
*
@@ -19,7 +19,7 @@
#include <linux/w1.h>
-/**
+/*
* Allow the active pullup to be disabled, default is enabled.
*
* Note from the DS2482 datasheet:
@@ -39,7 +39,7 @@ static int extra_config;
module_param(extra_config, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(extra_config, "Extra Configuration settings 1=APU,2=PPM,3=SPU,8=1WS");
-/**
+/*
* The DS2482 registers - there are 3 registers that are addressed by a read
* pointer. The read pointer is set by the last command executed.
*
@@ -62,7 +62,7 @@ MODULE_PARM_DESC(extra_config, "Extra Configuration settings 1=APU,2=PPM,3=SPU,8
#define DS2482_PTR_CODE_CHANNEL 0xD2 /* DS2482-800 only */
#define DS2482_PTR_CODE_CONFIG 0xC3
-/**
+/*
* Configure Register bit definitions
* The top 4 bits always read 0.
* To write, the top nibble must be the 1's compl. of the low nibble.
@@ -73,7 +73,7 @@ MODULE_PARM_DESC(extra_config, "Extra Configuration settings 1=APU,2=PPM,3=SPU,8
#define DS2482_REG_CFG_APU 0x01 /* active pull-up */
-/**
+/*
* Write and verify codes for the CHANNEL_SELECT command (DS2482-800 only).
* To set the channel, write the value at the index of the channel.
* Read and compare against the corresponding value to verify the change.
@@ -84,7 +84,7 @@ static const u8 ds2482_chan_rd[8] =
{ 0xB8, 0xB1, 0xAA, 0xA3, 0x9C, 0x95, 0x8E, 0x87 };
-/**
+/*
* Status Register bit definitions (read only)
*/
#define DS2482_REG_STS_DIR 0x80
@@ -124,9 +124,9 @@ struct ds2482_data {
/**
- * Helper to calculate values for configuration register
- * @param conf the raw config value
- * @return the value w/ complements that can be written to register
+ * ds2482_calculate_config - Helper to calculate values for configuration register
+ * @conf: the raw config value
+ * Return: the value w/ complements that can be written to register
*/
static inline u8 ds2482_calculate_config(u8 conf)
{
@@ -140,10 +140,10 @@ static inline u8 ds2482_calculate_config(u8 conf)
/**
- * Sets the read pointer.
- * @param pdev The ds2482 client pointer
- * @param read_ptr see DS2482_PTR_CODE_xxx above
- * @return -1 on failure, 0 on success
+ * ds2482_select_register - Sets the read pointer.
+ * @pdev: The ds2482 client pointer
+ * @read_ptr: see DS2482_PTR_CODE_xxx above
+ * Return: -1 on failure, 0 on success
*/
static inline int ds2482_select_register(struct ds2482_data *pdev, u8 read_ptr)
{
@@ -159,12 +159,12 @@ static inline int ds2482_select_register(struct ds2482_data *pdev, u8 read_ptr)
}
/**
- * Sends a command without a parameter
- * @param pdev The ds2482 client pointer
- * @param cmd DS2482_CMD_RESET,
+ * ds2482_send_cmd - Sends a command without a parameter
+ * @pdev: The ds2482 client pointer
+ * @cmd: DS2482_CMD_RESET,
* DS2482_CMD_1WIRE_RESET,
* DS2482_CMD_1WIRE_READ_BYTE
- * @return -1 on failure, 0 on success
+ * Return: -1 on failure, 0 on success
*/
static inline int ds2482_send_cmd(struct ds2482_data *pdev, u8 cmd)
{
@@ -176,14 +176,14 @@ static inline int ds2482_send_cmd(struct ds2482_data *pdev, u8 cmd)
}
/**
- * Sends a command with a parameter
- * @param pdev The ds2482 client pointer
- * @param cmd DS2482_CMD_WRITE_CONFIG,
+ * ds2482_send_cmd_data - Sends a command with a parameter
+ * @pdev: The ds2482 client pointer
+ * @cmd: DS2482_CMD_WRITE_CONFIG,
* DS2482_CMD_1WIRE_SINGLE_BIT,
* DS2482_CMD_1WIRE_WRITE_BYTE,
* DS2482_CMD_1WIRE_TRIPLET
- * @param byte The data to send
- * @return -1 on failure, 0 on success
+ * @byte: The data to send
+ * Return: -1 on failure, 0 on success
*/
static inline int ds2482_send_cmd_data(struct ds2482_data *pdev,
u8 cmd, u8 byte)
@@ -205,10 +205,10 @@ static inline int ds2482_send_cmd_data(struct ds2482_data *pdev,
#define DS2482_WAIT_IDLE_TIMEOUT 100
/**
- * Waits until the 1-wire interface is idle (not busy)
+ * ds2482_wait_1wire_idle - Waits until the 1-wire interface is idle (not busy)
*
- * @param pdev Pointer to the device structure
- * @return the last value read from status or -1 (failure)
+ * @pdev: Pointer to the device structure
+ * Return: the last value read from status or -1 (failure)
*/
static int ds2482_wait_1wire_idle(struct ds2482_data *pdev)
{
@@ -230,12 +230,12 @@ static int ds2482_wait_1wire_idle(struct ds2482_data *pdev)
}
/**
- * Selects a w1 channel.
+ * ds2482_set_channel - Selects a w1 channel.
* The 1-wire interface must be idle before calling this function.
*
- * @param pdev The ds2482 client pointer
- * @param channel 0-7
- * @return -1 (failure) or 0 (success)
+ * @pdev: The ds2482 client pointer
+ * @channel: 0-7
+ * Return: -1 (failure) or 0 (success)
*/
static int ds2482_set_channel(struct ds2482_data *pdev, u8 channel)
{
@@ -254,11 +254,11 @@ static int ds2482_set_channel(struct ds2482_data *pdev, u8 channel)
/**
- * Performs the touch-bit function, which writes a 0 or 1 and reads the level.
+ * ds2482_w1_touch_bit - Performs the touch-bit function, which writes a 0 or 1 and reads the level.
*
- * @param data The ds2482 channel pointer
- * @param bit The level to write: 0 or non-zero
- * @return The level read: 0 or 1
+ * @data: The ds2482 channel pointer
+ * @bit: The level to write: 0 or non-zero
+ * Return: The level read: 0 or 1
*/
static u8 ds2482_w1_touch_bit(void *data, u8 bit)
{
@@ -284,13 +284,13 @@ static u8 ds2482_w1_touch_bit(void *data, u8 bit)
}
/**
- * Performs the triplet function, which reads two bits and writes a bit.
+ * ds2482_w1_triplet - Performs the triplet function, which reads two bits and writes a bit.
* The bit written is determined by the two reads:
* 00 => dbit, 01 => 0, 10 => 1
*
- * @param data The ds2482 channel pointer
- * @param dbit The direction to choose if both branches are valid
- * @return b0=read1 b1=read2 b3=bit written
+ * @data: The ds2482 channel pointer
+ * @dbit: The direction to choose if both branches are valid
+ * Return: b0=read1 b1=read2 b3=bit written
*/
static u8 ds2482_w1_triplet(void *data, u8 dbit)
{
@@ -317,10 +317,10 @@ static u8 ds2482_w1_triplet(void *data, u8 dbit)
}
/**
- * Performs the write byte function.
+ * ds2482_w1_write_byte - Performs the write byte function.
*
- * @param data The ds2482 channel pointer
- * @param byte The value to write
+ * @data: The ds2482 channel pointer
+ * @byte: The value to write
*/
static void ds2482_w1_write_byte(void *data, u8 byte)
{
@@ -341,10 +341,10 @@ static void ds2482_w1_write_byte(void *data, u8 byte)
}
/**
- * Performs the read byte function.
+ * ds2482_w1_read_byte - Performs the read byte function.
*
- * @param data The ds2482 channel pointer
- * @return The value read
+ * @data: The ds2482 channel pointer
+ * Return: The value read
*/
static u8 ds2482_w1_read_byte(void *data)
{
@@ -378,10 +378,10 @@ static u8 ds2482_w1_read_byte(void *data)
/**
- * Sends a reset on the 1-wire interface
+ * ds2482_w1_reset_bus - Sends a reset on the 1-wire interface
*
- * @param data The ds2482 channel pointer
- * @return 0=Device present, 1=No device present or error
+ * @data: The ds2482 channel pointer
+ * Return: 0=Device present, 1=No device present or error
*/
static u8 ds2482_w1_reset_bus(void *data)
{
@@ -541,7 +541,7 @@ static int ds2482_remove(struct i2c_client *client)
return 0;
}
-/**
+/*
* Driver data (common to all clients)
*/
static const struct i2c_device_id ds2482_id[] = {
diff --git a/drivers/w1/slaves/w1_ds2438.c b/drivers/w1/slaves/w1_ds2438.c
index 5cfb0ae23e91..ca64f99c8f3d 100644
--- a/drivers/w1/slaves/w1_ds2438.c
+++ b/drivers/w1/slaves/w1_ds2438.c
@@ -49,6 +49,15 @@
#define DS2438_CURRENT_MSB 0x06
#define DS2438_THRESHOLD 0x07
+/* Page #1 definitions */
+#define DS2438_ETM_0 0x00
+#define DS2438_ETM_1 0x01
+#define DS2438_ETM_2 0x02
+#define DS2438_ETM_3 0x03
+#define DS2438_ICA 0x04
+#define DS2438_OFFSET_LSB 0x05
+#define DS2438_OFFSET_MSB 0x06
+
static int w1_ds2438_get_page(struct w1_slave *sl, int pageno, u8 *buf)
{
unsigned int retries = W1_DS2438_RETRIES;
@@ -62,13 +71,13 @@ static int w1_ds2438_get_page(struct w1_slave *sl, int pageno, u8 *buf)
if (w1_reset_select_slave(sl))
continue;
w1_buf[0] = W1_DS2438_RECALL_MEMORY;
- w1_buf[1] = 0x00;
+ w1_buf[1] = (u8)pageno;
w1_write_block(sl->master, w1_buf, 2);
if (w1_reset_select_slave(sl))
continue;
w1_buf[0] = W1_DS2438_READ_SCRATCH;
- w1_buf[1] = 0x00;
+ w1_buf[1] = (u8)pageno;
w1_write_block(sl->master, w1_buf, 2);
count = w1_read_block(sl->master, buf, DS2438_PAGE_SIZE + 1);
@@ -154,11 +163,11 @@ static int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value)
if ((status & mask) == value)
return 0; /* already set as requested */
- else {
- /* changing bit */
- status ^= mask;
- perform_write = 1;
- }
+
+ /* changing bit */
+ status ^= mask;
+ perform_write = 1;
+
break;
}
@@ -184,6 +193,34 @@ static int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value)
return -1;
}
+static int w1_ds2438_change_offset_register(struct w1_slave *sl, u8 *value)
+{
+ unsigned int retries = W1_DS2438_RETRIES;
+ u8 w1_buf[9];
+ u8 w1_page1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
+
+ if (w1_ds2438_get_page(sl, 1, w1_page1_buf) == 0) {
+ memcpy(&w1_buf[2], w1_page1_buf, DS2438_PAGE_SIZE - 1); /* last register reserved */
+ w1_buf[7] = value[0]; /* change only offset register */
+ w1_buf[8] = value[1];
+ while (retries--) {
+ if (w1_reset_select_slave(sl))
+ continue;
+ w1_buf[0] = W1_DS2438_WRITE_SCRATCH;
+ w1_buf[1] = 0x01; /* write to page 1 */
+ w1_write_block(sl->master, w1_buf, 9);
+
+ if (w1_reset_select_slave(sl))
+ continue;
+ w1_buf[0] = W1_DS2438_COPY_SCRATCH;
+ w1_buf[1] = 0x01;
+ w1_write_block(sl->master, w1_buf, 2);
+ return 0;
+ }
+ }
+ return -1;
+}
+
static int w1_ds2438_get_voltage(struct w1_slave *sl,
int adc_input, uint16_t *voltage)
{
@@ -287,9 +324,9 @@ static ssize_t iad_read(struct file *filp, struct kobject *kobj,
if (!buf)
return -EINVAL;
- if (w1_ds2438_get_current(sl, &voltage) == 0) {
+ if (w1_ds2438_get_current(sl, &voltage) == 0)
ret = snprintf(buf, count, "%i\n", voltage);
- } else
+ else
ret = -EIO;
return ret;
@@ -325,6 +362,55 @@ static ssize_t page0_read(struct file *filp, struct kobject *kobj,
return ret;
}
+static ssize_t page1_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);
+ int ret;
+ u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
+
+ if (off != 0)
+ return 0;
+ if (!buf)
+ return -EINVAL;
+
+ mutex_lock(&sl->master->bus_mutex);
+
+ /* Read no more than page1 size */
+ if (count > DS2438_PAGE_SIZE)
+ count = DS2438_PAGE_SIZE;
+
+ if (w1_ds2438_get_page(sl, 1, w1_buf) == 0) {
+ memcpy(buf, &w1_buf, count);
+ ret = count;
+ } else
+ ret = -EIO;
+
+ mutex_unlock(&sl->master->bus_mutex);
+
+ return ret;
+}
+
+static ssize_t offset_write(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);
+ int ret;
+
+ mutex_lock(&sl->master->bus_mutex);
+
+ if (w1_ds2438_change_offset_register(sl, buf) == 0)
+ ret = count;
+ else
+ ret = -EIO;
+
+ mutex_unlock(&sl->master->bus_mutex);
+
+ return ret;
+}
+
static ssize_t temperature_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t off, size_t count)
@@ -338,9 +424,9 @@ static ssize_t temperature_read(struct file *filp, struct kobject *kobj,
if (!buf)
return -EINVAL;
- if (w1_ds2438_get_temperature(sl, &temp) == 0) {
+ if (w1_ds2438_get_temperature(sl, &temp) == 0)
ret = snprintf(buf, count, "%i\n", temp);
- } else
+ else
ret = -EIO;
return ret;
@@ -359,9 +445,9 @@ static ssize_t vad_read(struct file *filp, struct kobject *kobj,
if (!buf)
return -EINVAL;
- if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VAD, &voltage) == 0) {
+ if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VAD, &voltage) == 0)
ret = snprintf(buf, count, "%u\n", voltage);
- } else
+ else
ret = -EIO;
return ret;
@@ -380,16 +466,18 @@ static ssize_t vdd_read(struct file *filp, struct kobject *kobj,
if (!buf)
return -EINVAL;
- if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VDD, &voltage) == 0) {
+ if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VDD, &voltage) == 0)
ret = snprintf(buf, count, "%u\n", voltage);
- } else
+ else
ret = -EIO;
return ret;
}
-static BIN_ATTR(iad, S_IRUGO | S_IWUSR | S_IWGRP, iad_read, iad_write, 0);
+static BIN_ATTR_RW(iad, 0);
static BIN_ATTR_RO(page0, DS2438_PAGE_SIZE);
+static BIN_ATTR_RO(page1, DS2438_PAGE_SIZE);
+static BIN_ATTR_WO(offset, 2);
static BIN_ATTR_RO(temperature, 0/* real length varies */);
static BIN_ATTR_RO(vad, 0/* real length varies */);
static BIN_ATTR_RO(vdd, 0/* real length varies */);
@@ -397,6 +485,8 @@ static BIN_ATTR_RO(vdd, 0/* real length varies */);
static struct bin_attribute *w1_ds2438_bin_attrs[] = {
&bin_attr_iad,
&bin_attr_page0,
+ &bin_attr_page1,
+ &bin_attr_offset,
&bin_attr_temperature,
&bin_attr_vad,
&bin_attr_vdd,
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index 9d08a1c9c445..ca70c5f03206 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -834,7 +834,7 @@ static int check_family_data(struct w1_slave *sl)
}
/**
- * support_bulk_read() - check if slave support bulk read
+ * bulk_read_support() - check if slave support bulk read
* @sl: device to check the ability
*
* Return: true if bulk read is supported, false if not or error
@@ -2056,7 +2056,6 @@ static ssize_t w1_seq_show(struct device *device,
{
struct w1_slave *sl = dev_to_w1_slave(device);
ssize_t c = PAGE_SIZE;
- int rv;
int i;
u8 ack;
u64 rn;
@@ -2084,7 +2083,7 @@ static ssize_t w1_seq_show(struct device *device,
goto error;
w1_write_8(sl->master, W1_42_COND_READ);
- rv = w1_read_block(sl->master, (u8 *)&rn, 8);
+ w1_read_block(sl->master, (u8 *)&rn, 8);
reg_num = (struct w1_reg_num *) &rn;
if (reg_num->family == W1_42_FINISHED_BYTE)
break;
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 355100dad60a..546dfc1e2349 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -22,9 +22,9 @@ menuconfig WATCHDOG
The watchdog is usually used together with the watchdog daemon
which is available from
- <ftp://ibiblio.org/pub/Linux/system/daemons/watchdog/>. This daemon can
- also monitor NFS connections and can reboot the machine when the process
- table is full.
+ <https://ibiblio.org/pub/Linux/system/daemons/watchdog/>. This daemon
+ can also monitor NFS connections and can reboot the machine when the
+ process table is full.
If unsure, say N.
@@ -73,6 +73,14 @@ config WATCHDOG_SYSFS
Say Y here if you want to enable watchdog device status read through
sysfs attributes.
+config WATCHDOG_HRTIMER_PRETIMEOUT
+ bool "Enable watchdog hrtimer-based pretimeouts"
+ help
+ Enable this if you want to use a hrtimer timer based pretimeout for
+ watchdogs that do not natively support pretimeout support. Be aware
+ that because this pretimeout functionality uses hrtimers, it may not
+ be able to fire before the actual watchdog fires in some situations.
+
comment "Watchdog Pretimeout Governors"
config WATCHDOG_PRETIMEOUT_GOV
@@ -302,7 +310,7 @@ config XILINX_WATCHDOG
depends on HAS_IOMEM
select WATCHDOG_CORE
help
- Watchdog driver for the xps_timebase_wdt ip core.
+ Watchdog driver for the xps_timebase_wdt IP core.
To compile this driver as a module, choose M here: the
module will be called of_xilinx_wdt.
@@ -404,8 +412,8 @@ config ASM9260_WATCHDOG
select WATCHDOG_CORE
select RESET_CONTROLLER
help
- Watchdog timer embedded into Alphascale asm9260 chips. This will reboot your
- system when the timeout is reached.
+ Watchdog timer embedded into Alphascale asm9260 chips. This will
+ reboot your system when the timeout is reached.
config AT91RM9200_WATCHDOG
tristate "AT91RM9200 watchdog"
@@ -548,8 +556,9 @@ config OMAP_WATCHDOG
depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS || COMPILE_TEST
select WATCHDOG_CORE
help
- Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y'
- here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer.
+ Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog.
+ Say 'Y' here to enable the
+ OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer.
config PNX4008_WATCHDOG
tristate "LPC32XX Watchdog"
@@ -980,6 +989,18 @@ config VISCONTI_WATCHDOG
Say Y here to include support for the watchdog timer in Toshiba
Visconti SoCs.
+config MSC313E_WATCHDOG
+ tristate "MStar MSC313e watchdog"
+ depends on ARCH_MSTARV7 || COMPILE_TEST
+ select WATCHDOG_CORE
+ help
+ Say Y here to include support for the Watchdog timer embedded
+ into MStar MSC313e chips. This will reboot your system when the
+ timeout is reached.
+
+ To compile this driver as a module, choose M here: the
+ module will be called msc313e_wdt.
+
# X86 (i386 + ia64 + x86_64) Architecture
config ACQUIRE_WDT
@@ -1096,13 +1117,16 @@ config SBC_FITPC2_WATCHDOG
This is the driver for the built-in watchdog timer on the fit-PC2,
fit-PC2i, CM-iAM single-board computers made by Compulab.
- It`s possible to enable watchdog timer either from BIOS (F2) or from booted Linux.
- When "Watchdog Timer Value" enabled one can set 31-255 s operational range.
+ It's possible to enable the watchdog timer either from BIOS (F2) or
+ from booted Linux.
+ When the "Watchdog Timer Value" is enabled one can set 31-255 seconds
+ operational range.
- Entering BIOS setup temporary disables watchdog operation regardless to current state,
- so system will not be restarted while user in BIOS setup.
+ Entering BIOS setup temporarily disables watchdog operation regardless
+ of current state, so system will not be restarted while user is in
+ BIOS setup.
- Once watchdog was enabled the system will be restarted every
+ Once the watchdog is enabled the system will be restarted every
"Watchdog Timer Value" period, so to prevent it user can restart or
disable the watchdog.
@@ -1124,11 +1148,12 @@ config IB700_WDT
depends on X86
help
This is the driver for the hardware watchdog on the IB700 Single
- Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog
- 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.
+ Board Computer produced by TMC Technology (www.tmc-uk.com). This
+ watchdog 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 slightly different hardware.
+ This driver is like the WDT501 driver but for slightly different
+ hardware.
To compile this driver as a module, choose M here: the
module will be called ib700wdt.
@@ -1807,10 +1832,10 @@ config PIC32_DMT
select WATCHDOG_CORE
depends on MACH_PIC32 || (MIPS && COMPILE_TEST)
help
- Watchdog driver for PIC32 instruction fetch counting timer. This specific
- timer is typically be used in misson critical and safety critical
- applications, where any single failure of the software functionality
- and sequencing must be detected.
+ Watchdog driver for PIC32 instruction fetch counting timer. This
+ specific timer is typically be used in mission critical and safety
+ critical applications, where any single failure of the software
+ functionality and sequencing must be detected.
To compile this driver as a loadable module, choose M here.
The module will be called pic32-dmt.
@@ -1844,10 +1869,6 @@ config 8xxx_WDT
For BookE processors (MPC85xx) use the BOOKE_WDT driver instead.
-config MV64X60_WDT
- tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
- depends on MV64X60 || COMPILE_TEST
-
config PIKA_WDT
tristate "PIKA FPGA Watchdog"
depends on WARP || (PPC64 && COMPILE_TEST)
@@ -2013,8 +2034,8 @@ 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.rst>. The PC
- watchdog cards can be ordered from <http://www.berkprod.com/>.
+ 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
module will be called pcwd.
@@ -2115,7 +2136,7 @@ config KEEMBAY_WATCHDOG
This option enable support for an In-secure watchdog timer driver for
Intel Keem Bay SoC. This WDT has a 32 bit timer and decrements in every
count unit. An interrupt will be triggered, when the count crosses
- the thershold configured in the register.
+ the threshold configured in the register.
To compile this driver as a module, choose M here: the
module will be called keembay_wdt.
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index a7eade8b4d45..abaf2ebd814e 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_WATCHDOG_CORE) += watchdog.o
watchdog-objs += watchdog_core.o watchdog_dev.o
watchdog-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV) += watchdog_pretimeout.o
+watchdog-$(CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT) += watchdog_hrtimer_pretimeout.o
obj-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP) += pretimeout_noop.o
obj-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC) += pretimeout_panic.o
@@ -92,6 +93,7 @@ obj-$(CONFIG_SPRD_WATCHDOG) += sprd_wdt.o
obj-$(CONFIG_PM8916_WATCHDOG) += pm8916_wdt.o
obj-$(CONFIG_ARM_SMC_WATCHDOG) += arm_smc_wdt.o
obj-$(CONFIG_VISCONTI_WATCHDOG) += visconti_wdt.o
+obj-$(CONFIG_MSC313E_WATCHDOG) += msc313e_wdt.o
# X86 (i386 + ia64 + x86_64) Architecture
obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
@@ -175,7 +177,6 @@ obj-$(CONFIG_PIC32_DMT) += pic32-dmt.o
# POWERPC Architecture
obj-$(CONFIG_GEF_WDT) += gef_wdt.o
obj-$(CONFIG_8xxx_WDT) += mpc8xxx_wdt.o
-obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
obj-$(CONFIG_PIKA_WDT) += pika_wdt.o
obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
obj-$(CONFIG_MEN_A21_WDT) += mena21_wdt.o
diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c
index 7e00960651fa..436571b6fc79 100644
--- a/drivers/watchdog/aspeed_wdt.c
+++ b/drivers/watchdog/aspeed_wdt.c
@@ -147,7 +147,7 @@ static int aspeed_wdt_set_timeout(struct watchdog_device *wdd,
wdd->timeout = timeout;
- actual = min(timeout, wdd->max_hw_heartbeat_ms * 1000);
+ actual = min(timeout, wdd->max_hw_heartbeat_ms / 1000);
writel(actual * WDT_RATE_1MHZ, wdt->base + WDT_RELOAD_VALUE);
writel(WDT_RESTART_MAGIC, wdt->base + WDT_RESTART);
@@ -175,8 +175,8 @@ static ssize_t access_cs0_show(struct device *dev,
struct aspeed_wdt *wdt = dev_get_drvdata(dev);
u32 status = readl(wdt->base + WDT_TIMEOUT_STATUS);
- return sprintf(buf, "%u\n",
- !(status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY));
+ return sysfs_emit(buf, "%u\n",
+ !(status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY));
}
static ssize_t access_cs0_store(struct device *dev,
diff --git a/drivers/watchdog/bcm7038_wdt.c b/drivers/watchdog/bcm7038_wdt.c
index 979caa18d3c8..acaaa0005d5b 100644
--- a/drivers/watchdog/bcm7038_wdt.c
+++ b/drivers/watchdog/bcm7038_wdt.c
@@ -34,6 +34,25 @@ struct bcm7038_watchdog {
static bool nowayout = WATCHDOG_NOWAYOUT;
+static inline void bcm7038_wdt_write(u32 value, void __iomem *addr)
+{
+ /* MIPS chips strapped for BE will automagically configure the
+ * peripheral registers for CPU-native byte order.
+ */
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ __raw_writel(value, addr);
+ else
+ writel_relaxed(value, addr);
+}
+
+static inline u32 bcm7038_wdt_read(void __iomem *addr)
+{
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ return __raw_readl(addr);
+ else
+ return readl_relaxed(addr);
+}
+
static void bcm7038_wdt_set_timeout_reg(struct watchdog_device *wdog)
{
struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog);
@@ -41,15 +60,15 @@ static void bcm7038_wdt_set_timeout_reg(struct watchdog_device *wdog)
timeout = wdt->rate * wdog->timeout;
- writel(timeout, wdt->base + WDT_TIMEOUT_REG);
+ bcm7038_wdt_write(timeout, wdt->base + WDT_TIMEOUT_REG);
}
static int bcm7038_wdt_ping(struct watchdog_device *wdog)
{
struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog);
- writel(WDT_START_1, wdt->base + WDT_CMD_REG);
- writel(WDT_START_2, wdt->base + WDT_CMD_REG);
+ bcm7038_wdt_write(WDT_START_1, wdt->base + WDT_CMD_REG);
+ bcm7038_wdt_write(WDT_START_2, wdt->base + WDT_CMD_REG);
return 0;
}
@@ -66,8 +85,8 @@ static int bcm7038_wdt_stop(struct watchdog_device *wdog)
{
struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog);
- writel(WDT_STOP_1, wdt->base + WDT_CMD_REG);
- writel(WDT_STOP_2, wdt->base + WDT_CMD_REG);
+ bcm7038_wdt_write(WDT_STOP_1, wdt->base + WDT_CMD_REG);
+ bcm7038_wdt_write(WDT_STOP_2, wdt->base + WDT_CMD_REG);
return 0;
}
@@ -88,7 +107,7 @@ static unsigned int bcm7038_wdt_get_timeleft(struct watchdog_device *wdog)
struct bcm7038_watchdog *wdt = watchdog_get_drvdata(wdog);
u32 time_left;
- time_left = readl(wdt->base + WDT_CMD_REG);
+ time_left = bcm7038_wdt_read(wdt->base + WDT_CMD_REG);
return time_left / wdt->rate;
}
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index 7817fb976f9c..5e4dc1a0f2c6 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -148,7 +148,7 @@ static void __booke_wdt_enable(void *data)
}
/**
- * booke_wdt_disable - disable the watchdog on the given CPU
+ * __booke_wdt_disable - disable the watchdog on the given CPU
*
* This function is called on each CPU. It disables the watchdog on that CPU.
*
diff --git a/drivers/watchdog/diag288_wdt.c b/drivers/watchdog/diag288_wdt.c
index aafc8d98bf9f..4cb10877017c 100644
--- a/drivers/watchdog/diag288_wdt.c
+++ b/drivers/watchdog/diag288_wdt.c
@@ -118,8 +118,6 @@ static int wdt_start(struct watchdog_device *dev)
if (test_and_set_bit(DIAG_WDOG_BUSY, &wdt_status))
return -EBUSY;
- ret = -ENODEV;
-
if (MACHINE_IS_VM) {
ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL);
if (!ebc_cmd) {
@@ -167,8 +165,6 @@ static int wdt_ping(struct watchdog_device *dev)
int ret;
unsigned int func;
- ret = -ENODEV;
-
if (MACHINE_IS_VM) {
ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL);
if (!ebc_cmd)
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index 32d0e1781e63..cd578843277e 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -13,22 +13,21 @@
*/
#include <linux/bitops.h>
-#include <linux/limits.h>
-#include <linux/kernel.h>
#include <linux/clk.h>
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/err.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/limits.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/interrupt.h>
#include <linux/of.h>
-#include <linux/pm.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/reset.h>
#include <linux/watchdog.h>
-#include <linux/debugfs.h>
#define WDOG_CONTROL_REG_OFFSET 0x00
#define WDOG_CONTROL_REG_WDT_EN_MASK 0x01
diff --git a/drivers/watchdog/eurotechwdt.c b/drivers/watchdog/eurotechwdt.c
index 2418ebb707bd..ce682942662c 100644
--- a/drivers/watchdog/eurotechwdt.c
+++ b/drivers/watchdog/eurotechwdt.c
@@ -392,7 +392,7 @@ static struct notifier_block eurwdt_notifier = {
};
/**
- * cleanup_module:
+ * eurwdt_exit:
*
* Unload the watchdog. You cannot do this with any file handles open.
* If your watchdog is set to continue ticking on close and you unload
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 22ddba3802ef..a5006a58e0db 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -45,6 +45,7 @@ static unsigned long __iomem *hpwdt_timer_con;
static const struct pci_device_id hpwdt_devices[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, /* iLO2 */
{ PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, /* iLO3 */
+ { PCI_DEVICE(PCI_VENDOR_ID_HP_3PAR, 0x0389) }, /* PCtrl */
{0}, /* terminate list */
};
MODULE_DEVICE_TABLE(pci, hpwdt_devices);
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index bf31d7b67a69..b3f604669e2c 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -71,6 +71,8 @@
#define TCOBASE(p) ((p)->tco_res->start)
/* SMI Control and Enable Register */
#define SMI_EN(p) ((p)->smi_res->start)
+#define TCO_EN (1 << 13)
+#define GBL_SMI_EN (1 << 0)
#define TCO_RLD(p) (TCOBASE(p) + 0x00) /* TCO Timer Reload/Curr. Value */
#define TCOv1_TMR(p) (TCOBASE(p) + 0x01) /* TCOv1 Timer Initial Value*/
@@ -355,8 +357,12 @@ static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
tmrval = seconds_to_ticks(p, t);
- /* For TCO v1 the timer counts down twice before rebooting */
- if (p->iTCO_version == 1)
+ /*
+ * If TCO SMIs are off, the timer counts down twice before rebooting.
+ * Otherwise, the BIOS generally reboots when the SMI triggers.
+ */
+ if (p->smi_res &&
+ (SMI_EN(p) & (TCO_EN | GBL_SMI_EN)) != (TCO_EN | GBL_SMI_EN))
tmrval /= 2;
/* from the specs: */
@@ -479,13 +485,13 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
if (!devm_request_region(dev, p->smi_res->start,
resource_size(p->smi_res),
pdev->name)) {
- pr_err("I/O address 0x%04llx already in use, device disabled\n",
+ dev_err(dev, "I/O address 0x%04llx already in use, device disabled\n",
(u64)SMI_EN(p));
return -EBUSY;
}
} else if (iTCO_vendorsupport ||
turn_SMI_watchdog_clear_off >= p->iTCO_version) {
- pr_err("SMI I/O resource is missing\n");
+ dev_err(dev, "SMI I/O resource is missing\n");
return -ENODEV;
}
@@ -521,7 +527,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
* Disables TCO logic generating an SMI#
*/
val32 = inl(SMI_EN(p));
- val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
+ val32 &= ~TCO_EN; /* Turn off SMI clearing watchdog */
outl(val32, SMI_EN(p));
}
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index b84f80f7d342..cc86018c5eb5 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -65,6 +65,7 @@ struct imx2_wdt_device {
struct regmap *regmap;
struct watchdog_device wdog;
bool ext_reset;
+ bool clk_is_on;
};
static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -160,6 +161,9 @@ static int imx2_wdt_ping(struct watchdog_device *wdog)
{
struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
+ if (!wdev->clk_is_on)
+ return 0;
+
regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ1);
regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ2);
return 0;
@@ -301,6 +305,8 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
if (ret)
return ret;
+ wdev->clk_is_on = true;
+
regmap_read(wdev->regmap, IMX2_WDT_WRSR, &val);
wdog->bootstatus = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0;
@@ -361,6 +367,8 @@ static int __maybe_unused imx2_wdt_suspend(struct device *dev)
clk_disable_unprepare(wdev->clk);
+ wdev->clk_is_on = false;
+
return 0;
}
@@ -375,6 +383,8 @@ static int __maybe_unused imx2_wdt_resume(struct device *dev)
if (ret)
return ret;
+ wdev->clk_is_on = true;
+
if (watchdog_active(wdog) && !imx2_wdt_is_running(wdev)) {
/*
* If the watchdog is still active and resumes
diff --git a/drivers/watchdog/imx_sc_wdt.c b/drivers/watchdog/imx_sc_wdt.c
index e9ee22a7cb45..8ac021748d16 100644
--- a/drivers/watchdog/imx_sc_wdt.c
+++ b/drivers/watchdog/imx_sc_wdt.c
@@ -183,16 +183,12 @@ static int imx_sc_wdt_probe(struct platform_device *pdev)
watchdog_stop_on_reboot(wdog);
watchdog_stop_on_unregister(wdog);
- ret = devm_watchdog_register_device(dev, wdog);
- if (ret)
- 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;
+ goto register_device;
}
imx_sc_wdd->wdt_notifier.notifier_call = imx_sc_wdt_notify;
@@ -203,7 +199,7 @@ static int imx_sc_wdt_probe(struct platform_device *pdev)
false);
dev_warn(dev,
"Register irq notifier failed, pretimeout NOT supported\n");
- return 0;
+ goto register_device;
}
ret = devm_add_action_or_reset(dev, imx_sc_wdt_action,
@@ -213,7 +209,8 @@ static int imx_sc_wdt_probe(struct platform_device *pdev)
else
dev_warn(dev, "Add action failed, pretimeout NOT supported\n");
- return 0;
+register_device:
+ return devm_watchdog_register_device(dev, wdog);
}
static int __maybe_unused imx_sc_wdt_suspend(struct device *dev)
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
index 2b4831842162..bb1122909396 100644
--- a/drivers/watchdog/it87_wdt.c
+++ b/drivers/watchdog/it87_wdt.c
@@ -152,14 +152,6 @@ static inline int superio_inw(int reg)
return val;
}
-static inline void superio_outw(int val, int reg)
-{
- outb(reg++, REG);
- outb(val >> 8, VAL);
- outb(reg, REG);
- outb(val, VAL);
-}
-
/* Internal function, should be called after superio_select(GPIO) */
static void _wdt_update_timeout(unsigned int t)
{
diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c
index bdf9564efa29..395bde79e292 100644
--- a/drivers/watchdog/jz4740_wdt.c
+++ b/drivers/watchdog/jz4740_wdt.c
@@ -176,9 +176,9 @@ static int jz4740_wdt_probe(struct platform_device *pdev)
watchdog_set_drvdata(jz4740_wdt, drvdata);
drvdata->map = device_node_to_regmap(dev->parent->of_node);
- if (!drvdata->map) {
+ if (IS_ERR(drvdata->map)) {
dev_err(dev, "regmap not found\n");
- return -EINVAL;
+ return PTR_ERR(drvdata->map);
}
return devm_watchdog_register_device(dev, &drvdata->wdt);
diff --git a/drivers/watchdog/keembay_wdt.c b/drivers/watchdog/keembay_wdt.c
index 547d3fea33ff..2a39114dbc64 100644
--- a/drivers/watchdog/keembay_wdt.c
+++ b/drivers/watchdog/keembay_wdt.c
@@ -23,12 +23,19 @@
#define TIM_WDOG_EN 0x8
#define TIM_SAFE 0xc
-#define WDT_ISR_MASK GENMASK(9, 8)
-#define WDT_ISR_CLEAR 0x8200ff18
+#define WDT_TH_INT_MASK BIT(8)
+#define WDT_TO_INT_MASK BIT(9)
+#define WDT_INT_CLEAR_SMC 0x8200ff18
+
#define WDT_UNLOCK 0xf1d0dead
+#define WDT_DISABLE 0x0
+#define WDT_ENABLE 0x1
+
#define WDT_LOAD_MAX U32_MAX
#define WDT_LOAD_MIN 1
+
#define WDT_TIMEOUT 5
+#define WDT_PRETIMEOUT 4
static unsigned int timeout = WDT_TIMEOUT;
module_param(timeout, int, 0);
@@ -82,8 +89,7 @@ static int keembay_wdt_start(struct watchdog_device *wdog)
{
struct keembay_wdt *wdt = watchdog_get_drvdata(wdog);
- keembay_wdt_set_timeout_reg(wdog);
- keembay_wdt_writel(wdt, TIM_WDOG_EN, 1);
+ keembay_wdt_writel(wdt, TIM_WDOG_EN, WDT_ENABLE);
return 0;
}
@@ -92,7 +98,7 @@ static int keembay_wdt_stop(struct watchdog_device *wdog)
{
struct keembay_wdt *wdt = watchdog_get_drvdata(wdog);
- keembay_wdt_writel(wdt, TIM_WDOG_EN, 0);
+ keembay_wdt_writel(wdt, TIM_WDOG_EN, WDT_DISABLE);
return 0;
}
@@ -108,6 +114,7 @@ static int keembay_wdt_set_timeout(struct watchdog_device *wdog, u32 t)
{
wdog->timeout = t;
keembay_wdt_set_timeout_reg(wdog);
+ keembay_wdt_set_pretimeout_reg(wdog);
return 0;
}
@@ -139,9 +146,8 @@ static irqreturn_t keembay_wdt_to_isr(int irq, void *dev_id)
struct keembay_wdt *wdt = dev_id;
struct arm_smccc_res res;
- keembay_wdt_writel(wdt, TIM_WATCHDOG, 1);
- arm_smccc_smc(WDT_ISR_CLEAR, WDT_ISR_MASK, 0, 0, 0, 0, 0, 0, &res);
- dev_crit(wdt->wdd.parent, "Intel Keem Bay non-sec wdt timeout.\n");
+ arm_smccc_smc(WDT_INT_CLEAR_SMC, WDT_TO_INT_MASK, 0, 0, 0, 0, 0, 0, &res);
+ dev_crit(wdt->wdd.parent, "Intel Keem Bay non-secure wdt timeout.\n");
emergency_restart();
return IRQ_HANDLED;
@@ -152,8 +158,10 @@ static irqreturn_t keembay_wdt_th_isr(int irq, void *dev_id)
struct keembay_wdt *wdt = dev_id;
struct arm_smccc_res res;
- arm_smccc_smc(WDT_ISR_CLEAR, WDT_ISR_MASK, 0, 0, 0, 0, 0, 0, &res);
- dev_crit(wdt->wdd.parent, "Intel Keem Bay non-sec wdt pre-timeout.\n");
+ keembay_wdt_set_pretimeout(&wdt->wdd, 0x0);
+
+ arm_smccc_smc(WDT_INT_CLEAR_SMC, WDT_TH_INT_MASK, 0, 0, 0, 0, 0, 0, &res);
+ dev_crit(wdt->wdd.parent, "Intel Keem Bay non-secure wdt pre-timeout.\n");
watchdog_notify_pretimeout(&wdt->wdd);
return IRQ_HANDLED;
@@ -224,11 +232,13 @@ static int keembay_wdt_probe(struct platform_device *pdev)
wdt->wdd.min_timeout = WDT_LOAD_MIN;
wdt->wdd.max_timeout = WDT_LOAD_MAX / wdt->rate;
wdt->wdd.timeout = WDT_TIMEOUT;
+ wdt->wdd.pretimeout = WDT_PRETIMEOUT;
watchdog_set_drvdata(&wdt->wdd, wdt);
watchdog_set_nowayout(&wdt->wdd, nowayout);
watchdog_init_timeout(&wdt->wdd, timeout, dev);
keembay_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout);
+ keembay_wdt_set_pretimeout(&wdt->wdd, wdt->wdd.pretimeout);
ret = devm_watchdog_register_device(dev, &wdt->wdd);
if (ret)
@@ -271,8 +281,8 @@ static const struct of_device_id keembay_wdt_match[] = {
MODULE_DEVICE_TABLE(of, keembay_wdt_match);
static struct platform_driver keembay_wdt_driver = {
- .probe = keembay_wdt_probe,
- .driver = {
+ .probe = keembay_wdt_probe,
+ .driver = {
.name = "keembay_wdt",
.of_match_table = keembay_wdt_match,
.pm = &keembay_wdt_pm_ops,
diff --git a/drivers/watchdog/lpc18xx_wdt.c b/drivers/watchdog/lpc18xx_wdt.c
index 78cf11c94941..60b6d74f267d 100644
--- a/drivers/watchdog/lpc18xx_wdt.c
+++ b/drivers/watchdog/lpc18xx_wdt.c
@@ -292,7 +292,7 @@ static int lpc18xx_wdt_remove(struct platform_device *pdev)
struct lpc18xx_wdt_dev *lpc18xx_wdt = platform_get_drvdata(pdev);
dev_warn(&pdev->dev, "I quit now, hardware will probably reboot!\n");
- del_timer(&lpc18xx_wdt->timer);
+ del_timer_sync(&lpc18xx_wdt->timer);
return 0;
}
diff --git a/drivers/watchdog/machzwd.c b/drivers/watchdog/machzwd.c
index 743377c5b173..73f2221f6222 100644
--- a/drivers/watchdog/machzwd.c
+++ b/drivers/watchdog/machzwd.c
@@ -174,6 +174,7 @@ static inline void zf_set_timer(unsigned short new, unsigned char n)
fallthrough;
case WD2:
zf_writeb(COUNTER_2, new > 0xff ? 0xff : new);
+ fallthrough;
default:
return;
}
diff --git a/drivers/watchdog/mei_wdt.c b/drivers/watchdog/mei_wdt.c
index e023d7d90d66..c7a7235e6224 100644
--- a/drivers/watchdog/mei_wdt.c
+++ b/drivers/watchdog/mei_wdt.c
@@ -105,7 +105,7 @@ struct mei_wdt {
#endif /* CONFIG_DEBUG_FS */
};
-/*
+/**
* struct mei_mc_hdr - Management Control Command Header
*
* @command: Management Control (0x2)
@@ -121,7 +121,7 @@ struct mei_mc_hdr {
};
/**
- * struct mei_wdt_start_request watchdog start/ping
+ * struct mei_wdt_start_request - watchdog start/ping
*
* @hdr: Management Control Command Header
* @timeout: timeout value
@@ -134,7 +134,7 @@ struct mei_wdt_start_request {
} __packed;
/**
- * struct mei_wdt_start_response watchdog start/ping response
+ * struct mei_wdt_start_response - watchdog start/ping response
*
* @hdr: Management Control Command Header
* @status: operation status
@@ -474,7 +474,7 @@ out:
complete(&wdt->response);
}
-/*
+/**
* mei_wdt_notif - callback for event notification
*
* @cldev: bus device
diff --git a/drivers/watchdog/meson_wdt.c b/drivers/watchdog/meson_wdt.c
index 459f3ae02c91..539feaa1f904 100644
--- a/drivers/watchdog/meson_wdt.c
+++ b/drivers/watchdog/meson_wdt.c
@@ -162,7 +162,6 @@ static int meson_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct meson_wdt_dev *meson_wdt;
- const struct of_device_id *of_id;
int err;
meson_wdt = devm_kzalloc(dev, sizeof(*meson_wdt), GFP_KERNEL);
@@ -173,12 +172,7 @@ static int meson_wdt_probe(struct platform_device *pdev)
if (IS_ERR(meson_wdt->wdt_base))
return PTR_ERR(meson_wdt->wdt_base);
- of_id = of_match_device(meson_wdt_dt_ids, dev);
- if (!of_id) {
- dev_err(dev, "Unable to initialize WDT data\n");
- return -ENODEV;
- }
- meson_wdt->data = of_id->data;
+ meson_wdt->data = device_get_match_data(dev);
meson_wdt->wdt_dev.parent = dev;
meson_wdt->wdt_dev.info = &meson_wdt_info;
diff --git a/drivers/watchdog/msc313e_wdt.c b/drivers/watchdog/msc313e_wdt.c
new file mode 100644
index 000000000000..0d497aa0fb7d
--- /dev/null
+++ b/drivers/watchdog/msc313e_wdt.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MStar WDT driver
+ *
+ * Copyright (C) 2019 - 2021 Daniel Palmer
+ * Copyright (C) 2021 Romain Perier
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+
+#define REG_WDT_CLR 0x0
+#define REG_WDT_MAX_PRD_L 0x10
+#define REG_WDT_MAX_PRD_H 0x14
+
+#define MSC313E_WDT_MIN_TIMEOUT 1
+#define MSC313E_WDT_DEFAULT_TIMEOUT 30
+
+static unsigned int timeout;
+
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
+
+struct msc313e_wdt_priv {
+ void __iomem *base;
+ struct watchdog_device wdev;
+ struct clk *clk;
+};
+
+static int msc313e_wdt_start(struct watchdog_device *wdev)
+{
+ struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev);
+ u32 timeout;
+ int err;
+
+ err = clk_prepare_enable(priv->clk);
+ if (err)
+ return err;
+
+ timeout = wdev->timeout * clk_get_rate(priv->clk);
+ writew(timeout & 0xffff, priv->base + REG_WDT_MAX_PRD_L);
+ writew((timeout >> 16) & 0xffff, priv->base + REG_WDT_MAX_PRD_H);
+ writew(1, priv->base + REG_WDT_CLR);
+ return 0;
+}
+
+static int msc313e_wdt_ping(struct watchdog_device *wdev)
+{
+ struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev);
+
+ writew(1, priv->base + REG_WDT_CLR);
+ return 0;
+}
+
+static int msc313e_wdt_stop(struct watchdog_device *wdev)
+{
+ struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev);
+
+ writew(0, priv->base + REG_WDT_MAX_PRD_L);
+ writew(0, priv->base + REG_WDT_MAX_PRD_H);
+ writew(0, priv->base + REG_WDT_CLR);
+ clk_disable_unprepare(priv->clk);
+ return 0;
+}
+
+static int msc313e_wdt_settimeout(struct watchdog_device *wdev, unsigned int new_time)
+{
+ wdev->timeout = new_time;
+
+ return msc313e_wdt_start(wdev);
+}
+
+static const struct watchdog_info msc313e_wdt_ident = {
+ .identity = "MSC313e watchdog",
+ .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+};
+
+static const struct watchdog_ops msc313e_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = msc313e_wdt_start,
+ .stop = msc313e_wdt_stop,
+ .ping = msc313e_wdt_ping,
+ .set_timeout = msc313e_wdt_settimeout,
+};
+
+static const struct of_device_id msc313e_wdt_of_match[] = {
+ { .compatible = "mstar,msc313e-wdt", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, msc313e_wdt_of_match);
+
+static int msc313e_wdt_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct msc313e_wdt_priv *priv;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(dev, "No input clock\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ priv->wdev.info = &msc313e_wdt_ident,
+ priv->wdev.ops = &msc313e_wdt_ops,
+ priv->wdev.parent = dev;
+ priv->wdev.min_timeout = MSC313E_WDT_MIN_TIMEOUT;
+ priv->wdev.max_timeout = U32_MAX / clk_get_rate(priv->clk);
+ priv->wdev.timeout = MSC313E_WDT_DEFAULT_TIMEOUT;
+
+ watchdog_set_drvdata(&priv->wdev, priv);
+
+ watchdog_init_timeout(&priv->wdev, timeout, dev);
+ watchdog_stop_on_reboot(&priv->wdev);
+ watchdog_stop_on_unregister(&priv->wdev);
+
+ return devm_watchdog_register_device(dev, &priv->wdev);
+}
+
+static int __maybe_unused msc313e_wdt_suspend(struct device *dev)
+{
+ struct msc313e_wdt_priv *priv = dev_get_drvdata(dev);
+
+ if (watchdog_active(&priv->wdev))
+ msc313e_wdt_stop(&priv->wdev);
+
+ return 0;
+}
+
+static int __maybe_unused msc313e_wdt_resume(struct device *dev)
+{
+ struct msc313e_wdt_priv *priv = dev_get_drvdata(dev);
+
+ if (watchdog_active(&priv->wdev))
+ msc313e_wdt_start(&priv->wdev);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(msc313e_wdt_pm_ops, msc313e_wdt_suspend, msc313e_wdt_resume);
+
+static struct platform_driver msc313e_wdt_driver = {
+ .driver = {
+ .name = "msc313e-wdt",
+ .of_match_table = msc313e_wdt_of_match,
+ .pm = &msc313e_wdt_pm_ops,
+ },
+ .probe = msc313e_wdt_probe,
+};
+module_platform_driver(msc313e_wdt_driver);
+
+MODULE_AUTHOR("Daniel Palmer <daniel@thingy.jp>");
+MODULE_DESCRIPTION("Watchdog driver for MStar MSC313e");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
index 97ca993bd009..16b6aff324a7 100644
--- a/drivers/watchdog/mtk_wdt.c
+++ b/drivers/watchdog/mtk_wdt.c
@@ -25,9 +25,10 @@
#include <linux/reset-controller.h>
#include <linux/types.h>
#include <linux/watchdog.h>
+#include <linux/interrupt.h>
#define WDT_MAX_TIMEOUT 31
-#define WDT_MIN_TIMEOUT 1
+#define WDT_MIN_TIMEOUT 2
#define WDT_LENGTH_TIMEOUT(n) ((n) << 5)
#define WDT_LENGTH 0x04
@@ -187,12 +188,19 @@ static int mtk_wdt_set_timeout(struct watchdog_device *wdt_dev,
u32 reg;
wdt_dev->timeout = timeout;
+ /*
+ * In dual mode, irq will be triggered at timeout / 2
+ * the real timeout occurs at timeout
+ */
+ if (wdt_dev->pretimeout)
+ wdt_dev->pretimeout = timeout / 2;
/*
* One bit is the value of 512 ticks
* The clock has 32 KHz
*/
- reg = WDT_LENGTH_TIMEOUT(timeout << 6) | WDT_LENGTH_KEY;
+ reg = WDT_LENGTH_TIMEOUT((timeout - wdt_dev->pretimeout) << 6)
+ | WDT_LENGTH_KEY;
iowrite32(reg, wdt_base + WDT_LENGTH);
mtk_wdt_ping(wdt_dev);
@@ -239,13 +247,48 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev)
return ret;
reg = ioread32(wdt_base + WDT_MODE);
- reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
+ if (wdt_dev->pretimeout)
+ reg |= (WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
+ else
+ reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
reg |= (WDT_MODE_EN | WDT_MODE_KEY);
iowrite32(reg, wdt_base + WDT_MODE);
return 0;
}
+static int mtk_wdt_set_pretimeout(struct watchdog_device *wdd,
+ unsigned int timeout)
+{
+ struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdd);
+ void __iomem *wdt_base = mtk_wdt->wdt_base;
+ u32 reg = ioread32(wdt_base + WDT_MODE);
+
+ if (timeout && !wdd->pretimeout) {
+ wdd->pretimeout = wdd->timeout / 2;
+ reg |= (WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
+ } else if (!timeout && wdd->pretimeout) {
+ wdd->pretimeout = 0;
+ reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
+ } else {
+ return 0;
+ }
+
+ reg |= WDT_MODE_KEY;
+ iowrite32(reg, wdt_base + WDT_MODE);
+
+ return mtk_wdt_set_timeout(wdd, wdd->timeout);
+}
+
+static irqreturn_t mtk_wdt_isr(int irq, void *arg)
+{
+ struct watchdog_device *wdd = arg;
+
+ watchdog_notify_pretimeout(wdd);
+
+ return IRQ_HANDLED;
+}
+
static const struct watchdog_info mtk_wdt_info = {
.identity = DRV_NAME,
.options = WDIOF_SETTIMEOUT |
@@ -253,12 +296,21 @@ static const struct watchdog_info mtk_wdt_info = {
WDIOF_MAGICCLOSE,
};
+static const struct watchdog_info mtk_wdt_pt_info = {
+ .identity = DRV_NAME,
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_PRETIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+};
+
static const struct watchdog_ops mtk_wdt_ops = {
.owner = THIS_MODULE,
.start = mtk_wdt_start,
.stop = mtk_wdt_stop,
.ping = mtk_wdt_ping,
.set_timeout = mtk_wdt_set_timeout,
+ .set_pretimeout = mtk_wdt_set_pretimeout,
.restart = mtk_wdt_restart,
};
@@ -267,7 +319,7 @@ static int mtk_wdt_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct mtk_wdt_dev *mtk_wdt;
const struct mtk_wdt_data *wdt_data;
- int err;
+ int err, irq;
mtk_wdt = devm_kzalloc(dev, sizeof(*mtk_wdt), GFP_KERNEL);
if (!mtk_wdt)
@@ -279,7 +331,22 @@ static int mtk_wdt_probe(struct platform_device *pdev)
if (IS_ERR(mtk_wdt->wdt_base))
return PTR_ERR(mtk_wdt->wdt_base);
- mtk_wdt->wdt_dev.info = &mtk_wdt_info;
+ irq = platform_get_irq(pdev, 0);
+ if (irq > 0) {
+ err = devm_request_irq(&pdev->dev, irq, mtk_wdt_isr, 0, "wdt_bark",
+ &mtk_wdt->wdt_dev);
+ if (err)
+ return err;
+
+ mtk_wdt->wdt_dev.info = &mtk_wdt_pt_info;
+ mtk_wdt->wdt_dev.pretimeout = WDT_MAX_TIMEOUT / 2;
+ } else {
+ if (irq == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ mtk_wdt->wdt_dev.info = &mtk_wdt_info;
+ }
+
mtk_wdt->wdt_dev.ops = &mtk_wdt_ops;
mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT;
mtk_wdt->wdt_dev.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT * 1000;
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c
index 8aa1cb4a295f..ea1bbf5ee528 100644
--- a/drivers/watchdog/mtx-1_wdt.c
+++ b/drivers/watchdog/mtx-1_wdt.c
@@ -41,8 +41,6 @@
#include <linux/uaccess.h>
#include <linux/gpio/consumer.h>
-#include <asm/mach-au1x00/au1000.h>
-
#define MTX1_WDT_INTERVAL (5 * HZ)
static int ticks = 100 * HZ;
diff --git a/drivers/watchdog/mv64x60_wdt.c b/drivers/watchdog/mv64x60_wdt.c
deleted file mode 100644
index 894aa63488d3..000000000000
--- a/drivers/watchdog/mv64x60_wdt.c
+++ /dev/null
@@ -1,324 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * mv64x60_wdt.c - MV64X60 (Marvell Discovery) watchdog userspace interface
- *
- * Author: James Chapman <jchapman@katalix.com>
- *
- * Platform-specific setup code should configure the dog to generate
- * interrupt or reset as required. This code only enables/disables
- * and services the watchdog.
- *
- * Derived from mpc8xx_wdt.c, with the following copyright.
- *
- * 2002 (c) Florian Schirmer <jolt@tuxbox.org>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/miscdevice.h>
-#include <linux/module.h>
-#include <linux/watchdog.h>
-#include <linux/platform_device.h>
-#include <linux/mv643xx.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-
-#define MV64x60_WDT_WDC_OFFSET 0
-
-/*
- * The watchdog configuration register contains a pair of 2-bit fields,
- * 1. a reload field, bits 27-26, which triggers a reload of
- * the countdown register, and
- * 2. an enable field, bits 25-24, which toggles between
- * enabling and disabling the watchdog timer.
- * Bit 31 is a read-only field which indicates whether the
- * watchdog timer is currently enabled.
- *
- * The low 24 bits contain the timer reload value.
- */
-#define MV64x60_WDC_ENABLE_SHIFT 24
-#define MV64x60_WDC_SERVICE_SHIFT 26
-#define MV64x60_WDC_ENABLED_SHIFT 31
-
-#define MV64x60_WDC_ENABLED_TRUE 1
-#define MV64x60_WDC_ENABLED_FALSE 0
-
-/* Flags bits */
-#define MV64x60_WDOG_FLAG_OPENED 0
-
-static unsigned long wdt_flags;
-static int wdt_status;
-static void __iomem *mv64x60_wdt_regs;
-static int mv64x60_wdt_timeout;
-static int mv64x60_wdt_count;
-static unsigned int bus_clk;
-static char expect_close;
-static DEFINE_SPINLOCK(mv64x60_wdt_spinlock);
-
-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) ")");
-
-static int mv64x60_wdt_toggle_wdc(int enabled_predicate, int field_shift)
-{
- u32 data;
- u32 enabled;
- int ret = 0;
-
- spin_lock(&mv64x60_wdt_spinlock);
- data = readl(mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
- enabled = (data >> MV64x60_WDC_ENABLED_SHIFT) & 1;
-
- /* only toggle the requested field if enabled state matches predicate */
- if ((enabled ^ enabled_predicate) == 0) {
- /* We write a 1, then a 2 -- to the appropriate field */
- data = (1 << field_shift) | mv64x60_wdt_count;
- writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
-
- data = (2 << field_shift) | mv64x60_wdt_count;
- writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
- ret = 1;
- }
- spin_unlock(&mv64x60_wdt_spinlock);
-
- return ret;
-}
-
-static void mv64x60_wdt_service(void)
-{
- mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
- MV64x60_WDC_SERVICE_SHIFT);
-}
-
-static void mv64x60_wdt_handler_enable(void)
-{
- if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_FALSE,
- MV64x60_WDC_ENABLE_SHIFT)) {
- mv64x60_wdt_service();
- pr_notice("watchdog activated\n");
- }
-}
-
-static void mv64x60_wdt_handler_disable(void)
-{
- if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
- MV64x60_WDC_ENABLE_SHIFT))
- pr_notice("watchdog deactivated\n");
-}
-
-static void mv64x60_wdt_set_timeout(unsigned int timeout)
-{
- /* maximum bus cycle count is 0xFFFFFFFF */
- if (timeout > 0xFFFFFFFF / bus_clk)
- timeout = 0xFFFFFFFF / bus_clk;
-
- mv64x60_wdt_count = timeout * bus_clk >> 8;
- mv64x60_wdt_timeout = timeout;
-}
-
-static int mv64x60_wdt_open(struct inode *inode, struct file *file)
-{
- if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags))
- return -EBUSY;
-
- if (nowayout)
- __module_get(THIS_MODULE);
-
- mv64x60_wdt_handler_enable();
-
- return stream_open(inode, file);
-}
-
-static int mv64x60_wdt_release(struct inode *inode, struct file *file)
-{
- if (expect_close == 42)
- mv64x60_wdt_handler_disable();
- else {
- pr_crit("unexpected close, not stopping timer!\n");
- mv64x60_wdt_service();
- }
- expect_close = 0;
-
- clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags);
-
- return 0;
-}
-
-static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
- size_t len, loff_t *ppos)
-{
- if (len) {
- if (!nowayout) {
- size_t i;
-
- expect_close = 0;
-
- for (i = 0; i != len; i++) {
- char c;
- if (get_user(c, data + i))
- return -EFAULT;
- if (c == 'V')
- expect_close = 42;
- }
- }
- mv64x60_wdt_service();
- }
-
- return len;
-}
-
-static long mv64x60_wdt_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int timeout;
- int options;
- void __user *argp = (void __user *)arg;
- static const struct watchdog_info info = {
- .options = WDIOF_SETTIMEOUT |
- WDIOF_MAGICCLOSE |
- WDIOF_KEEPALIVEPING,
- .firmware_version = 0,
- .identity = "MV64x60 watchdog",
- };
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- break;
-
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- if (put_user(wdt_status, (int __user *)argp))
- return -EFAULT;
- wdt_status &= ~WDIOF_KEEPALIVEPING;
- break;
-
- case WDIOC_GETTEMP:
- return -EOPNOTSUPP;
-
- case WDIOC_SETOPTIONS:
- if (get_user(options, (int __user *)argp))
- return -EFAULT;
-
- if (options & WDIOS_DISABLECARD)
- mv64x60_wdt_handler_disable();
-
- if (options & WDIOS_ENABLECARD)
- mv64x60_wdt_handler_enable();
- break;
-
- case WDIOC_KEEPALIVE:
- mv64x60_wdt_service();
- wdt_status |= WDIOF_KEEPALIVEPING;
- break;
-
- case WDIOC_SETTIMEOUT:
- if (get_user(timeout, (int __user *)argp))
- return -EFAULT;
- mv64x60_wdt_set_timeout(timeout);
- fallthrough;
-
- case WDIOC_GETTIMEOUT:
- if (put_user(mv64x60_wdt_timeout, (int __user *)argp))
- return -EFAULT;
- break;
-
- default:
- return -ENOTTY;
- }
-
- return 0;
-}
-
-static const struct file_operations mv64x60_wdt_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = mv64x60_wdt_write,
- .unlocked_ioctl = mv64x60_wdt_ioctl,
- .compat_ioctl = compat_ptr_ioctl,
- .open = mv64x60_wdt_open,
- .release = mv64x60_wdt_release,
-};
-
-static struct miscdevice mv64x60_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &mv64x60_wdt_fops,
-};
-
-static int mv64x60_wdt_probe(struct platform_device *dev)
-{
- struct mv64x60_wdt_pdata *pdata = dev_get_platdata(&dev->dev);
- struct resource *r;
- int timeout = 10;
-
- bus_clk = 133; /* in MHz */
- if (pdata) {
- timeout = pdata->timeout;
- bus_clk = pdata->bus_clk;
- }
-
- /* Since bus_clk is truncated MHz, actual frequency could be
- * up to 1MHz higher. Round up, since it's better to time out
- * too late than too soon.
- */
- bus_clk++;
- bus_clk *= 1000000; /* convert to Hz */
-
- r = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!r)
- return -ENODEV;
-
- mv64x60_wdt_regs = devm_ioremap(&dev->dev, r->start, resource_size(r));
- if (mv64x60_wdt_regs == NULL)
- return -ENOMEM;
-
- mv64x60_wdt_set_timeout(timeout);
-
- mv64x60_wdt_handler_disable(); /* in case timer was already running */
-
- return misc_register(&mv64x60_wdt_miscdev);
-}
-
-static int mv64x60_wdt_remove(struct platform_device *dev)
-{
- misc_deregister(&mv64x60_wdt_miscdev);
-
- mv64x60_wdt_handler_disable();
-
- return 0;
-}
-
-static struct platform_driver mv64x60_wdt_driver = {
- .probe = mv64x60_wdt_probe,
- .remove = mv64x60_wdt_remove,
- .driver = {
- .name = MV64x60_WDT_NAME,
- },
-};
-
-static int __init mv64x60_wdt_init(void)
-{
- pr_info("MV64x60 watchdog driver\n");
-
- return platform_driver_register(&mv64x60_wdt_driver);
-}
-
-static void __exit mv64x60_wdt_exit(void)
-{
- platform_driver_unregister(&mv64x60_wdt_driver);
-}
-
-module_init(mv64x60_wdt_init);
-module_exit(mv64x60_wdt_exit);
-
-MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
-MODULE_DESCRIPTION("MV64x60 watchdog driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" MV64x60_WDT_NAME);
diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c
index fde9e739b436..0fe71f7e66d5 100644
--- a/drivers/watchdog/octeon-wdt-main.c
+++ b/drivers/watchdog/octeon-wdt-main.c
@@ -54,6 +54,7 @@
#include <linux/delay.h>
#include <linux/cpu.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <asm/mipsregs.h>
#include <asm/uasm.h>
@@ -119,7 +120,7 @@ static int cpu2core(int cpu)
}
/**
- * Poke the watchdog when an interrupt is received
+ * octeon_wdt_poke_irq - Poke the watchdog when an interrupt is received
*
* @cpl:
* @dev_id:
@@ -153,7 +154,7 @@ static irqreturn_t octeon_wdt_poke_irq(int cpl, void *dev_id)
extern int prom_putchar(char c);
/**
- * Write a string to the uart
+ * octeon_wdt_write_string - Write a string to the uart
*
* @str: String to write
*/
@@ -165,7 +166,7 @@ static void octeon_wdt_write_string(const char *str)
}
/**
- * Write a hex number out of the uart
+ * octeon_wdt_write_hex() - Write a hex number out of the uart
*
* @value: Number to display
* @digits: Number of digits to print (1 to 16)
@@ -192,6 +193,8 @@ static const char reg_name[][3] = {
};
/**
+ * octeon_wdt_nmi_stage3:
+ *
* NMI stage 3 handler. NMIs are handled in the following manner:
* 1) The first NMI handler enables CVMSEG and transfers from
* the bootbus region into normal memory. It is careful to not
@@ -513,7 +516,7 @@ static struct watchdog_device octeon_wdt = {
static enum cpuhp_state octeon_wdt_online;
/**
- * Module/ driver initialization.
+ * octeon_wdt_init - Module/ driver initialization.
*
* Returns Zero on success
*/
@@ -585,7 +588,7 @@ err:
}
/**
- * Module / driver shutdown
+ * octeon_wdt_cleanup - Module / driver shutdown
*/
static void __exit octeon_wdt_cleanup(void)
{
diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c
index 7fe4f7c3f7ce..3318544366b8 100644
--- a/drivers/watchdog/of_xilinx_wdt.c
+++ b/drivers/watchdog/of_xilinx_wdt.c
@@ -6,6 +6,7 @@
* (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>)
*/
+#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/module.h>
@@ -24,12 +25,12 @@
#define XWT_TBR_OFFSET 0x8 /* Timebase Register Offset */
/* Control/Status Register Masks */
-#define XWT_CSR0_WRS_MASK 0x00000008 /* Reset status */
-#define XWT_CSR0_WDS_MASK 0x00000004 /* Timer state */
-#define XWT_CSR0_EWDT1_MASK 0x00000002 /* Enable bit 1 */
+#define XWT_CSR0_WRS_MASK BIT(3) /* Reset status */
+#define XWT_CSR0_WDS_MASK BIT(2) /* Timer state */
+#define XWT_CSR0_EWDT1_MASK BIT(1) /* Enable bit 1 */
/* Control/Status Register 0/1 bits */
-#define XWT_CSRX_EWDT2_MASK 0x00000001 /* Enable bit 2 */
+#define XWT_CSRX_EWDT2_MASK BIT(0) /* Enable bit 2 */
/* SelfTest constants */
#define XWT_MAX_SELFTEST_LOOP_COUNT 0x00010000
@@ -40,7 +41,7 @@
struct xwdt_device {
void __iomem *base;
u32 wdt_interval;
- spinlock_t spinlock;
+ spinlock_t spinlock; /* spinlock for register handling */
struct watchdog_device xilinx_wdt_wdd;
struct clk *clk;
};
@@ -70,6 +71,8 @@ static int xilinx_wdt_start(struct watchdog_device *wdd)
spin_unlock(&xdev->spinlock);
+ dev_dbg(wdd->parent, "Watchdog Started!\n");
+
return 0;
}
@@ -91,7 +94,7 @@ static int xilinx_wdt_stop(struct watchdog_device *wdd)
clk_disable(xdev->clk);
- pr_info("Stopped!\n");
+ dev_dbg(wdd->parent, "Watchdog Stopped!\n");
return 0;
}
@@ -208,6 +211,15 @@ static int xwdt_probe(struct platform_device *pdev)
"The watchdog clock freq cannot be obtained\n");
} else {
pfreq = clk_get_rate(xdev->clk);
+ rc = clk_prepare_enable(xdev->clk);
+ if (rc) {
+ dev_err(dev, "unable to enable clock\n");
+ return rc;
+ }
+ rc = devm_add_action_or_reset(dev, xwdt_clk_disable_unprepare,
+ xdev->clk);
+ if (rc)
+ return rc;
}
/*
@@ -221,16 +233,6 @@ static int xwdt_probe(struct platform_device *pdev)
spin_lock_init(&xdev->spinlock);
watchdog_set_drvdata(xilinx_wdt_wdd, xdev);
- rc = clk_prepare_enable(xdev->clk);
- if (rc) {
- dev_err(dev, "unable to enable clock\n");
- return rc;
- }
- rc = devm_add_action_or_reset(dev, xwdt_clk_disable_unprepare,
- xdev->clk);
- if (rc)
- return rc;
-
rc = xwdt_selftest(xdev);
if (rc == XWT_TIMER_FAILED) {
dev_err(dev, "SelfTest routine error\n");
@@ -243,8 +245,8 @@ static int xwdt_probe(struct platform_device *pdev)
clk_disable(xdev->clk);
- dev_info(dev, "Xilinx Watchdog Timer at %p with timeout %ds\n",
- xdev->base, xilinx_wdt_wdd->timeout);
+ dev_info(dev, "Xilinx Watchdog Timer with timeout %ds\n",
+ xilinx_wdt_wdd->timeout);
platform_set_drvdata(pdev, xdev);
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 4ddb4ea2e4a3..127eefc9161d 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -174,7 +174,7 @@ static int armadaxp_wdt_clock_init(struct platform_device *pdev,
return ret;
}
- /* Fix the wdt and timer1 clock freqency to 25MHz */
+ /* Fix the wdt and timer1 clock frequency to 25MHz */
val = WDT_AXP_FIXED_ENABLE_BIT | TIMER1_FIXED_ENABLE_BIT;
atomic_io_modify(dev->reg + TIMER_CTRL, val, val);
diff --git a/drivers/watchdog/pc87413_wdt.c b/drivers/watchdog/pc87413_wdt.c
index 2d4504302c9e..9f9a340427fc 100644
--- a/drivers/watchdog/pc87413_wdt.c
+++ b/drivers/watchdog/pc87413_wdt.c
@@ -445,7 +445,7 @@ static long pc87413_ioctl(struct file *file, unsigned int cmd,
/* -- Notifier funtions -----------------------------------------*/
/**
- * notify_sys:
+ * pc87413_notify_sys:
* @this: our notifier block
* @code: the event being reported
* @unused: unused
diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c
index e38a87ffe5f5..0d2209c5eaca 100644
--- a/drivers/watchdog/qcom-wdt.c
+++ b/drivers/watchdog/qcom-wdt.c
@@ -329,7 +329,9 @@ static int __maybe_unused qcom_wdt_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(qcom_wdt_pm_ops, qcom_wdt_suspend, qcom_wdt_resume);
+static const struct dev_pm_ops qcom_wdt_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(qcom_wdt_suspend, qcom_wdt_resume)
+};
static const struct of_device_id qcom_wdt_of_table[] = {
{ .compatible = "qcom,kpss-timer", .data = &match_data_apcs_tmr },
diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c
index e5d11d6a2600..ec20ad4e534f 100644
--- a/drivers/watchdog/sama5d4_wdt.c
+++ b/drivers/watchdog/sama5d4_wdt.c
@@ -268,8 +268,10 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
wdd->min_timeout = MIN_WDT_TIMEOUT;
wdd->max_timeout = MAX_WDT_TIMEOUT;
wdt->last_ping = jiffies;
- wdt->sam9x60_support = of_device_is_compatible(dev->of_node,
- "microchip,sam9x60-wdt");
+
+ if (of_device_is_compatible(dev->of_node, "microchip,sam9x60-wdt") ||
+ of_device_is_compatible(dev->of_node, "microchip,sama7g5-wdt"))
+ wdt->sam9x60_support = true;
watchdog_set_drvdata(wdd, wdt);
@@ -329,6 +331,10 @@ static const struct of_device_id sama5d4_wdt_of_match[] = {
{
.compatible = "microchip,sam9x60-wdt",
},
+ {
+ .compatible = "microchip,sama7g5-wdt",
+ },
+
{ }
};
MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match);
diff --git a/drivers/watchdog/sbc60xxwdt.c b/drivers/watchdog/sbc60xxwdt.c
index a947a63fb44a..7b974802dfc7 100644
--- a/drivers/watchdog/sbc60xxwdt.c
+++ b/drivers/watchdog/sbc60xxwdt.c
@@ -146,7 +146,7 @@ static void wdt_startup(void)
static void wdt_turnoff(void)
{
/* Stop the timer */
- del_timer(&timer);
+ del_timer_sync(&timer);
inb_p(wdt_stop);
pr_info("Watchdog timer is now disabled...\n");
}
diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c
index f0f1e3b2e463..ee9ff38929eb 100644
--- a/drivers/watchdog/sbsa_gwdt.c
+++ b/drivers/watchdog/sbsa_gwdt.c
@@ -73,16 +73,21 @@
#define SBSA_GWDT_WCS_WS0 BIT(1)
#define SBSA_GWDT_WCS_WS1 BIT(2)
+#define SBSA_GWDT_VERSION_MASK 0xF
+#define SBSA_GWDT_VERSION_SHIFT 16
+
/**
* struct sbsa_gwdt - Internal representation of the SBSA GWDT
* @wdd: kernel watchdog_device structure
* @clk: store the System Counter clock frequency, in Hz.
+ * @version: store the architecture version
* @refresh_base: Virtual address of the watchdog refresh frame
* @control_base: Virtual address of the watchdog control frame
*/
struct sbsa_gwdt {
struct watchdog_device wdd;
u32 clk;
+ int version;
void __iomem *refresh_base;
void __iomem *control_base;
};
@@ -113,6 +118,30 @@ MODULE_PARM_DESC(nowayout,
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
+ * Arm Base System Architecture 1.0 introduces watchdog v1 which
+ * increases the length watchdog offset register to 48 bits.
+ * - For version 0: WOR is 32 bits;
+ * - For version 1: WOR is 48 bits which comprises the register
+ * offset 0x8 and 0xC, and the bits [63:48] are reserved which are
+ * Read-As-Zero and Writes-Ignored.
+ */
+static u64 sbsa_gwdt_reg_read(struct sbsa_gwdt *gwdt)
+{
+ if (gwdt->version == 0)
+ return readl(gwdt->control_base + SBSA_GWDT_WOR);
+ else
+ return readq(gwdt->control_base + SBSA_GWDT_WOR);
+}
+
+static void sbsa_gwdt_reg_write(u64 val, struct sbsa_gwdt *gwdt)
+{
+ if (gwdt->version == 0)
+ writel((u32)val, gwdt->control_base + SBSA_GWDT_WOR);
+ else
+ writeq(val, gwdt->control_base + SBSA_GWDT_WOR);
+}
+
+/*
* watchdog operation functions
*/
static int sbsa_gwdt_set_timeout(struct watchdog_device *wdd,
@@ -123,16 +152,14 @@ static int sbsa_gwdt_set_timeout(struct watchdog_device *wdd,
wdd->timeout = timeout;
if (action)
- writel(gwdt->clk * timeout,
- gwdt->control_base + SBSA_GWDT_WOR);
+ sbsa_gwdt_reg_write(gwdt->clk * timeout, gwdt);
else
/*
* In the single stage mode, The first signal (WS0) is ignored,
* the timeout is (WOR * 2), so the WOR should be configured
* to half value of timeout.
*/
- writel(gwdt->clk / 2 * timeout,
- gwdt->control_base + SBSA_GWDT_WOR);
+ sbsa_gwdt_reg_write(gwdt->clk / 2 * timeout, gwdt);
return 0;
}
@@ -149,7 +176,7 @@ static unsigned int sbsa_gwdt_get_timeleft(struct watchdog_device *wdd)
*/
if (!action &&
!(readl(gwdt->control_base + SBSA_GWDT_WCS) & SBSA_GWDT_WCS_WS0))
- timeleft += readl(gwdt->control_base + SBSA_GWDT_WOR);
+ timeleft += sbsa_gwdt_reg_read(gwdt);
timeleft += lo_hi_readq(gwdt->control_base + SBSA_GWDT_WCV) -
arch_timer_read_counter();
@@ -172,6 +199,17 @@ static int sbsa_gwdt_keepalive(struct watchdog_device *wdd)
return 0;
}
+static void sbsa_gwdt_get_version(struct watchdog_device *wdd)
+{
+ struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd);
+ int ver;
+
+ ver = readl(gwdt->control_base + SBSA_GWDT_W_IIDR);
+ ver = (ver >> SBSA_GWDT_VERSION_SHIFT) & SBSA_GWDT_VERSION_MASK;
+
+ gwdt->version = ver;
+}
+
static int sbsa_gwdt_start(struct watchdog_device *wdd)
{
struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd);
@@ -252,10 +290,14 @@ static int sbsa_gwdt_probe(struct platform_device *pdev)
wdd->info = &sbsa_gwdt_info;
wdd->ops = &sbsa_gwdt_ops;
wdd->min_timeout = 1;
- wdd->max_hw_heartbeat_ms = U32_MAX / gwdt->clk * 1000;
wdd->timeout = DEFAULT_TIMEOUT;
watchdog_set_drvdata(wdd, gwdt);
watchdog_set_nowayout(wdd, nowayout);
+ sbsa_gwdt_get_version(wdd);
+ if (gwdt->version == 0)
+ wdd->max_hw_heartbeat_ms = U32_MAX / gwdt->clk * 1000;
+ else
+ wdd->max_hw_heartbeat_ms = GENMASK_ULL(47, 0) / gwdt->clk * 1000;
status = readl(cf_base + SBSA_GWDT_WCS);
if (status & SBSA_GWDT_WCS_WS1) {
diff --git a/drivers/watchdog/sc520_wdt.c b/drivers/watchdog/sc520_wdt.c
index e66e6b905964..ca65468f4b9c 100644
--- a/drivers/watchdog/sc520_wdt.c
+++ b/drivers/watchdog/sc520_wdt.c
@@ -186,7 +186,7 @@ static int wdt_startup(void)
static int wdt_turnoff(void)
{
/* Stop the timer */
- del_timer(&timer);
+ del_timer_sync(&timer);
/* Stop the watchdog */
wdt_config(0);
diff --git a/drivers/watchdog/sl28cpld_wdt.c b/drivers/watchdog/sl28cpld_wdt.c
index a45047d8d9ab..2de93298475f 100644
--- a/drivers/watchdog/sl28cpld_wdt.c
+++ b/drivers/watchdog/sl28cpld_wdt.c
@@ -164,7 +164,7 @@ static int sl28cpld_wdt_probe(struct platform_device *pdev)
/*
* Initial timeout value, may be overwritten by device tree or module
- * parmeter in watchdog_init_timeout().
+ * parameter in watchdog_init_timeout().
*
* Reading a zero here means that either the hardware has a default
* value of zero (which is very unlikely and definitely a hardware
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
index 58a00e1ab23b..dbeb2146c968 100644
--- a/drivers/watchdog/sp805_wdt.c
+++ b/drivers/watchdog/sp805_wdt.c
@@ -11,7 +11,6 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/resource.h>
#include <linux/amba/bus.h>
@@ -23,8 +22,8 @@
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/of.h>
#include <linux/pm.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
@@ -58,7 +57,8 @@
* @wdd: instance of struct watchdog_device
* @lock: spin lock protecting dev structure and io access
* @base: base address of wdt
- * @clk: clock structure of wdt
+ * @clk: (optional) clock structure of wdt
+ * @rate: (optional) clock rate when provided via properties
* @adev: amba device structure of wdt
* @status: current status of wdt
* @load_val: load value to be set for current timeout
@@ -231,6 +231,7 @@ static int
sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
{
struct sp805_wdt *wdt;
+ u64 rate = 0;
int ret = 0;
wdt = devm_kzalloc(&adev->dev, sizeof(*wdt), GFP_KERNEL);
@@ -243,25 +244,23 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
if (IS_ERR(wdt->base))
return PTR_ERR(wdt->base);
- if (adev->dev.of_node) {
- wdt->clk = devm_clk_get(&adev->dev, NULL);
- if (IS_ERR(wdt->clk)) {
- dev_err(&adev->dev, "Clock not found\n");
- return PTR_ERR(wdt->clk);
- }
- wdt->rate = clk_get_rate(wdt->clk);
- } else if (has_acpi_companion(&adev->dev)) {
- /*
- * When Driver probe with ACPI device, clock devices
- * are not available, so watchdog rate get from
- * clock-frequency property given in _DSD object.
- */
- device_property_read_u64(&adev->dev, "clock-frequency",
- &wdt->rate);
- if (!wdt->rate) {
- dev_err(&adev->dev, "no clock-frequency property\n");
- return -ENODEV;
- }
+ /*
+ * When driver probe with ACPI device, clock devices
+ * are not available, so watchdog rate get from
+ * clock-frequency property given in _DSD object.
+ */
+ device_property_read_u64(&adev->dev, "clock-frequency", &rate);
+
+ wdt->clk = devm_clk_get_optional(&adev->dev, NULL);
+ if (IS_ERR(wdt->clk))
+ return dev_err_probe(&adev->dev, PTR_ERR(wdt->clk), "Clock not found\n");
+
+ wdt->rate = clk_get_rate(wdt->clk);
+ if (!wdt->rate)
+ wdt->rate = rate;
+ if (!wdt->rate) {
+ dev_err(&adev->dev, "no clock-frequency property\n");
+ return -ENODEV;
}
wdt->adev = adev;
diff --git a/drivers/watchdog/w83877f_wdt.c b/drivers/watchdog/w83877f_wdt.c
index 5772cc5d3780..f2650863fd02 100644
--- a/drivers/watchdog/w83877f_wdt.c
+++ b/drivers/watchdog/w83877f_wdt.c
@@ -166,7 +166,7 @@ static void wdt_startup(void)
static void wdt_turnoff(void)
{
/* Stop the timer */
- del_timer(&timer);
+ del_timer_sync(&timer);
wdt_change(WDT_DISABLE);
diff --git a/drivers/watchdog/watchdog_core.h b/drivers/watchdog/watchdog_core.h
index a5062e8e0d13..5b35a8439e26 100644
--- a/drivers/watchdog/watchdog_core.h
+++ b/drivers/watchdog/watchdog_core.h
@@ -7,6 +7,8 @@
*
* (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>.
*
+ * (c) Copyright 2021 Hewlett Packard Enterprise Development LP.
+ *
* This source code is part of the generic code that can be used
* by all the watchdog timer drivers.
*
@@ -22,12 +24,58 @@
* This material is provided "AS-IS" and at no charge.
*/
+#include <linux/hrtimer.h>
+#include <linux/kthread.h>
+
#define MAX_DOGS 32 /* Maximum number of watchdog devices */
/*
+ * struct watchdog_core_data - watchdog core internal data
+ * @dev: The watchdog's internal device
+ * @cdev: The watchdog's Character device.
+ * @wdd: Pointer to watchdog device.
+ * @lock: Lock for watchdog core.
+ * @status: Watchdog core internal status bits.
+ */
+struct watchdog_core_data {
+ struct device dev;
+ struct cdev cdev;
+ struct watchdog_device *wdd;
+ struct mutex lock;
+ ktime_t last_keepalive;
+ ktime_t last_hw_keepalive;
+ ktime_t open_deadline;
+ struct hrtimer timer;
+ struct kthread_work work;
+#if IS_ENABLED(CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT)
+ struct hrtimer pretimeout_timer;
+#endif
+ unsigned long status; /* Internal status bits */
+#define _WDOG_DEV_OPEN 0 /* Opened ? */
+#define _WDOG_ALLOW_RELEASE 1 /* Did we receive the magic char ? */
+#define _WDOG_KEEPALIVE 2 /* Did we receive a keepalive ? */
+};
+
+/*
* Functions/procedures to be called by the core
*/
extern int watchdog_dev_register(struct watchdog_device *);
extern void watchdog_dev_unregister(struct watchdog_device *);
extern int __init watchdog_dev_init(void);
extern void __exit watchdog_dev_exit(void);
+
+static inline bool watchdog_have_pretimeout(struct watchdog_device *wdd)
+{
+ return wdd->info->options & WDIOF_PRETIMEOUT ||
+ IS_ENABLED(CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT);
+}
+
+#if IS_ENABLED(CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT)
+void watchdog_hrtimer_pretimeout_init(struct watchdog_device *wdd);
+void watchdog_hrtimer_pretimeout_start(struct watchdog_device *wdd);
+void watchdog_hrtimer_pretimeout_stop(struct watchdog_device *wdd);
+#else
+static inline void watchdog_hrtimer_pretimeout_init(struct watchdog_device *wdd) {}
+static inline void watchdog_hrtimer_pretimeout_start(struct watchdog_device *wdd) {}
+static inline void watchdog_hrtimer_pretimeout_stop(struct watchdog_device *wdd) {}
+#endif
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 2946f3a63110..3bab32485273 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -7,6 +7,7 @@
*
* (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>.
*
+ * (c) Copyright 2021 Hewlett Packard Enterprise Development LP.
*
* This source code is part of the generic code that can be used
* by all the watchdog timer drivers.
@@ -46,30 +47,6 @@
#include "watchdog_core.h"
#include "watchdog_pretimeout.h"
-/*
- * struct watchdog_core_data - watchdog core internal data
- * @dev: The watchdog's internal device
- * @cdev: The watchdog's Character device.
- * @wdd: Pointer to watchdog device.
- * @lock: Lock for watchdog core.
- * @status: Watchdog core internal status bits.
- */
-struct watchdog_core_data {
- struct device dev;
- struct cdev cdev;
- struct watchdog_device *wdd;
- 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 */
-#define _WDOG_DEV_OPEN 0 /* Opened ? */
-#define _WDOG_ALLOW_RELEASE 1 /* Did we receive the magic char ? */
-#define _WDOG_KEEPALIVE 2 /* Did we receive a keepalive ? */
-};
-
/* the dev_t structure to store the dynamically allocated watchdog devices */
static dev_t watchdog_devt;
/* Reference to watchdog device behind /dev/watchdog */
@@ -185,6 +162,9 @@ static int __watchdog_ping(struct watchdog_device *wdd)
else
err = wdd->ops->start(wdd); /* restart watchdog */
+ if (err == 0)
+ watchdog_hrtimer_pretimeout_start(wdd);
+
watchdog_update_worker(wdd);
return err;
@@ -275,8 +255,10 @@ static int watchdog_start(struct watchdog_device *wdd)
started_at = ktime_get();
if (watchdog_hw_running(wdd) && wdd->ops->ping) {
err = __watchdog_ping(wdd);
- if (err == 0)
+ if (err == 0) {
set_bit(WDOG_ACTIVE, &wdd->status);
+ watchdog_hrtimer_pretimeout_start(wdd);
+ }
} else {
err = wdd->ops->start(wdd);
if (err == 0) {
@@ -284,6 +266,7 @@ static int watchdog_start(struct watchdog_device *wdd)
wd_data->last_keepalive = started_at;
wd_data->last_hw_keepalive = started_at;
watchdog_update_worker(wdd);
+ watchdog_hrtimer_pretimeout_start(wdd);
}
}
@@ -325,6 +308,7 @@ static int watchdog_stop(struct watchdog_device *wdd)
if (err == 0) {
clear_bit(WDOG_ACTIVE, &wdd->status);
watchdog_update_worker(wdd);
+ watchdog_hrtimer_pretimeout_stop(wdd);
}
return err;
@@ -361,6 +345,9 @@ static unsigned int watchdog_get_status(struct watchdog_device *wdd)
if (test_and_clear_bit(_WDOG_KEEPALIVE, &wd_data->status))
status |= WDIOF_KEEPALIVEPING;
+ if (IS_ENABLED(CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT))
+ status |= WDIOF_PRETIMEOUT;
+
return status;
}
@@ -408,7 +395,7 @@ static int watchdog_set_pretimeout(struct watchdog_device *wdd,
{
int err = 0;
- if (!(wdd->info->options & WDIOF_PRETIMEOUT))
+ if (!watchdog_have_pretimeout(wdd))
return -EOPNOTSUPP;
if (watchdog_pretimeout_invalid(wdd, timeout))
@@ -451,7 +438,8 @@ static ssize_t nowayout_show(struct device *dev, struct device_attribute *attr,
{
struct watchdog_device *wdd = dev_get_drvdata(dev);
- return sprintf(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT, &wdd->status));
+ return sysfs_emit(buf, "%d\n", !!test_bit(WDOG_NO_WAY_OUT,
+ &wdd->status));
}
static ssize_t nowayout_store(struct device *dev, struct device_attribute *attr,
@@ -485,7 +473,7 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
status = watchdog_get_status(wdd);
mutex_unlock(&wd_data->lock);
- return sprintf(buf, "0x%x\n", status);
+ return sysfs_emit(buf, "0x%x\n", status);
}
static DEVICE_ATTR_RO(status);
@@ -494,7 +482,7 @@ static ssize_t bootstatus_show(struct device *dev,
{
struct watchdog_device *wdd = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", wdd->bootstatus);
+ return sysfs_emit(buf, "%u\n", wdd->bootstatus);
}
static DEVICE_ATTR_RO(bootstatus);
@@ -510,7 +498,7 @@ static ssize_t timeleft_show(struct device *dev, struct device_attribute *attr,
status = watchdog_get_timeleft(wdd, &val);
mutex_unlock(&wd_data->lock);
if (!status)
- status = sprintf(buf, "%u\n", val);
+ status = sysfs_emit(buf, "%u\n", val);
return status;
}
@@ -521,16 +509,34 @@ static ssize_t timeout_show(struct device *dev, struct device_attribute *attr,
{
struct watchdog_device *wdd = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", wdd->timeout);
+ return sysfs_emit(buf, "%u\n", wdd->timeout);
}
static DEVICE_ATTR_RO(timeout);
+static ssize_t min_timeout_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%u\n", wdd->min_timeout);
+}
+static DEVICE_ATTR_RO(min_timeout);
+
+static ssize_t max_timeout_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%u\n", wdd->max_timeout);
+}
+static DEVICE_ATTR_RO(max_timeout);
+
static ssize_t pretimeout_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct watchdog_device *wdd = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", wdd->pretimeout);
+ return sysfs_emit(buf, "%u\n", wdd->pretimeout);
}
static DEVICE_ATTR_RO(pretimeout);
@@ -539,7 +545,7 @@ static ssize_t identity_show(struct device *dev, struct device_attribute *attr,
{
struct watchdog_device *wdd = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", wdd->info->identity);
+ return sysfs_emit(buf, "%s\n", wdd->info->identity);
}
static DEVICE_ATTR_RO(identity);
@@ -549,9 +555,9 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
struct watchdog_device *wdd = dev_get_drvdata(dev);
if (watchdog_active(wdd))
- return sprintf(buf, "active\n");
+ return sysfs_emit(buf, "active\n");
- return sprintf(buf, "inactive\n");
+ return sysfs_emit(buf, "inactive\n");
}
static DEVICE_ATTR_RO(state);
@@ -594,13 +600,11 @@ static umode_t wdt_is_visible(struct kobject *kobj, struct attribute *attr,
if (attr == &dev_attr_timeleft.attr && !wdd->ops->get_timeleft)
mode = 0;
- else if (attr == &dev_attr_pretimeout.attr &&
- !(wdd->info->options & WDIOF_PRETIMEOUT))
+ else if (attr == &dev_attr_pretimeout.attr && !watchdog_have_pretimeout(wdd))
mode = 0;
else if ((attr == &dev_attr_pretimeout_governor.attr ||
attr == &dev_attr_pretimeout_available_governors.attr) &&
- (!(wdd->info->options & WDIOF_PRETIMEOUT) ||
- !IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_GOV)))
+ (!watchdog_have_pretimeout(wdd) || !IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_GOV)))
mode = 0;
return mode;
@@ -609,6 +613,8 @@ static struct attribute *wdt_attrs[] = {
&dev_attr_state.attr,
&dev_attr_identity.attr,
&dev_attr_timeout.attr,
+ &dev_attr_min_timeout.attr,
+ &dev_attr_max_timeout.attr,
&dev_attr_pretimeout.attr,
&dev_attr_timeleft.attr,
&dev_attr_bootstatus.attr,
@@ -1009,6 +1015,7 @@ static int watchdog_cdev_register(struct watchdog_device *wdd)
kthread_init_work(&wd_data->work, watchdog_ping_work);
hrtimer_init(&wd_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
wd_data->timer.function = watchdog_timer_expired;
+ watchdog_hrtimer_pretimeout_init(wdd);
if (wdd->id == 0) {
old_wd_data = wd_data;
@@ -1096,6 +1103,7 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
hrtimer_cancel(&wd_data->timer);
kthread_cancel_work_sync(&wd_data->work);
+ watchdog_hrtimer_pretimeout_stop(wdd);
put_device(&wd_data->dev);
}
diff --git a/drivers/watchdog/watchdog_hrtimer_pretimeout.c b/drivers/watchdog/watchdog_hrtimer_pretimeout.c
new file mode 100644
index 000000000000..940b53718a91
--- /dev/null
+++ b/drivers/watchdog/watchdog_hrtimer_pretimeout.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (c) Copyright 2021 Hewlett Packard Enterprise Development LP.
+ */
+
+#include <linux/hrtimer.h>
+#include <linux/watchdog.h>
+
+#include "watchdog_core.h"
+#include "watchdog_pretimeout.h"
+
+static enum hrtimer_restart watchdog_hrtimer_pretimeout(struct hrtimer *timer)
+{
+ struct watchdog_core_data *wd_data;
+
+ wd_data = container_of(timer, struct watchdog_core_data, pretimeout_timer);
+
+ watchdog_notify_pretimeout(wd_data->wdd);
+ return HRTIMER_NORESTART;
+}
+
+void watchdog_hrtimer_pretimeout_init(struct watchdog_device *wdd)
+{
+ struct watchdog_core_data *wd_data = wdd->wd_data;
+
+ hrtimer_init(&wd_data->pretimeout_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ wd_data->pretimeout_timer.function = watchdog_hrtimer_pretimeout;
+}
+
+void watchdog_hrtimer_pretimeout_start(struct watchdog_device *wdd)
+{
+ if (!(wdd->info->options & WDIOF_PRETIMEOUT) &&
+ !watchdog_pretimeout_invalid(wdd, wdd->pretimeout))
+ hrtimer_start(&wdd->wd_data->pretimeout_timer,
+ ktime_set(wdd->timeout - wdd->pretimeout, 0),
+ HRTIMER_MODE_REL);
+ else
+ hrtimer_cancel(&wdd->wd_data->pretimeout_timer);
+}
+
+void watchdog_hrtimer_pretimeout_stop(struct watchdog_device *wdd)
+{
+ hrtimer_cancel(&wdd->wd_data->pretimeout_timer);
+}
diff --git a/drivers/watchdog/watchdog_pretimeout.c b/drivers/watchdog/watchdog_pretimeout.c
index 01ca84be240f..376a495ab80c 100644
--- a/drivers/watchdog/watchdog_pretimeout.c
+++ b/drivers/watchdog/watchdog_pretimeout.c
@@ -9,6 +9,7 @@
#include <linux/string.h>
#include <linux/watchdog.h>
+#include "watchdog_core.h"
#include "watchdog_pretimeout.h"
/* Default watchdog pretimeout governor */
@@ -55,7 +56,7 @@ int watchdog_pretimeout_available_governors_get(char *buf)
mutex_lock(&governor_lock);
list_for_each_entry(priv, &governor_list, entry)
- count += sprintf(buf + count, "%s\n", priv->gov->name);
+ count += sysfs_emit_at(buf, count, "%s\n", priv->gov->name);
mutex_unlock(&governor_lock);
@@ -68,7 +69,7 @@ int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf)
spin_lock_irq(&pretimeout_lock);
if (wdd->gov)
- count = sprintf(buf, "%s\n", wdd->gov->name);
+ count = sysfs_emit(buf, "%s\n", wdd->gov->name);
spin_unlock_irq(&pretimeout_lock);
return count;
@@ -177,7 +178,7 @@ int watchdog_register_pretimeout(struct watchdog_device *wdd)
{
struct watchdog_pretimeout *p;
- if (!(wdd->info->options & WDIOF_PRETIMEOUT))
+ if (!watchdog_have_pretimeout(wdd))
return 0;
p = kzalloc(sizeof(*p), GFP_KERNEL);
@@ -197,7 +198,7 @@ void watchdog_unregister_pretimeout(struct watchdog_device *wdd)
{
struct watchdog_pretimeout *p, *t;
- if (!(wdd->info->options & WDIOF_PRETIMEOUT))
+ if (!watchdog_have_pretimeout(wdd))
return;
spin_lock_irq(&pretimeout_lock);
diff --git a/drivers/watchdog/wdat_wdt.c b/drivers/watchdog/wdat_wdt.c
index cec7917790e5..195c8c004b69 100644
--- a/drivers/watchdog/wdat_wdt.c
+++ b/drivers/watchdog/wdat_wdt.c
@@ -208,7 +208,7 @@ static int wdat_wdt_enable_reboot(struct wdat_wdt *wdat)
/*
* WDAT specification says that the watchdog is required to reboot
* the system when it fires. However, it also states that it is
- * recommeded to make it configurable through hardware register. We
+ * recommended to make it configurable through hardware register. We
* enable reboot now if it is configurable, just in case.
*/
ret = wdat_wdt_run_action(wdat, ACPI_WDAT_SET_REBOOT, 0, NULL);
@@ -475,7 +475,7 @@ static int wdat_wdt_suspend_noirq(struct device *dev)
return 0;
/*
- * We need to stop the watchdog if firmare is not doing it or if we
+ * We need to stop the watchdog if firmware is not doing it or if we
* are going suspend to idle (where firmware is not involved). If
* firmware is stopping the watchdog we kick it here one more time
* to give it some time.
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
index a9e40b5c633e..183876156243 100644
--- a/drivers/watchdog/wdt.c
+++ b/drivers/watchdog/wdt.c
@@ -494,7 +494,7 @@ static int wdt_temp_release(struct inode *inode, struct file *file)
}
/**
- * notify_sys:
+ * wdt_notify_sys:
* @this: our notifier block
* @code: the event being reported
* @unused: unused
@@ -558,7 +558,7 @@ static struct notifier_block wdt_notifier = {
};
/**
- * cleanup_module:
+ * wdt_exit:
*
* Unload the watchdog. You cannot do this with any file handles open.
* If your watchdog is set to continue ticking on close and you unload
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
index c3254ba5ace6..d5e56b601351 100644
--- a/drivers/watchdog/wdt_pci.c
+++ b/drivers/watchdog/wdt_pci.c
@@ -537,7 +537,7 @@ static int wdtpci_temp_release(struct inode *inode, struct file *file)
}
/**
- * notify_sys:
+ * wdtpci_notify_sys:
* @this: our notifier block
* @code: the event being reported
* @unused: unused
diff --git a/drivers/watchdog/ziirave_wdt.c b/drivers/watchdog/ziirave_wdt.c
index 4297280807ca..c5a9b820d43a 100644
--- a/drivers/watchdog/ziirave_wdt.c
+++ b/drivers/watchdog/ziirave_wdt.c
@@ -69,9 +69,6 @@ static char *ziirave_reasons[] = {"power cycle", "hw watchdog", NULL, NULL,
#define ZIIRAVE_CMD_JUMP_TO_BOOTLOADER_MAGIC 1
#define ZIIRAVE_CMD_RESET_PROCESSOR_MAGIC 1
-#define ZIIRAVE_FW_VERSION_FMT "02.%02u.%02u"
-#define ZIIRAVE_BL_VERSION_FMT "01.%02u.%02u"
-
struct ziirave_wdt_rev {
unsigned char major;
unsigned char minor;
@@ -445,8 +442,9 @@ static ssize_t ziirave_wdt_sysfs_show_firm(struct device *dev,
if (ret)
return ret;
- ret = sprintf(buf, ZIIRAVE_FW_VERSION_FMT, w_priv->firmware_rev.major,
- w_priv->firmware_rev.minor);
+ ret = sysfs_emit(buf, "02.%02u.%02u\n",
+ w_priv->firmware_rev.major,
+ w_priv->firmware_rev.minor);
mutex_unlock(&w_priv->sysfs_mutex);
@@ -468,8 +466,9 @@ static ssize_t ziirave_wdt_sysfs_show_boot(struct device *dev,
if (ret)
return ret;
- ret = sprintf(buf, ZIIRAVE_BL_VERSION_FMT, w_priv->bootloader_rev.major,
- w_priv->bootloader_rev.minor);
+ ret = sysfs_emit(buf, "01.%02u.%02u\n",
+ w_priv->bootloader_rev.major,
+ w_priv->bootloader_rev.minor);
mutex_unlock(&w_priv->sysfs_mutex);
@@ -491,7 +490,7 @@ static ssize_t ziirave_wdt_sysfs_show_reason(struct device *dev,
if (ret)
return ret;
- ret = sprintf(buf, "%s", ziirave_reasons[w_priv->reset_reason]);
+ ret = sysfs_emit(buf, "%s\n", ziirave_reasons[w_priv->reset_reason]);
mutex_unlock(&w_priv->sysfs_mutex);
@@ -536,7 +535,7 @@ static ssize_t ziirave_wdt_sysfs_store_firm(struct device *dev,
}
dev_info(&client->dev,
- "Firmware updated to version " ZIIRAVE_FW_VERSION_FMT "\n",
+ "Firmware updated to version 02.%02u.%02u\n",
w_priv->firmware_rev.major, w_priv->firmware_rev.minor);
/* Restore the watchdog timeout */
@@ -677,7 +676,7 @@ static int ziirave_wdt_probe(struct i2c_client *client,
}
dev_info(&client->dev,
- "Firmware version: " ZIIRAVE_FW_VERSION_FMT "\n",
+ "Firmware version: 02.%02u.%02u\n",
w_priv->firmware_rev.major, w_priv->firmware_rev.minor);
ret = ziirave_wdt_revision(client, &w_priv->bootloader_rev,
@@ -688,7 +687,7 @@ static int ziirave_wdt_probe(struct i2c_client *client,
}
dev_info(&client->dev,
- "Bootloader version: " ZIIRAVE_BL_VERSION_FMT "\n",
+ "Bootloader version: 01.%02u.%02u\n",
w_priv->bootloader_rev.major, w_priv->bootloader_rev.minor);
w_priv->reset_reason = i2c_smbus_read_byte_data(client,
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index 7bbfd58958bc..d7e361fb0548 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -642,6 +642,9 @@ static void xen_irq_lateeoi_locked(struct irq_info *info, bool spurious)
}
info->eoi_time = 0;
+
+ /* is_active hasn't been reset yet, do it now. */
+ smp_store_release(&info->is_active, 0);
do_unmask(info, EVT_MASK_REASON_EOI_PENDING);
}
@@ -811,6 +814,7 @@ static void xen_evtchn_close(evtchn_port_t port)
BUG();
}
+/* Not called for lateeoi events. */
static void event_handler_exit(struct irq_info *info)
{
smp_store_release(&info->is_active, 0);
@@ -1883,7 +1887,12 @@ static void lateeoi_ack_dynirq(struct irq_data *data)
if (VALID_EVTCHN(evtchn)) {
do_mask(info, EVT_MASK_REASON_EOI_PENDING);
- event_handler_exit(info);
+ /*
+ * Don't call event_handler_exit().
+ * Need to keep is_active non-zero in order to ignore re-raised
+ * events after cpu affinity changes while a lateeoi is pending.
+ */
+ clear_evtchn(evtchn);
}
}
diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c
index 1bcdd5227771..47aa3a1ccaf5 100644
--- a/drivers/xen/pcpu.c
+++ b/drivers/xen/pcpu.c
@@ -92,7 +92,7 @@ static int xen_pcpu_up(uint32_t cpu_id)
return HYPERVISOR_platform_op(&op);
}
-static ssize_t show_online(struct device *dev,
+static ssize_t online_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
@@ -101,7 +101,7 @@ static ssize_t show_online(struct device *dev,
return sprintf(buf, "%u\n", !!(cpu->flags & XEN_PCPU_FLAGS_ONLINE));
}
-static ssize_t __ref store_online(struct device *dev,
+static ssize_t __ref online_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -130,7 +130,7 @@ static ssize_t __ref store_online(struct device *dev,
ret = count;
return ret;
}
-static DEVICE_ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online);
+static DEVICE_ATTR_RW(online);
static struct attribute *pcpu_dev_attrs[] = {
&dev_attr_online.attr,
diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c
index a8d24433c8e9..8cd583db20b1 100644
--- a/drivers/xen/xen-balloon.c
+++ b/drivers/xen/xen-balloon.c
@@ -134,13 +134,13 @@ void xen_balloon_init(void)
EXPORT_SYMBOL_GPL(xen_balloon_init);
#define BALLOON_SHOW(name, format, args...) \
- static ssize_t show_##name(struct device *dev, \
+ static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
return sprintf(buf, format, ##args); \
} \
- static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+ static DEVICE_ATTR_RO(name)
BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low));
@@ -152,16 +152,15 @@ static DEVICE_ULONG_ATTR(retry_count, 0444, balloon_stats.retry_count);
static DEVICE_ULONG_ATTR(max_retry_count, 0644, balloon_stats.max_retry_count);
static DEVICE_BOOL_ATTR(scrub_pages, 0644, xen_scrub_pages);
-static ssize_t show_target_kb(struct device *dev, struct device_attribute *attr,
+static ssize_t target_kb_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages));
}
-static ssize_t store_target_kb(struct device *dev,
+static ssize_t target_kb_store(struct device *dev,
struct device_attribute *attr,
- const char *buf,
- size_t count)
+ const char *buf, size_t count)
{
char *endchar;
unsigned long long target_bytes;
@@ -176,22 +175,19 @@ static ssize_t store_target_kb(struct device *dev,
return count;
}
-static DEVICE_ATTR(target_kb, S_IRUGO | S_IWUSR,
- show_target_kb, store_target_kb);
+static DEVICE_ATTR_RW(target_kb);
-
-static ssize_t show_target(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t target_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
return sprintf(buf, "%llu\n",
(unsigned long long)balloon_stats.target_pages
<< PAGE_SHIFT);
}
-static ssize_t store_target(struct device *dev,
+static ssize_t target_store(struct device *dev,
struct device_attribute *attr,
- const char *buf,
- size_t count)
+ const char *buf, size_t count)
{
char *endchar;
unsigned long long target_bytes;
@@ -206,9 +202,7 @@ static ssize_t store_target(struct device *dev,
return count;
}
-static DEVICE_ATTR(target, S_IRUGO | S_IWUSR,
- show_target, store_target);
-
+static DEVICE_ATTR_RW(target);
static struct attribute *balloon_attrs[] = {
&dev_attr_target_kb.attr,
diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c
index 55a4763da05e..61ce0d142eea 100644
--- a/drivers/xen/xen-scsiback.c
+++ b/drivers/xen/xen-scsiback.c
@@ -222,10 +222,10 @@ static void scsiback_print_status(char *sense_buffer, int errors,
{
struct scsiback_tpg *tpg = pending_req->v2p->tpg;
- pr_err("[%s:%d] cmnd[0]=%02x -> st=%02x msg=%02x host=%02x drv=%02x\n",
+ pr_err("[%s:%d] cmnd[0]=%02x -> st=%02x msg=%02x host=%02x\n",
tpg->tport->tport_name, pending_req->v2p->lun,
- pending_req->cmnd[0], status_byte(errors), msg_byte(errors),
- host_byte(errors), driver_byte(errors));
+ pending_req->cmnd[0], errors & 0xff, COMMAND_COMPLETE,
+ host_byte(errors));
}
static void scsiback_fast_flush_area(struct vscsibk_pend *req)
@@ -719,10 +719,10 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info,
result = DID_NO_CONNECT;
break;
default:
- result = DRIVER_ERROR;
+ result = DID_ERROR;
break;
}
- scsiback_send_response(info, NULL, result << 24, 0,
+ scsiback_send_response(info, NULL, result << 16, 0,
ring_req.rqid);
return 1;
}
@@ -732,7 +732,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info,
if (scsiback_gnttab_data_map(&ring_req, pending_req)) {
scsiback_fast_flush_area(pending_req);
scsiback_do_resp_with_sense(NULL,
- DRIVER_ERROR << 24, 0, pending_req);
+ DID_ERROR << 16, 0, pending_req);
transport_generic_free_cmd(&pending_req->se_cmd, 0);
} else {
scsiback_cmd_exec(pending_req);
@@ -747,7 +747,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info,
break;
default:
pr_err_ratelimited("invalid request\n");
- scsiback_do_resp_with_sense(NULL, DRIVER_ERROR << 24, 0,
+ scsiback_do_resp_with_sense(NULL, DID_ERROR << 16, 0,
pending_req);
transport_generic_free_cmd(&pending_req->se_cmd, 0);
break;
@@ -1401,8 +1401,7 @@ static int scsiback_queue_status(struct se_cmd *se_cmd)
if (se_cmd->sense_buffer &&
((se_cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ||
(se_cmd->se_cmd_flags & SCF_EMULATED_TASK_SENSE)))
- pending_req->result = (DRIVER_SENSE << 24) |
- SAM_STAT_CHECK_CONDITION;
+ pending_req->result = SAM_STAT_CHECK_CONDITION;
else
pending_req->result = se_cmd->scsi_status;
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 97f0d234482d..33d09b3f6211 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -207,7 +207,7 @@ void xenbus_otherend_changed(struct xenbus_watch *watch,
EXPORT_SYMBOL_GPL(xenbus_otherend_changed);
#define XENBUS_SHOW_STAT(name) \
-static ssize_t show_##name(struct device *_dev, \
+static ssize_t name##_show(struct device *_dev, \
struct device_attribute *attr, \
char *buf) \
{ \
@@ -215,14 +215,14 @@ static ssize_t show_##name(struct device *_dev, \
\
return sprintf(buf, "%d\n", atomic_read(&dev->name)); \
} \
-static DEVICE_ATTR(name, 0444, show_##name, NULL)
+static DEVICE_ATTR_RO(name)
XENBUS_SHOW_STAT(event_channels);
XENBUS_SHOW_STAT(events);
XENBUS_SHOW_STAT(spurious_events);
XENBUS_SHOW_STAT(jiffies_eoi_delayed);
-static ssize_t show_spurious_threshold(struct device *_dev,
+static ssize_t spurious_threshold_show(struct device *_dev,
struct device_attribute *attr,
char *buf)
{
@@ -231,9 +231,9 @@ static ssize_t show_spurious_threshold(struct device *_dev,
return sprintf(buf, "%d\n", dev->spurious_threshold);
}
-static ssize_t set_spurious_threshold(struct device *_dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t spurious_threshold_store(struct device *_dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct xenbus_device *dev = to_xenbus_device(_dev);
unsigned int val;
@@ -248,8 +248,7 @@ static ssize_t set_spurious_threshold(struct device *_dev,
return count;
}
-static DEVICE_ATTR(spurious_threshold, 0644, show_spurious_threshold,
- set_spurious_threshold);
+static DEVICE_ATTR_RW(spurious_threshold);
static struct attribute *xenbus_attrs[] = {
&dev_attr_event_channels.attr,